From 8f9337f18a02172497117c520e93bc691610fedc Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 22 Aug 2022 19:54:18 +0200 Subject: [PATCH 001/433] jextract on macOS --- java-does-usb/jextract/gen_macos.sh | 15 ++ .../usb/macos/gen/Constants$root.java | 23 ++ .../usb/macos/gen/RuntimeHelper.java | 233 ++++++++++++++++++ .../codecrete/usb/macos/gen/constants$0.java | 22 ++ .../net/codecrete/usb/macos/gen/mach_h.java | 34 +++ 5 files changed, 327 insertions(+) create mode 100755 java-does-usb/jextract/gen_macos.sh create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach_h.java diff --git a/java-does-usb/jextract/gen_macos.sh b/java-does-usb/jextract/gen_macos.sh new file mode 100755 index 00000000..1ed1f947 --- /dev/null +++ b/java-does-usb/jextract/gen_macos.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +JEXTRACT=../../../jextract/build/jextract/bin/jextract + +# CoreFoundation +#$JEXTRACT --source --target-package net.codecrete.usb.macos.gen --output ../src/main/java \ +# -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include \ +# --include-function CFUUIDCreateFromUUIDBytes \ +# /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/CoreFoundation.framework/Versions/A/Headers/CoreFoundation.h + +## mach_error +$JEXTRACT --source --target-package net.codecrete.usb.macos.gen --output ../src/main/java \ + -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include \ + --include-function mach_error \ + /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/mach/mach.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/Constants$root.java new file mode 100644 index 00000000..14626843 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/Constants$root.java @@ -0,0 +1,23 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +import java.nio.ByteOrder; +import java.lang.foreign.*; +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/RuntimeHelper.java new file mode 100644 index 00000000..01993f2e --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/RuntimeHelper.java @@ -0,0 +1,233 @@ +package net.codecrete.usb.macos.gen; +// Generated by jextract + +import java.lang.foreign.Addressable; +import java.lang.foreign.Linker; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.io.File; +import java.nio.file.Path; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Optional; +import java.util.stream.Stream; + +import static java.lang.foreign.Linker.*; +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/constants$0.java new file mode 100644 index 00000000..9ec2b3a5 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/constants$0.java @@ -0,0 +1,22 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +import java.nio.ByteOrder; +import java.lang.foreign.*; +import static java.lang.foreign.ValueLayout.*; +class constants$0 { + + static final FunctionDescriptor mach_error$FUNC = FunctionDescriptor.ofVoid( + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle mach_error$MH = RuntimeHelper.downcallHandle( + "mach_error", + constants$0.mach_error$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach_h.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach_h.java new file mode 100644 index 00000000..c739f909 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach_h.java @@ -0,0 +1,34 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +import java.nio.ByteOrder; +import java.lang.foreign.*; +import static java.lang.foreign.ValueLayout.*; +public class mach_h { + + /* package-private */ mach_h() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static MethodHandle mach_error$MH() { + return RuntimeHelper.requireNonNull(constants$0.mach_error$MH,"mach_error"); + } + public static void mach_error ( Addressable str, int error_value) { + var mh$ = mach_error$MH(); + try { + mh$.invokeExact(str, error_value); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } +} + + From bbf8f350dd6abc7d3cbd6edfd969d4c54db8618c Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 22 Aug 2022 21:01:04 +0200 Subject: [PATCH 002/433] jextract on Linux --- java-does-usb/jextract/gen_linux.sh | 41 +++++++++ .../main/java/net/codecrete/usb/linux/IO.java | 84 ++----------------- .../codecrete/usb/linux/LinuxUSBDevice.java | 50 ++++++----- .../net/codecrete/usb/linux/USBDevFS.java | 55 ------------ .../java/net/codecrete/usb/macos/Kernel.java | 7 +- .../usb/macos/gen/Constants$root.java | 4 - .../usb/macos/gen/RuntimeHelper.java | 21 +---- .../codecrete/usb/macos/gen/constants$0.java | 5 +- .../net/codecrete/usb/macos/gen/mach_h.java | 5 +- 9 files changed, 86 insertions(+), 186 deletions(-) create mode 100755 java-does-usb/jextract/gen_linux.sh diff --git a/java-does-usb/jextract/gen_linux.sh b/java-does-usb/jextract/gen_linux.sh new file mode 100755 index 00000000..6fc40342 --- /dev/null +++ b/java-does-usb/jextract/gen_linux.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +JEXTRACT=../../../jextract/build/jextract/bin/jextract + +# sd-device.h (install libsystemd-dev if file is missing) +# Error: /usr/include/inttypes.h:290:8: error: unknown type name 'intmax_t' +#$JEXTRACT --source --output ../src/main/java \ +# --header-class-name sd_device \ +# --target-package net.codecrete.usb.linux.gen.sd-device +# /usr/include/systemd/sd-device.h + +# errno.h +$JEXTRACT --source --output ../src/main/java \ + --header-class-name errno \ + --target-package net.codecrete.usb.linux.gen.errno \ + /usr/include/errno.h + +# ioctl.h +$JEXTRACT --source --output ../src/main/java \ + --header-class-name ioctl \ + --target-package net.codecrete.usb.linux.gen.ioctl \ + /usr/include/x86_64-linux-gnu/sys/ioctl.h + +# fcntl.h +$JEXTRACT --source --output ../src/main/java \ + --header-class-name fcntl \ + --target-package net.codecrete.usb.linux.gen.fcntl \ + /usr/include/fcntl.h + +# unistd.h +$JEXTRACT --source --output ../src/main/java \ + --header-class-name unistd \ + --target-package net.codecrete.usb.linux.gen.unistd \ + /usr/include/unistd.h + +# usbdevice_fs.h +# Missing constants like USBDEVFS_CLAIMINTERFACE +$JEXTRACT --source --output ../src/main/java \ + --header-class-name usbdevice_fs \ + --target-package net.codecrete.usb.linux.gen.usbdevice_fs \ + /usr/include/linux/usbdevice_fs.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java index eda603be..68792634 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java @@ -7,89 +7,19 @@ package net.codecrete.usb.linux; -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; +import net.codecrete.usb.linux.gen.errno.errno; -import static java.lang.foreign.ValueLayout.*; +import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; -public class IO { - - public static final int O_RDONLY = 0; - public static final int O_WRONLY = 1; - public static final int O_RDWR = 2; - public static final int O_CREAT = 64; - public static final int O_EXCL = 128; - public static final int O_TRUNC = 512; - public static final int O_APPEND = 1024; - public static final int O_NONBLOCK = 2048; - public static final int O_CLOEXEC = 524288; - - private static final MethodHandle open$Func; - private static final MethodHandle ioctl$Func; - private static final MethodHandle close$Func; - private static final MethodHandle errno_location$Func; - - static { - Linker linker = Linker.nativeLinker(); - SymbolLookup lookup = linker.defaultLookup(); - - // int open (const char *__path, int __oflag, ...) - // (method handle without variadic arguments) - open$Func = linker.downcallHandle( - lookup.lookup("open").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT) - ); - - // int ioctl (int __fd, unsigned long int __request, ...); - ioctl$Func = linker.downcallHandle( - lookup.lookup("ioctl").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_LONG, ADDRESS) - ); - - // int close(int fd); - close$Func = linker.downcallHandle( - lookup.lookup("close").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT) - ); +import static java.lang.foreign.ValueLayout.JAVA_INT; - // int *__errno_location (void) - errno_location$Func = linker.downcallHandle( - lookup.lookup("__errno_location").get(), - FunctionDescriptor.of(ADDRESS) - ); - } - - // int open (const char *__path, int __oflag, ...) - public static int open(String path, int oflag) { - try (var session = MemorySession.openConfined()) { - var pathCStr = session.allocateUtf8String(path); - return (int) open$Func.invokeExact((Addressable) pathCStr, oflag); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // int ioctl (int __fd, unsigned long int __request, ...); - public static int ioctl(int fd, long request, Addressable val) { - try { - return (int) ioctl$Func.invokeExact(fd, request, val); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // int close(int fd); - public static int close(int fd) { - try { - return (int) close$Func.invokeExact(fd); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } +public class IO { public static int getErrno() { try (var session = MemorySession.openConfined()) { - var location = (MemoryAddress) errno_location$Func.invokeExact(); + var location = (MemoryAddress) errno.__errno_location(); var errnoSegment = MemorySegment.ofAddress(location, JAVA_INT.byteSize(), session); return errnoSegment.get(JAVA_INT, 0); } catch (Throwable e) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index c6c71b6d..e1b7c622 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -12,6 +12,11 @@ import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBException; import net.codecrete.usb.common.USBDeviceImpl; +import net.codecrete.usb.linux.gen.fcntl.fcntl; +import net.codecrete.usb.linux.gen.ioctl.ioctl; +import net.codecrete.usb.linux.gen.unistd.unistd; +import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_bulktransfer; +import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_ctrltransfer; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; @@ -26,15 +31,18 @@ public class LinuxUSBDevice extends USBDeviceImpl { LinuxUSBDevice(String path, USBDeviceInfo info) { super(path, info); - fd = IO.open(path, IO.O_RDWR | IO.O_CLOEXEC); - if (fd == -1) - throw new USBException("Cannot open USB device", IO.getErrno()); + try (var session = MemorySession.openConfined()) { + var pathUtf8 = session.allocateUtf8String(path); + fd = fcntl.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC()); + if (fd == -1) + throw new USBException("Cannot open USB device", IO.getErrno()); + } } public void claimInterface(int interfaceNumber) { try (var session = MemorySession.openConfined()) { var intfNumSegment = session.allocate(JAVA_INT, interfaceNumber); - int ret = IO.ioctl(fd, USBDevFS.CLAIMINTERFACE, intfNumSegment); + int ret = ioctl.ioctl(fd, USBDevFS.CLAIMINTERFACE, intfNumSegment.address()); if (ret != 0) throw new USBException("Cannot claim USB interface", IO.getErrno()); } @@ -43,21 +51,21 @@ public void claimInterface(int interfaceNumber) { public void releaseInterface(int interfaceNumber) { try (var session = MemorySession.openConfined()) { var intfNumSegment = session.allocate(JAVA_INT, interfaceNumber); - int ret = IO.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment); + int ret = ioctl.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment.address()); if (ret != 0) throw new USBException("Cannot release USB interface", IO.getErrno()); } } private MemorySegment createCtrlTransfer(MemorySession session, USBDirection direction, USBControlTransfer setup, MemorySegment data) { - var ctrlTransfer = session.allocate(USBDevFS.ctrltransfer$Struct); + var ctrlTransfer = session.allocate(usbdevfs_ctrltransfer.$LAYOUT()); var bmRequest = (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); - USBDevFS.ctrltransfer_bRequestType.set(ctrlTransfer, (byte) bmRequest); - USBDevFS.ctrltransfer_bRequest.set(ctrlTransfer, setup.request()); - USBDevFS.ctrltransfer_wValue.set(ctrlTransfer, setup.value()); - USBDevFS.ctrltransfer_wIndex.set(ctrlTransfer, setup.index()); - USBDevFS.ctrltransfer_wLength.set(ctrlTransfer, (short) data.byteSize()); - USBDevFS.ctrltransfer_data.set(ctrlTransfer, data.address()); + usbdevfs_ctrltransfer.bRequestType$set(ctrlTransfer, (byte) bmRequest); + usbdevfs_ctrltransfer.bRequest$set(ctrlTransfer, setup.request()); + usbdevfs_ctrltransfer.wValue$set(ctrlTransfer, setup.value()); + usbdevfs_ctrltransfer.wIndex$set(ctrlTransfer, setup.index()); + usbdevfs_ctrltransfer.wLength$set(ctrlTransfer, (short) data.byteSize()); + usbdevfs_ctrltransfer.data$set(ctrlTransfer, data.address()); return ctrlTransfer; } @@ -67,7 +75,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { var data = session.allocate(length); var ctrlTransfer = createCtrlTransfer(session, USBDirection.IN, setup, data); - int res = IO.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer); + int res = ioctl.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer.address()); if (res < 0) throw new USBException("Control IN transfer failed", res); @@ -84,17 +92,17 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { buffer.copyFrom(MemorySegment.ofArray(data)); var ctrlTransfer = createCtrlTransfer(session, USBDirection.OUT, setup, buffer); - int res = IO.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer); + int res = ioctl.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer.address()); if (res < 0) throw new USBException("Control OUT transfer failed", res); } } private MemorySegment createBulkTransfer(MemorySession session, int endpointAddress, MemorySegment data) { - var transfer = session.allocate(USBDevFS.bulktransfer$Struct); - USBDevFS.bulktransfer_ep.set(transfer, endpointAddress); - USBDevFS.bulktransfer_len.set(transfer, (int) data.byteSize()); - USBDevFS.bulktransfer_data.set(transfer, data.address()); + var transfer = session.allocate(usbdevfs_bulktransfer.$LAYOUT()); + usbdevfs_bulktransfer.ep$set(transfer, endpointAddress); + usbdevfs_bulktransfer.len$set(transfer, (int) data.byteSize()); + usbdevfs_bulktransfer.data$set(transfer, data.address()); return transfer; } @@ -105,7 +113,7 @@ public void transferOut(int endpointNumber, byte[] data) { buffer.copyFrom(MemorySegment.ofArray(data)); var transfer = createBulkTransfer(session, endpointNumber, buffer); - int res = IO.ioctl(fd, USBDevFS.BULK, transfer); + int res = ioctl.ioctl(fd, USBDevFS.BULK, transfer.address()); if (res < 0) throw new USBException(String.format("USB OUT transfer on endpoint %d failed", endpointNumber), res); } @@ -118,7 +126,7 @@ public byte[] transferIn(int endpointNumber, int maxLength) { var transfer = createBulkTransfer(session, 0x80 | endpointNumber, buffer); - int res = IO.ioctl(fd, USBDevFS.BULK, transfer); + int res = ioctl.ioctl(fd, USBDevFS.BULK, transfer.address()); if (res < 0) throw new USBException(String.format("USB IN transfer on endpoint %d failed", endpointNumber), res); @@ -128,6 +136,6 @@ public byte[] transferIn(int endpointNumber, int maxLength) { @Override public void close() throws Exception { - IO.close(fd); + unistd.close(fd); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java index b7fc431d..96b6c011 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java @@ -7,14 +7,6 @@ package net.codecrete.usb.linux; -import java.lang.foreign.GroupLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.MemoryLayout.paddingLayout; -import static java.lang.foreign.MemoryLayout.structLayout; -import static java.lang.foreign.ValueLayout.*; - /** * Data structures and constants related to the USB device file system. */ @@ -24,51 +16,4 @@ public class USBDevFS { public static final long BULK = 0xc0185502; public static final long CLAIMINTERFACE = 0x8004550F; public static final long RELEASEINTERFACE = 0x80045510; - - // struct usbdevfs_ctrltransfer { - // __u8 bRequestType; - // __u8 bRequest; - // __u16 wValue; - // __u16 wIndex; - // __u16 wLength; - // __u32 timeout; /* in milliseconds */ - // void *data; - //}; - public static final GroupLayout ctrltransfer$Struct = structLayout( - JAVA_BYTE.withName("bRequestType"), - JAVA_BYTE.withName("bRequest"), - JAVA_SHORT.withName("wValue"), - JAVA_SHORT.withName("wIndex"), - JAVA_SHORT.withName("wLength"), - JAVA_INT.withName("timeout"), - paddingLayout(4 * 8), - ADDRESS.withName("data") - ); - - public static final VarHandle ctrltransfer_bRequestType = ctrltransfer$Struct.varHandle(groupElement("bRequestType")); - public static final VarHandle ctrltransfer_bRequest = ctrltransfer$Struct.varHandle(groupElement("bRequest")); - public static final VarHandle ctrltransfer_wValue = ctrltransfer$Struct.varHandle(groupElement("wValue")); - public static final VarHandle ctrltransfer_wIndex = ctrltransfer$Struct.varHandle(groupElement("wIndex")); - public static final VarHandle ctrltransfer_wLength = ctrltransfer$Struct.varHandle(groupElement("wLength")); - public static final VarHandle ctrltransfer_timeout = ctrltransfer$Struct.varHandle(groupElement("timeout")); - public static final VarHandle ctrltransfer_data = ctrltransfer$Struct.varHandle(groupElement("data")); - - // struct usbdevfs_bulktransfer { - // unsigned int ep; - // unsigned int len; - // unsigned int timeout; /* in milliseconds */ - // void *data; - //}; - public static final GroupLayout bulktransfer$Struct = structLayout( - JAVA_INT.withName("ep"), - JAVA_INT.withName("len"), - JAVA_INT.withName("timeout"), - paddingLayout(4 * 8), - ADDRESS.withName("data") - ); - - public static final VarHandle bulktransfer_ep = bulktransfer$Struct.varHandle(groupElement("ep")); - public static final VarHandle bulktransfer_len = bulktransfer$Struct.varHandle(groupElement("len")); - public static final VarHandle bulktransfer_timeout = bulktransfer$Struct.varHandle(groupElement("timeout")); - public static final VarHandle bulktransfer_data = bulktransfer$Struct.varHandle(groupElement("data")); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/Kernel.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/Kernel.java index 326accf2..f7c8103d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/Kernel.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/Kernel.java @@ -7,11 +7,12 @@ package net.codecrete.usb.macos; -import java.lang.foreign.*; +import java.lang.foreign.Addressable; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySession; import java.lang.invoke.MethodHandle; -import java.util.Optional; -import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.ADDRESS; import static java.lang.foreign.ValueLayout.JAVA_INT; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/Constants$root.java index 14626843..7697ff6a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/Constants$root.java @@ -2,10 +2,6 @@ package net.codecrete.usb.macos.gen; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -import java.nio.ByteOrder; -import java.lang.foreign.*; import static java.lang.foreign.ValueLayout.*; public class Constants$root { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/RuntimeHelper.java index 01993f2e..9cf8e4d1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/RuntimeHelper.java @@ -1,28 +1,11 @@ package net.codecrete.usb.macos.gen; // Generated by jextract -import java.lang.foreign.Addressable; -import java.lang.foreign.Linker; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.MemoryAddress; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.ValueLayout; +import java.lang.foreign.*; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import java.io.File; -import java.nio.file.Path; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Optional; -import java.util.stream.Stream; - -import static java.lang.foreign.Linker.*; + import static java.lang.foreign.ValueLayout.*; final class RuntimeHelper { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/constants$0.java index 9ec2b3a5..7e25031b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/constants$0.java @@ -2,11 +2,8 @@ package net.codecrete.usb.macos.gen; +import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -import java.nio.ByteOrder; -import java.lang.foreign.*; -import static java.lang.foreign.ValueLayout.*; class constants$0 { static final FunctionDescriptor mach_error$FUNC = FunctionDescriptor.ofVoid( diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach_h.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach_h.java index c739f909..24894eb4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach_h.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach_h.java @@ -2,10 +2,9 @@ package net.codecrete.usb.macos.gen; +import java.lang.foreign.Addressable; import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -import java.nio.ByteOrder; -import java.lang.foreign.*; + import static java.lang.foreign.ValueLayout.*; public class mach_h { From 7be8874ba27045ea18dfea127dae5bbaf0d31461 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 22 Aug 2022 21:09:06 +0200 Subject: [PATCH 003/433] jextract on Linux (2) --- .../usb/linux/gen/errno/Constants$root.java | 19 + .../usb/linux/gen/errno/RuntimeHelper.java | 216 ++ .../usb/linux/gen/errno/constants$0.java | 16 + .../codecrete/usb/linux/gen/errno/errno.java | 555 ++++ .../usb/linux/gen/fcntl/Constants$root.java | 19 + .../usb/linux/gen/fcntl/RuntimeHelper.java | 216 ++ .../usb/linux/gen/fcntl/__fsid_t.java | 25 + .../usb/linux/gen/fcntl/constants$0.java | 63 + .../usb/linux/gen/fcntl/constants$1.java | 20 + .../codecrete/usb/linux/gen/fcntl/fcntl.java | 686 +++++ .../codecrete/usb/linux/gen/fcntl/flock.java | 109 + .../codecrete/usb/linux/gen/fcntl/stat.java | 234 ++ .../usb/linux/gen/fcntl/timespec.java | 56 + .../usb/linux/gen/ioctl/Constants$root.java | 19 + .../usb/linux/gen/ioctl/RuntimeHelper.java | 216 ++ .../usb/linux/gen/ioctl/constants$0.java | 19 + .../codecrete/usb/linux/gen/ioctl/ioctl.java | 758 +++++ .../codecrete/usb/linux/gen/ioctl/termio.java | 112 + .../usb/linux/gen/ioctl/winsize.java | 90 + .../usb/linux/gen/unistd/Constants$root.java | 19 + .../usb/linux/gen/unistd/RuntimeHelper.java | 216 ++ .../usb/linux/gen/unistd/__fsid_t.java | 25 + .../usb/linux/gen/unistd/constants$0.java | 61 + .../usb/linux/gen/unistd/constants$1.java | 61 + .../usb/linux/gen/unistd/constants$10.java | 52 + .../usb/linux/gen/unistd/constants$11.java | 65 + .../usb/linux/gen/unistd/constants$12.java | 55 + .../usb/linux/gen/unistd/constants$13.java | 44 + .../usb/linux/gen/unistd/constants$14.java | 55 + .../usb/linux/gen/unistd/constants$15.java | 50 + .../usb/linux/gen/unistd/constants$16.java | 50 + .../usb/linux/gen/unistd/constants$17.java | 51 + .../usb/linux/gen/unistd/constants$18.java | 52 + .../usb/linux/gen/unistd/constants$19.java | 17 + .../usb/linux/gen/unistd/constants$2.java | 58 + .../usb/linux/gen/unistd/constants$3.java | 58 + .../usb/linux/gen/unistd/constants$4.java | 60 + .../usb/linux/gen/unistd/constants$5.java | 57 + .../usb/linux/gen/unistd/constants$6.java | 50 + .../usb/linux/gen/unistd/constants$7.java | 50 + .../usb/linux/gen/unistd/constants$8.java | 46 + .../usb/linux/gen/unistd/constants$9.java | 53 + .../usb/linux/gen/unistd/unistd.java | 2714 +++++++++++++++++ .../gen/usbdevice_fs/Constants$root.java | 19 + .../linux/gen/usbdevice_fs/RuntimeHelper.java | 216 ++ .../gen/usbdevice_fs/__kernel_fd_set.java | 25 + .../gen/usbdevice_fs/__kernel_fsid_t.java | 25 + .../usbdevice_fs/__kernel_sighandler_t.java | 27 + .../linux/gen/usbdevice_fs/constants$0.java | 21 + .../usbdevice_fs/usbdevfs_bulktransfer.java | 91 + .../usbdevice_fs/usbdevfs_connectinfo.java | 57 + .../usbdevice_fs/usbdevfs_conninfo_ex.java | 111 + .../usbdevice_fs/usbdevfs_ctrltransfer.java | 142 + .../usbdevfs_disconnect_claim.java | 60 + .../usbdevfs_disconnectsignal.java | 57 + .../gen/usbdevice_fs/usbdevfs_getdriver.java | 43 + .../usbdevice_fs/usbdevfs_hub_portinfo.java | 43 + .../gen/usbdevice_fs/usbdevfs_ioctl.java | 73 + .../usbdevfs_iso_packet_desc.java | 73 + .../usbdevice_fs/usbdevfs_setinterface.java | 56 + .../gen/usbdevice_fs/usbdevfs_streams.java | 57 + .../linux/gen/usbdevice_fs/usbdevfs_urb.java | 252 ++ .../linux/gen/usbdevice_fs/usbdevice_fs.java | 366 +++ 63 files changed, 9281 insertions(+) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/__fsid_t.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$1.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/flock.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/stat.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/timespec.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/ioctl.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/termio.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/winsize.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/__fsid_t.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$1.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$10.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$11.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$12.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$13.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$14.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$15.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$16.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$17.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$18.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$19.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$2.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$3.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$4.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$5.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$6.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$7.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$8.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$9.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_fd_set.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_fsid_t.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_sighandler_t.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_connectinfo.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_conninfo_ex.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnectsignal.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_getdriver.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_hub_portinfo.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_streams.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/Constants$root.java new file mode 100644 index 00000000..73adc572 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.errno; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/RuntimeHelper.java new file mode 100644 index 00000000..282b5dfb --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/RuntimeHelper.java @@ -0,0 +1,216 @@ +package net.codecrete.usb.linux.gen.errno; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java new file mode 100644 index 00000000..cb3211ae --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java @@ -0,0 +1,16 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.errno; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor __errno_location$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT); + static final MethodHandle __errno_location$MH = RuntimeHelper.downcallHandle( + "__errno_location", + constants$0.__errno_location$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java new file mode 100644 index 00000000..2a42c554 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -0,0 +1,555 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.errno; + +import java.lang.foreign.MemoryAddress; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.*; +public class errno { + + /* package-private */ errno() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static int _ERRNO_H() { + return (int)1L; + } + public static int _FEATURES_H() { + return (int)1L; + } + public static int _DEFAULT_SOURCE() { + return (int)1L; + } + public static int __GLIBC_USE_ISOC2X() { + return (int)0L; + } + public static int __USE_ISOC11() { + return (int)1L; + } + public static int __USE_ISOC99() { + return (int)1L; + } + public static int __USE_ISOC95() { + return (int)1L; + } + public static int __USE_POSIX_IMPLICITLY() { + return (int)1L; + } + public static int _POSIX_SOURCE() { + return (int)1L; + } + public static int __USE_POSIX() { + return (int)1L; + } + public static int __USE_POSIX2() { + return (int)1L; + } + public static int __USE_POSIX199309() { + return (int)1L; + } + public static int __USE_POSIX199506() { + return (int)1L; + } + public static int __USE_XOPEN2K() { + return (int)1L; + } + public static int __USE_XOPEN2K8() { + return (int)1L; + } + public static int _ATFILE_SOURCE() { + return (int)1L; + } + public static int __WORDSIZE() { + return (int)64L; + } + public static int __WORDSIZE_TIME64_COMPAT32() { + return (int)1L; + } + public static int __SYSCALL_WORDSIZE() { + return (int)64L; + } + public static int __USE_MISC() { + return (int)1L; + } + public static int __USE_ATFILE() { + return (int)1L; + } + public static int __USE_FORTIFY_LEVEL() { + return (int)0L; + } + public static int __GLIBC_USE_DEPRECATED_GETS() { + return (int)0L; + } + public static int __GLIBC_USE_DEPRECATED_SCANF() { + return (int)0L; + } + public static int _STDC_PREDEF_H() { + return (int)1L; + } + public static int __STDC_IEC_559__() { + return (int)1L; + } + public static int __STDC_IEC_559_COMPLEX__() { + return (int)1L; + } + public static int __GNU_LIBRARY__() { + return (int)6L; + } + public static int __GLIBC__() { + return (int)2L; + } + public static int __GLIBC_MINOR__() { + return (int)35L; + } + public static int _SYS_CDEFS_H() { + return (int)1L; + } + public static int __glibc_c99_flexarr_available() { + return (int)1L; + } + public static int __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI() { + return (int)0L; + } + public static int __HAVE_GENERIC_SELECTION() { + return (int)1L; + } + public static int _BITS_ERRNO_H() { + return (int)1L; + } + public static int EPERM() { + return (int)1L; + } + public static int ENOENT() { + return (int)2L; + } + public static int ESRCH() { + return (int)3L; + } + public static int EINTR() { + return (int)4L; + } + public static int EIO() { + return (int)5L; + } + public static int ENXIO() { + return (int)6L; + } + public static int E2BIG() { + return (int)7L; + } + public static int ENOEXEC() { + return (int)8L; + } + public static int EBADF() { + return (int)9L; + } + public static int ECHILD() { + return (int)10L; + } + public static int EAGAIN() { + return (int)11L; + } + public static int ENOMEM() { + return (int)12L; + } + public static int EACCES() { + return (int)13L; + } + public static int EFAULT() { + return (int)14L; + } + public static int ENOTBLK() { + return (int)15L; + } + public static int EBUSY() { + return (int)16L; + } + public static int EEXIST() { + return (int)17L; + } + public static int EXDEV() { + return (int)18L; + } + public static int ENODEV() { + return (int)19L; + } + public static int ENOTDIR() { + return (int)20L; + } + public static int EISDIR() { + return (int)21L; + } + public static int EINVAL() { + return (int)22L; + } + public static int ENFILE() { + return (int)23L; + } + public static int EMFILE() { + return (int)24L; + } + public static int ENOTTY() { + return (int)25L; + } + public static int ETXTBSY() { + return (int)26L; + } + public static int EFBIG() { + return (int)27L; + } + public static int ENOSPC() { + return (int)28L; + } + public static int ESPIPE() { + return (int)29L; + } + public static int EROFS() { + return (int)30L; + } + public static int EMLINK() { + return (int)31L; + } + public static int EPIPE() { + return (int)32L; + } + public static int EDOM() { + return (int)33L; + } + public static int ERANGE() { + return (int)34L; + } + public static int EDEADLK() { + return (int)35L; + } + public static int ENAMETOOLONG() { + return (int)36L; + } + public static int ENOLCK() { + return (int)37L; + } + public static int ENOSYS() { + return (int)38L; + } + public static int ENOTEMPTY() { + return (int)39L; + } + public static int ELOOP() { + return (int)40L; + } + public static int ENOMSG() { + return (int)42L; + } + public static int EIDRM() { + return (int)43L; + } + public static int ECHRNG() { + return (int)44L; + } + public static int EL2NSYNC() { + return (int)45L; + } + public static int EL3HLT() { + return (int)46L; + } + public static int EL3RST() { + return (int)47L; + } + public static int ELNRNG() { + return (int)48L; + } + public static int EUNATCH() { + return (int)49L; + } + public static int ENOCSI() { + return (int)50L; + } + public static int EL2HLT() { + return (int)51L; + } + public static int EBADE() { + return (int)52L; + } + public static int EBADR() { + return (int)53L; + } + public static int EXFULL() { + return (int)54L; + } + public static int ENOANO() { + return (int)55L; + } + public static int EBADRQC() { + return (int)56L; + } + public static int EBADSLT() { + return (int)57L; + } + public static int EBFONT() { + return (int)59L; + } + public static int ENOSTR() { + return (int)60L; + } + public static int ENODATA() { + return (int)61L; + } + public static int ETIME() { + return (int)62L; + } + public static int ENOSR() { + return (int)63L; + } + public static int ENONET() { + return (int)64L; + } + public static int ENOPKG() { + return (int)65L; + } + public static int EREMOTE() { + return (int)66L; + } + public static int ENOLINK() { + return (int)67L; + } + public static int EADV() { + return (int)68L; + } + public static int ESRMNT() { + return (int)69L; + } + public static int ECOMM() { + return (int)70L; + } + public static int EPROTO() { + return (int)71L; + } + public static int EMULTIHOP() { + return (int)72L; + } + public static int EDOTDOT() { + return (int)73L; + } + public static int EBADMSG() { + return (int)74L; + } + public static int EOVERFLOW() { + return (int)75L; + } + public static int ENOTUNIQ() { + return (int)76L; + } + public static int EBADFD() { + return (int)77L; + } + public static int EREMCHG() { + return (int)78L; + } + public static int ELIBACC() { + return (int)79L; + } + public static int ELIBBAD() { + return (int)80L; + } + public static int ELIBSCN() { + return (int)81L; + } + public static int ELIBMAX() { + return (int)82L; + } + public static int ELIBEXEC() { + return (int)83L; + } + public static int EILSEQ() { + return (int)84L; + } + public static int ERESTART() { + return (int)85L; + } + public static int ESTRPIPE() { + return (int)86L; + } + public static int EUSERS() { + return (int)87L; + } + public static int ENOTSOCK() { + return (int)88L; + } + public static int EDESTADDRREQ() { + return (int)89L; + } + public static int EMSGSIZE() { + return (int)90L; + } + public static int EPROTOTYPE() { + return (int)91L; + } + public static int ENOPROTOOPT() { + return (int)92L; + } + public static int EPROTONOSUPPORT() { + return (int)93L; + } + public static int ESOCKTNOSUPPORT() { + return (int)94L; + } + public static int EOPNOTSUPP() { + return (int)95L; + } + public static int EPFNOSUPPORT() { + return (int)96L; + } + public static int EAFNOSUPPORT() { + return (int)97L; + } + public static int EADDRINUSE() { + return (int)98L; + } + public static int EADDRNOTAVAIL() { + return (int)99L; + } + public static int ENETDOWN() { + return (int)100L; + } + public static int ENETUNREACH() { + return (int)101L; + } + public static int ENETRESET() { + return (int)102L; + } + public static int ECONNABORTED() { + return (int)103L; + } + public static int ECONNRESET() { + return (int)104L; + } + public static int ENOBUFS() { + return (int)105L; + } + public static int EISCONN() { + return (int)106L; + } + public static int ENOTCONN() { + return (int)107L; + } + public static int ESHUTDOWN() { + return (int)108L; + } + public static int ETOOMANYREFS() { + return (int)109L; + } + public static int ETIMEDOUT() { + return (int)110L; + } + public static int ECONNREFUSED() { + return (int)111L; + } + public static int EHOSTDOWN() { + return (int)112L; + } + public static int EHOSTUNREACH() { + return (int)113L; + } + public static int EALREADY() { + return (int)114L; + } + public static int EINPROGRESS() { + return (int)115L; + } + public static int ESTALE() { + return (int)116L; + } + public static int EUCLEAN() { + return (int)117L; + } + public static int ENOTNAM() { + return (int)118L; + } + public static int ENAVAIL() { + return (int)119L; + } + public static int EISNAM() { + return (int)120L; + } + public static int EREMOTEIO() { + return (int)121L; + } + public static int EDQUOT() { + return (int)122L; + } + public static int ENOMEDIUM() { + return (int)123L; + } + public static int EMEDIUMTYPE() { + return (int)124L; + } + public static int ECANCELED() { + return (int)125L; + } + public static int ENOKEY() { + return (int)126L; + } + public static int EKEYEXPIRED() { + return (int)127L; + } + public static int EKEYREVOKED() { + return (int)128L; + } + public static int EKEYREJECTED() { + return (int)129L; + } + public static int EOWNERDEAD() { + return (int)130L; + } + public static int ENOTRECOVERABLE() { + return (int)131L; + } + public static int ERFKILL() { + return (int)132L; + } + public static int EHWPOISON() { + return (int)133L; + } + public static MethodHandle __errno_location$MH() { + return RuntimeHelper.requireNonNull(constants$0.__errno_location$MH,"__errno_location"); + } + public static MemoryAddress __errno_location () { + var mh$ = __errno_location$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static long _POSIX_C_SOURCE() { + return 200809L; + } + public static int __TIMESIZE() { + return (int)64L; + } + public static long __STDC_IEC_60559_BFP__() { + return 201404L; + } + public static long __STDC_IEC_60559_COMPLEX__() { + return 201404L; + } + public static long __STDC_ISO_10646__() { + return 201706L; + } + public static int EWOULDBLOCK() { + return (int)11L; + } + public static int EDEADLOCK() { + return (int)35L; + } + public static int ENOTSUP() { + return (int)95L; + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/Constants$root.java new file mode 100644 index 00000000..c938e854 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.fcntl; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/RuntimeHelper.java new file mode 100644 index 00000000..48c09b33 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/RuntimeHelper.java @@ -0,0 +1,216 @@ +package net.codecrete.usb.linux.gen.fcntl; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/__fsid_t.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/__fsid_t.java new file mode 100644 index 00000000..681bc974 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/__fsid_t.java @@ -0,0 +1,25 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.fcntl; + +import java.lang.foreign.*; +public class __fsid_t { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + MemoryLayout.sequenceLayout(2, Constants$root.C_INT$LAYOUT).withName("__val") + ); + public static MemoryLayout $LAYOUT() { + return __fsid_t.$struct$LAYOUT; + } + public static MemorySegment __val$slice(MemorySegment seg) { + return seg.asSlice(0, 8); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java new file mode 100644 index 00000000..5dadf164 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java @@ -0,0 +1,63 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.fcntl; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor fcntl$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle fcntl$MH = RuntimeHelper.downcallHandleVariadic( + "fcntl", + constants$0.fcntl$FUNC + ); + static final FunctionDescriptor open$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle open$MH = RuntimeHelper.downcallHandleVariadic( + "open", + constants$0.open$FUNC + ); + static final FunctionDescriptor openat$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle openat$MH = RuntimeHelper.downcallHandleVariadic( + "openat", + constants$0.openat$FUNC + ); + static final FunctionDescriptor creat$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle creat$MH = RuntimeHelper.downcallHandle( + "creat", + constants$0.creat$FUNC + ); + static final FunctionDescriptor lockf$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle lockf$MH = RuntimeHelper.downcallHandle( + "lockf", + constants$0.lockf$FUNC + ); + static final FunctionDescriptor posix_fadvise$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle posix_fadvise$MH = RuntimeHelper.downcallHandle( + "posix_fadvise", + constants$0.posix_fadvise$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$1.java new file mode 100644 index 00000000..0c420af8 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$1.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.fcntl; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$1 { + + static final FunctionDescriptor posix_fallocate$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle posix_fallocate$MH = RuntimeHelper.downcallHandle( + "posix_fallocate", + constants$1.posix_fallocate$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java new file mode 100644 index 00000000..d2ce44d6 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java @@ -0,0 +1,686 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.fcntl; + +import java.lang.foreign.Addressable; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.*; +public class fcntl { + + /* package-private */ fcntl() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static int _FCNTL_H() { + return (int)1L; + } + public static int _FEATURES_H() { + return (int)1L; + } + public static int _DEFAULT_SOURCE() { + return (int)1L; + } + public static int __GLIBC_USE_ISOC2X() { + return (int)0L; + } + public static int __USE_ISOC11() { + return (int)1L; + } + public static int __USE_ISOC99() { + return (int)1L; + } + public static int __USE_ISOC95() { + return (int)1L; + } + public static int __USE_POSIX_IMPLICITLY() { + return (int)1L; + } + public static int _POSIX_SOURCE() { + return (int)1L; + } + public static int __USE_POSIX() { + return (int)1L; + } + public static int __USE_POSIX2() { + return (int)1L; + } + public static int __USE_POSIX199309() { + return (int)1L; + } + public static int __USE_POSIX199506() { + return (int)1L; + } + public static int __USE_XOPEN2K() { + return (int)1L; + } + public static int __USE_XOPEN2K8() { + return (int)1L; + } + public static int _ATFILE_SOURCE() { + return (int)1L; + } + public static int __WORDSIZE() { + return (int)64L; + } + public static int __WORDSIZE_TIME64_COMPAT32() { + return (int)1L; + } + public static int __SYSCALL_WORDSIZE() { + return (int)64L; + } + public static int __USE_MISC() { + return (int)1L; + } + public static int __USE_ATFILE() { + return (int)1L; + } + public static int __USE_FORTIFY_LEVEL() { + return (int)0L; + } + public static int __GLIBC_USE_DEPRECATED_GETS() { + return (int)0L; + } + public static int __GLIBC_USE_DEPRECATED_SCANF() { + return (int)0L; + } + public static int _STDC_PREDEF_H() { + return (int)1L; + } + public static int __STDC_IEC_559__() { + return (int)1L; + } + public static int __STDC_IEC_559_COMPLEX__() { + return (int)1L; + } + public static int __GNU_LIBRARY__() { + return (int)6L; + } + public static int __GLIBC__() { + return (int)2L; + } + public static int __GLIBC_MINOR__() { + return (int)35L; + } + public static int _SYS_CDEFS_H() { + return (int)1L; + } + public static int __glibc_c99_flexarr_available() { + return (int)1L; + } + public static int __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI() { + return (int)0L; + } + public static int __HAVE_GENERIC_SELECTION() { + return (int)1L; + } + public static int _BITS_TYPES_H() { + return (int)1L; + } + public static int _BITS_TYPESIZES_H() { + return (int)1L; + } + public static int __OFF_T_MATCHES_OFF64_T() { + return (int)1L; + } + public static int __INO_T_MATCHES_INO64_T() { + return (int)1L; + } + public static int __RLIM_T_MATCHES_RLIM64_T() { + return (int)1L; + } + public static int __STATFS_MATCHES_STATFS64() { + return (int)1L; + } + public static int __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64() { + return (int)1L; + } + public static int __FD_SETSIZE() { + return (int)1024L; + } + public static int _BITS_TIME64_H() { + return (int)1L; + } + public static int __O_LARGEFILE() { + return (int)0L; + } + public static int F_GETLK64() { + return (int)5L; + } + public static int F_SETLK64() { + return (int)6L; + } + public static int F_SETLKW64() { + return (int)7L; + } + public static int O_ACCMODE() { + return (int)3L; + } + public static int O_RDONLY() { + return (int)0L; + } + public static int O_WRONLY() { + return (int)1L; + } + public static int O_RDWR() { + return (int)2L; + } + public static int O_CREAT() { + return (int)64L; + } + public static int O_EXCL() { + return (int)128L; + } + public static int O_NOCTTY() { + return (int)256L; + } + public static int O_TRUNC() { + return (int)512L; + } + public static int O_APPEND() { + return (int)1024L; + } + public static int O_NONBLOCK() { + return (int)2048L; + } + public static int O_SYNC() { + return (int)1052672L; + } + public static int O_ASYNC() { + return (int)8192L; + } + public static int __O_DIRECTORY() { + return (int)65536L; + } + public static int __O_NOFOLLOW() { + return (int)131072L; + } + public static int __O_CLOEXEC() { + return (int)524288L; + } + public static int __O_DIRECT() { + return (int)16384L; + } + public static int __O_NOATIME() { + return (int)262144L; + } + public static int __O_PATH() { + return (int)2097152L; + } + public static int __O_DSYNC() { + return (int)4096L; + } + public static int F_GETLK() { + return (int)5L; + } + public static int F_SETLK() { + return (int)6L; + } + public static int F_SETLKW() { + return (int)7L; + } + public static int F_DUPFD() { + return (int)0L; + } + public static int F_GETFD() { + return (int)1L; + } + public static int F_SETFD() { + return (int)2L; + } + public static int F_GETFL() { + return (int)3L; + } + public static int F_SETFL() { + return (int)4L; + } + public static int __F_SETOWN() { + return (int)8L; + } + public static int __F_GETOWN() { + return (int)9L; + } + public static int __F_SETSIG() { + return (int)10L; + } + public static int __F_GETSIG() { + return (int)11L; + } + public static int __F_SETOWN_EX() { + return (int)15L; + } + public static int __F_GETOWN_EX() { + return (int)16L; + } + public static int F_DUPFD_CLOEXEC() { + return (int)1030L; + } + public static int FD_CLOEXEC() { + return (int)1L; + } + public static int F_RDLCK() { + return (int)0L; + } + public static int F_WRLCK() { + return (int)1L; + } + public static int F_UNLCK() { + return (int)2L; + } + public static int F_EXLCK() { + return (int)4L; + } + public static int F_SHLCK() { + return (int)8L; + } + public static int LOCK_SH() { + return (int)1L; + } + public static int LOCK_EX() { + return (int)2L; + } + public static int LOCK_NB() { + return (int)4L; + } + public static int LOCK_UN() { + return (int)8L; + } + public static int __POSIX_FADV_DONTNEED() { + return (int)4L; + } + public static int __POSIX_FADV_NOREUSE() { + return (int)5L; + } + public static int POSIX_FADV_NORMAL() { + return (int)0L; + } + public static int POSIX_FADV_RANDOM() { + return (int)1L; + } + public static int POSIX_FADV_SEQUENTIAL() { + return (int)2L; + } + public static int POSIX_FADV_WILLNEED() { + return (int)3L; + } + public static int AT_SYMLINK_NOFOLLOW() { + return (int)256L; + } + public static int AT_REMOVEDIR() { + return (int)512L; + } + public static int AT_SYMLINK_FOLLOW() { + return (int)1024L; + } + public static int AT_EACCESS() { + return (int)512L; + } + public static int _STRUCT_TIMESPEC() { + return (int)1L; + } + public static int _BITS_ENDIAN_H() { + return (int)1L; + } + public static int __LITTLE_ENDIAN() { + return (int)1234L; + } + public static int __BIG_ENDIAN() { + return (int)4321L; + } + public static int __PDP_ENDIAN() { + return (int)3412L; + } + public static int _BITS_ENDIANNESS_H() { + return (int)1L; + } + public static int __time_t_defined() { + return (int)1L; + } + public static int _BITS_STAT_H() { + return (int)1L; + } + public static int _BITS_STRUCT_STAT_H() { + return (int)1L; + } + public static int __S_IFMT() { + return (int)61440L; + } + public static int __S_IFDIR() { + return (int)16384L; + } + public static int __S_IFCHR() { + return (int)8192L; + } + public static int __S_IFBLK() { + return (int)24576L; + } + public static int __S_IFREG() { + return (int)32768L; + } + public static int __S_IFIFO() { + return (int)4096L; + } + public static int __S_IFLNK() { + return (int)40960L; + } + public static int __S_IFSOCK() { + return (int)49152L; + } + public static int __S_ISUID() { + return (int)2048L; + } + public static int __S_ISGID() { + return (int)1024L; + } + public static int __S_ISVTX() { + return (int)512L; + } + public static int __S_IREAD() { + return (int)256L; + } + public static int __S_IWRITE() { + return (int)128L; + } + public static int __S_IEXEC() { + return (int)64L; + } + public static int R_OK() { + return (int)4L; + } + public static int W_OK() { + return (int)2L; + } + public static int X_OK() { + return (int)1L; + } + public static int F_OK() { + return (int)0L; + } + public static int SEEK_SET() { + return (int)0L; + } + public static int SEEK_CUR() { + return (int)1L; + } + public static int SEEK_END() { + return (int)2L; + } + public static int F_ULOCK() { + return (int)0L; + } + public static int F_LOCK() { + return (int)1L; + } + public static int F_TLOCK() { + return (int)2L; + } + public static int F_TEST() { + return (int)3L; + } + public static OfShort __int16_t = Constants$root.C_SHORT$LAYOUT; + public static OfInt __int32_t = Constants$root.C_INT$LAYOUT; + public static OfLong __int64_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfShort __int_least16_t = Constants$root.C_SHORT$LAYOUT; + public static OfInt __int_least32_t = Constants$root.C_INT$LAYOUT; + public static OfLong __int_least64_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __quad_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __intmax_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __off_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __off64_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfInt __pid_t = Constants$root.C_INT$LAYOUT; + public static OfLong __clock_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __time_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __suseconds_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __suseconds64_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfInt __daddr_t = Constants$root.C_INT$LAYOUT; + public static OfInt __key_t = Constants$root.C_INT$LAYOUT; + public static OfInt __clockid_t = Constants$root.C_INT$LAYOUT; + public static OfAddress __timer_t = Constants$root.C_POINTER$LAYOUT; + public static OfLong __blksize_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __blkcnt_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __blkcnt64_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __fsword_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __ssize_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __syscall_slong_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __loff_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfAddress __caddr_t = Constants$root.C_POINTER$LAYOUT; + public static OfLong __intptr_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfInt __sig_atomic_t = Constants$root.C_INT$LAYOUT; + public static OfLong off_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfInt pid_t = Constants$root.C_INT$LAYOUT; + public static OfLong time_t = Constants$root.C_LONG_LONG$LAYOUT; + public static MethodHandle fcntl$MH() { + return RuntimeHelper.requireNonNull(constants$0.fcntl$MH,"fcntl"); + } + public static int fcntl ( int __fd, int __cmd, Object... x2) { + var mh$ = fcntl$MH(); + try { + return (int)mh$.invokeExact(__fd, __cmd, x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle open$MH() { + return RuntimeHelper.requireNonNull(constants$0.open$MH,"open"); + } + public static int open ( Addressable __file, int __oflag, Object... x2) { + var mh$ = open$MH(); + try { + return (int)mh$.invokeExact(__file, __oflag, x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle openat$MH() { + return RuntimeHelper.requireNonNull(constants$0.openat$MH,"openat"); + } + public static int openat ( int __fd, Addressable __file, int __oflag, Object... x3) { + var mh$ = openat$MH(); + try { + return (int)mh$.invokeExact(__fd, __file, __oflag, x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle creat$MH() { + return RuntimeHelper.requireNonNull(constants$0.creat$MH,"creat"); + } + public static int creat ( Addressable __file, int __mode) { + var mh$ = creat$MH(); + try { + return (int)mh$.invokeExact(__file, __mode); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle lockf$MH() { + return RuntimeHelper.requireNonNull(constants$0.lockf$MH,"lockf"); + } + public static int lockf ( int __fd, int __cmd, long __len) { + var mh$ = lockf$MH(); + try { + return (int)mh$.invokeExact(__fd, __cmd, __len); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle posix_fadvise$MH() { + return RuntimeHelper.requireNonNull(constants$0.posix_fadvise$MH,"posix_fadvise"); + } + public static int posix_fadvise ( int __fd, long __offset, long __len, int __advise) { + var mh$ = posix_fadvise$MH(); + try { + return (int)mh$.invokeExact(__fd, __offset, __len, __advise); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle posix_fallocate$MH() { + return RuntimeHelper.requireNonNull(constants$1.posix_fallocate$MH,"posix_fallocate"); + } + public static int posix_fallocate ( int __fd, long __offset, long __len) { + var mh$ = posix_fallocate$MH(); + try { + return (int)mh$.invokeExact(__fd, __offset, __len); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static long _POSIX_C_SOURCE() { + return 200809L; + } + public static int __TIMESIZE() { + return (int)64L; + } + public static long __STDC_IEC_60559_BFP__() { + return 201404L; + } + public static long __STDC_IEC_60559_COMPLEX__() { + return 201404L; + } + public static long __STDC_ISO_10646__() { + return 201706L; + } + public static int O_NDELAY() { + return (int)2048L; + } + public static int O_FSYNC() { + return (int)1052672L; + } + public static int __O_TMPFILE() { + return (int)4259840L; + } + public static int O_DIRECTORY() { + return (int)65536L; + } + public static int O_NOFOLLOW() { + return (int)131072L; + } + public static int O_CLOEXEC() { + return (int)524288L; + } + public static int O_DSYNC() { + return (int)4096L; + } + public static int O_RSYNC() { + return (int)1052672L; + } + public static int F_SETOWN() { + return (int)8L; + } + public static int F_GETOWN() { + return (int)9L; + } + public static int FAPPEND() { + return (int)1024L; + } + public static int FFSYNC() { + return (int)1052672L; + } + public static int FASYNC() { + return (int)8192L; + } + public static int FNONBLOCK() { + return (int)2048L; + } + public static int FNDELAY() { + return (int)2048L; + } + public static int POSIX_FADV_DONTNEED() { + return (int)4L; + } + public static int POSIX_FADV_NOREUSE() { + return (int)5L; + } + public static int AT_FDCWD() { + return (int)-100L; + } + public static int __BYTE_ORDER() { + return (int)1234L; + } + public static int __FLOAT_WORD_ORDER() { + return (int)1234L; + } + public static long UTIME_NOW() { + return 1073741823L; + } + public static long UTIME_OMIT() { + return 1073741822L; + } + public static int S_IFMT() { + return (int)61440L; + } + public static int S_IFDIR() { + return (int)16384L; + } + public static int S_IFCHR() { + return (int)8192L; + } + public static int S_IFBLK() { + return (int)24576L; + } + public static int S_IFREG() { + return (int)32768L; + } + public static int S_IFIFO() { + return (int)4096L; + } + public static int S_IFLNK() { + return (int)40960L; + } + public static int S_IFSOCK() { + return (int)49152L; + } + public static int S_ISUID() { + return (int)2048L; + } + public static int S_ISGID() { + return (int)1024L; + } + public static int S_ISVTX() { + return (int)512L; + } + public static int S_IRUSR() { + return (int)256L; + } + public static int S_IWUSR() { + return (int)128L; + } + public static int S_IXUSR() { + return (int)64L; + } + public static int S_IRWXU() { + return (int)448L; + } + public static int S_IRGRP() { + return (int)32L; + } + public static int S_IWGRP() { + return (int)16L; + } + public static int S_IXGRP() { + return (int)8L; + } + public static int S_IRWXG() { + return (int)56L; + } + public static int S_IROTH() { + return (int)4L; + } + public static int S_IWOTH() { + return (int)2L; + } + public static int S_IXOTH() { + return (int)1L; + } + public static int S_IRWXO() { + return (int)7L; + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/flock.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/flock.java new file mode 100644 index 00000000..e3192d4c --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/flock.java @@ -0,0 +1,109 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.fcntl; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class flock { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_SHORT$LAYOUT.withName("l_type"), + Constants$root.C_SHORT$LAYOUT.withName("l_whence"), + MemoryLayout.paddingLayout(32), + Constants$root.C_LONG_LONG$LAYOUT.withName("l_start"), + Constants$root.C_LONG_LONG$LAYOUT.withName("l_len"), + Constants$root.C_INT$LAYOUT.withName("l_pid"), + MemoryLayout.paddingLayout(32) + ).withName("flock"); + public static MemoryLayout $LAYOUT() { + return flock.$struct$LAYOUT; + } + static final VarHandle l_type$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("l_type")); + public static VarHandle l_type$VH() { + return flock.l_type$VH; + } + public static short l_type$get(MemorySegment seg) { + return (short)flock.l_type$VH.get(seg); + } + public static void l_type$set( MemorySegment seg, short x) { + flock.l_type$VH.set(seg, x); + } + public static short l_type$get(MemorySegment seg, long index) { + return (short)flock.l_type$VH.get(seg.asSlice(index*sizeof())); + } + public static void l_type$set(MemorySegment seg, long index, short x) { + flock.l_type$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle l_whence$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("l_whence")); + public static VarHandle l_whence$VH() { + return flock.l_whence$VH; + } + public static short l_whence$get(MemorySegment seg) { + return (short)flock.l_whence$VH.get(seg); + } + public static void l_whence$set( MemorySegment seg, short x) { + flock.l_whence$VH.set(seg, x); + } + public static short l_whence$get(MemorySegment seg, long index) { + return (short)flock.l_whence$VH.get(seg.asSlice(index*sizeof())); + } + public static void l_whence$set(MemorySegment seg, long index, short x) { + flock.l_whence$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle l_start$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("l_start")); + public static VarHandle l_start$VH() { + return flock.l_start$VH; + } + public static long l_start$get(MemorySegment seg) { + return (long)flock.l_start$VH.get(seg); + } + public static void l_start$set( MemorySegment seg, long x) { + flock.l_start$VH.set(seg, x); + } + public static long l_start$get(MemorySegment seg, long index) { + return (long)flock.l_start$VH.get(seg.asSlice(index*sizeof())); + } + public static void l_start$set(MemorySegment seg, long index, long x) { + flock.l_start$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle l_len$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("l_len")); + public static VarHandle l_len$VH() { + return flock.l_len$VH; + } + public static long l_len$get(MemorySegment seg) { + return (long)flock.l_len$VH.get(seg); + } + public static void l_len$set( MemorySegment seg, long x) { + flock.l_len$VH.set(seg, x); + } + public static long l_len$get(MemorySegment seg, long index) { + return (long)flock.l_len$VH.get(seg.asSlice(index*sizeof())); + } + public static void l_len$set(MemorySegment seg, long index, long x) { + flock.l_len$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle l_pid$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("l_pid")); + public static VarHandle l_pid$VH() { + return flock.l_pid$VH; + } + public static int l_pid$get(MemorySegment seg) { + return (int)flock.l_pid$VH.get(seg); + } + public static void l_pid$set( MemorySegment seg, int x) { + flock.l_pid$VH.set(seg, x); + } + public static int l_pid$get(MemorySegment seg, long index) { + return (int)flock.l_pid$VH.get(seg.asSlice(index*sizeof())); + } + public static void l_pid$set(MemorySegment seg, long index, int x) { + flock.l_pid$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/stat.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/stat.java new file mode 100644 index 00000000..c41afa20 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/stat.java @@ -0,0 +1,234 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.fcntl; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class stat { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_LONG_LONG$LAYOUT.withName("st_dev"), + Constants$root.C_LONG_LONG$LAYOUT.withName("st_ino"), + Constants$root.C_LONG_LONG$LAYOUT.withName("st_nlink"), + Constants$root.C_INT$LAYOUT.withName("st_mode"), + Constants$root.C_INT$LAYOUT.withName("st_uid"), + Constants$root.C_INT$LAYOUT.withName("st_gid"), + Constants$root.C_INT$LAYOUT.withName("__pad0"), + Constants$root.C_LONG_LONG$LAYOUT.withName("st_rdev"), + Constants$root.C_LONG_LONG$LAYOUT.withName("st_size"), + Constants$root.C_LONG_LONG$LAYOUT.withName("st_blksize"), + Constants$root.C_LONG_LONG$LAYOUT.withName("st_blocks"), + MemoryLayout.structLayout( + Constants$root.C_LONG_LONG$LAYOUT.withName("tv_sec"), + Constants$root.C_LONG_LONG$LAYOUT.withName("tv_nsec") + ).withName("st_atim"), + MemoryLayout.structLayout( + Constants$root.C_LONG_LONG$LAYOUT.withName("tv_sec"), + Constants$root.C_LONG_LONG$LAYOUT.withName("tv_nsec") + ).withName("st_mtim"), + MemoryLayout.structLayout( + Constants$root.C_LONG_LONG$LAYOUT.withName("tv_sec"), + Constants$root.C_LONG_LONG$LAYOUT.withName("tv_nsec") + ).withName("st_ctim"), + MemoryLayout.sequenceLayout(3, Constants$root.C_LONG_LONG$LAYOUT).withName("__glibc_reserved") + ).withName("stat"); + public static MemoryLayout $LAYOUT() { + return stat.$struct$LAYOUT; + } + static final VarHandle st_dev$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_dev")); + public static VarHandle st_dev$VH() { + return stat.st_dev$VH; + } + public static long st_dev$get(MemorySegment seg) { + return (long)stat.st_dev$VH.get(seg); + } + public static void st_dev$set( MemorySegment seg, long x) { + stat.st_dev$VH.set(seg, x); + } + public static long st_dev$get(MemorySegment seg, long index) { + return (long)stat.st_dev$VH.get(seg.asSlice(index*sizeof())); + } + public static void st_dev$set(MemorySegment seg, long index, long x) { + stat.st_dev$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle st_ino$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_ino")); + public static VarHandle st_ino$VH() { + return stat.st_ino$VH; + } + public static long st_ino$get(MemorySegment seg) { + return (long)stat.st_ino$VH.get(seg); + } + public static void st_ino$set( MemorySegment seg, long x) { + stat.st_ino$VH.set(seg, x); + } + public static long st_ino$get(MemorySegment seg, long index) { + return (long)stat.st_ino$VH.get(seg.asSlice(index*sizeof())); + } + public static void st_ino$set(MemorySegment seg, long index, long x) { + stat.st_ino$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle st_nlink$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_nlink")); + public static VarHandle st_nlink$VH() { + return stat.st_nlink$VH; + } + public static long st_nlink$get(MemorySegment seg) { + return (long)stat.st_nlink$VH.get(seg); + } + public static void st_nlink$set( MemorySegment seg, long x) { + stat.st_nlink$VH.set(seg, x); + } + public static long st_nlink$get(MemorySegment seg, long index) { + return (long)stat.st_nlink$VH.get(seg.asSlice(index*sizeof())); + } + public static void st_nlink$set(MemorySegment seg, long index, long x) { + stat.st_nlink$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle st_mode$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_mode")); + public static VarHandle st_mode$VH() { + return stat.st_mode$VH; + } + public static int st_mode$get(MemorySegment seg) { + return (int)stat.st_mode$VH.get(seg); + } + public static void st_mode$set( MemorySegment seg, int x) { + stat.st_mode$VH.set(seg, x); + } + public static int st_mode$get(MemorySegment seg, long index) { + return (int)stat.st_mode$VH.get(seg.asSlice(index*sizeof())); + } + public static void st_mode$set(MemorySegment seg, long index, int x) { + stat.st_mode$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle st_uid$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_uid")); + public static VarHandle st_uid$VH() { + return stat.st_uid$VH; + } + public static int st_uid$get(MemorySegment seg) { + return (int)stat.st_uid$VH.get(seg); + } + public static void st_uid$set( MemorySegment seg, int x) { + stat.st_uid$VH.set(seg, x); + } + public static int st_uid$get(MemorySegment seg, long index) { + return (int)stat.st_uid$VH.get(seg.asSlice(index*sizeof())); + } + public static void st_uid$set(MemorySegment seg, long index, int x) { + stat.st_uid$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle st_gid$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_gid")); + public static VarHandle st_gid$VH() { + return stat.st_gid$VH; + } + public static int st_gid$get(MemorySegment seg) { + return (int)stat.st_gid$VH.get(seg); + } + public static void st_gid$set( MemorySegment seg, int x) { + stat.st_gid$VH.set(seg, x); + } + public static int st_gid$get(MemorySegment seg, long index) { + return (int)stat.st_gid$VH.get(seg.asSlice(index*sizeof())); + } + public static void st_gid$set(MemorySegment seg, long index, int x) { + stat.st_gid$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle __pad0$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("__pad0")); + public static VarHandle __pad0$VH() { + return stat.__pad0$VH; + } + public static int __pad0$get(MemorySegment seg) { + return (int)stat.__pad0$VH.get(seg); + } + public static void __pad0$set( MemorySegment seg, int x) { + stat.__pad0$VH.set(seg, x); + } + public static int __pad0$get(MemorySegment seg, long index) { + return (int)stat.__pad0$VH.get(seg.asSlice(index*sizeof())); + } + public static void __pad0$set(MemorySegment seg, long index, int x) { + stat.__pad0$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle st_rdev$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_rdev")); + public static VarHandle st_rdev$VH() { + return stat.st_rdev$VH; + } + public static long st_rdev$get(MemorySegment seg) { + return (long)stat.st_rdev$VH.get(seg); + } + public static void st_rdev$set( MemorySegment seg, long x) { + stat.st_rdev$VH.set(seg, x); + } + public static long st_rdev$get(MemorySegment seg, long index) { + return (long)stat.st_rdev$VH.get(seg.asSlice(index*sizeof())); + } + public static void st_rdev$set(MemorySegment seg, long index, long x) { + stat.st_rdev$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle st_size$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_size")); + public static VarHandle st_size$VH() { + return stat.st_size$VH; + } + public static long st_size$get(MemorySegment seg) { + return (long)stat.st_size$VH.get(seg); + } + public static void st_size$set( MemorySegment seg, long x) { + stat.st_size$VH.set(seg, x); + } + public static long st_size$get(MemorySegment seg, long index) { + return (long)stat.st_size$VH.get(seg.asSlice(index*sizeof())); + } + public static void st_size$set(MemorySegment seg, long index, long x) { + stat.st_size$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle st_blksize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_blksize")); + public static VarHandle st_blksize$VH() { + return stat.st_blksize$VH; + } + public static long st_blksize$get(MemorySegment seg) { + return (long)stat.st_blksize$VH.get(seg); + } + public static void st_blksize$set( MemorySegment seg, long x) { + stat.st_blksize$VH.set(seg, x); + } + public static long st_blksize$get(MemorySegment seg, long index) { + return (long)stat.st_blksize$VH.get(seg.asSlice(index*sizeof())); + } + public static void st_blksize$set(MemorySegment seg, long index, long x) { + stat.st_blksize$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle st_blocks$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_blocks")); + public static VarHandle st_blocks$VH() { + return stat.st_blocks$VH; + } + public static long st_blocks$get(MemorySegment seg) { + return (long)stat.st_blocks$VH.get(seg); + } + public static void st_blocks$set( MemorySegment seg, long x) { + stat.st_blocks$VH.set(seg, x); + } + public static long st_blocks$get(MemorySegment seg, long index) { + return (long)stat.st_blocks$VH.get(seg.asSlice(index*sizeof())); + } + public static void st_blocks$set(MemorySegment seg, long index, long x) { + stat.st_blocks$VH.set(seg.asSlice(index*sizeof()), x); + } + public static MemorySegment st_atim$slice(MemorySegment seg) { + return seg.asSlice(72, 16); + } + public static MemorySegment st_mtim$slice(MemorySegment seg) { + return seg.asSlice(88, 16); + } + public static MemorySegment st_ctim$slice(MemorySegment seg) { + return seg.asSlice(104, 16); + } + public static MemorySegment __glibc_reserved$slice(MemorySegment seg) { + return seg.asSlice(120, 24); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/timespec.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/timespec.java new file mode 100644 index 00000000..5dae8dc0 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/timespec.java @@ -0,0 +1,56 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.fcntl; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class timespec { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_LONG_LONG$LAYOUT.withName("tv_sec"), + Constants$root.C_LONG_LONG$LAYOUT.withName("tv_nsec") + ).withName("timespec"); + public static MemoryLayout $LAYOUT() { + return timespec.$struct$LAYOUT; + } + static final VarHandle tv_sec$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("tv_sec")); + public static VarHandle tv_sec$VH() { + return timespec.tv_sec$VH; + } + public static long tv_sec$get(MemorySegment seg) { + return (long)timespec.tv_sec$VH.get(seg); + } + public static void tv_sec$set( MemorySegment seg, long x) { + timespec.tv_sec$VH.set(seg, x); + } + public static long tv_sec$get(MemorySegment seg, long index) { + return (long)timespec.tv_sec$VH.get(seg.asSlice(index*sizeof())); + } + public static void tv_sec$set(MemorySegment seg, long index, long x) { + timespec.tv_sec$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle tv_nsec$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("tv_nsec")); + public static VarHandle tv_nsec$VH() { + return timespec.tv_nsec$VH; + } + public static long tv_nsec$get(MemorySegment seg) { + return (long)timespec.tv_nsec$VH.get(seg); + } + public static void tv_nsec$set( MemorySegment seg, long x) { + timespec.tv_nsec$VH.set(seg, x); + } + public static long tv_nsec$get(MemorySegment seg, long index) { + return (long)timespec.tv_nsec$VH.get(seg.asSlice(index*sizeof())); + } + public static void tv_nsec$set(MemorySegment seg, long index, long x) { + timespec.tv_nsec$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/Constants$root.java new file mode 100644 index 00000000..c9e48345 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.ioctl; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/RuntimeHelper.java new file mode 100644 index 00000000..e7740016 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/RuntimeHelper.java @@ -0,0 +1,216 @@ +package net.codecrete.usb.linux.gen.ioctl; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/constants$0.java new file mode 100644 index 00000000..e68a7892 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/constants$0.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.ioctl; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor ioctl$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle ioctl$MH = RuntimeHelper.downcallHandleVariadic( + "ioctl", + constants$0.ioctl$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/ioctl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/ioctl.java new file mode 100644 index 00000000..795090b8 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/ioctl.java @@ -0,0 +1,758 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.ioctl; + +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.*; +public class ioctl { + + /* package-private */ ioctl() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static int _SYS_IOCTL_H() { + return (int)1L; + } + public static int _FEATURES_H() { + return (int)1L; + } + public static int _DEFAULT_SOURCE() { + return (int)1L; + } + public static int __GLIBC_USE_ISOC2X() { + return (int)0L; + } + public static int __USE_ISOC11() { + return (int)1L; + } + public static int __USE_ISOC99() { + return (int)1L; + } + public static int __USE_ISOC95() { + return (int)1L; + } + public static int __USE_POSIX_IMPLICITLY() { + return (int)1L; + } + public static int _POSIX_SOURCE() { + return (int)1L; + } + public static int __USE_POSIX() { + return (int)1L; + } + public static int __USE_POSIX2() { + return (int)1L; + } + public static int __USE_POSIX199309() { + return (int)1L; + } + public static int __USE_POSIX199506() { + return (int)1L; + } + public static int __USE_XOPEN2K() { + return (int)1L; + } + public static int __USE_XOPEN2K8() { + return (int)1L; + } + public static int _ATFILE_SOURCE() { + return (int)1L; + } + public static int __WORDSIZE() { + return (int)64L; + } + public static int __WORDSIZE_TIME64_COMPAT32() { + return (int)1L; + } + public static int __SYSCALL_WORDSIZE() { + return (int)64L; + } + public static int __USE_MISC() { + return (int)1L; + } + public static int __USE_ATFILE() { + return (int)1L; + } + public static int __USE_FORTIFY_LEVEL() { + return (int)0L; + } + public static int __GLIBC_USE_DEPRECATED_GETS() { + return (int)0L; + } + public static int __GLIBC_USE_DEPRECATED_SCANF() { + return (int)0L; + } + public static int _STDC_PREDEF_H() { + return (int)1L; + } + public static int __STDC_IEC_559__() { + return (int)1L; + } + public static int __STDC_IEC_559_COMPLEX__() { + return (int)1L; + } + public static int __GNU_LIBRARY__() { + return (int)6L; + } + public static int __GLIBC__() { + return (int)2L; + } + public static int __GLIBC_MINOR__() { + return (int)35L; + } + public static int _SYS_CDEFS_H() { + return (int)1L; + } + public static int __glibc_c99_flexarr_available() { + return (int)1L; + } + public static int __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI() { + return (int)0L; + } + public static int __HAVE_GENERIC_SELECTION() { + return (int)1L; + } + public static int _IOC_NRBITS() { + return (int)8L; + } + public static int _IOC_TYPEBITS() { + return (int)8L; + } + public static int _IOC_SIZEBITS() { + return (int)14L; + } + public static int _IOC_DIRBITS() { + return (int)2L; + } + public static int _IOC_NRSHIFT() { + return (int)0L; + } + public static int TCGETS() { + return (int)21505L; + } + public static int TCSETS() { + return (int)21506L; + } + public static int TCSETSW() { + return (int)21507L; + } + public static int TCSETSF() { + return (int)21508L; + } + public static int TCGETA() { + return (int)21509L; + } + public static int TCSETA() { + return (int)21510L; + } + public static int TCSETAW() { + return (int)21511L; + } + public static int TCSETAF() { + return (int)21512L; + } + public static int TCSBRK() { + return (int)21513L; + } + public static int TCXONC() { + return (int)21514L; + } + public static int TCFLSH() { + return (int)21515L; + } + public static int TIOCEXCL() { + return (int)21516L; + } + public static int TIOCNXCL() { + return (int)21517L; + } + public static int TIOCSCTTY() { + return (int)21518L; + } + public static int TIOCGPGRP() { + return (int)21519L; + } + public static int TIOCSPGRP() { + return (int)21520L; + } + public static int TIOCOUTQ() { + return (int)21521L; + } + public static int TIOCSTI() { + return (int)21522L; + } + public static int TIOCGWINSZ() { + return (int)21523L; + } + public static int TIOCSWINSZ() { + return (int)21524L; + } + public static int TIOCMGET() { + return (int)21525L; + } + public static int TIOCMBIS() { + return (int)21526L; + } + public static int TIOCMBIC() { + return (int)21527L; + } + public static int TIOCMSET() { + return (int)21528L; + } + public static int TIOCGSOFTCAR() { + return (int)21529L; + } + public static int TIOCSSOFTCAR() { + return (int)21530L; + } + public static int FIONREAD() { + return (int)21531L; + } + public static int TIOCLINUX() { + return (int)21532L; + } + public static int TIOCCONS() { + return (int)21533L; + } + public static int TIOCGSERIAL() { + return (int)21534L; + } + public static int TIOCSSERIAL() { + return (int)21535L; + } + public static int TIOCPKT() { + return (int)21536L; + } + public static int FIONBIO() { + return (int)21537L; + } + public static int TIOCNOTTY() { + return (int)21538L; + } + public static int TIOCSETD() { + return (int)21539L; + } + public static int TIOCGETD() { + return (int)21540L; + } + public static int TCSBRKP() { + return (int)21541L; + } + public static int TIOCSBRK() { + return (int)21543L; + } + public static int TIOCCBRK() { + return (int)21544L; + } + public static int TIOCGSID() { + return (int)21545L; + } + public static int TIOCGRS485() { + return (int)21550L; + } + public static int TIOCSRS485() { + return (int)21551L; + } + public static int TCGETX() { + return (int)21554L; + } + public static int TCSETX() { + return (int)21555L; + } + public static int TCSETXF() { + return (int)21556L; + } + public static int TCSETXW() { + return (int)21557L; + } + public static int TIOCVHANGUP() { + return (int)21559L; + } + public static int FIONCLEX() { + return (int)21584L; + } + public static int FIOCLEX() { + return (int)21585L; + } + public static int FIOASYNC() { + return (int)21586L; + } + public static int TIOCSERCONFIG() { + return (int)21587L; + } + public static int TIOCSERGWILD() { + return (int)21588L; + } + public static int TIOCSERSWILD() { + return (int)21589L; + } + public static int TIOCGLCKTRMIOS() { + return (int)21590L; + } + public static int TIOCSLCKTRMIOS() { + return (int)21591L; + } + public static int TIOCSERGSTRUCT() { + return (int)21592L; + } + public static int TIOCSERGETLSR() { + return (int)21593L; + } + public static int TIOCSERGETMULTI() { + return (int)21594L; + } + public static int TIOCSERSETMULTI() { + return (int)21595L; + } + public static int TIOCMIWAIT() { + return (int)21596L; + } + public static int TIOCGICOUNT() { + return (int)21597L; + } + public static int FIOQSIZE() { + return (int)21600L; + } + public static int TIOCPKT_DATA() { + return (int)0L; + } + public static int TIOCPKT_FLUSHREAD() { + return (int)1L; + } + public static int TIOCPKT_FLUSHWRITE() { + return (int)2L; + } + public static int TIOCPKT_STOP() { + return (int)4L; + } + public static int TIOCPKT_START() { + return (int)8L; + } + public static int TIOCPKT_NOSTOP() { + return (int)16L; + } + public static int TIOCPKT_DOSTOP() { + return (int)32L; + } + public static int TIOCPKT_IOCTL() { + return (int)64L; + } + public static int TIOCSER_TEMT() { + return (int)1L; + } + public static int SIOCADDRT() { + return (int)35083L; + } + public static int SIOCDELRT() { + return (int)35084L; + } + public static int SIOCRTMSG() { + return (int)35085L; + } + public static int SIOCGIFNAME() { + return (int)35088L; + } + public static int SIOCSIFLINK() { + return (int)35089L; + } + public static int SIOCGIFCONF() { + return (int)35090L; + } + public static int SIOCGIFFLAGS() { + return (int)35091L; + } + public static int SIOCSIFFLAGS() { + return (int)35092L; + } + public static int SIOCGIFADDR() { + return (int)35093L; + } + public static int SIOCSIFADDR() { + return (int)35094L; + } + public static int SIOCGIFDSTADDR() { + return (int)35095L; + } + public static int SIOCSIFDSTADDR() { + return (int)35096L; + } + public static int SIOCGIFBRDADDR() { + return (int)35097L; + } + public static int SIOCSIFBRDADDR() { + return (int)35098L; + } + public static int SIOCGIFNETMASK() { + return (int)35099L; + } + public static int SIOCSIFNETMASK() { + return (int)35100L; + } + public static int SIOCGIFMETRIC() { + return (int)35101L; + } + public static int SIOCSIFMETRIC() { + return (int)35102L; + } + public static int SIOCGIFMEM() { + return (int)35103L; + } + public static int SIOCSIFMEM() { + return (int)35104L; + } + public static int SIOCGIFMTU() { + return (int)35105L; + } + public static int SIOCSIFMTU() { + return (int)35106L; + } + public static int SIOCSIFNAME() { + return (int)35107L; + } + public static int SIOCSIFHWADDR() { + return (int)35108L; + } + public static int SIOCGIFENCAP() { + return (int)35109L; + } + public static int SIOCSIFENCAP() { + return (int)35110L; + } + public static int SIOCGIFHWADDR() { + return (int)35111L; + } + public static int SIOCGIFSLAVE() { + return (int)35113L; + } + public static int SIOCSIFSLAVE() { + return (int)35120L; + } + public static int SIOCADDMULTI() { + return (int)35121L; + } + public static int SIOCDELMULTI() { + return (int)35122L; + } + public static int SIOCGIFINDEX() { + return (int)35123L; + } + public static int SIOCSIFPFLAGS() { + return (int)35124L; + } + public static int SIOCGIFPFLAGS() { + return (int)35125L; + } + public static int SIOCDIFADDR() { + return (int)35126L; + } + public static int SIOCSIFHWBROADCAST() { + return (int)35127L; + } + public static int SIOCGIFCOUNT() { + return (int)35128L; + } + public static int SIOCGIFBR() { + return (int)35136L; + } + public static int SIOCSIFBR() { + return (int)35137L; + } + public static int SIOCGIFTXQLEN() { + return (int)35138L; + } + public static int SIOCSIFTXQLEN() { + return (int)35139L; + } + public static int SIOCDARP() { + return (int)35155L; + } + public static int SIOCGARP() { + return (int)35156L; + } + public static int SIOCSARP() { + return (int)35157L; + } + public static int SIOCDRARP() { + return (int)35168L; + } + public static int SIOCGRARP() { + return (int)35169L; + } + public static int SIOCSRARP() { + return (int)35170L; + } + public static int SIOCGIFMAP() { + return (int)35184L; + } + public static int SIOCSIFMAP() { + return (int)35185L; + } + public static int SIOCADDDLCI() { + return (int)35200L; + } + public static int SIOCDELDLCI() { + return (int)35201L; + } + public static int SIOCDEVPRIVATE() { + return (int)35312L; + } + public static int SIOCPROTOPRIVATE() { + return (int)35296L; + } + public static int NCC() { + return (int)8L; + } + public static int TIOCM_LE() { + return (int)1L; + } + public static int TIOCM_DTR() { + return (int)2L; + } + public static int TIOCM_RTS() { + return (int)4L; + } + public static int TIOCM_ST() { + return (int)8L; + } + public static int TIOCM_SR() { + return (int)16L; + } + public static int TIOCM_CTS() { + return (int)32L; + } + public static int TIOCM_CAR() { + return (int)64L; + } + public static int TIOCM_RNG() { + return (int)128L; + } + public static int TIOCM_DSR() { + return (int)256L; + } + public static int N_TTY() { + return (int)0L; + } + public static int N_SLIP() { + return (int)1L; + } + public static int N_MOUSE() { + return (int)2L; + } + public static int N_PPP() { + return (int)3L; + } + public static int N_STRIP() { + return (int)4L; + } + public static int N_AX25() { + return (int)5L; + } + public static int N_X25() { + return (int)6L; + } + public static int N_6PACK() { + return (int)7L; + } + public static int N_MASC() { + return (int)8L; + } + public static int N_R3964() { + return (int)9L; + } + public static int N_PROFIBUS_FDL() { + return (int)10L; + } + public static int N_IRDA() { + return (int)11L; + } + public static int N_SMSBLOCK() { + return (int)12L; + } + public static int N_HDLC() { + return (int)13L; + } + public static int N_SYNC_PPP() { + return (int)14L; + } + public static int N_HCI() { + return (int)15L; + } + public static int CERASE() { + return (int)127L; + } + public static int CMIN() { + return (int)1L; + } + public static int CQUIT() { + return (int)28L; + } + public static int CTIME() { + return (int)0L; + } + public static MethodHandle ioctl$MH() { + return RuntimeHelper.requireNonNull(constants$0.ioctl$MH,"ioctl"); + } + public static int ioctl ( int __fd, long __request, Object... x2) { + var mh$ = ioctl$MH(); + try { + return (int)mh$.invokeExact(__fd, __request, x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static long _POSIX_C_SOURCE() { + return 200809L; + } + public static int __TIMESIZE() { + return (int)64L; + } + public static long __STDC_IEC_60559_BFP__() { + return 201404L; + } + public static long __STDC_IEC_60559_COMPLEX__() { + return 201404L; + } + public static long __STDC_ISO_10646__() { + return 201706L; + } + public static int _IOC_NRMASK() { + return (int)255L; + } + public static int _IOC_TYPEMASK() { + return (int)255L; + } + public static int _IOC_SIZEMASK() { + return (int)16383L; + } + public static int _IOC_DIRMASK() { + return (int)3L; + } + public static int _IOC_TYPESHIFT() { + return (int)8L; + } + public static int _IOC_SIZESHIFT() { + return (int)16L; + } + public static int _IOC_DIRSHIFT() { + return (int)30L; + } + public static int _IOC_NONE() { + return (int)0L; + } + public static int _IOC_WRITE() { + return (int)1L; + } + public static int _IOC_READ() { + return (int)2L; + } + public static int IOC_IN() { + return (int)1073741824L; + } + public static int IOC_OUT() { + return (int)2147483648L; + } + public static int IOC_INOUT() { + return (int)3221225472L; + } + public static int IOCSIZE_MASK() { + return (int)1073676288L; + } + public static int IOCSIZE_SHIFT() { + return (int)16L; + } + public static int TIOCINQ() { + return (int)21531L; + } + public static long TIOCGPTN() { + return 2147767344L; + } + public static long TIOCSPTLCK() { + return 1074025521L; + } + public static long TIOCGDEV() { + return 2147767346L; + } + public static long TIOCSIG() { + return 1074025526L; + } + public static long TIOCGPKT() { + return 2147767352L; + } + public static long TIOCGPTLCK() { + return 2147767353L; + } + public static long TIOCGEXCL() { + return 2147767360L; + } + public static int TIOCGPTPEER() { + return (int)21569L; + } + public static int SIOGIFINDEX() { + return (int)35123L; + } + public static int TIOCM_CD() { + return (int)64L; + } + public static int TIOCM_RI() { + return (int)128L; + } + public static int CEOF() { + return (int)4L; + } + public static int CEOL() { + return (int)0L; + } + public static int CINTR() { + return (int)3L; + } + public static int CSTATUS() { + return (int)0L; + } + public static int CKILL() { + return (int)21L; + } + public static int CSUSP() { + return (int)26L; + } + public static int CDSUSP() { + return (int)25L; + } + public static int CSTART() { + return (int)17L; + } + public static int CSTOP() { + return (int)19L; + } + public static int CLNEXT() { + return (int)22L; + } + public static int CDISCARD() { + return (int)15L; + } + public static int CWERASE() { + return (int)23L; + } + public static int CREPRINT() { + return (int)18L; + } + public static int CEOT() { + return (int)4L; + } + public static int CBRK() { + return (int)0L; + } + public static int CRPRNT() { + return (int)18L; + } + public static int CFLUSH() { + return (int)15L; + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/termio.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/termio.java new file mode 100644 index 00000000..500ef096 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/termio.java @@ -0,0 +1,112 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.ioctl; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class termio { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_SHORT$LAYOUT.withName("c_iflag"), + Constants$root.C_SHORT$LAYOUT.withName("c_oflag"), + Constants$root.C_SHORT$LAYOUT.withName("c_cflag"), + Constants$root.C_SHORT$LAYOUT.withName("c_lflag"), + Constants$root.C_CHAR$LAYOUT.withName("c_line"), + MemoryLayout.sequenceLayout(8, Constants$root.C_CHAR$LAYOUT).withName("c_cc"), + MemoryLayout.paddingLayout(8) + ).withName("termio"); + public static MemoryLayout $LAYOUT() { + return termio.$struct$LAYOUT; + } + static final VarHandle c_iflag$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("c_iflag")); + public static VarHandle c_iflag$VH() { + return termio.c_iflag$VH; + } + public static short c_iflag$get(MemorySegment seg) { + return (short)termio.c_iflag$VH.get(seg); + } + public static void c_iflag$set( MemorySegment seg, short x) { + termio.c_iflag$VH.set(seg, x); + } + public static short c_iflag$get(MemorySegment seg, long index) { + return (short)termio.c_iflag$VH.get(seg.asSlice(index*sizeof())); + } + public static void c_iflag$set(MemorySegment seg, long index, short x) { + termio.c_iflag$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle c_oflag$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("c_oflag")); + public static VarHandle c_oflag$VH() { + return termio.c_oflag$VH; + } + public static short c_oflag$get(MemorySegment seg) { + return (short)termio.c_oflag$VH.get(seg); + } + public static void c_oflag$set( MemorySegment seg, short x) { + termio.c_oflag$VH.set(seg, x); + } + public static short c_oflag$get(MemorySegment seg, long index) { + return (short)termio.c_oflag$VH.get(seg.asSlice(index*sizeof())); + } + public static void c_oflag$set(MemorySegment seg, long index, short x) { + termio.c_oflag$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle c_cflag$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("c_cflag")); + public static VarHandle c_cflag$VH() { + return termio.c_cflag$VH; + } + public static short c_cflag$get(MemorySegment seg) { + return (short)termio.c_cflag$VH.get(seg); + } + public static void c_cflag$set( MemorySegment seg, short x) { + termio.c_cflag$VH.set(seg, x); + } + public static short c_cflag$get(MemorySegment seg, long index) { + return (short)termio.c_cflag$VH.get(seg.asSlice(index*sizeof())); + } + public static void c_cflag$set(MemorySegment seg, long index, short x) { + termio.c_cflag$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle c_lflag$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("c_lflag")); + public static VarHandle c_lflag$VH() { + return termio.c_lflag$VH; + } + public static short c_lflag$get(MemorySegment seg) { + return (short)termio.c_lflag$VH.get(seg); + } + public static void c_lflag$set( MemorySegment seg, short x) { + termio.c_lflag$VH.set(seg, x); + } + public static short c_lflag$get(MemorySegment seg, long index) { + return (short)termio.c_lflag$VH.get(seg.asSlice(index*sizeof())); + } + public static void c_lflag$set(MemorySegment seg, long index, short x) { + termio.c_lflag$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle c_line$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("c_line")); + public static VarHandle c_line$VH() { + return termio.c_line$VH; + } + public static byte c_line$get(MemorySegment seg) { + return (byte)termio.c_line$VH.get(seg); + } + public static void c_line$set( MemorySegment seg, byte x) { + termio.c_line$VH.set(seg, x); + } + public static byte c_line$get(MemorySegment seg, long index) { + return (byte)termio.c_line$VH.get(seg.asSlice(index*sizeof())); + } + public static void c_line$set(MemorySegment seg, long index, byte x) { + termio.c_line$VH.set(seg.asSlice(index*sizeof()), x); + } + public static MemorySegment c_cc$slice(MemorySegment seg) { + return seg.asSlice(9, 8); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/winsize.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/winsize.java new file mode 100644 index 00000000..d05924c2 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/winsize.java @@ -0,0 +1,90 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.ioctl; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class winsize { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_SHORT$LAYOUT.withName("ws_row"), + Constants$root.C_SHORT$LAYOUT.withName("ws_col"), + Constants$root.C_SHORT$LAYOUT.withName("ws_xpixel"), + Constants$root.C_SHORT$LAYOUT.withName("ws_ypixel") + ).withName("winsize"); + public static MemoryLayout $LAYOUT() { + return winsize.$struct$LAYOUT; + } + static final VarHandle ws_row$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ws_row")); + public static VarHandle ws_row$VH() { + return winsize.ws_row$VH; + } + public static short ws_row$get(MemorySegment seg) { + return (short)winsize.ws_row$VH.get(seg); + } + public static void ws_row$set( MemorySegment seg, short x) { + winsize.ws_row$VH.set(seg, x); + } + public static short ws_row$get(MemorySegment seg, long index) { + return (short)winsize.ws_row$VH.get(seg.asSlice(index*sizeof())); + } + public static void ws_row$set(MemorySegment seg, long index, short x) { + winsize.ws_row$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle ws_col$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ws_col")); + public static VarHandle ws_col$VH() { + return winsize.ws_col$VH; + } + public static short ws_col$get(MemorySegment seg) { + return (short)winsize.ws_col$VH.get(seg); + } + public static void ws_col$set( MemorySegment seg, short x) { + winsize.ws_col$VH.set(seg, x); + } + public static short ws_col$get(MemorySegment seg, long index) { + return (short)winsize.ws_col$VH.get(seg.asSlice(index*sizeof())); + } + public static void ws_col$set(MemorySegment seg, long index, short x) { + winsize.ws_col$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle ws_xpixel$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ws_xpixel")); + public static VarHandle ws_xpixel$VH() { + return winsize.ws_xpixel$VH; + } + public static short ws_xpixel$get(MemorySegment seg) { + return (short)winsize.ws_xpixel$VH.get(seg); + } + public static void ws_xpixel$set( MemorySegment seg, short x) { + winsize.ws_xpixel$VH.set(seg, x); + } + public static short ws_xpixel$get(MemorySegment seg, long index) { + return (short)winsize.ws_xpixel$VH.get(seg.asSlice(index*sizeof())); + } + public static void ws_xpixel$set(MemorySegment seg, long index, short x) { + winsize.ws_xpixel$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle ws_ypixel$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ws_ypixel")); + public static VarHandle ws_ypixel$VH() { + return winsize.ws_ypixel$VH; + } + public static short ws_ypixel$get(MemorySegment seg) { + return (short)winsize.ws_ypixel$VH.get(seg); + } + public static void ws_ypixel$set( MemorySegment seg, short x) { + winsize.ws_ypixel$VH.set(seg, x); + } + public static short ws_ypixel$get(MemorySegment seg, long index) { + return (short)winsize.ws_ypixel$VH.get(seg.asSlice(index*sizeof())); + } + public static void ws_ypixel$set(MemorySegment seg, long index, short x) { + winsize.ws_ypixel$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/Constants$root.java new file mode 100644 index 00000000..1fe4e3c0 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/RuntimeHelper.java new file mode 100644 index 00000000..b771271b --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/RuntimeHelper.java @@ -0,0 +1,216 @@ +package net.codecrete.usb.linux.gen.unistd; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/__fsid_t.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/__fsid_t.java new file mode 100644 index 00000000..990f9f6b --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/__fsid_t.java @@ -0,0 +1,25 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.*; +public class __fsid_t { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + MemoryLayout.sequenceLayout(2, Constants$root.C_INT$LAYOUT).withName("__val") + ); + public static MemoryLayout $LAYOUT() { + return __fsid_t.$struct$LAYOUT; + } + public static MemorySegment __val$slice(MemorySegment seg) { + return seg.asSlice(0, 8); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java new file mode 100644 index 00000000..4535a379 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java @@ -0,0 +1,61 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor access$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle access$MH = RuntimeHelper.downcallHandle( + "access", + constants$0.access$FUNC + ); + static final FunctionDescriptor faccessat$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle faccessat$MH = RuntimeHelper.downcallHandle( + "faccessat", + constants$0.faccessat$FUNC + ); + static final FunctionDescriptor lseek$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle lseek$MH = RuntimeHelper.downcallHandle( + "lseek", + constants$0.lseek$FUNC + ); + static final FunctionDescriptor close$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle close$MH = RuntimeHelper.downcallHandle( + "close", + constants$0.close$FUNC + ); + static final FunctionDescriptor closefrom$FUNC = FunctionDescriptor.ofVoid( + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle closefrom$MH = RuntimeHelper.downcallHandle( + "closefrom", + constants$0.closefrom$FUNC + ); + static final FunctionDescriptor read$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle read$MH = RuntimeHelper.downcallHandle( + "read", + constants$0.read$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$1.java new file mode 100644 index 00000000..0cc4fe56 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$1.java @@ -0,0 +1,61 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$1 { + + static final FunctionDescriptor write$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle write$MH = RuntimeHelper.downcallHandle( + "write", + constants$1.write$FUNC + ); + static final FunctionDescriptor pread$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle pread$MH = RuntimeHelper.downcallHandle( + "pread", + constants$1.pread$FUNC + ); + static final FunctionDescriptor pwrite$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle pwrite$MH = RuntimeHelper.downcallHandle( + "pwrite", + constants$1.pwrite$FUNC + ); + static final FunctionDescriptor pipe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle pipe$MH = RuntimeHelper.downcallHandle( + "pipe", + constants$1.pipe$FUNC + ); + static final FunctionDescriptor alarm$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle alarm$MH = RuntimeHelper.downcallHandle( + "alarm", + constants$1.alarm$FUNC + ); + static final FunctionDescriptor sleep$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle sleep$MH = RuntimeHelper.downcallHandle( + "sleep", + constants$1.sleep$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$10.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$10.java new file mode 100644 index 00000000..64c7caab --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$10.java @@ -0,0 +1,52 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$10 { + + static final FunctionDescriptor vfork$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle vfork$MH = RuntimeHelper.downcallHandle( + "vfork", + constants$10.vfork$FUNC + ); + static final FunctionDescriptor ttyname$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle ttyname$MH = RuntimeHelper.downcallHandle( + "ttyname", + constants$10.ttyname$FUNC + ); + static final FunctionDescriptor ttyname_r$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle ttyname_r$MH = RuntimeHelper.downcallHandle( + "ttyname_r", + constants$10.ttyname_r$FUNC + ); + static final FunctionDescriptor isatty$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle isatty$MH = RuntimeHelper.downcallHandle( + "isatty", + constants$10.isatty$FUNC + ); + static final FunctionDescriptor ttyslot$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle ttyslot$MH = RuntimeHelper.downcallHandle( + "ttyslot", + constants$10.ttyslot$FUNC + ); + static final FunctionDescriptor link$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle link$MH = RuntimeHelper.downcallHandle( + "link", + constants$10.link$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$11.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$11.java new file mode 100644 index 00000000..4dc75380 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$11.java @@ -0,0 +1,65 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$11 { + + static final FunctionDescriptor linkat$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle linkat$MH = RuntimeHelper.downcallHandle( + "linkat", + constants$11.linkat$FUNC + ); + static final FunctionDescriptor symlink$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle symlink$MH = RuntimeHelper.downcallHandle( + "symlink", + constants$11.symlink$FUNC + ); + static final FunctionDescriptor readlink$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle readlink$MH = RuntimeHelper.downcallHandle( + "readlink", + constants$11.readlink$FUNC + ); + static final FunctionDescriptor symlinkat$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle symlinkat$MH = RuntimeHelper.downcallHandle( + "symlinkat", + constants$11.symlinkat$FUNC + ); + static final FunctionDescriptor readlinkat$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle readlinkat$MH = RuntimeHelper.downcallHandle( + "readlinkat", + constants$11.readlinkat$FUNC + ); + static final FunctionDescriptor unlink$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle unlink$MH = RuntimeHelper.downcallHandle( + "unlink", + constants$11.unlink$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$12.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$12.java new file mode 100644 index 00000000..b73d5e46 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$12.java @@ -0,0 +1,55 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$12 { + + static final FunctionDescriptor unlinkat$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle unlinkat$MH = RuntimeHelper.downcallHandle( + "unlinkat", + constants$12.unlinkat$FUNC + ); + static final FunctionDescriptor rmdir$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle rmdir$MH = RuntimeHelper.downcallHandle( + "rmdir", + constants$12.rmdir$FUNC + ); + static final FunctionDescriptor tcgetpgrp$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle tcgetpgrp$MH = RuntimeHelper.downcallHandle( + "tcgetpgrp", + constants$12.tcgetpgrp$FUNC + ); + static final FunctionDescriptor tcsetpgrp$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle tcsetpgrp$MH = RuntimeHelper.downcallHandle( + "tcsetpgrp", + constants$12.tcsetpgrp$FUNC + ); + static final FunctionDescriptor getlogin$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT); + static final MethodHandle getlogin$MH = RuntimeHelper.downcallHandle( + "getlogin", + constants$12.getlogin$FUNC + ); + static final FunctionDescriptor getlogin_r$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle getlogin_r$MH = RuntimeHelper.downcallHandle( + "getlogin_r", + constants$12.getlogin_r$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$13.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$13.java new file mode 100644 index 00000000..bab872f5 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$13.java @@ -0,0 +1,44 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.OfAddress; +import static java.lang.foreign.ValueLayout.OfInt; +class constants$13 { + + static final FunctionDescriptor setlogin$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle setlogin$MH = RuntimeHelper.downcallHandle( + "setlogin", + constants$13.setlogin$FUNC + ); + static final OfAddress optarg$LAYOUT = Constants$root.C_POINTER$LAYOUT; + static final VarHandle optarg$VH = constants$13.optarg$LAYOUT.varHandle(); + static final MemorySegment optarg$SEGMENT = RuntimeHelper.lookupGlobalVariable("optarg", constants$13.optarg$LAYOUT); + static final OfInt optind$LAYOUT = Constants$root.C_INT$LAYOUT; + static final VarHandle optind$VH = constants$13.optind$LAYOUT.varHandle(); + static final MemorySegment optind$SEGMENT = RuntimeHelper.lookupGlobalVariable("optind", constants$13.optind$LAYOUT); + static final OfInt opterr$LAYOUT = Constants$root.C_INT$LAYOUT; + static final VarHandle opterr$VH = constants$13.opterr$LAYOUT.varHandle(); + static final MemorySegment opterr$SEGMENT = RuntimeHelper.lookupGlobalVariable("opterr", constants$13.opterr$LAYOUT); + static final OfInt optopt$LAYOUT = Constants$root.C_INT$LAYOUT; + static final VarHandle optopt$VH = constants$13.optopt$LAYOUT.varHandle(); + static final MemorySegment optopt$SEGMENT = RuntimeHelper.lookupGlobalVariable("optopt", constants$13.optopt$LAYOUT); + static final FunctionDescriptor getopt$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle getopt$MH = RuntimeHelper.downcallHandle( + "getopt", + constants$13.getopt$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$14.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$14.java new file mode 100644 index 00000000..68193487 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$14.java @@ -0,0 +1,55 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$14 { + + static final FunctionDescriptor gethostname$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle gethostname$MH = RuntimeHelper.downcallHandle( + "gethostname", + constants$14.gethostname$FUNC + ); + static final FunctionDescriptor sethostname$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle sethostname$MH = RuntimeHelper.downcallHandle( + "sethostname", + constants$14.sethostname$FUNC + ); + static final FunctionDescriptor sethostid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle sethostid$MH = RuntimeHelper.downcallHandle( + "sethostid", + constants$14.sethostid$FUNC + ); + static final FunctionDescriptor getdomainname$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle getdomainname$MH = RuntimeHelper.downcallHandle( + "getdomainname", + constants$14.getdomainname$FUNC + ); + static final FunctionDescriptor setdomainname$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle setdomainname$MH = RuntimeHelper.downcallHandle( + "setdomainname", + constants$14.setdomainname$FUNC + ); + static final FunctionDescriptor vhangup$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle vhangup$MH = RuntimeHelper.downcallHandle( + "vhangup", + constants$14.vhangup$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$15.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$15.java new file mode 100644 index 00000000..432d2995 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$15.java @@ -0,0 +1,50 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$15 { + + static final FunctionDescriptor revoke$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle revoke$MH = RuntimeHelper.downcallHandle( + "revoke", + constants$15.revoke$FUNC + ); + static final FunctionDescriptor profil$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle profil$MH = RuntimeHelper.downcallHandle( + "profil", + constants$15.profil$FUNC + ); + static final FunctionDescriptor acct$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle acct$MH = RuntimeHelper.downcallHandle( + "acct", + constants$15.acct$FUNC + ); + static final FunctionDescriptor getusershell$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT); + static final MethodHandle getusershell$MH = RuntimeHelper.downcallHandle( + "getusershell", + constants$15.getusershell$FUNC + ); + static final FunctionDescriptor endusershell$FUNC = FunctionDescriptor.ofVoid(); + static final MethodHandle endusershell$MH = RuntimeHelper.downcallHandle( + "endusershell", + constants$15.endusershell$FUNC + ); + static final FunctionDescriptor setusershell$FUNC = FunctionDescriptor.ofVoid(); + static final MethodHandle setusershell$MH = RuntimeHelper.downcallHandle( + "setusershell", + constants$15.setusershell$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$16.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$16.java new file mode 100644 index 00000000..2373648b --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$16.java @@ -0,0 +1,50 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$16 { + + static final FunctionDescriptor daemon$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle daemon$MH = RuntimeHelper.downcallHandle( + "daemon", + constants$16.daemon$FUNC + ); + static final FunctionDescriptor chroot$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle chroot$MH = RuntimeHelper.downcallHandle( + "chroot", + constants$16.chroot$FUNC + ); + static final FunctionDescriptor getpass$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle getpass$MH = RuntimeHelper.downcallHandle( + "getpass", + constants$16.getpass$FUNC + ); + static final FunctionDescriptor fsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle fsync$MH = RuntimeHelper.downcallHandle( + "fsync", + constants$16.fsync$FUNC + ); + static final FunctionDescriptor gethostid$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT); + static final MethodHandle gethostid$MH = RuntimeHelper.downcallHandle( + "gethostid", + constants$16.gethostid$FUNC + ); + static final FunctionDescriptor sync$FUNC = FunctionDescriptor.ofVoid(); + static final MethodHandle sync$MH = RuntimeHelper.downcallHandle( + "sync", + constants$16.sync$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$17.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$17.java new file mode 100644 index 00000000..9e76f6e5 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$17.java @@ -0,0 +1,51 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$17 { + + static final FunctionDescriptor getpagesize$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle getpagesize$MH = RuntimeHelper.downcallHandle( + "getpagesize", + constants$17.getpagesize$FUNC + ); + static final FunctionDescriptor getdtablesize$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle getdtablesize$MH = RuntimeHelper.downcallHandle( + "getdtablesize", + constants$17.getdtablesize$FUNC + ); + static final FunctionDescriptor truncate$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle truncate$MH = RuntimeHelper.downcallHandle( + "truncate", + constants$17.truncate$FUNC + ); + static final FunctionDescriptor ftruncate$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle ftruncate$MH = RuntimeHelper.downcallHandle( + "ftruncate", + constants$17.ftruncate$FUNC + ); + static final FunctionDescriptor brk$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle brk$MH = RuntimeHelper.downcallHandle( + "brk", + constants$17.brk$FUNC + ); + static final FunctionDescriptor sbrk$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle sbrk$MH = RuntimeHelper.downcallHandle( + "sbrk", + constants$17.sbrk$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$18.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$18.java new file mode 100644 index 00000000..794239b3 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$18.java @@ -0,0 +1,52 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; +class constants$18 { + + static final FunctionDescriptor syscall$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle syscall$MH = RuntimeHelper.downcallHandleVariadic( + "syscall", + constants$18.syscall$FUNC + ); + static final FunctionDescriptor lockf$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle lockf$MH = RuntimeHelper.downcallHandle( + "lockf", + constants$18.lockf$FUNC + ); + static final FunctionDescriptor fdatasync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle fdatasync$MH = RuntimeHelper.downcallHandle( + "fdatasync", + constants$18.fdatasync$FUNC + ); + static final FunctionDescriptor crypt$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle crypt$MH = RuntimeHelper.downcallHandle( + "crypt", + constants$18.crypt$FUNC + ); + static final FunctionDescriptor getentropy$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle getentropy$MH = RuntimeHelper.downcallHandle( + "getentropy", + constants$18.getentropy$FUNC + ); + static final MemorySegment __ILP32_OFF32_CFLAGS$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("-m32"); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$19.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$19.java new file mode 100644 index 00000000..a33d0a5c --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$19.java @@ -0,0 +1,17 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; +class constants$19 { + + static final MemorySegment __ILP32_OFF32_LDFLAGS$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("-m32"); + static final MemorySegment __ILP32_OFFBIG_CFLAGS$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("-m32 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"); + static final MemorySegment __ILP32_OFFBIG_LDFLAGS$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("-m32"); + static final MemorySegment __LP64_OFF64_CFLAGS$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("-m64"); + static final MemorySegment __LP64_OFF64_LDFLAGS$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("-m64"); + static final MemoryAddress NULL$ADDR = MemoryAddress.ofLong(0L); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$2.java new file mode 100644 index 00000000..df7185a3 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$2.java @@ -0,0 +1,58 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$2 { + + static final FunctionDescriptor ualarm$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle ualarm$MH = RuntimeHelper.downcallHandle( + "ualarm", + constants$2.ualarm$FUNC + ); + static final FunctionDescriptor usleep$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle usleep$MH = RuntimeHelper.downcallHandle( + "usleep", + constants$2.usleep$FUNC + ); + static final FunctionDescriptor pause$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle pause$MH = RuntimeHelper.downcallHandle( + "pause", + constants$2.pause$FUNC + ); + static final FunctionDescriptor chown$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle chown$MH = RuntimeHelper.downcallHandle( + "chown", + constants$2.chown$FUNC + ); + static final FunctionDescriptor fchown$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle fchown$MH = RuntimeHelper.downcallHandle( + "fchown", + constants$2.fchown$FUNC + ); + static final FunctionDescriptor lchown$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle lchown$MH = RuntimeHelper.downcallHandle( + "lchown", + constants$2.lchown$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$3.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$3.java new file mode 100644 index 00000000..81b2b5d6 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$3.java @@ -0,0 +1,58 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$3 { + + static final FunctionDescriptor fchownat$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle fchownat$MH = RuntimeHelper.downcallHandle( + "fchownat", + constants$3.fchownat$FUNC + ); + static final FunctionDescriptor chdir$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle chdir$MH = RuntimeHelper.downcallHandle( + "chdir", + constants$3.chdir$FUNC + ); + static final FunctionDescriptor fchdir$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle fchdir$MH = RuntimeHelper.downcallHandle( + "fchdir", + constants$3.fchdir$FUNC + ); + static final FunctionDescriptor getcwd$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle getcwd$MH = RuntimeHelper.downcallHandle( + "getcwd", + constants$3.getcwd$FUNC + ); + static final FunctionDescriptor getwd$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle getwd$MH = RuntimeHelper.downcallHandle( + "getwd", + constants$3.getwd$FUNC + ); + static final FunctionDescriptor dup$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle dup$MH = RuntimeHelper.downcallHandle( + "dup", + constants$3.dup$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$4.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$4.java new file mode 100644 index 00000000..ec8066b8 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$4.java @@ -0,0 +1,60 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.OfAddress; +class constants$4 { + + static final FunctionDescriptor dup2$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle dup2$MH = RuntimeHelper.downcallHandle( + "dup2", + constants$4.dup2$FUNC + ); + static final OfAddress __environ$LAYOUT = Constants$root.C_POINTER$LAYOUT; + static final VarHandle __environ$VH = constants$4.__environ$LAYOUT.varHandle(); + static final MemorySegment __environ$SEGMENT = RuntimeHelper.lookupGlobalVariable("__environ", constants$4.__environ$LAYOUT); + static final FunctionDescriptor execve$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle execve$MH = RuntimeHelper.downcallHandle( + "execve", + constants$4.execve$FUNC + ); + static final FunctionDescriptor fexecve$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle fexecve$MH = RuntimeHelper.downcallHandle( + "fexecve", + constants$4.fexecve$FUNC + ); + static final FunctionDescriptor execv$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle execv$MH = RuntimeHelper.downcallHandle( + "execv", + constants$4.execv$FUNC + ); + static final FunctionDescriptor execle$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle execle$MH = RuntimeHelper.downcallHandleVariadic( + "execle", + constants$4.execle$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$5.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$5.java new file mode 100644 index 00000000..973d637c --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$5.java @@ -0,0 +1,57 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$5 { + + static final FunctionDescriptor execl$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle execl$MH = RuntimeHelper.downcallHandleVariadic( + "execl", + constants$5.execl$FUNC + ); + static final FunctionDescriptor execvp$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle execvp$MH = RuntimeHelper.downcallHandle( + "execvp", + constants$5.execvp$FUNC + ); + static final FunctionDescriptor execlp$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle execlp$MH = RuntimeHelper.downcallHandleVariadic( + "execlp", + constants$5.execlp$FUNC + ); + static final FunctionDescriptor nice$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle nice$MH = RuntimeHelper.downcallHandle( + "nice", + constants$5.nice$FUNC + ); + static final FunctionDescriptor _exit$FUNC = FunctionDescriptor.ofVoid( + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle _exit$MH = RuntimeHelper.downcallHandle( + "_exit", + constants$5._exit$FUNC + ); + static final FunctionDescriptor pathconf$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle pathconf$MH = RuntimeHelper.downcallHandle( + "pathconf", + constants$5.pathconf$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$6.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$6.java new file mode 100644 index 00000000..da5a5a31 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$6.java @@ -0,0 +1,50 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$6 { + + static final FunctionDescriptor fpathconf$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle fpathconf$MH = RuntimeHelper.downcallHandle( + "fpathconf", + constants$6.fpathconf$FUNC + ); + static final FunctionDescriptor sysconf$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle sysconf$MH = RuntimeHelper.downcallHandle( + "sysconf", + constants$6.sysconf$FUNC + ); + static final FunctionDescriptor confstr$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle confstr$MH = RuntimeHelper.downcallHandle( + "confstr", + constants$6.confstr$FUNC + ); + static final FunctionDescriptor getpid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle getpid$MH = RuntimeHelper.downcallHandle( + "getpid", + constants$6.getpid$FUNC + ); + static final FunctionDescriptor getppid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle getppid$MH = RuntimeHelper.downcallHandle( + "getppid", + constants$6.getppid$FUNC + ); + static final FunctionDescriptor getpgrp$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle getpgrp$MH = RuntimeHelper.downcallHandle( + "getpgrp", + constants$6.getpgrp$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$7.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$7.java new file mode 100644 index 00000000..d08b63a9 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$7.java @@ -0,0 +1,50 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$7 { + + static final FunctionDescriptor __getpgid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle __getpgid$MH = RuntimeHelper.downcallHandle( + "__getpgid", + constants$7.__getpgid$FUNC + ); + static final FunctionDescriptor getpgid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle getpgid$MH = RuntimeHelper.downcallHandle( + "getpgid", + constants$7.getpgid$FUNC + ); + static final FunctionDescriptor setpgid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle setpgid$MH = RuntimeHelper.downcallHandle( + "setpgid", + constants$7.setpgid$FUNC + ); + static final FunctionDescriptor setpgrp$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle setpgrp$MH = RuntimeHelper.downcallHandle( + "setpgrp", + constants$7.setpgrp$FUNC + ); + static final FunctionDescriptor setsid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle setsid$MH = RuntimeHelper.downcallHandle( + "setsid", + constants$7.setsid$FUNC + ); + static final FunctionDescriptor getsid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle getsid$MH = RuntimeHelper.downcallHandle( + "getsid", + constants$7.getsid$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$8.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$8.java new file mode 100644 index 00000000..a94fab3c --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$8.java @@ -0,0 +1,46 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$8 { + + static final FunctionDescriptor getuid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle getuid$MH = RuntimeHelper.downcallHandle( + "getuid", + constants$8.getuid$FUNC + ); + static final FunctionDescriptor geteuid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle geteuid$MH = RuntimeHelper.downcallHandle( + "geteuid", + constants$8.geteuid$FUNC + ); + static final FunctionDescriptor getgid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle getgid$MH = RuntimeHelper.downcallHandle( + "getgid", + constants$8.getgid$FUNC + ); + static final FunctionDescriptor getegid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle getegid$MH = RuntimeHelper.downcallHandle( + "getegid", + constants$8.getegid$FUNC + ); + static final FunctionDescriptor getgroups$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle getgroups$MH = RuntimeHelper.downcallHandle( + "getgroups", + constants$8.getgroups$FUNC + ); + static final FunctionDescriptor setuid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle setuid$MH = RuntimeHelper.downcallHandle( + "setuid", + constants$8.setuid$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$9.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$9.java new file mode 100644 index 00000000..e4e65a59 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$9.java @@ -0,0 +1,53 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$9 { + + static final FunctionDescriptor setreuid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle setreuid$MH = RuntimeHelper.downcallHandle( + "setreuid", + constants$9.setreuid$FUNC + ); + static final FunctionDescriptor seteuid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle seteuid$MH = RuntimeHelper.downcallHandle( + "seteuid", + constants$9.seteuid$FUNC + ); + static final FunctionDescriptor setgid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle setgid$MH = RuntimeHelper.downcallHandle( + "setgid", + constants$9.setgid$FUNC + ); + static final FunctionDescriptor setregid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle setregid$MH = RuntimeHelper.downcallHandle( + "setregid", + constants$9.setregid$FUNC + ); + static final FunctionDescriptor setegid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle setegid$MH = RuntimeHelper.downcallHandle( + "setegid", + constants$9.setegid$FUNC + ); + static final FunctionDescriptor fork$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle fork$MH = RuntimeHelper.downcallHandle( + "fork", + constants$9.fork$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java new file mode 100644 index 00000000..cf6b6b76 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java @@ -0,0 +1,2714 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.foreign.Addressable; +import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.*; +public class unistd { + + /* package-private */ unistd() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static int _UNISTD_H() { + return (int)1L; + } + public static int _FEATURES_H() { + return (int)1L; + } + public static int _DEFAULT_SOURCE() { + return (int)1L; + } + public static int __GLIBC_USE_ISOC2X() { + return (int)0L; + } + public static int __USE_ISOC11() { + return (int)1L; + } + public static int __USE_ISOC99() { + return (int)1L; + } + public static int __USE_ISOC95() { + return (int)1L; + } + public static int __USE_POSIX_IMPLICITLY() { + return (int)1L; + } + public static int _POSIX_SOURCE() { + return (int)1L; + } + public static int __USE_POSIX() { + return (int)1L; + } + public static int __USE_POSIX2() { + return (int)1L; + } + public static int __USE_POSIX199309() { + return (int)1L; + } + public static int __USE_POSIX199506() { + return (int)1L; + } + public static int __USE_XOPEN2K() { + return (int)1L; + } + public static int __USE_XOPEN2K8() { + return (int)1L; + } + public static int _ATFILE_SOURCE() { + return (int)1L; + } + public static int __WORDSIZE() { + return (int)64L; + } + public static int __WORDSIZE_TIME64_COMPAT32() { + return (int)1L; + } + public static int __SYSCALL_WORDSIZE() { + return (int)64L; + } + public static int __USE_MISC() { + return (int)1L; + } + public static int __USE_ATFILE() { + return (int)1L; + } + public static int __USE_FORTIFY_LEVEL() { + return (int)0L; + } + public static int __GLIBC_USE_DEPRECATED_GETS() { + return (int)0L; + } + public static int __GLIBC_USE_DEPRECATED_SCANF() { + return (int)0L; + } + public static int _STDC_PREDEF_H() { + return (int)1L; + } + public static int __STDC_IEC_559__() { + return (int)1L; + } + public static int __STDC_IEC_559_COMPLEX__() { + return (int)1L; + } + public static int __GNU_LIBRARY__() { + return (int)6L; + } + public static int __GLIBC__() { + return (int)2L; + } + public static int __GLIBC_MINOR__() { + return (int)35L; + } + public static int _SYS_CDEFS_H() { + return (int)1L; + } + public static int __glibc_c99_flexarr_available() { + return (int)1L; + } + public static int __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI() { + return (int)0L; + } + public static int __HAVE_GENERIC_SELECTION() { + return (int)1L; + } + public static int _XOPEN_VERSION() { + return (int)700L; + } + public static int _XOPEN_XCU_VERSION() { + return (int)4L; + } + public static int _XOPEN_XPG2() { + return (int)1L; + } + public static int _XOPEN_XPG3() { + return (int)1L; + } + public static int _XOPEN_XPG4() { + return (int)1L; + } + public static int _XOPEN_UNIX() { + return (int)1L; + } + public static int _XOPEN_ENH_I18N() { + return (int)1L; + } + public static int _XOPEN_LEGACY() { + return (int)1L; + } + public static int _BITS_POSIX_OPT_H() { + return (int)1L; + } + public static int _POSIX_JOB_CONTROL() { + return (int)1L; + } + public static int _POSIX_SAVED_IDS() { + return (int)1L; + } + public static int _POSIX_CHOWN_RESTRICTED() { + return (int)0L; + } + public static int _POSIX_NO_TRUNC() { + return (int)1L; + } + public static int _XOPEN_REALTIME() { + return (int)1L; + } + public static int _XOPEN_REALTIME_THREADS() { + return (int)1L; + } + public static int _XOPEN_SHM() { + return (int)1L; + } + public static int _POSIX_REENTRANT_FUNCTIONS() { + return (int)1L; + } + public static int _POSIX_ASYNC_IO() { + return (int)1L; + } + public static int _LFS_ASYNCHRONOUS_IO() { + return (int)1L; + } + public static int _LFS64_ASYNCHRONOUS_IO() { + return (int)1L; + } + public static int _LFS_LARGEFILE() { + return (int)1L; + } + public static int _LFS64_LARGEFILE() { + return (int)1L; + } + public static int _LFS64_STDIO() { + return (int)1L; + } + public static int _POSIX_CPUTIME() { + return (int)0L; + } + public static int _POSIX_THREAD_CPUTIME() { + return (int)0L; + } + public static int _POSIX_REGEXP() { + return (int)1L; + } + public static int _POSIX_SHELL() { + return (int)1L; + } + public static int _POSIX_MONOTONIC_CLOCK() { + return (int)0L; + } + public static int _POSIX_V7_LP64_OFF64() { + return (int)1L; + } + public static int _POSIX_V6_LP64_OFF64() { + return (int)1L; + } + public static int _XBS5_LP64_OFF64() { + return (int)1L; + } + public static int STDIN_FILENO() { + return (int)0L; + } + public static int STDOUT_FILENO() { + return (int)1L; + } + public static int STDERR_FILENO() { + return (int)2L; + } + public static int _BITS_TYPES_H() { + return (int)1L; + } + public static int _BITS_TYPESIZES_H() { + return (int)1L; + } + public static int __OFF_T_MATCHES_OFF64_T() { + return (int)1L; + } + public static int __INO_T_MATCHES_INO64_T() { + return (int)1L; + } + public static int __RLIM_T_MATCHES_RLIM64_T() { + return (int)1L; + } + public static int __STATFS_MATCHES_STATFS64() { + return (int)1L; + } + public static int __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64() { + return (int)1L; + } + public static int __FD_SETSIZE() { + return (int)1024L; + } + public static int _BITS_TIME64_H() { + return (int)1L; + } + public static int R_OK() { + return (int)4L; + } + public static int W_OK() { + return (int)2L; + } + public static int X_OK() { + return (int)1L; + } + public static int F_OK() { + return (int)0L; + } + public static int SEEK_SET() { + return (int)0L; + } + public static int SEEK_CUR() { + return (int)1L; + } + public static int SEEK_END() { + return (int)2L; + } + public static int _GETOPT_POSIX_H() { + return (int)1L; + } + public static int _GETOPT_CORE_H() { + return (int)1L; + } + public static int F_ULOCK() { + return (int)0L; + } + public static int F_LOCK() { + return (int)1L; + } + public static int F_TLOCK() { + return (int)2L; + } + public static int F_TEST() { + return (int)3L; + } + public static OfShort __int16_t = Constants$root.C_SHORT$LAYOUT; + public static OfInt __int32_t = Constants$root.C_INT$LAYOUT; + public static OfLong __int64_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfShort __int_least16_t = Constants$root.C_SHORT$LAYOUT; + public static OfInt __int_least32_t = Constants$root.C_INT$LAYOUT; + public static OfLong __int_least64_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __quad_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __intmax_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __off_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __off64_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfInt __pid_t = Constants$root.C_INT$LAYOUT; + public static OfLong __clock_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __time_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __suseconds_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __suseconds64_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfInt __daddr_t = Constants$root.C_INT$LAYOUT; + public static OfInt __key_t = Constants$root.C_INT$LAYOUT; + public static OfInt __clockid_t = Constants$root.C_INT$LAYOUT; + public static OfAddress __timer_t = Constants$root.C_POINTER$LAYOUT; + public static OfLong __blksize_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __blkcnt_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __blkcnt64_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __fsword_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __ssize_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __syscall_slong_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __loff_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfAddress __caddr_t = Constants$root.C_POINTER$LAYOUT; + public static OfLong __intptr_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfInt __sig_atomic_t = Constants$root.C_INT$LAYOUT; + public static OfLong ssize_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong off_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfInt pid_t = Constants$root.C_INT$LAYOUT; + public static OfLong intptr_t = Constants$root.C_LONG_LONG$LAYOUT; + public static MethodHandle access$MH() { + return RuntimeHelper.requireNonNull(constants$0.access$MH,"access"); + } + public static int access ( Addressable __name, int __type) { + var mh$ = access$MH(); + try { + return (int)mh$.invokeExact(__name, __type); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle faccessat$MH() { + return RuntimeHelper.requireNonNull(constants$0.faccessat$MH,"faccessat"); + } + public static int faccessat ( int __fd, Addressable __file, int __type, int __flag) { + var mh$ = faccessat$MH(); + try { + return (int)mh$.invokeExact(__fd, __file, __type, __flag); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle lseek$MH() { + return RuntimeHelper.requireNonNull(constants$0.lseek$MH,"lseek"); + } + public static long lseek ( int __fd, long __offset, int __whence) { + var mh$ = lseek$MH(); + try { + return (long)mh$.invokeExact(__fd, __offset, __whence); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle close$MH() { + return RuntimeHelper.requireNonNull(constants$0.close$MH,"close"); + } + public static int close ( int __fd) { + var mh$ = close$MH(); + try { + return (int)mh$.invokeExact(__fd); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle closefrom$MH() { + return RuntimeHelper.requireNonNull(constants$0.closefrom$MH,"closefrom"); + } + public static void closefrom ( int __lowfd) { + var mh$ = closefrom$MH(); + try { + mh$.invokeExact(__lowfd); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle read$MH() { + return RuntimeHelper.requireNonNull(constants$0.read$MH,"read"); + } + public static long read ( int __fd, Addressable __buf, long __nbytes) { + var mh$ = read$MH(); + try { + return (long)mh$.invokeExact(__fd, __buf, __nbytes); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle write$MH() { + return RuntimeHelper.requireNonNull(constants$1.write$MH,"write"); + } + public static long write ( int __fd, Addressable __buf, long __n) { + var mh$ = write$MH(); + try { + return (long)mh$.invokeExact(__fd, __buf, __n); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle pread$MH() { + return RuntimeHelper.requireNonNull(constants$1.pread$MH,"pread"); + } + public static long pread ( int __fd, Addressable __buf, long __nbytes, long __offset) { + var mh$ = pread$MH(); + try { + return (long)mh$.invokeExact(__fd, __buf, __nbytes, __offset); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle pwrite$MH() { + return RuntimeHelper.requireNonNull(constants$1.pwrite$MH,"pwrite"); + } + public static long pwrite ( int __fd, Addressable __buf, long __n, long __offset) { + var mh$ = pwrite$MH(); + try { + return (long)mh$.invokeExact(__fd, __buf, __n, __offset); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle pipe$MH() { + return RuntimeHelper.requireNonNull(constants$1.pipe$MH,"pipe"); + } + public static int pipe ( Addressable __pipedes) { + var mh$ = pipe$MH(); + try { + return (int)mh$.invokeExact(__pipedes); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle alarm$MH() { + return RuntimeHelper.requireNonNull(constants$1.alarm$MH,"alarm"); + } + public static int alarm ( int __seconds) { + var mh$ = alarm$MH(); + try { + return (int)mh$.invokeExact(__seconds); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle sleep$MH() { + return RuntimeHelper.requireNonNull(constants$1.sleep$MH,"sleep"); + } + public static int sleep ( int __seconds) { + var mh$ = sleep$MH(); + try { + return (int)mh$.invokeExact(__seconds); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle ualarm$MH() { + return RuntimeHelper.requireNonNull(constants$2.ualarm$MH,"ualarm"); + } + public static int ualarm ( int __value, int __interval) { + var mh$ = ualarm$MH(); + try { + return (int)mh$.invokeExact(__value, __interval); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle usleep$MH() { + return RuntimeHelper.requireNonNull(constants$2.usleep$MH,"usleep"); + } + public static int usleep ( int __useconds) { + var mh$ = usleep$MH(); + try { + return (int)mh$.invokeExact(__useconds); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle pause$MH() { + return RuntimeHelper.requireNonNull(constants$2.pause$MH,"pause"); + } + public static int pause () { + var mh$ = pause$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle chown$MH() { + return RuntimeHelper.requireNonNull(constants$2.chown$MH,"chown"); + } + public static int chown ( Addressable __file, int __owner, int __group) { + var mh$ = chown$MH(); + try { + return (int)mh$.invokeExact(__file, __owner, __group); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle fchown$MH() { + return RuntimeHelper.requireNonNull(constants$2.fchown$MH,"fchown"); + } + public static int fchown ( int __fd, int __owner, int __group) { + var mh$ = fchown$MH(); + try { + return (int)mh$.invokeExact(__fd, __owner, __group); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle lchown$MH() { + return RuntimeHelper.requireNonNull(constants$2.lchown$MH,"lchown"); + } + public static int lchown ( Addressable __file, int __owner, int __group) { + var mh$ = lchown$MH(); + try { + return (int)mh$.invokeExact(__file, __owner, __group); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle fchownat$MH() { + return RuntimeHelper.requireNonNull(constants$3.fchownat$MH,"fchownat"); + } + public static int fchownat ( int __fd, Addressable __file, int __owner, int __group, int __flag) { + var mh$ = fchownat$MH(); + try { + return (int)mh$.invokeExact(__fd, __file, __owner, __group, __flag); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle chdir$MH() { + return RuntimeHelper.requireNonNull(constants$3.chdir$MH,"chdir"); + } + public static int chdir ( Addressable __path) { + var mh$ = chdir$MH(); + try { + return (int)mh$.invokeExact(__path); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle fchdir$MH() { + return RuntimeHelper.requireNonNull(constants$3.fchdir$MH,"fchdir"); + } + public static int fchdir ( int __fd) { + var mh$ = fchdir$MH(); + try { + return (int)mh$.invokeExact(__fd); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getcwd$MH() { + return RuntimeHelper.requireNonNull(constants$3.getcwd$MH,"getcwd"); + } + public static MemoryAddress getcwd ( Addressable __buf, long __size) { + var mh$ = getcwd$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(__buf, __size); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getwd$MH() { + return RuntimeHelper.requireNonNull(constants$3.getwd$MH,"getwd"); + } + public static MemoryAddress getwd ( Addressable __buf) { + var mh$ = getwd$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(__buf); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle dup$MH() { + return RuntimeHelper.requireNonNull(constants$3.dup$MH,"dup"); + } + public static int dup ( int __fd) { + var mh$ = dup$MH(); + try { + return (int)mh$.invokeExact(__fd); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle dup2$MH() { + return RuntimeHelper.requireNonNull(constants$4.dup2$MH,"dup2"); + } + public static int dup2 ( int __fd, int __fd2) { + var mh$ = dup2$MH(); + try { + return (int)mh$.invokeExact(__fd, __fd2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MemoryLayout __environ$LAYOUT() { + return constants$4.__environ$LAYOUT; + } + public static VarHandle __environ$VH() { + return constants$4.__environ$VH; + } + public static MemorySegment __environ$SEGMENT() { + return RuntimeHelper.requireNonNull(constants$4.__environ$SEGMENT,"__environ"); + } + public static MemoryAddress __environ$get() { + return (java.lang.foreign.MemoryAddress) constants$4.__environ$VH.get(RuntimeHelper.requireNonNull(constants$4.__environ$SEGMENT, "__environ")); + } + public static void __environ$set( MemoryAddress x) { + constants$4.__environ$VH.set(RuntimeHelper.requireNonNull(constants$4.__environ$SEGMENT, "__environ"), x); + } + public static MethodHandle execve$MH() { + return RuntimeHelper.requireNonNull(constants$4.execve$MH,"execve"); + } + public static int execve ( Addressable __path, Addressable __argv, Addressable __envp) { + var mh$ = execve$MH(); + try { + return (int)mh$.invokeExact(__path, __argv, __envp); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle fexecve$MH() { + return RuntimeHelper.requireNonNull(constants$4.fexecve$MH,"fexecve"); + } + public static int fexecve ( int __fd, Addressable __argv, Addressable __envp) { + var mh$ = fexecve$MH(); + try { + return (int)mh$.invokeExact(__fd, __argv, __envp); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle execv$MH() { + return RuntimeHelper.requireNonNull(constants$4.execv$MH,"execv"); + } + public static int execv ( Addressable __path, Addressable __argv) { + var mh$ = execv$MH(); + try { + return (int)mh$.invokeExact(__path, __argv); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle execle$MH() { + return RuntimeHelper.requireNonNull(constants$4.execle$MH,"execle"); + } + public static int execle ( Addressable __path, Addressable __arg, Object... x2) { + var mh$ = execle$MH(); + try { + return (int)mh$.invokeExact(__path, __arg, x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle execl$MH() { + return RuntimeHelper.requireNonNull(constants$5.execl$MH,"execl"); + } + public static int execl ( Addressable __path, Addressable __arg, Object... x2) { + var mh$ = execl$MH(); + try { + return (int)mh$.invokeExact(__path, __arg, x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle execvp$MH() { + return RuntimeHelper.requireNonNull(constants$5.execvp$MH,"execvp"); + } + public static int execvp ( Addressable __file, Addressable __argv) { + var mh$ = execvp$MH(); + try { + return (int)mh$.invokeExact(__file, __argv); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle execlp$MH() { + return RuntimeHelper.requireNonNull(constants$5.execlp$MH,"execlp"); + } + public static int execlp ( Addressable __file, Addressable __arg, Object... x2) { + var mh$ = execlp$MH(); + try { + return (int)mh$.invokeExact(__file, __arg, x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle nice$MH() { + return RuntimeHelper.requireNonNull(constants$5.nice$MH,"nice"); + } + public static int nice ( int __inc) { + var mh$ = nice$MH(); + try { + return (int)mh$.invokeExact(__inc); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle _exit$MH() { + return RuntimeHelper.requireNonNull(constants$5._exit$MH,"_exit"); + } + public static void _exit ( int __status) { + var mh$ = _exit$MH(); + try { + mh$.invokeExact(__status); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static int _PC_LINK_MAX() { + return (int)0L; + } + public static int _PC_MAX_CANON() { + return (int)1L; + } + public static int _PC_MAX_INPUT() { + return (int)2L; + } + public static int _PC_NAME_MAX() { + return (int)3L; + } + public static int _PC_PATH_MAX() { + return (int)4L; + } + public static int _PC_PIPE_BUF() { + return (int)5L; + } + public static int _PC_CHOWN_RESTRICTED() { + return (int)6L; + } + public static int _PC_NO_TRUNC() { + return (int)7L; + } + public static int _PC_VDISABLE() { + return (int)8L; + } + public static int _PC_SYNC_IO() { + return (int)9L; + } + public static int _PC_ASYNC_IO() { + return (int)10L; + } + public static int _PC_PRIO_IO() { + return (int)11L; + } + public static int _PC_SOCK_MAXBUF() { + return (int)12L; + } + public static int _PC_FILESIZEBITS() { + return (int)13L; + } + public static int _PC_REC_INCR_XFER_SIZE() { + return (int)14L; + } + public static int _PC_REC_MAX_XFER_SIZE() { + return (int)15L; + } + public static int _PC_REC_MIN_XFER_SIZE() { + return (int)16L; + } + public static int _PC_REC_XFER_ALIGN() { + return (int)17L; + } + public static int _PC_ALLOC_SIZE_MIN() { + return (int)18L; + } + public static int _PC_SYMLINK_MAX() { + return (int)19L; + } + public static int _PC_2_SYMLINKS() { + return (int)20L; + } + public static int _SC_ARG_MAX() { + return (int)0L; + } + public static int _SC_CHILD_MAX() { + return (int)1L; + } + public static int _SC_CLK_TCK() { + return (int)2L; + } + public static int _SC_NGROUPS_MAX() { + return (int)3L; + } + public static int _SC_OPEN_MAX() { + return (int)4L; + } + public static int _SC_STREAM_MAX() { + return (int)5L; + } + public static int _SC_TZNAME_MAX() { + return (int)6L; + } + public static int _SC_JOB_CONTROL() { + return (int)7L; + } + public static int _SC_SAVED_IDS() { + return (int)8L; + } + public static int _SC_REALTIME_SIGNALS() { + return (int)9L; + } + public static int _SC_PRIORITY_SCHEDULING() { + return (int)10L; + } + public static int _SC_TIMERS() { + return (int)11L; + } + public static int _SC_ASYNCHRONOUS_IO() { + return (int)12L; + } + public static int _SC_PRIORITIZED_IO() { + return (int)13L; + } + public static int _SC_SYNCHRONIZED_IO() { + return (int)14L; + } + public static int _SC_FSYNC() { + return (int)15L; + } + public static int _SC_MAPPED_FILES() { + return (int)16L; + } + public static int _SC_MEMLOCK() { + return (int)17L; + } + public static int _SC_MEMLOCK_RANGE() { + return (int)18L; + } + public static int _SC_MEMORY_PROTECTION() { + return (int)19L; + } + public static int _SC_MESSAGE_PASSING() { + return (int)20L; + } + public static int _SC_SEMAPHORES() { + return (int)21L; + } + public static int _SC_SHARED_MEMORY_OBJECTS() { + return (int)22L; + } + public static int _SC_AIO_LISTIO_MAX() { + return (int)23L; + } + public static int _SC_AIO_MAX() { + return (int)24L; + } + public static int _SC_AIO_PRIO_DELTA_MAX() { + return (int)25L; + } + public static int _SC_DELAYTIMER_MAX() { + return (int)26L; + } + public static int _SC_MQ_OPEN_MAX() { + return (int)27L; + } + public static int _SC_MQ_PRIO_MAX() { + return (int)28L; + } + public static int _SC_VERSION() { + return (int)29L; + } + public static int _SC_PAGESIZE() { + return (int)30L; + } + public static int _SC_RTSIG_MAX() { + return (int)31L; + } + public static int _SC_SEM_NSEMS_MAX() { + return (int)32L; + } + public static int _SC_SEM_VALUE_MAX() { + return (int)33L; + } + public static int _SC_SIGQUEUE_MAX() { + return (int)34L; + } + public static int _SC_TIMER_MAX() { + return (int)35L; + } + public static int _SC_BC_BASE_MAX() { + return (int)36L; + } + public static int _SC_BC_DIM_MAX() { + return (int)37L; + } + public static int _SC_BC_SCALE_MAX() { + return (int)38L; + } + public static int _SC_BC_STRING_MAX() { + return (int)39L; + } + public static int _SC_COLL_WEIGHTS_MAX() { + return (int)40L; + } + public static int _SC_EQUIV_CLASS_MAX() { + return (int)41L; + } + public static int _SC_EXPR_NEST_MAX() { + return (int)42L; + } + public static int _SC_LINE_MAX() { + return (int)43L; + } + public static int _SC_RE_DUP_MAX() { + return (int)44L; + } + public static int _SC_CHARCLASS_NAME_MAX() { + return (int)45L; + } + public static int _SC_2_VERSION() { + return (int)46L; + } + public static int _SC_2_C_BIND() { + return (int)47L; + } + public static int _SC_2_C_DEV() { + return (int)48L; + } + public static int _SC_2_FORT_DEV() { + return (int)49L; + } + public static int _SC_2_FORT_RUN() { + return (int)50L; + } + public static int _SC_2_SW_DEV() { + return (int)51L; + } + public static int _SC_2_LOCALEDEF() { + return (int)52L; + } + public static int _SC_PII() { + return (int)53L; + } + public static int _SC_PII_XTI() { + return (int)54L; + } + public static int _SC_PII_SOCKET() { + return (int)55L; + } + public static int _SC_PII_INTERNET() { + return (int)56L; + } + public static int _SC_PII_OSI() { + return (int)57L; + } + public static int _SC_POLL() { + return (int)58L; + } + public static int _SC_SELECT() { + return (int)59L; + } + public static int _SC_UIO_MAXIOV() { + return (int)60L; + } + public static int _SC_IOV_MAX() { + return (int)60L; + } + public static int _SC_PII_INTERNET_STREAM() { + return (int)61L; + } + public static int _SC_PII_INTERNET_DGRAM() { + return (int)62L; + } + public static int _SC_PII_OSI_COTS() { + return (int)63L; + } + public static int _SC_PII_OSI_CLTS() { + return (int)64L; + } + public static int _SC_PII_OSI_M() { + return (int)65L; + } + public static int _SC_T_IOV_MAX() { + return (int)66L; + } + public static int _SC_THREADS() { + return (int)67L; + } + public static int _SC_THREAD_SAFE_FUNCTIONS() { + return (int)68L; + } + public static int _SC_GETGR_R_SIZE_MAX() { + return (int)69L; + } + public static int _SC_GETPW_R_SIZE_MAX() { + return (int)70L; + } + public static int _SC_LOGIN_NAME_MAX() { + return (int)71L; + } + public static int _SC_TTY_NAME_MAX() { + return (int)72L; + } + public static int _SC_THREAD_DESTRUCTOR_ITERATIONS() { + return (int)73L; + } + public static int _SC_THREAD_KEYS_MAX() { + return (int)74L; + } + public static int _SC_THREAD_STACK_MIN() { + return (int)75L; + } + public static int _SC_THREAD_THREADS_MAX() { + return (int)76L; + } + public static int _SC_THREAD_ATTR_STACKADDR() { + return (int)77L; + } + public static int _SC_THREAD_ATTR_STACKSIZE() { + return (int)78L; + } + public static int _SC_THREAD_PRIORITY_SCHEDULING() { + return (int)79L; + } + public static int _SC_THREAD_PRIO_INHERIT() { + return (int)80L; + } + public static int _SC_THREAD_PRIO_PROTECT() { + return (int)81L; + } + public static int _SC_THREAD_PROCESS_SHARED() { + return (int)82L; + } + public static int _SC_NPROCESSORS_CONF() { + return (int)83L; + } + public static int _SC_NPROCESSORS_ONLN() { + return (int)84L; + } + public static int _SC_PHYS_PAGES() { + return (int)85L; + } + public static int _SC_AVPHYS_PAGES() { + return (int)86L; + } + public static int _SC_ATEXIT_MAX() { + return (int)87L; + } + public static int _SC_PASS_MAX() { + return (int)88L; + } + public static int _SC_XOPEN_VERSION() { + return (int)89L; + } + public static int _SC_XOPEN_XCU_VERSION() { + return (int)90L; + } + public static int _SC_XOPEN_UNIX() { + return (int)91L; + } + public static int _SC_XOPEN_CRYPT() { + return (int)92L; + } + public static int _SC_XOPEN_ENH_I18N() { + return (int)93L; + } + public static int _SC_XOPEN_SHM() { + return (int)94L; + } + public static int _SC_2_CHAR_TERM() { + return (int)95L; + } + public static int _SC_2_C_VERSION() { + return (int)96L; + } + public static int _SC_2_UPE() { + return (int)97L; + } + public static int _SC_XOPEN_XPG2() { + return (int)98L; + } + public static int _SC_XOPEN_XPG3() { + return (int)99L; + } + public static int _SC_XOPEN_XPG4() { + return (int)100L; + } + public static int _SC_CHAR_BIT() { + return (int)101L; + } + public static int _SC_CHAR_MAX() { + return (int)102L; + } + public static int _SC_CHAR_MIN() { + return (int)103L; + } + public static int _SC_INT_MAX() { + return (int)104L; + } + public static int _SC_INT_MIN() { + return (int)105L; + } + public static int _SC_LONG_BIT() { + return (int)106L; + } + public static int _SC_WORD_BIT() { + return (int)107L; + } + public static int _SC_MB_LEN_MAX() { + return (int)108L; + } + public static int _SC_NZERO() { + return (int)109L; + } + public static int _SC_SSIZE_MAX() { + return (int)110L; + } + public static int _SC_SCHAR_MAX() { + return (int)111L; + } + public static int _SC_SCHAR_MIN() { + return (int)112L; + } + public static int _SC_SHRT_MAX() { + return (int)113L; + } + public static int _SC_SHRT_MIN() { + return (int)114L; + } + public static int _SC_UCHAR_MAX() { + return (int)115L; + } + public static int _SC_UINT_MAX() { + return (int)116L; + } + public static int _SC_ULONG_MAX() { + return (int)117L; + } + public static int _SC_USHRT_MAX() { + return (int)118L; + } + public static int _SC_NL_ARGMAX() { + return (int)119L; + } + public static int _SC_NL_LANGMAX() { + return (int)120L; + } + public static int _SC_NL_MSGMAX() { + return (int)121L; + } + public static int _SC_NL_NMAX() { + return (int)122L; + } + public static int _SC_NL_SETMAX() { + return (int)123L; + } + public static int _SC_NL_TEXTMAX() { + return (int)124L; + } + public static int _SC_XBS5_ILP32_OFF32() { + return (int)125L; + } + public static int _SC_XBS5_ILP32_OFFBIG() { + return (int)126L; + } + public static int _SC_XBS5_LP64_OFF64() { + return (int)127L; + } + public static int _SC_XBS5_LPBIG_OFFBIG() { + return (int)128L; + } + public static int _SC_XOPEN_LEGACY() { + return (int)129L; + } + public static int _SC_XOPEN_REALTIME() { + return (int)130L; + } + public static int _SC_XOPEN_REALTIME_THREADS() { + return (int)131L; + } + public static int _SC_ADVISORY_INFO() { + return (int)132L; + } + public static int _SC_BARRIERS() { + return (int)133L; + } + public static int _SC_BASE() { + return (int)134L; + } + public static int _SC_C_LANG_SUPPORT() { + return (int)135L; + } + public static int _SC_C_LANG_SUPPORT_R() { + return (int)136L; + } + public static int _SC_CLOCK_SELECTION() { + return (int)137L; + } + public static int _SC_CPUTIME() { + return (int)138L; + } + public static int _SC_THREAD_CPUTIME() { + return (int)139L; + } + public static int _SC_DEVICE_IO() { + return (int)140L; + } + public static int _SC_DEVICE_SPECIFIC() { + return (int)141L; + } + public static int _SC_DEVICE_SPECIFIC_R() { + return (int)142L; + } + public static int _SC_FD_MGMT() { + return (int)143L; + } + public static int _SC_FIFO() { + return (int)144L; + } + public static int _SC_PIPE() { + return (int)145L; + } + public static int _SC_FILE_ATTRIBUTES() { + return (int)146L; + } + public static int _SC_FILE_LOCKING() { + return (int)147L; + } + public static int _SC_FILE_SYSTEM() { + return (int)148L; + } + public static int _SC_MONOTONIC_CLOCK() { + return (int)149L; + } + public static int _SC_MULTI_PROCESS() { + return (int)150L; + } + public static int _SC_SINGLE_PROCESS() { + return (int)151L; + } + public static int _SC_NETWORKING() { + return (int)152L; + } + public static int _SC_READER_WRITER_LOCKS() { + return (int)153L; + } + public static int _SC_SPIN_LOCKS() { + return (int)154L; + } + public static int _SC_REGEXP() { + return (int)155L; + } + public static int _SC_REGEX_VERSION() { + return (int)156L; + } + public static int _SC_SHELL() { + return (int)157L; + } + public static int _SC_SIGNALS() { + return (int)158L; + } + public static int _SC_SPAWN() { + return (int)159L; + } + public static int _SC_SPORADIC_SERVER() { + return (int)160L; + } + public static int _SC_THREAD_SPORADIC_SERVER() { + return (int)161L; + } + public static int _SC_SYSTEM_DATABASE() { + return (int)162L; + } + public static int _SC_SYSTEM_DATABASE_R() { + return (int)163L; + } + public static int _SC_TIMEOUTS() { + return (int)164L; + } + public static int _SC_TYPED_MEMORY_OBJECTS() { + return (int)165L; + } + public static int _SC_USER_GROUPS() { + return (int)166L; + } + public static int _SC_USER_GROUPS_R() { + return (int)167L; + } + public static int _SC_2_PBS() { + return (int)168L; + } + public static int _SC_2_PBS_ACCOUNTING() { + return (int)169L; + } + public static int _SC_2_PBS_LOCATE() { + return (int)170L; + } + public static int _SC_2_PBS_MESSAGE() { + return (int)171L; + } + public static int _SC_2_PBS_TRACK() { + return (int)172L; + } + public static int _SC_SYMLOOP_MAX() { + return (int)173L; + } + public static int _SC_STREAMS() { + return (int)174L; + } + public static int _SC_2_PBS_CHECKPOINT() { + return (int)175L; + } + public static int _SC_V6_ILP32_OFF32() { + return (int)176L; + } + public static int _SC_V6_ILP32_OFFBIG() { + return (int)177L; + } + public static int _SC_V6_LP64_OFF64() { + return (int)178L; + } + public static int _SC_V6_LPBIG_OFFBIG() { + return (int)179L; + } + public static int _SC_HOST_NAME_MAX() { + return (int)180L; + } + public static int _SC_TRACE() { + return (int)181L; + } + public static int _SC_TRACE_EVENT_FILTER() { + return (int)182L; + } + public static int _SC_TRACE_INHERIT() { + return (int)183L; + } + public static int _SC_TRACE_LOG() { + return (int)184L; + } + public static int _SC_LEVEL1_ICACHE_SIZE() { + return (int)185L; + } + public static int _SC_LEVEL1_ICACHE_ASSOC() { + return (int)186L; + } + public static int _SC_LEVEL1_ICACHE_LINESIZE() { + return (int)187L; + } + public static int _SC_LEVEL1_DCACHE_SIZE() { + return (int)188L; + } + public static int _SC_LEVEL1_DCACHE_ASSOC() { + return (int)189L; + } + public static int _SC_LEVEL1_DCACHE_LINESIZE() { + return (int)190L; + } + public static int _SC_LEVEL2_CACHE_SIZE() { + return (int)191L; + } + public static int _SC_LEVEL2_CACHE_ASSOC() { + return (int)192L; + } + public static int _SC_LEVEL2_CACHE_LINESIZE() { + return (int)193L; + } + public static int _SC_LEVEL3_CACHE_SIZE() { + return (int)194L; + } + public static int _SC_LEVEL3_CACHE_ASSOC() { + return (int)195L; + } + public static int _SC_LEVEL3_CACHE_LINESIZE() { + return (int)196L; + } + public static int _SC_LEVEL4_CACHE_SIZE() { + return (int)197L; + } + public static int _SC_LEVEL4_CACHE_ASSOC() { + return (int)198L; + } + public static int _SC_LEVEL4_CACHE_LINESIZE() { + return (int)199L; + } + public static int _SC_IPV6() { + return (int)235L; + } + public static int _SC_RAW_SOCKETS() { + return (int)236L; + } + public static int _SC_V7_ILP32_OFF32() { + return (int)237L; + } + public static int _SC_V7_ILP32_OFFBIG() { + return (int)238L; + } + public static int _SC_V7_LP64_OFF64() { + return (int)239L; + } + public static int _SC_V7_LPBIG_OFFBIG() { + return (int)240L; + } + public static int _SC_SS_REPL_MAX() { + return (int)241L; + } + public static int _SC_TRACE_EVENT_NAME_MAX() { + return (int)242L; + } + public static int _SC_TRACE_NAME_MAX() { + return (int)243L; + } + public static int _SC_TRACE_SYS_MAX() { + return (int)244L; + } + public static int _SC_TRACE_USER_EVENT_MAX() { + return (int)245L; + } + public static int _SC_XOPEN_STREAMS() { + return (int)246L; + } + public static int _SC_THREAD_ROBUST_PRIO_INHERIT() { + return (int)247L; + } + public static int _SC_THREAD_ROBUST_PRIO_PROTECT() { + return (int)248L; + } + public static int _SC_MINSIGSTKSZ() { + return (int)249L; + } + public static int _SC_SIGSTKSZ() { + return (int)250L; + } + public static int _CS_PATH() { + return (int)0L; + } + public static int _CS_V6_WIDTH_RESTRICTED_ENVS() { + return (int)1L; + } + public static int _CS_GNU_LIBC_VERSION() { + return (int)2L; + } + public static int _CS_GNU_LIBPTHREAD_VERSION() { + return (int)3L; + } + public static int _CS_V5_WIDTH_RESTRICTED_ENVS() { + return (int)4L; + } + public static int _CS_V7_WIDTH_RESTRICTED_ENVS() { + return (int)5L; + } + public static int _CS_LFS_CFLAGS() { + return (int)1000L; + } + public static int _CS_LFS_LDFLAGS() { + return (int)1001L; + } + public static int _CS_LFS_LIBS() { + return (int)1002L; + } + public static int _CS_LFS_LINTFLAGS() { + return (int)1003L; + } + public static int _CS_LFS64_CFLAGS() { + return (int)1004L; + } + public static int _CS_LFS64_LDFLAGS() { + return (int)1005L; + } + public static int _CS_LFS64_LIBS() { + return (int)1006L; + } + public static int _CS_LFS64_LINTFLAGS() { + return (int)1007L; + } + public static int _CS_XBS5_ILP32_OFF32_CFLAGS() { + return (int)1100L; + } + public static int _CS_XBS5_ILP32_OFF32_LDFLAGS() { + return (int)1101L; + } + public static int _CS_XBS5_ILP32_OFF32_LIBS() { + return (int)1102L; + } + public static int _CS_XBS5_ILP32_OFF32_LINTFLAGS() { + return (int)1103L; + } + public static int _CS_XBS5_ILP32_OFFBIG_CFLAGS() { + return (int)1104L; + } + public static int _CS_XBS5_ILP32_OFFBIG_LDFLAGS() { + return (int)1105L; + } + public static int _CS_XBS5_ILP32_OFFBIG_LIBS() { + return (int)1106L; + } + public static int _CS_XBS5_ILP32_OFFBIG_LINTFLAGS() { + return (int)1107L; + } + public static int _CS_XBS5_LP64_OFF64_CFLAGS() { + return (int)1108L; + } + public static int _CS_XBS5_LP64_OFF64_LDFLAGS() { + return (int)1109L; + } + public static int _CS_XBS5_LP64_OFF64_LIBS() { + return (int)1110L; + } + public static int _CS_XBS5_LP64_OFF64_LINTFLAGS() { + return (int)1111L; + } + public static int _CS_XBS5_LPBIG_OFFBIG_CFLAGS() { + return (int)1112L; + } + public static int _CS_XBS5_LPBIG_OFFBIG_LDFLAGS() { + return (int)1113L; + } + public static int _CS_XBS5_LPBIG_OFFBIG_LIBS() { + return (int)1114L; + } + public static int _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS() { + return (int)1115L; + } + public static int _CS_POSIX_V6_ILP32_OFF32_CFLAGS() { + return (int)1116L; + } + public static int _CS_POSIX_V6_ILP32_OFF32_LDFLAGS() { + return (int)1117L; + } + public static int _CS_POSIX_V6_ILP32_OFF32_LIBS() { + return (int)1118L; + } + public static int _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS() { + return (int)1119L; + } + public static int _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS() { + return (int)1120L; + } + public static int _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS() { + return (int)1121L; + } + public static int _CS_POSIX_V6_ILP32_OFFBIG_LIBS() { + return (int)1122L; + } + public static int _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS() { + return (int)1123L; + } + public static int _CS_POSIX_V6_LP64_OFF64_CFLAGS() { + return (int)1124L; + } + public static int _CS_POSIX_V6_LP64_OFF64_LDFLAGS() { + return (int)1125L; + } + public static int _CS_POSIX_V6_LP64_OFF64_LIBS() { + return (int)1126L; + } + public static int _CS_POSIX_V6_LP64_OFF64_LINTFLAGS() { + return (int)1127L; + } + public static int _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS() { + return (int)1128L; + } + public static int _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS() { + return (int)1129L; + } + public static int _CS_POSIX_V6_LPBIG_OFFBIG_LIBS() { + return (int)1130L; + } + public static int _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS() { + return (int)1131L; + } + public static int _CS_POSIX_V7_ILP32_OFF32_CFLAGS() { + return (int)1132L; + } + public static int _CS_POSIX_V7_ILP32_OFF32_LDFLAGS() { + return (int)1133L; + } + public static int _CS_POSIX_V7_ILP32_OFF32_LIBS() { + return (int)1134L; + } + public static int _CS_POSIX_V7_ILP32_OFF32_LINTFLAGS() { + return (int)1135L; + } + public static int _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS() { + return (int)1136L; + } + public static int _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS() { + return (int)1137L; + } + public static int _CS_POSIX_V7_ILP32_OFFBIG_LIBS() { + return (int)1138L; + } + public static int _CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS() { + return (int)1139L; + } + public static int _CS_POSIX_V7_LP64_OFF64_CFLAGS() { + return (int)1140L; + } + public static int _CS_POSIX_V7_LP64_OFF64_LDFLAGS() { + return (int)1141L; + } + public static int _CS_POSIX_V7_LP64_OFF64_LIBS() { + return (int)1142L; + } + public static int _CS_POSIX_V7_LP64_OFF64_LINTFLAGS() { + return (int)1143L; + } + public static int _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS() { + return (int)1144L; + } + public static int _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS() { + return (int)1145L; + } + public static int _CS_POSIX_V7_LPBIG_OFFBIG_LIBS() { + return (int)1146L; + } + public static int _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS() { + return (int)1147L; + } + public static int _CS_V6_ENV() { + return (int)1148L; + } + public static int _CS_V7_ENV() { + return (int)1149L; + } + public static MethodHandle pathconf$MH() { + return RuntimeHelper.requireNonNull(constants$5.pathconf$MH,"pathconf"); + } + public static long pathconf ( Addressable __path, int __name) { + var mh$ = pathconf$MH(); + try { + return (long)mh$.invokeExact(__path, __name); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle fpathconf$MH() { + return RuntimeHelper.requireNonNull(constants$6.fpathconf$MH,"fpathconf"); + } + public static long fpathconf ( int __fd, int __name) { + var mh$ = fpathconf$MH(); + try { + return (long)mh$.invokeExact(__fd, __name); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle sysconf$MH() { + return RuntimeHelper.requireNonNull(constants$6.sysconf$MH,"sysconf"); + } + public static long sysconf ( int __name) { + var mh$ = sysconf$MH(); + try { + return (long)mh$.invokeExact(__name); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle confstr$MH() { + return RuntimeHelper.requireNonNull(constants$6.confstr$MH,"confstr"); + } + public static long confstr ( int __name, Addressable __buf, long __len) { + var mh$ = confstr$MH(); + try { + return (long)mh$.invokeExact(__name, __buf, __len); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getpid$MH() { + return RuntimeHelper.requireNonNull(constants$6.getpid$MH,"getpid"); + } + public static int getpid () { + var mh$ = getpid$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getppid$MH() { + return RuntimeHelper.requireNonNull(constants$6.getppid$MH,"getppid"); + } + public static int getppid () { + var mh$ = getppid$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getpgrp$MH() { + return RuntimeHelper.requireNonNull(constants$6.getpgrp$MH,"getpgrp"); + } + public static int getpgrp () { + var mh$ = getpgrp$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle __getpgid$MH() { + return RuntimeHelper.requireNonNull(constants$7.__getpgid$MH,"__getpgid"); + } + public static int __getpgid ( int __pid) { + var mh$ = __getpgid$MH(); + try { + return (int)mh$.invokeExact(__pid); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getpgid$MH() { + return RuntimeHelper.requireNonNull(constants$7.getpgid$MH,"getpgid"); + } + public static int getpgid ( int __pid) { + var mh$ = getpgid$MH(); + try { + return (int)mh$.invokeExact(__pid); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle setpgid$MH() { + return RuntimeHelper.requireNonNull(constants$7.setpgid$MH,"setpgid"); + } + public static int setpgid ( int __pid, int __pgid) { + var mh$ = setpgid$MH(); + try { + return (int)mh$.invokeExact(__pid, __pgid); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle setpgrp$MH() { + return RuntimeHelper.requireNonNull(constants$7.setpgrp$MH,"setpgrp"); + } + public static int setpgrp () { + var mh$ = setpgrp$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle setsid$MH() { + return RuntimeHelper.requireNonNull(constants$7.setsid$MH,"setsid"); + } + public static int setsid () { + var mh$ = setsid$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getsid$MH() { + return RuntimeHelper.requireNonNull(constants$7.getsid$MH,"getsid"); + } + public static int getsid ( int __pid) { + var mh$ = getsid$MH(); + try { + return (int)mh$.invokeExact(__pid); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getuid$MH() { + return RuntimeHelper.requireNonNull(constants$8.getuid$MH,"getuid"); + } + public static int getuid () { + var mh$ = getuid$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle geteuid$MH() { + return RuntimeHelper.requireNonNull(constants$8.geteuid$MH,"geteuid"); + } + public static int geteuid () { + var mh$ = geteuid$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getgid$MH() { + return RuntimeHelper.requireNonNull(constants$8.getgid$MH,"getgid"); + } + public static int getgid () { + var mh$ = getgid$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getegid$MH() { + return RuntimeHelper.requireNonNull(constants$8.getegid$MH,"getegid"); + } + public static int getegid () { + var mh$ = getegid$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getgroups$MH() { + return RuntimeHelper.requireNonNull(constants$8.getgroups$MH,"getgroups"); + } + public static int getgroups ( int __size, Addressable __list) { + var mh$ = getgroups$MH(); + try { + return (int)mh$.invokeExact(__size, __list); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle setuid$MH() { + return RuntimeHelper.requireNonNull(constants$8.setuid$MH,"setuid"); + } + public static int setuid ( int __uid) { + var mh$ = setuid$MH(); + try { + return (int)mh$.invokeExact(__uid); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle setreuid$MH() { + return RuntimeHelper.requireNonNull(constants$9.setreuid$MH,"setreuid"); + } + public static int setreuid ( int __ruid, int __euid) { + var mh$ = setreuid$MH(); + try { + return (int)mh$.invokeExact(__ruid, __euid); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle seteuid$MH() { + return RuntimeHelper.requireNonNull(constants$9.seteuid$MH,"seteuid"); + } + public static int seteuid ( int __uid) { + var mh$ = seteuid$MH(); + try { + return (int)mh$.invokeExact(__uid); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle setgid$MH() { + return RuntimeHelper.requireNonNull(constants$9.setgid$MH,"setgid"); + } + public static int setgid ( int __gid) { + var mh$ = setgid$MH(); + try { + return (int)mh$.invokeExact(__gid); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle setregid$MH() { + return RuntimeHelper.requireNonNull(constants$9.setregid$MH,"setregid"); + } + public static int setregid ( int __rgid, int __egid) { + var mh$ = setregid$MH(); + try { + return (int)mh$.invokeExact(__rgid, __egid); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle setegid$MH() { + return RuntimeHelper.requireNonNull(constants$9.setegid$MH,"setegid"); + } + public static int setegid ( int __gid) { + var mh$ = setegid$MH(); + try { + return (int)mh$.invokeExact(__gid); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle fork$MH() { + return RuntimeHelper.requireNonNull(constants$9.fork$MH,"fork"); + } + public static int fork () { + var mh$ = fork$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle vfork$MH() { + return RuntimeHelper.requireNonNull(constants$10.vfork$MH,"vfork"); + } + public static int vfork () { + var mh$ = vfork$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle ttyname$MH() { + return RuntimeHelper.requireNonNull(constants$10.ttyname$MH,"ttyname"); + } + public static MemoryAddress ttyname ( int __fd) { + var mh$ = ttyname$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(__fd); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle ttyname_r$MH() { + return RuntimeHelper.requireNonNull(constants$10.ttyname_r$MH,"ttyname_r"); + } + public static int ttyname_r ( int __fd, Addressable __buf, long __buflen) { + var mh$ = ttyname_r$MH(); + try { + return (int)mh$.invokeExact(__fd, __buf, __buflen); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle isatty$MH() { + return RuntimeHelper.requireNonNull(constants$10.isatty$MH,"isatty"); + } + public static int isatty ( int __fd) { + var mh$ = isatty$MH(); + try { + return (int)mh$.invokeExact(__fd); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle ttyslot$MH() { + return RuntimeHelper.requireNonNull(constants$10.ttyslot$MH,"ttyslot"); + } + public static int ttyslot () { + var mh$ = ttyslot$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle link$MH() { + return RuntimeHelper.requireNonNull(constants$10.link$MH,"link"); + } + public static int link ( Addressable __from, Addressable __to) { + var mh$ = link$MH(); + try { + return (int)mh$.invokeExact(__from, __to); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle linkat$MH() { + return RuntimeHelper.requireNonNull(constants$11.linkat$MH,"linkat"); + } + public static int linkat ( int __fromfd, Addressable __from, int __tofd, Addressable __to, int __flags) { + var mh$ = linkat$MH(); + try { + return (int)mh$.invokeExact(__fromfd, __from, __tofd, __to, __flags); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle symlink$MH() { + return RuntimeHelper.requireNonNull(constants$11.symlink$MH,"symlink"); + } + public static int symlink ( Addressable __from, Addressable __to) { + var mh$ = symlink$MH(); + try { + return (int)mh$.invokeExact(__from, __to); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle readlink$MH() { + return RuntimeHelper.requireNonNull(constants$11.readlink$MH,"readlink"); + } + public static long readlink ( Addressable __path, Addressable __buf, long __len) { + var mh$ = readlink$MH(); + try { + return (long)mh$.invokeExact(__path, __buf, __len); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle symlinkat$MH() { + return RuntimeHelper.requireNonNull(constants$11.symlinkat$MH,"symlinkat"); + } + public static int symlinkat ( Addressable __from, int __tofd, Addressable __to) { + var mh$ = symlinkat$MH(); + try { + return (int)mh$.invokeExact(__from, __tofd, __to); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle readlinkat$MH() { + return RuntimeHelper.requireNonNull(constants$11.readlinkat$MH,"readlinkat"); + } + public static long readlinkat ( int __fd, Addressable __path, Addressable __buf, long __len) { + var mh$ = readlinkat$MH(); + try { + return (long)mh$.invokeExact(__fd, __path, __buf, __len); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle unlink$MH() { + return RuntimeHelper.requireNonNull(constants$11.unlink$MH,"unlink"); + } + public static int unlink ( Addressable __name) { + var mh$ = unlink$MH(); + try { + return (int)mh$.invokeExact(__name); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle unlinkat$MH() { + return RuntimeHelper.requireNonNull(constants$12.unlinkat$MH,"unlinkat"); + } + public static int unlinkat ( int __fd, Addressable __name, int __flag) { + var mh$ = unlinkat$MH(); + try { + return (int)mh$.invokeExact(__fd, __name, __flag); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle rmdir$MH() { + return RuntimeHelper.requireNonNull(constants$12.rmdir$MH,"rmdir"); + } + public static int rmdir ( Addressable __path) { + var mh$ = rmdir$MH(); + try { + return (int)mh$.invokeExact(__path); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle tcgetpgrp$MH() { + return RuntimeHelper.requireNonNull(constants$12.tcgetpgrp$MH,"tcgetpgrp"); + } + public static int tcgetpgrp ( int __fd) { + var mh$ = tcgetpgrp$MH(); + try { + return (int)mh$.invokeExact(__fd); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle tcsetpgrp$MH() { + return RuntimeHelper.requireNonNull(constants$12.tcsetpgrp$MH,"tcsetpgrp"); + } + public static int tcsetpgrp ( int __fd, int __pgrp_id) { + var mh$ = tcsetpgrp$MH(); + try { + return (int)mh$.invokeExact(__fd, __pgrp_id); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getlogin$MH() { + return RuntimeHelper.requireNonNull(constants$12.getlogin$MH,"getlogin"); + } + public static MemoryAddress getlogin () { + var mh$ = getlogin$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getlogin_r$MH() { + return RuntimeHelper.requireNonNull(constants$12.getlogin_r$MH,"getlogin_r"); + } + public static int getlogin_r ( Addressable __name, long __name_len) { + var mh$ = getlogin_r$MH(); + try { + return (int)mh$.invokeExact(__name, __name_len); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle setlogin$MH() { + return RuntimeHelper.requireNonNull(constants$13.setlogin$MH,"setlogin"); + } + public static int setlogin ( Addressable __name) { + var mh$ = setlogin$MH(); + try { + return (int)mh$.invokeExact(__name); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MemoryLayout optarg$LAYOUT() { + return constants$13.optarg$LAYOUT; + } + public static VarHandle optarg$VH() { + return constants$13.optarg$VH; + } + public static MemorySegment optarg$SEGMENT() { + return RuntimeHelper.requireNonNull(constants$13.optarg$SEGMENT,"optarg"); + } + public static MemoryAddress optarg$get() { + return (java.lang.foreign.MemoryAddress) constants$13.optarg$VH.get(RuntimeHelper.requireNonNull(constants$13.optarg$SEGMENT, "optarg")); + } + public static void optarg$set( MemoryAddress x) { + constants$13.optarg$VH.set(RuntimeHelper.requireNonNull(constants$13.optarg$SEGMENT, "optarg"), x); + } + public static MemoryLayout optind$LAYOUT() { + return constants$13.optind$LAYOUT; + } + public static VarHandle optind$VH() { + return constants$13.optind$VH; + } + public static MemorySegment optind$SEGMENT() { + return RuntimeHelper.requireNonNull(constants$13.optind$SEGMENT,"optind"); + } + public static int optind$get() { + return (int) constants$13.optind$VH.get(RuntimeHelper.requireNonNull(constants$13.optind$SEGMENT, "optind")); + } + public static void optind$set( int x) { + constants$13.optind$VH.set(RuntimeHelper.requireNonNull(constants$13.optind$SEGMENT, "optind"), x); + } + public static MemoryLayout opterr$LAYOUT() { + return constants$13.opterr$LAYOUT; + } + public static VarHandle opterr$VH() { + return constants$13.opterr$VH; + } + public static MemorySegment opterr$SEGMENT() { + return RuntimeHelper.requireNonNull(constants$13.opterr$SEGMENT,"opterr"); + } + public static int opterr$get() { + return (int) constants$13.opterr$VH.get(RuntimeHelper.requireNonNull(constants$13.opterr$SEGMENT, "opterr")); + } + public static void opterr$set( int x) { + constants$13.opterr$VH.set(RuntimeHelper.requireNonNull(constants$13.opterr$SEGMENT, "opterr"), x); + } + public static MemoryLayout optopt$LAYOUT() { + return constants$13.optopt$LAYOUT; + } + public static VarHandle optopt$VH() { + return constants$13.optopt$VH; + } + public static MemorySegment optopt$SEGMENT() { + return RuntimeHelper.requireNonNull(constants$13.optopt$SEGMENT,"optopt"); + } + public static int optopt$get() { + return (int) constants$13.optopt$VH.get(RuntimeHelper.requireNonNull(constants$13.optopt$SEGMENT, "optopt")); + } + public static void optopt$set( int x) { + constants$13.optopt$VH.set(RuntimeHelper.requireNonNull(constants$13.optopt$SEGMENT, "optopt"), x); + } + public static MethodHandle getopt$MH() { + return RuntimeHelper.requireNonNull(constants$13.getopt$MH,"getopt"); + } + public static int getopt ( int ___argc, Addressable ___argv, Addressable __shortopts) { + var mh$ = getopt$MH(); + try { + return (int)mh$.invokeExact(___argc, ___argv, __shortopts); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle gethostname$MH() { + return RuntimeHelper.requireNonNull(constants$14.gethostname$MH,"gethostname"); + } + public static int gethostname ( Addressable __name, long __len) { + var mh$ = gethostname$MH(); + try { + return (int)mh$.invokeExact(__name, __len); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle sethostname$MH() { + return RuntimeHelper.requireNonNull(constants$14.sethostname$MH,"sethostname"); + } + public static int sethostname ( Addressable __name, long __len) { + var mh$ = sethostname$MH(); + try { + return (int)mh$.invokeExact(__name, __len); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle sethostid$MH() { + return RuntimeHelper.requireNonNull(constants$14.sethostid$MH,"sethostid"); + } + public static int sethostid ( long __id) { + var mh$ = sethostid$MH(); + try { + return (int)mh$.invokeExact(__id); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getdomainname$MH() { + return RuntimeHelper.requireNonNull(constants$14.getdomainname$MH,"getdomainname"); + } + public static int getdomainname ( Addressable __name, long __len) { + var mh$ = getdomainname$MH(); + try { + return (int)mh$.invokeExact(__name, __len); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle setdomainname$MH() { + return RuntimeHelper.requireNonNull(constants$14.setdomainname$MH,"setdomainname"); + } + public static int setdomainname ( Addressable __name, long __len) { + var mh$ = setdomainname$MH(); + try { + return (int)mh$.invokeExact(__name, __len); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle vhangup$MH() { + return RuntimeHelper.requireNonNull(constants$14.vhangup$MH,"vhangup"); + } + public static int vhangup () { + var mh$ = vhangup$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle revoke$MH() { + return RuntimeHelper.requireNonNull(constants$15.revoke$MH,"revoke"); + } + public static int revoke ( Addressable __file) { + var mh$ = revoke$MH(); + try { + return (int)mh$.invokeExact(__file); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle profil$MH() { + return RuntimeHelper.requireNonNull(constants$15.profil$MH,"profil"); + } + public static int profil ( Addressable __sample_buffer, long __size, long __offset, int __scale) { + var mh$ = profil$MH(); + try { + return (int)mh$.invokeExact(__sample_buffer, __size, __offset, __scale); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle acct$MH() { + return RuntimeHelper.requireNonNull(constants$15.acct$MH,"acct"); + } + public static int acct ( Addressable __name) { + var mh$ = acct$MH(); + try { + return (int)mh$.invokeExact(__name); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getusershell$MH() { + return RuntimeHelper.requireNonNull(constants$15.getusershell$MH,"getusershell"); + } + public static MemoryAddress getusershell () { + var mh$ = getusershell$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle endusershell$MH() { + return RuntimeHelper.requireNonNull(constants$15.endusershell$MH,"endusershell"); + } + public static void endusershell () { + var mh$ = endusershell$MH(); + try { + mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle setusershell$MH() { + return RuntimeHelper.requireNonNull(constants$15.setusershell$MH,"setusershell"); + } + public static void setusershell () { + var mh$ = setusershell$MH(); + try { + mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle daemon$MH() { + return RuntimeHelper.requireNonNull(constants$16.daemon$MH,"daemon"); + } + public static int daemon ( int __nochdir, int __noclose) { + var mh$ = daemon$MH(); + try { + return (int)mh$.invokeExact(__nochdir, __noclose); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle chroot$MH() { + return RuntimeHelper.requireNonNull(constants$16.chroot$MH,"chroot"); + } + public static int chroot ( Addressable __path) { + var mh$ = chroot$MH(); + try { + return (int)mh$.invokeExact(__path); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getpass$MH() { + return RuntimeHelper.requireNonNull(constants$16.getpass$MH,"getpass"); + } + public static MemoryAddress getpass ( Addressable __prompt) { + var mh$ = getpass$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(__prompt); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle fsync$MH() { + return RuntimeHelper.requireNonNull(constants$16.fsync$MH,"fsync"); + } + public static int fsync ( int __fd) { + var mh$ = fsync$MH(); + try { + return (int)mh$.invokeExact(__fd); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle gethostid$MH() { + return RuntimeHelper.requireNonNull(constants$16.gethostid$MH,"gethostid"); + } + public static long gethostid () { + var mh$ = gethostid$MH(); + try { + return (long)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle sync$MH() { + return RuntimeHelper.requireNonNull(constants$16.sync$MH,"sync"); + } + public static void sync () { + var mh$ = sync$MH(); + try { + mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getpagesize$MH() { + return RuntimeHelper.requireNonNull(constants$17.getpagesize$MH,"getpagesize"); + } + public static int getpagesize () { + var mh$ = getpagesize$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getdtablesize$MH() { + return RuntimeHelper.requireNonNull(constants$17.getdtablesize$MH,"getdtablesize"); + } + public static int getdtablesize () { + var mh$ = getdtablesize$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle truncate$MH() { + return RuntimeHelper.requireNonNull(constants$17.truncate$MH,"truncate"); + } + public static int truncate ( Addressable __file, long __length) { + var mh$ = truncate$MH(); + try { + return (int)mh$.invokeExact(__file, __length); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle ftruncate$MH() { + return RuntimeHelper.requireNonNull(constants$17.ftruncate$MH,"ftruncate"); + } + public static int ftruncate ( int __fd, long __length) { + var mh$ = ftruncate$MH(); + try { + return (int)mh$.invokeExact(__fd, __length); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle brk$MH() { + return RuntimeHelper.requireNonNull(constants$17.brk$MH,"brk"); + } + public static int brk ( Addressable __addr) { + var mh$ = brk$MH(); + try { + return (int)mh$.invokeExact(__addr); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle sbrk$MH() { + return RuntimeHelper.requireNonNull(constants$17.sbrk$MH,"sbrk"); + } + public static MemoryAddress sbrk ( long __delta) { + var mh$ = sbrk$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(__delta); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle syscall$MH() { + return RuntimeHelper.requireNonNull(constants$18.syscall$MH,"syscall"); + } + public static long syscall ( long __sysno, Object... x1) { + var mh$ = syscall$MH(); + try { + return (long)mh$.invokeExact(__sysno, x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle lockf$MH() { + return RuntimeHelper.requireNonNull(constants$18.lockf$MH,"lockf"); + } + public static int lockf ( int __fd, int __cmd, long __len) { + var mh$ = lockf$MH(); + try { + return (int)mh$.invokeExact(__fd, __cmd, __len); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle fdatasync$MH() { + return RuntimeHelper.requireNonNull(constants$18.fdatasync$MH,"fdatasync"); + } + public static int fdatasync ( int __fildes) { + var mh$ = fdatasync$MH(); + try { + return (int)mh$.invokeExact(__fildes); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle crypt$MH() { + return RuntimeHelper.requireNonNull(constants$18.crypt$MH,"crypt"); + } + public static MemoryAddress crypt ( Addressable __key, Addressable __salt) { + var mh$ = crypt$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(__key, __salt); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle getentropy$MH() { + return RuntimeHelper.requireNonNull(constants$18.getentropy$MH,"getentropy"); + } + public static int getentropy ( Addressable __buffer, long __length) { + var mh$ = getentropy$MH(); + try { + return (int)mh$.invokeExact(__buffer, __length); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static long _POSIX_C_SOURCE() { + return 200809L; + } + public static int __TIMESIZE() { + return (int)64L; + } + public static long __STDC_IEC_60559_BFP__() { + return 201404L; + } + public static long __STDC_IEC_60559_COMPLEX__() { + return 201404L; + } + public static long __STDC_ISO_10646__() { + return 201706L; + } + public static long _POSIX_VERSION() { + return 200809L; + } + public static long __POSIX2_THIS_VERSION() { + return 200809L; + } + public static long _POSIX2_VERSION() { + return 200809L; + } + public static long _POSIX2_C_VERSION() { + return 200809L; + } + public static long _POSIX2_C_BIND() { + return 200809L; + } + public static long _POSIX2_C_DEV() { + return 200809L; + } + public static long _POSIX2_SW_DEV() { + return 200809L; + } + public static long _POSIX2_LOCALEDEF() { + return 200809L; + } + public static long _POSIX_PRIORITY_SCHEDULING() { + return 200809L; + } + public static long _POSIX_SYNCHRONIZED_IO() { + return 200809L; + } + public static long _POSIX_FSYNC() { + return 200809L; + } + public static long _POSIX_MAPPED_FILES() { + return 200809L; + } + public static long _POSIX_MEMLOCK() { + return 200809L; + } + public static long _POSIX_MEMLOCK_RANGE() { + return 200809L; + } + public static long _POSIX_MEMORY_PROTECTION() { + return 200809L; + } + public static int _POSIX_VDISABLE() { + return (int)0L; + } + public static long _POSIX_THREADS() { + return 200809L; + } + public static long _POSIX_THREAD_SAFE_FUNCTIONS() { + return 200809L; + } + public static long _POSIX_THREAD_PRIORITY_SCHEDULING() { + return 200809L; + } + public static long _POSIX_THREAD_ATTR_STACKSIZE() { + return 200809L; + } + public static long _POSIX_THREAD_ATTR_STACKADDR() { + return 200809L; + } + public static long _POSIX_THREAD_PRIO_INHERIT() { + return 200809L; + } + public static long _POSIX_THREAD_PRIO_PROTECT() { + return 200809L; + } + public static long _POSIX_THREAD_ROBUST_PRIO_INHERIT() { + return 200809L; + } + public static int _POSIX_THREAD_ROBUST_PRIO_PROTECT() { + return (int)-1L; + } + public static long _POSIX_SEMAPHORES() { + return 200809L; + } + public static long _POSIX_REALTIME_SIGNALS() { + return 200809L; + } + public static long _POSIX_ASYNCHRONOUS_IO() { + return 200809L; + } + public static long _POSIX_PRIORITIZED_IO() { + return 200809L; + } + public static long _POSIX_SHARED_MEMORY_OBJECTS() { + return 200809L; + } + public static long _POSIX_READER_WRITER_LOCKS() { + return 200809L; + } + public static long _POSIX_TIMEOUTS() { + return 200809L; + } + public static long _POSIX_SPIN_LOCKS() { + return 200809L; + } + public static long _POSIX_SPAWN() { + return 200809L; + } + public static long _POSIX_TIMERS() { + return 200809L; + } + public static long _POSIX_BARRIERS() { + return 200809L; + } + public static long _POSIX_MESSAGE_PASSING() { + return 200809L; + } + public static long _POSIX_THREAD_PROCESS_SHARED() { + return 200809L; + } + public static long _POSIX_CLOCK_SELECTION() { + return 200809L; + } + public static long _POSIX_ADVISORY_INFO() { + return 200809L; + } + public static long _POSIX_IPV6() { + return 200809L; + } + public static long _POSIX_RAW_SOCKETS() { + return 200809L; + } + public static long _POSIX2_CHAR_TERM() { + return 200809L; + } + public static int _POSIX_SPORADIC_SERVER() { + return (int)-1L; + } + public static int _POSIX_THREAD_SPORADIC_SERVER() { + return (int)-1L; + } + public static int _POSIX_TRACE() { + return (int)-1L; + } + public static int _POSIX_TRACE_EVENT_FILTER() { + return (int)-1L; + } + public static int _POSIX_TRACE_INHERIT() { + return (int)-1L; + } + public static int _POSIX_TRACE_LOG() { + return (int)-1L; + } + public static int _POSIX_TYPED_MEMORY_OBJECTS() { + return (int)-1L; + } + public static int _POSIX_V7_LPBIG_OFFBIG() { + return (int)-1L; + } + public static int _POSIX_V6_LPBIG_OFFBIG() { + return (int)-1L; + } + public static int _XBS5_LPBIG_OFFBIG() { + return (int)-1L; + } + public static MemorySegment __ILP32_OFF32_CFLAGS() { + return constants$18.__ILP32_OFF32_CFLAGS$SEGMENT; + } + public static MemorySegment __ILP32_OFF32_LDFLAGS() { + return constants$19.__ILP32_OFF32_LDFLAGS$SEGMENT; + } + public static MemorySegment __ILP32_OFFBIG_CFLAGS() { + return constants$19.__ILP32_OFFBIG_CFLAGS$SEGMENT; + } + public static MemorySegment __ILP32_OFFBIG_LDFLAGS() { + return constants$19.__ILP32_OFFBIG_LDFLAGS$SEGMENT; + } + public static MemorySegment __LP64_OFF64_CFLAGS() { + return constants$19.__LP64_OFF64_CFLAGS$SEGMENT; + } + public static MemorySegment __LP64_OFF64_LDFLAGS() { + return constants$19.__LP64_OFF64_LDFLAGS$SEGMENT; + } + public static MemoryAddress NULL() { + return constants$19.NULL$ADDR; + } + public static int L_SET() { + return (int)0L; + } + public static int L_INCR() { + return (int)1L; + } + public static int L_XTND() { + return (int)2L; + } + public static int _SC_PAGE_SIZE() { + return (int)30L; + } + public static int _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS() { + return (int)1L; + } + public static int _CS_POSIX_V5_WIDTH_RESTRICTED_ENVS() { + return (int)4L; + } + public static int _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS() { + return (int)5L; + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/Constants$root.java new file mode 100644 index 00000000..e013f088 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/RuntimeHelper.java new file mode 100644 index 00000000..8d30b2af --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/RuntimeHelper.java @@ -0,0 +1,216 @@ +package net.codecrete.usb.linux.gen.usbdevice_fs; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_fd_set.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_fd_set.java new file mode 100644 index 00000000..3d447c24 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_fd_set.java @@ -0,0 +1,25 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +public class __kernel_fd_set { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + MemoryLayout.sequenceLayout(16, Constants$root.C_LONG_LONG$LAYOUT).withName("fds_bits") + ); + public static MemoryLayout $LAYOUT() { + return __kernel_fd_set.$struct$LAYOUT; + } + public static MemorySegment fds_bits$slice(MemorySegment seg) { + return seg.asSlice(0, 128); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_fsid_t.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_fsid_t.java new file mode 100644 index 00000000..1122a232 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_fsid_t.java @@ -0,0 +1,25 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +public class __kernel_fsid_t { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + MemoryLayout.sequenceLayout(2, Constants$root.C_INT$LAYOUT).withName("val") + ); + public static MemoryLayout $LAYOUT() { + return __kernel_fsid_t.$struct$LAYOUT; + } + public static MemorySegment val$slice(MemorySegment seg) { + return seg.asSlice(0, 8); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_sighandler_t.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_sighandler_t.java new file mode 100644 index 00000000..43fc2525 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_sighandler_t.java @@ -0,0 +1,27 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.Addressable; +import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; +public interface __kernel_sighandler_t { + + void apply(int _x0); + static MemorySegment allocate(__kernel_sighandler_t fi, MemorySession session) { + return RuntimeHelper.upcallStub(__kernel_sighandler_t.class, fi, constants$0.__kernel_sighandler_t$FUNC, session); + } + static __kernel_sighandler_t ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (int __x0) -> { + try { + constants$0.__kernel_sighandler_t$MH.invokeExact((Addressable)symbol, __x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$0.java new file mode 100644 index 00000000..d455d82c --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$0.java @@ -0,0 +1,21 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor __kernel_sighandler_t$FUNC = FunctionDescriptor.ofVoid( + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle __kernel_sighandler_t$MH = RuntimeHelper.downcallHandle( + constants$0.__kernel_sighandler_t$FUNC + ); + static final MemorySegment REISERFS_SUPER_MAGIC_STRING$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("ReIsErFs"); + static final MemorySegment REISER2FS_SUPER_MAGIC_STRING$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("ReIsEr2Fs"); + static final MemorySegment REISER2FS_JR_SUPER_MAGIC_STRING$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("ReIsEr3Fs"); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java new file mode 100644 index 00000000..670dc414 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java @@ -0,0 +1,91 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class usbdevfs_bulktransfer { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_INT$LAYOUT.withName("ep"), + Constants$root.C_INT$LAYOUT.withName("len"), + Constants$root.C_INT$LAYOUT.withName("timeout"), + MemoryLayout.paddingLayout(32), + Constants$root.C_POINTER$LAYOUT.withName("data") + ).withName("usbdevfs_bulktransfer"); + public static MemoryLayout $LAYOUT() { + return usbdevfs_bulktransfer.$struct$LAYOUT; + } + static final VarHandle ep$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ep")); + public static VarHandle ep$VH() { + return usbdevfs_bulktransfer.ep$VH; + } + public static int ep$get(MemorySegment seg) { + return (int)usbdevfs_bulktransfer.ep$VH.get(seg); + } + public static void ep$set( MemorySegment seg, int x) { + usbdevfs_bulktransfer.ep$VH.set(seg, x); + } + public static int ep$get(MemorySegment seg, long index) { + return (int)usbdevfs_bulktransfer.ep$VH.get(seg.asSlice(index*sizeof())); + } + public static void ep$set(MemorySegment seg, long index, int x) { + usbdevfs_bulktransfer.ep$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle len$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("len")); + public static VarHandle len$VH() { + return usbdevfs_bulktransfer.len$VH; + } + public static int len$get(MemorySegment seg) { + return (int)usbdevfs_bulktransfer.len$VH.get(seg); + } + public static void len$set( MemorySegment seg, int x) { + usbdevfs_bulktransfer.len$VH.set(seg, x); + } + public static int len$get(MemorySegment seg, long index) { + return (int)usbdevfs_bulktransfer.len$VH.get(seg.asSlice(index*sizeof())); + } + public static void len$set(MemorySegment seg, long index, int x) { + usbdevfs_bulktransfer.len$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle timeout$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("timeout")); + public static VarHandle timeout$VH() { + return usbdevfs_bulktransfer.timeout$VH; + } + public static int timeout$get(MemorySegment seg) { + return (int)usbdevfs_bulktransfer.timeout$VH.get(seg); + } + public static void timeout$set( MemorySegment seg, int x) { + usbdevfs_bulktransfer.timeout$VH.set(seg, x); + } + public static int timeout$get(MemorySegment seg, long index) { + return (int)usbdevfs_bulktransfer.timeout$VH.get(seg.asSlice(index*sizeof())); + } + public static void timeout$set(MemorySegment seg, long index, int x) { + usbdevfs_bulktransfer.timeout$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle data$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("data")); + public static VarHandle data$VH() { + return usbdevfs_bulktransfer.data$VH; + } + public static MemoryAddress data$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)usbdevfs_bulktransfer.data$VH.get(seg); + } + public static void data$set( MemorySegment seg, MemoryAddress x) { + usbdevfs_bulktransfer.data$VH.set(seg, x); + } + public static MemoryAddress data$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)usbdevfs_bulktransfer.data$VH.get(seg.asSlice(index*sizeof())); + } + public static void data$set(MemorySegment seg, long index, MemoryAddress x) { + usbdevfs_bulktransfer.data$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_connectinfo.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_connectinfo.java new file mode 100644 index 00000000..0ad90f26 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_connectinfo.java @@ -0,0 +1,57 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class usbdevfs_connectinfo { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_INT$LAYOUT.withName("devnum"), + Constants$root.C_CHAR$LAYOUT.withName("slow"), + MemoryLayout.paddingLayout(24) + ).withName("usbdevfs_connectinfo"); + public static MemoryLayout $LAYOUT() { + return usbdevfs_connectinfo.$struct$LAYOUT; + } + static final VarHandle devnum$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("devnum")); + public static VarHandle devnum$VH() { + return usbdevfs_connectinfo.devnum$VH; + } + public static int devnum$get(MemorySegment seg) { + return (int)usbdevfs_connectinfo.devnum$VH.get(seg); + } + public static void devnum$set( MemorySegment seg, int x) { + usbdevfs_connectinfo.devnum$VH.set(seg, x); + } + public static int devnum$get(MemorySegment seg, long index) { + return (int)usbdevfs_connectinfo.devnum$VH.get(seg.asSlice(index*sizeof())); + } + public static void devnum$set(MemorySegment seg, long index, int x) { + usbdevfs_connectinfo.devnum$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle slow$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("slow")); + public static VarHandle slow$VH() { + return usbdevfs_connectinfo.slow$VH; + } + public static byte slow$get(MemorySegment seg) { + return (byte)usbdevfs_connectinfo.slow$VH.get(seg); + } + public static void slow$set( MemorySegment seg, byte x) { + usbdevfs_connectinfo.slow$VH.set(seg, x); + } + public static byte slow$get(MemorySegment seg, long index) { + return (byte)usbdevfs_connectinfo.slow$VH.get(seg.asSlice(index*sizeof())); + } + public static void slow$set(MemorySegment seg, long index, byte x) { + usbdevfs_connectinfo.slow$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_conninfo_ex.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_conninfo_ex.java new file mode 100644 index 00000000..3279b19a --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_conninfo_ex.java @@ -0,0 +1,111 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class usbdevfs_conninfo_ex { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_INT$LAYOUT.withName("size"), + Constants$root.C_INT$LAYOUT.withName("busnum"), + Constants$root.C_INT$LAYOUT.withName("devnum"), + Constants$root.C_INT$LAYOUT.withName("speed"), + Constants$root.C_CHAR$LAYOUT.withName("num_ports"), + MemoryLayout.sequenceLayout(7, Constants$root.C_CHAR$LAYOUT).withName("ports") + ).withName("usbdevfs_conninfo_ex"); + public static MemoryLayout $LAYOUT() { + return usbdevfs_conninfo_ex.$struct$LAYOUT; + } + static final VarHandle size$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("size")); + public static VarHandle size$VH() { + return usbdevfs_conninfo_ex.size$VH; + } + public static int size$get(MemorySegment seg) { + return (int)usbdevfs_conninfo_ex.size$VH.get(seg); + } + public static void size$set( MemorySegment seg, int x) { + usbdevfs_conninfo_ex.size$VH.set(seg, x); + } + public static int size$get(MemorySegment seg, long index) { + return (int)usbdevfs_conninfo_ex.size$VH.get(seg.asSlice(index*sizeof())); + } + public static void size$set(MemorySegment seg, long index, int x) { + usbdevfs_conninfo_ex.size$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle busnum$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("busnum")); + public static VarHandle busnum$VH() { + return usbdevfs_conninfo_ex.busnum$VH; + } + public static int busnum$get(MemorySegment seg) { + return (int)usbdevfs_conninfo_ex.busnum$VH.get(seg); + } + public static void busnum$set( MemorySegment seg, int x) { + usbdevfs_conninfo_ex.busnum$VH.set(seg, x); + } + public static int busnum$get(MemorySegment seg, long index) { + return (int)usbdevfs_conninfo_ex.busnum$VH.get(seg.asSlice(index*sizeof())); + } + public static void busnum$set(MemorySegment seg, long index, int x) { + usbdevfs_conninfo_ex.busnum$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle devnum$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("devnum")); + public static VarHandle devnum$VH() { + return usbdevfs_conninfo_ex.devnum$VH; + } + public static int devnum$get(MemorySegment seg) { + return (int)usbdevfs_conninfo_ex.devnum$VH.get(seg); + } + public static void devnum$set( MemorySegment seg, int x) { + usbdevfs_conninfo_ex.devnum$VH.set(seg, x); + } + public static int devnum$get(MemorySegment seg, long index) { + return (int)usbdevfs_conninfo_ex.devnum$VH.get(seg.asSlice(index*sizeof())); + } + public static void devnum$set(MemorySegment seg, long index, int x) { + usbdevfs_conninfo_ex.devnum$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle speed$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("speed")); + public static VarHandle speed$VH() { + return usbdevfs_conninfo_ex.speed$VH; + } + public static int speed$get(MemorySegment seg) { + return (int)usbdevfs_conninfo_ex.speed$VH.get(seg); + } + public static void speed$set( MemorySegment seg, int x) { + usbdevfs_conninfo_ex.speed$VH.set(seg, x); + } + public static int speed$get(MemorySegment seg, long index) { + return (int)usbdevfs_conninfo_ex.speed$VH.get(seg.asSlice(index*sizeof())); + } + public static void speed$set(MemorySegment seg, long index, int x) { + usbdevfs_conninfo_ex.speed$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle num_ports$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("num_ports")); + public static VarHandle num_ports$VH() { + return usbdevfs_conninfo_ex.num_ports$VH; + } + public static byte num_ports$get(MemorySegment seg) { + return (byte)usbdevfs_conninfo_ex.num_ports$VH.get(seg); + } + public static void num_ports$set( MemorySegment seg, byte x) { + usbdevfs_conninfo_ex.num_ports$VH.set(seg, x); + } + public static byte num_ports$get(MemorySegment seg, long index) { + return (byte)usbdevfs_conninfo_ex.num_ports$VH.get(seg.asSlice(index*sizeof())); + } + public static void num_ports$set(MemorySegment seg, long index, byte x) { + usbdevfs_conninfo_ex.num_ports$VH.set(seg.asSlice(index*sizeof()), x); + } + public static MemorySegment ports$slice(MemorySegment seg) { + return seg.asSlice(17, 7); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java new file mode 100644 index 00000000..2dd9c901 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java @@ -0,0 +1,142 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class usbdevfs_ctrltransfer { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("bRequestType"), + Constants$root.C_CHAR$LAYOUT.withName("bRequest"), + Constants$root.C_SHORT$LAYOUT.withName("wValue"), + Constants$root.C_SHORT$LAYOUT.withName("wIndex"), + Constants$root.C_SHORT$LAYOUT.withName("wLength"), + Constants$root.C_INT$LAYOUT.withName("timeout"), + MemoryLayout.paddingLayout(32), + Constants$root.C_POINTER$LAYOUT.withName("data") + ).withName("usbdevfs_ctrltransfer"); + public static MemoryLayout $LAYOUT() { + return usbdevfs_ctrltransfer.$struct$LAYOUT; + } + static final VarHandle bRequestType$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("bRequestType")); + public static VarHandle bRequestType$VH() { + return usbdevfs_ctrltransfer.bRequestType$VH; + } + public static byte bRequestType$get(MemorySegment seg) { + return (byte)usbdevfs_ctrltransfer.bRequestType$VH.get(seg); + } + public static void bRequestType$set( MemorySegment seg, byte x) { + usbdevfs_ctrltransfer.bRequestType$VH.set(seg, x); + } + public static byte bRequestType$get(MemorySegment seg, long index) { + return (byte)usbdevfs_ctrltransfer.bRequestType$VH.get(seg.asSlice(index*sizeof())); + } + public static void bRequestType$set(MemorySegment seg, long index, byte x) { + usbdevfs_ctrltransfer.bRequestType$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle bRequest$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("bRequest")); + public static VarHandle bRequest$VH() { + return usbdevfs_ctrltransfer.bRequest$VH; + } + public static byte bRequest$get(MemorySegment seg) { + return (byte)usbdevfs_ctrltransfer.bRequest$VH.get(seg); + } + public static void bRequest$set( MemorySegment seg, byte x) { + usbdevfs_ctrltransfer.bRequest$VH.set(seg, x); + } + public static byte bRequest$get(MemorySegment seg, long index) { + return (byte)usbdevfs_ctrltransfer.bRequest$VH.get(seg.asSlice(index*sizeof())); + } + public static void bRequest$set(MemorySegment seg, long index, byte x) { + usbdevfs_ctrltransfer.bRequest$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle wValue$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("wValue")); + public static VarHandle wValue$VH() { + return usbdevfs_ctrltransfer.wValue$VH; + } + public static short wValue$get(MemorySegment seg) { + return (short)usbdevfs_ctrltransfer.wValue$VH.get(seg); + } + public static void wValue$set( MemorySegment seg, short x) { + usbdevfs_ctrltransfer.wValue$VH.set(seg, x); + } + public static short wValue$get(MemorySegment seg, long index) { + return (short)usbdevfs_ctrltransfer.wValue$VH.get(seg.asSlice(index*sizeof())); + } + public static void wValue$set(MemorySegment seg, long index, short x) { + usbdevfs_ctrltransfer.wValue$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle wIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("wIndex")); + public static VarHandle wIndex$VH() { + return usbdevfs_ctrltransfer.wIndex$VH; + } + public static short wIndex$get(MemorySegment seg) { + return (short)usbdevfs_ctrltransfer.wIndex$VH.get(seg); + } + public static void wIndex$set( MemorySegment seg, short x) { + usbdevfs_ctrltransfer.wIndex$VH.set(seg, x); + } + public static short wIndex$get(MemorySegment seg, long index) { + return (short)usbdevfs_ctrltransfer.wIndex$VH.get(seg.asSlice(index*sizeof())); + } + public static void wIndex$set(MemorySegment seg, long index, short x) { + usbdevfs_ctrltransfer.wIndex$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle wLength$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("wLength")); + public static VarHandle wLength$VH() { + return usbdevfs_ctrltransfer.wLength$VH; + } + public static short wLength$get(MemorySegment seg) { + return (short)usbdevfs_ctrltransfer.wLength$VH.get(seg); + } + public static void wLength$set( MemorySegment seg, short x) { + usbdevfs_ctrltransfer.wLength$VH.set(seg, x); + } + public static short wLength$get(MemorySegment seg, long index) { + return (short)usbdevfs_ctrltransfer.wLength$VH.get(seg.asSlice(index*sizeof())); + } + public static void wLength$set(MemorySegment seg, long index, short x) { + usbdevfs_ctrltransfer.wLength$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle timeout$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("timeout")); + public static VarHandle timeout$VH() { + return usbdevfs_ctrltransfer.timeout$VH; + } + public static int timeout$get(MemorySegment seg) { + return (int)usbdevfs_ctrltransfer.timeout$VH.get(seg); + } + public static void timeout$set( MemorySegment seg, int x) { + usbdevfs_ctrltransfer.timeout$VH.set(seg, x); + } + public static int timeout$get(MemorySegment seg, long index) { + return (int)usbdevfs_ctrltransfer.timeout$VH.get(seg.asSlice(index*sizeof())); + } + public static void timeout$set(MemorySegment seg, long index, int x) { + usbdevfs_ctrltransfer.timeout$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle data$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("data")); + public static VarHandle data$VH() { + return usbdevfs_ctrltransfer.data$VH; + } + public static MemoryAddress data$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)usbdevfs_ctrltransfer.data$VH.get(seg); + } + public static void data$set( MemorySegment seg, MemoryAddress x) { + usbdevfs_ctrltransfer.data$VH.set(seg, x); + } + public static MemoryAddress data$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)usbdevfs_ctrltransfer.data$VH.get(seg.asSlice(index*sizeof())); + } + public static void data$set(MemorySegment seg, long index, MemoryAddress x) { + usbdevfs_ctrltransfer.data$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java new file mode 100644 index 00000000..023757d7 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java @@ -0,0 +1,60 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class usbdevfs_disconnect_claim { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_INT$LAYOUT.withName("interface"), + Constants$root.C_INT$LAYOUT.withName("flags"), + MemoryLayout.sequenceLayout(256, Constants$root.C_CHAR$LAYOUT).withName("driver") + ).withName("usbdevfs_disconnect_claim"); + public static MemoryLayout $LAYOUT() { + return usbdevfs_disconnect_claim.$struct$LAYOUT; + } + static final VarHandle interface_$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("interface")); + public static VarHandle interface_$VH() { + return usbdevfs_disconnect_claim.interface_$VH; + } + public static int interface_$get(MemorySegment seg) { + return (int)usbdevfs_disconnect_claim.interface_$VH.get(seg); + } + public static void interface_$set( MemorySegment seg, int x) { + usbdevfs_disconnect_claim.interface_$VH.set(seg, x); + } + public static int interface_$get(MemorySegment seg, long index) { + return (int)usbdevfs_disconnect_claim.interface_$VH.get(seg.asSlice(index*sizeof())); + } + public static void interface_$set(MemorySegment seg, long index, int x) { + usbdevfs_disconnect_claim.interface_$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle flags$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("flags")); + public static VarHandle flags$VH() { + return usbdevfs_disconnect_claim.flags$VH; + } + public static int flags$get(MemorySegment seg) { + return (int)usbdevfs_disconnect_claim.flags$VH.get(seg); + } + public static void flags$set( MemorySegment seg, int x) { + usbdevfs_disconnect_claim.flags$VH.set(seg, x); + } + public static int flags$get(MemorySegment seg, long index) { + return (int)usbdevfs_disconnect_claim.flags$VH.get(seg.asSlice(index*sizeof())); + } + public static void flags$set(MemorySegment seg, long index, int x) { + usbdevfs_disconnect_claim.flags$VH.set(seg.asSlice(index*sizeof()), x); + } + public static MemorySegment driver$slice(MemorySegment seg) { + return seg.asSlice(8, 256); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnectsignal.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnectsignal.java new file mode 100644 index 00000000..97bf5c5e --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnectsignal.java @@ -0,0 +1,57 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class usbdevfs_disconnectsignal { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_INT$LAYOUT.withName("signr"), + MemoryLayout.paddingLayout(32), + Constants$root.C_POINTER$LAYOUT.withName("context") + ).withName("usbdevfs_disconnectsignal"); + public static MemoryLayout $LAYOUT() { + return usbdevfs_disconnectsignal.$struct$LAYOUT; + } + static final VarHandle signr$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("signr")); + public static VarHandle signr$VH() { + return usbdevfs_disconnectsignal.signr$VH; + } + public static int signr$get(MemorySegment seg) { + return (int)usbdevfs_disconnectsignal.signr$VH.get(seg); + } + public static void signr$set( MemorySegment seg, int x) { + usbdevfs_disconnectsignal.signr$VH.set(seg, x); + } + public static int signr$get(MemorySegment seg, long index) { + return (int)usbdevfs_disconnectsignal.signr$VH.get(seg.asSlice(index*sizeof())); + } + public static void signr$set(MemorySegment seg, long index, int x) { + usbdevfs_disconnectsignal.signr$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle context$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("context")); + public static VarHandle context$VH() { + return usbdevfs_disconnectsignal.context$VH; + } + public static MemoryAddress context$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)usbdevfs_disconnectsignal.context$VH.get(seg); + } + public static void context$set( MemorySegment seg, MemoryAddress x) { + usbdevfs_disconnectsignal.context$VH.set(seg, x); + } + public static MemoryAddress context$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)usbdevfs_disconnectsignal.context$VH.get(seg.asSlice(index*sizeof())); + } + public static void context$set(MemorySegment seg, long index, MemoryAddress x) { + usbdevfs_disconnectsignal.context$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_getdriver.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_getdriver.java new file mode 100644 index 00000000..50208d87 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_getdriver.java @@ -0,0 +1,43 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class usbdevfs_getdriver { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_INT$LAYOUT.withName("interface"), + MemoryLayout.sequenceLayout(256, Constants$root.C_CHAR$LAYOUT).withName("driver") + ).withName("usbdevfs_getdriver"); + public static MemoryLayout $LAYOUT() { + return usbdevfs_getdriver.$struct$LAYOUT; + } + static final VarHandle interface_$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("interface")); + public static VarHandle interface_$VH() { + return usbdevfs_getdriver.interface_$VH; + } + public static int interface_$get(MemorySegment seg) { + return (int)usbdevfs_getdriver.interface_$VH.get(seg); + } + public static void interface_$set( MemorySegment seg, int x) { + usbdevfs_getdriver.interface_$VH.set(seg, x); + } + public static int interface_$get(MemorySegment seg, long index) { + return (int)usbdevfs_getdriver.interface_$VH.get(seg.asSlice(index*sizeof())); + } + public static void interface_$set(MemorySegment seg, long index, int x) { + usbdevfs_getdriver.interface_$VH.set(seg.asSlice(index*sizeof()), x); + } + public static MemorySegment driver$slice(MemorySegment seg) { + return seg.asSlice(4, 256); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_hub_portinfo.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_hub_portinfo.java new file mode 100644 index 00000000..e7c195cd --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_hub_portinfo.java @@ -0,0 +1,43 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class usbdevfs_hub_portinfo { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("nports"), + MemoryLayout.sequenceLayout(127, Constants$root.C_CHAR$LAYOUT).withName("port") + ).withName("usbdevfs_hub_portinfo"); + public static MemoryLayout $LAYOUT() { + return usbdevfs_hub_portinfo.$struct$LAYOUT; + } + static final VarHandle nports$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("nports")); + public static VarHandle nports$VH() { + return usbdevfs_hub_portinfo.nports$VH; + } + public static byte nports$get(MemorySegment seg) { + return (byte)usbdevfs_hub_portinfo.nports$VH.get(seg); + } + public static void nports$set( MemorySegment seg, byte x) { + usbdevfs_hub_portinfo.nports$VH.set(seg, x); + } + public static byte nports$get(MemorySegment seg, long index) { + return (byte)usbdevfs_hub_portinfo.nports$VH.get(seg.asSlice(index*sizeof())); + } + public static void nports$set(MemorySegment seg, long index, byte x) { + usbdevfs_hub_portinfo.nports$VH.set(seg.asSlice(index*sizeof()), x); + } + public static MemorySegment port$slice(MemorySegment seg) { + return seg.asSlice(1, 127); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java new file mode 100644 index 00000000..35caf795 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java @@ -0,0 +1,73 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class usbdevfs_ioctl { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_INT$LAYOUT.withName("ifno"), + Constants$root.C_INT$LAYOUT.withName("ioctl_code"), + Constants$root.C_POINTER$LAYOUT.withName("data") + ).withName("usbdevfs_ioctl"); + public static MemoryLayout $LAYOUT() { + return usbdevfs_ioctl.$struct$LAYOUT; + } + static final VarHandle ifno$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ifno")); + public static VarHandle ifno$VH() { + return usbdevfs_ioctl.ifno$VH; + } + public static int ifno$get(MemorySegment seg) { + return (int)usbdevfs_ioctl.ifno$VH.get(seg); + } + public static void ifno$set( MemorySegment seg, int x) { + usbdevfs_ioctl.ifno$VH.set(seg, x); + } + public static int ifno$get(MemorySegment seg, long index) { + return (int)usbdevfs_ioctl.ifno$VH.get(seg.asSlice(index*sizeof())); + } + public static void ifno$set(MemorySegment seg, long index, int x) { + usbdevfs_ioctl.ifno$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle ioctl_code$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ioctl_code")); + public static VarHandle ioctl_code$VH() { + return usbdevfs_ioctl.ioctl_code$VH; + } + public static int ioctl_code$get(MemorySegment seg) { + return (int)usbdevfs_ioctl.ioctl_code$VH.get(seg); + } + public static void ioctl_code$set( MemorySegment seg, int x) { + usbdevfs_ioctl.ioctl_code$VH.set(seg, x); + } + public static int ioctl_code$get(MemorySegment seg, long index) { + return (int)usbdevfs_ioctl.ioctl_code$VH.get(seg.asSlice(index*sizeof())); + } + public static void ioctl_code$set(MemorySegment seg, long index, int x) { + usbdevfs_ioctl.ioctl_code$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle data$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("data")); + public static VarHandle data$VH() { + return usbdevfs_ioctl.data$VH; + } + public static MemoryAddress data$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)usbdevfs_ioctl.data$VH.get(seg); + } + public static void data$set( MemorySegment seg, MemoryAddress x) { + usbdevfs_ioctl.data$VH.set(seg, x); + } + public static MemoryAddress data$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)usbdevfs_ioctl.data$VH.get(seg.asSlice(index*sizeof())); + } + public static void data$set(MemorySegment seg, long index, MemoryAddress x) { + usbdevfs_ioctl.data$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java new file mode 100644 index 00000000..dcbb988b --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java @@ -0,0 +1,73 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class usbdevfs_iso_packet_desc { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_INT$LAYOUT.withName("length"), + Constants$root.C_INT$LAYOUT.withName("actual_length"), + Constants$root.C_INT$LAYOUT.withName("status") + ).withName("usbdevfs_iso_packet_desc"); + public static MemoryLayout $LAYOUT() { + return usbdevfs_iso_packet_desc.$struct$LAYOUT; + } + static final VarHandle length$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("length")); + public static VarHandle length$VH() { + return usbdevfs_iso_packet_desc.length$VH; + } + public static int length$get(MemorySegment seg) { + return (int)usbdevfs_iso_packet_desc.length$VH.get(seg); + } + public static void length$set( MemorySegment seg, int x) { + usbdevfs_iso_packet_desc.length$VH.set(seg, x); + } + public static int length$get(MemorySegment seg, long index) { + return (int)usbdevfs_iso_packet_desc.length$VH.get(seg.asSlice(index*sizeof())); + } + public static void length$set(MemorySegment seg, long index, int x) { + usbdevfs_iso_packet_desc.length$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle actual_length$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("actual_length")); + public static VarHandle actual_length$VH() { + return usbdevfs_iso_packet_desc.actual_length$VH; + } + public static int actual_length$get(MemorySegment seg) { + return (int)usbdevfs_iso_packet_desc.actual_length$VH.get(seg); + } + public static void actual_length$set( MemorySegment seg, int x) { + usbdevfs_iso_packet_desc.actual_length$VH.set(seg, x); + } + public static int actual_length$get(MemorySegment seg, long index) { + return (int)usbdevfs_iso_packet_desc.actual_length$VH.get(seg.asSlice(index*sizeof())); + } + public static void actual_length$set(MemorySegment seg, long index, int x) { + usbdevfs_iso_packet_desc.actual_length$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle status$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("status")); + public static VarHandle status$VH() { + return usbdevfs_iso_packet_desc.status$VH; + } + public static int status$get(MemorySegment seg) { + return (int)usbdevfs_iso_packet_desc.status$VH.get(seg); + } + public static void status$set( MemorySegment seg, int x) { + usbdevfs_iso_packet_desc.status$VH.set(seg, x); + } + public static int status$get(MemorySegment seg, long index) { + return (int)usbdevfs_iso_packet_desc.status$VH.get(seg.asSlice(index*sizeof())); + } + public static void status$set(MemorySegment seg, long index, int x) { + usbdevfs_iso_packet_desc.status$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java new file mode 100644 index 00000000..0aec7f05 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java @@ -0,0 +1,56 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class usbdevfs_setinterface { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_INT$LAYOUT.withName("interface"), + Constants$root.C_INT$LAYOUT.withName("altsetting") + ).withName("usbdevfs_setinterface"); + public static MemoryLayout $LAYOUT() { + return usbdevfs_setinterface.$struct$LAYOUT; + } + static final VarHandle interface_$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("interface")); + public static VarHandle interface_$VH() { + return usbdevfs_setinterface.interface_$VH; + } + public static int interface_$get(MemorySegment seg) { + return (int)usbdevfs_setinterface.interface_$VH.get(seg); + } + public static void interface_$set( MemorySegment seg, int x) { + usbdevfs_setinterface.interface_$VH.set(seg, x); + } + public static int interface_$get(MemorySegment seg, long index) { + return (int)usbdevfs_setinterface.interface_$VH.get(seg.asSlice(index*sizeof())); + } + public static void interface_$set(MemorySegment seg, long index, int x) { + usbdevfs_setinterface.interface_$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle altsetting$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("altsetting")); + public static VarHandle altsetting$VH() { + return usbdevfs_setinterface.altsetting$VH; + } + public static int altsetting$get(MemorySegment seg) { + return (int)usbdevfs_setinterface.altsetting$VH.get(seg); + } + public static void altsetting$set( MemorySegment seg, int x) { + usbdevfs_setinterface.altsetting$VH.set(seg, x); + } + public static int altsetting$get(MemorySegment seg, long index) { + return (int)usbdevfs_setinterface.altsetting$VH.get(seg.asSlice(index*sizeof())); + } + public static void altsetting$set(MemorySegment seg, long index, int x) { + usbdevfs_setinterface.altsetting$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_streams.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_streams.java new file mode 100644 index 00000000..463692b3 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_streams.java @@ -0,0 +1,57 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class usbdevfs_streams { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_INT$LAYOUT.withName("num_streams"), + Constants$root.C_INT$LAYOUT.withName("num_eps"), + MemoryLayout.sequenceLayout(0, Constants$root.C_CHAR$LAYOUT).withName("eps") + ).withName("usbdevfs_streams"); + public static MemoryLayout $LAYOUT() { + return usbdevfs_streams.$struct$LAYOUT; + } + static final VarHandle num_streams$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("num_streams")); + public static VarHandle num_streams$VH() { + return usbdevfs_streams.num_streams$VH; + } + public static int num_streams$get(MemorySegment seg) { + return (int)usbdevfs_streams.num_streams$VH.get(seg); + } + public static void num_streams$set( MemorySegment seg, int x) { + usbdevfs_streams.num_streams$VH.set(seg, x); + } + public static int num_streams$get(MemorySegment seg, long index) { + return (int)usbdevfs_streams.num_streams$VH.get(seg.asSlice(index*sizeof())); + } + public static void num_streams$set(MemorySegment seg, long index, int x) { + usbdevfs_streams.num_streams$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle num_eps$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("num_eps")); + public static VarHandle num_eps$VH() { + return usbdevfs_streams.num_eps$VH; + } + public static int num_eps$get(MemorySegment seg) { + return (int)usbdevfs_streams.num_eps$VH.get(seg); + } + public static void num_eps$set( MemorySegment seg, int x) { + usbdevfs_streams.num_eps$VH.set(seg, x); + } + public static int num_eps$get(MemorySegment seg, long index) { + return (int)usbdevfs_streams.num_eps$VH.get(seg.asSlice(index*sizeof())); + } + public static void num_eps$set(MemorySegment seg, long index, int x) { + usbdevfs_streams.num_eps$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java new file mode 100644 index 00000000..5ffb8ae3 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java @@ -0,0 +1,252 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class usbdevfs_urb { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("type"), + Constants$root.C_CHAR$LAYOUT.withName("endpoint"), + MemoryLayout.paddingLayout(16), + Constants$root.C_INT$LAYOUT.withName("status"), + Constants$root.C_INT$LAYOUT.withName("flags"), + MemoryLayout.paddingLayout(32), + Constants$root.C_POINTER$LAYOUT.withName("buffer"), + Constants$root.C_INT$LAYOUT.withName("buffer_length"), + Constants$root.C_INT$LAYOUT.withName("actual_length"), + Constants$root.C_INT$LAYOUT.withName("start_frame"), + MemoryLayout.unionLayout( + Constants$root.C_INT$LAYOUT.withName("number_of_packets"), + Constants$root.C_INT$LAYOUT.withName("stream_id") + ).withName("$anon$0"), + Constants$root.C_INT$LAYOUT.withName("error_count"), + Constants$root.C_INT$LAYOUT.withName("signr"), + Constants$root.C_POINTER$LAYOUT.withName("usercontext"), + MemoryLayout.sequenceLayout(0, MemoryLayout.structLayout( + Constants$root.C_INT$LAYOUT.withName("length"), + Constants$root.C_INT$LAYOUT.withName("actual_length"), + Constants$root.C_INT$LAYOUT.withName("status") + ).withName("usbdevfs_iso_packet_desc")).withName("iso_frame_desc") + ).withName("usbdevfs_urb"); + public static MemoryLayout $LAYOUT() { + return usbdevfs_urb.$struct$LAYOUT; + } + static final VarHandle type$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("type")); + public static VarHandle type$VH() { + return usbdevfs_urb.type$VH; + } + public static byte type$get(MemorySegment seg) { + return (byte)usbdevfs_urb.type$VH.get(seg); + } + public static void type$set( MemorySegment seg, byte x) { + usbdevfs_urb.type$VH.set(seg, x); + } + public static byte type$get(MemorySegment seg, long index) { + return (byte)usbdevfs_urb.type$VH.get(seg.asSlice(index*sizeof())); + } + public static void type$set(MemorySegment seg, long index, byte x) { + usbdevfs_urb.type$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle endpoint$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("endpoint")); + public static VarHandle endpoint$VH() { + return usbdevfs_urb.endpoint$VH; + } + public static byte endpoint$get(MemorySegment seg) { + return (byte)usbdevfs_urb.endpoint$VH.get(seg); + } + public static void endpoint$set( MemorySegment seg, byte x) { + usbdevfs_urb.endpoint$VH.set(seg, x); + } + public static byte endpoint$get(MemorySegment seg, long index) { + return (byte)usbdevfs_urb.endpoint$VH.get(seg.asSlice(index*sizeof())); + } + public static void endpoint$set(MemorySegment seg, long index, byte x) { + usbdevfs_urb.endpoint$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle status$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("status")); + public static VarHandle status$VH() { + return usbdevfs_urb.status$VH; + } + public static int status$get(MemorySegment seg) { + return (int)usbdevfs_urb.status$VH.get(seg); + } + public static void status$set( MemorySegment seg, int x) { + usbdevfs_urb.status$VH.set(seg, x); + } + public static int status$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.status$VH.get(seg.asSlice(index*sizeof())); + } + public static void status$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.status$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle flags$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("flags")); + public static VarHandle flags$VH() { + return usbdevfs_urb.flags$VH; + } + public static int flags$get(MemorySegment seg) { + return (int)usbdevfs_urb.flags$VH.get(seg); + } + public static void flags$set( MemorySegment seg, int x) { + usbdevfs_urb.flags$VH.set(seg, x); + } + public static int flags$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.flags$VH.get(seg.asSlice(index*sizeof())); + } + public static void flags$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.flags$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle buffer$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("buffer")); + public static VarHandle buffer$VH() { + return usbdevfs_urb.buffer$VH; + } + public static MemoryAddress buffer$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)usbdevfs_urb.buffer$VH.get(seg); + } + public static void buffer$set( MemorySegment seg, MemoryAddress x) { + usbdevfs_urb.buffer$VH.set(seg, x); + } + public static MemoryAddress buffer$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)usbdevfs_urb.buffer$VH.get(seg.asSlice(index*sizeof())); + } + public static void buffer$set(MemorySegment seg, long index, MemoryAddress x) { + usbdevfs_urb.buffer$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle buffer_length$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("buffer_length")); + public static VarHandle buffer_length$VH() { + return usbdevfs_urb.buffer_length$VH; + } + public static int buffer_length$get(MemorySegment seg) { + return (int)usbdevfs_urb.buffer_length$VH.get(seg); + } + public static void buffer_length$set( MemorySegment seg, int x) { + usbdevfs_urb.buffer_length$VH.set(seg, x); + } + public static int buffer_length$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.buffer_length$VH.get(seg.asSlice(index*sizeof())); + } + public static void buffer_length$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.buffer_length$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle actual_length$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("actual_length")); + public static VarHandle actual_length$VH() { + return usbdevfs_urb.actual_length$VH; + } + public static int actual_length$get(MemorySegment seg) { + return (int)usbdevfs_urb.actual_length$VH.get(seg); + } + public static void actual_length$set( MemorySegment seg, int x) { + usbdevfs_urb.actual_length$VH.set(seg, x); + } + public static int actual_length$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.actual_length$VH.get(seg.asSlice(index*sizeof())); + } + public static void actual_length$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.actual_length$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle start_frame$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("start_frame")); + public static VarHandle start_frame$VH() { + return usbdevfs_urb.start_frame$VH; + } + public static int start_frame$get(MemorySegment seg) { + return (int)usbdevfs_urb.start_frame$VH.get(seg); + } + public static void start_frame$set( MemorySegment seg, int x) { + usbdevfs_urb.start_frame$VH.set(seg, x); + } + public static int start_frame$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.start_frame$VH.get(seg.asSlice(index*sizeof())); + } + public static void start_frame$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.start_frame$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle number_of_packets$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("number_of_packets")); + public static VarHandle number_of_packets$VH() { + return usbdevfs_urb.number_of_packets$VH; + } + public static int number_of_packets$get(MemorySegment seg) { + return (int)usbdevfs_urb.number_of_packets$VH.get(seg); + } + public static void number_of_packets$set( MemorySegment seg, int x) { + usbdevfs_urb.number_of_packets$VH.set(seg, x); + } + public static int number_of_packets$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.number_of_packets$VH.get(seg.asSlice(index*sizeof())); + } + public static void number_of_packets$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.number_of_packets$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle stream_id$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("stream_id")); + public static VarHandle stream_id$VH() { + return usbdevfs_urb.stream_id$VH; + } + public static int stream_id$get(MemorySegment seg) { + return (int)usbdevfs_urb.stream_id$VH.get(seg); + } + public static void stream_id$set( MemorySegment seg, int x) { + usbdevfs_urb.stream_id$VH.set(seg, x); + } + public static int stream_id$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.stream_id$VH.get(seg.asSlice(index*sizeof())); + } + public static void stream_id$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.stream_id$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle error_count$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("error_count")); + public static VarHandle error_count$VH() { + return usbdevfs_urb.error_count$VH; + } + public static int error_count$get(MemorySegment seg) { + return (int)usbdevfs_urb.error_count$VH.get(seg); + } + public static void error_count$set( MemorySegment seg, int x) { + usbdevfs_urb.error_count$VH.set(seg, x); + } + public static int error_count$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.error_count$VH.get(seg.asSlice(index*sizeof())); + } + public static void error_count$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.error_count$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle signr$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("signr")); + public static VarHandle signr$VH() { + return usbdevfs_urb.signr$VH; + } + public static int signr$get(MemorySegment seg) { + return (int)usbdevfs_urb.signr$VH.get(seg); + } + public static void signr$set( MemorySegment seg, int x) { + usbdevfs_urb.signr$VH.set(seg, x); + } + public static int signr$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.signr$VH.get(seg.asSlice(index*sizeof())); + } + public static void signr$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.signr$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle usercontext$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("usercontext")); + public static VarHandle usercontext$VH() { + return usbdevfs_urb.usercontext$VH; + } + public static MemoryAddress usercontext$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)usbdevfs_urb.usercontext$VH.get(seg); + } + public static void usercontext$set( MemorySegment seg, MemoryAddress x) { + usbdevfs_urb.usercontext$VH.set(seg, x); + } + public static MemoryAddress usercontext$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)usbdevfs_urb.usercontext$VH.get(seg.asSlice(index*sizeof())); + } + public static void usercontext$set(MemorySegment seg, long index, MemoryAddress x) { + usbdevfs_urb.usercontext$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java new file mode 100644 index 00000000..034c4d1b --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java @@ -0,0 +1,366 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.MemorySegment; + +import static java.lang.foreign.ValueLayout.*; +public class usbdevice_fs { + + /* package-private */ usbdevice_fs() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static int __BITS_PER_LONG() { + return (int)64L; + } + public static int __FD_SETSIZE() { + return (int)1024L; + } + public static int ADFS_SUPER_MAGIC() { + return (int)44533L; + } + public static int AFFS_SUPER_MAGIC() { + return (int)44543L; + } + public static int AFS_SUPER_MAGIC() { + return (int)1397113167L; + } + public static int AUTOFS_SUPER_MAGIC() { + return (int)391L; + } + public static int CODA_SUPER_MAGIC() { + return (int)1937076805L; + } + public static int CRAMFS_MAGIC() { + return (int)684539205L; + } + public static int CRAMFS_MAGIC_WEND() { + return (int)1161678120L; + } + public static int DEBUGFS_MAGIC() { + return (int)1684170528L; + } + public static int SECURITYFS_MAGIC() { + return (int)1935894131L; + } + public static int SMACK_MAGIC() { + return (int)1128357203L; + } + public static int TMPFS_MAGIC() { + return (int)16914836L; + } + public static int SQUASHFS_MAGIC() { + return (int)1936814952L; + } + public static int ECRYPTFS_SUPER_MAGIC() { + return (int)61791L; + } + public static int EFS_SUPER_MAGIC() { + return (int)4278867L; + } + public static int EXT2_SUPER_MAGIC() { + return (int)61267L; + } + public static int EXT3_SUPER_MAGIC() { + return (int)61267L; + } + public static int EXT4_SUPER_MAGIC() { + return (int)61267L; + } + public static int NILFS_SUPER_MAGIC() { + return (int)13364L; + } + public static int ISOFS_SUPER_MAGIC() { + return (int)38496L; + } + public static int JFFS2_SUPER_MAGIC() { + return (int)29366L; + } + public static int XFS_SUPER_MAGIC() { + return (int)1481003842L; + } + public static int PSTOREFS_MAGIC() { + return (int)1634035564L; + } + public static int HOSTFS_SUPER_MAGIC() { + return (int)12648430L; + } + public static int OVERLAYFS_SUPER_MAGIC() { + return (int)2035054128L; + } + public static int MINIX_SUPER_MAGIC() { + return (int)4991L; + } + public static int MINIX_SUPER_MAGIC2() { + return (int)5007L; + } + public static int MINIX2_SUPER_MAGIC() { + return (int)9320L; + } + public static int MINIX2_SUPER_MAGIC2() { + return (int)9336L; + } + public static int MINIX3_SUPER_MAGIC() { + return (int)19802L; + } + public static int MSDOS_SUPER_MAGIC() { + return (int)19780L; + } + public static int NCP_SUPER_MAGIC() { + return (int)22092L; + } + public static int NFS_SUPER_MAGIC() { + return (int)26985L; + } + public static int OCFS2_SUPER_MAGIC() { + return (int)1952539503L; + } + public static int OPENPROM_SUPER_MAGIC() { + return (int)40865L; + } + public static int QNX4_SUPER_MAGIC() { + return (int)47L; + } + public static int QNX6_SUPER_MAGIC() { + return (int)1746473250L; + } + public static int AFS_FS_MAGIC() { + return (int)1799439955L; + } + public static int REISERFS_SUPER_MAGIC() { + return (int)1382369651L; + } + public static int SMB_SUPER_MAGIC() { + return (int)20859L; + } + public static int CGROUP_SUPER_MAGIC() { + return (int)2613483L; + } + public static int CGROUP2_SUPER_MAGIC() { + return (int)1667723888L; + } + public static int RDTGROUP_SUPER_MAGIC() { + return (int)124082209L; + } + public static int STACK_END_MAGIC() { + return (int)1470918301L; + } + public static int TRACEFS_MAGIC() { + return (int)1953653091L; + } + public static int V9FS_MAGIC() { + return (int)16914839L; + } + public static int BDEVFS_MAGIC() { + return (int)1650746742L; + } + public static int DAXFS_MAGIC() { + return (int)1684300152L; + } + public static int BINFMTFS_MAGIC() { + return (int)1112100429L; + } + public static int DEVPTS_SUPER_MAGIC() { + return (int)7377L; + } + public static int BINDERFS_SUPER_MAGIC() { + return (int)1819242352L; + } + public static int FUTEXFS_SUPER_MAGIC() { + return (int)195894762L; + } + public static int PIPEFS_MAGIC() { + return (int)1346981957L; + } + public static int PROC_SUPER_MAGIC() { + return (int)40864L; + } + public static int SOCKFS_MAGIC() { + return (int)1397703499L; + } + public static int SYSFS_MAGIC() { + return (int)1650812274L; + } + public static int USBDEVICE_SUPER_MAGIC() { + return (int)40866L; + } + public static int MTD_INODE_FS_MAGIC() { + return (int)288389204L; + } + public static int ANON_INODE_FS_MAGIC() { + return (int)151263540L; + } + public static int BTRFS_TEST_MAGIC() { + return (int)1936880249L; + } + public static int NSFS_MAGIC() { + return (int)1853056627L; + } + public static int AAFS_MAGIC() { + return (int)1513908720L; + } + public static int ZONEFS_MAGIC() { + return (int)1515144787L; + } + public static int UDF_SUPER_MAGIC() { + return (int)352400198L; + } + public static int BALLOON_KVM_MAGIC() { + return (int)325456742L; + } + public static int ZSMALLOC_MAGIC() { + return (int)1479104553L; + } + public static int DMA_BUF_MAGIC() { + return (int)1145913666L; + } + public static int DEVMEM_MAGIC() { + return (int)1162691661L; + } + public static int Z3FOLD_MAGIC() { + return (int)51L; + } + public static int SECRETMEM_MAGIC() { + return (int)1397048141L; + } + public static int SHIFTFS_MAGIC() { + return (int)1785031266L; + } + public static int USBDEVFS_MAXDRIVERNAME() { + return (int)255L; + } + public static int USBDEVFS_URB_SHORT_NOT_OK() { + return (int)1L; + } + public static int USBDEVFS_URB_ISO_ASAP() { + return (int)2L; + } + public static int USBDEVFS_URB_BULK_CONTINUATION() { + return (int)4L; + } + public static int USBDEVFS_URB_NO_FSBR() { + return (int)32L; + } + public static int USBDEVFS_URB_ZERO_PACKET() { + return (int)64L; + } + public static int USBDEVFS_URB_NO_INTERRUPT() { + return (int)128L; + } + public static int USBDEVFS_URB_TYPE_ISO() { + return (int)0L; + } + public static int USBDEVFS_URB_TYPE_INTERRUPT() { + return (int)1L; + } + public static int USBDEVFS_URB_TYPE_CONTROL() { + return (int)2L; + } + public static int USBDEVFS_URB_TYPE_BULK() { + return (int)3L; + } + public static int USBDEVFS_CAP_ZERO_PACKET() { + return (int)1L; + } + public static int USBDEVFS_CAP_BULK_CONTINUATION() { + return (int)2L; + } + public static int USBDEVFS_CAP_NO_PACKET_SIZE_LIM() { + return (int)4L; + } + public static int USBDEVFS_CAP_BULK_SCATTER_GATHER() { + return (int)8L; + } + public static int USBDEVFS_CAP_REAP_AFTER_DISCONNECT() { + return (int)16L; + } + public static int USBDEVFS_CAP_MMAP() { + return (int)32L; + } + public static int USBDEVFS_CAP_DROP_PRIVILEGES() { + return (int)64L; + } + public static int USBDEVFS_CAP_CONNINFO_EX() { + return (int)128L; + } + public static int USBDEVFS_CAP_SUSPEND() { + return (int)256L; + } + public static int USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER() { + return (int)1L; + } + public static int USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER() { + return (int)2L; + } + public static OfShort __s16 = Constants$root.C_SHORT$LAYOUT; + public static OfInt __s32 = Constants$root.C_INT$LAYOUT; + public static OfLong __s64 = Constants$root.C_LONG_LONG$LAYOUT; + public static OfInt __kernel_key_t = Constants$root.C_INT$LAYOUT; + public static OfInt __kernel_mqd_t = Constants$root.C_INT$LAYOUT; + public static OfLong __kernel_long_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfInt __kernel_pid_t = Constants$root.C_INT$LAYOUT; + public static OfInt __kernel_ipc_pid_t = Constants$root.C_INT$LAYOUT; + public static OfLong __kernel_suseconds_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfInt __kernel_daddr_t = Constants$root.C_INT$LAYOUT; + public static OfLong __kernel_ssize_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __kernel_ptrdiff_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __kernel_off_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __kernel_loff_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __kernel_old_time_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __kernel_time_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __kernel_time64_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong __kernel_clock_t = Constants$root.C_LONG_LONG$LAYOUT; + public static OfInt __kernel_timer_t = Constants$root.C_INT$LAYOUT; + public static OfInt __kernel_clockid_t = Constants$root.C_INT$LAYOUT; + public static OfAddress __kernel_caddr_t = Constants$root.C_POINTER$LAYOUT; + public static int SELINUX_MAGIC() { + return (int)4185718668L; + } + public static int RAMFS_MAGIC() { + return (int)2240043254L; + } + public static int HUGETLBFS_MAGIC() { + return (int)2508478710L; + } + public static int EROFS_SUPER_MAGIC_V1() { + return (int)3774210530L; + } + public static int XENFS_SUPER_MAGIC() { + return (int)2881100148L; + } + public static int BTRFS_SUPER_MAGIC() { + return (int)2435016766L; + } + public static int F2FS_SUPER_MAGIC() { + return (int)4076150800L; + } + public static int HPFS_SUPER_MAGIC() { + return (int)4187351113L; + } + public static int EFIVARFS_MAGIC() { + return (int)3730735588L; + } + public static MemorySegment REISERFS_SUPER_MAGIC_STRING() { + return constants$0.REISERFS_SUPER_MAGIC_STRING$SEGMENT; + } + public static MemorySegment REISER2FS_SUPER_MAGIC_STRING() { + return constants$0.REISER2FS_SUPER_MAGIC_STRING$SEGMENT; + } + public static MemorySegment REISER2FS_JR_SUPER_MAGIC_STRING() { + return constants$0.REISER2FS_JR_SUPER_MAGIC_STRING$SEGMENT; + } + public static int BPF_FS_MAGIC() { + return (int)3405662737L; + } + public static int PPC_CMM_MAGIC() { + return (int)3344373136L; + } +} + + From 03dda1f01db5a867b83efdaa468bccd7dfbcac77 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 22 Aug 2022 20:11:10 +0200 Subject: [PATCH 004/433] jextract tests on Windows --- java-does-usb/jextract/gen_windows.cmd | 67 ++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 java-does-usb/jextract/gen_windows.cmd diff --git a/java-does-usb/jextract/gen_windows.cmd b/java-does-usb/jextract/gen_windows.cmd new file mode 100644 index 00000000..399b9408 --- /dev/null +++ b/java-does-usb/jextract/gen_windows.cmd @@ -0,0 +1,67 @@ +#!/bin/sh + +set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract + +:: handleapi.h +:: Generates more than 1000 files +:: Functions like CloseHandle() are generated multiple times but none of them in a public class +::%JEXTRACT% --source --output ../src/main/java ^ +:: -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ +:: --header-class-name handleapi ^ +:: --target-package net.codecrete.usb.windows.gen.handleapi ^ +:: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\handleapi.h" + +:: Generates code that produces run-time error: +:: java.lang.UnsatisfiedLinkError: unresolved symbol: CloseHandle +::%JEXTRACT% --source --output ../src/main/java ^ +:: -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ +:: --header-class-name handleapi ^ +:: --target-package net.codecrete.usb.windows.gen.handleapi ^ +:: --include-function CloseHandle ^ +:: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\handleapi.h" + +:: Generates code that produces run-time error: +:: java.lang.UnsatisfiedLinkError: unresolved symbol: CloseHandle +::%JEXTRACT% --source --output ../src/main/java ^ +:: -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ +:: --header-class-name handleapi ^ +:: --target-package net.codecrete.usb.windows.gen.handleapi ^ +:: --include-function CloseHandle ^ +:: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\Windows.h" + +:: winusb.h +:: Fails with error: +:: C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\shared\usb.h:32:9: error: unknown type name 'LARGE_INTEGER' +:: winusb.h requires that certain other header files (like Windows.h) are processed first +::%JEXTRACT% --source --output ../src/main/java ^ +:: -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ +:: --header-class-name WinUSB ^ +:: --target-package net.codecrete.usb.windows.gen.winusb ^ +:: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\winusb.h" + +:: cfgmgr32.h +:: Fails with error: +:: C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\shared\devpropdef.h:33:9: error: unknown type name 'ULONG' +::%JEXTRACT% --source --output ../src/main/java ^ +:: -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ +:: --header-class-name CfgMgr32 ^ +:: --target-package net.codecrete.usb.windows.gen.cfgmgr32 ^ +:: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\cfgmgr32.h" + +:: setupapi.h +:: Fails with error: +:: C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\setupapi.h:65:9: error: unknown type name 'GUID' +::%JEXTRACT% --source --output ../src/main/java ^ +:: -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ +:: --header-class-name SetupApi ^ +:: --target-package net.codecrete.usb.windows.gen.setupapi ^ +:: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\setupapi.h" + +:: usbioctl.h +:: Fails with error: +:: C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\setupapi.h:65:9: error: unknown type name 'GUID' +::%JEXTRACT% --source --output ../src/main/java ^ +:: -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ +:: --header-class-name USBIOCtl ^ +:: --target-package net.codecrete.usb.windows.gen.usbioctl ^ +:: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\shared\usbioctl.h" From e434b587ac9d86f057bf891cde141a8529b18454 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 22 Aug 2022 22:15:41 +0200 Subject: [PATCH 005/433] macOS: nicer class name --- java-does-usb/jextract/gen_macos.sh | 1 + .../net/codecrete/usb/macos/gen/{mach_h.java => mach.java} | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) rename java-does-usb/src/main/java/net/codecrete/usb/macos/gen/{mach_h.java => mach.java} (95%) diff --git a/java-does-usb/jextract/gen_macos.sh b/java-does-usb/jextract/gen_macos.sh index 1ed1f947..2aabdfc6 100755 --- a/java-does-usb/jextract/gen_macos.sh +++ b/java-does-usb/jextract/gen_macos.sh @@ -11,5 +11,6 @@ JEXTRACT=../../../jextract/build/jextract/bin/jextract ## mach_error $JEXTRACT --source --target-package net.codecrete.usb.macos.gen --output ../src/main/java \ -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include \ + --header-class-name mach \ --include-function mach_error \ /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/mach/mach.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach_h.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach.java similarity index 95% rename from java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach_h.java rename to java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach.java index 24894eb4..c9d09ce1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach_h.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach.java @@ -6,9 +6,9 @@ import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; -public class mach_h { +public class mach { - /* package-private */ mach_h() {} + /* package-private */ mach() {} public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; public static OfInt C_INT = Constants$root.C_INT$LAYOUT; From 2c8764bb0755142745696f5699e83aec1e62a366 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 23 Aug 2022 19:59:12 +0200 Subject: [PATCH 006/433] Linux: reduce jextract gen to needed functions/structs --- java-does-usb/jextract/gen_linux.sh | 12 + .../codecrete/usb/linux/gen/errno/errno.java | 522 ---- .../usb/linux/gen/fcntl/__fsid_t.java | 25 - .../usb/linux/gen/fcntl/constants$0.java | 44 - .../usb/linux/gen/fcntl/constants$1.java | 20 - .../codecrete/usb/linux/gen/fcntl/fcntl.java | 647 ---- .../codecrete/usb/linux/gen/fcntl/flock.java | 109 - .../codecrete/usb/linux/gen/fcntl/stat.java | 234 -- .../usb/linux/gen/fcntl/timespec.java | 56 - .../codecrete/usb/linux/gen/ioctl/ioctl.java | 726 ----- .../codecrete/usb/linux/gen/ioctl/termio.java | 112 - .../usb/linux/gen/ioctl/winsize.java | 90 - .../usb/linux/gen/unistd/__fsid_t.java | 25 - .../usb/linux/gen/unistd/constants$0.java | 43 - .../usb/linux/gen/unistd/constants$1.java | 61 - .../usb/linux/gen/unistd/constants$10.java | 52 - .../usb/linux/gen/unistd/constants$11.java | 65 - .../usb/linux/gen/unistd/constants$12.java | 55 - .../usb/linux/gen/unistd/constants$13.java | 44 - .../usb/linux/gen/unistd/constants$14.java | 55 - .../usb/linux/gen/unistd/constants$15.java | 50 - .../usb/linux/gen/unistd/constants$16.java | 50 - .../usb/linux/gen/unistd/constants$17.java | 51 - .../usb/linux/gen/unistd/constants$18.java | 52 - .../usb/linux/gen/unistd/constants$19.java | 17 - .../usb/linux/gen/unistd/constants$2.java | 58 - .../usb/linux/gen/unistd/constants$3.java | 58 - .../usb/linux/gen/unistd/constants$4.java | 60 - .../usb/linux/gen/unistd/constants$5.java | 57 - .../usb/linux/gen/unistd/constants$6.java | 50 - .../usb/linux/gen/unistd/constants$7.java | 50 - .../usb/linux/gen/unistd/constants$8.java | 46 - .../usb/linux/gen/unistd/constants$9.java | 53 - .../usb/linux/gen/unistd/unistd.java | 2682 ----------------- .../gen/usbdevice_fs/__kernel_fd_set.java | 25 - .../gen/usbdevice_fs/__kernel_fsid_t.java | 25 - .../usbdevice_fs/__kernel_sighandler_t.java | 27 - .../linux/gen/usbdevice_fs/constants$0.java | 21 - .../usbdevice_fs/usbdevfs_connectinfo.java | 57 - .../usbdevice_fs/usbdevfs_conninfo_ex.java | 111 - .../usbdevfs_disconnect_claim.java | 60 - .../usbdevfs_disconnectsignal.java | 57 - .../gen/usbdevice_fs/usbdevfs_getdriver.java | 43 - .../usbdevice_fs/usbdevfs_hub_portinfo.java | 43 - .../gen/usbdevice_fs/usbdevfs_ioctl.java | 73 - .../usbdevfs_iso_packet_desc.java | 73 - .../usbdevice_fs/usbdevfs_setinterface.java | 56 - .../gen/usbdevice_fs/usbdevfs_streams.java | 57 - .../linux/gen/usbdevice_fs/usbdevfs_urb.java | 252 -- .../linux/gen/usbdevice_fs/usbdevice_fs.java | 347 --- 50 files changed, 12 insertions(+), 7646 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/__fsid_t.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$1.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/flock.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/stat.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/timespec.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/termio.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/winsize.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/__fsid_t.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$1.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$10.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$11.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$12.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$13.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$14.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$15.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$16.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$17.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$18.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$19.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$2.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$3.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$4.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$5.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$6.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$7.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$8.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$9.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_fd_set.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_fsid_t.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_sighandler_t.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_connectinfo.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_conninfo_ex.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnectsignal.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_getdriver.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_hub_portinfo.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_streams.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java diff --git a/java-does-usb/jextract/gen_linux.sh b/java-does-usb/jextract/gen_linux.sh index 6fc40342..cfd9db19 100755 --- a/java-does-usb/jextract/gen_linux.sh +++ b/java-does-usb/jextract/gen_linux.sh @@ -13,24 +13,30 @@ JEXTRACT=../../../jextract/build/jextract/bin/jextract $JEXTRACT --source --output ../src/main/java \ --header-class-name errno \ --target-package net.codecrete.usb.linux.gen.errno \ + --include-function __errno_location \ /usr/include/errno.h # ioctl.h $JEXTRACT --source --output ../src/main/java \ --header-class-name ioctl \ --target-package net.codecrete.usb.linux.gen.ioctl \ + --include-function ioctl \ /usr/include/x86_64-linux-gnu/sys/ioctl.h # fcntl.h $JEXTRACT --source --output ../src/main/java \ --header-class-name fcntl \ --target-package net.codecrete.usb.linux.gen.fcntl \ + --include-function open \ + --include-macro O_CLOEXEC \ + --include-macro O_RDWR \ /usr/include/fcntl.h # unistd.h $JEXTRACT --source --output ../src/main/java \ --header-class-name unistd \ --target-package net.codecrete.usb.linux.gen.unistd \ + --include-function close \ /usr/include/unistd.h # usbdevice_fs.h @@ -38,4 +44,10 @@ $JEXTRACT --source --output ../src/main/java \ $JEXTRACT --source --output ../src/main/java \ --header-class-name usbdevice_fs \ --target-package net.codecrete.usb.linux.gen.usbdevice_fs \ + --include-struct usbdevfs_bulktransfer \ + --include-struct usbdevfs_ctrltransfer \ + --include-macro USBDEVFS_CONTROL \ + --include-macro USBDEVFS_BULK \ + --include-macro USBDEVFS_CLAIMINTERFACE \ + --include-macro USBDEVFS_RELEASEINTERFACE \ /usr/include/linux/usbdevice_fs.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java index 2a42c554..ddc5d6e8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -17,504 +17,6 @@ public class errno { public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; - public static int _ERRNO_H() { - return (int)1L; - } - public static int _FEATURES_H() { - return (int)1L; - } - public static int _DEFAULT_SOURCE() { - return (int)1L; - } - public static int __GLIBC_USE_ISOC2X() { - return (int)0L; - } - public static int __USE_ISOC11() { - return (int)1L; - } - public static int __USE_ISOC99() { - return (int)1L; - } - public static int __USE_ISOC95() { - return (int)1L; - } - public static int __USE_POSIX_IMPLICITLY() { - return (int)1L; - } - public static int _POSIX_SOURCE() { - return (int)1L; - } - public static int __USE_POSIX() { - return (int)1L; - } - public static int __USE_POSIX2() { - return (int)1L; - } - public static int __USE_POSIX199309() { - return (int)1L; - } - public static int __USE_POSIX199506() { - return (int)1L; - } - public static int __USE_XOPEN2K() { - return (int)1L; - } - public static int __USE_XOPEN2K8() { - return (int)1L; - } - public static int _ATFILE_SOURCE() { - return (int)1L; - } - public static int __WORDSIZE() { - return (int)64L; - } - public static int __WORDSIZE_TIME64_COMPAT32() { - return (int)1L; - } - public static int __SYSCALL_WORDSIZE() { - return (int)64L; - } - public static int __USE_MISC() { - return (int)1L; - } - public static int __USE_ATFILE() { - return (int)1L; - } - public static int __USE_FORTIFY_LEVEL() { - return (int)0L; - } - public static int __GLIBC_USE_DEPRECATED_GETS() { - return (int)0L; - } - public static int __GLIBC_USE_DEPRECATED_SCANF() { - return (int)0L; - } - public static int _STDC_PREDEF_H() { - return (int)1L; - } - public static int __STDC_IEC_559__() { - return (int)1L; - } - public static int __STDC_IEC_559_COMPLEX__() { - return (int)1L; - } - public static int __GNU_LIBRARY__() { - return (int)6L; - } - public static int __GLIBC__() { - return (int)2L; - } - public static int __GLIBC_MINOR__() { - return (int)35L; - } - public static int _SYS_CDEFS_H() { - return (int)1L; - } - public static int __glibc_c99_flexarr_available() { - return (int)1L; - } - public static int __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI() { - return (int)0L; - } - public static int __HAVE_GENERIC_SELECTION() { - return (int)1L; - } - public static int _BITS_ERRNO_H() { - return (int)1L; - } - public static int EPERM() { - return (int)1L; - } - public static int ENOENT() { - return (int)2L; - } - public static int ESRCH() { - return (int)3L; - } - public static int EINTR() { - return (int)4L; - } - public static int EIO() { - return (int)5L; - } - public static int ENXIO() { - return (int)6L; - } - public static int E2BIG() { - return (int)7L; - } - public static int ENOEXEC() { - return (int)8L; - } - public static int EBADF() { - return (int)9L; - } - public static int ECHILD() { - return (int)10L; - } - public static int EAGAIN() { - return (int)11L; - } - public static int ENOMEM() { - return (int)12L; - } - public static int EACCES() { - return (int)13L; - } - public static int EFAULT() { - return (int)14L; - } - public static int ENOTBLK() { - return (int)15L; - } - public static int EBUSY() { - return (int)16L; - } - public static int EEXIST() { - return (int)17L; - } - public static int EXDEV() { - return (int)18L; - } - public static int ENODEV() { - return (int)19L; - } - public static int ENOTDIR() { - return (int)20L; - } - public static int EISDIR() { - return (int)21L; - } - public static int EINVAL() { - return (int)22L; - } - public static int ENFILE() { - return (int)23L; - } - public static int EMFILE() { - return (int)24L; - } - public static int ENOTTY() { - return (int)25L; - } - public static int ETXTBSY() { - return (int)26L; - } - public static int EFBIG() { - return (int)27L; - } - public static int ENOSPC() { - return (int)28L; - } - public static int ESPIPE() { - return (int)29L; - } - public static int EROFS() { - return (int)30L; - } - public static int EMLINK() { - return (int)31L; - } - public static int EPIPE() { - return (int)32L; - } - public static int EDOM() { - return (int)33L; - } - public static int ERANGE() { - return (int)34L; - } - public static int EDEADLK() { - return (int)35L; - } - public static int ENAMETOOLONG() { - return (int)36L; - } - public static int ENOLCK() { - return (int)37L; - } - public static int ENOSYS() { - return (int)38L; - } - public static int ENOTEMPTY() { - return (int)39L; - } - public static int ELOOP() { - return (int)40L; - } - public static int ENOMSG() { - return (int)42L; - } - public static int EIDRM() { - return (int)43L; - } - public static int ECHRNG() { - return (int)44L; - } - public static int EL2NSYNC() { - return (int)45L; - } - public static int EL3HLT() { - return (int)46L; - } - public static int EL3RST() { - return (int)47L; - } - public static int ELNRNG() { - return (int)48L; - } - public static int EUNATCH() { - return (int)49L; - } - public static int ENOCSI() { - return (int)50L; - } - public static int EL2HLT() { - return (int)51L; - } - public static int EBADE() { - return (int)52L; - } - public static int EBADR() { - return (int)53L; - } - public static int EXFULL() { - return (int)54L; - } - public static int ENOANO() { - return (int)55L; - } - public static int EBADRQC() { - return (int)56L; - } - public static int EBADSLT() { - return (int)57L; - } - public static int EBFONT() { - return (int)59L; - } - public static int ENOSTR() { - return (int)60L; - } - public static int ENODATA() { - return (int)61L; - } - public static int ETIME() { - return (int)62L; - } - public static int ENOSR() { - return (int)63L; - } - public static int ENONET() { - return (int)64L; - } - public static int ENOPKG() { - return (int)65L; - } - public static int EREMOTE() { - return (int)66L; - } - public static int ENOLINK() { - return (int)67L; - } - public static int EADV() { - return (int)68L; - } - public static int ESRMNT() { - return (int)69L; - } - public static int ECOMM() { - return (int)70L; - } - public static int EPROTO() { - return (int)71L; - } - public static int EMULTIHOP() { - return (int)72L; - } - public static int EDOTDOT() { - return (int)73L; - } - public static int EBADMSG() { - return (int)74L; - } - public static int EOVERFLOW() { - return (int)75L; - } - public static int ENOTUNIQ() { - return (int)76L; - } - public static int EBADFD() { - return (int)77L; - } - public static int EREMCHG() { - return (int)78L; - } - public static int ELIBACC() { - return (int)79L; - } - public static int ELIBBAD() { - return (int)80L; - } - public static int ELIBSCN() { - return (int)81L; - } - public static int ELIBMAX() { - return (int)82L; - } - public static int ELIBEXEC() { - return (int)83L; - } - public static int EILSEQ() { - return (int)84L; - } - public static int ERESTART() { - return (int)85L; - } - public static int ESTRPIPE() { - return (int)86L; - } - public static int EUSERS() { - return (int)87L; - } - public static int ENOTSOCK() { - return (int)88L; - } - public static int EDESTADDRREQ() { - return (int)89L; - } - public static int EMSGSIZE() { - return (int)90L; - } - public static int EPROTOTYPE() { - return (int)91L; - } - public static int ENOPROTOOPT() { - return (int)92L; - } - public static int EPROTONOSUPPORT() { - return (int)93L; - } - public static int ESOCKTNOSUPPORT() { - return (int)94L; - } - public static int EOPNOTSUPP() { - return (int)95L; - } - public static int EPFNOSUPPORT() { - return (int)96L; - } - public static int EAFNOSUPPORT() { - return (int)97L; - } - public static int EADDRINUSE() { - return (int)98L; - } - public static int EADDRNOTAVAIL() { - return (int)99L; - } - public static int ENETDOWN() { - return (int)100L; - } - public static int ENETUNREACH() { - return (int)101L; - } - public static int ENETRESET() { - return (int)102L; - } - public static int ECONNABORTED() { - return (int)103L; - } - public static int ECONNRESET() { - return (int)104L; - } - public static int ENOBUFS() { - return (int)105L; - } - public static int EISCONN() { - return (int)106L; - } - public static int ENOTCONN() { - return (int)107L; - } - public static int ESHUTDOWN() { - return (int)108L; - } - public static int ETOOMANYREFS() { - return (int)109L; - } - public static int ETIMEDOUT() { - return (int)110L; - } - public static int ECONNREFUSED() { - return (int)111L; - } - public static int EHOSTDOWN() { - return (int)112L; - } - public static int EHOSTUNREACH() { - return (int)113L; - } - public static int EALREADY() { - return (int)114L; - } - public static int EINPROGRESS() { - return (int)115L; - } - public static int ESTALE() { - return (int)116L; - } - public static int EUCLEAN() { - return (int)117L; - } - public static int ENOTNAM() { - return (int)118L; - } - public static int ENAVAIL() { - return (int)119L; - } - public static int EISNAM() { - return (int)120L; - } - public static int EREMOTEIO() { - return (int)121L; - } - public static int EDQUOT() { - return (int)122L; - } - public static int ENOMEDIUM() { - return (int)123L; - } - public static int EMEDIUMTYPE() { - return (int)124L; - } - public static int ECANCELED() { - return (int)125L; - } - public static int ENOKEY() { - return (int)126L; - } - public static int EKEYEXPIRED() { - return (int)127L; - } - public static int EKEYREVOKED() { - return (int)128L; - } - public static int EKEYREJECTED() { - return (int)129L; - } - public static int EOWNERDEAD() { - return (int)130L; - } - public static int ENOTRECOVERABLE() { - return (int)131L; - } - public static int ERFKILL() { - return (int)132L; - } - public static int EHWPOISON() { - return (int)133L; - } public static MethodHandle __errno_location$MH() { return RuntimeHelper.requireNonNull(constants$0.__errno_location$MH,"__errno_location"); } @@ -526,30 +28,6 @@ public static MemoryAddress __errno_location () { throw new AssertionError("should not reach here", ex$); } } - public static long _POSIX_C_SOURCE() { - return 200809L; - } - public static int __TIMESIZE() { - return (int)64L; - } - public static long __STDC_IEC_60559_BFP__() { - return 201404L; - } - public static long __STDC_IEC_60559_COMPLEX__() { - return 201404L; - } - public static long __STDC_ISO_10646__() { - return 201706L; - } - public static int EWOULDBLOCK() { - return (int)11L; - } - public static int EDEADLOCK() { - return (int)35L; - } - public static int ENOTSUP() { - return (int)95L; - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/__fsid_t.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/__fsid_t.java deleted file mode 100644 index 681bc974..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/__fsid_t.java +++ /dev/null @@ -1,25 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.fcntl; - -import java.lang.foreign.*; -public class __fsid_t { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - MemoryLayout.sequenceLayout(2, Constants$root.C_INT$LAYOUT).withName("__val") - ); - public static MemoryLayout $LAYOUT() { - return __fsid_t.$struct$LAYOUT; - } - public static MemorySegment __val$slice(MemorySegment seg) { - return seg.asSlice(0, 8); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java index 5dadf164..517dcb8f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java @@ -6,14 +6,6 @@ import java.lang.invoke.MethodHandle; class constants$0 { - static final FunctionDescriptor fcntl$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle fcntl$MH = RuntimeHelper.downcallHandleVariadic( - "fcntl", - constants$0.fcntl$FUNC - ); static final FunctionDescriptor open$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_INT$LAYOUT @@ -22,42 +14,6 @@ class constants$0 { "open", constants$0.open$FUNC ); - static final FunctionDescriptor openat$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle openat$MH = RuntimeHelper.downcallHandleVariadic( - "openat", - constants$0.openat$FUNC - ); - static final FunctionDescriptor creat$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle creat$MH = RuntimeHelper.downcallHandle( - "creat", - constants$0.creat$FUNC - ); - static final FunctionDescriptor lockf$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle lockf$MH = RuntimeHelper.downcallHandle( - "lockf", - constants$0.lockf$FUNC - ); - static final FunctionDescriptor posix_fadvise$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle posix_fadvise$MH = RuntimeHelper.downcallHandle( - "posix_fadvise", - constants$0.posix_fadvise$FUNC - ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$1.java deleted file mode 100644 index 0c420af8..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$1.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.fcntl; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$1 { - - static final FunctionDescriptor posix_fallocate$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle posix_fallocate$MH = RuntimeHelper.downcallHandle( - "posix_fallocate", - constants$1.posix_fallocate$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java index d2ce44d6..41eb1e0c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java @@ -17,454 +17,9 @@ public class fcntl { public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; - public static int _FCNTL_H() { - return (int)1L; - } - public static int _FEATURES_H() { - return (int)1L; - } - public static int _DEFAULT_SOURCE() { - return (int)1L; - } - public static int __GLIBC_USE_ISOC2X() { - return (int)0L; - } - public static int __USE_ISOC11() { - return (int)1L; - } - public static int __USE_ISOC99() { - return (int)1L; - } - public static int __USE_ISOC95() { - return (int)1L; - } - public static int __USE_POSIX_IMPLICITLY() { - return (int)1L; - } - public static int _POSIX_SOURCE() { - return (int)1L; - } - public static int __USE_POSIX() { - return (int)1L; - } - public static int __USE_POSIX2() { - return (int)1L; - } - public static int __USE_POSIX199309() { - return (int)1L; - } - public static int __USE_POSIX199506() { - return (int)1L; - } - public static int __USE_XOPEN2K() { - return (int)1L; - } - public static int __USE_XOPEN2K8() { - return (int)1L; - } - public static int _ATFILE_SOURCE() { - return (int)1L; - } - public static int __WORDSIZE() { - return (int)64L; - } - public static int __WORDSIZE_TIME64_COMPAT32() { - return (int)1L; - } - public static int __SYSCALL_WORDSIZE() { - return (int)64L; - } - public static int __USE_MISC() { - return (int)1L; - } - public static int __USE_ATFILE() { - return (int)1L; - } - public static int __USE_FORTIFY_LEVEL() { - return (int)0L; - } - public static int __GLIBC_USE_DEPRECATED_GETS() { - return (int)0L; - } - public static int __GLIBC_USE_DEPRECATED_SCANF() { - return (int)0L; - } - public static int _STDC_PREDEF_H() { - return (int)1L; - } - public static int __STDC_IEC_559__() { - return (int)1L; - } - public static int __STDC_IEC_559_COMPLEX__() { - return (int)1L; - } - public static int __GNU_LIBRARY__() { - return (int)6L; - } - public static int __GLIBC__() { - return (int)2L; - } - public static int __GLIBC_MINOR__() { - return (int)35L; - } - public static int _SYS_CDEFS_H() { - return (int)1L; - } - public static int __glibc_c99_flexarr_available() { - return (int)1L; - } - public static int __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI() { - return (int)0L; - } - public static int __HAVE_GENERIC_SELECTION() { - return (int)1L; - } - public static int _BITS_TYPES_H() { - return (int)1L; - } - public static int _BITS_TYPESIZES_H() { - return (int)1L; - } - public static int __OFF_T_MATCHES_OFF64_T() { - return (int)1L; - } - public static int __INO_T_MATCHES_INO64_T() { - return (int)1L; - } - public static int __RLIM_T_MATCHES_RLIM64_T() { - return (int)1L; - } - public static int __STATFS_MATCHES_STATFS64() { - return (int)1L; - } - public static int __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64() { - return (int)1L; - } - public static int __FD_SETSIZE() { - return (int)1024L; - } - public static int _BITS_TIME64_H() { - return (int)1L; - } - public static int __O_LARGEFILE() { - return (int)0L; - } - public static int F_GETLK64() { - return (int)5L; - } - public static int F_SETLK64() { - return (int)6L; - } - public static int F_SETLKW64() { - return (int)7L; - } - public static int O_ACCMODE() { - return (int)3L; - } - public static int O_RDONLY() { - return (int)0L; - } - public static int O_WRONLY() { - return (int)1L; - } public static int O_RDWR() { return (int)2L; } - public static int O_CREAT() { - return (int)64L; - } - public static int O_EXCL() { - return (int)128L; - } - public static int O_NOCTTY() { - return (int)256L; - } - public static int O_TRUNC() { - return (int)512L; - } - public static int O_APPEND() { - return (int)1024L; - } - public static int O_NONBLOCK() { - return (int)2048L; - } - public static int O_SYNC() { - return (int)1052672L; - } - public static int O_ASYNC() { - return (int)8192L; - } - public static int __O_DIRECTORY() { - return (int)65536L; - } - public static int __O_NOFOLLOW() { - return (int)131072L; - } - public static int __O_CLOEXEC() { - return (int)524288L; - } - public static int __O_DIRECT() { - return (int)16384L; - } - public static int __O_NOATIME() { - return (int)262144L; - } - public static int __O_PATH() { - return (int)2097152L; - } - public static int __O_DSYNC() { - return (int)4096L; - } - public static int F_GETLK() { - return (int)5L; - } - public static int F_SETLK() { - return (int)6L; - } - public static int F_SETLKW() { - return (int)7L; - } - public static int F_DUPFD() { - return (int)0L; - } - public static int F_GETFD() { - return (int)1L; - } - public static int F_SETFD() { - return (int)2L; - } - public static int F_GETFL() { - return (int)3L; - } - public static int F_SETFL() { - return (int)4L; - } - public static int __F_SETOWN() { - return (int)8L; - } - public static int __F_GETOWN() { - return (int)9L; - } - public static int __F_SETSIG() { - return (int)10L; - } - public static int __F_GETSIG() { - return (int)11L; - } - public static int __F_SETOWN_EX() { - return (int)15L; - } - public static int __F_GETOWN_EX() { - return (int)16L; - } - public static int F_DUPFD_CLOEXEC() { - return (int)1030L; - } - public static int FD_CLOEXEC() { - return (int)1L; - } - public static int F_RDLCK() { - return (int)0L; - } - public static int F_WRLCK() { - return (int)1L; - } - public static int F_UNLCK() { - return (int)2L; - } - public static int F_EXLCK() { - return (int)4L; - } - public static int F_SHLCK() { - return (int)8L; - } - public static int LOCK_SH() { - return (int)1L; - } - public static int LOCK_EX() { - return (int)2L; - } - public static int LOCK_NB() { - return (int)4L; - } - public static int LOCK_UN() { - return (int)8L; - } - public static int __POSIX_FADV_DONTNEED() { - return (int)4L; - } - public static int __POSIX_FADV_NOREUSE() { - return (int)5L; - } - public static int POSIX_FADV_NORMAL() { - return (int)0L; - } - public static int POSIX_FADV_RANDOM() { - return (int)1L; - } - public static int POSIX_FADV_SEQUENTIAL() { - return (int)2L; - } - public static int POSIX_FADV_WILLNEED() { - return (int)3L; - } - public static int AT_SYMLINK_NOFOLLOW() { - return (int)256L; - } - public static int AT_REMOVEDIR() { - return (int)512L; - } - public static int AT_SYMLINK_FOLLOW() { - return (int)1024L; - } - public static int AT_EACCESS() { - return (int)512L; - } - public static int _STRUCT_TIMESPEC() { - return (int)1L; - } - public static int _BITS_ENDIAN_H() { - return (int)1L; - } - public static int __LITTLE_ENDIAN() { - return (int)1234L; - } - public static int __BIG_ENDIAN() { - return (int)4321L; - } - public static int __PDP_ENDIAN() { - return (int)3412L; - } - public static int _BITS_ENDIANNESS_H() { - return (int)1L; - } - public static int __time_t_defined() { - return (int)1L; - } - public static int _BITS_STAT_H() { - return (int)1L; - } - public static int _BITS_STRUCT_STAT_H() { - return (int)1L; - } - public static int __S_IFMT() { - return (int)61440L; - } - public static int __S_IFDIR() { - return (int)16384L; - } - public static int __S_IFCHR() { - return (int)8192L; - } - public static int __S_IFBLK() { - return (int)24576L; - } - public static int __S_IFREG() { - return (int)32768L; - } - public static int __S_IFIFO() { - return (int)4096L; - } - public static int __S_IFLNK() { - return (int)40960L; - } - public static int __S_IFSOCK() { - return (int)49152L; - } - public static int __S_ISUID() { - return (int)2048L; - } - public static int __S_ISGID() { - return (int)1024L; - } - public static int __S_ISVTX() { - return (int)512L; - } - public static int __S_IREAD() { - return (int)256L; - } - public static int __S_IWRITE() { - return (int)128L; - } - public static int __S_IEXEC() { - return (int)64L; - } - public static int R_OK() { - return (int)4L; - } - public static int W_OK() { - return (int)2L; - } - public static int X_OK() { - return (int)1L; - } - public static int F_OK() { - return (int)0L; - } - public static int SEEK_SET() { - return (int)0L; - } - public static int SEEK_CUR() { - return (int)1L; - } - public static int SEEK_END() { - return (int)2L; - } - public static int F_ULOCK() { - return (int)0L; - } - public static int F_LOCK() { - return (int)1L; - } - public static int F_TLOCK() { - return (int)2L; - } - public static int F_TEST() { - return (int)3L; - } - public static OfShort __int16_t = Constants$root.C_SHORT$LAYOUT; - public static OfInt __int32_t = Constants$root.C_INT$LAYOUT; - public static OfLong __int64_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfShort __int_least16_t = Constants$root.C_SHORT$LAYOUT; - public static OfInt __int_least32_t = Constants$root.C_INT$LAYOUT; - public static OfLong __int_least64_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __quad_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __intmax_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __off_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __off64_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfInt __pid_t = Constants$root.C_INT$LAYOUT; - public static OfLong __clock_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __time_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __suseconds_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __suseconds64_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfInt __daddr_t = Constants$root.C_INT$LAYOUT; - public static OfInt __key_t = Constants$root.C_INT$LAYOUT; - public static OfInt __clockid_t = Constants$root.C_INT$LAYOUT; - public static OfAddress __timer_t = Constants$root.C_POINTER$LAYOUT; - public static OfLong __blksize_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __blkcnt_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __blkcnt64_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __fsword_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __ssize_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __syscall_slong_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __loff_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfAddress __caddr_t = Constants$root.C_POINTER$LAYOUT; - public static OfLong __intptr_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfInt __sig_atomic_t = Constants$root.C_INT$LAYOUT; - public static OfLong off_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfInt pid_t = Constants$root.C_INT$LAYOUT; - public static OfLong time_t = Constants$root.C_LONG_LONG$LAYOUT; - public static MethodHandle fcntl$MH() { - return RuntimeHelper.requireNonNull(constants$0.fcntl$MH,"fcntl"); - } - public static int fcntl ( int __fd, int __cmd, Object... x2) { - var mh$ = fcntl$MH(); - try { - return (int)mh$.invokeExact(__fd, __cmd, x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } public static MethodHandle open$MH() { return RuntimeHelper.requireNonNull(constants$0.open$MH,"open"); } @@ -476,211 +31,9 @@ public static int open ( Addressable __file, int __oflag, Object... x2) { throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle openat$MH() { - return RuntimeHelper.requireNonNull(constants$0.openat$MH,"openat"); - } - public static int openat ( int __fd, Addressable __file, int __oflag, Object... x3) { - var mh$ = openat$MH(); - try { - return (int)mh$.invokeExact(__fd, __file, __oflag, x3); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle creat$MH() { - return RuntimeHelper.requireNonNull(constants$0.creat$MH,"creat"); - } - public static int creat ( Addressable __file, int __mode) { - var mh$ = creat$MH(); - try { - return (int)mh$.invokeExact(__file, __mode); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle lockf$MH() { - return RuntimeHelper.requireNonNull(constants$0.lockf$MH,"lockf"); - } - public static int lockf ( int __fd, int __cmd, long __len) { - var mh$ = lockf$MH(); - try { - return (int)mh$.invokeExact(__fd, __cmd, __len); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle posix_fadvise$MH() { - return RuntimeHelper.requireNonNull(constants$0.posix_fadvise$MH,"posix_fadvise"); - } - public static int posix_fadvise ( int __fd, long __offset, long __len, int __advise) { - var mh$ = posix_fadvise$MH(); - try { - return (int)mh$.invokeExact(__fd, __offset, __len, __advise); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle posix_fallocate$MH() { - return RuntimeHelper.requireNonNull(constants$1.posix_fallocate$MH,"posix_fallocate"); - } - public static int posix_fallocate ( int __fd, long __offset, long __len) { - var mh$ = posix_fallocate$MH(); - try { - return (int)mh$.invokeExact(__fd, __offset, __len); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static long _POSIX_C_SOURCE() { - return 200809L; - } - public static int __TIMESIZE() { - return (int)64L; - } - public static long __STDC_IEC_60559_BFP__() { - return 201404L; - } - public static long __STDC_IEC_60559_COMPLEX__() { - return 201404L; - } - public static long __STDC_ISO_10646__() { - return 201706L; - } - public static int O_NDELAY() { - return (int)2048L; - } - public static int O_FSYNC() { - return (int)1052672L; - } - public static int __O_TMPFILE() { - return (int)4259840L; - } - public static int O_DIRECTORY() { - return (int)65536L; - } - public static int O_NOFOLLOW() { - return (int)131072L; - } public static int O_CLOEXEC() { return (int)524288L; } - public static int O_DSYNC() { - return (int)4096L; - } - public static int O_RSYNC() { - return (int)1052672L; - } - public static int F_SETOWN() { - return (int)8L; - } - public static int F_GETOWN() { - return (int)9L; - } - public static int FAPPEND() { - return (int)1024L; - } - public static int FFSYNC() { - return (int)1052672L; - } - public static int FASYNC() { - return (int)8192L; - } - public static int FNONBLOCK() { - return (int)2048L; - } - public static int FNDELAY() { - return (int)2048L; - } - public static int POSIX_FADV_DONTNEED() { - return (int)4L; - } - public static int POSIX_FADV_NOREUSE() { - return (int)5L; - } - public static int AT_FDCWD() { - return (int)-100L; - } - public static int __BYTE_ORDER() { - return (int)1234L; - } - public static int __FLOAT_WORD_ORDER() { - return (int)1234L; - } - public static long UTIME_NOW() { - return 1073741823L; - } - public static long UTIME_OMIT() { - return 1073741822L; - } - public static int S_IFMT() { - return (int)61440L; - } - public static int S_IFDIR() { - return (int)16384L; - } - public static int S_IFCHR() { - return (int)8192L; - } - public static int S_IFBLK() { - return (int)24576L; - } - public static int S_IFREG() { - return (int)32768L; - } - public static int S_IFIFO() { - return (int)4096L; - } - public static int S_IFLNK() { - return (int)40960L; - } - public static int S_IFSOCK() { - return (int)49152L; - } - public static int S_ISUID() { - return (int)2048L; - } - public static int S_ISGID() { - return (int)1024L; - } - public static int S_ISVTX() { - return (int)512L; - } - public static int S_IRUSR() { - return (int)256L; - } - public static int S_IWUSR() { - return (int)128L; - } - public static int S_IXUSR() { - return (int)64L; - } - public static int S_IRWXU() { - return (int)448L; - } - public static int S_IRGRP() { - return (int)32L; - } - public static int S_IWGRP() { - return (int)16L; - } - public static int S_IXGRP() { - return (int)8L; - } - public static int S_IRWXG() { - return (int)56L; - } - public static int S_IROTH() { - return (int)4L; - } - public static int S_IWOTH() { - return (int)2L; - } - public static int S_IXOTH() { - return (int)1L; - } - public static int S_IRWXO() { - return (int)7L; - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/flock.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/flock.java deleted file mode 100644 index e3192d4c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/flock.java +++ /dev/null @@ -1,109 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.fcntl; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; -public class flock { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_SHORT$LAYOUT.withName("l_type"), - Constants$root.C_SHORT$LAYOUT.withName("l_whence"), - MemoryLayout.paddingLayout(32), - Constants$root.C_LONG_LONG$LAYOUT.withName("l_start"), - Constants$root.C_LONG_LONG$LAYOUT.withName("l_len"), - Constants$root.C_INT$LAYOUT.withName("l_pid"), - MemoryLayout.paddingLayout(32) - ).withName("flock"); - public static MemoryLayout $LAYOUT() { - return flock.$struct$LAYOUT; - } - static final VarHandle l_type$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("l_type")); - public static VarHandle l_type$VH() { - return flock.l_type$VH; - } - public static short l_type$get(MemorySegment seg) { - return (short)flock.l_type$VH.get(seg); - } - public static void l_type$set( MemorySegment seg, short x) { - flock.l_type$VH.set(seg, x); - } - public static short l_type$get(MemorySegment seg, long index) { - return (short)flock.l_type$VH.get(seg.asSlice(index*sizeof())); - } - public static void l_type$set(MemorySegment seg, long index, short x) { - flock.l_type$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle l_whence$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("l_whence")); - public static VarHandle l_whence$VH() { - return flock.l_whence$VH; - } - public static short l_whence$get(MemorySegment seg) { - return (short)flock.l_whence$VH.get(seg); - } - public static void l_whence$set( MemorySegment seg, short x) { - flock.l_whence$VH.set(seg, x); - } - public static short l_whence$get(MemorySegment seg, long index) { - return (short)flock.l_whence$VH.get(seg.asSlice(index*sizeof())); - } - public static void l_whence$set(MemorySegment seg, long index, short x) { - flock.l_whence$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle l_start$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("l_start")); - public static VarHandle l_start$VH() { - return flock.l_start$VH; - } - public static long l_start$get(MemorySegment seg) { - return (long)flock.l_start$VH.get(seg); - } - public static void l_start$set( MemorySegment seg, long x) { - flock.l_start$VH.set(seg, x); - } - public static long l_start$get(MemorySegment seg, long index) { - return (long)flock.l_start$VH.get(seg.asSlice(index*sizeof())); - } - public static void l_start$set(MemorySegment seg, long index, long x) { - flock.l_start$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle l_len$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("l_len")); - public static VarHandle l_len$VH() { - return flock.l_len$VH; - } - public static long l_len$get(MemorySegment seg) { - return (long)flock.l_len$VH.get(seg); - } - public static void l_len$set( MemorySegment seg, long x) { - flock.l_len$VH.set(seg, x); - } - public static long l_len$get(MemorySegment seg, long index) { - return (long)flock.l_len$VH.get(seg.asSlice(index*sizeof())); - } - public static void l_len$set(MemorySegment seg, long index, long x) { - flock.l_len$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle l_pid$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("l_pid")); - public static VarHandle l_pid$VH() { - return flock.l_pid$VH; - } - public static int l_pid$get(MemorySegment seg) { - return (int)flock.l_pid$VH.get(seg); - } - public static void l_pid$set( MemorySegment seg, int x) { - flock.l_pid$VH.set(seg, x); - } - public static int l_pid$get(MemorySegment seg, long index) { - return (int)flock.l_pid$VH.get(seg.asSlice(index*sizeof())); - } - public static void l_pid$set(MemorySegment seg, long index, int x) { - flock.l_pid$VH.set(seg.asSlice(index*sizeof()), x); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/stat.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/stat.java deleted file mode 100644 index c41afa20..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/stat.java +++ /dev/null @@ -1,234 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.fcntl; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; -public class stat { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_LONG_LONG$LAYOUT.withName("st_dev"), - Constants$root.C_LONG_LONG$LAYOUT.withName("st_ino"), - Constants$root.C_LONG_LONG$LAYOUT.withName("st_nlink"), - Constants$root.C_INT$LAYOUT.withName("st_mode"), - Constants$root.C_INT$LAYOUT.withName("st_uid"), - Constants$root.C_INT$LAYOUT.withName("st_gid"), - Constants$root.C_INT$LAYOUT.withName("__pad0"), - Constants$root.C_LONG_LONG$LAYOUT.withName("st_rdev"), - Constants$root.C_LONG_LONG$LAYOUT.withName("st_size"), - Constants$root.C_LONG_LONG$LAYOUT.withName("st_blksize"), - Constants$root.C_LONG_LONG$LAYOUT.withName("st_blocks"), - MemoryLayout.structLayout( - Constants$root.C_LONG_LONG$LAYOUT.withName("tv_sec"), - Constants$root.C_LONG_LONG$LAYOUT.withName("tv_nsec") - ).withName("st_atim"), - MemoryLayout.structLayout( - Constants$root.C_LONG_LONG$LAYOUT.withName("tv_sec"), - Constants$root.C_LONG_LONG$LAYOUT.withName("tv_nsec") - ).withName("st_mtim"), - MemoryLayout.structLayout( - Constants$root.C_LONG_LONG$LAYOUT.withName("tv_sec"), - Constants$root.C_LONG_LONG$LAYOUT.withName("tv_nsec") - ).withName("st_ctim"), - MemoryLayout.sequenceLayout(3, Constants$root.C_LONG_LONG$LAYOUT).withName("__glibc_reserved") - ).withName("stat"); - public static MemoryLayout $LAYOUT() { - return stat.$struct$LAYOUT; - } - static final VarHandle st_dev$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_dev")); - public static VarHandle st_dev$VH() { - return stat.st_dev$VH; - } - public static long st_dev$get(MemorySegment seg) { - return (long)stat.st_dev$VH.get(seg); - } - public static void st_dev$set( MemorySegment seg, long x) { - stat.st_dev$VH.set(seg, x); - } - public static long st_dev$get(MemorySegment seg, long index) { - return (long)stat.st_dev$VH.get(seg.asSlice(index*sizeof())); - } - public static void st_dev$set(MemorySegment seg, long index, long x) { - stat.st_dev$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle st_ino$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_ino")); - public static VarHandle st_ino$VH() { - return stat.st_ino$VH; - } - public static long st_ino$get(MemorySegment seg) { - return (long)stat.st_ino$VH.get(seg); - } - public static void st_ino$set( MemorySegment seg, long x) { - stat.st_ino$VH.set(seg, x); - } - public static long st_ino$get(MemorySegment seg, long index) { - return (long)stat.st_ino$VH.get(seg.asSlice(index*sizeof())); - } - public static void st_ino$set(MemorySegment seg, long index, long x) { - stat.st_ino$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle st_nlink$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_nlink")); - public static VarHandle st_nlink$VH() { - return stat.st_nlink$VH; - } - public static long st_nlink$get(MemorySegment seg) { - return (long)stat.st_nlink$VH.get(seg); - } - public static void st_nlink$set( MemorySegment seg, long x) { - stat.st_nlink$VH.set(seg, x); - } - public static long st_nlink$get(MemorySegment seg, long index) { - return (long)stat.st_nlink$VH.get(seg.asSlice(index*sizeof())); - } - public static void st_nlink$set(MemorySegment seg, long index, long x) { - stat.st_nlink$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle st_mode$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_mode")); - public static VarHandle st_mode$VH() { - return stat.st_mode$VH; - } - public static int st_mode$get(MemorySegment seg) { - return (int)stat.st_mode$VH.get(seg); - } - public static void st_mode$set( MemorySegment seg, int x) { - stat.st_mode$VH.set(seg, x); - } - public static int st_mode$get(MemorySegment seg, long index) { - return (int)stat.st_mode$VH.get(seg.asSlice(index*sizeof())); - } - public static void st_mode$set(MemorySegment seg, long index, int x) { - stat.st_mode$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle st_uid$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_uid")); - public static VarHandle st_uid$VH() { - return stat.st_uid$VH; - } - public static int st_uid$get(MemorySegment seg) { - return (int)stat.st_uid$VH.get(seg); - } - public static void st_uid$set( MemorySegment seg, int x) { - stat.st_uid$VH.set(seg, x); - } - public static int st_uid$get(MemorySegment seg, long index) { - return (int)stat.st_uid$VH.get(seg.asSlice(index*sizeof())); - } - public static void st_uid$set(MemorySegment seg, long index, int x) { - stat.st_uid$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle st_gid$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_gid")); - public static VarHandle st_gid$VH() { - return stat.st_gid$VH; - } - public static int st_gid$get(MemorySegment seg) { - return (int)stat.st_gid$VH.get(seg); - } - public static void st_gid$set( MemorySegment seg, int x) { - stat.st_gid$VH.set(seg, x); - } - public static int st_gid$get(MemorySegment seg, long index) { - return (int)stat.st_gid$VH.get(seg.asSlice(index*sizeof())); - } - public static void st_gid$set(MemorySegment seg, long index, int x) { - stat.st_gid$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle __pad0$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("__pad0")); - public static VarHandle __pad0$VH() { - return stat.__pad0$VH; - } - public static int __pad0$get(MemorySegment seg) { - return (int)stat.__pad0$VH.get(seg); - } - public static void __pad0$set( MemorySegment seg, int x) { - stat.__pad0$VH.set(seg, x); - } - public static int __pad0$get(MemorySegment seg, long index) { - return (int)stat.__pad0$VH.get(seg.asSlice(index*sizeof())); - } - public static void __pad0$set(MemorySegment seg, long index, int x) { - stat.__pad0$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle st_rdev$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_rdev")); - public static VarHandle st_rdev$VH() { - return stat.st_rdev$VH; - } - public static long st_rdev$get(MemorySegment seg) { - return (long)stat.st_rdev$VH.get(seg); - } - public static void st_rdev$set( MemorySegment seg, long x) { - stat.st_rdev$VH.set(seg, x); - } - public static long st_rdev$get(MemorySegment seg, long index) { - return (long)stat.st_rdev$VH.get(seg.asSlice(index*sizeof())); - } - public static void st_rdev$set(MemorySegment seg, long index, long x) { - stat.st_rdev$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle st_size$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_size")); - public static VarHandle st_size$VH() { - return stat.st_size$VH; - } - public static long st_size$get(MemorySegment seg) { - return (long)stat.st_size$VH.get(seg); - } - public static void st_size$set( MemorySegment seg, long x) { - stat.st_size$VH.set(seg, x); - } - public static long st_size$get(MemorySegment seg, long index) { - return (long)stat.st_size$VH.get(seg.asSlice(index*sizeof())); - } - public static void st_size$set(MemorySegment seg, long index, long x) { - stat.st_size$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle st_blksize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_blksize")); - public static VarHandle st_blksize$VH() { - return stat.st_blksize$VH; - } - public static long st_blksize$get(MemorySegment seg) { - return (long)stat.st_blksize$VH.get(seg); - } - public static void st_blksize$set( MemorySegment seg, long x) { - stat.st_blksize$VH.set(seg, x); - } - public static long st_blksize$get(MemorySegment seg, long index) { - return (long)stat.st_blksize$VH.get(seg.asSlice(index*sizeof())); - } - public static void st_blksize$set(MemorySegment seg, long index, long x) { - stat.st_blksize$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle st_blocks$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("st_blocks")); - public static VarHandle st_blocks$VH() { - return stat.st_blocks$VH; - } - public static long st_blocks$get(MemorySegment seg) { - return (long)stat.st_blocks$VH.get(seg); - } - public static void st_blocks$set( MemorySegment seg, long x) { - stat.st_blocks$VH.set(seg, x); - } - public static long st_blocks$get(MemorySegment seg, long index) { - return (long)stat.st_blocks$VH.get(seg.asSlice(index*sizeof())); - } - public static void st_blocks$set(MemorySegment seg, long index, long x) { - stat.st_blocks$VH.set(seg.asSlice(index*sizeof()), x); - } - public static MemorySegment st_atim$slice(MemorySegment seg) { - return seg.asSlice(72, 16); - } - public static MemorySegment st_mtim$slice(MemorySegment seg) { - return seg.asSlice(88, 16); - } - public static MemorySegment st_ctim$slice(MemorySegment seg) { - return seg.asSlice(104, 16); - } - public static MemorySegment __glibc_reserved$slice(MemorySegment seg) { - return seg.asSlice(120, 24); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/timespec.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/timespec.java deleted file mode 100644 index 5dae8dc0..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/timespec.java +++ /dev/null @@ -1,56 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.fcntl; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; -public class timespec { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_LONG_LONG$LAYOUT.withName("tv_sec"), - Constants$root.C_LONG_LONG$LAYOUT.withName("tv_nsec") - ).withName("timespec"); - public static MemoryLayout $LAYOUT() { - return timespec.$struct$LAYOUT; - } - static final VarHandle tv_sec$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("tv_sec")); - public static VarHandle tv_sec$VH() { - return timespec.tv_sec$VH; - } - public static long tv_sec$get(MemorySegment seg) { - return (long)timespec.tv_sec$VH.get(seg); - } - public static void tv_sec$set( MemorySegment seg, long x) { - timespec.tv_sec$VH.set(seg, x); - } - public static long tv_sec$get(MemorySegment seg, long index) { - return (long)timespec.tv_sec$VH.get(seg.asSlice(index*sizeof())); - } - public static void tv_sec$set(MemorySegment seg, long index, long x) { - timespec.tv_sec$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle tv_nsec$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("tv_nsec")); - public static VarHandle tv_nsec$VH() { - return timespec.tv_nsec$VH; - } - public static long tv_nsec$get(MemorySegment seg) { - return (long)timespec.tv_nsec$VH.get(seg); - } - public static void tv_nsec$set( MemorySegment seg, long x) { - timespec.tv_nsec$VH.set(seg, x); - } - public static long tv_nsec$get(MemorySegment seg, long index) { - return (long)timespec.tv_nsec$VH.get(seg.asSlice(index*sizeof())); - } - public static void tv_nsec$set(MemorySegment seg, long index, long x) { - timespec.tv_nsec$VH.set(seg.asSlice(index*sizeof()), x); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/ioctl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/ioctl.java index 795090b8..cbe51a0b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/ioctl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/ioctl.java @@ -16,585 +16,6 @@ public class ioctl { public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; - public static int _SYS_IOCTL_H() { - return (int)1L; - } - public static int _FEATURES_H() { - return (int)1L; - } - public static int _DEFAULT_SOURCE() { - return (int)1L; - } - public static int __GLIBC_USE_ISOC2X() { - return (int)0L; - } - public static int __USE_ISOC11() { - return (int)1L; - } - public static int __USE_ISOC99() { - return (int)1L; - } - public static int __USE_ISOC95() { - return (int)1L; - } - public static int __USE_POSIX_IMPLICITLY() { - return (int)1L; - } - public static int _POSIX_SOURCE() { - return (int)1L; - } - public static int __USE_POSIX() { - return (int)1L; - } - public static int __USE_POSIX2() { - return (int)1L; - } - public static int __USE_POSIX199309() { - return (int)1L; - } - public static int __USE_POSIX199506() { - return (int)1L; - } - public static int __USE_XOPEN2K() { - return (int)1L; - } - public static int __USE_XOPEN2K8() { - return (int)1L; - } - public static int _ATFILE_SOURCE() { - return (int)1L; - } - public static int __WORDSIZE() { - return (int)64L; - } - public static int __WORDSIZE_TIME64_COMPAT32() { - return (int)1L; - } - public static int __SYSCALL_WORDSIZE() { - return (int)64L; - } - public static int __USE_MISC() { - return (int)1L; - } - public static int __USE_ATFILE() { - return (int)1L; - } - public static int __USE_FORTIFY_LEVEL() { - return (int)0L; - } - public static int __GLIBC_USE_DEPRECATED_GETS() { - return (int)0L; - } - public static int __GLIBC_USE_DEPRECATED_SCANF() { - return (int)0L; - } - public static int _STDC_PREDEF_H() { - return (int)1L; - } - public static int __STDC_IEC_559__() { - return (int)1L; - } - public static int __STDC_IEC_559_COMPLEX__() { - return (int)1L; - } - public static int __GNU_LIBRARY__() { - return (int)6L; - } - public static int __GLIBC__() { - return (int)2L; - } - public static int __GLIBC_MINOR__() { - return (int)35L; - } - public static int _SYS_CDEFS_H() { - return (int)1L; - } - public static int __glibc_c99_flexarr_available() { - return (int)1L; - } - public static int __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI() { - return (int)0L; - } - public static int __HAVE_GENERIC_SELECTION() { - return (int)1L; - } - public static int _IOC_NRBITS() { - return (int)8L; - } - public static int _IOC_TYPEBITS() { - return (int)8L; - } - public static int _IOC_SIZEBITS() { - return (int)14L; - } - public static int _IOC_DIRBITS() { - return (int)2L; - } - public static int _IOC_NRSHIFT() { - return (int)0L; - } - public static int TCGETS() { - return (int)21505L; - } - public static int TCSETS() { - return (int)21506L; - } - public static int TCSETSW() { - return (int)21507L; - } - public static int TCSETSF() { - return (int)21508L; - } - public static int TCGETA() { - return (int)21509L; - } - public static int TCSETA() { - return (int)21510L; - } - public static int TCSETAW() { - return (int)21511L; - } - public static int TCSETAF() { - return (int)21512L; - } - public static int TCSBRK() { - return (int)21513L; - } - public static int TCXONC() { - return (int)21514L; - } - public static int TCFLSH() { - return (int)21515L; - } - public static int TIOCEXCL() { - return (int)21516L; - } - public static int TIOCNXCL() { - return (int)21517L; - } - public static int TIOCSCTTY() { - return (int)21518L; - } - public static int TIOCGPGRP() { - return (int)21519L; - } - public static int TIOCSPGRP() { - return (int)21520L; - } - public static int TIOCOUTQ() { - return (int)21521L; - } - public static int TIOCSTI() { - return (int)21522L; - } - public static int TIOCGWINSZ() { - return (int)21523L; - } - public static int TIOCSWINSZ() { - return (int)21524L; - } - public static int TIOCMGET() { - return (int)21525L; - } - public static int TIOCMBIS() { - return (int)21526L; - } - public static int TIOCMBIC() { - return (int)21527L; - } - public static int TIOCMSET() { - return (int)21528L; - } - public static int TIOCGSOFTCAR() { - return (int)21529L; - } - public static int TIOCSSOFTCAR() { - return (int)21530L; - } - public static int FIONREAD() { - return (int)21531L; - } - public static int TIOCLINUX() { - return (int)21532L; - } - public static int TIOCCONS() { - return (int)21533L; - } - public static int TIOCGSERIAL() { - return (int)21534L; - } - public static int TIOCSSERIAL() { - return (int)21535L; - } - public static int TIOCPKT() { - return (int)21536L; - } - public static int FIONBIO() { - return (int)21537L; - } - public static int TIOCNOTTY() { - return (int)21538L; - } - public static int TIOCSETD() { - return (int)21539L; - } - public static int TIOCGETD() { - return (int)21540L; - } - public static int TCSBRKP() { - return (int)21541L; - } - public static int TIOCSBRK() { - return (int)21543L; - } - public static int TIOCCBRK() { - return (int)21544L; - } - public static int TIOCGSID() { - return (int)21545L; - } - public static int TIOCGRS485() { - return (int)21550L; - } - public static int TIOCSRS485() { - return (int)21551L; - } - public static int TCGETX() { - return (int)21554L; - } - public static int TCSETX() { - return (int)21555L; - } - public static int TCSETXF() { - return (int)21556L; - } - public static int TCSETXW() { - return (int)21557L; - } - public static int TIOCVHANGUP() { - return (int)21559L; - } - public static int FIONCLEX() { - return (int)21584L; - } - public static int FIOCLEX() { - return (int)21585L; - } - public static int FIOASYNC() { - return (int)21586L; - } - public static int TIOCSERCONFIG() { - return (int)21587L; - } - public static int TIOCSERGWILD() { - return (int)21588L; - } - public static int TIOCSERSWILD() { - return (int)21589L; - } - public static int TIOCGLCKTRMIOS() { - return (int)21590L; - } - public static int TIOCSLCKTRMIOS() { - return (int)21591L; - } - public static int TIOCSERGSTRUCT() { - return (int)21592L; - } - public static int TIOCSERGETLSR() { - return (int)21593L; - } - public static int TIOCSERGETMULTI() { - return (int)21594L; - } - public static int TIOCSERSETMULTI() { - return (int)21595L; - } - public static int TIOCMIWAIT() { - return (int)21596L; - } - public static int TIOCGICOUNT() { - return (int)21597L; - } - public static int FIOQSIZE() { - return (int)21600L; - } - public static int TIOCPKT_DATA() { - return (int)0L; - } - public static int TIOCPKT_FLUSHREAD() { - return (int)1L; - } - public static int TIOCPKT_FLUSHWRITE() { - return (int)2L; - } - public static int TIOCPKT_STOP() { - return (int)4L; - } - public static int TIOCPKT_START() { - return (int)8L; - } - public static int TIOCPKT_NOSTOP() { - return (int)16L; - } - public static int TIOCPKT_DOSTOP() { - return (int)32L; - } - public static int TIOCPKT_IOCTL() { - return (int)64L; - } - public static int TIOCSER_TEMT() { - return (int)1L; - } - public static int SIOCADDRT() { - return (int)35083L; - } - public static int SIOCDELRT() { - return (int)35084L; - } - public static int SIOCRTMSG() { - return (int)35085L; - } - public static int SIOCGIFNAME() { - return (int)35088L; - } - public static int SIOCSIFLINK() { - return (int)35089L; - } - public static int SIOCGIFCONF() { - return (int)35090L; - } - public static int SIOCGIFFLAGS() { - return (int)35091L; - } - public static int SIOCSIFFLAGS() { - return (int)35092L; - } - public static int SIOCGIFADDR() { - return (int)35093L; - } - public static int SIOCSIFADDR() { - return (int)35094L; - } - public static int SIOCGIFDSTADDR() { - return (int)35095L; - } - public static int SIOCSIFDSTADDR() { - return (int)35096L; - } - public static int SIOCGIFBRDADDR() { - return (int)35097L; - } - public static int SIOCSIFBRDADDR() { - return (int)35098L; - } - public static int SIOCGIFNETMASK() { - return (int)35099L; - } - public static int SIOCSIFNETMASK() { - return (int)35100L; - } - public static int SIOCGIFMETRIC() { - return (int)35101L; - } - public static int SIOCSIFMETRIC() { - return (int)35102L; - } - public static int SIOCGIFMEM() { - return (int)35103L; - } - public static int SIOCSIFMEM() { - return (int)35104L; - } - public static int SIOCGIFMTU() { - return (int)35105L; - } - public static int SIOCSIFMTU() { - return (int)35106L; - } - public static int SIOCSIFNAME() { - return (int)35107L; - } - public static int SIOCSIFHWADDR() { - return (int)35108L; - } - public static int SIOCGIFENCAP() { - return (int)35109L; - } - public static int SIOCSIFENCAP() { - return (int)35110L; - } - public static int SIOCGIFHWADDR() { - return (int)35111L; - } - public static int SIOCGIFSLAVE() { - return (int)35113L; - } - public static int SIOCSIFSLAVE() { - return (int)35120L; - } - public static int SIOCADDMULTI() { - return (int)35121L; - } - public static int SIOCDELMULTI() { - return (int)35122L; - } - public static int SIOCGIFINDEX() { - return (int)35123L; - } - public static int SIOCSIFPFLAGS() { - return (int)35124L; - } - public static int SIOCGIFPFLAGS() { - return (int)35125L; - } - public static int SIOCDIFADDR() { - return (int)35126L; - } - public static int SIOCSIFHWBROADCAST() { - return (int)35127L; - } - public static int SIOCGIFCOUNT() { - return (int)35128L; - } - public static int SIOCGIFBR() { - return (int)35136L; - } - public static int SIOCSIFBR() { - return (int)35137L; - } - public static int SIOCGIFTXQLEN() { - return (int)35138L; - } - public static int SIOCSIFTXQLEN() { - return (int)35139L; - } - public static int SIOCDARP() { - return (int)35155L; - } - public static int SIOCGARP() { - return (int)35156L; - } - public static int SIOCSARP() { - return (int)35157L; - } - public static int SIOCDRARP() { - return (int)35168L; - } - public static int SIOCGRARP() { - return (int)35169L; - } - public static int SIOCSRARP() { - return (int)35170L; - } - public static int SIOCGIFMAP() { - return (int)35184L; - } - public static int SIOCSIFMAP() { - return (int)35185L; - } - public static int SIOCADDDLCI() { - return (int)35200L; - } - public static int SIOCDELDLCI() { - return (int)35201L; - } - public static int SIOCDEVPRIVATE() { - return (int)35312L; - } - public static int SIOCPROTOPRIVATE() { - return (int)35296L; - } - public static int NCC() { - return (int)8L; - } - public static int TIOCM_LE() { - return (int)1L; - } - public static int TIOCM_DTR() { - return (int)2L; - } - public static int TIOCM_RTS() { - return (int)4L; - } - public static int TIOCM_ST() { - return (int)8L; - } - public static int TIOCM_SR() { - return (int)16L; - } - public static int TIOCM_CTS() { - return (int)32L; - } - public static int TIOCM_CAR() { - return (int)64L; - } - public static int TIOCM_RNG() { - return (int)128L; - } - public static int TIOCM_DSR() { - return (int)256L; - } - public static int N_TTY() { - return (int)0L; - } - public static int N_SLIP() { - return (int)1L; - } - public static int N_MOUSE() { - return (int)2L; - } - public static int N_PPP() { - return (int)3L; - } - public static int N_STRIP() { - return (int)4L; - } - public static int N_AX25() { - return (int)5L; - } - public static int N_X25() { - return (int)6L; - } - public static int N_6PACK() { - return (int)7L; - } - public static int N_MASC() { - return (int)8L; - } - public static int N_R3964() { - return (int)9L; - } - public static int N_PROFIBUS_FDL() { - return (int)10L; - } - public static int N_IRDA() { - return (int)11L; - } - public static int N_SMSBLOCK() { - return (int)12L; - } - public static int N_HDLC() { - return (int)13L; - } - public static int N_SYNC_PPP() { - return (int)14L; - } - public static int N_HCI() { - return (int)15L; - } - public static int CERASE() { - return (int)127L; - } - public static int CMIN() { - return (int)1L; - } - public static int CQUIT() { - return (int)28L; - } - public static int CTIME() { - return (int)0L; - } public static MethodHandle ioctl$MH() { return RuntimeHelper.requireNonNull(constants$0.ioctl$MH,"ioctl"); } @@ -606,153 +27,6 @@ public static int ioctl ( int __fd, long __request, Object... x2) { throw new AssertionError("should not reach here", ex$); } } - public static long _POSIX_C_SOURCE() { - return 200809L; - } - public static int __TIMESIZE() { - return (int)64L; - } - public static long __STDC_IEC_60559_BFP__() { - return 201404L; - } - public static long __STDC_IEC_60559_COMPLEX__() { - return 201404L; - } - public static long __STDC_ISO_10646__() { - return 201706L; - } - public static int _IOC_NRMASK() { - return (int)255L; - } - public static int _IOC_TYPEMASK() { - return (int)255L; - } - public static int _IOC_SIZEMASK() { - return (int)16383L; - } - public static int _IOC_DIRMASK() { - return (int)3L; - } - public static int _IOC_TYPESHIFT() { - return (int)8L; - } - public static int _IOC_SIZESHIFT() { - return (int)16L; - } - public static int _IOC_DIRSHIFT() { - return (int)30L; - } - public static int _IOC_NONE() { - return (int)0L; - } - public static int _IOC_WRITE() { - return (int)1L; - } - public static int _IOC_READ() { - return (int)2L; - } - public static int IOC_IN() { - return (int)1073741824L; - } - public static int IOC_OUT() { - return (int)2147483648L; - } - public static int IOC_INOUT() { - return (int)3221225472L; - } - public static int IOCSIZE_MASK() { - return (int)1073676288L; - } - public static int IOCSIZE_SHIFT() { - return (int)16L; - } - public static int TIOCINQ() { - return (int)21531L; - } - public static long TIOCGPTN() { - return 2147767344L; - } - public static long TIOCSPTLCK() { - return 1074025521L; - } - public static long TIOCGDEV() { - return 2147767346L; - } - public static long TIOCSIG() { - return 1074025526L; - } - public static long TIOCGPKT() { - return 2147767352L; - } - public static long TIOCGPTLCK() { - return 2147767353L; - } - public static long TIOCGEXCL() { - return 2147767360L; - } - public static int TIOCGPTPEER() { - return (int)21569L; - } - public static int SIOGIFINDEX() { - return (int)35123L; - } - public static int TIOCM_CD() { - return (int)64L; - } - public static int TIOCM_RI() { - return (int)128L; - } - public static int CEOF() { - return (int)4L; - } - public static int CEOL() { - return (int)0L; - } - public static int CINTR() { - return (int)3L; - } - public static int CSTATUS() { - return (int)0L; - } - public static int CKILL() { - return (int)21L; - } - public static int CSUSP() { - return (int)26L; - } - public static int CDSUSP() { - return (int)25L; - } - public static int CSTART() { - return (int)17L; - } - public static int CSTOP() { - return (int)19L; - } - public static int CLNEXT() { - return (int)22L; - } - public static int CDISCARD() { - return (int)15L; - } - public static int CWERASE() { - return (int)23L; - } - public static int CREPRINT() { - return (int)18L; - } - public static int CEOT() { - return (int)4L; - } - public static int CBRK() { - return (int)0L; - } - public static int CRPRNT() { - return (int)18L; - } - public static int CFLUSH() { - return (int)15L; - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/termio.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/termio.java deleted file mode 100644 index 500ef096..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/termio.java +++ /dev/null @@ -1,112 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.ioctl; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; -public class termio { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_SHORT$LAYOUT.withName("c_iflag"), - Constants$root.C_SHORT$LAYOUT.withName("c_oflag"), - Constants$root.C_SHORT$LAYOUT.withName("c_cflag"), - Constants$root.C_SHORT$LAYOUT.withName("c_lflag"), - Constants$root.C_CHAR$LAYOUT.withName("c_line"), - MemoryLayout.sequenceLayout(8, Constants$root.C_CHAR$LAYOUT).withName("c_cc"), - MemoryLayout.paddingLayout(8) - ).withName("termio"); - public static MemoryLayout $LAYOUT() { - return termio.$struct$LAYOUT; - } - static final VarHandle c_iflag$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("c_iflag")); - public static VarHandle c_iflag$VH() { - return termio.c_iflag$VH; - } - public static short c_iflag$get(MemorySegment seg) { - return (short)termio.c_iflag$VH.get(seg); - } - public static void c_iflag$set( MemorySegment seg, short x) { - termio.c_iflag$VH.set(seg, x); - } - public static short c_iflag$get(MemorySegment seg, long index) { - return (short)termio.c_iflag$VH.get(seg.asSlice(index*sizeof())); - } - public static void c_iflag$set(MemorySegment seg, long index, short x) { - termio.c_iflag$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle c_oflag$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("c_oflag")); - public static VarHandle c_oflag$VH() { - return termio.c_oflag$VH; - } - public static short c_oflag$get(MemorySegment seg) { - return (short)termio.c_oflag$VH.get(seg); - } - public static void c_oflag$set( MemorySegment seg, short x) { - termio.c_oflag$VH.set(seg, x); - } - public static short c_oflag$get(MemorySegment seg, long index) { - return (short)termio.c_oflag$VH.get(seg.asSlice(index*sizeof())); - } - public static void c_oflag$set(MemorySegment seg, long index, short x) { - termio.c_oflag$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle c_cflag$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("c_cflag")); - public static VarHandle c_cflag$VH() { - return termio.c_cflag$VH; - } - public static short c_cflag$get(MemorySegment seg) { - return (short)termio.c_cflag$VH.get(seg); - } - public static void c_cflag$set( MemorySegment seg, short x) { - termio.c_cflag$VH.set(seg, x); - } - public static short c_cflag$get(MemorySegment seg, long index) { - return (short)termio.c_cflag$VH.get(seg.asSlice(index*sizeof())); - } - public static void c_cflag$set(MemorySegment seg, long index, short x) { - termio.c_cflag$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle c_lflag$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("c_lflag")); - public static VarHandle c_lflag$VH() { - return termio.c_lflag$VH; - } - public static short c_lflag$get(MemorySegment seg) { - return (short)termio.c_lflag$VH.get(seg); - } - public static void c_lflag$set( MemorySegment seg, short x) { - termio.c_lflag$VH.set(seg, x); - } - public static short c_lflag$get(MemorySegment seg, long index) { - return (short)termio.c_lflag$VH.get(seg.asSlice(index*sizeof())); - } - public static void c_lflag$set(MemorySegment seg, long index, short x) { - termio.c_lflag$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle c_line$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("c_line")); - public static VarHandle c_line$VH() { - return termio.c_line$VH; - } - public static byte c_line$get(MemorySegment seg) { - return (byte)termio.c_line$VH.get(seg); - } - public static void c_line$set( MemorySegment seg, byte x) { - termio.c_line$VH.set(seg, x); - } - public static byte c_line$get(MemorySegment seg, long index) { - return (byte)termio.c_line$VH.get(seg.asSlice(index*sizeof())); - } - public static void c_line$set(MemorySegment seg, long index, byte x) { - termio.c_line$VH.set(seg.asSlice(index*sizeof()), x); - } - public static MemorySegment c_cc$slice(MemorySegment seg) { - return seg.asSlice(9, 8); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/winsize.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/winsize.java deleted file mode 100644 index d05924c2..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/winsize.java +++ /dev/null @@ -1,90 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.ioctl; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; -public class winsize { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_SHORT$LAYOUT.withName("ws_row"), - Constants$root.C_SHORT$LAYOUT.withName("ws_col"), - Constants$root.C_SHORT$LAYOUT.withName("ws_xpixel"), - Constants$root.C_SHORT$LAYOUT.withName("ws_ypixel") - ).withName("winsize"); - public static MemoryLayout $LAYOUT() { - return winsize.$struct$LAYOUT; - } - static final VarHandle ws_row$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ws_row")); - public static VarHandle ws_row$VH() { - return winsize.ws_row$VH; - } - public static short ws_row$get(MemorySegment seg) { - return (short)winsize.ws_row$VH.get(seg); - } - public static void ws_row$set( MemorySegment seg, short x) { - winsize.ws_row$VH.set(seg, x); - } - public static short ws_row$get(MemorySegment seg, long index) { - return (short)winsize.ws_row$VH.get(seg.asSlice(index*sizeof())); - } - public static void ws_row$set(MemorySegment seg, long index, short x) { - winsize.ws_row$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle ws_col$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ws_col")); - public static VarHandle ws_col$VH() { - return winsize.ws_col$VH; - } - public static short ws_col$get(MemorySegment seg) { - return (short)winsize.ws_col$VH.get(seg); - } - public static void ws_col$set( MemorySegment seg, short x) { - winsize.ws_col$VH.set(seg, x); - } - public static short ws_col$get(MemorySegment seg, long index) { - return (short)winsize.ws_col$VH.get(seg.asSlice(index*sizeof())); - } - public static void ws_col$set(MemorySegment seg, long index, short x) { - winsize.ws_col$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle ws_xpixel$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ws_xpixel")); - public static VarHandle ws_xpixel$VH() { - return winsize.ws_xpixel$VH; - } - public static short ws_xpixel$get(MemorySegment seg) { - return (short)winsize.ws_xpixel$VH.get(seg); - } - public static void ws_xpixel$set( MemorySegment seg, short x) { - winsize.ws_xpixel$VH.set(seg, x); - } - public static short ws_xpixel$get(MemorySegment seg, long index) { - return (short)winsize.ws_xpixel$VH.get(seg.asSlice(index*sizeof())); - } - public static void ws_xpixel$set(MemorySegment seg, long index, short x) { - winsize.ws_xpixel$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle ws_ypixel$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ws_ypixel")); - public static VarHandle ws_ypixel$VH() { - return winsize.ws_ypixel$VH; - } - public static short ws_ypixel$get(MemorySegment seg) { - return (short)winsize.ws_ypixel$VH.get(seg); - } - public static void ws_ypixel$set( MemorySegment seg, short x) { - winsize.ws_ypixel$VH.set(seg, x); - } - public static short ws_ypixel$get(MemorySegment seg, long index) { - return (short)winsize.ws_ypixel$VH.get(seg.asSlice(index*sizeof())); - } - public static void ws_ypixel$set(MemorySegment seg, long index, short x) { - winsize.ws_ypixel$VH.set(seg.asSlice(index*sizeof()), x); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/__fsid_t.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/__fsid_t.java deleted file mode 100644 index 990f9f6b..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/__fsid_t.java +++ /dev/null @@ -1,25 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.*; -public class __fsid_t { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - MemoryLayout.sequenceLayout(2, Constants$root.C_INT$LAYOUT).withName("__val") - ); - public static MemoryLayout $LAYOUT() { - return __fsid_t.$struct$LAYOUT; - } - public static MemorySegment __val$slice(MemorySegment seg) { - return seg.asSlice(0, 8); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java index 4535a379..26995ca4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java @@ -6,33 +6,6 @@ import java.lang.invoke.MethodHandle; class constants$0 { - static final FunctionDescriptor access$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle access$MH = RuntimeHelper.downcallHandle( - "access", - constants$0.access$FUNC - ); - static final FunctionDescriptor faccessat$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle faccessat$MH = RuntimeHelper.downcallHandle( - "faccessat", - constants$0.faccessat$FUNC - ); - static final FunctionDescriptor lseek$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle lseek$MH = RuntimeHelper.downcallHandle( - "lseek", - constants$0.lseek$FUNC - ); static final FunctionDescriptor close$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_INT$LAYOUT ); @@ -40,22 +13,6 @@ class constants$0 { "close", constants$0.close$FUNC ); - static final FunctionDescriptor closefrom$FUNC = FunctionDescriptor.ofVoid( - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle closefrom$MH = RuntimeHelper.downcallHandle( - "closefrom", - constants$0.closefrom$FUNC - ); - static final FunctionDescriptor read$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle read$MH = RuntimeHelper.downcallHandle( - "read", - constants$0.read$FUNC - ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$1.java deleted file mode 100644 index 0cc4fe56..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$1.java +++ /dev/null @@ -1,61 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$1 { - - static final FunctionDescriptor write$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle write$MH = RuntimeHelper.downcallHandle( - "write", - constants$1.write$FUNC - ); - static final FunctionDescriptor pread$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle pread$MH = RuntimeHelper.downcallHandle( - "pread", - constants$1.pread$FUNC - ); - static final FunctionDescriptor pwrite$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle pwrite$MH = RuntimeHelper.downcallHandle( - "pwrite", - constants$1.pwrite$FUNC - ); - static final FunctionDescriptor pipe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle pipe$MH = RuntimeHelper.downcallHandle( - "pipe", - constants$1.pipe$FUNC - ); - static final FunctionDescriptor alarm$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle alarm$MH = RuntimeHelper.downcallHandle( - "alarm", - constants$1.alarm$FUNC - ); - static final FunctionDescriptor sleep$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle sleep$MH = RuntimeHelper.downcallHandle( - "sleep", - constants$1.sleep$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$10.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$10.java deleted file mode 100644 index 64c7caab..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$10.java +++ /dev/null @@ -1,52 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$10 { - - static final FunctionDescriptor vfork$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); - static final MethodHandle vfork$MH = RuntimeHelper.downcallHandle( - "vfork", - constants$10.vfork$FUNC - ); - static final FunctionDescriptor ttyname$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle ttyname$MH = RuntimeHelper.downcallHandle( - "ttyname", - constants$10.ttyname$FUNC - ); - static final FunctionDescriptor ttyname_r$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle ttyname_r$MH = RuntimeHelper.downcallHandle( - "ttyname_r", - constants$10.ttyname_r$FUNC - ); - static final FunctionDescriptor isatty$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle isatty$MH = RuntimeHelper.downcallHandle( - "isatty", - constants$10.isatty$FUNC - ); - static final FunctionDescriptor ttyslot$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); - static final MethodHandle ttyslot$MH = RuntimeHelper.downcallHandle( - "ttyslot", - constants$10.ttyslot$FUNC - ); - static final FunctionDescriptor link$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle link$MH = RuntimeHelper.downcallHandle( - "link", - constants$10.link$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$11.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$11.java deleted file mode 100644 index 4dc75380..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$11.java +++ /dev/null @@ -1,65 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$11 { - - static final FunctionDescriptor linkat$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle linkat$MH = RuntimeHelper.downcallHandle( - "linkat", - constants$11.linkat$FUNC - ); - static final FunctionDescriptor symlink$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle symlink$MH = RuntimeHelper.downcallHandle( - "symlink", - constants$11.symlink$FUNC - ); - static final FunctionDescriptor readlink$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle readlink$MH = RuntimeHelper.downcallHandle( - "readlink", - constants$11.readlink$FUNC - ); - static final FunctionDescriptor symlinkat$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle symlinkat$MH = RuntimeHelper.downcallHandle( - "symlinkat", - constants$11.symlinkat$FUNC - ); - static final FunctionDescriptor readlinkat$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle readlinkat$MH = RuntimeHelper.downcallHandle( - "readlinkat", - constants$11.readlinkat$FUNC - ); - static final FunctionDescriptor unlink$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle unlink$MH = RuntimeHelper.downcallHandle( - "unlink", - constants$11.unlink$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$12.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$12.java deleted file mode 100644 index b73d5e46..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$12.java +++ /dev/null @@ -1,55 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$12 { - - static final FunctionDescriptor unlinkat$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle unlinkat$MH = RuntimeHelper.downcallHandle( - "unlinkat", - constants$12.unlinkat$FUNC - ); - static final FunctionDescriptor rmdir$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle rmdir$MH = RuntimeHelper.downcallHandle( - "rmdir", - constants$12.rmdir$FUNC - ); - static final FunctionDescriptor tcgetpgrp$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle tcgetpgrp$MH = RuntimeHelper.downcallHandle( - "tcgetpgrp", - constants$12.tcgetpgrp$FUNC - ); - static final FunctionDescriptor tcsetpgrp$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle tcsetpgrp$MH = RuntimeHelper.downcallHandle( - "tcsetpgrp", - constants$12.tcsetpgrp$FUNC - ); - static final FunctionDescriptor getlogin$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT); - static final MethodHandle getlogin$MH = RuntimeHelper.downcallHandle( - "getlogin", - constants$12.getlogin$FUNC - ); - static final FunctionDescriptor getlogin_r$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle getlogin_r$MH = RuntimeHelper.downcallHandle( - "getlogin_r", - constants$12.getlogin_r$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$13.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$13.java deleted file mode 100644 index bab872f5..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$13.java +++ /dev/null @@ -1,44 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemorySegment; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.OfAddress; -import static java.lang.foreign.ValueLayout.OfInt; -class constants$13 { - - static final FunctionDescriptor setlogin$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle setlogin$MH = RuntimeHelper.downcallHandle( - "setlogin", - constants$13.setlogin$FUNC - ); - static final OfAddress optarg$LAYOUT = Constants$root.C_POINTER$LAYOUT; - static final VarHandle optarg$VH = constants$13.optarg$LAYOUT.varHandle(); - static final MemorySegment optarg$SEGMENT = RuntimeHelper.lookupGlobalVariable("optarg", constants$13.optarg$LAYOUT); - static final OfInt optind$LAYOUT = Constants$root.C_INT$LAYOUT; - static final VarHandle optind$VH = constants$13.optind$LAYOUT.varHandle(); - static final MemorySegment optind$SEGMENT = RuntimeHelper.lookupGlobalVariable("optind", constants$13.optind$LAYOUT); - static final OfInt opterr$LAYOUT = Constants$root.C_INT$LAYOUT; - static final VarHandle opterr$VH = constants$13.opterr$LAYOUT.varHandle(); - static final MemorySegment opterr$SEGMENT = RuntimeHelper.lookupGlobalVariable("opterr", constants$13.opterr$LAYOUT); - static final OfInt optopt$LAYOUT = Constants$root.C_INT$LAYOUT; - static final VarHandle optopt$VH = constants$13.optopt$LAYOUT.varHandle(); - static final MemorySegment optopt$SEGMENT = RuntimeHelper.lookupGlobalVariable("optopt", constants$13.optopt$LAYOUT); - static final FunctionDescriptor getopt$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle getopt$MH = RuntimeHelper.downcallHandle( - "getopt", - constants$13.getopt$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$14.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$14.java deleted file mode 100644 index 68193487..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$14.java +++ /dev/null @@ -1,55 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$14 { - - static final FunctionDescriptor gethostname$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle gethostname$MH = RuntimeHelper.downcallHandle( - "gethostname", - constants$14.gethostname$FUNC - ); - static final FunctionDescriptor sethostname$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle sethostname$MH = RuntimeHelper.downcallHandle( - "sethostname", - constants$14.sethostname$FUNC - ); - static final FunctionDescriptor sethostid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle sethostid$MH = RuntimeHelper.downcallHandle( - "sethostid", - constants$14.sethostid$FUNC - ); - static final FunctionDescriptor getdomainname$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle getdomainname$MH = RuntimeHelper.downcallHandle( - "getdomainname", - constants$14.getdomainname$FUNC - ); - static final FunctionDescriptor setdomainname$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle setdomainname$MH = RuntimeHelper.downcallHandle( - "setdomainname", - constants$14.setdomainname$FUNC - ); - static final FunctionDescriptor vhangup$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); - static final MethodHandle vhangup$MH = RuntimeHelper.downcallHandle( - "vhangup", - constants$14.vhangup$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$15.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$15.java deleted file mode 100644 index 432d2995..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$15.java +++ /dev/null @@ -1,50 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$15 { - - static final FunctionDescriptor revoke$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle revoke$MH = RuntimeHelper.downcallHandle( - "revoke", - constants$15.revoke$FUNC - ); - static final FunctionDescriptor profil$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle profil$MH = RuntimeHelper.downcallHandle( - "profil", - constants$15.profil$FUNC - ); - static final FunctionDescriptor acct$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle acct$MH = RuntimeHelper.downcallHandle( - "acct", - constants$15.acct$FUNC - ); - static final FunctionDescriptor getusershell$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT); - static final MethodHandle getusershell$MH = RuntimeHelper.downcallHandle( - "getusershell", - constants$15.getusershell$FUNC - ); - static final FunctionDescriptor endusershell$FUNC = FunctionDescriptor.ofVoid(); - static final MethodHandle endusershell$MH = RuntimeHelper.downcallHandle( - "endusershell", - constants$15.endusershell$FUNC - ); - static final FunctionDescriptor setusershell$FUNC = FunctionDescriptor.ofVoid(); - static final MethodHandle setusershell$MH = RuntimeHelper.downcallHandle( - "setusershell", - constants$15.setusershell$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$16.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$16.java deleted file mode 100644 index 2373648b..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$16.java +++ /dev/null @@ -1,50 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$16 { - - static final FunctionDescriptor daemon$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle daemon$MH = RuntimeHelper.downcallHandle( - "daemon", - constants$16.daemon$FUNC - ); - static final FunctionDescriptor chroot$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle chroot$MH = RuntimeHelper.downcallHandle( - "chroot", - constants$16.chroot$FUNC - ); - static final FunctionDescriptor getpass$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle getpass$MH = RuntimeHelper.downcallHandle( - "getpass", - constants$16.getpass$FUNC - ); - static final FunctionDescriptor fsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle fsync$MH = RuntimeHelper.downcallHandle( - "fsync", - constants$16.fsync$FUNC - ); - static final FunctionDescriptor gethostid$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT); - static final MethodHandle gethostid$MH = RuntimeHelper.downcallHandle( - "gethostid", - constants$16.gethostid$FUNC - ); - static final FunctionDescriptor sync$FUNC = FunctionDescriptor.ofVoid(); - static final MethodHandle sync$MH = RuntimeHelper.downcallHandle( - "sync", - constants$16.sync$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$17.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$17.java deleted file mode 100644 index 9e76f6e5..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$17.java +++ /dev/null @@ -1,51 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$17 { - - static final FunctionDescriptor getpagesize$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); - static final MethodHandle getpagesize$MH = RuntimeHelper.downcallHandle( - "getpagesize", - constants$17.getpagesize$FUNC - ); - static final FunctionDescriptor getdtablesize$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); - static final MethodHandle getdtablesize$MH = RuntimeHelper.downcallHandle( - "getdtablesize", - constants$17.getdtablesize$FUNC - ); - static final FunctionDescriptor truncate$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle truncate$MH = RuntimeHelper.downcallHandle( - "truncate", - constants$17.truncate$FUNC - ); - static final FunctionDescriptor ftruncate$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle ftruncate$MH = RuntimeHelper.downcallHandle( - "ftruncate", - constants$17.ftruncate$FUNC - ); - static final FunctionDescriptor brk$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle brk$MH = RuntimeHelper.downcallHandle( - "brk", - constants$17.brk$FUNC - ); - static final FunctionDescriptor sbrk$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle sbrk$MH = RuntimeHelper.downcallHandle( - "sbrk", - constants$17.sbrk$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$18.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$18.java deleted file mode 100644 index 794239b3..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$18.java +++ /dev/null @@ -1,52 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemorySegment; -import java.lang.invoke.MethodHandle; -class constants$18 { - - static final FunctionDescriptor syscall$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle syscall$MH = RuntimeHelper.downcallHandleVariadic( - "syscall", - constants$18.syscall$FUNC - ); - static final FunctionDescriptor lockf$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle lockf$MH = RuntimeHelper.downcallHandle( - "lockf", - constants$18.lockf$FUNC - ); - static final FunctionDescriptor fdatasync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle fdatasync$MH = RuntimeHelper.downcallHandle( - "fdatasync", - constants$18.fdatasync$FUNC - ); - static final FunctionDescriptor crypt$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle crypt$MH = RuntimeHelper.downcallHandle( - "crypt", - constants$18.crypt$FUNC - ); - static final FunctionDescriptor getentropy$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle getentropy$MH = RuntimeHelper.downcallHandle( - "getentropy", - constants$18.getentropy$FUNC - ); - static final MemorySegment __ILP32_OFF32_CFLAGS$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("-m32"); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$19.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$19.java deleted file mode 100644 index a33d0a5c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$19.java +++ /dev/null @@ -1,17 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.MemoryAddress; -import java.lang.foreign.MemorySegment; -class constants$19 { - - static final MemorySegment __ILP32_OFF32_LDFLAGS$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("-m32"); - static final MemorySegment __ILP32_OFFBIG_CFLAGS$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("-m32 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"); - static final MemorySegment __ILP32_OFFBIG_LDFLAGS$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("-m32"); - static final MemorySegment __LP64_OFF64_CFLAGS$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("-m64"); - static final MemorySegment __LP64_OFF64_LDFLAGS$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("-m64"); - static final MemoryAddress NULL$ADDR = MemoryAddress.ofLong(0L); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$2.java deleted file mode 100644 index df7185a3..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$2.java +++ /dev/null @@ -1,58 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$2 { - - static final FunctionDescriptor ualarm$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle ualarm$MH = RuntimeHelper.downcallHandle( - "ualarm", - constants$2.ualarm$FUNC - ); - static final FunctionDescriptor usleep$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle usleep$MH = RuntimeHelper.downcallHandle( - "usleep", - constants$2.usleep$FUNC - ); - static final FunctionDescriptor pause$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); - static final MethodHandle pause$MH = RuntimeHelper.downcallHandle( - "pause", - constants$2.pause$FUNC - ); - static final FunctionDescriptor chown$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle chown$MH = RuntimeHelper.downcallHandle( - "chown", - constants$2.chown$FUNC - ); - static final FunctionDescriptor fchown$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle fchown$MH = RuntimeHelper.downcallHandle( - "fchown", - constants$2.fchown$FUNC - ); - static final FunctionDescriptor lchown$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle lchown$MH = RuntimeHelper.downcallHandle( - "lchown", - constants$2.lchown$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$3.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$3.java deleted file mode 100644 index 81b2b5d6..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$3.java +++ /dev/null @@ -1,58 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$3 { - - static final FunctionDescriptor fchownat$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle fchownat$MH = RuntimeHelper.downcallHandle( - "fchownat", - constants$3.fchownat$FUNC - ); - static final FunctionDescriptor chdir$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle chdir$MH = RuntimeHelper.downcallHandle( - "chdir", - constants$3.chdir$FUNC - ); - static final FunctionDescriptor fchdir$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle fchdir$MH = RuntimeHelper.downcallHandle( - "fchdir", - constants$3.fchdir$FUNC - ); - static final FunctionDescriptor getcwd$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle getcwd$MH = RuntimeHelper.downcallHandle( - "getcwd", - constants$3.getcwd$FUNC - ); - static final FunctionDescriptor getwd$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle getwd$MH = RuntimeHelper.downcallHandle( - "getwd", - constants$3.getwd$FUNC - ); - static final FunctionDescriptor dup$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle dup$MH = RuntimeHelper.downcallHandle( - "dup", - constants$3.dup$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$4.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$4.java deleted file mode 100644 index ec8066b8..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$4.java +++ /dev/null @@ -1,60 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemorySegment; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.OfAddress; -class constants$4 { - - static final FunctionDescriptor dup2$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle dup2$MH = RuntimeHelper.downcallHandle( - "dup2", - constants$4.dup2$FUNC - ); - static final OfAddress __environ$LAYOUT = Constants$root.C_POINTER$LAYOUT; - static final VarHandle __environ$VH = constants$4.__environ$LAYOUT.varHandle(); - static final MemorySegment __environ$SEGMENT = RuntimeHelper.lookupGlobalVariable("__environ", constants$4.__environ$LAYOUT); - static final FunctionDescriptor execve$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle execve$MH = RuntimeHelper.downcallHandle( - "execve", - constants$4.execve$FUNC - ); - static final FunctionDescriptor fexecve$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle fexecve$MH = RuntimeHelper.downcallHandle( - "fexecve", - constants$4.fexecve$FUNC - ); - static final FunctionDescriptor execv$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle execv$MH = RuntimeHelper.downcallHandle( - "execv", - constants$4.execv$FUNC - ); - static final FunctionDescriptor execle$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle execle$MH = RuntimeHelper.downcallHandleVariadic( - "execle", - constants$4.execle$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$5.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$5.java deleted file mode 100644 index 973d637c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$5.java +++ /dev/null @@ -1,57 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$5 { - - static final FunctionDescriptor execl$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle execl$MH = RuntimeHelper.downcallHandleVariadic( - "execl", - constants$5.execl$FUNC - ); - static final FunctionDescriptor execvp$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle execvp$MH = RuntimeHelper.downcallHandle( - "execvp", - constants$5.execvp$FUNC - ); - static final FunctionDescriptor execlp$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle execlp$MH = RuntimeHelper.downcallHandleVariadic( - "execlp", - constants$5.execlp$FUNC - ); - static final FunctionDescriptor nice$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle nice$MH = RuntimeHelper.downcallHandle( - "nice", - constants$5.nice$FUNC - ); - static final FunctionDescriptor _exit$FUNC = FunctionDescriptor.ofVoid( - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle _exit$MH = RuntimeHelper.downcallHandle( - "_exit", - constants$5._exit$FUNC - ); - static final FunctionDescriptor pathconf$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle pathconf$MH = RuntimeHelper.downcallHandle( - "pathconf", - constants$5.pathconf$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$6.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$6.java deleted file mode 100644 index da5a5a31..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$6.java +++ /dev/null @@ -1,50 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$6 { - - static final FunctionDescriptor fpathconf$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle fpathconf$MH = RuntimeHelper.downcallHandle( - "fpathconf", - constants$6.fpathconf$FUNC - ); - static final FunctionDescriptor sysconf$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle sysconf$MH = RuntimeHelper.downcallHandle( - "sysconf", - constants$6.sysconf$FUNC - ); - static final FunctionDescriptor confstr$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle confstr$MH = RuntimeHelper.downcallHandle( - "confstr", - constants$6.confstr$FUNC - ); - static final FunctionDescriptor getpid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); - static final MethodHandle getpid$MH = RuntimeHelper.downcallHandle( - "getpid", - constants$6.getpid$FUNC - ); - static final FunctionDescriptor getppid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); - static final MethodHandle getppid$MH = RuntimeHelper.downcallHandle( - "getppid", - constants$6.getppid$FUNC - ); - static final FunctionDescriptor getpgrp$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); - static final MethodHandle getpgrp$MH = RuntimeHelper.downcallHandle( - "getpgrp", - constants$6.getpgrp$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$7.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$7.java deleted file mode 100644 index d08b63a9..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$7.java +++ /dev/null @@ -1,50 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$7 { - - static final FunctionDescriptor __getpgid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle __getpgid$MH = RuntimeHelper.downcallHandle( - "__getpgid", - constants$7.__getpgid$FUNC - ); - static final FunctionDescriptor getpgid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle getpgid$MH = RuntimeHelper.downcallHandle( - "getpgid", - constants$7.getpgid$FUNC - ); - static final FunctionDescriptor setpgid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle setpgid$MH = RuntimeHelper.downcallHandle( - "setpgid", - constants$7.setpgid$FUNC - ); - static final FunctionDescriptor setpgrp$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); - static final MethodHandle setpgrp$MH = RuntimeHelper.downcallHandle( - "setpgrp", - constants$7.setpgrp$FUNC - ); - static final FunctionDescriptor setsid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); - static final MethodHandle setsid$MH = RuntimeHelper.downcallHandle( - "setsid", - constants$7.setsid$FUNC - ); - static final FunctionDescriptor getsid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle getsid$MH = RuntimeHelper.downcallHandle( - "getsid", - constants$7.getsid$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$8.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$8.java deleted file mode 100644 index a94fab3c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$8.java +++ /dev/null @@ -1,46 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$8 { - - static final FunctionDescriptor getuid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); - static final MethodHandle getuid$MH = RuntimeHelper.downcallHandle( - "getuid", - constants$8.getuid$FUNC - ); - static final FunctionDescriptor geteuid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); - static final MethodHandle geteuid$MH = RuntimeHelper.downcallHandle( - "geteuid", - constants$8.geteuid$FUNC - ); - static final FunctionDescriptor getgid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); - static final MethodHandle getgid$MH = RuntimeHelper.downcallHandle( - "getgid", - constants$8.getgid$FUNC - ); - static final FunctionDescriptor getegid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); - static final MethodHandle getegid$MH = RuntimeHelper.downcallHandle( - "getegid", - constants$8.getegid$FUNC - ); - static final FunctionDescriptor getgroups$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle getgroups$MH = RuntimeHelper.downcallHandle( - "getgroups", - constants$8.getgroups$FUNC - ); - static final FunctionDescriptor setuid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle setuid$MH = RuntimeHelper.downcallHandle( - "setuid", - constants$8.setuid$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$9.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$9.java deleted file mode 100644 index e4e65a59..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$9.java +++ /dev/null @@ -1,53 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$9 { - - static final FunctionDescriptor setreuid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle setreuid$MH = RuntimeHelper.downcallHandle( - "setreuid", - constants$9.setreuid$FUNC - ); - static final FunctionDescriptor seteuid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle seteuid$MH = RuntimeHelper.downcallHandle( - "seteuid", - constants$9.seteuid$FUNC - ); - static final FunctionDescriptor setgid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle setgid$MH = RuntimeHelper.downcallHandle( - "setgid", - constants$9.setgid$FUNC - ); - static final FunctionDescriptor setregid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle setregid$MH = RuntimeHelper.downcallHandle( - "setregid", - constants$9.setregid$FUNC - ); - static final FunctionDescriptor setegid$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle setegid$MH = RuntimeHelper.downcallHandle( - "setegid", - constants$9.setegid$FUNC - ); - static final FunctionDescriptor fork$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); - static final MethodHandle fork$MH = RuntimeHelper.downcallHandle( - "fork", - constants$9.fork$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java index cf6b6b76..74045e41 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java @@ -2,12 +2,7 @@ package net.codecrete.usb.linux.gen.unistd; -import java.lang.foreign.Addressable; -import java.lang.foreign.MemoryAddress; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; import static java.lang.foreign.ValueLayout.*; public class unistd { @@ -21,342 +16,6 @@ public class unistd { public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; - public static int _UNISTD_H() { - return (int)1L; - } - public static int _FEATURES_H() { - return (int)1L; - } - public static int _DEFAULT_SOURCE() { - return (int)1L; - } - public static int __GLIBC_USE_ISOC2X() { - return (int)0L; - } - public static int __USE_ISOC11() { - return (int)1L; - } - public static int __USE_ISOC99() { - return (int)1L; - } - public static int __USE_ISOC95() { - return (int)1L; - } - public static int __USE_POSIX_IMPLICITLY() { - return (int)1L; - } - public static int _POSIX_SOURCE() { - return (int)1L; - } - public static int __USE_POSIX() { - return (int)1L; - } - public static int __USE_POSIX2() { - return (int)1L; - } - public static int __USE_POSIX199309() { - return (int)1L; - } - public static int __USE_POSIX199506() { - return (int)1L; - } - public static int __USE_XOPEN2K() { - return (int)1L; - } - public static int __USE_XOPEN2K8() { - return (int)1L; - } - public static int _ATFILE_SOURCE() { - return (int)1L; - } - public static int __WORDSIZE() { - return (int)64L; - } - public static int __WORDSIZE_TIME64_COMPAT32() { - return (int)1L; - } - public static int __SYSCALL_WORDSIZE() { - return (int)64L; - } - public static int __USE_MISC() { - return (int)1L; - } - public static int __USE_ATFILE() { - return (int)1L; - } - public static int __USE_FORTIFY_LEVEL() { - return (int)0L; - } - public static int __GLIBC_USE_DEPRECATED_GETS() { - return (int)0L; - } - public static int __GLIBC_USE_DEPRECATED_SCANF() { - return (int)0L; - } - public static int _STDC_PREDEF_H() { - return (int)1L; - } - public static int __STDC_IEC_559__() { - return (int)1L; - } - public static int __STDC_IEC_559_COMPLEX__() { - return (int)1L; - } - public static int __GNU_LIBRARY__() { - return (int)6L; - } - public static int __GLIBC__() { - return (int)2L; - } - public static int __GLIBC_MINOR__() { - return (int)35L; - } - public static int _SYS_CDEFS_H() { - return (int)1L; - } - public static int __glibc_c99_flexarr_available() { - return (int)1L; - } - public static int __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI() { - return (int)0L; - } - public static int __HAVE_GENERIC_SELECTION() { - return (int)1L; - } - public static int _XOPEN_VERSION() { - return (int)700L; - } - public static int _XOPEN_XCU_VERSION() { - return (int)4L; - } - public static int _XOPEN_XPG2() { - return (int)1L; - } - public static int _XOPEN_XPG3() { - return (int)1L; - } - public static int _XOPEN_XPG4() { - return (int)1L; - } - public static int _XOPEN_UNIX() { - return (int)1L; - } - public static int _XOPEN_ENH_I18N() { - return (int)1L; - } - public static int _XOPEN_LEGACY() { - return (int)1L; - } - public static int _BITS_POSIX_OPT_H() { - return (int)1L; - } - public static int _POSIX_JOB_CONTROL() { - return (int)1L; - } - public static int _POSIX_SAVED_IDS() { - return (int)1L; - } - public static int _POSIX_CHOWN_RESTRICTED() { - return (int)0L; - } - public static int _POSIX_NO_TRUNC() { - return (int)1L; - } - public static int _XOPEN_REALTIME() { - return (int)1L; - } - public static int _XOPEN_REALTIME_THREADS() { - return (int)1L; - } - public static int _XOPEN_SHM() { - return (int)1L; - } - public static int _POSIX_REENTRANT_FUNCTIONS() { - return (int)1L; - } - public static int _POSIX_ASYNC_IO() { - return (int)1L; - } - public static int _LFS_ASYNCHRONOUS_IO() { - return (int)1L; - } - public static int _LFS64_ASYNCHRONOUS_IO() { - return (int)1L; - } - public static int _LFS_LARGEFILE() { - return (int)1L; - } - public static int _LFS64_LARGEFILE() { - return (int)1L; - } - public static int _LFS64_STDIO() { - return (int)1L; - } - public static int _POSIX_CPUTIME() { - return (int)0L; - } - public static int _POSIX_THREAD_CPUTIME() { - return (int)0L; - } - public static int _POSIX_REGEXP() { - return (int)1L; - } - public static int _POSIX_SHELL() { - return (int)1L; - } - public static int _POSIX_MONOTONIC_CLOCK() { - return (int)0L; - } - public static int _POSIX_V7_LP64_OFF64() { - return (int)1L; - } - public static int _POSIX_V6_LP64_OFF64() { - return (int)1L; - } - public static int _XBS5_LP64_OFF64() { - return (int)1L; - } - public static int STDIN_FILENO() { - return (int)0L; - } - public static int STDOUT_FILENO() { - return (int)1L; - } - public static int STDERR_FILENO() { - return (int)2L; - } - public static int _BITS_TYPES_H() { - return (int)1L; - } - public static int _BITS_TYPESIZES_H() { - return (int)1L; - } - public static int __OFF_T_MATCHES_OFF64_T() { - return (int)1L; - } - public static int __INO_T_MATCHES_INO64_T() { - return (int)1L; - } - public static int __RLIM_T_MATCHES_RLIM64_T() { - return (int)1L; - } - public static int __STATFS_MATCHES_STATFS64() { - return (int)1L; - } - public static int __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64() { - return (int)1L; - } - public static int __FD_SETSIZE() { - return (int)1024L; - } - public static int _BITS_TIME64_H() { - return (int)1L; - } - public static int R_OK() { - return (int)4L; - } - public static int W_OK() { - return (int)2L; - } - public static int X_OK() { - return (int)1L; - } - public static int F_OK() { - return (int)0L; - } - public static int SEEK_SET() { - return (int)0L; - } - public static int SEEK_CUR() { - return (int)1L; - } - public static int SEEK_END() { - return (int)2L; - } - public static int _GETOPT_POSIX_H() { - return (int)1L; - } - public static int _GETOPT_CORE_H() { - return (int)1L; - } - public static int F_ULOCK() { - return (int)0L; - } - public static int F_LOCK() { - return (int)1L; - } - public static int F_TLOCK() { - return (int)2L; - } - public static int F_TEST() { - return (int)3L; - } - public static OfShort __int16_t = Constants$root.C_SHORT$LAYOUT; - public static OfInt __int32_t = Constants$root.C_INT$LAYOUT; - public static OfLong __int64_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfShort __int_least16_t = Constants$root.C_SHORT$LAYOUT; - public static OfInt __int_least32_t = Constants$root.C_INT$LAYOUT; - public static OfLong __int_least64_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __quad_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __intmax_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __off_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __off64_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfInt __pid_t = Constants$root.C_INT$LAYOUT; - public static OfLong __clock_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __time_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __suseconds_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __suseconds64_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfInt __daddr_t = Constants$root.C_INT$LAYOUT; - public static OfInt __key_t = Constants$root.C_INT$LAYOUT; - public static OfInt __clockid_t = Constants$root.C_INT$LAYOUT; - public static OfAddress __timer_t = Constants$root.C_POINTER$LAYOUT; - public static OfLong __blksize_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __blkcnt_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __blkcnt64_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __fsword_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __ssize_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __syscall_slong_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __loff_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfAddress __caddr_t = Constants$root.C_POINTER$LAYOUT; - public static OfLong __intptr_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfInt __sig_atomic_t = Constants$root.C_INT$LAYOUT; - public static OfLong ssize_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong off_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfInt pid_t = Constants$root.C_INT$LAYOUT; - public static OfLong intptr_t = Constants$root.C_LONG_LONG$LAYOUT; - public static MethodHandle access$MH() { - return RuntimeHelper.requireNonNull(constants$0.access$MH,"access"); - } - public static int access ( Addressable __name, int __type) { - var mh$ = access$MH(); - try { - return (int)mh$.invokeExact(__name, __type); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle faccessat$MH() { - return RuntimeHelper.requireNonNull(constants$0.faccessat$MH,"faccessat"); - } - public static int faccessat ( int __fd, Addressable __file, int __type, int __flag) { - var mh$ = faccessat$MH(); - try { - return (int)mh$.invokeExact(__fd, __file, __type, __flag); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle lseek$MH() { - return RuntimeHelper.requireNonNull(constants$0.lseek$MH,"lseek"); - } - public static long lseek ( int __fd, long __offset, int __whence) { - var mh$ = lseek$MH(); - try { - return (long)mh$.invokeExact(__fd, __offset, __whence); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } public static MethodHandle close$MH() { return RuntimeHelper.requireNonNull(constants$0.close$MH,"close"); } @@ -368,2347 +27,6 @@ public static int close ( int __fd) { throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle closefrom$MH() { - return RuntimeHelper.requireNonNull(constants$0.closefrom$MH,"closefrom"); - } - public static void closefrom ( int __lowfd) { - var mh$ = closefrom$MH(); - try { - mh$.invokeExact(__lowfd); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle read$MH() { - return RuntimeHelper.requireNonNull(constants$0.read$MH,"read"); - } - public static long read ( int __fd, Addressable __buf, long __nbytes) { - var mh$ = read$MH(); - try { - return (long)mh$.invokeExact(__fd, __buf, __nbytes); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle write$MH() { - return RuntimeHelper.requireNonNull(constants$1.write$MH,"write"); - } - public static long write ( int __fd, Addressable __buf, long __n) { - var mh$ = write$MH(); - try { - return (long)mh$.invokeExact(__fd, __buf, __n); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle pread$MH() { - return RuntimeHelper.requireNonNull(constants$1.pread$MH,"pread"); - } - public static long pread ( int __fd, Addressable __buf, long __nbytes, long __offset) { - var mh$ = pread$MH(); - try { - return (long)mh$.invokeExact(__fd, __buf, __nbytes, __offset); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle pwrite$MH() { - return RuntimeHelper.requireNonNull(constants$1.pwrite$MH,"pwrite"); - } - public static long pwrite ( int __fd, Addressable __buf, long __n, long __offset) { - var mh$ = pwrite$MH(); - try { - return (long)mh$.invokeExact(__fd, __buf, __n, __offset); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle pipe$MH() { - return RuntimeHelper.requireNonNull(constants$1.pipe$MH,"pipe"); - } - public static int pipe ( Addressable __pipedes) { - var mh$ = pipe$MH(); - try { - return (int)mh$.invokeExact(__pipedes); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle alarm$MH() { - return RuntimeHelper.requireNonNull(constants$1.alarm$MH,"alarm"); - } - public static int alarm ( int __seconds) { - var mh$ = alarm$MH(); - try { - return (int)mh$.invokeExact(__seconds); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle sleep$MH() { - return RuntimeHelper.requireNonNull(constants$1.sleep$MH,"sleep"); - } - public static int sleep ( int __seconds) { - var mh$ = sleep$MH(); - try { - return (int)mh$.invokeExact(__seconds); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle ualarm$MH() { - return RuntimeHelper.requireNonNull(constants$2.ualarm$MH,"ualarm"); - } - public static int ualarm ( int __value, int __interval) { - var mh$ = ualarm$MH(); - try { - return (int)mh$.invokeExact(__value, __interval); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle usleep$MH() { - return RuntimeHelper.requireNonNull(constants$2.usleep$MH,"usleep"); - } - public static int usleep ( int __useconds) { - var mh$ = usleep$MH(); - try { - return (int)mh$.invokeExact(__useconds); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle pause$MH() { - return RuntimeHelper.requireNonNull(constants$2.pause$MH,"pause"); - } - public static int pause () { - var mh$ = pause$MH(); - try { - return (int)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle chown$MH() { - return RuntimeHelper.requireNonNull(constants$2.chown$MH,"chown"); - } - public static int chown ( Addressable __file, int __owner, int __group) { - var mh$ = chown$MH(); - try { - return (int)mh$.invokeExact(__file, __owner, __group); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle fchown$MH() { - return RuntimeHelper.requireNonNull(constants$2.fchown$MH,"fchown"); - } - public static int fchown ( int __fd, int __owner, int __group) { - var mh$ = fchown$MH(); - try { - return (int)mh$.invokeExact(__fd, __owner, __group); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle lchown$MH() { - return RuntimeHelper.requireNonNull(constants$2.lchown$MH,"lchown"); - } - public static int lchown ( Addressable __file, int __owner, int __group) { - var mh$ = lchown$MH(); - try { - return (int)mh$.invokeExact(__file, __owner, __group); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle fchownat$MH() { - return RuntimeHelper.requireNonNull(constants$3.fchownat$MH,"fchownat"); - } - public static int fchownat ( int __fd, Addressable __file, int __owner, int __group, int __flag) { - var mh$ = fchownat$MH(); - try { - return (int)mh$.invokeExact(__fd, __file, __owner, __group, __flag); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle chdir$MH() { - return RuntimeHelper.requireNonNull(constants$3.chdir$MH,"chdir"); - } - public static int chdir ( Addressable __path) { - var mh$ = chdir$MH(); - try { - return (int)mh$.invokeExact(__path); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle fchdir$MH() { - return RuntimeHelper.requireNonNull(constants$3.fchdir$MH,"fchdir"); - } - public static int fchdir ( int __fd) { - var mh$ = fchdir$MH(); - try { - return (int)mh$.invokeExact(__fd); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getcwd$MH() { - return RuntimeHelper.requireNonNull(constants$3.getcwd$MH,"getcwd"); - } - public static MemoryAddress getcwd ( Addressable __buf, long __size) { - var mh$ = getcwd$MH(); - try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(__buf, __size); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getwd$MH() { - return RuntimeHelper.requireNonNull(constants$3.getwd$MH,"getwd"); - } - public static MemoryAddress getwd ( Addressable __buf) { - var mh$ = getwd$MH(); - try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(__buf); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle dup$MH() { - return RuntimeHelper.requireNonNull(constants$3.dup$MH,"dup"); - } - public static int dup ( int __fd) { - var mh$ = dup$MH(); - try { - return (int)mh$.invokeExact(__fd); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle dup2$MH() { - return RuntimeHelper.requireNonNull(constants$4.dup2$MH,"dup2"); - } - public static int dup2 ( int __fd, int __fd2) { - var mh$ = dup2$MH(); - try { - return (int)mh$.invokeExact(__fd, __fd2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MemoryLayout __environ$LAYOUT() { - return constants$4.__environ$LAYOUT; - } - public static VarHandle __environ$VH() { - return constants$4.__environ$VH; - } - public static MemorySegment __environ$SEGMENT() { - return RuntimeHelper.requireNonNull(constants$4.__environ$SEGMENT,"__environ"); - } - public static MemoryAddress __environ$get() { - return (java.lang.foreign.MemoryAddress) constants$4.__environ$VH.get(RuntimeHelper.requireNonNull(constants$4.__environ$SEGMENT, "__environ")); - } - public static void __environ$set( MemoryAddress x) { - constants$4.__environ$VH.set(RuntimeHelper.requireNonNull(constants$4.__environ$SEGMENT, "__environ"), x); - } - public static MethodHandle execve$MH() { - return RuntimeHelper.requireNonNull(constants$4.execve$MH,"execve"); - } - public static int execve ( Addressable __path, Addressable __argv, Addressable __envp) { - var mh$ = execve$MH(); - try { - return (int)mh$.invokeExact(__path, __argv, __envp); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle fexecve$MH() { - return RuntimeHelper.requireNonNull(constants$4.fexecve$MH,"fexecve"); - } - public static int fexecve ( int __fd, Addressable __argv, Addressable __envp) { - var mh$ = fexecve$MH(); - try { - return (int)mh$.invokeExact(__fd, __argv, __envp); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle execv$MH() { - return RuntimeHelper.requireNonNull(constants$4.execv$MH,"execv"); - } - public static int execv ( Addressable __path, Addressable __argv) { - var mh$ = execv$MH(); - try { - return (int)mh$.invokeExact(__path, __argv); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle execle$MH() { - return RuntimeHelper.requireNonNull(constants$4.execle$MH,"execle"); - } - public static int execle ( Addressable __path, Addressable __arg, Object... x2) { - var mh$ = execle$MH(); - try { - return (int)mh$.invokeExact(__path, __arg, x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle execl$MH() { - return RuntimeHelper.requireNonNull(constants$5.execl$MH,"execl"); - } - public static int execl ( Addressable __path, Addressable __arg, Object... x2) { - var mh$ = execl$MH(); - try { - return (int)mh$.invokeExact(__path, __arg, x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle execvp$MH() { - return RuntimeHelper.requireNonNull(constants$5.execvp$MH,"execvp"); - } - public static int execvp ( Addressable __file, Addressable __argv) { - var mh$ = execvp$MH(); - try { - return (int)mh$.invokeExact(__file, __argv); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle execlp$MH() { - return RuntimeHelper.requireNonNull(constants$5.execlp$MH,"execlp"); - } - public static int execlp ( Addressable __file, Addressable __arg, Object... x2) { - var mh$ = execlp$MH(); - try { - return (int)mh$.invokeExact(__file, __arg, x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle nice$MH() { - return RuntimeHelper.requireNonNull(constants$5.nice$MH,"nice"); - } - public static int nice ( int __inc) { - var mh$ = nice$MH(); - try { - return (int)mh$.invokeExact(__inc); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle _exit$MH() { - return RuntimeHelper.requireNonNull(constants$5._exit$MH,"_exit"); - } - public static void _exit ( int __status) { - var mh$ = _exit$MH(); - try { - mh$.invokeExact(__status); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static int _PC_LINK_MAX() { - return (int)0L; - } - public static int _PC_MAX_CANON() { - return (int)1L; - } - public static int _PC_MAX_INPUT() { - return (int)2L; - } - public static int _PC_NAME_MAX() { - return (int)3L; - } - public static int _PC_PATH_MAX() { - return (int)4L; - } - public static int _PC_PIPE_BUF() { - return (int)5L; - } - public static int _PC_CHOWN_RESTRICTED() { - return (int)6L; - } - public static int _PC_NO_TRUNC() { - return (int)7L; - } - public static int _PC_VDISABLE() { - return (int)8L; - } - public static int _PC_SYNC_IO() { - return (int)9L; - } - public static int _PC_ASYNC_IO() { - return (int)10L; - } - public static int _PC_PRIO_IO() { - return (int)11L; - } - public static int _PC_SOCK_MAXBUF() { - return (int)12L; - } - public static int _PC_FILESIZEBITS() { - return (int)13L; - } - public static int _PC_REC_INCR_XFER_SIZE() { - return (int)14L; - } - public static int _PC_REC_MAX_XFER_SIZE() { - return (int)15L; - } - public static int _PC_REC_MIN_XFER_SIZE() { - return (int)16L; - } - public static int _PC_REC_XFER_ALIGN() { - return (int)17L; - } - public static int _PC_ALLOC_SIZE_MIN() { - return (int)18L; - } - public static int _PC_SYMLINK_MAX() { - return (int)19L; - } - public static int _PC_2_SYMLINKS() { - return (int)20L; - } - public static int _SC_ARG_MAX() { - return (int)0L; - } - public static int _SC_CHILD_MAX() { - return (int)1L; - } - public static int _SC_CLK_TCK() { - return (int)2L; - } - public static int _SC_NGROUPS_MAX() { - return (int)3L; - } - public static int _SC_OPEN_MAX() { - return (int)4L; - } - public static int _SC_STREAM_MAX() { - return (int)5L; - } - public static int _SC_TZNAME_MAX() { - return (int)6L; - } - public static int _SC_JOB_CONTROL() { - return (int)7L; - } - public static int _SC_SAVED_IDS() { - return (int)8L; - } - public static int _SC_REALTIME_SIGNALS() { - return (int)9L; - } - public static int _SC_PRIORITY_SCHEDULING() { - return (int)10L; - } - public static int _SC_TIMERS() { - return (int)11L; - } - public static int _SC_ASYNCHRONOUS_IO() { - return (int)12L; - } - public static int _SC_PRIORITIZED_IO() { - return (int)13L; - } - public static int _SC_SYNCHRONIZED_IO() { - return (int)14L; - } - public static int _SC_FSYNC() { - return (int)15L; - } - public static int _SC_MAPPED_FILES() { - return (int)16L; - } - public static int _SC_MEMLOCK() { - return (int)17L; - } - public static int _SC_MEMLOCK_RANGE() { - return (int)18L; - } - public static int _SC_MEMORY_PROTECTION() { - return (int)19L; - } - public static int _SC_MESSAGE_PASSING() { - return (int)20L; - } - public static int _SC_SEMAPHORES() { - return (int)21L; - } - public static int _SC_SHARED_MEMORY_OBJECTS() { - return (int)22L; - } - public static int _SC_AIO_LISTIO_MAX() { - return (int)23L; - } - public static int _SC_AIO_MAX() { - return (int)24L; - } - public static int _SC_AIO_PRIO_DELTA_MAX() { - return (int)25L; - } - public static int _SC_DELAYTIMER_MAX() { - return (int)26L; - } - public static int _SC_MQ_OPEN_MAX() { - return (int)27L; - } - public static int _SC_MQ_PRIO_MAX() { - return (int)28L; - } - public static int _SC_VERSION() { - return (int)29L; - } - public static int _SC_PAGESIZE() { - return (int)30L; - } - public static int _SC_RTSIG_MAX() { - return (int)31L; - } - public static int _SC_SEM_NSEMS_MAX() { - return (int)32L; - } - public static int _SC_SEM_VALUE_MAX() { - return (int)33L; - } - public static int _SC_SIGQUEUE_MAX() { - return (int)34L; - } - public static int _SC_TIMER_MAX() { - return (int)35L; - } - public static int _SC_BC_BASE_MAX() { - return (int)36L; - } - public static int _SC_BC_DIM_MAX() { - return (int)37L; - } - public static int _SC_BC_SCALE_MAX() { - return (int)38L; - } - public static int _SC_BC_STRING_MAX() { - return (int)39L; - } - public static int _SC_COLL_WEIGHTS_MAX() { - return (int)40L; - } - public static int _SC_EQUIV_CLASS_MAX() { - return (int)41L; - } - public static int _SC_EXPR_NEST_MAX() { - return (int)42L; - } - public static int _SC_LINE_MAX() { - return (int)43L; - } - public static int _SC_RE_DUP_MAX() { - return (int)44L; - } - public static int _SC_CHARCLASS_NAME_MAX() { - return (int)45L; - } - public static int _SC_2_VERSION() { - return (int)46L; - } - public static int _SC_2_C_BIND() { - return (int)47L; - } - public static int _SC_2_C_DEV() { - return (int)48L; - } - public static int _SC_2_FORT_DEV() { - return (int)49L; - } - public static int _SC_2_FORT_RUN() { - return (int)50L; - } - public static int _SC_2_SW_DEV() { - return (int)51L; - } - public static int _SC_2_LOCALEDEF() { - return (int)52L; - } - public static int _SC_PII() { - return (int)53L; - } - public static int _SC_PII_XTI() { - return (int)54L; - } - public static int _SC_PII_SOCKET() { - return (int)55L; - } - public static int _SC_PII_INTERNET() { - return (int)56L; - } - public static int _SC_PII_OSI() { - return (int)57L; - } - public static int _SC_POLL() { - return (int)58L; - } - public static int _SC_SELECT() { - return (int)59L; - } - public static int _SC_UIO_MAXIOV() { - return (int)60L; - } - public static int _SC_IOV_MAX() { - return (int)60L; - } - public static int _SC_PII_INTERNET_STREAM() { - return (int)61L; - } - public static int _SC_PII_INTERNET_DGRAM() { - return (int)62L; - } - public static int _SC_PII_OSI_COTS() { - return (int)63L; - } - public static int _SC_PII_OSI_CLTS() { - return (int)64L; - } - public static int _SC_PII_OSI_M() { - return (int)65L; - } - public static int _SC_T_IOV_MAX() { - return (int)66L; - } - public static int _SC_THREADS() { - return (int)67L; - } - public static int _SC_THREAD_SAFE_FUNCTIONS() { - return (int)68L; - } - public static int _SC_GETGR_R_SIZE_MAX() { - return (int)69L; - } - public static int _SC_GETPW_R_SIZE_MAX() { - return (int)70L; - } - public static int _SC_LOGIN_NAME_MAX() { - return (int)71L; - } - public static int _SC_TTY_NAME_MAX() { - return (int)72L; - } - public static int _SC_THREAD_DESTRUCTOR_ITERATIONS() { - return (int)73L; - } - public static int _SC_THREAD_KEYS_MAX() { - return (int)74L; - } - public static int _SC_THREAD_STACK_MIN() { - return (int)75L; - } - public static int _SC_THREAD_THREADS_MAX() { - return (int)76L; - } - public static int _SC_THREAD_ATTR_STACKADDR() { - return (int)77L; - } - public static int _SC_THREAD_ATTR_STACKSIZE() { - return (int)78L; - } - public static int _SC_THREAD_PRIORITY_SCHEDULING() { - return (int)79L; - } - public static int _SC_THREAD_PRIO_INHERIT() { - return (int)80L; - } - public static int _SC_THREAD_PRIO_PROTECT() { - return (int)81L; - } - public static int _SC_THREAD_PROCESS_SHARED() { - return (int)82L; - } - public static int _SC_NPROCESSORS_CONF() { - return (int)83L; - } - public static int _SC_NPROCESSORS_ONLN() { - return (int)84L; - } - public static int _SC_PHYS_PAGES() { - return (int)85L; - } - public static int _SC_AVPHYS_PAGES() { - return (int)86L; - } - public static int _SC_ATEXIT_MAX() { - return (int)87L; - } - public static int _SC_PASS_MAX() { - return (int)88L; - } - public static int _SC_XOPEN_VERSION() { - return (int)89L; - } - public static int _SC_XOPEN_XCU_VERSION() { - return (int)90L; - } - public static int _SC_XOPEN_UNIX() { - return (int)91L; - } - public static int _SC_XOPEN_CRYPT() { - return (int)92L; - } - public static int _SC_XOPEN_ENH_I18N() { - return (int)93L; - } - public static int _SC_XOPEN_SHM() { - return (int)94L; - } - public static int _SC_2_CHAR_TERM() { - return (int)95L; - } - public static int _SC_2_C_VERSION() { - return (int)96L; - } - public static int _SC_2_UPE() { - return (int)97L; - } - public static int _SC_XOPEN_XPG2() { - return (int)98L; - } - public static int _SC_XOPEN_XPG3() { - return (int)99L; - } - public static int _SC_XOPEN_XPG4() { - return (int)100L; - } - public static int _SC_CHAR_BIT() { - return (int)101L; - } - public static int _SC_CHAR_MAX() { - return (int)102L; - } - public static int _SC_CHAR_MIN() { - return (int)103L; - } - public static int _SC_INT_MAX() { - return (int)104L; - } - public static int _SC_INT_MIN() { - return (int)105L; - } - public static int _SC_LONG_BIT() { - return (int)106L; - } - public static int _SC_WORD_BIT() { - return (int)107L; - } - public static int _SC_MB_LEN_MAX() { - return (int)108L; - } - public static int _SC_NZERO() { - return (int)109L; - } - public static int _SC_SSIZE_MAX() { - return (int)110L; - } - public static int _SC_SCHAR_MAX() { - return (int)111L; - } - public static int _SC_SCHAR_MIN() { - return (int)112L; - } - public static int _SC_SHRT_MAX() { - return (int)113L; - } - public static int _SC_SHRT_MIN() { - return (int)114L; - } - public static int _SC_UCHAR_MAX() { - return (int)115L; - } - public static int _SC_UINT_MAX() { - return (int)116L; - } - public static int _SC_ULONG_MAX() { - return (int)117L; - } - public static int _SC_USHRT_MAX() { - return (int)118L; - } - public static int _SC_NL_ARGMAX() { - return (int)119L; - } - public static int _SC_NL_LANGMAX() { - return (int)120L; - } - public static int _SC_NL_MSGMAX() { - return (int)121L; - } - public static int _SC_NL_NMAX() { - return (int)122L; - } - public static int _SC_NL_SETMAX() { - return (int)123L; - } - public static int _SC_NL_TEXTMAX() { - return (int)124L; - } - public static int _SC_XBS5_ILP32_OFF32() { - return (int)125L; - } - public static int _SC_XBS5_ILP32_OFFBIG() { - return (int)126L; - } - public static int _SC_XBS5_LP64_OFF64() { - return (int)127L; - } - public static int _SC_XBS5_LPBIG_OFFBIG() { - return (int)128L; - } - public static int _SC_XOPEN_LEGACY() { - return (int)129L; - } - public static int _SC_XOPEN_REALTIME() { - return (int)130L; - } - public static int _SC_XOPEN_REALTIME_THREADS() { - return (int)131L; - } - public static int _SC_ADVISORY_INFO() { - return (int)132L; - } - public static int _SC_BARRIERS() { - return (int)133L; - } - public static int _SC_BASE() { - return (int)134L; - } - public static int _SC_C_LANG_SUPPORT() { - return (int)135L; - } - public static int _SC_C_LANG_SUPPORT_R() { - return (int)136L; - } - public static int _SC_CLOCK_SELECTION() { - return (int)137L; - } - public static int _SC_CPUTIME() { - return (int)138L; - } - public static int _SC_THREAD_CPUTIME() { - return (int)139L; - } - public static int _SC_DEVICE_IO() { - return (int)140L; - } - public static int _SC_DEVICE_SPECIFIC() { - return (int)141L; - } - public static int _SC_DEVICE_SPECIFIC_R() { - return (int)142L; - } - public static int _SC_FD_MGMT() { - return (int)143L; - } - public static int _SC_FIFO() { - return (int)144L; - } - public static int _SC_PIPE() { - return (int)145L; - } - public static int _SC_FILE_ATTRIBUTES() { - return (int)146L; - } - public static int _SC_FILE_LOCKING() { - return (int)147L; - } - public static int _SC_FILE_SYSTEM() { - return (int)148L; - } - public static int _SC_MONOTONIC_CLOCK() { - return (int)149L; - } - public static int _SC_MULTI_PROCESS() { - return (int)150L; - } - public static int _SC_SINGLE_PROCESS() { - return (int)151L; - } - public static int _SC_NETWORKING() { - return (int)152L; - } - public static int _SC_READER_WRITER_LOCKS() { - return (int)153L; - } - public static int _SC_SPIN_LOCKS() { - return (int)154L; - } - public static int _SC_REGEXP() { - return (int)155L; - } - public static int _SC_REGEX_VERSION() { - return (int)156L; - } - public static int _SC_SHELL() { - return (int)157L; - } - public static int _SC_SIGNALS() { - return (int)158L; - } - public static int _SC_SPAWN() { - return (int)159L; - } - public static int _SC_SPORADIC_SERVER() { - return (int)160L; - } - public static int _SC_THREAD_SPORADIC_SERVER() { - return (int)161L; - } - public static int _SC_SYSTEM_DATABASE() { - return (int)162L; - } - public static int _SC_SYSTEM_DATABASE_R() { - return (int)163L; - } - public static int _SC_TIMEOUTS() { - return (int)164L; - } - public static int _SC_TYPED_MEMORY_OBJECTS() { - return (int)165L; - } - public static int _SC_USER_GROUPS() { - return (int)166L; - } - public static int _SC_USER_GROUPS_R() { - return (int)167L; - } - public static int _SC_2_PBS() { - return (int)168L; - } - public static int _SC_2_PBS_ACCOUNTING() { - return (int)169L; - } - public static int _SC_2_PBS_LOCATE() { - return (int)170L; - } - public static int _SC_2_PBS_MESSAGE() { - return (int)171L; - } - public static int _SC_2_PBS_TRACK() { - return (int)172L; - } - public static int _SC_SYMLOOP_MAX() { - return (int)173L; - } - public static int _SC_STREAMS() { - return (int)174L; - } - public static int _SC_2_PBS_CHECKPOINT() { - return (int)175L; - } - public static int _SC_V6_ILP32_OFF32() { - return (int)176L; - } - public static int _SC_V6_ILP32_OFFBIG() { - return (int)177L; - } - public static int _SC_V6_LP64_OFF64() { - return (int)178L; - } - public static int _SC_V6_LPBIG_OFFBIG() { - return (int)179L; - } - public static int _SC_HOST_NAME_MAX() { - return (int)180L; - } - public static int _SC_TRACE() { - return (int)181L; - } - public static int _SC_TRACE_EVENT_FILTER() { - return (int)182L; - } - public static int _SC_TRACE_INHERIT() { - return (int)183L; - } - public static int _SC_TRACE_LOG() { - return (int)184L; - } - public static int _SC_LEVEL1_ICACHE_SIZE() { - return (int)185L; - } - public static int _SC_LEVEL1_ICACHE_ASSOC() { - return (int)186L; - } - public static int _SC_LEVEL1_ICACHE_LINESIZE() { - return (int)187L; - } - public static int _SC_LEVEL1_DCACHE_SIZE() { - return (int)188L; - } - public static int _SC_LEVEL1_DCACHE_ASSOC() { - return (int)189L; - } - public static int _SC_LEVEL1_DCACHE_LINESIZE() { - return (int)190L; - } - public static int _SC_LEVEL2_CACHE_SIZE() { - return (int)191L; - } - public static int _SC_LEVEL2_CACHE_ASSOC() { - return (int)192L; - } - public static int _SC_LEVEL2_CACHE_LINESIZE() { - return (int)193L; - } - public static int _SC_LEVEL3_CACHE_SIZE() { - return (int)194L; - } - public static int _SC_LEVEL3_CACHE_ASSOC() { - return (int)195L; - } - public static int _SC_LEVEL3_CACHE_LINESIZE() { - return (int)196L; - } - public static int _SC_LEVEL4_CACHE_SIZE() { - return (int)197L; - } - public static int _SC_LEVEL4_CACHE_ASSOC() { - return (int)198L; - } - public static int _SC_LEVEL4_CACHE_LINESIZE() { - return (int)199L; - } - public static int _SC_IPV6() { - return (int)235L; - } - public static int _SC_RAW_SOCKETS() { - return (int)236L; - } - public static int _SC_V7_ILP32_OFF32() { - return (int)237L; - } - public static int _SC_V7_ILP32_OFFBIG() { - return (int)238L; - } - public static int _SC_V7_LP64_OFF64() { - return (int)239L; - } - public static int _SC_V7_LPBIG_OFFBIG() { - return (int)240L; - } - public static int _SC_SS_REPL_MAX() { - return (int)241L; - } - public static int _SC_TRACE_EVENT_NAME_MAX() { - return (int)242L; - } - public static int _SC_TRACE_NAME_MAX() { - return (int)243L; - } - public static int _SC_TRACE_SYS_MAX() { - return (int)244L; - } - public static int _SC_TRACE_USER_EVENT_MAX() { - return (int)245L; - } - public static int _SC_XOPEN_STREAMS() { - return (int)246L; - } - public static int _SC_THREAD_ROBUST_PRIO_INHERIT() { - return (int)247L; - } - public static int _SC_THREAD_ROBUST_PRIO_PROTECT() { - return (int)248L; - } - public static int _SC_MINSIGSTKSZ() { - return (int)249L; - } - public static int _SC_SIGSTKSZ() { - return (int)250L; - } - public static int _CS_PATH() { - return (int)0L; - } - public static int _CS_V6_WIDTH_RESTRICTED_ENVS() { - return (int)1L; - } - public static int _CS_GNU_LIBC_VERSION() { - return (int)2L; - } - public static int _CS_GNU_LIBPTHREAD_VERSION() { - return (int)3L; - } - public static int _CS_V5_WIDTH_RESTRICTED_ENVS() { - return (int)4L; - } - public static int _CS_V7_WIDTH_RESTRICTED_ENVS() { - return (int)5L; - } - public static int _CS_LFS_CFLAGS() { - return (int)1000L; - } - public static int _CS_LFS_LDFLAGS() { - return (int)1001L; - } - public static int _CS_LFS_LIBS() { - return (int)1002L; - } - public static int _CS_LFS_LINTFLAGS() { - return (int)1003L; - } - public static int _CS_LFS64_CFLAGS() { - return (int)1004L; - } - public static int _CS_LFS64_LDFLAGS() { - return (int)1005L; - } - public static int _CS_LFS64_LIBS() { - return (int)1006L; - } - public static int _CS_LFS64_LINTFLAGS() { - return (int)1007L; - } - public static int _CS_XBS5_ILP32_OFF32_CFLAGS() { - return (int)1100L; - } - public static int _CS_XBS5_ILP32_OFF32_LDFLAGS() { - return (int)1101L; - } - public static int _CS_XBS5_ILP32_OFF32_LIBS() { - return (int)1102L; - } - public static int _CS_XBS5_ILP32_OFF32_LINTFLAGS() { - return (int)1103L; - } - public static int _CS_XBS5_ILP32_OFFBIG_CFLAGS() { - return (int)1104L; - } - public static int _CS_XBS5_ILP32_OFFBIG_LDFLAGS() { - return (int)1105L; - } - public static int _CS_XBS5_ILP32_OFFBIG_LIBS() { - return (int)1106L; - } - public static int _CS_XBS5_ILP32_OFFBIG_LINTFLAGS() { - return (int)1107L; - } - public static int _CS_XBS5_LP64_OFF64_CFLAGS() { - return (int)1108L; - } - public static int _CS_XBS5_LP64_OFF64_LDFLAGS() { - return (int)1109L; - } - public static int _CS_XBS5_LP64_OFF64_LIBS() { - return (int)1110L; - } - public static int _CS_XBS5_LP64_OFF64_LINTFLAGS() { - return (int)1111L; - } - public static int _CS_XBS5_LPBIG_OFFBIG_CFLAGS() { - return (int)1112L; - } - public static int _CS_XBS5_LPBIG_OFFBIG_LDFLAGS() { - return (int)1113L; - } - public static int _CS_XBS5_LPBIG_OFFBIG_LIBS() { - return (int)1114L; - } - public static int _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS() { - return (int)1115L; - } - public static int _CS_POSIX_V6_ILP32_OFF32_CFLAGS() { - return (int)1116L; - } - public static int _CS_POSIX_V6_ILP32_OFF32_LDFLAGS() { - return (int)1117L; - } - public static int _CS_POSIX_V6_ILP32_OFF32_LIBS() { - return (int)1118L; - } - public static int _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS() { - return (int)1119L; - } - public static int _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS() { - return (int)1120L; - } - public static int _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS() { - return (int)1121L; - } - public static int _CS_POSIX_V6_ILP32_OFFBIG_LIBS() { - return (int)1122L; - } - public static int _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS() { - return (int)1123L; - } - public static int _CS_POSIX_V6_LP64_OFF64_CFLAGS() { - return (int)1124L; - } - public static int _CS_POSIX_V6_LP64_OFF64_LDFLAGS() { - return (int)1125L; - } - public static int _CS_POSIX_V6_LP64_OFF64_LIBS() { - return (int)1126L; - } - public static int _CS_POSIX_V6_LP64_OFF64_LINTFLAGS() { - return (int)1127L; - } - public static int _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS() { - return (int)1128L; - } - public static int _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS() { - return (int)1129L; - } - public static int _CS_POSIX_V6_LPBIG_OFFBIG_LIBS() { - return (int)1130L; - } - public static int _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS() { - return (int)1131L; - } - public static int _CS_POSIX_V7_ILP32_OFF32_CFLAGS() { - return (int)1132L; - } - public static int _CS_POSIX_V7_ILP32_OFF32_LDFLAGS() { - return (int)1133L; - } - public static int _CS_POSIX_V7_ILP32_OFF32_LIBS() { - return (int)1134L; - } - public static int _CS_POSIX_V7_ILP32_OFF32_LINTFLAGS() { - return (int)1135L; - } - public static int _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS() { - return (int)1136L; - } - public static int _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS() { - return (int)1137L; - } - public static int _CS_POSIX_V7_ILP32_OFFBIG_LIBS() { - return (int)1138L; - } - public static int _CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS() { - return (int)1139L; - } - public static int _CS_POSIX_V7_LP64_OFF64_CFLAGS() { - return (int)1140L; - } - public static int _CS_POSIX_V7_LP64_OFF64_LDFLAGS() { - return (int)1141L; - } - public static int _CS_POSIX_V7_LP64_OFF64_LIBS() { - return (int)1142L; - } - public static int _CS_POSIX_V7_LP64_OFF64_LINTFLAGS() { - return (int)1143L; - } - public static int _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS() { - return (int)1144L; - } - public static int _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS() { - return (int)1145L; - } - public static int _CS_POSIX_V7_LPBIG_OFFBIG_LIBS() { - return (int)1146L; - } - public static int _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS() { - return (int)1147L; - } - public static int _CS_V6_ENV() { - return (int)1148L; - } - public static int _CS_V7_ENV() { - return (int)1149L; - } - public static MethodHandle pathconf$MH() { - return RuntimeHelper.requireNonNull(constants$5.pathconf$MH,"pathconf"); - } - public static long pathconf ( Addressable __path, int __name) { - var mh$ = pathconf$MH(); - try { - return (long)mh$.invokeExact(__path, __name); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle fpathconf$MH() { - return RuntimeHelper.requireNonNull(constants$6.fpathconf$MH,"fpathconf"); - } - public static long fpathconf ( int __fd, int __name) { - var mh$ = fpathconf$MH(); - try { - return (long)mh$.invokeExact(__fd, __name); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle sysconf$MH() { - return RuntimeHelper.requireNonNull(constants$6.sysconf$MH,"sysconf"); - } - public static long sysconf ( int __name) { - var mh$ = sysconf$MH(); - try { - return (long)mh$.invokeExact(__name); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle confstr$MH() { - return RuntimeHelper.requireNonNull(constants$6.confstr$MH,"confstr"); - } - public static long confstr ( int __name, Addressable __buf, long __len) { - var mh$ = confstr$MH(); - try { - return (long)mh$.invokeExact(__name, __buf, __len); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getpid$MH() { - return RuntimeHelper.requireNonNull(constants$6.getpid$MH,"getpid"); - } - public static int getpid () { - var mh$ = getpid$MH(); - try { - return (int)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getppid$MH() { - return RuntimeHelper.requireNonNull(constants$6.getppid$MH,"getppid"); - } - public static int getppid () { - var mh$ = getppid$MH(); - try { - return (int)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getpgrp$MH() { - return RuntimeHelper.requireNonNull(constants$6.getpgrp$MH,"getpgrp"); - } - public static int getpgrp () { - var mh$ = getpgrp$MH(); - try { - return (int)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle __getpgid$MH() { - return RuntimeHelper.requireNonNull(constants$7.__getpgid$MH,"__getpgid"); - } - public static int __getpgid ( int __pid) { - var mh$ = __getpgid$MH(); - try { - return (int)mh$.invokeExact(__pid); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getpgid$MH() { - return RuntimeHelper.requireNonNull(constants$7.getpgid$MH,"getpgid"); - } - public static int getpgid ( int __pid) { - var mh$ = getpgid$MH(); - try { - return (int)mh$.invokeExact(__pid); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle setpgid$MH() { - return RuntimeHelper.requireNonNull(constants$7.setpgid$MH,"setpgid"); - } - public static int setpgid ( int __pid, int __pgid) { - var mh$ = setpgid$MH(); - try { - return (int)mh$.invokeExact(__pid, __pgid); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle setpgrp$MH() { - return RuntimeHelper.requireNonNull(constants$7.setpgrp$MH,"setpgrp"); - } - public static int setpgrp () { - var mh$ = setpgrp$MH(); - try { - return (int)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle setsid$MH() { - return RuntimeHelper.requireNonNull(constants$7.setsid$MH,"setsid"); - } - public static int setsid () { - var mh$ = setsid$MH(); - try { - return (int)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getsid$MH() { - return RuntimeHelper.requireNonNull(constants$7.getsid$MH,"getsid"); - } - public static int getsid ( int __pid) { - var mh$ = getsid$MH(); - try { - return (int)mh$.invokeExact(__pid); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getuid$MH() { - return RuntimeHelper.requireNonNull(constants$8.getuid$MH,"getuid"); - } - public static int getuid () { - var mh$ = getuid$MH(); - try { - return (int)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle geteuid$MH() { - return RuntimeHelper.requireNonNull(constants$8.geteuid$MH,"geteuid"); - } - public static int geteuid () { - var mh$ = geteuid$MH(); - try { - return (int)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getgid$MH() { - return RuntimeHelper.requireNonNull(constants$8.getgid$MH,"getgid"); - } - public static int getgid () { - var mh$ = getgid$MH(); - try { - return (int)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getegid$MH() { - return RuntimeHelper.requireNonNull(constants$8.getegid$MH,"getegid"); - } - public static int getegid () { - var mh$ = getegid$MH(); - try { - return (int)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getgroups$MH() { - return RuntimeHelper.requireNonNull(constants$8.getgroups$MH,"getgroups"); - } - public static int getgroups ( int __size, Addressable __list) { - var mh$ = getgroups$MH(); - try { - return (int)mh$.invokeExact(__size, __list); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle setuid$MH() { - return RuntimeHelper.requireNonNull(constants$8.setuid$MH,"setuid"); - } - public static int setuid ( int __uid) { - var mh$ = setuid$MH(); - try { - return (int)mh$.invokeExact(__uid); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle setreuid$MH() { - return RuntimeHelper.requireNonNull(constants$9.setreuid$MH,"setreuid"); - } - public static int setreuid ( int __ruid, int __euid) { - var mh$ = setreuid$MH(); - try { - return (int)mh$.invokeExact(__ruid, __euid); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle seteuid$MH() { - return RuntimeHelper.requireNonNull(constants$9.seteuid$MH,"seteuid"); - } - public static int seteuid ( int __uid) { - var mh$ = seteuid$MH(); - try { - return (int)mh$.invokeExact(__uid); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle setgid$MH() { - return RuntimeHelper.requireNonNull(constants$9.setgid$MH,"setgid"); - } - public static int setgid ( int __gid) { - var mh$ = setgid$MH(); - try { - return (int)mh$.invokeExact(__gid); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle setregid$MH() { - return RuntimeHelper.requireNonNull(constants$9.setregid$MH,"setregid"); - } - public static int setregid ( int __rgid, int __egid) { - var mh$ = setregid$MH(); - try { - return (int)mh$.invokeExact(__rgid, __egid); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle setegid$MH() { - return RuntimeHelper.requireNonNull(constants$9.setegid$MH,"setegid"); - } - public static int setegid ( int __gid) { - var mh$ = setegid$MH(); - try { - return (int)mh$.invokeExact(__gid); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle fork$MH() { - return RuntimeHelper.requireNonNull(constants$9.fork$MH,"fork"); - } - public static int fork () { - var mh$ = fork$MH(); - try { - return (int)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle vfork$MH() { - return RuntimeHelper.requireNonNull(constants$10.vfork$MH,"vfork"); - } - public static int vfork () { - var mh$ = vfork$MH(); - try { - return (int)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle ttyname$MH() { - return RuntimeHelper.requireNonNull(constants$10.ttyname$MH,"ttyname"); - } - public static MemoryAddress ttyname ( int __fd) { - var mh$ = ttyname$MH(); - try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(__fd); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle ttyname_r$MH() { - return RuntimeHelper.requireNonNull(constants$10.ttyname_r$MH,"ttyname_r"); - } - public static int ttyname_r ( int __fd, Addressable __buf, long __buflen) { - var mh$ = ttyname_r$MH(); - try { - return (int)mh$.invokeExact(__fd, __buf, __buflen); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle isatty$MH() { - return RuntimeHelper.requireNonNull(constants$10.isatty$MH,"isatty"); - } - public static int isatty ( int __fd) { - var mh$ = isatty$MH(); - try { - return (int)mh$.invokeExact(__fd); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle ttyslot$MH() { - return RuntimeHelper.requireNonNull(constants$10.ttyslot$MH,"ttyslot"); - } - public static int ttyslot () { - var mh$ = ttyslot$MH(); - try { - return (int)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle link$MH() { - return RuntimeHelper.requireNonNull(constants$10.link$MH,"link"); - } - public static int link ( Addressable __from, Addressable __to) { - var mh$ = link$MH(); - try { - return (int)mh$.invokeExact(__from, __to); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle linkat$MH() { - return RuntimeHelper.requireNonNull(constants$11.linkat$MH,"linkat"); - } - public static int linkat ( int __fromfd, Addressable __from, int __tofd, Addressable __to, int __flags) { - var mh$ = linkat$MH(); - try { - return (int)mh$.invokeExact(__fromfd, __from, __tofd, __to, __flags); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle symlink$MH() { - return RuntimeHelper.requireNonNull(constants$11.symlink$MH,"symlink"); - } - public static int symlink ( Addressable __from, Addressable __to) { - var mh$ = symlink$MH(); - try { - return (int)mh$.invokeExact(__from, __to); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle readlink$MH() { - return RuntimeHelper.requireNonNull(constants$11.readlink$MH,"readlink"); - } - public static long readlink ( Addressable __path, Addressable __buf, long __len) { - var mh$ = readlink$MH(); - try { - return (long)mh$.invokeExact(__path, __buf, __len); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle symlinkat$MH() { - return RuntimeHelper.requireNonNull(constants$11.symlinkat$MH,"symlinkat"); - } - public static int symlinkat ( Addressable __from, int __tofd, Addressable __to) { - var mh$ = symlinkat$MH(); - try { - return (int)mh$.invokeExact(__from, __tofd, __to); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle readlinkat$MH() { - return RuntimeHelper.requireNonNull(constants$11.readlinkat$MH,"readlinkat"); - } - public static long readlinkat ( int __fd, Addressable __path, Addressable __buf, long __len) { - var mh$ = readlinkat$MH(); - try { - return (long)mh$.invokeExact(__fd, __path, __buf, __len); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle unlink$MH() { - return RuntimeHelper.requireNonNull(constants$11.unlink$MH,"unlink"); - } - public static int unlink ( Addressable __name) { - var mh$ = unlink$MH(); - try { - return (int)mh$.invokeExact(__name); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle unlinkat$MH() { - return RuntimeHelper.requireNonNull(constants$12.unlinkat$MH,"unlinkat"); - } - public static int unlinkat ( int __fd, Addressable __name, int __flag) { - var mh$ = unlinkat$MH(); - try { - return (int)mh$.invokeExact(__fd, __name, __flag); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle rmdir$MH() { - return RuntimeHelper.requireNonNull(constants$12.rmdir$MH,"rmdir"); - } - public static int rmdir ( Addressable __path) { - var mh$ = rmdir$MH(); - try { - return (int)mh$.invokeExact(__path); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle tcgetpgrp$MH() { - return RuntimeHelper.requireNonNull(constants$12.tcgetpgrp$MH,"tcgetpgrp"); - } - public static int tcgetpgrp ( int __fd) { - var mh$ = tcgetpgrp$MH(); - try { - return (int)mh$.invokeExact(__fd); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle tcsetpgrp$MH() { - return RuntimeHelper.requireNonNull(constants$12.tcsetpgrp$MH,"tcsetpgrp"); - } - public static int tcsetpgrp ( int __fd, int __pgrp_id) { - var mh$ = tcsetpgrp$MH(); - try { - return (int)mh$.invokeExact(__fd, __pgrp_id); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getlogin$MH() { - return RuntimeHelper.requireNonNull(constants$12.getlogin$MH,"getlogin"); - } - public static MemoryAddress getlogin () { - var mh$ = getlogin$MH(); - try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getlogin_r$MH() { - return RuntimeHelper.requireNonNull(constants$12.getlogin_r$MH,"getlogin_r"); - } - public static int getlogin_r ( Addressable __name, long __name_len) { - var mh$ = getlogin_r$MH(); - try { - return (int)mh$.invokeExact(__name, __name_len); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle setlogin$MH() { - return RuntimeHelper.requireNonNull(constants$13.setlogin$MH,"setlogin"); - } - public static int setlogin ( Addressable __name) { - var mh$ = setlogin$MH(); - try { - return (int)mh$.invokeExact(__name); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MemoryLayout optarg$LAYOUT() { - return constants$13.optarg$LAYOUT; - } - public static VarHandle optarg$VH() { - return constants$13.optarg$VH; - } - public static MemorySegment optarg$SEGMENT() { - return RuntimeHelper.requireNonNull(constants$13.optarg$SEGMENT,"optarg"); - } - public static MemoryAddress optarg$get() { - return (java.lang.foreign.MemoryAddress) constants$13.optarg$VH.get(RuntimeHelper.requireNonNull(constants$13.optarg$SEGMENT, "optarg")); - } - public static void optarg$set( MemoryAddress x) { - constants$13.optarg$VH.set(RuntimeHelper.requireNonNull(constants$13.optarg$SEGMENT, "optarg"), x); - } - public static MemoryLayout optind$LAYOUT() { - return constants$13.optind$LAYOUT; - } - public static VarHandle optind$VH() { - return constants$13.optind$VH; - } - public static MemorySegment optind$SEGMENT() { - return RuntimeHelper.requireNonNull(constants$13.optind$SEGMENT,"optind"); - } - public static int optind$get() { - return (int) constants$13.optind$VH.get(RuntimeHelper.requireNonNull(constants$13.optind$SEGMENT, "optind")); - } - public static void optind$set( int x) { - constants$13.optind$VH.set(RuntimeHelper.requireNonNull(constants$13.optind$SEGMENT, "optind"), x); - } - public static MemoryLayout opterr$LAYOUT() { - return constants$13.opterr$LAYOUT; - } - public static VarHandle opterr$VH() { - return constants$13.opterr$VH; - } - public static MemorySegment opterr$SEGMENT() { - return RuntimeHelper.requireNonNull(constants$13.opterr$SEGMENT,"opterr"); - } - public static int opterr$get() { - return (int) constants$13.opterr$VH.get(RuntimeHelper.requireNonNull(constants$13.opterr$SEGMENT, "opterr")); - } - public static void opterr$set( int x) { - constants$13.opterr$VH.set(RuntimeHelper.requireNonNull(constants$13.opterr$SEGMENT, "opterr"), x); - } - public static MemoryLayout optopt$LAYOUT() { - return constants$13.optopt$LAYOUT; - } - public static VarHandle optopt$VH() { - return constants$13.optopt$VH; - } - public static MemorySegment optopt$SEGMENT() { - return RuntimeHelper.requireNonNull(constants$13.optopt$SEGMENT,"optopt"); - } - public static int optopt$get() { - return (int) constants$13.optopt$VH.get(RuntimeHelper.requireNonNull(constants$13.optopt$SEGMENT, "optopt")); - } - public static void optopt$set( int x) { - constants$13.optopt$VH.set(RuntimeHelper.requireNonNull(constants$13.optopt$SEGMENT, "optopt"), x); - } - public static MethodHandle getopt$MH() { - return RuntimeHelper.requireNonNull(constants$13.getopt$MH,"getopt"); - } - public static int getopt ( int ___argc, Addressable ___argv, Addressable __shortopts) { - var mh$ = getopt$MH(); - try { - return (int)mh$.invokeExact(___argc, ___argv, __shortopts); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle gethostname$MH() { - return RuntimeHelper.requireNonNull(constants$14.gethostname$MH,"gethostname"); - } - public static int gethostname ( Addressable __name, long __len) { - var mh$ = gethostname$MH(); - try { - return (int)mh$.invokeExact(__name, __len); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle sethostname$MH() { - return RuntimeHelper.requireNonNull(constants$14.sethostname$MH,"sethostname"); - } - public static int sethostname ( Addressable __name, long __len) { - var mh$ = sethostname$MH(); - try { - return (int)mh$.invokeExact(__name, __len); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle sethostid$MH() { - return RuntimeHelper.requireNonNull(constants$14.sethostid$MH,"sethostid"); - } - public static int sethostid ( long __id) { - var mh$ = sethostid$MH(); - try { - return (int)mh$.invokeExact(__id); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getdomainname$MH() { - return RuntimeHelper.requireNonNull(constants$14.getdomainname$MH,"getdomainname"); - } - public static int getdomainname ( Addressable __name, long __len) { - var mh$ = getdomainname$MH(); - try { - return (int)mh$.invokeExact(__name, __len); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle setdomainname$MH() { - return RuntimeHelper.requireNonNull(constants$14.setdomainname$MH,"setdomainname"); - } - public static int setdomainname ( Addressable __name, long __len) { - var mh$ = setdomainname$MH(); - try { - return (int)mh$.invokeExact(__name, __len); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle vhangup$MH() { - return RuntimeHelper.requireNonNull(constants$14.vhangup$MH,"vhangup"); - } - public static int vhangup () { - var mh$ = vhangup$MH(); - try { - return (int)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle revoke$MH() { - return RuntimeHelper.requireNonNull(constants$15.revoke$MH,"revoke"); - } - public static int revoke ( Addressable __file) { - var mh$ = revoke$MH(); - try { - return (int)mh$.invokeExact(__file); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle profil$MH() { - return RuntimeHelper.requireNonNull(constants$15.profil$MH,"profil"); - } - public static int profil ( Addressable __sample_buffer, long __size, long __offset, int __scale) { - var mh$ = profil$MH(); - try { - return (int)mh$.invokeExact(__sample_buffer, __size, __offset, __scale); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle acct$MH() { - return RuntimeHelper.requireNonNull(constants$15.acct$MH,"acct"); - } - public static int acct ( Addressable __name) { - var mh$ = acct$MH(); - try { - return (int)mh$.invokeExact(__name); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getusershell$MH() { - return RuntimeHelper.requireNonNull(constants$15.getusershell$MH,"getusershell"); - } - public static MemoryAddress getusershell () { - var mh$ = getusershell$MH(); - try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle endusershell$MH() { - return RuntimeHelper.requireNonNull(constants$15.endusershell$MH,"endusershell"); - } - public static void endusershell () { - var mh$ = endusershell$MH(); - try { - mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle setusershell$MH() { - return RuntimeHelper.requireNonNull(constants$15.setusershell$MH,"setusershell"); - } - public static void setusershell () { - var mh$ = setusershell$MH(); - try { - mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle daemon$MH() { - return RuntimeHelper.requireNonNull(constants$16.daemon$MH,"daemon"); - } - public static int daemon ( int __nochdir, int __noclose) { - var mh$ = daemon$MH(); - try { - return (int)mh$.invokeExact(__nochdir, __noclose); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle chroot$MH() { - return RuntimeHelper.requireNonNull(constants$16.chroot$MH,"chroot"); - } - public static int chroot ( Addressable __path) { - var mh$ = chroot$MH(); - try { - return (int)mh$.invokeExact(__path); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getpass$MH() { - return RuntimeHelper.requireNonNull(constants$16.getpass$MH,"getpass"); - } - public static MemoryAddress getpass ( Addressable __prompt) { - var mh$ = getpass$MH(); - try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(__prompt); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle fsync$MH() { - return RuntimeHelper.requireNonNull(constants$16.fsync$MH,"fsync"); - } - public static int fsync ( int __fd) { - var mh$ = fsync$MH(); - try { - return (int)mh$.invokeExact(__fd); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle gethostid$MH() { - return RuntimeHelper.requireNonNull(constants$16.gethostid$MH,"gethostid"); - } - public static long gethostid () { - var mh$ = gethostid$MH(); - try { - return (long)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle sync$MH() { - return RuntimeHelper.requireNonNull(constants$16.sync$MH,"sync"); - } - public static void sync () { - var mh$ = sync$MH(); - try { - mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getpagesize$MH() { - return RuntimeHelper.requireNonNull(constants$17.getpagesize$MH,"getpagesize"); - } - public static int getpagesize () { - var mh$ = getpagesize$MH(); - try { - return (int)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getdtablesize$MH() { - return RuntimeHelper.requireNonNull(constants$17.getdtablesize$MH,"getdtablesize"); - } - public static int getdtablesize () { - var mh$ = getdtablesize$MH(); - try { - return (int)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle truncate$MH() { - return RuntimeHelper.requireNonNull(constants$17.truncate$MH,"truncate"); - } - public static int truncate ( Addressable __file, long __length) { - var mh$ = truncate$MH(); - try { - return (int)mh$.invokeExact(__file, __length); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle ftruncate$MH() { - return RuntimeHelper.requireNonNull(constants$17.ftruncate$MH,"ftruncate"); - } - public static int ftruncate ( int __fd, long __length) { - var mh$ = ftruncate$MH(); - try { - return (int)mh$.invokeExact(__fd, __length); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle brk$MH() { - return RuntimeHelper.requireNonNull(constants$17.brk$MH,"brk"); - } - public static int brk ( Addressable __addr) { - var mh$ = brk$MH(); - try { - return (int)mh$.invokeExact(__addr); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle sbrk$MH() { - return RuntimeHelper.requireNonNull(constants$17.sbrk$MH,"sbrk"); - } - public static MemoryAddress sbrk ( long __delta) { - var mh$ = sbrk$MH(); - try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(__delta); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle syscall$MH() { - return RuntimeHelper.requireNonNull(constants$18.syscall$MH,"syscall"); - } - public static long syscall ( long __sysno, Object... x1) { - var mh$ = syscall$MH(); - try { - return (long)mh$.invokeExact(__sysno, x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle lockf$MH() { - return RuntimeHelper.requireNonNull(constants$18.lockf$MH,"lockf"); - } - public static int lockf ( int __fd, int __cmd, long __len) { - var mh$ = lockf$MH(); - try { - return (int)mh$.invokeExact(__fd, __cmd, __len); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle fdatasync$MH() { - return RuntimeHelper.requireNonNull(constants$18.fdatasync$MH,"fdatasync"); - } - public static int fdatasync ( int __fildes) { - var mh$ = fdatasync$MH(); - try { - return (int)mh$.invokeExact(__fildes); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle crypt$MH() { - return RuntimeHelper.requireNonNull(constants$18.crypt$MH,"crypt"); - } - public static MemoryAddress crypt ( Addressable __key, Addressable __salt) { - var mh$ = crypt$MH(); - try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(__key, __salt); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle getentropy$MH() { - return RuntimeHelper.requireNonNull(constants$18.getentropy$MH,"getentropy"); - } - public static int getentropy ( Addressable __buffer, long __length) { - var mh$ = getentropy$MH(); - try { - return (int)mh$.invokeExact(__buffer, __length); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static long _POSIX_C_SOURCE() { - return 200809L; - } - public static int __TIMESIZE() { - return (int)64L; - } - public static long __STDC_IEC_60559_BFP__() { - return 201404L; - } - public static long __STDC_IEC_60559_COMPLEX__() { - return 201404L; - } - public static long __STDC_ISO_10646__() { - return 201706L; - } - public static long _POSIX_VERSION() { - return 200809L; - } - public static long __POSIX2_THIS_VERSION() { - return 200809L; - } - public static long _POSIX2_VERSION() { - return 200809L; - } - public static long _POSIX2_C_VERSION() { - return 200809L; - } - public static long _POSIX2_C_BIND() { - return 200809L; - } - public static long _POSIX2_C_DEV() { - return 200809L; - } - public static long _POSIX2_SW_DEV() { - return 200809L; - } - public static long _POSIX2_LOCALEDEF() { - return 200809L; - } - public static long _POSIX_PRIORITY_SCHEDULING() { - return 200809L; - } - public static long _POSIX_SYNCHRONIZED_IO() { - return 200809L; - } - public static long _POSIX_FSYNC() { - return 200809L; - } - public static long _POSIX_MAPPED_FILES() { - return 200809L; - } - public static long _POSIX_MEMLOCK() { - return 200809L; - } - public static long _POSIX_MEMLOCK_RANGE() { - return 200809L; - } - public static long _POSIX_MEMORY_PROTECTION() { - return 200809L; - } - public static int _POSIX_VDISABLE() { - return (int)0L; - } - public static long _POSIX_THREADS() { - return 200809L; - } - public static long _POSIX_THREAD_SAFE_FUNCTIONS() { - return 200809L; - } - public static long _POSIX_THREAD_PRIORITY_SCHEDULING() { - return 200809L; - } - public static long _POSIX_THREAD_ATTR_STACKSIZE() { - return 200809L; - } - public static long _POSIX_THREAD_ATTR_STACKADDR() { - return 200809L; - } - public static long _POSIX_THREAD_PRIO_INHERIT() { - return 200809L; - } - public static long _POSIX_THREAD_PRIO_PROTECT() { - return 200809L; - } - public static long _POSIX_THREAD_ROBUST_PRIO_INHERIT() { - return 200809L; - } - public static int _POSIX_THREAD_ROBUST_PRIO_PROTECT() { - return (int)-1L; - } - public static long _POSIX_SEMAPHORES() { - return 200809L; - } - public static long _POSIX_REALTIME_SIGNALS() { - return 200809L; - } - public static long _POSIX_ASYNCHRONOUS_IO() { - return 200809L; - } - public static long _POSIX_PRIORITIZED_IO() { - return 200809L; - } - public static long _POSIX_SHARED_MEMORY_OBJECTS() { - return 200809L; - } - public static long _POSIX_READER_WRITER_LOCKS() { - return 200809L; - } - public static long _POSIX_TIMEOUTS() { - return 200809L; - } - public static long _POSIX_SPIN_LOCKS() { - return 200809L; - } - public static long _POSIX_SPAWN() { - return 200809L; - } - public static long _POSIX_TIMERS() { - return 200809L; - } - public static long _POSIX_BARRIERS() { - return 200809L; - } - public static long _POSIX_MESSAGE_PASSING() { - return 200809L; - } - public static long _POSIX_THREAD_PROCESS_SHARED() { - return 200809L; - } - public static long _POSIX_CLOCK_SELECTION() { - return 200809L; - } - public static long _POSIX_ADVISORY_INFO() { - return 200809L; - } - public static long _POSIX_IPV6() { - return 200809L; - } - public static long _POSIX_RAW_SOCKETS() { - return 200809L; - } - public static long _POSIX2_CHAR_TERM() { - return 200809L; - } - public static int _POSIX_SPORADIC_SERVER() { - return (int)-1L; - } - public static int _POSIX_THREAD_SPORADIC_SERVER() { - return (int)-1L; - } - public static int _POSIX_TRACE() { - return (int)-1L; - } - public static int _POSIX_TRACE_EVENT_FILTER() { - return (int)-1L; - } - public static int _POSIX_TRACE_INHERIT() { - return (int)-1L; - } - public static int _POSIX_TRACE_LOG() { - return (int)-1L; - } - public static int _POSIX_TYPED_MEMORY_OBJECTS() { - return (int)-1L; - } - public static int _POSIX_V7_LPBIG_OFFBIG() { - return (int)-1L; - } - public static int _POSIX_V6_LPBIG_OFFBIG() { - return (int)-1L; - } - public static int _XBS5_LPBIG_OFFBIG() { - return (int)-1L; - } - public static MemorySegment __ILP32_OFF32_CFLAGS() { - return constants$18.__ILP32_OFF32_CFLAGS$SEGMENT; - } - public static MemorySegment __ILP32_OFF32_LDFLAGS() { - return constants$19.__ILP32_OFF32_LDFLAGS$SEGMENT; - } - public static MemorySegment __ILP32_OFFBIG_CFLAGS() { - return constants$19.__ILP32_OFFBIG_CFLAGS$SEGMENT; - } - public static MemorySegment __ILP32_OFFBIG_LDFLAGS() { - return constants$19.__ILP32_OFFBIG_LDFLAGS$SEGMENT; - } - public static MemorySegment __LP64_OFF64_CFLAGS() { - return constants$19.__LP64_OFF64_CFLAGS$SEGMENT; - } - public static MemorySegment __LP64_OFF64_LDFLAGS() { - return constants$19.__LP64_OFF64_LDFLAGS$SEGMENT; - } - public static MemoryAddress NULL() { - return constants$19.NULL$ADDR; - } - public static int L_SET() { - return (int)0L; - } - public static int L_INCR() { - return (int)1L; - } - public static int L_XTND() { - return (int)2L; - } - public static int _SC_PAGE_SIZE() { - return (int)30L; - } - public static int _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS() { - return (int)1L; - } - public static int _CS_POSIX_V5_WIDTH_RESTRICTED_ENVS() { - return (int)4L; - } - public static int _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS() { - return (int)5L; - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_fd_set.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_fd_set.java deleted file mode 100644 index 3d447c24..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_fd_set.java +++ /dev/null @@ -1,25 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.*; -public class __kernel_fd_set { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - MemoryLayout.sequenceLayout(16, Constants$root.C_LONG_LONG$LAYOUT).withName("fds_bits") - ); - public static MemoryLayout $LAYOUT() { - return __kernel_fd_set.$struct$LAYOUT; - } - public static MemorySegment fds_bits$slice(MemorySegment seg) { - return seg.asSlice(0, 128); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_fsid_t.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_fsid_t.java deleted file mode 100644 index 1122a232..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_fsid_t.java +++ /dev/null @@ -1,25 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.*; -public class __kernel_fsid_t { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - MemoryLayout.sequenceLayout(2, Constants$root.C_INT$LAYOUT).withName("val") - ); - public static MemoryLayout $LAYOUT() { - return __kernel_fsid_t.$struct$LAYOUT; - } - public static MemorySegment val$slice(MemorySegment seg) { - return seg.asSlice(0, 8); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_sighandler_t.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_sighandler_t.java deleted file mode 100644 index 43fc2525..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/__kernel_sighandler_t.java +++ /dev/null @@ -1,27 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.Addressable; -import java.lang.foreign.MemoryAddress; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; -public interface __kernel_sighandler_t { - - void apply(int _x0); - static MemorySegment allocate(__kernel_sighandler_t fi, MemorySession session) { - return RuntimeHelper.upcallStub(__kernel_sighandler_t.class, fi, constants$0.__kernel_sighandler_t$FUNC, session); - } - static __kernel_sighandler_t ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (int __x0) -> { - try { - constants$0.__kernel_sighandler_t$MH.invokeExact((Addressable)symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$0.java deleted file mode 100644 index d455d82c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$0.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemorySegment; -import java.lang.invoke.MethodHandle; -class constants$0 { - - static final FunctionDescriptor __kernel_sighandler_t$FUNC = FunctionDescriptor.ofVoid( - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle __kernel_sighandler_t$MH = RuntimeHelper.downcallHandle( - constants$0.__kernel_sighandler_t$FUNC - ); - static final MemorySegment REISERFS_SUPER_MAGIC_STRING$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("ReIsErFs"); - static final MemorySegment REISER2FS_SUPER_MAGIC_STRING$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("ReIsEr2Fs"); - static final MemorySegment REISER2FS_JR_SUPER_MAGIC_STRING$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("ReIsEr3Fs"); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_connectinfo.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_connectinfo.java deleted file mode 100644 index 0ad90f26..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_connectinfo.java +++ /dev/null @@ -1,57 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; -public class usbdevfs_connectinfo { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_INT$LAYOUT.withName("devnum"), - Constants$root.C_CHAR$LAYOUT.withName("slow"), - MemoryLayout.paddingLayout(24) - ).withName("usbdevfs_connectinfo"); - public static MemoryLayout $LAYOUT() { - return usbdevfs_connectinfo.$struct$LAYOUT; - } - static final VarHandle devnum$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("devnum")); - public static VarHandle devnum$VH() { - return usbdevfs_connectinfo.devnum$VH; - } - public static int devnum$get(MemorySegment seg) { - return (int)usbdevfs_connectinfo.devnum$VH.get(seg); - } - public static void devnum$set( MemorySegment seg, int x) { - usbdevfs_connectinfo.devnum$VH.set(seg, x); - } - public static int devnum$get(MemorySegment seg, long index) { - return (int)usbdevfs_connectinfo.devnum$VH.get(seg.asSlice(index*sizeof())); - } - public static void devnum$set(MemorySegment seg, long index, int x) { - usbdevfs_connectinfo.devnum$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle slow$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("slow")); - public static VarHandle slow$VH() { - return usbdevfs_connectinfo.slow$VH; - } - public static byte slow$get(MemorySegment seg) { - return (byte)usbdevfs_connectinfo.slow$VH.get(seg); - } - public static void slow$set( MemorySegment seg, byte x) { - usbdevfs_connectinfo.slow$VH.set(seg, x); - } - public static byte slow$get(MemorySegment seg, long index) { - return (byte)usbdevfs_connectinfo.slow$VH.get(seg.asSlice(index*sizeof())); - } - public static void slow$set(MemorySegment seg, long index, byte x) { - usbdevfs_connectinfo.slow$VH.set(seg.asSlice(index*sizeof()), x); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_conninfo_ex.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_conninfo_ex.java deleted file mode 100644 index 3279b19a..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_conninfo_ex.java +++ /dev/null @@ -1,111 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; -public class usbdevfs_conninfo_ex { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_INT$LAYOUT.withName("size"), - Constants$root.C_INT$LAYOUT.withName("busnum"), - Constants$root.C_INT$LAYOUT.withName("devnum"), - Constants$root.C_INT$LAYOUT.withName("speed"), - Constants$root.C_CHAR$LAYOUT.withName("num_ports"), - MemoryLayout.sequenceLayout(7, Constants$root.C_CHAR$LAYOUT).withName("ports") - ).withName("usbdevfs_conninfo_ex"); - public static MemoryLayout $LAYOUT() { - return usbdevfs_conninfo_ex.$struct$LAYOUT; - } - static final VarHandle size$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("size")); - public static VarHandle size$VH() { - return usbdevfs_conninfo_ex.size$VH; - } - public static int size$get(MemorySegment seg) { - return (int)usbdevfs_conninfo_ex.size$VH.get(seg); - } - public static void size$set( MemorySegment seg, int x) { - usbdevfs_conninfo_ex.size$VH.set(seg, x); - } - public static int size$get(MemorySegment seg, long index) { - return (int)usbdevfs_conninfo_ex.size$VH.get(seg.asSlice(index*sizeof())); - } - public static void size$set(MemorySegment seg, long index, int x) { - usbdevfs_conninfo_ex.size$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle busnum$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("busnum")); - public static VarHandle busnum$VH() { - return usbdevfs_conninfo_ex.busnum$VH; - } - public static int busnum$get(MemorySegment seg) { - return (int)usbdevfs_conninfo_ex.busnum$VH.get(seg); - } - public static void busnum$set( MemorySegment seg, int x) { - usbdevfs_conninfo_ex.busnum$VH.set(seg, x); - } - public static int busnum$get(MemorySegment seg, long index) { - return (int)usbdevfs_conninfo_ex.busnum$VH.get(seg.asSlice(index*sizeof())); - } - public static void busnum$set(MemorySegment seg, long index, int x) { - usbdevfs_conninfo_ex.busnum$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle devnum$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("devnum")); - public static VarHandle devnum$VH() { - return usbdevfs_conninfo_ex.devnum$VH; - } - public static int devnum$get(MemorySegment seg) { - return (int)usbdevfs_conninfo_ex.devnum$VH.get(seg); - } - public static void devnum$set( MemorySegment seg, int x) { - usbdevfs_conninfo_ex.devnum$VH.set(seg, x); - } - public static int devnum$get(MemorySegment seg, long index) { - return (int)usbdevfs_conninfo_ex.devnum$VH.get(seg.asSlice(index*sizeof())); - } - public static void devnum$set(MemorySegment seg, long index, int x) { - usbdevfs_conninfo_ex.devnum$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle speed$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("speed")); - public static VarHandle speed$VH() { - return usbdevfs_conninfo_ex.speed$VH; - } - public static int speed$get(MemorySegment seg) { - return (int)usbdevfs_conninfo_ex.speed$VH.get(seg); - } - public static void speed$set( MemorySegment seg, int x) { - usbdevfs_conninfo_ex.speed$VH.set(seg, x); - } - public static int speed$get(MemorySegment seg, long index) { - return (int)usbdevfs_conninfo_ex.speed$VH.get(seg.asSlice(index*sizeof())); - } - public static void speed$set(MemorySegment seg, long index, int x) { - usbdevfs_conninfo_ex.speed$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle num_ports$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("num_ports")); - public static VarHandle num_ports$VH() { - return usbdevfs_conninfo_ex.num_ports$VH; - } - public static byte num_ports$get(MemorySegment seg) { - return (byte)usbdevfs_conninfo_ex.num_ports$VH.get(seg); - } - public static void num_ports$set( MemorySegment seg, byte x) { - usbdevfs_conninfo_ex.num_ports$VH.set(seg, x); - } - public static byte num_ports$get(MemorySegment seg, long index) { - return (byte)usbdevfs_conninfo_ex.num_ports$VH.get(seg.asSlice(index*sizeof())); - } - public static void num_ports$set(MemorySegment seg, long index, byte x) { - usbdevfs_conninfo_ex.num_ports$VH.set(seg.asSlice(index*sizeof()), x); - } - public static MemorySegment ports$slice(MemorySegment seg) { - return seg.asSlice(17, 7); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java deleted file mode 100644 index 023757d7..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java +++ /dev/null @@ -1,60 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; -public class usbdevfs_disconnect_claim { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_INT$LAYOUT.withName("interface"), - Constants$root.C_INT$LAYOUT.withName("flags"), - MemoryLayout.sequenceLayout(256, Constants$root.C_CHAR$LAYOUT).withName("driver") - ).withName("usbdevfs_disconnect_claim"); - public static MemoryLayout $LAYOUT() { - return usbdevfs_disconnect_claim.$struct$LAYOUT; - } - static final VarHandle interface_$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("interface")); - public static VarHandle interface_$VH() { - return usbdevfs_disconnect_claim.interface_$VH; - } - public static int interface_$get(MemorySegment seg) { - return (int)usbdevfs_disconnect_claim.interface_$VH.get(seg); - } - public static void interface_$set( MemorySegment seg, int x) { - usbdevfs_disconnect_claim.interface_$VH.set(seg, x); - } - public static int interface_$get(MemorySegment seg, long index) { - return (int)usbdevfs_disconnect_claim.interface_$VH.get(seg.asSlice(index*sizeof())); - } - public static void interface_$set(MemorySegment seg, long index, int x) { - usbdevfs_disconnect_claim.interface_$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle flags$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("flags")); - public static VarHandle flags$VH() { - return usbdevfs_disconnect_claim.flags$VH; - } - public static int flags$get(MemorySegment seg) { - return (int)usbdevfs_disconnect_claim.flags$VH.get(seg); - } - public static void flags$set( MemorySegment seg, int x) { - usbdevfs_disconnect_claim.flags$VH.set(seg, x); - } - public static int flags$get(MemorySegment seg, long index) { - return (int)usbdevfs_disconnect_claim.flags$VH.get(seg.asSlice(index*sizeof())); - } - public static void flags$set(MemorySegment seg, long index, int x) { - usbdevfs_disconnect_claim.flags$VH.set(seg.asSlice(index*sizeof()), x); - } - public static MemorySegment driver$slice(MemorySegment seg) { - return seg.asSlice(8, 256); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnectsignal.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnectsignal.java deleted file mode 100644 index 97bf5c5e..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnectsignal.java +++ /dev/null @@ -1,57 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; -public class usbdevfs_disconnectsignal { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_INT$LAYOUT.withName("signr"), - MemoryLayout.paddingLayout(32), - Constants$root.C_POINTER$LAYOUT.withName("context") - ).withName("usbdevfs_disconnectsignal"); - public static MemoryLayout $LAYOUT() { - return usbdevfs_disconnectsignal.$struct$LAYOUT; - } - static final VarHandle signr$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("signr")); - public static VarHandle signr$VH() { - return usbdevfs_disconnectsignal.signr$VH; - } - public static int signr$get(MemorySegment seg) { - return (int)usbdevfs_disconnectsignal.signr$VH.get(seg); - } - public static void signr$set( MemorySegment seg, int x) { - usbdevfs_disconnectsignal.signr$VH.set(seg, x); - } - public static int signr$get(MemorySegment seg, long index) { - return (int)usbdevfs_disconnectsignal.signr$VH.get(seg.asSlice(index*sizeof())); - } - public static void signr$set(MemorySegment seg, long index, int x) { - usbdevfs_disconnectsignal.signr$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle context$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("context")); - public static VarHandle context$VH() { - return usbdevfs_disconnectsignal.context$VH; - } - public static MemoryAddress context$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)usbdevfs_disconnectsignal.context$VH.get(seg); - } - public static void context$set( MemorySegment seg, MemoryAddress x) { - usbdevfs_disconnectsignal.context$VH.set(seg, x); - } - public static MemoryAddress context$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)usbdevfs_disconnectsignal.context$VH.get(seg.asSlice(index*sizeof())); - } - public static void context$set(MemorySegment seg, long index, MemoryAddress x) { - usbdevfs_disconnectsignal.context$VH.set(seg.asSlice(index*sizeof()), x); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_getdriver.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_getdriver.java deleted file mode 100644 index 50208d87..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_getdriver.java +++ /dev/null @@ -1,43 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; -public class usbdevfs_getdriver { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_INT$LAYOUT.withName("interface"), - MemoryLayout.sequenceLayout(256, Constants$root.C_CHAR$LAYOUT).withName("driver") - ).withName("usbdevfs_getdriver"); - public static MemoryLayout $LAYOUT() { - return usbdevfs_getdriver.$struct$LAYOUT; - } - static final VarHandle interface_$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("interface")); - public static VarHandle interface_$VH() { - return usbdevfs_getdriver.interface_$VH; - } - public static int interface_$get(MemorySegment seg) { - return (int)usbdevfs_getdriver.interface_$VH.get(seg); - } - public static void interface_$set( MemorySegment seg, int x) { - usbdevfs_getdriver.interface_$VH.set(seg, x); - } - public static int interface_$get(MemorySegment seg, long index) { - return (int)usbdevfs_getdriver.interface_$VH.get(seg.asSlice(index*sizeof())); - } - public static void interface_$set(MemorySegment seg, long index, int x) { - usbdevfs_getdriver.interface_$VH.set(seg.asSlice(index*sizeof()), x); - } - public static MemorySegment driver$slice(MemorySegment seg) { - return seg.asSlice(4, 256); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_hub_portinfo.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_hub_portinfo.java deleted file mode 100644 index e7c195cd..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_hub_portinfo.java +++ /dev/null @@ -1,43 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; -public class usbdevfs_hub_portinfo { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("nports"), - MemoryLayout.sequenceLayout(127, Constants$root.C_CHAR$LAYOUT).withName("port") - ).withName("usbdevfs_hub_portinfo"); - public static MemoryLayout $LAYOUT() { - return usbdevfs_hub_portinfo.$struct$LAYOUT; - } - static final VarHandle nports$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("nports")); - public static VarHandle nports$VH() { - return usbdevfs_hub_portinfo.nports$VH; - } - public static byte nports$get(MemorySegment seg) { - return (byte)usbdevfs_hub_portinfo.nports$VH.get(seg); - } - public static void nports$set( MemorySegment seg, byte x) { - usbdevfs_hub_portinfo.nports$VH.set(seg, x); - } - public static byte nports$get(MemorySegment seg, long index) { - return (byte)usbdevfs_hub_portinfo.nports$VH.get(seg.asSlice(index*sizeof())); - } - public static void nports$set(MemorySegment seg, long index, byte x) { - usbdevfs_hub_portinfo.nports$VH.set(seg.asSlice(index*sizeof()), x); - } - public static MemorySegment port$slice(MemorySegment seg) { - return seg.asSlice(1, 127); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java deleted file mode 100644 index 35caf795..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java +++ /dev/null @@ -1,73 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; -public class usbdevfs_ioctl { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_INT$LAYOUT.withName("ifno"), - Constants$root.C_INT$LAYOUT.withName("ioctl_code"), - Constants$root.C_POINTER$LAYOUT.withName("data") - ).withName("usbdevfs_ioctl"); - public static MemoryLayout $LAYOUT() { - return usbdevfs_ioctl.$struct$LAYOUT; - } - static final VarHandle ifno$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ifno")); - public static VarHandle ifno$VH() { - return usbdevfs_ioctl.ifno$VH; - } - public static int ifno$get(MemorySegment seg) { - return (int)usbdevfs_ioctl.ifno$VH.get(seg); - } - public static void ifno$set( MemorySegment seg, int x) { - usbdevfs_ioctl.ifno$VH.set(seg, x); - } - public static int ifno$get(MemorySegment seg, long index) { - return (int)usbdevfs_ioctl.ifno$VH.get(seg.asSlice(index*sizeof())); - } - public static void ifno$set(MemorySegment seg, long index, int x) { - usbdevfs_ioctl.ifno$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle ioctl_code$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ioctl_code")); - public static VarHandle ioctl_code$VH() { - return usbdevfs_ioctl.ioctl_code$VH; - } - public static int ioctl_code$get(MemorySegment seg) { - return (int)usbdevfs_ioctl.ioctl_code$VH.get(seg); - } - public static void ioctl_code$set( MemorySegment seg, int x) { - usbdevfs_ioctl.ioctl_code$VH.set(seg, x); - } - public static int ioctl_code$get(MemorySegment seg, long index) { - return (int)usbdevfs_ioctl.ioctl_code$VH.get(seg.asSlice(index*sizeof())); - } - public static void ioctl_code$set(MemorySegment seg, long index, int x) { - usbdevfs_ioctl.ioctl_code$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle data$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("data")); - public static VarHandle data$VH() { - return usbdevfs_ioctl.data$VH; - } - public static MemoryAddress data$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)usbdevfs_ioctl.data$VH.get(seg); - } - public static void data$set( MemorySegment seg, MemoryAddress x) { - usbdevfs_ioctl.data$VH.set(seg, x); - } - public static MemoryAddress data$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)usbdevfs_ioctl.data$VH.get(seg.asSlice(index*sizeof())); - } - public static void data$set(MemorySegment seg, long index, MemoryAddress x) { - usbdevfs_ioctl.data$VH.set(seg.asSlice(index*sizeof()), x); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java deleted file mode 100644 index dcbb988b..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java +++ /dev/null @@ -1,73 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; -public class usbdevfs_iso_packet_desc { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_INT$LAYOUT.withName("length"), - Constants$root.C_INT$LAYOUT.withName("actual_length"), - Constants$root.C_INT$LAYOUT.withName("status") - ).withName("usbdevfs_iso_packet_desc"); - public static MemoryLayout $LAYOUT() { - return usbdevfs_iso_packet_desc.$struct$LAYOUT; - } - static final VarHandle length$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("length")); - public static VarHandle length$VH() { - return usbdevfs_iso_packet_desc.length$VH; - } - public static int length$get(MemorySegment seg) { - return (int)usbdevfs_iso_packet_desc.length$VH.get(seg); - } - public static void length$set( MemorySegment seg, int x) { - usbdevfs_iso_packet_desc.length$VH.set(seg, x); - } - public static int length$get(MemorySegment seg, long index) { - return (int)usbdevfs_iso_packet_desc.length$VH.get(seg.asSlice(index*sizeof())); - } - public static void length$set(MemorySegment seg, long index, int x) { - usbdevfs_iso_packet_desc.length$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle actual_length$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("actual_length")); - public static VarHandle actual_length$VH() { - return usbdevfs_iso_packet_desc.actual_length$VH; - } - public static int actual_length$get(MemorySegment seg) { - return (int)usbdevfs_iso_packet_desc.actual_length$VH.get(seg); - } - public static void actual_length$set( MemorySegment seg, int x) { - usbdevfs_iso_packet_desc.actual_length$VH.set(seg, x); - } - public static int actual_length$get(MemorySegment seg, long index) { - return (int)usbdevfs_iso_packet_desc.actual_length$VH.get(seg.asSlice(index*sizeof())); - } - public static void actual_length$set(MemorySegment seg, long index, int x) { - usbdevfs_iso_packet_desc.actual_length$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle status$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("status")); - public static VarHandle status$VH() { - return usbdevfs_iso_packet_desc.status$VH; - } - public static int status$get(MemorySegment seg) { - return (int)usbdevfs_iso_packet_desc.status$VH.get(seg); - } - public static void status$set( MemorySegment seg, int x) { - usbdevfs_iso_packet_desc.status$VH.set(seg, x); - } - public static int status$get(MemorySegment seg, long index) { - return (int)usbdevfs_iso_packet_desc.status$VH.get(seg.asSlice(index*sizeof())); - } - public static void status$set(MemorySegment seg, long index, int x) { - usbdevfs_iso_packet_desc.status$VH.set(seg.asSlice(index*sizeof()), x); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java deleted file mode 100644 index 0aec7f05..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java +++ /dev/null @@ -1,56 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; -public class usbdevfs_setinterface { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_INT$LAYOUT.withName("interface"), - Constants$root.C_INT$LAYOUT.withName("altsetting") - ).withName("usbdevfs_setinterface"); - public static MemoryLayout $LAYOUT() { - return usbdevfs_setinterface.$struct$LAYOUT; - } - static final VarHandle interface_$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("interface")); - public static VarHandle interface_$VH() { - return usbdevfs_setinterface.interface_$VH; - } - public static int interface_$get(MemorySegment seg) { - return (int)usbdevfs_setinterface.interface_$VH.get(seg); - } - public static void interface_$set( MemorySegment seg, int x) { - usbdevfs_setinterface.interface_$VH.set(seg, x); - } - public static int interface_$get(MemorySegment seg, long index) { - return (int)usbdevfs_setinterface.interface_$VH.get(seg.asSlice(index*sizeof())); - } - public static void interface_$set(MemorySegment seg, long index, int x) { - usbdevfs_setinterface.interface_$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle altsetting$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("altsetting")); - public static VarHandle altsetting$VH() { - return usbdevfs_setinterface.altsetting$VH; - } - public static int altsetting$get(MemorySegment seg) { - return (int)usbdevfs_setinterface.altsetting$VH.get(seg); - } - public static void altsetting$set( MemorySegment seg, int x) { - usbdevfs_setinterface.altsetting$VH.set(seg, x); - } - public static int altsetting$get(MemorySegment seg, long index) { - return (int)usbdevfs_setinterface.altsetting$VH.get(seg.asSlice(index*sizeof())); - } - public static void altsetting$set(MemorySegment seg, long index, int x) { - usbdevfs_setinterface.altsetting$VH.set(seg.asSlice(index*sizeof()), x); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_streams.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_streams.java deleted file mode 100644 index 463692b3..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_streams.java +++ /dev/null @@ -1,57 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; -public class usbdevfs_streams { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_INT$LAYOUT.withName("num_streams"), - Constants$root.C_INT$LAYOUT.withName("num_eps"), - MemoryLayout.sequenceLayout(0, Constants$root.C_CHAR$LAYOUT).withName("eps") - ).withName("usbdevfs_streams"); - public static MemoryLayout $LAYOUT() { - return usbdevfs_streams.$struct$LAYOUT; - } - static final VarHandle num_streams$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("num_streams")); - public static VarHandle num_streams$VH() { - return usbdevfs_streams.num_streams$VH; - } - public static int num_streams$get(MemorySegment seg) { - return (int)usbdevfs_streams.num_streams$VH.get(seg); - } - public static void num_streams$set( MemorySegment seg, int x) { - usbdevfs_streams.num_streams$VH.set(seg, x); - } - public static int num_streams$get(MemorySegment seg, long index) { - return (int)usbdevfs_streams.num_streams$VH.get(seg.asSlice(index*sizeof())); - } - public static void num_streams$set(MemorySegment seg, long index, int x) { - usbdevfs_streams.num_streams$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle num_eps$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("num_eps")); - public static VarHandle num_eps$VH() { - return usbdevfs_streams.num_eps$VH; - } - public static int num_eps$get(MemorySegment seg) { - return (int)usbdevfs_streams.num_eps$VH.get(seg); - } - public static void num_eps$set( MemorySegment seg, int x) { - usbdevfs_streams.num_eps$VH.set(seg, x); - } - public static int num_eps$get(MemorySegment seg, long index) { - return (int)usbdevfs_streams.num_eps$VH.get(seg.asSlice(index*sizeof())); - } - public static void num_eps$set(MemorySegment seg, long index, int x) { - usbdevfs_streams.num_eps$VH.set(seg.asSlice(index*sizeof()), x); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java deleted file mode 100644 index 5ffb8ae3..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java +++ /dev/null @@ -1,252 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; -public class usbdevfs_urb { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("type"), - Constants$root.C_CHAR$LAYOUT.withName("endpoint"), - MemoryLayout.paddingLayout(16), - Constants$root.C_INT$LAYOUT.withName("status"), - Constants$root.C_INT$LAYOUT.withName("flags"), - MemoryLayout.paddingLayout(32), - Constants$root.C_POINTER$LAYOUT.withName("buffer"), - Constants$root.C_INT$LAYOUT.withName("buffer_length"), - Constants$root.C_INT$LAYOUT.withName("actual_length"), - Constants$root.C_INT$LAYOUT.withName("start_frame"), - MemoryLayout.unionLayout( - Constants$root.C_INT$LAYOUT.withName("number_of_packets"), - Constants$root.C_INT$LAYOUT.withName("stream_id") - ).withName("$anon$0"), - Constants$root.C_INT$LAYOUT.withName("error_count"), - Constants$root.C_INT$LAYOUT.withName("signr"), - Constants$root.C_POINTER$LAYOUT.withName("usercontext"), - MemoryLayout.sequenceLayout(0, MemoryLayout.structLayout( - Constants$root.C_INT$LAYOUT.withName("length"), - Constants$root.C_INT$LAYOUT.withName("actual_length"), - Constants$root.C_INT$LAYOUT.withName("status") - ).withName("usbdevfs_iso_packet_desc")).withName("iso_frame_desc") - ).withName("usbdevfs_urb"); - public static MemoryLayout $LAYOUT() { - return usbdevfs_urb.$struct$LAYOUT; - } - static final VarHandle type$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("type")); - public static VarHandle type$VH() { - return usbdevfs_urb.type$VH; - } - public static byte type$get(MemorySegment seg) { - return (byte)usbdevfs_urb.type$VH.get(seg); - } - public static void type$set( MemorySegment seg, byte x) { - usbdevfs_urb.type$VH.set(seg, x); - } - public static byte type$get(MemorySegment seg, long index) { - return (byte)usbdevfs_urb.type$VH.get(seg.asSlice(index*sizeof())); - } - public static void type$set(MemorySegment seg, long index, byte x) { - usbdevfs_urb.type$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle endpoint$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("endpoint")); - public static VarHandle endpoint$VH() { - return usbdevfs_urb.endpoint$VH; - } - public static byte endpoint$get(MemorySegment seg) { - return (byte)usbdevfs_urb.endpoint$VH.get(seg); - } - public static void endpoint$set( MemorySegment seg, byte x) { - usbdevfs_urb.endpoint$VH.set(seg, x); - } - public static byte endpoint$get(MemorySegment seg, long index) { - return (byte)usbdevfs_urb.endpoint$VH.get(seg.asSlice(index*sizeof())); - } - public static void endpoint$set(MemorySegment seg, long index, byte x) { - usbdevfs_urb.endpoint$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle status$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("status")); - public static VarHandle status$VH() { - return usbdevfs_urb.status$VH; - } - public static int status$get(MemorySegment seg) { - return (int)usbdevfs_urb.status$VH.get(seg); - } - public static void status$set( MemorySegment seg, int x) { - usbdevfs_urb.status$VH.set(seg, x); - } - public static int status$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.status$VH.get(seg.asSlice(index*sizeof())); - } - public static void status$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.status$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle flags$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("flags")); - public static VarHandle flags$VH() { - return usbdevfs_urb.flags$VH; - } - public static int flags$get(MemorySegment seg) { - return (int)usbdevfs_urb.flags$VH.get(seg); - } - public static void flags$set( MemorySegment seg, int x) { - usbdevfs_urb.flags$VH.set(seg, x); - } - public static int flags$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.flags$VH.get(seg.asSlice(index*sizeof())); - } - public static void flags$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.flags$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle buffer$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("buffer")); - public static VarHandle buffer$VH() { - return usbdevfs_urb.buffer$VH; - } - public static MemoryAddress buffer$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)usbdevfs_urb.buffer$VH.get(seg); - } - public static void buffer$set( MemorySegment seg, MemoryAddress x) { - usbdevfs_urb.buffer$VH.set(seg, x); - } - public static MemoryAddress buffer$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)usbdevfs_urb.buffer$VH.get(seg.asSlice(index*sizeof())); - } - public static void buffer$set(MemorySegment seg, long index, MemoryAddress x) { - usbdevfs_urb.buffer$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle buffer_length$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("buffer_length")); - public static VarHandle buffer_length$VH() { - return usbdevfs_urb.buffer_length$VH; - } - public static int buffer_length$get(MemorySegment seg) { - return (int)usbdevfs_urb.buffer_length$VH.get(seg); - } - public static void buffer_length$set( MemorySegment seg, int x) { - usbdevfs_urb.buffer_length$VH.set(seg, x); - } - public static int buffer_length$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.buffer_length$VH.get(seg.asSlice(index*sizeof())); - } - public static void buffer_length$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.buffer_length$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle actual_length$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("actual_length")); - public static VarHandle actual_length$VH() { - return usbdevfs_urb.actual_length$VH; - } - public static int actual_length$get(MemorySegment seg) { - return (int)usbdevfs_urb.actual_length$VH.get(seg); - } - public static void actual_length$set( MemorySegment seg, int x) { - usbdevfs_urb.actual_length$VH.set(seg, x); - } - public static int actual_length$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.actual_length$VH.get(seg.asSlice(index*sizeof())); - } - public static void actual_length$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.actual_length$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle start_frame$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("start_frame")); - public static VarHandle start_frame$VH() { - return usbdevfs_urb.start_frame$VH; - } - public static int start_frame$get(MemorySegment seg) { - return (int)usbdevfs_urb.start_frame$VH.get(seg); - } - public static void start_frame$set( MemorySegment seg, int x) { - usbdevfs_urb.start_frame$VH.set(seg, x); - } - public static int start_frame$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.start_frame$VH.get(seg.asSlice(index*sizeof())); - } - public static void start_frame$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.start_frame$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle number_of_packets$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("number_of_packets")); - public static VarHandle number_of_packets$VH() { - return usbdevfs_urb.number_of_packets$VH; - } - public static int number_of_packets$get(MemorySegment seg) { - return (int)usbdevfs_urb.number_of_packets$VH.get(seg); - } - public static void number_of_packets$set( MemorySegment seg, int x) { - usbdevfs_urb.number_of_packets$VH.set(seg, x); - } - public static int number_of_packets$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.number_of_packets$VH.get(seg.asSlice(index*sizeof())); - } - public static void number_of_packets$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.number_of_packets$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle stream_id$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("stream_id")); - public static VarHandle stream_id$VH() { - return usbdevfs_urb.stream_id$VH; - } - public static int stream_id$get(MemorySegment seg) { - return (int)usbdevfs_urb.stream_id$VH.get(seg); - } - public static void stream_id$set( MemorySegment seg, int x) { - usbdevfs_urb.stream_id$VH.set(seg, x); - } - public static int stream_id$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.stream_id$VH.get(seg.asSlice(index*sizeof())); - } - public static void stream_id$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.stream_id$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle error_count$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("error_count")); - public static VarHandle error_count$VH() { - return usbdevfs_urb.error_count$VH; - } - public static int error_count$get(MemorySegment seg) { - return (int)usbdevfs_urb.error_count$VH.get(seg); - } - public static void error_count$set( MemorySegment seg, int x) { - usbdevfs_urb.error_count$VH.set(seg, x); - } - public static int error_count$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.error_count$VH.get(seg.asSlice(index*sizeof())); - } - public static void error_count$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.error_count$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle signr$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("signr")); - public static VarHandle signr$VH() { - return usbdevfs_urb.signr$VH; - } - public static int signr$get(MemorySegment seg) { - return (int)usbdevfs_urb.signr$VH.get(seg); - } - public static void signr$set( MemorySegment seg, int x) { - usbdevfs_urb.signr$VH.set(seg, x); - } - public static int signr$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.signr$VH.get(seg.asSlice(index*sizeof())); - } - public static void signr$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.signr$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle usercontext$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("usercontext")); - public static VarHandle usercontext$VH() { - return usbdevfs_urb.usercontext$VH; - } - public static MemoryAddress usercontext$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)usbdevfs_urb.usercontext$VH.get(seg); - } - public static void usercontext$set( MemorySegment seg, MemoryAddress x) { - usbdevfs_urb.usercontext$VH.set(seg, x); - } - public static MemoryAddress usercontext$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)usbdevfs_urb.usercontext$VH.get(seg.asSlice(index*sizeof())); - } - public static void usercontext$set(MemorySegment seg, long index, MemoryAddress x) { - usbdevfs_urb.usercontext$VH.set(seg.asSlice(index*sizeof()), x); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java index 034c4d1b..e396cb35 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java @@ -2,8 +2,6 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; -import java.lang.foreign.MemorySegment; - import static java.lang.foreign.ValueLayout.*; public class usbdevice_fs { @@ -16,351 +14,6 @@ public class usbdevice_fs { public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; - public static int __BITS_PER_LONG() { - return (int)64L; - } - public static int __FD_SETSIZE() { - return (int)1024L; - } - public static int ADFS_SUPER_MAGIC() { - return (int)44533L; - } - public static int AFFS_SUPER_MAGIC() { - return (int)44543L; - } - public static int AFS_SUPER_MAGIC() { - return (int)1397113167L; - } - public static int AUTOFS_SUPER_MAGIC() { - return (int)391L; - } - public static int CODA_SUPER_MAGIC() { - return (int)1937076805L; - } - public static int CRAMFS_MAGIC() { - return (int)684539205L; - } - public static int CRAMFS_MAGIC_WEND() { - return (int)1161678120L; - } - public static int DEBUGFS_MAGIC() { - return (int)1684170528L; - } - public static int SECURITYFS_MAGIC() { - return (int)1935894131L; - } - public static int SMACK_MAGIC() { - return (int)1128357203L; - } - public static int TMPFS_MAGIC() { - return (int)16914836L; - } - public static int SQUASHFS_MAGIC() { - return (int)1936814952L; - } - public static int ECRYPTFS_SUPER_MAGIC() { - return (int)61791L; - } - public static int EFS_SUPER_MAGIC() { - return (int)4278867L; - } - public static int EXT2_SUPER_MAGIC() { - return (int)61267L; - } - public static int EXT3_SUPER_MAGIC() { - return (int)61267L; - } - public static int EXT4_SUPER_MAGIC() { - return (int)61267L; - } - public static int NILFS_SUPER_MAGIC() { - return (int)13364L; - } - public static int ISOFS_SUPER_MAGIC() { - return (int)38496L; - } - public static int JFFS2_SUPER_MAGIC() { - return (int)29366L; - } - public static int XFS_SUPER_MAGIC() { - return (int)1481003842L; - } - public static int PSTOREFS_MAGIC() { - return (int)1634035564L; - } - public static int HOSTFS_SUPER_MAGIC() { - return (int)12648430L; - } - public static int OVERLAYFS_SUPER_MAGIC() { - return (int)2035054128L; - } - public static int MINIX_SUPER_MAGIC() { - return (int)4991L; - } - public static int MINIX_SUPER_MAGIC2() { - return (int)5007L; - } - public static int MINIX2_SUPER_MAGIC() { - return (int)9320L; - } - public static int MINIX2_SUPER_MAGIC2() { - return (int)9336L; - } - public static int MINIX3_SUPER_MAGIC() { - return (int)19802L; - } - public static int MSDOS_SUPER_MAGIC() { - return (int)19780L; - } - public static int NCP_SUPER_MAGIC() { - return (int)22092L; - } - public static int NFS_SUPER_MAGIC() { - return (int)26985L; - } - public static int OCFS2_SUPER_MAGIC() { - return (int)1952539503L; - } - public static int OPENPROM_SUPER_MAGIC() { - return (int)40865L; - } - public static int QNX4_SUPER_MAGIC() { - return (int)47L; - } - public static int QNX6_SUPER_MAGIC() { - return (int)1746473250L; - } - public static int AFS_FS_MAGIC() { - return (int)1799439955L; - } - public static int REISERFS_SUPER_MAGIC() { - return (int)1382369651L; - } - public static int SMB_SUPER_MAGIC() { - return (int)20859L; - } - public static int CGROUP_SUPER_MAGIC() { - return (int)2613483L; - } - public static int CGROUP2_SUPER_MAGIC() { - return (int)1667723888L; - } - public static int RDTGROUP_SUPER_MAGIC() { - return (int)124082209L; - } - public static int STACK_END_MAGIC() { - return (int)1470918301L; - } - public static int TRACEFS_MAGIC() { - return (int)1953653091L; - } - public static int V9FS_MAGIC() { - return (int)16914839L; - } - public static int BDEVFS_MAGIC() { - return (int)1650746742L; - } - public static int DAXFS_MAGIC() { - return (int)1684300152L; - } - public static int BINFMTFS_MAGIC() { - return (int)1112100429L; - } - public static int DEVPTS_SUPER_MAGIC() { - return (int)7377L; - } - public static int BINDERFS_SUPER_MAGIC() { - return (int)1819242352L; - } - public static int FUTEXFS_SUPER_MAGIC() { - return (int)195894762L; - } - public static int PIPEFS_MAGIC() { - return (int)1346981957L; - } - public static int PROC_SUPER_MAGIC() { - return (int)40864L; - } - public static int SOCKFS_MAGIC() { - return (int)1397703499L; - } - public static int SYSFS_MAGIC() { - return (int)1650812274L; - } - public static int USBDEVICE_SUPER_MAGIC() { - return (int)40866L; - } - public static int MTD_INODE_FS_MAGIC() { - return (int)288389204L; - } - public static int ANON_INODE_FS_MAGIC() { - return (int)151263540L; - } - public static int BTRFS_TEST_MAGIC() { - return (int)1936880249L; - } - public static int NSFS_MAGIC() { - return (int)1853056627L; - } - public static int AAFS_MAGIC() { - return (int)1513908720L; - } - public static int ZONEFS_MAGIC() { - return (int)1515144787L; - } - public static int UDF_SUPER_MAGIC() { - return (int)352400198L; - } - public static int BALLOON_KVM_MAGIC() { - return (int)325456742L; - } - public static int ZSMALLOC_MAGIC() { - return (int)1479104553L; - } - public static int DMA_BUF_MAGIC() { - return (int)1145913666L; - } - public static int DEVMEM_MAGIC() { - return (int)1162691661L; - } - public static int Z3FOLD_MAGIC() { - return (int)51L; - } - public static int SECRETMEM_MAGIC() { - return (int)1397048141L; - } - public static int SHIFTFS_MAGIC() { - return (int)1785031266L; - } - public static int USBDEVFS_MAXDRIVERNAME() { - return (int)255L; - } - public static int USBDEVFS_URB_SHORT_NOT_OK() { - return (int)1L; - } - public static int USBDEVFS_URB_ISO_ASAP() { - return (int)2L; - } - public static int USBDEVFS_URB_BULK_CONTINUATION() { - return (int)4L; - } - public static int USBDEVFS_URB_NO_FSBR() { - return (int)32L; - } - public static int USBDEVFS_URB_ZERO_PACKET() { - return (int)64L; - } - public static int USBDEVFS_URB_NO_INTERRUPT() { - return (int)128L; - } - public static int USBDEVFS_URB_TYPE_ISO() { - return (int)0L; - } - public static int USBDEVFS_URB_TYPE_INTERRUPT() { - return (int)1L; - } - public static int USBDEVFS_URB_TYPE_CONTROL() { - return (int)2L; - } - public static int USBDEVFS_URB_TYPE_BULK() { - return (int)3L; - } - public static int USBDEVFS_CAP_ZERO_PACKET() { - return (int)1L; - } - public static int USBDEVFS_CAP_BULK_CONTINUATION() { - return (int)2L; - } - public static int USBDEVFS_CAP_NO_PACKET_SIZE_LIM() { - return (int)4L; - } - public static int USBDEVFS_CAP_BULK_SCATTER_GATHER() { - return (int)8L; - } - public static int USBDEVFS_CAP_REAP_AFTER_DISCONNECT() { - return (int)16L; - } - public static int USBDEVFS_CAP_MMAP() { - return (int)32L; - } - public static int USBDEVFS_CAP_DROP_PRIVILEGES() { - return (int)64L; - } - public static int USBDEVFS_CAP_CONNINFO_EX() { - return (int)128L; - } - public static int USBDEVFS_CAP_SUSPEND() { - return (int)256L; - } - public static int USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER() { - return (int)1L; - } - public static int USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER() { - return (int)2L; - } - public static OfShort __s16 = Constants$root.C_SHORT$LAYOUT; - public static OfInt __s32 = Constants$root.C_INT$LAYOUT; - public static OfLong __s64 = Constants$root.C_LONG_LONG$LAYOUT; - public static OfInt __kernel_key_t = Constants$root.C_INT$LAYOUT; - public static OfInt __kernel_mqd_t = Constants$root.C_INT$LAYOUT; - public static OfLong __kernel_long_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfInt __kernel_pid_t = Constants$root.C_INT$LAYOUT; - public static OfInt __kernel_ipc_pid_t = Constants$root.C_INT$LAYOUT; - public static OfLong __kernel_suseconds_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfInt __kernel_daddr_t = Constants$root.C_INT$LAYOUT; - public static OfLong __kernel_ssize_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __kernel_ptrdiff_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __kernel_off_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __kernel_loff_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __kernel_old_time_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __kernel_time_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __kernel_time64_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong __kernel_clock_t = Constants$root.C_LONG_LONG$LAYOUT; - public static OfInt __kernel_timer_t = Constants$root.C_INT$LAYOUT; - public static OfInt __kernel_clockid_t = Constants$root.C_INT$LAYOUT; - public static OfAddress __kernel_caddr_t = Constants$root.C_POINTER$LAYOUT; - public static int SELINUX_MAGIC() { - return (int)4185718668L; - } - public static int RAMFS_MAGIC() { - return (int)2240043254L; - } - public static int HUGETLBFS_MAGIC() { - return (int)2508478710L; - } - public static int EROFS_SUPER_MAGIC_V1() { - return (int)3774210530L; - } - public static int XENFS_SUPER_MAGIC() { - return (int)2881100148L; - } - public static int BTRFS_SUPER_MAGIC() { - return (int)2435016766L; - } - public static int F2FS_SUPER_MAGIC() { - return (int)4076150800L; - } - public static int HPFS_SUPER_MAGIC() { - return (int)4187351113L; - } - public static int EFIVARFS_MAGIC() { - return (int)3730735588L; - } - public static MemorySegment REISERFS_SUPER_MAGIC_STRING() { - return constants$0.REISERFS_SUPER_MAGIC_STRING$SEGMENT; - } - public static MemorySegment REISER2FS_SUPER_MAGIC_STRING() { - return constants$0.REISER2FS_SUPER_MAGIC_STRING$SEGMENT; - } - public static MemorySegment REISER2FS_JR_SUPER_MAGIC_STRING() { - return constants$0.REISER2FS_JR_SUPER_MAGIC_STRING$SEGMENT; - } - public static int BPF_FS_MAGIC() { - return (int)3405662737L; - } - public static int PPC_CMM_MAGIC() { - return (int)3344373136L; - } } From cc9a697b6a224cb800595fef26a767f558803a89 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 23 Aug 2022 20:00:10 +0200 Subject: [PATCH 007/433] jextract on Windows --- java-does-usb/jextract/gen_win_cfgmgr32.cmd | 12 + java-does-usb/jextract/gen_win_kernel32.cmd | 22 ++ java-does-usb/jextract/gen_win_setupapi.cmd | 22 ++ java-does-usb/jextract/gen_win_stdlib.cmd | 7 + java-does-usb/jextract/gen_win_usbioctl.cmd | 14 ++ java-does-usb/jextract/gen_win_winusb.cmd | 16 ++ java-does-usb/jextract/gen_windows.cmd | 50 +--- java-does-usb/jextract/windows_cfgmgr32.h | 2 + java-does-usb/jextract/windows_kernel32.h | 1 + java-does-usb/jextract/windows_setupapi.h | 2 + java-does-usb/jextract/windows_stdlib.h | 1 + java-does-usb/jextract/windows_usbioctl.h | 2 + java-does-usb/jextract/windows_winusb.h | 2 + .../net/codecrete/usb/windows/CfgMgr32.java | 77 ------ .../net/codecrete/usb/windows/SetupApi.java | 232 +----------------- .../java/net/codecrete/usb/windows/Win.java | 176 +------------ .../net/codecrete/usb/windows/WinUSB.java | 204 --------------- .../usb/windows/WindowsUSBDevice.java | 42 ++-- .../usb/windows/WindowsUSBDeviceRegistry.java | 71 +++--- .../usb/windows/gen/cfgmgr32/CfgMgr32.java | 44 ++++ .../windows/gen/cfgmgr32/Constants$root.java | 19 ++ .../windows/gen/cfgmgr32/RuntimeHelper.java | 216 ++++++++++++++++ .../usb/windows/gen/cfgmgr32/constants$0.java | 30 +++ .../windows/gen/kernel32/Constants$root.java | 19 ++ .../usb/windows/gen/kernel32/Kernel32.java | 91 +++++++ .../windows/gen/kernel32/RuntimeHelper.java | 216 ++++++++++++++++ .../usb/windows/gen/kernel32/constants$0.java | 50 ++++ .../windows/gen/setupapi/Constants$root.java | 19 ++ .../windows/gen/setupapi/RuntimeHelper.java | 216 ++++++++++++++++ .../usb/windows/gen/setupapi/SetupAPI.java | 98 ++++++++ .../setupapi/_SP_DEVICE_INTERFACE_DATA.java | 82 +++++++ .../_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java | 44 ++++ .../gen/setupapi/_SP_DEVINFO_DATA.java | 82 +++++++ .../usb/windows/gen/setupapi/constants$0.java | 73 ++++++ .../windows/gen/stdlib/Constants$root.java | 19 ++ .../usb/windows/gen/stdlib/RuntimeHelper.java | 216 ++++++++++++++++ .../usb/windows/gen/stdlib/StdLib.java | 33 +++ .../usb/windows/gen/stdlib/constants$0.java | 18 ++ .../windows/gen/usbioctl/Constants$root.java | 19 ++ .../windows/gen/usbioctl/RuntimeHelper.java | 216 ++++++++++++++++ .../usb/windows/gen/usbioctl/USBIoctl.java | 19 ++ .../_USB_NODE_CONNECTION_INFORMATION_EX.java | 171 +++++++++++++ .../windows/gen/winusb/Constants$root.java | 19 ++ .../usb/windows/gen/winusb/RuntimeHelper.java | 216 ++++++++++++++++ .../usb/windows/gen/winusb/WinUSB.java | 89 +++++++ .../usb/windows/gen/winusb/constants$0.java | 82 +++++++ 46 files changed, 2586 insertions(+), 785 deletions(-) create mode 100644 java-does-usb/jextract/gen_win_cfgmgr32.cmd create mode 100644 java-does-usb/jextract/gen_win_kernel32.cmd create mode 100644 java-does-usb/jextract/gen_win_setupapi.cmd create mode 100644 java-does-usb/jextract/gen_win_stdlib.cmd create mode 100644 java-does-usb/jextract/gen_win_usbioctl.cmd create mode 100644 java-does-usb/jextract/gen_win_winusb.cmd create mode 100644 java-does-usb/jextract/windows_cfgmgr32.h create mode 100644 java-does-usb/jextract/windows_kernel32.h create mode 100644 java-does-usb/jextract/windows_setupapi.h create mode 100644 java-does-usb/jextract/windows_stdlib.h create mode 100644 java-does-usb/jextract/windows_usbioctl.h create mode 100644 java-does-usb/jextract/windows_winusb.h delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/CfgMgr32.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/WinUSB.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/CfgMgr32.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/StdLib.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java diff --git a/java-does-usb/jextract/gen_win_cfgmgr32.cmd b/java-does-usb/jextract/gen_win_cfgmgr32.cmd new file mode 100644 index 00000000..e4bd1db9 --- /dev/null +++ b/java-does-usb/jextract/gen_win_cfgmgr32.cmd @@ -0,0 +1,12 @@ +set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract.bat +set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 +%JEXTRACT% --source --output ../src/main/java ^ + -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ + -I "%SDK_DIR%\um" ^ + -I "%SDK_DIR%\shared" ^ + -l Cfgmgr32 ^ + --header-class-name CfgMgr32 ^ + --target-package net.codecrete.usb.windows.gen.cfgmgr32 ^ + --include-function CM_Get_Parent ^ + --include-function CM_Get_Device_IDW ^ + windows_cfgmgr32.h diff --git a/java-does-usb/jextract/gen_win_kernel32.cmd b/java-does-usb/jextract/gen_win_kernel32.cmd new file mode 100644 index 00000000..90af5039 --- /dev/null +++ b/java-does-usb/jextract/gen_win_kernel32.cmd @@ -0,0 +1,22 @@ +set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract.bat +set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 +%JEXTRACT% --source --output ../src/main/java ^ + -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ + -I "%SDK_DIR%\um" ^ + -I "%SDK_DIR%\shared" ^ + -l Kernel32 ^ + --header-class-name Kernel32 ^ + --target-package net.codecrete.usb.windows.gen.kernel32 ^ + --include-function CreateFileW ^ + --include-function CloseHandle ^ + --include-function DeviceIoControl ^ + --include-function GetLastError ^ + --include-macro ERROR_NO_MORE_ITEMS ^ + --include-macro GENERIC_READ ^ + --include-macro GENERIC_WRITE ^ + --include-macro FILE_SHARE_READ ^ + --include-macro FILE_SHARE_WRITE ^ + --include-macro FILE_ATTRIBUTE_NORMAL ^ + --include-macro FILE_FLAG_OVERLAPPED ^ + --include-macro OPEN_EXISTING ^ + windows_kernel32.h diff --git a/java-does-usb/jextract/gen_win_setupapi.cmd b/java-does-usb/jextract/gen_win_setupapi.cmd new file mode 100644 index 00000000..baf7983a --- /dev/null +++ b/java-does-usb/jextract/gen_win_setupapi.cmd @@ -0,0 +1,22 @@ +set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract.bat +set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 +%JEXTRACT% --source --output ../src/main/java ^ + -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ + -I "%SDK_DIR%\um" ^ + -I "%SDK_DIR%\shared" ^ + -l SetupAPI ^ + --header-class-name SetupAPI ^ + --target-package net.codecrete.usb.windows.gen.setupapi ^ + --include-function SetupDiGetClassDevsW ^ + --include-function SetupDiDestroyDeviceInfoList ^ + --include-function SetupDiEnumDeviceInfo ^ + --include-function SetupDiEnumDeviceInterfaces ^ + --include-function SetupDiGetDeviceInterfaceDetailW ^ + --include-function SetupDiGetDeviceRegistryPropertyW ^ + --include-struct _SP_DEVINFO_DATA ^ + --include-struct _SP_DEVICE_INTERFACE_DATA ^ + --include-struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W ^ + --include-macro DIGCF_PRESENT ^ + --include-macro DIGCF_DEVICEINTERFACE ^ + --include-macro SPDRP_ADDRESS ^ + windows_setupapi.h diff --git a/java-does-usb/jextract/gen_win_stdlib.cmd b/java-does-usb/jextract/gen_win_stdlib.cmd new file mode 100644 index 00000000..cd387688 --- /dev/null +++ b/java-does-usb/jextract/gen_win_stdlib.cmd @@ -0,0 +1,7 @@ +set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract.bat +%JEXTRACT% --source --output ../src/main/java ^ + -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ + --header-class-name StdLib ^ + --target-package net.codecrete.usb.windows.gen.stdlib ^ + --include-function wcslen ^ + windows_stdlib.h diff --git a/java-does-usb/jextract/gen_win_usbioctl.cmd b/java-does-usb/jextract/gen_win_usbioctl.cmd new file mode 100644 index 00000000..b31b59b2 --- /dev/null +++ b/java-does-usb/jextract/gen_win_usbioctl.cmd @@ -0,0 +1,14 @@ +set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract.bat +set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 +%JEXTRACT% --source --output ../src/main/java ^ + -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ + -I "%SDK_DIR%\um" ^ + -I "%SDK_DIR%\shared" ^ + --header-class-name USBIoctl ^ + --target-package net.codecrete.usb.windows.gen.usbioctl ^ + --include-struct _USB_NODE_CONNECTION_INFORMATION_EX ^ + windows_usbioctl.h + +:: Generated code is invalid: No instance of type _USB_NODE_CONNECTION_INFORMATION_EX can be created.0 +:: They crash with: +:: java.lang.UnsupportedOperationException: Invalid alignment requirements for layout s16(DeviceAddress) diff --git a/java-does-usb/jextract/gen_win_winusb.cmd b/java-does-usb/jextract/gen_win_winusb.cmd new file mode 100644 index 00000000..bb52c94d --- /dev/null +++ b/java-does-usb/jextract/gen_win_winusb.cmd @@ -0,0 +1,16 @@ +set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract.bat +set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 +%JEXTRACT% --source --output ../src/main/java ^ + -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ + -I "%SDK_DIR%\um" ^ + -I "%SDK_DIR%\shared" ^ + -l Winusb ^ + --header-class-name WinUSB ^ + --target-package net.codecrete.usb.windows.gen.winusb ^ + --include-function WinUsb_Initialize ^ + --include-function WinUsb_Free ^ + --include-function WinUsb_GetDescriptor ^ + --include-function WinUsb_ControlTransfer ^ + --include-function WinUsb_WritePipe ^ + --include-function WinUsb_ReadPipe ^ + windows_winusb.h diff --git a/java-does-usb/jextract/gen_windows.cmd b/java-does-usb/jextract/gen_windows.cmd index 399b9408..f75288f1 100644 --- a/java-does-usb/jextract/gen_windows.cmd +++ b/java-does-usb/jextract/gen_windows.cmd @@ -1,43 +1,4 @@ -#!/bin/sh - -set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract - -:: handleapi.h -:: Generates more than 1000 files -:: Functions like CloseHandle() are generated multiple times but none of them in a public class -::%JEXTRACT% --source --output ../src/main/java ^ -:: -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -:: --header-class-name handleapi ^ -:: --target-package net.codecrete.usb.windows.gen.handleapi ^ -:: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\handleapi.h" - -:: Generates code that produces run-time error: -:: java.lang.UnsatisfiedLinkError: unresolved symbol: CloseHandle -::%JEXTRACT% --source --output ../src/main/java ^ -:: -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -:: --header-class-name handleapi ^ -:: --target-package net.codecrete.usb.windows.gen.handleapi ^ -:: --include-function CloseHandle ^ -:: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\handleapi.h" - -:: Generates code that produces run-time error: -:: java.lang.UnsatisfiedLinkError: unresolved symbol: CloseHandle -::%JEXTRACT% --source --output ../src/main/java ^ -:: -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -:: --header-class-name handleapi ^ -:: --target-package net.codecrete.usb.windows.gen.handleapi ^ -:: --include-function CloseHandle ^ -:: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\Windows.h" - -:: winusb.h -:: Fails with error: -:: C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\shared\usb.h:32:9: error: unknown type name 'LARGE_INTEGER' -:: winusb.h requires that certain other header files (like Windows.h) are processed first -::%JEXTRACT% --source --output ../src/main/java ^ -:: -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -:: --header-class-name WinUSB ^ -:: --target-package net.codecrete.usb.windows.gen.winusb ^ -:: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\winusb.h" +set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract.bat :: cfgmgr32.h :: Fails with error: @@ -56,12 +17,3 @@ set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract :: --header-class-name SetupApi ^ :: --target-package net.codecrete.usb.windows.gen.setupapi ^ :: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\setupapi.h" - -:: usbioctl.h -:: Fails with error: -:: C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\setupapi.h:65:9: error: unknown type name 'GUID' -::%JEXTRACT% --source --output ../src/main/java ^ -:: -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -:: --header-class-name USBIOCtl ^ -:: --target-package net.codecrete.usb.windows.gen.usbioctl ^ -:: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\shared\usbioctl.h" diff --git a/java-does-usb/jextract/windows_cfgmgr32.h b/java-does-usb/jextract/windows_cfgmgr32.h new file mode 100644 index 00000000..102a2987 --- /dev/null +++ b/java-does-usb/jextract/windows_cfgmgr32.h @@ -0,0 +1,2 @@ +#include +#include diff --git a/java-does-usb/jextract/windows_kernel32.h b/java-does-usb/jextract/windows_kernel32.h new file mode 100644 index 00000000..198556f6 --- /dev/null +++ b/java-does-usb/jextract/windows_kernel32.h @@ -0,0 +1 @@ +#include diff --git a/java-does-usb/jextract/windows_setupapi.h b/java-does-usb/jextract/windows_setupapi.h new file mode 100644 index 00000000..7597c78f --- /dev/null +++ b/java-does-usb/jextract/windows_setupapi.h @@ -0,0 +1,2 @@ +#include +#include diff --git a/java-does-usb/jextract/windows_stdlib.h b/java-does-usb/jextract/windows_stdlib.h new file mode 100644 index 00000000..3b2f5900 --- /dev/null +++ b/java-does-usb/jextract/windows_stdlib.h @@ -0,0 +1 @@ +#include diff --git a/java-does-usb/jextract/windows_usbioctl.h b/java-does-usb/jextract/windows_usbioctl.h new file mode 100644 index 00000000..2a284d46 --- /dev/null +++ b/java-does-usb/jextract/windows_usbioctl.h @@ -0,0 +1,2 @@ +#include +#include diff --git a/java-does-usb/jextract/windows_winusb.h b/java-does-usb/jextract/windows_winusb.h new file mode 100644 index 00000000..2fd0d78b --- /dev/null +++ b/java-does-usb/jextract/windows_winusb.h @@ -0,0 +1,2 @@ +#include +#include diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/CfgMgr32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/CfgMgr32.java deleted file mode 100644 index 91f85f77..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/CfgMgr32.java +++ /dev/null @@ -1,77 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.windows; - -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_INT; - -/** - * Windows CfgMgr32 functions and structures - */ -public class CfgMgr32 { - - private static final MethodHandle CM_Get_Parent$Func; - private static final MethodHandle CM_Get_Device_IDW$Func; - - static { - var session = MemorySession.openShared(); - Linker linker = Linker.nativeLinker(); - SymbolLookup lookup = SymbolLookup.libraryLookup("CfgMgr32", session); - - // CMAPI CONFIGRET CM_Get_Parent( - // [out] PDEVINST pdnDevInst, - // [in] DEVINST dnDevInst, - // [in] ULONG ulFlags - //); - CM_Get_Parent$Func = linker.downcallHandle( - lookup.lookup("CM_Get_Parent").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT, JAVA_INT) - ); - - // CMAPI CONFIGRET CM_Get_Device_IDW( - // [in] DEVINST dnDevInst, - // [out] PWSTR Buffer, - // [in] ULONG BufferLen, - // [in] ULONG ulFlags - //); - CM_Get_Device_IDW$Func = linker.downcallHandle( - lookup.lookup("CM_Get_Device_IDW").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS, JAVA_INT, JAVA_INT) - ); - } - - // CMAPI CONFIGRET CM_Get_Parent( - // [out] PDEVINST pdnDevInst, - // [in] DEVINST dnDevInst, - // [in] ULONG ulFlags - //); - public static int CM_Get_Parent(Addressable pdnDevInst, int dnDevInst, int ulFlags) { - try { - return (int) CM_Get_Parent$Func.invokeExact(pdnDevInst, dnDevInst, ulFlags); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // CMAPI CONFIGRET CM_Get_Device_IDW( - // [in] DEVINST dnDevInst, - // [out] PWSTR Buffer, - // [in] ULONG BufferLen, - // [in] ULONG ulFlags - //); - public static int CM_Get_Device_IDW(int dnDevInst, Addressable buffer, int bufferLen, int ulFlags) { - try { - return (int) CM_Get_Device_IDW$Func.invokeExact(dnDevInst, buffer, bufferLen, ulFlags); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/SetupApi.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/SetupApi.java index 8ea584e2..1424553b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/SetupApi.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/SetupApi.java @@ -8,7 +8,6 @@ package net.codecrete.usb.windows; import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; import static java.lang.foreign.MemoryLayout.PathElement.groupElement; @@ -19,38 +18,17 @@ */ public class SetupApi { - public static final int DIGCF_DEFAULT = 0x00000001; - public static final int DIGCF_PRESENT = 0x00000002; - public static final int DIGCF_ALLCLASSES = 0x00000004; - public static final int DIGCF_PROFILE = 0x00000008; - public static final int DIGCF_DEVICEINTERFACE = 0x00000010; - - public static final int SPDRP_ADDRESS = 0x0000001C; // Device Address (R) - private static final GroupLayout GUID$Struct; private static final VarHandle GUID_Data1; private static final VarHandle GUID_Data2; private static final VarHandle GUID_Data3; private static final long GUID_Data4$Offset; - public static final GroupLayout SP_DEVINFO_DATA$Struct; - public static final VarHandle SP_DEVINFO_DATA_cbSize; - public static final VarHandle SP_DEVINFO_DATA_DevInst; - - public static final GroupLayout SP_DEVICE_INTERFACE_DATA$Struct; - public static final VarHandle SP_DEVICE_INTERFACE_DATA_cbSize; - public static final GroupLayout SP_DEVICE_INTERFACE_DETAIL_DATA_W$Struct; - public static final VarHandle SP_DEVICE_INTERFACE_DETAIL_DATA_cbSize; - public static final long SP_DEVICE_INTERFACE_DETAIL_DATA_DevicePath$Offset; + public static final VarHandle SP_DEVICE_INTERFACE_DETAIL_DATA_W_cbSize; + public static final long SP_DEVICE_INTERFACE_DETAIL_DATA_W_DevicePath$Offset; - private static final MethodHandle SetupDiGetClassDevsW$Func; - private static final MethodHandle SetupDiDestroyDeviceInfoList$Func; public static final MemorySegment GUID_DEVINTERFACE_USB_DEVICE; - private static final MethodHandle SetupDiEnumDeviceInfo$Func; - private static final MethodHandle SetupDiEnumDeviceInterfaces$Func; - private static final MethodHandle SetupDiGetDeviceInterfaceDetailW$Func; - private static final MethodHandle SetupDiGetDeviceRegistryPropertyW$Func; static { var session = MemorySession.openShared(); @@ -74,35 +52,6 @@ public class SetupApi { GUID_Data3 = GUID$Struct.varHandle(groupElement("Data3")); GUID_Data4$Offset = GUID$Struct.byteOffset(groupElement("Data4")); - // typedef struct _SP_DEVINFO_DATA { - // DWORD cbSize; - // GUID ClassGuid; - // DWORD DevInst; // DEVINST handle - // ULONG_PTR Reserved; - // } SP_DEVINFO_DATA, *PSP_DEVINFO_DATA; - SP_DEVINFO_DATA$Struct = MemoryLayout.structLayout( - JAVA_INT.withName("cbSize"), - GUID$Struct.withName("ClassGuid"), - JAVA_INT.withName("DevInst"), - ADDRESS.withName("Reserved") - ); - SP_DEVINFO_DATA_cbSize = SP_DEVINFO_DATA$Struct.varHandle(groupElement("cbSize")); - SP_DEVINFO_DATA_DevInst = SP_DEVINFO_DATA$Struct.varHandle(groupElement("DevInst")); - - // typedef struct _SP_DEVICE_INTERFACE_DATA { - // DWORD cbSize; - // GUID InterfaceClassGuid; - // DWORD Flags; - // ULONG_PTR Reserved; - // } SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA; - SP_DEVICE_INTERFACE_DATA$Struct = MemoryLayout.structLayout( - JAVA_INT.withName("cbSize"), - GUID$Struct.withName("InterfaceClassGuid"), - JAVA_INT.withName("Flags"), - ADDRESS.withName("Reserved") - ); - SP_DEVICE_INTERFACE_DATA_cbSize = SP_DEVICE_INTERFACE_DATA$Struct.varHandle(groupElement("cbSize")); - // typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W { // DWORD cbSize; // WCHAR DevicePath[ANYSIZE_ARRAY]; @@ -111,78 +60,8 @@ public class SetupApi { JAVA_INT.withName("cbSize"), MemoryLayout.sequenceLayout(260, JAVA_CHAR).withName("DevicePath") ); - SP_DEVICE_INTERFACE_DETAIL_DATA_cbSize = SP_DEVICE_INTERFACE_DETAIL_DATA_W$Struct.varHandle(groupElement("cbSize")); - SP_DEVICE_INTERFACE_DETAIL_DATA_DevicePath$Offset = SP_DEVICE_INTERFACE_DETAIL_DATA_W$Struct.byteOffset(groupElement("DevicePath")); - - // WINSETUPAPI HDEVINFO SetupDiGetClassDevsW( - // [in, optional] const GUID *ClassGuid, - // [in, optional] PCWSTR Enumerator, - // [in, optional] HWND hwndParent, - // [in] DWORD Flags - //); - SetupDiGetClassDevsW$Func = linker.downcallHandle( - lookup.lookup("SetupDiGetClassDevsW").get(), - FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, ADDRESS, JAVA_INT) - ); - - // BOOL - // SetupDiDestroyDeviceInfoList( - // _In_ HDEVINFO DeviceInfoSet - // ); - SetupDiDestroyDeviceInfoList$Func = linker.downcallHandle( - lookup.lookup("SetupDiDestroyDeviceInfoList").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS) - ); - - //BOOL - //SetupDiEnumDeviceInfo( - // _In_ HDEVINFO DeviceInfoSet, - // _In_ DWORD MemberIndex, - // _Out_ PSP_DEVINFO_DATA DeviceInfoData - // ); - SetupDiEnumDeviceInfo$Func = linker.downcallHandle( - lookup.lookup("SetupDiEnumDeviceInfo").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT, ADDRESS) - ); - - // WINSETUPAPI BOOL SetupDiEnumDeviceInterfaces( - // [in] HDEVINFO DeviceInfoSet, - // [in, optional] PSP_DEVINFO_DATA DeviceInfoData, - // [in] const GUID *InterfaceClassGuid, - // [in] DWORD MemberIndex, - // [out] PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData - //); - SetupDiEnumDeviceInterfaces$Func = linker.downcallHandle( - lookup.lookup("SetupDiEnumDeviceInterfaces").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS) - ); - - // WINSETUPAPI BOOL SetupDiGetDeviceInterfaceDetailW( - // [in] HDEVINFO DeviceInfoSet, - // [in] PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, - // [out, optional] PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData, - // [in] DWORD DeviceInterfaceDetailDataSize, - // [out, optional] PDWORD RequiredSize, - // [out, optional] PSP_DEVINFO_DATA DeviceInfoData - //); - SetupDiGetDeviceInterfaceDetailW$Func = linker.downcallHandle( - lookup.lookup("SetupDiGetDeviceInterfaceDetailW").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS, ADDRESS) - ); - - // WINSETUPAPI BOOL SetupDiGetDeviceRegistryPropertyW( - // [in] HDEVINFO DeviceInfoSet, - // [in] PSP_DEVINFO_DATA DeviceInfoData, - // [in] DWORD Property, - // [out, optional] PDWORD PropertyRegDataType, - // [out, optional] PBYTE PropertyBuffer, - // [in] DWORD PropertyBufferSize, - // [out, optional] PDWORD RequiredSize - //); - SetupDiGetDeviceRegistryPropertyW$Func = linker.downcallHandle( - lookup.lookup("SetupDiGetDeviceRegistryPropertyW").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, JAVA_INT, ADDRESS, ADDRESS, JAVA_INT, ADDRESS) - ); + SP_DEVICE_INTERFACE_DETAIL_DATA_W_cbSize = SP_DEVICE_INTERFACE_DETAIL_DATA_W$Struct.varHandle(groupElement("cbSize")); + SP_DEVICE_INTERFACE_DETAIL_DATA_W_DevicePath$Offset = SP_DEVICE_INTERFACE_DETAIL_DATA_W$Struct.byteOffset(groupElement("DevicePath")); // A5DCBF10-6530-11D2-901F-00C04FB951ED GUID_DEVINTERFACE_USB_DEVICE = CreateGUID(0xA5DCBF10, (short) 0x6530, (short) 0x11D2, @@ -190,109 +69,6 @@ public class SetupApi { (byte) 0x4F, (byte) 0xB9, (byte) 0x51, (byte) 0xED); } - // WINSETUPAPI HDEVINFO SetupDiGetClassDevsW( - // [in, optional] const GUID *ClassGuid, - // [in, optional] PCWSTR Enumerator, - // [in, optional] HWND hwndParent, - // [in] DWORD Flags - //); - public static MemoryAddress SetupDiGetClassDevsW(Addressable classGuid, Addressable enumerator, - Addressable hwndParent, int flags) { - try { - return (MemoryAddress) SetupDiGetClassDevsW$Func.invokeExact(classGuid, enumerator, - hwndParent, flags); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // BOOL - // SetupDiDestroyDeviceInfoList( - // _In_ HDEVINFO DeviceInfoSet - // ); - public static boolean SetupDiDestroyDeviceInfoList(Addressable deviceInfoSet) { - try { - return (int) SetupDiDestroyDeviceInfoList$Func.invokeExact(deviceInfoSet) != 0; - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - //BOOL - //SetupDiEnumDeviceInfo( - // _In_ HDEVINFO DeviceInfoSet, - // _In_ DWORD MemberIndex, - // _Out_ PSP_DEVINFO_DATA DeviceInfoData - // ); - public static boolean SetupDiEnumDeviceInfo(Addressable deviceInfoSet, int memberIndex, Addressable deviceInfoData) { - try { - return (int) SetupDiEnumDeviceInfo$Func.invokeExact(deviceInfoSet, memberIndex, deviceInfoData) != 0; - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // WINSETUPAPI BOOL SetupDiEnumDeviceInterfaces( - // [in] HDEVINFO DeviceInfoSet, - // [in, optional] PSP_DEVINFO_DATA DeviceInfoData, - // [in] const GUID *InterfaceClassGuid, - // [in] DWORD MemberIndex, - // [out] PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData - //); - public static boolean SetupDiEnumDeviceInterfaces(Addressable deviceInfoSet, Addressable deviceInfoData, - Addressable interfaceClassGuid, int memberIndex, - Addressable deviceInterfaceData) { - try { - return (int) SetupDiEnumDeviceInterfaces$Func.invokeExact(deviceInfoSet, deviceInfoData, - interfaceClassGuid, memberIndex, - deviceInterfaceData) != 0; - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // WINSETUPAPI BOOL SetupDiGetDeviceInterfaceDetailW( - // [in] HDEVINFO DeviceInfoSet, - // [in] PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, - // [out, optional] PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData, - // [in] DWORD DeviceInterfaceDetailDataSize, - // [out, optional] PDWORD RequiredSize, - // [out, optional] PSP_DEVINFO_DATA DeviceInfoData - //); - public static boolean SetupDiGetDeviceInterfaceDetailW(Addressable deviceInfoSet, Addressable deviceInterfaceData, - Addressable deviceInterfaceDetailData, int deviceInterfaceDetailDataSize, - Addressable requiredSize, Addressable deviceInfoData) { - try { - return (int) SetupDiGetDeviceInterfaceDetailW$Func.invokeExact(deviceInfoSet, deviceInterfaceData, - deviceInterfaceDetailData, deviceInterfaceDetailDataSize, - requiredSize, deviceInfoData) != 0; - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // WINSETUPAPI BOOL SetupDiGetDeviceRegistryPropertyW( - // [in] HDEVINFO DeviceInfoSet, - // [in] PSP_DEVINFO_DATA DeviceInfoData, - // [in] DWORD Property, - // [out, optional] PDWORD PropertyRegDataType, - // [out, optional] PBYTE PropertyBuffer, - // [in] DWORD PropertyBufferSize, - // [out, optional] PDWORD RequiredSize - //); - public static boolean SetupDiGetDeviceRegistryPropertyW(Addressable deviceInfoSet, Addressable deviceInfoData, - int property, Addressable propertyRegDataType, - Addressable propertyBuffer, int propertyBufferSize, - Addressable requiredSize) { - try { - return (int) SetupDiGetDeviceRegistryPropertyW$Func.invokeExact(deviceInfoSet, deviceInfoData, - property, propertyRegDataType, - propertyBuffer, propertyBufferSize, - requiredSize) != 0; - } catch (Throwable e) { - throw new RuntimeException(e); - } - } /** * Creates a GUID in native memory. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index 3670b51f..b7df23db 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -7,120 +7,13 @@ package net.codecrete.usb.windows; -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.*; +import java.lang.foreign.MemoryAddress; /** - * Windows Kernel32 functions and Windows helpers. + * Windows helpers. */ public class Win { - public static final int ERROR_NO_MORE_ITEMS = 259; - - public static final int GENERIC_READ = 0x80000000; - public static final int GENERIC_WRITE = 0x40000000; - public static final int GENERIC_EXECUTE = 0x20000000; - public static final int GENERIC_ALL = 0x10000000; - - public static final int FILE_SHARE_READ = 0x00000001; - public static final int FILE_SHARE_WRITE = 0x00000002; - public static final int FILE_SHARE_DELETE = 0x00000004; - - public static final int FILE_ATTRIBUTE_READONLY = 0x00000001; - public static final int FILE_ATTRIBUTE_HIDDEN = 0x00000002; - public static final int FILE_ATTRIBUTE_SYSTEM = 0x00000004; - public static final int FILE_ATTRIBUTE_DIRECTORY = 0x00000010; - public static final int FILE_ATTRIBUTE_ARCHIVE = 0x00000020; - public static final int FILE_ATTRIBUTE_DEVICE = 0x00000040; - public static final int FILE_ATTRIBUTE_NORMAL = 0x00000080; - public static final int FILE_ATTRIBUTE_TEMPORARY = 0x00000100; - - public static final int FILE_FLAG_WRITE_THROUGH = 0x80000000; - public static final int FILE_FLAG_OVERLAPPED = 0x40000000; - public static final int FILE_FLAG_NO_BUFFERING = 0x20000000; - public static final int FILE_FLAG_RANDOM_ACCESS = 0x10000000; - public static final int FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000; - public static final int FILE_FLAG_DELETE_ON_CLOSE = 0x04000000; - - public static final int CREATE_NEW = 1; - public static final int CREATE_ALWAYS = 2; - public static final int OPEN_EXISTING = 3; - public static final int OPEN_ALWAYS = 4; - public static final int TRUNCATE_EXISTING = 5; - - private static final MethodHandle GetLastError$Func; - private static final MethodHandle CreateFileW$Func; - private static final MethodHandle CloseHandle$Func; - private static final MethodHandle DeviceIoControl$Func; - private static final MethodHandle wcslen$Func; - - - static { - var session = MemorySession.openShared(); - Linker linker = Linker.nativeLinker(); - SymbolLookup kernelLookup = SymbolLookup.libraryLookup("Kernel32", session); - - GetLastError$Func = linker.downcallHandle( - kernelLookup.lookup("GetLastError").get(), - FunctionDescriptor.of(JAVA_INT) - ); - - // HANDLE CreateFileW( - // [in] LPCWSTR lpFileName, - // [in] DWORD dwDesiredAccess, - // [in] DWORD dwShareMode, - // [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes, - // [in] DWORD dwCreationDisposition, - // [in] DWORD dwFlagsAndAttributes, - // [in, optional] HANDLE hTemplateFile - //); - CreateFileW$Func = linker.downcallHandle( - kernelLookup.lookup("CreateFileW").get(), - FunctionDescriptor.of(ADDRESS, ADDRESS, JAVA_INT, JAVA_INT, ADDRESS, JAVA_INT, JAVA_INT, ADDRESS) - ); - - // BOOL CloseHandle( - // [in] HANDLE hObject - //); - CloseHandle$Func = linker.downcallHandle( - kernelLookup.lookup("CloseHandle").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS) - ); - - // BOOL DeviceIoControl( - // [in] HANDLE hDevice, - // [in] DWORD dwIoControlCode, - // [in, optional] LPVOID lpInBuffer, - // [in] DWORD nInBufferSize, - // [out, optional] LPVOID lpOutBuffer, - // [in] DWORD nOutBufferSize, - // [out, optional] LPDWORD lpBytesReturned, - // [in, out, optional] LPOVERLAPPED lpOverlapped - //); - DeviceIoControl$Func = linker.downcallHandle( - kernelLookup.lookup("DeviceIoControl").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT, ADDRESS, JAVA_INT, ADDRESS, JAVA_INT, ADDRESS, ADDRESS) - ); - - // size_t wcslen( - // const wchar_t *str - //); - wcslen$Func = linker.downcallHandle( - linker.defaultLookup().lookup("wcslen").get(), - FunctionDescriptor.of(JAVA_LONG, ADDRESS) - ); - } - - public static int GetLastError() { - try { - return (int) GetLastError$Func.invokeExact(); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - /** * Checks if a Windows handle is invalid. * @@ -130,69 +23,4 @@ public static int GetLastError() { public static boolean IsInvalidHandle(MemoryAddress handle) { return handle.toRawLongValue() == -1L; } - - // HANDLE CreateFileW( - // [in] LPCWSTR lpFileName, - // [in] DWORD dwDesiredAccess, - // [in] DWORD dwShareMode, - // [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes, - // [in] DWORD dwCreationDisposition, - // [in] DWORD dwFlagsAndAttributes, - // [in, optional] HANDLE hTemplateFile - //); - public static MemoryAddress CreateFileW(Addressable lpFileName, int dwDesiredAccess, int dwShareMode, - Addressable lpSecurityAttriubtes, int dwCreationDisposition, - int dwFlagsAndAttributes, Addressable hTemplateFile) { - try { - return (MemoryAddress) CreateFileW$Func.invokeExact(lpFileName, dwDesiredAccess, dwShareMode, - lpSecurityAttriubtes, dwCreationDisposition, - dwFlagsAndAttributes, hTemplateFile); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - public static boolean CloseHandle(Addressable handle) { - try { - return (int) CloseHandle$Func.invokeExact(handle) != 0; - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // BOOL DeviceIoControl( - // [in] HANDLE hDevice, - // [in] DWORD dwIoControlCode, - // [in, optional] LPVOID lpInBuffer, - // [in] DWORD nInBufferSize, - // [out, optional] LPVOID lpOutBuffer, - // [in] DWORD nOutBufferSize, - // [out, optional] LPDWORD lpBytesReturned, - // [in, out, optional] LPOVERLAPPED lpOverlapped - //); - public static boolean DeviceIoControl(Addressable hDevice, int dwIOControlCode, - Addressable lpInBuffer, int nInBufferSize, - Addressable lpPoutBuffer, int nOutBufferSize, - Addressable lpBytesReturned, Addressable lpOverlapped) { - try { - return (int) DeviceIoControl$Func.invokeExact(hDevice, dwIOControlCode, - lpInBuffer, nInBufferSize, - lpPoutBuffer, nOutBufferSize, - lpBytesReturned, lpOverlapped) != 0; - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - - // size_t wcslen( - // const wchar_t *str - //); - public static long wcslen(Addressable str) { - try { - return (long) wcslen$Func.invokeExact(str); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WinUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WinUSB.java deleted file mode 100644 index f28b4f8f..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WinUSB.java +++ /dev/null @@ -1,204 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.windows; - -import net.codecrete.usb.common.USBStructs; - -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.*; - -/** - * WinUSB functions. - */ -public class WinUSB { - - private static final MethodHandle Initialize$Func; - private static final MethodHandle Free$Func; - private static final MethodHandle GetDescriptor$Func; - private static final MethodHandle ControlTransfer$Func; - private static final MethodHandle WritePipe$Func; - private static final MethodHandle ReadPipe$Func; - - static { - var session = MemorySession.openShared(); - Linker linker = Linker.nativeLinker(); - SymbolLookup lookup = SymbolLookup.libraryLookup("Winusb", session); - - // BOOL WinUsb_Initialize( - // [in] HANDLE DeviceHandle, - // [out] PWINUSB_INTERFACE_HANDLE InterfaceHandle - //); - Initialize$Func = linker.downcallHandle( - lookup.lookup("WinUsb_Initialize").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS) - ); - - // BOOL WinUsb_Free( - // [in] WINUSB_INTERFACE_HANDLE InterfaceHandle - //); - Free$Func = linker.downcallHandle( - lookup.lookup("WinUsb_Free").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS) - ); - - // BOOL WinUsb_GetDescriptor( - // [in] WINUSB_INTERFACE_HANDLE InterfaceHandle, - // [in] UCHAR DescriptorType, - // [in] UCHAR Index, - // [in] USHORT LanguageID, - // [out] PUCHAR Buffer, - // [in] ULONG BufferLength, - // [out] PULONG LengthTransferred - //); - GetDescriptor$Func = linker.downcallHandle( - lookup.lookup("WinUsb_GetDescriptor").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, JAVA_BYTE, JAVA_SHORT, ADDRESS, JAVA_INT, ADDRESS) - ); - - // BOOL WinUsb_ControlTransfer( - // [in] WINUSB_INTERFACE_HANDLE InterfaceHandle, - // [in] WINUSB_SETUP_PACKET SetupPacket, - // [out] PUCHAR Buffer, - // [in] ULONG BufferLength, - // [out, optional] PULONG LengthTransferred, - // [in, optional] LPOVERLAPPED Overlapped - //); - ControlTransfer$Func = linker.downcallHandle( - lookup.lookup("WinUsb_ControlTransfer").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS, USBStructs.SetupPacket$Struct, ADDRESS, JAVA_INT, ADDRESS, ADDRESS) - ); - - // BOOL WinUsb_WritePipe( - // [in] WINUSB_INTERFACE_HANDLE InterfaceHandle, - // [in] UCHAR PipeID, - // [in] PUCHAR Buffer, - // [in] ULONG BufferLength, - // [out, optional] PULONG LengthTransferred, - // [in, optional] LPOVERLAPPED Overlapped - //); - WritePipe$Func = linker.downcallHandle( - lookup.lookup("WinUsb_WritePipe").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS, JAVA_INT, ADDRESS, ADDRESS) - ); - - // BOOL WinUsb_ReadPipe( - // [in] WINUSB_INTERFACE_HANDLE InterfaceHandle, - // [in] UCHAR PipeID, - // [out] PUCHAR Buffer, - // [in] ULONG BufferLength, - // [out, optional] PULONG LengthTransferred, - // [in, optional] LPOVERLAPPED Overlapped - //); - ReadPipe$Func = linker.downcallHandle( - lookup.lookup("WinUsb_ReadPipe").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS, JAVA_INT, ADDRESS, ADDRESS) - ); - } - - // BOOL WinUsb_Initialize( - // [in] HANDLE DeviceHandle, - // [out] PWINUSB_INTERFACE_HANDLE InterfaceHandle - //); - public static boolean Initialize(Addressable deviceHandle, Addressable interfaceHandleHolder) { - try { - return (int) Initialize$Func.invokeExact(deviceHandle, interfaceHandleHolder) != 0; - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // BOOL WinUsb_Free( - // [in] WINUSB_INTERFACE_HANDLE InterfaceHandle - //); - public static boolean Free(Addressable interfaceHandle) { - try { - return (int) Free$Func.invokeExact(interfaceHandle) != 0; - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // BOOL WinUsb_GetDescriptor( - // [in] WINUSB_INTERFACE_HANDLE InterfaceHandle, - // [in] UCHAR DescriptorType, - // [in] UCHAR Index, - // [in] USHORT LanguageID, - // [out] PUCHAR Buffer, - // [in] ULONG BufferLength, - // [out] PULONG LengthTransferred - //); - public static boolean GetDescriptor(Addressable interfaceHandle, byte descriptorType, byte index, - short languageID, Addressable buffer, int bufferLength, - Addressable lengthTransferredHolder) { - try { - return (int) GetDescriptor$Func.invokeExact(interfaceHandle, descriptorType, index, - languageID, buffer, bufferLength, lengthTransferredHolder) != 0; - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // BOOL WinUsb_ControlTransfer( - // [in] WINUSB_INTERFACE_HANDLE InterfaceHandle, - // [in] WINUSB_SETUP_PACKET SetupPacket, - // [out] PUCHAR Buffer, - // [in] ULONG BufferLength, - // [out, optional] PULONG LengthTransferred, - // [in, optional] LPOVERLAPPED Overlapped - //); - public static boolean ControlTransfer(Addressable interfaceHandle, MemorySegment setupPacket, - Addressable buffer, int bufferLength, - Addressable lengthTransferredHolder, Addressable overlapped) { - try { - return (int) ControlTransfer$Func.invokeExact(interfaceHandle, setupPacket, - buffer, bufferLength, lengthTransferredHolder, overlapped) != 0; - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // BOOL WinUsb_WritePipe( - // [in] WINUSB_INTERFACE_HANDLE InterfaceHandle, - // [in] UCHAR PipeID, - // [in] PUCHAR Buffer, - // [in] ULONG BufferLength, - // [out, optional] PULONG LengthTransferred, - // [in, optional] LPOVERLAPPED Overlapped - //); - public static boolean WritePipe(Addressable interfaceHandle, byte pipeID, - Addressable buffer, int bufferLength, - Addressable lengthTransferredHolder, Addressable overlapped) { - try { - return (int) WritePipe$Func.invokeExact(interfaceHandle, pipeID, - buffer, bufferLength, lengthTransferredHolder, overlapped) != 0; - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // BOOL WinUsb_ReadPipe( - // [in] WINUSB_INTERFACE_HANDLE InterfaceHandle, - // [in] UCHAR PipeID, - // [out] PUCHAR Buffer, - // [in] ULONG BufferLength, - // [out, optional] PULONG LengthTransferred, - // [in, optional] LPOVERLAPPED Overlapped - //); - public static boolean ReadPipe(Addressable interfaceHandle, byte pipeID, - Addressable buffer, int bufferLength, - Addressable lengthTransferredHolder, Addressable overlapped) { - try { - return (int) ReadPipe$Func.invokeExact(interfaceHandle, pipeID, - buffer, bufferLength, lengthTransferredHolder, overlapped) != 0; - } catch (Throwable e) { - throw new RuntimeException(e); - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 90b210b9..1b413694 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -17,6 +17,8 @@ import net.codecrete.usb.common.USBDescriptors; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.common.USBStructs; +import net.codecrete.usb.windows.gen.kernel32.Kernel32; +import net.codecrete.usb.windows.gen.winusb.WinUSB; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; @@ -51,22 +53,22 @@ public class WindowsUSBDevice extends USBDeviceImpl { var chars = path.toCharArray(); var pathSegment = session.allocateArray(ValueLayout.JAVA_CHAR, chars.length + 1); pathSegment.copyFrom(MemorySegment.ofArray(chars)); - device = Win.CreateFileW(pathSegment, - Win.GENERIC_WRITE | Win.GENERIC_READ, - Win.FILE_SHARE_WRITE | Win.FILE_SHARE_READ, + device = Kernel32.CreateFileW(pathSegment, + Kernel32.GENERIC_WRITE() | Kernel32.GENERIC_READ(), + Kernel32.FILE_SHARE_WRITE() | Kernel32.FILE_SHARE_READ(), NULL, - Win.OPEN_EXISTING, - Win.FILE_ATTRIBUTE_NORMAL | Win.FILE_FLAG_OVERLAPPED, + Kernel32.OPEN_EXISTING(), + Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), NULL); if (Win.IsInvalidHandle(device)) - throw new USBException("Cannot open USB device", Win.GetLastError()); + throw new USBException("Cannot open USB device", Kernel32.GetLastError()); try { // open first USB interface var interfaceHandleHolder = session.allocate(ADDRESS); - if (!WinUSB.Initialize(device, interfaceHandleHolder)) - throw new USBException("Cannot open USB device", Win.GetLastError()); + if (WinUSB.WinUsb_Initialize(device, interfaceHandleHolder) == 0) + throw new USBException("Cannot open USB device", Kernel32.GetLastError()); firstInterface = interfaceHandleHolder.get(ADDRESS, 0); @@ -76,12 +78,12 @@ public class WindowsUSBDevice extends USBDeviceImpl { configuration = DescriptorParser.parseConfigurationDescriptor(desc); } catch (Throwable e) { - WinUSB.Free(firstInterface); + WinUSB.WinUsb_Free(firstInterface); throw e; } } catch (Throwable e) { - Win.CloseHandle(device); + Kernel32.CloseHandle(device); throw e; } } @@ -142,8 +144,8 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { var setupPacket = createSetupPacket(session, USBDirection.IN, setup, buffer); var lengthHolder = session.allocate(JAVA_INT); - if (!WinUSB.ControlTransfer(firstInterface, setupPacket, buffer, (int) buffer.byteSize(), lengthHolder, NULL)) - throw new USBException("Control transfer IN failed", Win.GetLastError()); + if (WinUSB.WinUsb_ControlTransfer(firstInterface, setupPacket, buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) + throw new USBException("Control transfer IN failed", Kernel32.GetLastError()); int rxLength = lengthHolder.get(JAVA_INT, 0); return buffer.asSlice(0, rxLength).toArray(JAVA_BYTE); @@ -164,8 +166,8 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { var setupPacket = createSetupPacket(session, USBDirection.OUT, setup, buffer); var lengthHolder = session.allocate(JAVA_INT); - if (!WinUSB.ControlTransfer(firstInterface, setupPacket, buffer, (int) buffer.byteSize(), lengthHolder, NULL)) - throw new USBException("Control transfer OUT failed", Win.GetLastError()); + if (WinUSB.WinUsb_ControlTransfer(firstInterface, setupPacket, buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) + throw new USBException("Control transfer OUT failed", Kernel32.GetLastError()); } } @@ -178,8 +180,8 @@ public void transferOut(int endpointNumber, byte[] data) { buffer.copyFrom(MemorySegment.ofArray(data)); var lengthHolder = session.allocate(JAVA_INT); - if (!WinUSB.WritePipe(firstInterface, endpointAddress, buffer, (int) buffer.byteSize(), lengthHolder, NULL)) - throw new USBException("Control transfer IN failed", Win.GetLastError()); + if (WinUSB.WinUsb_WritePipe(firstInterface, endpointAddress, buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) + throw new USBException("Control transfer IN failed", Kernel32.GetLastError()); } } @@ -191,8 +193,8 @@ public byte[] transferIn(int endpointNumber, int maxLength) { var buffer = session.allocate(maxLength); var lengthHolder = session.allocate(JAVA_INT); - if (!WinUSB.ReadPipe(firstInterface, endpointAddress, buffer, (int) buffer.byteSize(), lengthHolder, NULL)) - throw new USBException("Control transfer IN failed", Win.GetLastError()); + if (WinUSB.WinUsb_ReadPipe(firstInterface, endpointAddress, buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) + throw new USBException("Control transfer IN failed", Kernel32.GetLastError()); int len = lengthHolder.get(JAVA_INT, 0); return buffer.asSlice(0, len).toArray(JAVA_BYTE); @@ -201,7 +203,7 @@ public byte[] transferIn(int endpointNumber, int maxLength) { @Override public void close() throws Exception { - WinUSB.Free(firstInterface); - Win.CloseHandle(device); + WinUSB.WinUsb_Free(firstInterface); + Kernel32.CloseHandle(device); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index f11471d5..9c48636d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -12,6 +12,11 @@ import net.codecrete.usb.common.USBDescriptors; import net.codecrete.usb.common.USBDeviceRegistry; import net.codecrete.usb.common.USBStructs; +import net.codecrete.usb.windows.gen.cfgmgr32.CfgMgr32; +import net.codecrete.usb.windows.gen.kernel32.Kernel32; +import net.codecrete.usb.windows.gen.setupapi.SetupAPI; +import net.codecrete.usb.windows.gen.setupapi._SP_DEVINFO_DATA; +import net.codecrete.usb.windows.gen.stdlib.StdLib; import java.lang.foreign.Addressable; import java.lang.foreign.MemoryAddress; @@ -32,23 +37,23 @@ public List getAllDevices() { try (var outerSession = MemorySession.openConfined()) { // get as set of all USB devices present - final var devInfoSetHandle = SetupApi.SetupDiGetClassDevsW(SetupApi.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, SetupApi.DIGCF_PRESENT | SetupApi.DIGCF_DEVICEINTERFACE); + final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(SetupApi.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); if (Win.IsInvalidHandle(devInfoSetHandle)) throw new USBException("internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left - outerSession.addCloseAction(() -> SetupApi.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); + outerSession.addCloseAction(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); - var devInfo = MemorySegment.allocateNative(SetupApi.SP_DEVINFO_DATA$Struct, outerSession); - SetupApi.SP_DEVINFO_DATA_cbSize.set(devInfo, (int) SetupApi.SP_DEVINFO_DATA$Struct.byteSize()); + var devInfo = MemorySegment.allocateNative(_SP_DEVINFO_DATA.$LAYOUT(), outerSession); + _SP_DEVINFO_DATA.cbSize$set(devInfo, (int) _SP_DEVINFO_DATA.$LAYOUT().byteSize()); - var devInfoData = MemorySegment.allocateNative(SetupApi.SP_DEVINFO_DATA$Struct, outerSession); - SetupApi.SP_DEVINFO_DATA_cbSize.set(devInfoData, (int) SetupApi.SP_DEVINFO_DATA$Struct.byteSize()); + var devInfoData = MemorySegment.allocateNative(_SP_DEVINFO_DATA.$LAYOUT(), outerSession); + _SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) _SP_DEVINFO_DATA.$LAYOUT().byteSize()); for (int i = 0; true; i++) { - if (!SetupApi.SetupDiEnumDeviceInfo(devInfoSetHandle, i, devInfo)) { - int err = Win.GetLastError(); - if (err != Win.ERROR_NO_MORE_ITEMS) { + if (SetupAPI.SetupDiEnumDeviceInfo(devInfoSetHandle, i, devInfo) == 0) { + int err = Kernel32.GetLastError(); + if (err != Kernel32.ERROR_NO_MORE_ITEMS()) { throw new USBException("Internal error (SetupDiEnumDeviceInfo) "); } break; @@ -58,7 +63,7 @@ public List getAllDevices() { // get the parent device (a USB hub) var parentDevInstHolder = session.allocate(JAVA_INT); - int devInst = (int) SetupApi.SP_DEVINFO_DATA_DevInst.get(devInfo); + int devInst = (int) _SP_DEVINFO_DATA.DevInst$get(devInfo); int cmRet = CfgMgr32.CM_Get_Parent(parentDevInstHolder, devInst, 0); if (cmRet != 0) throw new USBException("Internal error (CM_Get_Parent)"); @@ -82,41 +87,41 @@ public List getAllDevices() { var hubPathSeg = session.allocateArray(JAVA_CHAR, hubPath.length()); hubPathSeg.copyFrom(MemorySegment.ofArray(hubPath.toCharArray())); - final var hubHandle = Win.CreateFileW(hubPathSeg, Win.GENERIC_WRITE, Win.FILE_SHARE_WRITE, - NULL, Win.OPEN_EXISTING, 0, NULL); + final var hubHandle = Kernel32.CreateFileW(hubPathSeg, Kernel32.GENERIC_WRITE(), Kernel32.FILE_SHARE_WRITE(), + NULL, Kernel32.OPEN_EXISTING(), 0, NULL); if (Win.IsInvalidHandle(hubHandle)) throw new USBException("Cannot open USB hub"); - session.addCloseAction(() -> Win.CloseHandle(hubHandle)); + session.addCloseAction(() -> Kernel32.CloseHandle(hubHandle)); // get the interface data - if (!SetupApi.SetupDiEnumDeviceInterfaces(devInfoSetHandle, devInfo, - SetupApi.GUID_DEVINTERFACE_USB_DEVICE, 0, devInfoData)) { - int lastError = Win.GetLastError(); - if (lastError == Win.ERROR_NO_MORE_ITEMS) + if (SetupAPI.SetupDiEnumDeviceInterfaces(devInfoSetHandle, devInfo, + SetupApi.GUID_DEVINTERFACE_USB_DEVICE, 0, devInfoData) == 0) { + int lastError = Kernel32.GetLastError(); + if (lastError == Kernel32.ERROR_NO_MORE_ITEMS()) throw new USBException("Internal error (SetupDiEnumDeviceInterfaces)"); continue; } // get path of first interface var intfDetailData = MemorySegment.allocateNative(SetupApi.SP_DEVICE_INTERFACE_DETAIL_DATA_W$Struct, session); - SetupApi.SP_DEVICE_INTERFACE_DETAIL_DATA_cbSize.set(intfDetailData, 8); + SetupApi.SP_DEVICE_INTERFACE_DETAIL_DATA_W_cbSize.set(intfDetailData, 8); int intfDatailDataSize = (int) SetupApi.SP_DEVICE_INTERFACE_DETAIL_DATA_W$Struct.byteSize(); - if (!SetupApi.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devInfoData, - intfDetailData, intfDatailDataSize, NULL, NULL)) - throw new USBException("Internal error (SetupDiGetDeviceInterfaceDetailA - 2)", Win.GetLastError()); + if (SetupAPI.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devInfoData, + intfDetailData, intfDatailDataSize, NULL, NULL) == 0) + throw new USBException("Internal error (SetupDiGetDeviceInterfaceDetailA - 2)", Kernel32.GetLastError()); - long pathLen = Win.wcslen(intfDetailData.address().addOffset(SetupApi.SP_DEVICE_INTERFACE_DETAIL_DATA_DevicePath$Offset)); - char[] devicePathChars = intfDetailData.asSlice(SetupApi.SP_DEVICE_INTERFACE_DETAIL_DATA_DevicePath$Offset, pathLen * 2).toArray(JAVA_CHAR); + long pathLen = StdLib.wcslen(intfDetailData.address().addOffset(SetupApi.SP_DEVICE_INTERFACE_DETAIL_DATA_W_DevicePath$Offset)); + char[] devicePathChars = intfDetailData.asSlice(SetupApi.SP_DEVICE_INTERFACE_DETAIL_DATA_W_DevicePath$Offset, pathLen * 2).toArray(JAVA_CHAR); String devicePath = new String(devicePathChars); // get device's hub port number var usbPortNumHolder = session.allocate(JAVA_INT); var sizeHolder = session.allocate(JAVA_INT); - if (!SetupApi.SetupDiGetDeviceRegistryPropertyW(devInfoSetHandle, devInfo, - SetupApi.SPDRP_ADDRESS, NULL, usbPortNumHolder, - (int) usbPortNumHolder.byteSize(), sizeHolder)) - throw new USBException("Internal error (cannot get device hub port)", Win.GetLastError()); + if (SetupAPI.SetupDiGetDeviceRegistryPropertyW(devInfoSetHandle, devInfo, + SetupAPI.SPDRP_ADDRESS(), NULL, usbPortNumHolder, + (int) usbPortNumHolder.byteSize(), sizeHolder) == 0) + throw new USBException("Internal error (cannot get device hub port)", Kernel32.GetLastError()); int usbPortNum = usbPortNumHolder.get(JAVA_INT, 0); result.add(createDeviceInfo(devicePath, hubHandle, usbPortNum)); @@ -135,11 +140,11 @@ private USBDeviceInfo createDeviceInfo(String devicePath, MemoryAddress hubHandl var connInfo = session.allocate(USBIOCtl.USB_NODE_CONNECTION_INFORMATION_EX$Struct); USBIOCtl.USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex.set(connInfo, usbPortNum); var sizeHolder = session.allocate(JAVA_INT); - if (!Win.DeviceIoControl(hubHandle, USBIOCtl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, + if (Kernel32.DeviceIoControl(hubHandle, USBIOCtl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, connInfo, (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), - sizeHolder, NULL)) - throw new USBException("Internal error (cannot get device descriptor)", Win.GetLastError()); + sizeHolder, NULL) == 0) + throw new USBException("Internal error (cannot get device descriptor)", Kernel32.GetLastError()); byte currentConfigurationValue = (byte) USBIOCtl.USB_NODE_CONNECTION_INFORMATION_EX_CurrentConfigurationValue.get(connInfo); @@ -188,11 +193,11 @@ private String getStringDescriptor(Addressable hubHandle, int usbPortNumber, int USBStructs.SetupPacket_wLength.set(setupPacket, (short) dataLen); var sizeHolder = session.allocate(JAVA_INT); - if (!Win.DeviceIoControl(hubHandle, USBIOCtl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + if (Kernel32.DeviceIoControl(hubHandle, USBIOCtl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, descriptorRequest, (int) descriptorRequest.byteSize(), descriptorRequest, (int) descriptorRequest.byteSize(), - sizeHolder, NULL)) - throw new USBException(String.format("Cannot retrieve string descriptor %d", index), Win.GetLastError()); + sizeHolder, NULL) == 0) + throw new USBException(String.format("Cannot retrieve string descriptor %d", index), Kernel32.GetLastError()); var stringDesc = descriptorRequest.asSlice(USBIOCtl.USB_DESCRIPTOR_REQUEST_Data$Offset, dataLen); int stringLen = 255 & (byte) USBIOCtl.USB_STRING_DESCRIPTOR_bLength.get(stringDesc); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/CfgMgr32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/CfgMgr32.java new file mode 100644 index 00000000..b7b83db0 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/CfgMgr32.java @@ -0,0 +1,44 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.cfgmgr32; + +import java.lang.foreign.Addressable; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.*; +public class CfgMgr32 { + + /* package-private */ CfgMgr32() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static MethodHandle CM_Get_Device_IDW$MH() { + return RuntimeHelper.requireNonNull(constants$0.CM_Get_Device_IDW$MH,"CM_Get_Device_IDW"); + } + public static int CM_Get_Device_IDW ( int dnDevInst, Addressable Buffer, int BufferLen, int ulFlags) { + var mh$ = CM_Get_Device_IDW$MH(); + try { + return (int)mh$.invokeExact(dnDevInst, Buffer, BufferLen, ulFlags); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle CM_Get_Parent$MH() { + return RuntimeHelper.requireNonNull(constants$0.CM_Get_Parent$MH,"CM_Get_Parent"); + } + public static int CM_Get_Parent ( Addressable pdnDevInst, int dnDevInst, int ulFlags) { + var mh$ = CM_Get_Parent$MH(); + try { + return (int)mh$.invokeExact(pdnDevInst, dnDevInst, ulFlags); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/Constants$root.java new file mode 100644 index 00000000..0f04844e --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.cfgmgr32; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/RuntimeHelper.java new file mode 100644 index 00000000..3ac64e04 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/RuntimeHelper.java @@ -0,0 +1,216 @@ +package net.codecrete.usb.windows.gen.cfgmgr32; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + System.loadLibrary("Cfgmgr32"); + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/constants$0.java new file mode 100644 index 00000000..de3dd42c --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/constants$0.java @@ -0,0 +1,30 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.cfgmgr32; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor CM_Get_Device_IDW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG$LAYOUT + ); + static final MethodHandle CM_Get_Device_IDW$MH = RuntimeHelper.downcallHandle( + "CM_Get_Device_IDW", + constants$0.CM_Get_Device_IDW$FUNC + ); + static final FunctionDescriptor CM_Get_Parent$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG$LAYOUT + ); + static final MethodHandle CM_Get_Parent$MH = RuntimeHelper.downcallHandle( + "CM_Get_Parent", + constants$0.CM_Get_Parent$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Constants$root.java new file mode 100644 index 00000000..bfc827c7 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.kernel32; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java new file mode 100644 index 00000000..21d2b421 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -0,0 +1,91 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.kernel32; + +import java.lang.foreign.Addressable; +import java.lang.foreign.MemoryAddress; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.*; +public class Kernel32 { + + /* package-private */ Kernel32() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static int FILE_SHARE_READ() { + return (int)1L; + } + public static int FILE_SHARE_WRITE() { + return (int)2L; + } + public static int FILE_ATTRIBUTE_NORMAL() { + return (int)128L; + } + public static int OPEN_EXISTING() { + return (int)3L; + } + public static int FILE_FLAG_OVERLAPPED() { + return (int)1073741824L; + } + public static MethodHandle CreateFileW$MH() { + return RuntimeHelper.requireNonNull(constants$0.CreateFileW$MH,"CreateFileW"); + } + public static MemoryAddress CreateFileW ( Addressable lpFileName, int dwDesiredAccess, int dwShareMode, Addressable lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, Addressable hTemplateFile) { + var mh$ = CreateFileW$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle CloseHandle$MH() { + return RuntimeHelper.requireNonNull(constants$0.CloseHandle$MH,"CloseHandle"); + } + public static int CloseHandle ( Addressable hObject) { + var mh$ = CloseHandle$MH(); + try { + return (int)mh$.invokeExact(hObject); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle GetLastError$MH() { + return RuntimeHelper.requireNonNull(constants$0.GetLastError$MH,"GetLastError"); + } + public static int GetLastError () { + var mh$ = GetLastError$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle DeviceIoControl$MH() { + return RuntimeHelper.requireNonNull(constants$0.DeviceIoControl$MH,"DeviceIoControl"); + } + public static int DeviceIoControl ( Addressable hDevice, int dwIoControlCode, Addressable lpInBuffer, int nInBufferSize, Addressable lpOutBuffer, int nOutBufferSize, Addressable lpBytesReturned, Addressable lpOverlapped) { + var mh$ = DeviceIoControl$MH(); + try { + return (int)mh$.invokeExact(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static int GENERIC_READ() { + return (int)2147483648L; + } + public static int GENERIC_WRITE() { + return (int)1073741824L; + } + public static int ERROR_NO_MORE_ITEMS() { + return (int)259L; + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java new file mode 100644 index 00000000..2ed328fb --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java @@ -0,0 +1,216 @@ +package net.codecrete.usb.windows.gen.kernel32; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + System.loadLibrary("Kernel32"); + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java new file mode 100644 index 00000000..a350bf86 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java @@ -0,0 +1,50 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.kernel32; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor CreateFileW$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CreateFileW$MH = RuntimeHelper.downcallHandle( + "CreateFileW", + constants$0.CreateFileW$FUNC + ); + static final FunctionDescriptor CloseHandle$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CloseHandle$MH = RuntimeHelper.downcallHandle( + "CloseHandle", + constants$0.CloseHandle$FUNC + ); + static final FunctionDescriptor GetLastError$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT); + static final MethodHandle GetLastError$MH = RuntimeHelper.downcallHandle( + "GetLastError", + constants$0.GetLastError$FUNC + ); + static final FunctionDescriptor DeviceIoControl$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle DeviceIoControl$MH = RuntimeHelper.downcallHandle( + "DeviceIoControl", + constants$0.DeviceIoControl$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/Constants$root.java new file mode 100644 index 00000000..b6bb6431 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.setupapi; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java new file mode 100644 index 00000000..55f8e04a --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java @@ -0,0 +1,216 @@ +package net.codecrete.usb.windows.gen.setupapi; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + System.loadLibrary("SetupAPI"); + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java new file mode 100644 index 00000000..88cd7162 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java @@ -0,0 +1,98 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.setupapi; + +import java.lang.foreign.Addressable; +import java.lang.foreign.MemoryAddress; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.*; +public class SetupAPI { + + /* package-private */ SetupAPI() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static int DIGCF_PRESENT() { + return (int)2L; + } + public static int DIGCF_DEVICEINTERFACE() { + return (int)16L; + } + public static MethodHandle SetupDiEnumDeviceInfo$MH() { + return RuntimeHelper.requireNonNull(constants$0.SetupDiEnumDeviceInfo$MH,"SetupDiEnumDeviceInfo"); + } + public static int SetupDiEnumDeviceInfo ( Addressable DeviceInfoSet, int MemberIndex, Addressable DeviceInfoData) { + var mh$ = SetupDiEnumDeviceInfo$MH(); + try { + return (int)mh$.invokeExact(DeviceInfoSet, MemberIndex, DeviceInfoData); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle SetupDiDestroyDeviceInfoList$MH() { + return RuntimeHelper.requireNonNull(constants$0.SetupDiDestroyDeviceInfoList$MH,"SetupDiDestroyDeviceInfoList"); + } + public static int SetupDiDestroyDeviceInfoList ( Addressable DeviceInfoSet) { + var mh$ = SetupDiDestroyDeviceInfoList$MH(); + try { + return (int)mh$.invokeExact(DeviceInfoSet); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle SetupDiEnumDeviceInterfaces$MH() { + return RuntimeHelper.requireNonNull(constants$0.SetupDiEnumDeviceInterfaces$MH,"SetupDiEnumDeviceInterfaces"); + } + public static int SetupDiEnumDeviceInterfaces ( Addressable DeviceInfoSet, Addressable DeviceInfoData, Addressable InterfaceClassGuid, int MemberIndex, Addressable DeviceInterfaceData) { + var mh$ = SetupDiEnumDeviceInterfaces$MH(); + try { + return (int)mh$.invokeExact(DeviceInfoSet, DeviceInfoData, InterfaceClassGuid, MemberIndex, DeviceInterfaceData); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle SetupDiGetDeviceInterfaceDetailW$MH() { + return RuntimeHelper.requireNonNull(constants$0.SetupDiGetDeviceInterfaceDetailW$MH,"SetupDiGetDeviceInterfaceDetailW"); + } + public static int SetupDiGetDeviceInterfaceDetailW ( Addressable DeviceInfoSet, Addressable DeviceInterfaceData, Addressable DeviceInterfaceDetailData, int DeviceInterfaceDetailDataSize, Addressable RequiredSize, Addressable DeviceInfoData) { + var mh$ = SetupDiGetDeviceInterfaceDetailW$MH(); + try { + return (int)mh$.invokeExact(DeviceInfoSet, DeviceInterfaceData, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle SetupDiGetClassDevsW$MH() { + return RuntimeHelper.requireNonNull(constants$0.SetupDiGetClassDevsW$MH,"SetupDiGetClassDevsW"); + } + public static MemoryAddress SetupDiGetClassDevsW ( Addressable ClassGuid, Addressable Enumerator, Addressable hwndParent, int Flags) { + var mh$ = SetupDiGetClassDevsW$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(ClassGuid, Enumerator, hwndParent, Flags); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle SetupDiGetDeviceRegistryPropertyW$MH() { + return RuntimeHelper.requireNonNull(constants$0.SetupDiGetDeviceRegistryPropertyW$MH,"SetupDiGetDeviceRegistryPropertyW"); + } + public static int SetupDiGetDeviceRegistryPropertyW ( Addressable DeviceInfoSet, Addressable DeviceInfoData, int Property, Addressable PropertyRegDataType, Addressable PropertyBuffer, int PropertyBufferSize, Addressable RequiredSize) { + var mh$ = SetupDiGetDeviceRegistryPropertyW$MH(); + try { + return (int)mh$.invokeExact(DeviceInfoSet, DeviceInfoData, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static int SPDRP_ADDRESS() { + return (int)28L; + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java new file mode 100644 index 00000000..de057457 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java @@ -0,0 +1,82 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.setupapi; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class _SP_DEVICE_INTERFACE_DATA { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_LONG$LAYOUT.withName("cbSize"), + MemoryLayout.structLayout( + Constants$root.C_LONG$LAYOUT.withName("Data1"), + Constants$root.C_SHORT$LAYOUT.withName("Data2"), + Constants$root.C_SHORT$LAYOUT.withName("Data3"), + MemoryLayout.sequenceLayout(8, Constants$root.C_CHAR$LAYOUT).withName("Data4") + ).withName("InterfaceClassGuid"), + Constants$root.C_LONG$LAYOUT.withName("Flags"), + Constants$root.C_LONG_LONG$LAYOUT.withName("Reserved") + ).withName("_SP_DEVICE_INTERFACE_DATA"); + public static MemoryLayout $LAYOUT() { + return _SP_DEVICE_INTERFACE_DATA.$struct$LAYOUT; + } + static final VarHandle cbSize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("cbSize")); + public static VarHandle cbSize$VH() { + return _SP_DEVICE_INTERFACE_DATA.cbSize$VH; + } + public static int cbSize$get(MemorySegment seg) { + return (int)_SP_DEVICE_INTERFACE_DATA.cbSize$VH.get(seg); + } + public static void cbSize$set( MemorySegment seg, int x) { + _SP_DEVICE_INTERFACE_DATA.cbSize$VH.set(seg, x); + } + public static int cbSize$get(MemorySegment seg, long index) { + return (int)_SP_DEVICE_INTERFACE_DATA.cbSize$VH.get(seg.asSlice(index*sizeof())); + } + public static void cbSize$set(MemorySegment seg, long index, int x) { + _SP_DEVICE_INTERFACE_DATA.cbSize$VH.set(seg.asSlice(index*sizeof()), x); + } + public static MemorySegment InterfaceClassGuid$slice(MemorySegment seg) { + return seg.asSlice(4, 16); + } + static final VarHandle Flags$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Flags")); + public static VarHandle Flags$VH() { + return _SP_DEVICE_INTERFACE_DATA.Flags$VH; + } + public static int Flags$get(MemorySegment seg) { + return (int)_SP_DEVICE_INTERFACE_DATA.Flags$VH.get(seg); + } + public static void Flags$set( MemorySegment seg, int x) { + _SP_DEVICE_INTERFACE_DATA.Flags$VH.set(seg, x); + } + public static int Flags$get(MemorySegment seg, long index) { + return (int)_SP_DEVICE_INTERFACE_DATA.Flags$VH.get(seg.asSlice(index*sizeof())); + } + public static void Flags$set(MemorySegment seg, long index, int x) { + _SP_DEVICE_INTERFACE_DATA.Flags$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle Reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Reserved")); + public static VarHandle Reserved$VH() { + return _SP_DEVICE_INTERFACE_DATA.Reserved$VH; + } + public static long Reserved$get(MemorySegment seg) { + return (long)_SP_DEVICE_INTERFACE_DATA.Reserved$VH.get(seg); + } + public static void Reserved$set( MemorySegment seg, long x) { + _SP_DEVICE_INTERFACE_DATA.Reserved$VH.set(seg, x); + } + public static long Reserved$get(MemorySegment seg, long index) { + return (long)_SP_DEVICE_INTERFACE_DATA.Reserved$VH.get(seg.asSlice(index*sizeof())); + } + public static void Reserved$set(MemorySegment seg, long index, long x) { + _SP_DEVICE_INTERFACE_DATA.Reserved$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java new file mode 100644 index 00000000..bc3ac979 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java @@ -0,0 +1,44 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.setupapi; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class _SP_DEVICE_INTERFACE_DETAIL_DATA_W { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_LONG$LAYOUT.withName("cbSize"), + MemoryLayout.sequenceLayout(1, Constants$root.C_SHORT$LAYOUT).withName("DevicePath"), + MemoryLayout.paddingLayout(16) + ).withName("_SP_DEVICE_INTERFACE_DETAIL_DATA_W"); + public static MemoryLayout $LAYOUT() { + return _SP_DEVICE_INTERFACE_DETAIL_DATA_W.$struct$LAYOUT; + } + static final VarHandle cbSize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("cbSize")); + public static VarHandle cbSize$VH() { + return _SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$VH; + } + public static int cbSize$get(MemorySegment seg) { + return (int)_SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$VH.get(seg); + } + public static void cbSize$set( MemorySegment seg, int x) { + _SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$VH.set(seg, x); + } + public static int cbSize$get(MemorySegment seg, long index) { + return (int)_SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$VH.get(seg.asSlice(index*sizeof())); + } + public static void cbSize$set(MemorySegment seg, long index, int x) { + _SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$VH.set(seg.asSlice(index*sizeof()), x); + } + public static MemorySegment DevicePath$slice(MemorySegment seg) { + return seg.asSlice(4, 2); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java new file mode 100644 index 00000000..dbba0ab5 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java @@ -0,0 +1,82 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.setupapi; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class _SP_DEVINFO_DATA { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_LONG$LAYOUT.withName("cbSize"), + MemoryLayout.structLayout( + Constants$root.C_LONG$LAYOUT.withName("Data1"), + Constants$root.C_SHORT$LAYOUT.withName("Data2"), + Constants$root.C_SHORT$LAYOUT.withName("Data3"), + MemoryLayout.sequenceLayout(8, Constants$root.C_CHAR$LAYOUT).withName("Data4") + ).withName("ClassGuid"), + Constants$root.C_LONG$LAYOUT.withName("DevInst"), + Constants$root.C_LONG_LONG$LAYOUT.withName("Reserved") + ).withName("_SP_DEVINFO_DATA"); + public static MemoryLayout $LAYOUT() { + return _SP_DEVINFO_DATA.$struct$LAYOUT; + } + static final VarHandle cbSize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("cbSize")); + public static VarHandle cbSize$VH() { + return _SP_DEVINFO_DATA.cbSize$VH; + } + public static int cbSize$get(MemorySegment seg) { + return (int)_SP_DEVINFO_DATA.cbSize$VH.get(seg); + } + public static void cbSize$set( MemorySegment seg, int x) { + _SP_DEVINFO_DATA.cbSize$VH.set(seg, x); + } + public static int cbSize$get(MemorySegment seg, long index) { + return (int)_SP_DEVINFO_DATA.cbSize$VH.get(seg.asSlice(index*sizeof())); + } + public static void cbSize$set(MemorySegment seg, long index, int x) { + _SP_DEVINFO_DATA.cbSize$VH.set(seg.asSlice(index*sizeof()), x); + } + public static MemorySegment ClassGuid$slice(MemorySegment seg) { + return seg.asSlice(4, 16); + } + static final VarHandle DevInst$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DevInst")); + public static VarHandle DevInst$VH() { + return _SP_DEVINFO_DATA.DevInst$VH; + } + public static int DevInst$get(MemorySegment seg) { + return (int)_SP_DEVINFO_DATA.DevInst$VH.get(seg); + } + public static void DevInst$set( MemorySegment seg, int x) { + _SP_DEVINFO_DATA.DevInst$VH.set(seg, x); + } + public static int DevInst$get(MemorySegment seg, long index) { + return (int)_SP_DEVINFO_DATA.DevInst$VH.get(seg.asSlice(index*sizeof())); + } + public static void DevInst$set(MemorySegment seg, long index, int x) { + _SP_DEVINFO_DATA.DevInst$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle Reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Reserved")); + public static VarHandle Reserved$VH() { + return _SP_DEVINFO_DATA.Reserved$VH; + } + public static long Reserved$get(MemorySegment seg) { + return (long)_SP_DEVINFO_DATA.Reserved$VH.get(seg); + } + public static void Reserved$set( MemorySegment seg, long x) { + _SP_DEVINFO_DATA.Reserved$VH.set(seg, x); + } + public static long Reserved$get(MemorySegment seg, long index) { + return (long)_SP_DEVINFO_DATA.Reserved$VH.get(seg.asSlice(index*sizeof())); + } + public static void Reserved$set(MemorySegment seg, long index, long x) { + _SP_DEVINFO_DATA.Reserved$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java new file mode 100644 index 00000000..1c6554b3 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java @@ -0,0 +1,73 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.setupapi; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor SetupDiEnumDeviceInfo$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle SetupDiEnumDeviceInfo$MH = RuntimeHelper.downcallHandle( + "SetupDiEnumDeviceInfo", + constants$0.SetupDiEnumDeviceInfo$FUNC + ); + static final FunctionDescriptor SetupDiDestroyDeviceInfoList$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle SetupDiDestroyDeviceInfoList$MH = RuntimeHelper.downcallHandle( + "SetupDiDestroyDeviceInfoList", + constants$0.SetupDiDestroyDeviceInfoList$FUNC + ); + static final FunctionDescriptor SetupDiEnumDeviceInterfaces$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle SetupDiEnumDeviceInterfaces$MH = RuntimeHelper.downcallHandle( + "SetupDiEnumDeviceInterfaces", + constants$0.SetupDiEnumDeviceInterfaces$FUNC + ); + static final FunctionDescriptor SetupDiGetDeviceInterfaceDetailW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle SetupDiGetDeviceInterfaceDetailW$MH = RuntimeHelper.downcallHandle( + "SetupDiGetDeviceInterfaceDetailW", + constants$0.SetupDiGetDeviceInterfaceDetailW$FUNC + ); + static final FunctionDescriptor SetupDiGetClassDevsW$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT + ); + static final MethodHandle SetupDiGetClassDevsW$MH = RuntimeHelper.downcallHandle( + "SetupDiGetClassDevsW", + constants$0.SetupDiGetClassDevsW$FUNC + ); + static final FunctionDescriptor SetupDiGetDeviceRegistryPropertyW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle SetupDiGetDeviceRegistryPropertyW$MH = RuntimeHelper.downcallHandle( + "SetupDiGetDeviceRegistryPropertyW", + constants$0.SetupDiGetDeviceRegistryPropertyW$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/Constants$root.java new file mode 100644 index 00000000..80f6c451 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.stdlib; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/RuntimeHelper.java new file mode 100644 index 00000000..ffabd418 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/RuntimeHelper.java @@ -0,0 +1,216 @@ +package net.codecrete.usb.windows.gen.stdlib; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/StdLib.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/StdLib.java new file mode 100644 index 00000000..e76fe363 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/StdLib.java @@ -0,0 +1,33 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.stdlib; + +import java.lang.foreign.Addressable; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.*; +public class StdLib { + + /* package-private */ StdLib() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static MethodHandle wcslen$MH() { + return RuntimeHelper.requireNonNull(constants$0.wcslen$MH,"wcslen"); + } + public static long wcslen ( Addressable _String) { + var mh$ = wcslen$MH(); + try { + return (long)mh$.invokeExact(_String); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/constants$0.java new file mode 100644 index 00000000..5ca00b1c --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/constants$0.java @@ -0,0 +1,18 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.stdlib; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor wcslen$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle wcslen$MH = RuntimeHelper.downcallHandle( + "wcslen", + constants$0.wcslen$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/Constants$root.java new file mode 100644 index 00000000..66ce20c5 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.usbioctl; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java new file mode 100644 index 00000000..5e1c6f71 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java @@ -0,0 +1,216 @@ +package net.codecrete.usb.windows.gen.usbioctl; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java new file mode 100644 index 00000000..d6a326fe --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.usbioctl; + +import static java.lang.foreign.ValueLayout.*; +public class USBIoctl { + + /* package-private */ USBIoctl() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java new file mode 100644 index 00000000..892dd93d --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java @@ -0,0 +1,171 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.usbioctl; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class _USB_NODE_CONNECTION_INFORMATION_EX { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_LONG$LAYOUT.withName("ConnectionIndex"), + MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("bLength"), + Constants$root.C_CHAR$LAYOUT.withName("bDescriptorType"), + Constants$root.C_SHORT$LAYOUT.withName("bcdUSB"), + Constants$root.C_CHAR$LAYOUT.withName("bDeviceClass"), + Constants$root.C_CHAR$LAYOUT.withName("bDeviceSubClass"), + Constants$root.C_CHAR$LAYOUT.withName("bDeviceProtocol"), + Constants$root.C_CHAR$LAYOUT.withName("bMaxPacketSize0"), + Constants$root.C_SHORT$LAYOUT.withName("idVendor"), + Constants$root.C_SHORT$LAYOUT.withName("idProduct"), + Constants$root.C_SHORT$LAYOUT.withName("bcdDevice"), + Constants$root.C_CHAR$LAYOUT.withName("iManufacturer"), + Constants$root.C_CHAR$LAYOUT.withName("iProduct"), + Constants$root.C_CHAR$LAYOUT.withName("iSerialNumber"), + Constants$root.C_CHAR$LAYOUT.withName("bNumConfigurations") + ).withName("DeviceDescriptor"), + Constants$root.C_CHAR$LAYOUT.withName("CurrentConfigurationValue"), + Constants$root.C_CHAR$LAYOUT.withName("Speed"), + Constants$root.C_CHAR$LAYOUT.withName("DeviceIsHub"), + Constants$root.C_SHORT$LAYOUT.withName("DeviceAddress"), + Constants$root.C_LONG$LAYOUT.withName("NumberOfOpenPipes"), + Constants$root.C_LONG$LAYOUT.withName("ConnectionStatus"), + MemoryLayout.sequenceLayout(0, MemoryLayout.structLayout( + MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("bLength"), + Constants$root.C_CHAR$LAYOUT.withName("bDescriptorType"), + Constants$root.C_CHAR$LAYOUT.withName("bEndpointAddress"), + Constants$root.C_CHAR$LAYOUT.withName("bmAttributes"), + Constants$root.C_SHORT$LAYOUT.withName("wMaxPacketSize"), + Constants$root.C_CHAR$LAYOUT.withName("bInterval") + ).withName("EndpointDescriptor"), + Constants$root.C_LONG$LAYOUT.withName("ScheduleOffset") + ).withName("_USB_PIPE_INFO")).withName("PipeList") + ).withName("_USB_NODE_CONNECTION_INFORMATION_EX"); + public static MemoryLayout $LAYOUT() { + return _USB_NODE_CONNECTION_INFORMATION_EX.$struct$LAYOUT; + } + static final VarHandle ConnectionIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ConnectionIndex")); + public static VarHandle ConnectionIndex$VH() { + return _USB_NODE_CONNECTION_INFORMATION_EX.ConnectionIndex$VH; + } + public static int ConnectionIndex$get(MemorySegment seg) { + return (int)_USB_NODE_CONNECTION_INFORMATION_EX.ConnectionIndex$VH.get(seg); + } + public static void ConnectionIndex$set( MemorySegment seg, int x) { + _USB_NODE_CONNECTION_INFORMATION_EX.ConnectionIndex$VH.set(seg, x); + } + public static int ConnectionIndex$get(MemorySegment seg, long index) { + return (int)_USB_NODE_CONNECTION_INFORMATION_EX.ConnectionIndex$VH.get(seg.asSlice(index*sizeof())); + } + public static void ConnectionIndex$set(MemorySegment seg, long index, int x) { + _USB_NODE_CONNECTION_INFORMATION_EX.ConnectionIndex$VH.set(seg.asSlice(index*sizeof()), x); + } + public static MemorySegment DeviceDescriptor$slice(MemorySegment seg) { + return seg.asSlice(4, 18); + } + static final VarHandle CurrentConfigurationValue$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CurrentConfigurationValue")); + public static VarHandle CurrentConfigurationValue$VH() { + return _USB_NODE_CONNECTION_INFORMATION_EX.CurrentConfigurationValue$VH; + } + public static byte CurrentConfigurationValue$get(MemorySegment seg) { + return (byte)_USB_NODE_CONNECTION_INFORMATION_EX.CurrentConfigurationValue$VH.get(seg); + } + public static void CurrentConfigurationValue$set( MemorySegment seg, byte x) { + _USB_NODE_CONNECTION_INFORMATION_EX.CurrentConfigurationValue$VH.set(seg, x); + } + public static byte CurrentConfigurationValue$get(MemorySegment seg, long index) { + return (byte)_USB_NODE_CONNECTION_INFORMATION_EX.CurrentConfigurationValue$VH.get(seg.asSlice(index*sizeof())); + } + public static void CurrentConfigurationValue$set(MemorySegment seg, long index, byte x) { + _USB_NODE_CONNECTION_INFORMATION_EX.CurrentConfigurationValue$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle Speed$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Speed")); + public static VarHandle Speed$VH() { + return _USB_NODE_CONNECTION_INFORMATION_EX.Speed$VH; + } + public static byte Speed$get(MemorySegment seg) { + return (byte)_USB_NODE_CONNECTION_INFORMATION_EX.Speed$VH.get(seg); + } + public static void Speed$set( MemorySegment seg, byte x) { + _USB_NODE_CONNECTION_INFORMATION_EX.Speed$VH.set(seg, x); + } + public static byte Speed$get(MemorySegment seg, long index) { + return (byte)_USB_NODE_CONNECTION_INFORMATION_EX.Speed$VH.get(seg.asSlice(index*sizeof())); + } + public static void Speed$set(MemorySegment seg, long index, byte x) { + _USB_NODE_CONNECTION_INFORMATION_EX.Speed$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle DeviceIsHub$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceIsHub")); + public static VarHandle DeviceIsHub$VH() { + return _USB_NODE_CONNECTION_INFORMATION_EX.DeviceIsHub$VH; + } + public static byte DeviceIsHub$get(MemorySegment seg) { + return (byte)_USB_NODE_CONNECTION_INFORMATION_EX.DeviceIsHub$VH.get(seg); + } + public static void DeviceIsHub$set( MemorySegment seg, byte x) { + _USB_NODE_CONNECTION_INFORMATION_EX.DeviceIsHub$VH.set(seg, x); + } + public static byte DeviceIsHub$get(MemorySegment seg, long index) { + return (byte)_USB_NODE_CONNECTION_INFORMATION_EX.DeviceIsHub$VH.get(seg.asSlice(index*sizeof())); + } + public static void DeviceIsHub$set(MemorySegment seg, long index, byte x) { + _USB_NODE_CONNECTION_INFORMATION_EX.DeviceIsHub$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle DeviceAddress$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceAddress")); + public static VarHandle DeviceAddress$VH() { + return _USB_NODE_CONNECTION_INFORMATION_EX.DeviceAddress$VH; + } + public static short DeviceAddress$get(MemorySegment seg) { + return (short)_USB_NODE_CONNECTION_INFORMATION_EX.DeviceAddress$VH.get(seg); + } + public static void DeviceAddress$set( MemorySegment seg, short x) { + _USB_NODE_CONNECTION_INFORMATION_EX.DeviceAddress$VH.set(seg, x); + } + public static short DeviceAddress$get(MemorySegment seg, long index) { + return (short)_USB_NODE_CONNECTION_INFORMATION_EX.DeviceAddress$VH.get(seg.asSlice(index*sizeof())); + } + public static void DeviceAddress$set(MemorySegment seg, long index, short x) { + _USB_NODE_CONNECTION_INFORMATION_EX.DeviceAddress$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle NumberOfOpenPipes$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("NumberOfOpenPipes")); + public static VarHandle NumberOfOpenPipes$VH() { + return _USB_NODE_CONNECTION_INFORMATION_EX.NumberOfOpenPipes$VH; + } + public static int NumberOfOpenPipes$get(MemorySegment seg) { + return (int)_USB_NODE_CONNECTION_INFORMATION_EX.NumberOfOpenPipes$VH.get(seg); + } + public static void NumberOfOpenPipes$set( MemorySegment seg, int x) { + _USB_NODE_CONNECTION_INFORMATION_EX.NumberOfOpenPipes$VH.set(seg, x); + } + public static int NumberOfOpenPipes$get(MemorySegment seg, long index) { + return (int)_USB_NODE_CONNECTION_INFORMATION_EX.NumberOfOpenPipes$VH.get(seg.asSlice(index*sizeof())); + } + public static void NumberOfOpenPipes$set(MemorySegment seg, long index, int x) { + _USB_NODE_CONNECTION_INFORMATION_EX.NumberOfOpenPipes$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle ConnectionStatus$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ConnectionStatus")); + public static VarHandle ConnectionStatus$VH() { + return _USB_NODE_CONNECTION_INFORMATION_EX.ConnectionStatus$VH; + } + public static int ConnectionStatus$get(MemorySegment seg) { + return (int)_USB_NODE_CONNECTION_INFORMATION_EX.ConnectionStatus$VH.get(seg); + } + public static void ConnectionStatus$set( MemorySegment seg, int x) { + _USB_NODE_CONNECTION_INFORMATION_EX.ConnectionStatus$VH.set(seg, x); + } + public static int ConnectionStatus$get(MemorySegment seg, long index) { + return (int)_USB_NODE_CONNECTION_INFORMATION_EX.ConnectionStatus$VH.get(seg.asSlice(index*sizeof())); + } + public static void ConnectionStatus$set(MemorySegment seg, long index, int x) { + _USB_NODE_CONNECTION_INFORMATION_EX.ConnectionStatus$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/Constants$root.java new file mode 100644 index 00000000..3568e394 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.winusb; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java new file mode 100644 index 00000000..f4a55475 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java @@ -0,0 +1,216 @@ +package net.codecrete.usb.windows.gen.winusb; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + System.loadLibrary("Winusb"); + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java new file mode 100644 index 00000000..43250a47 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java @@ -0,0 +1,89 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.winusb; + +import java.lang.foreign.Addressable; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.*; +public class WinUSB { + + /* package-private */ WinUSB() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static MethodHandle WinUsb_Initialize$MH() { + return RuntimeHelper.requireNonNull(constants$0.WinUsb_Initialize$MH,"WinUsb_Initialize"); + } + public static int WinUsb_Initialize ( Addressable DeviceHandle, Addressable InterfaceHandle) { + var mh$ = WinUsb_Initialize$MH(); + try { + return (int)mh$.invokeExact(DeviceHandle, InterfaceHandle); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle WinUsb_Free$MH() { + return RuntimeHelper.requireNonNull(constants$0.WinUsb_Free$MH,"WinUsb_Free"); + } + public static int WinUsb_Free ( Addressable InterfaceHandle) { + var mh$ = WinUsb_Free$MH(); + try { + return (int)mh$.invokeExact(InterfaceHandle); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle WinUsb_GetDescriptor$MH() { + return RuntimeHelper.requireNonNull(constants$0.WinUsb_GetDescriptor$MH,"WinUsb_GetDescriptor"); + } + public static int WinUsb_GetDescriptor ( Addressable InterfaceHandle, byte DescriptorType, byte Index, short LanguageID, Addressable Buffer, int BufferLength, Addressable LengthTransferred) { + var mh$ = WinUsb_GetDescriptor$MH(); + try { + return (int)mh$.invokeExact(InterfaceHandle, DescriptorType, Index, LanguageID, Buffer, BufferLength, LengthTransferred); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle WinUsb_ReadPipe$MH() { + return RuntimeHelper.requireNonNull(constants$0.WinUsb_ReadPipe$MH,"WinUsb_ReadPipe"); + } + public static int WinUsb_ReadPipe ( Addressable InterfaceHandle, byte PipeID, Addressable Buffer, int BufferLength, Addressable LengthTransferred, Addressable Overlapped) { + var mh$ = WinUsb_ReadPipe$MH(); + try { + return (int)mh$.invokeExact(InterfaceHandle, PipeID, Buffer, BufferLength, LengthTransferred, Overlapped); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle WinUsb_WritePipe$MH() { + return RuntimeHelper.requireNonNull(constants$0.WinUsb_WritePipe$MH,"WinUsb_WritePipe"); + } + public static int WinUsb_WritePipe ( Addressable InterfaceHandle, byte PipeID, Addressable Buffer, int BufferLength, Addressable LengthTransferred, Addressable Overlapped) { + var mh$ = WinUsb_WritePipe$MH(); + try { + return (int)mh$.invokeExact(InterfaceHandle, PipeID, Buffer, BufferLength, LengthTransferred, Overlapped); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle WinUsb_ControlTransfer$MH() { + return RuntimeHelper.requireNonNull(constants$0.WinUsb_ControlTransfer$MH,"WinUsb_ControlTransfer"); + } + public static int WinUsb_ControlTransfer ( Addressable InterfaceHandle, MemorySegment SetupPacket, Addressable Buffer, int BufferLength, Addressable LengthTransferred, Addressable Overlapped) { + var mh$ = WinUsb_ControlTransfer$MH(); + try { + return (int)mh$.invokeExact(InterfaceHandle, SetupPacket, Buffer, BufferLength, LengthTransferred, Overlapped); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java new file mode 100644 index 00000000..57e13e9a --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java @@ -0,0 +1,82 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.winusb; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor WinUsb_Initialize$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle WinUsb_Initialize$MH = RuntimeHelper.downcallHandle( + "WinUsb_Initialize", + constants$0.WinUsb_Initialize$FUNC + ); + static final FunctionDescriptor WinUsb_Free$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle WinUsb_Free$MH = RuntimeHelper.downcallHandle( + "WinUsb_Free", + constants$0.WinUsb_Free$FUNC + ); + static final FunctionDescriptor WinUsb_GetDescriptor$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_SHORT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle WinUsb_GetDescriptor$MH = RuntimeHelper.downcallHandle( + "WinUsb_GetDescriptor", + constants$0.WinUsb_GetDescriptor$FUNC + ); + static final FunctionDescriptor WinUsb_ReadPipe$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle WinUsb_ReadPipe$MH = RuntimeHelper.downcallHandle( + "WinUsb_ReadPipe", + constants$0.WinUsb_ReadPipe$FUNC + ); + static final FunctionDescriptor WinUsb_WritePipe$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle WinUsb_WritePipe$MH = RuntimeHelper.downcallHandle( + "WinUsb_WritePipe", + constants$0.WinUsb_WritePipe$FUNC + ); + static final FunctionDescriptor WinUsb_ControlTransfer$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("RequestType"), + Constants$root.C_CHAR$LAYOUT.withName("Request"), + Constants$root.C_SHORT$LAYOUT.withName("Value"), + Constants$root.C_SHORT$LAYOUT.withName("Index"), + Constants$root.C_SHORT$LAYOUT.withName("Length") + ).withName("_WINUSB_SETUP_PACKET"), + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle WinUsb_ControlTransfer$MH = RuntimeHelper.downcallHandle( + "WinUsb_ControlTransfer", + constants$0.WinUsb_ControlTransfer$FUNC + ); +} + + From 4b741a9eca6d8b3e983f17dca6114d8e0e7fb47a Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Tue, 23 Aug 2022 22:16:55 +0200 Subject: [PATCH 008/433] Windows: remove old file --- java-does-usb/jextract/gen_windows.cmd | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 java-does-usb/jextract/gen_windows.cmd diff --git a/java-does-usb/jextract/gen_windows.cmd b/java-does-usb/jextract/gen_windows.cmd deleted file mode 100644 index f75288f1..00000000 --- a/java-does-usb/jextract/gen_windows.cmd +++ /dev/null @@ -1,19 +0,0 @@ -set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract.bat - -:: cfgmgr32.h -:: Fails with error: -:: C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\shared\devpropdef.h:33:9: error: unknown type name 'ULONG' -::%JEXTRACT% --source --output ../src/main/java ^ -:: -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -:: --header-class-name CfgMgr32 ^ -:: --target-package net.codecrete.usb.windows.gen.cfgmgr32 ^ -:: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\cfgmgr32.h" - -:: setupapi.h -:: Fails with error: -:: C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\setupapi.h:65:9: error: unknown type name 'GUID' -::%JEXTRACT% --source --output ../src/main/java ^ -:: -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -:: --header-class-name SetupApi ^ -:: --target-package net.codecrete.usb.windows.gen.setupapi ^ -:: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\setupapi.h" From a6bb67c02b5ca0d305f963dc4b28d9a819acf038 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 24 Aug 2022 19:58:07 +0200 Subject: [PATCH 009/433] Windows: use more generated code --- java-does-usb/jextract/gen_win_cfgmgr32.cmd | 2 +- java-does-usb/jextract/gen_win_kernel32.cmd | 3 +- java-does-usb/jextract/gen_win_setupapi.cmd | 2 +- java-does-usb/jextract/gen_win_stdlib.cmd | 2 +- java-does-usb/jextract/gen_win_usbioctl.cmd | 4 +- java-does-usb/jextract/gen_win_winusb.cmd | 2 +- java-does-usb/jextract/windows_cfgmgr32.h | 2 - java-does-usb/jextract/windows_headers.h | 6 + java-does-usb/jextract/windows_kernel32.h | 1 - java-does-usb/jextract/windows_setupapi.h | 2 - java-does-usb/jextract/windows_stdlib.h | 1 - java-does-usb/jextract/windows_usbioctl.h | 2 - java-does-usb/jextract/windows_winusb.h | 2 - .../SP_DEVICE_INTERFACE_DETAIL_DATA_W.java | 48 ++++++++ .../net/codecrete/usb/windows/SetupApi.java | 106 ------------------ .../windows/{USBIOCtl.java => USBHelper.java} | 16 ++- .../java/net/codecrete/usb/windows/Win.java | 41 +++++++ .../usb/windows/WindowsUSBDeviceRegistry.java | 43 +++---- .../usb/windows/gen/kernel32/_GUID.java | 77 +++++++++++++ .../usb/windows/gen/usbioctl/USBIoctl.java | 6 + 20 files changed, 220 insertions(+), 148 deletions(-) delete mode 100644 java-does-usb/jextract/windows_cfgmgr32.h create mode 100644 java-does-usb/jextract/windows_headers.h delete mode 100644 java-does-usb/jextract/windows_kernel32.h delete mode 100644 java-does-usb/jextract/windows_setupapi.h delete mode 100644 java-does-usb/jextract/windows_stdlib.h delete mode 100644 java-does-usb/jextract/windows_usbioctl.h delete mode 100644 java-does-usb/jextract/windows_winusb.h create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/SetupApi.java rename java-does-usb/src/main/java/net/codecrete/usb/windows/{USBIOCtl.java => USBHelper.java} (90%) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java diff --git a/java-does-usb/jextract/gen_win_cfgmgr32.cmd b/java-does-usb/jextract/gen_win_cfgmgr32.cmd index e4bd1db9..320f0d0b 100644 --- a/java-does-usb/jextract/gen_win_cfgmgr32.cmd +++ b/java-does-usb/jextract/gen_win_cfgmgr32.cmd @@ -9,4 +9,4 @@ set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 --target-package net.codecrete.usb.windows.gen.cfgmgr32 ^ --include-function CM_Get_Parent ^ --include-function CM_Get_Device_IDW ^ - windows_cfgmgr32.h + windows_headers.h diff --git a/java-does-usb/jextract/gen_win_kernel32.cmd b/java-does-usb/jextract/gen_win_kernel32.cmd index 90af5039..173e672f 100644 --- a/java-does-usb/jextract/gen_win_kernel32.cmd +++ b/java-does-usb/jextract/gen_win_kernel32.cmd @@ -19,4 +19,5 @@ set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 --include-macro FILE_ATTRIBUTE_NORMAL ^ --include-macro FILE_FLAG_OVERLAPPED ^ --include-macro OPEN_EXISTING ^ - windows_kernel32.h + --include-struct _GUID ^ + windows_headers.h diff --git a/java-does-usb/jextract/gen_win_setupapi.cmd b/java-does-usb/jextract/gen_win_setupapi.cmd index baf7983a..baf0813b 100644 --- a/java-does-usb/jextract/gen_win_setupapi.cmd +++ b/java-does-usb/jextract/gen_win_setupapi.cmd @@ -19,4 +19,4 @@ set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 --include-macro DIGCF_PRESENT ^ --include-macro DIGCF_DEVICEINTERFACE ^ --include-macro SPDRP_ADDRESS ^ - windows_setupapi.h + windows_headers.h diff --git a/java-does-usb/jextract/gen_win_stdlib.cmd b/java-does-usb/jextract/gen_win_stdlib.cmd index cd387688..8a80e5e0 100644 --- a/java-does-usb/jextract/gen_win_stdlib.cmd +++ b/java-does-usb/jextract/gen_win_stdlib.cmd @@ -4,4 +4,4 @@ set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract.bat --header-class-name StdLib ^ --target-package net.codecrete.usb.windows.gen.stdlib ^ --include-function wcslen ^ - windows_stdlib.h + windows_headers.h diff --git a/java-does-usb/jextract/gen_win_usbioctl.cmd b/java-does-usb/jextract/gen_win_usbioctl.cmd index b31b59b2..76cb7589 100644 --- a/java-does-usb/jextract/gen_win_usbioctl.cmd +++ b/java-does-usb/jextract/gen_win_usbioctl.cmd @@ -7,7 +7,9 @@ set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 --header-class-name USBIoctl ^ --target-package net.codecrete.usb.windows.gen.usbioctl ^ --include-struct _USB_NODE_CONNECTION_INFORMATION_EX ^ - windows_usbioctl.h + --include-macro IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX ^ + --include-macro IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION ^ + windows_headers.h :: Generated code is invalid: No instance of type _USB_NODE_CONNECTION_INFORMATION_EX can be created.0 :: They crash with: diff --git a/java-does-usb/jextract/gen_win_winusb.cmd b/java-does-usb/jextract/gen_win_winusb.cmd index bb52c94d..a8975263 100644 --- a/java-does-usb/jextract/gen_win_winusb.cmd +++ b/java-does-usb/jextract/gen_win_winusb.cmd @@ -13,4 +13,4 @@ set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 --include-function WinUsb_ControlTransfer ^ --include-function WinUsb_WritePipe ^ --include-function WinUsb_ReadPipe ^ - windows_winusb.h + windows_headers.h diff --git a/java-does-usb/jextract/windows_cfgmgr32.h b/java-does-usb/jextract/windows_cfgmgr32.h deleted file mode 100644 index 102a2987..00000000 --- a/java-does-usb/jextract/windows_cfgmgr32.h +++ /dev/null @@ -1,2 +0,0 @@ -#include -#include diff --git a/java-does-usb/jextract/windows_headers.h b/java-does-usb/jextract/windows_headers.h new file mode 100644 index 00000000..aa8d0648 --- /dev/null +++ b/java-does-usb/jextract/windows_headers.h @@ -0,0 +1,6 @@ +#include +#include +#include +#include +#include +#include diff --git a/java-does-usb/jextract/windows_kernel32.h b/java-does-usb/jextract/windows_kernel32.h deleted file mode 100644 index 198556f6..00000000 --- a/java-does-usb/jextract/windows_kernel32.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/java-does-usb/jextract/windows_setupapi.h b/java-does-usb/jextract/windows_setupapi.h deleted file mode 100644 index 7597c78f..00000000 --- a/java-does-usb/jextract/windows_setupapi.h +++ /dev/null @@ -1,2 +0,0 @@ -#include -#include diff --git a/java-does-usb/jextract/windows_stdlib.h b/java-does-usb/jextract/windows_stdlib.h deleted file mode 100644 index 3b2f5900..00000000 --- a/java-does-usb/jextract/windows_stdlib.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/java-does-usb/jextract/windows_usbioctl.h b/java-does-usb/jextract/windows_usbioctl.h deleted file mode 100644 index 2a284d46..00000000 --- a/java-does-usb/jextract/windows_usbioctl.h +++ /dev/null @@ -1,2 +0,0 @@ -#include -#include diff --git a/java-does-usb/jextract/windows_winusb.h b/java-does-usb/jextract/windows_winusb.h deleted file mode 100644 index 2fd0d78b..00000000 --- a/java-does-usb/jextract/windows_winusb.h +++ /dev/null @@ -1,2 +0,0 @@ -#include -#include diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java new file mode 100644 index 00000000..f59344c3 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java @@ -0,0 +1,48 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.windows; + +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.JAVA_CHAR; +import static java.lang.foreign.ValueLayout.JAVA_INT; + +/** + * SP_DEVICE_INTERFACE_DETAIL_DATA_W struct with a path length of 260 characters. + */ +public class SP_DEVICE_INTERFACE_DETAIL_DATA_W { + + // typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W { + // DWORD cbSize; + // WCHAR DevicePath[ANYSIZE_ARRAY]; + //} SP_DEVICE_INTERFACE_DETAIL_DATA_W, *PSP_DEVICE_INTERFACE_DETAIL_DATA_W; + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + JAVA_INT.withName("cbSize"), + MemoryLayout.sequenceLayout(260, JAVA_CHAR).withName("DevicePath") + ); + + public static GroupLayout $LAYOUT() { + return $struct$LAYOUT; + } + + static final VarHandle cbSize$VH = $struct$LAYOUT.varHandle(groupElement("cbSize")); + + public static int cbSize$get(MemorySegment seg) { + return (int) cbSize$VH.get(seg); + } + + public static void cbSize$set(MemorySegment seg, int x) { + cbSize$VH.set(seg, x); + } + + public static final long DevicePath$Offset = $struct$LAYOUT.byteOffset(groupElement("DevicePath")); +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/SetupApi.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/SetupApi.java deleted file mode 100644 index 1424553b..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/SetupApi.java +++ /dev/null @@ -1,106 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.windows; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.*; - -/** - * Windows Setup API functions, constants and structures. - */ -public class SetupApi { - - private static final GroupLayout GUID$Struct; - private static final VarHandle GUID_Data1; - private static final VarHandle GUID_Data2; - private static final VarHandle GUID_Data3; - private static final long GUID_Data4$Offset; - - public static final GroupLayout SP_DEVICE_INTERFACE_DETAIL_DATA_W$Struct; - public static final VarHandle SP_DEVICE_INTERFACE_DETAIL_DATA_W_cbSize; - public static final long SP_DEVICE_INTERFACE_DETAIL_DATA_W_DevicePath$Offset; - - public static final MemorySegment GUID_DEVINTERFACE_USB_DEVICE; - - static { - var session = MemorySession.openShared(); - Linker linker = Linker.nativeLinker(); - SymbolLookup lookup = SymbolLookup.libraryLookup("SetupAPI", session); - - // typedef struct _GUID { - // unsigned long Data1; - // unsigned short Data2; - // unsigned short Data3; - // unsigned char Data4[ 8 ]; - //} GUID; - GUID$Struct = MemoryLayout.structLayout( - JAVA_INT.withName("Data1"), - JAVA_SHORT.withName("Data2"), - JAVA_SHORT.withName("Data3"), - MemoryLayout.sequenceLayout(8, JAVA_BYTE).withName("Data4") - ); - GUID_Data1 = GUID$Struct.varHandle(groupElement("Data1")); - GUID_Data2 = GUID$Struct.varHandle(groupElement("Data2")); - GUID_Data3 = GUID$Struct.varHandle(groupElement("Data3")); - GUID_Data4$Offset = GUID$Struct.byteOffset(groupElement("Data4")); - - // typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W { - // DWORD cbSize; - // WCHAR DevicePath[ANYSIZE_ARRAY]; - //} SP_DEVICE_INTERFACE_DETAIL_DATA_W, *PSP_DEVICE_INTERFACE_DETAIL_DATA_W; - SP_DEVICE_INTERFACE_DETAIL_DATA_W$Struct = MemoryLayout.structLayout( - JAVA_INT.withName("cbSize"), - MemoryLayout.sequenceLayout(260, JAVA_CHAR).withName("DevicePath") - ); - SP_DEVICE_INTERFACE_DETAIL_DATA_W_cbSize = SP_DEVICE_INTERFACE_DETAIL_DATA_W$Struct.varHandle(groupElement("cbSize")); - SP_DEVICE_INTERFACE_DETAIL_DATA_W_DevicePath$Offset = SP_DEVICE_INTERFACE_DETAIL_DATA_W$Struct.byteOffset(groupElement("DevicePath")); - - // A5DCBF10-6530-11D2-901F-00C04FB951ED - GUID_DEVINTERFACE_USB_DEVICE = CreateGUID(0xA5DCBF10, (short) 0x6530, (short) 0x11D2, - (byte) 0x90, (byte) 0x1F, (byte) 0x00, (byte) 0xC0, - (byte) 0x4F, (byte) 0xB9, (byte) 0x51, (byte) 0xED); - } - - - /** - * Creates a GUID in native memory. - * - * @param data1 Group 1 (4 bytes). - * @param data2 Group 2 (2 bytes). - * @param data3 Group 3 (2 bytes). - * @param data4_0 Byte 0 of group 4 - * @param data4_1 Byte 1 of group 4 - * @param data4_2 Byte 2 of group 4 - * @param data4_3 Byte 3 of group 4 - * @param data4_4 Byte 4 of group 4 - * @param data4_5 Byte 5 of group 4 - * @param data4_6 Byte 6 of group 4 - * @param data4_7 Byte 7 of group 4 - * @return GUID as memory segment - */ - public static MemorySegment CreateGUID(int data1, short data2, short data3, - byte data4_0, byte data4_1, byte data4_2, byte data4_3, - byte data4_4, byte data4_5, byte data4_6, byte data4_7) { - var guid = MemorySegment.allocateNative(GUID$Struct, MemorySession.global()); - GUID_Data1.set(guid, data1); - GUID_Data2.set(guid, data2); - GUID_Data3.set(guid, data3); - guid.set(JAVA_BYTE, GUID_Data4$Offset, data4_0); - guid.set(JAVA_BYTE, GUID_Data4$Offset + 1, data4_1); - guid.set(JAVA_BYTE, GUID_Data4$Offset + 2, data4_2); - guid.set(JAVA_BYTE, GUID_Data4$Offset + 3, data4_3); - guid.set(JAVA_BYTE, GUID_Data4$Offset + 4, data4_4); - guid.set(JAVA_BYTE, GUID_Data4$Offset + 5, data4_5); - guid.set(JAVA_BYTE, GUID_Data4$Offset + 6, data4_6); - guid.set(JAVA_BYTE, GUID_Data4$Offset + 7, data4_7); - return guid; - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBIOCtl.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java similarity index 90% rename from java-does-usb/src/main/java/net/codecrete/usb/windows/USBIOCtl.java rename to java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java index 7e1b061f..095f47e2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBIOCtl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java @@ -11,6 +11,7 @@ import net.codecrete.usb.common.USBStructs; import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemorySegment; import java.lang.invoke.VarHandle; import static java.lang.foreign.MemoryLayout.PathElement.groupElement; @@ -18,12 +19,13 @@ import static java.lang.foreign.ValueLayout.*; /** - * USB IO Control functions and structures + * USB constants and struct + *

+ * Mainly used to work around an alignment problem with the generated + * USB_NODE_CONNECTION_INFORMATION_EX struct. + *

*/ -public class USBIOCtl { - - public static final int IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX = 2229320; - public static final int IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION = 2229264; +public class USBHelper { public static final byte USB_REQUEST_GET_DESCRIPTOR = 0x06; @@ -43,6 +45,10 @@ public class USBIOCtl { public static final VarHandle USB_STRING_DESCRIPTOR_bLength; public static final VarHandle USB_STRING_DESCRIPTOR_bDescriptorType; public static final long USB_STRING_DESCRIPTOR_bString$Offset; + // A5DCBF10-6530-11D2-901F-00C04FB951ED + public static final MemorySegment GUID_DEVINTERFACE_USB_DEVICE = Win.CreateGUID(0xA5DCBF10, (short) 0x6530, (short) 0x11D2, + (byte) 0x90, (byte) 0x1F, (byte) 0x00, (byte) 0xC0, + (byte) 0x4F, (byte) 0xB9, (byte) 0x51, (byte) 0xED); static { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index b7df23db..22ecb309 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -7,7 +7,13 @@ package net.codecrete.usb.windows; +import net.codecrete.usb.windows.gen.kernel32._GUID; + import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; /** * Windows helpers. @@ -23,4 +29,39 @@ public class Win { public static boolean IsInvalidHandle(MemoryAddress handle) { return handle.toRawLongValue() == -1L; } + + /** + * Creates a GUID in native memory. + * + * @param data1 Group 1 (4 bytes). + * @param data2 Group 2 (2 bytes). + * @param data3 Group 3 (2 bytes). + * @param data4_0 Byte 0 of group 4 + * @param data4_1 Byte 1 of group 4 + * @param data4_2 Byte 2 of group 4 + * @param data4_3 Byte 3 of group 4 + * @param data4_4 Byte 4 of group 4 + * @param data4_5 Byte 5 of group 4 + * @param data4_6 Byte 6 of group 4 + * @param data4_7 Byte 7 of group 4 + * @return GUID as memory segment + */ + public static MemorySegment CreateGUID(int data1, short data2, short data3, + byte data4_0, byte data4_1, byte data4_2, byte data4_3, + byte data4_4, byte data4_5, byte data4_6, byte data4_7) { + var guid = MemorySegment.allocateNative(_GUID.$LAYOUT(), MemorySession.global()); + _GUID.Data1$set(guid, data1); + _GUID.Data2$set(guid, data2); + _GUID.Data3$set(guid, data3); + var data4 = _GUID.Data4$slice(guid); + data4.set(JAVA_BYTE, 0, data4_0); + data4.set(JAVA_BYTE, 1, data4_1); + data4.set(JAVA_BYTE, 2, data4_2); + data4.set(JAVA_BYTE, 3, data4_3); + data4.set(JAVA_BYTE, 4, data4_4); + data4.set(JAVA_BYTE, 5, data4_5); + data4.set(JAVA_BYTE, 6, data4_6); + data4.set(JAVA_BYTE, 7, data4_7); + return guid; + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 9c48636d..508d5de4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -17,6 +17,7 @@ import net.codecrete.usb.windows.gen.setupapi.SetupAPI; import net.codecrete.usb.windows.gen.setupapi._SP_DEVINFO_DATA; import net.codecrete.usb.windows.gen.stdlib.StdLib; +import net.codecrete.usb.windows.gen.usbioctl.USBIoctl; import java.lang.foreign.Addressable; import java.lang.foreign.MemoryAddress; @@ -37,7 +38,7 @@ public List getAllDevices() { try (var outerSession = MemorySession.openConfined()) { // get as set of all USB devices present - final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(SetupApi.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); + final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); if (Win.IsInvalidHandle(devInfoSetHandle)) throw new USBException("internal error (SetupDiGetClassDevsW)"); @@ -96,7 +97,7 @@ public List getAllDevices() { // get the interface data if (SetupAPI.SetupDiEnumDeviceInterfaces(devInfoSetHandle, devInfo, - SetupApi.GUID_DEVINTERFACE_USB_DEVICE, 0, devInfoData) == 0) { + USBHelper.GUID_DEVINTERFACE_USB_DEVICE, 0, devInfoData) == 0) { int lastError = Kernel32.GetLastError(); if (lastError == Kernel32.ERROR_NO_MORE_ITEMS()) throw new USBException("Internal error (SetupDiEnumDeviceInterfaces)"); @@ -104,15 +105,15 @@ public List getAllDevices() { } // get path of first interface - var intfDetailData = MemorySegment.allocateNative(SetupApi.SP_DEVICE_INTERFACE_DETAIL_DATA_W$Struct, session); - SetupApi.SP_DEVICE_INTERFACE_DETAIL_DATA_W_cbSize.set(intfDetailData, 8); - int intfDatailDataSize = (int) SetupApi.SP_DEVICE_INTERFACE_DETAIL_DATA_W$Struct.byteSize(); + var intfDetailData = MemorySegment.allocateNative(SP_DEVICE_INTERFACE_DETAIL_DATA_W.$LAYOUT(), session); + SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$set(intfDetailData, 8); + int intfDatailDataSize = (int) SP_DEVICE_INTERFACE_DETAIL_DATA_W.$LAYOUT().byteSize(); if (SetupAPI.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devInfoData, intfDetailData, intfDatailDataSize, NULL, NULL) == 0) throw new USBException("Internal error (SetupDiGetDeviceInterfaceDetailA - 2)", Kernel32.GetLastError()); - long pathLen = StdLib.wcslen(intfDetailData.address().addOffset(SetupApi.SP_DEVICE_INTERFACE_DETAIL_DATA_W_DevicePath$Offset)); - char[] devicePathChars = intfDetailData.asSlice(SetupApi.SP_DEVICE_INTERFACE_DETAIL_DATA_W_DevicePath$Offset, pathLen * 2).toArray(JAVA_CHAR); + long pathLen = StdLib.wcslen(intfDetailData.address().addOffset(SP_DEVICE_INTERFACE_DETAIL_DATA_W.DevicePath$Offset)); + char[] devicePathChars = intfDetailData.asSlice(SP_DEVICE_INTERFACE_DETAIL_DATA_W.DevicePath$Offset, pathLen * 2).toArray(JAVA_CHAR); String devicePath = new String(devicePathChars); // get device's hub port number @@ -137,20 +138,20 @@ private USBDeviceInfo createDeviceInfo(String devicePath, MemoryAddress hubHandl try (var session = MemorySession.openConfined()) { // get device descriptor - var connInfo = session.allocate(USBIOCtl.USB_NODE_CONNECTION_INFORMATION_EX$Struct); - USBIOCtl.USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex.set(connInfo, usbPortNum); + var connInfo = session.allocate(USBHelper.USB_NODE_CONNECTION_INFORMATION_EX$Struct); + USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex.set(connInfo, usbPortNum); var sizeHolder = session.allocate(JAVA_INT); - if (Kernel32.DeviceIoControl(hubHandle, USBIOCtl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, + if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), connInfo, (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL) == 0) throw new USBException("Internal error (cannot get device descriptor)", Kernel32.GetLastError()); byte currentConfigurationValue = - (byte) USBIOCtl.USB_NODE_CONNECTION_INFORMATION_EX_CurrentConfigurationValue.get(connInfo); + (byte) USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_CurrentConfigurationValue.get(connInfo); var deviceDesc = connInfo.asSlice( - USBIOCtl.USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset, + USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset, USBDescriptors.Device$Struct.byteSize()); // extract info from device descriptor @@ -181,27 +182,27 @@ private String getStringDescriptor(Addressable hubHandle, int usbPortNumber, int try (var session = MemorySession.openConfined()) { final int dataLen = 32; - var descriptorRequest = session.allocate(USBIOCtl.USB_DESCRIPTOR_REQUEST_Data$Offset + dataLen); - USBIOCtl.USB_DESCRIPTOR_REQUEST_ConnectionIndex.set(descriptorRequest, usbPortNumber); + var descriptorRequest = session.allocate(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset + dataLen); + USBHelper.USB_DESCRIPTOR_REQUEST_ConnectionIndex.set(descriptorRequest, usbPortNumber); var setupPacket = descriptorRequest.asSlice( - USBIOCtl.USB_DESCRIPTOR_REQUEST_SetupPacket$Offset, + USBHelper.USB_DESCRIPTOR_REQUEST_SetupPacket$Offset, USBStructs.SetupPacket$Struct.byteSize()); USBStructs.SetupPacket_bmRequest.set(setupPacket, (byte) 0x80); - USBStructs.SetupPacket_bRequest.set(setupPacket, USBIOCtl.USB_REQUEST_GET_DESCRIPTOR); - USBStructs.SetupPacket_wValue.set(setupPacket, (short) ((USBIOCtl.USB_STRING_DESCRIPTOR_TYPE << 8) | index)); + USBStructs.SetupPacket_bRequest.set(setupPacket, USBHelper.USB_REQUEST_GET_DESCRIPTOR); + USBStructs.SetupPacket_wValue.set(setupPacket, (short) ((USBHelper.USB_STRING_DESCRIPTOR_TYPE << 8) | index)); USBStructs.SetupPacket_wIndex.set(setupPacket, (short) 0x0409); USBStructs.SetupPacket_wLength.set(setupPacket, (short) dataLen); var sizeHolder = session.allocate(JAVA_INT); - if (Kernel32.DeviceIoControl(hubHandle, USBIOCtl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION(), descriptorRequest, (int) descriptorRequest.byteSize(), descriptorRequest, (int) descriptorRequest.byteSize(), sizeHolder, NULL) == 0) throw new USBException(String.format("Cannot retrieve string descriptor %d", index), Kernel32.GetLastError()); - var stringDesc = descriptorRequest.asSlice(USBIOCtl.USB_DESCRIPTOR_REQUEST_Data$Offset, dataLen); - int stringLen = 255 & (byte) USBIOCtl.USB_STRING_DESCRIPTOR_bLength.get(stringDesc); - var chars = stringDesc.asSlice(USBIOCtl.USB_STRING_DESCRIPTOR_bString$Offset, stringLen - 2) + var stringDesc = descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, dataLen); + int stringLen = 255 & (byte) USBHelper.USB_STRING_DESCRIPTOR_bLength.get(stringDesc); + var chars = stringDesc.asSlice(USBHelper.USB_STRING_DESCRIPTOR_bString$Offset, stringLen - 2) .toArray(JAVA_CHAR); return new String(chars); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java new file mode 100644 index 00000000..98826c26 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java @@ -0,0 +1,77 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.kernel32; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class _GUID { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_LONG$LAYOUT.withName("Data1"), + Constants$root.C_SHORT$LAYOUT.withName("Data2"), + Constants$root.C_SHORT$LAYOUT.withName("Data3"), + MemoryLayout.sequenceLayout(8, Constants$root.C_CHAR$LAYOUT).withName("Data4") + ).withName("_GUID"); + public static MemoryLayout $LAYOUT() { + return _GUID.$struct$LAYOUT; + } + static final VarHandle Data1$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Data1")); + public static VarHandle Data1$VH() { + return _GUID.Data1$VH; + } + public static int Data1$get(MemorySegment seg) { + return (int)_GUID.Data1$VH.get(seg); + } + public static void Data1$set( MemorySegment seg, int x) { + _GUID.Data1$VH.set(seg, x); + } + public static int Data1$get(MemorySegment seg, long index) { + return (int)_GUID.Data1$VH.get(seg.asSlice(index*sizeof())); + } + public static void Data1$set(MemorySegment seg, long index, int x) { + _GUID.Data1$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle Data2$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Data2")); + public static VarHandle Data2$VH() { + return _GUID.Data2$VH; + } + public static short Data2$get(MemorySegment seg) { + return (short)_GUID.Data2$VH.get(seg); + } + public static void Data2$set( MemorySegment seg, short x) { + _GUID.Data2$VH.set(seg, x); + } + public static short Data2$get(MemorySegment seg, long index) { + return (short)_GUID.Data2$VH.get(seg.asSlice(index*sizeof())); + } + public static void Data2$set(MemorySegment seg, long index, short x) { + _GUID.Data2$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle Data3$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Data3")); + public static VarHandle Data3$VH() { + return _GUID.Data3$VH; + } + public static short Data3$get(MemorySegment seg) { + return (short)_GUID.Data3$VH.get(seg); + } + public static void Data3$set( MemorySegment seg, short x) { + _GUID.Data3$VH.set(seg, x); + } + public static short Data3$get(MemorySegment seg, long index) { + return (short)_GUID.Data3$VH.get(seg.asSlice(index*sizeof())); + } + public static void Data3$set(MemorySegment seg, long index, short x) { + _GUID.Data3$VH.set(seg.asSlice(index*sizeof()), x); + } + public static MemorySegment Data4$slice(MemorySegment seg) { + return seg.asSlice(8, 8); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java index d6a326fe..bbb4e966 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java @@ -14,6 +14,12 @@ public class USBIoctl { public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static int IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION() { + return (int)2229264L; + } + public static int IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX() { + return (int)2229320L; + } } From 744384938e61276bef5352fd4f952fdefb1af59b Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 26 Aug 2022 17:54:08 +0200 Subject: [PATCH 010/433] macOS: monitor connect/disconnect --- java-does-usb/jextract/gen_macos.sh | 18 +- .../src/main/java/net/codecrete/usb/USB.java | 19 + .../java/net/codecrete/usb/USBDeviceInfo.java | 4 + .../codecrete/usb/common/USBDeviceImpl.java | 20 +- .../usb/common/USBDeviceInfoImpl.java | 20 +- .../usb/common/USBDeviceRegistry.java | 5 + .../codecrete/usb/linux/LinuxUSBDevice.java | 6 +- .../usb/linux/LinuxUSBDeviceInfo.java | 6 +- .../usb/linux/LinuxUSBDeviceRegistry.java | 9 + .../codecrete/usb/macos/CoreFoundation.java | 291 ++++++------ .../java/net/codecrete/usb/macos/IoKit.java | 441 ++++++++++-------- .../net/codecrete/usb/macos/IoKitHelper.java | 118 +++++ .../codecrete/usb/macos/MacosUSBDevice.java | 55 ++- .../usb/macos/MacosUSBDeviceInfo.java | 6 +- .../usb/macos/MacosUSBDeviceRegistry.java | 236 +++++++--- .../usb/macos/MacosUSBException.java | 29 ++ .../macos/gen/{ => mach}/Constants$root.java | 2 +- .../macos/gen/{ => mach}/RuntimeHelper.java | 2 +- .../usb/macos/gen/{ => mach}/constants$0.java | 9 +- .../usb/macos/gen/{ => mach}/mach.java | 14 +- .../usb/windows/WindowsUSBDevice.java | 10 +- .../usb/windows/WindowsUSBDeviceInfo.java | 6 +- .../usb/windows/WindowsUSBDeviceRegistry.java | 9 + .../codecrete/usb/sample/MonitorDevices.java | 22 + 24 files changed, 887 insertions(+), 470 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java rename java-does-usb/src/main/java/net/codecrete/usb/macos/gen/{ => mach}/Constants$root.java (94%) rename java-does-usb/src/main/java/net/codecrete/usb/macos/gen/{ => mach}/RuntimeHelper.java (99%) rename java-does-usb/src/main/java/net/codecrete/usb/macos/gen/{ => mach}/constants$0.java (54%) rename java-does-usb/src/main/java/net/codecrete/usb/macos/gen/{ => mach}/mach.java (67%) create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java diff --git a/java-does-usb/jextract/gen_macos.sh b/java-does-usb/jextract/gen_macos.sh index 2aabdfc6..31907319 100755 --- a/java-does-usb/jextract/gen_macos.sh +++ b/java-does-usb/jextract/gen_macos.sh @@ -1,16 +1,20 @@ #!/bin/sh JEXTRACT=../../../jextract/build/jextract/bin/jextract +SDK_DIR=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk # CoreFoundation -#$JEXTRACT --source --target-package net.codecrete.usb.macos.gen --output ../src/main/java \ -# -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include \ +#$JEXTRACT --source --output ../src/main/java \ +# -I $SDK_DIR/usr/include \ +# --target-package net.codecrete.usb.macos.gen.corefoundation # --include-function CFUUIDCreateFromUUIDBytes \ -# /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/CoreFoundation.framework/Versions/A/Headers/CoreFoundation.h +# $SDK_DIR/System/Library/Frameworks/CoreFoundation.framework/Versions/A/Headers/CoreFoundation.h -## mach_error -$JEXTRACT --source --target-package net.codecrete.usb.macos.gen --output ../src/main/java \ - -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include \ +# mach.h +$JEXTRACT --source --output ../src/main/java \ + -I $SDK_DIR/usr/include \ --header-class-name mach \ + --target-package net.codecrete.usb.macos.gen.mach \ --include-function mach_error \ - /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/mach/mach.h + --include-function mach_error_string \ + $SDK_DIR/usr/include/mach/mach.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USB.java b/java-does-usb/src/main/java/net/codecrete/usb/USB.java index c5f22ccc..5f9b7d35 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USB.java @@ -13,6 +13,7 @@ import net.codecrete.usb.windows.WindowsUSBDeviceRegistry; import java.util.List; +import java.util.function.Consumer; import java.util.stream.Collectors; /** @@ -104,4 +105,22 @@ public static USBDeviceInfo getDevice(List filters) { return instance().getAllDevices().stream().filter(dev -> USBDeviceFilter.matchesAny(dev, filters)) .findFirst().orElse(null); } + + /** + * Sets the handler to be called when a USB device is connected. + * + * @param handler handler function, or {@code null} to remove a previous handler + */ + public static void setOnDeviceConnected(Consumer handler) { + instance().setOnDeviceConnected(handler); + } + + /** + * Sets the handler to be called when a USB device is disconnected. + * + * @param handler handler function, or {@code null} to remove a previous handler + */ + public static void setOnDeviceDisconnected(Consumer handler) { + instance().setOnDeviceDisconnected(handler); + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceInfo.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceInfo.java index 880a32bd..c9eac5b1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceInfo.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceInfo.java @@ -18,6 +18,10 @@ * Instances of this class are not associated with any native resources * and can thus be easily handled in Java. *

+ *

+ * Multiple instances of the class might exist for the same USB device. + * Use {@code equals()} to test if they refer to the same device. + *

*/ public interface USBDeviceInfo { /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 938c798e..a4a04ca7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -9,12 +9,10 @@ import net.codecrete.usb.*; -import java.util.Objects; - public abstract class USBDeviceImpl implements USBDevice { - protected final String path; + protected final Object id; protected final int productId; protected final int vendorId; protected final String product; @@ -27,14 +25,16 @@ public abstract class USBDeviceImpl implements USBDevice { /** * Creates a new instance. * - * @param path device path + * @param id unique identifier * @param info USB device information */ protected USBDeviceImpl( - String path, + Object id, USBDeviceInfo info) { - this.path = path; + assert id != null; + + this.id = id; this.productId = info.getProductId(); this.vendorId = info.getVendorId(); this.product = info.getProduct(); @@ -117,12 +117,12 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; USBDeviceImpl that = (USBDeviceImpl) o; - return productId == that.productId && vendorId == that.vendorId && classCode == that.classCode && subclassCode == that.subclassCode && protocolCode == that.protocolCode && path.equals(that.path) && Objects.equals(product, that.product) && Objects.equals(manufacturer, that.manufacturer) && Objects.equals(serial, that.serial); + return id.equals(that.id); } @Override public int hashCode() { - return Objects.hash(path, productId, vendorId, product, manufacturer, serial, classCode, subclassCode, protocolCode); + return id.hashCode(); } @Override @@ -137,7 +137,7 @@ public String toString() { product + ", serial: " + serial + - ", path: " + - path; + ", ID: " + + id.toString(); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceInfoImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceInfoImpl.java index 55da0781..0e55dca6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceInfoImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceInfoImpl.java @@ -10,12 +10,10 @@ import net.codecrete.usb.USBDevice; import net.codecrete.usb.USBDeviceInfo; -import java.util.Objects; - public abstract class USBDeviceInfoImpl implements USBDeviceInfo { - protected final String path; + protected final Object id; protected final int productId; protected final int vendorId; protected final String product; @@ -28,7 +26,7 @@ public abstract class USBDeviceInfoImpl implements USBDeviceInfo { /** * Creates a new instance. * - * @param path device path + * @param id unique device ID * @param vendorId USB vendor ID * @param productId USB product ID * @param manufacturer manufacturer name @@ -39,11 +37,13 @@ public abstract class USBDeviceInfoImpl implements USBDeviceInfo { * @param protocolCode USB device protocol */ protected USBDeviceInfoImpl( - String path, int vendorId, int productId, + Object id, int vendorId, int productId, String manufacturer, String product, String serial, int classCode, int subclassCode, int protocolCode) { - this.path = path; + assert id != null; + + this.id = id; this.productId = productId; this.vendorId = vendorId; this.product = product; @@ -93,12 +93,12 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; USBDeviceInfoImpl that = (USBDeviceInfoImpl) o; - return productId == that.productId && vendorId == that.vendorId && classCode == that.classCode && subclassCode == that.subclassCode && protocolCode == that.protocolCode && path.equals(that.path) && Objects.equals(product, that.product) && Objects.equals(manufacturer, that.manufacturer) && Objects.equals(serial, that.serial); + return id.equals(that.id); } @Override public int hashCode() { - return Objects.hash(path, productId, vendorId, product, manufacturer, serial, classCode, subclassCode, protocolCode); + return id.hashCode(); } @Override @@ -113,7 +113,7 @@ public String toString() { product + ", serial: " + serial + - ", path: " + - path; + ", ID: " + + id; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index 4e314f7a..685797d0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -10,10 +10,15 @@ import net.codecrete.usb.USBDeviceInfo; import java.util.List; +import java.util.function.Consumer; /** * USB device registry. */ public interface USBDeviceRegistry { List getAllDevices(); + + void setOnDeviceConnected(Consumer handler); + + void setOnDeviceDisconnected(Consumer handler); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index e1b7c622..119bc478 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -28,11 +28,11 @@ public class LinuxUSBDevice extends USBDeviceImpl { private final int fd; - LinuxUSBDevice(String path, USBDeviceInfo info) { - super(path, info); + LinuxUSBDevice(Object id, USBDeviceInfo info) { + super(id, info); try (var session = MemorySession.openConfined()) { - var pathUtf8 = session.allocateUtf8String(path); + var pathUtf8 = session.allocateUtf8String(id.toString()); fd = fcntl.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC()); if (fd == -1) throw new USBException("Cannot open USB device", IO.getErrno()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceInfo.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceInfo.java index c7b5a2da..1d8c3d22 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceInfo.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceInfo.java @@ -13,17 +13,17 @@ public class LinuxUSBDeviceInfo extends USBDeviceInfoImpl { LinuxUSBDeviceInfo( - String path, int vendorId, int productId, + Object id, int vendorId, int productId, String manufacturer, String product, String serial, int classCode, int subclassCode, int protocolCode) { - super(path, vendorId, productId, + super(id, vendorId, productId, manufacturer, product, serial, classCode, subclassCode, protocolCode); } @Override public USBDevice open() { - return new LinuxUSBDevice(path, this); + return new LinuxUSBDevice(id, this); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 4a120556..c786705a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -15,6 +15,7 @@ import java.lang.foreign.MemorySession; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.ADDRESS; @@ -96,4 +97,12 @@ private static String getDeviceName(Addressable device) { return ret.getUtf8String(0); } } + + @Override + public void setOnDeviceConnected(Consumer handler) { + } + + @Override + public void setOnDeviceDisconnected(Consumer handler) { + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundation.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundation.java index 4cccd5b4..3f2857ae 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundation.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundation.java @@ -37,147 +37,129 @@ public class CoreFoundation { public static final long kCFNumberNSIntegerType = 15; public static final long kCFNumberCGFloatType = 16; - public static final GroupLayout CFUUIDBytes; - - public static final GroupLayout CFUUID; - public static final long CFUUID_bytes$Offset; - - public static final GroupLayout CFRange; - public static final VarHandle CFRange_location; - public static final VarHandle CFRange_range; - - - // private static final MethodHandle CFUUIDGetConstantUUIDWithBytes$Func; - private static final MethodHandle CFUUIDCreateFromUUIDBytes$Func; - private static final MethodHandle CFUUIDCreateString$Func; - private static final MethodHandle CFRelease$Func; - private static final MethodHandle CFStringGetLength$Func; - private static final MethodHandle CFStringGetCharacters$Func; - private static final MethodHandle CFStringCreateWithCharacters$Func; - private static final MethodHandle CFGetTypeID$Func; - private static final MethodHandle CFNumberGetTypeID$Func; - private static final MethodHandle CFStringGetTypeID$Func; - private static final MethodHandle CFNumberGetType$Func; - private static final MethodHandle CFNumberGetValue$Func; - - static { - var linker = Linker.nativeLinker(); - var cfSession = MemorySession.openShared(); - var coreFoundationLookup = SymbolLookup.libraryLookup("CoreFoundation.framework/CoreFoundation", cfSession); - - CFUUIDBytes = structLayout( - JAVA_BYTE.withName("byte0"), - JAVA_BYTE.withName("byte1"), - JAVA_BYTE.withName("byte2"), - JAVA_BYTE.withName("byte3"), - JAVA_BYTE.withName("byte4"), - JAVA_BYTE.withName("byte5"), - JAVA_BYTE.withName("byte6"), - JAVA_BYTE.withName("byte7"), - JAVA_BYTE.withName("byte8"), - JAVA_BYTE.withName("byte9"), - JAVA_BYTE.withName("byte10"), - JAVA_BYTE.withName("byte11"), - JAVA_BYTE.withName("byte12"), - JAVA_BYTE.withName("byte13"), - JAVA_BYTE.withName("byte14"), - JAVA_BYTE.withName("byte15") - ); - CFUUID = structLayout( - ADDRESS.withName("_cfisa"), // uintptr_t _cfisa; - sequenceLayout(4, JAVA_BYTE).withName("_cfinfo"), // uint8_t _cfinfo[4]; - JAVA_INT.withName("_rc"), // uint32_t _rc; - CFUUIDBytes.withName("_bytes") // CFUUIDBytes _bytes; - ); - CFUUID_bytes$Offset = CFUUID.byteOffset(MemoryLayout.PathElement.groupElement("_bytes")); - CFRange = structLayout( - JAVA_LONG.withName("location"), - JAVA_LONG.withName("range") - ); - CFRange_location = CFRange.varHandle(MemoryLayout.PathElement.groupElement("location")); - CFRange_range = CFRange.varHandle(MemoryLayout.PathElement.groupElement("range")); - - // CFUUIDRef CFUUIDGetConstantUUIDWithBytes(CFAllocatorRef alloc, uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4, uint8_t byte5, uint8_t byte6, uint8_t byte7, uint8_t byte8, uint8_t byte9, uint8_t byte10, uint8_t byte11, uint8_t byte12, uint8_t byte13, uint8_t byte14, uint8_t byte15) -// CFUUIDGetConstantUUIDWithBytes$Func = linker.downcallHandle( -// coreFoundationLookup.lookup("CFUUIDGetConstantUUIDWithBytes").get(), -// FunctionDescriptor.of( -// ADDRESS, ADDRESS, -// JAVA_BYTE, JAVA_BYTE, JAVA_BYTE, JAVA_BYTE, -// JAVA_BYTE, JAVA_BYTE, JAVA_BYTE, JAVA_BYTE, -// JAVA_BYTE, JAVA_BYTE, JAVA_BYTE, JAVA_BYTE, -// JAVA_BYTE, JAVA_BYTE, JAVA_BYTE, JAVA_BYTE) -// ); - - // CFUUIDRef CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc, CFUUIDBytes bytes); - CFUUIDCreateFromUUIDBytes$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFUUIDCreateFromUUIDBytes").get(), - FunctionDescriptor.of( - ADDRESS, ADDRESS, CFUUIDBytes - ) - ); - - // CFStringRef CFUUIDCreateString(CFAllocatorRef alloc, CFUUIDRef uuid); - CFUUIDCreateString$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFUUIDCreateString").get(), - FunctionDescriptor.of( - ADDRESS, ADDRESS, ADDRESS - ) - ); - - // void CFRelease(CFTypeRef cf); - CFRelease$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFRelease").get(), - FunctionDescriptor.ofVoid(ADDRESS) - ); - - // CFIndex CFStringGetLength(CFStringRef theString); - CFStringGetLength$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFStringGetLength").get(), - FunctionDescriptor.of(JAVA_LONG, ADDRESS) - ); - - // void CFStringGetCharacters(CFStringRef theString, CFRange range, UniChar *buffer); - CFStringGetCharacters$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFStringGetCharacters").get(), - FunctionDescriptor.ofVoid(ADDRESS, CFRange, ADDRESS) - ); - - // CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, const UniChar *chars, CFIndex numChars); - CFStringCreateWithCharacters$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFStringCreateWithCharacters").get(), - FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, JAVA_LONG) - ); - - // CFTypeID CFGetTypeID(CFTypeRef cf); - CFGetTypeID$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFGetTypeID").get(), - FunctionDescriptor.of(JAVA_LONG, ADDRESS) - ); - - // CFTypeID CFNumberGetTypeID(void); - CFNumberGetTypeID$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFNumberGetTypeID").get(), - FunctionDescriptor.of(JAVA_LONG) - ); - - // CFTypeID CFStringGetTypeID(void); - CFStringGetTypeID$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFStringGetTypeID").get(), - FunctionDescriptor.of(JAVA_LONG) - ); - - // CFNumberType CFNumberGetType(CFNumberRef number); - CFNumberGetType$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFNumberGetType").get(), - FunctionDescriptor.of(JAVA_LONG, ADDRESS) - ); - - // Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void *valuePtr); - CFNumberGetValue$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFNumberGetValue").get(), - FunctionDescriptor.of(JAVA_BOOLEAN, ADDRESS, JAVA_LONG, ADDRESS) - ); - } + private static final Linker linker = Linker.nativeLinker(); + private static final MemorySession cfSession = MemorySession.openShared(); + private static final SymbolLookup coreFoundationLookup = SymbolLookup.libraryLookup("CoreFoundation.framework/CoreFoundation", cfSession); + + public static final GroupLayout CFUUIDBytes = structLayout( + JAVA_BYTE.withName("byte0"), + JAVA_BYTE.withName("byte1"), + JAVA_BYTE.withName("byte2"), + JAVA_BYTE.withName("byte3"), + JAVA_BYTE.withName("byte4"), + JAVA_BYTE.withName("byte5"), + JAVA_BYTE.withName("byte6"), + JAVA_BYTE.withName("byte7"), + JAVA_BYTE.withName("byte8"), + JAVA_BYTE.withName("byte9"), + JAVA_BYTE.withName("byte10"), + JAVA_BYTE.withName("byte11"), + JAVA_BYTE.withName("byte12"), + JAVA_BYTE.withName("byte13"), + JAVA_BYTE.withName("byte14"), + JAVA_BYTE.withName("byte15") + ); + + public static final GroupLayout CFUUID = structLayout( + ADDRESS.withName("_cfisa"), // uintptr_t _cfisa; + sequenceLayout(4, JAVA_BYTE).withName("_cfinfo"), // uint8_t _cfinfo[4]; + JAVA_INT.withName("_rc"), // uint32_t _rc; + CFUUIDBytes.withName("_bytes") // CFUUIDBytes _bytes; + ); + public static final long CFUUID_bytes$Offset = CFUUID.byteOffset(MemoryLayout.PathElement.groupElement("_bytes")); + + public static final GroupLayout CFRange = structLayout( + JAVA_LONG.withName("location"), + JAVA_LONG.withName("range") + ); + public static final VarHandle CFRange_location = CFRange.varHandle(MemoryLayout.PathElement.groupElement("location")); + public static final VarHandle CFRange_range = CFRange.varHandle(MemoryLayout.PathElement.groupElement("range")); + + // CFUUIDRef CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc, CFUUIDBytes bytes); + private static final MethodHandle CFUUIDCreateFromUUIDBytes$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFUUIDCreateFromUUIDBytes").get(), + FunctionDescriptor.of( + ADDRESS, ADDRESS, CFUUIDBytes + ) + ); + + // CFStringRef CFUUIDCreateString(CFAllocatorRef alloc, CFUUIDRef uuid); + private static final MethodHandle CFUUIDCreateString$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFUUIDCreateString").get(), + FunctionDescriptor.of( + ADDRESS, ADDRESS, ADDRESS + ) + ); + + // void CFRelease(CFTypeRef cf); + private static final MethodHandle CFRelease$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFRelease").get(), + FunctionDescriptor.ofVoid(ADDRESS) + ); + + // CFIndex CFStringGetLength(CFStringRef theString); + private static final MethodHandle CFStringGetLength$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFStringGetLength").get(), + FunctionDescriptor.of(JAVA_LONG, ADDRESS) + ); + + // void CFStringGetCharacters(CFStringRef theString, CFRange range, UniChar *buffer); + private static final MethodHandle CFStringGetCharacters$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFStringGetCharacters").get(), + FunctionDescriptor.ofVoid(ADDRESS, CFRange, ADDRESS) + ); + + // CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, const UniChar *chars, CFIndex numChars); + private static final MethodHandle CFStringCreateWithCharacters$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFStringCreateWithCharacters").get(), + FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, JAVA_LONG) + ); + + // CFTypeID CFGetTypeID(CFTypeRef cf); + private static final MethodHandle CFGetTypeID$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFGetTypeID").get(), + FunctionDescriptor.of(JAVA_LONG, ADDRESS) + ); + + // CFTypeID CFNumberGetTypeID(void); + private static final MethodHandle CFNumberGetTypeID$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFNumberGetTypeID").get(), + FunctionDescriptor.of(JAVA_LONG) + ); + + // CFTypeID CFStringGetTypeID(void); + private static final MethodHandle CFStringGetTypeID$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFStringGetTypeID").get(), + FunctionDescriptor.of(JAVA_LONG) + ); + + // CFNumberType CFNumberGetType(CFNumberRef number); + private static final MethodHandle CFNumberGetType$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFNumberGetType").get(), + FunctionDescriptor.of(JAVA_LONG, ADDRESS) + ); + + // Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void *valuePtr); + private static final MethodHandle CFNumberGetValue$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFNumberGetValue").get(), + FunctionDescriptor.of(JAVA_BOOLEAN, ADDRESS, JAVA_LONG, ADDRESS) + ); + // CFRunLoopRef CFRunLoopGetCurrent(void); + private static final MethodHandle CFRunLoopGetCurrent$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFRunLoopGetCurrent").get(), + FunctionDescriptor.of(ADDRESS) + ); + // void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode); + private static final MethodHandle CFRunLoopAddSource$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFRunLoopAddSource").get(), + FunctionDescriptor.ofVoid(ADDRESS, ADDRESS, ADDRESS) + ); + // void CFRunLoopRun(void); + private static final MethodHandle CFRunLoopRun$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFRunLoopRun").get(), + FunctionDescriptor.ofVoid() + ); + public static String cfStringToJavaString(MemoryAddress string) { try (var session = MemorySession.openConfined()) { @@ -305,4 +287,31 @@ public static boolean CFNumberGetValue(Addressable number, long theType, Address throw new RuntimeException(t); } } + + // CFRunLoopRef CFRunLoopGetCurrent(void); + public static MemoryAddress CFRunLoopGetCurrent() { + try { + return (MemoryAddress) CFRunLoopGetCurrent$Func.invokeExact(); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + // void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode); + public static void CFRunLoopAddSource(Addressable runLoop, Addressable source, Addressable mode) { + try { + CFRunLoopAddSource$Func.invokeExact(runLoop, source, mode); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + // void CFRunLoopRun(void); + public static void CFRunLoopRun() { + try { + CFRunLoopRun$Func.invokeExact(); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java index bc5a87b2..7d8dc238 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java @@ -7,8 +7,6 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.common.Foreign; - import java.lang.foreign.*; import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; @@ -16,175 +14,198 @@ import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.MemoryLayout.PathElement.groupElement; import static java.lang.foreign.ValueLayout.*; -import static net.codecrete.usb.macos.CoreFoundation.*; +import static net.codecrete.usb.macos.CoreFoundation.CFUUIDBytes; +import static net.codecrete.usb.macos.CoreFoundation.javaStringToCfString; public class IoKit { + private static final Linker linker = Linker.nativeLinker(); + private static final MemorySession ioKitSession = MemorySession.openShared(); + private static final SymbolLookup ioKitLookup = SymbolLookup.libraryLookup("IOKit.framework/IOKit", ioKitSession); + + public static final Addressable kIOUSBPlane = ioKitSession.allocateUtf8String("IOUSB"); + public static final Addressable kIOServicePlane = ioKitSession.allocateUtf8String("IOService"); + + public static final GroupLayout IOCFPlugInInterface$Struct = MemoryLayout.structLayout( + ADDRESS.withName("_reserved"), // void *_reserved; + ADDRESS.withName("QueryInterface"), // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); + ADDRESS.withName("AddRef"), // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); + ADDRESS.withName("Release"), // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); + JAVA_SHORT.withName("version"), // UInt16 version; + JAVA_SHORT.withName("revision"), // UInt16 revision; + ADDRESS.withName("Probe"), // IOReturn (*Probe)(void *thisPointer, CFDictionaryRef propertyTable, io_service_t service, SInt32 * order); + ADDRESS.withName("Start"), // IOReturn (*Start)(void *thisPointer, CFDictionaryRef propertyTable, io_service_t service); + ADDRESS.withName("Stop") // IOReturn (*Stop)(void *thisPointer); + ); + + private static final VarHandle IUnknown_QueryInterface = IOCFPlugInInterface$Struct.varHandle(groupElement("QueryInterface")); + private static final VarHandle IUnknown_AddRef = IOCFPlugInInterface$Struct.varHandle(groupElement("AddRef")); + private static final VarHandle IUnknown_Release = IOCFPlugInInterface$Struct.varHandle(groupElement("Release")); + + // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); + private static final MethodHandle QueryInterface$Func = linker.downcallHandle( + FunctionDescriptor.of(JAVA_INT, ADDRESS, CFUUIDBytes, ADDRESS) + ); + + // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); + private static final MethodHandle AddRef$Func = linker.downcallHandle( + FunctionDescriptor.of(JAVA_INT, ADDRESS) + ); + + // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); + private static final MethodHandle Release$Func = linker.downcallHandle( + FunctionDescriptor.of(JAVA_INT, ADDRESS) + ); + + // io_registry_entry_t IORegistryGetRootEntry(mach_port_t mainPort); + private static final MethodHandle IORegistryGetRootEntry$Func = linker.downcallHandle( + ioKitLookup.lookup("IORegistryGetRootEntry").get(), + FunctionDescriptor.of(JAVA_INT, JAVA_INT) + ); + + // kern_return_t IOObjectRelease(io_object_t object); + private static final MethodHandle IOObjectRelease$Func = linker.downcallHandle( + ioKitLookup.lookup("IOObjectRelease").get(), + FunctionDescriptor.of(JAVA_INT, JAVA_INT) + ); + + // kern_return_t IORegistryEntryCreateIterator(io_registry_entry_t entry, const io_name_t plane, IOOptionBits options, io_iterator_t *iterator); + private static final MethodHandle IORegistryCreateIterator$Func = linker.downcallHandle( + ioKitLookup.lookup("IORegistryCreateIterator").get(), + FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS, JAVA_INT, ADDRESS) + ); + + // io_object_t IOIteratorNext(io_iterator_t iterator); + private static final MethodHandle IOIteratorNext$Func = linker.downcallHandle( + ioKitLookup.lookup("IOIteratorNext").get(), + FunctionDescriptor.of(JAVA_INT, JAVA_INT) + ); + + // kern_return_t IORegistryEntryGetPath(io_registry_entry_t entry, const io_name_t plane, io_string_t path); + private static final MethodHandle IORegistryEntryGetPath$Func = linker.downcallHandle( + ioKitLookup.lookup("IORegistryEntryGetPath").get(), + FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS, ADDRESS) + ); + + // CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options); + private static final MethodHandle IORegistryEntryCreateCFProperty$Func = linker.downcallHandle( + ioKitLookup.lookup("IORegistryEntryCreateCFProperty").get(), + FunctionDescriptor.of(ADDRESS, JAVA_INT, ADDRESS, ADDRESS, JAVA_INT) + ); + + // kern_return_t IOCreatePlugInInterfaceForService(io_service_t service, CFUUIDRef pluginType, CFUUIDRef interfaceType, IOCFPlugInInterface ***theInterface, SInt32 *theScore); + private static final MethodHandle IOCreatePlugInInterfaceForService$Func = linker.downcallHandle( + ioKitLookup.lookup("IOCreatePlugInInterfaceForService").get(), + FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS) + ); + + // io_registry_entry_t IORegistryEntryFromPath(mach_port_t mainPort, const io_string_t path); + private static final MethodHandle IORegistryEntryFromPath$Func = linker.downcallHandle( + ioKitLookup.lookup("IORegistryEntryFromPath").get(), + FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS) + ); + + // IONotificationPortRef IONotificationPortCreate(mach_port_t mainPort); + private static final MethodHandle IONotificationPortCreate$Func = linker.downcallHandle( + ioKitLookup.lookup("IONotificationPortCreate").get(), + FunctionDescriptor.of(ADDRESS, JAVA_INT) + ); + + // CFRunLoopSourceRef IONotificationPortGetRunLoopSource(IONotificationPortRef notify); + private static final MethodHandle IONotificationPortGetRunLoopSource$Func = linker.downcallHandle( + ioKitLookup.lookup("IONotificationPortGetRunLoopSource").get(), + FunctionDescriptor.of(ADDRESS, ADDRESS) + ); + + // io_service_t IOServiceGetMatchingService(mach_port_t mainPort, CFDictionaryRef matching); + private static final MethodHandle IOServiceGetMatchingService$Func = linker.downcallHandle( + ioKitLookup.lookup("IOServiceGetMatchingService").get(), + FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS) + ); + + // kern_return_t IOServiceAddMatchingNotification(IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void *refCon, io_iterator_t *notification); + private static final MethodHandle IOServiceAddMatchingNotification$Func = linker.downcallHandle( + ioKitLookup.lookup("IOServiceAddMatchingNotification").get(), + FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS) + ); + + // CFMutableDictionaryRef IOServiceMatching(const char *name); + private static final MethodHandle IOServiceMatching$Func = linker.downcallHandle( + ioKitLookup.lookup("IOServiceMatching").get(), + FunctionDescriptor.of(ADDRESS, ADDRESS) + ); + + // CFMutableDictionaryRef IORegistryEntryIDMatching(uint64_t entryID); + private static final MethodHandle IORegistryEntryIDMatching$Func = linker.downcallHandle( + ioKitLookup.lookup("IORegistryEntryIDMatching").get(), + FunctionDescriptor.of(ADDRESS, JAVA_LONG) + ); + + // kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t *entryID); + private static final MethodHandle IORegistryEntryGetRegistryEntryID$Func = linker.downcallHandle( + ioKitLookup.lookup("IORegistryEntryGetRegistryEntryID").get(), + FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS) + ); + + public static final MemoryAddress kIOUSBDeviceUserClientTypeID = CoreFoundation.CFUUIDCreateFromUUIDBytes( + NULL, + new byte[]{ + (byte) 0x9d, (byte) 0xc7, (byte) 0xb7, (byte) 0x80, + (byte) 0x9e, (byte) 0xc0, (byte) 0x11, (byte) 0xD4, + (byte) 0xa5, (byte) 0x4f, (byte) 0x00, (byte) 0x0a, + (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61 + }); + + public static final MemoryAddress kIOUSBInterfaceUserClientTypeID = CoreFoundation.CFUUIDCreateFromUUIDBytes( + NULL, + new byte[]{ + (byte) 0x2d, (byte) 0x97, (byte) 0x86, (byte) 0xc6, + (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, + (byte) 0xad, (byte) 0x51, (byte) 0x00, (byte) 0x0a, + (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61 + }); + + public static final MemoryAddress kIOUSBDeviceInterfaceID100 = CoreFoundation.CFUUIDCreateFromUUIDBytes( + NULL, + new byte[]{ + (byte) 0x5c, (byte) 0x81, (byte) 0x87, (byte) 0xd0, + (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, + (byte) 0x8b, (byte) 0x45, (byte) 0x00, (byte) 0x0a, + (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61 + }); + + public static final MemoryAddress kIOUSBInterfaceInterfaceID100 = CoreFoundation.CFUUIDCreateFromUUIDBytes( + NULL, + new byte[]{ + (byte) 0x73, (byte) 0xc9, (byte) 0x7a, (byte) 0xe8, + (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, + (byte) 0xb1, (byte) 0xd0, (byte) 0x00, (byte) 0x0a, + (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61 + }); + + public static final MemoryAddress kIOCFPlugInInterfaceID = CoreFoundation.CFUUIDCreateFromUUIDBytes( + NULL, + new byte[]{ + (byte) 0xC2, (byte) 0x44, (byte) 0xE8, (byte) 0x58, + (byte) 0x10, (byte) 0x9C, (byte) 0x11, (byte) 0xD4, + (byte) 0x91, (byte) 0xD4, (byte) 0x00, (byte) 0x50, + (byte) 0xE4, (byte) 0xC6, (byte) 0x42, (byte) 0x6F + }); public static final int kIOMasterPortDefault; - public static final Addressable kIOUSBPlane; - public static final Addressable kIOServicePlane; public static final int kIORegistryIterateRecursively = 1; - public static final MemoryAddress kIOUSBDeviceUserClientTypeID; - public static final MemoryAddress kIOUSBInterfaceUserClientTypeID; - public static final MemoryAddress kIOUSBDeviceInterfaceID100; - public static final MemoryAddress kIOUSBInterfaceInterfaceID100; - public static final MemoryAddress kIOCFPlugInInterfaceID; - - public static final GroupLayout IOCFPlugInInterface$Struct; - private static final VarHandle IUnknown_QueryInterface; - private static final VarHandle IUnknown_AddRef; - private static final VarHandle IUnknown_Release; - - private static final MethodHandle QueryInterface$Func; - private static final MethodHandle AddRef$Func; - private static final MethodHandle Release$Func; - - private static final MethodHandle IORegistryGetRootEntry$Func; - private static final MethodHandle IOObjectRelease$Func; - private static final MethodHandle IORegistryCreateIterator$Func; - private static final MethodHandle IOIteratorNext$Func; - private static final MethodHandle IORegistryEntryCreateCFProperty$Func; - private static final MethodHandle IORegistryEntryGetPath$Func; - private static final MethodHandle IOCreatePlugInInterfaceForService$Func; - private static final MethodHandle IORegistryEntryFromPath$Func; - static { - var linker = Linker.nativeLinker(); - var ioKitSession = MemorySession.openShared(); - var ioKitLookup = SymbolLookup.libraryLookup("IOKit.framework/IOKit", ioKitSession); + public static final MemorySegment kIOUSBDeviceClassName = ioKitSession.allocateUtf8String("IOUSBDevice"); + public static final MemorySegment kIOFirstMatchNotification = ioKitSession.allocateUtf8String("IOServiceFirstMatch"); + public static final MemorySegment kIOTerminatedNotification = ioKitSession.allocateUtf8String("IOServiceTerminate"); + + public static final MemoryAddress kCFRunLoopDefaultMode = javaStringToCfString("kCFRunLoopDefaultMode"); + + static { try (var session = MemorySession.openConfined()) { var kIOMasterPortDefaultAddress = ioKitLookup.lookup("kIOMasterPortDefault").get().address(); kIOMasterPortDefault = MemorySegment.ofAddress(kIOMasterPortDefaultAddress, 4, session).get(JAVA_INT, 0); } - - kIOUSBPlane = ioKitSession.allocateUtf8String("IOUSB"); - kIOServicePlane = ioKitSession.allocateUtf8String("IOService"); - - IOCFPlugInInterface$Struct = MemoryLayout.structLayout( - ADDRESS.withName("_reserved"), // void *_reserved; - ADDRESS.withName("QueryInterface"), // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); - ADDRESS.withName("AddRef"), // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); - ADDRESS.withName("Release"), // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); - JAVA_SHORT.withName("version"), // UInt16 version; - JAVA_SHORT.withName("revision"), // UInt16 revision; - ADDRESS.withName("Probe"), // IOReturn (*Probe)(void *thisPointer, CFDictionaryRef propertyTable, io_service_t service, SInt32 * order); - ADDRESS.withName("Start"), // IOReturn (*Start)(void *thisPointer, CFDictionaryRef propertyTable, io_service_t service); - ADDRESS.withName("Stop") // IOReturn (*Stop)(void *thisPointer); - ); - - IUnknown_QueryInterface = IOCFPlugInInterface$Struct.varHandle(groupElement("QueryInterface")); - IUnknown_AddRef = IOCFPlugInInterface$Struct.varHandle(groupElement("AddRef")); - IUnknown_Release = IOCFPlugInInterface$Struct.varHandle(groupElement("Release")); - - // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); - QueryInterface$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, CFUUIDBytes, ADDRESS) - ); - - // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); - AddRef$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS) - ); - - // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); - Release$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS) - ); - - - // io_registry_entry_t IORegistryGetRootEntry(mach_port_t mainPort); - IORegistryGetRootEntry$Func = linker.downcallHandle( - ioKitLookup.lookup("IORegistryGetRootEntry").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT) - ); - - // kern_return_t IOObjectRelease(io_object_t object); - IOObjectRelease$Func = linker.downcallHandle( - ioKitLookup.lookup("IOObjectRelease").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT) - ); - - // kern_return_t IORegistryEntryCreateIterator(io_registry_entry_t entry, const io_name_t plane, IOOptionBits options, io_iterator_t *iterator); - IORegistryCreateIterator$Func = linker.downcallHandle( - ioKitLookup.lookup("IORegistryCreateIterator").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS, JAVA_INT, ADDRESS) - ); - - // io_object_t IOIteratorNext(io_iterator_t iterator); - IOIteratorNext$Func = linker.downcallHandle( - ioKitLookup.lookup("IOIteratorNext").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT) - ); - - // kern_return_t IORegistryEntryGetPath(io_registry_entry_t entry, const io_name_t plane, io_string_t path); - IORegistryEntryGetPath$Func = linker.downcallHandle( - ioKitLookup.lookup("IORegistryEntryGetPath").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS, ADDRESS) - ); - - // CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options); - IORegistryEntryCreateCFProperty$Func = linker.downcallHandle( - ioKitLookup.lookup("IORegistryEntryCreateCFProperty").get(), - FunctionDescriptor.of(ADDRESS, JAVA_INT, ADDRESS, ADDRESS, JAVA_INT) - ); - - // kern_return_t IOCreatePlugInInterfaceForService(io_service_t service, CFUUIDRef pluginType, CFUUIDRef interfaceType, IOCFPlugInInterface ***theInterface, SInt32 *theScore); - IOCreatePlugInInterfaceForService$Func = linker.downcallHandle( - ioKitLookup.lookup("IOCreatePlugInInterfaceForService").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS) - ); - - // io_registry_entry_t IORegistryEntryFromPath(mach_port_t mainPort, const io_string_t path); - IORegistryEntryFromPath$Func = linker.downcallHandle( - ioKitLookup.lookup("IORegistryEntryFromPath").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS) - ); - - kIOUSBDeviceUserClientTypeID = CoreFoundation.CFUUIDCreateFromUUIDBytes( - NULL, - new byte[]{ - (byte) 0x9d, (byte) 0xc7, (byte) 0xb7, (byte) 0x80, - (byte) 0x9e, (byte) 0xc0, (byte) 0x11, (byte) 0xD4, - (byte) 0xa5, (byte) 0x4f, (byte) 0x00, (byte) 0x0a, - (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61 - }); - - kIOUSBInterfaceUserClientTypeID = CoreFoundation.CFUUIDCreateFromUUIDBytes( - NULL, - new byte[]{ - (byte) 0x2d, (byte) 0x97, (byte) 0x86, (byte) 0xc6, - (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, - (byte) 0xad, (byte) 0x51, (byte) 0x00, (byte) 0x0a, - (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61 - }); - - kIOUSBDeviceInterfaceID100 = CoreFoundation.CFUUIDCreateFromUUIDBytes( - NULL, - new byte[]{ - (byte) 0x5c, (byte) 0x81, (byte) 0x87, (byte) 0xd0, - (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, - (byte) 0x8b, (byte) 0x45, (byte) 0x00, (byte) 0x0a, - (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61 - }); - - kIOUSBInterfaceInterfaceID100 = CoreFoundation.CFUUIDCreateFromUUIDBytes( - NULL, - new byte[]{ - (byte) 0x73, (byte) 0xc9, (byte) 0x7a, (byte) 0xe8, - (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, - (byte) 0xb1, (byte) 0xd0, (byte) 0x00, (byte) 0x0a, - (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61 - }); - - kIOCFPlugInInterfaceID = CoreFoundation.CFUUIDCreateFromUUIDBytes( - NULL, - new byte[]{ - (byte) 0xC2, (byte) 0x44, (byte) 0xE8, (byte) 0x58, - (byte) 0x10, (byte) 0x9C, (byte) 0x11, (byte) 0xD4, - (byte) 0x91, (byte) 0xD4, (byte) 0x00, (byte) 0x50, - (byte) 0xE4, (byte) 0xC6, (byte) 0x42, (byte) 0x6F - }); } // io_registry_entry_t IORegistryGetRootEntry(mach_port_t mainPort); @@ -270,6 +291,70 @@ public static int IORegistryEntryFromPath(int mainPort, String path) { return (MemoryAddress) varHandle.get(obj); } + // IONotificationPortRef IONotificationPortCreate(mach_port_t mainPort); + public static MemoryAddress IONotificationPortCreate(int mainPort) { + try { + return (MemoryAddress) IONotificationPortCreate$Func.invokeExact(mainPort); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + // CFRunLoopSourceRef IONotificationPortGetRunLoopSource(IONotificationPortRef notify); + public static MemoryAddress IONotificationPortGetRunLoopSource(Addressable notify) { + try { + return (MemoryAddress) IONotificationPortGetRunLoopSource$Func.invokeExact(notify); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + // kern_return_t IOServiceAddMatchingNotification(IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void *refCon, io_iterator_t *notification); + public static int IOServiceAddMatchingNotification(Addressable notifyPort, Addressable notificationType, Addressable matching, Addressable callback, Addressable refCon, Addressable notificationHolder) { + try { + return (int) IOServiceAddMatchingNotification$Func.invokeExact(notifyPort, notificationType, matching, callback, refCon, notificationHolder); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + // CFMutableDictionaryRef IOServiceMatching(const char *name); + public static MemoryAddress IOServiceMatching(Addressable name) { + try { + return (MemoryAddress) IOServiceMatching$Func.invokeExact(name); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + // CFMutableDictionaryRef IORegistryEntryIDMatching(uint64_t entryID); + public static MemoryAddress IORegistryEntryIDMatching(long entryID) { + try { + return (MemoryAddress) IORegistryEntryIDMatching$Func.invokeExact(entryID); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + // io_service_t IOServiceGetMatchingService(mach_port_t mainPort, CFDictionaryRef matching); + public static int IOServiceGetMatchingService(int mainPort, Addressable matching) { + try { + return (int) IOServiceGetMatchingService$Func.invokeExact(mainPort, matching); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + // kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t *entryID); + public static int IORegistryEntryGetRegistryEntryID(int entry, Addressable entryIdHolder) { + try { + return (int) IORegistryEntryGetRegistryEntryID$Func.invokeExact(entry, entryIdHolder); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); public static int QueryInterface(MemoryAddress thisPointer, MemorySegment iid, Addressable ppv) { try (var session = MemorySession.openShared()) { @@ -300,40 +385,4 @@ public static int Release(MemoryAddress thisPointer) { } } - /** - * Get an interface of the specified service. - *

- * This method first request the specified plugin interfaces and then - * queries for the specified interface. - *

- * - * @param service the service - * @param pluginType the plugin interface type - * @param interfaceId the interface ID - * @return the interface, or null if the plugin type or interface is not available - */ - public static MemoryAddress GetInterface(int service, Addressable pluginType, MemoryAddress interfaceId) { - try (var session = MemorySession.openConfined()) { - // MemorySegment for holding IOCFPlugInInterface** - var plugPointer = session.allocate(ADDRESS, NULL); - // MemorySegment for holding score - var score = session.allocate(JAVA_INT, 0); - int ret = IOCreatePlugInInterfaceForService(service, pluginType, kIOCFPlugInInterfaceID, plugPointer, score); - if (ret != 0) - return null; - - var plug = Foreign.derefAddress(plugPointer.address(), session); - // MemorySegment for holding XXXInterface** - var intf = session.allocate(ADDRESS, NULL); - // UUID bytes - var refiid = MemorySegment.ofAddress(interfaceId.addOffset(CFUUID_bytes$Offset), CFUUID.byteSize(), session); - ret = QueryInterface(plug, refiid, intf); - Release(plug); - - if (ret != 0) - return null; - return Foreign.derefAddress(intf.address(), session); - } - - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java new file mode 100644 index 00000000..513b1d1f --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -0,0 +1,118 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.macos; + +import net.codecrete.usb.common.Foreign; + +import java.lang.foreign.Addressable; +import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; + +import static java.lang.foreign.MemoryAddress.NULL; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static net.codecrete.usb.macos.CoreFoundation.CFUUID; +import static net.codecrete.usb.macos.CoreFoundation.CFUUID_bytes$Offset; + +/** + * Helper functions for the IOKit framework. + */ +public class IoKitHelper { + private static final long NUMBER_TYPE_ID = CoreFoundation.CFNumberGetTypeID(); + private static final long STRING_TYPE_ID = CoreFoundation.CFStringGetTypeID(); + + /** + * Get an interface of the specified service. + *

+ * This method first request the specified plugin interfaces and then + * queries for the specified interface. + *

+ * + * @param service the service + * @param pluginType the plugin interface type + * @param interfaceId the interface ID + * @return the interface, or null if the plugin type or interface is not available + */ + public static MemoryAddress GetInterface(int service, Addressable pluginType, MemoryAddress interfaceId) { + try (var session = MemorySession.openConfined()) { + // MemorySegment for holding IOCFPlugInInterface** + var plugPointer = session.allocate(ADDRESS, NULL); + // MemorySegment for holding score + var score = session.allocate(JAVA_INT, 0); + int ret = IoKit.IOCreatePlugInInterfaceForService(service, pluginType, IoKit.kIOCFPlugInInterfaceID, plugPointer, score); + if (ret != 0) + return null; + + var plug = Foreign.derefAddress(plugPointer.address(), session); + // MemorySegment for holding XXXInterface** + var intf = session.allocate(ADDRESS, NULL); + // UUID bytes + var refiid = MemorySegment.ofAddress(interfaceId.addOffset(CFUUID_bytes$Offset), CFUUID.byteSize(), session); + ret = IoKit.QueryInterface(plug, refiid, intf); + IoKit.Release(plug); + + if (ret != 0) + return null; + return Foreign.derefAddress(intf.address(), session); + } + + } + + /** + * Gets a property of the specified IO registry service. + *

+ * The property must be of numeric type. + *

+ * @param service the service + * @param key the property key + * @return the property value, or {@code null} if the service doesn't have the property + */ + public static Integer GetPropertyInt(int service, String key) { + var value = IoKit.IORegistryEntryCreateCFProperty(service, key, NULL, 0); + if (value == NULL) + return null; + + Integer result = null; + var type = CoreFoundation.CFGetTypeID(value); + if (type == NUMBER_TYPE_ID) { + + try (var session = MemorySession.openConfined()) { + var numberValue = session.allocate(JAVA_INT, 0); + if (CoreFoundation.CFNumberGetValue(value, CoreFoundation.kCFNumberSInt32Type, numberValue)) + result = numberValue.get(JAVA_INT, 0); + } + } + + CoreFoundation.CFRelease(value); + return result; + } + + /** + * Gets a property of the specified IO registry service. + *

+ * The property must be of string type. + *

+ * @param service the service + * @param key the property key + * @return the property value, or {@code null} if the service doesn't have the property + */ + public static String GetPropertyString(int service, String key) { + var value = IoKit.IORegistryEntryCreateCFProperty(service, key, NULL, 0); + if (value == NULL) + return null; + + String result = null; + var type = CoreFoundation.CFGetTypeID(value); + if (type == STRING_TYPE_ID) + result = CoreFoundation.cfStringToJavaString(value); + + CoreFoundation.CFRelease(value); + return result; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 17e254ea..aa4e1d8d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -10,7 +10,6 @@ import net.codecrete.usb.USBControlTransfer; import net.codecrete.usb.USBDeviceInfo; import net.codecrete.usb.USBDirection; -import net.codecrete.usb.USBException; import net.codecrete.usb.common.USBDescriptors; import net.codecrete.usb.common.USBDeviceImpl; @@ -20,6 +19,8 @@ import java.util.ArrayList; import java.util.List; +import static java.lang.foreign.MemoryAddress.NULL; +import static java.lang.foreign.MemoryAddress.ofLong; import static java.lang.foreign.ValueLayout.*; public class MacosUSBDevice extends USBDeviceImpl { @@ -29,27 +30,33 @@ public class MacosUSBDevice extends USBDeviceImpl { private List claimedInterfaces; private List endpoints; - MacosUSBDevice(String path, USBDeviceInfo info) { - super(path, info); + MacosUSBDevice(Object id, USBDeviceInfo info) { + super(id, info); try (var session = MemorySession.openConfined()) { - // get service from IO registry - final int service = IoKit.IORegistryEntryFromPath(0, path); +// // get service from IO registry +// final int service = IoKit.IORegistryEntryFromPath(0, path); + var matching = IoKit.IORegistryEntryIDMatching((Long) id); + if (matching == NULL) + throw new MacosUSBException("IORegistryEntryIDMatching failed"); + + // Consumes matching instance + int service = IoKit.IOServiceGetMatchingService(IoKit.kIOMasterPortDefault, matching); if (service == 0) - throw new USBException("unable to open USB device (IORegistryEntryFromPath)"); + throw new MacosUSBException("unable to open USB device (IOServiceGetMatchingService)"); session.addCloseAction(() -> IoKit.IOObjectRelease(service)); // get user client interface - device = IoKit.GetInterface(service, IoKit.kIOUSBDeviceUserClientTypeID, IoKit.kIOUSBDeviceInterfaceID100); + device = IoKitHelper.GetInterface(service, IoKit.kIOUSBDeviceUserClientTypeID, IoKit.kIOUSBDeviceInterfaceID100); if (device == null) - throw new USBException("unable to open USB device (get client interface)"); + throw new MacosUSBException("unable to open USB device (get client interface)"); // open device int ret = IoKitUSB.USBDeviceOpen(device); if (ret != 0) { IoKit.Release(device); - throw new USBException("unable to open USB device", ret); + throw new MacosUSBException("unable to open USB device", ret); } try { @@ -57,7 +64,7 @@ public class MacosUSBDevice extends USBDeviceImpl { var descPtrHolder = session.allocate(ADDRESS); ret = IoKitUSB.GetConfigurationDescriptorPtr(device, (byte) 0, descPtrHolder); if (ret != 0) - throw new USBException("failed to query first configuration", ret); + throw new MacosUSBException("failed to query first configuration", ret); // get value of first configuration var configDesc = MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), USBDescriptors.Configuration.byteSize(), session); @@ -66,7 +73,7 @@ public class MacosUSBDevice extends USBDeviceImpl { // set configuration ret = IoKitUSB.SetConfiguration(device, (byte) configurationValue); if (ret != 0) - throw new USBException("failed to set configuration", ret); + throw new MacosUSBException("failed to set configuration", ret); } catch (Throwable e) { IoKitUSB.USBDeviceClose(device); @@ -99,7 +106,7 @@ private InterfaceInfo findInterface(int interfaceNumber) { final int service_final = service; session.addCloseAction(() -> IoKit.IOObjectRelease(service_final)); - final MemoryAddress intf = IoKit.GetInterface(service, IoKit.kIOUSBInterfaceUserClientTypeID, IoKit.kIOUSBInterfaceInterfaceID100); + final MemoryAddress intf = IoKitHelper.GetInterface(service, IoKit.kIOUSBInterfaceUserClientTypeID, IoKit.kIOUSBInterfaceInterfaceID100); if (intf == null) continue; @@ -118,7 +125,7 @@ private InterfaceInfo findInterface(int interfaceNumber) { } } - throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); + throw new MacosUSBException(String.format("Invalid interface number: %d", interfaceNumber)); } public void claimInterface(int interfaceNumber) { @@ -127,7 +134,7 @@ public void claimInterface(int interfaceNumber) { try { var ret = IoKitUSB.USBInterfaceOpen(interfaceInfo.asMemoryAddress()); if (ret != 0) - throw new USBException("Failed to claim interface", ret); + throw new MacosUSBException("Failed to claim interface", ret); } catch (Throwable t) { IoKit.Release(interfaceInfo.asMemoryAddress()); throw t; @@ -144,13 +151,13 @@ public void releaseInterface(int interfaceNumber) { var interfaceInfoOptional = claimedInterfaces.stream().filter(info -> info.interfaceNumber == interfaceNumber).findFirst(); if (interfaceInfoOptional.isEmpty()) - throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); + throw new MacosUSBException(String.format("Invalid interface number: %d", interfaceNumber)); var interfaceInfo = interfaceInfoOptional.get(); int ret = IoKitUSB.USBInterfaceClose(interfaceInfo.asMemoryAddress()); if (ret != 0) - throw new USBException("Failed to release interface", ret); + throw new MacosUSBException("Failed to release interface", ret); claimedInterfaces.remove(interfaceInfo); IoKit.Release(interfaceInfo.asMemoryAddress()); @@ -168,7 +175,7 @@ private void updateEndpointList() { var numEndpointsHolder = session.allocate(JAVA_BYTE); int ret = IoKitUSB.GetNumEndpoints(intf, numEndpointsHolder); if (ret != 0) - throw new USBException("Failed to get number of endpoints", ret); + throw new MacosUSBException("Failed to get number of endpoints", ret); int numEndpoints = numEndpointsHolder.get(JAVA_BYTE, 0) & 255; for (int pipeIndex = 1; pipeIndex <= numEndpoints; pipeIndex++) { @@ -182,7 +189,7 @@ private void updateEndpointList() { ret = IoKitUSB.GetPipeProperties(intf, (byte) pipeIndex, directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); if (ret != 0) - throw new USBException("Failed to get pipe properties", ret); + throw new MacosUSBException("Failed to get pipe properties", ret); var endpointInfo = new EndpointInfo(); endpointInfo.pipeIndex = pipeIndex; @@ -204,7 +211,7 @@ private EndpointInfo getEndpointInfo(int endpointNumber) { return endpointOptional.get(); } - throw new USBException(String.format("Endpoint number %d is not part of a claimed interface or invalid", endpointNumber)); + throw new MacosUSBException(String.format("Endpoint number %d is not part of a claimed interface or invalid", endpointNumber)); } private static MemorySegment createDeviceRequest(MemorySession session, USBDirection direction, USBControlTransfer setup, MemorySegment data) { @@ -227,7 +234,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { int ret = IoKitUSB.DeviceRequest(device, deviceRequest); if (ret != 0) - throw new USBException("Control IN transfer failed", ret); + throw new MacosUSBException("Control IN transfer failed", ret); int lenDone = (int) IoKitUSB.IOUSBDevRequest_wLenDone.get(deviceRequest); return data.asSlice(0, lenDone).toArray(JAVA_BYTE); @@ -245,7 +252,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { int ret = IoKitUSB.DeviceRequest(device, deviceRequest); if (ret != 0) - throw new USBException("Control IN transfer failed", ret); + throw new MacosUSBException("Control IN transfer failed", ret); } } @@ -260,7 +267,7 @@ public void transferOut(int endpointNumber, byte[] data) { int ret = IoKitUSB.WritePipe(endpointInfo.interfaceInfo.asMemoryAddress(), (byte) endpointInfo.pipeIndex, nativeData, data.length); if (ret != 0) - throw new USBException(String.format("Sending data to endpoint %d failed", endpointNumber), ret); + throw new MacosUSBException(String.format("Sending data to endpoint %d failed", endpointNumber), ret); } } @@ -274,7 +281,7 @@ public byte[] transferIn(int endpointNumber, int maxLength) { int ret = IoKitUSB.ReadPipe(endpointInfo.interfaceInfo.asMemoryAddress(), (byte) endpointInfo.pipeIndex, nativeData, sizeHolder); if (ret != 0) - throw new USBException(String.format("Receiving data from endpoint %d failed", endpointNumber), ret); + throw new MacosUSBException(String.format("Receiving data from endpoint %d failed", endpointNumber), ret); int size = sizeHolder.get(JAVA_INT, 0); var result = new byte[size]; @@ -301,7 +308,7 @@ static class InterfaceInfo { int interfaceNumber; MemoryAddress asMemoryAddress() { - return MemoryAddress.ofLong(addr); + return ofLong(addr); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceInfo.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceInfo.java index 516254fb..877f3296 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceInfo.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceInfo.java @@ -13,17 +13,17 @@ public class MacosUSBDeviceInfo extends USBDeviceInfoImpl { MacosUSBDeviceInfo( - String path, int vendorId, int productId, + Object id, int vendorId, int productId, String manufacturer, String product, String serial, int classCode, int subclassCode, int protocolCode) { - super(path, vendorId, productId, + super(id, vendorId, productId, manufacturer, product, serial, classCode, subclassCode, protocolCode); } @Override public USBDevice open() { - return new MacosUSBDevice(path, this); + return new MacosUSBDevice(id, this); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index f266b472..7ca6960f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -10,114 +10,228 @@ import net.codecrete.usb.USBDeviceInfo; import net.codecrete.usb.common.USBDeviceRegistry; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySession; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; import static java.lang.foreign.MemoryAddress.NULL; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.*; public class MacosUSBDeviceRegistry implements USBDeviceRegistry { - private static final long NUMBER_TYPE_ID = CoreFoundation.CFNumberGetTypeID(); - private static final long STRING_TYPE_ID = CoreFoundation.CFStringGetTypeID(); + private Consumer onDeviceConnectedHandler; + private Consumer onDeviceDisconnectedHandler; + private boolean isMonitorThreadStarted; public List getAllDevices() { - List result = new ArrayList<>(); - try (var outerSession = MemorySession.openConfined()) { + try (var session = MemorySession.openConfined()) { final int entry = IoKit.IORegistryGetRootEntry(IoKit.kIOMasterPortDefault); if (entry == 0) throw new RuntimeException("IORegistryGetRootEntry failed"); - outerSession.addCloseAction(() -> IoKit.IOObjectRelease(entry)); + session.addCloseAction(() -> IoKit.IOObjectRelease(entry)); - var iterHolder = outerSession.allocate(JAVA_INT); + var iterHolder = session.allocate(JAVA_INT); int ret = IoKit.IORegistryCreateIterator(0, IoKit.kIOUSBPlane, IoKit.kIORegistryIterateRecursively, iterHolder); final var iter = iterHolder.get(JAVA_INT, 0); if (ret != 0) throw new RuntimeException("IORegistryCreateIterator failed"); - outerSession.addCloseAction(() -> IoKit.IOObjectRelease(iter)); + session.addCloseAction(() -> IoKit.IOObjectRelease(iter)); + + return iterateDevices(iter, false); + } + } - int svc; - while ((svc = IoKit.IOIteratorNext(iter)) != 0) { - try (var session = MemorySession.openConfined()) { + /** + * Return all devices of the iterator in a list + */ + private List iterateDevices(int iter, boolean isDisconnected) { - final int service = svc; - session.addCloseAction(() -> IoKit.IOObjectRelease(service)); + List result = new ArrayList<>(); - // Test if service has user client interface (if not, it is likely a hub) - final MemoryAddress device = IoKit.GetInterface(service, IoKit.kIOUSBDeviceUserClientTypeID, IoKit.kIOUSBDeviceInterfaceID100); + int svc; + while ((svc = IoKit.IOIteratorNext(iter)) != 0) { + try (var session = MemorySession.openConfined()) { + + final int service = svc; + session.addCloseAction(() -> IoKit.IOObjectRelease(service)); + + // Test if service has user client interface (if not, it is likely a hub) + if (!isDisconnected) { + final MemoryAddress device = IoKitHelper.GetInterface(service, IoKit.kIOUSBDeviceUserClientTypeID, IoKit.kIOUSBDeviceInterfaceID100); if (device == null) continue; IoKit.Release(device); + } - // Get registry path - var path = session.allocateArray(JAVA_BYTE, 512); - ret = IoKit.IORegistryEntryGetPath(service, IoKit.kIOServicePlane, path); - if (ret != 0) - continue; + // Get registry path + String path; + var pathSegment = session.allocateArray(JAVA_BYTE, 512); + int ret = IoKit.IORegistryEntryGetPath(service, IoKit.kIOServicePlane, pathSegment); + if (ret == 0) { + path = pathSegment.getUtf8String(0); + } else if (isDisconnected) { + path = ""; + } else { + continue; + } - var deviceInfo = createDeviceInfo(path.getUtf8String(0), service); + // Get entry ID + var entryIdHolder = session.allocate(JAVA_LONG); + ret = IoKit.IORegistryEntryGetRegistryEntryID(service, entryIdHolder); + if (ret != 0) + throw new MacosUSBException("IORegistryEntryGetRegistryEntryID failed", ret); + var entryId = entryIdHolder.get(JAVA_LONG, 0); - if (deviceInfo != null) - result.add(deviceInfo); - } + var deviceInfo = createDeviceInfo(entryId, service); + + if (deviceInfo != null) + result.add(deviceInfo); } } return result; } - private USBDeviceInfo createDeviceInfo(String path, int service) { - Integer vendorId = GetPropertyInt(service, "idVendor"); - Integer productId = GetPropertyInt(service, "idProduct"); - String manufacturer = GetPropertyString(service, "kUSBVendorString"); - String product = GetPropertyString(service, "kUSBProductString"); - String serial = GetPropertyString(service, "kUSBSerialNumberString"); - Integer classCode = GetPropertyInt(service, "bDeviceClass"); - Integer subclassCode = GetPropertyInt(service, "bDeviceSubClass"); - Integer protocolCode = GetPropertyInt(service, "bDeviceProtocol"); - - if (vendorId == null || productId == null || classCode == null || subclassCode == null || protocolCode == null) - return null; + private synchronized void startDeviceMonitor() { + if (isMonitorThreadStarted) + return; - return new MacosUSBDeviceInfo(path, vendorId, productId, manufacturer, product, serial, classCode, subclassCode, protocolCode); + isMonitorThreadStarted = true; + Thread t = new Thread(this::monitorDevices, "USB device monitor"); + t.start(); } - private static Integer GetPropertyInt(int service, String key) { - var value = IoKit.IORegistryEntryCreateCFProperty(service, key, NULL, 0); - if (value == NULL) - return null; + private void monitorDevices() { - Integer result = null; - var type = CoreFoundation.CFGetTypeID(value); - if (type == NUMBER_TYPE_ID) { + try (var session = MemorySession.openConfined()) { - try (var session = MemorySession.openConfined()) { - var numberValue = session.allocate(JAVA_INT, 0); - if (CoreFoundation.CFNumberGetValue(value, CoreFoundation.kCFNumberSInt32Type, numberValue)) - result = numberValue.get(JAVA_INT, 0); - } + var notifyPort = IoKit.IONotificationPortCreate(IoKit.kIOMasterPortDefault); + var runLoopSource = IoKit.IONotificationPortGetRunLoopSource(notifyPort); + + var runLoop = CoreFoundation.CFRunLoopGetCurrent(); + CoreFoundation.CFRunLoopAddSource(runLoop, runLoopSource, IoKit.kCFRunLoopDefaultMode); + + var matchingDict = IoKit.IOServiceMatching(IoKit.kIOUSBDeviceClassName); + + // create callback stub (connected devices) + var onDeviceConnectedMH = MethodHandles.lookup().findVirtual( + MacosUSBDeviceRegistry.class, + "onDeviceConnected", + MethodType.methodType(void.class, MemoryAddress.class, int.class) + ).bindTo(this); + var onDeviceConnectedStub = Linker.nativeLinker().upcallStub( + onDeviceConnectedMH, + FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT), + session + ); + + // Set up a notification to be called when a device is first matched by I/O Kit. + // This method consumes the matchingDict reference. + var deviceIterHolder = session.allocate(JAVA_INT); + int ret = IoKit.IOServiceAddMatchingNotification(notifyPort, IoKit.kIOFirstMatchNotification, + matchingDict, onDeviceConnectedStub, NULL, deviceIterHolder); + if (ret != 0) + throw new MacosUSBException("IOServiceAddMatchingNotification failed", ret); + var deviceConnectedIter = deviceIterHolder.get(JAVA_INT, 0); + + // iterate current devices in order to arm the notifications + onDeviceConnected(NULL, deviceConnectedIter); + + // new matching dictionary for disconnected notifications + matchingDict = IoKit.IOServiceMatching(IoKit.kIOUSBDeviceClassName); + + // create callback stub (connected devices) + var onDeviceDisconnectedMH = MethodHandles.lookup().findVirtual( + MacosUSBDeviceRegistry.class, + "onDeviceDisconnected", + MethodType.methodType(void.class, MemoryAddress.class, int.class) + ).bindTo(this); + var onDeviceDisconnectedStub = Linker.nativeLinker().upcallStub( + onDeviceDisconnectedMH, + FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT), + session + ); + + // Set up a notification to be called when a device is terminated by I/O Kit. + // This method consumes the matchingDict reference. + deviceIterHolder.set(JAVA_INT, 0, 0); + ret = IoKit.IOServiceAddMatchingNotification(notifyPort, IoKit.kIOTerminatedNotification, + matchingDict, onDeviceDisconnectedStub, NULL, deviceIterHolder); + if (ret != 0) + throw new MacosUSBException("IOServiceAddMatchingNotification (2) failed", ret); + var deviceDisconnectedIter = deviceIterHolder.get(JAVA_INT, 0); + + // iterate current devices in order to arm the notifications + onDeviceDisconnected(NULL, deviceDisconnectedIter); + + CoreFoundation.CFRunLoopRun(); + + } catch (NoSuchMethodException | IllegalAccessException e) { + throw new RuntimeException(e); } + } - CoreFoundation.CFRelease(value); - return result; + private void onDeviceConnected(MemoryAddress ignoredRefCon, int iterator) { + var devices = iterateDevices(iterator, false); + if (onDeviceConnectedHandler == null) + return; + + for (var device : devices) + onDeviceConnectedHandler.accept(device); + } + + private void onDeviceDisconnected(MemoryAddress ignoredRefCon, int iterator) { + var devices = iterateDevices(iterator, true); + if (onDeviceDisconnectedHandler == null) + return; + + for (var device : devices) + onDeviceDisconnectedHandler.accept(device); } - private static String GetPropertyString(int service, String key) { - var value = IoKit.IORegistryEntryCreateCFProperty(service, key, NULL, 0); - if (value == NULL) + private USBDeviceInfo createDeviceInfo(long entryID, int service) { + Integer vendorId = IoKitHelper.GetPropertyInt(service, "idVendor"); + Integer productId = IoKitHelper.GetPropertyInt(service, "idProduct"); + String manufacturer = IoKitHelper.GetPropertyString(service, "kUSBVendorString"); + String product = IoKitHelper.GetPropertyString(service, "kUSBProductString"); + String serial = IoKitHelper.GetPropertyString(service, "kUSBSerialNumberString"); + Integer classCode = IoKitHelper.GetPropertyInt(service, "bDeviceClass"); + Integer subclassCode = IoKitHelper.GetPropertyInt(service, "bDeviceSubClass"); + Integer protocolCode = IoKitHelper.GetPropertyInt(service, "bDeviceProtocol"); + + if (vendorId == null || productId == null || classCode == null || subclassCode == null || protocolCode == null) return null; - String result = null; - var type = CoreFoundation.CFGetTypeID(value); - if (type == STRING_TYPE_ID) - result = CoreFoundation.cfStringToJavaString(value); + return new MacosUSBDeviceInfo(entryID, vendorId, productId, manufacturer, product, serial, classCode, subclassCode, protocolCode); + } - CoreFoundation.CFRelease(value); - return result; + @Override + public void setOnDeviceConnected(Consumer handler) { + if (handler == null) { + onDeviceConnectedHandler = null; + return; + } + + onDeviceConnectedHandler = handler; + startDeviceMonitor(); + } + + @Override + public void setOnDeviceDisconnected(Consumer handler) { + if (handler == null) { + onDeviceDisconnectedHandler = null; + return; + } + + onDeviceDisconnectedHandler = handler; + startDeviceMonitor(); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java new file mode 100644 index 00000000..3d59df8d --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java @@ -0,0 +1,29 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +package net.codecrete.usb.macos; + +import net.codecrete.usb.USBException; +import net.codecrete.usb.macos.gen.mach.mach; + +public class MacosUSBException extends USBException { + public MacosUSBException(String message) { + super(message); + } + + public MacosUSBException(String message, int errorCode) { + super(String.format("%s - %s", message, machErrorMessage(errorCode)), errorCode); + } + + public MacosUSBException(String message, Throwable cause) { + super(message, cause); + } + + private static String machErrorMessage(int errorCode) { + var msg = mach.mach_error_string(errorCode); + return msg.getUtf8String(0); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java similarity index 94% rename from java-does-usb/src/main/java/net/codecrete/usb/macos/gen/Constants$root.java rename to java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java index 7697ff6a..7ac0bc7e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java @@ -1,6 +1,6 @@ // Generated by jextract -package net.codecrete.usb.macos.gen; +package net.codecrete.usb.macos.gen.mach; import static java.lang.foreign.ValueLayout.*; public class Constants$root { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java similarity index 99% rename from java-does-usb/src/main/java/net/codecrete/usb/macos/gen/RuntimeHelper.java rename to java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java index 9cf8e4d1..cb43e170 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java @@ -1,4 +1,4 @@ -package net.codecrete.usb.macos.gen; +package net.codecrete.usb.macos.gen.mach; // Generated by jextract import java.lang.foreign.*; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java similarity index 54% rename from java-does-usb/src/main/java/net/codecrete/usb/macos/gen/constants$0.java rename to java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java index 7e25031b..3d61da92 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java @@ -1,11 +1,18 @@ // Generated by jextract -package net.codecrete.usb.macos.gen; +package net.codecrete.usb.macos.gen.mach; import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; class constants$0 { + static final FunctionDescriptor mach_error_string$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle mach_error_string$MH = RuntimeHelper.downcallHandle( + "mach_error_string", + constants$0.mach_error_string$FUNC + ); static final FunctionDescriptor mach_error$FUNC = FunctionDescriptor.ofVoid( Constants$root.C_POINTER$LAYOUT, Constants$root.C_INT$LAYOUT diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java similarity index 67% rename from java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach.java rename to java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java index c9d09ce1..8e162bc9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java @@ -1,8 +1,9 @@ // Generated by jextract -package net.codecrete.usb.macos.gen; +package net.codecrete.usb.macos.gen.mach; import java.lang.foreign.Addressable; +import java.lang.foreign.MemoryAddress; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; @@ -17,6 +18,17 @@ public class mach { public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static MethodHandle mach_error_string$MH() { + return RuntimeHelper.requireNonNull(constants$0.mach_error_string$MH,"mach_error_string"); + } + public static MemoryAddress mach_error_string ( int error_value) { + var mh$ = mach_error_string$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(error_value); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static MethodHandle mach_error$MH() { return RuntimeHelper.requireNonNull(constants$0.mach_error$MH,"mach_error"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 1b413694..a637c22e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -43,16 +43,16 @@ public class WindowsUSBDevice extends USBDeviceImpl { private List claimedInterfaces; - WindowsUSBDevice(String path, USBDeviceInfo info, byte currentConfigurationValue) { - super(path, info); + WindowsUSBDevice(Object id, USBDeviceInfo info, byte currentConfigurationValue) { + super(id, info); this.currentConfigurationValue = currentConfigurationValue; try (var session = MemorySession.openConfined()) { // open Windows device - var chars = path.toCharArray(); - var pathSegment = session.allocateArray(ValueLayout.JAVA_CHAR, chars.length + 1); - pathSegment.copyFrom(MemorySegment.ofArray(chars)); + var pathChars = id.toString().toCharArray(); + var pathSegment = session.allocateArray(ValueLayout.JAVA_CHAR, pathChars.length + 1); + pathSegment.copyFrom(MemorySegment.ofArray(pathChars)); device = Kernel32.CreateFileW(pathSegment, Kernel32.GENERIC_WRITE() | Kernel32.GENERIC_READ(), Kernel32.FILE_SHARE_WRITE() | Kernel32.FILE_SHARE_READ(), diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java index 39c3a22b..1c0a3763 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java @@ -15,12 +15,12 @@ public class WindowsUSBDeviceInfo extends USBDeviceInfoImpl { private final byte currentConfigurationValue; WindowsUSBDeviceInfo( - String path, int vendorId, int productId, + Object id, int vendorId, int productId, String manufacturer, String product, String serial, int classCode, int subclassCode, int protocolCode, byte currentConfigurationValue) { - super(path, vendorId, productId, + super(id, vendorId, productId, manufacturer, product, serial, classCode, subclassCode, protocolCode); this.currentConfigurationValue = currentConfigurationValue; @@ -28,6 +28,6 @@ public class WindowsUSBDeviceInfo extends USBDeviceInfoImpl { @Override public USBDevice open() { - return new WindowsUSBDevice(path, this, currentConfigurationValue); + return new WindowsUSBDevice(id, this, currentConfigurationValue); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 508d5de4..04e8586b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -25,6 +25,7 @@ import java.lang.foreign.MemorySession; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.JAVA_CHAR; @@ -207,4 +208,12 @@ private String getStringDescriptor(Addressable hubHandle, int usbPortNumber, int return new String(chars); } } + + @Override + public void setOnDeviceConnected(Consumer handler) { + } + + @Override + public void setOnDeviceDisconnected(Consumer handler) { + } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java b/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java new file mode 100644 index 00000000..bf1ef2ef --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java @@ -0,0 +1,22 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.sample; + +import net.codecrete.usb.USB; +import net.codecrete.usb.USBDeviceInfo; + +/** + * Sample program enumerating the connected USB devices + */ +public class MonitorDevices { + + public static void main(String[] args) { + USB.setOnDeviceConnected((dev) -> System.out.println("Connected: " + dev.toString())); + USB.setOnDeviceDisconnected((dev) -> System.out.println("Disconnected: " + dev.toString())); + } +} From 45c6f2131055d5b740c2e0c796bb403e30620e8d Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 26 Aug 2022 19:35:27 +0200 Subject: [PATCH 011/433] macOS: suppress initial list of devices when monitoring --- .../usb/macos/MacosUSBDeviceRegistry.java | 39 +++++++++---------- .../usb/windows/WindowsUSBDeviceRegistry.java | 2 +- .../usb/sample/EnumerateDevices.java | 2 +- .../codecrete/usb/sample/MonitorDevices.java | 7 +++- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 7ca6960f..407757dc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -28,6 +28,7 @@ public class MacosUSBDeviceRegistry implements USBDeviceRegistry { private Consumer onDeviceConnectedHandler; private Consumer onDeviceDisconnectedHandler; private boolean isMonitorThreadStarted; + private boolean isMonitoringReady; public List getAllDevices() { @@ -38,7 +39,9 @@ public List getAllDevices() { throw new RuntimeException("IORegistryGetRootEntry failed"); session.addCloseAction(() -> IoKit.IOObjectRelease(entry)); + // create an iterator for USB devices var iterHolder = session.allocate(JAVA_INT); + // TODO: passing 'entry' as the first argument does not work - why? int ret = IoKit.IORegistryCreateIterator(0, IoKit.kIOUSBPlane, IoKit.kIORegistryIterateRecursively, iterHolder); final var iter = iterHolder.get(JAVA_INT, 0); if (ret != 0) @@ -50,42 +53,34 @@ public List getAllDevices() { } /** - * Return all devices of the iterator in a list + * Process the iterator and return a list of devices ({@link USBDeviceInfo}). + * + * @param iterator iterator + * @param isDisconnected flag is the iterator is for disconnected devices + * @return list of devices */ - private List iterateDevices(int iter, boolean isDisconnected) { + private List iterateDevices(int iterator, boolean isDisconnected) { List result = new ArrayList<>(); int svc; - while ((svc = IoKit.IOIteratorNext(iter)) != 0) { + while ((svc = IoKit.IOIteratorNext(iterator)) != 0) { try (var session = MemorySession.openConfined()) { final int service = svc; session.addCloseAction(() -> IoKit.IOObjectRelease(service)); - // Test if service has user client interface (if not, it is likely a hub) + // test if service has user client interface (if not, it is likely a controller) if (!isDisconnected) { - final MemoryAddress device = IoKitHelper.GetInterface(service, IoKit.kIOUSBDeviceUserClientTypeID, IoKit.kIOUSBDeviceInterfaceID100); + final var device = IoKitHelper.GetInterface(service, IoKit.kIOUSBDeviceUserClientTypeID, IoKit.kIOUSBDeviceInterfaceID100); if (device == null) continue; IoKit.Release(device); } - // Get registry path - String path; - var pathSegment = session.allocateArray(JAVA_BYTE, 512); - int ret = IoKit.IORegistryEntryGetPath(service, IoKit.kIOServicePlane, pathSegment); - if (ret == 0) { - path = pathSegment.getUtf8String(0); - } else if (isDisconnected) { - path = ""; - } else { - continue; - } - - // Get entry ID + // get entry ID (as unique ID) var entryIdHolder = session.allocate(JAVA_LONG); - ret = IoKit.IORegistryEntryGetRegistryEntryID(service, entryIdHolder); + int ret = IoKit.IORegistryEntryGetRegistryEntryID(service, entryIdHolder); if (ret != 0) throw new MacosUSBException("IORegistryEntryGetRegistryEntryID failed", ret); var entryId = entryIdHolder.get(JAVA_LONG, 0); @@ -172,6 +167,7 @@ private void monitorDevices() { // iterate current devices in order to arm the notifications onDeviceDisconnected(NULL, deviceDisconnectedIter); + isMonitoringReady = true; CoreFoundation.CFRunLoopRun(); } catch (NoSuchMethodException | IllegalAccessException e) { @@ -181,7 +177,7 @@ private void monitorDevices() { private void onDeviceConnected(MemoryAddress ignoredRefCon, int iterator) { var devices = iterateDevices(iterator, false); - if (onDeviceConnectedHandler == null) + if (onDeviceConnectedHandler == null || !isMonitoringReady) return; for (var device : devices) @@ -190,7 +186,7 @@ private void onDeviceConnected(MemoryAddress ignoredRefCon, int iterator) { private void onDeviceDisconnected(MemoryAddress ignoredRefCon, int iterator) { var devices = iterateDevices(iterator, true); - if (onDeviceDisconnectedHandler == null) + if (onDeviceDisconnectedHandler == null || !isMonitoringReady) return; for (var device : devices) @@ -198,6 +194,7 @@ private void onDeviceDisconnected(MemoryAddress ignoredRefCon, int iterator) { } private USBDeviceInfo createDeviceInfo(long entryID, int service) { + Integer vendorId = IoKitHelper.GetPropertyInt(service, "idVendor"); Integer productId = IoKitHelper.GetPropertyInt(service, "idProduct"); String manufacturer = IoKitHelper.GetPropertyString(service, "kUSBVendorString"); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 04e8586b..e71c550a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -65,7 +65,7 @@ public List getAllDevices() { // get the parent device (a USB hub) var parentDevInstHolder = session.allocate(JAVA_INT); - int devInst = (int) _SP_DEVINFO_DATA.DevInst$get(devInfo); + int devInst = _SP_DEVINFO_DATA.DevInst$get(devInfo); int cmRet = CfgMgr32.CM_Get_Parent(parentDevInstHolder, devInst, 0); if (cmRet != 0) throw new USBException("Internal error (CM_Get_Parent)"); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/EnumerateDevices.java b/java-does-usb/src/test/java/net/codecrete/usb/sample/EnumerateDevices.java index 536044b6..c18a3b45 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/sample/EnumerateDevices.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/sample/EnumerateDevices.java @@ -10,7 +10,7 @@ import net.codecrete.usb.USB; /** - * Sample program enumerating the connected USB devices + * Sample program displaying the connected USB devices */ public class EnumerateDevices { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java b/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java index bf1ef2ef..983c4a0a 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java @@ -8,14 +8,17 @@ package net.codecrete.usb.sample; import net.codecrete.usb.USB; -import net.codecrete.usb.USBDeviceInfo; /** - * Sample program enumerating the connected USB devices + * Sample program displaying information when USB devices are connected or disconnected. + *

+ * Quit with Ctrl-C or whatever stops a program on your platform. + *

*/ public class MonitorDevices { public static void main(String[] args) { + System.out.println("Monitoring USB devices..."); USB.setOnDeviceConnected((dev) -> System.out.println("Connected: " + dev.toString())); USB.setOnDeviceDisconnected((dev) -> System.out.println("Disconnected: " + dev.toString())); } From b419048a904be596121478436c0388dbc5d6c2ff Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 26 Aug 2022 22:26:40 +0200 Subject: [PATCH 012/433] isSameDevice() for easy comparison --- .../java/net/codecrete/usb/USBDevice.java | 19 ++++++++ .../java/net/codecrete/usb/USBDeviceInfo.java | 23 +++++++++- .../codecrete/usb/common/USBDeviceImpl.java | 14 +++++- .../usb/common/USBDeviceInfoImpl.java | 15 +++++- .../codecrete/usb/macos/MacosUSBDevice.java | 8 ++-- .../net/codecrete/usb/IsSameDeviceTest.java | 46 +++++++++++++++++++ 6 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/IsSameDeviceTest.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index cf211508..43f37e7e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -151,4 +151,23 @@ public interface USBDevice extends AutoCloseable { * @return received data */ byte[] transferIn(int endpointNumber, int maxLength); + + + /** + * Returns if this instance and another {@link USBDeviceInfo} instance + * represent the same USB device. + * + * @param device other device instance + * @return {@code true} if they are the same, {@code false} otherwise + */ + boolean isSameDevice(USBDeviceInfo device); + + /** + * Returns if this instance and another {@link USBDevice} instance + * represent the same USB device. + * + * @param device other device info instance + * @return {@code true} if they are the same, {@code false} otherwise + */ + boolean isSameDevice(USBDevice device); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceInfo.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceInfo.java index c9eac5b1..70572e34 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceInfo.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceInfo.java @@ -19,8 +19,9 @@ * and can thus be easily handled in Java. *

*

- * Multiple instances of the class might exist for the same USB device. - * Use {@code equals()} to test if they refer to the same device. + * Multiple instances of this class might exist for the same USB device. + * Use {@code equals()} or {@code isSameDevice()} to test if two instances + * represent the same USB device. *

*/ public interface USBDeviceInfo { @@ -94,4 +95,22 @@ public interface USBDeviceInfo { * @return USB device */ USBDevice open(); + + /** + * Returns if this instance and another {@link USBDevice} instance + * represent the same USB device. + * + * @param device other device instance + * @return {@code true} if they are the same, {@code false} otherwise + */ + boolean isSameDevice(USBDevice device); + + /** + * Returns if this instance and another {@link USBDeviceInfo} instance + * represent the same USB device. + * + * @param device other device info instance + * @return {@code true} if they are the same, {@code false} otherwise + */ + boolean isSameDevice(USBDeviceInfo device); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index a4a04ca7..833ac2d5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -11,7 +11,6 @@ public abstract class USBDeviceImpl implements USBDevice { - protected final Object id; protected final int productId; protected final int vendorId; @@ -111,6 +110,19 @@ protected byte[] getDescriptor(int descriptorType, int index, int language) { return result; } + @Override + public boolean isSameDevice(USBDeviceInfo device) { + if (device instanceof USBDeviceInfoImpl) + return id.equals(((USBDeviceInfoImpl)device).id); + return false; + } + + @Override + public boolean isSameDevice(USBDevice device) { + if (device instanceof USBDeviceImpl) + return id.equals(((USBDeviceImpl)device).id); + return false; + } @Override public boolean equals(Object o) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceInfoImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceInfoImpl.java index 0e55dca6..21f34bc0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceInfoImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceInfoImpl.java @@ -12,7 +12,6 @@ public abstract class USBDeviceInfoImpl implements USBDeviceInfo { - protected final Object id; protected final int productId; protected final int vendorId; @@ -88,6 +87,20 @@ public int getProtocolCode() { return protocolCode; } + @Override + public boolean isSameDevice(USBDeviceInfo device) { + if (device instanceof USBDeviceInfoImpl) + return id.equals(((USBDeviceInfoImpl)device).id); + return false; + } + + @Override + public boolean isSameDevice(USBDevice device) { + if (device instanceof USBDeviceImpl) + return id.equals(((USBDeviceImpl)device).id); + return false; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index aa4e1d8d..3153465e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -294,9 +294,11 @@ public byte[] transferIn(int endpointNumber, int maxLength) { @Override public void close() throws Exception { - for (InterfaceInfo interfaceInfo : claimedInterfaces) { - IoKitUSB.USBInterfaceClose(interfaceInfo.asMemoryAddress()); - IoKit.Release(interfaceInfo.asMemoryAddress()); + if (claimedInterfaces != null) { + for (InterfaceInfo interfaceInfo : claimedInterfaces) { + IoKitUSB.USBInterfaceClose(interfaceInfo.asMemoryAddress()); + IoKit.Release(interfaceInfo.asMemoryAddress()); + } } IoKitUSB.USBDeviceClose(device); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/IsSameDeviceTest.java b/java-does-usb/src/test/java/net/codecrete/usb/IsSameDeviceTest.java new file mode 100644 index 00000000..f91b813d --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/IsSameDeviceTest.java @@ -0,0 +1,46 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Unit test for isSame() +// + +package net.codecrete.usb; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class IsSameDeviceTest { + + @Test + void getAllDevices_includesTestDevice() throws Exception { + var testDeviceInfo = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); + try (var testDevice = testDeviceInfo.open()) { + var deviceList = USB.getAllDevices(); + + long count = deviceList.stream().filter(testDevice::isSameDevice).count(); + assertEquals(1, count); + + count = deviceList.stream().filter((info) -> info.isSameDevice(testDevice)).count(); + assertEquals(1, count); + + count = deviceList.stream().filter(testDeviceInfo::isSameDevice).count(); + assertEquals(1, count); + + count = deviceList.stream().filter((info) -> info.isSameDevice(testDeviceInfo)).count(); + assertEquals(1, count); + } + } + + @Test + void openDevice_isSameAsDeviceInfo() throws Exception { + var testDeviceInfo = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); + try (var testDevice = testDeviceInfo.open()) { + assertTrue(testDevice.isSameDevice(testDeviceInfo)); + assertTrue(testDeviceInfo.isSameDevice(testDevice)); + } + } +} From 164a18fc215f78da1885087349126bf1970a86fd Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 27 Aug 2022 09:49:26 +0200 Subject: [PATCH 013/433] macOS: clean up native API wrappers --- .../codecrete/usb/macos/CoreFoundation.java | 167 ++--- .../usb/macos/CoreFoundationHelper.java | 63 ++ .../java/net/codecrete/usb/macos/IoKit.java | 384 ++++++----- .../net/codecrete/usb/macos/IoKitHelper.java | 2 +- .../net/codecrete/usb/macos/IoKitUSB.java | 608 ++++++++---------- .../java/net/codecrete/usb/macos/Kernel.java | 41 -- 6 files changed, 578 insertions(+), 687 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/Kernel.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundation.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundation.java index 3f2857ae..de430987 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundation.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundation.java @@ -11,11 +11,17 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; -import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.MemoryLayout.sequenceLayout; import static java.lang.foreign.MemoryLayout.structLayout; import static java.lang.foreign.ValueLayout.*; +/** + * Constants and functions for the Core Foundation framework. + *

+ * In the future, jextract will hopefully be able to generate code for + * macOS frameworks in order to generate most of this. + *

+ */ public class CoreFoundation { // Fixed-width types public static final long kCFNumberSInt8Type = 1; @@ -82,109 +88,6 @@ public class CoreFoundation { ADDRESS, ADDRESS, CFUUIDBytes ) ); - - // CFStringRef CFUUIDCreateString(CFAllocatorRef alloc, CFUUIDRef uuid); - private static final MethodHandle CFUUIDCreateString$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFUUIDCreateString").get(), - FunctionDescriptor.of( - ADDRESS, ADDRESS, ADDRESS - ) - ); - - // void CFRelease(CFTypeRef cf); - private static final MethodHandle CFRelease$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFRelease").get(), - FunctionDescriptor.ofVoid(ADDRESS) - ); - - // CFIndex CFStringGetLength(CFStringRef theString); - private static final MethodHandle CFStringGetLength$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFStringGetLength").get(), - FunctionDescriptor.of(JAVA_LONG, ADDRESS) - ); - - // void CFStringGetCharacters(CFStringRef theString, CFRange range, UniChar *buffer); - private static final MethodHandle CFStringGetCharacters$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFStringGetCharacters").get(), - FunctionDescriptor.ofVoid(ADDRESS, CFRange, ADDRESS) - ); - - // CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, const UniChar *chars, CFIndex numChars); - private static final MethodHandle CFStringCreateWithCharacters$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFStringCreateWithCharacters").get(), - FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, JAVA_LONG) - ); - - // CFTypeID CFGetTypeID(CFTypeRef cf); - private static final MethodHandle CFGetTypeID$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFGetTypeID").get(), - FunctionDescriptor.of(JAVA_LONG, ADDRESS) - ); - - // CFTypeID CFNumberGetTypeID(void); - private static final MethodHandle CFNumberGetTypeID$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFNumberGetTypeID").get(), - FunctionDescriptor.of(JAVA_LONG) - ); - - // CFTypeID CFStringGetTypeID(void); - private static final MethodHandle CFStringGetTypeID$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFStringGetTypeID").get(), - FunctionDescriptor.of(JAVA_LONG) - ); - - // CFNumberType CFNumberGetType(CFNumberRef number); - private static final MethodHandle CFNumberGetType$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFNumberGetType").get(), - FunctionDescriptor.of(JAVA_LONG, ADDRESS) - ); - - // Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void *valuePtr); - private static final MethodHandle CFNumberGetValue$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFNumberGetValue").get(), - FunctionDescriptor.of(JAVA_BOOLEAN, ADDRESS, JAVA_LONG, ADDRESS) - ); - // CFRunLoopRef CFRunLoopGetCurrent(void); - private static final MethodHandle CFRunLoopGetCurrent$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFRunLoopGetCurrent").get(), - FunctionDescriptor.of(ADDRESS) - ); - // void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode); - private static final MethodHandle CFRunLoopAddSource$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFRunLoopAddSource").get(), - FunctionDescriptor.ofVoid(ADDRESS, ADDRESS, ADDRESS) - ); - // void CFRunLoopRun(void); - private static final MethodHandle CFRunLoopRun$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFRunLoopRun").get(), - FunctionDescriptor.ofVoid() - ); - - - public static String cfStringToJavaString(MemoryAddress string) { - try (var session = MemorySession.openConfined()) { - long strLen = CFStringGetLength(string); - var buffer = session.allocateArray(JAVA_CHAR, strLen); - var range = session.allocate(CFRange); - CFRange_location.set(range, 0); - CFRange_range.set(range, strLen); - CFStringGetCharacters(string, range, buffer); - return new String(buffer.toArray(JAVA_CHAR)); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - public static MemoryAddress javaStringToCfString(String string) { - try (var session = MemorySession.openConfined()) { - char[] charArray = string.toCharArray(); - var chars = session.allocateArray(JAVA_CHAR, charArray.length); - chars.copyFrom(MemorySegment.ofArray(charArray)); - return CFStringCreateWithCharacters(NULL, chars, string.length()); - } - } - - // CFUUIDRef CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc, CFUUIDBytes bytes); public static MemoryAddress CFUUIDCreateFromUUIDBytes(Addressable allocator, byte[] bytes) { try (var session = MemorySession.openConfined()) { var uuidBytes = session.allocate(16); @@ -196,10 +99,16 @@ public static MemoryAddress CFUUIDCreateFromUUIDBytes(Addressable allocator, byt } // CFStringRef CFUUIDCreateString(CFAllocatorRef alloc, CFUUIDRef uuid); + private static final MethodHandle CFUUIDCreateString$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFUUIDCreateString").get(), + FunctionDescriptor.of( + ADDRESS, ADDRESS, ADDRESS + ) + ); public static String CFUUIDCreateString(Addressable allocator, Addressable uuid) { try { MemoryAddress str = (MemoryAddress) CFUUIDCreateString$Func.invokeExact(allocator, uuid); - String result = cfStringToJavaString(str); + String result = CoreFoundationHelper.stringFromCFStringRef(str); CFRelease(str); return result; } catch (Throwable t) { @@ -208,6 +117,10 @@ public static String CFUUIDCreateString(Addressable allocator, Addressable uuid) } // void CFRelease(CFTypeRef cf); + private static final MethodHandle CFRelease$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFRelease").get(), + FunctionDescriptor.ofVoid(ADDRESS) + ); public static void CFRelease(Addressable object) { try { CFRelease$Func.invokeExact(object); @@ -217,6 +130,10 @@ public static void CFRelease(Addressable object) { } // CFIndex CFStringGetLength(CFStringRef theString); + private static final MethodHandle CFStringGetLength$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFStringGetLength").get(), + FunctionDescriptor.of(JAVA_LONG, ADDRESS) + ); public static long CFStringGetLength(Addressable str) { try { return (long) CFStringGetLength$Func.invokeExact(str); @@ -226,6 +143,10 @@ public static long CFStringGetLength(Addressable str) { } // void CFStringGetCharacters(CFStringRef theString, CFRange range, UniChar *buffer); + private static final MethodHandle CFStringGetCharacters$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFStringGetCharacters").get(), + FunctionDescriptor.ofVoid(ADDRESS, CFRange, ADDRESS) + ); public static void CFStringGetCharacters(Addressable str, MemorySegment range, Addressable buffer) { try { CFStringGetCharacters$Func.invokeExact(str, range, buffer); @@ -235,6 +156,10 @@ public static void CFStringGetCharacters(Addressable str, MemorySegment range, A } // CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, const UniChar *chars, CFIndex numChars); + private static final MethodHandle CFStringCreateWithCharacters$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFStringCreateWithCharacters").get(), + FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, JAVA_LONG) + ); public static MemoryAddress CFStringCreateWithCharacters(Addressable allocator, Addressable chars, long numChars) { try { return (MemoryAddress) CFStringCreateWithCharacters$Func.invokeExact(allocator, chars, numChars); @@ -244,6 +169,10 @@ public static MemoryAddress CFStringCreateWithCharacters(Addressable allocator, } // CFTypeID CFGetTypeID(CFTypeRef cf); + private static final MethodHandle CFGetTypeID$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFGetTypeID").get(), + FunctionDescriptor.of(JAVA_LONG, ADDRESS) + ); public static long CFGetTypeID(Addressable cf) { try { return (long) CFGetTypeID$Func.invokeExact(cf); @@ -253,6 +182,10 @@ public static long CFGetTypeID(Addressable cf) { } // CFTypeID CFNumberGetTypeID(void); + private static final MethodHandle CFNumberGetTypeID$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFNumberGetTypeID").get(), + FunctionDescriptor.of(JAVA_LONG) + ); public static long CFNumberGetTypeID() { try { return (long) CFNumberGetTypeID$Func.invokeExact(); @@ -262,6 +195,10 @@ public static long CFNumberGetTypeID() { } // CFTypeID CFStringGetTypeID(void); + private static final MethodHandle CFStringGetTypeID$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFStringGetTypeID").get(), + FunctionDescriptor.of(JAVA_LONG) + ); public static long CFStringGetTypeID() { try { return (long) CFStringGetTypeID$Func.invokeExact(); @@ -271,6 +208,10 @@ public static long CFStringGetTypeID() { } // CFNumberType CFNumberGetType(CFNumberRef number); + private static final MethodHandle CFNumberGetType$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFNumberGetType").get(), + FunctionDescriptor.of(JAVA_LONG, ADDRESS) + ); public static long CFNumberGetType(Addressable number) { try { return (long) CFNumberGetType$Func.invokeExact(number); @@ -280,6 +221,10 @@ public static long CFNumberGetType(Addressable number) { } // Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void *valuePtr); + private static final MethodHandle CFNumberGetValue$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFNumberGetValue").get(), + FunctionDescriptor.of(JAVA_BOOLEAN, ADDRESS, JAVA_LONG, ADDRESS) + ); public static boolean CFNumberGetValue(Addressable number, long theType, Addressable valuePtr) { try { return (boolean) CFNumberGetValue$Func.invokeExact(number, theType, valuePtr); @@ -289,6 +234,10 @@ public static boolean CFNumberGetValue(Addressable number, long theType, Address } // CFRunLoopRef CFRunLoopGetCurrent(void); + private static final MethodHandle CFRunLoopGetCurrent$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFRunLoopGetCurrent").get(), + FunctionDescriptor.of(ADDRESS) + ); public static MemoryAddress CFRunLoopGetCurrent() { try { return (MemoryAddress) CFRunLoopGetCurrent$Func.invokeExact(); @@ -298,6 +247,10 @@ public static MemoryAddress CFRunLoopGetCurrent() { } // void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode); + private static final MethodHandle CFRunLoopAddSource$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFRunLoopAddSource").get(), + FunctionDescriptor.ofVoid(ADDRESS, ADDRESS, ADDRESS) + ); public static void CFRunLoopAddSource(Addressable runLoop, Addressable source, Addressable mode) { try { CFRunLoopAddSource$Func.invokeExact(runLoop, source, mode); @@ -307,6 +260,10 @@ public static void CFRunLoopAddSource(Addressable runLoop, Addressable source, A } // void CFRunLoopRun(void); + private static final MethodHandle CFRunLoopRun$Func = linker.downcallHandle( + coreFoundationLookup.lookup("CFRunLoopRun").get(), + FunctionDescriptor.ofVoid() + ); public static void CFRunLoopRun() { try { CFRunLoopRun$Func.invokeExact(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java new file mode 100644 index 00000000..b589abdd --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java @@ -0,0 +1,63 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.macos; + +import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; + +import static java.lang.foreign.MemoryAddress.NULL; +import static java.lang.foreign.ValueLayout.JAVA_CHAR; + +/** + * Core Foundation helper functions + */ +public class CoreFoundationHelper { + + /** + * Gets Java string as a copy of the {@code CFStringRef}. + * + * @param string the string to copy ({@code CFStringRef}) + * @return copied string + */ + public static String stringFromCFStringRef(MemoryAddress string) { + + try (var session = MemorySession.openConfined()) { + + long strLen = CoreFoundation.CFStringGetLength(string); + var buffer = session.allocateArray(JAVA_CHAR, strLen); + var range = session.allocate(CoreFoundation.CFRange); + CoreFoundation.CFRange_location.set(range, 0); + CoreFoundation.CFRange_range.set(range, strLen); + CoreFoundation.CFStringGetCharacters(string, range, buffer); + return new String(buffer.toArray(JAVA_CHAR)); + + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + /** + * Creates a {@code CFStringRef} with a copy of the specified string + *

+ * Ownership follows the Create Rule, i.e. the caller takes + * ownership without incrementing the reference count. + *

+ * + * @param string the string + * @return {@code CFStringRef} + */ + public static MemoryAddress createCFStringRef(String string) { + try (var session = MemorySession.openConfined()) { + char[] charArray = string.toCharArray(); + var chars = session.allocateArray(JAVA_CHAR, charArray.length); + chars.copyFrom(MemorySegment.ofArray(charArray)); + return CoreFoundation.CFStringCreateWithCharacters(NULL, chars, string.length()); + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java index 7d8dc238..c386f077 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java @@ -15,8 +15,15 @@ import static java.lang.foreign.MemoryLayout.PathElement.groupElement; import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.macos.CoreFoundation.CFUUIDBytes; -import static net.codecrete.usb.macos.CoreFoundation.javaStringToCfString; - +import static net.codecrete.usb.macos.CoreFoundationHelper.createCFStringRef; + +/** + * Constants and functions for the IOKit framework. + *

+ * In the future, jextract will hopefully be able to generate code for + * macOS frameworks in order to generate most of this. + *

+ */ public class IoKit { private static final Linker linker = Linker.nativeLinker(); @@ -26,6 +33,15 @@ public class IoKit { public static final Addressable kIOUSBPlane = ioKitSession.allocateUtf8String("IOUSB"); public static final Addressable kIOServicePlane = ioKitSession.allocateUtf8String("IOService"); + public static final int kIOMasterPortDefault; + public static final int kIORegistryIterateRecursively = 1; + + public static final MemorySegment kIOUSBDeviceClassName = ioKitSession.allocateUtf8String("IOUSBDevice"); + public static final MemorySegment kIOFirstMatchNotification = ioKitSession.allocateUtf8String("IOServiceFirstMatch"); + public static final MemorySegment kIOTerminatedNotification = ioKitSession.allocateUtf8String("IOServiceTerminate"); + + public static final MemoryAddress kCFRunLoopDefaultMode = createCFStringRef("kCFRunLoopDefaultMode"); + public static final GroupLayout IOCFPlugInInterface$Struct = MemoryLayout.structLayout( ADDRESS.withName("_reserved"), // void *_reserved; ADDRESS.withName("QueryInterface"), // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); @@ -38,114 +54,261 @@ public class IoKit { ADDRESS.withName("Stop") // IOReturn (*Stop)(void *thisPointer); ); - private static final VarHandle IUnknown_QueryInterface = IOCFPlugInInterface$Struct.varHandle(groupElement("QueryInterface")); - private static final VarHandle IUnknown_AddRef = IOCFPlugInInterface$Struct.varHandle(groupElement("AddRef")); - private static final VarHandle IUnknown_Release = IOCFPlugInInterface$Struct.varHandle(groupElement("Release")); + /** + * Looks up the address of the specified virtual function in the {@code IOCFPlugInInterface} object + * @param thisPointer pointer to pointer to object + * @param varHandle variable handle to virtual function + * @param session memory session + * @return function address + */ + private static Addressable IOCFPlugInInterfaceFunctionAddress(MemoryAddress thisPointer, VarHandle varHandle, MemorySession session) { + var seg = MemorySegment.ofAddress(thisPointer, ADDRESS.byteSize(), session); + var thisValue = seg.get(ADDRESS, 0); + var obj = MemorySegment.ofAddress(thisValue, IOCFPlugInInterface$Struct.byteSize(), session); + return (MemoryAddress) varHandle.get(obj); + } // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); + private static final VarHandle IUnknown_QueryInterface = IOCFPlugInInterface$Struct.varHandle(groupElement("QueryInterface")); private static final MethodHandle QueryInterface$Func = linker.downcallHandle( FunctionDescriptor.of(JAVA_INT, ADDRESS, CFUUIDBytes, ADDRESS) ); + public static int QueryInterface(MemoryAddress thisPointer, MemorySegment iid, Addressable ppv) { + try (var session = MemorySession.openShared()) { + var funcPtr = IOCFPlugInInterfaceFunctionAddress(thisPointer, IUnknown_QueryInterface, session); + return (int) QueryInterface$Func.invokeExact(funcPtr, (Addressable) thisPointer, iid, ppv); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); + private static final VarHandle IUnknown_AddRef = IOCFPlugInInterface$Struct.varHandle(groupElement("AddRef")); private static final MethodHandle AddRef$Func = linker.downcallHandle( FunctionDescriptor.of(JAVA_INT, ADDRESS) ); + public static int AddRef(MemoryAddress thisPointer) { + try (var session = MemorySession.openShared()) { + var funcPtr = IOCFPlugInInterfaceFunctionAddress(thisPointer, IUnknown_AddRef, session); + return (int) AddRef$Func.invokeExact(funcPtr, (Addressable) thisPointer); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); + private static final VarHandle IUnknown_Release = IOCFPlugInInterface$Struct.varHandle(groupElement("Release")); private static final MethodHandle Release$Func = linker.downcallHandle( FunctionDescriptor.of(JAVA_INT, ADDRESS) ); + public static int Release(MemoryAddress thisPointer) { + try (var session = MemorySession.openShared()) { + var funcPtr = IOCFPlugInInterfaceFunctionAddress(thisPointer, IUnknown_Release, session); + return (int) Release$Func.invokeExact(funcPtr, (Addressable) thisPointer); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } // io_registry_entry_t IORegistryGetRootEntry(mach_port_t mainPort); private static final MethodHandle IORegistryGetRootEntry$Func = linker.downcallHandle( ioKitLookup.lookup("IORegistryGetRootEntry").get(), FunctionDescriptor.of(JAVA_INT, JAVA_INT) ); + public static int IORegistryGetRootEntry(int mainPort) { + try { + return (int) IORegistryGetRootEntry$Func.invokeExact(mainPort); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } // kern_return_t IOObjectRelease(io_object_t object); private static final MethodHandle IOObjectRelease$Func = linker.downcallHandle( ioKitLookup.lookup("IOObjectRelease").get(), FunctionDescriptor.of(JAVA_INT, JAVA_INT) ); + public static int IOObjectRelease(int object) { + try { + return (int) IOObjectRelease$Func.invokeExact(object); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } // kern_return_t IORegistryEntryCreateIterator(io_registry_entry_t entry, const io_name_t plane, IOOptionBits options, io_iterator_t *iterator); private static final MethodHandle IORegistryCreateIterator$Func = linker.downcallHandle( ioKitLookup.lookup("IORegistryCreateIterator").get(), FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS, JAVA_INT, ADDRESS) ); + public static int IORegistryCreateIterator(int entry, Addressable plane, int options, Addressable iterator) { + try { + return (int) IORegistryCreateIterator$Func.invokeExact(entry, plane, options, iterator); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } // io_object_t IOIteratorNext(io_iterator_t iterator); private static final MethodHandle IOIteratorNext$Func = linker.downcallHandle( ioKitLookup.lookup("IOIteratorNext").get(), FunctionDescriptor.of(JAVA_INT, JAVA_INT) ); + public static int IOIteratorNext(int iter) { + try { + return (int) IOIteratorNext$Func.invokeExact(iter); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } // kern_return_t IORegistryEntryGetPath(io_registry_entry_t entry, const io_name_t plane, io_string_t path); private static final MethodHandle IORegistryEntryGetPath$Func = linker.downcallHandle( ioKitLookup.lookup("IORegistryEntryGetPath").get(), FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS, ADDRESS) ); - - // CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options); - private static final MethodHandle IORegistryEntryCreateCFProperty$Func = linker.downcallHandle( - ioKitLookup.lookup("IORegistryEntryCreateCFProperty").get(), - FunctionDescriptor.of(ADDRESS, JAVA_INT, ADDRESS, ADDRESS, JAVA_INT) - ); + public static int IORegistryEntryGetPath(int entry, Addressable plane, Addressable path) { + try { + return (int) IORegistryEntryGetPath$Func.invokeExact(entry, plane, path); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } // kern_return_t IOCreatePlugInInterfaceForService(io_service_t service, CFUUIDRef pluginType, CFUUIDRef interfaceType, IOCFPlugInInterface ***theInterface, SInt32 *theScore); private static final MethodHandle IOCreatePlugInInterfaceForService$Func = linker.downcallHandle( ioKitLookup.lookup("IOCreatePlugInInterfaceForService").get(), FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS) ); + public static int IOCreatePlugInInterfaceForService(int service, Addressable pluginType, Addressable interfaceType, Addressable intf, Addressable score) { + try { + return (int) IOCreatePlugInInterfaceForService$Func.invokeExact(service, pluginType, interfaceType, intf, score); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + // CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options); + private static final MethodHandle IORegistryEntryCreateCFProperty$Func = linker.downcallHandle( + ioKitLookup.lookup("IORegistryEntryCreateCFProperty").get(), + FunctionDescriptor.of(ADDRESS, JAVA_INT, ADDRESS, ADDRESS, JAVA_INT) + ); + public static MemoryAddress IORegistryEntryCreateCFProperty(int entry, String key, Addressable allocator, int options) { + try { + var keyStr = CoreFoundationHelper.createCFStringRef(key); + var propValue = (MemoryAddress) IORegistryEntryCreateCFProperty$Func.invokeExact(entry, (Addressable) keyStr, allocator, options); + CoreFoundation.CFRelease(keyStr); + return propValue; + } catch (Throwable e) { + throw new RuntimeException(e); + } + } // io_registry_entry_t IORegistryEntryFromPath(mach_port_t mainPort, const io_string_t path); private static final MethodHandle IORegistryEntryFromPath$Func = linker.downcallHandle( ioKitLookup.lookup("IORegistryEntryFromPath").get(), FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS) ); + public static int IORegistryEntryFromPath(int mainPort, String path) { + try (var session = MemorySession.openConfined()) { + var pathCStr = session.allocateUtf8String(path); + return (int) IORegistryEntryFromPath$Func.invokeExact(mainPort, (Addressable) pathCStr); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } // IONotificationPortRef IONotificationPortCreate(mach_port_t mainPort); private static final MethodHandle IONotificationPortCreate$Func = linker.downcallHandle( ioKitLookup.lookup("IONotificationPortCreate").get(), FunctionDescriptor.of(ADDRESS, JAVA_INT) ); + public static MemoryAddress IONotificationPortCreate(int mainPort) { + try { + return (MemoryAddress) IONotificationPortCreate$Func.invokeExact(mainPort); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } // CFRunLoopSourceRef IONotificationPortGetRunLoopSource(IONotificationPortRef notify); private static final MethodHandle IONotificationPortGetRunLoopSource$Func = linker.downcallHandle( ioKitLookup.lookup("IONotificationPortGetRunLoopSource").get(), FunctionDescriptor.of(ADDRESS, ADDRESS) ); + public static MemoryAddress IONotificationPortGetRunLoopSource(Addressable notify) { + try { + return (MemoryAddress) IONotificationPortGetRunLoopSource$Func.invokeExact(notify); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } // io_service_t IOServiceGetMatchingService(mach_port_t mainPort, CFDictionaryRef matching); private static final MethodHandle IOServiceGetMatchingService$Func = linker.downcallHandle( ioKitLookup.lookup("IOServiceGetMatchingService").get(), FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS) ); + public static int IOServiceGetMatchingService(int mainPort, Addressable matching) { + try { + return (int) IOServiceGetMatchingService$Func.invokeExact(mainPort, matching); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + // kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t *entryID); + private static final MethodHandle IORegistryEntryGetRegistryEntryID$Func = linker.downcallHandle( + ioKitLookup.lookup("IORegistryEntryGetRegistryEntryID").get(), + FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS) + ); + + public static int IORegistryEntryGetRegistryEntryID(int entry, Addressable entryIdHolder) { + try { + return (int) IORegistryEntryGetRegistryEntryID$Func.invokeExact(entry, entryIdHolder); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } // kern_return_t IOServiceAddMatchingNotification(IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void *refCon, io_iterator_t *notification); private static final MethodHandle IOServiceAddMatchingNotification$Func = linker.downcallHandle( ioKitLookup.lookup("IOServiceAddMatchingNotification").get(), FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS) ); + public static int IOServiceAddMatchingNotification(Addressable notifyPort, Addressable notificationType, Addressable matching, Addressable callback, Addressable refCon, Addressable notificationHolder) { + try { + return (int) IOServiceAddMatchingNotification$Func.invokeExact(notifyPort, notificationType, matching, callback, refCon, notificationHolder); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } // CFMutableDictionaryRef IOServiceMatching(const char *name); private static final MethodHandle IOServiceMatching$Func = linker.downcallHandle( ioKitLookup.lookup("IOServiceMatching").get(), FunctionDescriptor.of(ADDRESS, ADDRESS) ); + public static MemoryAddress IOServiceMatching(Addressable name) { + try { + return (MemoryAddress) IOServiceMatching$Func.invokeExact(name); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } // CFMutableDictionaryRef IORegistryEntryIDMatching(uint64_t entryID); private static final MethodHandle IORegistryEntryIDMatching$Func = linker.downcallHandle( ioKitLookup.lookup("IORegistryEntryIDMatching").get(), FunctionDescriptor.of(ADDRESS, JAVA_LONG) ); - - // kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t *entryID); - private static final MethodHandle IORegistryEntryGetRegistryEntryID$Func = linker.downcallHandle( - ioKitLookup.lookup("IORegistryEntryGetRegistryEntryID").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS) - ); + public static MemoryAddress IORegistryEntryIDMatching(long entryID) { + try { + return (MemoryAddress) IORegistryEntryIDMatching$Func.invokeExact(entryID); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } public static final MemoryAddress kIOUSBDeviceUserClientTypeID = CoreFoundation.CFUUIDCreateFromUUIDBytes( NULL, @@ -191,15 +354,6 @@ public class IoKit { (byte) 0x91, (byte) 0xD4, (byte) 0x00, (byte) 0x50, (byte) 0xE4, (byte) 0xC6, (byte) 0x42, (byte) 0x6F }); - public static final int kIOMasterPortDefault; - public static final int kIORegistryIterateRecursively = 1; - - public static final MemorySegment kIOUSBDeviceClassName = ioKitSession.allocateUtf8String("IOUSBDevice"); - public static final MemorySegment kIOFirstMatchNotification = ioKitSession.allocateUtf8String("IOServiceFirstMatch"); - public static final MemorySegment kIOTerminatedNotification = ioKitSession.allocateUtf8String("IOServiceTerminate"); - - - public static final MemoryAddress kCFRunLoopDefaultMode = javaStringToCfString("kCFRunLoopDefaultMode"); static { try (var session = MemorySession.openConfined()) { @@ -207,182 +361,4 @@ public class IoKit { kIOMasterPortDefault = MemorySegment.ofAddress(kIOMasterPortDefaultAddress, 4, session).get(JAVA_INT, 0); } } - - // io_registry_entry_t IORegistryGetRootEntry(mach_port_t mainPort); - public static int IORegistryGetRootEntry(int mainPort) { - try { - return (int) IORegistryGetRootEntry$Func.invokeExact(mainPort); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // kern_return_t IOObjectRelease(io_object_t object); - public static int IOObjectRelease(int object) { - try { - return (int) IOObjectRelease$Func.invokeExact(object); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // kern_return_t IORegistryEntryCreateIterator(io_registry_entry_t entry, const io_name_t plane, IOOptionBits options, io_iterator_t *iterator); - public static int IORegistryCreateIterator(int entry, Addressable plane, int options, Addressable iterator) { - try { - return (int) IORegistryCreateIterator$Func.invokeExact(entry, plane, options, iterator); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // io_object_t IOIteratorNext(io_iterator_t iterator); - public static int IOIteratorNext(int iter) { - try { - return (int) IOIteratorNext$Func.invokeExact(iter); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options); - public static MemoryAddress IORegistryEntryCreateCFProperty(int entry, String key, Addressable allocator, int options) { - try { - var keyStr = CoreFoundation.javaStringToCfString(key); - var propValue = (MemoryAddress) IORegistryEntryCreateCFProperty$Func.invokeExact(entry, (Addressable) keyStr, allocator, options); - CoreFoundation.CFRelease(keyStr); - return propValue; - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // kern_return_t IORegistryEntryGetPath(io_registry_entry_t entry, const io_name_t plane, io_string_t path); - public static int IORegistryEntryGetPath(int entry, Addressable plane, Addressable path) { - try { - return (int) IORegistryEntryGetPath$Func.invokeExact(entry, plane, path); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // kern_return_t IOCreatePlugInInterfaceForService(io_service_t service, CFUUIDRef pluginType, CFUUIDRef interfaceType, IOCFPlugInInterface ***theInterface, SInt32 *theScore); - public static int IOCreatePlugInInterfaceForService(int service, Addressable pluginType, Addressable interfaceType, Addressable intf, Addressable score) { - try { - return (int) IOCreatePlugInInterfaceForService$Func.invokeExact(service, pluginType, interfaceType, intf, score); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // io_registry_entry_t IORegistryEntryFromPath(mach_port_t mainPort, const io_string_t path); - public static int IORegistryEntryFromPath(int mainPort, String path) { - try (var session = MemorySession.openConfined()) { - var pathCStr = session.allocateUtf8String(path); - return (int) IORegistryEntryFromPath$Func.invokeExact(mainPort, (Addressable) pathCStr); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - private static Addressable IOCFPlugInInterface$VirtFunc(MemoryAddress thisPointer, VarHandle varHandle, MemorySession session) { - var seg = MemorySegment.ofAddress(thisPointer, ADDRESS.byteSize(), session); - var thisValue = seg.get(ADDRESS, 0); - var obj = MemorySegment.ofAddress(thisValue, IOCFPlugInInterface$Struct.byteSize(), session); - return (MemoryAddress) varHandle.get(obj); - } - - // IONotificationPortRef IONotificationPortCreate(mach_port_t mainPort); - public static MemoryAddress IONotificationPortCreate(int mainPort) { - try { - return (MemoryAddress) IONotificationPortCreate$Func.invokeExact(mainPort); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // CFRunLoopSourceRef IONotificationPortGetRunLoopSource(IONotificationPortRef notify); - public static MemoryAddress IONotificationPortGetRunLoopSource(Addressable notify) { - try { - return (MemoryAddress) IONotificationPortGetRunLoopSource$Func.invokeExact(notify); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // kern_return_t IOServiceAddMatchingNotification(IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void *refCon, io_iterator_t *notification); - public static int IOServiceAddMatchingNotification(Addressable notifyPort, Addressable notificationType, Addressable matching, Addressable callback, Addressable refCon, Addressable notificationHolder) { - try { - return (int) IOServiceAddMatchingNotification$Func.invokeExact(notifyPort, notificationType, matching, callback, refCon, notificationHolder); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // CFMutableDictionaryRef IOServiceMatching(const char *name); - public static MemoryAddress IOServiceMatching(Addressable name) { - try { - return (MemoryAddress) IOServiceMatching$Func.invokeExact(name); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // CFMutableDictionaryRef IORegistryEntryIDMatching(uint64_t entryID); - public static MemoryAddress IORegistryEntryIDMatching(long entryID) { - try { - return (MemoryAddress) IORegistryEntryIDMatching$Func.invokeExact(entryID); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // io_service_t IOServiceGetMatchingService(mach_port_t mainPort, CFDictionaryRef matching); - public static int IOServiceGetMatchingService(int mainPort, Addressable matching) { - try { - return (int) IOServiceGetMatchingService$Func.invokeExact(mainPort, matching); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t *entryID); - public static int IORegistryEntryGetRegistryEntryID(int entry, Addressable entryIdHolder) { - try { - return (int) IORegistryEntryGetRegistryEntryID$Func.invokeExact(entry, entryIdHolder); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - - // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); - public static int QueryInterface(MemoryAddress thisPointer, MemorySegment iid, Addressable ppv) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOCFPlugInInterface$VirtFunc(thisPointer, IUnknown_QueryInterface, session); - return (int) QueryInterface$Func.invokeExact(funcPtr, (Addressable) thisPointer, iid, ppv); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); - public static int AddRef(MemoryAddress thisPointer) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOCFPlugInInterface$VirtFunc(thisPointer, IUnknown_AddRef, session); - return (int) AddRef$Func.invokeExact(funcPtr, (Addressable) thisPointer); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); - public static int Release(MemoryAddress thisPointer) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOCFPlugInInterface$VirtFunc(thisPointer, IUnknown_Release, session); - return (int) Release$Func.invokeExact(funcPtr, (Addressable) thisPointer); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index 513b1d1f..124f17e1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -110,7 +110,7 @@ public static String GetPropertyString(int service, String key) { String result = null; var type = CoreFoundation.CFGetTypeID(value); if (type == STRING_TYPE_ID) - result = CoreFoundation.cfStringToJavaString(value); + result = CoreFoundationHelper.stringFromCFStringRef(value); CoreFoundation.CFRelease(value); return result; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index 99436446..2d6fa7a1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -15,327 +15,95 @@ import static java.lang.foreign.MemoryLayout.structLayout; import static java.lang.foreign.ValueLayout.*; +/** + * Constants and functions for the USB specifict parts of IOKit framework. + *

+ * In the future, jextract will hopefully be able to generate code for + * macOS frameworks in order to generate most of this. + *

+ */ public class IoKitUSB { + private static final Linker linker = Linker.nativeLinker(); public static final short kIOUSBFindInterfaceDontCare = (short) 0xFFFF; - public static final GroupLayout IOUSBFindInterfaceRequest$Struct; - public static final VarHandle IOUSBFindInterfaceRequest_bInterfaceClass; - public static final VarHandle IOUSBFindInterfaceRequest_bInterfaceSubClass; - public static final VarHandle IOUSBFindInterfaceRequest_bInterfaceProtocol; - public static final VarHandle IOUSBFindInterfaceRequest_bAlternateSetting; - - private static final GroupLayout IOUSBDevice$Struct; - - private static final VarHandle IOUSBDevice_USBDeviceOpen; - private static final VarHandle IOUSBDevice_USBDeviceClose; - private static final VarHandle IOUSBDevice_SetConfiguration; - private static final VarHandle IOUSBDevice_GetConfigurationDescriptorPtr; - private static final VarHandle IOUSBDevice_GetNumberOfConfigurations; - private static final VarHandle IOUSBDevice_CreateInterfaceIterator; - private static final VarHandle IOUSBDevice_DeviceRequest; - - private static final MethodHandle USBDeviceOpen$Func; - private static final MethodHandle USBDeviceClose$Func; - private static final MethodHandle SetConfiguration$Func; - private static final MethodHandle GetConfigurationDescriptorPtr$Func; - private static final MethodHandle GetNumberOfConfigurations$Func; - private static final MethodHandle CreateInterfaceIterator$Func; - private static final MethodHandle DeviceRequest$Func; - - private static final GroupLayout IOUSBInterface$Struct; - - private static final VarHandle IOUSBInterface_USBInterfaceOpen; - private static final VarHandle IOUSBInterface_USBInterfaceClose; - private static final VarHandle IOUSBInterface_GetInterfaceNumber; - private static final VarHandle IOUSBInterface_GetNumEndpoints; - private static final VarHandle IOUSBInterface_GetPipeProperties; - private static final VarHandle IOUSBInterface_ReadPipe; - private static final VarHandle IOUSBInterface_WritePipe; - - private static final MethodHandle USBInterfaceOpen$Func; - private static final MethodHandle USBInterfaceClose$Func; - private static final MethodHandle GetInterfaceNumber$Func; - private static final MethodHandle GetNumEndpoints$Func; - private static final MethodHandle GetPipeProperties$Func; - private static final MethodHandle ReadPipe$Func; - private static final MethodHandle WritePipe$Func; - - public static final GroupLayout IOUSBDevRequest$Struct; - public static final VarHandle IOUSBDevRequest_bmRequestType; - public static final VarHandle IOUSBDevRequest_bRequest; - public static final VarHandle IOUSBDevRequest_wValue; - public static final VarHandle IOUSBDevRequest_wIndex; - public static final VarHandle IOUSBDevRequest_wLength; - public static final VarHandle IOUSBDevRequest_pData; - public static final VarHandle IOUSBDevRequest_wLenDone; - - - static { - var linker = Linker.nativeLinker(); - - // typedef struct { - // UInt16 bInterfaceClass; // requested class - // UInt16 bInterfaceSubClass; // requested subclass - // UInt16 bInterfaceProtocol; // requested protocol - // UInt16 bAlternateSetting; // requested alt setting - // } IOUSBFindInterfaceRequest; - IOUSBFindInterfaceRequest$Struct = structLayout( - JAVA_SHORT.withName("bInterfaceClass"), - JAVA_SHORT.withName("bInterfaceSubClass"), - JAVA_SHORT.withName("bInterfaceProtocol"), - JAVA_SHORT.withName("bAlternateSetting") - ); - - IOUSBFindInterfaceRequest_bInterfaceClass = IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bInterfaceClass")); - IOUSBFindInterfaceRequest_bInterfaceSubClass = IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bInterfaceSubClass")); - IOUSBFindInterfaceRequest_bInterfaceProtocol = IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bInterfaceProtocol")); - IOUSBFindInterfaceRequest_bAlternateSetting = IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bAlternateSetting")); - - IOUSBDevice$Struct = structLayout( - ADDRESS.withName("_reserved"), // void *_reserved; - ADDRESS.withName("QueryInterface"), // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); - ADDRESS.withName("AddRef"), // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); - ADDRESS.withName("Release"), // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); - ADDRESS.withName("CreateDeviceAsyncEventSource"), // IOReturn (*CreateDeviceAsyncEventSource)(void *self, CFRunLoopSourceRef *source); - ADDRESS.withName("GetDeviceAsyncEventSource"), // CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void *self); - ADDRESS.withName("CreateDeviceAsyncPort"), // IOReturn (*CreateDeviceAsyncPort)(void *self, mach_port_t *port); - ADDRESS.withName("GetDeviceAsyncPort"), // mach_port_t (*GetDeviceAsyncPort)(void *self); - ADDRESS.withName("USBDeviceOpen"), // IOReturn (*USBDeviceOpen)(void *self); - ADDRESS.withName("USBDeviceClose"), // IOReturn (*USBDeviceClose)(void *self); - ADDRESS.withName("GetDeviceClass"), // IOReturn (*GetDeviceClass)(void *self, UInt8 *devClass); - ADDRESS.withName("GetDeviceSubClass"), // IOReturn (*GetDeviceSubClass)(void *self, UInt8 *devSubClass); - ADDRESS.withName("GetDeviceProtocol"), // IOReturn (*GetDeviceProtocol)(void *self, UInt8 *devProtocol); - ADDRESS.withName("GetDeviceVendor"), // IOReturn (*GetDeviceVendor)(void *self, UInt16 *devVendor); - ADDRESS.withName("GetDeviceProduct"), // IOReturn (*GetDeviceProduct)(void *self, UInt16 *devProduct); - ADDRESS.withName("GetDeviceReleaseNumber"), // IOReturn (*GetDeviceReleaseNumber)(void *self, UInt16 *devRelNum); - ADDRESS.withName("GetDeviceAddress"), // IOReturn (*GetDeviceAddress)(void *self, USBDeviceAddress *addr); - ADDRESS.withName("GetDeviceBusPowerAvailable"), // IOReturn (*GetDeviceBusPowerAvailable)(void *self, UInt32 *powerAvailable); - ADDRESS.withName("GetDeviceSpeed"), // IOReturn (*GetDeviceSpeed)(void *self, UInt8 *devSpeed); - ADDRESS.withName("GetNumberOfConfigurations"), // IOReturn (*GetNumberOfConfigurations)(void *self, UInt8 *numConfig); - ADDRESS.withName("GetLocationID"), // IOReturn (*GetLocationID)(void *self, UInt32 *locationID); - ADDRESS.withName("GetConfigurationDescriptorPtr"), // IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc); - ADDRESS.withName("GetConfiguration"), // IOReturn (*GetConfiguration)(void *self, UInt8 *configNum); - ADDRESS.withName("SetConfiguration"), // IOReturn (*SetConfiguration)(void *self, UInt8 configNum); - ADDRESS.withName("GetBusFrameNumber"), // IOReturn (*GetBusFrameNumber)(void *self, UInt64 *frame, AbsoluteTime *atTime); - ADDRESS.withName("ResetDevice"), // IOReturn (*ResetDevice)(void *self); - ADDRESS.withName("DeviceRequest"), // IOReturn (*DeviceRequest)(void *self, IOUSBDevRequest *req); - ADDRESS.withName("DeviceRequestAsync"), // IOReturn (*DeviceRequestAsync)(void *self, IOUSBDevRequest *req, IOAsyncCallback1 callback, void *refCon); - ADDRESS.withName("CreateInterfaceIterator"), // IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter); - ADDRESS.withName("USBDeviceOpenSeize"), // IOReturn (*USBDeviceOpenSeize)(void *self); - ADDRESS.withName("DeviceRequestTO"), // IOReturn (*DeviceRequestTO)(void *self, IOUSBDevRequestTO *req); - ADDRESS.withName("DeviceRequestAsyncTO"), // IOReturn (*DeviceRequestAsyncTO)(void *self, IOUSBDevRequestTO *req, IOAsyncCallback1 callback, void *refCon); - ADDRESS.withName("USBDeviceSuspend"), // IOReturn (*USBDeviceSuspend)(void *self, Boolean suspend); - ADDRESS.withName("USBDeviceAbortPipeZero"), // IOReturn (*USBDeviceAbortPipeZero)(void *self); - ADDRESS.withName("USBGetManufacturerStringIndex"), // IOReturn (*USBGetManufacturerStringIndex)(void *self, UInt8 *msi); - ADDRESS.withName("USBGetProductStringIndex"), // IOReturn (*USBGetProductStringIndex)(void *self, UInt8 *psi); - ADDRESS.withName("USBGetSerialNumberStringIndex"), // IOReturn (*USBGetSerialNumberStringIndex)(void *self, UInt8 *snsi); - ADDRESS.withName("USBDeviceReEnumerate"), // IOReturn (*USBDeviceReEnumerate)(void *self, UInt32 options); - ADDRESS.withName("GetBusMicroFrameNumber"), // IOReturn (*GetBusMicroFrameNumber)(void *self, UInt64 *microFrame, AbsoluteTime *atTime); - ADDRESS.withName("GetIOUSBLibVersion"), // IOReturn (*GetIOUSBLibVersion)(void *self, NumVersion *ioUSBLibVersion, NumVersion *usbFamilyVersion); - ADDRESS.withName("GetBusFrameNumberWithTime"), // IOReturn (*GetBusFrameNumberWithTime)(void *self, UInt64 *frame, AbsoluteTime *atTime); - ADDRESS.withName("GetUSBDeviceInformation"), // IOReturn (*GetUSBDeviceInformation)(void *self, UInt32 *info); - ADDRESS.withName("RequestExtraPower"), // IOReturn (*RequestExtraPower)(void *self, UInt32 type, UInt32 requestedPower, UInt32 *powerAvailable); - ADDRESS.withName("ReturnExtraPower"), // IOReturn (*ReturnExtraPower)(void *self, UInt32 type, UInt32 powerReturned); - ADDRESS.withName("GetExtraPowerAllocated"), // IOReturn (*GetExtraPowerAllocated)(void *self, UInt32 type, UInt32 *powerAllocated); - ADDRESS.withName("GetBandwidthAvailableForDevice"), // IOReturn (*GetBandwidthAvailableForDevice)(void *self, UInt32 *bandwidth); - ADDRESS.withName("SetConfigurationV2"), // IOReturn (*SetConfigurationV2)(void *self, UInt8 configNum, bool startInterfaceMatching, bool issueRemoteWakeup); - ADDRESS.withName("RegisterForNotification"), // IOReturn (*RegisterForNotification)(void * self, UInt64 notificationMask, IOAsyncCallback2 callback, void *refCon, UInt64 *pRegistrationToken); - ADDRESS.withName("UnregisterNotification"), // IOReturn (*UnregisterNotification)(void *self, UInt64 registrationToken); - ADDRESS.withName("AcknowledgeNotification") // IOReturn (*AcknowledgeNotification)(void *self, UInt64 notificationToken); - ); - - IOUSBDevice_USBDeviceOpen = IOUSBDevice$Struct.varHandle(groupElement("USBDeviceOpen")); - IOUSBDevice_USBDeviceClose = IOUSBDevice$Struct.varHandle(groupElement("USBDeviceClose")); - IOUSBDevice_GetNumberOfConfigurations = IOUSBDevice$Struct.varHandle(groupElement("GetNumberOfConfigurations")); - IOUSBDevice_GetConfigurationDescriptorPtr = IOUSBDevice$Struct.varHandle(groupElement("GetConfigurationDescriptorPtr")); - IOUSBDevice_SetConfiguration = IOUSBDevice$Struct.varHandle(groupElement("SetConfiguration")); - IOUSBDevice_CreateInterfaceIterator = IOUSBDevice$Struct.varHandle(groupElement("CreateInterfaceIterator")); - IOUSBDevice_DeviceRequest = IOUSBDevice$Struct.varHandle(groupElement("DeviceRequest")); - - // IOReturn (*USBDeviceOpen)(void *self); - USBDeviceOpen$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS) - ); - - // IOReturn (*USBDeviceClose)(void *self); - USBDeviceClose$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS) - ); - - // IOReturn (*GetNumberOfConfigurations)(void *self, UInt8 *numConfig); - GetNumberOfConfigurations$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS) - ); - - // IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc); - GetConfigurationDescriptorPtr$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS) - ); - - // IOReturn (*SetConfiguration)(void *self, UInt8 configNum); - SetConfiguration$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE) - ); - - // IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter); - CreateInterfaceIterator$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS) - ); - - // IOReturn (*DeviceRequest)(void *self, IOUSBDevRequest *req); - DeviceRequest$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS) - ); - - IOUSBInterface$Struct = structLayout( - ADDRESS.withName("_reserved"), // void *_reserved; - ADDRESS.withName("QueryInterface"), // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); - ADDRESS.withName("AddRef"), // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); - ADDRESS.withName("Release"), // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); - ADDRESS.withName("CreateInterfaceAsyncEventSource"), // IOReturn (*CreateInterfaceAsyncEventSource)(void *self, CFRunLoopSourceRef *source); - ADDRESS.withName("GetInterfaceAsyncEventSource"), // CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void *self); - ADDRESS.withName("CreateInterfaceAsyncPort"), // IOReturn (*CreateInterfaceAsyncPort)(void *self, mach_port_t *port); - ADDRESS.withName("GetInterfaceAsyncPort"), // mach_port_t (*GetInterfaceAsyncPort)(void *self); - ADDRESS.withName("USBInterfaceOpen"), // IOReturn (*USBInterfaceOpen)(void *self); - ADDRESS.withName("USBInterfaceClose"), // IOReturn (*USBInterfaceClose)(void *self); - ADDRESS.withName("GetInterfaceClass"), // IOReturn (*GetInterfaceClass)(void *self, UInt8 *intfClass); - ADDRESS.withName("GetInterfaceSubClass"), // IOReturn (*GetInterfaceSubClass)(void *self, UInt8 *intfSubClass); - ADDRESS.withName("GetInterfaceProtocol"), // IOReturn (*GetInterfaceProtocol)(void *self, UInt8 *intfProtocol); - ADDRESS.withName("GetDeviceVendor"), // IOReturn (*GetDeviceVendor)(void *self, UInt16 *devVendor); - ADDRESS.withName("GetDeviceProduct"), // IOReturn (*GetDeviceProduct)(void *self, UInt16 *devProduct); - ADDRESS.withName("GetDeviceReleaseNumber"), // IOReturn (*GetDeviceReleaseNumber)(void *self, UInt16 *devRelNum); - ADDRESS.withName("GetConfigurationValue"), // IOReturn (*GetConfigurationValue)(void *self, UInt8 *configVal); - ADDRESS.withName("GetInterfaceNumber"), // IOReturn (*GetInterfaceNumber)(void *self, UInt8 *intfNumber); - ADDRESS.withName("GetAlternateSetting"), // IOReturn (*GetAlternateSetting)(void *self, UInt8 *intfAltSetting); - ADDRESS.withName("GetNumEndpoints"), // IOReturn (*GetNumEndpoints)(void *self, UInt8 *intfNumEndpoints); - ADDRESS.withName("GetLocationID"), // IOReturn (*GetLocationID)(void *self, UInt32 *locationID); - ADDRESS.withName("GetDevice"), // IOReturn (*GetDevice)(void *self, io_service_t *device); - ADDRESS.withName("SetAlternateInterface"), // IOReturn (*SetAlternateInterface)(void *self, UInt8 alternateSetting); - ADDRESS.withName("GetBusFrameNumber"), // IOReturn (*GetBusFrameNumber)(void *self, UInt64 *frame, AbsoluteTime *atTime); - ADDRESS.withName("ControlRequest"), // IOReturn (*ControlRequest)(void *self, UInt8 pipeRef, IOUSBDevRequest *req); - ADDRESS.withName("ControlRequestAsync"), // IOReturn (*ControlRequestAsync)(void *self, UInt8 pipeRef, IOUSBDevRequest *req, IOAsyncCallback1 callback, void *refCon); - ADDRESS.withName("GetPipeProperties"), // IOReturn (*GetPipeProperties)(void *self, UInt8 pipeRef, UInt8 *direction, UInt8 *number, UInt8 *transferType, UInt16 *maxPacketSize, UInt8 *interval); - ADDRESS.withName("GetPipeStatus"), // IOReturn (*GetPipeStatus)(void *self, UInt8 pipeRef); - ADDRESS.withName("AbortPipe"), // IOReturn (*AbortPipe)(void *self, UInt8 pipeRef); - ADDRESS.withName("ResetPipe"), // IOReturn (*ResetPipe)(void *self, UInt8 pipeRef); - ADDRESS.withName("ClearPipeStall"), // IOReturn (*ClearPipeStall)(void *self, UInt8 pipeRef); - ADDRESS.withName("ReadPipe"), // IOReturn (*ReadPipe)(void *self, UInt8 pipeRef, void *buf, UInt32 *size); - ADDRESS.withName("WritePipe"), // IOReturn (*WritePipe)(void *self, UInt8 pipeRef, void *buf, UInt32 size); - ADDRESS.withName("ReadPipeAsync"), // IOReturn (*ReadPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("WritePipeAsync"), // IOReturn (*WritePipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("ReadIsochPipeAsync"), // IOReturn (*ReadIsochPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt64 frameStart, UInt32 numFrames, IOUSBIsocFrame *frameList, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("WriteIsochPipeAsync"), // IOReturn (*WriteIsochPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt64 frameStart, UInt32 numFrames, IOUSBIsocFrame *frameList, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("ControlRequestTO"), // IOReturn (*ControlRequestTO)(void *self, UInt8 pipeRef, IOUSBDevRequestTO *req); - ADDRESS.withName("ControlRequestAsyncTO"), // IOReturn (*ControlRequestAsyncTO)(void *self, UInt8 pipeRef, IOUSBDevRequestTO *req, IOAsyncCallback1 callback, void *refCon); - ADDRESS.withName("ReadPipeTO"), // IOReturn (*ReadPipeTO)(void *self, UInt8 pipeRef, void *buf, UInt32 *size, UInt32 noDataTimeout, UInt32 completionTimeout); - ADDRESS.withName("WritePipeTO"), // IOReturn (*WritePipeTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout); - ADDRESS.withName("ReadPipeAsyncTO"), // IOReturn (*ReadPipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("WritePipeAsyncTO"), // IOReturn (*WritePipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("USBInterfaceGetStringIndex"), // IOReturn (*USBInterfaceGetStringIndex)(void *self, UInt8 *si); - ADDRESS.withName("USBInterfaceOpenSeize"), // IOReturn (*USBInterfaceOpenSeize)(void *self); - ADDRESS.withName("ClearPipeStallBothEnds"), // IOReturn (*ClearPipeStallBothEnds)(void *self, UInt8 pipeRef); - ADDRESS.withName("SetPipePolicy"), // IOReturn (*SetPipePolicy)(void *self, UInt8 pipeRef, UInt16 maxPacketSize, UInt8 maxInterval); - ADDRESS.withName("GetBandwidthAvailable"), // IOReturn (*GetBandwidthAvailable)(void *self, UInt32 *bandwidth); - ADDRESS.withName("GetEndpointProperties"), // IOReturn (*GetEndpointProperties)(void *self, UInt8 alternateSetting, UInt8 endpointNumber, UInt8 direction, UInt8 *transferType, UInt16 *maxPacketSize, UInt8 *interval); - ADDRESS.withName("LowLatencyReadIsochPipeAsync"), // IOReturn (*LowLatencyReadIsochPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt64 frameStart, UInt32 numFrames, UInt32 updateFrequency, IOUSBLowLatencyIsocFrame *frameList, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("LowLatencyWriteIsochPipeAsync"), // IOReturn (*LowLatencyWriteIsochPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt64 frameStart, UInt32 numFrames, UInt32 updateFrequency, IOUSBLowLatencyIsocFrame *frameList, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("LowLatencyCreateBuffer"), // IOReturn (*LowLatencyCreateBuffer)(void * self, void **buffer, IOByteCount size, UInt32 bufferType); - ADDRESS.withName("LowLatencyDestroyBuffer"), // IOReturn (*LowLatencyDestroyBuffer) (void * self, void * buffer ); - ADDRESS.withName("GetBusMicroFrameNumber"), // IOReturn (*GetBusMicroFrameNumber)(void *self, UInt64 *microFrame, AbsoluteTime *atTime); - ADDRESS.withName("GetFrameListTime"), // IOReturn (*GetFrameListTime)(void *self, UInt32 *microsecondsInFrame); - ADDRESS.withName("GetIOUSBLibVersion"), // IOReturn (*GetIOUSBLibVersion)(void *self, NumVersion *ioUSBLibVersion, NumVersion *usbFamilyVersion); - ADDRESS.withName("FindNextAssociatedDescriptor"), // IOUSBDescriptorHeader * (*FindNextAssociatedDescriptor)(void *self, const void *currentDescriptor, UInt8 descriptorType); - ADDRESS.withName("FindNextAltInterface"), // IOUSBDescriptorHeader * (*FindNextAltInterface)(void *self, const void *current, IOUSBFindInterfaceRequest *request); - ADDRESS.withName("GetBusFrameNumberWithTime"), // IOReturn (*GetBusFrameNumberWithTime)(void *self, UInt64 *frame, AbsoluteTime *atTime); - ADDRESS.withName("GetPipePropertiesV2"), // IOReturn (*GetPipePropertiesV2)(void *self, UInt8 pipeRef, UInt8 *direction, UInt8 *number, UInt8 *transferType, UInt16 *maxPacketSize, UInt8 *interval, UInt8 *maxBurst, UInt8 *mult, UInt16 *bytesPerInterval); - ADDRESS.withName("GetPipePropertiesV3"), // IOReturn (*GetPipePropertiesV3)(void *self, UInt8 pipeRef, IOUSBEndpointProperties *properties); - ADDRESS.withName("GetEndpointPropertiesV3"), // IOReturn (*GetEndpointPropertiesV3)(void *self, IOUSBEndpointProperties *properties); - ADDRESS.withName("SupportsStreams"), // IOReturn (*SupportsStreams)(void *self, UInt8 pipeRef, UInt32 *supportsStreams); - ADDRESS.withName("CreateStreams"), // IOReturn (*CreateStreams)(void *self, UInt8 pipeRef, UInt32 streamID); - ADDRESS.withName("GetConfiguredStreams"), // IOReturn (*GetConfiguredStreams)(void *self, UInt8 pipeRef, UInt32 *configuredStreams); - ADDRESS.withName("ReadStreamsPipeTO"), // IOReturn (*ReadStreamsPipeTO)(void *self, UInt8 pipeRef, UInt32 streamID, void *buf, UInt32 *size, UInt32 noDataTimeout, UInt32 completionTimeout); - ADDRESS.withName("WriteStreamsPipeTO"), // IOReturn (*WriteStreamsPipeTO)(void *self, UInt8 pipeRef, UInt32 streamID, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout); - ADDRESS.withName("ReadStreamsPipeAsyncTO"), // IOReturn (*ReadStreamsPipeAsyncTO)(void *self, UInt8 pipeRef, UInt32 streamID, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("WriteStreamsPipeAsyncTO"), // IOReturn (*WriteStreamsPipeAsyncTO)(void *self, UInt8 pipeRef, UInt32 streamID, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("AbortStreamsPipe"), // IOReturn (*AbortStreamsPipe)(void *self, UInt8 pipeRef, UInt32 streamID); - ADDRESS.withName("RegisterForNotification"), // IOReturn (*RegisterForNotification)(void * self, UInt64 notificationMask, IOAsyncCallback2 callback, void *refCon, UInt64 *pRegistrationToken); - ADDRESS.withName("UnregisterNotification"), // IOReturn (*UnregisterNotification)(void *self, UInt64 registrationToken); - ADDRESS.withName("AcknowledgeNotification"), // IOReturn (*AcknowledgeNotification)(void *self, UInt64 notificationToken); - ADDRESS.withName("RegisterDriver") // IOReturn (*RegisterDriver)(void *self); - ); - - IOUSBInterface_USBInterfaceOpen = IOUSBInterface$Struct.varHandle(groupElement("USBInterfaceOpen")); - IOUSBInterface_USBInterfaceClose = IOUSBInterface$Struct.varHandle(groupElement("USBInterfaceClose")); - IOUSBInterface_GetInterfaceNumber = IOUSBInterface$Struct.varHandle(groupElement("GetInterfaceNumber")); - IOUSBInterface_GetNumEndpoints = IOUSBInterface$Struct.varHandle(groupElement("GetNumEndpoints")); - IOUSBInterface_GetPipeProperties = IOUSBInterface$Struct.varHandle(groupElement("GetPipeProperties")); - IOUSBInterface_ReadPipe = IOUSBInterface$Struct.varHandle(groupElement("ReadPipe")); - IOUSBInterface_WritePipe = IOUSBInterface$Struct.varHandle(groupElement("WritePipe")); - - // IOReturn (*USBInterfaceOpen)(void *self);; - USBInterfaceOpen$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS) - ); - - // IOReturn (*USBInterfaceClose)(void *self);; - USBInterfaceClose$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS) - ); - - // IOReturn (*GetInterfaceNumber)(void *self, UInt8 *intfNumber); - GetInterfaceNumber$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS) - ); - - // IOReturn (*GetNumEndpoints)(void *self, UInt8 *intfNumEndpoints); - GetNumEndpoints$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS) - ); - - // IOReturn (*GetPipeProperties)(void *self, UInt8 pipeRef, UInt8 *direction, UInt8 *number, UInt8 *transferType, UInt16 *maxPacketSize, UInt8 *interval); - GetPipeProperties$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS) - ); - - // IOReturn (*ReadPipe)(void *self, UInt8 pipeRef, void *buf, UInt32 *size); - ReadPipe$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS, ADDRESS) - ); - - // IOReturn (*WritePipe)(void *self, UInt8 pipeRef, void *buf, UInt32 size); - WritePipe$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS, JAVA_INT) - ); - - // typedef struct { - // UInt8 bmRequestType; - // UInt8 bRequest; - // UInt16 wValue; - // UInt16 wIndex; - // UInt16 wLength; - // void* pData; - // UInt32 wLenDone; - //} IOUSBDevRequest; - IOUSBDevRequest$Struct = structLayout( - JAVA_BYTE.withName("bmRequestType"), - JAVA_BYTE.withName("bRequest"), - JAVA_SHORT.withName("wValue"), - JAVA_SHORT.withName("wIndex"), - JAVA_SHORT.withName("wLength"), - ADDRESS.withName("pData"), - JAVA_INT.withName("wLenDone") - ); - - IOUSBDevRequest_bmRequestType = IOUSBDevRequest$Struct.varHandle(groupElement("bmRequestType")); - IOUSBDevRequest_bRequest = IOUSBDevRequest$Struct.varHandle(groupElement("bRequest")); - IOUSBDevRequest_wValue = IOUSBDevRequest$Struct.varHandle(groupElement("wValue")); - IOUSBDevRequest_wIndex = IOUSBDevRequest$Struct.varHandle(groupElement("wIndex")); - IOUSBDevRequest_wLength = IOUSBDevRequest$Struct.varHandle(groupElement("wLength")); - IOUSBDevRequest_pData = IOUSBDevRequest$Struct.varHandle(groupElement("pData")); - IOUSBDevRequest_wLenDone = IOUSBDevRequest$Struct.varHandle(groupElement("wLenDone")); - } - - private static Addressable IOUSBDevice$VirtFunc(MemoryAddress thisPointer, VarHandle varHandle, MemorySession session) { + // typedef struct { + // UInt16 bInterfaceClass; // requested class + // UInt16 bInterfaceSubClass; // requested subclass + // UInt16 bInterfaceProtocol; // requested protocol + // UInt16 bAlternateSetting; // requested alt setting + // } IOUSBFindInterfaceRequest; + public static final GroupLayout IOUSBFindInterfaceRequest$Struct = structLayout( + JAVA_SHORT.withName("bInterfaceClass"), + JAVA_SHORT.withName("bInterfaceSubClass"), + JAVA_SHORT.withName("bInterfaceProtocol"), + JAVA_SHORT.withName("bAlternateSetting") + ); + public static final VarHandle IOUSBFindInterfaceRequest_bInterfaceClass = IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bInterfaceClass")); + public static final VarHandle IOUSBFindInterfaceRequest_bInterfaceSubClass = IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bInterfaceSubClass")); + public static final VarHandle IOUSBFindInterfaceRequest_bInterfaceProtocol = IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bInterfaceProtocol")); + public static final VarHandle IOUSBFindInterfaceRequest_bAlternateSetting = IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bAlternateSetting")); + + private static final GroupLayout IOUSBDevice$Struct = structLayout( + ADDRESS.withName("_reserved"), // void *_reserved; + ADDRESS.withName("QueryInterface"), // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); + ADDRESS.withName("AddRef"), // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); + ADDRESS.withName("Release"), // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); + ADDRESS.withName("CreateDeviceAsyncEventSource"), // IOReturn (*CreateDeviceAsyncEventSource)(void *self, CFRunLoopSourceRef *source); + ADDRESS.withName("GetDeviceAsyncEventSource"), // CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void *self); + ADDRESS.withName("CreateDeviceAsyncPort"), // IOReturn (*CreateDeviceAsyncPort)(void *self, mach_port_t *port); + ADDRESS.withName("GetDeviceAsyncPort"), // mach_port_t (*GetDeviceAsyncPort)(void *self); + ADDRESS.withName("USBDeviceOpen"), // IOReturn (*USBDeviceOpen)(void *self); + ADDRESS.withName("USBDeviceClose"), // IOReturn (*USBDeviceClose)(void *self); + ADDRESS.withName("GetDeviceClass"), // IOReturn (*GetDeviceClass)(void *self, UInt8 *devClass); + ADDRESS.withName("GetDeviceSubClass"), // IOReturn (*GetDeviceSubClass)(void *self, UInt8 *devSubClass); + ADDRESS.withName("GetDeviceProtocol"), // IOReturn (*GetDeviceProtocol)(void *self, UInt8 *devProtocol); + ADDRESS.withName("GetDeviceVendor"), // IOReturn (*GetDeviceVendor)(void *self, UInt16 *devVendor); + ADDRESS.withName("GetDeviceProduct"), // IOReturn (*GetDeviceProduct)(void *self, UInt16 *devProduct); + ADDRESS.withName("GetDeviceReleaseNumber"), // IOReturn (*GetDeviceReleaseNumber)(void *self, UInt16 *devRelNum); + ADDRESS.withName("GetDeviceAddress"), // IOReturn (*GetDeviceAddress)(void *self, USBDeviceAddress *addr); + ADDRESS.withName("GetDeviceBusPowerAvailable"), // IOReturn (*GetDeviceBusPowerAvailable)(void *self, UInt32 *powerAvailable); + ADDRESS.withName("GetDeviceSpeed"), // IOReturn (*GetDeviceSpeed)(void *self, UInt8 *devSpeed); + ADDRESS.withName("GetNumberOfConfigurations"), // IOReturn (*GetNumberOfConfigurations)(void *self, UInt8 *numConfig); + ADDRESS.withName("GetLocationID"), // IOReturn (*GetLocationID)(void *self, UInt32 *locationID); + ADDRESS.withName("GetConfigurationDescriptorPtr"), // IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc); + ADDRESS.withName("GetConfiguration"), // IOReturn (*GetConfiguration)(void *self, UInt8 *configNum); + ADDRESS.withName("SetConfiguration"), // IOReturn (*SetConfiguration)(void *self, UInt8 configNum); + ADDRESS.withName("GetBusFrameNumber"), // IOReturn (*GetBusFrameNumber)(void *self, UInt64 *frame, AbsoluteTime *atTime); + ADDRESS.withName("ResetDevice"), // IOReturn (*ResetDevice)(void *self); + ADDRESS.withName("DeviceRequest"), // IOReturn (*DeviceRequest)(void *self, IOUSBDevRequest *req); + ADDRESS.withName("DeviceRequestAsync"), // IOReturn (*DeviceRequestAsync)(void *self, IOUSBDevRequest *req, IOAsyncCallback1 callback, void *refCon); + ADDRESS.withName("CreateInterfaceIterator"), // IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter); + ADDRESS.withName("USBDeviceOpenSeize"), // IOReturn (*USBDeviceOpenSeize)(void *self); + ADDRESS.withName("DeviceRequestTO"), // IOReturn (*DeviceRequestTO)(void *self, IOUSBDevRequestTO *req); + ADDRESS.withName("DeviceRequestAsyncTO"), // IOReturn (*DeviceRequestAsyncTO)(void *self, IOUSBDevRequestTO *req, IOAsyncCallback1 callback, void *refCon); + ADDRESS.withName("USBDeviceSuspend"), // IOReturn (*USBDeviceSuspend)(void *self, Boolean suspend); + ADDRESS.withName("USBDeviceAbortPipeZero"), // IOReturn (*USBDeviceAbortPipeZero)(void *self); + ADDRESS.withName("USBGetManufacturerStringIndex"), // IOReturn (*USBGetManufacturerStringIndex)(void *self, UInt8 *msi); + ADDRESS.withName("USBGetProductStringIndex"), // IOReturn (*USBGetProductStringIndex)(void *self, UInt8 *psi); + ADDRESS.withName("USBGetSerialNumberStringIndex"), // IOReturn (*USBGetSerialNumberStringIndex)(void *self, UInt8 *snsi); + ADDRESS.withName("USBDeviceReEnumerate"), // IOReturn (*USBDeviceReEnumerate)(void *self, UInt32 options); + ADDRESS.withName("GetBusMicroFrameNumber"), // IOReturn (*GetBusMicroFrameNumber)(void *self, UInt64 *microFrame, AbsoluteTime *atTime); + ADDRESS.withName("GetIOUSBLibVersion"), // IOReturn (*GetIOUSBLibVersion)(void *self, NumVersion *ioUSBLibVersion, NumVersion *usbFamilyVersion); + ADDRESS.withName("GetBusFrameNumberWithTime"), // IOReturn (*GetBusFrameNumberWithTime)(void *self, UInt64 *frame, AbsoluteTime *atTime); + ADDRESS.withName("GetUSBDeviceInformation"), // IOReturn (*GetUSBDeviceInformation)(void *self, UInt32 *info); + ADDRESS.withName("RequestExtraPower"), // IOReturn (*RequestExtraPower)(void *self, UInt32 type, UInt32 requestedPower, UInt32 *powerAvailable); + ADDRESS.withName("ReturnExtraPower"), // IOReturn (*ReturnExtraPower)(void *self, UInt32 type, UInt32 powerReturned); + ADDRESS.withName("GetExtraPowerAllocated"), // IOReturn (*GetExtraPowerAllocated)(void *self, UInt32 type, UInt32 *powerAllocated); + ADDRESS.withName("GetBandwidthAvailableForDevice"), // IOReturn (*GetBandwidthAvailableForDevice)(void *self, UInt32 *bandwidth); + ADDRESS.withName("SetConfigurationV2"), // IOReturn (*SetConfigurationV2)(void *self, UInt8 configNum, bool startInterfaceMatching, bool issueRemoteWakeup); + ADDRESS.withName("RegisterForNotification"), // IOReturn (*RegisterForNotification)(void * self, UInt64 notificationMask, IOAsyncCallback2 callback, void *refCon, UInt64 *pRegistrationToken); + ADDRESS.withName("UnregisterNotification"), // IOReturn (*UnregisterNotification)(void *self, UInt64 registrationToken); + ADDRESS.withName("AcknowledgeNotification") // IOReturn (*AcknowledgeNotification)(void *self, UInt64 notificationToken); + ); + + /** + * Looks up the address of the specified virtual function in the {@code IOUSBDevice} object + * @param thisPointer pointer to pointer to object + * @param varHandle variable handle to virtual function + * @param session memory session + * @return function address + */ + private static Addressable IOUSBDeviceFunctionAddress(MemoryAddress thisPointer, VarHandle varHandle, MemorySession session) { var seg = MemorySegment.ofAddress(thisPointer, ADDRESS.byteSize(), session); var thisValue = seg.get(ADDRESS, 0); var obj = MemorySegment.ofAddress(thisValue, IOUSBDevice$Struct.byteSize(), session); @@ -343,9 +111,13 @@ public class IoKitUSB { } // IOReturn (*USBDeviceOpen)(void *self); + private static final VarHandle IOUSBDevice_USBDeviceOpen = IOUSBDevice$Struct.varHandle(groupElement("USBDeviceOpen")); + private static final MethodHandle USBDeviceOpen$Func = linker.downcallHandle( + FunctionDescriptor.of(JAVA_INT, ADDRESS) + ); public static int USBDeviceOpen(MemoryAddress thisPointer) { try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBDevice$VirtFunc(thisPointer, IOUSBDevice_USBDeviceOpen, session); + var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_USBDeviceOpen, session); return (int) USBDeviceOpen$Func.invokeExact(funcPtr, (Addressable) thisPointer); } catch (Throwable e) { throw new RuntimeException(e); @@ -353,19 +125,27 @@ public static int USBDeviceOpen(MemoryAddress thisPointer) { } // IOReturn (*USBDeviceClose)(void *self); + private static final VarHandle IOUSBDevice_USBDeviceClose = IOUSBDevice$Struct.varHandle(groupElement("USBDeviceClose")); + private static final MethodHandle USBDeviceClose$Func = linker.downcallHandle( + FunctionDescriptor.of(JAVA_INT, ADDRESS) + ); public static int USBDeviceClose(MemoryAddress thisPointer) { try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBDevice$VirtFunc(thisPointer, IOUSBDevice_USBDeviceClose, session); + var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_USBDeviceClose, session); return (int) USBDeviceClose$Func.invokeExact(funcPtr, (Addressable) thisPointer); } catch (Throwable e) { throw new RuntimeException(e); } } - // IOReturn (*GetNumberOfConfigurations)(void *self, UInt8 *numConfig); + // IOReturn (*GetNumberOfConfigurations)(void *self, UInt8 *numConfig); + private static final VarHandle IOUSBDevice_GetNumberOfConfigurations = IOUSBDevice$Struct.varHandle(groupElement("GetNumberOfConfigurations")); + private static final MethodHandle GetNumberOfConfigurations$Func = linker.downcallHandle( + FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS) + ); public static int GetNumberOfConfigurations(MemoryAddress thisPointer, Addressable numConfigHolder) { try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBDevice$VirtFunc(thisPointer, IOUSBDevice_GetNumberOfConfigurations, session); + var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_GetNumberOfConfigurations, session); return (int) GetNumberOfConfigurations$Func.invokeExact(funcPtr, (Addressable) thisPointer, numConfigHolder); } catch (Throwable e) { throw new RuntimeException(e); @@ -373,9 +153,13 @@ public static int GetNumberOfConfigurations(MemoryAddress thisPointer, Addressab } // IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc); + private static final VarHandle IOUSBDevice_GetConfigurationDescriptorPtr = IOUSBDevice$Struct.varHandle(groupElement("GetConfigurationDescriptorPtr")); + private static final MethodHandle GetConfigurationDescriptorPtr$Func = linker.downcallHandle( + FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS) + ); public static int GetConfigurationDescriptorPtr(MemoryAddress thisPointer, byte configIndex, Addressable descHolder) { try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBDevice$VirtFunc(thisPointer, IOUSBDevice_GetConfigurationDescriptorPtr, session); + var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_GetConfigurationDescriptorPtr, session); return (int) GetConfigurationDescriptorPtr$Func.invokeExact(funcPtr, (Addressable) thisPointer, configIndex, descHolder); } catch (Throwable e) { throw new RuntimeException(e); @@ -383,9 +167,13 @@ public static int GetConfigurationDescriptorPtr(MemoryAddress thisPointer, byte } // IOReturn (*SetConfiguration)(void *self, UInt8 configNum); + private static final VarHandle IOUSBDevice_SetConfiguration = IOUSBDevice$Struct.varHandle(groupElement("SetConfiguration")); + private static final MethodHandle SetConfiguration$Func = linker.downcallHandle( + FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE) + ); public static int SetConfiguration(MemoryAddress thisPointer, byte configValue) { try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBDevice$VirtFunc(thisPointer, IOUSBDevice_SetConfiguration, session); + var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_SetConfiguration, session); return (int) SetConfiguration$Func.invokeExact(funcPtr, (Addressable) thisPointer, configValue); } catch (Throwable e) { throw new RuntimeException(e); @@ -393,9 +181,13 @@ public static int SetConfiguration(MemoryAddress thisPointer, byte configValue) } // IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter); + private static final VarHandle IOUSBDevice_CreateInterfaceIterator = IOUSBDevice$Struct.varHandle(groupElement("CreateInterfaceIterator")); + private static final MethodHandle CreateInterfaceIterator$Func = linker.downcallHandle( + FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS) + ); public static int CreateInterfaceIterator(MemoryAddress thisPointer, Addressable req, Addressable iter) { try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBDevice$VirtFunc(thisPointer, IOUSBDevice_CreateInterfaceIterator, session); + var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_CreateInterfaceIterator, session); return (int) CreateInterfaceIterator$Func.invokeExact(funcPtr, (Addressable) thisPointer, req, iter); } catch (Throwable e) { throw new RuntimeException(e); @@ -403,36 +195,132 @@ public static int CreateInterfaceIterator(MemoryAddress thisPointer, Addressable } // IOReturn (*DeviceRequest)(void *self, IOUSBDevRequest *req); + private static final VarHandle IOUSBDevice_DeviceRequest = IOUSBDevice$Struct.varHandle(groupElement("DeviceRequest")); + private static final MethodHandle DeviceRequest$Func = linker.downcallHandle( + FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS) + ); public static int DeviceRequest(MemoryAddress thisPointer, Addressable deviceRequest) { try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBDevice$VirtFunc(thisPointer, IOUSBDevice_DeviceRequest, session); + var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_DeviceRequest, session); return (int) DeviceRequest$Func.invokeExact(funcPtr, (Addressable) thisPointer, deviceRequest); } catch (Throwable e) { throw new RuntimeException(e); } } - private static Addressable IOUSBInterface$VirtFunc(MemoryAddress thisPointer, VarHandle varHandle, MemorySession session) { + private static final GroupLayout IOUSBInterface$Struct = structLayout( + ADDRESS.withName("_reserved"), // void *_reserved; + ADDRESS.withName("QueryInterface"), // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); + ADDRESS.withName("AddRef"), // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); + ADDRESS.withName("Release"), // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); + ADDRESS.withName("CreateInterfaceAsyncEventSource"), // IOReturn (*CreateInterfaceAsyncEventSource)(void *self, CFRunLoopSourceRef *source); + ADDRESS.withName("GetInterfaceAsyncEventSource"), // CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void *self); + ADDRESS.withName("CreateInterfaceAsyncPort"), // IOReturn (*CreateInterfaceAsyncPort)(void *self, mach_port_t *port); + ADDRESS.withName("GetInterfaceAsyncPort"), // mach_port_t (*GetInterfaceAsyncPort)(void *self); + ADDRESS.withName("USBInterfaceOpen"), // IOReturn (*USBInterfaceOpen)(void *self); + ADDRESS.withName("USBInterfaceClose"), // IOReturn (*USBInterfaceClose)(void *self); + ADDRESS.withName("GetInterfaceClass"), // IOReturn (*GetInterfaceClass)(void *self, UInt8 *intfClass); + ADDRESS.withName("GetInterfaceSubClass"), // IOReturn (*GetInterfaceSubClass)(void *self, UInt8 *intfSubClass); + ADDRESS.withName("GetInterfaceProtocol"), // IOReturn (*GetInterfaceProtocol)(void *self, UInt8 *intfProtocol); + ADDRESS.withName("GetDeviceVendor"), // IOReturn (*GetDeviceVendor)(void *self, UInt16 *devVendor); + ADDRESS.withName("GetDeviceProduct"), // IOReturn (*GetDeviceProduct)(void *self, UInt16 *devProduct); + ADDRESS.withName("GetDeviceReleaseNumber"), // IOReturn (*GetDeviceReleaseNumber)(void *self, UInt16 *devRelNum); + ADDRESS.withName("GetConfigurationValue"), // IOReturn (*GetConfigurationValue)(void *self, UInt8 *configVal); + ADDRESS.withName("GetInterfaceNumber"), // IOReturn (*GetInterfaceNumber)(void *self, UInt8 *intfNumber); + ADDRESS.withName("GetAlternateSetting"), // IOReturn (*GetAlternateSetting)(void *self, UInt8 *intfAltSetting); + ADDRESS.withName("GetNumEndpoints"), // IOReturn (*GetNumEndpoints)(void *self, UInt8 *intfNumEndpoints); + ADDRESS.withName("GetLocationID"), // IOReturn (*GetLocationID)(void *self, UInt32 *locationID); + ADDRESS.withName("GetDevice"), // IOReturn (*GetDevice)(void *self, io_service_t *device); + ADDRESS.withName("SetAlternateInterface"), // IOReturn (*SetAlternateInterface)(void *self, UInt8 alternateSetting); + ADDRESS.withName("GetBusFrameNumber"), // IOReturn (*GetBusFrameNumber)(void *self, UInt64 *frame, AbsoluteTime *atTime); + ADDRESS.withName("ControlRequest"), // IOReturn (*ControlRequest)(void *self, UInt8 pipeRef, IOUSBDevRequest *req); + ADDRESS.withName("ControlRequestAsync"), // IOReturn (*ControlRequestAsync)(void *self, UInt8 pipeRef, IOUSBDevRequest *req, IOAsyncCallback1 callback, void *refCon); + ADDRESS.withName("GetPipeProperties"), // IOReturn (*GetPipeProperties)(void *self, UInt8 pipeRef, UInt8 *direction, UInt8 *number, UInt8 *transferType, UInt16 *maxPacketSize, UInt8 *interval); + ADDRESS.withName("GetPipeStatus"), // IOReturn (*GetPipeStatus)(void *self, UInt8 pipeRef); + ADDRESS.withName("AbortPipe"), // IOReturn (*AbortPipe)(void *self, UInt8 pipeRef); + ADDRESS.withName("ResetPipe"), // IOReturn (*ResetPipe)(void *self, UInt8 pipeRef); + ADDRESS.withName("ClearPipeStall"), // IOReturn (*ClearPipeStall)(void *self, UInt8 pipeRef); + ADDRESS.withName("ReadPipe"), // IOReturn (*ReadPipe)(void *self, UInt8 pipeRef, void *buf, UInt32 *size); + ADDRESS.withName("WritePipe"), // IOReturn (*WritePipe)(void *self, UInt8 pipeRef, void *buf, UInt32 size); + ADDRESS.withName("ReadPipeAsync"), // IOReturn (*ReadPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, void *refcon); + ADDRESS.withName("WritePipeAsync"), // IOReturn (*WritePipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, void *refcon); + ADDRESS.withName("ReadIsochPipeAsync"), // IOReturn (*ReadIsochPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt64 frameStart, UInt32 numFrames, IOUSBIsocFrame *frameList, IOAsyncCallback1 callback, void *refcon); + ADDRESS.withName("WriteIsochPipeAsync"), // IOReturn (*WriteIsochPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt64 frameStart, UInt32 numFrames, IOUSBIsocFrame *frameList, IOAsyncCallback1 callback, void *refcon); + ADDRESS.withName("ControlRequestTO"), // IOReturn (*ControlRequestTO)(void *self, UInt8 pipeRef, IOUSBDevRequestTO *req); + ADDRESS.withName("ControlRequestAsyncTO"), // IOReturn (*ControlRequestAsyncTO)(void *self, UInt8 pipeRef, IOUSBDevRequestTO *req, IOAsyncCallback1 callback, void *refCon); + ADDRESS.withName("ReadPipeTO"), // IOReturn (*ReadPipeTO)(void *self, UInt8 pipeRef, void *buf, UInt32 *size, UInt32 noDataTimeout, UInt32 completionTimeout); + ADDRESS.withName("WritePipeTO"), // IOReturn (*WritePipeTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout); + ADDRESS.withName("ReadPipeAsyncTO"), // IOReturn (*ReadPipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void *refcon); + ADDRESS.withName("WritePipeAsyncTO"), // IOReturn (*WritePipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void *refcon); + ADDRESS.withName("USBInterfaceGetStringIndex"), // IOReturn (*USBInterfaceGetStringIndex)(void *self, UInt8 *si); + ADDRESS.withName("USBInterfaceOpenSeize"), // IOReturn (*USBInterfaceOpenSeize)(void *self); + ADDRESS.withName("ClearPipeStallBothEnds"), // IOReturn (*ClearPipeStallBothEnds)(void *self, UInt8 pipeRef); + ADDRESS.withName("SetPipePolicy"), // IOReturn (*SetPipePolicy)(void *self, UInt8 pipeRef, UInt16 maxPacketSize, UInt8 maxInterval); + ADDRESS.withName("GetBandwidthAvailable"), // IOReturn (*GetBandwidthAvailable)(void *self, UInt32 *bandwidth); + ADDRESS.withName("GetEndpointProperties"), // IOReturn (*GetEndpointProperties)(void *self, UInt8 alternateSetting, UInt8 endpointNumber, UInt8 direction, UInt8 *transferType, UInt16 *maxPacketSize, UInt8 *interval); + ADDRESS.withName("LowLatencyReadIsochPipeAsync"), // IOReturn (*LowLatencyReadIsochPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt64 frameStart, UInt32 numFrames, UInt32 updateFrequency, IOUSBLowLatencyIsocFrame *frameList, IOAsyncCallback1 callback, void *refcon); + ADDRESS.withName("LowLatencyWriteIsochPipeAsync"), // IOReturn (*LowLatencyWriteIsochPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt64 frameStart, UInt32 numFrames, UInt32 updateFrequency, IOUSBLowLatencyIsocFrame *frameList, IOAsyncCallback1 callback, void *refcon); + ADDRESS.withName("LowLatencyCreateBuffer"), // IOReturn (*LowLatencyCreateBuffer)(void * self, void **buffer, IOByteCount size, UInt32 bufferType); + ADDRESS.withName("LowLatencyDestroyBuffer"), // IOReturn (*LowLatencyDestroyBuffer) (void * self, void * buffer ); + ADDRESS.withName("GetBusMicroFrameNumber"), // IOReturn (*GetBusMicroFrameNumber)(void *self, UInt64 *microFrame, AbsoluteTime *atTime); + ADDRESS.withName("GetFrameListTime"), // IOReturn (*GetFrameListTime)(void *self, UInt32 *microsecondsInFrame); + ADDRESS.withName("GetIOUSBLibVersion"), // IOReturn (*GetIOUSBLibVersion)(void *self, NumVersion *ioUSBLibVersion, NumVersion *usbFamilyVersion); + ADDRESS.withName("FindNextAssociatedDescriptor"), // IOUSBDescriptorHeader * (*FindNextAssociatedDescriptor)(void *self, const void *currentDescriptor, UInt8 descriptorType); + ADDRESS.withName("FindNextAltInterface"), // IOUSBDescriptorHeader * (*FindNextAltInterface)(void *self, const void *current, IOUSBFindInterfaceRequest *request); + ADDRESS.withName("GetBusFrameNumberWithTime"), // IOReturn (*GetBusFrameNumberWithTime)(void *self, UInt64 *frame, AbsoluteTime *atTime); + ADDRESS.withName("GetPipePropertiesV2"), // IOReturn (*GetPipePropertiesV2)(void *self, UInt8 pipeRef, UInt8 *direction, UInt8 *number, UInt8 *transferType, UInt16 *maxPacketSize, UInt8 *interval, UInt8 *maxBurst, UInt8 *mult, UInt16 *bytesPerInterval); + ADDRESS.withName("GetPipePropertiesV3"), // IOReturn (*GetPipePropertiesV3)(void *self, UInt8 pipeRef, IOUSBEndpointProperties *properties); + ADDRESS.withName("GetEndpointPropertiesV3"), // IOReturn (*GetEndpointPropertiesV3)(void *self, IOUSBEndpointProperties *properties); + ADDRESS.withName("SupportsStreams"), // IOReturn (*SupportsStreams)(void *self, UInt8 pipeRef, UInt32 *supportsStreams); + ADDRESS.withName("CreateStreams"), // IOReturn (*CreateStreams)(void *self, UInt8 pipeRef, UInt32 streamID); + ADDRESS.withName("GetConfiguredStreams"), // IOReturn (*GetConfiguredStreams)(void *self, UInt8 pipeRef, UInt32 *configuredStreams); + ADDRESS.withName("ReadStreamsPipeTO"), // IOReturn (*ReadStreamsPipeTO)(void *self, UInt8 pipeRef, UInt32 streamID, void *buf, UInt32 *size, UInt32 noDataTimeout, UInt32 completionTimeout); + ADDRESS.withName("WriteStreamsPipeTO"), // IOReturn (*WriteStreamsPipeTO)(void *self, UInt8 pipeRef, UInt32 streamID, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout); + ADDRESS.withName("ReadStreamsPipeAsyncTO"), // IOReturn (*ReadStreamsPipeAsyncTO)(void *self, UInt8 pipeRef, UInt32 streamID, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void *refcon); + ADDRESS.withName("WriteStreamsPipeAsyncTO"), // IOReturn (*WriteStreamsPipeAsyncTO)(void *self, UInt8 pipeRef, UInt32 streamID, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void *refcon); + ADDRESS.withName("AbortStreamsPipe"), // IOReturn (*AbortStreamsPipe)(void *self, UInt8 pipeRef, UInt32 streamID); + ADDRESS.withName("RegisterForNotification"), // IOReturn (*RegisterForNotification)(void * self, UInt64 notificationMask, IOAsyncCallback2 callback, void *refCon, UInt64 *pRegistrationToken); + ADDRESS.withName("UnregisterNotification"), // IOReturn (*UnregisterNotification)(void *self, UInt64 registrationToken); + ADDRESS.withName("AcknowledgeNotification"), // IOReturn (*AcknowledgeNotification)(void *self, UInt64 notificationToken); + ADDRESS.withName("RegisterDriver") // IOReturn (*RegisterDriver)(void *self); + ); + + /** + * Looks up the address of the specified virtual function in the {@code IOUSBInterface} object + * @param thisPointer pointer to pointer to object + * @param varHandle variable handle to virtual function + * @param session memory session + * @return function address + */ + private static Addressable IOUSBInterfaceFunctionAddress(MemoryAddress thisPointer, VarHandle varHandle, MemorySession session) { var seg = MemorySegment.ofAddress(thisPointer, ADDRESS.byteSize(), session); var thisValue = seg.get(ADDRESS, 0); var obj = MemorySegment.ofAddress(thisValue, IOUSBInterface$Struct.byteSize(), session); return (MemoryAddress) varHandle.get(obj); } - // IOReturn (*USBInterfaceOpen)(void *self); + // IOReturn (*USBInterfaceOpen)(void *self);; + private static final VarHandle IOUSBInterface_USBInterfaceOpen = IOUSBInterface$Struct.varHandle(groupElement("USBInterfaceOpen")); + private static final MethodHandle USBInterfaceOpen$Func = linker.downcallHandle( + FunctionDescriptor.of(JAVA_INT, ADDRESS) + ); public static int USBInterfaceOpen(MemoryAddress thisPointer) { try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBInterface$VirtFunc(thisPointer, IOUSBInterface_USBInterfaceOpen, session); + var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_USBInterfaceOpen, session); return (int) USBInterfaceOpen$Func.invokeExact(funcPtr, (Addressable) thisPointer); } catch (Throwable e) { throw new RuntimeException(e); } } - // IOReturn (*USBInterfaceClose)(void *self); + // IOReturn (*USBInterfaceClose)(void *self);; + private static final VarHandle IOUSBInterface_USBInterfaceClose = IOUSBInterface$Struct.varHandle(groupElement("USBInterfaceClose")); + private static final MethodHandle USBInterfaceClose$Func = linker.downcallHandle( + FunctionDescriptor.of(JAVA_INT, ADDRESS) + ); public static int USBInterfaceClose(MemoryAddress thisPointer) { try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBInterface$VirtFunc(thisPointer, IOUSBInterface_USBInterfaceClose, session); + var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_USBInterfaceClose, session); return (int) USBInterfaceClose$Func.invokeExact(funcPtr, (Addressable) thisPointer); } catch (Throwable e) { throw new RuntimeException(e); @@ -440,9 +328,13 @@ public static int USBInterfaceClose(MemoryAddress thisPointer) { } // IOReturn (*GetInterfaceNumber)(void *self, UInt8 *intfNumber); + private static final VarHandle IOUSBInterface_GetInterfaceNumber = IOUSBInterface$Struct.varHandle(groupElement("GetInterfaceNumber")); + private static final MethodHandle GetInterfaceNumber$Func = linker.downcallHandle( + FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS) + ); public static int GetInterfaceNumber(MemoryAddress thisPointer, Addressable intfNumberHolder) { try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBInterface$VirtFunc(thisPointer, IOUSBInterface_GetInterfaceNumber, session); + var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_GetInterfaceNumber, session); return (int) GetInterfaceNumber$Func.invokeExact(funcPtr, (Addressable) thisPointer, intfNumberHolder); } catch (Throwable e) { throw new RuntimeException(e); @@ -450,9 +342,13 @@ public static int GetInterfaceNumber(MemoryAddress thisPointer, Addressable intf } // IOReturn (*GetNumEndpoints)(void *self, UInt8 *intfNumEndpoints); + private static final VarHandle IOUSBInterface_GetNumEndpoints = IOUSBInterface$Struct.varHandle(groupElement("GetNumEndpoints")); + private static final MethodHandle GetNumEndpoints$Func = linker.downcallHandle( + FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS) + ); public static int GetNumEndpoints(MemoryAddress thisPointer, Addressable intfNumEndpointsHolder) { try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBInterface$VirtFunc(thisPointer, IOUSBInterface_GetNumEndpoints, session); + var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_GetNumEndpoints, session); return (int) GetNumEndpoints$Func.invokeExact(funcPtr, (Addressable) thisPointer, intfNumEndpointsHolder); } catch (Throwable e) { throw new RuntimeException(e); @@ -460,11 +356,15 @@ public static int GetNumEndpoints(MemoryAddress thisPointer, Addressable intfNum } // IOReturn (*GetPipeProperties)(void *self, UInt8 pipeRef, UInt8 *direction, UInt8 *number, UInt8 *transferType, UInt16 *maxPacketSize, UInt8 *interval); + private static final VarHandle IOUSBInterface_GetPipeProperties = IOUSBInterface$Struct.varHandle(groupElement("GetPipeProperties")); + private static final MethodHandle GetPipeProperties$Func = linker.downcallHandle( + FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS) + ); public static int GetPipeProperties(MemoryAddress thisPointer, byte pipeRef, Addressable directionHolder, Addressable numberHolder, Addressable transferTypeHolder, Addressable maxPacketSizeHolder, Addressable intervalHolder) { try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBInterface$VirtFunc(thisPointer, IOUSBInterface_GetPipeProperties, session); + var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_GetPipeProperties, session); return (int) GetPipeProperties$Func.invokeExact(funcPtr, (Addressable) thisPointer, pipeRef, directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); } catch (Throwable e) { @@ -473,9 +373,13 @@ public static int GetPipeProperties(MemoryAddress thisPointer, byte pipeRef, Add } // IOReturn (*ReadPipe)(void *self, UInt8 pipeRef, void *buf, UInt32 *size); + private static final VarHandle IOUSBInterface_ReadPipe = IOUSBInterface$Struct.varHandle(groupElement("ReadPipe")); + private static final MethodHandle ReadPipe$Func = linker.downcallHandle( + FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS, ADDRESS) + ); public static int ReadPipe(MemoryAddress thisPointer, byte pipeRef, Addressable buf, Addressable sizeHolder) { try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBInterface$VirtFunc(thisPointer, IOUSBInterface_ReadPipe, session); + var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_ReadPipe, session); return (int) ReadPipe$Func.invokeExact(funcPtr, (Addressable) thisPointer, pipeRef, buf, sizeHolder); } catch (Throwable e) { throw new RuntimeException(e); @@ -483,12 +387,44 @@ public static int ReadPipe(MemoryAddress thisPointer, byte pipeRef, Addressable } // IOReturn (*WritePipe)(void *self, UInt8 pipeRef, void *buf, UInt32 size); + private static final VarHandle IOUSBInterface_WritePipe = IOUSBInterface$Struct.varHandle(groupElement("WritePipe")); + private static final MethodHandle WritePipe$Func = linker.downcallHandle( + FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS, JAVA_INT) + ); public static int WritePipe(MemoryAddress thisPointer, byte pipeRef, Addressable buf, int size) { try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBInterface$VirtFunc(thisPointer, IOUSBInterface_WritePipe, session); + var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_WritePipe, session); return (int) WritePipe$Func.invokeExact(funcPtr, (Addressable) thisPointer, pipeRef, buf, size); } catch (Throwable e) { throw new RuntimeException(e); } } + + // typedef struct { + // UInt8 bmRequestType; + // UInt8 bRequest; + // UInt16 wValue; + // UInt16 wIndex; + // UInt16 wLength; + // void* pData; + // UInt32 wLenDone; + //} IOUSBDevRequest; + public static final GroupLayout IOUSBDevRequest$Struct = structLayout( + JAVA_BYTE.withName("bmRequestType"), + JAVA_BYTE.withName("bRequest"), + JAVA_SHORT.withName("wValue"), + JAVA_SHORT.withName("wIndex"), + JAVA_SHORT.withName("wLength"), + ADDRESS.withName("pData"), + JAVA_INT.withName("wLenDone") + ); + + public static final VarHandle IOUSBDevRequest_bmRequestType = IOUSBDevRequest$Struct.varHandle(groupElement("bmRequestType")); + public static final VarHandle IOUSBDevRequest_bRequest = IOUSBDevRequest$Struct.varHandle(groupElement("bRequest")); + public static final VarHandle IOUSBDevRequest_wValue = IOUSBDevRequest$Struct.varHandle(groupElement("wValue")); + public static final VarHandle IOUSBDevRequest_wIndex = IOUSBDevRequest$Struct.varHandle(groupElement("wIndex")); + public static final VarHandle IOUSBDevRequest_wLength = IOUSBDevRequest$Struct.varHandle(groupElement("wLength")); + public static final VarHandle IOUSBDevRequest_pData = IOUSBDevRequest$Struct.varHandle(groupElement("pData")); + public static final VarHandle IOUSBDevRequest_wLenDone = IOUSBDevRequest$Struct.varHandle(groupElement("wLenDone")); + } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/Kernel.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/Kernel.java deleted file mode 100644 index f7c8103d..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/Kernel.java +++ /dev/null @@ -1,41 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.macos; - -import java.lang.foreign.Addressable; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.Linker; -import java.lang.foreign.MemorySession; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_INT; - -/** - * MacOS Kernel functions, and a workaround to load Cocoa frameworks - */ -public class Kernel { - private static final MethodHandle mach_error; - - static { - var linker = Linker.nativeLinker(); - var defaultLookup = linker.defaultLookup(); - mach_error = linker.downcallHandle( - defaultLookup.lookup("mach_error").get(), - FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT) - ); - } - - public static void mach_error(String str, int errorValue) { - try (var session = MemorySession.openConfined()) { - mach_error.invokeExact((Addressable) session.allocateUtf8String(str), errorValue); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } -} From b411ba81289d2524ee733f88c2882d58e0aa8127 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 27 Aug 2022 16:17:23 +0200 Subject: [PATCH 014/433] Convert test device from STM32cube to libopencm3 framework --- README.md | 10 +- .../net/codecrete/usb/macos/IoKitUSB.java | 2 +- stm32-loopback/.vscode/settings.json | 16 -- stm32-loopback/bin/firmware.bin | Bin 13416 -> 0 bytes stm32-loopback/include/circ_buf.h | 55 ---- stm32-loopback/include/interrupts.h | 34 --- stm32-loopback/include/main.h | 29 -- stm32-loopback/include/usbd_conf.h | 42 --- stm32-loopback/include/usbd_desc.h | 28 -- stm32-loopback/include/usbd_loopback.h | 33 --- stm32-loopback/src/circ_buf.c | 107 ------- stm32-loopback/src/interrupts.c | 51 ---- stm32-loopback/src/main.c | 105 ------- stm32-loopback/src/usbd_desc.c | 149 ---------- stm32-loopback/src/usbd_impl.c | 211 -------------- stm32-loopback/src/usbd_loopback.c | 266 ------------------ .../loopback-stm32}/.clang-format | 0 .../loopback-stm32}/.gitignore | 0 .../loopback-stm32}/.vscode/extensions.json | 0 .../loopback-stm32}/README.md | 2 +- test-devices/loopback-stm32/bin/firmware.bin | Bin 0 -> 6328 bytes .../loopback-stm32}/bin/save_bin.sh | 0 .../loopback-stm32}/bin/upload_firmware.sh | 0 .../loopback-stm32/include/circ_buf.h | 155 ++++++++++ test-devices/loopback-stm32/include/common.h | 32 +++ .../loopback-stm32/include/usb_descriptor.h | 30 ++ test-devices/loopback-stm32/include/wcid.h | 17 ++ .../loopback-stm32}/platformio.ini | 2 +- test-devices/loopback-stm32/src/common.cpp | 37 +++ test-devices/loopback-stm32/src/main.cpp | 197 +++++++++++++ .../loopback-stm32/src/usb_descriptor.cpp | 138 +++++++++ test-devices/loopback-stm32/src/wcid.cpp | 81 ++++++ 32 files changed, 695 insertions(+), 1134 deletions(-) delete mode 100644 stm32-loopback/.vscode/settings.json delete mode 100755 stm32-loopback/bin/firmware.bin delete mode 100644 stm32-loopback/include/circ_buf.h delete mode 100644 stm32-loopback/include/interrupts.h delete mode 100644 stm32-loopback/include/main.h delete mode 100644 stm32-loopback/include/usbd_conf.h delete mode 100644 stm32-loopback/include/usbd_desc.h delete mode 100644 stm32-loopback/include/usbd_loopback.h delete mode 100644 stm32-loopback/src/circ_buf.c delete mode 100644 stm32-loopback/src/interrupts.c delete mode 100644 stm32-loopback/src/main.c delete mode 100644 stm32-loopback/src/usbd_desc.c delete mode 100644 stm32-loopback/src/usbd_impl.c delete mode 100644 stm32-loopback/src/usbd_loopback.c rename {stm32-loopback => test-devices/loopback-stm32}/.clang-format (100%) rename {stm32-loopback => test-devices/loopback-stm32}/.gitignore (100%) rename {stm32-loopback => test-devices/loopback-stm32}/.vscode/extensions.json (100%) rename {stm32-loopback => test-devices/loopback-stm32}/README.md (93%) create mode 100755 test-devices/loopback-stm32/bin/firmware.bin rename {stm32-loopback => test-devices/loopback-stm32}/bin/save_bin.sh (100%) rename {stm32-loopback => test-devices/loopback-stm32}/bin/upload_firmware.sh (100%) create mode 100644 test-devices/loopback-stm32/include/circ_buf.h create mode 100644 test-devices/loopback-stm32/include/common.h create mode 100644 test-devices/loopback-stm32/include/usb_descriptor.h create mode 100644 test-devices/loopback-stm32/include/wcid.h rename {stm32-loopback => test-devices/loopback-stm32}/platformio.ini (73%) create mode 100644 test-devices/loopback-stm32/src/common.cpp create mode 100644 test-devices/loopback-stm32/src/main.cpp create mode 100644 test-devices/loopback-stm32/src/usb_descriptor.cpp create mode 100644 test-devices/loopback-stm32/src/wcid.cpp diff --git a/README.md b/README.md index 6d6d3c28..20b6879f 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ It has been tested with Azul Zulu 19.0.75 EA 33. ## Testing -In order to run the unit tests, a special test device must be connected to the computer. See the [stm32-loopback](stm32-loopback) directory. +In order to run the unit tests, a special test device must be connected to the computer. See the [loopback-stm32](test-devices/loopback-stm32) directory. Tests can be run from the command line: @@ -81,7 +81,7 @@ No special considerations apply. Using this library, a Java application can conn ### Linux -*libsystemd* is used to discover USB devices. So it only runs on Linux distributions with systemd and the related library. +*libsystemd* is used to discover USB devices. So it only runs on Linux distributions with systemd and the related library. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfills this. Similar to macOS, a Java application can connect to any USB device and claim any interfaces that aren't claimed by an operating system driver or another application. @@ -93,18 +93,18 @@ Create a file called `/etc/udev/rules.d/80-javadoesusb-udev.rules` with the belo SUBSYSTEM=="usb", ATTRS{idVendor}=="cafe", MODE="0666" ``` -This adds the rule to assign permission mode 0666 to all USB devices with vendor ID 0xCAFE. This non-register vendor ID is used by test device. +This adds the rule to assign permission mode 0666 to all USB devices with vendor ID `0xCAFE`. This non-register vendor ID is used by test device. ### Windows -The Windows driver model is more rigid than the one in macOS or Linux. It's not possible to open any USB device by default. Instead, only devices using the WinUSB driver can be opened. This even applies to device with no installed driver. +The Windows driver model is more rigid than the ones of macOS or Linux. It's not possible to open any USB device by default. Instead, only devices using the WinUSB driver can be opened. This even applies to devices with no installed driver. USB devices can implement certain control requests to instruct Windows to automatically install the WinUSB driver (search for WCID or Microsoft OS Compatibility Descriptors). The driver can also be manually installed or replaced using a software called [Zadig](https://zadig.akeo.ie/). The test device implements these control requests. So the driver is installed automatically. -This library does not yet run reliably on Windows as the Foreign Function & Memory API as the Java VM sometimes overwrites the last error code, which is not just needed in error cases. It works incorrectly when run in the debugger and sometimes even without the debugger. A future version of the Foreign Function & Memory API will hopefully provide a way to save the last error code. The developers are aware of the issue. +This library does not yet run reliably on Windows as Java VM sometimes overwrites the last error code, which is not just needed in error cases. It works incorrectly when run in the debugger and sometimes even without the debugger. A future version of the Foreign Function & Memory API will hopefully provide a way to save the last error code. The developers are aware of the issue. The library has not been tested on Windows for ARM64. It might or might not work. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index 2d6fa7a1..49b841f3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -418,7 +418,7 @@ public static int WritePipe(MemoryAddress thisPointer, byte pipeRef, Addressable ADDRESS.withName("pData"), JAVA_INT.withName("wLenDone") ); - + public static final VarHandle IOUSBDevRequest_bmRequestType = IOUSBDevRequest$Struct.varHandle(groupElement("bmRequestType")); public static final VarHandle IOUSBDevRequest_bRequest = IOUSBDevRequest$Struct.varHandle(groupElement("bRequest")); public static final VarHandle IOUSBDevRequest_wValue = IOUSBDevRequest$Struct.varHandle(groupElement("wValue")); diff --git a/stm32-loopback/.vscode/settings.json b/stm32-loopback/.vscode/settings.json deleted file mode 100644 index abad96db..00000000 --- a/stm32-loopback/.vscode/settings.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "files.associations": { - "usbd_core.h": "c", - "usbd_conf.h": "c", - "usbd_def.h": "c", - "usbd_ioreq.h": "c", - "usbd_ctlreq.h": "c", - "main.h": "c", - "stm32f1xx_hal.h": "c", - "stm32f1xx.h": "c", - "stm32f1xx_ll_utils.h": "c", - "usbd_desc.h": "c", - "usbd_loopback.h": "c", - "circ_buf.h": "c" - } -} \ No newline at end of file diff --git a/stm32-loopback/bin/firmware.bin b/stm32-loopback/bin/firmware.bin deleted file mode 100755 index 9acc0506b15fbab7ab4ee265e99c259f5bf6a02c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13416 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 Ow@zrggVd*o(SHNbFZo>n diff --git a/stm32-loopback/include/circ_buf.h b/stm32-loopback/include/circ_buf.h deleted file mode 100644 index 3fa88648..00000000 --- a/stm32-loopback/include/circ_buf.h +++ /dev/null @@ -1,55 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Circular buffer for raw binary data. -// -// The circular buffer allows a reader and writer to -// use the buffer concurrently. -// - -#ifndef CIRC_BUF_H -#define CIRC_BUF_H - -#include - -#define BUF_SIZE 1025 - -#ifdef __cplusplus -extern "C" { -#endif - -/// Returns the maximum number of bytes that can be added to the buffer -int circ_buf_avail_size(); - -/// Returns the number of bytes in the buffer -int circ_buf_data_size(); - -/** - * Gets the oldest data from the buffer and removes it. - * @param buf buffer to copy data to - * @param max_len maximum number of bytes to copy - * @return the effective number of bytes - */ -int circ_buf_get_data(uint8_t *buf, int max_len); - -/** - * Adds data to the buffer - * - * @param buf the buffer with the data - * @param len the number of bytes to add - */ -void circ_buf_add_data(const uint8_t *buf, int len); - -/// Resets (empties) the circular buffer -void circ_buf_reset(); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/stm32-loopback/include/interrupts.h b/stm32-loopback/include/interrupts.h deleted file mode 100644 index f6462198..00000000 --- a/stm32-loopback/include/interrupts.h +++ /dev/null @@ -1,34 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Interrupt handlers -// - -#ifndef __INTERRUPTS_H -#define __INTERRUPTS_H - -#ifdef __cplusplus -extern "C" { -#endif - -void NMI_Handler(void); -void HardFault_Handler(void); -void MemManage_Handler(void); -void BusFault_Handler(void); -void UsageFault_Handler(void); -void SVC_Handler(void); -void DebugMon_Handler(void); -void PendSV_Handler(void); -void SysTick_Handler(void); -void USB_LP_CAN1_RX0_IRQHandler(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/stm32-loopback/include/main.h b/stm32-loopback/include/main.h deleted file mode 100644 index 252cdddb..00000000 --- a/stm32-loopback/include/main.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Main program -// - -#ifndef MAIN_H -#define MAIN_H - -#include - -#include "usbd_def.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void Error_Handler(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/stm32-loopback/include/usbd_conf.h b/stm32-loopback/include/usbd_conf.h deleted file mode 100644 index c16c7f32..00000000 --- a/stm32-loopback/include/usbd_conf.h +++ /dev/null @@ -1,42 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Common configuration -// - -#ifndef USBD_CONF_H -#define USBD_CONF_H - -#include -#include -#include - -#include "stm32f1xx.h" -#include "stm32f1xx_hal.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define USBD_MAX_NUM_INTERFACES 1 -#define USBD_MAX_NUM_CONFIGURATION 1 -#define USBD_MAX_STR_DESC_SIZ 512 -#define USBD_SUPPORT_USER_STRING_DESC 1 -#define USBD_DEBUG_LEVEL 0 -#define USBD_SELF_POWERED 1 -#define USBD_DFU_MAX_ITF_NUM 1 -#define USBD_DFU_XFER_SIZE 1024 -#define USBD_DFU_APP_DEFAULT_ADD 0x08000000 - -#define DEVICE_FS 0 - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/stm32-loopback/include/usbd_desc.h b/stm32-loopback/include/usbd_desc.h deleted file mode 100644 index d69b5ba8..00000000 --- a/stm32-loopback/include/usbd_desc.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// USB device descriptor -// - -#ifndef USBD_DESC_H -#define USBD_DESC_H - -#include "usbd_def.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Descriptor functions -extern USBD_DescriptorsTypeDef USBD_Descriptors; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/stm32-loopback/include/usbd_loopback.h b/stm32-loopback/include/usbd_loopback.h deleted file mode 100644 index e04d3d33..00000000 --- a/stm32-loopback/include/usbd_loopback.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Loopback interface -// - -#ifndef USB_LOOPBACK_H -#define USB_LOOPBACK_H - -#include "usbd_ioreq.h" - -#define DATA_OUT_EP 0x01U -#define DATA_IN_EP 0x82U -#define DATA_PACKET_SIZE 64 - -#ifdef __cplusplus -extern "C" { -#endif - -extern USBD_ClassTypeDef USBD_Vendor_Class; - -void usbd_check(USBD_HandleTypeDef *pdev); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/stm32-loopback/src/circ_buf.c b/stm32-loopback/src/circ_buf.c deleted file mode 100644 index 9210730e..00000000 --- a/stm32-loopback/src/circ_buf.c +++ /dev/null @@ -1,107 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Circular buffer for raw binary data. -// -// The circular buffer allows a reader and writer to -// use the buffer concurrently. -// - -#include "circ_buf.h" - -#include -#include - -#define BUF_SIZE 1025 - -// 0 <= head < BUF_SIZE -// 0 <= tail < BUF_SIZE -// head == tail: buffer is empty -// Therefore, the buffer must never be filled completely. -static volatile int buf_head = 0; // updated when adding data -static volatile int buf_tail = 0; // updated when removing data - -static uint8_t buffer[BUF_SIZE]; - -int circ_buf_avail_size() { - int head = buf_head; - int tail = buf_tail; - - if (head >= tail) { - return BUF_SIZE - (head - tail) - 1; - } else { - return tail - head - 1; - } -} - -int circ_buf_data_size() { - int head = buf_head; - int tail = buf_tail; - - if (head >= tail) { - return head - tail; - } else { - return BUF_SIZE - (tail - head); - } -} - -int circ_buf_get_data(uint8_t *buf, int max_len) { - int tail = buf_tail; - int head = buf_head; - - if (tail == head) - return 0; - - // get available data (without wrap around) - int len = (head > tail ? head : BUF_SIZE) - tail; - - // limit data to max_len - if (len > max_len) - len = max_len; - - // copy data - memcpy(buf, buffer + tail, len); - - // update tail - tail += len; - if (tail >= BUF_SIZE) - tail -= BUF_SIZE; - buf_tail = tail; - - // sufficient data or no more data - if (len == max_len || tail != 0) - return len; - - // copy more data - return circ_buf_get_data(buf + len, max_len - len) + len; -} - -void circ_buf_add_data(const uint8_t *buf, int len) { - int head = buf_head; - - // copy first part (from head to end of circular buffer) - int n = len; - if (n > BUF_SIZE - head) - n = BUF_SIZE - head; - memcpy(buffer + head, buf, n); - - // copy second part if needed (to start of circular buffer) - if (n < len) - memcpy(buffer, buf + n, len - n); - - // update head - head += len; - if (head >= BUF_SIZE) - head -= BUF_SIZE; - buf_head = head; -} - -void circ_buf_reset() { - buf_head = 0; - buf_tail = 0; -} diff --git a/stm32-loopback/src/interrupts.c b/stm32-loopback/src/interrupts.c deleted file mode 100644 index a61cc865..00000000 --- a/stm32-loopback/src/interrupts.c +++ /dev/null @@ -1,51 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Interrupt handlers -// - -#include "interrupts.h" - -#include "main.h" - -extern PCD_HandleTypeDef usb_pcd; - -void SysTick_Handler(void) { HAL_IncTick(); } - -void USB_LP_CAN1_RX0_IRQHandler(void) { HAL_PCD_IRQHandler(&usb_pcd); } - -void NMI_Handler(void) { - while (1) { - } -} - -void HardFault_Handler(void) { - while (1) { - } -} - -void MemManage_Handler(void) { - while (1) { - } -} - -void BusFault_Handler(void) { - while (1) { - } -} - -void UsageFault_Handler(void) { - while (1) { - } -} - -void SVC_Handler(void) {} - -void DebugMon_Handler(void) {} - -void PendSV_Handler(void) {} diff --git a/stm32-loopback/src/main.c b/stm32-loopback/src/main.c deleted file mode 100644 index 995f17b4..00000000 --- a/stm32-loopback/src/main.c +++ /dev/null @@ -1,105 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Main program -// - -#include "main.h" - -#include "circ_buf.h" -#include "usbd_desc.h" -#include "usbd_loopback.h" - -static void SystemClock_Config(void); -static void MX_GPIO_Init(void); -static void USB_Device_Init(void); - -static USBD_HandleTypeDef USBD_Device; - -int main(void) { - HAL_Init(); - SystemClock_Config(); - MX_GPIO_Init(); - USB_Device_Init(); - - while (1) { - usbd_check(&USBD_Device); - } -} - -void SystemClock_Config(void) { - RCC_OscInitTypeDef RCC_OscInitStruct = {0}; - RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; - RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; - - // Initializes the RCC Oscillators according to the specified parameters - // in the RCC_OscInitTypeDef structure. - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_LSE; - RCC_OscInitStruct.HSEState = RCC_HSE_ON; - RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; - RCC_OscInitStruct.LSEState = RCC_LSE_ON; - RCC_OscInitStruct.HSIState = RCC_HSI_ON; - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; - RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; - if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { - Error_Handler(); - } - - // Initializes the CPU, AHB and APB buses clocks - RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; - - if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { - Error_Handler(); - } - PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC | RCC_PERIPHCLK_USB; - PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; - PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5; - if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { - Error_Handler(); - } -} - -static void MX_GPIO_Init(void) { - // GPIO Ports Clock Enable - __HAL_RCC_GPIOD_CLK_ENABLE(); - __HAL_RCC_GPIOA_CLK_ENABLE(); -} - -void USB_Device_Init(void) { - // Pull USB D+ (A12) low for 80ms to trigger device reenumeration - HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET); - GPIO_InitTypeDef GPIO_InitStruct = {0}; - GPIO_InitStruct.Pin = GPIO_PIN_12; - GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - HAL_Delay(80); - - // Init USB Device Library, add supported class and start the library. - USBD_Init(&USBD_Device, &USBD_Descriptors, DEVICE_FS); - USBD_RegisterClass(&USBD_Device, &USBD_Vendor_Class); - USBD_Start(&USBD_Device); -} - -void HAL_MspInit(void) { - __HAL_RCC_AFIO_CLK_ENABLE(); - __HAL_RCC_PWR_CLK_ENABLE(); - __HAL_AFIO_REMAP_SWJ_NOJTAG(); -} - -void Error_Handler(void) { - __disable_irq(); - while (1) { - } -} diff --git a/stm32-loopback/src/usbd_desc.c b/stm32-loopback/src/usbd_desc.c deleted file mode 100644 index a703438b..00000000 --- a/stm32-loopback/src/usbd_desc.c +++ /dev/null @@ -1,149 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// USB device descriptor -// - -#include "usbd_desc.h" - -#include "stm32f1xx_ll_utils.h" -#include "usbd_conf.h" -#include "usbd_core.h" - -#define USBD_VID 0xcafe -#define USBD_LANGID_STRING 1033 -#define USBD_MANUFACTURER_STRING "JavaDoesUSB" -#define USBD_PID_FS 0xceaf -#define USBD_PRODUCT_STRING_FS "Loopback" -#define USBD_CONFIGURATION_STRING_FS "Loopback Config" -#define USBD_INTERFACE_STRING_FS "Loopback Interface" -#define USBD_DEV_RELESE 0x0061 - -static void GetSerialNumber(void); -static void IntToUnicode(uint32_t value, uint8_t *pbuf, uint8_t len); - -static uint8_t *GetDeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); -static uint8_t *GetLangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); -static uint8_t *GetManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); -static uint8_t *GetProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); -static uint8_t *GetSerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); -static uint8_t *GetConfigurationStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); -static uint8_t *GetInterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); - -USBD_DescriptorsTypeDef USBD_Descriptors = { - GetDeviceDescriptor, GetLangIDStrDescriptor, GetManufacturerStrDescriptor, GetProductStrDescriptor, - GetSerialStrDescriptor, GetConfigurationStrDescriptor, GetInterfaceStrDescriptor, -}; - -// USB device descriptor. -static const __ALIGN_BEGIN uint8_t deviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = { - 0x12, // bLength - USB_DESC_TYPE_DEVICE, // bDescriptorType - 0x00, // bcdUSB = 2.00 - 0x02, // - 0xff, // bDeviceClass = vendor specific - 0x00, // bDeviceSubClass - 0x00, // bDeviceProtocol = vendor specific - USB_MAX_EP0_SIZE, // bMaxPacketSize - LOBYTE(USBD_VID), // idVendor - HIBYTE(USBD_VID), // - LOBYTE(USBD_PID_FS), // idProduct - HIBYTE(USBD_PID_FS), // - LOBYTE(USBD_DEV_RELESE), // bcdDevice - HIBYTE(USBD_DEV_RELESE), // - USBD_IDX_MFC_STR, // Index of manufacturer string - USBD_IDX_PRODUCT_STR, // Index of product string - USBD_IDX_SERIAL_STR, // Index of serial number string - USBD_MAX_NUM_CONFIGURATION // bNumConfigurations -}; - -// USB lang indentifier descriptor. -static const __ALIGN_BEGIN uint8_t langIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = { - USB_LEN_LANGID_STR_DESC, - USB_DESC_TYPE_STRING, - LOBYTE(USBD_LANGID_STRING), - HIBYTE(USBD_LANGID_STRING), -}; - -// Internal string descriptor. -__ALIGN_BEGIN uint8_t stringDescBuffer[USBD_MAX_STR_DESC_SIZ] __ALIGN_END; - -#define USB_SIZ_STRING_SERIAL 0x1A - -static __ALIGN_BEGIN uint8_t serialStringDesc[USB_SIZ_STRING_SERIAL] __ALIGN_END = { - USB_SIZ_STRING_SERIAL, - USB_DESC_TYPE_STRING, -}; - -uint8_t *GetDeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { - UNUSED(speed); - *length = sizeof(deviceDesc); - return (uint8_t *)deviceDesc; -} - -uint8_t *GetLangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { - UNUSED(speed); - *length = sizeof(langIDDesc); - return (uint8_t *)langIDDesc; -} - -uint8_t *GetProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { - UNUSED(speed); - USBD_GetString((uint8_t *)USBD_PRODUCT_STRING_FS, stringDescBuffer, length); - return stringDescBuffer; -} - -uint8_t *GetManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { - UNUSED(speed); - USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, stringDescBuffer, length); - return stringDescBuffer; -} - -uint8_t *GetSerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { - UNUSED(speed); - *length = USB_SIZ_STRING_SERIAL; - GetSerialNumber(); - return serialStringDesc; -} - -uint8_t *GetConfigurationStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { - UNUSED(speed); - USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING_FS, stringDescBuffer, length); - return stringDescBuffer; -} - -uint8_t *GetInterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { - UNUSED(speed); - USBD_GetString((uint8_t *)USBD_INTERFACE_STRING_FS, stringDescBuffer, length); - return stringDescBuffer; -} - -static void GetSerialNumber(void) { - uint32_t id0 = LL_GetUID_Word0(); - uint32_t id1 = LL_GetUID_Word1(); - uint32_t id2 = LL_GetUID_Word2(); - - id0 += id2; - - if (id0 != 0) { - IntToUnicode(id0, &serialStringDesc[2], 8); - IntToUnicode(id1, &serialStringDesc[18], 4); - } -} - -const static char HEX_DIGITS[] = "0123456789ABCDEF"; - -static void IntToUnicode(uint32_t value, uint8_t *pbuf, uint8_t len) { - uint8_t idx = 0; - - for (idx = 0; idx < len; idx++) { - pbuf[2 * idx] = HEX_DIGITS[value >> 28]; - value = value << 4; - pbuf[2 * idx + 1] = 0; - } -} diff --git a/stm32-loopback/src/usbd_impl.c b/stm32-loopback/src/usbd_impl.c deleted file mode 100644 index bfc876da..00000000 --- a/stm32-loopback/src/usbd_impl.c +++ /dev/null @@ -1,211 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Low level USB implementation -// - -#include "stm32f1xx.h" -#include "stm32f1xx_hal.h" -#include "usbd_core.h" -#include "usbd_def.h" -#include "usbd_loopback.h" - -PCD_HandleTypeDef usb_pcd; -void Error_Handler(void); - -static USBD_StatusTypeDef Get_USB_Status(HAL_StatusTypeDef hal_status); - -void HAL_PCD_MspInit(PCD_HandleTypeDef *pcdHandle) { - if (pcdHandle->Instance == USB) { - // Enable USB clock - __HAL_RCC_USB_CLK_ENABLE(); - - // Configure USB interrupts - HAL_NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, 0, 0); - HAL_NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn); - } -} - -void HAL_PCD_MspDeInit(PCD_HandleTypeDef *pcdHandle) { - if (pcdHandle->Instance == USB) { - __HAL_RCC_USB_CLK_DISABLE(); - HAL_NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn); - } -} - -void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) { - USBD_LL_SetupStage((USBD_HandleTypeDef *)hpcd->pData, (uint8_t *)hpcd->Setup); -} - -void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) { - USBD_LL_DataOutStage((USBD_HandleTypeDef *)hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff); -} - -void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) { - USBD_LL_DataInStage((USBD_HandleTypeDef *)hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff); -} - -void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { USBD_LL_SOF((USBD_HandleTypeDef *)hpcd->pData); } - -void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd) { - USBD_LL_SetSpeed((USBD_HandleTypeDef *)hpcd->pData, USBD_SPEED_FULL); - - USBD_LL_Reset((USBD_HandleTypeDef *)hpcd->pData); -} - -void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) { - // Inform USB library that core enters in suspend Mode - USBD_LL_Suspend((USBD_HandleTypeDef *)hpcd->pData); - // Enter STOP mode - if (hpcd->Init.low_power_enable) { - // Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register - SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk)); - } -} - -void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd) { USBD_LL_Resume((USBD_HandleTypeDef *)hpcd->pData); } - -void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) { - USBD_LL_IsoOUTIncomplete((USBD_HandleTypeDef *)hpcd->pData, epnum); -} - -void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) { - USBD_LL_IsoINIncomplete((USBD_HandleTypeDef *)hpcd->pData, epnum); -} - -void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd) { USBD_LL_DevConnected((USBD_HandleTypeDef *)hpcd->pData); } - -void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) { USBD_LL_DevDisconnected((USBD_HandleTypeDef *)hpcd->pData); } - -USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev) { - // Link the driver to the stack - usb_pcd.pData = pdev; - pdev->pData = &usb_pcd; - - usb_pcd.Instance = USB; - usb_pcd.Init.dev_endpoints = 8; - usb_pcd.Init.speed = PCD_SPEED_FULL; - usb_pcd.Init.low_power_enable = DISABLE; - usb_pcd.Init.lpm_enable = DISABLE; - usb_pcd.Init.battery_charging_enable = DISABLE; - if (HAL_PCD_Init(&usb_pcd) != HAL_OK) { - Error_Handler(); - } - - // Configure endpoint 0 - HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, 0x00, PCD_SNG_BUF, 0x18); - HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, 0x80, PCD_SNG_BUF, 0x58); - - // configure endpoint 1 - HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, 0x01, PCD_SNG_BUF, 0x100); - - // configure endpoint 2 - HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, 0x82, PCD_SNG_BUF, 0x140); - - return USBD_OK; -} - -USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev) { - HAL_StatusTypeDef hal_status = HAL_OK; - USBD_StatusTypeDef usb_status = USBD_OK; - - hal_status = HAL_PCD_DeInit(pdev->pData); - - usb_status = Get_USB_Status(hal_status); - - return usb_status; -} - -USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev) { - HAL_StatusTypeDef hal_status = HAL_PCD_Start(pdev->pData); - return Get_USB_Status(hal_status); -} - -USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev) { - HAL_StatusTypeDef hal_status = HAL_PCD_Stop(pdev->pData); - return Get_USB_Status(hal_status); -} - -USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps) { - HAL_StatusTypeDef hal_status = HAL_PCD_EP_Open(pdev->pData, ep_addr, ep_mps, ep_type); - return Get_USB_Status(hal_status); -} - -USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { - HAL_StatusTypeDef hal_status = HAL_PCD_EP_Close(pdev->pData, ep_addr); - return Get_USB_Status(hal_status); -} - -USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { - HAL_StatusTypeDef hal_status = HAL_PCD_EP_Flush(pdev->pData, ep_addr); - return Get_USB_Status(hal_status); -} - -USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { - HAL_StatusTypeDef hal_status = HAL_PCD_EP_SetStall(pdev->pData, ep_addr); - return Get_USB_Status(hal_status); -} - -USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { - HAL_StatusTypeDef hal_status = HAL_PCD_EP_ClrStall(pdev->pData, ep_addr); - return Get_USB_Status(hal_status); -} - -uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { - PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef *)pdev->pData; - - if ((ep_addr & 0x80) == 0x80) { - return hpcd->IN_ep[ep_addr & 0x7F].is_stall; - } else { - return hpcd->OUT_ep[ep_addr & 0x7F].is_stall; - } -} - -USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr) { - HAL_StatusTypeDef hal_status = HAL_PCD_SetAddress(pdev->pData, dev_addr); - return Get_USB_Status(hal_status); -} - -USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint16_t size) { - HAL_StatusTypeDef hal_status = HAL_PCD_EP_Transmit(pdev->pData, ep_addr, pbuf, size); - return Get_USB_Status(hal_status); -} - -USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint16_t size) { - HAL_StatusTypeDef hal_status = HAL_PCD_EP_Receive(pdev->pData, ep_addr, pbuf, size); - return Get_USB_Status(hal_status); -} - -uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { - return HAL_PCD_EP_GetRxCount((PCD_HandleTypeDef *)pdev->pData, ep_addr); -} - -void USBD_LL_Delay(uint32_t delay) { HAL_Delay(delay); } - -USBD_StatusTypeDef Get_USB_Status(HAL_StatusTypeDef hal_status) { - USBD_StatusTypeDef usb_status = USBD_OK; - - switch (hal_status) { - case HAL_OK: - usb_status = USBD_OK; - break; - case HAL_ERROR: - usb_status = USBD_FAIL; - break; - case HAL_BUSY: - usb_status = USBD_BUSY; - break; - case HAL_TIMEOUT: - usb_status = USBD_FAIL; - break; - default: - usb_status = USBD_FAIL; - break; - } - return usb_status; -} diff --git a/stm32-loopback/src/usbd_loopback.c b/stm32-loopback/src/usbd_loopback.c deleted file mode 100644 index a8b51b06..00000000 --- a/stm32-loopback/src/usbd_loopback.c +++ /dev/null @@ -1,266 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Loopback interface -// - -#include "usbd_loopback.h" - -#include "circ_buf.h" -#include "main.h" -#include "usbd_ctlreq.h" - -static uint8_t USBD_Vendor_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx); -static uint8_t USBD_Vendor_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx); -static uint8_t USBD_Vendor_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); -static uint8_t USBD_Vendor_EP0_RxReady(USBD_HandleTypeDef *pdev); -static uint8_t USBD_Vendor_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum); -static uint8_t USBD_Vendor_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum); -static uint8_t *USBD_Vendor_GetConfigDesc(uint16_t *length); -static uint8_t *USBD_Vendor_GetStringDesc(USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length); - -static uint8_t data_packet_rx[DATA_PACKET_SIZE]; -static uint8_t data_packet_tx[DATA_PACKET_SIZE]; -static volatile bool is_transmitting = false; -static volatile bool is_receiving = false; -static volatile uint32_t ctrl_req_value = 0; -static uint8_t ctrl_req_buf[4]; - -USBD_ClassTypeDef USBD_Vendor_Class = { - USBD_Vendor_Init, - USBD_Vendor_DeInit, - USBD_Vendor_Setup, - NULL, // EP0_TxSent - USBD_Vendor_EP0_RxReady, - USBD_Vendor_DataIn, - USBD_Vendor_DataOut, - NULL, // SOF - NULL, - NULL, - NULL, - USBD_Vendor_GetConfigDesc, - NULL, - NULL, - USBD_Vendor_GetStringDesc, -}; - -#define CONFIG_DESC_SIZE 32U - -// USB blinky device configuration descriptor -__ALIGN_BEGIN static uint8_t Configuration_Desc[CONFIG_DESC_SIZE] __ALIGN_END = { - 0x09, // bLength: Configuration Descriptor size - USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration - LOBYTE(CONFIG_DESC_SIZE), // wTotalLength: Bytes returned - HIBYTE(0x00), // (cont.) - 0x01, // bNumInterfaces: 1 interface - 0x01, // bConfigurationValue: Configuration value - USBD_IDX_CONFIG_STR, // iConfiguration: Index of string descriptor for configuration - 0x80, // bmAttributes: bus powered - 0xfa, // MaxPower 500 mA: this current is used for detecting Vbus - - // Interface 0 descriptor - // offset 09 - 0x09, // bLength: Interface Descriptor size - USB_DESC_TYPE_INTERFACE, // bDescriptorType: Interface descriptor type - 0x00, // bInterfaceNumber: Number of Interface - 0x00, // bAlternateSetting: Alternate setting - 0x02, // bNumEndpoints - 0xff, // bInterfaceClass: vendor-specific - 0x00, // bInterfaceSubClass : 1=BOOT, 0=no boot - 0x00, // nInterfaceProtocol : 0=vendor specific - USBD_IDX_INTERFACE_STR, // iInterface: Index of string descriptor - - // Endpoint 1 descriptor - // offset 18 - 0x07, // bLength: endpoint descriptor size - USB_DESC_TYPE_ENDPOINT, // bDescriptorType: endpoint - DATA_OUT_EP, // bEndpointAddress: Endpoint Address (OUT) - USBD_EP_TYPE_BULK, // bmAttributes: bulk endpoint - LOBYTE(DATA_PACKET_SIZE), // wMaxPacketSize: maximum of 64 - HIBYTE(0x00), // (cont.) - 0x00, // bInterval: Polling Interval - - // Endpoint 2 descriptor - // offset 25 - 0x07, // bLength: endpoint descriptor size - USB_DESC_TYPE_ENDPOINT, // bDescriptorType: endpoint - DATA_IN_EP, // bEndpointAddress: Endpoint Address (IN) - USBD_EP_TYPE_BULK, // bmAttributes: bulk endpoint - LOBYTE(DATA_PACKET_SIZE), // wMaxPacketSize: maximum of 64 - HIBYTE(0x00), // (cont.) - 0x00, // bInterval: Polling Interval - - // offset 32 -}; - -#define WCID_VENDOR_CODE 0x37 - -// Microsoft WCID string descriptor (string index 0xee) -static const uint8_t msft_sig_desc[] = { - 0x12, // length = 18 bytes - USB_DESC_TYPE_STRING, // descriptor type string - 'M', - 0, - 'S', - 0, - 'F', - 0, - 'T', - 0, // 'M', 'S', 'F', 'T' - '1', - 0, - '0', - 0, - '0', - 0, // '1', '0', '0' - WCID_VENDOR_CODE, // vendor code - 0 // padding -}; - -// Microsoft WCID feature descriptor (index 0x0004) -static const uint8_t wcid_feature_desc[] = { - 0x28, 0x00, 0x00, 0x00, // length = 40 bytes - 0x00, 0x01, // version 1.0 (in BCD) - 0x04, 0x00, // compatibility descriptor index 0x0004 - 0x01, // number of sections - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved (7 bytes) - 0x00, // interface number 0 - 0x01, // reserved - 0x57, 0x49, 0x4E, 0x55, 0x53, 0x42, 0x00, 0x00, // Compatible ID "WINUSB\0\0" - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Subcompatible ID (unused) - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // reserved 6 bytes -}; - -uint8_t USBD_Vendor_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { - // open RX bulk endpoint - USBD_LL_OpenEP(pdev, DATA_OUT_EP, USBD_EP_TYPE_BULK, DATA_PACKET_SIZE); - pdev->ep_in[DATA_OUT_EP & 0x7F].is_used = 1; - - // Enable it to receive data (NAK -> VALID) - is_receiving = true; - USBD_LL_PrepareReceive(pdev, DATA_OUT_EP, data_packet_rx, sizeof(data_packet_rx)); - - // open TX bulk endpoint - USBD_LL_OpenEP(pdev, DATA_IN_EP, USBD_EP_TYPE_BULK, DATA_PACKET_SIZE); - pdev->ep_in[DATA_IN_EP & 0x7F].is_used = 1; - - return USBD_OK; -} - -uint8_t USBD_Vendor_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { - // close bulk end points - USBD_LL_CloseEP(pdev, DATA_OUT_EP); - pdev->ep_in[DATA_OUT_EP & 0x7F].is_used = 0; - - USBD_LL_CloseEP(pdev, DATA_IN_EP); - pdev->ep_in[DATA_IN_EP & 0x7F].is_used = 0; - - return USBD_OK; -} - -uint8_t USBD_Vendor_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) { - // Handle vendor control request - USBD_StatusTypeDef ret = USBD_OK; - - switch (req->bmRequest & USB_REQ_TYPE_MASK) { - case USB_REQ_TYPE_VENDOR: - if (req->bmRequest == 0x41 && req->bRequest == 0x01 && req->wIndex == 0x0000 && req->wLength == 0) { - // save value - ctrl_req_value = req->wValue; - - } else if (req->bmRequest == 0x41 && req->bRequest == 0x02 && req->wIndex == 0x0000 && req->wLength == 4) { - // receive 4 data bytes - USBD_CtlPrepareRx(pdev, ctrl_req_buf, 4); - - } else if (req->bmRequest == 0xc1 && req->bRequest == 0x03 && req->wIndex == 0x0000 && req->wLength == 4) { - // send saved value - uint32_t* p_value = (uint32_t*)&ctrl_req_buf; - *p_value = ctrl_req_value; - USBD_CtlSendData(pdev, ctrl_req_buf, 4); - - } else if (req->bRequest == WCID_VENDOR_CODE && req->wIndex == 0x0004) { - // WCID feature request - uint16_t len = sizeof(wcid_feature_desc); - if (len > req->wLength) - len = req->wLength; - USBD_CtlSendData(pdev, (uint8_t *)wcid_feature_desc, len); - - } else { - USBD_CtlError(pdev, req); - ret = USBD_FAIL; - } - break; - - default: - USBD_CtlError(pdev, req); - ret = USBD_FAIL; - break; - } - - return ret; -} - -uint8_t USBD_Vendor_EP0_RxReady(USBD_HandleTypeDef *pdev) { - uint32_t* p_value = (uint32_t*)&ctrl_req_buf; - ctrl_req_value = *p_value; - return USBD_OK; -} - - -uint8_t *USBD_Vendor_GetConfigDesc(uint16_t *length) { - // Return configuration descriptor - *length = sizeof(Configuration_Desc); - return Configuration_Desc; -} - -uint8_t *USBD_Vendor_GetStringDesc(USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length) { - // Return Microsoft OS string descriptor for index 0xee - if (index == 0xee) { - *length = sizeof(msft_sig_desc); - return (uint8_t *)msft_sig_desc; - } else { - *length = 0; - USBD_CtlError(pdev, NULL); - return NULL; - } -} - -uint8_t USBD_Vendor_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) { - uint32_t num_bytes_received = USBD_LL_GetRxDataSize(pdev, epnum); - - // add recievied data to circular buffer - circ_buf_add_data(data_packet_rx, num_bytes_received); - is_receiving = false; - - return USBD_OK; -} - -uint8_t USBD_Vendor_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) { - is_transmitting = false; - return USBD_OK; -} - -void usbd_check(USBD_HandleTypeDef *pdev) { - if (!is_transmitting) { - // get data from circular buffer - int size = circ_buf_get_data(data_packet_tx, DATA_PACKET_SIZE); - if (size != 0) { - is_transmitting = true; - USBD_LL_Transmit(pdev, DATA_IN_EP, data_packet_tx, size); - } - } - - if (!is_receiving) { - // check for sufficient space to enable receiving - bool has_space = circ_buf_avail_size() >= DATA_PACKET_SIZE; - if (has_space) { - is_receiving = true; - USBD_LL_PrepareReceive(pdev, DATA_OUT_EP, data_packet_rx, sizeof(data_packet_rx)); - } - } -} diff --git a/stm32-loopback/.clang-format b/test-devices/loopback-stm32/.clang-format similarity index 100% rename from stm32-loopback/.clang-format rename to test-devices/loopback-stm32/.clang-format diff --git a/stm32-loopback/.gitignore b/test-devices/loopback-stm32/.gitignore similarity index 100% rename from stm32-loopback/.gitignore rename to test-devices/loopback-stm32/.gitignore diff --git a/stm32-loopback/.vscode/extensions.json b/test-devices/loopback-stm32/.vscode/extensions.json similarity index 100% rename from stm32-loopback/.vscode/extensions.json rename to test-devices/loopback-stm32/.vscode/extensions.json diff --git a/stm32-loopback/README.md b/test-devices/loopback-stm32/README.md similarity index 93% rename from stm32-loopback/README.md rename to test-devices/loopback-stm32/README.md index 2484048a..e66aa28b 100644 --- a/stm32-loopback/README.md +++ b/test-devices/loopback-stm32/README.md @@ -7,7 +7,7 @@ For testing the *Java Does USB* library, a dedicated USB test device is needed. ### Loopback -All data sent to endpoint 0x01 (OUT) is sent back on endpoint 0x82 (IN). Both endpoints use bulk transfer with a maximum packet size of 64 bytes. The device uses an internal buffer of about 500 bytes. Up to this amount, the data can be first sent and then received. +All data sent to endpoint 0x01 (OUT) is sent back on endpoint 0x82 (IN). Both endpoints use bulk transfer with a maximum packet size of 64 bytes. The device uses an internal buffer of about 1000 bytes. Up to this amount, the data can be first sent and then received. ### Control requests diff --git a/test-devices/loopback-stm32/bin/firmware.bin b/test-devices/loopback-stm32/bin/firmware.bin new file mode 100755 index 0000000000000000000000000000000000000000..15033c10c180ab6736a7c7e5931924bee03c0f9b GIT binary patch literal 6328 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 literal 0 HcmV?d00001 diff --git a/stm32-loopback/bin/save_bin.sh b/test-devices/loopback-stm32/bin/save_bin.sh similarity index 100% rename from stm32-loopback/bin/save_bin.sh rename to test-devices/loopback-stm32/bin/save_bin.sh diff --git a/stm32-loopback/bin/upload_firmware.sh b/test-devices/loopback-stm32/bin/upload_firmware.sh similarity index 100% rename from stm32-loopback/bin/upload_firmware.sh rename to test-devices/loopback-stm32/bin/upload_firmware.sh diff --git a/test-devices/loopback-stm32/include/circ_buf.h b/test-devices/loopback-stm32/include/circ_buf.h new file mode 100644 index 00000000..4d9a6970 --- /dev/null +++ b/test-devices/loopback-stm32/include/circ_buf.h @@ -0,0 +1,155 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Circular buffer for raw binary data. +// +// The circular buffer allows a reader and writer to +// use the buffer concurrently. +// + +#pragma once + +#include +#include + +#include + +/** + * Circular buffer for raw binary data. + * + * The circular buffer allows a reader and writer to + * use the buffer concurrently. + * + * @param N number of bytes that fit into the buffer + */ +template +struct circ_buf { + private: + static constexpr int BUF_SIZE = N + 1; + + // 0 <= head < BUF_SIZE + // 0 <= tail < BUF_SIZE + // head == tail: buffer is empty + // Therefore, the buffer must never be filled completely. + volatile int buf_head = 0; // updated when adding data + volatile int buf_tail = 0; // updated when removing data + + uint8_t buffer[BUF_SIZE]; + + public: + /// Creates a new instance + circ_buf(); + + /// Returns the maximum number of bytes that can be added to the buffer + int avail_size(); + + /// Returns the number of bytes in the buffer + int data_size(); + + /** + * Gets the oldest data from the buffer and removes it. + * @param buf buffer to copy data to + * @param max_len maximum number of bytes to copy + * @return the effective number of bytes + */ + int get_data(uint8_t *buf, int max_len); + + /** + * Adds data to the buffer + * + * @param buf the buffer with the data + * @param len the number of bytes to add + */ + void add_data(const uint8_t *buf, int len); + + /// Resets (empties) the circular buffer + void reset(); +}; + +template +circ_buf::circ_buf() : buf_head(0), buf_tail(0) {} + +template +int circ_buf::avail_size() { + int head = buf_head; + int tail = buf_tail; + + if (head >= tail) { + return BUF_SIZE - (head - tail) - 1; + } else { + return tail - head - 1; + } +} + +template +int circ_buf::data_size() { + int head = buf_head; + int tail = buf_tail; + + if (head >= tail) { + return head - tail; + } else { + return BUF_SIZE - (tail - head); + } +} + +template +int circ_buf::get_data(uint8_t *buf, int max_len) { + int tail = buf_tail; + int head = buf_head; + + if (tail == head) + return 0; + + // get available data (without wrap around) + int len = (head > tail ? head : BUF_SIZE) - tail; + + // limit data to max_len + len = std::min(len, max_len); + + // copy data + memcpy(buf, buffer + tail, len); + + // update tail + tail += len; + if (tail >= BUF_SIZE) + tail -= BUF_SIZE; + buf_tail = tail; + + // sufficient data or no more data + if (len == max_len || tail != 0) + return len; + + // copy more data + return get_data(buf + len, max_len - len) + len; +} + +template +void circ_buf::add_data(const uint8_t *buf, int len) { + int head = buf_head; + + // copy first part (from head to end of circular buffer) + int n = std::min(len, BUF_SIZE - head); + memcpy(buffer + head, buf, n); + + // copy second part if needed (to start of circular buffer) + if (n < len) + memcpy(buffer, buf + n, len - n); + + // update head + head += len; + if (head >= BUF_SIZE) + head -= BUF_SIZE; + buf_head = head; +} + +template +void circ_buf::reset() { + buf_head = 0; + buf_tail = 0; +} diff --git a/test-devices/loopback-stm32/include/common.h b/test-devices/loopback-stm32/include/common.h new file mode 100644 index 00000000..427b2eb4 --- /dev/null +++ b/test-devices/loopback-stm32/include/common.h @@ -0,0 +1,32 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Commmon functions +// + +#pragma once + +#include + +/** + * @brief Initializes systick services + */ +void systick_init(); + +/** + * @brief Gets the time. + * + * @return number of milliseconds since a fixed time in the past + */ +uint32_t millis(); + +/** + * @brief Delays execution (busy wait) + * @param ms delay length, in milliseconds + */ +void delay(uint32_t ms); diff --git a/test-devices/loopback-stm32/include/usb_descriptor.h b/test-devices/loopback-stm32/include/usb_descriptor.h new file mode 100644 index 00000000..6a5df74a --- /dev/null +++ b/test-devices/loopback-stm32/include/usb_descriptor.h @@ -0,0 +1,30 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// USB descriptor +// + +#pragma once + +#include + +#define INTR_MAX_PACKET_SIZE 16 +#define BULK_MAX_PACKET_SIZE 64 + +// Endpoints +#define EP_LOOPBACK_RX 0x01 +#define EP_LOOPBACK_TX 0x82 + +// USB descriptor string table +extern const char *const usb_desc_strings[4]; +// USB device descriptor +extern const struct usb_device_descriptor usb_device_desc; +// USB device configurations +extern const struct usb_config_descriptor usb_config_descs[]; + +void usb_init_serial_num(); diff --git a/test-devices/loopback-stm32/include/wcid.h b/test-devices/loopback-stm32/include/wcid.h new file mode 100644 index 00000000..2c1041ef --- /dev/null +++ b/test-devices/loopback-stm32/include/wcid.h @@ -0,0 +1,17 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Microsoft WCID descriptors +// + +#pragma once + +#include + +// Register control request handlers for Microsoft WCID descriptors +void register_wcid_desc(usbd_device *usb_dev); diff --git a/stm32-loopback/platformio.ini b/test-devices/loopback-stm32/platformio.ini similarity index 73% rename from stm32-loopback/platformio.ini rename to test-devices/loopback-stm32/platformio.ini index 4ffb4da2..58ade09b 100644 --- a/stm32-loopback/platformio.ini +++ b/test-devices/loopback-stm32/platformio.ini @@ -1,4 +1,4 @@ [env:stm32-loopback] platform = ststm32 board = bluepill_f103c8 -framework = stm32cube +framework = libopencm3 diff --git a/test-devices/loopback-stm32/src/common.cpp b/test-devices/loopback-stm32/src/common.cpp new file mode 100644 index 00000000..5102b6bd --- /dev/null +++ b/test-devices/loopback-stm32/src/common.cpp @@ -0,0 +1,37 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Commmon functions +// + +#include "common.h" + +#include + +static volatile uint32_t millis_count; + +uint32_t millis() { return millis_count; } + +void delay(uint32_t ms) { + int32_t target_time = millis_count + ms; + while (target_time - (int32_t)millis_count > 0) + ; +} + +void systick_init() { + // Initialize SysTick + systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); + systick_set_reload(rcc_ahb_frequency / 8 / 1000 - 1); + + // Enable and start + systick_interrupt_enable(); + systick_counter_enable(); +} + +// System tick timer interrupt handler +extern "C" void sys_tick_handler() { millis_count++; } diff --git a/test-devices/loopback-stm32/src/main.cpp b/test-devices/loopback-stm32/src/main.cpp new file mode 100644 index 00000000..cc39f21f --- /dev/null +++ b/test-devices/loopback-stm32/src/main.cpp @@ -0,0 +1,197 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Main program +// + +#include +#include +#include +#include + +#include + +#include "circ_buf.h" +#include "common.h" +#include "usb_descriptor.h" +#include "wcid.h" + +static void on_usb_set_config(usbd_device *usbd_dev, uint16_t wValue); +static usbd_request_return_codes on_usb_control_request(usbd_device *usbd_dev, usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete); +static void on_usb_data_received(usbd_device *usbd_dev, uint8_t ep); +static void on_usb_data_transmitted(usbd_device *usbd_dev, uint8_t ep); +static void check_buffers(); + +// USB device instance +static usbd_device *usb_device; + +// buffer for control requests +static uint8_t usbd_control_buffer[256]; + +// Circular buffer for data +static circ_buf<1024> buffer; + +// Minimum free space in circular buffer for requesting more packets +static constexpr int MIN_FREE_SPACE = 2 * BULK_MAX_PACKET_SIZE; + +// indicates if loopback data is being transmitted +static volatile bool is_transmitting = false; + +// indicates if the endpoint is forced to NAK to prevent receiving further data +static volatile bool is_forced_nak = false; + +// value that can be saved and retrieved with control requests +static uint32_t saved_value; + + +void init() { + // Enable required clocks + rcc_clock_setup_in_hse_8mhz_out_72mhz(); + rcc_periph_clock_enable(RCC_GPIOA); + rcc_periph_clock_enable(RCC_GPIOC); + rcc_periph_clock_enable(RCC_AFIO); + rcc_periph_clock_enable(RCC_SPI1); + rcc_periph_clock_enable(RCC_USB); + + // Initialize systick services + systick_init(); +} + +void usb_init() { + // reset USB peripheral + rcc_periph_reset_pulse(RST_USB); + + // Pull USB D+ (A12) low for 80ms to trigger device reenumeration + gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO12); + gpio_clear(GPIOA, GPIO12); + delay(80); + + usb_init_serial_num(); + + // create USB device + usb_device = usbd_init(&st_usbfs_v1_usb_driver, &usb_device_desc, usb_config_descs, usb_desc_strings, + sizeof(usb_desc_strings) / sizeof(usb_desc_strings[0]), usbd_control_buffer, + sizeof(usbd_control_buffer)); + + // Set callback for config calls + usbd_register_set_config_callback(usb_device, on_usb_set_config); + register_wcid_desc(usb_device); +} + +// Called when the host connects to the device and selects a configuration +void on_usb_set_config(usbd_device *usbd_dev, __attribute__((unused)) uint16_t wValue) { + register_wcid_desc(usbd_dev); + usbd_register_control_callback(usbd_dev, + USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + on_usb_control_request); + usbd_ep_setup(usbd_dev, EP_LOOPBACK_RX, USB_ENDPOINT_ATTR_BULK, BULK_MAX_PACKET_SIZE, on_usb_data_received); + usbd_ep_setup(usbd_dev, EP_LOOPBACK_TX, USB_ENDPOINT_ATTR_BULK, BULK_MAX_PACKET_SIZE, on_usb_data_transmitted); + + buffer.reset(); + is_transmitting = false; + is_forced_nak = false; + saved_value = 0; +} + +// Called when data has been received +void on_usb_data_received(__attribute__((unused)) usbd_device *usbd_dev, __attribute__((unused)) uint8_t ep) { + // Retrieve USB data (has side effect of setting endpoint to VALID) + uint8_t packet[BULK_MAX_PACKET_SIZE] __attribute__((aligned(4))); + int len = usbd_ep_read_packet(usb_device, EP_LOOPBACK_RX, packet, sizeof(packet)); + + // copy data into circular buffer + buffer.add_data(packet, len); + +} + +// Called when data has been transmitted +void on_usb_data_transmitted(__attribute__((unused)) usbd_device *usbd_dev, __attribute__((unused)) uint8_t ep) { + is_transmitting = false; +} + +void check_buffers() { + + // If RX is stopped and there is sufficient space in the buffer, resume it + if (is_forced_nak) { + if (buffer.avail_size() >= MIN_FREE_SPACE) { + usbd_ep_nak_set(usb_device, EP_LOOPBACK_RX, 0); + is_forced_nak = false; + } + + // If RX is enabled but the space in the buffer is low, stop it + } else { + // check if there is space for less than 2 packets + if (buffer.avail_size() < MIN_FREE_SPACE) { + // set endpoint from VALID to NAK + usbd_ep_nak_set(usb_device, EP_LOOPBACK_RX, 1); + is_forced_nak = true; + } + } + + // If no data is being transmitted and there is data in the buffer, transmit a packet + if (!is_transmitting && buffer.data_size() >= 0) { + uint8_t packet[BULK_MAX_PACKET_SIZE] __attribute__((aligned(4))); + int len = buffer.get_data(packet, BULK_MAX_PACKET_SIZE); + usbd_ep_write_packet(usb_device, EP_LOOPBACK_TX, packet, len); + is_transmitting = true; + } +} + +usbd_request_return_codes on_usb_control_request( + __attribute__((unused)) usbd_device *usbd_dev, usb_setup_data *req, + uint8_t **buf, uint16_t *len, __attribute__((unused)) usbd_control_complete_callback *complete) { + + switch (req->bRequest) { + case 1: + if (req->wIndex == 0 && req->wLength == 0) { + saved_value = req->wValue; + return USBD_REQ_HANDLED; + } else { + return USBD_REQ_NOTSUPP; + } + break; + + case 2: + if (req->wIndex == 0 && req->wLength == 4) { + uint32_t* value = reinterpret_cast(*buf); + saved_value = *value; + return USBD_REQ_HANDLED; + } else { + return USBD_REQ_NOTSUPP; + } + break; + + case 3: + if (req->wIndex == 0) { + uint8_t* value = reinterpret_cast(&saved_value); + *len = std::min(*len, (uint16_t) 4); + memcpy(*buf, value, *len); + return USBD_REQ_HANDLED; + } else { + return USBD_REQ_NOTSUPP; + } + break; + + default: + ; // fall through + } + + return USBD_REQ_NEXT_CALLBACK; +} + + +int main() { + init(); + usb_init(); + + while (true) { + usbd_poll(usb_device); + check_buffers(); + } +} diff --git a/test-devices/loopback-stm32/src/usb_descriptor.cpp b/test-devices/loopback-stm32/src/usb_descriptor.cpp new file mode 100644 index 00000000..1c19a7bd --- /dev/null +++ b/test-devices/loopback-stm32/src/usb_descriptor.cpp @@ -0,0 +1,138 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// USB descriptor +// + +#include "usb_descriptor.h" + +#include + +static void put_hex(uint32_t value, char *buf, int len); + +#define USB_VID 0xcafe // Vendor ID +#define USB_PID 0xceaf // Product ID +#define USB_DEVICE_REL 0x0071 // release 0.7.1 + +// Interface index +#define INTF_LOOPBACK 0 + +static char serial_num[13]; + +const char *const usb_desc_strings[] = { + "JavaDoesUSB", // USB Manufacturer + "Loopback", // USB Product + serial_num, // Serial number +}; + +enum usb_strings_index { // Index of USB strings. Must sync with above, starts from 1. + USB_STRINGS_MANUFACTURER_ID = 1, + USB_STRINGS_PRODUCT_ID, + USB_STRINGS_SERIAL_NUMBER_ID, +}; + +static const struct usb_endpoint_descriptor comm_endpoint_descs[] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = EP_LOOPBACK_RX, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = BULK_MAX_PACKET_SIZE, + .bInterval = 0, + .extra = nullptr, + .extralen = 0, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = EP_LOOPBACK_TX, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = BULK_MAX_PACKET_SIZE, + .bInterval = 0, + .extra = nullptr, + .extralen = 0, + }, +}; + +static const struct usb_interface_descriptor comm_if_descs[] = { + { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = INTF_LOOPBACK, + .bAlternateSetting = 0, + .bNumEndpoints = sizeof(comm_endpoint_descs) / sizeof(comm_endpoint_descs[0]), + .bInterfaceClass = USB_CLASS_VENDOR, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, // vendor specific + .iInterface = 0, + .endpoint = comm_endpoint_descs, + .extra = nullptr, + .extralen = 0, + }, +}; + +static const struct usb_interface usb_interfaces[] = { + { + .cur_altsetting = nullptr, + .num_altsetting = sizeof(comm_if_descs) / sizeof(comm_if_descs[0]), + .iface_assoc = nullptr, + .altsetting = comm_if_descs, + }, +}; + +const struct usb_config_descriptor usb_config_descs[] = { + { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = sizeof(usb_interfaces) / sizeof(usb_interfaces[0]), + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, // bus-powered, i.e. it draws power from USB bus + .bMaxPower = 0xfa, // 500 mA + .interface = usb_interfaces, + }, +}; + +const struct usb_device_descriptor usb_device_desc = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, // USB version 2.00 + .bDeviceClass = USB_CLASS_VENDOR, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, // no class specific protocol + .bMaxPacketSize0 = BULK_MAX_PACKET_SIZE, + .idVendor = USB_VID, + .idProduct = USB_PID, + .bcdDevice = USB_DEVICE_REL, + .iManufacturer = USB_STRINGS_MANUFACTURER_ID, + .iProduct = USB_STRINGS_PRODUCT_ID, + .iSerialNumber = USB_STRINGS_SERIAL_NUMBER_ID, + .bNumConfigurations = sizeof(usb_config_descs) / sizeof(usb_config_descs[0]), +}; + +void usb_init_serial_num() { + uint32_t id0 = DESIG_UNIQUE_ID0; + uint32_t id1 = DESIG_UNIQUE_ID1; + uint32_t id2 = DESIG_UNIQUE_ID2; + + id0 += id2; + + put_hex(id0, serial_num, 8); + put_hex(id1, serial_num + 8, 4); + serial_num[12] = 0; +} + +const static char HEX_DIGITS[] = "0123456789ABCDEF"; + +void put_hex(uint32_t value, char *buf, int len) { + for (int idx = 0; idx < len; idx++) { + buf[idx] = HEX_DIGITS[value >> 28]; + value = value << 4; + } +} diff --git a/test-devices/loopback-stm32/src/wcid.cpp b/test-devices/loopback-stm32/src/wcid.cpp new file mode 100644 index 00000000..2c284f36 --- /dev/null +++ b/test-devices/loopback-stm32/src/wcid.cpp @@ -0,0 +1,81 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Microsoft WCID descriptors +// + +#include + +#include + +static usbd_request_return_codes msft_string_desc(usbd_device *usbd_dev, usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete); +static usbd_request_return_codes msft_feature_desc(usbd_device *usbd_dev, usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete); + +// Registers additional control request handlers to implement +// See https://github.com/pbatard/libwdi/wiki/WCID-Devices +void register_wcid_desc(usbd_device *usb_dev) { + usbd_register_control_callback(usb_dev, + USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + msft_string_desc); + usbd_register_control_callback(usb_dev, + USB_REQ_TYPE_VENDOR, USB_REQ_TYPE_TYPE, + msft_feature_desc); +} + +#define WCID_VENDOR_CODE 0x37 + +// Microsoft WCID string descriptor (string index 0xee) +static const uint8_t msft_sig_desc[] = { + 0x12, // length = 18 bytes + USB_DT_STRING, // descriptor type string + 'M', 0, 'S', 0, 'F', 0, 'T', 0, // 'M', 'S', 'F', 'T' + '1', 0, '0', 0, '0', 0, // '1', '0', '0' + WCID_VENDOR_CODE, // vendor code + 0 // padding +}; + +// Microsoft WCID feature descriptor (index 0x0004) +static const uint8_t wcid_feature_desc[] = { + 0x28, 0x00, 0x00, 0x00, // length = 40 bytes + 0x00, 0x01, // version 1.0 (in BCD) + 0x04, 0x00, // compatibility descriptor index 0x0004 + 0x01, // number of sections + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved (7 bytes) + 0x00, // interface number 0 + 0x01, // reserved + 0x57, 0x49, 0x4E, 0x55, 0x53, 0x42, 0x00, 0x00, // Compatible ID "WINUSB\0\0" + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Subcompatible ID (unused) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // reserved 6 bytes +}; + +usbd_request_return_codes msft_string_desc(__attribute__((unused)) usbd_device *usbd_dev, usb_setup_data *req, + uint8_t **buf, uint16_t *len, + __attribute__((unused)) usbd_control_complete_callback *complete) { + // 0x03: descriptor type string + // 0xee: Microsoft WCID string index + if (req->bRequest == USB_REQ_GET_DESCRIPTOR && req->wValue == 0x03ee) { + *buf = const_cast(reinterpret_cast(&msft_sig_desc)); + *len = std::min(*len, (uint16_t)msft_sig_desc[0]); + return USBD_REQ_HANDLED; + } + + return USBD_REQ_NEXT_CALLBACK; +} + +usbd_request_return_codes msft_feature_desc(__attribute__((unused)) usbd_device *usbd_dev, usb_setup_data *req, + uint8_t **buf, uint16_t *len, + __attribute__((unused)) usbd_control_complete_callback *complete) { + // 0x0004: Microsoft WCID index for feature descriptor + if (req->bRequest == WCID_VENDOR_CODE && req->wIndex == 0x0004) { + *buf = const_cast(reinterpret_cast(&wcid_feature_desc)); + *len = std::min(*len, (uint16_t)wcid_feature_desc[0]); + return USBD_REQ_HANDLED; + } + + return USBD_REQ_NEXT_CALLBACK; +} From a576a3f33ead182566684e0d6ceb1020f04a25f6 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 28 Aug 2022 20:03:00 +0200 Subject: [PATCH 015/433] Windows: Use SetupAPI functions instead of CfgMgr32 functions --- java-does-usb/jextract/gen_win_kernel32.cmd | 2 + java-does-usb/jextract/gen_win_setupapi.cmd | 3 + java-does-usb/jextract/windows_headers.h | 1 - .../codecrete/usb/windows/DeviceProperty.java | 134 +++++++++++ .../net/codecrete/usb/windows/USBHelper.java | 6 + .../usb/windows/WindowsUSBDeviceRegistry.java | 85 ++----- .../usb/windows/gen/cfgmgr32/CfgMgr32.java | 44 ---- .../windows/gen/cfgmgr32/Constants$root.java | 19 -- .../windows/gen/cfgmgr32/RuntimeHelper.java | 216 ------------------ .../usb/windows/gen/cfgmgr32/constants$0.java | 30 --- .../usb/windows/gen/kernel32/Kernel32.java | 6 + .../usb/windows/gen/setupapi/SetupAPI.java | 19 +- .../usb/windows/gen/setupapi/constants$0.java | 13 +- .../usb/windows/gen/setupapi/constants$1.java | 24 ++ 14 files changed, 218 insertions(+), 384 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/CfgMgr32.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/Constants$root.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java diff --git a/java-does-usb/jextract/gen_win_kernel32.cmd b/java-does-usb/jextract/gen_win_kernel32.cmd index 173e672f..2f524df8 100644 --- a/java-does-usb/jextract/gen_win_kernel32.cmd +++ b/java-does-usb/jextract/gen_win_kernel32.cmd @@ -11,7 +11,9 @@ set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 --include-function CloseHandle ^ --include-function DeviceIoControl ^ --include-function GetLastError ^ + --include-macro ERROR_SUCCESS ^ --include-macro ERROR_NO_MORE_ITEMS ^ + --include-macro ERROR_INSUFFICIENT_BUFFER ^ --include-macro GENERIC_READ ^ --include-macro GENERIC_WRITE ^ --include-macro FILE_SHARE_READ ^ diff --git a/java-does-usb/jextract/gen_win_setupapi.cmd b/java-does-usb/jextract/gen_win_setupapi.cmd index baf0813b..187cb288 100644 --- a/java-does-usb/jextract/gen_win_setupapi.cmd +++ b/java-does-usb/jextract/gen_win_setupapi.cmd @@ -13,10 +13,13 @@ set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 --include-function SetupDiEnumDeviceInterfaces ^ --include-function SetupDiGetDeviceInterfaceDetailW ^ --include-function SetupDiGetDeviceRegistryPropertyW ^ + --include-function SetupDiGetDevicePropertyW ^ --include-struct _SP_DEVINFO_DATA ^ --include-struct _SP_DEVICE_INTERFACE_DATA ^ --include-struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W ^ --include-macro DIGCF_PRESENT ^ --include-macro DIGCF_DEVICEINTERFACE ^ --include-macro SPDRP_ADDRESS ^ + --include-macro DEVPROP_TYPE_UINT32 ^ + --include-macro DEVPROP_TYPE_STRING ^ windows_headers.h diff --git a/java-does-usb/jextract/windows_headers.h b/java-does-usb/jextract/windows_headers.h index aa8d0648..a863aa14 100644 --- a/java-does-usb/jextract/windows_headers.h +++ b/java-does-usb/jextract/windows_headers.h @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java new file mode 100644 index 00000000..133651b3 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -0,0 +1,134 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.windows; + +import net.codecrete.usb.USBException; +import net.codecrete.usb.windows.gen.kernel32.Kernel32; +import net.codecrete.usb.windows.gen.kernel32._GUID; +import net.codecrete.usb.windows.gen.setupapi.SetupAPI; +import net.codecrete.usb.windows.gen.setupapi._SP_DEVICE_INTERFACE_DATA; +import net.codecrete.usb.windows.gen.stdlib.StdLib; + +import java.lang.foreign.Addressable; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; + +import static java.lang.foreign.MemoryAddress.NULL; +import static java.lang.foreign.ValueLayout.*; + +/** + * Device property GUIDs and functions + */ +public class DeviceProperty { + + public static final MemorySegment DEVPKEY_Device_Address = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, (short) 0x4efd, + (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, + (byte) 0x46, (byte) 0xa8, (byte) 0x50, (byte) 0xe0, 30); + + public static final MemorySegment DEVPKEY_Device_InstanceId = createDEVPROPKEY(0x78c34fc8, (short) 0x104a, (short) 0x4aca, + (byte) 0x9e, (byte) 0xa4, (byte) 0x52, (byte) 0x4d, + (byte) 0x52, (byte) 0x99, (byte) 0x6e, (byte) 0x57, 256); + + public static final MemorySegment DEVPKEY_Device_Parent = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, (short) 0x4706, + (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, + (byte) 0x80, (byte) 0x08, (byte) 0xa5, (byte) 0xa7, 8); + + public static int getDeviceIntProperty(Addressable devInfo, Addressable devInfoData, Addressable propertyKey) { + try (var session = MemorySession.openConfined()) { + var propertyTypeHolder = session.allocate(JAVA_INT); + var propertyValueHolder = session.allocate(JAVA_INT); + if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, + propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0) == 0) + throw new USBException("Internal error (SetupDiGetDevicePropertyW)", Kernel32.GetLastError()); + + if (propertyTypeHolder.get(JAVA_INT, 0) != SetupAPI.DEVPROP_TYPE_UINT32()) + throw new USBException("Internal error (expected property typ UINT32)"); + + return propertyValueHolder.get(JAVA_INT, 0); + } + } + + public static String getDeviceStringProperty(Addressable devInfo, Addressable devInfoData, Addressable propertyKey) { + try (var session = MemorySession.openConfined()) { + var propertyTypeHolder = session.allocate(JAVA_INT); + var requiredSizeHolder = session.allocate(JAVA_INT); + if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, + NULL, 0, requiredSizeHolder, 0) == 0) { + // TODO: Reactivate when proper GetLastError() handling is available +// int err = Kernel32.GetLastError(); +// if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) +// throw new USBException("Internal error (SetupDiGetDevicePropertyW)", Kernel32.GetLastError()); + } + + if (propertyTypeHolder.get(JAVA_INT, 0) != SetupAPI.DEVPROP_TYPE_STRING()) + throw new USBException("Internal error (expected property typ UINT32)"); + + int stringLen = requiredSizeHolder.get(JAVA_INT, 0) / 2 - 1; + + var propertyValueHolder = session.allocateArray(JAVA_CHAR, stringLen + 1); + if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, + propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0) == 0) + throw new USBException("Internal error (SetupDiGetDevicePropertyW)", Kernel32.GetLastError()); + + return new String(propertyValueHolder.asSlice(0, 2L * stringLen).toArray(JAVA_CHAR)); + } + } + + public static String getDevicePath(String instanceID, Addressable interfaceGuid) { + try (var session = MemorySession.openConfined()) { + // get device info set for instance + var instanceIDSegment = session.allocateArray(JAVA_CHAR, instanceID.length() + 1); + instanceIDSegment.asSlice(0, instanceID.length() * 2L).copyFrom(MemorySegment.ofArray(instanceID.toCharArray())); + final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(interfaceGuid, instanceIDSegment, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); + if (Win.IsInvalidHandle(devInfoSetHandle)) + throw new USBException("internal error (SetupDiGetClassDevsW)"); + + // ensure the result is destroyed when the scope is left + session.addCloseAction(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); + + // retrieve first element of enumeration + var devIntfData = session.allocate(_SP_DEVICE_INTERFACE_DATA.$LAYOUT()); + _SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); + if (SetupAPI.SetupDiEnumDeviceInterfaces(devInfoSetHandle, NULL, interfaceGuid, 0, devIntfData) == 0) + throw new USBException("internal error (SetupDiEnumDeviceInterfaces)"); + + // get path + var intfDetailData = session.allocate(SP_DEVICE_INTERFACE_DETAIL_DATA_W.$LAYOUT()); + SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$set(intfDetailData, 8); + int intfDetailDataSize = (int) SP_DEVICE_INTERFACE_DETAIL_DATA_W.$LAYOUT().byteSize(); + if (SetupAPI.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, + intfDetailData, intfDetailDataSize, NULL, NULL) == 0) + throw new USBException("Internal error (SetupDiGetDeviceInterfaceDetailW)", Kernel32.GetLastError()); + + long pathLen = StdLib.wcslen(intfDetailData.address().addOffset(SP_DEVICE_INTERFACE_DETAIL_DATA_W.DevicePath$Offset)); + return new String(intfDetailData.asSlice(SP_DEVICE_INTERFACE_DETAIL_DATA_W.DevicePath$Offset, 2L * pathLen).toArray(JAVA_CHAR)); + } + } + + public static MemorySegment createDEVPROPKEY(int data1, short data2, short data3, + byte data4_0, byte data4_1, byte data4_2, byte data4_3, + byte data4_4, byte data4_5, byte data4_6, byte data4_7, + int pid) { + var propKey = MemorySession.global().allocate(_GUID.sizeof() + JAVA_INT.byteSize()); + _GUID.Data1$set(propKey, data1); + _GUID.Data2$set(propKey, data2); + _GUID.Data3$set(propKey, data3); + var data4 = _GUID.Data4$slice(propKey); + data4.set(JAVA_BYTE, 0, data4_0); + data4.set(JAVA_BYTE, 1, data4_1); + data4.set(JAVA_BYTE, 2, data4_2); + data4.set(JAVA_BYTE, 3, data4_3); + data4.set(JAVA_BYTE, 4, data4_4); + data4.set(JAVA_BYTE, 5, data4_5); + data4.set(JAVA_BYTE, 6, data4_6); + data4.set(JAVA_BYTE, 7, data4_7); + propKey.set(JAVA_INT, 16, pid); + return propKey; + } + +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java index 095f47e2..162a680b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java @@ -50,6 +50,12 @@ public class USBHelper { (byte) 0x90, (byte) 0x1F, (byte) 0x00, (byte) 0xC0, (byte) 0x4F, (byte) 0xB9, (byte) 0x51, (byte) 0xED); + // f18a0e88-c30c-11d0-8815-00a0c906bed8 + + public static final MemorySegment GUID_DEVINTERFACE_USB_HUB = Win.CreateGUID(0xf18a0e88, (short) 0xc30c, (short) 0x11d0, + (byte) 0x88, (byte) 0x15, (byte) 0x00, (byte) 0xa0, + (byte) 0xc9, (byte) 0x06, (byte) 0xbe, (byte) 0xd8); + static { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index e71c550a..3df7cbbd 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -12,11 +12,9 @@ import net.codecrete.usb.common.USBDescriptors; import net.codecrete.usb.common.USBDeviceRegistry; import net.codecrete.usb.common.USBStructs; -import net.codecrete.usb.windows.gen.cfgmgr32.CfgMgr32; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.setupapi.SetupAPI; import net.codecrete.usb.windows.gen.setupapi._SP_DEVINFO_DATA; -import net.codecrete.usb.windows.gen.stdlib.StdLib; import net.codecrete.usb.windows.gen.usbioctl.USBIoctl; import java.lang.foreign.Addressable; @@ -38,8 +36,10 @@ public List getAllDevices() { List result = new ArrayList<>(); try (var outerSession = MemorySession.openConfined()) { - // get as set of all USB devices present - final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); + // get device information set of all USB devices present + final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW( + USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, + SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); if (Win.IsInvalidHandle(devInfoSetHandle)) throw new USBException("internal error (SetupDiGetClassDevsW)"); @@ -49,83 +49,34 @@ public List getAllDevices() { var devInfo = MemorySegment.allocateNative(_SP_DEVINFO_DATA.$LAYOUT(), outerSession); _SP_DEVINFO_DATA.cbSize$set(devInfo, (int) _SP_DEVINFO_DATA.$LAYOUT().byteSize()); - var devInfoData = MemorySegment.allocateNative(_SP_DEVINFO_DATA.$LAYOUT(), outerSession); - _SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) _SP_DEVINFO_DATA.$LAYOUT().byteSize()); - + // iterate all devices for (int i = 0; true; i++) { if (SetupAPI.SetupDiEnumDeviceInfo(devInfoSetHandle, i, devInfo) == 0) { int err = Kernel32.GetLastError(); - if (err != Kernel32.ERROR_NO_MORE_ITEMS()) { - throw new USBException("Internal error (SetupDiEnumDeviceInfo) "); - } - break; + if (err == Kernel32.ERROR_NO_MORE_ITEMS() || err == Kernel32.ERROR_SUCCESS()) + break; + throw new USBException("Internal error (SetupDiEnumDeviceInfo) "); } try (var session = MemorySession.openConfined()) { - // get the parent device (a USB hub) - var parentDevInstHolder = session.allocate(JAVA_INT); - int devInst = _SP_DEVINFO_DATA.DevInst$get(devInfo); - int cmRet = CfgMgr32.CM_Get_Parent(parentDevInstHolder, devInst, 0); - if (cmRet != 0) - throw new USBException("Internal error (CM_Get_Parent)"); - var parentDevInst = parentDevInstHolder.get(JAVA_INT, 0); - - // get parent device path - var pathBuffer = session.allocateArray(JAVA_CHAR, 260); - cmRet = CfgMgr32.CM_Get_Device_IDW(parentDevInst, pathBuffer, 260, 0); - if (cmRet != 0) - throw new USBException("Internal error (CM_Get_Device_ID)"); - - // create hub path - var pathChars = pathBuffer.toArray(JAVA_CHAR); - var index = 0; - for (; pathChars[index] != 0; index++) { - if (pathChars[index] == '\\' || pathChars[index] == '$') - pathChars[index] = '#'; - } - var hubPath = "\\\\?\\" + new String(pathChars, 0, index) + "#{f18a0e88-c30c-11d0-8815-00a0c906bed8}\0"; - - var hubPathSeg = session.allocateArray(JAVA_CHAR, hubPath.length()); - hubPathSeg.copyFrom(MemorySegment.ofArray(hubPath.toCharArray())); + var usbPortNum = DeviceProperty.getDeviceIntProperty(devInfoSetHandle, devInfo, DeviceProperty.DEVPKEY_Device_Address); + var instanceID = DeviceProperty.getDeviceStringProperty(devInfoSetHandle, devInfo, DeviceProperty.DEVPKEY_Device_InstanceId); + var devicePath = DeviceProperty.getDevicePath(instanceID, USBHelper.GUID_DEVINTERFACE_USB_DEVICE); + var parentInstanceID = DeviceProperty.getDeviceStringProperty(devInfoSetHandle, devInfo, DeviceProperty.DEVPKEY_Device_Parent); + var hubPath = DeviceProperty.getDevicePath(parentInstanceID, USBHelper.GUID_DEVINTERFACE_USB_HUB); + // open hub + var hubPathSeg = session.allocateArray(JAVA_CHAR, hubPath.length() + 2); + hubPathSeg.copyFrom(MemorySegment.ofArray(hubPath.toCharArray())); final var hubHandle = Kernel32.CreateFileW(hubPathSeg, Kernel32.GENERIC_WRITE(), Kernel32.FILE_SHARE_WRITE(), NULL, Kernel32.OPEN_EXISTING(), 0, NULL); if (Win.IsInvalidHandle(hubHandle)) - throw new USBException("Cannot open USB hub"); + throw new USBException("Cannot open USB hub", Kernel32.GetLastError()); + // ensure the hub is closed later session.addCloseAction(() -> Kernel32.CloseHandle(hubHandle)); - // get the interface data - if (SetupAPI.SetupDiEnumDeviceInterfaces(devInfoSetHandle, devInfo, - USBHelper.GUID_DEVINTERFACE_USB_DEVICE, 0, devInfoData) == 0) { - int lastError = Kernel32.GetLastError(); - if (lastError == Kernel32.ERROR_NO_MORE_ITEMS()) - throw new USBException("Internal error (SetupDiEnumDeviceInterfaces)"); - continue; - } - - // get path of first interface - var intfDetailData = MemorySegment.allocateNative(SP_DEVICE_INTERFACE_DETAIL_DATA_W.$LAYOUT(), session); - SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$set(intfDetailData, 8); - int intfDatailDataSize = (int) SP_DEVICE_INTERFACE_DETAIL_DATA_W.$LAYOUT().byteSize(); - if (SetupAPI.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devInfoData, - intfDetailData, intfDatailDataSize, NULL, NULL) == 0) - throw new USBException("Internal error (SetupDiGetDeviceInterfaceDetailA - 2)", Kernel32.GetLastError()); - - long pathLen = StdLib.wcslen(intfDetailData.address().addOffset(SP_DEVICE_INTERFACE_DETAIL_DATA_W.DevicePath$Offset)); - char[] devicePathChars = intfDetailData.asSlice(SP_DEVICE_INTERFACE_DETAIL_DATA_W.DevicePath$Offset, pathLen * 2).toArray(JAVA_CHAR); - String devicePath = new String(devicePathChars); - - // get device's hub port number - var usbPortNumHolder = session.allocate(JAVA_INT); - var sizeHolder = session.allocate(JAVA_INT); - if (SetupAPI.SetupDiGetDeviceRegistryPropertyW(devInfoSetHandle, devInfo, - SetupAPI.SPDRP_ADDRESS(), NULL, usbPortNumHolder, - (int) usbPortNumHolder.byteSize(), sizeHolder) == 0) - throw new USBException("Internal error (cannot get device hub port)", Kernel32.GetLastError()); - int usbPortNum = usbPortNumHolder.get(JAVA_INT, 0); - result.add(createDeviceInfo(devicePath, hubHandle, usbPortNum)); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/CfgMgr32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/CfgMgr32.java deleted file mode 100644 index b7b83db0..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/CfgMgr32.java +++ /dev/null @@ -1,44 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.cfgmgr32; - -import java.lang.foreign.Addressable; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.*; -public class CfgMgr32 { - - /* package-private */ CfgMgr32() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; - public static MethodHandle CM_Get_Device_IDW$MH() { - return RuntimeHelper.requireNonNull(constants$0.CM_Get_Device_IDW$MH,"CM_Get_Device_IDW"); - } - public static int CM_Get_Device_IDW ( int dnDevInst, Addressable Buffer, int BufferLen, int ulFlags) { - var mh$ = CM_Get_Device_IDW$MH(); - try { - return (int)mh$.invokeExact(dnDevInst, Buffer, BufferLen, ulFlags); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle CM_Get_Parent$MH() { - return RuntimeHelper.requireNonNull(constants$0.CM_Get_Parent$MH,"CM_Get_Parent"); - } - public static int CM_Get_Parent ( Addressable pdnDevInst, int dnDevInst, int ulFlags) { - var mh$ = CM_Get_Parent$MH(); - try { - return (int)mh$.invokeExact(pdnDevInst, dnDevInst, ulFlags); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/Constants$root.java deleted file mode 100644 index 0f04844e..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/Constants$root.java +++ /dev/null @@ -1,19 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.cfgmgr32; - -import static java.lang.foreign.ValueLayout.*; -public class Constants$root { - - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/RuntimeHelper.java deleted file mode 100644 index 3ac64e04..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/RuntimeHelper.java +++ /dev/null @@ -1,216 +0,0 @@ -package net.codecrete.usb.windows.gen.cfgmgr32; -// Generated by jextract - -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.*; - -final class RuntimeHelper { - - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); - - static { - System.loadLibrary("Cfgmgr32"); - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); - } - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); - } - - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { - try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); - } - - // Internals only below this point - - private static class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/constants$0.java deleted file mode 100644 index de3dd42c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/cfgmgr32/constants$0.java +++ /dev/null @@ -1,30 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.cfgmgr32; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$0 { - - static final FunctionDescriptor CM_Get_Device_IDW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT - ); - static final MethodHandle CM_Get_Device_IDW$MH = RuntimeHelper.downcallHandle( - "CM_Get_Device_IDW", - constants$0.CM_Get_Device_IDW$FUNC - ); - static final FunctionDescriptor CM_Get_Parent$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT - ); - static final MethodHandle CM_Get_Parent$MH = RuntimeHelper.downcallHandle( - "CM_Get_Parent", - constants$0.CM_Get_Parent$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java index 21d2b421..e523709a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -83,6 +83,12 @@ public static int GENERIC_READ() { public static int GENERIC_WRITE() { return (int)1073741824L; } + public static int ERROR_SUCCESS() { + return (int)0L; + } + public static int ERROR_INSUFFICIENT_BUFFER() { + return (int)122L; + } public static int ERROR_NO_MORE_ITEMS() { return (int)259L; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java index 88cd7162..ad616e12 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java @@ -18,6 +18,12 @@ public class SetupAPI { public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static int DEVPROP_TYPE_UINT32() { + return (int)7L; + } + public static int DEVPROP_TYPE_STRING() { + return (int)18L; + } public static int DIGCF_PRESENT() { return (int)2L; } @@ -79,8 +85,19 @@ public static MemoryAddress SetupDiGetClassDevsW ( Addressable ClassGuid, Addre throw new AssertionError("should not reach here", ex$); } } + public static MethodHandle SetupDiGetDevicePropertyW$MH() { + return RuntimeHelper.requireNonNull(constants$0.SetupDiGetDevicePropertyW$MH,"SetupDiGetDevicePropertyW"); + } + public static int SetupDiGetDevicePropertyW ( Addressable DeviceInfoSet, Addressable DeviceInfoData, Addressable PropertyKey, Addressable PropertyType, Addressable PropertyBuffer, int PropertyBufferSize, Addressable RequiredSize, int Flags) { + var mh$ = SetupDiGetDevicePropertyW$MH(); + try { + return (int)mh$.invokeExact(DeviceInfoSet, DeviceInfoData, PropertyKey, PropertyType, PropertyBuffer, PropertyBufferSize, RequiredSize, Flags); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static MethodHandle SetupDiGetDeviceRegistryPropertyW$MH() { - return RuntimeHelper.requireNonNull(constants$0.SetupDiGetDeviceRegistryPropertyW$MH,"SetupDiGetDeviceRegistryPropertyW"); + return RuntimeHelper.requireNonNull(constants$1.SetupDiGetDeviceRegistryPropertyW$MH,"SetupDiGetDeviceRegistryPropertyW"); } public static int SetupDiGetDeviceRegistryPropertyW ( Addressable DeviceInfoSet, Addressable DeviceInfoData, int Property, Addressable PropertyRegDataType, Addressable PropertyBuffer, int PropertyBufferSize, Addressable RequiredSize) { var mh$ = SetupDiGetDeviceRegistryPropertyW$MH(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java index 1c6554b3..00f31e8b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java @@ -55,18 +55,19 @@ class constants$0 { "SetupDiGetClassDevsW", constants$0.SetupDiGetClassDevsW$FUNC ); - static final FunctionDescriptor SetupDiGetDeviceRegistryPropertyW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + static final FunctionDescriptor SetupDiGetDevicePropertyW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT ); - static final MethodHandle SetupDiGetDeviceRegistryPropertyW$MH = RuntimeHelper.downcallHandle( - "SetupDiGetDeviceRegistryPropertyW", - constants$0.SetupDiGetDeviceRegistryPropertyW$FUNC + static final MethodHandle SetupDiGetDevicePropertyW$MH = RuntimeHelper.downcallHandle( + "SetupDiGetDevicePropertyW", + constants$0.SetupDiGetDevicePropertyW$FUNC ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java new file mode 100644 index 00000000..74594195 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java @@ -0,0 +1,24 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.setupapi; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$1 { + + static final FunctionDescriptor SetupDiGetDeviceRegistryPropertyW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle SetupDiGetDeviceRegistryPropertyW$MH = RuntimeHelper.downcallHandle( + "SetupDiGetDeviceRegistryPropertyW", + constants$1.SetupDiGetDeviceRegistryPropertyW$FUNC + ); +} + + From 9f9ab90ed58a5b17c87d6ef74efcaaee640c0bdc Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 28 Aug 2022 20:22:43 +0200 Subject: [PATCH 016/433] Windows: clean up string conversion --- .../codecrete/usb/windows/DeviceProperty.java | 9 ++--- .../java/net/codecrete/usb/windows/Win.java | 33 +++++++++++++++++++ .../usb/windows/WindowsUSBDevice.java | 5 +-- .../usb/windows/WindowsUSBDeviceRegistry.java | 4 +-- 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index 133651b3..ce0a54dc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -12,7 +12,6 @@ import net.codecrete.usb.windows.gen.kernel32._GUID; import net.codecrete.usb.windows.gen.setupapi.SetupAPI; import net.codecrete.usb.windows.gen.setupapi._SP_DEVICE_INTERFACE_DATA; -import net.codecrete.usb.windows.gen.stdlib.StdLib; import java.lang.foreign.Addressable; import java.lang.foreign.MemorySegment; @@ -75,15 +74,14 @@ public static String getDeviceStringProperty(Addressable devInfo, Addressable de propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0) == 0) throw new USBException("Internal error (SetupDiGetDevicePropertyW)", Kernel32.GetLastError()); - return new String(propertyValueHolder.asSlice(0, 2L * stringLen).toArray(JAVA_CHAR)); + return Win.createStringFromSegment(propertyValueHolder); } } public static String getDevicePath(String instanceID, Addressable interfaceGuid) { try (var session = MemorySession.openConfined()) { // get device info set for instance - var instanceIDSegment = session.allocateArray(JAVA_CHAR, instanceID.length() + 1); - instanceIDSegment.asSlice(0, instanceID.length() * 2L).copyFrom(MemorySegment.ofArray(instanceID.toCharArray())); + var instanceIDSegment = Win.createSegmentFromString(instanceID, session); final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(interfaceGuid, instanceIDSegment, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); if (Win.IsInvalidHandle(devInfoSetHandle)) throw new USBException("internal error (SetupDiGetClassDevsW)"); @@ -105,8 +103,7 @@ public static String getDevicePath(String instanceID, Addressable interfaceGuid) intfDetailData, intfDetailDataSize, NULL, NULL) == 0) throw new USBException("Internal error (SetupDiGetDeviceInterfaceDetailW)", Kernel32.GetLastError()); - long pathLen = StdLib.wcslen(intfDetailData.address().addOffset(SP_DEVICE_INTERFACE_DETAIL_DATA_W.DevicePath$Offset)); - return new String(intfDetailData.asSlice(SP_DEVICE_INTERFACE_DETAIL_DATA_W.DevicePath$Offset, 2L * pathLen).toArray(JAVA_CHAR)); + return Win.createStringFromSegment(intfDetailData.asSlice(SP_DEVICE_INTERFACE_DETAIL_DATA_W.DevicePath$Offset)); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index 22ecb309..c850dc72 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -8,12 +8,15 @@ package net.codecrete.usb.windows; import net.codecrete.usb.windows.gen.kernel32._GUID; +import net.codecrete.usb.windows.gen.stdlib.StdLib; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; +import java.lang.foreign.ValueLayout; import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_CHAR; /** * Windows helpers. @@ -30,6 +33,36 @@ public static boolean IsInvalidHandle(MemoryAddress handle) { return handle.toRawLongValue() == -1L; } + /** + * Creates a memory segment as a copy of a Java string. + *

+ * The memory segment contains a copy of the string (null-terminated, UTF-16/wide characters). + *

+ * @param str the string to copy + * @param session the memory session for the memory segment + * @return the resulting memory segment + */ + public static MemorySegment createSegmentFromString(String str, MemorySession session) { + // allocate segment (including space for terminating null) + var segment = session.allocateArray(ValueLayout.JAVA_CHAR, str.length() + 1); + // copy characters + segment.copyFrom(MemorySegment.ofArray(str.toCharArray())); + return segment; + } + + /** + * Creates a copy of the string in the memory segment. + *

+ * The string must be a null-terminated UTF-16 (wide character) string. + *

+ * @param segment the memory segment + * @return copied string + */ + public static String createStringFromSegment(MemorySegment segment) { + long strLen = StdLib.wcslen(segment); + return new String(segment.asSlice(0, 2L * strLen).toArray(JAVA_CHAR)); + } + /** * Creates a GUID in native memory. * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index a637c22e..eeee50b1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -23,7 +23,6 @@ import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; -import java.lang.foreign.ValueLayout; import java.util.ArrayList; import java.util.List; @@ -50,9 +49,7 @@ public class WindowsUSBDevice extends USBDeviceImpl { try (var session = MemorySession.openConfined()) { // open Windows device - var pathChars = id.toString().toCharArray(); - var pathSegment = session.allocateArray(ValueLayout.JAVA_CHAR, pathChars.length + 1); - pathSegment.copyFrom(MemorySegment.ofArray(pathChars)); + var pathSegment = Win.createSegmentFromString(id.toString(), session); device = Kernel32.CreateFileW(pathSegment, Kernel32.GENERIC_WRITE() | Kernel32.GENERIC_READ(), Kernel32.FILE_SHARE_WRITE() | Kernel32.FILE_SHARE_READ(), diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 3df7cbbd..2061d3c6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -67,8 +67,7 @@ public List getAllDevices() { var hubPath = DeviceProperty.getDevicePath(parentInstanceID, USBHelper.GUID_DEVINTERFACE_USB_HUB); // open hub - var hubPathSeg = session.allocateArray(JAVA_CHAR, hubPath.length() + 2); - hubPathSeg.copyFrom(MemorySegment.ofArray(hubPath.toCharArray())); + var hubPathSeg = Win.createSegmentFromString(hubPath, session); final var hubHandle = Kernel32.CreateFileW(hubPathSeg, Kernel32.GENERIC_WRITE(), Kernel32.FILE_SHARE_WRITE(), NULL, Kernel32.OPEN_EXISTING(), 0, NULL); if (Win.IsInvalidHandle(hubHandle)) @@ -152,6 +151,7 @@ private String getStringDescriptor(Addressable hubHandle, int usbPortNumber, int sizeHolder, NULL) == 0) throw new USBException(String.format("Cannot retrieve string descriptor %d", index), Kernel32.GetLastError()); + // The string descriptor is not null terminated var stringDesc = descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, dataLen); int stringLen = 255 & (byte) USBHelper.USB_STRING_DESCRIPTOR_bLength.get(stringDesc); var chars = stringDesc.asSlice(USBHelper.USB_STRING_DESCRIPTOR_bString$Offset, stringLen - 2) From 4c8e2ea002a177051ce0284d4d4b9dd23902fbee Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 28 Aug 2022 23:01:32 +0200 Subject: [PATCH 017/433] Windows: monitor connect/disconnect --- java-does-usb/jextract/gen_win_cfgmgr32.cmd | 12 - java-does-usb/jextract/gen_win_kernel32.cmd | 1 + java-does-usb/jextract/gen_win_setupapi.cmd | 1 + java-does-usb/jextract/gen_win_user32.cmd | 25 ++ java-does-usb/jextract/windows_headers.h | 1 + .../usb/windows/WindowsUSBDeviceInfo.java | 8 +- .../usb/windows/WindowsUSBDeviceRegistry.java | 258 ++++++++++++++++-- .../usb/windows/gen/kernel32/Kernel32.java | 11 + .../usb/windows/gen/kernel32/constants$0.java | 7 + .../usb/windows/gen/setupapi/SetupAPI.java | 13 +- .../usb/windows/gen/setupapi/constants$0.java | 24 +- .../usb/windows/gen/setupapi/constants$1.java | 14 + .../windows/gen/user32/Constants$root.java | 19 ++ .../usb/windows/gen/user32/RuntimeHelper.java | 216 +++++++++++++++ .../usb/windows/gen/user32/User32.java | 96 +++++++ .../_DEV_BROADCAST_DEVICEINTERFACE_W.java | 87 ++++++ .../gen/user32/_DEV_BROADCAST_HDR.java | 73 +++++ .../usb/windows/gen/user32/constants$0.java | 67 +++++ .../usb/windows/gen/user32/tagMSG.java | 116 ++++++++ .../windows/gen/user32/tagWNDCLASSEXW.java | 226 +++++++++++++++ 20 files changed, 1222 insertions(+), 53 deletions(-) delete mode 100644 java-does-usb/jextract/gen_win_cfgmgr32.cmd create mode 100644 java-does-usb/jextract/gen_win_user32.cmd create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java diff --git a/java-does-usb/jextract/gen_win_cfgmgr32.cmd b/java-does-usb/jextract/gen_win_cfgmgr32.cmd deleted file mode 100644 index 320f0d0b..00000000 --- a/java-does-usb/jextract/gen_win_cfgmgr32.cmd +++ /dev/null @@ -1,12 +0,0 @@ -set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract.bat -set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 -%JEXTRACT% --source --output ../src/main/java ^ - -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ - -I "%SDK_DIR%\um" ^ - -I "%SDK_DIR%\shared" ^ - -l Cfgmgr32 ^ - --header-class-name CfgMgr32 ^ - --target-package net.codecrete.usb.windows.gen.cfgmgr32 ^ - --include-function CM_Get_Parent ^ - --include-function CM_Get_Device_IDW ^ - windows_headers.h diff --git a/java-does-usb/jextract/gen_win_kernel32.cmd b/java-does-usb/jextract/gen_win_kernel32.cmd index 2f524df8..08aa4d94 100644 --- a/java-does-usb/jextract/gen_win_kernel32.cmd +++ b/java-does-usb/jextract/gen_win_kernel32.cmd @@ -11,6 +11,7 @@ set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 --include-function CloseHandle ^ --include-function DeviceIoControl ^ --include-function GetLastError ^ + --include-function GetModuleHandleW ^ --include-macro ERROR_SUCCESS ^ --include-macro ERROR_NO_MORE_ITEMS ^ --include-macro ERROR_INSUFFICIENT_BUFFER ^ diff --git a/java-does-usb/jextract/gen_win_setupapi.cmd b/java-does-usb/jextract/gen_win_setupapi.cmd index 187cb288..edaf3411 100644 --- a/java-does-usb/jextract/gen_win_setupapi.cmd +++ b/java-does-usb/jextract/gen_win_setupapi.cmd @@ -14,6 +14,7 @@ set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 --include-function SetupDiGetDeviceInterfaceDetailW ^ --include-function SetupDiGetDeviceRegistryPropertyW ^ --include-function SetupDiGetDevicePropertyW ^ + --include-function SetupDiOpenDeviceInterfaceW ^ --include-struct _SP_DEVINFO_DATA ^ --include-struct _SP_DEVICE_INTERFACE_DATA ^ --include-struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W ^ diff --git a/java-does-usb/jextract/gen_win_user32.cmd b/java-does-usb/jextract/gen_win_user32.cmd new file mode 100644 index 00000000..14f5ad2a --- /dev/null +++ b/java-does-usb/jextract/gen_win_user32.cmd @@ -0,0 +1,25 @@ +set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract.bat +set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 +%JEXTRACT% --source --output ../src/main/java ^ + -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ + -I "%SDK_DIR%\um" ^ + -I "%SDK_DIR%\shared" ^ + -l User32 ^ + --header-class-name User32 ^ + --target-package net.codecrete.usb.windows.gen.user32 ^ + --include-function RegisterClassExW ^ + --include-function CreateWindowExW ^ + --include-function RegisterDeviceNotificationW ^ + --include-function GetMessageW ^ + --include-function DefWindowProcW ^ + --include-macro DEVICE_NOTIFY_WINDOW_HANDLE ^ + --include-macro HWND_MESSAGE ^ + --include-macro WM_DEVICECHANGE ^ + --include-macro DBT_DEVICEARRIVAL ^ + --include-macro DBT_DEVICEREMOVECOMPLETE ^ + --include-macro DBT_DEVTYP_DEVICEINTERFACE ^ + --include-struct tagMSG ^ + --include-struct tagWNDCLASSEXW ^ + --include-struct _DEV_BROADCAST_HDR ^ + --include-struct _DEV_BROADCAST_DEVICEINTERFACE_W ^ + windows_headers.h diff --git a/java-does-usb/jextract/windows_headers.h b/java-does-usb/jextract/windows_headers.h index a863aa14..fbc95ecb 100644 --- a/java-does-usb/jextract/windows_headers.h +++ b/java-does-usb/jextract/windows_headers.h @@ -3,3 +3,4 @@ #include #include #include +#include diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java index 1c0a3763..b93ca796 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java @@ -15,17 +15,21 @@ public class WindowsUSBDeviceInfo extends USBDeviceInfoImpl { private final byte currentConfigurationValue; WindowsUSBDeviceInfo( - Object id, int vendorId, int productId, + String devicePath, int vendorId, int productId, String manufacturer, String product, String serial, int classCode, int subclassCode, int protocolCode, byte currentConfigurationValue) { - super(id, vendorId, productId, + super(devicePath, vendorId, productId, manufacturer, product, serial, classCode, subclassCode, protocolCode); this.currentConfigurationValue = currentConfigurationValue; } + String devicePath() { + return (String) id; + } + @Override public USBDevice open() { return new WindowsUSBDevice(id, this, currentConfigurationValue); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 2061d3c6..0f040c5c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -14,26 +14,47 @@ import net.codecrete.usb.common.USBStructs; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.setupapi.SetupAPI; +import net.codecrete.usb.windows.gen.setupapi._SP_DEVICE_INTERFACE_DATA; import net.codecrete.usb.windows.gen.setupapi._SP_DEVINFO_DATA; import net.codecrete.usb.windows.gen.usbioctl.USBIoctl; +import net.codecrete.usb.windows.gen.user32.*; -import java.lang.foreign.Addressable; -import java.lang.foreign.MemoryAddress; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; +import java.lang.foreign.*; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.function.Consumer; import static java.lang.foreign.MemoryAddress.NULL; -import static java.lang.foreign.ValueLayout.JAVA_CHAR; -import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.*; public class WindowsUSBDeviceRegistry implements USBDeviceRegistry { + private volatile List devices; + private Consumer onDeviceConnectedHandler; + private Consumer onDeviceDisconnectedHandler; + private boolean isMonitorThreadStarted; + + /** + * Create new instance + *

+ * Starts a second thread and immediately iterates all USB devices. + *

+ */ + public WindowsUSBDeviceRegistry() { + startDeviceMonitor(); + enumeratePresentDevices(); + } + public List getAllDevices() { + return devices; + } + + private void enumeratePresentDevices() { - List result = new ArrayList<>(); + List deviceList = new ArrayList<>(); try (var outerSession = MemorySession.openConfined()) { // get device information set of all USB devices present @@ -49,38 +70,49 @@ public List getAllDevices() { var devInfo = MemorySegment.allocateNative(_SP_DEVINFO_DATA.$LAYOUT(), outerSession); _SP_DEVINFO_DATA.cbSize$set(devInfo, (int) _SP_DEVINFO_DATA.$LAYOUT().byteSize()); + // ensure all hubs are closed later + final var hubHandles = new HashMap(); + outerSession.addCloseAction(() -> hubHandles.forEach((path, handle) -> Kernel32.CloseHandle(handle))); + // iterate all devices for (int i = 0; true; i++) { if (SetupAPI.SetupDiEnumDeviceInfo(devInfoSetHandle, i, devInfo) == 0) { int err = Kernel32.GetLastError(); + // TODO: Remove check for ERROR_SUCCESS if proper GetLastError() handling is available if (err == Kernel32.ERROR_NO_MORE_ITEMS() || err == Kernel32.ERROR_SUCCESS()) break; throw new USBException("Internal error (SetupDiEnumDeviceInfo) "); } - try (var session = MemorySession.openConfined()) { + var instanceID = DeviceProperty.getDeviceStringProperty(devInfoSetHandle, devInfo, DeviceProperty.DEVPKEY_Device_InstanceId); + var devicePath = DeviceProperty.getDevicePath(instanceID, USBHelper.GUID_DEVINTERFACE_USB_DEVICE); - var usbPortNum = DeviceProperty.getDeviceIntProperty(devInfoSetHandle, devInfo, DeviceProperty.DEVPKEY_Device_Address); - var instanceID = DeviceProperty.getDeviceStringProperty(devInfoSetHandle, devInfo, DeviceProperty.DEVPKEY_Device_InstanceId); - var devicePath = DeviceProperty.getDevicePath(instanceID, USBHelper.GUID_DEVINTERFACE_USB_DEVICE); - var parentInstanceID = DeviceProperty.getDeviceStringProperty(devInfoSetHandle, devInfo, DeviceProperty.DEVPKEY_Device_Parent); - var hubPath = DeviceProperty.getDevicePath(parentInstanceID, USBHelper.GUID_DEVINTERFACE_USB_HUB); + deviceList.add(createDeviceInfo(devInfoSetHandle, devInfo, devicePath, hubHandles)); + } - // open hub - var hubPathSeg = Win.createSegmentFromString(hubPath, session); - final var hubHandle = Kernel32.CreateFileW(hubPathSeg, Kernel32.GENERIC_WRITE(), Kernel32.FILE_SHARE_WRITE(), - NULL, Kernel32.OPEN_EXISTING(), 0, NULL); - if (Win.IsInvalidHandle(hubHandle)) - throw new USBException("Cannot open USB hub", Kernel32.GetLastError()); + devices = deviceList; + } + } - // ensure the hub is closed later - session.addCloseAction(() -> Kernel32.CloseHandle(hubHandle)); + private USBDeviceInfo createDeviceInfo(MemoryAddress devInfoSetHandle, MemorySegment devInfo, String devicePath, HashMap hubHandles) { + try (var session = MemorySession.openConfined()) { - result.add(createDeviceInfo(devicePath, hubHandle, usbPortNum)); - } + var usbPortNum = DeviceProperty.getDeviceIntProperty(devInfoSetHandle, devInfo, DeviceProperty.DEVPKEY_Device_Address); + var parentInstanceID = DeviceProperty.getDeviceStringProperty(devInfoSetHandle, devInfo, DeviceProperty.DEVPKEY_Device_Parent); + var hubPath = DeviceProperty.getDevicePath(parentInstanceID, USBHelper.GUID_DEVINTERFACE_USB_HUB); + + // open hub if not open yet + var hubHandle = hubHandles.get(hubPath); + if (hubHandle == null) { + var hubPathSeg = Win.createSegmentFromString(hubPath, session); + hubHandle = Kernel32.CreateFileW(hubPathSeg, Kernel32.GENERIC_WRITE(), Kernel32.FILE_SHARE_WRITE(), + NULL, Kernel32.OPEN_EXISTING(), 0, NULL); + if (Win.IsInvalidHandle(hubHandle)) + throw new USBException("Cannot open USB hub", Kernel32.GetLastError()); + hubHandles.put(hubPath, hubHandle); } - return result; + return createDeviceInfo(devicePath, hubHandle, usbPortNum); } } @@ -160,11 +192,189 @@ private String getStringDescriptor(Addressable hubHandle, int usbPortNumber, int } } + private synchronized void startDeviceMonitor() { + if (isMonitorThreadStarted) + return; + + isMonitorThreadStarted = true; + Thread t = new Thread(this::monitorDevices, "USB device monitor"); + t.start(); + } + + private void monitorDevices() { + try (var session = MemorySession.openConfined()) { + + final var className = Win.createSegmentFromString("USB_MONITOR", session); + final var windowName = Win.createSegmentFromString("USB device monitor", session); + final var instance = Kernel32.GetModuleHandleW(NULL); + + // create upcall for handling window messages + var handleWindowMessageMH = MethodHandles.lookup().findVirtual( + WindowsUSBDeviceRegistry.class, + "handleWindowMessage", + MethodType.methodType(long.class, MemoryAddress.class, int.class, long.class, long.class) + ).bindTo(this); + var handleWindowMessageStub = Linker.nativeLinker().upcallStub( + handleWindowMessageMH, + FunctionDescriptor.of(JAVA_LONG, ADDRESS, JAVA_INT, JAVA_LONG, JAVA_LONG), + session + ); + + // register window class + var wx = session.allocate(tagWNDCLASSEXW.$LAYOUT()); + tagWNDCLASSEXW.cbSize$set(wx, (int) wx.byteSize()); + tagWNDCLASSEXW.lpfnWndProc$set(wx, handleWindowMessageStub.address()); + tagWNDCLASSEXW.hInstance$set(wx, instance); + tagWNDCLASSEXW.lpszClassName$set(wx, className.address()); + User32.RegisterClassExW(wx); + + // create message-only window + Addressable hwnd = User32.CreateWindowExW(0, className, windowName, 0, + 0, 0, 0, 0, User32.HWND_MESSAGE(), NULL, instance, NULL); + if (hwnd == NULL) + throw new USBException("internal error (CreateWindowExW)", Kernel32.GetLastError()); + + // configure notifications + var notificationFilter = session.allocate(_DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); + _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$set(notificationFilter, (int) notificationFilter.byteSize()); + _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$set(notificationFilter, User32.DBT_DEVTYP_DEVICEINTERFACE()); + _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid$slice(notificationFilter).copyFrom(USBHelper.GUID_DEVINTERFACE_USB_DEVICE); + + var notifyHandle = User32.RegisterDeviceNotificationW(hwnd, notificationFilter, User32.DEVICE_NOTIFY_WINDOW_HANDLE()); + if (notifyHandle == NULL) + throw new USBException("internal error (RegisterDeviceNotificationW)", Kernel32.GetLastError()); + + // process messages + var msg = session.allocate(tagMSG.$LAYOUT()); + while (User32.GetMessageW(msg, hwnd, 0, 0) > 0) + ; // do nothing + + } catch (NoSuchMethodException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private long handleWindowMessage(MemoryAddress hWnd, int uMsg, long wParam, long lParam) { + + // check for message related to connecting/disconnecting devices + if (uMsg == User32.WM_DEVICECHANGE() && (wParam == User32.DBT_DEVICEARRIVAL() || wParam == User32.DBT_DEVICEREMOVECOMPLETE())) { + try (var session = MemorySession.openConfined()) { + var data = MemorySegment.ofAddress(MemoryAddress.ofLong(lParam), _DEV_BROADCAST_DEVICEINTERFACE_W.sizeof(), session); + if (_DEV_BROADCAST_HDR.dbch_devicetype$get(data) == User32.DBT_DEVTYP_DEVICEINTERFACE()) { + + // get device path + var nameSlice = MemorySegment.ofAddress(_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address(), 500, session); + var devicePath = Win.createStringFromSegment(nameSlice); + if (wParam == User32.DBT_DEVICEARRIVAL()) + onDeviceConnected(devicePath); + else + onDeviceDisconnected(devicePath); + return 0; + } + } + } + + // default message handling + return User32.DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + + private void onDeviceConnected(String devicePath) { + try (var session = MemorySession.openConfined()) { + + // get device information set of all USB devices present + final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW( + USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, + SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); + if (Win.IsInvalidHandle(devInfoSetHandle)) + throw new USBException("internal error (SetupDiGetClassDevsW)", Kernel32.GetLastError()); + + // ensure the result is destroyed when the scope is left + session.addCloseAction(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); + + var devIntfData = session.allocate(_SP_DEVICE_INTERFACE_DATA.$LAYOUT()); + _SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); + var devicePathSegment = Win.createSegmentFromString(devicePath, session); + if (SetupAPI.SetupDiOpenDeviceInterfaceW(devInfoSetHandle, devicePathSegment, 0, devIntfData) == 0) + throw new USBException("internal error (SetupDiOpenDeviceInterfaceW)", Kernel32.GetLastError()); + + var devInfo = session.allocate(_SP_DEVINFO_DATA.$LAYOUT()); + _SP_DEVINFO_DATA.cbSize$set(devInfo, (int) devInfo.byteSize()); + if (SetupAPI.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, NULL, 0, NULL, devInfo) == 0) { + int err = Kernel32.GetLastError(); + if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) + throw new USBException("internal error (SetupDiGetDeviceInterfaceDetailW)", err); + } + + // ensure all hubs are closed later + final var hubHandles = new HashMap(); + session.addCloseAction(() -> hubHandles.forEach((path, handle) -> Kernel32.CloseHandle(handle))); + + // check for duplicates + if (findDeviceIndex(devicePath) >= 0) + return; + + // create device info instance + var deviceInfo = createDeviceInfo(devInfoSetHandle, devInfo, devicePath, hubHandles); + + // copy list + var newDeviceList = new ArrayList<>(devices); + newDeviceList.add(deviceInfo); + devices = newDeviceList; + + // send notification + if (onDeviceConnectedHandler == null) + return; + onDeviceConnectedHandler.accept(deviceInfo); + } + } + + private void onDeviceDisconnected(String devicePath) { + int index = findDeviceIndex(devicePath); + if (index < 0) + return; // strange + + // copy list + var deviceInfo = devices.get(index); + var newDeviceList = new ArrayList<>(devices); + newDeviceList.remove(index); + devices = newDeviceList; + + // send notification + if (onDeviceDisconnectedHandler == null) + return; + onDeviceDisconnectedHandler.accept(deviceInfo); + } + + private int findDeviceIndex(String devicePath) { + if (devices == null) + return -1; + for (int i = 0; i < devices.size(); i++) { + var winInfo = (WindowsUSBDeviceInfo) devices.get(i); + if (winInfo.devicePath().equalsIgnoreCase(devicePath)) + return i; + } + return -1; + } + @Override public void setOnDeviceConnected(Consumer handler) { + if (handler == null) { + onDeviceConnectedHandler = null; + return; + } + + onDeviceConnectedHandler = handler; + startDeviceMonitor(); } @Override public void setOnDeviceDisconnected(Consumer handler) { + if (handler == null) { + onDeviceDisconnectedHandler = null; + return; + } + + onDeviceDisconnectedHandler = handler; + startDeviceMonitor(); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java index e523709a..1e481c41 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -77,6 +77,17 @@ public static int DeviceIoControl ( Addressable hDevice, int dwIoControlCode, throw new AssertionError("should not reach here", ex$); } } + public static MethodHandle GetModuleHandleW$MH() { + return RuntimeHelper.requireNonNull(constants$0.GetModuleHandleW$MH,"GetModuleHandleW"); + } + public static MemoryAddress GetModuleHandleW ( Addressable lpModuleName) { + var mh$ = GetModuleHandleW$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(lpModuleName); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static int GENERIC_READ() { return (int)2147483648L; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java index a350bf86..44c3452b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java @@ -45,6 +45,13 @@ class constants$0 { "DeviceIoControl", constants$0.DeviceIoControl$FUNC ); + static final FunctionDescriptor GetModuleHandleW$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetModuleHandleW$MH = RuntimeHelper.downcallHandle( + "GetModuleHandleW", + constants$0.GetModuleHandleW$FUNC + ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java index ad616e12..ff69c87e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java @@ -63,6 +63,17 @@ public static int SetupDiEnumDeviceInterfaces ( Addressable DeviceInfoSet, Addr throw new AssertionError("should not reach here", ex$); } } + public static MethodHandle SetupDiOpenDeviceInterfaceW$MH() { + return RuntimeHelper.requireNonNull(constants$0.SetupDiOpenDeviceInterfaceW$MH,"SetupDiOpenDeviceInterfaceW"); + } + public static int SetupDiOpenDeviceInterfaceW ( Addressable DeviceInfoSet, Addressable DevicePath, int OpenFlags, Addressable DeviceInterfaceData) { + var mh$ = SetupDiOpenDeviceInterfaceW$MH(); + try { + return (int)mh$.invokeExact(DeviceInfoSet, DevicePath, OpenFlags, DeviceInterfaceData); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static MethodHandle SetupDiGetDeviceInterfaceDetailW$MH() { return RuntimeHelper.requireNonNull(constants$0.SetupDiGetDeviceInterfaceDetailW$MH,"SetupDiGetDeviceInterfaceDetailW"); } @@ -86,7 +97,7 @@ public static MemoryAddress SetupDiGetClassDevsW ( Addressable ClassGuid, Addre } } public static MethodHandle SetupDiGetDevicePropertyW$MH() { - return RuntimeHelper.requireNonNull(constants$0.SetupDiGetDevicePropertyW$MH,"SetupDiGetDevicePropertyW"); + return RuntimeHelper.requireNonNull(constants$1.SetupDiGetDevicePropertyW$MH,"SetupDiGetDevicePropertyW"); } public static int SetupDiGetDevicePropertyW ( Addressable DeviceInfoSet, Addressable DeviceInfoData, Addressable PropertyKey, Addressable PropertyType, Addressable PropertyBuffer, int PropertyBufferSize, Addressable RequiredSize, int Flags) { var mh$ = SetupDiGetDevicePropertyW$MH(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java index 00f31e8b..4bec4d2c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java @@ -33,6 +33,16 @@ class constants$0 { "SetupDiEnumDeviceInterfaces", constants$0.SetupDiEnumDeviceInterfaces$FUNC ); + static final FunctionDescriptor SetupDiOpenDeviceInterfaceW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle SetupDiOpenDeviceInterfaceW$MH = RuntimeHelper.downcallHandle( + "SetupDiOpenDeviceInterfaceW", + constants$0.SetupDiOpenDeviceInterfaceW$FUNC + ); static final FunctionDescriptor SetupDiGetDeviceInterfaceDetailW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -55,20 +65,6 @@ class constants$0 { "SetupDiGetClassDevsW", constants$0.SetupDiGetClassDevsW$FUNC ); - static final FunctionDescriptor SetupDiGetDevicePropertyW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT - ); - static final MethodHandle SetupDiGetDevicePropertyW$MH = RuntimeHelper.downcallHandle( - "SetupDiGetDevicePropertyW", - constants$0.SetupDiGetDevicePropertyW$FUNC - ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java index 74594195..4b48fe18 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java @@ -6,6 +6,20 @@ import java.lang.invoke.MethodHandle; class constants$1 { + static final FunctionDescriptor SetupDiGetDevicePropertyW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT + ); + static final MethodHandle SetupDiGetDevicePropertyW$MH = RuntimeHelper.downcallHandle( + "SetupDiGetDevicePropertyW", + constants$1.SetupDiGetDevicePropertyW$FUNC + ); static final FunctionDescriptor SetupDiGetDeviceRegistryPropertyW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT, diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/Constants$root.java new file mode 100644 index 00000000..91462c49 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.user32; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java new file mode 100644 index 00000000..6da1ee8a --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java @@ -0,0 +1,216 @@ +package net.codecrete.usb.windows.gen.user32; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + System.loadLibrary("User32"); + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java new file mode 100644 index 00000000..92a80196 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java @@ -0,0 +1,96 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.user32; + +import java.lang.foreign.Addressable; +import java.lang.foreign.MemoryAddress; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.*; +public class User32 { + + /* package-private */ User32() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static int WM_DEVICECHANGE() { + return (int)537L; + } + public static int DEVICE_NOTIFY_WINDOW_HANDLE() { + return (int)0L; + } + public static int DBT_DEVICEARRIVAL() { + return (int)32768L; + } + public static int DBT_DEVICEREMOVECOMPLETE() { + return (int)32772L; + } + public static int DBT_DEVTYP_DEVICEINTERFACE() { + return (int)5L; + } + public static MethodHandle GetMessageW$MH() { + return RuntimeHelper.requireNonNull(constants$0.GetMessageW$MH,"GetMessageW"); + } + public static int GetMessageW ( Addressable lpMsg, Addressable hWnd, int wMsgFilterMin, int wMsgFilterMax) { + var mh$ = GetMessageW$MH(); + try { + return (int)mh$.invokeExact(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle RegisterDeviceNotificationW$MH() { + return RuntimeHelper.requireNonNull(constants$0.RegisterDeviceNotificationW$MH,"RegisterDeviceNotificationW"); + } + public static MemoryAddress RegisterDeviceNotificationW ( Addressable hRecipient, Addressable NotificationFilter, int Flags) { + var mh$ = RegisterDeviceNotificationW$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(hRecipient, NotificationFilter, Flags); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle DefWindowProcW$MH() { + return RuntimeHelper.requireNonNull(constants$0.DefWindowProcW$MH,"DefWindowProcW"); + } + public static long DefWindowProcW ( Addressable hWnd, int Msg, long wParam, long lParam) { + var mh$ = DefWindowProcW$MH(); + try { + return (long)mh$.invokeExact(hWnd, Msg, wParam, lParam); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle RegisterClassExW$MH() { + return RuntimeHelper.requireNonNull(constants$0.RegisterClassExW$MH,"RegisterClassExW"); + } + public static short RegisterClassExW ( Addressable x0) { + var mh$ = RegisterClassExW$MH(); + try { + return (short)mh$.invokeExact(x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle CreateWindowExW$MH() { + return RuntimeHelper.requireNonNull(constants$0.CreateWindowExW$MH,"CreateWindowExW"); + } + public static MemoryAddress CreateWindowExW ( int dwExStyle, Addressable lpClassName, Addressable lpWindowName, int dwStyle, int X, int Y, int nWidth, int nHeight, Addressable hWndParent, Addressable hMenu, Addressable hInstance, Addressable lpParam) { + var mh$ = CreateWindowExW$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MemoryAddress HWND_MESSAGE() { + return constants$0.HWND_MESSAGE$ADDR; + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java new file mode 100644 index 00000000..3a3548fc --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java @@ -0,0 +1,87 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.user32; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class _DEV_BROADCAST_DEVICEINTERFACE_W { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_LONG$LAYOUT.withName("dbcc_size"), + Constants$root.C_LONG$LAYOUT.withName("dbcc_devicetype"), + Constants$root.C_LONG$LAYOUT.withName("dbcc_reserved"), + MemoryLayout.structLayout( + Constants$root.C_LONG$LAYOUT.withName("Data1"), + Constants$root.C_SHORT$LAYOUT.withName("Data2"), + Constants$root.C_SHORT$LAYOUT.withName("Data3"), + MemoryLayout.sequenceLayout(8, Constants$root.C_CHAR$LAYOUT).withName("Data4") + ).withName("dbcc_classguid"), + MemoryLayout.sequenceLayout(1, Constants$root.C_SHORT$LAYOUT).withName("dbcc_name"), + MemoryLayout.paddingLayout(16) + ).withName("_DEV_BROADCAST_DEVICEINTERFACE_W"); + public static MemoryLayout $LAYOUT() { + return _DEV_BROADCAST_DEVICEINTERFACE_W.$struct$LAYOUT; + } + static final VarHandle dbcc_size$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("dbcc_size")); + public static VarHandle dbcc_size$VH() { + return _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$VH; + } + public static int dbcc_size$get(MemorySegment seg) { + return (int)_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$VH.get(seg); + } + public static void dbcc_size$set( MemorySegment seg, int x) { + _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$VH.set(seg, x); + } + public static int dbcc_size$get(MemorySegment seg, long index) { + return (int)_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$VH.get(seg.asSlice(index*sizeof())); + } + public static void dbcc_size$set(MemorySegment seg, long index, int x) { + _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle dbcc_devicetype$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("dbcc_devicetype")); + public static VarHandle dbcc_devicetype$VH() { + return _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$VH; + } + public static int dbcc_devicetype$get(MemorySegment seg) { + return (int)_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$VH.get(seg); + } + public static void dbcc_devicetype$set( MemorySegment seg, int x) { + _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$VH.set(seg, x); + } + public static int dbcc_devicetype$get(MemorySegment seg, long index) { + return (int)_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$VH.get(seg.asSlice(index*sizeof())); + } + public static void dbcc_devicetype$set(MemorySegment seg, long index, int x) { + _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle dbcc_reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("dbcc_reserved")); + public static VarHandle dbcc_reserved$VH() { + return _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_reserved$VH; + } + public static int dbcc_reserved$get(MemorySegment seg) { + return (int)_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_reserved$VH.get(seg); + } + public static void dbcc_reserved$set( MemorySegment seg, int x) { + _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_reserved$VH.set(seg, x); + } + public static int dbcc_reserved$get(MemorySegment seg, long index) { + return (int)_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_reserved$VH.get(seg.asSlice(index*sizeof())); + } + public static void dbcc_reserved$set(MemorySegment seg, long index, int x) { + _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_reserved$VH.set(seg.asSlice(index*sizeof()), x); + } + public static MemorySegment dbcc_classguid$slice(MemorySegment seg) { + return seg.asSlice(12, 16); + } + public static MemorySegment dbcc_name$slice(MemorySegment seg) { + return seg.asSlice(28, 2); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java new file mode 100644 index 00000000..85d5840e --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java @@ -0,0 +1,73 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.user32; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class _DEV_BROADCAST_HDR { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_LONG$LAYOUT.withName("dbch_size"), + Constants$root.C_LONG$LAYOUT.withName("dbch_devicetype"), + Constants$root.C_LONG$LAYOUT.withName("dbch_reserved") + ).withName("_DEV_BROADCAST_HDR"); + public static MemoryLayout $LAYOUT() { + return _DEV_BROADCAST_HDR.$struct$LAYOUT; + } + static final VarHandle dbch_size$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("dbch_size")); + public static VarHandle dbch_size$VH() { + return _DEV_BROADCAST_HDR.dbch_size$VH; + } + public static int dbch_size$get(MemorySegment seg) { + return (int)_DEV_BROADCAST_HDR.dbch_size$VH.get(seg); + } + public static void dbch_size$set( MemorySegment seg, int x) { + _DEV_BROADCAST_HDR.dbch_size$VH.set(seg, x); + } + public static int dbch_size$get(MemorySegment seg, long index) { + return (int)_DEV_BROADCAST_HDR.dbch_size$VH.get(seg.asSlice(index*sizeof())); + } + public static void dbch_size$set(MemorySegment seg, long index, int x) { + _DEV_BROADCAST_HDR.dbch_size$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle dbch_devicetype$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("dbch_devicetype")); + public static VarHandle dbch_devicetype$VH() { + return _DEV_BROADCAST_HDR.dbch_devicetype$VH; + } + public static int dbch_devicetype$get(MemorySegment seg) { + return (int)_DEV_BROADCAST_HDR.dbch_devicetype$VH.get(seg); + } + public static void dbch_devicetype$set( MemorySegment seg, int x) { + _DEV_BROADCAST_HDR.dbch_devicetype$VH.set(seg, x); + } + public static int dbch_devicetype$get(MemorySegment seg, long index) { + return (int)_DEV_BROADCAST_HDR.dbch_devicetype$VH.get(seg.asSlice(index*sizeof())); + } + public static void dbch_devicetype$set(MemorySegment seg, long index, int x) { + _DEV_BROADCAST_HDR.dbch_devicetype$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle dbch_reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("dbch_reserved")); + public static VarHandle dbch_reserved$VH() { + return _DEV_BROADCAST_HDR.dbch_reserved$VH; + } + public static int dbch_reserved$get(MemorySegment seg) { + return (int)_DEV_BROADCAST_HDR.dbch_reserved$VH.get(seg); + } + public static void dbch_reserved$set( MemorySegment seg, int x) { + _DEV_BROADCAST_HDR.dbch_reserved$VH.set(seg, x); + } + public static int dbch_reserved$get(MemorySegment seg, long index) { + return (int)_DEV_BROADCAST_HDR.dbch_reserved$VH.get(seg.asSlice(index*sizeof())); + } + public static void dbch_reserved$set(MemorySegment seg, long index, int x) { + _DEV_BROADCAST_HDR.dbch_reserved$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java new file mode 100644 index 00000000..f137ae31 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java @@ -0,0 +1,67 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.user32; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryAddress; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor GetMessageW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG$LAYOUT + ); + static final MethodHandle GetMessageW$MH = RuntimeHelper.downcallHandle( + "GetMessageW", + constants$0.GetMessageW$FUNC + ); + static final FunctionDescriptor RegisterDeviceNotificationW$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT + ); + static final MethodHandle RegisterDeviceNotificationW$MH = RuntimeHelper.downcallHandle( + "RegisterDeviceNotificationW", + constants$0.RegisterDeviceNotificationW$FUNC + ); + static final FunctionDescriptor DefWindowProcW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle DefWindowProcW$MH = RuntimeHelper.downcallHandle( + "DefWindowProcW", + constants$0.DefWindowProcW$FUNC + ); + static final FunctionDescriptor RegisterClassExW$FUNC = FunctionDescriptor.of(Constants$root.C_SHORT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle RegisterClassExW$MH = RuntimeHelper.downcallHandle( + "RegisterClassExW", + constants$0.RegisterClassExW$FUNC + ); + static final FunctionDescriptor CreateWindowExW$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CreateWindowExW$MH = RuntimeHelper.downcallHandle( + "CreateWindowExW", + constants$0.CreateWindowExW$FUNC + ); + static final MemoryAddress HWND_MESSAGE$ADDR = MemoryAddress.ofLong(-3L); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java new file mode 100644 index 00000000..1fad57f8 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java @@ -0,0 +1,116 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.user32; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class tagMSG { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_POINTER$LAYOUT.withName("hwnd"), + Constants$root.C_LONG$LAYOUT.withName("message"), + MemoryLayout.paddingLayout(32), + Constants$root.C_LONG_LONG$LAYOUT.withName("wParam"), + Constants$root.C_LONG_LONG$LAYOUT.withName("lParam"), + Constants$root.C_LONG$LAYOUT.withName("time"), + MemoryLayout.structLayout( + Constants$root.C_LONG$LAYOUT.withName("x"), + Constants$root.C_LONG$LAYOUT.withName("y") + ).withName("pt"), + MemoryLayout.paddingLayout(32) + ).withName("tagMSG"); + public static MemoryLayout $LAYOUT() { + return tagMSG.$struct$LAYOUT; + } + static final VarHandle hwnd$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hwnd")); + public static VarHandle hwnd$VH() { + return tagMSG.hwnd$VH; + } + public static MemoryAddress hwnd$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)tagMSG.hwnd$VH.get(seg); + } + public static void hwnd$set( MemorySegment seg, MemoryAddress x) { + tagMSG.hwnd$VH.set(seg, x); + } + public static MemoryAddress hwnd$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)tagMSG.hwnd$VH.get(seg.asSlice(index*sizeof())); + } + public static void hwnd$set(MemorySegment seg, long index, MemoryAddress x) { + tagMSG.hwnd$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle message$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("message")); + public static VarHandle message$VH() { + return tagMSG.message$VH; + } + public static int message$get(MemorySegment seg) { + return (int)tagMSG.message$VH.get(seg); + } + public static void message$set( MemorySegment seg, int x) { + tagMSG.message$VH.set(seg, x); + } + public static int message$get(MemorySegment seg, long index) { + return (int)tagMSG.message$VH.get(seg.asSlice(index*sizeof())); + } + public static void message$set(MemorySegment seg, long index, int x) { + tagMSG.message$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle wParam$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("wParam")); + public static VarHandle wParam$VH() { + return tagMSG.wParam$VH; + } + public static long wParam$get(MemorySegment seg) { + return (long)tagMSG.wParam$VH.get(seg); + } + public static void wParam$set( MemorySegment seg, long x) { + tagMSG.wParam$VH.set(seg, x); + } + public static long wParam$get(MemorySegment seg, long index) { + return (long)tagMSG.wParam$VH.get(seg.asSlice(index*sizeof())); + } + public static void wParam$set(MemorySegment seg, long index, long x) { + tagMSG.wParam$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle lParam$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("lParam")); + public static VarHandle lParam$VH() { + return tagMSG.lParam$VH; + } + public static long lParam$get(MemorySegment seg) { + return (long)tagMSG.lParam$VH.get(seg); + } + public static void lParam$set( MemorySegment seg, long x) { + tagMSG.lParam$VH.set(seg, x); + } + public static long lParam$get(MemorySegment seg, long index) { + return (long)tagMSG.lParam$VH.get(seg.asSlice(index*sizeof())); + } + public static void lParam$set(MemorySegment seg, long index, long x) { + tagMSG.lParam$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle time$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("time")); + public static VarHandle time$VH() { + return tagMSG.time$VH; + } + public static int time$get(MemorySegment seg) { + return (int)tagMSG.time$VH.get(seg); + } + public static void time$set( MemorySegment seg, int x) { + tagMSG.time$VH.set(seg, x); + } + public static int time$get(MemorySegment seg, long index) { + return (int)tagMSG.time$VH.get(seg.asSlice(index*sizeof())); + } + public static void time$set(MemorySegment seg, long index, int x) { + tagMSG.time$VH.set(seg.asSlice(index*sizeof()), x); + } + public static MemorySegment pt$slice(MemorySegment seg) { + return seg.asSlice(36, 8); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java new file mode 100644 index 00000000..9612b1a7 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java @@ -0,0 +1,226 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.user32; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class tagWNDCLASSEXW { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_LONG$LAYOUT.withName("cbSize"), + Constants$root.C_LONG$LAYOUT.withName("style"), + Constants$root.C_POINTER$LAYOUT.withName("lpfnWndProc"), + Constants$root.C_LONG$LAYOUT.withName("cbClsExtra"), + Constants$root.C_LONG$LAYOUT.withName("cbWndExtra"), + Constants$root.C_POINTER$LAYOUT.withName("hInstance"), + Constants$root.C_POINTER$LAYOUT.withName("hIcon"), + Constants$root.C_POINTER$LAYOUT.withName("hCursor"), + Constants$root.C_POINTER$LAYOUT.withName("hbrBackground"), + Constants$root.C_POINTER$LAYOUT.withName("lpszMenuName"), + Constants$root.C_POINTER$LAYOUT.withName("lpszClassName"), + Constants$root.C_POINTER$LAYOUT.withName("hIconSm") + ).withName("tagWNDCLASSEXW"); + public static MemoryLayout $LAYOUT() { + return tagWNDCLASSEXW.$struct$LAYOUT; + } + static final VarHandle cbSize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("cbSize")); + public static VarHandle cbSize$VH() { + return tagWNDCLASSEXW.cbSize$VH; + } + public static int cbSize$get(MemorySegment seg) { + return (int)tagWNDCLASSEXW.cbSize$VH.get(seg); + } + public static void cbSize$set( MemorySegment seg, int x) { + tagWNDCLASSEXW.cbSize$VH.set(seg, x); + } + public static int cbSize$get(MemorySegment seg, long index) { + return (int)tagWNDCLASSEXW.cbSize$VH.get(seg.asSlice(index*sizeof())); + } + public static void cbSize$set(MemorySegment seg, long index, int x) { + tagWNDCLASSEXW.cbSize$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle style$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("style")); + public static VarHandle style$VH() { + return tagWNDCLASSEXW.style$VH; + } + public static int style$get(MemorySegment seg) { + return (int)tagWNDCLASSEXW.style$VH.get(seg); + } + public static void style$set( MemorySegment seg, int x) { + tagWNDCLASSEXW.style$VH.set(seg, x); + } + public static int style$get(MemorySegment seg, long index) { + return (int)tagWNDCLASSEXW.style$VH.get(seg.asSlice(index*sizeof())); + } + public static void style$set(MemorySegment seg, long index, int x) { + tagWNDCLASSEXW.style$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle lpfnWndProc$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("lpfnWndProc")); + public static VarHandle lpfnWndProc$VH() { + return tagWNDCLASSEXW.lpfnWndProc$VH; + } + public static MemoryAddress lpfnWndProc$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.lpfnWndProc$VH.get(seg); + } + public static void lpfnWndProc$set( MemorySegment seg, MemoryAddress x) { + tagWNDCLASSEXW.lpfnWndProc$VH.set(seg, x); + } + public static MemoryAddress lpfnWndProc$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.lpfnWndProc$VH.get(seg.asSlice(index*sizeof())); + } + public static void lpfnWndProc$set(MemorySegment seg, long index, MemoryAddress x) { + tagWNDCLASSEXW.lpfnWndProc$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle cbClsExtra$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("cbClsExtra")); + public static VarHandle cbClsExtra$VH() { + return tagWNDCLASSEXW.cbClsExtra$VH; + } + public static int cbClsExtra$get(MemorySegment seg) { + return (int)tagWNDCLASSEXW.cbClsExtra$VH.get(seg); + } + public static void cbClsExtra$set( MemorySegment seg, int x) { + tagWNDCLASSEXW.cbClsExtra$VH.set(seg, x); + } + public static int cbClsExtra$get(MemorySegment seg, long index) { + return (int)tagWNDCLASSEXW.cbClsExtra$VH.get(seg.asSlice(index*sizeof())); + } + public static void cbClsExtra$set(MemorySegment seg, long index, int x) { + tagWNDCLASSEXW.cbClsExtra$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle cbWndExtra$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("cbWndExtra")); + public static VarHandle cbWndExtra$VH() { + return tagWNDCLASSEXW.cbWndExtra$VH; + } + public static int cbWndExtra$get(MemorySegment seg) { + return (int)tagWNDCLASSEXW.cbWndExtra$VH.get(seg); + } + public static void cbWndExtra$set( MemorySegment seg, int x) { + tagWNDCLASSEXW.cbWndExtra$VH.set(seg, x); + } + public static int cbWndExtra$get(MemorySegment seg, long index) { + return (int)tagWNDCLASSEXW.cbWndExtra$VH.get(seg.asSlice(index*sizeof())); + } + public static void cbWndExtra$set(MemorySegment seg, long index, int x) { + tagWNDCLASSEXW.cbWndExtra$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle hInstance$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hInstance")); + public static VarHandle hInstance$VH() { + return tagWNDCLASSEXW.hInstance$VH; + } + public static MemoryAddress hInstance$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hInstance$VH.get(seg); + } + public static void hInstance$set( MemorySegment seg, MemoryAddress x) { + tagWNDCLASSEXW.hInstance$VH.set(seg, x); + } + public static MemoryAddress hInstance$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hInstance$VH.get(seg.asSlice(index*sizeof())); + } + public static void hInstance$set(MemorySegment seg, long index, MemoryAddress x) { + tagWNDCLASSEXW.hInstance$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle hIcon$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hIcon")); + public static VarHandle hIcon$VH() { + return tagWNDCLASSEXW.hIcon$VH; + } + public static MemoryAddress hIcon$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hIcon$VH.get(seg); + } + public static void hIcon$set( MemorySegment seg, MemoryAddress x) { + tagWNDCLASSEXW.hIcon$VH.set(seg, x); + } + public static MemoryAddress hIcon$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hIcon$VH.get(seg.asSlice(index*sizeof())); + } + public static void hIcon$set(MemorySegment seg, long index, MemoryAddress x) { + tagWNDCLASSEXW.hIcon$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle hCursor$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hCursor")); + public static VarHandle hCursor$VH() { + return tagWNDCLASSEXW.hCursor$VH; + } + public static MemoryAddress hCursor$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hCursor$VH.get(seg); + } + public static void hCursor$set( MemorySegment seg, MemoryAddress x) { + tagWNDCLASSEXW.hCursor$VH.set(seg, x); + } + public static MemoryAddress hCursor$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hCursor$VH.get(seg.asSlice(index*sizeof())); + } + public static void hCursor$set(MemorySegment seg, long index, MemoryAddress x) { + tagWNDCLASSEXW.hCursor$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle hbrBackground$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hbrBackground")); + public static VarHandle hbrBackground$VH() { + return tagWNDCLASSEXW.hbrBackground$VH; + } + public static MemoryAddress hbrBackground$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hbrBackground$VH.get(seg); + } + public static void hbrBackground$set( MemorySegment seg, MemoryAddress x) { + tagWNDCLASSEXW.hbrBackground$VH.set(seg, x); + } + public static MemoryAddress hbrBackground$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hbrBackground$VH.get(seg.asSlice(index*sizeof())); + } + public static void hbrBackground$set(MemorySegment seg, long index, MemoryAddress x) { + tagWNDCLASSEXW.hbrBackground$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle lpszMenuName$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("lpszMenuName")); + public static VarHandle lpszMenuName$VH() { + return tagWNDCLASSEXW.lpszMenuName$VH; + } + public static MemoryAddress lpszMenuName$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.lpszMenuName$VH.get(seg); + } + public static void lpszMenuName$set( MemorySegment seg, MemoryAddress x) { + tagWNDCLASSEXW.lpszMenuName$VH.set(seg, x); + } + public static MemoryAddress lpszMenuName$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.lpszMenuName$VH.get(seg.asSlice(index*sizeof())); + } + public static void lpszMenuName$set(MemorySegment seg, long index, MemoryAddress x) { + tagWNDCLASSEXW.lpszMenuName$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle lpszClassName$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("lpszClassName")); + public static VarHandle lpszClassName$VH() { + return tagWNDCLASSEXW.lpszClassName$VH; + } + public static MemoryAddress lpszClassName$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.lpszClassName$VH.get(seg); + } + public static void lpszClassName$set( MemorySegment seg, MemoryAddress x) { + tagWNDCLASSEXW.lpszClassName$VH.set(seg, x); + } + public static MemoryAddress lpszClassName$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.lpszClassName$VH.get(seg.asSlice(index*sizeof())); + } + public static void lpszClassName$set(MemorySegment seg, long index, MemoryAddress x) { + tagWNDCLASSEXW.lpszClassName$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle hIconSm$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hIconSm")); + public static VarHandle hIconSm$VH() { + return tagWNDCLASSEXW.hIconSm$VH; + } + public static MemoryAddress hIconSm$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hIconSm$VH.get(seg); + } + public static void hIconSm$set( MemorySegment seg, MemoryAddress x) { + tagWNDCLASSEXW.hIconSm$VH.set(seg, x); + } + public static MemoryAddress hIconSm$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hIconSm$VH.get(seg.asSlice(index*sizeof())); + } + public static void hIconSm$set(MemorySegment seg, long index, MemoryAddress x) { + tagWNDCLASSEXW.hIconSm$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + From 81aafed17b49fd851bbaa1105c75b46d88afa380 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 28 Aug 2022 23:07:15 +0200 Subject: [PATCH 018/433] Windows: USBHelper cleanup --- .../net/codecrete/usb/windows/USBHelper.java | 146 ++++++++---------- 1 file changed, 64 insertions(+), 82 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java index 162a680b..68d25d54 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java @@ -21,8 +21,8 @@ /** * USB constants and struct *

- * Mainly used to work around an alignment problem with the generated - * USB_NODE_CONNECTION_INFORMATION_EX struct. + * Mainly used to work around an alignment problem with the generated + * USB_NODE_CONNECTION_INFORMATION_EX struct. *

*/ public class USBHelper { @@ -31,99 +31,81 @@ public class USBHelper { public static final short USB_STRING_DESCRIPTOR_TYPE = 0x03; - public static final GroupLayout USB_NODE_CONNECTION_INFORMATION_EX$Struct; - public static final VarHandle USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex; - public static final long USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset; - public static final VarHandle USB_NODE_CONNECTION_INFORMATION_EX_CurrentConfigurationValue; + // typedef struct _USB_NODE_CONNECTION_INFORMATION_EX { + // ULONG ConnectionIndex; /* INPUT */ + // /* usb device descriptor returned by this device + // during enumeration */ + // USB_DEVICE_DESCRIPTOR DeviceDescriptor;/* OUTPUT */ + // UCHAR CurrentConfigurationValue;/* OUTPUT */ + // /* values for the speed field are defined in USB200.h */ + // UCHAR Speed;/* OUTPUT */ + // BOOLEAN DeviceIsHub;/* OUTPUT */ + // USHORT DeviceAddress;/* OUTPUT */ + // ULONG NumberOfOpenPipes;/* OUTPUT */ + // USB_CONNECTION_STATUS ConnectionStatus;/* OUTPUT */ + // USB_PIPE_INFO PipeList[0];/* OUTPUT */ + //} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; + public static final GroupLayout USB_NODE_CONNECTION_INFORMATION_EX$Struct = structLayout( + JAVA_INT.withName("ConnectionIndex"), + USBDescriptors.Device$Struct.withName("DeviceDescriptor"), + JAVA_BYTE.withName("CurrentConfigurationValue"), + JAVA_BYTE.withName("Speed"), + JAVA_BYTE.withName("DeviceIsHub"), + JAVA_SHORT.withName("DeviceAddress"), + JAVA_INT.withName("NumberOfOpenPipes"), + JAVA_INT.withName("ConnectionStatus") + // USB_PIPE_INFO PipeList[0] + ); + public static final VarHandle USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex + = USB_NODE_CONNECTION_INFORMATION_EX$Struct.varHandle(groupElement("ConnectionIndex")); + public static final long USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset + = USB_NODE_CONNECTION_INFORMATION_EX$Struct.byteOffset(groupElement("DeviceDescriptor")); + public static final VarHandle USB_NODE_CONNECTION_INFORMATION_EX_CurrentConfigurationValue + = USB_NODE_CONNECTION_INFORMATION_EX$Struct.varHandle(groupElement("CurrentConfigurationValue")); - public static final GroupLayout USB_DESCRIPTOR_REQUEST$Struct; - public static final VarHandle USB_DESCRIPTOR_REQUEST_ConnectionIndex; - public static final long USB_DESCRIPTOR_REQUEST_SetupPacket$Offset; - public static final long USB_DESCRIPTOR_REQUEST_Data$Offset; + // typedef struct _USB_DESCRIPTOR_REQUEST { + // ULONG ConnectionIndex; + // struct { + // UCHAR bmRequest; + // UCHAR bRequest; + // USHORT wValue; + // USHORT wIndex; + // USHORT wLength; + // } SetupPacket; + // UCHAR Data[0]; + //} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST; + public static final GroupLayout USB_DESCRIPTOR_REQUEST$Struct = structLayout( + JAVA_INT.withName("ConnectionIndex"), + USBStructs.SetupPacket$Struct.withName("SetupPacket") + ); + public static final VarHandle USB_DESCRIPTOR_REQUEST_ConnectionIndex = USB_DESCRIPTOR_REQUEST$Struct.varHandle(groupElement("ConnectionIndex")); + public static final long USB_DESCRIPTOR_REQUEST_SetupPacket$Offset = USB_DESCRIPTOR_REQUEST$Struct.byteOffset(groupElement("SetupPacket")); + public static final long USB_DESCRIPTOR_REQUEST_Data$Offset = USB_DESCRIPTOR_REQUEST$Struct.byteSize(); + + // typedef struct _USB_STRING_DESCRIPTOR { + // UCHAR bLength; + // UCHAR bDescriptorType; + // WCHAR bString[1]; + //} USB_STRING_DESCRIPTOR, *PUSB_STRING_DESCRIPTOR; + public static final GroupLayout USB_STRING_DESCRIPTOR$Struct = structLayout( + JAVA_BYTE.withName("bLength"), + JAVA_BYTE.withName("bDescriptorType") + ); + public static final VarHandle USB_STRING_DESCRIPTOR_bLength = USB_STRING_DESCRIPTOR$Struct.varHandle(groupElement("bLength")); + public static final VarHandle USB_STRING_DESCRIPTOR_bDescriptorType = USB_STRING_DESCRIPTOR$Struct.varHandle(groupElement("bDescriptorType")); + public static final long USB_STRING_DESCRIPTOR_bString$Offset = USB_STRING_DESCRIPTOR$Struct.byteSize(); - public static final GroupLayout USB_STRING_DESCRIPTOR$Struct; - public static final VarHandle USB_STRING_DESCRIPTOR_bLength; - public static final VarHandle USB_STRING_DESCRIPTOR_bDescriptorType; - public static final long USB_STRING_DESCRIPTOR_bString$Offset; // A5DCBF10-6530-11D2-901F-00C04FB951ED public static final MemorySegment GUID_DEVINTERFACE_USB_DEVICE = Win.CreateGUID(0xA5DCBF10, (short) 0x6530, (short) 0x11D2, (byte) 0x90, (byte) 0x1F, (byte) 0x00, (byte) 0xC0, (byte) 0x4F, (byte) 0xB9, (byte) 0x51, (byte) 0xED); // f18a0e88-c30c-11d0-8815-00a0c906bed8 - public static final MemorySegment GUID_DEVINTERFACE_USB_HUB = Win.CreateGUID(0xf18a0e88, (short) 0xc30c, (short) 0x11d0, (byte) 0x88, (byte) 0x15, (byte) 0x00, (byte) 0xa0, (byte) 0xc9, (byte) 0x06, (byte) 0xbe, (byte) 0xd8); - static { - - // typedef struct _USB_NODE_CONNECTION_INFORMATION_EX { - // ULONG ConnectionIndex; /* INPUT */ - // /* usb device descriptor returned by this device - // during enumeration */ - // USB_DEVICE_DESCRIPTOR DeviceDescriptor;/* OUTPUT */ - // UCHAR CurrentConfigurationValue;/* OUTPUT */ - // /* values for the speed field are defined in USB200.h */ - // UCHAR Speed;/* OUTPUT */ - // BOOLEAN DeviceIsHub;/* OUTPUT */ - // USHORT DeviceAddress;/* OUTPUT */ - // ULONG NumberOfOpenPipes;/* OUTPUT */ - // USB_CONNECTION_STATUS ConnectionStatus;/* OUTPUT */ - // USB_PIPE_INFO PipeList[0];/* OUTPUT */ - //} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; - USB_NODE_CONNECTION_INFORMATION_EX$Struct = structLayout( - JAVA_INT.withName("ConnectionIndex"), - USBDescriptors.Device$Struct.withName("DeviceDescriptor"), - JAVA_BYTE.withName("CurrentConfigurationValue"), - JAVA_BYTE.withName("Speed"), - JAVA_BYTE.withName("DeviceIsHub"), - JAVA_SHORT.withName("DeviceAddress"), - JAVA_INT.withName("NumberOfOpenPipes"), - JAVA_INT.withName("ConnectionStatus") - // USB_PIPE_INFO PipeList[0] - ); assert USB_NODE_CONNECTION_INFORMATION_EX$Struct.byteSize() == 35; - - USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex - = USB_NODE_CONNECTION_INFORMATION_EX$Struct.varHandle(groupElement("ConnectionIndex")); - USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset - = USB_NODE_CONNECTION_INFORMATION_EX$Struct.byteOffset(groupElement("DeviceDescriptor")); - USB_NODE_CONNECTION_INFORMATION_EX_CurrentConfigurationValue - = USB_NODE_CONNECTION_INFORMATION_EX$Struct.varHandle(groupElement("CurrentConfigurationValue")); - - // typedef struct _USB_DESCRIPTOR_REQUEST { - // ULONG ConnectionIndex; - // struct { - // UCHAR bmRequest; - // UCHAR bRequest; - // USHORT wValue; - // USHORT wIndex; - // USHORT wLength; - // } SetupPacket; - // UCHAR Data[0]; - //} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST; - USB_DESCRIPTOR_REQUEST$Struct = structLayout( - JAVA_INT.withName("ConnectionIndex"), - USBStructs.SetupPacket$Struct.withName("SetupPacket") - ); - - USB_DESCRIPTOR_REQUEST_ConnectionIndex = USB_DESCRIPTOR_REQUEST$Struct.varHandle(groupElement("ConnectionIndex")); - USB_DESCRIPTOR_REQUEST_SetupPacket$Offset = USB_DESCRIPTOR_REQUEST$Struct.byteOffset(groupElement("SetupPacket")); - USB_DESCRIPTOR_REQUEST_Data$Offset = USB_DESCRIPTOR_REQUEST$Struct.byteSize(); - - // typedef struct _USB_STRING_DESCRIPTOR { - // UCHAR bLength; - // UCHAR bDescriptorType; - // WCHAR bString[1]; - //} USB_STRING_DESCRIPTOR, *PUSB_STRING_DESCRIPTOR; - USB_STRING_DESCRIPTOR$Struct = structLayout( - JAVA_BYTE.withName("bLength"), - JAVA_BYTE.withName("bDescriptorType") - ); - USB_STRING_DESCRIPTOR_bLength = USB_STRING_DESCRIPTOR$Struct.varHandle(groupElement("bLength")); - USB_STRING_DESCRIPTOR_bDescriptorType = USB_STRING_DESCRIPTOR$Struct.varHandle(groupElement("bDescriptorType")); - USB_STRING_DESCRIPTOR_bString$Offset = USB_STRING_DESCRIPTOR$Struct.byteSize(); } } From e4d4101823b0623872ca03d2223e55a04f457274 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 29 Aug 2022 19:05:27 +0200 Subject: [PATCH 019/433] macOS: maintain list of connected USB devices --- .../usb/common/USBDeviceRegistry.java | 25 +- .../usb/linux/LinuxUSBDeviceRegistry.java | 2 +- .../usb/macos/MacosUSBDeviceInfo.java | 4 + .../usb/macos/MacosUSBDeviceRegistry.java | 284 ++++++++++-------- .../usb/windows/WindowsUSBDeviceRegistry.java | 2 +- .../codecrete/usb/sample/MonitorDevices.java | 6 +- 6 files changed, 193 insertions(+), 130 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index 685797d0..215e81ca 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -15,10 +15,27 @@ /** * USB device registry. */ -public interface USBDeviceRegistry { - List getAllDevices(); +public abstract class USBDeviceRegistry { + protected Consumer onDeviceConnectedHandler; + protected Consumer onDeviceDisconnectedHandler; - void setOnDeviceConnected(Consumer handler); + public abstract List getAllDevices(); - void setOnDeviceDisconnected(Consumer handler); + public void setOnDeviceConnected(Consumer handler) { + onDeviceConnectedHandler = handler; + } + + public void setOnDeviceDisconnected(Consumer handler) { + onDeviceDisconnectedHandler = handler; + } + + protected void emitOnDeviceConnected(USBDeviceInfo device) { + if (onDeviceConnectedHandler != null) + onDeviceConnectedHandler.accept(device); + } + + protected void emitOnDeviceDisconnected(USBDeviceInfo device) { + if (onDeviceDisconnectedHandler != null) + onDeviceDisconnectedHandler.accept(device); + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index c786705a..8bb8d45d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -23,7 +23,7 @@ /** * USB implementation for Linux */ -public class LinuxUSBDeviceRegistry implements USBDeviceRegistry { +public class LinuxUSBDeviceRegistry extends USBDeviceRegistry { @Override public List getAllDevices() { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceInfo.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceInfo.java index 877f3296..f988475b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceInfo.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceInfo.java @@ -26,4 +26,8 @@ public class MacosUSBDeviceInfo extends USBDeviceInfoImpl { public USBDevice open() { return new MacosUSBDevice(id, this); } + + Object getId() { + return this.id; + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 407757dc..30990f59 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -10,50 +10,48 @@ import net.codecrete.usb.USBDeviceInfo; import net.codecrete.usb.common.USBDeviceRegistry; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryAddress; -import java.lang.foreign.MemorySession; +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.List; -import java.util.function.Consumer; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.*; -public class MacosUSBDeviceRegistry implements USBDeviceRegistry { - - private Consumer onDeviceConnectedHandler; - private Consumer onDeviceDisconnectedHandler; - private boolean isMonitorThreadStarted; - private boolean isMonitoringReady; +/** + * MacOS implementation of USB device registry. + *

+ * This singleton class maintains a list of connected USB devices. + * It start a background thread monitoring the USB devices that are + * connected and disconnected. + *

+ *

+ * The background thread also creates the initial devices list as + * setting up the notifications will initially deliver the connected + * devices anyway. + *

+ */ +public class MacosUSBDeviceRegistry extends USBDeviceRegistry { + + private volatile List devices; + private final Lock lock = new ReentrantLock(); + private final Condition enumerationComplete = lock.newCondition(); + + public MacosUSBDeviceRegistry() { + startDeviceMonitor(); + } public List getAllDevices() { - - try (var session = MemorySession.openConfined()) { - - final int entry = IoKit.IORegistryGetRootEntry(IoKit.kIOMasterPortDefault); - if (entry == 0) - throw new RuntimeException("IORegistryGetRootEntry failed"); - session.addCloseAction(() -> IoKit.IOObjectRelease(entry)); - - // create an iterator for USB devices - var iterHolder = session.allocate(JAVA_INT); - // TODO: passing 'entry' as the first argument does not work - why? - int ret = IoKit.IORegistryCreateIterator(0, IoKit.kIOUSBPlane, IoKit.kIORegistryIterateRecursively, iterHolder); - final var iter = iterHolder.get(JAVA_INT, 0); - if (ret != 0) - throw new RuntimeException("IORegistryCreateIterator failed"); - session.addCloseAction(() -> IoKit.IOObjectRelease(iter)); - - return iterateDevices(iter, false); - } + return devices; } /** - * Process the iterator and return a list of devices ({@link USBDeviceInfo}). + * Process the device iterator and return a list of devices ({@link USBDeviceInfo}). * * @param iterator iterator * @param isDisconnected flag is the iterator is for disconnected devices @@ -95,79 +93,87 @@ private List iterateDevices(int iterator, boolean isDisconnected) return result; } - private synchronized void startDeviceMonitor() { - if (isMonitorThreadStarted) - return; + private USBDeviceInfo createDeviceInfo(long entryID, int service) { - isMonitorThreadStarted = true; + Integer vendorId = IoKitHelper.GetPropertyInt(service, "idVendor"); + Integer productId = IoKitHelper.GetPropertyInt(service, "idProduct"); + String manufacturer = IoKitHelper.GetPropertyString(service, "kUSBVendorString"); + String product = IoKitHelper.GetPropertyString(service, "kUSBProductString"); + String serial = IoKitHelper.GetPropertyString(service, "kUSBSerialNumberString"); + Integer classCode = IoKitHelper.GetPropertyInt(service, "bDeviceClass"); + Integer subclassCode = IoKitHelper.GetPropertyInt(service, "bDeviceSubClass"); + Integer protocolCode = IoKitHelper.GetPropertyInt(service, "bDeviceProtocol"); + + if (vendorId == null || productId == null || classCode == null || subclassCode == null || protocolCode == null) + return null; + + return new MacosUSBDeviceInfo(entryID, vendorId, productId, manufacturer, product, serial, classCode, subclassCode, protocolCode); + } + + /** + * Starts the background thread and waits until the first device enumeration is complete. + */ + private void startDeviceMonitor() { + // start new thread Thread t = new Thread(this::monitorDevices, "USB device monitor"); + t.setDaemon(true); t.start(); + + // wait for initial device enumeration + lock.lock(); + try { + while (devices == null) { + enumerationComplete.awaitUninterruptibly(); + } + } finally { + lock.unlock(); + } } + /** + * Monitors the USB devices. + *

+ * This method is the core of the background thread. It runs forever and does not terminate. + *

+ */ private void monitorDevices() { + // as the method runs forever, there is no need to clean up one-time allocations try (var session = MemorySession.openConfined()) { + // setup run loop, run loop source and notification port var notifyPort = IoKit.IONotificationPortCreate(IoKit.kIOMasterPortDefault); var runLoopSource = IoKit.IONotificationPortGetRunLoopSource(notifyPort); - var runLoop = CoreFoundation.CFRunLoopGetCurrent(); CoreFoundation.CFRunLoopAddSource(runLoop, runLoopSource, IoKit.kCFRunLoopDefaultMode); - var matchingDict = IoKit.IOServiceMatching(IoKit.kIOUSBDeviceClassName); - - // create callback stub (connected devices) + // setup notification for connected devices var onDeviceConnectedMH = MethodHandles.lookup().findVirtual( - MacosUSBDeviceRegistry.class, - "onDeviceConnected", - MethodType.methodType(void.class, MemoryAddress.class, int.class) - ).bindTo(this); - var onDeviceConnectedStub = Linker.nativeLinker().upcallStub( - onDeviceConnectedMH, - FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT), - session - ); - - // Set up a notification to be called when a device is first matched by I/O Kit. - // This method consumes the matchingDict reference. - var deviceIterHolder = session.allocate(JAVA_INT); - int ret = IoKit.IOServiceAddMatchingNotification(notifyPort, IoKit.kIOFirstMatchNotification, - matchingDict, onDeviceConnectedStub, NULL, deviceIterHolder); - if (ret != 0) - throw new MacosUSBException("IOServiceAddMatchingNotification failed", ret); - var deviceConnectedIter = deviceIterHolder.get(JAVA_INT, 0); + MacosUSBDeviceRegistry.class, "onDevicesConnected", + MethodType.methodType(void.class, MemoryAddress.class, int.class)); + int deviceConnectedIter = setupNotification(session, notifyPort, IoKit.kIOFirstMatchNotification, onDeviceConnectedMH); // iterate current devices in order to arm the notifications - onDeviceConnected(NULL, deviceConnectedIter); - - // new matching dictionary for disconnected notifications - matchingDict = IoKit.IOServiceMatching(IoKit.kIOUSBDeviceClassName); + devices = iterateDevices(deviceConnectedIter, false); + + // signal completion of initial device enumeration + lock.lock(); + try { + enumerationComplete.signalAll(); + } finally { + lock.unlock(); + } - // create callback stub (connected devices) + // setup notification for disconnected devices var onDeviceDisconnectedMH = MethodHandles.lookup().findVirtual( - MacosUSBDeviceRegistry.class, - "onDeviceDisconnected", - MethodType.methodType(void.class, MemoryAddress.class, int.class) - ).bindTo(this); - var onDeviceDisconnectedStub = Linker.nativeLinker().upcallStub( - onDeviceDisconnectedMH, - FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT), - session - ); - - // Set up a notification to be called when a device is terminated by I/O Kit. - // This method consumes the matchingDict reference. - deviceIterHolder.set(JAVA_INT, 0, 0); - ret = IoKit.IOServiceAddMatchingNotification(notifyPort, IoKit.kIOTerminatedNotification, - matchingDict, onDeviceDisconnectedStub, NULL, deviceIterHolder); - if (ret != 0) - throw new MacosUSBException("IOServiceAddMatchingNotification (2) failed", ret); - var deviceDisconnectedIter = deviceIterHolder.get(JAVA_INT, 0); + MacosUSBDeviceRegistry.class, "onDevicesDisconnected", + MethodType.methodType(void.class, MemoryAddress.class, int.class)); + int deviceDisconnectedIter = setupNotification(session, notifyPort, IoKit.kIOTerminatedNotification, onDeviceDisconnectedMH); // iterate current devices in order to arm the notifications - onDeviceDisconnected(NULL, deviceDisconnectedIter); + onDevicesDisconnected(NULL, deviceDisconnectedIter); - isMonitoringReady = true; + // loop forever CoreFoundation.CFRunLoopRun(); } catch (NoSuchMethodException | IllegalAccessException e) { @@ -175,60 +181,92 @@ private void monitorDevices() { } } - private void onDeviceConnected(MemoryAddress ignoredRefCon, int iterator) { - var devices = iterateDevices(iterator, false); - if (onDeviceConnectedHandler == null || !isMonitoringReady) - return; + private int setupNotification(MemorySession session, MemoryAddress notifyPort, MemorySegment notificationType, MethodHandle callback) + throws NoSuchMethodException, IllegalAccessException { - for (var device : devices) - onDeviceConnectedHandler.accept(device); - } + // new matching dictionary for (dis)connected device notifications + MemoryAddress matchingDict = IoKit.IOServiceMatching(IoKit.kIOUSBDeviceClassName); - private void onDeviceDisconnected(MemoryAddress ignoredRefCon, int iterator) { - var devices = iterateDevices(iterator, true); - if (onDeviceDisconnectedHandler == null || !isMonitoringReady) - return; + // create callback stub + var onDeviceCallbackStub = Linker.nativeLinker().upcallStub( + callback.bindTo(this), + FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT), + session + ); - for (var device : devices) - onDeviceDisconnectedHandler.accept(device); - } + // Set up a notification to be called when a device is first matched / terminated by I/O Kit. + // This method consumes the matchingDict reference. + var deviceIterHolder = session.allocate(JAVA_INT); + int ret = IoKit.IOServiceAddMatchingNotification(notifyPort, notificationType, + matchingDict, onDeviceCallbackStub, NULL, deviceIterHolder); + if (ret != 0) + throw new MacosUSBException("IOServiceAddMatchingNotification failed", ret); - private USBDeviceInfo createDeviceInfo(long entryID, int service) { + return deviceIterHolder.get(JAVA_INT, 0); + } - Integer vendorId = IoKitHelper.GetPropertyInt(service, "idVendor"); - Integer productId = IoKitHelper.GetPropertyInt(service, "idProduct"); - String manufacturer = IoKitHelper.GetPropertyString(service, "kUSBVendorString"); - String product = IoKitHelper.GetPropertyString(service, "kUSBProductString"); - String serial = IoKitHelper.GetPropertyString(service, "kUSBSerialNumberString"); - Integer classCode = IoKitHelper.GetPropertyInt(service, "bDeviceClass"); - Integer subclassCode = IoKitHelper.GetPropertyInt(service, "bDeviceSubClass"); - Integer protocolCode = IoKitHelper.GetPropertyInt(service, "bDeviceProtocol"); + /** + * Callback function for monitoring connected USB devices. + *

+ * This method is used in an upcall from native code. + *

+ * @param ignoredRefCon ignored parameter + * @param iterator device iterator + */ + private void onDevicesConnected(MemoryAddress ignoredRefCon, int iterator) { + // retrieve device info for connected devices + var connectedDevices = iterateDevices(iterator, false); - if (vendorId == null || productId == null || classCode == null || subclassCode == null || protocolCode == null) - return null; + // create new device list with connected devices + var newDeviceList = new ArrayList<>(devices); + newDeviceList.addAll(connectedDevices); + devices = newDeviceList; - return new MacosUSBDeviceInfo(entryID, vendorId, productId, manufacturer, product, serial, classCode, subclassCode, protocolCode); + // emit events + connectedDevices.forEach(this::emitOnDeviceConnected); } - @Override - public void setOnDeviceConnected(Consumer handler) { - if (handler == null) { - onDeviceConnectedHandler = null; - return; + /** + * Callback function for monitoring disconnected USB devices. + *

+ * This method is used in an upcall from native code. + *

+ * @param ignoredRefCon ignored parameter + * @param iterator device iterator + */ + private void onDevicesDisconnected(MemoryAddress ignoredRefCon, int iterator) { + // retrieve device info for disconnected devices + var disconnectedDevices = iterateDevices(iterator, true); + + // create new device list without the disconnected devices + var newDeviceList = new ArrayList<>(devices); + for (var device : disconnectedDevices) { + int index = findDeviceIndex(newDeviceList, device); + if (index >= 0) + newDeviceList.remove(index); } + devices = newDeviceList; - onDeviceConnectedHandler = handler; - startDeviceMonitor(); + // emit events + disconnectedDevices.forEach(this::emitOnDeviceDisconnected); } - @Override - public void setOnDeviceDisconnected(Consumer handler) { - if (handler == null) { - onDeviceDisconnectedHandler = null; - return; + /** + * Find the index of the device in the device list. + *

+ * Devices are compared by their IO registry entry ID. + *

+ * @param deviceList the device list + * @param device the device + * @return the index of the device, or -1 if it is not found + */ + private static int findDeviceIndex(List deviceList, USBDeviceInfo device) { + Object id = ((MacosUSBDeviceInfo)device).getId(); + for (int i = 0; i < deviceList.size(); i++) { + var macDevice = (MacosUSBDeviceInfo) deviceList.get(i); + if (id.equals(macDevice.getId())) + return i; } - - onDeviceDisconnectedHandler = handler; - startDeviceMonitor(); + return -1; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 0f040c5c..7e78807e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -30,7 +30,7 @@ import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.*; -public class WindowsUSBDeviceRegistry implements USBDeviceRegistry { +public class WindowsUSBDeviceRegistry extends USBDeviceRegistry { private volatile List devices; private Consumer onDeviceConnectedHandler; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java b/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java index 983c4a0a..ea152847 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java @@ -17,9 +17,13 @@ */ public class MonitorDevices { - public static void main(String[] args) { + public static void main(String[] args) throws InterruptedException { System.out.println("Monitoring USB devices..."); USB.setOnDeviceConnected((dev) -> System.out.println("Connected: " + dev.toString())); USB.setOnDeviceDisconnected((dev) -> System.out.println("Disconnected: " + dev.toString())); + + while (true) { + Thread.sleep(1000000); + } } } From 32de076bb0f53290a347a3f2fc75d157c3110110 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 29 Aug 2022 20:15:30 +0200 Subject: [PATCH 020/433] Factor out common Windows and macOS code --- .../usb/common/USBDeviceRegistry.java | 40 +++++++++ .../usb/macos/MacosUSBDeviceRegistry.java | 38 +------- .../usb/windows/WindowsUSBDeviceRegistry.java | 88 ++++++++----------- 3 files changed, 78 insertions(+), 88 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index 215e81ca..e80ada9a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -10,15 +10,23 @@ import net.codecrete.usb.USBDeviceInfo; import java.util.List; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; /** * USB device registry. */ public abstract class USBDeviceRegistry { + + protected volatile List devices; protected Consumer onDeviceConnectedHandler; protected Consumer onDeviceDisconnectedHandler; + private final Lock lock = new ReentrantLock(); + private final Condition enumerationComplete = lock.newCondition(); + public abstract List getAllDevices(); public void setOnDeviceConnected(Consumer handler) { @@ -38,4 +46,36 @@ protected void emitOnDeviceDisconnected(USBDeviceInfo device) { if (onDeviceDisconnectedHandler != null) onDeviceDisconnectedHandler.accept(device); } + + /** + * Starts the background thread and waits until the first device enumeration is complete. + */ + protected void startDeviceMonitor(Runnable monitorTask) { + // start new thread + Thread t = new Thread(monitorTask, "USB device monitor"); + t.setDaemon(true); + t.start(); + + // wait for initial device enumeration + lock.lock(); + try { + while (devices == null) { + enumerationComplete.awaitUninterruptibly(); + } + } finally { + lock.unlock(); + } + } + + /** + * Signals completion of initial device enumeration. + */ + protected void signalEnumerationComplete() { + lock.lock(); + try { + enumerationComplete.signalAll(); + } finally { + lock.unlock(); + } + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 30990f59..31f027a7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -16,9 +16,6 @@ import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.*; @@ -27,7 +24,7 @@ * MacOS implementation of USB device registry. *

* This singleton class maintains a list of connected USB devices. - * It start a background thread monitoring the USB devices that are + * It starts a background thread monitoring the USB devices being * connected and disconnected. *

*

@@ -38,12 +35,8 @@ */ public class MacosUSBDeviceRegistry extends USBDeviceRegistry { - private volatile List devices; - private final Lock lock = new ReentrantLock(); - private final Condition enumerationComplete = lock.newCondition(); - public MacosUSBDeviceRegistry() { - startDeviceMonitor(); + startDeviceMonitor(this::monitorDevices); } public List getAllDevices() { @@ -110,26 +103,6 @@ private USBDeviceInfo createDeviceInfo(long entryID, int service) { return new MacosUSBDeviceInfo(entryID, vendorId, productId, manufacturer, product, serial, classCode, subclassCode, protocolCode); } - /** - * Starts the background thread and waits until the first device enumeration is complete. - */ - private void startDeviceMonitor() { - // start new thread - Thread t = new Thread(this::monitorDevices, "USB device monitor"); - t.setDaemon(true); - t.start(); - - // wait for initial device enumeration - lock.lock(); - try { - while (devices == null) { - enumerationComplete.awaitUninterruptibly(); - } - } finally { - lock.unlock(); - } - } - /** * Monitors the USB devices. *

@@ -157,12 +130,7 @@ private void monitorDevices() { devices = iterateDevices(deviceConnectedIter, false); // signal completion of initial device enumeration - lock.lock(); - try { - enumerationComplete.signalAll(); - } finally { - lock.unlock(); - } + signalEnumerationComplete(); // setup notification for disconnected devices var onDeviceDisconnectedMH = MethodHandles.lookup().findVirtual( diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 7e78807e..c7d39cc0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -25,18 +25,24 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.function.Consumer; import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.*; +/** + * Windows implementation of USB device registry. + *

+ * This singleton class maintains a list of connected USB devices. + * It starts a background thread monitoring the USB devices being + * connected and disconnected. + *

+ *

+ * The background thread also enumerates the already present devices + * and builds the initial device list. + *

+ */ public class WindowsUSBDeviceRegistry extends USBDeviceRegistry { - private volatile List devices; - private Consumer onDeviceConnectedHandler; - private Consumer onDeviceDisconnectedHandler; - private boolean isMonitorThreadStarted; - /** * Create new instance *

@@ -44,8 +50,7 @@ public class WindowsUSBDeviceRegistry extends USBDeviceRegistry { *

*/ public WindowsUSBDeviceRegistry() { - startDeviceMonitor(); - enumeratePresentDevices(); + startDeviceMonitor(this::monitorDevices); } public List getAllDevices() { @@ -192,15 +197,6 @@ private String getStringDescriptor(Addressable hubHandle, int usbPortNumber, int } } - private synchronized void startDeviceMonitor() { - if (isMonitorThreadStarted) - return; - - isMonitorThreadStarted = true; - Thread t = new Thread(this::monitorDevices, "USB device monitor"); - t.start(); - } - private void monitorDevices() { try (var session = MemorySession.openConfined()) { @@ -244,6 +240,12 @@ private void monitorDevices() { if (notifyHandle == NULL) throw new USBException("internal error (RegisterDeviceNotificationW)", Kernel32.GetLastError()); + // initial device enumeration + enumeratePresentDevices(); + + // signal that the enumeration is complete + signalEnumerationComplete(); + // process messages var msg = session.allocate(tagMSG.$LAYOUT()); while (User32.GetMessageW(msg, hwnd, 0, 0) > 0) @@ -310,7 +312,7 @@ private void onDeviceConnected(String devicePath) { session.addCloseAction(() -> hubHandles.forEach((path, handle) -> Kernel32.CloseHandle(handle))); // check for duplicates - if (findDeviceIndex(devicePath) >= 0) + if (findDeviceIndex(devices, devicePath) >= 0) return; // create device info instance @@ -322,59 +324,39 @@ private void onDeviceConnected(String devicePath) { devices = newDeviceList; // send notification - if (onDeviceConnectedHandler == null) - return; - onDeviceConnectedHandler.accept(deviceInfo); + emitOnDeviceConnected(deviceInfo); } } private void onDeviceDisconnected(String devicePath) { - int index = findDeviceIndex(devicePath); + + // locate device to be removed + int index = findDeviceIndex(devices, devicePath); if (index < 0) return; // strange - // copy list + // copy list and remove device var deviceInfo = devices.get(index); var newDeviceList = new ArrayList<>(devices); newDeviceList.remove(index); devices = newDeviceList; // send notification - if (onDeviceDisconnectedHandler == null) - return; - onDeviceDisconnectedHandler.accept(deviceInfo); + emitOnDeviceDisconnected(deviceInfo); } - private int findDeviceIndex(String devicePath) { - if (devices == null) - return -1; - for (int i = 0; i < devices.size(); i++) { - var winInfo = (WindowsUSBDeviceInfo) devices.get(i); + /** + * Finds the index of the device with the given path in the device list + * @param deviceList the device list + * @param devicePath the device path + * @return return the index, or -1 if the device is not found + */ + private static int findDeviceIndex(List deviceList, String devicePath) { + for (int i = 0; i < deviceList.size(); i++) { + var winInfo = (WindowsUSBDeviceInfo) deviceList.get(i); if (winInfo.devicePath().equalsIgnoreCase(devicePath)) return i; } return -1; } - - @Override - public void setOnDeviceConnected(Consumer handler) { - if (handler == null) { - onDeviceConnectedHandler = null; - return; - } - - onDeviceConnectedHandler = handler; - startDeviceMonitor(); - } - - @Override - public void setOnDeviceDisconnected(Consumer handler) { - if (handler == null) { - onDeviceDisconnectedHandler = null; - return; - } - - onDeviceDisconnectedHandler = handler; - startDeviceMonitor(); - } } From 5107d490bcaa8d2ab8fb145f05239d4709ec0994 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 29 Aug 2022 21:30:14 +0200 Subject: [PATCH 021/433] Linux: convert from libsystemd to libudev --- java-does-usb/jextract/gen_linux.sh | 19 ++ .../usb/linux/LinuxUSBDeviceRegistry.java | 142 +++++++----- .../java/net/codecrete/usb/linux/Systemd.java | 140 ----------- .../usb/linux/gen/udev/Constants$root.java | 19 ++ .../usb/linux/gen/udev/RuntimeHelper.java | 217 ++++++++++++++++++ .../usb/linux/gen/udev/constants$0.java | 52 +++++ .../usb/linux/gen/udev/constants$1.java | 55 +++++ .../codecrete/usb/linux/gen/udev/udev.java | 155 +++++++++++++ 8 files changed, 600 insertions(+), 199 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/Systemd.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java diff --git a/java-does-usb/jextract/gen_linux.sh b/java-does-usb/jextract/gen_linux.sh index cfd9db19..c85990cd 100755 --- a/java-does-usb/jextract/gen_linux.sh +++ b/java-does-usb/jextract/gen_linux.sh @@ -51,3 +51,22 @@ $JEXTRACT --source --output ../src/main/java \ --include-macro USBDEVFS_CLAIMINTERFACE \ --include-macro USBDEVFS_RELEASEINTERFACE \ /usr/include/linux/usbdevice_fs.h + +# libudev.h +$JEXTRACT --source --output ../src/main/java \ + --header-class-name udev \ + --target-package net.codecrete.usb.linux.gen.udev \ + -l udev \ + --include-function udev_new \ + --include-function udev_enumerate_new \ + --include-function udev_enumerate_add_match_subsystem \ + --include-function udev_enumerate_scan_devices \ + --include-function udev_enumerate_get_list_entry \ + --include-function udev_list_entry_get_next \ + --include-function udev_list_entry_get_name \ + --include-function udev_device_new_from_syspath \ + --include-function udev_device_get_devnode \ + --include-function udev_device_get_sysattr_value \ + --include-function udev_device_unref \ + --include-function udev_enumerate_unref \ + /usr/include/libudev.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 8bb8d45d..509359f6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -9,100 +9,124 @@ import net.codecrete.usb.USBDeviceInfo; import net.codecrete.usb.common.USBDeviceRegistry; +import net.codecrete.usb.linux.gen.udev.udev; import java.lang.foreign.Addressable; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; import java.util.ArrayList; import java.util.List; -import java.util.function.Consumer; import static java.lang.foreign.MemoryAddress.NULL; -import static java.lang.foreign.ValueLayout.ADDRESS; /** - * USB implementation for Linux + * Linux implementation of USB device registry. + *

+ * This singleton class maintains a list of connected USB devices. + * It starts a background thread monitoring the USB devices being + * connected and disconnected. + *

+ *

+ * The background thread also enumerates the already present devices + * and builds the initial device list. + *

*/ public class LinuxUSBDeviceRegistry extends USBDeviceRegistry { + + private static final MemorySegment SUBSYSTEM_USB = MemorySession.global().allocateUtf8String("usb"); + + /** + * Creates a new instance. + */ + public LinuxUSBDeviceRegistry() { + enumeratePresentDevices(); + } + @Override public List getAllDevices() { + return devices; + } + private void enumeratePresentDevices() { List result = new ArrayList<>(); - try (var session = MemorySession.openConfined()) { - // create enumerator - var eHolder = session.allocate(ADDRESS); - Systemd.sd_device_enumerator_new(eHolder); - var e = eHolder.get(ADDRESS, 0); - session.addCloseAction(() -> Systemd.sd_device_enumerator_unref(e)); - - // restrict to USB devices - Systemd.sd_device_enumerator_add_match_subsystem(e, "usb", 1); - - // iterate devices - for (var dev = Systemd.sd_device_enumerator_get_device_first(e); - dev != NULL; - dev = Systemd.sd_device_enumerator_get_device_next(e) - ) { - // retrieve device attributes - String idVendor = getDeviceAttribute(dev, "idVendor"); - if (idVendor == null) - continue; - - String idProduct = getDeviceAttribute(dev, "idProduct"); - if (idProduct == null) - continue; - - String devPath = getDeviceName(dev); - if (devPath == null) - continue; - - int vendorId = Integer.parseInt(idVendor, 16); - int productId = Integer.parseInt(idProduct, 16); - - // add device to result list - result.add(new LinuxUSBDeviceInfo(devPath, vendorId, productId, - getDeviceAttribute(dev, "manufacturer"), - getDeviceAttribute(dev, "product"), - getDeviceAttribute(dev, "serial"), - 0, 0, 0)); + try (var outerSession = MemorySession.openConfined()) { + + var udevInstance = udev.udev_new(); + + // create device enumerator + var enumerate = udev.udev_enumerate_new(udevInstance); + outerSession.addCloseAction(() -> udev.udev_enumerate_unref(enumerate)); + udev.udev_enumerate_add_match_subsystem(enumerate, SUBSYSTEM_USB); + udev.udev_enumerate_scan_devices(enumerate); + + // enumerate devices + for (var entry= udev.udev_enumerate_get_list_entry(enumerate); + entry != NULL; + entry = udev.udev_list_entry_get_next(entry)) { + + try (var session = MemorySession.openConfined()) { + + var path = udev.udev_list_entry_get_name(entry); + if (path == NULL) + continue; + + // get device handle + var dev = udev.udev_device_new_from_syspath(udevInstance, path); + if (dev == NULL) + continue; + + session.addCloseAction(() -> udev.udev_device_unref(dev)); + + // retrieve device attributes + String idVendor = getDeviceAttribute(dev, "idVendor"); + if (idVendor == null) + continue; + + String idProduct = getDeviceAttribute(dev, "idProduct"); + if (idProduct == null) + continue; + + // get device path + var devPath = getDeviceName(dev); + if (devPath == null) + continue; + + int vendorId = Integer.parseInt(idVendor, 16); + int productId = Integer.parseInt(idProduct, 16); + + // add device to result list + result.add(new LinuxUSBDeviceInfo(devPath, vendorId, productId, + getDeviceAttribute(dev, "manufacturer"), + getDeviceAttribute(dev, "product"), + getDeviceAttribute(dev, "serial"), + 0, 0, 0)); + } } } - return result; + devices = result; } private static String getDeviceAttribute(Addressable device, String attribute) { try (var session = MemorySession.openConfined()) { var sysattr = session.allocateUtf8String(attribute); - var valueHolder = session.allocate(ADDRESS); - int res = Systemd.sd_device_get_sysattr_value(device, sysattr, valueHolder); - if (res != 0) + var valueAddr = udev.udev_device_get_sysattr_value(device, sysattr); + if (valueAddr == NULL) return null; - var valuePointer = valueHolder.get(ADDRESS, 0); - var value = MemorySegment.ofAddress(valuePointer, 2000, session); + var value = MemorySegment.ofAddress(valueAddr, 2000, session); return value.getUtf8String(0); } } private static String getDeviceName(Addressable device) { try (var session = MemorySession.openConfined()) { - var retHolder = session.allocate(ADDRESS); - int res = Systemd.sd_device_get_devname(device, retHolder); - if (res != 0) + var devNameAddr = udev.udev_device_get_devnode(device); + if (devNameAddr == NULL) return null; - var retPointer = retHolder.get(ADDRESS, 0); - var ret = MemorySegment.ofAddress(retPointer, 2000, session); + var ret = MemorySegment.ofAddress(devNameAddr, 2000, session); return ret.getUtf8String(0); } } - - @Override - public void setOnDeviceConnected(Consumer handler) { - } - - @Override - public void setOnDeviceDisconnected(Consumer handler) { - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/Systemd.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/Systemd.java deleted file mode 100644 index 12a2f4ca..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/Systemd.java +++ /dev/null @@ -1,140 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.linux; - -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_INT; - -/** - * Functions and data structures of systemd. - */ -public class Systemd { - - private static final MethodHandle sd_device_enumerator_new$Func; - private static final MethodHandle sd_device_enumerator_unref$Func; - private static final MethodHandle sd_device_enumerator_add_match_subsystem$Func; - private static final MethodHandle sd_device_enumerator_get_device_first$Func; - private static final MethodHandle sd_device_enumerator_get_device_next$Func; - private static final MethodHandle sd_device_get_sysattr_value$Func; - private static final MethodHandle sd_device_get_devname$Func; - - static { - var session = MemorySession.openShared(); - Linker linker = Linker.nativeLinker(); - SymbolLookup lookup = SymbolLookup.libraryLookup("libsystemd.so.0", session); - - // int sd_device_enumerator_new(sd_device_enumerator **ret); - sd_device_enumerator_new$Func = linker.downcallHandle( - lookup.lookup("sd_device_enumerator_new").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS) - ); - - // sd_device_enumerator *sd_device_enumerator_unref(sd_device_enumerator *enumerator); - sd_device_enumerator_unref$Func = linker.downcallHandle( - lookup.lookup("sd_device_enumerator_unref").get(), - FunctionDescriptor.of(ADDRESS, ADDRESS) - ); - - // int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match); - sd_device_enumerator_add_match_subsystem$Func = linker.downcallHandle( - lookup.lookup("sd_device_enumerator_add_match_subsystem").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, JAVA_INT) - ); - - // sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator); - sd_device_enumerator_get_device_first$Func = linker.downcallHandle( - lookup.lookup("sd_device_enumerator_get_device_first").get(), - FunctionDescriptor.of(ADDRESS, ADDRESS) - ); - - // sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *enumerator); - sd_device_enumerator_get_device_next$Func = linker.downcallHandle( - lookup.lookup("sd_device_enumerator_get_device_next").get(), - FunctionDescriptor.of(ADDRESS, ADDRESS) - ); - - // int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value); - sd_device_get_sysattr_value$Func = linker.downcallHandle( - lookup.lookup("sd_device_get_sysattr_value").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS) - ); - - // int sd_device_get_devname(sd_device *device, const char **ret); - sd_device_get_devname$Func = linker.downcallHandle( - lookup.lookup("sd_device_get_devname").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS) - ); - } - - // int sd_device_enumerator_new(sd_device_enumerator **ret); - public static int sd_device_enumerator_new(Addressable ret) { - try { - return (int) sd_device_enumerator_new$Func.invokeExact(ret); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // sd_device_enumerator *sd_device_enumerator_unref(sd_device_enumerator *enumerator); - public static MemoryAddress sd_device_enumerator_unref(Addressable enumerator) { - try { - return (MemoryAddress) sd_device_enumerator_unref$Func.invokeExact(enumerator); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match); - public static int sd_device_enumerator_add_match_subsystem(Addressable enumerator, String subsystem, int match) { - try (var session = MemorySession.openConfined()) { - var subsys = session.allocateUtf8String(subsystem); - return (int) sd_device_enumerator_add_match_subsystem$Func.invokeExact(enumerator, (Addressable) subsys, match); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator); - public static MemoryAddress sd_device_enumerator_get_device_first(Addressable enumerator) { - try { - return (MemoryAddress) sd_device_enumerator_get_device_first$Func.invokeExact(enumerator); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *enumerator); - public static MemoryAddress sd_device_enumerator_get_device_next(Addressable enumerator) { - try { - return (MemoryAddress) sd_device_enumerator_get_device_next$Func.invokeExact(enumerator); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value); - public static int sd_device_get_sysattr_value(Addressable device, Addressable sysattr, Addressable value) { - try { - return (int) sd_device_get_sysattr_value$Func.invokeExact(device, sysattr, value); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // int sd_device_get_devname(sd_device *device, const char **ret); - public static int sd_device_get_devname(Addressable device, Addressable ret) { - try { - return (int) sd_device_get_devname$Func.invokeExact(device, ret); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/Constants$root.java new file mode 100644 index 00000000..2a06330e --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.udev; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java new file mode 100644 index 00000000..775c0b6c --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java @@ -0,0 +1,217 @@ +package net.codecrete.usb.linux.gen.udev; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { +// System.loadLibrary("udev"); +// SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so", MemorySession.openImplicit()); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java new file mode 100644 index 00000000..a6258650 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java @@ -0,0 +1,52 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.udev; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor udev_new$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT); + static final MethodHandle udev_new$MH = RuntimeHelper.downcallHandle( + "udev_new", + constants$0.udev_new$FUNC + ); + static final FunctionDescriptor udev_list_entry_get_next$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_list_entry_get_next$MH = RuntimeHelper.downcallHandle( + "udev_list_entry_get_next", + constants$0.udev_list_entry_get_next$FUNC + ); + static final FunctionDescriptor udev_list_entry_get_name$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_list_entry_get_name$MH = RuntimeHelper.downcallHandle( + "udev_list_entry_get_name", + constants$0.udev_list_entry_get_name$FUNC + ); + static final FunctionDescriptor udev_device_unref$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_device_unref$MH = RuntimeHelper.downcallHandle( + "udev_device_unref", + constants$0.udev_device_unref$FUNC + ); + static final FunctionDescriptor udev_device_new_from_syspath$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_device_new_from_syspath$MH = RuntimeHelper.downcallHandle( + "udev_device_new_from_syspath", + constants$0.udev_device_new_from_syspath$FUNC + ); + static final FunctionDescriptor udev_device_get_devnode$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_device_get_devnode$MH = RuntimeHelper.downcallHandle( + "udev_device_get_devnode", + constants$0.udev_device_get_devnode$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java new file mode 100644 index 00000000..9340bd78 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java @@ -0,0 +1,55 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.udev; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$1 { + + static final FunctionDescriptor udev_device_get_sysattr_value$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_device_get_sysattr_value$MH = RuntimeHelper.downcallHandle( + "udev_device_get_sysattr_value", + constants$1.udev_device_get_sysattr_value$FUNC + ); + static final FunctionDescriptor udev_enumerate_unref$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_enumerate_unref$MH = RuntimeHelper.downcallHandle( + "udev_enumerate_unref", + constants$1.udev_enumerate_unref$FUNC + ); + static final FunctionDescriptor udev_enumerate_new$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_enumerate_new$MH = RuntimeHelper.downcallHandle( + "udev_enumerate_new", + constants$1.udev_enumerate_new$FUNC + ); + static final FunctionDescriptor udev_enumerate_add_match_subsystem$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_enumerate_add_match_subsystem$MH = RuntimeHelper.downcallHandle( + "udev_enumerate_add_match_subsystem", + constants$1.udev_enumerate_add_match_subsystem$FUNC + ); + static final FunctionDescriptor udev_enumerate_scan_devices$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_enumerate_scan_devices$MH = RuntimeHelper.downcallHandle( + "udev_enumerate_scan_devices", + constants$1.udev_enumerate_scan_devices$FUNC + ); + static final FunctionDescriptor udev_enumerate_get_list_entry$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_enumerate_get_list_entry$MH = RuntimeHelper.downcallHandle( + "udev_enumerate_get_list_entry", + constants$1.udev_enumerate_get_list_entry$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java new file mode 100644 index 00000000..2b6bde54 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java @@ -0,0 +1,155 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.udev; + +import java.lang.foreign.Addressable; +import java.lang.foreign.MemoryAddress; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.*; +public class udev { + + /* package-private */ udev() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static MethodHandle udev_new$MH() { + return RuntimeHelper.requireNonNull(constants$0.udev_new$MH,"udev_new"); + } + public static MemoryAddress udev_new () { + var mh$ = udev_new$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle udev_list_entry_get_next$MH() { + return RuntimeHelper.requireNonNull(constants$0.udev_list_entry_get_next$MH,"udev_list_entry_get_next"); + } + public static MemoryAddress udev_list_entry_get_next ( Addressable list_entry) { + var mh$ = udev_list_entry_get_next$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(list_entry); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle udev_list_entry_get_name$MH() { + return RuntimeHelper.requireNonNull(constants$0.udev_list_entry_get_name$MH,"udev_list_entry_get_name"); + } + public static MemoryAddress udev_list_entry_get_name ( Addressable list_entry) { + var mh$ = udev_list_entry_get_name$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(list_entry); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle udev_device_unref$MH() { + return RuntimeHelper.requireNonNull(constants$0.udev_device_unref$MH,"udev_device_unref"); + } + public static MemoryAddress udev_device_unref ( Addressable udev_device) { + var mh$ = udev_device_unref$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev_device); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle udev_device_new_from_syspath$MH() { + return RuntimeHelper.requireNonNull(constants$0.udev_device_new_from_syspath$MH,"udev_device_new_from_syspath"); + } + public static MemoryAddress udev_device_new_from_syspath ( Addressable udev, Addressable syspath) { + var mh$ = udev_device_new_from_syspath$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev, syspath); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle udev_device_get_devnode$MH() { + return RuntimeHelper.requireNonNull(constants$0.udev_device_get_devnode$MH,"udev_device_get_devnode"); + } + public static MemoryAddress udev_device_get_devnode ( Addressable udev_device) { + var mh$ = udev_device_get_devnode$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev_device); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle udev_device_get_sysattr_value$MH() { + return RuntimeHelper.requireNonNull(constants$1.udev_device_get_sysattr_value$MH,"udev_device_get_sysattr_value"); + } + public static MemoryAddress udev_device_get_sysattr_value ( Addressable udev_device, Addressable sysattr) { + var mh$ = udev_device_get_sysattr_value$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev_device, sysattr); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle udev_enumerate_unref$MH() { + return RuntimeHelper.requireNonNull(constants$1.udev_enumerate_unref$MH,"udev_enumerate_unref"); + } + public static MemoryAddress udev_enumerate_unref ( Addressable udev_enumerate) { + var mh$ = udev_enumerate_unref$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev_enumerate); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle udev_enumerate_new$MH() { + return RuntimeHelper.requireNonNull(constants$1.udev_enumerate_new$MH,"udev_enumerate_new"); + } + public static MemoryAddress udev_enumerate_new ( Addressable udev) { + var mh$ = udev_enumerate_new$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle udev_enumerate_add_match_subsystem$MH() { + return RuntimeHelper.requireNonNull(constants$1.udev_enumerate_add_match_subsystem$MH,"udev_enumerate_add_match_subsystem"); + } + public static int udev_enumerate_add_match_subsystem ( Addressable udev_enumerate, Addressable subsystem) { + var mh$ = udev_enumerate_add_match_subsystem$MH(); + try { + return (int)mh$.invokeExact(udev_enumerate, subsystem); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle udev_enumerate_scan_devices$MH() { + return RuntimeHelper.requireNonNull(constants$1.udev_enumerate_scan_devices$MH,"udev_enumerate_scan_devices"); + } + public static int udev_enumerate_scan_devices ( Addressable udev_enumerate) { + var mh$ = udev_enumerate_scan_devices$MH(); + try { + return (int)mh$.invokeExact(udev_enumerate); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle udev_enumerate_get_list_entry$MH() { + return RuntimeHelper.requireNonNull(constants$1.udev_enumerate_get_list_entry$MH,"udev_enumerate_get_list_entry"); + } + public static MemoryAddress udev_enumerate_get_list_entry ( Addressable udev_enumerate) { + var mh$ = udev_enumerate_get_list_entry$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev_enumerate); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } +} + + From 7cf90aea493d4506a00193cc034c70e5a1c8211c Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 29 Aug 2022 23:26:44 +0200 Subject: [PATCH 022/433] Linux: USB device monitoring --- java-does-usb/jextract/gen_linux.sh | 16 ++ .../usb/common/USBDeviceInfoImpl.java | 4 + .../usb/common/USBDeviceRegistry.java | 48 ++++ .../usb/linux/LinuxUSBDeviceInfo.java | 4 + .../usb/linux/LinuxUSBDeviceRegistry.java | 181 ++++++++++++--- .../usb/linux/gen/select/Constants$root.java | 19 ++ .../usb/linux/gen/select/RuntimeHelper.java | 216 ++++++++++++++++++ .../usb/linux/gen/select/constants$0.java | 22 ++ .../usb/linux/gen/select/select.java | 36 +++ .../usb/linux/gen/udev/constants$0.java | 8 +- .../usb/linux/gen/udev/constants$1.java | 50 ++-- .../usb/linux/gen/udev/constants$2.java | 56 +++++ .../usb/linux/gen/udev/constants$3.java | 18 ++ .../codecrete/usb/linux/gen/udev/udev.java | 89 +++++++- .../usb/windows/WindowsUSBDeviceInfo.java | 4 - .../usb/windows/WindowsUSBDeviceRegistry.java | 44 +--- 16 files changed, 715 insertions(+), 100 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/select.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$2.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$3.java diff --git a/java-does-usb/jextract/gen_linux.sh b/java-does-usb/jextract/gen_linux.sh index c85990cd..55d983ba 100755 --- a/java-does-usb/jextract/gen_linux.sh +++ b/java-does-usb/jextract/gen_linux.sh @@ -5,6 +5,7 @@ JEXTRACT=../../../jextract/build/jextract/bin/jextract # sd-device.h (install libsystemd-dev if file is missing) # Error: /usr/include/inttypes.h:290:8: error: unknown type name 'intmax_t' #$JEXTRACT --source --output ../src/main/java \ +#$JEXTRACT --source --output ../src/main/java \ # --header-class-name sd_device \ # --target-package net.codecrete.usb.linux.gen.sd-device # /usr/include/systemd/sd-device.h @@ -69,4 +70,19 @@ $JEXTRACT --source --output ../src/main/java \ --include-function udev_device_get_sysattr_value \ --include-function udev_device_unref \ --include-function udev_enumerate_unref \ + --include-function udev_monitor_new_from_netlink \ + --include-function udev_monitor_enable_receiving \ + --include-function udev_monitor_filter_add_match_subsystem_devtype \ + --include-function udev_monitor_receive_device \ + --include-function udev_device_get_action \ + --include-function udev_device_get_devtype \ + --include-function udev_monitor_get_fd \ /usr/include/libudev.h + +# select.h +$JEXTRACT --source --output ../src/main/java \ + --header-class-name select \ + --target-package net.codecrete.usb.linux.gen.select \ + --include-function select \ + --include-macro FD_SETSIZE \ + /usr/include/x86_64-linux-gnu/sys/select.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceInfoImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceInfoImpl.java index 21f34bc0..1d95882b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceInfoImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceInfoImpl.java @@ -87,6 +87,10 @@ public int getProtocolCode() { return protocolCode; } + public Object getUniqueId() { + return id; + } + @Override public boolean isSameDevice(USBDeviceInfo device) { if (device instanceof USBDeviceInfoImpl) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index e80ada9a..e7a113ee 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -9,6 +9,7 @@ import net.codecrete.usb.USBDeviceInfo; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; @@ -78,4 +79,51 @@ protected void signalEnumerationComplete() { lock.unlock(); } } + + protected void addDevice(USBDeviceInfo device) { + // check for duplicates + if (findDeviceIndex(devices, ((USBDeviceInfoImpl)device).getUniqueId()) >= 0) + return; + + // copy list + var newDeviceList = new ArrayList(devices.size() + 1); + newDeviceList.addAll(devices); + newDeviceList.add(device); + devices = newDeviceList; + + // send notification + emitOnDeviceConnected(device); + } + + protected void removeDevice(String deviceId) { + // locate device to be removed + int index = findDeviceIndex(devices, deviceId); + if (index < 0) + return; // strange + + // copy list and remove device + var deviceInfo = devices.get(index); + var newDeviceList = new ArrayList<>(devices); + newDeviceList.remove(index); + devices = newDeviceList; + + // send notification + emitOnDeviceDisconnected(deviceInfo); + } + + + /** + * Finds the index of the device with the given ID in the device list + * @param deviceList the device list + * @param deviceId the unique device ID + * @return return the index, or -1 if the device is not found + */ + protected int findDeviceIndex(List deviceList, Object deviceId) { + for (int i = 0; i < deviceList.size(); i++) { + var dev = (USBDeviceInfoImpl) deviceList.get(i); + if (deviceId.equals(dev.getUniqueId())) + return i; + } + return -1; + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceInfo.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceInfo.java index 1d8c3d22..45f9fd75 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceInfo.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceInfo.java @@ -26,4 +26,8 @@ public class LinuxUSBDeviceInfo extends USBDeviceInfoImpl { public USBDevice open() { return new LinuxUSBDevice(id, this); } + + Object devicePath() { + return id; + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 509359f6..ed739607 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -8,16 +8,21 @@ package net.codecrete.usb.linux; import net.codecrete.usb.USBDeviceInfo; +import net.codecrete.usb.USBException; import net.codecrete.usb.common.USBDeviceRegistry; +import net.codecrete.usb.linux.gen.select.select; import net.codecrete.usb.linux.gen.udev.udev; import java.lang.foreign.Addressable; +import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; +import java.lang.invoke.MethodHandle; import java.util.ArrayList; import java.util.List; import static java.lang.foreign.MemoryAddress.NULL; +import static java.lang.foreign.ValueLayout.JAVA_LONG; /** * Linux implementation of USB device registry. @@ -34,12 +39,14 @@ public class LinuxUSBDeviceRegistry extends USBDeviceRegistry { private static final MemorySegment SUBSYSTEM_USB = MemorySession.global().allocateUtf8String("usb"); + private static final MemorySegment MONITOR_NAME = MemorySession.global().allocateUtf8String("udev"); + private static final MemorySegment DEVTYPE_USB_DEVICE = MemorySession.global().allocateUtf8String("usb_device"); /** * Creates a new instance. */ public LinuxUSBDeviceRegistry() { - enumeratePresentDevices(); + startDeviceMonitor(this::monitorDevices); } @Override @@ -47,17 +54,22 @@ public List getAllDevices() { return devices; } - private void enumeratePresentDevices() { + private void enumeratePresentDevices(Addressable udevInstance) { List result = new ArrayList<>(); try (var outerSession = MemorySession.openConfined()) { - var udevInstance = udev.udev_new(); - // create device enumerator var enumerate = udev.udev_enumerate_new(udevInstance); + if (enumerate == NULL) + throw new USBException("internal error (udev_enumerate_new)"); + outerSession.addCloseAction(() -> udev.udev_enumerate_unref(enumerate)); - udev.udev_enumerate_add_match_subsystem(enumerate, SUBSYSTEM_USB); - udev.udev_enumerate_scan_devices(enumerate); + + if (udev.udev_enumerate_add_match_subsystem(enumerate, SUBSYSTEM_USB) < 0) + throw new USBException("internal error (udev_enumerate_add_match_subsystem)"); + + if (udev.udev_enumerate_scan_devices(enumerate) < 0) + throw new USBException("internal error (udev_enumerate_scan_devices)"); // enumerate devices for (var entry= udev.udev_enumerate_get_list_entry(enumerate); @@ -75,36 +87,125 @@ private void enumeratePresentDevices() { if (dev == NULL) continue; + // ensure the device is released session.addCloseAction(() -> udev.udev_device_unref(dev)); - // retrieve device attributes - String idVendor = getDeviceAttribute(dev, "idVendor"); - if (idVendor == null) - continue; + // get device details + var deviceInfo = getDeviceDetails(dev); + if (deviceInfo != null) + result.add(deviceInfo); + } + } + } - String idProduct = getDeviceAttribute(dev, "idProduct"); - if (idProduct == null) - continue; + devices = result; + } - // get device path - var devPath = getDeviceName(dev); - if (devPath == null) - continue; + private void monitorDevices() { + + // setup udev monitor + var udevInstance = udev.udev_new(); + if (udevInstance == NULL) + throw new USBException("internal error (udev_new)"); - int vendorId = Integer.parseInt(idVendor, 16); - int productId = Integer.parseInt(idProduct, 16); + var monitor = udev.udev_monitor_new_from_netlink(udevInstance, MONITOR_NAME); + if (monitor == NULL) + throw new USBException("internal error (udev_monitor_new_from_netlink)"); - // add device to result list - result.add(new LinuxUSBDeviceInfo(devPath, vendorId, productId, - getDeviceAttribute(dev, "manufacturer"), - getDeviceAttribute(dev, "product"), - getDeviceAttribute(dev, "serial"), - 0, 0, 0)); + if (udev.udev_monitor_filter_add_match_subsystem_devtype(monitor, SUBSYSTEM_USB, DEVTYPE_USB_DEVICE) < 0) + throw new USBException("internal error (udev_monitor_filter_add_match_subsystem_devtype)"); + + if (udev.udev_monitor_enable_receiving(monitor) < 0) + throw new USBException("internal error (udev_monitor_enable_receiving)"); + + int fd = udev.udev_monitor_get_fd(monitor); + if (fd < 0) + throw new USBException("internal error (udev_monitor_get_fd)"); + + // create initial list of devices + enumeratePresentDevices(udevInstance); + + // signal initial enumeration is complete + signalEnumerationComplete(); + + // monitor device changes + while (true) { + try (var session = MemorySession.openConfined()) { + + // wait for next change + waitForFileDescriptor(fd, session); + + // retrieve change + var dev = udev.udev_monitor_receive_device(monitor); + if (dev == null) + continue; // shouldn't happen + + session.addCloseAction(() -> udev.udev_device_unref(dev)); + + // get details + var action = getDeviceAction(dev); + + if ("add".equals(action)) { + onDeviceConnected(dev); + } else if ("remove".equals(action)) { + onDeviceDisconnected(dev); } } } + } - devices = result; + private void onDeviceConnected(MemoryAddress device) { + + var deviceInfo = getDeviceDetails(device); + if (deviceInfo == null) + return; + + addDevice(deviceInfo); + } + + private void onDeviceDisconnected(MemoryAddress device) { + + var devPath = getDeviceName(device); + if (devPath == null) + return; + + removeDevice(devPath); + } + + /** + * Retrieves the device details and returns a {@code USBDeviceInfo} instance. + *

+ * If the device is missing one of vendor ID, product ID or device path, + * {@code null} is returned. + *

+ * @param device the device + * @return the device info + */ + private static USBDeviceInfo getDeviceDetails(MemoryAddress device) { + + // retrieve device attributes + String idVendor = getDeviceAttribute(device, "idVendor"); + if (idVendor == null) + return null; + + String idProduct = getDeviceAttribute(device, "idProduct"); + if (idProduct == null) + return null; + + // get device path + var devPath = getDeviceName(device); + if (devPath == null) + return null; + + int vendorId = Integer.parseInt(idVendor, 16); + int productId = Integer.parseInt(idProduct, 16); + + // create device info instance + return new LinuxUSBDeviceInfo(devPath, vendorId, productId, + getDeviceAttribute(device, "manufacturer"), + getDeviceAttribute(device, "product"), + getDeviceAttribute(device, "serial"), + 0, 0, 0); } private static String getDeviceAttribute(Addressable device, String attribute) { @@ -120,13 +221,39 @@ private static String getDeviceAttribute(Addressable device, String attribute) { } private static String getDeviceName(Addressable device) { + return callStringFunction(device, udev.udev_device_get_devnode$MH()); + } + + private static String getDeviceAction(Addressable device) { + return callStringFunction(device, udev.udev_device_get_action$MH()); + } + + private static String callStringFunction(Addressable device, MethodHandle function) { try (var session = MemorySession.openConfined()) { - var devNameAddr = udev.udev_device_get_devnode(device); + var devNameAddr = (MemoryAddress) function.invokeExact(device); if (devNameAddr == NULL) return null; var ret = MemorySegment.ofAddress(devNameAddr, 2000, session); return ret.getUtf8String(0); + + } catch (Throwable e) { + throw new RuntimeException(e); } } + + /** + * Waits until the specified file descriptor becomes ready for reading. + * @param fd the file descriptor + * @param session a memory session for allocating memory + */ + private static void waitForFileDescriptor(int fd, MemorySession session) { + // fd_set is a bit array with a capacity of FD_SETSIZE bits + var fds = session.allocate(JAVA_LONG, select.FD_SETSIZE() / JAVA_LONG.bitSize()); + fds.set(JAVA_LONG, fd / JAVA_LONG.bitSize(), 1L << (fd % JAVA_LONG.bitSize())); + + int res = select.select(fd + 1, fds, NULL, NULL, NULL); + if (res <= 0) + throw new USBException("internal error (select)"); + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/Constants$root.java new file mode 100644 index 00000000..bd53659c --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.select; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/RuntimeHelper.java new file mode 100644 index 00000000..a634735c --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/RuntimeHelper.java @@ -0,0 +1,216 @@ +package net.codecrete.usb.linux.gen.select; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/constants$0.java new file mode 100644 index 00000000..1e095f2b --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/constants$0.java @@ -0,0 +1,22 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.select; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor select$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle select$MH = RuntimeHelper.downcallHandle( + "select", + constants$0.select$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/select.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/select.java new file mode 100644 index 00000000..85d6f09d --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/select.java @@ -0,0 +1,36 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.select; + +import java.lang.foreign.Addressable; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.*; +public class select { + + /* package-private */ select() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static MethodHandle select$MH() { + return RuntimeHelper.requireNonNull(constants$0.select$MH,"select"); + } + public static int select ( int __nfds, Addressable __readfds, Addressable __writefds, Addressable __exceptfds, Addressable __timeout) { + var mh$ = select$MH(); + try { + return (int)mh$.invokeExact(__nfds, __readfds, __writefds, __exceptfds, __timeout); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static int FD_SETSIZE() { + return (int)1024L; + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java index a6258650..962ea187 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java @@ -40,12 +40,12 @@ class constants$0 { "udev_device_new_from_syspath", constants$0.udev_device_new_from_syspath$FUNC ); - static final FunctionDescriptor udev_device_get_devnode$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + static final FunctionDescriptor udev_device_get_devtype$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle udev_device_get_devnode$MH = RuntimeHelper.downcallHandle( - "udev_device_get_devnode", - constants$0.udev_device_get_devnode$FUNC + static final MethodHandle udev_device_get_devtype$MH = RuntimeHelper.downcallHandle( + "udev_device_get_devtype", + constants$0.udev_device_get_devtype$FUNC ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java index 9340bd78..986a90d3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java @@ -6,49 +6,49 @@ import java.lang.invoke.MethodHandle; class constants$1 { - static final FunctionDescriptor udev_device_get_sysattr_value$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, + static final FunctionDescriptor udev_device_get_devnode$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle udev_device_get_sysattr_value$MH = RuntimeHelper.downcallHandle( - "udev_device_get_sysattr_value", - constants$1.udev_device_get_sysattr_value$FUNC + static final MethodHandle udev_device_get_devnode$MH = RuntimeHelper.downcallHandle( + "udev_device_get_devnode", + constants$1.udev_device_get_devnode$FUNC ); - static final FunctionDescriptor udev_enumerate_unref$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + static final FunctionDescriptor udev_device_get_action$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle udev_enumerate_unref$MH = RuntimeHelper.downcallHandle( - "udev_enumerate_unref", - constants$1.udev_enumerate_unref$FUNC + static final MethodHandle udev_device_get_action$MH = RuntimeHelper.downcallHandle( + "udev_device_get_action", + constants$1.udev_device_get_action$FUNC ); - static final FunctionDescriptor udev_enumerate_new$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + static final FunctionDescriptor udev_device_get_sysattr_value$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle udev_enumerate_new$MH = RuntimeHelper.downcallHandle( - "udev_enumerate_new", - constants$1.udev_enumerate_new$FUNC + static final MethodHandle udev_device_get_sysattr_value$MH = RuntimeHelper.downcallHandle( + "udev_device_get_sysattr_value", + constants$1.udev_device_get_sysattr_value$FUNC ); - static final FunctionDescriptor udev_enumerate_add_match_subsystem$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + static final FunctionDescriptor udev_monitor_new_from_netlink$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle udev_enumerate_add_match_subsystem$MH = RuntimeHelper.downcallHandle( - "udev_enumerate_add_match_subsystem", - constants$1.udev_enumerate_add_match_subsystem$FUNC + static final MethodHandle udev_monitor_new_from_netlink$MH = RuntimeHelper.downcallHandle( + "udev_monitor_new_from_netlink", + constants$1.udev_monitor_new_from_netlink$FUNC ); - static final FunctionDescriptor udev_enumerate_scan_devices$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + static final FunctionDescriptor udev_monitor_enable_receiving$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle udev_enumerate_scan_devices$MH = RuntimeHelper.downcallHandle( - "udev_enumerate_scan_devices", - constants$1.udev_enumerate_scan_devices$FUNC + static final MethodHandle udev_monitor_enable_receiving$MH = RuntimeHelper.downcallHandle( + "udev_monitor_enable_receiving", + constants$1.udev_monitor_enable_receiving$FUNC ); - static final FunctionDescriptor udev_enumerate_get_list_entry$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + static final FunctionDescriptor udev_monitor_get_fd$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle udev_enumerate_get_list_entry$MH = RuntimeHelper.downcallHandle( - "udev_enumerate_get_list_entry", - constants$1.udev_enumerate_get_list_entry$FUNC + static final MethodHandle udev_monitor_get_fd$MH = RuntimeHelper.downcallHandle( + "udev_monitor_get_fd", + constants$1.udev_monitor_get_fd$FUNC ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$2.java new file mode 100644 index 00000000..47b95ed6 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$2.java @@ -0,0 +1,56 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.udev; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$2 { + + static final FunctionDescriptor udev_monitor_receive_device$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_monitor_receive_device$MH = RuntimeHelper.downcallHandle( + "udev_monitor_receive_device", + constants$2.udev_monitor_receive_device$FUNC + ); + static final FunctionDescriptor udev_monitor_filter_add_match_subsystem_devtype$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_monitor_filter_add_match_subsystem_devtype$MH = RuntimeHelper.downcallHandle( + "udev_monitor_filter_add_match_subsystem_devtype", + constants$2.udev_monitor_filter_add_match_subsystem_devtype$FUNC + ); + static final FunctionDescriptor udev_enumerate_unref$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_enumerate_unref$MH = RuntimeHelper.downcallHandle( + "udev_enumerate_unref", + constants$2.udev_enumerate_unref$FUNC + ); + static final FunctionDescriptor udev_enumerate_new$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_enumerate_new$MH = RuntimeHelper.downcallHandle( + "udev_enumerate_new", + constants$2.udev_enumerate_new$FUNC + ); + static final FunctionDescriptor udev_enumerate_add_match_subsystem$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_enumerate_add_match_subsystem$MH = RuntimeHelper.downcallHandle( + "udev_enumerate_add_match_subsystem", + constants$2.udev_enumerate_add_match_subsystem$FUNC + ); + static final FunctionDescriptor udev_enumerate_scan_devices$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_enumerate_scan_devices$MH = RuntimeHelper.downcallHandle( + "udev_enumerate_scan_devices", + constants$2.udev_enumerate_scan_devices$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$3.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$3.java new file mode 100644 index 00000000..862a7270 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$3.java @@ -0,0 +1,18 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.udev; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$3 { + + static final FunctionDescriptor udev_enumerate_get_list_entry$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle udev_enumerate_get_list_entry$MH = RuntimeHelper.downcallHandle( + "udev_enumerate_get_list_entry", + constants$3.udev_enumerate_get_list_entry$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java index 2b6bde54..ea5160ae 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java @@ -73,8 +73,19 @@ public static MemoryAddress udev_device_new_from_syspath ( Addressable udev, Ad throw new AssertionError("should not reach here", ex$); } } + public static MethodHandle udev_device_get_devtype$MH() { + return RuntimeHelper.requireNonNull(constants$0.udev_device_get_devtype$MH,"udev_device_get_devtype"); + } + public static MemoryAddress udev_device_get_devtype ( Addressable udev_device) { + var mh$ = udev_device_get_devtype$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev_device); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static MethodHandle udev_device_get_devnode$MH() { - return RuntimeHelper.requireNonNull(constants$0.udev_device_get_devnode$MH,"udev_device_get_devnode"); + return RuntimeHelper.requireNonNull(constants$1.udev_device_get_devnode$MH,"udev_device_get_devnode"); } public static MemoryAddress udev_device_get_devnode ( Addressable udev_device) { var mh$ = udev_device_get_devnode$MH(); @@ -84,6 +95,17 @@ public static MemoryAddress udev_device_get_devnode ( Addressable udev_device) { throw new AssertionError("should not reach here", ex$); } } + public static MethodHandle udev_device_get_action$MH() { + return RuntimeHelper.requireNonNull(constants$1.udev_device_get_action$MH,"udev_device_get_action"); + } + public static MemoryAddress udev_device_get_action ( Addressable udev_device) { + var mh$ = udev_device_get_action$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev_device); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static MethodHandle udev_device_get_sysattr_value$MH() { return RuntimeHelper.requireNonNull(constants$1.udev_device_get_sysattr_value$MH,"udev_device_get_sysattr_value"); } @@ -95,8 +117,63 @@ public static MemoryAddress udev_device_get_sysattr_value ( Addressable udev_dev throw new AssertionError("should not reach here", ex$); } } + public static MethodHandle udev_monitor_new_from_netlink$MH() { + return RuntimeHelper.requireNonNull(constants$1.udev_monitor_new_from_netlink$MH,"udev_monitor_new_from_netlink"); + } + public static MemoryAddress udev_monitor_new_from_netlink ( Addressable udev, Addressable name) { + var mh$ = udev_monitor_new_from_netlink$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev, name); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle udev_monitor_enable_receiving$MH() { + return RuntimeHelper.requireNonNull(constants$1.udev_monitor_enable_receiving$MH,"udev_monitor_enable_receiving"); + } + public static int udev_monitor_enable_receiving ( Addressable udev_monitor) { + var mh$ = udev_monitor_enable_receiving$MH(); + try { + return (int)mh$.invokeExact(udev_monitor); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle udev_monitor_get_fd$MH() { + return RuntimeHelper.requireNonNull(constants$1.udev_monitor_get_fd$MH,"udev_monitor_get_fd"); + } + public static int udev_monitor_get_fd ( Addressable udev_monitor) { + var mh$ = udev_monitor_get_fd$MH(); + try { + return (int)mh$.invokeExact(udev_monitor); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle udev_monitor_receive_device$MH() { + return RuntimeHelper.requireNonNull(constants$2.udev_monitor_receive_device$MH,"udev_monitor_receive_device"); + } + public static MemoryAddress udev_monitor_receive_device ( Addressable udev_monitor) { + var mh$ = udev_monitor_receive_device$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev_monitor); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle udev_monitor_filter_add_match_subsystem_devtype$MH() { + return RuntimeHelper.requireNonNull(constants$2.udev_monitor_filter_add_match_subsystem_devtype$MH,"udev_monitor_filter_add_match_subsystem_devtype"); + } + public static int udev_monitor_filter_add_match_subsystem_devtype ( Addressable udev_monitor, Addressable subsystem, Addressable devtype) { + var mh$ = udev_monitor_filter_add_match_subsystem_devtype$MH(); + try { + return (int)mh$.invokeExact(udev_monitor, subsystem, devtype); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static MethodHandle udev_enumerate_unref$MH() { - return RuntimeHelper.requireNonNull(constants$1.udev_enumerate_unref$MH,"udev_enumerate_unref"); + return RuntimeHelper.requireNonNull(constants$2.udev_enumerate_unref$MH,"udev_enumerate_unref"); } public static MemoryAddress udev_enumerate_unref ( Addressable udev_enumerate) { var mh$ = udev_enumerate_unref$MH(); @@ -107,7 +184,7 @@ public static MemoryAddress udev_enumerate_unref ( Addressable udev_enumerate) { } } public static MethodHandle udev_enumerate_new$MH() { - return RuntimeHelper.requireNonNull(constants$1.udev_enumerate_new$MH,"udev_enumerate_new"); + return RuntimeHelper.requireNonNull(constants$2.udev_enumerate_new$MH,"udev_enumerate_new"); } public static MemoryAddress udev_enumerate_new ( Addressable udev) { var mh$ = udev_enumerate_new$MH(); @@ -118,7 +195,7 @@ public static MemoryAddress udev_enumerate_new ( Addressable udev) { } } public static MethodHandle udev_enumerate_add_match_subsystem$MH() { - return RuntimeHelper.requireNonNull(constants$1.udev_enumerate_add_match_subsystem$MH,"udev_enumerate_add_match_subsystem"); + return RuntimeHelper.requireNonNull(constants$2.udev_enumerate_add_match_subsystem$MH,"udev_enumerate_add_match_subsystem"); } public static int udev_enumerate_add_match_subsystem ( Addressable udev_enumerate, Addressable subsystem) { var mh$ = udev_enumerate_add_match_subsystem$MH(); @@ -129,7 +206,7 @@ public static int udev_enumerate_add_match_subsystem ( Addressable udev_enumerat } } public static MethodHandle udev_enumerate_scan_devices$MH() { - return RuntimeHelper.requireNonNull(constants$1.udev_enumerate_scan_devices$MH,"udev_enumerate_scan_devices"); + return RuntimeHelper.requireNonNull(constants$2.udev_enumerate_scan_devices$MH,"udev_enumerate_scan_devices"); } public static int udev_enumerate_scan_devices ( Addressable udev_enumerate) { var mh$ = udev_enumerate_scan_devices$MH(); @@ -140,7 +217,7 @@ public static int udev_enumerate_scan_devices ( Addressable udev_enumerate) { } } public static MethodHandle udev_enumerate_get_list_entry$MH() { - return RuntimeHelper.requireNonNull(constants$1.udev_enumerate_get_list_entry$MH,"udev_enumerate_get_list_entry"); + return RuntimeHelper.requireNonNull(constants$3.udev_enumerate_get_list_entry$MH,"udev_enumerate_get_list_entry"); } public static MemoryAddress udev_enumerate_get_list_entry ( Addressable udev_enumerate) { var mh$ = udev_enumerate_get_list_entry$MH(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java index b93ca796..b13b4420 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java @@ -26,10 +26,6 @@ public class WindowsUSBDeviceInfo extends USBDeviceInfoImpl { this.currentConfigurationValue = currentConfigurationValue; } - String devicePath() { - return (String) id; - } - @Override public USBDevice open() { return new WindowsUSBDevice(id, this, currentConfigurationValue); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index c7d39cc0..c2a3d8d6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -10,6 +10,7 @@ import net.codecrete.usb.USBDeviceInfo; import net.codecrete.usb.USBException; import net.codecrete.usb.common.USBDescriptors; +import net.codecrete.usb.common.USBDeviceInfoImpl; import net.codecrete.usb.common.USBDeviceRegistry; import net.codecrete.usb.common.USBStructs; import net.codecrete.usb.windows.gen.kernel32.Kernel32; @@ -311,50 +312,25 @@ private void onDeviceConnected(String devicePath) { final var hubHandles = new HashMap(); session.addCloseAction(() -> hubHandles.forEach((path, handle) -> Kernel32.CloseHandle(handle))); - // check for duplicates - if (findDeviceIndex(devices, devicePath) >= 0) - return; - // create device info instance var deviceInfo = createDeviceInfo(devInfoSetHandle, devInfo, devicePath, hubHandles); - // copy list - var newDeviceList = new ArrayList<>(devices); - newDeviceList.add(deviceInfo); - devices = newDeviceList; - - // send notification - emitOnDeviceConnected(deviceInfo); + // add it to device list + addDevice(deviceInfo); } } private void onDeviceDisconnected(String devicePath) { - - // locate device to be removed - int index = findDeviceIndex(devices, devicePath); - if (index < 0) - return; // strange - - // copy list and remove device - var deviceInfo = devices.get(index); - var newDeviceList = new ArrayList<>(devices); - newDeviceList.remove(index); - devices = newDeviceList; - - // send notification - emitOnDeviceDisconnected(deviceInfo); + // remove from device list + removeDevice(devicePath); } - /** - * Finds the index of the device with the given path in the device list - * @param deviceList the device list - * @param devicePath the device path - * @return return the index, or -1 if the device is not found - */ - private static int findDeviceIndex(List deviceList, String devicePath) { + @Override + protected int findDeviceIndex(List deviceList, Object deviceId) { + var id = deviceId.toString(); for (int i = 0; i < deviceList.size(); i++) { - var winInfo = (WindowsUSBDeviceInfo) deviceList.get(i); - if (winInfo.devicePath().equalsIgnoreCase(devicePath)) + var dev = (USBDeviceInfoImpl) deviceList.get(i); + if (id.equalsIgnoreCase(dev.getUniqueId().toString())) return i; } return -1; From 2ff6f478c9fd0ebb4e835868cb6d7922e99718c2 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 29 Aug 2022 23:41:10 +0200 Subject: [PATCH 023/433] macOS: complete refactoring of common registry code --- .../usb/common/USBDeviceRegistry.java | 3 +- .../usb/macos/MacosUSBDeviceRegistry.java | 79 ++++++------------- 2 files changed, 24 insertions(+), 58 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index e7a113ee..f5529efa 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -95,7 +95,7 @@ protected void addDevice(USBDeviceInfo device) { emitOnDeviceConnected(device); } - protected void removeDevice(String deviceId) { + protected void removeDevice(Object deviceId) { // locate device to be removed int index = findDeviceIndex(devices, deviceId); if (index < 0) @@ -111,7 +111,6 @@ protected void removeDevice(String deviceId) { emitOnDeviceDisconnected(deviceInfo); } - /** * Finds the index of the device with the given ID in the device list * @param deviceList the device list diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 31f027a7..194ae049 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -16,6 +16,7 @@ import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.List; +import java.util.function.BiConsumer; import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.*; @@ -44,15 +45,13 @@ public List getAllDevices() { } /** - * Process the device iterator and return a list of devices ({@link USBDeviceInfo}). + * Process the devices resulting from the iterator * - * @param iterator iterator + * @param iterator the iterator * @param isDisconnected flag is the iterator is for disconnected devices - * @return list of devices + * @param function a function that will be called for each device with the entry ID and the service */ - private List iterateDevices(int iterator, boolean isDisconnected) { - - List result = new ArrayList<>(); + private void iterateDevices(int iterator, boolean isDisconnected, BiConsumer function) { int svc; while ((svc = IoKit.IOIteratorNext(iterator)) != 0) { @@ -76,17 +75,13 @@ private List iterateDevices(int iterator, boolean isDisconnected) throw new MacosUSBException("IORegistryEntryGetRegistryEntryID failed", ret); var entryId = entryIdHolder.get(JAVA_LONG, 0); - var deviceInfo = createDeviceInfo(entryId, service); - - if (deviceInfo != null) - result.add(deviceInfo); + // call function to process device + function.accept(entryId, service); } } - - return result; } - private USBDeviceInfo createDeviceInfo(long entryID, int service) { + private USBDeviceInfo createDeviceInfo(Long entryID, int service) { Integer vendorId = IoKitHelper.GetPropertyInt(service, "idVendor"); Integer productId = IoKitHelper.GetPropertyInt(service, "idProduct"); @@ -126,8 +121,13 @@ private void monitorDevices() { MethodType.methodType(void.class, MemoryAddress.class, int.class)); int deviceConnectedIter = setupNotification(session, notifyPort, IoKit.kIOFirstMatchNotification, onDeviceConnectedMH); - // iterate current devices in order to arm the notifications - devices = iterateDevices(deviceConnectedIter, false); + // iterate current devices in order to arm the notifications (and build initial device list) + devices = new ArrayList<>(); + iterateDevices(deviceConnectedIter, false, (entryId, service) -> { + var deviceInfo = createDeviceInfo(entryId, service); + if (deviceInfo != null) + devices.add(deviceInfo); + }); // signal completion of initial device enumeration signalEnumerationComplete(); @@ -182,16 +182,13 @@ private int setupNotification(MemorySession session, MemoryAddress notifyPort, M * @param iterator device iterator */ private void onDevicesConnected(MemoryAddress ignoredRefCon, int iterator) { - // retrieve device info for connected devices - var connectedDevices = iterateDevices(iterator, false); - - // create new device list with connected devices - var newDeviceList = new ArrayList<>(devices); - newDeviceList.addAll(connectedDevices); - devices = newDeviceList; - // emit events - connectedDevices.forEach(this::emitOnDeviceConnected); + // process device info for connected devices + iterateDevices(iterator, false, (entryId, service) -> { + var deviceInfo = createDeviceInfo(entryId, service); + if (deviceInfo != null) + addDevice(deviceInfo); + }); } /** @@ -203,38 +200,8 @@ private void onDevicesConnected(MemoryAddress ignoredRefCon, int iterator) { * @param iterator device iterator */ private void onDevicesDisconnected(MemoryAddress ignoredRefCon, int iterator) { - // retrieve device info for disconnected devices - var disconnectedDevices = iterateDevices(iterator, true); - - // create new device list without the disconnected devices - var newDeviceList = new ArrayList<>(devices); - for (var device : disconnectedDevices) { - int index = findDeviceIndex(newDeviceList, device); - if (index >= 0) - newDeviceList.remove(index); - } - devices = newDeviceList; - - // emit events - disconnectedDevices.forEach(this::emitOnDeviceDisconnected); - } - /** - * Find the index of the device in the device list. - *

- * Devices are compared by their IO registry entry ID. - *

- * @param deviceList the device list - * @param device the device - * @return the index of the device, or -1 if it is not found - */ - private static int findDeviceIndex(List deviceList, USBDeviceInfo device) { - Object id = ((MacosUSBDeviceInfo)device).getId(); - for (int i = 0; i < deviceList.size(); i++) { - var macDevice = (MacosUSBDeviceInfo) deviceList.get(i); - if (id.equals(macDevice.getId())) - return i; - } - return -1; + // process device info for disconnected devices + iterateDevices(iterator, true, (entryId, service) -> removeDevice(entryId)); } } From d0f6f24a565b673406eb1e00c62ad5089c9baca2 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 29 Aug 2022 23:46:24 +0200 Subject: [PATCH 024/433] README reflects additions and changes --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 20b6879f..d5ecf010 100644 --- a/README.md +++ b/README.md @@ -52,12 +52,12 @@ MAVEN_OPTS="--enable-preview --enable-native-access=ALL-UNNAMED" mvn install exe - Enumeration of USB devices - Control transfer - Bulk transfer +- Notification about connected/disconnected devices ### To do - Interrupt transfer - Isochronous transfer -- Notification about connected/disconnected devices - Descriptive information about interfaces, settings and endpoints - Alternate interface settings - Composite devices (on Windows) @@ -81,7 +81,7 @@ No special considerations apply. Using this library, a Java application can conn ### Linux -*libsystemd* is used to discover USB devices. So it only runs on Linux distributions with systemd and the related library. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfills this. +*libudev* is used to discover and monitor USB devices. The library is closely tied to *systemd*. So it only runs on Linux distributions with systemd and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfills this requriement. Similar to macOS, a Java application can connect to any USB device and claim any interfaces that aren't claimed by an operating system driver or another application. From d0816f98784ef2169951e2b5e786dfdc5fdea29f Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 30 Aug 2022 20:27:26 +0200 Subject: [PATCH 025/433] Linux: minor cleanup --- java-does-usb/jextract/gen_linux.sh | 2 +- .../java/net/codecrete/usb/linux/Linux.java | 36 +++++++++++++++++++ .../usb/linux/LinuxUSBDeviceRegistry.java | 30 +++++----------- .../usb/linux/gen/select/fd_set.java | 25 +++++++++++++ .../usb/linux/gen/select/select.java | 3 -- 5 files changed, 71 insertions(+), 25 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/fd_set.java diff --git a/java-does-usb/jextract/gen_linux.sh b/java-does-usb/jextract/gen_linux.sh index 55d983ba..1417a44e 100755 --- a/java-does-usb/jextract/gen_linux.sh +++ b/java-does-usb/jextract/gen_linux.sh @@ -84,5 +84,5 @@ $JEXTRACT --source --output ../src/main/java \ --header-class-name select \ --target-package net.codecrete.usb.linux.gen.select \ --include-function select \ - --include-macro FD_SETSIZE \ + --include-typedef fd_set \ /usr/include/x86_64-linux-gnu/sys/select.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java new file mode 100644 index 00000000..8d759c0e --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java @@ -0,0 +1,36 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.linux; + +import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; + +import static java.lang.foreign.MemoryAddress.NULL; + +/** + * Helper functions for Linux + */ +public class Linux { + + /** + * Creates a Java string as a copy of the null-terminated UTF-8 string. + * + * @param str the memory address pointing to string + * @return the Java string, or {@code null} if the memory address is 0 + */ + public static String createStringFromAddress(MemoryAddress str) { + try (var session = MemorySession.openConfined()) { + if (str == NULL) + return null; + + var ret = MemorySegment.ofAddress(str, 2000, session); + return ret.getUtf8String(0); + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index ed739607..d2826d07 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -10,6 +10,7 @@ import net.codecrete.usb.USBDeviceInfo; import net.codecrete.usb.USBException; import net.codecrete.usb.common.USBDeviceRegistry; +import net.codecrete.usb.linux.gen.select.fd_set; import net.codecrete.usb.linux.gen.select.select; import net.codecrete.usb.linux.gen.udev.udev; @@ -17,7 +18,6 @@ import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; -import java.lang.invoke.MethodHandle; import java.util.ArrayList; import java.util.List; @@ -72,7 +72,7 @@ private void enumeratePresentDevices(Addressable udevInstance) { throw new USBException("internal error (udev_enumerate_scan_devices)"); // enumerate devices - for (var entry= udev.udev_enumerate_get_list_entry(enumerate); + for (var entry = udev.udev_enumerate_get_list_entry(enumerate); entry != NULL; entry = udev.udev_list_entry_get_next(entry)) { @@ -178,6 +178,7 @@ private void onDeviceDisconnected(MemoryAddress device) { * If the device is missing one of vendor ID, product ID or device path, * {@code null} is returned. *

+ * * @param device the device * @return the device info */ @@ -221,35 +222,22 @@ private static String getDeviceAttribute(Addressable device, String attribute) { } private static String getDeviceName(Addressable device) { - return callStringFunction(device, udev.udev_device_get_devnode$MH()); + return Linux.createStringFromAddress(udev.udev_device_get_devnode(device)); } private static String getDeviceAction(Addressable device) { - return callStringFunction(device, udev.udev_device_get_action$MH()); - } - - private static String callStringFunction(Addressable device, MethodHandle function) { - try (var session = MemorySession.openConfined()) { - var devNameAddr = (MemoryAddress) function.invokeExact(device); - if (devNameAddr == NULL) - return null; - - var ret = MemorySegment.ofAddress(devNameAddr, 2000, session); - return ret.getUtf8String(0); - - } catch (Throwable e) { - throw new RuntimeException(e); - } + return Linux.createStringFromAddress(udev.udev_device_get_action(device)); } /** * Waits until the specified file descriptor becomes ready for reading. - * @param fd the file descriptor + * + * @param fd the file descriptor * @param session a memory session for allocating memory */ private static void waitForFileDescriptor(int fd, MemorySession session) { - // fd_set is a bit array with a capacity of FD_SETSIZE bits - var fds = session.allocate(JAVA_LONG, select.FD_SETSIZE() / JAVA_LONG.bitSize()); + // fd_set is a bit array (constructed from 64-bit integers) + var fds = session.allocate(fd_set.$LAYOUT()); fds.set(JAVA_LONG, fd / JAVA_LONG.bitSize(), 1L << (fd % JAVA_LONG.bitSize())); int res = select.select(fd + 1, fds, NULL, NULL, NULL); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/fd_set.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/fd_set.java new file mode 100644 index 00000000..2a321b89 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/fd_set.java @@ -0,0 +1,25 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.select; + +import java.lang.foreign.*; +public class fd_set { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + MemoryLayout.sequenceLayout(16, Constants$root.C_LONG_LONG$LAYOUT).withName("__fds_bits") + ); + public static MemoryLayout $LAYOUT() { + return fd_set.$struct$LAYOUT; + } + public static MemorySegment __fds_bits$slice(MemorySegment seg) { + return seg.asSlice(0, 128); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/select.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/select.java index 85d6f09d..85ed94b2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/select.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/select.java @@ -28,9 +28,6 @@ public static int select ( int __nfds, Addressable __readfds, Addressable __wr throw new AssertionError("should not reach here", ex$); } } - public static int FD_SETSIZE() { - return (int)1024L; - } } From 0e4125193e2a86e58d9cfc67577f9dcdb32417b0 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 31 Aug 2022 18:53:37 +0200 Subject: [PATCH 026/433] Document code generation --- java-does-usb/jextract/README.md | 67 ++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 java-does-usb/jextract/README.md diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md new file mode 100644 index 00000000..82a12f04 --- /dev/null +++ b/java-does-usb/jextract/README.md @@ -0,0 +1,67 @@ +# Code Generation with *jextract* + +Some of the binding code for accessing native functions and data structures is generated with [jextract](https://jdk.java.net/jextract/). The tool is still under construction and has its limitations. + +In order to generate the code, the scripts in this directory have to be run (`gen_linux.sh`, `gen_macos.sh` and `gen_win_xxx.cmd`). Each script has to be run on that particular operating system. + +The code is generated in directories below `gen`, i.e. `main/java/net/codecrete/usb/linux/gen` and similar for the other operating systems. For each library (`xxx.so` or `xxx.dll`) and each macOS framework, a separate package is created. + +The scripts explicitly specify the functions, structs etc. to include as generating code for entire operating system header files can result in an excessive amount of Java source files and classes. + +The resulting code is then committed to the source code repository. Before the commit, imports are cleaned up to get rid of superfluous imports. Most IDEs provide a convenient command to execute this on entire directories. + + +## Linux + +To run the script, most likely the header files for *libudev* must be installed (the library itself is most likely already installed): + +``` +sudo apt-get install libudev-dev +``` + +On Linux, *jextract* is very successful. The only limitations are: + +- `usbdevice_fs.h`: The macro `USBDEVFS_CONTROL` (and all similar ones) are not generated. They are probably considered a function-like macro. *jextract* does not generate code for function-like macro. But `USBDEVFS_CONTROL` is actually a constant. + +- `sd-device.h` (header file for *libsystemd*): *jextract* fails with *"Error: /usr/include/inttypes.h:290:8: error: unknown type name 'intmax_t'"*. The reason is yet unknown. This code is currently not needed as it uses *libudev* instead of *libsystemd*. They are related, *libsystemd* is the future solution, but it is missing support for monitoring devices. + +- `libudev.h`: After code generation, the class `RuntimeHelper.java` in `.../linux/gen/udev` must be manually modified as the code to access the library does not work for the directory the library is located in. So replace: + +``` + System.loadLibrary("udev"); + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); +``` + +with: + +``` + SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so", MemorySession.openImplicit()); +``` + + +## MacOS + +Most of the required native function on macOS are part of a framework. Framework internally have a more complex file organization of header and binary files than appears on the outside. Thus they require a special logic to locate framework header files. *clang* supports it with the `-F` and `-iframework`. *jextract* does not support it. The result is that only a single function is generated. The binding code for all other functions and data structures is written manually. + +Loading framework libraries at runtime also requires special support. That is already built in and working nicely, e.g. to load the *IOKit* framework, below code can be used. + +``` +SymbolLookup ioKitLookup SymbolLookup.libraryLookup("IOKit.framework/IOKit", MemorySession.openImplicit()); +``` + + +## Windows + +On Windows, several scripts must be run as *jextract* is a batch file that never returns. It's not possible to call it multiple times from a single script. + +Most Windows SDK header files are not independent. They require that `Windows.h` is included first. So instead of specifying the target header files directly, a helper header file (`windows_headers.h` in this directory) is specified. + +The known limitations are: + +- `typedef` to `struct`: If only the *typedef* is specified (`--include-typedef`), an empty Java class is generated. If both *typedef* and the *struct* it refers to are specified, the *typedef* class is still empty but inherits from the *struct* class, which contains all the *struct* members. + +- Variable size *struct*: Several Windows struct are of variable size. The last member is an array. The *struct* definition specifies array length 1. But you are expected to allocate more space depending on the actual array size you need. *jextract* generates code for array length 1 and when access array members, the length is checked. So the generated code isn't really usable. + +- `USB_NODE_CONNECTION_INFORMATION_EX`: This struct uses a packed layout without considering alignment. The last four members are on an offset even though they are multiple bytes long. *jextract* creates the correct offsets but defines strict alignment constraints for the members. So the memory layout cannot be instantiated as it throws an exception. + +- GUID constants like `GUID_DEVINTERFACE_USB_DEVICE` do not work. While code is generated, the code fails at run-time as it is unable to locate the symbol. This is most likely due to the fact that the constant isn't in any native library at all. Rather they are defined in file that uses them and then multiple copies are discarded at link time using [`__declspec(selectany)`](https://docs.microsoft.com/en-us/cpp/cpp/selectany?view=msvc-170). From 5f9cb31127ef238d7b35a95c32122f83a9e966af Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 31 Aug 2022 19:13:42 +0200 Subject: [PATCH 027/433] Windows: use cleaner typedef name --- java-does-usb/jextract/gen_win_kernel32.cmd | 3 +- java-does-usb/jextract/gen_win_setupapi.cmd | 5 +- java-does-usb/jextract/gen_win_stdlib.cmd | 2 +- java-does-usb/jextract/gen_win_usbioctl.cmd | 7 +- java-does-usb/jextract/gen_win_user32.cmd | 6 +- java-does-usb/jextract/gen_win_winusb.cmd | 2 +- .../codecrete/usb/windows/DeviceProperty.java | 18 +- .../java/net/codecrete/usb/windows/Win.java | 12 +- .../usb/windows/WindowsUSBDeviceRegistry.java | 42 ++--- .../usb/windows/gen/kernel32/GUID.java | 9 + .../setupapi/SP_DEVICE_INTERFACE_DATA.java | 9 + .../SP_DEVICE_INTERFACE_DETAIL_DATA_W.java | 9 + .../windows/gen/setupapi/SP_DEVINFO_DATA.java | 9 + .../_USB_NODE_CONNECTION_INFORMATION_EX.java | 171 ------------------ .../DEV_BROADCAST_DEVICEINTERFACE_W.java | 9 + .../windows/gen/user32/DEV_BROADCAST_HDR.java | 9 + .../codecrete/usb/windows/gen/user32/MSG.java | 9 + .../usb/windows/gen/user32/WNDCLASSEXW.java | 9 + 18 files changed, 122 insertions(+), 218 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/GUID.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DATA.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVINFO_DATA.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_DEVICEINTERFACE_W.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_HDR.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/MSG.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/WNDCLASSEXW.java diff --git a/java-does-usb/jextract/gen_win_kernel32.cmd b/java-does-usb/jextract/gen_win_kernel32.cmd index 08aa4d94..b591e50c 100644 --- a/java-does-usb/jextract/gen_win_kernel32.cmd +++ b/java-does-usb/jextract/gen_win_kernel32.cmd @@ -1,4 +1,4 @@ -set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract.bat +set JEXTRACT=..\..\..\jextract-19\bin\jextract.bat set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 %JEXTRACT% --source --output ../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ @@ -23,4 +23,5 @@ set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 --include-macro FILE_FLAG_OVERLAPPED ^ --include-macro OPEN_EXISTING ^ --include-struct _GUID ^ + --include-typedef GUID ^ windows_headers.h diff --git a/java-does-usb/jextract/gen_win_setupapi.cmd b/java-does-usb/jextract/gen_win_setupapi.cmd index edaf3411..c027cc38 100644 --- a/java-does-usb/jextract/gen_win_setupapi.cmd +++ b/java-does-usb/jextract/gen_win_setupapi.cmd @@ -1,4 +1,4 @@ -set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract.bat +set JEXTRACT=..\..\..\jextract-19\bin\jextract.bat set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 %JEXTRACT% --source --output ../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ @@ -16,8 +16,11 @@ set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 --include-function SetupDiGetDevicePropertyW ^ --include-function SetupDiOpenDeviceInterfaceW ^ --include-struct _SP_DEVINFO_DATA ^ + --include-typedef SP_DEVINFO_DATA ^ --include-struct _SP_DEVICE_INTERFACE_DATA ^ + --include-typedef SP_DEVICE_INTERFACE_DATA ^ --include-struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W ^ + --include-typedef SP_DEVICE_INTERFACE_DETAIL_DATA_W ^ --include-macro DIGCF_PRESENT ^ --include-macro DIGCF_DEVICEINTERFACE ^ --include-macro SPDRP_ADDRESS ^ diff --git a/java-does-usb/jextract/gen_win_stdlib.cmd b/java-does-usb/jextract/gen_win_stdlib.cmd index 8a80e5e0..e56b841f 100644 --- a/java-does-usb/jextract/gen_win_stdlib.cmd +++ b/java-does-usb/jextract/gen_win_stdlib.cmd @@ -1,4 +1,4 @@ -set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract.bat +set JEXTRACT=..\..\..\jextract-19\bin\jextract.bat %JEXTRACT% --source --output ../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ --header-class-name StdLib ^ diff --git a/java-does-usb/jextract/gen_win_usbioctl.cmd b/java-does-usb/jextract/gen_win_usbioctl.cmd index 76cb7589..6710f2ce 100644 --- a/java-does-usb/jextract/gen_win_usbioctl.cmd +++ b/java-does-usb/jextract/gen_win_usbioctl.cmd @@ -1,4 +1,4 @@ -set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract.bat +set JEXTRACT=..\..\..\jextract-19\bin\jextract.bat set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 %JEXTRACT% --source --output ../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ @@ -6,11 +6,6 @@ set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 -I "%SDK_DIR%\shared" ^ --header-class-name USBIoctl ^ --target-package net.codecrete.usb.windows.gen.usbioctl ^ - --include-struct _USB_NODE_CONNECTION_INFORMATION_EX ^ --include-macro IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX ^ --include-macro IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION ^ windows_headers.h - -:: Generated code is invalid: No instance of type _USB_NODE_CONNECTION_INFORMATION_EX can be created.0 -:: They crash with: -:: java.lang.UnsupportedOperationException: Invalid alignment requirements for layout s16(DeviceAddress) diff --git a/java-does-usb/jextract/gen_win_user32.cmd b/java-does-usb/jextract/gen_win_user32.cmd index 14f5ad2a..5dd02fd5 100644 --- a/java-does-usb/jextract/gen_win_user32.cmd +++ b/java-does-usb/jextract/gen_win_user32.cmd @@ -1,4 +1,4 @@ -set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract.bat +set JEXTRACT=..\..\..\jextract-19\bin\jextract.bat set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 %JEXTRACT% --source --output ../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ @@ -19,7 +19,11 @@ set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 --include-macro DBT_DEVICEREMOVECOMPLETE ^ --include-macro DBT_DEVTYP_DEVICEINTERFACE ^ --include-struct tagMSG ^ + --include-typedef MSG ^ --include-struct tagWNDCLASSEXW ^ + --include-typedef WNDCLASSEXW ^ --include-struct _DEV_BROADCAST_HDR ^ + --include-typedef DEV_BROADCAST_HDR ^ --include-struct _DEV_BROADCAST_DEVICEINTERFACE_W ^ + --include-typedef DEV_BROADCAST_DEVICEINTERFACE_W ^ windows_headers.h diff --git a/java-does-usb/jextract/gen_win_winusb.cmd b/java-does-usb/jextract/gen_win_winusb.cmd index a8975263..e059905c 100644 --- a/java-does-usb/jextract/gen_win_winusb.cmd +++ b/java-does-usb/jextract/gen_win_winusb.cmd @@ -1,4 +1,4 @@ -set JEXTRACT=..\..\..\jextract\build\jextract\bin\jextract.bat +set JEXTRACT=..\..\..\jextract-19\bin\jextract.bat set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 %JEXTRACT% --source --output ../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index ce0a54dc..825cac53 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -8,10 +8,10 @@ package net.codecrete.usb.windows; import net.codecrete.usb.USBException; +import net.codecrete.usb.windows.gen.kernel32.GUID; import net.codecrete.usb.windows.gen.kernel32.Kernel32; -import net.codecrete.usb.windows.gen.kernel32._GUID; +import net.codecrete.usb.windows.gen.setupapi.SP_DEVICE_INTERFACE_DATA; import net.codecrete.usb.windows.gen.setupapi.SetupAPI; -import net.codecrete.usb.windows.gen.setupapi._SP_DEVICE_INTERFACE_DATA; import java.lang.foreign.Addressable; import java.lang.foreign.MemorySegment; @@ -90,8 +90,8 @@ public static String getDevicePath(String instanceID, Addressable interfaceGuid) session.addCloseAction(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); // retrieve first element of enumeration - var devIntfData = session.allocate(_SP_DEVICE_INTERFACE_DATA.$LAYOUT()); - _SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); + var devIntfData = session.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); + SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); if (SetupAPI.SetupDiEnumDeviceInterfaces(devInfoSetHandle, NULL, interfaceGuid, 0, devIntfData) == 0) throw new USBException("internal error (SetupDiEnumDeviceInterfaces)"); @@ -111,11 +111,11 @@ public static MemorySegment createDEVPROPKEY(int data1, short data2, short data3 byte data4_0, byte data4_1, byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7, int pid) { - var propKey = MemorySession.global().allocate(_GUID.sizeof() + JAVA_INT.byteSize()); - _GUID.Data1$set(propKey, data1); - _GUID.Data2$set(propKey, data2); - _GUID.Data3$set(propKey, data3); - var data4 = _GUID.Data4$slice(propKey); + var propKey = MemorySession.global().allocate(GUID.sizeof() + JAVA_INT.byteSize()); + GUID.Data1$set(propKey, data1); + GUID.Data2$set(propKey, data2); + GUID.Data3$set(propKey, data3); + var data4 = GUID.Data4$slice(propKey); data4.set(JAVA_BYTE, 0, data4_0); data4.set(JAVA_BYTE, 1, data4_1); data4.set(JAVA_BYTE, 2, data4_2); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index c850dc72..b0aabe7f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -7,7 +7,7 @@ package net.codecrete.usb.windows; -import net.codecrete.usb.windows.gen.kernel32._GUID; +import net.codecrete.usb.windows.gen.kernel32.GUID; import net.codecrete.usb.windows.gen.stdlib.StdLib; import java.lang.foreign.MemoryAddress; @@ -82,11 +82,11 @@ public static String createStringFromSegment(MemorySegment segment) { public static MemorySegment CreateGUID(int data1, short data2, short data3, byte data4_0, byte data4_1, byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7) { - var guid = MemorySegment.allocateNative(_GUID.$LAYOUT(), MemorySession.global()); - _GUID.Data1$set(guid, data1); - _GUID.Data2$set(guid, data2); - _GUID.Data3$set(guid, data3); - var data4 = _GUID.Data4$slice(guid); + var guid = MemorySegment.allocateNative(GUID.$LAYOUT(), MemorySession.global()); + GUID.Data1$set(guid, data1); + GUID.Data2$set(guid, data2); + GUID.Data3$set(guid, data3); + var data4 = GUID.Data4$slice(guid); data4.set(JAVA_BYTE, 0, data4_0); data4.set(JAVA_BYTE, 1, data4_1); data4.set(JAVA_BYTE, 2, data4_2); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index c2a3d8d6..7fb8deab 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -14,9 +14,9 @@ import net.codecrete.usb.common.USBDeviceRegistry; import net.codecrete.usb.common.USBStructs; import net.codecrete.usb.windows.gen.kernel32.Kernel32; +import net.codecrete.usb.windows.gen.setupapi.SP_DEVICE_INTERFACE_DATA; +import net.codecrete.usb.windows.gen.setupapi.SP_DEVINFO_DATA; import net.codecrete.usb.windows.gen.setupapi.SetupAPI; -import net.codecrete.usb.windows.gen.setupapi._SP_DEVICE_INTERFACE_DATA; -import net.codecrete.usb.windows.gen.setupapi._SP_DEVINFO_DATA; import net.codecrete.usb.windows.gen.usbioctl.USBIoctl; import net.codecrete.usb.windows.gen.user32.*; @@ -73,8 +73,8 @@ private void enumeratePresentDevices() { // ensure the result is destroyed when the scope is left outerSession.addCloseAction(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); - var devInfo = MemorySegment.allocateNative(_SP_DEVINFO_DATA.$LAYOUT(), outerSession); - _SP_DEVINFO_DATA.cbSize$set(devInfo, (int) _SP_DEVINFO_DATA.$LAYOUT().byteSize()); + var devInfo = MemorySegment.allocateNative(SP_DEVINFO_DATA.$LAYOUT(), outerSession); + SP_DEVINFO_DATA.cbSize$set(devInfo, (int) SP_DEVINFO_DATA.$LAYOUT().byteSize()); // ensure all hubs are closed later final var hubHandles = new HashMap(); @@ -218,11 +218,11 @@ private void monitorDevices() { ); // register window class - var wx = session.allocate(tagWNDCLASSEXW.$LAYOUT()); - tagWNDCLASSEXW.cbSize$set(wx, (int) wx.byteSize()); - tagWNDCLASSEXW.lpfnWndProc$set(wx, handleWindowMessageStub.address()); - tagWNDCLASSEXW.hInstance$set(wx, instance); - tagWNDCLASSEXW.lpszClassName$set(wx, className.address()); + var wx = session.allocate(WNDCLASSEXW.$LAYOUT()); + WNDCLASSEXW.cbSize$set(wx, (int) wx.byteSize()); + WNDCLASSEXW.lpfnWndProc$set(wx, handleWindowMessageStub.address()); + WNDCLASSEXW.hInstance$set(wx, instance); + WNDCLASSEXW.lpszClassName$set(wx, className.address()); User32.RegisterClassExW(wx); // create message-only window @@ -232,10 +232,10 @@ private void monitorDevices() { throw new USBException("internal error (CreateWindowExW)", Kernel32.GetLastError()); // configure notifications - var notificationFilter = session.allocate(_DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); - _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$set(notificationFilter, (int) notificationFilter.byteSize()); - _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$set(notificationFilter, User32.DBT_DEVTYP_DEVICEINTERFACE()); - _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid$slice(notificationFilter).copyFrom(USBHelper.GUID_DEVINTERFACE_USB_DEVICE); + var notificationFilter = session.allocate(DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); + DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$set(notificationFilter, (int) notificationFilter.byteSize()); + DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$set(notificationFilter, User32.DBT_DEVTYP_DEVICEINTERFACE()); + DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid$slice(notificationFilter).copyFrom(USBHelper.GUID_DEVINTERFACE_USB_DEVICE); var notifyHandle = User32.RegisterDeviceNotificationW(hwnd, notificationFilter, User32.DEVICE_NOTIFY_WINDOW_HANDLE()); if (notifyHandle == NULL) @@ -248,7 +248,7 @@ private void monitorDevices() { signalEnumerationComplete(); // process messages - var msg = session.allocate(tagMSG.$LAYOUT()); + var msg = session.allocate(MSG.$LAYOUT()); while (User32.GetMessageW(msg, hwnd, 0, 0) > 0) ; // do nothing @@ -262,11 +262,11 @@ private long handleWindowMessage(MemoryAddress hWnd, int uMsg, long wParam, l // check for message related to connecting/disconnecting devices if (uMsg == User32.WM_DEVICECHANGE() && (wParam == User32.DBT_DEVICEARRIVAL() || wParam == User32.DBT_DEVICEREMOVECOMPLETE())) { try (var session = MemorySession.openConfined()) { - var data = MemorySegment.ofAddress(MemoryAddress.ofLong(lParam), _DEV_BROADCAST_DEVICEINTERFACE_W.sizeof(), session); - if (_DEV_BROADCAST_HDR.dbch_devicetype$get(data) == User32.DBT_DEVTYP_DEVICEINTERFACE()) { + var data = MemorySegment.ofAddress(MemoryAddress.ofLong(lParam), DEV_BROADCAST_DEVICEINTERFACE_W.sizeof(), session); + if (DEV_BROADCAST_HDR.dbch_devicetype$get(data) == User32.DBT_DEVTYP_DEVICEINTERFACE()) { // get device path - var nameSlice = MemorySegment.ofAddress(_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address(), 500, session); + var nameSlice = MemorySegment.ofAddress(DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address(), 500, session); var devicePath = Win.createStringFromSegment(nameSlice); if (wParam == User32.DBT_DEVICEARRIVAL()) onDeviceConnected(devicePath); @@ -294,14 +294,14 @@ private void onDeviceConnected(String devicePath) { // ensure the result is destroyed when the scope is left session.addCloseAction(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); - var devIntfData = session.allocate(_SP_DEVICE_INTERFACE_DATA.$LAYOUT()); - _SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); + var devIntfData = session.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); + SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); var devicePathSegment = Win.createSegmentFromString(devicePath, session); if (SetupAPI.SetupDiOpenDeviceInterfaceW(devInfoSetHandle, devicePathSegment, 0, devIntfData) == 0) throw new USBException("internal error (SetupDiOpenDeviceInterfaceW)", Kernel32.GetLastError()); - var devInfo = session.allocate(_SP_DEVINFO_DATA.$LAYOUT()); - _SP_DEVINFO_DATA.cbSize$set(devInfo, (int) devInfo.byteSize()); + var devInfo = session.allocate(SP_DEVINFO_DATA.$LAYOUT()); + SP_DEVINFO_DATA.cbSize$set(devInfo, (int) devInfo.byteSize()); if (SetupAPI.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, NULL, 0, NULL, devInfo) == 0) { int err = Kernel32.GetLastError(); if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/GUID.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/GUID.java new file mode 100644 index 00000000..ea550f1d --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/GUID.java @@ -0,0 +1,9 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.kernel32; + +public class GUID extends _GUID { + +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DATA.java new file mode 100644 index 00000000..95322b6e --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DATA.java @@ -0,0 +1,9 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.setupapi; + +public class SP_DEVICE_INTERFACE_DATA extends _SP_DEVICE_INTERFACE_DATA { + +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java new file mode 100644 index 00000000..77a1e06d --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java @@ -0,0 +1,9 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.setupapi; + +public class SP_DEVICE_INTERFACE_DETAIL_DATA_W extends _SP_DEVICE_INTERFACE_DETAIL_DATA_W { + +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVINFO_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVINFO_DATA.java new file mode 100644 index 00000000..89a49f0d --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVINFO_DATA.java @@ -0,0 +1,9 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.setupapi; + +public class SP_DEVINFO_DATA extends _SP_DEVINFO_DATA { + +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java deleted file mode 100644 index 892dd93d..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java +++ /dev/null @@ -1,171 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.usbioctl; - -import java.lang.foreign.*; -import java.lang.invoke.VarHandle; -public class _USB_NODE_CONNECTION_INFORMATION_EX { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_LONG$LAYOUT.withName("ConnectionIndex"), - MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("bLength"), - Constants$root.C_CHAR$LAYOUT.withName("bDescriptorType"), - Constants$root.C_SHORT$LAYOUT.withName("bcdUSB"), - Constants$root.C_CHAR$LAYOUT.withName("bDeviceClass"), - Constants$root.C_CHAR$LAYOUT.withName("bDeviceSubClass"), - Constants$root.C_CHAR$LAYOUT.withName("bDeviceProtocol"), - Constants$root.C_CHAR$LAYOUT.withName("bMaxPacketSize0"), - Constants$root.C_SHORT$LAYOUT.withName("idVendor"), - Constants$root.C_SHORT$LAYOUT.withName("idProduct"), - Constants$root.C_SHORT$LAYOUT.withName("bcdDevice"), - Constants$root.C_CHAR$LAYOUT.withName("iManufacturer"), - Constants$root.C_CHAR$LAYOUT.withName("iProduct"), - Constants$root.C_CHAR$LAYOUT.withName("iSerialNumber"), - Constants$root.C_CHAR$LAYOUT.withName("bNumConfigurations") - ).withName("DeviceDescriptor"), - Constants$root.C_CHAR$LAYOUT.withName("CurrentConfigurationValue"), - Constants$root.C_CHAR$LAYOUT.withName("Speed"), - Constants$root.C_CHAR$LAYOUT.withName("DeviceIsHub"), - Constants$root.C_SHORT$LAYOUT.withName("DeviceAddress"), - Constants$root.C_LONG$LAYOUT.withName("NumberOfOpenPipes"), - Constants$root.C_LONG$LAYOUT.withName("ConnectionStatus"), - MemoryLayout.sequenceLayout(0, MemoryLayout.structLayout( - MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("bLength"), - Constants$root.C_CHAR$LAYOUT.withName("bDescriptorType"), - Constants$root.C_CHAR$LAYOUT.withName("bEndpointAddress"), - Constants$root.C_CHAR$LAYOUT.withName("bmAttributes"), - Constants$root.C_SHORT$LAYOUT.withName("wMaxPacketSize"), - Constants$root.C_CHAR$LAYOUT.withName("bInterval") - ).withName("EndpointDescriptor"), - Constants$root.C_LONG$LAYOUT.withName("ScheduleOffset") - ).withName("_USB_PIPE_INFO")).withName("PipeList") - ).withName("_USB_NODE_CONNECTION_INFORMATION_EX"); - public static MemoryLayout $LAYOUT() { - return _USB_NODE_CONNECTION_INFORMATION_EX.$struct$LAYOUT; - } - static final VarHandle ConnectionIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ConnectionIndex")); - public static VarHandle ConnectionIndex$VH() { - return _USB_NODE_CONNECTION_INFORMATION_EX.ConnectionIndex$VH; - } - public static int ConnectionIndex$get(MemorySegment seg) { - return (int)_USB_NODE_CONNECTION_INFORMATION_EX.ConnectionIndex$VH.get(seg); - } - public static void ConnectionIndex$set( MemorySegment seg, int x) { - _USB_NODE_CONNECTION_INFORMATION_EX.ConnectionIndex$VH.set(seg, x); - } - public static int ConnectionIndex$get(MemorySegment seg, long index) { - return (int)_USB_NODE_CONNECTION_INFORMATION_EX.ConnectionIndex$VH.get(seg.asSlice(index*sizeof())); - } - public static void ConnectionIndex$set(MemorySegment seg, long index, int x) { - _USB_NODE_CONNECTION_INFORMATION_EX.ConnectionIndex$VH.set(seg.asSlice(index*sizeof()), x); - } - public static MemorySegment DeviceDescriptor$slice(MemorySegment seg) { - return seg.asSlice(4, 18); - } - static final VarHandle CurrentConfigurationValue$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CurrentConfigurationValue")); - public static VarHandle CurrentConfigurationValue$VH() { - return _USB_NODE_CONNECTION_INFORMATION_EX.CurrentConfigurationValue$VH; - } - public static byte CurrentConfigurationValue$get(MemorySegment seg) { - return (byte)_USB_NODE_CONNECTION_INFORMATION_EX.CurrentConfigurationValue$VH.get(seg); - } - public static void CurrentConfigurationValue$set( MemorySegment seg, byte x) { - _USB_NODE_CONNECTION_INFORMATION_EX.CurrentConfigurationValue$VH.set(seg, x); - } - public static byte CurrentConfigurationValue$get(MemorySegment seg, long index) { - return (byte)_USB_NODE_CONNECTION_INFORMATION_EX.CurrentConfigurationValue$VH.get(seg.asSlice(index*sizeof())); - } - public static void CurrentConfigurationValue$set(MemorySegment seg, long index, byte x) { - _USB_NODE_CONNECTION_INFORMATION_EX.CurrentConfigurationValue$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle Speed$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Speed")); - public static VarHandle Speed$VH() { - return _USB_NODE_CONNECTION_INFORMATION_EX.Speed$VH; - } - public static byte Speed$get(MemorySegment seg) { - return (byte)_USB_NODE_CONNECTION_INFORMATION_EX.Speed$VH.get(seg); - } - public static void Speed$set( MemorySegment seg, byte x) { - _USB_NODE_CONNECTION_INFORMATION_EX.Speed$VH.set(seg, x); - } - public static byte Speed$get(MemorySegment seg, long index) { - return (byte)_USB_NODE_CONNECTION_INFORMATION_EX.Speed$VH.get(seg.asSlice(index*sizeof())); - } - public static void Speed$set(MemorySegment seg, long index, byte x) { - _USB_NODE_CONNECTION_INFORMATION_EX.Speed$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle DeviceIsHub$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceIsHub")); - public static VarHandle DeviceIsHub$VH() { - return _USB_NODE_CONNECTION_INFORMATION_EX.DeviceIsHub$VH; - } - public static byte DeviceIsHub$get(MemorySegment seg) { - return (byte)_USB_NODE_CONNECTION_INFORMATION_EX.DeviceIsHub$VH.get(seg); - } - public static void DeviceIsHub$set( MemorySegment seg, byte x) { - _USB_NODE_CONNECTION_INFORMATION_EX.DeviceIsHub$VH.set(seg, x); - } - public static byte DeviceIsHub$get(MemorySegment seg, long index) { - return (byte)_USB_NODE_CONNECTION_INFORMATION_EX.DeviceIsHub$VH.get(seg.asSlice(index*sizeof())); - } - public static void DeviceIsHub$set(MemorySegment seg, long index, byte x) { - _USB_NODE_CONNECTION_INFORMATION_EX.DeviceIsHub$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle DeviceAddress$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceAddress")); - public static VarHandle DeviceAddress$VH() { - return _USB_NODE_CONNECTION_INFORMATION_EX.DeviceAddress$VH; - } - public static short DeviceAddress$get(MemorySegment seg) { - return (short)_USB_NODE_CONNECTION_INFORMATION_EX.DeviceAddress$VH.get(seg); - } - public static void DeviceAddress$set( MemorySegment seg, short x) { - _USB_NODE_CONNECTION_INFORMATION_EX.DeviceAddress$VH.set(seg, x); - } - public static short DeviceAddress$get(MemorySegment seg, long index) { - return (short)_USB_NODE_CONNECTION_INFORMATION_EX.DeviceAddress$VH.get(seg.asSlice(index*sizeof())); - } - public static void DeviceAddress$set(MemorySegment seg, long index, short x) { - _USB_NODE_CONNECTION_INFORMATION_EX.DeviceAddress$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle NumberOfOpenPipes$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("NumberOfOpenPipes")); - public static VarHandle NumberOfOpenPipes$VH() { - return _USB_NODE_CONNECTION_INFORMATION_EX.NumberOfOpenPipes$VH; - } - public static int NumberOfOpenPipes$get(MemorySegment seg) { - return (int)_USB_NODE_CONNECTION_INFORMATION_EX.NumberOfOpenPipes$VH.get(seg); - } - public static void NumberOfOpenPipes$set( MemorySegment seg, int x) { - _USB_NODE_CONNECTION_INFORMATION_EX.NumberOfOpenPipes$VH.set(seg, x); - } - public static int NumberOfOpenPipes$get(MemorySegment seg, long index) { - return (int)_USB_NODE_CONNECTION_INFORMATION_EX.NumberOfOpenPipes$VH.get(seg.asSlice(index*sizeof())); - } - public static void NumberOfOpenPipes$set(MemorySegment seg, long index, int x) { - _USB_NODE_CONNECTION_INFORMATION_EX.NumberOfOpenPipes$VH.set(seg.asSlice(index*sizeof()), x); - } - static final VarHandle ConnectionStatus$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ConnectionStatus")); - public static VarHandle ConnectionStatus$VH() { - return _USB_NODE_CONNECTION_INFORMATION_EX.ConnectionStatus$VH; - } - public static int ConnectionStatus$get(MemorySegment seg) { - return (int)_USB_NODE_CONNECTION_INFORMATION_EX.ConnectionStatus$VH.get(seg); - } - public static void ConnectionStatus$set( MemorySegment seg, int x) { - _USB_NODE_CONNECTION_INFORMATION_EX.ConnectionStatus$VH.set(seg, x); - } - public static int ConnectionStatus$get(MemorySegment seg, long index) { - return (int)_USB_NODE_CONNECTION_INFORMATION_EX.ConnectionStatus$VH.get(seg.asSlice(index*sizeof())); - } - public static void ConnectionStatus$set(MemorySegment seg, long index, int x) { - _USB_NODE_CONNECTION_INFORMATION_EX.ConnectionStatus$VH.set(seg.asSlice(index*sizeof()), x); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_DEVICEINTERFACE_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_DEVICEINTERFACE_W.java new file mode 100644 index 00000000..42c68946 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_DEVICEINTERFACE_W.java @@ -0,0 +1,9 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.user32; + +public class DEV_BROADCAST_DEVICEINTERFACE_W extends _DEV_BROADCAST_DEVICEINTERFACE_W { + +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_HDR.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_HDR.java new file mode 100644 index 00000000..bc2a60af --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_HDR.java @@ -0,0 +1,9 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.user32; + +public class DEV_BROADCAST_HDR extends _DEV_BROADCAST_HDR { + +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/MSG.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/MSG.java new file mode 100644 index 00000000..2cff5412 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/MSG.java @@ -0,0 +1,9 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.user32; + +public class MSG extends tagMSG { + +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/WNDCLASSEXW.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/WNDCLASSEXW.java new file mode 100644 index 00000000..b09b0cfc --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/WNDCLASSEXW.java @@ -0,0 +1,9 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.user32; + +public class WNDCLASSEXW extends tagWNDCLASSEXW { + +} + + From 5ca47136bc2a61288b196f125788f31130c79508 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Wed, 31 Aug 2022 21:26:35 +0200 Subject: [PATCH 028/433] macOS: Use pre-built jextract binaries --- java-does-usb/jextract/README.md | 7 ++++++- java-does-usb/jextract/gen_macos.sh | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index 82a12f04..bd23301e 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -1,6 +1,6 @@ # Code Generation with *jextract* -Some of the binding code for accessing native functions and data structures is generated with [jextract](https://jdk.java.net/jextract/). The tool is still under construction and has its limitations. +Some of the binding code for accessing native functions and data structures is generated with [jextract](https://jdk.java.net/jextract/). The tool is still under construction and has its limitations. In order to generate the code, the scripts in this directory have to be run (`gen_linux.sh`, `gen_macos.sh` and `gen_win_xxx.cmd`). Each script has to be run on that particular operating system. @@ -11,6 +11,11 @@ The scripts explicitly specify the functions, structs etc. to include as generat The resulting code is then committed to the source code repository. Before the commit, imports are cleaned up to get rid of superfluous imports. Most IDEs provide a convenient command to execute this on entire directories. +## General limitations + +- Binaries of *jextract* can be downloaded from https://jdk.java.net/jextract/. Only x64 binaries are available. It is unclear if the x64 jextract run on macOS with Apple Silicon (ARM64) using the Rosetta emulator produces valid bindings. So far, not problems have been detected. + + ## Linux To run the script, most likely the header files for *libudev* must be installed (the library itself is most likely already installed): diff --git a/java-does-usb/jextract/gen_macos.sh b/java-does-usb/jextract/gen_macos.sh index 31907319..bfdd2698 100755 --- a/java-does-usb/jextract/gen_macos.sh +++ b/java-does-usb/jextract/gen_macos.sh @@ -1,6 +1,6 @@ #!/bin/sh -JEXTRACT=../../../jextract/build/jextract/bin/jextract +JEXTRACT=../../../jextract-19/bin/jextract SDK_DIR=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk # CoreFoundation From 3659bf52b179ef0101fb05410da402b0135ba593 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Wed, 31 Aug 2022 21:29:30 +0200 Subject: [PATCH 029/433] macOS: Remove unnecessary function --- java-does-usb/jextract/gen_macos.sh | 1 - .../codecrete/usb/macos/gen/mach/constants$0.java | 8 -------- .../java/net/codecrete/usb/macos/gen/mach/mach.java | 12 ------------ 3 files changed, 21 deletions(-) diff --git a/java-does-usb/jextract/gen_macos.sh b/java-does-usb/jextract/gen_macos.sh index bfdd2698..ce77e369 100755 --- a/java-does-usb/jextract/gen_macos.sh +++ b/java-does-usb/jextract/gen_macos.sh @@ -15,6 +15,5 @@ $JEXTRACT --source --output ../src/main/java \ -I $SDK_DIR/usr/include \ --header-class-name mach \ --target-package net.codecrete.usb.macos.gen.mach \ - --include-function mach_error \ --include-function mach_error_string \ $SDK_DIR/usr/include/mach/mach.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java index 3d61da92..00707d13 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java @@ -13,14 +13,6 @@ class constants$0 { "mach_error_string", constants$0.mach_error_string$FUNC ); - static final FunctionDescriptor mach_error$FUNC = FunctionDescriptor.ofVoid( - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle mach_error$MH = RuntimeHelper.downcallHandle( - "mach_error", - constants$0.mach_error$FUNC - ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java index 8e162bc9..6b42d952 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java @@ -2,7 +2,6 @@ package net.codecrete.usb.macos.gen.mach; -import java.lang.foreign.Addressable; import java.lang.foreign.MemoryAddress; import java.lang.invoke.MethodHandle; @@ -29,17 +28,6 @@ public static MemoryAddress mach_error_string ( int error_value) { throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle mach_error$MH() { - return RuntimeHelper.requireNonNull(constants$0.mach_error$MH,"mach_error"); - } - public static void mach_error ( Addressable str, int error_value) { - var mh$ = mach_error$MH(); - try { - mh$.invokeExact(str, error_value); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } } From 16fbdff59c92ee8add59c386f7993c574390164f Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Wed, 31 Aug 2022 21:57:14 +0200 Subject: [PATCH 030/433] Factor out common registry code --- .../src/main/java/net/codecrete/usb/USB.java | 4 +- .../usb/common/USBDeviceRegistry.java | 80 +++++++++- .../usb/linux/LinuxUSBDeviceRegistry.java | 119 ++++++-------- .../usb/macos/MacosUSBDeviceRegistry.java | 124 +++++++-------- .../usb/windows/WindowsUSBDeviceRegistry.java | 148 ++++++++---------- 5 files changed, 245 insertions(+), 230 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USB.java b/java-does-usb/src/main/java/net/codecrete/usb/USB.java index 5f9b7d35..86cef6c9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USB.java @@ -41,8 +41,10 @@ private static USBDeviceRegistry createInstance() { private static USBDeviceRegistry _instance = null; private static synchronized USBDeviceRegistry instance() { - if (_instance == null) + if (_instance == null) { _instance = createInstance(); + _instance.start(); + } return _instance; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index f5529efa..c4ee6007 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -10,6 +10,7 @@ import net.codecrete.usb.USBDeviceInfo; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; @@ -17,18 +18,55 @@ import java.util.function.Consumer; /** - * USB device registry. + * Base class for USB device registry. + *

+ * This singleton class maintains a list of connected USB devices. + * It starts a background thread monitoring the USB devices being + * connected and disconnected. + *

+ *

+ * The background thread enumerates the already present devices + * and builds the initial device list. + *

*/ public abstract class USBDeviceRegistry { - protected volatile List devices; + private volatile List devices; protected Consumer onDeviceConnectedHandler; protected Consumer onDeviceDisconnectedHandler; private final Lock lock = new ReentrantLock(); private final Condition enumerationComplete = lock.newCondition(); - public abstract List getAllDevices(); + /** + * Start this device registry. + *

+ * This method blocks until the initial device enumeration has + * completed. + *

+ */ + public void start() { + startDeviceMonitor(this::monitorDevices); + } + + /** + * Enumerate the already present devices and then start monitoring + * devices being connected and disconnected. + *

+ * Implementors of this method are expected to call, {@link #setInitialDeviceList(List)} + * after the initial device implementation. + *

+ */ + protected abstract void monitorDevices(); + + /** + * Gets the list of the currently connected USB devices. + * + * @return list of devices + */ + public List getAllDevices() { + return Collections.unmodifiableList(devices); + } public void setOnDeviceConnected(Consumer handler) { onDeviceConnectedHandler = handler; @@ -50,6 +88,12 @@ protected void emitOnDeviceDisconnected(USBDeviceInfo device) { /** * Starts the background thread and waits until the first device enumeration is complete. + *

+ * In order to signal that the initial enumeration is complete, the monitor task is expected + * to call {@link #setInitialDeviceList(List)}. + *

+ * + * @param monitorTask the task to start in the background */ protected void startDeviceMonitor(Runnable monitorTask) { // start new thread @@ -71,7 +115,7 @@ protected void startDeviceMonitor(Runnable monitorTask) { /** * Signals completion of initial device enumeration. */ - protected void signalEnumerationComplete() { + private void signalEnumerationComplete() { lock.lock(); try { enumerationComplete.signalAll(); @@ -80,9 +124,27 @@ protected void signalEnumerationComplete() { } } + /** + * Sets the device list of the initial device enumeration. + *

+ * This function singals to the spawning thread that the enumeration is complete. + *

+ * + * @param deviceList the device list + */ + protected void setInitialDeviceList(List deviceList) { + devices = deviceList; + signalEnumerationComplete(); + } + + /** + * Adds a device to the list of connected USB devices. + * + * @param device device to add + */ protected void addDevice(USBDeviceInfo device) { // check for duplicates - if (findDeviceIndex(devices, ((USBDeviceInfoImpl)device).getUniqueId()) >= 0) + if (findDeviceIndex(devices, ((USBDeviceInfoImpl) device).getUniqueId()) >= 0) return; // copy list @@ -95,6 +157,11 @@ protected void addDevice(USBDeviceInfo device) { emitOnDeviceConnected(device); } + /** + * Removes a device from the list of connected USB devices. + * + * @param deviceId the unique ID of the device to remove + */ protected void removeDevice(Object deviceId) { // locate device to be removed int index = findDeviceIndex(devices, deviceId); @@ -113,8 +180,9 @@ protected void removeDevice(Object deviceId) { /** * Finds the index of the device with the given ID in the device list + * * @param deviceList the device list - * @param deviceId the unique device ID + * @param deviceId the unique device ID * @return return the index, or -1 if the device is not found */ protected int findDeviceIndex(List deviceList, Object deviceId) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index d2826d07..de5eb7bf 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -26,15 +26,6 @@ /** * Linux implementation of USB device registry. - *

- * This singleton class maintains a list of connected USB devices. - * It starts a background thread monitoring the USB devices being - * connected and disconnected. - *

- *

- * The background thread also enumerates the already present devices - * and builds the initial device list. - *

*/ public class LinuxUSBDeviceRegistry extends USBDeviceRegistry { @@ -42,66 +33,8 @@ public class LinuxUSBDeviceRegistry extends USBDeviceRegistry { private static final MemorySegment MONITOR_NAME = MemorySession.global().allocateUtf8String("udev"); private static final MemorySegment DEVTYPE_USB_DEVICE = MemorySession.global().allocateUtf8String("usb_device"); - /** - * Creates a new instance. - */ - public LinuxUSBDeviceRegistry() { - startDeviceMonitor(this::monitorDevices); - } - @Override - public List getAllDevices() { - return devices; - } - - private void enumeratePresentDevices(Addressable udevInstance) { - List result = new ArrayList<>(); - try (var outerSession = MemorySession.openConfined()) { - - // create device enumerator - var enumerate = udev.udev_enumerate_new(udevInstance); - if (enumerate == NULL) - throw new USBException("internal error (udev_enumerate_new)"); - - outerSession.addCloseAction(() -> udev.udev_enumerate_unref(enumerate)); - - if (udev.udev_enumerate_add_match_subsystem(enumerate, SUBSYSTEM_USB) < 0) - throw new USBException("internal error (udev_enumerate_add_match_subsystem)"); - - if (udev.udev_enumerate_scan_devices(enumerate) < 0) - throw new USBException("internal error (udev_enumerate_scan_devices)"); - - // enumerate devices - for (var entry = udev.udev_enumerate_get_list_entry(enumerate); - entry != NULL; - entry = udev.udev_list_entry_get_next(entry)) { - - try (var session = MemorySession.openConfined()) { - - var path = udev.udev_list_entry_get_name(entry); - if (path == NULL) - continue; - - // get device handle - var dev = udev.udev_device_new_from_syspath(udevInstance, path); - if (dev == NULL) - continue; - - // ensure the device is released - session.addCloseAction(() -> udev.udev_device_unref(dev)); - - // get device details - var deviceInfo = getDeviceDetails(dev); - if (deviceInfo != null) - result.add(deviceInfo); - } - } - } - - devices = result; - } - - private void monitorDevices() { + protected void monitorDevices() { // setup udev monitor var udevInstance = udev.udev_new(); @@ -125,9 +58,6 @@ private void monitorDevices() { // create initial list of devices enumeratePresentDevices(udevInstance); - // signal initial enumeration is complete - signalEnumerationComplete(); - // monitor device changes while (true) { try (var session = MemorySession.openConfined()) { @@ -154,6 +84,53 @@ private void monitorDevices() { } } + private void enumeratePresentDevices(Addressable udevInstance) { + List result = new ArrayList<>(); + try (var outerSession = MemorySession.openConfined()) { + + // create device enumerator + var enumerate = udev.udev_enumerate_new(udevInstance); + if (enumerate == NULL) + throw new USBException("internal error (udev_enumerate_new)"); + + outerSession.addCloseAction(() -> udev.udev_enumerate_unref(enumerate)); + + if (udev.udev_enumerate_add_match_subsystem(enumerate, SUBSYSTEM_USB) < 0) + throw new USBException("internal error (udev_enumerate_add_match_subsystem)"); + + if (udev.udev_enumerate_scan_devices(enumerate) < 0) + throw new USBException("internal error (udev_enumerate_scan_devices)"); + + // enumerate devices + for (var entry = udev.udev_enumerate_get_list_entry(enumerate); + entry != NULL; + entry = udev.udev_list_entry_get_next(entry)) { + + try (var session = MemorySession.openConfined()) { + + var path = udev.udev_list_entry_get_name(entry); + if (path == NULL) + continue; + + // get device handle + var dev = udev.udev_device_new_from_syspath(udevInstance, path); + if (dev == NULL) + continue; + + // ensure the device is released + session.addCloseAction(() -> udev.udev_device_unref(dev)); + + // get device details + var deviceInfo = getDeviceDetails(dev); + if (deviceInfo != null) + result.add(deviceInfo); + } + } + } + + setInitialDeviceList(result); + } + private void onDeviceConnected(MemoryAddress device) { var deviceInfo = getDeviceDetails(device); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 194ae049..35e51254 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -15,7 +15,6 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.ArrayList; -import java.util.List; import java.util.function.BiConsumer; import static java.lang.foreign.MemoryAddress.NULL; @@ -23,33 +22,65 @@ /** * MacOS implementation of USB device registry. - *

- * This singleton class maintains a list of connected USB devices. - * It starts a background thread monitoring the USB devices being - * connected and disconnected. - *

- *

- * The background thread also creates the initial devices list as - * setting up the notifications will initially deliver the connected - * devices anyway. - *

*/ public class MacosUSBDeviceRegistry extends USBDeviceRegistry { - public MacosUSBDeviceRegistry() { - startDeviceMonitor(this::monitorDevices); - } + /** + * Monitors the USB devices. + *

+ * This method is the core of the background thread. It runs forever and does not terminate. + *

+ */ + @Override + protected void monitorDevices() { + + // as the method runs forever, there is no need to clean up one-time allocations + try (var session = MemorySession.openConfined()) { + + // setup run loop, run loop source and notification port + var notifyPort = IoKit.IONotificationPortCreate(IoKit.kIOMasterPortDefault); + var runLoopSource = IoKit.IONotificationPortGetRunLoopSource(notifyPort); + var runLoop = CoreFoundation.CFRunLoopGetCurrent(); + CoreFoundation.CFRunLoopAddSource(runLoop, runLoopSource, IoKit.kCFRunLoopDefaultMode); + + // setup notification for connected devices + var onDeviceConnectedMH = MethodHandles.lookup().findVirtual( + MacosUSBDeviceRegistry.class, "onDevicesConnected", + MethodType.methodType(void.class, MemoryAddress.class, int.class)); + int deviceConnectedIter = setupNotification(session, notifyPort, IoKit.kIOFirstMatchNotification, onDeviceConnectedMH); + + // iterate current devices in order to arm the notifications (and build initial device list) + var deviceList = new ArrayList(); + iterateDevices(deviceConnectedIter, false, (entryId, service) -> { + var deviceInfo = createDeviceInfo(entryId, service); + if (deviceInfo != null) + deviceList.add(deviceInfo); + }); + setInitialDeviceList(deviceList); + + // setup notification for disconnected devices + var onDeviceDisconnectedMH = MethodHandles.lookup().findVirtual( + MacosUSBDeviceRegistry.class, "onDevicesDisconnected", + MethodType.methodType(void.class, MemoryAddress.class, int.class)); + int deviceDisconnectedIter = setupNotification(session, notifyPort, IoKit.kIOTerminatedNotification, onDeviceDisconnectedMH); - public List getAllDevices() { - return devices; + // iterate current devices in order to arm the notifications + onDevicesDisconnected(NULL, deviceDisconnectedIter); + + // loop forever + CoreFoundation.CFRunLoopRun(); + + } catch (NoSuchMethodException | IllegalAccessException e) { + throw new RuntimeException(e); + } } /** * Process the devices resulting from the iterator * - * @param iterator the iterator + * @param iterator the iterator * @param isDisconnected flag is the iterator is for disconnected devices - * @param function a function that will be called for each device with the entry ID and the service + * @param function a function that will be called for each device with the entry ID and the service */ private void iterateDevices(int iterator, boolean isDisconnected, BiConsumer function) { @@ -98,57 +129,6 @@ private USBDeviceInfo createDeviceInfo(Long entryID, int service) { return new MacosUSBDeviceInfo(entryID, vendorId, productId, manufacturer, product, serial, classCode, subclassCode, protocolCode); } - /** - * Monitors the USB devices. - *

- * This method is the core of the background thread. It runs forever and does not terminate. - *

- */ - private void monitorDevices() { - - // as the method runs forever, there is no need to clean up one-time allocations - try (var session = MemorySession.openConfined()) { - - // setup run loop, run loop source and notification port - var notifyPort = IoKit.IONotificationPortCreate(IoKit.kIOMasterPortDefault); - var runLoopSource = IoKit.IONotificationPortGetRunLoopSource(notifyPort); - var runLoop = CoreFoundation.CFRunLoopGetCurrent(); - CoreFoundation.CFRunLoopAddSource(runLoop, runLoopSource, IoKit.kCFRunLoopDefaultMode); - - // setup notification for connected devices - var onDeviceConnectedMH = MethodHandles.lookup().findVirtual( - MacosUSBDeviceRegistry.class, "onDevicesConnected", - MethodType.methodType(void.class, MemoryAddress.class, int.class)); - int deviceConnectedIter = setupNotification(session, notifyPort, IoKit.kIOFirstMatchNotification, onDeviceConnectedMH); - - // iterate current devices in order to arm the notifications (and build initial device list) - devices = new ArrayList<>(); - iterateDevices(deviceConnectedIter, false, (entryId, service) -> { - var deviceInfo = createDeviceInfo(entryId, service); - if (deviceInfo != null) - devices.add(deviceInfo); - }); - - // signal completion of initial device enumeration - signalEnumerationComplete(); - - // setup notification for disconnected devices - var onDeviceDisconnectedMH = MethodHandles.lookup().findVirtual( - MacosUSBDeviceRegistry.class, "onDevicesDisconnected", - MethodType.methodType(void.class, MemoryAddress.class, int.class)); - int deviceDisconnectedIter = setupNotification(session, notifyPort, IoKit.kIOTerminatedNotification, onDeviceDisconnectedMH); - - // iterate current devices in order to arm the notifications - onDevicesDisconnected(NULL, deviceDisconnectedIter); - - // loop forever - CoreFoundation.CFRunLoopRun(); - - } catch (NoSuchMethodException | IllegalAccessException e) { - throw new RuntimeException(e); - } - } - private int setupNotification(MemorySession session, MemoryAddress notifyPort, MemorySegment notificationType, MethodHandle callback) throws NoSuchMethodException, IllegalAccessException { @@ -178,8 +158,9 @@ private int setupNotification(MemorySession session, MemoryAddress notifyPort, M *

* This method is used in an upcall from native code. *

+ * * @param ignoredRefCon ignored parameter - * @param iterator device iterator + * @param iterator device iterator */ private void onDevicesConnected(MemoryAddress ignoredRefCon, int iterator) { @@ -196,8 +177,9 @@ private void onDevicesConnected(MemoryAddress ignoredRefCon, int iterator) { *

* This method is used in an upcall from native code. *

+ * * @param ignoredRefCon ignored parameter - * @param iterator device iterator + * @param iterator device iterator */ private void onDevicesDisconnected(MemoryAddress ignoredRefCon, int iterator) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 7fb8deab..8b75b901 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -32,30 +32,64 @@ /** * Windows implementation of USB device registry. - *

- * This singleton class maintains a list of connected USB devices. - * It starts a background thread monitoring the USB devices being - * connected and disconnected. - *

- *

- * The background thread also enumerates the already present devices - * and builds the initial device list. - *

*/ public class WindowsUSBDeviceRegistry extends USBDeviceRegistry { - /** - * Create new instance - *

- * Starts a second thread and immediately iterates all USB devices. - *

- */ - public WindowsUSBDeviceRegistry() { - startDeviceMonitor(this::monitorDevices); - } + @Override + protected void monitorDevices() { + try (var session = MemorySession.openConfined()) { + + final var className = Win.createSegmentFromString("USB_MONITOR", session); + final var windowName = Win.createSegmentFromString("USB device monitor", session); + final var instance = Kernel32.GetModuleHandleW(NULL); + + // create upcall for handling window messages + var handleWindowMessageMH = MethodHandles.lookup().findVirtual( + WindowsUSBDeviceRegistry.class, + "handleWindowMessage", + MethodType.methodType(long.class, MemoryAddress.class, int.class, long.class, long.class) + ).bindTo(this); + var handleWindowMessageStub = Linker.nativeLinker().upcallStub( + handleWindowMessageMH, + FunctionDescriptor.of(JAVA_LONG, ADDRESS, JAVA_INT, JAVA_LONG, JAVA_LONG), + session + ); - public List getAllDevices() { - return devices; + // register window class + var wx = session.allocate(WNDCLASSEXW.$LAYOUT()); + WNDCLASSEXW.cbSize$set(wx, (int) wx.byteSize()); + WNDCLASSEXW.lpfnWndProc$set(wx, handleWindowMessageStub.address()); + WNDCLASSEXW.hInstance$set(wx, instance); + WNDCLASSEXW.lpszClassName$set(wx, className.address()); + User32.RegisterClassExW(wx); + + // create message-only window + Addressable hwnd = User32.CreateWindowExW(0, className, windowName, 0, + 0, 0, 0, 0, User32.HWND_MESSAGE(), NULL, instance, NULL); + if (hwnd == NULL) + throw new USBException("internal error (CreateWindowExW)", Kernel32.GetLastError()); + + // configure notifications + var notificationFilter = session.allocate(DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); + DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$set(notificationFilter, (int) notificationFilter.byteSize()); + DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$set(notificationFilter, User32.DBT_DEVTYP_DEVICEINTERFACE()); + DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid$slice(notificationFilter).copyFrom(USBHelper.GUID_DEVINTERFACE_USB_DEVICE); + + var notifyHandle = User32.RegisterDeviceNotificationW(hwnd, notificationFilter, User32.DEVICE_NOTIFY_WINDOW_HANDLE()); + if (notifyHandle == NULL) + throw new USBException("internal error (RegisterDeviceNotificationW)", Kernel32.GetLastError()); + + // initial device enumeration + enumeratePresentDevices(); + + // process messages + var msg = session.allocate(MSG.$LAYOUT()); + while (User32.GetMessageW(msg, hwnd, 0, 0) > 0) + ; // do nothing + + } catch (NoSuchMethodException | IllegalAccessException e) { + throw new RuntimeException(e); + } } private void enumeratePresentDevices() { @@ -96,7 +130,7 @@ private void enumeratePresentDevices() { deviceList.add(createDeviceInfo(devInfoSetHandle, devInfo, devicePath, hubHandles)); } - devices = deviceList; + setInitialDeviceList(deviceList); } } @@ -198,66 +232,7 @@ private String getStringDescriptor(Addressable hubHandle, int usbPortNumber, int } } - private void monitorDevices() { - try (var session = MemorySession.openConfined()) { - - final var className = Win.createSegmentFromString("USB_MONITOR", session); - final var windowName = Win.createSegmentFromString("USB device monitor", session); - final var instance = Kernel32.GetModuleHandleW(NULL); - - // create upcall for handling window messages - var handleWindowMessageMH = MethodHandles.lookup().findVirtual( - WindowsUSBDeviceRegistry.class, - "handleWindowMessage", - MethodType.methodType(long.class, MemoryAddress.class, int.class, long.class, long.class) - ).bindTo(this); - var handleWindowMessageStub = Linker.nativeLinker().upcallStub( - handleWindowMessageMH, - FunctionDescriptor.of(JAVA_LONG, ADDRESS, JAVA_INT, JAVA_LONG, JAVA_LONG), - session - ); - - // register window class - var wx = session.allocate(WNDCLASSEXW.$LAYOUT()); - WNDCLASSEXW.cbSize$set(wx, (int) wx.byteSize()); - WNDCLASSEXW.lpfnWndProc$set(wx, handleWindowMessageStub.address()); - WNDCLASSEXW.hInstance$set(wx, instance); - WNDCLASSEXW.lpszClassName$set(wx, className.address()); - User32.RegisterClassExW(wx); - - // create message-only window - Addressable hwnd = User32.CreateWindowExW(0, className, windowName, 0, - 0, 0, 0, 0, User32.HWND_MESSAGE(), NULL, instance, NULL); - if (hwnd == NULL) - throw new USBException("internal error (CreateWindowExW)", Kernel32.GetLastError()); - - // configure notifications - var notificationFilter = session.allocate(DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); - DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$set(notificationFilter, (int) notificationFilter.byteSize()); - DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$set(notificationFilter, User32.DBT_DEVTYP_DEVICEINTERFACE()); - DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid$slice(notificationFilter).copyFrom(USBHelper.GUID_DEVINTERFACE_USB_DEVICE); - - var notifyHandle = User32.RegisterDeviceNotificationW(hwnd, notificationFilter, User32.DEVICE_NOTIFY_WINDOW_HANDLE()); - if (notifyHandle == NULL) - throw new USBException("internal error (RegisterDeviceNotificationW)", Kernel32.GetLastError()); - - // initial device enumeration - enumeratePresentDevices(); - - // signal that the enumeration is complete - signalEnumerationComplete(); - - // process messages - var msg = session.allocate(MSG.$LAYOUT()); - while (User32.GetMessageW(msg, hwnd, 0, 0) > 0) - ; // do nothing - - } catch (NoSuchMethodException | IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - private long handleWindowMessage(MemoryAddress hWnd, int uMsg, long wParam, long lParam) { + private long handleWindowMessage(MemoryAddress hWnd, int uMsg, long wParam, long lParam) { // check for message related to connecting/disconnecting devices if (uMsg == User32.WM_DEVICECHANGE() && (wParam == User32.DBT_DEVICEARRIVAL() || wParam == User32.DBT_DEVICEREMOVECOMPLETE())) { @@ -325,6 +300,17 @@ private void onDeviceDisconnected(String devicePath) { removeDevice(devicePath); } + /** + * Finds the index of the device in the list. + *

+ * This override uses a case-insensitive string comparison as Windows uses different casing + * when initially enumerating devices and during later monitoring. + *

+ * + * @param deviceList the device list + * @param deviceId the unique device ID + * @return index, or -1 if not found + */ @Override protected int findDeviceIndex(List deviceList, Object deviceId) { var id = deviceId.toString(); From 317e4289a38b0437b3f81f764fb832cae5d70715 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Thu, 1 Sep 2022 20:27:49 +0200 Subject: [PATCH 031/433] Prepare for merge of USBDeviceInfo and USBDevice --- .../codecrete/usb/common/USBDeviceImpl.java | 2 + .../codecrete/usb/linux/LinuxUSBDevice.java | 22 ++++++--- .../usb/linux/LinuxUSBDeviceInfo.java | 4 +- .../codecrete/usb/macos/MacosUSBDevice.java | 46 ++++++++++++------- .../usb/macos/MacosUSBDeviceInfo.java | 4 +- .../usb/windows/WindowsUSBDevice.java | 35 ++++++++++---- .../usb/windows/WindowsUSBDeviceInfo.java | 4 +- 7 files changed, 82 insertions(+), 35 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 833ac2d5..6ce61be5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -44,6 +44,8 @@ protected USBDeviceImpl( this.protocolCode = info.getProtocolCode(); } + public abstract void open(); + public int getProductId() { return productId; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 119bc478..5bec9e65 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -26,10 +26,16 @@ public class LinuxUSBDevice extends USBDeviceImpl { - private final int fd; + private int fd = -1; LinuxUSBDevice(Object id, USBDeviceInfo info) { super(id, info); + } + + @Override + public void open() { + if (fd != -1) + return; try (var session = MemorySession.openConfined()) { var pathUtf8 = session.allocateUtf8String(id.toString()); @@ -39,6 +45,15 @@ public class LinuxUSBDevice extends USBDeviceImpl { } } + @Override + public void close() throws Exception { + if (fd == -1) + return; + + unistd.close(fd); + fd = -1; + } + public void claimInterface(int interfaceNumber) { try (var session = MemorySession.openConfined()) { var intfNumSegment = session.allocate(JAVA_INT, interfaceNumber); @@ -133,9 +148,4 @@ public byte[] transferIn(int endpointNumber, int maxLength) { return buffer.asSlice(0, res).toArray(JAVA_BYTE); } } - - @Override - public void close() throws Exception { - unistd.close(fd); - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceInfo.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceInfo.java index 45f9fd75..0116715d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceInfo.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceInfo.java @@ -24,7 +24,9 @@ public class LinuxUSBDeviceInfo extends USBDeviceInfoImpl { @Override public USBDevice open() { - return new LinuxUSBDevice(id, this); + var device = new LinuxUSBDevice(id, this); + device.open(); + return device; } Object devicePath() { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 3153465e..4b0a6929 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -25,18 +25,23 @@ public class MacosUSBDevice extends USBDeviceImpl { - private final MemoryAddress device; - private final int configurationValue; + private MemoryAddress device; + private int configurationValue; private List claimedInterfaces; private List endpoints; MacosUSBDevice(Object id, USBDeviceInfo info) { super(id, info); + } + + @Override + public void open() { + if (device != null) + return; try (var session = MemorySession.openConfined()) { -// // get service from IO registry -// final int service = IoKit.IORegistryEntryFromPath(0, path); + // get service from IO registry var matching = IoKit.IORegistryEntryIDMatching((Long) id); if (matching == NULL) throw new MacosUSBException("IORegistryEntryIDMatching failed"); @@ -56,6 +61,7 @@ public class MacosUSBDevice extends USBDeviceImpl { int ret = IoKitUSB.USBDeviceOpen(device); if (ret != 0) { IoKit.Release(device); + device = null; throw new MacosUSBException("unable to open USB device", ret); } @@ -78,11 +84,30 @@ public class MacosUSBDevice extends USBDeviceImpl { } catch (Throwable e) { IoKitUSB.USBDeviceClose(device); IoKit.Release(device); + device = null; + configurationValue = 0; throw e; } } } + @Override + public void close() throws Exception { + if (device == null) + return; + + if (claimedInterfaces != null) { + for (InterfaceInfo interfaceInfo : claimedInterfaces) { + IoKitUSB.USBInterfaceClose(interfaceInfo.asMemoryAddress()); + IoKit.Release(interfaceInfo.asMemoryAddress()); + } + } + + IoKitUSB.USBDeviceClose(device); + IoKit.Release(device); + device = null; + } + private InterfaceInfo findInterface(int interfaceNumber) { try (var outerSession = MemorySession.openConfined()) { @@ -292,19 +317,6 @@ public byte[] transferIn(int endpointNumber, int maxLength) { } } - @Override - public void close() throws Exception { - if (claimedInterfaces != null) { - for (InterfaceInfo interfaceInfo : claimedInterfaces) { - IoKitUSB.USBInterfaceClose(interfaceInfo.asMemoryAddress()); - IoKit.Release(interfaceInfo.asMemoryAddress()); - } - } - - IoKitUSB.USBDeviceClose(device); - IoKit.Release(device); - } - static class InterfaceInfo { long addr; int interfaceNumber; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceInfo.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceInfo.java index f988475b..18ff4ffb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceInfo.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceInfo.java @@ -24,7 +24,9 @@ public class MacosUSBDeviceInfo extends USBDeviceInfoImpl { @Override public USBDevice open() { - return new MacosUSBDevice(id, this); + var device = new MacosUSBDevice(id, this); + device.open(); + return device; } Object getId() { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index eeee50b1..a7354bb0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -34,10 +34,10 @@ */ public class WindowsUSBDevice extends USBDeviceImpl { - private final MemoryAddress device; - private final MemoryAddress firstInterface; + private MemoryAddress device; + private MemoryAddress firstInterface; private final byte currentConfigurationValue; - private final Configuration configuration; + private Configuration configuration; private List claimedInterfaces; @@ -45,6 +45,13 @@ public class WindowsUSBDevice extends USBDeviceImpl { WindowsUSBDevice(Object id, USBDeviceInfo info, byte currentConfigurationValue) { super(id, info); this.currentConfigurationValue = currentConfigurationValue; + } + + @Override + public void open() { + + if (device != null) + return; try (var session = MemorySession.openConfined()) { @@ -81,11 +88,27 @@ public class WindowsUSBDevice extends USBDeviceImpl { } catch (Throwable e) { Kernel32.CloseHandle(device); + configuration = null; + firstInterface = null; + device = null; throw e; } } } + + @Override + public void close() throws Exception { + if (device == null) + return; + + WinUSB.WinUsb_Free(firstInterface); + firstInterface = null; + Kernel32.CloseHandle(device); + device = null; + configuration = null; + } + public void claimInterface(int interfaceNumber) { var intfOptional = configuration.interfaces.stream().filter(intf -> intf.number == interfaceNumber).findFirst(); @@ -197,10 +220,4 @@ public byte[] transferIn(int endpointNumber, int maxLength) { return buffer.asSlice(0, len).toArray(JAVA_BYTE); } } - - @Override - public void close() throws Exception { - WinUSB.WinUsb_Free(firstInterface); - Kernel32.CloseHandle(device); - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java index b13b4420..cada0e64 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java @@ -28,6 +28,8 @@ public class WindowsUSBDeviceInfo extends USBDeviceInfoImpl { @Override public USBDevice open() { - return new WindowsUSBDevice(id, this, currentConfigurationValue); + var device = new WindowsUSBDevice(id, this, currentConfigurationValue); + device.open(); + return device; } } From b43b8a2463c3f2fe02ac843500b84cf5e64c5ee3 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Thu, 1 Sep 2022 22:52:53 +0200 Subject: [PATCH 032/433] Merge USBDeviceInfo and USBDevice --- .../src/main/java/net/codecrete/usb/USB.java | 17 +-- .../java/net/codecrete/usb/USBDevice.java | 48 ++++--- .../net/codecrete/usb/USBDeviceFilter.java | 4 +- .../java/net/codecrete/usb/USBDeviceInfo.java | 116 --------------- .../codecrete/usb/common/USBDeviceImpl.java | 90 ++++++------ .../usb/common/USBDeviceInfoImpl.java | 136 ------------------ .../usb/common/USBDeviceRegistry.java | 43 +++--- .../codecrete/usb/linux/LinuxUSBDevice.java | 43 +++--- .../usb/linux/LinuxUSBDeviceInfo.java | 35 ----- .../usb/linux/LinuxUSBDeviceRegistry.java | 63 +++----- .../codecrete/usb/macos/MacosUSBDevice.java | 94 ++++++------ .../usb/macos/MacosUSBDeviceInfo.java | 35 ----- .../usb/macos/MacosUSBDeviceRegistry.java | 58 ++++---- .../usb/windows/WindowsUSBDevice.java | 56 ++++---- .../usb/windows/WindowsUSBDeviceInfo.java | 35 ----- .../usb/windows/WindowsUSBDeviceRegistry.java | 100 +++++++------ .../net/codecrete/usb/BulkTransferTest.java | 6 +- .../codecrete/usb/ControlTransferTest.java | 6 +- .../codecrete/usb/DeviceEnumerationTest.java | 4 +- .../net/codecrete/usb/IsSameDeviceTest.java | 46 ------ 20 files changed, 295 insertions(+), 740 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/USBDeviceInfo.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceInfoImpl.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceInfo.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceInfo.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java delete mode 100644 java-does-usb/src/test/java/net/codecrete/usb/IsSameDeviceTest.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USB.java b/java-does-usb/src/main/java/net/codecrete/usb/USB.java index 86cef6c9..1e8e4e97 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USB.java @@ -33,7 +33,8 @@ private static USBDeviceRegistry createInstance() { } else if (osName.equals("Linux") && (osArch.equals("amd64") || osArch.equals("aarch64"))) { impl = new LinuxUSBDeviceRegistry(); } else { - throw new UnsupportedOperationException(String.format("JavaCanDoUsb is not implemented for architecture %s/%s", osName, osArch)); + throw new UnsupportedOperationException(String.format("JavaCanDoUsb is not implemented for architecture " + + "%s/%s", osName, osArch)); } return impl; } @@ -62,7 +63,7 @@ private USB() { * * @return list of USB devices */ - public static List getAllDevices() { + public static List getAllDevices() { return instance().getAllDevices(); } @@ -72,7 +73,7 @@ public static List getAllDevices() { * @param filter device filter * @return list of USB devices */ - public static List getDevices(USBDeviceFilter filter) { + public static List getDevices(USBDeviceFilter filter) { return instance().getAllDevices().stream().filter(filter::matches).collect(Collectors.toList()); } @@ -82,7 +83,7 @@ public static List getDevices(USBDeviceFilter filter) { * @param filters list of device filters * @return list of USB devices */ - public static List getDevices(List filters) { + public static List getDevices(List filters) { return instance().getAllDevices().stream().filter(dev -> USBDeviceFilter.matchesAny(dev, filters)) .collect(Collectors.toList()); } @@ -93,7 +94,7 @@ public static List getDevices(List filters) { * @param filter device filter * @return USB device, or {@code null} if no device matches */ - public static USBDeviceInfo getDevice(USBDeviceFilter filter) { + public static USBDevice getDevice(USBDeviceFilter filter) { return instance().getAllDevices().stream().filter(filter::matches).findFirst().orElse(null); } @@ -103,7 +104,7 @@ public static USBDeviceInfo getDevice(USBDeviceFilter filter) { * @param filters list of device filters * @return USB device, or {@code null} if no device matches */ - public static USBDeviceInfo getDevice(List filters) { + public static USBDevice getDevice(List filters) { return instance().getAllDevices().stream().filter(dev -> USBDeviceFilter.matchesAny(dev, filters)) .findFirst().orElse(null); } @@ -113,7 +114,7 @@ public static USBDeviceInfo getDevice(List filters) { * * @param handler handler function, or {@code null} to remove a previous handler */ - public static void setOnDeviceConnected(Consumer handler) { + public static void setOnDeviceConnected(Consumer handler) { instance().setOnDeviceConnected(handler); } @@ -122,7 +123,7 @@ public static void setOnDeviceConnected(Consumer handler) { * * @param handler handler function, or {@code null} to remove a previous handler */ - public static void setOnDeviceDisconnected(Consumer handler) { + public static void setOnDeviceDisconnected(Consumer handler) { instance().setOnDeviceDisconnected(handler); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index 43f37e7e..6bf0e722 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -9,13 +9,17 @@ /** * USB device. - * *

- * Instances of this class are associated with operating system resources - * and must be close when they are no longer used. + * In order to make control requests and transfer data, the device must be + * opened and an interface must be claimed. In the open state, this current + * process has exclusive access to the device. + *

+ *

+ * Information about the device can be queried in both the open and the + * closed state. *

*/ -public interface USBDevice extends AutoCloseable { +public interface USBDevice { /** * USB product ID. @@ -77,6 +81,23 @@ public interface USBDevice extends AutoCloseable { */ int getProtocolCode(); + /** + * Opens the device for communication. + */ + void open(); + + /** + * Indicates if the device is open. + * + * @return {@code true} if the device is open, {@code false} if it is closed. + */ + boolean isOpen(); + + /** + * Closes the device. + */ + void close(); + /** * Claims the specified interface for exclusive use. * @@ -151,23 +172,4 @@ public interface USBDevice extends AutoCloseable { * @return received data */ byte[] transferIn(int endpointNumber, int maxLength); - - - /** - * Returns if this instance and another {@link USBDeviceInfo} instance - * represent the same USB device. - * - * @param device other device instance - * @return {@code true} if they are the same, {@code false} otherwise - */ - boolean isSameDevice(USBDeviceInfo device); - - /** - * Returns if this instance and another {@link USBDevice} instance - * represent the same USB device. - * - * @param device other device info instance - * @return {@code true} if they are the same, {@code false} otherwise - */ - boolean isSameDevice(USBDevice device); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java index c501e862..53400e2e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java @@ -172,7 +172,7 @@ public void setSerialNumber(String serialNumber) { * @param deviceInfo USB device information * @return {@code true} if it matches, {@code false} otherwise */ - public boolean matches(USBDeviceInfo deviceInfo) { + public boolean matches(USBDevice deviceInfo) { if (vendorId != null && deviceInfo.getVendorId() != vendorId) return false; if (productId != null && deviceInfo.getProductId() != productId) @@ -186,7 +186,7 @@ public boolean matches(USBDeviceInfo deviceInfo) { return protocolCode == null || deviceInfo.getProtocolCode() == protocolCode; } - public static boolean matchesAny(USBDeviceInfo deviceInfo, List filters) { + public static boolean matchesAny(USBDevice deviceInfo, List filters) { return filters.stream().anyMatch(filter -> filter.matches(deviceInfo)); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceInfo.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceInfo.java deleted file mode 100644 index 70572e34..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceInfo.java +++ /dev/null @@ -1,116 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb; - -/** - * Information about a USB device. - * - *

- * Instances of this class are created by {@link USB}, - * e.g. {@link USB#getAllDevices()}. - *

- *

- * Instances of this class are not associated with any native resources - * and can thus be easily handled in Java. - *

- *

- * Multiple instances of this class might exist for the same USB device. - * Use {@code equals()} or {@code isSameDevice()} to test if two instances - * represent the same USB device. - *

- */ -public interface USBDeviceInfo { - /** - * USB product ID. - * - * @return product ID - */ - int getProductId(); - - /** - * USB vendor ID. - * - * @return vendor ID - */ - int getVendorId(); - - /** - * Product name. - * - * @return product name or {@code null} if not provided by the device - */ - String getProduct(); - - /** - * Manufacturer name - * - * @return manufacturer name or {@code null} if not provided by the device - */ - String getManufacturer(); - - /** - * Serial number - *

- * Even though this is supposed to be a human-readable string, - * some devices are known to provide binary data. - *

- * - * @return serial number or {@code null} if not provided by the device - */ - String getSerial(); - - /** - * USB device class code ({@code bDeviceClass} from device descriptor). - * - * @return class code - */ - int getClassCode(); - - /** - * USB device subclass code ({@code bDeviceSubClass} from device descriptor). - * - * @return subclass code - */ - int getSubclassCode(); - - /** - * USB device protocol ({@code bDeviceProtocol} from device descriptor). - * - * @return protocol code - */ - int getProtocolCode(); - - /** - * Opens the device for communication. - * - *

- * As part of opening the device, the first configuration is activated. - *

- * - * @return USB device - */ - USBDevice open(); - - /** - * Returns if this instance and another {@link USBDevice} instance - * represent the same USB device. - * - * @param device other device instance - * @return {@code true} if they are the same, {@code false} otherwise - */ - boolean isSameDevice(USBDevice device); - - /** - * Returns if this instance and another {@link USBDeviceInfo} instance - * represent the same USB device. - * - * @param device other device info instance - * @return {@code true} if they are the same, {@code false} otherwise - */ - boolean isSameDevice(USBDeviceInfo device); -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 6ce61be5..a62f75c6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -7,15 +7,18 @@ package net.codecrete.usb.common; -import net.codecrete.usb.*; +import net.codecrete.usb.USBControlTransfer; +import net.codecrete.usb.USBDevice; +import net.codecrete.usb.USBRecipient; +import net.codecrete.usb.USBRequestType; public abstract class USBDeviceImpl implements USBDevice { protected final Object id; - protected final int productId; protected final int vendorId; - protected final String product; + protected final int productId; protected final String manufacturer; + protected final String product; protected final String serial; protected final int classCode; protected final int subclassCode; @@ -24,28 +27,38 @@ public abstract class USBDeviceImpl implements USBDevice { /** * Creates a new instance. * - * @param id unique identifier - * @param info USB device information + * @param id unique device ID + * @param vendorId USB vendor ID + * @param productId USB product ID + * @param manufacturer manufacturer name + * @param product product name + * @param serial serial number + * @param classCode USB device class code + * @param subclassCode USB device subclass code + * @param protocolCode USB device protocol */ - protected USBDeviceImpl( - Object id, - USBDeviceInfo info) { + protected USBDeviceImpl(Object id, int vendorId, int productId, String manufacturer, String product, + String serial, int classCode, int subclassCode, int protocolCode) { assert id != null; this.id = id; - this.productId = info.getProductId(); - this.vendorId = info.getVendorId(); - this.product = info.getProduct(); - this.manufacturer = info.getManufacturer(); - this.serial = info.getSerial(); - this.classCode = info.getClassCode(); - this.subclassCode = info.getSubclassCode(); - this.protocolCode = info.getProtocolCode(); + this.vendorId = vendorId; + this.productId = productId; + this.manufacturer = manufacturer; + this.product = product; + this.serial = serial; + this.classCode = classCode; + this.subclassCode = subclassCode; + this.protocolCode = protocolCode; } public abstract void open(); + public abstract void close(); + + public abstract boolean isOpen(); + public int getProductId() { return productId; } @@ -78,6 +91,10 @@ public int getProtocolCode() { return protocolCode; } + public Object getUniqueId() { + return id; + } + public abstract void claimInterface(int interfaceNumber); public abstract void releaseInterface(int interfaceNumber); @@ -93,39 +110,22 @@ public int getProtocolCode() { protected byte[] getDescriptor(int descriptorType, int index, int language) { // get descriptor header - var result = controlTransferIn( - new USBControlTransfer(USBRequestType.STANDARD, USBRecipient.DEVICE, - (byte) 0x06, (short) (descriptorType << 8 | index), (short) language), 9); + var result = controlTransferIn(new USBControlTransfer(USBRequestType.STANDARD, USBRecipient.DEVICE, + (byte) 0x06, (short) (descriptorType << 8 | index), (short) language), 9); // get effective length from header int length; if (descriptorType == USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE) length = (result[2] & 255) + 256 * (result[3] & 255); - else - length = result[0] & 255; + else length = result[0] & 255; // get full descriptor - result = controlTransferIn( - new USBControlTransfer(USBRequestType.STANDARD, USBRecipient.DEVICE, - (byte) 0x06, (short) (descriptorType << 8 | index), (short) language), length); + result = controlTransferIn(new USBControlTransfer(USBRequestType.STANDARD, USBRecipient.DEVICE, (byte) 0x06, + (short) (descriptorType << 8 | index), (short) language), length); return result; } - @Override - public boolean isSameDevice(USBDeviceInfo device) { - if (device instanceof USBDeviceInfoImpl) - return id.equals(((USBDeviceInfoImpl)device).id); - return false; - } - - @Override - public boolean isSameDevice(USBDevice device) { - if (device instanceof USBDeviceImpl) - return id.equals(((USBDeviceImpl)device).id); - return false; - } - @Override public boolean equals(Object o) { if (this == o) return true; @@ -141,17 +141,7 @@ public int hashCode() { @Override public String toString() { - return "VID: 0x" + - String.format("%04x", vendorId) + - ", PID: 0x" + - String.format("%04x", productId) + - ", manufacturer: " + - manufacturer + - ", product: " + - product + - ", serial: " + - serial + - ", ID: " + - id.toString(); + return "VID: 0x" + String.format("%04x", vendorId) + ", PID: 0x" + String.format("%04x", productId) + ", " + + "manufacturer: " + manufacturer + ", product: " + product + ", serial: " + serial + ", ID: " + id; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceInfoImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceInfoImpl.java deleted file mode 100644 index 1d95882b..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceInfoImpl.java +++ /dev/null @@ -1,136 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.common; - -import net.codecrete.usb.USBDevice; -import net.codecrete.usb.USBDeviceInfo; - -public abstract class USBDeviceInfoImpl implements USBDeviceInfo { - - protected final Object id; - protected final int productId; - protected final int vendorId; - protected final String product; - protected final String manufacturer; - protected final String serial; - protected final int classCode; - protected final int subclassCode; - protected final int protocolCode; - - /** - * Creates a new instance. - * - * @param id unique device ID - * @param vendorId USB vendor ID - * @param productId USB product ID - * @param manufacturer manufacturer name - * @param product product name - * @param serial serial number - * @param classCode USB device class code - * @param subclassCode USB device subclass code - * @param protocolCode USB device protocol - */ - protected USBDeviceInfoImpl( - Object id, int vendorId, int productId, - String manufacturer, String product, String serial, - int classCode, int subclassCode, int protocolCode) { - - assert id != null; - - this.id = id; - this.productId = productId; - this.vendorId = vendorId; - this.product = product; - this.manufacturer = manufacturer; - this.serial = serial; - this.classCode = classCode; - this.subclassCode = subclassCode; - this.protocolCode = protocolCode; - } - - public abstract USBDevice open(); - - public int getProductId() { - return productId; - } - - public int getVendorId() { - return vendorId; - } - - public String getProduct() { - return product; - } - - public String getManufacturer() { - return manufacturer; - } - - public String getSerial() { - return serial; - } - - public int getClassCode() { - return classCode; - } - - public int getSubclassCode() { - return subclassCode; - } - - public int getProtocolCode() { - return protocolCode; - } - - public Object getUniqueId() { - return id; - } - - @Override - public boolean isSameDevice(USBDeviceInfo device) { - if (device instanceof USBDeviceInfoImpl) - return id.equals(((USBDeviceInfoImpl)device).id); - return false; - } - - @Override - public boolean isSameDevice(USBDevice device) { - if (device instanceof USBDeviceImpl) - return id.equals(((USBDeviceImpl)device).id); - return false; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - USBDeviceInfoImpl that = (USBDeviceInfoImpl) o; - return id.equals(that.id); - } - - @Override - public int hashCode() { - return id.hashCode(); - } - - @Override - public String toString() { - return "VID: 0x" + - String.format("%04x", vendorId) + - ", PID: 0x" + - String.format("%04x", productId) + - ", manufacturer: " + - manufacturer + - ", product: " + - product + - ", serial: " + - serial + - ", ID: " + - id; - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index c4ee6007..929004bd 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -7,7 +7,7 @@ package net.codecrete.usb.common; -import net.codecrete.usb.USBDeviceInfo; +import net.codecrete.usb.USBDevice; import java.util.ArrayList; import java.util.Collections; @@ -31,9 +31,9 @@ */ public abstract class USBDeviceRegistry { - private volatile List devices; - protected Consumer onDeviceConnectedHandler; - protected Consumer onDeviceDisconnectedHandler; + private volatile List devices; + protected Consumer onDeviceConnectedHandler; + protected Consumer onDeviceDisconnectedHandler; private final Lock lock = new ReentrantLock(); private final Condition enumerationComplete = lock.newCondition(); @@ -64,26 +64,24 @@ public void start() { * * @return list of devices */ - public List getAllDevices() { + public List getAllDevices() { return Collections.unmodifiableList(devices); } - public void setOnDeviceConnected(Consumer handler) { + public void setOnDeviceConnected(Consumer handler) { onDeviceConnectedHandler = handler; } - public void setOnDeviceDisconnected(Consumer handler) { + public void setOnDeviceDisconnected(Consumer handler) { onDeviceDisconnectedHandler = handler; } - protected void emitOnDeviceConnected(USBDeviceInfo device) { - if (onDeviceConnectedHandler != null) - onDeviceConnectedHandler.accept(device); + protected void emitOnDeviceConnected(USBDevice device) { + if (onDeviceConnectedHandler != null) onDeviceConnectedHandler.accept(device); } - protected void emitOnDeviceDisconnected(USBDeviceInfo device) { - if (onDeviceDisconnectedHandler != null) - onDeviceDisconnectedHandler.accept(device); + protected void emitOnDeviceDisconnected(USBDevice device) { + if (onDeviceDisconnectedHandler != null) onDeviceDisconnectedHandler.accept(device); } /** @@ -132,7 +130,7 @@ private void signalEnumerationComplete() { * * @param deviceList the device list */ - protected void setInitialDeviceList(List deviceList) { + protected void setInitialDeviceList(List deviceList) { devices = deviceList; signalEnumerationComplete(); } @@ -142,13 +140,12 @@ protected void setInitialDeviceList(List deviceList) { * * @param device device to add */ - protected void addDevice(USBDeviceInfo device) { + protected void addDevice(USBDevice device) { // check for duplicates - if (findDeviceIndex(devices, ((USBDeviceInfoImpl) device).getUniqueId()) >= 0) - return; + if (findDeviceIndex(devices, ((USBDeviceImpl) device).getUniqueId()) >= 0) return; // copy list - var newDeviceList = new ArrayList(devices.size() + 1); + var newDeviceList = new ArrayList(devices.size() + 1); newDeviceList.addAll(devices); newDeviceList.add(device); devices = newDeviceList; @@ -165,8 +162,7 @@ protected void addDevice(USBDeviceInfo device) { protected void removeDevice(Object deviceId) { // locate device to be removed int index = findDeviceIndex(devices, deviceId); - if (index < 0) - return; // strange + if (index < 0) return; // strange // copy list and remove device var deviceInfo = devices.get(index); @@ -185,11 +181,10 @@ protected void removeDevice(Object deviceId) { * @param deviceId the unique device ID * @return return the index, or -1 if the device is not found */ - protected int findDeviceIndex(List deviceList, Object deviceId) { + protected int findDeviceIndex(List deviceList, Object deviceId) { for (int i = 0; i < deviceList.size(); i++) { - var dev = (USBDeviceInfoImpl) deviceList.get(i); - if (deviceId.equals(dev.getUniqueId())) - return i; + var dev = (USBDeviceImpl) deviceList.get(i); + if (deviceId.equals(dev.getUniqueId())) return i; } return -1; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 5bec9e65..101ae04e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -8,7 +8,6 @@ package net.codecrete.usb.linux; import net.codecrete.usb.USBControlTransfer; -import net.codecrete.usb.USBDeviceInfo; import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBException; import net.codecrete.usb.common.USBDeviceImpl; @@ -28,27 +27,30 @@ public class LinuxUSBDevice extends USBDeviceImpl { private int fd = -1; - LinuxUSBDevice(Object id, USBDeviceInfo info) { - super(id, info); + LinuxUSBDevice(Object id, int vendorId, int productId, String manufacturer, String product, String serial, + int classCode, int subclassCode, int protocolCode) { + super(id, vendorId, productId, manufacturer, product, serial, classCode, subclassCode, protocolCode); + } + + @Override + public boolean isOpen() { + return fd != -1; } @Override public void open() { - if (fd != -1) - return; + if (fd != -1) return; try (var session = MemorySession.openConfined()) { var pathUtf8 = session.allocateUtf8String(id.toString()); fd = fcntl.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC()); - if (fd == -1) - throw new USBException("Cannot open USB device", IO.getErrno()); + if (fd == -1) throw new USBException("Cannot open USB device", IO.getErrno()); } } @Override - public void close() throws Exception { - if (fd == -1) - return; + public void close() { + if (fd == -1) return; unistd.close(fd); fd = -1; @@ -58,8 +60,7 @@ public void claimInterface(int interfaceNumber) { try (var session = MemorySession.openConfined()) { var intfNumSegment = session.allocate(JAVA_INT, interfaceNumber); int ret = ioctl.ioctl(fd, USBDevFS.CLAIMINTERFACE, intfNumSegment.address()); - if (ret != 0) - throw new USBException("Cannot claim USB interface", IO.getErrno()); + if (ret != 0) throw new USBException("Cannot claim USB interface", IO.getErrno()); } } @@ -67,14 +68,15 @@ public void releaseInterface(int interfaceNumber) { try (var session = MemorySession.openConfined()) { var intfNumSegment = session.allocate(JAVA_INT, interfaceNumber); int ret = ioctl.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment.address()); - if (ret != 0) - throw new USBException("Cannot release USB interface", IO.getErrno()); + if (ret != 0) throw new USBException("Cannot release USB interface", IO.getErrno()); } } - private MemorySegment createCtrlTransfer(MemorySession session, USBDirection direction, USBControlTransfer setup, MemorySegment data) { + private MemorySegment createCtrlTransfer(MemorySession session, USBDirection direction, USBControlTransfer setup, + MemorySegment data) { var ctrlTransfer = session.allocate(usbdevfs_ctrltransfer.$LAYOUT()); - var bmRequest = (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); + var bmRequest = + (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); usbdevfs_ctrltransfer.bRequestType$set(ctrlTransfer, (byte) bmRequest); usbdevfs_ctrltransfer.bRequest$set(ctrlTransfer, setup.request()); usbdevfs_ctrltransfer.wValue$set(ctrlTransfer, setup.value()); @@ -91,8 +93,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { var ctrlTransfer = createCtrlTransfer(session, USBDirection.IN, setup, data); int res = ioctl.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer.address()); - if (res < 0) - throw new USBException("Control IN transfer failed", res); + if (res < 0) throw new USBException("Control IN transfer failed", res); return data.asSlice(0, res).toArray(JAVA_BYTE); } @@ -103,13 +104,11 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { try (var session = MemorySession.openConfined()) { int dataLength = data != null ? data.length : 0; var buffer = session.allocate(dataLength); - if (dataLength != 0) - buffer.copyFrom(MemorySegment.ofArray(data)); + if (dataLength != 0) buffer.copyFrom(MemorySegment.ofArray(data)); var ctrlTransfer = createCtrlTransfer(session, USBDirection.OUT, setup, buffer); int res = ioctl.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer.address()); - if (res < 0) - throw new USBException("Control OUT transfer failed", res); + if (res < 0) throw new USBException("Control OUT transfer failed", res); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceInfo.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceInfo.java deleted file mode 100644 index 0116715d..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceInfo.java +++ /dev/null @@ -1,35 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.linux; - -import net.codecrete.usb.USBDevice; -import net.codecrete.usb.common.USBDeviceInfoImpl; - -public class LinuxUSBDeviceInfo extends USBDeviceInfoImpl { - - LinuxUSBDeviceInfo( - Object id, int vendorId, int productId, - String manufacturer, String product, String serial, - int classCode, int subclassCode, int protocolCode) { - - super(id, vendorId, productId, - manufacturer, product, serial, - classCode, subclassCode, protocolCode); - } - - @Override - public USBDevice open() { - var device = new LinuxUSBDevice(id, this); - device.open(); - return device; - } - - Object devicePath() { - return id; - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index de5eb7bf..c7a5566f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -7,7 +7,7 @@ package net.codecrete.usb.linux; -import net.codecrete.usb.USBDeviceInfo; +import net.codecrete.usb.USBDevice; import net.codecrete.usb.USBException; import net.codecrete.usb.common.USBDeviceRegistry; import net.codecrete.usb.linux.gen.select.fd_set; @@ -38,12 +38,10 @@ protected void monitorDevices() { // setup udev monitor var udevInstance = udev.udev_new(); - if (udevInstance == NULL) - throw new USBException("internal error (udev_new)"); + if (udevInstance == NULL) throw new USBException("internal error (udev_new)"); var monitor = udev.udev_monitor_new_from_netlink(udevInstance, MONITOR_NAME); - if (monitor == NULL) - throw new USBException("internal error (udev_monitor_new_from_netlink)"); + if (monitor == NULL) throw new USBException("internal error (udev_monitor_new_from_netlink)"); if (udev.udev_monitor_filter_add_match_subsystem_devtype(monitor, SUBSYSTEM_USB, DEVTYPE_USB_DEVICE) < 0) throw new USBException("internal error (udev_monitor_filter_add_match_subsystem_devtype)"); @@ -52,8 +50,7 @@ protected void monitorDevices() { throw new USBException("internal error (udev_monitor_enable_receiving)"); int fd = udev.udev_monitor_get_fd(monitor); - if (fd < 0) - throw new USBException("internal error (udev_monitor_get_fd)"); + if (fd < 0) throw new USBException("internal error (udev_monitor_get_fd)"); // create initial list of devices enumeratePresentDevices(udevInstance); @@ -67,8 +64,7 @@ protected void monitorDevices() { // retrieve change var dev = udev.udev_monitor_receive_device(monitor); - if (dev == null) - continue; // shouldn't happen + if (dev == null) continue; // shouldn't happen session.addCloseAction(() -> udev.udev_device_unref(dev)); @@ -85,13 +81,12 @@ protected void monitorDevices() { } private void enumeratePresentDevices(Addressable udevInstance) { - List result = new ArrayList<>(); + List result = new ArrayList<>(); try (var outerSession = MemorySession.openConfined()) { // create device enumerator var enumerate = udev.udev_enumerate_new(udevInstance); - if (enumerate == NULL) - throw new USBException("internal error (udev_enumerate_new)"); + if (enumerate == NULL) throw new USBException("internal error (udev_enumerate_new)"); outerSession.addCloseAction(() -> udev.udev_enumerate_unref(enumerate)); @@ -102,28 +97,24 @@ private void enumeratePresentDevices(Addressable udevInstance) { throw new USBException("internal error (udev_enumerate_scan_devices)"); // enumerate devices - for (var entry = udev.udev_enumerate_get_list_entry(enumerate); - entry != NULL; - entry = udev.udev_list_entry_get_next(entry)) { + for (var entry = udev.udev_enumerate_get_list_entry(enumerate); entry != NULL; entry = + udev.udev_list_entry_get_next(entry)) { try (var session = MemorySession.openConfined()) { var path = udev.udev_list_entry_get_name(entry); - if (path == NULL) - continue; + if (path == NULL) continue; // get device handle var dev = udev.udev_device_new_from_syspath(udevInstance, path); - if (dev == NULL) - continue; + if (dev == NULL) continue; // ensure the device is released session.addCloseAction(() -> udev.udev_device_unref(dev)); // get device details var deviceInfo = getDeviceDetails(dev); - if (deviceInfo != null) - result.add(deviceInfo); + if (deviceInfo != null) result.add(deviceInfo); } } } @@ -134,8 +125,7 @@ private void enumeratePresentDevices(Addressable udevInstance) { private void onDeviceConnected(MemoryAddress device) { var deviceInfo = getDeviceDetails(device); - if (deviceInfo == null) - return; + if (deviceInfo == null) return; addDevice(deviceInfo); } @@ -143,8 +133,7 @@ private void onDeviceConnected(MemoryAddress device) { private void onDeviceDisconnected(MemoryAddress device) { var devPath = getDeviceName(device); - if (devPath == null) - return; + if (devPath == null) return; removeDevice(devPath); } @@ -159,39 +148,32 @@ private void onDeviceDisconnected(MemoryAddress device) { * @param device the device * @return the device info */ - private static USBDeviceInfo getDeviceDetails(MemoryAddress device) { + private static USBDevice getDeviceDetails(MemoryAddress device) { // retrieve device attributes String idVendor = getDeviceAttribute(device, "idVendor"); - if (idVendor == null) - return null; + if (idVendor == null) return null; String idProduct = getDeviceAttribute(device, "idProduct"); - if (idProduct == null) - return null; + if (idProduct == null) return null; // get device path var devPath = getDeviceName(device); - if (devPath == null) - return null; + if (devPath == null) return null; int vendorId = Integer.parseInt(idVendor, 16); int productId = Integer.parseInt(idProduct, 16); // create device info instance - return new LinuxUSBDeviceInfo(devPath, vendorId, productId, - getDeviceAttribute(device, "manufacturer"), - getDeviceAttribute(device, "product"), - getDeviceAttribute(device, "serial"), - 0, 0, 0); + return new LinuxUSBDevice(devPath, vendorId, productId, getDeviceAttribute(device, "manufacturer"), + getDeviceAttribute(device, "product"), getDeviceAttribute(device, "serial"), 0, 0, 0); } private static String getDeviceAttribute(Addressable device, String attribute) { try (var session = MemorySession.openConfined()) { var sysattr = session.allocateUtf8String(attribute); var valueAddr = udev.udev_device_get_sysattr_value(device, sysattr); - if (valueAddr == NULL) - return null; + if (valueAddr == NULL) return null; var value = MemorySegment.ofAddress(valueAddr, 2000, session); return value.getUtf8String(0); @@ -218,7 +200,6 @@ private static void waitForFileDescriptor(int fd, MemorySession session) { fds.set(JAVA_LONG, fd / JAVA_LONG.bitSize(), 1L << (fd % JAVA_LONG.bitSize())); int res = select.select(fd + 1, fds, NULL, NULL, NULL); - if (res <= 0) - throw new USBException("internal error (select)"); + if (res <= 0) throw new USBException("internal error (select)"); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 4b0a6929..a76dd584 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -8,7 +8,6 @@ package net.codecrete.usb.macos; import net.codecrete.usb.USBControlTransfer; -import net.codecrete.usb.USBDeviceInfo; import net.codecrete.usb.USBDirection; import net.codecrete.usb.common.USBDescriptors; import net.codecrete.usb.common.USBDeviceImpl; @@ -30,32 +29,35 @@ public class MacosUSBDevice extends USBDeviceImpl { private List claimedInterfaces; private List endpoints; - MacosUSBDevice(Object id, USBDeviceInfo info) { - super(id, info); + MacosUSBDevice(Object id, int vendorId, int productId, String manufacturer, String product, String serial, + int classCode, int subclassCode, int protocolCode) { + super(id, vendorId, productId, manufacturer, product, serial, classCode, subclassCode, protocolCode); + } + + @Override + public boolean isOpen() { + return device != null; } @Override public void open() { - if (device != null) - return; + if (device != null) return; try (var session = MemorySession.openConfined()) { // get service from IO registry var matching = IoKit.IORegistryEntryIDMatching((Long) id); - if (matching == NULL) - throw new MacosUSBException("IORegistryEntryIDMatching failed"); + if (matching == NULL) throw new MacosUSBException("IORegistryEntryIDMatching failed"); // Consumes matching instance int service = IoKit.IOServiceGetMatchingService(IoKit.kIOMasterPortDefault, matching); - if (service == 0) - throw new MacosUSBException("unable to open USB device (IOServiceGetMatchingService)"); + if (service == 0) throw new MacosUSBException("unable to open USB device (IOServiceGetMatchingService)"); session.addCloseAction(() -> IoKit.IOObjectRelease(service)); // get user client interface - device = IoKitHelper.GetInterface(service, IoKit.kIOUSBDeviceUserClientTypeID, IoKit.kIOUSBDeviceInterfaceID100); - if (device == null) - throw new MacosUSBException("unable to open USB device (get client interface)"); + device = IoKitHelper.GetInterface(service, IoKit.kIOUSBDeviceUserClientTypeID, + IoKit.kIOUSBDeviceInterfaceID100); + if (device == null) throw new MacosUSBException("unable to open USB device (get client interface)"); // open device int ret = IoKitUSB.USBDeviceOpen(device); @@ -69,17 +71,16 @@ public void open() { // retrieve information of first configuration var descPtrHolder = session.allocate(ADDRESS); ret = IoKitUSB.GetConfigurationDescriptorPtr(device, (byte) 0, descPtrHolder); - if (ret != 0) - throw new MacosUSBException("failed to query first configuration", ret); + if (ret != 0) throw new MacosUSBException("failed to query first configuration", ret); // get value of first configuration - var configDesc = MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), USBDescriptors.Configuration.byteSize(), session); + var configDesc = MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), + USBDescriptors.Configuration.byteSize(), session); configurationValue = 255 & (byte) USBDescriptors.Configuration_bConfigurationValue.get(configDesc); // set configuration ret = IoKitUSB.SetConfiguration(device, (byte) configurationValue); - if (ret != 0) - throw new MacosUSBException("failed to set configuration", ret); + if (ret != 0) throw new MacosUSBException("failed to set configuration", ret); } catch (Throwable e) { IoKitUSB.USBDeviceClose(device); @@ -92,15 +93,16 @@ public void open() { } @Override - public void close() throws Exception { - if (device == null) - return; + public void close() { + if (device == null) return; if (claimedInterfaces != null) { for (InterfaceInfo interfaceInfo : claimedInterfaces) { IoKitUSB.USBInterfaceClose(interfaceInfo.asMemoryAddress()); IoKit.Release(interfaceInfo.asMemoryAddress()); } + claimedInterfaces = null; + endpoints = null; } IoKitUSB.USBDeviceClose(device); @@ -120,8 +122,7 @@ private InterfaceInfo findInterface(int interfaceNumber) { var iterHolder = outerSession.allocate(JAVA_INT); int ret = IoKitUSB.CreateInterfaceIterator(device, request, iterHolder); final var iter = iterHolder.get(JAVA_INT, 0); - if (ret != 0) - throw new RuntimeException("CreateInterfaceIterator failed"); + if (ret != 0) throw new RuntimeException("CreateInterfaceIterator failed"); outerSession.addCloseAction(() -> IoKit.IOObjectRelease(iter)); int service; @@ -131,9 +132,9 @@ private InterfaceInfo findInterface(int interfaceNumber) { final int service_final = service; session.addCloseAction(() -> IoKit.IOObjectRelease(service_final)); - final MemoryAddress intf = IoKitHelper.GetInterface(service, IoKit.kIOUSBInterfaceUserClientTypeID, IoKit.kIOUSBInterfaceInterfaceID100); - if (intf == null) - continue; + final MemoryAddress intf = IoKitHelper.GetInterface(service, + IoKit.kIOUSBInterfaceUserClientTypeID, IoKit.kIOUSBInterfaceInterfaceID100); + if (intf == null) continue; var intfNumberHolder = session.allocate(JAVA_INT); IoKitUSB.GetInterfaceNumber(intf, intfNumberHolder); @@ -158,15 +159,13 @@ public void claimInterface(int interfaceNumber) { try { var ret = IoKitUSB.USBInterfaceOpen(interfaceInfo.asMemoryAddress()); - if (ret != 0) - throw new MacosUSBException("Failed to claim interface", ret); + if (ret != 0) throw new MacosUSBException("Failed to claim interface", ret); } catch (Throwable t) { IoKit.Release(interfaceInfo.asMemoryAddress()); throw t; } - if (claimedInterfaces == null) - claimedInterfaces = new ArrayList<>(); + if (claimedInterfaces == null) claimedInterfaces = new ArrayList<>(); claimedInterfaces.add(interfaceInfo); updateEndpointList(); @@ -181,8 +180,7 @@ public void releaseInterface(int interfaceNumber) { var interfaceInfo = interfaceInfoOptional.get(); int ret = IoKitUSB.USBInterfaceClose(interfaceInfo.asMemoryAddress()); - if (ret != 0) - throw new MacosUSBException("Failed to release interface", ret); + if (ret != 0) throw new MacosUSBException("Failed to release interface", ret); claimedInterfaces.remove(interfaceInfo); IoKit.Release(interfaceInfo.asMemoryAddress()); @@ -199,8 +197,7 @@ private void updateEndpointList() { var intf = interfaceInfo.asMemoryAddress(); var numEndpointsHolder = session.allocate(JAVA_BYTE); int ret = IoKitUSB.GetNumEndpoints(intf, numEndpointsHolder); - if (ret != 0) - throw new MacosUSBException("Failed to get number of endpoints", ret); + if (ret != 0) throw new MacosUSBException("Failed to get number of endpoints", ret); int numEndpoints = numEndpointsHolder.get(JAVA_BYTE, 0) & 255; for (int pipeIndex = 1; pipeIndex <= numEndpoints; pipeIndex++) { @@ -211,10 +208,9 @@ private void updateEndpointList() { var maxPacketSizeHolder = session.allocate(JAVA_SHORT); var intervalHolder = session.allocate(JAVA_BYTE); - ret = IoKitUSB.GetPipeProperties(intf, (byte) pipeIndex, directionHolder, - numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); - if (ret != 0) - throw new MacosUSBException("Failed to get pipe properties", ret); + ret = IoKitUSB.GetPipeProperties(intf, (byte) pipeIndex, directionHolder, numberHolder, + transferTypeHolder, maxPacketSizeHolder, intervalHolder); + if (ret != 0) throw new MacosUSBException("Failed to get pipe properties", ret); var endpointInfo = new EndpointInfo(); endpointInfo.pipeIndex = pipeIndex; @@ -232,16 +228,18 @@ private void updateEndpointList() { private EndpointInfo getEndpointInfo(int endpointNumber) { if (endpoints != null) { var endpointOptional = endpoints.stream().filter(info -> info.endpointNumber == endpointNumber).findFirst(); - if (endpointOptional.isPresent()) - return endpointOptional.get(); + if (endpointOptional.isPresent()) return endpointOptional.get(); } - throw new MacosUSBException(String.format("Endpoint number %d is not part of a claimed interface or invalid", endpointNumber)); + throw new MacosUSBException(String.format("Endpoint number %d is not part of a claimed interface or invalid", + endpointNumber)); } - private static MemorySegment createDeviceRequest(MemorySession session, USBDirection direction, USBControlTransfer setup, MemorySegment data) { + private static MemorySegment createDeviceRequest(MemorySession session, USBDirection direction, + USBControlTransfer setup, MemorySegment data) { var deviceRequest = session.allocate(IoKitUSB.IOUSBDevRequest$Struct); - var bmRequestType = (direction == USBDirection.IN ? 0x80 : 0x00) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); + var bmRequestType = + (direction == USBDirection.IN ? 0x80 : 0x00) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); IoKitUSB.IOUSBDevRequest_bmRequestType.set(deviceRequest, (byte) bmRequestType); IoKitUSB.IOUSBDevRequest_bRequest.set(deviceRequest, setup.request()); IoKitUSB.IOUSBDevRequest_wValue.set(deviceRequest, setup.value()); @@ -258,8 +256,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { var deviceRequest = createDeviceRequest(session, USBDirection.IN, setup, data); int ret = IoKitUSB.DeviceRequest(device, deviceRequest); - if (ret != 0) - throw new MacosUSBException("Control IN transfer failed", ret); + if (ret != 0) throw new MacosUSBException("Control IN transfer failed", ret); int lenDone = (int) IoKitUSB.IOUSBDevRequest_wLenDone.get(deviceRequest); return data.asSlice(0, lenDone).toArray(JAVA_BYTE); @@ -271,13 +268,11 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { try (var session = MemorySession.openConfined()) { int dataLength = data != null ? data.length : 0; var dataSegment = session.allocate(dataLength); - if (dataLength > 0) - dataSegment.copyFrom(MemorySegment.ofArray(data)); + if (dataLength > 0) dataSegment.copyFrom(MemorySegment.ofArray(data)); var deviceRequest = createDeviceRequest(session, USBDirection.OUT, setup, dataSegment); int ret = IoKitUSB.DeviceRequest(device, deviceRequest); - if (ret != 0) - throw new MacosUSBException("Control IN transfer failed", ret); + if (ret != 0) throw new MacosUSBException("Control IN transfer failed", ret); } } @@ -306,7 +301,8 @@ public byte[] transferIn(int endpointNumber, int maxLength) { int ret = IoKitUSB.ReadPipe(endpointInfo.interfaceInfo.asMemoryAddress(), (byte) endpointInfo.pipeIndex, nativeData, sizeHolder); if (ret != 0) - throw new MacosUSBException(String.format("Receiving data from endpoint %d failed", endpointNumber), ret); + throw new MacosUSBException(String.format("Receiving data from endpoint %d failed", endpointNumber), + ret); int size = sizeHolder.get(JAVA_INT, 0); var result = new byte[size]; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceInfo.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceInfo.java deleted file mode 100644 index 18ff4ffb..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceInfo.java +++ /dev/null @@ -1,35 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.macos; - -import net.codecrete.usb.USBDevice; -import net.codecrete.usb.common.USBDeviceInfoImpl; - -public class MacosUSBDeviceInfo extends USBDeviceInfoImpl { - - MacosUSBDeviceInfo( - Object id, int vendorId, int productId, - String manufacturer, String product, String serial, - int classCode, int subclassCode, int protocolCode) { - - super(id, vendorId, productId, - manufacturer, product, serial, - classCode, subclassCode, protocolCode); - } - - @Override - public USBDevice open() { - var device = new MacosUSBDevice(id, this); - device.open(); - return device; - } - - Object getId() { - return this.id; - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 35e51254..32e62229 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -7,7 +7,7 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.USBDeviceInfo; +import net.codecrete.usb.USBDevice; import net.codecrete.usb.common.USBDeviceRegistry; import java.lang.foreign.*; @@ -44,25 +44,24 @@ protected void monitorDevices() { CoreFoundation.CFRunLoopAddSource(runLoop, runLoopSource, IoKit.kCFRunLoopDefaultMode); // setup notification for connected devices - var onDeviceConnectedMH = MethodHandles.lookup().findVirtual( - MacosUSBDeviceRegistry.class, "onDevicesConnected", - MethodType.methodType(void.class, MemoryAddress.class, int.class)); - int deviceConnectedIter = setupNotification(session, notifyPort, IoKit.kIOFirstMatchNotification, onDeviceConnectedMH); + var onDeviceConnectedMH = MethodHandles.lookup().findVirtual(MacosUSBDeviceRegistry.class, + "onDevicesConnected", MethodType.methodType(void.class, MemoryAddress.class, int.class)); + int deviceConnectedIter = setupNotification(session, notifyPort, IoKit.kIOFirstMatchNotification, + onDeviceConnectedMH); // iterate current devices in order to arm the notifications (and build initial device list) - var deviceList = new ArrayList(); + var deviceList = new ArrayList(); iterateDevices(deviceConnectedIter, false, (entryId, service) -> { var deviceInfo = createDeviceInfo(entryId, service); - if (deviceInfo != null) - deviceList.add(deviceInfo); + if (deviceInfo != null) deviceList.add(deviceInfo); }); setInitialDeviceList(deviceList); // setup notification for disconnected devices - var onDeviceDisconnectedMH = MethodHandles.lookup().findVirtual( - MacosUSBDeviceRegistry.class, "onDevicesDisconnected", - MethodType.methodType(void.class, MemoryAddress.class, int.class)); - int deviceDisconnectedIter = setupNotification(session, notifyPort, IoKit.kIOTerminatedNotification, onDeviceDisconnectedMH); + var onDeviceDisconnectedMH = MethodHandles.lookup().findVirtual(MacosUSBDeviceRegistry.class, + "onDevicesDisconnected", MethodType.methodType(void.class, MemoryAddress.class, int.class)); + int deviceDisconnectedIter = setupNotification(session, notifyPort, IoKit.kIOTerminatedNotification, + onDeviceDisconnectedMH); // iterate current devices in order to arm the notifications onDevicesDisconnected(NULL, deviceDisconnectedIter); @@ -93,17 +92,16 @@ private void iterateDevices(int iterator, boolean isDisconnected, BiConsumer { var deviceInfo = createDeviceInfo(entryId, service); - if (deviceInfo != null) - addDevice(deviceInfo); + if (deviceInfo != null) addDevice(deviceInfo); }); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index a7354bb0..7643b29c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -8,7 +8,6 @@ package net.codecrete.usb.windows; import net.codecrete.usb.USBControlTransfer; -import net.codecrete.usb.USBDeviceInfo; import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBException; import net.codecrete.usb.common.DescriptorParser; @@ -38,15 +37,20 @@ public class WindowsUSBDevice extends USBDeviceImpl { private MemoryAddress firstInterface; private final byte currentConfigurationValue; private Configuration configuration; - private List claimedInterfaces; - WindowsUSBDevice(Object id, USBDeviceInfo info, byte currentConfigurationValue) { - super(id, info); + WindowsUSBDevice(Object id, int vendorId, int productId, String manufacturer, String product, String serial, + int classCode, int subclassCode, int protocolCode, byte currentConfigurationValue) { + super(id, vendorId, productId, manufacturer, product, serial, classCode, subclassCode, protocolCode); this.currentConfigurationValue = currentConfigurationValue; } + @Override + public boolean isOpen() { + return device != null; + } + @Override public void open() { @@ -57,13 +61,9 @@ public void open() { // open Windows device var pathSegment = Win.createSegmentFromString(id.toString(), session); - device = Kernel32.CreateFileW(pathSegment, - Kernel32.GENERIC_WRITE() | Kernel32.GENERIC_READ(), - Kernel32.FILE_SHARE_WRITE() | Kernel32.FILE_SHARE_READ(), - NULL, - Kernel32.OPEN_EXISTING(), - Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), - NULL); + device = Kernel32.CreateFileW(pathSegment, Kernel32.GENERIC_WRITE() | Kernel32.GENERIC_READ(), + Kernel32.FILE_SHARE_WRITE() | Kernel32.FILE_SHARE_READ(), NULL, Kernel32.OPEN_EXISTING(), + Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), NULL); if (Win.IsInvalidHandle(device)) throw new USBException("Cannot open USB device", Kernel32.GetLastError()); @@ -98,7 +98,7 @@ public void open() { @Override - public void close() throws Exception { + public void close() { if (device == null) return; @@ -110,8 +110,7 @@ public void close() throws Exception { } public void claimInterface(int interfaceNumber) { - var intfOptional = - configuration.interfaces.stream().filter(intf -> intf.number == interfaceNumber).findFirst(); + var intfOptional = configuration.interfaces.stream().filter(intf -> intf.number == interfaceNumber).findFirst(); if (intfOptional.isEmpty()) throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); @@ -122,10 +121,10 @@ public void claimInterface(int interfaceNumber) { } public void releaseInterface(int interfaceNumber) { - var intfOptional = - claimedInterfaces.stream().filter(intf -> intf.number == interfaceNumber).findFirst(); + var intfOptional = claimedInterfaces.stream().filter(intf -> intf.number == interfaceNumber).findFirst(); if (intfOptional.isEmpty()) - throw new USBException(String.format("Interface has not been claimed or is invalid: number %d", interfaceNumber)); + throw new USBException(String.format("Interface has not been claimed or is invalid: number %d", + interfaceNumber)); claimedInterfaces.remove(intfOptional.get()); } @@ -141,14 +140,15 @@ private byte checkEndpointNumber(int endpointNumber, USBDirection direction) { } } - throw new USBException( - String.format("Endpoint number %d is not part of a claimed interface, the endpoint does not operate in the %s direction or is otherwise invalid", - endpointNumber, direction.name())); + throw new USBException(String.format("Endpoint number %d is not part of a claimed interface, the endpoint " + + "does not operate " + "in the %s direction or is otherwise invalid", endpointNumber, direction.name())); } - private MemorySegment createSetupPacket(MemorySession session, USBDirection direction, USBControlTransfer setup, MemorySegment data) { + private MemorySegment createSetupPacket(MemorySession session, USBDirection direction, USBControlTransfer setup, + MemorySegment data) { var setupPacket = session.allocate(USBStructs.SetupPacket$Struct); - var bmRequest = (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); + var bmRequest = + (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); USBStructs.SetupPacket_bmRequest.set(setupPacket, (byte) bmRequest); USBStructs.SetupPacket_bRequest.set(setupPacket, setup.request()); USBStructs.SetupPacket_wValue.set(setupPacket, setup.value()); @@ -164,7 +164,8 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { var setupPacket = createSetupPacket(session, USBDirection.IN, setup, buffer); var lengthHolder = session.allocate(JAVA_INT); - if (WinUSB.WinUsb_ControlTransfer(firstInterface, setupPacket, buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) + if (WinUSB.WinUsb_ControlTransfer(firstInterface, setupPacket, buffer, (int) buffer.byteSize(), + lengthHolder, NULL) == 0) throw new USBException("Control transfer IN failed", Kernel32.GetLastError()); int rxLength = lengthHolder.get(JAVA_INT, 0); @@ -186,7 +187,8 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { var setupPacket = createSetupPacket(session, USBDirection.OUT, setup, buffer); var lengthHolder = session.allocate(JAVA_INT); - if (WinUSB.WinUsb_ControlTransfer(firstInterface, setupPacket, buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) + if (WinUSB.WinUsb_ControlTransfer(firstInterface, setupPacket, buffer, (int) buffer.byteSize(), + lengthHolder, NULL) == 0) throw new USBException("Control transfer OUT failed", Kernel32.GetLastError()); } } @@ -200,7 +202,8 @@ public void transferOut(int endpointNumber, byte[] data) { buffer.copyFrom(MemorySegment.ofArray(data)); var lengthHolder = session.allocate(JAVA_INT); - if (WinUSB.WinUsb_WritePipe(firstInterface, endpointAddress, buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) + if (WinUSB.WinUsb_WritePipe(firstInterface, endpointAddress, buffer, (int) buffer.byteSize(), + lengthHolder, NULL) == 0) throw new USBException("Control transfer IN failed", Kernel32.GetLastError()); } } @@ -213,7 +216,8 @@ public byte[] transferIn(int endpointNumber, int maxLength) { var buffer = session.allocate(maxLength); var lengthHolder = session.allocate(JAVA_INT); - if (WinUSB.WinUsb_ReadPipe(firstInterface, endpointAddress, buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) + if (WinUSB.WinUsb_ReadPipe(firstInterface, endpointAddress, buffer, (int) buffer.byteSize(), lengthHolder + , NULL) == 0) throw new USBException("Control transfer IN failed", Kernel32.GetLastError()); int len = lengthHolder.get(JAVA_INT, 0); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java deleted file mode 100644 index cada0e64..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceInfo.java +++ /dev/null @@ -1,35 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.windows; - -import net.codecrete.usb.USBDevice; -import net.codecrete.usb.common.USBDeviceInfoImpl; - -public class WindowsUSBDeviceInfo extends USBDeviceInfoImpl { - - private final byte currentConfigurationValue; - - WindowsUSBDeviceInfo( - String devicePath, int vendorId, int productId, - String manufacturer, String product, String serial, - int classCode, int subclassCode, int protocolCode, - byte currentConfigurationValue) { - - super(devicePath, vendorId, productId, - manufacturer, product, serial, - classCode, subclassCode, protocolCode); - this.currentConfigurationValue = currentConfigurationValue; - } - - @Override - public USBDevice open() { - var device = new WindowsUSBDevice(id, this, currentConfigurationValue); - device.open(); - return device; - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 8b75b901..6cbd9ee6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -7,10 +7,10 @@ package net.codecrete.usb.windows; -import net.codecrete.usb.USBDeviceInfo; +import net.codecrete.usb.USBDevice; import net.codecrete.usb.USBException; import net.codecrete.usb.common.USBDescriptors; -import net.codecrete.usb.common.USBDeviceInfoImpl; +import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.common.USBDeviceRegistry; import net.codecrete.usb.common.USBStructs; import net.codecrete.usb.windows.gen.kernel32.Kernel32; @@ -44,16 +44,11 @@ protected void monitorDevices() { final var instance = Kernel32.GetModuleHandleW(NULL); // create upcall for handling window messages - var handleWindowMessageMH = MethodHandles.lookup().findVirtual( - WindowsUSBDeviceRegistry.class, - "handleWindowMessage", - MethodType.methodType(long.class, MemoryAddress.class, int.class, long.class, long.class) - ).bindTo(this); - var handleWindowMessageStub = Linker.nativeLinker().upcallStub( - handleWindowMessageMH, - FunctionDescriptor.of(JAVA_LONG, ADDRESS, JAVA_INT, JAVA_LONG, JAVA_LONG), - session - ); + var handleWindowMessageMH = MethodHandles.lookup().findVirtual(WindowsUSBDeviceRegistry.class, + "handleWindowMessage", MethodType.methodType(long.class, MemoryAddress.class, int.class, + long.class, long.class)).bindTo(this); + var handleWindowMessageStub = Linker.nativeLinker().upcallStub(handleWindowMessageMH, + FunctionDescriptor.of(JAVA_LONG, ADDRESS, JAVA_INT, JAVA_LONG, JAVA_LONG), session); // register window class var wx = session.allocate(WNDCLASSEXW.$LAYOUT()); @@ -64,18 +59,20 @@ protected void monitorDevices() { User32.RegisterClassExW(wx); // create message-only window - Addressable hwnd = User32.CreateWindowExW(0, className, windowName, 0, - 0, 0, 0, 0, User32.HWND_MESSAGE(), NULL, instance, NULL); + Addressable hwnd = User32.CreateWindowExW(0, className, windowName, 0, 0, 0, 0, 0, User32.HWND_MESSAGE(), + NULL, instance, NULL); if (hwnd == NULL) throw new USBException("internal error (CreateWindowExW)", Kernel32.GetLastError()); // configure notifications var notificationFilter = session.allocate(DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$set(notificationFilter, (int) notificationFilter.byteSize()); - DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$set(notificationFilter, User32.DBT_DEVTYP_DEVICEINTERFACE()); + DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$set(notificationFilter, + User32.DBT_DEVTYP_DEVICEINTERFACE()); DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid$slice(notificationFilter).copyFrom(USBHelper.GUID_DEVINTERFACE_USB_DEVICE); - var notifyHandle = User32.RegisterDeviceNotificationW(hwnd, notificationFilter, User32.DEVICE_NOTIFY_WINDOW_HANDLE()); + var notifyHandle = User32.RegisterDeviceNotificationW(hwnd, notificationFilter, + User32.DEVICE_NOTIFY_WINDOW_HANDLE()); if (notifyHandle == NULL) throw new USBException("internal error (RegisterDeviceNotificationW)", Kernel32.GetLastError()); @@ -94,13 +91,12 @@ protected void monitorDevices() { private void enumeratePresentDevices() { - List deviceList = new ArrayList<>(); + List deviceList = new ArrayList<>(); try (var outerSession = MemorySession.openConfined()) { // get device information set of all USB devices present - final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW( - USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, - SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); + final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, + NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); if (Win.IsInvalidHandle(devInfoSetHandle)) throw new USBException("internal error (SetupDiGetClassDevsW)"); @@ -124,7 +120,8 @@ private void enumeratePresentDevices() { throw new USBException("Internal error (SetupDiEnumDeviceInfo) "); } - var instanceID = DeviceProperty.getDeviceStringProperty(devInfoSetHandle, devInfo, DeviceProperty.DEVPKEY_Device_InstanceId); + var instanceID = DeviceProperty.getDeviceStringProperty(devInfoSetHandle, devInfo, + DeviceProperty.DEVPKEY_Device_InstanceId); var devicePath = DeviceProperty.getDevicePath(instanceID, USBHelper.GUID_DEVINTERFACE_USB_DEVICE); deviceList.add(createDeviceInfo(devInfoSetHandle, devInfo, devicePath, hubHandles)); @@ -134,11 +131,14 @@ private void enumeratePresentDevices() { } } - private USBDeviceInfo createDeviceInfo(MemoryAddress devInfoSetHandle, MemorySegment devInfo, String devicePath, HashMap hubHandles) { + private USBDevice createDeviceInfo(MemoryAddress devInfoSetHandle, MemorySegment devInfo, String devicePath, + HashMap hubHandles) { try (var session = MemorySession.openConfined()) { - var usbPortNum = DeviceProperty.getDeviceIntProperty(devInfoSetHandle, devInfo, DeviceProperty.DEVPKEY_Device_Address); - var parentInstanceID = DeviceProperty.getDeviceStringProperty(devInfoSetHandle, devInfo, DeviceProperty.DEVPKEY_Device_Parent); + var usbPortNum = DeviceProperty.getDeviceIntProperty(devInfoSetHandle, devInfo, + DeviceProperty.DEVPKEY_Device_Address); + var parentInstanceID = DeviceProperty.getDeviceStringProperty(devInfoSetHandle, devInfo, + DeviceProperty.DEVPKEY_Device_Parent); var hubPath = DeviceProperty.getDevicePath(parentInstanceID, USBHelper.GUID_DEVINTERFACE_USB_HUB); // open hub if not open yet @@ -156,7 +156,7 @@ private USBDeviceInfo createDeviceInfo(MemoryAddress devInfoSetHandle, MemorySeg } } - private USBDeviceInfo createDeviceInfo(String devicePath, MemoryAddress hubHandle, int usbPortNum) { + private USBDevice createDeviceInfo(String devicePath, MemoryAddress hubHandle, int usbPortNum) { try (var session = MemorySession.openConfined()) { @@ -164,17 +164,14 @@ private USBDeviceInfo createDeviceInfo(String devicePath, MemoryAddress hubHandl var connInfo = session.allocate(USBHelper.USB_NODE_CONNECTION_INFORMATION_EX$Struct); USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex.set(connInfo, usbPortNum); var sizeHolder = session.allocate(JAVA_INT); - if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), - connInfo, (int) connInfo.byteSize(), - connInfo, (int) connInfo.byteSize(), - sizeHolder, NULL) == 0) + if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), connInfo + , (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL) == 0) throw new USBException("Internal error (cannot get device descriptor)", Kernel32.GetLastError()); byte currentConfigurationValue = (byte) USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_CurrentConfigurationValue.get(connInfo); - var deviceDesc = connInfo.asSlice( - USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset, + var deviceDesc = connInfo.asSlice(USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset, USBDescriptors.Device$Struct.byteSize()); // extract info from device descriptor @@ -191,11 +188,8 @@ private USBDeviceInfo createDeviceInfo(String devicePath, MemoryAddress hubHandl int subClassCode = 255 & (byte) USBDescriptors.Device_bDeviceSubClass.get(deviceDesc); int protocolCode = 255 & (byte) USBDescriptors.Device_bDeviceProtocol.get(deviceDesc); - return new WindowsUSBDeviceInfo( - devicePath, vendorId, productId, - manufacturer, product, serialNumber, - classCode, subClassCode, protocolCode, - currentConfigurationValue); + return new WindowsUSBDevice(devicePath, vendorId, productId, manufacturer, product, serialNumber, + classCode, subClassCode, protocolCode, currentConfigurationValue); } } @@ -207,27 +201,27 @@ private String getStringDescriptor(Addressable hubHandle, int usbPortNumber, int final int dataLen = 32; var descriptorRequest = session.allocate(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset + dataLen); USBHelper.USB_DESCRIPTOR_REQUEST_ConnectionIndex.set(descriptorRequest, usbPortNumber); - var setupPacket = descriptorRequest.asSlice( - USBHelper.USB_DESCRIPTOR_REQUEST_SetupPacket$Offset, + var setupPacket = descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_SetupPacket$Offset, USBStructs.SetupPacket$Struct.byteSize()); USBStructs.SetupPacket_bmRequest.set(setupPacket, (byte) 0x80); USBStructs.SetupPacket_bRequest.set(setupPacket, USBHelper.USB_REQUEST_GET_DESCRIPTOR); - USBStructs.SetupPacket_wValue.set(setupPacket, (short) ((USBHelper.USB_STRING_DESCRIPTOR_TYPE << 8) | index)); + USBStructs.SetupPacket_wValue.set(setupPacket, + (short) ((USBHelper.USB_STRING_DESCRIPTOR_TYPE << 8) | index)); USBStructs.SetupPacket_wIndex.set(setupPacket, (short) 0x0409); USBStructs.SetupPacket_wLength.set(setupPacket, (short) dataLen); var sizeHolder = session.allocate(JAVA_INT); if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION(), - descriptorRequest, (int) descriptorRequest.byteSize(), - descriptorRequest, (int) descriptorRequest.byteSize(), - sizeHolder, NULL) == 0) - throw new USBException(String.format("Cannot retrieve string descriptor %d", index), Kernel32.GetLastError()); + descriptorRequest, (int) descriptorRequest.byteSize(), descriptorRequest, + (int) descriptorRequest.byteSize(), sizeHolder, NULL) == 0) + throw new USBException(String.format("Cannot retrieve string descriptor %d", index), + Kernel32.GetLastError()); // The string descriptor is not null terminated var stringDesc = descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, dataLen); int stringLen = 255 & (byte) USBHelper.USB_STRING_DESCRIPTOR_bLength.get(stringDesc); - var chars = stringDesc.asSlice(USBHelper.USB_STRING_DESCRIPTOR_bString$Offset, stringLen - 2) - .toArray(JAVA_CHAR); + var chars = + stringDesc.asSlice(USBHelper.USB_STRING_DESCRIPTOR_bString$Offset, stringLen - 2).toArray(JAVA_CHAR); return new String(chars); } } @@ -237,11 +231,14 @@ private long handleWindowMessage(MemoryAddress hWnd, int uMsg, long wParam, long // check for message related to connecting/disconnecting devices if (uMsg == User32.WM_DEVICECHANGE() && (wParam == User32.DBT_DEVICEARRIVAL() || wParam == User32.DBT_DEVICEREMOVECOMPLETE())) { try (var session = MemorySession.openConfined()) { - var data = MemorySegment.ofAddress(MemoryAddress.ofLong(lParam), DEV_BROADCAST_DEVICEINTERFACE_W.sizeof(), session); + var data = MemorySegment.ofAddress(MemoryAddress.ofLong(lParam), + DEV_BROADCAST_DEVICEINTERFACE_W.sizeof(), session); if (DEV_BROADCAST_HDR.dbch_devicetype$get(data) == User32.DBT_DEVTYP_DEVICEINTERFACE()) { // get device path - var nameSlice = MemorySegment.ofAddress(DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address(), 500, session); + var nameSlice = + MemorySegment.ofAddress(DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address(), + 500, session); var devicePath = Win.createStringFromSegment(nameSlice); if (wParam == User32.DBT_DEVICEARRIVAL()) onDeviceConnected(devicePath); @@ -260,9 +257,8 @@ private void onDeviceConnected(String devicePath) { try (var session = MemorySession.openConfined()) { // get device information set of all USB devices present - final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW( - USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, - SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); + final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, + NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); if (Win.IsInvalidHandle(devInfoSetHandle)) throw new USBException("internal error (SetupDiGetClassDevsW)", Kernel32.GetLastError()); @@ -312,10 +308,10 @@ private void onDeviceDisconnected(String devicePath) { * @return index, or -1 if not found */ @Override - protected int findDeviceIndex(List deviceList, Object deviceId) { + protected int findDeviceIndex(List deviceList, Object deviceId) { var id = deviceId.toString(); for (int i = 0; i < deviceList.size(); i++) { - var dev = (USBDeviceInfoImpl) deviceList.get(i); + var dev = (USBDeviceImpl) deviceList.get(i); if (id.equalsIgnoreCase(dev.getUniqueId().toString())) return i; } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java index 7b339966..7ad86268 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java @@ -87,10 +87,10 @@ static byte[] generateRandomBytes(int numBytes, long seed) { @BeforeAll static void openDevice() { - var deviceInfo = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); - if (deviceInfo == null) + device = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); + if (device == null) throw new IllegalStateException("USB loopback test device must be connected"); - device = deviceInfo.open(); + device.open(); device.claimInterface(0); } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java index e37efe5e..8d4e6211 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java @@ -42,10 +42,10 @@ void storeValueInDataStage_canBeRetrieved() { @BeforeAll static void openDevice() { - var deviceInfo = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); - if (deviceInfo == null) + device = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); + if (device == null) throw new IllegalStateException("USB loopback test device must be connected"); - device = deviceInfo.open(); + device.open(); device.claimInterface(0); } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java index 7c14eac8..2fa6e43b 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java @@ -21,8 +21,8 @@ public class DeviceEnumerationTest { @BeforeAll static void openDevice() { - var deviceInfo = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); - if (deviceInfo == null) + var device = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); + if (device == null) throw new IllegalStateException("USB loopback test device must be connected"); } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/IsSameDeviceTest.java b/java-does-usb/src/test/java/net/codecrete/usb/IsSameDeviceTest.java deleted file mode 100644 index f91b813d..00000000 --- a/java-does-usb/src/test/java/net/codecrete/usb/IsSameDeviceTest.java +++ /dev/null @@ -1,46 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Unit test for isSame() -// - -package net.codecrete.usb; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -public class IsSameDeviceTest { - - @Test - void getAllDevices_includesTestDevice() throws Exception { - var testDeviceInfo = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); - try (var testDevice = testDeviceInfo.open()) { - var deviceList = USB.getAllDevices(); - - long count = deviceList.stream().filter(testDevice::isSameDevice).count(); - assertEquals(1, count); - - count = deviceList.stream().filter((info) -> info.isSameDevice(testDevice)).count(); - assertEquals(1, count); - - count = deviceList.stream().filter(testDeviceInfo::isSameDevice).count(); - assertEquals(1, count); - - count = deviceList.stream().filter((info) -> info.isSameDevice(testDeviceInfo)).count(); - assertEquals(1, count); - } - } - - @Test - void openDevice_isSameAsDeviceInfo() throws Exception { - var testDeviceInfo = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); - try (var testDevice = testDeviceInfo.open()) { - assertTrue(testDevice.isSameDevice(testDeviceInfo)); - assertTrue(testDeviceInfo.isSameDevice(testDevice)); - } - } -} From b78e22b62740491b620c8827adbba06438e0f427 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 1 Sep 2022 21:06:16 +0200 Subject: [PATCH 033/433] Windows: fix string descriptor length --- .../net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 6cbd9ee6..abd46925 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -198,7 +198,7 @@ private String getStringDescriptor(Addressable hubHandle, int usbPortNumber, int return null; try (var session = MemorySession.openConfined()) { - final int dataLen = 32; + final int dataLen = 255; var descriptorRequest = session.allocate(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset + dataLen); USBHelper.USB_DESCRIPTOR_REQUEST_ConnectionIndex.set(descriptorRequest, usbPortNumber); var setupPacket = descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_SetupPacket$Offset, From 5779dff4a7b0d9e5641bb9ee08f7d2170fe095c1 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 1 Sep 2022 23:15:29 +0200 Subject: [PATCH 034/433] Linux: use pre-built jextract --- java-does-usb/jextract/gen_linux.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-does-usb/jextract/gen_linux.sh b/java-does-usb/jextract/gen_linux.sh index 1417a44e..40cbd3ff 100755 --- a/java-does-usb/jextract/gen_linux.sh +++ b/java-does-usb/jextract/gen_linux.sh @@ -1,6 +1,6 @@ #!/bin/sh -JEXTRACT=../../../jextract/build/jextract/bin/jextract +JEXTRACT=../../../jextract-19/bin/jextract # sd-device.h (install libsystemd-dev if file is missing) # Error: /usr/include/inttypes.h:290:8: error: unknown type name 'intmax_t' From df9a991932784ea81789a297d0c8d4666cd967e1 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 2 Sep 2022 08:31:21 +0200 Subject: [PATCH 035/433] Consistent naming of USB device --- .../net/codecrete/usb/USBDeviceFilter.java | 30 +++++---- .../usb/common/USBDeviceRegistry.java | 9 ++- .../usb/linux/LinuxUSBDeviceRegistry.java | 61 ++++++++++--------- .../usb/macos/MacosUSBDeviceRegistry.java | 16 ++--- .../usb/windows/WindowsUSBDeviceRegistry.java | 27 +++++--- 5 files changed, 84 insertions(+), 59 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java index 53400e2e..810fa964 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java @@ -10,9 +10,9 @@ import java.util.List; /** - * Filter parameters for matching USB device. + * Filter condition for matching USB devices. *

- * In order to match this filter, all non-null properties + * In order to match this condition, all non-null properties * of this instance must be equal to the same properties of the USB device. *

*

@@ -169,24 +169,30 @@ public void setSerialNumber(String serialNumber) { /** * Tests if the specified USB device matches this filter. * - * @param deviceInfo USB device information + * @param device USB device * @return {@code true} if it matches, {@code false} otherwise */ - public boolean matches(USBDevice deviceInfo) { - if (vendorId != null && deviceInfo.getVendorId() != vendorId) + public boolean matches(USBDevice device) { + if (vendorId != null && device.getVendorId() != vendorId) return false; - if (productId != null && deviceInfo.getProductId() != productId) + if (productId != null && device.getProductId() != productId) return false; - if (serialNumber != null && !serialNumber.equals(deviceInfo.getSerial())) + if (serialNumber != null && !serialNumber.equals(device.getSerial())) return false; - if (classCode != null && deviceInfo.getClassCode() != classCode) + if (classCode != null && device.getClassCode() != classCode) return false; - if (subclassCode != null && deviceInfo.getSubclassCode() != subclassCode) + if (subclassCode != null && device.getSubclassCode() != subclassCode) return false; - return protocolCode == null || deviceInfo.getProtocolCode() == protocolCode; + return protocolCode == null || device.getProtocolCode() == protocolCode; } - public static boolean matchesAny(USBDevice deviceInfo, List filters) { - return filters.stream().anyMatch(filter -> filter.matches(deviceInfo)); + /** + * Test if the USB devices matches any of the filter conditions. + * @param device the USB device + * @param filters a list of filter conditions + * @return {@code true} if it matches, {@code false} otherwise + */ + public static boolean matchesAny(USBDevice device, List filters) { + return filters.stream().anyMatch(filter -> filter.matches(device)); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index 929004bd..914d4bc2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -53,7 +53,10 @@ public void start() { * Enumerate the already present devices and then start monitoring * devices being connected and disconnected. *

- * Implementors of this method are expected to call, {@link #setInitialDeviceList(List)} + * This function is run in a background thread. + *

+ *

+ * Implementors of this method are expected to call {@link #setInitialDeviceList(List)} * after the initial device implementation. *

*/ @@ -165,13 +168,13 @@ protected void removeDevice(Object deviceId) { if (index < 0) return; // strange // copy list and remove device - var deviceInfo = devices.get(index); + var device = devices.get(index); var newDeviceList = new ArrayList<>(devices); newDeviceList.remove(index); devices = newDeviceList; // send notification - emitOnDeviceDisconnected(deviceInfo); + emitOnDeviceDisconnected(device); } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index c7a5566f..0698d89f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -63,18 +63,18 @@ protected void monitorDevices() { waitForFileDescriptor(fd, session); // retrieve change - var dev = udev.udev_monitor_receive_device(monitor); - if (dev == null) continue; // shouldn't happen + var udevDevice = udev.udev_monitor_receive_device(monitor); + if (udevDevice == null) continue; // shouldn't happen - session.addCloseAction(() -> udev.udev_device_unref(dev)); + session.addCloseAction(() -> udev.udev_device_unref(udevDevice)); // get details - var action = getDeviceAction(dev); + var action = getDeviceAction(udevDevice); if ("add".equals(action)) { - onDeviceConnected(dev); + onDeviceConnected(udevDevice); } else if ("remove".equals(action)) { - onDeviceDisconnected(dev); + onDeviceDisconnected(udevDevice); } } } @@ -113,8 +113,9 @@ private void enumeratePresentDevices(Addressable udevInstance) { session.addCloseAction(() -> udev.udev_device_unref(dev)); // get device details - var deviceInfo = getDeviceDetails(dev); - if (deviceInfo != null) result.add(deviceInfo); + var device = getDeviceDetails(dev); + if (device != null) + result.add(device); } } } @@ -122,57 +123,57 @@ private void enumeratePresentDevices(Addressable udevInstance) { setInitialDeviceList(result); } - private void onDeviceConnected(MemoryAddress device) { + private void onDeviceConnected(MemoryAddress udevDevice) { - var deviceInfo = getDeviceDetails(device); - if (deviceInfo == null) return; + var device = getDeviceDetails(udevDevice); + if (device == null) return; - addDevice(deviceInfo); + addDevice(device); } - private void onDeviceDisconnected(MemoryAddress device) { + private void onDeviceDisconnected(MemoryAddress udevDevice) { - var devPath = getDeviceName(device); + var devPath = getDeviceName(udevDevice); if (devPath == null) return; removeDevice(devPath); } /** - * Retrieves the device details and returns a {@code USBDeviceInfo} instance. + * Retrieves the device details and returns a {@code USBDevice} instance. *

* If the device is missing one of vendor ID, product ID or device path, * {@code null} is returned. *

* - * @param device the device - * @return the device info + * @param udevDevice the device (udev_device*) + * @return the device instance */ - private static USBDevice getDeviceDetails(MemoryAddress device) { + private static USBDevice getDeviceDetails(MemoryAddress udevDevice) { // retrieve device attributes - String idVendor = getDeviceAttribute(device, "idVendor"); + String idVendor = getDeviceAttribute(udevDevice, "idVendor"); if (idVendor == null) return null; - String idProduct = getDeviceAttribute(device, "idProduct"); + String idProduct = getDeviceAttribute(udevDevice, "idProduct"); if (idProduct == null) return null; // get device path - var devPath = getDeviceName(device); + var devPath = getDeviceName(udevDevice); if (devPath == null) return null; int vendorId = Integer.parseInt(idVendor, 16); int productId = Integer.parseInt(idProduct, 16); - // create device info instance - return new LinuxUSBDevice(devPath, vendorId, productId, getDeviceAttribute(device, "manufacturer"), - getDeviceAttribute(device, "product"), getDeviceAttribute(device, "serial"), 0, 0, 0); + // create device instance + return new LinuxUSBDevice(devPath, vendorId, productId, getDeviceAttribute(udevDevice, "manufacturer"), + getDeviceAttribute(udevDevice, "product"), getDeviceAttribute(udevDevice, "serial"), 0, 0, 0); } - private static String getDeviceAttribute(Addressable device, String attribute) { + private static String getDeviceAttribute(Addressable udevDevice, String attribute) { try (var session = MemorySession.openConfined()) { var sysattr = session.allocateUtf8String(attribute); - var valueAddr = udev.udev_device_get_sysattr_value(device, sysattr); + var valueAddr = udev.udev_device_get_sysattr_value(udevDevice, sysattr); if (valueAddr == NULL) return null; var value = MemorySegment.ofAddress(valueAddr, 2000, session); @@ -180,12 +181,12 @@ private static String getDeviceAttribute(Addressable device, String attribute) { } } - private static String getDeviceName(Addressable device) { - return Linux.createStringFromAddress(udev.udev_device_get_devnode(device)); + private static String getDeviceName(Addressable udevDevice) { + return Linux.createStringFromAddress(udev.udev_device_get_devnode(udevDevice)); } - private static String getDeviceAction(Addressable device) { - return Linux.createStringFromAddress(udev.udev_device_get_action(device)); + private static String getDeviceAction(Addressable udevDevice) { + return Linux.createStringFromAddress(udev.udev_device_get_action(udevDevice)); } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 32e62229..14c88cb4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -52,8 +52,9 @@ protected void monitorDevices() { // iterate current devices in order to arm the notifications (and build initial device list) var deviceList = new ArrayList(); iterateDevices(deviceConnectedIter, false, (entryId, service) -> { - var deviceInfo = createDeviceInfo(entryId, service); - if (deviceInfo != null) deviceList.add(deviceInfo); + var device = createDevice(entryId, service); + if (device != null) + deviceList.add(device); }); setInitialDeviceList(deviceList); @@ -110,7 +111,7 @@ private void iterateDevices(int iterator, boolean isDisconnected, BiConsumer { - var deviceInfo = createDeviceInfo(entryId, service); - if (deviceInfo != null) addDevice(deviceInfo); + var device = createDevice(entryId, service); + if (device != null) + addDevice(device); }); } @@ -177,7 +179,7 @@ private void onDevicesConnected(MemoryAddress ignoredRefCon, int iterator) { */ private void onDevicesDisconnected(MemoryAddress ignoredRefCon, int iterator) { - // process device info for disconnected devices + // process device iterator for disconnected devices iterateDevices(iterator, true, (entryId, service) -> removeDevice(entryId)); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index abd46925..013dc01a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -32,6 +32,11 @@ /** * Windows implementation of USB device registry. + *

+ * To retrieve details of a USB device, this class accesses it indirectly + * via the parent. To address it the parent's handle (hub handle) and + * the device's port number is needed. + *

*/ public class WindowsUSBDeviceRegistry extends USBDeviceRegistry { @@ -124,14 +129,14 @@ private void enumeratePresentDevices() { DeviceProperty.DEVPKEY_Device_InstanceId); var devicePath = DeviceProperty.getDevicePath(instanceID, USBHelper.GUID_DEVINTERFACE_USB_DEVICE); - deviceList.add(createDeviceInfo(devInfoSetHandle, devInfo, devicePath, hubHandles)); + deviceList.add(createDeviceFromDeviceInfo(devInfoSetHandle, devInfo, devicePath, hubHandles)); } setInitialDeviceList(deviceList); } } - private USBDevice createDeviceInfo(MemoryAddress devInfoSetHandle, MemorySegment devInfo, String devicePath, + private USBDevice createDeviceFromDeviceInfo(MemoryAddress devInfoSetHandle, MemorySegment devInfo, String devicePath, HashMap hubHandles) { try (var session = MemorySession.openConfined()) { @@ -152,11 +157,18 @@ private USBDevice createDeviceInfo(MemoryAddress devInfoSetHandle, MemorySegment hubHandles.put(hubPath, hubHandle); } - return createDeviceInfo(devicePath, hubHandle, usbPortNum); + return createDevice(devicePath, hubHandle, usbPortNum); } } - private USBDevice createDeviceInfo(String devicePath, MemoryAddress hubHandle, int usbPortNum) { + /** + * Retrieve device descriptor and create {@code USBDevice} instance + * @param devicePath the device path + * @param hubHandle the hub handle (parent) + * @param usbPortNum the USB port number + * @return the {@code USBDevice} instance + */ + private USBDevice createDevice(String devicePath, MemoryAddress hubHandle, int usbPortNum) { try (var session = MemorySession.openConfined()) { @@ -198,6 +210,7 @@ private String getStringDescriptor(Addressable hubHandle, int usbPortNumber, int return null; try (var session = MemorySession.openConfined()) { + final int dataLen = 255; var descriptorRequest = session.allocate(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset + dataLen); USBHelper.USB_DESCRIPTOR_REQUEST_ConnectionIndex.set(descriptorRequest, usbPortNumber); @@ -283,11 +296,11 @@ private void onDeviceConnected(String devicePath) { final var hubHandles = new HashMap(); session.addCloseAction(() -> hubHandles.forEach((path, handle) -> Kernel32.CloseHandle(handle))); - // create device info instance - var deviceInfo = createDeviceInfo(devInfoSetHandle, devInfo, devicePath, hubHandles); + // create device instance + var device = createDeviceFromDeviceInfo(devInfoSetHandle, devInfo, devicePath, hubHandles); // add it to device list - addDevice(deviceInfo); + addDevice(device); } } From f0a4f16dffa06137f968182b4faf9573b827c20e Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 2 Sep 2022 08:43:41 +0200 Subject: [PATCH 036/433] Code cleanup --- .../net/codecrete/usb/common/DescriptorParser.java | 3 +-- .../codecrete/usb/linux/LinuxUSBDeviceRegistry.java | 1 + .../codecrete/usb/macos/MacosUSBDeviceRegistry.java | 2 +- .../net/codecrete/usb/windows/DeviceProperty.java | 13 +------------ .../main/java/net/codecrete/usb/windows/Win.java | 8 +++++++- .../java/net/codecrete/usb/BulkTransferTest.java | 2 +- .../java/net/codecrete/usb/ControlTransferTest.java | 2 +- .../net/codecrete/usb/sample/MonitorDevices.java | 1 + 8 files changed, 14 insertions(+), 18 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java index 12b1f6aa..085f4ece 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java @@ -27,7 +27,7 @@ public static Configuration parseConfigurationDescriptor(byte[] descriptor) { var desc = MemorySegment.ofArray(descriptor); var config = parseConfiguration(desc, 0); Interface lastInterface = null; - Endpoint lastEndpoint = null; + Endpoint lastEndpoint; int offset = peekDescLength(desc, 0); while (offset < desc.byteSize()) { @@ -38,7 +38,6 @@ public static Configuration parseConfigurationDescriptor(byte[] descriptor) { if (descType == USBDescriptors.INTERFACE_DESCRIPTOR_TYPE) { lastInterface = parseInterface(desc, offset); config.interfaces.add(lastInterface); - lastEndpoint = null; } else if (descType == USBDescriptors.ENDPOINT_DESCRIPTOR_TYPE) { lastEndpoint = parseEndpoint(desc, offset); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 0698d89f..2a14ec07 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -56,6 +56,7 @@ protected void monitorDevices() { enumeratePresentDevices(udevInstance); // monitor device changes + //noinspection InfiniteLoopStatement while (true) { try (var session = MemorySession.openConfined()) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 14c88cb4..6d8470ab 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -130,7 +130,7 @@ private USBDevice createDevice(Long entryID, int service) { } private int setupNotification(MemorySession session, MemoryAddress notifyPort, MemorySegment notificationType, - MethodHandle callback) throws NoSuchMethodException, IllegalAccessException { + MethodHandle callback) { // new matching dictionary for (dis)connected device notifications MemoryAddress matchingDict = IoKit.IOServiceMatching(IoKit.kIOUSBDeviceClassName); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index 825cac53..4b4d974a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -112,18 +112,7 @@ public static MemorySegment createDEVPROPKEY(int data1, short data2, short data3 byte data4_4, byte data4_5, byte data4_6, byte data4_7, int pid) { var propKey = MemorySession.global().allocate(GUID.sizeof() + JAVA_INT.byteSize()); - GUID.Data1$set(propKey, data1); - GUID.Data2$set(propKey, data2); - GUID.Data3$set(propKey, data3); - var data4 = GUID.Data4$slice(propKey); - data4.set(JAVA_BYTE, 0, data4_0); - data4.set(JAVA_BYTE, 1, data4_1); - data4.set(JAVA_BYTE, 2, data4_2); - data4.set(JAVA_BYTE, 3, data4_3); - data4.set(JAVA_BYTE, 4, data4_4); - data4.set(JAVA_BYTE, 5, data4_5); - data4.set(JAVA_BYTE, 6, data4_6); - data4.set(JAVA_BYTE, 7, data4_7); + Win.setGUID(propKey, data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4, data4_5, data4_6, data4_7); propKey.set(JAVA_INT, 16, pid); return propKey; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index b0aabe7f..cc4f0c75 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -83,6 +83,13 @@ public static MemorySegment CreateGUID(int data1, short data2, short data3, byte data4_0, byte data4_1, byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7) { var guid = MemorySegment.allocateNative(GUID.$LAYOUT(), MemorySession.global()); + setGUID(guid, data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4, data4_5, data4_6, data4_7); + return guid; + } + + public static void setGUID(MemorySegment guid, int data1, short data2, short data3, + byte data4_0, byte data4_1, byte data4_2, byte data4_3, + byte data4_4, byte data4_5, byte data4_6, byte data4_7) { GUID.Data1$set(guid, data1); GUID.Data2$set(guid, data2); GUID.Data3$set(guid, data3); @@ -95,6 +102,5 @@ public static MemorySegment CreateGUID(int data1, short data2, short data3, data4.set(JAVA_BYTE, 5, data4_5); data4.set(JAVA_BYTE, 6, data4_6); data4.set(JAVA_BYTE, 7, data4_7); - return guid; } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java index 7ad86268..d841ef54 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java @@ -95,7 +95,7 @@ static void openDevice() { } @AfterAll - static void closeDevice() throws Exception { + static void closeDevice() { if (device != null) { device.close(); device = null; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java index 8d4e6211..93531c0b 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java @@ -50,7 +50,7 @@ static void openDevice() { } @AfterAll - static void closeDevice() throws Exception { + static void closeDevice() { if (device != null) { device.close(); device = null; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java b/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java index ea152847..c141e44e 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java @@ -22,6 +22,7 @@ public static void main(String[] args) throws InterruptedException { USB.setOnDeviceConnected((dev) -> System.out.println("Connected: " + dev.toString())); USB.setOnDeviceDisconnected((dev) -> System.out.println("Disconnected: " + dev.toString())); + //noinspection InfiniteLoopStatement while (true) { Thread.sleep(1000000); } From 2038688733ccee716087c58d93debd4ae691e15a Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 2 Sep 2022 07:07:54 +0200 Subject: [PATCH 037/433] Windows: Use generated SP_DEVICE_INTERFACE_DETAIL_DATA --- .../codecrete/usb/windows/DeviceProperty.java | 14 ++++-- .../SP_DEVICE_INTERFACE_DETAIL_DATA_W.java | 48 ------------------- 2 files changed, 9 insertions(+), 53 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index 4b4d974a..16d9413b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -11,6 +11,7 @@ import net.codecrete.usb.windows.gen.kernel32.GUID; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.setupapi.SP_DEVICE_INTERFACE_DATA; +import net.codecrete.usb.windows.gen.setupapi.SP_DEVICE_INTERFACE_DETAIL_DATA_W; import net.codecrete.usb.windows.gen.setupapi.SetupAPI; import java.lang.foreign.Addressable; @@ -95,15 +96,18 @@ public static String getDevicePath(String instanceID, Addressable interfaceGuid) if (SetupAPI.SetupDiEnumDeviceInterfaces(devInfoSetHandle, NULL, interfaceGuid, 0, devIntfData) == 0) throw new USBException("internal error (SetupDiEnumDeviceInterfaces)"); - // get path - var intfDetailData = session.allocate(SP_DEVICE_INTERFACE_DETAIL_DATA_W.$LAYOUT()); - SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$set(intfDetailData, 8); - int intfDetailDataSize = (int) SP_DEVICE_INTERFACE_DETAIL_DATA_W.$LAYOUT().byteSize(); + // get device path + // (SP_DEVICE_INTERFACE_DETAIL_DATA_W is of variable length and requires a bigger allocation so + // the device path fits) + final int devicePathOffset = 4; + var intfDetailData = session.allocate(4 + 260 * 2); + SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$set(intfDetailData, (int) SP_DEVICE_INTERFACE_DETAIL_DATA_W.sizeof()); + int intfDetailDataSize = (int) intfDetailData.byteSize(); if (SetupAPI.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, intfDetailData, intfDetailDataSize, NULL, NULL) == 0) throw new USBException("Internal error (SetupDiGetDeviceInterfaceDetailW)", Kernel32.GetLastError()); - return Win.createStringFromSegment(intfDetailData.asSlice(SP_DEVICE_INTERFACE_DETAIL_DATA_W.DevicePath$Offset)); + return Win.createStringFromSegment(intfDetailData.asSlice(devicePathOffset)); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java deleted file mode 100644 index f59344c3..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java +++ /dev/null @@ -1,48 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.windows; - -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.JAVA_CHAR; -import static java.lang.foreign.ValueLayout.JAVA_INT; - -/** - * SP_DEVICE_INTERFACE_DETAIL_DATA_W struct with a path length of 260 characters. - */ -public class SP_DEVICE_INTERFACE_DETAIL_DATA_W { - - // typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W { - // DWORD cbSize; - // WCHAR DevicePath[ANYSIZE_ARRAY]; - //} SP_DEVICE_INTERFACE_DETAIL_DATA_W, *PSP_DEVICE_INTERFACE_DETAIL_DATA_W; - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - JAVA_INT.withName("cbSize"), - MemoryLayout.sequenceLayout(260, JAVA_CHAR).withName("DevicePath") - ); - - public static GroupLayout $LAYOUT() { - return $struct$LAYOUT; - } - - static final VarHandle cbSize$VH = $struct$LAYOUT.varHandle(groupElement("cbSize")); - - public static int cbSize$get(MemorySegment seg) { - return (int) cbSize$VH.get(seg); - } - - public static void cbSize$set(MemorySegment seg, int x) { - cbSize$VH.set(seg, x); - } - - public static final long DevicePath$Offset = $struct$LAYOUT.byteOffset(groupElement("DevicePath")); -} From 1f14abe2ab725f53d6a199623f1957b4672e3809 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 2 Sep 2022 23:00:06 +0200 Subject: [PATCH 038/433] Interface, alternate settings and endpoint description --- .../codecrete/usb/USBAlternateInterface.java | 65 +++++++++ .../java/net/codecrete/usb/USBDevice.java | 9 ++ .../java/net/codecrete/usb/USBEndpoint.java | 62 +++++++++ .../net/codecrete/usb/USBEndpointType.java | 26 ++++ .../java/net/codecrete/usb/USBInterface.java | 52 ++++++++ .../usb/common/DescriptorParser.java | 107 ++++++++++----- .../usb/common/USBAlternateInterfaceImpl.java | 61 +++++++++ .../codecrete/usb/common/USBDeviceImpl.java | 55 ++++++-- .../usb/common/USBDeviceRegistry.java | 15 ++- .../codecrete/usb/common/USBEndpointImpl.java | 50 +++++++ .../usb/common/USBInterfaceImpl.java | 51 +++++++ .../codecrete/usb/linux/LinuxUSBDevice.java | 5 +- .../usb/linux/LinuxUSBDeviceRegistry.java | 2 +- .../net/codecrete/usb/macos/IoKitHelper.java | 8 +- .../codecrete/usb/macos/MacosUSBDevice.java | 124 +++++++++--------- .../usb/macos/MacosUSBDeviceRegistry.java | 63 +++++---- .../codecrete/usb/windows/DeviceProperty.java | 3 +- .../usb/windows/WindowsUSBDevice.java | 25 ++-- .../usb/windows/WindowsUSBDeviceRegistry.java | 5 +- .../net/codecrete/usb/BulkTransferTest.java | 23 +--- .../codecrete/usb/ControlTransferTest.java | 26 +--- .../net/codecrete/usb/DescriptionTest.java | 60 +++++++++ .../net/codecrete/usb/TestDeviceBase.java | 37 ++++++ 23 files changed, 725 insertions(+), 209 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/USBEndpoint.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/USBEndpointType.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/USBEndpointImpl.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java new file mode 100644 index 00000000..573a0a38 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java @@ -0,0 +1,65 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb; + +import java.util.List; + +/** + * USB alternate interface setting. + *

+ * Instances of this class describe an alternate setting of a USB interface. + *

+ */ +public interface USBAlternateInterface { + + /** + * Gets the alternate setting number. + *

+ * It is equal to the {@code bAlternateSetting} field of the interface descriptor. + * + * @return the alternate setting number + */ + int getNumber(); + + /** + * Gets the interface class. + *

+ * Interface classes are defined by the USB standard. + *

+ * + * @return the interface class + */ + int getClassCode(); + + /** + * Gets the interface subclass. + *

+ * Interface subclasses are defined by the USB standard. + *

+ * + * @return the interface subclass + */ + int getSubclassCode(); + + /** + * Gets the interface protocol. + *

+ * Interface protocols are defined by the USB standard. + *

+ * + * @return the interface protocol + */ + int getProtocolCode(); + + /** + * Gets the endpoints of this alternate interface settings. + * + * @return a list of endpoints. + */ + List getEndpoints(); +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index 6bf0e722..9031fcf5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -7,6 +7,8 @@ package net.codecrete.usb; +import java.util.List; + /** * USB device. *

@@ -98,6 +100,13 @@ public interface USBDevice { */ void close(); + /** + * Gets the interfaces of this device. + * + * @return a list of USB interfaces + */ + List getInterfaces(); + /** * Claims the specified interface for exclusive use. * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBEndpoint.java b/java-does-usb/src/main/java/net/codecrete/usb/USBEndpoint.java new file mode 100644 index 00000000..1991a4c7 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBEndpoint.java @@ -0,0 +1,62 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb; + +/** + * USB endpoint. + *

+ * Instances of this class describe a USB endpoint. + *

+ */ +public interface USBEndpoint { + + /** + * Gets the USB endpoint number. + *

+ * It is extracted from the {@code bEndpointAddress} field in the + * endpoint descriptor. The value is in the range 1 to 127 and does + * not include the bit indicating the direction. + *

+ *

+ * Use this number when calling any of the transfer methods of a + * {@link USBDevice} instace. + *

+ * + * @return the endpoint number + */ + int getNumber(); + + /** + * Gets the direction of the endpoint. + *

+ * This information is derived from the direction bit of the + * {@code bEndpointAddress} field in the endpoint descriptor. + *

+ * + * @return the direction + */ + USBDirection getDirection(); + + /** + * Gets the USB endpoint type. + * + * @return the type + */ + USBEndpointType getType(); + + /** + * Gets the packet size. + *

+ * USB data transfer is divided into packets. This value + * indicates the maximum packet size. + *

+ * + * @return the packet size, in bytes. + */ + int getPacketSize(); +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBEndpointType.java b/java-does-usb/src/main/java/net/codecrete/usb/USBEndpointType.java new file mode 100644 index 00000000..d9c38003 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBEndpointType.java @@ -0,0 +1,26 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb; + +/** + * USB endpoint type. + */ +public enum USBEndpointType { + /** + * Bulk transfer + */ + BULK, + /** + * Interrupt transfer + */ + INTERRUPT, + /** + * Isochronous transfer + */ + ISOCHRONOUS +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java new file mode 100644 index 00000000..fa1ab044 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java @@ -0,0 +1,52 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb; + +import java.util.List; + +/** + * USB interface. + *

+ * Instances of this class describe an interface of a USB device. + *

+ */ +public interface USBInterface { + + /** + * Gets the interface number. + *

+ * It is equal to the {@code bInterfaceNumber} field of the interface descriptor. + * + * @return the interface number + */ + int getNumber(); + + /** + * Indicates if this interface is currently claimed for exclusive access. + * + * @return {@code true} if it is claimed, {@code false} otherwise. + */ + boolean isClaimed(); + + /** + * Gets the currently selected alternate interface setting. + *

+ * Initially, the alternate settings with number 0 is selected. + *

+ * + * @return the alternate interface setting. + */ + USBAlternateInterface getAlternate(); + + /** + * Gets all alternate settings of this interface. + * + * @return a list of the alternate settings + */ + List getAlternates(); +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java index 085f4ece..5a329c0f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java @@ -7,6 +7,11 @@ package net.codecrete.usb.common; +import net.codecrete.usb.USBDirection; +import net.codecrete.usb.USBEndpointType; +import net.codecrete.usb.USBException; +import net.codecrete.usb.USBInterface; + import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; import java.util.ArrayList; @@ -25,9 +30,20 @@ public class DescriptorParser { */ public static Configuration parseConfigurationDescriptor(byte[] descriptor) { var desc = MemorySegment.ofArray(descriptor); + return parseConfigurationDescriptor(desc); + } + + /** + * Parse a USB configuration descriptor (incl. interface and endpoint descriptors) + * + * @param desc configuration descriptor + * @return parsed configuration data + */ + public static Configuration parseConfigurationDescriptor(MemorySegment desc) { var config = parseConfiguration(desc, 0); - Interface lastInterface = null; - Endpoint lastEndpoint; + + USBAlternateInterfaceImpl lastAlternate = null; + USBEndpointImpl lastEndpoint; int offset = peekDescLength(desc, 0); while (offset < desc.byteSize()) { @@ -36,12 +52,20 @@ public static Configuration parseConfigurationDescriptor(byte[] descriptor) { int descType = peekDescType(desc, offset); if (descType == USBDescriptors.INTERFACE_DESCRIPTOR_TYPE) { - lastInterface = parseInterface(desc, offset); - config.interfaces.add(lastInterface); + var intf = parseInterface(desc, offset); + var parent = config.findInterfaceByNumber(intf.getNumber()); + if (parent != null) { + parent.addAlternate(intf.getAlternate()); + } else { + config.addInterface(intf); + } + lastAlternate = (USBAlternateInterfaceImpl) intf.getAlternate(); } else if (descType == USBDescriptors.ENDPOINT_DESCRIPTOR_TYPE) { lastEndpoint = parseEndpoint(desc, offset); - lastInterface.endpoints.add(lastEndpoint); + if (lastAlternate != null) + lastAlternate.addEndpoint(lastEndpoint); + } else { System.err.println("Warning: unsupported USB descriptor type " + descType); } @@ -55,6 +79,9 @@ public static Configuration parseConfigurationDescriptor(byte[] descriptor) { private static Configuration parseConfiguration(MemorySegment descriptor, int offset) { var desc = descriptor.asSlice(offset, USBDescriptors.Configuration.byteSize()); var config = new Configuration(); + if (USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE != (byte) USBDescriptors.Configuration_bDescriptorType.get(desc)) + throw new USBException("Invalid USB configuration descriptor"); + config.configValue = (byte) USBDescriptors.Configuration_bConfigurationValue.get(desc); config.attributes = (byte) USBDescriptors.Configuration_bmAttributes.get(desc); config.maxPower = (byte) USBDescriptors.Configuration_bMaxPower.get(desc); @@ -62,26 +89,41 @@ private static Configuration parseConfiguration(MemorySegment descriptor, int of return config; } - private static Interface parseInterface(MemorySegment descriptor, int offset) { + private static USBInterfaceImpl parseInterface(MemorySegment descriptor, int offset) { var desc = descriptor.asSlice(offset, USBDescriptors.Interface.byteSize()); - var intf = new Interface(); - intf.number = (byte) USBDescriptors.Interface_bInterfaceNumber.get(desc); - intf.altSetting = (byte) USBDescriptors.Interface_bAlternateSetting.get(desc); - intf.classCode = (byte) USBDescriptors.Interface_bInterfaceClass.get(desc); - intf.subclassCode = (byte) USBDescriptors.Interface_bInterfaceSubClass.get(desc); - intf.protocol = (byte) USBDescriptors.Interface_bInterfaceProtocol.get(desc); - intf.endpoints = new ArrayList<>(); - return intf; + var number = 255 & (byte) USBDescriptors.Interface_bInterfaceNumber.get(desc); + var altSetting = 255 & (byte) USBDescriptors.Interface_bAlternateSetting.get(desc); + var classCode = 255 & (byte) USBDescriptors.Interface_bInterfaceClass.get(desc); + var subclassCode = 255 & (byte) USBDescriptors.Interface_bInterfaceSubClass.get(desc); + var protocol = 255 & (byte) USBDescriptors.Interface_bInterfaceProtocol.get(desc); + var alternate = new USBAlternateInterfaceImpl(altSetting, classCode, subclassCode, protocol, new ArrayList<>()); + return new USBInterfaceImpl(number, List.of(alternate)); } - private static Endpoint parseEndpoint(MemorySegment descriptor, int offset) { + private static USBEndpointImpl parseEndpoint(MemorySegment descriptor, int offset) { var desc = descriptor.asSlice(offset, USBDescriptors.Endpoint.byteSize()); - var endpoint = new Endpoint(); - endpoint.address = (byte) USBDescriptors.Endpoint_bEndpointAddress.get(desc); - endpoint.attributes = (byte) USBDescriptors.Endpoint_bmAttributes.get(desc); - endpoint.maxPacketSize = (short) USBDescriptors.Endpoint_wMaxPacketSize.get(desc); - endpoint.interval = (byte) USBDescriptors.Endpoint_bInterval.get(desc); - return endpoint; + var address = (byte) USBDescriptors.Endpoint_bEndpointAddress.get(desc); + var attributes = (byte) USBDescriptors.Endpoint_bmAttributes.get(desc); + var maxPacketSize = (short) USBDescriptors.Endpoint_wMaxPacketSize.get(desc); + return new USBEndpointImpl(getEndpointNumber(address), getEndpointDirection(address), + getEndpointType(attributes), maxPacketSize); + } + + private static USBDirection getEndpointDirection(byte address) { + return (address & 0x80) != 0 ? USBDirection.IN : USBDirection.OUT; + } + + private static int getEndpointNumber(byte address) { + return address & 0x7f; + } + + private static USBEndpointType getEndpointType(byte attributes) { + return switch (attributes & 0x3) { + case 1 -> USBEndpointType.ISOCHRONOUS; + case 2 -> USBEndpointType.BULK; + case 3 -> USBEndpointType.INTERRUPT; + default -> null; + }; } /** @@ -107,25 +149,18 @@ private static int peekDescType(MemorySegment desc, int offset) { } public static class Configuration { - public List interfaces; + public List interfaces; public byte configValue; public byte attributes; public byte maxPower; - } - public static class Interface { - public byte number; - public byte altSetting; - public List endpoints; - public byte classCode; - public byte subclassCode; - public byte protocol; - } + void addInterface(USBInterface intf) { + interfaces.add(intf); + } - public static class Endpoint { - public byte address; - public byte attributes; - public short maxPacketSize; - public byte interval; + public USBInterfaceImpl findInterfaceByNumber(int number) { + return (USBInterfaceImpl) interfaces.stream() + .filter((intf) -> intf.getNumber() == number).findFirst().orElse(null); + } } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java new file mode 100644 index 00000000..9b46d54b --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java @@ -0,0 +1,61 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +import net.codecrete.usb.USBAlternateInterface; +import net.codecrete.usb.USBEndpoint; + +import java.util.Collections; +import java.util.List; + +public class USBAlternateInterfaceImpl implements USBAlternateInterface { + + private final int number; + private final int classCode; + private final int subclassCode; + private final int protocolCode; + private final List endpoints; + + public USBAlternateInterfaceImpl(int number, int classCode, int subclassCode, int protocolCode, + List endpoints) { + this.number = number; + this.classCode = classCode; + this.subclassCode = subclassCode; + this.protocolCode = protocolCode; + this.endpoints = endpoints; + } + + @Override + public int getNumber() { + return number; + } + + @Override + public int getClassCode() { + return classCode; + } + + @Override + public int getSubclassCode() { + return subclassCode; + } + + @Override + public int getProtocolCode() { + return protocolCode; + } + + @Override + public List getEndpoints() { + return Collections.unmodifiableList(endpoints); + } + + void addEndpoint(USBEndpoint endpoint) { + endpoints.add(endpoint); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index a62f75c6..63e321fc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -7,10 +7,10 @@ package net.codecrete.usb.common; -import net.codecrete.usb.USBControlTransfer; -import net.codecrete.usb.USBDevice; -import net.codecrete.usb.USBRecipient; -import net.codecrete.usb.USBRequestType; +import net.codecrete.usb.*; + +import java.util.Collections; +import java.util.List; public abstract class USBDeviceImpl implements USBDevice { @@ -20,9 +20,11 @@ public abstract class USBDeviceImpl implements USBDevice { protected final String manufacturer; protected final String product; protected final String serial; - protected final int classCode; - protected final int subclassCode; - protected final int protocolCode; + protected int classCode; + protected int subclassCode; + protected int protocolCode; + + protected List interfaces; /** * Creates a new instance. @@ -33,12 +35,9 @@ public abstract class USBDeviceImpl implements USBDevice { * @param manufacturer manufacturer name * @param product product name * @param serial serial number - * @param classCode USB device class code - * @param subclassCode USB device subclass code - * @param protocolCode USB device protocol */ protected USBDeviceImpl(Object id, int vendorId, int productId, String manufacturer, String product, - String serial, int classCode, int subclassCode, int protocolCode) { + String serial) { assert id != null; @@ -48,45 +47,58 @@ protected USBDeviceImpl(Object id, int vendorId, int productId, String manufactu this.manufacturer = manufacturer; this.product = product; this.serial = serial; - this.classCode = classCode; - this.subclassCode = subclassCode; - this.protocolCode = protocolCode; } + @Override public abstract void open(); + @Override public abstract void close(); + @Override public abstract boolean isOpen(); + protected void checkIsOpen() { + if (!isOpen()) + throw new USBException("The device needs to be open to call this method"); + } + + @Override public int getProductId() { return productId; } + @Override public int getVendorId() { return vendorId; } + @Override public String getProduct() { return product; } + @Override public String getManufacturer() { return manufacturer; } + @Override public String getSerial() { return serial; } + @Override public int getClassCode() { return classCode; } + @Override public int getSubclassCode() { return subclassCode; } + @Override public int getProtocolCode() { return protocolCode; } @@ -95,17 +107,32 @@ public Object getUniqueId() { return id; } + @Override + public List getInterfaces() { + return Collections.unmodifiableList(interfaces); + } + + public void setInterfaces(List interfaces) { + this.interfaces = interfaces; + } + + @Override public abstract void claimInterface(int interfaceNumber); + @Override public abstract void releaseInterface(int interfaceNumber); + @Override public abstract byte[] controlTransferIn(USBControlTransfer setup, int length); + @Override public abstract void controlTransferOut(USBControlTransfer setup, byte[] data); + @Override public abstract void transferOut(int endpointNumber, byte[] data); + @Override public abstract byte[] transferIn(int endpointNumber, int maxLength); protected byte[] getDescriptor(int descriptorType, int index, int language) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index 914d4bc2..476f6c18 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -165,7 +165,8 @@ protected void addDevice(USBDevice device) { protected void removeDevice(Object deviceId) { // locate device to be removed int index = findDeviceIndex(devices, deviceId); - if (index < 0) return; // strange + if (index < 0) + return; // strange // copy list and remove device var device = devices.get(index); @@ -191,4 +192,16 @@ protected int findDeviceIndex(List deviceList, Object deviceId) { } return -1; } + /** + * Finds the device with the given ID in the device list + * + * @param deviceId the unique device ID + * @return return device, or {@code null} if not found. + */ + protected USBDevice findDevice(Object deviceId) { + int index = findDeviceIndex(devices, deviceId); + if (index < 0) + return null; + return devices.get(index); + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBEndpointImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBEndpointImpl.java new file mode 100644 index 00000000..795b1138 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBEndpointImpl.java @@ -0,0 +1,50 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +import net.codecrete.usb.USBDirection; +import net.codecrete.usb.USBEndpoint; +import net.codecrete.usb.USBEndpointType; + +/** + * Implementation of {@code USBEndpoint} interface. + */ +public class USBEndpointImpl implements USBEndpoint { + + private final int number; + private final USBDirection direction; + private final USBEndpointType type; + private final int packetSize; + + public USBEndpointImpl(int number, USBDirection direction, USBEndpointType type, int packetSize) { + this.number = number; + this.direction = direction; + this.type = type; + this.packetSize = packetSize; + } + + @Override + public int getNumber() { + return number; + } + + @Override + public USBDirection getDirection() { + return direction; + } + + @Override + public USBEndpointType getType() { + return type; + } + + @Override + public int getPacketSize() { + return packetSize; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java new file mode 100644 index 00000000..52bd6131 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java @@ -0,0 +1,51 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +import net.codecrete.usb.USBAlternateInterface; +import net.codecrete.usb.USBInterface; + +import java.util.Collections; +import java.util.List; + +public class USBInterfaceImpl implements USBInterface { + + private int number; + private USBAlternateInterface alternate; + private List alternates; + + public USBInterfaceImpl(int number, List alternates) { + this.number = number; + this.alternates = alternates; + this.alternate = alternates.get(0); + } + + @Override + public int getNumber() { + return 0; + } + + @Override + public boolean isClaimed() { + return false; + } + + @Override + public USBAlternateInterface getAlternate() { + return alternate; + } + + @Override + public List getAlternates() { + return Collections.unmodifiableList(alternates); + } + + void addAlternate(USBAlternateInterface alt) { + alternates.add(alt); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 101ae04e..8bb11a1b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -27,9 +27,8 @@ public class LinuxUSBDevice extends USBDeviceImpl { private int fd = -1; - LinuxUSBDevice(Object id, int vendorId, int productId, String manufacturer, String product, String serial, - int classCode, int subclassCode, int protocolCode) { - super(id, vendorId, productId, manufacturer, product, serial, classCode, subclassCode, protocolCode); + LinuxUSBDevice(Object id, int vendorId, int productId, String manufacturer, String product, String serial) { + super(id, vendorId, productId, manufacturer, product, serial); } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 2a14ec07..57e22925 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -168,7 +168,7 @@ private static USBDevice getDeviceDetails(MemoryAddress udevDevice) { // create device instance return new LinuxUSBDevice(devPath, vendorId, productId, getDeviceAttribute(udevDevice, "manufacturer"), - getDeviceAttribute(udevDevice, "product"), getDeviceAttribute(udevDevice, "serial"), 0, 0, 0); + getDeviceAttribute(udevDevice, "product"), getDeviceAttribute(udevDevice, "serial")); } private static String getDeviceAttribute(Addressable udevDevice, String attribute) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index 124f17e1..d4727a9b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -39,7 +39,7 @@ public class IoKitHelper { * @param interfaceId the interface ID * @return the interface, or null if the plugin type or interface is not available */ - public static MemoryAddress GetInterface(int service, Addressable pluginType, MemoryAddress interfaceId) { + public static MemoryAddress getInterface(int service, Addressable pluginType, MemoryAddress interfaceId) { try (var session = MemorySession.openConfined()) { // MemorySegment for holding IOCFPlugInInterface** var plugPointer = session.allocate(ADDRESS, NULL); @@ -50,7 +50,7 @@ public static MemoryAddress GetInterface(int service, Addressable pluginType, Me return null; var plug = Foreign.derefAddress(plugPointer.address(), session); - // MemorySegment for holding XXXInterface** + // MemorySegment for holding xxxInterface** var intf = session.allocate(ADDRESS, NULL); // UUID bytes var refiid = MemorySegment.ofAddress(interfaceId.addOffset(CFUUID_bytes$Offset), CFUUID.byteSize(), session); @@ -73,7 +73,7 @@ public static MemoryAddress GetInterface(int service, Addressable pluginType, Me * @param key the property key * @return the property value, or {@code null} if the service doesn't have the property */ - public static Integer GetPropertyInt(int service, String key) { + public static Integer getPropertyInt(int service, String key) { var value = IoKit.IORegistryEntryCreateCFProperty(service, key, NULL, 0); if (value == NULL) return null; @@ -102,7 +102,7 @@ public static Integer GetPropertyInt(int service, String key) { * @param key the property key * @return the property value, or {@code null} if the service doesn't have the property */ - public static String GetPropertyString(int service, String key) { + public static String getPropertyString(int service, String key) { var value = IoKit.IORegistryEntryCreateCFProperty(service, key, NULL, 0); if (value == NULL) return null; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index a76dd584..8413d8e5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -9,6 +9,8 @@ import net.codecrete.usb.USBControlTransfer; import net.codecrete.usb.USBDirection; +import net.codecrete.usb.USBException; +import net.codecrete.usb.common.DescriptorParser; import net.codecrete.usb.common.USBDescriptors; import net.codecrete.usb.common.USBDeviceImpl; @@ -18,98 +20,99 @@ import java.util.ArrayList; import java.util.List; -import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.MemoryAddress.ofLong; import static java.lang.foreign.ValueLayout.*; public class MacosUSBDevice extends USBDeviceImpl { - private MemoryAddress device; + private final MemoryAddress device; private int configurationValue; private List claimedInterfaces; private List endpoints; - MacosUSBDevice(Object id, int vendorId, int productId, String manufacturer, String product, String serial, - int classCode, int subclassCode, int protocolCode) { - super(id, vendorId, productId, manufacturer, product, serial, classCode, subclassCode, protocolCode); + MacosUSBDevice(MemoryAddress device, Object id, int vendorId, int productId, String manufacturer, String product, String serial) { + super(id, vendorId, productId, manufacturer, product, serial); + this.device = device; + IoKit.AddRef(device); + + try { + loadDescription(); + } finally { + closeFully(); + } } @Override public boolean isOpen() { - return device != null; + return claimedInterfaces != null; } @Override public void open() { - if (device != null) return; + if (isOpen()) + throw new USBException("the device is already open"); - try (var session = MemorySession.openConfined()) { + // open device + int ret = IoKitUSB.USBDeviceOpen(device); + if (ret != 0) + throw new MacosUSBException("unable to open USB device", ret); - // get service from IO registry - var matching = IoKit.IORegistryEntryIDMatching((Long) id); - if (matching == NULL) throw new MacosUSBException("IORegistryEntryIDMatching failed"); - - // Consumes matching instance - int service = IoKit.IOServiceGetMatchingService(IoKit.kIOMasterPortDefault, matching); - if (service == 0) throw new MacosUSBException("unable to open USB device (IOServiceGetMatchingService)"); - session.addCloseAction(() -> IoKit.IOObjectRelease(service)); - - // get user client interface - device = IoKitHelper.GetInterface(service, IoKit.kIOUSBDeviceUserClientTypeID, - IoKit.kIOUSBDeviceInterfaceID100); - if (device == null) throw new MacosUSBException("unable to open USB device (get client interface)"); - - // open device - int ret = IoKitUSB.USBDeviceOpen(device); - if (ret != 0) { - IoKit.Release(device); - device = null; - throw new MacosUSBException("unable to open USB device", ret); - } + // set configuration + ret = IoKitUSB.SetConfiguration(device, (byte) configurationValue); + if (ret != 0) + throw new MacosUSBException("failed to set configuration", ret); + + claimedInterfaces = new ArrayList<>(); + } + + @Override + public void close() { + if (!isOpen()) + return; + + for (InterfaceInfo interfaceInfo : claimedInterfaces) { + IoKitUSB.USBInterfaceClose(interfaceInfo.asMemoryAddress()); + IoKit.Release(interfaceInfo.asMemoryAddress()); + } + claimedInterfaces = null; + endpoints = null; + } + + void closeFully() { + close(); + IoKitUSB.USBDeviceClose(device); + IoKit.Release(device); + } + + private void loadDescription() { + try (var session = MemorySession.openConfined()) { try { // retrieve information of first configuration var descPtrHolder = session.allocate(ADDRESS); - ret = IoKitUSB.GetConfigurationDescriptorPtr(device, (byte) 0, descPtrHolder); - if (ret != 0) throw new MacosUSBException("failed to query first configuration", ret); + int ret = IoKitUSB.GetConfigurationDescriptorPtr(device, (byte) 0, descPtrHolder); + if (ret != 0) + throw new MacosUSBException("failed to query first configuration", ret); // get value of first configuration - var configDesc = MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), + var configDescHeader = MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), USBDescriptors.Configuration.byteSize(), session); - configurationValue = 255 & (byte) USBDescriptors.Configuration_bConfigurationValue.get(configDesc); + int totalLength = (short) USBDescriptors.Configuration_wTotalLength.get(configDescHeader); + var configDesc = MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), + totalLength, session); - // set configuration - ret = IoKitUSB.SetConfiguration(device, (byte) configurationValue); - if (ret != 0) throw new MacosUSBException("failed to set configuration", ret); + var configuration = DescriptorParser.parseConfigurationDescriptor(configDesc); + + configurationValue = 255 & configuration.configValue; + setInterfaces(configuration.interfaces); } catch (Throwable e) { - IoKitUSB.USBDeviceClose(device); - IoKit.Release(device); - device = null; configurationValue = 0; throw e; } } } - @Override - public void close() { - if (device == null) return; - - if (claimedInterfaces != null) { - for (InterfaceInfo interfaceInfo : claimedInterfaces) { - IoKitUSB.USBInterfaceClose(interfaceInfo.asMemoryAddress()); - IoKit.Release(interfaceInfo.asMemoryAddress()); - } - claimedInterfaces = null; - endpoints = null; - } - - IoKitUSB.USBDeviceClose(device); - IoKit.Release(device); - device = null; - } - private InterfaceInfo findInterface(int interfaceNumber) { try (var outerSession = MemorySession.openConfined()) { @@ -132,7 +135,7 @@ private InterfaceInfo findInterface(int interfaceNumber) { final int service_final = service; session.addCloseAction(() -> IoKit.IOObjectRelease(service_final)); - final MemoryAddress intf = IoKitHelper.GetInterface(service, + final MemoryAddress intf = IoKitHelper.getInterface(service, IoKit.kIOUSBInterfaceUserClientTypeID, IoKit.kIOUSBInterfaceInterfaceID100); if (intf == null) continue; @@ -155,6 +158,8 @@ private InterfaceInfo findInterface(int interfaceNumber) { } public void claimInterface(int interfaceNumber) { + checkIsOpen();; + var interfaceInfo = findInterface(interfaceNumber); try { @@ -165,13 +170,14 @@ public void claimInterface(int interfaceNumber) { throw t; } - if (claimedInterfaces == null) claimedInterfaces = new ArrayList<>(); claimedInterfaces.add(interfaceInfo); updateEndpointList(); } public void releaseInterface(int interfaceNumber) { + checkIsOpen(); + var interfaceInfoOptional = claimedInterfaces.stream().filter(info -> info.interfaceNumber == interfaceNumber).findFirst(); if (interfaceInfoOptional.isEmpty()) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 6d8470ab..b8404ebe 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -15,7 +15,6 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.ArrayList; -import java.util.function.BiConsumer; import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.*; @@ -51,8 +50,8 @@ protected void monitorDevices() { // iterate current devices in order to arm the notifications (and build initial device list) var deviceList = new ArrayList(); - iterateDevices(deviceConnectedIter, false, (entryId, service) -> { - var device = createDevice(entryId, service); + iterateDevices(deviceConnectedIter, (entryId, service, deviceIntf) -> { + var device = createDevice(entryId, service, deviceIntf); if (device != null) deviceList.add(device); }); @@ -79,10 +78,9 @@ protected void monitorDevices() { * Process the devices resulting from the iterator * * @param iterator the iterator - * @param isDisconnected flag is the iterator is for disconnected devices * @param function a function that will be called for each device with the entry ID and the service */ - private void iterateDevices(int iterator, boolean isDisconnected, BiConsumer function) { + private void iterateDevices(int iterator, IOKitDeviceConsumer function) { int svc; while ((svc = IoKit.IOIteratorNext(iterator)) != 0) { @@ -91,42 +89,37 @@ private void iterateDevices(int iterator, boolean isDisconnected, BiConsumer IoKit.IOObjectRelease(service)); - // test if service has user client interface (if not, it is likely a controller) - if (!isDisconnected) { - final var device = IoKitHelper.GetInterface(service, IoKit.kIOUSBDeviceUserClientTypeID, - IoKit.kIOUSBDeviceInterfaceID100); - if (device == null) continue; - IoKit.Release(device); - } + var device = IoKitHelper.getInterface(service, IoKit.kIOUSBDeviceUserClientTypeID, + IoKit.kIOUSBDeviceInterfaceID100); // get entry ID (as unique ID) var entryIdHolder = session.allocate(JAVA_LONG); int ret = IoKit.IORegistryEntryGetRegistryEntryID(service, entryIdHolder); - if (ret != 0) throw new MacosUSBException("IORegistryEntryGetRegistryEntryID failed", ret); + if (ret != 0) + throw new MacosUSBException("IORegistryEntryGetRegistryEntryID failed", ret); var entryId = entryIdHolder.get(JAVA_LONG, 0); // call function to process device - function.accept(entryId, service); + function.accept(entryId, service, device); } } } - private USBDevice createDevice(Long entryID, int service) { + private USBDevice createDevice(Long entryID, int service, MemoryAddress deviceIntf) { - Integer vendorId = IoKitHelper.GetPropertyInt(service, "idVendor"); - Integer productId = IoKitHelper.GetPropertyInt(service, "idProduct"); - String manufacturer = IoKitHelper.GetPropertyString(service, "kUSBVendorString"); - String product = IoKitHelper.GetPropertyString(service, "kUSBProductString"); - String serial = IoKitHelper.GetPropertyString(service, "kUSBSerialNumberString"); - Integer classCode = IoKitHelper.GetPropertyInt(service, "bDeviceClass"); - Integer subclassCode = IoKitHelper.GetPropertyInt(service, "bDeviceSubClass"); - Integer protocolCode = IoKitHelper.GetPropertyInt(service, "bDeviceProtocol"); + if (deviceIntf == null) + return null; + + Integer vendorId = IoKitHelper.getPropertyInt(service, "idVendor"); + Integer productId = IoKitHelper.getPropertyInt(service, "idProduct"); + String manufacturer = IoKitHelper.getPropertyString(service, "kUSBVendorString"); + String product = IoKitHelper.getPropertyString(service, "kUSBProductString"); + String serial = IoKitHelper.getPropertyString(service, "kUSBSerialNumberString"); - if (vendorId == null || productId == null || classCode == null || subclassCode == null || protocolCode == null) + if (vendorId == null || productId == null) return null; - return new MacosUSBDevice(entryID, vendorId, productId, manufacturer, product, serial, classCode, - subclassCode, protocolCode); + return new MacosUSBDevice(deviceIntf, entryID, vendorId, productId, manufacturer, product, serial); } private int setupNotification(MemorySession session, MemoryAddress notifyPort, MemorySegment notificationType, @@ -161,8 +154,8 @@ private int setupNotification(MemorySession session, MemoryAddress notifyPort, M private void onDevicesConnected(MemoryAddress ignoredRefCon, int iterator) { // process device iterator for connected devices - iterateDevices(iterator, false, (entryId, service) -> { - var device = createDevice(entryId, service); + iterateDevices(iterator, (entryId, service, deviceIntf) -> { + var device = createDevice(entryId, service, deviceIntf); if (device != null) addDevice(device); }); @@ -180,6 +173,18 @@ private void onDevicesConnected(MemoryAddress ignoredRefCon, int iterator) { private void onDevicesDisconnected(MemoryAddress ignoredRefCon, int iterator) { // process device iterator for disconnected devices - iterateDevices(iterator, true, (entryId, service) -> removeDevice(entryId)); + iterateDevices(iterator, (entryId, service, deviceIntf) -> { + var device = findDevice(entryId); + if (device == null) + return; + + ((MacosUSBDevice)device).closeFully(); + removeDevice(entryId); + }); + } + + @FunctionalInterface + public interface IOKitDeviceConsumer { + void accept(long entryId, int service, MemoryAddress deviceIntf); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index 16d9413b..64f41a12 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -19,7 +19,8 @@ import java.lang.foreign.MemorySession; import static java.lang.foreign.MemoryAddress.NULL; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_CHAR; +import static java.lang.foreign.ValueLayout.JAVA_INT; /** * Device property GUIDs and functions diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 7643b29c..d0789f64 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -10,9 +10,9 @@ import net.codecrete.usb.USBControlTransfer; import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBException; +import net.codecrete.usb.USBInterface; import net.codecrete.usb.common.DescriptorParser; import net.codecrete.usb.common.DescriptorParser.Configuration; -import net.codecrete.usb.common.DescriptorParser.Interface; import net.codecrete.usb.common.USBDescriptors; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.common.USBStructs; @@ -37,12 +37,12 @@ public class WindowsUSBDevice extends USBDeviceImpl { private MemoryAddress firstInterface; private final byte currentConfigurationValue; private Configuration configuration; - private List claimedInterfaces; + private List claimedInterfaces; WindowsUSBDevice(Object id, int vendorId, int productId, String manufacturer, String product, String serial, - int classCode, int subclassCode, int protocolCode, byte currentConfigurationValue) { - super(id, vendorId, productId, manufacturer, product, serial, classCode, subclassCode, protocolCode); + byte currentConfigurationValue) { + super(id, vendorId, productId, manufacturer, product, serial); this.currentConfigurationValue = currentConfigurationValue; } @@ -110,32 +110,31 @@ public void close() { } public void claimInterface(int interfaceNumber) { - var intfOptional = configuration.interfaces.stream().filter(intf -> intf.number == interfaceNumber).findFirst(); - if (intfOptional.isEmpty()) + var intf = configuration.findInterfaceByNumber(interfaceNumber); + if (intf == null) throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); if (claimedInterfaces == null) claimedInterfaces = new ArrayList<>(); - claimedInterfaces.add(intfOptional.get()); + claimedInterfaces.add(intf); } public void releaseInterface(int interfaceNumber) { - var intfOptional = claimedInterfaces.stream().filter(intf -> intf.number == interfaceNumber).findFirst(); + var intfOptional = claimedInterfaces.stream().filter(intf -> intf.getNumber() == interfaceNumber).findFirst(); if (intfOptional.isEmpty()) - throw new USBException(String.format("Interface has not been claimed or is invalid: number %d", + throw new USBException(String.format("Interface has not been claimed: number %d", interfaceNumber)); claimedInterfaces.remove(intfOptional.get()); } private byte checkEndpointNumber(int endpointNumber, USBDirection direction) { - byte endpointAddress = (byte) ((direction.ordinal() << 7) | endpointNumber); if (endpointNumber >= 1 && endpointNumber <= 127 && claimedInterfaces != null) { for (var intf : claimedInterfaces) { - for (var ep : intf.endpoints) { - if (ep.address == endpointAddress) - return endpointAddress; + for (var ep : intf.getAlternate().getEndpoints()) { + if (ep.getNumber() == endpointNumber && ep.getDirection() == direction) + return (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)); } } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 013dc01a..fcab2583 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -196,12 +196,9 @@ private USBDevice createDevice(String devicePath, MemoryAddress hubHandle, int u int vendorId = 0xffff & (short) USBDescriptors.Device_idVendor.get(deviceDesc); int productId = 0xffff & (short) USBDescriptors.Device_idProduct.get(deviceDesc); - int classCode = 255 & (byte) USBDescriptors.Device_bDeviceClass.get(deviceDesc); - int subClassCode = 255 & (byte) USBDescriptors.Device_bDeviceSubClass.get(deviceDesc); - int protocolCode = 255 & (byte) USBDescriptors.Device_bDeviceProtocol.get(deviceDesc); return new WindowsUSBDevice(devicePath, vendorId, productId, manufacturer, product, serialNumber, - classCode, subClassCode, protocolCode, currentConfigurationValue); + currentConfigurationValue); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java index d841ef54..db4fb5c1 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java @@ -9,8 +9,6 @@ package net.codecrete.usb; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.io.ByteArrayOutputStream; @@ -20,14 +18,12 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; -public class BulkTransferTest { +public class BulkTransferTest extends TestDeviceBase { private static final int LOOPBACK_EP_OUT = 1; private static final int LOOPBACK_EP_IN = 2; private static final int MAX_PACKET_SIZE = 64; - private static USBDevice device; - @Test void smallTransfer_succeeds() { byte[] sampleData = generateRandomBytes(12, 293872394); @@ -84,21 +80,4 @@ static byte[] generateRandomBytes(int numBytes, long seed) { random.nextBytes(bytes); return bytes; } - - @BeforeAll - static void openDevice() { - device = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); - if (device == null) - throw new IllegalStateException("USB loopback test device must be connected"); - device.open(); - device.claimInterface(0); - } - - @AfterAll - static void closeDevice() { - if (device != null) { - device.close(); - device = null; - } - } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java index 93531c0b..0c6e9df7 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java @@ -9,15 +9,14 @@ package net.codecrete.usb; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertArrayEquals; -public class ControlTransferTest { - - private static USBDevice device; +/** + * Tests control transfers + */ +public class ControlTransferTest extends TestDeviceBase { @Test void storeValue_succeeds() { @@ -39,21 +38,4 @@ void storeValueInDataStage_canBeRetrieved() { var retrievedValue = device.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) 0), 4); assertArrayEquals(sentValue, retrievedValue); } - - @BeforeAll - static void openDevice() { - device = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); - if (device == null) - throw new IllegalStateException("USB loopback test device must be connected"); - device.open(); - device.claimInterface(0); - } - - @AfterAll - static void closeDevice() { - if (device != null) { - device.close(); - device = null; - } - } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java new file mode 100644 index 00000000..119364e0 --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -0,0 +1,60 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Unit tests for USB device enumeration +// + +package net.codecrete.usb; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests the interface, alternate settings and endpoint descriptions. + */ +public class DescriptionTest extends TestDeviceBase { + + @Test + void interfaceDescriptors_present() { + assertNotNull(device.getInterfaces()); + assertEquals(1, device.getInterfaces().size()); + + var intf = device.getInterfaces().get(0); + assertEquals(0, intf.getNumber()); + assertNotNull(intf.getAlternate()); + assertFalse(intf.isClaimed()); + } + + @Test + void alternateInterfaceDescriptors_present() { + var intf = device.getInterfaces().get(0); + var altIntf = intf.getAlternate(); + assertNotNull(intf.getAlternates()); + assertEquals(1, intf.getAlternates().size()); + assertSame(intf.getAlternates().get(0), altIntf); + assertEquals(0, altIntf.getNumber()); + } + + @Test + void endpointDescriptors_present() { + var altIntf = device.getInterfaces().get(0).getAlternate(); + assertNotNull(altIntf.getEndpoints()); + assertEquals(2, altIntf.getEndpoints().size()); + + var endpoint = altIntf.getEndpoints().get(0); + assertEquals(1, endpoint.getNumber()); + assertEquals(USBDirection.OUT, endpoint.getDirection()); + assertEquals(USBEndpointType.BULK, endpoint.getType()); + assertEquals(64, endpoint.getPacketSize()); + + endpoint = altIntf.getEndpoints().get(1); + assertEquals(2, endpoint.getNumber()); + assertEquals(USBDirection.IN, endpoint.getDirection()); + assertEquals(USBEndpointType.BULK, endpoint.getType()); + assertEquals(64, endpoint.getPacketSize()); + } +} diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java new file mode 100644 index 00000000..efd53b54 --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -0,0 +1,37 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Unit tests for USB device enumeration +// + +package net.codecrete.usb; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; + +/** + * Base class for tests using the test device. + */ +public class TestDeviceBase { + protected static USBDevice device; + + @BeforeAll + static void openDevice() { + device = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); + if (device == null) + throw new IllegalStateException("USB loopback test device must be connected"); + device.open(); + device.claimInterface(0); + } + + @AfterAll + static void closeDevice() { + if (device != null) { + device.close(); + device = null; + } + } +} From 0a5c67886df988ea14eeedc6708b972fce75fcd6 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 3 Sep 2022 10:20:37 +0200 Subject: [PATCH 039/433] macOS: Fix reference count issue --- .../net/codecrete/usb/common/Foreign.java | 29 ------------------- .../net/codecrete/usb/macos/IoKitHelper.java | 29 +++++++++++-------- .../codecrete/usb/macos/MacosUSBDevice.java | 7 +++-- .../usb/macos/MacosUSBDeviceRegistry.java | 12 ++++---- 4 files changed, 28 insertions(+), 49 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/Foreign.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/Foreign.java b/java-does-usb/src/main/java/net/codecrete/usb/common/Foreign.java deleted file mode 100644 index 000dda92..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/Foreign.java +++ /dev/null @@ -1,29 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.common; - -import java.lang.foreign.MemoryAddress; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; - -import static java.lang.foreign.ValueLayout.ADDRESS; - -public class Foreign { - - /** - * Dereference the pointer and return the address the pointer is pointing at - * - * @param pointer pointer to dereference - * @param session memory session - * @return dereferenced value (of type address) - */ - public static MemoryAddress derefAddress(MemoryAddress pointer, MemorySession session) { - var seg = MemorySegment.ofAddress(pointer, ADDRESS.byteSize(), session); - return seg.get(ADDRESS, 0); - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index d4727a9b..b88f5017 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -7,8 +7,6 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.common.Foreign; - import java.lang.foreign.Addressable; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; @@ -17,7 +15,7 @@ import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.ADDRESS; import static java.lang.foreign.ValueLayout.JAVA_INT; -import static net.codecrete.usb.macos.CoreFoundation.CFUUID; +import static net.codecrete.usb.macos.CoreFoundation.CFUUIDBytes; import static net.codecrete.usb.macos.CoreFoundation.CFUUID_bytes$Offset; /** @@ -42,26 +40,24 @@ public class IoKitHelper { public static MemoryAddress getInterface(int service, Addressable pluginType, MemoryAddress interfaceId) { try (var session = MemorySession.openConfined()) { // MemorySegment for holding IOCFPlugInInterface** - var plugPointer = session.allocate(ADDRESS, NULL); + var plugHolder = session.allocate(ADDRESS, NULL); // MemorySegment for holding score var score = session.allocate(JAVA_INT, 0); - int ret = IoKit.IOCreatePlugInInterfaceForService(service, pluginType, IoKit.kIOCFPlugInInterfaceID, plugPointer, score); + int ret = IoKit.IOCreatePlugInInterfaceForService(service, pluginType, IoKit.kIOCFPlugInInterfaceID, plugHolder, score); if (ret != 0) return null; + var plug = (MemoryAddress) plugHolder.get(ADDRESS, 0); - var plug = Foreign.derefAddress(plugPointer.address(), session); // MemorySegment for holding xxxInterface** - var intf = session.allocate(ADDRESS, NULL); + var intfHolder = session.allocate(ADDRESS, NULL); // UUID bytes - var refiid = MemorySegment.ofAddress(interfaceId.addOffset(CFUUID_bytes$Offset), CFUUID.byteSize(), session); - ret = IoKit.QueryInterface(plug, refiid, intf); + var refiid = MemorySegment.ofAddress(interfaceId.addOffset(CFUUID_bytes$Offset), CFUUIDBytes.byteSize(), session); + ret = IoKit.QueryInterface(plug, refiid, intfHolder); IoKit.Release(plug); - if (ret != 0) return null; - return Foreign.derefAddress(intf.address(), session); + return intfHolder.get(ADDRESS, 0); } - } /** @@ -115,4 +111,13 @@ public static String getPropertyString(int service, String key) { CoreFoundation.CFRelease(value); return result; } + + public static int getRefCount(MemoryAddress object) { + try (var session = MemorySession.openConfined()) { + var objSegment = MemorySegment.ofAddress(object, 16, session); + var dataAddr = objSegment.get(ADDRESS, 8); + var dataSegment = MemorySegment.ofAddress(dataAddr, 12, session); + return dataSegment.get(JAVA_INT, 8); + } + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 8413d8e5..784860bb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -33,12 +33,12 @@ public class MacosUSBDevice extends USBDeviceImpl { MacosUSBDevice(MemoryAddress device, Object id, int vendorId, int productId, String manufacturer, String product, String serial) { super(id, vendorId, productId, manufacturer, product, serial); this.device = device; - IoKit.AddRef(device); try { loadDescription(); - } finally { + } catch (Throwable t) { closeFully(); + throw t; } } @@ -74,13 +74,14 @@ public void close() { IoKitUSB.USBInterfaceClose(interfaceInfo.asMemoryAddress()); IoKit.Release(interfaceInfo.asMemoryAddress()); } + claimedInterfaces = null; endpoints = null; + IoKitUSB.USBDeviceClose(device); } void closeFully() { close(); - IoKitUSB.USBDeviceClose(device); IoKit.Release(device); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index b8404ebe..f7d7008d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -78,9 +78,9 @@ protected void monitorDevices() { * Process the devices resulting from the iterator * * @param iterator the iterator - * @param function a function that will be called for each device with the entry ID and the service + * @param consumer a consumer that will be called for each device with the entry ID and the service */ - private void iterateDevices(int iterator, IOKitDeviceConsumer function) { + private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { int svc; while ((svc = IoKit.IOIteratorNext(iterator)) != 0) { @@ -99,8 +99,8 @@ private void iterateDevices(int iterator, IOKitDeviceConsumer function) { throw new MacosUSBException("IORegistryEntryGetRegistryEntryID failed", ret); var entryId = entryIdHolder.get(JAVA_LONG, 0); - // call function to process device - function.accept(entryId, service, device); + // call consumer to process device + consumer.accept(entryId, service, device); } } } @@ -116,8 +116,10 @@ private USBDevice createDevice(Long entryID, int service, MemoryAddress deviceIn String product = IoKitHelper.getPropertyString(service, "kUSBProductString"); String serial = IoKitHelper.getPropertyString(service, "kUSBSerialNumberString"); - if (vendorId == null || productId == null) + if (vendorId == null || productId == null) { + IoKit.Release(deviceIntf); return null; + } return new MacosUSBDevice(deviceIntf, entryID, vendorId, productId, manufacturer, product, serial); } From 868880231f4e3b429123cd3c87099c96807e1fb3 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 3 Sep 2022 12:57:02 +0200 Subject: [PATCH 040/433] Windows: interface, alternate settings and endpoint description --- .../usb/common/DescriptorParser.java | 33 +++++--- .../codecrete/usb/common/USBDescriptors.java | 4 +- .../codecrete/usb/common/USBDeviceImpl.java | 23 +---- .../codecrete/usb/macos/MacosUSBDevice.java | 2 +- .../net/codecrete/usb/windows/USBHelper.java | 4 +- .../usb/windows/WindowsUSBDevice.java | 43 +++++----- .../usb/windows/WindowsUSBDeviceRegistry.java | 84 +++++++++++-------- 7 files changed, 106 insertions(+), 87 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java index 5a329c0f..ce64ff93 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java @@ -7,10 +7,7 @@ package net.codecrete.usb.common; -import net.codecrete.usb.USBDirection; -import net.codecrete.usb.USBEndpointType; -import net.codecrete.usb.USBException; -import net.codecrete.usb.USBInterface; +import net.codecrete.usb.*; import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; @@ -28,9 +25,9 @@ public class DescriptorParser { * @param descriptor configuration descriptor * @return parsed configuration data */ - public static Configuration parseConfigurationDescriptor(byte[] descriptor) { + public static Configuration parseConfigurationDescriptor(byte[] descriptor, int vendorID, int productID) { var desc = MemorySegment.ofArray(descriptor); - return parseConfigurationDescriptor(desc); + return parseConfigurationDescriptor(desc, vendorID, productID); } /** @@ -39,8 +36,8 @@ public static Configuration parseConfigurationDescriptor(byte[] descriptor) { * @param desc configuration descriptor * @return parsed configuration data */ - public static Configuration parseConfigurationDescriptor(MemorySegment desc) { - var config = parseConfiguration(desc, 0); + public static Configuration parseConfigurationDescriptor(MemorySegment desc, int vendorID, int productID) { + var config = parseConfiguration(desc); USBAlternateInterfaceImpl lastAlternate = null; USBEndpointImpl lastEndpoint; @@ -66,8 +63,14 @@ public static Configuration parseConfigurationDescriptor(MemorySegment desc) { if (lastAlternate != null) lastAlternate.addEndpoint(lastEndpoint); + } else //noinspection StatementWithEmptyBody + if (descType == USBDescriptors.HID_DESCRIPTOR) { + // known descriptor but not relevant + } else { - System.err.println("Warning: unsupported USB descriptor type " + descType); + System.err.printf( + "Info: [JavaDoesUSB] unsupported USB descriptor type %02x of device %04x/%04x - ignoring%n", + descType, vendorID, productID); } offset += descLength; @@ -76,12 +79,16 @@ public static Configuration parseConfigurationDescriptor(MemorySegment desc) { return config; } - private static Configuration parseConfiguration(MemorySegment descriptor, int offset) { - var desc = descriptor.asSlice(offset, USBDescriptors.Configuration.byteSize()); + private static Configuration parseConfiguration(MemorySegment descriptor) { + var desc = descriptor.asSlice(0, USBDescriptors.Configuration.byteSize()); var config = new Configuration(); if (USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE != (byte) USBDescriptors.Configuration_bDescriptorType.get(desc)) throw new USBException("Invalid USB configuration descriptor"); + short totalLength = (short) USBDescriptors.Configuration_wTotalLength.get(desc); + if (descriptor.byteSize() != totalLength) + throw new USBException("Invalid USB configuration descriptor length"); + config.configValue = (byte) USBDescriptors.Configuration_bConfigurationValue.get(desc); config.attributes = (byte) USBDescriptors.Configuration_bmAttributes.get(desc); config.maxPower = (byte) USBDescriptors.Configuration_bMaxPower.get(desc); @@ -97,7 +104,9 @@ private static USBInterfaceImpl parseInterface(MemorySegment descriptor, int off var subclassCode = 255 & (byte) USBDescriptors.Interface_bInterfaceSubClass.get(desc); var protocol = 255 & (byte) USBDescriptors.Interface_bInterfaceProtocol.get(desc); var alternate = new USBAlternateInterfaceImpl(altSetting, classCode, subclassCode, protocol, new ArrayList<>()); - return new USBInterfaceImpl(number, List.of(alternate)); + var alternates = new ArrayList(); + alternates.add(alternate); + return new USBInterfaceImpl(number, alternates); } private static USBEndpointImpl parseEndpoint(MemorySegment descriptor, int offset) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java index 53da4c90..20760d07 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java @@ -33,9 +33,10 @@ public class USBDescriptors { public static final byte INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE = 0x0b; public static final byte BOS_DESCRIPTOR_TYPE = 0x0f; public static final byte DEVICE_CAPABILITY_DESCRIPTOR_TYPE = 0x10; - public static final byte SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_TYPE = 0x30; + public static final byte HID_DESCRIPTOR = 0x21; public static final byte USB_20_HUB_DESCRIPTOR_TYPE = 0x29; public static final byte USB_30_HUB_DESCRIPTOR_TYPE = 0x2a; + public static final byte SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_TYPE = 0x30; public static final byte SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR_TYPE = 0x31; // typedef struct { @@ -79,6 +80,7 @@ public class USBDescriptors { public static final VarHandle Device_iManufacturer = Device$Struct.varHandle(groupElement("iManufacturer")); public static final VarHandle Device_iProduct = Device$Struct.varHandle(groupElement("iProduct")); public static final VarHandle Device_iSerialNumber = Device$Struct.varHandle(groupElement("iSerialNumber")); + public static final VarHandle Device_bNumConfigurations = Device$Struct.varHandle(groupElement("bNumConfigurations")); // struct USBConfigurationDescriptor //{ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 63e321fc..fb1eb52e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -7,7 +7,10 @@ package net.codecrete.usb.common; -import net.codecrete.usb.*; +import net.codecrete.usb.USBControlTransfer; +import net.codecrete.usb.USBDevice; +import net.codecrete.usb.USBException; +import net.codecrete.usb.USBInterface; import java.util.Collections; import java.util.List; @@ -135,24 +138,6 @@ public void setInterfaces(List interfaces) { @Override public abstract byte[] transferIn(int endpointNumber, int maxLength); - protected byte[] getDescriptor(int descriptorType, int index, int language) { - // get descriptor header - var result = controlTransferIn(new USBControlTransfer(USBRequestType.STANDARD, USBRecipient.DEVICE, - (byte) 0x06, (short) (descriptorType << 8 | index), (short) language), 9); - - // get effective length from header - int length; - if (descriptorType == USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE) - length = (result[2] & 255) + 256 * (result[3] & 255); - else length = result[0] & 255; - - // get full descriptor - result = controlTransferIn(new USBControlTransfer(USBRequestType.STANDARD, USBRecipient.DEVICE, (byte) 0x06, - (short) (descriptorType << 8 | index), (short) language), length); - - return result; - } - @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 784860bb..0f46e670 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -102,7 +102,7 @@ private void loadDescription() { var configDesc = MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), totalLength, session); - var configuration = DescriptorParser.parseConfigurationDescriptor(configDesc); + var configuration = DescriptorParser.parseConfigurationDescriptor(configDesc, getVendorId(), getProductId()); configurationValue = 255 & configuration.configValue; setInterfaces(configuration.interfaces); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java index 68d25d54..6cd7bc2a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java @@ -29,7 +29,6 @@ public class USBHelper { public static final byte USB_REQUEST_GET_DESCRIPTOR = 0x06; - public static final short USB_STRING_DESCRIPTOR_TYPE = 0x03; // typedef struct _USB_NODE_CONNECTION_INFORMATION_EX { // ULONG ConnectionIndex; /* INPUT */ @@ -60,6 +59,9 @@ public class USBHelper { = USB_NODE_CONNECTION_INFORMATION_EX$Struct.varHandle(groupElement("ConnectionIndex")); public static final long USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset = USB_NODE_CONNECTION_INFORMATION_EX$Struct.byteOffset(groupElement("DeviceDescriptor")); + public static MemorySegment USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(MemorySegment seg) { + return seg.asSlice(USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset, USBDescriptors.Device$Struct.byteSize()); + } public static final VarHandle USB_NODE_CONNECTION_INFORMATION_EX_CurrentConfigurationValue = USB_NODE_CONNECTION_INFORMATION_EX$Struct.varHandle(groupElement("CurrentConfigurationValue")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index d0789f64..7c8f426a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -13,7 +13,6 @@ import net.codecrete.usb.USBInterface; import net.codecrete.usb.common.DescriptorParser; import net.codecrete.usb.common.DescriptorParser.Configuration; -import net.codecrete.usb.common.USBDescriptors; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.common.USBStructs; import net.codecrete.usb.windows.gen.kernel32.Kernel32; @@ -35,15 +34,14 @@ public class WindowsUSBDevice extends USBDeviceImpl { private MemoryAddress device; private MemoryAddress firstInterface; - private final byte currentConfigurationValue; + private byte configurationValue; private Configuration configuration; private List claimedInterfaces; - WindowsUSBDevice(Object id, int vendorId, int productId, String manufacturer, String product, String serial, - byte currentConfigurationValue) { + MemorySegment configDesc) { super(id, vendorId, productId, manufacturer, product, serial); - this.currentConfigurationValue = currentConfigurationValue; + readDescription(configDesc); } @Override @@ -54,8 +52,8 @@ public boolean isOpen() { @Override public void open() { - if (device != null) - return; + if (isOpen()) + throw new USBException("the device is already open"); try (var session = MemorySession.openConfined()) { @@ -76,19 +74,8 @@ public void open() { firstInterface = interfaceHandleHolder.get(ADDRESS, 0); - try { - // read configuration - byte[] desc = getDescriptor(USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE, 0, 0); - configuration = DescriptorParser.parseConfigurationDescriptor(desc); - - } catch (Throwable e) { - WinUSB.WinUsb_Free(firstInterface); - throw e; - } - } catch (Throwable e) { Kernel32.CloseHandle(device); - configuration = null; firstInterface = null; device = null; throw e; @@ -96,20 +83,26 @@ public void open() { } } + private void readDescription(MemorySegment configDesc) { + configuration = DescriptorParser.parseConfigurationDescriptor(configDesc, getVendorId(), getProductId()); + configurationValue = configuration.configValue; + setInterfaces(configuration.interfaces); + } @Override public void close() { - if (device == null) + if (!isOpen()) return; WinUSB.WinUsb_Free(firstInterface); firstInterface = null; Kernel32.CloseHandle(device); device = null; - configuration = null; } public void claimInterface(int interfaceNumber) { + checkIsOpen(); + var intf = configuration.findInterfaceByNumber(interfaceNumber); if (intf == null) throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); @@ -121,6 +114,8 @@ public void claimInterface(int interfaceNumber) { } public void releaseInterface(int interfaceNumber) { + checkIsOpen(); + var intfOptional = claimedInterfaces.stream().filter(intf -> intf.getNumber() == interfaceNumber).findFirst(); if (intfOptional.isEmpty()) throw new USBException(String.format("Interface has not been claimed: number %d", @@ -158,6 +153,8 @@ private MemorySegment createSetupPacket(MemorySession session, USBDirection dire @Override public byte[] controlTransferIn(USBControlTransfer setup, int length) { + checkIsOpen(); + try (var session = MemorySession.openConfined()) { var buffer = session.allocate(length); var setupPacket = createSetupPacket(session, USBDirection.IN, setup, buffer); @@ -174,6 +171,8 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { @Override public void controlTransferOut(USBControlTransfer setup, byte[] data) { + checkIsOpen(); + try (var session = MemorySession.openConfined()) { // copy data to native memory @@ -194,6 +193,8 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { @Override public void transferOut(int endpointNumber, byte[] data) { + checkIsOpen(); + byte endpointAddress = checkEndpointNumber(endpointNumber, USBDirection.OUT); try (var session = MemorySession.openConfined()) { @@ -209,6 +210,8 @@ public void transferOut(int endpointNumber, byte[] data) { @Override public byte[] transferIn(int endpointNumber, int maxLength) { + checkIsOpen(); + byte endpointAddress = checkEndpointNumber(endpointNumber, USBDirection.IN); try (var session = MemorySession.openConfined()) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index fcab2583..acb160b9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -86,6 +86,7 @@ protected void monitorDevices() { // process messages var msg = session.allocate(MSG.$LAYOUT()); + //noinspection StatementWithEmptyBody while (User32.GetMessageW(msg, hwnd, 0, 0) > 0) ; // do nothing @@ -176,15 +177,14 @@ private USBDevice createDevice(String devicePath, MemoryAddress hubHandle, int u var connInfo = session.allocate(USBHelper.USB_NODE_CONNECTION_INFORMATION_EX$Struct); USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex.set(connInfo, usbPortNum); var sizeHolder = session.allocate(JAVA_INT); - if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), connInfo - , (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL) == 0) + if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), connInfo, + (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL) == 0) throw new USBException("Internal error (cannot get device descriptor)", Kernel32.GetLastError()); - byte currentConfigurationValue = - (byte) USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_CurrentConfigurationValue.get(connInfo); - - var deviceDesc = connInfo.asSlice(USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset, - USBDescriptors.Device$Struct.byteSize()); + var deviceDesc = USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(connInfo); + var currentConfigurationValue = + 255 & (byte) USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_CurrentConfigurationValue.get(connInfo); + var numConfigurations = 255 & (byte) USBDescriptors.Device_bNumConfigurations.get(deviceDesc); // extract info from device descriptor int manufacturerIndex = 255 & (byte) USBDescriptors.Device_iManufacturer.get(deviceDesc); @@ -197,38 +197,57 @@ private USBDevice createDevice(String devicePath, MemoryAddress hubHandle, int u int vendorId = 0xffff & (short) USBDescriptors.Device_idVendor.get(deviceDesc); int productId = 0xffff & (short) USBDescriptors.Device_idProduct.get(deviceDesc); - return new WindowsUSBDevice(devicePath, vendorId, productId, manufacturer, product, serialNumber, - currentConfigurationValue); + // search configuration descriptor with + MemorySegment configDesc = null; + for (int i = 0; i < numConfigurations; i++) { + var desc = getDescriptor(hubHandle, usbPortNum, + USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE, i, (short) 0, session); + if ((255 & (byte) USBDescriptors.Configuration_bConfigurationValue.get(desc)) == currentConfigurationValue) { + configDesc = desc; + break; + } + } + if (configDesc == null) + throw new USBException(String.format("Configuration descriptor %d not found", currentConfigurationValue)); + + return new WindowsUSBDevice(devicePath, vendorId, productId, manufacturer, product, serialNumber, configDesc); } } + private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, + int descriptorType, int index, short languageID, MemorySession session) { + + final int dataLen = 512; + var descriptorRequest = session.allocate(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset + dataLen); + USBHelper.USB_DESCRIPTOR_REQUEST_ConnectionIndex.set(descriptorRequest, usbPortNumber); + var setupPacket = descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_SetupPacket$Offset, + USBStructs.SetupPacket$Struct.byteSize()); + USBStructs.SetupPacket_bmRequest.set(setupPacket, (byte) 0x80); // device-to-host / type standard / recipient device + USBStructs.SetupPacket_bRequest.set(setupPacket, USBHelper.USB_REQUEST_GET_DESCRIPTOR); + USBStructs.SetupPacket_wValue.set(setupPacket, + (short) ((descriptorType << 8) | index)); + USBStructs.SetupPacket_wIndex.set(setupPacket, languageID); + USBStructs.SetupPacket_wLength.set(setupPacket, (short) dataLen); + + var sizeHolder = session.allocate(JAVA_INT); + if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION(), + descriptorRequest, (int) descriptorRequest.byteSize(), descriptorRequest, + (int) descriptorRequest.byteSize(), sizeHolder, NULL) == 0) + throw new USBException(String.format("Cannot retrieve descriptor %d", index), + Kernel32.GetLastError()); + + var size = sizeHolder.get(JAVA_INT, 0); + return descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, size - USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset); + } + private String getStringDescriptor(Addressable hubHandle, int usbPortNumber, int index) { if (index == 0) return null; try (var session = MemorySession.openConfined()) { + var stringDesc = getDescriptor(hubHandle, usbPortNumber, USBDescriptors.STRING_DESCRIPTOR_TYPE, + index, (short) 0x0409, session); - final int dataLen = 255; - var descriptorRequest = session.allocate(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset + dataLen); - USBHelper.USB_DESCRIPTOR_REQUEST_ConnectionIndex.set(descriptorRequest, usbPortNumber); - var setupPacket = descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_SetupPacket$Offset, - USBStructs.SetupPacket$Struct.byteSize()); - USBStructs.SetupPacket_bmRequest.set(setupPacket, (byte) 0x80); - USBStructs.SetupPacket_bRequest.set(setupPacket, USBHelper.USB_REQUEST_GET_DESCRIPTOR); - USBStructs.SetupPacket_wValue.set(setupPacket, - (short) ((USBHelper.USB_STRING_DESCRIPTOR_TYPE << 8) | index)); - USBStructs.SetupPacket_wIndex.set(setupPacket, (short) 0x0409); - USBStructs.SetupPacket_wLength.set(setupPacket, (short) dataLen); - - var sizeHolder = session.allocate(JAVA_INT); - if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION(), - descriptorRequest, (int) descriptorRequest.byteSize(), descriptorRequest, - (int) descriptorRequest.byteSize(), sizeHolder, NULL) == 0) - throw new USBException(String.format("Cannot retrieve string descriptor %d", index), - Kernel32.GetLastError()); - - // The string descriptor is not null terminated - var stringDesc = descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, dataLen); int stringLen = 255 & (byte) USBHelper.USB_STRING_DESCRIPTOR_bLength.get(stringDesc); var chars = stringDesc.asSlice(USBHelper.USB_STRING_DESCRIPTOR_bString$Offset, stringLen - 2).toArray(JAVA_CHAR); @@ -246,9 +265,8 @@ private long handleWindowMessage(MemoryAddress hWnd, int uMsg, long wParam, long if (DEV_BROADCAST_HDR.dbch_devicetype$get(data) == User32.DBT_DEVTYP_DEVICEINTERFACE()) { // get device path - var nameSlice = - MemorySegment.ofAddress(DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address(), - 500, session); + var nameSlice = MemorySegment.ofAddress( + DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address(), 500, session); var devicePath = Win.createStringFromSegment(nameSlice); if (wParam == User32.DBT_DEVICEARRIVAL()) onDeviceConnected(devicePath); From c67634879a0622606a5b5a13b66369b8fa088d24 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 3 Sep 2022 15:40:15 +0200 Subject: [PATCH 041/433] Windows: improve robustness for strange devices --- .../usb/common/DescriptorParser.java | 10 +- .../codecrete/usb/common/USBDescriptors.java | 6 +- .../usb/common/USBDeviceRegistry.java | 19 +- .../usb/windows/WindowsUSBDeviceRegistry.java | 182 +++++++++++------- .../codecrete/usb/sample/MonitorDevices.java | 9 +- 5 files changed, 145 insertions(+), 81 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java index ce64ff93..955e9d40 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java @@ -63,13 +63,19 @@ public static Configuration parseConfigurationDescriptor(MemorySegment desc, int if (lastAlternate != null) lastAlternate.addEndpoint(lastEndpoint); + } else if (descType == USBDescriptors.INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE) { + // TODO: interface associations + } else //noinspection StatementWithEmptyBody - if (descType == USBDescriptors.HID_DESCRIPTOR) { + if (descType == USBDescriptors.HID_DESCRIPTOR_TYPE + || descType == USBDescriptors.CS_INTERFACE_DESCRIPTOR_TYPE + || descType == USBDescriptors.CS_ENDPOINT_DESCRIPTOR_TYPE) { // known descriptor but not relevant } else { + // TODO: Remove warning once the relevant descriptors are processed System.err.printf( - "Info: [JavaDoesUSB] unsupported USB descriptor type %02x of device %04x/%04x - ignoring%n", + "Info: [JavaDoesUSB] unsupported USB descriptor type 0x%02x of device 0x%04x/0x%04x - ignoring%n", descType, vendorID, productID); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java index 20760d07..145095d9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java @@ -33,12 +33,16 @@ public class USBDescriptors { public static final byte INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE = 0x0b; public static final byte BOS_DESCRIPTOR_TYPE = 0x0f; public static final byte DEVICE_CAPABILITY_DESCRIPTOR_TYPE = 0x10; - public static final byte HID_DESCRIPTOR = 0x21; + public static final byte HID_DESCRIPTOR_TYPE = 0x21; + public static final byte CS_INTERFACE_DESCRIPTOR_TYPE = 0x24; + public static final byte CS_ENDPOINT_DESCRIPTOR_TYPE = 0x25; public static final byte USB_20_HUB_DESCRIPTOR_TYPE = 0x29; public static final byte USB_30_HUB_DESCRIPTOR_TYPE = 0x2a; public static final byte SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_TYPE = 0x30; public static final byte SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR_TYPE = 0x31; + public static final short DEFAULT_LANGUAGE = 0x0409; + // typedef struct { // UCHAR bLength; // UCHAR bDescriptorType; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index 476f6c18..08a592ea 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -8,6 +8,7 @@ package net.codecrete.usb.common; import net.codecrete.usb.USBDevice; +import net.codecrete.usb.USBException; import java.util.ArrayList; import java.util.Collections; @@ -32,6 +33,7 @@ public abstract class USBDeviceRegistry { private volatile List devices; + private volatile Throwable failureCause; protected Consumer onDeviceConnectedHandler; protected Consumer onDeviceDisconnectedHandler; @@ -105,12 +107,15 @@ protected void startDeviceMonitor(Runnable monitorTask) { // wait for initial device enumeration lock.lock(); try { - while (devices == null) { + while (devices == null && failureCause == null) { enumerationComplete.awaitUninterruptibly(); } } finally { lock.unlock(); } + + if (failureCause != null) + throw new USBException("Initial device enumeration has failed", failureCause); } /** @@ -125,10 +130,20 @@ private void signalEnumerationComplete() { } } + /** + * Signal failure of initial device enumeration. + * + * @param e cause of failure + */ + protected void enumerationFailed(Throwable e) { + failureCause = e; + signalEnumerationComplete(); + } + /** * Sets the device list of the initial device enumeration. *

- * This function singals to the spawning thread that the enumeration is complete. + * This function signals to the spawning thread that the enumeration is complete. *

* * @param deviceList the device list diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index acb160b9..fc358722 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -44,62 +44,67 @@ public class WindowsUSBDeviceRegistry extends USBDeviceRegistry { protected void monitorDevices() { try (var session = MemorySession.openConfined()) { - final var className = Win.createSegmentFromString("USB_MONITOR", session); - final var windowName = Win.createSegmentFromString("USB device monitor", session); - final var instance = Kernel32.GetModuleHandleW(NULL); - - // create upcall for handling window messages - var handleWindowMessageMH = MethodHandles.lookup().findVirtual(WindowsUSBDeviceRegistry.class, - "handleWindowMessage", MethodType.methodType(long.class, MemoryAddress.class, int.class, - long.class, long.class)).bindTo(this); - var handleWindowMessageStub = Linker.nativeLinker().upcallStub(handleWindowMessageMH, - FunctionDescriptor.of(JAVA_LONG, ADDRESS, JAVA_INT, JAVA_LONG, JAVA_LONG), session); - - // register window class - var wx = session.allocate(WNDCLASSEXW.$LAYOUT()); - WNDCLASSEXW.cbSize$set(wx, (int) wx.byteSize()); - WNDCLASSEXW.lpfnWndProc$set(wx, handleWindowMessageStub.address()); - WNDCLASSEXW.hInstance$set(wx, instance); - WNDCLASSEXW.lpszClassName$set(wx, className.address()); - User32.RegisterClassExW(wx); - - // create message-only window - Addressable hwnd = User32.CreateWindowExW(0, className, windowName, 0, 0, 0, 0, 0, User32.HWND_MESSAGE(), - NULL, instance, NULL); - if (hwnd == NULL) - throw new USBException("internal error (CreateWindowExW)", Kernel32.GetLastError()); - - // configure notifications - var notificationFilter = session.allocate(DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); - DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$set(notificationFilter, (int) notificationFilter.byteSize()); - DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$set(notificationFilter, - User32.DBT_DEVTYP_DEVICEINTERFACE()); - DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid$slice(notificationFilter).copyFrom(USBHelper.GUID_DEVINTERFACE_USB_DEVICE); - - var notifyHandle = User32.RegisterDeviceNotificationW(hwnd, notificationFilter, - User32.DEVICE_NOTIFY_WINDOW_HANDLE()); - if (notifyHandle == NULL) - throw new USBException("internal error (RegisterDeviceNotificationW)", Kernel32.GetLastError()); - - // initial device enumeration - enumeratePresentDevices(); + Addressable hwnd; + + try { + final var className = Win.createSegmentFromString("USB_MONITOR", session); + final var windowName = Win.createSegmentFromString("USB device monitor", session); + final var instance = Kernel32.GetModuleHandleW(NULL); + + // create upcall for handling window messages + var handleWindowMessageMH = MethodHandles.lookup().findVirtual(WindowsUSBDeviceRegistry.class, + "handleWindowMessage", MethodType.methodType(long.class, MemoryAddress.class, int.class, + long.class, long.class)).bindTo(this); + var handleWindowMessageStub = Linker.nativeLinker().upcallStub(handleWindowMessageMH, + FunctionDescriptor.of(JAVA_LONG, ADDRESS, JAVA_INT, JAVA_LONG, JAVA_LONG), session); + + // register window class + var wx = session.allocate(WNDCLASSEXW.$LAYOUT()); + WNDCLASSEXW.cbSize$set(wx, (int) wx.byteSize()); + WNDCLASSEXW.lpfnWndProc$set(wx, handleWindowMessageStub.address()); + WNDCLASSEXW.hInstance$set(wx, instance); + WNDCLASSEXW.lpszClassName$set(wx, className.address()); + User32.RegisterClassExW(wx); + + // create message-only window + hwnd = User32.CreateWindowExW(0, className, windowName, 0, 0, 0, 0, 0, User32.HWND_MESSAGE(), + NULL, instance, NULL); + if (hwnd == NULL) + throw new USBException("internal error (CreateWindowExW)", Kernel32.GetLastError()); + + // configure notifications + var notificationFilter = session.allocate(DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); + DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$set(notificationFilter, (int) notificationFilter.byteSize()); + DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$set(notificationFilter, + User32.DBT_DEVTYP_DEVICEINTERFACE()); + DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid$slice(notificationFilter).copyFrom(USBHelper.GUID_DEVINTERFACE_USB_DEVICE); + + var notifyHandle = User32.RegisterDeviceNotificationW(hwnd, notificationFilter, + User32.DEVICE_NOTIFY_WINDOW_HANDLE()); + if (notifyHandle == NULL) + throw new USBException("internal error (RegisterDeviceNotificationW)", Kernel32.GetLastError()); + + // initial device enumeration + enumeratePresentDevices(); + + } catch (Throwable e) { + enumerationFailed(e); + return; + } // process messages var msg = session.allocate(MSG.$LAYOUT()); //noinspection StatementWithEmptyBody while (User32.GetMessageW(msg, hwnd, 0, 0) > 0) ; // do nothing - - } catch (NoSuchMethodException | IllegalAccessException e) { - throw new RuntimeException(e); } } private void enumeratePresentDevices() { List deviceList = new ArrayList<>(); - try (var outerSession = MemorySession.openConfined()) { + // get device information set of all USB devices present final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); @@ -118,6 +123,7 @@ private void enumeratePresentDevices() { // iterate all devices for (int i = 0; true; i++) { + if (SetupAPI.SetupDiEnumDeviceInfo(devInfoSetHandle, i, devInfo) == 0) { int err = Kernel32.GetLastError(); // TODO: Remove check for ERROR_SUCCESS if proper GetLastError() handling is available @@ -130,7 +136,13 @@ private void enumeratePresentDevices() { DeviceProperty.DEVPKEY_Device_InstanceId); var devicePath = DeviceProperty.getDevicePath(instanceID, USBHelper.GUID_DEVINTERFACE_USB_DEVICE); - deviceList.add(createDeviceFromDeviceInfo(devInfoSetHandle, devInfo, devicePath, hubHandles)); + try { + deviceList.add(createDeviceFromDeviceInfo(devInfoSetHandle, devInfo, devicePath, hubHandles)); + + } catch (Throwable e) { + System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring%n", devicePath); + e.printStackTrace(System.err); + } } setInitialDeviceList(deviceList); @@ -164,6 +176,7 @@ private USBDevice createDeviceFromDeviceInfo(MemoryAddress devInfoSetHandle, Mem /** * Retrieve device descriptor and create {@code USBDevice} instance + * * @param devicePath the device path * @param hubHandle the hub handle (parent) * @param usbPortNum the USB port number @@ -182,9 +195,6 @@ private USBDevice createDevice(String devicePath, MemoryAddress hubHandle, int u throw new USBException("Internal error (cannot get device descriptor)", Kernel32.GetLastError()); var deviceDesc = USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(connInfo); - var currentConfigurationValue = - 255 & (byte) USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_CurrentConfigurationValue.get(connInfo); - var numConfigurations = 255 & (byte) USBDescriptors.Device_bNumConfigurations.get(deviceDesc); // extract info from device descriptor int manufacturerIndex = 255 & (byte) USBDescriptors.Device_iManufacturer.get(deviceDesc); @@ -197,28 +207,29 @@ private USBDevice createDevice(String devicePath, MemoryAddress hubHandle, int u int vendorId = 0xffff & (short) USBDescriptors.Device_idVendor.get(deviceDesc); int productId = 0xffff & (short) USBDescriptors.Device_idProduct.get(deviceDesc); - // search configuration descriptor with - MemorySegment configDesc = null; - for (int i = 0; i < numConfigurations; i++) { - var desc = getDescriptor(hubHandle, usbPortNum, - USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE, i, (short) 0, session); - if ((255 & (byte) USBDescriptors.Configuration_bConfigurationValue.get(desc)) == currentConfigurationValue) { - configDesc = desc; - break; - } - } - if (configDesc == null) - throw new USBException(String.format("Configuration descriptor %d not found", currentConfigurationValue)); + var configDesc = getDescriptor(hubHandle, usbPortNum, + USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE, 0, (short) 0, session); return new WindowsUSBDevice(devicePath, vendorId, productId, manufacturer, product, serialNumber, configDesc); } } private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, - int descriptorType, int index, short languageID, MemorySession session) { + int descriptorType, int index, short languageID, + MemorySession session) { + return getDescriptor(hubHandle, usbPortNumber, descriptorType, index, languageID, 0, session); + + } - final int dataLen = 512; - var descriptorRequest = session.allocate(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset + dataLen); + + private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, + int descriptorType, int index, short languageID, + int requestSize, MemorySession session) { + + int size = requestSize != 0 ? requestSize + (int) USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset : 256; + + // create descriptor requests + var descriptorRequest = session.allocate(size); USBHelper.USB_DESCRIPTOR_REQUEST_ConnectionIndex.set(descriptorRequest, usbPortNumber); var setupPacket = descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_SetupPacket$Offset, USBStructs.SetupPacket$Struct.byteSize()); @@ -227,17 +238,35 @@ private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, USBStructs.SetupPacket_wValue.set(setupPacket, (short) ((descriptorType << 8) | index)); USBStructs.SetupPacket_wIndex.set(setupPacket, languageID); - USBStructs.SetupPacket_wLength.set(setupPacket, (short) dataLen); + USBStructs.SetupPacket_wLength.set(setupPacket, (short) (size - USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset)); - var sizeHolder = session.allocate(JAVA_INT); + // execute request + var effectiveSizeHolder = session.allocate(JAVA_INT); if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION(), - descriptorRequest, (int) descriptorRequest.byteSize(), descriptorRequest, - (int) descriptorRequest.byteSize(), sizeHolder, NULL) == 0) + descriptorRequest, size, descriptorRequest, size, effectiveSizeHolder, NULL) == 0) throw new USBException(String.format("Cannot retrieve descriptor %d", index), Kernel32.GetLastError()); - var size = sizeHolder.get(JAVA_INT, 0); - return descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, size - USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset); + // determine size of descriptor + int expectedSize; + if (descriptorType != USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE) { + expectedSize = 255 & descriptorRequest.get(JAVA_BYTE, USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset); + } else { + var configDesc = descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, USBDescriptors.Configuration.byteSize()); + expectedSize = (short) USBDescriptors.Configuration_wTotalLength.get(configDesc); + } + + // check against effective size + var effectiveSize = effectiveSizeHolder.get(JAVA_INT, 0) - USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset; + if (effectiveSize != expectedSize) { + if (requestSize != 0) + throw new USBException("Unexpected descriptor size"); + + // repeat with correct size + return getDescriptor(hubHandle, usbPortNumber, descriptorType, index, languageID, expectedSize, session); + } + + return descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, effectiveSize); } private String getStringDescriptor(Addressable hubHandle, int usbPortNumber, int index) { @@ -246,7 +275,7 @@ private String getStringDescriptor(Addressable hubHandle, int usbPortNumber, int try (var session = MemorySession.openConfined()) { var stringDesc = getDescriptor(hubHandle, usbPortNumber, USBDescriptors.STRING_DESCRIPTOR_TYPE, - index, (short) 0x0409, session); + index, USBDescriptors.DEFAULT_LANGUAGE, session); int stringLen = 255 & (byte) USBHelper.USB_STRING_DESCRIPTOR_bLength.get(stringDesc); var chars = @@ -296,6 +325,7 @@ private void onDeviceConnected(String devicePath) { var devIntfData = session.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); var devicePathSegment = Win.createSegmentFromString(devicePath, session); + // TODO: Check if result needs to be freed if (SetupAPI.SetupDiOpenDeviceInterfaceW(devInfoSetHandle, devicePathSegment, 0, devIntfData) == 0) throw new USBException("internal error (SetupDiOpenDeviceInterfaceW)", Kernel32.GetLastError()); @@ -311,11 +341,17 @@ private void onDeviceConnected(String devicePath) { final var hubHandles = new HashMap(); session.addCloseAction(() -> hubHandles.forEach((path, handle) -> Kernel32.CloseHandle(handle))); - // create device instance - var device = createDeviceFromDeviceInfo(devInfoSetHandle, devInfo, devicePath, hubHandles); + try { + // create device instance + var device = createDeviceFromDeviceInfo(devInfoSetHandle, devInfo, devicePath, hubHandles); - // add it to device list - addDevice(device); + // add it to device list + addDevice(device); + + } catch (Throwable e) { + System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring%n", devicePath); + e.printStackTrace(System.err); + } } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java b/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java index c141e44e..3423ae4b 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java @@ -18,9 +18,12 @@ public class MonitorDevices { public static void main(String[] args) throws InterruptedException { - System.out.println("Monitoring USB devices..."); - USB.setOnDeviceConnected((dev) -> System.out.println("Connected: " + dev.toString())); - USB.setOnDeviceDisconnected((dev) -> System.out.println("Disconnected: " + dev.toString())); + USB.setOnDeviceConnected((device) -> System.out.println("Connected: " + device.toString())); + USB.setOnDeviceDisconnected((device) -> System.out.println("Disconnected: " + device.toString())); + + for (var device : USB.getAllDevices()) + System.out.println("Present: " + device.toString()); + System.out.println("Monitoring..."); //noinspection InfiniteLoopStatement while (true) { From 2b5346ad0ecb1e33a60de20b24aa86976992a58a Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 3 Sep 2022 17:10:55 +0200 Subject: [PATCH 042/433] macOS: improve robustness for unexpected cases --- .../codecrete/usb/macos/MacosUSBDevice.java | 9 +- .../usb/macos/MacosUSBDeviceRegistry.java | 126 ++++++++++++------ 2 files changed, 86 insertions(+), 49 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 0f46e670..fff7d86e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -34,12 +34,9 @@ public class MacosUSBDevice extends USBDeviceImpl { super(id, vendorId, productId, manufacturer, product, serial); this.device = device; - try { - loadDescription(); - } catch (Throwable t) { - closeFully(); - throw t; - } + loadDescription(); + + IoKit.AddRef(device); } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index f7d7008d..b3ca1559 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -15,6 +15,7 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.ArrayList; +import java.util.function.Consumer; import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.*; @@ -36,41 +37,41 @@ protected void monitorDevices() { // as the method runs forever, there is no need to clean up one-time allocations try (var session = MemorySession.openConfined()) { - // setup run loop, run loop source and notification port - var notifyPort = IoKit.IONotificationPortCreate(IoKit.kIOMasterPortDefault); - var runLoopSource = IoKit.IONotificationPortGetRunLoopSource(notifyPort); - var runLoop = CoreFoundation.CFRunLoopGetCurrent(); - CoreFoundation.CFRunLoopAddSource(runLoop, runLoopSource, IoKit.kCFRunLoopDefaultMode); - - // setup notification for connected devices - var onDeviceConnectedMH = MethodHandles.lookup().findVirtual(MacosUSBDeviceRegistry.class, - "onDevicesConnected", MethodType.methodType(void.class, MemoryAddress.class, int.class)); - int deviceConnectedIter = setupNotification(session, notifyPort, IoKit.kIOFirstMatchNotification, - onDeviceConnectedMH); - - // iterate current devices in order to arm the notifications (and build initial device list) - var deviceList = new ArrayList(); - iterateDevices(deviceConnectedIter, (entryId, service, deviceIntf) -> { - var device = createDevice(entryId, service, deviceIntf); - if (device != null) - deviceList.add(device); - }); - setInitialDeviceList(deviceList); + try { + + // setup run loop, run loop source and notification port + var notifyPort = IoKit.IONotificationPortCreate(IoKit.kIOMasterPortDefault); + var runLoopSource = IoKit.IONotificationPortGetRunLoopSource(notifyPort); + var runLoop = CoreFoundation.CFRunLoopGetCurrent(); + CoreFoundation.CFRunLoopAddSource(runLoop, runLoopSource, IoKit.kCFRunLoopDefaultMode); + + // setup notification for connected devices + var onDeviceConnectedMH = MethodHandles.lookup().findVirtual(MacosUSBDeviceRegistry.class, + "onDevicesConnected", MethodType.methodType(void.class, MemoryAddress.class, int.class)); + int deviceConnectedIter = setupNotification(session, notifyPort, IoKit.kIOFirstMatchNotification, + onDeviceConnectedMH); - // setup notification for disconnected devices - var onDeviceDisconnectedMH = MethodHandles.lookup().findVirtual(MacosUSBDeviceRegistry.class, - "onDevicesDisconnected", MethodType.methodType(void.class, MemoryAddress.class, int.class)); - int deviceDisconnectedIter = setupNotification(session, notifyPort, IoKit.kIOTerminatedNotification, - onDeviceDisconnectedMH); + // iterate current devices in order to arm the notifications (and build initial device list) + var deviceList = new ArrayList(); + iterateDevices(deviceConnectedIter, (device) -> deviceList.add(device)); + setInitialDeviceList(deviceList); - // iterate current devices in order to arm the notifications - onDevicesDisconnected(NULL, deviceDisconnectedIter); + // setup notification for disconnected devices + var onDeviceDisconnectedMH = MethodHandles.lookup().findVirtual(MacosUSBDeviceRegistry.class, + "onDevicesDisconnected", MethodType.methodType(void.class, MemoryAddress.class, int.class)); + int deviceDisconnectedIter = setupNotification(session, notifyPort, IoKit.kIOTerminatedNotification, + onDeviceDisconnectedMH); + + // iterate current devices in order to arm the notifications + onDevicesDisconnected(NULL, deviceDisconnectedIter); + + } catch (Throwable e) { + enumerationFailed(e); + return; + } // loop forever CoreFoundation.CFRunLoopRun(); - - } catch (NoSuchMethodException | IllegalAccessException e) { - throw new RuntimeException(e); } } @@ -92,6 +93,9 @@ private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { var device = IoKitHelper.getInterface(service, IoKit.kIOUSBDeviceUserClientTypeID, IoKit.kIOUSBDeviceInterfaceID100); + if (device != null) + session.addCloseAction(() -> IoKit.Release(device)); + // get entry ID (as unique ID) var entryIdHolder = session.allocate(JAVA_LONG); int ret = IoKit.IORegistryEntryGetRegistryEntryID(service, entryIdHolder); @@ -105,22 +109,51 @@ private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { } } - private USBDevice createDevice(Long entryID, int service, MemoryAddress deviceIntf) { + /** + * Calls the consumer for all devices produced by the iterator. + *

+ * This method tries to create a {@link USBDevice} instance. + * If it fails, an information is printed, but the consumer is not called. + *

+ * + * @param iterator the iterator + * @param consumer the consumer + */ + private void iterateDevices(int iterator, Consumer consumer) { + iterateDevices(iterator, (entryId, service, deviceIntf) -> { + + var deviceInfo = new VidPid(); + try { + var device = createDevice(entryId, service, deviceIntf, deviceInfo); + if (device != null) + consumer.accept(device); + + } catch (Throwable e) { + System.err.printf( + "Info: [JavaDoesUSB] failed to retrieve information about device 0x%04x/0x%04x - ignoring%n", + deviceInfo.vid, deviceInfo.pid); + e.printStackTrace(System.err); + } + }); + } + + private USBDevice createDevice(Long entryID, int service, MemoryAddress deviceIntf, VidPid info) { if (deviceIntf == null) return null; Integer vendorId = IoKitHelper.getPropertyInt(service, "idVendor"); Integer productId = IoKitHelper.getPropertyInt(service, "idProduct"); + if (vendorId == null || productId == null) + return null; + + info.vid = vendorId; + info.pid = productId; + String manufacturer = IoKitHelper.getPropertyString(service, "kUSBVendorString"); String product = IoKitHelper.getPropertyString(service, "kUSBProductString"); String serial = IoKitHelper.getPropertyString(service, "kUSBSerialNumberString"); - if (vendorId == null || productId == null) { - IoKit.Release(deviceIntf); - return null; - } - return new MacosUSBDevice(deviceIntf, entryID, vendorId, productId, manufacturer, product, serial); } @@ -156,11 +189,7 @@ private int setupNotification(MemorySession session, MemoryAddress notifyPort, M private void onDevicesConnected(MemoryAddress ignoredRefCon, int iterator) { // process device iterator for connected devices - iterateDevices(iterator, (entryId, service, deviceIntf) -> { - var device = createDevice(entryId, service, deviceIntf); - if (device != null) - addDevice(device); - }); + iterateDevices(iterator, this::addDevice); } /** @@ -180,13 +209,24 @@ private void onDevicesDisconnected(MemoryAddress ignoredRefCon, int iterator) { if (device == null) return; - ((MacosUSBDevice)device).closeFully(); + try { + ((MacosUSBDevice) device).closeFully(); + } catch (Throwable e) { + System.err.println("Info: [JavaDoesUSB] failed to close USB device - ignoring"); + e.printStackTrace(System.err); + } + removeDevice(entryId); }); } @FunctionalInterface - public interface IOKitDeviceConsumer { + interface IOKitDeviceConsumer { void accept(long entryId, int service, MemoryAddress deviceIntf); } + + static class VidPid { + int vid; + int pid; + } } From 22112b57c4722fa4c493b42e285d431a36558d2f Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 3 Sep 2022 18:06:48 +0200 Subject: [PATCH 043/433] Linux: descriptions for interface, alternate settings and endpoints --- .../usb/common/DescriptorParser.java | 13 +---------- .../codecrete/usb/linux/LinuxUSBDevice.java | 23 +++++++++++++++++++ .../usb/linux/LinuxUSBDeviceRegistry.java | 12 +++++++--- .../usb/macos/MacosUSBDeviceRegistry.java | 4 ++-- .../usb/windows/WindowsUSBDeviceRegistry.java | 4 ++-- 5 files changed, 37 insertions(+), 19 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java index 955e9d40..adc2675e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java @@ -19,17 +19,6 @@ */ public class DescriptorParser { - /** - * Parse a USB configuration descriptor (incl. interface and endpoint descriptors) - * - * @param descriptor configuration descriptor - * @return parsed configuration data - */ - public static Configuration parseConfigurationDescriptor(byte[] descriptor, int vendorID, int productID) { - var desc = MemorySegment.ofArray(descriptor); - return parseConfigurationDescriptor(desc, vendorID, productID); - } - /** * Parse a USB configuration descriptor (incl. interface and endpoint descriptors) * @@ -75,7 +64,7 @@ public static Configuration parseConfigurationDescriptor(MemorySegment desc, int } else { // TODO: Remove warning once the relevant descriptors are processed System.err.printf( - "Info: [JavaDoesUSB] unsupported USB descriptor type 0x%02x of device 0x%04x/0x%04x - ignoring%n", + "Info: [JavaDoesUSB] unsupported USB descriptor type 0x%02x of device 0x%04x/0x%04x - ignoring descriptor%n", descType, vendorID, productID); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 8bb11a1b..fb224ea0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -10,6 +10,7 @@ import net.codecrete.usb.USBControlTransfer; import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBException; +import net.codecrete.usb.common.DescriptorParser; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.linux.gen.fcntl.fcntl; import net.codecrete.usb.linux.gen.ioctl.ioctl; @@ -17,8 +18,11 @@ import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_bulktransfer; import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_ctrltransfer; +import java.io.IOException; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; +import java.nio.file.Files; +import java.nio.file.Path; import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_INT; @@ -29,6 +33,25 @@ public class LinuxUSBDevice extends USBDeviceImpl { LinuxUSBDevice(Object id, int vendorId, int productId, String manufacturer, String product, String serial) { super(id, vendorId, productId, manufacturer, product, serial); + loadDescription((String) id); + } + + private void loadDescription(String path) { + byte[] descriptors; + try { + descriptors = Files.readAllBytes(Path.of(path)); + } catch (IOException e) { + throw new USBException("Cannot read configuration descriptor", e); + } + + try (var session = MemorySession.openConfined()) { + var descriptorsSegment = MemorySegment.ofArray(descriptors); + // skip device descriptor + var configDesc = session.allocateArray(JAVA_BYTE, descriptors.length - 18); + configDesc.copyFrom(descriptorsSegment.asSlice(18)); + var configuration = DescriptorParser.parseConfigurationDescriptor(configDesc, getVendorId(), getProductId()); + setInterfaces(configuration.interfaces); + } } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 57e22925..a8eb7f8f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -14,10 +14,13 @@ import net.codecrete.usb.linux.gen.select.select; import net.codecrete.usb.linux.gen.udev.udev; +import java.io.IOException; import java.lang.foreign.Addressable; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @@ -154,14 +157,17 @@ private static USBDevice getDeviceDetails(MemoryAddress udevDevice) { // retrieve device attributes String idVendor = getDeviceAttribute(udevDevice, "idVendor"); - if (idVendor == null) return null; + if (idVendor == null) + return null; String idProduct = getDeviceAttribute(udevDevice, "idProduct"); - if (idProduct == null) return null; + if (idProduct == null) + return null; // get device path var devPath = getDeviceName(udevDevice); - if (devPath == null) return null; + if (devPath == null) + return null; int vendorId = Integer.parseInt(idVendor, 16); int productId = Integer.parseInt(idProduct, 16); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index b3ca1559..5cc575b8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -130,7 +130,7 @@ private void iterateDevices(int iterator, Consumer consumer) { } catch (Throwable e) { System.err.printf( - "Info: [JavaDoesUSB] failed to retrieve information about device 0x%04x/0x%04x - ignoring%n", + "Info: [JavaDoesUSB] failed to retrieve information about device 0x%04x/0x%04x - ignoring device%n", deviceInfo.vid, deviceInfo.pid); e.printStackTrace(System.err); } @@ -212,7 +212,7 @@ private void onDevicesDisconnected(MemoryAddress ignoredRefCon, int iterator) { try { ((MacosUSBDevice) device).closeFully(); } catch (Throwable e) { - System.err.println("Info: [JavaDoesUSB] failed to close USB device - ignoring"); + System.err.println("Info: [JavaDoesUSB] failed to close USB device - ignoring exception"); e.printStackTrace(System.err); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index fc358722..03587bee 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -140,7 +140,7 @@ private void enumeratePresentDevices() { deviceList.add(createDeviceFromDeviceInfo(devInfoSetHandle, devInfo, devicePath, hubHandles)); } catch (Throwable e) { - System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring%n", devicePath); + System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring device%n", devicePath); e.printStackTrace(System.err); } } @@ -349,7 +349,7 @@ private void onDeviceConnected(String devicePath) { addDevice(device); } catch (Throwable e) { - System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring%n", devicePath); + System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring device%n", devicePath); e.printStackTrace(System.err); } } From a07295466f85a0bd56babf0bcbb1a1f4086c29ab Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 3 Sep 2022 20:02:56 +0200 Subject: [PATCH 044/433] Linux: robustness for error cases --- .../usb/linux/LinuxUSBDeviceRegistry.java | 98 +++++++++++-------- 1 file changed, 59 insertions(+), 39 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index a8eb7f8f..e2c5e5f5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -14,13 +14,10 @@ import net.codecrete.usb.linux.gen.select.select; import net.codecrete.usb.linux.gen.udev.udev; -import java.io.IOException; import java.lang.foreign.Addressable; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @@ -39,24 +36,34 @@ public class LinuxUSBDeviceRegistry extends USBDeviceRegistry { @Override protected void monitorDevices() { - // setup udev monitor - var udevInstance = udev.udev_new(); - if (udevInstance == NULL) throw new USBException("internal error (udev_new)"); + int fd; + MemoryAddress monitor; - var monitor = udev.udev_monitor_new_from_netlink(udevInstance, MONITOR_NAME); - if (monitor == NULL) throw new USBException("internal error (udev_monitor_new_from_netlink)"); + try { + // setup udev monitor + var udevInstance = udev.udev_new(); + if (udevInstance == NULL) throw new USBException("internal error (udev_new)"); - if (udev.udev_monitor_filter_add_match_subsystem_devtype(monitor, SUBSYSTEM_USB, DEVTYPE_USB_DEVICE) < 0) - throw new USBException("internal error (udev_monitor_filter_add_match_subsystem_devtype)"); + monitor = udev.udev_monitor_new_from_netlink(udevInstance, MONITOR_NAME); + if (monitor == NULL) throw new USBException("internal error (udev_monitor_new_from_netlink)"); - if (udev.udev_monitor_enable_receiving(monitor) < 0) - throw new USBException("internal error (udev_monitor_enable_receiving)"); + if (udev.udev_monitor_filter_add_match_subsystem_devtype(monitor, SUBSYSTEM_USB, DEVTYPE_USB_DEVICE) < 0) + throw new USBException("internal error (udev_monitor_filter_add_match_subsystem_devtype)"); - int fd = udev.udev_monitor_get_fd(monitor); - if (fd < 0) throw new USBException("internal error (udev_monitor_get_fd)"); + if (udev.udev_monitor_enable_receiving(monitor) < 0) + throw new USBException("internal error (udev_monitor_enable_receiving)"); - // create initial list of devices - enumeratePresentDevices(udevInstance); + fd = udev.udev_monitor_get_fd(monitor); + if (fd < 0) throw new USBException("internal error (udev_monitor_get_fd)"); + + // create initial list of devices + var deviceList = enumeratePresentDevices(udevInstance); + setInitialDeviceList(deviceList); + + } catch (Throwable e) { + enumerationFailed(e); + return; + } // monitor device changes //noinspection InfiniteLoopStatement @@ -84,7 +91,7 @@ protected void monitorDevices() { } } - private void enumeratePresentDevices(Addressable udevInstance) { + private List enumeratePresentDevices(Addressable udevInstance) { List result = new ArrayList<>(); try (var outerSession = MemorySession.openConfined()) { @@ -107,11 +114,13 @@ private void enumeratePresentDevices(Addressable udevInstance) { try (var session = MemorySession.openConfined()) { var path = udev.udev_list_entry_get_name(entry); - if (path == NULL) continue; + if (path == NULL) + continue; // get device handle var dev = udev.udev_device_new_from_syspath(udevInstance, path); - if (dev == NULL) continue; + if (dev == NULL) + continue; // ensure the device is released session.addCloseAction(() -> udev.udev_device_unref(dev)); @@ -124,15 +133,14 @@ private void enumeratePresentDevices(Addressable udevInstance) { } } - setInitialDeviceList(result); + return result; } private void onDeviceConnected(MemoryAddress udevDevice) { var device = getDeviceDetails(udevDevice); - if (device == null) return; - - addDevice(device); + if (device != null) + addDevice(device); } private void onDeviceDisconnected(MemoryAddress udevDevice) { @@ -155,26 +163,38 @@ private void onDeviceDisconnected(MemoryAddress udevDevice) { */ private static USBDevice getDeviceDetails(MemoryAddress udevDevice) { - // retrieve device attributes - String idVendor = getDeviceAttribute(udevDevice, "idVendor"); - if (idVendor == null) - return null; + int vendorId = 0; + int productId = 0; - String idProduct = getDeviceAttribute(udevDevice, "idProduct"); - if (idProduct == null) - return null; + try { + // retrieve device attributes + String idVendor = getDeviceAttribute(udevDevice, "idVendor"); + if (idVendor == null) + return null; - // get device path - var devPath = getDeviceName(udevDevice); - if (devPath == null) - return null; + String idProduct = getDeviceAttribute(udevDevice, "idProduct"); + if (idProduct == null) + return null; + + // get device path + var devPath = getDeviceName(udevDevice); + if (devPath == null) + return null; - int vendorId = Integer.parseInt(idVendor, 16); - int productId = Integer.parseInt(idProduct, 16); + vendorId = Integer.parseInt(idVendor, 16); + productId = Integer.parseInt(idProduct, 16); - // create device instance - return new LinuxUSBDevice(devPath, vendorId, productId, getDeviceAttribute(udevDevice, "manufacturer"), - getDeviceAttribute(udevDevice, "product"), getDeviceAttribute(udevDevice, "serial")); + // create device instance + return new LinuxUSBDevice(devPath, vendorId, productId, getDeviceAttribute(udevDevice, "manufacturer"), + getDeviceAttribute(udevDevice, "product"), getDeviceAttribute(udevDevice, "serial")); + + } catch (Throwable e) { + System.err.printf( + "Info: [JavaDoesUSB] failed to retrieve information about device 0x%04x/0x%04x - ignoring device%n", + vendorId, productId); + e.printStackTrace(System.err); + return null; + } } private static String getDeviceAttribute(Addressable udevDevice, String attribute) { From 73a6666efaf29d54914dc2628ced9c9ca6fc13b9 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 3 Sep 2022 20:57:42 +0200 Subject: [PATCH 045/433] Rename public properties --- java-does-usb/src/main/java/module-info.java | 1 - .../codecrete/usb/USBAlternateInterface.java | 10 +-- .../java/net/codecrete/usb/USBDevice.java | 18 ++-- .../net/codecrete/usb/USBDeviceFilter.java | 74 ++++++++-------- .../java/net/codecrete/usb/USBEndpoint.java | 12 +-- .../java/net/codecrete/usb/USBException.java | 8 +- .../java/net/codecrete/usb/USBInterface.java | 6 +- ...EndpointType.java => USBTransferType.java} | 4 +- .../usb/common/DescriptorParser.java | 16 ++-- .../usb/common/USBAlternateInterfaceImpl.java | 42 ++++----- .../codecrete/usb/common/USBDeviceImpl.java | 86 +++++++++---------- .../codecrete/usb/common/USBEndpointImpl.java | 36 ++++---- .../usb/common/USBInterfaceImpl.java | 24 +++--- .../codecrete/usb/linux/LinuxUSBDevice.java | 4 +- .../codecrete/usb/macos/MacosUSBDevice.java | 2 +- .../usb/windows/WindowsUSBDevice.java | 10 +-- .../net/codecrete/usb/DescriptionTest.java | 52 +++++------ .../codecrete/usb/DeviceEnumerationTest.java | 18 ++-- 18 files changed, 211 insertions(+), 212 deletions(-) rename java-does-usb/src/main/java/net/codecrete/usb/{USBEndpointType.java => USBTransferType.java} (84%) diff --git a/java-does-usb/src/main/java/module-info.java b/java-does-usb/src/main/java/module-info.java index b0c0f2e1..dcb8c5c6 100644 --- a/java-does-usb/src/main/java/module-info.java +++ b/java-does-usb/src/main/java/module-info.java @@ -7,5 +7,4 @@ module net.codecrete.usb { exports net.codecrete.usb; - exports net.codecrete.usb.common; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java index 573a0a38..d32faa99 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java @@ -24,7 +24,7 @@ public interface USBAlternateInterface { * * @return the alternate setting number */ - int getNumber(); + int number(); /** * Gets the interface class. @@ -34,7 +34,7 @@ public interface USBAlternateInterface { * * @return the interface class */ - int getClassCode(); + int classCode(); /** * Gets the interface subclass. @@ -44,7 +44,7 @@ public interface USBAlternateInterface { * * @return the interface subclass */ - int getSubclassCode(); + int subclassCode(); /** * Gets the interface protocol. @@ -54,12 +54,12 @@ public interface USBAlternateInterface { * * @return the interface protocol */ - int getProtocolCode(); + int protocolCode(); /** * Gets the endpoints of this alternate interface settings. * * @return a list of endpoints. */ - List getEndpoints(); + List endpoints(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index 9031fcf5..0ce00a1e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -28,28 +28,28 @@ public interface USBDevice { * * @return product ID */ - int getProductId(); + int productId(); /** * USB vendor ID. * * @return vendor ID */ - int getVendorId(); + int vendorId(); /** * Product name. * * @return product name or {@code null} if not provided by the device */ - String getProduct(); + String product(); /** * Manufacturer name * * @return manufacturer name or {@code null} if not provided by the device */ - String getManufacturer(); + String manufacturer(); /** * Serial number @@ -60,28 +60,28 @@ public interface USBDevice { * * @return serial number or {@code null} if not provided by the device */ - String getSerial(); + String serialNumber(); /** * USB device class code ({@code bDeviceClass} from device descriptor). * * @return class code */ - int getClassCode(); + int classCode(); /** * USB device subclass code ({@code bDeviceSubClass} from device descriptor). * * @return subclass code */ - int getSubclassCode(); + int subclassCode(); /** * USB device protocol ({@code bDeviceProtocol} from device descriptor). * * @return protocol code */ - int getProtocolCode(); + int protocolCode(); /** * Opens the device for communication. @@ -105,7 +105,7 @@ public interface USBDevice { * * @return a list of USB interfaces */ - List getInterfaces(); + List interfaces(); /** * Claims the specified interface for exclusive use. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java index 810fa964..cce636c9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java @@ -21,12 +21,12 @@ *

*/ public class USBDeviceFilter { - private Integer vendorId; - private Integer productId; - private Integer classCode; - private Integer subclassCode; - private Integer protocolCode; - private String serialNumber; + private Integer vendorId_; + private Integer productId_; + private Integer classCode_; + private Integer subclassCode_; + private Integer protocolCode_; + private String serialNumber_; /** * Creates a new instance. @@ -41,8 +41,8 @@ public USBDeviceFilter() { * @param productId product ID */ public USBDeviceFilter(int vendorId, int productId) { - this.vendorId = vendorId; - this.productId = productId; + vendorId_ = vendorId; + productId_ = productId; } /** @@ -53,9 +53,9 @@ public USBDeviceFilter(int vendorId, int productId) { * @param serialNumber serial number */ public USBDeviceFilter(int vendorId, int productId, String serialNumber) { - this.vendorId = vendorId; - this.productId = productId; - this.serialNumber = serialNumber; + vendorId_ = vendorId; + productId_ = productId; + serialNumber_ = serialNumber; } /** @@ -63,8 +63,8 @@ public USBDeviceFilter(int vendorId, int productId, String serialNumber) { * * @return vendor ID, or {@code null} if the vendor ID is not relevant for matching */ - public Integer getVendorId() { - return vendorId; + public Integer vendorId() { + return vendorId_; } /** @@ -73,7 +73,7 @@ public Integer getVendorId() { * @param vendorId vendor ID, or {@code null} if the vendor ID is not relevant for matching */ public void setVendorId(Integer vendorId) { - this.vendorId = vendorId; + vendorId_ = vendorId; } /** @@ -81,8 +81,8 @@ public void setVendorId(Integer vendorId) { * * @return product ID, or {@code null} if the product ID is not relevant for matching */ - public Integer getProductId() { - return productId; + public Integer productId() { + return productId_; } /** @@ -91,7 +91,7 @@ public Integer getProductId() { * @param productId product ID, or {@code null} if the product ID is not relevant for matching */ public void setProductId(Integer productId) { - this.productId = productId; + productId_ = productId; } /** @@ -99,8 +99,8 @@ public void setProductId(Integer productId) { * * @return class code, or {@code null} if the class code is not relevant for matching */ - public Integer getClassCode() { - return classCode; + public Integer classCode() { + return classCode_; } /** @@ -109,7 +109,7 @@ public Integer getClassCode() { * @param classCode class code, or {@code null} if the class code is not relevant for matching */ public void setClassCode(Integer classCode) { - this.classCode = classCode; + classCode_ = classCode; } /** @@ -117,8 +117,8 @@ public void setClassCode(Integer classCode) { * * @return subclass code, or {@code null} if the subclass code is not relevant for matching */ - public Integer getSubclassCode() { - return subclassCode; + public Integer subclassCode() { + return subclassCode_; } /** @@ -127,7 +127,7 @@ public Integer getSubclassCode() { * @param subclassCode subclass code, or {@code null} if the subclass code is not relevant for matching */ public void setSubclassCode(Integer subclassCode) { - this.subclassCode = subclassCode; + subclassCode_ = subclassCode; } /** @@ -135,17 +135,17 @@ public void setSubclassCode(Integer subclassCode) { * * @return protocol code, or {@code null} if the protocol code is not relevant for matching */ - public Integer getProtocolCode() { - return protocolCode; + public Integer protocolCode() { + return protocolCode_; } /** * Sets the USB device protocol code. * - * @param protocolCode protocol code, or {@code null} if the protocol code is not relevant for matching + * @param protocolCode_ protocol code, or {@code null} if the protocol code is not relevant for matching */ - public void setProtocolCode(Integer protocolCode) { - this.protocolCode = protocolCode; + public void setProtocolCode_(Integer protocolCode_) { + protocolCode_ = protocolCode_; } /** @@ -153,8 +153,8 @@ public void setProtocolCode(Integer protocolCode) { * * @return serial number, or {@code null} if the serial number is not relevant for matching */ - public String getSerialNumber() { - return serialNumber; + public String serialNumber() { + return serialNumber_; } /** @@ -163,7 +163,7 @@ public String getSerialNumber() { * @param serialNumber serial number, or {@code null} if the serial number is not relevant for matching */ public void setSerialNumber(String serialNumber) { - this.serialNumber = serialNumber; + serialNumber_ = serialNumber; } /** @@ -173,17 +173,17 @@ public void setSerialNumber(String serialNumber) { * @return {@code true} if it matches, {@code false} otherwise */ public boolean matches(USBDevice device) { - if (vendorId != null && device.getVendorId() != vendorId) + if (vendorId_ != null && device.vendorId() != vendorId_) return false; - if (productId != null && device.getProductId() != productId) + if (productId_ != null && device.productId() != productId_) return false; - if (serialNumber != null && !serialNumber.equals(device.getSerial())) + if (serialNumber_ != null && !serialNumber_.equals(device.serialNumber())) return false; - if (classCode != null && device.getClassCode() != classCode) + if (classCode_ != null && device.classCode() != classCode_) return false; - if (subclassCode != null && device.getSubclassCode() != subclassCode) + if (subclassCode_ != null && device.subclassCode() != subclassCode_) return false; - return protocolCode == null || device.getProtocolCode() == protocolCode; + return protocolCode_ == null || device.protocolCode() == protocolCode_; } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBEndpoint.java b/java-does-usb/src/main/java/net/codecrete/usb/USBEndpoint.java index 1991a4c7..8ccd271d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBEndpoint.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBEndpoint.java @@ -29,7 +29,7 @@ public interface USBEndpoint { * * @return the endpoint number */ - int getNumber(); + int number(); /** * Gets the direction of the endpoint. @@ -40,14 +40,14 @@ public interface USBEndpoint { * * @return the direction */ - USBDirection getDirection(); + USBDirection direction(); /** - * Gets the USB endpoint type. + * Gets the USB endpoint transfer type. * - * @return the type + * @return the transfer type */ - USBEndpointType getType(); + USBTransferType transferType(); /** * Gets the packet size. @@ -58,5 +58,5 @@ public interface USBEndpoint { * * @return the packet size, in bytes. */ - int getPacketSize(); + int packetSize(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBException.java b/java-does-usb/src/main/java/net/codecrete/usb/USBException.java index 6af987c5..90f3c3e0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBException.java @@ -12,7 +12,7 @@ */ public class USBException extends RuntimeException { - private int errorCode = -1; + private int errorCode_ = -1; /** * Creates a new instance with a message. @@ -31,7 +31,7 @@ public USBException(String message) { */ public USBException(String message, int errorCode) { super(message + " (error code: " + errorCode + ")"); - this.errorCode = errorCode; + errorCode_ = errorCode; } /** @@ -49,7 +49,7 @@ public USBException(String message, Throwable cause) { * * @return the error code */ - public int GetErrorCode() { - return errorCode; + public int errorCode() { + return errorCode_; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java index fa1ab044..a213883b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java @@ -24,7 +24,7 @@ public interface USBInterface { * * @return the interface number */ - int getNumber(); + int number(); /** * Indicates if this interface is currently claimed for exclusive access. @@ -41,12 +41,12 @@ public interface USBInterface { * * @return the alternate interface setting. */ - USBAlternateInterface getAlternate(); + USBAlternateInterface alternate(); /** * Gets all alternate settings of this interface. * * @return a list of the alternate settings */ - List getAlternates(); + List alternates(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBEndpointType.java b/java-does-usb/src/main/java/net/codecrete/usb/USBTransferType.java similarity index 84% rename from java-does-usb/src/main/java/net/codecrete/usb/USBEndpointType.java rename to java-does-usb/src/main/java/net/codecrete/usb/USBTransferType.java index d9c38003..fc213a75 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBEndpointType.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBTransferType.java @@ -8,9 +8,9 @@ package net.codecrete.usb; /** - * USB endpoint type. + * USB endpoint transfer type. */ -public enum USBEndpointType { +public enum USBTransferType { /** * Bulk transfer */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java index adc2675e..4f925577 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java @@ -39,13 +39,13 @@ public static Configuration parseConfigurationDescriptor(MemorySegment desc, int if (descType == USBDescriptors.INTERFACE_DESCRIPTOR_TYPE) { var intf = parseInterface(desc, offset); - var parent = config.findInterfaceByNumber(intf.getNumber()); + var parent = config.findInterfaceByNumber(intf.number()); if (parent != null) { - parent.addAlternate(intf.getAlternate()); + parent.addAlternate(intf.alternate()); } else { config.addInterface(intf); } - lastAlternate = (USBAlternateInterfaceImpl) intf.getAlternate(); + lastAlternate = (USBAlternateInterfaceImpl) intf.alternate(); } else if (descType == USBDescriptors.ENDPOINT_DESCRIPTOR_TYPE) { lastEndpoint = parseEndpoint(desc, offset); @@ -121,11 +121,11 @@ private static int getEndpointNumber(byte address) { return address & 0x7f; } - private static USBEndpointType getEndpointType(byte attributes) { + private static USBTransferType getEndpointType(byte attributes) { return switch (attributes & 0x3) { - case 1 -> USBEndpointType.ISOCHRONOUS; - case 2 -> USBEndpointType.BULK; - case 3 -> USBEndpointType.INTERRUPT; + case 1 -> USBTransferType.ISOCHRONOUS; + case 2 -> USBTransferType.BULK; + case 3 -> USBTransferType.INTERRUPT; default -> null; }; } @@ -164,7 +164,7 @@ void addInterface(USBInterface intf) { public USBInterfaceImpl findInterfaceByNumber(int number) { return (USBInterfaceImpl) interfaces.stream() - .filter((intf) -> intf.getNumber() == number).findFirst().orElse(null); + .filter((intf) -> intf.number() == number).findFirst().orElse(null); } } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java index 9b46d54b..4bc5c9d2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java @@ -15,47 +15,47 @@ public class USBAlternateInterfaceImpl implements USBAlternateInterface { - private final int number; - private final int classCode; - private final int subclassCode; - private final int protocolCode; - private final List endpoints; + private final int number_; + private final int classCode_; + private final int subclassCode_; + private final int protocolCode_; + private final List endpoints_; public USBAlternateInterfaceImpl(int number, int classCode, int subclassCode, int protocolCode, List endpoints) { - this.number = number; - this.classCode = classCode; - this.subclassCode = subclassCode; - this.protocolCode = protocolCode; - this.endpoints = endpoints; + number_ = number; + classCode_ = classCode; + subclassCode_ = subclassCode; + protocolCode_ = protocolCode; + endpoints_ = endpoints; } @Override - public int getNumber() { - return number; + public int number() { + return number_; } @Override - public int getClassCode() { - return classCode; + public int classCode() { + return classCode_; } @Override - public int getSubclassCode() { - return subclassCode; + public int subclassCode() { + return subclassCode_; } @Override - public int getProtocolCode() { - return protocolCode; + public int protocolCode() { + return protocolCode_; } @Override - public List getEndpoints() { - return Collections.unmodifiableList(endpoints); + public List endpoints() { + return Collections.unmodifiableList(endpoints_); } void addEndpoint(USBEndpoint endpoint) { - endpoints.add(endpoint); + endpoints_.add(endpoint); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index fb1eb52e..3c1b633f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -17,17 +17,17 @@ public abstract class USBDeviceImpl implements USBDevice { - protected final Object id; - protected final int vendorId; - protected final int productId; - protected final String manufacturer; - protected final String product; - protected final String serial; - protected int classCode; - protected int subclassCode; - protected int protocolCode; - - protected List interfaces; + protected final Object id_; + protected final int vendorId_; + protected final int productId_; + protected final String manufacturer_; + protected final String product_; + protected final String serialNumber_; + protected int classCode_; + protected int subclassCode_; + protected int protocolCode_; + + protected List interfaces_; /** * Creates a new instance. @@ -37,19 +37,19 @@ public abstract class USBDeviceImpl implements USBDevice { * @param productId USB product ID * @param manufacturer manufacturer name * @param product product name - * @param serial serial number + * @param serialNumber serial number */ protected USBDeviceImpl(Object id, int vendorId, int productId, String manufacturer, String product, - String serial) { + String serialNumber) { assert id != null; - this.id = id; - this.vendorId = vendorId; - this.productId = productId; - this.manufacturer = manufacturer; - this.product = product; - this.serial = serial; + id_ = id; + vendorId_ = vendorId; + productId_ = productId; + manufacturer_ = manufacturer; + product_ = product; + serialNumber_ = serialNumber; } @Override @@ -67,56 +67,56 @@ protected void checkIsOpen() { } @Override - public int getProductId() { - return productId; + public int productId() { + return productId_; } @Override - public int getVendorId() { - return vendorId; + public int vendorId() { + return vendorId_; } @Override - public String getProduct() { - return product; + public String product() { + return product_; } @Override - public String getManufacturer() { - return manufacturer; + public String manufacturer() { + return manufacturer_; } @Override - public String getSerial() { - return serial; + public String serialNumber() { + return serialNumber_; } @Override - public int getClassCode() { - return classCode; + public int classCode() { + return classCode_; } @Override - public int getSubclassCode() { - return subclassCode; + public int subclassCode() { + return subclassCode_; } @Override - public int getProtocolCode() { - return protocolCode; + public int protocolCode() { + return protocolCode_; } public Object getUniqueId() { - return id; + return id_; } @Override - public List getInterfaces() { - return Collections.unmodifiableList(interfaces); + public List interfaces() { + return Collections.unmodifiableList(interfaces_); } public void setInterfaces(List interfaces) { - this.interfaces = interfaces; + interfaces_ = interfaces; } @Override @@ -143,17 +143,17 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; USBDeviceImpl that = (USBDeviceImpl) o; - return id.equals(that.id); + return id_.equals(that.id_); } @Override public int hashCode() { - return id.hashCode(); + return id_.hashCode(); } @Override public String toString() { - return "VID: 0x" + String.format("%04x", vendorId) + ", PID: 0x" + String.format("%04x", productId) + ", " + - "manufacturer: " + manufacturer + ", product: " + product + ", serial: " + serial + ", ID: " + id; + return "VID: 0x" + String.format("%04x", vendorId_) + ", PID: 0x" + String.format("%04x", productId_) + ", " + + "manufacturer: " + manufacturer_ + ", product: " + product_ + ", serial: " + serialNumber_ + ", ID: " + id_; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBEndpointImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBEndpointImpl.java index 795b1138..c245a4f3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBEndpointImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBEndpointImpl.java @@ -9,42 +9,42 @@ import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBEndpoint; -import net.codecrete.usb.USBEndpointType; +import net.codecrete.usb.USBTransferType; /** * Implementation of {@code USBEndpoint} interface. */ public class USBEndpointImpl implements USBEndpoint { - private final int number; - private final USBDirection direction; - private final USBEndpointType type; - private final int packetSize; + private final int number_; + private final USBDirection direction_; + private final USBTransferType type_; + private final int packetSize_; - public USBEndpointImpl(int number, USBDirection direction, USBEndpointType type, int packetSize) { - this.number = number; - this.direction = direction; - this.type = type; - this.packetSize = packetSize; + public USBEndpointImpl(int number, USBDirection direction, USBTransferType type, int packetSize) { + number_ = number; + direction_ = direction; + type_ = type; + packetSize_ = packetSize; } @Override - public int getNumber() { - return number; + public int number() { + return number_; } @Override - public USBDirection getDirection() { - return direction; + public USBDirection direction() { + return direction_; } @Override - public USBEndpointType getType() { - return type; + public USBTransferType transferType() { + return type_; } @Override - public int getPacketSize() { - return packetSize; + public int packetSize() { + return packetSize_; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java index 52bd6131..89d1ad72 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java @@ -15,18 +15,18 @@ public class USBInterfaceImpl implements USBInterface { - private int number; - private USBAlternateInterface alternate; - private List alternates; + private int number_; + private USBAlternateInterface alternate_; + private List alternates_; public USBInterfaceImpl(int number, List alternates) { - this.number = number; - this.alternates = alternates; - this.alternate = alternates.get(0); + number_ = number; + alternates_ = alternates; + alternate_ = alternates.get(0); } @Override - public int getNumber() { + public int number() { return 0; } @@ -36,16 +36,16 @@ public boolean isClaimed() { } @Override - public USBAlternateInterface getAlternate() { - return alternate; + public USBAlternateInterface alternate() { + return alternate_; } @Override - public List getAlternates() { - return Collections.unmodifiableList(alternates); + public List alternates() { + return Collections.unmodifiableList(alternates_); } void addAlternate(USBAlternateInterface alt) { - alternates.add(alt); + alternates_.add(alt); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index fb224ea0..3c6af1f3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -49,7 +49,7 @@ private void loadDescription(String path) { // skip device descriptor var configDesc = session.allocateArray(JAVA_BYTE, descriptors.length - 18); configDesc.copyFrom(descriptorsSegment.asSlice(18)); - var configuration = DescriptorParser.parseConfigurationDescriptor(configDesc, getVendorId(), getProductId()); + var configuration = DescriptorParser.parseConfigurationDescriptor(configDesc, vendorId(), productId()); setInterfaces(configuration.interfaces); } } @@ -64,7 +64,7 @@ public void open() { if (fd != -1) return; try (var session = MemorySession.openConfined()) { - var pathUtf8 = session.allocateUtf8String(id.toString()); + var pathUtf8 = session.allocateUtf8String(id_.toString()); fd = fcntl.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC()); if (fd == -1) throw new USBException("Cannot open USB device", IO.getErrno()); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index fff7d86e..8df91df9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -99,7 +99,7 @@ private void loadDescription() { var configDesc = MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), totalLength, session); - var configuration = DescriptorParser.parseConfigurationDescriptor(configDesc, getVendorId(), getProductId()); + var configuration = DescriptorParser.parseConfigurationDescriptor(configDesc, vendorId(), productId()); configurationValue = 255 & configuration.configValue; setInterfaces(configuration.interfaces); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 7c8f426a..4fae6e96 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -58,7 +58,7 @@ public void open() { try (var session = MemorySession.openConfined()) { // open Windows device - var pathSegment = Win.createSegmentFromString(id.toString(), session); + var pathSegment = Win.createSegmentFromString(id_.toString(), session); device = Kernel32.CreateFileW(pathSegment, Kernel32.GENERIC_WRITE() | Kernel32.GENERIC_READ(), Kernel32.FILE_SHARE_WRITE() | Kernel32.FILE_SHARE_READ(), NULL, Kernel32.OPEN_EXISTING(), Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), NULL); @@ -84,7 +84,7 @@ public void open() { } private void readDescription(MemorySegment configDesc) { - configuration = DescriptorParser.parseConfigurationDescriptor(configDesc, getVendorId(), getProductId()); + configuration = DescriptorParser.parseConfigurationDescriptor(configDesc, vendorId(), productId()); configurationValue = configuration.configValue; setInterfaces(configuration.interfaces); } @@ -116,7 +116,7 @@ public void claimInterface(int interfaceNumber) { public void releaseInterface(int interfaceNumber) { checkIsOpen(); - var intfOptional = claimedInterfaces.stream().filter(intf -> intf.getNumber() == interfaceNumber).findFirst(); + var intfOptional = claimedInterfaces.stream().filter(intf -> intf.number() == interfaceNumber).findFirst(); if (intfOptional.isEmpty()) throw new USBException(String.format("Interface has not been claimed: number %d", interfaceNumber)); @@ -127,8 +127,8 @@ public void releaseInterface(int interfaceNumber) { private byte checkEndpointNumber(int endpointNumber, USBDirection direction) { if (endpointNumber >= 1 && endpointNumber <= 127 && claimedInterfaces != null) { for (var intf : claimedInterfaces) { - for (var ep : intf.getAlternate().getEndpoints()) { - if (ep.getNumber() == endpointNumber && ep.getDirection() == direction) + for (var ep : intf.alternate().endpoints()) { + if (ep.number() == endpointNumber && ep.direction() == direction) return (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index 119364e0..bc8f4691 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -20,41 +20,41 @@ public class DescriptionTest extends TestDeviceBase { @Test void interfaceDescriptors_present() { - assertNotNull(device.getInterfaces()); - assertEquals(1, device.getInterfaces().size()); + assertNotNull(device.interfaces()); + assertEquals(1, device.interfaces().size()); - var intf = device.getInterfaces().get(0); - assertEquals(0, intf.getNumber()); - assertNotNull(intf.getAlternate()); + var intf = device.interfaces().get(0); + assertEquals(0, intf.number()); + assertNotNull(intf.alternate()); assertFalse(intf.isClaimed()); } @Test void alternateInterfaceDescriptors_present() { - var intf = device.getInterfaces().get(0); - var altIntf = intf.getAlternate(); - assertNotNull(intf.getAlternates()); - assertEquals(1, intf.getAlternates().size()); - assertSame(intf.getAlternates().get(0), altIntf); - assertEquals(0, altIntf.getNumber()); + var intf = device.interfaces().get(0); + var altIntf = intf.alternate(); + assertNotNull(intf.alternates()); + assertEquals(1, intf.alternates().size()); + assertSame(intf.alternates().get(0), altIntf); + assertEquals(0, altIntf.number()); } @Test void endpointDescriptors_present() { - var altIntf = device.getInterfaces().get(0).getAlternate(); - assertNotNull(altIntf.getEndpoints()); - assertEquals(2, altIntf.getEndpoints().size()); - - var endpoint = altIntf.getEndpoints().get(0); - assertEquals(1, endpoint.getNumber()); - assertEquals(USBDirection.OUT, endpoint.getDirection()); - assertEquals(USBEndpointType.BULK, endpoint.getType()); - assertEquals(64, endpoint.getPacketSize()); - - endpoint = altIntf.getEndpoints().get(1); - assertEquals(2, endpoint.getNumber()); - assertEquals(USBDirection.IN, endpoint.getDirection()); - assertEquals(USBEndpointType.BULK, endpoint.getType()); - assertEquals(64, endpoint.getPacketSize()); + var altIntf = device.interfaces().get(0).alternate(); + assertNotNull(altIntf.endpoints()); + assertEquals(2, altIntf.endpoints().size()); + + var endpoint = altIntf.endpoints().get(0); + assertEquals(1, endpoint.number()); + assertEquals(USBDirection.OUT, endpoint.direction()); + assertEquals(USBTransferType.BULK, endpoint.transferType()); + assertEquals(64, endpoint.packetSize()); + + endpoint = altIntf.endpoints().get(1); + assertEquals(2, endpoint.number()); + assertEquals(USBDirection.IN, endpoint.direction()); + assertEquals(USBTransferType.BULK, endpoint.transferType()); + assertEquals(64, endpoint.packetSize()); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java index 2fa6e43b..49ef514c 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java @@ -29,7 +29,7 @@ static void openDevice() { @Test void getAllDevices_includesLoopback() { var found = USB.getAllDevices().stream() - .anyMatch(device -> device.getVendorId() == 0xcafe && device.getProductId() == 0xceaf); + .anyMatch(device -> device.vendorId() == 0xcafe && device.productId() == 0xceaf); assertTrue(found); } @@ -37,8 +37,8 @@ void getAllDevices_includesLoopback() { void getDevicesWithFilter_returnsLoopback() { var result = USB.getDevices(new USBDeviceFilter(0xcafe, 0xceaf)); assertEquals(1, result.size()); - assertEquals(0xcafe, result.get(0).getVendorId()); - assertEquals(0xceaf, result.get(0).getProductId()); + assertEquals(0xcafe, result.get(0).vendorId()); + assertEquals(0xceaf, result.get(0).productId()); } @Test @@ -48,15 +48,15 @@ void getDevicesWithMultipleFilters_returnsLoopback() { new USBDeviceFilter(0x0000, 0xffff) )); assertEquals(1, result.size()); - assertEquals(0xcafe, result.get(0).getVendorId()); - assertEquals(0xceaf, result.get(0).getProductId()); + assertEquals(0xcafe, result.get(0).vendorId()); + assertEquals(0xceaf, result.get(0).productId()); } @Test void getDeviceWithFilter_returnsLoopback() { var device = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); - assertEquals(0xcafe, device.getVendorId()); - assertEquals(0xceaf, device.getProductId()); + assertEquals(0xcafe, device.vendorId()); + assertEquals(0xceaf, device.productId()); } @Test @@ -65,7 +65,7 @@ void getDeviceWithMultipleFilters_returnsLoopback() { new USBDeviceFilter(0xcafe, 0xceaf), new USBDeviceFilter(0x0000, 0xffff) )); - assertEquals(0xcafe, device.getVendorId()); - assertEquals(0xceaf, device.getProductId()); + assertEquals(0xcafe, device.vendorId()); + assertEquals(0xceaf, device.productId()); } } From 588deb5a514f866baf406cab2872aa293d25a480 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 3 Sep 2022 22:37:58 +0200 Subject: [PATCH 046/433] macOS: add device class codes --- .../codecrete/usb/USBAlternateInterface.java | 4 +++ .../codecrete/usb/common/USBDeviceImpl.java | 6 ++++ .../usb/macos/MacosUSBDeviceRegistry.java | 12 ++++++- .../net/codecrete/usb/BulkTransferTest.java | 4 +-- .../codecrete/usb/ControlTransferTest.java | 10 +++--- .../net/codecrete/usb/DescriptionTest.java | 31 ++++++++++++++----- .../codecrete/usb/DeviceEnumerationTest.java | 9 +----- .../net/codecrete/usb/TestDeviceBase.java | 16 +++++----- 8 files changed, 60 insertions(+), 32 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java index d32faa99..40041360 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java @@ -58,6 +58,10 @@ public interface USBAlternateInterface { /** * Gets the endpoints of this alternate interface settings. + *

+ * The endpoint list does not include endpoint 0, which + * is always available and reserved for control transfers. + *

* * @return a list of endpoints. */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 3c1b633f..1fab3e9c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -110,6 +110,12 @@ public Object getUniqueId() { return id_; } + public void setClassCodes(int classCode, int subclassCode, int protocolCode) { + classCode_ = classCode; + subclassCode_ = subclassCode; + protocolCode_ = protocolCode; + } + @Override public List interfaces() { return Collections.unmodifiableList(interfaces_); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 5cc575b8..a88be68c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -154,7 +154,17 @@ private USBDevice createDevice(Long entryID, int service, MemoryAddress deviceIn String product = IoKitHelper.getPropertyString(service, "kUSBProductString"); String serial = IoKitHelper.getPropertyString(service, "kUSBSerialNumberString"); - return new MacosUSBDevice(deviceIntf, entryID, vendorId, productId, manufacturer, product, serial); + var device = new MacosUSBDevice(deviceIntf, entryID, vendorId, productId, manufacturer, product, serial); + + Integer classCode = IoKitHelper.getPropertyInt(service, "bDeviceClass"); + Integer subclassCode = IoKitHelper.getPropertyInt(service, "bDeviceSubClass"); + Integer protocolCode = IoKitHelper.getPropertyInt(service, "bDeviceProtocol"); + + device.setClassCodes(classCode != null ? classCode : 0, + subclassCode != null ? subclassCode : 0, + protocolCode != null ? protocolCode : 0); + + return device; } private int setupNotification(MemorySession session, MemoryAddress notifyPort, MemorySegment notificationType, diff --git a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java index db4fb5c1..5f35b870 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java @@ -59,7 +59,7 @@ static void writeBytes(byte[] data) { int numBytes = 0; while (numBytes < data.length) { int size = Math.min(chunkSize, data.length - numBytes); - device.transferOut(LOOPBACK_EP_OUT, Arrays.copyOfRange(data, numBytes, numBytes + size)); + testDevice.transferOut(LOOPBACK_EP_OUT, Arrays.copyOfRange(data, numBytes, numBytes + size)); numBytes += size; } } @@ -67,7 +67,7 @@ static byte[] readBytes(int numBytes) { var buffer = new ByteArrayOutputStream(); int bytesRead = 0; while (bytesRead < numBytes) { - byte[] data = device.transferIn(LOOPBACK_EP_IN, MAX_PACKET_SIZE); + byte[] data = testDevice.transferIn(LOOPBACK_EP_IN, MAX_PACKET_SIZE); buffer.writeBytes(data); bytesRead += data.length; } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java index 0c6e9df7..9832a14a 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java @@ -20,13 +20,13 @@ public class ControlTransferTest extends TestDeviceBase { @Test void storeValue_succeeds() { - device.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x01, (short) 10730, (short) 0), null); + testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x01, (short) 10730, (short) 0), null); } @Test void retrieveValue_isSameAsStored() { - device.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x01, (short) 0x9a41, (short) 0), null); - var valueBytes = device.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) 0), 4); + testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x01, (short) 0x9a41, (short) 0), null); + var valueBytes = testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) 0), 4); var expectedBytes = new byte[] { (byte)0x41, (byte)0x9a, (byte)0x00, (byte)0x00 }; assertArrayEquals(expectedBytes, valueBytes); } @@ -34,8 +34,8 @@ void retrieveValue_isSameAsStored() { @Test void storeValueInDataStage_canBeRetrieved() { var sentValue = new byte[] { (byte)0x83, (byte)0x03, (byte)0xda, (byte)0x3e }; - device.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x02, (short) 0, (short) 0), sentValue); - var retrievedValue = device.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) 0), 4); + testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x02, (short) 0, (short) 0), sentValue); + var retrievedValue = testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) 0), 4); assertArrayEquals(sentValue, retrievedValue); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index bc8f4691..d80bea17 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -19,29 +19,44 @@ public class DescriptionTest extends TestDeviceBase { @Test - void interfaceDescriptors_present() { - assertNotNull(device.interfaces()); - assertEquals(1, device.interfaces().size()); + void deviceInfo_isCorrect() { + assertEquals("JavaDoesUSB", testDevice.manufacturer()); + assertEquals("Loopback", testDevice.product()); + assertEquals(12, testDevice.serialNumber().length()); - var intf = device.interfaces().get(0); + assertEquals(0xff, testDevice.classCode()); + assertEquals(0x00, testDevice.subclassCode()); + assertEquals(0x00, testDevice.protocolCode()); + } + + @Test + void interfaceDescriptors_isCorrect() { + assertNotNull(testDevice.interfaces()); + assertEquals(1, testDevice.interfaces().size()); + + var intf = testDevice.interfaces().get(0); assertEquals(0, intf.number()); assertNotNull(intf.alternate()); assertFalse(intf.isClaimed()); } @Test - void alternateInterfaceDescriptors_present() { - var intf = device.interfaces().get(0); + void alternateInterfaceDescriptors_isCorrect() { + var intf = testDevice.interfaces().get(0); var altIntf = intf.alternate(); assertNotNull(intf.alternates()); assertEquals(1, intf.alternates().size()); assertSame(intf.alternates().get(0), altIntf); assertEquals(0, altIntf.number()); + + assertEquals(0xff, altIntf.classCode()); + assertEquals(0x00, altIntf.subclassCode()); + assertEquals(0x00, altIntf.protocolCode()); } @Test - void endpointDescriptors_present() { - var altIntf = device.interfaces().get(0).alternate(); + void endpointDescriptors_isCorrect() { + var altIntf = testDevice.interfaces().get(0).alternate(); assertNotNull(altIntf.endpoints()); assertEquals(2, altIntf.endpoints().size()); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java index 49ef514c..002d849a 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java @@ -17,14 +17,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -public class DeviceEnumerationTest { - - @BeforeAll - static void openDevice() { - var device = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); - if (device == null) - throw new IllegalStateException("USB loopback test device must be connected"); - } +public class DeviceEnumerationTest extends TestDeviceBase { @Test void getAllDevices_includesLoopback() { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index efd53b54..3a1b3027 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -16,22 +16,22 @@ * Base class for tests using the test device. */ public class TestDeviceBase { - protected static USBDevice device; + protected static USBDevice testDevice; @BeforeAll static void openDevice() { - device = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); - if (device == null) + testDevice = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); + if (testDevice == null) throw new IllegalStateException("USB loopback test device must be connected"); - device.open(); - device.claimInterface(0); + testDevice.open(); + testDevice.claimInterface(0); } @AfterAll static void closeDevice() { - if (device != null) { - device.close(); - device = null; + if (testDevice != null) { + testDevice.close(); + testDevice = null; } } } From c2794fe4f8aee8dd402c48815feb79f766eb533a Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 3 Sep 2022 23:26:56 +0200 Subject: [PATCH 047/433] macOS: check for invalid endpoints and interfaces --- .../codecrete/usb/common/USBDeviceImpl.java | 41 +++++++- .../usb/common/USBInterfaceImpl.java | 16 +++- .../codecrete/usb/macos/MacosUSBDevice.java | 95 +++++++++++-------- .../usb/windows/WindowsUSBDevice.java | 22 +---- .../net/codecrete/usb/DescriptionTest.java | 2 +- .../codecrete/usb/InvalidOperationTest.java | 63 ++++++++++++ 6 files changed, 167 insertions(+), 72 deletions(-) create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 1fab3e9c..48cf071c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -7,10 +7,7 @@ package net.codecrete.usb.common; -import net.codecrete.usb.USBControlTransfer; -import net.codecrete.usb.USBDevice; -import net.codecrete.usb.USBException; -import net.codecrete.usb.USBInterface; +import net.codecrete.usb.*; import java.util.Collections; import java.util.List; @@ -131,6 +128,42 @@ public void setInterfaces(List interfaces) { @Override public abstract void releaseInterface(int interfaceNumber); + public void setClaimed(int interfaceNumber, boolean claimed) { + for (var intf : interfaces_) { + if (intf.number() == interfaceNumber) { + ((USBInterfaceImpl)intf).setClaimed(claimed); + return; + } + } + throw new USBException("Internal error (interface not found)"); + } + + /** + * Checks if the specified endpoint is valid for communication and returns the endpoint address. + * + * @param endpointNumber endpoint number (1 to 127) + * @param direction transfer direction + * @return endpoint address + */ + protected byte getEndpointAddress(int endpointNumber, USBDirection direction) { + + checkIsOpen(); + + if (endpointNumber >= 1 && endpointNumber <= 127) { + for (var intf : interfaces_) { + if (intf.isClaimed()) { + for (var ep : intf.alternate().endpoints()) { + if (ep.number() == endpointNumber && ep.direction() == direction) + return (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)); + } + } + } + } + + throw new USBException(String.format("Endpoint number %d is not part of a claimed interface, the endpoint " + + "does not operate in the %s direction or is otherwise invalid", endpointNumber, direction.name())); + } + @Override public abstract byte[] controlTransferIn(USBControlTransfer setup, int length); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java index 89d1ad72..9e9a6d15 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java @@ -15,9 +15,11 @@ public class USBInterfaceImpl implements USBInterface { - private int number_; - private USBAlternateInterface alternate_; - private List alternates_; + private final int number_; + private final USBAlternateInterface alternate_; + private final List alternates_; + + private boolean isClaimed_; public USBInterfaceImpl(int number, List alternates) { number_ = number; @@ -27,12 +29,16 @@ public USBInterfaceImpl(int number, List alternates) { @Override public int number() { - return 0; + return number_; } @Override public boolean isClaimed() { - return false; + return isClaimed_; + } + + void setClaimed(boolean claimed) { + isClaimed_ = claimed; } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 8df91df9..d48d0378 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -18,7 +18,9 @@ import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static java.lang.foreign.MemoryAddress.ofLong; import static java.lang.foreign.ValueLayout.*; @@ -28,7 +30,7 @@ public class MacosUSBDevice extends USBDeviceImpl { private final MemoryAddress device; private int configurationValue; private List claimedInterfaces; - private List endpoints; + private Map endpoints; MacosUSBDevice(MemoryAddress device, Object id, int vendorId, int productId, String manufacturer, String product, String serial) { super(id, vendorId, productId, manufacturer, product, serial); @@ -60,6 +62,7 @@ public void open() { throw new MacosUSBException("failed to set configuration", ret); claimedInterfaces = new ArrayList<>(); + updateEndpointList(); } @Override @@ -68,8 +71,8 @@ public void close() { return; for (InterfaceInfo interfaceInfo : claimedInterfaces) { - IoKitUSB.USBInterfaceClose(interfaceInfo.asMemoryAddress()); - IoKit.Release(interfaceInfo.asMemoryAddress()); + IoKitUSB.USBInterfaceClose(interfaceInfo.asAddress()); + IoKit.Release(interfaceInfo.asAddress()); } claimedInterfaces = null; @@ -144,10 +147,7 @@ private InterfaceInfo findInterface(int interfaceNumber) { continue; } - var info = new InterfaceInfo(); - info.addr = intf.toRawLongValue(); - info.interfaceNumber = interfaceNumber; - return info; + return new InterfaceInfo(intf.toRawLongValue(), interfaceNumber); } } } @@ -161,10 +161,13 @@ public void claimInterface(int interfaceNumber) { var interfaceInfo = findInterface(interfaceNumber); try { - var ret = IoKitUSB.USBInterfaceOpen(interfaceInfo.asMemoryAddress()); - if (ret != 0) throw new MacosUSBException("Failed to claim interface", ret); + var ret = IoKitUSB.USBInterfaceOpen(interfaceInfo.asAddress()); + if (ret != 0) + throw new MacosUSBException("Failed to claim interface", ret); + setClaimed(interfaceNumber, true); + } catch (Throwable t) { - IoKit.Release(interfaceInfo.asMemoryAddress()); + IoKit.Release(interfaceInfo.asAddress()); throw t; } @@ -183,25 +186,34 @@ public void releaseInterface(int interfaceNumber) { var interfaceInfo = interfaceInfoOptional.get(); - int ret = IoKitUSB.USBInterfaceClose(interfaceInfo.asMemoryAddress()); + int ret = IoKitUSB.USBInterfaceClose(interfaceInfo.asAddress()); if (ret != 0) throw new MacosUSBException("Failed to release interface", ret); claimedInterfaces.remove(interfaceInfo); - IoKit.Release(interfaceInfo.asMemoryAddress()); + IoKit.Release(interfaceInfo.asAddress()); + setClaimed(interfaceNumber, false); updateEndpointList(); } + /** + * Update the map of active endpoints. + *

+ * MacOS uses a pipe index to refer to endpoints. This method + * builds a map from endpoint address to pipe index. + *

+ */ private void updateEndpointList() { - endpoints = new ArrayList<>(); + endpoints = new HashMap<>(); for (InterfaceInfo interfaceInfo : claimedInterfaces) { try (var session = MemorySession.openConfined()) { - var intf = interfaceInfo.asMemoryAddress(); + var intf = interfaceInfo.asAddress(); var numEndpointsHolder = session.allocate(JAVA_BYTE); int ret = IoKitUSB.GetNumEndpoints(intf, numEndpointsHolder); - if (ret != 0) throw new MacosUSBException("Failed to get number of endpoints", ret); + if (ret != 0) + throw new MacosUSBException("Failed to get number of endpoints", ret); int numEndpoints = numEndpointsHolder.get(JAVA_BYTE, 0) & 255; for (int pipeIndex = 1; pipeIndex <= numEndpoints; pipeIndex++) { @@ -216,27 +228,26 @@ private void updateEndpointList() { transferTypeHolder, maxPacketSizeHolder, intervalHolder); if (ret != 0) throw new MacosUSBException("Failed to get pipe properties", ret); - var endpointInfo = new EndpointInfo(); - endpointInfo.pipeIndex = pipeIndex; - endpointInfo.endpointNumber = numberHolder.get(JAVA_BYTE, 0) & 255; + int endpointNumber = numberHolder.get(JAVA_BYTE, 0) & 255; int direction = directionHolder.get(JAVA_BYTE, 0) & 255; - endpointInfo.endpointAddress = endpointInfo.endpointNumber | (direction << 7); - endpointInfo.transferType = transferTypeHolder.get(JAVA_BYTE, 0) & 255; - endpointInfo.interfaceInfo = interfaceInfo; - endpoints.add(endpointInfo); + byte endpointAddress = (byte) (endpointNumber | (direction << 7)); + var endpointInfo = new EndpointInfo(interfaceInfo.addr, (byte) pipeIndex); + endpoints.put(endpointAddress, endpointInfo); } } } } - private EndpointInfo getEndpointInfo(int endpointNumber) { + private EndpointInfo getEndpointInfo(int endpointNumber, USBDirection direction) { if (endpoints != null) { - var endpointOptional = endpoints.stream().filter(info -> info.endpointNumber == endpointNumber).findFirst(); - if (endpointOptional.isPresent()) return endpointOptional.get(); + byte endpointAddress = (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)); + var endpointInfo = endpoints.get(endpointAddress); + if (endpointInfo != null) + return endpointInfo; } - throw new MacosUSBException(String.format("Endpoint number %d is not part of a claimed interface or invalid", - endpointNumber)); + throw new USBException(String.format("Endpoint number %d is not part of a claimed interface, the endpoint " + + "does not operate in the %s direction or is otherwise invalid", endpointNumber, direction.name())); } private static MemorySegment createDeviceRequest(MemorySession session, USBDirection direction, @@ -255,6 +266,8 @@ private static MemorySegment createDeviceRequest(MemorySession session, USBDirec @Override public byte[] controlTransferIn(USBControlTransfer setup, int length) { + checkIsOpen(); + try (var session = MemorySession.openConfined()) { var data = session.allocate(length); var deviceRequest = createDeviceRequest(session, USBDirection.IN, setup, data); @@ -269,6 +282,8 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { @Override public void controlTransferOut(USBControlTransfer setup, byte[] data) { + checkIsOpen(); + try (var session = MemorySession.openConfined()) { int dataLength = data != null ? data.length : 0; var dataSegment = session.allocate(dataLength); @@ -283,12 +298,12 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { @Override public void transferOut(int endpointNumber, byte[] data) { - var endpointInfo = getEndpointInfo(endpointNumber); + var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.OUT); try (var session = MemorySession.openConfined()) { var nativeData = session.allocateArray(JAVA_BYTE, data.length); nativeData.copyFrom(MemorySegment.ofArray(data)); - int ret = IoKitUSB.WritePipe(endpointInfo.interfaceInfo.asMemoryAddress(), (byte) endpointInfo.pipeIndex, + int ret = IoKitUSB.WritePipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData, data.length); if (ret != 0) throw new MacosUSBException(String.format("Sending data to endpoint %d failed", endpointNumber), ret); @@ -297,12 +312,13 @@ public void transferOut(int endpointNumber, byte[] data) { @Override public byte[] transferIn(int endpointNumber, int maxLength) { - var endpointInfo = getEndpointInfo(endpointNumber); + + var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.IN); try (var session = MemorySession.openConfined()) { var nativeData = session.allocateArray(JAVA_BYTE, maxLength); var sizeHolder = session.allocate(JAVA_INT, maxLength); - int ret = IoKitUSB.ReadPipe(endpointInfo.interfaceInfo.asMemoryAddress(), (byte) endpointInfo.pipeIndex, + int ret = IoKitUSB.ReadPipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData, sizeHolder); if (ret != 0) throw new MacosUSBException(String.format("Receiving data from endpoint %d failed", endpointNumber), @@ -317,20 +333,15 @@ public byte[] transferIn(int endpointNumber, int maxLength) { } } - static class InterfaceInfo { - long addr; - int interfaceNumber; - - MemoryAddress asMemoryAddress() { + record InterfaceInfo(long addr, int interfaceNumber) { + MemoryAddress asAddress() { return ofLong(addr); } } - static class EndpointInfo { - int endpointNumber; - int endpointAddress; - int transferType; - int pipeIndex; - InterfaceInfo interfaceInfo; + record EndpointInfo(long interfaceAddr, byte pipeIndex) { + MemoryAddress interfacAddress() { + return ofLong(interfaceAddr); + } } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 4fae6e96..e7900559 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -124,20 +124,6 @@ public void releaseInterface(int interfaceNumber) { claimedInterfaces.remove(intfOptional.get()); } - private byte checkEndpointNumber(int endpointNumber, USBDirection direction) { - if (endpointNumber >= 1 && endpointNumber <= 127 && claimedInterfaces != null) { - for (var intf : claimedInterfaces) { - for (var ep : intf.alternate().endpoints()) { - if (ep.number() == endpointNumber && ep.direction() == direction) - return (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)); - } - } - } - - throw new USBException(String.format("Endpoint number %d is not part of a claimed interface, the endpoint " + - "does not operate " + "in the %s direction or is otherwise invalid", endpointNumber, direction.name())); - } - private MemorySegment createSetupPacket(MemorySession session, USBDirection direction, USBControlTransfer setup, MemorySegment data) { var setupPacket = session.allocate(USBStructs.SetupPacket$Struct); @@ -193,9 +179,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { @Override public void transferOut(int endpointNumber, byte[] data) { - checkIsOpen(); - - byte endpointAddress = checkEndpointNumber(endpointNumber, USBDirection.OUT); + byte endpointAddress = getEndpointAddress(endpointNumber, USBDirection.OUT); try (var session = MemorySession.openConfined()) { var buffer = session.allocate(data.length); @@ -210,9 +194,7 @@ public void transferOut(int endpointNumber, byte[] data) { @Override public byte[] transferIn(int endpointNumber, int maxLength) { - checkIsOpen(); - - byte endpointAddress = checkEndpointNumber(endpointNumber, USBDirection.IN); + byte endpointAddress = getEndpointAddress(endpointNumber, USBDirection.IN); try (var session = MemorySession.openConfined()) { var buffer = session.allocate(maxLength); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index d80bea17..db78f93b 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -37,7 +37,7 @@ void interfaceDescriptors_isCorrect() { var intf = testDevice.interfaces().get(0); assertEquals(0, intf.number()); assertNotNull(intf.alternate()); - assertFalse(intf.isClaimed()); + assertTrue(intf.isClaimed()); } @Test diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java new file mode 100644 index 00000000..d0e5d54d --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java @@ -0,0 +1,63 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Unit test for bulk transfer +// + +package net.codecrete.usb; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class InvalidOperationTest extends TestDeviceBase { + + @Test + void claimInvalidInterface_throws() { + Assertions.assertThrows(USBException.class, () -> { + testDevice.claimInterface(1); + }); + Assertions.assertThrows(USBException.class, () -> { + testDevice.claimInterface(888); + }); + } + + @Test + void releaseInvalidInterface_throws() { + Assertions.assertThrows(USBException.class, () -> { + testDevice.releaseInterface(1); + }); + } + + + @Test + void invalidEndpoint_throws() { + var data = new byte[] { 34, 23, 99, 0, 17 }; + + Assertions.assertThrows(USBException.class, () -> { + testDevice.transferOut(2, data); + }); + + Assertions.assertThrows(USBException.class, () -> { + testDevice.transferOut(0, data); + }); + + Assertions.assertThrows(USBException.class, () -> { + testDevice.transferOut(3, data); + }); + + Assertions.assertThrows(USBException.class, () -> { + testDevice.transferIn(1, 64); + }); + + Assertions.assertThrows(USBException.class, () -> { + testDevice.transferIn(0, 64); + }); + + Assertions.assertThrows(USBException.class, () -> { + testDevice.transferIn(4, 64); + }); + } +} From dc2ca4df4dcd19720f52a52e680dd8cf1c0ac5e3 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 4 Sep 2022 07:41:21 +0200 Subject: [PATCH 048/433] Windows: manage claimed state of interfaces --- .../usb/common/USBInterfaceImpl.java | 2 +- .../usb/windows/WindowsUSBDevice.java | 21 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java index 9e9a6d15..7ff8c970 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java @@ -37,7 +37,7 @@ public boolean isClaimed() { return isClaimed_; } - void setClaimed(boolean claimed) { + public void setClaimed(boolean claimed) { isClaimed_ = claimed; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index e7900559..b297043e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -14,6 +14,7 @@ import net.codecrete.usb.common.DescriptorParser; import net.codecrete.usb.common.DescriptorParser.Configuration; import net.codecrete.usb.common.USBDeviceImpl; +import net.codecrete.usb.common.USBInterfaceImpl; import net.codecrete.usb.common.USBStructs; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.winusb.WinUSB; @@ -36,7 +37,6 @@ public class WindowsUSBDevice extends USBDeviceImpl { private MemoryAddress firstInterface; private byte configurationValue; private Configuration configuration; - private List claimedInterfaces; WindowsUSBDevice(Object id, int vendorId, int productId, String manufacturer, String product, String serial, MemorySegment configDesc) { @@ -94,6 +94,9 @@ public void close() { if (!isOpen()) return; + for (var intf : interfaces_) + ((USBInterfaceImpl) intf).setClaimed(false); + WinUSB.WinUsb_Free(firstInterface); firstInterface = null; Kernel32.CloseHandle(device); @@ -106,22 +109,20 @@ public void claimInterface(int interfaceNumber) { var intf = configuration.findInterfaceByNumber(interfaceNumber); if (intf == null) throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); + if (intf.isClaimed()) + throw new USBException(String.format("Interface %d has already been claimed", interfaceNumber)); - if (claimedInterfaces == null) - claimedInterfaces = new ArrayList<>(); - - claimedInterfaces.add(intf); + setClaimed(interfaceNumber, true); } public void releaseInterface(int interfaceNumber) { checkIsOpen(); - var intfOptional = claimedInterfaces.stream().filter(intf -> intf.number() == interfaceNumber).findFirst(); - if (intfOptional.isEmpty()) - throw new USBException(String.format("Interface has not been claimed: number %d", - interfaceNumber)); + var intf = configuration.findInterfaceByNumber(interfaceNumber); + if (intf == null) + throw new USBException(String.format("Interface %d has not been claimed", interfaceNumber)); - claimedInterfaces.remove(intfOptional.get()); + setClaimed(interfaceNumber, false); } private MemorySegment createSetupPacket(MemorySession session, USBDirection direction, USBControlTransfer setup, From fcac38c22f7fb3809e1ac981a07e7743ea21a356 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 4 Sep 2022 07:45:59 +0200 Subject: [PATCH 049/433] Add device class codes --- .../codecrete/usb/windows/WindowsUSBDeviceRegistry.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 03587bee..05533823 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -210,7 +210,14 @@ private USBDevice createDevice(String devicePath, MemoryAddress hubHandle, int u var configDesc = getDescriptor(hubHandle, usbPortNum, USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE, 0, (short) 0, session); - return new WindowsUSBDevice(devicePath, vendorId, productId, manufacturer, product, serialNumber, configDesc); + var device = new WindowsUSBDevice(devicePath, vendorId, productId, manufacturer, product, serialNumber, configDesc); + + int classCode = 255 & (byte) USBDescriptors.Device_bDeviceClass.get(deviceDesc); + int subclassCode = 255 & (byte) USBDescriptors.Device_bDeviceSubClass.get(deviceDesc); + int protocolCode = 255 & (byte) USBDescriptors.Device_bDeviceProtocol.get(deviceDesc); + device.setClassCodes(classCode, subclassCode, protocolCode); + + return device; } } From bf4d6c2b06c071a2325711a81f0a753345a69e5e Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 4 Sep 2022 08:00:11 +0200 Subject: [PATCH 050/433] Code cleanup --- .../net/codecrete/usb/USBDeviceFilter.java | 6 +- .../usb/common/DescriptorParser.java | 3 +- .../java/net/codecrete/usb/macos/IoKit.java | 82 ------------------- .../net/codecrete/usb/macos/IoKitUSB.java | 14 ---- .../codecrete/usb/macos/MacosUSBDevice.java | 2 +- .../usb/windows/WindowsUSBDevice.java | 5 -- .../codecrete/usb/DeviceEnumerationTest.java | 1 - .../codecrete/usb/InvalidOperationTest.java | 36 ++------ 8 files changed, 15 insertions(+), 134 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java index cce636c9..c4599418 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java @@ -142,10 +142,10 @@ public Integer protocolCode() { /** * Sets the USB device protocol code. * - * @param protocolCode_ protocol code, or {@code null} if the protocol code is not relevant for matching + * @param protocolCode protocol code, or {@code null} if the protocol code is not relevant for matching */ - public void setProtocolCode_(Integer protocolCode_) { - protocolCode_ = protocolCode_; + public void setProtocolCode_(Integer protocolCode) { + protocolCode_ = protocolCode; } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java index 4f925577..9de876ad 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java @@ -52,7 +52,8 @@ public static Configuration parseConfigurationDescriptor(MemorySegment desc, int if (lastAlternate != null) lastAlternate.addEndpoint(lastEndpoint); - } else if (descType == USBDescriptors.INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE) { + } else //noinspection StatementWithEmptyBody + if (descType == USBDescriptors.INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE) { // TODO: interface associations } else //noinspection StatementWithEmptyBody diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java index c386f077..55718b65 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java @@ -30,9 +30,6 @@ public class IoKit { private static final MemorySession ioKitSession = MemorySession.openShared(); private static final SymbolLookup ioKitLookup = SymbolLookup.libraryLookup("IOKit.framework/IOKit", ioKitSession); - public static final Addressable kIOUSBPlane = ioKitSession.allocateUtf8String("IOUSB"); - public static final Addressable kIOServicePlane = ioKitSession.allocateUtf8String("IOService"); - public static final int kIOMasterPortDefault; public static final int kIORegistryIterateRecursively = 1; @@ -110,19 +107,6 @@ public static int Release(MemoryAddress thisPointer) { } } - // io_registry_entry_t IORegistryGetRootEntry(mach_port_t mainPort); - private static final MethodHandle IORegistryGetRootEntry$Func = linker.downcallHandle( - ioKitLookup.lookup("IORegistryGetRootEntry").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT) - ); - public static int IORegistryGetRootEntry(int mainPort) { - try { - return (int) IORegistryGetRootEntry$Func.invokeExact(mainPort); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - // kern_return_t IOObjectRelease(io_object_t object); private static final MethodHandle IOObjectRelease$Func = linker.downcallHandle( ioKitLookup.lookup("IOObjectRelease").get(), @@ -136,19 +120,6 @@ public static int IOObjectRelease(int object) { } } - // kern_return_t IORegistryEntryCreateIterator(io_registry_entry_t entry, const io_name_t plane, IOOptionBits options, io_iterator_t *iterator); - private static final MethodHandle IORegistryCreateIterator$Func = linker.downcallHandle( - ioKitLookup.lookup("IORegistryCreateIterator").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS, JAVA_INT, ADDRESS) - ); - public static int IORegistryCreateIterator(int entry, Addressable plane, int options, Addressable iterator) { - try { - return (int) IORegistryCreateIterator$Func.invokeExact(entry, plane, options, iterator); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - // io_object_t IOIteratorNext(io_iterator_t iterator); private static final MethodHandle IOIteratorNext$Func = linker.downcallHandle( ioKitLookup.lookup("IOIteratorNext").get(), @@ -162,19 +133,6 @@ public static int IOIteratorNext(int iter) { } } - // kern_return_t IORegistryEntryGetPath(io_registry_entry_t entry, const io_name_t plane, io_string_t path); - private static final MethodHandle IORegistryEntryGetPath$Func = linker.downcallHandle( - ioKitLookup.lookup("IORegistryEntryGetPath").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS, ADDRESS) - ); - public static int IORegistryEntryGetPath(int entry, Addressable plane, Addressable path) { - try { - return (int) IORegistryEntryGetPath$Func.invokeExact(entry, plane, path); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - // kern_return_t IOCreatePlugInInterfaceForService(io_service_t service, CFUUIDRef pluginType, CFUUIDRef interfaceType, IOCFPlugInInterface ***theInterface, SInt32 *theScore); private static final MethodHandle IOCreatePlugInInterfaceForService$Func = linker.downcallHandle( ioKitLookup.lookup("IOCreatePlugInInterfaceForService").get(), @@ -204,20 +162,6 @@ public static MemoryAddress IORegistryEntryCreateCFProperty(int entry, String ke } } - // io_registry_entry_t IORegistryEntryFromPath(mach_port_t mainPort, const io_string_t path); - private static final MethodHandle IORegistryEntryFromPath$Func = linker.downcallHandle( - ioKitLookup.lookup("IORegistryEntryFromPath").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS) - ); - public static int IORegistryEntryFromPath(int mainPort, String path) { - try (var session = MemorySession.openConfined()) { - var pathCStr = session.allocateUtf8String(path); - return (int) IORegistryEntryFromPath$Func.invokeExact(mainPort, (Addressable) pathCStr); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - // IONotificationPortRef IONotificationPortCreate(mach_port_t mainPort); private static final MethodHandle IONotificationPortCreate$Func = linker.downcallHandle( ioKitLookup.lookup("IONotificationPortCreate").get(), @@ -244,19 +188,6 @@ public static MemoryAddress IONotificationPortGetRunLoopSource(Addressable notif } } - // io_service_t IOServiceGetMatchingService(mach_port_t mainPort, CFDictionaryRef matching); - private static final MethodHandle IOServiceGetMatchingService$Func = linker.downcallHandle( - ioKitLookup.lookup("IOServiceGetMatchingService").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS) - ); - public static int IOServiceGetMatchingService(int mainPort, Addressable matching) { - try { - return (int) IOServiceGetMatchingService$Func.invokeExact(mainPort, matching); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - // kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t *entryID); private static final MethodHandle IORegistryEntryGetRegistryEntryID$Func = linker.downcallHandle( ioKitLookup.lookup("IORegistryEntryGetRegistryEntryID").get(), @@ -297,19 +228,6 @@ public static MemoryAddress IOServiceMatching(Addressable name) { } } - // CFMutableDictionaryRef IORegistryEntryIDMatching(uint64_t entryID); - private static final MethodHandle IORegistryEntryIDMatching$Func = linker.downcallHandle( - ioKitLookup.lookup("IORegistryEntryIDMatching").get(), - FunctionDescriptor.of(ADDRESS, JAVA_LONG) - ); - public static MemoryAddress IORegistryEntryIDMatching(long entryID) { - try { - return (MemoryAddress) IORegistryEntryIDMatching$Func.invokeExact(entryID); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - public static final MemoryAddress kIOUSBDeviceUserClientTypeID = CoreFoundation.CFUUIDCreateFromUUIDBytes( NULL, new byte[]{ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index 49b841f3..a2e2a147 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -138,20 +138,6 @@ public static int USBDeviceClose(MemoryAddress thisPointer) { } } - // IOReturn (*GetNumberOfConfigurations)(void *self, UInt8 *numConfig); - private static final VarHandle IOUSBDevice_GetNumberOfConfigurations = IOUSBDevice$Struct.varHandle(groupElement("GetNumberOfConfigurations")); - private static final MethodHandle GetNumberOfConfigurations$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS) - ); - public static int GetNumberOfConfigurations(MemoryAddress thisPointer, Addressable numConfigHolder) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_GetNumberOfConfigurations, session); - return (int) GetNumberOfConfigurations$Func.invokeExact(funcPtr, (Addressable) thisPointer, numConfigHolder); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - // IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc); private static final VarHandle IOUSBDevice_GetConfigurationDescriptorPtr = IOUSBDevice$Struct.varHandle(groupElement("GetConfigurationDescriptorPtr")); private static final MethodHandle GetConfigurationDescriptorPtr$Func = linker.downcallHandle( diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index d48d0378..e3924370 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -156,7 +156,7 @@ private InterfaceInfo findInterface(int interfaceNumber) { } public void claimInterface(int interfaceNumber) { - checkIsOpen();; + checkIsOpen(); var interfaceInfo = findInterface(interfaceNumber); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index b297043e..10ec84f5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -10,7 +10,6 @@ import net.codecrete.usb.USBControlTransfer; import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBException; -import net.codecrete.usb.USBInterface; import net.codecrete.usb.common.DescriptorParser; import net.codecrete.usb.common.DescriptorParser.Configuration; import net.codecrete.usb.common.USBDeviceImpl; @@ -22,8 +21,6 @@ import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; -import java.util.ArrayList; -import java.util.List; import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.*; @@ -35,7 +32,6 @@ public class WindowsUSBDevice extends USBDeviceImpl { private MemoryAddress device; private MemoryAddress firstInterface; - private byte configurationValue; private Configuration configuration; WindowsUSBDevice(Object id, int vendorId, int productId, String manufacturer, String product, String serial, @@ -85,7 +81,6 @@ public void open() { private void readDescription(MemorySegment configDesc) { configuration = DescriptorParser.parseConfigurationDescriptor(configDesc, vendorId(), productId()); - configurationValue = configuration.configValue; setInterfaces(configuration.interfaces); } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java index 002d849a..828cb1a8 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java @@ -9,7 +9,6 @@ package net.codecrete.usb; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.util.List; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java index d0e5d54d..b9c116bd 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java @@ -16,19 +16,13 @@ public class InvalidOperationTest extends TestDeviceBase { @Test void claimInvalidInterface_throws() { - Assertions.assertThrows(USBException.class, () -> { - testDevice.claimInterface(1); - }); - Assertions.assertThrows(USBException.class, () -> { - testDevice.claimInterface(888); - }); + Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(1)); + Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(888)); } @Test void releaseInvalidInterface_throws() { - Assertions.assertThrows(USBException.class, () -> { - testDevice.releaseInterface(1); - }); + Assertions.assertThrows(USBException.class, () -> testDevice.releaseInterface(1)); } @@ -36,28 +30,16 @@ void releaseInvalidInterface_throws() { void invalidEndpoint_throws() { var data = new byte[] { 34, 23, 99, 0, 17 }; - Assertions.assertThrows(USBException.class, () -> { - testDevice.transferOut(2, data); - }); + Assertions.assertThrows(USBException.class, () -> testDevice.transferOut(2, data)); - Assertions.assertThrows(USBException.class, () -> { - testDevice.transferOut(0, data); - }); + Assertions.assertThrows(USBException.class, () -> testDevice.transferOut(0, data)); - Assertions.assertThrows(USBException.class, () -> { - testDevice.transferOut(3, data); - }); + Assertions.assertThrows(USBException.class, () -> testDevice.transferOut(3, data)); - Assertions.assertThrows(USBException.class, () -> { - testDevice.transferIn(1, 64); - }); + Assertions.assertThrows(USBException.class, () -> testDevice.transferIn(1, 64)); - Assertions.assertThrows(USBException.class, () -> { - testDevice.transferIn(0, 64); - }); + Assertions.assertThrows(USBException.class, () -> testDevice.transferIn(0, 64)); - Assertions.assertThrows(USBException.class, () -> { - testDevice.transferIn(4, 64); - }); + Assertions.assertThrows(USBException.class, () -> testDevice.transferIn(4, 64)); } } From 44c478c86549ab7092e4b5d386190b06ed9ae16f Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 4 Sep 2022 10:12:49 +0200 Subject: [PATCH 051/433] Linux: device class codes --- .../net/codecrete/usb/linux/LinuxUSBDevice.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 3c6af1f3..297616ff 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -11,6 +11,7 @@ import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBException; import net.codecrete.usb.common.DescriptorParser; +import net.codecrete.usb.common.USBDescriptors; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.linux.gen.fcntl.fcntl; import net.codecrete.usb.linux.gen.ioctl.ioctl; @@ -44,11 +45,24 @@ private void loadDescription(String path) { throw new USBException("Cannot read configuration descriptor", e); } + // the read bytes contain the device descriptor and the configuration descriptor + // (including the interface descriptors, endpoint descriptors etc.) + try (var session = MemorySession.openConfined()) { var descriptorsSegment = MemorySegment.ofArray(descriptors); + + // isolate device descriptor (copy descriptor to fix alignment issues) + var deviceDesc = session.allocate(USBDescriptors.Device$Struct); + deviceDesc.copyFrom(descriptorsSegment.asSlice(0, USBDescriptors.Device$Struct.byteSize())); + + int classCode = 255 & (byte) USBDescriptors.Device_bDeviceClass.get(deviceDesc); + int subclassCode = 255 & (byte) USBDescriptors.Device_bDeviceSubClass.get(deviceDesc); + int protocolCode = 255 & (byte) USBDescriptors.Device_bDeviceProtocol.get(deviceDesc); + setClassCodes(classCode, subclassCode, protocolCode); + // skip device descriptor var configDesc = session.allocateArray(JAVA_BYTE, descriptors.length - 18); - configDesc.copyFrom(descriptorsSegment.asSlice(18)); + configDesc.copyFrom(descriptorsSegment.asSlice(USBDescriptors.Device$Struct.byteSize())); var configuration = DescriptorParser.parseConfigurationDescriptor(configDesc, vendorId(), productId()); setInterfaces(configuration.interfaces); } From 5e5a53e5aad372633c5c91590d6ab90917494dda Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 4 Sep 2022 10:36:23 +0200 Subject: [PATCH 052/433] Linux: manage state of interfaces --- .../codecrete/usb/common/USBDeviceImpl.java | 11 ++++ .../codecrete/usb/linux/LinuxUSBDevice.java | 52 ++++++++++++++----- .../codecrete/usb/InvalidOperationTest.java | 4 ++ 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 48cf071c..f508df78 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -138,6 +138,17 @@ public void setClaimed(int interfaceNumber, boolean claimed) { throw new USBException("Internal error (interface not found)"); } + /** + * Returns the interface with the specified number. + * + * @param interfaceNumber the interface number + * @return the interface + */ + protected USBInterfaceImpl getInterface(int interfaceNumber) { + return (USBInterfaceImpl) interfaces_.stream() + .filter((intf) -> intf.number() == interfaceNumber).findFirst().orElse(null); + } + /** * Checks if the specified endpoint is valid for communication and returns the endpoint address. * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 297616ff..e854cae5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -13,6 +13,7 @@ import net.codecrete.usb.common.DescriptorParser; import net.codecrete.usb.common.USBDescriptors; import net.codecrete.usb.common.USBDeviceImpl; +import net.codecrete.usb.common.USBInterfaceImpl; import net.codecrete.usb.linux.gen.fcntl.fcntl; import net.codecrete.usb.linux.gen.ioctl.ioctl; import net.codecrete.usb.linux.gen.unistd.unistd; @@ -45,7 +46,7 @@ private void loadDescription(String path) { throw new USBException("Cannot read configuration descriptor", e); } - // the read bytes contain the device descriptor and the configuration descriptor + // `descriptors` contains the device descriptor followed by the configuration descriptor // (including the interface descriptors, endpoint descriptors etc.) try (var session = MemorySession.openConfined()) { @@ -75,7 +76,8 @@ public boolean isOpen() { @Override public void open() { - if (fd != -1) return; + if (isOpen()) + throw new USBException("the device is already open"); try (var session = MemorySession.openConfined()) { var pathUtf8 = session.allocateUtf8String(id_.toString()); @@ -86,21 +88,43 @@ public void open() { @Override public void close() { - if (fd == -1) return; + if (!isOpen()) + return; + + for (var intf : interfaces_) + ((USBInterfaceImpl) intf).setClaimed(false); unistd.close(fd); fd = -1; } public void claimInterface(int interfaceNumber) { + checkIsOpen(); + + var intf = getInterface(interfaceNumber); + if (intf == null) + throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); + if (intf.isClaimed()) + throw new USBException(String.format("Interface %d has already been claimed", interfaceNumber)); + try (var session = MemorySession.openConfined()) { var intfNumSegment = session.allocate(JAVA_INT, interfaceNumber); int ret = ioctl.ioctl(fd, USBDevFS.CLAIMINTERFACE, intfNumSegment.address()); - if (ret != 0) throw new USBException("Cannot claim USB interface", IO.getErrno()); + if (ret != 0) + throw new USBException("Cannot claim USB interface", IO.getErrno()); + setClaimed(interfaceNumber, true); } } public void releaseInterface(int interfaceNumber) { + checkIsOpen(); + + var intf = getInterface(interfaceNumber); + if (intf == null) + throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); + if (!intf.isClaimed()) + throw new USBException(String.format("Interface %d has not been claimed", interfaceNumber)); + try (var session = MemorySession.openConfined()) { var intfNumSegment = session.allocate(JAVA_INT, interfaceNumber); int ret = ioctl.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment.address()); @@ -129,7 +153,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { var ctrlTransfer = createCtrlTransfer(session, USBDirection.IN, setup, data); int res = ioctl.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer.address()); - if (res < 0) throw new USBException("Control IN transfer failed", res); + if (res < 0) throw new USBException("Control IN transfer failed", IO.getErrno()); return data.asSlice(0, res).toArray(JAVA_BYTE); } @@ -144,13 +168,13 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { var ctrlTransfer = createCtrlTransfer(session, USBDirection.OUT, setup, buffer); int res = ioctl.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer.address()); - if (res < 0) throw new USBException("Control OUT transfer failed", res); + if (res < 0) throw new USBException("Control OUT transfer failed", IO.getErrno()); } } - private MemorySegment createBulkTransfer(MemorySession session, int endpointAddress, MemorySegment data) { + private MemorySegment createBulkTransfer(MemorySession session, byte endpointAddress, MemorySegment data) { var transfer = session.allocate(usbdevfs_bulktransfer.$LAYOUT()); - usbdevfs_bulktransfer.ep$set(transfer, endpointAddress); + usbdevfs_bulktransfer.ep$set(transfer, 255 & endpointAddress); usbdevfs_bulktransfer.len$set(transfer, (int) data.byteSize()); usbdevfs_bulktransfer.data$set(transfer, data.address()); return transfer; @@ -158,27 +182,31 @@ private MemorySegment createBulkTransfer(MemorySession session, int endpointAddr @Override public void transferOut(int endpointNumber, byte[] data) { + var endpointAddress = getEndpointAddress(endpointNumber, USBDirection.OUT); + try (var session = MemorySession.openConfined()) { var buffer = session.allocate(data.length); buffer.copyFrom(MemorySegment.ofArray(data)); - var transfer = createBulkTransfer(session, endpointNumber, buffer); + var transfer = createBulkTransfer(session, endpointAddress, buffer); int res = ioctl.ioctl(fd, USBDevFS.BULK, transfer.address()); if (res < 0) - throw new USBException(String.format("USB OUT transfer on endpoint %d failed", endpointNumber), res); + throw new USBException(String.format("USB OUT transfer on endpoint %d failed", endpointNumber), IO.getErrno()); } } @Override public byte[] transferIn(int endpointNumber, int maxLength) { + var endpointAddress = getEndpointAddress(endpointNumber, USBDirection.IN); + try (var session = MemorySession.openConfined()) { var buffer = session.allocate(maxLength); - var transfer = createBulkTransfer(session, 0x80 | endpointNumber, buffer); + var transfer = createBulkTransfer(session, endpointAddress, buffer); int res = ioctl.ioctl(fd, USBDevFS.BULK, transfer.address()); if (res < 0) - throw new USBException(String.format("USB IN transfer on endpoint %d failed", endpointNumber), res); + throw new USBException(String.format("USB IN transfer on endpoint %d failed", endpointNumber), IO.getErrno()); return buffer.asSlice(0, res).toArray(JAVA_BYTE); } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java index b9c116bd..fcd5df47 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java @@ -16,7 +16,11 @@ public class InvalidOperationTest extends TestDeviceBase { @Test void claimInvalidInterface_throws() { + // throws error because it's already claimed + Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(0)); + // throws error because it's an invalid interface number Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(1)); + // throws error because it's an invalid interface number Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(888)); } From 8459e189f1c2100b4328494536ea8abdf9b2dc4e Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 4 Sep 2022 08:50:29 +0200 Subject: [PATCH 053/433] Unit tests for device lifecycle --- .../usb/windows/WindowsUSBDevice.java | 2 + .../codecrete/usb/DeviceLifecycleTest.java | 69 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 10ec84f5..7a431673 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -115,6 +115,8 @@ public void releaseInterface(int interfaceNumber) { var intf = configuration.findInterfaceByNumber(interfaceNumber); if (intf == null) + throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); + if (!intf.isClaimed()) throw new USBException(String.format("Interface %d has not been claimed", interfaceNumber)); setClaimed(interfaceNumber, false); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java new file mode 100644 index 00000000..9c2185b1 --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java @@ -0,0 +1,69 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Unit test for bulk transfer +// + +package net.codecrete.usb; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class DeviceLifecycleTest { + + private USBDevice device; + + @Test + void lifecycle_showsValidState() { + device = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); + if (device == null) + throw new IllegalStateException("USB loopback test device must be connected"); + + var intf = device.interfaces().get(0); + assertEquals(0, intf.number()); + + assertFalse(device.isOpen()); + assertFalse(intf.isClaimed()); + assertThrows(USBException.class, () -> device.claimInterface(0)); + assertThrows(USBException.class, () -> device.releaseInterface(0)); + + device.open(); + + assertTrue(device.isOpen()); + assertFalse(intf.isClaimed()); + assertThrows(USBException.class, () -> device.open()); + assertThrows(USBException.class, () -> device.releaseInterface(0)); + + device.claimInterface(0); + + assertTrue(device.isOpen()); + assertTrue(intf.isClaimed()); + assertThrows(USBException.class, () -> device.open()); + assertThrows(USBException.class, () -> device.claimInterface(0)); + + device.releaseInterface(0); + + assertTrue(device.isOpen()); + assertFalse(intf.isClaimed()); + assertThrows(USBException.class, () -> device.open()); + assertThrows(USBException.class, () -> device.releaseInterface(0)); + + device.close(); + + assertFalse(device.isOpen()); + assertFalse(intf.isClaimed()); + assertThrows(USBException.class, () -> device.claimInterface(0)); + assertThrows(USBException.class, () -> device.releaseInterface(0)); + } + + @AfterEach + void cleanup() { + if (device != null) + device.close(); + } +} From 5a1b74a1c4e27fef75673a78fc7b293c3ed1b53d Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 4 Sep 2022 08:56:01 +0200 Subject: [PATCH 054/433] Windows: Use interface collection of superclass --- .../java/net/codecrete/usb/windows/WindowsUSBDevice.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 7a431673..7d904482 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -11,7 +11,6 @@ import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBException; import net.codecrete.usb.common.DescriptorParser; -import net.codecrete.usb.common.DescriptorParser.Configuration; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.common.USBInterfaceImpl; import net.codecrete.usb.common.USBStructs; @@ -32,7 +31,6 @@ public class WindowsUSBDevice extends USBDeviceImpl { private MemoryAddress device; private MemoryAddress firstInterface; - private Configuration configuration; WindowsUSBDevice(Object id, int vendorId, int productId, String manufacturer, String product, String serial, MemorySegment configDesc) { @@ -80,7 +78,7 @@ public void open() { } private void readDescription(MemorySegment configDesc) { - configuration = DescriptorParser.parseConfigurationDescriptor(configDesc, vendorId(), productId()); + var configuration = DescriptorParser.parseConfigurationDescriptor(configDesc, vendorId(), productId()); setInterfaces(configuration.interfaces); } @@ -101,7 +99,7 @@ public void close() { public void claimInterface(int interfaceNumber) { checkIsOpen(); - var intf = configuration.findInterfaceByNumber(interfaceNumber); + var intf = getInterface(interfaceNumber); if (intf == null) throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); if (intf.isClaimed()) @@ -113,7 +111,7 @@ public void claimInterface(int interfaceNumber) { public void releaseInterface(int interfaceNumber) { checkIsOpen(); - var intf = configuration.findInterfaceByNumber(interfaceNumber); + var intf = getInterface(interfaceNumber); if (intf == null) throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); if (!intf.isClaimed()) From 0ed3475bbff4495d67b8c47a09f77772c722208a Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sun, 4 Sep 2022 13:34:07 +0200 Subject: [PATCH 055/433] macOS: fix interface state bug --- .../src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index e3924370..7586e43c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -73,6 +73,7 @@ public void close() { for (InterfaceInfo interfaceInfo : claimedInterfaces) { IoKitUSB.USBInterfaceClose(interfaceInfo.asAddress()); IoKit.Release(interfaceInfo.asAddress()); + setClaimed(interfaceInfo.interfaceNumber, false); } claimedInterfaces = null; From a2ab84309c045921c85c3dbbb5f33492b57700ed Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sun, 4 Sep 2022 13:45:17 +0200 Subject: [PATCH 056/433] Improve code formatting --- .../src/main/java/net/codecrete/usb/USB.java | 9 +- .../net/codecrete/usb/USBControlTransfer.java | 4 +- .../net/codecrete/usb/USBDeviceFilter.java | 3 +- .../usb/common/DescriptorParser.java | 26 +- .../codecrete/usb/common/USBDescriptors.java | 83 ++-- .../codecrete/usb/common/USBDeviceImpl.java | 23 +- .../usb/common/USBDeviceRegistry.java | 15 +- .../net/codecrete/usb/common/USBStructs.java | 10 +- .../codecrete/usb/linux/LinuxUSBDevice.java | 21 +- .../usb/linux/LinuxUSBDeviceRegistry.java | 29 +- .../java/net/codecrete/usb/macos/IoKit.java | 209 ++++---- .../net/codecrete/usb/macos/IoKitHelper.java | 12 +- .../net/codecrete/usb/macos/IoKitUSB.java | 445 +++++++++++------- .../usb/macos/MacosUSBDeviceRegistry.java | 14 +- .../codecrete/usb/windows/DeviceProperty.java | 52 +- .../net/codecrete/usb/windows/USBHelper.java | 67 ++- .../java/net/codecrete/usb/windows/Win.java | 15 +- .../usb/windows/WindowsUSBDeviceRegistry.java | 58 +-- 18 files changed, 595 insertions(+), 500 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USB.java b/java-does-usb/src/main/java/net/codecrete/usb/USB.java index 1e8e4e97..d39007c0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USB.java @@ -33,8 +33,7 @@ private static USBDeviceRegistry createInstance() { } else if (osName.equals("Linux") && (osArch.equals("amd64") || osArch.equals("aarch64"))) { impl = new LinuxUSBDeviceRegistry(); } else { - throw new UnsupportedOperationException(String.format("JavaCanDoUsb is not implemented for architecture " + - "%s/%s", osName, osArch)); + throw new UnsupportedOperationException(String.format("JavaCanDoUsb is not implemented for architecture " + "%s/%s", osName, osArch)); } return impl; } @@ -84,8 +83,7 @@ public static List getDevices(USBDeviceFilter filter) { * @return list of USB devices */ public static List getDevices(List filters) { - return instance().getAllDevices().stream().filter(dev -> USBDeviceFilter.matchesAny(dev, filters)) - .collect(Collectors.toList()); + return instance().getAllDevices().stream().filter(dev -> USBDeviceFilter.matchesAny(dev, filters)).collect(Collectors.toList()); } /** @@ -105,8 +103,7 @@ public static USBDevice getDevice(USBDeviceFilter filter) { * @return USB device, or {@code null} if no device matches */ public static USBDevice getDevice(List filters) { - return instance().getAllDevices().stream().filter(dev -> USBDeviceFilter.matchesAny(dev, filters)) - .findFirst().orElse(null); + return instance().getAllDevices().stream().filter(dev -> USBDeviceFilter.matchesAny(dev, filters)).findFirst().orElse(null); } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java index 7d2c26b3..bd382ec7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java @@ -19,6 +19,6 @@ * @param value value * @param index index */ -public record USBControlTransfer(USBRequestType requestType, USBRecipient recipient, - byte request, short value, short index) { +public record USBControlTransfer(USBRequestType requestType, USBRecipient recipient, byte request, short value, + short index) { } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java index c4599418..b7f784d0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java @@ -188,7 +188,8 @@ public boolean matches(USBDevice device) { /** * Test if the USB devices matches any of the filter conditions. - * @param device the USB device + * + * @param device the USB device * @param filters a list of filter conditions * @return {@code true} if it matches, {@code false} otherwise */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java index 9de876ad..f6f7ab6c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java @@ -54,20 +54,17 @@ public static Configuration parseConfigurationDescriptor(MemorySegment desc, int } else //noinspection StatementWithEmptyBody if (descType == USBDescriptors.INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE) { - // TODO: interface associations + // TODO: interface associations - } else //noinspection StatementWithEmptyBody - if (descType == USBDescriptors.HID_DESCRIPTOR_TYPE - || descType == USBDescriptors.CS_INTERFACE_DESCRIPTOR_TYPE - || descType == USBDescriptors.CS_ENDPOINT_DESCRIPTOR_TYPE) { - // known descriptor but not relevant - - } else { - // TODO: Remove warning once the relevant descriptors are processed - System.err.printf( - "Info: [JavaDoesUSB] unsupported USB descriptor type 0x%02x of device 0x%04x/0x%04x - ignoring descriptor%n", - descType, vendorID, productID); - } + } else //noinspection StatementWithEmptyBody + if (descType == USBDescriptors.HID_DESCRIPTOR_TYPE || descType == USBDescriptors.CS_INTERFACE_DESCRIPTOR_TYPE || descType == USBDescriptors.CS_ENDPOINT_DESCRIPTOR_TYPE) { + // known descriptor but not relevant + + } else { + // TODO: Remove warning once the relevant descriptors are processed + System.err.printf("Info: [JavaDoesUSB] unsupported USB descriptor type 0x%02x of device " + + "0x%04x/0x%04x - ignoring descriptor%n", descType, vendorID, productID); + } offset += descLength; } @@ -164,8 +161,7 @@ void addInterface(USBInterface intf) { } public USBInterfaceImpl findInterfaceByNumber(int number) { - return (USBInterfaceImpl) interfaces.stream() - .filter((intf) -> intf.number() == number).findFirst().orElse(null); + return (USBInterfaceImpl) interfaces.stream().filter((intf) -> intf.number() == number).findFirst().orElse(null); } } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java index 145095d9..ea8d5d45 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java @@ -59,22 +59,12 @@ public class USBDescriptors { // UCHAR iSerialNumber; // UCHAR bNumConfigurations; //} __attribute__((packed)); - public static final GroupLayout Device$Struct = structLayout( - JAVA_BYTE.withName("bLength"), - JAVA_BYTE.withName("bDescriptorType"), - JAVA_SHORT.withName("bcdUSB"), - JAVA_BYTE.withName("bDeviceClass"), - JAVA_BYTE.withName("bDeviceSubClass"), - JAVA_BYTE.withName("bDeviceProtocol"), - JAVA_BYTE.withName("bMaxPacketSize0"), - JAVA_SHORT.withName("idVendor"), - JAVA_SHORT.withName("idProduct"), - JAVA_SHORT.withName("bcdDevice"), - JAVA_BYTE.withName("iManufacturer"), - JAVA_BYTE.withName("iProduct"), - JAVA_BYTE.withName("iSerialNumber"), - JAVA_BYTE.withName("bNumConfigurations") - ); + public static final GroupLayout Device$Struct = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( + "bDescriptorType"), JAVA_SHORT.withName("bcdUSB"), JAVA_BYTE.withName("bDeviceClass"), + JAVA_BYTE.withName("bDeviceSubClass"), JAVA_BYTE.withName("bDeviceProtocol"), JAVA_BYTE.withName( + "bMaxPacketSize0"), JAVA_SHORT.withName("idVendor"), JAVA_SHORT.withName("idProduct"), + JAVA_SHORT.withName("bcdDevice"), JAVA_BYTE.withName("iManufacturer"), JAVA_BYTE.withName("iProduct"), + JAVA_BYTE.withName("iSerialNumber"), JAVA_BYTE.withName("bNumConfigurations")); public static final VarHandle Device_bDeviceClass = Device$Struct.varHandle(groupElement("bDeviceClass")); public static final VarHandle Device_bDeviceSubClass = Device$Struct.varHandle(groupElement("bDeviceSubClass")); @@ -84,7 +74,8 @@ public class USBDescriptors { public static final VarHandle Device_iManufacturer = Device$Struct.varHandle(groupElement("iManufacturer")); public static final VarHandle Device_iProduct = Device$Struct.varHandle(groupElement("iProduct")); public static final VarHandle Device_iSerialNumber = Device$Struct.varHandle(groupElement("iSerialNumber")); - public static final VarHandle Device_bNumConfigurations = Device$Struct.varHandle(groupElement("bNumConfigurations")); + public static final VarHandle Device_bNumConfigurations = Device$Struct.varHandle(groupElement( + "bNumConfigurations")); // struct USBConfigurationDescriptor //{ @@ -101,23 +92,21 @@ public class USBDescriptors { /** * USB configuration descriptor */ - public static final GroupLayout Configuration = structLayout( - JAVA_BYTE.withName("bLength"), - JAVA_BYTE.withName("bDescriptorType"), - JAVA_SHORT.withName("wTotalLength"), - JAVA_BYTE.withName("bNumInterfaces"), - JAVA_BYTE.withName("bConfigurationValue"), - JAVA_BYTE.withName("iConfiguration"), - JAVA_BYTE.withName("bmAttributes"), - JAVA_BYTE.withName("bMaxPower") - ); + public static final GroupLayout Configuration = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( + "bDescriptorType"), JAVA_SHORT.withName("wTotalLength"), JAVA_BYTE.withName("bNumInterfaces"), + JAVA_BYTE.withName("bConfigurationValue"), JAVA_BYTE.withName("iConfiguration"), JAVA_BYTE.withName( + "bmAttributes"), JAVA_BYTE.withName("bMaxPower")); public static final VarHandle Configuration_bLength = Configuration.varHandle(groupElement("bLength")); - public static final VarHandle Configuration_bDescriptorType = Configuration.varHandle(groupElement("bDescriptorType")); + public static final VarHandle Configuration_bDescriptorType = Configuration.varHandle(groupElement( + "bDescriptorType")); public static final VarHandle Configuration_wTotalLength = Configuration.varHandle(groupElement("wTotalLength")); - public static final VarHandle Configuration_bNumInterfaces = Configuration.varHandle(groupElement("bNumInterfaces")); - public static final VarHandle Configuration_bConfigurationValue = Configuration.varHandle(groupElement("bConfigurationValue")); - public static final VarHandle Configuration_iConfiguration = Configuration.varHandle(groupElement("iConfiguration")); + public static final VarHandle Configuration_bNumInterfaces = Configuration.varHandle(groupElement("bNumInterfaces" + )); + public static final VarHandle Configuration_bConfigurationValue = Configuration.varHandle(groupElement( + "bConfigurationValue")); + public static final VarHandle Configuration_iConfiguration = Configuration.varHandle(groupElement("iConfiguration" + )); public static final VarHandle Configuration_bmAttributes = Configuration.varHandle(groupElement("bmAttributes")); public static final VarHandle Configuration_bMaxPower = Configuration.varHandle(groupElement("bMaxPower")); @@ -134,17 +123,10 @@ public class USBDescriptors { // uint8_t iInterface; // } __attribute__((packed)); - public static final GroupLayout Interface = structLayout( - JAVA_BYTE.withName("bLength"), - JAVA_BYTE.withName("bDescriptorType"), - JAVA_BYTE.withName("bInterfaceNumber"), - JAVA_BYTE.withName("bAlternateSetting"), - JAVA_BYTE.withName("bNumEndpoints"), - JAVA_BYTE.withName("bInterfaceClass"), - JAVA_BYTE.withName("bInterfaceSubClass"), - JAVA_BYTE.withName("bInterfaceProtocol"), - JAVA_BYTE.withName("iInterface") - ); + public static final GroupLayout Interface = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( + "bDescriptorType"), JAVA_BYTE.withName("bInterfaceNumber"), JAVA_BYTE.withName("bAlternateSetting"), + JAVA_BYTE.withName("bNumEndpoints"), JAVA_BYTE.withName("bInterfaceClass"), JAVA_BYTE.withName( + "bInterfaceSubClass"), JAVA_BYTE.withName("bInterfaceProtocol"), JAVA_BYTE.withName("iInterface")); public static final VarHandle Interface_bLength = Interface.varHandle(groupElement("bLength")); public static final VarHandle Interface_bDescriptorType = Interface.varHandle(groupElement("bDescriptorType")); @@ -152,8 +134,10 @@ public class USBDescriptors { public static final VarHandle Interface_bAlternateSetting = Interface.varHandle(groupElement("bAlternateSetting")); public static final VarHandle Interface_bNumEndpoints = Interface.varHandle(groupElement("bNumEndpoints")); public static final VarHandle Interface_bInterfaceClass = Interface.varHandle(groupElement("bInterfaceClass")); - public static final VarHandle Interface_bInterfaceSubClass = Interface.varHandle(groupElement("bInterfaceSubClass")); - public static final VarHandle Interface_bInterfaceProtocol = Interface.varHandle(groupElement("bInterfaceProtocol")); + public static final VarHandle Interface_bInterfaceSubClass = Interface.varHandle(groupElement("bInterfaceSubClass" + )); + public static final VarHandle Interface_bInterfaceProtocol = Interface.varHandle(groupElement("bInterfaceProtocol" + )); public static final VarHandle Interface_iInterface = Interface.varHandle(groupElement("iInterface")); @@ -167,14 +151,9 @@ public class USBDescriptors { // uint8_t bInterval; // } __attribute__((packed)); - public static final GroupLayout Endpoint = structLayout( - JAVA_BYTE.withName("bLength"), - JAVA_BYTE.withName("bDescriptorType"), - JAVA_BYTE.withName("bEndpointAddress"), - JAVA_BYTE.withName("bmAttributes"), - JAVA_SHORT.withName("wMaxPacketSize").withBitAlignment(8), - JAVA_BYTE.withName("bInterval") - ); + public static final GroupLayout Endpoint = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( + "bDescriptorType"), JAVA_BYTE.withName("bEndpointAddress"), JAVA_BYTE.withName("bmAttributes"), + JAVA_SHORT.withName("wMaxPacketSize").withBitAlignment(8), JAVA_BYTE.withName("bInterval")); public static final VarHandle Endpoint_bLength = Endpoint.varHandle(groupElement("bLength")); public static final VarHandle Endpoint_bDescriptorType = Endpoint.varHandle(groupElement("bDescriptorType")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index f508df78..57608e49 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -131,7 +131,7 @@ public void setInterfaces(List interfaces) { public void setClaimed(int interfaceNumber, boolean claimed) { for (var intf : interfaces_) { if (intf.number() == interfaceNumber) { - ((USBInterfaceImpl)intf).setClaimed(claimed); + ((USBInterfaceImpl) intf).setClaimed(claimed); return; } } @@ -140,20 +140,19 @@ public void setClaimed(int interfaceNumber, boolean claimed) { /** * Returns the interface with the specified number. - * + * * @param interfaceNumber the interface number * @return the interface */ protected USBInterfaceImpl getInterface(int interfaceNumber) { - return (USBInterfaceImpl) interfaces_.stream() - .filter((intf) -> intf.number() == interfaceNumber).findFirst().orElse(null); + return (USBInterfaceImpl) interfaces_.stream().filter((intf) -> intf.number() == interfaceNumber).findFirst().orElse(null); } - + /** * Checks if the specified endpoint is valid for communication and returns the endpoint address. * * @param endpointNumber endpoint number (1 to 127) - * @param direction transfer direction + * @param direction transfer direction * @return endpoint address */ protected byte getEndpointAddress(int endpointNumber, USBDirection direction) { @@ -171,8 +170,7 @@ protected byte getEndpointAddress(int endpointNumber, USBDirection direction) { } } - throw new USBException(String.format("Endpoint number %d is not part of a claimed interface, the endpoint " + - "does not operate in the %s direction or is otherwise invalid", endpointNumber, direction.name())); + throw new USBException(String.format("Endpoint number %d is not part of a claimed interface, the endpoint " + "does not operate in the %s direction or is otherwise invalid", endpointNumber, direction.name())); } @Override @@ -190,8 +188,10 @@ protected byte getEndpointAddress(int endpointNumber, USBDirection direction) { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; USBDeviceImpl that = (USBDeviceImpl) o; return id_.equals(that.id_); } @@ -203,7 +203,6 @@ public int hashCode() { @Override public String toString() { - return "VID: 0x" + String.format("%04x", vendorId_) + ", PID: 0x" + String.format("%04x", productId_) + ", " + - "manufacturer: " + manufacturer_ + ", product: " + product_ + ", serial: " + serialNumber_ + ", ID: " + id_; + return "VID: 0x" + String.format("%04x", vendorId_) + ", PID: 0x" + String.format("%04x", productId_) + ", " + "manufacturer: " + manufacturer_ + ", product: " + product_ + ", serial: " + serialNumber_ + ", ID: " + id_; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index 08a592ea..a314be68 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -82,11 +82,13 @@ public void setOnDeviceDisconnected(Consumer handler) { } protected void emitOnDeviceConnected(USBDevice device) { - if (onDeviceConnectedHandler != null) onDeviceConnectedHandler.accept(device); + if (onDeviceConnectedHandler != null) + onDeviceConnectedHandler.accept(device); } protected void emitOnDeviceDisconnected(USBDevice device) { - if (onDeviceDisconnectedHandler != null) onDeviceDisconnectedHandler.accept(device); + if (onDeviceDisconnectedHandler != null) + onDeviceDisconnectedHandler.accept(device); } /** @@ -160,7 +162,8 @@ protected void setInitialDeviceList(List deviceList) { */ protected void addDevice(USBDevice device) { // check for duplicates - if (findDeviceIndex(devices, ((USBDeviceImpl) device).getUniqueId()) >= 0) return; + if (findDeviceIndex(devices, ((USBDeviceImpl) device).getUniqueId()) >= 0) + return; // copy list var newDeviceList = new ArrayList(devices.size() + 1); @@ -203,14 +206,16 @@ protected void removeDevice(Object deviceId) { protected int findDeviceIndex(List deviceList, Object deviceId) { for (int i = 0; i < deviceList.size(); i++) { var dev = (USBDeviceImpl) deviceList.get(i); - if (deviceId.equals(dev.getUniqueId())) return i; + if (deviceId.equals(dev.getUniqueId())) + return i; } return -1; } + /** * Finds the device with the given ID in the device list * - * @param deviceId the unique device ID + * @param deviceId the unique device ID * @return return device, or {@code null} if not found. */ protected USBDevice findDevice(Object deviceId) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBStructs.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBStructs.java index 6fbac84a..b98d3187 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBStructs.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBStructs.java @@ -19,13 +19,9 @@ public class USBStructs { // uint16_t Index; // uint16_t Length; //} __attribute__((packed)); - public static final GroupLayout SetupPacket$Struct = structLayout( - JAVA_BYTE.withName("bmRequest"), - JAVA_BYTE.withName("bRequest"), - JAVA_SHORT.withName("wValue"), - JAVA_SHORT.withName("wIndex"), - JAVA_SHORT.withName("wLength") - ); + public static final GroupLayout SetupPacket$Struct = structLayout(JAVA_BYTE.withName("bmRequest"), + JAVA_BYTE.withName("bRequest"), JAVA_SHORT.withName("wValue"), JAVA_SHORT.withName("wIndex"), + JAVA_SHORT.withName("wLength")); public static final VarHandle SetupPacket_bmRequest = SetupPacket$Struct.varHandle(groupElement("bmRequest")); public static final VarHandle SetupPacket_bRequest = SetupPacket$Struct.varHandle(groupElement("bRequest")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index e854cae5..b6f17195 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -82,7 +82,8 @@ public void open() { try (var session = MemorySession.openConfined()) { var pathUtf8 = session.allocateUtf8String(id_.toString()); fd = fcntl.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC()); - if (fd == -1) throw new USBException("Cannot open USB device", IO.getErrno()); + if (fd == -1) + throw new USBException("Cannot open USB device", IO.getErrno()); } } @@ -128,7 +129,8 @@ public void releaseInterface(int interfaceNumber) { try (var session = MemorySession.openConfined()) { var intfNumSegment = session.allocate(JAVA_INT, interfaceNumber); int ret = ioctl.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment.address()); - if (ret != 0) throw new USBException("Cannot release USB interface", IO.getErrno()); + if (ret != 0) + throw new USBException("Cannot release USB interface", IO.getErrno()); } } @@ -153,7 +155,8 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { var ctrlTransfer = createCtrlTransfer(session, USBDirection.IN, setup, data); int res = ioctl.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer.address()); - if (res < 0) throw new USBException("Control IN transfer failed", IO.getErrno()); + if (res < 0) + throw new USBException("Control IN transfer failed", IO.getErrno()); return data.asSlice(0, res).toArray(JAVA_BYTE); } @@ -164,11 +167,13 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { try (var session = MemorySession.openConfined()) { int dataLength = data != null ? data.length : 0; var buffer = session.allocate(dataLength); - if (dataLength != 0) buffer.copyFrom(MemorySegment.ofArray(data)); + if (dataLength != 0) + buffer.copyFrom(MemorySegment.ofArray(data)); var ctrlTransfer = createCtrlTransfer(session, USBDirection.OUT, setup, buffer); int res = ioctl.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer.address()); - if (res < 0) throw new USBException("Control OUT transfer failed", IO.getErrno()); + if (res < 0) + throw new USBException("Control OUT transfer failed", IO.getErrno()); } } @@ -191,7 +196,8 @@ public void transferOut(int endpointNumber, byte[] data) { int res = ioctl.ioctl(fd, USBDevFS.BULK, transfer.address()); if (res < 0) - throw new USBException(String.format("USB OUT transfer on endpoint %d failed", endpointNumber), IO.getErrno()); + throw new USBException(String.format("USB OUT transfer on endpoint %d failed", endpointNumber), + IO.getErrno()); } } @@ -206,7 +212,8 @@ public byte[] transferIn(int endpointNumber, int maxLength) { int res = ioctl.ioctl(fd, USBDevFS.BULK, transfer.address()); if (res < 0) - throw new USBException(String.format("USB IN transfer on endpoint %d failed", endpointNumber), IO.getErrno()); + throw new USBException(String.format("USB IN transfer on endpoint %d failed", endpointNumber), + IO.getErrno()); return buffer.asSlice(0, res).toArray(JAVA_BYTE); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index e2c5e5f5..18dcbd94 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -42,10 +42,12 @@ protected void monitorDevices() { try { // setup udev monitor var udevInstance = udev.udev_new(); - if (udevInstance == NULL) throw new USBException("internal error (udev_new)"); + if (udevInstance == NULL) + throw new USBException("internal error (udev_new)"); monitor = udev.udev_monitor_new_from_netlink(udevInstance, MONITOR_NAME); - if (monitor == NULL) throw new USBException("internal error (udev_monitor_new_from_netlink)"); + if (monitor == NULL) + throw new USBException("internal error (udev_monitor_new_from_netlink)"); if (udev.udev_monitor_filter_add_match_subsystem_devtype(monitor, SUBSYSTEM_USB, DEVTYPE_USB_DEVICE) < 0) throw new USBException("internal error (udev_monitor_filter_add_match_subsystem_devtype)"); @@ -54,7 +56,8 @@ protected void monitorDevices() { throw new USBException("internal error (udev_monitor_enable_receiving)"); fd = udev.udev_monitor_get_fd(monitor); - if (fd < 0) throw new USBException("internal error (udev_monitor_get_fd)"); + if (fd < 0) + throw new USBException("internal error (udev_monitor_get_fd)"); // create initial list of devices var deviceList = enumeratePresentDevices(udevInstance); @@ -75,7 +78,8 @@ protected void monitorDevices() { // retrieve change var udevDevice = udev.udev_monitor_receive_device(monitor); - if (udevDevice == null) continue; // shouldn't happen + if (udevDevice == null) + continue; // shouldn't happen session.addCloseAction(() -> udev.udev_device_unref(udevDevice)); @@ -97,7 +101,8 @@ private List enumeratePresentDevices(Addressable udevInstance) { // create device enumerator var enumerate = udev.udev_enumerate_new(udevInstance); - if (enumerate == NULL) throw new USBException("internal error (udev_enumerate_new)"); + if (enumerate == NULL) + throw new USBException("internal error (udev_enumerate_new)"); outerSession.addCloseAction(() -> udev.udev_enumerate_unref(enumerate)); @@ -146,7 +151,8 @@ private void onDeviceConnected(MemoryAddress udevDevice) { private void onDeviceDisconnected(MemoryAddress udevDevice) { var devPath = getDeviceName(udevDevice); - if (devPath == null) return; + if (devPath == null) + return; removeDevice(devPath); } @@ -189,9 +195,8 @@ private static USBDevice getDeviceDetails(MemoryAddress udevDevice) { getDeviceAttribute(udevDevice, "product"), getDeviceAttribute(udevDevice, "serial")); } catch (Throwable e) { - System.err.printf( - "Info: [JavaDoesUSB] failed to retrieve information about device 0x%04x/0x%04x - ignoring device%n", - vendorId, productId); + System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device 0x%04x/0x%04x - " + + "ignoring device%n", vendorId, productId); e.printStackTrace(System.err); return null; } @@ -201,7 +206,8 @@ private static String getDeviceAttribute(Addressable udevDevice, String attribut try (var session = MemorySession.openConfined()) { var sysattr = session.allocateUtf8String(attribute); var valueAddr = udev.udev_device_get_sysattr_value(udevDevice, sysattr); - if (valueAddr == NULL) return null; + if (valueAddr == NULL) + return null; var value = MemorySegment.ofAddress(valueAddr, 2000, session); return value.getUtf8String(0); @@ -228,6 +234,7 @@ private static void waitForFileDescriptor(int fd, MemorySession session) { fds.set(JAVA_LONG, fd / JAVA_LONG.bitSize(), 1L << (fd % JAVA_LONG.bitSize())); int res = select.select(fd + 1, fds, NULL, NULL, NULL); - if (res <= 0) throw new USBException("internal error (select)"); + if (res <= 0) + throw new USBException("internal error (select)"); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java index 55718b65..1c284ac9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java @@ -34,31 +34,37 @@ public class IoKit { public static final int kIORegistryIterateRecursively = 1; public static final MemorySegment kIOUSBDeviceClassName = ioKitSession.allocateUtf8String("IOUSBDevice"); - public static final MemorySegment kIOFirstMatchNotification = ioKitSession.allocateUtf8String("IOServiceFirstMatch"); + public static final MemorySegment kIOFirstMatchNotification = ioKitSession.allocateUtf8String( + "IOServiceFirstMatch"); public static final MemorySegment kIOTerminatedNotification = ioKitSession.allocateUtf8String("IOServiceTerminate"); public static final MemoryAddress kCFRunLoopDefaultMode = createCFStringRef("kCFRunLoopDefaultMode"); - public static final GroupLayout IOCFPlugInInterface$Struct = MemoryLayout.structLayout( - ADDRESS.withName("_reserved"), // void *_reserved; - ADDRESS.withName("QueryInterface"), // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); + public static final GroupLayout IOCFPlugInInterface$Struct = MemoryLayout.structLayout(ADDRESS.withName( + "_reserved"), // void *_reserved; + ADDRESS.withName("QueryInterface"), // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, + // REFIID iid, LPVOID *ppv); ADDRESS.withName("AddRef"), // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); ADDRESS.withName("Release"), // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); JAVA_SHORT.withName("version"), // UInt16 version; JAVA_SHORT.withName("revision"), // UInt16 revision; - ADDRESS.withName("Probe"), // IOReturn (*Probe)(void *thisPointer, CFDictionaryRef propertyTable, io_service_t service, SInt32 * order); - ADDRESS.withName("Start"), // IOReturn (*Start)(void *thisPointer, CFDictionaryRef propertyTable, io_service_t service); + ADDRESS.withName("Probe"), // IOReturn (*Probe)(void *thisPointer, CFDictionaryRef propertyTable, + // io_service_t service, SInt32 * order); + ADDRESS.withName("Start"), // IOReturn (*Start)(void *thisPointer, CFDictionaryRef propertyTable, + // io_service_t service); ADDRESS.withName("Stop") // IOReturn (*Stop)(void *thisPointer); ); /** * Looks up the address of the specified virtual function in the {@code IOCFPlugInInterface} object + * * @param thisPointer pointer to pointer to object - * @param varHandle variable handle to virtual function - * @param session memory session + * @param varHandle variable handle to virtual function + * @param session memory session * @return function address */ - private static Addressable IOCFPlugInInterfaceFunctionAddress(MemoryAddress thisPointer, VarHandle varHandle, MemorySession session) { + private static Addressable IOCFPlugInInterfaceFunctionAddress(MemoryAddress thisPointer, VarHandle varHandle, + MemorySession session) { var seg = MemorySegment.ofAddress(thisPointer, ADDRESS.byteSize(), session); var thisValue = seg.get(ADDRESS, 0); var obj = MemorySegment.ofAddress(thisValue, IOCFPlugInInterface$Struct.byteSize(), session); @@ -66,10 +72,11 @@ private static Addressable IOCFPlugInInterfaceFunctionAddress(MemoryAddress this } // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); - private static final VarHandle IUnknown_QueryInterface = IOCFPlugInInterface$Struct.varHandle(groupElement("QueryInterface")); - private static final MethodHandle QueryInterface$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, CFUUIDBytes, ADDRESS) - ); + private static final VarHandle IUnknown_QueryInterface = IOCFPlugInInterface$Struct.varHandle(groupElement( + "QueryInterface")); + private static final MethodHandle QueryInterface$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, + ADDRESS, CFUUIDBytes, ADDRESS)); + public static int QueryInterface(MemoryAddress thisPointer, MemorySegment iid, Addressable ppv) { try (var session = MemorySession.openShared()) { var funcPtr = IOCFPlugInInterfaceFunctionAddress(thisPointer, IUnknown_QueryInterface, session); @@ -81,9 +88,8 @@ public static int QueryInterface(MemoryAddress thisPointer, MemorySegment iid, A // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); private static final VarHandle IUnknown_AddRef = IOCFPlugInInterface$Struct.varHandle(groupElement("AddRef")); - private static final MethodHandle AddRef$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS) - ); + private static final MethodHandle AddRef$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, ADDRESS)); + public static int AddRef(MemoryAddress thisPointer) { try (var session = MemorySession.openShared()) { var funcPtr = IOCFPlugInInterfaceFunctionAddress(thisPointer, IUnknown_AddRef, session); @@ -95,9 +101,8 @@ public static int AddRef(MemoryAddress thisPointer) { // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); private static final VarHandle IUnknown_Release = IOCFPlugInInterface$Struct.varHandle(groupElement("Release")); - private static final MethodHandle Release$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS) - ); + private static final MethodHandle Release$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, ADDRESS)); + public static int Release(MemoryAddress thisPointer) { try (var session = MemorySession.openShared()) { var funcPtr = IOCFPlugInInterfaceFunctionAddress(thisPointer, IUnknown_Release, session); @@ -108,10 +113,9 @@ public static int Release(MemoryAddress thisPointer) { } // kern_return_t IOObjectRelease(io_object_t object); - private static final MethodHandle IOObjectRelease$Func = linker.downcallHandle( - ioKitLookup.lookup("IOObjectRelease").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT) - ); + private static final MethodHandle IOObjectRelease$Func = linker.downcallHandle(ioKitLookup.lookup( + "IOObjectRelease").get(), FunctionDescriptor.of(JAVA_INT, JAVA_INT)); + public static int IOObjectRelease(int object) { try { return (int) IOObjectRelease$Func.invokeExact(object); @@ -121,10 +125,10 @@ public static int IOObjectRelease(int object) { } // io_object_t IOIteratorNext(io_iterator_t iterator); - private static final MethodHandle IOIteratorNext$Func = linker.downcallHandle( - ioKitLookup.lookup("IOIteratorNext").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT) - ); + private static final MethodHandle IOIteratorNext$Func = + linker.downcallHandle(ioKitLookup.lookup("IOIteratorNext").get(), FunctionDescriptor.of(JAVA_INT, + JAVA_INT)); + public static int IOIteratorNext(int iter) { try { return (int) IOIteratorNext$Func.invokeExact(iter); @@ -133,28 +137,35 @@ public static int IOIteratorNext(int iter) { } } - // kern_return_t IOCreatePlugInInterfaceForService(io_service_t service, CFUUIDRef pluginType, CFUUIDRef interfaceType, IOCFPlugInInterface ***theInterface, SInt32 *theScore); - private static final MethodHandle IOCreatePlugInInterfaceForService$Func = linker.downcallHandle( - ioKitLookup.lookup("IOCreatePlugInInterfaceForService").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS) - ); - public static int IOCreatePlugInInterfaceForService(int service, Addressable pluginType, Addressable interfaceType, Addressable intf, Addressable score) { + // kern_return_t IOCreatePlugInInterfaceForService(io_service_t service, CFUUIDRef pluginType, CFUUIDRef + // interfaceType, IOCFPlugInInterface ***theInterface, SInt32 *theScore); + private static final MethodHandle IOCreatePlugInInterfaceForService$Func = + linker.downcallHandle(ioKitLookup.lookup("IOCreatePlugInInterfaceForService").get(), + FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS)); + + public static int IOCreatePlugInInterfaceForService(int service, Addressable pluginType, + Addressable interfaceType, Addressable intf, + Addressable score) { try { - return (int) IOCreatePlugInInterfaceForService$Func.invokeExact(service, pluginType, interfaceType, intf, score); + return (int) IOCreatePlugInInterfaceForService$Func.invokeExact(service, pluginType, interfaceType, intf, + score); } catch (Throwable e) { throw new RuntimeException(e); } } - // CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options); - private static final MethodHandle IORegistryEntryCreateCFProperty$Func = linker.downcallHandle( - ioKitLookup.lookup("IORegistryEntryCreateCFProperty").get(), - FunctionDescriptor.of(ADDRESS, JAVA_INT, ADDRESS, ADDRESS, JAVA_INT) - ); - public static MemoryAddress IORegistryEntryCreateCFProperty(int entry, String key, Addressable allocator, int options) { + // CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef + // allocator, IOOptionBits options); + private static final MethodHandle IORegistryEntryCreateCFProperty$Func = + linker.downcallHandle(ioKitLookup.lookup("IORegistryEntryCreateCFProperty").get(), + FunctionDescriptor.of(ADDRESS, JAVA_INT, ADDRESS, ADDRESS, JAVA_INT)); + + public static MemoryAddress IORegistryEntryCreateCFProperty(int entry, String key, Addressable allocator, + int options) { try { var keyStr = CoreFoundationHelper.createCFStringRef(key); - var propValue = (MemoryAddress) IORegistryEntryCreateCFProperty$Func.invokeExact(entry, (Addressable) keyStr, allocator, options); + var propValue = (MemoryAddress) IORegistryEntryCreateCFProperty$Func.invokeExact(entry, + (Addressable) keyStr, allocator, options); CoreFoundation.CFRelease(keyStr); return propValue; } catch (Throwable e) { @@ -163,10 +174,9 @@ public static MemoryAddress IORegistryEntryCreateCFProperty(int entry, String ke } // IONotificationPortRef IONotificationPortCreate(mach_port_t mainPort); - private static final MethodHandle IONotificationPortCreate$Func = linker.downcallHandle( - ioKitLookup.lookup("IONotificationPortCreate").get(), - FunctionDescriptor.of(ADDRESS, JAVA_INT) - ); + private static final MethodHandle IONotificationPortCreate$Func = linker.downcallHandle(ioKitLookup.lookup( + "IONotificationPortCreate").get(), FunctionDescriptor.of(ADDRESS, JAVA_INT)); + public static MemoryAddress IONotificationPortCreate(int mainPort) { try { return (MemoryAddress) IONotificationPortCreate$Func.invokeExact(mainPort); @@ -176,10 +186,10 @@ public static MemoryAddress IONotificationPortCreate(int mainPort) { } // CFRunLoopSourceRef IONotificationPortGetRunLoopSource(IONotificationPortRef notify); - private static final MethodHandle IONotificationPortGetRunLoopSource$Func = linker.downcallHandle( - ioKitLookup.lookup("IONotificationPortGetRunLoopSource").get(), - FunctionDescriptor.of(ADDRESS, ADDRESS) - ); + private static final MethodHandle IONotificationPortGetRunLoopSource$Func = + linker.downcallHandle(ioKitLookup.lookup("IONotificationPortGetRunLoopSource").get(), + FunctionDescriptor.of(ADDRESS, ADDRESS)); + public static MemoryAddress IONotificationPortGetRunLoopSource(Addressable notify) { try { return (MemoryAddress) IONotificationPortGetRunLoopSource$Func.invokeExact(notify); @@ -189,10 +199,9 @@ public static MemoryAddress IONotificationPortGetRunLoopSource(Addressable notif } // kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t *entryID); - private static final MethodHandle IORegistryEntryGetRegistryEntryID$Func = linker.downcallHandle( - ioKitLookup.lookup("IORegistryEntryGetRegistryEntryID").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS) - ); + private static final MethodHandle IORegistryEntryGetRegistryEntryID$Func = + linker.downcallHandle(ioKitLookup.lookup("IORegistryEntryGetRegistryEntryID").get(), + FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS)); public static int IORegistryEntryGetRegistryEntryID(int entry, Addressable entryIdHolder) { try { @@ -202,24 +211,28 @@ public static int IORegistryEntryGetRegistryEntryID(int entry, Addressable entry } } - // kern_return_t IOServiceAddMatchingNotification(IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void *refCon, io_iterator_t *notification); - private static final MethodHandle IOServiceAddMatchingNotification$Func = linker.downcallHandle( - ioKitLookup.lookup("IOServiceAddMatchingNotification").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS) - ); - public static int IOServiceAddMatchingNotification(Addressable notifyPort, Addressable notificationType, Addressable matching, Addressable callback, Addressable refCon, Addressable notificationHolder) { + // kern_return_t IOServiceAddMatchingNotification(IONotificationPortRef notifyPort, const io_name_t + // notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void *refCon, io_iterator_t + // *notification); + private static final MethodHandle IOServiceAddMatchingNotification$Func = + linker.downcallHandle(ioKitLookup.lookup("IOServiceAddMatchingNotification").get(), + FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS)); + + public static int IOServiceAddMatchingNotification(Addressable notifyPort, Addressable notificationType, + Addressable matching, Addressable callback, Addressable refCon + , Addressable notificationHolder) { try { - return (int) IOServiceAddMatchingNotification$Func.invokeExact(notifyPort, notificationType, matching, callback, refCon, notificationHolder); + return (int) IOServiceAddMatchingNotification$Func.invokeExact(notifyPort, notificationType, matching, + callback, refCon, notificationHolder); } catch (Throwable t) { throw new RuntimeException(t); } } // CFMutableDictionaryRef IOServiceMatching(const char *name); - private static final MethodHandle IOServiceMatching$Func = linker.downcallHandle( - ioKitLookup.lookup("IOServiceMatching").get(), - FunctionDescriptor.of(ADDRESS, ADDRESS) - ); + private static final MethodHandle IOServiceMatching$Func = linker.downcallHandle(ioKitLookup.lookup( + "IOServiceMatching").get(), FunctionDescriptor.of(ADDRESS, ADDRESS)); + public static MemoryAddress IOServiceMatching(Addressable name) { try { return (MemoryAddress) IOServiceMatching$Func.invokeExact(name); @@ -228,50 +241,30 @@ public static MemoryAddress IOServiceMatching(Addressable name) { } } - public static final MemoryAddress kIOUSBDeviceUserClientTypeID = CoreFoundation.CFUUIDCreateFromUUIDBytes( - NULL, - new byte[]{ - (byte) 0x9d, (byte) 0xc7, (byte) 0xb7, (byte) 0x80, - (byte) 0x9e, (byte) 0xc0, (byte) 0x11, (byte) 0xD4, - (byte) 0xa5, (byte) 0x4f, (byte) 0x00, (byte) 0x0a, - (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61 - }); - - public static final MemoryAddress kIOUSBInterfaceUserClientTypeID = CoreFoundation.CFUUIDCreateFromUUIDBytes( - NULL, - new byte[]{ - (byte) 0x2d, (byte) 0x97, (byte) 0x86, (byte) 0xc6, - (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, - (byte) 0xad, (byte) 0x51, (byte) 0x00, (byte) 0x0a, - (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61 - }); - - public static final MemoryAddress kIOUSBDeviceInterfaceID100 = CoreFoundation.CFUUIDCreateFromUUIDBytes( - NULL, - new byte[]{ - (byte) 0x5c, (byte) 0x81, (byte) 0x87, (byte) 0xd0, - (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, - (byte) 0x8b, (byte) 0x45, (byte) 0x00, (byte) 0x0a, - (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61 - }); - - public static final MemoryAddress kIOUSBInterfaceInterfaceID100 = CoreFoundation.CFUUIDCreateFromUUIDBytes( - NULL, - new byte[]{ - (byte) 0x73, (byte) 0xc9, (byte) 0x7a, (byte) 0xe8, - (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, - (byte) 0xb1, (byte) 0xd0, (byte) 0x00, (byte) 0x0a, - (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61 - }); - - public static final MemoryAddress kIOCFPlugInInterfaceID = CoreFoundation.CFUUIDCreateFromUUIDBytes( - NULL, - new byte[]{ - (byte) 0xC2, (byte) 0x44, (byte) 0xE8, (byte) 0x58, - (byte) 0x10, (byte) 0x9C, (byte) 0x11, (byte) 0xD4, - (byte) 0x91, (byte) 0xD4, (byte) 0x00, (byte) 0x50, - (byte) 0xE4, (byte) 0xC6, (byte) 0x42, (byte) 0x6F - }); + public static final MemoryAddress kIOUSBDeviceUserClientTypeID = CoreFoundation.CFUUIDCreateFromUUIDBytes(NULL, + new byte[]{(byte) 0x9d, (byte) 0xc7, (byte) 0xb7, (byte) 0x80, (byte) 0x9e, (byte) 0xc0, (byte) 0x11, + (byte) 0xD4, (byte) 0xa5, (byte) 0x4f, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, + (byte) 0x28, (byte) 0x61}); + + public static final MemoryAddress kIOUSBInterfaceUserClientTypeID = CoreFoundation.CFUUIDCreateFromUUIDBytes(NULL + , new byte[]{(byte) 0x2d, (byte) 0x97, (byte) 0x86, (byte) 0xc6, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, + (byte) 0xD4, (byte) 0xad, (byte) 0x51, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, + (byte) 0x28, (byte) 0x61}); + + public static final MemoryAddress kIOUSBDeviceInterfaceID100 = CoreFoundation.CFUUIDCreateFromUUIDBytes(NULL, + new byte[]{(byte) 0x5c, (byte) 0x81, (byte) 0x87, (byte) 0xd0, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, + (byte) 0xD4, (byte) 0x8b, (byte) 0x45, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, + (byte) 0x28, (byte) 0x61}); + + public static final MemoryAddress kIOUSBInterfaceInterfaceID100 = CoreFoundation.CFUUIDCreateFromUUIDBytes(NULL, + new byte[]{(byte) 0x73, (byte) 0xc9, (byte) 0x7a, (byte) 0xe8, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, + (byte) 0xD4, (byte) 0xb1, (byte) 0xd0, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, + (byte) 0x28, (byte) 0x61}); + + public static final MemoryAddress kIOCFPlugInInterfaceID = CoreFoundation.CFUUIDCreateFromUUIDBytes(NULL, + new byte[]{(byte) 0xC2, (byte) 0x44, (byte) 0xE8, (byte) 0x58, (byte) 0x10, (byte) 0x9C, (byte) 0x11, + (byte) 0xD4, (byte) 0x91, (byte) 0xD4, (byte) 0x00, (byte) 0x50, (byte) 0xE4, (byte) 0xC6, + (byte) 0x42, (byte) 0x6F}); static { try (var session = MemorySession.openConfined()) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index b88f5017..3f98fc41 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -43,7 +43,8 @@ public static MemoryAddress getInterface(int service, Addressable pluginType, Me var plugHolder = session.allocate(ADDRESS, NULL); // MemorySegment for holding score var score = session.allocate(JAVA_INT, 0); - int ret = IoKit.IOCreatePlugInInterfaceForService(service, pluginType, IoKit.kIOCFPlugInInterfaceID, plugHolder, score); + int ret = IoKit.IOCreatePlugInInterfaceForService(service, pluginType, IoKit.kIOCFPlugInInterfaceID, + plugHolder, score); if (ret != 0) return null; var plug = (MemoryAddress) plugHolder.get(ADDRESS, 0); @@ -51,7 +52,8 @@ public static MemoryAddress getInterface(int service, Addressable pluginType, Me // MemorySegment for holding xxxInterface** var intfHolder = session.allocate(ADDRESS, NULL); // UUID bytes - var refiid = MemorySegment.ofAddress(interfaceId.addOffset(CFUUID_bytes$Offset), CFUUIDBytes.byteSize(), session); + var refiid = MemorySegment.ofAddress(interfaceId.addOffset(CFUUID_bytes$Offset), CFUUIDBytes.byteSize(), + session); ret = IoKit.QueryInterface(plug, refiid, intfHolder); IoKit.Release(plug); if (ret != 0) @@ -65,8 +67,9 @@ public static MemoryAddress getInterface(int service, Addressable pluginType, Me *

* The property must be of numeric type. *

+ * * @param service the service - * @param key the property key + * @param key the property key * @return the property value, or {@code null} if the service doesn't have the property */ public static Integer getPropertyInt(int service, String key) { @@ -94,8 +97,9 @@ public static Integer getPropertyInt(int service, String key) { *

* The property must be of string type. *

+ * * @param service the service - * @param key the property key + * @param key the property key * @return the property value, or {@code null} if the service doesn't have the property */ public static String getPropertyString(int service, String key) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index a2e2a147..5eb4aba7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -32,25 +32,30 @@ public class IoKitUSB { // UInt16 bInterfaceProtocol; // requested protocol // UInt16 bAlternateSetting; // requested alt setting // } IOUSBFindInterfaceRequest; - public static final GroupLayout IOUSBFindInterfaceRequest$Struct = structLayout( - JAVA_SHORT.withName("bInterfaceClass"), - JAVA_SHORT.withName("bInterfaceSubClass"), - JAVA_SHORT.withName("bInterfaceProtocol"), - JAVA_SHORT.withName("bAlternateSetting") - ); - public static final VarHandle IOUSBFindInterfaceRequest_bInterfaceClass = IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bInterfaceClass")); - public static final VarHandle IOUSBFindInterfaceRequest_bInterfaceSubClass = IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bInterfaceSubClass")); - public static final VarHandle IOUSBFindInterfaceRequest_bInterfaceProtocol = IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bInterfaceProtocol")); - public static final VarHandle IOUSBFindInterfaceRequest_bAlternateSetting = IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bAlternateSetting")); - - private static final GroupLayout IOUSBDevice$Struct = structLayout( - ADDRESS.withName("_reserved"), // void *_reserved; - ADDRESS.withName("QueryInterface"), // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); + public static final GroupLayout IOUSBFindInterfaceRequest$Struct = structLayout(JAVA_SHORT.withName( + "bInterfaceClass"), JAVA_SHORT.withName("bInterfaceSubClass"), JAVA_SHORT.withName("bInterfaceProtocol"), + JAVA_SHORT.withName("bAlternateSetting")); + public static final VarHandle IOUSBFindInterfaceRequest_bInterfaceClass = + IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bInterfaceClass")); + public static final VarHandle IOUSBFindInterfaceRequest_bInterfaceSubClass = + IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bInterfaceSubClass")); + public static final VarHandle IOUSBFindInterfaceRequest_bInterfaceProtocol = + IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bInterfaceProtocol")); + public static final VarHandle IOUSBFindInterfaceRequest_bAlternateSetting = + IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bAlternateSetting")); + + private static final GroupLayout IOUSBDevice$Struct = structLayout(ADDRESS.withName("_reserved"), // void + // *_reserved; + ADDRESS.withName("QueryInterface"), // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, + // REFIID iid, LPVOID *ppv); ADDRESS.withName("AddRef"), // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); ADDRESS.withName("Release"), // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); - ADDRESS.withName("CreateDeviceAsyncEventSource"), // IOReturn (*CreateDeviceAsyncEventSource)(void *self, CFRunLoopSourceRef *source); - ADDRESS.withName("GetDeviceAsyncEventSource"), // CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void *self); - ADDRESS.withName("CreateDeviceAsyncPort"), // IOReturn (*CreateDeviceAsyncPort)(void *self, mach_port_t *port); + ADDRESS.withName("CreateDeviceAsyncEventSource"), // IOReturn (*CreateDeviceAsyncEventSource)(void *self, + // CFRunLoopSourceRef *source); + ADDRESS.withName("GetDeviceAsyncEventSource"), // CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void + // *self); + ADDRESS.withName("CreateDeviceAsyncPort"), // IOReturn (*CreateDeviceAsyncPort)(void *self, mach_port_t + // *port); ADDRESS.withName("GetDeviceAsyncPort"), // mach_port_t (*GetDeviceAsyncPort)(void *self); ADDRESS.withName("USBDeviceOpen"), // IOReturn (*USBDeviceOpen)(void *self); ADDRESS.withName("USBDeviceClose"), // IOReturn (*USBDeviceClose)(void *self); @@ -59,51 +64,76 @@ public class IoKitUSB { ADDRESS.withName("GetDeviceProtocol"), // IOReturn (*GetDeviceProtocol)(void *self, UInt8 *devProtocol); ADDRESS.withName("GetDeviceVendor"), // IOReturn (*GetDeviceVendor)(void *self, UInt16 *devVendor); ADDRESS.withName("GetDeviceProduct"), // IOReturn (*GetDeviceProduct)(void *self, UInt16 *devProduct); - ADDRESS.withName("GetDeviceReleaseNumber"), // IOReturn (*GetDeviceReleaseNumber)(void *self, UInt16 *devRelNum); + ADDRESS.withName("GetDeviceReleaseNumber"), // IOReturn (*GetDeviceReleaseNumber)(void *self, UInt16 + // *devRelNum); ADDRESS.withName("GetDeviceAddress"), // IOReturn (*GetDeviceAddress)(void *self, USBDeviceAddress *addr); - ADDRESS.withName("GetDeviceBusPowerAvailable"), // IOReturn (*GetDeviceBusPowerAvailable)(void *self, UInt32 *powerAvailable); + ADDRESS.withName("GetDeviceBusPowerAvailable"), // IOReturn (*GetDeviceBusPowerAvailable)(void *self, + // UInt32 *powerAvailable); ADDRESS.withName("GetDeviceSpeed"), // IOReturn (*GetDeviceSpeed)(void *self, UInt8 *devSpeed); - ADDRESS.withName("GetNumberOfConfigurations"), // IOReturn (*GetNumberOfConfigurations)(void *self, UInt8 *numConfig); + ADDRESS.withName("GetNumberOfConfigurations"), // IOReturn (*GetNumberOfConfigurations)(void *self, + // UInt8 *numConfig); ADDRESS.withName("GetLocationID"), // IOReturn (*GetLocationID)(void *self, UInt32 *locationID); - ADDRESS.withName("GetConfigurationDescriptorPtr"), // IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc); + ADDRESS.withName("GetConfigurationDescriptorPtr"), // IOReturn (*GetConfigurationDescriptorPtr)(void + // *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc); ADDRESS.withName("GetConfiguration"), // IOReturn (*GetConfiguration)(void *self, UInt8 *configNum); ADDRESS.withName("SetConfiguration"), // IOReturn (*SetConfiguration)(void *self, UInt8 configNum); - ADDRESS.withName("GetBusFrameNumber"), // IOReturn (*GetBusFrameNumber)(void *self, UInt64 *frame, AbsoluteTime *atTime); + ADDRESS.withName("GetBusFrameNumber"), // IOReturn (*GetBusFrameNumber)(void *self, UInt64 *frame, + // AbsoluteTime *atTime); ADDRESS.withName("ResetDevice"), // IOReturn (*ResetDevice)(void *self); ADDRESS.withName("DeviceRequest"), // IOReturn (*DeviceRequest)(void *self, IOUSBDevRequest *req); - ADDRESS.withName("DeviceRequestAsync"), // IOReturn (*DeviceRequestAsync)(void *self, IOUSBDevRequest *req, IOAsyncCallback1 callback, void *refCon); - ADDRESS.withName("CreateInterfaceIterator"), // IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter); + ADDRESS.withName("DeviceRequestAsync"), // IOReturn (*DeviceRequestAsync)(void *self, IOUSBDevRequest + // *req, IOAsyncCallback1 callback, void *refCon); + ADDRESS.withName("CreateInterfaceIterator"), // IOReturn (*CreateInterfaceIterator)(void *self, + // IOUSBFindInterfaceRequest *req, io_iterator_t *iter); ADDRESS.withName("USBDeviceOpenSeize"), // IOReturn (*USBDeviceOpenSeize)(void *self); ADDRESS.withName("DeviceRequestTO"), // IOReturn (*DeviceRequestTO)(void *self, IOUSBDevRequestTO *req); - ADDRESS.withName("DeviceRequestAsyncTO"), // IOReturn (*DeviceRequestAsyncTO)(void *self, IOUSBDevRequestTO *req, IOAsyncCallback1 callback, void *refCon); + ADDRESS.withName("DeviceRequestAsyncTO"), // IOReturn (*DeviceRequestAsyncTO)(void *self, + // IOUSBDevRequestTO *req, IOAsyncCallback1 callback, void *refCon); ADDRESS.withName("USBDeviceSuspend"), // IOReturn (*USBDeviceSuspend)(void *self, Boolean suspend); ADDRESS.withName("USBDeviceAbortPipeZero"), // IOReturn (*USBDeviceAbortPipeZero)(void *self); - ADDRESS.withName("USBGetManufacturerStringIndex"), // IOReturn (*USBGetManufacturerStringIndex)(void *self, UInt8 *msi); - ADDRESS.withName("USBGetProductStringIndex"), // IOReturn (*USBGetProductStringIndex)(void *self, UInt8 *psi); - ADDRESS.withName("USBGetSerialNumberStringIndex"), // IOReturn (*USBGetSerialNumberStringIndex)(void *self, UInt8 *snsi); + ADDRESS.withName("USBGetManufacturerStringIndex"), // IOReturn (*USBGetManufacturerStringIndex)(void + // *self, UInt8 *msi); + ADDRESS.withName("USBGetProductStringIndex"), // IOReturn (*USBGetProductStringIndex)(void *self, UInt8 + // *psi); + ADDRESS.withName("USBGetSerialNumberStringIndex"), // IOReturn (*USBGetSerialNumberStringIndex)(void + // *self, UInt8 *snsi); ADDRESS.withName("USBDeviceReEnumerate"), // IOReturn (*USBDeviceReEnumerate)(void *self, UInt32 options); - ADDRESS.withName("GetBusMicroFrameNumber"), // IOReturn (*GetBusMicroFrameNumber)(void *self, UInt64 *microFrame, AbsoluteTime *atTime); - ADDRESS.withName("GetIOUSBLibVersion"), // IOReturn (*GetIOUSBLibVersion)(void *self, NumVersion *ioUSBLibVersion, NumVersion *usbFamilyVersion); - ADDRESS.withName("GetBusFrameNumberWithTime"), // IOReturn (*GetBusFrameNumberWithTime)(void *self, UInt64 *frame, AbsoluteTime *atTime); - ADDRESS.withName("GetUSBDeviceInformation"), // IOReturn (*GetUSBDeviceInformation)(void *self, UInt32 *info); - ADDRESS.withName("RequestExtraPower"), // IOReturn (*RequestExtraPower)(void *self, UInt32 type, UInt32 requestedPower, UInt32 *powerAvailable); - ADDRESS.withName("ReturnExtraPower"), // IOReturn (*ReturnExtraPower)(void *self, UInt32 type, UInt32 powerReturned); - ADDRESS.withName("GetExtraPowerAllocated"), // IOReturn (*GetExtraPowerAllocated)(void *self, UInt32 type, UInt32 *powerAllocated); - ADDRESS.withName("GetBandwidthAvailableForDevice"), // IOReturn (*GetBandwidthAvailableForDevice)(void *self, UInt32 *bandwidth); - ADDRESS.withName("SetConfigurationV2"), // IOReturn (*SetConfigurationV2)(void *self, UInt8 configNum, bool startInterfaceMatching, bool issueRemoteWakeup); - ADDRESS.withName("RegisterForNotification"), // IOReturn (*RegisterForNotification)(void * self, UInt64 notificationMask, IOAsyncCallback2 callback, void *refCon, UInt64 *pRegistrationToken); - ADDRESS.withName("UnregisterNotification"), // IOReturn (*UnregisterNotification)(void *self, UInt64 registrationToken); - ADDRESS.withName("AcknowledgeNotification") // IOReturn (*AcknowledgeNotification)(void *self, UInt64 notificationToken); + ADDRESS.withName("GetBusMicroFrameNumber"), // IOReturn (*GetBusMicroFrameNumber)(void *self, UInt64 + // *microFrame, AbsoluteTime *atTime); + ADDRESS.withName("GetIOUSBLibVersion"), // IOReturn (*GetIOUSBLibVersion)(void *self, NumVersion + // *ioUSBLibVersion, NumVersion *usbFamilyVersion); + ADDRESS.withName("GetBusFrameNumberWithTime"), // IOReturn (*GetBusFrameNumberWithTime)(void *self, + // UInt64 *frame, AbsoluteTime *atTime); + ADDRESS.withName("GetUSBDeviceInformation"), // IOReturn (*GetUSBDeviceInformation)(void *self, UInt32 + // *info); + ADDRESS.withName("RequestExtraPower"), // IOReturn (*RequestExtraPower)(void *self, UInt32 type, UInt32 + // requestedPower, UInt32 *powerAvailable); + ADDRESS.withName("ReturnExtraPower"), // IOReturn (*ReturnExtraPower)(void *self, UInt32 type, UInt32 + // powerReturned); + ADDRESS.withName("GetExtraPowerAllocated"), // IOReturn (*GetExtraPowerAllocated)(void *self, UInt32 + // type, UInt32 *powerAllocated); + ADDRESS.withName("GetBandwidthAvailableForDevice"), // IOReturn (*GetBandwidthAvailableForDevice)(void + // *self, UInt32 *bandwidth); + ADDRESS.withName("SetConfigurationV2"), // IOReturn (*SetConfigurationV2)(void *self, UInt8 configNum, + // bool startInterfaceMatching, bool issueRemoteWakeup); + ADDRESS.withName("RegisterForNotification"), // IOReturn (*RegisterForNotification)(void * self, UInt64 + // notificationMask, IOAsyncCallback2 callback, void *refCon, UInt64 *pRegistrationToken); + ADDRESS.withName("UnregisterNotification"), // IOReturn (*UnregisterNotification)(void *self, UInt64 + // registrationToken); + ADDRESS.withName("AcknowledgeNotification") // IOReturn (*AcknowledgeNotification)(void *self, UInt64 + // notificationToken); ); /** * Looks up the address of the specified virtual function in the {@code IOUSBDevice} object + * * @param thisPointer pointer to pointer to object - * @param varHandle variable handle to virtual function - * @param session memory session + * @param varHandle variable handle to virtual function + * @param session memory session * @return function address */ - private static Addressable IOUSBDeviceFunctionAddress(MemoryAddress thisPointer, VarHandle varHandle, MemorySession session) { + private static Addressable IOUSBDeviceFunctionAddress(MemoryAddress thisPointer, VarHandle varHandle, + MemorySession session) { var seg = MemorySegment.ofAddress(thisPointer, ADDRESS.byteSize(), session); var thisValue = seg.get(ADDRESS, 0); var obj = MemorySegment.ofAddress(thisValue, IOUSBDevice$Struct.byteSize(), session); @@ -111,10 +141,11 @@ private static Addressable IOUSBDeviceFunctionAddress(MemoryAddress thisPointer, } // IOReturn (*USBDeviceOpen)(void *self); - private static final VarHandle IOUSBDevice_USBDeviceOpen = IOUSBDevice$Struct.varHandle(groupElement("USBDeviceOpen")); - private static final MethodHandle USBDeviceOpen$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS) - ); + private static final VarHandle IOUSBDevice_USBDeviceOpen = IOUSBDevice$Struct.varHandle(groupElement( + "USBDeviceOpen")); + private static final MethodHandle USBDeviceOpen$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, + ADDRESS)); + public static int USBDeviceOpen(MemoryAddress thisPointer) { try (var session = MemorySession.openShared()) { var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_USBDeviceOpen, session); @@ -125,10 +156,11 @@ public static int USBDeviceOpen(MemoryAddress thisPointer) { } // IOReturn (*USBDeviceClose)(void *self); - private static final VarHandle IOUSBDevice_USBDeviceClose = IOUSBDevice$Struct.varHandle(groupElement("USBDeviceClose")); - private static final MethodHandle USBDeviceClose$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS) - ); + private static final VarHandle IOUSBDevice_USBDeviceClose = IOUSBDevice$Struct.varHandle(groupElement( + "USBDeviceClose")); + private static final MethodHandle USBDeviceClose$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, + ADDRESS)); + public static int USBDeviceClose(MemoryAddress thisPointer) { try (var session = MemorySession.openShared()) { var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_USBDeviceClose, session); @@ -139,24 +171,28 @@ public static int USBDeviceClose(MemoryAddress thisPointer) { } // IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc); - private static final VarHandle IOUSBDevice_GetConfigurationDescriptorPtr = IOUSBDevice$Struct.varHandle(groupElement("GetConfigurationDescriptorPtr")); - private static final MethodHandle GetConfigurationDescriptorPtr$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS) - ); - public static int GetConfigurationDescriptorPtr(MemoryAddress thisPointer, byte configIndex, Addressable descHolder) { + private static final VarHandle IOUSBDevice_GetConfigurationDescriptorPtr = + IOUSBDevice$Struct.varHandle(groupElement("GetConfigurationDescriptorPtr")); + private static final MethodHandle GetConfigurationDescriptorPtr$Func = + linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS)); + + public static int GetConfigurationDescriptorPtr(MemoryAddress thisPointer, byte configIndex, + Addressable descHolder) { try (var session = MemorySession.openShared()) { var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_GetConfigurationDescriptorPtr, session); - return (int) GetConfigurationDescriptorPtr$Func.invokeExact(funcPtr, (Addressable) thisPointer, configIndex, descHolder); + return (int) GetConfigurationDescriptorPtr$Func.invokeExact(funcPtr, (Addressable) thisPointer, + configIndex, descHolder); } catch (Throwable e) { throw new RuntimeException(e); } } // IOReturn (*SetConfiguration)(void *self, UInt8 configNum); - private static final VarHandle IOUSBDevice_SetConfiguration = IOUSBDevice$Struct.varHandle(groupElement("SetConfiguration")); - private static final MethodHandle SetConfiguration$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE) - ); + private static final VarHandle IOUSBDevice_SetConfiguration = IOUSBDevice$Struct.varHandle(groupElement( + "SetConfiguration")); + private static final MethodHandle SetConfiguration$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, + ADDRESS, JAVA_BYTE)); + public static int SetConfiguration(MemoryAddress thisPointer, byte configValue) { try (var session = MemorySession.openShared()) { var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_SetConfiguration, session); @@ -167,10 +203,11 @@ public static int SetConfiguration(MemoryAddress thisPointer, byte configValue) } // IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter); - private static final VarHandle IOUSBDevice_CreateInterfaceIterator = IOUSBDevice$Struct.varHandle(groupElement("CreateInterfaceIterator")); - private static final MethodHandle CreateInterfaceIterator$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS) - ); + private static final VarHandle IOUSBDevice_CreateInterfaceIterator = IOUSBDevice$Struct.varHandle(groupElement( + "CreateInterfaceIterator")); + private static final MethodHandle CreateInterfaceIterator$Func = + linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS)); + public static int CreateInterfaceIterator(MemoryAddress thisPointer, Addressable req, Addressable iter) { try (var session = MemorySession.openShared()) { var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_CreateInterfaceIterator, session); @@ -181,10 +218,11 @@ public static int CreateInterfaceIterator(MemoryAddress thisPointer, Addressable } // IOReturn (*DeviceRequest)(void *self, IOUSBDevRequest *req); - private static final VarHandle IOUSBDevice_DeviceRequest = IOUSBDevice$Struct.varHandle(groupElement("DeviceRequest")); - private static final MethodHandle DeviceRequest$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS) - ); + private static final VarHandle IOUSBDevice_DeviceRequest = IOUSBDevice$Struct.varHandle(groupElement( + "DeviceRequest")); + private static final MethodHandle DeviceRequest$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, + ADDRESS, ADDRESS)); + public static int DeviceRequest(MemoryAddress thisPointer, Addressable deviceRequest) { try (var session = MemorySession.openShared()) { var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_DeviceRequest, session); @@ -194,91 +232,158 @@ public static int DeviceRequest(MemoryAddress thisPointer, Addressable deviceReq } } - private static final GroupLayout IOUSBInterface$Struct = structLayout( - ADDRESS.withName("_reserved"), // void *_reserved; - ADDRESS.withName("QueryInterface"), // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); + private static final GroupLayout IOUSBInterface$Struct = structLayout(ADDRESS.withName("_reserved"), // void + // *_reserved; + ADDRESS.withName("QueryInterface"), // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, + // REFIID iid, LPVOID *ppv); ADDRESS.withName("AddRef"), // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); ADDRESS.withName("Release"), // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); - ADDRESS.withName("CreateInterfaceAsyncEventSource"), // IOReturn (*CreateInterfaceAsyncEventSource)(void *self, CFRunLoopSourceRef *source); - ADDRESS.withName("GetInterfaceAsyncEventSource"), // CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void *self); - ADDRESS.withName("CreateInterfaceAsyncPort"), // IOReturn (*CreateInterfaceAsyncPort)(void *self, mach_port_t *port); + ADDRESS.withName("CreateInterfaceAsyncEventSource"), // IOReturn (*CreateInterfaceAsyncEventSource) + // (void *self, CFRunLoopSourceRef *source); + ADDRESS.withName("GetInterfaceAsyncEventSource"), // CFRunLoopSourceRef + // (*GetInterfaceAsyncEventSource)(void *self); + ADDRESS.withName("CreateInterfaceAsyncPort"), // IOReturn (*CreateInterfaceAsyncPort)(void *self, + // mach_port_t *port); ADDRESS.withName("GetInterfaceAsyncPort"), // mach_port_t (*GetInterfaceAsyncPort)(void *self); ADDRESS.withName("USBInterfaceOpen"), // IOReturn (*USBInterfaceOpen)(void *self); ADDRESS.withName("USBInterfaceClose"), // IOReturn (*USBInterfaceClose)(void *self); ADDRESS.withName("GetInterfaceClass"), // IOReturn (*GetInterfaceClass)(void *self, UInt8 *intfClass); - ADDRESS.withName("GetInterfaceSubClass"), // IOReturn (*GetInterfaceSubClass)(void *self, UInt8 *intfSubClass); - ADDRESS.withName("GetInterfaceProtocol"), // IOReturn (*GetInterfaceProtocol)(void *self, UInt8 *intfProtocol); + ADDRESS.withName("GetInterfaceSubClass"), // IOReturn (*GetInterfaceSubClass)(void *self, UInt8 + // *intfSubClass); + ADDRESS.withName("GetInterfaceProtocol"), // IOReturn (*GetInterfaceProtocol)(void *self, UInt8 + // *intfProtocol); ADDRESS.withName("GetDeviceVendor"), // IOReturn (*GetDeviceVendor)(void *self, UInt16 *devVendor); ADDRESS.withName("GetDeviceProduct"), // IOReturn (*GetDeviceProduct)(void *self, UInt16 *devProduct); - ADDRESS.withName("GetDeviceReleaseNumber"), // IOReturn (*GetDeviceReleaseNumber)(void *self, UInt16 *devRelNum); - ADDRESS.withName("GetConfigurationValue"), // IOReturn (*GetConfigurationValue)(void *self, UInt8 *configVal); + ADDRESS.withName("GetDeviceReleaseNumber"), // IOReturn (*GetDeviceReleaseNumber)(void *self, UInt16 + // *devRelNum); + ADDRESS.withName("GetConfigurationValue"), // IOReturn (*GetConfigurationValue)(void *self, UInt8 + // *configVal); ADDRESS.withName("GetInterfaceNumber"), // IOReturn (*GetInterfaceNumber)(void *self, UInt8 *intfNumber); - ADDRESS.withName("GetAlternateSetting"), // IOReturn (*GetAlternateSetting)(void *self, UInt8 *intfAltSetting); + ADDRESS.withName("GetAlternateSetting"), // IOReturn (*GetAlternateSetting)(void *self, UInt8 + // *intfAltSetting); ADDRESS.withName("GetNumEndpoints"), // IOReturn (*GetNumEndpoints)(void *self, UInt8 *intfNumEndpoints); ADDRESS.withName("GetLocationID"), // IOReturn (*GetLocationID)(void *self, UInt32 *locationID); ADDRESS.withName("GetDevice"), // IOReturn (*GetDevice)(void *self, io_service_t *device); - ADDRESS.withName("SetAlternateInterface"), // IOReturn (*SetAlternateInterface)(void *self, UInt8 alternateSetting); - ADDRESS.withName("GetBusFrameNumber"), // IOReturn (*GetBusFrameNumber)(void *self, UInt64 *frame, AbsoluteTime *atTime); - ADDRESS.withName("ControlRequest"), // IOReturn (*ControlRequest)(void *self, UInt8 pipeRef, IOUSBDevRequest *req); - ADDRESS.withName("ControlRequestAsync"), // IOReturn (*ControlRequestAsync)(void *self, UInt8 pipeRef, IOUSBDevRequest *req, IOAsyncCallback1 callback, void *refCon); - ADDRESS.withName("GetPipeProperties"), // IOReturn (*GetPipeProperties)(void *self, UInt8 pipeRef, UInt8 *direction, UInt8 *number, UInt8 *transferType, UInt16 *maxPacketSize, UInt8 *interval); + ADDRESS.withName("SetAlternateInterface"), // IOReturn (*SetAlternateInterface)(void *self, UInt8 + // alternateSetting); + ADDRESS.withName("GetBusFrameNumber"), // IOReturn (*GetBusFrameNumber)(void *self, UInt64 *frame, + // AbsoluteTime *atTime); + ADDRESS.withName("ControlRequest"), // IOReturn (*ControlRequest)(void *self, UInt8 pipeRef, + // IOUSBDevRequest *req); + ADDRESS.withName("ControlRequestAsync"), // IOReturn (*ControlRequestAsync)(void *self, UInt8 pipeRef, + // IOUSBDevRequest *req, IOAsyncCallback1 callback, void *refCon); + ADDRESS.withName("GetPipeProperties"), // IOReturn (*GetPipeProperties)(void *self, UInt8 pipeRef, + // UInt8 *direction, UInt8 *number, UInt8 *transferType, UInt16 *maxPacketSize, UInt8 *interval); ADDRESS.withName("GetPipeStatus"), // IOReturn (*GetPipeStatus)(void *self, UInt8 pipeRef); ADDRESS.withName("AbortPipe"), // IOReturn (*AbortPipe)(void *self, UInt8 pipeRef); ADDRESS.withName("ResetPipe"), // IOReturn (*ResetPipe)(void *self, UInt8 pipeRef); ADDRESS.withName("ClearPipeStall"), // IOReturn (*ClearPipeStall)(void *self, UInt8 pipeRef); - ADDRESS.withName("ReadPipe"), // IOReturn (*ReadPipe)(void *self, UInt8 pipeRef, void *buf, UInt32 *size); - ADDRESS.withName("WritePipe"), // IOReturn (*WritePipe)(void *self, UInt8 pipeRef, void *buf, UInt32 size); - ADDRESS.withName("ReadPipeAsync"), // IOReturn (*ReadPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("WritePipeAsync"), // IOReturn (*WritePipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("ReadIsochPipeAsync"), // IOReturn (*ReadIsochPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt64 frameStart, UInt32 numFrames, IOUSBIsocFrame *frameList, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("WriteIsochPipeAsync"), // IOReturn (*WriteIsochPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt64 frameStart, UInt32 numFrames, IOUSBIsocFrame *frameList, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("ControlRequestTO"), // IOReturn (*ControlRequestTO)(void *self, UInt8 pipeRef, IOUSBDevRequestTO *req); - ADDRESS.withName("ControlRequestAsyncTO"), // IOReturn (*ControlRequestAsyncTO)(void *self, UInt8 pipeRef, IOUSBDevRequestTO *req, IOAsyncCallback1 callback, void *refCon); - ADDRESS.withName("ReadPipeTO"), // IOReturn (*ReadPipeTO)(void *self, UInt8 pipeRef, void *buf, UInt32 *size, UInt32 noDataTimeout, UInt32 completionTimeout); - ADDRESS.withName("WritePipeTO"), // IOReturn (*WritePipeTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout); - ADDRESS.withName("ReadPipeAsyncTO"), // IOReturn (*ReadPipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("WritePipeAsyncTO"), // IOReturn (*WritePipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("USBInterfaceGetStringIndex"), // IOReturn (*USBInterfaceGetStringIndex)(void *self, UInt8 *si); + ADDRESS.withName("ReadPipe"), // IOReturn (*ReadPipe)(void *self, UInt8 pipeRef, void *buf, UInt32 + // *size); + ADDRESS.withName("WritePipe"), // IOReturn (*WritePipe)(void *self, UInt8 pipeRef, void *buf, UInt32 + // size); + ADDRESS.withName("ReadPipeAsync"), // IOReturn (*ReadPipeAsync)(void *self, UInt8 pipeRef, void *buf, + // UInt32 size, IOAsyncCallback1 callback, void *refcon); + ADDRESS.withName("WritePipeAsync"), // IOReturn (*WritePipeAsync)(void *self, UInt8 pipeRef, void + // *buf, UInt32 size, IOAsyncCallback1 callback, void *refcon); + ADDRESS.withName("ReadIsochPipeAsync"), // IOReturn (*ReadIsochPipeAsync)(void *self, UInt8 pipeRef, + // void *buf, UInt64 frameStart, UInt32 numFrames, IOUSBIsocFrame *frameList, IOAsyncCallback1 callback, + // void *refcon); + ADDRESS.withName("WriteIsochPipeAsync"), // IOReturn (*WriteIsochPipeAsync)(void *self, UInt8 pipeRef, + // void *buf, UInt64 frameStart, UInt32 numFrames, IOUSBIsocFrame *frameList, IOAsyncCallback1 callback, + // void *refcon); + ADDRESS.withName("ControlRequestTO"), // IOReturn (*ControlRequestTO)(void *self, UInt8 pipeRef, + // IOUSBDevRequestTO *req); + ADDRESS.withName("ControlRequestAsyncTO"), // IOReturn (*ControlRequestAsyncTO)(void *self, UInt8 + // pipeRef, IOUSBDevRequestTO *req, IOAsyncCallback1 callback, void *refCon); + ADDRESS.withName("ReadPipeTO"), // IOReturn (*ReadPipeTO)(void *self, UInt8 pipeRef, void *buf, UInt32 + // *size, UInt32 noDataTimeout, UInt32 completionTimeout); + ADDRESS.withName("WritePipeTO"), // IOReturn (*WritePipeTO)(void *self, UInt8 pipeRef, void *buf, + // UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout); + ADDRESS.withName("ReadPipeAsyncTO"), // IOReturn (*ReadPipeAsyncTO)(void *self, UInt8 pipeRef, void + // *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void + // *refcon); + ADDRESS.withName("WritePipeAsyncTO"), // IOReturn (*WritePipeAsyncTO)(void *self, UInt8 pipeRef, void + // *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void + // *refcon); + ADDRESS.withName("USBInterfaceGetStringIndex"), // IOReturn (*USBInterfaceGetStringIndex)(void *self, + // UInt8 *si); ADDRESS.withName("USBInterfaceOpenSeize"), // IOReturn (*USBInterfaceOpenSeize)(void *self); - ADDRESS.withName("ClearPipeStallBothEnds"), // IOReturn (*ClearPipeStallBothEnds)(void *self, UInt8 pipeRef); - ADDRESS.withName("SetPipePolicy"), // IOReturn (*SetPipePolicy)(void *self, UInt8 pipeRef, UInt16 maxPacketSize, UInt8 maxInterval); - ADDRESS.withName("GetBandwidthAvailable"), // IOReturn (*GetBandwidthAvailable)(void *self, UInt32 *bandwidth); - ADDRESS.withName("GetEndpointProperties"), // IOReturn (*GetEndpointProperties)(void *self, UInt8 alternateSetting, UInt8 endpointNumber, UInt8 direction, UInt8 *transferType, UInt16 *maxPacketSize, UInt8 *interval); - ADDRESS.withName("LowLatencyReadIsochPipeAsync"), // IOReturn (*LowLatencyReadIsochPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt64 frameStart, UInt32 numFrames, UInt32 updateFrequency, IOUSBLowLatencyIsocFrame *frameList, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("LowLatencyWriteIsochPipeAsync"), // IOReturn (*LowLatencyWriteIsochPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt64 frameStart, UInt32 numFrames, UInt32 updateFrequency, IOUSBLowLatencyIsocFrame *frameList, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("LowLatencyCreateBuffer"), // IOReturn (*LowLatencyCreateBuffer)(void * self, void **buffer, IOByteCount size, UInt32 bufferType); - ADDRESS.withName("LowLatencyDestroyBuffer"), // IOReturn (*LowLatencyDestroyBuffer) (void * self, void * buffer ); - ADDRESS.withName("GetBusMicroFrameNumber"), // IOReturn (*GetBusMicroFrameNumber)(void *self, UInt64 *microFrame, AbsoluteTime *atTime); - ADDRESS.withName("GetFrameListTime"), // IOReturn (*GetFrameListTime)(void *self, UInt32 *microsecondsInFrame); - ADDRESS.withName("GetIOUSBLibVersion"), // IOReturn (*GetIOUSBLibVersion)(void *self, NumVersion *ioUSBLibVersion, NumVersion *usbFamilyVersion); - ADDRESS.withName("FindNextAssociatedDescriptor"), // IOUSBDescriptorHeader * (*FindNextAssociatedDescriptor)(void *self, const void *currentDescriptor, UInt8 descriptorType); - ADDRESS.withName("FindNextAltInterface"), // IOUSBDescriptorHeader * (*FindNextAltInterface)(void *self, const void *current, IOUSBFindInterfaceRequest *request); - ADDRESS.withName("GetBusFrameNumberWithTime"), // IOReturn (*GetBusFrameNumberWithTime)(void *self, UInt64 *frame, AbsoluteTime *atTime); - ADDRESS.withName("GetPipePropertiesV2"), // IOReturn (*GetPipePropertiesV2)(void *self, UInt8 pipeRef, UInt8 *direction, UInt8 *number, UInt8 *transferType, UInt16 *maxPacketSize, UInt8 *interval, UInt8 *maxBurst, UInt8 *mult, UInt16 *bytesPerInterval); - ADDRESS.withName("GetPipePropertiesV3"), // IOReturn (*GetPipePropertiesV3)(void *self, UInt8 pipeRef, IOUSBEndpointProperties *properties); - ADDRESS.withName("GetEndpointPropertiesV3"), // IOReturn (*GetEndpointPropertiesV3)(void *self, IOUSBEndpointProperties *properties); - ADDRESS.withName("SupportsStreams"), // IOReturn (*SupportsStreams)(void *self, UInt8 pipeRef, UInt32 *supportsStreams); - ADDRESS.withName("CreateStreams"), // IOReturn (*CreateStreams)(void *self, UInt8 pipeRef, UInt32 streamID); - ADDRESS.withName("GetConfiguredStreams"), // IOReturn (*GetConfiguredStreams)(void *self, UInt8 pipeRef, UInt32 *configuredStreams); - ADDRESS.withName("ReadStreamsPipeTO"), // IOReturn (*ReadStreamsPipeTO)(void *self, UInt8 pipeRef, UInt32 streamID, void *buf, UInt32 *size, UInt32 noDataTimeout, UInt32 completionTimeout); - ADDRESS.withName("WriteStreamsPipeTO"), // IOReturn (*WriteStreamsPipeTO)(void *self, UInt8 pipeRef, UInt32 streamID, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout); - ADDRESS.withName("ReadStreamsPipeAsyncTO"), // IOReturn (*ReadStreamsPipeAsyncTO)(void *self, UInt8 pipeRef, UInt32 streamID, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("WriteStreamsPipeAsyncTO"), // IOReturn (*WriteStreamsPipeAsyncTO)(void *self, UInt8 pipeRef, UInt32 streamID, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("AbortStreamsPipe"), // IOReturn (*AbortStreamsPipe)(void *self, UInt8 pipeRef, UInt32 streamID); - ADDRESS.withName("RegisterForNotification"), // IOReturn (*RegisterForNotification)(void * self, UInt64 notificationMask, IOAsyncCallback2 callback, void *refCon, UInt64 *pRegistrationToken); - ADDRESS.withName("UnregisterNotification"), // IOReturn (*UnregisterNotification)(void *self, UInt64 registrationToken); - ADDRESS.withName("AcknowledgeNotification"), // IOReturn (*AcknowledgeNotification)(void *self, UInt64 notificationToken); + ADDRESS.withName("ClearPipeStallBothEnds"), // IOReturn (*ClearPipeStallBothEnds)(void *self, UInt8 + // pipeRef); + ADDRESS.withName("SetPipePolicy"), // IOReturn (*SetPipePolicy)(void *self, UInt8 pipeRef, UInt16 + // maxPacketSize, UInt8 maxInterval); + ADDRESS.withName("GetBandwidthAvailable"), // IOReturn (*GetBandwidthAvailable)(void *self, UInt32 + // *bandwidth); + ADDRESS.withName("GetEndpointProperties"), // IOReturn (*GetEndpointProperties)(void *self, UInt8 + // alternateSetting, UInt8 endpointNumber, UInt8 direction, UInt8 *transferType, UInt16 *maxPacketSize, + // UInt8 *interval); + ADDRESS.withName("LowLatencyReadIsochPipeAsync"), // IOReturn (*LowLatencyReadIsochPipeAsync)(void + // *self, UInt8 pipeRef, void *buf, UInt64 frameStart, UInt32 numFrames, UInt32 updateFrequency, + // IOUSBLowLatencyIsocFrame *frameList, IOAsyncCallback1 callback, void *refcon); + ADDRESS.withName("LowLatencyWriteIsochPipeAsync"), // IOReturn (*LowLatencyWriteIsochPipeAsync)(void + // *self, UInt8 pipeRef, void *buf, UInt64 frameStart, UInt32 numFrames, UInt32 updateFrequency, + // IOUSBLowLatencyIsocFrame *frameList, IOAsyncCallback1 callback, void *refcon); + ADDRESS.withName("LowLatencyCreateBuffer"), // IOReturn (*LowLatencyCreateBuffer)(void * self, void + // **buffer, IOByteCount size, UInt32 bufferType); + ADDRESS.withName("LowLatencyDestroyBuffer"), // IOReturn (*LowLatencyDestroyBuffer) (void * self, void + // * buffer ); + ADDRESS.withName("GetBusMicroFrameNumber"), // IOReturn (*GetBusMicroFrameNumber)(void *self, UInt64 + // *microFrame, AbsoluteTime *atTime); + ADDRESS.withName("GetFrameListTime"), // IOReturn (*GetFrameListTime)(void *self, UInt32 + // *microsecondsInFrame); + ADDRESS.withName("GetIOUSBLibVersion"), // IOReturn (*GetIOUSBLibVersion)(void *self, NumVersion + // *ioUSBLibVersion, NumVersion *usbFamilyVersion); + ADDRESS.withName("FindNextAssociatedDescriptor"), // IOUSBDescriptorHeader * + // (*FindNextAssociatedDescriptor)(void *self, const void *currentDescriptor, UInt8 descriptorType); + ADDRESS.withName("FindNextAltInterface"), // IOUSBDescriptorHeader * (*FindNextAltInterface)(void + // *self, const void *current, IOUSBFindInterfaceRequest *request); + ADDRESS.withName("GetBusFrameNumberWithTime"), // IOReturn (*GetBusFrameNumberWithTime)(void *self, + // UInt64 *frame, AbsoluteTime *atTime); + ADDRESS.withName("GetPipePropertiesV2"), // IOReturn (*GetPipePropertiesV2)(void *self, UInt8 pipeRef, + // UInt8 *direction, UInt8 *number, UInt8 *transferType, UInt16 *maxPacketSize, UInt8 *interval, UInt8 + // *maxBurst, UInt8 *mult, UInt16 *bytesPerInterval); + ADDRESS.withName("GetPipePropertiesV3"), // IOReturn (*GetPipePropertiesV3)(void *self, UInt8 pipeRef, + // IOUSBEndpointProperties *properties); + ADDRESS.withName("GetEndpointPropertiesV3"), // IOReturn (*GetEndpointPropertiesV3)(void *self, + // IOUSBEndpointProperties *properties); + ADDRESS.withName("SupportsStreams"), // IOReturn (*SupportsStreams)(void *self, UInt8 pipeRef, UInt32 + // *supportsStreams); + ADDRESS.withName("CreateStreams"), // IOReturn (*CreateStreams)(void *self, UInt8 pipeRef, UInt32 + // streamID); + ADDRESS.withName("GetConfiguredStreams"), // IOReturn (*GetConfiguredStreams)(void *self, UInt8 + // pipeRef, UInt32 *configuredStreams); + ADDRESS.withName("ReadStreamsPipeTO"), // IOReturn (*ReadStreamsPipeTO)(void *self, UInt8 pipeRef, + // UInt32 streamID, void *buf, UInt32 *size, UInt32 noDataTimeout, UInt32 completionTimeout); + ADDRESS.withName("WriteStreamsPipeTO"), // IOReturn (*WriteStreamsPipeTO)(void *self, UInt8 pipeRef, + // UInt32 streamID, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout); + ADDRESS.withName("ReadStreamsPipeAsyncTO"), // IOReturn (*ReadStreamsPipeAsyncTO)(void *self, UInt8 + // pipeRef, UInt32 streamID, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, + // IOAsyncCallback1 callback, void *refcon); + ADDRESS.withName("WriteStreamsPipeAsyncTO"), // IOReturn (*WriteStreamsPipeAsyncTO)(void *self, UInt8 + // pipeRef, UInt32 streamID, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, + // IOAsyncCallback1 callback, void *refcon); + ADDRESS.withName("AbortStreamsPipe"), // IOReturn (*AbortStreamsPipe)(void *self, UInt8 pipeRef, + // UInt32 streamID); + ADDRESS.withName("RegisterForNotification"), // IOReturn (*RegisterForNotification)(void * self, + // UInt64 notificationMask, IOAsyncCallback2 callback, void *refCon, UInt64 *pRegistrationToken); + ADDRESS.withName("UnregisterNotification"), // IOReturn (*UnregisterNotification)(void *self, UInt64 + // registrationToken); + ADDRESS.withName("AcknowledgeNotification"), // IOReturn (*AcknowledgeNotification)(void *self, UInt64 + // notificationToken); ADDRESS.withName("RegisterDriver") // IOReturn (*RegisterDriver)(void *self); ); /** * Looks up the address of the specified virtual function in the {@code IOUSBInterface} object + * * @param thisPointer pointer to pointer to object - * @param varHandle variable handle to virtual function - * @param session memory session + * @param varHandle variable handle to virtual function + * @param session memory session * @return function address */ - private static Addressable IOUSBInterfaceFunctionAddress(MemoryAddress thisPointer, VarHandle varHandle, MemorySession session) { + private static Addressable IOUSBInterfaceFunctionAddress(MemoryAddress thisPointer, VarHandle varHandle, + MemorySession session) { var seg = MemorySegment.ofAddress(thisPointer, ADDRESS.byteSize(), session); var thisValue = seg.get(ADDRESS, 0); var obj = MemorySegment.ofAddress(thisValue, IOUSBInterface$Struct.byteSize(), session); @@ -286,10 +391,11 @@ private static Addressable IOUSBInterfaceFunctionAddress(MemoryAddress thisPoint } // IOReturn (*USBInterfaceOpen)(void *self);; - private static final VarHandle IOUSBInterface_USBInterfaceOpen = IOUSBInterface$Struct.varHandle(groupElement("USBInterfaceOpen")); - private static final MethodHandle USBInterfaceOpen$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS) - ); + private static final VarHandle IOUSBInterface_USBInterfaceOpen = IOUSBInterface$Struct.varHandle(groupElement( + "USBInterfaceOpen")); + private static final MethodHandle USBInterfaceOpen$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, + ADDRESS)); + public static int USBInterfaceOpen(MemoryAddress thisPointer) { try (var session = MemorySession.openShared()) { var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_USBInterfaceOpen, session); @@ -300,10 +406,11 @@ public static int USBInterfaceOpen(MemoryAddress thisPointer) { } // IOReturn (*USBInterfaceClose)(void *self);; - private static final VarHandle IOUSBInterface_USBInterfaceClose = IOUSBInterface$Struct.varHandle(groupElement("USBInterfaceClose")); - private static final MethodHandle USBInterfaceClose$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS) - ); + private static final VarHandle IOUSBInterface_USBInterfaceClose = IOUSBInterface$Struct.varHandle(groupElement( + "USBInterfaceClose")); + private static final MethodHandle USBInterfaceClose$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, + ADDRESS)); + public static int USBInterfaceClose(MemoryAddress thisPointer) { try (var session = MemorySession.openShared()) { var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_USBInterfaceClose, session); @@ -314,10 +421,11 @@ public static int USBInterfaceClose(MemoryAddress thisPointer) { } // IOReturn (*GetInterfaceNumber)(void *self, UInt8 *intfNumber); - private static final VarHandle IOUSBInterface_GetInterfaceNumber = IOUSBInterface$Struct.varHandle(groupElement("GetInterfaceNumber")); - private static final MethodHandle GetInterfaceNumber$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS) - ); + private static final VarHandle IOUSBInterface_GetInterfaceNumber = IOUSBInterface$Struct.varHandle(groupElement( + "GetInterfaceNumber")); + private static final MethodHandle GetInterfaceNumber$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, + ADDRESS, ADDRESS)); + public static int GetInterfaceNumber(MemoryAddress thisPointer, Addressable intfNumberHolder) { try (var session = MemorySession.openShared()) { var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_GetInterfaceNumber, session); @@ -328,10 +436,11 @@ public static int GetInterfaceNumber(MemoryAddress thisPointer, Addressable intf } // IOReturn (*GetNumEndpoints)(void *self, UInt8 *intfNumEndpoints); - private static final VarHandle IOUSBInterface_GetNumEndpoints = IOUSBInterface$Struct.varHandle(groupElement("GetNumEndpoints")); - private static final MethodHandle GetNumEndpoints$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS) - ); + private static final VarHandle IOUSBInterface_GetNumEndpoints = IOUSBInterface$Struct.varHandle(groupElement( + "GetNumEndpoints")); + private static final MethodHandle GetNumEndpoints$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, + ADDRESS, ADDRESS)); + public static int GetNumEndpoints(MemoryAddress thisPointer, Addressable intfNumEndpointsHolder) { try (var session = MemorySession.openShared()) { var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_GetNumEndpoints, session); @@ -341,18 +450,20 @@ public static int GetNumEndpoints(MemoryAddress thisPointer, Addressable intfNum } } - // IOReturn (*GetPipeProperties)(void *self, UInt8 pipeRef, UInt8 *direction, UInt8 *number, UInt8 *transferType, UInt16 *maxPacketSize, UInt8 *interval); - private static final VarHandle IOUSBInterface_GetPipeProperties = IOUSBInterface$Struct.varHandle(groupElement("GetPipeProperties")); - private static final MethodHandle GetPipeProperties$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS) - ); + // IOReturn (*GetPipeProperties)(void *self, UInt8 pipeRef, UInt8 *direction, UInt8 *number, UInt8 *transferType, + // UInt16 *maxPacketSize, UInt8 *interval); + private static final VarHandle IOUSBInterface_GetPipeProperties = IOUSBInterface$Struct.varHandle(groupElement( + "GetPipeProperties")); + private static final MethodHandle GetPipeProperties$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, + ADDRESS, JAVA_BYTE, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS)); + public static int GetPipeProperties(MemoryAddress thisPointer, byte pipeRef, Addressable directionHolder, Addressable numberHolder, Addressable transferTypeHolder, Addressable maxPacketSizeHolder, Addressable intervalHolder) { try (var session = MemorySession.openShared()) { var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_GetPipeProperties, session); - return (int) GetPipeProperties$Func.invokeExact(funcPtr, (Addressable) thisPointer, pipeRef, directionHolder, - numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); + return (int) GetPipeProperties$Func.invokeExact(funcPtr, (Addressable) thisPointer, pipeRef, + directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); } catch (Throwable e) { throw new RuntimeException(e); } @@ -360,9 +471,9 @@ public static int GetPipeProperties(MemoryAddress thisPointer, byte pipeRef, Add // IOReturn (*ReadPipe)(void *self, UInt8 pipeRef, void *buf, UInt32 *size); private static final VarHandle IOUSBInterface_ReadPipe = IOUSBInterface$Struct.varHandle(groupElement("ReadPipe")); - private static final MethodHandle ReadPipe$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS, ADDRESS) - ); + private static final MethodHandle ReadPipe$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, ADDRESS, + JAVA_BYTE, ADDRESS, ADDRESS)); + public static int ReadPipe(MemoryAddress thisPointer, byte pipeRef, Addressable buf, Addressable sizeHolder) { try (var session = MemorySession.openShared()) { var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_ReadPipe, session); @@ -373,10 +484,11 @@ public static int ReadPipe(MemoryAddress thisPointer, byte pipeRef, Addressable } // IOReturn (*WritePipe)(void *self, UInt8 pipeRef, void *buf, UInt32 size); - private static final VarHandle IOUSBInterface_WritePipe = IOUSBInterface$Struct.varHandle(groupElement("WritePipe")); - private static final MethodHandle WritePipe$Func = linker.downcallHandle( - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS, JAVA_INT) - ); + private static final VarHandle IOUSBInterface_WritePipe = IOUSBInterface$Struct.varHandle(groupElement("WritePipe" + )); + private static final MethodHandle WritePipe$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, ADDRESS, + JAVA_BYTE, ADDRESS, JAVA_INT)); + public static int WritePipe(MemoryAddress thisPointer, byte pipeRef, Addressable buf, int size) { try (var session = MemorySession.openShared()) { var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_WritePipe, session); @@ -395,17 +507,12 @@ public static int WritePipe(MemoryAddress thisPointer, byte pipeRef, Addressable // void* pData; // UInt32 wLenDone; //} IOUSBDevRequest; - public static final GroupLayout IOUSBDevRequest$Struct = structLayout( - JAVA_BYTE.withName("bmRequestType"), - JAVA_BYTE.withName("bRequest"), - JAVA_SHORT.withName("wValue"), - JAVA_SHORT.withName("wIndex"), - JAVA_SHORT.withName("wLength"), - ADDRESS.withName("pData"), - JAVA_INT.withName("wLenDone") - ); + public static final GroupLayout IOUSBDevRequest$Struct = structLayout(JAVA_BYTE.withName("bmRequestType"), + JAVA_BYTE.withName("bRequest"), JAVA_SHORT.withName("wValue"), JAVA_SHORT.withName("wIndex"), + JAVA_SHORT.withName("wLength"), ADDRESS.withName("pData"), JAVA_INT.withName("wLenDone")); - public static final VarHandle IOUSBDevRequest_bmRequestType = IOUSBDevRequest$Struct.varHandle(groupElement("bmRequestType")); + public static final VarHandle IOUSBDevRequest_bmRequestType = IOUSBDevRequest$Struct.varHandle(groupElement( + "bmRequestType")); public static final VarHandle IOUSBDevRequest_bRequest = IOUSBDevRequest$Struct.varHandle(groupElement("bRequest")); public static final VarHandle IOUSBDevRequest_wValue = IOUSBDevRequest$Struct.varHandle(groupElement("wValue")); public static final VarHandle IOUSBDevRequest_wIndex = IOUSBDevRequest$Struct.varHandle(groupElement("wIndex")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index a88be68c..e1a1f6ce 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -78,8 +78,8 @@ protected void monitorDevices() { /** * Process the devices resulting from the iterator * - * @param iterator the iterator - * @param consumer a consumer that will be called for each device with the entry ID and the service + * @param iterator the iterator + * @param consumer a consumer that will be called for each device with the entry ID and the service */ private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { @@ -129,9 +129,7 @@ private void iterateDevices(int iterator, Consumer consumer) { consumer.accept(device); } catch (Throwable e) { - System.err.printf( - "Info: [JavaDoesUSB] failed to retrieve information about device 0x%04x/0x%04x - ignoring device%n", - deviceInfo.vid, deviceInfo.pid); + System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device 0x%04x/0x%04x - " + "ignoring device%n", deviceInfo.vid, deviceInfo.pid); e.printStackTrace(System.err); } }); @@ -160,8 +158,7 @@ private USBDevice createDevice(Long entryID, int service, MemoryAddress deviceIn Integer subclassCode = IoKitHelper.getPropertyInt(service, "bDeviceSubClass"); Integer protocolCode = IoKitHelper.getPropertyInt(service, "bDeviceProtocol"); - device.setClassCodes(classCode != null ? classCode : 0, - subclassCode != null ? subclassCode : 0, + device.setClassCodes(classCode != null ? classCode : 0, subclassCode != null ? subclassCode : 0, protocolCode != null ? protocolCode : 0); return device; @@ -182,7 +179,8 @@ private int setupNotification(MemorySession session, MemoryAddress notifyPort, M var deviceIterHolder = session.allocate(JAVA_INT); int ret = IoKit.IOServiceAddMatchingNotification(notifyPort, notificationType, matchingDict, onDeviceCallbackStub, NULL, deviceIterHolder); - if (ret != 0) throw new MacosUSBException("IOServiceAddMatchingNotification failed", ret); + if (ret != 0) + throw new MacosUSBException("IOServiceAddMatchingNotification failed", ret); return deviceIterHolder.get(JAVA_INT, 0); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index 64f41a12..5490bb20 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -27,17 +27,17 @@ */ public class DeviceProperty { - public static final MemorySegment DEVPKEY_Device_Address = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, (short) 0x4efd, - (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, - (byte) 0x46, (byte) 0xa8, (byte) 0x50, (byte) 0xe0, 30); + public static final MemorySegment DEVPKEY_Device_Address = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, + (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50 + , (byte) 0xe0, 30); - public static final MemorySegment DEVPKEY_Device_InstanceId = createDEVPROPKEY(0x78c34fc8, (short) 0x104a, (short) 0x4aca, - (byte) 0x9e, (byte) 0xa4, (byte) 0x52, (byte) 0x4d, - (byte) 0x52, (byte) 0x99, (byte) 0x6e, (byte) 0x57, 256); + public static final MemorySegment DEVPKEY_Device_InstanceId = createDEVPROPKEY(0x78c34fc8, (short) 0x104a, + (short) 0x4aca, (byte) 0x9e, (byte) 0xa4, (byte) 0x52, (byte) 0x4d, (byte) 0x52, (byte) 0x99, (byte) 0x6e + , (byte) 0x57, 256); - public static final MemorySegment DEVPKEY_Device_Parent = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, (short) 0x4706, - (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, - (byte) 0x80, (byte) 0x08, (byte) 0xa5, (byte) 0xa7, 8); + public static final MemorySegment DEVPKEY_Device_Parent = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, + (short) 0x4706, (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, (byte) 0x80, (byte) 0x08, (byte) 0xa5 + , (byte) 0xa7, 8); public static int getDeviceIntProperty(Addressable devInfo, Addressable devInfoData, Addressable propertyKey) { try (var session = MemorySession.openConfined()) { @@ -54,16 +54,18 @@ public static int getDeviceIntProperty(Addressable devInfo, Addressable devInfoD } } - public static String getDeviceStringProperty(Addressable devInfo, Addressable devInfoData, Addressable propertyKey) { + public static String getDeviceStringProperty(Addressable devInfo, Addressable devInfoData, + Addressable propertyKey) { try (var session = MemorySession.openConfined()) { var propertyTypeHolder = session.allocate(JAVA_INT); var requiredSizeHolder = session.allocate(JAVA_INT); - if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, - NULL, 0, requiredSizeHolder, 0) == 0) { + if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, NULL, 0, + requiredSizeHolder, 0) == 0) { // TODO: Reactivate when proper GetLastError() handling is available -// int err = Kernel32.GetLastError(); -// if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) -// throw new USBException("Internal error (SetupDiGetDevicePropertyW)", Kernel32.GetLastError()); + // int err = Kernel32.GetLastError(); + // if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) + // throw new USBException("Internal error (SetupDiGetDevicePropertyW)", Kernel32 + // .GetLastError()); } if (propertyTypeHolder.get(JAVA_INT, 0) != SetupAPI.DEVPROP_TYPE_STRING()) @@ -84,7 +86,8 @@ public static String getDevicePath(String instanceID, Addressable interfaceGuid) try (var session = MemorySession.openConfined()) { // get device info set for instance var instanceIDSegment = Win.createSegmentFromString(instanceID, session); - final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(interfaceGuid, instanceIDSegment, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); + final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(interfaceGuid, instanceIDSegment, NULL, + SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); if (Win.IsInvalidHandle(devInfoSetHandle)) throw new USBException("internal error (SetupDiGetClassDevsW)"); @@ -102,22 +105,23 @@ public static String getDevicePath(String instanceID, Addressable interfaceGuid) // the device path fits) final int devicePathOffset = 4; var intfDetailData = session.allocate(4 + 260 * 2); - SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$set(intfDetailData, (int) SP_DEVICE_INTERFACE_DETAIL_DATA_W.sizeof()); + SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$set(intfDetailData, + (int) SP_DEVICE_INTERFACE_DETAIL_DATA_W.sizeof()); int intfDetailDataSize = (int) intfDetailData.byteSize(); - if (SetupAPI.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, - intfDetailData, intfDetailDataSize, NULL, NULL) == 0) + if (SetupAPI.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, intfDetailData, + intfDetailDataSize, NULL, NULL) == 0) throw new USBException("Internal error (SetupDiGetDeviceInterfaceDetailW)", Kernel32.GetLastError()); return Win.createStringFromSegment(intfDetailData.asSlice(devicePathOffset)); } } - public static MemorySegment createDEVPROPKEY(int data1, short data2, short data3, - byte data4_0, byte data4_1, byte data4_2, byte data4_3, - byte data4_4, byte data4_5, byte data4_6, byte data4_7, - int pid) { + public static MemorySegment createDEVPROPKEY(int data1, short data2, short data3, byte data4_0, byte data4_1, + byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6 + , byte data4_7, int pid) { var propKey = MemorySession.global().allocate(GUID.sizeof() + JAVA_INT.byteSize()); - Win.setGUID(propKey, data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4, data4_5, data4_6, data4_7); + Win.setGUID(propKey, data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4, data4_5, data4_6, + data4_7); propKey.set(JAVA_INT, 16, pid); return propKey; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java index 6cd7bc2a..c0c84fdc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java @@ -44,26 +44,25 @@ public class USBHelper { // USB_CONNECTION_STATUS ConnectionStatus;/* OUTPUT */ // USB_PIPE_INFO PipeList[0];/* OUTPUT */ //} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; - public static final GroupLayout USB_NODE_CONNECTION_INFORMATION_EX$Struct = structLayout( - JAVA_INT.withName("ConnectionIndex"), - USBDescriptors.Device$Struct.withName("DeviceDescriptor"), - JAVA_BYTE.withName("CurrentConfigurationValue"), - JAVA_BYTE.withName("Speed"), - JAVA_BYTE.withName("DeviceIsHub"), - JAVA_SHORT.withName("DeviceAddress"), - JAVA_INT.withName("NumberOfOpenPipes"), - JAVA_INT.withName("ConnectionStatus") + public static final GroupLayout USB_NODE_CONNECTION_INFORMATION_EX$Struct = structLayout(JAVA_INT.withName( + "ConnectionIndex"), USBDescriptors.Device$Struct.withName("DeviceDescriptor"), JAVA_BYTE.withName( + "CurrentConfigurationValue"), JAVA_BYTE.withName("Speed"), JAVA_BYTE.withName("DeviceIsHub"), + JAVA_SHORT.withName("DeviceAddress"), JAVA_INT.withName("NumberOfOpenPipes"), JAVA_INT.withName( + "ConnectionStatus") // USB_PIPE_INFO PipeList[0] ); - public static final VarHandle USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex - = USB_NODE_CONNECTION_INFORMATION_EX$Struct.varHandle(groupElement("ConnectionIndex")); - public static final long USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset - = USB_NODE_CONNECTION_INFORMATION_EX$Struct.byteOffset(groupElement("DeviceDescriptor")); + public static final VarHandle USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex = + USB_NODE_CONNECTION_INFORMATION_EX$Struct.varHandle(groupElement("ConnectionIndex")); + public static final long USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset = + USB_NODE_CONNECTION_INFORMATION_EX$Struct.byteOffset(groupElement("DeviceDescriptor")); + public static MemorySegment USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(MemorySegment seg) { - return seg.asSlice(USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset, USBDescriptors.Device$Struct.byteSize()); + return seg.asSlice(USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset, + USBDescriptors.Device$Struct.byteSize()); } - public static final VarHandle USB_NODE_CONNECTION_INFORMATION_EX_CurrentConfigurationValue - = USB_NODE_CONNECTION_INFORMATION_EX$Struct.varHandle(groupElement("CurrentConfigurationValue")); + + public static final VarHandle USB_NODE_CONNECTION_INFORMATION_EX_CurrentConfigurationValue = + USB_NODE_CONNECTION_INFORMATION_EX$Struct.varHandle(groupElement("CurrentConfigurationValue")); // typedef struct _USB_DESCRIPTOR_REQUEST { // ULONG ConnectionIndex; @@ -76,12 +75,12 @@ public class USBHelper { // } SetupPacket; // UCHAR Data[0]; //} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST; - public static final GroupLayout USB_DESCRIPTOR_REQUEST$Struct = structLayout( - JAVA_INT.withName("ConnectionIndex"), - USBStructs.SetupPacket$Struct.withName("SetupPacket") - ); - public static final VarHandle USB_DESCRIPTOR_REQUEST_ConnectionIndex = USB_DESCRIPTOR_REQUEST$Struct.varHandle(groupElement("ConnectionIndex")); - public static final long USB_DESCRIPTOR_REQUEST_SetupPacket$Offset = USB_DESCRIPTOR_REQUEST$Struct.byteOffset(groupElement("SetupPacket")); + public static final GroupLayout USB_DESCRIPTOR_REQUEST$Struct = structLayout(JAVA_INT.withName("ConnectionIndex") + , USBStructs.SetupPacket$Struct.withName("SetupPacket")); + public static final VarHandle USB_DESCRIPTOR_REQUEST_ConnectionIndex = + USB_DESCRIPTOR_REQUEST$Struct.varHandle(groupElement("ConnectionIndex")); + public static final long USB_DESCRIPTOR_REQUEST_SetupPacket$Offset = + USB_DESCRIPTOR_REQUEST$Struct.byteOffset(groupElement("SetupPacket")); public static final long USB_DESCRIPTOR_REQUEST_Data$Offset = USB_DESCRIPTOR_REQUEST$Struct.byteSize(); // typedef struct _USB_STRING_DESCRIPTOR { @@ -89,23 +88,23 @@ public class USBHelper { // UCHAR bDescriptorType; // WCHAR bString[1]; //} USB_STRING_DESCRIPTOR, *PUSB_STRING_DESCRIPTOR; - public static final GroupLayout USB_STRING_DESCRIPTOR$Struct = structLayout( - JAVA_BYTE.withName("bLength"), - JAVA_BYTE.withName("bDescriptorType") - ); - public static final VarHandle USB_STRING_DESCRIPTOR_bLength = USB_STRING_DESCRIPTOR$Struct.varHandle(groupElement("bLength")); - public static final VarHandle USB_STRING_DESCRIPTOR_bDescriptorType = USB_STRING_DESCRIPTOR$Struct.varHandle(groupElement("bDescriptorType")); + public static final GroupLayout USB_STRING_DESCRIPTOR$Struct = structLayout(JAVA_BYTE.withName("bLength"), + JAVA_BYTE.withName("bDescriptorType")); + public static final VarHandle USB_STRING_DESCRIPTOR_bLength = + USB_STRING_DESCRIPTOR$Struct.varHandle(groupElement("bLength")); + public static final VarHandle USB_STRING_DESCRIPTOR_bDescriptorType = + USB_STRING_DESCRIPTOR$Struct.varHandle(groupElement("bDescriptorType")); public static final long USB_STRING_DESCRIPTOR_bString$Offset = USB_STRING_DESCRIPTOR$Struct.byteSize(); // A5DCBF10-6530-11D2-901F-00C04FB951ED - public static final MemorySegment GUID_DEVINTERFACE_USB_DEVICE = Win.CreateGUID(0xA5DCBF10, (short) 0x6530, (short) 0x11D2, - (byte) 0x90, (byte) 0x1F, (byte) 0x00, (byte) 0xC0, - (byte) 0x4F, (byte) 0xB9, (byte) 0x51, (byte) 0xED); + public static final MemorySegment GUID_DEVINTERFACE_USB_DEVICE = Win.CreateGUID(0xA5DCBF10, (short) 0x6530, + (short) 0x11D2, (byte) 0x90, (byte) 0x1F, (byte) 0x00, (byte) 0xC0, (byte) 0x4F, (byte) 0xB9, (byte) 0x51 + , (byte) 0xED); // f18a0e88-c30c-11d0-8815-00a0c906bed8 - public static final MemorySegment GUID_DEVINTERFACE_USB_HUB = Win.CreateGUID(0xf18a0e88, (short) 0xc30c, (short) 0x11d0, - (byte) 0x88, (byte) 0x15, (byte) 0x00, (byte) 0xa0, - (byte) 0xc9, (byte) 0x06, (byte) 0xbe, (byte) 0xd8); + public static final MemorySegment GUID_DEVINTERFACE_USB_HUB = Win.CreateGUID(0xf18a0e88, (short) 0xc30c, + (short) 0x11d0, (byte) 0x88, (byte) 0x15, (byte) 0x00, (byte) 0xa0, (byte) 0xc9, (byte) 0x06, (byte) 0xbe + , (byte) 0xd8); static { assert USB_NODE_CONNECTION_INFORMATION_EX$Struct.byteSize() == 35; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index cc4f0c75..72ad9c4e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -38,7 +38,8 @@ public static boolean IsInvalidHandle(MemoryAddress handle) { *

* The memory segment contains a copy of the string (null-terminated, UTF-16/wide characters). *

- * @param str the string to copy + * + * @param str the string to copy * @param session the memory session for the memory segment * @return the resulting memory segment */ @@ -55,6 +56,7 @@ public static MemorySegment createSegmentFromString(String str, MemorySession se *

* The string must be a null-terminated UTF-16 (wide character) string. *

+ * * @param segment the memory segment * @return copied string */ @@ -79,17 +81,16 @@ public static String createStringFromSegment(MemorySegment segment) { * @param data4_7 Byte 7 of group 4 * @return GUID as memory segment */ - public static MemorySegment CreateGUID(int data1, short data2, short data3, - byte data4_0, byte data4_1, byte data4_2, byte data4_3, - byte data4_4, byte data4_5, byte data4_6, byte data4_7) { + public static MemorySegment CreateGUID(int data1, short data2, short data3, byte data4_0, byte data4_1, + byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, + byte data4_7) { var guid = MemorySegment.allocateNative(GUID.$LAYOUT(), MemorySession.global()); setGUID(guid, data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4, data4_5, data4_6, data4_7); return guid; } - public static void setGUID(MemorySegment guid, int data1, short data2, short data3, - byte data4_0, byte data4_1, byte data4_2, byte data4_3, - byte data4_4, byte data4_5, byte data4_6, byte data4_7) { + public static void setGUID(MemorySegment guid, int data1, short data2, short data3, byte data4_0, byte data4_1, + byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7) { GUID.Data1$set(guid, data1); GUID.Data2$set(guid, data2); GUID.Data3$set(guid, data3); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 05533823..77c40fae 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -67,8 +67,8 @@ protected void monitorDevices() { User32.RegisterClassExW(wx); // create message-only window - hwnd = User32.CreateWindowExW(0, className, windowName, 0, 0, 0, 0, 0, User32.HWND_MESSAGE(), - NULL, instance, NULL); + hwnd = User32.CreateWindowExW(0, className, windowName, 0, 0, 0, 0, 0, User32.HWND_MESSAGE(), NULL, + instance, NULL); if (hwnd == NULL) throw new USBException("internal error (CreateWindowExW)", Kernel32.GetLastError()); @@ -140,7 +140,8 @@ private void enumeratePresentDevices() { deviceList.add(createDeviceFromDeviceInfo(devInfoSetHandle, devInfo, devicePath, hubHandles)); } catch (Throwable e) { - System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring device%n", devicePath); + System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring " + + "device%n", devicePath); e.printStackTrace(System.err); } } @@ -149,8 +150,8 @@ private void enumeratePresentDevices() { } } - private USBDevice createDeviceFromDeviceInfo(MemoryAddress devInfoSetHandle, MemorySegment devInfo, String devicePath, - HashMap hubHandles) { + private USBDevice createDeviceFromDeviceInfo(MemoryAddress devInfoSetHandle, MemorySegment devInfo, + String devicePath, HashMap hubHandles) { try (var session = MemorySession.openConfined()) { var usbPortNum = DeviceProperty.getDeviceIntProperty(devInfoSetHandle, devInfo, @@ -178,7 +179,7 @@ private USBDevice createDeviceFromDeviceInfo(MemoryAddress devInfoSetHandle, Mem * Retrieve device descriptor and create {@code USBDevice} instance * * @param devicePath the device path - * @param hubHandle the hub handle (parent) + * @param hubHandle the hub handle (parent) * @param usbPortNum the USB port number * @return the {@code USBDevice} instance */ @@ -190,8 +191,8 @@ private USBDevice createDevice(String devicePath, MemoryAddress hubHandle, int u var connInfo = session.allocate(USBHelper.USB_NODE_CONNECTION_INFORMATION_EX$Struct); USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex.set(connInfo, usbPortNum); var sizeHolder = session.allocate(JAVA_INT); - if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), connInfo, - (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL) == 0) + if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), connInfo + , (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL) == 0) throw new USBException("Internal error (cannot get device descriptor)", Kernel32.GetLastError()); var deviceDesc = USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(connInfo); @@ -207,10 +208,11 @@ private USBDevice createDevice(String devicePath, MemoryAddress hubHandle, int u int vendorId = 0xffff & (short) USBDescriptors.Device_idVendor.get(deviceDesc); int productId = 0xffff & (short) USBDescriptors.Device_idProduct.get(deviceDesc); - var configDesc = getDescriptor(hubHandle, usbPortNum, - USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE, 0, (short) 0, session); + var configDesc = getDescriptor(hubHandle, usbPortNum, USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE, 0, + (short) 0, session); - var device = new WindowsUSBDevice(devicePath, vendorId, productId, manufacturer, product, serialNumber, configDesc); + var device = new WindowsUSBDevice(devicePath, vendorId, productId, manufacturer, product, serialNumber, + configDesc); int classCode = 255 & (byte) USBDescriptors.Device_bDeviceClass.get(deviceDesc); int subclassCode = 255 & (byte) USBDescriptors.Device_bDeviceSubClass.get(deviceDesc); @@ -221,17 +223,15 @@ private USBDevice createDevice(String devicePath, MemoryAddress hubHandle, int u } } - private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, - int descriptorType, int index, short languageID, - MemorySession session) { + private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, int descriptorType, int index, + short languageID, MemorySession session) { return getDescriptor(hubHandle, usbPortNumber, descriptorType, index, languageID, 0, session); } - private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, - int descriptorType, int index, short languageID, - int requestSize, MemorySession session) { + private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, int descriptorType, int index, + short languageID, int requestSize, MemorySession session) { int size = requestSize != 0 ? requestSize + (int) USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset : 256; @@ -240,10 +240,10 @@ private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, USBHelper.USB_DESCRIPTOR_REQUEST_ConnectionIndex.set(descriptorRequest, usbPortNumber); var setupPacket = descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_SetupPacket$Offset, USBStructs.SetupPacket$Struct.byteSize()); - USBStructs.SetupPacket_bmRequest.set(setupPacket, (byte) 0x80); // device-to-host / type standard / recipient device + USBStructs.SetupPacket_bmRequest.set(setupPacket, (byte) 0x80); // device-to-host / type standard / recipient + // device USBStructs.SetupPacket_bRequest.set(setupPacket, USBHelper.USB_REQUEST_GET_DESCRIPTOR); - USBStructs.SetupPacket_wValue.set(setupPacket, - (short) ((descriptorType << 8) | index)); + USBStructs.SetupPacket_wValue.set(setupPacket, (short) ((descriptorType << 8) | index)); USBStructs.SetupPacket_wIndex.set(setupPacket, languageID); USBStructs.SetupPacket_wLength.set(setupPacket, (short) (size - USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset)); @@ -251,15 +251,15 @@ private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, var effectiveSizeHolder = session.allocate(JAVA_INT); if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION(), descriptorRequest, size, descriptorRequest, size, effectiveSizeHolder, NULL) == 0) - throw new USBException(String.format("Cannot retrieve descriptor %d", index), - Kernel32.GetLastError()); + throw new USBException(String.format("Cannot retrieve descriptor %d", index), Kernel32.GetLastError()); // determine size of descriptor int expectedSize; if (descriptorType != USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE) { expectedSize = 255 & descriptorRequest.get(JAVA_BYTE, USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset); } else { - var configDesc = descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, USBDescriptors.Configuration.byteSize()); + var configDesc = descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, + USBDescriptors.Configuration.byteSize()); expectedSize = (short) USBDescriptors.Configuration_wTotalLength.get(configDesc); } @@ -281,8 +281,8 @@ private String getStringDescriptor(Addressable hubHandle, int usbPortNumber, int return null; try (var session = MemorySession.openConfined()) { - var stringDesc = getDescriptor(hubHandle, usbPortNumber, USBDescriptors.STRING_DESCRIPTOR_TYPE, - index, USBDescriptors.DEFAULT_LANGUAGE, session); + var stringDesc = getDescriptor(hubHandle, usbPortNumber, USBDescriptors.STRING_DESCRIPTOR_TYPE, index, + USBDescriptors.DEFAULT_LANGUAGE, session); int stringLen = 255 & (byte) USBHelper.USB_STRING_DESCRIPTOR_bLength.get(stringDesc); var chars = @@ -301,8 +301,9 @@ private long handleWindowMessage(MemoryAddress hWnd, int uMsg, long wParam, long if (DEV_BROADCAST_HDR.dbch_devicetype$get(data) == User32.DBT_DEVTYP_DEVICEINTERFACE()) { // get device path - var nameSlice = MemorySegment.ofAddress( - DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address(), 500, session); + var nameSlice = + MemorySegment.ofAddress(DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address(), + 500, session); var devicePath = Win.createStringFromSegment(nameSlice); if (wParam == User32.DBT_DEVICEARRIVAL()) onDeviceConnected(devicePath); @@ -356,7 +357,8 @@ private void onDeviceConnected(String devicePath) { addDevice(device); } catch (Throwable e) { - System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring device%n", devicePath); + System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring " + + "device%n", devicePath); e.printStackTrace(System.err); } } From d8c3115935a558bf604a303713c7d9d9f6f1351d Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sun, 4 Sep 2022 13:57:58 +0200 Subject: [PATCH 057/433] Check for correct transfer type --- .../codecrete/usb/common/USBDeviceImpl.java | 8 +++--- .../codecrete/usb/linux/LinuxUSBDevice.java | 5 ++-- .../codecrete/usb/macos/MacosUSBDevice.java | 26 ++++++++++++++----- .../usb/windows/WindowsUSBDevice.java | 5 ++-- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 57608e49..b8719185 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -155,7 +155,7 @@ protected USBInterfaceImpl getInterface(int interfaceNumber) { * @param direction transfer direction * @return endpoint address */ - protected byte getEndpointAddress(int endpointNumber, USBDirection direction) { + protected byte getEndpointAddress(int endpointNumber, USBDirection direction, USBTransferType transferType) { checkIsOpen(); @@ -163,14 +163,16 @@ protected byte getEndpointAddress(int endpointNumber, USBDirection direction) { for (var intf : interfaces_) { if (intf.isClaimed()) { for (var ep : intf.alternate().endpoints()) { - if (ep.number() == endpointNumber && ep.direction() == direction) + if (ep.number() == endpointNumber && ep.direction() == direction && ep.transferType() == transferType) return (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)); } } } } - throw new USBException(String.format("Endpoint number %d is not part of a claimed interface, the endpoint " + "does not operate in the %s direction or is otherwise invalid", endpointNumber, direction.name())); + throw new USBException(String.format("Endpoint number %d does not exist, is not part of a claimed interface " + + "or is not valid for %s transfer in %s direction", endpointNumber, transferType.name(), + direction.name())); } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index b6f17195..89256c88 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -10,6 +10,7 @@ import net.codecrete.usb.USBControlTransfer; import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBException; +import net.codecrete.usb.USBTransferType; import net.codecrete.usb.common.DescriptorParser; import net.codecrete.usb.common.USBDescriptors; import net.codecrete.usb.common.USBDeviceImpl; @@ -187,7 +188,7 @@ private MemorySegment createBulkTransfer(MemorySession session, byte endpointAdd @Override public void transferOut(int endpointNumber, byte[] data) { - var endpointAddress = getEndpointAddress(endpointNumber, USBDirection.OUT); + var endpointAddress = getEndpointAddress(endpointNumber, USBDirection.OUT, USBTransferType.BULK); try (var session = MemorySession.openConfined()) { var buffer = session.allocate(data.length); @@ -203,7 +204,7 @@ public void transferOut(int endpointNumber, byte[] data) { @Override public byte[] transferIn(int endpointNumber, int maxLength) { - var endpointAddress = getEndpointAddress(endpointNumber, USBDirection.IN); + var endpointAddress = getEndpointAddress(endpointNumber, USBDirection.IN, USBTransferType.BULK); try (var session = MemorySession.openConfined()) { var buffer = session.allocate(maxLength); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 7586e43c..04691547 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -10,6 +10,7 @@ import net.codecrete.usb.USBControlTransfer; import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBException; +import net.codecrete.usb.USBTransferType; import net.codecrete.usb.common.DescriptorParser; import net.codecrete.usb.common.USBDescriptors; import net.codecrete.usb.common.USBDeviceImpl; @@ -232,14 +233,15 @@ private void updateEndpointList() { int endpointNumber = numberHolder.get(JAVA_BYTE, 0) & 255; int direction = directionHolder.get(JAVA_BYTE, 0) & 255; byte endpointAddress = (byte) (endpointNumber | (direction << 7)); - var endpointInfo = new EndpointInfo(interfaceInfo.addr, (byte) pipeIndex); + byte transferType = transferTypeHolder.get(JAVA_BYTE, 0); + var endpointInfo = new EndpointInfo(interfaceInfo.addr, (byte) pipeIndex, getTransferType(transferType)); endpoints.put(endpointAddress, endpointInfo); } } } } - private EndpointInfo getEndpointInfo(int endpointNumber, USBDirection direction) { + private EndpointInfo getEndpointInfo(int endpointNumber, USBDirection direction, USBTransferType transferType) { if (endpoints != null) { byte endpointAddress = (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)); var endpointInfo = endpoints.get(endpointAddress); @@ -247,8 +249,9 @@ private EndpointInfo getEndpointInfo(int endpointNumber, USBDirection direction) return endpointInfo; } - throw new USBException(String.format("Endpoint number %d is not part of a claimed interface, the endpoint " + - "does not operate in the %s direction or is otherwise invalid", endpointNumber, direction.name())); + throw new USBException(String.format("Endpoint number %d does not exist, is not part of a claimed interface " + + "or is not valid for %s transfer in %s direction", endpointNumber, transferType.name(), + direction.name())); } private static MemorySegment createDeviceRequest(MemorySession session, USBDirection direction, @@ -299,7 +302,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { @Override public void transferOut(int endpointNumber, byte[] data) { - var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.OUT); + var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK); try (var session = MemorySession.openConfined()) { var nativeData = session.allocateArray(JAVA_BYTE, data.length); @@ -314,7 +317,7 @@ public void transferOut(int endpointNumber, byte[] data) { @Override public byte[] transferIn(int endpointNumber, int maxLength) { - var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.IN); + var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK); try (var session = MemorySession.openConfined()) { var nativeData = session.allocateArray(JAVA_BYTE, maxLength); @@ -334,13 +337,22 @@ public byte[] transferIn(int endpointNumber, int maxLength) { } } + private static USBTransferType getTransferType(byte macosTransferType) { + return switch (macosTransferType) { + case 1 -> USBTransferType.ISOCHRONOUS; + case 2 -> USBTransferType.BULK; + case 3 -> USBTransferType.INTERRUPT; + default -> null; + }; + } + record InterfaceInfo(long addr, int interfaceNumber) { MemoryAddress asAddress() { return ofLong(addr); } } - record EndpointInfo(long interfaceAddr, byte pipeIndex) { + record EndpointInfo(long interfaceAddr, byte pipeIndex, USBTransferType transferType) { MemoryAddress interfacAddress() { return ofLong(interfaceAddr); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 7d904482..b26399e9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -10,6 +10,7 @@ import net.codecrete.usb.USBControlTransfer; import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBException; +import net.codecrete.usb.USBTransferType; import net.codecrete.usb.common.DescriptorParser; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.common.USBInterfaceImpl; @@ -175,7 +176,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { @Override public void transferOut(int endpointNumber, byte[] data) { - byte endpointAddress = getEndpointAddress(endpointNumber, USBDirection.OUT); + byte endpointAddress = getEndpointAddress(endpointNumber, USBDirection.OUT, USBTransferType.BULK); try (var session = MemorySession.openConfined()) { var buffer = session.allocate(data.length); @@ -190,7 +191,7 @@ public void transferOut(int endpointNumber, byte[] data) { @Override public byte[] transferIn(int endpointNumber, int maxLength) { - byte endpointAddress = getEndpointAddress(endpointNumber, USBDirection.IN); + byte endpointAddress = getEndpointAddress(endpointNumber, USBDirection.IN, USBTransferType.BULK); try (var session = MemorySession.openConfined()) { var buffer = session.allocate(maxLength); From 7f9072545060d545a2228230668736c09c95244e Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sun, 4 Sep 2022 13:59:03 +0200 Subject: [PATCH 058/433] macOS: add missing transfer type check --- .../src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 04691547..59954fcc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -245,7 +245,7 @@ private EndpointInfo getEndpointInfo(int endpointNumber, USBDirection direction, if (endpoints != null) { byte endpointAddress = (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)); var endpointInfo = endpoints.get(endpointAddress); - if (endpointInfo != null) + if (endpointInfo != null && endpointInfo.transferType == transferType) return endpointInfo; } From e5bcde715f528cc89fe402aee08e4ea38c6121e5 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 4 Sep 2022 14:43:17 +0200 Subject: [PATCH 059/433] Linux: fix interface state issue --- .../src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 89256c88..abd3f176 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -132,6 +132,7 @@ public void releaseInterface(int interfaceNumber) { int ret = ioctl.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment.address()); if (ret != 0) throw new USBException("Cannot release USB interface", IO.getErrno()); + setClaimed(interfaceNumber, false); } } From 18ab8fbfd169889b0b809496e72329e10e8694e5 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sun, 4 Sep 2022 14:15:43 +0200 Subject: [PATCH 060/433] Updated README to reflect progress --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d5ecf010..662fea7c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Java Does USB: USB library for Java -*Java Does USB* is a library for working with USB devices from Java. It allows to communicate with USB devices other than storage devices, keyboards etc., which implement standard USB classes the operating system takes care of. Typical cases are USB devices with a custom vendor-specific protocol. +*Java Does USB* is a library for working with USB devices from Java. It allows to query information about all conntected USB devices and to communicate with USB devices using custom / vendor specific protocols. (It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc.) The library uses the [Foreign Function & Memory API](https://github.com/openjdk/panama-foreign) to access native APIs of the underlying operating system. It only uses Java code and does not need JNI or any native third-party library. @@ -52,13 +52,13 @@ MAVEN_OPTS="--enable-preview --enable-native-access=ALL-UNNAMED" mvn install exe - Enumeration of USB devices - Control transfer - Bulk transfer -- Notification about connected/disconnected devices +- Notifications about connected/disconnected devices +- Descriptive information about interfaces, settings and endpoints ### To do - Interrupt transfer - Isochronous transfer -- Descriptive information about interfaces, settings and endpoints - Alternate interface settings - Composite devices (on Windows) - Generate and publish JavaDoc documentation @@ -81,7 +81,7 @@ No special considerations apply. Using this library, a Java application can conn ### Linux -*libudev* is used to discover and monitor USB devices. The library is closely tied to *systemd*. So it only runs on Linux distributions with systemd and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfills this requriement. +*libudev* is used to discover and monitor USB devices. The library is closely tied to *systemd*. So it only runs on Linux distributions with systemd and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfill this requriement. Similar to macOS, a Java application can connect to any USB device and claim any interfaces that aren't claimed by an operating system driver or another application. @@ -93,18 +93,18 @@ Create a file called `/etc/udev/rules.d/80-javadoesusb-udev.rules` with the belo SUBSYSTEM=="usb", ATTRS{idVendor}=="cafe", MODE="0666" ``` -This adds the rule to assign permission mode 0666 to all USB devices with vendor ID `0xCAFE`. This non-register vendor ID is used by test device. +This adds the rule to assign permission mode 0666 to all USB devices with vendor ID `0xCAFE`. This unregistered vendor ID is used by test device. ### Windows -The Windows driver model is more rigid than the ones of macOS or Linux. It's not possible to open any USB device by default. Instead, only devices using the WinUSB driver can be opened. This even applies to devices with no installed driver. +The Windows driver model is more rigid than the ones of macOS or Linux. It's not possible to open any USB device by default. Instead, only devices using the *WinUSB* driver can be opened. This even applies to devices with no installed driver. USB devices can implement certain control requests to instruct Windows to automatically install the WinUSB driver (search for WCID or Microsoft OS Compatibility Descriptors). The driver can also be manually installed or replaced using a software called [Zadig](https://zadig.akeo.ie/). -The test device implements these control requests. So the driver is installed automatically. +The test device implements the required control requests. So the driver is installed automatically. -This library does not yet run reliably on Windows as Java VM sometimes overwrites the last error code, which is not just needed in error cases. It works incorrectly when run in the debugger and sometimes even without the debugger. A future version of the Foreign Function & Memory API will hopefully provide a way to save the last error code. The developers are aware of the issue. +This library does not yet run reliably on Windows as the Java VM sometimes overwrites the last error code, which is needed for proper function, not just in error cases. It works incorrectly when run in the debugger and sometimes even without the debugger. A future version of the Foreign Function & Memory API will hopefully provide a way to save the last error code. The developers are aware of the issue. The library has not been tested on Windows for ARM64. It might or might not work. From c884771419c490e06eb258753a7507f314f6ed80 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sun, 4 Sep 2022 14:59:59 +0200 Subject: [PATCH 061/433] Validate with OpenJDK 19.0.77 EA 34 --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 662fea7c..d838b3fc 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ The Foreign Function & Memory API (aka as project Panama) is in preview and will - Java 19 Early Access, preview features enabled (available at https://www.azul.com/downloads/?package=jdk) - Windows (x86 64-bit), macOS (x86 64-bit, ARM 64-bit) or Linux 64 bit (x86 64-bit, ARM 64-bit) -It has been tested with Azul Zulu 19.0.75 EA 33. +It has been tested with Azul Zulu 19.0.77 EA 34. ## Testing @@ -63,6 +63,7 @@ MAVEN_OPTS="--enable-preview --enable-native-access=ALL-UNNAMED" mvn install exe - Composite devices (on Windows) - Generate and publish JavaDoc documentation - Make library available on Maven Central +- Standalone examples ### Not planned @@ -112,3 +113,9 @@ The library has not been tested on Windows for ARM64. It might or might not work ### 32-bit versions The Foreign Function & Memory API has not been implemented for 32-bit operating systems / JDKs. So it does not support them (and likely never will). + + + +## Code generation + +Many of the bindings for the native APIs have been generated with *jextract*. See the [jextract](java-does-usb/jextract) subdirectory for more information. From 16bee0b3601b99c43107edfb63a35dcefb52ec7f Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sun, 4 Sep 2022 20:37:45 +0200 Subject: [PATCH 062/433] Properly close device on disconnect --- .../codecrete/usb/common/USBDeviceRegistry.java | 15 +++++++++++++++ .../usb/linux/LinuxUSBDeviceRegistry.java | 2 +- .../usb/windows/WindowsUSBDeviceRegistry.java | 4 ++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index a314be68..a7818bfe 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -175,6 +175,21 @@ protected void addDevice(USBDevice device) { emitOnDeviceConnected(device); } + protected void closeAndRemoveDevice(Object deviceId) { + var device = findDevice(deviceId); + if (device == null) + return; + + try { + device.close(); + } catch (Throwable e) { + System.err.println("Info: [JavaDoesUSB] failed to close USB device - ignoring exception"); + e.printStackTrace(System.err); + } + + removeDevice(deviceId); + } + /** * Removes a device from the list of connected USB devices. * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 18dcbd94..2a793579 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -154,7 +154,7 @@ private void onDeviceDisconnected(MemoryAddress udevDevice) { if (devPath == null) return; - removeDevice(devPath); + closeAndRemoveDevice(devPath); } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 77c40fae..cb197091 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -13,6 +13,7 @@ import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.common.USBDeviceRegistry; import net.codecrete.usb.common.USBStructs; +import net.codecrete.usb.macos.MacosUSBDevice; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.setupapi.SP_DEVICE_INTERFACE_DATA; import net.codecrete.usb.windows.gen.setupapi.SP_DEVINFO_DATA; @@ -365,8 +366,7 @@ private void onDeviceConnected(String devicePath) { } private void onDeviceDisconnected(String devicePath) { - // remove from device list - removeDevice(devicePath); + closeAndRemoveDevice(devicePath); } /** From 125e95e5d810810703bcb25bda57d5d78f0308bd Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 5 Sep 2022 23:10:46 +0200 Subject: [PATCH 063/433] macOS: use jextract --- java-does-usb/jextract/README.md | 16 +- java-does-usb/jextract/gen_macos.sh | 19 - .../jextract/{ => linux}/gen_linux.sh | 4 +- java-does-usb/jextract/macos/cf_helper.h | 1 + .../jextract/macos/compile_flags.txt | 1 + java-does-usb/jextract/macos/gen_macos.sh | 67 + java-does-usb/jextract/macos/iokit_helper.h | 2 + .../usb/macos/gen/mach/Constants$root.java | 23 + .../usb/macos/gen/mach/RuntimeHelper.java | 233 ++ .../usb/macos/gen/mach/constants$0.java | 21 + .../codecrete/usb/macos/gen/mach/mach.java | 34 + .../{ => windows}/gen_win_kernel32.cmd | 4 +- .../{ => windows}/gen_win_setupapi.cmd | 4 +- .../jextract/{ => windows}/gen_win_stdlib.cmd | 4 +- .../{ => windows}/gen_win_usbioctl.cmd | 4 +- .../jextract/{ => windows}/gen_win_user32.cmd | 4 +- .../jextract/{ => windows}/gen_win_winusb.cmd | 4 +- .../jextract/{ => windows}/windows_headers.h | 0 .../codecrete/usb/macos/CoreFoundation.java | 274 -- .../usb/macos/CoreFoundationHelper.java | 9 +- .../java/net/codecrete/usb/macos/IoKit.java | 275 -- .../net/codecrete/usb/macos/IoKitHelper.java | 64 +- .../net/codecrete/usb/macos/IoKitUSB.java | 525 +-- .../codecrete/usb/macos/MacosUSBDevice.java | 70 +- .../usb/macos/MacosUSBDeviceRegistry.java | 28 +- .../java/net/codecrete/usb/macos/UUID.java | 50 + .../usb/macos/gen/corefoundation/CFRange.java | 56 + .../macos/gen/corefoundation/CFUUIDBytes.java | 294 ++ .../gen/corefoundation/Constants$root.java | 19 + .../gen/corefoundation/CoreFoundation.java | 159 + .../gen/corefoundation/RuntimeHelper.java | 217 + .../macos/gen/corefoundation/constants$0.java | 59 + .../macos/gen/corefoundation/constants$1.java | 70 + .../usb/macos/gen/iokit/Constants$root.java | 19 + .../macos/gen/iokit/IOCFPlugInInterface.java | 9 + .../gen/iokit/IOCFPlugInInterfaceStruct.java | 363 ++ .../codecrete/usb/macos/gen/iokit/IOKit.java | 167 + .../usb/macos/gen/iokit/IOUSBDevRequest.java | 142 + .../macos/gen/iokit/IOUSBDeviceInterface.java | 9 + .../macos/gen/iokit/IOUSBDeviceStruct942.java | 2317 +++++++++++ .../gen/iokit/IOUSBFindInterfaceRequest.java | 90 + .../gen/iokit/IOUSBInterfaceInterface.java | 9 + .../gen/iokit/IOUSBInterfaceStruct942.java | 3596 +++++++++++++++++ .../usb/macos/gen/iokit/RuntimeHelper.java | 217 + .../usb/macos/gen/iokit/constants$0.java | 50 + .../usb/macos/gen/iokit/constants$1.java | 61 + .../usb/macos/gen/iokit/constants$2.java | 12 + 47 files changed, 8566 insertions(+), 1109 deletions(-) delete mode 100755 java-does-usb/jextract/gen_macos.sh rename java-does-usb/jextract/{ => linux}/gen_linux.sh (96%) create mode 100644 java-does-usb/jextract/macos/cf_helper.h create mode 100644 java-does-usb/jextract/macos/compile_flags.txt create mode 100755 java-does-usb/jextract/macos/gen_macos.sh create mode 100644 java-does-usb/jextract/macos/iokit_helper.h create mode 100644 java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java create mode 100644 java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java create mode 100644 java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java create mode 100644 java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java rename java-does-usb/jextract/{ => windows}/gen_win_kernel32.cmd (89%) rename java-does-usb/jextract/{ => windows}/gen_win_setupapi.cmd (91%) rename java-does-usb/jextract/{ => windows}/gen_win_stdlib.cmd (64%) rename java-does-usb/jextract/{ => windows}/gen_win_usbioctl.cmd (79%) rename java-does-usb/jextract/{ => windows}/gen_win_user32.cmd (90%) rename java-does-usb/jextract/{ => windows}/gen_win_winusb.cmd (83%) rename java-does-usb/jextract/{ => windows}/windows_headers.h (100%) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundation.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterface.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct942.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct942.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$1.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$2.java diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index bd23301e..9d1bf3a8 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -33,26 +33,22 @@ On Linux, *jextract* is very successful. The only limitations are: - `libudev.h`: After code generation, the class `RuntimeHelper.java` in `.../linux/gen/udev` must be manually modified as the code to access the library does not work for the directory the library is located in. So replace: ``` - System.loadLibrary("udev"); - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); +System.loadLibrary("udev"); +SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); ``` with: ``` - SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so", MemorySession.openImplicit()); +SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so", MemorySession.openImplicit()); ``` ## MacOS -Most of the required native function on macOS are part of a framework. Framework internally have a more complex file organization of header and binary files than appears on the outside. Thus they require a special logic to locate framework header files. *clang* supports it with the `-F` and `-iframework`. *jextract* does not support it. The result is that only a single function is generated. The binding code for all other functions and data structures is written manually. +Most of the required native functions on macOS are part of a framework. Framework internally have a more complex file organization of header and binary files than appears on the outside. Thus they require a special logic to locate framework header files. *clang* supports it with the `-F`. *jextract* allows to specify the options via `compiler_flags.txt` file. Since the file must be in the local directory and since it does not apply to Linux and Windows, separate directories must be used for the operating systems. -Loading framework libraries at runtime also requires special support. That is already built in and working nicely, e.g. to load the *IOKit* framework, below code can be used. - -``` -SymbolLookup ioKitLookup SymbolLookup.libraryLookup("IOKit.framework/IOKit", MemorySession.openImplicit()); -``` +The generated code has the same problem as the Linux code for *udev*. It must be manually changed to use `SymbolLookup.libraryLookup()` for the libraries `CoreFoundation.framework/CoreFoundation` and `IOKit.framework/IOKit` respectively. ## Windows @@ -69,4 +65,4 @@ The known limitations are: - `USB_NODE_CONNECTION_INFORMATION_EX`: This struct uses a packed layout without considering alignment. The last four members are on an offset even though they are multiple bytes long. *jextract* creates the correct offsets but defines strict alignment constraints for the members. So the memory layout cannot be instantiated as it throws an exception. -- GUID constants like `GUID_DEVINTERFACE_USB_DEVICE` do not work. While code is generated, the code fails at run-time as it is unable to locate the symbol. This is most likely due to the fact that the constant isn't in any native library at all. Rather they are defined in file that uses them and then multiple copies are discarded at link time using [`__declspec(selectany)`](https://docs.microsoft.com/en-us/cpp/cpp/selectany?view=msvc-170). +- GUID constants like `GUID_DEVINTERFACE_USB_DEVICE` do not work. While code is generated, the code fails at run-time as it is unable to locate the symbol. This is due to the fact that `GUID_DEVINTERFACE_USB_DEVICE` actually resolve to a variable defintion and not to a variable declaration. So there is no such symbol in any library. Such constants should be skipped by *jextract*. diff --git a/java-does-usb/jextract/gen_macos.sh b/java-does-usb/jextract/gen_macos.sh deleted file mode 100755 index ce77e369..00000000 --- a/java-does-usb/jextract/gen_macos.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -JEXTRACT=../../../jextract-19/bin/jextract -SDK_DIR=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk - -# CoreFoundation -#$JEXTRACT --source --output ../src/main/java \ -# -I $SDK_DIR/usr/include \ -# --target-package net.codecrete.usb.macos.gen.corefoundation -# --include-function CFUUIDCreateFromUUIDBytes \ -# $SDK_DIR/System/Library/Frameworks/CoreFoundation.framework/Versions/A/Headers/CoreFoundation.h - -# mach.h -$JEXTRACT --source --output ../src/main/java \ - -I $SDK_DIR/usr/include \ - --header-class-name mach \ - --target-package net.codecrete.usb.macos.gen.mach \ - --include-function mach_error_string \ - $SDK_DIR/usr/include/mach/mach.h diff --git a/java-does-usb/jextract/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh similarity index 96% rename from java-does-usb/jextract/gen_linux.sh rename to java-does-usb/jextract/linux/gen_linux.sh index 40cbd3ff..1c74089e 100755 --- a/java-does-usb/jextract/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -1,6 +1,6 @@ #!/bin/sh -JEXTRACT=../../../jextract-19/bin/jextract +JEXTRACT=../../../../jextract-19/bin/jextract # sd-device.h (install libsystemd-dev if file is missing) # Error: /usr/include/inttypes.h:290:8: error: unknown type name 'intmax_t' @@ -11,7 +11,7 @@ JEXTRACT=../../../jextract-19/bin/jextract # /usr/include/systemd/sd-device.h # errno.h -$JEXTRACT --source --output ../src/main/java \ +$JEXTRACT --source --output ../../src/main/java \ --header-class-name errno \ --target-package net.codecrete.usb.linux.gen.errno \ --include-function __errno_location \ diff --git a/java-does-usb/jextract/macos/cf_helper.h b/java-does-usb/jextract/macos/cf_helper.h new file mode 100644 index 00000000..809392b1 --- /dev/null +++ b/java-does-usb/jextract/macos/cf_helper.h @@ -0,0 +1 @@ +#include diff --git a/java-does-usb/jextract/macos/compile_flags.txt b/java-does-usb/jextract/macos/compile_flags.txt new file mode 100644 index 00000000..f8512b49 --- /dev/null +++ b/java-does-usb/jextract/macos/compile_flags.txt @@ -0,0 +1 @@ +-F/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks \ No newline at end of file diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh new file mode 100755 index 00000000..03ffa77c --- /dev/null +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -0,0 +1,67 @@ +#!/bin/sh + +JEXTRACT=../../../../jextract-19/bin/jextract +# If SDK_DIR is changed, it needs to be changed in compiler flags as well. +SDK_DIR=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk + +# CoreFoundation +$JEXTRACT --source --output ../../src/main/java \ + -I $SDK_DIR/usr/include \ + -lCoreFoundation.framework \ + --header-class-name CoreFoundation \ + --target-package net.codecrete.usb.macos.gen.corefoundation \ + --include-typedef CFRange \ + --include-typedef CFUUIDBytes \ + --include-function CFUUIDCreateFromUUIDBytes \ + --include-function CFRelease \ + --include-function CFStringGetLength \ + --include-function CFStringGetCharacters \ + --include-function CFStringCreateWithCharacters \ + --include-function CFGetTypeID \ + --include-function CFNumberGetTypeID \ + --include-function CFStringGetTypeID \ + --include-function CFNumberGetValue \ + --include-function CFRunLoopGetCurrent \ + --include-function CFRunLoopAddSource \ + --include-function CFRunLoopRun \ + --include-macro kCFNumberSInt32Type \ + cf_helper.h + +# IOKit +$JEXTRACT --source --output ../../src/main/java \ + -I $SDK_DIR/usr/include \ + -lIOKit.framework \ + --header-class-name IOKit \ + --target-package net.codecrete.usb.macos.gen.iokit \ + --include-var kIOMasterPortDefault \ + --include-macro kIOUSBDeviceClassName \ + --include-macro kIOFirstMatchNotification \ + --include-macro kIOTerminatedNotification \ + --include-var kCFRunLoopDefaultMode \ + --include-struct IOCFPlugInInterfaceStruct \ + --include-typedef IOCFPlugInInterface \ + --include-function IOObjectRelease \ + --include-function IOIteratorNext \ + --include-function IOCreatePlugInInterfaceForService \ + --include-function IORegistryEntryCreateCFProperty \ + --include-function IONotificationPortCreate \ + --include-function IONotificationPortGetRunLoopSource \ + --include-function IORegistryEntryGetRegistryEntryID \ + --include-function IOServiceAddMatchingNotification \ + --include-function IOServiceMatching \ + --include-struct IOUSBDeviceStruct942 \ + --include-typedef IOUSBDeviceInterface \ + --include-macro kIOUSBFindInterfaceDontCare \ + --include-typedef IOUSBFindInterfaceRequest \ + --include-typedef IOUSBDevRequest \ + --include-struct IOUSBInterfaceStruct942 \ + --include-typedef IOUSBInterfaceInterface \ + iokit_helper.h + +# mach.h +$JEXTRACT --source --output ../src/main/java \ + -I $SDK_DIR/usr/include \ + --header-class-name mach \ + --target-package net.codecrete.usb.macos.gen.mach \ + --include-function mach_error_string \ + $SDK_DIR/usr/include/mach/mach.h diff --git a/java-does-usb/jextract/macos/iokit_helper.h b/java-does-usb/jextract/macos/iokit_helper.h new file mode 100644 index 00000000..39764e5f --- /dev/null +++ b/java-does-usb/jextract/macos/iokit_helper.h @@ -0,0 +1,2 @@ +#include +#include diff --git a/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java b/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java new file mode 100644 index 00000000..f9a32fff --- /dev/null +++ b/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java @@ -0,0 +1,23 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.mach; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +import java.nio.ByteOrder; +import java.lang.foreign.*; +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java b/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java new file mode 100644 index 00000000..ca772f77 --- /dev/null +++ b/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java @@ -0,0 +1,233 @@ +package net.codecrete.usb.macos.gen.mach; +// Generated by jextract + +import java.lang.foreign.Addressable; +import java.lang.foreign.Linker; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.io.File; +import java.nio.file.Path; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Optional; +import java.util.stream.Stream; + +import static java.lang.foreign.Linker.*; +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java b/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java new file mode 100644 index 00000000..95f87255 --- /dev/null +++ b/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java @@ -0,0 +1,21 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.mach; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +import java.nio.ByteOrder; +import java.lang.foreign.*; +import static java.lang.foreign.ValueLayout.*; +class constants$0 { + + static final FunctionDescriptor mach_error_string$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle mach_error_string$MH = RuntimeHelper.downcallHandle( + "mach_error_string", + constants$0.mach_error_string$FUNC + ); +} + + diff --git a/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java b/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java new file mode 100644 index 00000000..83147348 --- /dev/null +++ b/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java @@ -0,0 +1,34 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.mach; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +import java.nio.ByteOrder; +import java.lang.foreign.*; +import static java.lang.foreign.ValueLayout.*; +public class mach { + + /* package-private */ mach() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static MethodHandle mach_error_string$MH() { + return RuntimeHelper.requireNonNull(constants$0.mach_error_string$MH,"mach_error_string"); + } + public static MemoryAddress mach_error_string ( int error_value) { + var mh$ = mach_error_string$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(error_value); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } +} + + diff --git a/java-does-usb/jextract/gen_win_kernel32.cmd b/java-does-usb/jextract/windows/gen_win_kernel32.cmd similarity index 89% rename from java-does-usb/jextract/gen_win_kernel32.cmd rename to java-does-usb/jextract/windows/gen_win_kernel32.cmd index b591e50c..9a861e1d 100644 --- a/java-does-usb/jextract/gen_win_kernel32.cmd +++ b/java-does-usb/jextract/windows/gen_win_kernel32.cmd @@ -1,6 +1,6 @@ -set JEXTRACT=..\..\..\jextract-19\bin\jextract.bat +set JEXTRACT=..\..\..\..\jextract-19\bin\jextract.bat set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 -%JEXTRACT% --source --output ../src/main/java ^ +%JEXTRACT% --source --output ../../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -I "%SDK_DIR%\um" ^ -I "%SDK_DIR%\shared" ^ diff --git a/java-does-usb/jextract/gen_win_setupapi.cmd b/java-does-usb/jextract/windows/gen_win_setupapi.cmd similarity index 91% rename from java-does-usb/jextract/gen_win_setupapi.cmd rename to java-does-usb/jextract/windows/gen_win_setupapi.cmd index c027cc38..53b3b335 100644 --- a/java-does-usb/jextract/gen_win_setupapi.cmd +++ b/java-does-usb/jextract/windows/gen_win_setupapi.cmd @@ -1,6 +1,6 @@ -set JEXTRACT=..\..\..\jextract-19\bin\jextract.bat +set JEXTRACT=..\..\..\..\jextract-19\bin\jextract.bat set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 -%JEXTRACT% --source --output ../src/main/java ^ +%JEXTRACT% --source --output ../../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -I "%SDK_DIR%\um" ^ -I "%SDK_DIR%\shared" ^ diff --git a/java-does-usb/jextract/gen_win_stdlib.cmd b/java-does-usb/jextract/windows/gen_win_stdlib.cmd similarity index 64% rename from java-does-usb/jextract/gen_win_stdlib.cmd rename to java-does-usb/jextract/windows/gen_win_stdlib.cmd index e56b841f..bc23beb8 100644 --- a/java-does-usb/jextract/gen_win_stdlib.cmd +++ b/java-does-usb/jextract/windows/gen_win_stdlib.cmd @@ -1,5 +1,5 @@ -set JEXTRACT=..\..\..\jextract-19\bin\jextract.bat -%JEXTRACT% --source --output ../src/main/java ^ +set JEXTRACT=..\..\..\..\jextract-19\bin\jextract.bat +%JEXTRACT% --source --output ../../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ --header-class-name StdLib ^ --target-package net.codecrete.usb.windows.gen.stdlib ^ diff --git a/java-does-usb/jextract/gen_win_usbioctl.cmd b/java-does-usb/jextract/windows/gen_win_usbioctl.cmd similarity index 79% rename from java-does-usb/jextract/gen_win_usbioctl.cmd rename to java-does-usb/jextract/windows/gen_win_usbioctl.cmd index 6710f2ce..ccb9402a 100644 --- a/java-does-usb/jextract/gen_win_usbioctl.cmd +++ b/java-does-usb/jextract/windows/gen_win_usbioctl.cmd @@ -1,6 +1,6 @@ -set JEXTRACT=..\..\..\jextract-19\bin\jextract.bat +set JEXTRACT=..\..\..\..\jextract-19\bin\jextract.bat set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 -%JEXTRACT% --source --output ../src/main/java ^ +%JEXTRACT% --source --output ../../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -I "%SDK_DIR%\um" ^ -I "%SDK_DIR%\shared" ^ diff --git a/java-does-usb/jextract/gen_win_user32.cmd b/java-does-usb/jextract/windows/gen_win_user32.cmd similarity index 90% rename from java-does-usb/jextract/gen_win_user32.cmd rename to java-does-usb/jextract/windows/gen_win_user32.cmd index 5dd02fd5..3a17da1a 100644 --- a/java-does-usb/jextract/gen_win_user32.cmd +++ b/java-does-usb/jextract/windows/gen_win_user32.cmd @@ -1,6 +1,6 @@ -set JEXTRACT=..\..\..\jextract-19\bin\jextract.bat +set JEXTRACT=..\..\..\..\jextract-19\bin\jextract.bat set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 -%JEXTRACT% --source --output ../src/main/java ^ +%JEXTRACT% --source --output ../../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -I "%SDK_DIR%\um" ^ -I "%SDK_DIR%\shared" ^ diff --git a/java-does-usb/jextract/gen_win_winusb.cmd b/java-does-usb/jextract/windows/gen_win_winusb.cmd similarity index 83% rename from java-does-usb/jextract/gen_win_winusb.cmd rename to java-does-usb/jextract/windows/gen_win_winusb.cmd index e059905c..b1ed1327 100644 --- a/java-does-usb/jextract/gen_win_winusb.cmd +++ b/java-does-usb/jextract/windows/gen_win_winusb.cmd @@ -1,6 +1,6 @@ -set JEXTRACT=..\..\..\jextract-19\bin\jextract.bat +set JEXTRACT=..\..\..\..\jextract-19\bin\jextract.bat set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 -%JEXTRACT% --source --output ../src/main/java ^ +%JEXTRACT% --source --output ../../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -I "%SDK_DIR%\um" ^ -I "%SDK_DIR%\shared" ^ diff --git a/java-does-usb/jextract/windows_headers.h b/java-does-usb/jextract/windows/windows_headers.h similarity index 100% rename from java-does-usb/jextract/windows_headers.h rename to java-does-usb/jextract/windows/windows_headers.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundation.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundation.java deleted file mode 100644 index de430987..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundation.java +++ /dev/null @@ -1,274 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.macos; - -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.MemoryLayout.sequenceLayout; -import static java.lang.foreign.MemoryLayout.structLayout; -import static java.lang.foreign.ValueLayout.*; - -/** - * Constants and functions for the Core Foundation framework. - *

- * In the future, jextract will hopefully be able to generate code for - * macOS frameworks in order to generate most of this. - *

- */ -public class CoreFoundation { - // Fixed-width types - public static final long kCFNumberSInt8Type = 1; - public static final long kCFNumberSInt16Type = 2; - public static final long kCFNumberSInt32Type = 3; - public static final long kCFNumberSInt64Type = 4; - public static final long kCFNumberFloat32Type = 5; - public static final long kCFNumberFloat64Type = 6; // 64-bit IEEE 754 - // Basic C types - public static final long kCFNumberCharType = 7; - public static final long kCFNumberShortType = 8; - public static final long kCFNumberIntType = 9; - public static final long kCFNumberLongType = 10; - public static final long kCFNumberLongLongType = 11; - public static final long kCFNumberFloatType = 12; - public static final long kCFNumberDoubleType = 13; - // Other - public static final long kCFNumberCFIndexType = 14; - public static final long kCFNumberNSIntegerType = 15; - public static final long kCFNumberCGFloatType = 16; - - private static final Linker linker = Linker.nativeLinker(); - private static final MemorySession cfSession = MemorySession.openShared(); - private static final SymbolLookup coreFoundationLookup = SymbolLookup.libraryLookup("CoreFoundation.framework/CoreFoundation", cfSession); - - public static final GroupLayout CFUUIDBytes = structLayout( - JAVA_BYTE.withName("byte0"), - JAVA_BYTE.withName("byte1"), - JAVA_BYTE.withName("byte2"), - JAVA_BYTE.withName("byte3"), - JAVA_BYTE.withName("byte4"), - JAVA_BYTE.withName("byte5"), - JAVA_BYTE.withName("byte6"), - JAVA_BYTE.withName("byte7"), - JAVA_BYTE.withName("byte8"), - JAVA_BYTE.withName("byte9"), - JAVA_BYTE.withName("byte10"), - JAVA_BYTE.withName("byte11"), - JAVA_BYTE.withName("byte12"), - JAVA_BYTE.withName("byte13"), - JAVA_BYTE.withName("byte14"), - JAVA_BYTE.withName("byte15") - ); - - public static final GroupLayout CFUUID = structLayout( - ADDRESS.withName("_cfisa"), // uintptr_t _cfisa; - sequenceLayout(4, JAVA_BYTE).withName("_cfinfo"), // uint8_t _cfinfo[4]; - JAVA_INT.withName("_rc"), // uint32_t _rc; - CFUUIDBytes.withName("_bytes") // CFUUIDBytes _bytes; - ); - public static final long CFUUID_bytes$Offset = CFUUID.byteOffset(MemoryLayout.PathElement.groupElement("_bytes")); - - public static final GroupLayout CFRange = structLayout( - JAVA_LONG.withName("location"), - JAVA_LONG.withName("range") - ); - public static final VarHandle CFRange_location = CFRange.varHandle(MemoryLayout.PathElement.groupElement("location")); - public static final VarHandle CFRange_range = CFRange.varHandle(MemoryLayout.PathElement.groupElement("range")); - - // CFUUIDRef CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc, CFUUIDBytes bytes); - private static final MethodHandle CFUUIDCreateFromUUIDBytes$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFUUIDCreateFromUUIDBytes").get(), - FunctionDescriptor.of( - ADDRESS, ADDRESS, CFUUIDBytes - ) - ); - public static MemoryAddress CFUUIDCreateFromUUIDBytes(Addressable allocator, byte[] bytes) { - try (var session = MemorySession.openConfined()) { - var uuidBytes = session.allocate(16); - uuidBytes.asByteBuffer().put(bytes); - return (MemoryAddress) CFUUIDCreateFromUUIDBytes$Func.invokeExact(allocator, uuidBytes); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // CFStringRef CFUUIDCreateString(CFAllocatorRef alloc, CFUUIDRef uuid); - private static final MethodHandle CFUUIDCreateString$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFUUIDCreateString").get(), - FunctionDescriptor.of( - ADDRESS, ADDRESS, ADDRESS - ) - ); - public static String CFUUIDCreateString(Addressable allocator, Addressable uuid) { - try { - MemoryAddress str = (MemoryAddress) CFUUIDCreateString$Func.invokeExact(allocator, uuid); - String result = CoreFoundationHelper.stringFromCFStringRef(str); - CFRelease(str); - return result; - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // void CFRelease(CFTypeRef cf); - private static final MethodHandle CFRelease$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFRelease").get(), - FunctionDescriptor.ofVoid(ADDRESS) - ); - public static void CFRelease(Addressable object) { - try { - CFRelease$Func.invokeExact(object); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // CFIndex CFStringGetLength(CFStringRef theString); - private static final MethodHandle CFStringGetLength$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFStringGetLength").get(), - FunctionDescriptor.of(JAVA_LONG, ADDRESS) - ); - public static long CFStringGetLength(Addressable str) { - try { - return (long) CFStringGetLength$Func.invokeExact(str); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // void CFStringGetCharacters(CFStringRef theString, CFRange range, UniChar *buffer); - private static final MethodHandle CFStringGetCharacters$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFStringGetCharacters").get(), - FunctionDescriptor.ofVoid(ADDRESS, CFRange, ADDRESS) - ); - public static void CFStringGetCharacters(Addressable str, MemorySegment range, Addressable buffer) { - try { - CFStringGetCharacters$Func.invokeExact(str, range, buffer); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, const UniChar *chars, CFIndex numChars); - private static final MethodHandle CFStringCreateWithCharacters$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFStringCreateWithCharacters").get(), - FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, JAVA_LONG) - ); - public static MemoryAddress CFStringCreateWithCharacters(Addressable allocator, Addressable chars, long numChars) { - try { - return (MemoryAddress) CFStringCreateWithCharacters$Func.invokeExact(allocator, chars, numChars); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // CFTypeID CFGetTypeID(CFTypeRef cf); - private static final MethodHandle CFGetTypeID$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFGetTypeID").get(), - FunctionDescriptor.of(JAVA_LONG, ADDRESS) - ); - public static long CFGetTypeID(Addressable cf) { - try { - return (long) CFGetTypeID$Func.invokeExact(cf); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // CFTypeID CFNumberGetTypeID(void); - private static final MethodHandle CFNumberGetTypeID$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFNumberGetTypeID").get(), - FunctionDescriptor.of(JAVA_LONG) - ); - public static long CFNumberGetTypeID() { - try { - return (long) CFNumberGetTypeID$Func.invokeExact(); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // CFTypeID CFStringGetTypeID(void); - private static final MethodHandle CFStringGetTypeID$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFStringGetTypeID").get(), - FunctionDescriptor.of(JAVA_LONG) - ); - public static long CFStringGetTypeID() { - try { - return (long) CFStringGetTypeID$Func.invokeExact(); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // CFNumberType CFNumberGetType(CFNumberRef number); - private static final MethodHandle CFNumberGetType$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFNumberGetType").get(), - FunctionDescriptor.of(JAVA_LONG, ADDRESS) - ); - public static long CFNumberGetType(Addressable number) { - try { - return (long) CFNumberGetType$Func.invokeExact(number); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void *valuePtr); - private static final MethodHandle CFNumberGetValue$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFNumberGetValue").get(), - FunctionDescriptor.of(JAVA_BOOLEAN, ADDRESS, JAVA_LONG, ADDRESS) - ); - public static boolean CFNumberGetValue(Addressable number, long theType, Addressable valuePtr) { - try { - return (boolean) CFNumberGetValue$Func.invokeExact(number, theType, valuePtr); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // CFRunLoopRef CFRunLoopGetCurrent(void); - private static final MethodHandle CFRunLoopGetCurrent$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFRunLoopGetCurrent").get(), - FunctionDescriptor.of(ADDRESS) - ); - public static MemoryAddress CFRunLoopGetCurrent() { - try { - return (MemoryAddress) CFRunLoopGetCurrent$Func.invokeExact(); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode); - private static final MethodHandle CFRunLoopAddSource$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFRunLoopAddSource").get(), - FunctionDescriptor.ofVoid(ADDRESS, ADDRESS, ADDRESS) - ); - public static void CFRunLoopAddSource(Addressable runLoop, Addressable source, Addressable mode) { - try { - CFRunLoopAddSource$Func.invokeExact(runLoop, source, mode); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // void CFRunLoopRun(void); - private static final MethodHandle CFRunLoopRun$Func = linker.downcallHandle( - coreFoundationLookup.lookup("CFRunLoopRun").get(), - FunctionDescriptor.ofVoid() - ); - public static void CFRunLoopRun() { - try { - CFRunLoopRun$Func.invokeExact(); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java index b589abdd..6c663f8a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java @@ -7,6 +7,9 @@ package net.codecrete.usb.macos; +import net.codecrete.usb.macos.gen.corefoundation.CFRange; +import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; + import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; @@ -31,9 +34,9 @@ public static String stringFromCFStringRef(MemoryAddress string) { long strLen = CoreFoundation.CFStringGetLength(string); var buffer = session.allocateArray(JAVA_CHAR, strLen); - var range = session.allocate(CoreFoundation.CFRange); - CoreFoundation.CFRange_location.set(range, 0); - CoreFoundation.CFRange_range.set(range, strLen); + var range = session.allocate(CFRange.$LAYOUT()); + CFRange.location$set(range, 0); + CFRange.length$set(range, strLen); CoreFoundation.CFStringGetCharacters(string, range, buffer); return new String(buffer.toArray(JAVA_CHAR)); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java deleted file mode 100644 index 1c284ac9..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKit.java +++ /dev/null @@ -1,275 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.macos; - -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.MemoryAddress.NULL; -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.*; -import static net.codecrete.usb.macos.CoreFoundation.CFUUIDBytes; -import static net.codecrete.usb.macos.CoreFoundationHelper.createCFStringRef; - -/** - * Constants and functions for the IOKit framework. - *

- * In the future, jextract will hopefully be able to generate code for - * macOS frameworks in order to generate most of this. - *

- */ -public class IoKit { - - private static final Linker linker = Linker.nativeLinker(); - private static final MemorySession ioKitSession = MemorySession.openShared(); - private static final SymbolLookup ioKitLookup = SymbolLookup.libraryLookup("IOKit.framework/IOKit", ioKitSession); - - public static final int kIOMasterPortDefault; - public static final int kIORegistryIterateRecursively = 1; - - public static final MemorySegment kIOUSBDeviceClassName = ioKitSession.allocateUtf8String("IOUSBDevice"); - public static final MemorySegment kIOFirstMatchNotification = ioKitSession.allocateUtf8String( - "IOServiceFirstMatch"); - public static final MemorySegment kIOTerminatedNotification = ioKitSession.allocateUtf8String("IOServiceTerminate"); - - public static final MemoryAddress kCFRunLoopDefaultMode = createCFStringRef("kCFRunLoopDefaultMode"); - - public static final GroupLayout IOCFPlugInInterface$Struct = MemoryLayout.structLayout(ADDRESS.withName( - "_reserved"), // void *_reserved; - ADDRESS.withName("QueryInterface"), // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, - // REFIID iid, LPVOID *ppv); - ADDRESS.withName("AddRef"), // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); - ADDRESS.withName("Release"), // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); - JAVA_SHORT.withName("version"), // UInt16 version; - JAVA_SHORT.withName("revision"), // UInt16 revision; - ADDRESS.withName("Probe"), // IOReturn (*Probe)(void *thisPointer, CFDictionaryRef propertyTable, - // io_service_t service, SInt32 * order); - ADDRESS.withName("Start"), // IOReturn (*Start)(void *thisPointer, CFDictionaryRef propertyTable, - // io_service_t service); - ADDRESS.withName("Stop") // IOReturn (*Stop)(void *thisPointer); - ); - - /** - * Looks up the address of the specified virtual function in the {@code IOCFPlugInInterface} object - * - * @param thisPointer pointer to pointer to object - * @param varHandle variable handle to virtual function - * @param session memory session - * @return function address - */ - private static Addressable IOCFPlugInInterfaceFunctionAddress(MemoryAddress thisPointer, VarHandle varHandle, - MemorySession session) { - var seg = MemorySegment.ofAddress(thisPointer, ADDRESS.byteSize(), session); - var thisValue = seg.get(ADDRESS, 0); - var obj = MemorySegment.ofAddress(thisValue, IOCFPlugInInterface$Struct.byteSize(), session); - return (MemoryAddress) varHandle.get(obj); - } - - // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); - private static final VarHandle IUnknown_QueryInterface = IOCFPlugInInterface$Struct.varHandle(groupElement( - "QueryInterface")); - private static final MethodHandle QueryInterface$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, - ADDRESS, CFUUIDBytes, ADDRESS)); - - public static int QueryInterface(MemoryAddress thisPointer, MemorySegment iid, Addressable ppv) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOCFPlugInInterfaceFunctionAddress(thisPointer, IUnknown_QueryInterface, session); - return (int) QueryInterface$Func.invokeExact(funcPtr, (Addressable) thisPointer, iid, ppv); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); - private static final VarHandle IUnknown_AddRef = IOCFPlugInInterface$Struct.varHandle(groupElement("AddRef")); - private static final MethodHandle AddRef$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, ADDRESS)); - - public static int AddRef(MemoryAddress thisPointer) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOCFPlugInInterfaceFunctionAddress(thisPointer, IUnknown_AddRef, session); - return (int) AddRef$Func.invokeExact(funcPtr, (Addressable) thisPointer); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); - private static final VarHandle IUnknown_Release = IOCFPlugInInterface$Struct.varHandle(groupElement("Release")); - private static final MethodHandle Release$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, ADDRESS)); - - public static int Release(MemoryAddress thisPointer) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOCFPlugInInterfaceFunctionAddress(thisPointer, IUnknown_Release, session); - return (int) Release$Func.invokeExact(funcPtr, (Addressable) thisPointer); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // kern_return_t IOObjectRelease(io_object_t object); - private static final MethodHandle IOObjectRelease$Func = linker.downcallHandle(ioKitLookup.lookup( - "IOObjectRelease").get(), FunctionDescriptor.of(JAVA_INT, JAVA_INT)); - - public static int IOObjectRelease(int object) { - try { - return (int) IOObjectRelease$Func.invokeExact(object); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // io_object_t IOIteratorNext(io_iterator_t iterator); - private static final MethodHandle IOIteratorNext$Func = - linker.downcallHandle(ioKitLookup.lookup("IOIteratorNext").get(), FunctionDescriptor.of(JAVA_INT, - JAVA_INT)); - - public static int IOIteratorNext(int iter) { - try { - return (int) IOIteratorNext$Func.invokeExact(iter); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // kern_return_t IOCreatePlugInInterfaceForService(io_service_t service, CFUUIDRef pluginType, CFUUIDRef - // interfaceType, IOCFPlugInInterface ***theInterface, SInt32 *theScore); - private static final MethodHandle IOCreatePlugInInterfaceForService$Func = - linker.downcallHandle(ioKitLookup.lookup("IOCreatePlugInInterfaceForService").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS)); - - public static int IOCreatePlugInInterfaceForService(int service, Addressable pluginType, - Addressable interfaceType, Addressable intf, - Addressable score) { - try { - return (int) IOCreatePlugInInterfaceForService$Func.invokeExact(service, pluginType, interfaceType, intf, - score); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef - // allocator, IOOptionBits options); - private static final MethodHandle IORegistryEntryCreateCFProperty$Func = - linker.downcallHandle(ioKitLookup.lookup("IORegistryEntryCreateCFProperty").get(), - FunctionDescriptor.of(ADDRESS, JAVA_INT, ADDRESS, ADDRESS, JAVA_INT)); - - public static MemoryAddress IORegistryEntryCreateCFProperty(int entry, String key, Addressable allocator, - int options) { - try { - var keyStr = CoreFoundationHelper.createCFStringRef(key); - var propValue = (MemoryAddress) IORegistryEntryCreateCFProperty$Func.invokeExact(entry, - (Addressable) keyStr, allocator, options); - CoreFoundation.CFRelease(keyStr); - return propValue; - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - // IONotificationPortRef IONotificationPortCreate(mach_port_t mainPort); - private static final MethodHandle IONotificationPortCreate$Func = linker.downcallHandle(ioKitLookup.lookup( - "IONotificationPortCreate").get(), FunctionDescriptor.of(ADDRESS, JAVA_INT)); - - public static MemoryAddress IONotificationPortCreate(int mainPort) { - try { - return (MemoryAddress) IONotificationPortCreate$Func.invokeExact(mainPort); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // CFRunLoopSourceRef IONotificationPortGetRunLoopSource(IONotificationPortRef notify); - private static final MethodHandle IONotificationPortGetRunLoopSource$Func = - linker.downcallHandle(ioKitLookup.lookup("IONotificationPortGetRunLoopSource").get(), - FunctionDescriptor.of(ADDRESS, ADDRESS)); - - public static MemoryAddress IONotificationPortGetRunLoopSource(Addressable notify) { - try { - return (MemoryAddress) IONotificationPortGetRunLoopSource$Func.invokeExact(notify); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t *entryID); - private static final MethodHandle IORegistryEntryGetRegistryEntryID$Func = - linker.downcallHandle(ioKitLookup.lookup("IORegistryEntryGetRegistryEntryID").get(), - FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS)); - - public static int IORegistryEntryGetRegistryEntryID(int entry, Addressable entryIdHolder) { - try { - return (int) IORegistryEntryGetRegistryEntryID$Func.invokeExact(entry, entryIdHolder); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // kern_return_t IOServiceAddMatchingNotification(IONotificationPortRef notifyPort, const io_name_t - // notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void *refCon, io_iterator_t - // *notification); - private static final MethodHandle IOServiceAddMatchingNotification$Func = - linker.downcallHandle(ioKitLookup.lookup("IOServiceAddMatchingNotification").get(), - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS)); - - public static int IOServiceAddMatchingNotification(Addressable notifyPort, Addressable notificationType, - Addressable matching, Addressable callback, Addressable refCon - , Addressable notificationHolder) { - try { - return (int) IOServiceAddMatchingNotification$Func.invokeExact(notifyPort, notificationType, matching, - callback, refCon, notificationHolder); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - // CFMutableDictionaryRef IOServiceMatching(const char *name); - private static final MethodHandle IOServiceMatching$Func = linker.downcallHandle(ioKitLookup.lookup( - "IOServiceMatching").get(), FunctionDescriptor.of(ADDRESS, ADDRESS)); - - public static MemoryAddress IOServiceMatching(Addressable name) { - try { - return (MemoryAddress) IOServiceMatching$Func.invokeExact(name); - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - - public static final MemoryAddress kIOUSBDeviceUserClientTypeID = CoreFoundation.CFUUIDCreateFromUUIDBytes(NULL, - new byte[]{(byte) 0x9d, (byte) 0xc7, (byte) 0xb7, (byte) 0x80, (byte) 0x9e, (byte) 0xc0, (byte) 0x11, - (byte) 0xD4, (byte) 0xa5, (byte) 0x4f, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, - (byte) 0x28, (byte) 0x61}); - - public static final MemoryAddress kIOUSBInterfaceUserClientTypeID = CoreFoundation.CFUUIDCreateFromUUIDBytes(NULL - , new byte[]{(byte) 0x2d, (byte) 0x97, (byte) 0x86, (byte) 0xc6, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, - (byte) 0xD4, (byte) 0xad, (byte) 0x51, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, - (byte) 0x28, (byte) 0x61}); - - public static final MemoryAddress kIOUSBDeviceInterfaceID100 = CoreFoundation.CFUUIDCreateFromUUIDBytes(NULL, - new byte[]{(byte) 0x5c, (byte) 0x81, (byte) 0x87, (byte) 0xd0, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, - (byte) 0xD4, (byte) 0x8b, (byte) 0x45, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, - (byte) 0x28, (byte) 0x61}); - - public static final MemoryAddress kIOUSBInterfaceInterfaceID100 = CoreFoundation.CFUUIDCreateFromUUIDBytes(NULL, - new byte[]{(byte) 0x73, (byte) 0xc9, (byte) 0x7a, (byte) 0xe8, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, - (byte) 0xD4, (byte) 0xb1, (byte) 0xd0, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, - (byte) 0x28, (byte) 0x61}); - - public static final MemoryAddress kIOCFPlugInInterfaceID = CoreFoundation.CFUUIDCreateFromUUIDBytes(NULL, - new byte[]{(byte) 0xC2, (byte) 0x44, (byte) 0xE8, (byte) 0x58, (byte) 0x10, (byte) 0x9C, (byte) 0x11, - (byte) 0xD4, (byte) 0x91, (byte) 0xD4, (byte) 0x00, (byte) 0x50, (byte) 0xE4, (byte) 0xC6, - (byte) 0x42, (byte) 0x6F}); - - static { - try (var session = MemorySession.openConfined()) { - var kIOMasterPortDefaultAddress = ioKitLookup.lookup("kIOMasterPortDefault").get().address(); - kIOMasterPortDefault = MemorySegment.ofAddress(kIOMasterPortDefaultAddress, 4, session).get(JAVA_INT, 0); - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index 3f98fc41..832eda71 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -7,6 +7,10 @@ package net.codecrete.usb.macos; +import net.codecrete.usb.macos.gen.corefoundation.CFUUIDBytes; +import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; +import net.codecrete.usb.macos.gen.iokit.IOKit; + import java.lang.foreign.Addressable; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; @@ -15,15 +19,32 @@ import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.ADDRESS; import static java.lang.foreign.ValueLayout.JAVA_INT; -import static net.codecrete.usb.macos.CoreFoundation.CFUUIDBytes; -import static net.codecrete.usb.macos.CoreFoundation.CFUUID_bytes$Offset; +import static net.codecrete.usb.macos.UUID.CFUUID_bytes$Offset; /** - * Helper functions for the IOKit framework. + * Constants and helper functions for the IOKit framework. */ public class IoKitHelper { - private static final long NUMBER_TYPE_ID = CoreFoundation.CFNumberGetTypeID(); - private static final long STRING_TYPE_ID = CoreFoundation.CFStringGetTypeID(); + public static final MemoryAddress kIOUSBDeviceUserClientTypeID = UUID.CreateCFUUID( + new byte[]{(byte) 0x9d, (byte) 0xc7, (byte) 0xb7, (byte) 0x80, (byte) 0x9e, (byte) 0xc0, (byte) 0x11, + (byte) 0xD4, (byte) 0xa5, (byte) 0x4f, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, + (byte) 0x28, (byte) 0x61}); + public static final MemoryAddress kIOUSBInterfaceUserClientTypeID = UUID.CreateCFUUID( + new byte[]{(byte) 0x2d, (byte) 0x97, (byte) 0x86, (byte) 0xc6, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, + (byte) 0xD4, (byte) 0xad, (byte) 0x51, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, + (byte) 0x28, (byte) 0x61}); + public static final MemoryAddress kIOUSBDeviceInterfaceID100 = UUID.CreateCFUUID( + new byte[]{(byte) 0x5c, (byte) 0x81, (byte) 0x87, (byte) 0xd0, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, + (byte) 0xD4, (byte) 0x8b, (byte) 0x45, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, + (byte) 0x28, (byte) 0x61}); + public static final MemoryAddress kIOUSBInterfaceInterfaceID100 = UUID.CreateCFUUID( + new byte[]{(byte) 0x73, (byte) 0xc9, (byte) 0x7a, (byte) 0xe8, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, + (byte) 0xD4, (byte) 0xb1, (byte) 0xd0, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, + (byte) 0x28, (byte) 0x61}); + public static final MemoryAddress kIOCFPlugInInterfaceID = UUID.CreateCFUUID( + new byte[]{(byte) 0xC2, (byte) 0x44, (byte) 0xE8, (byte) 0x58, (byte) 0x10, (byte) 0x9C, (byte) 0x11, + (byte) 0xD4, (byte) 0x91, (byte) 0xD4, (byte) 0x00, (byte) 0x50, (byte) 0xE4, (byte) 0xC6, + (byte) 0x42, (byte) 0x6F}); /** * Get an interface of the specified service. @@ -43,7 +64,7 @@ public static MemoryAddress getInterface(int service, Addressable pluginType, Me var plugHolder = session.allocate(ADDRESS, NULL); // MemorySegment for holding score var score = session.allocate(JAVA_INT, 0); - int ret = IoKit.IOCreatePlugInInterfaceForService(service, pluginType, IoKit.kIOCFPlugInInterfaceID, + int ret = IOKit.IOCreatePlugInInterfaceForService(service, pluginType, kIOCFPlugInInterfaceID, plugHolder, score); if (ret != 0) return null; @@ -52,10 +73,10 @@ public static MemoryAddress getInterface(int service, Addressable pluginType, Me // MemorySegment for holding xxxInterface** var intfHolder = session.allocate(ADDRESS, NULL); // UUID bytes - var refiid = MemorySegment.ofAddress(interfaceId.addOffset(CFUUID_bytes$Offset), CFUUIDBytes.byteSize(), + var refiid = MemorySegment.ofAddress(interfaceId.addOffset(CFUUID_bytes$Offset), CFUUIDBytes.sizeof(), session); - ret = IoKit.QueryInterface(plug, refiid, intfHolder); - IoKit.Release(plug); + ret = IoKitUSB.QueryInterface(plug, refiid, intfHolder.address()); + IoKitUSB.Release(plug); if (ret != 0) return null; return intfHolder.get(ADDRESS, 0); @@ -73,17 +94,19 @@ public static MemoryAddress getInterface(int service, Addressable pluginType, Me * @return the property value, or {@code null} if the service doesn't have the property */ public static Integer getPropertyInt(int service, String key) { - var value = IoKit.IORegistryEntryCreateCFProperty(service, key, NULL, 0); + + var cfKey = CoreFoundationHelper.createCFStringRef(key); + var value = IOKit.IORegistryEntryCreateCFProperty(service, cfKey, NULL, 0); if (value == NULL) return null; Integer result = null; var type = CoreFoundation.CFGetTypeID(value); - if (type == NUMBER_TYPE_ID) { + if (type == CoreFoundation.CFNumberGetTypeID()) { try (var session = MemorySession.openConfined()) { var numberValue = session.allocate(JAVA_INT, 0); - if (CoreFoundation.CFNumberGetValue(value, CoreFoundation.kCFNumberSInt32Type, numberValue)) + if (CoreFoundation.CFNumberGetValue(value, CoreFoundation.kCFNumberSInt32Type(), numberValue) != 0) result = numberValue.get(JAVA_INT, 0); } } @@ -103,25 +126,28 @@ public static Integer getPropertyInt(int service, String key) { * @return the property value, or {@code null} if the service doesn't have the property */ public static String getPropertyString(int service, String key) { - var value = IoKit.IORegistryEntryCreateCFProperty(service, key, NULL, 0); + + var cfKey = CoreFoundationHelper.createCFStringRef(key); + var value = IOKit.IORegistryEntryCreateCFProperty(service, cfKey, NULL, 0); if (value == NULL) return null; String result = null; var type = CoreFoundation.CFGetTypeID(value); - if (type == STRING_TYPE_ID) + if (type == CoreFoundation.CFStringGetTypeID()) result = CoreFoundationHelper.stringFromCFStringRef(value); CoreFoundation.CFRelease(value); return result; } - public static int getRefCount(MemoryAddress object) { + // debugging aid + public static int getRefCount(MemoryAddress self) { try (var session = MemorySession.openConfined()) { - var objSegment = MemorySegment.ofAddress(object, 16, session); - var dataAddr = objSegment.get(ADDRESS, 8); - var dataSegment = MemorySegment.ofAddress(dataAddr, 12, session); - return dataSegment.get(JAVA_INT, 8); + var object = MemorySegment.ofAddress(self, 16, session); + var dataAddr = object.get(ADDRESS, ADDRESS.byteSize()); + var data = MemorySegment.ofAddress(dataAddr, 12, session); + return data.get(JAVA_INT, 8); } } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index 5eb4aba7..de4e7d22 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -7,517 +7,144 @@ package net.codecrete.usb.macos; -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; +import net.codecrete.usb.macos.gen.iokit.IOUSBDeviceInterface; +import net.codecrete.usb.macos.gen.iokit.IOUSBInterfaceInterface; -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.MemoryLayout.structLayout; -import static java.lang.foreign.ValueLayout.*; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; + +import static java.lang.foreign.ValueLayout.ADDRESS; /** - * Constants and functions for the USB specifict parts of IOKit framework. - *

- * In the future, jextract will hopefully be able to generate code for - * macOS frameworks in order to generate most of this. - *

+ * Helper functions to call the virtual methods of IOKit USB interfaces. */ public class IoKitUSB { private static final Linker linker = Linker.nativeLinker(); - public static final short kIOUSBFindInterfaceDontCare = (short) 0xFFFF; - // typedef struct { - // UInt16 bInterfaceClass; // requested class - // UInt16 bInterfaceSubClass; // requested subclass - // UInt16 bInterfaceProtocol; // requested protocol - // UInt16 bAlternateSetting; // requested alt setting - // } IOUSBFindInterfaceRequest; - public static final GroupLayout IOUSBFindInterfaceRequest$Struct = structLayout(JAVA_SHORT.withName( - "bInterfaceClass"), JAVA_SHORT.withName("bInterfaceSubClass"), JAVA_SHORT.withName("bInterfaceProtocol"), - JAVA_SHORT.withName("bAlternateSetting")); - public static final VarHandle IOUSBFindInterfaceRequest_bInterfaceClass = - IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bInterfaceClass")); - public static final VarHandle IOUSBFindInterfaceRequest_bInterfaceSubClass = - IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bInterfaceSubClass")); - public static final VarHandle IOUSBFindInterfaceRequest_bInterfaceProtocol = - IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bInterfaceProtocol")); - public static final VarHandle IOUSBFindInterfaceRequest_bAlternateSetting = - IOUSBFindInterfaceRequest$Struct.varHandle(groupElement("bAlternateSetting")); + private static MemorySegment getVtable(MemoryAddress self, MemorySession session) { + var object = MemorySegment.ofAddress(self, ADDRESS.byteSize(), session); + var vtableAddr = object.get(ADDRESS, 0); + // 800: size of biggest vtable and then some + return MemorySegment.ofAddress(vtableAddr, 800, session); + } - private static final GroupLayout IOUSBDevice$Struct = structLayout(ADDRESS.withName("_reserved"), // void - // *_reserved; - ADDRESS.withName("QueryInterface"), // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, - // REFIID iid, LPVOID *ppv); - ADDRESS.withName("AddRef"), // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); - ADDRESS.withName("Release"), // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); - ADDRESS.withName("CreateDeviceAsyncEventSource"), // IOReturn (*CreateDeviceAsyncEventSource)(void *self, - // CFRunLoopSourceRef *source); - ADDRESS.withName("GetDeviceAsyncEventSource"), // CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void - // *self); - ADDRESS.withName("CreateDeviceAsyncPort"), // IOReturn (*CreateDeviceAsyncPort)(void *self, mach_port_t - // *port); - ADDRESS.withName("GetDeviceAsyncPort"), // mach_port_t (*GetDeviceAsyncPort)(void *self); - ADDRESS.withName("USBDeviceOpen"), // IOReturn (*USBDeviceOpen)(void *self); - ADDRESS.withName("USBDeviceClose"), // IOReturn (*USBDeviceClose)(void *self); - ADDRESS.withName("GetDeviceClass"), // IOReturn (*GetDeviceClass)(void *self, UInt8 *devClass); - ADDRESS.withName("GetDeviceSubClass"), // IOReturn (*GetDeviceSubClass)(void *self, UInt8 *devSubClass); - ADDRESS.withName("GetDeviceProtocol"), // IOReturn (*GetDeviceProtocol)(void *self, UInt8 *devProtocol); - ADDRESS.withName("GetDeviceVendor"), // IOReturn (*GetDeviceVendor)(void *self, UInt16 *devVendor); - ADDRESS.withName("GetDeviceProduct"), // IOReturn (*GetDeviceProduct)(void *self, UInt16 *devProduct); - ADDRESS.withName("GetDeviceReleaseNumber"), // IOReturn (*GetDeviceReleaseNumber)(void *self, UInt16 - // *devRelNum); - ADDRESS.withName("GetDeviceAddress"), // IOReturn (*GetDeviceAddress)(void *self, USBDeviceAddress *addr); - ADDRESS.withName("GetDeviceBusPowerAvailable"), // IOReturn (*GetDeviceBusPowerAvailable)(void *self, - // UInt32 *powerAvailable); - ADDRESS.withName("GetDeviceSpeed"), // IOReturn (*GetDeviceSpeed)(void *self, UInt8 *devSpeed); - ADDRESS.withName("GetNumberOfConfigurations"), // IOReturn (*GetNumberOfConfigurations)(void *self, - // UInt8 *numConfig); - ADDRESS.withName("GetLocationID"), // IOReturn (*GetLocationID)(void *self, UInt32 *locationID); - ADDRESS.withName("GetConfigurationDescriptorPtr"), // IOReturn (*GetConfigurationDescriptorPtr)(void - // *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc); - ADDRESS.withName("GetConfiguration"), // IOReturn (*GetConfiguration)(void *self, UInt8 *configNum); - ADDRESS.withName("SetConfiguration"), // IOReturn (*SetConfiguration)(void *self, UInt8 configNum); - ADDRESS.withName("GetBusFrameNumber"), // IOReturn (*GetBusFrameNumber)(void *self, UInt64 *frame, - // AbsoluteTime *atTime); - ADDRESS.withName("ResetDevice"), // IOReturn (*ResetDevice)(void *self); - ADDRESS.withName("DeviceRequest"), // IOReturn (*DeviceRequest)(void *self, IOUSBDevRequest *req); - ADDRESS.withName("DeviceRequestAsync"), // IOReturn (*DeviceRequestAsync)(void *self, IOUSBDevRequest - // *req, IOAsyncCallback1 callback, void *refCon); - ADDRESS.withName("CreateInterfaceIterator"), // IOReturn (*CreateInterfaceIterator)(void *self, - // IOUSBFindInterfaceRequest *req, io_iterator_t *iter); - ADDRESS.withName("USBDeviceOpenSeize"), // IOReturn (*USBDeviceOpenSeize)(void *self); - ADDRESS.withName("DeviceRequestTO"), // IOReturn (*DeviceRequestTO)(void *self, IOUSBDevRequestTO *req); - ADDRESS.withName("DeviceRequestAsyncTO"), // IOReturn (*DeviceRequestAsyncTO)(void *self, - // IOUSBDevRequestTO *req, IOAsyncCallback1 callback, void *refCon); - ADDRESS.withName("USBDeviceSuspend"), // IOReturn (*USBDeviceSuspend)(void *self, Boolean suspend); - ADDRESS.withName("USBDeviceAbortPipeZero"), // IOReturn (*USBDeviceAbortPipeZero)(void *self); - ADDRESS.withName("USBGetManufacturerStringIndex"), // IOReturn (*USBGetManufacturerStringIndex)(void - // *self, UInt8 *msi); - ADDRESS.withName("USBGetProductStringIndex"), // IOReturn (*USBGetProductStringIndex)(void *self, UInt8 - // *psi); - ADDRESS.withName("USBGetSerialNumberStringIndex"), // IOReturn (*USBGetSerialNumberStringIndex)(void - // *self, UInt8 *snsi); - ADDRESS.withName("USBDeviceReEnumerate"), // IOReturn (*USBDeviceReEnumerate)(void *self, UInt32 options); - ADDRESS.withName("GetBusMicroFrameNumber"), // IOReturn (*GetBusMicroFrameNumber)(void *self, UInt64 - // *microFrame, AbsoluteTime *atTime); - ADDRESS.withName("GetIOUSBLibVersion"), // IOReturn (*GetIOUSBLibVersion)(void *self, NumVersion - // *ioUSBLibVersion, NumVersion *usbFamilyVersion); - ADDRESS.withName("GetBusFrameNumberWithTime"), // IOReturn (*GetBusFrameNumberWithTime)(void *self, - // UInt64 *frame, AbsoluteTime *atTime); - ADDRESS.withName("GetUSBDeviceInformation"), // IOReturn (*GetUSBDeviceInformation)(void *self, UInt32 - // *info); - ADDRESS.withName("RequestExtraPower"), // IOReturn (*RequestExtraPower)(void *self, UInt32 type, UInt32 - // requestedPower, UInt32 *powerAvailable); - ADDRESS.withName("ReturnExtraPower"), // IOReturn (*ReturnExtraPower)(void *self, UInt32 type, UInt32 - // powerReturned); - ADDRESS.withName("GetExtraPowerAllocated"), // IOReturn (*GetExtraPowerAllocated)(void *self, UInt32 - // type, UInt32 *powerAllocated); - ADDRESS.withName("GetBandwidthAvailableForDevice"), // IOReturn (*GetBandwidthAvailableForDevice)(void - // *self, UInt32 *bandwidth); - ADDRESS.withName("SetConfigurationV2"), // IOReturn (*SetConfigurationV2)(void *self, UInt8 configNum, - // bool startInterfaceMatching, bool issueRemoteWakeup); - ADDRESS.withName("RegisterForNotification"), // IOReturn (*RegisterForNotification)(void * self, UInt64 - // notificationMask, IOAsyncCallback2 callback, void *refCon, UInt64 *pRegistrationToken); - ADDRESS.withName("UnregisterNotification"), // IOReturn (*UnregisterNotification)(void *self, UInt64 - // registrationToken); - ADDRESS.withName("AcknowledgeNotification") // IOReturn (*AcknowledgeNotification)(void *self, UInt64 - // notificationToken); - ); + // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); + public static int QueryInterface(MemoryAddress self, MemorySegment iid, MemoryAddress ppv) { + try (var session = MemorySession.openConfined()) { + return IOUSBDeviceInterface.QueryInterface(getVtable(self, session), session).apply(self, iid, ppv); + } + } - /** - * Looks up the address of the specified virtual function in the {@code IOUSBDevice} object - * - * @param thisPointer pointer to pointer to object - * @param varHandle variable handle to virtual function - * @param session memory session - * @return function address - */ - private static Addressable IOUSBDeviceFunctionAddress(MemoryAddress thisPointer, VarHandle varHandle, - MemorySession session) { - var seg = MemorySegment.ofAddress(thisPointer, ADDRESS.byteSize(), session); - var thisValue = seg.get(ADDRESS, 0); - var obj = MemorySegment.ofAddress(thisValue, IOUSBDevice$Struct.byteSize(), session); - return (MemoryAddress) varHandle.get(obj); + // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); + public static int AddRef(MemoryAddress self) { + try (var session = MemorySession.openConfined()) { + return IOUSBDeviceInterface.AddRef(getVtable(self, session), session).apply(self); + } } - // IOReturn (*USBDeviceOpen)(void *self); - private static final VarHandle IOUSBDevice_USBDeviceOpen = IOUSBDevice$Struct.varHandle(groupElement( - "USBDeviceOpen")); - private static final MethodHandle USBDeviceOpen$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, - ADDRESS)); + // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer) + public static int Release(MemoryAddress self) { + try (var session = MemorySession.openConfined()) { + return IOUSBDeviceInterface.Release(getVtable(self, session), session).apply(self); + } + } - public static int USBDeviceOpen(MemoryAddress thisPointer) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_USBDeviceOpen, session); - return (int) USBDeviceOpen$Func.invokeExact(funcPtr, (Addressable) thisPointer); - } catch (Throwable e) { - throw new RuntimeException(e); + // IOReturn (*USBDeviceOpen)(void *self); + public static int USBDeviceOpen(MemoryAddress self) { + try (var session = MemorySession.openConfined()) { + return IOUSBDeviceInterface.USBDeviceOpen(getVtable(self, session), session).apply(self); } } // IOReturn (*USBDeviceClose)(void *self); - private static final VarHandle IOUSBDevice_USBDeviceClose = IOUSBDevice$Struct.varHandle(groupElement( - "USBDeviceClose")); - private static final MethodHandle USBDeviceClose$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, - ADDRESS)); - - public static int USBDeviceClose(MemoryAddress thisPointer) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_USBDeviceClose, session); - return (int) USBDeviceClose$Func.invokeExact(funcPtr, (Addressable) thisPointer); - } catch (Throwable e) { - throw new RuntimeException(e); + public static int USBDeviceClose(MemoryAddress self) { + try (var session = MemorySession.openConfined()) { + return IOUSBDeviceInterface.USBDeviceClose(getVtable(self, session), session).apply(self); } } // IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc); - private static final VarHandle IOUSBDevice_GetConfigurationDescriptorPtr = - IOUSBDevice$Struct.varHandle(groupElement("GetConfigurationDescriptorPtr")); - private static final MethodHandle GetConfigurationDescriptorPtr$Func = - linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS)); - - public static int GetConfigurationDescriptorPtr(MemoryAddress thisPointer, byte configIndex, - Addressable descHolder) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_GetConfigurationDescriptorPtr, session); - return (int) GetConfigurationDescriptorPtr$Func.invokeExact(funcPtr, (Addressable) thisPointer, - configIndex, descHolder); - } catch (Throwable e) { - throw new RuntimeException(e); + public static int GetConfigurationDescriptorPtr(MemoryAddress self, byte configIndex, + MemoryAddress descHolder) { + try (var session = MemorySession.openConfined()) { + return IOUSBDeviceInterface.GetConfigurationDescriptorPtr(getVtable(self, session), session).apply(self, configIndex, descHolder); } } // IOReturn (*SetConfiguration)(void *self, UInt8 configNum); - private static final VarHandle IOUSBDevice_SetConfiguration = IOUSBDevice$Struct.varHandle(groupElement( - "SetConfiguration")); - private static final MethodHandle SetConfiguration$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, - ADDRESS, JAVA_BYTE)); - - public static int SetConfiguration(MemoryAddress thisPointer, byte configValue) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_SetConfiguration, session); - return (int) SetConfiguration$Func.invokeExact(funcPtr, (Addressable) thisPointer, configValue); - } catch (Throwable e) { - throw new RuntimeException(e); + public static int SetConfiguration(MemoryAddress self, byte configValue) { + try (var session = MemorySession.openConfined()) { + return IOUSBDeviceInterface.SetConfiguration(getVtable(self, session), session).apply(self, configValue); } } // IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter); - private static final VarHandle IOUSBDevice_CreateInterfaceIterator = IOUSBDevice$Struct.varHandle(groupElement( - "CreateInterfaceIterator")); - private static final MethodHandle CreateInterfaceIterator$Func = - linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS)); - - public static int CreateInterfaceIterator(MemoryAddress thisPointer, Addressable req, Addressable iter) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_CreateInterfaceIterator, session); - return (int) CreateInterfaceIterator$Func.invokeExact(funcPtr, (Addressable) thisPointer, req, iter); - } catch (Throwable e) { - throw new RuntimeException(e); + public static int CreateInterfaceIterator(MemoryAddress self, MemoryAddress req, MemoryAddress iter) { + try (var session = MemorySession.openConfined()) { + return IOUSBDeviceInterface.CreateInterfaceIterator(getVtable(self, session), session).apply(self, req, iter); } } // IOReturn (*DeviceRequest)(void *self, IOUSBDevRequest *req); - private static final VarHandle IOUSBDevice_DeviceRequest = IOUSBDevice$Struct.varHandle(groupElement( - "DeviceRequest")); - private static final MethodHandle DeviceRequest$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, - ADDRESS, ADDRESS)); - - public static int DeviceRequest(MemoryAddress thisPointer, Addressable deviceRequest) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBDeviceFunctionAddress(thisPointer, IOUSBDevice_DeviceRequest, session); - return (int) DeviceRequest$Func.invokeExact(funcPtr, (Addressable) thisPointer, deviceRequest); - } catch (Throwable e) { - throw new RuntimeException(e); + public static int DeviceRequest(MemoryAddress self, MemoryAddress deviceRequest) { + try (var session = MemorySession.openConfined()) { + return IOUSBDeviceInterface.DeviceRequest(getVtable(self, session), session).apply(self, deviceRequest); } } - private static final GroupLayout IOUSBInterface$Struct = structLayout(ADDRESS.withName("_reserved"), // void - // *_reserved; - ADDRESS.withName("QueryInterface"), // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, - // REFIID iid, LPVOID *ppv); - ADDRESS.withName("AddRef"), // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); - ADDRESS.withName("Release"), // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer); - ADDRESS.withName("CreateInterfaceAsyncEventSource"), // IOReturn (*CreateInterfaceAsyncEventSource) - // (void *self, CFRunLoopSourceRef *source); - ADDRESS.withName("GetInterfaceAsyncEventSource"), // CFRunLoopSourceRef - // (*GetInterfaceAsyncEventSource)(void *self); - ADDRESS.withName("CreateInterfaceAsyncPort"), // IOReturn (*CreateInterfaceAsyncPort)(void *self, - // mach_port_t *port); - ADDRESS.withName("GetInterfaceAsyncPort"), // mach_port_t (*GetInterfaceAsyncPort)(void *self); - ADDRESS.withName("USBInterfaceOpen"), // IOReturn (*USBInterfaceOpen)(void *self); - ADDRESS.withName("USBInterfaceClose"), // IOReturn (*USBInterfaceClose)(void *self); - ADDRESS.withName("GetInterfaceClass"), // IOReturn (*GetInterfaceClass)(void *self, UInt8 *intfClass); - ADDRESS.withName("GetInterfaceSubClass"), // IOReturn (*GetInterfaceSubClass)(void *self, UInt8 - // *intfSubClass); - ADDRESS.withName("GetInterfaceProtocol"), // IOReturn (*GetInterfaceProtocol)(void *self, UInt8 - // *intfProtocol); - ADDRESS.withName("GetDeviceVendor"), // IOReturn (*GetDeviceVendor)(void *self, UInt16 *devVendor); - ADDRESS.withName("GetDeviceProduct"), // IOReturn (*GetDeviceProduct)(void *self, UInt16 *devProduct); - ADDRESS.withName("GetDeviceReleaseNumber"), // IOReturn (*GetDeviceReleaseNumber)(void *self, UInt16 - // *devRelNum); - ADDRESS.withName("GetConfigurationValue"), // IOReturn (*GetConfigurationValue)(void *self, UInt8 - // *configVal); - ADDRESS.withName("GetInterfaceNumber"), // IOReturn (*GetInterfaceNumber)(void *self, UInt8 *intfNumber); - ADDRESS.withName("GetAlternateSetting"), // IOReturn (*GetAlternateSetting)(void *self, UInt8 - // *intfAltSetting); - ADDRESS.withName("GetNumEndpoints"), // IOReturn (*GetNumEndpoints)(void *self, UInt8 *intfNumEndpoints); - ADDRESS.withName("GetLocationID"), // IOReturn (*GetLocationID)(void *self, UInt32 *locationID); - ADDRESS.withName("GetDevice"), // IOReturn (*GetDevice)(void *self, io_service_t *device); - ADDRESS.withName("SetAlternateInterface"), // IOReturn (*SetAlternateInterface)(void *self, UInt8 - // alternateSetting); - ADDRESS.withName("GetBusFrameNumber"), // IOReturn (*GetBusFrameNumber)(void *self, UInt64 *frame, - // AbsoluteTime *atTime); - ADDRESS.withName("ControlRequest"), // IOReturn (*ControlRequest)(void *self, UInt8 pipeRef, - // IOUSBDevRequest *req); - ADDRESS.withName("ControlRequestAsync"), // IOReturn (*ControlRequestAsync)(void *self, UInt8 pipeRef, - // IOUSBDevRequest *req, IOAsyncCallback1 callback, void *refCon); - ADDRESS.withName("GetPipeProperties"), // IOReturn (*GetPipeProperties)(void *self, UInt8 pipeRef, - // UInt8 *direction, UInt8 *number, UInt8 *transferType, UInt16 *maxPacketSize, UInt8 *interval); - ADDRESS.withName("GetPipeStatus"), // IOReturn (*GetPipeStatus)(void *self, UInt8 pipeRef); - ADDRESS.withName("AbortPipe"), // IOReturn (*AbortPipe)(void *self, UInt8 pipeRef); - ADDRESS.withName("ResetPipe"), // IOReturn (*ResetPipe)(void *self, UInt8 pipeRef); - ADDRESS.withName("ClearPipeStall"), // IOReturn (*ClearPipeStall)(void *self, UInt8 pipeRef); - ADDRESS.withName("ReadPipe"), // IOReturn (*ReadPipe)(void *self, UInt8 pipeRef, void *buf, UInt32 - // *size); - ADDRESS.withName("WritePipe"), // IOReturn (*WritePipe)(void *self, UInt8 pipeRef, void *buf, UInt32 - // size); - ADDRESS.withName("ReadPipeAsync"), // IOReturn (*ReadPipeAsync)(void *self, UInt8 pipeRef, void *buf, - // UInt32 size, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("WritePipeAsync"), // IOReturn (*WritePipeAsync)(void *self, UInt8 pipeRef, void - // *buf, UInt32 size, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("ReadIsochPipeAsync"), // IOReturn (*ReadIsochPipeAsync)(void *self, UInt8 pipeRef, - // void *buf, UInt64 frameStart, UInt32 numFrames, IOUSBIsocFrame *frameList, IOAsyncCallback1 callback, - // void *refcon); - ADDRESS.withName("WriteIsochPipeAsync"), // IOReturn (*WriteIsochPipeAsync)(void *self, UInt8 pipeRef, - // void *buf, UInt64 frameStart, UInt32 numFrames, IOUSBIsocFrame *frameList, IOAsyncCallback1 callback, - // void *refcon); - ADDRESS.withName("ControlRequestTO"), // IOReturn (*ControlRequestTO)(void *self, UInt8 pipeRef, - // IOUSBDevRequestTO *req); - ADDRESS.withName("ControlRequestAsyncTO"), // IOReturn (*ControlRequestAsyncTO)(void *self, UInt8 - // pipeRef, IOUSBDevRequestTO *req, IOAsyncCallback1 callback, void *refCon); - ADDRESS.withName("ReadPipeTO"), // IOReturn (*ReadPipeTO)(void *self, UInt8 pipeRef, void *buf, UInt32 - // *size, UInt32 noDataTimeout, UInt32 completionTimeout); - ADDRESS.withName("WritePipeTO"), // IOReturn (*WritePipeTO)(void *self, UInt8 pipeRef, void *buf, - // UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout); - ADDRESS.withName("ReadPipeAsyncTO"), // IOReturn (*ReadPipeAsyncTO)(void *self, UInt8 pipeRef, void - // *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void - // *refcon); - ADDRESS.withName("WritePipeAsyncTO"), // IOReturn (*WritePipeAsyncTO)(void *self, UInt8 pipeRef, void - // *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void - // *refcon); - ADDRESS.withName("USBInterfaceGetStringIndex"), // IOReturn (*USBInterfaceGetStringIndex)(void *self, - // UInt8 *si); - ADDRESS.withName("USBInterfaceOpenSeize"), // IOReturn (*USBInterfaceOpenSeize)(void *self); - ADDRESS.withName("ClearPipeStallBothEnds"), // IOReturn (*ClearPipeStallBothEnds)(void *self, UInt8 - // pipeRef); - ADDRESS.withName("SetPipePolicy"), // IOReturn (*SetPipePolicy)(void *self, UInt8 pipeRef, UInt16 - // maxPacketSize, UInt8 maxInterval); - ADDRESS.withName("GetBandwidthAvailable"), // IOReturn (*GetBandwidthAvailable)(void *self, UInt32 - // *bandwidth); - ADDRESS.withName("GetEndpointProperties"), // IOReturn (*GetEndpointProperties)(void *self, UInt8 - // alternateSetting, UInt8 endpointNumber, UInt8 direction, UInt8 *transferType, UInt16 *maxPacketSize, - // UInt8 *interval); - ADDRESS.withName("LowLatencyReadIsochPipeAsync"), // IOReturn (*LowLatencyReadIsochPipeAsync)(void - // *self, UInt8 pipeRef, void *buf, UInt64 frameStart, UInt32 numFrames, UInt32 updateFrequency, - // IOUSBLowLatencyIsocFrame *frameList, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("LowLatencyWriteIsochPipeAsync"), // IOReturn (*LowLatencyWriteIsochPipeAsync)(void - // *self, UInt8 pipeRef, void *buf, UInt64 frameStart, UInt32 numFrames, UInt32 updateFrequency, - // IOUSBLowLatencyIsocFrame *frameList, IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("LowLatencyCreateBuffer"), // IOReturn (*LowLatencyCreateBuffer)(void * self, void - // **buffer, IOByteCount size, UInt32 bufferType); - ADDRESS.withName("LowLatencyDestroyBuffer"), // IOReturn (*LowLatencyDestroyBuffer) (void * self, void - // * buffer ); - ADDRESS.withName("GetBusMicroFrameNumber"), // IOReturn (*GetBusMicroFrameNumber)(void *self, UInt64 - // *microFrame, AbsoluteTime *atTime); - ADDRESS.withName("GetFrameListTime"), // IOReturn (*GetFrameListTime)(void *self, UInt32 - // *microsecondsInFrame); - ADDRESS.withName("GetIOUSBLibVersion"), // IOReturn (*GetIOUSBLibVersion)(void *self, NumVersion - // *ioUSBLibVersion, NumVersion *usbFamilyVersion); - ADDRESS.withName("FindNextAssociatedDescriptor"), // IOUSBDescriptorHeader * - // (*FindNextAssociatedDescriptor)(void *self, const void *currentDescriptor, UInt8 descriptorType); - ADDRESS.withName("FindNextAltInterface"), // IOUSBDescriptorHeader * (*FindNextAltInterface)(void - // *self, const void *current, IOUSBFindInterfaceRequest *request); - ADDRESS.withName("GetBusFrameNumberWithTime"), // IOReturn (*GetBusFrameNumberWithTime)(void *self, - // UInt64 *frame, AbsoluteTime *atTime); - ADDRESS.withName("GetPipePropertiesV2"), // IOReturn (*GetPipePropertiesV2)(void *self, UInt8 pipeRef, - // UInt8 *direction, UInt8 *number, UInt8 *transferType, UInt16 *maxPacketSize, UInt8 *interval, UInt8 - // *maxBurst, UInt8 *mult, UInt16 *bytesPerInterval); - ADDRESS.withName("GetPipePropertiesV3"), // IOReturn (*GetPipePropertiesV3)(void *self, UInt8 pipeRef, - // IOUSBEndpointProperties *properties); - ADDRESS.withName("GetEndpointPropertiesV3"), // IOReturn (*GetEndpointPropertiesV3)(void *self, - // IOUSBEndpointProperties *properties); - ADDRESS.withName("SupportsStreams"), // IOReturn (*SupportsStreams)(void *self, UInt8 pipeRef, UInt32 - // *supportsStreams); - ADDRESS.withName("CreateStreams"), // IOReturn (*CreateStreams)(void *self, UInt8 pipeRef, UInt32 - // streamID); - ADDRESS.withName("GetConfiguredStreams"), // IOReturn (*GetConfiguredStreams)(void *self, UInt8 - // pipeRef, UInt32 *configuredStreams); - ADDRESS.withName("ReadStreamsPipeTO"), // IOReturn (*ReadStreamsPipeTO)(void *self, UInt8 pipeRef, - // UInt32 streamID, void *buf, UInt32 *size, UInt32 noDataTimeout, UInt32 completionTimeout); - ADDRESS.withName("WriteStreamsPipeTO"), // IOReturn (*WriteStreamsPipeTO)(void *self, UInt8 pipeRef, - // UInt32 streamID, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout); - ADDRESS.withName("ReadStreamsPipeAsyncTO"), // IOReturn (*ReadStreamsPipeAsyncTO)(void *self, UInt8 - // pipeRef, UInt32 streamID, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, - // IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("WriteStreamsPipeAsyncTO"), // IOReturn (*WriteStreamsPipeAsyncTO)(void *self, UInt8 - // pipeRef, UInt32 streamID, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, - // IOAsyncCallback1 callback, void *refcon); - ADDRESS.withName("AbortStreamsPipe"), // IOReturn (*AbortStreamsPipe)(void *self, UInt8 pipeRef, - // UInt32 streamID); - ADDRESS.withName("RegisterForNotification"), // IOReturn (*RegisterForNotification)(void * self, - // UInt64 notificationMask, IOAsyncCallback2 callback, void *refCon, UInt64 *pRegistrationToken); - ADDRESS.withName("UnregisterNotification"), // IOReturn (*UnregisterNotification)(void *self, UInt64 - // registrationToken); - ADDRESS.withName("AcknowledgeNotification"), // IOReturn (*AcknowledgeNotification)(void *self, UInt64 - // notificationToken); - ADDRESS.withName("RegisterDriver") // IOReturn (*RegisterDriver)(void *self); - ); - - /** - * Looks up the address of the specified virtual function in the {@code IOUSBInterface} object - * - * @param thisPointer pointer to pointer to object - * @param varHandle variable handle to virtual function - * @param session memory session - * @return function address - */ - private static Addressable IOUSBInterfaceFunctionAddress(MemoryAddress thisPointer, VarHandle varHandle, - MemorySession session) { - var seg = MemorySegment.ofAddress(thisPointer, ADDRESS.byteSize(), session); - var thisValue = seg.get(ADDRESS, 0); - var obj = MemorySegment.ofAddress(thisValue, IOUSBInterface$Struct.byteSize(), session); - return (MemoryAddress) varHandle.get(obj); - } - // IOReturn (*USBInterfaceOpen)(void *self);; - private static final VarHandle IOUSBInterface_USBInterfaceOpen = IOUSBInterface$Struct.varHandle(groupElement( - "USBInterfaceOpen")); - private static final MethodHandle USBInterfaceOpen$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, - ADDRESS)); - - public static int USBInterfaceOpen(MemoryAddress thisPointer) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_USBInterfaceOpen, session); - return (int) USBInterfaceOpen$Func.invokeExact(funcPtr, (Addressable) thisPointer); - } catch (Throwable e) { - throw new RuntimeException(e); + public static int USBInterfaceOpen(MemoryAddress self) { + try (var session = MemorySession.openConfined()) { + return IOUSBInterfaceInterface.USBInterfaceOpen(getVtable(self, session), session).apply(self); } } // IOReturn (*USBInterfaceClose)(void *self);; - private static final VarHandle IOUSBInterface_USBInterfaceClose = IOUSBInterface$Struct.varHandle(groupElement( - "USBInterfaceClose")); - private static final MethodHandle USBInterfaceClose$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, - ADDRESS)); - - public static int USBInterfaceClose(MemoryAddress thisPointer) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_USBInterfaceClose, session); - return (int) USBInterfaceClose$Func.invokeExact(funcPtr, (Addressable) thisPointer); - } catch (Throwable e) { - throw new RuntimeException(e); + public static int USBInterfaceClose(MemoryAddress self) { + try (var session = MemorySession.openConfined()) { + return IOUSBInterfaceInterface.USBInterfaceClose(getVtable(self, session), session).apply(self); } } // IOReturn (*GetInterfaceNumber)(void *self, UInt8 *intfNumber); - private static final VarHandle IOUSBInterface_GetInterfaceNumber = IOUSBInterface$Struct.varHandle(groupElement( - "GetInterfaceNumber")); - private static final MethodHandle GetInterfaceNumber$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, - ADDRESS, ADDRESS)); - - public static int GetInterfaceNumber(MemoryAddress thisPointer, Addressable intfNumberHolder) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_GetInterfaceNumber, session); - return (int) GetInterfaceNumber$Func.invokeExact(funcPtr, (Addressable) thisPointer, intfNumberHolder); - } catch (Throwable e) { - throw new RuntimeException(e); + public static int GetInterfaceNumber(MemoryAddress self, MemoryAddress intfNumberHolder) { + try (var session = MemorySession.openConfined()) { + return IOUSBInterfaceInterface.GetInterfaceNumber(getVtable(self, session), session).apply(self, intfNumberHolder); } } // IOReturn (*GetNumEndpoints)(void *self, UInt8 *intfNumEndpoints); - private static final VarHandle IOUSBInterface_GetNumEndpoints = IOUSBInterface$Struct.varHandle(groupElement( - "GetNumEndpoints")); - private static final MethodHandle GetNumEndpoints$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, - ADDRESS, ADDRESS)); - - public static int GetNumEndpoints(MemoryAddress thisPointer, Addressable intfNumEndpointsHolder) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_GetNumEndpoints, session); - return (int) GetNumEndpoints$Func.invokeExact(funcPtr, (Addressable) thisPointer, intfNumEndpointsHolder); - } catch (Throwable e) { - throw new RuntimeException(e); + public static int GetNumEndpoints(MemoryAddress self, MemoryAddress intfNumEndpointsHolder) { + try (var session = MemorySession.openConfined()) { + return IOUSBInterfaceInterface.GetNumEndpoints(getVtable(self, session), session).apply(self, intfNumEndpointsHolder); } } // IOReturn (*GetPipeProperties)(void *self, UInt8 pipeRef, UInt8 *direction, UInt8 *number, UInt8 *transferType, // UInt16 *maxPacketSize, UInt8 *interval); - private static final VarHandle IOUSBInterface_GetPipeProperties = IOUSBInterface$Struct.varHandle(groupElement( - "GetPipeProperties")); - private static final MethodHandle GetPipeProperties$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, - ADDRESS, JAVA_BYTE, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS)); - - public static int GetPipeProperties(MemoryAddress thisPointer, byte pipeRef, Addressable directionHolder, - Addressable numberHolder, Addressable transferTypeHolder, - Addressable maxPacketSizeHolder, Addressable intervalHolder) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_GetPipeProperties, session); - return (int) GetPipeProperties$Func.invokeExact(funcPtr, (Addressable) thisPointer, pipeRef, + public static int GetPipeProperties(MemoryAddress self, byte pipeRef, MemoryAddress directionHolder, + MemoryAddress numberHolder, MemoryAddress transferTypeHolder, + MemoryAddress maxPacketSizeHolder, MemoryAddress intervalHolder) { + try (var session = MemorySession.openConfined()) { + return IOUSBInterfaceInterface.GetPipeProperties(getVtable(self, session), session).apply(self, pipeRef, directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); - } catch (Throwable e) { - throw new RuntimeException(e); } } // IOReturn (*ReadPipe)(void *self, UInt8 pipeRef, void *buf, UInt32 *size); - private static final VarHandle IOUSBInterface_ReadPipe = IOUSBInterface$Struct.varHandle(groupElement("ReadPipe")); - private static final MethodHandle ReadPipe$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, ADDRESS, - JAVA_BYTE, ADDRESS, ADDRESS)); - - public static int ReadPipe(MemoryAddress thisPointer, byte pipeRef, Addressable buf, Addressable sizeHolder) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_ReadPipe, session); - return (int) ReadPipe$Func.invokeExact(funcPtr, (Addressable) thisPointer, pipeRef, buf, sizeHolder); - } catch (Throwable e) { - throw new RuntimeException(e); + public static int ReadPipe(MemoryAddress self, byte pipeRef, MemoryAddress buf, MemoryAddress sizeHolder) { + try (var session = MemorySession.openConfined()) { + return IOUSBInterfaceInterface.ReadPipe(getVtable(self, session), session) + .apply(self, pipeRef, buf, sizeHolder); } } // IOReturn (*WritePipe)(void *self, UInt8 pipeRef, void *buf, UInt32 size); - private static final VarHandle IOUSBInterface_WritePipe = IOUSBInterface$Struct.varHandle(groupElement("WritePipe" - )); - private static final MethodHandle WritePipe$Func = linker.downcallHandle(FunctionDescriptor.of(JAVA_INT, ADDRESS, - JAVA_BYTE, ADDRESS, JAVA_INT)); - - public static int WritePipe(MemoryAddress thisPointer, byte pipeRef, Addressable buf, int size) { - try (var session = MemorySession.openShared()) { - var funcPtr = IOUSBInterfaceFunctionAddress(thisPointer, IOUSBInterface_WritePipe, session); - return (int) WritePipe$Func.invokeExact(funcPtr, (Addressable) thisPointer, pipeRef, buf, size); - } catch (Throwable e) { - throw new RuntimeException(e); + public static int WritePipe(MemoryAddress self, byte pipeRef, MemoryAddress buf, int size) { + try (var session = MemorySession.openConfined()) { + return IOUSBInterfaceInterface.WritePipe(getVtable(self, session), session).apply(self, pipeRef, buf, size); } } - - // typedef struct { - // UInt8 bmRequestType; - // UInt8 bRequest; - // UInt16 wValue; - // UInt16 wIndex; - // UInt16 wLength; - // void* pData; - // UInt32 wLenDone; - //} IOUSBDevRequest; - public static final GroupLayout IOUSBDevRequest$Struct = structLayout(JAVA_BYTE.withName("bmRequestType"), - JAVA_BYTE.withName("bRequest"), JAVA_SHORT.withName("wValue"), JAVA_SHORT.withName("wIndex"), - JAVA_SHORT.withName("wLength"), ADDRESS.withName("pData"), JAVA_INT.withName("wLenDone")); - - public static final VarHandle IOUSBDevRequest_bmRequestType = IOUSBDevRequest$Struct.varHandle(groupElement( - "bmRequestType")); - public static final VarHandle IOUSBDevRequest_bRequest = IOUSBDevRequest$Struct.varHandle(groupElement("bRequest")); - public static final VarHandle IOUSBDevRequest_wValue = IOUSBDevRequest$Struct.varHandle(groupElement("wValue")); - public static final VarHandle IOUSBDevRequest_wIndex = IOUSBDevRequest$Struct.varHandle(groupElement("wIndex")); - public static final VarHandle IOUSBDevRequest_wLength = IOUSBDevRequest$Struct.varHandle(groupElement("wLength")); - public static final VarHandle IOUSBDevRequest_pData = IOUSBDevRequest$Struct.varHandle(groupElement("pData")); - public static final VarHandle IOUSBDevRequest_wLenDone = IOUSBDevRequest$Struct.varHandle(groupElement("wLenDone")); - } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 59954fcc..1a965ed8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -14,6 +14,9 @@ import net.codecrete.usb.common.DescriptorParser; import net.codecrete.usb.common.USBDescriptors; import net.codecrete.usb.common.USBDeviceImpl; +import net.codecrete.usb.macos.gen.iokit.IOKit; +import net.codecrete.usb.macos.gen.iokit.IOUSBDevRequest; +import net.codecrete.usb.macos.gen.iokit.IOUSBFindInterfaceRequest; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; @@ -39,7 +42,7 @@ public class MacosUSBDevice extends USBDeviceImpl { loadDescription(); - IoKit.AddRef(device); + IoKitUSB.AddRef(device); } @Override @@ -73,7 +76,7 @@ public void close() { for (InterfaceInfo interfaceInfo : claimedInterfaces) { IoKitUSB.USBInterfaceClose(interfaceInfo.asAddress()); - IoKit.Release(interfaceInfo.asAddress()); + IoKitUSB.Release(interfaceInfo.asAddress()); setClaimed(interfaceInfo.interfaceNumber, false); } @@ -84,7 +87,7 @@ public void close() { void closeFully() { close(); - IoKit.Release(device); + IoKitUSB.Release(device); } private void loadDescription() { @@ -93,7 +96,7 @@ private void loadDescription() { try { // retrieve information of first configuration var descPtrHolder = session.allocate(ADDRESS); - int ret = IoKitUSB.GetConfigurationDescriptorPtr(device, (byte) 0, descPtrHolder); + int ret = IoKitUSB.GetConfigurationDescriptorPtr(device, (byte) 0, descPtrHolder.address()); if (ret != 0) throw new MacosUSBException("failed to query first configuration", ret); @@ -119,33 +122,33 @@ private void loadDescription() { private InterfaceInfo findInterface(int interfaceNumber) { try (var outerSession = MemorySession.openConfined()) { - var request = outerSession.allocate(IoKitUSB.IOUSBFindInterfaceRequest$Struct); - IoKitUSB.IOUSBFindInterfaceRequest_bInterfaceClass.set(request, IoKitUSB.kIOUSBFindInterfaceDontCare); - IoKitUSB.IOUSBFindInterfaceRequest_bInterfaceSubClass.set(request, IoKitUSB.kIOUSBFindInterfaceDontCare); - IoKitUSB.IOUSBFindInterfaceRequest_bInterfaceProtocol.set(request, IoKitUSB.kIOUSBFindInterfaceDontCare); - IoKitUSB.IOUSBFindInterfaceRequest_bAlternateSetting.set(request, IoKitUSB.kIOUSBFindInterfaceDontCare); + var request = outerSession.allocate(IOUSBFindInterfaceRequest.$LAYOUT()); + IOUSBFindInterfaceRequest.bInterfaceClass$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); + IOUSBFindInterfaceRequest.bInterfaceSubClass$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); + IOUSBFindInterfaceRequest.bInterfaceProtocol$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); + IOUSBFindInterfaceRequest.bAlternateSetting$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); var iterHolder = outerSession.allocate(JAVA_INT); - int ret = IoKitUSB.CreateInterfaceIterator(device, request, iterHolder); + int ret = IoKitUSB.CreateInterfaceIterator(device, request.address(), iterHolder.address()); final var iter = iterHolder.get(JAVA_INT, 0); if (ret != 0) throw new RuntimeException("CreateInterfaceIterator failed"); - outerSession.addCloseAction(() -> IoKit.IOObjectRelease(iter)); + outerSession.addCloseAction(() -> IOKit.IOObjectRelease(iter)); int service; - while ((service = IoKit.IOIteratorNext(iter)) != 0) { + while ((service = IOKit.IOIteratorNext(iter)) != 0) { try (var session = MemorySession.openConfined()) { final int service_final = service; - session.addCloseAction(() -> IoKit.IOObjectRelease(service_final)); + session.addCloseAction(() -> IOKit.IOObjectRelease(service_final)); final MemoryAddress intf = IoKitHelper.getInterface(service, - IoKit.kIOUSBInterfaceUserClientTypeID, IoKit.kIOUSBInterfaceInterfaceID100); + IoKitHelper.kIOUSBInterfaceUserClientTypeID, IoKitHelper.kIOUSBInterfaceInterfaceID100); if (intf == null) continue; var intfNumberHolder = session.allocate(JAVA_INT); - IoKitUSB.GetInterfaceNumber(intf, intfNumberHolder); + IoKitUSB.GetInterfaceNumber(intf, intfNumberHolder.address()); if (intfNumberHolder.get(JAVA_INT, 0) != interfaceNumber) { - IoKit.Release(intf); + IoKitUSB.Release(intf); continue; } @@ -169,7 +172,7 @@ public void claimInterface(int interfaceNumber) { setClaimed(interfaceNumber, true); } catch (Throwable t) { - IoKit.Release(interfaceInfo.asAddress()); + IoKitUSB.Release(interfaceInfo.asAddress()); throw t; } @@ -192,7 +195,7 @@ public void releaseInterface(int interfaceNumber) { if (ret != 0) throw new MacosUSBException("Failed to release interface", ret); claimedInterfaces.remove(interfaceInfo); - IoKit.Release(interfaceInfo.asAddress()); + IoKitUSB.Release(interfaceInfo.asAddress()); setClaimed(interfaceNumber, false); updateEndpointList(); @@ -213,7 +216,7 @@ private void updateEndpointList() { var intf = interfaceInfo.asAddress(); var numEndpointsHolder = session.allocate(JAVA_BYTE); - int ret = IoKitUSB.GetNumEndpoints(intf, numEndpointsHolder); + int ret = IoKitUSB.GetNumEndpoints(intf, numEndpointsHolder.address()); if (ret != 0) throw new MacosUSBException("Failed to get number of endpoints", ret); int numEndpoints = numEndpointsHolder.get(JAVA_BYTE, 0) & 255; @@ -226,8 +229,9 @@ private void updateEndpointList() { var maxPacketSizeHolder = session.allocate(JAVA_SHORT); var intervalHolder = session.allocate(JAVA_BYTE); - ret = IoKitUSB.GetPipeProperties(intf, (byte) pipeIndex, directionHolder, numberHolder, - transferTypeHolder, maxPacketSizeHolder, intervalHolder); + ret = IoKitUSB.GetPipeProperties(intf, (byte) pipeIndex, directionHolder.address(), + numberHolder.address(), transferTypeHolder.address(), maxPacketSizeHolder.address(), + intervalHolder.address()); if (ret != 0) throw new MacosUSBException("Failed to get pipe properties", ret); int endpointNumber = numberHolder.get(JAVA_BYTE, 0) & 255; @@ -256,15 +260,15 @@ private EndpointInfo getEndpointInfo(int endpointNumber, USBDirection direction, private static MemorySegment createDeviceRequest(MemorySession session, USBDirection direction, USBControlTransfer setup, MemorySegment data) { - var deviceRequest = session.allocate(IoKitUSB.IOUSBDevRequest$Struct); + var deviceRequest = session.allocate(IOUSBDevRequest.$LAYOUT()); var bmRequestType = (direction == USBDirection.IN ? 0x80 : 0x00) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); - IoKitUSB.IOUSBDevRequest_bmRequestType.set(deviceRequest, (byte) bmRequestType); - IoKitUSB.IOUSBDevRequest_bRequest.set(deviceRequest, setup.request()); - IoKitUSB.IOUSBDevRequest_wValue.set(deviceRequest, setup.value()); - IoKitUSB.IOUSBDevRequest_wIndex.set(deviceRequest, setup.index()); - IoKitUSB.IOUSBDevRequest_wLength.set(deviceRequest, (short) data.byteSize()); - IoKitUSB.IOUSBDevRequest_pData.set(deviceRequest, data.address()); + IOUSBDevRequest.bmRequestType$set(deviceRequest, (byte) bmRequestType); + IOUSBDevRequest.bRequest$set(deviceRequest, setup.request()); + IOUSBDevRequest.wValue$set(deviceRequest, setup.value()); + IOUSBDevRequest.wIndex$set(deviceRequest, setup.index()); + IOUSBDevRequest.wLength$set(deviceRequest, (short) data.byteSize()); + IOUSBDevRequest.pData$set(deviceRequest, data.address()); return deviceRequest; } @@ -276,10 +280,10 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { var data = session.allocate(length); var deviceRequest = createDeviceRequest(session, USBDirection.IN, setup, data); - int ret = IoKitUSB.DeviceRequest(device, deviceRequest); + int ret = IoKitUSB.DeviceRequest(device, deviceRequest.address()); if (ret != 0) throw new MacosUSBException("Control IN transfer failed", ret); - int lenDone = (int) IoKitUSB.IOUSBDevRequest_wLenDone.get(deviceRequest); + int lenDone = (int) IOUSBDevRequest.wLenDone$get(deviceRequest); return data.asSlice(0, lenDone).toArray(JAVA_BYTE); } } @@ -294,7 +298,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { if (dataLength > 0) dataSegment.copyFrom(MemorySegment.ofArray(data)); var deviceRequest = createDeviceRequest(session, USBDirection.OUT, setup, dataSegment); - int ret = IoKitUSB.DeviceRequest(device, deviceRequest); + int ret = IoKitUSB.DeviceRequest(device, deviceRequest.address()); if (ret != 0) throw new MacosUSBException("Control IN transfer failed", ret); } } @@ -308,7 +312,7 @@ public void transferOut(int endpointNumber, byte[] data) { var nativeData = session.allocateArray(JAVA_BYTE, data.length); nativeData.copyFrom(MemorySegment.ofArray(data)); int ret = IoKitUSB.WritePipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, - nativeData, data.length); + nativeData.address(), data.length); if (ret != 0) throw new MacosUSBException(String.format("Sending data to endpoint %d failed", endpointNumber), ret); } @@ -323,7 +327,7 @@ public byte[] transferIn(int endpointNumber, int maxLength) { var nativeData = session.allocateArray(JAVA_BYTE, maxLength); var sizeHolder = session.allocate(JAVA_INT, maxLength); int ret = IoKitUSB.ReadPipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, - nativeData, sizeHolder); + nativeData.address(), sizeHolder.address()); if (ret != 0) throw new MacosUSBException(String.format("Receiving data from endpoint %d failed", endpointNumber), ret); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index e1a1f6ce..ce5bb49e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -9,6 +9,8 @@ import net.codecrete.usb.USBDevice; import net.codecrete.usb.common.USBDeviceRegistry; +import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; +import net.codecrete.usb.macos.gen.iokit.IOKit; import java.lang.foreign.*; import java.lang.invoke.MethodHandle; @@ -40,15 +42,15 @@ protected void monitorDevices() { try { // setup run loop, run loop source and notification port - var notifyPort = IoKit.IONotificationPortCreate(IoKit.kIOMasterPortDefault); - var runLoopSource = IoKit.IONotificationPortGetRunLoopSource(notifyPort); + var notifyPort = IOKit.IONotificationPortCreate(IOKit.kIOMasterPortDefault$get()); + var runLoopSource = IOKit.IONotificationPortGetRunLoopSource(notifyPort); var runLoop = CoreFoundation.CFRunLoopGetCurrent(); - CoreFoundation.CFRunLoopAddSource(runLoop, runLoopSource, IoKit.kCFRunLoopDefaultMode); + CoreFoundation.CFRunLoopAddSource(runLoop, runLoopSource, IOKit.kCFRunLoopDefaultMode$get()); // setup notification for connected devices var onDeviceConnectedMH = MethodHandles.lookup().findVirtual(MacosUSBDeviceRegistry.class, "onDevicesConnected", MethodType.methodType(void.class, MemoryAddress.class, int.class)); - int deviceConnectedIter = setupNotification(session, notifyPort, IoKit.kIOFirstMatchNotification, + int deviceConnectedIter = setupNotification(session, notifyPort, IOKit.kIOFirstMatchNotification(), onDeviceConnectedMH); // iterate current devices in order to arm the notifications (and build initial device list) @@ -59,7 +61,7 @@ protected void monitorDevices() { // setup notification for disconnected devices var onDeviceDisconnectedMH = MethodHandles.lookup().findVirtual(MacosUSBDeviceRegistry.class, "onDevicesDisconnected", MethodType.methodType(void.class, MemoryAddress.class, int.class)); - int deviceDisconnectedIter = setupNotification(session, notifyPort, IoKit.kIOTerminatedNotification, + int deviceDisconnectedIter = setupNotification(session, notifyPort, IOKit.kIOTerminatedNotification(), onDeviceDisconnectedMH); // iterate current devices in order to arm the notifications @@ -84,21 +86,21 @@ protected void monitorDevices() { private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { int svc; - while ((svc = IoKit.IOIteratorNext(iterator)) != 0) { + while ((svc = IOKit.IOIteratorNext(iterator)) != 0) { try (var session = MemorySession.openConfined()) { final int service = svc; - session.addCloseAction(() -> IoKit.IOObjectRelease(service)); + session.addCloseAction(() -> IOKit.IOObjectRelease(service)); - var device = IoKitHelper.getInterface(service, IoKit.kIOUSBDeviceUserClientTypeID, - IoKit.kIOUSBDeviceInterfaceID100); + var device = IoKitHelper.getInterface(service, IoKitHelper.kIOUSBDeviceUserClientTypeID, + IoKitHelper.kIOUSBDeviceInterfaceID100); if (device != null) - session.addCloseAction(() -> IoKit.Release(device)); + session.addCloseAction(() -> IoKitUSB.Release(device)); // get entry ID (as unique ID) var entryIdHolder = session.allocate(JAVA_LONG); - int ret = IoKit.IORegistryEntryGetRegistryEntryID(service, entryIdHolder); + int ret = IOKit.IORegistryEntryGetRegistryEntryID(service, entryIdHolder); if (ret != 0) throw new MacosUSBException("IORegistryEntryGetRegistryEntryID failed", ret); var entryId = entryIdHolder.get(JAVA_LONG, 0); @@ -168,7 +170,7 @@ private int setupNotification(MemorySession session, MemoryAddress notifyPort, M MethodHandle callback) { // new matching dictionary for (dis)connected device notifications - MemoryAddress matchingDict = IoKit.IOServiceMatching(IoKit.kIOUSBDeviceClassName); + MemoryAddress matchingDict = IOKit.IOServiceMatching(IOKit.kIOUSBDeviceClassName()); // create callback stub var onDeviceCallbackStub = Linker.nativeLinker().upcallStub(callback.bindTo(this), @@ -177,7 +179,7 @@ private int setupNotification(MemorySession session, MemoryAddress notifyPort, M // Set up a notification to be called when a device is first matched / terminated by I/O Kit. // This method consumes the matchingDict reference. var deviceIterHolder = session.allocate(JAVA_INT); - int ret = IoKit.IOServiceAddMatchingNotification(notifyPort, notificationType, matchingDict, + int ret = IOKit.IOServiceAddMatchingNotification(notifyPort, notificationType, matchingDict, onDeviceCallbackStub, NULL, deviceIterHolder); if (ret != 0) throw new MacosUSBException("IOServiceAddMatchingNotification failed", ret); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java new file mode 100644 index 00000000..e7761f51 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java @@ -0,0 +1,50 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.macos; + +import net.codecrete.usb.macos.gen.corefoundation.CFUUIDBytes; +import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; + +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySession; + +import static java.lang.foreign.MemoryAddress.NULL; +import static java.lang.foreign.MemoryLayout.sequenceLayout; +import static java.lang.foreign.MemoryLayout.structLayout; +import static java.lang.foreign.ValueLayout.*; + +/** + * Memory layouts and helpers for CFUUID. + */ +public class UUID { + + public static final GroupLayout CFUUID = structLayout( + ADDRESS.withName("_cfisa"), // uintptr_t _cfisa; + sequenceLayout(4, JAVA_BYTE).withName("_cfinfo"), // uint8_t _cfinfo[4]; + JAVA_INT.withName("_rc"), // uint32_t _rc; + CFUUIDBytes.$LAYOUT().withName("_bytes") // CFUUIDBytes _bytes; + ); + public static final long CFUUID_bytes$Offset = CFUUID.byteOffset(MemoryLayout.PathElement.groupElement("_bytes")); + + /** + * Creates a CFUUID struct from a byte array. + * @param bytes UUID as 16 bytes + * @return the CFUUID + */ + public static MemoryAddress CreateCFUUID(byte[] bytes) { + try (var session = MemorySession.openConfined()) { + var uuidBytes = session.allocate(16); + uuidBytes.asByteBuffer().put(bytes); + return CoreFoundation.CFUUIDCreateFromUUIDBytes(NULL, uuidBytes); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java new file mode 100644 index 00000000..d53e92ea --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java @@ -0,0 +1,56 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.corefoundation; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class CFRange { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_LONG_LONG$LAYOUT.withName("location"), + Constants$root.C_LONG_LONG$LAYOUT.withName("length") + ); + public static MemoryLayout $LAYOUT() { + return CFRange.$struct$LAYOUT; + } + static final VarHandle location$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("location")); + public static VarHandle location$VH() { + return CFRange.location$VH; + } + public static long location$get(MemorySegment seg) { + return (long)CFRange.location$VH.get(seg); + } + public static void location$set( MemorySegment seg, long x) { + CFRange.location$VH.set(seg, x); + } + public static long location$get(MemorySegment seg, long index) { + return (long)CFRange.location$VH.get(seg.asSlice(index*sizeof())); + } + public static void location$set(MemorySegment seg, long index, long x) { + CFRange.location$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle length$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("length")); + public static VarHandle length$VH() { + return CFRange.length$VH; + } + public static long length$get(MemorySegment seg) { + return (long)CFRange.length$VH.get(seg); + } + public static void length$set( MemorySegment seg, long x) { + CFRange.length$VH.set(seg, x); + } + public static long length$get(MemorySegment seg, long index) { + return (long)CFRange.length$VH.get(seg.asSlice(index*sizeof())); + } + public static void length$set(MemorySegment seg, long index, long x) { + CFRange.length$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java new file mode 100644 index 00000000..f69fbaa5 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java @@ -0,0 +1,294 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.corefoundation; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class CFUUIDBytes { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("byte0"), + Constants$root.C_CHAR$LAYOUT.withName("byte1"), + Constants$root.C_CHAR$LAYOUT.withName("byte2"), + Constants$root.C_CHAR$LAYOUT.withName("byte3"), + Constants$root.C_CHAR$LAYOUT.withName("byte4"), + Constants$root.C_CHAR$LAYOUT.withName("byte5"), + Constants$root.C_CHAR$LAYOUT.withName("byte6"), + Constants$root.C_CHAR$LAYOUT.withName("byte7"), + Constants$root.C_CHAR$LAYOUT.withName("byte8"), + Constants$root.C_CHAR$LAYOUT.withName("byte9"), + Constants$root.C_CHAR$LAYOUT.withName("byte10"), + Constants$root.C_CHAR$LAYOUT.withName("byte11"), + Constants$root.C_CHAR$LAYOUT.withName("byte12"), + Constants$root.C_CHAR$LAYOUT.withName("byte13"), + Constants$root.C_CHAR$LAYOUT.withName("byte14"), + Constants$root.C_CHAR$LAYOUT.withName("byte15") + ); + public static MemoryLayout $LAYOUT() { + return CFUUIDBytes.$struct$LAYOUT; + } + static final VarHandle byte0$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte0")); + public static VarHandle byte0$VH() { + return CFUUIDBytes.byte0$VH; + } + public static byte byte0$get(MemorySegment seg) { + return (byte)CFUUIDBytes.byte0$VH.get(seg); + } + public static void byte0$set( MemorySegment seg, byte x) { + CFUUIDBytes.byte0$VH.set(seg, x); + } + public static byte byte0$get(MemorySegment seg, long index) { + return (byte)CFUUIDBytes.byte0$VH.get(seg.asSlice(index*sizeof())); + } + public static void byte0$set(MemorySegment seg, long index, byte x) { + CFUUIDBytes.byte0$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle byte1$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte1")); + public static VarHandle byte1$VH() { + return CFUUIDBytes.byte1$VH; + } + public static byte byte1$get(MemorySegment seg) { + return (byte)CFUUIDBytes.byte1$VH.get(seg); + } + public static void byte1$set( MemorySegment seg, byte x) { + CFUUIDBytes.byte1$VH.set(seg, x); + } + public static byte byte1$get(MemorySegment seg, long index) { + return (byte)CFUUIDBytes.byte1$VH.get(seg.asSlice(index*sizeof())); + } + public static void byte1$set(MemorySegment seg, long index, byte x) { + CFUUIDBytes.byte1$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle byte2$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte2")); + public static VarHandle byte2$VH() { + return CFUUIDBytes.byte2$VH; + } + public static byte byte2$get(MemorySegment seg) { + return (byte)CFUUIDBytes.byte2$VH.get(seg); + } + public static void byte2$set( MemorySegment seg, byte x) { + CFUUIDBytes.byte2$VH.set(seg, x); + } + public static byte byte2$get(MemorySegment seg, long index) { + return (byte)CFUUIDBytes.byte2$VH.get(seg.asSlice(index*sizeof())); + } + public static void byte2$set(MemorySegment seg, long index, byte x) { + CFUUIDBytes.byte2$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle byte3$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte3")); + public static VarHandle byte3$VH() { + return CFUUIDBytes.byte3$VH; + } + public static byte byte3$get(MemorySegment seg) { + return (byte)CFUUIDBytes.byte3$VH.get(seg); + } + public static void byte3$set( MemorySegment seg, byte x) { + CFUUIDBytes.byte3$VH.set(seg, x); + } + public static byte byte3$get(MemorySegment seg, long index) { + return (byte)CFUUIDBytes.byte3$VH.get(seg.asSlice(index*sizeof())); + } + public static void byte3$set(MemorySegment seg, long index, byte x) { + CFUUIDBytes.byte3$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle byte4$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte4")); + public static VarHandle byte4$VH() { + return CFUUIDBytes.byte4$VH; + } + public static byte byte4$get(MemorySegment seg) { + return (byte)CFUUIDBytes.byte4$VH.get(seg); + } + public static void byte4$set( MemorySegment seg, byte x) { + CFUUIDBytes.byte4$VH.set(seg, x); + } + public static byte byte4$get(MemorySegment seg, long index) { + return (byte)CFUUIDBytes.byte4$VH.get(seg.asSlice(index*sizeof())); + } + public static void byte4$set(MemorySegment seg, long index, byte x) { + CFUUIDBytes.byte4$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle byte5$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte5")); + public static VarHandle byte5$VH() { + return CFUUIDBytes.byte5$VH; + } + public static byte byte5$get(MemorySegment seg) { + return (byte)CFUUIDBytes.byte5$VH.get(seg); + } + public static void byte5$set( MemorySegment seg, byte x) { + CFUUIDBytes.byte5$VH.set(seg, x); + } + public static byte byte5$get(MemorySegment seg, long index) { + return (byte)CFUUIDBytes.byte5$VH.get(seg.asSlice(index*sizeof())); + } + public static void byte5$set(MemorySegment seg, long index, byte x) { + CFUUIDBytes.byte5$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle byte6$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte6")); + public static VarHandle byte6$VH() { + return CFUUIDBytes.byte6$VH; + } + public static byte byte6$get(MemorySegment seg) { + return (byte)CFUUIDBytes.byte6$VH.get(seg); + } + public static void byte6$set( MemorySegment seg, byte x) { + CFUUIDBytes.byte6$VH.set(seg, x); + } + public static byte byte6$get(MemorySegment seg, long index) { + return (byte)CFUUIDBytes.byte6$VH.get(seg.asSlice(index*sizeof())); + } + public static void byte6$set(MemorySegment seg, long index, byte x) { + CFUUIDBytes.byte6$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle byte7$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte7")); + public static VarHandle byte7$VH() { + return CFUUIDBytes.byte7$VH; + } + public static byte byte7$get(MemorySegment seg) { + return (byte)CFUUIDBytes.byte7$VH.get(seg); + } + public static void byte7$set( MemorySegment seg, byte x) { + CFUUIDBytes.byte7$VH.set(seg, x); + } + public static byte byte7$get(MemorySegment seg, long index) { + return (byte)CFUUIDBytes.byte7$VH.get(seg.asSlice(index*sizeof())); + } + public static void byte7$set(MemorySegment seg, long index, byte x) { + CFUUIDBytes.byte7$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle byte8$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte8")); + public static VarHandle byte8$VH() { + return CFUUIDBytes.byte8$VH; + } + public static byte byte8$get(MemorySegment seg) { + return (byte)CFUUIDBytes.byte8$VH.get(seg); + } + public static void byte8$set( MemorySegment seg, byte x) { + CFUUIDBytes.byte8$VH.set(seg, x); + } + public static byte byte8$get(MemorySegment seg, long index) { + return (byte)CFUUIDBytes.byte8$VH.get(seg.asSlice(index*sizeof())); + } + public static void byte8$set(MemorySegment seg, long index, byte x) { + CFUUIDBytes.byte8$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle byte9$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte9")); + public static VarHandle byte9$VH() { + return CFUUIDBytes.byte9$VH; + } + public static byte byte9$get(MemorySegment seg) { + return (byte)CFUUIDBytes.byte9$VH.get(seg); + } + public static void byte9$set( MemorySegment seg, byte x) { + CFUUIDBytes.byte9$VH.set(seg, x); + } + public static byte byte9$get(MemorySegment seg, long index) { + return (byte)CFUUIDBytes.byte9$VH.get(seg.asSlice(index*sizeof())); + } + public static void byte9$set(MemorySegment seg, long index, byte x) { + CFUUIDBytes.byte9$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle byte10$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte10")); + public static VarHandle byte10$VH() { + return CFUUIDBytes.byte10$VH; + } + public static byte byte10$get(MemorySegment seg) { + return (byte)CFUUIDBytes.byte10$VH.get(seg); + } + public static void byte10$set( MemorySegment seg, byte x) { + CFUUIDBytes.byte10$VH.set(seg, x); + } + public static byte byte10$get(MemorySegment seg, long index) { + return (byte)CFUUIDBytes.byte10$VH.get(seg.asSlice(index*sizeof())); + } + public static void byte10$set(MemorySegment seg, long index, byte x) { + CFUUIDBytes.byte10$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle byte11$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte11")); + public static VarHandle byte11$VH() { + return CFUUIDBytes.byte11$VH; + } + public static byte byte11$get(MemorySegment seg) { + return (byte)CFUUIDBytes.byte11$VH.get(seg); + } + public static void byte11$set( MemorySegment seg, byte x) { + CFUUIDBytes.byte11$VH.set(seg, x); + } + public static byte byte11$get(MemorySegment seg, long index) { + return (byte)CFUUIDBytes.byte11$VH.get(seg.asSlice(index*sizeof())); + } + public static void byte11$set(MemorySegment seg, long index, byte x) { + CFUUIDBytes.byte11$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle byte12$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte12")); + public static VarHandle byte12$VH() { + return CFUUIDBytes.byte12$VH; + } + public static byte byte12$get(MemorySegment seg) { + return (byte)CFUUIDBytes.byte12$VH.get(seg); + } + public static void byte12$set( MemorySegment seg, byte x) { + CFUUIDBytes.byte12$VH.set(seg, x); + } + public static byte byte12$get(MemorySegment seg, long index) { + return (byte)CFUUIDBytes.byte12$VH.get(seg.asSlice(index*sizeof())); + } + public static void byte12$set(MemorySegment seg, long index, byte x) { + CFUUIDBytes.byte12$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle byte13$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte13")); + public static VarHandle byte13$VH() { + return CFUUIDBytes.byte13$VH; + } + public static byte byte13$get(MemorySegment seg) { + return (byte)CFUUIDBytes.byte13$VH.get(seg); + } + public static void byte13$set( MemorySegment seg, byte x) { + CFUUIDBytes.byte13$VH.set(seg, x); + } + public static byte byte13$get(MemorySegment seg, long index) { + return (byte)CFUUIDBytes.byte13$VH.get(seg.asSlice(index*sizeof())); + } + public static void byte13$set(MemorySegment seg, long index, byte x) { + CFUUIDBytes.byte13$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle byte14$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte14")); + public static VarHandle byte14$VH() { + return CFUUIDBytes.byte14$VH; + } + public static byte byte14$get(MemorySegment seg) { + return (byte)CFUUIDBytes.byte14$VH.get(seg); + } + public static void byte14$set( MemorySegment seg, byte x) { + CFUUIDBytes.byte14$VH.set(seg, x); + } + public static byte byte14$get(MemorySegment seg, long index) { + return (byte)CFUUIDBytes.byte14$VH.get(seg.asSlice(index*sizeof())); + } + public static void byte14$set(MemorySegment seg, long index, byte x) { + CFUUIDBytes.byte14$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle byte15$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte15")); + public static VarHandle byte15$VH() { + return CFUUIDBytes.byte15$VH; + } + public static byte byte15$get(MemorySegment seg) { + return (byte)CFUUIDBytes.byte15$VH.get(seg); + } + public static void byte15$set( MemorySegment seg, byte x) { + CFUUIDBytes.byte15$VH.set(seg, x); + } + public static byte byte15$get(MemorySegment seg, long index) { + return (byte)CFUUIDBytes.byte15$VH.get(seg.asSlice(index*sizeof())); + } + public static void byte15$set(MemorySegment seg, long index, byte x) { + CFUUIDBytes.byte15$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/Constants$root.java new file mode 100644 index 00000000..0755ccbe --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.corefoundation; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java new file mode 100644 index 00000000..df785d3a --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java @@ -0,0 +1,159 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.corefoundation; + +import java.lang.foreign.Addressable; +import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.*; +public class CoreFoundation { + + /* package-private */ CoreFoundation() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static MethodHandle CFGetTypeID$MH() { + return RuntimeHelper.requireNonNull(constants$0.CFGetTypeID$MH,"CFGetTypeID"); + } + public static long CFGetTypeID ( Addressable cf) { + var mh$ = CFGetTypeID$MH(); + try { + return (long)mh$.invokeExact(cf); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle CFRelease$MH() { + return RuntimeHelper.requireNonNull(constants$0.CFRelease$MH,"CFRelease"); + } + public static void CFRelease ( Addressable cf) { + var mh$ = CFRelease$MH(); + try { + mh$.invokeExact(cf); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle CFStringGetTypeID$MH() { + return RuntimeHelper.requireNonNull(constants$0.CFStringGetTypeID$MH,"CFStringGetTypeID"); + } + public static long CFStringGetTypeID () { + var mh$ = CFStringGetTypeID$MH(); + try { + return (long)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle CFStringCreateWithCharacters$MH() { + return RuntimeHelper.requireNonNull(constants$0.CFStringCreateWithCharacters$MH,"CFStringCreateWithCharacters"); + } + public static MemoryAddress CFStringCreateWithCharacters ( Addressable alloc, Addressable chars, long numChars) { + var mh$ = CFStringCreateWithCharacters$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(alloc, chars, numChars); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle CFStringGetLength$MH() { + return RuntimeHelper.requireNonNull(constants$0.CFStringGetLength$MH,"CFStringGetLength"); + } + public static long CFStringGetLength ( Addressable theString) { + var mh$ = CFStringGetLength$MH(); + try { + return (long)mh$.invokeExact(theString); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle CFStringGetCharacters$MH() { + return RuntimeHelper.requireNonNull(constants$0.CFStringGetCharacters$MH,"CFStringGetCharacters"); + } + public static void CFStringGetCharacters ( Addressable theString, MemorySegment range, Addressable buffer) { + var mh$ = CFStringGetCharacters$MH(); + try { + mh$.invokeExact(theString, range, buffer); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static int kCFNumberSInt32Type() { + return (int)3L; + } + public static MethodHandle CFNumberGetTypeID$MH() { + return RuntimeHelper.requireNonNull(constants$1.CFNumberGetTypeID$MH,"CFNumberGetTypeID"); + } + public static long CFNumberGetTypeID () { + var mh$ = CFNumberGetTypeID$MH(); + try { + return (long)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle CFNumberGetValue$MH() { + return RuntimeHelper.requireNonNull(constants$1.CFNumberGetValue$MH,"CFNumberGetValue"); + } + public static byte CFNumberGetValue ( Addressable number, long theType, Addressable valuePtr) { + var mh$ = CFNumberGetValue$MH(); + try { + return (byte)mh$.invokeExact(number, theType, valuePtr); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle CFRunLoopGetCurrent$MH() { + return RuntimeHelper.requireNonNull(constants$1.CFRunLoopGetCurrent$MH,"CFRunLoopGetCurrent"); + } + public static MemoryAddress CFRunLoopGetCurrent () { + var mh$ = CFRunLoopGetCurrent$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle CFRunLoopRun$MH() { + return RuntimeHelper.requireNonNull(constants$1.CFRunLoopRun$MH,"CFRunLoopRun"); + } + public static void CFRunLoopRun () { + var mh$ = CFRunLoopRun$MH(); + try { + mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle CFRunLoopAddSource$MH() { + return RuntimeHelper.requireNonNull(constants$1.CFRunLoopAddSource$MH,"CFRunLoopAddSource"); + } + public static void CFRunLoopAddSource ( Addressable rl, Addressable source, Addressable mode) { + var mh$ = CFRunLoopAddSource$MH(); + try { + mh$.invokeExact(rl, source, mode); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle CFUUIDCreateFromUUIDBytes$MH() { + return RuntimeHelper.requireNonNull(constants$1.CFUUIDCreateFromUUIDBytes$MH,"CFUUIDCreateFromUUIDBytes"); + } + public static MemoryAddress CFUUIDCreateFromUUIDBytes ( Addressable alloc, MemorySegment bytes) { + var mh$ = CFUUIDCreateFromUUIDBytes$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(alloc, bytes); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java new file mode 100644 index 00000000..868a5980 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java @@ -0,0 +1,217 @@ +package net.codecrete.usb.macos.gen.corefoundation; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { +// System.loadLibrary("CoreFoundation.framework"); +// SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SymbolLookup loaderLookup = SymbolLookup.libraryLookup("CoreFoundation.framework/CoreFoundation", MemorySession.openImplicit()); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$0.java new file mode 100644 index 00000000..08d7d3ea --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$0.java @@ -0,0 +1,59 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.corefoundation; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor CFGetTypeID$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CFGetTypeID$MH = RuntimeHelper.downcallHandle( + "CFGetTypeID", + constants$0.CFGetTypeID$FUNC + ); + static final FunctionDescriptor CFRelease$FUNC = FunctionDescriptor.ofVoid( + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CFRelease$MH = RuntimeHelper.downcallHandle( + "CFRelease", + constants$0.CFRelease$FUNC + ); + static final FunctionDescriptor CFStringGetTypeID$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT); + static final MethodHandle CFStringGetTypeID$MH = RuntimeHelper.downcallHandle( + "CFStringGetTypeID", + constants$0.CFStringGetTypeID$FUNC + ); + static final FunctionDescriptor CFStringCreateWithCharacters$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle CFStringCreateWithCharacters$MH = RuntimeHelper.downcallHandle( + "CFStringCreateWithCharacters", + constants$0.CFStringCreateWithCharacters$FUNC + ); + static final FunctionDescriptor CFStringGetLength$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CFStringGetLength$MH = RuntimeHelper.downcallHandle( + "CFStringGetLength", + constants$0.CFStringGetLength$FUNC + ); + static final FunctionDescriptor CFStringGetCharacters$FUNC = FunctionDescriptor.ofVoid( + Constants$root.C_POINTER$LAYOUT, + MemoryLayout.structLayout( + Constants$root.C_LONG_LONG$LAYOUT.withName("location"), + Constants$root.C_LONG_LONG$LAYOUT.withName("length") + ), + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CFStringGetCharacters$MH = RuntimeHelper.downcallHandle( + "CFStringGetCharacters", + constants$0.CFStringGetCharacters$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java new file mode 100644 index 00000000..f98c85dc --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java @@ -0,0 +1,70 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.corefoundation; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +class constants$1 { + + static final FunctionDescriptor CFNumberGetTypeID$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT); + static final MethodHandle CFNumberGetTypeID$MH = RuntimeHelper.downcallHandle( + "CFNumberGetTypeID", + constants$1.CFNumberGetTypeID$FUNC + ); + static final FunctionDescriptor CFNumberGetValue$FUNC = FunctionDescriptor.of(Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CFNumberGetValue$MH = RuntimeHelper.downcallHandle( + "CFNumberGetValue", + constants$1.CFNumberGetValue$FUNC + ); + static final FunctionDescriptor CFRunLoopGetCurrent$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT); + static final MethodHandle CFRunLoopGetCurrent$MH = RuntimeHelper.downcallHandle( + "CFRunLoopGetCurrent", + constants$1.CFRunLoopGetCurrent$FUNC + ); + static final FunctionDescriptor CFRunLoopRun$FUNC = FunctionDescriptor.ofVoid(); + static final MethodHandle CFRunLoopRun$MH = RuntimeHelper.downcallHandle( + "CFRunLoopRun", + constants$1.CFRunLoopRun$FUNC + ); + static final FunctionDescriptor CFRunLoopAddSource$FUNC = FunctionDescriptor.ofVoid( + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CFRunLoopAddSource$MH = RuntimeHelper.downcallHandle( + "CFRunLoopAddSource", + constants$1.CFRunLoopAddSource$FUNC + ); + static final FunctionDescriptor CFUUIDCreateFromUUIDBytes$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("byte0"), + Constants$root.C_CHAR$LAYOUT.withName("byte1"), + Constants$root.C_CHAR$LAYOUT.withName("byte2"), + Constants$root.C_CHAR$LAYOUT.withName("byte3"), + Constants$root.C_CHAR$LAYOUT.withName("byte4"), + Constants$root.C_CHAR$LAYOUT.withName("byte5"), + Constants$root.C_CHAR$LAYOUT.withName("byte6"), + Constants$root.C_CHAR$LAYOUT.withName("byte7"), + Constants$root.C_CHAR$LAYOUT.withName("byte8"), + Constants$root.C_CHAR$LAYOUT.withName("byte9"), + Constants$root.C_CHAR$LAYOUT.withName("byte10"), + Constants$root.C_CHAR$LAYOUT.withName("byte11"), + Constants$root.C_CHAR$LAYOUT.withName("byte12"), + Constants$root.C_CHAR$LAYOUT.withName("byte13"), + Constants$root.C_CHAR$LAYOUT.withName("byte14"), + Constants$root.C_CHAR$LAYOUT.withName("byte15") + ) + ); + static final MethodHandle CFUUIDCreateFromUUIDBytes$MH = RuntimeHelper.downcallHandle( + "CFUUIDCreateFromUUIDBytes", + constants$1.CFUUIDCreateFromUUIDBytes$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/Constants$root.java new file mode 100644 index 00000000..baa3d26a --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterface.java new file mode 100644 index 00000000..401ce8fc --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterface.java @@ -0,0 +1,9 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +public class IOCFPlugInInterface extends IOCFPlugInInterfaceStruct { + +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java new file mode 100644 index 00000000..5f9e0c79 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java @@ -0,0 +1,363 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +public class IOCFPlugInInterfaceStruct { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_POINTER$LAYOUT.withName("_reserved"), + Constants$root.C_POINTER$LAYOUT.withName("QueryInterface"), + Constants$root.C_POINTER$LAYOUT.withName("AddRef"), + Constants$root.C_POINTER$LAYOUT.withName("Release"), + Constants$root.C_SHORT$LAYOUT.withName("version"), + Constants$root.C_SHORT$LAYOUT.withName("revision"), + MemoryLayout.paddingLayout(32), + Constants$root.C_POINTER$LAYOUT.withName("Probe"), + Constants$root.C_POINTER$LAYOUT.withName("Start"), + Constants$root.C_POINTER$LAYOUT.withName("Stop") + ).withName("IOCFPlugInInterfaceStruct"); + public static MemoryLayout $LAYOUT() { + return IOCFPlugInInterfaceStruct.$struct$LAYOUT; + } + static final VarHandle _reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("_reserved")); + public static VarHandle _reserved$VH() { + return IOCFPlugInInterfaceStruct._reserved$VH; + } + public static MemoryAddress _reserved$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct._reserved$VH.get(seg); + } + public static void _reserved$set( MemorySegment seg, MemoryAddress x) { + IOCFPlugInInterfaceStruct._reserved$VH.set(seg, x); + } + public static MemoryAddress _reserved$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct._reserved$VH.get(seg.asSlice(index*sizeof())); + } + public static void _reserved$set(MemorySegment seg, long index, MemoryAddress x) { + IOCFPlugInInterfaceStruct._reserved$VH.set(seg.asSlice(index*sizeof()), x); + } + static final FunctionDescriptor QueryInterface$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("byte0"), + Constants$root.C_CHAR$LAYOUT.withName("byte1"), + Constants$root.C_CHAR$LAYOUT.withName("byte2"), + Constants$root.C_CHAR$LAYOUT.withName("byte3"), + Constants$root.C_CHAR$LAYOUT.withName("byte4"), + Constants$root.C_CHAR$LAYOUT.withName("byte5"), + Constants$root.C_CHAR$LAYOUT.withName("byte6"), + Constants$root.C_CHAR$LAYOUT.withName("byte7"), + Constants$root.C_CHAR$LAYOUT.withName("byte8"), + Constants$root.C_CHAR$LAYOUT.withName("byte9"), + Constants$root.C_CHAR$LAYOUT.withName("byte10"), + Constants$root.C_CHAR$LAYOUT.withName("byte11"), + Constants$root.C_CHAR$LAYOUT.withName("byte12"), + Constants$root.C_CHAR$LAYOUT.withName("byte13"), + Constants$root.C_CHAR$LAYOUT.withName("byte14"), + Constants$root.C_CHAR$LAYOUT.withName("byte15") + ), + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle QueryInterface$MH = RuntimeHelper.downcallHandle( + IOCFPlugInInterfaceStruct.QueryInterface$FUNC + ); + public interface QueryInterface { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(QueryInterface fi, MemorySession session) { + return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOCFPlugInInterfaceStruct.QueryInterface$FUNC, session); + } + static QueryInterface ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOCFPlugInInterfaceStruct.QueryInterface$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle QueryInterface$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("QueryInterface")); + public static VarHandle QueryInterface$VH() { + return IOCFPlugInInterfaceStruct.QueryInterface$VH; + } + public static MemoryAddress QueryInterface$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.QueryInterface$VH.get(seg); + } + public static void QueryInterface$set( MemorySegment seg, MemoryAddress x) { + IOCFPlugInInterfaceStruct.QueryInterface$VH.set(seg, x); + } + public static MemoryAddress QueryInterface$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.QueryInterface$VH.get(seg.asSlice(index*sizeof())); + } + public static void QueryInterface$set(MemorySegment seg, long index, MemoryAddress x) { + IOCFPlugInInterfaceStruct.QueryInterface$VH.set(seg.asSlice(index*sizeof()), x); + } + public static QueryInterface QueryInterface (MemorySegment segment, MemorySession session) { + return QueryInterface.ofAddress(QueryInterface$get(segment), session); + } + static final FunctionDescriptor AddRef$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle AddRef$MH = RuntimeHelper.downcallHandle( + IOCFPlugInInterfaceStruct.AddRef$FUNC + ); + public interface AddRef { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(AddRef fi, MemorySession session) { + return RuntimeHelper.upcallStub(AddRef.class, fi, IOCFPlugInInterfaceStruct.AddRef$FUNC, session); + } + static AddRef ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOCFPlugInInterfaceStruct.AddRef$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle AddRef$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AddRef")); + public static VarHandle AddRef$VH() { + return IOCFPlugInInterfaceStruct.AddRef$VH; + } + public static MemoryAddress AddRef$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.AddRef$VH.get(seg); + } + public static void AddRef$set( MemorySegment seg, MemoryAddress x) { + IOCFPlugInInterfaceStruct.AddRef$VH.set(seg, x); + } + public static MemoryAddress AddRef$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.AddRef$VH.get(seg.asSlice(index*sizeof())); + } + public static void AddRef$set(MemorySegment seg, long index, MemoryAddress x) { + IOCFPlugInInterfaceStruct.AddRef$VH.set(seg.asSlice(index*sizeof()), x); + } + public static AddRef AddRef (MemorySegment segment, MemorySession session) { + return AddRef.ofAddress(AddRef$get(segment), session); + } + static final FunctionDescriptor Release$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle Release$MH = RuntimeHelper.downcallHandle( + IOCFPlugInInterfaceStruct.Release$FUNC + ); + public interface Release { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(Release fi, MemorySession session) { + return RuntimeHelper.upcallStub(Release.class, fi, IOCFPlugInInterfaceStruct.Release$FUNC, session); + } + static Release ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOCFPlugInInterfaceStruct.Release$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle Release$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Release")); + public static VarHandle Release$VH() { + return IOCFPlugInInterfaceStruct.Release$VH; + } + public static MemoryAddress Release$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.Release$VH.get(seg); + } + public static void Release$set( MemorySegment seg, MemoryAddress x) { + IOCFPlugInInterfaceStruct.Release$VH.set(seg, x); + } + public static MemoryAddress Release$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.Release$VH.get(seg.asSlice(index*sizeof())); + } + public static void Release$set(MemorySegment seg, long index, MemoryAddress x) { + IOCFPlugInInterfaceStruct.Release$VH.set(seg.asSlice(index*sizeof()), x); + } + public static Release Release (MemorySegment segment, MemorySession session) { + return Release.ofAddress(Release$get(segment), session); + } + static final VarHandle version$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("version")); + public static VarHandle version$VH() { + return IOCFPlugInInterfaceStruct.version$VH; + } + public static short version$get(MemorySegment seg) { + return (short)IOCFPlugInInterfaceStruct.version$VH.get(seg); + } + public static void version$set( MemorySegment seg, short x) { + IOCFPlugInInterfaceStruct.version$VH.set(seg, x); + } + public static short version$get(MemorySegment seg, long index) { + return (short)IOCFPlugInInterfaceStruct.version$VH.get(seg.asSlice(index*sizeof())); + } + public static void version$set(MemorySegment seg, long index, short x) { + IOCFPlugInInterfaceStruct.version$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle revision$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("revision")); + public static VarHandle revision$VH() { + return IOCFPlugInInterfaceStruct.revision$VH; + } + public static short revision$get(MemorySegment seg) { + return (short)IOCFPlugInInterfaceStruct.revision$VH.get(seg); + } + public static void revision$set( MemorySegment seg, short x) { + IOCFPlugInInterfaceStruct.revision$VH.set(seg, x); + } + public static short revision$get(MemorySegment seg, long index) { + return (short)IOCFPlugInInterfaceStruct.revision$VH.get(seg.asSlice(index*sizeof())); + } + public static void revision$set(MemorySegment seg, long index, short x) { + IOCFPlugInInterfaceStruct.revision$VH.set(seg.asSlice(index*sizeof()), x); + } + static final FunctionDescriptor Probe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle Probe$MH = RuntimeHelper.downcallHandle( + IOCFPlugInInterfaceStruct.Probe$FUNC + ); + public interface Probe { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, int _x2, java.lang.foreign.MemoryAddress _x3); + static MemorySegment allocate(Probe fi, MemorySession session) { + return RuntimeHelper.upcallStub(Probe.class, fi, IOCFPlugInInterfaceStruct.Probe$FUNC, session); + } + static Probe ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, int __x2, java.lang.foreign.MemoryAddress __x3) -> { + try { + return (int)IOCFPlugInInterfaceStruct.Probe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, __x2, (java.lang.foreign.Addressable)__x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle Probe$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Probe")); + public static VarHandle Probe$VH() { + return IOCFPlugInInterfaceStruct.Probe$VH; + } + public static MemoryAddress Probe$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.Probe$VH.get(seg); + } + public static void Probe$set( MemorySegment seg, MemoryAddress x) { + IOCFPlugInInterfaceStruct.Probe$VH.set(seg, x); + } + public static MemoryAddress Probe$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.Probe$VH.get(seg.asSlice(index*sizeof())); + } + public static void Probe$set(MemorySegment seg, long index, MemoryAddress x) { + IOCFPlugInInterfaceStruct.Probe$VH.set(seg.asSlice(index*sizeof()), x); + } + public static Probe Probe (MemorySegment segment, MemorySession session) { + return Probe.ofAddress(Probe$get(segment), session); + } + static final FunctionDescriptor Start$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle Start$MH = RuntimeHelper.downcallHandle( + IOCFPlugInInterfaceStruct.Start$FUNC + ); + public interface Start { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, int _x2); + static MemorySegment allocate(Start fi, MemorySession session) { + return RuntimeHelper.upcallStub(Start.class, fi, IOCFPlugInInterfaceStruct.Start$FUNC, session); + } + static Start ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, int __x2) -> { + try { + return (int)IOCFPlugInInterfaceStruct.Start$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, __x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle Start$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Start")); + public static VarHandle Start$VH() { + return IOCFPlugInInterfaceStruct.Start$VH; + } + public static MemoryAddress Start$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.Start$VH.get(seg); + } + public static void Start$set( MemorySegment seg, MemoryAddress x) { + IOCFPlugInInterfaceStruct.Start$VH.set(seg, x); + } + public static MemoryAddress Start$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.Start$VH.get(seg.asSlice(index*sizeof())); + } + public static void Start$set(MemorySegment seg, long index, MemoryAddress x) { + IOCFPlugInInterfaceStruct.Start$VH.set(seg.asSlice(index*sizeof()), x); + } + public static Start Start (MemorySegment segment, MemorySession session) { + return Start.ofAddress(Start$get(segment), session); + } + static final FunctionDescriptor Stop$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle Stop$MH = RuntimeHelper.downcallHandle( + IOCFPlugInInterfaceStruct.Stop$FUNC + ); + public interface Stop { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(Stop fi, MemorySession session) { + return RuntimeHelper.upcallStub(Stop.class, fi, IOCFPlugInInterfaceStruct.Stop$FUNC, session); + } + static Stop ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOCFPlugInInterfaceStruct.Stop$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle Stop$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Stop")); + public static VarHandle Stop$VH() { + return IOCFPlugInInterfaceStruct.Stop$VH; + } + public static MemoryAddress Stop$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.Stop$VH.get(seg); + } + public static void Stop$set( MemorySegment seg, MemoryAddress x) { + IOCFPlugInInterfaceStruct.Stop$VH.set(seg, x); + } + public static MemoryAddress Stop$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.Stop$VH.get(seg.asSlice(index*sizeof())); + } + public static void Stop$set(MemorySegment seg, long index, MemoryAddress x) { + IOCFPlugInInterfaceStruct.Stop$VH.set(seg.asSlice(index*sizeof()), x); + } + public static Stop Stop (MemorySegment segment, MemorySession session) { + return Stop.ofAddress(Stop$get(segment), session); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java new file mode 100644 index 00000000..59ebcf8b --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java @@ -0,0 +1,167 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.Addressable; +import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.*; +public class IOKit { + + /* package-private */ IOKit() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static int kIOUSBFindInterfaceDontCare() { + return (int)65535L; + } + public static MemoryLayout kCFRunLoopDefaultMode$LAYOUT() { + return constants$0.kCFRunLoopDefaultMode$LAYOUT; + } + public static VarHandle kCFRunLoopDefaultMode$VH() { + return constants$0.kCFRunLoopDefaultMode$VH; + } + public static MemorySegment kCFRunLoopDefaultMode$SEGMENT() { + return RuntimeHelper.requireNonNull(constants$0.kCFRunLoopDefaultMode$SEGMENT,"kCFRunLoopDefaultMode"); + } + public static MemoryAddress kCFRunLoopDefaultMode$get() { + return (java.lang.foreign.MemoryAddress) constants$0.kCFRunLoopDefaultMode$VH.get(RuntimeHelper.requireNonNull(constants$0.kCFRunLoopDefaultMode$SEGMENT, "kCFRunLoopDefaultMode")); + } + public static void kCFRunLoopDefaultMode$set( MemoryAddress x) { + constants$0.kCFRunLoopDefaultMode$VH.set(RuntimeHelper.requireNonNull(constants$0.kCFRunLoopDefaultMode$SEGMENT, "kCFRunLoopDefaultMode"), x); + } + public static MemoryLayout kIOMasterPortDefault$LAYOUT() { + return constants$0.kIOMasterPortDefault$LAYOUT; + } + public static VarHandle kIOMasterPortDefault$VH() { + return constants$0.kIOMasterPortDefault$VH; + } + public static MemorySegment kIOMasterPortDefault$SEGMENT() { + return RuntimeHelper.requireNonNull(constants$0.kIOMasterPortDefault$SEGMENT,"kIOMasterPortDefault"); + } + public static int kIOMasterPortDefault$get() { + return (int) constants$0.kIOMasterPortDefault$VH.get(RuntimeHelper.requireNonNull(constants$0.kIOMasterPortDefault$SEGMENT, "kIOMasterPortDefault")); + } + public static void kIOMasterPortDefault$set( int x) { + constants$0.kIOMasterPortDefault$VH.set(RuntimeHelper.requireNonNull(constants$0.kIOMasterPortDefault$SEGMENT, "kIOMasterPortDefault"), x); + } + public static MethodHandle IONotificationPortCreate$MH() { + return RuntimeHelper.requireNonNull(constants$0.IONotificationPortCreate$MH,"IONotificationPortCreate"); + } + public static MemoryAddress IONotificationPortCreate ( int mainPort) { + var mh$ = IONotificationPortCreate$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(mainPort); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle IONotificationPortGetRunLoopSource$MH() { + return RuntimeHelper.requireNonNull(constants$0.IONotificationPortGetRunLoopSource$MH,"IONotificationPortGetRunLoopSource"); + } + public static MemoryAddress IONotificationPortGetRunLoopSource ( Addressable notify) { + var mh$ = IONotificationPortGetRunLoopSource$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(notify); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle IOObjectRelease$MH() { + return RuntimeHelper.requireNonNull(constants$0.IOObjectRelease$MH,"IOObjectRelease"); + } + public static int IOObjectRelease ( int object) { + var mh$ = IOObjectRelease$MH(); + try { + return (int)mh$.invokeExact(object); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle IOIteratorNext$MH() { + return RuntimeHelper.requireNonNull(constants$0.IOIteratorNext$MH,"IOIteratorNext"); + } + public static int IOIteratorNext ( int iterator) { + var mh$ = IOIteratorNext$MH(); + try { + return (int)mh$.invokeExact(iterator); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle IOServiceAddMatchingNotification$MH() { + return RuntimeHelper.requireNonNull(constants$1.IOServiceAddMatchingNotification$MH,"IOServiceAddMatchingNotification"); + } + public static int IOServiceAddMatchingNotification ( Addressable notifyPort, Addressable notificationType, Addressable matching, Addressable callback, Addressable refCon, Addressable notification) { + var mh$ = IOServiceAddMatchingNotification$MH(); + try { + return (int)mh$.invokeExact(notifyPort, notificationType, matching, callback, refCon, notification); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle IORegistryEntryGetRegistryEntryID$MH() { + return RuntimeHelper.requireNonNull(constants$1.IORegistryEntryGetRegistryEntryID$MH,"IORegistryEntryGetRegistryEntryID"); + } + public static int IORegistryEntryGetRegistryEntryID ( int entry, Addressable entryID) { + var mh$ = IORegistryEntryGetRegistryEntryID$MH(); + try { + return (int)mh$.invokeExact(entry, entryID); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle IORegistryEntryCreateCFProperty$MH() { + return RuntimeHelper.requireNonNull(constants$1.IORegistryEntryCreateCFProperty$MH,"IORegistryEntryCreateCFProperty"); + } + public static MemoryAddress IORegistryEntryCreateCFProperty ( int entry, Addressable key, Addressable allocator, int options) { + var mh$ = IORegistryEntryCreateCFProperty$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(entry, key, allocator, options); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle IOServiceMatching$MH() { + return RuntimeHelper.requireNonNull(constants$1.IOServiceMatching$MH,"IOServiceMatching"); + } + public static MemoryAddress IOServiceMatching ( Addressable name) { + var mh$ = IOServiceMatching$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(name); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle IOCreatePlugInInterfaceForService$MH() { + return RuntimeHelper.requireNonNull(constants$1.IOCreatePlugInInterfaceForService$MH,"IOCreatePlugInInterfaceForService"); + } + public static int IOCreatePlugInInterfaceForService ( int service, Addressable pluginType, Addressable interfaceType, Addressable theInterface, Addressable theScore) { + var mh$ = IOCreatePlugInInterfaceForService$MH(); + try { + return (int)mh$.invokeExact(service, pluginType, interfaceType, theInterface, theScore); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MemorySegment kIOFirstMatchNotification() { + return constants$1.kIOFirstMatchNotification$SEGMENT; + } + public static MemorySegment kIOTerminatedNotification() { + return constants$2.kIOTerminatedNotification$SEGMENT; + } + public static MemorySegment kIOUSBDeviceClassName() { + return constants$2.kIOUSBDeviceClassName$SEGMENT; + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java new file mode 100644 index 00000000..e376cdda --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java @@ -0,0 +1,142 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class IOUSBDevRequest { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("bmRequestType"), + Constants$root.C_CHAR$LAYOUT.withName("bRequest"), + Constants$root.C_SHORT$LAYOUT.withName("wValue"), + Constants$root.C_SHORT$LAYOUT.withName("wIndex"), + Constants$root.C_SHORT$LAYOUT.withName("wLength"), + Constants$root.C_POINTER$LAYOUT.withName("pData"), + Constants$root.C_INT$LAYOUT.withName("wLenDone"), + MemoryLayout.paddingLayout(32) + ); + public static MemoryLayout $LAYOUT() { + return IOUSBDevRequest.$struct$LAYOUT; + } + static final VarHandle bmRequestType$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("bmRequestType")); + public static VarHandle bmRequestType$VH() { + return IOUSBDevRequest.bmRequestType$VH; + } + public static byte bmRequestType$get(MemorySegment seg) { + return (byte)IOUSBDevRequest.bmRequestType$VH.get(seg); + } + public static void bmRequestType$set( MemorySegment seg, byte x) { + IOUSBDevRequest.bmRequestType$VH.set(seg, x); + } + public static byte bmRequestType$get(MemorySegment seg, long index) { + return (byte)IOUSBDevRequest.bmRequestType$VH.get(seg.asSlice(index*sizeof())); + } + public static void bmRequestType$set(MemorySegment seg, long index, byte x) { + IOUSBDevRequest.bmRequestType$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle bRequest$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("bRequest")); + public static VarHandle bRequest$VH() { + return IOUSBDevRequest.bRequest$VH; + } + public static byte bRequest$get(MemorySegment seg) { + return (byte)IOUSBDevRequest.bRequest$VH.get(seg); + } + public static void bRequest$set( MemorySegment seg, byte x) { + IOUSBDevRequest.bRequest$VH.set(seg, x); + } + public static byte bRequest$get(MemorySegment seg, long index) { + return (byte)IOUSBDevRequest.bRequest$VH.get(seg.asSlice(index*sizeof())); + } + public static void bRequest$set(MemorySegment seg, long index, byte x) { + IOUSBDevRequest.bRequest$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle wValue$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("wValue")); + public static VarHandle wValue$VH() { + return IOUSBDevRequest.wValue$VH; + } + public static short wValue$get(MemorySegment seg) { + return (short)IOUSBDevRequest.wValue$VH.get(seg); + } + public static void wValue$set( MemorySegment seg, short x) { + IOUSBDevRequest.wValue$VH.set(seg, x); + } + public static short wValue$get(MemorySegment seg, long index) { + return (short)IOUSBDevRequest.wValue$VH.get(seg.asSlice(index*sizeof())); + } + public static void wValue$set(MemorySegment seg, long index, short x) { + IOUSBDevRequest.wValue$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle wIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("wIndex")); + public static VarHandle wIndex$VH() { + return IOUSBDevRequest.wIndex$VH; + } + public static short wIndex$get(MemorySegment seg) { + return (short)IOUSBDevRequest.wIndex$VH.get(seg); + } + public static void wIndex$set( MemorySegment seg, short x) { + IOUSBDevRequest.wIndex$VH.set(seg, x); + } + public static short wIndex$get(MemorySegment seg, long index) { + return (short)IOUSBDevRequest.wIndex$VH.get(seg.asSlice(index*sizeof())); + } + public static void wIndex$set(MemorySegment seg, long index, short x) { + IOUSBDevRequest.wIndex$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle wLength$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("wLength")); + public static VarHandle wLength$VH() { + return IOUSBDevRequest.wLength$VH; + } + public static short wLength$get(MemorySegment seg) { + return (short)IOUSBDevRequest.wLength$VH.get(seg); + } + public static void wLength$set( MemorySegment seg, short x) { + IOUSBDevRequest.wLength$VH.set(seg, x); + } + public static short wLength$get(MemorySegment seg, long index) { + return (short)IOUSBDevRequest.wLength$VH.get(seg.asSlice(index*sizeof())); + } + public static void wLength$set(MemorySegment seg, long index, short x) { + IOUSBDevRequest.wLength$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle pData$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("pData")); + public static VarHandle pData$VH() { + return IOUSBDevRequest.pData$VH; + } + public static MemoryAddress pData$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDevRequest.pData$VH.get(seg); + } + public static void pData$set( MemorySegment seg, MemoryAddress x) { + IOUSBDevRequest.pData$VH.set(seg, x); + } + public static MemoryAddress pData$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDevRequest.pData$VH.get(seg.asSlice(index*sizeof())); + } + public static void pData$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDevRequest.pData$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle wLenDone$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("wLenDone")); + public static VarHandle wLenDone$VH() { + return IOUSBDevRequest.wLenDone$VH; + } + public static int wLenDone$get(MemorySegment seg) { + return (int)IOUSBDevRequest.wLenDone$VH.get(seg); + } + public static void wLenDone$set( MemorySegment seg, int x) { + IOUSBDevRequest.wLenDone$VH.set(seg, x); + } + public static int wLenDone$get(MemorySegment seg, long index) { + return (int)IOUSBDevRequest.wLenDone$VH.get(seg.asSlice(index*sizeof())); + } + public static void wLenDone$set(MemorySegment seg, long index, int x) { + IOUSBDevRequest.wLenDone$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface.java new file mode 100644 index 00000000..955982bc --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface.java @@ -0,0 +1,9 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +public class IOUSBDeviceInterface extends IOUSBDeviceStruct942 { + +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct942.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct942.java new file mode 100644 index 00000000..064a6458 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct942.java @@ -0,0 +1,2317 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +public class IOUSBDeviceStruct942 { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_POINTER$LAYOUT.withName("_reserved"), + Constants$root.C_POINTER$LAYOUT.withName("QueryInterface"), + Constants$root.C_POINTER$LAYOUT.withName("AddRef"), + Constants$root.C_POINTER$LAYOUT.withName("Release"), + Constants$root.C_POINTER$LAYOUT.withName("CreateDeviceAsyncEventSource"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceAsyncEventSource"), + Constants$root.C_POINTER$LAYOUT.withName("CreateDeviceAsyncPort"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceAsyncPort"), + Constants$root.C_POINTER$LAYOUT.withName("USBDeviceOpen"), + Constants$root.C_POINTER$LAYOUT.withName("USBDeviceClose"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceClass"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceSubClass"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceProtocol"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceVendor"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceProduct"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceReleaseNumber"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceAddress"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceBusPowerAvailable"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceSpeed"), + Constants$root.C_POINTER$LAYOUT.withName("GetNumberOfConfigurations"), + Constants$root.C_POINTER$LAYOUT.withName("GetLocationID"), + Constants$root.C_POINTER$LAYOUT.withName("GetConfigurationDescriptorPtr"), + Constants$root.C_POINTER$LAYOUT.withName("GetConfiguration"), + Constants$root.C_POINTER$LAYOUT.withName("SetConfiguration"), + Constants$root.C_POINTER$LAYOUT.withName("GetBusFrameNumber"), + Constants$root.C_POINTER$LAYOUT.withName("ResetDevice"), + Constants$root.C_POINTER$LAYOUT.withName("DeviceRequest"), + Constants$root.C_POINTER$LAYOUT.withName("DeviceRequestAsync"), + Constants$root.C_POINTER$LAYOUT.withName("CreateInterfaceIterator"), + Constants$root.C_POINTER$LAYOUT.withName("USBDeviceOpenSeize"), + Constants$root.C_POINTER$LAYOUT.withName("DeviceRequestTO"), + Constants$root.C_POINTER$LAYOUT.withName("DeviceRequestAsyncTO"), + Constants$root.C_POINTER$LAYOUT.withName("USBDeviceSuspend"), + Constants$root.C_POINTER$LAYOUT.withName("USBDeviceAbortPipeZero"), + Constants$root.C_POINTER$LAYOUT.withName("USBGetManufacturerStringIndex"), + Constants$root.C_POINTER$LAYOUT.withName("USBGetProductStringIndex"), + Constants$root.C_POINTER$LAYOUT.withName("USBGetSerialNumberStringIndex"), + Constants$root.C_POINTER$LAYOUT.withName("USBDeviceReEnumerate"), + Constants$root.C_POINTER$LAYOUT.withName("GetBusMicroFrameNumber"), + Constants$root.C_POINTER$LAYOUT.withName("GetIOUSBLibVersion"), + Constants$root.C_POINTER$LAYOUT.withName("GetBusFrameNumberWithTime"), + Constants$root.C_POINTER$LAYOUT.withName("GetUSBDeviceInformation"), + Constants$root.C_POINTER$LAYOUT.withName("RequestExtraPower"), + Constants$root.C_POINTER$LAYOUT.withName("ReturnExtraPower"), + Constants$root.C_POINTER$LAYOUT.withName("GetExtraPowerAllocated"), + Constants$root.C_POINTER$LAYOUT.withName("GetBandwidthAvailableForDevice"), + Constants$root.C_POINTER$LAYOUT.withName("SetConfigurationV2"), + Constants$root.C_POINTER$LAYOUT.withName("RegisterForNotification"), + Constants$root.C_POINTER$LAYOUT.withName("UnregisterNotification"), + Constants$root.C_POINTER$LAYOUT.withName("AcknowledgeNotification"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceAsyncNotificationPort") + ).withName("IOUSBDeviceStruct942"); + public static MemoryLayout $LAYOUT() { + return IOUSBDeviceStruct942.$struct$LAYOUT; + } + static final VarHandle _reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("_reserved")); + public static VarHandle _reserved$VH() { + return IOUSBDeviceStruct942._reserved$VH; + } + public static MemoryAddress _reserved$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942._reserved$VH.get(seg); + } + public static void _reserved$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942._reserved$VH.set(seg, x); + } + public static MemoryAddress _reserved$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942._reserved$VH.get(seg.asSlice(index*sizeof())); + } + public static void _reserved$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942._reserved$VH.set(seg.asSlice(index*sizeof()), x); + } + static final FunctionDescriptor QueryInterface$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("byte0"), + Constants$root.C_CHAR$LAYOUT.withName("byte1"), + Constants$root.C_CHAR$LAYOUT.withName("byte2"), + Constants$root.C_CHAR$LAYOUT.withName("byte3"), + Constants$root.C_CHAR$LAYOUT.withName("byte4"), + Constants$root.C_CHAR$LAYOUT.withName("byte5"), + Constants$root.C_CHAR$LAYOUT.withName("byte6"), + Constants$root.C_CHAR$LAYOUT.withName("byte7"), + Constants$root.C_CHAR$LAYOUT.withName("byte8"), + Constants$root.C_CHAR$LAYOUT.withName("byte9"), + Constants$root.C_CHAR$LAYOUT.withName("byte10"), + Constants$root.C_CHAR$LAYOUT.withName("byte11"), + Constants$root.C_CHAR$LAYOUT.withName("byte12"), + Constants$root.C_CHAR$LAYOUT.withName("byte13"), + Constants$root.C_CHAR$LAYOUT.withName("byte14"), + Constants$root.C_CHAR$LAYOUT.withName("byte15") + ), + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle QueryInterface$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.QueryInterface$FUNC + ); + public interface QueryInterface { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(QueryInterface fi, MemorySession session) { + return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOUSBDeviceStruct942.QueryInterface$FUNC, session); + } + static QueryInterface ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBDeviceStruct942.QueryInterface$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle QueryInterface$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("QueryInterface")); + public static VarHandle QueryInterface$VH() { + return IOUSBDeviceStruct942.QueryInterface$VH; + } + public static MemoryAddress QueryInterface$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.QueryInterface$VH.get(seg); + } + public static void QueryInterface$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.QueryInterface$VH.set(seg, x); + } + public static MemoryAddress QueryInterface$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.QueryInterface$VH.get(seg.asSlice(index*sizeof())); + } + public static void QueryInterface$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.QueryInterface$VH.set(seg.asSlice(index*sizeof()), x); + } + public static QueryInterface QueryInterface (MemorySegment segment, MemorySession session) { + return QueryInterface.ofAddress(QueryInterface$get(segment), session); + } + static final FunctionDescriptor AddRef$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle AddRef$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.AddRef$FUNC + ); + public interface AddRef { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(AddRef fi, MemorySession session) { + return RuntimeHelper.upcallStub(AddRef.class, fi, IOUSBDeviceStruct942.AddRef$FUNC, session); + } + static AddRef ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBDeviceStruct942.AddRef$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle AddRef$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AddRef")); + public static VarHandle AddRef$VH() { + return IOUSBDeviceStruct942.AddRef$VH; + } + public static MemoryAddress AddRef$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.AddRef$VH.get(seg); + } + public static void AddRef$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.AddRef$VH.set(seg, x); + } + public static MemoryAddress AddRef$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.AddRef$VH.get(seg.asSlice(index*sizeof())); + } + public static void AddRef$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.AddRef$VH.set(seg.asSlice(index*sizeof()), x); + } + public static AddRef AddRef (MemorySegment segment, MemorySession session) { + return AddRef.ofAddress(AddRef$get(segment), session); + } + static final FunctionDescriptor Release$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle Release$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.Release$FUNC + ); + public interface Release { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(Release fi, MemorySession session) { + return RuntimeHelper.upcallStub(Release.class, fi, IOUSBDeviceStruct942.Release$FUNC, session); + } + static Release ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBDeviceStruct942.Release$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle Release$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Release")); + public static VarHandle Release$VH() { + return IOUSBDeviceStruct942.Release$VH; + } + public static MemoryAddress Release$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.Release$VH.get(seg); + } + public static void Release$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.Release$VH.set(seg, x); + } + public static MemoryAddress Release$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.Release$VH.get(seg.asSlice(index*sizeof())); + } + public static void Release$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.Release$VH.set(seg.asSlice(index*sizeof()), x); + } + public static Release Release (MemorySegment segment, MemorySession session) { + return Release.ofAddress(Release$get(segment), session); + } + static final FunctionDescriptor CreateDeviceAsyncEventSource$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CreateDeviceAsyncEventSource$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.CreateDeviceAsyncEventSource$FUNC + ); + public interface CreateDeviceAsyncEventSource { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(CreateDeviceAsyncEventSource fi, MemorySession session) { + return RuntimeHelper.upcallStub(CreateDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct942.CreateDeviceAsyncEventSource$FUNC, session); + } + static CreateDeviceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.CreateDeviceAsyncEventSource$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle CreateDeviceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateDeviceAsyncEventSource")); + public static VarHandle CreateDeviceAsyncEventSource$VH() { + return IOUSBDeviceStruct942.CreateDeviceAsyncEventSource$VH; + } + public static MemoryAddress CreateDeviceAsyncEventSource$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.CreateDeviceAsyncEventSource$VH.get(seg); + } + public static void CreateDeviceAsyncEventSource$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.CreateDeviceAsyncEventSource$VH.set(seg, x); + } + public static MemoryAddress CreateDeviceAsyncEventSource$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.CreateDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + } + public static void CreateDeviceAsyncEventSource$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.CreateDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); + } + public static CreateDeviceAsyncEventSource CreateDeviceAsyncEventSource (MemorySegment segment, MemorySession session) { + return CreateDeviceAsyncEventSource.ofAddress(CreateDeviceAsyncEventSource$get(segment), session); + } + static final FunctionDescriptor GetDeviceAsyncEventSource$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceAsyncEventSource$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetDeviceAsyncEventSource$FUNC + ); + public interface GetDeviceAsyncEventSource { + + java.lang.foreign.Addressable apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(GetDeviceAsyncEventSource fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct942.GetDeviceAsyncEventSource$FUNC, session); + } + static GetDeviceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (java.lang.foreign.Addressable)(java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAsyncEventSource$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncEventSource")); + public static VarHandle GetDeviceAsyncEventSource$VH() { + return IOUSBDeviceStruct942.GetDeviceAsyncEventSource$VH; + } + public static MemoryAddress GetDeviceAsyncEventSource$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAsyncEventSource$VH.get(seg); + } + public static void GetDeviceAsyncEventSource$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceAsyncEventSource$VH.set(seg, x); + } + public static MemoryAddress GetDeviceAsyncEventSource$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceAsyncEventSource$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceAsyncEventSource GetDeviceAsyncEventSource (MemorySegment segment, MemorySession session) { + return GetDeviceAsyncEventSource.ofAddress(GetDeviceAsyncEventSource$get(segment), session); + } + static final FunctionDescriptor CreateDeviceAsyncPort$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CreateDeviceAsyncPort$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.CreateDeviceAsyncPort$FUNC + ); + public interface CreateDeviceAsyncPort { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(CreateDeviceAsyncPort fi, MemorySession session) { + return RuntimeHelper.upcallStub(CreateDeviceAsyncPort.class, fi, IOUSBDeviceStruct942.CreateDeviceAsyncPort$FUNC, session); + } + static CreateDeviceAsyncPort ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.CreateDeviceAsyncPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle CreateDeviceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateDeviceAsyncPort")); + public static VarHandle CreateDeviceAsyncPort$VH() { + return IOUSBDeviceStruct942.CreateDeviceAsyncPort$VH; + } + public static MemoryAddress CreateDeviceAsyncPort$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.CreateDeviceAsyncPort$VH.get(seg); + } + public static void CreateDeviceAsyncPort$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.CreateDeviceAsyncPort$VH.set(seg, x); + } + public static MemoryAddress CreateDeviceAsyncPort$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.CreateDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + } + public static void CreateDeviceAsyncPort$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.CreateDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); + } + public static CreateDeviceAsyncPort CreateDeviceAsyncPort (MemorySegment segment, MemorySession session) { + return CreateDeviceAsyncPort.ofAddress(CreateDeviceAsyncPort$get(segment), session); + } + static final FunctionDescriptor GetDeviceAsyncPort$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceAsyncPort$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetDeviceAsyncPort$FUNC + ); + public interface GetDeviceAsyncPort { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(GetDeviceAsyncPort fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceAsyncPort.class, fi, IOUSBDeviceStruct942.GetDeviceAsyncPort$FUNC, session); + } + static GetDeviceAsyncPort ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBDeviceStruct942.GetDeviceAsyncPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncPort")); + public static VarHandle GetDeviceAsyncPort$VH() { + return IOUSBDeviceStruct942.GetDeviceAsyncPort$VH; + } + public static MemoryAddress GetDeviceAsyncPort$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAsyncPort$VH.get(seg); + } + public static void GetDeviceAsyncPort$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceAsyncPort$VH.set(seg, x); + } + public static MemoryAddress GetDeviceAsyncPort$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceAsyncPort$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceAsyncPort GetDeviceAsyncPort (MemorySegment segment, MemorySession session) { + return GetDeviceAsyncPort.ofAddress(GetDeviceAsyncPort$get(segment), session); + } + static final FunctionDescriptor USBDeviceOpen$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBDeviceOpen$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.USBDeviceOpen$FUNC + ); + public interface USBDeviceOpen { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(USBDeviceOpen fi, MemorySession session) { + return RuntimeHelper.upcallStub(USBDeviceOpen.class, fi, IOUSBDeviceStruct942.USBDeviceOpen$FUNC, session); + } + static USBDeviceOpen ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBDeviceStruct942.USBDeviceOpen$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBDeviceOpen$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceOpen")); + public static VarHandle USBDeviceOpen$VH() { + return IOUSBDeviceStruct942.USBDeviceOpen$VH; + } + public static MemoryAddress USBDeviceOpen$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceOpen$VH.get(seg); + } + public static void USBDeviceOpen$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.USBDeviceOpen$VH.set(seg, x); + } + public static MemoryAddress USBDeviceOpen$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceOpen$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBDeviceOpen$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.USBDeviceOpen$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBDeviceOpen USBDeviceOpen (MemorySegment segment, MemorySession session) { + return USBDeviceOpen.ofAddress(USBDeviceOpen$get(segment), session); + } + static final FunctionDescriptor USBDeviceClose$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBDeviceClose$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.USBDeviceClose$FUNC + ); + public interface USBDeviceClose { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(USBDeviceClose fi, MemorySession session) { + return RuntimeHelper.upcallStub(USBDeviceClose.class, fi, IOUSBDeviceStruct942.USBDeviceClose$FUNC, session); + } + static USBDeviceClose ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBDeviceStruct942.USBDeviceClose$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBDeviceClose$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceClose")); + public static VarHandle USBDeviceClose$VH() { + return IOUSBDeviceStruct942.USBDeviceClose$VH; + } + public static MemoryAddress USBDeviceClose$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceClose$VH.get(seg); + } + public static void USBDeviceClose$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.USBDeviceClose$VH.set(seg, x); + } + public static MemoryAddress USBDeviceClose$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceClose$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBDeviceClose$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.USBDeviceClose$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBDeviceClose USBDeviceClose (MemorySegment segment, MemorySession session) { + return USBDeviceClose.ofAddress(USBDeviceClose$get(segment), session); + } + static final FunctionDescriptor GetDeviceClass$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceClass$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetDeviceClass$FUNC + ); + public interface GetDeviceClass { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceClass fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceClass.class, fi, IOUSBDeviceStruct942.GetDeviceClass$FUNC, session); + } + static GetDeviceClass ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.GetDeviceClass$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceClass")); + public static VarHandle GetDeviceClass$VH() { + return IOUSBDeviceStruct942.GetDeviceClass$VH; + } + public static MemoryAddress GetDeviceClass$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceClass$VH.get(seg); + } + public static void GetDeviceClass$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceClass$VH.set(seg, x); + } + public static MemoryAddress GetDeviceClass$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceClass$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceClass$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceClass$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceClass GetDeviceClass (MemorySegment segment, MemorySession session) { + return GetDeviceClass.ofAddress(GetDeviceClass$get(segment), session); + } + static final FunctionDescriptor GetDeviceSubClass$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceSubClass$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetDeviceSubClass$FUNC + ); + public interface GetDeviceSubClass { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceSubClass fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceSubClass.class, fi, IOUSBDeviceStruct942.GetDeviceSubClass$FUNC, session); + } + static GetDeviceSubClass ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.GetDeviceSubClass$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceSubClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceSubClass")); + public static VarHandle GetDeviceSubClass$VH() { + return IOUSBDeviceStruct942.GetDeviceSubClass$VH; + } + public static MemoryAddress GetDeviceSubClass$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceSubClass$VH.get(seg); + } + public static void GetDeviceSubClass$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceSubClass$VH.set(seg, x); + } + public static MemoryAddress GetDeviceSubClass$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceSubClass$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceSubClass$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceSubClass$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceSubClass GetDeviceSubClass (MemorySegment segment, MemorySession session) { + return GetDeviceSubClass.ofAddress(GetDeviceSubClass$get(segment), session); + } + static final FunctionDescriptor GetDeviceProtocol$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceProtocol$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetDeviceProtocol$FUNC + ); + public interface GetDeviceProtocol { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceProtocol fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceProtocol.class, fi, IOUSBDeviceStruct942.GetDeviceProtocol$FUNC, session); + } + static GetDeviceProtocol ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.GetDeviceProtocol$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceProtocol$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProtocol")); + public static VarHandle GetDeviceProtocol$VH() { + return IOUSBDeviceStruct942.GetDeviceProtocol$VH; + } + public static MemoryAddress GetDeviceProtocol$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceProtocol$VH.get(seg); + } + public static void GetDeviceProtocol$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceProtocol$VH.set(seg, x); + } + public static MemoryAddress GetDeviceProtocol$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceProtocol$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceProtocol$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceProtocol$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceProtocol GetDeviceProtocol (MemorySegment segment, MemorySession session) { + return GetDeviceProtocol.ofAddress(GetDeviceProtocol$get(segment), session); + } + static final FunctionDescriptor GetDeviceVendor$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceVendor$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetDeviceVendor$FUNC + ); + public interface GetDeviceVendor { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceVendor fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceVendor.class, fi, IOUSBDeviceStruct942.GetDeviceVendor$FUNC, session); + } + static GetDeviceVendor ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.GetDeviceVendor$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceVendor$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceVendor")); + public static VarHandle GetDeviceVendor$VH() { + return IOUSBDeviceStruct942.GetDeviceVendor$VH; + } + public static MemoryAddress GetDeviceVendor$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceVendor$VH.get(seg); + } + public static void GetDeviceVendor$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceVendor$VH.set(seg, x); + } + public static MemoryAddress GetDeviceVendor$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceVendor$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceVendor$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceVendor$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceVendor GetDeviceVendor (MemorySegment segment, MemorySession session) { + return GetDeviceVendor.ofAddress(GetDeviceVendor$get(segment), session); + } + static final FunctionDescriptor GetDeviceProduct$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceProduct$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetDeviceProduct$FUNC + ); + public interface GetDeviceProduct { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceProduct fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceProduct.class, fi, IOUSBDeviceStruct942.GetDeviceProduct$FUNC, session); + } + static GetDeviceProduct ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.GetDeviceProduct$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceProduct$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProduct")); + public static VarHandle GetDeviceProduct$VH() { + return IOUSBDeviceStruct942.GetDeviceProduct$VH; + } + public static MemoryAddress GetDeviceProduct$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceProduct$VH.get(seg); + } + public static void GetDeviceProduct$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceProduct$VH.set(seg, x); + } + public static MemoryAddress GetDeviceProduct$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceProduct$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceProduct$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceProduct$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceProduct GetDeviceProduct (MemorySegment segment, MemorySession session) { + return GetDeviceProduct.ofAddress(GetDeviceProduct$get(segment), session); + } + static final FunctionDescriptor GetDeviceReleaseNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceReleaseNumber$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetDeviceReleaseNumber$FUNC + ); + public interface GetDeviceReleaseNumber { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceReleaseNumber fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceReleaseNumber.class, fi, IOUSBDeviceStruct942.GetDeviceReleaseNumber$FUNC, session); + } + static GetDeviceReleaseNumber ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.GetDeviceReleaseNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceReleaseNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceReleaseNumber")); + public static VarHandle GetDeviceReleaseNumber$VH() { + return IOUSBDeviceStruct942.GetDeviceReleaseNumber$VH; + } + public static MemoryAddress GetDeviceReleaseNumber$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceReleaseNumber$VH.get(seg); + } + public static void GetDeviceReleaseNumber$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceReleaseNumber$VH.set(seg, x); + } + public static MemoryAddress GetDeviceReleaseNumber$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceReleaseNumber$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceReleaseNumber$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceReleaseNumber$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceReleaseNumber GetDeviceReleaseNumber (MemorySegment segment, MemorySession session) { + return GetDeviceReleaseNumber.ofAddress(GetDeviceReleaseNumber$get(segment), session); + } + static final FunctionDescriptor GetDeviceAddress$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceAddress$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetDeviceAddress$FUNC + ); + public interface GetDeviceAddress { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceAddress fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceAddress.class, fi, IOUSBDeviceStruct942.GetDeviceAddress$FUNC, session); + } + static GetDeviceAddress ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.GetDeviceAddress$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceAddress$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAddress")); + public static VarHandle GetDeviceAddress$VH() { + return IOUSBDeviceStruct942.GetDeviceAddress$VH; + } + public static MemoryAddress GetDeviceAddress$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAddress$VH.get(seg); + } + public static void GetDeviceAddress$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceAddress$VH.set(seg, x); + } + public static MemoryAddress GetDeviceAddress$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAddress$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceAddress$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceAddress$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceAddress GetDeviceAddress (MemorySegment segment, MemorySession session) { + return GetDeviceAddress.ofAddress(GetDeviceAddress$get(segment), session); + } + static final FunctionDescriptor GetDeviceBusPowerAvailable$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceBusPowerAvailable$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetDeviceBusPowerAvailable$FUNC + ); + public interface GetDeviceBusPowerAvailable { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceBusPowerAvailable fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceBusPowerAvailable.class, fi, IOUSBDeviceStruct942.GetDeviceBusPowerAvailable$FUNC, session); + } + static GetDeviceBusPowerAvailable ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.GetDeviceBusPowerAvailable$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceBusPowerAvailable$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceBusPowerAvailable")); + public static VarHandle GetDeviceBusPowerAvailable$VH() { + return IOUSBDeviceStruct942.GetDeviceBusPowerAvailable$VH; + } + public static MemoryAddress GetDeviceBusPowerAvailable$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceBusPowerAvailable$VH.get(seg); + } + public static void GetDeviceBusPowerAvailable$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceBusPowerAvailable$VH.set(seg, x); + } + public static MemoryAddress GetDeviceBusPowerAvailable$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceBusPowerAvailable$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceBusPowerAvailable$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceBusPowerAvailable$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceBusPowerAvailable GetDeviceBusPowerAvailable (MemorySegment segment, MemorySession session) { + return GetDeviceBusPowerAvailable.ofAddress(GetDeviceBusPowerAvailable$get(segment), session); + } + static final FunctionDescriptor GetDeviceSpeed$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceSpeed$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetDeviceSpeed$FUNC + ); + public interface GetDeviceSpeed { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceSpeed fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceSpeed.class, fi, IOUSBDeviceStruct942.GetDeviceSpeed$FUNC, session); + } + static GetDeviceSpeed ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.GetDeviceSpeed$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceSpeed$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceSpeed")); + public static VarHandle GetDeviceSpeed$VH() { + return IOUSBDeviceStruct942.GetDeviceSpeed$VH; + } + public static MemoryAddress GetDeviceSpeed$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceSpeed$VH.get(seg); + } + public static void GetDeviceSpeed$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceSpeed$VH.set(seg, x); + } + public static MemoryAddress GetDeviceSpeed$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceSpeed$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceSpeed$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceSpeed$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceSpeed GetDeviceSpeed (MemorySegment segment, MemorySession session) { + return GetDeviceSpeed.ofAddress(GetDeviceSpeed$get(segment), session); + } + static final FunctionDescriptor GetNumberOfConfigurations$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetNumberOfConfigurations$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetNumberOfConfigurations$FUNC + ); + public interface GetNumberOfConfigurations { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetNumberOfConfigurations fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetNumberOfConfigurations.class, fi, IOUSBDeviceStruct942.GetNumberOfConfigurations$FUNC, session); + } + static GetNumberOfConfigurations ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.GetNumberOfConfigurations$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetNumberOfConfigurations$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetNumberOfConfigurations")); + public static VarHandle GetNumberOfConfigurations$VH() { + return IOUSBDeviceStruct942.GetNumberOfConfigurations$VH; + } + public static MemoryAddress GetNumberOfConfigurations$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetNumberOfConfigurations$VH.get(seg); + } + public static void GetNumberOfConfigurations$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetNumberOfConfigurations$VH.set(seg, x); + } + public static MemoryAddress GetNumberOfConfigurations$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetNumberOfConfigurations$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetNumberOfConfigurations$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetNumberOfConfigurations$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetNumberOfConfigurations GetNumberOfConfigurations (MemorySegment segment, MemorySession session) { + return GetNumberOfConfigurations.ofAddress(GetNumberOfConfigurations$get(segment), session); + } + static final FunctionDescriptor GetLocationID$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetLocationID$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetLocationID$FUNC + ); + public interface GetLocationID { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetLocationID fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetLocationID.class, fi, IOUSBDeviceStruct942.GetLocationID$FUNC, session); + } + static GetLocationID ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.GetLocationID$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetLocationID$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetLocationID")); + public static VarHandle GetLocationID$VH() { + return IOUSBDeviceStruct942.GetLocationID$VH; + } + public static MemoryAddress GetLocationID$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetLocationID$VH.get(seg); + } + public static void GetLocationID$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetLocationID$VH.set(seg, x); + } + public static MemoryAddress GetLocationID$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetLocationID$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetLocationID$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetLocationID$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetLocationID GetLocationID (MemorySegment segment, MemorySession session) { + return GetLocationID.ofAddress(GetLocationID$get(segment), session); + } + static final FunctionDescriptor GetConfigurationDescriptorPtr$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetConfigurationDescriptorPtr$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetConfigurationDescriptorPtr$FUNC + ); + public interface GetConfigurationDescriptorPtr { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(GetConfigurationDescriptorPtr fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetConfigurationDescriptorPtr.class, fi, IOUSBDeviceStruct942.GetConfigurationDescriptorPtr$FUNC, session); + } + static GetConfigurationDescriptorPtr ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBDeviceStruct942.GetConfigurationDescriptorPtr$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetConfigurationDescriptorPtr$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetConfigurationDescriptorPtr")); + public static VarHandle GetConfigurationDescriptorPtr$VH() { + return IOUSBDeviceStruct942.GetConfigurationDescriptorPtr$VH; + } + public static MemoryAddress GetConfigurationDescriptorPtr$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetConfigurationDescriptorPtr$VH.get(seg); + } + public static void GetConfigurationDescriptorPtr$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetConfigurationDescriptorPtr$VH.set(seg, x); + } + public static MemoryAddress GetConfigurationDescriptorPtr$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetConfigurationDescriptorPtr$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetConfigurationDescriptorPtr$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetConfigurationDescriptorPtr$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetConfigurationDescriptorPtr GetConfigurationDescriptorPtr (MemorySegment segment, MemorySession session) { + return GetConfigurationDescriptorPtr.ofAddress(GetConfigurationDescriptorPtr$get(segment), session); + } + static final FunctionDescriptor GetConfiguration$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetConfiguration$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetConfiguration$FUNC + ); + public interface GetConfiguration { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetConfiguration fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetConfiguration.class, fi, IOUSBDeviceStruct942.GetConfiguration$FUNC, session); + } + static GetConfiguration ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.GetConfiguration$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetConfiguration$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetConfiguration")); + public static VarHandle GetConfiguration$VH() { + return IOUSBDeviceStruct942.GetConfiguration$VH; + } + public static MemoryAddress GetConfiguration$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetConfiguration$VH.get(seg); + } + public static void GetConfiguration$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetConfiguration$VH.set(seg, x); + } + public static MemoryAddress GetConfiguration$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetConfiguration$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetConfiguration$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetConfiguration GetConfiguration (MemorySegment segment, MemorySession session) { + return GetConfiguration.ofAddress(GetConfiguration$get(segment), session); + } + static final FunctionDescriptor SetConfiguration$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT + ); + static final MethodHandle SetConfiguration$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.SetConfiguration$FUNC + ); + public interface SetConfiguration { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); + static MemorySegment allocate(SetConfiguration fi, MemorySession session) { + return RuntimeHelper.upcallStub(SetConfiguration.class, fi, IOUSBDeviceStruct942.SetConfiguration$FUNC, session); + } + static SetConfiguration ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { + try { + return (int)IOUSBDeviceStruct942.SetConfiguration$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle SetConfiguration$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetConfiguration")); + public static VarHandle SetConfiguration$VH() { + return IOUSBDeviceStruct942.SetConfiguration$VH; + } + public static MemoryAddress SetConfiguration$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.SetConfiguration$VH.get(seg); + } + public static void SetConfiguration$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.SetConfiguration$VH.set(seg, x); + } + public static MemoryAddress SetConfiguration$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.SetConfiguration$VH.get(seg.asSlice(index*sizeof())); + } + public static void SetConfiguration$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.SetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); + } + public static SetConfiguration SetConfiguration (MemorySegment segment, MemorySession session) { + return SetConfiguration.ofAddress(SetConfiguration$get(segment), session); + } + static final FunctionDescriptor GetBusFrameNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetBusFrameNumber$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetBusFrameNumber$FUNC + ); + public interface GetBusFrameNumber { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(GetBusFrameNumber fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetBusFrameNumber.class, fi, IOUSBDeviceStruct942.GetBusFrameNumber$FUNC, session); + } + static GetBusFrameNumber ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBDeviceStruct942.GetBusFrameNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetBusFrameNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBusFrameNumber")); + public static VarHandle GetBusFrameNumber$VH() { + return IOUSBDeviceStruct942.GetBusFrameNumber$VH; + } + public static MemoryAddress GetBusFrameNumber$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetBusFrameNumber$VH.get(seg); + } + public static void GetBusFrameNumber$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetBusFrameNumber$VH.set(seg, x); + } + public static MemoryAddress GetBusFrameNumber$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetBusFrameNumber$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetBusFrameNumber$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetBusFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetBusFrameNumber GetBusFrameNumber (MemorySegment segment, MemorySession session) { + return GetBusFrameNumber.ofAddress(GetBusFrameNumber$get(segment), session); + } + static final FunctionDescriptor ResetDevice$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle ResetDevice$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.ResetDevice$FUNC + ); + public interface ResetDevice { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(ResetDevice fi, MemorySession session) { + return RuntimeHelper.upcallStub(ResetDevice.class, fi, IOUSBDeviceStruct942.ResetDevice$FUNC, session); + } + static ResetDevice ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBDeviceStruct942.ResetDevice$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle ResetDevice$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ResetDevice")); + public static VarHandle ResetDevice$VH() { + return IOUSBDeviceStruct942.ResetDevice$VH; + } + public static MemoryAddress ResetDevice$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.ResetDevice$VH.get(seg); + } + public static void ResetDevice$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.ResetDevice$VH.set(seg, x); + } + public static MemoryAddress ResetDevice$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.ResetDevice$VH.get(seg.asSlice(index*sizeof())); + } + public static void ResetDevice$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.ResetDevice$VH.set(seg.asSlice(index*sizeof()), x); + } + public static ResetDevice ResetDevice (MemorySegment segment, MemorySession session) { + return ResetDevice.ofAddress(ResetDevice$get(segment), session); + } + static final FunctionDescriptor DeviceRequest$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle DeviceRequest$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.DeviceRequest$FUNC + ); + public interface DeviceRequest { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(DeviceRequest fi, MemorySession session) { + return RuntimeHelper.upcallStub(DeviceRequest.class, fi, IOUSBDeviceStruct942.DeviceRequest$FUNC, session); + } + static DeviceRequest ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.DeviceRequest$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle DeviceRequest$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequest")); + public static VarHandle DeviceRequest$VH() { + return IOUSBDeviceStruct942.DeviceRequest$VH; + } + public static MemoryAddress DeviceRequest$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.DeviceRequest$VH.get(seg); + } + public static void DeviceRequest$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.DeviceRequest$VH.set(seg, x); + } + public static MemoryAddress DeviceRequest$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.DeviceRequest$VH.get(seg.asSlice(index*sizeof())); + } + public static void DeviceRequest$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.DeviceRequest$VH.set(seg.asSlice(index*sizeof()), x); + } + public static DeviceRequest DeviceRequest (MemorySegment segment, MemorySession session) { + return DeviceRequest.ofAddress(DeviceRequest$get(segment), session); + } + static final FunctionDescriptor DeviceRequestAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle DeviceRequestAsync$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.DeviceRequestAsync$FUNC + ); + public interface DeviceRequestAsync { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3); + static MemorySegment allocate(DeviceRequestAsync fi, MemorySession session) { + return RuntimeHelper.upcallStub(DeviceRequestAsync.class, fi, IOUSBDeviceStruct942.DeviceRequestAsync$FUNC, session); + } + static DeviceRequestAsync ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3) -> { + try { + return (int)IOUSBDeviceStruct942.DeviceRequestAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle DeviceRequestAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestAsync")); + public static VarHandle DeviceRequestAsync$VH() { + return IOUSBDeviceStruct942.DeviceRequestAsync$VH; + } + public static MemoryAddress DeviceRequestAsync$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.DeviceRequestAsync$VH.get(seg); + } + public static void DeviceRequestAsync$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.DeviceRequestAsync$VH.set(seg, x); + } + public static MemoryAddress DeviceRequestAsync$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.DeviceRequestAsync$VH.get(seg.asSlice(index*sizeof())); + } + public static void DeviceRequestAsync$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.DeviceRequestAsync$VH.set(seg.asSlice(index*sizeof()), x); + } + public static DeviceRequestAsync DeviceRequestAsync (MemorySegment segment, MemorySession session) { + return DeviceRequestAsync.ofAddress(DeviceRequestAsync$get(segment), session); + } + static final FunctionDescriptor CreateInterfaceIterator$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CreateInterfaceIterator$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.CreateInterfaceIterator$FUNC + ); + public interface CreateInterfaceIterator { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(CreateInterfaceIterator fi, MemorySession session) { + return RuntimeHelper.upcallStub(CreateInterfaceIterator.class, fi, IOUSBDeviceStruct942.CreateInterfaceIterator$FUNC, session); + } + static CreateInterfaceIterator ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBDeviceStruct942.CreateInterfaceIterator$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle CreateInterfaceIterator$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceIterator")); + public static VarHandle CreateInterfaceIterator$VH() { + return IOUSBDeviceStruct942.CreateInterfaceIterator$VH; + } + public static MemoryAddress CreateInterfaceIterator$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.CreateInterfaceIterator$VH.get(seg); + } + public static void CreateInterfaceIterator$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.CreateInterfaceIterator$VH.set(seg, x); + } + public static MemoryAddress CreateInterfaceIterator$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.CreateInterfaceIterator$VH.get(seg.asSlice(index*sizeof())); + } + public static void CreateInterfaceIterator$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.CreateInterfaceIterator$VH.set(seg.asSlice(index*sizeof()), x); + } + public static CreateInterfaceIterator CreateInterfaceIterator (MemorySegment segment, MemorySession session) { + return CreateInterfaceIterator.ofAddress(CreateInterfaceIterator$get(segment), session); + } + static final FunctionDescriptor USBDeviceOpenSeize$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBDeviceOpenSeize$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.USBDeviceOpenSeize$FUNC + ); + public interface USBDeviceOpenSeize { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(USBDeviceOpenSeize fi, MemorySession session) { + return RuntimeHelper.upcallStub(USBDeviceOpenSeize.class, fi, IOUSBDeviceStruct942.USBDeviceOpenSeize$FUNC, session); + } + static USBDeviceOpenSeize ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBDeviceStruct942.USBDeviceOpenSeize$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBDeviceOpenSeize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceOpenSeize")); + public static VarHandle USBDeviceOpenSeize$VH() { + return IOUSBDeviceStruct942.USBDeviceOpenSeize$VH; + } + public static MemoryAddress USBDeviceOpenSeize$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceOpenSeize$VH.get(seg); + } + public static void USBDeviceOpenSeize$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.USBDeviceOpenSeize$VH.set(seg, x); + } + public static MemoryAddress USBDeviceOpenSeize$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceOpenSeize$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBDeviceOpenSeize$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.USBDeviceOpenSeize$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBDeviceOpenSeize USBDeviceOpenSeize (MemorySegment segment, MemorySession session) { + return USBDeviceOpenSeize.ofAddress(USBDeviceOpenSeize$get(segment), session); + } + static final FunctionDescriptor DeviceRequestTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle DeviceRequestTO$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.DeviceRequestTO$FUNC + ); + public interface DeviceRequestTO { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(DeviceRequestTO fi, MemorySession session) { + return RuntimeHelper.upcallStub(DeviceRequestTO.class, fi, IOUSBDeviceStruct942.DeviceRequestTO$FUNC, session); + } + static DeviceRequestTO ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.DeviceRequestTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle DeviceRequestTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestTO")); + public static VarHandle DeviceRequestTO$VH() { + return IOUSBDeviceStruct942.DeviceRequestTO$VH; + } + public static MemoryAddress DeviceRequestTO$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.DeviceRequestTO$VH.get(seg); + } + public static void DeviceRequestTO$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.DeviceRequestTO$VH.set(seg, x); + } + public static MemoryAddress DeviceRequestTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.DeviceRequestTO$VH.get(seg.asSlice(index*sizeof())); + } + public static void DeviceRequestTO$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.DeviceRequestTO$VH.set(seg.asSlice(index*sizeof()), x); + } + public static DeviceRequestTO DeviceRequestTO (MemorySegment segment, MemorySession session) { + return DeviceRequestTO.ofAddress(DeviceRequestTO$get(segment), session); + } + static final FunctionDescriptor DeviceRequestAsyncTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle DeviceRequestAsyncTO$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.DeviceRequestAsyncTO$FUNC + ); + public interface DeviceRequestAsyncTO { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3); + static MemorySegment allocate(DeviceRequestAsyncTO fi, MemorySession session) { + return RuntimeHelper.upcallStub(DeviceRequestAsyncTO.class, fi, IOUSBDeviceStruct942.DeviceRequestAsyncTO$FUNC, session); + } + static DeviceRequestAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3) -> { + try { + return (int)IOUSBDeviceStruct942.DeviceRequestAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle DeviceRequestAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestAsyncTO")); + public static VarHandle DeviceRequestAsyncTO$VH() { + return IOUSBDeviceStruct942.DeviceRequestAsyncTO$VH; + } + public static MemoryAddress DeviceRequestAsyncTO$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.DeviceRequestAsyncTO$VH.get(seg); + } + public static void DeviceRequestAsyncTO$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.DeviceRequestAsyncTO$VH.set(seg, x); + } + public static MemoryAddress DeviceRequestAsyncTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.DeviceRequestAsyncTO$VH.get(seg.asSlice(index*sizeof())); + } + public static void DeviceRequestAsyncTO$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.DeviceRequestAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); + } + public static DeviceRequestAsyncTO DeviceRequestAsyncTO (MemorySegment segment, MemorySession session) { + return DeviceRequestAsyncTO.ofAddress(DeviceRequestAsyncTO$get(segment), session); + } + static final FunctionDescriptor USBDeviceSuspend$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT + ); + static final MethodHandle USBDeviceSuspend$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.USBDeviceSuspend$FUNC + ); + public interface USBDeviceSuspend { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); + static MemorySegment allocate(USBDeviceSuspend fi, MemorySession session) { + return RuntimeHelper.upcallStub(USBDeviceSuspend.class, fi, IOUSBDeviceStruct942.USBDeviceSuspend$FUNC, session); + } + static USBDeviceSuspend ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { + try { + return (int)IOUSBDeviceStruct942.USBDeviceSuspend$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBDeviceSuspend$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceSuspend")); + public static VarHandle USBDeviceSuspend$VH() { + return IOUSBDeviceStruct942.USBDeviceSuspend$VH; + } + public static MemoryAddress USBDeviceSuspend$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceSuspend$VH.get(seg); + } + public static void USBDeviceSuspend$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.USBDeviceSuspend$VH.set(seg, x); + } + public static MemoryAddress USBDeviceSuspend$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceSuspend$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBDeviceSuspend$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.USBDeviceSuspend$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBDeviceSuspend USBDeviceSuspend (MemorySegment segment, MemorySession session) { + return USBDeviceSuspend.ofAddress(USBDeviceSuspend$get(segment), session); + } + static final FunctionDescriptor USBDeviceAbortPipeZero$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBDeviceAbortPipeZero$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.USBDeviceAbortPipeZero$FUNC + ); + public interface USBDeviceAbortPipeZero { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(USBDeviceAbortPipeZero fi, MemorySession session) { + return RuntimeHelper.upcallStub(USBDeviceAbortPipeZero.class, fi, IOUSBDeviceStruct942.USBDeviceAbortPipeZero$FUNC, session); + } + static USBDeviceAbortPipeZero ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBDeviceStruct942.USBDeviceAbortPipeZero$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBDeviceAbortPipeZero$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceAbortPipeZero")); + public static VarHandle USBDeviceAbortPipeZero$VH() { + return IOUSBDeviceStruct942.USBDeviceAbortPipeZero$VH; + } + public static MemoryAddress USBDeviceAbortPipeZero$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceAbortPipeZero$VH.get(seg); + } + public static void USBDeviceAbortPipeZero$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.USBDeviceAbortPipeZero$VH.set(seg, x); + } + public static MemoryAddress USBDeviceAbortPipeZero$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceAbortPipeZero$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBDeviceAbortPipeZero$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.USBDeviceAbortPipeZero$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBDeviceAbortPipeZero USBDeviceAbortPipeZero (MemorySegment segment, MemorySession session) { + return USBDeviceAbortPipeZero.ofAddress(USBDeviceAbortPipeZero$get(segment), session); + } + static final FunctionDescriptor USBGetManufacturerStringIndex$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBGetManufacturerStringIndex$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.USBGetManufacturerStringIndex$FUNC + ); + public interface USBGetManufacturerStringIndex { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(USBGetManufacturerStringIndex fi, MemorySession session) { + return RuntimeHelper.upcallStub(USBGetManufacturerStringIndex.class, fi, IOUSBDeviceStruct942.USBGetManufacturerStringIndex$FUNC, session); + } + static USBGetManufacturerStringIndex ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.USBGetManufacturerStringIndex$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBGetManufacturerStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBGetManufacturerStringIndex")); + public static VarHandle USBGetManufacturerStringIndex$VH() { + return IOUSBDeviceStruct942.USBGetManufacturerStringIndex$VH; + } + public static MemoryAddress USBGetManufacturerStringIndex$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBGetManufacturerStringIndex$VH.get(seg); + } + public static void USBGetManufacturerStringIndex$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.USBGetManufacturerStringIndex$VH.set(seg, x); + } + public static MemoryAddress USBGetManufacturerStringIndex$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBGetManufacturerStringIndex$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBGetManufacturerStringIndex$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.USBGetManufacturerStringIndex$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBGetManufacturerStringIndex USBGetManufacturerStringIndex (MemorySegment segment, MemorySession session) { + return USBGetManufacturerStringIndex.ofAddress(USBGetManufacturerStringIndex$get(segment), session); + } + static final FunctionDescriptor USBGetProductStringIndex$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBGetProductStringIndex$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.USBGetProductStringIndex$FUNC + ); + public interface USBGetProductStringIndex { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(USBGetProductStringIndex fi, MemorySession session) { + return RuntimeHelper.upcallStub(USBGetProductStringIndex.class, fi, IOUSBDeviceStruct942.USBGetProductStringIndex$FUNC, session); + } + static USBGetProductStringIndex ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.USBGetProductStringIndex$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBGetProductStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBGetProductStringIndex")); + public static VarHandle USBGetProductStringIndex$VH() { + return IOUSBDeviceStruct942.USBGetProductStringIndex$VH; + } + public static MemoryAddress USBGetProductStringIndex$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBGetProductStringIndex$VH.get(seg); + } + public static void USBGetProductStringIndex$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.USBGetProductStringIndex$VH.set(seg, x); + } + public static MemoryAddress USBGetProductStringIndex$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBGetProductStringIndex$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBGetProductStringIndex$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.USBGetProductStringIndex$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBGetProductStringIndex USBGetProductStringIndex (MemorySegment segment, MemorySession session) { + return USBGetProductStringIndex.ofAddress(USBGetProductStringIndex$get(segment), session); + } + static final FunctionDescriptor USBGetSerialNumberStringIndex$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBGetSerialNumberStringIndex$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.USBGetSerialNumberStringIndex$FUNC + ); + public interface USBGetSerialNumberStringIndex { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(USBGetSerialNumberStringIndex fi, MemorySession session) { + return RuntimeHelper.upcallStub(USBGetSerialNumberStringIndex.class, fi, IOUSBDeviceStruct942.USBGetSerialNumberStringIndex$FUNC, session); + } + static USBGetSerialNumberStringIndex ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.USBGetSerialNumberStringIndex$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBGetSerialNumberStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBGetSerialNumberStringIndex")); + public static VarHandle USBGetSerialNumberStringIndex$VH() { + return IOUSBDeviceStruct942.USBGetSerialNumberStringIndex$VH; + } + public static MemoryAddress USBGetSerialNumberStringIndex$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBGetSerialNumberStringIndex$VH.get(seg); + } + public static void USBGetSerialNumberStringIndex$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.USBGetSerialNumberStringIndex$VH.set(seg, x); + } + public static MemoryAddress USBGetSerialNumberStringIndex$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBGetSerialNumberStringIndex$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBGetSerialNumberStringIndex$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.USBGetSerialNumberStringIndex$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBGetSerialNumberStringIndex USBGetSerialNumberStringIndex (MemorySegment segment, MemorySession session) { + return USBGetSerialNumberStringIndex.ofAddress(USBGetSerialNumberStringIndex$get(segment), session); + } + static final FunctionDescriptor USBDeviceReEnumerate$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle USBDeviceReEnumerate$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.USBDeviceReEnumerate$FUNC + ); + public interface USBDeviceReEnumerate { + + int apply(java.lang.foreign.MemoryAddress _x0, int _x1); + static MemorySegment allocate(USBDeviceReEnumerate fi, MemorySession session) { + return RuntimeHelper.upcallStub(USBDeviceReEnumerate.class, fi, IOUSBDeviceStruct942.USBDeviceReEnumerate$FUNC, session); + } + static USBDeviceReEnumerate ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, int __x1) -> { + try { + return (int)IOUSBDeviceStruct942.USBDeviceReEnumerate$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBDeviceReEnumerate$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceReEnumerate")); + public static VarHandle USBDeviceReEnumerate$VH() { + return IOUSBDeviceStruct942.USBDeviceReEnumerate$VH; + } + public static MemoryAddress USBDeviceReEnumerate$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceReEnumerate$VH.get(seg); + } + public static void USBDeviceReEnumerate$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.USBDeviceReEnumerate$VH.set(seg, x); + } + public static MemoryAddress USBDeviceReEnumerate$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceReEnumerate$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBDeviceReEnumerate$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.USBDeviceReEnumerate$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBDeviceReEnumerate USBDeviceReEnumerate (MemorySegment segment, MemorySession session) { + return USBDeviceReEnumerate.ofAddress(USBDeviceReEnumerate$get(segment), session); + } + static final FunctionDescriptor GetBusMicroFrameNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetBusMicroFrameNumber$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetBusMicroFrameNumber$FUNC + ); + public interface GetBusMicroFrameNumber { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(GetBusMicroFrameNumber fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetBusMicroFrameNumber.class, fi, IOUSBDeviceStruct942.GetBusMicroFrameNumber$FUNC, session); + } + static GetBusMicroFrameNumber ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBDeviceStruct942.GetBusMicroFrameNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetBusMicroFrameNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBusMicroFrameNumber")); + public static VarHandle GetBusMicroFrameNumber$VH() { + return IOUSBDeviceStruct942.GetBusMicroFrameNumber$VH; + } + public static MemoryAddress GetBusMicroFrameNumber$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetBusMicroFrameNumber$VH.get(seg); + } + public static void GetBusMicroFrameNumber$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetBusMicroFrameNumber$VH.set(seg, x); + } + public static MemoryAddress GetBusMicroFrameNumber$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetBusMicroFrameNumber$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetBusMicroFrameNumber$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetBusMicroFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetBusMicroFrameNumber GetBusMicroFrameNumber (MemorySegment segment, MemorySession session) { + return GetBusMicroFrameNumber.ofAddress(GetBusMicroFrameNumber$get(segment), session); + } + static final FunctionDescriptor GetIOUSBLibVersion$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetIOUSBLibVersion$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetIOUSBLibVersion$FUNC + ); + public interface GetIOUSBLibVersion { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(GetIOUSBLibVersion fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetIOUSBLibVersion.class, fi, IOUSBDeviceStruct942.GetIOUSBLibVersion$FUNC, session); + } + static GetIOUSBLibVersion ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBDeviceStruct942.GetIOUSBLibVersion$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetIOUSBLibVersion$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetIOUSBLibVersion")); + public static VarHandle GetIOUSBLibVersion$VH() { + return IOUSBDeviceStruct942.GetIOUSBLibVersion$VH; + } + public static MemoryAddress GetIOUSBLibVersion$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetIOUSBLibVersion$VH.get(seg); + } + public static void GetIOUSBLibVersion$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetIOUSBLibVersion$VH.set(seg, x); + } + public static MemoryAddress GetIOUSBLibVersion$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetIOUSBLibVersion$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetIOUSBLibVersion$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetIOUSBLibVersion$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetIOUSBLibVersion GetIOUSBLibVersion (MemorySegment segment, MemorySession session) { + return GetIOUSBLibVersion.ofAddress(GetIOUSBLibVersion$get(segment), session); + } + static final FunctionDescriptor GetBusFrameNumberWithTime$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetBusFrameNumberWithTime$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetBusFrameNumberWithTime$FUNC + ); + public interface GetBusFrameNumberWithTime { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(GetBusFrameNumberWithTime fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetBusFrameNumberWithTime.class, fi, IOUSBDeviceStruct942.GetBusFrameNumberWithTime$FUNC, session); + } + static GetBusFrameNumberWithTime ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBDeviceStruct942.GetBusFrameNumberWithTime$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetBusFrameNumberWithTime$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBusFrameNumberWithTime")); + public static VarHandle GetBusFrameNumberWithTime$VH() { + return IOUSBDeviceStruct942.GetBusFrameNumberWithTime$VH; + } + public static MemoryAddress GetBusFrameNumberWithTime$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetBusFrameNumberWithTime$VH.get(seg); + } + public static void GetBusFrameNumberWithTime$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetBusFrameNumberWithTime$VH.set(seg, x); + } + public static MemoryAddress GetBusFrameNumberWithTime$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetBusFrameNumberWithTime$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetBusFrameNumberWithTime$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetBusFrameNumberWithTime$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetBusFrameNumberWithTime GetBusFrameNumberWithTime (MemorySegment segment, MemorySession session) { + return GetBusFrameNumberWithTime.ofAddress(GetBusFrameNumberWithTime$get(segment), session); + } + static final FunctionDescriptor GetUSBDeviceInformation$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetUSBDeviceInformation$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetUSBDeviceInformation$FUNC + ); + public interface GetUSBDeviceInformation { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetUSBDeviceInformation fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetUSBDeviceInformation.class, fi, IOUSBDeviceStruct942.GetUSBDeviceInformation$FUNC, session); + } + static GetUSBDeviceInformation ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.GetUSBDeviceInformation$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetUSBDeviceInformation$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetUSBDeviceInformation")); + public static VarHandle GetUSBDeviceInformation$VH() { + return IOUSBDeviceStruct942.GetUSBDeviceInformation$VH; + } + public static MemoryAddress GetUSBDeviceInformation$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetUSBDeviceInformation$VH.get(seg); + } + public static void GetUSBDeviceInformation$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetUSBDeviceInformation$VH.set(seg, x); + } + public static MemoryAddress GetUSBDeviceInformation$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetUSBDeviceInformation$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetUSBDeviceInformation$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetUSBDeviceInformation$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetUSBDeviceInformation GetUSBDeviceInformation (MemorySegment segment, MemorySession session) { + return GetUSBDeviceInformation.ofAddress(GetUSBDeviceInformation$get(segment), session); + } + static final FunctionDescriptor RequestExtraPower$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle RequestExtraPower$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.RequestExtraPower$FUNC + ); + public interface RequestExtraPower { + + int apply(java.lang.foreign.MemoryAddress _x0, int _x1, int _x2, java.lang.foreign.MemoryAddress _x3); + static MemorySegment allocate(RequestExtraPower fi, MemorySession session) { + return RuntimeHelper.upcallStub(RequestExtraPower.class, fi, IOUSBDeviceStruct942.RequestExtraPower$FUNC, session); + } + static RequestExtraPower ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, int __x1, int __x2, java.lang.foreign.MemoryAddress __x3) -> { + try { + return (int)IOUSBDeviceStruct942.RequestExtraPower$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, (java.lang.foreign.Addressable)__x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle RequestExtraPower$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("RequestExtraPower")); + public static VarHandle RequestExtraPower$VH() { + return IOUSBDeviceStruct942.RequestExtraPower$VH; + } + public static MemoryAddress RequestExtraPower$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.RequestExtraPower$VH.get(seg); + } + public static void RequestExtraPower$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.RequestExtraPower$VH.set(seg, x); + } + public static MemoryAddress RequestExtraPower$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.RequestExtraPower$VH.get(seg.asSlice(index*sizeof())); + } + public static void RequestExtraPower$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.RequestExtraPower$VH.set(seg.asSlice(index*sizeof()), x); + } + public static RequestExtraPower RequestExtraPower (MemorySegment segment, MemorySession session) { + return RequestExtraPower.ofAddress(RequestExtraPower$get(segment), session); + } + static final FunctionDescriptor ReturnExtraPower$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle ReturnExtraPower$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.ReturnExtraPower$FUNC + ); + public interface ReturnExtraPower { + + int apply(java.lang.foreign.MemoryAddress _x0, int _x1, int _x2); + static MemorySegment allocate(ReturnExtraPower fi, MemorySession session) { + return RuntimeHelper.upcallStub(ReturnExtraPower.class, fi, IOUSBDeviceStruct942.ReturnExtraPower$FUNC, session); + } + static ReturnExtraPower ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, int __x1, int __x2) -> { + try { + return (int)IOUSBDeviceStruct942.ReturnExtraPower$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle ReturnExtraPower$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReturnExtraPower")); + public static VarHandle ReturnExtraPower$VH() { + return IOUSBDeviceStruct942.ReturnExtraPower$VH; + } + public static MemoryAddress ReturnExtraPower$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.ReturnExtraPower$VH.get(seg); + } + public static void ReturnExtraPower$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.ReturnExtraPower$VH.set(seg, x); + } + public static MemoryAddress ReturnExtraPower$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.ReturnExtraPower$VH.get(seg.asSlice(index*sizeof())); + } + public static void ReturnExtraPower$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.ReturnExtraPower$VH.set(seg.asSlice(index*sizeof()), x); + } + public static ReturnExtraPower ReturnExtraPower (MemorySegment segment, MemorySession session) { + return ReturnExtraPower.ofAddress(ReturnExtraPower$get(segment), session); + } + static final FunctionDescriptor GetExtraPowerAllocated$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetExtraPowerAllocated$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetExtraPowerAllocated$FUNC + ); + public interface GetExtraPowerAllocated { + + int apply(java.lang.foreign.MemoryAddress _x0, int _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(GetExtraPowerAllocated fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetExtraPowerAllocated.class, fi, IOUSBDeviceStruct942.GetExtraPowerAllocated$FUNC, session); + } + static GetExtraPowerAllocated ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, int __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBDeviceStruct942.GetExtraPowerAllocated$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetExtraPowerAllocated$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetExtraPowerAllocated")); + public static VarHandle GetExtraPowerAllocated$VH() { + return IOUSBDeviceStruct942.GetExtraPowerAllocated$VH; + } + public static MemoryAddress GetExtraPowerAllocated$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetExtraPowerAllocated$VH.get(seg); + } + public static void GetExtraPowerAllocated$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetExtraPowerAllocated$VH.set(seg, x); + } + public static MemoryAddress GetExtraPowerAllocated$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetExtraPowerAllocated$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetExtraPowerAllocated$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetExtraPowerAllocated$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetExtraPowerAllocated GetExtraPowerAllocated (MemorySegment segment, MemorySession session) { + return GetExtraPowerAllocated.ofAddress(GetExtraPowerAllocated$get(segment), session); + } + static final FunctionDescriptor GetBandwidthAvailableForDevice$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetBandwidthAvailableForDevice$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetBandwidthAvailableForDevice$FUNC + ); + public interface GetBandwidthAvailableForDevice { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetBandwidthAvailableForDevice fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetBandwidthAvailableForDevice.class, fi, IOUSBDeviceStruct942.GetBandwidthAvailableForDevice$FUNC, session); + } + static GetBandwidthAvailableForDevice ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct942.GetBandwidthAvailableForDevice$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetBandwidthAvailableForDevice$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBandwidthAvailableForDevice")); + public static VarHandle GetBandwidthAvailableForDevice$VH() { + return IOUSBDeviceStruct942.GetBandwidthAvailableForDevice$VH; + } + public static MemoryAddress GetBandwidthAvailableForDevice$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetBandwidthAvailableForDevice$VH.get(seg); + } + public static void GetBandwidthAvailableForDevice$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetBandwidthAvailableForDevice$VH.set(seg, x); + } + public static MemoryAddress GetBandwidthAvailableForDevice$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetBandwidthAvailableForDevice$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetBandwidthAvailableForDevice$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetBandwidthAvailableForDevice$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetBandwidthAvailableForDevice GetBandwidthAvailableForDevice (MemorySegment segment, MemorySession session) { + return GetBandwidthAvailableForDevice.ofAddress(GetBandwidthAvailableForDevice$get(segment), session); + } + static final FunctionDescriptor SetConfigurationV2$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_BOOL$LAYOUT, + Constants$root.C_BOOL$LAYOUT + ); + static final MethodHandle SetConfigurationV2$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.SetConfigurationV2$FUNC + ); + public interface SetConfigurationV2 { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, boolean _x2, boolean _x3); + static MemorySegment allocate(SetConfigurationV2 fi, MemorySession session) { + return RuntimeHelper.upcallStub(SetConfigurationV2.class, fi, IOUSBDeviceStruct942.SetConfigurationV2$FUNC, session); + } + static SetConfigurationV2 ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, boolean __x2, boolean __x3) -> { + try { + return (int)IOUSBDeviceStruct942.SetConfigurationV2$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, __x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle SetConfigurationV2$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetConfigurationV2")); + public static VarHandle SetConfigurationV2$VH() { + return IOUSBDeviceStruct942.SetConfigurationV2$VH; + } + public static MemoryAddress SetConfigurationV2$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.SetConfigurationV2$VH.get(seg); + } + public static void SetConfigurationV2$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.SetConfigurationV2$VH.set(seg, x); + } + public static MemoryAddress SetConfigurationV2$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.SetConfigurationV2$VH.get(seg.asSlice(index*sizeof())); + } + public static void SetConfigurationV2$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.SetConfigurationV2$VH.set(seg.asSlice(index*sizeof()), x); + } + public static SetConfigurationV2 SetConfigurationV2 (MemorySegment segment, MemorySession session) { + return SetConfigurationV2.ofAddress(SetConfigurationV2$get(segment), session); + } + static final FunctionDescriptor RegisterForNotification$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle RegisterForNotification$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.RegisterForNotification$FUNC + ); + public interface RegisterForNotification { + + int apply(java.lang.foreign.MemoryAddress _x0, long _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, java.lang.foreign.MemoryAddress _x4); + static MemorySegment allocate(RegisterForNotification fi, MemorySession session) { + return RuntimeHelper.upcallStub(RegisterForNotification.class, fi, IOUSBDeviceStruct942.RegisterForNotification$FUNC, session); + } + static RegisterForNotification ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, long __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, java.lang.foreign.MemoryAddress __x4) -> { + try { + return (int)IOUSBDeviceStruct942.RegisterForNotification$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle RegisterForNotification$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("RegisterForNotification")); + public static VarHandle RegisterForNotification$VH() { + return IOUSBDeviceStruct942.RegisterForNotification$VH; + } + public static MemoryAddress RegisterForNotification$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.RegisterForNotification$VH.get(seg); + } + public static void RegisterForNotification$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.RegisterForNotification$VH.set(seg, x); + } + public static MemoryAddress RegisterForNotification$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.RegisterForNotification$VH.get(seg.asSlice(index*sizeof())); + } + public static void RegisterForNotification$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.RegisterForNotification$VH.set(seg.asSlice(index*sizeof()), x); + } + public static RegisterForNotification RegisterForNotification (MemorySegment segment, MemorySession session) { + return RegisterForNotification.ofAddress(RegisterForNotification$get(segment), session); + } + static final FunctionDescriptor UnregisterNotification$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle UnregisterNotification$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.UnregisterNotification$FUNC + ); + public interface UnregisterNotification { + + int apply(java.lang.foreign.MemoryAddress _x0, long _x1); + static MemorySegment allocate(UnregisterNotification fi, MemorySession session) { + return RuntimeHelper.upcallStub(UnregisterNotification.class, fi, IOUSBDeviceStruct942.UnregisterNotification$FUNC, session); + } + static UnregisterNotification ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, long __x1) -> { + try { + return (int)IOUSBDeviceStruct942.UnregisterNotification$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle UnregisterNotification$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("UnregisterNotification")); + public static VarHandle UnregisterNotification$VH() { + return IOUSBDeviceStruct942.UnregisterNotification$VH; + } + public static MemoryAddress UnregisterNotification$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.UnregisterNotification$VH.get(seg); + } + public static void UnregisterNotification$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.UnregisterNotification$VH.set(seg, x); + } + public static MemoryAddress UnregisterNotification$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.UnregisterNotification$VH.get(seg.asSlice(index*sizeof())); + } + public static void UnregisterNotification$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.UnregisterNotification$VH.set(seg.asSlice(index*sizeof()), x); + } + public static UnregisterNotification UnregisterNotification (MemorySegment segment, MemorySession session) { + return UnregisterNotification.ofAddress(UnregisterNotification$get(segment), session); + } + static final FunctionDescriptor AcknowledgeNotification$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle AcknowledgeNotification$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.AcknowledgeNotification$FUNC + ); + public interface AcknowledgeNotification { + + int apply(java.lang.foreign.MemoryAddress _x0, long _x1); + static MemorySegment allocate(AcknowledgeNotification fi, MemorySession session) { + return RuntimeHelper.upcallStub(AcknowledgeNotification.class, fi, IOUSBDeviceStruct942.AcknowledgeNotification$FUNC, session); + } + static AcknowledgeNotification ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, long __x1) -> { + try { + return (int)IOUSBDeviceStruct942.AcknowledgeNotification$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle AcknowledgeNotification$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AcknowledgeNotification")); + public static VarHandle AcknowledgeNotification$VH() { + return IOUSBDeviceStruct942.AcknowledgeNotification$VH; + } + public static MemoryAddress AcknowledgeNotification$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.AcknowledgeNotification$VH.get(seg); + } + public static void AcknowledgeNotification$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.AcknowledgeNotification$VH.set(seg, x); + } + public static MemoryAddress AcknowledgeNotification$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.AcknowledgeNotification$VH.get(seg.asSlice(index*sizeof())); + } + public static void AcknowledgeNotification$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.AcknowledgeNotification$VH.set(seg.asSlice(index*sizeof()), x); + } + public static AcknowledgeNotification AcknowledgeNotification (MemorySegment segment, MemorySession session) { + return AcknowledgeNotification.ofAddress(AcknowledgeNotification$get(segment), session); + } + static final FunctionDescriptor GetDeviceAsyncNotificationPort$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceAsyncNotificationPort$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct942.GetDeviceAsyncNotificationPort$FUNC + ); + public interface GetDeviceAsyncNotificationPort { + + java.lang.foreign.Addressable apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(GetDeviceAsyncNotificationPort fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceAsyncNotificationPort.class, fi, IOUSBDeviceStruct942.GetDeviceAsyncNotificationPort$FUNC, session); + } + static GetDeviceAsyncNotificationPort ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (java.lang.foreign.Addressable)(java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAsyncNotificationPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceAsyncNotificationPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncNotificationPort")); + public static VarHandle GetDeviceAsyncNotificationPort$VH() { + return IOUSBDeviceStruct942.GetDeviceAsyncNotificationPort$VH; + } + public static MemoryAddress GetDeviceAsyncNotificationPort$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAsyncNotificationPort$VH.get(seg); + } + public static void GetDeviceAsyncNotificationPort$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceAsyncNotificationPort$VH.set(seg, x); + } + public static MemoryAddress GetDeviceAsyncNotificationPort$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAsyncNotificationPort$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceAsyncNotificationPort$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct942.GetDeviceAsyncNotificationPort$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceAsyncNotificationPort GetDeviceAsyncNotificationPort (MemorySegment segment, MemorySession session) { + return GetDeviceAsyncNotificationPort.ofAddress(GetDeviceAsyncNotificationPort$get(segment), session); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java new file mode 100644 index 00000000..e4e95f67 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java @@ -0,0 +1,90 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class IOUSBFindInterfaceRequest { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_SHORT$LAYOUT.withName("bInterfaceClass"), + Constants$root.C_SHORT$LAYOUT.withName("bInterfaceSubClass"), + Constants$root.C_SHORT$LAYOUT.withName("bInterfaceProtocol"), + Constants$root.C_SHORT$LAYOUT.withName("bAlternateSetting") + ); + public static MemoryLayout $LAYOUT() { + return IOUSBFindInterfaceRequest.$struct$LAYOUT; + } + static final VarHandle bInterfaceClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("bInterfaceClass")); + public static VarHandle bInterfaceClass$VH() { + return IOUSBFindInterfaceRequest.bInterfaceClass$VH; + } + public static short bInterfaceClass$get(MemorySegment seg) { + return (short)IOUSBFindInterfaceRequest.bInterfaceClass$VH.get(seg); + } + public static void bInterfaceClass$set( MemorySegment seg, short x) { + IOUSBFindInterfaceRequest.bInterfaceClass$VH.set(seg, x); + } + public static short bInterfaceClass$get(MemorySegment seg, long index) { + return (short)IOUSBFindInterfaceRequest.bInterfaceClass$VH.get(seg.asSlice(index*sizeof())); + } + public static void bInterfaceClass$set(MemorySegment seg, long index, short x) { + IOUSBFindInterfaceRequest.bInterfaceClass$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle bInterfaceSubClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("bInterfaceSubClass")); + public static VarHandle bInterfaceSubClass$VH() { + return IOUSBFindInterfaceRequest.bInterfaceSubClass$VH; + } + public static short bInterfaceSubClass$get(MemorySegment seg) { + return (short)IOUSBFindInterfaceRequest.bInterfaceSubClass$VH.get(seg); + } + public static void bInterfaceSubClass$set( MemorySegment seg, short x) { + IOUSBFindInterfaceRequest.bInterfaceSubClass$VH.set(seg, x); + } + public static short bInterfaceSubClass$get(MemorySegment seg, long index) { + return (short)IOUSBFindInterfaceRequest.bInterfaceSubClass$VH.get(seg.asSlice(index*sizeof())); + } + public static void bInterfaceSubClass$set(MemorySegment seg, long index, short x) { + IOUSBFindInterfaceRequest.bInterfaceSubClass$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle bInterfaceProtocol$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("bInterfaceProtocol")); + public static VarHandle bInterfaceProtocol$VH() { + return IOUSBFindInterfaceRequest.bInterfaceProtocol$VH; + } + public static short bInterfaceProtocol$get(MemorySegment seg) { + return (short)IOUSBFindInterfaceRequest.bInterfaceProtocol$VH.get(seg); + } + public static void bInterfaceProtocol$set( MemorySegment seg, short x) { + IOUSBFindInterfaceRequest.bInterfaceProtocol$VH.set(seg, x); + } + public static short bInterfaceProtocol$get(MemorySegment seg, long index) { + return (short)IOUSBFindInterfaceRequest.bInterfaceProtocol$VH.get(seg.asSlice(index*sizeof())); + } + public static void bInterfaceProtocol$set(MemorySegment seg, long index, short x) { + IOUSBFindInterfaceRequest.bInterfaceProtocol$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle bAlternateSetting$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("bAlternateSetting")); + public static VarHandle bAlternateSetting$VH() { + return IOUSBFindInterfaceRequest.bAlternateSetting$VH; + } + public static short bAlternateSetting$get(MemorySegment seg) { + return (short)IOUSBFindInterfaceRequest.bAlternateSetting$VH.get(seg); + } + public static void bAlternateSetting$set( MemorySegment seg, short x) { + IOUSBFindInterfaceRequest.bAlternateSetting$VH.set(seg, x); + } + public static short bAlternateSetting$get(MemorySegment seg, long index) { + return (short)IOUSBFindInterfaceRequest.bAlternateSetting$VH.get(seg.asSlice(index*sizeof())); + } + public static void bAlternateSetting$set(MemorySegment seg, long index, short x) { + IOUSBFindInterfaceRequest.bAlternateSetting$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface.java new file mode 100644 index 00000000..11bc0952 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface.java @@ -0,0 +1,9 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +public class IOUSBInterfaceInterface extends IOUSBInterfaceStruct942 { + +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct942.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct942.java new file mode 100644 index 00000000..26284e6f --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct942.java @@ -0,0 +1,3596 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +public class IOUSBInterfaceStruct942 { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_POINTER$LAYOUT.withName("_reserved"), + Constants$root.C_POINTER$LAYOUT.withName("QueryInterface"), + Constants$root.C_POINTER$LAYOUT.withName("AddRef"), + Constants$root.C_POINTER$LAYOUT.withName("Release"), + Constants$root.C_POINTER$LAYOUT.withName("CreateInterfaceAsyncEventSource"), + Constants$root.C_POINTER$LAYOUT.withName("GetInterfaceAsyncEventSource"), + Constants$root.C_POINTER$LAYOUT.withName("CreateInterfaceAsyncPort"), + Constants$root.C_POINTER$LAYOUT.withName("GetInterfaceAsyncPort"), + Constants$root.C_POINTER$LAYOUT.withName("USBInterfaceOpen"), + Constants$root.C_POINTER$LAYOUT.withName("USBInterfaceClose"), + Constants$root.C_POINTER$LAYOUT.withName("GetInterfaceClass"), + Constants$root.C_POINTER$LAYOUT.withName("GetInterfaceSubClass"), + Constants$root.C_POINTER$LAYOUT.withName("GetInterfaceProtocol"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceVendor"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceProduct"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceReleaseNumber"), + Constants$root.C_POINTER$LAYOUT.withName("GetConfigurationValue"), + Constants$root.C_POINTER$LAYOUT.withName("GetInterfaceNumber"), + Constants$root.C_POINTER$LAYOUT.withName("GetAlternateSetting"), + Constants$root.C_POINTER$LAYOUT.withName("GetNumEndpoints"), + Constants$root.C_POINTER$LAYOUT.withName("GetLocationID"), + Constants$root.C_POINTER$LAYOUT.withName("GetDevice"), + Constants$root.C_POINTER$LAYOUT.withName("SetAlternateInterface"), + Constants$root.C_POINTER$LAYOUT.withName("GetBusFrameNumber"), + Constants$root.C_POINTER$LAYOUT.withName("ControlRequest"), + Constants$root.C_POINTER$LAYOUT.withName("ControlRequestAsync"), + Constants$root.C_POINTER$LAYOUT.withName("GetPipeProperties"), + Constants$root.C_POINTER$LAYOUT.withName("GetPipeStatus"), + Constants$root.C_POINTER$LAYOUT.withName("AbortPipe"), + Constants$root.C_POINTER$LAYOUT.withName("ResetPipe"), + Constants$root.C_POINTER$LAYOUT.withName("ClearPipeStall"), + Constants$root.C_POINTER$LAYOUT.withName("ReadPipe"), + Constants$root.C_POINTER$LAYOUT.withName("WritePipe"), + Constants$root.C_POINTER$LAYOUT.withName("ReadPipeAsync"), + Constants$root.C_POINTER$LAYOUT.withName("WritePipeAsync"), + Constants$root.C_POINTER$LAYOUT.withName("ReadIsochPipeAsync"), + Constants$root.C_POINTER$LAYOUT.withName("WriteIsochPipeAsync"), + Constants$root.C_POINTER$LAYOUT.withName("ControlRequestTO"), + Constants$root.C_POINTER$LAYOUT.withName("ControlRequestAsyncTO"), + Constants$root.C_POINTER$LAYOUT.withName("ReadPipeTO"), + Constants$root.C_POINTER$LAYOUT.withName("WritePipeTO"), + Constants$root.C_POINTER$LAYOUT.withName("ReadPipeAsyncTO"), + Constants$root.C_POINTER$LAYOUT.withName("WritePipeAsyncTO"), + Constants$root.C_POINTER$LAYOUT.withName("USBInterfaceGetStringIndex"), + Constants$root.C_POINTER$LAYOUT.withName("USBInterfaceOpenSeize"), + Constants$root.C_POINTER$LAYOUT.withName("ClearPipeStallBothEnds"), + Constants$root.C_POINTER$LAYOUT.withName("SetPipePolicy"), + Constants$root.C_POINTER$LAYOUT.withName("GetBandwidthAvailable"), + Constants$root.C_POINTER$LAYOUT.withName("GetEndpointProperties"), + Constants$root.C_POINTER$LAYOUT.withName("LowLatencyReadIsochPipeAsync"), + Constants$root.C_POINTER$LAYOUT.withName("LowLatencyWriteIsochPipeAsync"), + Constants$root.C_POINTER$LAYOUT.withName("LowLatencyCreateBuffer"), + Constants$root.C_POINTER$LAYOUT.withName("LowLatencyDestroyBuffer"), + Constants$root.C_POINTER$LAYOUT.withName("GetBusMicroFrameNumber"), + Constants$root.C_POINTER$LAYOUT.withName("GetFrameListTime"), + Constants$root.C_POINTER$LAYOUT.withName("GetIOUSBLibVersion"), + Constants$root.C_POINTER$LAYOUT.withName("FindNextAssociatedDescriptor"), + Constants$root.C_POINTER$LAYOUT.withName("FindNextAltInterface"), + Constants$root.C_POINTER$LAYOUT.withName("GetBusFrameNumberWithTime"), + Constants$root.C_POINTER$LAYOUT.withName("GetPipePropertiesV2"), + Constants$root.C_POINTER$LAYOUT.withName("GetPipePropertiesV3"), + Constants$root.C_POINTER$LAYOUT.withName("GetEndpointPropertiesV3"), + Constants$root.C_POINTER$LAYOUT.withName("SupportsStreams"), + Constants$root.C_POINTER$LAYOUT.withName("CreateStreams"), + Constants$root.C_POINTER$LAYOUT.withName("GetConfiguredStreams"), + Constants$root.C_POINTER$LAYOUT.withName("ReadStreamsPipeTO"), + Constants$root.C_POINTER$LAYOUT.withName("WriteStreamsPipeTO"), + Constants$root.C_POINTER$LAYOUT.withName("ReadStreamsPipeAsyncTO"), + Constants$root.C_POINTER$LAYOUT.withName("WriteStreamsPipeAsyncTO"), + Constants$root.C_POINTER$LAYOUT.withName("AbortStreamsPipe"), + Constants$root.C_POINTER$LAYOUT.withName("RegisterForNotification"), + Constants$root.C_POINTER$LAYOUT.withName("UnregisterNotification"), + Constants$root.C_POINTER$LAYOUT.withName("AcknowledgeNotification"), + Constants$root.C_POINTER$LAYOUT.withName("RegisterDriver"), + Constants$root.C_POINTER$LAYOUT.withName("SetDeviceIdlePolicy"), + Constants$root.C_POINTER$LAYOUT.withName("SetPipeIdlePolicy"), + Constants$root.C_POINTER$LAYOUT.withName("GetInterfaceAsyncNotificationPort") + ).withName("IOUSBInterfaceStruct942"); + public static MemoryLayout $LAYOUT() { + return IOUSBInterfaceStruct942.$struct$LAYOUT; + } + static final VarHandle _reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("_reserved")); + public static VarHandle _reserved$VH() { + return IOUSBInterfaceStruct942._reserved$VH; + } + public static MemoryAddress _reserved$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942._reserved$VH.get(seg); + } + public static void _reserved$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942._reserved$VH.set(seg, x); + } + public static MemoryAddress _reserved$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942._reserved$VH.get(seg.asSlice(index*sizeof())); + } + public static void _reserved$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942._reserved$VH.set(seg.asSlice(index*sizeof()), x); + } + static final FunctionDescriptor QueryInterface$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("byte0"), + Constants$root.C_CHAR$LAYOUT.withName("byte1"), + Constants$root.C_CHAR$LAYOUT.withName("byte2"), + Constants$root.C_CHAR$LAYOUT.withName("byte3"), + Constants$root.C_CHAR$LAYOUT.withName("byte4"), + Constants$root.C_CHAR$LAYOUT.withName("byte5"), + Constants$root.C_CHAR$LAYOUT.withName("byte6"), + Constants$root.C_CHAR$LAYOUT.withName("byte7"), + Constants$root.C_CHAR$LAYOUT.withName("byte8"), + Constants$root.C_CHAR$LAYOUT.withName("byte9"), + Constants$root.C_CHAR$LAYOUT.withName("byte10"), + Constants$root.C_CHAR$LAYOUT.withName("byte11"), + Constants$root.C_CHAR$LAYOUT.withName("byte12"), + Constants$root.C_CHAR$LAYOUT.withName("byte13"), + Constants$root.C_CHAR$LAYOUT.withName("byte14"), + Constants$root.C_CHAR$LAYOUT.withName("byte15") + ), + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle QueryInterface$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.QueryInterface$FUNC + ); + public interface QueryInterface { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(QueryInterface fi, MemorySession session) { + return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOUSBInterfaceStruct942.QueryInterface$FUNC, session); + } + static QueryInterface ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBInterfaceStruct942.QueryInterface$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle QueryInterface$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("QueryInterface")); + public static VarHandle QueryInterface$VH() { + return IOUSBInterfaceStruct942.QueryInterface$VH; + } + public static MemoryAddress QueryInterface$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.QueryInterface$VH.get(seg); + } + public static void QueryInterface$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.QueryInterface$VH.set(seg, x); + } + public static MemoryAddress QueryInterface$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.QueryInterface$VH.get(seg.asSlice(index*sizeof())); + } + public static void QueryInterface$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.QueryInterface$VH.set(seg.asSlice(index*sizeof()), x); + } + public static QueryInterface QueryInterface (MemorySegment segment, MemorySession session) { + return QueryInterface.ofAddress(QueryInterface$get(segment), session); + } + static final FunctionDescriptor AddRef$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle AddRef$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.AddRef$FUNC + ); + public interface AddRef { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(AddRef fi, MemorySession session) { + return RuntimeHelper.upcallStub(AddRef.class, fi, IOUSBInterfaceStruct942.AddRef$FUNC, session); + } + static AddRef ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBInterfaceStruct942.AddRef$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle AddRef$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AddRef")); + public static VarHandle AddRef$VH() { + return IOUSBInterfaceStruct942.AddRef$VH; + } + public static MemoryAddress AddRef$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.AddRef$VH.get(seg); + } + public static void AddRef$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.AddRef$VH.set(seg, x); + } + public static MemoryAddress AddRef$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.AddRef$VH.get(seg.asSlice(index*sizeof())); + } + public static void AddRef$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.AddRef$VH.set(seg.asSlice(index*sizeof()), x); + } + public static AddRef AddRef (MemorySegment segment, MemorySession session) { + return AddRef.ofAddress(AddRef$get(segment), session); + } + static final FunctionDescriptor Release$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle Release$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.Release$FUNC + ); + public interface Release { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(Release fi, MemorySession session) { + return RuntimeHelper.upcallStub(Release.class, fi, IOUSBInterfaceStruct942.Release$FUNC, session); + } + static Release ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBInterfaceStruct942.Release$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle Release$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Release")); + public static VarHandle Release$VH() { + return IOUSBInterfaceStruct942.Release$VH; + } + public static MemoryAddress Release$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.Release$VH.get(seg); + } + public static void Release$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.Release$VH.set(seg, x); + } + public static MemoryAddress Release$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.Release$VH.get(seg.asSlice(index*sizeof())); + } + public static void Release$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.Release$VH.set(seg.asSlice(index*sizeof()), x); + } + public static Release Release (MemorySegment segment, MemorySession session) { + return Release.ofAddress(Release$get(segment), session); + } + static final FunctionDescriptor CreateInterfaceAsyncEventSource$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CreateInterfaceAsyncEventSource$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.CreateInterfaceAsyncEventSource$FUNC + ); + public interface CreateInterfaceAsyncEventSource { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(CreateInterfaceAsyncEventSource fi, MemorySession session) { + return RuntimeHelper.upcallStub(CreateInterfaceAsyncEventSource.class, fi, IOUSBInterfaceStruct942.CreateInterfaceAsyncEventSource$FUNC, session); + } + static CreateInterfaceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.CreateInterfaceAsyncEventSource$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle CreateInterfaceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceAsyncEventSource")); + public static VarHandle CreateInterfaceAsyncEventSource$VH() { + return IOUSBInterfaceStruct942.CreateInterfaceAsyncEventSource$VH; + } + public static MemoryAddress CreateInterfaceAsyncEventSource$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.CreateInterfaceAsyncEventSource$VH.get(seg); + } + public static void CreateInterfaceAsyncEventSource$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.CreateInterfaceAsyncEventSource$VH.set(seg, x); + } + public static MemoryAddress CreateInterfaceAsyncEventSource$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.CreateInterfaceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + } + public static void CreateInterfaceAsyncEventSource$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.CreateInterfaceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); + } + public static CreateInterfaceAsyncEventSource CreateInterfaceAsyncEventSource (MemorySegment segment, MemorySession session) { + return CreateInterfaceAsyncEventSource.ofAddress(CreateInterfaceAsyncEventSource$get(segment), session); + } + static final FunctionDescriptor GetInterfaceAsyncEventSource$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetInterfaceAsyncEventSource$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetInterfaceAsyncEventSource$FUNC + ); + public interface GetInterfaceAsyncEventSource { + + java.lang.foreign.Addressable apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(GetInterfaceAsyncEventSource fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetInterfaceAsyncEventSource.class, fi, IOUSBInterfaceStruct942.GetInterfaceAsyncEventSource$FUNC, session); + } + static GetInterfaceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (java.lang.foreign.Addressable)(java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceAsyncEventSource$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetInterfaceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceAsyncEventSource")); + public static VarHandle GetInterfaceAsyncEventSource$VH() { + return IOUSBInterfaceStruct942.GetInterfaceAsyncEventSource$VH; + } + public static MemoryAddress GetInterfaceAsyncEventSource$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceAsyncEventSource$VH.get(seg); + } + public static void GetInterfaceAsyncEventSource$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetInterfaceAsyncEventSource$VH.set(seg, x); + } + public static MemoryAddress GetInterfaceAsyncEventSource$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetInterfaceAsyncEventSource$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetInterfaceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetInterfaceAsyncEventSource GetInterfaceAsyncEventSource (MemorySegment segment, MemorySession session) { + return GetInterfaceAsyncEventSource.ofAddress(GetInterfaceAsyncEventSource$get(segment), session); + } + static final FunctionDescriptor CreateInterfaceAsyncPort$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CreateInterfaceAsyncPort$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.CreateInterfaceAsyncPort$FUNC + ); + public interface CreateInterfaceAsyncPort { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(CreateInterfaceAsyncPort fi, MemorySession session) { + return RuntimeHelper.upcallStub(CreateInterfaceAsyncPort.class, fi, IOUSBInterfaceStruct942.CreateInterfaceAsyncPort$FUNC, session); + } + static CreateInterfaceAsyncPort ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.CreateInterfaceAsyncPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle CreateInterfaceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceAsyncPort")); + public static VarHandle CreateInterfaceAsyncPort$VH() { + return IOUSBInterfaceStruct942.CreateInterfaceAsyncPort$VH; + } + public static MemoryAddress CreateInterfaceAsyncPort$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.CreateInterfaceAsyncPort$VH.get(seg); + } + public static void CreateInterfaceAsyncPort$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.CreateInterfaceAsyncPort$VH.set(seg, x); + } + public static MemoryAddress CreateInterfaceAsyncPort$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.CreateInterfaceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + } + public static void CreateInterfaceAsyncPort$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.CreateInterfaceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); + } + public static CreateInterfaceAsyncPort CreateInterfaceAsyncPort (MemorySegment segment, MemorySession session) { + return CreateInterfaceAsyncPort.ofAddress(CreateInterfaceAsyncPort$get(segment), session); + } + static final FunctionDescriptor GetInterfaceAsyncPort$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetInterfaceAsyncPort$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetInterfaceAsyncPort$FUNC + ); + public interface GetInterfaceAsyncPort { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(GetInterfaceAsyncPort fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetInterfaceAsyncPort.class, fi, IOUSBInterfaceStruct942.GetInterfaceAsyncPort$FUNC, session); + } + static GetInterfaceAsyncPort ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBInterfaceStruct942.GetInterfaceAsyncPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetInterfaceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceAsyncPort")); + public static VarHandle GetInterfaceAsyncPort$VH() { + return IOUSBInterfaceStruct942.GetInterfaceAsyncPort$VH; + } + public static MemoryAddress GetInterfaceAsyncPort$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceAsyncPort$VH.get(seg); + } + public static void GetInterfaceAsyncPort$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetInterfaceAsyncPort$VH.set(seg, x); + } + public static MemoryAddress GetInterfaceAsyncPort$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetInterfaceAsyncPort$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetInterfaceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetInterfaceAsyncPort GetInterfaceAsyncPort (MemorySegment segment, MemorySession session) { + return GetInterfaceAsyncPort.ofAddress(GetInterfaceAsyncPort$get(segment), session); + } + static final FunctionDescriptor USBInterfaceOpen$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBInterfaceOpen$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.USBInterfaceOpen$FUNC + ); + public interface USBInterfaceOpen { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(USBInterfaceOpen fi, MemorySession session) { + return RuntimeHelper.upcallStub(USBInterfaceOpen.class, fi, IOUSBInterfaceStruct942.USBInterfaceOpen$FUNC, session); + } + static USBInterfaceOpen ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBInterfaceStruct942.USBInterfaceOpen$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBInterfaceOpen$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceOpen")); + public static VarHandle USBInterfaceOpen$VH() { + return IOUSBInterfaceStruct942.USBInterfaceOpen$VH; + } + public static MemoryAddress USBInterfaceOpen$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.USBInterfaceOpen$VH.get(seg); + } + public static void USBInterfaceOpen$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.USBInterfaceOpen$VH.set(seg, x); + } + public static MemoryAddress USBInterfaceOpen$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.USBInterfaceOpen$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBInterfaceOpen$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.USBInterfaceOpen$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBInterfaceOpen USBInterfaceOpen (MemorySegment segment, MemorySession session) { + return USBInterfaceOpen.ofAddress(USBInterfaceOpen$get(segment), session); + } + static final FunctionDescriptor USBInterfaceClose$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBInterfaceClose$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.USBInterfaceClose$FUNC + ); + public interface USBInterfaceClose { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(USBInterfaceClose fi, MemorySession session) { + return RuntimeHelper.upcallStub(USBInterfaceClose.class, fi, IOUSBInterfaceStruct942.USBInterfaceClose$FUNC, session); + } + static USBInterfaceClose ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBInterfaceStruct942.USBInterfaceClose$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBInterfaceClose$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceClose")); + public static VarHandle USBInterfaceClose$VH() { + return IOUSBInterfaceStruct942.USBInterfaceClose$VH; + } + public static MemoryAddress USBInterfaceClose$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.USBInterfaceClose$VH.get(seg); + } + public static void USBInterfaceClose$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.USBInterfaceClose$VH.set(seg, x); + } + public static MemoryAddress USBInterfaceClose$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.USBInterfaceClose$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBInterfaceClose$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.USBInterfaceClose$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBInterfaceClose USBInterfaceClose (MemorySegment segment, MemorySession session) { + return USBInterfaceClose.ofAddress(USBInterfaceClose$get(segment), session); + } + static final FunctionDescriptor GetInterfaceClass$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetInterfaceClass$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetInterfaceClass$FUNC + ); + public interface GetInterfaceClass { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetInterfaceClass fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetInterfaceClass.class, fi, IOUSBInterfaceStruct942.GetInterfaceClass$FUNC, session); + } + static GetInterfaceClass ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.GetInterfaceClass$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetInterfaceClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceClass")); + public static VarHandle GetInterfaceClass$VH() { + return IOUSBInterfaceStruct942.GetInterfaceClass$VH; + } + public static MemoryAddress GetInterfaceClass$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceClass$VH.get(seg); + } + public static void GetInterfaceClass$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetInterfaceClass$VH.set(seg, x); + } + public static MemoryAddress GetInterfaceClass$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceClass$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetInterfaceClass$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetInterfaceClass$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetInterfaceClass GetInterfaceClass (MemorySegment segment, MemorySession session) { + return GetInterfaceClass.ofAddress(GetInterfaceClass$get(segment), session); + } + static final FunctionDescriptor GetInterfaceSubClass$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetInterfaceSubClass$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetInterfaceSubClass$FUNC + ); + public interface GetInterfaceSubClass { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetInterfaceSubClass fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetInterfaceSubClass.class, fi, IOUSBInterfaceStruct942.GetInterfaceSubClass$FUNC, session); + } + static GetInterfaceSubClass ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.GetInterfaceSubClass$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetInterfaceSubClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceSubClass")); + public static VarHandle GetInterfaceSubClass$VH() { + return IOUSBInterfaceStruct942.GetInterfaceSubClass$VH; + } + public static MemoryAddress GetInterfaceSubClass$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceSubClass$VH.get(seg); + } + public static void GetInterfaceSubClass$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetInterfaceSubClass$VH.set(seg, x); + } + public static MemoryAddress GetInterfaceSubClass$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceSubClass$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetInterfaceSubClass$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetInterfaceSubClass$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetInterfaceSubClass GetInterfaceSubClass (MemorySegment segment, MemorySession session) { + return GetInterfaceSubClass.ofAddress(GetInterfaceSubClass$get(segment), session); + } + static final FunctionDescriptor GetInterfaceProtocol$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetInterfaceProtocol$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetInterfaceProtocol$FUNC + ); + public interface GetInterfaceProtocol { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetInterfaceProtocol fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetInterfaceProtocol.class, fi, IOUSBInterfaceStruct942.GetInterfaceProtocol$FUNC, session); + } + static GetInterfaceProtocol ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.GetInterfaceProtocol$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetInterfaceProtocol$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceProtocol")); + public static VarHandle GetInterfaceProtocol$VH() { + return IOUSBInterfaceStruct942.GetInterfaceProtocol$VH; + } + public static MemoryAddress GetInterfaceProtocol$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceProtocol$VH.get(seg); + } + public static void GetInterfaceProtocol$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetInterfaceProtocol$VH.set(seg, x); + } + public static MemoryAddress GetInterfaceProtocol$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceProtocol$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetInterfaceProtocol$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetInterfaceProtocol$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetInterfaceProtocol GetInterfaceProtocol (MemorySegment segment, MemorySession session) { + return GetInterfaceProtocol.ofAddress(GetInterfaceProtocol$get(segment), session); + } + static final FunctionDescriptor GetDeviceVendor$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceVendor$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetDeviceVendor$FUNC + ); + public interface GetDeviceVendor { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceVendor fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceVendor.class, fi, IOUSBInterfaceStruct942.GetDeviceVendor$FUNC, session); + } + static GetDeviceVendor ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.GetDeviceVendor$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceVendor$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceVendor")); + public static VarHandle GetDeviceVendor$VH() { + return IOUSBInterfaceStruct942.GetDeviceVendor$VH; + } + public static MemoryAddress GetDeviceVendor$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetDeviceVendor$VH.get(seg); + } + public static void GetDeviceVendor$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetDeviceVendor$VH.set(seg, x); + } + public static MemoryAddress GetDeviceVendor$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetDeviceVendor$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceVendor$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetDeviceVendor$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceVendor GetDeviceVendor (MemorySegment segment, MemorySession session) { + return GetDeviceVendor.ofAddress(GetDeviceVendor$get(segment), session); + } + static final FunctionDescriptor GetDeviceProduct$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceProduct$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetDeviceProduct$FUNC + ); + public interface GetDeviceProduct { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceProduct fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceProduct.class, fi, IOUSBInterfaceStruct942.GetDeviceProduct$FUNC, session); + } + static GetDeviceProduct ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.GetDeviceProduct$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceProduct$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProduct")); + public static VarHandle GetDeviceProduct$VH() { + return IOUSBInterfaceStruct942.GetDeviceProduct$VH; + } + public static MemoryAddress GetDeviceProduct$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetDeviceProduct$VH.get(seg); + } + public static void GetDeviceProduct$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetDeviceProduct$VH.set(seg, x); + } + public static MemoryAddress GetDeviceProduct$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetDeviceProduct$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceProduct$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetDeviceProduct$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceProduct GetDeviceProduct (MemorySegment segment, MemorySession session) { + return GetDeviceProduct.ofAddress(GetDeviceProduct$get(segment), session); + } + static final FunctionDescriptor GetDeviceReleaseNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceReleaseNumber$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetDeviceReleaseNumber$FUNC + ); + public interface GetDeviceReleaseNumber { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceReleaseNumber fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceReleaseNumber.class, fi, IOUSBInterfaceStruct942.GetDeviceReleaseNumber$FUNC, session); + } + static GetDeviceReleaseNumber ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.GetDeviceReleaseNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceReleaseNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceReleaseNumber")); + public static VarHandle GetDeviceReleaseNumber$VH() { + return IOUSBInterfaceStruct942.GetDeviceReleaseNumber$VH; + } + public static MemoryAddress GetDeviceReleaseNumber$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetDeviceReleaseNumber$VH.get(seg); + } + public static void GetDeviceReleaseNumber$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetDeviceReleaseNumber$VH.set(seg, x); + } + public static MemoryAddress GetDeviceReleaseNumber$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetDeviceReleaseNumber$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceReleaseNumber$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetDeviceReleaseNumber$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceReleaseNumber GetDeviceReleaseNumber (MemorySegment segment, MemorySession session) { + return GetDeviceReleaseNumber.ofAddress(GetDeviceReleaseNumber$get(segment), session); + } + static final FunctionDescriptor GetConfigurationValue$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetConfigurationValue$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetConfigurationValue$FUNC + ); + public interface GetConfigurationValue { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetConfigurationValue fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetConfigurationValue.class, fi, IOUSBInterfaceStruct942.GetConfigurationValue$FUNC, session); + } + static GetConfigurationValue ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.GetConfigurationValue$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetConfigurationValue$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetConfigurationValue")); + public static VarHandle GetConfigurationValue$VH() { + return IOUSBInterfaceStruct942.GetConfigurationValue$VH; + } + public static MemoryAddress GetConfigurationValue$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetConfigurationValue$VH.get(seg); + } + public static void GetConfigurationValue$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetConfigurationValue$VH.set(seg, x); + } + public static MemoryAddress GetConfigurationValue$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetConfigurationValue$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetConfigurationValue$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetConfigurationValue$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetConfigurationValue GetConfigurationValue (MemorySegment segment, MemorySession session) { + return GetConfigurationValue.ofAddress(GetConfigurationValue$get(segment), session); + } + static final FunctionDescriptor GetInterfaceNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetInterfaceNumber$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetInterfaceNumber$FUNC + ); + public interface GetInterfaceNumber { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetInterfaceNumber fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetInterfaceNumber.class, fi, IOUSBInterfaceStruct942.GetInterfaceNumber$FUNC, session); + } + static GetInterfaceNumber ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.GetInterfaceNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetInterfaceNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceNumber")); + public static VarHandle GetInterfaceNumber$VH() { + return IOUSBInterfaceStruct942.GetInterfaceNumber$VH; + } + public static MemoryAddress GetInterfaceNumber$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceNumber$VH.get(seg); + } + public static void GetInterfaceNumber$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetInterfaceNumber$VH.set(seg, x); + } + public static MemoryAddress GetInterfaceNumber$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceNumber$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetInterfaceNumber$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetInterfaceNumber$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetInterfaceNumber GetInterfaceNumber (MemorySegment segment, MemorySession session) { + return GetInterfaceNumber.ofAddress(GetInterfaceNumber$get(segment), session); + } + static final FunctionDescriptor GetAlternateSetting$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetAlternateSetting$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetAlternateSetting$FUNC + ); + public interface GetAlternateSetting { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetAlternateSetting fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetAlternateSetting.class, fi, IOUSBInterfaceStruct942.GetAlternateSetting$FUNC, session); + } + static GetAlternateSetting ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.GetAlternateSetting$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetAlternateSetting$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetAlternateSetting")); + public static VarHandle GetAlternateSetting$VH() { + return IOUSBInterfaceStruct942.GetAlternateSetting$VH; + } + public static MemoryAddress GetAlternateSetting$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetAlternateSetting$VH.get(seg); + } + public static void GetAlternateSetting$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetAlternateSetting$VH.set(seg, x); + } + public static MemoryAddress GetAlternateSetting$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetAlternateSetting$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetAlternateSetting$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetAlternateSetting$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetAlternateSetting GetAlternateSetting (MemorySegment segment, MemorySession session) { + return GetAlternateSetting.ofAddress(GetAlternateSetting$get(segment), session); + } + static final FunctionDescriptor GetNumEndpoints$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetNumEndpoints$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetNumEndpoints$FUNC + ); + public interface GetNumEndpoints { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetNumEndpoints fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetNumEndpoints.class, fi, IOUSBInterfaceStruct942.GetNumEndpoints$FUNC, session); + } + static GetNumEndpoints ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.GetNumEndpoints$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetNumEndpoints$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetNumEndpoints")); + public static VarHandle GetNumEndpoints$VH() { + return IOUSBInterfaceStruct942.GetNumEndpoints$VH; + } + public static MemoryAddress GetNumEndpoints$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetNumEndpoints$VH.get(seg); + } + public static void GetNumEndpoints$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetNumEndpoints$VH.set(seg, x); + } + public static MemoryAddress GetNumEndpoints$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetNumEndpoints$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetNumEndpoints$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetNumEndpoints$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetNumEndpoints GetNumEndpoints (MemorySegment segment, MemorySession session) { + return GetNumEndpoints.ofAddress(GetNumEndpoints$get(segment), session); + } + static final FunctionDescriptor GetLocationID$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetLocationID$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetLocationID$FUNC + ); + public interface GetLocationID { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetLocationID fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetLocationID.class, fi, IOUSBInterfaceStruct942.GetLocationID$FUNC, session); + } + static GetLocationID ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.GetLocationID$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetLocationID$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetLocationID")); + public static VarHandle GetLocationID$VH() { + return IOUSBInterfaceStruct942.GetLocationID$VH; + } + public static MemoryAddress GetLocationID$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetLocationID$VH.get(seg); + } + public static void GetLocationID$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetLocationID$VH.set(seg, x); + } + public static MemoryAddress GetLocationID$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetLocationID$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetLocationID$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetLocationID$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetLocationID GetLocationID (MemorySegment segment, MemorySession session) { + return GetLocationID.ofAddress(GetLocationID$get(segment), session); + } + static final FunctionDescriptor GetDevice$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDevice$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetDevice$FUNC + ); + public interface GetDevice { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDevice fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDevice.class, fi, IOUSBInterfaceStruct942.GetDevice$FUNC, session); + } + static GetDevice ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.GetDevice$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDevice$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDevice")); + public static VarHandle GetDevice$VH() { + return IOUSBInterfaceStruct942.GetDevice$VH; + } + public static MemoryAddress GetDevice$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetDevice$VH.get(seg); + } + public static void GetDevice$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetDevice$VH.set(seg, x); + } + public static MemoryAddress GetDevice$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetDevice$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDevice$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetDevice$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDevice GetDevice (MemorySegment segment, MemorySession session) { + return GetDevice.ofAddress(GetDevice$get(segment), session); + } + static final FunctionDescriptor SetAlternateInterface$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT + ); + static final MethodHandle SetAlternateInterface$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.SetAlternateInterface$FUNC + ); + public interface SetAlternateInterface { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); + static MemorySegment allocate(SetAlternateInterface fi, MemorySession session) { + return RuntimeHelper.upcallStub(SetAlternateInterface.class, fi, IOUSBInterfaceStruct942.SetAlternateInterface$FUNC, session); + } + static SetAlternateInterface ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.SetAlternateInterface$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle SetAlternateInterface$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetAlternateInterface")); + public static VarHandle SetAlternateInterface$VH() { + return IOUSBInterfaceStruct942.SetAlternateInterface$VH; + } + public static MemoryAddress SetAlternateInterface$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SetAlternateInterface$VH.get(seg); + } + public static void SetAlternateInterface$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.SetAlternateInterface$VH.set(seg, x); + } + public static MemoryAddress SetAlternateInterface$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SetAlternateInterface$VH.get(seg.asSlice(index*sizeof())); + } + public static void SetAlternateInterface$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.SetAlternateInterface$VH.set(seg.asSlice(index*sizeof()), x); + } + public static SetAlternateInterface SetAlternateInterface (MemorySegment segment, MemorySession session) { + return SetAlternateInterface.ofAddress(SetAlternateInterface$get(segment), session); + } + static final FunctionDescriptor GetBusFrameNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetBusFrameNumber$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetBusFrameNumber$FUNC + ); + public interface GetBusFrameNumber { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(GetBusFrameNumber fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetBusFrameNumber.class, fi, IOUSBInterfaceStruct942.GetBusFrameNumber$FUNC, session); + } + static GetBusFrameNumber ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBInterfaceStruct942.GetBusFrameNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetBusFrameNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBusFrameNumber")); + public static VarHandle GetBusFrameNumber$VH() { + return IOUSBInterfaceStruct942.GetBusFrameNumber$VH; + } + public static MemoryAddress GetBusFrameNumber$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetBusFrameNumber$VH.get(seg); + } + public static void GetBusFrameNumber$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetBusFrameNumber$VH.set(seg, x); + } + public static MemoryAddress GetBusFrameNumber$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetBusFrameNumber$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetBusFrameNumber$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetBusFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetBusFrameNumber GetBusFrameNumber (MemorySegment segment, MemorySession session) { + return GetBusFrameNumber.ofAddress(GetBusFrameNumber$get(segment), session); + } + static final FunctionDescriptor ControlRequest$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle ControlRequest$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.ControlRequest$FUNC + ); + public interface ControlRequest { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(ControlRequest fi, MemorySession session) { + return RuntimeHelper.upcallStub(ControlRequest.class, fi, IOUSBInterfaceStruct942.ControlRequest$FUNC, session); + } + static ControlRequest ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBInterfaceStruct942.ControlRequest$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle ControlRequest$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ControlRequest")); + public static VarHandle ControlRequest$VH() { + return IOUSBInterfaceStruct942.ControlRequest$VH; + } + public static MemoryAddress ControlRequest$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ControlRequest$VH.get(seg); + } + public static void ControlRequest$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.ControlRequest$VH.set(seg, x); + } + public static MemoryAddress ControlRequest$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ControlRequest$VH.get(seg.asSlice(index*sizeof())); + } + public static void ControlRequest$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.ControlRequest$VH.set(seg.asSlice(index*sizeof()), x); + } + public static ControlRequest ControlRequest (MemorySegment segment, MemorySession session) { + return ControlRequest.ofAddress(ControlRequest$get(segment), session); + } + static final FunctionDescriptor ControlRequestAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle ControlRequestAsync$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.ControlRequestAsync$FUNC + ); + public interface ControlRequestAsync { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, java.lang.foreign.MemoryAddress _x4); + static MemorySegment allocate(ControlRequestAsync fi, MemorySession session) { + return RuntimeHelper.upcallStub(ControlRequestAsync.class, fi, IOUSBInterfaceStruct942.ControlRequestAsync$FUNC, session); + } + static ControlRequestAsync ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, java.lang.foreign.MemoryAddress __x4) -> { + try { + return (int)IOUSBInterfaceStruct942.ControlRequestAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle ControlRequestAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ControlRequestAsync")); + public static VarHandle ControlRequestAsync$VH() { + return IOUSBInterfaceStruct942.ControlRequestAsync$VH; + } + public static MemoryAddress ControlRequestAsync$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ControlRequestAsync$VH.get(seg); + } + public static void ControlRequestAsync$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.ControlRequestAsync$VH.set(seg, x); + } + public static MemoryAddress ControlRequestAsync$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ControlRequestAsync$VH.get(seg.asSlice(index*sizeof())); + } + public static void ControlRequestAsync$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.ControlRequestAsync$VH.set(seg.asSlice(index*sizeof()), x); + } + public static ControlRequestAsync ControlRequestAsync (MemorySegment segment, MemorySession session) { + return ControlRequestAsync.ofAddress(ControlRequestAsync$get(segment), session); + } + static final FunctionDescriptor GetPipeProperties$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetPipeProperties$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetPipeProperties$FUNC + ); + public interface GetPipeProperties { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, java.lang.foreign.MemoryAddress _x4, java.lang.foreign.MemoryAddress _x5, java.lang.foreign.MemoryAddress _x6); + static MemorySegment allocate(GetPipeProperties fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetPipeProperties.class, fi, IOUSBInterfaceStruct942.GetPipeProperties$FUNC, session); + } + static GetPipeProperties ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, java.lang.foreign.MemoryAddress __x4, java.lang.foreign.MemoryAddress __x5, java.lang.foreign.MemoryAddress __x6) -> { + try { + return (int)IOUSBInterfaceStruct942.GetPipeProperties$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetPipeProperties$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetPipeProperties")); + public static VarHandle GetPipeProperties$VH() { + return IOUSBInterfaceStruct942.GetPipeProperties$VH; + } + public static MemoryAddress GetPipeProperties$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetPipeProperties$VH.get(seg); + } + public static void GetPipeProperties$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetPipeProperties$VH.set(seg, x); + } + public static MemoryAddress GetPipeProperties$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetPipeProperties$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetPipeProperties$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetPipeProperties$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetPipeProperties GetPipeProperties (MemorySegment segment, MemorySession session) { + return GetPipeProperties.ofAddress(GetPipeProperties$get(segment), session); + } + static final FunctionDescriptor GetPipeStatus$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT + ); + static final MethodHandle GetPipeStatus$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetPipeStatus$FUNC + ); + public interface GetPipeStatus { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); + static MemorySegment allocate(GetPipeStatus fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetPipeStatus.class, fi, IOUSBInterfaceStruct942.GetPipeStatus$FUNC, session); + } + static GetPipeStatus ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.GetPipeStatus$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetPipeStatus$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetPipeStatus")); + public static VarHandle GetPipeStatus$VH() { + return IOUSBInterfaceStruct942.GetPipeStatus$VH; + } + public static MemoryAddress GetPipeStatus$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetPipeStatus$VH.get(seg); + } + public static void GetPipeStatus$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetPipeStatus$VH.set(seg, x); + } + public static MemoryAddress GetPipeStatus$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetPipeStatus$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetPipeStatus$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetPipeStatus$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetPipeStatus GetPipeStatus (MemorySegment segment, MemorySession session) { + return GetPipeStatus.ofAddress(GetPipeStatus$get(segment), session); + } + static final FunctionDescriptor AbortPipe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT + ); + static final MethodHandle AbortPipe$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.AbortPipe$FUNC + ); + public interface AbortPipe { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); + static MemorySegment allocate(AbortPipe fi, MemorySession session) { + return RuntimeHelper.upcallStub(AbortPipe.class, fi, IOUSBInterfaceStruct942.AbortPipe$FUNC, session); + } + static AbortPipe ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.AbortPipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle AbortPipe$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AbortPipe")); + public static VarHandle AbortPipe$VH() { + return IOUSBInterfaceStruct942.AbortPipe$VH; + } + public static MemoryAddress AbortPipe$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.AbortPipe$VH.get(seg); + } + public static void AbortPipe$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.AbortPipe$VH.set(seg, x); + } + public static MemoryAddress AbortPipe$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.AbortPipe$VH.get(seg.asSlice(index*sizeof())); + } + public static void AbortPipe$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.AbortPipe$VH.set(seg.asSlice(index*sizeof()), x); + } + public static AbortPipe AbortPipe (MemorySegment segment, MemorySession session) { + return AbortPipe.ofAddress(AbortPipe$get(segment), session); + } + static final FunctionDescriptor ResetPipe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT + ); + static final MethodHandle ResetPipe$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.ResetPipe$FUNC + ); + public interface ResetPipe { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); + static MemorySegment allocate(ResetPipe fi, MemorySession session) { + return RuntimeHelper.upcallStub(ResetPipe.class, fi, IOUSBInterfaceStruct942.ResetPipe$FUNC, session); + } + static ResetPipe ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.ResetPipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle ResetPipe$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ResetPipe")); + public static VarHandle ResetPipe$VH() { + return IOUSBInterfaceStruct942.ResetPipe$VH; + } + public static MemoryAddress ResetPipe$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ResetPipe$VH.get(seg); + } + public static void ResetPipe$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.ResetPipe$VH.set(seg, x); + } + public static MemoryAddress ResetPipe$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ResetPipe$VH.get(seg.asSlice(index*sizeof())); + } + public static void ResetPipe$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.ResetPipe$VH.set(seg.asSlice(index*sizeof()), x); + } + public static ResetPipe ResetPipe (MemorySegment segment, MemorySession session) { + return ResetPipe.ofAddress(ResetPipe$get(segment), session); + } + static final FunctionDescriptor ClearPipeStall$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT + ); + static final MethodHandle ClearPipeStall$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.ClearPipeStall$FUNC + ); + public interface ClearPipeStall { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); + static MemorySegment allocate(ClearPipeStall fi, MemorySession session) { + return RuntimeHelper.upcallStub(ClearPipeStall.class, fi, IOUSBInterfaceStruct942.ClearPipeStall$FUNC, session); + } + static ClearPipeStall ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.ClearPipeStall$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle ClearPipeStall$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ClearPipeStall")); + public static VarHandle ClearPipeStall$VH() { + return IOUSBInterfaceStruct942.ClearPipeStall$VH; + } + public static MemoryAddress ClearPipeStall$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ClearPipeStall$VH.get(seg); + } + public static void ClearPipeStall$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.ClearPipeStall$VH.set(seg, x); + } + public static MemoryAddress ClearPipeStall$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ClearPipeStall$VH.get(seg.asSlice(index*sizeof())); + } + public static void ClearPipeStall$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.ClearPipeStall$VH.set(seg.asSlice(index*sizeof()), x); + } + public static ClearPipeStall ClearPipeStall (MemorySegment segment, MemorySession session) { + return ClearPipeStall.ofAddress(ClearPipeStall$get(segment), session); + } + static final FunctionDescriptor ReadPipe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle ReadPipe$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.ReadPipe$FUNC + ); + public interface ReadPipe { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3); + static MemorySegment allocate(ReadPipe fi, MemorySession session) { + return RuntimeHelper.upcallStub(ReadPipe.class, fi, IOUSBInterfaceStruct942.ReadPipe$FUNC, session); + } + static ReadPipe ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3) -> { + try { + return (int)IOUSBInterfaceStruct942.ReadPipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle ReadPipe$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadPipe")); + public static VarHandle ReadPipe$VH() { + return IOUSBInterfaceStruct942.ReadPipe$VH; + } + public static MemoryAddress ReadPipe$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadPipe$VH.get(seg); + } + public static void ReadPipe$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.ReadPipe$VH.set(seg, x); + } + public static MemoryAddress ReadPipe$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadPipe$VH.get(seg.asSlice(index*sizeof())); + } + public static void ReadPipe$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.ReadPipe$VH.set(seg.asSlice(index*sizeof()), x); + } + public static ReadPipe ReadPipe (MemorySegment segment, MemorySession session) { + return ReadPipe.ofAddress(ReadPipe$get(segment), session); + } + static final FunctionDescriptor WritePipe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle WritePipe$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.WritePipe$FUNC + ); + public interface WritePipe { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3); + static MemorySegment allocate(WritePipe fi, MemorySession session) { + return RuntimeHelper.upcallStub(WritePipe.class, fi, IOUSBInterfaceStruct942.WritePipe$FUNC, session); + } + static WritePipe ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3) -> { + try { + return (int)IOUSBInterfaceStruct942.WritePipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle WritePipe$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WritePipe")); + public static VarHandle WritePipe$VH() { + return IOUSBInterfaceStruct942.WritePipe$VH; + } + public static MemoryAddress WritePipe$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WritePipe$VH.get(seg); + } + public static void WritePipe$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.WritePipe$VH.set(seg, x); + } + public static MemoryAddress WritePipe$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WritePipe$VH.get(seg.asSlice(index*sizeof())); + } + public static void WritePipe$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.WritePipe$VH.set(seg.asSlice(index*sizeof()), x); + } + public static WritePipe WritePipe (MemorySegment segment, MemorySession session) { + return WritePipe.ofAddress(WritePipe$get(segment), session); + } + static final FunctionDescriptor ReadPipeAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle ReadPipeAsync$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.ReadPipeAsync$FUNC + ); + public interface ReadPipeAsync { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3, java.lang.foreign.MemoryAddress _x4, java.lang.foreign.MemoryAddress _x5); + static MemorySegment allocate(ReadPipeAsync fi, MemorySession session) { + return RuntimeHelper.upcallStub(ReadPipeAsync.class, fi, IOUSBInterfaceStruct942.ReadPipeAsync$FUNC, session); + } + static ReadPipeAsync ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3, java.lang.foreign.MemoryAddress __x4, java.lang.foreign.MemoryAddress __x5) -> { + try { + return (int)IOUSBInterfaceStruct942.ReadPipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle ReadPipeAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadPipeAsync")); + public static VarHandle ReadPipeAsync$VH() { + return IOUSBInterfaceStruct942.ReadPipeAsync$VH; + } + public static MemoryAddress ReadPipeAsync$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadPipeAsync$VH.get(seg); + } + public static void ReadPipeAsync$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.ReadPipeAsync$VH.set(seg, x); + } + public static MemoryAddress ReadPipeAsync$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadPipeAsync$VH.get(seg.asSlice(index*sizeof())); + } + public static void ReadPipeAsync$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.ReadPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); + } + public static ReadPipeAsync ReadPipeAsync (MemorySegment segment, MemorySession session) { + return ReadPipeAsync.ofAddress(ReadPipeAsync$get(segment), session); + } + static final FunctionDescriptor WritePipeAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle WritePipeAsync$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.WritePipeAsync$FUNC + ); + public interface WritePipeAsync { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3, java.lang.foreign.MemoryAddress _x4, java.lang.foreign.MemoryAddress _x5); + static MemorySegment allocate(WritePipeAsync fi, MemorySession session) { + return RuntimeHelper.upcallStub(WritePipeAsync.class, fi, IOUSBInterfaceStruct942.WritePipeAsync$FUNC, session); + } + static WritePipeAsync ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3, java.lang.foreign.MemoryAddress __x4, java.lang.foreign.MemoryAddress __x5) -> { + try { + return (int)IOUSBInterfaceStruct942.WritePipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle WritePipeAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WritePipeAsync")); + public static VarHandle WritePipeAsync$VH() { + return IOUSBInterfaceStruct942.WritePipeAsync$VH; + } + public static MemoryAddress WritePipeAsync$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WritePipeAsync$VH.get(seg); + } + public static void WritePipeAsync$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.WritePipeAsync$VH.set(seg, x); + } + public static MemoryAddress WritePipeAsync$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WritePipeAsync$VH.get(seg.asSlice(index*sizeof())); + } + public static void WritePipeAsync$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.WritePipeAsync$VH.set(seg.asSlice(index*sizeof()), x); + } + public static WritePipeAsync WritePipeAsync (MemorySegment segment, MemorySession session) { + return WritePipeAsync.ofAddress(WritePipeAsync$get(segment), session); + } + static final FunctionDescriptor ReadIsochPipeAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle ReadIsochPipeAsync$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.ReadIsochPipeAsync$FUNC + ); + public interface ReadIsochPipeAsync { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, long _x3, int _x4, java.lang.foreign.MemoryAddress _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7); + static MemorySegment allocate(ReadIsochPipeAsync fi, MemorySession session) { + return RuntimeHelper.upcallStub(ReadIsochPipeAsync.class, fi, IOUSBInterfaceStruct942.ReadIsochPipeAsync$FUNC, session); + } + static ReadIsochPipeAsync ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, long __x3, int __x4, java.lang.foreign.MemoryAddress __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7) -> { + try { + return (int)IOUSBInterfaceStruct942.ReadIsochPipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle ReadIsochPipeAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadIsochPipeAsync")); + public static VarHandle ReadIsochPipeAsync$VH() { + return IOUSBInterfaceStruct942.ReadIsochPipeAsync$VH; + } + public static MemoryAddress ReadIsochPipeAsync$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadIsochPipeAsync$VH.get(seg); + } + public static void ReadIsochPipeAsync$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.ReadIsochPipeAsync$VH.set(seg, x); + } + public static MemoryAddress ReadIsochPipeAsync$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadIsochPipeAsync$VH.get(seg.asSlice(index*sizeof())); + } + public static void ReadIsochPipeAsync$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.ReadIsochPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); + } + public static ReadIsochPipeAsync ReadIsochPipeAsync (MemorySegment segment, MemorySession session) { + return ReadIsochPipeAsync.ofAddress(ReadIsochPipeAsync$get(segment), session); + } + static final FunctionDescriptor WriteIsochPipeAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle WriteIsochPipeAsync$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.WriteIsochPipeAsync$FUNC + ); + public interface WriteIsochPipeAsync { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, long _x3, int _x4, java.lang.foreign.MemoryAddress _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7); + static MemorySegment allocate(WriteIsochPipeAsync fi, MemorySession session) { + return RuntimeHelper.upcallStub(WriteIsochPipeAsync.class, fi, IOUSBInterfaceStruct942.WriteIsochPipeAsync$FUNC, session); + } + static WriteIsochPipeAsync ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, long __x3, int __x4, java.lang.foreign.MemoryAddress __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7) -> { + try { + return (int)IOUSBInterfaceStruct942.WriteIsochPipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle WriteIsochPipeAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WriteIsochPipeAsync")); + public static VarHandle WriteIsochPipeAsync$VH() { + return IOUSBInterfaceStruct942.WriteIsochPipeAsync$VH; + } + public static MemoryAddress WriteIsochPipeAsync$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WriteIsochPipeAsync$VH.get(seg); + } + public static void WriteIsochPipeAsync$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.WriteIsochPipeAsync$VH.set(seg, x); + } + public static MemoryAddress WriteIsochPipeAsync$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WriteIsochPipeAsync$VH.get(seg.asSlice(index*sizeof())); + } + public static void WriteIsochPipeAsync$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.WriteIsochPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); + } + public static WriteIsochPipeAsync WriteIsochPipeAsync (MemorySegment segment, MemorySession session) { + return WriteIsochPipeAsync.ofAddress(WriteIsochPipeAsync$get(segment), session); + } + static final FunctionDescriptor ControlRequestTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle ControlRequestTO$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.ControlRequestTO$FUNC + ); + public interface ControlRequestTO { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(ControlRequestTO fi, MemorySession session) { + return RuntimeHelper.upcallStub(ControlRequestTO.class, fi, IOUSBInterfaceStruct942.ControlRequestTO$FUNC, session); + } + static ControlRequestTO ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBInterfaceStruct942.ControlRequestTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle ControlRequestTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ControlRequestTO")); + public static VarHandle ControlRequestTO$VH() { + return IOUSBInterfaceStruct942.ControlRequestTO$VH; + } + public static MemoryAddress ControlRequestTO$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ControlRequestTO$VH.get(seg); + } + public static void ControlRequestTO$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.ControlRequestTO$VH.set(seg, x); + } + public static MemoryAddress ControlRequestTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ControlRequestTO$VH.get(seg.asSlice(index*sizeof())); + } + public static void ControlRequestTO$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.ControlRequestTO$VH.set(seg.asSlice(index*sizeof()), x); + } + public static ControlRequestTO ControlRequestTO (MemorySegment segment, MemorySession session) { + return ControlRequestTO.ofAddress(ControlRequestTO$get(segment), session); + } + static final FunctionDescriptor ControlRequestAsyncTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle ControlRequestAsyncTO$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.ControlRequestAsyncTO$FUNC + ); + public interface ControlRequestAsyncTO { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, java.lang.foreign.MemoryAddress _x4); + static MemorySegment allocate(ControlRequestAsyncTO fi, MemorySession session) { + return RuntimeHelper.upcallStub(ControlRequestAsyncTO.class, fi, IOUSBInterfaceStruct942.ControlRequestAsyncTO$FUNC, session); + } + static ControlRequestAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, java.lang.foreign.MemoryAddress __x4) -> { + try { + return (int)IOUSBInterfaceStruct942.ControlRequestAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle ControlRequestAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ControlRequestAsyncTO")); + public static VarHandle ControlRequestAsyncTO$VH() { + return IOUSBInterfaceStruct942.ControlRequestAsyncTO$VH; + } + public static MemoryAddress ControlRequestAsyncTO$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ControlRequestAsyncTO$VH.get(seg); + } + public static void ControlRequestAsyncTO$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.ControlRequestAsyncTO$VH.set(seg, x); + } + public static MemoryAddress ControlRequestAsyncTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ControlRequestAsyncTO$VH.get(seg.asSlice(index*sizeof())); + } + public static void ControlRequestAsyncTO$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.ControlRequestAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); + } + public static ControlRequestAsyncTO ControlRequestAsyncTO (MemorySegment segment, MemorySession session) { + return ControlRequestAsyncTO.ofAddress(ControlRequestAsyncTO$get(segment), session); + } + static final FunctionDescriptor ReadPipeTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle ReadPipeTO$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.ReadPipeTO$FUNC + ); + public interface ReadPipeTO { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, int _x4, int _x5); + static MemorySegment allocate(ReadPipeTO fi, MemorySession session) { + return RuntimeHelper.upcallStub(ReadPipeTO.class, fi, IOUSBInterfaceStruct942.ReadPipeTO$FUNC, session); + } + static ReadPipeTO ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, int __x4, int __x5) -> { + try { + return (int)IOUSBInterfaceStruct942.ReadPipeTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, __x4, __x5); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle ReadPipeTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadPipeTO")); + public static VarHandle ReadPipeTO$VH() { + return IOUSBInterfaceStruct942.ReadPipeTO$VH; + } + public static MemoryAddress ReadPipeTO$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadPipeTO$VH.get(seg); + } + public static void ReadPipeTO$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.ReadPipeTO$VH.set(seg, x); + } + public static MemoryAddress ReadPipeTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadPipeTO$VH.get(seg.asSlice(index*sizeof())); + } + public static void ReadPipeTO$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.ReadPipeTO$VH.set(seg.asSlice(index*sizeof()), x); + } + public static ReadPipeTO ReadPipeTO (MemorySegment segment, MemorySession session) { + return ReadPipeTO.ofAddress(ReadPipeTO$get(segment), session); + } + static final FunctionDescriptor WritePipeTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle WritePipeTO$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.WritePipeTO$FUNC + ); + public interface WritePipeTO { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3, int _x4, int _x5); + static MemorySegment allocate(WritePipeTO fi, MemorySession session) { + return RuntimeHelper.upcallStub(WritePipeTO.class, fi, IOUSBInterfaceStruct942.WritePipeTO$FUNC, session); + } + static WritePipeTO ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3, int __x4, int __x5) -> { + try { + return (int)IOUSBInterfaceStruct942.WritePipeTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, __x5); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle WritePipeTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WritePipeTO")); + public static VarHandle WritePipeTO$VH() { + return IOUSBInterfaceStruct942.WritePipeTO$VH; + } + public static MemoryAddress WritePipeTO$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WritePipeTO$VH.get(seg); + } + public static void WritePipeTO$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.WritePipeTO$VH.set(seg, x); + } + public static MemoryAddress WritePipeTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WritePipeTO$VH.get(seg.asSlice(index*sizeof())); + } + public static void WritePipeTO$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.WritePipeTO$VH.set(seg.asSlice(index*sizeof()), x); + } + public static WritePipeTO WritePipeTO (MemorySegment segment, MemorySession session) { + return WritePipeTO.ofAddress(WritePipeTO$get(segment), session); + } + static final FunctionDescriptor ReadPipeAsyncTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle ReadPipeAsyncTO$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.ReadPipeAsyncTO$FUNC + ); + public interface ReadPipeAsyncTO { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3, int _x4, int _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7); + static MemorySegment allocate(ReadPipeAsyncTO fi, MemorySession session) { + return RuntimeHelper.upcallStub(ReadPipeAsyncTO.class, fi, IOUSBInterfaceStruct942.ReadPipeAsyncTO$FUNC, session); + } + static ReadPipeAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3, int __x4, int __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7) -> { + try { + return (int)IOUSBInterfaceStruct942.ReadPipeAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, __x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle ReadPipeAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadPipeAsyncTO")); + public static VarHandle ReadPipeAsyncTO$VH() { + return IOUSBInterfaceStruct942.ReadPipeAsyncTO$VH; + } + public static MemoryAddress ReadPipeAsyncTO$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadPipeAsyncTO$VH.get(seg); + } + public static void ReadPipeAsyncTO$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.ReadPipeAsyncTO$VH.set(seg, x); + } + public static MemoryAddress ReadPipeAsyncTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadPipeAsyncTO$VH.get(seg.asSlice(index*sizeof())); + } + public static void ReadPipeAsyncTO$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.ReadPipeAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); + } + public static ReadPipeAsyncTO ReadPipeAsyncTO (MemorySegment segment, MemorySession session) { + return ReadPipeAsyncTO.ofAddress(ReadPipeAsyncTO$get(segment), session); + } + static final FunctionDescriptor WritePipeAsyncTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle WritePipeAsyncTO$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.WritePipeAsyncTO$FUNC + ); + public interface WritePipeAsyncTO { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3, int _x4, int _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7); + static MemorySegment allocate(WritePipeAsyncTO fi, MemorySession session) { + return RuntimeHelper.upcallStub(WritePipeAsyncTO.class, fi, IOUSBInterfaceStruct942.WritePipeAsyncTO$FUNC, session); + } + static WritePipeAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3, int __x4, int __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7) -> { + try { + return (int)IOUSBInterfaceStruct942.WritePipeAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, __x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle WritePipeAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WritePipeAsyncTO")); + public static VarHandle WritePipeAsyncTO$VH() { + return IOUSBInterfaceStruct942.WritePipeAsyncTO$VH; + } + public static MemoryAddress WritePipeAsyncTO$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WritePipeAsyncTO$VH.get(seg); + } + public static void WritePipeAsyncTO$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.WritePipeAsyncTO$VH.set(seg, x); + } + public static MemoryAddress WritePipeAsyncTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WritePipeAsyncTO$VH.get(seg.asSlice(index*sizeof())); + } + public static void WritePipeAsyncTO$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.WritePipeAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); + } + public static WritePipeAsyncTO WritePipeAsyncTO (MemorySegment segment, MemorySession session) { + return WritePipeAsyncTO.ofAddress(WritePipeAsyncTO$get(segment), session); + } + static final FunctionDescriptor USBInterfaceGetStringIndex$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBInterfaceGetStringIndex$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.USBInterfaceGetStringIndex$FUNC + ); + public interface USBInterfaceGetStringIndex { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(USBInterfaceGetStringIndex fi, MemorySession session) { + return RuntimeHelper.upcallStub(USBInterfaceGetStringIndex.class, fi, IOUSBInterfaceStruct942.USBInterfaceGetStringIndex$FUNC, session); + } + static USBInterfaceGetStringIndex ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.USBInterfaceGetStringIndex$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBInterfaceGetStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceGetStringIndex")); + public static VarHandle USBInterfaceGetStringIndex$VH() { + return IOUSBInterfaceStruct942.USBInterfaceGetStringIndex$VH; + } + public static MemoryAddress USBInterfaceGetStringIndex$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.USBInterfaceGetStringIndex$VH.get(seg); + } + public static void USBInterfaceGetStringIndex$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.USBInterfaceGetStringIndex$VH.set(seg, x); + } + public static MemoryAddress USBInterfaceGetStringIndex$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.USBInterfaceGetStringIndex$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBInterfaceGetStringIndex$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.USBInterfaceGetStringIndex$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBInterfaceGetStringIndex USBInterfaceGetStringIndex (MemorySegment segment, MemorySession session) { + return USBInterfaceGetStringIndex.ofAddress(USBInterfaceGetStringIndex$get(segment), session); + } + static final FunctionDescriptor USBInterfaceOpenSeize$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBInterfaceOpenSeize$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.USBInterfaceOpenSeize$FUNC + ); + public interface USBInterfaceOpenSeize { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(USBInterfaceOpenSeize fi, MemorySession session) { + return RuntimeHelper.upcallStub(USBInterfaceOpenSeize.class, fi, IOUSBInterfaceStruct942.USBInterfaceOpenSeize$FUNC, session); + } + static USBInterfaceOpenSeize ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBInterfaceStruct942.USBInterfaceOpenSeize$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBInterfaceOpenSeize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceOpenSeize")); + public static VarHandle USBInterfaceOpenSeize$VH() { + return IOUSBInterfaceStruct942.USBInterfaceOpenSeize$VH; + } + public static MemoryAddress USBInterfaceOpenSeize$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.USBInterfaceOpenSeize$VH.get(seg); + } + public static void USBInterfaceOpenSeize$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.USBInterfaceOpenSeize$VH.set(seg, x); + } + public static MemoryAddress USBInterfaceOpenSeize$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.USBInterfaceOpenSeize$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBInterfaceOpenSeize$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.USBInterfaceOpenSeize$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBInterfaceOpenSeize USBInterfaceOpenSeize (MemorySegment segment, MemorySession session) { + return USBInterfaceOpenSeize.ofAddress(USBInterfaceOpenSeize$get(segment), session); + } + static final FunctionDescriptor ClearPipeStallBothEnds$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT + ); + static final MethodHandle ClearPipeStallBothEnds$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.ClearPipeStallBothEnds$FUNC + ); + public interface ClearPipeStallBothEnds { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); + static MemorySegment allocate(ClearPipeStallBothEnds fi, MemorySession session) { + return RuntimeHelper.upcallStub(ClearPipeStallBothEnds.class, fi, IOUSBInterfaceStruct942.ClearPipeStallBothEnds$FUNC, session); + } + static ClearPipeStallBothEnds ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.ClearPipeStallBothEnds$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle ClearPipeStallBothEnds$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ClearPipeStallBothEnds")); + public static VarHandle ClearPipeStallBothEnds$VH() { + return IOUSBInterfaceStruct942.ClearPipeStallBothEnds$VH; + } + public static MemoryAddress ClearPipeStallBothEnds$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ClearPipeStallBothEnds$VH.get(seg); + } + public static void ClearPipeStallBothEnds$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.ClearPipeStallBothEnds$VH.set(seg, x); + } + public static MemoryAddress ClearPipeStallBothEnds$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ClearPipeStallBothEnds$VH.get(seg.asSlice(index*sizeof())); + } + public static void ClearPipeStallBothEnds$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.ClearPipeStallBothEnds$VH.set(seg.asSlice(index*sizeof()), x); + } + public static ClearPipeStallBothEnds ClearPipeStallBothEnds (MemorySegment segment, MemorySession session) { + return ClearPipeStallBothEnds.ofAddress(ClearPipeStallBothEnds$get(segment), session); + } + static final FunctionDescriptor SetPipePolicy$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_SHORT$LAYOUT, + Constants$root.C_CHAR$LAYOUT + ); + static final MethodHandle SetPipePolicy$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.SetPipePolicy$FUNC + ); + public interface SetPipePolicy { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, short _x2, byte _x3); + static MemorySegment allocate(SetPipePolicy fi, MemorySession session) { + return RuntimeHelper.upcallStub(SetPipePolicy.class, fi, IOUSBInterfaceStruct942.SetPipePolicy$FUNC, session); + } + static SetPipePolicy ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, short __x2, byte __x3) -> { + try { + return (int)IOUSBInterfaceStruct942.SetPipePolicy$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, __x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle SetPipePolicy$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetPipePolicy")); + public static VarHandle SetPipePolicy$VH() { + return IOUSBInterfaceStruct942.SetPipePolicy$VH; + } + public static MemoryAddress SetPipePolicy$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SetPipePolicy$VH.get(seg); + } + public static void SetPipePolicy$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.SetPipePolicy$VH.set(seg, x); + } + public static MemoryAddress SetPipePolicy$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SetPipePolicy$VH.get(seg.asSlice(index*sizeof())); + } + public static void SetPipePolicy$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.SetPipePolicy$VH.set(seg.asSlice(index*sizeof()), x); + } + public static SetPipePolicy SetPipePolicy (MemorySegment segment, MemorySession session) { + return SetPipePolicy.ofAddress(SetPipePolicy$get(segment), session); + } + static final FunctionDescriptor GetBandwidthAvailable$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetBandwidthAvailable$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetBandwidthAvailable$FUNC + ); + public interface GetBandwidthAvailable { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetBandwidthAvailable fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetBandwidthAvailable.class, fi, IOUSBInterfaceStruct942.GetBandwidthAvailable$FUNC, session); + } + static GetBandwidthAvailable ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.GetBandwidthAvailable$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetBandwidthAvailable$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBandwidthAvailable")); + public static VarHandle GetBandwidthAvailable$VH() { + return IOUSBInterfaceStruct942.GetBandwidthAvailable$VH; + } + public static MemoryAddress GetBandwidthAvailable$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetBandwidthAvailable$VH.get(seg); + } + public static void GetBandwidthAvailable$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetBandwidthAvailable$VH.set(seg, x); + } + public static MemoryAddress GetBandwidthAvailable$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetBandwidthAvailable$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetBandwidthAvailable$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetBandwidthAvailable$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetBandwidthAvailable GetBandwidthAvailable (MemorySegment segment, MemorySession session) { + return GetBandwidthAvailable.ofAddress(GetBandwidthAvailable$get(segment), session); + } + static final FunctionDescriptor GetEndpointProperties$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetEndpointProperties$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetEndpointProperties$FUNC + ); + public interface GetEndpointProperties { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, byte _x2, byte _x3, java.lang.foreign.MemoryAddress _x4, java.lang.foreign.MemoryAddress _x5, java.lang.foreign.MemoryAddress _x6); + static MemorySegment allocate(GetEndpointProperties fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetEndpointProperties.class, fi, IOUSBInterfaceStruct942.GetEndpointProperties$FUNC, session); + } + static GetEndpointProperties ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, byte __x2, byte __x3, java.lang.foreign.MemoryAddress __x4, java.lang.foreign.MemoryAddress __x5, java.lang.foreign.MemoryAddress __x6) -> { + try { + return (int)IOUSBInterfaceStruct942.GetEndpointProperties$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, __x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetEndpointProperties$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetEndpointProperties")); + public static VarHandle GetEndpointProperties$VH() { + return IOUSBInterfaceStruct942.GetEndpointProperties$VH; + } + public static MemoryAddress GetEndpointProperties$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetEndpointProperties$VH.get(seg); + } + public static void GetEndpointProperties$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetEndpointProperties$VH.set(seg, x); + } + public static MemoryAddress GetEndpointProperties$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetEndpointProperties$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetEndpointProperties$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetEndpointProperties$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetEndpointProperties GetEndpointProperties (MemorySegment segment, MemorySession session) { + return GetEndpointProperties.ofAddress(GetEndpointProperties$get(segment), session); + } + static final FunctionDescriptor LowLatencyReadIsochPipeAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle LowLatencyReadIsochPipeAsync$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.LowLatencyReadIsochPipeAsync$FUNC + ); + public interface LowLatencyReadIsochPipeAsync { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, long _x3, int _x4, int _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7, java.lang.foreign.MemoryAddress _x8); + static MemorySegment allocate(LowLatencyReadIsochPipeAsync fi, MemorySession session) { + return RuntimeHelper.upcallStub(LowLatencyReadIsochPipeAsync.class, fi, IOUSBInterfaceStruct942.LowLatencyReadIsochPipeAsync$FUNC, session); + } + static LowLatencyReadIsochPipeAsync ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, long __x3, int __x4, int __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7, java.lang.foreign.MemoryAddress __x8) -> { + try { + return (int)IOUSBInterfaceStruct942.LowLatencyReadIsochPipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, __x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7, (java.lang.foreign.Addressable)__x8); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle LowLatencyReadIsochPipeAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("LowLatencyReadIsochPipeAsync")); + public static VarHandle LowLatencyReadIsochPipeAsync$VH() { + return IOUSBInterfaceStruct942.LowLatencyReadIsochPipeAsync$VH; + } + public static MemoryAddress LowLatencyReadIsochPipeAsync$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.LowLatencyReadIsochPipeAsync$VH.get(seg); + } + public static void LowLatencyReadIsochPipeAsync$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.LowLatencyReadIsochPipeAsync$VH.set(seg, x); + } + public static MemoryAddress LowLatencyReadIsochPipeAsync$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.LowLatencyReadIsochPipeAsync$VH.get(seg.asSlice(index*sizeof())); + } + public static void LowLatencyReadIsochPipeAsync$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.LowLatencyReadIsochPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); + } + public static LowLatencyReadIsochPipeAsync LowLatencyReadIsochPipeAsync (MemorySegment segment, MemorySession session) { + return LowLatencyReadIsochPipeAsync.ofAddress(LowLatencyReadIsochPipeAsync$get(segment), session); + } + static final FunctionDescriptor LowLatencyWriteIsochPipeAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle LowLatencyWriteIsochPipeAsync$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.LowLatencyWriteIsochPipeAsync$FUNC + ); + public interface LowLatencyWriteIsochPipeAsync { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, long _x3, int _x4, int _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7, java.lang.foreign.MemoryAddress _x8); + static MemorySegment allocate(LowLatencyWriteIsochPipeAsync fi, MemorySession session) { + return RuntimeHelper.upcallStub(LowLatencyWriteIsochPipeAsync.class, fi, IOUSBInterfaceStruct942.LowLatencyWriteIsochPipeAsync$FUNC, session); + } + static LowLatencyWriteIsochPipeAsync ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, long __x3, int __x4, int __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7, java.lang.foreign.MemoryAddress __x8) -> { + try { + return (int)IOUSBInterfaceStruct942.LowLatencyWriteIsochPipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, __x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7, (java.lang.foreign.Addressable)__x8); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle LowLatencyWriteIsochPipeAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("LowLatencyWriteIsochPipeAsync")); + public static VarHandle LowLatencyWriteIsochPipeAsync$VH() { + return IOUSBInterfaceStruct942.LowLatencyWriteIsochPipeAsync$VH; + } + public static MemoryAddress LowLatencyWriteIsochPipeAsync$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.LowLatencyWriteIsochPipeAsync$VH.get(seg); + } + public static void LowLatencyWriteIsochPipeAsync$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.LowLatencyWriteIsochPipeAsync$VH.set(seg, x); + } + public static MemoryAddress LowLatencyWriteIsochPipeAsync$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.LowLatencyWriteIsochPipeAsync$VH.get(seg.asSlice(index*sizeof())); + } + public static void LowLatencyWriteIsochPipeAsync$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.LowLatencyWriteIsochPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); + } + public static LowLatencyWriteIsochPipeAsync LowLatencyWriteIsochPipeAsync (MemorySegment segment, MemorySession session) { + return LowLatencyWriteIsochPipeAsync.ofAddress(LowLatencyWriteIsochPipeAsync$get(segment), session); + } + static final FunctionDescriptor LowLatencyCreateBuffer$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle LowLatencyCreateBuffer$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.LowLatencyCreateBuffer$FUNC + ); + public interface LowLatencyCreateBuffer { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, int _x2, int _x3); + static MemorySegment allocate(LowLatencyCreateBuffer fi, MemorySession session) { + return RuntimeHelper.upcallStub(LowLatencyCreateBuffer.class, fi, IOUSBInterfaceStruct942.LowLatencyCreateBuffer$FUNC, session); + } + static LowLatencyCreateBuffer ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, int __x2, int __x3) -> { + try { + return (int)IOUSBInterfaceStruct942.LowLatencyCreateBuffer$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, __x2, __x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle LowLatencyCreateBuffer$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("LowLatencyCreateBuffer")); + public static VarHandle LowLatencyCreateBuffer$VH() { + return IOUSBInterfaceStruct942.LowLatencyCreateBuffer$VH; + } + public static MemoryAddress LowLatencyCreateBuffer$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.LowLatencyCreateBuffer$VH.get(seg); + } + public static void LowLatencyCreateBuffer$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.LowLatencyCreateBuffer$VH.set(seg, x); + } + public static MemoryAddress LowLatencyCreateBuffer$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.LowLatencyCreateBuffer$VH.get(seg.asSlice(index*sizeof())); + } + public static void LowLatencyCreateBuffer$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.LowLatencyCreateBuffer$VH.set(seg.asSlice(index*sizeof()), x); + } + public static LowLatencyCreateBuffer LowLatencyCreateBuffer (MemorySegment segment, MemorySession session) { + return LowLatencyCreateBuffer.ofAddress(LowLatencyCreateBuffer$get(segment), session); + } + static final FunctionDescriptor LowLatencyDestroyBuffer$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle LowLatencyDestroyBuffer$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.LowLatencyDestroyBuffer$FUNC + ); + public interface LowLatencyDestroyBuffer { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(LowLatencyDestroyBuffer fi, MemorySession session) { + return RuntimeHelper.upcallStub(LowLatencyDestroyBuffer.class, fi, IOUSBInterfaceStruct942.LowLatencyDestroyBuffer$FUNC, session); + } + static LowLatencyDestroyBuffer ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.LowLatencyDestroyBuffer$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle LowLatencyDestroyBuffer$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("LowLatencyDestroyBuffer")); + public static VarHandle LowLatencyDestroyBuffer$VH() { + return IOUSBInterfaceStruct942.LowLatencyDestroyBuffer$VH; + } + public static MemoryAddress LowLatencyDestroyBuffer$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.LowLatencyDestroyBuffer$VH.get(seg); + } + public static void LowLatencyDestroyBuffer$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.LowLatencyDestroyBuffer$VH.set(seg, x); + } + public static MemoryAddress LowLatencyDestroyBuffer$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.LowLatencyDestroyBuffer$VH.get(seg.asSlice(index*sizeof())); + } + public static void LowLatencyDestroyBuffer$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.LowLatencyDestroyBuffer$VH.set(seg.asSlice(index*sizeof()), x); + } + public static LowLatencyDestroyBuffer LowLatencyDestroyBuffer (MemorySegment segment, MemorySession session) { + return LowLatencyDestroyBuffer.ofAddress(LowLatencyDestroyBuffer$get(segment), session); + } + static final FunctionDescriptor GetBusMicroFrameNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetBusMicroFrameNumber$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetBusMicroFrameNumber$FUNC + ); + public interface GetBusMicroFrameNumber { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(GetBusMicroFrameNumber fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetBusMicroFrameNumber.class, fi, IOUSBInterfaceStruct942.GetBusMicroFrameNumber$FUNC, session); + } + static GetBusMicroFrameNumber ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBInterfaceStruct942.GetBusMicroFrameNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetBusMicroFrameNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBusMicroFrameNumber")); + public static VarHandle GetBusMicroFrameNumber$VH() { + return IOUSBInterfaceStruct942.GetBusMicroFrameNumber$VH; + } + public static MemoryAddress GetBusMicroFrameNumber$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetBusMicroFrameNumber$VH.get(seg); + } + public static void GetBusMicroFrameNumber$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetBusMicroFrameNumber$VH.set(seg, x); + } + public static MemoryAddress GetBusMicroFrameNumber$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetBusMicroFrameNumber$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetBusMicroFrameNumber$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetBusMicroFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetBusMicroFrameNumber GetBusMicroFrameNumber (MemorySegment segment, MemorySession session) { + return GetBusMicroFrameNumber.ofAddress(GetBusMicroFrameNumber$get(segment), session); + } + static final FunctionDescriptor GetFrameListTime$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetFrameListTime$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetFrameListTime$FUNC + ); + public interface GetFrameListTime { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetFrameListTime fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetFrameListTime.class, fi, IOUSBInterfaceStruct942.GetFrameListTime$FUNC, session); + } + static GetFrameListTime ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.GetFrameListTime$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetFrameListTime$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetFrameListTime")); + public static VarHandle GetFrameListTime$VH() { + return IOUSBInterfaceStruct942.GetFrameListTime$VH; + } + public static MemoryAddress GetFrameListTime$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetFrameListTime$VH.get(seg); + } + public static void GetFrameListTime$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetFrameListTime$VH.set(seg, x); + } + public static MemoryAddress GetFrameListTime$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetFrameListTime$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetFrameListTime$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetFrameListTime$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetFrameListTime GetFrameListTime (MemorySegment segment, MemorySession session) { + return GetFrameListTime.ofAddress(GetFrameListTime$get(segment), session); + } + static final FunctionDescriptor GetIOUSBLibVersion$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetIOUSBLibVersion$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetIOUSBLibVersion$FUNC + ); + public interface GetIOUSBLibVersion { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(GetIOUSBLibVersion fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetIOUSBLibVersion.class, fi, IOUSBInterfaceStruct942.GetIOUSBLibVersion$FUNC, session); + } + static GetIOUSBLibVersion ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBInterfaceStruct942.GetIOUSBLibVersion$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetIOUSBLibVersion$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetIOUSBLibVersion")); + public static VarHandle GetIOUSBLibVersion$VH() { + return IOUSBInterfaceStruct942.GetIOUSBLibVersion$VH; + } + public static MemoryAddress GetIOUSBLibVersion$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetIOUSBLibVersion$VH.get(seg); + } + public static void GetIOUSBLibVersion$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetIOUSBLibVersion$VH.set(seg, x); + } + public static MemoryAddress GetIOUSBLibVersion$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetIOUSBLibVersion$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetIOUSBLibVersion$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetIOUSBLibVersion$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetIOUSBLibVersion GetIOUSBLibVersion (MemorySegment segment, MemorySession session) { + return GetIOUSBLibVersion.ofAddress(GetIOUSBLibVersion$get(segment), session); + } + static final FunctionDescriptor FindNextAssociatedDescriptor$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT + ); + static final MethodHandle FindNextAssociatedDescriptor$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.FindNextAssociatedDescriptor$FUNC + ); + public interface FindNextAssociatedDescriptor { + + java.lang.foreign.Addressable apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, byte _x2); + static MemorySegment allocate(FindNextAssociatedDescriptor fi, MemorySession session) { + return RuntimeHelper.upcallStub(FindNextAssociatedDescriptor.class, fi, IOUSBInterfaceStruct942.FindNextAssociatedDescriptor$FUNC, session); + } + static FindNextAssociatedDescriptor ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, byte __x2) -> { + try { + return (java.lang.foreign.Addressable)(java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.FindNextAssociatedDescriptor$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, __x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle FindNextAssociatedDescriptor$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("FindNextAssociatedDescriptor")); + public static VarHandle FindNextAssociatedDescriptor$VH() { + return IOUSBInterfaceStruct942.FindNextAssociatedDescriptor$VH; + } + public static MemoryAddress FindNextAssociatedDescriptor$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.FindNextAssociatedDescriptor$VH.get(seg); + } + public static void FindNextAssociatedDescriptor$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.FindNextAssociatedDescriptor$VH.set(seg, x); + } + public static MemoryAddress FindNextAssociatedDescriptor$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.FindNextAssociatedDescriptor$VH.get(seg.asSlice(index*sizeof())); + } + public static void FindNextAssociatedDescriptor$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.FindNextAssociatedDescriptor$VH.set(seg.asSlice(index*sizeof()), x); + } + public static FindNextAssociatedDescriptor FindNextAssociatedDescriptor (MemorySegment segment, MemorySession session) { + return FindNextAssociatedDescriptor.ofAddress(FindNextAssociatedDescriptor$get(segment), session); + } + static final FunctionDescriptor FindNextAltInterface$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle FindNextAltInterface$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.FindNextAltInterface$FUNC + ); + public interface FindNextAltInterface { + + java.lang.foreign.Addressable apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(FindNextAltInterface fi, MemorySession session) { + return RuntimeHelper.upcallStub(FindNextAltInterface.class, fi, IOUSBInterfaceStruct942.FindNextAltInterface$FUNC, session); + } + static FindNextAltInterface ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (java.lang.foreign.Addressable)(java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.FindNextAltInterface$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle FindNextAltInterface$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("FindNextAltInterface")); + public static VarHandle FindNextAltInterface$VH() { + return IOUSBInterfaceStruct942.FindNextAltInterface$VH; + } + public static MemoryAddress FindNextAltInterface$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.FindNextAltInterface$VH.get(seg); + } + public static void FindNextAltInterface$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.FindNextAltInterface$VH.set(seg, x); + } + public static MemoryAddress FindNextAltInterface$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.FindNextAltInterface$VH.get(seg.asSlice(index*sizeof())); + } + public static void FindNextAltInterface$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.FindNextAltInterface$VH.set(seg.asSlice(index*sizeof()), x); + } + public static FindNextAltInterface FindNextAltInterface (MemorySegment segment, MemorySession session) { + return FindNextAltInterface.ofAddress(FindNextAltInterface$get(segment), session); + } + static final FunctionDescriptor GetBusFrameNumberWithTime$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetBusFrameNumberWithTime$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetBusFrameNumberWithTime$FUNC + ); + public interface GetBusFrameNumberWithTime { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(GetBusFrameNumberWithTime fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetBusFrameNumberWithTime.class, fi, IOUSBInterfaceStruct942.GetBusFrameNumberWithTime$FUNC, session); + } + static GetBusFrameNumberWithTime ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBInterfaceStruct942.GetBusFrameNumberWithTime$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetBusFrameNumberWithTime$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBusFrameNumberWithTime")); + public static VarHandle GetBusFrameNumberWithTime$VH() { + return IOUSBInterfaceStruct942.GetBusFrameNumberWithTime$VH; + } + public static MemoryAddress GetBusFrameNumberWithTime$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetBusFrameNumberWithTime$VH.get(seg); + } + public static void GetBusFrameNumberWithTime$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetBusFrameNumberWithTime$VH.set(seg, x); + } + public static MemoryAddress GetBusFrameNumberWithTime$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetBusFrameNumberWithTime$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetBusFrameNumberWithTime$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetBusFrameNumberWithTime$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetBusFrameNumberWithTime GetBusFrameNumberWithTime (MemorySegment segment, MemorySession session) { + return GetBusFrameNumberWithTime.ofAddress(GetBusFrameNumberWithTime$get(segment), session); + } + static final FunctionDescriptor GetPipePropertiesV2$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetPipePropertiesV2$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetPipePropertiesV2$FUNC + ); + public interface GetPipePropertiesV2 { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, java.lang.foreign.MemoryAddress _x4, java.lang.foreign.MemoryAddress _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7, java.lang.foreign.MemoryAddress _x8, java.lang.foreign.MemoryAddress _x9); + static MemorySegment allocate(GetPipePropertiesV2 fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetPipePropertiesV2.class, fi, IOUSBInterfaceStruct942.GetPipePropertiesV2$FUNC, session); + } + static GetPipePropertiesV2 ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, java.lang.foreign.MemoryAddress __x4, java.lang.foreign.MemoryAddress __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7, java.lang.foreign.MemoryAddress __x8, java.lang.foreign.MemoryAddress __x9) -> { + try { + return (int)IOUSBInterfaceStruct942.GetPipePropertiesV2$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7, (java.lang.foreign.Addressable)__x8, (java.lang.foreign.Addressable)__x9); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetPipePropertiesV2$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetPipePropertiesV2")); + public static VarHandle GetPipePropertiesV2$VH() { + return IOUSBInterfaceStruct942.GetPipePropertiesV2$VH; + } + public static MemoryAddress GetPipePropertiesV2$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetPipePropertiesV2$VH.get(seg); + } + public static void GetPipePropertiesV2$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetPipePropertiesV2$VH.set(seg, x); + } + public static MemoryAddress GetPipePropertiesV2$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetPipePropertiesV2$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetPipePropertiesV2$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetPipePropertiesV2$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetPipePropertiesV2 GetPipePropertiesV2 (MemorySegment segment, MemorySession session) { + return GetPipePropertiesV2.ofAddress(GetPipePropertiesV2$get(segment), session); + } + static final FunctionDescriptor GetPipePropertiesV3$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetPipePropertiesV3$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetPipePropertiesV3$FUNC + ); + public interface GetPipePropertiesV3 { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(GetPipePropertiesV3 fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetPipePropertiesV3.class, fi, IOUSBInterfaceStruct942.GetPipePropertiesV3$FUNC, session); + } + static GetPipePropertiesV3 ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBInterfaceStruct942.GetPipePropertiesV3$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetPipePropertiesV3$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetPipePropertiesV3")); + public static VarHandle GetPipePropertiesV3$VH() { + return IOUSBInterfaceStruct942.GetPipePropertiesV3$VH; + } + public static MemoryAddress GetPipePropertiesV3$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetPipePropertiesV3$VH.get(seg); + } + public static void GetPipePropertiesV3$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetPipePropertiesV3$VH.set(seg, x); + } + public static MemoryAddress GetPipePropertiesV3$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetPipePropertiesV3$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetPipePropertiesV3$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetPipePropertiesV3$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetPipePropertiesV3 GetPipePropertiesV3 (MemorySegment segment, MemorySession session) { + return GetPipePropertiesV3.ofAddress(GetPipePropertiesV3$get(segment), session); + } + static final FunctionDescriptor GetEndpointPropertiesV3$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetEndpointPropertiesV3$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetEndpointPropertiesV3$FUNC + ); + public interface GetEndpointPropertiesV3 { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetEndpointPropertiesV3 fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetEndpointPropertiesV3.class, fi, IOUSBInterfaceStruct942.GetEndpointPropertiesV3$FUNC, session); + } + static GetEndpointPropertiesV3 ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.GetEndpointPropertiesV3$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetEndpointPropertiesV3$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetEndpointPropertiesV3")); + public static VarHandle GetEndpointPropertiesV3$VH() { + return IOUSBInterfaceStruct942.GetEndpointPropertiesV3$VH; + } + public static MemoryAddress GetEndpointPropertiesV3$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetEndpointPropertiesV3$VH.get(seg); + } + public static void GetEndpointPropertiesV3$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetEndpointPropertiesV3$VH.set(seg, x); + } + public static MemoryAddress GetEndpointPropertiesV3$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetEndpointPropertiesV3$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetEndpointPropertiesV3$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetEndpointPropertiesV3$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetEndpointPropertiesV3 GetEndpointPropertiesV3 (MemorySegment segment, MemorySession session) { + return GetEndpointPropertiesV3.ofAddress(GetEndpointPropertiesV3$get(segment), session); + } + static final FunctionDescriptor SupportsStreams$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle SupportsStreams$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.SupportsStreams$FUNC + ); + public interface SupportsStreams { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(SupportsStreams fi, MemorySession session) { + return RuntimeHelper.upcallStub(SupportsStreams.class, fi, IOUSBInterfaceStruct942.SupportsStreams$FUNC, session); + } + static SupportsStreams ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBInterfaceStruct942.SupportsStreams$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle SupportsStreams$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SupportsStreams")); + public static VarHandle SupportsStreams$VH() { + return IOUSBInterfaceStruct942.SupportsStreams$VH; + } + public static MemoryAddress SupportsStreams$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SupportsStreams$VH.get(seg); + } + public static void SupportsStreams$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.SupportsStreams$VH.set(seg, x); + } + public static MemoryAddress SupportsStreams$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SupportsStreams$VH.get(seg.asSlice(index*sizeof())); + } + public static void SupportsStreams$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.SupportsStreams$VH.set(seg.asSlice(index*sizeof()), x); + } + public static SupportsStreams SupportsStreams (MemorySegment segment, MemorySession session) { + return SupportsStreams.ofAddress(SupportsStreams$get(segment), session); + } + static final FunctionDescriptor CreateStreams$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle CreateStreams$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.CreateStreams$FUNC + ); + public interface CreateStreams { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, int _x2); + static MemorySegment allocate(CreateStreams fi, MemorySession session) { + return RuntimeHelper.upcallStub(CreateStreams.class, fi, IOUSBInterfaceStruct942.CreateStreams$FUNC, session); + } + static CreateStreams ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, int __x2) -> { + try { + return (int)IOUSBInterfaceStruct942.CreateStreams$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle CreateStreams$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateStreams")); + public static VarHandle CreateStreams$VH() { + return IOUSBInterfaceStruct942.CreateStreams$VH; + } + public static MemoryAddress CreateStreams$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.CreateStreams$VH.get(seg); + } + public static void CreateStreams$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.CreateStreams$VH.set(seg, x); + } + public static MemoryAddress CreateStreams$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.CreateStreams$VH.get(seg.asSlice(index*sizeof())); + } + public static void CreateStreams$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.CreateStreams$VH.set(seg.asSlice(index*sizeof()), x); + } + public static CreateStreams CreateStreams (MemorySegment segment, MemorySession session) { + return CreateStreams.ofAddress(CreateStreams$get(segment), session); + } + static final FunctionDescriptor GetConfiguredStreams$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetConfiguredStreams$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetConfiguredStreams$FUNC + ); + public interface GetConfiguredStreams { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(GetConfiguredStreams fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetConfiguredStreams.class, fi, IOUSBInterfaceStruct942.GetConfiguredStreams$FUNC, session); + } + static GetConfiguredStreams ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBInterfaceStruct942.GetConfiguredStreams$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetConfiguredStreams$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetConfiguredStreams")); + public static VarHandle GetConfiguredStreams$VH() { + return IOUSBInterfaceStruct942.GetConfiguredStreams$VH; + } + public static MemoryAddress GetConfiguredStreams$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetConfiguredStreams$VH.get(seg); + } + public static void GetConfiguredStreams$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetConfiguredStreams$VH.set(seg, x); + } + public static MemoryAddress GetConfiguredStreams$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetConfiguredStreams$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetConfiguredStreams$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetConfiguredStreams$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetConfiguredStreams GetConfiguredStreams (MemorySegment segment, MemorySession session) { + return GetConfiguredStreams.ofAddress(GetConfiguredStreams$get(segment), session); + } + static final FunctionDescriptor ReadStreamsPipeTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle ReadStreamsPipeTO$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.ReadStreamsPipeTO$FUNC + ); + public interface ReadStreamsPipeTO { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, int _x2, java.lang.foreign.MemoryAddress _x3, java.lang.foreign.MemoryAddress _x4, int _x5, int _x6); + static MemorySegment allocate(ReadStreamsPipeTO fi, MemorySession session) { + return RuntimeHelper.upcallStub(ReadStreamsPipeTO.class, fi, IOUSBInterfaceStruct942.ReadStreamsPipeTO$FUNC, session); + } + static ReadStreamsPipeTO ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, int __x2, java.lang.foreign.MemoryAddress __x3, java.lang.foreign.MemoryAddress __x4, int __x5, int __x6) -> { + try { + return (int)IOUSBInterfaceStruct942.ReadStreamsPipeTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4, __x5, __x6); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle ReadStreamsPipeTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadStreamsPipeTO")); + public static VarHandle ReadStreamsPipeTO$VH() { + return IOUSBInterfaceStruct942.ReadStreamsPipeTO$VH; + } + public static MemoryAddress ReadStreamsPipeTO$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadStreamsPipeTO$VH.get(seg); + } + public static void ReadStreamsPipeTO$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.ReadStreamsPipeTO$VH.set(seg, x); + } + public static MemoryAddress ReadStreamsPipeTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadStreamsPipeTO$VH.get(seg.asSlice(index*sizeof())); + } + public static void ReadStreamsPipeTO$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.ReadStreamsPipeTO$VH.set(seg.asSlice(index*sizeof()), x); + } + public static ReadStreamsPipeTO ReadStreamsPipeTO (MemorySegment segment, MemorySession session) { + return ReadStreamsPipeTO.ofAddress(ReadStreamsPipeTO$get(segment), session); + } + static final FunctionDescriptor WriteStreamsPipeTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle WriteStreamsPipeTO$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.WriteStreamsPipeTO$FUNC + ); + public interface WriteStreamsPipeTO { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, int _x2, java.lang.foreign.MemoryAddress _x3, int _x4, int _x5, int _x6); + static MemorySegment allocate(WriteStreamsPipeTO fi, MemorySession session) { + return RuntimeHelper.upcallStub(WriteStreamsPipeTO.class, fi, IOUSBInterfaceStruct942.WriteStreamsPipeTO$FUNC, session); + } + static WriteStreamsPipeTO ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, int __x2, java.lang.foreign.MemoryAddress __x3, int __x4, int __x5, int __x6) -> { + try { + return (int)IOUSBInterfaceStruct942.WriteStreamsPipeTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, (java.lang.foreign.Addressable)__x3, __x4, __x5, __x6); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle WriteStreamsPipeTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WriteStreamsPipeTO")); + public static VarHandle WriteStreamsPipeTO$VH() { + return IOUSBInterfaceStruct942.WriteStreamsPipeTO$VH; + } + public static MemoryAddress WriteStreamsPipeTO$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WriteStreamsPipeTO$VH.get(seg); + } + public static void WriteStreamsPipeTO$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.WriteStreamsPipeTO$VH.set(seg, x); + } + public static MemoryAddress WriteStreamsPipeTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WriteStreamsPipeTO$VH.get(seg.asSlice(index*sizeof())); + } + public static void WriteStreamsPipeTO$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.WriteStreamsPipeTO$VH.set(seg.asSlice(index*sizeof()), x); + } + public static WriteStreamsPipeTO WriteStreamsPipeTO (MemorySegment segment, MemorySession session) { + return WriteStreamsPipeTO.ofAddress(WriteStreamsPipeTO$get(segment), session); + } + static final FunctionDescriptor ReadStreamsPipeAsyncTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle ReadStreamsPipeAsyncTO$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.ReadStreamsPipeAsyncTO$FUNC + ); + public interface ReadStreamsPipeAsyncTO { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, int _x2, java.lang.foreign.MemoryAddress _x3, int _x4, int _x5, int _x6, java.lang.foreign.MemoryAddress _x7, java.lang.foreign.MemoryAddress _x8); + static MemorySegment allocate(ReadStreamsPipeAsyncTO fi, MemorySession session) { + return RuntimeHelper.upcallStub(ReadStreamsPipeAsyncTO.class, fi, IOUSBInterfaceStruct942.ReadStreamsPipeAsyncTO$FUNC, session); + } + static ReadStreamsPipeAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, int __x2, java.lang.foreign.MemoryAddress __x3, int __x4, int __x5, int __x6, java.lang.foreign.MemoryAddress __x7, java.lang.foreign.MemoryAddress __x8) -> { + try { + return (int)IOUSBInterfaceStruct942.ReadStreamsPipeAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, (java.lang.foreign.Addressable)__x3, __x4, __x5, __x6, (java.lang.foreign.Addressable)__x7, (java.lang.foreign.Addressable)__x8); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle ReadStreamsPipeAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadStreamsPipeAsyncTO")); + public static VarHandle ReadStreamsPipeAsyncTO$VH() { + return IOUSBInterfaceStruct942.ReadStreamsPipeAsyncTO$VH; + } + public static MemoryAddress ReadStreamsPipeAsyncTO$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadStreamsPipeAsyncTO$VH.get(seg); + } + public static void ReadStreamsPipeAsyncTO$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.ReadStreamsPipeAsyncTO$VH.set(seg, x); + } + public static MemoryAddress ReadStreamsPipeAsyncTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadStreamsPipeAsyncTO$VH.get(seg.asSlice(index*sizeof())); + } + public static void ReadStreamsPipeAsyncTO$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.ReadStreamsPipeAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); + } + public static ReadStreamsPipeAsyncTO ReadStreamsPipeAsyncTO (MemorySegment segment, MemorySession session) { + return ReadStreamsPipeAsyncTO.ofAddress(ReadStreamsPipeAsyncTO$get(segment), session); + } + static final FunctionDescriptor WriteStreamsPipeAsyncTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle WriteStreamsPipeAsyncTO$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.WriteStreamsPipeAsyncTO$FUNC + ); + public interface WriteStreamsPipeAsyncTO { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, int _x2, java.lang.foreign.MemoryAddress _x3, int _x4, int _x5, int _x6, java.lang.foreign.MemoryAddress _x7, java.lang.foreign.MemoryAddress _x8); + static MemorySegment allocate(WriteStreamsPipeAsyncTO fi, MemorySession session) { + return RuntimeHelper.upcallStub(WriteStreamsPipeAsyncTO.class, fi, IOUSBInterfaceStruct942.WriteStreamsPipeAsyncTO$FUNC, session); + } + static WriteStreamsPipeAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, int __x2, java.lang.foreign.MemoryAddress __x3, int __x4, int __x5, int __x6, java.lang.foreign.MemoryAddress __x7, java.lang.foreign.MemoryAddress __x8) -> { + try { + return (int)IOUSBInterfaceStruct942.WriteStreamsPipeAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, (java.lang.foreign.Addressable)__x3, __x4, __x5, __x6, (java.lang.foreign.Addressable)__x7, (java.lang.foreign.Addressable)__x8); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle WriteStreamsPipeAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WriteStreamsPipeAsyncTO")); + public static VarHandle WriteStreamsPipeAsyncTO$VH() { + return IOUSBInterfaceStruct942.WriteStreamsPipeAsyncTO$VH; + } + public static MemoryAddress WriteStreamsPipeAsyncTO$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WriteStreamsPipeAsyncTO$VH.get(seg); + } + public static void WriteStreamsPipeAsyncTO$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.WriteStreamsPipeAsyncTO$VH.set(seg, x); + } + public static MemoryAddress WriteStreamsPipeAsyncTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WriteStreamsPipeAsyncTO$VH.get(seg.asSlice(index*sizeof())); + } + public static void WriteStreamsPipeAsyncTO$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.WriteStreamsPipeAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); + } + public static WriteStreamsPipeAsyncTO WriteStreamsPipeAsyncTO (MemorySegment segment, MemorySession session) { + return WriteStreamsPipeAsyncTO.ofAddress(WriteStreamsPipeAsyncTO$get(segment), session); + } + static final FunctionDescriptor AbortStreamsPipe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle AbortStreamsPipe$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.AbortStreamsPipe$FUNC + ); + public interface AbortStreamsPipe { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, int _x2); + static MemorySegment allocate(AbortStreamsPipe fi, MemorySession session) { + return RuntimeHelper.upcallStub(AbortStreamsPipe.class, fi, IOUSBInterfaceStruct942.AbortStreamsPipe$FUNC, session); + } + static AbortStreamsPipe ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, int __x2) -> { + try { + return (int)IOUSBInterfaceStruct942.AbortStreamsPipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle AbortStreamsPipe$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AbortStreamsPipe")); + public static VarHandle AbortStreamsPipe$VH() { + return IOUSBInterfaceStruct942.AbortStreamsPipe$VH; + } + public static MemoryAddress AbortStreamsPipe$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.AbortStreamsPipe$VH.get(seg); + } + public static void AbortStreamsPipe$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.AbortStreamsPipe$VH.set(seg, x); + } + public static MemoryAddress AbortStreamsPipe$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.AbortStreamsPipe$VH.get(seg.asSlice(index*sizeof())); + } + public static void AbortStreamsPipe$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.AbortStreamsPipe$VH.set(seg.asSlice(index*sizeof()), x); + } + public static AbortStreamsPipe AbortStreamsPipe (MemorySegment segment, MemorySession session) { + return AbortStreamsPipe.ofAddress(AbortStreamsPipe$get(segment), session); + } + static final FunctionDescriptor RegisterForNotification$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle RegisterForNotification$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.RegisterForNotification$FUNC + ); + public interface RegisterForNotification { + + int apply(java.lang.foreign.MemoryAddress _x0, long _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, java.lang.foreign.MemoryAddress _x4); + static MemorySegment allocate(RegisterForNotification fi, MemorySession session) { + return RuntimeHelper.upcallStub(RegisterForNotification.class, fi, IOUSBInterfaceStruct942.RegisterForNotification$FUNC, session); + } + static RegisterForNotification ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, long __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, java.lang.foreign.MemoryAddress __x4) -> { + try { + return (int)IOUSBInterfaceStruct942.RegisterForNotification$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle RegisterForNotification$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("RegisterForNotification")); + public static VarHandle RegisterForNotification$VH() { + return IOUSBInterfaceStruct942.RegisterForNotification$VH; + } + public static MemoryAddress RegisterForNotification$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.RegisterForNotification$VH.get(seg); + } + public static void RegisterForNotification$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.RegisterForNotification$VH.set(seg, x); + } + public static MemoryAddress RegisterForNotification$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.RegisterForNotification$VH.get(seg.asSlice(index*sizeof())); + } + public static void RegisterForNotification$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.RegisterForNotification$VH.set(seg.asSlice(index*sizeof()), x); + } + public static RegisterForNotification RegisterForNotification (MemorySegment segment, MemorySession session) { + return RegisterForNotification.ofAddress(RegisterForNotification$get(segment), session); + } + static final FunctionDescriptor UnregisterNotification$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle UnregisterNotification$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.UnregisterNotification$FUNC + ); + public interface UnregisterNotification { + + int apply(java.lang.foreign.MemoryAddress _x0, long _x1); + static MemorySegment allocate(UnregisterNotification fi, MemorySession session) { + return RuntimeHelper.upcallStub(UnregisterNotification.class, fi, IOUSBInterfaceStruct942.UnregisterNotification$FUNC, session); + } + static UnregisterNotification ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, long __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.UnregisterNotification$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle UnregisterNotification$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("UnregisterNotification")); + public static VarHandle UnregisterNotification$VH() { + return IOUSBInterfaceStruct942.UnregisterNotification$VH; + } + public static MemoryAddress UnregisterNotification$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.UnregisterNotification$VH.get(seg); + } + public static void UnregisterNotification$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.UnregisterNotification$VH.set(seg, x); + } + public static MemoryAddress UnregisterNotification$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.UnregisterNotification$VH.get(seg.asSlice(index*sizeof())); + } + public static void UnregisterNotification$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.UnregisterNotification$VH.set(seg.asSlice(index*sizeof()), x); + } + public static UnregisterNotification UnregisterNotification (MemorySegment segment, MemorySession session) { + return UnregisterNotification.ofAddress(UnregisterNotification$get(segment), session); + } + static final FunctionDescriptor AcknowledgeNotification$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT + ); + static final MethodHandle AcknowledgeNotification$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.AcknowledgeNotification$FUNC + ); + public interface AcknowledgeNotification { + + int apply(java.lang.foreign.MemoryAddress _x0, long _x1); + static MemorySegment allocate(AcknowledgeNotification fi, MemorySession session) { + return RuntimeHelper.upcallStub(AcknowledgeNotification.class, fi, IOUSBInterfaceStruct942.AcknowledgeNotification$FUNC, session); + } + static AcknowledgeNotification ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, long __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.AcknowledgeNotification$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle AcknowledgeNotification$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AcknowledgeNotification")); + public static VarHandle AcknowledgeNotification$VH() { + return IOUSBInterfaceStruct942.AcknowledgeNotification$VH; + } + public static MemoryAddress AcknowledgeNotification$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.AcknowledgeNotification$VH.get(seg); + } + public static void AcknowledgeNotification$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.AcknowledgeNotification$VH.set(seg, x); + } + public static MemoryAddress AcknowledgeNotification$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.AcknowledgeNotification$VH.get(seg.asSlice(index*sizeof())); + } + public static void AcknowledgeNotification$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.AcknowledgeNotification$VH.set(seg.asSlice(index*sizeof()), x); + } + public static AcknowledgeNotification AcknowledgeNotification (MemorySegment segment, MemorySession session) { + return AcknowledgeNotification.ofAddress(AcknowledgeNotification$get(segment), session); + } + static final FunctionDescriptor RegisterDriver$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle RegisterDriver$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.RegisterDriver$FUNC + ); + public interface RegisterDriver { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(RegisterDriver fi, MemorySession session) { + return RuntimeHelper.upcallStub(RegisterDriver.class, fi, IOUSBInterfaceStruct942.RegisterDriver$FUNC, session); + } + static RegisterDriver ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBInterfaceStruct942.RegisterDriver$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle RegisterDriver$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("RegisterDriver")); + public static VarHandle RegisterDriver$VH() { + return IOUSBInterfaceStruct942.RegisterDriver$VH; + } + public static MemoryAddress RegisterDriver$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.RegisterDriver$VH.get(seg); + } + public static void RegisterDriver$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.RegisterDriver$VH.set(seg, x); + } + public static MemoryAddress RegisterDriver$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.RegisterDriver$VH.get(seg.asSlice(index*sizeof())); + } + public static void RegisterDriver$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.RegisterDriver$VH.set(seg.asSlice(index*sizeof()), x); + } + public static RegisterDriver RegisterDriver (MemorySegment segment, MemorySession session) { + return RegisterDriver.ofAddress(RegisterDriver$get(segment), session); + } + static final FunctionDescriptor SetDeviceIdlePolicy$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle SetDeviceIdlePolicy$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.SetDeviceIdlePolicy$FUNC + ); + public interface SetDeviceIdlePolicy { + + int apply(java.lang.foreign.MemoryAddress _x0, int _x1); + static MemorySegment allocate(SetDeviceIdlePolicy fi, MemorySession session) { + return RuntimeHelper.upcallStub(SetDeviceIdlePolicy.class, fi, IOUSBInterfaceStruct942.SetDeviceIdlePolicy$FUNC, session); + } + static SetDeviceIdlePolicy ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, int __x1) -> { + try { + return (int)IOUSBInterfaceStruct942.SetDeviceIdlePolicy$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle SetDeviceIdlePolicy$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetDeviceIdlePolicy")); + public static VarHandle SetDeviceIdlePolicy$VH() { + return IOUSBInterfaceStruct942.SetDeviceIdlePolicy$VH; + } + public static MemoryAddress SetDeviceIdlePolicy$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SetDeviceIdlePolicy$VH.get(seg); + } + public static void SetDeviceIdlePolicy$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.SetDeviceIdlePolicy$VH.set(seg, x); + } + public static MemoryAddress SetDeviceIdlePolicy$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SetDeviceIdlePolicy$VH.get(seg.asSlice(index*sizeof())); + } + public static void SetDeviceIdlePolicy$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.SetDeviceIdlePolicy$VH.set(seg.asSlice(index*sizeof()), x); + } + public static SetDeviceIdlePolicy SetDeviceIdlePolicy (MemorySegment segment, MemorySession session) { + return SetDeviceIdlePolicy.ofAddress(SetDeviceIdlePolicy$get(segment), session); + } + static final FunctionDescriptor SetPipeIdlePolicy$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle SetPipeIdlePolicy$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.SetPipeIdlePolicy$FUNC + ); + public interface SetPipeIdlePolicy { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, int _x2); + static MemorySegment allocate(SetPipeIdlePolicy fi, MemorySession session) { + return RuntimeHelper.upcallStub(SetPipeIdlePolicy.class, fi, IOUSBInterfaceStruct942.SetPipeIdlePolicy$FUNC, session); + } + static SetPipeIdlePolicy ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, int __x2) -> { + try { + return (int)IOUSBInterfaceStruct942.SetPipeIdlePolicy$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle SetPipeIdlePolicy$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetPipeIdlePolicy")); + public static VarHandle SetPipeIdlePolicy$VH() { + return IOUSBInterfaceStruct942.SetPipeIdlePolicy$VH; + } + public static MemoryAddress SetPipeIdlePolicy$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SetPipeIdlePolicy$VH.get(seg); + } + public static void SetPipeIdlePolicy$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.SetPipeIdlePolicy$VH.set(seg, x); + } + public static MemoryAddress SetPipeIdlePolicy$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SetPipeIdlePolicy$VH.get(seg.asSlice(index*sizeof())); + } + public static void SetPipeIdlePolicy$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.SetPipeIdlePolicy$VH.set(seg.asSlice(index*sizeof()), x); + } + public static SetPipeIdlePolicy SetPipeIdlePolicy (MemorySegment segment, MemorySession session) { + return SetPipeIdlePolicy.ofAddress(SetPipeIdlePolicy$get(segment), session); + } + static final FunctionDescriptor GetInterfaceAsyncNotificationPort$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetInterfaceAsyncNotificationPort$MH = RuntimeHelper.downcallHandle( + IOUSBInterfaceStruct942.GetInterfaceAsyncNotificationPort$FUNC + ); + public interface GetInterfaceAsyncNotificationPort { + + java.lang.foreign.Addressable apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(GetInterfaceAsyncNotificationPort fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetInterfaceAsyncNotificationPort.class, fi, IOUSBInterfaceStruct942.GetInterfaceAsyncNotificationPort$FUNC, session); + } + static GetInterfaceAsyncNotificationPort ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (java.lang.foreign.Addressable)(java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceAsyncNotificationPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetInterfaceAsyncNotificationPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceAsyncNotificationPort")); + public static VarHandle GetInterfaceAsyncNotificationPort$VH() { + return IOUSBInterfaceStruct942.GetInterfaceAsyncNotificationPort$VH; + } + public static MemoryAddress GetInterfaceAsyncNotificationPort$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceAsyncNotificationPort$VH.get(seg); + } + public static void GetInterfaceAsyncNotificationPort$set( MemorySegment seg, MemoryAddress x) { + IOUSBInterfaceStruct942.GetInterfaceAsyncNotificationPort$VH.set(seg, x); + } + public static MemoryAddress GetInterfaceAsyncNotificationPort$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceAsyncNotificationPort$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetInterfaceAsyncNotificationPort$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBInterfaceStruct942.GetInterfaceAsyncNotificationPort$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetInterfaceAsyncNotificationPort GetInterfaceAsyncNotificationPort (MemorySegment segment, MemorySession session) { + return GetInterfaceAsyncNotificationPort.ofAddress(GetInterfaceAsyncNotificationPort$get(segment), session); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java new file mode 100644 index 00000000..18defbd9 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java @@ -0,0 +1,217 @@ +package net.codecrete.usb.macos.gen.iokit; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { +// System.loadLibrary("IOKit.framework"); +// SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SymbolLookup loaderLookup = SymbolLookup.libraryLookup("IOKit.framework/IOKit", MemorySession.openImplicit()); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java new file mode 100644 index 00000000..75a6b3ae --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java @@ -0,0 +1,50 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.OfAddress; +import static java.lang.foreign.ValueLayout.OfInt; +class constants$0 { + + static final OfAddress kCFRunLoopDefaultMode$LAYOUT = Constants$root.C_POINTER$LAYOUT; + static final VarHandle kCFRunLoopDefaultMode$VH = constants$0.kCFRunLoopDefaultMode$LAYOUT.varHandle(); + static final MemorySegment kCFRunLoopDefaultMode$SEGMENT = RuntimeHelper.lookupGlobalVariable("kCFRunLoopDefaultMode", constants$0.kCFRunLoopDefaultMode$LAYOUT); + static final OfInt kIOMasterPortDefault$LAYOUT = Constants$root.C_INT$LAYOUT; + static final VarHandle kIOMasterPortDefault$VH = constants$0.kIOMasterPortDefault$LAYOUT.varHandle(); + static final MemorySegment kIOMasterPortDefault$SEGMENT = RuntimeHelper.lookupGlobalVariable("kIOMasterPortDefault", constants$0.kIOMasterPortDefault$LAYOUT); + static final FunctionDescriptor IONotificationPortCreate$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle IONotificationPortCreate$MH = RuntimeHelper.downcallHandle( + "IONotificationPortCreate", + constants$0.IONotificationPortCreate$FUNC + ); + static final FunctionDescriptor IONotificationPortGetRunLoopSource$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle IONotificationPortGetRunLoopSource$MH = RuntimeHelper.downcallHandle( + "IONotificationPortGetRunLoopSource", + constants$0.IONotificationPortGetRunLoopSource$FUNC + ); + static final FunctionDescriptor IOObjectRelease$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle IOObjectRelease$MH = RuntimeHelper.downcallHandle( + "IOObjectRelease", + constants$0.IOObjectRelease$FUNC + ); + static final FunctionDescriptor IOIteratorNext$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle IOIteratorNext$MH = RuntimeHelper.downcallHandle( + "IOIteratorNext", + constants$0.IOIteratorNext$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$1.java new file mode 100644 index 00000000..f6bb1dbf --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$1.java @@ -0,0 +1,61 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; +class constants$1 { + + static final FunctionDescriptor IOServiceAddMatchingNotification$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle IOServiceAddMatchingNotification$MH = RuntimeHelper.downcallHandle( + "IOServiceAddMatchingNotification", + constants$1.IOServiceAddMatchingNotification$FUNC + ); + static final FunctionDescriptor IORegistryEntryGetRegistryEntryID$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle IORegistryEntryGetRegistryEntryID$MH = RuntimeHelper.downcallHandle( + "IORegistryEntryGetRegistryEntryID", + constants$1.IORegistryEntryGetRegistryEntryID$FUNC + ); + static final FunctionDescriptor IORegistryEntryCreateCFProperty$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle IORegistryEntryCreateCFProperty$MH = RuntimeHelper.downcallHandle( + "IORegistryEntryCreateCFProperty", + constants$1.IORegistryEntryCreateCFProperty$FUNC + ); + static final FunctionDescriptor IOServiceMatching$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle IOServiceMatching$MH = RuntimeHelper.downcallHandle( + "IOServiceMatching", + constants$1.IOServiceMatching$FUNC + ); + static final FunctionDescriptor IOCreatePlugInInterfaceForService$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle IOCreatePlugInInterfaceForService$MH = RuntimeHelper.downcallHandle( + "IOCreatePlugInInterfaceForService", + constants$1.IOCreatePlugInInterfaceForService$FUNC + ); + static final MemorySegment kIOFirstMatchNotification$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("IOServiceFirstMatch"); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$2.java new file mode 100644 index 00000000..c82ad78e --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$2.java @@ -0,0 +1,12 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemorySegment; +class constants$2 { + + static final MemorySegment kIOTerminatedNotification$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("IOServiceTerminate"); + static final MemorySegment kIOUSBDeviceClassName$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("IOUSBDevice"); +} + + From 8cc6130c5a8135aa1842bf62149c4f2f38f1de18 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 6 Sep 2022 22:23:27 +0200 Subject: [PATCH 064/433] Windows: merge jextract scripts --- java-does-usb/jextract/README.md | 22 +- .../usb/macos/gen/mach/Constants$root.java | 23 -- .../usb/macos/gen/mach/RuntimeHelper.java | 233 ------------------ .../usb/macos/gen/mach/constants$0.java | 21 -- .../codecrete/usb/macos/gen/mach/mach.java | 34 --- java-does-usb/jextract/windows/gen_win.cmd | 116 +++++++++ .../jextract/windows/gen_win_kernel32.cmd | 27 -- .../jextract/windows/gen_win_setupapi.cmd | 29 --- .../jextract/windows/gen_win_stdlib.cmd | 7 - .../jextract/windows/gen_win_usbioctl.cmd | 11 - .../jextract/windows/gen_win_user32.cmd | 29 --- .../jextract/windows/gen_win_winusb.cmd | 16 -- .../usb/windows/WindowsUSBDeviceRegistry.java | 1 - 13 files changed, 129 insertions(+), 440 deletions(-) delete mode 100644 java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java delete mode 100644 java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java delete mode 100644 java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java delete mode 100644 java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java create mode 100644 java-does-usb/jextract/windows/gen_win.cmd delete mode 100644 java-does-usb/jextract/windows/gen_win_kernel32.cmd delete mode 100644 java-does-usb/jextract/windows/gen_win_setupapi.cmd delete mode 100644 java-does-usb/jextract/windows/gen_win_stdlib.cmd delete mode 100644 java-does-usb/jextract/windows/gen_win_usbioctl.cmd delete mode 100644 java-does-usb/jextract/windows/gen_win_user32.cmd delete mode 100644 java-does-usb/jextract/windows/gen_win_winusb.cmd diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index 9d1bf3a8..fce509dd 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -13,7 +13,15 @@ The resulting code is then committed to the source code repository. Before the c ## General limitations -- Binaries of *jextract* can be downloaded from https://jdk.java.net/jextract/. Only x64 binaries are available. It is unclear if the x64 jextract run on macOS with Apple Silicon (ARM64) using the Rosetta emulator produces valid bindings. So far, not problems have been detected. +- Binaries of *jextract* can be downloaded from https://jdk.java.net/jextract/. x64 binaries are available but no ARM64. According to the mailing list, cross-compiling is not possible, i.e. ARM64 binaries are needed on macOS with Apple Silicon. But so far, the x64 binaries have worked without problems. + +- `typedef` and `struct`: + + 1. If only the `typedef` is included (`--include-typedef`), an empty Java class is generated. + 2. If both *typedef* and the `struct` it refers to are included, the `typedef` class inherits from the `struct` class, which contains all the `struct` members. + 3. If the `typedef` refers to an unnamed `struct`, the generated class contains all the `struct` members. + + Case 1 looks like a bug. ## Linux @@ -24,7 +32,7 @@ To run the script, most likely the header files for *libudev* must be installed sudo apt-get install libudev-dev ``` -On Linux, *jextract* is very successful. The only limitations are: +On Linux, the limitations are: - `usbdevice_fs.h`: The macro `USBDEVFS_CONTROL` (and all similar ones) are not generated. They are probably considered a function-like macro. *jextract* does not generate code for function-like macro. But `USBDEVFS_CONTROL` is actually a constant. @@ -53,16 +61,12 @@ The generated code has the same problem as the Linux code for *udev*. It must be ## Windows -On Windows, several scripts must be run as *jextract* is a batch file that never returns. It's not possible to call it multiple times from a single script. - Most Windows SDK header files are not independent. They require that `Windows.h` is included first. So instead of specifying the target header files directly, a helper header file (`windows_headers.h` in this directory) is specified. The known limitations are: -- `typedef` to `struct`: If only the *typedef* is specified (`--include-typedef`), an empty Java class is generated. If both *typedef* and the *struct* it refers to are specified, the *typedef* class is still empty but inherits from the *struct* class, which contains all the *struct* members. - -- Variable size *struct*: Several Windows struct are of variable size. The last member is an array. The *struct* definition specifies array length 1. But you are expected to allocate more space depending on the actual array size you need. *jextract* generates code for array length 1 and when access array members, the length is checked. So the generated code isn't really usable. +- Variable size `struct`: Several Windows struct are of variable size. The last member is an array. The `struct` definition specifies array length 1. But you are expected to allocate more space depending on the actual array size you need. *jextract* generates code for array length 1 and when access array members, the length is checked. So the generated code is difficult to use. Variable size `struct`s are a pain - in any language. -- `USB_NODE_CONNECTION_INFORMATION_EX`: This struct uses a packed layout without considering alignment. The last four members are on an offset even though they are multiple bytes long. *jextract* creates the correct offsets but defines strict alignment constraints for the members. So the memory layout cannot be instantiated as it throws an exception. +- `USB_NODE_CONNECTION_INFORMATION_EX`: This struct uses a packed layout without considering alignment. The last four members are on an odd offset even though they are multiple bytes long. *jextract* creates the correct offsets but defines strict alignment constraints for the members. So the memory layout cannot be instantiated as it throws an exception. -- GUID constants like `GUID_DEVINTERFACE_USB_DEVICE` do not work. While code is generated, the code fails at run-time as it is unable to locate the symbol. This is due to the fact that `GUID_DEVINTERFACE_USB_DEVICE` actually resolve to a variable defintion and not to a variable declaration. So there is no such symbol in any library. Such constants should be skipped by *jextract*. +- GUID constants like `GUID_DEVINTERFACE_USB_DEVICE` do not work. While code is generated, the code fails at run-time as it is unable to locate the symbol. This is due to the fact that `GUID_DEVINTERFACE_USB_DEVICE` actually resolve to a variable definition and not to a variable declaration. It is not part of any library. Such constants should be skipped by *jextract*. diff --git a/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java b/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java deleted file mode 100644 index f9a32fff..00000000 --- a/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java +++ /dev/null @@ -1,23 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.mach; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -import java.nio.ByteOrder; -import java.lang.foreign.*; -import static java.lang.foreign.ValueLayout.*; -public class Constants$root { - - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); -} - - diff --git a/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java b/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java deleted file mode 100644 index ca772f77..00000000 --- a/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java +++ /dev/null @@ -1,233 +0,0 @@ -package net.codecrete.usb.macos.gen.mach; -// Generated by jextract - -import java.lang.foreign.Addressable; -import java.lang.foreign.Linker; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.MemoryAddress; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.io.File; -import java.nio.file.Path; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Optional; -import java.util.stream.Stream; - -import static java.lang.foreign.Linker.*; -import static java.lang.foreign.ValueLayout.*; - -final class RuntimeHelper { - - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); - - static { - - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); - } - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); - } - - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { - try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); - } - - // Internals only below this point - - private static class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java b/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java deleted file mode 100644 index 95f87255..00000000 --- a/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.mach; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -import java.nio.ByteOrder; -import java.lang.foreign.*; -import static java.lang.foreign.ValueLayout.*; -class constants$0 { - - static final FunctionDescriptor mach_error_string$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle mach_error_string$MH = RuntimeHelper.downcallHandle( - "mach_error_string", - constants$0.mach_error_string$FUNC - ); -} - - diff --git a/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java b/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java deleted file mode 100644 index 83147348..00000000 --- a/java-does-usb/jextract/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java +++ /dev/null @@ -1,34 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.mach; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -import java.nio.ByteOrder; -import java.lang.foreign.*; -import static java.lang.foreign.ValueLayout.*; -public class mach { - - /* package-private */ mach() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; - public static MethodHandle mach_error_string$MH() { - return RuntimeHelper.requireNonNull(constants$0.mach_error_string$MH,"mach_error_string"); - } - public static MemoryAddress mach_error_string ( int error_value) { - var mh$ = mach_error_string$MH(); - try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(error_value); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } -} - - diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd new file mode 100644 index 00000000..837f34b1 --- /dev/null +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -0,0 +1,116 @@ +set JEXTRACT=..\..\..\..\jextract-19\bin\jextract.bat +set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 + +call %JEXTRACT% --source --output ../../src/main/java ^ + -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ + -I "%SDK_DIR%\um" ^ + -I "%SDK_DIR%\shared" ^ + -l Kernel32 ^ + --header-class-name Kernel32 ^ + --target-package net.codecrete.usb.windows.gen.kernel32 ^ + --include-function CreateFileW ^ + --include-function CloseHandle ^ + --include-function DeviceIoControl ^ + --include-function GetLastError ^ + --include-function GetModuleHandleW ^ + --include-macro ERROR_SUCCESS ^ + --include-macro ERROR_NO_MORE_ITEMS ^ + --include-macro ERROR_INSUFFICIENT_BUFFER ^ + --include-macro GENERIC_READ ^ + --include-macro GENERIC_WRITE ^ + --include-macro FILE_SHARE_READ ^ + --include-macro FILE_SHARE_WRITE ^ + --include-macro FILE_ATTRIBUTE_NORMAL ^ + --include-macro FILE_FLAG_OVERLAPPED ^ + --include-macro OPEN_EXISTING ^ + --include-struct _GUID ^ + --include-typedef GUID ^ + windows_headers.h + +call %JEXTRACT% --source --output ../../src/main/java ^ + -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ + -I "%SDK_DIR%\um" ^ + -I "%SDK_DIR%\shared" ^ + -l SetupAPI ^ + --header-class-name SetupAPI ^ + --target-package net.codecrete.usb.windows.gen.setupapi ^ + --include-function SetupDiGetClassDevsW ^ + --include-function SetupDiDestroyDeviceInfoList ^ + --include-function SetupDiEnumDeviceInfo ^ + --include-function SetupDiEnumDeviceInterfaces ^ + --include-function SetupDiGetDeviceInterfaceDetailW ^ + --include-function SetupDiGetDeviceRegistryPropertyW ^ + --include-function SetupDiGetDevicePropertyW ^ + --include-function SetupDiOpenDeviceInterfaceW ^ + --include-struct _SP_DEVINFO_DATA ^ + --include-typedef SP_DEVINFO_DATA ^ + --include-struct _SP_DEVICE_INTERFACE_DATA ^ + --include-typedef SP_DEVICE_INTERFACE_DATA ^ + --include-struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W ^ + --include-typedef SP_DEVICE_INTERFACE_DETAIL_DATA_W ^ + --include-macro DIGCF_PRESENT ^ + --include-macro DIGCF_DEVICEINTERFACE ^ + --include-macro SPDRP_ADDRESS ^ + --include-macro DEVPROP_TYPE_UINT32 ^ + --include-macro DEVPROP_TYPE_STRING ^ + windows_headers.h + +call %JEXTRACT% --source --output ../../src/main/java ^ + -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ + --header-class-name StdLib ^ + --target-package net.codecrete.usb.windows.gen.stdlib ^ + --include-function wcslen ^ + windows_headers.h + +call %JEXTRACT% --source --output ../../src/main/java ^ + -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ + -I "%SDK_DIR%\um" ^ + -I "%SDK_DIR%\shared" ^ + --header-class-name USBIoctl ^ + --target-package net.codecrete.usb.windows.gen.usbioctl ^ + --include-macro IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX ^ + --include-macro IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION ^ + windows_headers.h + +call %JEXTRACT% --source --output ../../src/main/java ^ + -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ + -I "%SDK_DIR%\um" ^ + -I "%SDK_DIR%\shared" ^ + -l User32 ^ + --header-class-name User32 ^ + --target-package net.codecrete.usb.windows.gen.user32 ^ + --include-function RegisterClassExW ^ + --include-function CreateWindowExW ^ + --include-function RegisterDeviceNotificationW ^ + --include-function GetMessageW ^ + --include-function DefWindowProcW ^ + --include-macro DEVICE_NOTIFY_WINDOW_HANDLE ^ + --include-macro HWND_MESSAGE ^ + --include-macro WM_DEVICECHANGE ^ + --include-macro DBT_DEVICEARRIVAL ^ + --include-macro DBT_DEVICEREMOVECOMPLETE ^ + --include-macro DBT_DEVTYP_DEVICEINTERFACE ^ + --include-struct tagMSG ^ + --include-typedef MSG ^ + --include-struct tagWNDCLASSEXW ^ + --include-typedef WNDCLASSEXW ^ + --include-struct _DEV_BROADCAST_HDR ^ + --include-typedef DEV_BROADCAST_HDR ^ + --include-struct _DEV_BROADCAST_DEVICEINTERFACE_W ^ + --include-typedef DEV_BROADCAST_DEVICEINTERFACE_W ^ + windows_headers.h + +call %JEXTRACT% --source --output ../../src/main/java ^ + -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ + -I "%SDK_DIR%\um" ^ + -I "%SDK_DIR%\shared" ^ + -l Winusb ^ + --header-class-name WinUSB ^ + --target-package net.codecrete.usb.windows.gen.winusb ^ + --include-function WinUsb_Initialize ^ + --include-function WinUsb_Free ^ + --include-function WinUsb_GetDescriptor ^ + --include-function WinUsb_ControlTransfer ^ + --include-function WinUsb_WritePipe ^ + --include-function WinUsb_ReadPipe ^ + windows_headers.h diff --git a/java-does-usb/jextract/windows/gen_win_kernel32.cmd b/java-does-usb/jextract/windows/gen_win_kernel32.cmd deleted file mode 100644 index 9a861e1d..00000000 --- a/java-does-usb/jextract/windows/gen_win_kernel32.cmd +++ /dev/null @@ -1,27 +0,0 @@ -set JEXTRACT=..\..\..\..\jextract-19\bin\jextract.bat -set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 -%JEXTRACT% --source --output ../../src/main/java ^ - -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ - -I "%SDK_DIR%\um" ^ - -I "%SDK_DIR%\shared" ^ - -l Kernel32 ^ - --header-class-name Kernel32 ^ - --target-package net.codecrete.usb.windows.gen.kernel32 ^ - --include-function CreateFileW ^ - --include-function CloseHandle ^ - --include-function DeviceIoControl ^ - --include-function GetLastError ^ - --include-function GetModuleHandleW ^ - --include-macro ERROR_SUCCESS ^ - --include-macro ERROR_NO_MORE_ITEMS ^ - --include-macro ERROR_INSUFFICIENT_BUFFER ^ - --include-macro GENERIC_READ ^ - --include-macro GENERIC_WRITE ^ - --include-macro FILE_SHARE_READ ^ - --include-macro FILE_SHARE_WRITE ^ - --include-macro FILE_ATTRIBUTE_NORMAL ^ - --include-macro FILE_FLAG_OVERLAPPED ^ - --include-macro OPEN_EXISTING ^ - --include-struct _GUID ^ - --include-typedef GUID ^ - windows_headers.h diff --git a/java-does-usb/jextract/windows/gen_win_setupapi.cmd b/java-does-usb/jextract/windows/gen_win_setupapi.cmd deleted file mode 100644 index 53b3b335..00000000 --- a/java-does-usb/jextract/windows/gen_win_setupapi.cmd +++ /dev/null @@ -1,29 +0,0 @@ -set JEXTRACT=..\..\..\..\jextract-19\bin\jextract.bat -set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 -%JEXTRACT% --source --output ../../src/main/java ^ - -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ - -I "%SDK_DIR%\um" ^ - -I "%SDK_DIR%\shared" ^ - -l SetupAPI ^ - --header-class-name SetupAPI ^ - --target-package net.codecrete.usb.windows.gen.setupapi ^ - --include-function SetupDiGetClassDevsW ^ - --include-function SetupDiDestroyDeviceInfoList ^ - --include-function SetupDiEnumDeviceInfo ^ - --include-function SetupDiEnumDeviceInterfaces ^ - --include-function SetupDiGetDeviceInterfaceDetailW ^ - --include-function SetupDiGetDeviceRegistryPropertyW ^ - --include-function SetupDiGetDevicePropertyW ^ - --include-function SetupDiOpenDeviceInterfaceW ^ - --include-struct _SP_DEVINFO_DATA ^ - --include-typedef SP_DEVINFO_DATA ^ - --include-struct _SP_DEVICE_INTERFACE_DATA ^ - --include-typedef SP_DEVICE_INTERFACE_DATA ^ - --include-struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W ^ - --include-typedef SP_DEVICE_INTERFACE_DETAIL_DATA_W ^ - --include-macro DIGCF_PRESENT ^ - --include-macro DIGCF_DEVICEINTERFACE ^ - --include-macro SPDRP_ADDRESS ^ - --include-macro DEVPROP_TYPE_UINT32 ^ - --include-macro DEVPROP_TYPE_STRING ^ - windows_headers.h diff --git a/java-does-usb/jextract/windows/gen_win_stdlib.cmd b/java-does-usb/jextract/windows/gen_win_stdlib.cmd deleted file mode 100644 index bc23beb8..00000000 --- a/java-does-usb/jextract/windows/gen_win_stdlib.cmd +++ /dev/null @@ -1,7 +0,0 @@ -set JEXTRACT=..\..\..\..\jextract-19\bin\jextract.bat -%JEXTRACT% --source --output ../../src/main/java ^ - -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ - --header-class-name StdLib ^ - --target-package net.codecrete.usb.windows.gen.stdlib ^ - --include-function wcslen ^ - windows_headers.h diff --git a/java-does-usb/jextract/windows/gen_win_usbioctl.cmd b/java-does-usb/jextract/windows/gen_win_usbioctl.cmd deleted file mode 100644 index ccb9402a..00000000 --- a/java-does-usb/jextract/windows/gen_win_usbioctl.cmd +++ /dev/null @@ -1,11 +0,0 @@ -set JEXTRACT=..\..\..\..\jextract-19\bin\jextract.bat -set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 -%JEXTRACT% --source --output ../../src/main/java ^ - -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ - -I "%SDK_DIR%\um" ^ - -I "%SDK_DIR%\shared" ^ - --header-class-name USBIoctl ^ - --target-package net.codecrete.usb.windows.gen.usbioctl ^ - --include-macro IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX ^ - --include-macro IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION ^ - windows_headers.h diff --git a/java-does-usb/jextract/windows/gen_win_user32.cmd b/java-does-usb/jextract/windows/gen_win_user32.cmd deleted file mode 100644 index 3a17da1a..00000000 --- a/java-does-usb/jextract/windows/gen_win_user32.cmd +++ /dev/null @@ -1,29 +0,0 @@ -set JEXTRACT=..\..\..\..\jextract-19\bin\jextract.bat -set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 -%JEXTRACT% --source --output ../../src/main/java ^ - -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ - -I "%SDK_DIR%\um" ^ - -I "%SDK_DIR%\shared" ^ - -l User32 ^ - --header-class-name User32 ^ - --target-package net.codecrete.usb.windows.gen.user32 ^ - --include-function RegisterClassExW ^ - --include-function CreateWindowExW ^ - --include-function RegisterDeviceNotificationW ^ - --include-function GetMessageW ^ - --include-function DefWindowProcW ^ - --include-macro DEVICE_NOTIFY_WINDOW_HANDLE ^ - --include-macro HWND_MESSAGE ^ - --include-macro WM_DEVICECHANGE ^ - --include-macro DBT_DEVICEARRIVAL ^ - --include-macro DBT_DEVICEREMOVECOMPLETE ^ - --include-macro DBT_DEVTYP_DEVICEINTERFACE ^ - --include-struct tagMSG ^ - --include-typedef MSG ^ - --include-struct tagWNDCLASSEXW ^ - --include-typedef WNDCLASSEXW ^ - --include-struct _DEV_BROADCAST_HDR ^ - --include-typedef DEV_BROADCAST_HDR ^ - --include-struct _DEV_BROADCAST_DEVICEINTERFACE_W ^ - --include-typedef DEV_BROADCAST_DEVICEINTERFACE_W ^ - windows_headers.h diff --git a/java-does-usb/jextract/windows/gen_win_winusb.cmd b/java-does-usb/jextract/windows/gen_win_winusb.cmd deleted file mode 100644 index b1ed1327..00000000 --- a/java-does-usb/jextract/windows/gen_win_winusb.cmd +++ /dev/null @@ -1,16 +0,0 @@ -set JEXTRACT=..\..\..\..\jextract-19\bin\jextract.bat -set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 -%JEXTRACT% --source --output ../../src/main/java ^ - -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ - -I "%SDK_DIR%\um" ^ - -I "%SDK_DIR%\shared" ^ - -l Winusb ^ - --header-class-name WinUSB ^ - --target-package net.codecrete.usb.windows.gen.winusb ^ - --include-function WinUsb_Initialize ^ - --include-function WinUsb_Free ^ - --include-function WinUsb_GetDescriptor ^ - --include-function WinUsb_ControlTransfer ^ - --include-function WinUsb_WritePipe ^ - --include-function WinUsb_ReadPipe ^ - windows_headers.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index cb197091..f38cf07f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -13,7 +13,6 @@ import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.common.USBDeviceRegistry; import net.codecrete.usb.common.USBStructs; -import net.codecrete.usb.macos.MacosUSBDevice; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.setupapi.SP_DEVICE_INTERFACE_DATA; import net.codecrete.usb.windows.gen.setupapi.SP_DEVINFO_DATA; From c0bd004dba21abe19235c1151ac26a312d94f584 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Tue, 6 Sep 2022 22:48:41 +0200 Subject: [PATCH 065/433] macOS: Fix path --- java-does-usb/jextract/macos/gen_macos.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index 03ffa77c..aecbf5fe 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -59,7 +59,7 @@ $JEXTRACT --source --output ../../src/main/java \ iokit_helper.h # mach.h -$JEXTRACT --source --output ../src/main/java \ +$JEXTRACT --source --output ../../src/main/java \ -I $SDK_DIR/usr/include \ --header-class-name mach \ --target-package net.codecrete.usb.macos.gen.mach \ From 3102d26a263304beaf50fa5e27cdff5e4c740c6b Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Wed, 7 Sep 2022 19:40:32 +0200 Subject: [PATCH 066/433] macOS: Remove CFUUID hack --- java-does-usb/jextract/README.md | 22 +++++++-- java-does-usb/jextract/macos/gen_macos.sh | 3 +- .../net/codecrete/usb/macos/IoKitHelper.java | 5 +-- .../java/net/codecrete/usb/macos/UUID.java | 14 ------ .../gen/corefoundation/CoreFoundation.java | 14 +++++- .../macos/gen/corefoundation/constants$1.java | 45 +++++++++---------- .../macos/gen/corefoundation/constants$2.java | 37 +++++++++++++++ 7 files changed, 94 insertions(+), 46 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index fce509dd..aafa701b 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -13,7 +13,7 @@ The resulting code is then committed to the source code repository. Before the c ## General limitations -- Binaries of *jextract* can be downloaded from https://jdk.java.net/jextract/. x64 binaries are available but no ARM64. According to the mailing list, cross-compiling is not possible, i.e. ARM64 binaries are needed on macOS with Apple Silicon. But so far, the x64 binaries have worked without problems. +- Binaries of *jextract* can be downloaded from https://jdk.java.net/jextract/. x64 binaries are available but no ARM64 binaries. According to the mailing list, cross-compiling is not possible, i.e. ARM64 binaries are needed on macOS with Apple Silicon. But so far, the x64 binaries (using the Rosetta2 emulation) have worked without problems. - `typedef` and `struct`: @@ -23,6 +23,16 @@ The resulting code is then committed to the source code repository. Before the c Case 1 looks like a bug. +- *jextract* is not really transparent about what it does. It often skips elements without providing any information. In particular, it will silently skip a requested element in these cases: + + - `--include-var myvar` if `myvar` is declared as `static`. + - `--include-var myvar` if `myvar` is an `enum` constant. `enum` constants must be requested with `--include-macro`. + - `--include-macro MYMACRO` if `MYMACRO` is function-like, even if it evaluates to a constant. + - `--include-struct mystruct` if `mystruct` is actually a `typedef` to a `struct`. + - `--include-typedef mystruct` if `mystruct` is actually a `struct`. + - `--include-typedef mytypedef` if `mytypedef` is a `typedef` for a primitive type. + + ## Linux @@ -34,9 +44,9 @@ sudo apt-get install libudev-dev On Linux, the limitations are: -- `usbdevice_fs.h`: The macro `USBDEVFS_CONTROL` (and all similar ones) are not generated. They are probably considered a function-like macro. *jextract* does not generate code for function-like macro. But `USBDEVFS_CONTROL` is actually a constant. +- `usbdevice_fs.h`: The macro `USBDEVFS_CONTROL` and all similar ones are not generated. They are probably considered function-like macros. *jextract* does not generate code for function-like macros. But `USBDEVFS_CONTROL` evaluates to a constant. -- `sd-device.h` (header file for *libsystemd*): *jextract* fails with *"Error: /usr/include/inttypes.h:290:8: error: unknown type name 'intmax_t'"*. The reason is yet unknown. This code is currently not needed as it uses *libudev* instead of *libsystemd*. They are related, *libsystemd* is the future solution, but it is missing support for monitoring devices. +- `sd-device.h` (header file for *libsystemd*): *jextract* fails with *"Error: /usr/include/inttypes.h:290:8: error: unknown type name 'intmax_t'"*. The reason is yet unknown. This code is currently not needed as *libudev* is used instead of *libsystemd*. They are related, *libsystemd* is the future solution, but it is missing support for monitoring devices. - `libudev.h`: After code generation, the class `RuntimeHelper.java` in `.../linux/gen/udev` must be manually modified as the code to access the library does not work for the directory the library is located in. So replace: @@ -70,3 +80,9 @@ The known limitations are: - `USB_NODE_CONNECTION_INFORMATION_EX`: This struct uses a packed layout without considering alignment. The last four members are on an odd offset even though they are multiple bytes long. *jextract* creates the correct offsets but defines strict alignment constraints for the members. So the memory layout cannot be instantiated as it throws an exception. - GUID constants like `GUID_DEVINTERFACE_USB_DEVICE` do not work. While code is generated, the code fails at run-time as it is unable to locate the symbol. This is due to the fact that `GUID_DEVINTERFACE_USB_DEVICE` actually resolve to a variable definition and not to a variable declaration. It is not part of any library. Such constants should be skipped by *jextract*. + +- *jextract* is a batch script and turns off *echo mode*. If a single batch scripts has multiple calls of *jextract*, two things need to be considered: + + - If the regular command interpreter `cmd.exe` is used, *jextract* must be called using `call`, i.e. `call jextract header.h`. + - If *PowerShell* is used instead, `call` is not needed but *PowerShell* must be configured to allow the execution of scripts. + - *jextract* turns off *echo mode*. So the first call will behave differently than the following calls. diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index aecbf5fe..c90d5cbe 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -1,7 +1,7 @@ #!/bin/sh JEXTRACT=../../../../jextract-19/bin/jextract -# If SDK_DIR is changed, it needs to be changed in compiler flags as well. +# If SDK_DIR is changed, it needs to be changed in compile_flags.txt as well. SDK_DIR=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk # CoreFoundation @@ -24,6 +24,7 @@ $JEXTRACT --source --output ../../src/main/java \ --include-function CFRunLoopGetCurrent \ --include-function CFRunLoopAddSource \ --include-function CFRunLoopRun \ + --include-function CFUUIDGetUUIDBytes \ --include-macro kCFNumberSInt32Type \ cf_helper.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index 832eda71..4e03bda3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -7,7 +7,6 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.macos.gen.corefoundation.CFUUIDBytes; import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; import net.codecrete.usb.macos.gen.iokit.IOKit; @@ -19,7 +18,6 @@ import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.ADDRESS; import static java.lang.foreign.ValueLayout.JAVA_INT; -import static net.codecrete.usb.macos.UUID.CFUUID_bytes$Offset; /** * Constants and helper functions for the IOKit framework. @@ -73,8 +71,7 @@ public static MemoryAddress getInterface(int service, Addressable pluginType, Me // MemorySegment for holding xxxInterface** var intfHolder = session.allocate(ADDRESS, NULL); // UUID bytes - var refiid = MemorySegment.ofAddress(interfaceId.addOffset(CFUUID_bytes$Offset), CFUUIDBytes.sizeof(), - session); + var refiid = CoreFoundation.CFUUIDGetUUIDBytes(session, interfaceId); ret = IoKitUSB.QueryInterface(plug, refiid, intfHolder.address()); IoKitUSB.Release(plug); if (ret != 0) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java index e7761f51..cccaa04c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java @@ -7,32 +7,18 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.macos.gen.corefoundation.CFUUIDBytes; import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; -import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryAddress; -import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySession; import static java.lang.foreign.MemoryAddress.NULL; -import static java.lang.foreign.MemoryLayout.sequenceLayout; -import static java.lang.foreign.MemoryLayout.structLayout; -import static java.lang.foreign.ValueLayout.*; /** * Memory layouts and helpers for CFUUID. */ public class UUID { - public static final GroupLayout CFUUID = structLayout( - ADDRESS.withName("_cfisa"), // uintptr_t _cfisa; - sequenceLayout(4, JAVA_BYTE).withName("_cfinfo"), // uint8_t _cfinfo[4]; - JAVA_INT.withName("_rc"), // uint32_t _rc; - CFUUIDBytes.$LAYOUT().withName("_bytes") // CFUUIDBytes _bytes; - ); - public static final long CFUUID_bytes$Offset = CFUUID.byteOffset(MemoryLayout.PathElement.groupElement("_bytes")); - /** * Creates a CFUUID struct from a byte array. * @param bytes UUID as 16 bytes diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java index df785d3a..2e501cd5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java @@ -5,6 +5,7 @@ import java.lang.foreign.Addressable; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; @@ -143,8 +144,19 @@ public static void CFRunLoopAddSource ( Addressable rl, Addressable source, Ad throw new AssertionError("should not reach here", ex$); } } + public static MethodHandle CFUUIDGetUUIDBytes$MH() { + return RuntimeHelper.requireNonNull(constants$1.CFUUIDGetUUIDBytes$MH,"CFUUIDGetUUIDBytes"); + } + public static MemorySegment CFUUIDGetUUIDBytes ( SegmentAllocator allocator, Addressable uuid) { + var mh$ = CFUUIDGetUUIDBytes$MH(); + try { + return (java.lang.foreign.MemorySegment)mh$.invokeExact(allocator, uuid); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static MethodHandle CFUUIDCreateFromUUIDBytes$MH() { - return RuntimeHelper.requireNonNull(constants$1.CFUUIDCreateFromUUIDBytes$MH,"CFUUIDCreateFromUUIDBytes"); + return RuntimeHelper.requireNonNull(constants$2.CFUUIDCreateFromUUIDBytes$MH,"CFUUIDCreateFromUUIDBytes"); } public static MemoryAddress CFUUIDCreateFromUUIDBytes ( Addressable alloc, MemorySegment bytes) { var mh$ = CFUUIDCreateFromUUIDBytes$MH(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java index f98c85dc..16dac46b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java @@ -40,30 +40,29 @@ class constants$1 { "CFRunLoopAddSource", constants$1.CFRunLoopAddSource$FUNC ); - static final FunctionDescriptor CFUUIDCreateFromUUIDBytes$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("byte0"), - Constants$root.C_CHAR$LAYOUT.withName("byte1"), - Constants$root.C_CHAR$LAYOUT.withName("byte2"), - Constants$root.C_CHAR$LAYOUT.withName("byte3"), - Constants$root.C_CHAR$LAYOUT.withName("byte4"), - Constants$root.C_CHAR$LAYOUT.withName("byte5"), - Constants$root.C_CHAR$LAYOUT.withName("byte6"), - Constants$root.C_CHAR$LAYOUT.withName("byte7"), - Constants$root.C_CHAR$LAYOUT.withName("byte8"), - Constants$root.C_CHAR$LAYOUT.withName("byte9"), - Constants$root.C_CHAR$LAYOUT.withName("byte10"), - Constants$root.C_CHAR$LAYOUT.withName("byte11"), - Constants$root.C_CHAR$LAYOUT.withName("byte12"), - Constants$root.C_CHAR$LAYOUT.withName("byte13"), - Constants$root.C_CHAR$LAYOUT.withName("byte14"), - Constants$root.C_CHAR$LAYOUT.withName("byte15") - ) + static final FunctionDescriptor CFUUIDGetUUIDBytes$FUNC = FunctionDescriptor.of(MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("byte0"), + Constants$root.C_CHAR$LAYOUT.withName("byte1"), + Constants$root.C_CHAR$LAYOUT.withName("byte2"), + Constants$root.C_CHAR$LAYOUT.withName("byte3"), + Constants$root.C_CHAR$LAYOUT.withName("byte4"), + Constants$root.C_CHAR$LAYOUT.withName("byte5"), + Constants$root.C_CHAR$LAYOUT.withName("byte6"), + Constants$root.C_CHAR$LAYOUT.withName("byte7"), + Constants$root.C_CHAR$LAYOUT.withName("byte8"), + Constants$root.C_CHAR$LAYOUT.withName("byte9"), + Constants$root.C_CHAR$LAYOUT.withName("byte10"), + Constants$root.C_CHAR$LAYOUT.withName("byte11"), + Constants$root.C_CHAR$LAYOUT.withName("byte12"), + Constants$root.C_CHAR$LAYOUT.withName("byte13"), + Constants$root.C_CHAR$LAYOUT.withName("byte14"), + Constants$root.C_CHAR$LAYOUT.withName("byte15") + ), + Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle CFUUIDCreateFromUUIDBytes$MH = RuntimeHelper.downcallHandle( - "CFUUIDCreateFromUUIDBytes", - constants$1.CFUUIDCreateFromUUIDBytes$FUNC + static final MethodHandle CFUUIDGetUUIDBytes$MH = RuntimeHelper.downcallHandle( + "CFUUIDGetUUIDBytes", + constants$1.CFUUIDGetUUIDBytes$FUNC ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java new file mode 100644 index 00000000..9558038b --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java @@ -0,0 +1,37 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.corefoundation; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +class constants$2 { + + static final FunctionDescriptor CFUUIDCreateFromUUIDBytes$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("byte0"), + Constants$root.C_CHAR$LAYOUT.withName("byte1"), + Constants$root.C_CHAR$LAYOUT.withName("byte2"), + Constants$root.C_CHAR$LAYOUT.withName("byte3"), + Constants$root.C_CHAR$LAYOUT.withName("byte4"), + Constants$root.C_CHAR$LAYOUT.withName("byte5"), + Constants$root.C_CHAR$LAYOUT.withName("byte6"), + Constants$root.C_CHAR$LAYOUT.withName("byte7"), + Constants$root.C_CHAR$LAYOUT.withName("byte8"), + Constants$root.C_CHAR$LAYOUT.withName("byte9"), + Constants$root.C_CHAR$LAYOUT.withName("byte10"), + Constants$root.C_CHAR$LAYOUT.withName("byte11"), + Constants$root.C_CHAR$LAYOUT.withName("byte12"), + Constants$root.C_CHAR$LAYOUT.withName("byte13"), + Constants$root.C_CHAR$LAYOUT.withName("byte14"), + Constants$root.C_CHAR$LAYOUT.withName("byte15") + ) + ); + static final MethodHandle CFUUIDCreateFromUUIDBytes$MH = RuntimeHelper.downcallHandle( + "CFUUIDCreateFromUUIDBytes", + constants$2.CFUUIDCreateFromUUIDBytes$FUNC + ); +} + + From d8761fc960dd6e50761cab733b306a7ae0718e58 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Wed, 7 Sep 2022 21:27:46 +0200 Subject: [PATCH 067/433] Interrupt endpoints for test device --- .../net/codecrete/usb/DescriptionTest.java | 14 +++- test-devices/loopback-stm32/README.md | 13 +++- .../loopback-stm32/include/usb_descriptor.h | 2 + test-devices/loopback-stm32/src/main.cpp | 76 ++++++++++++++----- .../loopback-stm32/src/usb_descriptor.cpp | 20 +++++ 5 files changed, 102 insertions(+), 23 deletions(-) diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index db78f93b..60162543 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -58,7 +58,7 @@ void alternateInterfaceDescriptors_isCorrect() { void endpointDescriptors_isCorrect() { var altIntf = testDevice.interfaces().get(0).alternate(); assertNotNull(altIntf.endpoints()); - assertEquals(2, altIntf.endpoints().size()); + assertEquals(4, altIntf.endpoints().size()); var endpoint = altIntf.endpoints().get(0); assertEquals(1, endpoint.number()); @@ -71,5 +71,17 @@ void endpointDescriptors_isCorrect() { assertEquals(USBDirection.IN, endpoint.direction()); assertEquals(USBTransferType.BULK, endpoint.transferType()); assertEquals(64, endpoint.packetSize()); + + endpoint = altIntf.endpoints().get(2); + assertEquals(3, endpoint.number()); + assertEquals(USBDirection.OUT, endpoint.direction()); + assertEquals(USBTransferType.INTERRUPT, endpoint.transferType()); + assertEquals(16, endpoint.packetSize()); + + endpoint = altIntf.endpoints().get(3); + assertEquals(3, endpoint.number()); + assertEquals(USBDirection.IN, endpoint.direction()); + assertEquals(USBTransferType.INTERRUPT, endpoint.transferType()); + assertEquals(16, endpoint.packetSize()); } } diff --git a/test-devices/loopback-stm32/README.md b/test-devices/loopback-stm32/README.md index e66aa28b..29105953 100644 --- a/test-devices/loopback-stm32/README.md +++ b/test-devices/loopback-stm32/README.md @@ -5,9 +5,18 @@ For testing the *Java Does USB* library, a dedicated USB test device is needed. ## Test features -### Loopback +### Endpoints + +| Endpoint | Transfer Type | Direction | Packet Size | Function | +| - | - | - | - | - | +| 0x00 | Control | Bidirectional | | See *Control requests* below | +| 0x01 | Bulk | Host to device | 64 bytes | Loopback: all data received on this endpoint are then transmitted on endpoint 0x82. | +| 0x82 | Bulk | Device to host | 64 bytes | Loopback: Transmits the data received on endpoint 0x01. | +| 0x03 | Interrupt | Host to device | 16 bytes | Echo: All packets received on this endpoint are transmitted twice on endpoint 0x83. | +| 0x83 | Interrupt | Device to host | 16 bytes | Echo: Transmits all packets received on endpoint 0x03 twice. | + +The bulk endpoints 0x01 and 0x82 use an internal buffer of about 1000 bytes. Data up to this amount can be sent and received sequentially. If more data is sent without receiving at the same time, flow control kicks in and endpoint 0x01 will stop receiving data until there is room in the buffer. -All data sent to endpoint 0x01 (OUT) is sent back on endpoint 0x82 (IN). Both endpoints use bulk transfer with a maximum packet size of 64 bytes. The device uses an internal buffer of about 1000 bytes. Up to this amount, the data can be first sent and then received. ### Control requests diff --git a/test-devices/loopback-stm32/include/usb_descriptor.h b/test-devices/loopback-stm32/include/usb_descriptor.h index 6a5df74a..d200756a 100644 --- a/test-devices/loopback-stm32/include/usb_descriptor.h +++ b/test-devices/loopback-stm32/include/usb_descriptor.h @@ -19,6 +19,8 @@ // Endpoints #define EP_LOOPBACK_RX 0x01 #define EP_LOOPBACK_TX 0x82 +#define EP_ECHO_RX 0x03 +#define EP_ECHO_TX 0x83 // USB descriptor string table extern const char *const usb_desc_strings[4]; diff --git a/test-devices/loopback-stm32/src/main.cpp b/test-devices/loopback-stm32/src/main.cpp index cc39f21f..8d049e4a 100644 --- a/test-devices/loopback-stm32/src/main.cpp +++ b/test-devices/loopback-stm32/src/main.cpp @@ -23,8 +23,10 @@ static void on_usb_set_config(usbd_device *usbd_dev, uint16_t wValue); static usbd_request_return_codes on_usb_control_request(usbd_device *usbd_dev, usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete); -static void on_usb_data_received(usbd_device *usbd_dev, uint8_t ep); -static void on_usb_data_transmitted(usbd_device *usbd_dev, uint8_t ep); +static void on_usb_loopback_received(usbd_device *usbd_dev, uint8_t ep); +static void on_usb_loopback_transmitted(usbd_device *usbd_dev, uint8_t ep); +static void on_usb_echo_received(usbd_device *usbd_dev, uint8_t ep); +static void on_usb_echo_transmitted(usbd_device *usbd_dev, uint8_t ep); static void check_buffers(); // USB device instance @@ -40,14 +42,23 @@ static circ_buf<1024> buffer; static constexpr int MIN_FREE_SPACE = 2 * BULK_MAX_PACKET_SIZE; // indicates if loopback data is being transmitted -static volatile bool is_transmitting = false; +static bool is_loopback_tx = false; -// indicates if the endpoint is forced to NAK to prevent receiving further data -static volatile bool is_forced_nak = false; +// indicates if the loopback RX endpoint is forced to NAK to prevent receiving further data +static bool is_loopback_rx_nak = false; // value that can be saved and retrieved with control requests static uint32_t saved_value; +// echo message +static char echo_msg[INTR_MAX_PACKET_SIZE]; + +// echo message length +static int echo_msg_len; + +// number of echos left to transmit (if > 1, RX endpointed is NAKed) +static int num_echos_left; + void init() { // Enable required clocks @@ -90,38 +101,42 @@ void on_usb_set_config(usbd_device *usbd_dev, __attribute__((unused)) uint16_t w USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, on_usb_control_request); - usbd_ep_setup(usbd_dev, EP_LOOPBACK_RX, USB_ENDPOINT_ATTR_BULK, BULK_MAX_PACKET_SIZE, on_usb_data_received); - usbd_ep_setup(usbd_dev, EP_LOOPBACK_TX, USB_ENDPOINT_ATTR_BULK, BULK_MAX_PACKET_SIZE, on_usb_data_transmitted); + usbd_ep_setup(usbd_dev, EP_LOOPBACK_RX, USB_ENDPOINT_ATTR_BULK, BULK_MAX_PACKET_SIZE, on_usb_loopback_received); + usbd_ep_setup(usbd_dev, EP_LOOPBACK_TX, USB_ENDPOINT_ATTR_BULK, BULK_MAX_PACKET_SIZE, on_usb_loopback_transmitted); + usbd_ep_setup(usbd_dev, EP_ECHO_RX, USB_ENDPOINT_ATTR_INTERRUPT, INTR_MAX_PACKET_SIZE, on_usb_echo_received); + usbd_ep_setup(usbd_dev, EP_ECHO_TX, USB_ENDPOINT_ATTR_INTERRUPT, INTR_MAX_PACKET_SIZE, on_usb_echo_transmitted); buffer.reset(); - is_transmitting = false; - is_forced_nak = false; + is_loopback_tx = false; + is_loopback_rx_nak = false; + num_echos_left = 0; + echo_msg_len = 0; saved_value = 0; } -// Called when data has been received -void on_usb_data_received(__attribute__((unused)) usbd_device *usbd_dev, __attribute__((unused)) uint8_t ep) { +// Called when loopback data has been received +void on_usb_loopback_received(usbd_device *usbd_dev, uint8_t ep) { // Retrieve USB data (has side effect of setting endpoint to VALID) uint8_t packet[BULK_MAX_PACKET_SIZE] __attribute__((aligned(4))); - int len = usbd_ep_read_packet(usb_device, EP_LOOPBACK_RX, packet, sizeof(packet)); + int len = usbd_ep_read_packet(usbd_dev, ep, packet, sizeof(packet)); // copy data into circular buffer buffer.add_data(packet, len); } -// Called when data has been transmitted -void on_usb_data_transmitted(__attribute__((unused)) usbd_device *usbd_dev, __attribute__((unused)) uint8_t ep) { - is_transmitting = false; +// Called when loopback data has been transmitted +void on_usb_loopback_transmitted(__attribute__((unused)) usbd_device *usbd_dev, __attribute__((unused)) uint8_t ep) { + is_loopback_tx = false; } void check_buffers() { // If RX is stopped and there is sufficient space in the buffer, resume it - if (is_forced_nak) { + if (is_loopback_rx_nak) { if (buffer.avail_size() >= MIN_FREE_SPACE) { usbd_ep_nak_set(usb_device, EP_LOOPBACK_RX, 0); - is_forced_nak = false; + is_loopback_rx_nak = false; } // If RX is enabled but the space in the buffer is low, stop it @@ -130,19 +145,40 @@ void check_buffers() { if (buffer.avail_size() < MIN_FREE_SPACE) { // set endpoint from VALID to NAK usbd_ep_nak_set(usb_device, EP_LOOPBACK_RX, 1); - is_forced_nak = true; + is_loopback_rx_nak = true; } } // If no data is being transmitted and there is data in the buffer, transmit a packet - if (!is_transmitting && buffer.data_size() >= 0) { + if (!is_loopback_tx && buffer.data_size() >= 0) { uint8_t packet[BULK_MAX_PACKET_SIZE] __attribute__((aligned(4))); int len = buffer.get_data(packet, BULK_MAX_PACKET_SIZE); usbd_ep_write_packet(usb_device, EP_LOOPBACK_TX, packet, len); - is_transmitting = true; + is_loopback_tx = true; + } +} + +// Called when echo data has been received +void on_usb_echo_received(usbd_device *usbd_dev,uint8_t ep) { + // Retrieve USB data (has side effect of setting endpoint to VALID) + echo_msg_len = usbd_ep_read_packet(usbd_dev, EP_ECHO_RX, echo_msg, sizeof(echo_msg)); + usbd_ep_nak_set(usbd_dev, ep, 1); + + usbd_ep_write_packet(usbd_dev, EP_ECHO_TX, echo_msg, echo_msg_len); + num_echos_left = 2; +} + +// Called when echo data has been transmitted +void on_usb_echo_transmitted(__attribute__((unused)) usbd_device *usbd_dev, __attribute__((unused)) uint8_t ep) { + num_echos_left--; + if (num_echos_left > 0) { + usbd_ep_write_packet(usbd_dev, ep, echo_msg, echo_msg_len); + } else { + usbd_ep_nak_set(usbd_dev, EP_ECHO_RX, 0); } } + usbd_request_return_codes on_usb_control_request( __attribute__((unused)) usbd_device *usbd_dev, usb_setup_data *req, uint8_t **buf, uint16_t *len, __attribute__((unused)) usbd_control_complete_callback *complete) { diff --git a/test-devices/loopback-stm32/src/usb_descriptor.cpp b/test-devices/loopback-stm32/src/usb_descriptor.cpp index 1c19a7bd..7c26184c 100644 --- a/test-devices/loopback-stm32/src/usb_descriptor.cpp +++ b/test-devices/loopback-stm32/src/usb_descriptor.cpp @@ -57,6 +57,26 @@ static const struct usb_endpoint_descriptor comm_endpoint_descs[] = { .extra = nullptr, .extralen = 0, }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = EP_ECHO_RX, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = INTR_MAX_PACKET_SIZE, + .bInterval = 16, + .extra = nullptr, + .extralen = 0, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = EP_ECHO_TX, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = INTR_MAX_PACKET_SIZE, + .bInterval = 16, + .extra = nullptr, + .extralen = 0, + }, }; static const struct usb_interface_descriptor comm_if_descs[] = { From f217f22cfb52995bc40f466c7d6123a41080cbe3 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Wed, 7 Sep 2022 21:44:06 +0200 Subject: [PATCH 068/433] macOS: add interrupt transfer --- .../codecrete/usb/macos/MacosUSBDevice.java | 19 ++++++--- .../net/codecrete/usb/BulkTransferTest.java | 8 ---- .../codecrete/usb/InterruptTransferTest.java | 39 +++++++++++++++++++ .../codecrete/usb/InvalidOperationTest.java | 4 +- .../net/codecrete/usb/TestDeviceBase.java | 9 +++++ 5 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 1a965ed8..33bbe34d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -245,16 +245,23 @@ private void updateEndpointList() { } } - private EndpointInfo getEndpointInfo(int endpointNumber, USBDirection direction, USBTransferType transferType) { + private EndpointInfo getEndpointInfo(int endpointNumber, USBDirection direction, + USBTransferType transferType1, USBTransferType transferType2) { if (endpoints != null) { byte endpointAddress = (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)); var endpointInfo = endpoints.get(endpointAddress); - if (endpointInfo != null && endpointInfo.transferType == transferType) + if (endpointInfo != null + && (endpointInfo.transferType == transferType1 || endpointInfo.transferType == transferType2)) return endpointInfo; } + String transferTypeDesc; + if (transferType2 == null) + transferTypeDesc = transferType1.name(); + else + transferTypeDesc = String.format("%s or %s", transferType1.name(), transferType2.name()); throw new USBException(String.format("Endpoint number %d does not exist, is not part of a claimed interface " + - "or is not valid for %s transfer in %s direction", endpointNumber, transferType.name(), + "or is not valid for %s transfer in %s direction", endpointNumber, transferTypeDesc, direction.name())); } @@ -306,7 +313,8 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { @Override public void transferOut(int endpointNumber, byte[] data) { - var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK); + var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, + USBTransferType.BULK, USBTransferType.INTERRUPT); try (var session = MemorySession.openConfined()) { var nativeData = session.allocateArray(JAVA_BYTE, data.length); @@ -321,7 +329,8 @@ public void transferOut(int endpointNumber, byte[] data) { @Override public byte[] transferIn(int endpointNumber, int maxLength) { - var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK); + var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.IN, + USBTransferType.BULK, USBTransferType.INTERRUPT); try (var session = MemorySession.openConfined()) { var nativeData = session.allocateArray(JAVA_BYTE, maxLength); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java index 5f35b870..1c903fe3 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java @@ -13,7 +13,6 @@ import java.io.ByteArrayOutputStream; import java.util.Arrays; -import java.util.Random; import java.util.concurrent.CompletableFuture; import static org.junit.jupiter.api.Assertions.assertArrayEquals; @@ -73,11 +72,4 @@ static byte[] readBytes(int numBytes) { } return buffer.toByteArray(); } - - static byte[] generateRandomBytes(int numBytes, long seed) { - var random = new Random(seed); - var bytes = new byte[numBytes]; - random.nextBytes(bytes); - return bytes; - } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java new file mode 100644 index 00000000..832393ff --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java @@ -0,0 +1,39 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Unit test for bulk transfer +// + +package net.codecrete.usb; + +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +public class InterruptTransferTest extends TestDeviceBase { + + private static final int ECHO_EP_OUT = 3; + private static final int ECHO_EP_IN = 3; + private static final int MAX_PACKET_SIZE = 16; + + @Test + void smallTransfer_succeeds() { + byte[] sampleData = generateRandomBytes(12, 293872394); + testDevice.transferOut(ECHO_EP_OUT, sampleData); + + // receive first echo + byte[] echo = testDevice.transferIn(ECHO_EP_IN, MAX_PACKET_SIZE); + assertArrayEquals(sampleData, echo); + + // receive second echo + echo = testDevice.transferIn(ECHO_EP_IN, MAX_PACKET_SIZE); + assertArrayEquals(sampleData, echo); + } +} diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java index fcd5df47..4f135009 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java @@ -38,12 +38,12 @@ void invalidEndpoint_throws() { Assertions.assertThrows(USBException.class, () -> testDevice.transferOut(0, data)); - Assertions.assertThrows(USBException.class, () -> testDevice.transferOut(3, data)); + Assertions.assertThrows(USBException.class, () -> testDevice.transferOut(4, data)); Assertions.assertThrows(USBException.class, () -> testDevice.transferIn(1, 64)); Assertions.assertThrows(USBException.class, () -> testDevice.transferIn(0, 64)); - Assertions.assertThrows(USBException.class, () -> testDevice.transferIn(4, 64)); + Assertions.assertThrows(USBException.class, () -> testDevice.transferIn(5, 64)); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index 3a1b3027..8323b6d5 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -12,6 +12,8 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; +import java.util.Random; + /** * Base class for tests using the test device. */ @@ -34,4 +36,11 @@ static void closeDevice() { testDevice = null; } } + + static byte[] generateRandomBytes(int numBytes, long seed) { + var random = new Random(seed); + var bytes = new byte[numBytes]; + random.nextBytes(bytes); + return bytes; + } } From 1ecac28cc62c62c2fe4ce22ac47450d0e8c48100 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 7 Sep 2022 22:03:58 +0200 Subject: [PATCH 069/433] Windows: add control transfer --- .../net/codecrete/usb/common/USBDeviceImpl.java | 13 ++++++++++--- .../net/codecrete/usb/linux/LinuxUSBDevice.java | 6 ++++-- .../net/codecrete/usb/windows/WindowsUSBDevice.java | 6 ++++-- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index b8719185..6c32f7e6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -155,7 +155,8 @@ protected USBInterfaceImpl getInterface(int interfaceNumber) { * @param direction transfer direction * @return endpoint address */ - protected byte getEndpointAddress(int endpointNumber, USBDirection direction, USBTransferType transferType) { + protected byte getEndpointAddress(int endpointNumber, USBDirection direction, + USBTransferType transferType1, USBTransferType transferType2) { checkIsOpen(); @@ -163,15 +164,21 @@ protected byte getEndpointAddress(int endpointNumber, USBDirection direction, US for (var intf : interfaces_) { if (intf.isClaimed()) { for (var ep : intf.alternate().endpoints()) { - if (ep.number() == endpointNumber && ep.direction() == direction && ep.transferType() == transferType) + if (ep.number() == endpointNumber && ep.direction() == direction + && (ep.transferType() == transferType1 || ep.transferType() == transferType2)) return (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)); } } } } + String transferTypeDesc; + if (transferType2 == null) + transferTypeDesc = transferType1.name(); + else + transferTypeDesc = String.format("%s or %s", transferType1.name(), transferType2.name()); throw new USBException(String.format("Endpoint number %d does not exist, is not part of a claimed interface " + - "or is not valid for %s transfer in %s direction", endpointNumber, transferType.name(), + "or is not valid for %s transfer in %s direction", endpointNumber, transferTypeDesc, direction.name())); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index abd3f176..2da40535 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -189,7 +189,8 @@ private MemorySegment createBulkTransfer(MemorySession session, byte endpointAdd @Override public void transferOut(int endpointNumber, byte[] data) { - var endpointAddress = getEndpointAddress(endpointNumber, USBDirection.OUT, USBTransferType.BULK); + var endpointAddress = getEndpointAddress(endpointNumber, USBDirection.OUT, + USBTransferType.BULK, USBTransferType.INTERRUPT); try (var session = MemorySession.openConfined()) { var buffer = session.allocate(data.length); @@ -205,7 +206,8 @@ public void transferOut(int endpointNumber, byte[] data) { @Override public byte[] transferIn(int endpointNumber, int maxLength) { - var endpointAddress = getEndpointAddress(endpointNumber, USBDirection.IN, USBTransferType.BULK); + var endpointAddress = getEndpointAddress(endpointNumber, USBDirection.IN, + USBTransferType.BULK, USBTransferType.INTERRUPT); try (var session = MemorySession.openConfined()) { var buffer = session.allocate(maxLength); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index b26399e9..ce74e54e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -176,7 +176,8 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { @Override public void transferOut(int endpointNumber, byte[] data) { - byte endpointAddress = getEndpointAddress(endpointNumber, USBDirection.OUT, USBTransferType.BULK); + byte endpointAddress = getEndpointAddress(endpointNumber, USBDirection.OUT, + USBTransferType.BULK, USBTransferType.INTERRUPT); try (var session = MemorySession.openConfined()) { var buffer = session.allocate(data.length); @@ -191,7 +192,8 @@ public void transferOut(int endpointNumber, byte[] data) { @Override public byte[] transferIn(int endpointNumber, int maxLength) { - byte endpointAddress = getEndpointAddress(endpointNumber, USBDirection.IN, USBTransferType.BULK); + byte endpointAddress = getEndpointAddress(endpointNumber, USBDirection.IN, + USBTransferType.BULK, USBTransferType.INTERRUPT); try (var session = MemorySession.openConfined()) { var buffer = session.allocate(maxLength); From aa14ce6a39099534aed0eb62c437efb5c7fcf5f2 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 7 Sep 2022 22:26:24 +0200 Subject: [PATCH 070/433] Linux: fix jextract script --- java-does-usb/jextract/linux/gen_linux.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index 1c74089e..ce4b94c1 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -18,14 +18,14 @@ $JEXTRACT --source --output ../../src/main/java \ /usr/include/errno.h # ioctl.h -$JEXTRACT --source --output ../src/main/java \ +$JEXTRACT --source --output ../../src/main/java \ --header-class-name ioctl \ --target-package net.codecrete.usb.linux.gen.ioctl \ --include-function ioctl \ /usr/include/x86_64-linux-gnu/sys/ioctl.h # fcntl.h -$JEXTRACT --source --output ../src/main/java \ +$JEXTRACT --source --output ../../src/main/java \ --header-class-name fcntl \ --target-package net.codecrete.usb.linux.gen.fcntl \ --include-function open \ @@ -34,7 +34,7 @@ $JEXTRACT --source --output ../src/main/java \ /usr/include/fcntl.h # unistd.h -$JEXTRACT --source --output ../src/main/java \ +$JEXTRACT --source --output ../../src/main/java \ --header-class-name unistd \ --target-package net.codecrete.usb.linux.gen.unistd \ --include-function close \ @@ -42,7 +42,7 @@ $JEXTRACT --source --output ../src/main/java \ # usbdevice_fs.h # Missing constants like USBDEVFS_CLAIMINTERFACE -$JEXTRACT --source --output ../src/main/java \ +$JEXTRACT --source --output ../../src/main/java \ --header-class-name usbdevice_fs \ --target-package net.codecrete.usb.linux.gen.usbdevice_fs \ --include-struct usbdevfs_bulktransfer \ @@ -54,7 +54,7 @@ $JEXTRACT --source --output ../src/main/java \ /usr/include/linux/usbdevice_fs.h # libudev.h -$JEXTRACT --source --output ../src/main/java \ +$JEXTRACT --source --output ../../src/main/java \ --header-class-name udev \ --target-package net.codecrete.usb.linux.gen.udev \ -l udev \ @@ -80,7 +80,7 @@ $JEXTRACT --source --output ../src/main/java \ /usr/include/libudev.h # select.h -$JEXTRACT --source --output ../src/main/java \ +$JEXTRACT --source --output ../../src/main/java \ --header-class-name select \ --target-package net.codecrete.usb.linux.gen.select \ --include-function select \ From 92a74b6ae5936bf3c992ef54d9574bc564a6913f Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Wed, 7 Sep 2022 22:28:26 +0200 Subject: [PATCH 071/433] test device: new firmware --- test-devices/loopback-stm32/bin/firmware.bin | Bin 6328 -> 6536 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test-devices/loopback-stm32/bin/firmware.bin b/test-devices/loopback-stm32/bin/firmware.bin index 15033c10c180ab6736a7c7e5931924bee03c0f9b..b691999df54fa8bcb7e6a474088f7cf50d5f8842 100755 GIT binary patch delta 1267 zcmb`HTWAwO6o$|2W|Ofdc9S&CCat*HSS=Aj>-~ZxTDF*_H>!9=q98;;=$l2sC*pv{Oe37FLQ8V(=k_Bi=7W^#_d_?bU8{Y$`qUf=f5CzvFNwUF8wcWjrT zq+351JNiqXEV7hXS({jQ?cp~xPOSUv2$_+o1yKDthYr@tV%W%NiHM5*8{ZTIEfchO zltjR~T?+j652HU&5;dRU#TBY9N5Q&Qsx(9mSa(E@^7xA-h`N*hR7YxR(%<opU$K(Mmn0ixDpMTxm)R(dMO==@XkR zFk^c6xbWVRpovB}We+cuCgORXxo@pRRm-vdC3-x%8{-d_HrVv2L%;W>?$A!MsAu)1 zyrl2K^saXlh&52WvRWG5QR8_hk)=AZuCaC@n1MW(=Suq1WChIeryQe_;Y`+;U^NYa zCSp}K4MDyvn{V&WRq4qtA?6toV}TJ8t9xjg^+ONLn!&ZE&j_W6$}3@-PX`~Ejyd+j zXgZvBqxi8xuh~23(5~7}HEhzgj@Ze3c!Tcw=oEaWnhqZ#*4E;Sf}lPxfI3=$Jg*VW zfz?rrj|ua@I#q1_oahAWINCVcKD2Al9>Mw3INwv`PvFPbC$|9@73+l?-&upW+*^lv zo+&_Wq%j2a4Lcz2C41Nx@j{5-N%?+26Hw;nRA&n!~ps!rsvu>bsJwUfi1KN%DHS3XQS6r8YdT^xG z!v^Gribptc7dh);WAZk#jPGb-w~s)J;2&h8q2@xyyQ`j>?Ne7@q_c_ zVrS!esyUkep^z$~oKF&^J2}0~d_?Kv_eoyZ4j|dawE<9;HnW0Zw?AJ(`@(Ni5S3H6 z&qMM-=|~%b)D8T0zR#n^+tT3C*V{tPAzi(#SA|B+(|r_}2^ql$5eZ0Y?QEoEMe*Ak z9LJ9Y2BJRCU(TJHm7}SM;>*xPTa(&!zdS!VD{Jyv zYFqppi3jrINv-=$l1eU_ywZAy;;w*cjZ&)&ovsrRGDwuODI$GIQ0Y?wq=f_<2jz6i z_nnr4GL&ju_xFM_fa*hih*l4B*tQfh9 zh`dC5ja=cQ+7~(MrR-b~xM|Q8Iv46a262&J6dH8}0!YuC{Jn6Po)q~vp_*2U+^cg7 zegRlU?36A+4WkBNLME_#nX%f8MZIMe?VCnmuT8+_Q7d_+rN}_cz*=$VsgZYB$_<5R z+L2Wwe{N|b6`WY74vb-MM(n3bhmZ9YKEFhN2Q{`$Y|&b-A*C_9qllo?IE#s%Zs7oa zbn-4yq;H-4t|;*taldKS3G63AF}Z-RiOqF|>X2H2Eg+jVU^Usm%Is*PcB8H!gO2Ti PR)<<$qgwQ>H(-Z9vxyR0 From d1bf96b1d51c4c7edab1aa2b79608a90d4d870af Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Wed, 7 Sep 2022 22:30:15 +0200 Subject: [PATCH 072/433] Update README to reflect progress --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d838b3fc..1e011fa8 100644 --- a/README.md +++ b/README.md @@ -52,12 +52,12 @@ MAVEN_OPTS="--enable-preview --enable-native-access=ALL-UNNAMED" mvn install exe - Enumeration of USB devices - Control transfer - Bulk transfer +- Interrupt transfer - Notifications about connected/disconnected devices - Descriptive information about interfaces, settings and endpoints ### To do -- Interrupt transfer - Isochronous transfer - Alternate interface settings - Composite devices (on Windows) From ffd0273ebc3fbd473d2dc64f859d3eeb6b3f5a69 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Thu, 8 Sep 2022 21:56:19 +0200 Subject: [PATCH 073/433] Code size statistics --- java-does-usb/jextract/README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index aafa701b..cfd1632c 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -86,3 +86,22 @@ The known limitations are: - If the regular command interpreter `cmd.exe` is used, *jextract* must be called using `call`, i.e. `call jextract header.h`. - If *PowerShell* is used instead, `call` is not needed but *PowerShell* must be configured to allow the execution of scripts. - *jextract* turns off *echo mode*. So the first call will behave differently than the following calls. + + +## Code Size + +*jextract* generates a comprehensive set of methods for each function, struct, struct member etc. Most of it will not be used as a typical application just uses a subset of struct members, might only read or write them etc. So a considerable amount of code is generated. For some types, it's a bit excessive. + +The worst example is [`IOUSBInterfaceStruct942`](https://github.com/manuelbl/JavaDoesUSB/blob/main/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct942.java) (macOS). This is a `struct` consisting of about 75 member functions. It's bascially a vtable of a C++ class. *jextract* generates the same number of classes plus a huge class for the struct itself. The total code size (compiled) for this single `struct` is over 300 kByte. + +The table below shows statictics for version 0.2.0 of the library: + +| Operating Systems | Manually Created | % | Generated | % | Total | % | +| - | -:| -:| -:| -:| -:| -:| +| Linux | 24,140 | 1.96% | 182,774 | 14.84% | 206,914 | 16.80% | +| macOS | 57,788 | 4.69% | 666,037 | 54.08% | 723,825 | 58.77% | +| Windows | 46,085 | 3.74% | 201,000 | 16.32% | 247,085 | 20.06% | +| Common | 53,774 | 4.37% | 53,774 | 0.00% | | 4.37% | +| Grand Total | 181,787 | 14.76% | 1,049,811 | 85.24% | 1,231,598 | 100.00% | + +*Code Size (compiled), in bytes and percentage of total size* From 0538e463ab2c16d100346ac0441c8170ef638d9f Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Thu, 8 Sep 2022 22:16:20 +0200 Subject: [PATCH 074/433] Generate Javadoc --- java-does-usb/pom.xml | 107 +++++++++++++++++- java-does-usb/src/main/java/module-info.java | 3 + .../net/codecrete/usb/USBControlTransfer.java | 2 +- .../java/net/codecrete/usb/USBDirection.java | 2 +- .../java/net/codecrete/usb/USBException.java | 5 +- .../java/net/codecrete/usb/USBInterface.java | 1 + .../java/net/codecrete/usb/USBRecipient.java | 2 +- .../net/codecrete/usb/USBRequestType.java | 2 +- .../net/codecrete/usb/USBTransferType.java | 2 +- 9 files changed, 118 insertions(+), 8 deletions(-) diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 3de8d3d1..3a3bc066 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 1.0-SNAPSHOT + 0.3-SNAPSHOT 19 @@ -15,6 +15,7 @@ Java Does USB + https://github.com/manuelbl/JavaDoesUSB Access USB devices from Java without additional libraries @@ -25,12 +26,88 @@ - Manuel Bl + Manuel Bleichenbacher manuel.bleichenbacher@gmail.com https://github.com/manuelbl + + scm:git:https://github.com/manuelbl/JavaDoesUSB.git + scm:git:https://github.com/manuelbl/JavaDoesUSB.git + https://github.com/manuelbl/JavaDoesUSB + + + + + release + + + performRelease + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 3.0.1 + + + sign-artifacts + verify + + sign + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.3.0 + + + attach-javadocs + + jar + + + + + ${java.home}/bin/javadoc + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.1 + + + attach-sources + + jar-no-fork + + + + + + + + + + + + ossrh + https://s01.oss.sonatype.org/content/repositories/snapshots + + + ossrh + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ + + + @@ -52,7 +129,32 @@ --enable-preview --enable-native-access=ALL-UNNAMED + + org.apache.maven.plugins + maven-javadoc-plugin + 3.4.1 + + 19 + --enable-preview + + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.13 + true + + ossrh + https://s01.oss.sonatype.org/ + true + + + + @@ -63,4 +165,5 @@ test + diff --git a/java-does-usb/src/main/java/module-info.java b/java-does-usb/src/main/java/module-info.java index dcb8c5c6..cf4daec9 100644 --- a/java-does-usb/src/main/java/module-info.java +++ b/java-does-usb/src/main/java/module-info.java @@ -5,6 +5,9 @@ // https://opensource.org/licenses/MIT // +/** + * Java Does USB – work with USB devices + */ module net.codecrete.usb { exports net.codecrete.usb; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java index bd382ec7..ba5678f1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java @@ -8,7 +8,7 @@ package net.codecrete.usb; /** - * USB control transfer parameters + * USB control transfer parameters. *

* See USB specification for additional information *

diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDirection.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDirection.java index 38050593..8e2e7981 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDirection.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDirection.java @@ -8,7 +8,7 @@ package net.codecrete.usb; /** - * USB endpoint data direction. + * USB endpoint data direction enumeration. */ public enum USBDirection { /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBException.java b/java-does-usb/src/main/java/net/codecrete/usb/USBException.java index 90f3c3e0..31827e62 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBException.java @@ -8,10 +8,13 @@ package net.codecrete.usb; /** - * This exception is thrown if an operation with USB devices fails. + * USB exception, thrown if an operation with USB devices fails. */ public class USBException extends RuntimeException { + /** + * Error code. + */ private int errorCode_ = -1; /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java index a213883b..bfb5f68a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java @@ -21,6 +21,7 @@ public interface USBInterface { * Gets the interface number. *

* It is equal to the {@code bInterfaceNumber} field of the interface descriptor. + *

* * @return the interface number */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBRecipient.java b/java-does-usb/src/main/java/net/codecrete/usb/USBRecipient.java index afde6bcb..250238a2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBRecipient.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBRecipient.java @@ -8,7 +8,7 @@ package net.codecrete.usb; /** - * USB control transfer recipient + * USB control transfer recipient enumeration. */ public enum USBRecipient { /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBRequestType.java b/java-does-usb/src/main/java/net/codecrete/usb/USBRequestType.java index 5d7e1b5e..05ede7e6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBRequestType.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBRequestType.java @@ -8,7 +8,7 @@ package net.codecrete.usb; /** - * USB control transfer request type + * USB control transfer request type enumeration. */ public enum USBRequestType { /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBTransferType.java b/java-does-usb/src/main/java/net/codecrete/usb/USBTransferType.java index fc213a75..3acdc2c1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBTransferType.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBTransferType.java @@ -8,7 +8,7 @@ package net.codecrete.usb; /** - * USB endpoint transfer type. + * USB endpoint transfer type enumeration. */ public enum USBTransferType { /** From bc2658659c70c4d3d1315a2b20e26c7b8d95d20f Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 9 Sep 2022 09:17:26 +0200 Subject: [PATCH 075/433] Monitor example --- examples/monitor/README.md | 66 +++++++++++++ examples/monitor/pom.xml | 94 +++++++++++++++++++ .../net/codecrete/usb/examples/Monitor.java | 38 ++++++++ 3 files changed, 198 insertions(+) create mode 100644 examples/monitor/README.md create mode 100644 examples/monitor/pom.xml create mode 100644 examples/monitor/src/main/java/net/codecrete/usb/examples/Monitor.java diff --git a/examples/monitor/README.md b/examples/monitor/README.md new file mode 100644 index 00000000..33acf3ba --- /dev/null +++ b/examples/monitor/README.md @@ -0,0 +1,66 @@ +# USB Device Monitoring + +This sample program monitors USB devices as they are connected and disconnected. + +## Prerequisites + +- Java 19 +- Apache Maven +- 64-bit operating system (Windows, macOS, Linux) + +## How to run + +### Install Java 19 + +Check that *Java 19* is installed: + +```shell +$ java -version +``` + +If not, download and install it, e.g. from [Azul](https://www.azul.com/downloads/?package=jdk). + +### Install Maven + +Check that *Maven* is installed: + +```shell +$ mvn -version +``` + +If it is not present, install it, typically using package manager like *Homebrew* on macOS, *Chocolately* on Windows and *apt* on Linux. + +### Create the *java-does-usb* library + +Since the *java-does-usb* library is not yet available on Maven Central, it must be built locally: + +```shell +$ cd JavaDoesUSB/java-does-usb +$ mvn install +``` + +The result will be put in your local Maven repository. + +### Run the sample + +```shell +$ cd JavaDoesUSB/examples/monitor +$ mvn compile exec:exec +[INFO] Scanning for projects... +[INFO] +[INFO] -----------------< net.codecrete.usb.examples:monitor >----------------- +[INFO] Building monitor 0.3-SNAPSHOT +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] +[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ monitor --- +[INFO] Using 'UTF-8' encoding to copy filtered resources. +[INFO] skip non existing resourceDirectory /Users/me/Documents/JavaDoesUSB/examples/monitor/src/main/resources +[INFO] +[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ monitor --- +[INFO] Nothing to compile - all classes are up to date +[INFO] +[INFO] --- exec-maven-plugin:3.1.0:exec (default-cli) @ monitor --- +Present: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 8D8F515C5456, ID: 4295291950 +Present: VID: 0x1a40, PID: 0x0801, manufacturer: null, product: USB 2.0 Hub, serial: null, ID: 4295291734 +Monitoring... Press ENTER to quit. +``` diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml new file mode 100644 index 00000000..44d91804 --- /dev/null +++ b/examples/monitor/pom.xml @@ -0,0 +1,94 @@ + + + + 4.0.0 + + net.codecrete.usb.examples + monitor + 0.3-SNAPSHOT + + monitor + https://github.com/manuelbl/JavaDoesUSB/examples/monitor + + + UTF-8 + 19 + 19 + + + + + net.codecrete.usb + java-does-usb + 0.3-SNAPSHOT + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + 19 + --enable-preview + 19 + 19 + + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + java + + --enable-preview + --enable-native-access=ALL-UNNAMED + -classpath + + net.codecrete.usb.examples.Monitor + + + + + + + diff --git a/examples/monitor/src/main/java/net/codecrete/usb/examples/Monitor.java b/examples/monitor/src/main/java/net/codecrete/usb/examples/Monitor.java new file mode 100644 index 00000000..a897ba94 --- /dev/null +++ b/examples/monitor/src/main/java/net/codecrete/usb/examples/Monitor.java @@ -0,0 +1,38 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.examples; + +import net.codecrete.usb.USB; +import net.codecrete.usb.USBDevice; + +import java.io.IOException; + +/** + * Sample application monitoring USB devices as they are connected and disconnected. + */ +public class Monitor { + + public static void main(String[] args) throws IOException { + // register callbacks for events + USB.setOnDeviceConnected((device) -> printDetails(device, "Connected")); + USB.setOnDeviceDisconnected((device) -> printDetails(device, "Disconnected")); + + // display the already present USB devices + for (var device : USB.getAllDevices()) + printDetails(device, "Present"); + + // wait for ENTER to quit program + System.out.println("Monitoring... Press ENTER to quit."); + System.in.read(); + } + + private static void printDetails(USBDevice device, String event) { + System.out.printf("%-14s", event + ":"); + System.out.println(device.toString()); + } +} From df3cc118bf0c02e75acc4ccddac0bef80dc4820c Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 9 Sep 2022 14:31:07 +0200 Subject: [PATCH 076/433] Enumeration example --- examples/enumerate/README.md | 69 ++++++++++++++ examples/enumerate/pom.xml | 94 +++++++++++++++++++ .../net/codecrete/usb/examples/Enumerate.java | 72 ++++++++++++++ 3 files changed, 235 insertions(+) create mode 100644 examples/enumerate/README.md create mode 100644 examples/enumerate/pom.xml create mode 100644 examples/enumerate/src/main/java/net/codecrete/usb/examples/Enumerate.java diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md new file mode 100644 index 00000000..0ad96ce1 --- /dev/null +++ b/examples/enumerate/README.md @@ -0,0 +1,69 @@ +# USB Device Enumeration + +This sample enumerates the connected USB devices and provides information about the interfaces and endpoints. + +## Prerequisites + +- Java 19 +- Apache Maven +- 64-bit operating system (Windows, macOS, Linux) + +## How to run + +### Install Java 19 + +Check that *Java 19* is installed: + +```shell +$ java -version +``` + +If not, download and install it, e.g. from [Azul](https://www.azul.com/downloads/?package=jdk). + +### Install Maven + +Check that *Maven* is installed: + +```shell +$ mvn -version +``` + +If it is not present, install it, typically using package manager like *Homebrew* on macOS, *Chocolately* on Windows and *apt* on Linux. + +### Create the *java-does-usb* library + +Since the *java-does-usb* library is not yet available on Maven Central, it must be built locally: + +```shell +$ cd JavaDoesUSB/java-does-usb +$ mvn install +``` + +The result will be put in your local Maven repository. + +### Run the sample + +```shell +$ cd JavaDoesUSB/examples/enumerate +$ mvn compile exec:exec +[INFO] Scanning for projects... +[INFO] +[INFO] ----------------< net.codecrete.usb.examples:enumerate >---------------- +[INFO] Building enumerate 0.3-SNAPSHOT +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] +[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ enumerate --- +[INFO] Using 'UTF-8' encoding to copy filtered resources. +[INFO] skip non existing resourceDirectory /Users/me/Documents/JavaDoesUSB/examples/enumerate/src/main/resources +[INFO] +[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ enumerate --- +[INFO] Nothing to compile - all classes are up to date +[INFO] +[INFO] --- exec-maven-plugin:3.1.0:exec (default-cli) @ enumerate --- +Device: + VID: 0xcafe + PID: 0xceaf + Manufacturer: JavaDoesUSB + Product name: Loopback +... +``` diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml new file mode 100644 index 00000000..6a93f49c --- /dev/null +++ b/examples/enumerate/pom.xml @@ -0,0 +1,94 @@ + + + + 4.0.0 + + net.codecrete.usb.examples + enumerate + 0.3-SNAPSHOT + + enumerate + https://github.com/manuelbl/JavaDoesUSB/examples/enumerate + + + UTF-8 + 19 + 19 + + + + + net.codecrete.usb + java-does-usb + 0.3-SNAPSHOT + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + 19 + --enable-preview + 19 + 19 + + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + java + + --enable-preview + --enable-native-access=ALL-UNNAMED + -classpath + + net.codecrete.usb.examples.Enumerate + + + + + + + diff --git a/examples/enumerate/src/main/java/net/codecrete/usb/examples/Enumerate.java b/examples/enumerate/src/main/java/net/codecrete/usb/examples/Enumerate.java new file mode 100644 index 00000000..e5db9dc6 --- /dev/null +++ b/examples/enumerate/src/main/java/net/codecrete/usb/examples/Enumerate.java @@ -0,0 +1,72 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.examples; + +import net.codecrete.usb.*; + +/** + * Sample application enumerating connected USB devices. + */ +public class Enumerate { + + public static void main(String[] args) { + // display the already present USB devices + for (var device : USB.getAllDevices()) + printDevice(device); + } + + private static void printDevice(USBDevice device) { + System.out.println("Device:"); + System.out.printf(" VID: 0x%04x%n", device.vendorId()); + System.out.printf(" PID: 0x%04x%n", device.productId()); + if (device.manufacturer() != null) + System.out.printf(" Manufacturer: %s%n", device.manufacturer()); + if (device.product() != null) + System.out.printf(" Product name: %s%n", device.product()); + if (device.serialNumber() != null) + System.out.printf(" Serial number: %s%n", device.serialNumber()); + System.out.printf(" Device class: 0x%02x%n", device.classCode()); + System.out.printf(" Device subclass: 0x%02x%n", device.subclassCode()); + System.out.printf(" Device protocol: 0x%02x%n", device.protocolCode()); + + for (var intf: device.interfaces()) + printInterface(intf); + + System.out.println(); + System.out.println(); + } + + private static void printInterface(USBInterface intf) { + for (var alt : intf.alternates()) + printAlternate(alt, intf.number(), alt == intf.alternate()); + } + + private static void printAlternate(USBAlternateInterface alt, int intferaceNumber, boolean isDefault) { + System.out.println(); + if (isDefault) { + System.out.printf(" Interface %d%n", intferaceNumber); + } else { + System.out.printf(" Interface %d (alternate %d)%n", intferaceNumber, alt.number()); + } + + System.out.printf(" Interface class: 0x%02x%n", alt.classCode()); + System.out.printf(" Interface subclass: 0x%02x%n", alt.subclassCode()); + System.out.printf(" Interface protocol: 0x%02x%n", alt.protocolCode()); + + for (var endpoint : alt.endpoints()) + printEndpoint(endpoint); + } + + private static void printEndpoint(USBEndpoint endpoint) { + System.out.println(); + System.out.printf(" Endpoint %d%n", endpoint.number()); + System.out.printf(" Direction: %s%n", endpoint.direction().name()); + System.out.printf(" Transfer type: %s%n", endpoint.transferType().name()); + System.out.printf(" Packet size: %d bytes%n", endpoint.packetSize()); + } +} From 01316473daf11621e2da1222fbb5fb952247f1ab Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 9 Sep 2022 14:45:24 +0200 Subject: [PATCH 077/433] Bulk transfer example --- examples/bulk_transfer/README.md | 72 ++++++++++++++ examples/bulk_transfer/pom.xml | 94 +++++++++++++++++++ .../codecrete/usb/examples/BulkTransfer.java | 42 +++++++++ 3 files changed, 208 insertions(+) create mode 100644 examples/bulk_transfer/README.md create mode 100644 examples/bulk_transfer/pom.xml create mode 100644 examples/bulk_transfer/src/main/java/net/codecrete/usb/examples/BulkTransfer.java diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md new file mode 100644 index 00000000..e6a473e2 --- /dev/null +++ b/examples/bulk_transfer/README.md @@ -0,0 +1,72 @@ +# Bulk Transfer + +This sample shows how to find a device, open it and transfer data from and to bulk endpoints. + +## Prerequisites + +- Java 19 +- Apache Maven +- 64-bit operating system (Windows, macOS, Linux) + +## How to run + +### Install Java 19 + +Check that *Java 19* is installed: + +```shell +$ java -version +``` + +If not, download and install it, e.g. from [Azul](https://www.azul.com/downloads/?package=jdk). + +### Install Maven + +Check that *Maven* is installed: + +```shell +$ mvn -version +``` + +If it is not present, install it, typically using package manager like *Homebrew* on macOS, *Chocolately* on Windows and *apt* on Linux. + +### Create the *java-does-usb* library + +Since the *java-does-usb* library is not yet available on Maven Central, it must be built locally: + +```shell +$ cd JavaDoesUSB/java-does-usb +$ mvn install +``` + +The result will be put in your local Maven repository. + +### Run the sample + +```shell +$ cd JavaDoesUSB/examples/bulk_transfer +$ mvn compile exec:exec +[INFO] Scanning for projects... +[INFO] +[INFO] --------------< net.codecrete.usb.examples:bulk-transfer >-------------- +[INFO] Building bulk-transfer 0.3-SNAPSHOT +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] +[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ bulk-transfer --- +[INFO] Using 'UTF-8' encoding to copy filtered resources. +[INFO] skip non existing resourceDirectory /Users/manuel/Documents/Lab/JavaDoesUSB/examples/bulk_transfer/src/main/resources +[INFO] +[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ bulk-transfer --- +[INFO] Changes detected - recompiling the module! +[INFO] Compiling 1 source file to /Users/manuel/Documents/Lab/JavaDoesUSB/examples/bulk_transfer/target/classes +[INFO] +[INFO] --- exec-maven-plugin:3.1.0:exec (default-cli) @ bulk-transfer --- +6 bytes sent. +6 bytes received. +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 3.830 s +[INFO] Finished at: 2022-09-09T14:43:10+02:00 +[INFO] ------------------------------------------------------------------------ +``` diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml new file mode 100644 index 00000000..5c5ab600 --- /dev/null +++ b/examples/bulk_transfer/pom.xml @@ -0,0 +1,94 @@ + + + + 4.0.0 + + net.codecrete.usb.examples + bulk-transfer + 0.3-SNAPSHOT + + bulk-transfer + https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer + + + UTF-8 + 19 + 19 + + + + + net.codecrete.usb + java-does-usb + 0.3-SNAPSHOT + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + 19 + --enable-preview + 19 + 19 + + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + java + + --enable-preview + --enable-native-access=ALL-UNNAMED + -classpath + + net.codecrete.usb.examples.BulkTransfer + + + + + + + diff --git a/examples/bulk_transfer/src/main/java/net/codecrete/usb/examples/BulkTransfer.java b/examples/bulk_transfer/src/main/java/net/codecrete/usb/examples/BulkTransfer.java new file mode 100644 index 00000000..34a27e95 --- /dev/null +++ b/examples/bulk_transfer/src/main/java/net/codecrete/usb/examples/BulkTransfer.java @@ -0,0 +1,42 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.examples; + +import net.codecrete.usb.*; + +/** + * Sample application transferring data to and from bulk endpoints. + *

+ * This example assumes that one of the interfaces has two bulk endpoints, + * one for sending and one for receiving data. The test device fulfils + * this requirement (see https://github.com/manuelbl/JavaDoesUSB/tree/main/test-devices/loopback-stm32) + *

+ */ +public class BulkTransfer { + + private static final int VID = 0xcafe; + private static final int PID = 0xceaf; + private static final int INTERFACE_NO = 0; + private static final int ENDPOINT_OUT = 1; + private static final int ENDPOINT_IN = 2; + + public static void main(String[] args) { + var device = USB.getDevice(new USBDeviceFilter(VID, PID)); + device.open(); + device.claimInterface(INTERFACE_NO); + + var data = new byte[] { 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21 }; + device.transferOut(ENDPOINT_OUT, data); + System.out.println(data.length + " bytes sent."); + + data = device.transferIn(ENDPOINT_IN, 64); + System.out.println(data.length + " bytes received."); + + device.close(); + } +} From c89e99bd50762f99ba5049506d32808f0bb22648 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 9 Sep 2022 17:33:28 +0200 Subject: [PATCH 078/433] Mention examples in README --- README.md | 8 +++++++- examples/bulk_transfer/README.md | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e011fa8..f454a859 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,6 @@ MAVEN_OPTS="--enable-preview --enable-native-access=ALL-UNNAMED" mvn install exe - Composite devices (on Windows) - Generate and publish JavaDoc documentation - Make library available on Maven Central -- Standalone examples ### Not planned @@ -119,3 +118,10 @@ The Foreign Function & Memory API has not been implemented for 32-bit operating ## Code generation Many of the bindings for the native APIs have been generated with *jextract*. See the [jextract](java-does-usb/jextract) subdirectory for more information. + + +## Examples + +- [Bulk Transfer](examples/bulk_transfer/) demonstrates how to find a USB device, open it and communicate using bulk transfer. +- [Enumeration](examples/enumerate/) lists all connected USB devices and displays information about interfaces and endpoints. +- [Monitor](examples/monitor/) lists the connected USB devices and then monitors for USB devices being connected and disconnnected. diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index e6a473e2..8168582c 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -7,6 +7,7 @@ This sample shows how to find a device, open it and transfer data from and to bu - Java 19 - Apache Maven - 64-bit operating system (Windows, macOS, Linux) +- A USB device with bulk IN and OUT endpoints (e.g. the test device, see https://github.com/manuelbl/JavaDoesUSB/tree/main/test-devices/loopback-stm32) ## How to run From c486bc271391dd64d558607a8b3b0d620141b291 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 9 Sep 2022 19:56:37 +0200 Subject: [PATCH 079/433] Print descriptive USB class info --- .../net/codecrete/usb/examples/Enumerate.java | 28 ++- .../codecrete/usb/examples/USBClassInfo.java | 236 ++++++++++++++++++ 2 files changed, 258 insertions(+), 6 deletions(-) create mode 100644 examples/enumerate/src/main/java/net/codecrete/usb/examples/USBClassInfo.java diff --git a/examples/enumerate/src/main/java/net/codecrete/usb/examples/Enumerate.java b/examples/enumerate/src/main/java/net/codecrete/usb/examples/Enumerate.java index e5db9dc6..ee89765a 100644 --- a/examples/enumerate/src/main/java/net/codecrete/usb/examples/Enumerate.java +++ b/examples/enumerate/src/main/java/net/codecrete/usb/examples/Enumerate.java @@ -9,6 +9,8 @@ import net.codecrete.usb.*; +import java.util.Optional; + /** * Sample application enumerating connected USB devices. */ @@ -30,9 +32,12 @@ private static void printDevice(USBDevice device) { System.out.printf(" Product name: %s%n", device.product()); if (device.serialNumber() != null) System.out.printf(" Serial number: %s%n", device.serialNumber()); - System.out.printf(" Device class: 0x%02x%n", device.classCode()); - System.out.printf(" Device subclass: 0x%02x%n", device.subclassCode()); - System.out.printf(" Device protocol: 0x%02x%n", device.protocolCode()); + System.out.printf(" Device class: 0x%02x", device.classCode()); + printInParens(USBClassInfo.lookupClass(device.classCode())); + System.out.printf(" Device subclass: 0x%02x", device.subclassCode()); + printInParens(USBClassInfo.lookupSubclass(device.classCode(), device.subclassCode())); + System.out.printf(" Device protocol: 0x%02x", device.protocolCode()); + printInParens(USBClassInfo.lookupProtocol(device.classCode(), device.subclassCode(), device.protocolCode())); for (var intf: device.interfaces()) printInterface(intf); @@ -41,6 +46,14 @@ private static void printDevice(USBDevice device) { System.out.println(); } + private static void printInParens(Optional text) { + if (text.isPresent()) { + System.out.printf(" (%s)%n", text.get()); + } else { + System.out.println(); + } + } + private static void printInterface(USBInterface intf) { for (var alt : intf.alternates()) printAlternate(alt, intf.number(), alt == intf.alternate()); @@ -54,9 +67,12 @@ private static void printAlternate(USBAlternateInterface alt, int intferaceNumbe System.out.printf(" Interface %d (alternate %d)%n", intferaceNumber, alt.number()); } - System.out.printf(" Interface class: 0x%02x%n", alt.classCode()); - System.out.printf(" Interface subclass: 0x%02x%n", alt.subclassCode()); - System.out.printf(" Interface protocol: 0x%02x%n", alt.protocolCode()); + System.out.printf(" Interface class: 0x%02x", alt.classCode()); + printInParens(USBClassInfo.lookupClass(alt.classCode())); + System.out.printf(" Interface subclass: 0x%02x", alt.subclassCode()); + printInParens(USBClassInfo.lookupProtocol(alt.classCode(), alt.subclassCode(), alt.protocolCode())); + System.out.printf(" Interface protocol: 0x%02x", alt.protocolCode()); + printInParens(USBClassInfo.lookupProtocol(alt.classCode(), alt.subclassCode(), alt.protocolCode())); for (var endpoint : alt.endpoints()) printEndpoint(endpoint); diff --git a/examples/enumerate/src/main/java/net/codecrete/usb/examples/USBClassInfo.java b/examples/enumerate/src/main/java/net/codecrete/usb/examples/USBClassInfo.java new file mode 100644 index 00000000..487c2f48 --- /dev/null +++ b/examples/enumerate/src/main/java/net/codecrete/usb/examples/USBClassInfo.java @@ -0,0 +1,236 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.examples; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * Provides the names of known USB classes, subclasses and protocols. + */ +public class USBClassInfo { + + private static final List classCodes = new ArrayList<>(); + private static final List subclassCodes = new ArrayList<>(); + private static final List protocolCodes = new ArrayList<>(); + + // List of known device classes, subclasses and + // from http://www.linux-usb.org/usb.ids + private static final String RAW_DATA = """ +C 00 (Defined at Interface level) +C 01 Audio + 01 Control Device + 02 Streaming + 03 MIDI Streaming +C 02 Communications + 01 Direct Line + 02 Abstract (modem) + 00 None + 01 AT-commands (v.25ter) + 02 AT-commands (PCCA101) + 03 AT-commands (PCCA101 + wakeup) + 04 AT-commands (GSM) + 05 AT-commands (3G) + 06 AT-commands (CDMA) + fe Defined by command set descriptor + ff Vendor Specific (MSFT RNDIS?) + 03 Telephone + 04 Multi-Channel + 05 CAPI Control + 06 Ethernet Networking + 07 ATM Networking + 08 Wireless Handset Control + 09 Device Management + 0a Mobile Direct Line + 0b OBEX + 0c Ethernet Emulation + 07 Ethernet Emulation (EEM) +C 03 Human Interface Device + 00 No Subclass + 00 None + 01 Keyboard + 02 Mouse + 01 Boot Interface Subclass + 00 None + 01 Keyboard + 02 Mouse +C 05 Physical Interface Device +C 06 Imaging + 01 Still Image Capture + 01 Picture Transfer Protocol (PIMA 15470) +C 07 Printer + 01 Printer + 00 Reserved/Undefined + 01 Unidirectional + 02 Bidirectional + 03 IEEE 1284.4 compatible bidirectional + ff Vendor Specific +C 08 Mass Storage + 01 RBC (typically Flash) + 00 Control/Bulk/Interrupt + 01 Control/Bulk + 50 Bulk-Only + 02 SFF-8020i, MMC-2 (ATAPI) + 03 QIC-157 + 04 Floppy (UFI) + 00 Control/Bulk/Interrupt + 01 Control/Bulk + 50 Bulk-Only + 05 SFF-8070i + 06 SCSI + 00 Control/Bulk/Interrupt + 01 Control/Bulk + 50 Bulk-Only +C 09 Hub + 00 Unused + 00 Full speed (or root) hub + 01 Single TT + 02 TT per port +C 0a CDC Data + 00 Unused + 30 I.430 ISDN BRI + 31 HDLC + 32 Transparent + 50 Q.921M + 51 Q.921 + 52 Q.921TM + 90 V.42bis + 91 Q.932 EuroISDN + 92 V.120 V.24 rate ISDN + 93 CAPI 2.0 + fd Host Based Driver + fe CDC PUF + ff Vendor specific +C 0b Chip/SmartCard +C 0d Content Security +C 0e Video + 00 Undefined + 01 Video Control + 02 Video Streaming + 03 Video Interface Collection +C 58 Xbox + 42 Controller +C dc Diagnostic + 01 Reprogrammable Diagnostics + 01 USB2 Compliance +C e0 Wireless + 01 Radio Frequency + 01 Bluetooth + 02 Ultra WideBand Radio Control + 03 RNDIS + 02 Wireless USB Wire Adapter + 01 Host Wire Adapter Control/Data Streaming + 02 Device Wire Adapter Control/Data Streaming + 03 Device Wire Adapter Isochronous Streaming +C ef Miscellaneous Device + 01 ? + 01 Microsoft ActiveSync + 02 Palm Sync + 02 ? + 01 Interface Association + 02 Wire Adapter Multifunction Peripheral + 03 ? + 01 Cable Based Association + 05 USB3 Vision +C fe Application Specific Interface + 01 Device Firmware Update + 02 IRDA Bridge + 03 Test and Measurement + 01 TMC + 02 USB488 +C ff Vendor Specific Class + ff Vendor Specific Subclass + ff Vendor Specific Protocol"""; + + + /** + * Provides the name of the specified USB class. + * @param classCode the USB class code + * @return an optional name + */ + public static Optional lookupClass(int classCode) { + loadData(); + return classCodes.stream() + .filter((cc) -> cc.classCode == classCode) + .map((cc) -> cc.name) + .findFirst(); + } + + /** + * Provides the name of the specified USB subclass. + * @param classCode the USB class code + * @param subclassCode the USB subclass code + * @return an optional name + */ + public static Optional lookupSubclass(int classCode, int subclassCode) { + loadData(); + return subclassCodes.stream() + .filter((scc) -> scc.classCode == classCode && scc.subclassCode == subclassCode) + .map((cc) -> cc.name) + .findFirst(); + } + + /** + * Provides the name of the specified USB protocol. + * @param classCode the USB class code + * @param subclassCode the USB subclass code + * @param protocolCode the USB protocol code + * @return an optional name + */ + public static Optional lookupProtocol(int classCode, int subclassCode, int protocolCode) { + loadData(); + return protocolCodes.stream() + .filter((scc) -> scc.classCode == classCode && scc.subclassCode == subclassCode + && scc.protocolCode == protocolCode) + .map((cc) -> cc.name) + .findFirst(); + } + + private static void loadData() { + if (classCodes.size() > 0) + return; + + try (var stringReader = new StringReader(RAW_DATA); + var reader = new BufferedReader(stringReader)) { + + int classCode = 0; + int subclassCode = 0; + String line; + + while ((line = reader.readLine()) != null) { + // protocol line + if (line.startsWith("\t\t")) { + int protocol = Integer.parseInt(line.substring(2, 4), 16); + protocolCodes.add(new ProtocolCode(classCode, subclassCode, protocol, line.substring(6))); + // subclass line + } else if (line.startsWith("\t")) { + subclassCode = Integer.parseInt(line.substring(1, 3), 16); + subclassCodes.add(new SubclassCode(classCode, subclassCode, line.substring(5))); + // class line + } else if (line.startsWith("C ")) { + classCode = Integer.parseInt(line.substring(2, 4), 16); + classCodes.add(new ClassCode(classCode, line.substring(6))); + + } else { + throw new IllegalStateException("Invalid raw data"); + } + } + + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + record ClassCode(int classCode, String name) { } + record SubclassCode(int classCode, int subclassCode, String name) { } + record ProtocolCode(int classCode, int subclassCode, int protocolCode, String name) { } +} From 2f2ae9409f321491dd21d56d501c5c50bdef60d1 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 10 Sep 2022 13:48:50 +0200 Subject: [PATCH 080/433] Composite USB test device --- .../net/codecrete/usb/BulkTransferTest.java | 6 +- .../net/codecrete/usb/DescriptionTest.java | 10 +- .../codecrete/usb/DeviceEnumerationTest.java | 26 +- .../codecrete/usb/DeviceLifecycleTest.java | 25 +- .../codecrete/usb/InterruptTransferTest.java | 12 +- .../codecrete/usb/InvalidOperationTest.java | 2 +- .../net/codecrete/usb/TestDeviceBase.java | 22 +- test-devices/composite-stm32/.clang-format | 4 + test-devices/composite-stm32/.gitignore | 5 + .../composite-stm32/.vscode/extensions.json | 10 + test-devices/composite-stm32/README.md | 61 ++++ test-devices/composite-stm32/bin/firmware.bin | Bin 0 -> 7060 bytes test-devices/composite-stm32/bin/save_bin.sh | 2 + .../composite-stm32/bin/upload_firmware.sh | 2 + .../composite-stm32/include/circ_buf.h | 155 ++++++++ test-devices/composite-stm32/include/common.h | 32 ++ .../composite-stm32/include/usb_descriptor.h | 35 ++ test-devices/composite-stm32/include/wcid.h | 17 + test-devices/composite-stm32/platformio.ini | 4 + test-devices/composite-stm32/src/common.cpp | 37 ++ test-devices/composite-stm32/src/main.cpp | 338 ++++++++++++++++++ .../composite-stm32/src/usb_descriptor.cpp | 302 ++++++++++++++++ test-devices/composite-stm32/src/wcid.cpp | 81 +++++ test-devices/loopback-stm32/bin/save_bin.sh | 2 +- test-devices/loopback-stm32/platformio.ini | 2 +- 25 files changed, 1142 insertions(+), 50 deletions(-) create mode 100644 test-devices/composite-stm32/.clang-format create mode 100644 test-devices/composite-stm32/.gitignore create mode 100644 test-devices/composite-stm32/.vscode/extensions.json create mode 100644 test-devices/composite-stm32/README.md create mode 100755 test-devices/composite-stm32/bin/firmware.bin create mode 100755 test-devices/composite-stm32/bin/save_bin.sh create mode 100755 test-devices/composite-stm32/bin/upload_firmware.sh create mode 100644 test-devices/composite-stm32/include/circ_buf.h create mode 100644 test-devices/composite-stm32/include/common.h create mode 100644 test-devices/composite-stm32/include/usb_descriptor.h create mode 100644 test-devices/composite-stm32/include/wcid.h create mode 100644 test-devices/composite-stm32/platformio.ini create mode 100644 test-devices/composite-stm32/src/common.cpp create mode 100644 test-devices/composite-stm32/src/main.cpp create mode 100644 test-devices/composite-stm32/src/usb_descriptor.cpp create mode 100644 test-devices/composite-stm32/src/wcid.cpp diff --git a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java index 1c903fe3..db0aafad 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java @@ -19,10 +19,6 @@ public class BulkTransferTest extends TestDeviceBase { - private static final int LOOPBACK_EP_OUT = 1; - private static final int LOOPBACK_EP_IN = 2; - private static final int MAX_PACKET_SIZE = 64; - @Test void smallTransfer_succeeds() { byte[] sampleData = generateRandomBytes(12, 293872394); @@ -66,7 +62,7 @@ static byte[] readBytes(int numBytes) { var buffer = new ByteArrayOutputStream(); int bytesRead = 0; while (bytesRead < numBytes) { - byte[] data = testDevice.transferIn(LOOPBACK_EP_IN, MAX_PACKET_SIZE); + byte[] data = testDevice.transferIn(LOOPBACK_EP_IN, LOOPBACK_MAX_PACKET_SIZE); buffer.writeBytes(data); bytesRead += data.length; } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index 60162543..293d6c5e 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -32,17 +32,17 @@ void deviceInfo_isCorrect() { @Test void interfaceDescriptors_isCorrect() { assertNotNull(testDevice.interfaces()); - assertEquals(1, testDevice.interfaces().size()); + assertEquals(LOOPBACK_INTF + 1, testDevice.interfaces().size()); - var intf = testDevice.interfaces().get(0); - assertEquals(0, intf.number()); + var intf = testDevice.interfaces().get(LOOPBACK_INTF); + assertEquals(LOOPBACK_INTF, intf.number()); assertNotNull(intf.alternate()); assertTrue(intf.isClaimed()); } @Test void alternateInterfaceDescriptors_isCorrect() { - var intf = testDevice.interfaces().get(0); + var intf = testDevice.interfaces().get(LOOPBACK_INTF); var altIntf = intf.alternate(); assertNotNull(intf.alternates()); assertEquals(1, intf.alternates().size()); @@ -56,7 +56,7 @@ void alternateInterfaceDescriptors_isCorrect() { @Test void endpointDescriptors_isCorrect() { - var altIntf = testDevice.interfaces().get(0).alternate(); + var altIntf = testDevice.interfaces().get(LOOPBACK_INTF).alternate(); assertNotNull(altIntf.endpoints()); assertEquals(4, altIntf.endpoints().size()); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java index 828cb1a8..600e5671 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java @@ -21,43 +21,43 @@ public class DeviceEnumerationTest extends TestDeviceBase { @Test void getAllDevices_includesLoopback() { var found = USB.getAllDevices().stream() - .anyMatch(device -> device.vendorId() == 0xcafe && device.productId() == 0xceaf); + .anyMatch(device -> device.vendorId() == VID && device.productId() == PID); assertTrue(found); } @Test void getDevicesWithFilter_returnsLoopback() { - var result = USB.getDevices(new USBDeviceFilter(0xcafe, 0xceaf)); + var result = USB.getDevices(new USBDeviceFilter(VID, PID)); assertEquals(1, result.size()); - assertEquals(0xcafe, result.get(0).vendorId()); - assertEquals(0xceaf, result.get(0).productId()); + assertEquals(VID, result.get(0).vendorId()); + assertEquals(PID, result.get(0).productId()); } @Test void getDevicesWithMultipleFilters_returnsLoopback() { var result = USB.getDevices(List.of( - new USBDeviceFilter(0xcafe, 0xceaf), + new USBDeviceFilter(VID, PID), new USBDeviceFilter(0x0000, 0xffff) )); assertEquals(1, result.size()); - assertEquals(0xcafe, result.get(0).vendorId()); - assertEquals(0xceaf, result.get(0).productId()); + assertEquals(VID, result.get(0).vendorId()); + assertEquals(PID, result.get(0).productId()); } @Test void getDeviceWithFilter_returnsLoopback() { - var device = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); - assertEquals(0xcafe, device.vendorId()); - assertEquals(0xceaf, device.productId()); + var device = USB.getDevice(new USBDeviceFilter(VID, PID)); + assertEquals(VID, device.vendorId()); + assertEquals(PID, device.productId()); } @Test void getDeviceWithMultipleFilters_returnsLoopback() { var device = USB.getDevice(List.of( - new USBDeviceFilter(0xcafe, 0xceaf), + new USBDeviceFilter(VID, PID), new USBDeviceFilter(0x0000, 0xffff) )); - assertEquals(0xcafe, device.vendorId()); - assertEquals(0xceaf, device.productId()); + assertEquals(VID, device.vendorId()); + assertEquals(PID, device.productId()); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java index 9c2185b1..3d5f46aa 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java @@ -12,6 +12,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import static net.codecrete.usb.TestDeviceBase.*; import static org.junit.jupiter.api.Assertions.*; public class DeviceLifecycleTest { @@ -20,45 +21,45 @@ public class DeviceLifecycleTest { @Test void lifecycle_showsValidState() { - device = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); + device = USB.getDevice(new USBDeviceFilter(VID, PID)); if (device == null) throw new IllegalStateException("USB loopback test device must be connected"); - var intf = device.interfaces().get(0); - assertEquals(0, intf.number()); + var intf = device.interfaces().get(LOOPBACK_INTF); + assertEquals(LOOPBACK_INTF, intf.number()); assertFalse(device.isOpen()); assertFalse(intf.isClaimed()); - assertThrows(USBException.class, () -> device.claimInterface(0)); - assertThrows(USBException.class, () -> device.releaseInterface(0)); + assertThrows(USBException.class, () -> device.claimInterface(LOOPBACK_INTF)); + assertThrows(USBException.class, () -> device.releaseInterface(LOOPBACK_INTF)); device.open(); assertTrue(device.isOpen()); assertFalse(intf.isClaimed()); assertThrows(USBException.class, () -> device.open()); - assertThrows(USBException.class, () -> device.releaseInterface(0)); + assertThrows(USBException.class, () -> device.releaseInterface(LOOPBACK_INTF)); - device.claimInterface(0); + device.claimInterface(LOOPBACK_INTF); assertTrue(device.isOpen()); assertTrue(intf.isClaimed()); assertThrows(USBException.class, () -> device.open()); - assertThrows(USBException.class, () -> device.claimInterface(0)); + assertThrows(USBException.class, () -> device.claimInterface(LOOPBACK_INTF)); - device.releaseInterface(0); + device.releaseInterface(LOOPBACK_INTF); assertTrue(device.isOpen()); assertFalse(intf.isClaimed()); assertThrows(USBException.class, () -> device.open()); - assertThrows(USBException.class, () -> device.releaseInterface(0)); + assertThrows(USBException.class, () -> device.releaseInterface(LOOPBACK_INTF)); device.close(); assertFalse(device.isOpen()); assertFalse(intf.isClaimed()); - assertThrows(USBException.class, () -> device.claimInterface(0)); - assertThrows(USBException.class, () -> device.releaseInterface(0)); + assertThrows(USBException.class, () -> device.claimInterface(LOOPBACK_INTF)); + assertThrows(USBException.class, () -> device.releaseInterface(LOOPBACK_INTF)); } @AfterEach diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java index 832393ff..6298e637 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java @@ -11,29 +11,21 @@ import org.junit.jupiter.api.Test; -import java.io.ByteArrayOutputStream; -import java.util.Arrays; -import java.util.concurrent.CompletableFuture; - import static org.junit.jupiter.api.Assertions.assertArrayEquals; public class InterruptTransferTest extends TestDeviceBase { - private static final int ECHO_EP_OUT = 3; - private static final int ECHO_EP_IN = 3; - private static final int MAX_PACKET_SIZE = 16; - @Test void smallTransfer_succeeds() { byte[] sampleData = generateRandomBytes(12, 293872394); testDevice.transferOut(ECHO_EP_OUT, sampleData); // receive first echo - byte[] echo = testDevice.transferIn(ECHO_EP_IN, MAX_PACKET_SIZE); + byte[] echo = testDevice.transferIn(ECHO_EP_IN, ECHO_MAX_PACKET_SIZE); assertArrayEquals(sampleData, echo); // receive second echo - echo = testDevice.transferIn(ECHO_EP_IN, MAX_PACKET_SIZE); + echo = testDevice.transferIn(ECHO_EP_IN, ECHO_MAX_PACKET_SIZE); assertArrayEquals(sampleData, echo); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java index 4f135009..17f875a8 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java @@ -19,7 +19,7 @@ void claimInvalidInterface_throws() { // throws error because it's already claimed Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(0)); // throws error because it's an invalid interface number - Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(1)); + Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(3)); // throws error because it's an invalid interface number Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(888)); } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index 8323b6d5..f3b7d7d7 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -18,15 +18,33 @@ * Base class for tests using the test device. */ public class TestDeviceBase { + /** + * Test device vendor ID + */ + static final int VID = 0xcafe; + /** + * Test device product ID + */ + static final int PID = 0xceaf; + /** + * Test device loopback interface number + */ + static final int LOOPBACK_INTF = 0; + protected static final int LOOPBACK_EP_OUT = 1; + protected static final int LOOPBACK_EP_IN = 2; + protected static final int LOOPBACK_MAX_PACKET_SIZE = 64; + protected static final int ECHO_EP_OUT = 3; + protected static final int ECHO_EP_IN = 3; + protected static final int ECHO_MAX_PACKET_SIZE = 16; protected static USBDevice testDevice; @BeforeAll static void openDevice() { - testDevice = USB.getDevice(new USBDeviceFilter(0xcafe, 0xceaf)); + testDevice = USB.getDevice(new USBDeviceFilter(VID, PID)); if (testDevice == null) throw new IllegalStateException("USB loopback test device must be connected"); testDevice.open(); - testDevice.claimInterface(0); + testDevice.claimInterface(LOOPBACK_INTF); } @AfterAll diff --git a/test-devices/composite-stm32/.clang-format b/test-devices/composite-stm32/.clang-format new file mode 100644 index 00000000..10e6b191 --- /dev/null +++ b/test-devices/composite-stm32/.clang-format @@ -0,0 +1,4 @@ +BasedOnStyle: Google +AllowShortIfStatementsOnASingleLine: false +IndentWidth: 4 +ColumnLimit: 120 diff --git a/test-devices/composite-stm32/.gitignore b/test-devices/composite-stm32/.gitignore new file mode 100644 index 00000000..89cc49cb --- /dev/null +++ b/test-devices/composite-stm32/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/test-devices/composite-stm32/.vscode/extensions.json b/test-devices/composite-stm32/.vscode/extensions.json new file mode 100644 index 00000000..080e70d0 --- /dev/null +++ b/test-devices/composite-stm32/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/test-devices/composite-stm32/README.md b/test-devices/composite-stm32/README.md new file mode 100644 index 00000000..fc008e56 --- /dev/null +++ b/test-devices/composite-stm32/README.md @@ -0,0 +1,61 @@ +# Composite Test Device + +Firmware for a composite device consisting of virtual serial port (aka CDC ACM) on interface 0 and 1 and a vendor-specific class on interface 2. This code is for an STM32F103C8 microcontroller. This microcontroller is found on many inexpensive development board, most notabily on the so called *Blue Pill*. Such boards are available for about 3 USD, including the required ST-Link programmer. + + +## Endpoint overview + +### Endpoints + +| Interface | Endpoint | Transfer Type | Direction | Packet Size | Function | +| - | - | - | - | - | - | +| – | 0x00 | Control | Bidirectional | | See *Control requests* below | +| 0 | 0x84 | Interrupt | Device to host | 16 bytes | CDC: Serial state events (not used) | +| 1 | 0x05 | Bulk | Host to device | 64 bytes | CDC: Serial data from host to device | +| 1 | 0x85 | Bulk | Device to host | 64 bytes | CDC: Serial data from device to host | +| 2 | 0x01 | Bulk | Host to device | 64 bytes | Loopback: all data received on this endpoint are then transmitted on endpoint 0x82. | +| 2 | 0x82 | Bulk | Device to host | 64 bytes | Loopback: Transmits the data received on endpoint 0x01. | +| 2 | 0x03 | Interrupt | Host to device | 16 bytes | Echo: All packets received on this endpoint are transmitted twice on endpoint 0x83. | +| 2 | 0x83 | Interrupt | Device to host | 16 bytes | Echo: Transmits all packets received on endpoint 0x03 twice. | + +The virtual serial port on interfaces 0 and 1 implements the CDC ACM class. All operating systems will recognize it as serial port and will automatically make it available as such. No drivers need to be installed. The implementations connects the incoming and outgoing data in a loopback configuration. So all data sent from the host to the device is send back to the host. Control requests to configure baud rates, parity etc. are accpeted but have no effect. And the implementation does not send any state events. + +The bulk endpoints 0x01 and 0x82 use an internal buffer of about 1000 bytes. Data up to this amount can be sent and received sequentially. If more data is sent without receiving at the same time, flow control kicks in and endpoint 0x01 will stop receiving data until there is room in the buffer. + + +### Control requests + +Several vendor-specific control requests are supported for testing: + +| `bmRequest` | `bRequest` | `wValue` | `wIndex` | `wLength` | Data | Action | +| - | - | - | - | - | - | - | +| 0x41 | 0x01 | *value* | 0 | 0 | none | Host to device: *value* is saved in device | +| 0x41 | 0x02 | 0 | 0 | 4 | *value* (32-bit LE) | Host to device: *value* is saved in device | +| 0xC1 | 0x03 | 0 | 0 | 4 | *value* (32-bit LE) | Device to host: saved *value* is transmitted | + +Additionally, the control request of CDC ACM PTSN (for configuring and querying the serial port) are accepted but have no effect in most cases. + + +## Building + +This project requires [PlatformIO](https://platformio.org/). The easiest way to get up and running is to use Visual Studio Code and then install the [PlatformIO IDE extension](https://marketplace.visualstudio.com/items?itemName=platformio.platformio-ide). + +After the extension is installed, open this folder and then click checkbox icon (*Build* action) in the status bar. + +To upload the code to the microcontroller: + +- Connect the ST-Link programmer to the development board +- Connect the ST-Link programmer to your computer +- Click the arrow icon (*Upload* action) in the status bar + + +## Binary release + +The directory `bin` contains a pre-built firmware. In order to upload it, a utility is needed, either [STM32CubeProgrammer](https://www.st.com/en/development-tools/stm32cubeprog.html) (requires an STM account, does not properly work on macOS) or the [open-source ST-Link command line utility](https://github.com/stlink-org/stlink). See the respective web site for installation instructions. + +If the commmand line utility is used, run these commands to upload it: + +``` +cd stm32-loopback/bin +st-flash write firmware.bin 0x08000000 +``` diff --git a/test-devices/composite-stm32/bin/firmware.bin b/test-devices/composite-stm32/bin/firmware.bin new file mode 100755 index 0000000000000000000000000000000000000000..4ae97923ff4d8368eb2d6ae9a95686b7e2fd3bda GIT binary patch literal 7060 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 +#include + +#include + +/** + * Circular buffer for raw binary data. + * + * The circular buffer allows a reader and writer to + * use the buffer concurrently. + * + * @param N number of bytes that fit into the buffer + */ +template +struct circ_buf { + private: + static constexpr int BUF_SIZE = N + 1; + + // 0 <= head < BUF_SIZE + // 0 <= tail < BUF_SIZE + // head == tail: buffer is empty + // Therefore, the buffer must never be filled completely. + volatile int buf_head = 0; // updated when adding data + volatile int buf_tail = 0; // updated when removing data + + uint8_t buffer[BUF_SIZE]; + + public: + /// Creates a new instance + circ_buf(); + + /// Returns the maximum number of bytes that can be added to the buffer + int avail_size(); + + /// Returns the number of bytes in the buffer + int data_size(); + + /** + * Gets the oldest data from the buffer and removes it. + * @param buf buffer to copy data to + * @param max_len maximum number of bytes to copy + * @return the effective number of bytes + */ + int get_data(uint8_t *buf, int max_len); + + /** + * Adds data to the buffer + * + * @param buf the buffer with the data + * @param len the number of bytes to add + */ + void add_data(const uint8_t *buf, int len); + + /// Resets (empties) the circular buffer + void reset(); +}; + +template +circ_buf::circ_buf() : buf_head(0), buf_tail(0) {} + +template +int circ_buf::avail_size() { + int head = buf_head; + int tail = buf_tail; + + if (head >= tail) { + return BUF_SIZE - (head - tail) - 1; + } else { + return tail - head - 1; + } +} + +template +int circ_buf::data_size() { + int head = buf_head; + int tail = buf_tail; + + if (head >= tail) { + return head - tail; + } else { + return BUF_SIZE - (tail - head); + } +} + +template +int circ_buf::get_data(uint8_t *buf, int max_len) { + int tail = buf_tail; + int head = buf_head; + + if (tail == head) + return 0; + + // get available data (without wrap around) + int len = (head > tail ? head : BUF_SIZE) - tail; + + // limit data to max_len + len = std::min(len, max_len); + + // copy data + memcpy(buf, buffer + tail, len); + + // update tail + tail += len; + if (tail >= BUF_SIZE) + tail -= BUF_SIZE; + buf_tail = tail; + + // sufficient data or no more data + if (len == max_len || tail != 0) + return len; + + // copy more data + return get_data(buf + len, max_len - len) + len; +} + +template +void circ_buf::add_data(const uint8_t *buf, int len) { + int head = buf_head; + + // copy first part (from head to end of circular buffer) + int n = std::min(len, BUF_SIZE - head); + memcpy(buffer + head, buf, n); + + // copy second part if needed (to start of circular buffer) + if (n < len) + memcpy(buffer, buf + n, len - n); + + // update head + head += len; + if (head >= BUF_SIZE) + head -= BUF_SIZE; + buf_head = head; +} + +template +void circ_buf::reset() { + buf_head = 0; + buf_tail = 0; +} diff --git a/test-devices/composite-stm32/include/common.h b/test-devices/composite-stm32/include/common.h new file mode 100644 index 00000000..427b2eb4 --- /dev/null +++ b/test-devices/composite-stm32/include/common.h @@ -0,0 +1,32 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Commmon functions +// + +#pragma once + +#include + +/** + * @brief Initializes systick services + */ +void systick_init(); + +/** + * @brief Gets the time. + * + * @return number of milliseconds since a fixed time in the past + */ +uint32_t millis(); + +/** + * @brief Delays execution (busy wait) + * @param ms delay length, in milliseconds + */ +void delay(uint32_t ms); diff --git a/test-devices/composite-stm32/include/usb_descriptor.h b/test-devices/composite-stm32/include/usb_descriptor.h new file mode 100644 index 00000000..0d01413b --- /dev/null +++ b/test-devices/composite-stm32/include/usb_descriptor.h @@ -0,0 +1,35 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// USB descriptor +// + +#pragma once + +#include + +#define INTR_MAX_PACKET_SIZE 16 +#define BULK_MAX_PACKET_SIZE 64 + +// Endpoints +#define EP_LOOPBACK_RX 0x01 +#define EP_LOOPBACK_TX 0x82 +#define EP_ECHO_RX 0x03 +#define EP_ECHO_TX 0x83 +#define EP_CDC_COMM 0x84 +#define EP_CDC_DATA_RX 0x05 +#define EP_CDC_DATA_TX 0x85 + +// USB descriptor string table +extern const char *const usb_desc_strings[4]; +// USB device descriptor +extern const struct usb_device_descriptor usb_device_desc; +// USB device configurations +extern const struct usb_config_descriptor usb_config_descs[]; + +void usb_init_serial_num(); diff --git a/test-devices/composite-stm32/include/wcid.h b/test-devices/composite-stm32/include/wcid.h new file mode 100644 index 00000000..2c1041ef --- /dev/null +++ b/test-devices/composite-stm32/include/wcid.h @@ -0,0 +1,17 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Microsoft WCID descriptors +// + +#pragma once + +#include + +// Register control request handlers for Microsoft WCID descriptors +void register_wcid_desc(usbd_device *usb_dev); diff --git a/test-devices/composite-stm32/platformio.ini b/test-devices/composite-stm32/platformio.ini new file mode 100644 index 00000000..7d74ce50 --- /dev/null +++ b/test-devices/composite-stm32/platformio.ini @@ -0,0 +1,4 @@ +[env:composite-stm32] +platform = ststm32 +board = bluepill_f103c8 +framework = libopencm3 diff --git a/test-devices/composite-stm32/src/common.cpp b/test-devices/composite-stm32/src/common.cpp new file mode 100644 index 00000000..5102b6bd --- /dev/null +++ b/test-devices/composite-stm32/src/common.cpp @@ -0,0 +1,37 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Commmon functions +// + +#include "common.h" + +#include + +static volatile uint32_t millis_count; + +uint32_t millis() { return millis_count; } + +void delay(uint32_t ms) { + int32_t target_time = millis_count + ms; + while (target_time - (int32_t)millis_count > 0) + ; +} + +void systick_init() { + // Initialize SysTick + systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); + systick_set_reload(rcc_ahb_frequency / 8 / 1000 - 1); + + // Enable and start + systick_interrupt_enable(); + systick_counter_enable(); +} + +// System tick timer interrupt handler +extern "C" void sys_tick_handler() { millis_count++; } diff --git a/test-devices/composite-stm32/src/main.cpp b/test-devices/composite-stm32/src/main.cpp new file mode 100644 index 00000000..9fe392b5 --- /dev/null +++ b/test-devices/composite-stm32/src/main.cpp @@ -0,0 +1,338 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Main program +// + +#include +#include +#include +#include +#include + +#include + +#include "circ_buf.h" +#include "common.h" +#include "usb_descriptor.h" +#include "wcid.h" + +#define USB_CDC_REQ_GET_LINE_CODING 0x21 + +static void on_usb_set_config(usbd_device *usbd_dev, uint16_t wValue); +static usbd_request_return_codes on_vendor_control_request(usbd_device *usbd_dev, usb_setup_data *req, uint8_t **buf, + uint16_t *len, usbd_control_complete_callback *complete); +static usbd_request_return_codes on_class_control_request(usbd_device *usbd_dev, usb_setup_data *req, uint8_t **buf, + uint16_t *len, usbd_control_complete_callback *complete); +static void on_usb_loopback_received(usbd_device *usbd_dev, uint8_t ep); +static void on_usb_loopback_transmitted(usbd_device *usbd_dev, uint8_t ep); +static void on_usb_serial_received(usbd_device *usbd_dev, uint8_t ep); +static void on_usb_serial_transmitted(usbd_device *usbd_dev, uint8_t ep); +static void on_usb_serial_notif_transmitted(usbd_device *usbd_dev, uint8_t ep); +static void on_usb_echo_received(usbd_device *usbd_dev, uint8_t ep); +static void on_usb_echo_transmitted(usbd_device *usbd_dev, uint8_t ep); +static void check_loopback_buffers(); +static void check_serial_buffers(); + +// USB device instance +static usbd_device *usb_device; + +// buffer for control requests +static uint8_t usbd_control_buffer[256]; + +// Circular buffer for loopback test endpoints +static circ_buf<1024> loopback_buffer; + +// Minimum free space in circular buffer for requesting more packets +static constexpr int MIN_FREE_SPACE = 2 * BULK_MAX_PACKET_SIZE; + +// indicates if loopback data is being transmitted +static bool is_loopback_tx = false; + +// indicates if the loopback RX endpoint is forced to NAK to prevent receiving further data +static bool is_loopback_rx_nak = false; + +// value that can be saved and retrieved with control requests +static uint32_t saved_value; + +// echo message +static char echo_msg[INTR_MAX_PACKET_SIZE]; + +// echo message length +static int echo_msg_len; + +// number of echos left to transmit (if > 1, RX endpointed is NAKed) +static int num_echos_left; + +// Circular buffer for serial port +static circ_buf<1024> serial_buffer; + +// indicates if serial data is being transmitted +static bool is_serial_tx = false; + +// indicates if the serial RX endpoint is forced to NAK to prevent receiving further data +static bool is_serial_rx_nak = false; + +void init() { + // Enable required clocks + rcc_clock_setup_in_hse_8mhz_out_72mhz(); + rcc_periph_clock_enable(RCC_GPIOA); + rcc_periph_clock_enable(RCC_GPIOC); + rcc_periph_clock_enable(RCC_AFIO); + rcc_periph_clock_enable(RCC_SPI1); + rcc_periph_clock_enable(RCC_USB); + + // Initialize systick services + systick_init(); +} + +void usb_init() { + // reset USB peripheral + rcc_periph_reset_pulse(RST_USB); + + // Pull USB D+ (A12) low for 80ms to trigger device reenumeration + gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO12); + gpio_clear(GPIOA, GPIO12); + delay(80); + + usb_init_serial_num(); + + // create USB device + usb_device = usbd_init(&st_usbfs_v1_usb_driver, &usb_device_desc, usb_config_descs, usb_desc_strings, + sizeof(usb_desc_strings) / sizeof(usb_desc_strings[0]), usbd_control_buffer, + sizeof(usbd_control_buffer)); + + // Set callback for config calls + usbd_register_set_config_callback(usb_device, on_usb_set_config); + register_wcid_desc(usb_device); +} + +// Called when the host connects to the device and selects a configuration +void on_usb_set_config(usbd_device *usbd_dev, __attribute__((unused)) uint16_t wValue) { + register_wcid_desc(usbd_dev); + + // register control request handler for vendor specific requests (used for test) + usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, on_vendor_control_request); + + // resgier control request handler for class specific requests (used for CDC ACM) + usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, on_class_control_request); + + usbd_ep_setup(usbd_dev, EP_CDC_COMM, USB_ENDPOINT_ATTR_INTERRUPT, INTR_MAX_PACKET_SIZE, + on_usb_serial_notif_transmitted); + usbd_ep_setup(usbd_dev, EP_CDC_DATA_RX, USB_ENDPOINT_ATTR_BULK, BULK_MAX_PACKET_SIZE, on_usb_serial_received); + usbd_ep_setup(usbd_dev, EP_CDC_DATA_TX, USB_ENDPOINT_ATTR_BULK, BULK_MAX_PACKET_SIZE, on_usb_serial_transmitted); + + usbd_ep_setup(usbd_dev, EP_LOOPBACK_RX, USB_ENDPOINT_ATTR_BULK, BULK_MAX_PACKET_SIZE, on_usb_loopback_received); + usbd_ep_setup(usbd_dev, EP_LOOPBACK_TX, USB_ENDPOINT_ATTR_BULK, BULK_MAX_PACKET_SIZE, on_usb_loopback_transmitted); + usbd_ep_setup(usbd_dev, EP_ECHO_RX, USB_ENDPOINT_ATTR_INTERRUPT, INTR_MAX_PACKET_SIZE, on_usb_echo_received); + usbd_ep_setup(usbd_dev, EP_ECHO_TX, USB_ENDPOINT_ATTR_INTERRUPT, INTR_MAX_PACKET_SIZE, on_usb_echo_transmitted); + + loopback_buffer.reset(); + is_loopback_tx = false; + is_loopback_rx_nak = false; + num_echos_left = 0; + echo_msg_len = 0; + saved_value = 0; + serial_buffer.reset(); + is_serial_tx = false; + is_serial_rx_nak = false; +} + +// Called when loopback data has been received +void on_usb_loopback_received(usbd_device *usbd_dev, uint8_t ep) { + // Retrieve USB data (has side effect of setting endpoint to VALID) + uint8_t packet[BULK_MAX_PACKET_SIZE] __attribute__((aligned(4))); + int len = usbd_ep_read_packet(usbd_dev, ep, packet, sizeof(packet)); + + // copy data into circular buffer + loopback_buffer.add_data(packet, len); +} + +// Called when loopback data has been transmitted +void on_usb_loopback_transmitted(__attribute__((unused)) usbd_device *usbd_dev, __attribute__((unused)) uint8_t ep) { + is_loopback_tx = false; +} + +void check_loopback_buffers() { + // If RX is stopped and there is sufficient space in the buffer, resume it + if (is_loopback_rx_nak) { + if (loopback_buffer.avail_size() >= MIN_FREE_SPACE) { + usbd_ep_nak_set(usb_device, EP_LOOPBACK_RX, 0); + is_loopback_rx_nak = false; + } + + // If RX is enabled but the space in the buffer is low, stop it + } else { + // check if there is space for less than 2 packets + if (loopback_buffer.avail_size() < MIN_FREE_SPACE) { + // set endpoint from VALID to NAK + usbd_ep_nak_set(usb_device, EP_LOOPBACK_RX, 1); + is_loopback_rx_nak = true; + } + } + + // If no data is being transmitted and there is data in the buffer, transmit a packet + if (!is_loopback_tx && loopback_buffer.data_size() >= 0) { + uint8_t packet[BULK_MAX_PACKET_SIZE] __attribute__((aligned(4))); + int len = loopback_buffer.get_data(packet, BULK_MAX_PACKET_SIZE); + usbd_ep_write_packet(usb_device, EP_LOOPBACK_TX, packet, len); + is_loopback_tx = true; + } +} + +// Called when echo data has been received +void on_usb_echo_received(usbd_device *usbd_dev, uint8_t ep) { + // Retrieve USB data (has side effect of setting endpoint to VALID) + echo_msg_len = usbd_ep_read_packet(usbd_dev, EP_ECHO_RX, echo_msg, sizeof(echo_msg)); + usbd_ep_nak_set(usbd_dev, ep, 1); + + usbd_ep_write_packet(usbd_dev, EP_ECHO_TX, echo_msg, echo_msg_len); + num_echos_left = 2; +} + +// Called when echo data has been transmitted +void on_usb_echo_transmitted(__attribute__((unused)) usbd_device *usbd_dev, __attribute__((unused)) uint8_t ep) { + num_echos_left--; + if (num_echos_left > 0) { + usbd_ep_write_packet(usbd_dev, ep, echo_msg, echo_msg_len); + } else { + usbd_ep_nak_set(usbd_dev, EP_ECHO_RX, 0); + } +} + +// Called when serial data has been received +void on_usb_serial_received(usbd_device *usbd_dev, uint8_t ep) { + // Retrieve USB data (has side effect of setting endpoint to VALID) + uint8_t packet[BULK_MAX_PACKET_SIZE] __attribute__((aligned(4))); + int len = usbd_ep_read_packet(usbd_dev, ep, packet, sizeof(packet)); + + // copy data into circular buffer + serial_buffer.add_data(packet, len); +} + +// Called when serial data has been transmitted +void on_usb_serial_transmitted(__attribute__((unused)) usbd_device *usbd_dev, __attribute__((unused)) uint8_t ep) { + is_serial_tx = false; +} + +// Called when a serial state notification has been transmitted +void on_usb_serial_notif_transmitted(__attribute__((unused)) usbd_device *usbd_dev, + __attribute__((unused)) uint8_t ep) { + // not used +} + +void check_serial_buffers() { + // If RX is stopped and there is sufficient space in the buffer, resume it + if (is_serial_rx_nak) { + if (serial_buffer.avail_size() >= MIN_FREE_SPACE) { + usbd_ep_nak_set(usb_device, EP_CDC_DATA_RX, 0); + is_serial_rx_nak = false; + } + + // If RX is enabled but the space in the buffer is low, stop it + } else { + // check if there is space for less than 2 packets + if (serial_buffer.avail_size() < MIN_FREE_SPACE) { + // set endpoint from VALID to NAK + usbd_ep_nak_set(usb_device, EP_CDC_DATA_RX, 1); + is_serial_rx_nak = true; + } + } + + // If no data is being transmitted and there is data in the buffer, transmit a packet + if (!is_serial_tx && serial_buffer.data_size() >= 0) { + uint8_t packet[BULK_MAX_PACKET_SIZE] __attribute__((aligned(4))); + int len = serial_buffer.get_data(packet, BULK_MAX_PACKET_SIZE); + usbd_ep_write_packet(usb_device, EP_CDC_DATA_TX, packet, len); + is_serial_tx = true; + } +} + +usbd_request_return_codes on_vendor_control_request(__attribute__((unused)) usbd_device *usbd_dev, usb_setup_data *req, + uint8_t **buf, uint16_t *len, + __attribute__((unused)) usbd_control_complete_callback *complete) { + switch (req->bRequest) { + case 1: + if (req->wIndex == 0 && req->wLength == 0) { + saved_value = req->wValue; + return USBD_REQ_HANDLED; + } else { + return USBD_REQ_NOTSUPP; + } + break; + + case 2: + if (req->wIndex == 0 && req->wLength == 4) { + uint32_t *value = reinterpret_cast(*buf); + saved_value = *value; + return USBD_REQ_HANDLED; + } else { + return USBD_REQ_NOTSUPP; + } + break; + + case 3: + if (req->wIndex == 0) { + uint8_t *value = reinterpret_cast(&saved_value); + *len = std::min(*len, (uint16_t)4); + memcpy(*buf, value, *len); + return USBD_REQ_HANDLED; + } else { + return USBD_REQ_NOTSUPP; + } + break; + + default:; // fall through + } + + return USBD_REQ_NEXT_CALLBACK; +} + +// Process ACM requests on control endpoint +usbd_request_return_codes on_class_control_request(__attribute__((unused)) usbd_device *usbd_dev, usb_setup_data *req, + uint8_t **buf, uint16_t *len, + __attribute__((unused)) usbd_control_complete_callback *complete) { + switch (req->bRequest) { + case USB_CDC_REQ_SET_LINE_CODING: + if (*len < sizeof(struct usb_cdc_line_coding)) + return USBD_REQ_NOTSUPP; + + return USBD_REQ_HANDLED; + + case USB_CDC_REQ_GET_LINE_CODING: { + if (*len < sizeof(struct usb_cdc_line_coding)) + return USBD_REQ_NOTSUPP; + + struct usb_cdc_line_coding *line_coding = (struct usb_cdc_line_coding *)*buf; + line_coding->dwDTERate = 115200; + line_coding->bDataBits = 8; + line_coding->bParityType = 0; + line_coding->bCharFormat = 0; + + *len = sizeof(struct usb_cdc_line_coding); + return USBD_REQ_HANDLED; + } + + case USB_CDC_REQ_SET_CONTROL_LINE_STATE: + return USBD_REQ_HANDLED; + } + return USBD_REQ_NEXT_CALLBACK; +} + +int main() { + init(); + usb_init(); + + while (true) { + usbd_poll(usb_device); + check_loopback_buffers(); + check_serial_buffers(); + } +} diff --git a/test-devices/composite-stm32/src/usb_descriptor.cpp b/test-devices/composite-stm32/src/usb_descriptor.cpp new file mode 100644 index 00000000..6c155c33 --- /dev/null +++ b/test-devices/composite-stm32/src/usb_descriptor.cpp @@ -0,0 +1,302 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// USB descriptor +// + +#include "usb_descriptor.h" + +#include +#include + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +static void put_hex(uint32_t value, char *buf, int len); + +#define USB_VID 0xcafe // Vendor ID +#define USB_PID 0xcea0 // Product ID +#define USB_DEVICE_REL 0x0032 // release 0.3.2 + +// Interface index +#define INTF_CDC_COMM 0 +#define INTF_CDC_DATA 1 +#define INTF_LOOPBACK 2 + +static char serial_num[13]; + +const char *const usb_desc_strings[] = { + "JavaDoesUSB", // USB Manufacturer + "Loopback", // USB Product + serial_num, // Serial number, + "Loopback Serial Port" // Function description +}; + +enum usb_strings_index { // Index of USB strings. Must sync with above, starts from 1. + USB_STRINGS_MANUFACTURER_ID = 1, + USB_STRINGS_PRODUCT_ID, + USB_STRINGS_SERIAL_NUMBER_ID, + USB_STRINGS_SERIAL_PORT_ID, +}; + +typedef struct { + struct usb_cdc_header_descriptor header; + struct usb_cdc_call_management_descriptor call_mgmt; + struct usb_cdc_acm_descriptor acm; + struct usb_cdc_union_descriptor cdc_union; +} __attribute__((packed)) cdcacm_functional_descriptors; + +// --- CDC ACM --- + +// CDC communicatoin endpoint +static const usb_endpoint_descriptor cdc_comm_ep_desc[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = EP_CDC_COMM, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = INTR_MAX_PACKET_SIZE, + .bInterval = 32, + .extra = nullptr, + .extralen = 0, +}}; + +// CDC data endpoints +static const usb_endpoint_descriptor cdc_data_ep_desc[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = EP_CDC_DATA_RX, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = BULK_MAX_PACKET_SIZE, + .bInterval = 1, + .extra = nullptr, + .extralen = 0, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = EP_CDC_DATA_TX, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = BULK_MAX_PACKET_SIZE, + .bInterval = 1, + .extra = nullptr, + .extralen = 0, + }}; + +// CDC ACM function descriptor +static const cdcacm_functional_descriptors cdc_func_desc = { + .header = + { + .bFunctionLength = sizeof(usb_cdc_header_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_HEADER, + .bcdCDC = 0x0110, + }, + .call_mgmt = + { + // see chapter 5.3.1 in PSTN120 + .bFunctionLength = sizeof(usb_cdc_call_management_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, + .bmCapabilities = 0, // no call management + .bDataInterface = INTF_CDC_DATA, + }, + .acm = + { + // see chapter 5.3.2 in PSTN120 + .bFunctionLength = sizeof(usb_cdc_acm_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_ACM, + .bmCapabilities = 2, // device supports the request combination of Set_Line_Coding, Set_Control_Line_State, + // Get_Line_Coding, and the notification Serial_State + }, + .cdc_union = { + .bFunctionLength = sizeof(usb_cdc_union_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_UNION, + .bControlInterface = INTF_CDC_COMM, + .bSubordinateInterface0 = INTF_CDC_DATA, + }}; + +// CDC interfaces descriptors +static const usb_interface_descriptor cdc_comm_if_desc[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = INTF_CDC_COMM, + .bAlternateSetting = 0, + .bNumEndpoints = ARRAY_SIZE(cdc_comm_ep_desc), + .bInterfaceClass = USB_CLASS_CDC, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_PROTOCOL_AT, + .iInterface = 0, + .endpoint = cdc_comm_ep_desc, + .extra = &cdc_func_desc, + .extralen = sizeof(cdc_func_desc), +}}; + +static const usb_interface_descriptor cdc_data_if_desc[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = INTF_CDC_DATA, + .bAlternateSetting = 0, + .bNumEndpoints = ARRAY_SIZE(cdc_data_ep_desc), + .bInterfaceClass = USB_CLASS_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + .endpoint = cdc_data_ep_desc, + .extra = nullptr, + .extralen = 0, +}}; + +// CDC interface association +static const usb_iface_assoc_descriptor cdc_assoc_desc = { + .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, + .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, + .bFirstInterface = INTF_CDC_COMM, + .bInterfaceCount = 2, + .bFunctionClass = USB_CLASS_CDC, + .bFunctionSubClass = USB_CDC_SUBCLASS_ACM, + .bFunctionProtocol = USB_CDC_PROTOCOL_AT, + .iFunction = USB_STRINGS_SERIAL_PORT_ID, +}; + +// --- Loopback test interface --- + +// Test endpoints +static const struct usb_endpoint_descriptor loopback_endpoint_descs[] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = EP_LOOPBACK_RX, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = BULK_MAX_PACKET_SIZE, + .bInterval = 0, + .extra = nullptr, + .extralen = 0, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = EP_LOOPBACK_TX, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = BULK_MAX_PACKET_SIZE, + .bInterval = 0, + .extra = nullptr, + .extralen = 0, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = EP_ECHO_RX, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = INTR_MAX_PACKET_SIZE, + .bInterval = 16, + .extra = nullptr, + .extralen = 0, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = EP_ECHO_TX, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = INTR_MAX_PACKET_SIZE, + .bInterval = 16, + .extra = nullptr, + .extralen = 0, + }, +}; + +// Test interface +static const struct usb_interface_descriptor loopback_if_descs[] = { + { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = INTF_LOOPBACK, + .bAlternateSetting = 0, + .bNumEndpoints = ARRAY_SIZE(loopback_endpoint_descs), + .bInterfaceClass = USB_CLASS_VENDOR, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, // vendor specific + .iInterface = 0, + .endpoint = loopback_endpoint_descs, + .extra = nullptr, + .extralen = 0, + }, +}; + +static const struct usb_interface usb_interfaces[] = { + { + .cur_altsetting = nullptr, + .num_altsetting = ARRAY_SIZE(cdc_comm_if_desc), + .iface_assoc = &cdc_assoc_desc, + .altsetting = cdc_comm_if_desc, + }, + { + .cur_altsetting = nullptr, + .num_altsetting = ARRAY_SIZE(cdc_data_if_desc), + .iface_assoc = nullptr, + .altsetting = cdc_data_if_desc, + }, + { + .cur_altsetting = nullptr, + .num_altsetting = ARRAY_SIZE(loopback_if_descs), + .iface_assoc = nullptr, + .altsetting = loopback_if_descs, + }, +}; + +const struct usb_config_descriptor usb_config_descs[] = { + { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = ARRAY_SIZE(usb_interfaces), + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, // bus-powered, i.e. it draws power from USB bus + .bMaxPower = 0xfa, // 500 mA + .interface = usb_interfaces, + }, +}; + +const struct usb_device_descriptor usb_device_desc = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, // USB version 2.00 + .bDeviceClass = 0, // defined by interfaces + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = USB_VID, + .idProduct = USB_PID, + .bcdDevice = USB_DEVICE_REL, + .iManufacturer = USB_STRINGS_MANUFACTURER_ID, + .iProduct = USB_STRINGS_PRODUCT_ID, + .iSerialNumber = USB_STRINGS_SERIAL_NUMBER_ID, + .bNumConfigurations = ARRAY_SIZE(usb_config_descs), +}; + +void usb_init_serial_num() { + uint32_t id0 = DESIG_UNIQUE_ID0; + uint32_t id1 = DESIG_UNIQUE_ID1; + uint32_t id2 = DESIG_UNIQUE_ID2; + + id0 += id2; + + put_hex(id0, serial_num, 8); + put_hex(id1, serial_num + 8, 4); + serial_num[12] = 0; +} + +const static char HEX_DIGITS[] = "0123456789ABCDEF"; + +void put_hex(uint32_t value, char *buf, int len) { + for (int idx = 0; idx < len; idx++) { + buf[idx] = HEX_DIGITS[value >> 28]; + value = value << 4; + } +} diff --git a/test-devices/composite-stm32/src/wcid.cpp b/test-devices/composite-stm32/src/wcid.cpp new file mode 100644 index 00000000..2c284f36 --- /dev/null +++ b/test-devices/composite-stm32/src/wcid.cpp @@ -0,0 +1,81 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Microsoft WCID descriptors +// + +#include + +#include + +static usbd_request_return_codes msft_string_desc(usbd_device *usbd_dev, usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete); +static usbd_request_return_codes msft_feature_desc(usbd_device *usbd_dev, usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete); + +// Registers additional control request handlers to implement +// See https://github.com/pbatard/libwdi/wiki/WCID-Devices +void register_wcid_desc(usbd_device *usb_dev) { + usbd_register_control_callback(usb_dev, + USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + msft_string_desc); + usbd_register_control_callback(usb_dev, + USB_REQ_TYPE_VENDOR, USB_REQ_TYPE_TYPE, + msft_feature_desc); +} + +#define WCID_VENDOR_CODE 0x37 + +// Microsoft WCID string descriptor (string index 0xee) +static const uint8_t msft_sig_desc[] = { + 0x12, // length = 18 bytes + USB_DT_STRING, // descriptor type string + 'M', 0, 'S', 0, 'F', 0, 'T', 0, // 'M', 'S', 'F', 'T' + '1', 0, '0', 0, '0', 0, // '1', '0', '0' + WCID_VENDOR_CODE, // vendor code + 0 // padding +}; + +// Microsoft WCID feature descriptor (index 0x0004) +static const uint8_t wcid_feature_desc[] = { + 0x28, 0x00, 0x00, 0x00, // length = 40 bytes + 0x00, 0x01, // version 1.0 (in BCD) + 0x04, 0x00, // compatibility descriptor index 0x0004 + 0x01, // number of sections + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved (7 bytes) + 0x00, // interface number 0 + 0x01, // reserved + 0x57, 0x49, 0x4E, 0x55, 0x53, 0x42, 0x00, 0x00, // Compatible ID "WINUSB\0\0" + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Subcompatible ID (unused) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // reserved 6 bytes +}; + +usbd_request_return_codes msft_string_desc(__attribute__((unused)) usbd_device *usbd_dev, usb_setup_data *req, + uint8_t **buf, uint16_t *len, + __attribute__((unused)) usbd_control_complete_callback *complete) { + // 0x03: descriptor type string + // 0xee: Microsoft WCID string index + if (req->bRequest == USB_REQ_GET_DESCRIPTOR && req->wValue == 0x03ee) { + *buf = const_cast(reinterpret_cast(&msft_sig_desc)); + *len = std::min(*len, (uint16_t)msft_sig_desc[0]); + return USBD_REQ_HANDLED; + } + + return USBD_REQ_NEXT_CALLBACK; +} + +usbd_request_return_codes msft_feature_desc(__attribute__((unused)) usbd_device *usbd_dev, usb_setup_data *req, + uint8_t **buf, uint16_t *len, + __attribute__((unused)) usbd_control_complete_callback *complete) { + // 0x0004: Microsoft WCID index for feature descriptor + if (req->bRequest == WCID_VENDOR_CODE && req->wIndex == 0x0004) { + *buf = const_cast(reinterpret_cast(&wcid_feature_desc)); + *len = std::min(*len, (uint16_t)wcid_feature_desc[0]); + return USBD_REQ_HANDLED; + } + + return USBD_REQ_NEXT_CALLBACK; +} diff --git a/test-devices/loopback-stm32/bin/save_bin.sh b/test-devices/loopback-stm32/bin/save_bin.sh index e9755685..0e134cfb 100755 --- a/test-devices/loopback-stm32/bin/save_bin.sh +++ b/test-devices/loopback-stm32/bin/save_bin.sh @@ -1,2 +1,2 @@ #!/bin/bash -cp ../.pio/build/stm32-loopback/firmware.bin . +cp ../.pio/build/loopback-stm32/firmware.bin . diff --git a/test-devices/loopback-stm32/platformio.ini b/test-devices/loopback-stm32/platformio.ini index 58ade09b..d586996e 100644 --- a/test-devices/loopback-stm32/platformio.ini +++ b/test-devices/loopback-stm32/platformio.ini @@ -1,4 +1,4 @@ -[env:stm32-loopback] +[env:loopback-stm32] platform = ststm32 board = bluepill_f103c8 framework = libopencm3 From 1e5af645ba6d8a751c779d2a8f494607b14aa4ca Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 10 Sep 2022 23:54:56 +0200 Subject: [PATCH 081/433] MS OS 2.0 descriptors for composite test device --- .../composite-stm32/.vscode/settings.json | 7 + .../composite-stm32/include/usb_bos.h | 263 ++++++++++++++++++ .../composite-stm32/include/usb_bos_desc.h | 28 ++ test-devices/composite-stm32/include/wcid.h | 17 -- test-devices/composite-stm32/src/main.cpp | 11 +- test-devices/composite-stm32/src/usb_bos.cpp | 98 +++++++ .../composite-stm32/src/usb_bos_desc.c | 89 ++++++ .../composite-stm32/src/usb_descriptor.cpp | 184 ++++++------ test-devices/composite-stm32/src/wcid.cpp | 81 ------ 9 files changed, 587 insertions(+), 191 deletions(-) create mode 100644 test-devices/composite-stm32/.vscode/settings.json create mode 100644 test-devices/composite-stm32/include/usb_bos.h create mode 100644 test-devices/composite-stm32/include/usb_bos_desc.h delete mode 100644 test-devices/composite-stm32/include/wcid.h create mode 100644 test-devices/composite-stm32/src/usb_bos.cpp create mode 100644 test-devices/composite-stm32/src/usb_bos_desc.c delete mode 100644 test-devices/composite-stm32/src/wcid.cpp diff --git a/test-devices/composite-stm32/.vscode/settings.json b/test-devices/composite-stm32/.vscode/settings.json new file mode 100644 index 00000000..7e488cff --- /dev/null +++ b/test-devices/composite-stm32/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "files.associations": { + "usbd.h": "c", + "usb_bos.h": "c", + "usb_bos_desc.h": "c" + } +} \ No newline at end of file diff --git a/test-devices/composite-stm32/include/usb_bos.h b/test-devices/composite-stm32/include/usb_bos.h new file mode 100644 index 00000000..f73ebd65 --- /dev/null +++ b/test-devices/composite-stm32/include/usb_bos.h @@ -0,0 +1,263 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// USB binary device object store (BOS) +// + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/// Descriptor type Binary Device Object Store (BOS) + +static const uint8_t USB_DT_BOS = 15; +/// Descriptor type Device Capability +#define USB_DT_DEVICE_CAPABILITY 16 + +/// Microsoft WCID string index +static const uint8_t USB_WIN_MSFT_WCID_STR_IDX = 0xee; + +/// Microsoft compatible ID feature descriptor request index (wIndex) +static const uint16_t USB_WIN_COMP_ID_REQ_INDEX = 0x0004; + +#define USB_WIN_WCID_DEFAULT_VENDOR_CODE 0xf0 + + + +/// USB BOS device capability types +typedef enum { + /// USB BOS device capability type for Wireless USB-specific device level capabilities + USB_DEV_CAPA_WIRELESS_USB = 0x01, + /// USB BOS device capability type for USB 2.0 extension descriptor + USB_DEV_CAPA_USB_2_0_EXTENSION = 0x02, + /// USB BOS device capability type for SuperSpeed USB specific device level capabilities + USB_DEV_CAPA_SUPERSPEED_USB = 0x03, + /// USB BOS device capability type for instance unique ID used to identify the instance across all operating modes + USB_DEV_CAPA_CONTAINER_ID = 0x04, + /// USB BOS device capability type for device capability specific to a particular platform/operating system + USB_DEV_CAPA_PLATFORM = 0x05, + /// USB BOS device capability type for various PD capabilities of this device + USB_DEV_CAPA_POWER_DELIVERY_CAPABILITY = 0x06, + /// USB BOS device capability type for information on each battery supported by the device + USB_DEV_CAPA_BATTERY_INFO_CAPABILITY = 0x07, + /// USB BOS device capability type for consumer characteristics of a port on the device + USB_DEV_CAPA_PD_CONSUMER_PORT_CAPABILITY = 0x08, + /// USB BOS device capability type for provider characteristics of a port on the device + USB_DEV_CAPA_PD_PROVIDER_PORT_CAPABILITY = 0x09, + /// USB BOS device capability type for SuperSpeed Plus USB specific device level capabilities + USB_DEV_CAPA_SUPERSPEED_PLUS = 0x0a, + /// USB BOS device capability type for precision time measurement (PTM) capability descriptor + USB_DEV_CAPA_PRECISION_TIME_MEASUREMENT = 0x0b, + /// USB BOS device capability type for wireless USB 1.1-specific device level capabilities + USB_DEV_CAPA_WIRELESS_USB_EXT = 0x0c, + /// USB BOS device capability type for billboard capability + USB_DEV_CAPA_BILLBOARD = 0x0d, + /// USB BOS device capability type for authentication capability descriptor + USB_DEV_CAPA_AUTHENTICATION = 0x0e, + /// USB BOS device capability type billboard ex capability + USB_DEV_CAPA_BILLBOARD_EX = 0x0f, + /// USB BOS device capability type for summarizing configuration information for a function implemented by the device + USB_DEV_CAPA_CONFIGURATION_SUMMARY = 0x10, +} usb_dev_capa_type_e; + +/// USB BOS descriptor +typedef struct usb_bos_desc { + /// Size of this descriptor + uint8_t bLength; + /// Type of this descriptor (use USB_DT_BOS) + uint8_t bDescriptorType; + /// Length of this descriptor and all of its sub descriptors + uint16_t wTotalLength; + /// The number of separate device capability descriptors in the BOS + uint8_t bNumDeviceCaps; +} __attribute__((packed)) usb_bos_desc; + +/// USB BOS device capability descriptor (generic) +typedef struct usb_bos_device_capability_desc { + /// Size of this descriptor + uint8_t bLength; + /// Type of this descriptor (use USB_DT_DEVICE_CAPABILITY) + uint8_t bDescriptorType; + /// Device capability type (see usb_dev_capa_type_e) + uint8_t bDevCapabilityType; + /// Capability-specific data + uint8_t data[]; +} __attribute__((packed)) usb_bos_device_capability_desc; + +/// USB BOS device capability platform descriptor +typedef struct usb_bos_platform_desc { + /// Size of this descriptor + uint8_t bLength; + /// Type of this descriptor (use USB_DT_DEVICE_CAPABILITY) + uint8_t bDescriptorType; + /// Device capability type (use USB_DEV_CAPA_PLATFORM) + uint8_t bDevCapabilityType; + /// Reserved. Set to 0. + uint8_t bReserved; + /// A 128-bit number (UUID) that uniquely identifies a platform specific capability of the device + uint8_t platformCapabilityUUID[16]; + /// Platform-specific capability data + uint8_t capabilityData[]; +} __attribute__((packed)) usb_bos_platform_desc; + + +/// Microsoft OS 2.0 request `wIndex` value to retrieve MS OS 2.0 vendor-specific descriptor +static const uint8_t USB_MSOS20_CTRL_INDEX_DESC = 0x07; +/// Microsoft OS 2.0 request `wIndex` value to set alternate enumeration +static const uint8_t USB_MSOS20_CTRL_INDEX_SET_ALT_ENUM = 0x08; + +/// UUID for Microsoft OS 2.0 platform capability: {d8dd60df-4589-4cc7-9cd2-659d9e648a9f} +#define USB_PLATFORM_CAPABILITY_MICROSOFT_OS20_UUID {0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F} + +/// Microsoft OS 2.0 descriptor types +typedef enum { + /// Microsoft OS 2.0 descriptor type for set header + USB_MSOS20_DT_SET_HEADER_DESCRIPTOR = 0x00, + /// Microsoft OS 2.0 descriptor type for configuration subset header + USB_MSOS20_DT_SUBSET_HEADER_CONFIGURATION = 0x01, + /// Microsoft OS 2.0 descriptor type for function subset header + USB_MSOS20_DT_SUBSET_HEADER_FUNCTION = 0x02, + /// Microsoft OS 2.0 feature descriptor type for compatible ID descriptor + USB_MSOS20_DT_FEATURE_COMPATBLE_ID = 0x03, + /// Microsoft OS 2.0 feature descriptor type for registry propery descriptor + USB_MSOS20_DT_FEATURE_REG_PROPERTY = 0x04, + /// Microsoft OS 2.0 feature descriptor type for minimum USB resume time descriptor + USB_MSOS20_DT_FEATURE_MIN_RESUME_TIME = 0x05, + /// Microsoft OS 2.0 feature descriptor type for model ID descriptor + USB_MSOS20_DT_FEATURE_MODEL_ID = 0x06, + /// Microsoft OS 2.0 feature descriptor type for CCGP device descriptor + USB_MSOS20_DT_FEATURE_CCGP_DEVICE = 0x07, + /// Microsoft OS 2.0 feature descriptor type for vendor revision descriptor + USB_MSOS20_DT_FEATURE_VENDOR_REVISION = 0x08, +} usb_msos20_desc_type_e; + +/// Microsoft OS 2.0 property types +typedef enum { + /// A NULL-terminated Unicode String (REG_SZ) + USB_MSOS20_PROP_DATA_TYPE_STRING = 1, + /// A NULL-terminated Unicode String that includes environment variables (REG_EXPAND_SZ) + USB_MSOS20_PROP_DATA_TYPE_STRING_EXPAND = 2, + /// Free-form binary (REG_BINARY) + USB_MSOS20_PROP_DATA_TYPE_BINARY = 3, + /// A little-endian 32-bit integer (REG_DWORD_LITTLE_ENDIAN) + USB_MSOS20_PROP_DATA_TYPE_INT32LE = 4, + /// A big-endian 32-bit integer (REG_DWORD_BIG_ENDIAN) + USB_MSOS20_PROP_DATA_TYPE_INT32BE = 5, + /// A NULL-terminated Unicode string that contains a symbolic link (REG_LINK) + USB_MSOS20_PROP_DATA_TYPE_STRING_LINK = 6, + /// Multiple NULL-terminated Unicode strings (REG_MULTI_SZ) + USB_MSOS20_PROP_DATA_TYPE_STRING_MULTI = 7, +} usb_msos20_prop_data_type_e; + +/// Microsoft OS 2.0 descriptor Windows version +typedef enum { + /// Windows version 8.1 + USB_MSOS20_WIN_VER_8_1 = 0x06030000, + /// Windows version 10 + USB_MSOS20_WIN_VER_10 = 0x0a000000, +} usb_msos20_win_ver_e; + +/// USB BOS device capability platform descriptor for Microsoft OS 2.0 +typedef struct usb_msos20_platform_desc { + /// Size of this descriptor + uint8_t bLength; + /// Type of this descriptor (use USB_DT_DEVICE_CAPABILITY) + uint8_t bDescriptorType; + /// Device capability type (use USB_DEV_CAPA_PLATFORM) + uint8_t bDevCapabilityType; + /// Reserved. Set to 0. + uint8_t bReserved; + /// A 128-bit number / UUID (use USB_PLATFORM_CAPABILITY_MICROSOFT_OS20_UUID) + uint8_t platformCapabilityUUID[16]; + /// Minimum Windows version (see usb_msos20_win_ver_e) + uint32_t dwWindowsVersion; + /// The length, in bytes, of the MS OS 2.0 descriptor set + uint16_t wMSOSDescriptorSetTotalLength; + /// Vendor defined code to use to retrieve this version of the MS OS 2.0 descriptor and also to set alternate enumeration behavior on the device + uint8_t bMS_VendorCode; + /// A non-zero value to send to the device to indicate that the device may return non-default USB descriptors for enumeration. If the device does not support alternate enumeration, this value shall be 0. + uint8_t bAltEnumCode; +} __attribute__((packed)) usb_msos20_platform_desc; + +/// Microsoft OS 2.0 descriptor set header +typedef struct usb_msos20_desc_set_header +{ + /// The length, in bytes, of this header + uint16_t wLength; + /// The type of this descriptor (use USB_MSOS20_DT_SET_HEADER_DESCRIPTOR) + uint16_t wDescriptorType; + /// Windows version (see usb_msos20_win_ver_e) + uint32_t dwWindowsVersion; + /// The size of entire MS OS 2.0 descriptor set. The value shall match the value in the descriptor set information structure. + uint16_t wTotalLength; +} __attribute__((packed)) usb_msos20_desc_set_header; + +/// Microsoft OS 2.0 descriptor configuration subset header +typedef struct usb_msos20_desc_subset_header_config +{ + /// The length, in bytes, of this header + uint16_t wLength; + /// The type of this descriptor (use USB_MSOS20_DT_SUBSET_HEADER_CONFIGURATION) + uint16_t wDescriptorType; + /// The configuration value for the USB configuration to which this subset applies + uint8_t bConfigurationValue; + /// Reserved. Set to 0. + uint8_t bReserved; + /// The size of entire configuration subset including this header. + uint16_t wTotalLength; +} __attribute__((packed)) usb_msos20_desc_subset_header_config; + +/// Microsoft OS 2.0 descriptor function subset header +typedef struct usb_msos20_desc_subset_header_function +{ + /// The length, in bytes, of this header + uint16_t wLength; + /// The type of this descriptor (use USB_MSOS20_DT_SUBSET_HEADER_FUNCTION) + uint16_t wDescriptorType; + /// The interface number for the first interface of the function to which this subset applies. + uint8_t bFirstInterface; + /// Reserved. Set to 0. + uint8_t bReserved; + /// The size of entire function subset including this header. + uint16_t wTotalLength; +} __attribute__((packed)) usb_msos20_desc_subset_header_function; + +/// Microsoft OS 2.0 compatible ID descriptor +typedef struct usb_msos20_desc_compatible_id +{ + /// The length, in bytes, of this header + uint16_t wLength; + /// The type of this descriptor (use USB_MSOS20_DT_FEATURE_COMPATBLE_ID) + uint16_t wDescriptorType; + /// Compatible ID string + char compatibleID[8]; + /// Sub-compatible ID string + char subCompatibleID[8]; +} __attribute__((packed)) usb_msos20_desc_compatible_id; + +extern const usb_msos20_platform_desc msos_desc; + +/** + * Register the control request handler to respond to BOS request (for automatic WinUSB installation) + * + * @param device USB device + * @param bos_descs array of BOS descriptors + * @param num_bos_descs number of BOS descriptors + * @param msos_desc_set MS OS 2.0 descriptor set + */ +void usb_dev_register_bos(usbd_device* device, + const usb_bos_device_capability_desc* const * bos_descs, int num_bos_descs, + const usb_msos20_desc_set_header* msos_desc_set, uint8_t msos_vendor_code); + +#ifdef __cplusplus +} +#endif diff --git a/test-devices/composite-stm32/include/usb_bos_desc.h b/test-devices/composite-stm32/include/usb_bos_desc.h new file mode 100644 index 00000000..eacfbf57 --- /dev/null +++ b/test-devices/composite-stm32/include/usb_bos_desc.h @@ -0,0 +1,28 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// USB BOS descriptor +// + +#pragma once + +#include "usb_bos.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSOS_VENDOR_CODE 0x44 + +extern const usb_bos_device_capability_desc* const bos_descs[1]; +extern const usb_msos20_desc_set_header* msos_desc_set; + +#ifdef __cplusplus +} +#endif diff --git a/test-devices/composite-stm32/include/wcid.h b/test-devices/composite-stm32/include/wcid.h deleted file mode 100644 index 2c1041ef..00000000 --- a/test-devices/composite-stm32/include/wcid.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Microsoft WCID descriptors -// - -#pragma once - -#include - -// Register control request handlers for Microsoft WCID descriptors -void register_wcid_desc(usbd_device *usb_dev); diff --git a/test-devices/composite-stm32/src/main.cpp b/test-devices/composite-stm32/src/main.cpp index 9fe392b5..cd6bd424 100644 --- a/test-devices/composite-stm32/src/main.cpp +++ b/test-devices/composite-stm32/src/main.cpp @@ -20,7 +20,7 @@ #include "circ_buf.h" #include "common.h" #include "usb_descriptor.h" -#include "wcid.h" +#include "usb_bos_desc.h" #define USB_CDC_REQ_GET_LINE_CODING 0x21 @@ -78,6 +78,7 @@ static bool is_serial_tx = false; // indicates if the serial RX endpoint is forced to NAK to prevent receiving further data static bool is_serial_rx_nak = false; + void init() { // Enable required clocks rcc_clock_setup_in_hse_8mhz_out_72mhz(); @@ -109,18 +110,20 @@ void usb_init() { // Set callback for config calls usbd_register_set_config_callback(usb_device, on_usb_set_config); - register_wcid_desc(usb_device); + usb_dev_register_bos(usb_device, bos_descs, sizeof(bos_descs) / sizeof(bos_descs[0]), + msos_desc_set, MSOS_VENDOR_CODE); } // Called when the host connects to the device and selects a configuration void on_usb_set_config(usbd_device *usbd_dev, __attribute__((unused)) uint16_t wValue) { - register_wcid_desc(usbd_dev); + usb_dev_register_bos(usb_device, bos_descs, sizeof(bos_descs) / sizeof(bos_descs[0]), + msos_desc_set, MSOS_VENDOR_CODE); // register control request handler for vendor specific requests (used for test) usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, on_vendor_control_request); - // resgier control request handler for class specific requests (used for CDC ACM) + // register control request handler for class specific requests (used for CDC ACM) usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, on_class_control_request); diff --git a/test-devices/composite-stm32/src/usb_bos.cpp b/test-devices/composite-stm32/src/usb_bos.cpp new file mode 100644 index 00000000..020c9da8 --- /dev/null +++ b/test-devices/composite-stm32/src/usb_bos.cpp @@ -0,0 +1,98 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// USB binary device object store (BOS) +// + +#include "usb_bos.h" +#include + +static uint32_t build_descriptor(uint8_t* buf); +static enum usbd_request_return_codes on_bos_control_request( + usbd_device* usbd_dev, struct usb_setup_data* req, + uint8_t** buf, uint16_t* len, usbd_control_complete_callback* complete); + +static inline int imin(int a, int b) { return a < b ? a : b; } +static inline int descriptor_type(uint16_t wValue) { return wValue >> 8; } +static inline int descriptor_index(uint16_t wValue) { return wValue & 0xFF; } + +static const usb_bos_device_capability_desc* const* bos_descs; +static int num_bos_descs; +static const usb_msos20_desc_set_header* msos_desc_set; +static uint8_t msos_vendor_code; + + +void usb_dev_register_bos(usbd_device* device, + const usb_bos_device_capability_desc* const * descs, int num_descs, + const usb_msos20_desc_set_header* msos_set, uint8_t vendor_code) { + + bos_descs = descs; + num_bos_descs = num_descs; + msos_desc_set = msos_set; + msos_vendor_code = vendor_code; + + usbd_register_control_callback(device, USB_REQ_TYPE_IN | USB_REQ_TYPE_DEVICE, + USB_REQ_TYPE_DIRECTION | USB_REQ_TYPE_RECIPIENT, on_bos_control_request); +} + +#define APPEND_TO_DESC(data_ptr, data_len) \ + memcpy(buf_end, data_ptr, data_len); \ + buf_end += data_len; + +uint32_t build_descriptor(uint8_t* buf) { + uint8_t* buf_end = buf; + + usb_bos_desc root_desc = { + .bLength = sizeof(usb_bos_desc), + .bDescriptorType = USB_DT_BOS, + .wTotalLength = 0, + .bNumDeviceCaps = (uint8_t) num_bos_descs + }; + + APPEND_TO_DESC(&root_desc, sizeof(root_desc)) + + for (int i = 0; i < num_bos_descs; i++) { + APPEND_TO_DESC(bos_descs[i], bos_descs[i]->bLength) + } + + uint32_t length = buf_end - buf; + + // use memcpy() as buffer might not be word aligned + memcpy(buf + 2, &length, sizeof(uint16_t)); + + return length; +} + +#undef APPEND_TO_DESC + +enum usbd_request_return_codes on_bos_control_request( + __attribute__((unused)) usbd_device* dev, struct usb_setup_data* req, uint8_t** buf, uint16_t* len, + __attribute__((unused)) usbd_control_complete_callback* complete) { + + if (req->bmRequestType == (USB_REQ_TYPE_IN | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE)) { + + if (req->bRequest == USB_REQ_GET_DESCRIPTOR && descriptor_type(req->wValue) == USB_DT_BOS) { + + // USB BOS descriptor (incl. Microsoft OS 2.0 platform capability descriptor) + if (descriptor_index(req->wValue) != 0) + return USBD_REQ_NOTSUPP; + *len = imin(*len, build_descriptor(*buf)); + return USBD_REQ_HANDLED; + } + + } else if (req->bmRequestType == (USB_REQ_TYPE_IN | USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE)) { + // Microsoft OS 2.0 descriptor + if (req->bRequest == msos_vendor_code && req->wValue == 0 && req->wIndex == USB_MSOS20_CTRL_INDEX_DESC) { + memcpy(*buf, msos_desc_set, msos_desc.wMSOSDescriptorSetTotalLength); + *len = imin(*len, msos_desc.wMSOSDescriptorSetTotalLength); + return USBD_REQ_HANDLED; + } + } + + return USBD_REQ_NEXT_CALLBACK; +} diff --git a/test-devices/composite-stm32/src/usb_bos_desc.c b/test-devices/composite-stm32/src/usb_bos_desc.c new file mode 100644 index 00000000..eeb6039d --- /dev/null +++ b/test-devices/composite-stm32/src/usb_bos_desc.c @@ -0,0 +1,89 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// USB BOS descriptor to install WinUSB for loopback test interface +// + +#include "usb_bos_desc.h" + +#define DEV_INTF_GUID_NAME u"DeviceInterfaceGUIDs" +#define DEV_INTF_GUID_DATA u"{049CD59E-33EE-4CB2-B0BB-1C49F3CB6358}" + +const struct msos20_desc_set { + usb_msos20_desc_set_header descSetHeader; + usb_msos20_desc_subset_header_config descSubsetConfig; + usb_msos20_desc_subset_header_function descSubsetFunction; + usb_msos20_desc_compatible_id descCompId; + struct { + uint16_t wLength; + uint16_t wDescriptorType; + uint16_t wPropertyDataType; + uint16_t wPropertyNameLength; + uint16_t propertyName[sizeof(DEV_INTF_GUID_NAME) / 2]; + uint16_t wPropertyDataLength; + uint16_t propertyData[sizeof(DEV_INTF_GUID_DATA) / 2 + 1]; + } devIntfGuid; + +} msos_set = { + + .descSetHeader = { + .wLength = sizeof(usb_msos20_desc_set_header), + .wDescriptorType = USB_MSOS20_DT_SET_HEADER_DESCRIPTOR, + .dwWindowsVersion = USB_MSOS20_WIN_VER_8_1, + .wTotalLength = sizeof(msos_set) + }, + .descSubsetConfig = { + .wLength = sizeof(usb_msos20_desc_subset_header_config), + .wDescriptorType = USB_MSOS20_DT_SUBSET_HEADER_CONFIGURATION, + .bConfigurationValue = 0, + .wTotalLength = sizeof(msos_set.descSubsetConfig) + sizeof(msos_set.descSubsetFunction) + + sizeof(msos_set.descCompId) + sizeof(msos_set.devIntfGuid), + }, + .descSubsetFunction = { + .wLength = sizeof(usb_msos20_desc_subset_header_function), + .wDescriptorType = USB_MSOS20_DT_SUBSET_HEADER_FUNCTION, + .bFirstInterface = 2, + .wTotalLength = sizeof(msos_set.descSubsetFunction) + sizeof(msos_set.descCompId) + + sizeof(msos_set.devIntfGuid), + }, + .descCompId = { + .wLength = sizeof(usb_msos20_desc_compatible_id), + .wDescriptorType = USB_MSOS20_DT_FEATURE_COMPATBLE_ID, + .compatibleID = "WINUSB\0\0", + .subCompatibleID = "\0\0\0\0\0\0\0\0" + }, + .devIntfGuid = { + .wLength = sizeof(msos_set.devIntfGuid), + .wDescriptorType = USB_MSOS20_DT_FEATURE_REG_PROPERTY, + .wPropertyDataType = USB_MSOS20_PROP_DATA_TYPE_STRING_MULTI, + .wPropertyNameLength = sizeof(msos_set.devIntfGuid.propertyName), + .propertyName = DEV_INTF_GUID_NAME, + .wPropertyDataLength = sizeof(msos_set.devIntfGuid.propertyData), + .propertyData = DEV_INTF_GUID_DATA "\0" + } +}; + +const usb_msos20_desc_set_header* msos_desc_set = &msos_set.descSetHeader; + +const usb_msos20_platform_desc msos_desc = { + .bLength = sizeof(usb_msos20_platform_desc), + .bDescriptorType = USB_DT_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_DEV_CAPA_PLATFORM, + .bReserved = 0, + .platformCapabilityUUID = USB_PLATFORM_CAPABILITY_MICROSOFT_OS20_UUID, + .dwWindowsVersion = USB_MSOS20_WIN_VER_8_1, + .wMSOSDescriptorSetTotalLength = sizeof(msos_set), + .bMS_VendorCode = MSOS_VENDOR_CODE, + .bAltEnumCode = 0 +}; + +// BOS device capability descriptors +const usb_bos_device_capability_desc* const bos_descs[] = { + // Microsoft OS 2.0 descriptor (for autmatic WinUSB installation) + (const usb_bos_device_capability_desc*)&msos_desc +}; diff --git a/test-devices/composite-stm32/src/usb_descriptor.cpp b/test-devices/composite-stm32/src/usb_descriptor.cpp index 6c155c33..05827bf5 100644 --- a/test-devices/composite-stm32/src/usb_descriptor.cpp +++ b/test-devices/composite-stm32/src/usb_descriptor.cpp @@ -20,7 +20,7 @@ static void put_hex(uint32_t value, char *buf, int len); #define USB_VID 0xcafe // Vendor ID #define USB_PID 0xcea0 // Product ID -#define USB_DEVICE_REL 0x0032 // release 0.3.2 +#define USB_DEVICE_REL 0x0034 // release 0.3.3 // Interface index #define INTF_CDC_COMM 0 @@ -53,104 +53,110 @@ typedef struct { // --- CDC ACM --- // CDC communicatoin endpoint -static const usb_endpoint_descriptor cdc_comm_ep_desc[] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_CDC_COMM, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = INTR_MAX_PACKET_SIZE, - .bInterval = 32, - .extra = nullptr, - .extralen = 0, -}}; +static const usb_endpoint_descriptor cdc_comm_ep_desc[] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = EP_CDC_COMM, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = INTR_MAX_PACKET_SIZE, + .bInterval = 32, + .extra = nullptr, + .extralen = 0, + } +}; // CDC data endpoints -static const usb_endpoint_descriptor cdc_data_ep_desc[] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_CDC_DATA_RX, - .bmAttributes = USB_ENDPOINT_ATTR_BULK, - .wMaxPacketSize = BULK_MAX_PACKET_SIZE, - .bInterval = 1, - .extra = nullptr, - .extralen = 0, - }, - { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_CDC_DATA_TX, - .bmAttributes = USB_ENDPOINT_ATTR_BULK, - .wMaxPacketSize = BULK_MAX_PACKET_SIZE, - .bInterval = 1, - .extra = nullptr, - .extralen = 0, - }}; +static const usb_endpoint_descriptor cdc_data_ep_desc[] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = EP_CDC_DATA_RX, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = BULK_MAX_PACKET_SIZE, + .bInterval = 1, + .extra = nullptr, + .extralen = 0, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = EP_CDC_DATA_TX, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = BULK_MAX_PACKET_SIZE, + .bInterval = 1, + .extra = nullptr, + .extralen = 0, + } +}; // CDC ACM function descriptor static const cdcacm_functional_descriptors cdc_func_desc = { - .header = - { - .bFunctionLength = sizeof(usb_cdc_header_descriptor), - .bDescriptorType = CS_INTERFACE, - .bDescriptorSubtype = USB_CDC_TYPE_HEADER, - .bcdCDC = 0x0110, - }, - .call_mgmt = - { - // see chapter 5.3.1 in PSTN120 - .bFunctionLength = sizeof(usb_cdc_call_management_descriptor), - .bDescriptorType = CS_INTERFACE, - .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, - .bmCapabilities = 0, // no call management - .bDataInterface = INTF_CDC_DATA, - }, - .acm = - { - // see chapter 5.3.2 in PSTN120 - .bFunctionLength = sizeof(usb_cdc_acm_descriptor), - .bDescriptorType = CS_INTERFACE, - .bDescriptorSubtype = USB_CDC_TYPE_ACM, - .bmCapabilities = 2, // device supports the request combination of Set_Line_Coding, Set_Control_Line_State, - // Get_Line_Coding, and the notification Serial_State - }, + .header = { + .bFunctionLength = sizeof(usb_cdc_header_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_HEADER, + .bcdCDC = 0x0110, + }, + .call_mgmt = { + // see chapter 5.3.1 in PSTN120 + .bFunctionLength = sizeof(usb_cdc_call_management_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, + .bmCapabilities = 0, // no call management + .bDataInterface = INTF_CDC_DATA, + }, + .acm = { + // see chapter 5.3.2 in PSTN120 + .bFunctionLength = sizeof(usb_cdc_acm_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_ACM, + .bmCapabilities = 2, // device supports the request combination of Set_Line_Coding, Set_Control_Line_State, + // Get_Line_Coding, and the notification Serial_State + }, .cdc_union = { .bFunctionLength = sizeof(usb_cdc_union_descriptor), .bDescriptorType = CS_INTERFACE, .bDescriptorSubtype = USB_CDC_TYPE_UNION, .bControlInterface = INTF_CDC_COMM, .bSubordinateInterface0 = INTF_CDC_DATA, - }}; + } +}; // CDC interfaces descriptors -static const usb_interface_descriptor cdc_comm_if_desc[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = INTF_CDC_COMM, - .bAlternateSetting = 0, - .bNumEndpoints = ARRAY_SIZE(cdc_comm_ep_desc), - .bInterfaceClass = USB_CLASS_CDC, - .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, - .bInterfaceProtocol = USB_CDC_PROTOCOL_AT, - .iInterface = 0, - .endpoint = cdc_comm_ep_desc, - .extra = &cdc_func_desc, - .extralen = sizeof(cdc_func_desc), -}}; +static const usb_interface_descriptor cdc_comm_if_desc[] = { + { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = INTF_CDC_COMM, + .bAlternateSetting = 0, + .bNumEndpoints = ARRAY_SIZE(cdc_comm_ep_desc), + .bInterfaceClass = USB_CLASS_CDC, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_PROTOCOL_AT, + .iInterface = 0, + .endpoint = cdc_comm_ep_desc, + .extra = &cdc_func_desc, + .extralen = sizeof(cdc_func_desc), + } +}; -static const usb_interface_descriptor cdc_data_if_desc[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = INTF_CDC_DATA, - .bAlternateSetting = 0, - .bNumEndpoints = ARRAY_SIZE(cdc_data_ep_desc), - .bInterfaceClass = USB_CLASS_DATA, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = 0, - .endpoint = cdc_data_ep_desc, - .extra = nullptr, - .extralen = 0, -}}; +static const usb_interface_descriptor cdc_data_if_desc[] = { + { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = INTF_CDC_DATA, + .bAlternateSetting = 0, + .bNumEndpoints = ARRAY_SIZE(cdc_data_ep_desc), + .bInterfaceClass = USB_CLASS_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + .endpoint = cdc_data_ep_desc, + .extra = nullptr, + .extralen = 0, + } +}; // CDC interface association static const usb_iface_assoc_descriptor cdc_assoc_desc = { @@ -266,10 +272,10 @@ const struct usb_config_descriptor usb_config_descs[] = { const struct usb_device_descriptor usb_device_desc = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0200, // USB version 2.00 - .bDeviceClass = 0, // defined by interfaces - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, + .bcdUSB = 0x0210, // USB version 2.1.0 (minimum version for BOS) + .bDeviceClass = 0xef, + .bDeviceSubClass = 0x02, + .bDeviceProtocol = 0x01, .bMaxPacketSize0 = 64, .idVendor = USB_VID, .idProduct = USB_PID, diff --git a/test-devices/composite-stm32/src/wcid.cpp b/test-devices/composite-stm32/src/wcid.cpp deleted file mode 100644 index 2c284f36..00000000 --- a/test-devices/composite-stm32/src/wcid.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Microsoft WCID descriptors -// - -#include - -#include - -static usbd_request_return_codes msft_string_desc(usbd_device *usbd_dev, usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete); -static usbd_request_return_codes msft_feature_desc(usbd_device *usbd_dev, usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete); - -// Registers additional control request handlers to implement -// See https://github.com/pbatard/libwdi/wiki/WCID-Devices -void register_wcid_desc(usbd_device *usb_dev) { - usbd_register_control_callback(usb_dev, - USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - msft_string_desc); - usbd_register_control_callback(usb_dev, - USB_REQ_TYPE_VENDOR, USB_REQ_TYPE_TYPE, - msft_feature_desc); -} - -#define WCID_VENDOR_CODE 0x37 - -// Microsoft WCID string descriptor (string index 0xee) -static const uint8_t msft_sig_desc[] = { - 0x12, // length = 18 bytes - USB_DT_STRING, // descriptor type string - 'M', 0, 'S', 0, 'F', 0, 'T', 0, // 'M', 'S', 'F', 'T' - '1', 0, '0', 0, '0', 0, // '1', '0', '0' - WCID_VENDOR_CODE, // vendor code - 0 // padding -}; - -// Microsoft WCID feature descriptor (index 0x0004) -static const uint8_t wcid_feature_desc[] = { - 0x28, 0x00, 0x00, 0x00, // length = 40 bytes - 0x00, 0x01, // version 1.0 (in BCD) - 0x04, 0x00, // compatibility descriptor index 0x0004 - 0x01, // number of sections - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved (7 bytes) - 0x00, // interface number 0 - 0x01, // reserved - 0x57, 0x49, 0x4E, 0x55, 0x53, 0x42, 0x00, 0x00, // Compatible ID "WINUSB\0\0" - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Subcompatible ID (unused) - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // reserved 6 bytes -}; - -usbd_request_return_codes msft_string_desc(__attribute__((unused)) usbd_device *usbd_dev, usb_setup_data *req, - uint8_t **buf, uint16_t *len, - __attribute__((unused)) usbd_control_complete_callback *complete) { - // 0x03: descriptor type string - // 0xee: Microsoft WCID string index - if (req->bRequest == USB_REQ_GET_DESCRIPTOR && req->wValue == 0x03ee) { - *buf = const_cast(reinterpret_cast(&msft_sig_desc)); - *len = std::min(*len, (uint16_t)msft_sig_desc[0]); - return USBD_REQ_HANDLED; - } - - return USBD_REQ_NEXT_CALLBACK; -} - -usbd_request_return_codes msft_feature_desc(__attribute__((unused)) usbd_device *usbd_dev, usb_setup_data *req, - uint8_t **buf, uint16_t *len, - __attribute__((unused)) usbd_control_complete_callback *complete) { - // 0x0004: Microsoft WCID index for feature descriptor - if (req->bRequest == WCID_VENDOR_CODE && req->wIndex == 0x0004) { - *buf = const_cast(reinterpret_cast(&wcid_feature_desc)); - *len = std::min(*len, (uint16_t)wcid_feature_desc[0]); - return USBD_REQ_HANDLED; - } - - return USBD_REQ_NEXT_CALLBACK; -} From 469d2a724f3cb3a3ecbd055a02d6e52ab50b8d63 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 12 Sep 2022 22:28:44 +0200 Subject: [PATCH 082/433] Windows: composite devices --- java-does-usb/jextract/windows/gen_win.cmd | 37 +++ .../codecrete/usb/common/USBDeviceImpl.java | 60 ++++- .../usb/windows/CompositeFunction.java | 81 +++++++ .../codecrete/usb/windows/DeviceProperty.java | 109 +++++++-- .../java/net/codecrete/usb/windows/Win.java | 23 ++ .../usb/windows/WindowsUSBDevice.java | 171 +++++++++----- .../usb/windows/WindowsUSBDeviceRegistry.java | 122 +++++++++- .../usb/windows/WindowsUSBException.java | 43 ++++ .../usb/windows/gen/advapi32/Advapi32.java | 50 ++++ .../windows/gen/advapi32/Constants$root.java | 19 ++ .../windows/gen/advapi32/RuntimeHelper.java | 216 ++++++++++++++++++ .../usb/windows/gen/advapi32/constants$0.java | 30 +++ .../usb/windows/gen/kernel32/Kernel32.java | 37 +++ .../usb/windows/gen/kernel32/constants$0.java | 7 + .../usb/windows/gen/kernel32/constants$1.java | 24 ++ .../usb/windows/gen/ole32/Constants$root.java | 19 ++ .../usb/windows/gen/ole32/Ole32.java | 33 +++ .../usb/windows/gen/ole32/RuntimeHelper.java | 216 ++++++++++++++++++ .../usb/windows/gen/ole32/constants$0.java | 19 ++ .../usb/windows/gen/setupapi/SetupAPI.java | 46 +++- .../usb/windows/gen/setupapi/constants$0.java | 41 ++-- .../usb/windows/gen/setupapi/constants$1.java | 34 +++ .../usb/windows/gen/winusb/WinUSB.java | 13 +- .../usb/windows/gen/winusb/constants$0.java | 28 +-- .../usb/windows/gen/winusb/constants$1.java | 30 +++ .../codecrete/usb/ControlTransferTest.java | 14 +- .../net/codecrete/usb/DescriptionTest.java | 6 +- .../codecrete/usb/InvalidOperationTest.java | 2 +- .../net/codecrete/usb/TestDeviceBase.java | 4 +- test-devices/composite-stm32/README.md | 10 +- test-devices/composite-stm32/src/main.cpp | 6 +- 31 files changed, 1393 insertions(+), 157 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/CompositeFunction.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index 837f34b1..d0b57daa 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -13,9 +13,13 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-function DeviceIoControl ^ --include-function GetLastError ^ --include-function GetModuleHandleW ^ + --include-function FormatMessageW ^ + --include-function LocalFree ^ --include-macro ERROR_SUCCESS ^ --include-macro ERROR_NO_MORE_ITEMS ^ + --include-macro ERROR_MORE_DATA ^ --include-macro ERROR_INSUFFICIENT_BUFFER ^ + --include-macro ERROR_FILE_NOT_FOUND ^ --include-macro GENERIC_READ ^ --include-macro GENERIC_WRITE ^ --include-macro FILE_SHARE_READ ^ @@ -23,6 +27,9 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-macro FILE_ATTRIBUTE_NORMAL ^ --include-macro FILE_FLAG_OVERLAPPED ^ --include-macro OPEN_EXISTING ^ + --include-macro FORMAT_MESSAGE_ALLOCATE_BUFFER ^ + --include-macro FORMAT_MESSAGE_FROM_SYSTEM ^ + --include-macro FORMAT_MESSAGE_IGNORE_INSERTS ^ --include-struct _GUID ^ --include-typedef GUID ^ windows_headers.h @@ -42,6 +49,9 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-function SetupDiGetDeviceRegistryPropertyW ^ --include-function SetupDiGetDevicePropertyW ^ --include-function SetupDiOpenDeviceInterfaceW ^ + --include-function SetupDiCreateDeviceInfoList ^ + --include-function SetupDiOpenDeviceInfoW ^ + --include-function SetupDiOpenDevRegKey ^ --include-struct _SP_DEVINFO_DATA ^ --include-typedef SP_DEVINFO_DATA ^ --include-struct _SP_DEVICE_INTERFACE_DATA ^ @@ -53,6 +63,9 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-macro SPDRP_ADDRESS ^ --include-macro DEVPROP_TYPE_UINT32 ^ --include-macro DEVPROP_TYPE_STRING ^ + --include-macro DEVPROP_TYPEMOD_LIST ^ + --include-macro DICS_FLAG_GLOBAL ^ + --include-macro DIREG_DEV ^ windows_headers.h call %JEXTRACT% --source --output ../../src/main/java ^ @@ -113,4 +126,28 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-function WinUsb_ControlTransfer ^ --include-function WinUsb_WritePipe ^ --include-function WinUsb_ReadPipe ^ + --include-function WinUsb_GetAssociatedInterface ^ + windows_headers.h + +call %JEXTRACT% --source --output ../../src/main/java ^ + -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ + -I "%SDK_DIR%\um" ^ + -I "%SDK_DIR%\shared" ^ + -l Advapi32 ^ + --header-class-name Advapi32 ^ + --target-package net.codecrete.usb.windows.gen.advapi32 ^ + --include-function RegQueryValueExW ^ + --include-function RegCloseKey ^ + --include-macro REG_MULTI_SZ ^ + --include-macro KEY_READ ^ + windows_headers.h + +call %JEXTRACT% --source --output ../../src/main/java ^ + -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ + -I "%SDK_DIR%\um" ^ + -I "%SDK_DIR%\shared" ^ + -l Ole32 ^ + --header-class-name Ole32 ^ + --target-package net.codecrete.usb.windows.gen.ole32 ^ + --include-function CLSIDFromString ^ windows_headers.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 6c32f7e6..86240667 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -153,6 +153,8 @@ protected USBInterfaceImpl getInterface(int interfaceNumber) { * * @param endpointNumber endpoint number (1 to 127) * @param direction transfer direction + * @param transferType1 transfer type 1 + * @param transferType2 transfer type 2 (or {@code null}) * @return endpoint address */ protected byte getEndpointAddress(int endpointNumber, USBDirection direction, @@ -172,16 +174,69 @@ protected byte getEndpointAddress(int endpointNumber, USBDirection direction, } } + throwInvalidEndpointException(endpointNumber, direction, transferType1, transferType2); + return 0; // will never be reached + } + + /** + * Checks if the specified endpoint is valid for communication and returns the endpoint. + * + * @param endpointNumber endpoint number (1 to 127) + * @param direction transfer direction + * @param transferType1 transfer type 1 + * @param transferType2 transfer type 2 (or {@code null}) + * @return endpoint + */ + protected EndpointInfo getEndpoint(int endpointNumber, USBDirection direction, + USBTransferType transferType1, USBTransferType transferType2) { + + checkIsOpen(); + + if (endpointNumber >= 1 && endpointNumber <= 127) { + for (var intf : interfaces_) { + if (intf.isClaimed()) { + for (var ep : intf.alternate().endpoints()) { + if (ep.number() == endpointNumber && ep.direction() == direction + && (ep.transferType() == transferType1 || ep.transferType() == transferType2)) + return new EndpointInfo(intf.number(), ep.number(), + (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0))); + } + } + } + } + + throwInvalidEndpointException(endpointNumber, direction, transferType1, transferType2); + return null; // will never be reached + } + + protected void throwInvalidEndpointException(int endpointNumber, USBDirection direction, + USBTransferType transferType1, USBTransferType transferType2) { String transferTypeDesc; if (transferType2 == null) transferTypeDesc = transferType1.name(); else transferTypeDesc = String.format("%s or %s", transferType1.name(), transferType2.name()); throw new USBException(String.format("Endpoint number %d does not exist, is not part of a claimed interface " + - "or is not valid for %s transfer in %s direction", endpointNumber, transferTypeDesc, + "or is not valid for %s transfer in %s direction", endpointNumber, transferTypeDesc, direction.name())); } + protected int getInterfaceNumber(int endpointNumber) { + if (endpointNumber < 1 || endpointNumber > 127) + return -1; + + for (var intf : interfaces_) { + if (intf.isClaimed()) { + for (var ep : intf.alternate().endpoints()) { + if (ep.number() == endpointNumber) + return intf.number(); + } + } + } + + return -1; + } + @Override public abstract byte[] controlTransferIn(USBControlTransfer setup, int length); @@ -214,4 +269,7 @@ public int hashCode() { public String toString() { return "VID: 0x" + String.format("%04x", vendorId_) + ", PID: 0x" + String.format("%04x", productId_) + ", " + "manufacturer: " + manufacturer_ + ", product: " + product_ + ", serial: " + serialNumber_ + ", ID: " + id_; } + + public record EndpointInfo(int interfaceNumber, int endpointNumber, byte endpointAddress) { + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/CompositeFunction.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/CompositeFunction.java new file mode 100644 index 00000000..acf7326c --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/CompositeFunction.java @@ -0,0 +1,81 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.windows; + +import java.lang.foreign.MemoryAddress; + +/** + * Describes the function of an interface of a composite USB device. + *

+ * A composite USB device can have multiple functions, e.g. a mass + * storage function and a virtual serial port function. Each function + * will appear as a separate device in Window. + *

+ *

+ * A function consists of one or more interfaces. Functions with + * multiple interfaces must have consecutive interface numbers. The + * interfaces after the first one are called associated interfaces. + *

+ *

+ * On Windows, each function has a separate device path. Each device + * path must be opened and each interface must be opened. + * Furthermore, the first and the associated interfaces are + * treated differently. + *

+ */ +public class CompositeFunction { + // TODO: implement associated interfaces + + // TODO: implement devices without interfaces + + private final int firstInterfaceNumber_; + private final int numInterfaces_; + private final String devicePath_; + private MemoryAddress deviceHandle_; + private MemoryAddress firstInterfaceHandle_; + + /** + * Creates a new instance with a single interface. + * + * @param interfaceNumber the interface number + * @param devicePath the device path + */ + public CompositeFunction(int interfaceNumber, String devicePath) { + firstInterfaceNumber_ = interfaceNumber; + numInterfaces_ = 1; + devicePath_ = devicePath; + } + + public int firstInterfaceNumber() { + return firstInterfaceNumber_; + } + + public int numInterfaces() { + return numInterfaces_; + } + + public String devicePath() { + return devicePath_; + } + + public MemoryAddress deviceHandle() { + return deviceHandle_; + } + + public void setDeviceHandle(MemoryAddress deviceHandle) { + deviceHandle_ = deviceHandle; + } + + public MemoryAddress firstInterfaceHandle() { + return firstInterfaceHandle_; + } + + public void setFirstInterfaceHandle(MemoryAddress firstInterfaceHandle) { + firstInterfaceHandle_ = firstInterfaceHandle; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index 5490bb20..a57aa7b3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -8,6 +8,7 @@ package net.codecrete.usb.windows; import net.codecrete.usb.USBException; +import net.codecrete.usb.windows.gen.advapi32.Advapi32; import net.codecrete.usb.windows.gen.kernel32.GUID; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.setupapi.SP_DEVICE_INTERFACE_DATA; @@ -15,8 +16,10 @@ import net.codecrete.usb.windows.gen.setupapi.SetupAPI; import java.lang.foreign.Addressable; +import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; +import java.util.List; import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.JAVA_CHAR; @@ -39,16 +42,28 @@ public class DeviceProperty { (short) 0x4706, (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, (byte) 0x80, (byte) 0x08, (byte) 0xa5 , (byte) 0xa7, 8); + public static final MemorySegment DEVPKEY_Device_Service = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, + (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50, + (byte) 0xe0, 6); + + public static final MemorySegment DEVPKEY_Device_Children = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, + (short) 0x4706, (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, (byte) 0x80, (byte) 0x08, (byte) 0xa5, + (byte) 0xa7, 9); + + public static final MemorySegment DEVPKEY_Device_HardwareIds = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, + (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50, + (byte) 0xe0, 3); + public static int getDeviceIntProperty(Addressable devInfo, Addressable devInfoData, Addressable propertyKey) { try (var session = MemorySession.openConfined()) { var propertyTypeHolder = session.allocate(JAVA_INT); var propertyValueHolder = session.allocate(JAVA_INT); if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0) == 0) - throw new USBException("Internal error (SetupDiGetDevicePropertyW)", Kernel32.GetLastError()); + throw new WindowsUSBException("Internal error (SetupDiGetDevicePropertyW)", Kernel32.GetLastError()); if (propertyTypeHolder.get(JAVA_INT, 0) != SetupAPI.DEVPROP_TYPE_UINT32()) - throw new USBException("Internal error (expected property typ UINT32)"); + throw new USBException("Internal error (expected property type UINT32)"); return propertyValueHolder.get(JAVA_INT, 0); } @@ -57,31 +72,77 @@ public static int getDeviceIntProperty(Addressable devInfo, Addressable devInfoD public static String getDeviceStringProperty(Addressable devInfo, Addressable devInfoData, Addressable propertyKey) { try (var session = MemorySession.openConfined()) { - var propertyTypeHolder = session.allocate(JAVA_INT); - var requiredSizeHolder = session.allocate(JAVA_INT); - if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, NULL, 0, - requiredSizeHolder, 0) == 0) { - // TODO: Reactivate when proper GetLastError() handling is available - // int err = Kernel32.GetLastError(); - // if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) - // throw new USBException("Internal error (SetupDiGetDevicePropertyW)", Kernel32 - // .GetLastError()); - } - - if (propertyTypeHolder.get(JAVA_INT, 0) != SetupAPI.DEVPROP_TYPE_STRING()) - throw new USBException("Internal error (expected property typ UINT32)"); - - int stringLen = requiredSizeHolder.get(JAVA_INT, 0) / 2 - 1; - - var propertyValueHolder = session.allocateArray(JAVA_CHAR, stringLen + 1); - if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, - propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0) == 0) - throw new USBException("Internal error (SetupDiGetDevicePropertyW)", Kernel32.GetLastError()); + var propertyValue = getProperty(devInfo, devInfoData, propertyKey, + SetupAPI.DEVPROP_TYPE_STRING(), session); + return Win.createStringFromSegment(propertyValue); + } + } + + public static List getDeviceStringListProperty(Addressable devInfo, Addressable devInfoData, + Addressable propertyKey) { + try (var session = MemorySession.openConfined()) { + var propertyValue = getProperty(devInfo, devInfoData, propertyKey, + SetupAPI.DEVPROP_TYPE_STRING() | SetupAPI.DEVPROP_TYPEMOD_LIST(), session); - return Win.createStringFromSegment(propertyValueHolder); + return Win.createStringListFromSegment(propertyValue); } } + private static MemorySegment getProperty(Addressable devInfo, Addressable devInfoData, Addressable propertyKey, + int propertyType, MemorySession session) { + var propertyTypeHolder = session.allocate(JAVA_INT); + var requiredSizeHolder = session.allocate(JAVA_INT); + if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, NULL, 0, + requiredSizeHolder, 0) == 0) { + // TODO: Reactivate when proper GetLastError() handling is available + // int err = Kernel32.GetLastError(); + // if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) + // throw new WindowsUSBException("Internal error (SetupDiGetDevicePropertyW)", Kernel32 + // .GetLastError()); + } + + if (propertyTypeHolder.get(JAVA_INT, 0) != propertyType) + throw new USBException("Internal error (unexpected property type)"); + + int stringLen = requiredSizeHolder.get(JAVA_INT, 0) / 2 - 1; + + var propertyValueHolder = session.allocateArray(JAVA_CHAR, stringLen + 1); + if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, + propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0) == 0) + throw new WindowsUSBException("Internal error (SetupDiGetDevicePropertyW)", Kernel32.GetLastError()); + + return propertyValueHolder; + } + + public static List findDeviceInterfaceGUIDs(MemoryAddress devInfoSetHandle, MemorySegment devInfo, MemorySession session) { + + // open device registry key + var regKey = SetupAPI.SetupDiOpenDevRegKey(devInfoSetHandle, devInfo, SetupAPI.DICS_FLAG_GLOBAL(), + 0, SetupAPI.DIREG_DEV(), Advapi32.KEY_READ()); + if (Win.IsInvalidHandle(regKey)) + throw new WindowsUSBException("Cannot open device registry key", Kernel32.GetLastError()); + session.addCloseAction(() -> Advapi32.RegCloseKey(regKey)); + + // read registry value (without buffer, to query length) + var keyNameSegment = Win.createSegmentFromString("DeviceInterfaceGUIDs", session); + var valueTypeHolder = session.allocate(JAVA_INT); + var valueSizeHolder = session.allocate(JAVA_INT); + var res = Advapi32.RegQueryValueExW(regKey, keyNameSegment, NULL, valueTypeHolder, NULL, valueSizeHolder); + if (res == Kernel32.ERROR_FILE_NOT_FOUND()) + return List.of(); // no device interface GUIDs + if (res != 0 && res != Kernel32.ERROR_MORE_DATA()) + throw new WindowsUSBException("Internal error (RegQueryValueExW)", res); + + // read registry value (with buffer) + var valueSize = valueSizeHolder.get(JAVA_INT, 0); + var value = session.allocate(valueSize); + res = Advapi32.RegQueryValueExW(regKey, keyNameSegment, NULL, valueTypeHolder, value, valueSizeHolder); + if (res != 0) + throw new WindowsUSBException("Internal error (RegQueryValueExW)", res); + + return Win.createStringListFromSegment(value); + } + public static String getDevicePath(String instanceID, Addressable interfaceGuid) { try (var session = MemorySession.openConfined()) { // get device info set for instance @@ -110,7 +171,7 @@ public static String getDevicePath(String instanceID, Addressable interfaceGuid) int intfDetailDataSize = (int) intfDetailData.byteSize(); if (SetupAPI.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, intfDetailData, intfDetailDataSize, NULL, NULL) == 0) - throw new USBException("Internal error (SetupDiGetDeviceInterfaceDetailW)", Kernel32.GetLastError()); + throw new WindowsUSBException("Internal error (SetupDiGetDeviceInterfaceDetailW)", Kernel32.GetLastError()); return Win.createStringFromSegment(intfDetailData.asSlice(devicePathOffset)); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index 72ad9c4e..ac2e51a0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -14,6 +14,8 @@ import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; import java.lang.foreign.ValueLayout; +import java.util.ArrayList; +import java.util.List; import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_CHAR; @@ -65,6 +67,27 @@ public static String createStringFromSegment(MemorySegment segment) { return new String(segment.asSlice(0, 2L * strLen).toArray(JAVA_CHAR)); } + /** + * Creates a copy of the string list in the memory segment. + *

+ * The string list a a series of null-terminated UTF-16 (wide character) strings. + * The list is terminated with yet another null character. + *

+ * + * @param segment the memory segment + * @return copied string list + */ + public static List createStringListFromSegment(MemorySegment segment) { + var stringList = new ArrayList(); + int offset = 0; + while (segment.get(JAVA_CHAR, offset) != '\0') { + var str = Win.createStringFromSegment(segment.asSlice(offset)); + offset += str.length() * 2 + 2; + stringList.add(str); + } + return stringList; + } + /** * Creates a GUID in native memory. * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index ce74e54e..8f201719 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -7,20 +7,16 @@ package net.codecrete.usb.windows; -import net.codecrete.usb.USBControlTransfer; -import net.codecrete.usb.USBDirection; -import net.codecrete.usb.USBException; -import net.codecrete.usb.USBTransferType; +import net.codecrete.usb.*; import net.codecrete.usb.common.DescriptorParser; import net.codecrete.usb.common.USBDeviceImpl; -import net.codecrete.usb.common.USBInterfaceImpl; import net.codecrete.usb.common.USBStructs; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.winusb.WinUSB; -import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; +import java.util.List; import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.*; @@ -30,52 +26,27 @@ */ public class WindowsUSBDevice extends USBDeviceImpl { - private MemoryAddress device; - private MemoryAddress firstInterface; + private final List functions; + private boolean isOpen_; - WindowsUSBDevice(Object id, int vendorId, int productId, String manufacturer, String product, String serial, + WindowsUSBDevice(String devicePath, List functions, int vendorId, int productId, String manufacturer, String product, String serial, MemorySegment configDesc) { - super(id, vendorId, productId, manufacturer, product, serial); + super(devicePath, vendorId, productId, manufacturer, product, serial); + this.functions = functions; readDescription(configDesc); } @Override public boolean isOpen() { - return device != null; + return isOpen_; } @Override public void open() { - if (isOpen()) throw new USBException("the device is already open"); - try (var session = MemorySession.openConfined()) { - - // open Windows device - var pathSegment = Win.createSegmentFromString(id_.toString(), session); - device = Kernel32.CreateFileW(pathSegment, Kernel32.GENERIC_WRITE() | Kernel32.GENERIC_READ(), - Kernel32.FILE_SHARE_WRITE() | Kernel32.FILE_SHARE_READ(), NULL, Kernel32.OPEN_EXISTING(), - Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), NULL); - - if (Win.IsInvalidHandle(device)) - throw new USBException("Cannot open USB device", Kernel32.GetLastError()); - - try { - // open first USB interface - var interfaceHandleHolder = session.allocate(ADDRESS); - if (WinUSB.WinUsb_Initialize(device, interfaceHandleHolder) == 0) - throw new USBException("Cannot open USB device", Kernel32.GetLastError()); - - firstInterface = interfaceHandleHolder.get(ADDRESS, 0); - - } catch (Throwable e) { - Kernel32.CloseHandle(device); - firstInterface = null; - device = null; - throw e; - } - } + isOpen_ = true; } private void readDescription(MemorySegment configDesc) { @@ -88,13 +59,54 @@ public void close() { if (!isOpen()) return; - for (var intf : interfaces_) - ((USBInterfaceImpl) intf).setClaimed(false); + for (var intf : interfaces_) { + if (intf.isClaimed()) + releaseInterface(intf.number()); + } + + isOpen_ = false; + } + + private CompositeFunction findFunction(int interfaceNumber) { + return functions.stream() + .filter((func) -> func.firstInterfaceNumber() == interfaceNumber).findFirst().orElse(null); + } - WinUSB.WinUsb_Free(firstInterface); - firstInterface = null; - Kernel32.CloseHandle(device); - device = null; + private CompositeFunction findAnyOpenFunction() { + return functions.stream() + .filter((func) -> func.firstInterfaceHandle() != null).findFirst().orElse(null); + } + + private CompositeFunction findControlTransferFunction(USBControlTransfer setup) { + + int interfaceNumber = -1; + int endpointNumber = -1; + + if (setup.recipient() == USBRecipient.INTERFACE) { + + interfaceNumber = setup.index() & 0xff; + + } else if (setup.recipient() == USBRecipient.ENDPOINT) { + + endpointNumber = setup.index() & 0xff; + if (endpointNumber != 0) { + interfaceNumber = getInterfaceNumber(endpointNumber); + if (interfaceNumber == -1) + interfaceNumber = -2; + } + } + + CompositeFunction function = null; + if (interfaceNumber >= 0) { + function = findFunction(interfaceNumber); + } else if (interfaceNumber == -1) { + function = findAnyOpenFunction(); + } + + if (function == null || function.firstInterfaceHandle() == null) + throw new USBException("Interface not claimed for control transfer"); + + return function; } public void claimInterface(int interfaceNumber) { @@ -105,6 +117,37 @@ public void claimInterface(int interfaceNumber) { throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); if (intf.isClaimed()) throw new USBException(String.format("Interface %d has already been claimed", interfaceNumber)); + var function = findFunction(interfaceNumber); + if (function == null) + throw new USBException(String.format("Interface number %d cannot be claimed (no DeviceInterfaceGUID?)", interfaceNumber)); + + try (var session = MemorySession.openConfined()) { + + // open Windows device + var pathSegment = Win.createSegmentFromString(function.devicePath(), session); + var deviceHandle = Kernel32.CreateFileW(pathSegment, Kernel32.GENERIC_WRITE() | Kernel32.GENERIC_READ(), + Kernel32.FILE_SHARE_WRITE() | Kernel32.FILE_SHARE_READ(), NULL, Kernel32.OPEN_EXISTING(), + Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), NULL); + + if (Win.IsInvalidHandle(deviceHandle)) + throw new WindowsUSBException( + String.format("Cannot open USB device %s", function.devicePath()), Kernel32.GetLastError()); + + try { + // open interface + var interfaceHandleHolder = session.allocate(ADDRESS); + if (WinUSB.WinUsb_Initialize(deviceHandle, interfaceHandleHolder) == 0) + throw new WindowsUSBException("Cannot open WinUSB device", Kernel32.GetLastError()); + var interfaceHandle = interfaceHandleHolder.get(ADDRESS, 0); + + function.setDeviceHandle(deviceHandle); + function.setFirstInterfaceHandle(interfaceHandle); + + } catch (Throwable e) { + Kernel32.CloseHandle(deviceHandle); + throw e; + } + } setClaimed(interfaceNumber, true); } @@ -118,6 +161,16 @@ public void releaseInterface(int interfaceNumber) { if (!intf.isClaimed()) throw new USBException(String.format("Interface %d has not been claimed", interfaceNumber)); + var function = findFunction(interfaceNumber); + assert function != null; + + if (function.deviceHandle() != null) { + WinUSB.WinUsb_Free(function.firstInterfaceHandle()); + function.setFirstInterfaceHandle(null); + Kernel32.CloseHandle(function.deviceHandle()); + function.setDeviceHandle(null); + } + setClaimed(interfaceNumber, false); } @@ -137,15 +190,16 @@ private MemorySegment createSetupPacket(MemorySession session, USBDirection dire @Override public byte[] controlTransferIn(USBControlTransfer setup, int length) { checkIsOpen(); + var function = findControlTransferFunction(setup); try (var session = MemorySession.openConfined()) { var buffer = session.allocate(length); var setupPacket = createSetupPacket(session, USBDirection.IN, setup, buffer); var lengthHolder = session.allocate(JAVA_INT); - if (WinUSB.WinUsb_ControlTransfer(firstInterface, setupPacket, buffer, (int) buffer.byteSize(), + if (WinUSB.WinUsb_ControlTransfer(function.firstInterfaceHandle(), setupPacket, buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) - throw new USBException("Control transfer IN failed", Kernel32.GetLastError()); + throw new WindowsUSBException("Control transfer IN failed", Kernel32.GetLastError()); int rxLength = lengthHolder.get(JAVA_INT, 0); return buffer.asSlice(0, rxLength).toArray(JAVA_BYTE); @@ -155,6 +209,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { @Override public void controlTransferOut(USBControlTransfer setup, byte[] data) { checkIsOpen(); + var function = findControlTransferFunction(setup); try (var session = MemorySession.openConfined()) { @@ -168,40 +223,44 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { var setupPacket = createSetupPacket(session, USBDirection.OUT, setup, buffer); var lengthHolder = session.allocate(JAVA_INT); - if (WinUSB.WinUsb_ControlTransfer(firstInterface, setupPacket, buffer, (int) buffer.byteSize(), + if (WinUSB.WinUsb_ControlTransfer(function.firstInterfaceHandle(), setupPacket, buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) - throw new USBException("Control transfer OUT failed", Kernel32.GetLastError()); + throw new WindowsUSBException("Control transfer OUT failed", Kernel32.GetLastError()); } } @Override public void transferOut(int endpointNumber, byte[] data) { - byte endpointAddress = getEndpointAddress(endpointNumber, USBDirection.OUT, - USBTransferType.BULK, USBTransferType.INTERRUPT); + checkIsOpen(); + + var endpoint = getEndpoint(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); + var function = findFunction(endpoint.interfaceNumber()); + assert function != null; try (var session = MemorySession.openConfined()) { var buffer = session.allocate(data.length); buffer.copyFrom(MemorySegment.ofArray(data)); var lengthHolder = session.allocate(JAVA_INT); - if (WinUSB.WinUsb_WritePipe(firstInterface, endpointAddress, buffer, (int) buffer.byteSize(), + if (WinUSB.WinUsb_WritePipe(function.firstInterfaceHandle(), endpoint.endpointAddress(), buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) - throw new USBException("Control transfer IN failed", Kernel32.GetLastError()); + throw new WindowsUSBException("Bulk/interrupt transfer OUT failed", Kernel32.GetLastError()); } } @Override public byte[] transferIn(int endpointNumber, int maxLength) { - byte endpointAddress = getEndpointAddress(endpointNumber, USBDirection.IN, - USBTransferType.BULK, USBTransferType.INTERRUPT); + var endpoint = getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); + var function = findFunction(endpoint.interfaceNumber()); + assert function != null; try (var session = MemorySession.openConfined()) { var buffer = session.allocate(maxLength); var lengthHolder = session.allocate(JAVA_INT); - if (WinUSB.WinUsb_ReadPipe(firstInterface, endpointAddress, buffer, (int) buffer.byteSize(), lengthHolder + if (WinUSB.WinUsb_ReadPipe(function.firstInterfaceHandle(), endpoint.endpointAddress(), buffer, (int) buffer.byteSize(), lengthHolder , NULL) == 0) - throw new USBException("Control transfer IN failed", Kernel32.GetLastError()); + throw new WindowsUSBException("Bulk/interrupt transfer IN failed", Kernel32.GetLastError()); int len = lengthHolder.get(JAVA_INT, 0); return buffer.asSlice(0, len).toArray(JAVA_BYTE); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index f38cf07f..90053454 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -13,7 +13,9 @@ import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.common.USBDeviceRegistry; import net.codecrete.usb.common.USBStructs; +import net.codecrete.usb.windows.gen.kernel32.GUID; import net.codecrete.usb.windows.gen.kernel32.Kernel32; +import net.codecrete.usb.windows.gen.ole32.Ole32; import net.codecrete.usb.windows.gen.setupapi.SP_DEVICE_INTERFACE_DATA; import net.codecrete.usb.windows.gen.setupapi.SP_DEVINFO_DATA; import net.codecrete.usb.windows.gen.setupapi.SetupAPI; @@ -26,6 +28,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.regex.Pattern; import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.*; @@ -70,7 +73,7 @@ protected void monitorDevices() { hwnd = User32.CreateWindowExW(0, className, windowName, 0, 0, 0, 0, 0, User32.HWND_MESSAGE(), NULL, instance, NULL); if (hwnd == NULL) - throw new USBException("internal error (CreateWindowExW)", Kernel32.GetLastError()); + throw new WindowsUSBException("internal error (CreateWindowExW)", Kernel32.GetLastError()); // configure notifications var notificationFilter = session.allocate(DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); @@ -82,7 +85,7 @@ protected void monitorDevices() { var notifyHandle = User32.RegisterDeviceNotificationW(hwnd, notificationFilter, User32.DEVICE_NOTIFY_WINDOW_HANDLE()); if (notifyHandle == NULL) - throw new USBException("internal error (RegisterDeviceNotificationW)", Kernel32.GetLastError()); + throw new WindowsUSBException("internal error (RegisterDeviceNotificationW)", Kernel32.GetLastError()); // initial device enumeration enumeratePresentDevices(); @@ -150,6 +153,63 @@ private void enumeratePresentDevices() { } } + /** + * Gets the functions of the children of a composite device + * + * @param childrenIds the children IDs + * @return a list of functions (interface number and device path) + */ + private List getCompositeFunctions(List childrenIds) { + + var functions = new ArrayList(); + + // iterate all children + for (var instanceId : childrenIds) { + try (var session = MemorySession.openConfined()) { + // create device info set + var devInfoSetHandle = SetupAPI.SetupDiCreateDeviceInfoList(NULL, NULL); + if (Win.IsInvalidHandle(devInfoSetHandle)) + throw new WindowsUSBException("Cannot create device info list", Kernel32.GetLastError()); + session.addCloseAction(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); + + // get device info for child + var devInfo = session.allocate(SP_DEVINFO_DATA.$LAYOUT()); + SP_DEVINFO_DATA.cbSize$set(devInfo, (int) devInfo.byteSize()); + var instanceIdSegment = Win.createSegmentFromString(instanceId, session); + if (SetupAPI.SetupDiOpenDeviceInfoW(devInfoSetHandle, instanceIdSegment, NULL, 0, devInfo) == 0) + throw new WindowsUSBException("Internal error (SetupDiOpenDeviceInfoW)", Kernel32.GetLastError()); + + // get hardware IDs (to extract interface number) + var hardwareIds = DeviceProperty.getDeviceStringListProperty(devInfoSetHandle, devInfo, + DeviceProperty.DEVPKEY_Device_HardwareIds); + int interfaceNumber = extractInterfaceNumber(hardwareIds); + if (interfaceNumber == -1) + continue; + + var guids = DeviceProperty.findDeviceInterfaceGUIDs(devInfoSetHandle, devInfo, session); + + for (var guid : guids) { + // check for Class GUID + var guidSegment = Win.createSegmentFromString(guid, session); + var clsid = session.allocate(GUID.$LAYOUT()); + if (Ole32.CLSIDFromString(guidSegment, clsid) != 0) + continue; + + try { + var devicePath = DeviceProperty.getDevicePath(instanceId, clsid); + functions.add(new CompositeFunction(interfaceNumber, devicePath)); + break; + } catch (Exception e) { + // ignore and try next one + } + } + } + + } + + return functions; + } + private USBDevice createDeviceFromDeviceInfo(MemoryAddress devInfoSetHandle, MemorySegment devInfo, String devicePath, HashMap hubHandles) { try (var session = MemorySession.openConfined()) { @@ -171,19 +231,33 @@ private USBDevice createDeviceFromDeviceInfo(MemoryAddress devInfoSetHandle, Mem hubHandles.put(hubPath, hubHandle); } - return createDevice(devicePath, hubHandle, usbPortNum); + // check for composite device + var deviceService = DeviceProperty.getDeviceStringProperty(devInfoSetHandle, devInfo, + DeviceProperty.DEVPKEY_Device_Service); + + List functions; + if (isCompositeDevice(deviceService)) { + functions = getCompositeFunctions(DeviceProperty.getDeviceStringListProperty(devInfoSetHandle, devInfo, + DeviceProperty.DEVPKEY_Device_Children)); + } else { + functions = new ArrayList<>(); + functions.add(new CompositeFunction(0, devicePath)); + } + + return createDevice(devicePath, functions, hubHandle, usbPortNum); } } /** * Retrieve device descriptor and create {@code USBDevice} instance * - * @param devicePath the device path + * @param functions composite functions * @param hubHandle the hub handle (parent) * @param usbPortNum the USB port number * @return the {@code USBDevice} instance */ - private USBDevice createDevice(String devicePath, MemoryAddress hubHandle, int usbPortNum) { + private USBDevice createDevice(String devicePath, List functions, MemoryAddress hubHandle, + int usbPortNum) { try (var session = MemorySession.openConfined()) { @@ -193,7 +267,7 @@ private USBDevice createDevice(String devicePath, MemoryAddress hubHandle, int u var sizeHolder = session.allocate(JAVA_INT); if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), connInfo , (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL) == 0) - throw new USBException("Internal error (cannot get device descriptor)", Kernel32.GetLastError()); + throw new WindowsUSBException("Internal error (cannot get device descriptor)", Kernel32.GetLastError()); var deviceDesc = USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(connInfo); @@ -211,8 +285,8 @@ private USBDevice createDevice(String devicePath, MemoryAddress hubHandle, int u var configDesc = getDescriptor(hubHandle, usbPortNum, USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE, 0, (short) 0, session); - var device = new WindowsUSBDevice(devicePath, vendorId, productId, manufacturer, product, serialNumber, - configDesc); + var device = new WindowsUSBDevice(devicePath, functions, vendorId, productId, manufacturer, product, + serialNumber, configDesc); int classCode = 255 & (byte) USBDescriptors.Device_bDeviceClass.get(deviceDesc); int subclassCode = 255 & (byte) USBDescriptors.Device_bDeviceSubClass.get(deviceDesc); @@ -229,7 +303,6 @@ private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, in } - private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, int descriptorType, int index, short languageID, int requestSize, MemorySession session) { @@ -251,7 +324,7 @@ private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, in var effectiveSizeHolder = session.allocate(JAVA_INT); if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION(), descriptorRequest, size, descriptorRequest, size, effectiveSizeHolder, NULL) == 0) - throw new USBException(String.format("Cannot retrieve descriptor %d", index), Kernel32.GetLastError()); + throw new WindowsUSBException(String.format("Cannot retrieve descriptor %d", index), Kernel32.GetLastError()); // determine size of descriptor int expectedSize; @@ -325,7 +398,7 @@ private void onDeviceConnected(String devicePath) { final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); if (Win.IsInvalidHandle(devInfoSetHandle)) - throw new USBException("internal error (SetupDiGetClassDevsW)", Kernel32.GetLastError()); + throw new WindowsUSBException("internal error (SetupDiGetClassDevsW)", Kernel32.GetLastError()); // ensure the result is destroyed when the scope is left session.addCloseAction(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); @@ -335,7 +408,7 @@ private void onDeviceConnected(String devicePath) { var devicePathSegment = Win.createSegmentFromString(devicePath, session); // TODO: Check if result needs to be freed if (SetupAPI.SetupDiOpenDeviceInterfaceW(devInfoSetHandle, devicePathSegment, 0, devIntfData) == 0) - throw new USBException("internal error (SetupDiOpenDeviceInterfaceW)", Kernel32.GetLastError()); + throw new WindowsUSBException("internal error (SetupDiOpenDeviceInterfaceW)", Kernel32.GetLastError()); var devInfo = session.allocate(SP_DEVINFO_DATA.$LAYOUT()); SP_DEVINFO_DATA.cbSize$set(devInfo, (int) devInfo.byteSize()); @@ -389,4 +462,29 @@ protected int findDeviceIndex(List deviceList, Object deviceId) { } return -1; } + + private static boolean isCompositeDevice(String deviceService) { + // usbccgp is the USB Generic Parent Driver used for composite devices + return "usbccgp".equalsIgnoreCase(deviceService); + } + + private static final Pattern MULTIPLE_INTERFACE_ID = Pattern.compile("USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); + + private static int extractInterfaceNumber(List hardwareIds) { + // Also see https://docs.microsoft.com/en-us/windows-hardware/drivers/install/standard-usb-identifiers#multiple-interface-usb-devices + + for (var id : hardwareIds) { + var matcher = MULTIPLE_INTERFACE_ID.matcher(id); + if (matcher.find()) { + var intfHexNumber = matcher.group(1); + try { + return Integer.parseInt(intfHexNumber, 16); + } catch (NumberFormatException e) { + // ignore and try next one + } + } + } + + return -1; + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java new file mode 100644 index 00000000..c6463801 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java @@ -0,0 +1,43 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +package net.codecrete.usb.windows; + +import net.codecrete.usb.USBException; +import net.codecrete.usb.windows.gen.kernel32.Kernel32; + +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; + +import static java.lang.foreign.MemoryAddress.NULL; +import static java.lang.foreign.ValueLayout.ADDRESS; + +public class WindowsUSBException extends USBException { + public WindowsUSBException(String message) { + super(message); + } + + public WindowsUSBException(String message, int errorCode) { + super(String.format("%s - %s", message, getErrorMessage(errorCode)), errorCode); + } + + public WindowsUSBException(String message, Throwable cause) { + super(message, cause); + } + + private static String getErrorMessage(int errorCode) { + try (var session = MemorySession.openConfined()) { + var messagePointerHolder = session.allocate(ADDRESS); + Kernel32.FormatMessageW(Kernel32.FORMAT_MESSAGE_ALLOCATE_BUFFER() + | Kernel32.FORMAT_MESSAGE_FROM_SYSTEM() | Kernel32.FORMAT_MESSAGE_IGNORE_INSERTS(), + NULL, errorCode, 0, messagePointerHolder, 0, NULL); + var messagePointer = messagePointerHolder.get(ADDRESS, 0); + String message = Win.createStringFromSegment(MemorySegment.ofAddress(messagePointer, 4000, session)); + Kernel32.LocalFree(messagePointer); + return message.trim(); + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java new file mode 100644 index 00000000..d65c860a --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java @@ -0,0 +1,50 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.advapi32; + +import java.lang.foreign.Addressable; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.*; +public class Advapi32 { + + /* package-private */ Advapi32() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static MethodHandle RegCloseKey$MH() { + return RuntimeHelper.requireNonNull(constants$0.RegCloseKey$MH,"RegCloseKey"); + } + public static int RegCloseKey ( Addressable hKey) { + var mh$ = RegCloseKey$MH(); + try { + return (int)mh$.invokeExact(hKey); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle RegQueryValueExW$MH() { + return RuntimeHelper.requireNonNull(constants$0.RegQueryValueExW$MH,"RegQueryValueExW"); + } + public static int RegQueryValueExW ( Addressable hKey, Addressable lpValueName, Addressable lpReserved, Addressable lpType, Addressable lpData, Addressable lpcbData) { + var mh$ = RegQueryValueExW$MH(); + try { + return (int)mh$.invokeExact(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static int KEY_READ() { + return (int)131097L; + } + public static int REG_MULTI_SZ() { + return (int)7L; + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Constants$root.java new file mode 100644 index 00000000..e1a30f5a --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.advapi32; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java new file mode 100644 index 00000000..707bc5cb --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java @@ -0,0 +1,216 @@ +package net.codecrete.usb.windows.gen.advapi32; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + System.loadLibrary("Advapi32"); + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/constants$0.java new file mode 100644 index 00000000..d7b38ce0 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/constants$0.java @@ -0,0 +1,30 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.advapi32; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor RegCloseKey$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle RegCloseKey$MH = RuntimeHelper.downcallHandle( + "RegCloseKey", + constants$0.RegCloseKey$FUNC + ); + static final FunctionDescriptor RegQueryValueExW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle RegQueryValueExW$MH = RuntimeHelper.downcallHandle( + "RegQueryValueExW", + constants$0.RegQueryValueExW$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java index 1e481c41..f4de7118 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -33,6 +33,15 @@ public static int OPEN_EXISTING() { public static int FILE_FLAG_OVERLAPPED() { return (int)1073741824L; } + public static int FORMAT_MESSAGE_ALLOCATE_BUFFER() { + return (int)256L; + } + public static int FORMAT_MESSAGE_IGNORE_INSERTS() { + return (int)512L; + } + public static int FORMAT_MESSAGE_FROM_SYSTEM() { + return (int)4096L; + } public static MethodHandle CreateFileW$MH() { return RuntimeHelper.requireNonNull(constants$0.CreateFileW$MH,"CreateFileW"); } @@ -88,6 +97,28 @@ public static MemoryAddress GetModuleHandleW ( Addressable lpModuleName) { throw new AssertionError("should not reach here", ex$); } } + public static MethodHandle LocalFree$MH() { + return RuntimeHelper.requireNonNull(constants$0.LocalFree$MH,"LocalFree"); + } + public static MemoryAddress LocalFree ( Addressable hMem) { + var mh$ = LocalFree$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(hMem); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle FormatMessageW$MH() { + return RuntimeHelper.requireNonNull(constants$1.FormatMessageW$MH,"FormatMessageW"); + } + public static int FormatMessageW ( int dwFlags, Addressable lpSource, int dwMessageId, int dwLanguageId, Addressable lpBuffer, int nSize, Addressable Arguments) { + var mh$ = FormatMessageW$MH(); + try { + return (int)mh$.invokeExact(dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static int GENERIC_READ() { return (int)2147483648L; } @@ -97,9 +128,15 @@ public static int GENERIC_WRITE() { public static int ERROR_SUCCESS() { return (int)0L; } + public static int ERROR_FILE_NOT_FOUND() { + return (int)2L; + } public static int ERROR_INSUFFICIENT_BUFFER() { return (int)122L; } + public static int ERROR_MORE_DATA() { + return (int)234L; + } public static int ERROR_NO_MORE_ITEMS() { return (int)259L; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java index 44c3452b..60564f7a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java @@ -52,6 +52,13 @@ class constants$0 { "GetModuleHandleW", constants$0.GetModuleHandleW$FUNC ); + static final FunctionDescriptor LocalFree$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle LocalFree$MH = RuntimeHelper.downcallHandle( + "LocalFree", + constants$0.LocalFree$FUNC + ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java new file mode 100644 index 00000000..1c4e52c7 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java @@ -0,0 +1,24 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.kernel32; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$1 { + + static final FunctionDescriptor FormatMessageW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle FormatMessageW$MH = RuntimeHelper.downcallHandle( + "FormatMessageW", + constants$1.FormatMessageW$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Constants$root.java new file mode 100644 index 00000000..b87f060d --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.ole32; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java new file mode 100644 index 00000000..f52d7fbe --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java @@ -0,0 +1,33 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.ole32; + +import java.lang.foreign.Addressable; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.*; +public class Ole32 { + + /* package-private */ Ole32() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static MethodHandle CLSIDFromString$MH() { + return RuntimeHelper.requireNonNull(constants$0.CLSIDFromString$MH,"CLSIDFromString"); + } + public static int CLSIDFromString ( Addressable lpsz, Addressable pclsid) { + var mh$ = CLSIDFromString$MH(); + try { + return (int)mh$.invokeExact(lpsz, pclsid); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java new file mode 100644 index 00000000..cd067be7 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java @@ -0,0 +1,216 @@ +package net.codecrete.usb.windows.gen.ole32; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + System.loadLibrary("Ole32"); + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/constants$0.java new file mode 100644 index 00000000..b42663eb --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/constants$0.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.ole32; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor CLSIDFromString$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CLSIDFromString$MH = RuntimeHelper.downcallHandle( + "CLSIDFromString", + constants$0.CLSIDFromString$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java index ff69c87e..e2ff0b66 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java @@ -18,18 +18,49 @@ public class SetupAPI { public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static int DEVPROP_TYPEMOD_LIST() { + return (int)8192L; + } public static int DEVPROP_TYPE_UINT32() { return (int)7L; } public static int DEVPROP_TYPE_STRING() { return (int)18L; } + public static int DICS_FLAG_GLOBAL() { + return (int)1L; + } public static int DIGCF_PRESENT() { return (int)2L; } public static int DIGCF_DEVICEINTERFACE() { return (int)16L; } + public static int DIREG_DEV() { + return (int)1L; + } + public static MethodHandle SetupDiCreateDeviceInfoList$MH() { + return RuntimeHelper.requireNonNull(constants$0.SetupDiCreateDeviceInfoList$MH,"SetupDiCreateDeviceInfoList"); + } + public static MemoryAddress SetupDiCreateDeviceInfoList ( Addressable ClassGuid, Addressable hwndParent) { + var mh$ = SetupDiCreateDeviceInfoList$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(ClassGuid, hwndParent); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle SetupDiOpenDeviceInfoW$MH() { + return RuntimeHelper.requireNonNull(constants$0.SetupDiOpenDeviceInfoW$MH,"SetupDiOpenDeviceInfoW"); + } + public static int SetupDiOpenDeviceInfoW ( Addressable DeviceInfoSet, Addressable DeviceInstanceId, Addressable hwndParent, int OpenFlags, Addressable DeviceInfoData) { + var mh$ = SetupDiOpenDeviceInfoW$MH(); + try { + return (int)mh$.invokeExact(DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static MethodHandle SetupDiEnumDeviceInfo$MH() { return RuntimeHelper.requireNonNull(constants$0.SetupDiEnumDeviceInfo$MH,"SetupDiEnumDeviceInfo"); } @@ -75,7 +106,7 @@ public static int SetupDiOpenDeviceInterfaceW ( Addressable DeviceInfoSet, Addr } } public static MethodHandle SetupDiGetDeviceInterfaceDetailW$MH() { - return RuntimeHelper.requireNonNull(constants$0.SetupDiGetDeviceInterfaceDetailW$MH,"SetupDiGetDeviceInterfaceDetailW"); + return RuntimeHelper.requireNonNull(constants$1.SetupDiGetDeviceInterfaceDetailW$MH,"SetupDiGetDeviceInterfaceDetailW"); } public static int SetupDiGetDeviceInterfaceDetailW ( Addressable DeviceInfoSet, Addressable DeviceInterfaceData, Addressable DeviceInterfaceDetailData, int DeviceInterfaceDetailDataSize, Addressable RequiredSize, Addressable DeviceInfoData) { var mh$ = SetupDiGetDeviceInterfaceDetailW$MH(); @@ -86,7 +117,7 @@ public static int SetupDiGetDeviceInterfaceDetailW ( Addressable DeviceInfoSet, } } public static MethodHandle SetupDiGetClassDevsW$MH() { - return RuntimeHelper.requireNonNull(constants$0.SetupDiGetClassDevsW$MH,"SetupDiGetClassDevsW"); + return RuntimeHelper.requireNonNull(constants$1.SetupDiGetClassDevsW$MH,"SetupDiGetClassDevsW"); } public static MemoryAddress SetupDiGetClassDevsW ( Addressable ClassGuid, Addressable Enumerator, Addressable hwndParent, int Flags) { var mh$ = SetupDiGetClassDevsW$MH(); @@ -96,6 +127,17 @@ public static MemoryAddress SetupDiGetClassDevsW ( Addressable ClassGuid, Addre throw new AssertionError("should not reach here", ex$); } } + public static MethodHandle SetupDiOpenDevRegKey$MH() { + return RuntimeHelper.requireNonNull(constants$1.SetupDiOpenDevRegKey$MH,"SetupDiOpenDevRegKey"); + } + public static MemoryAddress SetupDiOpenDevRegKey ( Addressable DeviceInfoSet, Addressable DeviceInfoData, int Scope, int HwProfile, int KeyType, int samDesired) { + var mh$ = SetupDiOpenDevRegKey$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(DeviceInfoSet, DeviceInfoData, Scope, HwProfile, KeyType, samDesired); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static MethodHandle SetupDiGetDevicePropertyW$MH() { return RuntimeHelper.requireNonNull(constants$1.SetupDiGetDevicePropertyW$MH,"SetupDiGetDevicePropertyW"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java index 4bec4d2c..60b0522a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java @@ -6,6 +6,25 @@ import java.lang.invoke.MethodHandle; class constants$0 { + static final FunctionDescriptor SetupDiCreateDeviceInfoList$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle SetupDiCreateDeviceInfoList$MH = RuntimeHelper.downcallHandle( + "SetupDiCreateDeviceInfoList", + constants$0.SetupDiCreateDeviceInfoList$FUNC + ); + static final FunctionDescriptor SetupDiOpenDeviceInfoW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle SetupDiOpenDeviceInfoW$MH = RuntimeHelper.downcallHandle( + "SetupDiOpenDeviceInfoW", + constants$0.SetupDiOpenDeviceInfoW$FUNC + ); static final FunctionDescriptor SetupDiEnumDeviceInfo$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_LONG$LAYOUT, @@ -43,28 +62,6 @@ class constants$0 { "SetupDiOpenDeviceInterfaceW", constants$0.SetupDiOpenDeviceInterfaceW$FUNC ); - static final FunctionDescriptor SetupDiGetDeviceInterfaceDetailW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle SetupDiGetDeviceInterfaceDetailW$MH = RuntimeHelper.downcallHandle( - "SetupDiGetDeviceInterfaceDetailW", - constants$0.SetupDiGetDeviceInterfaceDetailW$FUNC - ); - static final FunctionDescriptor SetupDiGetClassDevsW$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT - ); - static final MethodHandle SetupDiGetClassDevsW$MH = RuntimeHelper.downcallHandle( - "SetupDiGetClassDevsW", - constants$0.SetupDiGetClassDevsW$FUNC - ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java index 4b48fe18..1aeac7c7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java @@ -6,6 +6,40 @@ import java.lang.invoke.MethodHandle; class constants$1 { + static final FunctionDescriptor SetupDiGetDeviceInterfaceDetailW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle SetupDiGetDeviceInterfaceDetailW$MH = RuntimeHelper.downcallHandle( + "SetupDiGetDeviceInterfaceDetailW", + constants$1.SetupDiGetDeviceInterfaceDetailW$FUNC + ); + static final FunctionDescriptor SetupDiGetClassDevsW$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT + ); + static final MethodHandle SetupDiGetClassDevsW$MH = RuntimeHelper.downcallHandle( + "SetupDiGetClassDevsW", + constants$1.SetupDiGetClassDevsW$FUNC + ); + static final FunctionDescriptor SetupDiOpenDevRegKey$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG$LAYOUT + ); + static final MethodHandle SetupDiOpenDevRegKey$MH = RuntimeHelper.downcallHandle( + "SetupDiOpenDevRegKey", + constants$1.SetupDiOpenDevRegKey$FUNC + ); static final FunctionDescriptor SetupDiGetDevicePropertyW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT, diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java index 43250a47..f3cc4111 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java @@ -40,6 +40,17 @@ public static int WinUsb_Free ( Addressable InterfaceHandle) { throw new AssertionError("should not reach here", ex$); } } + public static MethodHandle WinUsb_GetAssociatedInterface$MH() { + return RuntimeHelper.requireNonNull(constants$0.WinUsb_GetAssociatedInterface$MH,"WinUsb_GetAssociatedInterface"); + } + public static int WinUsb_GetAssociatedInterface ( Addressable InterfaceHandle, byte AssociatedInterfaceIndex, Addressable AssociatedInterfaceHandle) { + var mh$ = WinUsb_GetAssociatedInterface$MH(); + try { + return (int)mh$.invokeExact(InterfaceHandle, AssociatedInterfaceIndex, AssociatedInterfaceHandle); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static MethodHandle WinUsb_GetDescriptor$MH() { return RuntimeHelper.requireNonNull(constants$0.WinUsb_GetDescriptor$MH,"WinUsb_GetDescriptor"); } @@ -74,7 +85,7 @@ public static int WinUsb_WritePipe ( Addressable InterfaceHandle, byte PipeID, } } public static MethodHandle WinUsb_ControlTransfer$MH() { - return RuntimeHelper.requireNonNull(constants$0.WinUsb_ControlTransfer$MH,"WinUsb_ControlTransfer"); + return RuntimeHelper.requireNonNull(constants$1.WinUsb_ControlTransfer$MH,"WinUsb_ControlTransfer"); } public static int WinUsb_ControlTransfer ( Addressable InterfaceHandle, MemorySegment SetupPacket, Addressable Buffer, int BufferLength, Addressable LengthTransferred, Addressable Overlapped) { var mh$ = WinUsb_ControlTransfer$MH(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java index 57e13e9a..66a14d35 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java @@ -3,7 +3,6 @@ package net.codecrete.usb.windows.gen.winusb; import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; import java.lang.invoke.MethodHandle; class constants$0 { @@ -22,6 +21,15 @@ class constants$0 { "WinUsb_Free", constants$0.WinUsb_Free$FUNC ); + static final FunctionDescriptor WinUsb_GetAssociatedInterface$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle WinUsb_GetAssociatedInterface$MH = RuntimeHelper.downcallHandle( + "WinUsb_GetAssociatedInterface", + constants$0.WinUsb_GetAssociatedInterface$FUNC + ); static final FunctionDescriptor WinUsb_GetDescriptor$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_CHAR$LAYOUT, @@ -59,24 +67,6 @@ class constants$0 { "WinUsb_WritePipe", constants$0.WinUsb_WritePipe$FUNC ); - static final FunctionDescriptor WinUsb_ControlTransfer$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("RequestType"), - Constants$root.C_CHAR$LAYOUT.withName("Request"), - Constants$root.C_SHORT$LAYOUT.withName("Value"), - Constants$root.C_SHORT$LAYOUT.withName("Index"), - Constants$root.C_SHORT$LAYOUT.withName("Length") - ).withName("_WINUSB_SETUP_PACKET"), - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle WinUsb_ControlTransfer$MH = RuntimeHelper.downcallHandle( - "WinUsb_ControlTransfer", - constants$0.WinUsb_ControlTransfer$FUNC - ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java new file mode 100644 index 00000000..123b8fad --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java @@ -0,0 +1,30 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.winusb; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +class constants$1 { + + static final FunctionDescriptor WinUsb_ControlTransfer$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("RequestType"), + Constants$root.C_CHAR$LAYOUT.withName("Request"), + Constants$root.C_SHORT$LAYOUT.withName("Value"), + Constants$root.C_SHORT$LAYOUT.withName("Index"), + Constants$root.C_SHORT$LAYOUT.withName("Length") + ).withName("_WINUSB_SETUP_PACKET"), + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle WinUsb_ControlTransfer$MH = RuntimeHelper.downcallHandle( + "WinUsb_ControlTransfer", + constants$1.WinUsb_ControlTransfer$FUNC + ); +} + + diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java index 9832a14a..a5d1374c 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java @@ -20,22 +20,22 @@ public class ControlTransferTest extends TestDeviceBase { @Test void storeValue_succeeds() { - testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x01, (short) 10730, (short) 0), null); + testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x01, (short) 10730, (short) LOOPBACK_INTF), null); } @Test void retrieveValue_isSameAsStored() { - testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x01, (short) 0x9a41, (short) 0), null); - var valueBytes = testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) 0), 4); - var expectedBytes = new byte[] { (byte)0x41, (byte)0x9a, (byte)0x00, (byte)0x00 }; + testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x01, (short) 0x9a41, (short) LOOPBACK_INTF), null); + var valueBytes = testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) LOOPBACK_INTF), 4); + var expectedBytes = new byte[]{(byte) 0x41, (byte) 0x9a, (byte) 0x00, (byte) 0x00}; assertArrayEquals(expectedBytes, valueBytes); } @Test void storeValueInDataStage_canBeRetrieved() { - var sentValue = new byte[] { (byte)0x83, (byte)0x03, (byte)0xda, (byte)0x3e }; - testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x02, (short) 0, (short) 0), sentValue); - var retrievedValue = testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) 0), 4); + var sentValue = new byte[]{(byte) 0x83, (byte) 0x03, (byte) 0xda, (byte) 0x3e}; + testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x02, (short) 0, (short) LOOPBACK_INTF), sentValue); + var retrievedValue = testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) LOOPBACK_INTF), 4); assertArrayEquals(sentValue, retrievedValue); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index 293d6c5e..542b5cc0 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -24,9 +24,9 @@ void deviceInfo_isCorrect() { assertEquals("Loopback", testDevice.product()); assertEquals(12, testDevice.serialNumber().length()); - assertEquals(0xff, testDevice.classCode()); - assertEquals(0x00, testDevice.subclassCode()); - assertEquals(0x00, testDevice.protocolCode()); + assertEquals(0xef, testDevice.classCode()); + assertEquals(0x02, testDevice.subclassCode()); + assertEquals(0x01, testDevice.protocolCode()); } @Test diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java index 17f875a8..cacd7dd9 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java @@ -17,7 +17,7 @@ public class InvalidOperationTest extends TestDeviceBase { @Test void claimInvalidInterface_throws() { // throws error because it's already claimed - Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(0)); + Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(LOOPBACK_INTF)); // throws error because it's an invalid interface number Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(3)); // throws error because it's an invalid interface number diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index f3b7d7d7..75799ead 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -25,11 +25,11 @@ public class TestDeviceBase { /** * Test device product ID */ - static final int PID = 0xceaf; + static final int PID = 0xcea0; /** * Test device loopback interface number */ - static final int LOOPBACK_INTF = 0; + static final int LOOPBACK_INTF = 2; protected static final int LOOPBACK_EP_OUT = 1; protected static final int LOOPBACK_EP_IN = 2; protected static final int LOOPBACK_MAX_PACKET_SIZE = 64; diff --git a/test-devices/composite-stm32/README.md b/test-devices/composite-stm32/README.md index fc008e56..6f28875c 100644 --- a/test-devices/composite-stm32/README.md +++ b/test-devices/composite-stm32/README.md @@ -28,10 +28,12 @@ The bulk endpoints 0x01 and 0x82 use an internal buffer of about 1000 bytes. Dat Several vendor-specific control requests are supported for testing: | `bmRequest` | `bRequest` | `wValue` | `wIndex` | `wLength` | Data | Action | -| - | - | - | - | - | - | - | -| 0x41 | 0x01 | *value* | 0 | 0 | none | Host to device: *value* is saved in device | -| 0x41 | 0x02 | 0 | 0 | 4 | *value* (32-bit LE) | Host to device: *value* is saved in device | -| 0xC1 | 0x03 | 0 | 0 | 4 | *value* (32-bit LE) | Device to host: saved *value* is transmitted | +| -:| -:| -:| -:| -:| - | - | +| 0x41 | 0x01 | *value* | 2 | 0 | none | Host to device: *value* is saved in device | +| 0x41 | 0x02 | 0 | 2 | 4 | *value* (32-bit LE) | Host to device: *value* is saved in device | +| 0xC1 | 0x03 | 0 | 2 | 4 | *value* (32-bit LE) | Device to host: saved *value* is transmitted | + +Note: The lower byte of `wIndex` contains the interface number. Additionally, the control request of CDC ACM PTSN (for configuring and querying the serial port) are accepted but have no effect in most cases. diff --git a/test-devices/composite-stm32/src/main.cpp b/test-devices/composite-stm32/src/main.cpp index cd6bd424..20adde7b 100644 --- a/test-devices/composite-stm32/src/main.cpp +++ b/test-devices/composite-stm32/src/main.cpp @@ -263,7 +263,7 @@ usbd_request_return_codes on_vendor_control_request(__attribute__((unused)) usbd __attribute__((unused)) usbd_control_complete_callback *complete) { switch (req->bRequest) { case 1: - if (req->wIndex == 0 && req->wLength == 0) { + if (req->wIndex == 2 && req->wLength == 0) { saved_value = req->wValue; return USBD_REQ_HANDLED; } else { @@ -272,7 +272,7 @@ usbd_request_return_codes on_vendor_control_request(__attribute__((unused)) usbd break; case 2: - if (req->wIndex == 0 && req->wLength == 4) { + if (req->wIndex == 2 && req->wLength == 4) { uint32_t *value = reinterpret_cast(*buf); saved_value = *value; return USBD_REQ_HANDLED; @@ -282,7 +282,7 @@ usbd_request_return_codes on_vendor_control_request(__attribute__((unused)) usbd break; case 3: - if (req->wIndex == 0) { + if (req->wIndex == 2) { uint8_t *value = reinterpret_cast(&saved_value); *len = std::min(*len, (uint16_t)4); memcpy(*buf, value, *len); From d9bb7630e9976be578ebaa457a68cc09e663a889 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 12 Sep 2022 22:53:22 +0200 Subject: [PATCH 083/433] General tests for both test devices --- .../codecrete/usb/ControlTransferTest.java | 10 ++-- .../net/codecrete/usb/DescriptionTest.java | 24 ++++++--- .../codecrete/usb/DeviceEnumerationTest.java | 26 ++++----- .../codecrete/usb/DeviceLifecycleTest.java | 28 +++++----- .../codecrete/usb/InvalidOperationTest.java | 2 +- .../net/codecrete/usb/TestDeviceBase.java | 53 +++++++++++++++---- 6 files changed, 91 insertions(+), 52 deletions(-) diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java index a5d1374c..b0d2840f 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java @@ -20,13 +20,13 @@ public class ControlTransferTest extends TestDeviceBase { @Test void storeValue_succeeds() { - testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x01, (short) 10730, (short) LOOPBACK_INTF), null); + testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x01, (short) 10730, (short) interfaceNumber), null); } @Test void retrieveValue_isSameAsStored() { - testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x01, (short) 0x9a41, (short) LOOPBACK_INTF), null); - var valueBytes = testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) LOOPBACK_INTF), 4); + testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x01, (short) 0x9a41, (short) interfaceNumber), null); + var valueBytes = testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) interfaceNumber), 4); var expectedBytes = new byte[]{(byte) 0x41, (byte) 0x9a, (byte) 0x00, (byte) 0x00}; assertArrayEquals(expectedBytes, valueBytes); } @@ -34,8 +34,8 @@ void retrieveValue_isSameAsStored() { @Test void storeValueInDataStage_canBeRetrieved() { var sentValue = new byte[]{(byte) 0x83, (byte) 0x03, (byte) 0xda, (byte) 0x3e}; - testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x02, (short) 0, (short) LOOPBACK_INTF), sentValue); - var retrievedValue = testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) LOOPBACK_INTF), 4); + testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x02, (short) 0, (short) interfaceNumber), sentValue); + var retrievedValue = testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) interfaceNumber), 4); assertArrayEquals(sentValue, retrievedValue); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index 542b5cc0..98755ce7 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -24,25 +24,33 @@ void deviceInfo_isCorrect() { assertEquals("Loopback", testDevice.product()); assertEquals(12, testDevice.serialNumber().length()); - assertEquals(0xef, testDevice.classCode()); - assertEquals(0x02, testDevice.subclassCode()); - assertEquals(0x01, testDevice.protocolCode()); + if (interfaceNumber == 2) { + // composite device + assertEquals(0xef, testDevice.classCode()); + assertEquals(0x02, testDevice.subclassCode()); + assertEquals(0x01, testDevice.protocolCode()); + } else { + // simple device + assertEquals(0xff, testDevice.classCode()); + assertEquals(0x00, testDevice.subclassCode()); + assertEquals(0x00, testDevice.protocolCode()); + } } @Test void interfaceDescriptors_isCorrect() { assertNotNull(testDevice.interfaces()); - assertEquals(LOOPBACK_INTF + 1, testDevice.interfaces().size()); + assertEquals(interfaceNumber + 1, testDevice.interfaces().size()); - var intf = testDevice.interfaces().get(LOOPBACK_INTF); - assertEquals(LOOPBACK_INTF, intf.number()); + var intf = testDevice.interfaces().get(interfaceNumber); + assertEquals(interfaceNumber, intf.number()); assertNotNull(intf.alternate()); assertTrue(intf.isClaimed()); } @Test void alternateInterfaceDescriptors_isCorrect() { - var intf = testDevice.interfaces().get(LOOPBACK_INTF); + var intf = testDevice.interfaces().get(interfaceNumber); var altIntf = intf.alternate(); assertNotNull(intf.alternates()); assertEquals(1, intf.alternates().size()); @@ -56,7 +64,7 @@ void alternateInterfaceDescriptors_isCorrect() { @Test void endpointDescriptors_isCorrect() { - var altIntf = testDevice.interfaces().get(LOOPBACK_INTF).alternate(); + var altIntf = testDevice.interfaces().get(interfaceNumber).alternate(); assertNotNull(altIntf.endpoints()); assertEquals(4, altIntf.endpoints().size()); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java index 600e5671..78eb349a 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java @@ -21,43 +21,43 @@ public class DeviceEnumerationTest extends TestDeviceBase { @Test void getAllDevices_includesLoopback() { var found = USB.getAllDevices().stream() - .anyMatch(device -> device.vendorId() == VID && device.productId() == PID); + .anyMatch(device -> device.vendorId() == vid && device.productId() == pid); assertTrue(found); } @Test void getDevicesWithFilter_returnsLoopback() { - var result = USB.getDevices(new USBDeviceFilter(VID, PID)); + var result = USB.getDevices(new USBDeviceFilter(vid, pid)); assertEquals(1, result.size()); - assertEquals(VID, result.get(0).vendorId()); - assertEquals(PID, result.get(0).productId()); + assertEquals(vid, result.get(0).vendorId()); + assertEquals(pid, result.get(0).productId()); } @Test void getDevicesWithMultipleFilters_returnsLoopback() { var result = USB.getDevices(List.of( - new USBDeviceFilter(VID, PID), + new USBDeviceFilter(vid, pid), new USBDeviceFilter(0x0000, 0xffff) )); assertEquals(1, result.size()); - assertEquals(VID, result.get(0).vendorId()); - assertEquals(PID, result.get(0).productId()); + assertEquals(vid, result.get(0).vendorId()); + assertEquals(pid, result.get(0).productId()); } @Test void getDeviceWithFilter_returnsLoopback() { - var device = USB.getDevice(new USBDeviceFilter(VID, PID)); - assertEquals(VID, device.vendorId()); - assertEquals(PID, device.productId()); + var device = USB.getDevice(new USBDeviceFilter(vid, pid)); + assertEquals(vid, device.vendorId()); + assertEquals(pid, device.productId()); } @Test void getDeviceWithMultipleFilters_returnsLoopback() { var device = USB.getDevice(List.of( - new USBDeviceFilter(VID, PID), + new USBDeviceFilter(vid, pid), new USBDeviceFilter(0x0000, 0xffff) )); - assertEquals(VID, device.vendorId()); - assertEquals(PID, device.productId()); + assertEquals(vid, device.vendorId()); + assertEquals(pid, device.productId()); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java index 3d5f46aa..c9aa23be 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java @@ -12,7 +12,6 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; -import static net.codecrete.usb.TestDeviceBase.*; import static org.junit.jupiter.api.Assertions.*; public class DeviceLifecycleTest { @@ -21,45 +20,44 @@ public class DeviceLifecycleTest { @Test void lifecycle_showsValidState() { - device = USB.getDevice(new USBDeviceFilter(VID, PID)); - if (device == null) - throw new IllegalStateException("USB loopback test device must be connected"); + device = TestDeviceBase.getDevice(); + int interfaceNumber = TestDeviceBase.getInterfaceNumber(device); - var intf = device.interfaces().get(LOOPBACK_INTF); - assertEquals(LOOPBACK_INTF, intf.number()); + var intf = device.interfaces().get(interfaceNumber); + assertEquals(interfaceNumber, intf.number()); assertFalse(device.isOpen()); assertFalse(intf.isClaimed()); - assertThrows(USBException.class, () -> device.claimInterface(LOOPBACK_INTF)); - assertThrows(USBException.class, () -> device.releaseInterface(LOOPBACK_INTF)); + assertThrows(USBException.class, () -> device.claimInterface(interfaceNumber)); + assertThrows(USBException.class, () -> device.releaseInterface(interfaceNumber)); device.open(); assertTrue(device.isOpen()); assertFalse(intf.isClaimed()); assertThrows(USBException.class, () -> device.open()); - assertThrows(USBException.class, () -> device.releaseInterface(LOOPBACK_INTF)); + assertThrows(USBException.class, () -> device.releaseInterface(interfaceNumber)); - device.claimInterface(LOOPBACK_INTF); + device.claimInterface(interfaceNumber); assertTrue(device.isOpen()); assertTrue(intf.isClaimed()); assertThrows(USBException.class, () -> device.open()); - assertThrows(USBException.class, () -> device.claimInterface(LOOPBACK_INTF)); + assertThrows(USBException.class, () -> device.claimInterface(interfaceNumber)); - device.releaseInterface(LOOPBACK_INTF); + device.releaseInterface(interfaceNumber); assertTrue(device.isOpen()); assertFalse(intf.isClaimed()); assertThrows(USBException.class, () -> device.open()); - assertThrows(USBException.class, () -> device.releaseInterface(LOOPBACK_INTF)); + assertThrows(USBException.class, () -> device.releaseInterface(interfaceNumber)); device.close(); assertFalse(device.isOpen()); assertFalse(intf.isClaimed()); - assertThrows(USBException.class, () -> device.claimInterface(LOOPBACK_INTF)); - assertThrows(USBException.class, () -> device.releaseInterface(LOOPBACK_INTF)); + assertThrows(USBException.class, () -> device.claimInterface(interfaceNumber)); + assertThrows(USBException.class, () -> device.releaseInterface(interfaceNumber)); } @AfterEach diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java index cacd7dd9..e2d5326e 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java @@ -17,7 +17,7 @@ public class InvalidOperationTest extends TestDeviceBase { @Test void claimInvalidInterface_throws() { // throws error because it's already claimed - Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(LOOPBACK_INTF)); + Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(interfaceNumber)); // throws error because it's an invalid interface number Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(3)); // throws error because it's an invalid interface number diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index 75799ead..94275a5e 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -19,17 +19,35 @@ */ public class TestDeviceBase { /** - * Test device vendor ID + * Simple test device vendor ID */ - static final int VID = 0xcafe; + static final int VID_SIMPLE = 0xcafe; /** - * Test device product ID + * Simple test device product ID */ - static final int PID = 0xcea0; + static final int PID_SIMPLE = 0xceaf; /** - * Test device loopback interface number + * Simple test device loopback interface number */ - static final int LOOPBACK_INTF = 2; + static final int LOOPBACK_INTF_SIMPLE = 0; + /** + * Composite test device vendor ID + */ + static final int VID_COMPOSITE = 0xcafe; + /** + * Composite test device product ID + */ + static final int PID_COMPOSITE = 0xcea0; + /** + * Composite test device loopback interface number + */ + static final int LOOPBACK_INTF_COMPOSITE = 2; + /** + * Interface number of connected test device + */ + protected static int vid = -1; + protected static int pid = -1; + protected static int interfaceNumber = -1; protected static final int LOOPBACK_EP_OUT = 1; protected static final int LOOPBACK_EP_IN = 2; protected static final int LOOPBACK_MAX_PACKET_SIZE = 64; @@ -38,13 +56,28 @@ public class TestDeviceBase { protected static final int ECHO_MAX_PACKET_SIZE = 16; protected static USBDevice testDevice; + static USBDevice getDevice() { + var device = USB.getDevice(new USBDeviceFilter(VID_COMPOSITE, PID_COMPOSITE)); + if (device == null) + device = USB.getDevice(new USBDeviceFilter(VID_SIMPLE, PID_SIMPLE)); + if (device == null) + throw new IllegalStateException("No test device connected"); + return device; + } + + static int getInterfaceNumber(USBDevice device) { + return device.productId() == PID_COMPOSITE ? LOOPBACK_INTF_COMPOSITE : LOOPBACK_INTF_SIMPLE; + } + @BeforeAll static void openDevice() { - testDevice = USB.getDevice(new USBDeviceFilter(VID, PID)); - if (testDevice == null) - throw new IllegalStateException("USB loopback test device must be connected"); + testDevice = getDevice(); + vid = testDevice.vendorId(); + pid = testDevice.productId(); + interfaceNumber = getInterfaceNumber(testDevice); + testDevice.open(); - testDevice.claimInterface(LOOPBACK_INTF); + testDevice.claimInterface(interfaceNumber); } @AfterAll From 1a6b86eed0cb1058f520bc495aeeaad50f5c5831 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 12 Sep 2022 23:04:38 +0200 Subject: [PATCH 084/433] Update README to reflect progress --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f454a859..1f75e7f3 100644 --- a/README.md +++ b/README.md @@ -55,12 +55,13 @@ MAVEN_OPTS="--enable-preview --enable-native-access=ALL-UNNAMED" mvn install exe - Interrupt transfer - Notifications about connected/disconnected devices - Descriptive information about interfaces, settings and endpoints +- Support fo composite devices ### To do -- Isochronous transfer - Alternate interface settings -- Composite devices (on Windows) +- Support for associated interfaces +- Isochronous transfer - Generate and publish JavaDoc documentation - Make library available on Maven Central @@ -81,7 +82,7 @@ No special considerations apply. Using this library, a Java application can conn ### Linux -*libudev* is used to discover and monitor USB devices. The library is closely tied to *systemd*. So it only runs on Linux distributions with systemd and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfill this requriement. +*libudev* is used to discover and monitor USB devices. The library is closely tied to *systemd*. So it only runs on Linux distributions with systemd and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfill this requirement. Similar to macOS, a Java application can connect to any USB device and claim any interfaces that aren't claimed by an operating system driver or another application. @@ -102,7 +103,7 @@ The Windows driver model is more rigid than the ones of macOS or Linux. It's not USB devices can implement certain control requests to instruct Windows to automatically install the WinUSB driver (search for WCID or Microsoft OS Compatibility Descriptors). The driver can also be manually installed or replaced using a software called [Zadig](https://zadig.akeo.ie/). -The test device implements the required control requests. So the driver is installed automatically. +The test devices implement the required control requests. So the driver is installed automatically. This library does not yet run reliably on Windows as the Java VM sometimes overwrites the last error code, which is needed for proper function, not just in error cases. It works incorrectly when run in the debugger and sometimes even without the debugger. A future version of the Foreign Function & Memory API will hopefully provide a way to save the last error code. The developers are aware of the issue. From 46a36ed627d7ee23abcaef3b09ac477ef22f7b10 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Tue, 13 Sep 2022 20:58:30 +0200 Subject: [PATCH 085/433] Increase version to 0.3.0 --- examples/bulk_transfer/pom.xml | 4 ++-- examples/enumerate/pom.xml | 4 ++-- examples/monitor/pom.xml | 4 ++-- java-does-usb/pom.xml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index 5c5ab600..30ae7f23 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples bulk-transfer - 0.3-SNAPSHOT + 0.3.0 bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.3-SNAPSHOT + 0.3.0 diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index 6a93f49c..2e254974 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples enumerate - 0.3-SNAPSHOT + 0.3.0 enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.3-SNAPSHOT + 0.3.0 diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index 44d91804..6f0f8e1a 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples monitor - 0.3-SNAPSHOT + 0.3.0 monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.3-SNAPSHOT + 0.3.0 diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 3a3bc066..8cd36970 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 0.3-SNAPSHOT + 0.3.0 19 From 27e3ac23f8e0092612f139bd4440412c9ec71acc Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Tue, 13 Sep 2022 21:27:17 +0200 Subject: [PATCH 086/433] Fix sontatype server name --- java-does-usb/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 8cd36970..723bbc75 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -100,11 +100,11 @@ ossrh - https://s01.oss.sonatype.org/content/repositories/snapshots + https://oss.sonatype.org/content/repositories/snapshots ossrh - https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ + https://oss.sonatype.org/service/local/staging/deploy/maven2/ From c2a392dbb135c5e3a8321f991b106ea3cfca6e2e Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Tue, 13 Sep 2022 22:02:42 +0200 Subject: [PATCH 087/433] Simplify maven file --- java-does-usb/pom.xml | 95 ++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 59 deletions(-) diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 723bbc75..5b6c4ace 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -38,65 +38,6 @@ https://github.com/manuelbl/JavaDoesUSB - - - release - - - performRelease - true - - - - - - org.apache.maven.plugins - maven-gpg-plugin - 3.0.1 - - - sign-artifacts - verify - - sign - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.3.0 - - - attach-javadocs - - jar - - - - - ${java.home}/bin/javadoc - - - - org.apache.maven.plugins - maven-source-plugin - 3.2.1 - - - attach-sources - - jar-no-fork - - - - - - - - - ossrh @@ -133,11 +74,47 @@ org.apache.maven.plugins maven-javadoc-plugin 3.4.1 + + + attach-javadocs + + jar + + + 19 --enable-preview + ${java.home}/bin/javadoc + + org.apache.maven.plugins + maven-gpg-plugin + 3.0.1 + + + sign-artifacts + verify + + sign + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.1 + + + attach-sources + + jar-no-fork + + + + From 3ffb3ae9f7d0bcfe49e7da9b8242593eaf3796b8 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Tue, 13 Sep 2022 22:14:10 +0200 Subject: [PATCH 088/433] Mention Javadoc documentation --- README.md | 80 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 1f75e7f3..d9c84c38 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Java Does USB: USB library for Java +[![javadoc](https://javadoc.io/badge2/net.codecrete.usb/java-does-usb/javadoc.svg)](https://javadoc.io/doc/net.codecrete.usb/java-does-usb) + *Java Does USB* is a library for working with USB devices from Java. It allows to query information about all conntected USB devices and to communicate with USB devices using custom / vendor specific protocols. (It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc.) The library uses the [Foreign Function & Memory API](https://github.com/openjdk/panama-foreign) to access native APIs of the underlying operating system. It only uses Java code and does not need JNI or any native third-party library. @@ -15,34 +17,6 @@ The Foreign Function & Memory API (aka as project Panama) is in preview and will It has been tested with Azul Zulu 19.0.77 EA 34. -## Testing - -In order to run the unit tests, a special test device must be connected to the computer. See the [loopback-stm32](test-devices/loopback-stm32) directory. - -Tests can be run from the command line: - -``` -mvn clean test -``` - -If they are run from an IDE (such as IntelliJ IDEA), you must likely configure VM options to enable preview features and allow native access: - -``` ---enable-preview --enable-native-access=net.codecrete.usb -``` - -Or (if modules are ignored): - -``` ---enable-preview --enable-native-access=ALL-UNNAMED -``` - -If you don't have the test device, you can get a glimpse at the library running the below command. It enumerates all connected USB devices. - -``` -MAVEN_OPTS="--enable-preview --enable-native-access=ALL-UNNAMED" mvn install exec:java -Dexec.classpathScope="test" -DskipTests -Dexec.mainClass="net.codecrete.usb.sample.EnumerateDevices" -``` - ## Features @@ -50,20 +24,17 @@ MAVEN_OPTS="--enable-preview --enable-native-access=ALL-UNNAMED" mvn install exe - Single API for all operating systems (similar to WebUSB API) - Enumeration of USB devices -- Control transfer -- Bulk transfer -- Interrupt transfer +- Control, bulk and interrupt transfer - Notifications about connected/disconnected devices - Descriptive information about interfaces, settings and endpoints - Support fo composite devices +- Published on Maven Central ### To do - Alternate interface settings - Support for associated interfaces - Isochronous transfer -- Generate and publish JavaDoc documentation -- Make library available on Maven Central ### Not planned @@ -82,7 +53,7 @@ No special considerations apply. Using this library, a Java application can conn ### Linux -*libudev* is used to discover and monitor USB devices. The library is closely tied to *systemd*. So it only runs on Linux distributions with systemd and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfill this requirement. +*libudev* is used to discover and monitor USB devices. It is closely tied to *systemd*. So the library only runs on Linux distributions with *systemd* and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfill this requirement. Similar to macOS, a Java application can connect to any USB device and claim any interfaces that aren't claimed by an operating system driver or another application. @@ -116,9 +87,10 @@ The Foreign Function & Memory API has not been implemented for 32-bit operating -## Code generation +## Documentation + +- [Javadoc](https://javadoc.io/doc/net.codecrete.usb/java-does-usb) -Many of the bindings for the native APIs have been generated with *jextract*. See the [jextract](java-does-usb/jextract) subdirectory for more information. ## Examples @@ -126,3 +98,39 @@ Many of the bindings for the native APIs have been generated with *jextract*. Se - [Bulk Transfer](examples/bulk_transfer/) demonstrates how to find a USB device, open it and communicate using bulk transfer. - [Enumeration](examples/enumerate/) lists all connected USB devices and displays information about interfaces and endpoints. - [Monitor](examples/monitor/) lists the connected USB devices and then monitors for USB devices being connected and disconnnected. + + + +## Code generation + +Many bindings for the native APIs have been generated with *jextract*. See the [jextract](java-does-usb/jextract) subdirectory for more information. + + + +## Testing + +In order to run the unit tests, a special test device must be connected to the computer. See the [loopback-stm32](test-devices/loopback-stm32) directory. + +Tests can be run from the command line: + +``` +mvn clean test +``` + +If they are run from an IDE (such as IntelliJ IDEA), you must likely configure VM options to enable preview features and allow native access: + +``` +--enable-preview --enable-native-access=net.codecrete.usb +``` + +Or (if modules are ignored): + +``` +--enable-preview --enable-native-access=ALL-UNNAMED +``` + +If you don't have the test device, you can get a glimpse at the library running the below command. It enumerates all connected USB devices. + +``` +MAVEN_OPTS="--enable-preview --enable-native-access=ALL-UNNAMED" mvn install exec:java -Dexec.classpathScope="test" -DskipTests -Dexec.mainClass="net.codecrete.usb.sample.EnumerateDevices" +``` From ff576ce2c54749a0aac9a24a3f1ef4c0f3a05843 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Wed, 14 Sep 2022 19:09:57 +0200 Subject: [PATCH 089/433] Minor code cleanup --- .../src/main/java/net/codecrete/usb/macos/IoKitUSB.java | 2 -- .../java/net/codecrete/usb/macos/MacosUSBDevice.java | 2 +- .../java/net/codecrete/usb/windows/WindowsUSBDevice.java | 2 +- .../java/net/codecrete/usb/sample/MonitorDevices.java | 9 ++++----- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index de4e7d22..4ac6d155 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -10,7 +10,6 @@ import net.codecrete.usb.macos.gen.iokit.IOUSBDeviceInterface; import net.codecrete.usb.macos.gen.iokit.IOUSBInterfaceInterface; -import java.lang.foreign.Linker; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; @@ -21,7 +20,6 @@ * Helper functions to call the virtual methods of IOKit USB interfaces. */ public class IoKitUSB { - private static final Linker linker = Linker.nativeLinker(); private static MemorySegment getVtable(MemoryAddress self, MemorySession session) { var object = MemorySegment.ofAddress(self, ADDRESS.byteSize(), session); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 33bbe34d..af2b69fb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -290,7 +290,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { int ret = IoKitUSB.DeviceRequest(device, deviceRequest.address()); if (ret != 0) throw new MacosUSBException("Control IN transfer failed", ret); - int lenDone = (int) IOUSBDevRequest.wLenDone$get(deviceRequest); + int lenDone = IOUSBDevRequest.wLenDone$get(deviceRequest); return data.asSlice(0, lenDone).toArray(JAVA_BYTE); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 8f201719..f4fa3c7a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -80,7 +80,7 @@ private CompositeFunction findAnyOpenFunction() { private CompositeFunction findControlTransferFunction(USBControlTransfer setup) { int interfaceNumber = -1; - int endpointNumber = -1; + int endpointNumber; if (setup.recipient() == USBRecipient.INTERFACE) { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java b/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java index 3423ae4b..fa27dd40 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java @@ -9,6 +9,8 @@ import net.codecrete.usb.USB; +import java.io.IOException; + /** * Sample program displaying information when USB devices are connected or disconnected. *

@@ -17,7 +19,7 @@ */ public class MonitorDevices { - public static void main(String[] args) throws InterruptedException { + public static void main(String[] args) throws IOException { USB.setOnDeviceConnected((device) -> System.out.println("Connected: " + device.toString())); USB.setOnDeviceDisconnected((device) -> System.out.println("Disconnected: " + device.toString())); @@ -25,9 +27,6 @@ public static void main(String[] args) throws InterruptedException { System.out.println("Present: " + device.toString()); System.out.println("Monitoring..."); - //noinspection InfiniteLoopStatement - while (true) { - Thread.sleep(1000000); - } + System.in.read(); } } From 6906f4ef98009ab543763903142888a425a0992b Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Wed, 14 Sep 2022 22:45:21 +0200 Subject: [PATCH 090/433] Add USB and device version --- README.md | 2 + .../java/net/codecrete/usb/USBDevice.java | 32 ++++++++++-- .../main/java/net/codecrete/usb/Version.java | 52 +++++++++++++++++++ .../codecrete/usb/common/USBDescriptors.java | 28 ++++++---- .../codecrete/usb/common/USBDeviceImpl.java | 13 +++++ .../codecrete/usb/linux/LinuxUSBDevice.java | 6 ++- .../usb/macos/MacosUSBDeviceRegistry.java | 5 ++ .../usb/windows/WindowsUSBDeviceRegistry.java | 4 ++ .../net/codecrete/usb/DescriptionTest.java | 16 ++++-- .../codecrete/usb/sample/MonitorDevices.java | 1 + 10 files changed, 143 insertions(+), 16 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/Version.java diff --git a/README.md b/README.md index d9c84c38..e6a1f4f9 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,8 @@ It has been tested with Azul Zulu 19.0.77 EA 34. ### To do +- Transfers with time-out +- Device and USB protocol revision - Alternate interface settings - Support for associated interfaces - Isochronous transfer diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index 0ce00a1e..5b664945 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -83,6 +83,20 @@ public interface USBDevice { */ int protocolCode(); + /** + * USB protocol version supported by this device. + * + * @return version + */ + Version usbVersion(); + + /** + * Device version (as declared by the manufacturer). + * + * @return version + */ + Version deviceVersion(); + /** * Opens the device for communication. */ @@ -130,6 +144,12 @@ public interface USBDevice { * The control transfer request is sent to endpoint 0. The transfer is expected to * have a Data In stage. *

+ *

+ * Requests with an interface or an endpoint as recipient are expected to + * have the interface and endpoint number, respectively, in the lower byte of + * {@code wIndex}. This convention is enforced by Windows. The addressed interface + * or the interface of the addressed endpoint must have been claimed. + *

* * @param setup control transfer setup parameters * @param length maximum length of expected data @@ -146,6 +166,12 @@ public interface USBDevice { * The control transfer request is sent to endpoint 0. The transfer is expected to either have * no data stage or a Data Out stage. *

+ *

+ * Requests with an interface or an endpoint as recipient are expected to + * have the interface and endpoint number, respectively, in the lower byte of + * {@code wIndex}. This convention is enforced by Windows. The addressed interface + * or the interface of the addressed endpoint must have been claimed. + *

* * @param setup control transfer setup parameters * @param data data to send, or {@code null} if the transfer has no data stage. @@ -158,7 +184,7 @@ public interface USBDevice { * This method blocks until the data has been sent or an error has occurred. *

*

- * This method is suitable for bulk and interrupt endpoints. + * This method can send data to bulk and interrupt endpoints. *

* * @param endpointNumber endpoint number (in the range between 1 and 127) @@ -167,13 +193,13 @@ public interface USBDevice { void transferOut(int endpointNumber, byte[] data); /** - * Receives data to this device. + * Receives data from this device. *

* This method blocks until at least a packet has been received or an error has occurred. * The minimum value for {@code maxLength} is the maximum size of packets sent on the endpoint. *

*

- * This method is suitable for bulk and interrupt endpoints. + * This method can receive data from bulk and interrupt endpoints. *

* * @param endpointNumber endpoint number (in the range between 1 and 127, i.e. without the direction bit) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/Version.java b/java-does-usb/src/main/java/net/codecrete/usb/Version.java new file mode 100644 index 00000000..dc4a314d --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/Version.java @@ -0,0 +1,52 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb; + +/** + * Semantic version number. + */ +public final class Version { + + private final int bcdVersion; + + public Version(int bcdVersion) { + this.bcdVersion = bcdVersion; + } + + public int major() { + return bcdVersion >> 8; + } + + public int minor() { + return (bcdVersion >> 4) & 0x0f; + } + + public int subminor() { + return bcdVersion & 0x0f; + } + + @Override + public String toString() { + return String.format("%d.%d.%d", major(), minor(), subminor()); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Version version = (Version) o; + return bcdVersion == version.bcdVersion; + } + + @Override + public int hashCode() { + return bcdVersion; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java index ea8d5d45..2ead6d77 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java @@ -59,23 +59,33 @@ public class USBDescriptors { // UCHAR iSerialNumber; // UCHAR bNumConfigurations; //} __attribute__((packed)); - public static final GroupLayout Device$Struct = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( - "bDescriptorType"), JAVA_SHORT.withName("bcdUSB"), JAVA_BYTE.withName("bDeviceClass"), - JAVA_BYTE.withName("bDeviceSubClass"), JAVA_BYTE.withName("bDeviceProtocol"), JAVA_BYTE.withName( - "bMaxPacketSize0"), JAVA_SHORT.withName("idVendor"), JAVA_SHORT.withName("idProduct"), - JAVA_SHORT.withName("bcdDevice"), JAVA_BYTE.withName("iManufacturer"), JAVA_BYTE.withName("iProduct"), - JAVA_BYTE.withName("iSerialNumber"), JAVA_BYTE.withName("bNumConfigurations")); - + public static final GroupLayout Device$Struct = structLayout( + JAVA_BYTE.withName("bLength"), + JAVA_BYTE.withName("bDescriptorType"), + JAVA_SHORT.withName("bcdUSB"), + JAVA_BYTE.withName("bDeviceClass"), + JAVA_BYTE.withName("bDeviceSubClass"), + JAVA_BYTE.withName("bDeviceProtocol"), + JAVA_BYTE.withName("bMaxPacketSize0"), + JAVA_SHORT.withName("idVendor"), + JAVA_SHORT.withName("idProduct"), + JAVA_SHORT.withName("bcdDevice"), + JAVA_BYTE.withName("iManufacturer"), + JAVA_BYTE.withName("iProduct"), + JAVA_BYTE.withName("iSerialNumber"), + JAVA_BYTE.withName("bNumConfigurations") + ); + + public static final VarHandle Device_bcdUSB = Device$Struct.varHandle(groupElement("bcdUSB")); public static final VarHandle Device_bDeviceClass = Device$Struct.varHandle(groupElement("bDeviceClass")); public static final VarHandle Device_bDeviceSubClass = Device$Struct.varHandle(groupElement("bDeviceSubClass")); public static final VarHandle Device_bDeviceProtocol = Device$Struct.varHandle(groupElement("bDeviceProtocol")); public static final VarHandle Device_idVendor = Device$Struct.varHandle(groupElement("idVendor")); public static final VarHandle Device_idProduct = Device$Struct.varHandle(groupElement("idProduct")); + public static final VarHandle Device_bcdDevice = Device$Struct.varHandle(groupElement("bcdDevice")); public static final VarHandle Device_iManufacturer = Device$Struct.varHandle(groupElement("iManufacturer")); public static final VarHandle Device_iProduct = Device$Struct.varHandle(groupElement("iProduct")); public static final VarHandle Device_iSerialNumber = Device$Struct.varHandle(groupElement("iSerialNumber")); - public static final VarHandle Device_bNumConfigurations = Device$Struct.varHandle(groupElement( - "bNumConfigurations")); // struct USBConfigurationDescriptor //{ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 86240667..8eb1446b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -23,6 +23,8 @@ public abstract class USBDeviceImpl implements USBDevice { protected int classCode_; protected int subclassCode_; protected int protocolCode_; + protected Version usbVersion_; + protected Version deviceVersion_; protected List interfaces_; @@ -103,6 +105,12 @@ public int protocolCode() { return protocolCode_; } + @Override + public Version usbVersion() { return usbVersion_; } + + @Override + public Version deviceVersion() { return deviceVersion_; } + public Object getUniqueId() { return id_; } @@ -113,6 +121,11 @@ public void setClassCodes(int classCode, int subclassCode, int protocolCode) { protocolCode_ = protocolCode; } + public void setVersions(int usbVersion, int deviceVersion) { + usbVersion_ = new Version(usbVersion); + deviceVersion_ = new Version(deviceVersion); + } + @Override public List interfaces() { return Collections.unmodifiableList(interfaces_); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 2da40535..fcae2330 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -53,7 +53,7 @@ private void loadDescription(String path) { try (var session = MemorySession.openConfined()) { var descriptorsSegment = MemorySegment.ofArray(descriptors); - // isolate device descriptor (copy descriptor to fix alignment issues) + // separate device descriptor (and copy it to fix alignment issues) var deviceDesc = session.allocate(USBDescriptors.Device$Struct); deviceDesc.copyFrom(descriptorsSegment.asSlice(0, USBDescriptors.Device$Struct.byteSize())); @@ -62,6 +62,10 @@ private void loadDescription(String path) { int protocolCode = 255 & (byte) USBDescriptors.Device_bDeviceProtocol.get(deviceDesc); setClassCodes(classCode, subclassCode, protocolCode); + var usbVersion = (short) USBDescriptors.Device_bcdUSB.get(deviceDesc); + var deviceVersion = (short) USBDescriptors.Device_bcdDevice.get(deviceDesc); + setVersions(usbVersion, deviceVersion); + // skip device descriptor var configDesc = session.allocateArray(JAVA_BYTE, descriptors.length - 18); configDesc.copyFrom(descriptorsSegment.asSlice(USBDescriptors.Device$Struct.byteSize())); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index ce5bb49e..dc8b5d75 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -163,6 +163,11 @@ private USBDevice createDevice(Long entryID, int service, MemoryAddress deviceIn device.setClassCodes(classCode != null ? classCode : 0, subclassCode != null ? subclassCode : 0, protocolCode != null ? protocolCode : 0); + Integer usbVersion = IoKitHelper.getPropertyInt(service, "bcdUSB"); + Integer deviceVersion = IoKitHelper.getPropertyInt(service, "bcdDevice"); + //noinspection ConstantConditions + device.setVersions(usbVersion, deviceVersion); + return device; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 90053454..c47a5c0e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -293,6 +293,10 @@ private USBDevice createDevice(String devicePath, List functi int protocolCode = 255 & (byte) USBDescriptors.Device_bDeviceProtocol.get(deviceDesc); device.setClassCodes(classCode, subclassCode, protocolCode); + var usbVersion = (short) USBDescriptors.Device_bcdUSB.get(deviceDesc); + var deviceVersion = (short) USBDescriptors.Device_bcdDevice.get(deviceDesc); + device.setVersions(usbVersion, deviceVersion); + return device; } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index 98755ce7..d30433b3 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -35,10 +35,20 @@ void deviceInfo_isCorrect() { assertEquals(0x00, testDevice.subclassCode()); assertEquals(0x00, testDevice.protocolCode()); } + + boolean isComposite = pid == TestDeviceBase.PID_COMPOSITE; + + assertEquals(2, testDevice.usbVersion().major()); + assertEquals(isComposite ? 1 : 0, testDevice.usbVersion().minor()); + assertEquals(0, testDevice.usbVersion().subminor()); + + assertEquals(0, testDevice.deviceVersion().major()); + assertEquals(isComposite ? 3 : 7, testDevice.deviceVersion().minor()); + assertEquals(isComposite ? 4 : 1, testDevice.deviceVersion().subminor()); } @Test - void interfaceDescriptors_isCorrect() { + void interfaceDescriptor_isCorrect() { assertNotNull(testDevice.interfaces()); assertEquals(interfaceNumber + 1, testDevice.interfaces().size()); @@ -49,7 +59,7 @@ void interfaceDescriptors_isCorrect() { } @Test - void alternateInterfaceDescriptors_isCorrect() { + void alternateInterfaceDescriptor_isCorrect() { var intf = testDevice.interfaces().get(interfaceNumber); var altIntf = intf.alternate(); assertNotNull(intf.alternates()); @@ -63,7 +73,7 @@ void alternateInterfaceDescriptors_isCorrect() { } @Test - void endpointDescriptors_isCorrect() { + void endpointDescriptors_areCorrect() { var altIntf = testDevice.interfaces().get(interfaceNumber).alternate(); assertNotNull(altIntf.endpoints()); assertEquals(4, altIntf.endpoints().size()); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java b/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java index fa27dd40..9f0c0df3 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java @@ -27,6 +27,7 @@ public static void main(String[] args) throws IOException { System.out.println("Present: " + device.toString()); System.out.println("Monitoring..."); + //noinspection ResultOfMethodCallIgnored System.in.read(); } } From 050740f327636ff4cf379f7d6a12a4dfd9cb537d Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 14 Sep 2022 23:33:30 +0200 Subject: [PATCH 091/433] Release device interface data --- java-does-usb/jextract/windows/gen_win.cmd | 1 + .../usb/windows/WindowsUSBDeviceRegistry.java | 6 +++++- .../codecrete/usb/windows/gen/setupapi/SetupAPI.java | 11 +++++++++++ .../usb/windows/gen/setupapi/constants$1.java | 8 ++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index d0b57daa..c69865d2 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -52,6 +52,7 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-function SetupDiCreateDeviceInfoList ^ --include-function SetupDiOpenDeviceInfoW ^ --include-function SetupDiOpenDevRegKey ^ + --include-function SetupDiDeleteDeviceInterfaceData ^ --include-struct _SP_DEVINFO_DATA ^ --include-typedef SP_DEVINFO_DATA ^ --include-struct _SP_DEVICE_INTERFACE_DATA ^ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index c47a5c0e..7aeaac09 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -418,10 +418,14 @@ private void onDeviceConnected(String devicePath) { SP_DEVINFO_DATA.cbSize$set(devInfo, (int) devInfo.byteSize()); if (SetupAPI.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, NULL, 0, NULL, devInfo) == 0) { int err = Kernel32.GetLastError(); - if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) + if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) { + SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSetHandle, devIntfData); throw new USBException("internal error (SetupDiGetDeviceInterfaceDetailW)", err); + } } + SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSetHandle, devIntfData); + // ensure all hubs are closed later final var hubHandles = new HashMap(); session.addCloseAction(() -> hubHandles.forEach((path, handle) -> Kernel32.CloseHandle(handle))); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java index e2ff0b66..f860b4ec 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java @@ -105,6 +105,17 @@ public static int SetupDiOpenDeviceInterfaceW ( Addressable DeviceInfoSet, Addr throw new AssertionError("should not reach here", ex$); } } + public static MethodHandle SetupDiDeleteDeviceInterfaceData$MH() { + return RuntimeHelper.requireNonNull(constants$1.SetupDiDeleteDeviceInterfaceData$MH,"SetupDiDeleteDeviceInterfaceData"); + } + public static int SetupDiDeleteDeviceInterfaceData ( Addressable DeviceInfoSet, Addressable DeviceInterfaceData) { + var mh$ = SetupDiDeleteDeviceInterfaceData$MH(); + try { + return (int)mh$.invokeExact(DeviceInfoSet, DeviceInterfaceData); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static MethodHandle SetupDiGetDeviceInterfaceDetailW$MH() { return RuntimeHelper.requireNonNull(constants$1.SetupDiGetDeviceInterfaceDetailW$MH,"SetupDiGetDeviceInterfaceDetailW"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java index 1aeac7c7..1cadf471 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java @@ -6,6 +6,14 @@ import java.lang.invoke.MethodHandle; class constants$1 { + static final FunctionDescriptor SetupDiDeleteDeviceInterfaceData$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle SetupDiDeleteDeviceInterfaceData$MH = RuntimeHelper.downcallHandle( + "SetupDiDeleteDeviceInterfaceData", + constants$1.SetupDiDeleteDeviceInterfaceData$FUNC + ); static final FunctionDescriptor SetupDiGetDeviceInterfaceDetailW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT, From 435e4b3941c790c0afb8936424b3d673e48e3f10 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 16 Sep 2022 19:53:07 +0200 Subject: [PATCH 092/433] Simplified cleanup related to closed memory segment --- .../codecrete/usb/common/ForeignMemory.java | 43 +++++++++++++++++++ .../usb/windows/WindowsUSBDeviceRegistry.java | 14 ++---- 2 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java new file mode 100644 index 00000000..be23291c --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java @@ -0,0 +1,43 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; +import java.util.function.Consumer; + +/** + * Helper functions for the foreign memory API. + */ +public class ForeignMemory { + + /** + * Adds a custom cleanup action which will be execution when the session of the + * specified memory segment ends. + *

+ * Note that the {@code segment}'s session will already be closed. The {@code segment} + * can no longer be used for function call. For that reason, the cleanup + * action is passed a copy of the segment (separate Java instance pointing to the + * same native memory). + *

+ * @param segment the segment to be accessed during the cleanup + * @param action the cleanup action + */ + public static void addCloseAction(MemorySegment segment, Consumer action) { + long size = segment.byteSize(); + MemoryAddress address = segment.address(); + Runnable closeAction = () -> { + try (MemorySession closingSession = MemorySession.openConfined()) { + MemorySegment dup = MemorySegment.ofAddress(address, size, closingSession); + action.accept(dup); + } + }; + segment.session().addCloseAction(closeAction); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 7aeaac09..702b83f6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -9,10 +9,7 @@ import net.codecrete.usb.USBDevice; import net.codecrete.usb.USBException; -import net.codecrete.usb.common.USBDescriptors; -import net.codecrete.usb.common.USBDeviceImpl; -import net.codecrete.usb.common.USBDeviceRegistry; -import net.codecrete.usb.common.USBStructs; +import net.codecrete.usb.common.*; import net.codecrete.usb.windows.gen.kernel32.GUID; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.ole32.Ole32; @@ -410,22 +407,19 @@ private void onDeviceConnected(String devicePath) { var devIntfData = session.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); var devicePathSegment = Win.createSegmentFromString(devicePath, session); - // TODO: Check if result needs to be freed if (SetupAPI.SetupDiOpenDeviceInterfaceW(devInfoSetHandle, devicePathSegment, 0, devIntfData) == 0) throw new WindowsUSBException("internal error (SetupDiOpenDeviceInterfaceW)", Kernel32.GetLastError()); + ForeignMemory.addCloseAction(devIntfData, (segment) -> SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSetHandle, segment)); + var devInfo = session.allocate(SP_DEVINFO_DATA.$LAYOUT()); SP_DEVINFO_DATA.cbSize$set(devInfo, (int) devInfo.byteSize()); if (SetupAPI.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, NULL, 0, NULL, devInfo) == 0) { int err = Kernel32.GetLastError(); - if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) { - SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSetHandle, devIntfData); + if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) throw new USBException("internal error (SetupDiGetDeviceInterfaceDetailW)", err); - } } - SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSetHandle, devIntfData); - // ensure all hubs are closed later final var hubHandles = new HashMap(); session.addCloseAction(() -> hubHandles.forEach((path, handle) -> Kernel32.CloseHandle(handle))); From ff4604cceaf882b23345d05187685b3dd9e20d50 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 16 Sep 2022 19:59:45 +0200 Subject: [PATCH 093/433] Minor cleanup (and more future-proof for JDK 20) --- .../main/java/net/codecrete/usb/common/ForeignMemory.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java index be23291c..8f3b53ed 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java @@ -7,7 +7,6 @@ package net.codecrete.usb.common; -import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; import java.util.function.Consumer; @@ -30,11 +29,11 @@ public class ForeignMemory { * @param action the cleanup action */ public static void addCloseAction(MemorySegment segment, Consumer action) { - long size = segment.byteSize(); - MemoryAddress address = segment.address(); + var size = segment.byteSize(); + var address = segment.address(); Runnable closeAction = () -> { try (MemorySession closingSession = MemorySession.openConfined()) { - MemorySegment dup = MemorySegment.ofAddress(address, size, closingSession); + var dup = MemorySegment.ofAddress(address, size, closingSession); action.accept(dup); } }; From 1f3929ce108a5b38d89079a6512084d609f431ef Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sun, 18 Sep 2022 13:36:47 +0200 Subject: [PATCH 094/433] MacOS reference code --- reference/README.md | 7 + reference/macos/.gitignore | 7 + reference/macos/USB/assertion.cpp | 56 +++ reference/macos/USB/assertion.hpp | 26 ++ reference/macos/USB/iokit_helper.cpp | 57 +++ reference/macos/USB/iokit_helper.hpp | 41 +++ reference/macos/USB/main.cpp | 15 + reference/macos/USB/scope.hpp | 52 +++ reference/macos/USB/tests.cpp | 161 +++++++++ reference/macos/USB/tests.hpp | 36 ++ reference/macos/USB/usb_device.cpp | 264 ++++++++++++++ reference/macos/USB/usb_device.hpp | 213 +++++++++++ reference/macos/USB/usb_error.cpp | 43 +++ reference/macos/USB/usb_error.hpp | 45 +++ reference/macos/USB/usb_registry.cpp | 184 ++++++++++ reference/macos/USB/usb_registry.hpp | 68 ++++ reference/macos/usb.xcodeproj/project.pbxproj | 336 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/xcschemes/USB.xcscheme | 80 +++++ 20 files changed, 1706 insertions(+) create mode 100644 reference/README.md create mode 100644 reference/macos/.gitignore create mode 100644 reference/macos/USB/assertion.cpp create mode 100644 reference/macos/USB/assertion.hpp create mode 100644 reference/macos/USB/iokit_helper.cpp create mode 100644 reference/macos/USB/iokit_helper.hpp create mode 100644 reference/macos/USB/main.cpp create mode 100644 reference/macos/USB/scope.hpp create mode 100644 reference/macos/USB/tests.cpp create mode 100644 reference/macos/USB/tests.hpp create mode 100644 reference/macos/USB/usb_device.cpp create mode 100644 reference/macos/USB/usb_device.hpp create mode 100644 reference/macos/USB/usb_error.cpp create mode 100644 reference/macos/USB/usb_error.hpp create mode 100644 reference/macos/USB/usb_registry.cpp create mode 100644 reference/macos/USB/usb_registry.hpp create mode 100644 reference/macos/usb.xcodeproj/project.pbxproj create mode 100644 reference/macos/usb.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 reference/macos/usb.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 reference/macos/usb.xcodeproj/xcshareddata/xcschemes/USB.xcscheme diff --git a/reference/README.md b/reference/README.md new file mode 100644 index 00000000..ad8937bc --- /dev/null +++ b/reference/README.md @@ -0,0 +1,7 @@ +# C++ Reference Code + +The C++ reference code is used to first implement the features before it is translated to Java code. It's easier to first write the code in C++ as better code completion, type checking etc. is available for the native APIs. + +The C++ code contains less error checking, less test cases and does not cover all features. + +- [MacOS](macos) (for use with Xcode) diff --git a/reference/macos/.gitignore b/reference/macos/.gitignore new file mode 100644 index 00000000..e0633855 --- /dev/null +++ b/reference/macos/.gitignore @@ -0,0 +1,7 @@ +## User settings +xcuserdata/ + +## Xcode 8 and earlier +*.xcscmblueprint +*.xccheckout + diff --git a/reference/macos/USB/assertion.cpp b/reference/macos/USB/assertion.cpp new file mode 100644 index 00000000..4e3111b5 --- /dev/null +++ b/reference/macos/USB/assertion.cpp @@ -0,0 +1,56 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "assertion.hpp" + +#include +#include + +static void failed(const char* check, const char* message) { + if (message == nullptr) + message = "Check failed"; + std::cerr << message << ": " << check << std::endl; + throw new check_failed_error(); +} + +void assert_equals(int expected, int actual, const char* message) { + if (actual != expected) { + char buf[50]; + snprintf(buf, sizeof(buf), "expected: %d, actual: %d", expected, actual); + failed(buf, message); + } +} + +void assert_equals(long expected, long actual, const char* message) { + if (actual != expected) { + char buf[50]; + snprintf(buf, sizeof(buf), "expected: %ld, actual: %ld", expected, actual); + failed(buf, message); + } +} + +void assert_equals(unsigned long expected, unsigned long actual, const char* message) { + if (actual != expected) { + char buf[50]; + snprintf(buf, sizeof(buf), "expected: %lud, actual: %lud", expected, actual); + failed(buf, message); + } +} + +void assert_equals(const std::vector& expected, const std::vector& actual, const char* message) { + assert_equals(expected.size(), actual.size(), message); + for (int i = 0; i < expected.size(); i++) { + assert_equals(expected[i], actual[i], message); + } +} + + +check_failed_error::check_failed_error() noexcept { } +check_failed_error::~check_failed_error() noexcept { } +const char* check_failed_error::what() const noexcept { return "check failed"; } diff --git a/reference/macos/USB/assertion.hpp b/reference/macos/USB/assertion.hpp new file mode 100644 index 00000000..09968407 --- /dev/null +++ b/reference/macos/USB/assertion.hpp @@ -0,0 +1,26 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include +#include + + +void assert_equals(int expected, int actual, const char* message = nullptr); +void assert_equals(long expected, long actual, const char* message = nullptr); +void assert_equals(unsigned long expected, unsigned long actual, const char* message = nullptr); +void assert_equals(const std::vector& expected, const std::vector& actual, const char* message = nullptr); + +class check_failed_error : public std::exception { +public: + check_failed_error() noexcept; + virtual ~check_failed_error() noexcept; + virtual const char* what() const noexcept; +}; diff --git a/reference/macos/USB/iokit_helper.cpp b/reference/macos/USB/iokit_helper.cpp new file mode 100644 index 00000000..49512179 --- /dev/null +++ b/reference/macos/USB/iokit_helper.cpp @@ -0,0 +1,57 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "iokit_helper.hpp" +#include "scope.hpp" + +#include + +std::string iokit_helper::string_from_cfstring(CFStringRef str) { + const char* cstr = CFStringGetCStringPtr(str, kCFStringEncodingUTF8); + if (cstr != nullptr) + return std::string(cstr); + + CFIndex len = CFStringGetLength(str) * 3 + 1; + std::string result(len, 0); + CFStringGetCString(str, &result[0], len, kCFStringEncodingUTF8); + len = strlen(result.c_str()); + result.resize(len); + + return result; +} + +std::string iokit_helper::ioreg_get_property_as_string(io_service_t service, CFStringRef property_name) { + CFTypeRef property = IORegistryEntryCreateCFProperty(service, property_name, nullptr, 0); + if (property == nullptr) + return std::string(); + + auto property_guard = make_scope_exit([&property]() { CFRelease(property); }); + + CFTypeID type = CFGetTypeID(property); + if (type != CFStringGetTypeID()) + return std::string(); + + return string_from_cfstring(static_cast(property)); +} + +int iokit_helper::ioreg_get_property_as_int(io_service_t service, CFStringRef property_name) { + CFTypeRef property = IORegistryEntryCreateCFProperty(service, property_name, nullptr, 0); + if (property == nullptr) + return 0; + + auto property_guard = make_scope_exit([&property]() { CFRelease(property); }); + + CFTypeID type = CFGetTypeID(property); + if (type != CFNumberGetTypeID()) + return 0; + + int value = 0; + CFNumberGetValue(static_cast(property), kCFNumberSInt32Type, &value); + return value; +} diff --git a/reference/macos/USB/iokit_helper.hpp b/reference/macos/USB/iokit_helper.hpp new file mode 100644 index 00000000..f69a4c56 --- /dev/null +++ b/reference/macos/USB/iokit_helper.hpp @@ -0,0 +1,41 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include +#include +#include + +class iokit_helper { +public: + template static T** get_interface(io_service_t service, CFUUIDRef plugin_type, CFUUIDRef interface_id); + + static std::string string_from_cfstring(CFStringRef str); + static std::string ioreg_get_property_as_string(io_service_t service, CFStringRef property_name); + static int ioreg_get_property_as_int(io_service_t service, CFStringRef property_name); +}; + +template T** iokit_helper::get_interface(io_service_t service, CFUUIDRef plugin_type, CFUUIDRef interface_id) { + + // get plug-in interface + IOCFPlugInInterface** plug = nullptr; + SInt32 score = 0; + kern_return_t kret = IOCreatePlugInInterfaceForService(service, plugin_type, kIOCFPlugInInterfaceID, &plug, &score); + if (kret != kIOReturnSuccess) + return nullptr; + + auto plug_guard = make_scope_exit([&plug]() { (*plug)->Release(plug); }); + + // Get requested interface + T** intf = nullptr; + (*plug)->QueryInterface(plug, CFUUIDGetUUIDBytes(interface_id), (void**)&intf); + return intf; +} + diff --git a/reference/macos/USB/main.cpp b/reference/macos/USB/main.cpp new file mode 100644 index 00000000..64e85de5 --- /dev/null +++ b/reference/macos/USB/main.cpp @@ -0,0 +1,15 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "tests.hpp" + +int main(int argc, const char * argv[]) { + tests t; + t.run(); +} diff --git a/reference/macos/USB/scope.hpp b/reference/macos/USB/scope.hpp new file mode 100644 index 00000000..53e3e39f --- /dev/null +++ b/reference/macos/USB/scope.hpp @@ -0,0 +1,52 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include + +template +class scope_exit +{ +public: + template + explicit scope_exit(Fn&& fn) noexcept + : exit_fn(std::forward(fn)), exec_on_destruction(true) + { } + + scope_exit(scope_exit&& other) noexcept + : exit_fn(std::forward(other.exit_fn)), + exec_on_destruction(other.exec_on_destruction) + { + other.release(); + } + + ~scope_exit() noexcept { + if (exec_on_destruction) + exit_fn(); + } + + void release() noexcept { + exec_on_destruction = false; + } + + scope_exit(scope_exit const&) = delete; + + scope_exit& operator=(scope_exit const&) = delete; + scope_exit& operator=(scope_exit&&) = delete; + +private: + EF exit_fn; + bool exec_on_destruction; +}; + +template +scope_exit::type> make_scope_exit(EF&& exit_function) { + return scope_exit::type>(std::forward(exit_function)); +} diff --git a/reference/macos/USB/tests.cpp b/reference/macos/USB/tests.cpp new file mode 100644 index 00000000..b16dbc80 --- /dev/null +++ b/reference/macos/USB/tests.cpp @@ -0,0 +1,161 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "tests.hpp" +#include "assertion.hpp" + +#include +#include + +using random_bytes_engine = std::independent_bits_engine< + std::default_random_engine, CHAR_BIT, unsigned char>; + + +void tests::run() { + registry.start(); + + for (auto device : registry.get_devices()) { + std::cout << "Present: " << device->description() << std::endl; + } + + registry.set_on_device_connected([this](auto device) { on_device_connected(device); }); + registry.set_on_device_disconnected([this](auto device) { on_device_disconnected(device); }); + + for (auto device : registry.get_devices()) + on_device(device); + + std::cout << "Press RETURN to quit" << std::endl; + std::string line; + std::getline(std::cin, line); +} + +void tests::test_current_device() { + std::cout << "Found test device" << std::endl; + test_device->open(); + test_device->claim_interface(0); + + test_control_transfers(); + test_bulk_transfers(); + + test_device->release_interface(); + test_device->close(); + std::cout << "Test completed" << std::endl; +} + +void tests::test_control_transfers() { + usb_control_request request_set_value_no_data = { + .bmRequestType = usb_control_request::request_type(usb_request_type::direction_out, + usb_request_type::type_vendor, + usb_request_type::recipient_interface), + .bRequest = 0x01, + .wValue = 0x9a41, + .wIndex = 0, // interface number + .wLength = 0 + }; + test_device->control_transfer(request_set_value_no_data); + + usb_control_request request_get_data = { + .bmRequestType = usb_control_request::request_type(usb_request_type::direction_in, + usb_request_type::type_vendor, + usb_request_type::recipient_interface), + .bRequest = 0x03, + .wValue = 0, + .wIndex = 0, // interface number + .wLength = 4 + }; + auto data = test_device->control_transfer_in(request_get_data); + std::vector expected_data{ 0x41, 0x9a, 0x00, 0x00 }; + assert_equals(expected_data, data); + + std::vector sent_value{ 0x83, 0x03, 0xda, 0x3d }; + usb_control_request request_set_value_data = { + .bmRequestType = usb_control_request::request_type(usb_request_type::direction_out, + usb_request_type::type_vendor, + usb_request_type::recipient_interface), + .bRequest = 0x02, + .wValue = 0, + .wIndex = 0, // interface number + .wLength = static_cast(sent_value.size()) + }; + test_device->control_transfer_out(request_set_value_data, sent_value); + + data = test_device->control_transfer_in(request_get_data); + assert_equals(sent_value, data); +} + +void tests::test_bulk_transfers() { + test_loopback(12); + test_loopback(130); + test_loopback(123709); +} + +void tests::test_loopback(int num_bytes) { + + // generate random bytes + auto random_data = random_bytes(num_bytes); + + // prepare vector for receiving data + std::vector rx_data; + rx_data.reserve(num_bytes); + + // read in separate thread + std::thread reader([this, &rx_data, num_bytes]() { + int bytes_read = 0; + while (bytes_read < num_bytes) { + auto data = test_device->transfer_in(2, 64); + rx_data.insert(rx_data.end(), data.begin(), data.end()); + bytes_read += data.size(); + } + }); + + // send rand bytes in chunks + const int chunk_size = 100; + int bytes_written = 0; + while (bytes_written < num_bytes) { + int size = std::min(chunk_size, num_bytes - bytes_written); + std::vector chunk = {random_data.begin() + bytes_written, random_data.begin() + bytes_written + size}; + test_device->transfer_out(1, chunk); + bytes_written += size; + } + + // wait for reader + reader.join(); + + // check result + assert_equals(random_data, rx_data); +} + +void tests::on_device(usb_device_ptr device) { + if (is_test_device(device)) { + test_device = device; + test_current_device(); + test_device = nullptr; + } +} + +void tests::on_device_connected(usb_device_ptr device) { + std::cout << "Connected: " << device->description() << std::endl; + on_device(device); +} + +void tests::on_device_disconnected(usb_device_ptr device) { + std::cout << "Disconnected: " << device->description() << std::endl; +} + +std::vector tests::random_bytes(int num) { + random_bytes_engine rbe; + std::vector data(num); + std::generate(begin(data), end(data), std::ref(rbe)); + return data; +} + + +bool tests::is_test_device(usb_device_ptr device) { + return device->vendor_id() == 0xcafe && device->product_id() == 0xceaf; +} diff --git a/reference/macos/USB/tests.hpp b/reference/macos/USB/tests.hpp new file mode 100644 index 00000000..992de2b9 --- /dev/null +++ b/reference/macos/USB/tests.hpp @@ -0,0 +1,36 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include "usb_device.hpp" +#include "usb_registry.hpp" + +class tests { +public: + void run(); + +private: + void test_current_device(); + void test_control_transfers(); + void test_bulk_transfers(); + + void test_loopback(int num_bytes); + + void on_device(usb_device_ptr device); + void on_device_connected(usb_device_ptr device); + void on_device_disconnected(usb_device_ptr device); + + static std::vector random_bytes(int num); + static bool is_test_device(usb_device_ptr device); + + usb_device_ptr test_device; + usb_registry registry; +}; + diff --git a/reference/macos/USB/usb_device.cpp b/reference/macos/USB/usb_device.cpp new file mode 100644 index 00000000..1c6c7f83 --- /dev/null +++ b/reference/macos/USB/usb_device.cpp @@ -0,0 +1,264 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "usb_device.hpp" +#include "usb_error.hpp" +#include "scope.hpp" +#include "iokit_helper.hpp" + +#include + +#include + +usb_device::usb_device(io_service_t service, IOUSBDeviceInterface** device, uint64_t entry_id, int vendor_id, int product_id) +: entry_id_(entry_id), device_(device), interface_(nullptr), vendor_id_(vendor_id), product_id_(product_id), is_open_(false) { + + (*device)->AddRef(device); + + manufacturer_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBVendorString)); + product_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBProductString)); + serial_number_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBSerialNumberString)); +} + +usb_device::~usb_device() { + close(); +} + +std::string usb_device::description() const { + + const char* fmt = "VID: 0x%04x, PID: 0x%04x, manufacturer: %s, product: %s, serial: %s"; + int len = snprintf(nullptr, 0, fmt, + vendor_id_, product_id_, manufacturer_.c_str(), product_.c_str(), serial_number_.c_str()); + std::string desc; + desc.resize(len + 1); + + snprintf(&desc[0], desc.size(), fmt, + vendor_id_, product_id_, manufacturer_.c_str(), product_.c_str(), serial_number_.c_str()); + + return desc; +} + +bool usb_device::is_open() const { + return is_open_; +} + +void usb_device::open() { + if (is_open()) + throw new usb_error("USB device is already open", 0); + + IOReturn ret = (*device_)->USBDeviceOpen(device_); + usb_error::check(ret, "unable to open USB device"); + + ret = (*device_)->SetConfiguration(device_, 1); + usb_error::check(ret, "failed to set USB device configuration"); + + is_open_ = true; +} + +void usb_device::close() { + if (!is_open()) + return; + + IOReturn ret = (*device_)->USBDeviceClose(device_); + if (ret != kIOReturnSuccess) + throw usb_error("unable to close USB device", ret); + + is_open_ = false; +} + +void usb_device::claim_interface(int interface_number) { + + if (interface_ != nullptr) + throw usb_error("an interface has already been claimed"); + + // find interface + IOUSBFindInterfaceRequest request; + request.bInterfaceClass = kIOUSBFindInterfaceDontCare; + request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; + request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; + request.bAlternateSetting = kIOUSBFindInterfaceDontCare; + + io_iterator_t iter; + IOReturn ret = (*device_)->CreateInterfaceIterator(device_, &request, &iter); + usb_error::check(ret, "internal error (CreateInterfaceIterator)"); + auto iter_guard = make_scope_exit([iter]() { IOObjectRelease(iter); }); + + io_service_t service; + IOUSBInterfaceInterface** interface = nullptr; + while ((service = IOIteratorNext(iter)) != 0) { + + auto service_guard = make_scope_exit([service]() { IOObjectRelease(service); }); + + IOUSBInterfaceInterface** intf = iokit_helper::get_interface(service, kIOUSBInterfaceUserClientTypeID, kIOUSBInterfaceInterfaceID); + if (intf == nullptr) + throw usb_error("internal error (failed to create interface interface)"); + + auto intf_guard = make_scope_exit([intf]() { (*intf)->Release(intf); }); + + UInt8 num; + ret = (*intf)->GetInterfaceNumber(intf, &num); + usb_error::check(ret, "internal error (GetInterfaceNumber)"); + + if (interface_number == num) { + interface = intf; + (*interface)->AddRef(interface); + break; + } + } + + if (interface == nullptr) + throw usb_error("no USB interface found for given number"); + + auto interface_guard = make_scope_exit([interface]() { (*interface)->Release(interface); }); + + ret = (*interface)->USBInterfaceOpen(interface); + usb_error::check(ret, "failed to open USB interface"); + + UInt8 num_pipes = 0; + ret = (*interface)->GetNumEndpoints(interface, &num_pipes); + usb_error::check(ret, "internal error (GetNumEndpoints)"); + + endpoint_addresses_.clear(); + for (int i = 1; i <= num_pipes; i++) { + UInt8 direction = 0; + UInt8 number = 0; + UInt8 ignore = 0; + UInt16 ignore2 = 0; + ret = (*interface)->GetPipeProperties(interface, i, &direction, &number, &ignore, &ignore2, &ignore); + usb_error::check(ret, "internal error (GetPipeProperties)"); + endpoint_addresses_.push_back((direction << 7) | number); + } + + interface_ = interface; + (*interface_)->AddRef(interface_); +} + +void usb_device::release_interface() { + if (interface_ == nullptr) + throw usb_error("no interface has been claimed"); + + (*interface_)->USBInterfaceClose(interface_); + (*interface_)->Release(interface_); + interface_ = nullptr; + endpoint_addresses_.clear(); +} + +std::vector usb_device::transfer_in(int endpoint_number, int data_len, int timeout) { + if (interface_ == nullptr) + throw usb_error("no interface has been claimed"); + + UInt32 size = data_len; + std::vector data(data_len); + IOReturn ret; + if (timeout != 0) + ret = (*interface_)->ReadPipeTO(interface_, ep_in_pipe(endpoint_number), data.data(), &size, timeout, timeout); + else + ret = (*interface_)->ReadPipe(interface_, ep_in_pipe(endpoint_number), data.data(), &size); + + if (ret != kIOReturnSuccess) { + if (ret == kIOUSBTransactionTimeout) + throw usb_error("time-out reading from USB endpoint", ret); + + throw usb_error("error reading from USB endpoint", ret); + } + + data.resize(size); + return data; +} + +void usb_device::transfer_out(int endpoint_number, const std::vector& data, int timeout) { + if (interface_ == nullptr) + throw usb_error("no interface has been claimed"); + + IOReturn ret; + if (timeout != 0) + ret = (*interface_)->WritePipeTO(interface_, ep_out_pipe(endpoint_number), const_cast(data.data()), static_cast(data.size()), timeout, timeout); + else + ret = (*interface_)->WritePipe(interface_, ep_out_pipe(endpoint_number), const_cast(data.data()), static_cast(data.size())); + + if (ret != kIOReturnSuccess) { + if (ret == kIOUSBTransactionTimeout) + throw usb_error("time-out writing to USB endpoint", ret); + + throw usb_error("error writing to USB endpoint", ret); + } +} + +int usb_device::control_transfer_core(const usb_control_request &request, uint8_t* data, int timeout) { + + if (!is_open()) + throw usb_error("USB device is not open"); + + IOUSBDevRequestTO io_request = { + .bmRequestType = request.bmRequestType, + .bRequest = request.bRequest, + .wValue = request.wValue, + .wIndex = request.wIndex, + .wLength = request.wLength, + .pData = data, + .wLenDone = 0, + .noDataTimeout = (UInt32)timeout, + .completionTimeout = (UInt32)timeout + }; + + IOReturn ret; + if (timeout != 0) + ret = (*device_)->DeviceRequestTO(device_, &io_request); + else + ret = (*device_)->DeviceRequest(device_, (IOUSBDevRequest*) &io_request); + + if (ret != kIOReturnSuccess) { + if (ret == kIOUSBTransactionTimeout) + throw usb_error("time-out sending control request", ret); + + throw usb_error("error sending control request", ret); + } + + return io_request.wLenDone; +} + +void usb_device::control_transfer(const usb_control_request& request, int timeout ) { + if (request.wLength != 0) + throw usb_error("'control_transfer' only supports request without data phase but 'wLength' != 0"); + + control_transfer_core(request, nullptr, timeout); +} + +void usb_device::control_transfer_out(const usb_control_request& request, const std::vector& data, int timeout ) { + if ((request.bmRequestType & 0x80) != 0) + throw usb_error("direction mismatch between 'control_transfer_out' and direction bit in 'bmRequestType'"); + + control_transfer_core(request, const_cast(data.data()), timeout); +} + +std::vector usb_device::control_transfer_in(const usb_control_request& request, int timeout ) { + if ((request.bmRequestType & 0x80) == 0) + throw usb_error("direction mismatch between 'control_transfer_in' and direction bit in 'bmRequestType'"); + + std::vector data(request.wLength); + control_transfer_core(request, data.data(), timeout); + data.resize(request.wLength); + return data; +} + +UInt8 usb_device::ep_to_pipe(int endpoint_address) { + auto it = std::find (endpoint_addresses_.begin(), endpoint_addresses_.end(), endpoint_address); + if (it != endpoint_addresses_.end()) + return std::distance(endpoint_addresses_.begin(), it) + 1; + + throw usb_error("invalid endpoint number"); +} + +UInt8 usb_device::ep_out_pipe(int endpoint_number) { + return ep_to_pipe(endpoint_number); +} + +UInt8 usb_device::ep_in_pipe(int endpoint_number) { + return ep_to_pipe(endpoint_number + 128); +} diff --git a/reference/macos/USB/usb_device.hpp b/reference/macos/USB/usb_device.hpp new file mode 100644 index 00000000..f6c729f8 --- /dev/null +++ b/reference/macos/USB/usb_device.hpp @@ -0,0 +1,213 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include +#include + +#include +#include +#include +#include + + +/** + * USB control request type. + * + * Bitmask values for direction (bit 7), type (bits 6..5) and recipient (bits 4..0) + */ +enum class usb_request_type { + // bit 7 : direction + /// Direction device to host + direction_in = 0x80, + /// Direction host to device + direction_out = 0x00, + // bits 6..5 : type + /// Standard request + type_standard = 0x00, + /// Class-specific request + type_class = 0x20, + /// Vendor-defined request + type_vendor = 0x40, + // bits 4..0 : recipient + /// Request for device + recipient_device = 0x00, + /// Request for interface + recipient_interface = 0x01, + /// Request for endpoint + recipient_endpoint = 0x02, + /// Request for other recipient + recipient_other = 0x03 +}; + + +/** + * USB control request structure. + */ +struct usb_control_request { + /// Request type + uint8_t bmRequestType; + /// Specific request number + uint8_t bRequest; + /// Value (request specific) + uint16_t wValue; + /// Index (request specific) + uint16_t wIndex; + /// Number of bytes to transfer if there is a data stage + uint16_t wLength; + + static uint8_t request_type(usb_request_type direction, usb_request_type type, usb_request_type recipient) { + return static_cast(direction) + static_cast(type) + static_cast(recipient); + } +}; + + +/** + * USB device. + * + * Must be used with `std::shared_ptr`. + */ +class usb_device { +public: + ~usb_device(); + + /// USB vendor ID + int vendor_id() const { return vendor_id_; } + /// USB product ID + int product_id() const { return product_id_; } + /// Manufacturer name + std::string manufacturer() const { return manufacturer_; } + /// Product name + std::string product() const { return product_; } + /// Serial number + std::string serial_number() const { return serial_number_; } + /// Descriptive string including VID, PID, manufacturer, product name and serial number + std::string description() const; + + /// Opens the device for communication + void open(); + + /// Closes the device + void close(); + + /// Indicates if device is open + bool is_open() const; + + /** + * Claims an interface + * + * A single interface can be claimed. + * + * @param interface_number interface number + */ + void claim_interface(int interface_number); + + /** + * Releases the claimed interface. + */ + void release_interface(); + + /** + * Receives data from a bulk or interrupt endpoint. + * + * The amount of bytes read will be influced by the underlying USB packets. + * If a short packet is sent, the function will return after having read fewer bytes + * than specified. The function will fail if a bigger packet has been received than + * will fit into the given buffer. So the specified data length should be big enough for + * the maximum packet size (64 bytes for full-speed USB). + * + * The timeout specifies the maximum time it may take to complete the operation. + * If the operation does not complete within that time, the function returns after reading + * less or no data at all. + * + * Interrupt endpoints do not support timeouts. Thus, 0 has to be specified. + * + * @param endpoint_number endpoint number (between 1 and 127) + * @param data_len maximum length to read (in bytes) + * @param timeout timeout (in ms, 0 for no timeout) + * @return received data + */ + std::vector transfer_in(int endpoint_number, int data_len, int timeout = 0); + + /** + * Transmits data to a bulk or interrupt endpoint. + * + * The timeout specifies the maximum time it may take to complete the operation. + * If the operation does not complete within that time, the function returns after writing + * less or no data at all. + * + * Interrupt endpoints do not support timeouts. Thus, 0 has to be specified. + * + * @param endpoint_number endpoint number (between 1 and 127) + * @param data data to transmit + * @param timeout timeout (in ms, 0 for no timeout) + */ + void transfer_out(int endpoint_number, const std::vector& data, int timeout = 0); + + /** + * Send a control request with no Data phase. + * + * The request is always sent to endpoint 0. + * + * @param request request to send + * @param timeout timeout (in ms, 0 for no timeout) + */ + void control_transfer(const usb_control_request& request, int timeout = 0); + + /** + * Send a control request with a DATA OUT phase. + * + * The request is always sent to endpoint 0. + * + * The length of the passed data vector and `request.wLength` must be equal. + * + * @param request request to send + * @param data buffer containing data to be sent in DATA phase. + * @param timeout timeout (in ms, 0 for no timeout) + */ + void control_transfer_out(const usb_control_request& request, const std::vector& data, int timeout = 0); + + /** + * Send a control request with a DATA IN phase. + * + * The request is always sent to endpoint 0. + * + * The data is received in the specified data buffer. The length of buffer is specified in `request.wLength`. + * + * @param request request to send + * @param timeout timeout (in ms, 0 for no timeout) + * @return received data + */ + std::vector control_transfer_in(const usb_control_request& request, int timeout = 0); + +private: + usb_device(io_service_t service, IOUSBDeviceInterface** device, uint64_t entry_id, int vendor_id, int product_id); + uint64_t entry_id() const { return entry_id_; } + UInt8 ep_to_pipe(int endpoint_address); + UInt8 ep_out_pipe(int endpoint_number); + UInt8 ep_in_pipe(int endpoint_number); + int control_transfer_core(const usb_control_request& request, uint8_t* data, int timeout); + + uint64_t entry_id_; + IOUSBDeviceInterface** device_; + bool is_open_; + IOUSBInterfaceInterface** interface_; + std::vector endpoint_addresses_; + + int product_id_; + int vendor_id_; + std::string manufacturer_; + std::string product_; + std::string serial_number_; + + friend class usb_registry; +}; + +typedef std::shared_ptr usb_device_ptr; diff --git a/reference/macos/USB/usb_error.cpp b/reference/macos/USB/usb_error.cpp new file mode 100644 index 00000000..b24aec03 --- /dev/null +++ b/reference/macos/USB/usb_error.cpp @@ -0,0 +1,43 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "usb_error.hpp" + +#include + + +usb_error::usb_error(const char* message, int code) noexcept + : _message(full_message(message, code)), _code(code) { } + +usb_error::~usb_error() noexcept { } + +const char* usb_error::what() const noexcept { + return _message.c_str(); +} + +long usb_error::error_code() { + return _code; +} + +void usb_error::check(int code, const char *message) { + if (code != 0) + throw usb_error(message, code); +} + +std::string usb_error::full_message(const char* message, int code) { + if (code == 0) + return message; + + std::string msg(message); + msg += " ("; + msg += mach_error_string(code); + msg += ")"; + + return msg; +} diff --git a/reference/macos/USB/usb_error.hpp b/reference/macos/USB/usb_error.hpp new file mode 100644 index 00000000..83c35739 --- /dev/null +++ b/reference/macos/USB/usb_error.hpp @@ -0,0 +1,45 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include +#include + +/// USB error exception +class usb_error : public std::exception { +public: + /** + * Creates a new instance. + * + *@param message error message + *@param code a Mach error code, or 0 if no Mach code is available + */ + usb_error(const char* message, int code = 0) noexcept; + + virtual ~usb_error() noexcept; + + virtual const char* what() const noexcept; + /// Mach error code + long error_code(); + + /** + * Throws a USB error exception if the code indicates an error. + * + * @param code Mach error code + * @param message additional information for the error message + */ + static void check(int code, const char* message); + +private: + static std::string full_message(const char* message, int code); + + std::string _message; + long _code; +}; diff --git a/reference/macos/USB/usb_registry.cpp b/reference/macos/USB/usb_registry.cpp new file mode 100644 index 00000000..f434d473 --- /dev/null +++ b/reference/macos/USB/usb_registry.cpp @@ -0,0 +1,184 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "usb_registry.hpp" +#include "usb_device.hpp" +#include "usb_error.hpp" +#include "iokit_helper.hpp" +#include "scope.hpp" + +#include +#include +#include + +usb_registry::usb_registry() +: notify_port(nullptr), run_loop_source(nullptr), + device_connected_iter(0), device_disconnected_iter(0), + on_connected_callback(nullptr), on_disconnected_callback(nullptr), + is_device_list_ready(false) { +} + +usb_registry::~usb_registry() { + if (device_connected_iter != 0) { + IOObjectRelease(device_connected_iter); + device_connected_iter = 0; + } + if (device_disconnected_iter != 0) { + IOObjectRelease(device_disconnected_iter); + device_disconnected_iter = 0; + } + + CFRunLoopStop(run_loop); + monitor_thread.join(); + + if (notify_port != nullptr) { + IONotificationPortDestroy(notify_port); + notify_port = nullptr; + } +} + +std::vector usb_registry::get_devices() { + return devices; +} + +void usb_registry::set_on_device_connected(std::function callback) { + on_connected_callback = callback; +} + +void usb_registry::set_on_device_disconnected(std::function callback) { + on_disconnected_callback = callback; +} + +void usb_registry::start() { + monitor_thread = std::thread(&usb_registry::monitor, this); + + std::unique_lock wait_lock(monitor_mutex); + monitor_condition.wait(wait_lock, [this] { return is_device_list_ready; }); +} + +void usb_registry::monitor() { + + notify_port = IONotificationPortCreate(kIOMainPortDefault); + run_loop_source = IONotificationPortGetRunLoopSource(notify_port); + + run_loop = CFRunLoopGetCurrent(); + CFRunLoopAddSource(run_loop, run_loop_source, kCFRunLoopDefaultMode); + + auto matching_dict = IOServiceMatching(kIOUSBDeviceClassName); // Interested in instances of USB device + + // Now set up a notification to be called when a device is first matched by I/O Kit. + // This method consumes the matchingDict reference. + kern_return_t kr = IOServiceAddMatchingNotification(notify_port, + kIOFirstMatchNotification, // notificationType + matching_dict, // matching + device_connected_f, // callback + this, // refCon + &device_connected_iter // notification + ); + usb_error::check(kr, "IOServiceAddMatchingNotification failed"); + + // iterate the already connected devices and activate notifications + device_connected(device_connected_iter); + + matching_dict = IOServiceMatching(kIOUSBDeviceClassName); // Interested in instances of USB device + + // Now set up a notification to be called when a device is disconnected. + // This method consumes the matchingDict reference. + kr = IOServiceAddMatchingNotification(notify_port, + kIOTerminatedNotification, // notificationType + matching_dict, // matching + device_disconnected_f, // callback + this, // refCon + &device_disconnected_iter // notification + ); + usb_error::check(kr, "IOServiceAddMatchingNotification failed"); + + // iterate to activate notifications + device_disconnected(device_disconnected_iter); + + is_device_list_ready = true; + monitor_condition.notify_all(); + + // start run loop + CFRunLoopRun(); +} + +void usb_registry::device_connected_f(void *refcon, io_iterator_t iterator) { + auto self = reinterpret_cast(refcon); + self->device_connected(iterator); +} + +void usb_registry::device_connected(io_iterator_t iterator) { + // Walk the iterator + io_service_t service; + while ((service = IOIteratorNext(iterator)) != 0) { + + auto service_guard = make_scope_exit([service]() { IOObjectRelease(service); }); + + // Test if the device has a client interface (otherwise it's likely a controller) + IOUSBDeviceInterface** dev = iokit_helper::get_interface(service, kIOUSBDeviceUserClientTypeID, kIOUSBDeviceInterfaceID); + if (dev == nullptr) + continue; + + auto dev_guard = make_scope_exit([dev]() { (*dev)->Release(dev); }); + + // Get VID and PID + int vendor_id = iokit_helper::ioreg_get_property_as_int(service, CFSTR(kUSBVendorID)); + int product_id = iokit_helper::ioreg_get_property_as_int(service, CFSTR(kUSBProductID)); + if (vendor_id == 0 || product_id == 0) + continue; // controller or similar + + // Get entry ID + uint64_t entry_id = 0; + kern_return_t kr = IORegistryEntryGetRegistryEntryID(service, &entry_id); + if (kr != 0) + continue; // ignore + + // Create new device + std::shared_ptr device(new usb_device(service, dev, entry_id, vendor_id, product_id)); + devices.push_back(device); + + // Call callback function + if (on_connected_callback != nullptr) + on_connected_callback(device); + } +} + +void usb_registry::device_disconnected_f(void *refcon, io_iterator_t iterator) { + auto self = reinterpret_cast(refcon); + self->device_disconnected(iterator); +} + +void usb_registry::device_disconnected(io_iterator_t iterator) { + // Walk the iterator + io_service_t service; + while ((service = IOIteratorNext(iterator)) != 0) { + + auto service_guard = make_scope_exit([service]() { IOObjectRelease(service); }); + + // Get entry ID + uint64_t entry_id = 0; + kern_return_t kr = IORegistryEntryGetRegistryEntryID(service, &entry_id); + if (kr != 0) + continue; // ignore + + // find device in device list + auto it = std::find_if(devices.cbegin(), devices.cend(), [entry_id](auto device) { return device->entry_id() == entry_id; }); + if (it == devices.cend()) + continue; // not part of the device list + + // remove from device list + usb_device_ptr device = *it; + devices.erase(it); + + // call callback function + if (on_disconnected_callback != nullptr) + on_disconnected_callback(device); + } +} diff --git a/reference/macos/USB/usb_registry.hpp b/reference/macos/USB/usb_registry.hpp new file mode 100644 index 00000000..9fd820fc --- /dev/null +++ b/reference/macos/USB/usb_registry.hpp @@ -0,0 +1,68 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include "usb_device.hpp" + +#include + +#include +#include +#include +#include +#include +#include + +/** + * Registry of connected USB devices. + */ +class usb_registry { +public: + /// Create a new instance + usb_registry(); + ~usb_registry(); + + /// Sets a function to be called when a new device is connected. + void set_on_device_connected(std::function callback); + /// Sets a function to be called when a device is disconnected + void set_on_device_disconnected(std::function callback); + + /// Starts the registry + void start(); + + /// Gets the currently connected devices. + std::vector> get_devices(); + +private: + /// Method run in background to monitor USB devices + void monitor(); + + void device_connected(io_iterator_t iterator); + void device_disconnected(io_iterator_t iterator); + + static void device_connected_f(void *refcon, io_iterator_t iterator); + static void device_disconnected_f(void *refcon, io_iterator_t iterator); + + std::vector devices; + + std::function on_connected_callback; + std::function on_disconnected_callback; + + std::thread monitor_thread; + CFRunLoopRef run_loop; + IONotificationPortRef notify_port; + CFRunLoopSourceRef run_loop_source; + io_iterator_t device_connected_iter; + io_iterator_t device_disconnected_iter; + + bool is_device_list_ready; + std::mutex monitor_mutex; + std::condition_variable monitor_condition; +}; diff --git a/reference/macos/usb.xcodeproj/project.pbxproj b/reference/macos/usb.xcodeproj/project.pbxproj new file mode 100644 index 00000000..ccdc03d9 --- /dev/null +++ b/reference/macos/usb.xcodeproj/project.pbxproj @@ -0,0 +1,336 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 64937C6428D5EBF1009BD0C2 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64937C6328D5EBF1009BD0C2 /* main.cpp */; }; + 64937C7228D5ED1F009BD0C2 /* usb_registry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64937C6B28D5ED1F009BD0C2 /* usb_registry.cpp */; }; + 64937C7328D5ED1F009BD0C2 /* iokit_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64937C6C28D5ED1F009BD0C2 /* iokit_helper.cpp */; }; + 64937C7628D5ED8D009BD0C2 /* usb_error.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64937C7428D5ED8D009BD0C2 /* usb_error.cpp */; }; + 64937C7928D5FE6D009BD0C2 /* usb_device.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64937C7728D5FE6D009BD0C2 /* usb_device.cpp */; }; + 64937C7C28D60C67009BD0C2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 64937C7B28D60C67009BD0C2 /* IOKit.framework */; }; + 64937C7E28D60C82009BD0C2 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 64937C7D28D60C82009BD0C2 /* CoreFoundation.framework */; }; + 64937C8128D6F9DE009BD0C2 /* tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64937C7F28D6F9DE009BD0C2 /* tests.cpp */; }; + 64937C8428D71D31009BD0C2 /* assertion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64937C8228D71D31009BD0C2 /* assertion.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 64937C5E28D5EBF1009BD0C2 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 64937C6028D5EBF1009BD0C2 /* USB */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = USB; sourceTree = BUILT_PRODUCTS_DIR; }; + 64937C6328D5EBF1009BD0C2 /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 64937C6B28D5ED1F009BD0C2 /* usb_registry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = usb_registry.cpp; sourceTree = ""; }; + 64937C6C28D5ED1F009BD0C2 /* iokit_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = iokit_helper.cpp; sourceTree = ""; }; + 64937C6D28D5ED1F009BD0C2 /* iokit_helper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = iokit_helper.hpp; sourceTree = ""; }; + 64937C6E28D5ED1F009BD0C2 /* usb_registry.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = usb_registry.hpp; sourceTree = ""; }; + 64937C6F28D5ED1F009BD0C2 /* scope.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = scope.hpp; sourceTree = ""; }; + 64937C7428D5ED8D009BD0C2 /* usb_error.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = usb_error.cpp; sourceTree = ""; }; + 64937C7528D5ED8D009BD0C2 /* usb_error.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = usb_error.hpp; sourceTree = ""; }; + 64937C7728D5FE6D009BD0C2 /* usb_device.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = usb_device.cpp; sourceTree = ""; }; + 64937C7828D5FE6D009BD0C2 /* usb_device.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = usb_device.hpp; sourceTree = ""; }; + 64937C7B28D60C67009BD0C2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 64937C7D28D60C82009BD0C2 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + 64937C7F28D6F9DE009BD0C2 /* tests.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = tests.cpp; sourceTree = ""; }; + 64937C8028D6F9DE009BD0C2 /* tests.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = tests.hpp; sourceTree = ""; }; + 64937C8228D71D31009BD0C2 /* assertion.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = assertion.cpp; sourceTree = ""; }; + 64937C8328D71D31009BD0C2 /* assertion.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = assertion.hpp; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 64937C5D28D5EBF1009BD0C2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 64937C7E28D60C82009BD0C2 /* CoreFoundation.framework in Frameworks */, + 64937C7C28D60C67009BD0C2 /* IOKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 64937C5728D5EBF1009BD0C2 = { + isa = PBXGroup; + children = ( + 64937C6228D5EBF1009BD0C2 /* USB */, + 64937C6128D5EBF1009BD0C2 /* Products */, + 64937C7A28D60C67009BD0C2 /* Frameworks */, + ); + sourceTree = ""; + }; + 64937C6128D5EBF1009BD0C2 /* Products */ = { + isa = PBXGroup; + children = ( + 64937C6028D5EBF1009BD0C2 /* USB */, + ); + name = Products; + sourceTree = ""; + }; + 64937C6228D5EBF1009BD0C2 /* USB */ = { + isa = PBXGroup; + children = ( + 64937C6C28D5ED1F009BD0C2 /* iokit_helper.cpp */, + 64937C6D28D5ED1F009BD0C2 /* iokit_helper.hpp */, + 64937C6F28D5ED1F009BD0C2 /* scope.hpp */, + 64937C6B28D5ED1F009BD0C2 /* usb_registry.cpp */, + 64937C6E28D5ED1F009BD0C2 /* usb_registry.hpp */, + 64937C6328D5EBF1009BD0C2 /* main.cpp */, + 64937C7428D5ED8D009BD0C2 /* usb_error.cpp */, + 64937C7528D5ED8D009BD0C2 /* usb_error.hpp */, + 64937C7728D5FE6D009BD0C2 /* usb_device.cpp */, + 64937C7828D5FE6D009BD0C2 /* usb_device.hpp */, + 64937C7F28D6F9DE009BD0C2 /* tests.cpp */, + 64937C8028D6F9DE009BD0C2 /* tests.hpp */, + 64937C8228D71D31009BD0C2 /* assertion.cpp */, + 64937C8328D71D31009BD0C2 /* assertion.hpp */, + ); + path = USB; + sourceTree = ""; + }; + 64937C7A28D60C67009BD0C2 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 64937C7D28D60C82009BD0C2 /* CoreFoundation.framework */, + 64937C7B28D60C67009BD0C2 /* IOKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 64937C5F28D5EBF1009BD0C2 /* USB */ = { + isa = PBXNativeTarget; + buildConfigurationList = 64937C6728D5EBF1009BD0C2 /* Build configuration list for PBXNativeTarget "USB" */; + buildPhases = ( + 64937C5C28D5EBF1009BD0C2 /* Sources */, + 64937C5D28D5EBF1009BD0C2 /* Frameworks */, + 64937C5E28D5EBF1009BD0C2 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = USB; + productName = USB; + productReference = 64937C6028D5EBF1009BD0C2 /* USB */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 64937C5828D5EBF1009BD0C2 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastUpgradeCheck = 1400; + TargetAttributes = { + 64937C5F28D5EBF1009BD0C2 = { + CreatedOnToolsVersion = 14.0; + }; + }; + }; + buildConfigurationList = 64937C5B28D5EBF1009BD0C2 /* Build configuration list for PBXProject "usb" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 64937C5728D5EBF1009BD0C2; + productRefGroup = 64937C6128D5EBF1009BD0C2 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 64937C5F28D5EBF1009BD0C2 /* USB */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 64937C5C28D5EBF1009BD0C2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 64937C7328D5ED1F009BD0C2 /* iokit_helper.cpp in Sources */, + 64937C8428D71D31009BD0C2 /* assertion.cpp in Sources */, + 64937C7928D5FE6D009BD0C2 /* usb_device.cpp in Sources */, + 64937C7228D5ED1F009BD0C2 /* usb_registry.cpp in Sources */, + 64937C6428D5EBF1009BD0C2 /* main.cpp in Sources */, + 64937C7628D5ED8D009BD0C2 /* usb_error.cpp in Sources */, + 64937C8128D6F9DE009BD0C2 /* tests.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 64937C6528D5EBF1009BD0C2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 64937C6628D5EBF1009BD0C2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + }; + name = Release; + }; + 64937C6828D5EBF1009BD0C2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 4H9ZA7X4C4; + ENABLE_HARDENED_RUNTIME = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 64937C6928D5EBF1009BD0C2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 4H9ZA7X4C4; + ENABLE_HARDENED_RUNTIME = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 64937C5B28D5EBF1009BD0C2 /* Build configuration list for PBXProject "usb" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 64937C6528D5EBF1009BD0C2 /* Debug */, + 64937C6628D5EBF1009BD0C2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 64937C6728D5EBF1009BD0C2 /* Build configuration list for PBXNativeTarget "USB" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 64937C6828D5EBF1009BD0C2 /* Debug */, + 64937C6928D5EBF1009BD0C2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 64937C5828D5EBF1009BD0C2 /* Project object */; +} diff --git a/reference/macos/usb.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/reference/macos/usb.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/reference/macos/usb.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/reference/macos/usb.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/reference/macos/usb.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/reference/macos/usb.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/reference/macos/usb.xcodeproj/xcshareddata/xcschemes/USB.xcscheme b/reference/macos/usb.xcodeproj/xcshareddata/xcschemes/USB.xcscheme new file mode 100644 index 00000000..46c6a98b --- /dev/null +++ b/reference/macos/usb.xcodeproj/xcshareddata/xcschemes/USB.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From fd934e819ffe54ea01c21537d8d0a8468c8ac640 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 18 Sep 2022 21:37:05 +0200 Subject: [PATCH 095/433] Windows reference code --- reference/README.md | 1 + reference/macos/USB/usb_registry.cpp | 1 + reference/windows/.gitignore | 9 + reference/windows/USB/USB.vcxproj | 148 +++++++++ reference/windows/USB/USB.vcxproj.filters | 57 ++++ reference/windows/USB/assertion.cpp | 64 ++++ reference/windows/USB/assertion.hpp | 27 ++ reference/windows/USB/main.cpp | 15 + reference/windows/USB/scope.hpp | 52 ++++ reference/windows/USB/tests.cpp | 164 ++++++++++ reference/windows/USB/tests.hpp | 36 +++ reference/windows/USB/usb_device.cpp | 183 +++++++++++ reference/windows/USB/usb_device.hpp | 212 +++++++++++++ reference/windows/USB/usb_error.cpp | 50 +++ reference/windows/USB/usb_error.hpp | 44 +++ reference/windows/USB/usb_registry.cpp | 358 ++++++++++++++++++++++ reference/windows/USB/usb_registry.hpp | 76 +++++ reference/windows/windows.sln | 31 ++ 18 files changed, 1528 insertions(+) create mode 100644 reference/windows/.gitignore create mode 100644 reference/windows/USB/USB.vcxproj create mode 100644 reference/windows/USB/USB.vcxproj.filters create mode 100644 reference/windows/USB/assertion.cpp create mode 100644 reference/windows/USB/assertion.hpp create mode 100644 reference/windows/USB/main.cpp create mode 100644 reference/windows/USB/scope.hpp create mode 100644 reference/windows/USB/tests.cpp create mode 100644 reference/windows/USB/tests.hpp create mode 100644 reference/windows/USB/usb_device.cpp create mode 100644 reference/windows/USB/usb_device.hpp create mode 100644 reference/windows/USB/usb_error.cpp create mode 100644 reference/windows/USB/usb_error.hpp create mode 100644 reference/windows/USB/usb_registry.cpp create mode 100644 reference/windows/USB/usb_registry.hpp create mode 100644 reference/windows/windows.sln diff --git a/reference/README.md b/reference/README.md index ad8937bc..265d80e6 100644 --- a/reference/README.md +++ b/reference/README.md @@ -5,3 +5,4 @@ The C++ reference code is used to first implement the features before it is tran The C++ code contains less error checking, less test cases and does not cover all features. - [MacOS](macos) (for use with Xcode) +- [Windows](windows) (for use with Visual Studio) diff --git a/reference/macos/USB/usb_registry.cpp b/reference/macos/USB/usb_registry.cpp index f434d473..2158ad6c 100644 --- a/reference/macos/USB/usb_registry.cpp +++ b/reference/macos/USB/usb_registry.cpp @@ -15,6 +15,7 @@ #include #include +#include #include usb_registry::usb_registry() diff --git a/reference/windows/.gitignore b/reference/windows/.gitignore new file mode 100644 index 00000000..5bc969ab --- /dev/null +++ b/reference/windows/.gitignore @@ -0,0 +1,9 @@ +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates +.vs/ +x64/ +x86/ + diff --git a/reference/windows/USB/USB.vcxproj b/reference/windows/USB/USB.vcxproj new file mode 100644 index 00000000..f8bd5d6b --- /dev/null +++ b/reference/windows/USB/USB.vcxproj @@ -0,0 +1,148 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + 16.0 + Win32Proj + {31927336-b5d2-44b6-aaaa-eaf79e673087} + USB + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + \ No newline at end of file diff --git a/reference/windows/USB/USB.vcxproj.filters b/reference/windows/USB/USB.vcxproj.filters new file mode 100644 index 00000000..ffebc144 --- /dev/null +++ b/reference/windows/USB/USB.vcxproj.filters @@ -0,0 +1,57 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/reference/windows/USB/assertion.cpp b/reference/windows/USB/assertion.cpp new file mode 100644 index 00000000..2a60687a --- /dev/null +++ b/reference/windows/USB/assertion.cpp @@ -0,0 +1,64 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "assertion.hpp" + +#include +#include + +static void failed(const char* check, const char* message) { + if (message == nullptr) + message = "Check failed"; + std::cerr << message << ": " << check << std::endl; + throw new check_failed_error(); +} + +void assert_equals(int expected, int actual, const char* message) { + if (actual != expected) { + char buf[50]; + snprintf(buf, sizeof(buf), "expected: %d, actual: %d", expected, actual); + failed(buf, message); + } +} + +void assert_equals(long expected, long actual, const char* message) { + if (actual != expected) { + char buf[50]; + snprintf(buf, sizeof(buf), "expected: %ld, actual: %ld", expected, actual); + failed(buf, message); + } +} + +void assert_equals(unsigned long expected, unsigned long actual, const char* message) { + if (actual != expected) { + char buf[50]; + snprintf(buf, sizeof(buf), "expected: %lud, actual: %lud", expected, actual); + failed(buf, message); + } +} + +void assert_equals(size_t expected, size_t actual, const char* message) { + if (actual != expected) { + char buf[50]; + snprintf(buf, sizeof(buf), "expected: %lld, actual: %lld", expected, actual); + failed(buf, message); + } +} + +void assert_equals(const std::vector& expected, const std::vector& actual, const char* message) { + assert_equals(expected.size(), actual.size(), message); + for (int i = 0; i < expected.size(); i++) { + assert_equals(expected[i], actual[i], message); + } +} + + +check_failed_error::check_failed_error() noexcept { } +check_failed_error::~check_failed_error() noexcept { } +const char* check_failed_error::what() const noexcept { return "check failed"; } diff --git a/reference/windows/USB/assertion.hpp b/reference/windows/USB/assertion.hpp new file mode 100644 index 00000000..4c458fd3 --- /dev/null +++ b/reference/windows/USB/assertion.hpp @@ -0,0 +1,27 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include +#include + + +void assert_equals(int expected, int actual, const char* message = nullptr); +void assert_equals(long expected, long actual, const char* message = nullptr); +void assert_equals(unsigned long expected, unsigned long actual, const char* message = nullptr); +void assert_equals(size_t expected, size_t actual, const char* message = nullptr); +void assert_equals(const std::vector& expected, const std::vector& actual, const char* message = nullptr); + +class check_failed_error : public std::exception { +public: + check_failed_error() noexcept; + virtual ~check_failed_error() noexcept; + virtual const char* what() const noexcept; +}; diff --git a/reference/windows/USB/main.cpp b/reference/windows/USB/main.cpp new file mode 100644 index 00000000..64e85de5 --- /dev/null +++ b/reference/windows/USB/main.cpp @@ -0,0 +1,15 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "tests.hpp" + +int main(int argc, const char * argv[]) { + tests t; + t.run(); +} diff --git a/reference/windows/USB/scope.hpp b/reference/windows/USB/scope.hpp new file mode 100644 index 00000000..53e3e39f --- /dev/null +++ b/reference/windows/USB/scope.hpp @@ -0,0 +1,52 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include + +template +class scope_exit +{ +public: + template + explicit scope_exit(Fn&& fn) noexcept + : exit_fn(std::forward(fn)), exec_on_destruction(true) + { } + + scope_exit(scope_exit&& other) noexcept + : exit_fn(std::forward(other.exit_fn)), + exec_on_destruction(other.exec_on_destruction) + { + other.release(); + } + + ~scope_exit() noexcept { + if (exec_on_destruction) + exit_fn(); + } + + void release() noexcept { + exec_on_destruction = false; + } + + scope_exit(scope_exit const&) = delete; + + scope_exit& operator=(scope_exit const&) = delete; + scope_exit& operator=(scope_exit&&) = delete; + +private: + EF exit_fn; + bool exec_on_destruction; +}; + +template +scope_exit::type> make_scope_exit(EF&& exit_function) { + return scope_exit::type>(std::forward(exit_function)); +} diff --git a/reference/windows/USB/tests.cpp b/reference/windows/USB/tests.cpp new file mode 100644 index 00000000..73d7da40 --- /dev/null +++ b/reference/windows/USB/tests.cpp @@ -0,0 +1,164 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "tests.hpp" +#include "assertion.hpp" + +#include +#include + +#undef min +#undef max + + +using random_ushort_engine = std::independent_bits_engine< + std::default_random_engine, CHAR_BIT, unsigned short>; + + +void tests::run() { + registry.start(); + + for (auto& device : registry.get_devices()) { + std::cout << "Present: " << device->description() << std::endl; + } + + registry.set_on_device_connected([this](auto device) { on_device_connected(device); }); + registry.set_on_device_disconnected([this](auto device) { on_device_disconnected(device); }); + + for (auto& device : registry.get_devices()) + on_device(device); + + std::cout << "Press RETURN to quit" << std::endl; + std::string line; + std::getline(std::cin, line); +} + +void tests::test_current_device() { + try { + std::cout << "Found test device" << std::endl; + test_device->open(); + test_device->claim_interface(0); + + test_control_transfers(); + test_bulk_transfers(); + + test_device->release_interface(); + test_device->close(); + std::cout << "Test completed" << std::endl; + } + catch (const std::exception& e) { + std::cout << "Test failed: " << e.what() << std::endl; + } +} + +void tests::test_control_transfers() { + usb_control_request request_set_value_no_data = { 0 }; + request_set_value_no_data.bmRequestType = usb_control_request::request_type(usb_request_type::direction_out, + usb_request_type::type_vendor, usb_request_type::recipient_interface); + request_set_value_no_data.bRequest = 0x01; + request_set_value_no_data.wValue = 0x9a41; + request_set_value_no_data.wIndex = 0; // interface number + request_set_value_no_data.wLength = 0; + test_device->control_transfer(request_set_value_no_data); + + usb_control_request request_get_data = { 0 }; + request_get_data.bmRequestType = usb_control_request::request_type(usb_request_type::direction_in, + usb_request_type::type_vendor, usb_request_type::recipient_interface); + request_get_data.bRequest = 0x03; + request_get_data.wValue = 0; + request_get_data.wIndex = 0; // interface number + request_get_data.wLength = 4; + auto data = test_device->control_transfer_in(request_get_data); + std::vector expected_data{ 0x41, 0x9a, 0x00, 0x00 }; + assert_equals(expected_data, data); + + std::vector sent_value{ 0x83, 0x03, 0xda, 0x3d }; + usb_control_request request_set_value_data = { 0 }; + request_set_value_data.bmRequestType = usb_control_request::request_type(usb_request_type::direction_out, + usb_request_type::type_vendor, usb_request_type::recipient_interface); + request_set_value_data.bRequest = 0x02; + request_set_value_data.wValue = 0; + request_set_value_data.wIndex = 0; // interface number + request_set_value_data.wLength = static_cast(sent_value.size()); + test_device->control_transfer_out(request_set_value_data, sent_value); + + data = test_device->control_transfer_in(request_get_data); + assert_equals(sent_value, data); +} + +void tests::test_bulk_transfers() { + test_loopback(12); + test_loopback(130); + test_loopback(123709); +} + +void tests::test_loopback(int num_bytes) { + + // generate random bytes + auto random_data = random_bytes(num_bytes); + + // prepare vector for receiving data + std::vector rx_data; + rx_data.reserve(num_bytes); + + // read in separate thread + std::thread reader([this, &rx_data, num_bytes]() { + size_t bytes_read = 0; + while (bytes_read < num_bytes) { + auto data = test_device->transfer_in(2, 64); + rx_data.insert(rx_data.end(), data.begin(), data.end()); + bytes_read += data.size(); + } + }); + + // send rand bytes in chunks + const int chunk_size = 100; + int bytes_written = 0; + while (bytes_written < num_bytes) { + int size = std::min(chunk_size, num_bytes - bytes_written); + std::vector chunk = {random_data.begin() + bytes_written, random_data.begin() + bytes_written + size}; + test_device->transfer_out(1, chunk); + bytes_written += size; + } + + // wait for reader + reader.join(); + + // check result + assert_equals(random_data, rx_data); +} + +void tests::on_device(usb_device_ptr device) { + if (is_test_device(device)) { + test_device = device; + test_current_device(); + test_device = nullptr; + } +} + +void tests::on_device_connected(usb_device_ptr device) { + std::cout << "Connected: " << device->description() << std::endl; + on_device(device); +} + +void tests::on_device_disconnected(usb_device_ptr device) { + std::cout << "Disconnected: " << device->description() << std::endl; +} + +std::vector tests::random_bytes(int num) { + random_ushort_engine rbe; + std::vector data((num + 1) / 2); + std::generate(begin(data), end(data), std::ref(rbe)); + const uint8_t* p = reinterpret_cast(data.data()); + return std::vector(p, p + num); +} + +bool tests::is_test_device(usb_device_ptr device) { + return device->vendor_id() == 0xcafe && device->product_id() == 0xceaf; +} diff --git a/reference/windows/USB/tests.hpp b/reference/windows/USB/tests.hpp new file mode 100644 index 00000000..992de2b9 --- /dev/null +++ b/reference/windows/USB/tests.hpp @@ -0,0 +1,36 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include "usb_device.hpp" +#include "usb_registry.hpp" + +class tests { +public: + void run(); + +private: + void test_current_device(); + void test_control_transfers(); + void test_bulk_transfers(); + + void test_loopback(int num_bytes); + + void on_device(usb_device_ptr device); + void on_device_connected(usb_device_ptr device); + void on_device_disconnected(usb_device_ptr device); + + static std::vector random_bytes(int num); + static bool is_test_device(usb_device_ptr device); + + usb_device_ptr test_device; + usb_registry registry; +}; + diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp new file mode 100644 index 00000000..78e007d6 --- /dev/null +++ b/reference/windows/USB/usb_device.cpp @@ -0,0 +1,183 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "usb_device.hpp" +#include "usb_error.hpp" +#include "scope.hpp" + +#include + +usb_device::usb_device(const std::wstring& device_path, int vendor_id, int product_id) +: device_path_(device_path), device_handle_(nullptr), interface_handle_(nullptr), + vendor_id_(vendor_id), product_id_(product_id), is_open_(false) { + + //manufacturer_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBVendorString)); + //product_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBProductString)); + //serial_number_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBSerialNumberString)); +} + +usb_device::~usb_device() { + close(); +} + +std::string usb_device::description() const { + + const char* fmt = "VID: 0x%04x, PID: 0x%04x, manufacturer: %s, product: %s, serial: %s"; + int len = snprintf(nullptr, 0, fmt, + vendor_id_, product_id_, manufacturer_.c_str(), product_.c_str(), serial_number_.c_str()); + std::string desc; + desc.resize((size_t) len + 1); + + snprintf(&desc[0], desc.size(), fmt, + vendor_id_, product_id_, manufacturer_.c_str(), product_.c_str(), serial_number_.c_str()); + + return desc; +} + +bool usb_device::is_open() const { + return is_open_; +} + +void usb_device::open() { + if (is_open()) + throw new usb_error("USB device is already open", 0); + + is_open_ = true; +} + +void usb_device::close() { + if (!is_open()) + return; + + if (interface_handle_ != nullptr) + release_interface(); + + is_open_ = false; +} + +void usb_device::claim_interface(int interface_number) { + + if (interface_handle_ != nullptr) + throw usb_error("an interface has already been claimed"); + + auto handle = CreateFileW(device_path_.c_str(), + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE | FILE_SHARE_READ, + nullptr, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + nullptr); + if (handle == INVALID_HANDLE_VALUE) + usb_error::throw_error("Cannot open USB device"); + + + if (!WinUsb_Initialize(handle, &interface_handle_)) { + CloseHandle(handle); + usb_error::throw_error("Cannot open USB device"); + return; + } + + device_handle_ = handle; +} + +void usb_device::release_interface() { + if (interface_handle_ == nullptr) + throw usb_error("no interface has been claimed"); + + if (interface_handle_ != nullptr) { + WinUsb_Free(interface_handle_); + interface_handle_ = nullptr; + } + if (device_handle_ != nullptr) { + CloseHandle(device_handle_); + device_handle_ = nullptr; + } +} + +std::vector usb_device::transfer_in(int endpoint_number, int data_len, int timeout) { + if (interface_handle_ == nullptr) + throw usb_error("no interface has been claimed"); + + UCHAR endpoint_address = endpoint_number + 128; + + ULONG value = timeout; + if (!WinUsb_SetPipePolicy(interface_handle_, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) + usb_error::throw_error("Failed to set endpoint timeout"); + + std::vector data(data_len); + + DWORD len = 0; + if (!WinUsb_ReadPipe(interface_handle_, endpoint_address, static_cast(data.data()), data_len, &len, nullptr)) + usb_error::throw_error("Cannot receive from USB endpoint"); + + data.resize(len); + return data; +} + +void usb_device::transfer_out(int endpoint_number, const std::vector& data, int timeout) { + if (interface_handle_ == nullptr) + throw usb_error("no interface has been claimed"); + + UCHAR endpoint_address = endpoint_number; + + ULONG value = timeout; + if (!WinUsb_SetPipePolicy(interface_handle_, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) + usb_error::throw_error("Failed to set endpoint timeout"); + + DWORD len = 0; + if (!WinUsb_WritePipe(interface_handle_, endpoint_address, const_cast(data.data()), static_cast(data.size()), &len, nullptr)) + usb_error::throw_error("Failed to transmit to USB endpoint"); +} + +int usb_device::control_transfer_core(const usb_control_request &request, uint8_t* data, int timeout) { + + if (!is_open()) + throw usb_error("USB device is not open"); + + ULONG value = timeout; + if (!WinUsb_SetPipePolicy(interface_handle_, 0, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) + usb_error::throw_error("Failed to set endpoint timeout"); + + WINUSB_SETUP_PACKET setup_packet = { 0 }; + setup_packet.RequestType = request.bmRequestType; + setup_packet.Request = request.bRequest; + setup_packet.Value = request.wValue; + setup_packet.Index = request.wIndex; + setup_packet.Length = request.wLength; + + DWORD len = 0; + if (!WinUsb_ControlTransfer(interface_handle_, setup_packet, data, request.wLength, &len, nullptr)) + usb_error::throw_error("Control transfer failed"); + + return len; +} + +void usb_device::control_transfer(const usb_control_request& request, int timeout ) { + if (request.wLength != 0) + throw usb_error("'control_transfer' only supports request without data phase but 'wLength' != 0"); + + control_transfer_core(request, nullptr, timeout); +} + +void usb_device::control_transfer_out(const usb_control_request& request, const std::vector& data, int timeout ) { + if ((request.bmRequestType & 0x80) != 0) + throw usb_error("direction mismatch between 'control_transfer_out' and direction bit in 'bmRequestType'"); + + control_transfer_core(request, const_cast(data.data()), timeout); +} + +std::vector usb_device::control_transfer_in(const usb_control_request& request, int timeout ) { + if ((request.bmRequestType & 0x80) == 0) + throw usb_error("direction mismatch between 'control_transfer_in' and direction bit in 'bmRequestType'"); + + std::vector data(request.wLength); + control_transfer_core(request, data.data(), timeout); + data.resize(request.wLength); + return data; +} diff --git a/reference/windows/USB/usb_device.hpp b/reference/windows/USB/usb_device.hpp new file mode 100644 index 00000000..bc5c9efa --- /dev/null +++ b/reference/windows/USB/usb_device.hpp @@ -0,0 +1,212 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include +#include +#include +#include + +#include +#undef min +#undef max +#undef LowSpeed +#include + + +/** + * USB control request type. + * + * Bitmask values for direction (bit 7), type (bits 6..5) and recipient (bits 4..0) + */ +enum class usb_request_type { + // bit 7 : direction + /// Direction device to host + direction_in = 0x80, + /// Direction host to device + direction_out = 0x00, + // bits 6..5 : type + /// Standard request + type_standard = 0x00, + /// Class-specific request + type_class = 0x20, + /// Vendor-defined request + type_vendor = 0x40, + // bits 4..0 : recipient + /// Request for device + recipient_device = 0x00, + /// Request for interface + recipient_interface = 0x01, + /// Request for endpoint + recipient_endpoint = 0x02, + /// Request for other recipient + recipient_other = 0x03 +}; + + +/** + * USB control request structure. + */ +struct usb_control_request { + /// Request type + uint8_t bmRequestType; + /// Specific request number + uint8_t bRequest; + /// Value (request specific) + uint16_t wValue; + /// Index (request specific) + uint16_t wIndex; + /// Number of bytes to transfer if there is a data stage + uint16_t wLength; + + static uint8_t request_type(usb_request_type direction, usb_request_type type, usb_request_type recipient) { + return static_cast(direction) + static_cast(type) + static_cast(recipient); + } +}; + + +/** + * USB device. + * + * Must be used with `std::shared_ptr`. + */ +class usb_device { +public: + ~usb_device(); + + /// USB vendor ID + int vendor_id() const { return vendor_id_; } + /// USB product ID + int product_id() const { return product_id_; } + /// Manufacturer name + std::string manufacturer() const { return manufacturer_; } + /// Product name + std::string product() const { return product_; } + /// Serial number + std::string serial_number() const { return serial_number_; } + /// Descriptive string including VID, PID, manufacturer, product name and serial number + std::string description() const; + + /// Opens the device for communication + void open(); + + /// Closes the device + void close(); + + /// Indicates if device is open + bool is_open() const; + + /** + * Claims an interface + * + * A single interface can be claimed. + * + * @param interface_number interface number + */ + void claim_interface(int interface_number); + + /** + * Releases the claimed interface. + */ + void release_interface(); + + /** + * Receives data from a bulk or interrupt endpoint. + * + * The amount of bytes read will be influced by the underlying USB packets. + * If a short packet is sent, the function will return after having read fewer bytes + * than specified. The function will fail if a bigger packet has been received than + * will fit into the given buffer. So the specified data length should be big enough for + * the maximum packet size (64 bytes for full-speed USB). + * + * The timeout specifies the maximum time it may take to complete the operation. + * If the operation does not complete within that time, the function returns after reading + * less or no data at all. + * + * Interrupt endpoints do not support timeouts. Thus, 0 has to be specified. + * + * @param endpoint_number endpoint number (between 1 and 127) + * @param data_len maximum length to read (in bytes) + * @param timeout timeout (in ms, 0 for no timeout) + * @return received data + */ + std::vector transfer_in(int endpoint_number, int data_len, int timeout = 0); + + /** + * Transmits data to a bulk or interrupt endpoint. + * + * The timeout specifies the maximum time it may take to complete the operation. + * If the operation does not complete within that time, the function returns after writing + * less or no data at all. + * + * Interrupt endpoints do not support timeouts. Thus, 0 has to be specified. + * + * @param endpoint_number endpoint number (between 1 and 127) + * @param data data to transmit + * @param timeout timeout (in ms, 0 for no timeout) + */ + void transfer_out(int endpoint_number, const std::vector& data, int timeout = 0); + + /** + * Send a control request with no Data phase. + * + * The request is always sent to endpoint 0. + * + * @param request request to send + * @param timeout timeout (in ms, 0 for no timeout) + */ + void control_transfer(const usb_control_request& request, int timeout = 0); + + /** + * Send a control request with a DATA OUT phase. + * + * The request is always sent to endpoint 0. + * + * The length of the passed data vector and `request.wLength` must be equal. + * + * @param request request to send + * @param data buffer containing data to be sent in DATA phase. + * @param timeout timeout (in ms, 0 for no timeout) + */ + void control_transfer_out(const usb_control_request& request, const std::vector& data, int timeout = 0); + + /** + * Send a control request with a DATA IN phase. + * + * The request is always sent to endpoint 0. + * + * The data is received in the specified data buffer. The length of buffer is specified in `request.wLength`. + * + * @param request request to send + * @param timeout timeout (in ms, 0 for no timeout) + * @return received data + */ + std::vector control_transfer_in(const usb_control_request& request, int timeout = 0); + +private: + usb_device(const std::wstring& device_path, int vendor_id, int product_id); + int control_transfer_core(const usb_control_request& request, uint8_t* data, int timeout); + const wchar_t* device_path() { return device_path_.c_str(); } + + std::wstring device_path_; + HANDLE device_handle_; + WINUSB_INTERFACE_HANDLE interface_handle_; + bool is_open_; + + int product_id_; + int vendor_id_; + std::string manufacturer_; + std::string product_; + std::string serial_number_; + + friend class usb_registry; +}; + +typedef std::shared_ptr usb_device_ptr; diff --git a/reference/windows/USB/usb_error.cpp b/reference/windows/USB/usb_error.cpp new file mode 100644 index 00000000..660b3e4c --- /dev/null +++ b/reference/windows/USB/usb_error.cpp @@ -0,0 +1,50 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "usb_error.hpp" + +#include + + +usb_error::usb_error(const char* message, int code) noexcept + : _message(full_message(message, code)), _code(code) { } + +usb_error::~usb_error() noexcept { } + +const char* usb_error::what() const noexcept { + return _message.c_str(); +} + +long usb_error::error_code() { + return _code; +} + +void usb_error::throw_error(const char* message) { + throw usb_error(message, GetLastError()); +} + +std::string usb_error::full_message(const char* message, int code) { + if (code == 0) + return message; + + LPSTR messageBuffer = nullptr; + + size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, code, 0, (LPSTR)&messageBuffer, 0, NULL); + + std::string msg(message); + msg += " ("; + msg.append(messageBuffer, size); + msg += ")"; + + // free the allocated memory + LocalFree(messageBuffer); + + return msg; +} diff --git a/reference/windows/USB/usb_error.hpp b/reference/windows/USB/usb_error.hpp new file mode 100644 index 00000000..ed529720 --- /dev/null +++ b/reference/windows/USB/usb_error.hpp @@ -0,0 +1,44 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include +#include + +/// USB error exception +class usb_error : public std::exception { +public: + /** + * Creates a new instance. + * + *@param message error message + *@param code a Windows error code, or 0 if no Windows code is available + */ + usb_error(const char* message, int code = 0) noexcept; + + virtual ~usb_error() noexcept; + + virtual const char* what() const noexcept; + /// Mach error code + long error_code(); + + /** + * Throws a USB error exception with the `GetLastError()` code. + * + * @param message additional information for the error message + */ + __declspec(noreturn) static void throw_error(const char* message); + +private: + static std::string full_message(const char* message, int code); + + std::string _message; + long _code; +}; diff --git a/reference/windows/USB/usb_registry.cpp b/reference/windows/USB/usb_registry.cpp new file mode 100644 index 00000000..c508e59f --- /dev/null +++ b/reference/windows/USB/usb_registry.cpp @@ -0,0 +1,358 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "usb_registry.hpp" +#include "usb_device.hpp" +#include "usb_error.hpp" +#include "scope.hpp" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#pragma comment (lib, "SetupAPI.lib") +#pragma comment (lib, "Winusb.lib") + + +usb_registry::usb_registry() +: on_connected_callback(nullptr), on_disconnected_callback(nullptr), + is_device_list_ready(false), background_thread_id_(0), message_window(nullptr) { +} + +usb_registry::~usb_registry() { + + SendMessage(message_window, WM_CLOSE, 0, 0); + monitor_thread.join(); + +} + +std::vector usb_registry::get_devices() { + return devices; +} + +void usb_registry::set_on_device_connected(std::function callback) { + on_connected_callback = callback; +} + +void usb_registry::set_on_device_disconnected(std::function callback) { + on_disconnected_callback = callback; +} + +void usb_registry::start() { + monitor_thread = std::thread(&usb_registry::monitor, this); + + std::unique_lock wait_lock(monitor_mutex); + monitor_condition.wait(wait_lock, [this] { return is_device_list_ready; }); +} + +static const LPCWSTR CLASS_NAME = L"USB_MONITOR"; +static const LPCWSTR WINDOW_NAME = L"USB device monitor"; + +void usb_registry::monitor() { + + background_thread_id_ = GetCurrentThreadId(); + HMODULE instance = GetModuleHandleW(nullptr); + + WNDCLASSEXW wx = { 0 }; + wx.cbSize = sizeof(WNDCLASSEX); + wx.lpfnWndProc = handle_windows_message; + wx.hInstance = instance; + wx.lpszClassName = CLASS_NAME; + + ATOM atom = RegisterClassExW(&wx); + if (atom == 0) + usb_error::throw_error("internal error (RegisterClassExW)"); + + auto atom_gard = make_scope_exit([instance]() { UnregisterClassW(CLASS_NAME, instance); }); + + message_window = CreateWindowExW( + 0, + CLASS_NAME, + WINDOW_NAME, + 0, + 0, + 0, + 0, + 0, + HWND_MESSAGE, + nullptr, + instance, + this + ); + if (message_window == nullptr) + usb_error::throw_error("internal error (CreateWindowExW)"); + + DEV_BROADCAST_DEVICEINTERFACE_W notification_filter = { 0 }; + + notification_filter.dbcc_size = sizeof(notification_filter); + notification_filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + notification_filter.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE; + + HDEVNOTIFY notify_handle = RegisterDeviceNotificationW(message_window, ¬ification_filter, DEVICE_NOTIFY_WINDOW_HANDLE /* | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES */); + if (notify_handle == NULL) + usb_error::throw_error("internal error (RegisterDeviceNotificationW)"); + + auto notify_handle_guard = make_scope_exit([notify_handle]() { UnregisterDeviceNotification(notify_handle); }); + + detect_present_devices(); + + is_device_list_ready = true; + monitor_condition.notify_all(); + + MSG msg = { 0 }; + while (GetMessageW(&msg, message_window, 0, 0) > 0) { + std::cout << "GetMessageW" << std::endl; + } +} + +void usb_registry::detect_present_devices() { + + // get device information set of all USB devices present + HDEVINFO dev_info_set_hdl = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (dev_info_set_hdl == INVALID_HANDLE_VALUE) + throw usb_error("internal error (SetupDiGetClassDevsA)", GetLastError()); + + // ensure the result id destroyed when the scope is left + auto dev_info_set_guard = make_scope_exit([dev_info_set_hdl]() { + SetupDiDestroyDeviceInfoList(dev_info_set_hdl); + }); + + SP_DEVINFO_DATA dev_info = { sizeof(dev_info) }; + + // iterate over the set + for (int i = 0; ; i++) { + if (!SetupDiEnumDeviceInfo(dev_info_set_hdl, i, &dev_info)) { + DWORD err = GetLastError(); + if (err == ERROR_NO_MORE_ITEMS) + break; + throw usb_error("Internal error (SetupDiEnumDeviceInfo)", err); + } + + // create new device + auto device = create_device(dev_info_set_hdl, &dev_info); + devices.push_back(device); + } +} + +std::shared_ptr usb_registry::create_device(HDEVINFO dev_info_set_hdl, SP_DEVINFO_DATA* dev_info) { + + DWORD usb_port_num = get_device_property_int(dev_info_set_hdl, dev_info, &DEVPKEY_Device_Address); + std::wstring instance_id = get_device_property_string(dev_info_set_hdl, dev_info, &DEVPKEY_Device_InstanceId); + std::wstring parent_instance_id = get_device_property_string(dev_info_set_hdl, dev_info, &DEVPKEY_Device_Parent); + + std::wstring hub_path = get_device_path(parent_instance_id, &GUID_DEVINTERFACE_USB_HUB); + + // open parent (hub) + HANDLE hub_handle = CreateFileW(hub_path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); + if (hub_handle == INVALID_HANDLE_VALUE) + usb_error::throw_error("Cannot open USB hub"); + + auto hub_handle_guard = make_scope_exit([hub_handle]() { + CloseHandle(hub_handle); + }); + + auto path = get_device_path(instance_id, &GUID_DEVINTERFACE_USB_DEVICE); + + // get device descriptor + USB_NODE_CONNECTION_INFORMATION_EX conn_info = { 0 }; + conn_info.ConnectionIndex = usb_port_num; + DWORD size = 0; + if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, sizeof(conn_info), &conn_info, sizeof(conn_info), &size, nullptr)) + usb_error::throw_error("Internal error (cannot get device descriptor)"); + + // Create new device + std::shared_ptr device(new usb_device(path, conn_info.DeviceDescriptor.idVendor, conn_info.DeviceDescriptor.idProduct)); + return device; +} + +LRESULT usb_registry::handle_windows_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + + usb_registry* self = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); + + switch (uMsg) { + case WM_CREATE: { + CREATESTRUCT* cs = reinterpret_cast(lParam); + self = reinterpret_cast(cs->lpCreateParams); + SetLastError(ERROR_SUCCESS); + LONG_PTR result = SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast(self)); + break; + } + + case WM_DESTROY: { + LONG_PTR result = SetWindowLongPtr(hWnd, GWLP_USERDATA, NULL); + PostQuitMessage(0); + break; + } + } + + if (self != nullptr && self->handle_message(hWnd, uMsg, wParam, lParam)) + return NULL; + + return DefWindowProcW(hWnd, uMsg, wParam, lParam); +} + +bool usb_registry::handle_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + if (uMsg != WM_DEVICECHANGE) + return false; + if (wParam != DBT_DEVICEARRIVAL && wParam != DBT_DEVICEREMOVECOMPLETE) + return false; + DEV_BROADCAST_HDR* header = reinterpret_cast(lParam); + if (header->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE) + return false; + + DEV_BROADCAST_DEVICEINTERFACE_W* broadcast = reinterpret_cast(lParam); + if (wParam == DBT_DEVICEARRIVAL) { + on_device_connected(broadcast->dbcc_name); + } + else { + on_device_disconnected(broadcast->dbcc_name); + } + return true; +} + +void usb_registry::on_device_connected(const WCHAR* path) { + // get as set of all USB devices present + HDEVINFO dev_info_set_hdl = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (dev_info_set_hdl == INVALID_HANDLE_VALUE) + usb_error::throw_error("internal error (SetupDiGetClassDevsW)"); + + // ensure the result is destroyed when the scope is left + auto dev_info_set_guard = make_scope_exit([dev_info_set_hdl]() { + SetupDiDestroyDeviceInfoList(dev_info_set_hdl); + }); + + SP_DEVICE_INTERFACE_DATA dev_intf_data = { sizeof(dev_intf_data) }; + if (!SetupDiOpenDeviceInterfaceW(dev_info_set_hdl, path, 0, &dev_intf_data)) + usb_error::throw_error("internal error (SetupDiOpenDeviceInterfaceW)"); + + auto dev_intf_data_guard = make_scope_exit([dev_info_set_hdl, &dev_intf_data]() { + SetupDiDeleteDeviceInterfaceData(dev_info_set_hdl, &dev_intf_data); + }); + + SP_DEVINFO_DATA dev_info = { sizeof(dev_info) }; + if (!SetupDiGetDeviceInterfaceDetailW(dev_info_set_hdl, &dev_intf_data, nullptr, 0, nullptr, &dev_info)) { + DWORD err = GetLastError(); + if (err != ERROR_INSUFFICIENT_BUFFER) + throw usb_error("internal error (SetupDiGetDeviceInterfaceDetailW)", err); + } + + // create new device + auto device = create_device(dev_info_set_hdl, &dev_info); + devices.push_back(device); + + // Call callback function + if (on_connected_callback != nullptr) { + try { + on_connected_callback(device); + } + catch (const std::exception& e) { + std::cerr << "Unhandled exception: " << e.what() << std::endl; + } + catch (...) { + std::cerr << "Unhandled exception (not derived from std::exception)" << std::endl; + } + } +} + +void usb_registry::on_device_disconnected(const WCHAR* path) { + + // find device in device list + auto it = std::find_if(devices.cbegin(), devices.cend(), [path](auto device) { return lstrcmpiW(path, device->device_path()) == 0; }); + if (it == devices.cend()) + return; // not part of the device list + + // remove from device list + usb_device_ptr device = *it; + devices.erase(it); + + // call callback function + if (on_disconnected_callback != nullptr) { + try { + on_disconnected_callback(device); + } + catch (const std::exception& e) { + std::cerr << "Unhandled exception: " << e.what() << std::endl; + } + catch (...) { + std::cerr << "Unhandled exception (not derived from std::exception)" << std::endl; + } + } +} + +uint32_t usb_registry::get_device_property_int(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { + // query property value + DEVPROPTYPE property_type; + uint32_t property_value = -1; + if (!SetupDiGetDevicePropertyW(dev_info, dev_info_data, prop_key, &property_type, reinterpret_cast(&property_value), sizeof(property_value), nullptr, 0)) + usb_error::throw_error("internal error (SetupDiGetDevicePropertyW)"); + + // check property type + if (property_type != DEVPROP_TYPE_UINT32) + throw usb_error("internal error (SetupDiGetDevicePropertyW)"); + + return property_value; +} + +std::wstring usb_registry::get_device_property_string(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { + + // query length + DWORD required_size = 0; + DEVPROPTYPE property_type; + if (!SetupDiGetDevicePropertyW(dev_info, dev_info_data, prop_key, &property_type, nullptr, 0, &required_size, 0)) { + DWORD err = GetLastError(); + if (err != ERROR_INSUFFICIENT_BUFFER) + throw usb_error("internal error (SetupDiGetDevicePropertyW)", err); + } + + // check property type + if (property_type != DEVPROP_TYPE_STRING) + throw usb_error("internal error (SetupDiGetDevicePropertyW)"); + + // query property value + std::wstring property_value; + property_value.resize(required_size / sizeof(WCHAR)); + if (!SetupDiGetDevicePropertyW(dev_info, dev_info_data, prop_key, &property_type, reinterpret_cast(&property_value[0]), required_size, nullptr, 0)) + usb_error::throw_error("internal error (SetupDiGetDevicePropertyW)"); + + return property_value; +} + +std::wstring usb_registry::get_device_path(const std::wstring& instance_id, const GUID* interface_guid) { + + // get device info set for instance + HDEVINFO dev_info_set_hdl = SetupDiGetClassDevsW(interface_guid, instance_id.c_str(), nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (dev_info_set_hdl == INVALID_HANDLE_VALUE) + usb_error::throw_error("internal error (SetupDiGetClassDevsW)"); + + // ensure the result is destroyed when the scope is left + auto dev_info_set_guard = make_scope_exit([dev_info_set_hdl]() { + SetupDiDestroyDeviceInfoList(dev_info_set_hdl); + }); + + // retrieve first element of enumeration + SP_DEVICE_INTERFACE_DATA dev_intf_data = { sizeof(dev_intf_data) }; + if (!SetupDiEnumDeviceInterfaces(dev_info_set_hdl, nullptr, interface_guid, 0, &dev_intf_data)) + usb_error::throw_error("internal error (SetupDiEnumDeviceInterfaces)"); + + // retrieve path + uint8_t dev_path_buf[MAX_PATH * sizeof(WCHAR) + sizeof(DWORD)]; + memset(dev_path_buf, 0, sizeof(dev_path_buf)); + PSP_DEVICE_INTERFACE_DETAIL_DATA_W intf_detail_data = reinterpret_cast(dev_path_buf); + intf_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); + if (!SetupDiGetDeviceInterfaceDetailW(dev_info_set_hdl, &dev_intf_data, intf_detail_data, sizeof(dev_path_buf), nullptr, nullptr)) + throw usb_error("Internal error (SetupDiGetDeviceInterfaceDetailA)", GetLastError()); + + return intf_detail_data->DevicePath; +} \ No newline at end of file diff --git a/reference/windows/USB/usb_registry.hpp b/reference/windows/USB/usb_registry.hpp new file mode 100644 index 00000000..5b2d967f --- /dev/null +++ b/reference/windows/USB/usb_registry.hpp @@ -0,0 +1,76 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include "usb_device.hpp" + +#include +#include +#include +#include +#include +#include + +#include +#undef min +#undef max +#undef LowSpeed +#include + +/** + * Registry of connected USB devices. + */ +class usb_registry { +public: + /// Create a new instance + usb_registry(); + ~usb_registry(); + + /// Sets a function to be called when a new device is connected. + void set_on_device_connected(std::function callback); + /// Sets a function to be called when a device is disconnected + void set_on_device_disconnected(std::function callback); + + /// Starts the registry + void start(); + + /// Gets the currently connected devices. + std::vector> get_devices(); + +private: + /// Method run in background to monitor USB devices + void monitor(); + + void detect_present_devices(); + + void on_device_connected(const WCHAR* path); + void on_device_disconnected(const WCHAR* path); + + bool handle_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + static LRESULT handle_windows_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + std::shared_ptr create_device(HDEVINFO dev_info_set_hdl, SP_DEVINFO_DATA* dev_info); + + static uint32_t get_device_property_int(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key); + static std::wstring get_device_property_string(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key); + static std::wstring get_device_path(const std::wstring& instance_id, const GUID* interface_guid); + + std::vector devices; + + std::function on_connected_callback; + std::function on_disconnected_callback; + + std::thread monitor_thread; + + bool is_device_list_ready; + std::mutex monitor_mutex; + std::condition_variable monitor_condition; + DWORD background_thread_id_; + HWND message_window; +}; diff --git a/reference/windows/windows.sln b/reference/windows/windows.sln new file mode 100644 index 00000000..fe2e778f --- /dev/null +++ b/reference/windows/windows.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32804.467 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "USB", "USB\USB.vcxproj", "{31927336-B5D2-44B6-AAAA-EAF79E673087}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {31927336-B5D2-44B6-AAAA-EAF79E673087}.Debug|x64.ActiveCfg = Debug|x64 + {31927336-B5D2-44B6-AAAA-EAF79E673087}.Debug|x64.Build.0 = Debug|x64 + {31927336-B5D2-44B6-AAAA-EAF79E673087}.Debug|x86.ActiveCfg = Debug|Win32 + {31927336-B5D2-44B6-AAAA-EAF79E673087}.Debug|x86.Build.0 = Debug|Win32 + {31927336-B5D2-44B6-AAAA-EAF79E673087}.Release|x64.ActiveCfg = Release|x64 + {31927336-B5D2-44B6-AAAA-EAF79E673087}.Release|x64.Build.0 = Release|x64 + {31927336-B5D2-44B6-AAAA-EAF79E673087}.Release|x86.ActiveCfg = Release|Win32 + {31927336-B5D2-44B6-AAAA-EAF79E673087}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1507F032-6C02-4585-9120-EE4104CB0FAC} + EndGlobalSection +EndGlobal From 75ec6c556f08c24cf21c1b613519e19f46613211 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Thu, 22 Sep 2022 20:14:06 +0200 Subject: [PATCH 096/433] Compatibility with Windows code --- reference/macos/USB/tests.cpp | 11 +++++----- reference/macos/USB/usb_registry.cpp | 2 +- reference/macos/usb.xcodeproj/project.pbxproj | 22 ++++++++++--------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/reference/macos/USB/tests.cpp b/reference/macos/USB/tests.cpp index b16dbc80..6b53c83f 100644 --- a/reference/macos/USB/tests.cpp +++ b/reference/macos/USB/tests.cpp @@ -13,8 +13,8 @@ #include #include -using random_bytes_engine = std::independent_bits_engine< - std::default_random_engine, CHAR_BIT, unsigned char>; +using random_ushort_engine = std::independent_bits_engine< + std::default_random_engine, 16, unsigned short>; void tests::run() { @@ -149,10 +149,11 @@ void tests::on_device_disconnected(usb_device_ptr device) { } std::vector tests::random_bytes(int num) { - random_bytes_engine rbe; - std::vector data(num); + random_ushort_engine rbe; + std::vector data((num + 1) / 2); std::generate(begin(data), end(data), std::ref(rbe)); - return data; + const uint8_t* p = reinterpret_cast(data.data()); + return std::vector(p, p + num); } diff --git a/reference/macos/USB/usb_registry.cpp b/reference/macos/USB/usb_registry.cpp index 2158ad6c..bee6b975 100644 --- a/reference/macos/USB/usb_registry.cpp +++ b/reference/macos/USB/usb_registry.cpp @@ -59,7 +59,7 @@ void usb_registry::set_on_device_disconnected(std::function wait_lock(monitor_mutex); monitor_condition.wait(wait_lock, [this] { return is_device_list_ready; }); } diff --git a/reference/macos/usb.xcodeproj/project.pbxproj b/reference/macos/usb.xcodeproj/project.pbxproj index ccdc03d9..6028251f 100644 --- a/reference/macos/usb.xcodeproj/project.pbxproj +++ b/reference/macos/usb.xcodeproj/project.pbxproj @@ -83,20 +83,20 @@ 64937C6228D5EBF1009BD0C2 /* USB */ = { isa = PBXGroup; children = ( - 64937C6C28D5ED1F009BD0C2 /* iokit_helper.cpp */, + 64937C8328D71D31009BD0C2 /* assertion.hpp */, + 64937C8228D71D31009BD0C2 /* assertion.cpp */, 64937C6D28D5ED1F009BD0C2 /* iokit_helper.hpp */, - 64937C6F28D5ED1F009BD0C2 /* scope.hpp */, - 64937C6B28D5ED1F009BD0C2 /* usb_registry.cpp */, - 64937C6E28D5ED1F009BD0C2 /* usb_registry.hpp */, + 64937C6C28D5ED1F009BD0C2 /* iokit_helper.cpp */, 64937C6328D5EBF1009BD0C2 /* main.cpp */, - 64937C7428D5ED8D009BD0C2 /* usb_error.cpp */, + 64937C6F28D5ED1F009BD0C2 /* scope.hpp */, + 64937C8028D6F9DE009BD0C2 /* tests.hpp */, + 64937C7F28D6F9DE009BD0C2 /* tests.cpp */, 64937C7528D5ED8D009BD0C2 /* usb_error.hpp */, - 64937C7728D5FE6D009BD0C2 /* usb_device.cpp */, + 64937C7428D5ED8D009BD0C2 /* usb_error.cpp */, 64937C7828D5FE6D009BD0C2 /* usb_device.hpp */, - 64937C7F28D6F9DE009BD0C2 /* tests.cpp */, - 64937C8028D6F9DE009BD0C2 /* tests.hpp */, - 64937C8228D71D31009BD0C2 /* assertion.cpp */, - 64937C8328D71D31009BD0C2 /* assertion.hpp */, + 64937C7728D5FE6D009BD0C2 /* usb_device.cpp */, + 64937C6E28D5ED1F009BD0C2 /* usb_registry.hpp */, + 64937C6B28D5ED1F009BD0C2 /* usb_registry.cpp */, ); path = USB; sourceTree = ""; @@ -292,6 +292,7 @@ 64937C6828D5EBF1009BD0C2 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 4H9ZA7X4C4; ENABLE_HARDENED_RUNTIME = YES; @@ -302,6 +303,7 @@ 64937C6928D5EBF1009BD0C2 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 4H9ZA7X4C4; ENABLE_HARDENED_RUNTIME = YES; From 671e61ad45866f5fcd2d42d3704b287ff58915e3 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 22 Sep 2022 23:35:09 +0200 Subject: [PATCH 097/433] Linux reference code --- reference/linux/.gitignore | 12 ++ reference/linux/.vscode/settings.json | 58 +++++++ reference/linux/CMakeLists.txt | 22 +++ reference/linux/assertion.cpp | 56 +++++++ reference/linux/assertion.hpp | 27 +++ reference/linux/main.cpp | 15 ++ reference/linux/scope.hpp | 52 ++++++ reference/linux/tests.cpp | 162 ++++++++++++++++++ reference/linux/tests.hpp | 36 ++++ reference/linux/usb_device.cpp | 173 +++++++++++++++++++ reference/linux/usb_device.hpp | 205 +++++++++++++++++++++++ reference/linux/usb_error.cpp | 43 +++++ reference/linux/usb_error.hpp | 44 +++++ reference/linux/usb_registry.cpp | 228 ++++++++++++++++++++++++++ reference/linux/usb_registry.hpp | 67 ++++++++ 15 files changed, 1200 insertions(+) create mode 100644 reference/linux/.gitignore create mode 100644 reference/linux/.vscode/settings.json create mode 100644 reference/linux/CMakeLists.txt create mode 100644 reference/linux/assertion.cpp create mode 100644 reference/linux/assertion.hpp create mode 100644 reference/linux/main.cpp create mode 100644 reference/linux/scope.hpp create mode 100644 reference/linux/tests.cpp create mode 100644 reference/linux/tests.hpp create mode 100644 reference/linux/usb_device.cpp create mode 100644 reference/linux/usb_device.hpp create mode 100644 reference/linux/usb_error.cpp create mode 100644 reference/linux/usb_error.hpp create mode 100644 reference/linux/usb_registry.cpp create mode 100644 reference/linux/usb_registry.hpp diff --git a/reference/linux/.gitignore b/reference/linux/.gitignore new file mode 100644 index 00000000..7098f773 --- /dev/null +++ b/reference/linux/.gitignore @@ -0,0 +1,12 @@ +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps +build/ diff --git a/reference/linux/.vscode/settings.json b/reference/linux/.vscode/settings.json new file mode 100644 index 00000000..9eac4d83 --- /dev/null +++ b/reference/linux/.vscode/settings.json @@ -0,0 +1,58 @@ +{ + "files.associations": { + "cstdio": "cpp", + "string": "cpp", + "condition_variable": "cpp", + "system_error": "cpp", + "iostream": "cpp", + "cstdlib": "cpp", + "mutex": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "cinttypes": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "ratio": "cpp", + "string_view": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "semaphore": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "typeinfo": "cpp" + } +} \ No newline at end of file diff --git a/reference/linux/CMakeLists.txt b/reference/linux/CMakeLists.txt new file mode 100644 index 00000000..925a2428 --- /dev/null +++ b/reference/linux/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.10) + +project(linux) + +set (CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) + +set(SOURCES + assertion.cpp assertion.hpp + main.cpp + scope.hpp + tests.cpp tests.hpp + usb_device.cpp usb_device.hpp + usb_error.cpp usb_error.hpp + usb_registry.cpp usb_registry.hpp +) + +add_executable(linux_usb ${SOURCES}) +target_link_libraries(linux_usb Threads::Threads) +target_link_libraries(linux_usb -ludev) diff --git a/reference/linux/assertion.cpp b/reference/linux/assertion.cpp new file mode 100644 index 00000000..4e3111b5 --- /dev/null +++ b/reference/linux/assertion.cpp @@ -0,0 +1,56 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "assertion.hpp" + +#include +#include + +static void failed(const char* check, const char* message) { + if (message == nullptr) + message = "Check failed"; + std::cerr << message << ": " << check << std::endl; + throw new check_failed_error(); +} + +void assert_equals(int expected, int actual, const char* message) { + if (actual != expected) { + char buf[50]; + snprintf(buf, sizeof(buf), "expected: %d, actual: %d", expected, actual); + failed(buf, message); + } +} + +void assert_equals(long expected, long actual, const char* message) { + if (actual != expected) { + char buf[50]; + snprintf(buf, sizeof(buf), "expected: %ld, actual: %ld", expected, actual); + failed(buf, message); + } +} + +void assert_equals(unsigned long expected, unsigned long actual, const char* message) { + if (actual != expected) { + char buf[50]; + snprintf(buf, sizeof(buf), "expected: %lud, actual: %lud", expected, actual); + failed(buf, message); + } +} + +void assert_equals(const std::vector& expected, const std::vector& actual, const char* message) { + assert_equals(expected.size(), actual.size(), message); + for (int i = 0; i < expected.size(); i++) { + assert_equals(expected[i], actual[i], message); + } +} + + +check_failed_error::check_failed_error() noexcept { } +check_failed_error::~check_failed_error() noexcept { } +const char* check_failed_error::what() const noexcept { return "check failed"; } diff --git a/reference/linux/assertion.hpp b/reference/linux/assertion.hpp new file mode 100644 index 00000000..1d763e13 --- /dev/null +++ b/reference/linux/assertion.hpp @@ -0,0 +1,27 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include +#include +#include + + +void assert_equals(int expected, int actual, const char* message = nullptr); +void assert_equals(long expected, long actual, const char* message = nullptr); +void assert_equals(unsigned long expected, unsigned long actual, const char* message = nullptr); +void assert_equals(const std::vector& expected, const std::vector& actual, const char* message = nullptr); + +class check_failed_error : public std::exception { +public: + check_failed_error() noexcept; + virtual ~check_failed_error() noexcept; + virtual const char* what() const noexcept; +}; diff --git a/reference/linux/main.cpp b/reference/linux/main.cpp new file mode 100644 index 00000000..64e85de5 --- /dev/null +++ b/reference/linux/main.cpp @@ -0,0 +1,15 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "tests.hpp" + +int main(int argc, const char * argv[]) { + tests t; + t.run(); +} diff --git a/reference/linux/scope.hpp b/reference/linux/scope.hpp new file mode 100644 index 00000000..53e3e39f --- /dev/null +++ b/reference/linux/scope.hpp @@ -0,0 +1,52 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include + +template +class scope_exit +{ +public: + template + explicit scope_exit(Fn&& fn) noexcept + : exit_fn(std::forward(fn)), exec_on_destruction(true) + { } + + scope_exit(scope_exit&& other) noexcept + : exit_fn(std::forward(other.exit_fn)), + exec_on_destruction(other.exec_on_destruction) + { + other.release(); + } + + ~scope_exit() noexcept { + if (exec_on_destruction) + exit_fn(); + } + + void release() noexcept { + exec_on_destruction = false; + } + + scope_exit(scope_exit const&) = delete; + + scope_exit& operator=(scope_exit const&) = delete; + scope_exit& operator=(scope_exit&&) = delete; + +private: + EF exit_fn; + bool exec_on_destruction; +}; + +template +scope_exit::type> make_scope_exit(EF&& exit_function) { + return scope_exit::type>(std::forward(exit_function)); +} diff --git a/reference/linux/tests.cpp b/reference/linux/tests.cpp new file mode 100644 index 00000000..6b53c83f --- /dev/null +++ b/reference/linux/tests.cpp @@ -0,0 +1,162 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "tests.hpp" +#include "assertion.hpp" + +#include +#include + +using random_ushort_engine = std::independent_bits_engine< + std::default_random_engine, 16, unsigned short>; + + +void tests::run() { + registry.start(); + + for (auto device : registry.get_devices()) { + std::cout << "Present: " << device->description() << std::endl; + } + + registry.set_on_device_connected([this](auto device) { on_device_connected(device); }); + registry.set_on_device_disconnected([this](auto device) { on_device_disconnected(device); }); + + for (auto device : registry.get_devices()) + on_device(device); + + std::cout << "Press RETURN to quit" << std::endl; + std::string line; + std::getline(std::cin, line); +} + +void tests::test_current_device() { + std::cout << "Found test device" << std::endl; + test_device->open(); + test_device->claim_interface(0); + + test_control_transfers(); + test_bulk_transfers(); + + test_device->release_interface(); + test_device->close(); + std::cout << "Test completed" << std::endl; +} + +void tests::test_control_transfers() { + usb_control_request request_set_value_no_data = { + .bmRequestType = usb_control_request::request_type(usb_request_type::direction_out, + usb_request_type::type_vendor, + usb_request_type::recipient_interface), + .bRequest = 0x01, + .wValue = 0x9a41, + .wIndex = 0, // interface number + .wLength = 0 + }; + test_device->control_transfer(request_set_value_no_data); + + usb_control_request request_get_data = { + .bmRequestType = usb_control_request::request_type(usb_request_type::direction_in, + usb_request_type::type_vendor, + usb_request_type::recipient_interface), + .bRequest = 0x03, + .wValue = 0, + .wIndex = 0, // interface number + .wLength = 4 + }; + auto data = test_device->control_transfer_in(request_get_data); + std::vector expected_data{ 0x41, 0x9a, 0x00, 0x00 }; + assert_equals(expected_data, data); + + std::vector sent_value{ 0x83, 0x03, 0xda, 0x3d }; + usb_control_request request_set_value_data = { + .bmRequestType = usb_control_request::request_type(usb_request_type::direction_out, + usb_request_type::type_vendor, + usb_request_type::recipient_interface), + .bRequest = 0x02, + .wValue = 0, + .wIndex = 0, // interface number + .wLength = static_cast(sent_value.size()) + }; + test_device->control_transfer_out(request_set_value_data, sent_value); + + data = test_device->control_transfer_in(request_get_data); + assert_equals(sent_value, data); +} + +void tests::test_bulk_transfers() { + test_loopback(12); + test_loopback(130); + test_loopback(123709); +} + +void tests::test_loopback(int num_bytes) { + + // generate random bytes + auto random_data = random_bytes(num_bytes); + + // prepare vector for receiving data + std::vector rx_data; + rx_data.reserve(num_bytes); + + // read in separate thread + std::thread reader([this, &rx_data, num_bytes]() { + int bytes_read = 0; + while (bytes_read < num_bytes) { + auto data = test_device->transfer_in(2, 64); + rx_data.insert(rx_data.end(), data.begin(), data.end()); + bytes_read += data.size(); + } + }); + + // send rand bytes in chunks + const int chunk_size = 100; + int bytes_written = 0; + while (bytes_written < num_bytes) { + int size = std::min(chunk_size, num_bytes - bytes_written); + std::vector chunk = {random_data.begin() + bytes_written, random_data.begin() + bytes_written + size}; + test_device->transfer_out(1, chunk); + bytes_written += size; + } + + // wait for reader + reader.join(); + + // check result + assert_equals(random_data, rx_data); +} + +void tests::on_device(usb_device_ptr device) { + if (is_test_device(device)) { + test_device = device; + test_current_device(); + test_device = nullptr; + } +} + +void tests::on_device_connected(usb_device_ptr device) { + std::cout << "Connected: " << device->description() << std::endl; + on_device(device); +} + +void tests::on_device_disconnected(usb_device_ptr device) { + std::cout << "Disconnected: " << device->description() << std::endl; +} + +std::vector tests::random_bytes(int num) { + random_ushort_engine rbe; + std::vector data((num + 1) / 2); + std::generate(begin(data), end(data), std::ref(rbe)); + const uint8_t* p = reinterpret_cast(data.data()); + return std::vector(p, p + num); +} + + +bool tests::is_test_device(usb_device_ptr device) { + return device->vendor_id() == 0xcafe && device->product_id() == 0xceaf; +} diff --git a/reference/linux/tests.hpp b/reference/linux/tests.hpp new file mode 100644 index 00000000..992de2b9 --- /dev/null +++ b/reference/linux/tests.hpp @@ -0,0 +1,36 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include "usb_device.hpp" +#include "usb_registry.hpp" + +class tests { +public: + void run(); + +private: + void test_current_device(); + void test_control_transfers(); + void test_bulk_transfers(); + + void test_loopback(int num_bytes); + + void on_device(usb_device_ptr device); + void on_device_connected(usb_device_ptr device); + void on_device_disconnected(usb_device_ptr device); + + static std::vector random_bytes(int num); + static bool is_test_device(usb_device_ptr device); + + usb_device_ptr test_device; + usb_registry registry; +}; + diff --git a/reference/linux/usb_device.cpp b/reference/linux/usb_device.cpp new file mode 100644 index 00000000..8a3322fd --- /dev/null +++ b/reference/linux/usb_device.cpp @@ -0,0 +1,173 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "usb_device.hpp" +#include "usb_error.hpp" +#include "scope.hpp" + +#include +#include +#include +#include + +#include + +usb_device::usb_device(const char* path, int vendor_id, int product_id) +: path_(path), fd_(-1), claimed_interface_(-1), vendor_id_(vendor_id), product_id_(product_id) { + + +// manufacturer_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBVendorString)); +// product_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBProductString)); +// serial_number_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBSerialNumberString)); +} + +usb_device::~usb_device() { + if (is_open()) + close(); +} + +std::string usb_device::description() const { + + const char* fmt = "VID: 0x%04x, PID: 0x%04x, manufacturer: %s, product: %s, serial: %s"; + int len = snprintf(nullptr, 0, fmt, + vendor_id_, product_id_, manufacturer_.c_str(), product_.c_str(), serial_number_.c_str()); + std::string desc; + desc.resize(len + 1); + + snprintf(&desc[0], desc.size(), fmt, + vendor_id_, product_id_, manufacturer_.c_str(), product_.c_str(), serial_number_.c_str()); + + return desc; +} + +bool usb_device::is_open() const { + return fd_ >= 0; +} + +void usb_device::open() { + if (is_open()) + throw usb_error("USB device is already open", 0); + + fd_ = ::open(path_.c_str(), O_RDWR | O_CLOEXEC); + if (fd_ == -1) + usb_error::throw_error("Cannot open USB device"); +} + +void usb_device::close() { + if (!is_open()) + return; + + if (claimed_interface_ >= 0) + release_interface(); + + int ret = ::close(fd_); + if (ret != 0) + usb_error::throw_error("unable to close USB device"); +} + +void usb_device::claim_interface(int interface_number) { + + if (claimed_interface_ >= 0) + throw usb_error("an interface has already been claimed"); + + int result = ioctl(fd_, USBDEVFS_CLAIMINTERFACE, &interface_number); + if (result < 0) + usb_error::throw_error("Failed to claim interface 0"); + + claimed_interface_ = interface_number; +} + +void usb_device::release_interface() { + if (claimed_interface_ < 0) + throw usb_error("no interface has been claimed"); + + int result = ioctl(fd_, USBDEVFS_RELEASEINTERFACE, &claimed_interface_); + if (result < 0) + usb_error::throw_error("Failed to release interface"); + + claimed_interface_ = -1; +} + +std::vector usb_device::transfer_in(int endpoint_number, int data_len, int timeout) { + if (claimed_interface_ < 0) + throw usb_error("no interface has been claimed"); + + std::vector data(data_len); + + struct usbdevfs_bulktransfer transfer = {0}; + transfer.ep = endpoint_number + 128; + transfer.len = data_len; + transfer.timeout = timeout; + transfer.data = data.data(); + + int result = ioctl(fd_, USBDEVFS_BULK, &transfer); + if (result < 0) + usb_error::throw_error("error receiving from USB endpoint"); + + return data; +} + +void usb_device::transfer_out(int endpoint_number, const std::vector& data, int timeout) { + if (claimed_interface_ < 0) + throw usb_error("no interface has been claimed"); + + struct usbdevfs_bulktransfer transfer = {0}; + transfer.ep = endpoint_number; + transfer.len = data.size(); + transfer.timeout = timeout; + transfer.data = const_cast(data.data()); + + int result = ioctl(fd_, USBDEVFS_BULK, &transfer); + if (result < 0) + usb_error::throw_error("error transmitting to USB endpoint"); +} + +int usb_device::control_transfer_core(const usb_control_request &request, uint8_t* data, int timeout) { + + if (!is_open()) + throw usb_error("USB device is not open"); + + struct usbdevfs_ctrltransfer ctrl_request = {0}; + ctrl_request.bRequestType = request.bmRequestType; + ctrl_request.bRequest = request.bRequest; + ctrl_request.wValue = request.wValue; + ctrl_request.wIndex = request.wIndex; + ctrl_request.wLength = request.wLength; + ctrl_request.timeout = timeout; + + int result = ioctl(fd_, USBDEVFS_CONTROL, &ctrl_request); + if (result < 0) + usb_error::throw_error("error sending control request"); + + return result; +} + +void usb_device::control_transfer(const usb_control_request& request, int timeout ) { + if (request.wLength != 0) + throw usb_error("'control_transfer' only supports request without data phase but 'wLength' != 0"); + + control_transfer_core(request, nullptr, timeout); +} + +void usb_device::control_transfer_out(const usb_control_request& request, const std::vector& data, int timeout ) { + if ((request.bmRequestType & 0x80) != 0) + throw usb_error("direction mismatch between 'control_transfer_out' and direction bit in 'bmRequestType'"); + + control_transfer_core(request, const_cast(data.data()), timeout); +} + +std::vector usb_device::control_transfer_in(const usb_control_request& request, int timeout ) { + if ((request.bmRequestType & 0x80) == 0) + throw usb_error("direction mismatch between 'control_transfer_in' and direction bit in 'bmRequestType'"); + + std::vector data(request.wLength); + control_transfer_core(request, data.data(), timeout); + data.resize(request.wLength); + return data; +} diff --git a/reference/linux/usb_device.hpp b/reference/linux/usb_device.hpp new file mode 100644 index 00000000..30a27445 --- /dev/null +++ b/reference/linux/usb_device.hpp @@ -0,0 +1,205 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include +#include +#include +#include + + +/** + * USB control request type. + * + * Bitmask values for direction (bit 7), type (bits 6..5) and recipient (bits 4..0) + */ +enum class usb_request_type { + // bit 7 : direction + /// Direction device to host + direction_in = 0x80, + /// Direction host to device + direction_out = 0x00, + // bits 6..5 : type + /// Standard request + type_standard = 0x00, + /// Class-specific request + type_class = 0x20, + /// Vendor-defined request + type_vendor = 0x40, + // bits 4..0 : recipient + /// Request for device + recipient_device = 0x00, + /// Request for interface + recipient_interface = 0x01, + /// Request for endpoint + recipient_endpoint = 0x02, + /// Request for other recipient + recipient_other = 0x03 +}; + + +/** + * USB control request structure. + */ +struct usb_control_request { + /// Request type + uint8_t bmRequestType; + /// Specific request number + uint8_t bRequest; + /// Value (request specific) + uint16_t wValue; + /// Index (request specific) + uint16_t wIndex; + /// Number of bytes to transfer if there is a data stage + uint16_t wLength; + + static uint8_t request_type(usb_request_type direction, usb_request_type type, usb_request_type recipient) { + return static_cast(direction) + static_cast(type) + static_cast(recipient); + } +}; + + +/** + * USB device. + * + * Must be used with `std::shared_ptr`. + */ +class usb_device { +public: + ~usb_device(); + + /// USB vendor ID + int vendor_id() const { return vendor_id_; } + /// USB product ID + int product_id() const { return product_id_; } + /// Manufacturer name + std::string manufacturer() const { return manufacturer_; } + /// Product name + std::string product() const { return product_; } + /// Serial number + std::string serial_number() const { return serial_number_; } + /// Descriptive string including VID, PID, manufacturer, product name and serial number + std::string description() const; + + /// Opens the device for communication + void open(); + + /// Closes the device + void close(); + + /// Indicates if device is open + bool is_open() const; + + /** + * Claims an interface + * + * A single interface can be claimed. + * + * @param interface_number interface number + */ + void claim_interface(int interface_number); + + /** + * Releases the claimed interface. + */ + void release_interface(); + + /** + * Receives data from a bulk or interrupt endpoint. + * + * The amount of bytes read will be influced by the underlying USB packets. + * If a short packet is sent, the function will return after having read fewer bytes + * than specified. The function will fail if a bigger packet has been received than + * will fit into the given buffer. So the specified data length should be big enough for + * the maximum packet size (64 bytes for full-speed USB). + * + * The timeout specifies the maximum time it may take to complete the operation. + * If the operation does not complete within that time, the function returns after reading + * less or no data at all. + * + * Interrupt endpoints do not support timeouts. Thus, 0 has to be specified. + * + * @param endpoint_number endpoint number (between 1 and 127) + * @param data_len maximum length to read (in bytes) + * @param timeout timeout (in ms, 0 for no timeout) + * @return received data + */ + std::vector transfer_in(int endpoint_number, int data_len, int timeout = 0); + + /** + * Transmits data to a bulk or interrupt endpoint. + * + * The timeout specifies the maximum time it may take to complete the operation. + * If the operation does not complete within that time, the function returns after writing + * less or no data at all. + * + * Interrupt endpoints do not support timeouts. Thus, 0 has to be specified. + * + * @param endpoint_number endpoint number (between 1 and 127) + * @param data data to transmit + * @param timeout timeout (in ms, 0 for no timeout) + */ + void transfer_out(int endpoint_number, const std::vector& data, int timeout = 0); + + /** + * Send a control request with no Data phase. + * + * The request is always sent to endpoint 0. + * + * @param request request to send + * @param timeout timeout (in ms, 0 for no timeout) + */ + void control_transfer(const usb_control_request& request, int timeout = 0); + + /** + * Send a control request with a DATA OUT phase. + * + * The request is always sent to endpoint 0. + * + * The length of the passed data vector and `request.wLength` must be equal. + * + * @param request request to send + * @param data buffer containing data to be sent in DATA phase. + * @param timeout timeout (in ms, 0 for no timeout) + */ + void control_transfer_out(const usb_control_request& request, const std::vector& data, int timeout = 0); + + /** + * Send a control request with a DATA IN phase. + * + * The request is always sent to endpoint 0. + * + * The data is received in the specified data buffer. The length of buffer is specified in `request.wLength`. + * + * @param request request to send + * @param timeout timeout (in ms, 0 for no timeout) + * @return received data + */ + std::vector control_transfer_in(const usb_control_request& request, int timeout = 0); + +private: + usb_device(const char* path, int vendor_id, int product_id); + const char* path() const { return path_.c_str(); } + int control_transfer_core(const usb_control_request& request, uint8_t* data, int timeout); + + std::string path_; + int fd_; + int claimed_interface_; + + int product_id_; + int vendor_id_; + std::string manufacturer_; + std::string product_; + std::string serial_number_; + + friend class usb_registry; +}; + +typedef std::shared_ptr usb_device_ptr; diff --git a/reference/linux/usb_error.cpp b/reference/linux/usb_error.cpp new file mode 100644 index 00000000..8228ba2d --- /dev/null +++ b/reference/linux/usb_error.cpp @@ -0,0 +1,43 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "usb_error.hpp" + +#include +#include + + +usb_error::usb_error(const char* message, int code) noexcept + : _message(full_message(message, code)), _code(code) { } + +usb_error::~usb_error() noexcept { } + +const char* usb_error::what() const noexcept { + return _message.c_str(); +} + +long usb_error::error_code() { + return _code; +} + +void usb_error::throw_error(const char* message) { + throw usb_error(message, errno); +} + +std::string usb_error::full_message(const char* message, int code) { + if (code == 0) + return message; + + std::string msg(message); + msg += " ("; + msg += strerror(code); + msg += ")"; + + return msg; +} diff --git a/reference/linux/usb_error.hpp b/reference/linux/usb_error.hpp new file mode 100644 index 00000000..f1a846db --- /dev/null +++ b/reference/linux/usb_error.hpp @@ -0,0 +1,44 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include +#include + +/// USB error exception +class usb_error : public std::exception { +public: + /** + * Creates a new instance. + * + *@param message error message + *@param code a Mach error code, or 0 if no Mach code is available + */ + usb_error(const char* message, int code = 0) noexcept; + + virtual ~usb_error() noexcept; + + virtual const char* what() const noexcept; + /// Mach error code + long error_code(); + + /** + * Throws a USB error exception using `errno` as the error code. + * + * @param message additional information for the error message + */ + static void throw_error(const char* message); + +private: + static std::string full_message(const char* message, int code); + + std::string _message; + long _code; +}; diff --git a/reference/linux/usb_registry.cpp b/reference/linux/usb_registry.cpp new file mode 100644 index 00000000..784ea172 --- /dev/null +++ b/reference/linux/usb_registry.cpp @@ -0,0 +1,228 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#include "usb_registry.hpp" +#include "usb_device.hpp" +#include "usb_error.hpp" +#include "scope.hpp" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +usb_registry::usb_registry() +: wake_event_fd(-1), + on_connected_callback(nullptr), on_disconnected_callback(nullptr), + is_device_list_ready(false) { +} + +usb_registry::~usb_registry() { + eventfd_write(wake_event_fd, 1); + monitor_thread.join(); + ::close(wake_event_fd); +} + +std::vector usb_registry::get_devices() { + return devices; +} + +void usb_registry::set_on_device_connected(std::function callback) { + on_connected_callback = callback; +} + +void usb_registry::set_on_device_disconnected(std::function callback) { + on_disconnected_callback = callback; +} + +void usb_registry::start() { + wake_event_fd = eventfd(0, 0); + if (wake_event_fd < 0) + usb_error::throw_error("internal error(eventfd)"); + + monitor_thread = std::thread(&usb_registry::monitor, this); + + std::unique_lock wait_lock(monitor_mutex); + monitor_condition.wait(wait_lock, [this] { return is_device_list_ready; }); +} + +void usb_registry::monitor() { + + udev* udev = udev_new(); + if (udev == nullptr) + throw usb_error("internal error (udev_new)"); + + auto udev_guard = make_scope_exit([udev]() { udev_unref(udev); }); + + udev_monitor* monitor = udev_monitor_new_from_netlink(udev, "udev"); + if (monitor == nullptr) + throw usb_error("internal error (udev_monitor_new_from_netlink)"); + + auto monitor_guard = make_scope_exit([monitor]() { udev_monitor_unref(monitor); }); + + if (udev_monitor_filter_add_match_subsystem_devtype(monitor, "usb", "usb_device") < 0) + throw usb_error("internal error (udev_monitor_filter_add_match_subsystem_devtype)"); + + if (udev_monitor_enable_receiving(monitor) < 0) + throw usb_error("internal error (udev_monitor_enable_receiving)"); + + int monitor_fd = udev_monitor_get_fd(monitor); + if (monitor_fd < 0) + throw usb_error("internal error (udev_monitor_get_fd)"); + + enumerate_present_devices(udev); + + is_device_list_ready = true; + monitor_condition.notify_all(); + + while (true) { + + pollfd fds[2]; + fds[0].fd = monitor_fd; + fds[0].events = POLLIN; + fds[1].fd = wake_event_fd; + fds[1].events = POLLIN; + + int ret = poll(fds, 2, -1); + if (ret < 0) + usb_error::throw_error("internal error (poll)"); + + if ((fds[1].revents & POLLIN) != 0) + break; + + // get affected device + udev_device* device = udev_monitor_receive_device(monitor); + if (device == nullptr) + continue; // shouldn't happen + + auto device_guard = make_scope_exit([device]() { udev_device_unref(device); }); + + const char* action = udev_device_get_action(device); + if (strcmp("add", action) == 0) { + on_device_connected(device); + } else if (strcmp("remove", action) == 0) { + on_device_disconnected(device); + } + } +} + +void usb_registry::on_device_connected(udev_device* udev_dev) { + + usb_device_ptr device = create_device(udev_dev); + if (!device) + return; + + devices.push_back(device); + + if (on_connected_callback != nullptr) { + try { + on_connected_callback(device); + } catch (usb_error& e) { + std::cerr << "Unhandled exception on device connect: " << e.what() << std::endl; + } catch (...) { + std::cerr << "Unhandled exception on device connect." << std::endl; + } + } +} + +void usb_registry::on_device_disconnected(udev_device* udev_dev) { + + const char* path = udev_device_get_devnode(udev_dev); + if (path == nullptr) + throw usb_error("internal error (udev_device_get_devnode)"); + + // find device in device list + auto it = std::find_if(devices.cbegin(), devices.cend(), [path](auto dev) { return strcmp(dev->path(), path) == 0; }); + if (it == devices.cend()) + return; // not part of the device list + + // remove from device list + usb_device_ptr device = *it; + devices.erase(it); + + // call callback function + if (on_disconnected_callback != nullptr) { + try { + on_disconnected_callback(device); + } catch (usb_error& e) { + std::cerr << "Unhandled exception on device disconnect: " << e.what() << std::endl; + } catch (...) { + std::cerr << "Unhandled exception on device disconnect." << std::endl; + } + } +} + +void usb_registry::enumerate_present_devices(udev* udev) { + + udev_enumerate* enumerate = udev_enumerate_new(udev); + if (enumerate == nullptr) + throw usb_error("internal error (udev_enumerate_new)"); + + auto enumerate_guard = make_scope_exit([enumerate]() { udev_enumerate_unref(enumerate); }); + + if (udev_enumerate_add_match_subsystem(enumerate, "usb") < 0) + throw usb_error("internal error (udev_enumerate_add_match_subsystem)"); + + if (udev_enumerate_scan_devices(enumerate) < 0) + throw usb_error("internal error (udev_enumerate_scan_devices)"); + + for (udev_list_entry* entry = udev_enumerate_get_list_entry(enumerate); + entry != nullptr; + entry = udev_list_entry_get_next(entry)) { + + const char* path = udev_list_entry_get_name(entry); + if (path == nullptr) + continue; + + // get device handle + udev_device* udev_dev = udev_device_new_from_syspath(udev, path); + if (udev_dev == nullptr) + continue; + + auto udev_dev_guard = make_scope_exit([udev_dev]() { udev_device_unref(udev_dev); }); + + // create device + usb_device_ptr device = create_device(udev_dev); + if (device) + devices.push_back(device); + } +} + +std::shared_ptr usb_registry::create_device(udev_device* udev_dev) { + int vendor_id = 0; + int product_id = 0; + + const char* vendor_id_str = udev_device_get_sysattr_value(udev_dev, "idVendor"); + if (vendor_id_str == nullptr) + return nullptr; + + const char* product_id_str = udev_device_get_sysattr_value(udev_dev, "idProduct"); + if (product_id_str == nullptr) + return nullptr; + + const char* path = udev_device_get_devnode(udev_dev); + if (path == nullptr) + return nullptr; + + vendor_id = strtol(vendor_id_str, nullptr, 16); + product_id = strtol(product_id_str, nullptr, 16); + + if (vendor_id == 0 || product_id == 0) + return nullptr; + + return std::shared_ptr(new usb_device(path, vendor_id, product_id)); +} diff --git a/reference/linux/usb_registry.hpp b/reference/linux/usb_registry.hpp new file mode 100644 index 00000000..c17384d2 --- /dev/null +++ b/reference/linux/usb_registry.hpp @@ -0,0 +1,67 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for macOS +// + +#pragma once + +#include "usb_device.hpp" + +#include +#include +#include +#include +#include +#include + +struct udev; +struct udev_device; + + +/** + * Registry of connected USB devices. + */ +class usb_registry { +public: + /// Create a new instance + usb_registry(); + ~usb_registry(); + + /// Sets a function to be called when a new device is connected. + void set_on_device_connected(std::function callback); + /// Sets a function to be called when a device is disconnected + void set_on_device_disconnected(std::function callback); + + /// Starts the registry + void start(); + + /// Gets the currently connected devices. + std::vector> get_devices(); + +private: + /// Method run in background to monitor USB devices + void monitor(); + void enumerate_present_devices(udev* udev); + + void on_device_connected(udev_device* udev_dev); + void on_device_disconnected(udev_device* udev_dev); + + std::shared_ptr create_device(udev_device* udev_dev); + + std::vector devices; + + std::function on_connected_callback; + std::function on_disconnected_callback; + + std::thread monitor_thread; + + int wake_event_fd; + + bool is_device_list_ready; + std::mutex monitor_mutex; + std::condition_variable monitor_condition; +}; From 50f76110834ce4455065ffa44f52464696452742 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 23 Sep 2022 08:43:15 +0200 Subject: [PATCH 098/433] Fixes for Linux reference code --- reference/linux/usb_device.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/reference/linux/usb_device.cpp b/reference/linux/usb_device.cpp index 8a3322fd..711ad252 100644 --- a/reference/linux/usb_device.cpp +++ b/reference/linux/usb_device.cpp @@ -20,11 +20,6 @@ usb_device::usb_device(const char* path, int vendor_id, int product_id) : path_(path), fd_(-1), claimed_interface_(-1), vendor_id_(vendor_id), product_id_(product_id) { - - -// manufacturer_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBVendorString)); -// product_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBProductString)); -// serial_number_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBSerialNumberString)); } usb_device::~usb_device() { @@ -67,6 +62,7 @@ void usb_device::close() { release_interface(); int ret = ::close(fd_); + fd_ = -1; if (ret != 0) usb_error::throw_error("unable to close USB device"); } @@ -110,6 +106,7 @@ std::vector usb_device::transfer_in(int endpoint_number, int data_len, if (result < 0) usb_error::throw_error("error receiving from USB endpoint"); + data.resize(result); return data; } @@ -140,6 +137,7 @@ int usb_device::control_transfer_core(const usb_control_request &request, uint8_ ctrl_request.wIndex = request.wIndex; ctrl_request.wLength = request.wLength; ctrl_request.timeout = timeout; + ctrl_request.data = data; int result = ioctl(fd_, USBDEVFS_CONTROL, &ctrl_request); if (result < 0) From d0e28842c65c35c110941308d544e2140f92cd0d Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 23 Sep 2022 09:02:44 +0200 Subject: [PATCH 099/433] Linux: replace select() with poll() --- java-does-usb/jextract/linux/gen_linux.sh | 15 ++-- .../usb/linux/LinuxUSBDeviceRegistry.java | 18 ++--- .../gen/{select => poll}/Constants$root.java | 2 +- .../gen/{select => poll}/RuntimeHelper.java | 2 +- .../usb/linux/gen/poll/constants$0.java | 20 +++++ .../{select/select.java => poll/poll.java} | 19 +++-- .../codecrete/usb/linux/gen/poll/pollfd.java | 73 +++++++++++++++++++ .../usb/linux/gen/select/constants$0.java | 22 ------ .../usb/linux/gen/select/fd_set.java | 25 ------- 9 files changed, 123 insertions(+), 73 deletions(-) rename java-does-usb/src/main/java/net/codecrete/usb/linux/gen/{select => poll}/Constants$root.java (94%) rename java-does-usb/src/main/java/net/codecrete/usb/linux/gen/{select => poll}/RuntimeHelper.java (99%) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java rename java-does-usb/src/main/java/net/codecrete/usb/linux/gen/{select/select.java => poll/poll.java} (62%) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/fd_set.java diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index ce4b94c1..cd7ece06 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -54,6 +54,7 @@ $JEXTRACT --source --output ../../src/main/java \ /usr/include/linux/usbdevice_fs.h # libudev.h +# (install libudev-dev if file is missing) $JEXTRACT --source --output ../../src/main/java \ --header-class-name udev \ --target-package net.codecrete.usb.linux.gen.udev \ @@ -79,10 +80,12 @@ $JEXTRACT --source --output ../../src/main/java \ --include-function udev_monitor_get_fd \ /usr/include/libudev.h -# select.h +# poll.h $JEXTRACT --source --output ../../src/main/java \ - --header-class-name select \ - --target-package net.codecrete.usb.linux.gen.select \ - --include-function select \ - --include-typedef fd_set \ - /usr/include/x86_64-linux-gnu/sys/select.h + --header-class-name poll \ + --target-package net.codecrete.usb.linux.gen.poll \ + --include-function poll \ + --include-struct pollfd \ + --include-macro POLLIN \ + /usr/include/poll.h + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 2a793579..3827d975 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -10,8 +10,8 @@ import net.codecrete.usb.USBDevice; import net.codecrete.usb.USBException; import net.codecrete.usb.common.USBDeviceRegistry; -import net.codecrete.usb.linux.gen.select.fd_set; -import net.codecrete.usb.linux.gen.select.select; +import net.codecrete.usb.linux.gen.poll.poll; +import net.codecrete.usb.linux.gen.poll.pollfd; import net.codecrete.usb.linux.gen.udev.udev; import java.lang.foreign.Addressable; @@ -22,7 +22,6 @@ import java.util.List; import static java.lang.foreign.MemoryAddress.NULL; -import static java.lang.foreign.ValueLayout.JAVA_LONG; /** * Linux implementation of USB device registry. @@ -229,12 +228,11 @@ private static String getDeviceAction(Addressable udevDevice) { * @param session a memory session for allocating memory */ private static void waitForFileDescriptor(int fd, MemorySession session) { - // fd_set is a bit array (constructed from 64-bit integers) - var fds = session.allocate(fd_set.$LAYOUT()); - fds.set(JAVA_LONG, fd / JAVA_LONG.bitSize(), 1L << (fd % JAVA_LONG.bitSize())); - - int res = select.select(fd + 1, fds, NULL, NULL, NULL); - if (res <= 0) - throw new USBException("internal error (select)"); + var fds = session.allocate(pollfd.$LAYOUT()); + pollfd.fd$set(fds, fd); + pollfd.events$set(fds, (short) poll.POLLIN()); + int res = poll.poll(fds, 1, -1); + if (res < 0) + throw new USBException("internal error (poll)"); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/Constants$root.java similarity index 94% rename from java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/Constants$root.java rename to java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/Constants$root.java index bd53659c..80ad3009 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/Constants$root.java @@ -1,6 +1,6 @@ // Generated by jextract -package net.codecrete.usb.linux.gen.select; +package net.codecrete.usb.linux.gen.poll; import static java.lang.foreign.ValueLayout.*; public class Constants$root { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/RuntimeHelper.java similarity index 99% rename from java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/RuntimeHelper.java rename to java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/RuntimeHelper.java index a634735c..e5aded55 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/RuntimeHelper.java @@ -1,4 +1,4 @@ -package net.codecrete.usb.linux.gen.select; +package net.codecrete.usb.linux.gen.poll; // Generated by jextract import java.lang.foreign.*; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java new file mode 100644 index 00000000..5ec525aa --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.poll; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor poll$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle poll$MH = RuntimeHelper.downcallHandle( + "poll", + constants$0.poll$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/select.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java similarity index 62% rename from java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/select.java rename to java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java index 85ed94b2..22cd1353 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/select.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java @@ -1,14 +1,14 @@ // Generated by jextract -package net.codecrete.usb.linux.gen.select; +package net.codecrete.usb.linux.gen.poll; import java.lang.foreign.Addressable; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; -public class select { +public class poll { - /* package-private */ select() {} + /* package-private */ poll() {} public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; public static OfInt C_INT = Constants$root.C_INT$LAYOUT; @@ -17,13 +17,16 @@ public class select { public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; - public static MethodHandle select$MH() { - return RuntimeHelper.requireNonNull(constants$0.select$MH,"select"); + public static int POLLIN() { + return (int)1L; } - public static int select ( int __nfds, Addressable __readfds, Addressable __writefds, Addressable __exceptfds, Addressable __timeout) { - var mh$ = select$MH(); + public static MethodHandle poll$MH() { + return RuntimeHelper.requireNonNull(constants$0.poll$MH,"poll"); + } + public static int poll ( Addressable __fds, long __nfds, int __timeout) { + var mh$ = poll$MH(); try { - return (int)mh$.invokeExact(__nfds, __readfds, __writefds, __exceptfds, __timeout); + return (int)mh$.invokeExact(__fds, __nfds, __timeout); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java new file mode 100644 index 00000000..b96bf436 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java @@ -0,0 +1,73 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.poll; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class pollfd { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_INT$LAYOUT.withName("fd"), + Constants$root.C_SHORT$LAYOUT.withName("events"), + Constants$root.C_SHORT$LAYOUT.withName("revents") + ).withName("pollfd"); + public static MemoryLayout $LAYOUT() { + return pollfd.$struct$LAYOUT; + } + static final VarHandle fd$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("fd")); + public static VarHandle fd$VH() { + return pollfd.fd$VH; + } + public static int fd$get(MemorySegment seg) { + return (int)pollfd.fd$VH.get(seg); + } + public static void fd$set( MemorySegment seg, int x) { + pollfd.fd$VH.set(seg, x); + } + public static int fd$get(MemorySegment seg, long index) { + return (int)pollfd.fd$VH.get(seg.asSlice(index*sizeof())); + } + public static void fd$set(MemorySegment seg, long index, int x) { + pollfd.fd$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle events$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("events")); + public static VarHandle events$VH() { + return pollfd.events$VH; + } + public static short events$get(MemorySegment seg) { + return (short)pollfd.events$VH.get(seg); + } + public static void events$set( MemorySegment seg, short x) { + pollfd.events$VH.set(seg, x); + } + public static short events$get(MemorySegment seg, long index) { + return (short)pollfd.events$VH.get(seg.asSlice(index*sizeof())); + } + public static void events$set(MemorySegment seg, long index, short x) { + pollfd.events$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle revents$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("revents")); + public static VarHandle revents$VH() { + return pollfd.revents$VH; + } + public static short revents$get(MemorySegment seg) { + return (short)pollfd.revents$VH.get(seg); + } + public static void revents$set( MemorySegment seg, short x) { + pollfd.revents$VH.set(seg, x); + } + public static short revents$get(MemorySegment seg, long index) { + return (short)pollfd.revents$VH.get(seg.asSlice(index*sizeof())); + } + public static void revents$set(MemorySegment seg, long index, short x) { + pollfd.revents$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/constants$0.java deleted file mode 100644 index 1e095f2b..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/constants$0.java +++ /dev/null @@ -1,22 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.select; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -class constants$0 { - - static final FunctionDescriptor select$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle select$MH = RuntimeHelper.downcallHandle( - "select", - constants$0.select$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/fd_set.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/fd_set.java deleted file mode 100644 index 2a321b89..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/select/fd_set.java +++ /dev/null @@ -1,25 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.select; - -import java.lang.foreign.*; -public class fd_set { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - MemoryLayout.sequenceLayout(16, Constants$root.C_LONG_LONG$LAYOUT).withName("__fds_bits") - ); - public static MemoryLayout $LAYOUT() { - return fd_set.$struct$LAYOUT; - } - public static MemorySegment __fds_bits$slice(MemorySegment seg) { - return seg.asSlice(0, 128); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - From 82df4918152671811e2fae2d6cbcefbff1092761 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 23 Sep 2022 14:07:49 +0200 Subject: [PATCH 100/433] Refactor device descriptor code --- .../usb/common/DeviceDescriptor.java | 110 ++++++++++++++++++ .../codecrete/usb/common/USBDescriptors.java | 45 ------- .../codecrete/usb/common/USBDeviceImpl.java | 60 ++++++++-- .../codecrete/usb/linux/LinuxUSBDevice.java | 28 ++--- .../usb/linux/LinuxUSBDeviceRegistry.java | 6 +- .../codecrete/usb/macos/MacosUSBDevice.java | 4 +- .../usb/macos/MacosUSBDeviceRegistry.java | 4 +- .../net/codecrete/usb/windows/USBHelper.java | 23 ++-- .../usb/windows/WindowsUSBDevice.java | 4 +- .../usb/windows/WindowsUSBDeviceRegistry.java | 29 ++--- 10 files changed, 198 insertions(+), 115 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/DeviceDescriptor.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/DeviceDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/common/DeviceDescriptor.java new file mode 100644 index 00000000..c5a305e6 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/DeviceDescriptor.java @@ -0,0 +1,110 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.MemoryLayout.structLayout; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; + +public class DeviceDescriptor { + + private final MemorySegment descriptor; + + public DeviceDescriptor(MemorySegment descriptor) { + this.descriptor = descriptor; + } + + public int bcdUSB() { + return 0xffff & (short) bcdUSB$VH.get(descriptor); + } + + public int bDeviceClass() { + return 0xff & (byte) bDeviceClass$VH.get(descriptor); + } + + public int bDeviceSubClass() { + return 0xff & (byte) bDeviceSubClass$VH.get(descriptor); + } + + public int bDeviceProtocol() { + return 0xff & (byte) bDeviceProtocol$VH.get(descriptor); + } + + public int idVendor() { + return 0xffff & (short) idVendor$VH.get(descriptor); + } + + public int idProduct() { + return 0xffff & (short) idProduct$VH.get(descriptor); + } + + public int bcdDevice() { + return 0xffff & (short) bcdDevice$VH.get(descriptor); + } + + public int iManufacturer() { + return 0xffff & (short) iManufacturer$VH.get(descriptor); + } + + public int iProduct() { + return 0xffff & (short) iProduct$VH.get(descriptor); + } + + public int iSerialNumber() { + return 0xffff & (short) iSerialNumber$VH.get(descriptor); + } + + // typedef struct { + // UCHAR bLength; + // UCHAR bDescriptorType; + // USHORT bcdUSB; + // UCHAR bDeviceClass; + // UCHAR bDeviceSubClass; + // UCHAR bDeviceProtocol; + // UCHAR bMaxPacketSize0; + // USHORT idVendor; + // USHORT idProduct; + // USHORT bcdDevice; + // UCHAR iManufacturer; + // UCHAR iProduct; + // UCHAR iSerialNumber; + // UCHAR bNumConfigurations; + //} __attribute__((packed)); + public static final GroupLayout LAYOUT = structLayout( + JAVA_BYTE.withName("bLength"), + JAVA_BYTE.withName("bDescriptorType"), + JAVA_SHORT.withName("bcdUSB"), + JAVA_BYTE.withName("bDeviceClass"), + JAVA_BYTE.withName("bDeviceSubClass"), + JAVA_BYTE.withName("bDeviceProtocol"), + JAVA_BYTE.withName("bMaxPacketSize0"), + JAVA_SHORT.withName("idVendor"), + JAVA_SHORT.withName("idProduct"), + JAVA_SHORT.withName("bcdDevice"), + JAVA_BYTE.withName("iManufacturer"), + JAVA_BYTE.withName("iProduct"), + JAVA_BYTE.withName("iSerialNumber"), + JAVA_BYTE.withName("bNumConfigurations") + ); + + private static final VarHandle bcdUSB$VH = LAYOUT.varHandle(groupElement("bcdUSB")); + private static final VarHandle bDeviceClass$VH = LAYOUT.varHandle(groupElement("bDeviceClass")); + private static final VarHandle bDeviceSubClass$VH = LAYOUT.varHandle(groupElement("bDeviceSubClass")); + private static final VarHandle bDeviceProtocol$VH = LAYOUT.varHandle(groupElement("bDeviceProtocol")); + private static final VarHandle idVendor$VH = LAYOUT.varHandle(groupElement("idVendor")); + private static final VarHandle idProduct$VH = LAYOUT.varHandle(groupElement("idProduct")); + private static final VarHandle bcdDevice$VH = LAYOUT.varHandle(groupElement("bcdDevice")); + private static final VarHandle iManufacturer$VH = LAYOUT.varHandle(groupElement("iManufacturer")); + private static final VarHandle iProduct$VH = LAYOUT.varHandle(groupElement("iProduct")); + private static final VarHandle iSerialNumber$VH = LAYOUT.varHandle(groupElement("iSerialNumber")); +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java index 2ead6d77..0ff60844 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java @@ -43,50 +43,6 @@ public class USBDescriptors { public static final short DEFAULT_LANGUAGE = 0x0409; - // typedef struct { - // UCHAR bLength; - // UCHAR bDescriptorType; - // USHORT bcdUSB; - // UCHAR bDeviceClass; - // UCHAR bDeviceSubClass; - // UCHAR bDeviceProtocol; - // UCHAR bMaxPacketSize0; - // USHORT idVendor; - // USHORT idProduct; - // USHORT bcdDevice; - // UCHAR iManufacturer; - // UCHAR iProduct; - // UCHAR iSerialNumber; - // UCHAR bNumConfigurations; - //} __attribute__((packed)); - public static final GroupLayout Device$Struct = structLayout( - JAVA_BYTE.withName("bLength"), - JAVA_BYTE.withName("bDescriptorType"), - JAVA_SHORT.withName("bcdUSB"), - JAVA_BYTE.withName("bDeviceClass"), - JAVA_BYTE.withName("bDeviceSubClass"), - JAVA_BYTE.withName("bDeviceProtocol"), - JAVA_BYTE.withName("bMaxPacketSize0"), - JAVA_SHORT.withName("idVendor"), - JAVA_SHORT.withName("idProduct"), - JAVA_SHORT.withName("bcdDevice"), - JAVA_BYTE.withName("iManufacturer"), - JAVA_BYTE.withName("iProduct"), - JAVA_BYTE.withName("iSerialNumber"), - JAVA_BYTE.withName("bNumConfigurations") - ); - - public static final VarHandle Device_bcdUSB = Device$Struct.varHandle(groupElement("bcdUSB")); - public static final VarHandle Device_bDeviceClass = Device$Struct.varHandle(groupElement("bDeviceClass")); - public static final VarHandle Device_bDeviceSubClass = Device$Struct.varHandle(groupElement("bDeviceSubClass")); - public static final VarHandle Device_bDeviceProtocol = Device$Struct.varHandle(groupElement("bDeviceProtocol")); - public static final VarHandle Device_idVendor = Device$Struct.varHandle(groupElement("idVendor")); - public static final VarHandle Device_idProduct = Device$Struct.varHandle(groupElement("idProduct")); - public static final VarHandle Device_bcdDevice = Device$Struct.varHandle(groupElement("bcdDevice")); - public static final VarHandle Device_iManufacturer = Device$Struct.varHandle(groupElement("iManufacturer")); - public static final VarHandle Device_iProduct = Device$Struct.varHandle(groupElement("iProduct")); - public static final VarHandle Device_iSerialNumber = Device$Struct.varHandle(groupElement("iSerialNumber")); - // struct USBConfigurationDescriptor //{ // uint8_t bLength; @@ -174,7 +130,6 @@ public class USBDescriptors { static { - assert Device$Struct.byteSize() == 18; assert Configuration.byteSize() == 9; assert Interface.byteSize() == 9; assert Endpoint.byteSize() == 7; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 8eb1446b..ee74b527 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -9,17 +9,19 @@ import net.codecrete.usb.*; +import java.lang.foreign.MemorySegment; import java.util.Collections; import java.util.List; +import java.util.function.Function; public abstract class USBDeviceImpl implements USBDevice { protected final Object id_; protected final int vendorId_; protected final int productId_; - protected final String manufacturer_; - protected final String product_; - protected final String serialNumber_; + protected String manufacturer_; + protected String product_; + protected String serialNumber_; protected int classCode_; protected int subclassCode_; protected int protocolCode_; @@ -34,21 +36,14 @@ public abstract class USBDeviceImpl implements USBDevice { * @param id unique device ID * @param vendorId USB vendor ID * @param productId USB product ID - * @param manufacturer manufacturer name - * @param product product name - * @param serialNumber serial number */ - protected USBDeviceImpl(Object id, int vendorId, int productId, String manufacturer, String product, - String serialNumber) { + protected USBDeviceImpl(Object id, int vendorId, int productId) { assert id != null; id_ = id; vendorId_ = vendorId; productId_ = productId; - manufacturer_ = manufacturer; - product_ = product; - serialNumber_ = serialNumber; } @Override @@ -115,6 +110,49 @@ public Object getUniqueId() { return id_; } + /** + * Sets the class codes and version for the device descriptor. + * @param descriptor the device descriptor + */ + public void setFromDeviceDescriptor(MemorySegment descriptor) { + var deviceDescriptor = new DeviceDescriptor(descriptor); + classCode_ = deviceDescriptor.bDeviceClass() & 255; + subclassCode_ = deviceDescriptor.bDeviceSubClass() & 255; + protocolCode_ = deviceDescriptor.bDeviceProtocol() & 255; + usbVersion_ = new Version(deviceDescriptor.bcdUSB()); + deviceVersion_ = new Version(deviceDescriptor.bcdDevice()); + + } + + /** + * Set the product strings. + * + * @param manufacturer manufacturer name + * @param product product name + * @param serialNumber serial number + */ + public void setProductStrings(String manufacturer, String product, String serialNumber) { + manufacturer_ = manufacturer; + product_ = product; + serialNumber_ = serialNumber; + } + + /** + * Sets the product strings from the device descriptor. + *

+ * To lookup the string, a lookup function is provided. It takes the + * string ID and returns the string from the string descriptor. + *

+ * @param descriptor device descriptor + * @param stringLookup string lookup function + */ + public void setProductString(MemorySegment descriptor, Function stringLookup) { + var deviceDescriptor = new DeviceDescriptor(descriptor); + manufacturer_ = stringLookup.apply(deviceDescriptor.iManufacturer()); + product_ = stringLookup.apply(deviceDescriptor.iProduct()); + serialNumber_ = stringLookup.apply(deviceDescriptor.iSerialNumber()); + } + public void setClassCodes(int classCode, int subclassCode, int protocolCode) { classCode_ = classCode; subclassCode_ = subclassCode; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index fcae2330..fcce94ca 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -11,10 +11,7 @@ import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBException; import net.codecrete.usb.USBTransferType; -import net.codecrete.usb.common.DescriptorParser; -import net.codecrete.usb.common.USBDescriptors; -import net.codecrete.usb.common.USBDeviceImpl; -import net.codecrete.usb.common.USBInterfaceImpl; +import net.codecrete.usb.common.*; import net.codecrete.usb.linux.gen.fcntl.fcntl; import net.codecrete.usb.linux.gen.ioctl.ioctl; import net.codecrete.usb.linux.gen.unistd.unistd; @@ -34,8 +31,8 @@ public class LinuxUSBDevice extends USBDeviceImpl { private int fd = -1; - LinuxUSBDevice(Object id, int vendorId, int productId, String manufacturer, String product, String serial) { - super(id, vendorId, productId, manufacturer, product, serial); + LinuxUSBDevice(Object id, int vendorId, int productId) { + super(id, vendorId, productId); loadDescription((String) id); } @@ -53,22 +50,15 @@ private void loadDescription(String path) { try (var session = MemorySession.openConfined()) { var descriptorsSegment = MemorySegment.ofArray(descriptors); - // separate device descriptor (and copy it to fix alignment issues) - var deviceDesc = session.allocate(USBDescriptors.Device$Struct); - deviceDesc.copyFrom(descriptorsSegment.asSlice(0, USBDescriptors.Device$Struct.byteSize())); + // split off device descriptor (and copy it to fix alignment issues) + var deviceDesc = session.allocate(DeviceDescriptor.LAYOUT); + deviceDesc.copyFrom(descriptorsSegment.asSlice(0, DeviceDescriptor.LAYOUT.byteSize())); - int classCode = 255 & (byte) USBDescriptors.Device_bDeviceClass.get(deviceDesc); - int subclassCode = 255 & (byte) USBDescriptors.Device_bDeviceSubClass.get(deviceDesc); - int protocolCode = 255 & (byte) USBDescriptors.Device_bDeviceProtocol.get(deviceDesc); - setClassCodes(classCode, subclassCode, protocolCode); + setFromDeviceDescriptor(deviceDesc); - var usbVersion = (short) USBDescriptors.Device_bcdUSB.get(deviceDesc); - var deviceVersion = (short) USBDescriptors.Device_bcdDevice.get(deviceDesc); - setVersions(usbVersion, deviceVersion); - - // skip device descriptor + // skip to configuration descriptor var configDesc = session.allocateArray(JAVA_BYTE, descriptors.length - 18); - configDesc.copyFrom(descriptorsSegment.asSlice(USBDescriptors.Device$Struct.byteSize())); + configDesc.copyFrom(descriptorsSegment.asSlice(DeviceDescriptor.LAYOUT.byteSize())); var configuration = DescriptorParser.parseConfigurationDescriptor(configDesc, vendorId(), productId()); setInterfaces(configuration.interfaces); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 3827d975..6c9bd1b5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -190,9 +190,13 @@ private static USBDevice getDeviceDetails(MemoryAddress udevDevice) { productId = Integer.parseInt(idProduct, 16); // create device instance - return new LinuxUSBDevice(devPath, vendorId, productId, getDeviceAttribute(udevDevice, "manufacturer"), + var device = new LinuxUSBDevice(devPath, vendorId, productId); + + device.setProductStrings(getDeviceAttribute(udevDevice, "manufacturer"), getDeviceAttribute(udevDevice, "product"), getDeviceAttribute(udevDevice, "serial")); + return device; + } catch (Throwable e) { System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device 0x%04x/0x%04x - " + "ignoring device%n", vendorId, productId); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index af2b69fb..5a2f9146 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -36,8 +36,8 @@ public class MacosUSBDevice extends USBDeviceImpl { private List claimedInterfaces; private Map endpoints; - MacosUSBDevice(MemoryAddress device, Object id, int vendorId, int productId, String manufacturer, String product, String serial) { - super(id, vendorId, productId, manufacturer, product, serial); + MacosUSBDevice(MemoryAddress device, Object id, int vendorId, int productId) { + super(id, vendorId, productId); this.device = device; loadDescription(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index dc8b5d75..c9848989 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -150,11 +150,13 @@ private USBDevice createDevice(Long entryID, int service, MemoryAddress deviceIn info.vid = vendorId; info.pid = productId; + var device = new MacosUSBDevice(deviceIntf, entryID, vendorId, productId); + String manufacturer = IoKitHelper.getPropertyString(service, "kUSBVendorString"); String product = IoKitHelper.getPropertyString(service, "kUSBProductString"); String serial = IoKitHelper.getPropertyString(service, "kUSBSerialNumberString"); - var device = new MacosUSBDevice(deviceIntf, entryID, vendorId, productId, manufacturer, product, serial); + device.setProductStrings(manufacturer, product, serial); Integer classCode = IoKitHelper.getPropertyInt(service, "bDeviceClass"); Integer subclassCode = IoKitHelper.getPropertyInt(service, "bDeviceSubClass"); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java index c0c84fdc..08eaa124 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java @@ -7,7 +7,7 @@ package net.codecrete.usb.windows; -import net.codecrete.usb.common.USBDescriptors; +import net.codecrete.usb.common.DeviceDescriptor; import net.codecrete.usb.common.USBStructs; import java.lang.foreign.GroupLayout; @@ -44,11 +44,15 @@ public class USBHelper { // USB_CONNECTION_STATUS ConnectionStatus;/* OUTPUT */ // USB_PIPE_INFO PipeList[0];/* OUTPUT */ //} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; - public static final GroupLayout USB_NODE_CONNECTION_INFORMATION_EX$Struct = structLayout(JAVA_INT.withName( - "ConnectionIndex"), USBDescriptors.Device$Struct.withName("DeviceDescriptor"), JAVA_BYTE.withName( - "CurrentConfigurationValue"), JAVA_BYTE.withName("Speed"), JAVA_BYTE.withName("DeviceIsHub"), - JAVA_SHORT.withName("DeviceAddress"), JAVA_INT.withName("NumberOfOpenPipes"), JAVA_INT.withName( - "ConnectionStatus") + public static final GroupLayout USB_NODE_CONNECTION_INFORMATION_EX$Struct = structLayout( + JAVA_INT.withName("ConnectionIndex"), + DeviceDescriptor.LAYOUT.withName("DeviceDescriptor"), + JAVA_BYTE.withName("CurrentConfigurationValue"), + JAVA_BYTE.withName("Speed"), + JAVA_BYTE.withName("DeviceIsHub"), + JAVA_SHORT.withName("DeviceAddress"), + JAVA_INT.withName("NumberOfOpenPipes"), + JAVA_INT.withName("ConnectionStatus") // USB_PIPE_INFO PipeList[0] ); public static final VarHandle USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex = @@ -58,12 +62,9 @@ public class USBHelper { public static MemorySegment USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(MemorySegment seg) { return seg.asSlice(USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset, - USBDescriptors.Device$Struct.byteSize()); + DeviceDescriptor.LAYOUT.byteSize()); } - public static final VarHandle USB_NODE_CONNECTION_INFORMATION_EX_CurrentConfigurationValue = - USB_NODE_CONNECTION_INFORMATION_EX$Struct.varHandle(groupElement("CurrentConfigurationValue")); - // typedef struct _USB_DESCRIPTOR_REQUEST { // ULONG ConnectionIndex; // struct { @@ -92,8 +93,6 @@ public class USBHelper { JAVA_BYTE.withName("bDescriptorType")); public static final VarHandle USB_STRING_DESCRIPTOR_bLength = USB_STRING_DESCRIPTOR$Struct.varHandle(groupElement("bLength")); - public static final VarHandle USB_STRING_DESCRIPTOR_bDescriptorType = - USB_STRING_DESCRIPTOR$Struct.varHandle(groupElement("bDescriptorType")); public static final long USB_STRING_DESCRIPTOR_bString$Offset = USB_STRING_DESCRIPTOR$Struct.byteSize(); // A5DCBF10-6530-11D2-901F-00C04FB951ED diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index f4fa3c7a..fdf20205 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -29,9 +29,9 @@ public class WindowsUSBDevice extends USBDeviceImpl { private final List functions; private boolean isOpen_; - WindowsUSBDevice(String devicePath, List functions, int vendorId, int productId, String manufacturer, String product, String serial, + WindowsUSBDevice(String devicePath, List functions, int vendorId, int productId, MemorySegment configDesc) { - super(devicePath, vendorId, productId, manufacturer, product, serial); + super(devicePath, vendorId, productId); this.functions = functions; readDescription(configDesc); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 702b83f6..7954d1f3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -266,33 +266,18 @@ private USBDevice createDevice(String devicePath, List functi , (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL) == 0) throw new WindowsUSBException("Internal error (cannot get device descriptor)", Kernel32.GetLastError()); - var deviceDesc = USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(connInfo); + var descriptorSegment = USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(connInfo); + var deviceDescriptor = new DeviceDescriptor(descriptorSegment); - // extract info from device descriptor - int manufacturerIndex = 255 & (byte) USBDescriptors.Device_iManufacturer.get(deviceDesc); - String manufacturer = getStringDescriptor(hubHandle, usbPortNum, manufacturerIndex); - int productIndex = 255 & (byte) USBDescriptors.Device_iProduct.get(deviceDesc); - String product = getStringDescriptor(hubHandle, usbPortNum, productIndex); - int serialNumberIndex = 255 & (byte) USBDescriptors.Device_iSerialNumber.get(deviceDesc); - String serialNumber = getStringDescriptor(hubHandle, usbPortNum, serialNumberIndex); - - int vendorId = 0xffff & (short) USBDescriptors.Device_idVendor.get(deviceDesc); - int productId = 0xffff & (short) USBDescriptors.Device_idProduct.get(deviceDesc); + int vendorId = deviceDescriptor.idVendor(); + int productId = deviceDescriptor.idProduct(); var configDesc = getDescriptor(hubHandle, usbPortNum, USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE, 0, (short) 0, session); - var device = new WindowsUSBDevice(devicePath, functions, vendorId, productId, manufacturer, product, - serialNumber, configDesc); - - int classCode = 255 & (byte) USBDescriptors.Device_bDeviceClass.get(deviceDesc); - int subclassCode = 255 & (byte) USBDescriptors.Device_bDeviceSubClass.get(deviceDesc); - int protocolCode = 255 & (byte) USBDescriptors.Device_bDeviceProtocol.get(deviceDesc); - device.setClassCodes(classCode, subclassCode, protocolCode); - - var usbVersion = (short) USBDescriptors.Device_bcdUSB.get(deviceDesc); - var deviceVersion = (short) USBDescriptors.Device_bcdDevice.get(deviceDesc); - device.setVersions(usbVersion, deviceVersion); + var device = new WindowsUSBDevice(devicePath, functions, vendorId, productId, configDesc); + device.setFromDeviceDescriptor(descriptorSegment); + device.setProductString(descriptorSegment, (index) -> getStringDescriptor(hubHandle, usbPortNum, index)); return device; } From 1d5347b0bbdf88334d15308c0de4b8a63ef029ae Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 24 Sep 2022 16:44:46 +0200 Subject: [PATCH 101/433] Clean up USB descriptor classes --- .../CompositeFunction.java | 36 +++- .../codecrete/usb/common/Configuration.java | 69 +++++++ .../usb/common/ConfigurationParser.java | 168 ++++++++++++++++++ .../usb/common/DescriptorParser.java | 167 ----------------- .../codecrete/usb/common/USBDescriptors.java | 137 -------------- .../codecrete/usb/common/USBDeviceImpl.java | 11 +- .../net/codecrete/usb/common/USBStructs.java | 35 ---- .../codecrete/usb/linux/LinuxUSBDevice.java | 5 +- .../codecrete/usb/macos/MacosUSBDevice.java | 16 +- .../usbstandard/ConfigurationDescriptor.java | 90 ++++++++++ .../codecrete/usb/usbstandard/Constants.java | 37 ++++ .../DeviceDescriptor.java | 56 +++--- .../usb/usbstandard/EndpointDescriptor.java | 71 ++++++++ .../InterfaceAssociationDescriptor.java | 85 +++++++++ .../usb/usbstandard/InterfaceDescriptor.java | 92 ++++++++++ .../usb/usbstandard/SetupPacket.java | 111 ++++++++++++ .../usb/usbstandard/StringDescriptor.java | 55 ++++++ .../net/codecrete/usb/windows/USBHelper.java | 21 +-- .../usb/windows/WindowsUSBDevice.java | 23 +-- .../usb/windows/WindowsUSBDeviceRegistry.java | 44 ++--- 20 files changed, 901 insertions(+), 428 deletions(-) rename java-does-usb/src/main/java/net/codecrete/usb/{windows => common}/CompositeFunction.java (67%) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/USBStructs.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/usbstandard/Constants.java rename java-does-usb/src/main/java/net/codecrete/usb/{common => usbstandard}/DeviceDescriptor.java (77%) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/CompositeFunction.java b/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java similarity index 67% rename from java-does-usb/src/main/java/net/codecrete/usb/windows/CompositeFunction.java rename to java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java index acf7326c..3c90d003 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/CompositeFunction.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java @@ -5,7 +5,7 @@ // https://opensource.org/licenses/MIT // -package net.codecrete.usb.windows; +package net.codecrete.usb.common; import java.lang.foreign.MemoryAddress; @@ -35,10 +35,30 @@ public class CompositeFunction { private final int firstInterfaceNumber_; private final int numInterfaces_; - private final String devicePath_; + private int classCode_; + private int subclassCode_; + private int protocolCode_; + private String devicePath_; private MemoryAddress deviceHandle_; private MemoryAddress firstInterfaceHandle_; + /** + * Creates a new instance. + * + * @param firstInterfaceNumber the number of the first interface + * @param numInterfaces the number of interfaces + * @param classCode the function class + * @param subclassCode the function subclass + * @param protocolCode the function protocol + */ + public CompositeFunction(int firstInterfaceNumber, int numInterfaces, int classCode, int subclassCode, int protocolCode) { + firstInterfaceNumber_ = firstInterfaceNumber; + numInterfaces_ = numInterfaces; + classCode_ = classCode; + subclassCode_ = subclassCode; + protocolCode_ = protocolCode; + } + /** * Creates a new instance with a single interface. * @@ -59,6 +79,18 @@ public int numInterfaces() { return numInterfaces_; } + public int classCode() { + return classCode_; + } + + public int subclassCode() { + return subclassCode_; + } + + public int protocolCode() { + return protocolCode_; + } + public String devicePath() { return devicePath_; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java b/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java new file mode 100644 index 00000000..0df069e5 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java @@ -0,0 +1,69 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +import net.codecrete.usb.USBInterface; + +import java.util.ArrayList; +import java.util.List; + +/** + * Describes a device configuration. + */ +public class Configuration { + private final List functions_; + private final List interfaces_; + private final int configValue_; + private final int attributes_; + private final int maxPower_; + + public Configuration(int configValue, int attributes, int maxPower) { + configValue_ = configValue; + attributes_ = attributes; + maxPower_ = maxPower; + functions_ = new ArrayList<>(); + interfaces_ = new ArrayList<>(); + } + + public int configValue() { + return configValue_; + } + + public int attributes() { + return attributes_; + } + + public int maxPower() { + return maxPower_; + } + + public List interfaces() { + return interfaces_; + } + + public List functions() { return functions_; } + + public void addInterface(USBInterface intf) { + interfaces_.add(intf); + } + + public USBInterfaceImpl findInterfaceByNumber(int number) { + return (USBInterfaceImpl) interfaces_.stream().filter((intf) -> intf.number() == number).findFirst().orElse(null); + } + + public void addFunction(CompositeFunction function) { + functions_.add(function); + } + + public CompositeFunction findFunction(int interfaceNumber) { + return functions_.stream() + .filter((f) -> interfaceNumber >= f.firstInterfaceNumber() + && interfaceNumber < f.firstInterfaceNumber() + f.numInterfaces()) + .findFirst().orElse(null); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java new file mode 100644 index 00000000..8476e91f --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java @@ -0,0 +1,168 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +import net.codecrete.usb.*; +import net.codecrete.usb.usbstandard.ConfigurationDescriptor; +import net.codecrete.usb.usbstandard.EndpointDescriptor; +import net.codecrete.usb.usbstandard.InterfaceAssociationDescriptor; +import net.codecrete.usb.usbstandard.InterfaceDescriptor; + +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.util.ArrayList; + +import static net.codecrete.usb.usbstandard.Constants.*; + +/** + * Parser for USB configuration descriptors + */ +public class ConfigurationParser { + + /** + * Parse a USB configuration descriptor (incl. interface and endpoint descriptors) + * + * @param desc configuration descriptor + * @return parsed configuration data + */ + public static Configuration parseConfigurationDescriptor(MemorySegment desc) { + var parser = new ConfigurationParser(desc); + return parser.parse(); + } + + private final MemorySegment descriptor; + private Configuration configuration; + + /** + * Creates a new parser for USB configuration descriptors (incl. interface and endpoint descriptors) + * + * @param descriptor configuration descriptor + */ + public ConfigurationParser(MemorySegment descriptor) { + this.descriptor = descriptor; + } + + public Configuration parse() { + parseHeader(); + + USBAlternateInterfaceImpl lastAlternate = null; + USBEndpointImpl lastEndpoint; + int offset = peekDescLength(0); + + while (offset < descriptor.byteSize()) { + + int descLength = peekDescLength(offset); + int descType = peekDescType(offset); + + if (descType == INTERFACE_DESCRIPTOR_TYPE) { + var intf = parseInterface(offset); + + var parent = configuration.findInterfaceByNumber(intf.number()); + if (parent != null) { + parent.addAlternate(intf.alternate()); + } else { + configuration.addInterface(intf); + } + lastAlternate = (USBAlternateInterfaceImpl) intf.alternate(); + + var function = configuration.findFunction(intf.number()); + if (function == null) { + function = new CompositeFunction(intf.number(), 1, lastAlternate.classCode(), + lastAlternate.subclassCode(), lastAlternate.protocolCode()); + configuration.addFunction(function); + } + + } else if (descType == ENDPOINT_DESCRIPTOR_TYPE) { + lastEndpoint = parseEndpoint(offset); + if (lastAlternate != null) + lastAlternate.addEndpoint(lastEndpoint); + + } else if (descType == INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE) { + parseIAD(offset); + } + + offset += descLength; + } + + return configuration; + } + + private void parseHeader() { + var desc = new ConfigurationDescriptor(descriptor); + if (CONFIGURATION_DESCRIPTOR_TYPE != desc.descriptorType()) + throw new USBException("Invalid USB configuration descriptor"); + + int totalLength = desc.totalLength(); + if (descriptor.byteSize() != totalLength) + throw new USBException("Invalid USB configuration descriptor length"); + + configuration = new Configuration(desc.configurationValue(), desc.attributes(), desc.maxPower()); + } + + private USBInterfaceImpl parseInterface(int offset) { + var desc = new InterfaceDescriptor(descriptor.asSlice(offset, InterfaceDescriptor.LAYOUT.byteSize())); + var alternate = new USBAlternateInterfaceImpl(desc.alternateSetting(), desc.interfaceClass(), + desc.interfaceSubClass(), desc.interfaceProtocol(), new ArrayList<>()); + var alternates = new ArrayList(); + alternates.add(alternate); + return new USBInterfaceImpl(desc.interfaceNumber(), alternates); + } + + private void parseIAD(int offset) { + var desc = new InterfaceAssociationDescriptor( + descriptor.asSlice(offset, InterfaceAssociationDescriptor.LAYOUT.byteSize())); + var function = new CompositeFunction(desc.firstInterface(), desc.interfaceCount(), desc.functionClass(), + desc.functionSubClass(), desc.functionProtocol()); + configuration.addFunction(function); + } + + private USBEndpointImpl parseEndpoint(int offset) { + var desc = new EndpointDescriptor(descriptor.asSlice(offset, EndpointDescriptor.LAYOUT.byteSize())); + var address = desc.endpointAddress(); + return new USBEndpointImpl(getEndpointNumber(address), getEndpointDirection(address), + getEndpointType(desc.attributes()), desc.maxPacketSize()); + } + + private static USBDirection getEndpointDirection(int address) { + return (address & 0x80) != 0 ? USBDirection.IN : USBDirection.OUT; + } + + private static int getEndpointNumber(int address) { + return address & 0x7f; + } + + private static USBTransferType getEndpointType(int attributes) { + return switch (attributes & 0x3) { + case 1 -> USBTransferType.ISOCHRONOUS; + case 2 -> USBTransferType.BULK; + case 3 -> USBTransferType.INTERRUPT; + default -> null; + }; + } + + /** + * Get descriptor length. + * + * @param offset offset to the descriptor of interest + * @return descriptor length (in bytes) + */ + private int peekDescLength(int offset) { + return 0xff & descriptor.get(ValueLayout.JAVA_BYTE, offset); + } + + /** + * Get descriptor type. + * + * @param offset offset to the descriptor of interest + * @return descriptor type + */ + private int peekDescType(int offset) { + return 0xff & descriptor.get(ValueLayout.JAVA_BYTE, offset + 1); + } + +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java deleted file mode 100644 index f6f7ab6c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/DescriptorParser.java +++ /dev/null @@ -1,167 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.common; - -import net.codecrete.usb.*; - -import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; -import java.util.ArrayList; -import java.util.List; - -/** - * Parser for USB descriptors - */ -public class DescriptorParser { - - /** - * Parse a USB configuration descriptor (incl. interface and endpoint descriptors) - * - * @param desc configuration descriptor - * @return parsed configuration data - */ - public static Configuration parseConfigurationDescriptor(MemorySegment desc, int vendorID, int productID) { - var config = parseConfiguration(desc); - - USBAlternateInterfaceImpl lastAlternate = null; - USBEndpointImpl lastEndpoint; - int offset = peekDescLength(desc, 0); - - while (offset < desc.byteSize()) { - - int descLength = peekDescLength(desc, offset); - int descType = peekDescType(desc, offset); - - if (descType == USBDescriptors.INTERFACE_DESCRIPTOR_TYPE) { - var intf = parseInterface(desc, offset); - var parent = config.findInterfaceByNumber(intf.number()); - if (parent != null) { - parent.addAlternate(intf.alternate()); - } else { - config.addInterface(intf); - } - lastAlternate = (USBAlternateInterfaceImpl) intf.alternate(); - - } else if (descType == USBDescriptors.ENDPOINT_DESCRIPTOR_TYPE) { - lastEndpoint = parseEndpoint(desc, offset); - if (lastAlternate != null) - lastAlternate.addEndpoint(lastEndpoint); - - } else //noinspection StatementWithEmptyBody - if (descType == USBDescriptors.INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE) { - // TODO: interface associations - - } else //noinspection StatementWithEmptyBody - if (descType == USBDescriptors.HID_DESCRIPTOR_TYPE || descType == USBDescriptors.CS_INTERFACE_DESCRIPTOR_TYPE || descType == USBDescriptors.CS_ENDPOINT_DESCRIPTOR_TYPE) { - // known descriptor but not relevant - - } else { - // TODO: Remove warning once the relevant descriptors are processed - System.err.printf("Info: [JavaDoesUSB] unsupported USB descriptor type 0x%02x of device " + - "0x%04x/0x%04x - ignoring descriptor%n", descType, vendorID, productID); - } - - offset += descLength; - } - - return config; - } - - private static Configuration parseConfiguration(MemorySegment descriptor) { - var desc = descriptor.asSlice(0, USBDescriptors.Configuration.byteSize()); - var config = new Configuration(); - if (USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE != (byte) USBDescriptors.Configuration_bDescriptorType.get(desc)) - throw new USBException("Invalid USB configuration descriptor"); - - short totalLength = (short) USBDescriptors.Configuration_wTotalLength.get(desc); - if (descriptor.byteSize() != totalLength) - throw new USBException("Invalid USB configuration descriptor length"); - - config.configValue = (byte) USBDescriptors.Configuration_bConfigurationValue.get(desc); - config.attributes = (byte) USBDescriptors.Configuration_bmAttributes.get(desc); - config.maxPower = (byte) USBDescriptors.Configuration_bMaxPower.get(desc); - config.interfaces = new ArrayList<>(); - return config; - } - - private static USBInterfaceImpl parseInterface(MemorySegment descriptor, int offset) { - var desc = descriptor.asSlice(offset, USBDescriptors.Interface.byteSize()); - var number = 255 & (byte) USBDescriptors.Interface_bInterfaceNumber.get(desc); - var altSetting = 255 & (byte) USBDescriptors.Interface_bAlternateSetting.get(desc); - var classCode = 255 & (byte) USBDescriptors.Interface_bInterfaceClass.get(desc); - var subclassCode = 255 & (byte) USBDescriptors.Interface_bInterfaceSubClass.get(desc); - var protocol = 255 & (byte) USBDescriptors.Interface_bInterfaceProtocol.get(desc); - var alternate = new USBAlternateInterfaceImpl(altSetting, classCode, subclassCode, protocol, new ArrayList<>()); - var alternates = new ArrayList(); - alternates.add(alternate); - return new USBInterfaceImpl(number, alternates); - } - - private static USBEndpointImpl parseEndpoint(MemorySegment descriptor, int offset) { - var desc = descriptor.asSlice(offset, USBDescriptors.Endpoint.byteSize()); - var address = (byte) USBDescriptors.Endpoint_bEndpointAddress.get(desc); - var attributes = (byte) USBDescriptors.Endpoint_bmAttributes.get(desc); - var maxPacketSize = (short) USBDescriptors.Endpoint_wMaxPacketSize.get(desc); - return new USBEndpointImpl(getEndpointNumber(address), getEndpointDirection(address), - getEndpointType(attributes), maxPacketSize); - } - - private static USBDirection getEndpointDirection(byte address) { - return (address & 0x80) != 0 ? USBDirection.IN : USBDirection.OUT; - } - - private static int getEndpointNumber(byte address) { - return address & 0x7f; - } - - private static USBTransferType getEndpointType(byte attributes) { - return switch (attributes & 0x3) { - case 1 -> USBTransferType.ISOCHRONOUS; - case 2 -> USBTransferType.BULK; - case 3 -> USBTransferType.INTERRUPT; - default -> null; - }; - } - - /** - * Get descriptor length. - * - * @param desc byte array containing multiple descriptors - * @param offset offset to the descriptor of interest - * @return descriptor length (in bytes) - */ - private static int peekDescLength(MemorySegment desc, int offset) { - return 255 & desc.get(ValueLayout.JAVA_BYTE, offset); - } - - /** - * Get descriptor type. - * - * @param desc byte array containing multiple descriptors - * @param offset offset to the descriptor of interest - * @return descriptor type - */ - private static int peekDescType(MemorySegment desc, int offset) { - return 255 & desc.get(ValueLayout.JAVA_BYTE, offset + 1); - } - - public static class Configuration { - public List interfaces; - public byte configValue; - public byte attributes; - public byte maxPower; - - void addInterface(USBInterface intf) { - interfaces.add(intf); - } - - public USBInterfaceImpl findInterfaceByNumber(int number) { - return (USBInterfaceImpl) interfaces.stream().filter((intf) -> intf.number() == number).findFirst().orElse(null); - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java deleted file mode 100644 index 0ff60844..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDescriptors.java +++ /dev/null @@ -1,137 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.common; - -import java.lang.foreign.GroupLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.MemoryLayout.structLayout; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; - -/** - * Memory layout of USB descriptors. - */ -public class USBDescriptors { - - public static final byte DEVICE_DESCRIPTOR_TYPE = 0x01; - public static final byte CONFIGURATION_DESCRIPTOR_TYPE = 0x02; - public static final byte STRING_DESCRIPTOR_TYPE = 0x03; - public static final byte INTERFACE_DESCRIPTOR_TYPE = 0x04; - public static final byte ENDPOINT_DESCRIPTOR_TYPE = 0x05; - public static final byte DEVICE_QUALIFIER_DESCRIPTOR_TYPE = 0x06; - public static final byte OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE = 0x07; - public static final byte INTERFACE_POWER_DESCRIPTOR_TYPE = 0x08; - public static final byte OTG_DESCRIPTOR_TYPE = 0x09; - public static final byte DEBUG_DESCRIPTOR_TYPE = 0x0a; - public static final byte INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE = 0x0b; - public static final byte BOS_DESCRIPTOR_TYPE = 0x0f; - public static final byte DEVICE_CAPABILITY_DESCRIPTOR_TYPE = 0x10; - public static final byte HID_DESCRIPTOR_TYPE = 0x21; - public static final byte CS_INTERFACE_DESCRIPTOR_TYPE = 0x24; - public static final byte CS_ENDPOINT_DESCRIPTOR_TYPE = 0x25; - public static final byte USB_20_HUB_DESCRIPTOR_TYPE = 0x29; - public static final byte USB_30_HUB_DESCRIPTOR_TYPE = 0x2a; - public static final byte SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_TYPE = 0x30; - public static final byte SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR_TYPE = 0x31; - - public static final short DEFAULT_LANGUAGE = 0x0409; - - // struct USBConfigurationDescriptor - //{ - // uint8_t bLength; - // uint8_t bDescriptorType; - // uint16_t wTotalLength; - // uint8_t bNumInterfaces; - // uint8_t bConfigurationValue; - // uint8_t iConfiguration; - // uint8_t bmAttributes; - // uint8_t MaxPower; - //} __attribute__((packed)); - - /** - * USB configuration descriptor - */ - public static final GroupLayout Configuration = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( - "bDescriptorType"), JAVA_SHORT.withName("wTotalLength"), JAVA_BYTE.withName("bNumInterfaces"), - JAVA_BYTE.withName("bConfigurationValue"), JAVA_BYTE.withName("iConfiguration"), JAVA_BYTE.withName( - "bmAttributes"), JAVA_BYTE.withName("bMaxPower")); - - public static final VarHandle Configuration_bLength = Configuration.varHandle(groupElement("bLength")); - public static final VarHandle Configuration_bDescriptorType = Configuration.varHandle(groupElement( - "bDescriptorType")); - public static final VarHandle Configuration_wTotalLength = Configuration.varHandle(groupElement("wTotalLength")); - public static final VarHandle Configuration_bNumInterfaces = Configuration.varHandle(groupElement("bNumInterfaces" - )); - public static final VarHandle Configuration_bConfigurationValue = Configuration.varHandle(groupElement( - "bConfigurationValue")); - public static final VarHandle Configuration_iConfiguration = Configuration.varHandle(groupElement("iConfiguration" - )); - public static final VarHandle Configuration_bmAttributes = Configuration.varHandle(groupElement("bmAttributes")); - public static final VarHandle Configuration_bMaxPower = Configuration.varHandle(groupElement("bMaxPower")); - - // struct USBInterfaceDescriptor - // { - // uint8_t bLength; - // uint8_t bDescriptorType; - // uint8_t bInterfaceNumber; - // uint8_t bAlternateSetting; - // uint8_t bNumEndpoints; - // uint8_t bInterfaceClass; - // uint8_t bInterfaceSubClass; - // uint8_t bInterfaceProtocol; - // uint8_t iInterface; - // } __attribute__((packed)); - - public static final GroupLayout Interface = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( - "bDescriptorType"), JAVA_BYTE.withName("bInterfaceNumber"), JAVA_BYTE.withName("bAlternateSetting"), - JAVA_BYTE.withName("bNumEndpoints"), JAVA_BYTE.withName("bInterfaceClass"), JAVA_BYTE.withName( - "bInterfaceSubClass"), JAVA_BYTE.withName("bInterfaceProtocol"), JAVA_BYTE.withName("iInterface")); - - public static final VarHandle Interface_bLength = Interface.varHandle(groupElement("bLength")); - public static final VarHandle Interface_bDescriptorType = Interface.varHandle(groupElement("bDescriptorType")); - public static final VarHandle Interface_bInterfaceNumber = Interface.varHandle(groupElement("bInterfaceNumber")); - public static final VarHandle Interface_bAlternateSetting = Interface.varHandle(groupElement("bAlternateSetting")); - public static final VarHandle Interface_bNumEndpoints = Interface.varHandle(groupElement("bNumEndpoints")); - public static final VarHandle Interface_bInterfaceClass = Interface.varHandle(groupElement("bInterfaceClass")); - public static final VarHandle Interface_bInterfaceSubClass = Interface.varHandle(groupElement("bInterfaceSubClass" - )); - public static final VarHandle Interface_bInterfaceProtocol = Interface.varHandle(groupElement("bInterfaceProtocol" - )); - public static final VarHandle Interface_iInterface = Interface.varHandle(groupElement("iInterface")); - - - // struct USBInterfaceDescriptor - // { - // uint8_t bLength; - // uint8_t bDescriptorType; - // uint8_t bEndpointAddress; - // uint8_t bmAttributes; - // uint16_t wMaxPacketSize; - // uint8_t bInterval; - // } __attribute__((packed)); - - public static final GroupLayout Endpoint = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( - "bDescriptorType"), JAVA_BYTE.withName("bEndpointAddress"), JAVA_BYTE.withName("bmAttributes"), - JAVA_SHORT.withName("wMaxPacketSize").withBitAlignment(8), JAVA_BYTE.withName("bInterval")); - - public static final VarHandle Endpoint_bLength = Endpoint.varHandle(groupElement("bLength")); - public static final VarHandle Endpoint_bDescriptorType = Endpoint.varHandle(groupElement("bDescriptorType")); - public static final VarHandle Endpoint_bEndpointAddress = Endpoint.varHandle(groupElement("bEndpointAddress")); - public static final VarHandle Endpoint_bmAttributes = Endpoint.varHandle(groupElement("bmAttributes")); - public static final VarHandle Endpoint_wMaxPacketSize = Endpoint.varHandle(groupElement("wMaxPacketSize")); - public static final VarHandle Endpoint_bInterval = Endpoint.varHandle(groupElement("bInterval")); - - - static { - assert Configuration.byteSize() == 9; - assert Interface.byteSize() == 9; - assert Endpoint.byteSize() == 7; - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index ee74b527..2df47caf 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -8,6 +8,7 @@ package net.codecrete.usb.common; import net.codecrete.usb.*; +import net.codecrete.usb.usbstandard.DeviceDescriptor; import java.lang.foreign.MemorySegment; import java.util.Collections; @@ -116,11 +117,11 @@ public Object getUniqueId() { */ public void setFromDeviceDescriptor(MemorySegment descriptor) { var deviceDescriptor = new DeviceDescriptor(descriptor); - classCode_ = deviceDescriptor.bDeviceClass() & 255; - subclassCode_ = deviceDescriptor.bDeviceSubClass() & 255; - protocolCode_ = deviceDescriptor.bDeviceProtocol() & 255; - usbVersion_ = new Version(deviceDescriptor.bcdUSB()); - deviceVersion_ = new Version(deviceDescriptor.bcdDevice()); + classCode_ = deviceDescriptor.deviceClass() & 255; + subclassCode_ = deviceDescriptor.deviceSubClass() & 255; + protocolCode_ = deviceDescriptor.deviceProtocol() & 255; + usbVersion_ = new Version(deviceDescriptor.usbVersion()); + deviceVersion_ = new Version(deviceDescriptor.deviceVersion()); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBStructs.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBStructs.java deleted file mode 100644 index b98d3187..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBStructs.java +++ /dev/null @@ -1,35 +0,0 @@ -package net.codecrete.usb.common; - -import java.lang.foreign.GroupLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.MemoryLayout.structLayout; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; - -/** - * Memory layout of USB data structures. - */ -public class USBStructs { - // typedef struct { - // uint8_t RequestType; - // uint8_t Request; - // uint8_t Value; - // uint16_t Index; - // uint16_t Length; - //} __attribute__((packed)); - public static final GroupLayout SetupPacket$Struct = structLayout(JAVA_BYTE.withName("bmRequest"), - JAVA_BYTE.withName("bRequest"), JAVA_SHORT.withName("wValue"), JAVA_SHORT.withName("wIndex"), - JAVA_SHORT.withName("wLength")); - - public static final VarHandle SetupPacket_bmRequest = SetupPacket$Struct.varHandle(groupElement("bmRequest")); - public static final VarHandle SetupPacket_bRequest = SetupPacket$Struct.varHandle(groupElement("bRequest")); - public static final VarHandle SetupPacket_wValue = SetupPacket$Struct.varHandle(groupElement("wValue")); - public static final VarHandle SetupPacket_wIndex = SetupPacket$Struct.varHandle(groupElement("wIndex")); - public static final VarHandle SetupPacket_wLength = SetupPacket$Struct.varHandle(groupElement("wLength")); - - static { - assert SetupPacket$Struct.byteSize() == 8; - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index fcce94ca..395d8a73 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -12,6 +12,7 @@ import net.codecrete.usb.USBException; import net.codecrete.usb.USBTransferType; import net.codecrete.usb.common.*; +import net.codecrete.usb.usbstandard.DeviceDescriptor; import net.codecrete.usb.linux.gen.fcntl.fcntl; import net.codecrete.usb.linux.gen.ioctl.ioctl; import net.codecrete.usb.linux.gen.unistd.unistd; @@ -59,8 +60,8 @@ private void loadDescription(String path) { // skip to configuration descriptor var configDesc = session.allocateArray(JAVA_BYTE, descriptors.length - 18); configDesc.copyFrom(descriptorsSegment.asSlice(DeviceDescriptor.LAYOUT.byteSize())); - var configuration = DescriptorParser.parseConfigurationDescriptor(configDesc, vendorId(), productId()); - setInterfaces(configuration.interfaces); + var configuration = ConfigurationParser.parseConfigurationDescriptor(configDesc); + setInterfaces(configuration.interfaces()); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 5a2f9146..f8ec4c3c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -11,9 +11,9 @@ import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBException; import net.codecrete.usb.USBTransferType; -import net.codecrete.usb.common.DescriptorParser; -import net.codecrete.usb.common.USBDescriptors; +import net.codecrete.usb.common.ConfigurationParser; import net.codecrete.usb.common.USBDeviceImpl; +import net.codecrete.usb.usbstandard.ConfigurationDescriptor; import net.codecrete.usb.macos.gen.iokit.IOKit; import net.codecrete.usb.macos.gen.iokit.IOUSBDevRequest; import net.codecrete.usb.macos.gen.iokit.IOUSBFindInterfaceRequest; @@ -101,16 +101,16 @@ private void loadDescription() { throw new MacosUSBException("failed to query first configuration", ret); // get value of first configuration - var configDescHeader = MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), - USBDescriptors.Configuration.byteSize(), session); - int totalLength = (short) USBDescriptors.Configuration_wTotalLength.get(configDescHeader); + var configDescHeader = new ConfigurationDescriptor(MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), + ConfigurationDescriptor.LAYOUT.byteSize(), session)); + int totalLength = configDescHeader.totalLength(); var configDesc = MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), totalLength, session); - var configuration = DescriptorParser.parseConfigurationDescriptor(configDesc, vendorId(), productId()); + var configuration = ConfigurationParser.parseConfigurationDescriptor(configDesc); - configurationValue = 255 & configuration.configValue; - setInterfaces(configuration.interfaces); + configurationValue = 255 & configuration.configValue(); + setInterfaces(configuration.interfaces()); } catch (Throwable e) { configurationValue = 0; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java new file mode 100644 index 00000000..c832b5fb --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java @@ -0,0 +1,90 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.usbstandard; + +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.MemoryLayout.structLayout; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; + +/** + * USB configuration descriptor + */ +public class ConfigurationDescriptor { + + private final MemorySegment descriptor; + + public ConfigurationDescriptor(MemorySegment descriptor) { + this.descriptor = descriptor; + } + + public int descriptorType() { + return 0xff & (byte) bDescriptorType$VH.get(descriptor); + } + public int totalLength() { + return 0xffff & (short) wTotalLength$VH.get(descriptor); + } + + public int numInterfaces() { + return 0xff & (byte) bNumInterfaces$VH.get(descriptor); + } + + public int configurationValue() { + return 0xff & (byte) bConfigurationValue$VH.get(descriptor); + } + + public int iConfiguration() { + return 0xff & (byte) iConfiguration$VH.get(descriptor); + } + + public int attributes() { + return 0xff & (byte) bmAttributes$VH.get(descriptor); + } + + public int maxPower() { + return 0xff & (byte) bMaxPower$VH.get(descriptor); + } + + + // struct USBConfigurationDescriptor { + // uint8_t bLength; + // uint8_t bDescriptorType; + // uint16_t wTotalLength; + // uint8_t bNumInterfaces; + // uint8_t bConfigurationValue; + // uint8_t iConfiguration; + // uint8_t bmAttributes; + // uint8_t bMaxPower; + // } __attribute__((packed)); + public static final GroupLayout LAYOUT = structLayout( + JAVA_BYTE.withName("bLength"), + JAVA_BYTE.withName("bDescriptorType"), + JAVA_SHORT.withName("wTotalLength"), + JAVA_BYTE.withName("bNumInterfaces"), + JAVA_BYTE.withName("bConfigurationValue"), + JAVA_BYTE.withName("iConfiguration"), + JAVA_BYTE.withName("bmAttributes"), + JAVA_BYTE.withName("bMaxPower") + ); + + private static final VarHandle bDescriptorType$VH = LAYOUT.varHandle(groupElement("bDescriptorType")); + private static final VarHandle wTotalLength$VH = LAYOUT.varHandle(groupElement("wTotalLength")); + private static final VarHandle bNumInterfaces$VH = LAYOUT.varHandle(groupElement("bNumInterfaces")); + private static final VarHandle bConfigurationValue$VH = LAYOUT.varHandle(groupElement("bConfigurationValue")); + private static final VarHandle iConfiguration$VH = LAYOUT.varHandle(groupElement("iConfiguration")); + private static final VarHandle bmAttributes$VH = LAYOUT.varHandle(groupElement("bmAttributes")); + private static final VarHandle bMaxPower$VH = LAYOUT.varHandle(groupElement("bMaxPower")); + + static { + assert LAYOUT.byteSize() == 9; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/Constants.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/Constants.java new file mode 100644 index 00000000..7189af42 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/Constants.java @@ -0,0 +1,37 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.usbstandard; + +/** + * Memory layout of USB descriptors. + */ +public class Constants { + + public static final byte DEVICE_DESCRIPTOR_TYPE = 0x01; + public static final byte CONFIGURATION_DESCRIPTOR_TYPE = 0x02; + public static final byte STRING_DESCRIPTOR_TYPE = 0x03; + public static final byte INTERFACE_DESCRIPTOR_TYPE = 0x04; + public static final byte ENDPOINT_DESCRIPTOR_TYPE = 0x05; + public static final byte DEVICE_QUALIFIER_DESCRIPTOR_TYPE = 0x06; + public static final byte OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE = 0x07; + public static final byte INTERFACE_POWER_DESCRIPTOR_TYPE = 0x08; + public static final byte OTG_DESCRIPTOR_TYPE = 0x09; + public static final byte DEBUG_DESCRIPTOR_TYPE = 0x0a; + public static final byte INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE = 0x0b; + public static final byte BOS_DESCRIPTOR_TYPE = 0x0f; + public static final byte DEVICE_CAPABILITY_DESCRIPTOR_TYPE = 0x10; + public static final byte HID_DESCRIPTOR_TYPE = 0x21; + public static final byte CS_INTERFACE_DESCRIPTOR_TYPE = 0x24; + public static final byte CS_ENDPOINT_DESCRIPTOR_TYPE = 0x25; + public static final byte USB_20_HUB_DESCRIPTOR_TYPE = 0x29; + public static final byte USB_30_HUB_DESCRIPTOR_TYPE = 0x2a; + public static final byte SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_TYPE = 0x30; + public static final byte SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR_TYPE = 0x31; + + public static final short DEFAULT_LANGUAGE = 0x0409; +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/DeviceDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java similarity index 77% rename from java-does-usb/src/main/java/net/codecrete/usb/common/DeviceDescriptor.java rename to java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java index c5a305e6..856106e1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/DeviceDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java @@ -5,7 +5,7 @@ // https://opensource.org/licenses/MIT // -package net.codecrete.usb.common; +package net.codecrete.usb.usbstandard; import java.lang.foreign.GroupLayout; import java.lang.foreign.MemorySegment; @@ -16,6 +16,9 @@ import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_SHORT; +/** + * USB device descriptor + */ public class DeviceDescriptor { private final MemorySegment descriptor; @@ -24,31 +27,31 @@ public DeviceDescriptor(MemorySegment descriptor) { this.descriptor = descriptor; } - public int bcdUSB() { + public int usbVersion() { return 0xffff & (short) bcdUSB$VH.get(descriptor); } - public int bDeviceClass() { + public int deviceClass() { return 0xff & (byte) bDeviceClass$VH.get(descriptor); } - public int bDeviceSubClass() { + public int deviceSubClass() { return 0xff & (byte) bDeviceSubClass$VH.get(descriptor); } - public int bDeviceProtocol() { + public int deviceProtocol() { return 0xff & (byte) bDeviceProtocol$VH.get(descriptor); } - public int idVendor() { + public int vendorID() { return 0xffff & (short) idVendor$VH.get(descriptor); } - public int idProduct() { + public int productID() { return 0xffff & (short) idProduct$VH.get(descriptor); } - public int bcdDevice() { + public int deviceVersion() { return 0xffff & (short) bcdDevice$VH.get(descriptor); } @@ -64,22 +67,22 @@ public int iSerialNumber() { return 0xffff & (short) iSerialNumber$VH.get(descriptor); } - // typedef struct { - // UCHAR bLength; - // UCHAR bDescriptorType; - // USHORT bcdUSB; - // UCHAR bDeviceClass; - // UCHAR bDeviceSubClass; - // UCHAR bDeviceProtocol; - // UCHAR bMaxPacketSize0; - // USHORT idVendor; - // USHORT idProduct; - // USHORT bcdDevice; - // UCHAR iManufacturer; - // UCHAR iProduct; - // UCHAR iSerialNumber; - // UCHAR bNumConfigurations; - //} __attribute__((packed)); + // struct USBDeviceDescriptor { + // uint8_t bLength; + // uint8_t bDescriptorType; + // uint16_t bcdUSB; + // uint8_t bDeviceClass; + // uint8_t bDeviceSubClass; + // uint8_t bDeviceProtocol; + // uint8_t bMaxPacketSize0; + // uint16_t idVendor; + // uint16_t idProduct; + // uint16_t bcdDevice; + // uint8_t iManufacturer; + // uint8_t iProduct; + // uint8_t iSerialNumber; + // uint8_t bNumConfigurations; + // } __attribute__((packed)); public static final GroupLayout LAYOUT = structLayout( JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName("bDescriptorType"), @@ -107,4 +110,9 @@ public int iSerialNumber() { private static final VarHandle iManufacturer$VH = LAYOUT.varHandle(groupElement("iManufacturer")); private static final VarHandle iProduct$VH = LAYOUT.varHandle(groupElement("iProduct")); private static final VarHandle iSerialNumber$VH = LAYOUT.varHandle(groupElement("iSerialNumber")); + + + static { + assert LAYOUT.byteSize() == 18; + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java new file mode 100644 index 00000000..acc345b0 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java @@ -0,0 +1,71 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.usbstandard; + +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.MemoryLayout.structLayout; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; + +/** + * USB endpoint descriptor + */ +public class EndpointDescriptor { + + private final MemorySegment descriptor; + + public EndpointDescriptor(MemorySegment descriptor) { + this.descriptor = descriptor; + } + + public int endpointAddress() { + return 0xff & (byte) bEndpointAddress$VH.get(descriptor); + } + + public int attributes() { + return 0xff & (byte) bmAttributes$VH.get(descriptor); + } + + public int maxPacketSize() { + return 0xffff & (short) wMaxPacketSize$VH.get(descriptor); + } + + public int interval() { + return 0xff & (byte) bInterval$VH.get(descriptor); + } + + // struct USBEndpointDescriptor { + // uint8_t bLength; + // uint8_t bDescriptorType; + // uint8_t bEndpointAddress; + // uint8_t bmAttributes; + // uint16_t wMaxPacketSize; + // uint8_t bInterval; + // } __attribute__((packed)); + public static final GroupLayout LAYOUT = structLayout( + JAVA_BYTE.withName("bLength"), + JAVA_BYTE.withName("bDescriptorType"), + JAVA_BYTE.withName("bEndpointAddress"), + JAVA_BYTE.withName("bmAttributes"), + JAVA_SHORT.withBitAlignment(8).withName("wMaxPacketSize"), + JAVA_BYTE.withName("bInterval") + ); + + private static final VarHandle bEndpointAddress$VH = LAYOUT.varHandle(groupElement("bEndpointAddress")); + private static final VarHandle bmAttributes$VH = LAYOUT.varHandle(groupElement("bmAttributes")); + private static final VarHandle wMaxPacketSize$VH = LAYOUT.varHandle(groupElement("wMaxPacketSize")); + private static final VarHandle bInterval$VH = LAYOUT.varHandle(groupElement("bInterval")); + + static { + assert LAYOUT.byteSize() == 7; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java new file mode 100644 index 00000000..dd312d3d --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java @@ -0,0 +1,85 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.usbstandard; + +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.MemoryLayout.structLayout; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; + +/** + * USB interface association descriptor (IAD) + */ +public class InterfaceAssociationDescriptor { + + private final MemorySegment descriptor; + + public InterfaceAssociationDescriptor(MemorySegment descriptor) { + this.descriptor = descriptor; + } + + public int firstInterface() { + return 0xff & (byte) bFirstInterface$VH.get(descriptor); + } + + public int interfaceCount() { + return 0xff & (byte) bInterfaceCount$VH.get(descriptor); + } + + public int functionClass() { + return 0xff & (byte) bFunctionClass$VH.get(descriptor); + } + + public int functionSubClass() { + return 0xff & (byte) bFunctionSubClass$VH.get(descriptor); + } + + public int functionProtocol() { + return 0xff & (byte) bFunctionProtocol$VH.get(descriptor); + } + + public int function() { + return 0xff & (byte) iFunction$VH.get(descriptor); + } + + + // struct USBInterfaceAssociationDescriptor { + // uint8_t bLength, + // uint8_t bDescriptorType, + // uint8_t bFirstInterface, + // uint8_t bInterfaceCount, + // uint8_t bFunctionClass, + // uint8_t bFunctionSubClass, + // uint8_t bFunctionProtocol, + // uint8_t iFunction + // } __attribute__((packed)); + public static final GroupLayout LAYOUT = structLayout( + JAVA_BYTE.withName("bLength"), + JAVA_BYTE.withName("bDescriptorType"), + JAVA_BYTE.withName("bFirstInterface"), + JAVA_BYTE.withName("bInterfaceCount"), + JAVA_BYTE.withName("bFunctionClass"), + JAVA_BYTE.withName("bFunctionSubClass"), + JAVA_BYTE.withName("bFunctionProtocol"), + JAVA_BYTE.withName("iFunction") + ); + + private static final VarHandle bFirstInterface$VH = LAYOUT.varHandle(groupElement("bFirstInterface")); + private static final VarHandle bInterfaceCount$VH = LAYOUT.varHandle(groupElement("bInterfaceCount")); + private static final VarHandle bFunctionClass$VH = LAYOUT.varHandle(groupElement("bFunctionClass")); + private static final VarHandle bFunctionSubClass$VH = LAYOUT.varHandle(groupElement("bFunctionSubClass")); + private static final VarHandle bFunctionProtocol$VH = LAYOUT.varHandle(groupElement("bFunctionProtocol")); + private static final VarHandle iFunction$VH = LAYOUT.varHandle(groupElement("iFunction")); + + static { + assert LAYOUT.byteSize() == 8; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java new file mode 100644 index 00000000..d7f8746f --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java @@ -0,0 +1,92 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.usbstandard; + +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.MemoryLayout.structLayout; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; + +/** + * USB interface descriptor + */ +public class InterfaceDescriptor { + + private final MemorySegment descriptor; + + public InterfaceDescriptor(MemorySegment descriptor) { + this.descriptor = descriptor; + } + + public int interfaceNumber() { + return 0xff & (byte) bInterfaceNumber$VH.get(descriptor); + } + + public int alternateSetting() { + return 0xff & (byte) bAlternateSetting$VH.get(descriptor); + } + + public int numEndpoints() { + return 0xff & (byte) bNumEndpoints$VH.get(descriptor); + } + + public int interfaceClass() { + return 0xff & (byte) bInterfaceClass$VH.get(descriptor); + } + + public int interfaceSubClass() { + return 0xff & (byte) bInterfaceSubClass$VH.get(descriptor); + } + + public int interfaceProtocol() { + return 0xff & (byte) bInterfaceProtocol$VH.get(descriptor); + } + + public int iInterface() { + return 0xff & (byte) iInterface$VH.get(descriptor); + } + + // struct USBInterfaceDescriptor { + // uint8_t bLength; + // uint8_t bDescriptorType; + // uint8_t bInterfaceNumber; + // uint8_t bAlternateSetting; + // uint8_t bNumEndpoints; + // uint8_t bInterfaceClass; + // uint8_t bInterfaceSubClass; + // uint8_t bInterfaceProtocol; + // uint8_t iInterface; + // } __attribute__((packed)); + public static final GroupLayout LAYOUT = structLayout( + JAVA_BYTE.withName("bLength"), + JAVA_BYTE.withName("bDescriptorType"), + JAVA_BYTE.withName("bInterfaceNumber"), + JAVA_BYTE.withName("bAlternateSetting"), + JAVA_BYTE.withName("bNumEndpoints"), + JAVA_BYTE.withName("bInterfaceClass"), + JAVA_BYTE.withName("bInterfaceSubClass"), + JAVA_BYTE.withName("bInterfaceProtocol"), + JAVA_BYTE.withName("iInterface") + ); + + private static final VarHandle bInterfaceNumber$VH = LAYOUT.varHandle(groupElement("bInterfaceNumber")); + private static final VarHandle bAlternateSetting$VH = LAYOUT.varHandle(groupElement("bAlternateSetting")); + private static final VarHandle bNumEndpoints$VH = LAYOUT.varHandle(groupElement("bNumEndpoints")); + private static final VarHandle bInterfaceClass$VH = LAYOUT.varHandle(groupElement("bInterfaceClass")); + private static final VarHandle bInterfaceSubClass$VH = LAYOUT.varHandle(groupElement("bInterfaceSubClass")); + private static final VarHandle bInterfaceProtocol$VH = LAYOUT.varHandle(groupElement("bInterfaceProtocol")); + private static final VarHandle iInterface$VH = LAYOUT.varHandle(groupElement("iInterface")); + + + static { + assert LAYOUT.byteSize() == 9; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java new file mode 100644 index 00000000..afb022c7 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java @@ -0,0 +1,111 @@ +package net.codecrete.usb.usbstandard; + +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.MemoryLayout.structLayout; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; + +/** + * USB setup packet. + */ +public class SetupPacket { + + private final MemorySegment descriptor; + + /** + * Creates a setup packet accessing the specified memory segment. + * + * @param descriptor memory segment + */ + public SetupPacket(MemorySegment descriptor) { + this.descriptor = descriptor; + } + + /** + * Creates a setup packet by allocating a native memory segment. + * + * @param session memory session + */ + public SetupPacket(MemorySession session) { + this.descriptor = session.allocate(LAYOUT); + } + + /** + * Gets the memory segment of this setup packet. + * + * @return memory segment + */ + public MemorySegment segment() { + return descriptor; + } + + public int requestType() { + return 0xff & (byte) bmRequestType$VH.get(descriptor); + } + + public void setRequestType(int requestType) { + bmRequestType$VH.set(descriptor, (byte) requestType); + } + + public int request() { + return 0xff & (byte) bRequest$VH.get(descriptor); + } + + public void setRequest(int request) { + bRequest$VH.set(descriptor, (byte) request); + } + + public int value() { + return 0xffff & (short) wValue$VH.get(descriptor); + } + + public void setValue(int value) { + wValue$VH.set(descriptor, (short) value); + } + + public int index() { + return 0xffff & (short) wIndex$VH.get(descriptor); + } + + public void setIndex(int index) { + wIndex$VH.set(descriptor, (short) index); + } + + public int length() { + return 0xffff & (short) wLength$VH.get(descriptor); + } + + public void setLength(int length) { + wLength$VH.set(descriptor, (short) length); + } + + // struct USBSetupPacket { + // uint8_t bmRequestType; + // uint8_t bRequest; + // uint8_t wValue; + // uint16_t wIndex; + // uint16_t wLength; + // } __attribute__((packed)); + public static final GroupLayout LAYOUT = structLayout( + JAVA_BYTE.withName("bmRequestType"), + JAVA_BYTE.withName("bRequest"), + JAVA_SHORT.withName("wValue"), + JAVA_SHORT.withName("wIndex"), + JAVA_SHORT.withName("wLength") + ); + + private static final VarHandle bmRequestType$VH = LAYOUT.varHandle(groupElement("bmRequestType")); + private static final VarHandle bRequest$VH = LAYOUT.varHandle(groupElement("bRequest")); + private static final VarHandle wValue$VH = LAYOUT.varHandle(groupElement("wValue")); + private static final VarHandle wIndex$VH = LAYOUT.varHandle(groupElement("wIndex")); + private static final VarHandle wLength$VH = LAYOUT.varHandle(groupElement("wLength")); + + static { + assert LAYOUT.byteSize() == 8; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java new file mode 100644 index 00000000..970821a0 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java @@ -0,0 +1,55 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.usbstandard; + +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.MemoryLayout.structLayout; +import static java.lang.foreign.ValueLayout.*; + +/** + * USB string descriptor + */ +public class StringDescriptor { + + private final MemorySegment descriptor; + + public StringDescriptor(MemorySegment descriptor) { + this.descriptor = descriptor; + } + + public int length() { + return 0xff & (byte) bLength$VH.get(descriptor); + } + + public String string() { + var chars = descriptor.asSlice(string$offset, length() - 2).toArray(JAVA_CHAR); + return new String(chars); + } + + // struct USBStringDescriptor { + // uint8_t bLength; + // uint8_t bDescriptorType; + // uint16_t string[1]; + // } __attribute__((packed)); + public static final GroupLayout LAYOUT = structLayout( + JAVA_BYTE.withName("bLength"), + JAVA_BYTE.withName("bDescriptorType"), + JAVA_SHORT.withName("string") + ); + + private static final VarHandle bLength$VH = LAYOUT.varHandle(groupElement("bLength")); + private static final long string$offset = LAYOUT.byteOffset(groupElement("string")); + + static { + assert LAYOUT.byteSize() == 7; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java index 08eaa124..53ba0dfc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java @@ -7,8 +7,8 @@ package net.codecrete.usb.windows; -import net.codecrete.usb.common.DeviceDescriptor; -import net.codecrete.usb.common.USBStructs; +import net.codecrete.usb.usbstandard.DeviceDescriptor; +import net.codecrete.usb.usbstandard.SetupPacket; import java.lang.foreign.GroupLayout; import java.lang.foreign.MemorySegment; @@ -76,25 +76,16 @@ public class USBHelper { // } SetupPacket; // UCHAR Data[0]; //} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST; - public static final GroupLayout USB_DESCRIPTOR_REQUEST$Struct = structLayout(JAVA_INT.withName("ConnectionIndex") - , USBStructs.SetupPacket$Struct.withName("SetupPacket")); + public static final GroupLayout USB_DESCRIPTOR_REQUEST$Struct = structLayout( + JAVA_INT.withName("ConnectionIndex"), + SetupPacket.LAYOUT.withName("SetupPacket") + ); public static final VarHandle USB_DESCRIPTOR_REQUEST_ConnectionIndex = USB_DESCRIPTOR_REQUEST$Struct.varHandle(groupElement("ConnectionIndex")); public static final long USB_DESCRIPTOR_REQUEST_SetupPacket$Offset = USB_DESCRIPTOR_REQUEST$Struct.byteOffset(groupElement("SetupPacket")); public static final long USB_DESCRIPTOR_REQUEST_Data$Offset = USB_DESCRIPTOR_REQUEST$Struct.byteSize(); - // typedef struct _USB_STRING_DESCRIPTOR { - // UCHAR bLength; - // UCHAR bDescriptorType; - // WCHAR bString[1]; - //} USB_STRING_DESCRIPTOR, *PUSB_STRING_DESCRIPTOR; - public static final GroupLayout USB_STRING_DESCRIPTOR$Struct = structLayout(JAVA_BYTE.withName("bLength"), - JAVA_BYTE.withName("bDescriptorType")); - public static final VarHandle USB_STRING_DESCRIPTOR_bLength = - USB_STRING_DESCRIPTOR$Struct.varHandle(groupElement("bLength")); - public static final long USB_STRING_DESCRIPTOR_bString$Offset = USB_STRING_DESCRIPTOR$Struct.byteSize(); - // A5DCBF10-6530-11D2-901F-00C04FB951ED public static final MemorySegment GUID_DEVINTERFACE_USB_DEVICE = Win.CreateGUID(0xA5DCBF10, (short) 0x6530, (short) 0x11D2, (byte) 0x90, (byte) 0x1F, (byte) 0x00, (byte) 0xC0, (byte) 0x4F, (byte) 0xB9, (byte) 0x51 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index fdf20205..d025a70e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -8,9 +8,10 @@ package net.codecrete.usb.windows; import net.codecrete.usb.*; -import net.codecrete.usb.common.DescriptorParser; +import net.codecrete.usb.common.CompositeFunction; +import net.codecrete.usb.common.ConfigurationParser; import net.codecrete.usb.common.USBDeviceImpl; -import net.codecrete.usb.common.USBStructs; +import net.codecrete.usb.usbstandard.SetupPacket; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.winusb.WinUSB; @@ -50,8 +51,8 @@ public void open() { } private void readDescription(MemorySegment configDesc) { - var configuration = DescriptorParser.parseConfigurationDescriptor(configDesc, vendorId(), productId()); - setInterfaces(configuration.interfaces); + var configuration = ConfigurationParser.parseConfigurationDescriptor(configDesc); + setInterfaces(configuration.interfaces()); } @Override @@ -176,15 +177,15 @@ public void releaseInterface(int interfaceNumber) { private MemorySegment createSetupPacket(MemorySession session, USBDirection direction, USBControlTransfer setup, MemorySegment data) { - var setupPacket = session.allocate(USBStructs.SetupPacket$Struct); + var setupPacket = new SetupPacket(session); var bmRequest = (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); - USBStructs.SetupPacket_bmRequest.set(setupPacket, (byte) bmRequest); - USBStructs.SetupPacket_bRequest.set(setupPacket, setup.request()); - USBStructs.SetupPacket_wValue.set(setupPacket, setup.value()); - USBStructs.SetupPacket_wIndex.set(setupPacket, setup.index()); - USBStructs.SetupPacket_wLength.set(setupPacket, (short) (data != null ? data.byteSize() : 0)); - return setupPacket; + setupPacket.setRequestType(bmRequest); + setupPacket.setRequest(setup.request()); + setupPacket.setValue(setup.value()); + setupPacket.setIndex(setup.index()); + setupPacket.setLength(data != null ? (int) data.byteSize() : 0); + return setupPacket.segment(); } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 7954d1f3..2f3e5b82 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -10,6 +10,10 @@ import net.codecrete.usb.USBDevice; import net.codecrete.usb.USBException; import net.codecrete.usb.common.*; +import net.codecrete.usb.usbstandard.ConfigurationDescriptor; +import net.codecrete.usb.usbstandard.DeviceDescriptor; +import net.codecrete.usb.usbstandard.SetupPacket; +import net.codecrete.usb.usbstandard.StringDescriptor; import net.codecrete.usb.windows.gen.kernel32.GUID; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.ole32.Ole32; @@ -29,6 +33,7 @@ import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.*; +import static net.codecrete.usb.usbstandard.Constants.*; /** * Windows implementation of USB device registry. @@ -269,10 +274,10 @@ private USBDevice createDevice(String devicePath, List functi var descriptorSegment = USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(connInfo); var deviceDescriptor = new DeviceDescriptor(descriptorSegment); - int vendorId = deviceDescriptor.idVendor(); - int productId = deviceDescriptor.idProduct(); + int vendorId = deviceDescriptor.vendorID(); + int productId = deviceDescriptor.productID(); - var configDesc = getDescriptor(hubHandle, usbPortNum, USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE, 0, + var configDesc = getDescriptor(hubHandle, usbPortNum, CONFIGURATION_DESCRIPTOR_TYPE, 0, (short) 0, session); var device = new WindowsUSBDevice(devicePath, functions, vendorId, productId, configDesc); @@ -297,14 +302,13 @@ private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, in // create descriptor requests var descriptorRequest = session.allocate(size); USBHelper.USB_DESCRIPTOR_REQUEST_ConnectionIndex.set(descriptorRequest, usbPortNumber); - var setupPacket = descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_SetupPacket$Offset, - USBStructs.SetupPacket$Struct.byteSize()); - USBStructs.SetupPacket_bmRequest.set(setupPacket, (byte) 0x80); // device-to-host / type standard / recipient - // device - USBStructs.SetupPacket_bRequest.set(setupPacket, USBHelper.USB_REQUEST_GET_DESCRIPTOR); - USBStructs.SetupPacket_wValue.set(setupPacket, (short) ((descriptorType << 8) | index)); - USBStructs.SetupPacket_wIndex.set(setupPacket, languageID); - USBStructs.SetupPacket_wLength.set(setupPacket, (short) (size - USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset)); + var setupPacket = new SetupPacket(descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_SetupPacket$Offset, + SetupPacket.LAYOUT.byteSize())); + setupPacket.setRequestType(0x80); // device-to-host / type standard / recipient device + setupPacket.setRequest(USBHelper.USB_REQUEST_GET_DESCRIPTOR); + setupPacket.setValue((descriptorType << 8) | index); + setupPacket.setIndex(languageID); + setupPacket.setLength(size - (int)USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset); // execute request var effectiveSizeHolder = session.allocate(JAVA_INT); @@ -314,12 +318,12 @@ private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, in // determine size of descriptor int expectedSize; - if (descriptorType != USBDescriptors.CONFIGURATION_DESCRIPTOR_TYPE) { + if (descriptorType != CONFIGURATION_DESCRIPTOR_TYPE) { expectedSize = 255 & descriptorRequest.get(JAVA_BYTE, USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset); } else { - var configDesc = descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, - USBDescriptors.Configuration.byteSize()); - expectedSize = (short) USBDescriptors.Configuration_wTotalLength.get(configDesc); + var configDesc = new ConfigurationDescriptor(descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, + ConfigurationDescriptor.LAYOUT.byteSize())); + expectedSize = configDesc.totalLength(); } // check against effective size @@ -340,13 +344,9 @@ private String getStringDescriptor(Addressable hubHandle, int usbPortNumber, int return null; try (var session = MemorySession.openConfined()) { - var stringDesc = getDescriptor(hubHandle, usbPortNumber, USBDescriptors.STRING_DESCRIPTOR_TYPE, index, - USBDescriptors.DEFAULT_LANGUAGE, session); - - int stringLen = 255 & (byte) USBHelper.USB_STRING_DESCRIPTOR_bLength.get(stringDesc); - var chars = - stringDesc.asSlice(USBHelper.USB_STRING_DESCRIPTOR_bString$Offset, stringLen - 2).toArray(JAVA_CHAR); - return new String(chars); + var stringDesc = new StringDescriptor(getDescriptor(hubHandle, usbPortNumber, STRING_DESCRIPTOR_TYPE, index, + DEFAULT_LANGUAGE, session)); + return stringDesc.string(); } } From 44c007750ee310404993bbf622f8a2ffd9d66975 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 24 Sep 2022 20:44:31 +0200 Subject: [PATCH 102/433] Interface associations for Windows --- .../usb/common/CompositeFunction.java | 53 +---- .../usb/usbstandard/StringDescriptor.java | 4 - .../usb/windows/InterfaceHandle.java | 46 ++++ .../usb/windows/WindowsUSBDevice.java | 222 ++++++++++-------- .../usb/windows/WindowsUSBDeviceRegistry.java | 31 ++- 5 files changed, 193 insertions(+), 163 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java b/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java index 3c90d003..497b5aba 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java @@ -7,8 +7,6 @@ package net.codecrete.usb.common; -import java.lang.foreign.MemoryAddress; - /** * Describes the function of an interface of a composite USB device. *

@@ -21,26 +19,13 @@ * multiple interfaces must have consecutive interface numbers. The * interfaces after the first one are called associated interfaces. *

- *

- * On Windows, each function has a separate device path. Each device - * path must be opened and each interface must be opened. - * Furthermore, the first and the associated interfaces are - * treated differently. - *

*/ public class CompositeFunction { - // TODO: implement associated interfaces - - // TODO: implement devices without interfaces - private final int firstInterfaceNumber_; private final int numInterfaces_; - private int classCode_; - private int subclassCode_; - private int protocolCode_; - private String devicePath_; - private MemoryAddress deviceHandle_; - private MemoryAddress firstInterfaceHandle_; + private final int classCode_; + private final int subclassCode_; + private final int protocolCode_; /** * Creates a new instance. @@ -59,18 +44,6 @@ public CompositeFunction(int firstInterfaceNumber, int numInterfaces, int classC protocolCode_ = protocolCode; } - /** - * Creates a new instance with a single interface. - * - * @param interfaceNumber the interface number - * @param devicePath the device path - */ - public CompositeFunction(int interfaceNumber, String devicePath) { - firstInterfaceNumber_ = interfaceNumber; - numInterfaces_ = 1; - devicePath_ = devicePath; - } - public int firstInterfaceNumber() { return firstInterfaceNumber_; } @@ -90,24 +63,4 @@ public int subclassCode() { public int protocolCode() { return protocolCode_; } - - public String devicePath() { - return devicePath_; - } - - public MemoryAddress deviceHandle() { - return deviceHandle_; - } - - public void setDeviceHandle(MemoryAddress deviceHandle) { - deviceHandle_ = deviceHandle; - } - - public MemoryAddress firstInterfaceHandle() { - return firstInterfaceHandle_; - } - - public void setFirstInterfaceHandle(MemoryAddress firstInterfaceHandle) { - firstInterfaceHandle_ = firstInterfaceHandle; - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java index 970821a0..96dea670 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java @@ -48,8 +48,4 @@ public String string() { private static final VarHandle bLength$VH = LAYOUT.varHandle(groupElement("bLength")); private static final long string$offset = LAYOUT.byteOffset(groupElement("string")); - - static { - assert LAYOUT.byteSize() == 7; - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java new file mode 100644 index 00000000..0ef4fa98 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java @@ -0,0 +1,46 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.windows; + +import java.lang.foreign.MemoryAddress; + +/** + * Handles for WinUSB devices and interfaces + */ +class InterfaceHandle { + /** + * The number of this interface. + */ + int interfaceNumber; + /** + * The number of the first interface in the same composite function. + */ + int firstInterfaceNumber; + /** + * The device path. + *

+ * This is only set for the first interface in a composite function. + *

+ */ + String devicePath; + /** + * The file handle of the device. + *

+ * This is only used for the first interface in a composite function. + *

+ */ + MemoryAddress deviceHandle; + /** + * The WinUSB handle of the interface. + */ + MemoryAddress interfaceHandle; + /** + * Count indicating how many interface depend on the device being open. + */ + int deviceOpenCount; +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index d025a70e..2db379bb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -8,16 +8,18 @@ package net.codecrete.usb.windows; import net.codecrete.usb.*; -import net.codecrete.usb.common.CompositeFunction; import net.codecrete.usb.common.ConfigurationParser; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.usbstandard.SetupPacket; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.winusb.WinUSB; +import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; +import java.util.ArrayList; import java.util.List; +import java.util.Map; import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.*; @@ -27,14 +29,43 @@ */ public class WindowsUSBDevice extends USBDeviceImpl { - private final List functions; + private List interfaceHandles_; private boolean isOpen_; - WindowsUSBDevice(String devicePath, List functions, int vendorId, int productId, - MemorySegment configDesc) { + WindowsUSBDevice(String devicePath, Map children, int vendorId, int productId, MemorySegment configDesc) { super(devicePath, vendorId, productId); - this.functions = functions; - readDescription(configDesc); + readDescription(configDesc, devicePath, children); + } + + private void readDescription(MemorySegment configDesc, String devicePath, Map children) { + var configuration = ConfigurationParser.parseConfigurationDescriptor(configDesc); + setInterfaces(configuration.interfaces()); + + // build list of interface handles + interfaceHandles_ = new ArrayList<>(); + for (var intf : configuration.interfaces()) { + var interfaceNumber = intf.number(); + var function = configuration.findFunction(interfaceNumber); + + var intfHandle = new InterfaceHandle(); + intfHandle.interfaceNumber = interfaceNumber; + if (function == null) { + intfHandle.firstInterfaceNumber = interfaceNumber; + intfHandle.devicePath = devicePath; + devicePath = null; + } else if (function.firstInterfaceNumber() == interfaceNumber) { + intfHandle.firstInterfaceNumber = interfaceNumber; + if (children != null) { + intfHandle.devicePath = children.get(interfaceNumber); + } else { + intfHandle.devicePath = devicePath; + devicePath = null; + } + } else { + intfHandle.firstInterfaceNumber = function.firstInterfaceNumber(); + } + interfaceHandles_.add(intfHandle); + } } @Override @@ -50,11 +81,6 @@ public void open() { isOpen_ = true; } - private void readDescription(MemorySegment configDesc) { - var configuration = ConfigurationParser.parseConfigurationDescriptor(configDesc); - setInterfaces(configuration.interfaces()); - } - @Override public void close() { if (!isOpen()) @@ -68,71 +94,37 @@ public void close() { isOpen_ = false; } - private CompositeFunction findFunction(int interfaceNumber) { - return functions.stream() - .filter((func) -> func.firstInterfaceNumber() == interfaceNumber).findFirst().orElse(null); - } - - private CompositeFunction findAnyOpenFunction() { - return functions.stream() - .filter((func) -> func.firstInterfaceHandle() != null).findFirst().orElse(null); - } - - private CompositeFunction findControlTransferFunction(USBControlTransfer setup) { - - int interfaceNumber = -1; - int endpointNumber; - - if (setup.recipient() == USBRecipient.INTERFACE) { - - interfaceNumber = setup.index() & 0xff; - - } else if (setup.recipient() == USBRecipient.ENDPOINT) { - - endpointNumber = setup.index() & 0xff; - if (endpointNumber != 0) { - interfaceNumber = getInterfaceNumber(endpointNumber); - if (interfaceNumber == -1) - interfaceNumber = -2; - } - } - - CompositeFunction function = null; - if (interfaceNumber >= 0) { - function = findFunction(interfaceNumber); - } else if (interfaceNumber == -1) { - function = findAnyOpenFunction(); - } - - if (function == null || function.firstInterfaceHandle() == null) - throw new USBException("Interface not claimed for control transfer"); - - return function; - } - public void claimInterface(int interfaceNumber) { checkIsOpen(); - var intf = getInterface(interfaceNumber); - if (intf == null) - throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); - if (intf.isClaimed()) + var intfHandle = getInterfaceHandle(interfaceNumber); + if (intfHandle.interfaceHandle != null) throw new USBException(String.format("Interface %d has already been claimed", interfaceNumber)); - var function = findFunction(interfaceNumber); - if (function == null) - throw new USBException(String.format("Interface number %d cannot be claimed (no DeviceInterfaceGUID?)", interfaceNumber)); + + var firstIntfHandle = intfHandle; + if (intfHandle.firstInterfaceNumber != interfaceNumber) + firstIntfHandle = getInterfaceHandle(intfHandle.firstInterfaceNumber); + + if (firstIntfHandle.devicePath == null) + throw new USBException(String.format("Interface number %d cannot be claimed (non WinUSB device?)", interfaceNumber)); try (var session = MemorySession.openConfined()) { - // open Windows device - var pathSegment = Win.createSegmentFromString(function.devicePath(), session); - var deviceHandle = Kernel32.CreateFileW(pathSegment, Kernel32.GENERIC_WRITE() | Kernel32.GENERIC_READ(), - Kernel32.FILE_SHARE_WRITE() | Kernel32.FILE_SHARE_READ(), NULL, Kernel32.OPEN_EXISTING(), - Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), NULL); + MemoryAddress deviceHandle; - if (Win.IsInvalidHandle(deviceHandle)) - throw new WindowsUSBException( - String.format("Cannot open USB device %s", function.devicePath()), Kernel32.GetLastError()); + // open Windows device if needed + if (firstIntfHandle.deviceHandle == null) { + var pathSegment = Win.createSegmentFromString(firstIntfHandle.devicePath, session); + deviceHandle = Kernel32.CreateFileW(pathSegment, Kernel32.GENERIC_WRITE() | Kernel32.GENERIC_READ(), + Kernel32.FILE_SHARE_WRITE() | Kernel32.FILE_SHARE_READ(), NULL, Kernel32.OPEN_EXISTING(), + Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), NULL); + + if (Win.IsInvalidHandle(deviceHandle)) + throw new WindowsUSBException( + String.format("Cannot open USB device %s", firstIntfHandle.devicePath), Kernel32.GetLastError()); + } else { + deviceHandle = firstIntfHandle.deviceHandle; + } try { // open interface @@ -141,8 +133,9 @@ public void claimInterface(int interfaceNumber) { throw new WindowsUSBException("Cannot open WinUSB device", Kernel32.GetLastError()); var interfaceHandle = interfaceHandleHolder.get(ADDRESS, 0); - function.setDeviceHandle(deviceHandle); - function.setFirstInterfaceHandle(interfaceHandle); + firstIntfHandle.deviceHandle = deviceHandle; + firstIntfHandle.deviceOpenCount += 1; + intfHandle.interfaceHandle = interfaceHandle; } catch (Throwable e) { Kernel32.CloseHandle(deviceHandle); @@ -156,20 +149,23 @@ public void claimInterface(int interfaceNumber) { public void releaseInterface(int interfaceNumber) { checkIsOpen(); - var intf = getInterface(interfaceNumber); - if (intf == null) - throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); - if (!intf.isClaimed()) + var intfHandle = getInterfaceHandle(interfaceNumber); + if (intfHandle.interfaceHandle == null) throw new USBException(String.format("Interface %d has not been claimed", interfaceNumber)); - var function = findFunction(interfaceNumber); - assert function != null; + var firstIntfHandle = intfHandle; + if (intfHandle.firstInterfaceNumber != interfaceNumber) + firstIntfHandle = getInterfaceHandle(intfHandle.firstInterfaceNumber); + + // close interface + WinUSB.WinUsb_Free(intfHandle.interfaceHandle); + intfHandle.interfaceHandle = null; - if (function.deviceHandle() != null) { - WinUSB.WinUsb_Free(function.firstInterfaceHandle()); - function.setFirstInterfaceHandle(null); - Kernel32.CloseHandle(function.deviceHandle()); - function.setDeviceHandle(null); + // close device + firstIntfHandle.deviceOpenCount -= 1; + if (firstIntfHandle.deviceOpenCount == 0) { + Kernel32.CloseHandle(firstIntfHandle.deviceHandle); + firstIntfHandle.deviceHandle = null; } setClaimed(interfaceNumber, false); @@ -191,14 +187,14 @@ private MemorySegment createSetupPacket(MemorySession session, USBDirection dire @Override public byte[] controlTransferIn(USBControlTransfer setup, int length) { checkIsOpen(); - var function = findControlTransferFunction(setup); + var intfHandle = findControlTransferInterface(setup); try (var session = MemorySession.openConfined()) { var buffer = session.allocate(length); var setupPacket = createSetupPacket(session, USBDirection.IN, setup, buffer); var lengthHolder = session.allocate(JAVA_INT); - if (WinUSB.WinUsb_ControlTransfer(function.firstInterfaceHandle(), setupPacket, buffer, (int) buffer.byteSize(), + if (WinUSB.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) throw new WindowsUSBException("Control transfer IN failed", Kernel32.GetLastError()); @@ -210,7 +206,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { @Override public void controlTransferOut(USBControlTransfer setup, byte[] data) { checkIsOpen(); - var function = findControlTransferFunction(setup); + var intfHandle = findControlTransferInterface(setup); try (var session = MemorySession.openConfined()) { @@ -224,7 +220,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { var setupPacket = createSetupPacket(session, USBDirection.OUT, setup, buffer); var lengthHolder = session.allocate(JAVA_INT); - if (WinUSB.WinUsb_ControlTransfer(function.firstInterfaceHandle(), setupPacket, buffer, (int) buffer.byteSize(), + if (WinUSB.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) throw new WindowsUSBException("Control transfer OUT failed", Kernel32.GetLastError()); } @@ -235,15 +231,14 @@ public void transferOut(int endpointNumber, byte[] data) { checkIsOpen(); var endpoint = getEndpoint(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); - var function = findFunction(endpoint.interfaceNumber()); - assert function != null; + var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var session = MemorySession.openConfined()) { var buffer = session.allocate(data.length); buffer.copyFrom(MemorySegment.ofArray(data)); var lengthHolder = session.allocate(JAVA_INT); - if (WinUSB.WinUsb_WritePipe(function.firstInterfaceHandle(), endpoint.endpointAddress(), buffer, (int) buffer.byteSize(), + if (WinUSB.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) throw new WindowsUSBException("Bulk/interrupt transfer OUT failed", Kernel32.GetLastError()); } @@ -252,19 +247,62 @@ public void transferOut(int endpointNumber, byte[] data) { @Override public byte[] transferIn(int endpointNumber, int maxLength) { var endpoint = getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); - var function = findFunction(endpoint.interfaceNumber()); - assert function != null; + var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var session = MemorySession.openConfined()) { var buffer = session.allocate(maxLength); var lengthHolder = session.allocate(JAVA_INT); - if (WinUSB.WinUsb_ReadPipe(function.firstInterfaceHandle(), endpoint.endpointAddress(), buffer, (int) buffer.byteSize(), lengthHolder - , NULL) == 0) + if (WinUSB.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, (int) buffer.byteSize(), + lengthHolder, NULL) == 0) throw new WindowsUSBException("Bulk/interrupt transfer IN failed", Kernel32.GetLastError()); int len = lengthHolder.get(JAVA_INT, 0); return buffer.asSlice(0, len).toArray(JAVA_BYTE); } } + + private InterfaceHandle getInterfaceHandle(int interfaceNumber) { + for (var intfHandle : interfaceHandles_) { + if (intfHandle.interfaceNumber == interfaceNumber) + return intfHandle; + } + + throw new USBException(String.format("Invalid interface number: %s", interfaceNumber)); + } + + private InterfaceHandle findControlTransferInterface(USBControlTransfer setup) { + + int interfaceNumber = -1; + int endpointNumber; + + if (setup.recipient() == USBRecipient.INTERFACE) { + + interfaceNumber = setup.index() & 0xff; + + } else if (setup.recipient() == USBRecipient.ENDPOINT) { + + endpointNumber = setup.index() & 0xff; + if (endpointNumber != 0) { + interfaceNumber = getInterfaceNumber(endpointNumber); + if (interfaceNumber == -1) + throw new USBException(String.format("Invalid endpoint number %d or interface not claimed", endpointNumber)); + } + } + + if (interfaceNumber >= 0) { + var intfHandle = getInterfaceHandle(interfaceNumber); + if (intfHandle.interfaceHandle == null) + throw new USBException(String.format("Interface number %d has not been claimed", interfaceNumber)); + return intfHandle; + } + + // for control transfer to device, use any claimed interface + for (var intfHandle : interfaceHandles_) { + if (intfHandle.interfaceHandle != null) + return intfHandle; + } + + throw new USBException("Control transfer failed as no interface has been claimed"); + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 2f3e5b82..1e3369a7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.regex.Pattern; import static java.lang.foreign.MemoryAddress.NULL; @@ -156,14 +157,14 @@ private void enumeratePresentDevices() { } /** - * Gets the functions of the children of a composite device + * Enumerate the children of a composite device. * * @param childrenIds the children IDs - * @return a list of functions (interface number and device path) + * @return map of containing children device paths, index by the first interface number */ - private List getCompositeFunctions(List childrenIds) { + private Map enumerateChildren(List childrenIds) { - var functions = new ArrayList(); + var children = new HashMap(); // iterate all children for (var instanceId : childrenIds) { @@ -199,17 +200,16 @@ private List getCompositeFunctions(List childrenIds) try { var devicePath = DeviceProperty.getDevicePath(instanceId, clsid); - functions.add(new CompositeFunction(interfaceNumber, devicePath)); + children.put(interfaceNumber, devicePath); break; } catch (Exception e) { // ignore and try next one } } } - } - return functions; + return children; } private USBDevice createDeviceFromDeviceInfo(MemoryAddress devInfoSetHandle, MemorySegment devInfo, @@ -237,29 +237,26 @@ private USBDevice createDeviceFromDeviceInfo(MemoryAddress devInfoSetHandle, Mem var deviceService = DeviceProperty.getDeviceStringProperty(devInfoSetHandle, devInfo, DeviceProperty.DEVPKEY_Device_Service); - List functions; + Map children = null; if (isCompositeDevice(deviceService)) { - functions = getCompositeFunctions(DeviceProperty.getDeviceStringListProperty(devInfoSetHandle, devInfo, + children = enumerateChildren(DeviceProperty.getDeviceStringListProperty(devInfoSetHandle, devInfo, DeviceProperty.DEVPKEY_Device_Children)); - } else { - functions = new ArrayList<>(); - functions.add(new CompositeFunction(0, devicePath)); } - return createDevice(devicePath, functions, hubHandle, usbPortNum); + return createDevice(devicePath, children, hubHandle, usbPortNum); } } /** * Retrieve device descriptor and create {@code USBDevice} instance * - * @param functions composite functions + * @param devicePath the device path + * @param children map of child device paths, indexed by the first interface number * @param hubHandle the hub handle (parent) * @param usbPortNum the USB port number * @return the {@code USBDevice} instance */ - private USBDevice createDevice(String devicePath, List functions, MemoryAddress hubHandle, - int usbPortNum) { + private USBDevice createDevice(String devicePath, Map children, MemoryAddress hubHandle, int usbPortNum) { try (var session = MemorySession.openConfined()) { @@ -280,7 +277,7 @@ private USBDevice createDevice(String devicePath, List functi var configDesc = getDescriptor(hubHandle, usbPortNum, CONFIGURATION_DESCRIPTOR_TYPE, 0, (short) 0, session); - var device = new WindowsUSBDevice(devicePath, functions, vendorId, productId, configDesc); + var device = new WindowsUSBDevice(devicePath, children, vendorId, productId, configDesc); device.setFromDeviceDescriptor(descriptorSegment); device.setProductString(descriptorSegment, (index) -> getStringDescriptor(hubHandle, usbPortNum, index)); From 83a0e16c8e727a5c0ce5d15bd95c94e98458543d Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 24 Sep 2022 22:49:24 +0200 Subject: [PATCH 103/433] Update README --- README.md | 5 ++--- reference/README.md | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e6a1f4f9..2c30dfb9 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The Foreign Function & Memory API (aka as project Panama) is in preview and will ## Prerequisite -- Java 19 Early Access, preview features enabled (available at https://www.azul.com/downloads/?package=jdk) +- Java 19, preview features enabled (available at https://www.azul.com/downloads/?package=jdk) - Windows (x86 64-bit), macOS (x86 64-bit, ARM 64-bit) or Linux 64 bit (x86 64-bit, ARM 64-bit) It has been tested with Azul Zulu 19.0.77 EA 34. @@ -27,7 +27,7 @@ It has been tested with Azul Zulu 19.0.77 EA 34. - Control, bulk and interrupt transfer - Notifications about connected/disconnected devices - Descriptive information about interfaces, settings and endpoints -- Support fo composite devices +- Support fo composite devices and interface association - Published on Maven Central ### To do @@ -35,7 +35,6 @@ It has been tested with Azul Zulu 19.0.77 EA 34. - Transfers with time-out - Device and USB protocol revision - Alternate interface settings -- Support for associated interfaces - Isochronous transfer ### Not planned diff --git a/reference/README.md b/reference/README.md index 265d80e6..6b5c71d1 100644 --- a/reference/README.md +++ b/reference/README.md @@ -6,3 +6,4 @@ The C++ code contains less error checking, less test cases and does not cover al - [MacOS](macos) (for use with Xcode) - [Windows](windows) (for use with Visual Studio) +- [LInux](linux) (for use with CMake) From 8d11100e76fe999b0346ca793cac7cd4630a5c1c Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 7 Oct 2022 21:21:12 +0200 Subject: [PATCH 104/433] Convert test devices to CMSIS/TinyUSB --- .../composite-stm32/.vscode/settings.json | 7 - test-devices/composite-stm32/README.md | 114 +- .../composite-stm32/bin/blackpill-f401cc.bin | Bin 0 -> 11468 bytes .../composite-stm32/bin/blackpill-f411ce.bin | Bin 0 -> 11472 bytes .../composite-stm32/bin/bluepill-f103c8.bin | Bin 0 -> 10028 bytes test-devices/composite-stm32/bin/firmware.bin | Bin 7060 -> 0 bytes test-devices/composite-stm32/bin/save_bin.sh | 2 - .../composite-stm32/bin/upload_firmware.sh | 2 - test-devices/composite-stm32/include/board.h | 37 + .../composite-stm32/include/circ_buf.h | 155 -- test-devices/composite-stm32/include/common.h | 32 - .../composite-stm32/include/usb_bos.h | 263 -- .../composite-stm32/include/usb_bos_desc.h | 28 - .../composite-stm32/include/usb_descriptor.h | 35 - .../composite-stm32/include/usb_descriptors.h | 31 + .../composite-stm32/include/vendor_custom.h | 115 + .../composite-stm32/lib/config/tusb_config.h | 131 + .../lib/tinyusb/class/audio/audio.h | 933 +++++++ .../lib/tinyusb/class/audio/audio_device.c | 2475 +++++++++++++++++ .../lib/tinyusb/class/audio/audio_device.h | 699 +++++ .../lib/tinyusb/class/bth/bth_device.c | 260 ++ .../lib/tinyusb/class/bth/bth_device.h | 109 + .../lib/tinyusb/class/cdc/cdc.h | 409 +++ .../lib/tinyusb/class/cdc/cdc_device.c | 486 ++++ .../lib/tinyusb/class/cdc/cdc_device.h | 260 ++ .../lib/tinyusb/class/cdc/cdc_host.c | 260 ++ .../lib/tinyusb/class/cdc/cdc_host.h | 134 + .../lib/tinyusb/class/cdc/cdc_rndis.h | 301 ++ .../lib/tinyusb/class/cdc/cdc_rndis_host.c | 289 ++ .../lib/tinyusb/class/cdc/cdc_rndis_host.h | 63 + .../lib/tinyusb/class/dfu/dfu.h | 119 + .../lib/tinyusb/class/dfu/dfu_device.c | 460 +++ .../lib/tinyusb/class/dfu/dfu_device.h | 98 + .../lib/tinyusb/class/dfu/dfu_rt_device.c | 128 + .../lib/tinyusb/class/dfu/dfu_rt_device.h | 54 + .../lib/tinyusb/class/hid/hid.h | 1122 ++++++++ .../lib/tinyusb/class/hid/hid_device.c | 419 +++ .../lib/tinyusb/class/hid/hid_device.h | 393 +++ .../lib/tinyusb/class/hid/hid_host.c | 676 +++++ .../lib/tinyusb/class/hid/hid_host.h | 152 + .../lib/tinyusb/class/midi/midi.h | 212 ++ .../lib/tinyusb/class/midi/midi_device.c | 545 ++++ .../lib/tinyusb/class/midi/midi_device.h | 173 ++ .../lib/tinyusb/class/msc/msc.h | 382 +++ .../lib/tinyusb/class/msc/msc_device.c | 952 +++++++ .../lib/tinyusb/class/msc/msc_device.h | 162 ++ .../lib/tinyusb/class/msc/msc_host.c | 499 ++++ .../lib/tinyusb/class/msc/msc_host.h | 119 + .../lib/tinyusb/class/net/ecm_rndis_device.c | 447 +++ .../lib/tinyusb/class/net/ncm.h | 69 + .../lib/tinyusb/class/net/ncm_device.c | 511 ++++ .../lib/tinyusb/class/net/net_device.h | 118 + .../lib/tinyusb/class/usbtmc/usbtmc.h | 319 +++ .../lib/tinyusb/class/usbtmc/usbtmc_device.c | 886 ++++++ .../lib/tinyusb/class/usbtmc/usbtmc_device.h | 112 + .../lib/tinyusb/class/vendor/vendor_device.c | 272 ++ .../lib/tinyusb/class/vendor/vendor_device.h | 145 + .../lib/tinyusb/class/vendor/vendor_host.c | 146 + .../lib/tinyusb/class/vendor/vendor_host.h | 67 + .../lib/tinyusb/class/video/video.h | 480 ++++ .../lib/tinyusb/class/video/video_device.c | 1151 ++++++++ .../lib/tinyusb/class/video/video_device.h | 97 + .../lib/tinyusb/common/tusb_common.h | 266 ++ .../lib/tinyusb/common/tusb_compiler.h | 274 ++ .../lib/tinyusb/common/tusb_debug.h | 178 ++ .../lib/tinyusb/common/tusb_fifo.c | 1007 +++++++ .../lib/tinyusb/common/tusb_fifo.h | 151 + .../lib/tinyusb/common/tusb_mcu.h | 289 ++ .../lib/tinyusb/common/tusb_private.h | 65 + .../lib/tinyusb/common/tusb_timeout.h | 80 + .../lib/tinyusb/common/tusb_types.h | 541 ++++ .../lib/tinyusb/common/tusb_verify.h | 156 ++ .../composite-stm32/lib/tinyusb/device/dcd.h | 224 ++ .../composite-stm32/lib/tinyusb/device/usbd.c | 1389 +++++++++ .../composite-stm32/lib/tinyusb/device/usbd.h | 865 ++++++ .../lib/tinyusb/device/usbd_control.c | 233 ++ .../lib/tinyusb/device/usbd_pvt.h | 121 + .../lib/tinyusb/dwc2/dcd_dwc2.c | 1351 +++++++++ .../lib/tinyusb/dwc2/dwc2_bcm.h | 89 + .../lib/tinyusb/dwc2/dwc2_efm32.h | 89 + .../lib/tinyusb/dwc2/dwc2_esp32.h | 96 + .../lib/tinyusb/dwc2/dwc2_gd32.h | 101 + .../lib/tinyusb/dwc2/dwc2_stm32.h | 226 ++ .../lib/tinyusb/dwc2/dwc2_type.h | 1739 ++++++++++++ .../lib/tinyusb/dwc2/dwc2_xmc.h | 88 + .../composite-stm32/lib/tinyusb/osal/osal.h | 89 + .../lib/tinyusb/osal/osal_freertos.h | 187 ++ .../lib/tinyusb/osal/osal_mynewt.h | 176 ++ .../lib/tinyusb/osal/osal_none.h | 181 ++ .../lib/tinyusb/osal/osal_pico.h | 184 ++ .../lib/tinyusb/osal/osal_rtthread.h | 132 + .../lib/tinyusb/osal/osal_rtx4.h | 170 ++ .../lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c | 1162 ++++++++ .../stm32_fsdev/dcd_stm32_fsdev_pvt_st.h | 422 +++ .../composite-stm32/lib/tinyusb/tusb.c | 314 +++ .../composite-stm32/lib/tinyusb/tusb.h | 138 + .../composite-stm32/lib/tinyusb/tusb_option.h | 430 +++ test-devices/composite-stm32/platformio.ini | 31 +- test-devices/composite-stm32/save_firmware.sh | 6 + test-devices/composite-stm32/src/board_f1.c | 215 ++ test-devices/composite-stm32/src/board_f4.c | 281 ++ test-devices/composite-stm32/src/common.cpp | 37 - test-devices/composite-stm32/src/main.c | 236 ++ test-devices/composite-stm32/src/main.cpp | 341 --- test-devices/composite-stm32/src/usb_bos.cpp | 98 - .../composite-stm32/src/usb_bos_desc.c | 89 - .../composite-stm32/src/usb_descriptor.cpp | 308 -- .../composite-stm32/src/usb_descriptors.c | 174 ++ .../composite-stm32/src/vendor_custom.c | 111 + test-devices/loopback-stm32/README.md | 72 +- .../loopback-stm32/bin/blackpill-f401cc.bin | Bin 0 -> 9908 bytes .../loopback-stm32/bin/blackpill-f411ce.bin | Bin 0 -> 9912 bytes .../loopback-stm32/bin/bluepill-f103c8.bin | Bin 0 -> 8112 bytes test-devices/loopback-stm32/bin/firmware.bin | Bin 6536 -> 0 bytes test-devices/loopback-stm32/bin/save_bin.sh | 2 - .../loopback-stm32/bin/upload_firmware.sh | 2 - test-devices/loopback-stm32/include/board.h | 37 + .../loopback-stm32/include/circ_buf.h | 155 -- test-devices/loopback-stm32/include/common.h | 32 - .../{usb_descriptor.h => usb_descriptors.h} | 12 +- .../loopback-stm32/include/vendor_custom.h | 115 + test-devices/loopback-stm32/include/wcid.h | 17 - .../loopback-stm32/lib/config/tusb_config.h | 122 + .../lib/tinyusb/class/audio/audio.h | 933 +++++++ .../lib/tinyusb/class/audio/audio_device.c | 2475 +++++++++++++++++ .../lib/tinyusb/class/audio/audio_device.h | 699 +++++ .../lib/tinyusb/class/bth/bth_device.c | 260 ++ .../lib/tinyusb/class/bth/bth_device.h | 109 + .../lib/tinyusb/class/cdc/cdc.h | 409 +++ .../lib/tinyusb/class/cdc/cdc_device.c | 486 ++++ .../lib/tinyusb/class/cdc/cdc_device.h | 260 ++ .../lib/tinyusb/class/cdc/cdc_host.c | 260 ++ .../lib/tinyusb/class/cdc/cdc_host.h | 134 + .../lib/tinyusb/class/cdc/cdc_rndis.h | 301 ++ .../lib/tinyusb/class/cdc/cdc_rndis_host.c | 289 ++ .../lib/tinyusb/class/cdc/cdc_rndis_host.h | 63 + .../lib/tinyusb/class/dfu/dfu.h | 119 + .../lib/tinyusb/class/dfu/dfu_device.c | 460 +++ .../lib/tinyusb/class/dfu/dfu_device.h | 98 + .../lib/tinyusb/class/dfu/dfu_rt_device.c | 128 + .../lib/tinyusb/class/dfu/dfu_rt_device.h | 54 + .../lib/tinyusb/class/hid/hid.h | 1122 ++++++++ .../lib/tinyusb/class/hid/hid_device.c | 419 +++ .../lib/tinyusb/class/hid/hid_device.h | 393 +++ .../lib/tinyusb/class/hid/hid_host.c | 676 +++++ .../lib/tinyusb/class/hid/hid_host.h | 152 + .../lib/tinyusb/class/midi/midi.h | 212 ++ .../lib/tinyusb/class/midi/midi_device.c | 545 ++++ .../lib/tinyusb/class/midi/midi_device.h | 173 ++ .../lib/tinyusb/class/msc/msc.h | 382 +++ .../lib/tinyusb/class/msc/msc_device.c | 952 +++++++ .../lib/tinyusb/class/msc/msc_device.h | 162 ++ .../lib/tinyusb/class/msc/msc_host.c | 499 ++++ .../lib/tinyusb/class/msc/msc_host.h | 119 + .../lib/tinyusb/class/net/ecm_rndis_device.c | 447 +++ .../lib/tinyusb/class/net/ncm.h | 69 + .../lib/tinyusb/class/net/ncm_device.c | 511 ++++ .../lib/tinyusb/class/net/net_device.h | 118 + .../lib/tinyusb/class/usbtmc/usbtmc.h | 319 +++ .../lib/tinyusb/class/usbtmc/usbtmc_device.c | 886 ++++++ .../lib/tinyusb/class/usbtmc/usbtmc_device.h | 112 + .../lib/tinyusb/class/vendor/vendor_device.c | 272 ++ .../lib/tinyusb/class/vendor/vendor_device.h | 145 + .../lib/tinyusb/class/vendor/vendor_host.c | 146 + .../lib/tinyusb/class/vendor/vendor_host.h | 67 + .../lib/tinyusb/class/video/video.h | 480 ++++ .../lib/tinyusb/class/video/video_device.c | 1151 ++++++++ .../lib/tinyusb/class/video/video_device.h | 97 + .../lib/tinyusb/common/tusb_common.h | 266 ++ .../lib/tinyusb/common/tusb_compiler.h | 274 ++ .../lib/tinyusb/common/tusb_debug.h | 178 ++ .../lib/tinyusb/common/tusb_fifo.c | 1007 +++++++ .../lib/tinyusb/common/tusb_fifo.h | 151 + .../lib/tinyusb/common/tusb_mcu.h | 289 ++ .../lib/tinyusb/common/tusb_private.h | 65 + .../lib/tinyusb/common/tusb_timeout.h | 80 + .../lib/tinyusb/common/tusb_types.h | 541 ++++ .../lib/tinyusb/common/tusb_verify.h | 156 ++ .../loopback-stm32/lib/tinyusb/device/dcd.h | 224 ++ .../loopback-stm32/lib/tinyusb/device/usbd.c | 1389 +++++++++ .../loopback-stm32/lib/tinyusb/device/usbd.h | 865 ++++++ .../lib/tinyusb/device/usbd_control.c | 233 ++ .../lib/tinyusb/device/usbd_pvt.h | 121 + .../lib/tinyusb/dwc2/dcd_dwc2.c | 1351 +++++++++ .../lib/tinyusb/dwc2/dwc2_bcm.h | 89 + .../lib/tinyusb/dwc2/dwc2_efm32.h | 89 + .../lib/tinyusb/dwc2/dwc2_esp32.h | 96 + .../lib/tinyusb/dwc2/dwc2_gd32.h | 101 + .../lib/tinyusb/dwc2/dwc2_stm32.h | 226 ++ .../lib/tinyusb/dwc2/dwc2_type.h | 1739 ++++++++++++ .../lib/tinyusb/dwc2/dwc2_xmc.h | 88 + .../loopback-stm32/lib/tinyusb/osal/osal.h | 89 + .../lib/tinyusb/osal/osal_freertos.h | 187 ++ .../lib/tinyusb/osal/osal_mynewt.h | 176 ++ .../lib/tinyusb/osal/osal_none.h | 181 ++ .../lib/tinyusb/osal/osal_pico.h | 184 ++ .../lib/tinyusb/osal/osal_rtthread.h | 132 + .../lib/tinyusb/osal/osal_rtx4.h | 170 ++ .../lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c | 1162 ++++++++ .../stm32_fsdev/dcd_stm32_fsdev_pvt_st.h | 422 +++ .../loopback-stm32/lib/tinyusb/tusb.c | 314 +++ .../loopback-stm32/lib/tinyusb/tusb.h | 138 + .../loopback-stm32/lib/tinyusb/tusb_option.h | 430 +++ test-devices/loopback-stm32/platformio.ini | 30 +- test-devices/loopback-stm32/save_firmware.sh | 6 + test-devices/loopback-stm32/src/board_f1.c | 215 ++ test-devices/loopback-stm32/src/board_f4.c | 281 ++ test-devices/loopback-stm32/src/common.cpp | 37 - test-devices/loopback-stm32/src/main.c | 234 ++ test-devices/loopback-stm32/src/main.cpp | 233 -- .../loopback-stm32/src/usb_descriptor.cpp | 158 -- .../loopback-stm32/src/usb_descriptors.c | 151 + .../loopback-stm32/src/vendor_custom.c | 111 + test-devices/loopback-stm32/src/wcid.cpp | 81 - 214 files changed, 65549 insertions(+), 2165 deletions(-) delete mode 100644 test-devices/composite-stm32/.vscode/settings.json create mode 100755 test-devices/composite-stm32/bin/blackpill-f401cc.bin create mode 100755 test-devices/composite-stm32/bin/blackpill-f411ce.bin create mode 100755 test-devices/composite-stm32/bin/bluepill-f103c8.bin delete mode 100755 test-devices/composite-stm32/bin/firmware.bin delete mode 100755 test-devices/composite-stm32/bin/save_bin.sh delete mode 100755 test-devices/composite-stm32/bin/upload_firmware.sh create mode 100644 test-devices/composite-stm32/include/board.h delete mode 100644 test-devices/composite-stm32/include/circ_buf.h delete mode 100644 test-devices/composite-stm32/include/common.h delete mode 100644 test-devices/composite-stm32/include/usb_bos.h delete mode 100644 test-devices/composite-stm32/include/usb_bos_desc.h delete mode 100644 test-devices/composite-stm32/include/usb_descriptor.h create mode 100644 test-devices/composite-stm32/include/usb_descriptors.h create mode 100644 test-devices/composite-stm32/include/vendor_custom.h create mode 100644 test-devices/composite-stm32/lib/config/tusb_config.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/audio/audio.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.h create mode 100755 test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.c create mode 100755 test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_device.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_device.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/hid/hid.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/midi/midi.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/msc/msc.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/net/ecm_rndis_device.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/net/ncm.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/net/ncm_device.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/net/net_device.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/video/video.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/video/video_device.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/video/video_device.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/common/tusb_common.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/common/tusb_compiler.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/common/tusb_debug.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/common/tusb_mcu.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/common/tusb_private.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/common/tusb_timeout.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/common/tusb_types.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/common/tusb_verify.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/device/dcd.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/device/usbd.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/device/usbd.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/device/usbd_control.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/device/usbd_pvt.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/dwc2/dcd_dwc2.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_bcm.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_efm32.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_esp32.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_gd32.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_stm32.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_type.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_xmc.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/osal/osal.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/osal/osal_freertos.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/osal/osal_mynewt.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/osal/osal_none.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/osal/osal_pico.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/osal/osal_rtthread.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/osal/osal_rtx4.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/tusb.c create mode 100644 test-devices/composite-stm32/lib/tinyusb/tusb.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/tusb_option.h create mode 100755 test-devices/composite-stm32/save_firmware.sh create mode 100644 test-devices/composite-stm32/src/board_f1.c create mode 100644 test-devices/composite-stm32/src/board_f4.c delete mode 100644 test-devices/composite-stm32/src/common.cpp create mode 100644 test-devices/composite-stm32/src/main.c delete mode 100644 test-devices/composite-stm32/src/main.cpp delete mode 100644 test-devices/composite-stm32/src/usb_bos.cpp delete mode 100644 test-devices/composite-stm32/src/usb_bos_desc.c delete mode 100644 test-devices/composite-stm32/src/usb_descriptor.cpp create mode 100644 test-devices/composite-stm32/src/usb_descriptors.c create mode 100644 test-devices/composite-stm32/src/vendor_custom.c create mode 100755 test-devices/loopback-stm32/bin/blackpill-f401cc.bin create mode 100755 test-devices/loopback-stm32/bin/blackpill-f411ce.bin create mode 100755 test-devices/loopback-stm32/bin/bluepill-f103c8.bin delete mode 100755 test-devices/loopback-stm32/bin/firmware.bin delete mode 100755 test-devices/loopback-stm32/bin/save_bin.sh delete mode 100755 test-devices/loopback-stm32/bin/upload_firmware.sh create mode 100644 test-devices/loopback-stm32/include/board.h delete mode 100644 test-devices/loopback-stm32/include/circ_buf.h delete mode 100644 test-devices/loopback-stm32/include/common.h rename test-devices/loopback-stm32/include/{usb_descriptor.h => usb_descriptors.h} (59%) create mode 100644 test-devices/loopback-stm32/include/vendor_custom.h delete mode 100644 test-devices/loopback-stm32/include/wcid.h create mode 100644 test-devices/loopback-stm32/lib/config/tusb_config.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/audio/audio.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/audio/audio_device.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/audio/audio_device.h create mode 100755 test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.c create mode 100755 test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_device.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_device.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/hid/hid.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/midi/midi.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/msc/msc.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/net/ecm_rndis_device.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/net/ncm.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/net/ncm_device.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/net/net_device.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/video/video.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/common/tusb_common.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/common/tusb_compiler.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/common/tusb_debug.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/common/tusb_mcu.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/common/tusb_private.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/common/tusb_timeout.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/common/tusb_types.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/common/tusb_verify.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/device/dcd.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/device/usbd.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/device/usbd.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/device/usbd_control.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/device/usbd_pvt.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_bcm.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_efm32.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_esp32.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_gd32.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_stm32.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_type.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_xmc.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/osal/osal.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/osal/osal_freertos.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/osal/osal_mynewt.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/osal/osal_none.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/osal/osal_pico.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtthread.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtx4.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/tusb.c create mode 100644 test-devices/loopback-stm32/lib/tinyusb/tusb.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/tusb_option.h create mode 100755 test-devices/loopback-stm32/save_firmware.sh create mode 100644 test-devices/loopback-stm32/src/board_f1.c create mode 100644 test-devices/loopback-stm32/src/board_f4.c delete mode 100644 test-devices/loopback-stm32/src/common.cpp create mode 100644 test-devices/loopback-stm32/src/main.c delete mode 100644 test-devices/loopback-stm32/src/main.cpp delete mode 100644 test-devices/loopback-stm32/src/usb_descriptor.cpp create mode 100644 test-devices/loopback-stm32/src/usb_descriptors.c create mode 100644 test-devices/loopback-stm32/src/vendor_custom.c delete mode 100644 test-devices/loopback-stm32/src/wcid.cpp diff --git a/test-devices/composite-stm32/.vscode/settings.json b/test-devices/composite-stm32/.vscode/settings.json deleted file mode 100644 index 7e488cff..00000000 --- a/test-devices/composite-stm32/.vscode/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files.associations": { - "usbd.h": "c", - "usb_bos.h": "c", - "usb_bos_desc.h": "c" - } -} \ No newline at end of file diff --git a/test-devices/composite-stm32/README.md b/test-devices/composite-stm32/README.md index 6f28875c..eb8e508e 100644 --- a/test-devices/composite-stm32/README.md +++ b/test-devices/composite-stm32/README.md @@ -1,26 +1,40 @@ # Composite Test Device -Firmware for a composite device consisting of virtual serial port (aka CDC ACM) on interface 0 and 1 and a vendor-specific class on interface 2. This code is for an STM32F103C8 microcontroller. This microcontroller is found on many inexpensive development board, most notabily on the so called *Blue Pill*. Such boards are available for about 3 USD, including the required ST-Link programmer. +Firmware for a composite device consisting of virtual serial port (aka CDC ACM) on interface 0 and 1 and a vendor-specific class on interface 2. This is the code for STM32 microcontrollers. It is found on many inexpensive development board, most notabily on the so called *Blue Pill* and *Black Pill* boards. They are available for about 3 USD. +## Supported boards -## Endpoint overview +- BlackPill with STM32F401CC microcontroller +- BlackPill with STM32F411CE microcontroller +- BluePill with STM32F103C8 microcontroller + +To upload the firmware, the STM32F4x microcontroller have a built-in USB bootloader. The STM32F1x microcontrollers need an ST-Link debug adapter (or a USB-to-serial converter). + + +## Test features ### Endpoints -| Interface | Endpoint | Transfer Type | Direction | Packet Size | Function | -| - | - | - | - | - | - | -| – | 0x00 | Control | Bidirectional | | See *Control requests* below | -| 0 | 0x84 | Interrupt | Device to host | 16 bytes | CDC: Serial state events (not used) | -| 1 | 0x05 | Bulk | Host to device | 64 bytes | CDC: Serial data from host to device | -| 1 | 0x85 | Bulk | Device to host | 64 bytes | CDC: Serial data from device to host | -| 2 | 0x01 | Bulk | Host to device | 64 bytes | Loopback: all data received on this endpoint are then transmitted on endpoint 0x82. | -| 2 | 0x82 | Bulk | Device to host | 64 bytes | Loopback: Transmits the data received on endpoint 0x01. | -| 2 | 0x03 | Interrupt | Host to device | 16 bytes | Echo: All packets received on this endpoint are transmitted twice on endpoint 0x83. | -| 2 | 0x83 | Interrupt | Device to host | 16 bytes | Echo: Transmits all packets received on endpoint 0x03 twice. | +#define EP_CDC_COMM 0x83 +#define EP_CDC_DATA_RX 0x02 +#define EP_CDC_DATA_TX 0x81 + +#define EP_LOOPBACK_RX 0x01 +#define EP_LOOPBACK_TX 0x82 -The virtual serial port on interfaces 0 and 1 implements the CDC ACM class. All operating systems will recognize it as serial port and will automatically make it available as such. No drivers need to be installed. The implementations connects the incoming and outgoing data in a loopback configuration. So all data sent from the host to the device is send back to the host. Control requests to configure baud rates, parity etc. are accpeted but have no effect. And the implementation does not send any state events. -The bulk endpoints 0x01 and 0x82 use an internal buffer of about 1000 bytes. Data up to this amount can be sent and received sequentially. If more data is sent without receiving at the same time, flow control kicks in and endpoint 0x01 will stop receiving data until there is room in the buffer. +| Endpoint | Transfer Type | Direction | Packet Size | Function | +| - | - | - | - | - | +| 0x00 | Control | Bidirectional | | See *Control requests* below | +| 0x81 | Bulk | Device to host | 64 bytes | CDC: Serial data from device to host. | +| 0x02 | Bulk | Host to device | 64 bytes | CDC: Serial data from host to device. | +| 0x83 | Interrupt | Device to host | 64 bytes | CDC: Serial state events (not used). | +| 0x01 | Bulk | Host to device | 64 bytes | Loopback: all data received on this endpoint is transmitted on endpoint 0x82. | +| 0x82 | Bulk | Device to host | 64 bytes | Loopback: Transmits the data received on endpoint 0x01. | + +The virtual serial port on interfaces 0 and 1 implements the CDC ACM class. All operating systems will recognize it as serial port and will automatically make it available as such. No drivers need to be installed. The implementations connects the incoming and outgoing data in a loopback configuration. So all data sent from the host to the device is send back to the host. Control requests to configure baud rates, parity etc. are accepted but have no effect. And the implementation does not send any state events. + +The bulk endpoints 0x01 and 0x82 use an internal buffer of about 500 bytes. Data up to this amount can be sent and received sequentially. If more data is sent without receiving at the same time, flow control kicks in and endpoint 0x01 will stop receiving data until there is room in the buffer. ### Control requests @@ -28,36 +42,76 @@ The bulk endpoints 0x01 and 0x82 use an internal buffer of about 1000 bytes. Dat Several vendor-specific control requests are supported for testing: | `bmRequest` | `bRequest` | `wValue` | `wIndex` | `wLength` | Data | Action | -| -:| -:| -:| -:| -:| - | - | -| 0x41 | 0x01 | *value* | 2 | 0 | none | Host to device: *value* is saved in device | -| 0x41 | 0x02 | 0 | 2 | 4 | *value* (32-bit LE) | Host to device: *value* is saved in device | -| 0xC1 | 0x03 | 0 | 2 | 4 | *value* (32-bit LE) | Device to host: saved *value* is transmitted | - -Note: The lower byte of `wIndex` contains the interface number. +| - | - | - | - | - | - | - | +| 0x41 | 0x01 | *value* | 0 | 0 | none | Host to device: *value* is saved in device | +| 0x41 | 0x02 | 0 | 0 | 4 | *value* (32-bit LE) | Host to device: *value* is saved in device | +| 0xC1 | 0x03 | 0 | 0 | 4 | *value* (32-bit LE) | Device to host: saved *value* is transmitted | -Additionally, the control request of CDC ACM PTSN (for configuring and querying the serial port) are accepted but have no effect in most cases. - -## Building +## Building the firmware This project requires [PlatformIO](https://platformio.org/). The easiest way to get up and running is to use Visual Studio Code and then install the [PlatformIO IDE extension](https://marketplace.visualstudio.com/items?itemName=platformio.platformio-ide). -After the extension is installed, open this folder and then click checkbox icon (*Build* action) in the status bar. +After the extension is installed, open this folder and select your board type by clicking on "Default (tinyusb-stm32)" in the status bar. Wait until the status bar no longer indicates activity. Then click the checkbox icon (*Build* action) in the status bar. + +To load the firmware onto the board, either connect it via ST-Link programmer to the 4 pins on the short side of the board or use the built-in USB bootloader (BlackPill only). -To upload the code to the microcontroller: +For upload with a ST-Link programmer: - Connect the ST-Link programmer to the development board - Connect the ST-Link programmer to your computer - Click the arrow icon (*Upload* action) in the status bar +For other means of upload, see *Binary releases* below. + + +## Binary releases + +The directory `bin` contains a pre-built firmware: + +- `blackpill-f401cc.bin`: Firmware for BlackPill with STM32F401CC microcontroller +- `blackpill-f411ce.bin`: Firmware for BlackPill with STM32F411CE microcontroller +- `bluepill-f103c8.bin`: Firmware for BluePill with STM32F103C8 microcontroller -## Binary release +### Upload using built-in bootloader -The directory `bin` contains a pre-built firmware. In order to upload it, a utility is needed, either [STM32CubeProgrammer](https://www.st.com/en/development-tools/stm32cubeprog.html) (requires an STM account, does not properly work on macOS) or the [open-source ST-Link command line utility](https://github.com/stlink-org/stlink). See the respective web site for installation instructions. +To upload using the BlackPill's built-in bootloader: -If the commmand line utility is used, run these commands to upload it: +1. Install the *dfu-util* command-line utility (typically using a package manager like *HomeBrew* on macOS, *Chocolatey* on Windows, or *Apt* on Linux). +2. Press the *Boot* button while connecting the board via USB to your computer. By pressing the *Boot* button, the device enters bootloader mode. +3. Verify with `dfu-util --list` that the bootloader is available via USB. If not unplug the device and repeat step 2. +4. Run the below command from the project directory. +5. Unplug and reconnect the board from your computer. The LED should now blink about twice a second. ``` -cd stm32-loopback/bin -st-flash write firmware.bin 0x08000000 +dfu-util --device 0483:df11 --alt 0 --dfuse-address 0x08000000 --reset --download bin/blackpill-fxxx.bin ``` + +Make sure you change the filename `blackpill-fxxx.bin` to the name matching your board. + +If you built the firmware yourself, you will find the firmware file in `.pio/build/blackpill-f401cc/firmware.bin` (and similar for other boards). + +### Upload using ST-Link programmer + +In order to upload it using the ST-Link programmer: + +1. Install the *stlink* command-line utility (typically using a package manager like *HomeBrew* on macOS, *Chocolatey* on Windows, or *Apt* on Linux). +2. Unplug the microcontroller board from your computer (in case it is connected). +3. Connect the ST-Link via jumper wires to your board (4 pins on the short side of the board). +4. Connect the ST-Link via USB cable to your computer. +5. Run the below command from the project directory. +6. Unplug the microcontroller board from the ST-Link and connect it to your computer (via USB). + +``` +st-flash write bin/bluepill-f103c8.bin 0x08000000 +``` + +Make sure you change the filename `bluepill-f103c8.bin` to the name matching your board. + +If you built the firmware yourself, you will find the firmware file in `.pio/build/bluepill-f103c8/firmware.bin` (and similar for other boards). + +## Implementation + +This code uses the CMSIS 5 library (mainly for startup code and register definitions) and TinyUSB for USB. For easier use with PlatformIO, a copy of TinyUSB is integrated into the project. The used TinyUSB code in `lib/tinyusb` is an unmodified subset of the library. + +Since the official TinyUSB vendor class is rather limited, an alternative implementation is provided (see [vendor_custom.h](include/vendor_custom.h) and [vendor_custom.c](src/vendor_custom.c)). \ No newline at end of file diff --git a/test-devices/composite-stm32/bin/blackpill-f401cc.bin b/test-devices/composite-stm32/bin/blackpill-f401cc.bin new file mode 100755 index 0000000000000000000000000000000000000000..e09bfae6ea72119f780f86487b3db5bdf750de89 GIT binary patch literal 11468 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 z z>Uc{DS`Mu?v=+uJK~Ezyng?G3S^)34Xc4*@@lY#3w?S<_lyi|4YGx?;c-sPiFNXR& zxPV>={XD$QF#f;dJd{=cq}uk_gKG(6<&Qn)s;RDhWRk->U>!^0`2uwPMaXqD!?PbA z(*LW8@<))D>wt&k=bleM?Bc|4^CU~G00%M$fg{ub3cC#+^1shvXquaf*!vaWTOtj7 N^~PorIQS7M{||CU`o#bM literal 0 HcmV?d00001 diff --git a/test-devices/composite-stm32/bin/bluepill-f103c8.bin b/test-devices/composite-stm32/bin/bluepill-f103c8.bin new file mode 100755 index 0000000000000000000000000000000000000000..004fc49dc32058d95419d624c0f6d7bb16305641 GIT binary patch literal 10028 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 +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +// Initialize the board +void board_init(void); + +// Set the LED on or off +void board_led_write(bool on); + +// Return the number of milliseconds since a time in the past +uint32_t board_millis(void); + +// USB serial number +extern char board_serial_num[13]; + + +#ifdef __cplusplus +} +#endif diff --git a/test-devices/composite-stm32/include/circ_buf.h b/test-devices/composite-stm32/include/circ_buf.h deleted file mode 100644 index 4d9a6970..00000000 --- a/test-devices/composite-stm32/include/circ_buf.h +++ /dev/null @@ -1,155 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Circular buffer for raw binary data. -// -// The circular buffer allows a reader and writer to -// use the buffer concurrently. -// - -#pragma once - -#include -#include - -#include - -/** - * Circular buffer for raw binary data. - * - * The circular buffer allows a reader and writer to - * use the buffer concurrently. - * - * @param N number of bytes that fit into the buffer - */ -template -struct circ_buf { - private: - static constexpr int BUF_SIZE = N + 1; - - // 0 <= head < BUF_SIZE - // 0 <= tail < BUF_SIZE - // head == tail: buffer is empty - // Therefore, the buffer must never be filled completely. - volatile int buf_head = 0; // updated when adding data - volatile int buf_tail = 0; // updated when removing data - - uint8_t buffer[BUF_SIZE]; - - public: - /// Creates a new instance - circ_buf(); - - /// Returns the maximum number of bytes that can be added to the buffer - int avail_size(); - - /// Returns the number of bytes in the buffer - int data_size(); - - /** - * Gets the oldest data from the buffer and removes it. - * @param buf buffer to copy data to - * @param max_len maximum number of bytes to copy - * @return the effective number of bytes - */ - int get_data(uint8_t *buf, int max_len); - - /** - * Adds data to the buffer - * - * @param buf the buffer with the data - * @param len the number of bytes to add - */ - void add_data(const uint8_t *buf, int len); - - /// Resets (empties) the circular buffer - void reset(); -}; - -template -circ_buf::circ_buf() : buf_head(0), buf_tail(0) {} - -template -int circ_buf::avail_size() { - int head = buf_head; - int tail = buf_tail; - - if (head >= tail) { - return BUF_SIZE - (head - tail) - 1; - } else { - return tail - head - 1; - } -} - -template -int circ_buf::data_size() { - int head = buf_head; - int tail = buf_tail; - - if (head >= tail) { - return head - tail; - } else { - return BUF_SIZE - (tail - head); - } -} - -template -int circ_buf::get_data(uint8_t *buf, int max_len) { - int tail = buf_tail; - int head = buf_head; - - if (tail == head) - return 0; - - // get available data (without wrap around) - int len = (head > tail ? head : BUF_SIZE) - tail; - - // limit data to max_len - len = std::min(len, max_len); - - // copy data - memcpy(buf, buffer + tail, len); - - // update tail - tail += len; - if (tail >= BUF_SIZE) - tail -= BUF_SIZE; - buf_tail = tail; - - // sufficient data or no more data - if (len == max_len || tail != 0) - return len; - - // copy more data - return get_data(buf + len, max_len - len) + len; -} - -template -void circ_buf::add_data(const uint8_t *buf, int len) { - int head = buf_head; - - // copy first part (from head to end of circular buffer) - int n = std::min(len, BUF_SIZE - head); - memcpy(buffer + head, buf, n); - - // copy second part if needed (to start of circular buffer) - if (n < len) - memcpy(buffer, buf + n, len - n); - - // update head - head += len; - if (head >= BUF_SIZE) - head -= BUF_SIZE; - buf_head = head; -} - -template -void circ_buf::reset() { - buf_head = 0; - buf_tail = 0; -} diff --git a/test-devices/composite-stm32/include/common.h b/test-devices/composite-stm32/include/common.h deleted file mode 100644 index 427b2eb4..00000000 --- a/test-devices/composite-stm32/include/common.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Commmon functions -// - -#pragma once - -#include - -/** - * @brief Initializes systick services - */ -void systick_init(); - -/** - * @brief Gets the time. - * - * @return number of milliseconds since a fixed time in the past - */ -uint32_t millis(); - -/** - * @brief Delays execution (busy wait) - * @param ms delay length, in milliseconds - */ -void delay(uint32_t ms); diff --git a/test-devices/composite-stm32/include/usb_bos.h b/test-devices/composite-stm32/include/usb_bos.h deleted file mode 100644 index f73ebd65..00000000 --- a/test-devices/composite-stm32/include/usb_bos.h +++ /dev/null @@ -1,263 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// USB binary device object store (BOS) -// - -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/// Descriptor type Binary Device Object Store (BOS) - -static const uint8_t USB_DT_BOS = 15; -/// Descriptor type Device Capability -#define USB_DT_DEVICE_CAPABILITY 16 - -/// Microsoft WCID string index -static const uint8_t USB_WIN_MSFT_WCID_STR_IDX = 0xee; - -/// Microsoft compatible ID feature descriptor request index (wIndex) -static const uint16_t USB_WIN_COMP_ID_REQ_INDEX = 0x0004; - -#define USB_WIN_WCID_DEFAULT_VENDOR_CODE 0xf0 - - - -/// USB BOS device capability types -typedef enum { - /// USB BOS device capability type for Wireless USB-specific device level capabilities - USB_DEV_CAPA_WIRELESS_USB = 0x01, - /// USB BOS device capability type for USB 2.0 extension descriptor - USB_DEV_CAPA_USB_2_0_EXTENSION = 0x02, - /// USB BOS device capability type for SuperSpeed USB specific device level capabilities - USB_DEV_CAPA_SUPERSPEED_USB = 0x03, - /// USB BOS device capability type for instance unique ID used to identify the instance across all operating modes - USB_DEV_CAPA_CONTAINER_ID = 0x04, - /// USB BOS device capability type for device capability specific to a particular platform/operating system - USB_DEV_CAPA_PLATFORM = 0x05, - /// USB BOS device capability type for various PD capabilities of this device - USB_DEV_CAPA_POWER_DELIVERY_CAPABILITY = 0x06, - /// USB BOS device capability type for information on each battery supported by the device - USB_DEV_CAPA_BATTERY_INFO_CAPABILITY = 0x07, - /// USB BOS device capability type for consumer characteristics of a port on the device - USB_DEV_CAPA_PD_CONSUMER_PORT_CAPABILITY = 0x08, - /// USB BOS device capability type for provider characteristics of a port on the device - USB_DEV_CAPA_PD_PROVIDER_PORT_CAPABILITY = 0x09, - /// USB BOS device capability type for SuperSpeed Plus USB specific device level capabilities - USB_DEV_CAPA_SUPERSPEED_PLUS = 0x0a, - /// USB BOS device capability type for precision time measurement (PTM) capability descriptor - USB_DEV_CAPA_PRECISION_TIME_MEASUREMENT = 0x0b, - /// USB BOS device capability type for wireless USB 1.1-specific device level capabilities - USB_DEV_CAPA_WIRELESS_USB_EXT = 0x0c, - /// USB BOS device capability type for billboard capability - USB_DEV_CAPA_BILLBOARD = 0x0d, - /// USB BOS device capability type for authentication capability descriptor - USB_DEV_CAPA_AUTHENTICATION = 0x0e, - /// USB BOS device capability type billboard ex capability - USB_DEV_CAPA_BILLBOARD_EX = 0x0f, - /// USB BOS device capability type for summarizing configuration information for a function implemented by the device - USB_DEV_CAPA_CONFIGURATION_SUMMARY = 0x10, -} usb_dev_capa_type_e; - -/// USB BOS descriptor -typedef struct usb_bos_desc { - /// Size of this descriptor - uint8_t bLength; - /// Type of this descriptor (use USB_DT_BOS) - uint8_t bDescriptorType; - /// Length of this descriptor and all of its sub descriptors - uint16_t wTotalLength; - /// The number of separate device capability descriptors in the BOS - uint8_t bNumDeviceCaps; -} __attribute__((packed)) usb_bos_desc; - -/// USB BOS device capability descriptor (generic) -typedef struct usb_bos_device_capability_desc { - /// Size of this descriptor - uint8_t bLength; - /// Type of this descriptor (use USB_DT_DEVICE_CAPABILITY) - uint8_t bDescriptorType; - /// Device capability type (see usb_dev_capa_type_e) - uint8_t bDevCapabilityType; - /// Capability-specific data - uint8_t data[]; -} __attribute__((packed)) usb_bos_device_capability_desc; - -/// USB BOS device capability platform descriptor -typedef struct usb_bos_platform_desc { - /// Size of this descriptor - uint8_t bLength; - /// Type of this descriptor (use USB_DT_DEVICE_CAPABILITY) - uint8_t bDescriptorType; - /// Device capability type (use USB_DEV_CAPA_PLATFORM) - uint8_t bDevCapabilityType; - /// Reserved. Set to 0. - uint8_t bReserved; - /// A 128-bit number (UUID) that uniquely identifies a platform specific capability of the device - uint8_t platformCapabilityUUID[16]; - /// Platform-specific capability data - uint8_t capabilityData[]; -} __attribute__((packed)) usb_bos_platform_desc; - - -/// Microsoft OS 2.0 request `wIndex` value to retrieve MS OS 2.0 vendor-specific descriptor -static const uint8_t USB_MSOS20_CTRL_INDEX_DESC = 0x07; -/// Microsoft OS 2.0 request `wIndex` value to set alternate enumeration -static const uint8_t USB_MSOS20_CTRL_INDEX_SET_ALT_ENUM = 0x08; - -/// UUID for Microsoft OS 2.0 platform capability: {d8dd60df-4589-4cc7-9cd2-659d9e648a9f} -#define USB_PLATFORM_CAPABILITY_MICROSOFT_OS20_UUID {0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F} - -/// Microsoft OS 2.0 descriptor types -typedef enum { - /// Microsoft OS 2.0 descriptor type for set header - USB_MSOS20_DT_SET_HEADER_DESCRIPTOR = 0x00, - /// Microsoft OS 2.0 descriptor type for configuration subset header - USB_MSOS20_DT_SUBSET_HEADER_CONFIGURATION = 0x01, - /// Microsoft OS 2.0 descriptor type for function subset header - USB_MSOS20_DT_SUBSET_HEADER_FUNCTION = 0x02, - /// Microsoft OS 2.0 feature descriptor type for compatible ID descriptor - USB_MSOS20_DT_FEATURE_COMPATBLE_ID = 0x03, - /// Microsoft OS 2.0 feature descriptor type for registry propery descriptor - USB_MSOS20_DT_FEATURE_REG_PROPERTY = 0x04, - /// Microsoft OS 2.0 feature descriptor type for minimum USB resume time descriptor - USB_MSOS20_DT_FEATURE_MIN_RESUME_TIME = 0x05, - /// Microsoft OS 2.0 feature descriptor type for model ID descriptor - USB_MSOS20_DT_FEATURE_MODEL_ID = 0x06, - /// Microsoft OS 2.0 feature descriptor type for CCGP device descriptor - USB_MSOS20_DT_FEATURE_CCGP_DEVICE = 0x07, - /// Microsoft OS 2.0 feature descriptor type for vendor revision descriptor - USB_MSOS20_DT_FEATURE_VENDOR_REVISION = 0x08, -} usb_msos20_desc_type_e; - -/// Microsoft OS 2.0 property types -typedef enum { - /// A NULL-terminated Unicode String (REG_SZ) - USB_MSOS20_PROP_DATA_TYPE_STRING = 1, - /// A NULL-terminated Unicode String that includes environment variables (REG_EXPAND_SZ) - USB_MSOS20_PROP_DATA_TYPE_STRING_EXPAND = 2, - /// Free-form binary (REG_BINARY) - USB_MSOS20_PROP_DATA_TYPE_BINARY = 3, - /// A little-endian 32-bit integer (REG_DWORD_LITTLE_ENDIAN) - USB_MSOS20_PROP_DATA_TYPE_INT32LE = 4, - /// A big-endian 32-bit integer (REG_DWORD_BIG_ENDIAN) - USB_MSOS20_PROP_DATA_TYPE_INT32BE = 5, - /// A NULL-terminated Unicode string that contains a symbolic link (REG_LINK) - USB_MSOS20_PROP_DATA_TYPE_STRING_LINK = 6, - /// Multiple NULL-terminated Unicode strings (REG_MULTI_SZ) - USB_MSOS20_PROP_DATA_TYPE_STRING_MULTI = 7, -} usb_msos20_prop_data_type_e; - -/// Microsoft OS 2.0 descriptor Windows version -typedef enum { - /// Windows version 8.1 - USB_MSOS20_WIN_VER_8_1 = 0x06030000, - /// Windows version 10 - USB_MSOS20_WIN_VER_10 = 0x0a000000, -} usb_msos20_win_ver_e; - -/// USB BOS device capability platform descriptor for Microsoft OS 2.0 -typedef struct usb_msos20_platform_desc { - /// Size of this descriptor - uint8_t bLength; - /// Type of this descriptor (use USB_DT_DEVICE_CAPABILITY) - uint8_t bDescriptorType; - /// Device capability type (use USB_DEV_CAPA_PLATFORM) - uint8_t bDevCapabilityType; - /// Reserved. Set to 0. - uint8_t bReserved; - /// A 128-bit number / UUID (use USB_PLATFORM_CAPABILITY_MICROSOFT_OS20_UUID) - uint8_t platformCapabilityUUID[16]; - /// Minimum Windows version (see usb_msos20_win_ver_e) - uint32_t dwWindowsVersion; - /// The length, in bytes, of the MS OS 2.0 descriptor set - uint16_t wMSOSDescriptorSetTotalLength; - /// Vendor defined code to use to retrieve this version of the MS OS 2.0 descriptor and also to set alternate enumeration behavior on the device - uint8_t bMS_VendorCode; - /// A non-zero value to send to the device to indicate that the device may return non-default USB descriptors for enumeration. If the device does not support alternate enumeration, this value shall be 0. - uint8_t bAltEnumCode; -} __attribute__((packed)) usb_msos20_platform_desc; - -/// Microsoft OS 2.0 descriptor set header -typedef struct usb_msos20_desc_set_header -{ - /// The length, in bytes, of this header - uint16_t wLength; - /// The type of this descriptor (use USB_MSOS20_DT_SET_HEADER_DESCRIPTOR) - uint16_t wDescriptorType; - /// Windows version (see usb_msos20_win_ver_e) - uint32_t dwWindowsVersion; - /// The size of entire MS OS 2.0 descriptor set. The value shall match the value in the descriptor set information structure. - uint16_t wTotalLength; -} __attribute__((packed)) usb_msos20_desc_set_header; - -/// Microsoft OS 2.0 descriptor configuration subset header -typedef struct usb_msos20_desc_subset_header_config -{ - /// The length, in bytes, of this header - uint16_t wLength; - /// The type of this descriptor (use USB_MSOS20_DT_SUBSET_HEADER_CONFIGURATION) - uint16_t wDescriptorType; - /// The configuration value for the USB configuration to which this subset applies - uint8_t bConfigurationValue; - /// Reserved. Set to 0. - uint8_t bReserved; - /// The size of entire configuration subset including this header. - uint16_t wTotalLength; -} __attribute__((packed)) usb_msos20_desc_subset_header_config; - -/// Microsoft OS 2.0 descriptor function subset header -typedef struct usb_msos20_desc_subset_header_function -{ - /// The length, in bytes, of this header - uint16_t wLength; - /// The type of this descriptor (use USB_MSOS20_DT_SUBSET_HEADER_FUNCTION) - uint16_t wDescriptorType; - /// The interface number for the first interface of the function to which this subset applies. - uint8_t bFirstInterface; - /// Reserved. Set to 0. - uint8_t bReserved; - /// The size of entire function subset including this header. - uint16_t wTotalLength; -} __attribute__((packed)) usb_msos20_desc_subset_header_function; - -/// Microsoft OS 2.0 compatible ID descriptor -typedef struct usb_msos20_desc_compatible_id -{ - /// The length, in bytes, of this header - uint16_t wLength; - /// The type of this descriptor (use USB_MSOS20_DT_FEATURE_COMPATBLE_ID) - uint16_t wDescriptorType; - /// Compatible ID string - char compatibleID[8]; - /// Sub-compatible ID string - char subCompatibleID[8]; -} __attribute__((packed)) usb_msos20_desc_compatible_id; - -extern const usb_msos20_platform_desc msos_desc; - -/** - * Register the control request handler to respond to BOS request (for automatic WinUSB installation) - * - * @param device USB device - * @param bos_descs array of BOS descriptors - * @param num_bos_descs number of BOS descriptors - * @param msos_desc_set MS OS 2.0 descriptor set - */ -void usb_dev_register_bos(usbd_device* device, - const usb_bos_device_capability_desc* const * bos_descs, int num_bos_descs, - const usb_msos20_desc_set_header* msos_desc_set, uint8_t msos_vendor_code); - -#ifdef __cplusplus -} -#endif diff --git a/test-devices/composite-stm32/include/usb_bos_desc.h b/test-devices/composite-stm32/include/usb_bos_desc.h deleted file mode 100644 index eacfbf57..00000000 --- a/test-devices/composite-stm32/include/usb_bos_desc.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// USB BOS descriptor -// - -#pragma once - -#include "usb_bos.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define MSOS_VENDOR_CODE 0x44 - -extern const usb_bos_device_capability_desc* const bos_descs[1]; -extern const usb_msos20_desc_set_header* msos_desc_set; - -#ifdef __cplusplus -} -#endif diff --git a/test-devices/composite-stm32/include/usb_descriptor.h b/test-devices/composite-stm32/include/usb_descriptor.h deleted file mode 100644 index 0d01413b..00000000 --- a/test-devices/composite-stm32/include/usb_descriptor.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// USB descriptor -// - -#pragma once - -#include - -#define INTR_MAX_PACKET_SIZE 16 -#define BULK_MAX_PACKET_SIZE 64 - -// Endpoints -#define EP_LOOPBACK_RX 0x01 -#define EP_LOOPBACK_TX 0x82 -#define EP_ECHO_RX 0x03 -#define EP_ECHO_TX 0x83 -#define EP_CDC_COMM 0x84 -#define EP_CDC_DATA_RX 0x05 -#define EP_CDC_DATA_TX 0x85 - -// USB descriptor string table -extern const char *const usb_desc_strings[4]; -// USB device descriptor -extern const struct usb_device_descriptor usb_device_desc; -// USB device configurations -extern const struct usb_config_descriptor usb_config_descs[]; - -void usb_init_serial_num(); diff --git a/test-devices/composite-stm32/include/usb_descriptors.h b/test-devices/composite-stm32/include/usb_descriptors.h new file mode 100644 index 00000000..32edc120 --- /dev/null +++ b/test-devices/composite-stm32/include/usb_descriptors.h @@ -0,0 +1,31 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// USB descriptor +// + +#pragma once + +#include + +#define INTR_MAX_PACKET_SIZE 16 +#define BULK_MAX_PACKET_SIZE 64 + +// Endpoints +#define EP_CDC_COMM 0x83 +#define EP_CDC_DATA_RX 0x02 +#define EP_CDC_DATA_TX 0x81 + +#define EP_LOOPBACK_RX 0x01 +#define EP_LOOPBACK_TX 0x82 + +#define MSOS_VENDOR_CODE 0x44 + +extern uint8_t const desc_ms_os_20[]; + +void usb_init_serial_num(); diff --git a/test-devices/composite-stm32/include/vendor_custom.h b/test-devices/composite-stm32/include/vendor_custom.h new file mode 100644 index 00000000..03976045 --- /dev/null +++ b/test-devices/composite-stm32/include/vendor_custom.h @@ -0,0 +1,115 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// USB driver for interfaces with vendor specific class. +// The interface can have any number of bulk and interrupt endpoints. +// + +#pragma once + +#include "common/tusb_common.h" +#include "device/usbd_pvt.h" + +// --- Macro to create USB configuration descriptor + +// Interface descriptor: interface number, number of endponts +#define CUSTOM_VENDOR_INTERFACE(_itfnum, _numeps) \ + /* Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, _numeps, TUSB_CLASS_VENDOR_SPECIFIC, 0x00, 0x00, 0 + +// Bulk endpoint descriptor: endpoint address, packet size +#define CUSTOM_VENDOR_BULK_ENDPOINT(_epaddr, _packetsize) \ + /* Endpoint */\ + 7, TUSB_DESC_ENDPOINT, _epaddr, TUSB_XFER_BULK, U16_TO_U8S_LE(_packetsize), 0 + +// Interrupt endpoint descriptor: endpoint address, packet size, interval +#define CUSTOM_VENDOR_INTERRUPT_ENDPOINT(_epaddr, _packetsize, _interval) \ + /* Endpoint */\ + 7, TUSB_DESC_ENDPOINT, _epaddr, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_packetsize), _interval + + +// --- Application API + +/** + * @brief Prepares to recieve data on an OUT endpoint. + * + * The buffer must stay valid until the `cust_vendor_rx_cb()` callback + * reports that data has been received. + * + * If the OUT endpoint is already receiving data, this function does nothing. + * + * @param ep_addr endpoint address (1 to 127) + * @param buf pointer to buffer for received data + * @param buf_len length of buffer + */ +void cust_vendor_prepare_recv(uint8_t ep_addr, void* buf, uint32_t buf_len); + +/** + * @brief Gets if the endpoint is busy receiving data. + * + * @param ep_addr endpoint address (1 to 127) + * @return true if the endpoint is busy receiving + * @return false it the endpoint is idle + */ +bool cust_vendor_is_receiving(uint8_t ep_addr); + +/** + * @brief Transmits data on an IN endpoint. + * + * The data must stay valid until the `cust_vendor_tx_cb()` callback + * reports that the data has been transmitted. + * + * If the IN endpoint is already transmitting data, this function does nothing. + * + * @param ep_addr endpoint address (129 to 255) + * @param data pointer to data to transmit + * @param data_len number of bytes to transmit + */ +void cust_vendor_start_transmit(uint8_t ep_addr, void const * data, uint32_t data_len); + +/** + * @brief Gets if the endpoint is busy transmitting data. + * + * @param ep_addr endpoint address (129 to 255) + * @return true if the endpoint is busy transmitting + * @return false it the endpoint is idle + */ +bool cust_vendor_is_transmitting(uint8_t ep_addr); + + +// --- Application Callback API + +/** + * @brief Invoked when new data has been received on an OUT endpoint. + * + * @param ep_addr endpoint address (1 to 127) + * @param recv_bytes number of received bytes + */ +TU_ATTR_WEAK void cust_vendor_rx_cb(uint8_t ep_addr, uint32_t recv_bytes); + +/** + * @brief Invoked when data has been transmitted on an IN endpoint. + * + * @param ep_addr endpoint address (129 to 255) + * @param sent_bytes number of sent bytes + */ +TU_ATTR_WEAK void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes); + +/** + * @brief Invoked when an interface of this class has been opened. + * + * This function is called as part of a SET CONFIGURATION control request. + * + * @param intf interface number + */ +TU_ATTR_WEAK void cust_vendor_intf_open_cb(uint8_t intf); + + +// --- Driver to be registered in usbd_app_driver_get_cb() + +const usbd_class_driver_t cust_vendor_driver; diff --git a/test-devices/composite-stm32/lib/config/tusb_config.h b/test-devices/composite-stm32/lib/config/tusb_config.h new file mode 100644 index 00000000..130bdf8a --- /dev/null +++ b/test-devices/composite-stm32/lib/config/tusb_config.h @@ -0,0 +1,131 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef _TUSB_CONFIG_H_ +#define _TUSB_CONFIG_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Board Specific Configuration +//--------------------------------------------------------------------+ + +// RHPort number used for device can be defined by board.mk, default to port 0 +#ifndef BOARD_TUD_RHPORT +#define BOARD_TUD_RHPORT 0 +#endif + +// RHPort max operational speed can defined by board.mk +#ifndef BOARD_TUD_MAX_SPEED +#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED +#endif + +//-------------------------------------------------------------------- +// COMMON CONFIGURATION +//-------------------------------------------------------------------- + +// defined by compiler flags for flexibility +#ifndef CFG_TUSB_MCU +#error CFG_TUSB_MCU must be defined +#endif + +#ifndef CFG_TUSB_OS +#define CFG_TUSB_OS OPT_OS_NONE +#endif + +#ifndef CFG_TUSB_DEBUG +#define CFG_TUSB_DEBUG 0 +#endif + +// Enable Device stack +#define CFG_TUD_ENABLED 1 + +// Default is max speed that hardware controller could support with on-chip PHY +#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED + +/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. + * Tinyusb use follows macros to declare transferring memory so that they can be put + * into those specific section. + * e.g + * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) + * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) + */ +#ifndef CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_SECTION +#endif + +#ifndef CFG_TUSB_MEM_ALIGN +#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) +#endif + +//-------------------------------------------------------------------- +// DEVICE CONFIGURATION +//-------------------------------------------------------------------- + +#ifndef CFG_TUD_ENDPOINT0_SIZE +#define CFG_TUD_ENDPOINT0_SIZE 64 +#endif + +//------------- CLASS -------------// +#ifndef CFG_TUD_CDC +#define CFG_TUD_CDC 0 +#endif +#ifndef CFG_TUD_MSC +#define CFG_TUD_MSC 0 +#endif +#ifndef CFG_TUD_HID +#define CFG_TUD_HID 0 +#endif +#ifndef CFG_TUD_MIDI +#define CFG_TUD_MIDI 0 +#endif +#ifndef CFG_TUD_VENDOR +#define CFG_TUD_VENDOR 0 +#endif + +// HID buffer size Should be sufficient to hold ID (if any) + Data +#define CFG_TUD_HID_EP_BUFSIZE 64 + +// Vendor FIFO size of TX and RX +// If not configured vendor endpoints will not be buffered +#define CFG_TUD_VENDOR_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) +#define CFG_TUD_VENDOR_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) + +#ifndef CFG_TUD_CDC_RX_BUFSIZE +#define CFG_TUD_CDC_RX_BUFSIZE 64 +#endif + +#ifndef CFG_TUD_CDC_TX_BUFSIZE +#define CFG_TUD_CDC_TX_BUFSIZE 64 +#endif + + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CONFIG_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/audio/audio.h b/test-devices/composite-stm32/lib/tinyusb/class/audio/audio.h new file mode 100644 index 00000000..6f9c1a6b --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/audio/audio.h @@ -0,0 +1,933 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2020 Reinhard Panhuber + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup group_class + * \defgroup ClassDriver_Audio Audio + * Currently only MIDI subclass is supported + * @{ */ + +#ifndef _TUSB_AUDIO_H__ +#define _TUSB_AUDIO_H__ + +#include "common/tusb_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Audio Device Class Codes + +/// A.2 - Audio Function Subclass Codes +typedef enum +{ + AUDIO_FUNCTION_SUBCLASS_UNDEFINED = 0x00, +} audio_function_subclass_type_t; + +/// A.3 - Audio Function Protocol Codes +typedef enum +{ + AUDIO_FUNC_PROTOCOL_CODE_UNDEF = 0x00, + AUDIO_FUNC_PROTOCOL_CODE_V2 = 0x20, ///< Version 2.0 +} audio_function_protocol_code_t; + +/// A.5 - Audio Interface Subclass Codes +typedef enum +{ + AUDIO_SUBCLASS_UNDEFINED = 0x00, + AUDIO_SUBCLASS_CONTROL , ///< Audio Control + AUDIO_SUBCLASS_STREAMING , ///< Audio Streaming + AUDIO_SUBCLASS_MIDI_STREAMING , ///< MIDI Streaming +} audio_subclass_type_t; + +/// A.6 - Audio Interface Protocol Codes +typedef enum +{ + AUDIO_INT_PROTOCOL_CODE_UNDEF = 0x00, + AUDIO_INT_PROTOCOL_CODE_V2 = 0x20, ///< Version 2.0 +} audio_interface_protocol_code_t; + +/// A.7 - Audio Function Category Codes +typedef enum +{ + AUDIO_FUNC_UNDEF = 0x00, + AUDIO_FUNC_DESKTOP_SPEAKER = 0x01, + AUDIO_FUNC_HOME_THEATER = 0x02, + AUDIO_FUNC_MICROPHONE = 0x03, + AUDIO_FUNC_HEADSET = 0x04, + AUDIO_FUNC_TELEPHONE = 0x05, + AUDIO_FUNC_CONVERTER = 0x06, + AUDIO_FUNC_SOUND_RECODER = 0x07, + AUDIO_FUNC_IO_BOX = 0x08, + AUDIO_FUNC_MUSICAL_INSTRUMENT = 0x09, + AUDIO_FUNC_PRO_AUDIO = 0x0A, + AUDIO_FUNC_AUDIO_VIDEO = 0x0B, + AUDIO_FUNC_CONTROL_PANEL = 0x0C, + AUDIO_FUNC_OTHER = 0xFF, +} audio_function_code_t; + +/// A.9 - Audio Class-Specific AC Interface Descriptor Subtypes UAC2 +typedef enum +{ + AUDIO_CS_AC_INTERFACE_AC_DESCRIPTOR_UNDEF = 0x00, + AUDIO_CS_AC_INTERFACE_HEADER = 0x01, + AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL = 0x02, + AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL = 0x03, + AUDIO_CS_AC_INTERFACE_MIXER_UNIT = 0x04, + AUDIO_CS_AC_INTERFACE_SELECTOR_UNIT = 0x05, + AUDIO_CS_AC_INTERFACE_FEATURE_UNIT = 0x06, + AUDIO_CS_AC_INTERFACE_EFFECT_UNIT = 0x07, + AUDIO_CS_AC_INTERFACE_PROCESSING_UNIT = 0x08, + AUDIO_CS_AC_INTERFACE_EXTENSION_UNIT = 0x09, + AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE = 0x0A, + AUDIO_CS_AC_INTERFACE_CLOCK_SELECTOR = 0x0B, + AUDIO_CS_AC_INTERFACE_CLOCK_MULTIPLIER = 0x0C, + AUDIO_CS_AC_INTERFACE_SAMPLE_RATE_CONVERTER = 0x0D, +} audio_cs_ac_interface_subtype_t; + +/// A.10 - Audio Class-Specific AS Interface Descriptor Subtypes UAC2 +typedef enum +{ + AUDIO_CS_AS_INTERFACE_AS_DESCRIPTOR_UNDEF = 0x00, + AUDIO_CS_AS_INTERFACE_AS_GENERAL = 0x01, + AUDIO_CS_AS_INTERFACE_FORMAT_TYPE = 0x02, + AUDIO_CS_AS_INTERFACE_ENCODER = 0x03, + AUDIO_CS_AS_INTERFACE_DECODER = 0x04, +} audio_cs_as_interface_subtype_t; + +/// A.11 - Effect Unit Effect Types +typedef enum +{ + AUDIO_EFFECT_TYPE_UNDEF = 0x00, + AUDIO_EFFECT_TYPE_PARAM_EQ_SECTION = 0x01, + AUDIO_EFFECT_TYPE_REVERBERATION = 0x02, + AUDIO_EFFECT_TYPE_MOD_DELAY = 0x03, + AUDIO_EFFECT_TYPE_DYN_RANGE_COMP = 0x04, +} audio_effect_unit_effect_type_t; + +/// A.12 - Processing Unit Process Types +typedef enum +{ + AUDIO_PROCESS_TYPE_UNDEF = 0x00, + AUDIO_PROCESS_TYPE_UP_DOWN_MIX = 0x01, + AUDIO_PROCESS_TYPE_DOLBY_PROLOGIC = 0x02, + AUDIO_PROCESS_TYPE_STEREO_EXTENDER = 0x03, +} audio_processing_unit_process_type_t; + +/// A.13 - Audio Class-Specific EP Descriptor Subtypes UAC2 +typedef enum +{ + AUDIO_CS_EP_SUBTYPE_UNDEF = 0x00, + AUDIO_CS_EP_SUBTYPE_GENERAL = 0x01, +} audio_cs_ep_subtype_t; + +/// A.14 - Audio Class-Specific Request Codes +typedef enum +{ + AUDIO_CS_REQ_UNDEF = 0x00, + AUDIO_CS_REQ_CUR = 0x01, + AUDIO_CS_REQ_RANGE = 0x02, + AUDIO_CS_REQ_MEM = 0x03, +} audio_cs_req_t; + +/// A.17 - Control Selector Codes + +/// A.17.1 - Clock Source Control Selectors +typedef enum +{ + AUDIO_CS_CTRL_UNDEF = 0x00, + AUDIO_CS_CTRL_SAM_FREQ = 0x01, + AUDIO_CS_CTRL_CLK_VALID = 0x02, +} audio_clock_src_control_selector_t; + +/// A.17.2 - Clock Selector Control Selectors +typedef enum +{ + AUDIO_CX_CTRL_UNDEF = 0x00, + AUDIO_CX_CTRL_CONTROL = 0x01, +} audio_clock_sel_control_selector_t; + +/// A.17.3 - Clock Multiplier Control Selectors +typedef enum +{ + AUDIO_CM_CTRL_UNDEF = 0x00, + AUDIO_CM_CTRL_NUMERATOR_CONTROL = 0x01, + AUDIO_CM_CTRL_DENOMINATOR_CONTROL = 0x02, +} audio_clock_mul_control_selector_t; + +/// A.17.4 - Terminal Control Selectors +typedef enum +{ + AUDIO_TE_CTRL_UNDEF = 0x00, + AUDIO_TE_CTRL_COPY_PROTECT = 0x01, + AUDIO_TE_CTRL_CONNECTOR = 0x02, + AUDIO_TE_CTRL_OVERLOAD = 0x03, + AUDIO_TE_CTRL_CLUSTER = 0x04, + AUDIO_TE_CTRL_UNDERFLOW = 0x05, + AUDIO_TE_CTRL_OVERFLOW = 0x06, + AUDIO_TE_CTRL_LATENCY = 0x07, +} audio_terminal_control_selector_t; + +/// A.17.5 - Mixer Control Selectors +typedef enum +{ + AUDIO_MU_CTRL_UNDEF = 0x00, + AUDIO_MU_CTRL_MIXER = 0x01, + AUDIO_MU_CTRL_CLUSTER = 0x02, + AUDIO_MU_CTRL_UNDERFLOW = 0x03, + AUDIO_MU_CTRL_OVERFLOW = 0x04, + AUDIO_MU_CTRL_LATENCY = 0x05, +} audio_mixer_control_selector_t; + +/// A.17.6 - Selector Control Selectors +typedef enum +{ + AUDIO_SU_CTRL_UNDEF = 0x00, + AUDIO_SU_CTRL_SELECTOR = 0x01, + AUDIO_SU_CTRL_LATENCY = 0x02, +} audio_sel_control_selector_t; + +/// A.17.7 - Feature Unit Control Selectors +typedef enum +{ + AUDIO_FU_CTRL_UNDEF = 0x00, + AUDIO_FU_CTRL_MUTE = 0x01, + AUDIO_FU_CTRL_VOLUME = 0x02, + AUDIO_FU_CTRL_BASS = 0x03, + AUDIO_FU_CTRL_MID = 0x04, + AUDIO_FU_CTRL_TREBLE = 0x05, + AUDIO_FU_CTRL_GRAPHIC_EQUALIZER = 0x06, + AUDIO_FU_CTRL_AGC = 0x07, + AUDIO_FU_CTRL_DELAY = 0x08, + AUDIO_FU_CTRL_BASS_BOOST = 0x09, + AUDIO_FU_CTRL_LOUDNESS = 0x0A, + AUDIO_FU_CTRL_INPUT_GAIN = 0x0B, + AUDIO_FU_CTRL_GAIN_PAD = 0x0C, + AUDIO_FU_CTRL_INVERTER = 0x0D, + AUDIO_FU_CTRL_UNDERFLOW = 0x0E, + AUDIO_FU_CTRL_OVERVLOW = 0x0F, + AUDIO_FU_CTRL_LATENCY = 0x10, +} audio_feature_unit_control_selector_t; + +/// A.17.8 Effect Unit Control Selectors + +/// A.17.8.1 Parametric Equalizer Section Effect Unit Control Selectors +typedef enum +{ + AUDIO_PE_CTRL_UNDEF = 0x00, + AUDIO_PE_CTRL_ENABLE = 0x01, + AUDIO_PE_CTRL_CENTERFREQ = 0x02, + AUDIO_PE_CTRL_QFACTOR = 0x03, + AUDIO_PE_CTRL_GAIN = 0x04, + AUDIO_PE_CTRL_UNDERFLOW = 0x05, + AUDIO_PE_CTRL_OVERFLOW = 0x06, + AUDIO_PE_CTRL_LATENCY = 0x07, +} audio_parametric_equalizer_control_selector_t; + +/// A.17.8.2 Reverberation Effect Unit Control Selectors +typedef enum +{ + AUDIO_RV_CTRL_UNDEF = 0x00, + AUDIO_RV_CTRL_ENABLE = 0x01, + AUDIO_RV_CTRL_TYPE = 0x02, + AUDIO_RV_CTRL_LEVEL = 0x03, + AUDIO_RV_CTRL_TIME = 0x04, + AUDIO_RV_CTRL_FEEDBACK = 0x05, + AUDIO_RV_CTRL_PREDELAY = 0x06, + AUDIO_RV_CTRL_DENSITY = 0x07, + AUDIO_RV_CTRL_HIFREQ_ROLLOFF = 0x08, + AUDIO_RV_CTRL_UNDERFLOW = 0x09, + AUDIO_RV_CTRL_OVERFLOW = 0x0A, + AUDIO_RV_CTRL_LATENCY = 0x0B, +} audio_reverberation_effect_control_selector_t; + +/// A.17.8.3 Modulation Delay Effect Unit Control Selectors +typedef enum +{ + AUDIO_MD_CTRL_UNDEF = 0x00, + AUDIO_MD_CTRL_ENABLE = 0x01, + AUDIO_MD_CTRL_BALANCE = 0x02, + AUDIO_MD_CTRL_RATE = 0x03, + AUDIO_MD_CTRL_DEPTH = 0x04, + AUDIO_MD_CTRL_TIME = 0x05, + AUDIO_MD_CTRL_FEEDBACK = 0x06, + AUDIO_MD_CTRL_UNDERFLOW = 0x07, + AUDIO_MD_CTRL_OVERFLOW = 0x08, + AUDIO_MD_CTRL_LATENCY = 0x09, +} audio_modulation_delay_control_selector_t; + +/// A.17.8.4 Dynamic Range Compressor Effect Unit Control Selectors +typedef enum +{ + AUDIO_DR_CTRL_UNDEF = 0x00, + AUDIO_DR_CTRL_ENABLE = 0x01, + AUDIO_DR_CTRL_COMPRESSION_RATE = 0x02, + AUDIO_DR_CTRL_MAXAMPL = 0x03, + AUDIO_DR_CTRL_THRESHOLD = 0x04, + AUDIO_DR_CTRL_ATTACK_TIME = 0x05, + AUDIO_DR_CTRL_RELEASE_TIME = 0x06, + AUDIO_DR_CTRL_UNDERFLOW = 0x07, + AUDIO_DR_CTRL_OVERFLOW = 0x08, + AUDIO_DR_CTRL_LATENCY = 0x09, +} audio_dynamic_range_compression_control_selector_t; + +/// A.17.9 Processing Unit Control Selectors + +/// A.17.9.1 Up/Down-mix Processing Unit Control Selectors +typedef enum +{ + AUDIO_UD_CTRL_UNDEF = 0x00, + AUDIO_UD_CTRL_ENABLE = 0x01, + AUDIO_UD_CTRL_MODE_SELECT = 0x02, + AUDIO_UD_CTRL_CLUSTER = 0x03, + AUDIO_UD_CTRL_UNDERFLOW = 0x04, + AUDIO_UD_CTRL_OVERFLOW = 0x05, + AUDIO_UD_CTRL_LATENCY = 0x06, +} audio_up_down_mix_control_selector_t; + +/// A.17.9.2 Dolby Prologic ™ Processing Unit Control Selectors +typedef enum +{ + AUDIO_DP_CTRL_UNDEF = 0x00, + AUDIO_DP_CTRL_ENABLE = 0x01, + AUDIO_DP_CTRL_MODE_SELECT = 0x02, + AUDIO_DP_CTRL_CLUSTER = 0x03, + AUDIO_DP_CTRL_UNDERFLOW = 0x04, + AUDIO_DP_CTRL_OVERFLOW = 0x05, + AUDIO_DP_CTRL_LATENCY = 0x06, +} audio_dolby_prologic_control_selector_t; + +/// A.17.9.3 Stereo Extender Processing Unit Control Selectors +typedef enum +{ + AUDIO_ST_EXT_CTRL_UNDEF = 0x00, + AUDIO_ST_EXT_CTRL_ENABLE = 0x01, + AUDIO_ST_EXT_CTRL_WIDTH = 0x02, + AUDIO_ST_EXT_CTRL_UNDERFLOW = 0x03, + AUDIO_ST_EXT_CTRL_OVERFLOW = 0x04, + AUDIO_ST_EXT_CTRL_LATENCY = 0x05, +} audio_stereo_extender_control_selector_t; + +/// A.17.10 Extension Unit Control Selectors +typedef enum +{ + AUDIO_XU_CTRL_UNDEF = 0x00, + AUDIO_XU_CTRL_ENABLE = 0x01, + AUDIO_XU_CTRL_CLUSTER = 0x02, + AUDIO_XU_CTRL_UNDERFLOW = 0x03, + AUDIO_XU_CTRL_OVERFLOW = 0x04, + AUDIO_XU_CTRL_LATENCY = 0x05, +} audio_extension_unit_control_selector_t; + +/// A.17.11 AudioStreaming Interface Control Selectors +typedef enum +{ + AUDIO_AS_CTRL_UNDEF = 0x00, + AUDIO_AS_CTRL_ACT_ALT_SETTING = 0x01, + AUDIO_AS_CTRL_VAL_ALT_SETTINGS = 0x02, + AUDIO_AS_CTRL_AUDIO_DATA_FORMAT = 0x03, +} audio_audiostreaming_interface_control_selector_t; + +/// A.17.12 Encoder Control Selectors +typedef enum +{ + AUDIO_EN_CTRL_UNDEF = 0x00, + AUDIO_EN_CTRL_BIT_RATE = 0x01, + AUDIO_EN_CTRL_QUALITY = 0x02, + AUDIO_EN_CTRL_VBR = 0x03, + AUDIO_EN_CTRL_TYPE = 0x04, + AUDIO_EN_CTRL_UNDERFLOW = 0x05, + AUDIO_EN_CTRL_OVERFLOW = 0x06, + AUDIO_EN_CTRL_ENCODER_ERROR = 0x07, + AUDIO_EN_CTRL_PARAM1 = 0x08, + AUDIO_EN_CTRL_PARAM2 = 0x09, + AUDIO_EN_CTRL_PARAM3 = 0x0A, + AUDIO_EN_CTRL_PARAM4 = 0x0B, + AUDIO_EN_CTRL_PARAM5 = 0x0C, + AUDIO_EN_CTRL_PARAM6 = 0x0D, + AUDIO_EN_CTRL_PARAM7 = 0x0E, + AUDIO_EN_CTRL_PARAM8 = 0x0F, +} audio_encoder_control_selector_t; + +/// A.17.13 Decoder Control Selectors + +/// A.17.13.1 MPEG Decoder Control Selectors +typedef enum +{ + AUDIO_MPD_CTRL_UNDEF = 0x00, + AUDIO_MPD_CTRL_DUAL_CHANNEL = 0x01, + AUDIO_MPD_CTRL_SECOND_STEREO = 0x02, + AUDIO_MPD_CTRL_MULTILINGUAL = 0x03, + AUDIO_MPD_CTRL_DYN_RANGE = 0x04, + AUDIO_MPD_CTRL_SCALING = 0x05, + AUDIO_MPD_CTRL_HILO_SCALING = 0x06, + AUDIO_MPD_CTRL_UNDERFLOW = 0x07, + AUDIO_MPD_CTRL_OVERFLOW = 0x08, + AUDIO_MPD_CTRL_DECODER_ERROR = 0x09, +} audio_MPEG_decoder_control_selector_t; + +/// A.17.13.2 AC-3 Decoder Control Selectors +typedef enum +{ + AUDIO_AD_CTRL_UNDEF = 0x00, + AUDIO_AD_CTRL_MODE = 0x01, + AUDIO_AD_CTRL_DYN_RANGE = 0x02, + AUDIO_AD_CTRL_SCALING = 0x03, + AUDIO_AD_CTRL_HILO_SCALING = 0x04, + AUDIO_AD_CTRL_UNDERFLOW = 0x05, + AUDIO_AD_CTRL_OVERFLOW = 0x06, + AUDIO_AD_CTRL_DECODER_ERROR = 0x07, +} audio_AC3_decoder_control_selector_t; + +/// A.17.13.3 WMA Decoder Control Selectors +typedef enum +{ + AUDIO_WD_CTRL_UNDEF = 0x00, + AUDIO_WD_CTRL_UNDERFLOW = 0x01, + AUDIO_WD_CTRL_OVERFLOW = 0x02, + AUDIO_WD_CTRL_DECODER_ERROR = 0x03, +} audio_WMA_decoder_control_selector_t; + +/// A.17.13.4 DTS Decoder Control Selectors +typedef enum +{ + AUDIO_DD_CTRL_UNDEF = 0x00, + AUDIO_DD_CTRL_UNDERFLOW = 0x01, + AUDIO_DD_CTRL_OVERFLOW = 0x02, + AUDIO_DD_CTRL_DECODER_ERROR = 0x03, +} audio_DTS_decoder_control_selector_t; + +/// A.17.14 Endpoint Control Selectors +typedef enum +{ + AUDIO_EP_CTRL_UNDEF = 0x00, + AUDIO_EP_CTRL_PITCH = 0x01, + AUDIO_EP_CTRL_DATA_OVERRUN = 0x02, + AUDIO_EP_CTRL_DATA_UNDERRUN = 0x03, +} audio_EP_control_selector_t; + +/// Terminal Types + +/// 2.1 - Audio Class-Terminal Types UAC2 +typedef enum +{ + AUDIO_TERM_TYPE_USB_UNDEFINED = 0x0100, + AUDIO_TERM_TYPE_USB_STREAMING = 0x0101, + AUDIO_TERM_TYPE_USB_VENDOR_SPEC = 0x01FF, +} audio_terminal_type_t; + +/// 2.2 - Audio Class-Input Terminal Types UAC2 +typedef enum +{ + AUDIO_TERM_TYPE_IN_UNDEFINED = 0x0200, + AUDIO_TERM_TYPE_IN_GENERIC_MIC = 0x0201, + AUDIO_TERM_TYPE_IN_DESKTOP_MIC = 0x0202, + AUDIO_TERM_TYPE_IN_PERSONAL_MIC = 0x0203, + AUDIO_TERM_TYPE_IN_OMNI_MIC = 0x0204, + AUDIO_TERM_TYPE_IN_ARRAY_MIC = 0x0205, + AUDIO_TERM_TYPE_IN_PROC_ARRAY_MIC = 0x0206, +} audio_terminal_input_type_t; + +/// 2.3 - Audio Class-Output Terminal Types UAC2 +typedef enum +{ + AUDIO_TERM_TYPE_OUT_UNDEFINED = 0x0300, + AUDIO_TERM_TYPE_OUT_GENERIC_SPEAKER = 0x0301, + AUDIO_TERM_TYPE_OUT_HEADPHONES = 0x0302, + AUDIO_TERM_TYPE_OUT_HEAD_MNT_DISP_AUIDO = 0x0303, + AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER = 0x0304, + AUDIO_TERM_TYPE_OUT_ROOM_SPEAKER = 0x0305, + AUDIO_TERM_TYPE_OUT_COMMUNICATION_SPEAKER = 0x0306, + AUDIO_TERM_TYPE_OUT_LOW_FRQ_EFFECTS_SPEAKER = 0x0307, +} audio_terminal_output_type_t; + +/// Rest is yet to be implemented + +/// Additional Audio Device Class Codes - Source: Audio Data Formats + +/// A.1 - Audio Class-Format Type Codes UAC2 +typedef enum +{ + AUDIO_FORMAT_TYPE_UNDEFINED = 0x00, + AUDIO_FORMAT_TYPE_I = 0x01, + AUDIO_FORMAT_TYPE_II = 0x02, + AUDIO_FORMAT_TYPE_III = 0x03, + AUDIO_FORMAT_TYPE_IV = 0x04, + AUDIO_EXT_FORMAT_TYPE_I = 0x81, + AUDIO_EXT_FORMAT_TYPE_II = 0x82, + AUDIO_EXT_FORMAT_TYPE_III = 0x83, +} audio_format_type_t; + +// A.2.1 - Audio Class-Audio Data Format Type I UAC2 +typedef enum +{ + AUDIO_DATA_FORMAT_TYPE_I_PCM = (uint32_t) (1 << 0), + AUDIO_DATA_FORMAT_TYPE_I_PCM8 = (uint32_t) (1 << 1), + AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT = (uint32_t) (1 << 2), + AUDIO_DATA_FORMAT_TYPE_I_ALAW = (uint32_t) (1 << 3), + AUDIO_DATA_FORMAT_TYPE_I_MULAW = (uint32_t) (1 << 4), + AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA = 0x80000000, +} audio_data_format_type_I_t; + +/// All remaining definitions are taken from the descriptor descriptions in the UAC2 main specification + +/// Audio Class-Control Values UAC2 +typedef enum +{ + AUDIO_CTRL_NONE = 0x00, ///< No Host access + AUDIO_CTRL_R = 0x01, ///< Host read access only + AUDIO_CTRL_RW = 0x03, ///< Host read write access +} audio_control_t; + +/// Audio Class-Specific AC Interface Descriptor Controls UAC2 +typedef enum +{ + AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS = 0, +} audio_cs_ac_interface_control_pos_t; + +/// Audio Class-Specific AS Interface Descriptor Controls UAC2 +typedef enum +{ + AUDIO_CS_AS_INTERFACE_CTRL_ACTIVE_ALT_SET_POS = 0, + AUDIO_CS_AS_INTERFACE_CTRL_VALID_ALT_SET_POS = 2, +} audio_cs_as_interface_control_pos_t; + +/// Audio Class-Specific AS Isochronous Data EP Attributes UAC2 +typedef enum +{ + AUDIO_CS_AS_ISO_DATA_EP_ATT_MAX_PACKETS_ONLY = 0x80, + AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK = 0x00, +} audio_cs_as_iso_data_ep_attribute_t; + +/// Audio Class-Specific AS Isochronous Data EP Controls UAC2 +typedef enum +{ + AUDIO_CS_AS_ISO_DATA_EP_CTRL_PITCH_POS = 0, + AUDIO_CS_AS_ISO_DATA_EP_CTRL_DATA_OVERRUN_POS = 2, + AUDIO_CS_AS_ISO_DATA_EP_CTRL_DATA_UNDERRUN_POS = 4, +} audio_cs_as_iso_data_ep_control_pos_t; + +/// Audio Class-Specific AS Isochronous Data EP Lock Delay Units UAC2 +typedef enum +{ + AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED = 0x00, + AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC = 0x01, + AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_PCM_SAMPLES = 0x02, +} audio_cs_as_iso_data_ep_lock_delay_unit_t; + +/// Audio Class-Clock Source Attributes UAC2 +typedef enum +{ + AUDIO_CLOCK_SOURCE_ATT_EXT_CLK = 0x00, + AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK = 0x01, + AUDIO_CLOCK_SOURCE_ATT_INT_VAR_CLK = 0x02, + AUDIO_CLOCK_SOURCE_ATT_INT_PRO_CLK = 0x03, + AUDIO_CLOCK_SOURCE_ATT_CLK_SYC_SOF = 0x04, +} audio_clock_source_attribute_t; + +/// Audio Class-Clock Source Controls UAC2 +typedef enum +{ + AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS = 0, + AUDIO_CLOCK_SOURCE_CTRL_CLK_VAL_POS = 2, +} audio_clock_source_control_pos_t; + +/// Audio Class-Clock Selector Controls UAC2 +typedef enum +{ + AUDIO_CLOCK_SELECTOR_CTRL_POS = 0, +} audio_clock_selector_control_pos_t; + +/// Audio Class-Clock Multiplier Controls UAC2 +typedef enum +{ + AUDIO_CLOCK_MULTIPLIER_CTRL_NUMERATOR_POS = 0, + AUDIO_CLOCK_MULTIPLIER_CTRL_DENOMINATOR_POS = 2, +} audio_clock_multiplier_control_pos_t; + +/// Audio Class-Input Terminal Controls UAC2 +typedef enum +{ + AUDIO_IN_TERM_CTRL_CPY_PROT_POS = 0, + AUDIO_IN_TERM_CTRL_CONNECTOR_POS = 2, + AUDIO_IN_TERM_CTRL_OVERLOAD_POS = 4, + AUDIO_IN_TERM_CTRL_CLUSTER_POS = 6, + AUDIO_IN_TERM_CTRL_UNDERFLOW_POS = 8, + AUDIO_IN_TERM_CTRL_OVERFLOW_POS = 10, +} audio_terminal_input_control_pos_t; + +/// Audio Class-Output Terminal Controls UAC2 +typedef enum +{ + AUDIO_OUT_TERM_CTRL_CPY_PROT_POS = 0, + AUDIO_OUT_TERM_CTRL_CONNECTOR_POS = 2, + AUDIO_OUT_TERM_CTRL_OVERLOAD_POS = 4, + AUDIO_OUT_TERM_CTRL_UNDERFLOW_POS = 6, + AUDIO_OUT_TERM_CTRL_OVERFLOW_POS = 8, +} audio_terminal_output_control_pos_t; + +/// Audio Class-Feature Unit Controls UAC2 +typedef enum +{ + AUDIO_FEATURE_UNIT_CTRL_MUTE_POS = 0, + AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS = 2, + AUDIO_FEATURE_UNIT_CTRL_BASS_POS = 4, + AUDIO_FEATURE_UNIT_CTRL_MID_POS = 6, + AUDIO_FEATURE_UNIT_CTRL_TREBLE_POS = 8, + AUDIO_FEATURE_UNIT_CTRL_GRAPHIC_EQU_POS = 10, + AUDIO_FEATURE_UNIT_CTRL_AGC_POS = 12, + AUDIO_FEATURE_UNIT_CTRL_DELAY_POS = 14, + AUDIO_FEATURE_UNIT_CTRL_BASS_BOOST_POS = 16, + AUDIO_FEATURE_UNIT_CTRL_LOUDNESS_POS = 18, + AUDIO_FEATURE_UNIT_CTRL_INPUT_GAIN_POS = 20, + AUDIO_FEATURE_UNIT_CTRL_INPUT_GAIN_PAD_POS = 22, + AUDIO_FEATURE_UNIT_CTRL_PHASE_INV_POS = 24, + AUDIO_FEATURE_UNIT_CTRL_UNDERFLOW_POS = 26, + AUDIO_FEATURE_UNIT_CTRL_OVERFLOW_POS = 28, +} audio_feature_unit_control_pos_t; + +/// Audio Class-Audio Channel Configuration UAC2 +typedef enum +{ + AUDIO_CHANNEL_CONFIG_NON_PREDEFINED = 0x00000000, + AUDIO_CHANNEL_CONFIG_FRONT_LEFT = 0x00000001, + AUDIO_CHANNEL_CONFIG_FRONT_RIGHT = 0x00000002, + AUDIO_CHANNEL_CONFIG_FRONT_CENTER = 0x00000004, + AUDIO_CHANNEL_CONFIG_LOW_FRQ_EFFECTS = 0x00000008, + AUDIO_CHANNEL_CONFIG_BACK_LEFT = 0x00000010, + AUDIO_CHANNEL_CONFIG_BACK_RIGHT = 0x00000020, + AUDIO_CHANNEL_CONFIG_FRONT_LEFT_OF_CENTER = 0x00000040, + AUDIO_CHANNEL_CONFIG_FRONT_RIGHT_OF_CENTER = 0x00000080, + AUDIO_CHANNEL_CONFIG_BACK_CENTER = 0x00000100, + AUDIO_CHANNEL_CONFIG_SIDE_LEFT = 0x00000200, + AUDIO_CHANNEL_CONFIG_SIDE_RIGHT = 0x00000400, + AUDIO_CHANNEL_CONFIG_TOP_CENTER = 0x00000800, + AUDIO_CHANNEL_CONFIG_TOP_FRONT_LEFT = 0x00001000, + AUDIO_CHANNEL_CONFIG_TOP_FRONT_CENTER = 0x00002000, + AUDIO_CHANNEL_CONFIG_TOP_FRONT_RIGHT = 0x00004000, + AUDIO_CHANNEL_CONFIG_TOP_BACK_LEFT = 0x00008000, + AUDIO_CHANNEL_CONFIG_TOP_BACK_CENTER = 0x00010000, + AUDIO_CHANNEL_CONFIG_TOP_BACK_RIGHT = 0x00020000, + AUDIO_CHANNEL_CONFIG_TOP_FRONT_LEFT_OF_CENTER = 0x00040000, + AUDIO_CHANNEL_CONFIG_TOP_FRONT_RIGHT_OF_CENTER = 0x00080000, + AUDIO_CHANNEL_CONFIG_LEFT_LOW_FRQ_EFFECTS = 0x00100000, + AUDIO_CHANNEL_CONFIG_RIGHT_LOW_FRQ_EFFECTS = 0x00200000, + AUDIO_CHANNEL_CONFIG_TOP_SIDE_LEFT = 0x00400000, + AUDIO_CHANNEL_CONFIG_TOP_SIDE_RIGHT = 0x00800000, + AUDIO_CHANNEL_CONFIG_BOTTOM_CENTER = 0x01000000, + AUDIO_CHANNEL_CONFIG_BACK_LEFT_OF_CENTER = 0x02000000, + AUDIO_CHANNEL_CONFIG_BACK_RIGHT_OF_CENTER = 0x04000000, + AUDIO_CHANNEL_CONFIG_RAW_DATA = 0x80000000, +} audio_channel_config_t; + +/// AUDIO Channel Cluster Descriptor (4.1) +typedef struct TU_ATTR_PACKED { + uint8_t bNrChannels; ///< Number of channels currently connected. + audio_channel_config_t bmChannelConfig; ///< Bitmap according to 'audio_channel_config_t' with a 1 set if channel is connected and 0 else. In case channels are non-predefined ignore them here (see UAC2 specification 4.1 Audio Channel Cluster Descriptor. + uint8_t iChannelNames; ///< Index of a string descriptor, describing the name of the first inserted channel with a non-predefined spatial location. +} audio_desc_channel_cluster_t; + +/// AUDIO Class-Specific AC Interface Header Descriptor (4.7.2) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes: 9. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_HEADER. + uint16_t bcdADC ; ///< Audio Device Class Specification Release Number in Binary-Coded Decimal. Value: U16_TO_U8S_LE(0x0200). + uint8_t bCategory ; ///< Constant, indicating the primary use of this audio function, as intended by the manufacturer. See: audio_function_t. + uint16_t wTotalLength ; ///< Total number of bytes returned for the class-specific AudioControl interface descriptor. Includes the combined length of this descriptor header and all Clock Source, Unit and Terminal descriptors. + uint8_t bmControls ; ///< See: audio_cs_ac_interface_control_pos_t. +} audio_desc_cs_ac_interface_t; + +/// AUDIO Clock Source Descriptor (4.7.2.1) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes: 8. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE. + uint8_t bClockID ; ///< Constant uniquely identifying the Clock Source Entity within the audio function. This value is used in all requests to address this Entity. + uint8_t bmAttributes ; ///< See: audio_clock_source_attribute_t. + uint8_t bmControls ; ///< See: audio_clock_source_control_pos_t. + uint8_t bAssocTerminal ; ///< Terminal ID of the Terminal that is associated with this Clock Source. + uint8_t iClockSource ; ///< Index of a string descriptor, describing the Clock Source Entity. +} audio_desc_clock_source_t; + +/// AUDIO Clock Selector Descriptor (4.7.2.2) for ONE pin +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor, in bytes: 7+p. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_SELECTOR. + uint8_t bClockID ; ///< Constant uniquely identifying the Clock Selector Entity within the audio function. This value is used in all requests to address this Entity. + uint8_t bNrInPins ; ///< Number of Input Pins of this Unit: p = 1 thus bNrInPins = 1. + uint8_t baCSourceID ; ///< ID of the Clock Entity to which the first Clock Input Pin of this Clock Selector Entity is connected.. + uint8_t bmControls ; ///< See: audio_clock_selector_control_pos_t. + uint8_t iClockSource ; ///< Index of a string descriptor, describing the Clock Selector Entity. +} audio_desc_clock_selector_t; + +/// AUDIO Clock Selector Descriptor (4.7.2.2) for multiple pins +#define audio_desc_clock_selector_n_t(source_num) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength ; \ + uint8_t bDescriptorType ; \ + uint8_t bDescriptorSubType ; \ + uint8_t bClockID ; \ + uint8_t bNrInPins ; \ + struct TU_ATTR_PACKED { \ + uint8_t baSourceID ; \ + } sourceID[source_num] ; \ + uint8_t bmControls ; \ + uint8_t iClockSource ; \ +} + +/// AUDIO Clock Multiplier Descriptor (4.7.2.3) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor, in bytes: 7. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_MULTIPLIER. + uint8_t bClockID ; ///< Constant uniquely identifying the Clock Multiplier Entity within the audio function. This value is used in all requests to address this Entity. + uint8_t bCSourceID ; ///< ID of the Clock Entity to which the last Clock Input Pin of this Clock Selector Entity is connected. + uint8_t bmControls ; ///< See: audio_clock_multiplier_control_pos_t. + uint8_t iClockSource ; ///< Index of a string descriptor, describing the Clock Multiplier Entity. +} audio_desc_clock_multiplier_t; + +/// AUDIO Input Terminal Descriptor(4.7.2.4) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor, in bytes: 17. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL. + uint16_t wTerminalType ; ///< Constant characterizing the type of Terminal. See: audio_terminal_type_t for USB streaming and audio_terminal_input_type_t for other input types. + uint8_t bAssocTerminal ; ///< ID of the Output Terminal to which this Input Terminal is associated. + uint8_t bCSourceID ; ///< ID of the Clock Entity to which this Input Terminal is connected. + uint8_t bNrChannels ; ///< Number of logical output channels in the Terminal’s output audio channel cluster. + uint32_t bmChannelConfig ; ///< Describes the spatial location of the logical channels. See:audio_channel_config_t. + uint16_t bmControls ; ///< See: audio_terminal_input_control_pos_t. + uint8_t iTerminal ; ///< Index of a string descriptor, describing the Input Terminal. +} audio_desc_input_terminal_t; + +/// AUDIO Output Terminal Descriptor(4.7.2.5) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor, in bytes: 12. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL. + uint8_t bTerminalID ; ///< Constant uniquely identifying the Terminal within the audio function. This value is used in all requests to address this Terminal. + uint16_t wTerminalType ; ///< Constant characterizing the type of Terminal. See: audio_terminal_type_t for USB streaming and audio_terminal_output_type_t for other output types. + uint8_t bAssocTerminal ; ///< Constant, identifying the Input Terminal to which this Output Terminal is associated. + uint8_t bSourceID ; ///< ID of the Unit or Terminal to which this Terminal is connected. + uint8_t bCSourceID ; ///< ID of the Clock Entity to which this Output Terminal is connected. + uint16_t bmControls ; ///< See: audio_terminal_output_type_t. + uint8_t iTerminal ; ///< Index of a string descriptor, describing the Output Terminal. +} audio_desc_output_terminal_t; + +/// AUDIO Feature Unit Descriptor(4.7.2.8) for ONE channel +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor, in bytes: 14. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_FEATURE_UNIT. + uint8_t bUnitID ; ///< Constant uniquely identifying the Unit within the audio function. This value is used in all requests to address this Unit. + uint8_t bSourceID ; ///< ID of the Unit or Terminal to which this Feature Unit is connected. + struct TU_ATTR_PACKED { + uint32_t bmaControls ; ///< See: audio_feature_unit_control_pos_t. Controls0 is master channel 0 (always present) and Controls1 is logical channel 1. + } controls[2] ; + uint8_t iTerminal ; ///< Index of a string descriptor, describing this Feature Unit. +} audio_desc_feature_unit_t; + +/// AUDIO Feature Unit Descriptor(4.7.2.8) for multiple channels +#define audio_desc_feature_unit_n_t(ch_num)\ + struct TU_ATTR_PACKED { \ + uint8_t bLength ; /* 6+(ch_num+1)*4 */\ + uint8_t bDescriptorType ; \ + uint8_t bDescriptorSubType ; \ + uint8_t bUnitID ; \ + uint8_t bSourceID ; \ + struct TU_ATTR_PACKED { \ + uint32_t bmaControls ; \ + } controls[ch_num+1] ; \ + uint8_t iTerminal ; \ +} + +/// AUDIO Class-Specific AS Interface Descriptor(4.9.2) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor, in bytes: 16. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AS_INTERFACE_AS_GENERAL. + uint8_t bTerminalLink ; ///< The Terminal ID of the Terminal to which this interface is connected. + uint8_t bmControls ; ///< See: audio_cs_as_interface_control_pos_t. + uint8_t bFormatType ; ///< Constant identifying the Format Type the AudioStreaming interface is using. See: audio_format_type_t. + uint32_t bmFormats ; ///< The Audio Data Format(s) that can be used to communicate with this interface.See: audio_data_format_type_I_t. + uint8_t bNrChannels ; ///< Number of physical channels in the AS Interface audio channel cluster. + uint32_t bmChannelConfig ; ///< Describes the spatial location of the physical channels. See: audio_channel_config_t. + uint8_t iChannelNames ; ///< Index of a string descriptor, describing the name of the first physical channel. +} audio_desc_cs_as_interface_t; + +/// AUDIO Type I Format Type Descriptor(2.3.1.6 - Audio Formats) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor, in bytes: 6. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AS_INTERFACE_FORMAT_TYPE. + uint8_t bFormatType ; ///< Constant identifying the Format Type the AudioStreaming interface is using. Value: AUDIO_FORMAT_TYPE_I. + uint8_t bSubslotSize ; ///< The number of bytes occupied by one audio subslot. Can be 1, 2, 3 or 4. + uint8_t bBitResolution ; ///< The number of effectively used bits from the available bits in an audio subslot. +} audio_desc_type_I_format_t; + +/// AUDIO Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor, in bytes: 8. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_ENDPOINT. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_EP_SUBTYPE_GENERAL. + uint8_t bmAttributes ; ///< See: audio_cs_as_iso_data_ep_attribute_t. + uint8_t bmControls ; ///< See: audio_cs_as_iso_data_ep_control_pos_t. + uint8_t bLockDelayUnits ; ///< Indicates the units used for the wLockDelay field. See: audio_cs_as_iso_data_ep_lock_delay_unit_t. + uint16_t wLockDelay ; ///< Indicates the time it takes this endpoint to reliably lock its internal clock recovery circuitry. Units used depend on the value of the bLockDelayUnits field. +} audio_desc_cs_as_iso_data_ep_t; + +// 5.2.2 Control Request Layout +typedef struct TU_ATTR_PACKED +{ + union + { + struct TU_ATTR_PACKED + { + uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t. + uint8_t type : 2; ///< Request type tusb_request_type_t. + uint8_t direction : 1; ///< Direction type. tusb_dir_t + } bmRequestType_bit; + + uint8_t bmRequestType; + }; + + uint8_t bRequest; ///< Request type audio_cs_req_t + uint8_t bChannelNumber; + uint8_t bControlSelector; + union + { + uint8_t bInterface; + uint8_t bEndpoint; + }; + uint8_t bEntityID; + uint16_t wLength; +} audio_control_request_t; + +//// 5.2.3 Control Request Parameter Block Layout + +// 5.2.3.1 1-byte Control CUR Parameter Block +typedef struct TU_ATTR_PACKED +{ + int8_t bCur ; ///< The setting for the CUR attribute of the addressed Control +} audio_control_cur_1_t; + +// 5.2.3.2 2-byte Control CUR Parameter Block +typedef struct TU_ATTR_PACKED +{ + int16_t bCur ; ///< The setting for the CUR attribute of the addressed Control +} audio_control_cur_2_t; + +// 5.2.3.3 4-byte Control CUR Parameter Block +typedef struct TU_ATTR_PACKED +{ + int32_t bCur ; ///< The setting for the CUR attribute of the addressed Control +} audio_control_cur_4_t; + +// Use the following ONLY for RECEIVED data - compiler does not know how many subranges are defined! Use the one below for predefined lengths - or if you know what you are doing do what you like +// 5.2.3.1 1-byte Control RANGE Parameter Block +typedef struct TU_ATTR_PACKED { + uint16_t wNumSubRanges; + struct TU_ATTR_PACKED { + int8_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/ + int8_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/ + uint8_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/ + } subrange[] ; +} audio_control_range_1_t; + +// 5.2.3.2 2-byte Control RANGE Parameter Block +typedef struct TU_ATTR_PACKED { + uint16_t wNumSubRanges; + struct TU_ATTR_PACKED { + int16_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/ + int16_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/ + uint16_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/ + } subrange[] ; +} audio_control_range_2_t; + +// 5.2.3.3 4-byte Control RANGE Parameter Block +typedef struct TU_ATTR_PACKED { + uint16_t wNumSubRanges; + struct TU_ATTR_PACKED { + int32_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/ + int32_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/ + uint32_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/ + } subrange[] ; +} audio_control_range_4_t; + +// 5.2.3.1 1-byte Control RANGE Parameter Block +#define audio_control_range_1_n_t(numSubRanges) \ + struct TU_ATTR_PACKED { \ + uint16_t wNumSubRanges; \ + struct TU_ATTR_PACKED { \ + int8_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/\ + int8_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/\ + uint8_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/\ + } subrange[numSubRanges] ; \ +} + +/// 5.2.3.2 2-byte Control RANGE Parameter Block +#define audio_control_range_2_n_t(numSubRanges) \ + struct TU_ATTR_PACKED { \ + uint16_t wNumSubRanges; \ + struct TU_ATTR_PACKED { \ + int16_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/\ + int16_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/\ + uint16_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/\ + } subrange[numSubRanges]; \ +} + +// 5.2.3.3 4-byte Control RANGE Parameter Block +#define audio_control_range_4_n_t(numSubRanges) \ + struct TU_ATTR_PACKED { \ + uint16_t wNumSubRanges; \ + struct TU_ATTR_PACKED { \ + int32_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/\ + int32_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/\ + uint32_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/\ + } subrange[numSubRanges]; \ +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif + +/** @} */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.c b/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.c new file mode 100644 index 00000000..a021755b --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.c @@ -0,0 +1,2475 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Reinhard Panhuber, Jerzy Kasenberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/* + * This driver supports at most one out EP, one in EP, one control EP, and one feedback EP and one alternative interface other than zero. Hence, only one input terminal and one output terminal are support, if you need more adjust the driver! + * It supports multiple TX and RX channels. + * + * In case you need more alternate interfaces, you need to define additional defines for this specific alternate interface. Just define them and set them in the set_interface function. + * + * There are three data flow structures currently implemented, where at least one SW-FIFO is used to decouple the asynchronous processes MCU vs. host + * + * 1. Input data -> SW-FIFO -> MCU USB + * + * The most easiest version, available in case the target MCU can handle the software FIFO (SW-FIFO) and if it is implemented in the device driver (if yes then dcd_edpt_xfer_fifo() is available) + * + * 2. Input data -> SW-FIFO -> Linear buffer -> MCU USB + * + * In case the target MCU can not handle a SW-FIFO, a linear buffer is used. This uses the default function dcd_edpt_xfer(). In this case more memory is required. + * + * 3. (Input data 1 | Input data 2 | ... | Input data N) -> (SW-FIFO 1 | SW-FIFO 2 | ... | SW-FIFO N) -> Linear buffer -> MCU USB + * + * This case is used if you have more channels which need to be combined into one stream. Every channel has its own SW-FIFO. All data is encoded into an Linear buffer. + * + * The same holds in the RX case. + * + * */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_AUDIO) + +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "audio_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +// Use ring buffer if it's available, some MCUs need extra RAM requirements +#ifndef TUD_AUDIO_PREFER_RING_BUFFER +#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT +#define TUD_AUDIO_PREFER_RING_BUFFER 0 +#else +#define TUD_AUDIO_PREFER_RING_BUFFER 1 +#endif +#endif + +// Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer +// is available or driver is would need to be changed dramatically + +// Only STM32 synopsys and dcd_transdimension use non-linear buffer for now +// Synopsys detection copied from dcd_synopsys.c (refactor later on) +#if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \ + defined (STM32F107xB) || defined (STM32F107xC) +#define STM32F1_SYNOPSYS +#endif + +#if defined (STM32L475xx) || defined (STM32L476xx) || \ + defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \ + defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || \ + defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx) +#define STM32L4_SYNOPSYS +#endif + +#if (CFG_TUSB_MCU == OPT_MCU_STM32F1 && defined(STM32F1_SYNOPSYS)) || \ + CFG_TUSB_MCU == OPT_MCU_STM32F2 || \ + CFG_TUSB_MCU == OPT_MCU_STM32F4 || \ + CFG_TUSB_MCU == OPT_MCU_STM32F7 || \ + CFG_TUSB_MCU == OPT_MCU_STM32H7 || \ + (CFG_TUSB_MCU == OPT_MCU_STM32L4 && defined(STM32L4_SYNOPSYS)) || \ + CFG_TUSB_MCU == OPT_MCU_RX63X || \ + CFG_TUSB_MCU == OPT_MCU_RX65X || \ + CFG_TUSB_MCU == OPT_MCU_RX72N || \ + CFG_TUSB_MCU == OPT_MCU_GD32VF103 || \ + CFG_TUSB_MCU == OPT_MCU_LPC18XX || \ + CFG_TUSB_MCU == OPT_MCU_LPC43XX || \ + CFG_TUSB_MCU == OPT_MCU_MIMXRT || \ + CFG_TUSB_MCU == OPT_MCU_MSP432E4 +#if TUD_AUDIO_PREFER_RING_BUFFER +#define USE_LINEAR_BUFFER 0 +#else +#define USE_LINEAR_BUFFER 1 +#endif +#else +#define USE_LINEAR_BUFFER 1 +#endif + +// Declaration of buffers + +// Check for maximum supported numbers +#if CFG_TUD_AUDIO > 3 +#error Maximum number of audio functions restricted to three! +#endif + +// EP IN software buffers and mutexes +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING + +// Linear buffer TX in case: +// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR +// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into +#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) +#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX]; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX]; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX]; +#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) + +// EP OUT software buffers and mutexes +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING + +// Linear buffer RX in case: +// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR +// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) +#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX]; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX]; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX]; +#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) + +// Control buffers +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ]; +#if CFG_TUD_AUDIO > 1 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ]; +#endif +#if CFG_TUD_AUDIO > 2 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ]; +#endif + +// Active alternate setting of interfaces +uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT]; +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 +uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT]; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 +uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; +#endif + +// Software encoding/decoding support FIFOs +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING +#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ]; +tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ]; +tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ]; +tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING +#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ]; +tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ]; +tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ]; +tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif +#endif + +typedef struct +{ + uint8_t rhport; + uint8_t const * p_desc; // Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function + +#if CFG_TUD_AUDIO_ENABLE_EP_IN + uint8_t ep_in; // TX audio data EP. + uint16_t ep_in_sz; // Current size of TX EP + uint8_t ep_in_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to output terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + uint8_t ep_out; // Incoming (into uC) audio data EP. + uint16_t ep_out_sz; // Current size of RX EP + uint8_t ep_out_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to input terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + uint8_t ep_fb; // Feedback EP. +#endif + +#endif + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN + uint8_t ep_int_ctr; // Audio control interrupt EP. +#endif + + /*------------- From this point, data is not cleared by bus reset -------------*/ + + uint16_t desc_length; // Length of audio function descriptor + + // Buffer for control requests + uint8_t * ctrl_buf; + uint8_t ctrl_buf_sz; + + // Current active alternate settings + uint8_t * alt_setting; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! + + // EP Transfer buffers and FIFOs +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +#if !CFG_TUD_AUDIO_ENABLE_DECODING + tu_fifo_t ep_out_ff; +#endif + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + struct { + uint32_t value; // Feedback value for asynchronous mode (in 16.16 format). + uint32_t min_value; // min value according to UAC2 FMT-2.0 section 2.3.1.1. + uint32_t max_value; // max value according to UAC2 FMT-2.0 section 2.3.1.1. + + uint8_t frame_shift; // bInterval-1 in unit of frame (FS), micro-frame (HS) + uint8_t compute_method; + + union { + uint8_t power_of_2; // pre-computed power of 2 shift + float float_const; // pre-computed float constant + + struct { + uint32_t sample_freq; + uint32_t mclk_freq; + }fixed; + +#if 0 // implement later + struct { + uint32_t nominal_value; + uint32_t threshold_bytes; + }fifo_count; +#endif + }compute; + + } feedback; +#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING + tu_fifo_t ep_in_ff; +#endif + + // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74) +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE]; +#endif + + // Decoding parameters - parameters are set when alternate AS interface is set by host + // Coding is currently only supported for EP. Software coding corresponding to AS interfaces without EPs are not supported currently. +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING + audio_format_type_t format_type_rx; + uint8_t n_channels_rx; + +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + audio_data_format_type_I_t format_type_I_rx; + uint8_t n_bytes_per_sampe_rx; + uint8_t n_channels_per_ff_rx; + uint8_t n_ff_used_rx; +#endif +#endif + + // Encoding parameters - parameters are set when alternate AS interface is set by host +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + audio_format_type_t format_type_tx; + uint8_t n_channels_tx; + +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + audio_data_format_type_I_t format_type_I_tx; + uint8_t n_bytes_per_sampe_tx; + uint8_t n_channels_per_ff_tx; + uint8_t n_ff_used_tx; +#endif +#endif + + // Support FIFOs for software encoding and decoding +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING + tu_fifo_t * rx_supp_ff; + uint8_t n_rx_supp_ff; + uint16_t rx_supp_ff_sz_max; +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + tu_fifo_t * tx_supp_ff; + uint8_t n_tx_supp_ff; + uint16_t tx_supp_ff_sz_max; +#endif + + // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR the support FIFOs are used +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) + uint8_t * lin_buf_out; +#define USE_LINEAR_BUFFER_RX 1 +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) + uint8_t * lin_buf_in; +#define USE_LINEAR_BUFFER_TX 1 +#endif + +} audiod_function_t; + +#ifndef USE_LINEAR_BUFFER_TX +#define USE_LINEAR_BUFFER_TX 0 +#endif + +#ifndef USE_LINEAR_BUFFER_RX +#define USE_LINEAR_BUFFER_RX 0 +#endif + +#define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ctrl_buf) + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +CFG_TUSB_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO]; + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received); +#endif + +#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT +static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN +static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t* audio); +#endif + +#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN +static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio); +#endif + +static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request); +static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request); + +static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int); +static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int); +static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id); +static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id); +static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id); +static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio); + +#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING +static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf); + +static inline uint8_t tu_desc_subtype(void const* desc) +{ + return ((uint8_t const*) desc)[2]; +} +#endif + +bool tud_audio_n_mounted(uint8_t func_id) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO); + audiod_function_t* audio = &_audiod_fct[func_id]; + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + if (audio->ep_out == 0) return false; +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN + if (audio->ep_in == 0) return false; +#endif + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN + if (audio->ep_int_ctr == 0) return false; +#endif + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + if (audio->ep_fb == 0) return false; +#endif + + return true; +} + +//--------------------------------------------------------------------+ +// READ API +//--------------------------------------------------------------------+ + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING + +uint16_t tud_audio_n_available(uint8_t func_id) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + return tu_fifo_count(&_audiod_fct[func_id].ep_out_ff); +} + +uint16_t tud_audio_n_read(uint8_t func_id, void* buffer, uint16_t bufsize) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + return tu_fifo_read_n(&_audiod_fct[func_id].ep_out_ff, buffer, bufsize); +} + +bool tud_audio_n_clear_ep_out_ff(uint8_t func_id) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + return tu_fifo_clear(&_audiod_fct[func_id].ep_out_ff); +} + +tu_fifo_t* tud_audio_n_get_ep_out_ff(uint8_t func_id) +{ + if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_out_ff; + return NULL; +} + +#endif + +#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT +// Delete all content in the support RX FIFOs +bool tud_audio_n_clear_rx_support_ff(uint8_t func_id, uint8_t ff_idx) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); + return tu_fifo_clear(&_audiod_fct[func_id].rx_supp_ff[ff_idx]); +} + +uint16_t tud_audio_n_available_support_ff(uint8_t func_id, uint8_t ff_idx) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); + return tu_fifo_count(&_audiod_fct[func_id].rx_supp_ff[ff_idx]); +} + +uint16_t tud_audio_n_read_support_ff(uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); + return tu_fifo_read_n(&_audiod_fct[func_id].rx_supp_ff[ff_idx], buffer, bufsize); +} + +tu_fifo_t* tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx) +{ + if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff) return &_audiod_fct[func_id].rx_supp_ff[ff_idx]; + return NULL; +} +#endif + +// This function is called once an audio packet is received by the USB and is responsible for putting data from USB memory into EP_OUT_FIFO (or support FIFOs + decoding of received stream into audio channels). +// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_DECODING = 0. + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + +static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received) +{ + uint8_t idxItf = 0; + uint8_t const *dummy2; + uint8_t idx_audio_fct = 0; + + if (tud_audio_rx_done_pre_read_cb || tud_audio_rx_done_post_read_cb) + { + idx_audio_fct = audiod_get_audio_fct_idx(audio); + TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2)); + } + + // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO (or decoded into support RX software FIFO) + if (tud_audio_rx_done_pre_read_cb) + { + TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); + } + +#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT + + switch (audio->format_type_rx) + { + case AUDIO_FORMAT_TYPE_UNDEFINED: + // INDIVIDUAL DECODING PROCEDURE REQUIRED HERE! + TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n"); + TU_BREAKPOINT(); + break; + + case AUDIO_FORMAT_TYPE_I: + + switch (audio->format_type_I_rx) + { + case AUDIO_DATA_FORMAT_TYPE_I_PCM: + TU_VERIFY(audiod_decode_type_I_pcm(rhport, audio, n_bytes_received)); + break; + + default: + // DESIRED CFG_TUD_AUDIO_FORMAT_TYPE_I_RX NOT IMPLEMENTED! + TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_RX encoding not implemented!\r\n"); + TU_BREAKPOINT(); + break; + } + break; + + default: + // Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented! + TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented!\r\n"); + TU_BREAKPOINT(); + break; + } + + // Prepare for next transmission + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); + +#else + +#if USE_LINEAR_BUFFER_RX + // Data currently is in linear buffer, copy into EP OUT FIFO + TU_VERIFY(tu_fifo_write_n(&audio->ep_out_ff, audio->lin_buf_out, n_bytes_received)); + + // Schedule for next receive + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); +#else + // Data is already placed in EP FIFO, schedule for next receive + TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false); +#endif + +#endif + + // Call a weak callback here - a possibility for user to get informed decoding was completed + if (tud_audio_rx_done_post_read_cb) + { + TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); + } + + return true; +} + +#endif //CFG_TUD_AUDIO_ENABLE_EP_OUT + +// The following functions are used in case CFG_TUD_AUDIO_ENABLE_DECODING != 0 +#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT + +// Decoding according to 2.3.1.5 Audio Streams + +// Helper function +static inline uint8_t * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesToCopy, void * dst, uint8_t * dst_end, uint8_t * src, uint8_t const n_ff_used) +{ + + // This function is an optimized version of + // while((uint8_t *)dst < dst_end) + // { + // memcpy(dst, src, nBytesToCopy); + // dst = (uint8_t *)dst + nBytesToCopy; + // src += nBytesToCopy * n_ff_used; + // } + + // Optimize for fast half word copies + typedef struct{ + uint16_t val; + } __attribute((__packed__)) unaligned_uint16_t; + + // Optimize for fast word copies + typedef struct{ + uint32_t val; + } __attribute((__packed__)) unaligned_uint32_t; + + switch (nBytesToCopy) + { + case 1: + while((uint8_t *)dst < dst_end) + { + *(uint8_t *)dst++ = *src; + src += n_ff_used; + } + break; + + case 2: + while((uint8_t *)dst < dst_end) + { + *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src; + dst += 2; + src += 2 * n_ff_used; + } + break; + + case 3: + while((uint8_t *)dst < dst_end) + { + // memcpy(dst, src, 3); + // dst = (uint8_t *)dst + 3; + // src += 3 * n_ff_used; + + // TODO: Is there a faster way to copy 3 bytes? + *(uint8_t *)dst++ = *src++; + *(uint8_t *)dst++ = *src++; + *(uint8_t *)dst++ = *src++; + + src += 3 * (n_ff_used - 1); + } + break; + + case 4: + while((uint8_t *)dst < dst_end) + { + *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src; + dst += 4; + src += 4 * n_ff_used; + } + break; + } + + return src; +} + +static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received) +{ + (void) rhport; + + // Determine amount of samples + uint8_t const n_ff_used = audio->n_ff_used_rx; + uint16_t const nBytesPerFFToRead = n_bytes_received / n_ff_used; + uint8_t cnt_ff; + + // Decode + uint8_t * src; + uint8_t * dst_end; + + tu_fifo_buffer_info_t info; + + for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) + { + tu_fifo_get_write_info(&audio->rx_supp_ff[cnt_ff], &info); + + if (info.len_lin != 0) + { + info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin); + src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx]; + dst_end = info.ptr_lin + info.len_lin; + src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_lin, dst_end, src, n_ff_used); + + // Handle wrapped part of FIFO + info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap); + if (info.len_wrap != 0) + { + dst_end = info.ptr_wrap + info.len_wrap; + audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_wrap, dst_end, src, n_ff_used); + } + tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], info.len_lin + info.len_wrap); + } + } + + // Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it + // TU_VERIFY(cnt != n_bytes); + + return true; +} +#endif //CFG_TUD_AUDIO_ENABLE_DECODING + +//--------------------------------------------------------------------+ +// WRITE API +//--------------------------------------------------------------------+ + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING + +/** + * \brief Write data to EP in buffer + * + * Write data to buffer. If it is full, new data can be inserted once a transmit was scheduled. See audiod_tx_done_cb(). + * If TX FIFOs are used, this function is not available in order to not let the user mess up the encoding process. + * + * \param[in] func_id: Index of audio function interface + * \param[in] data: Pointer to data array to be copied from + * \param[in] len: # of array elements to copy + * \return Number of bytes actually written + */ +uint16_t tud_audio_n_write(uint8_t func_id, const void * data, uint16_t len) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + return tu_fifo_write_n(&_audiod_fct[func_id].ep_in_ff, data, len); +} + +bool tud_audio_n_clear_ep_in_ff(uint8_t func_id) // Delete all content in the EP IN FIFO +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + return tu_fifo_clear(&_audiod_fct[func_id].ep_in_ff); +} + +tu_fifo_t* tud_audio_n_get_ep_in_ff(uint8_t func_id) +{ + if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_in_ff; + return NULL; +} + +#endif + +#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN + +uint16_t tud_audio_n_flush_tx_support_ff(uint8_t func_id) // Force all content in the support TX FIFOs to be written into linear buffer and schedule a transmit +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + audiod_function_t* audio = &_audiod_fct[func_id]; + + uint16_t n_bytes_copied = tu_fifo_count(&audio->tx_supp_ff[0]); + + TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio)); + + n_bytes_copied -= tu_fifo_count(&audio->tx_supp_ff[0]); + n_bytes_copied = n_bytes_copied*audio->tx_supp_ff[0].item_size; + + return n_bytes_copied; +} + +bool tud_audio_n_clear_tx_support_ff(uint8_t func_id, uint8_t ff_idx) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff); + return tu_fifo_clear(&_audiod_fct[func_id].tx_supp_ff[ff_idx]); +} + +uint16_t tud_audio_n_write_support_ff(uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff); + return tu_fifo_write_n(&_audiod_fct[func_id].tx_supp_ff[ff_idx], data, len); +} + +tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx) +{ + if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff) return &_audiod_fct[func_id].tx_supp_ff[ff_idx]; + return NULL; +} + +#endif + + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN + +// If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_ctr_done_cb() is called in inform user +uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint16_t len) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + + // We write directly into the EP's buffer - abort if previous transfer not complete + TU_VERIFY(!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr)); + + // Check length + TU_VERIFY(len <= CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE); + + memcpy(_audiod_fct[func_id].ep_int_ctr_buf, buffer, len); + + // Schedule transmit + TU_VERIFY(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr, _audiod_fct[func_id].ep_int_ctr_buf, len)); + + return true; +} + +#endif + + +// This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission. +// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_ENCODING = 0 and use tud_audio_n_write. + +// n_bytes_copied - Informs caller how many bytes were loaded. In case n_bytes_copied = 0, a ZLP is scheduled to inform host no data is available for current frame. +#if CFG_TUD_AUDIO_ENABLE_EP_IN +static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio) +{ + uint8_t idxItf; + uint8_t const *dummy2; + + uint8_t idx_audio_fct = audiod_get_audio_fct_idx(audio); + TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, audio, &idxItf, &dummy2)); + + // Only send something if current alternate interface is not 0 as in this case nothing is to be sent due to UAC2 specifications + if (audio->alt_setting[idxItf] == 0) return false; + + // Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer (in case FIFOs are used) or + // if no FIFOs are used the user may use this call back to load its data into the EP IN buffer by use of tud_audio_n_write_ep_in_buffer(). + if (tud_audio_tx_done_pre_load_cb) TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); + + // Send everything in ISO EP FIFO + uint16_t n_bytes_tx; + + // If support FIFOs are used, encode and schedule transmit +#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN + switch (audio->format_type_tx) + { + case AUDIO_FORMAT_TYPE_UNDEFINED: + // INDIVIDUAL ENCODING PROCEDURE REQUIRED HERE! + TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n"); + TU_BREAKPOINT(); + n_bytes_tx = 0; + break; + + case AUDIO_FORMAT_TYPE_I: + + switch (audio->format_type_I_tx) + { + case AUDIO_DATA_FORMAT_TYPE_I_PCM: + + n_bytes_tx = audiod_encode_type_I_pcm(rhport, audio); + break; + + default: + // YOUR ENCODING IS REQUIRED HERE! + TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_TX encoding not implemented!\r\n"); + TU_BREAKPOINT(); + n_bytes_tx = 0; + break; + } + break; + + default: + // Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented! + TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!\r\n"); + TU_BREAKPOINT(); + n_bytes_tx = 0; + break; + } + + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx)); + +#else + // No support FIFOs, if no linear buffer required schedule transmit, else put data into linear buffer and schedule + + n_bytes_tx = tu_min16(tu_fifo_count(&audio->ep_in_ff), audio->ep_in_sz); // Limit up to max packet size, more can not be done for ISO + +#if USE_LINEAR_BUFFER_TX + tu_fifo_read_n(&audio->ep_in_ff, audio->lin_buf_in, n_bytes_tx); + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx)); +#else + // Send everything in ISO EP FIFO + TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx)); +#endif + +#endif + + // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame + if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); + + return true; +} + +#endif //CFG_TUD_AUDIO_ENABLE_EP_IN + +#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN +// Take samples from the support buffer and encode them into the IN EP software FIFO +// Returns number of bytes written into linear buffer + +/* 2.3.1.7.1 PCM Format +The PCM (Pulse Coded Modulation) format is the most commonly used audio format to represent audio +data streams. The audio data is not compressed and uses a signed two’s-complement fixed point format. It +is left-justified (the sign bit is the Msb) and data is padded with trailing zeros to fill the remaining unused +bits of the subslot. The binary point is located to the right of the sign bit so that all values lie within the +range [-1, +1) + */ + +/* + * This function encodes channels saved within the support FIFOs into one stream by interleaving the PCM samples + * in the support FIFOs according to 2.3.1.5 Audio Streams. It does not control justification (left or right) and + * does not change the number of bytes per sample. + * */ + +// Helper function +static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, uint8_t * src, uint8_t * src_end, uint8_t * dst, uint8_t const n_ff_used) +{ + // Optimize for fast half word copies + typedef struct{ + uint16_t val; + } __attribute((__packed__)) unaligned_uint16_t; + + // Optimize for fast word copies + typedef struct{ + uint32_t val; + } __attribute((__packed__)) unaligned_uint32_t; + + switch (nBytesToCopy) + { + case 1: + while(src < src_end) + { + *dst = *src++; + dst += n_ff_used; + } + break; + + case 2: + while(src < src_end) + { + *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src; + src += 2; + dst += 2 * n_ff_used; + } + break; + + case 3: + while(src < src_end) + { + // memcpy(dst, src, 3); + // src = (uint8_t *)src + 3; + // dst += 3 * n_ff_used; + + // TODO: Is there a faster way to copy 3 bytes? + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + + dst += 3 * (n_ff_used - 1); + } + break; + + case 4: + while(src < src_end) + { + *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src; + src += 4; + dst += 4 * n_ff_used; + } + break; + } + + return dst; +} + +static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio) +{ + // This function relies on the fact that the length of the support FIFOs was configured to be a multiple of the active sample size in bytes s.t. no sample is split within a wrap + // This is ensured within set_interface, where the FIFOs are reconfigured according to this size + + // We encode directly into IN EP's linear buffer - abort if previous transfer not complete + TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); + + // Determine amount of samples + uint8_t const n_ff_used = audio->n_ff_used_tx; + uint16_t const nBytesToCopy = audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx; + uint16_t const capPerFF = audio->ep_in_sz / n_ff_used; // Sample capacity per FIFO in bytes + uint16_t nBytesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]); + uint8_t cnt_ff; + + for (cnt_ff = 1; cnt_ff < n_ff_used; cnt_ff++) + { + uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cnt_ff]); + if (count < nBytesPerFFToSend) + { + nBytesPerFFToSend = count; + } + } + + // Check if there is enough + if (nBytesPerFFToSend == 0) return 0; + + // Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT! + nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, capPerFF); + + // Round to full number of samples (flooring) + nBytesPerFFToSend = (nBytesPerFFToSend / nBytesToCopy) * nBytesToCopy; + + // Encode + uint8_t * dst; + uint8_t * src_end; + + tu_fifo_buffer_info_t info; + + for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) + { + dst = &audio->lin_buf_in[cnt_ff*audio->n_channels_per_ff_tx*audio->n_bytes_per_sampe_tx]; + + tu_fifo_get_read_info(&audio->tx_supp_ff[cnt_ff], &info); + + if (info.len_lin != 0) + { + info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin); // Limit up to desired length + src_end = (uint8_t *)info.ptr_lin + info.len_lin; + dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_lin, src_end, dst, n_ff_used); + + // Limit up to desired length + info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap); + + // Handle wrapped part of FIFO + if (info.len_wrap != 0) + { + src_end = (uint8_t *)info.ptr_wrap + info.len_wrap; + audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_wrap, src_end, dst, n_ff_used); + } + + tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], info.len_lin + info.len_wrap); + } + } + + return nBytesPerFFToSend * n_ff_used; +} +#endif //CFG_TUD_AUDIO_ENABLE_ENCODING + +// This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio) +{ + return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->feedback.value, 4); +} +#endif + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void audiod_init(void) +{ + tu_memclr(_audiod_fct, sizeof(_audiod_fct)); + + for(uint8_t i=0; ictrl_buf = ctrl_buf_1; + audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ; + break; +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ > 0 + case 1: + audio->ctrl_buf = ctrl_buf_2; + audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ > 0 + case 2: + audio->ctrl_buf = ctrl_buf_3; + audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ; + break; +#endif + } + + // Initialize active alternate interface buffers + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0 + case 0: + audio->alt_setting = alt_setting_1; + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 + case 1: + audio->alt_setting = alt_setting_2; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 + case 2: + audio->alt_setting = alt_setting_3; + break; +#endif + } + + // Initialize IN EP FIFO if required +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING + + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 + case 0: + tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_1), NULL); +#endif + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 + case 1: + tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_2), NULL); +#endif + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 + case 2: + tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_3), NULL); +#endif + break; +#endif + } +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING + + // Initialize linear buffers +#if USE_LINEAR_BUFFER_TX + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 + case 0: + audio->lin_buf_in = lin_buf_in_1; + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 + case 1: + audio->lin_buf_in = lin_buf_in_2; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 + case 2: + audio->lin_buf_in = lin_buf_in_3; + break; +#endif + } +#endif // USE_LINEAR_BUFFER_TX + + // Initialize OUT EP FIFO if required +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING + + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 + case 0: + tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_1)); +#endif + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 + case 1: + tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_2)); +#endif + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 + case 2: + tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_3)); +#endif + break; +#endif + } +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING + + // Initialize linear buffers +#if USE_LINEAR_BUFFER_RX + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 + case 0: + audio->lin_buf_out = lin_buf_out_1; + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 + case 1: + audio->lin_buf_out = lin_buf_out_2; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 + case 2: + audio->lin_buf_out = lin_buf_out_3; + break; +#endif + } +#endif // USE_LINEAR_BUFFER_TX + + // Initialize TX support FIFOs if required +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 + case 0: + audio->tx_supp_ff = tx_supp_ff_1; + audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; + audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&tx_supp_ff_1[cnt], tx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&tx_supp_ff_1[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_1[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 + +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + case 1: + audio->tx_supp_ff = tx_supp_ff_2; + audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; + audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&tx_supp_ff_2[cnt], tx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&tx_supp_ff_2[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_2[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 + case 2: + audio->tx_supp_ff = tx_supp_ff_3; + audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; + audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&tx_supp_ff_3[cnt], tx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&tx_supp_ff_3[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_3[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + } +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + + // Set encoding parameters for Type_I formats +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 + case 0: + audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX; + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + case 1: + audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 + case 2: + audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX; + break; +#endif + } +#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + + // Initialize RX support FIFOs if required +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING + + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 + case 0: + audio->rx_supp_ff = rx_supp_ff_1; + audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; + audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&rx_supp_ff_1[cnt], rx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&rx_supp_ff_1[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_1[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 + +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + case 1: + audio->rx_supp_ff = rx_supp_ff_2; + audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; + audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&rx_supp_ff_2[cnt], rx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&rx_supp_ff_2[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_2[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 + case 2: + audio->rx_supp_ff = rx_supp_ff_3; + audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; + audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&rx_supp_ff_3[cnt], rx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&rx_supp_ff_3[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_3[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + } +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + + // Set encoding parameters for Type_I formats +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 + case 0: + audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX; + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + case 1: + audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 + case 2: + audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX; + break; +#endif + } +#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + } +} + +void audiod_reset(uint8_t rhport) +{ + (void) rhport; + + for(uint8_t i=0; iep_in_ff); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING + tu_fifo_clear(&audio->ep_out_ff); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) + { + tu_fifo_clear(&audio->tx_supp_ff[cnt]); + } +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING + for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) + { + tu_fifo_clear(&audio->rx_supp_ff[cnt]); + } +#endif + } +} + +uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + (void) max_len; + + TU_VERIFY ( TUSB_CLASS_AUDIO == itf_desc->bInterfaceClass && + AUDIO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass); + + // Verify version is correct - this check can be omitted + TU_VERIFY(itf_desc->bInterfaceProtocol == AUDIO_INT_PROTOCOL_CODE_V2); + + // Verify interrupt control EP is enabled if demanded by descriptor - this should be best some static check however - this check can be omitted + if (itf_desc->bNumEndpoints == 1) // 0 or 1 EPs are allowed + { + TU_VERIFY(CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0); + } + + // Alternate setting MUST be zero - this check can be omitted + TU_VERIFY(itf_desc->bAlternateSetting == 0); + + // Find available audio driver interface + uint8_t i; + for (i = 0; i < CFG_TUD_AUDIO; i++) + { + if (!_audiod_fct[i].p_desc) + { + _audiod_fct[i].p_desc = (uint8_t const *)itf_desc; // Save pointer to AC descriptor which is by specification always the first one + _audiod_fct[i].rhport = rhport; + + // Setup descriptor lengths + switch (i) + { + case 0: + _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_1_DESC_LEN; + break; +#if CFG_TUD_AUDIO > 1 + case 1: + _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_2_DESC_LEN; + break; +#endif +#if CFG_TUD_AUDIO > 2 + case 2: + _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_3_DESC_LEN; + break; +#endif + } + + break; + } + } + + // Verify we found a free one + TU_ASSERT( i < CFG_TUD_AUDIO ); + + // This is all we need so far - the EPs are setup by a later set_interface request (as per UAC2 specification) + uint16_t drv_len = _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; // - TUD_AUDIO_DESC_IAD_LEN since tinyUSB already handles the IAD descriptor + + return drv_len; +} + +static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request) +{ + uint8_t const itf = tu_u16_low(p_request->wIndex); + + // Find index of audio streaming interface + uint8_t func_id, idxItf; + uint8_t const *dummy; + + TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &dummy)); + TU_VERIFY(tud_control_xfer(rhport, p_request, &_audiod_fct[func_id].alt_setting[idxItf], 1)); + + TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf, _audiod_fct[func_id].alt_setting[idxItf]); + + return true; +} + +static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request) +{ + (void) rhport; + + // Here we need to do the following: + + // 1. Find the audio driver assigned to the given interface to be set + // Since one audio driver interface has to be able to cover an unknown number of interfaces (AC, AS + its alternate settings), the best memory efficient way to solve this is to always search through the descriptors. + // The audio driver is mapped to an audio function by a reference pointer to the corresponding AC interface of this audio function which serves as a starting point for searching + + // 2. Close EPs which are currently open + // To do so it is not necessary to know the current active alternate interface since we already save the current EP addresses - we simply close them + + // 3. Open new EP + + uint8_t const itf = tu_u16_low(p_request->wIndex); + uint8_t const alt = tu_u16_low(p_request->wValue); + + TU_LOG2(" Set itf: %u - alt: %u\r\n", itf, alt); + + // Find index of audio streaming interface and index of interface + uint8_t func_id, idxItf; + uint8_t const *p_desc; + TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &p_desc)); + + audiod_function_t* audio = &_audiod_fct[func_id]; + + // Look if there is an EP to be closed - for this driver, there are only 3 possible EPs which may be closed (only AS related EPs can be closed, AC EP (if present) is always open) +#if CFG_TUD_AUDIO_ENABLE_EP_IN + if (audio->ep_in_as_intf_num == itf) + { + audio->ep_in_as_intf_num = 0; + usbd_edpt_close(rhport, audio->ep_in); + + // Clear FIFOs, since data is no longer valid +#if !CFG_TUD_AUDIO_ENABLE_ENCODING + tu_fifo_clear(&audio->ep_in_ff); +#else + for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) + { + tu_fifo_clear(&audio->tx_supp_ff[cnt]); + } +#endif + + // Invoke callback - can be used to stop data sampling + if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); + + audio->ep_in = 0; // Necessary? + + } +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + if (audio->ep_out_as_intf_num == itf) + { + audio->ep_out_as_intf_num = 0; + usbd_edpt_close(rhport, audio->ep_out); + + // Clear FIFOs, since data is no longer valid +#if !CFG_TUD_AUDIO_ENABLE_DECODING + tu_fifo_clear(&audio->ep_out_ff); +#else + for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) + { + tu_fifo_clear(&audio->rx_supp_ff[cnt]); + } +#endif + + // Invoke callback - can be used to stop data sampling + if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); + + audio->ep_out = 0; // Necessary? + + // Close corresponding feedback EP +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + usbd_edpt_close(rhport, audio->ep_fb); + audio->ep_fb = 0; + tu_memclr(&audio->feedback, sizeof(audio->feedback)); +#endif + } +#endif + + // Save current alternative interface setting + audio->alt_setting[idxItf] = alt; + + // Open new EP if necessary - EPs are only to be closed or opened for AS interfaces - Look for AS interface with correct alternate interface + // Get pointer at end + uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; + + // p_desc starts at required interface with alternate setting zero + while (p_desc < p_desc_end) + { + // Find correct interface + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == alt) + { +#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING + uint8_t const * p_desc_parse_for_params = p_desc; +#endif + // From this point forward follow the EP descriptors associated to the current alternate setting interface - Open EPs if necessary + uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints; + while (foundEPs < nEps && p_desc < p_desc_end) + { + if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) + { + tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc; + TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); + + uint8_t const ep_addr = desc_ep->bEndpointAddress; + + //TODO: We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND! + usbd_edpt_clear_stall(rhport, ep_addr); + +#if CFG_TUD_AUDIO_ENABLE_EP_IN + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 0x00) // Check if usage is data EP + { + // Save address + audio->ep_in = ep_addr; + audio->ep_in_as_intf_num = itf; + audio->ep_in_sz = tu_edpt_packet_size(desc_ep); + + // If software encoding is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters +#if CFG_TUD_AUDIO_ENABLE_ENCODING + audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf); + + // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / audio->n_bytes_per_sampe_tx) * audio->n_bytes_per_sampe_tx); + for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) + { + tu_fifo_config(&audio->tx_supp_ff[cnt], audio->tx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); + } + audio->n_ff_used_tx = audio->n_channels_tx / audio->n_channels_per_ff_tx; + TU_ASSERT( audio->n_ff_used_tx <= audio->n_tx_supp_ff ); +#endif + +#endif + + // Schedule first transmit if alternate interface is not zero i.e. streaming is disabled - in case no sample data is available a ZLP is loaded + // It is necessary to trigger this here since the refill is done with an RX FIFO empty interrupt which can only trigger if something was in there + TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_fct[func_id])); + } +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + + if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) // Checking usage not necessary + { + // Save address + audio->ep_out = ep_addr; + audio->ep_out_as_intf_num = itf; + audio->ep_out_sz = tu_edpt_packet_size(desc_ep); + +#if CFG_TUD_AUDIO_ENABLE_DECODING + audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf); + + // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sampe_rx) * audio->n_bytes_per_sampe_rx; + for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) + { + tu_fifo_config(&audio->rx_supp_ff[cnt], audio->rx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); + } + audio->n_ff_used_rx = audio->n_channels_rx / audio->n_channels_per_ff_rx; + TU_ASSERT( audio->n_ff_used_rx <= audio->n_rx_supp_ff ); +#endif +#endif + + // Prepare for incoming data +#if USE_LINEAR_BUFFER_RX + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); +#else + TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false); +#endif + } + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 1) // Check if usage is explicit data feedback + { + audio->ep_fb = ep_addr; + audio->feedback.frame_shift = desc_ep->bInterval -1; + + // Enable SOF interrupt if callback is implemented + if (tud_audio_feedback_interval_isr) usbd_sof_enable(rhport, true); + } +#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT + + foundEPs += 1; + } + p_desc = tu_desc_next(p_desc); + } + + TU_VERIFY(foundEPs == nEps); + + // Invoke one callback for a final set interface + if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + // Prepare feedback computation if callback is available + if (tud_audio_feedback_params_cb) + { + audio_feedback_params_t fb_param; + + tud_audio_feedback_params_cb(func_id, alt, &fb_param); + audio->feedback.compute_method = fb_param.method; + + // Minimal/Maximum value in 16.16 format for full speed (1ms per frame) or high speed (125 us per frame) + uint32_t const frame_div = (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000; + audio->feedback.min_value = (fb_param.sample_freq/frame_div - 1) << 16; + audio->feedback.max_value = (fb_param.sample_freq/frame_div + 1) << 16; + + switch(fb_param.method) + { + case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: + case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT: + case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2: + set_fb_params_freq(audio, fb_param.sample_freq, fb_param.frequency.mclk_freq); + break; + + #if 0 // implement later + case AUDIO_FEEDBACK_METHOD_FIFO_COUNT: + { + uint64_t fb64 = ((uint64_t) fb_param.sample_freq) << 16; + audio->feedback.compute.fifo_count.nominal_value = (uint32_t) (fb64 / frame_div); + audio->feedback.compute.fifo_count.threshold_bytes = fb_param.fifo_count.threshold_bytes; + + tud_audio_fb_set(audio->feedback.compute.fifo_count.nominal_value); + } + break; + #endif + + // nothing to do + default: break; + } + } +#endif + + // We are done - abort loop + break; + } + + // Moving forward + p_desc = tu_desc_next(p_desc); + } + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + // Disable SOF interrupt if no driver has any enabled feedback EP + bool disable = true; + for(uint8_t i=0; i < CFG_TUD_AUDIO; i++) + { + if (_audiod_fct[i].ep_fb != 0) + { + disable = false; + break; + } + } + if (disable) usbd_sof_enable(rhport, false); +#endif + + tud_control_status(rhport, p_request); + + return true; +} + +// Invoked when class request DATA stage is finished. +// return false to stall control EP (e.g Host send non-sense DATA) +static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const * p_request) +{ + // Handle audio class specific set requests + if(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) + { + uint8_t func_id; + + switch (p_request->bmRequestType_bit.recipient) + { + case TUSB_REQ_RCPT_INTERFACE: + { + uint8_t itf = TU_U16_LOW(p_request->wIndex); + uint8_t entityID = TU_U16_HIGH(p_request->wIndex); + + if (entityID != 0) + { + if (tud_audio_set_req_entity_cb) + { + // Check if entity is present and get corresponding driver index + TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); + + // Invoke callback + return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); + } + else + { + TU_LOG2(" No entity set request callback available!\r\n"); + return false; // In case no callback function is present or request can not be conducted we stall it + } + } + else + { + if (tud_audio_set_req_itf_cb) + { + // Find index of audio driver structure and verify interface really exists + TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); + + // Invoke callback + return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); + } + else + { + TU_LOG2(" No interface set request callback available!\r\n"); + return false; // In case no callback function is present or request can not be conducted we stall it + } + } + } + break; + + case TUSB_REQ_RCPT_ENDPOINT: + { + uint8_t ep = TU_U16_LOW(p_request->wIndex); + + if (tud_audio_set_req_ep_cb) + { + // Check if entity is present and get corresponding driver index + TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); + + // Invoke callback + return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); + } + else + { + TU_LOG2(" No EP set request callback available!\r\n"); + return false; // In case no callback function is present or request can not be conducted we stall it + } + } + break; + // Unknown/Unsupported recipient + default: TU_BREAKPOINT(); return false; + } + } + return true; +} + +// Handle class control request +// return false to stall control endpoint (e.g unsupported request) +static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const * p_request) +{ + (void) rhport; + + // Handle standard requests - standard set requests usually have no data stage so we also handle set requests here + if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) + { + switch (p_request->bRequest) + { + case TUSB_REQ_GET_INTERFACE: + return audiod_get_interface(rhport, p_request); + + case TUSB_REQ_SET_INTERFACE: + return audiod_set_interface(rhport, p_request); + + // Unknown/Unsupported request + default: TU_BREAKPOINT(); return false; + } + } + + // Handle class requests + if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) + { + uint8_t itf = TU_U16_LOW(p_request->wIndex); + uint8_t func_id; + + // Conduct checks which depend on the recipient + switch (p_request->bmRequestType_bit.recipient) + { + case TUSB_REQ_RCPT_INTERFACE: + { + uint8_t entityID = TU_U16_HIGH(p_request->wIndex); + + // Verify if entity is present + if (entityID != 0) + { + // Find index of audio driver structure and verify entity really exists + TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); + + // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests + if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) + { + if (tud_audio_get_req_entity_cb) + { + return tud_audio_get_req_entity_cb(rhport, p_request); + } + else + { + TU_LOG2(" No entity get request callback available!\r\n"); + return false; // Stall + } + } + } + else + { + // Find index of audio driver structure and verify interface really exists + TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); + + // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests + if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) + { + if (tud_audio_get_req_itf_cb) + { + return tud_audio_get_req_itf_cb(rhport, p_request); + } + else + { + TU_LOG2(" No interface get request callback available!\r\n"); + return false; // Stall + } + } + } + } + break; + + case TUSB_REQ_RCPT_ENDPOINT: + { + uint8_t ep = TU_U16_LOW(p_request->wIndex); + + // Find index of audio driver structure and verify EP really exists + TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); + + // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests + if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) + { + if (tud_audio_get_req_ep_cb) + { + return tud_audio_get_req_ep_cb(rhport, p_request); + } + else + { + TU_LOG2(" No EP get request callback available!\r\n"); + return false; // Stall + } + } + } + break; + + // Unknown/Unsupported recipient + default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false; + } + + // If we end here, the received request is a set request - we schedule a receive for the data stage and return true here. We handle the rest later in audiod_control_complete() once the data stage was finished + TU_VERIFY(tud_control_xfer(rhport, p_request, _audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz)); + return true; + } + + // There went something wrong - unsupported control request type + TU_BREAKPOINT(); + return false; +} + +bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if ( stage == CONTROL_STAGE_SETUP ) + { + return audiod_control_request(rhport, request); + } + else if ( stage == CONTROL_STAGE_DATA ) + { + return audiod_control_complete(rhport, request); + } + + return true; +} + +bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) result; + (void) xferred_bytes; + + // Search for interface belonging to given end point address and proceed as required + for (uint8_t func_id = 0; func_id < CFG_TUD_AUDIO; func_id++) + { + audiod_function_t* audio = &_audiod_fct[func_id]; + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN + + // Data transmission of control interrupt finished + if (audio->ep_int_ctr == ep_addr) + { + // According to USB2 specification, maximum payload of interrupt EP is 8 bytes on low speed, 64 bytes on full speed, and 1024 bytes on high speed (but only if an alternate interface other than 0 is used - see specification p. 49) + // In case there is nothing to send we have to return a NAK - this is taken care of by PHY ??? + // In case of an erroneous transmission a retransmission is conducted - this is taken care of by PHY ??? + + // I assume here, that things above are handled by PHY + // All transmission is done - what remains to do is to inform job was completed + + if (tud_audio_int_ctr_done_cb) TU_VERIFY(tud_audio_int_ctr_done_cb(rhport, (uint16_t) xferred_bytes)); + } + +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN + + // Data transmission of audio packet finished + if (audio->ep_in == ep_addr && audio->alt_setting != 0) + { + // USB 2.0, section 5.6.4, third paragraph, states "An isochronous endpoint must specify its required bus access period. However, an isochronous endpoint must be prepared to handle poll rates faster than the one specified." + // That paragraph goes on to say "An isochronous IN endpoint must return a zero-length packet whenever data is requested at a faster interval than the specified interval and data is not available." + // This can only be solved reliably if we load a ZLP after every IN transmission since we can not say if the host requests samples earlier than we declared! Once all samples are collected we overwrite the loaded ZLP. + + // Check if there is data to load into EPs buffer - if not load it with ZLP + // Be aware - we as a device are not able to know if the host polls for data with a faster rate as we stated this in the descriptors. Therefore we always have to put something into the EPs buffer. However, once we did that, there is no way of aborting this or replacing what we put into the buffer before! + // This is the only place where we can fill something into the EPs buffer! + + // Load new data + TU_VERIFY(audiod_tx_done_cb(rhport, audio)); + + // Transmission of ZLP is done by audiod_tx_done_cb() + return true; + } +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + + // New audio packet received + if (audio->ep_out == ep_addr) + { + TU_VERIFY(audiod_rx_done_cb(rhport, audio, (uint16_t) xferred_bytes)); + return true; + } + + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + // Transmission of feedback EP finished + if (audio->ep_fb == ep_addr) + { + if (tud_audio_fb_done_cb) tud_audio_fb_done_cb(func_id); + + // Schedule a transmit with the new value if EP is not busy + if (!usbd_edpt_busy(rhport, audio->ep_fb)) + { + // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent + return audiod_fb_send(rhport, audio); + } + } +#endif +#endif + } + + return false; +} + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + +static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq) +{ + // Check if frame interval is within sane limits + // The interval value n_frames was taken from the descriptors within audiod_set_interface() + + // n_frames_min is ceil(2^10 * f_s / f_m) for full speed and ceil(2^13 * f_s / f_m) for high speed + // this lower limit ensures the measures feedback value has sufficient precision + uint32_t const k = (TUSB_SPEED_FULL == tud_speed_get()) ? 10 : 13; + uint32_t const n_frame = (1UL << audio->feedback.frame_shift); + + if ( (((1UL << k) * sample_freq / mclk_freq) + 1) > n_frame ) + { + TU_LOG1(" UAC2 feedback interval too small\r\n"); TU_BREAKPOINT(); return false; + } + + // Check if parameters really allow for a power of two division + if ((mclk_freq % sample_freq) == 0 && tu_is_power_of_two(mclk_freq / sample_freq)) + { + audio->feedback.compute_method = AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2; + audio->feedback.compute.power_of_2 = 16 - audio->feedback.frame_shift - tu_log2(mclk_freq / sample_freq); + } + else if ( audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT) + { + audio->feedback.compute.float_const = (float)sample_freq / mclk_freq * (1UL << (16 - audio->feedback.frame_shift)); + } + else + { + audio->feedback.compute.fixed.sample_freq = sample_freq; + audio->feedback.compute.fixed.mclk_freq = mclk_freq; + } + + return true; +} + +uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles) +{ + audiod_function_t* audio = &_audiod_fct[func_id]; + uint32_t feedback; + + switch (audio->feedback.compute_method) + { + case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2: + feedback = (cycles << audio->feedback.compute.power_of_2); + break; + + case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT: + feedback = (uint32_t) ((float) cycles * audio->feedback.compute.float_const); + break; + + case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: + { + uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - audio->feedback.frame_shift); + feedback = (uint32_t) (fb64 / audio->feedback.compute.fixed.mclk_freq); + } + break; + + default: return 0; + } + + // For Windows: https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/usb-2-0-audio-drivers + // The size of isochronous packets created by the device must be within the limits specified in FMT-2.0 section 2.3.1.1. + // This means that the deviation of actual packet size from nominal size must not exceed +/- one audio slot + // (audio slot = channel count samples). + if ( feedback > audio->feedback.max_value ) feedback = audio->feedback.max_value; + if ( feedback < audio->feedback.min_value ) feedback = audio->feedback.min_value; + + tud_audio_n_fb_set(func_id, feedback); + + return feedback; +} +#endif + +TU_ATTR_FAST_FUNC void audiod_sof_isr (uint8_t rhport, uint32_t frame_count) +{ + (void) rhport; + (void) frame_count; + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + // Determine feedback value - The feedback method is described in 5.12.4.2 of the USB 2.0 spec + // Boiled down, the feedback value Ff = n_samples / (micro)frame. + // Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s) + // The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where P = min( ceil(log2(f_m / f_s)), K) + // feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames + + // Iterate over audio functions and set feedback value + for(uint8_t i=0; i < CFG_TUD_AUDIO; i++) + { + audiod_function_t* audio = &_audiod_fct[i]; + + if (audio->ep_fb != 0) + { + // HS shift need to be adjusted since SOF event is generated for frame only + uint8_t const hs_adjust = (TUSB_SPEED_HIGH == tud_speed_get()) ? 3 : 0; + uint32_t const interval = 1UL << (audio->feedback.frame_shift - hs_adjust); + if ( 0 == (frame_count & (interval-1)) ) + { + if(tud_audio_feedback_interval_isr) tud_audio_feedback_interval_isr(i, frame_count, audio->feedback.frame_shift); + } + } + } +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +} + +bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len) +{ + // Handles only sending of data not receiving + if (p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) return false; + + // Get corresponding driver index + uint8_t func_id; + uint8_t itf = TU_U16_LOW(p_request->wIndex); + + // Conduct checks which depend on the recipient + switch (p_request->bmRequestType_bit.recipient) + { + case TUSB_REQ_RCPT_INTERFACE: + { + uint8_t entityID = TU_U16_HIGH(p_request->wIndex); + + // Verify if entity is present + if (entityID != 0) + { + // Find index of audio driver structure and verify entity really exists + TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); + } + else + { + // Find index of audio driver structure and verify interface really exists + TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); + } + } + break; + + case TUSB_REQ_RCPT_ENDPOINT: + { + uint8_t ep = TU_U16_LOW(p_request->wIndex); + + // Find index of audio driver structure and verify EP really exists + TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); + } + break; + + // Unknown/Unsupported recipient + default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false; + } + + // Crop length + if (len > _audiod_fct[func_id].ctrl_buf_sz) len = _audiod_fct[func_id].ctrl_buf_sz; + + // Copy into buffer + memcpy((void *)_audiod_fct[func_id].ctrl_buf, data, (size_t)len); + + // Schedule transmit + return tud_control_xfer(rhport, p_request, (void*)_audiod_fct[func_id].ctrl_buf, len); +} + +// This helper function finds for a given audio function and AS interface number the index of the attached driver structure, the index of the interface in the audio function +// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and +// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero. +static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int) +{ + if (audio->p_desc) + { + // Get pointer at end + uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; + + // Advance past AC descriptors + uint8_t const *p_desc = tu_desc_next(audio->p_desc); + p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength; + + uint8_t tmp = 0; + while (p_desc < p_desc_end) + { + // We assume the number of alternate settings is increasing thus we return the index of alternate setting zero! + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0) + { + if (((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf) + { + *idxItf = tmp; + *pp_desc_int = p_desc; + return true; + } + // Increase index, bytes read, and pointer + tmp++; + } + p_desc = tu_desc_next(p_desc); + } + } + return false; +} + +// This helper function finds for a given AS interface number the index of the attached driver structure, the index of the interface in the audio function +// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and +// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero. +static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int) +{ + // Loop over audio driver interfaces + uint8_t i; + for (i = 0; i < CFG_TUD_AUDIO; i++) + { + if (audiod_get_AS_interface_index(itf, &_audiod_fct[i], idxItf, pp_desc_int)) + { + *func_id = i; + return true; + } + } + + return false; +} + +// Verify an entity with the given ID exists and returns also the corresponding driver index +static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id) +{ + uint8_t i; + for (i = 0; i < CFG_TUD_AUDIO; i++) + { + // Look for the correct driver by checking if the unique standard AC interface number fits + if (_audiod_fct[i].p_desc && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf) + { + // Get pointers after class specific AC descriptors and end of AC descriptors - entities are defined in between + uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc); // Points to CS AC descriptor + uint8_t const *p_desc_end = ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength + p_desc; + p_desc = tu_desc_next(p_desc); // Get past CS AC descriptor + + while (p_desc < p_desc_end) + { + if (p_desc[3] == entityID) // Entity IDs are always at offset 3 + { + *func_id = i; + return true; + } + p_desc = tu_desc_next(p_desc); + } + } + } + return false; +} + +static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id) +{ + uint8_t i; + for (i = 0; i < CFG_TUD_AUDIO; i++) + { + if (_audiod_fct[i].p_desc) + { + // Get pointer at beginning and end + uint8_t const *p_desc = _audiod_fct[i].p_desc; + uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; + + while (p_desc < p_desc_end) + { + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf) + { + *func_id = i; + return true; + } + p_desc = tu_desc_next(p_desc); + } + } + } + return false; +} + +static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id) +{ + uint8_t i; + for (i = 0; i < CFG_TUD_AUDIO; i++) + { + if (_audiod_fct[i].p_desc) + { + // Get pointer at end + uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length; + + // Advance past AC descriptors - EP we look for are streaming EPs + uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc); + p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength; + + while (p_desc < p_desc_end) + { + if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT && ((tusb_desc_endpoint_t const * )p_desc)->bEndpointAddress == ep) + { + *func_id = i; + return true; + } + p_desc = tu_desc_next(p_desc); + } + } + } + return false; +} + +#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING +// p_desc points to the AS interface of alternate setting zero +// itf is the interface number of the corresponding interface - we check if the interface belongs to EP in or EP out to see if it is a TX or RX parameter +// Currently, only AS interfaces with an EP (in or out) are supposed to be parsed for! +static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf) +{ +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT + if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) return; // Abort, this interface has no EP, this driver does not support this currently +#endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT + if (as_itf != audio->ep_in_as_intf_num) return; +#endif +#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT + if (as_itf != audio->ep_out_as_intf_num) return; +#endif + + p_desc = tu_desc_next(p_desc); // Exclude standard AS interface descriptor of current alternate interface descriptor + + while (p_desc < p_desc_end) + { + // Abort if follow up descriptor is a new standard interface descriptor - indicates the last AS descriptor was already finished + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) break; + + // Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format type and format and also to get number of physical channels + if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL) + { +#if CFG_TUD_AUDIO_ENABLE_EP_IN + if (as_itf == audio->ep_in_as_intf_num) + { + audio->n_channels_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels; + audio->format_type_tx = (audio_format_type_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType); + +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + audio->format_type_I_tx = (audio_data_format_type_I_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats); +#endif + } +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + if (as_itf == audio->ep_out_as_intf_num) + { + audio->n_channels_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels; + audio->format_type_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType; +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + audio->format_type_I_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats; +#endif + } +#endif + } + + // Look for a Type I Format Type Descriptor(2.3.1.6 - Audio Formats) +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_FORMAT_TYPE && ((audio_desc_type_I_format_t const * )p_desc)->bFormatType == AUDIO_FORMAT_TYPE_I) + { +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT + if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) break; // Abort loop, this interface has no EP, this driver does not support this currently +#endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT + if (as_itf != audio->ep_in_as_intf_num) break; +#endif +#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT + if (as_itf != audio->ep_out_as_intf_num) break; +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN + if (as_itf == audio->ep_in_as_intf_num) + { + audio->n_bytes_per_sampe_tx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; + } +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + if (as_itf == audio->ep_out_as_intf_num) + { + audio->n_bytes_per_sampe_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; + } +#endif + } +#endif + + // Other format types are not supported yet + + p_desc = tu_desc_next(p_desc); + } +} +#endif + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + +bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + + // Format the feedback value +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION + if ( TUSB_SPEED_FULL == tud_speed_get() ) + { + uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].feedback.value; + + // For FS format is 10.14 + *(fb++) = (feedback >> 2) & 0xFF; + *(fb++) = (feedback >> 10) & 0xFF; + *(fb++) = (feedback >> 18) & 0xFF; + // 4th byte is needed to work correctly with MS Windows + *fb = 0; + }else +#else + { + // Send value as-is, caller will choose the appropriate format + _audiod_fct[func_id].feedback.value = feedback; + } +#endif + + // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value + if (!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb)) + { + return audiod_fb_send(_audiod_fct[func_id].rhport, &_audiod_fct[func_id]); + } + + return true; +} +#endif + +// No security checks here - internal function only which should always succeed +uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio) +{ + for (uint8_t cnt=0; cnt < CFG_TUD_AUDIO; cnt++) + { + if (&_audiod_fct[cnt] == audio) return cnt; + } + return 0; +} + +#endif //CFG_TUD_ENABLED && CFG_TUD_AUDIO diff --git a/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.h b/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.h new file mode 100644 index 00000000..0ef100fa --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.h @@ -0,0 +1,699 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Ha Thach (tinyusb.org) + * Copyright (c) 2020 Reinhard Panhuber + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_AUDIO_DEVICE_H_ +#define _TUSB_AUDIO_DEVICE_H_ + +#include "audio.h" + +//--------------------------------------------------------------------+ +// Class Driver Configuration +//--------------------------------------------------------------------+ + +// All sizes are in bytes! + +#ifndef CFG_TUD_AUDIO_FUNC_1_DESC_LEN +#error You must tell the driver the length of the audio function descriptor including IAD descriptor +#endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_DESC_LEN +#error You must tell the driver the length of the audio function descriptor including IAD descriptor +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_DESC_LEN +#error You must tell the driver the length of the audio function descriptor including IAD descriptor +#endif +#endif + +// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces +#ifndef CFG_TUD_AUDIO_FUNC_1_N_AS_INT +#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! +#endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_N_AS_INT +#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_N_AS_INT +#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! +#endif +#endif + +// Size of control buffer used to receive and send control messages via EP0 - has to be big enough to hold your biggest request structure e.g. range requests with multiple intervals defined or cluster descriptors +#ifndef CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ +#error You must define an audio class control request buffer size! +#endif + +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ +#error You must define an audio class control request buffer size! +#endif +#endif + +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ +#error You must define an audio class control request buffer size! +#endif +#endif + +// End point sizes IN BYTES - Limits: Full Speed <= 1023, High Speed <= 1024 +#ifndef CFG_TUD_AUDIO_ENABLE_EP_IN +#define CFG_TUD_AUDIO_ENABLE_EP_IN 0 // TX +#endif + +#ifndef CFG_TUD_AUDIO_ENABLE_EP_OUT +#define CFG_TUD_AUDIO_ENABLE_EP_OUT 0 // RX +#endif + +// Maximum EP sizes for all alternate AS interface settings - used for checks and buffer allocation +#if CFG_TUD_AUDIO_ENABLE_EP_IN +#ifndef CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX +#error You must tell the driver the biggest EP IN size! +#endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX +#error You must tell the driver the biggest EP IN size! +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX +#error You must tell the driver the biggest EP IN size! +#endif +#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +#ifndef CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX +#error You must tell the driver the biggest EP OUT size! +#endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX +#error You must tell the driver the biggest EP OUT size! +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX +#error You must tell the driver the biggest EP OUT size! +#endif +#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT + +// Software EP FIFO buffer sizes - must be >= max EP SIZEs! +#ifndef CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ 0 +#endif + +#ifndef CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ 0 +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN +#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size +#endif + +#if CFG_TUD_AUDIO > 1 +#if CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size +#endif +#endif + +#if CFG_TUD_AUDIO > 2 +#if CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size +#endif +#endif +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size +#endif + +#if CFG_TUD_AUDIO > 1 +#if CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size +#endif +#endif + +#if CFG_TUD_AUDIO > 2 +#if CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size +#endif +#endif +#endif + +// Enable/disable feedback EP (required for asynchronous RX applications) +#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // Feedback - 0 or 1 +#endif + +// Enable/disable conversion from 16.16 to 10.14 format on full-speed devices. See tud_audio_n_fb_set(). +#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION +#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 0 // 0 or 1 +#endif + +// Audio interrupt control EP size - disabled if 0 +#ifndef CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 // Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74) +#endif + +#ifndef CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE +#define CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE 6 // Buffer size of audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74) +#endif + +// Use software encoding/decoding + +// The software coding feature of the driver is not mandatory. It is useful if, for instance, you have two I2S streams which need to be interleaved +// into a single PCM stream as SAMPLE_1 | SAMPLE_2 | SAMPLE_3 | SAMPLE_4. +// +// Currently, only PCM type I encoding/decoding is supported! +// +// If the coding feature is to be used, support FIFOs need to be configured. Their sizes and numbers are defined below. + +// Encoding/decoding is done in software and thus time consuming. If you can encode/decode your stream more efficiently do not use the +// support FIFOs but write/read directly into/from the EP_X_SW_BUFFER_FIFOs using +// - tud_audio_n_write() or +// - tud_audio_n_read(). +// To write/read to/from the support FIFOs use +// - tud_audio_n_write_support_ff() or +// - tud_audio_n_read_support_ff(). +// +// The encoding/decoding format type done is defined below. +// +// The encoding/decoding starts when the private callback functions +// - audio_tx_done_cb() +// - audio_rx_done_cb() +// are invoked. If support FIFOs are used, the corresponding encoding/decoding functions are called from there. +// Once encoding/decoding is done the result is put directly into the EP_X_SW_BUFFER_FIFOs. You can use the public callback functions +// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb() +// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb() +// if you want to get informed what happened. +// +// If you don't use the support FIFOs you may use the public callback functions +// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb() +// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb() +// to write/read from/into the EP_X_SW_BUFFER_FIFOs at the right time. +// +// If you need a different encoding which is not support so far implement it in the +// - audio_tx_done_cb() +// - audio_rx_done_cb() +// functions. + +// Enable encoding/decodings - for these to work, support FIFOs need to be setup in appropriate numbers and size +// The actual coding parameters of active AS alternate interface is parsed from the descriptors + +// The item size of the FIFO is always fixed to one i.e. bytes! Furthermore, the actively used FIFO depth is reconfigured such that the depth is a multiple of the current sample size in order to avoid samples to get split up in case of a wrap in the FIFO ring buffer (depth = (max_depth / sampe_sz) * sampe_sz)! +// This is important to remind in case you use DMAs! If the sample sizes changes, the DMA MUST BE RECONFIGURED just like the FIFOs for a different depth!!! + +// For PCM encoding/decoding + +#ifndef CFG_TUD_AUDIO_ENABLE_ENCODING +#define CFG_TUD_AUDIO_ENABLE_ENCODING 0 +#endif + +#ifndef CFG_TUD_AUDIO_ENABLE_DECODING +#define CFG_TUD_AUDIO_ENABLE_DECODING 0 +#endif + +// This enabling allows to save the current coding parameters e.g. # of bytes per sample etc. - TYPE_I includes common PCM encoding +#ifndef CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING +#define CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING 0 +#endif + +#ifndef CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING +#define CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING 0 +#endif + +// Type I Coding parameters not given within UAC2 descriptors +// It would be possible to allow for a more flexible setting and not fix this parameter as done below. However, this is most often not needed and kept for later if really necessary. The more flexible setting could be implemented within set_interface(), however, how the values are saved per alternate setting is to be determined! +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING +#ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO +#endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO +#endif +#endif +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING +#ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO +#endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO +#endif +#endif +#endif + +// Remaining types not support so far + +// Number of support FIFOs to set up - multiple channels can be handled by one FIFO - very common is two channels per FIFO stemming from one I2S interface +#ifndef CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO 0 +#endif + +#ifndef CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO 0 +#endif + +// Size of support FIFOs IN BYTES - if size > 0 there are as many FIFOs set up as CFG_TUD_AUDIO_FUNC_X_N_TX_SUPP_SW_FIFO and CFG_TUD_AUDIO_FUNC_X_N_RX_SUPP_SW_FIFO +#ifndef CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ 0 // FIFO size - minimum size: ceil(f_s/1000) * max(# of TX channels) / (# of TX support FIFOs) * max(# of bytes per sample) +#endif +#ifndef CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ 0 +#endif + +#ifndef CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ 0 // FIFO size - minimum size: ceil(f_s/1000) * max(# of RX channels) / (# of RX support FIFOs) * max(# of bytes per sample) +#endif +#ifndef CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ 0 +#endif + +//static_assert(sizeof(tud_audio_desc_lengths) != CFG_TUD_AUDIO, "Supply audio function descriptor pack length!"); + +// Supported types of this driver: +// AUDIO_DATA_FORMAT_TYPE_I_PCM - Required definitions: CFG_TUD_AUDIO_N_CHANNELS and CFG_TUD_AUDIO_BYTES_PER_CHANNEL + +#ifdef __cplusplus +extern "C" { +#endif + +/** \addtogroup AUDIO_Serial Serial + * @{ + * \defgroup AUDIO_Serial_Device Device + * @{ */ + +//--------------------------------------------------------------------+ +// Application API (Multiple Interfaces) +// CFG_TUD_AUDIO > 1 +//--------------------------------------------------------------------+ +bool tud_audio_n_mounted (uint8_t func_id); + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +uint16_t tud_audio_n_available (uint8_t func_id); +uint16_t tud_audio_n_read (uint8_t func_id, void* buffer, uint16_t bufsize); +bool tud_audio_n_clear_ep_out_ff (uint8_t func_id); // Delete all content in the EP OUT FIFO +tu_fifo_t* tud_audio_n_get_ep_out_ff (uint8_t func_id); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING +bool tud_audio_n_clear_rx_support_ff (uint8_t func_id, uint8_t ff_idx); // Delete all content in the support RX FIFOs +uint16_t tud_audio_n_available_support_ff (uint8_t func_id, uint8_t ff_idx); +uint16_t tud_audio_n_read_support_ff (uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize); +tu_fifo_t* tud_audio_n_get_rx_support_ff (uint8_t func_id, uint8_t ff_idx); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +uint16_t tud_audio_n_write (uint8_t func_id, const void * data, uint16_t len); +bool tud_audio_n_clear_ep_in_ff (uint8_t func_id); // Delete all content in the EP IN FIFO +tu_fifo_t* tud_audio_n_get_ep_in_ff (uint8_t func_id); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING +uint16_t tud_audio_n_flush_tx_support_ff (uint8_t func_id); // Force all content in the support TX FIFOs to be written into EP SW FIFO +bool tud_audio_n_clear_tx_support_ff (uint8_t func_id, uint8_t ff_idx); +uint16_t tud_audio_n_write_support_ff (uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len); +tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_idx); +#endif + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +uint16_t tud_audio_int_ctr_n_write (uint8_t func_id, uint8_t const* buffer, uint16_t len); +#endif + +//--------------------------------------------------------------------+ +// Application API (Interface0) +//--------------------------------------------------------------------+ + +static inline bool tud_audio_mounted (void); + +// RX API + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +static inline uint16_t tud_audio_available (void); +static inline bool tud_audio_clear_ep_out_ff (void); // Delete all content in the EP OUT FIFO +static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize); +static inline tu_fifo_t* tud_audio_get_ep_out_ff (void); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING +static inline bool tud_audio_clear_rx_support_ff (uint8_t ff_idx); +static inline uint16_t tud_audio_available_support_ff (uint8_t ff_idx); +static inline uint16_t tud_audio_read_support_ff (uint8_t ff_idx, void* buffer, uint16_t bufsize); +static inline tu_fifo_t* tud_audio_get_rx_support_ff (uint8_t ff_idx); +#endif + +// TX API + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +static inline uint16_t tud_audio_write (const void * data, uint16_t len); +static inline bool tud_audio_clear_ep_in_ff (void); +static inline tu_fifo_t* tud_audio_get_ep_in_ff (void); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING +static inline uint16_t tud_audio_flush_tx_support_ff (void); +static inline uint16_t tud_audio_clear_tx_support_ff (uint8_t ff_idx); +static inline uint16_t tud_audio_write_support_ff (uint8_t ff_idx, const void * data, uint16_t len); +static inline tu_fifo_t* tud_audio_get_tx_support_ff (uint8_t ff_idx); +#endif + +// INT CTR API + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +static inline uint16_t tud_audio_int_ctr_write (uint8_t const* buffer, uint16_t len); +#endif + +// Buffer control EP data and schedule a transmit +// This function is intended to be used if you do not have a persistent buffer or memory location available (e.g. non-local variables) and need to answer onto a +// get request. This function buffers your answer request frame into the control buffer of the corresponding audio driver and schedules a transmit for sending it. +// Since transmission is triggered via interrupts, a persistent memory location is required onto which the buffer pointer in pointing. If you already have such +// available you may directly use 'tud_control_xfer(...)'. In this case data does not need to be copied into an additional buffer and you save some time. +// If the request's wLength is zero, a status packet is sent instead. +bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len); + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ + +#if CFG_TUD_AUDIO_ENABLE_EP_IN +TU_ATTR_WEAK bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting); +TU_ATTR_WEAK bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +TU_ATTR_WEAK bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting); +TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id); + + +// determined by the user itself and set by use of tud_audio_n_fb_set(). The feedback value may be determined e.g. from some fill status of some FIFO buffer. Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus less CPU load, disadvantage: typically a larger FIFO is needed to compensate for jitter (e.g. 8 frames), i.e. a larger delay is introduced. + +// Feedback value is calculated within the audio driver by use of SOF interrupt. The driver needs information about the master clock f_m from which the audio sample frequency f_s is derived, f_s itself, and the cycle count of f_m at time of the SOF interrupt (e.g. by use of a hardware counter) - see tud_audio_set_fb_params(). Advantage: Reduced jitter in the feedback value computation, hence, the receive FIFO can be smaller (e.g. 2 frames) and thus a smaller delay is possible, disadvantage: higher CPU load due to SOF ISR handling every frame i.e. 1ms or 125us. This option is a great starting point to try the SOF ISR option but depending on your hardware setup (performance of the CPU) it might not work. If so, figure out why and use the next option. (The most critical point is the reading of the cycle counter value of f_m. It is read from within the SOF ISR - see: audiod_sof() -, hence, the ISR must has a high priority such that no software dependent "random" delay i.e. jitter is introduced). + +// Feedback value is determined by the user by use of SOF interrupt. The user may use tud_audio_sof_isr() which is called every SOF (of course only invoked when an alternate interface other than zero was set). The number of frames used to determine the feedback value for the currently active alternate setting can be get by tud_audio_get_fb_n_frames(). The feedback value must be set by use of tud_audio_n_fb_set(). + +// This function is used to provide data rate feedback from an asynchronous sink. Feedback value will be sent at FB endpoint interval till it's changed. +// +// The feedback format is specified to be 16.16 for HS and 10.14 for FS devices (see Universal Serial Bus Specification Revision 2.0 5.12.4.2). By default, +// the choice of format is left to the caller and feedback argument is sent as-is. If CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION is set, then tinyusb +// expects 16.16 format and handles the conversion to 10.14 on FS. +// +// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 devices. On Linux and macOS it seems the +// driver can work with either format. So a good compromise is to keep format correction disabled and stick to 16.16 format. + +// Feedback value can be determined from within the SOF ISR of the audio driver. This should reduce jitter. If the feature is used, the user can not set the feedback value. + +// Determine feedback value - The feedback method is described in 5.12.4.2 of the USB 2.0 spec +// Boiled down, the feedback value Ff = n_samples / (micro)frame. +// Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s) +// The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where P = min( ceil(log2(f_m / f_s)), K) +// feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames + +bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback); +static inline bool tud_audio_fb_set(uint32_t feedback); + +// Update feedback value with passed cycles since last time this update function is called. +// Typically called within tud_audio_sof_isr(). Required tud_audio_feedback_params_cb() is implemented +// This function will also call tud_audio_feedback_set() +// return feedback value in 16.16 for reference (0 for error) +uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles); + +enum { + AUDIO_FEEDBACK_METHOD_DISABLED, + AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED, + AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT, + AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2, + + // impelemnt later + // AUDIO_FEEDBACK_METHOD_FIFO_COUNT +}; + +typedef struct { + uint8_t method; + uint32_t sample_freq; // sample frequency in Hz + + union { + struct { + uint32_t mclk_freq; // Main clock frequency in Hz i.e. master clock to which sample clock is based on + }frequency; + +#if 0 // implement later + struct { + uint32_t threshold_bytes; // minimum number of bytes received to be considered as filled/ready + }fifo_count; +#endif + }; +}audio_feedback_params_t; + +// Invoked when needed to set feedback parameters +TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param); + +// Callback in ISR context, invoked periodically according to feedback endpoint bInterval. +// Could be used to compute and update feedback value, should be placed in RAM if possible +// frame_number : current SOF count +// interval_shift: number of bit shift i.e log2(interval) from Feedback endpoint descriptor +TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift); + +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t n_bytes_copied); +#endif + +// Invoked when audio set interface request received +TU_ATTR_WEAK bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request); + +// Invoked when audio set interface request received which closes an EP +TU_ATTR_WEAK bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request); + +// Invoked when audio class specific set request received for an EP +TU_ATTR_WEAK bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); + +// Invoked when audio class specific set request received for an interface +TU_ATTR_WEAK bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); + +// Invoked when audio class specific set request received for an entity +TU_ATTR_WEAK bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); + +// Invoked when audio class specific get request received for an EP +TU_ATTR_WEAK bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request); + +// Invoked when audio class specific get request received for an interface +TU_ATTR_WEAK bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request); + +// Invoked when audio class specific get request received for an entity +TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request); + +//--------------------------------------------------------------------+ +// Inline Functions +//--------------------------------------------------------------------+ + +static inline bool tud_audio_mounted(void) +{ + return tud_audio_n_mounted(0); +} + +// RX API + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING + +static inline uint16_t tud_audio_available(void) +{ + return tud_audio_n_available(0); +} + +static inline uint16_t tud_audio_read(void* buffer, uint16_t bufsize) +{ + return tud_audio_n_read(0, buffer, bufsize); +} + +static inline bool tud_audio_clear_ep_out_ff(void) +{ + return tud_audio_n_clear_ep_out_ff(0); +} + +static inline tu_fifo_t* tud_audio_get_ep_out_ff(void) +{ + return tud_audio_n_get_ep_out_ff(0); +} + +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING + +static inline bool tud_audio_clear_rx_support_ff(uint8_t ff_idx) +{ + return tud_audio_n_clear_rx_support_ff(0, ff_idx); +} + +static inline uint16_t tud_audio_available_support_ff(uint8_t ff_idx) +{ + return tud_audio_n_available_support_ff(0, ff_idx); +} + +static inline uint16_t tud_audio_read_support_ff(uint8_t ff_idx, void* buffer, uint16_t bufsize) +{ + return tud_audio_n_read_support_ff(0, ff_idx, buffer, bufsize); +} + +static inline tu_fifo_t* tud_audio_get_rx_support_ff(uint8_t ff_idx) +{ + return tud_audio_n_get_rx_support_ff(0, ff_idx); +} + +#endif + +// TX API + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING + +static inline uint16_t tud_audio_write(const void * data, uint16_t len) +{ + return tud_audio_n_write(0, data, len); +} + +static inline bool tud_audio_clear_ep_in_ff(void) +{ + return tud_audio_n_clear_ep_in_ff(0); +} + +static inline tu_fifo_t* tud_audio_get_ep_in_ff(void) +{ + return tud_audio_n_get_ep_in_ff(0); +} + +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + +static inline uint16_t tud_audio_flush_tx_support_ff(void) +{ + return tud_audio_n_flush_tx_support_ff(0); +} + +static inline uint16_t tud_audio_clear_tx_support_ff(uint8_t ff_idx) +{ + return tud_audio_n_clear_tx_support_ff(0, ff_idx); +} + +static inline uint16_t tud_audio_write_support_ff(uint8_t ff_idx, const void * data, uint16_t len) +{ + return tud_audio_n_write_support_ff(0, ff_idx, data, len); +} + +static inline tu_fifo_t* tud_audio_get_tx_support_ff(uint8_t ff_idx) +{ + return tud_audio_n_get_tx_support_ff(0, ff_idx); +} + +#endif + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t len) +{ + return tud_audio_int_ctr_n_write(0, buffer, len); +} +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + +static inline bool tud_audio_fb_set(uint32_t feedback) +{ + return tud_audio_n_fb_set(0, feedback); +} + +#endif + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void audiod_init (void); +void audiod_reset (uint8_t rhport); +uint16_t audiod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +bool audiod_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); +void audiod_sof_isr (uint8_t rhport, uint32_t frame_count); + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_AUDIO_DEVICE_H_ */ + +/** @} */ +/** @} */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.c b/test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.c new file mode 100755 index 00000000..f96bb355 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.c @@ -0,0 +1,260 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Jerzy Kasenberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_BTH) + +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "bth_device.h" +#include + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +typedef struct +{ + uint8_t itf_num; + uint8_t ep_ev; + uint8_t ep_acl_in; + uint8_t ep_acl_out; + uint8_t ep_voice[2]; // Not used yet + uint8_t ep_voice_size[2][CFG_TUD_BTH_ISO_ALT_COUNT]; + + // Endpoint Transfer buffer + CFG_TUSB_MEM_ALIGN bt_hci_cmd_t hci_cmd; + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_BTH_DATA_EPSIZE]; + +} btd_interface_t; + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +CFG_TUSB_MEM_SECTION btd_interface_t _btd_itf; + +static bool bt_tx_data(uint8_t ep, void *data, uint16_t len) +{ + uint8_t const rhport = 0; + + // skip if previous transfer not complete + TU_VERIFY(!usbd_edpt_busy(rhport, ep)); + + TU_ASSERT(usbd_edpt_xfer(rhport, ep, data, len)); + + return true; +} + +//--------------------------------------------------------------------+ +// READ API +//--------------------------------------------------------------------+ + + +//--------------------------------------------------------------------+ +// WRITE API +//--------------------------------------------------------------------+ + +bool tud_bt_event_send(void *event, uint16_t event_len) +{ + return bt_tx_data(_btd_itf.ep_ev, event, event_len); +} + +bool tud_bt_acl_data_send(void *event, uint16_t event_len) +{ + return bt_tx_data(_btd_itf.ep_acl_in, event, event_len); +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void btd_init(void) +{ + tu_memclr(&_btd_itf, sizeof(_btd_itf)); +} + +void btd_reset(uint8_t rhport) +{ + (void)rhport; +} + +uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) +{ + tusb_desc_endpoint_t const *desc_ep; + uint16_t drv_len = 0; + // Size of single alternative of ISO interface + const uint16_t iso_alt_itf_size = sizeof(tusb_desc_interface_t) + 2 * sizeof(tusb_desc_endpoint_t); + // Size of hci interface + const uint16_t hci_itf_size = sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t); + // Ensure this is BT Primary Controller + TU_VERIFY(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass && + TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass && + TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0); + + TU_ASSERT(itf_desc->bNumEndpoints == 3 && max_len >= hci_itf_size); + + _btd_itf.itf_num = itf_desc->bInterfaceNumber; + + desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); + + TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer, 0); + TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); + _btd_itf.ep_ev = desc_ep->bEndpointAddress; + + // Open endpoint pair + TU_ASSERT(usbd_open_edpt_pair(rhport, tu_desc_next(desc_ep), 2, TUSB_XFER_BULK, &_btd_itf.ep_acl_out, + &_btd_itf.ep_acl_in), 0); + + itf_desc = (tusb_desc_interface_t const *)tu_desc_next(tu_desc_next(tu_desc_next(desc_ep))); + + // Prepare for incoming data from host + TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE), 0); + + drv_len = hci_itf_size; + + // Ensure this is still BT Primary Controller + TU_ASSERT(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass && + TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass && + TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0); + TU_ASSERT(itf_desc->bNumEndpoints == 2 && max_len >= iso_alt_itf_size + drv_len); + + uint8_t dir; + + desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc); + TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0); + TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0); + dir = tu_edpt_dir(desc_ep->bEndpointAddress); + _btd_itf.ep_voice[dir] = desc_ep->bEndpointAddress; + // Store endpoint size for alternative + _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); + + desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep); + TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0); + dir = tu_edpt_dir(desc_ep->bEndpointAddress); + _btd_itf.ep_voice[dir] = desc_ep->bEndpointAddress; + // Store endpoint size for alternative + _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); + drv_len += iso_alt_itf_size; + + for (int i = 1; i < CFG_TUD_BTH_ISO_ALT_COUNT && drv_len + iso_alt_itf_size <= max_len; ++i) { + // Make sure rest of alternatives matches + itf_desc = (tusb_desc_interface_t const *)tu_desc_next(desc_ep); + if (itf_desc->bDescriptorType != TUSB_DESC_INTERFACE || + TUSB_CLASS_WIRELESS_CONTROLLER != itf_desc->bInterfaceClass || + TUD_BT_APP_SUBCLASS != itf_desc->bInterfaceSubClass || + TUD_BT_PROTOCOL_PRIMARY_CONTROLLER != itf_desc->bInterfaceProtocol) + { + // Not an Iso interface instance + break; + } + TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0); + + desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc); + dir = tu_edpt_dir(desc_ep->bEndpointAddress); + // Verify that alternative endpoint are same as first ones + TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT && + _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0); + _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); + + desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep); + dir = tu_edpt_dir(desc_ep->bEndpointAddress); + // Verify that alternative endpoint are same as first ones + TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT && + _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0); + _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); + drv_len += iso_alt_itf_size; + } + + return drv_len; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) +{ + (void)rhport; + + if ( stage == CONTROL_STAGE_SETUP ) + { + if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && + request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE) + { + // HCI command packet addressing for single function Primary Controllers + TU_VERIFY(request->bRequest == 0 && request->wValue == 0 && request->wIndex == 0); + } + else if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE) + { + if (request->bRequest == TUSB_REQ_SET_INTERFACE && _btd_itf.itf_num + 1 == request->wIndex) + { + // TODO: Set interface it would involve changing size of endpoint size + } + else + { + // HCI command packet for Primary Controller function in a composite device + TU_VERIFY(request->bRequest == 0 && request->wValue == 0 && request->wIndex == _btd_itf.itf_num); + } + } + else return false; + + return tud_control_xfer(rhport, request, &_btd_itf.hci_cmd, sizeof(_btd_itf.hci_cmd)); + } + else if ( stage == CONTROL_STAGE_DATA ) + { + // Handle class request only + TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); + + if (tud_bt_hci_cmd_cb) tud_bt_hci_cmd_cb(&_btd_itf.hci_cmd, tu_min16(request->wLength, sizeof(_btd_itf.hci_cmd))); + } + + return true; +} + +bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void)result; + + // received new data from host + if (ep_addr == _btd_itf.ep_acl_out) + { + if (tud_bt_acl_data_received_cb) tud_bt_acl_data_received_cb(_btd_itf.epout_buf, xferred_bytes); + + // prepare for next data + TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE)); + } + else if (ep_addr == _btd_itf.ep_ev) + { + if (tud_bt_event_sent_cb) tud_bt_event_sent_cb((uint16_t)xferred_bytes); + } + else if (ep_addr == _btd_itf.ep_acl_in) + { + if (tud_bt_acl_data_sent_cb) tud_bt_acl_data_sent_cb((uint16_t)xferred_bytes); + } + + return true; +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.h b/test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.h new file mode 100755 index 00000000..1b90d091 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.h @@ -0,0 +1,109 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Jerzy Kasenberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_BTH_DEVICE_H_ +#define _TUSB_BTH_DEVICE_H_ + +#include +#include + +//--------------------------------------------------------------------+ +// Class Driver Configuration +//--------------------------------------------------------------------+ +#ifndef CFG_TUD_BTH_EVENT_EPSIZE +#define CFG_TUD_BTH_EVENT_EPSIZE 16 +#endif +#ifndef CFG_TUD_BTH_DATA_EPSIZE +#define CFG_TUD_BTH_DATA_EPSIZE 64 +#endif + +typedef struct TU_ATTR_PACKED +{ + uint16_t op_code; + uint8_t param_length; + uint8_t param[255]; +} bt_hci_cmd_t; + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ + +// Invoked when HCI command was received over USB from Bluetooth host. +// Detailed format is described in Bluetooth core specification Vol 2, +// Part E, 5.4.1. +// Length of the command is from 3 bytes (2 bytes for OpCode, +// 1 byte for parameter total length) to 258. +TU_ATTR_WEAK void tud_bt_hci_cmd_cb(void *hci_cmd, size_t cmd_len); + +// Invoked when ACL data was received over USB from Bluetooth host. +// Detailed format is described in Bluetooth core specification Vol 2, +// Part E, 5.4.2. +// Length is from 4 bytes, (12 bits for Handle, 4 bits for flags +// and 16 bits for data total length) to endpoint size. +TU_ATTR_WEAK void tud_bt_acl_data_received_cb(void *acl_data, uint16_t data_len); + +// Called when event sent with tud_bt_event_send() was delivered to BT stack. +// Controller can release/reuse buffer with Event packet at this point. +TU_ATTR_WEAK void tud_bt_event_sent_cb(uint16_t sent_bytes); + +// Called when ACL data that was sent with tud_bt_acl_data_send() +// was delivered to BT stack. +// Controller can release/reuse buffer with ACL packet at this point. +TU_ATTR_WEAK void tud_bt_acl_data_sent_cb(uint16_t sent_bytes); + +// Bluetooth controller calls this function when it wants to send even packet +// as described in Bluetooth core specification Vol 2, Part E, 5.4.4. +// Event has at least 2 bytes, first is Event code second contains parameter +// total length. Controller can release/reuse event memory after +// tud_bt_event_sent_cb() is called. +bool tud_bt_event_send(void *event, uint16_t event_len); + +// Bluetooth controller calls this to send ACL data packet +// as described in Bluetooth core specification Vol 2, Part E, 5.4.2 +// Minimum length is 4 bytes, (12 bits for Handle, 4 bits for flags +// and 16 bits for data total length). Upper limit is not limited +// to endpoint size since buffer is allocate by controller +// and must not be reused till tud_bt_acl_data_sent_cb() is called. +bool tud_bt_acl_data_send(void *acl_data, uint16_t data_len); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void btd_init (void); +void btd_reset (uint8_t rhport); +uint16_t btd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool btd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); +bool btd_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_BTH_DEVICE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc.h b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc.h new file mode 100644 index 00000000..e345139e --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc.h @@ -0,0 +1,409 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup group_class + * \defgroup ClassDriver_CDC Communication Device Class (CDC) + * Currently only Abstract Control Model subclass is supported + * @{ */ + +#ifndef _TUSB_CDC_H__ +#define _TUSB_CDC_H__ + +#include "common/tusb_common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** \defgroup ClassDriver_CDC_Common Common Definitions + * @{ */ + +// TODO remove +/// CDC Pipe ID, used to indicate which pipe the API is addressing to (Notification, Out, In) +typedef enum +{ + CDC_PIPE_NOTIFICATION , ///< Notification pipe + CDC_PIPE_DATA_IN , ///< Data in pipe + CDC_PIPE_DATA_OUT , ///< Data out pipe + CDC_PIPE_ERROR , ///< Invalid Pipe ID +}cdc_pipeid_t; + +//--------------------------------------------------------------------+ +// CDC Communication Interface Class +//--------------------------------------------------------------------+ + +/// Communication Interface Subclass Codes +typedef enum +{ + CDC_COMM_SUBCLASS_DIRECT_LINE_CONTROL_MODEL = 0x01 , ///< Direct Line Control Model [USBPSTN1.2] + CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL = 0x02 , ///< Abstract Control Model [USBPSTN1.2] + CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL = 0x03 , ///< Telephone Control Model [USBPSTN1.2] + CDC_COMM_SUBCLASS_MULTICHANNEL_CONTROL_MODEL = 0x04 , ///< Multi-Channel Control Model [USBISDN1.2] + CDC_COMM_SUBCLASS_CAPI_CONTROL_MODEL = 0x05 , ///< CAPI Control Model [USBISDN1.2] + CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL = 0x06 , ///< Ethernet Networking Control Model [USBECM1.2] + CDC_COMM_SUBCLASS_ATM_NETWORKING_CONTROL_MODEL = 0x07 , ///< ATM Networking Control Model [USBATM1.2] + CDC_COMM_SUBCLASS_WIRELESS_HANDSET_CONTROL_MODEL = 0x08 , ///< Wireless Handset Control Model [USBWMC1.1] + CDC_COMM_SUBCLASS_DEVICE_MANAGEMENT = 0x09 , ///< Device Management [USBWMC1.1] + CDC_COMM_SUBCLASS_MOBILE_DIRECT_LINE_MODEL = 0x0A , ///< Mobile Direct Line Model [USBWMC1.1] + CDC_COMM_SUBCLASS_OBEX = 0x0B , ///< OBEX [USBWMC1.1] + CDC_COMM_SUBCLASS_ETHERNET_EMULATION_MODEL = 0x0C , ///< Ethernet Emulation Model [USBEEM1.0] + CDC_COMM_SUBCLASS_NETWORK_CONTROL_MODEL = 0x0D ///< Network Control Model [USBNCM1.0] +} cdc_comm_sublcass_type_t; + +/// Communication Interface Protocol Codes +typedef enum +{ + CDC_COMM_PROTOCOL_NONE = 0x00 , ///< No specific protocol + CDC_COMM_PROTOCOL_ATCOMMAND = 0x01 , ///< AT Commands: V.250 etc + CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101 = 0x02 , ///< AT Commands defined by PCCA-101 + CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101_AND_ANNEXO = 0x03 , ///< AT Commands defined by PCCA-101 & Annex O + CDC_COMM_PROTOCOL_ATCOMMAND_GSM_707 = 0x04 , ///< AT Commands defined by GSM 07.07 + CDC_COMM_PROTOCOL_ATCOMMAND_3GPP_27007 = 0x05 , ///< AT Commands defined by 3GPP 27.007 + CDC_COMM_PROTOCOL_ATCOMMAND_CDMA = 0x06 , ///< AT Commands defined by TIA for CDMA + CDC_COMM_PROTOCOL_ETHERNET_EMULATION_MODEL = 0x07 ///< Ethernet Emulation Model +} cdc_comm_protocol_type_t; + +//------------- SubType Descriptor in COMM Functional Descriptor -------------// +/// Communication Interface SubType Descriptor +typedef enum +{ + CDC_FUNC_DESC_HEADER = 0x00 , ///< Header Functional Descriptor, which marks the beginning of the concatenated set of functional descriptors for the interface. + CDC_FUNC_DESC_CALL_MANAGEMENT = 0x01 , ///< Call Management Functional Descriptor. + CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT = 0x02 , ///< Abstract Control Management Functional Descriptor. + CDC_FUNC_DESC_DIRECT_LINE_MANAGEMENT = 0x03 , ///< Direct Line Management Functional Descriptor. + CDC_FUNC_DESC_TELEPHONE_RINGER = 0x04 , ///< Telephone Ringer Functional Descriptor. + CDC_FUNC_DESC_TELEPHONE_CALL_AND_LINE_STATE_REPORTING_CAPACITY = 0x05 , ///< Telephone Call and Line State Reporting Capabilities Functional Descriptor. + CDC_FUNC_DESC_UNION = 0x06 , ///< Union Functional Descriptor + CDC_FUNC_DESC_COUNTRY_SELECTION = 0x07 , ///< Country Selection Functional Descriptor + CDC_FUNC_DESC_TELEPHONE_OPERATIONAL_MODES = 0x08 , ///< Telephone Operational ModesFunctional Descriptor + CDC_FUNC_DESC_USB_TERMINAL = 0x09 , ///< USB Terminal Functional Descriptor + CDC_FUNC_DESC_NETWORK_CHANNEL_TERMINAL = 0x0A , ///< Network Channel Terminal Descriptor + CDC_FUNC_DESC_PROTOCOL_UNIT = 0x0B , ///< Protocol Unit Functional Descriptor + CDC_FUNC_DESC_EXTENSION_UNIT = 0x0C , ///< Extension Unit Functional Descriptor + CDC_FUNC_DESC_MULTICHANEL_MANAGEMENT = 0x0D , ///< Multi-Channel Management Functional Descriptor + CDC_FUNC_DESC_CAPI_CONTROL_MANAGEMENT = 0x0E , ///< CAPI Control Management Functional Descriptor + CDC_FUNC_DESC_ETHERNET_NETWORKING = 0x0F , ///< Ethernet Networking Functional Descriptor + CDC_FUNC_DESC_ATM_NETWORKING = 0x10 , ///< ATM Networking Functional Descriptor + CDC_FUNC_DESC_WIRELESS_HANDSET_CONTROL_MODEL = 0x11 , ///< Wireless Handset Control Model Functional Descriptor + CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL = 0x12 , ///< Mobile Direct Line Model Functional Descriptor + CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL_DETAIL = 0x13 , ///< MDLM Detail Functional Descriptor + CDC_FUNC_DESC_DEVICE_MANAGEMENT_MODEL = 0x14 , ///< Device Management Model Functional Descriptor + CDC_FUNC_DESC_OBEX = 0x15 , ///< OBEX Functional Descriptor + CDC_FUNC_DESC_COMMAND_SET = 0x16 , ///< Command Set Functional Descriptor + CDC_FUNC_DESC_COMMAND_SET_DETAIL = 0x17 , ///< Command Set Detail Functional Descriptor + CDC_FUNC_DESC_TELEPHONE_CONTROL_MODEL = 0x18 , ///< Telephone Control Model Functional Descriptor + CDC_FUNC_DESC_OBEX_SERVICE_IDENTIFIER = 0x19 , ///< OBEX Service Identifier Functional Descriptor + CDC_FUNC_DESC_NCM = 0x1A , ///< NCM Functional Descriptor +}cdc_func_desc_type_t; + +//--------------------------------------------------------------------+ +// CDC Data Interface Class +//--------------------------------------------------------------------+ + +// SUBCLASS code of Data Interface is not used and should/must be zero + +// Data Interface Protocol Codes +typedef enum{ + CDC_DATA_PROTOCOL_ISDN_BRI = 0x30, ///< Physical interface protocol for ISDN BRI + CDC_DATA_PROTOCOL_HDLC = 0x31, ///< HDLC + CDC_DATA_PROTOCOL_TRANSPARENT = 0x32, ///< Transparent + CDC_DATA_PROTOCOL_Q921_MANAGEMENT = 0x50, ///< Management protocol for Q.921 data link protocol + CDC_DATA_PROTOCOL_Q921_DATA_LINK = 0x51, ///< Data link protocol for Q.931 + CDC_DATA_PROTOCOL_Q921_TEI_MULTIPLEXOR = 0x52, ///< TEI-multiplexor for Q.921 data link protocol + CDC_DATA_PROTOCOL_V42BIS_DATA_COMPRESSION = 0x90, ///< Data compression procedures + CDC_DATA_PROTOCOL_EURO_ISDN = 0x91, ///< Euro-ISDN protocol control + CDC_DATA_PROTOCOL_V24_RATE_ADAPTION_TO_ISDN = 0x92, ///< V.24 rate adaptation to ISDN + CDC_DATA_PROTOCOL_CAPI_COMMAND = 0x93, ///< CAPI Commands + CDC_DATA_PROTOCOL_HOST_BASED_DRIVER = 0xFD, ///< Host based driver. Note: This protocol code should only be used in messages between host and device to identify the host driver portion of a protocol stack. + CDC_DATA_PROTOCOL_IN_PROTOCOL_UNIT_FUNCTIONAL_DESCRIPTOR = 0xFE ///< The protocol(s) are described using a ProtocolUnit Functional Descriptors on Communications Class Interface +}cdc_data_protocol_type_t; + +//--------------------------------------------------------------------+ +// Management Element Request (Control Endpoint) +//--------------------------------------------------------------------+ + +/// Communication Interface Management Element Request Codes +typedef enum +{ + CDC_REQUEST_SEND_ENCAPSULATED_COMMAND = 0x00, ///< is used to issue a command in the format of the supported control protocol of the Communications Class interface + CDC_REQUEST_GET_ENCAPSULATED_RESPONSE = 0x01, ///< is used to request a response in the format of the supported control protocol of the Communications Class interface. + CDC_REQUEST_SET_COMM_FEATURE = 0x02, + CDC_REQUEST_GET_COMM_FEATURE = 0x03, + CDC_REQUEST_CLEAR_COMM_FEATURE = 0x04, + + CDC_REQUEST_SET_AUX_LINE_STATE = 0x10, + CDC_REQUEST_SET_HOOK_STATE = 0x11, + CDC_REQUEST_PULSE_SETUP = 0x12, + CDC_REQUEST_SEND_PULSE = 0x13, + CDC_REQUEST_SET_PULSE_TIME = 0x14, + CDC_REQUEST_RING_AUX_JACK = 0x15, + + CDC_REQUEST_SET_LINE_CODING = 0x20, + CDC_REQUEST_GET_LINE_CODING = 0x21, + CDC_REQUEST_SET_CONTROL_LINE_STATE = 0x22, + CDC_REQUEST_SEND_BREAK = 0x23, + + CDC_REQUEST_SET_RINGER_PARMS = 0x30, + CDC_REQUEST_GET_RINGER_PARMS = 0x31, + CDC_REQUEST_SET_OPERATION_PARMS = 0x32, + CDC_REQUEST_GET_OPERATION_PARMS = 0x33, + CDC_REQUEST_SET_LINE_PARMS = 0x34, + CDC_REQUEST_GET_LINE_PARMS = 0x35, + CDC_REQUEST_DIAL_DIGITS = 0x36, + CDC_REQUEST_SET_UNIT_PARAMETER = 0x37, + CDC_REQUEST_GET_UNIT_PARAMETER = 0x38, + CDC_REQUEST_CLEAR_UNIT_PARAMETER = 0x39, + CDC_REQUEST_GET_PROFILE = 0x3A, + + CDC_REQUEST_SET_ETHERNET_MULTICAST_FILTERS = 0x40, + CDC_REQUEST_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x41, + CDC_REQUEST_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x42, + CDC_REQUEST_SET_ETHERNET_PACKET_FILTER = 0x43, + CDC_REQUEST_GET_ETHERNET_STATISTIC = 0x44, + + CDC_REQUEST_SET_ATM_DATA_FORMAT = 0x50, + CDC_REQUEST_GET_ATM_DEVICE_STATISTICS = 0x51, + CDC_REQUEST_SET_ATM_DEFAULT_VC = 0x52, + CDC_REQUEST_GET_ATM_VC_STATISTICS = 0x53, + + CDC_REQUEST_MDLM_SEMANTIC_MODEL = 0x60, +}cdc_management_request_t; + +//--------------------------------------------------------------------+ +// Management Elemenent Notification (Notification Endpoint) +//--------------------------------------------------------------------+ + +/// 6.3 Notification Codes +typedef enum +{ + CDC_NOTIF_NETWORK_CONNECTION = 0x00, ///< This notification allows the device to notify the host about network connection status. + CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request. + CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08, + CDC_NOTIF_RING_DETECT = 0x09, + CDC_NOTIF_SERIAL_STATE = 0x20, + CDC_NOTIF_CALL_STATE_CHANGE = 0x28, + CDC_NOTIF_LINE_STATE_CHANGE = 0x29, + CDC_NOTIF_CONNECTION_SPEED_CHANGE = 0x2A, ///< This notification allows the device to inform the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred + CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40, +}cdc_notification_request_t; + +//--------------------------------------------------------------------+ +// Class Specific Functional Descriptor (Communication Interface) +//--------------------------------------------------------------------+ + +// Start of all packed definitions for compiler without per-type packed +TU_ATTR_PACKED_BEGIN +TU_ATTR_BIT_FIELD_ORDER_BEGIN + +/// Header Functional Descriptor (Communication Interface) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUNC_DESC_ + uint16_t bcdCDC ; ///< CDC release number in Binary-Coded Decimal +}cdc_desc_func_header_t; + +/// Union Functional Descriptor (Communication Interface) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + uint8_t bControlInterface ; ///< Interface number of Communication Interface + uint8_t bSubordinateInterface ; ///< Array of Interface number of Data Interface +}cdc_desc_func_union_t; + +#define cdc_desc_func_union_n_t(no_slave)\ + struct TU_ATTR_PACKED { \ + uint8_t bLength ;\ + uint8_t bDescriptorType ;\ + uint8_t bDescriptorSubType ;\ + uint8_t bControlInterface ;\ + uint8_t bSubordinateInterface[no_slave] ;\ +} + +/// Country Selection Functional Descriptor (Communication Interface) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + uint8_t iCountryCodeRelDate ; ///< Index of a string giving the release date for the implemented ISO 3166 Country Codes. + uint16_t wCountryCode ; ///< Country code in the format as defined in [ISO3166], release date as specified inoffset 3 for the first supported country. +}cdc_desc_func_country_selection_t; + +#define cdc_desc_func_country_selection_n_t(no_country) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength ;\ + uint8_t bDescriptorType ;\ + uint8_t bDescriptorSubType ;\ + uint8_t iCountryCodeRelDate ;\ + uint16_t wCountryCode[no_country] ;\ +} + +//--------------------------------------------------------------------+ +// PUBLIC SWITCHED TELEPHONE NETWORK (PSTN) SUBCLASS +//--------------------------------------------------------------------+ + +/// \brief Call Management Functional Descriptor +/// \details This functional descriptor describes the processing of calls for the Communications Class interface. +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + + struct { + uint8_t handle_call : 1; ///< 0 - Device sends/receives call management information only over the Communications Class interface. 1 - Device can send/receive call management information over a Data Class interface. + uint8_t send_recv_call : 1; ///< 0 - Device does not handle call management itself. 1 - Device handles call management itself. + uint8_t TU_RESERVED : 6; + } bmCapabilities; + + uint8_t bDataInterface; +}cdc_desc_func_call_management_t; + +typedef struct TU_ATTR_PACKED +{ + uint8_t support_comm_request : 1; ///< Device supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature. + uint8_t support_line_request : 1; ///< Device supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State. + uint8_t support_send_break : 1; ///< Device supports the request Send_Break + uint8_t support_notification_network_connection : 1; ///< Device supports the notification Network_Connection. + uint8_t TU_RESERVED : 4; +}cdc_acm_capability_t; + +TU_VERIFY_STATIC(sizeof(cdc_acm_capability_t) == 1, "mostly problem with compiler"); + +/// Abstract Control Management Functional Descriptor +/// This functional descriptor describes the commands supported by by the Communications Class interface with SubClass code of \ref CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + cdc_acm_capability_t bmCapabilities ; +}cdc_desc_func_acm_t; + +/// \brief Direct Line Management Functional Descriptor +/// \details This functional descriptor describes the commands supported by the Communications Class interface with SubClass code of \ref CDC_FUNC_DESC_DIRECT_LINE_MANAGEMENT +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + struct { + uint8_t require_pulse_setup : 1; ///< Device requires extra Pulse_Setup request during pulse dialing sequence to disengage holding circuit. + uint8_t support_aux_request : 1; ///< Device supports the request combination of Set_Aux_Line_State, Ring_Aux_Jack, and notification Aux_Jack_Hook_State. + uint8_t support_pulse_request : 1; ///< Device supports the request combination of Pulse_Setup, Send_Pulse, and Set_Pulse_Time. + uint8_t TU_RESERVED : 5; + } bmCapabilities; +}cdc_desc_func_direct_line_management_t; + +/// \brief Telephone Ringer Functional Descriptor +/// \details The Telephone Ringer functional descriptor describes the ringer capabilities supported by the Communications Class interface, +/// with the SubClass code of \ref CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + uint8_t bRingerVolSteps ; + uint8_t bNumRingerPatterns ; +}cdc_desc_func_telephone_ringer_t; + +/// \brief Telephone Operational Modes Functional Descriptor +/// \details The Telephone Operational Modes functional descriptor describes the operational modes supported by +/// the Communications Class interface, with the SubClass code of \ref CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + struct { + uint8_t simple_mode : 1; + uint8_t standalone_mode : 1; + uint8_t computer_centric_mode : 1; + uint8_t TU_RESERVED : 5; + } bmCapabilities; +}cdc_desc_func_telephone_operational_modes_t; + +/// \brief Telephone Call and Line State Reporting Capabilities Descriptor +/// \details The Telephone Call and Line State Reporting Capabilities functional descriptor describes the abilities of a +/// telephone device to report optional call and line states. +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + struct { + uint32_t interrupted_dialtone : 1; ///< 0 : Reports only dialtone (does not differentiate between normal and interrupted dialtone). 1 : Reports interrupted dialtone in addition to normal dialtone + uint32_t ringback_busy_fastbusy : 1; ///< 0 : Reports only dialing state. 1 : Reports ringback, busy, and fast busy states. + uint32_t caller_id : 1; ///< 0 : Does not report caller ID. 1 : Reports caller ID information. + uint32_t incoming_distinctive : 1; ///< 0 : Reports only incoming ringing. 1 : Reports incoming distinctive ringing patterns. + uint32_t dual_tone_multi_freq : 1; ///< 0 : Cannot report dual tone multi-frequency (DTMF) digits input remotely over the telephone line. 1 : Can report DTMF digits input remotely over the telephone line. + uint32_t line_state_change : 1; ///< 0 : Does not support line state change notification. 1 : Does support line state change notification + uint32_t TU_RESERVED : 26; + } bmCapabilities; +}cdc_desc_func_telephone_call_state_reporting_capabilities_t; + +// TODO remove +static inline uint8_t cdc_functional_desc_typeof(uint8_t const * p_desc) +{ + return p_desc[2]; +} + +//--------------------------------------------------------------------+ +// Requests +//--------------------------------------------------------------------+ +typedef struct TU_ATTR_PACKED +{ + uint32_t bit_rate; + uint8_t stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits + uint8_t parity; ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space + uint8_t data_bits; ///< can be 5, 6, 7, 8 or 16 +} cdc_line_coding_t; + +TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct"); + +typedef struct TU_ATTR_PACKED +{ + uint16_t dte_is_present : 1; ///< Indicates to DCE if DTE is presentor not. This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR. + uint16_t half_duplex_carrier_control : 1; + uint16_t : 14; +} cdc_line_control_state_t; + +TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct"); + +TU_ATTR_PACKED_END // End of all packed definitions +TU_ATTR_BIT_FIELD_ORDER_END + +#ifdef __cplusplus + } +#endif + +#endif + +/** @} */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.c b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.c new file mode 100644 index 00000000..fab6f003 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.c @@ -0,0 +1,486 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_CDC) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "cdc_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +enum +{ + BULK_PACKET_SIZE = (TUD_OPT_HIGH_SPEED ? 512 : 64) +}; + +typedef struct +{ + uint8_t itf_num; + uint8_t ep_notif; + uint8_t ep_in; + uint8_t ep_out; + + // Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) + uint8_t line_state; + + /*------------- From this point, data is not cleared by bus reset -------------*/ + char wanted_char; + cdc_line_coding_t line_coding; + + // FIFO + tu_fifo_t rx_ff; + tu_fifo_t tx_ff; + + uint8_t rx_ff_buf[CFG_TUD_CDC_RX_BUFSIZE]; + uint8_t tx_ff_buf[CFG_TUD_CDC_TX_BUFSIZE]; + +#if CFG_FIFO_MUTEX + osal_mutex_def_t rx_ff_mutex; + osal_mutex_def_t tx_ff_mutex; +#endif + + // Endpoint Transfer buffer + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EP_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CDC_EP_BUFSIZE]; + +}cdcd_interface_t; + +#define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, wanted_char) + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +CFG_TUSB_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; + +static bool _prep_out_transaction (cdcd_interface_t* p_cdc) +{ + uint8_t const rhport = 0; + uint16_t available = tu_fifo_remaining(&p_cdc->rx_ff); + + // Prepare for incoming data but only allow what we can store in the ring buffer. + // TODO Actually we can still carry out the transfer, keeping count of received bytes + // and slowly move it to the FIFO when read(). + // This pre-check reduces endpoint claiming + TU_VERIFY(available >= sizeof(p_cdc->epout_buf)); + + // claim endpoint + TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_out)); + + // fifo can be changed before endpoint is claimed + available = tu_fifo_remaining(&p_cdc->rx_ff); + + if ( available >= sizeof(p_cdc->epout_buf) ) + { + return usbd_edpt_xfer(rhport, p_cdc->ep_out, p_cdc->epout_buf, sizeof(p_cdc->epout_buf)); + }else + { + // Release endpoint since we don't make any transfer + usbd_edpt_release(rhport, p_cdc->ep_out); + + return false; + } +} + +//--------------------------------------------------------------------+ +// APPLICATION API +//--------------------------------------------------------------------+ +bool tud_cdc_n_connected(uint8_t itf) +{ + // DTR (bit 0) active is considered as connected + return tud_ready() && tu_bit_test(_cdcd_itf[itf].line_state, 0); +} + +uint8_t tud_cdc_n_get_line_state (uint8_t itf) +{ + return _cdcd_itf[itf].line_state; +} + +void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding) +{ + (*coding) = _cdcd_itf[itf].line_coding; +} + +void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted) +{ + _cdcd_itf[itf].wanted_char = wanted; +} + + +//--------------------------------------------------------------------+ +// READ API +//--------------------------------------------------------------------+ +uint32_t tud_cdc_n_available(uint8_t itf) +{ + return tu_fifo_count(&_cdcd_itf[itf].rx_ff); +} + +uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize) +{ + cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; + uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, (uint16_t) bufsize); + _prep_out_transaction(p_cdc); + return num_read; +} + +bool tud_cdc_n_peek(uint8_t itf, uint8_t* chr) +{ + return tu_fifo_peek(&_cdcd_itf[itf].rx_ff, chr); +} + +void tud_cdc_n_read_flush (uint8_t itf) +{ + cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; + tu_fifo_clear(&p_cdc->rx_ff); + _prep_out_transaction(p_cdc); +} + +//--------------------------------------------------------------------+ +// WRITE API +//--------------------------------------------------------------------+ +uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) +{ + cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; + uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) bufsize); + + // flush if queue more than packet size + if ( tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE ) + { + tud_cdc_n_write_flush(itf); + } + + return ret; +} + +uint32_t tud_cdc_n_write_flush (uint8_t itf) +{ + cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; + + // Skip if usb is not ready yet + TU_VERIFY( tud_ready(), 0 ); + + // No data to send + if ( !tu_fifo_count(&p_cdc->tx_ff) ) return 0; + + uint8_t const rhport = 0; + + // Claim the endpoint + TU_VERIFY( usbd_edpt_claim(rhport, p_cdc->ep_in), 0 ); + + // Pull data from FIFO + uint16_t const count = tu_fifo_read_n(&p_cdc->tx_ff, p_cdc->epin_buf, sizeof(p_cdc->epin_buf)); + + if ( count ) + { + TU_ASSERT( usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 ); + return count; + }else + { + // Release endpoint since we don't make any transfer + // Note: data is dropped if terminal is not connected + usbd_edpt_release(rhport, p_cdc->ep_in); + return 0; + } +} + +uint32_t tud_cdc_n_write_available (uint8_t itf) +{ + return tu_fifo_remaining(&_cdcd_itf[itf].tx_ff); +} + +bool tud_cdc_n_write_clear (uint8_t itf) +{ + return tu_fifo_clear(&_cdcd_itf[itf].tx_ff); +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void cdcd_init(void) +{ + tu_memclr(_cdcd_itf, sizeof(_cdcd_itf)); + + for(uint8_t i=0; iwanted_char = (char) -1; + + // default line coding is : stop bit = 1, parity = none, data bits = 8 + p_cdc->line_coding.bit_rate = 115200; + p_cdc->line_coding.stop_bits = 0; + p_cdc->line_coding.parity = 0; + p_cdc->line_coding.data_bits = 8; + + // Config RX fifo + tu_fifo_config(&p_cdc->rx_ff, p_cdc->rx_ff_buf, TU_ARRAY_SIZE(p_cdc->rx_ff_buf), 1, false); + + // Config TX fifo as overwritable at initialization and will be changed to non-overwritable + // if terminal supports DTR bit. Without DTR we do not know if data is actually polled by terminal. + // In this way, the most current data is prioritized. + tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, true); + +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, osal_mutex_create(&p_cdc->rx_ff_mutex)); + tu_fifo_config_mutex(&p_cdc->tx_ff, osal_mutex_create(&p_cdc->tx_ff_mutex), NULL); +#endif + } +} + +void cdcd_reset(uint8_t rhport) +{ + (void) rhport; + + for(uint8_t i=0; irx_ff); + tu_fifo_clear(&p_cdc->tx_ff); + tu_fifo_set_overwritable(&p_cdc->tx_ff, true); + } +} + +uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + // Only support ACM subclass + TU_VERIFY( TUSB_CLASS_CDC == itf_desc->bInterfaceClass && + CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass, 0); + + // Find available interface + cdcd_interface_t * p_cdc = NULL; + for(uint8_t cdc_id=0; cdc_iditf_num = itf_desc->bInterfaceNumber; + + uint16_t drv_len = sizeof(tusb_desc_interface_t); + uint8_t const * p_desc = tu_desc_next( itf_desc ); + + // Communication Functional Descriptors + while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) + { + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + { + // notification endpoint + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; + + TU_ASSERT( usbd_edpt_open(rhport, desc_ep), 0 ); + p_cdc->ep_notif = desc_ep->bEndpointAddress; + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + //------------- Data Interface (if any) -------------// + if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && + (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) + { + // next to endpoint descriptor + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + + // Open endpoint pair + TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in), 0 ); + + drv_len += 2*sizeof(tusb_desc_endpoint_t); + } + + // Prepare for incoming data + _prep_out_transaction(p_cdc); + + return drv_len; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + // Handle class request only + TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); + + uint8_t itf = 0; + cdcd_interface_t* p_cdc = _cdcd_itf; + + // Identify which interface to use + for ( ; ; itf++, p_cdc++) + { + if (itf >= TU_ARRAY_SIZE(_cdcd_itf)) return false; + + if ( p_cdc->itf_num == request->wIndex ) break; + } + + switch ( request->bRequest ) + { + case CDC_REQUEST_SET_LINE_CODING: + if (stage == CONTROL_STAGE_SETUP) + { + TU_LOG2(" Set Line Coding\r\n"); + tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); + } + else if ( stage == CONTROL_STAGE_ACK) + { + if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding); + } + break; + + case CDC_REQUEST_GET_LINE_CODING: + if (stage == CONTROL_STAGE_SETUP) + { + TU_LOG2(" Get Line Coding\r\n"); + tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); + } + break; + + case CDC_REQUEST_SET_CONTROL_LINE_STATE: + if (stage == CONTROL_STAGE_SETUP) + { + tud_control_status(rhport, request); + } + else if (stage == CONTROL_STAGE_ACK) + { + // CDC PSTN v1.2 section 6.3.12 + // Bit 0: Indicates if DTE is present or not. + // This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR (Data Terminal Ready) + // Bit 1: Carrier control for half-duplex modems. + // This signal corresponds to V.24 signal 105 and RS-232 signal RTS (Request to Send) + bool const dtr = tu_bit_test(request->wValue, 0); + bool const rts = tu_bit_test(request->wValue, 1); + + p_cdc->line_state = (uint8_t) request->wValue; + + // Disable fifo overwriting if DTR bit is set + tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr); + + TU_LOG2(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); + + // Invoke callback + if ( tud_cdc_line_state_cb ) tud_cdc_line_state_cb(itf, dtr, rts); + } + break; + case CDC_REQUEST_SEND_BREAK: + if (stage == CONTROL_STAGE_SETUP) + { + tud_control_status(rhport, request); + } + else if (stage == CONTROL_STAGE_ACK) + { + TU_LOG2(" Send Break\r\n"); + if ( tud_cdc_send_break_cb ) tud_cdc_send_break_cb(itf, request->wValue); + } + break; + + default: return false; // stall unsupported request + } + + return true; +} + +bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) result; + + uint8_t itf; + cdcd_interface_t* p_cdc; + + // Identify which interface to use + for (itf = 0; itf < CFG_TUD_CDC; itf++) + { + p_cdc = &_cdcd_itf[itf]; + if ( ( ep_addr == p_cdc->ep_out ) || ( ep_addr == p_cdc->ep_in ) ) break; + } + TU_ASSERT(itf < CFG_TUD_CDC); + + // Received new data + if ( ep_addr == p_cdc->ep_out ) + { + tu_fifo_write_n(&p_cdc->rx_ff, &p_cdc->epout_buf, (uint16_t) xferred_bytes); + + // Check for wanted char and invoke callback if needed + if ( tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1) ) + { + for ( uint32_t i = 0; i < xferred_bytes; i++ ) + { + if ( (p_cdc->wanted_char == p_cdc->epout_buf[i]) && !tu_fifo_empty(&p_cdc->rx_ff) ) + { + tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char); + } + } + } + + // invoke receive callback (if there is still data) + if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf); + + // prepare for OUT transaction + _prep_out_transaction(p_cdc); + } + + // Data sent to host, we continue to fetch from tx fifo to send. + // Note: This will cause incorrect baudrate set in line coding. + // Though maybe the baudrate is not really important !!! + if ( ep_addr == p_cdc->ep_in ) + { + // invoke transmit callback to possibly refill tx fifo + if ( tud_cdc_tx_complete_cb ) tud_cdc_tx_complete_cb(itf); + + if ( 0 == tud_cdc_n_write_flush(itf) ) + { + // If there is no data left, a ZLP should be sent if + // xferred_bytes is multiple of EP Packet size and not zero + if ( !tu_fifo_count(&p_cdc->tx_ff) && xferred_bytes && (0 == (xferred_bytes & (BULK_PACKET_SIZE-1))) ) + { + if ( usbd_edpt_claim(rhport, p_cdc->ep_in) ) + { + usbd_edpt_xfer(rhport, p_cdc->ep_in, NULL, 0); + } + } + } + } + + // nothing to do with notif endpoint for now + + return true; +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.h b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.h new file mode 100644 index 00000000..fbc7162a --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.h @@ -0,0 +1,260 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_CDC_DEVICE_H_ +#define _TUSB_CDC_DEVICE_H_ + +#include "common/tusb_common.h" +#include "cdc.h" + +//--------------------------------------------------------------------+ +// Class Driver Configuration +//--------------------------------------------------------------------+ +#if !defined(CFG_TUD_CDC_EP_BUFSIZE) && defined(CFG_TUD_CDC_EPSIZE) + #warning CFG_TUD_CDC_EPSIZE is renamed to CFG_TUD_CDC_EP_BUFSIZE, please update to use the new name + #define CFG_TUD_CDC_EP_BUFSIZE CFG_TUD_CDC_EPSIZE +#endif + +#ifndef CFG_TUD_CDC_EP_BUFSIZE + #define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +/** \addtogroup CDC_Serial Serial + * @{ + * \defgroup CDC_Serial_Device Device + * @{ */ + +//--------------------------------------------------------------------+ +// Application API (Multiple Ports) +// CFG_TUD_CDC > 1 +//--------------------------------------------------------------------+ + +// Check if terminal is connected to this port +bool tud_cdc_n_connected (uint8_t itf); + +// Get current line state. Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) +uint8_t tud_cdc_n_get_line_state (uint8_t itf); + +// Get current line encoding: bit rate, stop bits parity etc .. +void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding); + +// Set special character that will trigger tud_cdc_rx_wanted_cb() callback on receiving +void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted); + +// Get the number of bytes available for reading +uint32_t tud_cdc_n_available (uint8_t itf); + +// Read received bytes +uint32_t tud_cdc_n_read (uint8_t itf, void* buffer, uint32_t bufsize); + +// Read a byte, return -1 if there is none +static inline +int32_t tud_cdc_n_read_char (uint8_t itf); + +// Clear the received FIFO +void tud_cdc_n_read_flush (uint8_t itf); + +// Get a byte from FIFO at the specified position without removing it +bool tud_cdc_n_peek (uint8_t itf, uint8_t* ui8); + +// Write bytes to TX FIFO, data may remain in the FIFO for a while +uint32_t tud_cdc_n_write (uint8_t itf, void const* buffer, uint32_t bufsize); + +// Write a byte +static inline +uint32_t tud_cdc_n_write_char (uint8_t itf, char ch); + +// Write a null-terminated string +static inline +uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str); + +// Force sending data if possible, return number of forced bytes +uint32_t tud_cdc_n_write_flush (uint8_t itf); + +// Return the number of bytes (characters) available for writing to TX FIFO buffer in a single n_write operation. +uint32_t tud_cdc_n_write_available (uint8_t itf); + +// Clear the transmit FIFO +bool tud_cdc_n_write_clear (uint8_t itf); + +//--------------------------------------------------------------------+ +// Application API (Single Port) +//--------------------------------------------------------------------+ +static inline bool tud_cdc_connected (void); +static inline uint8_t tud_cdc_get_line_state (void); +static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding); +static inline void tud_cdc_set_wanted_char (char wanted); + +static inline uint32_t tud_cdc_available (void); +static inline int32_t tud_cdc_read_char (void); +static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize); +static inline void tud_cdc_read_flush (void); +static inline bool tud_cdc_peek (uint8_t* ui8); + +static inline uint32_t tud_cdc_write_char (char ch); +static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize); +static inline uint32_t tud_cdc_write_str (char const* str); +static inline uint32_t tud_cdc_write_flush (void); +static inline uint32_t tud_cdc_write_available (void); +static inline bool tud_cdc_write_clear (void); + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ + +// Invoked when received new data +TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf); + +// Invoked when received `wanted_char` +TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char); + +// Invoked when space becomes available in TX buffer +TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf); + +// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE +TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts); + +// Invoked when line coding is change via SET_LINE_CODING +TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding); + +// Invoked when received send break +TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms); + +//--------------------------------------------------------------------+ +// Inline Functions +//--------------------------------------------------------------------+ +static inline int32_t tud_cdc_n_read_char (uint8_t itf) +{ + uint8_t ch; + return tud_cdc_n_read(itf, &ch, 1) ? (int32_t) ch : -1; +} + +static inline uint32_t tud_cdc_n_write_char(uint8_t itf, char ch) +{ + return tud_cdc_n_write(itf, &ch, 1); +} + +static inline uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str) +{ + return tud_cdc_n_write(itf, str, strlen(str)); +} + +static inline bool tud_cdc_connected (void) +{ + return tud_cdc_n_connected(0); +} + +static inline uint8_t tud_cdc_get_line_state (void) +{ + return tud_cdc_n_get_line_state(0); +} + +static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding) +{ + tud_cdc_n_get_line_coding(0, coding); +} + +static inline void tud_cdc_set_wanted_char (char wanted) +{ + tud_cdc_n_set_wanted_char(0, wanted); +} + +static inline uint32_t tud_cdc_available (void) +{ + return tud_cdc_n_available(0); +} + +static inline int32_t tud_cdc_read_char (void) +{ + return tud_cdc_n_read_char(0); +} + +static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize) +{ + return tud_cdc_n_read(0, buffer, bufsize); +} + +static inline void tud_cdc_read_flush (void) +{ + tud_cdc_n_read_flush(0); +} + +static inline bool tud_cdc_peek (uint8_t* ui8) +{ + return tud_cdc_n_peek(0, ui8); +} + +static inline uint32_t tud_cdc_write_char (char ch) +{ + return tud_cdc_n_write_char(0, ch); +} + +static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize) +{ + return tud_cdc_n_write(0, buffer, bufsize); +} + +static inline uint32_t tud_cdc_write_str (char const* str) +{ + return tud_cdc_n_write_str(0, str); +} + +static inline uint32_t tud_cdc_write_flush (void) +{ + return tud_cdc_n_write_flush(0); +} + +static inline uint32_t tud_cdc_write_available(void) +{ + return tud_cdc_n_write_available(0); +} + +static inline bool tud_cdc_write_clear(void) +{ + return tud_cdc_n_write_clear(0); +} + +/** @} */ +/** @} */ + +//--------------------------------------------------------------------+ +// INTERNAL USBD-CLASS DRIVER API +//--------------------------------------------------------------------+ +void cdcd_init (void); +void cdcd_reset (uint8_t rhport); +uint16_t cdcd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool cdcd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +bool cdcd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CDC_DEVICE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.c b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.c new file mode 100644 index 00000000..ee824cb4 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.c @@ -0,0 +1,260 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUH_ENABLED && CFG_TUH_CDC) + +#include "host/usbh.h" +#include "host/usbh_classdriver.h" + +#include "cdc_host.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +typedef struct { + uint8_t itf_num; + uint8_t itf_protocol; + + uint8_t ep_notif; + uint8_t ep_in; + uint8_t ep_out; + + cdc_acm_capability_t acm_capability; + +} cdch_data_t; + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +static cdch_data_t cdch_data[CFG_TUH_DEVICE_MAX]; + +static inline cdch_data_t* get_itf(uint8_t dev_addr) +{ + return &cdch_data[dev_addr-1]; +} + +bool tuh_cdc_mounted(uint8_t dev_addr) +{ + cdch_data_t* cdc = get_itf(dev_addr); + return cdc->ep_in && cdc->ep_out; +} + +bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid) +{ + if ( !tuh_cdc_mounted(dev_addr) ) return false; + + cdch_data_t const * p_cdc = get_itf(dev_addr); + + switch (pipeid) + { + case CDC_PIPE_NOTIFICATION: + return usbh_edpt_busy(dev_addr, p_cdc->ep_notif ); + + case CDC_PIPE_DATA_IN: + return usbh_edpt_busy(dev_addr, p_cdc->ep_in ); + + case CDC_PIPE_DATA_OUT: + return usbh_edpt_busy(dev_addr, p_cdc->ep_out ); + + default: + return false; + } +} + +//--------------------------------------------------------------------+ +// APPLICATION API (parameter validation needed) +//--------------------------------------------------------------------+ +bool tuh_cdc_serial_is_mounted(uint8_t dev_addr) +{ + // TODO consider all AT Command as serial candidate + return tuh_cdc_mounted(dev_addr) && + (cdch_data[dev_addr-1].itf_protocol <= CDC_COMM_PROTOCOL_ATCOMMAND_CDMA); +} + +bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify) +{ + (void) is_notify; + TU_VERIFY( tuh_cdc_mounted(dev_addr) ); + TU_VERIFY( p_data != NULL && length); + + uint8_t const ep_out = cdch_data[dev_addr-1].ep_out; + if ( usbh_edpt_busy(dev_addr, ep_out) ) return false; + + return usbh_edpt_xfer(dev_addr, ep_out, (void*)(uintptr_t) p_data, (uint16_t) length); +} + +bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify) +{ + (void) is_notify; + TU_VERIFY( tuh_cdc_mounted(dev_addr) ); + TU_VERIFY( p_buffer != NULL && length ); + + uint8_t const ep_in = cdch_data[dev_addr-1].ep_in; + if ( usbh_edpt_busy(dev_addr, ep_in) ) return false; + + return usbh_edpt_xfer(dev_addr, ep_in, p_buffer, (uint16_t) length); +} + +bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb) +{ + cdch_data_t const * p_cdc = get_itf(dev_addr); + + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, + .wValue = tu_htole16((uint16_t) ((dtr ? 1u : 0u) | (rts ? 2u : 0u))), + .wIndex = tu_htole16(p_cdc->itf_num), + .wLength = 0 + }; + + tuh_xfer_t xfer = + { + .daddr = dev_addr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb, + .user_data = 0 + }; + + return tuh_control_xfer(&xfer); +} + +//--------------------------------------------------------------------+ +// USBH-CLASS DRIVER API +//--------------------------------------------------------------------+ +void cdch_init(void) +{ + tu_memclr(cdch_data, sizeof(cdch_data)); +} + +bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) +{ + (void) rhport; + (void) max_len; + + // Only support ACM subclass + // Protocol 0xFF can be RNDIS device for windows XP + TU_VERIFY( TUSB_CLASS_CDC == itf_desc->bInterfaceClass && + CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass && + 0xFF != itf_desc->bInterfaceProtocol); + + cdch_data_t * p_cdc = get_itf(dev_addr); + + p_cdc->itf_num = itf_desc->bInterfaceNumber; + p_cdc->itf_protocol = itf_desc->bInterfaceProtocol; + + //------------- Communication Interface -------------// + uint16_t drv_len = tu_desc_len(itf_desc); + uint8_t const * p_desc = tu_desc_next(itf_desc); + + // Communication Functional Descriptors + while( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) + { + if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) ) + { + // save ACM bmCapabilities + p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities; + } + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + { + // notification endpoint + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; + + TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) ); + p_cdc->ep_notif = desc_ep->bEndpointAddress; + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + //------------- Data Interface (if any) -------------// + if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && + (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) + { + // next to endpoint descriptor + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + + // data endpoints expected to be in pairs + for(uint32_t i=0; i<2; i++) + { + tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; + TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); + + TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); + + if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) + { + p_cdc->ep_in = desc_ep->bEndpointAddress; + }else + { + p_cdc->ep_out = desc_ep->bEndpointAddress; + } + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next( p_desc ); + } + } + + return true; +} + +bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num) +{ + (void) dev_addr; (void) itf_num; + return true; +} + +bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +{ + (void) ep_addr; + tuh_cdc_xfer_isr( dev_addr, event, 0, xferred_bytes ); + return true; +} + +void cdch_close(uint8_t dev_addr) +{ + TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); + + cdch_data_t * p_cdc = get_itf(dev_addr); + tu_memclr(p_cdc, sizeof(cdch_data_t)); +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.h b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.h new file mode 100644 index 00000000..33dbd2ef --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.h @@ -0,0 +1,134 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_CDC_HOST_H_ +#define _TUSB_CDC_HOST_H_ + +#include "cdc.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// CDC APPLICATION PUBLIC API +//--------------------------------------------------------------------+ +/** \ingroup ClassDriver_CDC Communication Device Class (CDC) + * \addtogroup CDC_Serial Serial + * @{ + * \defgroup CDC_Serial_Host Host + * @{ */ + +bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb); + +static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb) +{ + return tuh_cdc_set_control_line_state(dev_addr, true, true, complete_cb); +} + +static inline bool tuh_cdc_disconnect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb) +{ + return tuh_cdc_set_control_line_state(dev_addr, false, false, complete_cb); +} + +/** \brief Check if device support CDC Serial interface or not + * \param[in] dev_addr device address + * \retval true if device supports + * \retval false if device does not support or is not mounted + */ +bool tuh_cdc_serial_is_mounted(uint8_t dev_addr); + +/** \brief Check if the interface is currently busy or not + * \param[in] dev_addr device address + * \param[in] pipeid value from \ref cdc_pipeid_t to indicate target pipe. + * \retval true if the interface is busy, meaning the stack is still transferring/waiting data from/to device + * \retval false if the interface is not busy, meaning the stack successfully transferred data from/to device + * \note This function is used to check if previous transfer is complete (success or error), so that the next transfer + * can be scheduled. User needs to make sure the corresponding interface is mounted + * (by \ref tuh_cdc_serial_is_mounted) before calling this function. + */ +bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid); + +/** \brief Perform USB OUT transfer to device + * \param[in] dev_addr device address + * \param[in] p_data Buffer containing data. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION) + * \param[in] length Number of bytes to be transferred via USB bus + * \retval TUSB_ERROR_NONE on success + * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device + * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request) + * \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct + * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the + * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION. + */ +bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify); + +/** \brief Perform USB IN transfer to get data from device + * \param[in] dev_addr device address + * \param[in] p_buffer Buffer containing received data. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION) + * \param[in] length Number of bytes to be transferred via USB bus + * \retval TUSB_ERROR_NONE on success + * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device + * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request) + * \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct + * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the + * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION. + */ +bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify); + +//--------------------------------------------------------------------+ +// CDC APPLICATION CALLBACKS +//--------------------------------------------------------------------+ + +/** \brief Callback function that is invoked when an transferring event occurred + * \param[in] dev_addr Address of device + * \param[in] event an value from \ref xfer_result_t + * \param[in] pipe_id value from \ref cdc_pipeid_t indicate the pipe + * \param[in] xferred_bytes Number of bytes transferred via USB bus + * \note event can be one of following + * - XFER_RESULT_SUCCESS : previously scheduled transfer completes successfully. + * - XFER_RESULT_FAILED : previously scheduled transfer encountered a transaction error. + * - XFER_RESULT_STALLED : previously scheduled transfer is stalled by device. + * \note + */ +void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes); + +/// @} // group CDC_Serial_Host +/// @} + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void cdch_init (void); +bool cdch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); +bool cdch_set_config (uint8_t dev_addr, uint8_t itf_num); +bool cdch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); +void cdch_close (uint8_t dev_addr); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CDC_HOST_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis.h b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis.h new file mode 100644 index 00000000..e0f129fe --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis.h @@ -0,0 +1,301 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup ClassDriver_CDC Communication Device Class (CDC) + * \defgroup CDC_RNDIS Remote Network Driver Interface Specification (RNDIS) + * @{ + * \defgroup CDC_RNDIS_Common Common Definitions + * @{ */ + +#ifndef _TUSB_CDC_RNDIS_H_ +#define _TUSB_CDC_RNDIS_H_ + +#include "cdc.h" + +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef __CC_ARM +#pragma diag_suppress 66 // Suppress Keil warnings #66-D: enumeration value is out of "int" range +#endif + +/// RNDIS Message Types +typedef enum +{ + RNDIS_MSG_PACKET = 0x00000001UL, ///< The host and device use this to send network data to one another. + + RNDIS_MSG_INITIALIZE = 0x00000002UL, ///< Sent by the host to initialize the device. + RNDIS_MSG_INITIALIZE_CMPLT = 0x80000002UL, ///< Device response to an initialize message. + + RNDIS_MSG_HALT = 0x00000003UL, ///< Sent by the host to halt the device. This does not have a response. It is optional for the device to send this message to the host. + + RNDIS_MSG_QUERY = 0x00000004UL, ///< Sent by the host to send a query OID. + RNDIS_MSG_QUERY_CMPLT = 0x80000004UL, ///< Device response to a query OID. + + RNDIS_MSG_SET = 0x00000005UL, ///< Sent by the host to send a set OID. + RNDIS_MSG_SET_CMPLT = 0x80000005UL, ///< Device response to a set OID. + + RNDIS_MSG_RESET = 0x00000006UL, ///< Sent by the host to perform a soft reset on the device. + RNDIS_MSG_RESET_CMPLT = 0x80000006UL, ///< Device response to reset message. + + RNDIS_MSG_INDICATE_STATUS = 0x00000007UL, ///< Sent by the device to indicate its status or an error when an unrecognized message is received. + + RNDIS_MSG_KEEP_ALIVE = 0x00000008UL, ///< During idle periods, sent every few seconds by the host to check that the device is still responsive. It is optional for the device to send this message to check if the host is active. + RNDIS_MSG_KEEP_ALIVE_CMPLT = 0x80000008UL ///< The device response to a keepalivemessage. The host can respond with this message to a keepalive message from the device when the device implements the optional KeepAliveTimer. +}rndis_msg_type_t; + +/// RNDIS Message Status Values +typedef enum +{ + RNDIS_STATUS_SUCCESS = 0x00000000UL, ///< Success + RNDIS_STATUS_FAILURE = 0xC0000001UL, ///< Unspecified error + RNDIS_STATUS_INVALID_DATA = 0xC0010015UL, ///< Invalid data error + RNDIS_STATUS_NOT_SUPPORTED = 0xC00000BBUL, ///< Unsupported request error + RNDIS_STATUS_MEDIA_CONNECT = 0x4001000BUL, ///< Device is connected to a network medium. + RNDIS_STATUS_MEDIA_DISCONNECT = 0x4001000CUL ///< Device is disconnected from the medium. +}rndis_msg_status_t; + +#ifdef __CC_ARM +#pragma diag_default 66 // return Keil 66 to normal severity +#endif + +//--------------------------------------------------------------------+ +// MESSAGE STRUCTURE +//--------------------------------------------------------------------+ + +//------------- Initialize -------------// +/// \brief Initialize Message +/// \details This message MUST be sent by the host to initialize the device. +typedef struct { + uint32_t type ; ///< Message type, must be \ref RNDIS_MSG_INITIALIZE + uint32_t length ; ///< Message length in bytes, must be 0x18 + uint32_t request_id ; ///< A 32-bit integer value, generated by the host, used to match the host's sent request to the response from the device. + uint32_t major_version ; ///< The major version of the RNDIS Protocol implemented by the host. + uint32_t minor_version ; ///< The minor version of the RNDIS Protocol implemented by the host + uint32_t max_xfer_size ; ///< The maximum size, in bytes, of any single bus data transfer that the host expects to receive from the device. +}rndis_msg_initialize_t; + +/// \brief Initialize Complete Message +/// \details This message MUST be sent by the device in response to an initialize message. +typedef struct { + uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_INITIALIZE_CMPLT + uint32_t length ; ///< Message length in bytes, must be 0x30 + uint32_t request_id ; ///< A 32-bit integer value from \a request_id field of the \ref rndis_msg_initialize_t to which this message is a response. + uint32_t status ; ///< The initialization status of the device, has value from \ref rndis_msg_status_t + uint32_t major_version ; ///< the highest-numbered RNDIS Protocol version supported by the device. + uint32_t minor_version ; ///< the highest-numbered RNDIS Protocol version supported by the device. + uint32_t device_flags ; ///< MUST be set to 0x000000010. Other values are reserved for future use. + uint32_t medium ; ///< is 0x00 for RNDIS_MEDIUM_802_3 + uint32_t max_packet_per_xfer ; ///< The maximum number of concatenated \ref RNDIS_MSG_PACKET messages that the device can handle in a single bus transfer to it. This value MUST be at least 1. + uint32_t max_xfer_size ; ///< The maximum size, in bytes, of any single bus data transfer that the device expects to receive from the host. + uint32_t packet_alignment_factor ; ///< The byte alignment the device expects for each RNDIS message that is part of a multimessage transfer to it. The value is specified as an exponent of 2; for example, the host uses 2{PacketAlignmentFactor} as the alignment value. + uint32_t reserved[2] ; +} rndis_msg_initialize_cmplt_t; + +//------------- Query -------------// +/// \brief Query Message +/// \details This message MUST be sent by the host to query an OID. +typedef struct { + uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_QUERY + uint32_t length ; ///< Message length in bytes, including the header and the \a oid_buffer + uint32_t request_id ; ///< A 32-bit integer value, generated by the host, used to match the host's sent request to the response from the device. + uint32_t oid ; ///< The integer value of the host operating system-defined identifier, for the parameter of the device being queried for. + uint32_t buffer_length ; ///< The length, in bytes, of the input data required for the OID query. This MUST be set to 0 when there is no input data associated with the OID. + uint32_t buffer_offset ; ///< The offset, in bytes, from the beginning of \a request_id field where the input data for the query is located in the message. This value MUST be set to 0 when there is no input data associated with the OID. + uint32_t reserved ; + uint8_t oid_buffer[] ; ///< Flexible array contains the input data supplied by the host, required for the OID query request processing by the device, as per the host NDIS specification. +} rndis_msg_query_t, rndis_msg_set_t; + +TU_VERIFY_STATIC(sizeof(rndis_msg_query_t) == 28, "Make sure flexible array member does not affect layout"); + +/// \brief Query Complete Message +/// \details This message MUST be sent by the device in response to a query OID message. +typedef struct { + uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_QUERY_CMPLT + uint32_t length ; ///< Message length in bytes, including the header and the \a oid_buffer + uint32_t request_id ; ///< A 32-bit integer value from \a request_id field of the \ref rndis_msg_query_t to which this message is a response. + uint32_t status ; ///< The status of processing for the query request, has value from \ref rndis_msg_status_t. + uint32_t buffer_length ; ///< The length, in bytes, of the data in the response to the query. This MUST be set to 0 when there is no OIDInputBuffer. + uint32_t buffer_offset ; ///< The offset, in bytes, from the beginning of \a request_id field where the response data for the query is located in the message. This MUST be set to 0 when there is no \ref oid_buffer. + uint8_t oid_buffer[] ; ///< Flexible array member contains the response data to the OID query request as specified by the host. +} rndis_msg_query_cmplt_t; + +TU_VERIFY_STATIC(sizeof(rndis_msg_query_cmplt_t) == 24, "Make sure flexible array member does not affect layout"); + +//------------- Reset -------------// +/// \brief Reset Message +/// \details This message MUST be sent by the host to perform a soft reset on the device. +typedef struct { + uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_RESET + uint32_t length ; ///< Message length in bytes, MUST be 0x06 + uint32_t reserved ; +} rndis_msg_reset_t; + +/// \brief Reset Complete Message +/// \details This message MUST be sent by the device in response to a reset message. +typedef struct { + uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_RESET_CMPLT + uint32_t length ; ///< Message length in bytes, MUST be 0x10 + uint32_t status ; ///< The status of processing for the \ref rndis_msg_reset_t, has value from \ref rndis_msg_status_t. + uint32_t addressing_reset ; ///< This field indicates whether the addressing information, which is the multicast address list or packet filter, has been lost during the reset operation. This MUST be set to 0x00000001 if the device requires that the host to resend addressing information or MUST be set to zero otherwise. +} rndis_msg_reset_cmplt_t; + +//typedef struct { +// uint32_t type; +// uint32_t length; +// uint32_t status; +// uint32_t buffer_length; +// uint32_t buffer_offset; +// uint32_t diagnostic_status; // optional +// uint32_t diagnostic_error_offset; // optional +// uint32_t status_buffer[0]; // optional +//} rndis_msg_indicate_status_t; + +/// \brief Keep Alive Message +/// \details This message MUST be sent by the host to check that device is still responsive. It is optional for the device to send this message to check if the host is active +typedef struct { + uint32_t type ; ///< Message Type + uint32_t length ; ///< Message length in bytes, MUST be 0x10 + uint32_t request_id ; +} rndis_msg_keep_alive_t, rndis_msg_halt_t; + +/// \brief Set Complete Message +/// \brief This message MUST be sent in response to a the request message +typedef struct { + uint32_t type ; ///< Message Type + uint32_t length ; ///< Message length in bytes, MUST be 0x10 + uint32_t request_id ; ///< must be the same as requesting message + uint32_t status ; ///< The status of processing for the request message request by the device to which this message is the response. +} rndis_msg_set_cmplt_t, rndis_msg_keep_alive_cmplt_t; + +/// \brief Packet Data Message +/// \brief This message MUST be used by the host and the device to send network data to one another. +typedef struct { + uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_PACKET + uint32_t length ; ///< Message length in bytes, The total length of this RNDIS message including the header, payload, and padding. + uint32_t data_offset ; ///< Specifies the offset, in bytes, from the start of this \a data_offset field of this message to the start of the data. This MUST be an integer multiple of 4. + uint32_t data_length ; ///< Specifies the number of bytes in the payload of this message. + uint32_t out_of_band_data_offet ; ///< Specifies the offset, in bytes, of the first out-of-band data record from the start of the DataOffset field in this message. MUST be an integer multiple of 4 when out-of-band data is present or set to 0 otherwise. When there are multiple out-ofband data records, each subsequent record MUST immediately follow the previous out-of-band data record. + uint32_t out_of_band_data_length ; ///< Specifies, in bytes, the total length of the out-of-band data. + uint32_t num_out_of_band_data_elements ; ///< Specifies the number of out-of-band records in this message. + uint32_t per_packet_info_offset ; ///< Specifies the offset, in bytes, of the start of per-packet-info data record from the start of the \a data_offset field in this message. MUST be an integer multiple of 4 when per-packet-info data record is present or MUST be set to 0 otherwise. When there are multiple per-packet-info data records, each subsequent record MUST immediately follow the previous record. + uint32_t per_packet_info_length ; ///< Specifies, in bytes, the total length of per-packetinformation contained in this message. + uint32_t reserved[2] ; + uint32_t payload[0] ; ///< Network data contained in this message. + + // uint8_t padding[0] + // Additional bytes of zeros added at the end of the message to comply with + // the internal and external padding requirements. Internal padding SHOULD be as per the + // specification of the out-of-band data record and per-packet-info data record. The external + //padding size SHOULD be determined based on the PacketAlignmentFactor field specification + //in REMOTE_NDIS_INITIALIZE_CMPLT message by the device, when multiple + //REMOTE_NDIS_PACKET_MSG messages are bundled together in a single bus-native message. + //In this case, all but the very last REMOTE_NDIS_PACKET_MSG MUST respect the + //PacketAlignmentFactor field. + + // rndis_msg_packet_t [0] : (optional) more packet if multiple packet per bus transaction is supported +} rndis_msg_packet_t; + + +typedef struct { + uint32_t size ; ///< Length, in bytes, of this header and appended data and padding. This value MUST be an integer multiple of 4. + uint32_t type ; ///< MUST be as per host operating system specification. + uint32_t offset ; ///< The byte offset from the beginning of this record to the beginning of data. + uint32_t data[0] ; ///< Flexible array contains data +} rndis_msg_out_of_band_data_t, rndis_msg_per_packet_info_t; + +//--------------------------------------------------------------------+ +// NDIS Object ID +//--------------------------------------------------------------------+ + +/// NDIS Object ID +typedef enum +{ + //------------- General Required OIDs -------------// + RNDIS_OID_GEN_SUPPORTED_LIST = 0x00010101, ///< List of supported OIDs + RNDIS_OID_GEN_HARDWARE_STATUS = 0x00010102, ///< Hardware status + RNDIS_OID_GEN_MEDIA_SUPPORTED = 0x00010103, ///< Media types supported (encoded) + RNDIS_OID_GEN_MEDIA_IN_USE = 0x00010104, ///< Media types in use (encoded) + RNDIS_OID_GEN_MAXIMUM_LOOKAHEAD = 0x00010105, ///< + RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE = 0x00010106, ///< Maximum frame size in bytes + RNDIS_OID_GEN_LINK_SPEED = 0x00010107, ///< Link speed in units of 100 bps + RNDIS_OID_GEN_TRANSMIT_BUFFER_SPACE = 0x00010108, ///< Transmit buffer space + RNDIS_OID_GEN_RECEIVE_BUFFER_SPACE = 0x00010109, ///< Receive buffer space + RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE = 0x0001010A, ///< Minimum amount of storage, in bytes, that a single packet occupies in the transmit buffer space of the NIC + RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE = 0x0001010B, ///< Amount of storage, in bytes, that a single packet occupies in the receive buffer space of the NIC + RNDIS_OID_GEN_VENDOR_ID = 0x0001010C, ///< Vendor NIC code + RNDIS_OID_GEN_VENDOR_DESCRIPTION = 0x0001010D, ///< Vendor network card description + RNDIS_OID_GEN_CURRENT_PACKET_FILTER = 0x0001010E, ///< Current packet filter (encoded) + RNDIS_OID_GEN_CURRENT_LOOKAHEAD = 0x0001010F, ///< Current lookahead size in bytes + RNDIS_OID_GEN_DRIVER_VERSION = 0x00010110, ///< NDIS version number used by the driver + RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE = 0x00010111, ///< Maximum total packet length in bytes + RNDIS_OID_GEN_PROTOCOL_OPTIONS = 0x00010112, ///< Optional protocol flags (encoded) + RNDIS_OID_GEN_MAC_OPTIONS = 0x00010113, ///< Optional NIC flags (encoded) + RNDIS_OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114, ///< Whether the NIC is connected to the network + RNDIS_OID_GEN_MAXIMUM_SEND_PACKETS = 0x00010115, ///< The maximum number of send packets the driver can accept per call to its MiniportSendPacketsfunction + + //------------- General Optional OIDs -------------// + RNDIS_OID_GEN_VENDOR_DRIVER_VERSION = 0x00010116, ///< Vendor-assigned version number of the driver + RNDIS_OID_GEN_SUPPORTED_GUIDS = 0x00010117, ///< The custom GUIDs (Globally Unique Identifier) supported by the miniport driver + RNDIS_OID_GEN_NETWORK_LAYER_ADDRESSES = 0x00010118, ///< List of network-layer addresses associated with the binding between a transport and the driver + RNDIS_OID_GEN_TRANSPORT_HEADER_OFFSET = 0x00010119, ///< Size of packets' additional headers + RNDIS_OID_GEN_MEDIA_CAPABILITIES = 0x00010201, ///< + RNDIS_OID_GEN_PHYSICAL_MEDIUM = 0x00010202, ///< Physical media supported by the miniport driver (encoded) + + //------------- 802.3 Objects (Ethernet) -------------// + RNDIS_OID_802_3_PERMANENT_ADDRESS = 0x01010101, ///< Permanent station address + RNDIS_OID_802_3_CURRENT_ADDRESS = 0x01010102, ///< Current station address + RNDIS_OID_802_3_MULTICAST_LIST = 0x01010103, ///< Current multicast address list + RNDIS_OID_802_3_MAXIMUM_LIST_SIZE = 0x01010104, ///< Maximum size of multicast address list +} rndis_oid_type_t; + +/// RNDIS Packet Filter Bits \ref RNDIS_OID_GEN_CURRENT_PACKET_FILTER. +typedef enum +{ + RNDIS_PACKET_TYPE_DIRECTED = 0x00000001, ///< Directed packets. Directed packets contain a destination address equal to the station address of the NIC. + RNDIS_PACKET_TYPE_MULTICAST = 0x00000002, ///< Multicast address packets sent to addresses in the multicast address list. + RNDIS_PACKET_TYPE_ALL_MULTICAST = 0x00000004, ///< All multicast address packets, not just the ones enumerated in the multicast address list. + RNDIS_PACKET_TYPE_BROADCAST = 0x00000008, ///< Broadcast packets. + RNDIS_PACKET_TYPE_SOURCE_ROUTING = 0x00000010, ///< All source routing packets. If the protocol driver sets this bit, the NDIS library attempts to act as a source routing bridge. + RNDIS_PACKET_TYPE_PROMISCUOUS = 0x00000020, ///< Specifies all packets regardless of whether VLAN filtering is enabled or not and whether the VLAN identifier matches or not. + RNDIS_PACKET_TYPE_SMT = 0x00000040, ///< SMT packets that an FDDI NIC receives. + RNDIS_PACKET_TYPE_ALL_LOCAL = 0x00000080, ///< All packets sent by installed protocols and all packets indicated by the NIC that is identified by a given NdisBindingHandle. + RNDIS_PACKET_TYPE_GROUP = 0x00001000, ///< Packets sent to the current group address. + RNDIS_PACKET_TYPE_ALL_FUNCTIONAL = 0x00002000, ///< All functional address packets, not just the ones in the current functional address. + RNDIS_PACKET_TYPE_FUNCTIONAL = 0x00004000, ///< Functional address packets sent to addresses included in the current functional address. + RNDIS_PACKET_TYPE_MAC_FRAME = 0x00008000, ///< NIC driver frames that a Token Ring NIC receives. + RNDIS_PACKET_TYPE_NO_LOCAL = 0x00010000, +} rndis_packet_filter_type_t; + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CDC_RNDIS_H_ */ + +/** @} */ +/** @} */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c new file mode 100644 index 00000000..8f28f51a --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c @@ -0,0 +1,289 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUH_ENABLED && CFG_TUH_CDC && CFG_TUH_CDC_RNDIS) + +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "common/tusb_common.h" +#include "cdc_host.h" +#include "cdc_rndis_host.h" + +#if 0 // TODO remove subtask related macros later +// Sub Task +#define OSAL_SUBTASK_BEGIN +#define OSAL_SUBTASK_END return TUSB_ERROR_NONE; + +#define STASK_RETURN(_error) return _error; +#define STASK_INVOKE(_subtask, _status) (_status) = _subtask +#define STASK_ASSERT(_cond) TU_VERIFY(_cond, TUSB_ERROR_OSAL_TASK_FAILED) +#endif + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +#define RNDIS_MSG_PAYLOAD_MAX (1024*4) + +CFG_TUSB_MEM_SECTION static uint8_t msg_notification[CFG_TUH_DEVICE_MAX][8]; +CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t msg_payload[RNDIS_MSG_PAYLOAD_MAX]; + +static rndish_data_t rndish_data[CFG_TUH_DEVICE_MAX]; + +// TODO Microsoft requires message length for any get command must be at least 4096 bytes + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +static tusb_error_t rndis_body_subtask(void); +static tusb_error_t send_message_get_response_subtask( uint8_t dev_addr, cdch_data_t *p_cdc, + uint8_t * p_mess, uint32_t mess_length, + uint8_t *p_response ); + +//--------------------------------------------------------------------+ +// APPLICATION API +//--------------------------------------------------------------------+ +tusb_error_t tusbh_cdc_rndis_get_mac_addr(uint8_t dev_addr, uint8_t mac_address[6]) +{ + TU_ASSERT( tusbh_cdc_rndis_is_mounted(dev_addr), TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED); + TU_VERIFY( mac_address, TUSB_ERROR_INVALID_PARA); + + memcpy(mac_address, rndish_data[dev_addr-1].mac_address, 6); + + return TUSB_ERROR_NONE; +} + +//--------------------------------------------------------------------+ +// IMPLEMENTATION +//--------------------------------------------------------------------+ + +// To enable the TASK_ASSERT style (quick return on false condition) in a real RTOS, a task must act as a wrapper +// and is used mainly to call subtasks. Within a subtask return statement can be called freely, the task with +// forever loop cannot have any return at all. +OSAL_TASK_FUNCTION(cdch_rndis_task) (void* param;) +{ + OSAL_TASK_BEGIN + rndis_body_subtask(); + OSAL_TASK_END +} + +static tusb_error_t rndis_body_subtask(void) +{ + static uint8_t relative_addr; + + OSAL_SUBTASK_BEGIN + + for (relative_addr = 0; relative_addr < CFG_TUH_DEVICE_MAX; relative_addr++) + { + + } + + osal_task_delay(100); + + OSAL_SUBTASK_END +} + +//--------------------------------------------------------------------+ +// RNDIS-CDC Driver API +//--------------------------------------------------------------------+ +void rndish_init(void) +{ + tu_memclr(rndish_data, sizeof(rndish_data_t)*CFG_TUH_DEVICE_MAX); + + //------------- Task creation -------------// + + //------------- semaphore creation for notificaiton pipe -------------// + for(uint8_t i=0; itype == RNDIS_MSG_INITIALIZE_CMPLT && p_init_cmpt->status == RNDIS_STATUS_SUCCESS && + p_init_cmpt->max_packet_per_xfer == 1 && p_init_cmpt->max_xfer_size <= RNDIS_MSG_PAYLOAD_MAX); + rndish_data[dev_addr-1].max_xfer_size = p_init_cmpt->max_xfer_size; + + //------------- Message Query 802.3 Permanent Address -------------// + memcpy(msg_payload, &msg_query_permanent_addr, sizeof(rndis_msg_query_t)); + tu_memclr(msg_payload + sizeof(rndis_msg_query_t), 6); // 6 bytes for MAC address + + STASK_INVOKE( + send_message_get_response_subtask( dev_addr, p_cdc, + msg_payload, sizeof(rndis_msg_query_t) + 6, + msg_payload), + error + ); + if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error); + + rndis_msg_query_cmplt_t * const p_query_cmpt = (rndis_msg_query_cmplt_t *) msg_payload; + STASK_ASSERT(p_query_cmpt->type == RNDIS_MSG_QUERY_CMPLT && p_query_cmpt->status == RNDIS_STATUS_SUCCESS); + memcpy(rndish_data[dev_addr-1].mac_address, msg_payload + 8 + p_query_cmpt->buffer_offset, 6); + + //------------- Set OID_GEN_CURRENT_PACKET_FILTER to (DIRECTED | MULTICAST | BROADCAST) -------------// + memcpy(msg_payload, &msg_set_packet_filter, sizeof(rndis_msg_set_t)); + tu_memclr(msg_payload + sizeof(rndis_msg_set_t), 4); // 4 bytes for filter flags + ((rndis_msg_set_t*) msg_payload)->oid_buffer[0] = (RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_MULTICAST | RNDIS_PACKET_TYPE_BROADCAST); + + STASK_INVOKE( + send_message_get_response_subtask( dev_addr, p_cdc, + msg_payload, sizeof(rndis_msg_set_t) + 4, + msg_payload), + error + ); + if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error); + + rndis_msg_set_cmplt_t * const p_set_cmpt = (rndis_msg_set_cmplt_t *) msg_payload; + STASK_ASSERT(p_set_cmpt->type == RNDIS_MSG_SET_CMPLT && p_set_cmpt->status == RNDIS_STATUS_SUCCESS); + + tusbh_cdc_rndis_mounted_cb(dev_addr); + + OSAL_SUBTASK_END +} + +void rndish_xfer_isr(cdch_data_t *p_cdc, pipe_handle_t pipe_hdl, xfer_result_t event, uint32_t xferred_bytes) +{ + if ( pipehandle_is_equal(pipe_hdl, p_cdc->pipe_notification) ) + { + osal_semaphore_post( rndish_data[pipe_hdl.dev_addr-1].sem_notification_hdl ); + } +} + +//--------------------------------------------------------------------+ +// INTERNAL & HELPER +//--------------------------------------------------------------------+ +static tusb_error_t send_message_get_response_subtask( uint8_t dev_addr, cdch_data_t *p_cdc, + uint8_t * p_mess, uint32_t mess_length, + uint8_t *p_response) +{ + tusb_error_t error; + + OSAL_SUBTASK_BEGIN + + //------------- Send RNDIS Control Message -------------// + STASK_INVOKE( + usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_OUT, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_INTERFACE), + CDC_REQUEST_SEND_ENCAPSULATED_COMMAND, 0, p_cdc->interface_number, + mess_length, p_mess), + error + ); + if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error); + + //------------- waiting for Response Available notification -------------// + (void) usbh_edpt_xfer(p_cdc->pipe_notification, msg_notification[dev_addr-1], 8); + osal_semaphore_wait(rndish_data[dev_addr-1].sem_notification_hdl, OSAL_TIMEOUT_NORMAL, &error); + if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error); + STASK_ASSERT(msg_notification[dev_addr-1][0] == 1); + + //------------- Get RNDIS Message Initialize Complete -------------// + STASK_INVOKE( + usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_INTERFACE), + CDC_REQUEST_GET_ENCAPSULATED_RESPONSE, 0, p_cdc->interface_number, + RNDIS_MSG_PAYLOAD_MAX, p_response), + error + ); + if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error); + + OSAL_SUBTASK_END +} + +//static tusb_error_t send_process_msg_initialize_subtask(uint8_t dev_addr, cdch_data_t *p_cdc) +//{ +// tusb_error_t error; +// +// OSAL_SUBTASK_BEGIN +// +// *((rndis_msg_initialize_t*) msg_payload) = (rndis_msg_initialize_t) +// { +// .type = RNDIS_MSG_INITIALIZE, +// .length = sizeof(rndis_msg_initialize_t), +// .request_id = 1, // TODO should use some magic number +// .major_version = 1, +// .minor_version = 0, +// .max_xfer_size = 0x4000 // TODO mimic windows +// }; +// +// +// +// OSAL_SUBTASK_END +//} +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.h b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.h new file mode 100644 index 00000000..447cc4e9 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.h @@ -0,0 +1,63 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup CDC_RNDIS + * \defgroup CDC_RNSID_Host Host + * @{ */ + +#ifndef _TUSB_CDC_RNDIS_HOST_H_ +#define _TUSB_CDC_RNDIS_HOST_H_ + +#include "common/tusb_common.h" +#include "host/usbh.h" +#include "cdc_rndis.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// INTERNAL RNDIS-CDC Driver API +//--------------------------------------------------------------------+ +typedef struct { + OSAL_SEM_DEF(semaphore_notification); + osal_semaphore_handle_t sem_notification_hdl; // used to wait on notification pipe + uint32_t max_xfer_size; // got from device's msg initialize complete + uint8_t mac_address[6]; +}rndish_data_t; + +void rndish_init(void); +bool rndish_open_subtask(uint8_t dev_addr, cdch_data_t *p_cdc); +void rndish_xfer_isr(cdch_data_t *p_cdc, pipe_handle_t pipe_hdl, xfer_result_t event, uint32_t xferred_bytes); +void rndish_close(uint8_t dev_addr); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CDC_RNDIS_HOST_H_ */ + +/** @} */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu.h b/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu.h new file mode 100644 index 00000000..114c827b --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu.h @@ -0,0 +1,119 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 XMOS LIMITED + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_DFU_H_ +#define _TUSB_DFU_H_ + +#include "common/tusb_common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Common Definitions +//--------------------------------------------------------------------+ + +// DFU Protocol +typedef enum +{ + DFU_PROTOCOL_RT = 0x01, + DFU_PROTOCOL_DFU = 0x02, +} dfu_protocol_type_t; + +// DFU Descriptor Type +typedef enum +{ + DFU_DESC_FUNCTIONAL = 0x21, +} dfu_descriptor_type_t; + +// DFU Requests +typedef enum { + DFU_REQUEST_DETACH = 0, + DFU_REQUEST_DNLOAD = 1, + DFU_REQUEST_UPLOAD = 2, + DFU_REQUEST_GETSTATUS = 3, + DFU_REQUEST_CLRSTATUS = 4, + DFU_REQUEST_GETSTATE = 5, + DFU_REQUEST_ABORT = 6, +} dfu_requests_t; + +// DFU States +typedef enum { + APP_IDLE = 0, + APP_DETACH = 1, + DFU_IDLE = 2, + DFU_DNLOAD_SYNC = 3, + DFU_DNBUSY = 4, + DFU_DNLOAD_IDLE = 5, + DFU_MANIFEST_SYNC = 6, + DFU_MANIFEST = 7, + DFU_MANIFEST_WAIT_RESET = 8, + DFU_UPLOAD_IDLE = 9, + DFU_ERROR = 10, +} dfu_state_t; + +// DFU Status +typedef enum { + DFU_STATUS_OK = 0x00, + DFU_STATUS_ERR_TARGET = 0x01, + DFU_STATUS_ERR_FILE = 0x02, + DFU_STATUS_ERR_WRITE = 0x03, + DFU_STATUS_ERR_ERASE = 0x04, + DFU_STATUS_ERR_CHECK_ERASED = 0x05, + DFU_STATUS_ERR_PROG = 0x06, + DFU_STATUS_ERR_VERIFY = 0x07, + DFU_STATUS_ERR_ADDRESS = 0x08, + DFU_STATUS_ERR_NOTDONE = 0x09, + DFU_STATUS_ERR_FIRMWARE = 0x0A, + DFU_STATUS_ERR_VENDOR = 0x0B, + DFU_STATUS_ERR_USBR = 0x0C, + DFU_STATUS_ERR_POR = 0x0D, + DFU_STATUS_ERR_UNKNOWN = 0x0E, + DFU_STATUS_ERR_STALLEDPKT = 0x0F, +} dfu_status_t; + +#define DFU_ATTR_CAN_DOWNLOAD (1u << 0) +#define DFU_ATTR_CAN_UPLOAD (1u << 1) +#define DFU_ATTR_MANIFESTATION_TOLERANT (1u << 2) +#define DFU_ATTR_WILL_DETACH (1u << 3) + +// DFU Status Request Payload +typedef struct TU_ATTR_PACKED +{ + uint8_t bStatus; + uint8_t bwPollTimeout[3]; + uint8_t bState; + uint8_t iString; +} dfu_status_response_t; + +TU_VERIFY_STATIC( sizeof(dfu_status_response_t) == 6, "size is not correct"); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_DFU_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_device.c b/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_device.c new file mode 100644 index 00000000..aa5891ca --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_device.c @@ -0,0 +1,460 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 XMOS LIMITED + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_DFU) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "dfu_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +typedef struct +{ + uint8_t attrs; + uint8_t alt; + + dfu_state_t state; + dfu_status_t status; + + bool flashing_in_progress; + uint16_t block; + uint16_t length; + + CFG_TUSB_MEM_ALIGN uint8_t transfer_buf[CFG_TUD_DFU_XFER_BUFSIZE]; +} dfu_state_ctx_t; + +// Only a single dfu state is allowed +CFG_TUSB_MEM_SECTION static dfu_state_ctx_t _dfu_ctx; + +static void reset_state(void) +{ + _dfu_ctx.state = DFU_IDLE; + _dfu_ctx.status = DFU_STATUS_OK; + _dfu_ctx.flashing_in_progress = false; +} + +static bool reply_getstatus(uint8_t rhport, tusb_control_request_t const * request, dfu_state_t state, dfu_status_t status, uint32_t timeout); +static bool process_download_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + +//--------------------------------------------------------------------+ +// Debug +//--------------------------------------------------------------------+ +#if CFG_TUSB_DEBUG >= 2 + +static tu_lookup_entry_t const _dfu_request_lookup[] = +{ + { .key = DFU_REQUEST_DETACH , .data = "DETACH" }, + { .key = DFU_REQUEST_DNLOAD , .data = "DNLOAD" }, + { .key = DFU_REQUEST_UPLOAD , .data = "UPLOAD" }, + { .key = DFU_REQUEST_GETSTATUS , .data = "GETSTATUS" }, + { .key = DFU_REQUEST_CLRSTATUS , .data = "CLRSTATUS" }, + { .key = DFU_REQUEST_GETSTATE , .data = "GETSTATE" }, + { .key = DFU_REQUEST_ABORT , .data = "ABORT" }, +}; + +static tu_lookup_table_t const _dfu_request_table = +{ + .count = TU_ARRAY_SIZE(_dfu_request_lookup), + .items = _dfu_request_lookup +}; + +static tu_lookup_entry_t const _dfu_state_lookup[] = +{ + { .key = APP_IDLE , .data = "APP_IDLE" }, + { .key = APP_DETACH , .data = "APP_DETACH" }, + { .key = DFU_IDLE , .data = "IDLE" }, + { .key = DFU_DNLOAD_SYNC , .data = "DNLOAD_SYNC" }, + { .key = DFU_DNBUSY , .data = "DNBUSY" }, + { .key = DFU_DNLOAD_IDLE , .data = "DNLOAD_IDLE" }, + { .key = DFU_MANIFEST_SYNC , .data = "MANIFEST_SYNC" }, + { .key = DFU_MANIFEST , .data = "MANIFEST" }, + { .key = DFU_MANIFEST_WAIT_RESET , .data = "MANIFEST_WAIT_RESET" }, + { .key = DFU_UPLOAD_IDLE , .data = "UPLOAD_IDLE" }, + { .key = DFU_ERROR , .data = "ERROR" }, +}; + +static tu_lookup_table_t const _dfu_state_table = +{ + .count = TU_ARRAY_SIZE(_dfu_state_lookup), + .items = _dfu_state_lookup +}; + +static tu_lookup_entry_t const _dfu_status_lookup[] = +{ + { .key = DFU_STATUS_OK , .data = "OK" }, + { .key = DFU_STATUS_ERR_TARGET , .data = "errTARGET" }, + { .key = DFU_STATUS_ERR_FILE , .data = "errFILE" }, + { .key = DFU_STATUS_ERR_WRITE , .data = "errWRITE" }, + { .key = DFU_STATUS_ERR_ERASE , .data = "errERASE" }, + { .key = DFU_STATUS_ERR_CHECK_ERASED , .data = "errCHECK_ERASED" }, + { .key = DFU_STATUS_ERR_PROG , .data = "errPROG" }, + { .key = DFU_STATUS_ERR_VERIFY , .data = "errVERIFY" }, + { .key = DFU_STATUS_ERR_ADDRESS , .data = "errADDRESS" }, + { .key = DFU_STATUS_ERR_NOTDONE , .data = "errNOTDONE" }, + { .key = DFU_STATUS_ERR_FIRMWARE , .data = "errFIRMWARE" }, + { .key = DFU_STATUS_ERR_VENDOR , .data = "errVENDOR" }, + { .key = DFU_STATUS_ERR_USBR , .data = "errUSBR" }, + { .key = DFU_STATUS_ERR_POR , .data = "errPOR" }, + { .key = DFU_STATUS_ERR_UNKNOWN , .data = "errUNKNOWN" }, + { .key = DFU_STATUS_ERR_STALLEDPKT , .data = "errSTALLEDPKT" }, +}; + +static tu_lookup_table_t const _dfu_status_table = +{ + .count = TU_ARRAY_SIZE(_dfu_status_lookup), + .items = _dfu_status_lookup +}; + +#endif + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void dfu_moded_reset(uint8_t rhport) +{ + (void) rhport; + + _dfu_ctx.attrs = 0; + _dfu_ctx.alt = 0; + + reset_state(); +} + +void dfu_moded_init(void) +{ + dfu_moded_reset(0); +} + +uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + (void) rhport; + + //------------- Interface (with Alt) descriptor -------------// + uint8_t const itf_num = itf_desc->bInterfaceNumber; + uint8_t alt_count = 0; + + uint16_t drv_len = 0; + TU_VERIFY(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS && itf_desc->bInterfaceProtocol == DFU_PROTOCOL_DFU, 0); + + while(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS && itf_desc->bInterfaceProtocol == DFU_PROTOCOL_DFU) + { + TU_ASSERT(max_len > drv_len, 0); + + // Alternate must have the same interface number + TU_ASSERT(itf_desc->bInterfaceNumber == itf_num, 0); + + // Alt should increase by one every time + TU_ASSERT(itf_desc->bAlternateSetting == alt_count, 0); + alt_count++; + + drv_len += tu_desc_len(itf_desc); + itf_desc = (tusb_desc_interface_t const *) tu_desc_next(itf_desc); + } + + //------------- DFU Functional descriptor -------------// + tusb_desc_dfu_functional_t const *func_desc = (tusb_desc_dfu_functional_t const *) itf_desc; + TU_ASSERT(tu_desc_type(func_desc) == TUSB_DESC_FUNCTIONAL, 0); + drv_len += sizeof(tusb_desc_dfu_functional_t); + + _dfu_ctx.attrs = func_desc->bAttributes; + + // CFG_TUD_DFU_XFER_BUFSIZE has to be set to the buffer size used in TUD_DFU_DESCRIPTOR + uint16_t const transfer_size = tu_le16toh( tu_unaligned_read16((uint8_t const*) func_desc + offsetof(tusb_desc_dfu_functional_t, wTransferSize)) ); + TU_ASSERT(transfer_size <= CFG_TUD_DFU_XFER_BUFSIZE, drv_len); + + return drv_len; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); + + TU_LOG2(" DFU State : %s, Status: %s\r\n", tu_lookup_find(&_dfu_state_table, _dfu_ctx.state), tu_lookup_find(&_dfu_status_table, _dfu_ctx.status)); + + if ( request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD ) + { + // Standard request include GET/SET_INTERFACE + switch ( request->bRequest ) + { + case TUSB_REQ_SET_INTERFACE: + if ( stage == CONTROL_STAGE_SETUP ) + { + // Switch Alt interface and reset state machine + _dfu_ctx.alt = (uint8_t) request->wValue; + reset_state(); + return tud_control_status(rhport, request); + } + break; + + case TUSB_REQ_GET_INTERFACE: + if(stage == CONTROL_STAGE_SETUP) + { + return tud_control_xfer(rhport, request, &_dfu_ctx.alt, 1); + } + break; + + // unsupported request + default: return false; + } + } + else if ( request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS ) + { + TU_LOG2(" DFU Request: %s\r\n", tu_lookup_find(&_dfu_request_table, request->bRequest)); + + // Class request + switch ( request->bRequest ) + { + case DFU_REQUEST_DETACH: + if ( stage == CONTROL_STAGE_SETUP ) + { + tud_control_status(rhport, request); + } + else if ( stage == CONTROL_STAGE_ACK ) + { + if ( tud_dfu_detach_cb ) tud_dfu_detach_cb(); + } + break; + + case DFU_REQUEST_CLRSTATUS: + if ( stage == CONTROL_STAGE_SETUP ) + { + reset_state(); + tud_control_status(rhport, request); + } + break; + + case DFU_REQUEST_GETSTATE: + if ( stage == CONTROL_STAGE_SETUP ) + { + tud_control_xfer(rhport, request, &_dfu_ctx.state, 1); + } + break; + + case DFU_REQUEST_ABORT: + if ( stage == CONTROL_STAGE_SETUP ) + { + reset_state(); + tud_control_status(rhport, request); + } + else if ( stage == CONTROL_STAGE_ACK ) + { + if ( tud_dfu_abort_cb ) tud_dfu_abort_cb(_dfu_ctx.alt); + } + break; + + case DFU_REQUEST_UPLOAD: + if ( stage == CONTROL_STAGE_SETUP ) + { + TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_UPLOAD); + TU_VERIFY(tud_dfu_upload_cb); + TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE); + + uint16_t const xfer_len = tud_dfu_upload_cb(_dfu_ctx.alt, request->wValue, _dfu_ctx.transfer_buf, request->wLength); + + return tud_control_xfer(rhport, request, _dfu_ctx.transfer_buf, xfer_len); + } + break; + + case DFU_REQUEST_DNLOAD: + if ( stage == CONTROL_STAGE_SETUP ) + { + TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_DOWNLOAD); + TU_VERIFY(_dfu_ctx.state == DFU_IDLE || _dfu_ctx.state == DFU_DNLOAD_IDLE); + TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE); + + // set to true for both download and manifest + _dfu_ctx.flashing_in_progress = true; + + // save block and length for flashing + _dfu_ctx.block = request->wValue; + _dfu_ctx.length = request->wLength; + + if ( request->wLength ) + { + // Download with payload -> transition to DOWNLOAD SYNC + _dfu_ctx.state = DFU_DNLOAD_SYNC; + return tud_control_xfer(rhport, request, _dfu_ctx.transfer_buf, request->wLength); + } + else + { + // Download is complete -> transition to MANIFEST SYNC + _dfu_ctx.state = DFU_MANIFEST_SYNC; + return tud_control_status(rhport, request); + } + } + break; + + case DFU_REQUEST_GETSTATUS: + switch ( _dfu_ctx.state ) + { + case DFU_DNLOAD_SYNC: + return process_download_get_status(rhport, stage, request); + break; + + case DFU_MANIFEST_SYNC: + return process_manifest_get_status(rhport, stage, request); + break; + + default: + if ( stage == CONTROL_STAGE_SETUP ) return reply_getstatus(rhport, request, _dfu_ctx.state, _dfu_ctx.status, 0); + break; + } + break; + + default: return false; // stall unsupported request + } + }else + { + return false; // unsupported request + } + + return true; +} + +void tud_dfu_finish_flashing(uint8_t status) +{ + _dfu_ctx.flashing_in_progress = false; + + if ( status == DFU_STATUS_OK ) + { + if (_dfu_ctx.state == DFU_DNBUSY) + { + _dfu_ctx.state = DFU_DNLOAD_SYNC; + } + else if (_dfu_ctx.state == DFU_MANIFEST) + { + _dfu_ctx.state = (_dfu_ctx.attrs & DFU_ATTR_MANIFESTATION_TOLERANT) + ? DFU_MANIFEST_SYNC : DFU_MANIFEST_WAIT_RESET; + } + } + else + { + // failed while flashing, move to dfuError + _dfu_ctx.state = DFU_ERROR; + _dfu_ctx.status = (dfu_status_t)status; + } +} + +static bool process_download_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if ( stage == CONTROL_STAGE_SETUP ) + { + // only transition to next state on CONTROL_STAGE_ACK + dfu_state_t next_state; + uint32_t timeout; + + if ( _dfu_ctx.flashing_in_progress ) + { + next_state = DFU_DNBUSY; + timeout = tud_dfu_get_timeout_cb(_dfu_ctx.alt, (uint8_t) next_state); + } + else + { + next_state = DFU_DNLOAD_IDLE; + timeout = 0; + } + + return reply_getstatus(rhport, request, next_state, _dfu_ctx.status, timeout); + } + else if ( stage == CONTROL_STAGE_ACK ) + { + if ( _dfu_ctx.flashing_in_progress ) + { + _dfu_ctx.state = DFU_DNBUSY; + tud_dfu_download_cb(_dfu_ctx.alt, _dfu_ctx.block, _dfu_ctx.transfer_buf, _dfu_ctx.length); + }else + { + _dfu_ctx.state = DFU_DNLOAD_IDLE; + } + } + + return true; +} + +static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if ( stage == CONTROL_STAGE_SETUP ) + { + // only transition to next state on CONTROL_STAGE_ACK + dfu_state_t next_state; + uint32_t timeout; + + if ( _dfu_ctx.flashing_in_progress ) + { + next_state = DFU_MANIFEST; + timeout = tud_dfu_get_timeout_cb(_dfu_ctx.alt, next_state); + } + else + { + next_state = DFU_IDLE; + timeout = 0; + } + + return reply_getstatus(rhport, request, next_state, _dfu_ctx.status, timeout); + } + else if ( stage == CONTROL_STAGE_ACK ) + { + if ( _dfu_ctx.flashing_in_progress ) + { + _dfu_ctx.state = DFU_MANIFEST; + tud_dfu_manifest_cb(_dfu_ctx.alt); + } + else + { + _dfu_ctx.state = DFU_IDLE; + } + } + + return true; +} + +static bool reply_getstatus(uint8_t rhport, tusb_control_request_t const * request, dfu_state_t state, dfu_status_t status, uint32_t timeout) +{ + dfu_status_response_t resp; + resp.bStatus = (uint8_t) status; + resp.bwPollTimeout[0] = TU_U32_BYTE0(timeout); + resp.bwPollTimeout[1] = TU_U32_BYTE1(timeout); + resp.bwPollTimeout[2] = TU_U32_BYTE2(timeout); + resp.bState = (uint8_t) state; + resp.iString = 0; + + return tud_control_xfer(rhport, request, &resp, sizeof(dfu_status_response_t)); +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_device.h b/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_device.h new file mode 100644 index 00000000..fecf8596 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_device.h @@ -0,0 +1,98 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 XMOS LIMITED + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_DFU_DEVICE_H_ +#define _TUSB_DFU_DEVICE_H_ + +#include "dfu.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Class Driver Default Configure & Validation +//--------------------------------------------------------------------+ + +#if !defined(CFG_TUD_DFU_XFER_BUFSIZE) + #error "CFG_TUD_DFU_XFER_BUFSIZE must be defined, it has to be set to the buffer size used in TUD_DFU_DESCRIPTOR" +#endif + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + +// Must be called when the application is done with flashing started by +// tud_dfu_download_cb() and tud_dfu_manifest_cb(). +// status is DFU_STATUS_OK if successful, any other error status will cause state to enter dfuError +void tud_dfu_finish_flashing(uint8_t status); + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ + +// Note: alt is used as the partition number, in order to support multiple partitions like FLASH, EEPROM, etc. + +// Invoked right before tud_dfu_download_cb() (state=DFU_DNBUSY) or tud_dfu_manifest_cb() (state=DFU_MANIFEST) +// Application return timeout in milliseconds (bwPollTimeout) for the next download/manifest operation. +// During this period, USB host won't try to communicate with us. +uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state); + +// Invoked when received DFU_DNLOAD (wLength>0) following by DFU_GETSTATUS (state=DFU_DNBUSY) requests +// This callback could be returned before flashing op is complete (async). +// Once finished flashing, application must call tud_dfu_finish_flashing() +void tud_dfu_download_cb (uint8_t alt, uint16_t block_num, uint8_t const *data, uint16_t length); + +// Invoked when download process is complete, received DFU_DNLOAD (wLength=0) following by DFU_GETSTATUS (state=Manifest) +// Application can do checksum, or actual flashing if buffered entire image previously. +// Once finished flashing, application must call tud_dfu_finish_flashing() +void tud_dfu_manifest_cb(uint8_t alt); + +// Invoked when received DFU_UPLOAD request +// Application must populate data with up to length bytes and +// Return the number of written bytes +TU_ATTR_WEAK uint16_t tud_dfu_upload_cb(uint8_t alt, uint16_t block_num, uint8_t* data, uint16_t length); + +// Invoked when a DFU_DETACH request is received +TU_ATTR_WEAK void tud_dfu_detach_cb(void); + +// Invoked when the Host has terminated a download or upload transfer +TU_ATTR_WEAK void tud_dfu_abort_cb(uint8_t alt); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void dfu_moded_init(void); +void dfu_moded_reset(uint8_t rhport); +uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_DFU_MODE_DEVICE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c b/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c new file mode 100644 index 00000000..b9cd6096 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c @@ -0,0 +1,128 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Sylvain Munaut + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_DFU_RUNTIME) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "dfu_rt_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void dfu_rtd_init(void) +{ +} + +void dfu_rtd_reset(uint8_t rhport) +{ + (void) rhport; +} + +uint16_t dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + (void) rhport; + (void) max_len; + + // Ensure this is DFU Runtime + TU_VERIFY((itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS) && + (itf_desc->bInterfaceProtocol == DFU_PROTOCOL_RT), 0); + + uint8_t const * p_desc = tu_desc_next( itf_desc ); + uint16_t drv_len = sizeof(tusb_desc_interface_t); + + if ( TUSB_DESC_FUNCTIONAL == tu_desc_type(p_desc) ) + { + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + return drv_len; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + // nothing to do with DATA or ACK stage + if ( stage != CONTROL_STAGE_SETUP ) return true; + + TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); + + // dfu-util will try to claim the interface with SET_INTERFACE request before sending DFU request + if ( TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type && + TUSB_REQ_SET_INTERFACE == request->bRequest ) + { + tud_control_status(rhport, request); + return true; + } + + // Handle class request only from here + TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); + + switch (request->bRequest) + { + case DFU_REQUEST_DETACH: + { + TU_LOG2(" DFU RT Request: DETACH\r\n"); + tud_control_status(rhport, request); + tud_dfu_runtime_reboot_to_dfu_cb(); + } + break; + + case DFU_REQUEST_GETSTATUS: + { + TU_LOG2(" DFU RT Request: GETSTATUS\r\n"); + dfu_status_response_t resp; + // Status = OK, Poll timeout is ignored during RT, State = APP_IDLE, IString = 0 + memset(&resp, 0x00, sizeof(dfu_status_response_t)); + tud_control_xfer(rhport, request, &resp, sizeof(dfu_status_response_t)); + } + break; + + default: + { + TU_LOG2(" DFU RT Unexpected Request: %d\r\n", request->bRequest); + return false; // stall unsupported request + } + } + + return true; +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.h b/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.h new file mode 100644 index 00000000..babaa821 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.h @@ -0,0 +1,54 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Sylvain Munaut + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_DFU_RT_DEVICE_H_ +#define _TUSB_DFU_RT_DEVICE_H_ + +#include "dfu.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ +// Invoked when a DFU_DETACH request is received and bitWillDetach is set +void tud_dfu_runtime_reboot_to_dfu_cb(void); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void dfu_rtd_init(void); +void dfu_rtd_reset(uint8_t rhport); +uint16_t dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_DFU_RT_DEVICE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid.h b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid.h new file mode 100644 index 00000000..44a464be --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid.h @@ -0,0 +1,1122 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup group_class + * \defgroup ClassDriver_HID Human Interface Device (HID) + * @{ */ + +#ifndef _TUSB_HID_H_ +#define _TUSB_HID_H_ + +#include "common/tusb_common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Common Definitions +//--------------------------------------------------------------------+ +/** \defgroup ClassDriver_HID_Common Common Definitions + * @{ */ + +/// USB HID Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength; /**< Numeric expression that is the total size of the HID descriptor */ + uint8_t bDescriptorType; /**< Constant name specifying type of HID descriptor. */ + + uint16_t bcdHID; /**< Numeric expression identifying the HID Class Specification release */ + uint8_t bCountryCode; /**< Numeric expression identifying country code of the localized hardware. */ + uint8_t bNumDescriptors; /**< Numeric expression specifying the number of class descriptors */ + + uint8_t bReportType; /**< Type of HID class report. */ + uint16_t wReportLength; /**< the total size of the Report descriptor. */ +} tusb_hid_descriptor_hid_t; + +/// HID Subclass +typedef enum +{ + HID_SUBCLASS_NONE = 0, ///< No Subclass + HID_SUBCLASS_BOOT = 1 ///< Boot Interface Subclass +}hid_subclass_enum_t; + +/// HID Interface Protocol +typedef enum +{ + HID_ITF_PROTOCOL_NONE = 0, ///< None + HID_ITF_PROTOCOL_KEYBOARD = 1, ///< Keyboard + HID_ITF_PROTOCOL_MOUSE = 2 ///< Mouse +}hid_interface_protocol_enum_t; + +/// HID Descriptor Type +typedef enum +{ + HID_DESC_TYPE_HID = 0x21, ///< HID Descriptor + HID_DESC_TYPE_REPORT = 0x22, ///< Report Descriptor + HID_DESC_TYPE_PHYSICAL = 0x23 ///< Physical Descriptor +}hid_descriptor_enum_t; + +/// HID Request Report Type +typedef enum +{ + HID_REPORT_TYPE_INVALID = 0, + HID_REPORT_TYPE_INPUT, ///< Input + HID_REPORT_TYPE_OUTPUT, ///< Output + HID_REPORT_TYPE_FEATURE ///< Feature +}hid_report_type_t; + +/// HID Class Specific Control Request +typedef enum +{ + HID_REQ_CONTROL_GET_REPORT = 0x01, ///< Get Report + HID_REQ_CONTROL_GET_IDLE = 0x02, ///< Get Idle + HID_REQ_CONTROL_GET_PROTOCOL = 0x03, ///< Get Protocol + HID_REQ_CONTROL_SET_REPORT = 0x09, ///< Set Report + HID_REQ_CONTROL_SET_IDLE = 0x0a, ///< Set Idle + HID_REQ_CONTROL_SET_PROTOCOL = 0x0b ///< Set Protocol +}hid_request_enum_t; + +/// HID Local Code +typedef enum +{ + HID_LOCAL_NotSupported = 0 , ///< NotSupported + HID_LOCAL_Arabic , ///< Arabic + HID_LOCAL_Belgian , ///< Belgian + HID_LOCAL_Canadian_Bilingual , ///< Canadian_Bilingual + HID_LOCAL_Canadian_French , ///< Canadian_French + HID_LOCAL_Czech_Republic , ///< Czech_Republic + HID_LOCAL_Danish , ///< Danish + HID_LOCAL_Finnish , ///< Finnish + HID_LOCAL_French , ///< French + HID_LOCAL_German , ///< German + HID_LOCAL_Greek , ///< Greek + HID_LOCAL_Hebrew , ///< Hebrew + HID_LOCAL_Hungary , ///< Hungary + HID_LOCAL_International , ///< International + HID_LOCAL_Italian , ///< Italian + HID_LOCAL_Japan_Katakana , ///< Japan_Katakana + HID_LOCAL_Korean , ///< Korean + HID_LOCAL_Latin_American , ///< Latin_American + HID_LOCAL_Netherlands_Dutch , ///< Netherlands/Dutch + HID_LOCAL_Norwegian , ///< Norwegian + HID_LOCAL_Persian_Farsi , ///< Persian (Farsi) + HID_LOCAL_Poland , ///< Poland + HID_LOCAL_Portuguese , ///< Portuguese + HID_LOCAL_Russia , ///< Russia + HID_LOCAL_Slovakia , ///< Slovakia + HID_LOCAL_Spanish , ///< Spanish + HID_LOCAL_Swedish , ///< Swedish + HID_LOCAL_Swiss_French , ///< Swiss/French + HID_LOCAL_Swiss_German , ///< Swiss/German + HID_LOCAL_Switzerland , ///< Switzerland + HID_LOCAL_Taiwan , ///< Taiwan + HID_LOCAL_Turkish_Q , ///< Turkish-Q + HID_LOCAL_UK , ///< UK + HID_LOCAL_US , ///< US + HID_LOCAL_Yugoslavia , ///< Yugoslavia + HID_LOCAL_Turkish_F ///< Turkish-F +} hid_local_enum_t; + +// HID protocol value used by GetProtocol / SetProtocol +typedef enum +{ + HID_PROTOCOL_BOOT = 0, + HID_PROTOCOL_REPORT = 1 +} hid_protocol_mode_enum_t; + +/** @} */ + +//--------------------------------------------------------------------+ +// GAMEPAD +//--------------------------------------------------------------------+ +/** \addtogroup ClassDriver_HID_Gamepad Gamepad + * @{ */ + +/* From https://www.kernel.org/doc/html/latest/input/gamepad.html + ____________________________ __ + / [__ZL__] [__ZR__] \ | + / [__ TL __] [__ TR __] \ | Front Triggers + __/________________________________\__ __| + / _ \ | + / /\ __ (N) \ | + / || __ |MO| __ _ _ \ | Main Pad + | <===DP===> |SE| |ST| (W) -|- (E) | | + \ || ___ ___ _ / | + /\ \/ / \ / \ (S) /\ __| + / \________ | LS | ____ | RS | ________/ \ | +| / \ \___/ / \ \___/ / \ | | Control Sticks +| / \_____/ \_____/ \ | __| +| / \ | + \_____/ \_____/ + + |________|______| |______|___________| + D-Pad Left Right Action Pad + Stick Stick + + |_____________| + Menu Pad + + Most gamepads have the following features: + - Action-Pad 4 buttons in diamonds-shape (on the right side) NORTH, SOUTH, WEST and EAST. + - D-Pad (Direction-pad) 4 buttons (on the left side) that point up, down, left and right. + - Menu-Pad Different constellations, but most-times 2 buttons: SELECT - START. + - Analog-Sticks provide freely moveable sticks to control directions, Analog-sticks may also + provide a digital button if you press them. + - Triggers are located on the upper-side of the pad in vertical direction. The upper buttons + are normally named Left- and Right-Triggers, the lower buttons Z-Left and Z-Right. + - Rumble Many devices provide force-feedback features. But are mostly just simple rumble motors. + */ + +/// HID Gamepad Protocol Report. +typedef struct TU_ATTR_PACKED +{ + int8_t x; ///< Delta x movement of left analog-stick + int8_t y; ///< Delta y movement of left analog-stick + int8_t z; ///< Delta z movement of right analog-joystick + int8_t rz; ///< Delta Rz movement of right analog-joystick + int8_t rx; ///< Delta Rx movement of analog left trigger + int8_t ry; ///< Delta Ry movement of analog right trigger + uint8_t hat; ///< Buttons mask for currently pressed buttons in the DPad/hat + uint32_t buttons; ///< Buttons mask for currently pressed buttons +}hid_gamepad_report_t; + +/// Standard Gamepad Buttons Bitmap +typedef enum +{ + GAMEPAD_BUTTON_0 = TU_BIT(0), + GAMEPAD_BUTTON_1 = TU_BIT(1), + GAMEPAD_BUTTON_2 = TU_BIT(2), + GAMEPAD_BUTTON_3 = TU_BIT(3), + GAMEPAD_BUTTON_4 = TU_BIT(4), + GAMEPAD_BUTTON_5 = TU_BIT(5), + GAMEPAD_BUTTON_6 = TU_BIT(6), + GAMEPAD_BUTTON_7 = TU_BIT(7), + GAMEPAD_BUTTON_8 = TU_BIT(8), + GAMEPAD_BUTTON_9 = TU_BIT(9), + GAMEPAD_BUTTON_10 = TU_BIT(10), + GAMEPAD_BUTTON_11 = TU_BIT(11), + GAMEPAD_BUTTON_12 = TU_BIT(12), + GAMEPAD_BUTTON_13 = TU_BIT(13), + GAMEPAD_BUTTON_14 = TU_BIT(14), + GAMEPAD_BUTTON_15 = TU_BIT(15), + GAMEPAD_BUTTON_16 = TU_BIT(16), + GAMEPAD_BUTTON_17 = TU_BIT(17), + GAMEPAD_BUTTON_18 = TU_BIT(18), + GAMEPAD_BUTTON_19 = TU_BIT(19), + GAMEPAD_BUTTON_20 = TU_BIT(20), + GAMEPAD_BUTTON_21 = TU_BIT(21), + GAMEPAD_BUTTON_22 = TU_BIT(22), + GAMEPAD_BUTTON_23 = TU_BIT(23), + GAMEPAD_BUTTON_24 = TU_BIT(24), + GAMEPAD_BUTTON_25 = TU_BIT(25), + GAMEPAD_BUTTON_26 = TU_BIT(26), + GAMEPAD_BUTTON_27 = TU_BIT(27), + GAMEPAD_BUTTON_28 = TU_BIT(28), + GAMEPAD_BUTTON_29 = TU_BIT(29), + GAMEPAD_BUTTON_30 = TU_BIT(30), + GAMEPAD_BUTTON_31 = TU_BIT(31), +}hid_gamepad_button_bm_t; + +/// Standard Gamepad Buttons Naming from Linux input event codes +/// https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h +#define GAMEPAD_BUTTON_A GAMEPAD_BUTTON_0 +#define GAMEPAD_BUTTON_SOUTH GAMEPAD_BUTTON_0 + +#define GAMEPAD_BUTTON_B GAMEPAD_BUTTON_1 +#define GAMEPAD_BUTTON_EAST GAMEPAD_BUTTON_1 + +#define GAMEPAD_BUTTON_C GAMEPAD_BUTTON_2 + +#define GAMEPAD_BUTTON_X GAMEPAD_BUTTON_3 +#define GAMEPAD_BUTTON_NORTH GAMEPAD_BUTTON_3 + +#define GAMEPAD_BUTTON_Y GAMEPAD_BUTTON_4 +#define GAMEPAD_BUTTON_WEST GAMEPAD_BUTTON_4 + +#define GAMEPAD_BUTTON_Z GAMEPAD_BUTTON_5 +#define GAMEPAD_BUTTON_TL GAMEPAD_BUTTON_6 +#define GAMEPAD_BUTTON_TR GAMEPAD_BUTTON_7 +#define GAMEPAD_BUTTON_TL2 GAMEPAD_BUTTON_8 +#define GAMEPAD_BUTTON_TR2 GAMEPAD_BUTTON_9 +#define GAMEPAD_BUTTON_SELECT GAMEPAD_BUTTON_10 +#define GAMEPAD_BUTTON_START GAMEPAD_BUTTON_11 +#define GAMEPAD_BUTTON_MODE GAMEPAD_BUTTON_12 +#define GAMEPAD_BUTTON_THUMBL GAMEPAD_BUTTON_13 +#define GAMEPAD_BUTTON_THUMBR GAMEPAD_BUTTON_14 + +/// Standard Gamepad HAT/DPAD Buttons (from Linux input event codes) +typedef enum +{ + GAMEPAD_HAT_CENTERED = 0, ///< DPAD_CENTERED + GAMEPAD_HAT_UP = 1, ///< DPAD_UP + GAMEPAD_HAT_UP_RIGHT = 2, ///< DPAD_UP_RIGHT + GAMEPAD_HAT_RIGHT = 3, ///< DPAD_RIGHT + GAMEPAD_HAT_DOWN_RIGHT = 4, ///< DPAD_DOWN_RIGHT + GAMEPAD_HAT_DOWN = 5, ///< DPAD_DOWN + GAMEPAD_HAT_DOWN_LEFT = 6, ///< DPAD_DOWN_LEFT + GAMEPAD_HAT_LEFT = 7, ///< DPAD_LEFT + GAMEPAD_HAT_UP_LEFT = 8, ///< DPAD_UP_LEFT +}hid_gamepad_hat_t; + +/// @} + +//--------------------------------------------------------------------+ +// MOUSE +//--------------------------------------------------------------------+ +/** \addtogroup ClassDriver_HID_Mouse Mouse + * @{ */ + +/// Standard HID Boot Protocol Mouse Report. +typedef struct TU_ATTR_PACKED +{ + uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */ + int8_t x; /**< Current delta x movement of the mouse. */ + int8_t y; /**< Current delta y movement on the mouse. */ + int8_t wheel; /**< Current delta wheel movement on the mouse. */ + int8_t pan; // using AC Pan +} hid_mouse_report_t; + +/// Standard Mouse Buttons Bitmap +typedef enum +{ + MOUSE_BUTTON_LEFT = TU_BIT(0), ///< Left button + MOUSE_BUTTON_RIGHT = TU_BIT(1), ///< Right button + MOUSE_BUTTON_MIDDLE = TU_BIT(2), ///< Middle button + MOUSE_BUTTON_BACKWARD = TU_BIT(3), ///< Backward button, + MOUSE_BUTTON_FORWARD = TU_BIT(4), ///< Forward button, +}hid_mouse_button_bm_t; + +/// @} + +//--------------------------------------------------------------------+ +// Keyboard +//--------------------------------------------------------------------+ +/** \addtogroup ClassDriver_HID_Keyboard Keyboard + * @{ */ + +/// Standard HID Boot Protocol Keyboard Report. +typedef struct TU_ATTR_PACKED +{ + uint8_t modifier; /**< Keyboard modifier (KEYBOARD_MODIFIER_* masks). */ + uint8_t reserved; /**< Reserved for OEM use, always set to 0. */ + uint8_t keycode[6]; /**< Key codes of the currently pressed keys. */ +} hid_keyboard_report_t; + +/// Keyboard modifier codes bitmap +typedef enum +{ + KEYBOARD_MODIFIER_LEFTCTRL = TU_BIT(0), ///< Left Control + KEYBOARD_MODIFIER_LEFTSHIFT = TU_BIT(1), ///< Left Shift + KEYBOARD_MODIFIER_LEFTALT = TU_BIT(2), ///< Left Alt + KEYBOARD_MODIFIER_LEFTGUI = TU_BIT(3), ///< Left Window + KEYBOARD_MODIFIER_RIGHTCTRL = TU_BIT(4), ///< Right Control + KEYBOARD_MODIFIER_RIGHTSHIFT = TU_BIT(5), ///< Right Shift + KEYBOARD_MODIFIER_RIGHTALT = TU_BIT(6), ///< Right Alt + KEYBOARD_MODIFIER_RIGHTGUI = TU_BIT(7) ///< Right Window +}hid_keyboard_modifier_bm_t; + +typedef enum +{ + KEYBOARD_LED_NUMLOCK = TU_BIT(0), ///< Num Lock LED + KEYBOARD_LED_CAPSLOCK = TU_BIT(1), ///< Caps Lock LED + KEYBOARD_LED_SCROLLLOCK = TU_BIT(2), ///< Scroll Lock LED + KEYBOARD_LED_COMPOSE = TU_BIT(3), ///< Composition Mode + KEYBOARD_LED_KANA = TU_BIT(4) ///< Kana mode +}hid_keyboard_led_bm_t; + +/// @} + +//--------------------------------------------------------------------+ +// HID KEYCODE +//--------------------------------------------------------------------+ +#define HID_KEY_NONE 0x00 +#define HID_KEY_A 0x04 +#define HID_KEY_B 0x05 +#define HID_KEY_C 0x06 +#define HID_KEY_D 0x07 +#define HID_KEY_E 0x08 +#define HID_KEY_F 0x09 +#define HID_KEY_G 0x0A +#define HID_KEY_H 0x0B +#define HID_KEY_I 0x0C +#define HID_KEY_J 0x0D +#define HID_KEY_K 0x0E +#define HID_KEY_L 0x0F +#define HID_KEY_M 0x10 +#define HID_KEY_N 0x11 +#define HID_KEY_O 0x12 +#define HID_KEY_P 0x13 +#define HID_KEY_Q 0x14 +#define HID_KEY_R 0x15 +#define HID_KEY_S 0x16 +#define HID_KEY_T 0x17 +#define HID_KEY_U 0x18 +#define HID_KEY_V 0x19 +#define HID_KEY_W 0x1A +#define HID_KEY_X 0x1B +#define HID_KEY_Y 0x1C +#define HID_KEY_Z 0x1D +#define HID_KEY_1 0x1E +#define HID_KEY_2 0x1F +#define HID_KEY_3 0x20 +#define HID_KEY_4 0x21 +#define HID_KEY_5 0x22 +#define HID_KEY_6 0x23 +#define HID_KEY_7 0x24 +#define HID_KEY_8 0x25 +#define HID_KEY_9 0x26 +#define HID_KEY_0 0x27 +#define HID_KEY_ENTER 0x28 +#define HID_KEY_ESCAPE 0x29 +#define HID_KEY_BACKSPACE 0x2A +#define HID_KEY_TAB 0x2B +#define HID_KEY_SPACE 0x2C +#define HID_KEY_MINUS 0x2D +#define HID_KEY_EQUAL 0x2E +#define HID_KEY_BRACKET_LEFT 0x2F +#define HID_KEY_BRACKET_RIGHT 0x30 +#define HID_KEY_BACKSLASH 0x31 +#define HID_KEY_EUROPE_1 0x32 +#define HID_KEY_SEMICOLON 0x33 +#define HID_KEY_APOSTROPHE 0x34 +#define HID_KEY_GRAVE 0x35 +#define HID_KEY_COMMA 0x36 +#define HID_KEY_PERIOD 0x37 +#define HID_KEY_SLASH 0x38 +#define HID_KEY_CAPS_LOCK 0x39 +#define HID_KEY_F1 0x3A +#define HID_KEY_F2 0x3B +#define HID_KEY_F3 0x3C +#define HID_KEY_F4 0x3D +#define HID_KEY_F5 0x3E +#define HID_KEY_F6 0x3F +#define HID_KEY_F7 0x40 +#define HID_KEY_F8 0x41 +#define HID_KEY_F9 0x42 +#define HID_KEY_F10 0x43 +#define HID_KEY_F11 0x44 +#define HID_KEY_F12 0x45 +#define HID_KEY_PRINT_SCREEN 0x46 +#define HID_KEY_SCROLL_LOCK 0x47 +#define HID_KEY_PAUSE 0x48 +#define HID_KEY_INSERT 0x49 +#define HID_KEY_HOME 0x4A +#define HID_KEY_PAGE_UP 0x4B +#define HID_KEY_DELETE 0x4C +#define HID_KEY_END 0x4D +#define HID_KEY_PAGE_DOWN 0x4E +#define HID_KEY_ARROW_RIGHT 0x4F +#define HID_KEY_ARROW_LEFT 0x50 +#define HID_KEY_ARROW_DOWN 0x51 +#define HID_KEY_ARROW_UP 0x52 +#define HID_KEY_NUM_LOCK 0x53 +#define HID_KEY_KEYPAD_DIVIDE 0x54 +#define HID_KEY_KEYPAD_MULTIPLY 0x55 +#define HID_KEY_KEYPAD_SUBTRACT 0x56 +#define HID_KEY_KEYPAD_ADD 0x57 +#define HID_KEY_KEYPAD_ENTER 0x58 +#define HID_KEY_KEYPAD_1 0x59 +#define HID_KEY_KEYPAD_2 0x5A +#define HID_KEY_KEYPAD_3 0x5B +#define HID_KEY_KEYPAD_4 0x5C +#define HID_KEY_KEYPAD_5 0x5D +#define HID_KEY_KEYPAD_6 0x5E +#define HID_KEY_KEYPAD_7 0x5F +#define HID_KEY_KEYPAD_8 0x60 +#define HID_KEY_KEYPAD_9 0x61 +#define HID_KEY_KEYPAD_0 0x62 +#define HID_KEY_KEYPAD_DECIMAL 0x63 +#define HID_KEY_EUROPE_2 0x64 +#define HID_KEY_APPLICATION 0x65 +#define HID_KEY_POWER 0x66 +#define HID_KEY_KEYPAD_EQUAL 0x67 +#define HID_KEY_F13 0x68 +#define HID_KEY_F14 0x69 +#define HID_KEY_F15 0x6A +#define HID_KEY_F16 0x6B +#define HID_KEY_F17 0x6C +#define HID_KEY_F18 0x6D +#define HID_KEY_F19 0x6E +#define HID_KEY_F20 0x6F +#define HID_KEY_F21 0x70 +#define HID_KEY_F22 0x71 +#define HID_KEY_F23 0x72 +#define HID_KEY_F24 0x73 +#define HID_KEY_EXECUTE 0x74 +#define HID_KEY_HELP 0x75 +#define HID_KEY_MENU 0x76 +#define HID_KEY_SELECT 0x77 +#define HID_KEY_STOP 0x78 +#define HID_KEY_AGAIN 0x79 +#define HID_KEY_UNDO 0x7A +#define HID_KEY_CUT 0x7B +#define HID_KEY_COPY 0x7C +#define HID_KEY_PASTE 0x7D +#define HID_KEY_FIND 0x7E +#define HID_KEY_MUTE 0x7F +#define HID_KEY_VOLUME_UP 0x80 +#define HID_KEY_VOLUME_DOWN 0x81 +#define HID_KEY_LOCKING_CAPS_LOCK 0x82 +#define HID_KEY_LOCKING_NUM_LOCK 0x83 +#define HID_KEY_LOCKING_SCROLL_LOCK 0x84 +#define HID_KEY_KEYPAD_COMMA 0x85 +#define HID_KEY_KEYPAD_EQUAL_SIGN 0x86 +#define HID_KEY_KANJI1 0x87 +#define HID_KEY_KANJI2 0x88 +#define HID_KEY_KANJI3 0x89 +#define HID_KEY_KANJI4 0x8A +#define HID_KEY_KANJI5 0x8B +#define HID_KEY_KANJI6 0x8C +#define HID_KEY_KANJI7 0x8D +#define HID_KEY_KANJI8 0x8E +#define HID_KEY_KANJI9 0x8F +#define HID_KEY_LANG1 0x90 +#define HID_KEY_LANG2 0x91 +#define HID_KEY_LANG3 0x92 +#define HID_KEY_LANG4 0x93 +#define HID_KEY_LANG5 0x94 +#define HID_KEY_LANG6 0x95 +#define HID_KEY_LANG7 0x96 +#define HID_KEY_LANG8 0x97 +#define HID_KEY_LANG9 0x98 +#define HID_KEY_ALTERNATE_ERASE 0x99 +#define HID_KEY_SYSREQ_ATTENTION 0x9A +#define HID_KEY_CANCEL 0x9B +#define HID_KEY_CLEAR 0x9C +#define HID_KEY_PRIOR 0x9D +#define HID_KEY_RETURN 0x9E +#define HID_KEY_SEPARATOR 0x9F +#define HID_KEY_OUT 0xA0 +#define HID_KEY_OPER 0xA1 +#define HID_KEY_CLEAR_AGAIN 0xA2 +#define HID_KEY_CRSEL_PROPS 0xA3 +#define HID_KEY_EXSEL 0xA4 +// RESERVED 0xA5-DF +#define HID_KEY_CONTROL_LEFT 0xE0 +#define HID_KEY_SHIFT_LEFT 0xE1 +#define HID_KEY_ALT_LEFT 0xE2 +#define HID_KEY_GUI_LEFT 0xE3 +#define HID_KEY_CONTROL_RIGHT 0xE4 +#define HID_KEY_SHIFT_RIGHT 0xE5 +#define HID_KEY_ALT_RIGHT 0xE6 +#define HID_KEY_GUI_RIGHT 0xE7 + + +//--------------------------------------------------------------------+ +// REPORT DESCRIPTOR +//--------------------------------------------------------------------+ + +//------------- ITEM & TAG -------------// +#define HID_REPORT_DATA_0(data) +#define HID_REPORT_DATA_1(data) , data +#define HID_REPORT_DATA_2(data) , U16_TO_U8S_LE(data) +#define HID_REPORT_DATA_3(data) , U32_TO_U8S_LE(data) + +#define HID_REPORT_ITEM(data, tag, type, size) \ + (((tag) << 4) | ((type) << 2) | (size)) HID_REPORT_DATA_##size(data) + +// Report Item Types +enum { + RI_TYPE_MAIN = 0, + RI_TYPE_GLOBAL = 1, + RI_TYPE_LOCAL = 2 +}; + +//------------- Main Items - HID 1.11 section 6.2.2.4 -------------// + +// Report Item Main group +enum { + RI_MAIN_INPUT = 8, + RI_MAIN_OUTPUT = 9, + RI_MAIN_COLLECTION = 10, + RI_MAIN_FEATURE = 11, + RI_MAIN_COLLECTION_END = 12 +}; + +#define HID_INPUT(x) HID_REPORT_ITEM(x, RI_MAIN_INPUT , RI_TYPE_MAIN, 1) +#define HID_OUTPUT(x) HID_REPORT_ITEM(x, RI_MAIN_OUTPUT , RI_TYPE_MAIN, 1) +#define HID_COLLECTION(x) HID_REPORT_ITEM(x, RI_MAIN_COLLECTION , RI_TYPE_MAIN, 1) +#define HID_FEATURE(x) HID_REPORT_ITEM(x, RI_MAIN_FEATURE , RI_TYPE_MAIN, 1) +#define HID_COLLECTION_END HID_REPORT_ITEM(x, RI_MAIN_COLLECTION_END, RI_TYPE_MAIN, 0) + +//------------- Input, Output, Feature - HID 1.11 section 6.2.2.5 -------------// +#define HID_DATA (0<<0) +#define HID_CONSTANT (1<<0) + +#define HID_ARRAY (0<<1) +#define HID_VARIABLE (1<<1) + +#define HID_ABSOLUTE (0<<2) +#define HID_RELATIVE (1<<2) + +#define HID_WRAP_NO (0<<3) +#define HID_WRAP (1<<3) + +#define HID_LINEAR (0<<4) +#define HID_NONLINEAR (1<<4) + +#define HID_PREFERRED_STATE (0<<5) +#define HID_PREFERRED_NO (1<<5) + +#define HID_NO_NULL_POSITION (0<<6) +#define HID_NULL_STATE (1<<6) + +#define HID_NON_VOLATILE (0<<7) +#define HID_VOLATILE (1<<7) + +#define HID_BITFIELD (0<<8) +#define HID_BUFFERED_BYTES (1<<8) + +//------------- Collection Item - HID 1.11 section 6.2.2.6 -------------// +enum { + HID_COLLECTION_PHYSICAL = 0, + HID_COLLECTION_APPLICATION, + HID_COLLECTION_LOGICAL, + HID_COLLECTION_REPORT, + HID_COLLECTION_NAMED_ARRAY, + HID_COLLECTION_USAGE_SWITCH, + HID_COLLECTION_USAGE_MODIFIER +}; + +//------------- Global Items - HID 1.11 section 6.2.2.7 -------------// + +// Report Item Global group +enum { + RI_GLOBAL_USAGE_PAGE = 0, + RI_GLOBAL_LOGICAL_MIN = 1, + RI_GLOBAL_LOGICAL_MAX = 2, + RI_GLOBAL_PHYSICAL_MIN = 3, + RI_GLOBAL_PHYSICAL_MAX = 4, + RI_GLOBAL_UNIT_EXPONENT = 5, + RI_GLOBAL_UNIT = 6, + RI_GLOBAL_REPORT_SIZE = 7, + RI_GLOBAL_REPORT_ID = 8, + RI_GLOBAL_REPORT_COUNT = 9, + RI_GLOBAL_PUSH = 10, + RI_GLOBAL_POP = 11 +}; + +#define HID_USAGE_PAGE(x) HID_REPORT_ITEM(x, RI_GLOBAL_USAGE_PAGE, RI_TYPE_GLOBAL, 1) +#define HID_USAGE_PAGE_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_USAGE_PAGE, RI_TYPE_GLOBAL, n) + +#define HID_LOGICAL_MIN(x) HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MIN, RI_TYPE_GLOBAL, 1) +#define HID_LOGICAL_MIN_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MIN, RI_TYPE_GLOBAL, n) + +#define HID_LOGICAL_MAX(x) HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MAX, RI_TYPE_GLOBAL, 1) +#define HID_LOGICAL_MAX_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MAX, RI_TYPE_GLOBAL, n) + +#define HID_PHYSICAL_MIN(x) HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MIN, RI_TYPE_GLOBAL, 1) +#define HID_PHYSICAL_MIN_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MIN, RI_TYPE_GLOBAL, n) + +#define HID_PHYSICAL_MAX(x) HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MAX, RI_TYPE_GLOBAL, 1) +#define HID_PHYSICAL_MAX_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MAX, RI_TYPE_GLOBAL, n) + +#define HID_UNIT_EXPONENT(x) HID_REPORT_ITEM(x, RI_GLOBAL_UNIT_EXPONENT, RI_TYPE_GLOBAL, 1) +#define HID_UNIT_EXPONENT_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_UNIT_EXPONENT, RI_TYPE_GLOBAL, n) + +#define HID_UNIT(x) HID_REPORT_ITEM(x, RI_GLOBAL_UNIT, RI_TYPE_GLOBAL, 1) +#define HID_UNIT_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_UNIT, RI_TYPE_GLOBAL, n) + +#define HID_REPORT_SIZE(x) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_SIZE, RI_TYPE_GLOBAL, 1) +#define HID_REPORT_SIZE_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_SIZE, RI_TYPE_GLOBAL, n) + +#define HID_REPORT_ID(x) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_ID, RI_TYPE_GLOBAL, 1), +#define HID_REPORT_ID_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_ID, RI_TYPE_GLOBAL, n), + +#define HID_REPORT_COUNT(x) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_COUNT, RI_TYPE_GLOBAL, 1) +#define HID_REPORT_COUNT_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_COUNT, RI_TYPE_GLOBAL, n) + +#define HID_PUSH HID_REPORT_ITEM(x, RI_GLOBAL_PUSH, RI_TYPE_GLOBAL, 0) +#define HID_POP HID_REPORT_ITEM(x, RI_GLOBAL_POP, RI_TYPE_GLOBAL, 0) + +//------------- LOCAL ITEMS 6.2.2.8 -------------// + +enum { + RI_LOCAL_USAGE = 0, + RI_LOCAL_USAGE_MIN = 1, + RI_LOCAL_USAGE_MAX = 2, + RI_LOCAL_DESIGNATOR_INDEX = 3, + RI_LOCAL_DESIGNATOR_MIN = 4, + RI_LOCAL_DESIGNATOR_MAX = 5, + // 6 is reserved + RI_LOCAL_STRING_INDEX = 7, + RI_LOCAL_STRING_MIN = 8, + RI_LOCAL_STRING_MAX = 9, + RI_LOCAL_DELIMITER = 10, +}; + +#define HID_USAGE(x) HID_REPORT_ITEM(x, RI_LOCAL_USAGE, RI_TYPE_LOCAL, 1) +#define HID_USAGE_N(x, n) HID_REPORT_ITEM(x, RI_LOCAL_USAGE, RI_TYPE_LOCAL, n) + +#define HID_USAGE_MIN(x) HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MIN, RI_TYPE_LOCAL, 1) +#define HID_USAGE_MIN_N(x, n) HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MIN, RI_TYPE_LOCAL, n) + +#define HID_USAGE_MAX(x) HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MAX, RI_TYPE_LOCAL, 1) +#define HID_USAGE_MAX_N(x, n) HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MAX, RI_TYPE_LOCAL, n) + +//--------------------------------------------------------------------+ +// Usage Table +//--------------------------------------------------------------------+ + +/// HID Usage Table - Table 1: Usage Page Summary +enum { + HID_USAGE_PAGE_DESKTOP = 0x01, + HID_USAGE_PAGE_SIMULATE = 0x02, + HID_USAGE_PAGE_VIRTUAL_REALITY = 0x03, + HID_USAGE_PAGE_SPORT = 0x04, + HID_USAGE_PAGE_GAME = 0x05, + HID_USAGE_PAGE_GENERIC_DEVICE = 0x06, + HID_USAGE_PAGE_KEYBOARD = 0x07, + HID_USAGE_PAGE_LED = 0x08, + HID_USAGE_PAGE_BUTTON = 0x09, + HID_USAGE_PAGE_ORDINAL = 0x0a, + HID_USAGE_PAGE_TELEPHONY = 0x0b, + HID_USAGE_PAGE_CONSUMER = 0x0c, + HID_USAGE_PAGE_DIGITIZER = 0x0d, + HID_USAGE_PAGE_PID = 0x0f, + HID_USAGE_PAGE_UNICODE = 0x10, + HID_USAGE_PAGE_ALPHA_DISPLAY = 0x14, + HID_USAGE_PAGE_MEDICAL = 0x40, + HID_USAGE_PAGE_MONITOR = 0x80, //0x80 - 0x83 + HID_USAGE_PAGE_POWER = 0x84, // 0x084 - 0x87 + HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c, + HID_USAGE_PAGE_SCALE = 0x8d, + HID_USAGE_PAGE_MSR = 0x8e, + HID_USAGE_PAGE_CAMERA = 0x90, + HID_USAGE_PAGE_ARCADE = 0x91, + HID_USAGE_PAGE_VENDOR = 0xFF00 // 0xFF00 - 0xFFFF +}; + +/// HID Usage Table - Table 6: Generic Desktop Page +enum { + HID_USAGE_DESKTOP_POINTER = 0x01, + HID_USAGE_DESKTOP_MOUSE = 0x02, + HID_USAGE_DESKTOP_JOYSTICK = 0x04, + HID_USAGE_DESKTOP_GAMEPAD = 0x05, + HID_USAGE_DESKTOP_KEYBOARD = 0x06, + HID_USAGE_DESKTOP_KEYPAD = 0x07, + HID_USAGE_DESKTOP_MULTI_AXIS_CONTROLLER = 0x08, + HID_USAGE_DESKTOP_TABLET_PC_SYSTEM = 0x09, + HID_USAGE_DESKTOP_X = 0x30, + HID_USAGE_DESKTOP_Y = 0x31, + HID_USAGE_DESKTOP_Z = 0x32, + HID_USAGE_DESKTOP_RX = 0x33, + HID_USAGE_DESKTOP_RY = 0x34, + HID_USAGE_DESKTOP_RZ = 0x35, + HID_USAGE_DESKTOP_SLIDER = 0x36, + HID_USAGE_DESKTOP_DIAL = 0x37, + HID_USAGE_DESKTOP_WHEEL = 0x38, + HID_USAGE_DESKTOP_HAT_SWITCH = 0x39, + HID_USAGE_DESKTOP_COUNTED_BUFFER = 0x3a, + HID_USAGE_DESKTOP_BYTE_COUNT = 0x3b, + HID_USAGE_DESKTOP_MOTION_WAKEUP = 0x3c, + HID_USAGE_DESKTOP_START = 0x3d, + HID_USAGE_DESKTOP_SELECT = 0x3e, + HID_USAGE_DESKTOP_VX = 0x40, + HID_USAGE_DESKTOP_VY = 0x41, + HID_USAGE_DESKTOP_VZ = 0x42, + HID_USAGE_DESKTOP_VBRX = 0x43, + HID_USAGE_DESKTOP_VBRY = 0x44, + HID_USAGE_DESKTOP_VBRZ = 0x45, + HID_USAGE_DESKTOP_VNO = 0x46, + HID_USAGE_DESKTOP_FEATURE_NOTIFICATION = 0x47, + HID_USAGE_DESKTOP_RESOLUTION_MULTIPLIER = 0x48, + HID_USAGE_DESKTOP_SYSTEM_CONTROL = 0x80, + HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN = 0x81, + HID_USAGE_DESKTOP_SYSTEM_SLEEP = 0x82, + HID_USAGE_DESKTOP_SYSTEM_WAKE_UP = 0x83, + HID_USAGE_DESKTOP_SYSTEM_CONTEXT_MENU = 0x84, + HID_USAGE_DESKTOP_SYSTEM_MAIN_MENU = 0x85, + HID_USAGE_DESKTOP_SYSTEM_APP_MENU = 0x86, + HID_USAGE_DESKTOP_SYSTEM_MENU_HELP = 0x87, + HID_USAGE_DESKTOP_SYSTEM_MENU_EXIT = 0x88, + HID_USAGE_DESKTOP_SYSTEM_MENU_SELECT = 0x89, + HID_USAGE_DESKTOP_SYSTEM_MENU_RIGHT = 0x8A, + HID_USAGE_DESKTOP_SYSTEM_MENU_LEFT = 0x8B, + HID_USAGE_DESKTOP_SYSTEM_MENU_UP = 0x8C, + HID_USAGE_DESKTOP_SYSTEM_MENU_DOWN = 0x8D, + HID_USAGE_DESKTOP_SYSTEM_COLD_RESTART = 0x8E, + HID_USAGE_DESKTOP_SYSTEM_WARM_RESTART = 0x8F, + HID_USAGE_DESKTOP_DPAD_UP = 0x90, + HID_USAGE_DESKTOP_DPAD_DOWN = 0x91, + HID_USAGE_DESKTOP_DPAD_RIGHT = 0x92, + HID_USAGE_DESKTOP_DPAD_LEFT = 0x93, + HID_USAGE_DESKTOP_SYSTEM_DOCK = 0xA0, + HID_USAGE_DESKTOP_SYSTEM_UNDOCK = 0xA1, + HID_USAGE_DESKTOP_SYSTEM_SETUP = 0xA2, + HID_USAGE_DESKTOP_SYSTEM_BREAK = 0xA3, + HID_USAGE_DESKTOP_SYSTEM_DEBUGGER_BREAK = 0xA4, + HID_USAGE_DESKTOP_APPLICATION_BREAK = 0xA5, + HID_USAGE_DESKTOP_APPLICATION_DEBUGGER_BREAK = 0xA6, + HID_USAGE_DESKTOP_SYSTEM_SPEAKER_MUTE = 0xA7, + HID_USAGE_DESKTOP_SYSTEM_HIBERNATE = 0xA8, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INVERT = 0xB0, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INTERNAL = 0xB1, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_EXTERNAL = 0xB2, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_BOTH = 0xB3, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_DUAL = 0xB4, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_TOGGLE_INT_EXT = 0xB5, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_SWAP_PRIMARY_SECONDARY = 0xB6, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_LCD_AUTOSCALE = 0xB7 +}; + + +/// HID Usage Table: Consumer Page (0x0C) +/// Only contains controls that supported by Windows (whole list is too long) +enum +{ + // Generic Control + HID_USAGE_CONSUMER_CONTROL = 0x0001, + + // Power Control + HID_USAGE_CONSUMER_POWER = 0x0030, + HID_USAGE_CONSUMER_RESET = 0x0031, + HID_USAGE_CONSUMER_SLEEP = 0x0032, + + // Screen Brightness + HID_USAGE_CONSUMER_BRIGHTNESS_INCREMENT = 0x006F, + HID_USAGE_CONSUMER_BRIGHTNESS_DECREMENT = 0x0070, + + // These HID usages operate only on mobile systems (battery powered) and + // require Windows 8 (build 8302 or greater). + HID_USAGE_CONSUMER_WIRELESS_RADIO_CONTROLS = 0x000C, + HID_USAGE_CONSUMER_WIRELESS_RADIO_BUTTONS = 0x00C6, + HID_USAGE_CONSUMER_WIRELESS_RADIO_LED = 0x00C7, + HID_USAGE_CONSUMER_WIRELESS_RADIO_SLIDER_SWITCH = 0x00C8, + + // Media Control + HID_USAGE_CONSUMER_PLAY_PAUSE = 0x00CD, + HID_USAGE_CONSUMER_SCAN_NEXT = 0x00B5, + HID_USAGE_CONSUMER_SCAN_PREVIOUS = 0x00B6, + HID_USAGE_CONSUMER_STOP = 0x00B7, + HID_USAGE_CONSUMER_VOLUME = 0x00E0, + HID_USAGE_CONSUMER_MUTE = 0x00E2, + HID_USAGE_CONSUMER_BASS = 0x00E3, + HID_USAGE_CONSUMER_TREBLE = 0x00E4, + HID_USAGE_CONSUMER_BASS_BOOST = 0x00E5, + HID_USAGE_CONSUMER_VOLUME_INCREMENT = 0x00E9, + HID_USAGE_CONSUMER_VOLUME_DECREMENT = 0x00EA, + HID_USAGE_CONSUMER_BASS_INCREMENT = 0x0152, + HID_USAGE_CONSUMER_BASS_DECREMENT = 0x0153, + HID_USAGE_CONSUMER_TREBLE_INCREMENT = 0x0154, + HID_USAGE_CONSUMER_TREBLE_DECREMENT = 0x0155, + + // Application Launcher + HID_USAGE_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION = 0x0183, + HID_USAGE_CONSUMER_AL_EMAIL_READER = 0x018A, + HID_USAGE_CONSUMER_AL_CALCULATOR = 0x0192, + HID_USAGE_CONSUMER_AL_LOCAL_BROWSER = 0x0194, + + // Browser/Explorer Specific + HID_USAGE_CONSUMER_AC_SEARCH = 0x0221, + HID_USAGE_CONSUMER_AC_HOME = 0x0223, + HID_USAGE_CONSUMER_AC_BACK = 0x0224, + HID_USAGE_CONSUMER_AC_FORWARD = 0x0225, + HID_USAGE_CONSUMER_AC_STOP = 0x0226, + HID_USAGE_CONSUMER_AC_REFRESH = 0x0227, + HID_USAGE_CONSUMER_AC_BOOKMARKS = 0x022A, + + // Mouse Horizontal scroll + HID_USAGE_CONSUMER_AC_PAN = 0x0238, +}; + +/*-------------------------------------------------------------------- + * ASCII to KEYCODE Conversion + * Expand to array of [128][2] (shift, keycode) + * + * Usage: example to convert input chr into keyboard report (modifier + keycode) + * + * uint8_t const conv_table[128][2] = { HID_ASCII_TO_KEYCODE }; + * + * uint8_t keycode[6] = { 0 }; + * uint8_t modifier = 0; + * + * if ( conv_table[chr][0] ) modifier = KEYBOARD_MODIFIER_LEFTSHIFT; + * keycode[0] = conv_table[chr][1]; + * tud_hid_keyboard_report(report_id, modifier, keycode); + * + *--------------------------------------------------------------------*/ +#define HID_ASCII_TO_KEYCODE \ + {0, 0 }, /* 0x00 Null */ \ + {0, 0 }, /* 0x01 */ \ + {0, 0 }, /* 0x02 */ \ + {0, 0 }, /* 0x03 */ \ + {0, 0 }, /* 0x04 */ \ + {0, 0 }, /* 0x05 */ \ + {0, 0 }, /* 0x06 */ \ + {0, 0 }, /* 0x07 */ \ + {0, HID_KEY_BACKSPACE }, /* 0x08 Backspace */ \ + {0, HID_KEY_TAB }, /* 0x09 Tab */ \ + {0, HID_KEY_ENTER }, /* 0x0A Line Feed */ \ + {0, 0 }, /* 0x0B */ \ + {0, 0 }, /* 0x0C */ \ + {0, HID_KEY_ENTER }, /* 0x0D CR */ \ + {0, 0 }, /* 0x0E */ \ + {0, 0 }, /* 0x0F */ \ + {0, 0 }, /* 0x10 */ \ + {0, 0 }, /* 0x11 */ \ + {0, 0 }, /* 0x12 */ \ + {0, 0 }, /* 0x13 */ \ + {0, 0 }, /* 0x14 */ \ + {0, 0 }, /* 0x15 */ \ + {0, 0 }, /* 0x16 */ \ + {0, 0 }, /* 0x17 */ \ + {0, 0 }, /* 0x18 */ \ + {0, 0 }, /* 0x19 */ \ + {0, 0 }, /* 0x1A */ \ + {0, HID_KEY_ESCAPE }, /* 0x1B Escape */ \ + {0, 0 }, /* 0x1C */ \ + {0, 0 }, /* 0x1D */ \ + {0, 0 }, /* 0x1E */ \ + {0, 0 }, /* 0x1F */ \ + \ + {0, HID_KEY_SPACE }, /* 0x20 */ \ + {1, HID_KEY_1 }, /* 0x21 ! */ \ + {1, HID_KEY_APOSTROPHE }, /* 0x22 " */ \ + {1, HID_KEY_3 }, /* 0x23 # */ \ + {1, HID_KEY_4 }, /* 0x24 $ */ \ + {1, HID_KEY_5 }, /* 0x25 % */ \ + {1, HID_KEY_7 }, /* 0x26 & */ \ + {0, HID_KEY_APOSTROPHE }, /* 0x27 ' */ \ + {1, HID_KEY_9 }, /* 0x28 ( */ \ + {1, HID_KEY_0 }, /* 0x29 ) */ \ + {1, HID_KEY_8 }, /* 0x2A * */ \ + {1, HID_KEY_EQUAL }, /* 0x2B + */ \ + {0, HID_KEY_COMMA }, /* 0x2C , */ \ + {0, HID_KEY_MINUS }, /* 0x2D - */ \ + {0, HID_KEY_PERIOD }, /* 0x2E . */ \ + {0, HID_KEY_SLASH }, /* 0x2F / */ \ + {0, HID_KEY_0 }, /* 0x30 0 */ \ + {0, HID_KEY_1 }, /* 0x31 1 */ \ + {0, HID_KEY_2 }, /* 0x32 2 */ \ + {0, HID_KEY_3 }, /* 0x33 3 */ \ + {0, HID_KEY_4 }, /* 0x34 4 */ \ + {0, HID_KEY_5 }, /* 0x35 5 */ \ + {0, HID_KEY_6 }, /* 0x36 6 */ \ + {0, HID_KEY_7 }, /* 0x37 7 */ \ + {0, HID_KEY_8 }, /* 0x38 8 */ \ + {0, HID_KEY_9 }, /* 0x39 9 */ \ + {1, HID_KEY_SEMICOLON }, /* 0x3A : */ \ + {0, HID_KEY_SEMICOLON }, /* 0x3B ; */ \ + {1, HID_KEY_COMMA }, /* 0x3C < */ \ + {0, HID_KEY_EQUAL }, /* 0x3D = */ \ + {1, HID_KEY_PERIOD }, /* 0x3E > */ \ + {1, HID_KEY_SLASH }, /* 0x3F ? */ \ + \ + {1, HID_KEY_2 }, /* 0x40 @ */ \ + {1, HID_KEY_A }, /* 0x41 A */ \ + {1, HID_KEY_B }, /* 0x42 B */ \ + {1, HID_KEY_C }, /* 0x43 C */ \ + {1, HID_KEY_D }, /* 0x44 D */ \ + {1, HID_KEY_E }, /* 0x45 E */ \ + {1, HID_KEY_F }, /* 0x46 F */ \ + {1, HID_KEY_G }, /* 0x47 G */ \ + {1, HID_KEY_H }, /* 0x48 H */ \ + {1, HID_KEY_I }, /* 0x49 I */ \ + {1, HID_KEY_J }, /* 0x4A J */ \ + {1, HID_KEY_K }, /* 0x4B K */ \ + {1, HID_KEY_L }, /* 0x4C L */ \ + {1, HID_KEY_M }, /* 0x4D M */ \ + {1, HID_KEY_N }, /* 0x4E N */ \ + {1, HID_KEY_O }, /* 0x4F O */ \ + {1, HID_KEY_P }, /* 0x50 P */ \ + {1, HID_KEY_Q }, /* 0x51 Q */ \ + {1, HID_KEY_R }, /* 0x52 R */ \ + {1, HID_KEY_S }, /* 0x53 S */ \ + {1, HID_KEY_T }, /* 0x55 T */ \ + {1, HID_KEY_U }, /* 0x55 U */ \ + {1, HID_KEY_V }, /* 0x56 V */ \ + {1, HID_KEY_W }, /* 0x57 W */ \ + {1, HID_KEY_X }, /* 0x58 X */ \ + {1, HID_KEY_Y }, /* 0x59 Y */ \ + {1, HID_KEY_Z }, /* 0x5A Z */ \ + {0, HID_KEY_BRACKET_LEFT }, /* 0x5B [ */ \ + {0, HID_KEY_BACKSLASH }, /* 0x5C '\' */ \ + {0, HID_KEY_BRACKET_RIGHT }, /* 0x5D ] */ \ + {1, HID_KEY_6 }, /* 0x5E ^ */ \ + {1, HID_KEY_MINUS }, /* 0x5F _ */ \ + \ + {0, HID_KEY_GRAVE }, /* 0x60 ` */ \ + {0, HID_KEY_A }, /* 0x61 a */ \ + {0, HID_KEY_B }, /* 0x62 b */ \ + {0, HID_KEY_C }, /* 0x63 c */ \ + {0, HID_KEY_D }, /* 0x66 d */ \ + {0, HID_KEY_E }, /* 0x65 e */ \ + {0, HID_KEY_F }, /* 0x66 f */ \ + {0, HID_KEY_G }, /* 0x67 g */ \ + {0, HID_KEY_H }, /* 0x68 h */ \ + {0, HID_KEY_I }, /* 0x69 i */ \ + {0, HID_KEY_J }, /* 0x6A j */ \ + {0, HID_KEY_K }, /* 0x6B k */ \ + {0, HID_KEY_L }, /* 0x6C l */ \ + {0, HID_KEY_M }, /* 0x6D m */ \ + {0, HID_KEY_N }, /* 0x6E n */ \ + {0, HID_KEY_O }, /* 0x6F o */ \ + {0, HID_KEY_P }, /* 0x70 p */ \ + {0, HID_KEY_Q }, /* 0x71 q */ \ + {0, HID_KEY_R }, /* 0x72 r */ \ + {0, HID_KEY_S }, /* 0x73 s */ \ + {0, HID_KEY_T }, /* 0x75 t */ \ + {0, HID_KEY_U }, /* 0x75 u */ \ + {0, HID_KEY_V }, /* 0x76 v */ \ + {0, HID_KEY_W }, /* 0x77 w */ \ + {0, HID_KEY_X }, /* 0x78 x */ \ + {0, HID_KEY_Y }, /* 0x79 y */ \ + {0, HID_KEY_Z }, /* 0x7A z */ \ + {1, HID_KEY_BRACKET_LEFT }, /* 0x7B { */ \ + {1, HID_KEY_BACKSLASH }, /* 0x7C | */ \ + {1, HID_KEY_BRACKET_RIGHT }, /* 0x7D } */ \ + {1, HID_KEY_GRAVE }, /* 0x7E ~ */ \ + {0, HID_KEY_DELETE } /* 0x7F Delete */ \ + +/*-------------------------------------------------------------------- + * KEYCODE to Ascii Conversion + * Expand to array of [128][2] (ascii without shift, ascii with shift) + * + * Usage: example to convert ascii from keycode (key) and shift modifier (shift). + * Here we assume key < 128 ( printable ) + * + * uint8_t const conv_table[128][2] = { HID_KEYCODE_TO_ASCII }; + * char ch = shift ? conv_table[chr][1] : conv_table[chr][0]; + * + *--------------------------------------------------------------------*/ +#define HID_KEYCODE_TO_ASCII \ + {0 , 0 }, /* 0x00 */ \ + {0 , 0 }, /* 0x01 */ \ + {0 , 0 }, /* 0x02 */ \ + {0 , 0 }, /* 0x03 */ \ + {'a' , 'A' }, /* 0x04 */ \ + {'b' , 'B' }, /* 0x05 */ \ + {'c' , 'C' }, /* 0x06 */ \ + {'d' , 'D' }, /* 0x07 */ \ + {'e' , 'E' }, /* 0x08 */ \ + {'f' , 'F' }, /* 0x09 */ \ + {'g' , 'G' }, /* 0x0a */ \ + {'h' , 'H' }, /* 0x0b */ \ + {'i' , 'I' }, /* 0x0c */ \ + {'j' , 'J' }, /* 0x0d */ \ + {'k' , 'K' }, /* 0x0e */ \ + {'l' , 'L' }, /* 0x0f */ \ + {'m' , 'M' }, /* 0x10 */ \ + {'n' , 'N' }, /* 0x11 */ \ + {'o' , 'O' }, /* 0x12 */ \ + {'p' , 'P' }, /* 0x13 */ \ + {'q' , 'Q' }, /* 0x14 */ \ + {'r' , 'R' }, /* 0x15 */ \ + {'s' , 'S' }, /* 0x16 */ \ + {'t' , 'T' }, /* 0x17 */ \ + {'u' , 'U' }, /* 0x18 */ \ + {'v' , 'V' }, /* 0x19 */ \ + {'w' , 'W' }, /* 0x1a */ \ + {'x' , 'X' }, /* 0x1b */ \ + {'y' , 'Y' }, /* 0x1c */ \ + {'z' , 'Z' }, /* 0x1d */ \ + {'1' , '!' }, /* 0x1e */ \ + {'2' , '@' }, /* 0x1f */ \ + {'3' , '#' }, /* 0x20 */ \ + {'4' , '$' }, /* 0x21 */ \ + {'5' , '%' }, /* 0x22 */ \ + {'6' , '^' }, /* 0x23 */ \ + {'7' , '&' }, /* 0x24 */ \ + {'8' , '*' }, /* 0x25 */ \ + {'9' , '(' }, /* 0x26 */ \ + {'0' , ')' }, /* 0x27 */ \ + {'\r' , '\r' }, /* 0x28 */ \ + {'\x1b', '\x1b' }, /* 0x29 */ \ + {'\b' , '\b' }, /* 0x2a */ \ + {'\t' , '\t' }, /* 0x2b */ \ + {' ' , ' ' }, /* 0x2c */ \ + {'-' , '_' }, /* 0x2d */ \ + {'=' , '+' }, /* 0x2e */ \ + {'[' , '{' }, /* 0x2f */ \ + {']' , '}' }, /* 0x30 */ \ + {'\\' , '|' }, /* 0x31 */ \ + {'#' , '~' }, /* 0x32 */ \ + {';' , ':' }, /* 0x33 */ \ + {'\'' , '\"' }, /* 0x34 */ \ + {'`' , '~' }, /* 0x35 */ \ + {',' , '<' }, /* 0x36 */ \ + {'.' , '>' }, /* 0x37 */ \ + {'/' , '?' }, /* 0x38 */ \ + \ + {0 , 0 }, /* 0x39 */ \ + {0 , 0 }, /* 0x3a */ \ + {0 , 0 }, /* 0x3b */ \ + {0 , 0 }, /* 0x3c */ \ + {0 , 0 }, /* 0x3d */ \ + {0 , 0 }, /* 0x3e */ \ + {0 , 0 }, /* 0x3f */ \ + {0 , 0 }, /* 0x40 */ \ + {0 , 0 }, /* 0x41 */ \ + {0 , 0 }, /* 0x42 */ \ + {0 , 0 }, /* 0x43 */ \ + {0 , 0 }, /* 0x44 */ \ + {0 , 0 }, /* 0x45 */ \ + {0 , 0 }, /* 0x46 */ \ + {0 , 0 }, /* 0x47 */ \ + {0 , 0 }, /* 0x48 */ \ + {0 , 0 }, /* 0x49 */ \ + {0 , 0 }, /* 0x4a */ \ + {0 , 0 }, /* 0x4b */ \ + {0 , 0 }, /* 0x4c */ \ + {0 , 0 }, /* 0x4d */ \ + {0 , 0 }, /* 0x4e */ \ + {0 , 0 }, /* 0x4f */ \ + {0 , 0 }, /* 0x50 */ \ + {0 , 0 }, /* 0x51 */ \ + {0 , 0 }, /* 0x52 */ \ + {0 , 0 }, /* 0x53 */ \ + \ + {'/' , '/' }, /* 0x54 */ \ + {'*' , '*' }, /* 0x55 */ \ + {'-' , '-' }, /* 0x56 */ \ + {'+' , '+' }, /* 0x57 */ \ + {'\r' , '\r' }, /* 0x58 */ \ + {'1' , 0 }, /* 0x59 */ \ + {'2' , 0 }, /* 0x5a */ \ + {'3' , 0 }, /* 0x5b */ \ + {'4' , 0 }, /* 0x5c */ \ + {'5' , '5' }, /* 0x5d */ \ + {'6' , 0 }, /* 0x5e */ \ + {'7' , 0 }, /* 0x5f */ \ + {'8' , 0 }, /* 0x60 */ \ + {'9' , 0 }, /* 0x61 */ \ + {'0' , 0 }, /* 0x62 */ \ + {'.' , 0 }, /* 0x63 */ \ + {0 , 0 }, /* 0x64 */ \ + {0 , 0 }, /* 0x65 */ \ + {0 , 0 }, /* 0x66 */ \ + {'=' , '=' }, /* 0x67 */ \ + + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_HID_H__ */ + +/// @} diff --git a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.c b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.c new file mode 100644 index 00000000..8077e4de --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.c @@ -0,0 +1,419 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_HID) + +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "hid_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +typedef struct +{ + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; // optional Out endpoint + uint8_t itf_protocol; // Boot mouse or keyboard + + uint8_t protocol_mode; // Boot (0) or Report protocol (1) + uint8_t idle_rate; // up to application to handle idle rate + uint16_t report_desc_len; + + CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE]; + + // TODO save hid descriptor since host can specifically request this after enumeration + // Note: HID descriptor may be not available from application after enumeration + tusb_hid_descriptor_hid_t const * hid_descriptor; +} hidd_interface_t; + +CFG_TUSB_MEM_SECTION static hidd_interface_t _hidd_itf[CFG_TUD_HID]; + +/*------------- Helpers -------------*/ +static inline uint8_t get_index_by_itfnum(uint8_t itf_num) +{ + for (uint8_t i=0; i < CFG_TUD_HID; i++ ) + { + if ( itf_num == _hidd_itf[i].itf_num ) return i; + } + + return 0xFF; +} + +//--------------------------------------------------------------------+ +// APPLICATION API +//--------------------------------------------------------------------+ +bool tud_hid_n_ready(uint8_t instance) +{ + uint8_t const rhport = 0; + uint8_t const ep_in = _hidd_itf[instance].ep_in; + return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(rhport, ep_in); +} + +bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint16_t len) +{ + uint8_t const rhport = 0; + hidd_interface_t * p_hid = &_hidd_itf[instance]; + + // claim endpoint + TU_VERIFY( usbd_edpt_claim(rhport, p_hid->ep_in) ); + + // prepare data + if (report_id) + { + len = tu_min16(len, CFG_TUD_HID_EP_BUFSIZE-1); + + p_hid->epin_buf[0] = report_id; + memcpy(p_hid->epin_buf+1, report, len); + len++; + }else + { + // If report id = 0, skip ID field + len = tu_min16(len, CFG_TUD_HID_EP_BUFSIZE); + memcpy(p_hid->epin_buf, report, len); + } + + return usbd_edpt_xfer(rhport, p_hid->ep_in, p_hid->epin_buf, len); +} + +uint8_t tud_hid_n_interface_protocol(uint8_t instance) +{ + return _hidd_itf[instance].itf_protocol; +} + +uint8_t tud_hid_n_get_protocol(uint8_t instance) +{ + return _hidd_itf[instance].protocol_mode; +} + +bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6]) +{ + hid_keyboard_report_t report; + + report.modifier = modifier; + report.reserved = 0; + + if ( keycode ) + { + memcpy(report.keycode, keycode, 6); + }else + { + tu_memclr(report.keycode, 6); + } + + return tud_hid_n_report(instance, report_id, &report, sizeof(report)); +} + +bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, + uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) +{ + hid_mouse_report_t report = + { + .buttons = buttons, + .x = x, + .y = y, + .wheel = vertical, + .pan = horizontal + }; + + return tud_hid_n_report(instance, report_id, &report, sizeof(report)); +} + +bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, + int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) +{ + hid_gamepad_report_t report = + { + .x = x, + .y = y, + .z = z, + .rz = rz, + .rx = rx, + .ry = ry, + .hat = hat, + .buttons = buttons, + }; + + return tud_hid_n_report(instance, report_id, &report, sizeof(report)); +} + +//--------------------------------------------------------------------+ +// USBD-CLASS API +//--------------------------------------------------------------------+ +void hidd_init(void) +{ + hidd_reset(0); +} + +void hidd_reset(uint8_t rhport) +{ + (void) rhport; + tu_memclr(_hidd_itf, sizeof(_hidd_itf)); +} + +uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) +{ + TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0); + + // len = interface + hid + n*endpoints + uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); + TU_ASSERT(max_len >= drv_len, 0); + + // Find available interface + hidd_interface_t * p_hid = NULL; + uint8_t hid_id; + for(hid_id=0; hid_idhid_descriptor = (tusb_hid_descriptor_hid_t const *) p_desc; + + //------------- Endpoint Descriptor -------------// + p_desc = tu_desc_next(p_desc); + TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_INTERRUPT, &p_hid->ep_out, &p_hid->ep_in), 0); + + if ( desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT ) p_hid->itf_protocol = desc_itf->bInterfaceProtocol; + + p_hid->protocol_mode = HID_PROTOCOL_REPORT; // Per Specs: default is report mode + p_hid->itf_num = desc_itf->bInterfaceNumber; + + // Use offsetof to avoid pointer to the odd/misaligned address + p_hid->report_desc_len = tu_unaligned_read16((uint8_t const*) p_hid->hid_descriptor + offsetof(tusb_hid_descriptor_hid_t, wReportLength)); + + // Prepare for output endpoint + if (p_hid->ep_out) + { + if ( !usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)) ) + { + TU_LOG_FAILED(); + TU_BREAKPOINT(); + } + } + + return drv_len; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); + + uint8_t const hid_itf = get_index_by_itfnum((uint8_t) request->wIndex); + TU_VERIFY(hid_itf < CFG_TUD_HID); + + hidd_interface_t* p_hid = &_hidd_itf[hid_itf]; + + if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) + { + //------------- STD Request -------------// + if ( stage == CONTROL_STAGE_SETUP ) + { + uint8_t const desc_type = tu_u16_high(request->wValue); + //uint8_t const desc_index = tu_u16_low (request->wValue); + + if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_HID) + { + TU_VERIFY(p_hid->hid_descriptor); + TU_VERIFY(tud_control_xfer(rhport, request, (void*)(uintptr_t) p_hid->hid_descriptor, p_hid->hid_descriptor->bLength)); + } + else if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT) + { + uint8_t const * desc_report = tud_hid_descriptor_report_cb(hid_itf); + tud_control_xfer(rhport, request, (void*)(uintptr_t) desc_report, p_hid->report_desc_len); + } + else + { + return false; // stall unsupported request + } + } + } + else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) + { + //------------- Class Specific Request -------------// + switch( request->bRequest ) + { + case HID_REQ_CONTROL_GET_REPORT: + if ( stage == CONTROL_STAGE_SETUP ) + { + uint8_t const report_type = tu_u16_high(request->wValue); + uint8_t const report_id = tu_u16_low(request->wValue); + + uint8_t* report_buf = p_hid->epin_buf; + uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); + + uint16_t xferlen = 0; + + // If host request a specific Report ID, add ID to as 1 byte of response + if ( (report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1) ) + { + *report_buf++ = report_id; + req_len--; + + xferlen++; + } + + xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len); + TU_ASSERT( xferlen > 0 ); + + tud_control_xfer(rhport, request, p_hid->epin_buf, xferlen); + } + break; + + case HID_REQ_CONTROL_SET_REPORT: + if ( stage == CONTROL_STAGE_SETUP ) + { + TU_VERIFY(request->wLength <= sizeof(p_hid->epout_buf)); + tud_control_xfer(rhport, request, p_hid->epout_buf, request->wLength); + } + else if ( stage == CONTROL_STAGE_ACK ) + { + uint8_t const report_type = tu_u16_high(request->wValue); + uint8_t const report_id = tu_u16_low(request->wValue); + + uint8_t const* report_buf = p_hid->epout_buf; + uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); + + // If host request a specific Report ID, extract report ID in buffer before invoking callback + if ( (report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0]) ) + { + report_buf++; + report_len--; + } + + tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, report_len); + } + break; + + case HID_REQ_CONTROL_SET_IDLE: + if ( stage == CONTROL_STAGE_SETUP ) + { + p_hid->idle_rate = tu_u16_high(request->wValue); + if ( tud_hid_set_idle_cb ) + { + // stall request if callback return false + TU_VERIFY( tud_hid_set_idle_cb( hid_itf, p_hid->idle_rate) ); + } + + tud_control_status(rhport, request); + } + break; + + case HID_REQ_CONTROL_GET_IDLE: + if ( stage == CONTROL_STAGE_SETUP ) + { + // TODO idle rate of report + tud_control_xfer(rhport, request, &p_hid->idle_rate, 1); + } + break; + + case HID_REQ_CONTROL_GET_PROTOCOL: + if ( stage == CONTROL_STAGE_SETUP ) + { + tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1); + } + break; + + case HID_REQ_CONTROL_SET_PROTOCOL: + if ( stage == CONTROL_STAGE_SETUP ) + { + tud_control_status(rhport, request); + } + else if ( stage == CONTROL_STAGE_ACK ) + { + p_hid->protocol_mode = (uint8_t) request->wValue; + if (tud_hid_set_protocol_cb) + { + tud_hid_set_protocol_cb(hid_itf, p_hid->protocol_mode); + } + } + break; + + default: return false; // stall unsupported request + } + }else + { + return false; // stall unsupported request + } + + return true; +} + +bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) result; + + uint8_t instance = 0; + hidd_interface_t * p_hid = _hidd_itf; + + // Identify which interface to use + for (instance = 0; instance < CFG_TUD_HID; instance++) + { + p_hid = &_hidd_itf[instance]; + if ( (ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in) ) break; + } + TU_ASSERT(instance < CFG_TUD_HID); + + // Sent report successfully + if (ep_addr == p_hid->ep_in) + { + if (tud_hid_report_complete_cb) + { + tud_hid_report_complete_cb(instance, p_hid->epin_buf, (/*uint16_t*/ uint8_t) xferred_bytes); + } + } + // Received report + else if (ep_addr == p_hid->ep_out) + { + tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, (uint16_t) xferred_bytes); + TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))); + } + + return true; +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.h b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.h new file mode 100644 index 00000000..3143b102 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.h @@ -0,0 +1,393 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_HID_DEVICE_H_ +#define _TUSB_HID_DEVICE_H_ + +#include "hid.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Class Driver Default Configure & Validation +//--------------------------------------------------------------------+ + +#if !defined(CFG_TUD_HID_EP_BUFSIZE) & defined(CFG_TUD_HID_BUFSIZE) + // TODO warn user to use new name later on + // #warning CFG_TUD_HID_BUFSIZE is renamed to CFG_TUD_HID_EP_BUFSIZE, please update to use the new name + #define CFG_TUD_HID_EP_BUFSIZE CFG_TUD_HID_BUFSIZE +#endif + +#ifndef CFG_TUD_HID_EP_BUFSIZE + #define CFG_TUD_HID_EP_BUFSIZE 64 +#endif + +//--------------------------------------------------------------------+ +// Application API (Multiple Instances) +// CFG_TUD_HID > 1 +//--------------------------------------------------------------------+ + +// Check if the interface is ready to use +bool tud_hid_n_ready(uint8_t instance); + +// Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values +uint8_t tud_hid_n_interface_protocol(uint8_t instance); + +// Get current active protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) +uint8_t tud_hid_n_get_protocol(uint8_t instance); + +// Send report to host +bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint16_t len); + +// KEYBOARD: convenient helper to send keyboard report if application +// use template layout report as defined by hid_keyboard_report_t +bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6]); + +// MOUSE: convenient helper to send mouse report if application +// use template layout report as defined by hid_mouse_report_t +bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal); + +// Gamepad: convenient helper to send gamepad report if application +// use template layout report TUD_HID_REPORT_DESC_GAMEPAD +bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); + +//--------------------------------------------------------------------+ +// Application API (Single Port) +//--------------------------------------------------------------------+ +static inline bool tud_hid_ready(void); +static inline uint8_t tud_hid_interface_protocol(void); +static inline uint8_t tud_hid_get_protocol(void); +static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len); +static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]); +static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal); +static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); + +//--------------------------------------------------------------------+ +// Callbacks (Weak is optional) +//--------------------------------------------------------------------+ + +// Invoked when received GET HID REPORT DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance); + +// Invoked when received GET_REPORT control request +// Application must fill buffer report's content and return its length. +// Return zero will cause the stack to STALL request +uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen); + +// Invoked when received SET_REPORT control request or +// received data on OUT endpoint ( Report ID = 0, Type = 0 ) +void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize); + +// Invoked when received SET_PROTOCOL request +// protocol is either HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) +TU_ATTR_WEAK void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol); + +// Invoked when received SET_IDLE request. return false will stall the request +// - Idle Rate = 0 : only send report if there is changes, i.e skip duplication +// - Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms). +TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate); + +// Invoked when sent REPORT successfully to host +// Application can use this to send the next report +// Note: For composite reports, report[0] is report ID +TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, /*uint16_t*/ uint8_t len ); + + +//--------------------------------------------------------------------+ +// Inline Functions +//--------------------------------------------------------------------+ +static inline bool tud_hid_ready(void) +{ + return tud_hid_n_ready(0); +} + +static inline uint8_t tud_hid_interface_protocol(void) +{ + return tud_hid_n_interface_protocol(0); +} + +static inline uint8_t tud_hid_get_protocol(void) +{ + return tud_hid_n_get_protocol(0); +} + +static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len) +{ + return tud_hid_n_report(0, report_id, report, len); +} + +static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]) +{ + return tud_hid_n_keyboard_report(0, report_id, modifier, keycode); +} + +static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) +{ + return tud_hid_n_mouse_report(0, report_id, buttons, x, y, vertical, horizontal); +} + +static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) +{ + return tud_hid_n_gamepad_report(0, report_id, x, y, z, rz, rx, ry, hat, buttons); +} + +/* --------------------------------------------------------------------+ + * HID Report Descriptor Template + * + * Convenient for declaring popular HID device (keyboard, mouse, consumer, + * gamepad etc...). Templates take "HID_REPORT_ID(n)" as input, leave + * empty if multiple reports is not used + * + * - Only 1 report: no parameter + * uint8_t const report_desc[] = { TUD_HID_REPORT_DESC_KEYBOARD() }; + * + * - Multiple Reports: "HID_REPORT_ID(ID)" must be passed to template + * uint8_t const report_desc[] = + * { + * TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(1) ) , + * TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(2) ) + * }; + *--------------------------------------------------------------------*/ + +// Keyboard Report Descriptor Template +#define TUD_HID_REPORT_DESC_KEYBOARD(...) \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_KEYBOARD ) ,\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ + __VA_ARGS__ \ + /* 8 bits Modifier Keys (Shfit, Control, Alt) */ \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\ + HID_USAGE_MIN ( 224 ) ,\ + HID_USAGE_MAX ( 231 ) ,\ + HID_LOGICAL_MIN ( 0 ) ,\ + HID_LOGICAL_MAX ( 1 ) ,\ + HID_REPORT_COUNT ( 8 ) ,\ + HID_REPORT_SIZE ( 1 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + /* 8 bit reserved */ \ + HID_REPORT_COUNT ( 1 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_INPUT ( HID_CONSTANT ) ,\ + /* Output 5-bit LED Indicator Kana | Compose | ScrollLock | CapsLock | NumLock */ \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_LED ) ,\ + HID_USAGE_MIN ( 1 ) ,\ + HID_USAGE_MAX ( 5 ) ,\ + HID_REPORT_COUNT ( 5 ) ,\ + HID_REPORT_SIZE ( 1 ) ,\ + HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + /* led padding */ \ + HID_REPORT_COUNT ( 1 ) ,\ + HID_REPORT_SIZE ( 3 ) ,\ + HID_OUTPUT ( HID_CONSTANT ) ,\ + /* 6-byte Keycodes */ \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\ + HID_USAGE_MIN ( 0 ) ,\ + HID_USAGE_MAX_N ( 255, 2 ) ,\ + HID_LOGICAL_MIN ( 0 ) ,\ + HID_LOGICAL_MAX_N( 255, 2 ) ,\ + HID_REPORT_COUNT ( 6 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\ + HID_COLLECTION_END \ + +// Mouse Report Descriptor Template +#define TUD_HID_REPORT_DESC_MOUSE(...) \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ) ,\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ + __VA_ARGS__ \ + HID_USAGE ( HID_USAGE_DESKTOP_POINTER ) ,\ + HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\ + HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\ + HID_USAGE_MIN ( 1 ) ,\ + HID_USAGE_MAX ( 5 ) ,\ + HID_LOGICAL_MIN ( 0 ) ,\ + HID_LOGICAL_MAX ( 1 ) ,\ + /* Left, Right, Middle, Backward, Forward buttons */ \ + HID_REPORT_COUNT( 5 ) ,\ + HID_REPORT_SIZE ( 1 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + /* 3 bit padding */ \ + HID_REPORT_COUNT( 1 ) ,\ + HID_REPORT_SIZE ( 3 ) ,\ + HID_INPUT ( HID_CONSTANT ) ,\ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + /* X, Y position [-127, 127] */ \ + HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\ + HID_LOGICAL_MIN ( 0x81 ) ,\ + HID_LOGICAL_MAX ( 0x7f ) ,\ + HID_REPORT_COUNT( 2 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\ + /* Verital wheel scroll [-127, 127] */ \ + HID_USAGE ( HID_USAGE_DESKTOP_WHEEL ) ,\ + HID_LOGICAL_MIN ( 0x81 ) ,\ + HID_LOGICAL_MAX ( 0x7f ) ,\ + HID_REPORT_COUNT( 1 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\ + HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ), \ + /* Horizontal wheel scroll [-127, 127] */ \ + HID_USAGE_N ( HID_USAGE_CONSUMER_AC_PAN, 2 ), \ + HID_LOGICAL_MIN ( 0x81 ), \ + HID_LOGICAL_MAX ( 0x7f ), \ + HID_REPORT_COUNT( 1 ), \ + HID_REPORT_SIZE ( 8 ), \ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), \ + HID_COLLECTION_END , \ + HID_COLLECTION_END \ + +// Consumer Control Report Descriptor Template +#define TUD_HID_REPORT_DESC_CONSUMER(...) \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ) ,\ + HID_USAGE ( HID_USAGE_CONSUMER_CONTROL ) ,\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ + __VA_ARGS__ \ + HID_LOGICAL_MIN ( 0x00 ) ,\ + HID_LOGICAL_MAX_N( 0x03FF, 2 ) ,\ + HID_USAGE_MIN ( 0x00 ) ,\ + HID_USAGE_MAX_N ( 0x03FF, 2 ) ,\ + HID_REPORT_COUNT ( 1 ) ,\ + HID_REPORT_SIZE ( 16 ) ,\ + HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\ + HID_COLLECTION_END \ + +/* System Control Report Descriptor Template + * 0x00 - do nothing + * 0x01 - Power Off + * 0x02 - Standby + * 0x03 - Wake Host + */ +#define TUD_HID_REPORT_DESC_SYSTEM_CONTROL(...) \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_CONTROL ) ,\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ + __VA_ARGS__ \ + /* 2 bit system power control */ \ + HID_LOGICAL_MIN ( 1 ) ,\ + HID_LOGICAL_MAX ( 3 ) ,\ + HID_REPORT_COUNT ( 1 ) ,\ + HID_REPORT_SIZE ( 2 ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_SLEEP ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_WAKE_UP ) ,\ + HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\ + /* 6 bit padding */ \ + HID_REPORT_COUNT ( 1 ) ,\ + HID_REPORT_SIZE ( 6 ) ,\ + HID_INPUT ( HID_CONSTANT ) ,\ + HID_COLLECTION_END \ + +// Gamepad Report Descriptor Template +// with 32 buttons, 2 joysticks and 1 hat/dpad with following layout +// | X | Y | Z | Rz | Rx | Ry (1 byte each) | hat/DPAD (1 byte) | Button Map (4 bytes) | +#define TUD_HID_REPORT_DESC_GAMEPAD(...) \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_GAMEPAD ) ,\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ + __VA_ARGS__ \ + /* 8 bit X, Y, Z, Rz, Rx, Ry (min -127, max 127 ) */ \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_Z ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_RZ ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_RX ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_RY ) ,\ + HID_LOGICAL_MIN ( 0x81 ) ,\ + HID_LOGICAL_MAX ( 0x7f ) ,\ + HID_REPORT_COUNT ( 6 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + /* 8 bit DPad/Hat Button Map */ \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_HAT_SWITCH ) ,\ + HID_LOGICAL_MIN ( 1 ) ,\ + HID_LOGICAL_MAX ( 8 ) ,\ + HID_PHYSICAL_MIN ( 0 ) ,\ + HID_PHYSICAL_MAX_N ( 315, 2 ) ,\ + HID_REPORT_COUNT ( 1 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + /* 32 bit Button Map */ \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\ + HID_USAGE_MIN ( 1 ) ,\ + HID_USAGE_MAX ( 32 ) ,\ + HID_LOGICAL_MIN ( 0 ) ,\ + HID_LOGICAL_MAX ( 1 ) ,\ + HID_REPORT_COUNT ( 32 ) ,\ + HID_REPORT_SIZE ( 1 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + HID_COLLECTION_END \ + +// HID Generic Input & Output +// - 1st parameter is report size (mandatory) +// - 2nd parameter is report id HID_REPORT_ID(n) (optional) +#define TUD_HID_REPORT_DESC_GENERIC_INOUT(report_size, ...) \ + HID_USAGE_PAGE_N ( HID_USAGE_PAGE_VENDOR, 2 ),\ + HID_USAGE ( 0x01 ),\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ),\ + /* Report ID if any */\ + __VA_ARGS__ \ + /* Input */ \ + HID_USAGE ( 0x02 ),\ + HID_LOGICAL_MIN ( 0x00 ),\ + HID_LOGICAL_MAX_N ( 0xff, 2 ),\ + HID_REPORT_SIZE ( 8 ),\ + HID_REPORT_COUNT( report_size ),\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\ + /* Output */ \ + HID_USAGE ( 0x03 ),\ + HID_LOGICAL_MIN ( 0x00 ),\ + HID_LOGICAL_MAX_N ( 0xff, 2 ),\ + HID_REPORT_SIZE ( 8 ),\ + HID_REPORT_COUNT( report_size ),\ + HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\ + HID_COLLECTION_END \ + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void hidd_init (void); +void hidd_reset (uint8_t rhport); +uint16_t hidd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +bool hidd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_HID_DEVICE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.c b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.c new file mode 100644 index 00000000..ca745464 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.c @@ -0,0 +1,676 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUH_ENABLED && CFG_TUH_HID) + +#include "host/usbh.h" +#include "host/usbh_classdriver.h" + +#include "hid_host.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +typedef struct +{ + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; + + uint8_t itf_protocol; // None, Keyboard, Mouse + uint8_t protocol_mode; // Boot (0) or Report protocol (1) + + uint8_t report_desc_type; + uint16_t report_desc_len; + + uint16_t epin_size; + uint16_t epout_size; + + uint8_t epin_buf[CFG_TUH_HID_EPIN_BUFSIZE]; + uint8_t epout_buf[CFG_TUH_HID_EPOUT_BUFSIZE]; +} hidh_interface_t; + +typedef struct +{ + uint8_t inst_count; + hidh_interface_t instances[CFG_TUH_HID]; +} hidh_device_t; + +static hidh_device_t _hidh_dev[CFG_TUH_DEVICE_MAX]; + +//------------- Internal prototypes -------------// + +// Get HID device & interface +TU_ATTR_ALWAYS_INLINE static inline hidh_device_t* get_dev(uint8_t dev_addr); +TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_instance(uint8_t dev_addr, uint8_t instance); +static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf); +static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr); + +//--------------------------------------------------------------------+ +// Interface API +//--------------------------------------------------------------------+ + +uint8_t tuh_hid_instance_count(uint8_t dev_addr) +{ + return get_dev(dev_addr)->inst_count; +} + +bool tuh_hid_mounted(uint8_t dev_addr, uint8_t instance) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + return (hid_itf->ep_in != 0) || (hid_itf->ep_out != 0); +} + +uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + return hid_itf->itf_protocol; +} + +//--------------------------------------------------------------------+ +// Control Endpoint API +//--------------------------------------------------------------------+ + +uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + return hid_itf->protocol_mode; +} + +static void set_protocol_complete(tuh_xfer_t* xfer) +{ + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const daddr = xfer->daddr; + uint8_t const instance = get_instance_id_by_itfnum(daddr, itf_num); + hidh_interface_t* hid_itf = get_instance(daddr, instance); + + if (XFER_RESULT_SUCCESS == xfer->result) + { + hid_itf->protocol_mode = (uint8_t) tu_le16toh(xfer->setup->wValue); + } + + if (tuh_hid_set_protocol_complete_cb) + { + tuh_hid_set_protocol_complete_cb(daddr, instance, hid_itf->protocol_mode); + } +} + + +static bool _hidh_set_protocol(uint8_t dev_addr, uint8_t itf_num, uint8_t protocol, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + TU_LOG2("HID Set Protocol = %d\r\n", protocol); + + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = HID_REQ_CONTROL_SET_PROTOCOL, + .wValue = protocol, + .wIndex = itf_num, + .wLength = 0 + }; + + tuh_xfer_t xfer = + { + .daddr = dev_addr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb, + .user_data = user_data + }; + + TU_ASSERT( tuh_control_xfer(&xfer) ); + return true; +} + +bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + TU_VERIFY(hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE); + + return _hidh_set_protocol(dev_addr, hid_itf->itf_num, protocol, set_protocol_complete, 0); +} + +static void set_report_complete(tuh_xfer_t* xfer) +{ + TU_LOG2("HID Set Report complete\r\n"); + + if (tuh_hid_set_report_complete_cb) + { + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const instance = get_instance_id_by_itfnum(xfer->daddr, itf_num); + + uint8_t const report_type = tu_u16_high(xfer->setup->wValue); + uint8_t const report_id = tu_u16_low(xfer->setup->wValue); + + tuh_hid_set_report_complete_cb(xfer->daddr, instance, report_id, report_type, + (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0); + } +} + +bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + TU_LOG2("HID Set Report: id = %u, type = %u, len = %u\r\n", report_id, report_type, len); + + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = HID_REQ_CONTROL_SET_REPORT, + .wValue = tu_u16(report_type, report_id), + .wIndex = hid_itf->itf_num, + .wLength = len + }; + + tuh_xfer_t xfer = + { + .daddr = dev_addr, + .ep_addr = 0, + .setup = &request, + .buffer = report, + .complete_cb = set_report_complete, + .user_data = 0 + }; + + TU_ASSERT( tuh_control_xfer(&xfer) ); + return true; +} + +static bool _hidh_set_idle(uint8_t dev_addr, uint8_t itf_num, uint16_t idle_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + // SET IDLE request, device can stall if not support this request + TU_LOG2("HID Set Idle \r\n"); + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = HID_REQ_CONTROL_SET_IDLE, + .wValue = idle_rate, + .wIndex = itf_num, + .wLength = 0 + }; + + tuh_xfer_t xfer = + { + .daddr = dev_addr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb, + .user_data = user_data + }; + + TU_ASSERT( tuh_control_xfer(&xfer) ); + + return true; +} + +//--------------------------------------------------------------------+ +// Interrupt Endpoint API +//--------------------------------------------------------------------+ + +bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + + // claim endpoint + TU_VERIFY( usbh_edpt_claim(dev_addr, hid_itf->ep_in) ); + + if ( !usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size) ) + { + usbh_edpt_claim(dev_addr, hid_itf->ep_in); + return false; + } + + return true; +} + +//bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance) +//{ +// TU_VERIFY(tuh_n_hid_n_mounted(dev_addr, instance)); +// +// hidh_interface_t* hid_itf = get_instance(dev_addr, instance); +// return !usbh_edpt_busy(dev_addr, hid_itf->ep_in); +//} + +//void tuh_hid_send_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t const* report, uint16_t len); + +//--------------------------------------------------------------------+ +// USBH API +//--------------------------------------------------------------------+ +void hidh_init(void) +{ + tu_memclr(_hidh_dev, sizeof(_hidh_dev)); +} + +bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) result; + + uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const instance = get_instance_id_by_epaddr(dev_addr, ep_addr); + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + + if ( dir == TUSB_DIR_IN ) + { + TU_LOG2(" Get Report callback (%u, %u)\r\n", dev_addr, instance); + TU_LOG3_MEM(hid_itf->epin_buf, xferred_bytes, 2); + tuh_hid_report_received_cb(dev_addr, instance, hid_itf->epin_buf, (uint16_t) xferred_bytes); + }else + { + if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(dev_addr, instance, hid_itf->epout_buf, (uint16_t) xferred_bytes); + } + + return true; +} + +void hidh_close(uint8_t dev_addr) +{ + TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); + + hidh_device_t* hid_dev = get_dev(dev_addr); + + if (tuh_hid_umount_cb) + { + for (uint8_t inst = 0; inst < hid_dev->inst_count; inst++ ) tuh_hid_umount_cb(dev_addr, inst); + } + + tu_memclr(hid_dev, sizeof(hidh_device_t)); +} + +//--------------------------------------------------------------------+ +// Enumeration +//--------------------------------------------------------------------+ + +bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) +{ + (void) rhport; + (void) max_len; + + TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass); + + TU_LOG2("[%u] HID opening Interface %u\r\n", dev_addr, desc_itf->bInterfaceNumber); + + // len = interface + hid + n*endpoints + uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); + TU_ASSERT(max_len >= drv_len); + + uint8_t const *p_desc = (uint8_t const *) desc_itf; + + //------------- HID descriptor -------------// + p_desc = tu_desc_next(p_desc); + tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc; + TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType); + + // not enough interface, try to increase CFG_TUH_HID + // TODO multiple devices + hidh_device_t* hid_dev = get_dev(dev_addr); + TU_ASSERT(hid_dev->inst_count < CFG_TUH_HID, 0); + + hidh_interface_t* hid_itf = get_instance(dev_addr, hid_dev->inst_count); + + //------------- Endpoint Descriptors -------------// + p_desc = tu_desc_next(p_desc); + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; + + for(int i = 0; i < desc_itf->bNumEndpoints; i++) + { + TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType); + TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) ); + + if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) + { + hid_itf->ep_in = desc_ep->bEndpointAddress; + hid_itf->epin_size = tu_edpt_packet_size(desc_ep); + } + else + { + hid_itf->ep_out = desc_ep->bEndpointAddress; + hid_itf->epout_size = tu_edpt_packet_size(desc_ep); + } + + p_desc = tu_desc_next(p_desc); + desc_ep = (tusb_desc_endpoint_t const *) p_desc; + } + + hid_dev->inst_count++; + + hid_itf->itf_num = desc_itf->bInterfaceNumber; + + // Assume bNumDescriptors = 1 + hid_itf->report_desc_type = desc_hid->bReportType; + hid_itf->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength); + + // Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config + hid_itf->protocol_mode = HID_PROTOCOL_BOOT; + if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass ) hid_itf->itf_protocol = desc_itf->bInterfaceProtocol; + + return true; +} + +//--------------------------------------------------------------------+ +// Set Configure +//--------------------------------------------------------------------+ + +enum { + CONFG_SET_IDLE, + CONFIG_SET_PROTOCOL, + CONFIG_GET_REPORT_DESC, + CONFIG_COMPLETE +}; + +static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len); +static void process_set_config(tuh_xfer_t* xfer); + +bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num) +{ + tusb_control_request_t request; + request.wIndex = tu_htole16((uint16_t) itf_num); + + tuh_xfer_t xfer; + xfer.daddr = dev_addr; + xfer.result = XFER_RESULT_SUCCESS; + xfer.setup = &request; + xfer.user_data = CONFG_SET_IDLE; + + // fake request to kick-off the set config process + process_set_config(&xfer); + + return true; +} + +static void process_set_config(tuh_xfer_t* xfer) +{ + // Stall is a valid response for SET_IDLE, therefore we could ignore its result + if ( xfer->setup->bRequest != HID_REQ_CONTROL_SET_IDLE ) + { + TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, ); + } + + uintptr_t const state = xfer->user_data; + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const daddr = xfer->daddr; + + uint8_t const instance = get_instance_id_by_itfnum(daddr, itf_num); + hidh_interface_t* hid_itf = get_instance(daddr, instance); + + switch(state) + { + case CONFG_SET_IDLE: + { + // Idle rate = 0 mean only report when there is changes + const uint16_t idle_rate = 0; + const uintptr_t next_state = (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? CONFIG_SET_PROTOCOL : CONFIG_GET_REPORT_DESC; + _hidh_set_idle(daddr, itf_num, idle_rate, process_set_config, next_state); + } + break; + + case CONFIG_SET_PROTOCOL: + _hidh_set_protocol(daddr, hid_itf->itf_num, HID_PROTOCOL_BOOT, process_set_config, CONFIG_GET_REPORT_DESC); + break; + + case CONFIG_GET_REPORT_DESC: + // Get Report Descriptor if possible + // using usbh enumeration buffer since report descriptor can be very long + if( hid_itf->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE ) + { + TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", hid_itf->report_desc_len); + + // Driver is mounted without report descriptor + config_driver_mount_complete(daddr, instance, NULL, 0); + }else + { + tuh_descriptor_get_hid_report(daddr, itf_num, hid_itf->report_desc_type, 0, usbh_get_enum_buf(), hid_itf->report_desc_len, process_set_config, CONFIG_COMPLETE); + } + break; + + case CONFIG_COMPLETE: + { + uint8_t const* desc_report = usbh_get_enum_buf(); + uint16_t const desc_len = tu_le16toh(xfer->setup->wLength); + + config_driver_mount_complete(daddr, instance, desc_report, desc_len); + } + break; + + default: break; + } +} + +static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + + // enumeration is complete + tuh_hid_mount_cb(dev_addr, instance, desc_report, desc_len); + + // notify usbh that driver enumeration is complete + usbh_driver_set_config_complete(dev_addr, hid_itf->itf_num); +} + +//--------------------------------------------------------------------+ +// Report Descriptor Parser +//--------------------------------------------------------------------+ + +uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) +{ + // Report Item 6.2.2.2 USB HID 1.11 + union TU_ATTR_PACKED + { + uint8_t byte; + struct TU_ATTR_PACKED + { + uint8_t size : 2; + uint8_t type : 2; + uint8_t tag : 4; + }; + } header; + + tu_memclr(report_info_arr, arr_count*sizeof(tuh_hid_report_info_t)); + + uint8_t report_num = 0; + tuh_hid_report_info_t* info = report_info_arr; + + // current parsed report count & size from descriptor +// uint8_t ri_report_count = 0; +// uint8_t ri_report_size = 0; + + uint8_t ri_collection_depth = 0; + + while(desc_len && report_num < arr_count) + { + header.byte = *desc_report++; + desc_len--; + + uint8_t const tag = header.tag; + uint8_t const type = header.type; + uint8_t const size = header.size; + + uint8_t const data8 = desc_report[0]; + + TU_LOG(3, "tag = %d, type = %d, size = %d, data = ", tag, type, size); + for(uint32_t i=0; iusage_page, desc_report, size); + break; + + case RI_GLOBAL_LOGICAL_MIN : break; + case RI_GLOBAL_LOGICAL_MAX : break; + case RI_GLOBAL_PHYSICAL_MIN : break; + case RI_GLOBAL_PHYSICAL_MAX : break; + + case RI_GLOBAL_REPORT_ID: + info->report_id = data8; + break; + + case RI_GLOBAL_REPORT_SIZE: +// ri_report_size = data8; + break; + + case RI_GLOBAL_REPORT_COUNT: +// ri_report_count = data8; + break; + + case RI_GLOBAL_UNIT_EXPONENT : break; + case RI_GLOBAL_UNIT : break; + case RI_GLOBAL_PUSH : break; + case RI_GLOBAL_POP : break; + + default: break; + } + break; + + case RI_TYPE_LOCAL: + switch(tag) + { + case RI_LOCAL_USAGE: + // only take in account the "usage" before starting REPORT ID + if ( ri_collection_depth == 0 ) info->usage = data8; + break; + + case RI_LOCAL_USAGE_MIN : break; + case RI_LOCAL_USAGE_MAX : break; + case RI_LOCAL_DESIGNATOR_INDEX : break; + case RI_LOCAL_DESIGNATOR_MIN : break; + case RI_LOCAL_DESIGNATOR_MAX : break; + case RI_LOCAL_STRING_INDEX : break; + case RI_LOCAL_STRING_MIN : break; + case RI_LOCAL_STRING_MAX : break; + case RI_LOCAL_DELIMITER : break; + default: break; + } + break; + + // error + default: break; + } + + desc_report += size; + desc_len -= size; + } + + for ( uint8_t i = 0; i < report_num; i++ ) + { + info = report_info_arr+i; + TU_LOG2("%u: id = %u, usage_page = %u, usage = %u\r\n", i, info->report_id, info->usage_page, info->usage); + } + + return report_num; +} + +//--------------------------------------------------------------------+ +// Helper +//--------------------------------------------------------------------+ + +// Get Device by address +TU_ATTR_ALWAYS_INLINE static inline hidh_device_t* get_dev(uint8_t dev_addr) +{ + return &_hidh_dev[dev_addr-1]; +} + +// Get Interface by instance number +TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_instance(uint8_t dev_addr, uint8_t instance) +{ + return &_hidh_dev[dev_addr-1].instances[instance]; +} + +// Get instance ID by interface number +static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf) +{ + for ( uint8_t inst = 0; inst < CFG_TUH_HID; inst++ ) + { + hidh_interface_t *hid = get_instance(dev_addr, inst); + + if ( (hid->itf_num == itf) && (hid->ep_in || hid->ep_out) ) return inst; + } + + return 0xff; +} + +// Get instance ID by endpoint address +static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr) +{ + for ( uint8_t inst = 0; inst < CFG_TUH_HID; inst++ ) + { + hidh_interface_t *hid = get_instance(dev_addr, inst); + + if ( (ep_addr == hid->ep_in) || ( ep_addr == hid->ep_out) ) return inst; + } + + return 0xff; +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.h b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.h new file mode 100644 index 00000000..fe09b03b --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.h @@ -0,0 +1,152 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_HID_HOST_H_ +#define _TUSB_HID_HOST_H_ + +#include "hid.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Class Driver Configuration +//--------------------------------------------------------------------+ + +// TODO Highspeed interrupt can be up to 512 bytes +#ifndef CFG_TUH_HID_EPIN_BUFSIZE +#define CFG_TUH_HID_EPIN_BUFSIZE 64 +#endif + +#ifndef CFG_TUH_HID_EPOUT_BUFSIZE +#define CFG_TUH_HID_EPOUT_BUFSIZE 64 +#endif + + +typedef struct +{ + uint8_t report_id; + uint8_t usage; + uint16_t usage_page; + + // TODO still use the endpoint size for now +// uint8_t in_len; // length of IN report +// uint8_t out_len; // length of OUT report +} tuh_hid_report_info_t; + +//--------------------------------------------------------------------+ +// Interface API +//--------------------------------------------------------------------+ + +// Get the number of HID instances +uint8_t tuh_hid_instance_count(uint8_t dev_addr); + +// Check if HID instance is mounted +bool tuh_hid_mounted(uint8_t dev_addr, uint8_t instance); + +// Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values +uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance); + +// Parse report descriptor into array of report_info struct and return number of reports. +// For complicated report, application should write its own parser. +uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED; + +//--------------------------------------------------------------------+ +// Control Endpoint API +//--------------------------------------------------------------------+ + +// Get current protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) +// Note: Device will be initialized in Boot protocol for simplicity. +// Application can use set_protocol() to switch back to Report protocol. +uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance); + +// Set protocol to HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) +// This function is only supported by Boot interface (tuh_n_hid_interface_protocol() != NONE) +bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol); + +// Set Report using control endpoint +// report_type is either Intput, Output or Feature, (value from hid_report_type_t) +bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, void* report, uint16_t len); + +//--------------------------------------------------------------------+ +// Interrupt Endpoint API +//--------------------------------------------------------------------+ + +// Check if the interface is ready to use +//bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance); + +// Try to receive next report on Interrupt Endpoint. Immediately return +// - true If succeeded, tuh_hid_report_received_cb() callback will be invoked when report is available +// - false if failed to queue the transfer e.g endpoint is busy +bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance); + +// Send report using interrupt endpoint +// If report_id > 0 (composite), it will be sent as 1st byte, then report contents. Otherwise only report content is sent. +//void tuh_hid_send_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t const* report, uint16_t len); + +//--------------------------------------------------------------------+ +// Callbacks (Weak is optional) +//--------------------------------------------------------------------+ + +// Invoked when device with hid interface is mounted +// Report descriptor is also available for use. tuh_hid_parse_report_descriptor() +// can be used to parse common/simple enough descriptor. +// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped +// therefore report_desc = NULL, desc_len = 0 +void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report_desc, uint16_t desc_len); + +// Invoked when device with hid interface is un-mounted +TU_ATTR_WEAK void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance); + +// Invoked when received report from device via interrupt endpoint +// Note: if there is report ID (composite), it is 1st byte of report +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); + +// Invoked when sent report to device successfully via interrupt endpoint +TU_ATTR_WEAK void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); + +// Invoked when Sent Report to device via either control endpoint +// len = 0 indicate there is error in the transfer e.g stalled response +TU_ATTR_WEAK void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len); + +// Invoked when Set Protocol request is complete +TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t protocol); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void hidh_init (void); +bool hidh_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); +bool hidh_set_config (uint8_t dev_addr, uint8_t itf_num); +bool hidh_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); +void hidh_close (uint8_t dev_addr); + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_HID_HOST_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/midi/midi.h b/test-devices/composite-stm32/lib/tinyusb/class/midi/midi.h new file mode 100644 index 00000000..74dc4174 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/midi/midi.h @@ -0,0 +1,212 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup group_class + * \defgroup ClassDriver_CDC Communication Device Class (CDC) + * Currently only Abstract Control Model subclass is supported + * @{ */ + +#ifndef _TUSB_MIDI_H__ +#define _TUSB_MIDI_H__ + +#include "common/tusb_common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Class Specific Descriptor +//--------------------------------------------------------------------+ + +typedef enum +{ + MIDI_CS_INTERFACE_HEADER = 0x01, + MIDI_CS_INTERFACE_IN_JACK = 0x02, + MIDI_CS_INTERFACE_OUT_JACK = 0x03, + MIDI_CS_INTERFACE_ELEMENT = 0x04, +} midi_cs_interface_subtype_t; + +typedef enum +{ + MIDI_CS_ENDPOINT_GENERAL = 0x01 +} midi_cs_endpoint_subtype_t; + +typedef enum +{ + MIDI_JACK_EMBEDDED = 0x01, + MIDI_JACK_EXTERNAL = 0x02 +} midi_jack_type_t; + +typedef enum +{ + MIDI_CIN_MISC = 0, + MIDI_CIN_CABLE_EVENT = 1, + MIDI_CIN_SYSCOM_2BYTE = 2, // 2 byte system common message e.g MTC, SongSelect + MIDI_CIN_SYSCOM_3BYTE = 3, // 3 byte system common message e.g SPP + MIDI_CIN_SYSEX_START = 4, // SysEx starts or continue + MIDI_CIN_SYSEX_END_1BYTE = 5, // SysEx ends with 1 data, or 1 byte system common message + MIDI_CIN_SYSEX_END_2BYTE = 6, // SysEx ends with 2 data + MIDI_CIN_SYSEX_END_3BYTE = 7, // SysEx ends with 3 data + MIDI_CIN_NOTE_ON = 8, + MIDI_CIN_NOTE_OFF = 9, + MIDI_CIN_POLY_KEYPRESS = 10, + MIDI_CIN_CONTROL_CHANGE = 11, + MIDI_CIN_PROGRAM_CHANGE = 12, + MIDI_CIN_CHANNEL_PRESSURE = 13, + MIDI_CIN_PITCH_BEND_CHANGE = 14, + MIDI_CIN_1BYTE_DATA = 15 +} midi_code_index_number_t; + +// MIDI 1.0 status byte +enum +{ + //------------- System Exclusive -------------// + MIDI_STATUS_SYSEX_START = 0xF0, + MIDI_STATUS_SYSEX_END = 0xF7, + + //------------- System Common -------------// + MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME = 0xF1, + MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER = 0xF2, + MIDI_STATUS_SYSCOM_SONG_SELECT = 0xF3, + // F4, F5 is undefined + MIDI_STATUS_SYSCOM_TUNE_REQUEST = 0xF6, + + //------------- System RealTime -------------// + MIDI_STATUS_SYSREAL_TIMING_CLOCK = 0xF8, + // 0xF9 is undefined + MIDI_STATUS_SYSREAL_START = 0xFA, + MIDI_STATUS_SYSREAL_CONTINUE = 0xFB, + MIDI_STATUS_SYSREAL_STOP = 0xFC, + // 0xFD is undefined + MIDI_STATUS_SYSREAL_ACTIVE_SENSING = 0xFE, + MIDI_STATUS_SYSREAL_SYSTEM_RESET = 0xFF, +}; + +/// MIDI Interface Header Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType + uint16_t bcdMSC ; ///< MidiStreaming SubClass release number in Binary-Coded Decimal + uint16_t wTotalLength ; +} midi_desc_header_t; + +/// MIDI In Jack Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType + uint8_t bJackType ; ///< Embedded or External + uint8_t bJackID ; ///< Unique ID for MIDI IN Jack + uint8_t iJack ; ///< string descriptor +} midi_desc_in_jack_t; + + +/// MIDI Out Jack Descriptor with single pin +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType + uint8_t bJackType ; ///< Embedded or External + uint8_t bJackID ; ///< Unique ID for MIDI IN Jack + uint8_t bNrInputPins; + + uint8_t baSourceID; + uint8_t baSourcePin; + + uint8_t iJack ; ///< string descriptor +} midi_desc_out_jack_t ; + +/// MIDI Out Jack Descriptor with multiple pins +#define midi_desc_out_jack_n_t(input_num) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength ; \ + uint8_t bDescriptorType ; \ + uint8_t bDescriptorSubType ; \ + uint8_t bJackType ; \ + uint8_t bJackID ; \ + uint8_t bNrInputPins ; \ + struct TU_ATTR_PACKED { \ + uint8_t baSourceID; \ + uint8_t baSourcePin; \ + } pins[input_num]; \ + uint8_t iJack ; \ + } + +/// MIDI Element Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType + uint8_t bElementID; + + uint8_t bNrInputPins; + uint8_t baSourceID; + uint8_t baSourcePin; + + uint8_t bNrOutputPins; + uint8_t bInTerminalLink; + uint8_t bOutTerminalLink; + uint8_t bElCapsSize; + + uint16_t bmElementCaps; + uint8_t iElement; +} midi_desc_element_t; + +/// MIDI Element Descriptor with multiple pins +#define midi_desc_element_n_t(input_num) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint8_t bDescriptorSubType; \ + uint8_t bElementID; \ + uint8_t bNrInputPins; \ + struct TU_ATTR_PACKED { \ + uint8_t baSourceID; \ + uint8_t baSourcePin; \ + } pins[input_num]; \ + uint8_t bNrOutputPins; \ + uint8_t bInTerminalLink; \ + uint8_t bOutTerminalLink; \ + uint8_t bElCapsSize; \ + uint16_t bmElementCaps; \ + uint8_t iElement; \ + } + +/** @} */ + +#ifdef __cplusplus + } +#endif + +#endif + +/** @} */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.c b/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.c new file mode 100644 index 00000000..de41706e --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.c @@ -0,0 +1,545 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_MIDI) + +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "midi_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +typedef struct +{ + uint8_t buffer[4]; + uint8_t index; + uint8_t total; +}midid_stream_t; + +typedef struct +{ + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; + + // For Stream read()/write() API + // Messages are always 4 bytes long, queue them for reading and writing so the + // callers can use the Stream interface with single-byte read/write calls. + midid_stream_t stream_write; + midid_stream_t stream_read; + + /*------------- From this point, data is not cleared by bus reset -------------*/ + // FIFO + tu_fifo_t rx_ff; + tu_fifo_t tx_ff; + uint8_t rx_ff_buf[CFG_TUD_MIDI_RX_BUFSIZE]; + uint8_t tx_ff_buf[CFG_TUD_MIDI_TX_BUFSIZE]; + + #if CFG_FIFO_MUTEX + osal_mutex_def_t rx_ff_mutex; + osal_mutex_def_t tx_ff_mutex; + #endif + + // Endpoint Transfer buffer + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_MIDI_EP_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_MIDI_EP_BUFSIZE]; + +} midid_interface_t; + +#define ITF_MEM_RESET_SIZE offsetof(midid_interface_t, rx_ff) + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +CFG_TUSB_MEM_SECTION midid_interface_t _midid_itf[CFG_TUD_MIDI]; + +bool tud_midi_n_mounted (uint8_t itf) +{ + midid_interface_t* midi = &_midid_itf[itf]; + return midi->ep_in && midi->ep_out; +} + +static void _prep_out_transaction (midid_interface_t* p_midi) +{ + uint8_t const rhport = 0; + uint16_t available = tu_fifo_remaining(&p_midi->rx_ff); + + // Prepare for incoming data but only allow what we can store in the ring buffer. + // TODO Actually we can still carry out the transfer, keeping count of received bytes + // and slowly move it to the FIFO when read(). + // This pre-check reduces endpoint claiming + TU_VERIFY(available >= sizeof(p_midi->epout_buf), ); + + // claim endpoint + TU_VERIFY(usbd_edpt_claim(rhport, p_midi->ep_out), ); + + // fifo can be changed before endpoint is claimed + available = tu_fifo_remaining(&p_midi->rx_ff); + + if ( available >= sizeof(p_midi->epout_buf) ) { + usbd_edpt_xfer(rhport, p_midi->ep_out, p_midi->epout_buf, sizeof(p_midi->epout_buf)); + }else + { + // Release endpoint since we don't make any transfer + usbd_edpt_release(rhport, p_midi->ep_out); + } +} + +//--------------------------------------------------------------------+ +// READ API +//--------------------------------------------------------------------+ +uint32_t tud_midi_n_available(uint8_t itf, uint8_t cable_num) +{ + (void) cable_num; + + midid_interface_t* midi = &_midid_itf[itf]; + midid_stream_t const* stream = &midi->stream_read; + + // when using with packet API stream total & index are both zero + return tu_fifo_count(&midi->rx_ff) + (uint8_t) (stream->total - stream->index); +} + +uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize) +{ + (void) cable_num; + TU_VERIFY(bufsize, 0); + + uint8_t* buf8 = (uint8_t*) buffer; + + midid_interface_t* midi = &_midid_itf[itf]; + midid_stream_t* stream = &midi->stream_read; + + uint32_t total_read = 0; + while( bufsize ) + { + // Get new packet from fifo, then set packet expected bytes + if ( stream->total == 0 ) + { + // return if there is no more data from fifo + if ( !tud_midi_n_packet_read(itf, stream->buffer) ) return total_read; + + uint8_t const code_index = stream->buffer[0] & 0x0f; + + // MIDI 1.0 Table 4-1: Code Index Number Classifications + switch(code_index) + { + case MIDI_CIN_MISC: + case MIDI_CIN_CABLE_EVENT: + // These are reserved and unused, possibly issue somewhere, skip this packet + return 0; + break; + + case MIDI_CIN_SYSEX_END_1BYTE: + case MIDI_CIN_1BYTE_DATA: + stream->total = 1; + break; + + case MIDI_CIN_SYSCOM_2BYTE : + case MIDI_CIN_SYSEX_END_2BYTE : + case MIDI_CIN_PROGRAM_CHANGE : + case MIDI_CIN_CHANNEL_PRESSURE : + stream->total = 2; + break; + + default: + stream->total = 3; + break; + } + } + + // Copy data up to bufsize + uint8_t const count = (uint8_t) tu_min32(stream->total - stream->index, bufsize); + + // Skip the header (1st byte) in the buffer + memcpy(buf8, stream->buffer + 1 + stream->index, count); + + total_read += count; + stream->index += count; + buf8 += count; + bufsize -= count; + + // complete current event packet, reset stream + if ( stream->total == stream->index ) + { + stream->index = 0; + stream->total = 0; + } + } + + return total_read; +} + +bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]) +{ + midid_interface_t* midi = &_midid_itf[itf]; + TU_VERIFY(midi->ep_out); + + uint32_t const num_read = tu_fifo_read_n(&midi->rx_ff, packet, 4); + _prep_out_transaction(midi); + return (num_read == 4); +} + +//--------------------------------------------------------------------+ +// WRITE API +//--------------------------------------------------------------------+ + +static uint32_t write_flush(midid_interface_t* midi) +{ + // No data to send + if ( !tu_fifo_count(&midi->tx_ff) ) return 0; + + uint8_t const rhport = 0; + + // skip if previous transfer not complete + TU_VERIFY( usbd_edpt_claim(rhport, midi->ep_in), 0 ); + + uint16_t count = tu_fifo_read_n(&midi->tx_ff, midi->epin_buf, CFG_TUD_MIDI_EP_BUFSIZE); + + if (count) + { + TU_ASSERT( usbd_edpt_xfer(rhport, midi->ep_in, midi->epin_buf, count), 0 ); + return count; + }else + { + // Release endpoint since we don't make any transfer + usbd_edpt_release(rhport, midi->ep_in); + return 0; + } +} + +uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) +{ + midid_interface_t* midi = &_midid_itf[itf]; + TU_VERIFY(midi->ep_in, 0); + + midid_stream_t* stream = &midi->stream_write; + + uint32_t i = 0; + while ( (i < bufsize) && (tu_fifo_remaining(&midi->tx_ff) >= 4) ) + { + uint8_t const data = buffer[i]; + i++; + + if ( stream->index == 0 ) + { + //------------- New event packet -------------// + + uint8_t const msg = data >> 4; + + stream->index = 2; + stream->buffer[1] = data; + + // Check to see if we're still in a SysEx transmit. + if ( stream->buffer[0] == MIDI_CIN_SYSEX_START ) + { + if ( data == MIDI_STATUS_SYSEX_END ) + { + stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; + stream->total = 2; + } + else + { + stream->total = 4; + } + } + else if ( (msg >= 0x8 && msg <= 0xB) || msg == 0xE ) + { + // Channel Voice Messages + stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg); + stream->total = 4; + } + else if ( msg == 0xC || msg == 0xD) + { + // Channel Voice Messages, two-byte variants (Program Change and Channel Pressure) + stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg); + stream->total = 3; + } + else if ( msg == 0xf ) + { + // System message + if ( data == MIDI_STATUS_SYSEX_START ) + { + stream->buffer[0] = MIDI_CIN_SYSEX_START; + stream->total = 4; + } + else if ( data == MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME || data == MIDI_STATUS_SYSCOM_SONG_SELECT ) + { + stream->buffer[0] = MIDI_CIN_SYSCOM_2BYTE; + stream->total = 3; + } + else if ( data == MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER ) + { + stream->buffer[0] = MIDI_CIN_SYSCOM_3BYTE; + stream->total = 4; + } + else + { + stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; + stream->total = 2; + } + } + else + { + // Pack individual bytes if we don't support packing them into words. + stream->buffer[0] = (uint8_t) (cable_num << 4 | 0xf); + stream->buffer[2] = 0; + stream->buffer[3] = 0; + stream->index = 2; + stream->total = 2; + } + } + else + { + //------------- On-going (buffering) packet -------------// + + TU_ASSERT(stream->index < 4, i); + stream->buffer[stream->index] = data; + stream->index++; + + // See if this byte ends a SysEx. + if ( stream->buffer[0] == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END ) + { + stream->buffer[0] = MIDI_CIN_SYSEX_START + (stream->index - 1); + stream->total = stream->index; + } + } + + // Send out packet + if ( stream->index == stream->total ) + { + // zeroes unused bytes + for(uint8_t idx = stream->total; idx < 4; idx++) stream->buffer[idx] = 0; + + uint16_t const count = tu_fifo_write_n(&midi->tx_ff, stream->buffer, 4); + + // complete current event packet, reset stream + stream->index = stream->total = 0; + + // FIFO overflown, since we already check fifo remaining. It is probably race condition + TU_ASSERT(count == 4, i); + } + } + + write_flush(midi); + + return i; +} + +bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]) +{ + midid_interface_t* midi = &_midid_itf[itf]; + TU_VERIFY(midi->ep_in); + + if (tu_fifo_remaining(&midi->tx_ff) < 4) return false; + + tu_fifo_write_n(&midi->tx_ff, packet, 4); + write_flush(midi); + + return true; +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void midid_init(void) +{ + tu_memclr(_midid_itf, sizeof(_midid_itf)); + + for(uint8_t i=0; irx_ff, midi->rx_ff_buf, CFG_TUD_MIDI_RX_BUFSIZE, 1, false); // true, true + tu_fifo_config(&midi->tx_ff, midi->tx_ff_buf, CFG_TUD_MIDI_TX_BUFSIZE, 1, false); // OBVS. + + #if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&midi->rx_ff, NULL, osal_mutex_create(&midi->rx_ff_mutex)); + tu_fifo_config_mutex(&midi->tx_ff, osal_mutex_create(&midi->tx_ff_mutex), NULL); + #endif + } +} + +void midid_reset(uint8_t rhport) +{ + (void) rhport; + + for(uint8_t i=0; irx_ff); + tu_fifo_clear(&midi->tx_ff); + } +} + +uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) +{ + // 1st Interface is Audio Control v1 + TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass && + AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass && + AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_itf->bInterfaceProtocol, 0); + + uint16_t drv_len = tu_desc_len(desc_itf); + uint8_t const * p_desc = tu_desc_next(desc_itf); + + // Skip Class Specific descriptors + while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) + { + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + // 2nd Interface is MIDI Streaming + TU_VERIFY(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); + tusb_desc_interface_t const * desc_midi = (tusb_desc_interface_t const *) p_desc; + + TU_VERIFY(TUSB_CLASS_AUDIO == desc_midi->bInterfaceClass && + AUDIO_SUBCLASS_MIDI_STREAMING == desc_midi->bInterfaceSubClass && + AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_midi->bInterfaceProtocol, 0); + + // Find available interface + midid_interface_t * p_midi = NULL; + for(uint8_t i=0; iitf_num = desc_midi->bInterfaceNumber; + (void) p_midi->itf_num; + + // next descriptor + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + + // Find and open endpoint descriptors + uint8_t found_endpoints = 0; + while ( (found_endpoints < desc_midi->bNumEndpoints) && (drv_len <= max_len) ) + { + if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + { + TU_ASSERT(usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0); + uint8_t ep_addr = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; + + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) + { + p_midi->ep_in = ep_addr; + } else { + p_midi->ep_out = ep_addr; + } + + // Class Specific MIDI Stream endpoint descriptor + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + + found_endpoints += 1; + } + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + // Prepare for incoming data + _prep_out_transaction(p_midi); + + return drv_len; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool midid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + (void) rhport; + (void) stage; + (void) request; + + // driver doesn't support any request yet + return false; +} + +bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) result; + (void) rhport; + + uint8_t itf; + midid_interface_t* p_midi; + + // Identify which interface to use + for (itf = 0; itf < CFG_TUD_MIDI; itf++) + { + p_midi = &_midid_itf[itf]; + if ( ( ep_addr == p_midi->ep_out ) || ( ep_addr == p_midi->ep_in ) ) break; + } + TU_ASSERT(itf < CFG_TUD_MIDI); + + // receive new data + if ( ep_addr == p_midi->ep_out ) + { + tu_fifo_write_n(&p_midi->rx_ff, p_midi->epout_buf, (uint16_t) xferred_bytes); + + // invoke receive callback if available + if (tud_midi_rx_cb) tud_midi_rx_cb(itf); + + // prepare for next + // TODO for now ep_out is not used by public API therefore there is no race condition, + // and does not need to claim like ep_in + _prep_out_transaction(p_midi); + } + else if ( ep_addr == p_midi->ep_in ) + { + if (0 == write_flush(p_midi)) + { + // If there is no data left, a ZLP should be sent if + // xferred_bytes is multiple of EP size and not zero + if ( !tu_fifo_count(&p_midi->tx_ff) && xferred_bytes && (0 == (xferred_bytes % CFG_TUD_MIDI_EP_BUFSIZE)) ) + { + if ( usbd_edpt_claim(rhport, p_midi->ep_in) ) + { + usbd_edpt_xfer(rhport, p_midi->ep_in, NULL, 0); + } + } + } + } + + return true; +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.h b/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.h new file mode 100644 index 00000000..211edc8d --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.h @@ -0,0 +1,173 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_MIDI_DEVICE_H_ +#define _TUSB_MIDI_DEVICE_H_ + +#include "class/audio/audio.h" +#include "midi.h" + +//--------------------------------------------------------------------+ +// Class Driver Configuration +//--------------------------------------------------------------------+ + +#if !defined(CFG_TUD_MIDI_EP_BUFSIZE) && defined(CFG_TUD_MIDI_EPSIZE) + #warning CFG_TUD_MIDI_EPSIZE is renamed to CFG_TUD_MIDI_EP_BUFSIZE, please update to use the new name + #define CFG_TUD_MIDI_EP_BUFSIZE CFG_TUD_MIDI_EPSIZE +#endif + +#ifndef CFG_TUD_MIDI_EP_BUFSIZE + #define CFG_TUD_MIDI_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +/** \addtogroup MIDI_Serial Serial + * @{ + * \defgroup MIDI_Serial_Device Device + * @{ */ + +//--------------------------------------------------------------------+ +// Application API (Multiple Interfaces) +// CFG_TUD_MIDI > 1 +//--------------------------------------------------------------------+ + +// Check if midi interface is mounted +bool tud_midi_n_mounted (uint8_t itf); + +// Get the number of bytes available for reading +uint32_t tud_midi_n_available (uint8_t itf, uint8_t cable_num); + +// Read byte stream (legacy) +uint32_t tud_midi_n_stream_read (uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize); + +// Write byte Stream (legacy) +uint32_t tud_midi_n_stream_write (uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); + +// Read event packet (4 bytes) +bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]); + +// Write event packet (4 bytes) +bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]); + +//--------------------------------------------------------------------+ +// Application API (Single Interface) +//--------------------------------------------------------------------+ +static inline bool tud_midi_mounted (void); +static inline uint32_t tud_midi_available (void); + +static inline uint32_t tud_midi_stream_read (void* buffer, uint32_t bufsize); +static inline uint32_t tud_midi_stream_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); + +static inline bool tud_midi_packet_read (uint8_t packet[4]); +static inline bool tud_midi_packet_write (uint8_t const packet[4]); + +//------------- Deprecated API name -------------// +// TODO remove after 0.10.0 release + +TU_ATTR_DEPRECATED("tud_midi_read() is renamed to tud_midi_stream_read()") +static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize) +{ + return tud_midi_stream_read(buffer, bufsize); +} + +TU_ATTR_DEPRECATED("tud_midi_write() is renamed to tud_midi_stream_write()") +static inline uint32_t tud_midi_write(uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) +{ + return tud_midi_stream_write(cable_num, buffer, bufsize); +} + + +TU_ATTR_DEPRECATED("tud_midi_send() is renamed to tud_midi_packet_write()") +static inline bool tud_midi_send(uint8_t packet[4]) +{ + return tud_midi_packet_write(packet); +} + +TU_ATTR_DEPRECATED("tud_midi_receive() is renamed to tud_midi_packet_read()") +static inline bool tud_midi_receive(uint8_t packet[4]) +{ + return tud_midi_packet_read(packet); +} + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tud_midi_rx_cb(uint8_t itf); + +//--------------------------------------------------------------------+ +// Inline Functions +//--------------------------------------------------------------------+ + +static inline bool tud_midi_mounted (void) +{ + return tud_midi_n_mounted(0); +} + +static inline uint32_t tud_midi_available (void) +{ + return tud_midi_n_available(0, 0); +} + +static inline uint32_t tud_midi_stream_read (void* buffer, uint32_t bufsize) +{ + return tud_midi_n_stream_read(0, 0, buffer, bufsize); +} + +static inline uint32_t tud_midi_stream_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) +{ + return tud_midi_n_stream_write(0, cable_num, buffer, bufsize); +} + +static inline bool tud_midi_packet_read (uint8_t packet[4]) +{ + return tud_midi_n_packet_read(0, packet); +} + +static inline bool tud_midi_packet_write (uint8_t const packet[4]) +{ + return tud_midi_n_packet_write(0, packet); +} + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void midid_init (void); +void midid_reset (uint8_t rhport); +uint16_t midid_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool midid_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +bool midid_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_MIDI_DEVICE_H_ */ + +/** @} */ +/** @} */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc.h b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc.h new file mode 100644 index 00000000..84b6e4d7 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc.h @@ -0,0 +1,382 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_MSC_H_ +#define _TUSB_MSC_H_ + +#include "common/tusb_common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Mass Storage Class Constant +//--------------------------------------------------------------------+ +/// MassStorage Subclass +typedef enum +{ + MSC_SUBCLASS_RBC = 1 , ///< Reduced Block Commands (RBC) T10 Project 1240-D + MSC_SUBCLASS_SFF_MMC , ///< SFF-8020i, MMC-2 (ATAPI). Typically used by a CD/DVD device + MSC_SUBCLASS_QIC , ///< QIC-157. Typically used by a tape device + MSC_SUBCLASS_UFI , ///< UFI. Typically used by Floppy Disk Drive (FDD) device + MSC_SUBCLASS_SFF , ///< SFF-8070i. Can be used by Floppy Disk Drive (FDD) device + MSC_SUBCLASS_SCSI ///< SCSI transparent command set +}msc_subclass_type_t; + +enum { + MSC_CBW_SIGNATURE = 0x43425355, ///< Constant value of 43425355h (little endian) + MSC_CSW_SIGNATURE = 0x53425355 ///< Constant value of 53425355h (little endian) +}; + +/// \brief MassStorage Protocol. +/// \details CBI only approved to use with full-speed floopy disk & should not used with highspeed or device other than floopy +typedef enum +{ + MSC_PROTOCOL_CBI = 0 , ///< Control/Bulk/Interrupt protocol (with command completion interrupt) + MSC_PROTOCOL_CBI_NO_INTERRUPT = 1 , ///< Control/Bulk/Interrupt protocol (without command completion interrupt) + MSC_PROTOCOL_BOT = 0x50 ///< Bulk-Only Transport +}msc_protocol_type_t; + +/// MassStorage Class-Specific Control Request +typedef enum +{ + MSC_REQ_GET_MAX_LUN = 254, ///< The Get Max LUN device request is used to determine the number of logical units supported by the device. Logical Unit Numbers on the device shall be numbered contiguously starting from LUN 0 to a maximum LUN of 15 + MSC_REQ_RESET = 255 ///< This request is used to reset the mass storage device and its associated interface. This class-specific request shall ready the device for the next CBW from the host. +}msc_request_type_t; + +/// \brief Command Block Status Values +/// \details Indicates the success or failure of the command. The device shall set this byte to zero if the command completed +/// successfully. A non-zero value shall indicate a failure during command execution according to the following +typedef enum +{ + MSC_CSW_STATUS_PASSED = 0 , ///< MSC_CSW_STATUS_PASSED + MSC_CSW_STATUS_FAILED , ///< MSC_CSW_STATUS_FAILED + MSC_CSW_STATUS_PHASE_ERROR ///< MSC_CSW_STATUS_PHASE_ERROR +}msc_csw_status_t; + +/// Command Block Wrapper +typedef struct TU_ATTR_PACKED +{ + uint32_t signature; ///< Signature that helps identify this data packet as a CBW. The signature field shall contain the value 43425355h (little endian), indicating a CBW. + uint32_t tag; ///< Tag sent by the host. The device shall echo the contents of this field back to the host in the dCSWTagfield of the associated CSW. The dCSWTagpositively associates a CSW with the corresponding CBW. + uint32_t total_bytes; ///< The number of bytes of data that the host expects to transfer on the Bulk-In or Bulk-Out endpoint (as indicated by the Direction bit) during the execution of this command. If this field is zero, the device and the host shall transfer no data between the CBW and the associated CSW, and the device shall ignore the value of the Direction bit in bmCBWFlags. + uint8_t dir; ///< Bit 7 of this field define transfer direction \n - 0 : Data-Out from host to the device. \n - 1 : Data-In from the device to the host. + uint8_t lun; ///< The device Logical Unit Number (LUN) to which the command block is being sent. For devices that support multiple LUNs, the host shall place into this field the LUN to which this command block is addressed. Otherwise, the host shall set this field to zero. + uint8_t cmd_len; ///< The valid length of the CBWCBin bytes. This defines the valid length of the command block. The only legal values are 1 through 16 + uint8_t command[16]; ///< The command block to be executed by the device. The device shall interpret the first cmd_len bytes in this field as a command block +}msc_cbw_t; + +TU_VERIFY_STATIC(sizeof(msc_cbw_t) == 31, "size is not correct"); + +/// Command Status Wrapper +typedef struct TU_ATTR_PACKED +{ + uint32_t signature ; ///< Signature that helps identify this data packet as a CSW. The signature field shall contain the value 53425355h (little endian), indicating CSW. + uint32_t tag ; ///< The device shall set this field to the value received in the dCBWTag of the associated CBW. + uint32_t data_residue ; ///< For Data-Out the device shall report in the dCSWDataResiduethe difference between the amount of data expected as stated in the dCBWDataTransferLength, and the actual amount of data processed by the device. For Data-In the device shall report in the dCSWDataResiduethe difference between the amount of data expected as stated in the dCBWDataTransferLengthand the actual amount of relevant data sent by the device + uint8_t status ; ///< indicates the success or failure of the command. Values from \ref msc_csw_status_t +}msc_csw_t; + +TU_VERIFY_STATIC(sizeof(msc_csw_t) == 13, "size is not correct"); + +//--------------------------------------------------------------------+ +// SCSI Constant +//--------------------------------------------------------------------+ + +/// SCSI Command Operation Code +typedef enum +{ + SCSI_CMD_TEST_UNIT_READY = 0x00, ///< The SCSI Test Unit Ready command is used to determine if a device is ready to transfer data (read/write), i.e. if a disk has spun up, if a tape is loaded and ready etc. The device does not perform a self-test operation. + SCSI_CMD_INQUIRY = 0x12, ///< The SCSI Inquiry command is used to obtain basic information from a target device. + SCSI_CMD_MODE_SELECT_6 = 0x15, ///< provides a means for the application client to specify medium, logical unit, or peripheral device parameters to the device server. Device servers that implement the MODE SELECT(6) command shall also implement the MODE SENSE(6) command. Application clients should issue MODE SENSE(6) prior to each MODE SELECT(6) to determine supported mode pages, page lengths, and other parameters. + SCSI_CMD_MODE_SENSE_6 = 0x1A, ///< provides a means for a device server to report parameters to an application client. It is a complementary command to the MODE SELECT(6) command. Device servers that implement the MODE SENSE(6) command shall also implement the MODE SELECT(6) command. + SCSI_CMD_START_STOP_UNIT = 0x1B, + SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1E, + SCSI_CMD_READ_CAPACITY_10 = 0x25, ///< The SCSI Read Capacity command is used to obtain data capacity information from a target device. + SCSI_CMD_REQUEST_SENSE = 0x03, ///< The SCSI Request Sense command is part of the SCSI computer protocol standard. This command is used to obtain sense data -- status/error information -- from a target device. + SCSI_CMD_READ_FORMAT_CAPACITY = 0x23, ///< The command allows the Host to request a list of the possible format capacities for an installed writable media. This command also has the capability to report the writable capacity for a media when it is installed + SCSI_CMD_READ_10 = 0x28, ///< The READ (10) command requests that the device server read the specified logical block(s) and transfer them to the data-in buffer. + SCSI_CMD_WRITE_10 = 0x2A, ///< The WRITE (10) command requests thatthe device server transfer the specified logical block(s) from the data-out buffer and write them. +}scsi_cmd_type_t; + +/// SCSI Sense Key +typedef enum +{ + SCSI_SENSE_NONE = 0x00, ///< no specific Sense Key. This would be the case for a successful command + SCSI_SENSE_RECOVERED_ERROR = 0x01, ///< ndicates the last command completed successfully with some recovery action performed by the disc drive. + SCSI_SENSE_NOT_READY = 0x02, ///< Indicates the logical unit addressed cannot be accessed. + SCSI_SENSE_MEDIUM_ERROR = 0x03, ///< Indicates the command terminated with a non-recovered error condition. + SCSI_SENSE_HARDWARE_ERROR = 0x04, ///< Indicates the disc drive detected a nonrecoverable hardware failure while performing the command or during a self test. + SCSI_SENSE_ILLEGAL_REQUEST = 0x05, ///< Indicates an illegal parameter in the command descriptor block or in the additional parameters + SCSI_SENSE_UNIT_ATTENTION = 0x06, ///< Indicates the disc drive may have been reset. + SCSI_SENSE_DATA_PROTECT = 0x07, ///< Indicates that a command that reads or writes the medium was attempted on a block that is protected from this operation. The read or write operation is not performed. + SCSI_SENSE_FIRMWARE_ERROR = 0x08, ///< Vendor specific sense key. + SCSI_SENSE_ABORTED_COMMAND = 0x0b, ///< Indicates the disc drive aborted the command. + SCSI_SENSE_EQUAL = 0x0c, ///< Indicates a SEARCH DATA command has satisfied an equal comparison. + SCSI_SENSE_VOLUME_OVERFLOW = 0x0d, ///< Indicates a buffered peripheral device has reached the end of medium partition and data remains in the buffer that has not been written to the medium. + SCSI_SENSE_MISCOMPARE = 0x0e ///< ndicates that the source data did not match the data read from the medium. +}scsi_sense_key_type_t; + +//--------------------------------------------------------------------+ +// SCSI Primary Command (SPC-4) +//--------------------------------------------------------------------+ + +/// SCSI Test Unit Ready Command +typedef struct TU_ATTR_PACKED +{ + uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_TEST_UNIT_READY + uint8_t lun ; ///< Logical Unit + uint8_t reserved[3] ; + uint8_t control ; +} scsi_test_unit_ready_t; + +TU_VERIFY_STATIC(sizeof(scsi_test_unit_ready_t) == 6, "size is not correct"); + +/// SCSI Inquiry Command +typedef struct TU_ATTR_PACKED +{ + uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_INQUIRY + uint8_t reserved1 ; + uint8_t page_code ; + uint8_t reserved2 ; + uint8_t alloc_length ; ///< specifies the maximum number of bytes that USB host has allocated in the Data-In Buffer. An allocation length of zero specifies that no data shall be transferred. + uint8_t control ; +} scsi_inquiry_t, scsi_request_sense_t; + +TU_VERIFY_STATIC(sizeof(scsi_inquiry_t) == 6, "size is not correct"); + +/// SCSI Inquiry Response Data +typedef struct TU_ATTR_PACKED +{ + uint8_t peripheral_device_type : 5; + uint8_t peripheral_qualifier : 3; + + uint8_t : 7; + uint8_t is_removable : 1; + + uint8_t version; + + uint8_t response_data_format : 4; + uint8_t hierarchical_support : 1; + uint8_t normal_aca : 1; + uint8_t : 2; + + uint8_t additional_length; + + uint8_t protect : 1; + uint8_t : 2; + uint8_t third_party_copy : 1; + uint8_t target_port_group_support : 2; + uint8_t access_control_coordinator : 1; + uint8_t scc_support : 1; + + uint8_t addr16 : 1; + uint8_t : 3; + uint8_t multi_port : 1; + uint8_t : 1; // vendor specific + uint8_t enclosure_service : 1; + uint8_t : 1; + + uint8_t : 1; // vendor specific + uint8_t cmd_que : 1; + uint8_t : 2; + uint8_t sync : 1; + uint8_t wbus16 : 1; + uint8_t : 2; + + uint8_t vendor_id[8] ; ///< 8 bytes of ASCII data identifying the vendor of the product. + uint8_t product_id[16]; ///< 16 bytes of ASCII data defined by the vendor. + uint8_t product_rev[4]; ///< 4 bytes of ASCII data defined by the vendor. +} scsi_inquiry_resp_t; + +TU_VERIFY_STATIC(sizeof(scsi_inquiry_resp_t) == 36, "size is not correct"); + + +typedef struct TU_ATTR_PACKED +{ + uint8_t response_code : 7; ///< 70h - current errors, Fixed Format 71h - deferred errors, Fixed Format + uint8_t valid : 1; + + uint8_t reserved; + + uint8_t sense_key : 4; + uint8_t : 1; + uint8_t ili : 1; ///< Incorrect length indicator + uint8_t end_of_medium : 1; + uint8_t filemark : 1; + + uint32_t information; + uint8_t add_sense_len; + uint32_t command_specific_info; + uint8_t add_sense_code; + uint8_t add_sense_qualifier; + uint8_t field_replaceable_unit_code; + + uint8_t sense_key_specific[3]; ///< sense key specific valid bit is bit 7 of key[0], aka MSB in Big Endian layout + +} scsi_sense_fixed_resp_t; + +TU_VERIFY_STATIC(sizeof(scsi_sense_fixed_resp_t) == 18, "size is not correct"); + +typedef struct TU_ATTR_PACKED +{ + uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_MODE_SENSE_6 + + uint8_t : 3; + uint8_t disable_block_descriptor : 1; + uint8_t : 4; + + uint8_t page_code : 6; + uint8_t page_control : 2; + + uint8_t subpage_code; + uint8_t alloc_length; + uint8_t control; +} scsi_mode_sense6_t; + +TU_VERIFY_STATIC( sizeof(scsi_mode_sense6_t) == 6, "size is not correct"); + +// This is only a Mode parameter header(6). +typedef struct TU_ATTR_PACKED +{ + uint8_t data_len; + uint8_t medium_type; + + uint8_t reserved : 7; + bool write_protected : 1; + + uint8_t block_descriptor_len; +} scsi_mode_sense6_resp_t; + +TU_VERIFY_STATIC( sizeof(scsi_mode_sense6_resp_t) == 4, "size is not correct"); + +typedef struct TU_ATTR_PACKED +{ + uint8_t cmd_code; ///< SCSI OpCode for \ref SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL + uint8_t reserved[3]; + uint8_t prohibit_removal; + uint8_t control; +} scsi_prevent_allow_medium_removal_t; + +TU_VERIFY_STATIC( sizeof(scsi_prevent_allow_medium_removal_t) == 6, "size is not correct"); + +typedef struct TU_ATTR_PACKED +{ + uint8_t cmd_code; + + uint8_t immded : 1; + uint8_t : 7; + + uint8_t TU_RESERVED; + + uint8_t power_condition_mod : 4; + uint8_t : 4; + + uint8_t start : 1; + uint8_t load_eject : 1; + uint8_t no_flush : 1; + uint8_t : 1; + uint8_t power_condition : 4; + + uint8_t control; +} scsi_start_stop_unit_t; + +TU_VERIFY_STATIC( sizeof(scsi_start_stop_unit_t) == 6, "size is not correct"); + +//--------------------------------------------------------------------+ +// SCSI MMC +//--------------------------------------------------------------------+ +/// SCSI Read Format Capacity: Write Capacity +typedef struct TU_ATTR_PACKED +{ + uint8_t cmd_code; + uint8_t reserved[6]; + uint16_t alloc_length; + uint8_t control; +} scsi_read_format_capacity_t; + +TU_VERIFY_STATIC( sizeof(scsi_read_format_capacity_t) == 10, "size is not correct"); + +typedef struct TU_ATTR_PACKED{ + uint8_t reserved[3]; + uint8_t list_length; /// must be 8*n, length in bytes of formattable capacity descriptor followed it. + + uint32_t block_num; /// Number of Logical Blocks + uint8_t descriptor_type; // 00: reserved, 01 unformatted media , 10 Formatted media, 11 No media present + + uint8_t reserved2; + uint16_t block_size_u16; + +} scsi_read_format_capacity_data_t; + +TU_VERIFY_STATIC( sizeof(scsi_read_format_capacity_data_t) == 12, "size is not correct"); + +//--------------------------------------------------------------------+ +// SCSI Block Command (SBC-3) +// NOTE: All data in SCSI command are in Big Endian +//--------------------------------------------------------------------+ + +/// SCSI Read Capacity 10 Command: Read Capacity +typedef struct TU_ATTR_PACKED +{ + uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_READ_CAPACITY_10 + uint8_t reserved1 ; + uint32_t lba ; ///< The first Logical Block Address (LBA) accessed by this command + uint16_t reserved2 ; + uint8_t partial_medium_indicator ; + uint8_t control ; +} scsi_read_capacity10_t; + +TU_VERIFY_STATIC(sizeof(scsi_read_capacity10_t) == 10, "size is not correct"); + +/// SCSI Read Capacity 10 Response Data +typedef struct { + uint32_t last_lba ; ///< The last Logical Block Address of the device + uint32_t block_size ; ///< Block size in bytes +} scsi_read_capacity10_resp_t; + +TU_VERIFY_STATIC(sizeof(scsi_read_capacity10_resp_t) == 8, "size is not correct"); + +/// SCSI Read 10 Command +typedef struct TU_ATTR_PACKED +{ + uint8_t cmd_code ; ///< SCSI OpCode + uint8_t reserved ; // has LUN according to wiki + uint32_t lba ; ///< The first Logical Block Address (LBA) accessed by this command + uint8_t reserved2 ; + uint16_t block_count ; ///< Number of Blocks used by this command + uint8_t control ; +} scsi_read10_t, scsi_write10_t; + +TU_VERIFY_STATIC(sizeof(scsi_read10_t) == 10, "size is not correct"); +TU_VERIFY_STATIC(sizeof(scsi_write10_t) == 10, "size is not correct"); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_MSC_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.c b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.c new file mode 100644 index 00000000..00b0a1d0 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.c @@ -0,0 +1,952 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_MSC) + +#include "device/dcd.h" // for faking dcd_event_xfer_complete +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "msc_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +// Can be selectively disabled to reduce logging when troubleshooting other driver +#define MSC_DEBUG 2 + +enum +{ + MSC_STAGE_CMD = 0, + MSC_STAGE_DATA, + MSC_STAGE_STATUS, + MSC_STAGE_STATUS_SENT, + MSC_STAGE_NEED_RESET, +}; + +typedef struct +{ + // TODO optimize alignment + CFG_TUSB_MEM_ALIGN msc_cbw_t cbw; + CFG_TUSB_MEM_ALIGN msc_csw_t csw; + + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; + + // Bulk Only Transfer (BOT) Protocol + uint8_t stage; + uint32_t total_len; // byte to be transferred, can be smaller than total_bytes in cbw + uint32_t xferred_len; // numbered of bytes transferred so far in the Data Stage + + // Sense Response Data + uint8_t sense_key; + uint8_t add_sense_code; + uint8_t add_sense_qualifier; +}mscd_interface_t; + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static mscd_interface_t _mscd_itf; +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _mscd_buf[CFG_TUD_MSC_EP_BUFSIZE]; + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize); +static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc); + +static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc); +static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes); + +TU_ATTR_ALWAYS_INLINE static inline bool is_data_in(uint8_t dir) +{ + return tu_bit_test(dir, 7); +} + +static inline bool send_csw(uint8_t rhport, mscd_interface_t* p_msc) +{ + // Data residue is always = host expect - actual transferred + p_msc->csw.data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len; + + p_msc->stage = MSC_STAGE_STATUS_SENT; + return usbd_edpt_xfer(rhport, p_msc->ep_in , (uint8_t*) &p_msc->csw, sizeof(msc_csw_t)); +} + +static inline bool prepare_cbw(uint8_t rhport, mscd_interface_t* p_msc) +{ + p_msc->stage = MSC_STAGE_CMD; + return usbd_edpt_xfer(rhport, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)); +} + +static void fail_scsi_op(uint8_t rhport, mscd_interface_t* p_msc, uint8_t status) +{ + msc_cbw_t const * p_cbw = &p_msc->cbw; + msc_csw_t * p_csw = &p_msc->csw; + + p_csw->status = status; + p_csw->data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len; + p_msc->stage = MSC_STAGE_STATUS; + + // failed but sense key is not set: default to Illegal Request + if ( p_msc->sense_key == 0 ) tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); + + // If there is data stage and not yet complete, stall it + if ( p_cbw->total_bytes && p_csw->data_residue ) + { + if ( is_data_in(p_cbw->dir) ) + { + usbd_edpt_stall(rhport, p_msc->ep_in); + } + else + { + usbd_edpt_stall(rhport, p_msc->ep_out); + } + } +} + +static inline uint32_t rdwr10_get_lba(uint8_t const command[]) +{ + // use offsetof to avoid pointer to the odd/unaligned address + uint32_t const lba = tu_unaligned_read32(command + offsetof(scsi_write10_t, lba)); + + // lba is in Big Endian + return tu_ntohl(lba); +} + +static inline uint16_t rdwr10_get_blockcount(msc_cbw_t const* cbw) +{ + uint16_t const block_count = tu_unaligned_read16(cbw->command + offsetof(scsi_write10_t, block_count)); + return tu_ntohs(block_count); +} + +static inline uint16_t rdwr10_get_blocksize(msc_cbw_t const* cbw) +{ + // first extract block count in the command + uint16_t const block_count = rdwr10_get_blockcount(cbw); + + // invalid block count + if (block_count == 0) return 0; + + return (uint16_t) (cbw->total_bytes / block_count); +} + +uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw) +{ + uint8_t status = MSC_CSW_STATUS_PASSED; + uint16_t const block_count = rdwr10_get_blockcount(cbw); + + if ( cbw->total_bytes == 0 ) + { + if ( block_count ) + { + TU_LOG(MSC_DEBUG, " SCSI case 2 (Hn < Di) or case 3 (Hn < Do) \r\n"); + status = MSC_CSW_STATUS_PHASE_ERROR; + }else + { + // no data transfer, only exist in complaint test suite + } + }else + { + if ( SCSI_CMD_READ_10 == cbw->command[0] && !is_data_in(cbw->dir) ) + { + TU_LOG(MSC_DEBUG, " SCSI case 10 (Ho <> Di)\r\n"); + status = MSC_CSW_STATUS_PHASE_ERROR; + } + else if ( SCSI_CMD_WRITE_10 == cbw->command[0] && is_data_in(cbw->dir) ) + { + TU_LOG(MSC_DEBUG, " SCSI case 8 (Hi <> Do)\r\n"); + status = MSC_CSW_STATUS_PHASE_ERROR; + } + else if ( 0 == block_count ) + { + TU_LOG(MSC_DEBUG, " SCSI case 4 Hi > Dn (READ10) or case 9 Ho > Dn (WRITE10) \r\n"); + status = MSC_CSW_STATUS_FAILED; + } + else if ( cbw->total_bytes / block_count == 0 ) + { + TU_LOG(MSC_DEBUG, " Computed block size = 0. SCSI case 7 Hi < Di (READ10) or case 13 Ho < Do (WRIT10)\r\n"); + status = MSC_CSW_STATUS_PHASE_ERROR; + } + } + + return status; +} + +//--------------------------------------------------------------------+ +// Debug +//--------------------------------------------------------------------+ +#if CFG_TUSB_DEBUG >= 2 + +TU_ATTR_UNUSED static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] = +{ + { .key = SCSI_CMD_TEST_UNIT_READY , .data = "Test Unit Ready" }, + { .key = SCSI_CMD_INQUIRY , .data = "Inquiry" }, + { .key = SCSI_CMD_MODE_SELECT_6 , .data = "Mode_Select 6" }, + { .key = SCSI_CMD_MODE_SENSE_6 , .data = "Mode_Sense 6" }, + { .key = SCSI_CMD_START_STOP_UNIT , .data = "Start Stop Unit" }, + { .key = SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL , .data = "Prevent/Allow Medium Removal" }, + { .key = SCSI_CMD_READ_CAPACITY_10 , .data = "Read Capacity10" }, + { .key = SCSI_CMD_REQUEST_SENSE , .data = "Request Sense" }, + { .key = SCSI_CMD_READ_FORMAT_CAPACITY , .data = "Read Format Capacity" }, + { .key = SCSI_CMD_READ_10 , .data = "Read10" }, + { .key = SCSI_CMD_WRITE_10 , .data = "Write10" } +}; + +TU_ATTR_UNUSED static tu_lookup_table_t const _msc_scsi_cmd_table = +{ + .count = TU_ARRAY_SIZE(_msc_scsi_cmd_lookup), + .items = _msc_scsi_cmd_lookup +}; + +#endif + +//--------------------------------------------------------------------+ +// APPLICATION API +//--------------------------------------------------------------------+ +bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier) +{ + (void) lun; + + _mscd_itf.sense_key = sense_key; + _mscd_itf.add_sense_code = add_sense_code; + _mscd_itf.add_sense_qualifier = add_sense_qualifier; + + return true; +} + +static inline void set_sense_medium_not_present(uint8_t lun) +{ + // default sense is NOT READY, MEDIUM NOT PRESENT + tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00); +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void mscd_init(void) +{ + tu_memclr(&_mscd_itf, sizeof(mscd_interface_t)); +} + +void mscd_reset(uint8_t rhport) +{ + (void) rhport; + tu_memclr(&_mscd_itf, sizeof(mscd_interface_t)); +} + +uint16_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + // only support SCSI's BOT protocol + TU_VERIFY(TUSB_CLASS_MSC == itf_desc->bInterfaceClass && + MSC_SUBCLASS_SCSI == itf_desc->bInterfaceSubClass && + MSC_PROTOCOL_BOT == itf_desc->bInterfaceProtocol, 0); + + // msc driver length is fixed + uint16_t const drv_len = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t); + + // Max length must be at least 1 interface + 2 endpoints + TU_ASSERT(max_len >= drv_len, 0); + + mscd_interface_t * p_msc = &_mscd_itf; + p_msc->itf_num = itf_desc->bInterfaceNumber; + + // Open endpoint pair + TU_ASSERT( usbd_open_edpt_pair(rhport, tu_desc_next(itf_desc), 2, TUSB_XFER_BULK, &p_msc->ep_out, &p_msc->ep_in), 0 ); + + // Prepare for Command Block Wrapper + TU_ASSERT( prepare_cbw(rhport, p_msc), drv_len); + + return drv_len; +} + +static void proc_bot_reset(mscd_interface_t* p_msc) +{ + p_msc->stage = MSC_STAGE_CMD; + p_msc->total_len = 0; + p_msc->xferred_len = 0; + + p_msc->sense_key = 0; + p_msc->add_sense_code = 0; + p_msc->add_sense_qualifier = 0; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + // nothing to do with DATA & ACK stage + if (stage != CONTROL_STAGE_SETUP) return true; + + mscd_interface_t* p_msc = &_mscd_itf; + + // Clear Endpoint Feature (stall) for recovery + if ( TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type && + TUSB_REQ_RCPT_ENDPOINT == request->bmRequestType_bit.recipient && + TUSB_REQ_CLEAR_FEATURE == request->bRequest && + TUSB_REQ_FEATURE_EDPT_HALT == request->wValue ) + { + uint8_t const ep_addr = tu_u16_low(request->wIndex); + + if ( p_msc->stage == MSC_STAGE_NEED_RESET ) + { + // reset recovery is required to recover from this stage + // Clear Stall request cannot resolve this -> continue to stall endpoint + usbd_edpt_stall(rhport, ep_addr); + } + else + { + if ( ep_addr == p_msc->ep_in ) + { + if ( p_msc->stage == MSC_STAGE_STATUS ) + { + // resume sending SCSI status if we are in this stage previously before stalled + TU_ASSERT( send_csw(rhport, p_msc) ); + } + } + else if ( ep_addr == p_msc->ep_out ) + { + if ( p_msc->stage == MSC_STAGE_CMD ) + { + // part of reset recovery (probably due to invalid CBW) -> prepare for new command + // Note: skip if already queued previously + if ( usbd_edpt_ready(rhport, p_msc->ep_out) ) + { + TU_ASSERT( prepare_cbw(rhport, p_msc) ); + } + } + } + } + + return true; + } + + // From this point only handle class request only + TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); + + switch ( request->bRequest ) + { + case MSC_REQ_RESET: + TU_LOG(MSC_DEBUG, " MSC BOT Reset\r\n"); + TU_VERIFY(request->wValue == 0 && request->wLength == 0); + + // driver state reset + proc_bot_reset(p_msc); + + tud_control_status(rhport, request); + break; + + case MSC_REQ_GET_MAX_LUN: + { + TU_LOG(MSC_DEBUG, " MSC Get Max Lun\r\n"); + TU_VERIFY(request->wValue == 0 && request->wLength == 1); + + uint8_t maxlun = 1; + if (tud_msc_get_maxlun_cb) maxlun = tud_msc_get_maxlun_cb(); + TU_VERIFY(maxlun); + + // MAX LUN is minus 1 by specs + maxlun--; + + tud_control_xfer(rhport, request, &maxlun, 1); + } + break; + + default: return false; // stall unsupported request + } + + return true; +} + +bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +{ + (void) event; + + mscd_interface_t* p_msc = &_mscd_itf; + msc_cbw_t const * p_cbw = &p_msc->cbw; + msc_csw_t * p_csw = &p_msc->csw; + + switch (p_msc->stage) + { + case MSC_STAGE_CMD: + //------------- new CBW received -------------// + // Complete IN while waiting for CMD is usually Status of previous SCSI op, ignore it + if(ep_addr != p_msc->ep_out) return true; + + if ( !(xferred_bytes == sizeof(msc_cbw_t) && p_cbw->signature == MSC_CBW_SIGNATURE) ) + { + TU_LOG(MSC_DEBUG, " SCSI CBW is not valid\r\n"); + + // BOT 6.6.1 If CBW is not valid stall both endpoints until reset recovery + p_msc->stage = MSC_STAGE_NEED_RESET; + + // invalid CBW stall both endpoints + usbd_edpt_stall(rhport, p_msc->ep_in); + usbd_edpt_stall(rhport, p_msc->ep_out); + + return false; + } + + TU_LOG(MSC_DEBUG, " SCSI Command [Lun%u]: %s\r\n", p_cbw->lun, tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0])); + //TU_LOG_MEM(MSC_DEBUG, p_cbw, xferred_bytes, 2); + + p_csw->signature = MSC_CSW_SIGNATURE; + p_csw->tag = p_cbw->tag; + p_csw->data_residue = 0; + p_csw->status = MSC_CSW_STATUS_PASSED; + + /*------------- Parse command and prepare DATA -------------*/ + p_msc->stage = MSC_STAGE_DATA; + p_msc->total_len = p_cbw->total_bytes; + p_msc->xferred_len = 0; + + // Read10 or Write10 + if ( (SCSI_CMD_READ_10 == p_cbw->command[0]) || (SCSI_CMD_WRITE_10 == p_cbw->command[0]) ) + { + uint8_t const status = rdwr10_validate_cmd(p_cbw); + + if ( status != MSC_CSW_STATUS_PASSED) + { + fail_scsi_op(rhport, p_msc, status); + }else if ( p_cbw->total_bytes ) + { + if (SCSI_CMD_READ_10 == p_cbw->command[0]) + { + proc_read10_cmd(rhport, p_msc); + }else + { + proc_write10_cmd(rhport, p_msc); + } + }else + { + // no data transfer, only exist in complaint test suite + p_msc->stage = MSC_STAGE_STATUS; + } + } + else + { + // For other SCSI commands + // 1. OUT : queue transfer (invoke app callback after done) + // 2. IN & Zero: Process if is built-in, else Invoke app callback. Skip DATA if zero length + if ( (p_cbw->total_bytes > 0 ) && !is_data_in(p_cbw->dir) ) + { + if (p_cbw->total_bytes > sizeof(_mscd_buf)) + { + TU_LOG(MSC_DEBUG, " SCSI reject non READ10/WRITE10 with large data\r\n"); + fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + }else + { + // Didn't check for case 9 (Ho > Dn), which requires examining scsi command first + // but it is OK to just receive data then responded with failed status + TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, (uint16_t) p_msc->total_len) ); + } + }else + { + // First process if it is a built-in commands + int32_t resplen = proc_builtin_scsi(p_cbw->lun, p_cbw->command, _mscd_buf, sizeof(_mscd_buf)); + + // Invoke user callback if not built-in + if ( (resplen < 0) && (p_msc->sense_key == 0) ) + { + resplen = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, (uint16_t) p_msc->total_len); + } + + if ( resplen < 0 ) + { + // unsupported command + TU_LOG(MSC_DEBUG, " SCSI unsupported or failed command\r\n"); + fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + } + else if (resplen == 0) + { + if (p_cbw->total_bytes) + { + // 6.7 The 13 Cases: case 4 (Hi > Dn) + // TU_LOG(MSC_DEBUG, " SCSI case 4 (Hi > Dn): %lu\r\n", p_cbw->total_bytes); + fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + }else + { + // case 1 Hn = Dn: all good + p_msc->stage = MSC_STAGE_STATUS; + } + } + else + { + if ( p_cbw->total_bytes == 0 ) + { + // 6.7 The 13 Cases: case 2 (Hn < Di) + // TU_LOG(MSC_DEBUG, " SCSI case 2 (Hn < Di): %lu\r\n", p_cbw->total_bytes); + fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + }else + { + // cannot return more than host expect + p_msc->total_len = tu_min32((uint32_t) resplen, p_cbw->total_bytes); + TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, (uint16_t) p_msc->total_len) ); + } + } + } + } + break; + + case MSC_STAGE_DATA: + TU_LOG(MSC_DEBUG, " SCSI Data [Lun%u]\r\n", p_cbw->lun); + //TU_LOG_MEM(MSC_DEBUG, _mscd_buf, xferred_bytes, 2); + + if (SCSI_CMD_READ_10 == p_cbw->command[0]) + { + p_msc->xferred_len += xferred_bytes; + + if ( p_msc->xferred_len >= p_msc->total_len ) + { + // Data Stage is complete + p_msc->stage = MSC_STAGE_STATUS; + }else + { + proc_read10_cmd(rhport, p_msc); + } + } + else if (SCSI_CMD_WRITE_10 == p_cbw->command[0]) + { + proc_write10_new_data(rhport, p_msc, xferred_bytes); + } + else + { + p_msc->xferred_len += xferred_bytes; + + // OUT transfer, invoke callback if needed + if ( !is_data_in(p_cbw->dir) ) + { + int32_t cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, (uint16_t) p_msc->total_len); + + if ( cb_result < 0 ) + { + // unsupported command + TU_LOG(MSC_DEBUG, " SCSI unsupported command\r\n"); + fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + }else + { + // TODO haven't implement this scenario any further yet + } + } + + if ( p_msc->xferred_len >= p_msc->total_len ) + { + // Data Stage is complete + p_msc->stage = MSC_STAGE_STATUS; + } + else + { + // This scenario with command that take more than one transfer is already rejected at Command stage + TU_BREAKPOINT(); + } + } + break; + + case MSC_STAGE_STATUS: + // processed immediately after this switch, supposedly to be empty + break; + + case MSC_STAGE_STATUS_SENT: + // Wait for the Status phase to complete + if( (ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t)) ) + { + TU_LOG(MSC_DEBUG, " SCSI Status [Lun%u] = %u\r\n", p_cbw->lun, p_csw->status); + // TU_LOG_MEM(MSC_DEBUG, p_csw, xferred_bytes, 2); + + // Invoke complete callback if defined + // Note: There is racing issue with samd51 + qspi flash testing with arduino + // if complete_cb() is invoked after queuing the status. + switch(p_cbw->command[0]) + { + case SCSI_CMD_READ_10: + if ( tud_msc_read10_complete_cb ) tud_msc_read10_complete_cb(p_cbw->lun); + break; + + case SCSI_CMD_WRITE_10: + if ( tud_msc_write10_complete_cb ) tud_msc_write10_complete_cb(p_cbw->lun); + break; + + default: + if ( tud_msc_scsi_complete_cb ) tud_msc_scsi_complete_cb(p_cbw->lun, p_cbw->command); + break; + } + + TU_ASSERT( prepare_cbw(rhport, p_msc) ); + }else + { + // Any xfer ended here is consider unknown error, ignore it + TU_LOG1(" Warning expect SCSI Status but received unknown data\r\n"); + } + break; + + default : break; + } + + if ( p_msc->stage == MSC_STAGE_STATUS ) + { + // skip status if epin is currently stalled, will do it when received Clear Stall request + if ( !usbd_edpt_stalled(rhport, p_msc->ep_in) ) + { + if ( (p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir) ) + { + // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status + // TU_LOG(MSC_DEBUG, " SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len); + usbd_edpt_stall(rhport, p_msc->ep_in); + }else + { + TU_ASSERT( send_csw(rhport, p_msc) ); + } + } + + #if TU_CHECK_MCU(OPT_MCU_CXD56) + // WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD. + // There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and + // hope everything will work + if ( usbd_edpt_stalled(rhport, p_msc->ep_in) ) + { + usbd_edpt_clear_stall(rhport, p_msc->ep_in); + send_csw(rhport, p_msc); + } + #endif + } + + return true; +} + +/*------------------------------------------------------------------*/ +/* SCSI Command Process + *------------------------------------------------------------------*/ + +// return response's length (copied to buffer). Negative if it is not an built-in command or indicate Failed status (CSW) +// In case of a failed status, sense key must be set for reason of failure +static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize) +{ + (void) bufsize; // TODO refractor later + int32_t resplen; + + mscd_interface_t* p_msc = &_mscd_itf; + + switch ( scsi_cmd[0] ) + { + case SCSI_CMD_TEST_UNIT_READY: + resplen = 0; + if ( !tud_msc_test_unit_ready_cb(lun) ) + { + // Failed status response + resplen = - 1; + + // set default sense if not set by callback + if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); + } + break; + + case SCSI_CMD_START_STOP_UNIT: + resplen = 0; + + if (tud_msc_start_stop_cb) + { + scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const *) scsi_cmd; + if ( !tud_msc_start_stop_cb(lun, start_stop->power_condition, start_stop->start, start_stop->load_eject) ) + { + // Failed status response + resplen = - 1; + + // set default sense if not set by callback + if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); + } + } + break; + + case SCSI_CMD_READ_CAPACITY_10: + { + uint32_t block_count; + uint32_t block_size; + uint16_t block_size_u16; + + tud_msc_capacity_cb(lun, &block_count, &block_size_u16); + block_size = (uint32_t) block_size_u16; + + // Invalid block size/count from callback, possibly unit is not ready + // stall this request, set sense key to NOT READY + if (block_count == 0 || block_size == 0) + { + resplen = -1; + + // set default sense if not set by callback + if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); + }else + { + scsi_read_capacity10_resp_t read_capa10; + + read_capa10.last_lba = tu_htonl(block_count-1); + read_capa10.block_size = tu_htonl(block_size); + + resplen = sizeof(read_capa10); + memcpy(buffer, &read_capa10, (size_t) resplen); + } + } + break; + + case SCSI_CMD_READ_FORMAT_CAPACITY: + { + scsi_read_format_capacity_data_t read_fmt_capa = + { + .list_length = 8, + .block_num = 0, + .descriptor_type = 2, // formatted media + .block_size_u16 = 0 + }; + + uint32_t block_count; + uint16_t block_size; + + tud_msc_capacity_cb(lun, &block_count, &block_size); + + // Invalid block size/count from callback, possibly unit is not ready + // stall this request, set sense key to NOT READY + if (block_count == 0 || block_size == 0) + { + resplen = -1; + + // set default sense if not set by callback + if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); + }else + { + read_fmt_capa.block_num = tu_htonl(block_count); + read_fmt_capa.block_size_u16 = tu_htons(block_size); + + resplen = sizeof(read_fmt_capa); + memcpy(buffer, &read_fmt_capa, (size_t) resplen); + } + } + break; + + case SCSI_CMD_INQUIRY: + { + scsi_inquiry_resp_t inquiry_rsp = + { + .is_removable = 1, + .version = 2, + .response_data_format = 2, + .additional_length = sizeof(scsi_inquiry_resp_t) - 5, + }; + + // vendor_id, product_id, product_rev is space padded string + memset(inquiry_rsp.vendor_id , ' ', sizeof(inquiry_rsp.vendor_id)); + memset(inquiry_rsp.product_id , ' ', sizeof(inquiry_rsp.product_id)); + memset(inquiry_rsp.product_rev, ' ', sizeof(inquiry_rsp.product_rev)); + + tud_msc_inquiry_cb(lun, inquiry_rsp.vendor_id, inquiry_rsp.product_id, inquiry_rsp.product_rev); + + resplen = sizeof(inquiry_rsp); + memcpy(buffer, &inquiry_rsp, (size_t) resplen); + } + break; + + case SCSI_CMD_MODE_SENSE_6: + { + scsi_mode_sense6_resp_t mode_resp = + { + .data_len = 3, + .medium_type = 0, + .write_protected = false, + .reserved = 0, + .block_descriptor_len = 0 // no block descriptor are included + }; + + bool writable = true; + if ( tud_msc_is_writable_cb ) + { + writable = tud_msc_is_writable_cb(lun); + } + + mode_resp.write_protected = !writable; + + resplen = sizeof(mode_resp); + memcpy(buffer, &mode_resp, (size_t) resplen); + } + break; + + case SCSI_CMD_REQUEST_SENSE: + { + scsi_sense_fixed_resp_t sense_rsp = + { + .response_code = 0x70, // current, fixed format + .valid = 1 + }; + + sense_rsp.add_sense_len = sizeof(scsi_sense_fixed_resp_t) - 8; + sense_rsp.sense_key = (uint8_t) (p_msc->sense_key & 0x0F); + sense_rsp.add_sense_code = p_msc->add_sense_code; + sense_rsp.add_sense_qualifier = p_msc->add_sense_qualifier; + + resplen = sizeof(sense_rsp); + memcpy(buffer, &sense_rsp, (size_t) resplen); + + // request sense callback could overwrite the sense data + if (tud_msc_request_sense_cb) + { + resplen = tud_msc_request_sense_cb(lun, buffer, (uint16_t) bufsize); + } + + // Clear sense data after copy + tud_msc_set_sense(lun, 0, 0, 0); + } + break; + + default: resplen = -1; break; + } + + return resplen; +} + +static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc) +{ + msc_cbw_t const * p_cbw = &p_msc->cbw; + + // block size already verified not zero + uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); + + // Adjust lba with transferred bytes + uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz); + + // remaining bytes capped at class buffer + int32_t nbytes = (int32_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len); + + // Application can consume smaller bytes + uint32_t const offset = p_msc->xferred_len % block_sz; + nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_buf, (uint32_t) nbytes); + + if ( nbytes < 0 ) + { + // negative means error -> endpoint is stalled & status in CSW set to failed + TU_LOG(MSC_DEBUG, " tud_msc_read10_cb() return -1\r\n"); + + // set sense + set_sense_medium_not_present(p_cbw->lun); + + fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + } + else if ( nbytes == 0 ) + { + // zero means not ready -> simulate an transfer complete so that this driver callback will fired again + dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false); + } + else + { + TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, (uint16_t) nbytes), ); + } +} + +static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc) +{ + msc_cbw_t const * p_cbw = &p_msc->cbw; + bool writable = true; + + if ( tud_msc_is_writable_cb ) + { + writable = tud_msc_is_writable_cb(p_cbw->lun); + } + + if ( !writable ) + { + // Not writable, complete this SCSI op with error + // Sense = Write protected + tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_DATA_PROTECT, 0x27, 0x00); + fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + return; + } + + // remaining bytes capped at class buffer + uint16_t nbytes = (uint16_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len); + + // Write10 callback will be called later when usb transfer complete + TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, nbytes), ); +} + +// process new data arrived from WRITE10 +static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes) +{ + msc_cbw_t const * p_cbw = &p_msc->cbw; + + // block size already verified not zero + uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); + + // Adjust lba with transferred bytes + uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz); + + // Invoke callback to consume new data + uint32_t const offset = p_msc->xferred_len % block_sz; + int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_buf, xferred_bytes); + + if ( nbytes < 0 ) + { + // negative means error -> failed this scsi op + TU_LOG(MSC_DEBUG, " tud_msc_write10_cb() return -1\r\n"); + + // update actual byte before failed + p_msc->xferred_len += xferred_bytes; + + // Set sense + set_sense_medium_not_present(p_cbw->lun); + + fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + }else + { + // Application consume less than what we got (including zero) + if ( (uint32_t) nbytes < xferred_bytes ) + { + uint32_t const left_over = xferred_bytes - (uint32_t) nbytes; + if ( nbytes > 0 ) + { + p_msc->xferred_len += (uint16_t) nbytes; + memmove(_mscd_buf, _mscd_buf+nbytes, left_over); + } + + // simulate an transfer complete with adjusted parameters --> callback will be invoked with adjusted parameter + dcd_event_xfer_complete(rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false); + } + else + { + // Application consume all bytes in our buffer + p_msc->xferred_len += xferred_bytes; + + if ( p_msc->xferred_len >= p_msc->total_len ) + { + // Data Stage is complete + p_msc->stage = MSC_STAGE_STATUS; + }else + { + // prepare to receive more data from host + proc_write10_cmd(rhport, p_msc); + } + } + } +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.h b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.h new file mode 100644 index 00000000..5839b168 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.h @@ -0,0 +1,162 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_MSC_DEVICE_H_ +#define _TUSB_MSC_DEVICE_H_ + +#include "common/tusb_common.h" +#include "msc.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Class Driver Configuration +//--------------------------------------------------------------------+ + +#if !defined(CFG_TUD_MSC_EP_BUFSIZE) & defined(CFG_TUD_MSC_BUFSIZE) + // TODO warn user to use new name later on + // #warning CFG_TUD_MSC_BUFSIZE is renamed to CFG_TUD_MSC_EP_BUFSIZE, please update to use the new name + #define CFG_TUD_MSC_EP_BUFSIZE CFG_TUD_MSC_BUFSIZE +#endif + +#ifndef CFG_TUD_MSC_EP_BUFSIZE + #error CFG_TUD_MSC_EP_BUFSIZE must be defined, value of a block size should work well, the more the better +#endif + +TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct"); + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + +// Set SCSI sense response +bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier); + +//--------------------------------------------------------------------+ +// Application Callbacks (WEAK is optional) +//--------------------------------------------------------------------+ + +// Invoked when received SCSI READ10 command +// - Address = lba * BLOCK_SIZE + offset +// - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. +// +// - Application fill the buffer (up to bufsize) with address contents and return number of read byte. If +// - read < bufsize : These bytes are transferred first and callback invoked again for remaining data. +// +// - read == 0 : Indicate application is not ready yet e.g disk I/O busy. +// Callback invoked again with the same parameters later on. +// +// - read < 0 : Indicate application error e.g invalid address. This request will be STALLed +// and return failed status in command status wrapper phase. +int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); + +// Invoked when received SCSI WRITE10 command +// - Address = lba * BLOCK_SIZE + offset +// - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. +// +// - Application write data from buffer to address contents (up to bufsize) and return number of written byte. If +// - write < bufsize : callback invoked again with remaining data later on. +// +// - write == 0 : Indicate application is not ready yet e.g disk I/O busy. +// Callback invoked again with the same parameters later on. +// +// - write < 0 : Indicate application error e.g invalid address. This request will be STALLed +// and return failed status in command status wrapper phase. +// +// TODO change buffer to const uint8_t* +int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize); + +// Invoked when received SCSI_CMD_INQUIRY +// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]); + +// Invoked when received Test Unit Ready command. +// return true allowing host to read/write this LUN e.g SD card inserted +bool tud_msc_test_unit_ready_cb(uint8_t lun); + +// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size +// Application update block count and block size +void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size); + +/** + * Invoked when received an SCSI command not in built-in list below. + * - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, TEST_UNIT_READY, START_STOP_UNIT, MODE_SENSE6, REQUEST_SENSE + * - READ10 and WRITE10 has their own callbacks + * + * \param[in] lun Logical unit number + * \param[in] scsi_cmd SCSI command contents which application must examine to response accordingly + * \param[out] buffer Buffer for SCSI Data Stage. + * - For INPUT: application must fill this with response. + * - For OUTPUT it holds the Data from host + * \param[in] bufsize Buffer's length. + * + * \return Actual bytes processed, can be zero for no-data command. + * \retval negative Indicate error e.g unsupported command, tinyusb will \b STALL the corresponding + * endpoint and return failed status in command status wrapper phase. + */ +int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize); + +/*------------- Optional callbacks -------------*/ + +// Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation +TU_ATTR_WEAK uint8_t tud_msc_get_maxlun_cb(void); + +// Invoked when received Start Stop Unit command +// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage +// - Start = 1 : active mode, if load_eject = 1 : load disk storage +TU_ATTR_WEAK bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject); + +// Invoked when received REQUEST_SENSE +TU_ATTR_WEAK int32_t tud_msc_request_sense_cb(uint8_t lun, void* buffer, uint16_t bufsize); + +// Invoked when Read10 command is complete +TU_ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun); + +// Invoke when Write10 command is complete, can be used to flush flash caching +TU_ATTR_WEAK void tud_msc_write10_complete_cb(uint8_t lun); + +// Invoked when command in tud_msc_scsi_cb is complete +TU_ATTR_WEAK void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16]); + +// Invoked to check if device is writable as part of SCSI WRITE10 +TU_ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void mscd_init (void); +void mscd_reset (uint8_t rhport); +uint16_t mscd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool mscd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * p_request); +bool mscd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_MSC_DEVICE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.c b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.c new file mode 100644 index 00000000..934f79ff --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.c @@ -0,0 +1,499 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUH_ENABLED && CFG_TUH_MSC + +#include "host/usbh.h" +#include "host/usbh_classdriver.h" + +#include "msc_host.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +enum +{ + MSC_STAGE_IDLE = 0, + MSC_STAGE_CMD, + MSC_STAGE_DATA, + MSC_STAGE_STATUS, +}; + +typedef struct +{ + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; + + uint8_t max_lun; + + volatile bool configured; // Receive SET_CONFIGURE + volatile bool mounted; // Enumeration is complete + + struct { + uint32_t block_size; + uint32_t block_count; + } capacity[CFG_TUH_MSC_MAXLUN]; + + //------------- SCSI -------------// + uint8_t stage; + void* buffer; + tuh_msc_complete_cb_t complete_cb; + + msc_cbw_t cbw; + msc_csw_t csw; +}msch_interface_t; + +CFG_TUSB_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUH_DEVICE_MAX]; + +// buffer used to read scsi information when mounted +// largest response data currently is inquiry TODO Inquiry is not part of enum anymore +CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) +static uint8_t _msch_buffer[sizeof(scsi_inquiry_resp_t)]; + +TU_ATTR_ALWAYS_INLINE +static inline msch_interface_t* get_itf(uint8_t dev_addr) +{ + return &_msch_itf[dev_addr-1]; +} + +//--------------------------------------------------------------------+ +// PUBLIC API +//--------------------------------------------------------------------+ +uint8_t tuh_msc_get_maxlun(uint8_t dev_addr) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + return p_msc->max_lun; +} + +uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + return p_msc->capacity[lun].block_count; +} + +uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + return p_msc->capacity[lun].block_size; +} + +bool tuh_msc_mounted(uint8_t dev_addr) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + return p_msc->mounted; +} + +bool tuh_msc_ready(uint8_t dev_addr) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + return p_msc->mounted && !usbh_edpt_busy(dev_addr, p_msc->ep_in); +} + +//--------------------------------------------------------------------+ +// PUBLIC API: SCSI COMMAND +//--------------------------------------------------------------------+ +static inline void cbw_init(msc_cbw_t *cbw, uint8_t lun) +{ + tu_memclr(cbw, sizeof(msc_cbw_t)); + cbw->signature = MSC_CBW_SIGNATURE; + cbw->tag = 0x54555342; // TUSB + cbw->lun = lun; +} + +bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + TU_VERIFY(p_msc->configured); + + // TODO claim endpoint + + p_msc->cbw = *cbw; + p_msc->stage = MSC_STAGE_CMD; + p_msc->buffer = data; + p_msc->complete_cb = complete_cb; + + TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t))); + + return true; +} + +bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + TU_VERIFY(p_msc->configured); + + msc_cbw_t cbw; + cbw_init(&cbw, lun); + + cbw.total_bytes = sizeof(scsi_read_capacity10_resp_t); + cbw.dir = TUSB_DIR_IN_MASK; + cbw.cmd_len = sizeof(scsi_read_capacity10_t); + cbw.command[0] = SCSI_CMD_READ_CAPACITY_10; + + return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb); +} + +bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + TU_VERIFY(p_msc->mounted); + + msc_cbw_t cbw; + cbw_init(&cbw, lun); + + cbw.total_bytes = sizeof(scsi_inquiry_resp_t); + cbw.dir = TUSB_DIR_IN_MASK; + cbw.cmd_len = sizeof(scsi_inquiry_t); + + scsi_inquiry_t const cmd_inquiry = + { + .cmd_code = SCSI_CMD_INQUIRY, + .alloc_length = sizeof(scsi_inquiry_resp_t) + }; + memcpy(cbw.command, &cmd_inquiry, cbw.cmd_len); + + return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb); +} + +bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + TU_VERIFY(p_msc->configured); + + msc_cbw_t cbw; + cbw_init(&cbw, lun); + + cbw.total_bytes = 0; + cbw.dir = TUSB_DIR_OUT; + cbw.cmd_len = sizeof(scsi_test_unit_ready_t); + cbw.command[0] = SCSI_CMD_TEST_UNIT_READY; + cbw.command[1] = lun; // according to wiki TODO need verification + + return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb); +} + +bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb) +{ + msc_cbw_t cbw; + cbw_init(&cbw, lun); + + cbw.total_bytes = 18; // TODO sense response + cbw.dir = TUSB_DIR_IN_MASK; + cbw.cmd_len = sizeof(scsi_request_sense_t); + + scsi_request_sense_t const cmd_request_sense = + { + .cmd_code = SCSI_CMD_REQUEST_SENSE, + .alloc_length = 18 + }; + + memcpy(cbw.command, &cmd_request_sense, cbw.cmd_len); + + return tuh_msc_scsi_command(dev_addr, &cbw, resposne, complete_cb); +} + +bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + TU_VERIFY(p_msc->mounted); + + msc_cbw_t cbw; + cbw_init(&cbw, lun); + + cbw.total_bytes = block_count*p_msc->capacity[lun].block_size; + cbw.dir = TUSB_DIR_IN_MASK; + cbw.cmd_len = sizeof(scsi_read10_t); + + scsi_read10_t const cmd_read10 = + { + .cmd_code = SCSI_CMD_READ_10, + .lba = tu_htonl(lba), + .block_count = tu_htons(block_count) + }; + + memcpy(cbw.command, &cmd_read10, cbw.cmd_len); + + return tuh_msc_scsi_command(dev_addr, &cbw, buffer, complete_cb); +} + +bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + TU_VERIFY(p_msc->mounted); + + msc_cbw_t cbw; + cbw_init(&cbw, lun); + + cbw.total_bytes = block_count*p_msc->capacity[lun].block_size; + cbw.dir = TUSB_DIR_OUT; + cbw.cmd_len = sizeof(scsi_write10_t); + + scsi_write10_t const cmd_write10 = + { + .cmd_code = SCSI_CMD_WRITE_10, + .lba = tu_htonl(lba), + .block_count = tu_htons(block_count) + }; + + memcpy(cbw.command, &cmd_write10, cbw.cmd_len); + + return tuh_msc_scsi_command(dev_addr, &cbw, (void*)(uintptr_t) buffer, complete_cb); +} + +#if 0 +// MSC interface Reset (not used now) +bool tuh_msc_reset(uint8_t dev_addr) +{ + tusb_control_request_t const new_request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = MSC_REQ_RESET, + .wValue = 0, + .wIndex = p_msc->itf_num, + .wLength = 0 + }; + TU_ASSERT( usbh_control_xfer( dev_addr, &new_request, NULL ) ); +} +#endif + +//--------------------------------------------------------------------+ +// CLASS-USBH API +//--------------------------------------------------------------------+ +void msch_init(void) +{ + tu_memclr(_msch_itf, sizeof(_msch_itf)); +} + +void msch_close(uint8_t dev_addr) +{ + TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); + + msch_interface_t* p_msc = get_itf(dev_addr); + + // invoke Application Callback + if (p_msc->mounted && tuh_msc_umount_cb) tuh_msc_umount_cb(dev_addr); + + tu_memclr(p_msc, sizeof(msch_interface_t)); +} + +bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + msc_cbw_t const * cbw = &p_msc->cbw; + msc_csw_t * csw = &p_msc->csw; + + switch (p_msc->stage) + { + case MSC_STAGE_CMD: + // Must be Command Block + TU_ASSERT(ep_addr == p_msc->ep_out && event == XFER_RESULT_SUCCESS && xferred_bytes == sizeof(msc_cbw_t)); + + if ( cbw->total_bytes && p_msc->buffer ) + { + // Data stage if any + p_msc->stage = MSC_STAGE_DATA; + + uint8_t const ep_data = (cbw->dir & TUSB_DIR_IN_MASK) ? p_msc->ep_in : p_msc->ep_out; + TU_ASSERT(usbh_edpt_xfer(dev_addr, ep_data, p_msc->buffer, (uint16_t) cbw->total_bytes)); + }else + { + // Status stage + p_msc->stage = MSC_STAGE_STATUS; + TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t))); + } + break; + + case MSC_STAGE_DATA: + // Status stage + p_msc->stage = MSC_STAGE_STATUS; + TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t))); + break; + + case MSC_STAGE_STATUS: + // SCSI op is complete + p_msc->stage = MSC_STAGE_IDLE; + + if (p_msc->complete_cb) p_msc->complete_cb(dev_addr, cbw, csw); + break; + + // unknown state + default: break; + } + + return true; +} + +//--------------------------------------------------------------------+ +// MSC Enumeration +//--------------------------------------------------------------------+ + +static void config_get_maxlun_complete (tuh_xfer_t* xfer); +static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); +static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); +static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); + +bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) +{ + (void) rhport; + TU_VERIFY (MSC_SUBCLASS_SCSI == desc_itf->bInterfaceSubClass && + MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol); + + // msc driver length is fixed + uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); + TU_ASSERT(drv_len <= max_len); + + msch_interface_t* p_msc = get_itf(dev_addr); + tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(desc_itf); + + for(uint32_t i=0; i<2; i++) + { + TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer); + TU_ASSERT(tuh_edpt_open(dev_addr, ep_desc)); + + if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN ) + { + p_msc->ep_in = ep_desc->bEndpointAddress; + }else + { + p_msc->ep_out = ep_desc->bEndpointAddress; + } + + ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(ep_desc); + } + + p_msc->itf_num = desc_itf->bInterfaceNumber; + + return true; +} + +bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + TU_ASSERT(p_msc->itf_num == itf_num); + + p_msc->configured = true; + + //------------- Get Max Lun -------------// + TU_LOG2("MSC Get Max Lun\r\n"); + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN + }, + .bRequest = MSC_REQ_GET_MAX_LUN, + .wValue = 0, + .wIndex = itf_num, + .wLength = 1 + }; + + tuh_xfer_t xfer = + { + .daddr = dev_addr, + .ep_addr = 0, + .setup = &request, + .buffer = &p_msc->max_lun, + .complete_cb = config_get_maxlun_complete, + .user_data = 0 + }; + TU_ASSERT(tuh_control_xfer(&xfer)); + + return true; +} + +static void config_get_maxlun_complete (tuh_xfer_t* xfer) +{ + uint8_t const daddr = xfer->daddr; + msch_interface_t* p_msc = get_itf(daddr); + + // STALL means zero + p_msc->max_lun = (XFER_RESULT_SUCCESS == xfer->result) ? _msch_buffer[0] : 0; + p_msc->max_lun++; // MAX LUN is minus 1 by specs + + // TODO multiple LUN support + TU_LOG2("SCSI Test Unit Ready\r\n"); + uint8_t const lun = 0; + tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete); +} + +static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +{ + if (csw->status == 0) + { + // Unit is ready, read its capacity + TU_LOG2("SCSI Read Capacity\r\n"); + tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete); + }else + { + // Note: During enumeration, some device fails Test Unit Ready and require a few retries + // with Request Sense to start working !! + // TODO limit number of retries + TU_LOG2("SCSI Request Sense\r\n"); + TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, _msch_buffer, config_request_sense_complete)); + } + + return true; +} + +static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +{ + TU_ASSERT(csw->status == 0); + TU_ASSERT(tuh_msc_test_unit_ready(dev_addr, cbw->lun, config_test_unit_ready_complete)); + return true; +} + +static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +{ + TU_ASSERT(csw->status == 0); + + msch_interface_t* p_msc = get_itf(dev_addr); + + // Capacity response field: Block size and Last LBA are both Big-Endian + scsi_read_capacity10_resp_t* resp = (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer); + p_msc->capacity[cbw->lun].block_count = tu_ntohl(resp->last_lba) + 1; + p_msc->capacity[cbw->lun].block_size = tu_ntohl(resp->block_size); + + // Mark enumeration is complete + p_msc->mounted = true; + if (tuh_msc_mount_cb) tuh_msc_mount_cb(dev_addr); + + // notify usbh that driver enumeration is complete + usbh_driver_set_config_complete(dev_addr, p_msc->itf_num); + + return true; +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.h b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.h new file mode 100644 index 00000000..7718ad4f --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.h @@ -0,0 +1,119 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_MSC_HOST_H_ +#define _TUSB_MSC_HOST_H_ + +#include "msc.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Class Driver Configuration +//--------------------------------------------------------------------+ + +#ifndef CFG_TUH_MSC_MAXLUN +#define CFG_TUH_MSC_MAXLUN 4 +#endif + +typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + +// Check if device supports MassStorage interface. +// This function true after tuh_msc_mounted_cb() and false after tuh_msc_unmounted_cb() +bool tuh_msc_mounted(uint8_t dev_addr); + +// Check if the interface is currently ready or busy transferring data +bool tuh_msc_ready(uint8_t dev_addr); + +// Get Max Lun +uint8_t tuh_msc_get_maxlun(uint8_t dev_addr); + +// Get number of block +uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun); + +// Get block size in bytes +uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun); + +// Perform a full SCSI command (cbw, data, csw) in non-blocking manner. +// Complete callback is invoked when SCSI op is complete. +// return true if success, false if there is already pending operation. +bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb); + +// Perform SCSI Inquiry command +// Complete callback is invoked when SCSI op is complete. +bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb); + +// Perform SCSI Test Unit Ready command +// Complete callback is invoked when SCSI op is complete. +bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb); + +// Perform SCSI Request Sense 10 command +// Complete callback is invoked when SCSI op is complete. +bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb); + +// Perform SCSI Read 10 command. Read n blocks starting from LBA to buffer +// Complete callback is invoked when SCSI op is complete. +bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb); + +// Perform SCSI Write 10 command. Write n blocks starting from LBA to device +// Complete callback is invoked when SCSI op is complete. +bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb); + +// Perform SCSI Read Capacity 10 command +// Complete callback is invoked when SCSI op is complete. +// Note: during enumeration, host stack already carried out this request. Application can retrieve capacity by +// simply call tuh_msc_get_block_count() and tuh_msc_get_block_size() +bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb); + +//------------- Application Callback -------------// + +// Invoked when a device with MassStorage interface is mounted +TU_ATTR_WEAK void tuh_msc_mount_cb(uint8_t dev_addr); + +// Invoked when a device with MassStorage interface is unmounted +TU_ATTR_WEAK void tuh_msc_umount_cb(uint8_t dev_addr); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ + +void msch_init (void); +bool msch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); +bool msch_set_config (uint8_t dev_addr, uint8_t itf_num); +void msch_close (uint8_t dev_addr); +bool msch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_MSC_HOST_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/net/ecm_rndis_device.c b/test-devices/composite-stm32/lib/tinyusb/class/net/ecm_rndis_device.c new file mode 100644 index 00000000..5f316762 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/net/ecm_rndis_device.c @@ -0,0 +1,447 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Peter Lawrence + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if ( CFG_TUD_ENABLED && CFG_TUD_ECM_RNDIS ) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "net_device.h" +#include "rndis_protocol.h" + +void rndis_class_set_handler(uint8_t *data, int size); /* found in ./misc/networking/rndis_reports.c */ + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +typedef struct +{ + uint8_t itf_num; // Index number of Management Interface, +1 for Data Interface + uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active + + uint8_t ep_notif; + uint8_t ep_in; + uint8_t ep_out; + + bool ecm_mode; + + // Endpoint descriptor use to open/close when receving SetInterface + // TODO since configuration descriptor may not be long-lived memory, we should + // keep a copy of endpoint attribute instead + uint8_t const * ecm_desc_epdata; + +} netd_interface_t; + +#define CFG_TUD_NET_PACKET_PREFIX_LEN sizeof(rndis_data_packet_t) +#define CFG_TUD_NET_PACKET_SUFFIX_LEN 0 + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t received[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t transmitted[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; + +struct ecm_notify_struct +{ + tusb_control_request_t header; + uint32_t downlink, uplink; +}; + +static const struct ecm_notify_struct ecm_notify_nc = +{ + .header = { + .bmRequestType = 0xA1, + .bRequest = 0 /* NETWORK_CONNECTION aka NetworkConnection */, + .wValue = 1 /* Connected */, + .wLength = 0, + }, +}; + +static const struct ecm_notify_struct ecm_notify_csc = +{ + .header = { + .bmRequestType = 0xA1, + .bRequest = 0x2A /* CONNECTION_SPEED_CHANGE aka ConnectionSpeedChange */, + .wLength = 8, + }, + .downlink = 9728000, + .uplink = 9728000, +}; + +// TODO remove CFG_TUSB_MEM_SECTION, control internal buffer is already in this special section +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static union +{ + uint8_t rndis_buf[120]; + struct ecm_notify_struct ecm_buf; +} notify; + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +// TODO remove CFG_TUSB_MEM_SECTION +CFG_TUSB_MEM_SECTION static netd_interface_t _netd_itf; + +static bool can_xmit; + +void tud_network_recv_renew(void) +{ + usbd_edpt_xfer(0, _netd_itf.ep_out, received, sizeof(received)); +} + +static void do_in_xfer(uint8_t *buf, uint16_t len) +{ + can_xmit = false; + usbd_edpt_xfer(0, _netd_itf.ep_in, buf, len); +} + +void netd_report(uint8_t *buf, uint16_t len) +{ + uint8_t const rhport = 0; + + // skip if previous report not yet acknowledged by host + if ( usbd_edpt_busy(rhport, _netd_itf.ep_notif) ) return; + usbd_edpt_xfer(rhport, _netd_itf.ep_notif, buf, len); +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void netd_init(void) +{ + tu_memclr(&_netd_itf, sizeof(_netd_itf)); +} + +void netd_reset(uint8_t rhport) +{ + (void) rhport; + + netd_init(); +} + +uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + bool const is_rndis = (TUD_RNDIS_ITF_CLASS == itf_desc->bInterfaceClass && + TUD_RNDIS_ITF_SUBCLASS == itf_desc->bInterfaceSubClass && + TUD_RNDIS_ITF_PROTOCOL == itf_desc->bInterfaceProtocol); + + bool const is_ecm = (TUSB_CLASS_CDC == itf_desc->bInterfaceClass && + CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL == itf_desc->bInterfaceSubClass && + 0x00 == itf_desc->bInterfaceProtocol); + + TU_VERIFY(is_rndis || is_ecm, 0); + + // confirm interface hasn't already been allocated + TU_ASSERT(0 == _netd_itf.ep_notif, 0); + + // sanity check the descriptor + _netd_itf.ecm_mode = is_ecm; + + //------------- Management Interface -------------// + _netd_itf.itf_num = itf_desc->bInterfaceNumber; + + uint16_t drv_len = sizeof(tusb_desc_interface_t); + uint8_t const * p_desc = tu_desc_next( itf_desc ); + + // Communication Functional Descriptors + while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) + { + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + // notification endpoint (if any) + if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + { + TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 ); + + _netd_itf.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + //------------- Data Interface -------------// + // - RNDIS Data followed immediately by a pair of endpoints + // - CDC-ECM data interface has 2 alternate settings + // - 0 : zero endpoints for inactive (default) + // - 1 : IN & OUT endpoints for active networking + TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); + + do + { + tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc; + TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass, 0); + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + }while( _netd_itf.ecm_mode && (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (drv_len <= max_len) ); + + // Pair of endpoints + TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0); + + if ( _netd_itf.ecm_mode ) + { + // ECM by default is in-active, save the endpoint attribute + // to open later when received setInterface + _netd_itf.ecm_desc_epdata = p_desc; + }else + { + // Open endpoint pair for RNDIS + TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in), 0 ); + + tud_network_init_cb(); + + // we are ready to transmit a packet + can_xmit = true; + + // prepare for incoming packets + tud_network_recv_renew(); + } + + drv_len += 2*sizeof(tusb_desc_endpoint_t); + + return drv_len; +} + +static void ecm_report(bool nc) +{ + notify.ecm_buf = (nc) ? ecm_notify_nc : ecm_notify_csc; + notify.ecm_buf.header.wIndex = _netd_itf.itf_num; + netd_report((uint8_t *)¬ify.ecm_buf, (nc) ? sizeof(notify.ecm_buf.header) : sizeof(notify.ecm_buf)); +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if ( stage == CONTROL_STAGE_SETUP ) + { + switch ( request->bmRequestType_bit.type ) + { + case TUSB_REQ_TYPE_STANDARD: + switch ( request->bRequest ) + { + case TUSB_REQ_GET_INTERFACE: + { + uint8_t const req_itfnum = (uint8_t) request->wIndex; + TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum); + + tud_control_xfer(rhport, request, &_netd_itf.itf_data_alt, 1); + } + break; + + case TUSB_REQ_SET_INTERFACE: + { + uint8_t const req_itfnum = (uint8_t) request->wIndex; + uint8_t const req_alt = (uint8_t) request->wValue; + + // Only valid for Data Interface with Alternate is either 0 or 1 + TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum && req_alt < 2); + + // ACM-ECM only: qequest to enable/disable network activities + TU_VERIFY(_netd_itf.ecm_mode); + + _netd_itf.itf_data_alt = req_alt; + + if ( _netd_itf.itf_data_alt ) + { + // TODO since we don't actually close endpoint + // hack here to not re-open it + if ( _netd_itf.ep_in == 0 && _netd_itf.ep_out == 0 ) + { + TU_ASSERT(_netd_itf.ecm_desc_epdata); + TU_ASSERT( usbd_open_edpt_pair(rhport, _netd_itf.ecm_desc_epdata, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in) ); + + // TODO should be merge with RNDIS's after endpoint opened + // Also should have opposite callback for application to disable network !! + tud_network_init_cb(); + can_xmit = true; // we are ready to transmit a packet + tud_network_recv_renew(); // prepare for incoming packets + } + }else + { + // TODO close the endpoint pair + // For now pretend that we did, this should have no harm since host won't try to + // communicate with the endpoints again + // _netd_itf.ep_in = _netd_itf.ep_out = 0 + } + + tud_control_status(rhport, request); + } + break; + + // unsupported request + default: return false; + } + break; + + case TUSB_REQ_TYPE_CLASS: + TU_VERIFY (_netd_itf.itf_num == request->wIndex); + + if (_netd_itf.ecm_mode) + { + /* the only required CDC-ECM Management Element Request is SetEthernetPacketFilter */ + if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest) + { + tud_control_xfer(rhport, request, NULL, 0); + ecm_report(true); + } + } + else + { + if (request->bmRequestType_bit.direction == TUSB_DIR_IN) + { + rndis_generic_msg_t *rndis_msg = (rndis_generic_msg_t *) ((void*) notify.rndis_buf); + uint32_t msglen = tu_le32toh(rndis_msg->MessageLength); + TU_ASSERT(msglen <= sizeof(notify.rndis_buf)); + tud_control_xfer(rhport, request, notify.rndis_buf, (uint16_t) msglen); + } + else + { + tud_control_xfer(rhport, request, notify.rndis_buf, (uint16_t) sizeof(notify.rndis_buf)); + } + } + break; + + // unsupported request + default: return false; + } + } + else if ( stage == CONTROL_STAGE_DATA ) + { + // Handle RNDIS class control OUT only + if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && + request->bmRequestType_bit.direction == TUSB_DIR_OUT && + _netd_itf.itf_num == request->wIndex) + { + if ( !_netd_itf.ecm_mode ) + { + rndis_class_set_handler(notify.rndis_buf, request->wLength); + } + } + } + + return true; +} + +static void handle_incoming_packet(uint32_t len) +{ + uint8_t *pnt = received; + uint32_t size = 0; + + if (_netd_itf.ecm_mode) + { + size = len; + } + else + { + rndis_data_packet_t *r = (rndis_data_packet_t *) ((void*) pnt); + if (len >= sizeof(rndis_data_packet_t)) + if ( (r->MessageType == REMOTE_NDIS_PACKET_MSG) && (r->MessageLength <= len)) + if ( (r->DataOffset + offsetof(rndis_data_packet_t, DataOffset) + r->DataLength) <= len) + { + pnt = &received[r->DataOffset + offsetof(rndis_data_packet_t, DataOffset)]; + size = r->DataLength; + } + } + + if (!tud_network_recv_cb(pnt, (uint16_t) size)) + { + /* if a buffer was never handled by user code, we must renew on the user's behalf */ + tud_network_recv_renew(); + } +} + +bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) rhport; + (void) result; + + /* new packet received */ + if ( ep_addr == _netd_itf.ep_out ) + { + handle_incoming_packet(xferred_bytes); + } + + /* data transmission finished */ + if ( ep_addr == _netd_itf.ep_in ) + { + /* TinyUSB requires the class driver to implement ZLP (since ZLP usage is class-specific) */ + + if ( xferred_bytes && (0 == (xferred_bytes % CFG_TUD_NET_ENDPOINT_SIZE)) ) + { + do_in_xfer(NULL, 0); /* a ZLP is needed */ + } + else + { + /* we're finally finished */ + can_xmit = true; + } + } + + if ( _netd_itf.ecm_mode && (ep_addr == _netd_itf.ep_notif) ) + { + if (sizeof(notify.ecm_buf.header) == xferred_bytes) ecm_report(false); + } + + return true; +} + +bool tud_network_can_xmit(uint16_t size) +{ + (void)size; + + return can_xmit; +} + +void tud_network_xmit(void *ref, uint16_t arg) +{ + uint8_t *data; + uint16_t len; + + if (!can_xmit) + return; + + len = (_netd_itf.ecm_mode) ? 0 : CFG_TUD_NET_PACKET_PREFIX_LEN; + data = transmitted + len; + + len += tud_network_xmit_cb(data, ref, arg); + + if (!_netd_itf.ecm_mode) + { + rndis_data_packet_t *hdr = (rndis_data_packet_t *) ((void*) transmitted); + memset(hdr, 0, sizeof(rndis_data_packet_t)); + hdr->MessageType = REMOTE_NDIS_PACKET_MSG; + hdr->MessageLength = len; + hdr->DataOffset = sizeof(rndis_data_packet_t) - offsetof(rndis_data_packet_t, DataOffset); + hdr->DataLength = len - sizeof(rndis_data_packet_t); + } + + do_in_xfer(transmitted, len); +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/net/ncm.h b/test-devices/composite-stm32/lib/tinyusb/class/net/ncm.h new file mode 100644 index 00000000..96ba11fb --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/net/ncm.h @@ -0,0 +1,69 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + + +#ifndef _TUSB_NCM_H_ +#define _TUSB_NCM_H_ + +#include "common/tusb_common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +// Table 4.3 Data Class Interface Protocol Codes +typedef enum +{ + NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK = 0x01 +} ncm_data_interface_protocol_code_t; + + +// Table 6.2 Class-Specific Request Codes for Network Control Model subclass +typedef enum +{ + NCM_SET_ETHERNET_MULTICAST_FILTERS = 0x40, + NCM_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x41, + NCM_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x42, + NCM_SET_ETHERNET_PACKET_FILTER = 0x43, + NCM_GET_ETHERNET_STATISTIC = 0x44, + NCM_GET_NTB_PARAMETERS = 0x80, + NCM_GET_NET_ADDRESS = 0x81, + NCM_SET_NET_ADDRESS = 0x82, + NCM_GET_NTB_FORMAT = 0x83, + NCM_SET_NTB_FORMAT = 0x84, + NCM_GET_NTB_INPUT_SIZE = 0x85, + NCM_SET_NTB_INPUT_SIZE = 0x86, + NCM_GET_MAX_DATAGRAM_SIZE = 0x87, + NCM_SET_MAX_DATAGRAM_SIZE = 0x88, + NCM_GET_CRC_MODE = 0x89, + NCM_SET_CRC_MODE = 0x8A, +} ncm_request_code_t; + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/net/ncm_device.c b/test-devices/composite-stm32/lib/tinyusb/class/net/ncm_device.c new file mode 100644 index 00000000..00892b49 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/net/ncm_device.c @@ -0,0 +1,511 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Jacob Berg Potter + * Copyright (c) 2020 Peter Lawrence + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if ( CFG_TUD_ENABLED && CFG_TUD_NCM ) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" +#include "net_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +#define NTH16_SIGNATURE 0x484D434E +#define NDP16_SIGNATURE_NCM0 0x304D434E +#define NDP16_SIGNATURE_NCM1 0x314D434E + +typedef struct TU_ATTR_PACKED +{ + uint16_t wLength; + uint16_t bmNtbFormatsSupported; + uint32_t dwNtbInMaxSize; + uint16_t wNdbInDivisor; + uint16_t wNdbInPayloadRemainder; + uint16_t wNdbInAlignment; + uint16_t wReserved; + uint32_t dwNtbOutMaxSize; + uint16_t wNdbOutDivisor; + uint16_t wNdbOutPayloadRemainder; + uint16_t wNdbOutAlignment; + uint16_t wNtbOutMaxDatagrams; +} ntb_parameters_t; + +typedef struct TU_ATTR_PACKED +{ + uint32_t dwSignature; + uint16_t wHeaderLength; + uint16_t wSequence; + uint16_t wBlockLength; + uint16_t wNdpIndex; +} nth16_t; + +typedef struct TU_ATTR_PACKED +{ + uint16_t wDatagramIndex; + uint16_t wDatagramLength; +} ndp16_datagram_t; + +typedef struct TU_ATTR_PACKED +{ + uint32_t dwSignature; + uint16_t wLength; + uint16_t wNextNdpIndex; + ndp16_datagram_t datagram[]; +} ndp16_t; + +typedef union TU_ATTR_PACKED { + struct { + nth16_t nth; + ndp16_t ndp; + }; + uint8_t data[CFG_TUD_NCM_IN_NTB_MAX_SIZE]; +} transmit_ntb_t; + +struct ecm_notify_struct +{ + tusb_control_request_t header; + uint32_t downlink, uplink; +}; + +typedef struct +{ + uint8_t itf_num; // Index number of Management Interface, +1 for Data Interface + uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active + + uint8_t ep_notif; + uint8_t ep_in; + uint8_t ep_out; + + const ndp16_t *ndp; + uint8_t num_datagrams, current_datagram_index; + + enum { + REPORT_SPEED, + REPORT_CONNECTED, + REPORT_DONE + } report_state; + bool report_pending; + + uint8_t current_ntb; // Index in transmit_ntb[] that is currently being filled with datagrams + uint8_t datagram_count; // Number of datagrams in transmit_ntb[current_ntb] + uint16_t next_datagram_offset; // Offset in transmit_ntb[current_ntb].data to place the next datagram + uint16_t ntb_in_size; // Maximum size of transmitted (IN to host) NTBs; initially CFG_TUD_NCM_IN_NTB_MAX_SIZE + uint8_t max_datagrams_per_ntb; // Maximum number of datagrams per NTB; initially CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB + + uint16_t nth_sequence; // Sequence number counter for transmitted NTBs + + bool transferring; + +} ncm_interface_t; + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static const ntb_parameters_t ntb_parameters = { + .wLength = sizeof(ntb_parameters_t), + .bmNtbFormatsSupported = 0x01, + .dwNtbInMaxSize = CFG_TUD_NCM_IN_NTB_MAX_SIZE, + .wNdbInDivisor = 4, + .wNdbInPayloadRemainder = 0, + .wNdbInAlignment = CFG_TUD_NCM_ALIGNMENT, + .wReserved = 0, + .dwNtbOutMaxSize = CFG_TUD_NCM_OUT_NTB_MAX_SIZE, + .wNdbOutDivisor = 4, + .wNdbOutPayloadRemainder = 0, + .wNdbOutAlignment = CFG_TUD_NCM_ALIGNMENT, + .wNtbOutMaxDatagrams = 0 +}; + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static transmit_ntb_t transmit_ntb[2]; + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t receive_ntb[CFG_TUD_NCM_OUT_NTB_MAX_SIZE]; + +static ncm_interface_t ncm_interface; + +/* + * Set up the NTB state in ncm_interface to be ready to add datagrams. + */ +static void ncm_prepare_for_tx(void) { + ncm_interface.datagram_count = 0; + // datagrams start after all the headers + ncm_interface.next_datagram_offset = sizeof(nth16_t) + sizeof(ndp16_t) + + ((CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB + 1) * sizeof(ndp16_datagram_t)); +} + +/* + * If not already transmitting, start sending the current NTB to the host and swap buffers + * to start filling the other one with datagrams. + */ +static void ncm_start_tx(void) { + if (ncm_interface.transferring) { + return; + } + + transmit_ntb_t *ntb = &transmit_ntb[ncm_interface.current_ntb]; + size_t ntb_length = ncm_interface.next_datagram_offset; + + // Fill in NTB header + ntb->nth.dwSignature = NTH16_SIGNATURE; + ntb->nth.wHeaderLength = sizeof(nth16_t); + ntb->nth.wSequence = ncm_interface.nth_sequence++; + ntb->nth.wBlockLength = ntb_length; + ntb->nth.wNdpIndex = sizeof(nth16_t); + + // Fill in NDP16 header and terminator + ntb->ndp.dwSignature = NDP16_SIGNATURE_NCM0; + ntb->ndp.wLength = sizeof(ndp16_t) + (ncm_interface.datagram_count + 1) * sizeof(ndp16_datagram_t); + ntb->ndp.wNextNdpIndex = 0; + ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramIndex = 0; + ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramLength = 0; + + // Kick off an endpoint transfer + usbd_edpt_xfer(0, ncm_interface.ep_in, ntb->data, ntb_length); + ncm_interface.transferring = true; + + // Swap to the other NTB and clear it out + ncm_interface.current_ntb = 1 - ncm_interface.current_ntb; + ncm_prepare_for_tx(); +} + +static struct ecm_notify_struct ncm_notify_connected = +{ + .header = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN + }, + .bRequest = CDC_NOTIF_NETWORK_CONNECTION, + .wValue = 1 /* Connected */, + .wLength = 0, + }, +}; + +static struct ecm_notify_struct ncm_notify_speed_change = +{ + .header = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN + }, + .bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE, + .wLength = 8, + }, + .downlink = 10000000, + .uplink = 10000000, +}; + +void tud_network_recv_renew(void) +{ + if (!ncm_interface.num_datagrams) + { + usbd_edpt_xfer(0, ncm_interface.ep_out, receive_ntb, sizeof(receive_ntb)); + return; + } + + const ndp16_t *ndp = ncm_interface.ndp; + const int i = ncm_interface.current_datagram_index; + ncm_interface.current_datagram_index++; + ncm_interface.num_datagrams--; + + tud_network_recv_cb(receive_ntb + ndp->datagram[i].wDatagramIndex, ndp->datagram[i].wDatagramLength); +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ + +void netd_init(void) +{ + tu_memclr(&ncm_interface, sizeof(ncm_interface)); + ncm_interface.ntb_in_size = CFG_TUD_NCM_IN_NTB_MAX_SIZE; + ncm_interface.max_datagrams_per_ntb = CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB; + ncm_prepare_for_tx(); +} + +void netd_reset(uint8_t rhport) +{ + (void) rhport; + + netd_init(); +} + +uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + // confirm interface hasn't already been allocated + TU_ASSERT(0 == ncm_interface.ep_notif, 0); + + //------------- Management Interface -------------// + ncm_interface.itf_num = itf_desc->bInterfaceNumber; + + uint16_t drv_len = sizeof(tusb_desc_interface_t); + uint8_t const * p_desc = tu_desc_next( itf_desc ); + + // Communication Functional Descriptors + while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) + { + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + // notification endpoint (if any) + if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + { + TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 ); + + ncm_interface.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + //------------- Data Interface -------------// + // - CDC-NCM data interface has 2 alternate settings + // - 0 : zero endpoints for inactive (default) + // - 1 : IN & OUT endpoints for transfer of NTBs + TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); + + do + { + tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc; + TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass, 0); + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } while((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (drv_len <= max_len)); + + // Pair of endpoints + TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0); + + TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &ncm_interface.ep_out, &ncm_interface.ep_in) ); + + drv_len += 2*sizeof(tusb_desc_endpoint_t); + + return drv_len; +} + +static void ncm_report(void) +{ + uint8_t const rhport = 0; + if (ncm_interface.report_state == REPORT_SPEED) { + ncm_notify_speed_change.header.wIndex = ncm_interface.itf_num; + usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_speed_change, sizeof(ncm_notify_speed_change)); + ncm_interface.report_state = REPORT_CONNECTED; + ncm_interface.report_pending = true; + } else if (ncm_interface.report_state == REPORT_CONNECTED) { + ncm_notify_connected.header.wIndex = ncm_interface.itf_num; + usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_connected, sizeof(ncm_notify_connected)); + ncm_interface.report_state = REPORT_DONE; + ncm_interface.report_pending = true; + } +} + +TU_ATTR_WEAK void tud_network_link_state_cb(bool state) +{ + (void)state; +} + +// Handle class control request +// return false to stall control endpoint (e.g unsupported request) +bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if ( stage != CONTROL_STAGE_SETUP ) return true; + + switch ( request->bmRequestType_bit.type ) + { + case TUSB_REQ_TYPE_STANDARD: + switch ( request->bRequest ) + { + case TUSB_REQ_GET_INTERFACE: + { + uint8_t const req_itfnum = (uint8_t) request->wIndex; + TU_VERIFY(ncm_interface.itf_num + 1 == req_itfnum); + + tud_control_xfer(rhport, request, &ncm_interface.itf_data_alt, 1); + } + break; + + case TUSB_REQ_SET_INTERFACE: + { + uint8_t const req_itfnum = (uint8_t) request->wIndex; + uint8_t const req_alt = (uint8_t) request->wValue; + + // Only valid for Data Interface with Alternate is either 0 or 1 + TU_VERIFY(ncm_interface.itf_num + 1 == req_itfnum && req_alt < 2); + + if (req_alt != ncm_interface.itf_data_alt) { + ncm_interface.itf_data_alt = req_alt; + + if (ncm_interface.itf_data_alt) { + if (!usbd_edpt_busy(rhport, ncm_interface.ep_out)) { + tud_network_recv_renew(); // prepare for incoming datagrams + } + if (!ncm_interface.report_pending) { + ncm_report(); + } + } + + tud_network_link_state_cb(ncm_interface.itf_data_alt); + } + + tud_control_status(rhport, request); + } + break; + + // unsupported request + default: return false; + } + break; + + case TUSB_REQ_TYPE_CLASS: + TU_VERIFY (ncm_interface.itf_num == request->wIndex); + + if (NCM_GET_NTB_PARAMETERS == request->bRequest) + { + tud_control_xfer(rhport, request, (void*)&ntb_parameters, sizeof(ntb_parameters)); + } + + break; + + // unsupported request + default: return false; + } + + return true; +} + +static void handle_incoming_datagram(uint32_t len) +{ + uint32_t size = len; + + if (len == 0) { + return; + } + + TU_ASSERT(size >= sizeof(nth16_t), ); + + const nth16_t *hdr = (const nth16_t *)receive_ntb; + TU_ASSERT(hdr->dwSignature == NTH16_SIGNATURE, ); + TU_ASSERT(hdr->wNdpIndex >= sizeof(nth16_t) && (hdr->wNdpIndex + sizeof(ndp16_t)) <= len, ); + + const ndp16_t *ndp = (const ndp16_t *)(receive_ntb + hdr->wNdpIndex); + TU_ASSERT(ndp->dwSignature == NDP16_SIGNATURE_NCM0 || ndp->dwSignature == NDP16_SIGNATURE_NCM1, ); + TU_ASSERT(hdr->wNdpIndex + ndp->wLength <= len, ); + + int num_datagrams = (ndp->wLength - 12) / 4; + ncm_interface.current_datagram_index = 0; + ncm_interface.num_datagrams = 0; + ncm_interface.ndp = ndp; + for (int i = 0; i < num_datagrams && ndp->datagram[i].wDatagramIndex && ndp->datagram[i].wDatagramLength; i++) + { + ncm_interface.num_datagrams++; + } + + tud_network_recv_renew(); +} + +bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) rhport; + (void) result; + + /* new datagram receive_ntb */ + if (ep_addr == ncm_interface.ep_out ) + { + handle_incoming_datagram(xferred_bytes); + } + + /* data transmission finished */ + if (ep_addr == ncm_interface.ep_in ) + { + if (ncm_interface.transferring) { + ncm_interface.transferring = false; + } + + // If there are datagrams queued up that we tried to send while this NTB was being emitted, send them now + if (ncm_interface.datagram_count && ncm_interface.itf_data_alt == 1) { + ncm_start_tx(); + } + } + + if (ep_addr == ncm_interface.ep_notif ) + { + ncm_interface.report_pending = false; + ncm_report(); + } + + return true; +} + +// poll network driver for its ability to accept another packet to transmit +bool tud_network_can_xmit(uint16_t size) +{ + TU_VERIFY(ncm_interface.itf_data_alt == 1); + + if (ncm_interface.datagram_count >= ncm_interface.max_datagrams_per_ntb) { + TU_LOG2("NTB full [by count]\r\n"); + return false; + } + + size_t next_datagram_offset = ncm_interface.next_datagram_offset; + if (next_datagram_offset + size > ncm_interface.ntb_in_size) { + TU_LOG2("ntb full [by size]\r\n"); + return false; + } + + return true; +} + +void tud_network_xmit(void *ref, uint16_t arg) +{ + transmit_ntb_t *ntb = &transmit_ntb[ncm_interface.current_ntb]; + size_t next_datagram_offset = ncm_interface.next_datagram_offset; + + uint16_t size = tud_network_xmit_cb(ntb->data + next_datagram_offset, ref, arg); + + ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramIndex = ncm_interface.next_datagram_offset; + ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramLength = size; + + ncm_interface.datagram_count++; + next_datagram_offset += size; + + // round up so the next datagram is aligned correctly + next_datagram_offset += (CFG_TUD_NCM_ALIGNMENT - 1); + next_datagram_offset -= (next_datagram_offset % CFG_TUD_NCM_ALIGNMENT); + + ncm_interface.next_datagram_offset = next_datagram_offset; + + ncm_start_tx(); +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/net/net_device.h b/test-devices/composite-stm32/lib/tinyusb/class/net/net_device.h new file mode 100644 index 00000000..6e294465 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/net/net_device.h @@ -0,0 +1,118 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Peter Lawrence + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_NET_DEVICE_H_ +#define _TUSB_NET_DEVICE_H_ + +#include "class/cdc/cdc.h" + +#if CFG_TUD_ECM_RNDIS && CFG_TUD_NCM +#error "Cannot enable both ECM_RNDIS and NCM network drivers" +#endif + +#include "ncm.h" + +/* declared here, NOT in usb_descriptors.c, so that the driver can intelligently ZLP as needed */ +#define CFG_TUD_NET_ENDPOINT_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) + +/* Maximum Transmission Unit (in bytes) of the network, including Ethernet header */ +#ifndef CFG_TUD_NET_MTU +#define CFG_TUD_NET_MTU 1514 +#endif + +#ifndef CFG_TUD_NCM_IN_NTB_MAX_SIZE +#define CFG_TUD_NCM_IN_NTB_MAX_SIZE 3200 +#endif + +#ifndef CFG_TUD_NCM_OUT_NTB_MAX_SIZE +#define CFG_TUD_NCM_OUT_NTB_MAX_SIZE 3200 +#endif + +#ifndef CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB +#define CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB 8 +#endif + +#ifndef CFG_TUD_NCM_ALIGNMENT +#define CFG_TUD_NCM_ALIGNMENT 4 +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + +// indicate to network driver that client has finished with the packet provided to network_recv_cb() +void tud_network_recv_renew(void); + +// poll network driver for its ability to accept another packet to transmit +bool tud_network_can_xmit(uint16_t size); + +// if network_can_xmit() returns true, network_xmit() can be called once +void tud_network_xmit(void *ref, uint16_t arg); + +//--------------------------------------------------------------------+ +// Application Callbacks (WEAK is optional) +//--------------------------------------------------------------------+ + +// client must provide this: return false if the packet buffer was not accepted +bool tud_network_recv_cb(const uint8_t *src, uint16_t size); + +// client must provide this: copy from network stack packet pointer to dst +uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg); + +//------------- ECM/RNDIS -------------// + +// client must provide this: initialize any network state back to the beginning +void tud_network_init_cb(void); + +// client must provide this: 48-bit MAC address +// TODO removed later since it is not part of tinyusb stack +extern const uint8_t tud_network_mac_address[6]; + +//------------- NCM -------------// + +// callback to client providing optional indication of internal state of network driver +void tud_network_link_state_cb(bool state); + +//--------------------------------------------------------------------+ +// INTERNAL USBD-CLASS DRIVER API +//--------------------------------------------------------------------+ +void netd_init (void); +void netd_reset (uint8_t rhport); +uint16_t netd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +bool netd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); +void netd_report (uint8_t *buf, uint16_t len); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_NET_DEVICE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc.h b/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc.h new file mode 100644 index 00000000..e7016ae2 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc.h @@ -0,0 +1,319 @@ + +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 N Conrad + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_USBTMC_H__ +#define _TUSB_USBTMC_H__ + +#include "common/tusb_common.h" + + +/* Implements USBTMC Revision 1.0, April 14, 2003 + + String descriptors must have a "LANGID=0x409"/US English string. + Characters must be 0x20 (' ') to 0x7E ('~') ASCII, + But MUST not contain: "/:?\* + Also must not have leading or trailing space (' ') + Device descriptor must state USB version 0x0200 or greater + + If USB488DeviceCapabilites.D2 = 1 (SR1), then there must be a INT endpoint. +*/ + +#define USBTMC_VERSION 0x0100 +#define USBTMC_488_VERSION 0x0100 + +typedef enum { + USBTMC_MSGID_DEV_DEP_MSG_OUT = 1u, + USBTMC_MSGID_DEV_DEP_MSG_IN = 2u, + USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT = 126u, + USBTMC_MSGID_VENDOR_SPECIFIC_IN = 127u, + USBTMC_MSGID_USB488_TRIGGER = 128u, +} usbtmc_msgid_enum; + +/// \brief Message header (For BULK OUT and BULK IN); 4 bytes +typedef struct TU_ATTR_PACKED +{ + uint8_t MsgID ; ///< Message type ID (usbtmc_msgid_enum) + uint8_t bTag ; ///< Transfer ID 1<=bTag<=255 + uint8_t bTagInverse ; ///< Complement of the tag + uint8_t _reserved ; ///< Must be 0x00 +} usbtmc_msg_header_t; + +typedef struct TU_ATTR_PACKED +{ + usbtmc_msg_header_t header; + uint8_t data[8]; +} usbtmc_msg_generic_t; + +/* Uses on the bulk-out endpoint: */ +// Next 8 bytes are message-specific +typedef struct TU_ATTR_PACKED { + usbtmc_msg_header_t header ; ///< Header + uint32_t TransferSize ; ///< Transfer size; LSB first + struct TU_ATTR_PACKED + { + unsigned int EOM : 1 ; ///< EOM set on last byte + } bmTransferAttributes; + uint8_t _reserved[3]; +} usbtmc_msg_request_dev_dep_out; + +TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_dev_dep_out) == 12u, "struct wrong length"); + +// Next 8 bytes are message-specific +typedef struct TU_ATTR_PACKED +{ + usbtmc_msg_header_t header ; ///< Header + uint32_t TransferSize ; ///< Transfer size; LSB first + struct TU_ATTR_PACKED + { + unsigned int TermCharEnabled : 1 ; ///< "The Bulk-IN transfer must terminate on the specified TermChar."; CAPABILITIES must list TermChar + } bmTransferAttributes; + uint8_t TermChar; + uint8_t _reserved[2]; +} usbtmc_msg_request_dev_dep_in; + +TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_dev_dep_in) == 12u, "struct wrong length"); + +/* Bulk-in headers */ + +typedef struct TU_ATTR_PACKED +{ + usbtmc_msg_header_t header; + uint32_t TransferSize; + struct TU_ATTR_PACKED + { + uint8_t EOM: 1; ///< Last byte of transfer is the end of the message + uint8_t UsingTermChar: 1; ///< Support TermChar && Request.TermCharEnabled && last char in transfer is TermChar + } bmTransferAttributes; + uint8_t _reserved[3]; +} usbtmc_msg_dev_dep_msg_in_header_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_msg_dev_dep_msg_in_header_t) == 12u, "struct wrong length"); + +/* Unsupported vendor things.... Are these ever used?*/ + +typedef struct TU_ATTR_PACKED +{ + usbtmc_msg_header_t header ; ///< Header + uint32_t TransferSize ; ///< Transfer size; LSB first + uint8_t _reserved[4]; +} usbtmc_msg_request_vendor_specific_out; + + +TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_vendor_specific_out) == 12u, "struct wrong length"); + +typedef struct TU_ATTR_PACKED +{ + usbtmc_msg_header_t header ; ///< Header + uint32_t TransferSize ; ///< Transfer size; LSB first + uint8_t _reserved[4]; +} usbtmc_msg_request_vendor_specific_in; + +TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_vendor_specific_in) == 12u, "struct wrong length"); + +// Control request type should use tusb_control_request_t + +/* +typedef struct TU_ATTR_PACKED { + struct { + unsigned int Recipient : 5 ; ///< EOM set on last byte + unsigned int Type : 2 ; ///< EOM set on last byte + unsigned int DirectionToHost : 1 ; ///< 0 is OUT, 1 is IN + } bmRequestType; + uint8_t bRequest ; ///< If bmRequestType.Type = Class, see usmtmc_request_type_enum + uint16_t wValue ; + uint16_t wIndex ; + uint16_t wLength ; // Number of bytes in data stage +} usbtmc_class_specific_control_req; + +*/ +// bulk-in protocol errors +enum { + USBTMC_BULK_IN_ERR_INCOMPLETE_HEADER = 1u, + USBTMC_BULK_IN_ERR_UNSUPPORTED = 2u, + USBTMC_BULK_IN_ERR_BAD_PARAMETER = 3u, + USBTMC_BULK_IN_ERR_DATA_TOO_SHORT = 4u, + USBTMC_BULK_IN_ERR_DATA_TOO_LONG = 5u, +}; +// bult-in halt errors +enum { + USBTMC_BULK_IN_ERR = 1u, ///< receives a USBTMC command message that expects a response while a + /// Bulk-IN transfer is in progress +}; + +typedef enum { + USBTMC_bREQUEST_INITIATE_ABORT_BULK_OUT = 1u, + USBTMC_bREQUEST_CHECK_ABORT_BULK_OUT_STATUS = 2u, + USBTMC_bREQUEST_INITIATE_ABORT_BULK_IN = 3u, + USBTMC_bREQUEST_CHECK_ABORT_BULK_IN_STATUS = 4u, + USBTMC_bREQUEST_INITIATE_CLEAR = 5u, + USBTMC_bREQUEST_CHECK_CLEAR_STATUS = 6u, + USBTMC_bREQUEST_GET_CAPABILITIES = 7u, + + USBTMC_bREQUEST_INDICATOR_PULSE = 64u, // Optional + + /****** USBTMC 488 *************/ + USB488_bREQUEST_READ_STATUS_BYTE = 128u, + USB488_bREQUEST_REN_CONTROL = 160u, + USB488_bREQUEST_GO_TO_LOCAL = 161u, + USB488_bREQUEST_LOCAL_LOCKOUT = 162u, + +} usmtmc_request_type_enum; + +typedef enum { + USBTMC_STATUS_SUCCESS = 0x01, + USBTMC_STATUS_PENDING = 0x02, + USBTMC_STATUS_FAILED = 0x80, + USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS = 0x81, + USBTMC_STATUS_SPLIT_NOT_IN_PROGRESS = 0x82, + USBTMC_STATUS_SPLIT_IN_PROGRESS = 0x83, + + /****** USBTMC 488 *************/ + USB488_STATUS_INTERRUPT_IN_BUSY = 0x20 +} usbtmc_status_enum; + +/************************************************************ + * Control Responses + */ + +typedef struct TU_ATTR_PACKED { + uint8_t USBTMC_status; ///< usbtmc_status_enum + uint8_t _reserved; + uint16_t bcdUSBTMC; ///< USBTMC_VERSION + + struct TU_ATTR_PACKED + { + unsigned int listenOnly :1; + unsigned int talkOnly :1; + unsigned int supportsIndicatorPulse :1; + } bmIntfcCapabilities; + struct TU_ATTR_PACKED + { + unsigned int canEndBulkInOnTermChar :1; + } bmDevCapabilities; + uint8_t _reserved2[6]; + uint8_t _reserved3[12]; +} usbtmc_response_capabilities_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_response_capabilities_t) == 0x18, "struct wrong length"); + +typedef struct TU_ATTR_PACKED +{ + uint8_t USBTMC_status; + struct TU_ATTR_PACKED + { + unsigned int BulkInFifoBytes :1; + } bmClear; +} usbtmc_get_clear_status_rsp_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_get_clear_status_rsp_t) == 2u, "struct wrong length"); + +// Used for both abort bulk IN and bulk OUT +typedef struct TU_ATTR_PACKED +{ + uint8_t USBTMC_status; + uint8_t bTag; +} usbtmc_initiate_abort_rsp_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_get_clear_status_rsp_t) == 2u, "struct wrong length"); + +// Used for both check_abort_bulk_in_status and check_abort_bulk_out_status +typedef struct TU_ATTR_PACKED +{ + uint8_t USBTMC_status; + struct TU_ATTR_PACKED + { + unsigned int BulkInFifoBytes : 1; ///< Has queued data or a short packet that is queued + } bmAbortBulkIn; + uint8_t _reserved[2]; ///< Must be zero + uint32_t NBYTES_RXD_TXD; +} usbtmc_check_abort_bulk_rsp_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_check_abort_bulk_rsp_t) == 8u, "struct wrong length"); + +typedef struct TU_ATTR_PACKED +{ + uint8_t USBTMC_status; ///< usbtmc_status_enum + uint8_t _reserved; + uint16_t bcdUSBTMC; ///< USBTMC_VERSION + + struct TU_ATTR_PACKED + { + unsigned int listenOnly :1; + unsigned int talkOnly :1; + unsigned int supportsIndicatorPulse :1; + } bmIntfcCapabilities; + + struct TU_ATTR_PACKED + { + unsigned int canEndBulkInOnTermChar :1; + } bmDevCapabilities; + + uint8_t _reserved2[6]; + uint16_t bcdUSB488; + + struct TU_ATTR_PACKED + { + unsigned int is488_2 :1; + unsigned int supportsREN_GTL_LLO :1; + unsigned int supportsTrigger :1; + } bmIntfcCapabilities488; + + struct TU_ATTR_PACKED + { + unsigned int SCPI :1; + unsigned int SR1 :1; + unsigned int RL1 :1; + unsigned int DT1 :1; + } bmDevCapabilities488; + uint8_t _reserved3[8]; +} usbtmc_response_capabilities_488_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_response_capabilities_488_t) == 0x18, "struct wrong length"); + +typedef struct TU_ATTR_PACKED +{ + uint8_t USBTMC_status; + uint8_t bTag; + uint8_t statusByte; +} usbtmc_read_stb_rsp_488_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_rsp_488_t) == 3u, "struct wrong length"); + +typedef struct TU_ATTR_PACKED +{ + struct TU_ATTR_PACKED + { + unsigned int bTag : 7; + unsigned int one : 1; + } bNotify1; + uint8_t StatusByte; +} usbtmc_read_stb_interrupt_488_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_interrupt_488_t) == 2u, "struct wrong length"); + +#endif + diff --git a/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c b/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c new file mode 100644 index 00000000..af4a9273 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c @@ -0,0 +1,886 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Nathan Conrad + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/* + * This library is not fully reentrant, though it is reentrant from the view + * of either the application layer or the USB stack. Due to its locking, + * it is not safe to call its functions from interrupts. + * + * The one exception is that its functions may not be called from the application + * until the USB stack is initialized. This should not be a problem since the + * device shouldn't be sending messages until it receives a request from the + * host. + */ + + +/* + * In the case of single-CPU "no OS", this task is never preempted other than by + * interrupts, and the USBTMC code isn't called by interrupts, so all is OK. For "no OS", + * the mutex structure's main effect is to disable the USB interrupts. + * With an OS, this class driver uses the OSAL to perform locking. The code uses a single lock + * and does not call outside of this class with a lock held, so deadlocks won't happen. + */ + +//Limitations: +// "vendor-specific" commands are not handled. +// Dealing with "termchar" must be handled by the application layer, +// though additional error checking is does in this module. +// talkOnly and listenOnly are NOT supported. They're not permitted +// in USB488, anyway. + +/* Supported: + * + * Notification pulse + * Trigger + * Read status byte (both by interrupt endpoint and control message) + * + */ + + +// TODO: +// USBTMC 3.2.2 error conditions not strictly followed +// No local lock-out, REN, or GTL. +// Clear message available status byte at the correct time? (488 4.3.1.3) +// Ability to defer status byte transmission +// Transmission of status byte in response to USB488 SRQ condition + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_USBTMC) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "usbtmc_device.h" + +#ifdef xDEBUG +#include "uart_util.h" +static char logMsg[150]; +#endif + +// Buffer size must be an exact multiple of the max packet size for both +// bulk (up to 64 bytes for FS, 512 bytes for HS). In addation, this driver +// imposes a minimum buffer size of 32 bytes. +#define USBTMCD_BUFFER_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) + +/* + * The state machine does not allow simultaneous reading and writing. This is + * consistent with USBTMC. + */ + +typedef enum +{ + STATE_CLOSED, // Endpoints have not yet been opened since USB reset + STATE_NAK, // Bulk-out endpoint is in NAK state. + STATE_IDLE, // Bulk-out endpoint is waiting for CMD. + STATE_RCV, // Bulk-out is receiving DEV_DEP message + STATE_TX_REQUESTED, + STATE_TX_INITIATED, + STATE_TX_SHORTED, + STATE_CLEARING, + STATE_ABORTING_BULK_IN, + STATE_ABORTING_BULK_IN_SHORTED, // aborting, and short packet has been queued for transmission + STATE_ABORTING_BULK_IN_ABORTED, // aborting, and short packet has been transmitted + STATE_ABORTING_BULK_OUT, + STATE_NUM_STATES +} usbtmcd_state_enum; + +#if (CFG_TUD_USBTMC_ENABLE_488) + typedef usbtmc_response_capabilities_488_t usbtmc_capabilities_specific_t; +#else + typedef usbtmc_response_capabilities_t usbtmc_capabilities_specific_t; +#endif + + +typedef struct +{ + volatile usbtmcd_state_enum state; + + uint8_t itf_id; + uint8_t rhport; + uint8_t ep_bulk_in; + uint8_t ep_bulk_out; + uint8_t ep_int_in; + // IN buffer is only used for first packet, not the remainder + // in order to deal with prepending header + CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_in_buf[USBTMCD_BUFFER_SIZE]; + uint32_t ep_bulk_in_wMaxPacketSize; + // OUT buffer receives one packet at a time + CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_out_buf[USBTMCD_BUFFER_SIZE]; + uint32_t ep_bulk_out_wMaxPacketSize; + + uint32_t transfer_size_remaining; // also used for requested length for bulk IN. + uint32_t transfer_size_sent; // To keep track of data bytes that have been queued in FIFO (not header bytes) + + uint8_t lastBulkOutTag; // used for aborts (mostly) + uint8_t lastBulkInTag; // used for aborts (mostly) + + uint8_t const * devInBuffer; // pointer to application-layer used for transmissions + + usbtmc_capabilities_specific_t const * capabilities; +} usbtmc_interface_state_t; + +CFG_TUSB_MEM_SECTION static usbtmc_interface_state_t usbtmc_state = +{ + .itf_id = 0xFF, +}; + +// We need all headers to fit in a single packet in this implementation, 32 bytes will fit all standard USBTMC headers +TU_VERIFY_STATIC(USBTMCD_BUFFER_SIZE >= 32u,"USBTMC dev buffer size too small"); + +static bool handle_devMsgOutStart(uint8_t rhport, void *data, size_t len); +static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t packetLen); + +static uint8_t termChar; +static uint8_t termCharRequested = false; + +osal_mutex_def_t usbtmcLockBuffer; +static osal_mutex_t usbtmcLock; + +// Our own private lock, mostly for the state variable. +#define criticalEnter() do {osal_mutex_lock(usbtmcLock,OSAL_TIMEOUT_WAIT_FOREVER); } while (0) +#define criticalLeave() do {osal_mutex_unlock(usbtmcLock); } while (0) + +bool atomicChangeState(usbtmcd_state_enum expectedState, usbtmcd_state_enum newState) +{ + bool ret = true; + criticalEnter(); + usbtmcd_state_enum oldState = usbtmc_state.state; + if (oldState == expectedState) + { + usbtmc_state.state = newState; + } + else + { + ret = false; + } + criticalLeave(); + return ret; +} + +// called from app +// We keep a reference to the buffer, so it MUST not change until the app is +// notified that the transfer is complete. +// length of data is specified in the hdr. + +// We can't just send the whole thing at once because we need to concatanate the +// header with the data. +bool tud_usbtmc_transmit_dev_msg_data( + const void * data, size_t len, + bool endOfMessage, + bool usingTermChar) +{ + const unsigned int txBufLen = sizeof(usbtmc_state.ep_bulk_in_buf); + +#ifndef NDEBUG + TU_ASSERT(len > 0u); + TU_ASSERT(len <= usbtmc_state.transfer_size_remaining); + TU_ASSERT(usbtmc_state.transfer_size_sent == 0u); + if(usingTermChar) + { + TU_ASSERT(usbtmc_state.capabilities->bmDevCapabilities.canEndBulkInOnTermChar); + TU_ASSERT(termCharRequested); + TU_ASSERT(((uint8_t const*)data)[len-1u] == termChar); + } +#endif + + TU_VERIFY(usbtmc_state.state == STATE_TX_REQUESTED); + usbtmc_msg_dev_dep_msg_in_header_t *hdr = (usbtmc_msg_dev_dep_msg_in_header_t*)usbtmc_state.ep_bulk_in_buf; + tu_varclr(hdr); + hdr->header.MsgID = USBTMC_MSGID_DEV_DEP_MSG_IN; + hdr->header.bTag = usbtmc_state.lastBulkInTag; + hdr->header.bTagInverse = (uint8_t)~(usbtmc_state.lastBulkInTag); + hdr->TransferSize = len; + hdr->bmTransferAttributes.EOM = endOfMessage; + hdr->bmTransferAttributes.UsingTermChar = usingTermChar; + + // Copy in the header + const size_t headerLen = sizeof(*hdr); + const size_t dataLen = ((headerLen + hdr->TransferSize) <= txBufLen) ? + len : (txBufLen - headerLen); + const size_t packetLen = headerLen + dataLen; + + memcpy((uint8_t*)(usbtmc_state.ep_bulk_in_buf) + headerLen, data, dataLen); + usbtmc_state.transfer_size_remaining = len - dataLen; + usbtmc_state.transfer_size_sent = dataLen; + usbtmc_state.devInBuffer = (uint8_t const*) data + (dataLen); + + bool stateChanged = + atomicChangeState(STATE_TX_REQUESTED, (packetLen >= txBufLen) ? STATE_TX_INITIATED : STATE_TX_SHORTED); + TU_VERIFY(stateChanged); + TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf, (uint16_t)packetLen)); + return true; +} + +void usbtmcd_init_cb(void) +{ + usbtmc_state.capabilities = tud_usbtmc_get_capabilities_cb(); +#ifndef NDEBUG +# if CFG_TUD_USBTMC_ENABLE_488 + if (usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger) { + TU_ASSERT(&tud_usbtmc_msg_trigger_cb != NULL,); + } + // Per USB488 spec: table 8 + TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.listenOnly,); + TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.talkOnly,); +# endif + if (usbtmc_state.capabilities->bmIntfcCapabilities.supportsIndicatorPulse) { + TU_ASSERT(&tud_usbtmc_indicator_pulse_cb != NULL,); + } +#endif + + usbtmcLock = osal_mutex_create(&usbtmcLockBuffer); +} + +uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + (void)rhport; + + uint16_t drv_len; + uint8_t const * p_desc; + uint8_t found_endpoints = 0; + + TU_VERIFY(itf_desc->bInterfaceClass == TUD_USBTMC_APP_CLASS , 0); + TU_VERIFY(itf_desc->bInterfaceSubClass == TUD_USBTMC_APP_SUBCLASS, 0); + +#ifndef NDEBUG + // Only 2 or 3 endpoints are allowed for USBTMC. + TU_ASSERT((itf_desc->bNumEndpoints == 2) || (itf_desc->bNumEndpoints ==3), 0); +#endif + + TU_ASSERT(usbtmc_state.state == STATE_CLOSED, 0); + + // Interface + drv_len = 0u; + p_desc = (uint8_t const *) itf_desc; + + usbtmc_state.itf_id = itf_desc->bInterfaceNumber; + usbtmc_state.rhport = rhport; + + while (found_endpoints < itf_desc->bNumEndpoints && drv_len <= max_len) + { + if ( TUSB_DESC_ENDPOINT == p_desc[DESC_OFFSET_TYPE]) + { + tusb_desc_endpoint_t const *ep_desc = (tusb_desc_endpoint_t const *)p_desc; + switch(ep_desc->bmAttributes.xfer) { + case TUSB_XFER_BULK: + // Ensure buffer is an exact multiple of the maxPacketSize + TU_ASSERT((USBTMCD_BUFFER_SIZE % tu_edpt_packet_size(ep_desc)) == 0, 0); + if (tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN) + { + usbtmc_state.ep_bulk_in = ep_desc->bEndpointAddress; + usbtmc_state.ep_bulk_in_wMaxPacketSize = tu_edpt_packet_size(ep_desc); + } else { + usbtmc_state.ep_bulk_out = ep_desc->bEndpointAddress; + usbtmc_state.ep_bulk_out_wMaxPacketSize = tu_edpt_packet_size(ep_desc); + } + + break; + case TUSB_XFER_INTERRUPT: +#ifndef NDEBUG + TU_ASSERT(tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN, 0); + TU_ASSERT(usbtmc_state.ep_int_in == 0, 0); +#endif + usbtmc_state.ep_int_in = ep_desc->bEndpointAddress; + break; + default: + TU_ASSERT(false, 0); + } + TU_ASSERT( usbd_edpt_open(rhport, ep_desc), 0); + found_endpoints++; + } + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + // bulk endpoints are required, but interrupt IN is optional +#ifndef NDEBUG + TU_ASSERT(usbtmc_state.ep_bulk_in != 0, 0); + TU_ASSERT(usbtmc_state.ep_bulk_out != 0, 0); + if (itf_desc->bNumEndpoints == 2) + { + TU_ASSERT(usbtmc_state.ep_int_in == 0, 0); + } + else if (itf_desc->bNumEndpoints == 3) + { + TU_ASSERT(usbtmc_state.ep_int_in != 0, 0); + } +#if (CFG_TUD_USBTMC_ENABLE_488) + if(usbtmc_state.capabilities->bmIntfcCapabilities488.is488_2 || + usbtmc_state.capabilities->bmDevCapabilities488.SR1) + { + TU_ASSERT(usbtmc_state.ep_int_in != 0, 0); + } +#endif +#endif + atomicChangeState(STATE_CLOSED, STATE_NAK); + tud_usbtmc_open_cb(itf_desc->iInterface); + + return drv_len; +} +// Tell USBTMC class to set its bulk-in EP to ACK so that it can +// receive USBTMC commands. +// Returns false if it was already in an ACK state or is busy +// processing a command (such as a clear). Returns true if it was +// in the NAK state and successfully transitioned to the ACK wait +// state. +bool tud_usbtmc_start_bus_read() +{ + usbtmcd_state_enum oldState = usbtmc_state.state; + switch(oldState) + { + // These may transition to IDLE + case STATE_NAK: + case STATE_ABORTING_BULK_IN_ABORTED: + TU_VERIFY(atomicChangeState(oldState, STATE_IDLE)); + break; + // When receiving, let it remain receiving + case STATE_RCV: + break; + default: + TU_VERIFY(false); + } + TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, 64)); + return true; +} + +void usbtmcd_reset_cb(uint8_t rhport) +{ + (void)rhport; + usbtmc_capabilities_specific_t const * capabilities = tud_usbtmc_get_capabilities_cb(); + + criticalEnter(); + tu_varclr(&usbtmc_state); + usbtmc_state.capabilities = capabilities; + usbtmc_state.itf_id = 0xFFu; + criticalLeave(); +} + +static bool handle_devMsgOutStart(uint8_t rhport, void *data, size_t len) +{ + (void)rhport; + // return true upon failure, as we can assume error is being handled elsewhere. + TU_VERIFY(atomicChangeState(STATE_IDLE, STATE_RCV), true); + usbtmc_state.transfer_size_sent = 0u; + + // must be a header, should have been confirmed before calling here. + usbtmc_msg_request_dev_dep_out *msg = (usbtmc_msg_request_dev_dep_out*)data; + usbtmc_state.transfer_size_remaining = msg->TransferSize; + TU_VERIFY(tud_usbtmc_msgBulkOut_start_cb(msg)); + + TU_VERIFY(handle_devMsgOut(rhport, (uint8_t*)data + sizeof(*msg), len - sizeof(*msg), len)); + usbtmc_state.lastBulkOutTag = msg->header.bTag; + return true; +} + +static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t packetLen) +{ + (void)rhport; + // return true upon failure, as we can assume error is being handled elsewhere. + TU_VERIFY(usbtmc_state.state == STATE_RCV,true); + + bool shortPacket = (packetLen < usbtmc_state.ep_bulk_out_wMaxPacketSize); + + // Packet is to be considered complete when we get enough data or at a short packet. + bool atEnd = false; + if(len >= usbtmc_state.transfer_size_remaining || shortPacket) + { + atEnd = true; + TU_VERIFY(atomicChangeState(STATE_RCV, STATE_NAK)); + } + + len = tu_min32(len, usbtmc_state.transfer_size_remaining); + + usbtmc_state.transfer_size_remaining -= len; + usbtmc_state.transfer_size_sent += len; + + // App may (should?) call the wait_for_bus() command at this point + if(!tud_usbtmc_msg_data_cb(data, len, atEnd)) + { + // TODO: Go to an error state upon failure other than just stalling the EP? + return false; + } + + + return true; +} + +static bool handle_devMsgIn(void *data, size_t len) +{ + TU_VERIFY(len == sizeof(usbtmc_msg_request_dev_dep_in)); + usbtmc_msg_request_dev_dep_in *msg = (usbtmc_msg_request_dev_dep_in*)data; + bool stateChanged = atomicChangeState(STATE_IDLE, STATE_TX_REQUESTED); + TU_VERIFY(stateChanged); + usbtmc_state.lastBulkInTag = msg->header.bTag; + usbtmc_state.transfer_size_remaining = msg->TransferSize; + usbtmc_state.transfer_size_sent = 0u; + + termCharRequested = msg->bmTransferAttributes.TermCharEnabled; + termChar = msg->TermChar; + + if(termCharRequested) + TU_VERIFY(usbtmc_state.capabilities->bmDevCapabilities.canEndBulkInOnTermChar); + + TU_VERIFY(tud_usbtmc_msgBulkIn_request_cb(msg)); + return true; +} + +bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + TU_VERIFY(result == XFER_RESULT_SUCCESS); + //uart_tx_str_sync("TMC XFER CB\r\n"); + if(usbtmc_state.state == STATE_CLEARING) { + return true; /* I think we can ignore everything here */ + } + + if(ep_addr == usbtmc_state.ep_bulk_out) + { + usbtmc_msg_generic_t *msg = NULL; + + switch(usbtmc_state.state) + { + case STATE_IDLE: + TU_VERIFY(xferred_bytes >= sizeof(usbtmc_msg_generic_t)); + msg = (usbtmc_msg_generic_t*)(usbtmc_state.ep_bulk_out_buf); + uint8_t invInvTag = (uint8_t)~(msg->header.bTagInverse); + TU_VERIFY(msg->header.bTag == invInvTag); + TU_VERIFY(msg->header.bTag != 0x00); + + switch(msg->header.MsgID) { + case USBTMC_MSGID_DEV_DEP_MSG_OUT: + if(!handle_devMsgOutStart(rhport, msg, xferred_bytes)) + { + usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); + TU_VERIFY(false); + } + break; + + case USBTMC_MSGID_DEV_DEP_MSG_IN: + TU_VERIFY(handle_devMsgIn(msg, xferred_bytes)); + break; + +#if (CFG_TUD_USBTMC_ENABLE_488) + case USBTMC_MSGID_USB488_TRIGGER: + // Spec says we halt the EP if we didn't declare we support it. + TU_VERIFY(usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger); + TU_VERIFY(tud_usbtmc_msg_trigger_cb(msg)); + + break; +#endif + case USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT: + case USBTMC_MSGID_VENDOR_SPECIFIC_IN: + default: + usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); + TU_VERIFY(false); + return false; + } + return true; + + case STATE_RCV: + if(!handle_devMsgOut(rhport, usbtmc_state.ep_bulk_out_buf, xferred_bytes, xferred_bytes)) + { + usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); + TU_VERIFY(false); + } + return true; + + case STATE_ABORTING_BULK_OUT: + TU_VERIFY(false); + return false; // Should be stalled by now, shouldn't have received a packet. + + case STATE_TX_REQUESTED: + case STATE_TX_INITIATED: + case STATE_ABORTING_BULK_IN: + case STATE_ABORTING_BULK_IN_SHORTED: + case STATE_ABORTING_BULK_IN_ABORTED: + default: + TU_VERIFY(false); + } + } + else if(ep_addr == usbtmc_state.ep_bulk_in) + { + switch(usbtmc_state.state) { + case STATE_TX_SHORTED: + TU_VERIFY(atomicChangeState(STATE_TX_SHORTED, STATE_NAK)); + TU_VERIFY(tud_usbtmc_msgBulkIn_complete_cb()); + break; + + case STATE_TX_INITIATED: + if(usbtmc_state.transfer_size_remaining >= sizeof(usbtmc_state.ep_bulk_in_buf)) + { + // FIXME! This removes const below! + TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, + (void*)(uintptr_t) usbtmc_state.devInBuffer, sizeof(usbtmc_state.ep_bulk_in_buf))); + usbtmc_state.devInBuffer += sizeof(usbtmc_state.ep_bulk_in_buf); + usbtmc_state.transfer_size_remaining -= sizeof(usbtmc_state.ep_bulk_in_buf); + usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.ep_bulk_in_buf); + } + else // last packet + { + size_t packetLen = usbtmc_state.transfer_size_remaining; + memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, usbtmc_state.transfer_size_remaining); + usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.transfer_size_remaining); + usbtmc_state.transfer_size_remaining = 0; + usbtmc_state.devInBuffer = NULL; + TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf, (uint16_t)packetLen) ); + if(((packetLen % usbtmc_state.ep_bulk_in_wMaxPacketSize) != 0) || (packetLen == 0 )) + { + usbtmc_state.state = STATE_TX_SHORTED; + } + } + return true; + + case STATE_ABORTING_BULK_IN: + // need to send short packet (ZLP?) + TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,(uint16_t)0u)); + usbtmc_state.state = STATE_ABORTING_BULK_IN_SHORTED; + return true; + + case STATE_ABORTING_BULK_IN_SHORTED: + /* Done. :)*/ + usbtmc_state.state = STATE_ABORTING_BULK_IN_ABORTED; + return true; + + default: + TU_ASSERT(false); + return false; + } + } + else if (ep_addr == usbtmc_state.ep_int_in) { + // Good? + return true; + } + return false; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + // nothing to do with DATA and ACK stage + if ( stage != CONTROL_STAGE_SETUP ) return true; + + uint8_t tmcStatusCode = USBTMC_STATUS_FAILED; +#if (CFG_TUD_USBTMC_ENABLE_488) + uint8_t bTag; +#endif + + if((request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) && + (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_ENDPOINT) && + (request->bRequest == TUSB_REQ_CLEAR_FEATURE) && + (request->wValue == TUSB_REQ_FEATURE_EDPT_HALT)) + { + uint32_t ep_addr = (request->wIndex); + + // At this point, a transfer MAY be in progress. Based on USB spec, when clearing bulk EP HALT, + // the EP transfer buffer needs to be cleared and DTOG needs to be reset, even if + // the EP is not halted. The only USBD API interface to do this is to stall and then unstall the EP. + if(ep_addr == usbtmc_state.ep_bulk_out) + { + criticalEnter(); + usbd_edpt_stall(rhport, (uint8_t)ep_addr); + usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr); + usbtmc_state.state = STATE_NAK; // USBD core has placed EP in NAK state for us + criticalLeave(); + tud_usbtmc_bulkOut_clearFeature_cb(); + } + else if (ep_addr == usbtmc_state.ep_bulk_in) + { + usbd_edpt_stall(rhport, (uint8_t)ep_addr); + usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr); + tud_usbtmc_bulkIn_clearFeature_cb(); + } + else if ((usbtmc_state.ep_int_in != 0) && (ep_addr == usbtmc_state.ep_int_in)) + { + // Clearing interrupt in EP + usbd_edpt_stall(rhport, (uint8_t)ep_addr); + usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr); + } + else + { + return false; + } + return true; + } + + // Otherwise, we only handle class requests. + if(request->bmRequestType_bit.type != TUSB_REQ_TYPE_CLASS) + { + return false; + } + + // Verification that we own the interface is unneeded since it's been routed to us specifically. + + switch(request->bRequest) + { + // USBTMC required requests + case USBTMC_bREQUEST_INITIATE_ABORT_BULK_OUT: + { + usbtmc_initiate_abort_rsp_t rsp = { + .bTag = usbtmc_state.lastBulkOutTag, + }; + TU_VERIFY(request->bmRequestType == 0xA2); // in,class,interface + TU_VERIFY(request->wLength == sizeof(rsp)); + TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_out); + + // wValue is the requested bTag to abort + if(usbtmc_state.state != STATE_RCV) + { + rsp.USBTMC_status = USBTMC_STATUS_FAILED; + } + else if(usbtmc_state.lastBulkOutTag == (request->wValue & 0x7Fu)) + { + rsp.USBTMC_status = USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS; + } + else + { + rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; + // Check if we've queued a short packet + criticalEnter(); + usbtmc_state.state = STATE_ABORTING_BULK_OUT; + criticalLeave(); + TU_VERIFY(tud_usbtmc_initiate_abort_bulk_out_cb(&(rsp.USBTMC_status))); + usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); + } + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); + return true; + } + + case USBTMC_bREQUEST_CHECK_ABORT_BULK_OUT_STATUS: + { + usbtmc_check_abort_bulk_rsp_t rsp = { + .USBTMC_status = USBTMC_STATUS_SUCCESS, + .NBYTES_RXD_TXD = usbtmc_state.transfer_size_sent + }; + TU_VERIFY(request->bmRequestType == 0xA2); // in,class,EP + TU_VERIFY(request->wLength == sizeof(rsp)); + TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_out); + TU_VERIFY(tud_usbtmc_check_abort_bulk_out_cb(&rsp)); + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); + return true; + } + + case USBTMC_bREQUEST_INITIATE_ABORT_BULK_IN: + { + usbtmc_initiate_abort_rsp_t rsp = { + .bTag = usbtmc_state.lastBulkInTag, + }; + TU_VERIFY(request->bmRequestType == 0xA2); // in,class,interface + TU_VERIFY(request->wLength == sizeof(rsp)); + TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_in); + // wValue is the requested bTag to abort + if((usbtmc_state.state == STATE_TX_REQUESTED || usbtmc_state.state == STATE_TX_INITIATED) && + usbtmc_state.lastBulkInTag == (request->wValue & 0x7Fu)) + { + rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; + usbtmc_state.transfer_size_remaining = 0u; + // Check if we've queued a short packet + criticalEnter(); + usbtmc_state.state = ((usbtmc_state.transfer_size_sent % usbtmc_state.ep_bulk_in_wMaxPacketSize) == 0) ? + STATE_ABORTING_BULK_IN : STATE_ABORTING_BULK_IN_SHORTED; + criticalLeave(); + if(usbtmc_state.transfer_size_sent == 0) + { + // Send short packet, nothing is in the buffer yet + TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,(uint16_t)0u)); + usbtmc_state.state = STATE_ABORTING_BULK_IN_SHORTED; + } + TU_VERIFY(tud_usbtmc_initiate_abort_bulk_in_cb(&(rsp.USBTMC_status))); + } + else if((usbtmc_state.state == STATE_TX_REQUESTED || usbtmc_state.state == STATE_TX_INITIATED)) + { // FIXME: Unsure how to check if the OUT endpoint fifo is non-empty.... + rsp.USBTMC_status = USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS; + } + else + { + rsp.USBTMC_status = USBTMC_STATUS_FAILED; + } + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); + return true; + } + + case USBTMC_bREQUEST_CHECK_ABORT_BULK_IN_STATUS: + { + TU_VERIFY(request->bmRequestType == 0xA2); // in,class,EP + TU_VERIFY(request->wLength == 8u); + + usbtmc_check_abort_bulk_rsp_t rsp = + { + .USBTMC_status = USBTMC_STATUS_FAILED, + .bmAbortBulkIn = + { + .BulkInFifoBytes = (usbtmc_state.state != STATE_ABORTING_BULK_IN_ABORTED) + }, + .NBYTES_RXD_TXD = usbtmc_state.transfer_size_sent, + }; + TU_VERIFY(tud_usbtmc_check_abort_bulk_in_cb(&rsp)); + criticalEnter(); + switch(usbtmc_state.state) + { + case STATE_ABORTING_BULK_IN_ABORTED: + rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; + usbtmc_state.state = STATE_IDLE; + break; + case STATE_ABORTING_BULK_IN: + case STATE_ABORTING_BULK_OUT: + rsp.USBTMC_status = USBTMC_STATUS_PENDING; + break; + default: + break; + } + criticalLeave(); + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); + + return true; + } + + case USBTMC_bREQUEST_INITIATE_CLEAR: + { + TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface + TU_VERIFY(request->wLength == sizeof(tmcStatusCode)); + // After receiving an INITIATE_CLEAR request, the device must Halt the Bulk-OUT endpoint, queue the + // control endpoint response shown in Table 31, and clear all input buffers and output buffers. + usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); + usbtmc_state.transfer_size_remaining = 0; + criticalEnter(); + usbtmc_state.state = STATE_CLEARING; + criticalLeave(); + TU_VERIFY(tud_usbtmc_initiate_clear_cb(&tmcStatusCode)); + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&tmcStatusCode,sizeof(tmcStatusCode))); + return true; + } + + case USBTMC_bREQUEST_CHECK_CLEAR_STATUS: + { + TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface + usbtmc_get_clear_status_rsp_t clearStatusRsp = {0}; + TU_VERIFY(request->wLength == sizeof(clearStatusRsp)); + + if(usbd_edpt_busy(rhport, usbtmc_state.ep_bulk_in)) + { + // Stuff stuck in TX buffer? + clearStatusRsp.bmClear.BulkInFifoBytes = 1; + clearStatusRsp.USBTMC_status = USBTMC_STATUS_PENDING; + } + else + { + // Let app check if it's clear + TU_VERIFY(tud_usbtmc_check_clear_cb(&clearStatusRsp)); + } + if(clearStatusRsp.USBTMC_status == USBTMC_STATUS_SUCCESS) + { + criticalEnter(); + usbtmc_state.state = STATE_IDLE; + criticalLeave(); + } + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&clearStatusRsp,sizeof(clearStatusRsp))); + return true; + } + + case USBTMC_bREQUEST_GET_CAPABILITIES: + { + TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface + TU_VERIFY(request->wLength == sizeof(*(usbtmc_state.capabilities))); + TU_VERIFY(tud_control_xfer(rhport, request, (void*)(uintptr_t) usbtmc_state.capabilities, sizeof(*usbtmc_state.capabilities))); + return true; + } + // USBTMC Optional Requests + + case USBTMC_bREQUEST_INDICATOR_PULSE: // Optional + { + TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface + TU_VERIFY(request->wLength == sizeof(tmcStatusCode)); + TU_VERIFY(usbtmc_state.capabilities->bmIntfcCapabilities.supportsIndicatorPulse); + TU_VERIFY(tud_usbtmc_indicator_pulse_cb(request, &tmcStatusCode)); + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&tmcStatusCode, sizeof(tmcStatusCode))); + return true; + } +#if (CFG_TUD_USBTMC_ENABLE_488) + + // USB488 required requests + case USB488_bREQUEST_READ_STATUS_BYTE: + { + usbtmc_read_stb_rsp_488_t rsp; + TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface + TU_VERIFY(request->wLength == sizeof(rsp)); // in,class,interface + + bTag = request->wValue & 0x7F; + TU_VERIFY(request->bmRequestType == 0xA1); + TU_VERIFY((request->wValue & (~0x7F)) == 0u); // Other bits are required to be zero (USB488v1.0 Table 11) + TU_VERIFY(bTag >= 0x02 && bTag <= 127); + TU_VERIFY(request->wIndex == usbtmc_state.itf_id); + TU_VERIFY(request->wLength == 0x0003); + rsp.bTag = (uint8_t)bTag; + if(usbtmc_state.ep_int_in != 0) + { + rsp.statusByte = 0x00; // Use interrupt endpoint, instead. Must be 0x00 (USB488v1.0 4.3.1.2) + if(usbd_edpt_busy(rhport, usbtmc_state.ep_int_in)) + { + rsp.USBTMC_status = USB488_STATUS_INTERRUPT_IN_BUSY; + } + else + { + rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; + usbtmc_read_stb_interrupt_488_t intMsg = + { + .bNotify1 = { + .one = 1, + .bTag = bTag & 0x7Fu, + }, + .StatusByte = tud_usbtmc_get_stb_cb(&(rsp.USBTMC_status)) + }; + // Must be queued before control request response sent (USB488v1.0 4.3.1.2) + usbd_edpt_xfer(rhport, usbtmc_state.ep_int_in, (void*)&intMsg, sizeof(intMsg)); + } + } + else + { + rsp.statusByte = tud_usbtmc_get_stb_cb(&(rsp.USBTMC_status)); + } + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp, sizeof(rsp))); + return true; + } + // USB488 optional requests + case USB488_bREQUEST_REN_CONTROL: + case USB488_bREQUEST_GO_TO_LOCAL: + case USB488_bREQUEST_LOCAL_LOCKOUT: + { + TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface + TU_VERIFY(false); + return false; + } +#endif + + default: + TU_VERIFY(false); + return false; + } + TU_VERIFY(false); +} + +#endif /* CFG_TUD_TSMC */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h b/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h new file mode 100644 index 00000000..144b3315 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h @@ -0,0 +1,112 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 N Conrad + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + + +#ifndef CLASS_USBTMC_USBTMC_DEVICE_H_ +#define CLASS_USBTMC_USBTMC_DEVICE_H_ + +#include "usbtmc.h" + +// Enable 488 mode by default +#if !defined(CFG_TUD_USBTMC_ENABLE_488) +#define CFG_TUD_USBTMC_ENABLE_488 (1) +#endif + +/*********************************************** + * Functions to be implemeted by the class implementation + */ + +// In order to proceed, app must call call tud_usbtmc_start_bus_read(rhport) during or soon after: +// * tud_usbtmc_open_cb +// * tud_usbtmc_msg_data_cb +// * tud_usbtmc_msgBulkIn_complete_cb +// * tud_usbtmc_msg_trigger_cb +// * (successful) tud_usbtmc_check_abort_bulk_out_cb +// * (successful) tud_usbtmc_check_abort_bulk_in_cb +// * (successful) tud_usmtmc_bulkOut_clearFeature_cb + +#if (CFG_TUD_USBTMC_ENABLE_488) +usbtmc_response_capabilities_488_t const * tud_usbtmc_get_capabilities_cb(void); +#else +usbtmc_response_capabilities_t const * tud_usbtmc_get_capabilities_cb(void); +#endif + +void tud_usbtmc_open_cb(uint8_t interface_id); + +bool tud_usbtmc_msgBulkOut_start_cb(usbtmc_msg_request_dev_dep_out const * msgHeader); +// transfer_complete does not imply that a message is complete. +bool tud_usbtmc_msg_data_cb( void *data, size_t len, bool transfer_complete); +void tud_usbtmc_bulkOut_clearFeature_cb(void); // Notice to clear and abort the pending BULK out transfer + +bool tud_usbtmc_msgBulkIn_request_cb(usbtmc_msg_request_dev_dep_in const * request); +bool tud_usbtmc_msgBulkIn_complete_cb(void); +void tud_usbtmc_bulkIn_clearFeature_cb(void); // Notice to clear and abort the pending BULK out transfer + +bool tud_usbtmc_initiate_abort_bulk_in_cb(uint8_t *tmcResult); +bool tud_usbtmc_initiate_abort_bulk_out_cb(uint8_t *tmcResult); +bool tud_usbtmc_initiate_clear_cb(uint8_t *tmcResult); + +bool tud_usbtmc_check_abort_bulk_in_cb(usbtmc_check_abort_bulk_rsp_t *rsp); +bool tud_usbtmc_check_abort_bulk_out_cb(usbtmc_check_abort_bulk_rsp_t *rsp); +bool tud_usbtmc_check_clear_cb(usbtmc_get_clear_status_rsp_t *rsp); + +// Indicator pulse should be 0.5 to 1.0 seconds long +TU_ATTR_WEAK bool tud_usbtmc_indicator_pulse_cb(tusb_control_request_t const * msg, uint8_t *tmcResult); + +#if (CFG_TUD_USBTMC_ENABLE_488) +uint8_t tud_usbtmc_get_stb_cb(uint8_t *tmcResult); +TU_ATTR_WEAK bool tud_usbtmc_msg_trigger_cb(usbtmc_msg_generic_t* msg); +//TU_ATTR_WEAK bool tud_usbtmc_app_go_to_local_cb(); +#endif + +/******************************************* + * Called from app + * + * We keep a reference to the buffer, so it MUST not change until the app is + * notified that the transfer is complete. + ******************************************/ + +bool tud_usbtmc_transmit_dev_msg_data( + const void * data, size_t len, + bool endOfMessage, bool usingTermChar); + +bool tud_usbtmc_start_bus_read(void); + + +/* "callbacks" from USB device core */ + +uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +void usbtmcd_reset_cb(uint8_t rhport); +bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); +bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +void usbtmcd_init_cb(void); + +/************************************************************ + * USBTMC Descriptor Templates + *************************************************************/ + + +#endif /* CLASS_USBTMC_USBTMC_DEVICE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.c b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.c new file mode 100644 index 00000000..3b81a108 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.c @@ -0,0 +1,272 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_VENDOR) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "vendor_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +typedef struct +{ + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; + + /*------------- From this point, data is not cleared by bus reset -------------*/ + tu_fifo_t rx_ff; + tu_fifo_t tx_ff; + + uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE]; + uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE]; + +#if CFG_FIFO_MUTEX + osal_mutex_def_t rx_ff_mutex; + osal_mutex_def_t tx_ff_mutex; +#endif + + // Endpoint Transfer buffer + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_VENDOR_EPSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_VENDOR_EPSIZE]; +} vendord_interface_t; + +CFG_TUSB_MEM_SECTION static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR]; + +#define ITF_MEM_RESET_SIZE offsetof(vendord_interface_t, rx_ff) + + +bool tud_vendor_n_mounted (uint8_t itf) +{ + return _vendord_itf[itf].ep_in && _vendord_itf[itf].ep_out; +} + +uint32_t tud_vendor_n_available (uint8_t itf) +{ + return tu_fifo_count(&_vendord_itf[itf].rx_ff); +} + +bool tud_vendor_n_peek(uint8_t itf, uint8_t* u8) +{ + return tu_fifo_peek(&_vendord_itf[itf].rx_ff, u8); +} + +//--------------------------------------------------------------------+ +// Read API +//--------------------------------------------------------------------+ +static void _prep_out_transaction (vendord_interface_t* p_itf) +{ + uint8_t const rhport = 0; + + // skip if previous transfer not complete + if ( usbd_edpt_busy(rhport, p_itf->ep_out) ) return; + + // Prepare for incoming data but only allow what we can store in the ring buffer. + uint16_t max_read = tu_fifo_remaining(&p_itf->rx_ff); + if ( max_read >= CFG_TUD_VENDOR_EPSIZE ) + { + usbd_edpt_xfer(rhport, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE); + } +} + +uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize) +{ + vendord_interface_t* p_itf = &_vendord_itf[itf]; + uint32_t num_read = tu_fifo_read_n(&p_itf->rx_ff, buffer, (uint16_t) bufsize); + _prep_out_transaction(p_itf); + return num_read; +} + +void tud_vendor_n_read_flush (uint8_t itf) +{ + vendord_interface_t* p_itf = &_vendord_itf[itf]; + tu_fifo_clear(&p_itf->rx_ff); + _prep_out_transaction(p_itf); +} + +//--------------------------------------------------------------------+ +// Write API +//--------------------------------------------------------------------+ +static uint16_t maybe_transmit(vendord_interface_t* p_itf) +{ + uint8_t const rhport = 0; + + // skip if previous transfer not complete + TU_VERIFY( !usbd_edpt_busy(rhport, p_itf->ep_in) ); + + uint16_t count = tu_fifo_read_n(&p_itf->tx_ff, p_itf->epin_buf, CFG_TUD_VENDOR_EPSIZE); + if (count > 0) + { + TU_ASSERT( usbd_edpt_xfer(rhport, p_itf->ep_in, p_itf->epin_buf, count) ); + } + return count; +} + +uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize) +{ + vendord_interface_t* p_itf = &_vendord_itf[itf]; + uint16_t ret = tu_fifo_write_n(&p_itf->tx_ff, buffer, (uint16_t) bufsize); + if (tu_fifo_count(&p_itf->tx_ff) >= CFG_TUD_VENDOR_EPSIZE) { + maybe_transmit(p_itf); + } + return ret; +} + +uint32_t tud_vendor_n_flush (uint8_t itf) +{ + vendord_interface_t* p_itf = &_vendord_itf[itf]; + uint32_t ret = maybe_transmit(p_itf); + + return ret; +} + +uint32_t tud_vendor_n_write_available (uint8_t itf) +{ + return tu_fifo_remaining(&_vendord_itf[itf].tx_ff); +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void vendord_init(void) +{ + tu_memclr(_vendord_itf, sizeof(_vendord_itf)); + + for(uint8_t i=0; irx_ff, p_itf->rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, 1, false); + tu_fifo_config(&p_itf->tx_ff, p_itf->tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, 1, false); + +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&p_itf->rx_ff, NULL, osal_mutex_create(&p_itf->rx_ff_mutex)); + tu_fifo_config_mutex(&p_itf->tx_ff, osal_mutex_create(&p_itf->tx_ff_mutex), NULL); +#endif + } +} + +void vendord_reset(uint8_t rhport) +{ + (void) rhport; + + for(uint8_t i=0; irx_ff); + tu_fifo_clear(&p_itf->tx_ff); + } +} + +uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) +{ + TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0); + + uint8_t const * p_desc = tu_desc_next(desc_itf); + uint8_t const * desc_end = p_desc + max_len; + + // Find available interface + vendord_interface_t* p_vendor = NULL; + for(uint8_t i=0; iitf_num = desc_itf->bInterfaceNumber; + if (desc_itf->bNumEndpoints) + { + // skip non-endpoint descriptors + while ( (TUSB_DESC_ENDPOINT != tu_desc_type(p_desc)) && (p_desc < desc_end) ) + { + p_desc = tu_desc_next(p_desc); + } + + // Open endpoint pair with usbd helper + TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_BULK, &p_vendor->ep_out, &p_vendor->ep_in), 0); + + p_desc += desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t); + + // Prepare for incoming data + if ( p_vendor->ep_out ) + { + TU_ASSERT(usbd_edpt_xfer(rhport, p_vendor->ep_out, p_vendor->epout_buf, sizeof(p_vendor->epout_buf)), 0); + } + + if ( p_vendor->ep_in ) maybe_transmit(p_vendor); + } + + return (uint16_t) ((uintptr_t) p_desc - (uintptr_t) desc_itf); +} + +bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) rhport; + (void) result; + + uint8_t itf = 0; + vendord_interface_t* p_itf = _vendord_itf; + + for ( ; ; itf++, p_itf++) + { + if (itf >= TU_ARRAY_SIZE(_vendord_itf)) return false; + + if ( ( ep_addr == p_itf->ep_out ) || ( ep_addr == p_itf->ep_in ) ) break; + } + + if ( ep_addr == p_itf->ep_out ) + { + // Receive new data + tu_fifo_write_n(&p_itf->rx_ff, p_itf->epout_buf, (uint16_t) xferred_bytes); + + // Invoked callback if any + if (tud_vendor_rx_cb) tud_vendor_rx_cb(itf); + + _prep_out_transaction(p_itf); + } + else if ( ep_addr == p_itf->ep_in ) + { + if (tud_vendor_tx_cb) tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes); + // Send complete, try to send more if possible + maybe_transmit(p_itf); + } + + return true; +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.h b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.h new file mode 100644 index 00000000..4a873e5f --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.h @@ -0,0 +1,145 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_VENDOR_DEVICE_H_ +#define _TUSB_VENDOR_DEVICE_H_ + +#include "common/tusb_common.h" + +#ifndef CFG_TUD_VENDOR_EPSIZE +#define CFG_TUD_VENDOR_EPSIZE 64 +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Application API (Multiple Interfaces) +//--------------------------------------------------------------------+ +bool tud_vendor_n_mounted (uint8_t itf); + +uint32_t tud_vendor_n_available (uint8_t itf); +uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize); +bool tud_vendor_n_peek (uint8_t itf, uint8_t* ui8); +void tud_vendor_n_read_flush (uint8_t itf); + +uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize); +uint32_t tud_vendor_n_write_available (uint8_t itf); + +static inline +uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str); +uint32_t tud_vendor_n_flush (uint8_t itf); + +//--------------------------------------------------------------------+ +// Application API (Single Port) +//--------------------------------------------------------------------+ +static inline bool tud_vendor_mounted (void); +static inline uint32_t tud_vendor_available (void); +static inline uint32_t tud_vendor_read (void* buffer, uint32_t bufsize); +static inline bool tud_vendor_peek (uint8_t* ui8); +static inline void tud_vendor_read_flush (void); +static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize); +static inline uint32_t tud_vendor_write_str (char const* str); +static inline uint32_t tud_vendor_write_available (void); +static inline uint32_t tud_vendor_flush (void); + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ + +// Invoked when received new data +TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf); +// Invoked when last rx transfer finished +TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes); + +//--------------------------------------------------------------------+ +// Inline Functions +//--------------------------------------------------------------------+ + +static inline uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str) +{ + return tud_vendor_n_write(itf, str, strlen(str)); +} + +static inline bool tud_vendor_mounted (void) +{ + return tud_vendor_n_mounted(0); +} + +static inline uint32_t tud_vendor_available (void) +{ + return tud_vendor_n_available(0); +} + +static inline uint32_t tud_vendor_read (void* buffer, uint32_t bufsize) +{ + return tud_vendor_n_read(0, buffer, bufsize); +} + +static inline bool tud_vendor_peek (uint8_t* ui8) +{ + return tud_vendor_n_peek(0, ui8); +} + +static inline void tud_vendor_read_flush(void) +{ + tud_vendor_n_read_flush(0); +} + +static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize) +{ + return tud_vendor_n_write(0, buffer, bufsize); +} + +static inline uint32_t tud_vendor_write_str (char const* str) +{ + return tud_vendor_n_write_str(0, str); +} + +static inline uint32_t tud_vendor_write_available (void) +{ + return tud_vendor_n_write_available(0); +} + +static inline uint32_t tud_vendor_flush (void) +{ + return tud_vendor_n_flush(0); +} + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void vendord_init(void); +void vendord_reset(uint8_t rhport); +uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_VENDOR_DEVICE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.c b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.c new file mode 100644 index 00000000..dbea1228 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.c @@ -0,0 +1,146 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUH_ENABLED && CFG_TUH_VENDOR) + +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "host/usbh.h" +#include "vendor_host.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +custom_interface_info_t custom_interface[CFG_TUH_DEVICE_MAX]; + +static tusb_error_t cush_validate_paras(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length) +{ + if ( !tusbh_custom_is_mounted(dev_addr, vendor_id, product_id) ) + { + return TUSB_ERROR_DEVICE_NOT_READY; + } + + TU_ASSERT( p_buffer != NULL && length != 0, TUSB_ERROR_INVALID_PARA); + + return TUSB_ERROR_NONE; +} +//--------------------------------------------------------------------+ +// APPLICATION API (need to check parameters) +//--------------------------------------------------------------------+ +tusb_error_t tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length) +{ + TU_ASSERT_ERR( cush_validate_paras(dev_addr, vendor_id, product_id, p_buffer, length) ); + + if ( !hcd_pipe_is_idle(custom_interface[dev_addr-1].pipe_in) ) + { + return TUSB_ERROR_INTERFACE_IS_BUSY; + } + + (void) usbh_edpt_xfer( custom_interface[dev_addr-1].pipe_in, p_buffer, length); + + return TUSB_ERROR_NONE; +} + +tusb_error_t tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length) +{ + TU_ASSERT_ERR( cush_validate_paras(dev_addr, vendor_id, product_id, p_data, length) ); + + if ( !hcd_pipe_is_idle(custom_interface[dev_addr-1].pipe_out) ) + { + return TUSB_ERROR_INTERFACE_IS_BUSY; + } + + (void) usbh_edpt_xfer( custom_interface[dev_addr-1].pipe_out, p_data, length); + + return TUSB_ERROR_NONE; +} + +//--------------------------------------------------------------------+ +// USBH-CLASS API +//--------------------------------------------------------------------+ +void cush_init(void) +{ + tu_memclr(&custom_interface, sizeof(custom_interface_info_t) * CFG_TUH_DEVICE_MAX); +} + +tusb_error_t cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length) +{ + // FIXME quick hack to test lpc1k custom class with 2 bulk endpoints + uint8_t const *p_desc = (uint8_t const *) p_interface_desc; + p_desc = tu_desc_next(p_desc); + + //------------- Bulk Endpoints Descriptor -------------// + for(uint32_t i=0; i<2; i++) + { + tusb_desc_endpoint_t const *p_endpoint = (tusb_desc_endpoint_t const *) p_desc; + TU_ASSERT(TUSB_DESC_ENDPOINT == p_endpoint->bDescriptorType, TUSB_ERROR_INVALID_PARA); + + pipe_handle_t * p_pipe_hdl = ( p_endpoint->bEndpointAddress & TUSB_DIR_IN_MASK ) ? + &custom_interface[dev_addr-1].pipe_in : &custom_interface[dev_addr-1].pipe_out; + *p_pipe_hdl = usbh_edpt_open(dev_addr, p_endpoint, TUSB_CLASS_VENDOR_SPECIFIC); + TU_ASSERT ( pipehandle_is_valid(*p_pipe_hdl), TUSB_ERROR_HCD_OPEN_PIPE_FAILED ); + + p_desc = tu_desc_next(p_desc); + } + + (*p_length) = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t); + return TUSB_ERROR_NONE; +} + +void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event) +{ + +} + +void cush_close(uint8_t dev_addr) +{ + tusb_error_t err1, err2; + custom_interface_info_t * p_interface = &custom_interface[dev_addr-1]; + + // TODO re-consider to check pipe valid before calling pipe_close + if( pipehandle_is_valid( p_interface->pipe_in ) ) + { + err1 = hcd_pipe_close( p_interface->pipe_in ); + } + + if ( pipehandle_is_valid( p_interface->pipe_out ) ) + { + err2 = hcd_pipe_close( p_interface->pipe_out ); + } + + tu_memclr(p_interface, sizeof(custom_interface_info_t)); + + TU_ASSERT(err1 == TUSB_ERROR_NONE && err2 == TUSB_ERROR_NONE, (void) 0 ); +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.h b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.h new file mode 100644 index 00000000..65223fbc --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.h @@ -0,0 +1,67 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_VENDOR_HOST_H_ +#define _TUSB_VENDOR_HOST_H_ + +#include "common/tusb_common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +typedef struct { + pipe_handle_t pipe_in; + pipe_handle_t pipe_out; +}custom_interface_info_t; + +//--------------------------------------------------------------------+ +// USBH-CLASS DRIVER API +//--------------------------------------------------------------------+ +static inline bool tusbh_custom_is_mounted(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id) +{ + (void) vendor_id; // TODO check this later + (void) product_id; +// return (tusbh_device_get_mounted_class_flag(dev_addr) & TU_BIT(TUSB_CLASS_MAPPED_INDEX_END-1) ) != 0; + return false; +} + +bool tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length); +bool tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void cush_init(void); +bool cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length); +void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event); +void cush_close(uint8_t dev_addr); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_VENDOR_HOST_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/video/video.h b/test-devices/composite-stm32/lib/tinyusb/class/video/video.h new file mode 100644 index 00000000..84474654 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/video/video.h @@ -0,0 +1,480 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Koji KITAYAMA + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef TUSB_VIDEO_H_ +#define TUSB_VIDEO_H_ + +#include "common/tusb_common.h" + +// Table 3-19 Color Matching Descriptor +typedef enum { + VIDEO_COLOR_PRIMARIES_UNDEFINED = 0x00, + VIDEO_COLOR_PRIMARIES_BT709, // sRGB (default) + VIDEO_COLOR_PRIMARIES_BT470_2M, + VIDEO_COLOR_PRIMARIES_BT470_2BG, + VIDEO_COLOR_PRIMARIES_SMPTE170M, + VIDEO_COLOR_PRIMARIES_SMPTE240M, +} video_color_primaries_t; + +// Table 3-19 Color Matching Descriptor +typedef enum { + VIDEO_COLOR_XFER_CH_UNDEFINED = 0x00, + VIDEO_COLOR_XFER_CH_BT709, // default + VIDEO_COLOR_XFER_CH_BT470_2M, + VIDEO_COLOR_XFER_CH_BT470_2BG, + VIDEO_COLOR_XFER_CH_SMPTE170M, + VIDEO_COLOR_XFER_CH_SMPTE240M, + VIDEO_COLOR_XFER_CH_LINEAR, + VIDEO_COLOR_XFER_CH_SRGB, +} video_color_transfer_characteristics_t; + +// Table 3-19 Color Matching Descriptor +typedef enum { + VIDEO_COLOR_COEF_UNDEFINED = 0x00, + VIDEO_COLOR_COEF_BT709, + VIDEO_COLOR_COEF_FCC, + VIDEO_COLOR_COEF_BT470_2BG, + VIDEO_COLOR_COEF_SMPTE170M, // BT.601 default + VIDEO_COLOR_COEF_SMPTE240M, +} video_color_matrix_coefficients_t; + +/* 4.2.1.2 Request Error Code Control */ +typedef enum { + VIDEO_ERROR_NONE = 0, /* The request succeeded. */ + VIDEO_ERROR_NOT_READY, + VIDEO_ERROR_WRONG_STATE, + VIDEO_ERROR_POWER, + VIDEO_ERROR_OUT_OF_RANGE, + VIDEO_ERROR_INVALID_UNIT, + VIDEO_ERROR_INVALID_CONTROL, + VIDEO_ERROR_INVALID_REQUEST, + VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE, + VIDEO_ERROR_UNKNOWN = 0xFF, +} video_error_code_t; + +/* A.2 Interface Subclass */ +typedef enum { + VIDEO_SUBCLASS_UNDEFINED = 0x00, + VIDEO_SUBCLASS_CONTROL, + VIDEO_SUBCLASS_STREAMING, + VIDEO_SUBCLASS_INTERFACE_COLLECTION, +} video_subclass_type_t; + +/* A.3 Interface Protocol */ +typedef enum { + VIDEO_ITF_PROTOCOL_UNDEFINED = 0x00, + VIDEO_ITF_PROTOCOL_15, +} video_interface_protocol_code_t; + +/* A.5 Class-Specific VideoControl Interface Descriptor Subtypes */ +typedef enum { + VIDEO_CS_ITF_VC_UNDEFINED = 0x00, + VIDEO_CS_ITF_VC_HEADER, + VIDEO_CS_ITF_VC_INPUT_TERMINAL, + VIDEO_CS_ITF_VC_OUTPUT_TERMINAL, + VIDEO_CS_ITF_VC_SELECTOR_UNIT, + VIDEO_CS_ITF_VC_PROCESSING_UNIT, + VIDEO_CS_ITF_VC_EXTENSION_UNIT, + VIDEO_CS_ITF_VC_ENCODING_UNIT, + VIDEO_CS_ITF_VC_MAX, +} video_cs_vc_interface_subtype_t; + +/* A.6 Class-Specific VideoStreaming Interface Descriptor Subtypes */ +typedef enum { + VIDEO_CS_ITF_VS_UNDEFINED = 0x00, + VIDEO_CS_ITF_VS_INPUT_HEADER = 0x01, + VIDEO_CS_ITF_VS_OUTPUT_HEADER = 0x02, + VIDEO_CS_ITF_VS_STILL_IMAGE_FRAME = 0x03, + VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED = 0x04, + VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED = 0x05, + VIDEO_CS_ITF_VS_FORMAT_MJPEG = 0x06, + VIDEO_CS_ITF_VS_FRAME_MJPEG = 0x07, + VIDEO_CS_ITF_VS_FORMAT_MPEG2TS = 0x0A, + VIDEO_CS_ITF_VS_FORMAT_DV = 0x0C, + VIDEO_CS_ITF_VS_COLORFORMAT = 0x0D, + VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED = 0x10, + VIDEO_CS_ITF_VS_FRAME_FRAME_BASED = 0x11, + VIDEO_CS_ITF_VS_FORMAT_STREAM_BASED = 0x12, + VIDEO_CS_ITF_VS_FORMAT_H264 = 0x13, + VIDEO_CS_ITF_VS_FRAME_H264 = 0x14, + VIDEO_CS_ITF_VS_FORMAT_H264_SIMULCAST = 0x15, + VIDEO_CS_ITF_VS_FORMAT_VP8 = 0x16, + VIDEO_CS_ITF_VS_FRAME_VP8 = 0x17, + VIDEO_CS_ITF_VS_FORMAT_VP8_SIMULCAST = 0x18, +} video_cs_vs_interface_subtype_t; + +/* A.7. Class-Specific Endpoint Descriptor Subtypes */ +typedef enum { + VIDEO_CS_EP_UNDEFINED = 0x00, + VIDEO_CS_EP_GENERAL, + VIDEO_CS_EP_ENDPOINT, + VIDEO_CS_EP_INTERRUPT +} video_cs_ep_subtype_t; + +/* A.8 Class-Specific Request Codes */ +typedef enum { + VIDEO_REQUEST_UNDEFINED = 0x00, + VIDEO_REQUEST_SET_CUR = 0x01, + VIDEO_REQUEST_SET_CUR_ALL = 0x11, + VIDEO_REQUEST_GET_CUR = 0x81, + VIDEO_REQUEST_GET_MIN = 0x82, + VIDEO_REQUEST_GET_MAX = 0x83, + VIDEO_REQUEST_GET_RES = 0x84, + VIDEO_REQUEST_GET_LEN = 0x85, + VIDEO_REQUEST_GET_INFO = 0x86, + VIDEO_REQUEST_GET_DEF = 0x87, + VIDEO_REQUEST_GET_CUR_ALL = 0x91, + VIDEO_REQUEST_GET_MIN_ALL = 0x92, + VIDEO_REQUEST_GET_MAX_ALL = 0x93, + VIDEO_REQUEST_GET_RES_ALL = 0x94, + VIDEO_REQUEST_GET_DEF_ALL = 0x97 +} video_control_request_t; + +/* A.9.1 VideoControl Interface Control Selectors */ +typedef enum { + VIDEO_VC_CTL_UNDEFINED = 0x00, + VIDEO_VC_CTL_VIDEO_POWER_MODE, + VIDEO_VC_CTL_REQUEST_ERROR_CODE, +} video_interface_control_selector_t; + +/* A.9.8 VideoStreaming Interface Control Selectors */ +typedef enum { + VIDEO_VS_CTL_UNDEFINED = 0x00, + VIDEO_VS_CTL_PROBE, + VIDEO_VS_CTL_COMMIT, + VIDEO_VS_CTL_STILL_PROBE, + VIDEO_VS_CTL_STILL_COMMIT, + VIDEO_VS_CTL_STILL_IMAGE_TRIGGER, + VIDEO_VS_CTL_STREAM_ERROR_CODE, + VIDEO_VS_CTL_GENERATE_KEY_FRAME, + VIDEO_VS_CTL_UPDATE_FRAME_SEGMENT, + VIDEO_VS_CTL_SYNCH_DELAY_CONTROL, +} video_interface_streaming_selector_t; + +/* B. Terminal Types */ +typedef enum { + // Terminal + VIDEO_TT_VENDOR_SPECIFIC = 0x0100, + VIDEO_TT_STREAMING = 0x0101, + + // Input + VIDEO_ITT_VENDOR_SPECIFIC = 0x0200, + VIDEO_ITT_CAMERA = 0x0201, + VIDEO_ITT_MEDIA_TRANSPORT_INPUT = 0x0202, + + // Output + VIDEO_OTT_VENDOR_SPECIFIC = 0x0300, + VIDEO_OTT_DISPLAY = 0x0301, + VIDEO_OTT_MEDIA_TRANSPORT_OUTPUT = 0x0302, + + // External + VIDEO_ETT_VENDOR_SPEIFIC = 0x0400, + VIDEO_ETT_COMPOSITE_CONNECTOR = 0x0401, + VIDEO_ETT_SVIDEO_CONNECTOR = 0x0402, + VIDEO_ETT_COMPONENT_CONNECTOR = 0x0403, +} video_terminal_type_t; + +//--------------------------------------------------------------------+ +// Descriptors +//--------------------------------------------------------------------+ + +/* 2.3.4.2 */ +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint16_t bcdUVC; + uint16_t wTotalLength; + uint32_t dwClockFrequency; + uint8_t bInCollection; + uint8_t baInterfaceNr[]; +} tusb_desc_cs_video_ctl_itf_hdr_t; + +/* 2.4.3.3 */ +typedef struct TU_ATTR_PACKED { + uint8_t bHeaderLength; + union { + uint8_t bmHeaderInfo; + struct { + uint8_t FrameID: 1; + uint8_t EndOfFrame: 1; + uint8_t PresentationTime: 1; + uint8_t SourceClockReference: 1; + uint8_t PayloadSpecific: 1; + uint8_t StillImage: 1; + uint8_t Error: 1; + uint8_t EndOfHeader: 1; + }; + }; +} tusb_video_payload_header_t; + +/* 3.9.2.1 */ +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bNumFormats; + uint16_t wTotalLength; + uint8_t bEndpointAddress; + uint8_t bmInfo; + uint8_t bTerminalLink; + uint8_t bStillCaptureMethod; + uint8_t bTriggerSupport; + uint8_t bTriggerUsage; + uint8_t bControlSize; + uint8_t bmaControls[]; +} tusb_desc_cs_video_stm_itf_in_hdr_t; + +/* 3.9.2.2 */ +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bNumFormats; + uint16_t wTotalLength; + uint8_t bEndpointAddress; + uint8_t bTerminalLink; + uint8_t bControlSize; + uint8_t bmaControls[]; +} tusb_desc_cs_video_stm_itf_out_hdr_t; + +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bNumFormats; + uint16_t wTotalLength; + uint8_t bEndpointAddress; + union { + struct { + uint8_t bmInfo; + uint8_t bTerminalLink; + uint8_t bStillCaptureMethod; + uint8_t bTriggerSupport; + uint8_t bTriggerUsage; + uint8_t bControlSize; + uint8_t bmaControls[]; + } input; + struct { + uint8_t bEndpointAddress; + uint8_t bTerminalLink; + uint8_t bControlSize; + uint8_t bmaControls[]; + } output; + }; +} tusb_desc_cs_video_stm_itf_hdr_t; + +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFormatIndex; + uint8_t bNumFrameDescriptors; + uint8_t guidFormat[16]; + uint8_t bBitsPerPixel; + uint8_t bDefaultFrameIndex; + uint8_t bAspectRatioX; + uint8_t bAspectRatioY; + uint8_t bmInterlaceFlags; + uint8_t bCopyProtect; +} tusb_desc_cs_video_fmt_uncompressed_t; + +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFrameIndex; + uint8_t bmCapabilities; + uint16_t wWidth; + uint16_t wHeight; + uint32_t dwMinBitRate; + uint32_t dwMaxBitRate; + uint32_t dwMaxVideoFrameBufferSize; /* deprecated */ + uint32_t dwDefaultFrameInterval; + uint8_t bFrameIntervalType; + uint32_t dwFrameInterval[]; +} tusb_desc_cs_video_frm_uncompressed_t; + +//--------------------------------------------------------------------+ +// Requests +//--------------------------------------------------------------------+ + +/* 4.3.1.1 */ +typedef struct TU_ATTR_PACKED { + union { + uint8_t bmHint; + struct TU_ATTR_PACKED { + uint16_t dwFrameInterval: 1; + uint16_t wKeyFrameRatel : 1; + uint16_t wPFrameRate : 1; + uint16_t wCompQuality : 1; + uint16_t wCompWindowSize: 1; + uint16_t : 0; + } Hint; + }; + uint8_t bFormatIndex; + uint8_t bFrameIndex; + uint32_t dwFrameInterval; + uint16_t wKeyFrameRate; + uint16_t wPFrameRate; + uint16_t wCompQuality; + uint16_t wCompWindowSize; + uint16_t wDelay; + uint32_t dwMaxVideoFrameSize; + uint32_t dwMaxPayloadTransferSize; + uint32_t dwClockFrequency; + union { + uint8_t bmFramingInfo; + struct TU_ATTR_PACKED { + uint8_t FrameID : 1; + uint8_t EndOfFrame: 1; + uint8_t EndOfSlice: 1; + uint8_t : 0; + } FramingInfo; + }; + uint8_t bPreferedVersion; + uint8_t bMinVersion; + uint8_t bMaxVersion; + uint8_t bUsage; + uint8_t bBitDepthLuma; + uint8_t bmSettings; + uint8_t bMaxNumberOfRefFramesPlus1; + uint16_t bmRateControlModes; + uint64_t bmLayoutPerStream; +} video_probe_and_commit_control_t; + +TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not correct"); + +#define TUD_VIDEO_DESC_IAD_LEN 8 +#define TUD_VIDEO_DESC_STD_VC_LEN 9 +#define TUD_VIDEO_DESC_CS_VC_LEN 12 +#define TUD_VIDEO_DESC_INPUT_TERM_LEN 8 +#define TUD_VIDEO_DESC_OUTPUT_TERM_LEN 9 +#define TUD_VIDEO_DESC_CAMERA_TERM_LEN 18 +#define TUD_VIDEO_DESC_STD_VS_LEN 9 +#define TUD_VIDEO_DESC_CS_VS_IN_LEN 13 +#define TUD_VIDEO_DESC_CS_VS_OUT_LEN 9 +#define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN 27 +#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN 38 +#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN 26 +#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN 6 + +/* 2.2 compression formats */ +#define TUD_VIDEO_GUID_YUY2 0x59,0x55,0x59,0x32,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 +#define TUD_VIDEO_GUID_NV12 0x4E,0x56,0x31,0x32,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 +#define TUD_VIDEO_GUID_M420 0x4D,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 +#define TUD_VIDEO_GUID_I420 0x49,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 + +#define TUD_VIDEO_DESC_IAD(_firstitfs, _nitfs, _stridx) \ + TUD_VIDEO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, \ + _firstitfs, _nitfs, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_INTERFACE_COLLECTION, \ + VIDEO_ITF_PROTOCOL_UNDEFINED, _stridx + +#define TUD_VIDEO_DESC_STD_VC(_itfnum, _nEPs, _stridx) \ + TUD_VIDEO_DESC_STD_VC_LEN, TUSB_DESC_INTERFACE, _itfnum, /* fixed to zero */ 0x00, \ + _nEPs, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_CONTROL, VIDEO_ITF_PROTOCOL_15, _stridx + +/* 3.7.2 */ +#define TUD_VIDEO_DESC_CS_VC(_bcdUVC, _totallen, _clkfreq, ...) \ + TUD_VIDEO_DESC_CS_VC_LEN + (TU_ARGS_NUM(__VA_ARGS__)), TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_HEADER, \ + U16_TO_U8S_LE(_bcdUVC), U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VC_LEN + (TU_ARGS_NUM(__VA_ARGS__))), \ + U32_TO_U8S_LE(_clkfreq), TU_ARGS_NUM(__VA_ARGS__), __VA_ARGS__ + +/* 3.7.2.1 */ +#define TUD_VIDEO_DESC_INPUT_TERM(_tid, _tt, _at, _stridx) \ + TUD_VIDEO_DESC_INPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_INPUT_TERMINAL, \ + _tid, U16_TO_U8S_LE(_tt), _at, _stridx + +/* 3.7.2.2 */ +#define TUD_VIDEO_DESC_OUTPUT_TERM(_tid, _tt, _at, _srcid, _stridx) \ + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_OUTPUT_TERMINAL, \ + _tid, U16_TO_U8S_LE(_tt), _at, _srcid, _stridx + +/* 3.7.2.3 */ +#define TUD_VIDEO_DESC_CAMERA_TERM(_tid, _at, _stridx, _focal_min, _focal_max, _focal, _ctls) \ + TUD_VIDEO_DESC_CAMERA_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_INPUT_TERMINAL, \ + _tid, U16_TO_U8S_LE(VIDEO_ITT_CAMERA), _at, _stridx, \ + U16_TO_U8S_LE(_focal_min), U16_TO_U8S_LE(_focal_max), U16_TO_U8S_LE(_focal), 3, \ + TU_U32_BYTE0(_ctls), TU_U32_BYTE1(_ctls), TU_U32_BYTE2(_ctls) + +/* 3.9.1 */ +#define TUD_VIDEO_DESC_STD_VS(_itfnum, _alt, _epn, _stridx) \ + TUD_VIDEO_DESC_STD_VS_LEN, TUSB_DESC_INTERFACE, _itfnum, _alt, \ + _epn, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_STREAMING, VIDEO_ITF_PROTOCOL_15, _stridx + +/* 3.9.2.1 */ +#define TUD_VIDEO_DESC_CS_VS_INPUT(_numfmt, _totallen, _ep, _inf, _termlnk, _sticaptmeth, _trgspt, _trgusg, ...) \ + TUD_VIDEO_DESC_CS_VS_IN_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__)), TUSB_DESC_CS_INTERFACE, \ + VIDEO_CS_ITF_VS_INPUT_HEADER, _numfmt, \ + U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VS_IN_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__))), \ + _ep, _inf, _termlnk, _sticaptmeth, _trgspt, _trgusg, (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ + +/* 3.9.2.2 */ +#define TUD_VIDEO_DESC_CS_VS_OUTPUT(_numfmt, _totallen, _ep, _inf, _termlnk, ...) \ + TUD_VIDEO_DESC_CS_VS_OUT_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__)), TUSB_DESC_CS_INTERFACE, \ + VIDEO_CS_ITF_VS_OUTPUT_HEADER, _numfmt, \ + U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VS_OUT_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__))), \ + _ep, _inf, _termlnk, (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ + +/* Uncompressed 3.1.1 */ +#define TUD_VIDEO_GUID(_g0,_g1,_g2,_g3,_g4,_g5,_g6,_g7,_g8,_g9,_g10,_g11,_g12,_g13,_g14,_g15) _g0,_g1,_g2,_g3,_g4,_g5,_g6,_g7,_g8,_g9,_g10,_g11,_g12,_g13,_g14,_g15 + +#define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR(_fmtidx, _numfrmdesc, \ + _guid, _bitsperpix, _frmidx, _asrx, _asry, _interlace, _cp) \ + TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED, \ + _fmtidx, _numfrmdesc, TUD_VIDEO_GUID(_guid), \ + _bitsperpix, _frmidx, _asrx, _asry, _interlace, _cp + +/* Uncompressed 3.1.2 Table 3-3 */ +#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, _minfrminterval, _maxfrminterval, _frmintervalstep) \ + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, \ + _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ + U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), 0, \ + U32_TO_U8S_LE(_minfrminterval), U32_TO_U8S_LE(_maxfrminterval), U32_TO_U8S_LE(_frmintervalstep) + +/* Uncompressed 3.1.2 Table 3-4 */ +#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, ...) \ + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN + (TU_ARGS_NUM(__VA_ARGS__)) * 4, \ + TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, \ + _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ + U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ + +/* 3.9.2.6 */ +#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(_color, _trns, _mat) \ + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN, \ + TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_COLORFORMAT, \ + _color, _trns, _mat + +/* 3.10.1.1 */ +#define TUD_VIDEO_DESC_EP_ISO(_ep, _epsize, _ep_interval) \ + 7, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS,\ + U16_TO_U8S_LE(_epsize), _ep_interval + +/* 3.10.1.2 */ +#define TUD_VIDEO_DESC_EP_BULK(_ep, _epsize, _ep_interval) \ + 7, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), _ep_interval + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/video/video_device.c b/test-devices/composite-stm32/lib/tinyusb/class/video/video_device.c new file mode 100644 index 00000000..7636db5f --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/video/video_device.c @@ -0,0 +1,1151 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Koji KITAYAMA + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_VIDEO && CFG_TUD_VIDEO_STREAMING) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "video_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +typedef struct { + tusb_desc_interface_t std; + tusb_desc_cs_video_ctl_itf_hdr_t ctl; +} tusb_desc_vc_itf_t; + +typedef struct { + tusb_desc_interface_t std; + tusb_desc_cs_video_stm_itf_hdr_t stm; +} tusb_desc_vs_itf_t; + +typedef union { + tusb_desc_cs_video_ctl_itf_hdr_t ctl; + tusb_desc_cs_video_stm_itf_hdr_t stm; +} tusb_desc_video_itf_hdr_t; + +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bEntityId; +} tusb_desc_cs_video_entity_itf_t; + +/* video streaming interface */ +typedef struct TU_ATTR_PACKED { + uint8_t index_vc; /* index of bound video control interface */ + uint8_t index_vs; /* index from the video control interface */ + struct { + uint16_t beg; /* Offset of the begging of video streaming interface descriptor */ + uint16_t end; /* Offset of the end of video streaming interface descriptor */ + uint16_t cur; /* Offset of the current settings */ + uint16_t ep[2]; /* Offset of endpoint descriptors. 0: streaming, 1: still capture */ + } desc; + uint8_t *buffer; /* frame buffer. assume linear buffer. no support for stride access */ + uint32_t bufsize; /* frame buffer size */ + uint32_t offset; /* offset for the next payload transfer */ + uint32_t max_payload_transfer_size; + uint8_t error_code;/* error code */ + /*------------- From this point, data is not cleared by bus reset -------------*/ + CFG_TUSB_MEM_ALIGN uint8_t ep_buf[CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE]; /* EP transfer buffer for streaming */ +} videod_streaming_interface_t; + +/* video control interface */ +typedef struct TU_ATTR_PACKED { + void const *beg; /* The head of the first video control interface descriptor */ + uint16_t len; /* Byte length of the descriptors */ + uint16_t cur; /* offset for current video control interface */ + uint8_t stm[CFG_TUD_VIDEO_STREAMING]; /* Indices of streaming interface */ + uint8_t error_code; /* error code */ + uint8_t power_mode; + + /*------------- From this point, data is not cleared by bus reset -------------*/ + // CFG_TUSB_MEM_ALIGN uint8_t ctl_buf[64]; /* EP transfer buffer for interrupt transfer */ + +} videod_interface_t; + +#define ITF_STM_MEM_RESET_SIZE offsetof(videod_streaming_interface_t, ep_buf) + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +CFG_TUSB_MEM_SECTION static videod_interface_t _videod_itf[CFG_TUD_VIDEO]; +CFG_TUSB_MEM_SECTION static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING]; + +static uint8_t const _cap_get = 0x1u; /* support for GET */ +static uint8_t const _cap_get_set = 0x3u; /* support for GET and SET */ + +/** Get interface number from the interface descriptor + * + * @param[in] desc interface descriptor + * + * @return bInterfaceNumber */ +static inline uint8_t _desc_itfnum(void const *desc) +{ + return ((uint8_t const*)desc)[2]; +} + +/** Get endpoint address from the endpoint descriptor + * + * @param[in] desc endpoint descriptor + * + * @return bEndpointAddress */ +static inline uint8_t _desc_ep_addr(void const *desc) +{ + return ((uint8_t const*)desc)[2]; +} + +/** Get instance of streaming interface + * + * @param[in] ctl_idx instance number of video control + * @param[in] stm_idx index number of streaming interface + * + * @return instance */ +static videod_streaming_interface_t* _get_instance_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) +{ + videod_interface_t *ctl = &_videod_itf[ctl_idx]; + if (!ctl->beg) return NULL; + videod_streaming_interface_t *stm = &_videod_streaming_itf[ctl->stm[stm_idx]]; + if (!stm->desc.beg) return NULL; + return stm; +} + +static tusb_desc_vc_itf_t const* _get_desc_vc(videod_interface_t const *self) +{ + return (tusb_desc_vc_itf_t const *)(self->beg + self->cur); +} + +static tusb_desc_vs_itf_t const* _get_desc_vs(videod_streaming_interface_t const *self) +{ + if (!self->desc.cur) return NULL; + void const *desc = _videod_itf[self->index_vc].beg; + return (tusb_desc_vs_itf_t const*)(desc + self->desc.cur); +} + +/** Find the first descriptor of a given type + * + * @param[in] beg The head of descriptor byte array. + * @param[in] end The tail of descriptor byte array. + * @param[in] desc_type The target descriptor type. + * + * @return The pointer for interface descriptor. + * @retval end did not found interface descriptor */ +static void const* _find_desc(void const *beg, void const *end, uint_fast8_t desc_type) +{ + void const *cur = beg; + while ((cur < end) && (desc_type != tu_desc_type(cur))) { + cur = tu_desc_next(cur); + } + return cur; +} + +/** Find the first descriptor specified by the arguments + * + * @param[in] beg The head of descriptor byte array. + * @param[in] end The tail of descriptor byte array. + * @param[in] desc_type The target descriptor type + * @param[in] element_0 The target element following the desc_type + * @param[in] element_1 The target element following the element_0 + * + * @return The pointer for interface descriptor. + * @retval end did not found interface descriptor */ +static void const* _find_desc_3(void const *beg, void const *end, + uint_fast8_t desc_type, + uint_fast8_t element_0, + uint_fast8_t element_1) +{ + for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, desc_type)) { + uint8_t const *p = (uint8_t const *)cur; + if ((p[2] == element_0) && (p[3] == element_1)) { + return cur; + } + cur = tu_desc_next(cur); + } + return end; +} + +/** Return the next interface descriptor which has another interface number. + * + * @param[in] beg The head of descriptor byte array. + * @param[in] end The tail of descriptor byte array. + * + * @return The pointer for interface descriptor. + * @retval end did not found interface descriptor */ +static void const* _next_desc_itf(void const *beg, void const *end) +{ + void const *cur = beg; + uint_fast8_t itfnum = ((tusb_desc_interface_t const*)cur)->bInterfaceNumber; + while ((cur < end) && + (itfnum == ((tusb_desc_interface_t const*)cur)->bInterfaceNumber)) { + cur = _find_desc(tu_desc_next(cur), end, TUSB_DESC_INTERFACE); + } + return cur; +} + +/** Find the first interface descriptor with the specified interface number and alternate setting number. + * + * @param[in] beg The head of descriptor byte array. + * @param[in] end The tail of descriptor byte array. + * @param[in] itfnum The target interface number. + * @param[in] altnum The target alternate setting number. + * + * @return The pointer for interface descriptor. + * @retval end did not found interface descriptor */ +static inline void const* _find_desc_itf(void const *beg, void const *end, uint_fast8_t itfnum, uint_fast8_t altnum) +{ + return _find_desc_3(beg, end, TUSB_DESC_INTERFACE, itfnum, altnum); +} + +/** Find the first endpoint descriptor belonging to the current interface descriptor. + * + * The search range is from `beg` to `end` or the next interface descriptor. + * + * @param[in] beg The head of descriptor byte array. + * @param[in] end The tail of descriptor byte array. + * + * @return The pointer for endpoint descriptor. + * @retval end did not found endpoint descriptor */ +static void const* _find_desc_ep(void const *beg, void const *end) +{ + for (void const *cur = beg; cur < end; cur = tu_desc_next(cur)) { + uint_fast8_t desc_type = tu_desc_type(cur); + if (TUSB_DESC_ENDPOINT == desc_type) return cur; + if (TUSB_DESC_INTERFACE == desc_type) break; + } + return end; +} + +/** Find the first entity descriptor with the entity ID + * specified by the argument belonging to the current video control descriptor. + * + * @param[in] desc The video control interface descriptor. + * @param[in] entityid The target entity id. + * + * @return The pointer for interface descriptor. + * @retval end did not found interface descriptor */ +static void const* _find_desc_entity(void const *desc, uint_fast8_t entityid) +{ + tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const*)desc; + void const *beg = vc; + void const *end = beg + vc->std.bLength + vc->ctl.wTotalLength; + for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) { + tusb_desc_cs_video_entity_itf_t const *itf = (tusb_desc_cs_video_entity_itf_t const *)cur; + if ((VIDEO_CS_ITF_VC_INPUT_TERMINAL <= itf->bDescriptorSubtype + && itf->bDescriptorSubtype < VIDEO_CS_ITF_VC_MAX) + && itf->bEntityId == entityid) { + return itf; + } + cur = tu_desc_next(cur); + } + return end; +} + +/** Return the end of the video streaming descriptor. */ +static inline void const* _end_of_streaming_descriptor(void const *desc) +{ + tusb_desc_vs_itf_t const *vs = (tusb_desc_vs_itf_t const *)desc; + return desc + vs->std.bLength + vs->stm.wTotalLength; +} + +/** Find the first format descriptor with the specified format number. */ +static inline tusb_desc_cs_video_fmt_uncompressed_t const *_find_desc_format(void const *beg, void const *end, uint_fast8_t fmtnum) +{ + return (tusb_desc_cs_video_fmt_uncompressed_t const*) + _find_desc_3(beg, end, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED, fmtnum); +} + +/** Find the first frame descriptor with the specified format number. */ +static inline tusb_desc_cs_video_frm_uncompressed_t const *_find_desc_frame(void const *beg, void const *end, uint_fast8_t frmnum) +{ + return (tusb_desc_cs_video_frm_uncompressed_t const*) + _find_desc_3(beg, end, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, frmnum); +} + +/** Set uniquely determined values to variables that have not been set + * + * @param[in,out] param Target */ +static bool _update_streaming_parameters(videod_streaming_interface_t const *stm, + video_probe_and_commit_control_t *param) +{ + tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); + uint_fast8_t fmtnum = param->bFormatIndex; + TU_ASSERT(vs && fmtnum <= vs->stm.bNumFormats); + if (!fmtnum) { + if (1 < vs->stm.bNumFormats) return true; /* Need to negotiate all variables. */ + fmtnum = 1; + param->bFormatIndex = 1; + } + + /* Set the parameters determined by the format */ + param->wKeyFrameRate = 1; + param->wPFrameRate = 0; + param->wCompQuality = 1; /* 1 to 10000 */ + param->wCompWindowSize = 1; /* GOP size? */ + param->wDelay = 0; /* milliseconds */ + param->dwClockFrequency = 27000000; /* same as MPEG-2 system time clock */ + param->bmFramingInfo = 0x3; /* enables FrameID and EndOfFrame */ + param->bPreferedVersion = 1; + param->bMinVersion = 1; + param->bMaxVersion = 1; + param->bUsage = 0; + param->bBitDepthLuma = 8; + + void const *end = _end_of_streaming_descriptor(vs); + tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); + TU_ASSERT(fmt != end); + uint_fast8_t frmnum = param->bFrameIndex; + TU_ASSERT(frmnum <= fmt->bNumFrameDescriptors); + if (!frmnum) { + if (1 < fmt->bNumFrameDescriptors) return true; + frmnum = 1; + param->bFrameIndex = 1; + } + tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); + TU_ASSERT(frm != end); + + /* Set the parameters determined by the frame */ + uint_fast32_t frame_size = param->dwMaxVideoFrameSize; + if (!frame_size) { + frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->bBitsPerPixel / 8; + param->dwMaxVideoFrameSize = frame_size; + } + + uint_fast32_t interval = param->dwFrameInterval; + if (!interval) { + if ((1 < frm->bFrameIntervalType) || + ((0 == frm->bFrameIntervalType) && (frm->dwFrameInterval[1] != frm->dwFrameInterval[0]))) { + return true; + } + interval = frm->dwFrameInterval[0]; + param->dwFrameInterval = interval; + } + uint_fast32_t interval_ms = interval / 10000; + TU_ASSERT(interval_ms); + uint_fast32_t payload_size = (frame_size + interval_ms - 1) / interval_ms + 2; + param->dwMaxPayloadTransferSize = payload_size; + return true; +} + +/** Set the minimum, maximum, default values or resolutions to variables which need to negotiate with the host + * + * @param[in] request GET_MAX, GET_MIN, GET_RES or GET_DEF + * @param[in,out] param Target + */ +static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *stm, uint_fast8_t request, + video_probe_and_commit_control_t *param) +{ + uint_fast8_t const fmtnum = param->bFormatIndex; + if (!fmtnum) { + switch (request) { + case VIDEO_REQUEST_GET_MAX: + param->bFormatIndex = _get_desc_vs(stm)->stm.bNumFormats; + break; + case VIDEO_REQUEST_GET_MIN: + case VIDEO_REQUEST_GET_DEF: + param->bFormatIndex = 1; + break; + default: return false; + } + /* Set the parameters determined by the format */ + param->wKeyFrameRate = 1; + param->wPFrameRate = 0; + param->wCompQuality = 1; /* 1 to 10000 */ + param->wCompWindowSize = 1; /* GOP size? */ + param->wDelay = 0; /* milliseconds */ + param->dwClockFrequency = 27000000; /* same as MPEG-2 system time clock */ + param->bmFramingInfo = 0x3; /* enables FrameID and EndOfFrame */ + param->bPreferedVersion = 1; + param->bMinVersion = 1; + param->bMaxVersion = 1; + param->bUsage = 0; + param->bBitDepthLuma = 8; + return true; + } + + uint_fast8_t frmnum = param->bFrameIndex; + if (!frmnum) { + tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); + TU_ASSERT(vs); + void const *end = _end_of_streaming_descriptor(vs); + tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); + switch (request) { + case VIDEO_REQUEST_GET_MAX: + frmnum = fmt->bNumFrameDescriptors; + break; + case VIDEO_REQUEST_GET_MIN: + frmnum = 1; + break; + case VIDEO_REQUEST_GET_DEF: + frmnum = fmt->bDefaultFrameIndex; + break; + default: return false; + } + param->bFrameIndex = (uint8_t) frmnum; + /* Set the parameters determined by the frame */ + tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); + param->dwMaxVideoFrameSize = (uint32_t) (frm->wWidth * frm->wHeight * fmt->bBitsPerPixel / 8); + return true; + } + + if (!param->dwFrameInterval) { + tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); + TU_ASSERT(vs); + void const *end = _end_of_streaming_descriptor(vs); + tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); + tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); + + uint_fast32_t interval, interval_ms; + switch (request) { + case VIDEO_REQUEST_GET_MAX: + { + uint_fast32_t min_interval, max_interval; + uint_fast8_t num_intervals = frm->bFrameIntervalType; + max_interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1]; + min_interval = frm->dwFrameInterval[0]; + interval = max_interval; + interval_ms = min_interval / 10000; + } + break; + case VIDEO_REQUEST_GET_MIN: + { + uint_fast32_t min_interval, max_interval; + uint_fast8_t num_intervals = frm->bFrameIntervalType; + max_interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1]; + min_interval = frm->dwFrameInterval[0]; + interval = min_interval; + interval_ms = max_interval / 10000; + } + break; + case VIDEO_REQUEST_GET_DEF: + interval = frm->dwDefaultFrameInterval; + interval_ms = interval / 10000; + break; + case VIDEO_REQUEST_GET_RES: + { + uint_fast8_t num_intervals = frm->bFrameIntervalType; + if (num_intervals) { + interval = 0; + } else { + interval = frm->dwFrameInterval[2]; + interval_ms = interval / 10000; + } + } + break; + default: return false; + } + param->dwFrameInterval = interval; + if (!interval) { + param->dwMaxPayloadTransferSize = 0; + } else { + uint_fast32_t frame_size = param->dwMaxVideoFrameSize; + if (!interval_ms) { + param->dwMaxPayloadTransferSize = frame_size + 2; + } else { + param->dwMaxPayloadTransferSize = (frame_size + interval_ms - 1) / interval_ms + 2; + } + } + return true; + } + return true; +} + +/** Close current video control interface. + * + * @param[in,out] self Video control interface context. + * @param[in] altnum The target alternate setting number. */ +static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self) +{ + tusb_desc_vc_itf_t const *vc = _get_desc_vc(self); + /* The next descriptor after the class-specific VC interface header descriptor. */ + void const *cur = (void const*)vc + vc->std.bLength + vc->ctl.bLength; + /* The end of the video control interface descriptor. */ + void const *end = (void const*)vc + vc->std.bLength + vc->ctl.wTotalLength; + if (vc->std.bNumEndpoints) { + /* Find the notification endpoint descriptor. */ + cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT); + TU_ASSERT(cur < end); + tusb_desc_endpoint_t const *notif = (tusb_desc_endpoint_t const *)cur; + usbd_edpt_close(rhport, notif->bEndpointAddress); + } + self->cur = 0; + return true; +} + +/** Set the alternate setting to own video control interface. + * + * @param[in,out] self Video control interface context. + * @param[in] altnum The target alternate setting number. */ +static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t altnum) +{ + TU_LOG2(" open VC %d\n", altnum); + void const *beg = self->beg; + void const *end = beg + self->len; + /* The first descriptor is a video control interface descriptor. */ + void const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); + TU_LOG2(" cur %d\n", cur - beg); + TU_VERIFY(cur < end); + + tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const *)cur; + TU_LOG2(" bInCollection %d\n", vc->ctl.bInCollection); + /* Support for up to 2 streaming interfaces only. */ + TU_ASSERT(vc->ctl.bInCollection <= CFG_TUD_VIDEO_STREAMING); + + /* Update to point the end of the video control interface descriptor. */ + end = cur + vc->std.bLength + vc->ctl.wTotalLength; + /* Advance to the next descriptor after the class-specific VC interface header descriptor. */ + cur += vc->std.bLength + vc->ctl.bLength; + TU_LOG2(" bNumEndpoints %d\n", vc->std.bNumEndpoints); + /* Open the notification endpoint if it exist. */ + if (vc->std.bNumEndpoints) { + /* Support for 1 endpoint only. */ + TU_VERIFY(1 == vc->std.bNumEndpoints); + /* Find the notification endpoint descriptor. */ + cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT); + TU_VERIFY(cur < end); + tusb_desc_endpoint_t const *notif = (tusb_desc_endpoint_t const *)cur; + /* Open the notification endpoint */ + TU_ASSERT(usbd_edpt_open(rhport, notif)); + } + self->cur = (uint16_t) ((void const*)vc - beg); + return true; +} + +/** Set the alternate setting to own video streaming interface. + * + * @param[in,out] stm Streaming interface context. + * @param[in] altnum The target alternate setting number. */ +static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint_fast8_t altnum) +{ + uint_fast8_t i; + TU_LOG2(" reopen VS %d\n", altnum); + void const *desc = _videod_itf[stm->index_vc].beg; + + /* Close endpoints of previous settings. */ + for (i = 0; i < TU_ARRAY_SIZE(stm->desc.ep); ++i) { + uint_fast16_t ofs_ep = stm->desc.ep[i]; + if (!ofs_ep) break; + uint8_t ep_adr = _desc_ep_addr(desc + ofs_ep); + usbd_edpt_close(rhport, ep_adr); + stm->desc.ep[i] = 0; + TU_LOG2(" close EP%02x\n", ep_adr); + } + /* clear transfer management information */ + stm->buffer = NULL; + stm->bufsize = 0; + stm->offset = 0; + + /* Find a alternate interface */ + void const *beg = desc + stm->desc.beg; + void const *end = desc + stm->desc.end; + void const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); + TU_VERIFY(cur < end); + uint_fast8_t numeps = ((tusb_desc_interface_t const *)cur)->bNumEndpoints; + TU_ASSERT(numeps <= TU_ARRAY_SIZE(stm->desc.ep)); + stm->desc.cur = (uint16_t) (cur - desc); /* Save the offset of the new settings */ + if (!altnum) { + /* initialize streaming settings */ + stm->max_payload_transfer_size = 0; + video_probe_and_commit_control_t *param = + (video_probe_and_commit_control_t *)&stm->ep_buf; + tu_memclr(param, sizeof(*param)); + return _update_streaming_parameters(stm, param); + } + /* Open endpoints of the new settings. */ + for (i = 0, cur = tu_desc_next(cur); i < numeps; ++i, cur = tu_desc_next(cur)) { + cur = _find_desc_ep(cur, end); + TU_ASSERT(cur < end); + tusb_desc_endpoint_t const *ep = (tusb_desc_endpoint_t const*)cur; + if (!stm->max_payload_transfer_size) { + video_probe_and_commit_control_t const *param = (video_probe_and_commit_control_t const*)&stm->ep_buf; + uint_fast32_t max_size = param->dwMaxPayloadTransferSize; + if ((TUSB_XFER_ISOCHRONOUS == ep->bmAttributes.xfer) && + (tu_edpt_packet_size(ep) < max_size)) + { + /* FS must be less than or equal to max packet size */ + return false; + } + /* Set the negotiated value */ + stm->max_payload_transfer_size = max_size; + } + TU_ASSERT(usbd_edpt_open(rhport, ep)); + stm->desc.ep[i] = (uint16_t) (cur - desc); + TU_LOG2(" open EP%02x\n", _desc_ep_addr(cur)); + } + /* initialize payload header */ + tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf; + hdr->bHeaderLength = sizeof(*hdr); + hdr->bmHeaderInfo = 0; + + return true; +} + +/** Prepare the next packet payload. */ +static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm) +{ + uint_fast16_t remaining = stm->bufsize - stm->offset; + uint_fast16_t hdr_len = stm->ep_buf[0]; + uint_fast16_t pkt_len = stm->max_payload_transfer_size; + if (hdr_len + remaining < pkt_len) { + pkt_len = hdr_len + remaining; + } + uint_fast16_t data_len = pkt_len - hdr_len; + memcpy(&stm->ep_buf[hdr_len], stm->buffer + stm->offset, data_len); + stm->offset += data_len; + remaining -= data_len; + if (!remaining) { + tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf; + hdr->EndOfFrame = 1; + } + return hdr_len + data_len; +} + +/** Handle a standard request to the video control interface. */ +static int handle_video_ctl_std_req(uint8_t rhport, uint8_t stage, + tusb_control_request_t const *request, + uint_fast8_t ctl_idx) +{ + switch (request->bRequest) { + case TUSB_REQ_GET_INTERFACE: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); + tusb_desc_vc_itf_t const *vc = _get_desc_vc(&_videod_itf[ctl_idx]); + TU_VERIFY(vc, VIDEO_ERROR_UNKNOWN); + + uint8_t alt_num = vc->std.bAlternateSetting; + + TU_VERIFY(tud_control_xfer(rhport, request, &alt_num, sizeof(alt_num)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case TUSB_REQ_SET_INTERFACE: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(0 == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(_close_vc_itf(rhport, &_videod_itf[ctl_idx]), VIDEO_ERROR_UNKNOWN); + TU_VERIFY(_open_vc_itf(rhport, &_videod_itf[ctl_idx], request->wValue), VIDEO_ERROR_UNKNOWN); + tud_control_status(rhport, request); + } + return VIDEO_ERROR_NONE; + + default: /* Unknown/Unsupported request */ + TU_BREAKPOINT(); + return VIDEO_ERROR_INVALID_REQUEST; + } +} + +static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage, + tusb_control_request_t const *request, + uint_fast8_t ctl_idx) +{ + videod_interface_t *self = &_videod_itf[ctl_idx]; + + /* 4.2.1 Interface Control Request */ + switch (TU_U16_HIGH(request->wValue)) { + case VIDEO_VC_CTL_VIDEO_POWER_MODE: + switch (request->bRequest) { + case VIDEO_REQUEST_SET_CUR: + if (stage == CONTROL_STAGE_SETUP) { + TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, &self->power_mode, sizeof(self->power_mode)), VIDEO_ERROR_UNKNOWN); + } else if (stage == CONTROL_STAGE_ACK) { + if (tud_video_power_mode_cb) return tud_video_power_mode_cb(ctl_idx, self->power_mode); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_CUR: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, &self->power_mode, sizeof(self->power_mode)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_INFO: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + default: break; + } + break; + + case VIDEO_VC_CTL_REQUEST_ERROR_CODE: + switch (request->bRequest) { + case VIDEO_REQUEST_GET_CUR: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(tud_control_xfer(rhport, request, &self->error_code, sizeof(uint8_t)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_INFO: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get, sizeof(_cap_get)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + default: break; + } + break; + + default: break; + } + + /* Unknown/Unsupported request */ + TU_BREAKPOINT(); + return VIDEO_ERROR_INVALID_REQUEST; +} + +static int handle_video_ctl_req(uint8_t rhport, uint8_t stage, + tusb_control_request_t const *request, + uint_fast8_t ctl_idx) +{ + uint_fast8_t entity_id; + switch (request->bmRequestType_bit.type) { + case TUSB_REQ_TYPE_STANDARD: + return handle_video_ctl_std_req(rhport, stage, request, ctl_idx); + + case TUSB_REQ_TYPE_CLASS: + entity_id = TU_U16_HIGH(request->wIndex); + if (!entity_id) { + return handle_video_ctl_cs_req(rhport, stage, request, ctl_idx); + } else { + TU_VERIFY(_find_desc_entity(_get_desc_vc(&_videod_itf[ctl_idx]), entity_id), VIDEO_ERROR_INVALID_REQUEST); + return VIDEO_ERROR_NONE; + } + + default: + return VIDEO_ERROR_INVALID_REQUEST; + } +} + +static int handle_video_stm_std_req(uint8_t rhport, uint8_t stage, + tusb_control_request_t const *request, + uint_fast8_t stm_idx) +{ + videod_streaming_interface_t *self = &_videod_streaming_itf[stm_idx]; + switch (request->bRequest) { + case TUSB_REQ_GET_INTERFACE: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); + tusb_desc_vs_itf_t const *vs = _get_desc_vs(self); + TU_VERIFY(vs, VIDEO_ERROR_UNKNOWN); + uint8_t alt_num = vs->std.bAlternateSetting; + + TU_VERIFY(tud_control_xfer(rhport, request, &alt_num, sizeof(alt_num)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case TUSB_REQ_SET_INTERFACE: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(_open_vs_itf(rhport, self, request->wValue), VIDEO_ERROR_UNKNOWN); + tud_control_status(rhport, request); + } + return VIDEO_ERROR_NONE; + + default: /* Unknown/Unsupported request */ + TU_BREAKPOINT(); + return VIDEO_ERROR_INVALID_REQUEST; + } +} + +static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, + tusb_control_request_t const *request, + uint_fast8_t stm_idx) +{ + (void)rhport; + videod_streaming_interface_t *self = &_videod_streaming_itf[stm_idx]; + + /* 4.2.1 Interface Control Request */ + switch (TU_U16_HIGH(request->wValue)) { + case VIDEO_VS_CTL_STREAM_ERROR_CODE: + switch (request->bRequest) { + case VIDEO_REQUEST_GET_CUR: + if (stage == CONTROL_STAGE_SETUP) + { + /* TODO */ + TU_VERIFY(tud_control_xfer(rhport, request, &self->error_code, sizeof(uint8_t)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_INFO: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get, sizeof(_cap_get)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + default: break; + } + break; + + case VIDEO_VS_CTL_PROBE: + switch (request->bRequest) { + case VIDEO_REQUEST_SET_CUR: + if (stage == CONTROL_STAGE_SETUP) { + TU_VERIFY(sizeof(video_probe_and_commit_control_t) == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), + VIDEO_ERROR_UNKNOWN); + } else if (stage == CONTROL_STAGE_ACK) { + TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf), + VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_CUR: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_MIN: + case VIDEO_REQUEST_GET_MAX: + case VIDEO_REQUEST_GET_RES: + case VIDEO_REQUEST_GET_DEF: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN); + video_probe_and_commit_control_t tmp; + tmp = *(video_probe_and_commit_control_t*)&self->ep_buf; + TU_VERIFY(_negotiate_streaming_parameters(self, request->bRequest, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); + TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_LEN: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN); + uint16_t len = sizeof(video_probe_and_commit_control_t); + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_INFO: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + default: break; + } + break; + + case VIDEO_VS_CTL_COMMIT: + switch (request->bRequest) { + case VIDEO_REQUEST_SET_CUR: + if (stage == CONTROL_STAGE_SETUP) { + TU_VERIFY(sizeof(video_probe_and_commit_control_t) == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); + } else if (stage == CONTROL_STAGE_ACK) { + TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); + if (tud_video_commit_cb) { + return tud_video_commit_cb(self->index_vc, self->index_vs, (video_probe_and_commit_control_t*)self->ep_buf); + } + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_CUR: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_LEN: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN); + uint16_t len = sizeof(video_probe_and_commit_control_t); + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_INFO: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + default: break; + } + break; + + case VIDEO_VS_CTL_STILL_PROBE: + case VIDEO_VS_CTL_STILL_COMMIT: + case VIDEO_VS_CTL_STILL_IMAGE_TRIGGER: + case VIDEO_VS_CTL_GENERATE_KEY_FRAME: + case VIDEO_VS_CTL_UPDATE_FRAME_SEGMENT: + case VIDEO_VS_CTL_SYNCH_DELAY_CONTROL: + /* TODO */ + break; + + default: break; + } + + /* Unknown/Unsupported request */ + TU_BREAKPOINT(); + return VIDEO_ERROR_INVALID_REQUEST; +} + +static int handle_video_stm_req(uint8_t rhport, uint8_t stage, + tusb_control_request_t const *request, + uint_fast8_t stm_idx) +{ + switch (request->bmRequestType_bit.type) { + case TUSB_REQ_TYPE_STANDARD: + return handle_video_stm_std_req(rhport, stage, request, stm_idx); + + case TUSB_REQ_TYPE_CLASS: + if (TU_U16_HIGH(request->wIndex)) return VIDEO_ERROR_INVALID_REQUEST; + return handle_video_stm_cs_req(rhport, stage, request, stm_idx); + + default: return VIDEO_ERROR_INVALID_REQUEST; + } + return VIDEO_ERROR_UNKNOWN; +} + +//--------------------------------------------------------------------+ +// APPLICATION API +//--------------------------------------------------------------------+ + +bool tud_video_n_connected(uint_fast8_t ctl_idx) +{ + TU_ASSERT(ctl_idx < CFG_TUD_VIDEO); + videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, 0); + if (stm) return true; + return false; +} + +bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) +{ + TU_ASSERT(ctl_idx < CFG_TUD_VIDEO); + TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING); + videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx); + if (!stm || !stm->desc.ep[0]) return false; + return true; +} + +bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *buffer, size_t bufsize) +{ + TU_ASSERT(ctl_idx < CFG_TUD_VIDEO); + TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING); + if (!buffer || !bufsize) return false; + videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx); + if (!stm || !stm->desc.ep[0] || stm->buffer) return false; + + /* Find EP address */ + void const *desc = _videod_itf[stm->index_vc].beg; + uint8_t ep_addr = 0; + for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { + uint_fast16_t ofs_ep = stm->desc.ep[i]; + if (!ofs_ep) continue; + ep_addr = _desc_ep_addr(desc + ofs_ep); + break; + } + if (!ep_addr) return false; + + TU_VERIFY( usbd_edpt_claim(0, ep_addr) ); + /* update the packet header */ + tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf; + hdr->FrameID ^= 1; + hdr->EndOfFrame = 0; + /* update the packet data */ + stm->buffer = (uint8_t*)buffer; + stm->bufsize = bufsize; + uint_fast16_t pkt_len = _prepare_in_payload(stm); + TU_ASSERT( usbd_edpt_xfer(0, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0); + return true; +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void videod_init(void) +{ + for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) { + videod_interface_t* ctl = &_videod_itf[i]; + tu_memclr(ctl, sizeof(*ctl)); + } + for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { + videod_streaming_interface_t *stm = &_videod_streaming_itf[i]; + tu_memclr(stm, ITF_STM_MEM_RESET_SIZE); + } +} + +void videod_reset(uint8_t rhport) +{ + (void) rhport; + for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) { + videod_interface_t* ctl = &_videod_itf[i]; + tu_memclr(ctl, sizeof(*ctl)); + } + for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { + videod_streaming_interface_t *stm = &_videod_streaming_itf[i]; + tu_memclr(stm, ITF_STM_MEM_RESET_SIZE); + } +} + +uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + TU_VERIFY((TUSB_CLASS_VIDEO == itf_desc->bInterfaceClass) && + (VIDEO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass) && + (VIDEO_ITF_PROTOCOL_15 == itf_desc->bInterfaceProtocol), 0); + + /* Find available interface */ + videod_interface_t *self = NULL; + uint8_t ctl_idx; + for (ctl_idx = 0; ctl_idx < CFG_TUD_VIDEO; ++ctl_idx) { + if (_videod_itf[ctl_idx].beg) continue; + self = &_videod_itf[ctl_idx]; + break; + } + TU_ASSERT(ctl_idx < CFG_TUD_VIDEO, 0); + + void const *end = (void const*)itf_desc + max_len; + self->beg = itf_desc; + self->len = max_len; + /*------------- Video Control Interface -------------*/ + TU_VERIFY(_open_vc_itf(rhport, self, 0), 0); + tusb_desc_vc_itf_t const *vc = _get_desc_vc(self); + uint_fast8_t bInCollection = vc->ctl.bInCollection; + /* Find the end of the video interface descriptor */ + void const *cur = _next_desc_itf(itf_desc, end); + for (uint8_t stm_idx = 0; stm_idx < bInCollection; ++stm_idx) { + videod_streaming_interface_t *stm = NULL; + /* find free streaming interface handle */ + for (uint8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { + if (_videod_streaming_itf[i].desc.beg) continue; + stm = &_videod_streaming_itf[i]; + self->stm[stm_idx] = i; + break; + } + TU_ASSERT(stm, 0); + stm->index_vc = ctl_idx; + stm->index_vs = stm_idx; + stm->desc.beg = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); + cur = _next_desc_itf(cur, end); + stm->desc.end = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); + } + self->len = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); + return (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + int err; + TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); + uint_fast8_t itfnum = tu_u16_low(request->wIndex); + + /* Identify which control interface to use */ + uint_fast8_t itf; + for (itf = 0; itf < CFG_TUD_VIDEO; ++itf) { + void const *desc = _videod_itf[itf].beg; + if (!desc) continue; + if (itfnum == _desc_itfnum(desc)) break; + } + + if (itf < CFG_TUD_VIDEO) { + err = handle_video_ctl_req(rhport, stage, request, itf); + _videod_itf[itf].error_code = (uint8_t)err; + if (err) return false; + return true; + } + + /* Identify which streaming interface to use */ + for (itf = 0; itf < CFG_TUD_VIDEO_STREAMING; ++itf) { + videod_streaming_interface_t *stm = &_videod_streaming_itf[itf]; + if (!stm->desc.beg) continue; + void const *desc = _videod_itf[stm->index_vc].beg; + if (itfnum == _desc_itfnum(desc + stm->desc.beg)) break; + } + + if (itf < CFG_TUD_VIDEO_STREAMING) { + err = handle_video_stm_req(rhport, stage, request, itf); + _videod_streaming_itf[itf].error_code = (uint8_t)err; + if (err) return false; + return true; + } + return false; +} + +bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void)result; (void)xferred_bytes; + + /* find streaming handle */ + uint_fast8_t itf; + videod_interface_t *ctl; + videod_streaming_interface_t *stm; + for (itf = 0; itf < CFG_TUD_VIDEO_STREAMING; ++itf) { + stm = &_videod_streaming_itf[itf]; + uint_fast16_t const ep_ofs = stm->desc.ep[0]; + if (!ep_ofs) continue; + ctl = &_videod_itf[stm->index_vc]; + void const *desc = ctl->beg; + if (ep_addr == _desc_ep_addr(desc + ep_ofs)) break; + } + + TU_ASSERT(itf < CFG_TUD_VIDEO_STREAMING); + if (stm->offset < stm->bufsize) { + /* Claim the endpoint */ + TU_VERIFY( usbd_edpt_claim(rhport, ep_addr), 0); + uint_fast16_t pkt_len = _prepare_in_payload(stm); + TU_ASSERT( usbd_edpt_xfer(rhport, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0); + } else { + stm->buffer = NULL; + stm->bufsize = 0; + stm->offset = 0; + if (tud_video_frame_xfer_complete_cb) { + tud_video_frame_xfer_complete_cb(stm->index_vc, stm->index_vs); + } + } + return true; +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/video/video_device.h b/test-devices/composite-stm32/lib/tinyusb/class/video/video_device.h new file mode 100644 index 00000000..ee2fcb9d --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/video/video_device.h @@ -0,0 +1,97 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2021 Koji KITAYAMA + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef TUSB_VIDEO_DEVICE_H_ +#define TUSB_VIDEO_DEVICE_H_ + +#include "common/tusb_common.h" +#include "video.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Application API (Multiple Ports) +// CFG_TUD_VIDEO > 1 +//--------------------------------------------------------------------+ + +/** Return true if streaming + * + * @param[in] ctl_idx Destination control interface index + * @param[in] stm_idx Destination streaming interface index */ +bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx); + +/** Transfer a frame + * + * @param[in] ctl_idx Destination control interface index + * @param[in] stm_idx Destination streaming interface index + * @param[in] buffer Frame buffer. The caller must not use this buffer until the operation is completed. + * @param[in] bufsize Byte size of the frame buffer */ +bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *buffer, size_t bufsize); + +/*------------- Optional callbacks -------------*/ +/** Invoked when compeletion of a frame transfer + * + * @param[in] ctl_idx Destination control interface index + * @param[in] stm_idx Destination streaming interface index */ +TU_ATTR_WEAK void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx); + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ + +/** Invoked when SET_POWER_MODE request received + * + * @param[in] ctl_idx Destination control interface index + * @param[in] stm_idx Destination streaming interface index + * @return video_error_code_t */ +TU_ATTR_WEAK int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod); + +/** Invoked when VS_COMMIT_CONTROL(SET_CUR) request received + * + * @param[in] ctl_idx Destination control interface index + * @param[in] stm_idx Destination streaming interface index + * @param[in] parameters Video streaming parameters + * @return video_error_code_t */ +TU_ATTR_WEAK int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, + video_probe_and_commit_control_t const *parameters); + +//--------------------------------------------------------------------+ +// INTERNAL USBD-CLASS DRIVER API +//--------------------------------------------------------------------+ +void videod_init (void); +void videod_reset (uint8_t rhport); +uint16_t videod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +bool videod_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_common.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_common.h new file mode 100644 index 00000000..b1ee40a1 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_common.h @@ -0,0 +1,266 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_COMMON_H_ +#define _TUSB_COMMON_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Macros Helper +//--------------------------------------------------------------------+ +#define TU_ARRAY_SIZE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) ) +#define TU_MIN(_x, _y) ( ( (_x) < (_y) ) ? (_x) : (_y) ) +#define TU_MAX(_x, _y) ( ( (_x) > (_y) ) ? (_x) : (_y) ) + +#define TU_U16(_high, _low) ((uint16_t) (((_high) << 8) | (_low))) +#define TU_U16_HIGH(_u16) ((uint8_t) (((_u16) >> 8) & 0x00ff)) +#define TU_U16_LOW(_u16) ((uint8_t) ((_u16) & 0x00ff)) +#define U16_TO_U8S_BE(_u16) TU_U16_HIGH(_u16), TU_U16_LOW(_u16) +#define U16_TO_U8S_LE(_u16) TU_U16_LOW(_u16), TU_U16_HIGH(_u16) + +#define TU_U32_BYTE3(_u32) ((uint8_t) ((((uint32_t) _u32) >> 24) & 0x000000ff)) // MSB +#define TU_U32_BYTE2(_u32) ((uint8_t) ((((uint32_t) _u32) >> 16) & 0x000000ff)) +#define TU_U32_BYTE1(_u32) ((uint8_t) ((((uint32_t) _u32) >> 8) & 0x000000ff)) +#define TU_U32_BYTE0(_u32) ((uint8_t) (((uint32_t) _u32) & 0x000000ff)) // LSB + +#define U32_TO_U8S_BE(_u32) TU_U32_BYTE3(_u32), TU_U32_BYTE2(_u32), TU_U32_BYTE1(_u32), TU_U32_BYTE0(_u32) +#define U32_TO_U8S_LE(_u32) TU_U32_BYTE0(_u32), TU_U32_BYTE1(_u32), TU_U32_BYTE2(_u32), TU_U32_BYTE3(_u32) + +#define TU_BIT(n) (1UL << (n)) +#define TU_GENMASK(h, l) ( (UINT32_MAX << (l)) & (UINT32_MAX >> (31 - (h))) ) + +//--------------------------------------------------------------------+ +// Includes +//--------------------------------------------------------------------+ + +// Standard Headers +#include +#include +#include +#include +#include + +// Tinyusb Common Headers +#include "tusb_option.h" +#include "tusb_compiler.h" +#include "tusb_verify.h" +#include "tusb_types.h" +#include "tusb_debug.h" + +#include "tusb_timeout.h" // TODO remove + +//--------------------------------------------------------------------+ +// Internal Inline Functions +//--------------------------------------------------------------------+ + +//------------- Mem -------------// +#define tu_memclr(buffer, size) memset((buffer), 0, (size)) +#define tu_varclr(_var) tu_memclr(_var, sizeof(*(_var))) + +//------------- Bytes -------------// +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_u32(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0) +{ + return ( ((uint32_t) b3) << 24) | ( ((uint32_t) b2) << 16) | ( ((uint32_t) b1) << 8) | b0; +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u16(uint8_t high, uint8_t low) +{ + return (uint16_t) ((((uint16_t) high) << 8) | low); +} + +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u32_byte3(uint32_t ui32) { return TU_U32_BYTE3(ui32); } +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u32_byte2(uint32_t ui32) { return TU_U32_BYTE2(ui32); } +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u32_byte1(uint32_t ui32) { return TU_U32_BYTE1(ui32); } +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u32_byte0(uint32_t ui32) { return TU_U32_BYTE0(ui32); } + +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u32_high16(uint32_t ui32) { return (uint16_t) (ui32 >> 16); } +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u32_low16 (uint32_t ui32) { return (uint16_t) (ui32 & 0x0000ffffu); } + +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u16_high(uint16_t ui16) { return TU_U16_HIGH(ui16); } +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u16_low (uint16_t ui16) { return TU_U16_LOW(ui16); } + +//------------- Bits -------------// +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_bit_set (uint32_t value, uint8_t pos) { return value | TU_BIT(pos); } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_bit_clear(uint32_t value, uint8_t pos) { return value & (~TU_BIT(pos)); } +TU_ATTR_ALWAYS_INLINE static inline bool tu_bit_test (uint32_t value, uint8_t pos) { return (value & TU_BIT(pos)) ? true : false; } + +//------------- Min -------------// +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_min8 (uint8_t x, uint8_t y ) { return (x < y) ? x : y; } +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_min16 (uint16_t x, uint16_t y) { return (x < y) ? x : y; } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_min32 (uint32_t x, uint32_t y) { return (x < y) ? x : y; } + +//------------- Max -------------// +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_max8 (uint8_t x, uint8_t y ) { return (x > y) ? x : y; } +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_max16 (uint16_t x, uint16_t y) { return (x > y) ? x : y; } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_max32 (uint32_t x, uint32_t y) { return (x > y) ? x : y; } + +//------------- Align -------------// +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align(uint32_t value, uint32_t alignment) +{ + return value & ((uint32_t) ~(alignment-1)); +} + +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align16 (uint32_t value) { return (value & 0xFFFFFFF0UL); } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align32 (uint32_t value) { return (value & 0xFFFFFFE0UL); } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align4k (uint32_t value) { return (value & 0xFFFFF000UL); } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_offset4k(uint32_t value) { return (value & 0xFFFUL); } + +//------------- Mathematics -------------// +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_div_ceil(uint32_t v, uint32_t d) { return (v + d -1)/d; } + +// log2 of a value is its MSB's position +// TODO use clz TODO remove +static inline uint8_t tu_log2(uint32_t value) +{ + uint8_t result = 0; + while (value >>= 1) { result++; } + return result; +} + +//static inline uint8_t tu_log2(uint32_t value) +//{ +// return sizeof(uint32_t) * CHAR_BIT - __builtin_clz(x) - 1; +//} + +static inline bool tu_is_power_of_two(uint32_t value) +{ + return (value != 0) && ((value & (value - 1)) == 0); +} + +//------------- Unaligned Access -------------// +#if TUP_ARCH_STRICT_ALIGN + +// Rely on compiler to generate correct code for unaligned access +typedef struct { uint16_t val; } TU_ATTR_PACKED tu_unaligned_uint16_t; +typedef struct { uint32_t val; } TU_ATTR_PACKED tu_unaligned_uint32_t; + +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32(const void* mem) +{ + tu_unaligned_uint32_t const* ua32 = (tu_unaligned_uint32_t const*) mem; + return ua32->val; +} + +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32(void* mem, uint32_t value) +{ + tu_unaligned_uint32_t* ua32 = (tu_unaligned_uint32_t*) mem; + ua32->val = value; +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16(const void* mem) +{ + tu_unaligned_uint16_t const* ua16 = (tu_unaligned_uint16_t const*) mem; + return ua16->val; +} + +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void* mem, uint16_t value) +{ + tu_unaligned_uint16_t* ua16 = (tu_unaligned_uint16_t*) mem; + ua16->val = value; +} + +#elif TUP_MCU_STRICT_ALIGN + +// MCU such as LPC_IP3511 Highspeed cannot access unaligned memory on USB_RAM although it is ARM M4. +// We have to manually pick up bytes since tu_unaligned_uint32_t will still generate unaligned code +// NOTE: volatile cast to memory to prevent compiler to optimize and generate unaligned code +// TODO Big Endian may need minor changes +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32(const void* mem) +{ + volatile uint8_t const* buf8 = (uint8_t const*) mem; + return tu_u32(buf8[3], buf8[2], buf8[1], buf8[0]); +} + +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32(void* mem, uint32_t value) +{ + volatile uint8_t* buf8 = (uint8_t*) mem; + buf8[0] = tu_u32_byte0(value); + buf8[1] = tu_u32_byte1(value); + buf8[2] = tu_u32_byte2(value); + buf8[3] = tu_u32_byte3(value); +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16(const void* mem) +{ + volatile uint8_t const* buf8 = (uint8_t const*) mem; + return tu_u16(buf8[1], buf8[0]); +} + +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void* mem, uint16_t value) +{ + volatile uint8_t* buf8 = (uint8_t*) mem; + buf8[0] = tu_u16_low(value); + buf8[1] = tu_u16_high(value); +} + + +#else + +// MCU that could access unaligned memory natively +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32 (const void* mem) { return *((uint32_t const *) mem); } +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16 (const void* mem) { return *((uint16_t const *) mem); } + +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32 (void* mem, uint32_t value ) { *((uint32_t*) mem) = value; } +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16 (void* mem, uint16_t value ) { *((uint16_t*) mem) = value; } + +#endif + +// To be removed +//------------- Binary constant -------------// +#if defined(__GNUC__) && !defined(__CC_ARM) + +#define TU_BIN8(x) ((uint8_t) (0b##x)) +#define TU_BIN16(b1, b2) ((uint16_t) (0b##b1##b2)) +#define TU_BIN32(b1, b2, b3, b4) ((uint32_t) (0b##b1##b2##b3##b4)) + +#else + +// internal macro of B8, B16, B32 +#define _B8__(x) (((x&0x0000000FUL)?1:0) \ + +((x&0x000000F0UL)?2:0) \ + +((x&0x00000F00UL)?4:0) \ + +((x&0x0000F000UL)?8:0) \ + +((x&0x000F0000UL)?16:0) \ + +((x&0x00F00000UL)?32:0) \ + +((x&0x0F000000UL)?64:0) \ + +((x&0xF0000000UL)?128:0)) + +#define TU_BIN8(d) ((uint8_t) _B8__(0x##d##UL)) +#define TU_BIN16(dmsb,dlsb) (((uint16_t)TU_BIN8(dmsb)<<8) + TU_BIN8(dlsb)) +#define TU_BIN32(dmsb,db2,db3,dlsb) \ + (((uint32_t)TU_BIN8(dmsb)<<24) \ + + ((uint32_t)TU_BIN8(db2)<<16) \ + + ((uint32_t)TU_BIN8(db3)<<8) \ + + TU_BIN8(dlsb)) +#endif + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_COMMON_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_compiler.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_compiler.h new file mode 100644 index 00000000..2c30daf6 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_compiler.h @@ -0,0 +1,274 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup Group_Common + * \defgroup Group_Compiler Compiler + * \brief Group_Compiler brief + * @{ */ + +#ifndef _TUSB_COMPILER_H_ +#define _TUSB_COMPILER_H_ + +#define TU_TOKEN(x) x +#define TU_STRING(x) #x ///< stringify without expand +#define TU_XSTRING(x) TU_STRING(x) ///< expand then stringify + +#define TU_STRCAT(a, b) a##b ///< concat without expand +#define TU_STRCAT3(a, b, c) a##b##c ///< concat without expand + +#define TU_XSTRCAT(a, b) TU_STRCAT(a, b) ///< expand then concat +#define TU_XSTRCAT3(a, b, c) TU_STRCAT3(a, b, c) ///< expand then concat 3 tokens + +#define TU_INCLUDE_PATH(_dir,_file) TU_XSTRING( TU_TOKEN(_dir)TU_TOKEN(_file) ) + +#if defined __COUNTER__ && __COUNTER__ != __COUNTER__ + #define _TU_COUNTER_ __COUNTER__ +#else + #define _TU_COUNTER_ __LINE__ +#endif + +// Compile-time Assert +#if defined (__cplusplus) && __cplusplus >= 201103L + #define TU_VERIFY_STATIC static_assert +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define TU_VERIFY_STATIC _Static_assert +#elif defined(__CCRX__) + #define TU_VERIFY_STATIC(const_expr, _mess) typedef char TU_XSTRCAT(Line, __LINE__)[(const_expr) ? 1 : 0]; +#else + #define TU_VERIFY_STATIC(const_expr, _mess) enum { TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1/(!!(const_expr)) } +#endif + +// for declaration of reserved field, make use of _TU_COUNTER_ +#define TU_RESERVED TU_XSTRCAT(reserved, _TU_COUNTER_) + +#define TU_LITTLE_ENDIAN (0x12u) +#define TU_BIG_ENDIAN (0x21u) + +/*------------------------------------------------------------------*/ +/* Count number of arguments of __VA_ARGS__ + * - reference https://stackoverflow.com/questions/2124339/c-preprocessor-va-args-number-of-arguments + * - _GET_NTH_ARG() takes args >= N (64) but only expand to Nth one (64th) + * - _RSEQ_N() is reverse sequential to N to add padding to have + * Nth position is the same as the number of arguments + * - ##__VA_ARGS__ is used to deal with 0 paramerter (swallows comma) + *------------------------------------------------------------------*/ +#if !defined(__CCRX__) +#define TU_ARGS_NUM(...) _TU_NARG(_0, ##__VA_ARGS__,_RSEQ_N()) +#else +#define TU_ARGS_NUM(...) _TU_NARG(_0, __VA_ARGS__,_RSEQ_N()) +#endif + +#define _TU_NARG(...) _GET_NTH_ARG(__VA_ARGS__) +#define _GET_NTH_ARG( \ + _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ + _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ + _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ + _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ + _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ + _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ + _61,_62,_63,N,...) N +#define _RSEQ_N() \ + 62,61,60, \ + 59,58,57,56,55,54,53,52,51,50, \ + 49,48,47,46,45,44,43,42,41,40, \ + 39,38,37,36,35,34,33,32,31,30, \ + 29,28,27,26,25,24,23,22,21,20, \ + 19,18,17,16,15,14,13,12,11,10, \ + 9,8,7,6,5,4,3,2,1,0 + +// Apply an macro X to each of the arguments with an separated of choice +#define TU_ARGS_APPLY(_X, _s, ...) TU_XSTRCAT(_TU_ARGS_APPLY_, TU_ARGS_NUM(__VA_ARGS__))(_X, _s, __VA_ARGS__) + +#define _TU_ARGS_APPLY_1(_X, _s, _a1) _X(_a1) +#define _TU_ARGS_APPLY_2(_X, _s, _a1, _a2) _X(_a1) _s _X(_a2) +#define _TU_ARGS_APPLY_3(_X, _s, _a1, _a2, _a3) _X(_a1) _s _TU_ARGS_APPLY_2(_X, _s, _a2, _a3) +#define _TU_ARGS_APPLY_4(_X, _s, _a1, _a2, _a3, _a4) _X(_a1) _s _TU_ARGS_APPLY_3(_X, _s, _a2, _a3, _a4) +#define _TU_ARGS_APPLY_5(_X, _s, _a1, _a2, _a3, _a4, _a5) _X(_a1) _s _TU_ARGS_APPLY_4(_X, _s, _a2, _a3, _a4, _a5) +#define _TU_ARGS_APPLY_6(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6) _X(_a1) _s _TU_ARGS_APPLY_5(_X, _s, _a2, _a3, _a4, _a5, _a6) +#define _TU_ARGS_APPLY_7(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6, _a7) _X(_a1) _s _TU_ARGS_APPLY_6(_X, _s, _a2, _a3, _a4, _a5, _a6, _a7) +#define _TU_ARGS_APPLY_8(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6, _a7, _a8) _X(_a1) _s _TU_ARGS_APPLY_7(_X, _s, _a2, _a3, _a4, _a5, _a6, _a7, _a8) + +//--------------------------------------------------------------------+ +// Compiler porting with Attribute and Endian +//--------------------------------------------------------------------+ + +// TODO refactor since __attribute__ is supported across many compiler +#if defined(__GNUC__) + #define TU_ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes))) + #define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name))) + #define TU_ATTR_PACKED __attribute__ ((packed)) + #define TU_ATTR_WEAK __attribute__ ((weak)) + #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) + #define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used + #define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused + #define TU_ATTR_USED __attribute__ ((used)) // Function/Variable is meant to be used + + #define TU_ATTR_PACKED_BEGIN + #define TU_ATTR_PACKED_END + #define TU_ATTR_BIT_FIELD_ORDER_BEGIN + #define TU_ATTR_BIT_FIELD_ORDER_END + + #if __has_attribute(__fallthrough__) + #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough)) + #else + #define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */ + #endif + + // Endian conversion use well-known host to network (big endian) naming + #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + #define TU_BYTE_ORDER TU_LITTLE_ENDIAN + #else + #define TU_BYTE_ORDER TU_BIG_ENDIAN + #endif + + #define TU_BSWAP16(u16) (__builtin_bswap16(u16)) + #define TU_BSWAP32(u32) (__builtin_bswap32(u32)) + + #ifndef __ARMCC_VERSION + // List of obsolete callback function that is renamed and should not be defined. + // Put it here since only gcc support this pragma + #pragma GCC poison tud_vendor_control_request_cb + #endif + +#elif defined(__TI_COMPILER_VERSION__) + #define TU_ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes))) + #define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name))) + #define TU_ATTR_PACKED __attribute__ ((packed)) + #define TU_ATTR_WEAK __attribute__ ((weak)) + #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) + #define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used + #define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused + #define TU_ATTR_USED __attribute__ ((used)) + #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough)) + + #define TU_ATTR_PACKED_BEGIN + #define TU_ATTR_PACKED_END + #define TU_ATTR_BIT_FIELD_ORDER_BEGIN + #define TU_ATTR_BIT_FIELD_ORDER_END + + // __BYTE_ORDER is defined in the TI ARM compiler, but not MSP430 (which is little endian) + #if ((__BYTE_ORDER__) == (__ORDER_LITTLE_ENDIAN__)) || defined(__MSP430__) + #define TU_BYTE_ORDER TU_LITTLE_ENDIAN + #else + #define TU_BYTE_ORDER TU_BIG_ENDIAN + #endif + + #define TU_BSWAP16(u16) (__builtin_bswap16(u16)) + #define TU_BSWAP32(u32) (__builtin_bswap32(u32)) + +#elif defined(__ICCARM__) + #include + #define TU_ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes))) + #define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name))) + #define TU_ATTR_PACKED __attribute__ ((packed)) + #define TU_ATTR_WEAK __attribute__ ((weak)) + #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) + #define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used + #define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused + #define TU_ATTR_USED __attribute__ ((used)) // Function/Variable is meant to be used + #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough)) + + #define TU_ATTR_PACKED_BEGIN + #define TU_ATTR_PACKED_END + #define TU_ATTR_BIT_FIELD_ORDER_BEGIN + #define TU_ATTR_BIT_FIELD_ORDER_END + + // Endian conversion use well-known host to network (big endian) naming + #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + #define TU_BYTE_ORDER TU_LITTLE_ENDIAN + #else + #define TU_BYTE_ORDER TU_BIG_ENDIAN + #endif + + #define TU_BSWAP16(u16) (__iar_builtin_REV16(u16)) + #define TU_BSWAP32(u32) (__iar_builtin_REV(u32)) + +#elif defined(__CCRX__) + #define TU_ATTR_ALIGNED(Bytes) + #define TU_ATTR_SECTION(sec_name) + #define TU_ATTR_PACKED + #define TU_ATTR_WEAK + #define TU_ATTR_ALWAYS_INLINE + #define TU_ATTR_DEPRECATED(mess) + #define TU_ATTR_UNUSED + #define TU_ATTR_USED + #define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */ + + #define TU_ATTR_PACKED_BEGIN _Pragma("pack") + #define TU_ATTR_PACKED_END _Pragma("packoption") + #define TU_ATTR_BIT_FIELD_ORDER_BEGIN _Pragma("bit_order right") + #define TU_ATTR_BIT_FIELD_ORDER_END _Pragma("bit_order") + + // Endian conversion use well-known host to network (big endian) naming + #if defined(__LIT) + #define TU_BYTE_ORDER TU_LITTLE_ENDIAN + #else + #define TU_BYTE_ORDER TU_BIG_ENDIAN + #endif + + #define TU_BSWAP16(u16) ((unsigned short)_builtin_revw((unsigned long)u16)) + #define TU_BSWAP32(u32) (_builtin_revl(u32)) + +#else + #error "Compiler attribute porting is required" +#endif + + +#if (TU_BYTE_ORDER == TU_LITTLE_ENDIAN) + + #define tu_htons(u16) (TU_BSWAP16(u16)) + #define tu_ntohs(u16) (TU_BSWAP16(u16)) + + #define tu_htonl(u32) (TU_BSWAP32(u32)) + #define tu_ntohl(u32) (TU_BSWAP32(u32)) + + #define tu_htole16(u16) (u16) + #define tu_le16toh(u16) (u16) + + #define tu_htole32(u32) (u32) + #define tu_le32toh(u32) (u32) + +#elif (TU_BYTE_ORDER == TU_BIG_ENDIAN) + + #define tu_htons(u16) (u16) + #define tu_ntohs(u16) (u16) + + #define tu_htonl(u32) (u32) + #define tu_ntohl(u32) (u32) + + #define tu_htole16(u16) (TU_BSWAP16(u16)) + #define tu_le16toh(u16) (TU_BSWAP16(u16)) + + #define tu_htole32(u32) (TU_BSWAP32(u32)) + #define tu_le32toh(u32) (TU_BSWAP32(u32)) + +#else + #error Byte order is undefined +#endif + +#endif /* _TUSB_COMPILER_H_ */ + +/// @} diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_debug.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_debug.h new file mode 100644 index 00000000..ac5bee6e --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_debug.h @@ -0,0 +1,178 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2022, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_DEBUG_H_ +#define _TUSB_DEBUG_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Debug +//--------------------------------------------------------------------+ + +// CFG_TUSB_DEBUG for debugging +// 0 : no debug +// 1 : print error +// 2 : print warning +// 3 : print info +#if CFG_TUSB_DEBUG + +// Enum to String for debugging purposes +#if CFG_TUSB_DEBUG >= 2 +extern char const* const tu_str_speed[]; +extern char const* const tu_str_std_request[]; +#endif + +void tu_print_mem(void const *buf, uint32_t count, uint8_t indent); + +#ifdef CFG_TUSB_DEBUG_PRINTF + extern int CFG_TUSB_DEBUG_PRINTF(const char *format, ...); + #define tu_printf CFG_TUSB_DEBUG_PRINTF +#else + #define tu_printf printf +#endif + +static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) +{ + for(uint32_t i=0; i= 2 + #define TU_LOG2 TU_LOG1 + #define TU_LOG2_MEM TU_LOG1_MEM + #define TU_LOG2_ARR TU_LOG1_ARR + #define TU_LOG2_VAR TU_LOG1_VAR + #define TU_LOG2_INT TU_LOG1_INT + #define TU_LOG2_HEX TU_LOG1_HEX +#endif + +// Log Level 3: Info +#if CFG_TUSB_DEBUG >= 3 + #define TU_LOG3 TU_LOG1 + #define TU_LOG3_MEM TU_LOG1_MEM + #define TU_LOG3_ARR TU_LOG1_ARR + #define TU_LOG3_VAR TU_LOG1_VAR + #define TU_LOG3_INT TU_LOG1_INT + #define TU_LOG3_HEX TU_LOG1_HEX +#endif + +typedef struct +{ + uint32_t key; + const char* data; +} tu_lookup_entry_t; + +typedef struct +{ + uint16_t count; + tu_lookup_entry_t const* items; +} tu_lookup_table_t; + +static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) +{ + static char not_found[11]; + + for(uint16_t i=0; icount; i++) + { + if (p_table->items[i].key == key) return p_table->items[i].data; + } + + // not found return the key value in hex + snprintf(not_found, sizeof(not_found), "0x%08lX", (unsigned long) key); + + return not_found; +} + +#endif // CFG_TUSB_DEBUG + +#ifndef TU_LOG + #define TU_LOG(n, ...) + #define TU_LOG_MEM(n, ...) + #define TU_LOG_VAR(n, ...) + #define TU_LOG_INT(n, ...) + #define TU_LOG_HEX(n, ...) + #define TU_LOG_LOCATION() + #define TU_LOG_FAILED() +#endif + +// TODO replace all TU_LOGn with TU_LOG(n) + +#define TU_LOG0(...) +#define TU_LOG0_MEM(...) +#define TU_LOG0_VAR(...) +#define TU_LOG0_INT(...) +#define TU_LOG0_HEX(...) + +#ifndef TU_LOG1 + #define TU_LOG1(...) + #define TU_LOG1_MEM(...) + #define TU_LOG1_VAR(...) + #define TU_LOG1_INT(...) + #define TU_LOG1_HEX(...) +#endif + +#ifndef TU_LOG2 + #define TU_LOG2(...) + #define TU_LOG2_MEM(...) + #define TU_LOG2_VAR(...) + #define TU_LOG2_INT(...) + #define TU_LOG2_HEX(...) +#endif + +#ifndef TU_LOG3 + #define TU_LOG3(...) + #define TU_LOG3_MEM(...) + #define TU_LOG3_VAR(...) + #define TU_LOG3_INT(...) + #define TU_LOG3_HEX(...) +#endif + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_DEBUG_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.c b/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.c new file mode 100644 index 00000000..895b9208 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.c @@ -0,0 +1,1007 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2020 Reinhard Panhuber - rework to unmasked pointers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "osal/osal.h" +#include "tusb_fifo.h" + +// Supress IAR warning +// Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement +#if defined(__ICCARM__) +#pragma diag_suppress = Pa082 +#endif + +// implement mutex lock and unlock +#if CFG_FIFO_MUTEX + +static inline void _ff_lock(tu_fifo_mutex_t mutex) +{ + if (mutex) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); +} + +static inline void _ff_unlock(tu_fifo_mutex_t mutex) +{ + if (mutex) osal_mutex_unlock(mutex); +} + +#else + +#define _ff_lock(_mutex) +#define _ff_unlock(_mutex) + +#endif + +/** \enum tu_fifo_copy_mode_t + * \brief Write modes intended to allow special read and write functions to be able to + * copy data to and from USB hardware FIFOs as needed for e.g. STM32s and others + */ +typedef enum +{ + TU_FIFO_COPY_INC, ///< Copy from/to an increasing source/destination address - default mode + TU_FIFO_COPY_CST_FULL_WORDS, ///< Copy from/to a constant source/destination address - required for e.g. STM32 to write into USB hardware FIFO +} tu_fifo_copy_mode_t; + +bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable) +{ + if (depth > 0x8000) return false; // Maximum depth is 2^15 items + + _ff_lock(f->mutex_wr); + _ff_lock(f->mutex_rd); + + f->buffer = (uint8_t*) buffer; + f->depth = depth; + f->item_size = item_size; + f->overwritable = overwritable; + + // Limit index space to 2*depth - this allows for a fast "modulo" calculation + // but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable + // only if overflow happens once (important for unsupervised DMA applications) + f->max_pointer_idx = (uint16_t) (2*depth - 1); + f->non_used_index_space = UINT16_MAX - f->max_pointer_idx; + + f->rd_idx = f->wr_idx = 0; + + _ff_unlock(f->mutex_wr); + _ff_unlock(f->mutex_rd); + + return true; +} + +// Static functions are intended to work on local variables +static inline uint16_t _ff_mod(uint16_t idx, uint16_t depth) +{ + while ( idx >= depth) idx -= depth; + return idx; +} + +// Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address +// Code adapted from dcd_synopsis.c +// TODO generalize with configurable 1 byte or 4 byte each read +static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t len) +{ + volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf; + + // Reading full available 32 bit words from const app address + uint16_t full_words = len >> 2; + while(full_words--) + { + tu_unaligned_write32(ff_buf, *rx_fifo); + ff_buf += 4; + } + + // Read the remaining 1-3 bytes from const app address + uint8_t const bytes_rem = len & 0x03; + if ( bytes_rem ) + { + uint32_t tmp32 = *rx_fifo; + memcpy(ff_buf, &tmp32, bytes_rem); + } +} + +// Intended to be used to write to hardware USB FIFO in e.g. STM32 +// where all data is written to a constant address in full word copies +static void _ff_pull_const_addr(void * app_buf, const uint8_t * ff_buf, uint16_t len) +{ + volatile uint32_t * tx_fifo = (volatile uint32_t *) app_buf; + + // Pushing full available 32 bit words to const app address + uint16_t full_words = len >> 2; + while(full_words--) + { + *tx_fifo = tu_unaligned_read32(ff_buf); + ff_buf += 4; + } + + // Write the remaining 1-3 bytes into const app address + uint8_t const bytes_rem = len & 0x03; + if ( bytes_rem ) + { + uint32_t tmp32 = 0; + memcpy(&tmp32, ff_buf, bytes_rem); + + *tx_fifo = tmp32; + } +} + +// send one item to FIFO WITHOUT updating write pointer +static inline void _ff_push(tu_fifo_t* f, void const * app_buf, uint16_t rel) +{ + memcpy(f->buffer + (rel * f->item_size), app_buf, f->item_size); +} + +// send n items to FIFO WITHOUT updating write pointer +static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode) +{ + uint16_t const nLin = f->depth - rel; + uint16_t const nWrap = n - nLin; + + uint16_t nLin_bytes = nLin * f->item_size; + uint16_t nWrap_bytes = nWrap * f->item_size; + + // current buffer of fifo + uint8_t* ff_buf = f->buffer + (rel * f->item_size); + + switch (copy_mode) + { + case TU_FIFO_COPY_INC: + if(n <= nLin) + { + // Linear only + memcpy(ff_buf, app_buf, n*f->item_size); + } + else + { + // Wrap around + + // Write data to linear part of buffer + memcpy(ff_buf, app_buf, nLin_bytes); + + // Write data wrapped around + memcpy(f->buffer, ((uint8_t const*) app_buf) + nLin_bytes, nWrap_bytes); + } + break; + + case TU_FIFO_COPY_CST_FULL_WORDS: + // Intended for hardware buffers from which it can be read word by word only + if(n <= nLin) + { + // Linear only + _ff_push_const_addr(ff_buf, app_buf, n*f->item_size); + } + else + { + // Wrap around case + + // Write full words to linear part of buffer + uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC; + _ff_push_const_addr(ff_buf, app_buf, nLin_4n_bytes); + ff_buf += nLin_4n_bytes; + + // There could be odd 1-3 bytes before the wrap-around boundary + volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf; + uint8_t rem = nLin_bytes & 0x03; + if (rem > 0) + { + uint8_t remrem = (uint8_t) tu_min16(nWrap_bytes, 4-rem); + nWrap_bytes -= remrem; + + uint32_t tmp32 = *rx_fifo; + uint8_t * src_u8 = ((uint8_t *) &tmp32); + + // Write 1-3 bytes before wrapped boundary + while(rem--) *ff_buf++ = *src_u8++; + + // Read more bytes to beginning to complete a word + ff_buf = f->buffer; + while(remrem--) *ff_buf++ = *src_u8++; + } + else + { + ff_buf = f->buffer; // wrap around to beginning + } + + // Write data wrapped part + if (nWrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, nWrap_bytes); + } + break; + } +} + +// get one item from FIFO WITHOUT updating read pointer +static inline void _ff_pull(tu_fifo_t* f, void * app_buf, uint16_t rel) +{ + memcpy(app_buf, f->buffer + (rel * f->item_size), f->item_size); +} + +// get n items from FIFO WITHOUT updating read pointer +static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode) +{ + uint16_t const nLin = f->depth - rel; + uint16_t const nWrap = n - nLin; // only used if wrapped + + uint16_t nLin_bytes = nLin * f->item_size; + uint16_t nWrap_bytes = nWrap * f->item_size; + + // current buffer of fifo + uint8_t* ff_buf = f->buffer + (rel * f->item_size); + + switch (copy_mode) + { + case TU_FIFO_COPY_INC: + if ( n <= nLin ) + { + // Linear only + memcpy(app_buf, ff_buf, n*f->item_size); + } + else + { + // Wrap around + + // Read data from linear part of buffer + memcpy(app_buf, ff_buf, nLin_bytes); + + // Read data wrapped part + memcpy((uint8_t*) app_buf + nLin_bytes, f->buffer, nWrap_bytes); + } + break; + + case TU_FIFO_COPY_CST_FULL_WORDS: + if ( n <= nLin ) + { + // Linear only + _ff_pull_const_addr(app_buf, ff_buf, n*f->item_size); + } + else + { + // Wrap around case + + // Read full words from linear part of buffer + uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC; + _ff_pull_const_addr(app_buf, ff_buf, nLin_4n_bytes); + ff_buf += nLin_4n_bytes; + + // There could be odd 1-3 bytes before the wrap-around boundary + volatile uint32_t * tx_fifo = (volatile uint32_t *) app_buf; + uint8_t rem = nLin_bytes & 0x03; + if (rem > 0) + { + uint8_t remrem = (uint8_t) tu_min16(nWrap_bytes, 4-rem); + nWrap_bytes -= remrem; + + uint32_t tmp32=0; + uint8_t * dst_u8 = (uint8_t *)&tmp32; + + // Read 1-3 bytes before wrapped boundary + while(rem--) *dst_u8++ = *ff_buf++; + + // Read more bytes from beginning to complete a word + ff_buf = f->buffer; + while(remrem--) *dst_u8++ = *ff_buf++; + + *tx_fifo = tmp32; + } + else + { + ff_buf = f->buffer; // wrap around to beginning + } + + // Read data wrapped part + if (nWrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, nWrap_bytes); + } + break; + + default: break; + } +} + +// Advance an absolute pointer +static uint16_t advance_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) +{ + // We limit the index space of p such that a correct wrap around happens + // Check for a wrap around or if we are in unused index space - This has to be checked first!! + // We are exploiting the wrap around to the correct index + if ((p > (uint16_t)(p + offset)) || ((uint16_t)(p + offset) > f->max_pointer_idx)) + { + p = (uint16_t) ((p + offset) + f->non_used_index_space); + } + else + { + p += offset; + } + return p; +} + +// Backward an absolute pointer +static uint16_t backward_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) +{ + // We limit the index space of p such that a correct wrap around happens + // Check for a wrap around or if we are in unused index space - This has to be checked first!! + // We are exploiting the wrap around to the correct index + if ((p < (uint16_t)(p - offset)) || ((uint16_t)(p - offset) > f->max_pointer_idx)) + { + p = (uint16_t) ((p - offset) - f->non_used_index_space); + } + else + { + p -= offset; + } + return p; +} + +// get relative from absolute pointer +static uint16_t get_relative_pointer(tu_fifo_t* f, uint16_t p) +{ + return _ff_mod(p, f->depth); +} + +// Works on local copies of w and r - return only the difference and as such can be used to determine an overflow +static inline uint16_t _tu_fifo_count(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) +{ + uint16_t cnt = wAbs-rAbs; + + // In case we have non-power of two depth we need a further modification + if (rAbs > wAbs) cnt -= f->non_used_index_space; + + return cnt; +} + +// Works on local copies of w and r +static inline bool _tu_fifo_empty(uint16_t wAbs, uint16_t rAbs) +{ + return wAbs == rAbs; +} + +// Works on local copies of w and r +static inline bool _tu_fifo_full(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) +{ + return (_tu_fifo_count(f, wAbs, rAbs) == f->depth); +} + +// Works on local copies of w and r +// BE AWARE - THIS FUNCTION MIGHT NOT GIVE A CORRECT ANSWERE IN CASE WRITE POINTER "OVERFLOWS" +// Only one overflow is allowed for this function to work e.g. if depth = 100, you must not +// write more than 2*depth-1 items in one rush without updating write pointer. Otherwise +// write pointer wraps and you pointer states are messed up. This can only happen if you +// use DMAs, write functions do not allow such an error. +static inline bool _tu_fifo_overflowed(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) +{ + return (_tu_fifo_count(f, wAbs, rAbs) > f->depth); +} + +// Works on local copies of w +// For more details see _tu_fifo_overflow()! +static inline void _tu_fifo_correct_read_pointer(tu_fifo_t* f, uint16_t wAbs) +{ + f->rd_idx = backward_pointer(f, wAbs, f->depth); +} + +// Works on local copies of w and r +// Must be protected by mutexes since in case of an overflow read pointer gets modified +static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wAbs, uint16_t rAbs) +{ + uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs); + + // Check overflow and correct if required + if (cnt > f->depth) + { + _tu_fifo_correct_read_pointer(f, wAbs); + cnt = f->depth; + } + + // Skip beginning of buffer + if (cnt == 0) return false; + + uint16_t rRel = get_relative_pointer(f, rAbs); + + // Peek data + _ff_pull(f, p_buffer, rRel); + + return true; +} + +// Works on local copies of w and r +// Must be protected by mutexes since in case of an overflow read pointer gets modified +static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t wAbs, uint16_t rAbs, tu_fifo_copy_mode_t copy_mode) +{ + uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs); + + // Check overflow and correct if required + if (cnt > f->depth) + { + _tu_fifo_correct_read_pointer(f, wAbs); + rAbs = f->rd_idx; + cnt = f->depth; + } + + // Skip beginning of buffer + if (cnt == 0) return 0; + + // Check if we can read something at and after offset - if too less is available we read what remains + if (cnt < n) n = cnt; + + uint16_t rRel = get_relative_pointer(f, rAbs); + + // Peek data + _ff_pull_n(f, p_buffer, n, rRel, copy_mode); + + return n; +} + +// Works on local copies of w and r +static inline uint16_t _tu_fifo_remaining(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) +{ + return f->depth - _tu_fifo_count(f, wAbs, rAbs); +} + +static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu_fifo_copy_mode_t copy_mode) +{ + if ( n == 0 ) return 0; + + _ff_lock(f->mutex_wr); + + uint16_t w = f->wr_idx, r = f->rd_idx; + uint8_t const* buf8 = (uint8_t const*) data; + + if (!f->overwritable) + { + // Not overwritable limit up to full + n = tu_min16(n, _tu_fifo_remaining(f, w, r)); + } + else if (n >= f->depth) + { + // Only copy last part + buf8 = buf8 + (n - f->depth) * f->item_size; + n = f->depth; + + // We start writing at the read pointer's position since we fill the complete + // buffer and we do not want to modify the read pointer within a write function! + // This would end up in a race condition with read functions! + w = r; + } + + uint16_t wRel = get_relative_pointer(f, w); + + // Write data + _ff_push_n(f, buf8, n, wRel, copy_mode); + + // Advance pointer + f->wr_idx = advance_pointer(f, w, n); + + _ff_unlock(f->mutex_wr); + + return n; +} + +static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo_copy_mode_t copy_mode) +{ + _ff_lock(f->mutex_rd); + + // Peek the data + // f->rd_idx might get modified in case of an overflow so we can not use a local variable + n = _tu_fifo_peek_n(f, buffer, n, f->wr_idx, f->rd_idx, copy_mode); + + // Advance read pointer + f->rd_idx = advance_pointer(f, f->rd_idx, n); + + _ff_unlock(f->mutex_rd); + return n; +} + +/******************************************************************************/ +/*! + @brief Get number of items in FIFO. + + As this function only reads the read and write pointers once, this function is + reentrant and thus thread and ISR save without any mutexes. In case an + overflow occurred, this function return f.depth at maximum. Overflows are + checked and corrected for in the read functions! + + @param[in] f + Pointer to the FIFO buffer to manipulate + + @returns Number of items in FIFO + */ +/******************************************************************************/ +uint16_t tu_fifo_count(tu_fifo_t* f) +{ + return tu_min16(_tu_fifo_count(f, f->wr_idx, f->rd_idx), f->depth); +} + +/******************************************************************************/ +/*! + @brief Check if FIFO is empty. + + As this function only reads the read and write pointers once, this function is + reentrant and thus thread and ISR save without any mutexes. + + @param[in] f + Pointer to the FIFO buffer to manipulate + + @returns Number of items in FIFO + */ +/******************************************************************************/ +bool tu_fifo_empty(tu_fifo_t* f) +{ + return _tu_fifo_empty(f->wr_idx, f->rd_idx); +} + +/******************************************************************************/ +/*! + @brief Check if FIFO is full. + + As this function only reads the read and write pointers once, this function is + reentrant and thus thread and ISR save without any mutexes. + + @param[in] f + Pointer to the FIFO buffer to manipulate + + @returns Number of items in FIFO + */ +/******************************************************************************/ +bool tu_fifo_full(tu_fifo_t* f) +{ + return _tu_fifo_full(f, f->wr_idx, f->rd_idx); +} + +/******************************************************************************/ +/*! + @brief Get remaining space in FIFO. + + As this function only reads the read and write pointers once, this function is + reentrant and thus thread and ISR save without any mutexes. + + @param[in] f + Pointer to the FIFO buffer to manipulate + + @returns Number of items in FIFO + */ +/******************************************************************************/ +uint16_t tu_fifo_remaining(tu_fifo_t* f) +{ + return _tu_fifo_remaining(f, f->wr_idx, f->rd_idx); +} + +/******************************************************************************/ +/*! + @brief Check if overflow happened. + + BE AWARE - THIS FUNCTION MIGHT NOT GIVE A CORRECT ANSWERE IN CASE WRITE POINTER "OVERFLOWS" + Only one overflow is allowed for this function to work e.g. if depth = 100, you must not + write more than 2*depth-1 items in one rush without updating write pointer. Otherwise + write pointer wraps and your pointer states are messed up. This can only happen if you + use DMAs, write functions do not allow such an error. Avoid such nasty things! + + All reading functions (read, peek) check for overflows and correct read pointer on their own such + that latest items are read. + If required (e.g. for DMA use) you can also correct the read pointer by + tu_fifo_correct_read_pointer(). + + @param[in] f + Pointer to the FIFO buffer to manipulate + + @returns True if overflow happened + */ +/******************************************************************************/ +bool tu_fifo_overflowed(tu_fifo_t* f) +{ + return _tu_fifo_overflowed(f, f->wr_idx, f->rd_idx); +} + +// Only use in case tu_fifo_overflow() returned true! +void tu_fifo_correct_read_pointer(tu_fifo_t* f) +{ + _ff_lock(f->mutex_rd); + _tu_fifo_correct_read_pointer(f, f->wr_idx); + _ff_unlock(f->mutex_rd); +} + +/******************************************************************************/ +/*! + @brief Read one element out of the buffer. + + This function will return the element located at the array index of the + read pointer, and then increment the read pointer index. + This function checks for an overflow and corrects read pointer if required. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] buffer + Pointer to the place holder for data read from the buffer + + @returns TRUE if the queue is not empty + */ +/******************************************************************************/ +bool tu_fifo_read(tu_fifo_t* f, void * buffer) +{ + _ff_lock(f->mutex_rd); + + // Peek the data + // f->rd_idx might get modified in case of an overflow so we can not use a local variable + bool ret = _tu_fifo_peek(f, buffer, f->wr_idx, f->rd_idx); + + // Advance pointer + f->rd_idx = advance_pointer(f, f->rd_idx, ret); + + _ff_unlock(f->mutex_rd); + return ret; +} + +/******************************************************************************/ +/*! + @brief This function will read n elements from the array index specified by + the read pointer and increment the read index. + This function checks for an overflow and corrects read pointer if required. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] buffer + The pointer to data location + @param[in] n + Number of element that buffer can afford + + @returns number of items read from the FIFO + */ +/******************************************************************************/ +uint16_t tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n) +{ + return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_INC); +} + +uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t* f, void * buffer, uint16_t n) +{ + return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_CST_FULL_WORDS); +} + +/******************************************************************************/ +/*! + @brief Read one item without removing it from the FIFO. + This function checks for an overflow and corrects read pointer if required. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] offset + Position to read from in the FIFO buffer with respect to read pointer + @param[in] p_buffer + Pointer to the place holder for data read from the buffer + + @returns TRUE if the queue is not empty + */ +/******************************************************************************/ +bool tu_fifo_peek(tu_fifo_t* f, void * p_buffer) +{ + _ff_lock(f->mutex_rd); + bool ret = _tu_fifo_peek(f, p_buffer, f->wr_idx, f->rd_idx); + _ff_unlock(f->mutex_rd); + return ret; +} + +/******************************************************************************/ +/*! + @brief Read n items without removing it from the FIFO + This function checks for an overflow and corrects read pointer if required. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] p_buffer + Pointer to the place holder for data read from the buffer + @param[in] n + Number of items to peek + + @returns Number of bytes written to p_buffer + */ +/******************************************************************************/ +uint16_t tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n) +{ + _ff_lock(f->mutex_rd); + uint16_t ret = _tu_fifo_peek_n(f, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_COPY_INC); + _ff_unlock(f->mutex_rd); + return ret; +} + +/******************************************************************************/ +/*! + @brief Write one element into the buffer. + + This function will write one element into the array index specified by + the write pointer and increment the write index. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] data + The byte to add to the FIFO + + @returns TRUE if the data was written to the FIFO (overwrittable + FIFO will always return TRUE) + */ +/******************************************************************************/ +bool tu_fifo_write(tu_fifo_t* f, const void * data) +{ + _ff_lock(f->mutex_wr); + + bool ret; + uint16_t const w = f->wr_idx; + + if ( _tu_fifo_full(f, w, f->rd_idx) && !f->overwritable ) + { + ret = false; + }else + { + uint16_t wRel = get_relative_pointer(f, w); + + // Write data + _ff_push(f, data, wRel); + + // Advance pointer + f->wr_idx = advance_pointer(f, w, 1); + + ret = true; + } + + _ff_unlock(f->mutex_wr); + + return ret; +} + +/******************************************************************************/ +/*! + @brief This function will write n elements into the array index specified by + the write pointer and increment the write index. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] data + The pointer to data to add to the FIFO + @param[in] count + Number of element + @return Number of written elements + */ +/******************************************************************************/ +uint16_t tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n) +{ + return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_INC); +} + +/******************************************************************************/ +/*! + @brief This function will write n elements into the array index specified by + the write pointer and increment the write index. The source address will + not be incremented which is useful for reading from registers. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] data + The pointer to data to add to the FIFO + @param[in] count + Number of element + @return Number of written elements + */ +/******************************************************************************/ +uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t* f, const void * data, uint16_t n) +{ + return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_CST_FULL_WORDS); +} + +/******************************************************************************/ +/*! + @brief Clear the fifo read and write pointers + + @param[in] f + Pointer to the FIFO buffer to manipulate + */ +/******************************************************************************/ +bool tu_fifo_clear(tu_fifo_t *f) +{ + _ff_lock(f->mutex_wr); + _ff_lock(f->mutex_rd); + + f->rd_idx = f->wr_idx = 0; + f->max_pointer_idx = (uint16_t) (2*f->depth-1); + f->non_used_index_space = UINT16_MAX - f->max_pointer_idx; + + _ff_unlock(f->mutex_wr); + _ff_unlock(f->mutex_rd); + return true; +} + +/******************************************************************************/ +/*! + @brief Change the fifo mode to overwritable or not overwritable + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] overwritable + Overwritable mode the fifo is set to + */ +/******************************************************************************/ +bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) +{ + _ff_lock(f->mutex_wr); + _ff_lock(f->mutex_rd); + + f->overwritable = overwritable; + + _ff_unlock(f->mutex_wr); + _ff_unlock(f->mutex_rd); + + return true; +} + +/******************************************************************************/ +/*! + @brief Advance write pointer - intended to be used in combination with DMA. + It is possible to fill the FIFO by use of a DMA in circular mode. Within + DMA ISRs you may update the write pointer to be able to read from the FIFO. + As long as the DMA is the only process writing into the FIFO this is safe + to use. + + USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE! + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] n + Number of items the write pointer moves forward + */ +/******************************************************************************/ +void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n) +{ + f->wr_idx = advance_pointer(f, f->wr_idx, n); +} + +/******************************************************************************/ +/*! + @brief Advance read pointer - intended to be used in combination with DMA. + It is possible to read from the FIFO by use of a DMA in linear mode. Within + DMA ISRs you may update the read pointer to be able to again write into the + FIFO. As long as the DMA is the only process reading from the FIFO this is + safe to use. + + USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE! + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] n + Number of items the read pointer moves forward + */ +/******************************************************************************/ +void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n) +{ + f->rd_idx = advance_pointer(f, f->rd_idx, n); +} + +/******************************************************************************/ +/*! + @brief Get read info + + Returns the length and pointer from which bytes can be read in a linear manner. + This is of major interest for DMA transmissions. If returned length is zero the + corresponding pointer is invalid. + The read pointer does NOT get advanced, use tu_fifo_advance_read_pointer() to + do so! + @param[in] f + Pointer to FIFO + @param[out] *info + Pointer to struct which holds the desired infos + */ +/******************************************************************************/ +void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) +{ + // Operate on temporary values in case they change in between + uint16_t w = f->wr_idx, r = f->rd_idx; + + uint16_t cnt = _tu_fifo_count(f, w, r); + + // Check overflow and correct if required - may happen in case a DMA wrote too fast + if (cnt > f->depth) + { + _ff_lock(f->mutex_rd); + _tu_fifo_correct_read_pointer(f, w); + _ff_unlock(f->mutex_rd); + r = f->rd_idx; + cnt = f->depth; + } + + // Check if fifo is empty + if (cnt == 0) + { + info->len_lin = 0; + info->len_wrap = 0; + info->ptr_lin = NULL; + info->ptr_wrap = NULL; + return; + } + + // Get relative pointers + w = get_relative_pointer(f, w); + r = get_relative_pointer(f, r); + + // Copy pointer to buffer to start reading from + info->ptr_lin = &f->buffer[r]; + + // Check if there is a wrap around necessary + if (w > r) { + // Non wrapping case + info->len_lin = cnt; + info->len_wrap = 0; + info->ptr_wrap = NULL; + } + else + { + info->len_lin = f->depth - r; // Also the case if FIFO was full + info->len_wrap = cnt - info->len_lin; + info->ptr_wrap = f->buffer; + } +} + +/******************************************************************************/ +/*! + @brief Get linear write info + + Returns the length and pointer to which bytes can be written into FIFO in a linear manner. + This is of major interest for DMA transmissions not using circular mode. If a returned length is zero the + corresponding pointer is invalid. The returned lengths summed up are the currently free space in the FIFO. + The write pointer does NOT get advanced, use tu_fifo_advance_write_pointer() to do so! + TAKE CARE TO NOT OVERFLOW THE BUFFER MORE THAN TWO TIMES THE FIFO DEPTH - IT CAN NOT RECOVERE OTHERWISE! + @param[in] f + Pointer to FIFO + @param[out] *info + Pointer to struct which holds the desired infos + */ +/******************************************************************************/ +void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) +{ + uint16_t w = f->wr_idx, r = f->rd_idx; + uint16_t free = _tu_fifo_remaining(f, w, r); + + if (free == 0) + { + info->len_lin = 0; + info->len_wrap = 0; + info->ptr_lin = NULL; + info->ptr_wrap = NULL; + return; + } + + // Get relative pointers + w = get_relative_pointer(f, w); + r = get_relative_pointer(f, r); + + // Copy pointer to buffer to start writing to + info->ptr_lin = &f->buffer[w]; + + if (w < r) + { + // Non wrapping case + info->len_lin = r-w; + info->len_wrap = 0; + info->ptr_wrap = NULL; + } + else + { + info->len_lin = f->depth - w; + info->len_wrap = free - info->len_lin; // Remaining length - n already was limited to free or FIFO depth + info->ptr_wrap = f->buffer; // Always start of buffer + } +} diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.h new file mode 100644 index 00000000..18db289a --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.h @@ -0,0 +1,151 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2020 Reinhard Panhuber - rework to unmasked pointers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_FIFO_H_ +#define _TUSB_FIFO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// Due to the use of unmasked pointers, this FIFO does not suffer from loosing +// one item slice. Furthermore, write and read operations are completely +// decoupled as write and read functions do not modify a common state. Henceforth, +// writing or reading from the FIFO within an ISR is safe as long as no other +// process (thread or ISR) interferes. +// Also, this FIFO is ready to be used in combination with a DMA as the write and +// read pointers can be updated from within a DMA ISR. Overflows are detectable +// within a certain number (see tu_fifo_overflow()). + +#include "common/tusb_common.h" + +// mutex is only needed for RTOS +// for OS None, we don't get preempted +#define CFG_FIFO_MUTEX (CFG_TUSB_OS != OPT_OS_NONE) + +#if CFG_FIFO_MUTEX +#include "osal/osal.h" +#define tu_fifo_mutex_t osal_mutex_t +#endif + +typedef struct +{ + uint8_t* buffer ; ///< buffer pointer + uint16_t depth ; ///< max items + uint16_t item_size ; ///< size of each item + bool overwritable ; + + uint16_t non_used_index_space ; ///< required for non-power-of-two buffer length + uint16_t max_pointer_idx ; ///< maximum absolute pointer index + + volatile uint16_t wr_idx ; ///< write pointer + volatile uint16_t rd_idx ; ///< read pointer + +#if CFG_FIFO_MUTEX + tu_fifo_mutex_t mutex_wr; + tu_fifo_mutex_t mutex_rd; +#endif + +} tu_fifo_t; + +typedef struct +{ + uint16_t len_lin ; ///< linear length in item size + uint16_t len_wrap ; ///< wrapped length in item size + void * ptr_lin ; ///< linear part start pointer + void * ptr_wrap ; ///< wrapped part start pointer +} tu_fifo_buffer_info_t; + +#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable) \ +{ \ + .buffer = _buffer, \ + .depth = _depth, \ + .item_size = sizeof(_type), \ + .overwritable = _overwritable, \ + .non_used_index_space = UINT16_MAX - (2*(_depth)-1), \ + .max_pointer_idx = 2*(_depth)-1, \ +} + +#define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \ + uint8_t _name##_buf[_depth*sizeof(_type)]; \ + tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _type, _overwritable) + + +bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable); +bool tu_fifo_clear(tu_fifo_t *f); +bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable); + +#if CFG_FIFO_MUTEX +TU_ATTR_ALWAYS_INLINE static inline +void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t write_mutex_hdl, tu_fifo_mutex_t read_mutex_hdl) +{ + f->mutex_wr = write_mutex_hdl; + f->mutex_rd = read_mutex_hdl; +} +#endif + +bool tu_fifo_write (tu_fifo_t* f, void const * p_data); +uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * p_data, uint16_t n); +uint16_t tu_fifo_write_n_const_addr_full_words (tu_fifo_t* f, const void * data, uint16_t n); + +bool tu_fifo_read (tu_fifo_t* f, void * p_buffer); +uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t n); +uint16_t tu_fifo_read_n_const_addr_full_words (tu_fifo_t* f, void * buffer, uint16_t n); + +bool tu_fifo_peek (tu_fifo_t* f, void * p_buffer); +uint16_t tu_fifo_peek_n (tu_fifo_t* f, void * p_buffer, uint16_t n); + +uint16_t tu_fifo_count (tu_fifo_t* f); +uint16_t tu_fifo_remaining (tu_fifo_t* f); +bool tu_fifo_empty (tu_fifo_t* f); +bool tu_fifo_full (tu_fifo_t* f); +bool tu_fifo_overflowed (tu_fifo_t* f); +void tu_fifo_correct_read_pointer (tu_fifo_t* f); + +TU_ATTR_ALWAYS_INLINE static inline +uint16_t tu_fifo_depth(tu_fifo_t* f) +{ + return f->depth; +} + +// Pointer modifications intended to be used in combinations with DMAs. +// USE WITH CARE - NO SAFTY CHECKS CONDUCTED HERE! NOT MUTEX PROTECTED! +void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n); +void tu_fifo_advance_read_pointer (tu_fifo_t *f, uint16_t n); + +// If you want to read/write from/to the FIFO by use of a DMA, you may need to conduct two copies +// to handle a possible wrapping part. These functions deliver a pointer to start +// reading/writing from/to and a valid linear length along which no wrap occurs. +void tu_fifo_get_read_info (tu_fifo_t *f, tu_fifo_buffer_info_t *info); +void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info); + + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_FIFO_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_mcu.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_mcu.h new file mode 100644 index 00000000..baa82fc1 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_mcu.h @@ -0,0 +1,289 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef TUSB_MCU_H_ +#define TUSB_MCU_H_ + +//--------------------------------------------------------------------+ +// Port Specific +// TUP stand for TinyUSB Port (can be renamed) +//--------------------------------------------------------------------+ + +//------------- Unaligned Memory Access -------------// + +// ARMv7+ (M3-M7, M23-M33) can access unaligned memory +#if (defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) + #define TUP_ARCH_STRICT_ALIGN 0 +#else + #define TUP_ARCH_STRICT_ALIGN 1 +#endif + +/* USB Controller Attributes for Device, Host or MCU (both) + * - ENDPOINT_MAX: max (logical) number of endpoint + * - ENDPOINT_EXCLUSIVE_NUMBER: endpoint number with different direction IN and OUT aren't allowed, + * e.g EP1 OUT & EP1 IN cannot exist together + * - RHPORT_HIGHSPEED: support highspeed with on-chip PHY + */ + +//------------- NXP -------------// +#if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX) + #define TUP_DCD_ENDPOINT_MAX 5 + +#elif TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX) + #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_USBIP_OHCI + +#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX) + // TODO USB0 has 6, USB1 has 4 + #define TUP_USBIP_CHIPIDEA_HS + #define TUP_USBIP_EHCI + + #define TUP_DCD_ENDPOINT_MAX 6 + #define TUP_RHPORT_HIGHSPEED 1 // Port0 HS, Port1 FS + +#elif TU_CHECK_MCU(OPT_MCU_LPC51UXX) + #define TUP_DCD_ENDPOINT_MAX 5 + +#elif TU_CHECK_MCU(OPT_MCU_LPC54XXX) + // TODO USB0 has 5, USB1 has 6 + #define TUP_DCD_ENDPOINT_MAX 6 + +#elif TU_CHECK_MCU(OPT_MCU_LPC55XX) + // TODO USB0 has 5, USB1 has 6 + #define TUP_DCD_ENDPOINT_MAX 6 + +#elif TU_CHECK_MCU(OPT_MCU_MIMXRT) + #define TUP_USBIP_CHIPIDEA_HS + #define TUP_USBIP_EHCI + + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_RHPORT_HIGHSPEED 1 // Port0 HS, Port1 HS + +#elif TU_CHECK_MCU(OPT_MCU_MKL25ZXX, OPT_MCU_K32L2BXX) + #define TUP_DCD_ENDPOINT_MAX 16 + +#elif TU_CHECK_MCU(OPT_MCU_MM32F327X) + #define TUP_DCD_ENDPOINT_MAX 16 + +//------------- Nordic -------------// +#elif TU_CHECK_MCU(OPT_MCU_NRF5X) + // 8 CBI + 1 ISO + #define TUP_DCD_ENDPOINT_MAX 9 + +//------------- Microchip -------------// +#elif TU_CHECK_MCU(OPT_MCU_SAMD21, OPT_MCU_SAMD51, OPT_MCU_SAME5X) || \ + TU_CHECK_MCU(OPT_MCU_SAMD11, OPT_MCU_SAML21, OPT_MCU_SAML22) + #define TUP_DCD_ENDPOINT_MAX 8 + +#elif TU_CHECK_MCU(OPT_MCU_SAMG) + #define TUP_DCD_ENDPOINT_MAX 6 + #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + +#elif TU_CHECK_MCU(OPT_MCU_SAMX7X) + #define TUP_DCD_ENDPOINT_MAX 10 + #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + +#elif TU_CHECK_MCU(OPT_MCU_PIC32MZ) + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + +//------------- ST -------------// +#elif TU_CHECK_MCU(OPT_MCU_STM32F0) + #define TUP_DCD_ENDPOINT_MAX 8 + +#elif TU_CHECK_MCU(OPT_MCU_STM32F1) + #if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \ + defined (STM32F107xB) || defined (STM32F107xC) + #define TUP_USBIP_DWC2 + #define TUP_USBIP_DWC2_STM32 + + #define TUP_DCD_ENDPOINT_MAX 4 + #else + #define TUP_DCD_ENDPOINT_MAX 8 + #endif + +#elif TU_CHECK_MCU(OPT_MCU_STM32F2) + #define TUP_USBIP_DWC2 + #define TUP_USBIP_DWC2_STM32 + + // FS has 4 ep, HS has 5 ep + #define TUP_DCD_ENDPOINT_MAX 6 + +#elif TU_CHECK_MCU(OPT_MCU_STM32F3) + #define TUP_DCD_ENDPOINT_MAX 8 + +#elif TU_CHECK_MCU(OPT_MCU_STM32F4) + #define TUP_USBIP_DWC2 + #define TUP_USBIP_DWC2_STM32 + + // For most mcu, FS has 4, HS has 6. TODO 446/469/479 HS has 9 + #define TUP_DCD_ENDPOINT_MAX 6 + +#elif TU_CHECK_MCU(OPT_MCU_STM32F7) + #define TUP_USBIP_DWC2 + #define TUP_USBIP_DWC2_STM32 + + // FS has 6, HS has 9 + #define TUP_DCD_ENDPOINT_MAX 9 + + // MCU with on-chip HS Phy + #if defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F733xx) + #define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS + #endif + +#elif TU_CHECK_MCU(OPT_MCU_STM32H7) + #define TUP_USBIP_DWC2 + #define TUP_USBIP_DWC2_STM32 + + #define TUP_DCD_ENDPOINT_MAX 9 + +#elif TU_CHECK_MCU(OPT_MCU_STM32G4) + #define TUP_DCD_ENDPOINT_MAX 8 + +#elif TU_CHECK_MCU(OPT_MCU_STM32L0, OPT_MCU_STM32L1) + #define TUP_DCD_ENDPOINT_MAX 8 + +#elif TU_CHECK_MCU(OPT_MCU_STM32L4) + #if defined (STM32L475xx) || defined (STM32L476xx) || \ + defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \ + defined (STM32L4A6xx) || defined (STM32L4P5xx) || defined (STM32L4Q5xx) || \ + defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || \ + defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx) + #define TUP_USBIP_DWC2 + #define TUP_USBIP_DWC2_STM32 + + #define TUP_DCD_ENDPOINT_MAX 6 + #else + #define TUP_DCD_ENDPOINT_MAX 8 + #endif + +#elif TU_CHECK_MCU(OPT_MCU_STM32WB) + #define TUP_DCD_ENDPOINT_MAX 8 + +//------------- Sony -------------// +#elif TU_CHECK_MCU(OPT_MCU_CXD56) + #define TUP_DCD_ENDPOINT_MAX 7 + #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + +//------------- TI -------------// +#elif TU_CHECK_MCU(OPT_MCU_MSP430x5xx) + #define TUP_DCD_ENDPOINT_MAX 8 + +#elif TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129) + #define TUP_DCD_ENDPOINT_MAX 8 + +//------------- ValentyUSB -------------// +#elif TU_CHECK_MCU(OPT_MCU_VALENTYUSB_EPTRI) + #define TUP_DCD_ENDPOINT_MAX 16 + +//------------- Nuvoton -------------// +#elif TU_CHECK_MCU(OPT_MCU_NUC121, OPT_MCU_NUC126) + #define TUP_DCD_ENDPOINT_MAX 8 + +#elif TU_CHECK_MCU(OPT_MCU_NUC120) + #define TUP_DCD_ENDPOINT_MAX 6 + +#elif TU_CHECK_MCU(OPT_MCU_NUC505) + #define TUP_DCD_ENDPOINT_MAX 12 + #define TUP_RHPORT_HIGHSPEED 1 + +//------------- Espressif -------------// +#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + #define TUP_USBIP_DWC2 + #define TUP_DCD_ENDPOINT_MAX 6 + +//------------- Dialog -------------// +#elif TU_CHECK_MCU(OPT_MCU_DA1469X) + #define TUP_DCD_ENDPOINT_MAX 4 + +//------------- Raspberry Pi -------------// +#elif TU_CHECK_MCU(OPT_MCU_RP2040) + #define TUP_DCD_ENDPOINT_MAX 16 + + #define TU_ATTR_FAST_FUNC __attribute__((section(".time_critical.tinyusb"))) + +//------------- Silabs -------------// +#elif TU_CHECK_MCU(OPT_MCU_EFM32GG) + #define TUP_USBIP_DWC2 + #define TUP_DCD_ENDPOINT_MAX 7 + +//------------- Renesas -------------// +#elif TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N) + #define TUP_DCD_ENDPOINT_MAX 10 + +//------------- GigaDevice -------------// +#elif TU_CHECK_MCU(OPT_MCU_GD32VF103) + #define TUP_USBIP_DWC2 + #define TUP_DCD_ENDPOINT_MAX 4 + +//------------- Broadcom -------------// +#elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837) + #define TUP_USBIP_DWC2 + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_RHPORT_HIGHSPEED 1 + +//------------- Broadcom -------------// +#elif TU_CHECK_MCU(OPT_MCU_XMC4000) + #define TUP_USBIP_DWC2 + #define TUP_DCD_ENDPOINT_MAX 8 + +//------------- BridgeTek -------------// +#elif TU_CHECK_MCU(OPT_MCU_FT90X) + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_RHPORT_HIGHSPEED 1 + +#elif TU_CHECK_MCU(OPT_MCU_FT93X) + #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_RHPORT_HIGHSPEED 1 + +//------------ Allwinner -------------// +#elif TU_CHECK_MCU(OPT_MCU_F1C100S) + #define TUP_DCD_ENDPOINT_MAX 4 + +#endif + +//--------------------------------------------------------------------+ +// Default Values +//--------------------------------------------------------------------+ + +#ifndef TUP_DCD_ENDPOINT_MAX + #warning "TUP_DCD_ENDPOINT_MAX is not defined for this MCU, default to 8" + #define TUP_DCD_ENDPOINT_MAX 8 +#endif + +// Default to fullspeed if not defined +#ifndef TUP_RHPORT_HIGHSPEED + #define TUP_RHPORT_HIGHSPEED 0 +#endif + +// fast function, normally mean placing function in SRAM +#ifndef TU_ATTR_FAST_FUNC + #define TU_ATTR_FAST_FUNC +#endif + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_private.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_private.h new file mode 100644 index 00000000..b34506f6 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_private.h @@ -0,0 +1,65 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2022, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + + +#ifndef _TUSB_PRIVATE_H_ +#define _TUSB_PRIVATE_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +typedef struct TU_ATTR_PACKED +{ + volatile uint8_t busy : 1; + volatile uint8_t stalled : 1; + volatile uint8_t claimed : 1; +}tu_edpt_state_t; + +//--------------------------------------------------------------------+ +// Internal Helper used by Host and Device Stack +//--------------------------------------------------------------------+ + +// Check if endpoint descriptor is valid per USB specs +bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed); + +// Bind all endpoint of a interface descriptor to class driver +void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* p_desc, uint16_t desc_len, uint8_t driver_id); + +// Calculate total length of n interfaces (depending on IAD) +uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len); + +// Claim an endpoint with provided mutex +bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex); + +// Release an endpoint with provided mutex +bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_PRIVATE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_timeout.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_timeout.h new file mode 100644 index 00000000..ce53955f --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_timeout.h @@ -0,0 +1,80 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup Group_Common Common Files + * \defgroup Group_TimeoutTimer timeout timer + * @{ */ + +#ifndef _TUSB_TIMEOUT_H_ +#define _TUSB_TIMEOUT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uint32_t start; + uint32_t interval; +}tu_timeout_t; + +#if 0 + +extern uint32_t tusb_hal_millis(void); + +static inline void tu_timeout_set(tu_timeout_t* tt, uint32_t msec) +{ + tt->interval = msec; + tt->start = tusb_hal_millis(); +} + +static inline bool tu_timeout_expired(tu_timeout_t* tt) +{ + return ( tusb_hal_millis() - tt->start ) >= tt->interval; +} + +// For used with periodic event to prevent drift +static inline void tu_timeout_reset(tu_timeout_t* tt) +{ + tt->start += tt->interval; +} + +static inline void tu_timeout_restart(tu_timeout_t* tt) +{ + tt->start = tusb_hal_millis(); +} + +#endif + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_TIMEOUT_H_ */ + +/** @} */ diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_types.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_types.h new file mode 100644 index 00000000..1f2a38d4 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_types.h @@ -0,0 +1,541 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup group_usb_definitions + * \defgroup USBDef_Type USB Types + * @{ */ + +#ifndef _TUSB_TYPES_H_ +#define _TUSB_TYPES_H_ + +#include +#include +#include "tusb_compiler.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/*------------------------------------------------------------------*/ +/* CONSTANTS + *------------------------------------------------------------------*/ + +/// defined base on EHCI specs value for Endpoint Speed +typedef enum +{ + TUSB_SPEED_FULL = 0, + TUSB_SPEED_LOW = 1, + TUSB_SPEED_HIGH = 2, + TUSB_SPEED_INVALID = 0xff, +}tusb_speed_t; + +/// defined base on USB Specs Endpoint's bmAttributes +typedef enum +{ + TUSB_XFER_CONTROL = 0 , + TUSB_XFER_ISOCHRONOUS , + TUSB_XFER_BULK , + TUSB_XFER_INTERRUPT +}tusb_xfer_type_t; + +typedef enum +{ + TUSB_DIR_OUT = 0, + TUSB_DIR_IN = 1, + + TUSB_DIR_IN_MASK = 0x80 +}tusb_dir_t; + +/// Isochronous End Point Attributes +typedef enum +{ + TUSB_ISO_EP_ATT_NO_SYNC = 0x00, + TUSB_ISO_EP_ATT_ASYNCHRONOUS = 0x04, + TUSB_ISO_EP_ATT_ADAPTIVE = 0x08, + TUSB_ISO_EP_ATT_SYNCHRONOUS = 0x0C, + TUSB_ISO_EP_ATT_DATA = 0x00, ///< Data End Point + TUSB_ISO_EP_ATT_EXPLICIT_FB = 0x10, ///< Feedback End Point + TUSB_ISO_EP_ATT_IMPLICIT_FB = 0x20, ///< Data endpoint that also serves as an implicit feedback +}tusb_iso_ep_attribute_t; + +/// USB Descriptor Types +typedef enum +{ + TUSB_DESC_DEVICE = 0x01, + TUSB_DESC_CONFIGURATION = 0x02, + TUSB_DESC_STRING = 0x03, + TUSB_DESC_INTERFACE = 0x04, + TUSB_DESC_ENDPOINT = 0x05, + TUSB_DESC_DEVICE_QUALIFIER = 0x06, + TUSB_DESC_OTHER_SPEED_CONFIG = 0x07, + TUSB_DESC_INTERFACE_POWER = 0x08, + TUSB_DESC_OTG = 0x09, + TUSB_DESC_DEBUG = 0x0A, + TUSB_DESC_INTERFACE_ASSOCIATION = 0x0B, + + TUSB_DESC_BOS = 0x0F, + TUSB_DESC_DEVICE_CAPABILITY = 0x10, + + TUSB_DESC_FUNCTIONAL = 0x21, + + // Class Specific Descriptor + TUSB_DESC_CS_DEVICE = 0x21, + TUSB_DESC_CS_CONFIGURATION = 0x22, + TUSB_DESC_CS_STRING = 0x23, + TUSB_DESC_CS_INTERFACE = 0x24, + TUSB_DESC_CS_ENDPOINT = 0x25, + + TUSB_DESC_SUPERSPEED_ENDPOINT_COMPANION = 0x30, + TUSB_DESC_SUPERSPEED_ISO_ENDPOINT_COMPANION = 0x31 +}tusb_desc_type_t; + +typedef enum +{ + TUSB_REQ_GET_STATUS = 0 , + TUSB_REQ_CLEAR_FEATURE = 1 , + TUSB_REQ_RESERVED = 2 , + TUSB_REQ_SET_FEATURE = 3 , + TUSB_REQ_RESERVED2 = 4 , + TUSB_REQ_SET_ADDRESS = 5 , + TUSB_REQ_GET_DESCRIPTOR = 6 , + TUSB_REQ_SET_DESCRIPTOR = 7 , + TUSB_REQ_GET_CONFIGURATION = 8 , + TUSB_REQ_SET_CONFIGURATION = 9 , + TUSB_REQ_GET_INTERFACE = 10 , + TUSB_REQ_SET_INTERFACE = 11 , + TUSB_REQ_SYNCH_FRAME = 12 +}tusb_request_code_t; + +typedef enum +{ + TUSB_REQ_FEATURE_EDPT_HALT = 0, + TUSB_REQ_FEATURE_REMOTE_WAKEUP = 1, + TUSB_REQ_FEATURE_TEST_MODE = 2 +}tusb_request_feature_selector_t; + +typedef enum +{ + TUSB_REQ_TYPE_STANDARD = 0, + TUSB_REQ_TYPE_CLASS, + TUSB_REQ_TYPE_VENDOR, + TUSB_REQ_TYPE_INVALID +} tusb_request_type_t; + +typedef enum +{ + TUSB_REQ_RCPT_DEVICE =0, + TUSB_REQ_RCPT_INTERFACE, + TUSB_REQ_RCPT_ENDPOINT, + TUSB_REQ_RCPT_OTHER +} tusb_request_recipient_t; + +// https://www.usb.org/defined-class-codes +typedef enum +{ + TUSB_CLASS_UNSPECIFIED = 0 , + TUSB_CLASS_AUDIO = 1 , + TUSB_CLASS_CDC = 2 , + TUSB_CLASS_HID = 3 , + TUSB_CLASS_RESERVED_4 = 4 , + TUSB_CLASS_PHYSICAL = 5 , + TUSB_CLASS_IMAGE = 6 , + TUSB_CLASS_PRINTER = 7 , + TUSB_CLASS_MSC = 8 , + TUSB_CLASS_HUB = 9 , + TUSB_CLASS_CDC_DATA = 10 , + TUSB_CLASS_SMART_CARD = 11 , + TUSB_CLASS_RESERVED_12 = 12 , + TUSB_CLASS_CONTENT_SECURITY = 13 , + TUSB_CLASS_VIDEO = 14 , + TUSB_CLASS_PERSONAL_HEALTHCARE = 15 , + TUSB_CLASS_AUDIO_VIDEO = 16 , + + TUSB_CLASS_DIAGNOSTIC = 0xDC , + TUSB_CLASS_WIRELESS_CONTROLLER = 0xE0 , + TUSB_CLASS_MISC = 0xEF , + TUSB_CLASS_APPLICATION_SPECIFIC = 0xFE , + TUSB_CLASS_VENDOR_SPECIFIC = 0xFF +}tusb_class_code_t; + +typedef enum +{ + MISC_SUBCLASS_COMMON = 2 +}misc_subclass_type_t; + +typedef enum +{ + MISC_PROTOCOL_IAD = 1 +}misc_protocol_type_t; + +typedef enum +{ + APP_SUBCLASS_USBTMC = 0x03, + APP_SUBCLASS_DFU_RUNTIME = 0x01 +} app_subclass_type_t; + +typedef enum +{ + DEVICE_CAPABILITY_WIRELESS_USB = 0x01, + DEVICE_CAPABILITY_USB20_EXTENSION = 0x02, + DEVICE_CAPABILITY_SUPERSPEED_USB = 0x03, + DEVICE_CAPABILITY_CONTAINER_id = 0x04, + DEVICE_CAPABILITY_PLATFORM = 0x05, + DEVICE_CAPABILITY_POWER_DELIVERY = 0x06, + DEVICE_CAPABILITY_BATTERY_INFO = 0x07, + DEVICE_CAPABILITY_PD_CONSUMER_PORT = 0x08, + DEVICE_CAPABILITY_PD_PROVIDER_PORT = 0x09, + DEVICE_CAPABILITY_SUPERSPEED_PLUS = 0x0A, + DEVICE_CAPABILITY_PRECESION_TIME_MEASUREMENT = 0x0B, + DEVICE_CAPABILITY_WIRELESS_USB_EXT = 0x0C, + DEVICE_CAPABILITY_BILLBOARD = 0x0D, + DEVICE_CAPABILITY_AUTHENTICATION = 0x0E, + DEVICE_CAPABILITY_BILLBOARD_EX = 0x0F, + DEVICE_CAPABILITY_CONFIGURATION_SUMMARY = 0x10 +}device_capability_type_t; + +enum { + TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = TU_BIT(5), + TUSB_DESC_CONFIG_ATT_SELF_POWERED = TU_BIT(6), +}; + +#define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2) + +typedef enum +{ + XFER_RESULT_SUCCESS, + XFER_RESULT_FAILED, + XFER_RESULT_STALLED, + XFER_RESULT_TIMEOUT, + XFER_RESULT_INVALID +}xfer_result_t; + +enum // TODO remove +{ + DESC_OFFSET_LEN = 0, + DESC_OFFSET_TYPE = 1 +}; + +enum +{ + INTERFACE_INVALID_NUMBER = 0xff +}; + + +typedef enum +{ + MS_OS_20_SET_HEADER_DESCRIPTOR = 0x00, + MS_OS_20_SUBSET_HEADER_CONFIGURATION = 0x01, + MS_OS_20_SUBSET_HEADER_FUNCTION = 0x02, + MS_OS_20_FEATURE_COMPATBLE_ID = 0x03, + MS_OS_20_FEATURE_REG_PROPERTY = 0x04, + MS_OS_20_FEATURE_MIN_RESUME_TIME = 0x05, + MS_OS_20_FEATURE_MODEL_ID = 0x06, + MS_OS_20_FEATURE_CCGP_DEVICE = 0x07, + MS_OS_20_FEATURE_VENDOR_REVISION = 0x08 +} microsoft_os_20_type_t; + +enum +{ + CONTROL_STAGE_IDLE, + CONTROL_STAGE_SETUP, + CONTROL_STAGE_DATA, + CONTROL_STAGE_ACK +}; + +//--------------------------------------------------------------------+ +// USB Descriptors +//--------------------------------------------------------------------+ + +// Start of all packed definitions for compiler without per-type packed +TU_ATTR_PACKED_BEGIN +TU_ATTR_BIT_FIELD_ORDER_BEGIN + +/// USB Device Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< DEVICE Descriptor Type. + uint16_t bcdUSB ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). This field identifies the release of the USB Specification with which the device and its descriptors are compliant. + + uint8_t bDeviceClass ; ///< Class code (assigned by the USB-IF). \li If this field is reset to zero, each interface within a configuration specifies its own class information and the various interfaces operate independently. \li If this field is set to a value between 1 and FEH, the device supports different class specifications on different interfaces and the interfaces may not operate independently. This value identifies the class definition used for the aggregate interfaces. \li If this field is set to FFH, the device class is vendor-specific. + uint8_t bDeviceSubClass ; ///< Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass field. \li If the bDeviceClass field is reset to zero, this field must also be reset to zero. \li If the bDeviceClass field is not set to FFH, all values are reserved for assignment by the USB-IF. + uint8_t bDeviceProtocol ; ///< Protocol code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass and the bDeviceSubClass fields. If a device supports class-specific protocols on a device basis as opposed to an interface basis, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use class-specific protocols on a device basis. However, it may use classspecific protocols on an interface basis. \li If this field is set to FFH, the device uses a vendor-specific protocol on a device basis. + uint8_t bMaxPacketSize0 ; ///< Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid). For HS devices is fixed to 64. + + uint16_t idVendor ; ///< Vendor ID (assigned by the USB-IF). + uint16_t idProduct ; ///< Product ID (assigned by the manufacturer). + uint16_t bcdDevice ; ///< Device release number in binary-coded decimal. + uint8_t iManufacturer ; ///< Index of string descriptor describing manufacturer. + uint8_t iProduct ; ///< Index of string descriptor describing product. + uint8_t iSerialNumber ; ///< Index of string descriptor describing the device's serial number. + + uint8_t bNumConfigurations ; ///< Number of possible configurations. +} tusb_desc_device_t; + +TU_VERIFY_STATIC( sizeof(tusb_desc_device_t) == 18, "size is not correct"); + +// USB Binary Device Object Store (BOS) Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes + uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type + uint16_t wTotalLength ; ///< Total length of data returned for this descriptor + uint8_t bNumDeviceCaps ; ///< Number of device capability descriptors in the BOS +} tusb_desc_bos_t; + +TU_VERIFY_STATIC( sizeof(tusb_desc_bos_t) == 5, "size is not correct"); + +/// USB Configuration Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes + uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type + uint16_t wTotalLength ; ///< Total length of data returned for this configuration. Includes the combined length of all descriptors (configuration, interface, endpoint, and class- or vendor-specific) returned for this configuration. + + uint8_t bNumInterfaces ; ///< Number of interfaces supported by this configuration + uint8_t bConfigurationValue ; ///< Value to use as an argument to the SetConfiguration() request to select this configuration. + uint8_t iConfiguration ; ///< Index of string descriptor describing this configuration + uint8_t bmAttributes ; ///< Configuration characteristics \n D7: Reserved (set to one)\n D6: Self-powered \n D5: Remote Wakeup \n D4...0: Reserved (reset to zero) \n D7 is reserved and must be set to one for historical reasons. \n A device configuration that uses power from the bus and a local source reports a non-zero value in bMaxPower to indicate the amount of bus power required and sets D6. The actual power source at runtime may be determined using the GetStatus(DEVICE) request (see USB 2.0 spec Section 9.4.5). \n If a device configuration supports remote wakeup, D5 is set to one. + uint8_t bMaxPower ; ///< Maximum power consumption of the USB device from the bus in this specific configuration when the device is fully operational. Expressed in 2 mA units (i.e., 50 = 100 mA). +} tusb_desc_configuration_t; + +TU_VERIFY_STATIC( sizeof(tusb_desc_configuration_t) == 9, "size is not correct"); + +/// USB Interface Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes + uint8_t bDescriptorType ; ///< INTERFACE Descriptor Type + + uint8_t bInterfaceNumber ; ///< Number of this interface. Zero-based value identifying the index in the array of concurrent interfaces supported by this configuration. + uint8_t bAlternateSetting ; ///< Value used to select this alternate setting for the interface identified in the prior field + uint8_t bNumEndpoints ; ///< Number of endpoints used by this interface (excluding endpoint zero). If this value is zero, this interface only uses the Default Control Pipe. + uint8_t bInterfaceClass ; ///< Class code (assigned by the USB-IF). \li A value of zero is reserved for future standardization. \li If this field is set to FFH, the interface class is vendor-specific. \li All other values are reserved for assignment by the USB-IF. + uint8_t bInterfaceSubClass ; ///< Subclass code (assigned by the USB-IF). \n These codes are qualified by the value of the bInterfaceClass field. \li If the bInterfaceClass field is reset to zero, this field must also be reset to zero. \li If the bInterfaceClass field is not set to FFH, all values are reserved for assignment by the USB-IF. + uint8_t bInterfaceProtocol ; ///< Protocol code (assigned by the USB). \n These codes are qualified by the value of the bInterfaceClass and the bInterfaceSubClass fields. If an interface supports class-specific requests, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use a class-specific protocol on this interface. \li If this field is set to FFH, the device uses a vendor-specific protocol for this interface. + uint8_t iInterface ; ///< Index of string descriptor describing this interface +} tusb_desc_interface_t; + +TU_VERIFY_STATIC( sizeof(tusb_desc_interface_t) == 9, "size is not correct"); + +/// USB Endpoint Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; // Size of this descriptor in bytes + uint8_t bDescriptorType ; // ENDPOINT Descriptor Type + + uint8_t bEndpointAddress ; // The address of the endpoint + + struct TU_ATTR_PACKED { + uint8_t xfer : 2; // Control, ISO, Bulk, Interrupt + uint8_t sync : 2; // None, Asynchronous, Adaptive, Synchronous + uint8_t usage : 2; // Data, Feedback, Implicit feedback + uint8_t : 2; + } bmAttributes; + + uint16_t wMaxPacketSize ; // Bit 10..0 : max packet size, bit 12..11 additional transaction per highspeed micro-frame + uint8_t bInterval ; // Polling interval, in frames or microframes depending on the operating speed +} tusb_desc_endpoint_t; + +TU_VERIFY_STATIC( sizeof(tusb_desc_endpoint_t) == 7, "size is not correct"); + +/// USB Other Speed Configuration Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of descriptor + uint8_t bDescriptorType ; ///< Other_speed_Configuration Type + uint16_t wTotalLength ; ///< Total length of data returned + + uint8_t bNumInterfaces ; ///< Number of interfaces supported by this speed configuration + uint8_t bConfigurationValue ; ///< Value to use to select configuration + uint8_t iConfiguration ; ///< Index of string descriptor + uint8_t bmAttributes ; ///< Same as Configuration descriptor + uint8_t bMaxPower ; ///< Same as Configuration descriptor +} tusb_desc_other_speed_t; + +/// USB Device Qualifier Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of descriptor + uint8_t bDescriptorType ; ///< Device Qualifier Type + uint16_t bcdUSB ; ///< USB specification version number (e.g., 0200H for V2.00) + + uint8_t bDeviceClass ; ///< Class Code + uint8_t bDeviceSubClass ; ///< SubClass Code + uint8_t bDeviceProtocol ; ///< Protocol Code + + uint8_t bMaxPacketSize0 ; ///< Maximum packet size for other speed + uint8_t bNumConfigurations ; ///< Number of Other-speed Configurations + uint8_t bReserved ; ///< Reserved for future use, must be zero +} tusb_desc_device_qualifier_t; + +TU_VERIFY_STATIC( sizeof(tusb_desc_device_qualifier_t) == 10, "size is not correct"); + +/// USB Interface Association Descriptor (IAD ECN) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of descriptor + uint8_t bDescriptorType ; ///< Other_speed_Configuration Type + + uint8_t bFirstInterface ; ///< Index of the first associated interface. + uint8_t bInterfaceCount ; ///< Total number of associated interfaces. + + uint8_t bFunctionClass ; ///< Interface class ID. + uint8_t bFunctionSubClass ; ///< Interface subclass ID. + uint8_t bFunctionProtocol ; ///< Interface protocol ID. + + uint8_t iFunction ; ///< Index of the string descriptor describing the interface association. +} tusb_desc_interface_assoc_t; + +// USB String Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes + uint8_t bDescriptorType ; ///< Descriptor Type + uint16_t unicode_string[]; +} tusb_desc_string_t; + +// USB Binary Device Object Store (BOS) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength; + uint8_t bDescriptorType ; + uint8_t bDevCapabilityType; + uint8_t bReserved; + uint8_t PlatformCapabilityUUID[16]; + uint8_t CapabilityData[]; +} tusb_desc_bos_platform_t; + +// USB WebuSB URL Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bScheme; + char url[]; +} tusb_desc_webusb_url_t; + +// DFU Functional Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength; + uint8_t bDescriptorType; + + union { + struct TU_ATTR_PACKED { + uint8_t bitCanDnload : 1; + uint8_t bitCanUpload : 1; + uint8_t bitManifestationTolerant : 1; + uint8_t bitWillDetach : 1; + uint8_t reserved : 4; + } bmAttributes; + + uint8_t bAttributes; + }; + + uint16_t wDetachTimeOut; + uint16_t wTransferSize; + uint16_t bcdDFUVersion; +} tusb_desc_dfu_functional_t; + +/*------------------------------------------------------------------*/ +/* Types + *------------------------------------------------------------------*/ +typedef struct TU_ATTR_PACKED{ + union { + struct TU_ATTR_PACKED { + uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t. + uint8_t type : 2; ///< Request type tusb_request_type_t. + uint8_t direction : 1; ///< Direction type. tusb_dir_t + } bmRequestType_bit; + + uint8_t bmRequestType; + }; + + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} tusb_control_request_t; + +TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "size is not correct"); + + +TU_ATTR_PACKED_END // End of all packed definitions +TU_ATTR_BIT_FIELD_ORDER_END + +//--------------------------------------------------------------------+ +// Endpoint helper +//--------------------------------------------------------------------+ + +// Get direction from Endpoint address +TU_ATTR_ALWAYS_INLINE static inline tusb_dir_t tu_edpt_dir(uint8_t addr) +{ + return (addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; +} + +// Get Endpoint number from address +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_number(uint8_t addr) +{ + return (uint8_t)(addr & (~TUSB_DIR_IN_MASK)); +} + +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir) +{ + return (uint8_t)(num | (dir ? TUSB_DIR_IN_MASK : 0)); +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep) +{ + return tu_le16toh(desc_ep->wMaxPacketSize) & TU_GENMASK(10, 0); +} + +//--------------------------------------------------------------------+ +// Descriptor helper +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline uint8_t const * tu_desc_next(void const* desc) +{ + uint8_t const* desc8 = (uint8_t const*) desc; + return desc8 + desc8[DESC_OFFSET_LEN]; +} + +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_type(void const* desc) +{ + return ((uint8_t const*) desc)[DESC_OFFSET_TYPE]; +} + +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc) +{ + return ((uint8_t const*) desc)[DESC_OFFSET_LEN]; +} + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_TYPES_H_ */ + +/** @} */ diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_verify.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_verify.h new file mode 100644 index 00000000..a52a6d26 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_verify.h @@ -0,0 +1,156 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ +#ifndef TUSB_VERIFY_H_ +#define TUSB_VERIFY_H_ + +#include +#include +#include "tusb_option.h" +#include "tusb_compiler.h" + +/*------------------------------------------------------------------*/ +/* This file use an advanced macro technique to mimic the default parameter + * as C++ for the sake of code simplicity. Beware of a headache macro + * manipulation that you are told to stay away. + * + * This contains macros for both VERIFY and ASSERT: + * + * VERIFY: Used when there is an error condition which is not the + * fault of the MCU. For example, bounds checking on data + * sent to the micro over USB should use this function. + * Another example is checking for buffer overflows, where + * returning from the active function causes a NAK. + * + * ASSERT: Used for error conditions that are caused by MCU firmware + * bugs. This is used to discover bugs in the code more + * quickly. One example would be adding assertions in library + * function calls to confirm a function's (untainted) + * parameters are valid. + * + * The difference in behavior is that ASSERT triggers a breakpoint while + * verify does not. + * + * #define TU_VERIFY(cond) if(cond) return false; + * #define TU_VERIFY(cond,ret) if(cond) return ret; + * + * #define TU_VERIFY_HDLR(cond,handler) if(cond) {handler; return false;} + * #define TU_VERIFY_HDLR(cond,ret,handler) if(cond) {handler; return ret;} + * + * #define TU_ASSERT(cond) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return false;} + * #define TU_ASSERT(cond,ret) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return ret;} + * + *------------------------------------------------------------------*/ + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// TU_VERIFY Helper +//--------------------------------------------------------------------+ + +#if CFG_TUSB_DEBUG + #include + #define _MESS_FAILED() tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__) +#else + #define _MESS_FAILED() do {} while (0) +#endif + +// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7, M33 +#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__) + #define TU_BREAKPOINT() do \ + { \ + volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \ + if ( (*ARM_CM_DHCSR) & 1UL ) __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */ \ + } while(0) + +#elif defined(__riscv) + #define TU_BREAKPOINT() do { __asm("ebreak\n"); } while(0) + +#elif defined(_mips) + #define TU_BREAKPOINT() do { __asm("sdbbp 0"); } while (0) + +#else + #define TU_BREAKPOINT() do {} while (0) +#endif + +/*------------------------------------------------------------------*/ +/* Macro Generator + *------------------------------------------------------------------*/ + +// Helper to implement optional parameter for TU_VERIFY Macro family +#define _GET_3RD_ARG(arg1, arg2, arg3, ...) arg3 +#define _GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4 + +/*------------- Generator for TU_VERIFY and TU_VERIFY_HDLR -------------*/ +#define TU_VERIFY_DEFINE(_cond, _handler, _ret) do \ +{ \ + if ( !(_cond) ) { _handler; return _ret; } \ +} while(0) + +/*------------------------------------------------------------------*/ +/* TU_VERIFY + * - TU_VERIFY_1ARGS : return false if failed + * - TU_VERIFY_2ARGS : return provided value if failed + *------------------------------------------------------------------*/ +#define TU_VERIFY_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, , false) +#define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, , _ret) + +#define TU_VERIFY(...) _GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, UNUSED)(__VA_ARGS__) + + +/*------------------------------------------------------------------*/ +/* TU_VERIFY WITH HANDLER + * - TU_VERIFY_HDLR_2ARGS : execute handler, return false if failed + * - TU_VERIFY_HDLR_3ARGS : execute handler, return provided error if failed + *------------------------------------------------------------------*/ +#define TU_VERIFY_HDLR_2ARGS(_cond, _handler) TU_VERIFY_DEFINE(_cond, _handler, false) +#define TU_VERIFY_HDLR_3ARGS(_cond, _handler, _ret) TU_VERIFY_DEFINE(_cond, _handler, _ret) + +#define TU_VERIFY_HDLR(...) _GET_4TH_ARG(__VA_ARGS__, TU_VERIFY_HDLR_3ARGS, TU_VERIFY_HDLR_2ARGS,UNUSED)(__VA_ARGS__) + +/*------------------------------------------------------------------*/ +/* ASSERT + * basically TU_VERIFY with TU_BREAKPOINT() as handler + * - 1 arg : return false if failed + * - 2 arg : return error if failed + *------------------------------------------------------------------*/ +#define ASSERT_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), false) +#define ASSERT_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), _ret) + +#ifndef TU_ASSERT +#define TU_ASSERT(...) _GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS,UNUSED)(__VA_ARGS__) +#endif + +/*------------------------------------------------------------------*/ +/* ASSERT HDLR + *------------------------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif /* TUSB_VERIFY_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/device/dcd.h b/test-devices/composite-stm32/lib/tinyusb/device/dcd.h new file mode 100644 index 00000000..c1780f65 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/device/dcd.h @@ -0,0 +1,224 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_DCD_H_ +#define _TUSB_DCD_H_ + +#include "common/tusb_common.h" +#include "osal/osal.h" +#include "common/tusb_fifo.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Configuration +//--------------------------------------------------------------------+ + +#ifndef CFG_TUD_ENDPPOINT_MAX + #define CFG_TUD_ENDPPOINT_MAX TUP_DCD_ENDPOINT_MAX +#endif + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF PROTYPES +//--------------------------------------------------------------------+ + +typedef enum +{ + DCD_EVENT_INVALID = 0, + DCD_EVENT_BUS_RESET, + DCD_EVENT_UNPLUGGED, + DCD_EVENT_SOF, + DCD_EVENT_SUSPEND, // TODO LPM Sleep L1 support + DCD_EVENT_RESUME, + + DCD_EVENT_SETUP_RECEIVED, + DCD_EVENT_XFER_COMPLETE, + + // Not an DCD event, just a convenient way to defer ISR function + USBD_EVENT_FUNC_CALL, + + DCD_EVENT_COUNT +} dcd_eventid_t; + +typedef struct TU_ATTR_ALIGNED(4) +{ + uint8_t rhport; + uint8_t event_id; + + union + { + // BUS RESET + struct { + tusb_speed_t speed; + } bus_reset; + + // SOF + struct { + uint32_t frame_count; + }sof; + + // SETUP_RECEIVED + tusb_control_request_t setup_received; + + // XFER_COMPLETE + struct { + uint8_t ep_addr; + uint8_t result; + uint32_t len; + }xfer_complete; + + // FUNC_CALL + struct { + void (*func) (void*); + void* param; + }func_call; + }; +} dcd_event_t; + +//TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct"); + +//--------------------------------------------------------------------+ +// Controller API +//--------------------------------------------------------------------+ + +// Initialize controller to device mode +void dcd_init (uint8_t rhport); + +// Interrupt Handler +void dcd_int_handler(uint8_t rhport); + +// Enable device interrupt +void dcd_int_enable (uint8_t rhport); + +// Disable device interrupt +void dcd_int_disable(uint8_t rhport); + +// Receive Set Address request, mcu port must also include status IN response +void dcd_set_address(uint8_t rhport, uint8_t dev_addr); + +// Wake up host +void dcd_remote_wakeup(uint8_t rhport); + +// Connect by enabling internal pull-up resistor on D+/D- +void dcd_connect(uint8_t rhport) TU_ATTR_WEAK; + +// Disconnect by disabling internal pull-up resistor on D+/D- +void dcd_disconnect(uint8_t rhport) TU_ATTR_WEAK; + +// Enable/Disable Start-of-frame interrupt. Default is disabled +void dcd_sof_enable(uint8_t rhport, bool en); + +//--------------------------------------------------------------------+ +// Endpoint API +//--------------------------------------------------------------------+ + +// Invoked when a control transfer's status stage is complete. +// May help DCD to prepare for next control transfer, this API is optional. +void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) TU_ATTR_WEAK; + +// Configure endpoint's registers according to descriptor +bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_ep); + +// Close all non-control endpoints, cancel all pending transfers if any. +// Invoked when switching from a non-zero Configuration by SET_CONFIGURE therefore +// required for multiple configuration support. +void dcd_edpt_close_all (uint8_t rhport); + +// Close an endpoint. +// Since it is weak, caller must TU_ASSERT this function's existence before calling it. +void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK; + +// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack +bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); + +// Submit an transfer using fifo, When complete dcd_event_xfer_complete() is invoked to notify the stack +// This API is optional, may be useful for register-based for transferring data. +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) TU_ATTR_WEAK; + +// Stall endpoint, any queuing transfer should be removed from endpoint +void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); + +// clear stall, data toggle is also reset to DATA0 +// This API never calls with control endpoints, since it is auto cleared when receiving setup packet +void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr); + +//--------------------------------------------------------------------+ +// Event API (implemented by stack) +//--------------------------------------------------------------------+ + +// Called by DCD to notify device stack +extern void dcd_event_handler(dcd_event_t const * event, bool in_isr); + +// helper to send bus signal event +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = eid }; + dcd_event_handler(&event, in_isr); +} + +// helper to send bus reset event +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_reset (uint8_t rhport, tusb_speed_t speed, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_BUS_RESET }; + event.bus_reset.speed = speed; + dcd_event_handler(&event, in_isr); +} + +// helper to send setup received +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SETUP_RECEIVED }; + memcpy(&event.setup_received, setup, 8); + + dcd_event_handler(&event, in_isr); +} + +// helper to send transfer complete event +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_XFER_COMPLETE }; + + event.xfer_complete.ep_addr = ep_addr; + event.xfer_complete.len = xferred_bytes; + event.xfer_complete.result = result; + + dcd_event_handler(&event, in_isr); +} + +static inline void dcd_event_sof(uint8_t rhport, uint32_t frame_count, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SOF }; + event.sof.frame_count = frame_count; + dcd_event_handler(&event, in_isr); +} + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_DCD_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/device/usbd.c b/test-devices/composite-stm32/lib/tinyusb/device/usbd.c new file mode 100644 index 00000000..c199e647 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/device/usbd.c @@ -0,0 +1,1389 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUD_ENABLED + +#include "device/dcd.h" +#include "tusb.h" +#include "common/tusb_private.h" + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +//--------------------------------------------------------------------+ +// USBD Configuration +//--------------------------------------------------------------------+ + +// Debug level of USBD +#define USBD_DBG 2 + +#ifndef CFG_TUD_TASK_QUEUE_SZ + #define CFG_TUD_TASK_QUEUE_SZ 16 +#endif + +//--------------------------------------------------------------------+ +// Device Data +//--------------------------------------------------------------------+ + +// Invalid driver ID in itf2drv[] ep2drv[][] mapping +enum { DRVID_INVALID = 0xFFu }; + +typedef struct +{ + struct TU_ATTR_PACKED + { + volatile uint8_t connected : 1; + volatile uint8_t addressed : 1; + volatile uint8_t suspended : 1; + + uint8_t remote_wakeup_en : 1; // enable/disable by host + uint8_t remote_wakeup_support : 1; // configuration descriptor's attribute + uint8_t self_powered : 1; // configuration descriptor's attribute + }; + + volatile uint8_t cfg_num; // current active configuration (0x00 is not configured) + uint8_t speed; + + uint8_t itf2drv[CFG_TUD_INTERFACE_MAX]; // map interface number to driver (0xff is invalid) + uint8_t ep2drv[CFG_TUD_ENDPPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid ), can use only 4-bit each + + tu_edpt_state_t ep_status[CFG_TUD_ENDPPOINT_MAX][2]; + +}usbd_device_t; + +static usbd_device_t _usbd_dev; + +//--------------------------------------------------------------------+ +// Class Driver +//--------------------------------------------------------------------+ +#if CFG_TUSB_DEBUG >= 2 + #define DRIVER_NAME(_name) .name = _name, +#else + #define DRIVER_NAME(_name) +#endif + +// Built-in class drivers +static usbd_class_driver_t const _usbd_driver[] = +{ + #if CFG_TUD_CDC + { + DRIVER_NAME("CDC") + .init = cdcd_init, + .reset = cdcd_reset, + .open = cdcd_open, + .control_xfer_cb = cdcd_control_xfer_cb, + .xfer_cb = cdcd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_MSC + { + DRIVER_NAME("MSC") + .init = mscd_init, + .reset = mscd_reset, + .open = mscd_open, + .control_xfer_cb = mscd_control_xfer_cb, + .xfer_cb = mscd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_HID + { + DRIVER_NAME("HID") + .init = hidd_init, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hidd_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_AUDIO + { + DRIVER_NAME("AUDIO") + .init = audiod_init, + .reset = audiod_reset, + .open = audiod_open, + .control_xfer_cb = audiod_control_xfer_cb, + .xfer_cb = audiod_xfer_cb, + .sof = audiod_sof_isr + }, + #endif + + #if CFG_TUD_VIDEO + { + DRIVER_NAME("VIDEO") + .init = videod_init, + .reset = videod_reset, + .open = videod_open, + .control_xfer_cb = videod_control_xfer_cb, + .xfer_cb = videod_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_MIDI + { + DRIVER_NAME("MIDI") + .init = midid_init, + .open = midid_open, + .reset = midid_reset, + .control_xfer_cb = midid_control_xfer_cb, + .xfer_cb = midid_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_VENDOR + { + DRIVER_NAME("VENDOR") + .init = vendord_init, + .reset = vendord_reset, + .open = vendord_open, + .control_xfer_cb = tud_vendor_control_xfer_cb, + .xfer_cb = vendord_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_USBTMC + { + DRIVER_NAME("TMC") + .init = usbtmcd_init_cb, + .reset = usbtmcd_reset_cb, + .open = usbtmcd_open_cb, + .control_xfer_cb = usbtmcd_control_xfer_cb, + .xfer_cb = usbtmcd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_DFU_RUNTIME + { + DRIVER_NAME("DFU-RUNTIME") + .init = dfu_rtd_init, + .reset = dfu_rtd_reset, + .open = dfu_rtd_open, + .control_xfer_cb = dfu_rtd_control_xfer_cb, + .xfer_cb = NULL, + .sof = NULL + }, + #endif + + #if CFG_TUD_DFU + { + DRIVER_NAME("DFU") + .init = dfu_moded_init, + .reset = dfu_moded_reset, + .open = dfu_moded_open, + .control_xfer_cb = dfu_moded_control_xfer_cb, + .xfer_cb = NULL, + .sof = NULL + }, + #endif + + #if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM + { + DRIVER_NAME("NET") + .init = netd_init, + .reset = netd_reset, + .open = netd_open, + .control_xfer_cb = netd_control_xfer_cb, + .xfer_cb = netd_xfer_cb, + .sof = NULL, + }, + #endif + + #if CFG_TUD_BTH + { + DRIVER_NAME("BTH") + .init = btd_init, + .reset = btd_reset, + .open = btd_open, + .control_xfer_cb = btd_control_xfer_cb, + .xfer_cb = btd_xfer_cb, + .sof = NULL + }, + #endif +}; + +enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(_usbd_driver) }; + +// Additional class drivers implemented by application +static usbd_class_driver_t const * _app_driver = NULL; +static uint8_t _app_driver_count = 0; + +// virtually joins built-in and application drivers together. +// Application is positioned first to allow overwriting built-in ones. +static inline usbd_class_driver_t const * get_driver(uint8_t drvid) +{ + // Application drivers + if ( usbd_app_driver_get_cb ) + { + if ( drvid < _app_driver_count ) return &_app_driver[drvid]; + drvid -= _app_driver_count; + } + + // Built-in drivers + if (drvid < BUILTIN_DRIVER_COUNT) return &_usbd_driver[drvid]; + + return NULL; +} + +#define TOTAL_DRIVER_COUNT (_app_driver_count + BUILTIN_DRIVER_COUNT) + +//--------------------------------------------------------------------+ +// DCD Event +//--------------------------------------------------------------------+ + +enum { RHPORT_INVALID = 0xFFu }; +static uint8_t _usbd_rhport = RHPORT_INVALID; + +// Event queue +// usbd_int_set() is used as mutex in OS NONE config +OSAL_QUEUE_DEF(usbd_int_set, _usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t); +static osal_queue_t _usbd_q; + +// Mutex for claiming endpoint, only needed when using with preempted RTOS +#if CFG_TUSB_OS != OPT_OS_NONE +static osal_mutex_def_t _ubsd_mutexdef; +static osal_mutex_t _usbd_mutex; +#endif + + +//--------------------------------------------------------------------+ +// Prototypes +//--------------------------------------------------------------------+ +static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request); +static bool process_set_config(uint8_t rhport, uint8_t cfg_num); +static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request); + +// from usbd_control.c +void usbd_control_reset(void); +void usbd_control_set_request(tusb_control_request_t const *request); +void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp ); +bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); + + +//--------------------------------------------------------------------+ +// Debug +//--------------------------------------------------------------------+ +#if CFG_TUSB_DEBUG >= 2 +static char const* const _usbd_event_str[DCD_EVENT_COUNT] = +{ + "Invalid" , + "Bus Reset" , + "Unplugged" , + "SOF" , + "Suspend" , + "Resume" , + "Setup Received" , + "Xfer Complete" , + "Func Call" +}; + +// for usbd_control to print the name of control complete driver +void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback) +{ + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) + { + usbd_class_driver_t const * driver = get_driver(i); + if ( driver && driver->control_xfer_cb == callback ) + { + TU_LOG(USBD_DBG, " %s control complete\r\n", driver->name); + return; + } + } +} + +#endif + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ +tusb_speed_t tud_speed_get(void) +{ + return (tusb_speed_t) _usbd_dev.speed; +} + +bool tud_connected(void) +{ + return _usbd_dev.connected; +} + +bool tud_mounted(void) +{ + return _usbd_dev.cfg_num ? true : false; +} + +bool tud_suspended(void) +{ + return _usbd_dev.suspended; +} + +bool tud_remote_wakeup(void) +{ + // only wake up host if this feature is supported and enabled and we are suspended + TU_VERIFY (_usbd_dev.suspended && _usbd_dev.remote_wakeup_support && _usbd_dev.remote_wakeup_en ); + dcd_remote_wakeup(_usbd_rhport); + return true; +} + +bool tud_disconnect(void) +{ + TU_VERIFY(dcd_disconnect); + dcd_disconnect(_usbd_rhport); + return true; +} + +bool tud_connect(void) +{ + TU_VERIFY(dcd_connect); + dcd_connect(_usbd_rhport); + return true; +} + +//--------------------------------------------------------------------+ +// USBD Task +//--------------------------------------------------------------------+ +bool tud_inited(void) +{ + return _usbd_rhport != RHPORT_INVALID; +} + +bool tud_init (uint8_t rhport) +{ + // skip if already initialized + if ( tud_inited() ) return true; + + TU_LOG(USBD_DBG, "USBD init on controller %u\r\n", rhport); + TU_LOG_INT(USBD_DBG, sizeof(usbd_device_t)); + + tu_varclr(&_usbd_dev); + +#if CFG_TUSB_OS != OPT_OS_NONE + // Init device mutex + _usbd_mutex = osal_mutex_create(&_ubsd_mutexdef); + TU_ASSERT(_usbd_mutex); +#endif + + // Init device queue & task + _usbd_q = osal_queue_create(&_usbd_qdef); + TU_ASSERT(_usbd_q); + + // Get application driver if available + if ( usbd_app_driver_get_cb ) + { + _app_driver = usbd_app_driver_get_cb(&_app_driver_count); + } + + // Init class drivers + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) + { + usbd_class_driver_t const * driver = get_driver(i); + TU_ASSERT(driver); + TU_LOG(USBD_DBG, "%s init\r\n", driver->name); + driver->init(); + } + + _usbd_rhport = rhport; + + // Init device controller driver + dcd_init(rhport); + dcd_int_enable(rhport); + + return true; +} + +static void configuration_reset(uint8_t rhport) +{ + for ( uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++ ) + { + usbd_class_driver_t const * driver = get_driver(i); + TU_ASSERT(driver, ); + driver->reset(rhport); + } + + tu_varclr(&_usbd_dev); + memset(_usbd_dev.itf2drv, DRVID_INVALID, sizeof(_usbd_dev.itf2drv)); // invalid mapping + memset(_usbd_dev.ep2drv , DRVID_INVALID, sizeof(_usbd_dev.ep2drv )); // invalid mapping +} + +static void usbd_reset(uint8_t rhport) +{ + configuration_reset(rhport); + usbd_control_reset(); +} + +bool tud_task_event_ready(void) +{ + // Skip if stack is not initialized + if ( !tusb_inited() ) return false; + + return !osal_queue_empty(_usbd_q); +} + +/* USB Device Driver task + * This top level thread manages all device controller event and delegates events to class-specific drivers. + * This should be called periodically within the mainloop or rtos thread. + * + @code + int main(void) + { + application_init(); + tusb_init(); + + while(1) // the mainloop + { + application_code(); + tud_task(); // tinyusb device task + } + } + @endcode + */ +void tud_task_ext(uint32_t timeout_ms, bool in_isr) +{ + (void) in_isr; // not implemented yet + + // Skip if stack is not initialized + if ( !tusb_inited() ) return; + + // Loop until there is no more events in the queue + while (1) + { + dcd_event_t event; + if ( !osal_queue_receive(_usbd_q, &event, timeout_ms) ) return; + +#if CFG_TUSB_DEBUG >= 2 + if (event.event_id == DCD_EVENT_SETUP_RECEIVED) TU_LOG(USBD_DBG, "\r\n"); // extra line for setup + TU_LOG(USBD_DBG, "USBD %s ", event.event_id < DCD_EVENT_COUNT ? _usbd_event_str[event.event_id] : "CORRUPTED"); +#endif + + switch ( event.event_id ) + { + case DCD_EVENT_BUS_RESET: + TU_LOG(USBD_DBG, ": %s Speed\r\n", tu_str_speed[event.bus_reset.speed]); + usbd_reset(event.rhport); + _usbd_dev.speed = event.bus_reset.speed; + break; + + case DCD_EVENT_UNPLUGGED: + TU_LOG(USBD_DBG, "\r\n"); + usbd_reset(event.rhport); + + // invoke callback + if (tud_umount_cb) tud_umount_cb(); + break; + + case DCD_EVENT_SETUP_RECEIVED: + TU_LOG_VAR(USBD_DBG, &event.setup_received); + TU_LOG(USBD_DBG, "\r\n"); + + // Mark as connected after receiving 1st setup packet. + // But it is easier to set it every time instead of wasting time to check then set + _usbd_dev.connected = 1; + + // mark both in & out control as free + _usbd_dev.ep_status[0][TUSB_DIR_OUT].busy = false; + _usbd_dev.ep_status[0][TUSB_DIR_OUT].claimed = 0; + _usbd_dev.ep_status[0][TUSB_DIR_IN ].busy = false; + _usbd_dev.ep_status[0][TUSB_DIR_IN ].claimed = 0; + + // Process control request + if ( !process_control_request(event.rhport, &event.setup_received) ) + { + TU_LOG(USBD_DBG, " Stall EP0\r\n"); + // Failed -> stall both control endpoint IN and OUT + dcd_edpt_stall(event.rhport, 0); + dcd_edpt_stall(event.rhport, 0 | TUSB_DIR_IN_MASK); + } + break; + + case DCD_EVENT_XFER_COMPLETE: + { + // Invoke the class callback associated with the endpoint address + uint8_t const ep_addr = event.xfer_complete.ep_addr; + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const ep_dir = tu_edpt_dir(ep_addr); + + TU_LOG(USBD_DBG, "on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len); + + _usbd_dev.ep_status[epnum][ep_dir].busy = false; + _usbd_dev.ep_status[epnum][ep_dir].claimed = 0; + + if ( 0 == epnum ) + { + usbd_control_xfer_cb(event.rhport, ep_addr, (xfer_result_t)event.xfer_complete.result, event.xfer_complete.len); + } + else + { + usbd_class_driver_t const * driver = get_driver( _usbd_dev.ep2drv[epnum][ep_dir] ); + TU_ASSERT(driver, ); + + TU_LOG(USBD_DBG, " %s xfer callback\r\n", driver->name); + driver->xfer_cb(event.rhport, ep_addr, (xfer_result_t)event.xfer_complete.result, event.xfer_complete.len); + } + } + break; + + case DCD_EVENT_SUSPEND: + // NOTE: When plugging/unplugging device, the D+/D- state are unstable and + // can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ), which result in a series of event + // e.g suspend -> resume -> unplug/plug. Skip suspend/resume if not connected + if ( _usbd_dev.connected ) + { + TU_LOG(USBD_DBG, ": Remote Wakeup = %u\r\n", _usbd_dev.remote_wakeup_en); + if (tud_suspend_cb) tud_suspend_cb(_usbd_dev.remote_wakeup_en); + }else + { + TU_LOG(USBD_DBG, " Skipped\r\n"); + } + break; + + case DCD_EVENT_RESUME: + if ( _usbd_dev.connected ) + { + TU_LOG(USBD_DBG, "\r\n"); + if (tud_resume_cb) tud_resume_cb(); + }else + { + TU_LOG(USBD_DBG, " Skipped\r\n"); + } + break; + + case USBD_EVENT_FUNC_CALL: + TU_LOG(USBD_DBG, "\r\n"); + if ( event.func_call.func ) event.func_call.func(event.func_call.param); + break; + + case DCD_EVENT_SOF: + default: + TU_BREAKPOINT(); + break; + } + +#if CFG_TUSB_OS != OPT_OS_NONE && CFG_TUSB_OS != OPT_OS_PICO + // return if there is no more events, for application to run other background + if (osal_queue_empty(_usbd_q)) return; +#endif + } +} + +//--------------------------------------------------------------------+ +// Control Request Parser & Handling +//--------------------------------------------------------------------+ + +// Helper to invoke class driver control request handler +static bool invoke_class_control(uint8_t rhport, usbd_class_driver_t const * driver, tusb_control_request_t const * request) +{ + usbd_control_set_complete_callback(driver->control_xfer_cb); + TU_LOG(USBD_DBG, " %s control request\r\n", driver->name); + return driver->control_xfer_cb(rhport, CONTROL_STAGE_SETUP, request); +} + +// This handles the actual request and its response. +// return false will cause its caller to stall control endpoint +static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request) +{ + usbd_control_set_complete_callback(NULL); + + TU_ASSERT(p_request->bmRequestType_bit.type < TUSB_REQ_TYPE_INVALID); + + // Vendor request + if ( p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR ) + { + TU_VERIFY(tud_vendor_control_xfer_cb); + + usbd_control_set_complete_callback(tud_vendor_control_xfer_cb); + return tud_vendor_control_xfer_cb(rhport, CONTROL_STAGE_SETUP, p_request); + } + +#if CFG_TUSB_DEBUG >= 2 + if (TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type && p_request->bRequest <= TUSB_REQ_SYNCH_FRAME) + { + TU_LOG(USBD_DBG, " %s", tu_str_std_request[p_request->bRequest]); + if (TUSB_REQ_GET_DESCRIPTOR != p_request->bRequest) TU_LOG(USBD_DBG, "\r\n"); + } +#endif + + switch ( p_request->bmRequestType_bit.recipient ) + { + //------------- Device Requests e.g in enumeration -------------// + case TUSB_REQ_RCPT_DEVICE: + if ( TUSB_REQ_TYPE_CLASS == p_request->bmRequestType_bit.type ) + { + uint8_t const itf = tu_u16_low(p_request->wIndex); + TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv)); + + usbd_class_driver_t const * driver = get_driver(_usbd_dev.itf2drv[itf]); + TU_VERIFY(driver); + + // forward to class driver: "non-STD request to Interface" + return invoke_class_control(rhport, driver, p_request); + } + + if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) + { + // Non standard request is not supported + TU_BREAKPOINT(); + return false; + } + + switch ( p_request->bRequest ) + { + case TUSB_REQ_SET_ADDRESS: + // Depending on mcu, status phase could be sent either before or after changing device address, + // or even require stack to not response with status at all + // Therefore DCD must take full responsibility to response and include zlp status packet if needed. + usbd_control_set_request(p_request); // set request since DCD has no access to tud_control_status() API + dcd_set_address(rhport, (uint8_t) p_request->wValue); + // skip tud_control_status() + _usbd_dev.addressed = 1; + break; + + case TUSB_REQ_GET_CONFIGURATION: + { + uint8_t cfg_num = _usbd_dev.cfg_num; + tud_control_xfer(rhport, p_request, &cfg_num, 1); + } + break; + + case TUSB_REQ_SET_CONFIGURATION: + { + uint8_t const cfg_num = (uint8_t) p_request->wValue; + + // Only process if new configure is different + if (_usbd_dev.cfg_num != cfg_num) + { + if ( _usbd_dev.cfg_num ) + { + // already configured: need to clear all endpoints and driver first + TU_LOG(USBD_DBG, " Clear current Configuration (%u) before switching\r\n", _usbd_dev.cfg_num); + + // close all non-control endpoints, cancel all pending transfers if any + dcd_edpt_close_all(rhport); + + // close all drivers and current configured state except bus speed + uint8_t const speed = _usbd_dev.speed; + configuration_reset(rhport); + + _usbd_dev.speed = speed; // restore speed + } + + // switch to new configuration if not zero + if ( cfg_num ) TU_ASSERT( process_set_config(rhport, cfg_num) ); + } + + _usbd_dev.cfg_num = cfg_num; + tud_control_status(rhport, p_request); + } + break; + + case TUSB_REQ_GET_DESCRIPTOR: + TU_VERIFY( process_get_descriptor(rhport, p_request) ); + break; + + case TUSB_REQ_SET_FEATURE: + // Only support remote wakeup for device feature + TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue); + + TU_LOG(USBD_DBG, " Enable Remote Wakeup\r\n"); + + // Host may enable remote wake up before suspending especially HID device + _usbd_dev.remote_wakeup_en = true; + tud_control_status(rhport, p_request); + break; + + case TUSB_REQ_CLEAR_FEATURE: + // Only support remote wakeup for device feature + TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue); + + TU_LOG(USBD_DBG, " Disable Remote Wakeup\r\n"); + + // Host may disable remote wake up after resuming + _usbd_dev.remote_wakeup_en = false; + tud_control_status(rhport, p_request); + break; + + case TUSB_REQ_GET_STATUS: + { + // Device status bit mask + // - Bit 0: Self Powered + // - Bit 1: Remote Wakeup enabled + uint16_t status = (uint16_t) ((_usbd_dev.self_powered ? 1u : 0u) | (_usbd_dev.remote_wakeup_en ? 2u : 0u)); + tud_control_xfer(rhport, p_request, &status, 2); + } + break; + + // Unknown/Unsupported request + default: TU_BREAKPOINT(); return false; + } + break; + + //------------- Class/Interface Specific Request -------------// + case TUSB_REQ_RCPT_INTERFACE: + { + uint8_t const itf = tu_u16_low(p_request->wIndex); + TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv)); + + usbd_class_driver_t const * driver = get_driver(_usbd_dev.itf2drv[itf]); + TU_VERIFY(driver); + + // all requests to Interface (STD or Class) is forwarded to class driver. + // notable requests are: GET HID REPORT DESCRIPTOR, SET_INTERFACE, GET_INTERFACE + if ( !invoke_class_control(rhport, driver, p_request) ) + { + // For GET_INTERFACE and SET_INTERFACE, it is mandatory to respond even if the class + // driver doesn't use alternate settings or implement this + TU_VERIFY(TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type); + + switch(p_request->bRequest) + { + case TUSB_REQ_GET_INTERFACE: + case TUSB_REQ_SET_INTERFACE: + // Clear complete callback if driver set since it can also stall the request. + usbd_control_set_complete_callback(NULL); + + if (TUSB_REQ_GET_INTERFACE == p_request->bRequest) + { + uint8_t alternate = 0; + tud_control_xfer(rhport, p_request, &alternate, 1); + }else + { + tud_control_status(rhport, p_request); + } + break; + + default: return false; + } + } + } + break; + + //------------- Endpoint Request -------------// + case TUSB_REQ_RCPT_ENDPOINT: + { + uint8_t const ep_addr = tu_u16_low(p_request->wIndex); + uint8_t const ep_num = tu_edpt_number(ep_addr); + uint8_t const ep_dir = tu_edpt_dir(ep_addr); + + TU_ASSERT(ep_num < TU_ARRAY_SIZE(_usbd_dev.ep2drv) ); + + usbd_class_driver_t const * driver = get_driver(_usbd_dev.ep2drv[ep_num][ep_dir]); + + if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) + { + // Forward class request to its driver + TU_VERIFY(driver); + return invoke_class_control(rhport, driver, p_request); + } + else + { + // Handle STD request to endpoint + switch ( p_request->bRequest ) + { + case TUSB_REQ_GET_STATUS: + { + uint16_t status = usbd_edpt_stalled(rhport, ep_addr) ? 0x0001 : 0x0000; + tud_control_xfer(rhport, p_request, &status, 2); + } + break; + + case TUSB_REQ_CLEAR_FEATURE: + case TUSB_REQ_SET_FEATURE: + { + if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) + { + if ( TUSB_REQ_CLEAR_FEATURE == p_request->bRequest ) + { + usbd_edpt_clear_stall(rhport, ep_addr); + }else + { + usbd_edpt_stall(rhport, ep_addr); + } + } + + if (driver) + { + // Some classes such as USBTMC needs to clear/re-init its buffer when receiving CLEAR_FEATURE request + // We will also forward std request targeted endpoint to class drivers as well + + // STD request must always be ACKed regardless of driver returned value + // Also clear complete callback if driver set since it can also stall the request. + (void) invoke_class_control(rhport, driver, p_request); + usbd_control_set_complete_callback(NULL); + + // skip ZLP status if driver already did that + if ( !_usbd_dev.ep_status[0][TUSB_DIR_IN].busy ) tud_control_status(rhport, p_request); + } + } + break; + + // Unknown/Unsupported request + default: TU_BREAKPOINT(); return false; + } + } + } + break; + + // Unknown recipient + default: TU_BREAKPOINT(); return false; + } + + return true; +} + +// Process Set Configure Request +// This function parse configuration descriptor & open drivers accordingly +static bool process_set_config(uint8_t rhport, uint8_t cfg_num) +{ + // index is cfg_num-1 + tusb_desc_configuration_t const * desc_cfg = (tusb_desc_configuration_t const *) tud_descriptor_configuration_cb(cfg_num-1); + TU_ASSERT(desc_cfg != NULL && desc_cfg->bDescriptorType == TUSB_DESC_CONFIGURATION); + + // Parse configuration descriptor + _usbd_dev.remote_wakeup_support = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP) ? 1u : 0u; + _usbd_dev.self_powered = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_SELF_POWERED ) ? 1u : 0u; + + // Parse interface descriptor + uint8_t const * p_desc = ((uint8_t const*) desc_cfg) + sizeof(tusb_desc_configuration_t); + uint8_t const * desc_end = ((uint8_t const*) desc_cfg) + tu_le16toh(desc_cfg->wTotalLength); + + while( p_desc < desc_end ) + { + uint8_t assoc_itf_count = 1; + + // Class will always starts with Interface Association (if any) and then Interface descriptor + if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) ) + { + tusb_desc_interface_assoc_t const * desc_iad = (tusb_desc_interface_assoc_t const *) p_desc; + assoc_itf_count = desc_iad->bInterfaceCount; + + p_desc = tu_desc_next(p_desc); // next to Interface + + // IAD's first interface number and class should match with opened interface + //TU_ASSERT(desc_iad->bFirstInterface == desc_itf->bInterfaceNumber && + // desc_iad->bFunctionClass == desc_itf->bInterfaceClass); + } + + TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) ); + tusb_desc_interface_t const * desc_itf = (tusb_desc_interface_t const*) p_desc; + + // Find driver for this interface + uint16_t const remaining_len = (uint16_t) (desc_end-p_desc); + uint8_t drv_id; + for (drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) + { + usbd_class_driver_t const *driver = get_driver(drv_id); + TU_ASSERT(driver); + uint16_t const drv_len = driver->open(rhport, desc_itf, remaining_len); + + if ( (sizeof(tusb_desc_interface_t) <= drv_len) && (drv_len <= remaining_len) ) + { + // Open successfully + TU_LOG(USBD_DBG, " %s opened\r\n", driver->name); + + // Some drivers use 2 or more interfaces but may not have IAD e.g MIDI (always) or + // BTH (even CDC) with class in device descriptor (single interface) + if ( assoc_itf_count == 1) + { + #if CFG_TUD_CDC + if ( driver->open == cdcd_open ) assoc_itf_count = 2; + #endif + + #if CFG_TUD_MIDI + if ( driver->open == midid_open ) assoc_itf_count = 2; + #endif + + #if CFG_TUD_BTH && CFG_TUD_BTH_ISO_ALT_COUNT + if ( driver->open == btd_open ) assoc_itf_count = 2; + #endif + } + + // bind (associated) interfaces to found driver + for(uint8_t i=0; ibInterfaceNumber+i; + + // Interface number must not be used already + TU_ASSERT(DRVID_INVALID == _usbd_dev.itf2drv[itf_num]); + _usbd_dev.itf2drv[itf_num] = drv_id; + } + + // bind all endpoints to found driver + tu_edpt_bind_driver(_usbd_dev.ep2drv, desc_itf, drv_len, drv_id); + + // next Interface + p_desc += drv_len; + + break; // exit driver find loop + } + } + + // Failed if there is no supported drivers + TU_ASSERT(drv_id < TOTAL_DRIVER_COUNT); + } + + // invoke callback + if (tud_mount_cb) tud_mount_cb(); + + return true; +} + +// return descriptor's buffer and update desc_len +static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request) +{ + tusb_desc_type_t const desc_type = (tusb_desc_type_t) tu_u16_high(p_request->wValue); + uint8_t const desc_index = tu_u16_low( p_request->wValue ); + + switch(desc_type) + { + case TUSB_DESC_DEVICE: + { + TU_LOG(USBD_DBG, " Device\r\n"); + + void* desc_device = (void*) (uintptr_t) tud_descriptor_device_cb(); + + // Only response with exactly 1 Packet if: not addressed and host requested more data than device descriptor has. + // This only happens with the very first get device descriptor and EP0 size = 8 or 16. + if ((CFG_TUD_ENDPOINT0_SIZE < sizeof(tusb_desc_device_t)) && !_usbd_dev.addressed && + ((tusb_control_request_t const*) p_request)->wLength > sizeof(tusb_desc_device_t)) + { + // Hack here: we modify the request length to prevent usbd_control response with zlp + // since we are responding with 1 packet & less data than wLength. + tusb_control_request_t mod_request = *p_request; + mod_request.wLength = CFG_TUD_ENDPOINT0_SIZE; + + return tud_control_xfer(rhport, &mod_request, desc_device, CFG_TUD_ENDPOINT0_SIZE); + }else + { + return tud_control_xfer(rhport, p_request, desc_device, sizeof(tusb_desc_device_t)); + } + } + // break; // unreachable + + case TUSB_DESC_BOS: + { + TU_LOG(USBD_DBG, " BOS\r\n"); + + // requested by host if USB > 2.0 ( i.e 2.1 or 3.x ) + if (!tud_descriptor_bos_cb) return false; + + uintptr_t desc_bos = (uintptr_t) tud_descriptor_bos_cb(); + TU_ASSERT(desc_bos); + + // Use offsetof to avoid pointer to the odd/misaligned address + uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_bos + offsetof(tusb_desc_bos_t, wTotalLength))) ); + + return tud_control_xfer(rhport, p_request, (void*) desc_bos, total_len); + } + // break; // unreachable + + case TUSB_DESC_CONFIGURATION: + case TUSB_DESC_OTHER_SPEED_CONFIG: + { + uintptr_t desc_config; + + if ( desc_type == TUSB_DESC_CONFIGURATION ) + { + TU_LOG(USBD_DBG, " Configuration[%u]\r\n", desc_index); + desc_config = (uintptr_t) tud_descriptor_configuration_cb(desc_index); + }else + { + // Host only request this after getting Device Qualifier descriptor + TU_LOG(USBD_DBG, " Other Speed Configuration\r\n"); + TU_VERIFY( tud_descriptor_other_speed_configuration_cb ); + desc_config = (uintptr_t) tud_descriptor_other_speed_configuration_cb(desc_index); + } + + TU_ASSERT(desc_config); + + // Use offsetof to avoid pointer to the odd/misaligned address + uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_config + offsetof(tusb_desc_configuration_t, wTotalLength))) ); + + return tud_control_xfer(rhport, p_request, (void*) desc_config, total_len); + } + // break; // unreachable + + case TUSB_DESC_STRING: + { + TU_LOG(USBD_DBG, " String[%u]\r\n", desc_index); + + // String Descriptor always uses the desc set from user + uint8_t const* desc_str = (uint8_t const*) tud_descriptor_string_cb(desc_index, tu_le16toh(p_request->wIndex)); + TU_VERIFY(desc_str); + + // first byte of descriptor is its size + return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_str, tu_desc_len(desc_str)); + } + // break; // unreachable + + case TUSB_DESC_DEVICE_QUALIFIER: + { + TU_LOG(USBD_DBG, " Device Qualifier\r\n"); + + TU_VERIFY( tud_descriptor_device_qualifier_cb ); + + uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb(); + TU_VERIFY(desc_qualifier); + + // first byte of descriptor is its size + return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_qualifier, tu_desc_len(desc_qualifier)); + } + // break; // unreachable + + default: return false; + } +} + +//--------------------------------------------------------------------+ +// DCD Event Handler +//--------------------------------------------------------------------+ +TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const * event, bool in_isr) +{ + switch (event->event_id) + { + case DCD_EVENT_UNPLUGGED: + _usbd_dev.connected = 0; + _usbd_dev.addressed = 0; + _usbd_dev.cfg_num = 0; + _usbd_dev.suspended = 0; + osal_queue_send(_usbd_q, event, in_isr); + break; + + case DCD_EVENT_SUSPEND: + // NOTE: When plugging/unplugging device, the D+/D- state are unstable and + // can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ). + // In addition, some MCUs such as SAMD or boards that haven no VBUS detection cannot distinguish + // suspended vs disconnected. We will skip handling SUSPEND/RESUME event if not currently connected + if ( _usbd_dev.connected ) + { + _usbd_dev.suspended = 1; + osal_queue_send(_usbd_q, event, in_isr); + } + break; + + case DCD_EVENT_RESUME: + // skip event if not connected (especially required for SAMD) + if ( _usbd_dev.connected ) + { + _usbd_dev.suspended = 0; + osal_queue_send(_usbd_q, event, in_isr); + } + break; + + case DCD_EVENT_SOF: + // SOF driver handler in ISR context + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) + { + usbd_class_driver_t const * driver = get_driver(i); + if (driver && driver->sof) + { + driver->sof(event->rhport, event->sof.frame_count); + } + } + + // Some MCUs after running dcd_remote_wakeup() does not have way to detect the end of remote wakeup + // which last 1-15 ms. DCD can use SOF as a clear indicator that bus is back to operational + if ( _usbd_dev.suspended ) + { + _usbd_dev.suspended = 0; + + dcd_event_t const event_resume = { .rhport = event->rhport, .event_id = DCD_EVENT_RESUME }; + osal_queue_send(_usbd_q, &event_resume, in_isr); + } + + // skip osal queue for SOF in usbd task + break; + + default: + osal_queue_send(_usbd_q, event, in_isr); + break; + } +} + +//--------------------------------------------------------------------+ +// USBD API For Class Driver +//--------------------------------------------------------------------+ + +void usbd_int_set(bool enabled) +{ + if (enabled) + { + dcd_int_enable(_usbd_rhport); + }else + { + dcd_int_disable(_usbd_rhport); + } +} + +// Parse consecutive endpoint descriptors (IN & OUT) +bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in) +{ + for(int i=0; ibDescriptorType && xfer_type == desc_ep->bmAttributes.xfer); + TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); + + if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) + { + (*ep_in) = desc_ep->bEndpointAddress; + }else + { + (*ep_out) = desc_ep->bEndpointAddress; + } + + p_desc = tu_desc_next(p_desc); + } + + return true; +} + +// Helper to defer an isr function +void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr) +{ + dcd_event_t event = + { + .rhport = 0, + .event_id = USBD_EVENT_FUNC_CALL, + }; + + event.func_call.func = func; + event.func_call.param = param; + + dcd_event_handler(&event, in_isr); +} + +//--------------------------------------------------------------------+ +// USBD Endpoint API +//--------------------------------------------------------------------+ + +bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) +{ + rhport = _usbd_rhport; + + TU_ASSERT(tu_edpt_number(desc_ep->bEndpointAddress) < CFG_TUD_ENDPPOINT_MAX); + TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed)); + + return dcd_edpt_open(rhport, desc_ep); +} + +bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + + // TODO add this check later, also make sure we don't starve an out endpoint while suspending + // TU_VERIFY(tud_ready()); + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir]; + +#if TUSB_OPT_MUTEX + return tu_edpt_claim(ep_state, _usbd_mutex); +#else + return tu_edpt_claim(ep_state, NULL); +#endif +} + +bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir]; + +#if TUSB_OPT_MUTEX + return tu_edpt_release(ep_state, _usbd_mutex); +#else + return tu_edpt_release(ep_state, NULL); +#endif +} + +bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +{ + rhport = _usbd_rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + // TODO skip ready() check for now since enumeration also use this API + // TU_VERIFY(tud_ready()); + + TU_LOG(USBD_DBG, " Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes); + + // Attempt to transfer on a busy endpoint, sound like an race condition ! + TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0); + + // Set busy first since the actual transfer can be complete before dcd_edpt_xfer() + // could return and USBD task can preempt and clear the busy + _usbd_dev.ep_status[epnum][dir].busy = true; + + if ( dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes) ) + { + return true; + }else + { + // DCD error, mark endpoint as ready to allow next transfer + _usbd_dev.ep_status[epnum][dir].busy = false; + _usbd_dev.ep_status[epnum][dir].claimed = 0; + TU_LOG(USBD_DBG, "FAILED\r\n"); + TU_BREAKPOINT(); + return false; + } +} + +// The number of bytes has to be given explicitly to allow more flexible control of how many +// bytes should be written and second to keep the return value free to give back a boolean +// success message. If total_bytes is too big, the FIFO will copy only what is available +// into the USB buffer! +bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + rhport = _usbd_rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + TU_LOG(USBD_DBG, " Queue ISO EP %02X with %u bytes ... ", ep_addr, total_bytes); + + // Attempt to transfer on a busy endpoint, sound like an race condition ! + TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0); + + // Set busy first since the actual transfer can be complete before dcd_edpt_xfer() could return + // and usbd task can preempt and clear the busy + _usbd_dev.ep_status[epnum][dir].busy = true; + + if (dcd_edpt_xfer_fifo(rhport, ep_addr, ff, total_bytes)) + { + TU_LOG(USBD_DBG, "OK\r\n"); + return true; + }else + { + // DCD error, mark endpoint as ready to allow next transfer + _usbd_dev.ep_status[epnum][dir].busy = false; + _usbd_dev.ep_status[epnum][dir].claimed = 0; + TU_LOG(USBD_DBG, "failed\r\n"); + TU_BREAKPOINT(); + return false; + } +} + +bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + return _usbd_dev.ep_status[epnum][dir].busy; +} + +void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr) +{ + rhport = _usbd_rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + // only stalled if currently cleared + if ( !_usbd_dev.ep_status[epnum][dir].stalled ) + { + TU_LOG(USBD_DBG, " Stall EP %02X\r\n", ep_addr); + dcd_edpt_stall(rhport, ep_addr); + _usbd_dev.ep_status[epnum][dir].stalled = true; + _usbd_dev.ep_status[epnum][dir].busy = true; + } +} + +void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) +{ + rhport = _usbd_rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + // only clear if currently stalled + if ( _usbd_dev.ep_status[epnum][dir].stalled ) + { + TU_LOG(USBD_DBG, " Clear Stall EP %02X\r\n", ep_addr); + dcd_edpt_clear_stall(rhport, ep_addr); + _usbd_dev.ep_status[epnum][dir].stalled = false; + _usbd_dev.ep_status[epnum][dir].busy = false; + } +} + +bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + return _usbd_dev.ep_status[epnum][dir].stalled; +} + +/** + * usbd_edpt_close will disable an endpoint. + * + * In progress transfers on this EP may be delivered after this call. + * + */ +void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) +{ + rhport = _usbd_rhport; + + TU_ASSERT(dcd_edpt_close, /**/); + TU_LOG(USBD_DBG, " CLOSING Endpoint: 0x%02X\r\n", ep_addr); + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + dcd_edpt_close(rhport, ep_addr); + _usbd_dev.ep_status[epnum][dir].stalled = false; + _usbd_dev.ep_status[epnum][dir].busy = false; + _usbd_dev.ep_status[epnum][dir].claimed = false; + + return; +} + +void usbd_sof_enable(uint8_t rhport, bool en) +{ + rhport = _usbd_rhport; + + // TODO: Check needed if all drivers including the user sof_cb does not need an active SOF ISR any more. + // Only if all drivers switched off SOF calls the SOF interrupt may be disabled + dcd_sof_enable(rhport, en); +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/device/usbd.h b/test-devices/composite-stm32/lib/tinyusb/device/usbd.h new file mode 100644 index 00000000..17b4d927 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/device/usbd.h @@ -0,0 +1,865 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_USBD_H_ +#define _TUSB_USBD_H_ + +#include "common/tusb_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + +// Init device stack +bool tud_init (uint8_t rhport); + +// Check if device stack is already initialized +bool tud_inited(void); + +// Task function should be called in main/rtos loop, extended version of tud_task() +// - timeout_ms: millisecond to wait, zero = no wait, 0xFFFFFFFF = wait forever +// - in_isr: if function is called in ISR +void tud_task_ext(uint32_t timeout_ms, bool in_isr); + +// Task function should be called in main/rtos loop +TU_ATTR_ALWAYS_INLINE static inline +void tud_task (void) +{ + tud_task_ext(UINT32_MAX, false); +} + +// Check if there is pending events need processing by tud_task() +bool tud_task_event_ready(void); + +#ifndef _TUSB_DCD_H_ +extern void dcd_int_handler(uint8_t rhport); +#endif + +// Interrupt handler, name alias to DCD +#define tud_int_handler dcd_int_handler + +// Get current bus speed +tusb_speed_t tud_speed_get(void); + +// Check if device is connected (may not mounted/configured yet) +// True if just got out of Bus Reset and received the very first data from host +bool tud_connected(void); + +// Check if device is connected and configured +bool tud_mounted(void); + +// Check if device is suspended +bool tud_suspended(void); + +// Check if device is ready to transfer +TU_ATTR_ALWAYS_INLINE static inline +bool tud_ready(void) +{ + return tud_mounted() && !tud_suspended(); +} + +// Remote wake up host, only if suspended and enabled by host +bool tud_remote_wakeup(void); + +// Enable pull-up resistor on D+ D- +// Return false on unsupported MCUs +bool tud_disconnect(void); + +// Disable pull-up resistor on D+ D- +// Return false on unsupported MCUs +bool tud_connect(void); + +// Carry out Data and Status stage of control transfer +// - If len = 0, it is equivalent to sending status only +// - If len > wLength : it will be truncated +bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len); + +// Send STATUS (zero length) packet +bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request); + +//--------------------------------------------------------------------+ +// Application Callbacks (WEAK is optional) +//--------------------------------------------------------------------+ + +// Invoked when received GET DEVICE DESCRIPTOR request +// Application return pointer to descriptor +uint8_t const * tud_descriptor_device_cb(void); + +// Invoked when received GET CONFIGURATION DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +uint8_t const * tud_descriptor_configuration_cb(uint8_t index); + +// Invoked when received GET STRING DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid); + +// Invoked when received GET BOS DESCRIPTOR request +// Application return pointer to descriptor +TU_ATTR_WEAK uint8_t const * tud_descriptor_bos_cb(void); + +// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. +// device_qualifier descriptor describes information about a high-speed capable device that would +// change if the device were operating at the other speed. If not highspeed capable stall this request. +TU_ATTR_WEAK uint8_t const* tud_descriptor_device_qualifier_cb(void); + +// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa +TU_ATTR_WEAK uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index); + +// Invoked when device is mounted (configured) +TU_ATTR_WEAK void tud_mount_cb(void); + +// Invoked when device is unmounted +TU_ATTR_WEAK void tud_umount_cb(void); + +// Invoked when usb bus is suspended +// Within 7ms, device must draw an average of current less than 2.5 mA from bus +TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en); + +// Invoked when usb bus is resumed +TU_ATTR_WEAK void tud_resume_cb(void); + +// Invoked when received control request with VENDOR TYPE +TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + +//--------------------------------------------------------------------+ +// Binary Device Object Store (BOS) Descriptor Templates +//--------------------------------------------------------------------+ + +#define TUD_BOS_DESC_LEN 5 + +// total length, number of device caps +#define TUD_BOS_DESCRIPTOR(_total_len, _caps_num) \ + 5, TUSB_DESC_BOS, U16_TO_U8S_LE(_total_len), _caps_num + +// Device Capability Platform 128-bit UUID + Data +#define TUD_BOS_PLATFORM_DESCRIPTOR(...) \ + 4+TU_ARGS_NUM(__VA_ARGS__), TUSB_DESC_DEVICE_CAPABILITY, DEVICE_CAPABILITY_PLATFORM, 0x00, __VA_ARGS__ + +//------------- WebUSB BOS Platform -------------// + +// Descriptor Length +#define TUD_BOS_WEBUSB_DESC_LEN 24 + +// Vendor Code, iLandingPage +#define TUD_BOS_WEBUSB_DESCRIPTOR(_vendor_code, _ipage) \ + TUD_BOS_PLATFORM_DESCRIPTOR(TUD_BOS_WEBUSB_UUID, U16_TO_U8S_LE(0x0100), _vendor_code, _ipage) + +#define TUD_BOS_WEBUSB_UUID \ + 0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, \ + 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65 + +//------------- Microsoft OS 2.0 Platform -------------// +#define TUD_BOS_MICROSOFT_OS_DESC_LEN 28 + +// Total Length of descriptor set, vendor code +#define TUD_BOS_MS_OS_20_DESCRIPTOR(_desc_set_len, _vendor_code) \ + TUD_BOS_PLATFORM_DESCRIPTOR(TUD_BOS_MS_OS_20_UUID, U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(_desc_set_len), _vendor_code, 0) + +#define TUD_BOS_MS_OS_20_UUID \ + 0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, \ + 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F + +//--------------------------------------------------------------------+ +// Configuration Descriptor Templates +//--------------------------------------------------------------------+ + +#define TUD_CONFIG_DESC_LEN (9) + +// Config number, interface count, string index, total length, attribute, power in mA +#define TUD_CONFIG_DESCRIPTOR(config_num, _itfcount, _stridx, _total_len, _attribute, _power_ma) \ + 9, TUSB_DESC_CONFIGURATION, U16_TO_U8S_LE(_total_len), _itfcount, config_num, _stridx, TU_BIT(7) | _attribute, (_power_ma)/2 + +//--------------------------------------------------------------------+ +// CDC Descriptor Templates +//--------------------------------------------------------------------+ + +// Length of template descriptor: 66 bytes +#define TUD_CDC_DESC_LEN (8+9+5+5+4+5+7+9+7+7) + +// CDC Descriptor Template +// Interface number, string index, EP notification address and size, EP data address (out, in) and size. +#define TUD_CDC_DESCRIPTOR(_itfnum, _stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize) \ + /* Interface Associate */\ + 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_NONE, 0,\ + /* CDC Control Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_NONE, _stridx,\ + /* CDC Header */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\ + /* CDC Call */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (uint8_t)((_itfnum) + 1),\ + /* CDC ACM: support line request */\ + 4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 2,\ + /* CDC Union */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\ + /* Endpoint Notification */\ + 7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 16,\ + /* CDC Data Interface */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0 + +//--------------------------------------------------------------------+ +// MSC Descriptor Templates +//--------------------------------------------------------------------+ + +// Length of template descriptor: 23 bytes +#define TUD_MSC_DESC_LEN (9 + 7 + 7) + +// Interface number, string index, EP Out & EP In address, EP size +#define TUD_MSC_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \ + /* Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_MSC, MSC_SUBCLASS_SCSI, MSC_PROTOCOL_BOT, _stridx,\ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0 + + +//--------------------------------------------------------------------+ +// HID Descriptor Templates +//--------------------------------------------------------------------+ + +// Length of template descriptor: 25 bytes +#define TUD_HID_DESC_LEN (9 + 9 + 7) + +// HID Input only descriptor +// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval +#define TUD_HID_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epin, _epsize, _ep_interval) \ + /* Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? (uint8_t)HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\ + /* HID descriptor */\ + 9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval + +// Length of template descriptor: 32 bytes +#define TUD_HID_INOUT_DESC_LEN (9 + 9 + 7 + 7) + +// HID Input & Output descriptor +// Interface number, string index, protocol, report descriptor len, EP OUT & IN address, size & polling interval +#define TUD_HID_INOUT_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epout, _epin, _epsize, _ep_interval) \ + /* Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? (uint8_t)HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\ + /* HID descriptor */\ + 9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval, \ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval + +//--------------------------------------------------------------------+ +// MIDI Descriptor Templates +// Note: MIDI v1.0 is based on Audio v1.0 +//--------------------------------------------------------------------+ + +#define TUD_MIDI_DESC_HEAD_LEN (9 + 9 + 9 + 7) +#define TUD_MIDI_DESC_HEAD(_itfnum, _stridx, _numcables) \ + /* Audio Control (AC) Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_FUNC_PROTOCOL_CODE_UNDEF, _stridx,\ + /* AC Header */\ + 9, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(0x0009), 1, (uint8_t)((_itfnum) + 1),\ + /* MIDI Streaming (MS) Interface */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum) + 1), 0, 2, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_MIDI_STREAMING, AUDIO_FUNC_PROTOCOL_CODE_UNDEF, 0,\ + /* MS Header */\ + 7, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(7 + (_numcables) * TUD_MIDI_DESC_JACK_LEN) + +#define TUD_MIDI_JACKID_IN_EMB(_cablenum) \ + (uint8_t)(((_cablenum) - 1) * 4 + 1) + +#define TUD_MIDI_JACKID_IN_EXT(_cablenum) \ + (uint8_t)(((_cablenum) - 1) * 4 + 2) + +#define TUD_MIDI_JACKID_OUT_EMB(_cablenum) \ + (uint8_t)(((_cablenum) - 1) * 4 + 3) + +#define TUD_MIDI_JACKID_OUT_EXT(_cablenum) \ + (uint8_t)(((_cablenum) - 1) * 4 + 4) + +#define TUD_MIDI_DESC_JACK_LEN (6 + 6 + 9 + 9) +#define TUD_MIDI_DESC_JACK(_cablenum) \ + /* MS In Jack (Embedded) */\ + 6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_IN_EMB(_cablenum), 0,\ + /* MS In Jack (External) */\ + 6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_IN_EXT(_cablenum), 0,\ + /* MS Out Jack (Embedded), connected to In Jack External */\ + 9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_OUT_EMB(_cablenum), 1, TUD_MIDI_JACKID_IN_EXT(_cablenum), 1, 0,\ + /* MS Out Jack (External), connected to In Jack Embedded */\ + 9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_OUT_EXT(_cablenum), 1, TUD_MIDI_JACKID_IN_EMB(_cablenum), 1, 0 + +#define TUD_MIDI_DESC_EP_LEN(_numcables) (9 + 4 + (_numcables)) +#define TUD_MIDI_DESC_EP(_epout, _epsize, _numcables) \ + /* Endpoint: Note Audio v1.0's endpoint has 9 bytes instead of 7 */\ + 9, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0, 0, 0, \ + /* MS Endpoint (connected to embedded jack) */\ + (uint8_t)(4 + (_numcables)), TUSB_DESC_CS_ENDPOINT, MIDI_CS_ENDPOINT_GENERAL, _numcables + +// Length of template descriptor (88 bytes) +#define TUD_MIDI_DESC_LEN (TUD_MIDI_DESC_HEAD_LEN + TUD_MIDI_DESC_JACK_LEN + TUD_MIDI_DESC_EP_LEN(1) * 2) + +// MIDI simple descriptor +// - 1 Embedded Jack In connected to 1 External Jack Out +// - 1 Embedded Jack out connected to 1 External Jack In +#define TUD_MIDI_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \ + TUD_MIDI_DESC_HEAD(_itfnum, _stridx, 1),\ + TUD_MIDI_DESC_JACK(1),\ + TUD_MIDI_DESC_EP(_epout, _epsize, 1),\ + TUD_MIDI_JACKID_IN_EMB(1),\ + TUD_MIDI_DESC_EP(_epin, _epsize, 1),\ + TUD_MIDI_JACKID_OUT_EMB(1) + +//--------------------------------------------------------------------+ +// Audio v2.0 Descriptor Templates +//--------------------------------------------------------------------+ + +/* Standard Interface Association Descriptor (IAD) */ +#define TUD_AUDIO_DESC_IAD_LEN 8 +#define TUD_AUDIO_DESC_IAD(_firstitfs, _nitfs, _stridx) \ + TUD_AUDIO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, _firstitfs, _nitfs, TUSB_CLASS_AUDIO, AUDIO_FUNCTION_SUBCLASS_UNDEFINED, AUDIO_FUNC_PROTOCOL_CODE_V2, _stridx + +/* Standard AC Interface Descriptor(4.7.1) */ +#define TUD_AUDIO_DESC_STD_AC_LEN 9 +#define TUD_AUDIO_DESC_STD_AC(_itfnum, _nEPs, _stridx) /* _nEPs is 0 or 1 */\ + TUD_AUDIO_DESC_STD_AC_LEN, TUSB_DESC_INTERFACE, _itfnum, /* fixed to zero */ 0x00, _nEPs, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_INT_PROTOCOL_CODE_V2, _stridx + +/* Class-Specific AC Interface Header Descriptor(4.7.2) */ +#define TUD_AUDIO_DESC_CS_AC_LEN 9 +#define TUD_AUDIO_DESC_CS_AC(_bcdADC, _category, _totallen, _ctrl) /* _bcdADC : Audio Device Class Specification Release Number in Binary-Coded Decimal, _category : see audio_function_t, _totallen : Total number of bytes returned for the class-specific AudioControl interface i.e. Clock Source, Unit and Terminal descriptors - Do not include TUD_AUDIO_DESC_CS_AC_LEN, we already do this here*/ \ + TUD_AUDIO_DESC_CS_AC_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_HEADER, U16_TO_U8S_LE(_bcdADC), _category, U16_TO_U8S_LE(_totallen + TUD_AUDIO_DESC_CS_AC_LEN), _ctrl + +/* Clock Source Descriptor(4.7.2.1) */ +#define TUD_AUDIO_DESC_CLK_SRC_LEN 8 +#define TUD_AUDIO_DESC_CLK_SRC(_clkid, _attr, _ctrl, _assocTerm, _stridx) \ + TUD_AUDIO_DESC_CLK_SRC_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE, _clkid, _attr, _ctrl, _assocTerm, _stridx + +/* Input Terminal Descriptor(4.7.2.4) */ +#define TUD_AUDIO_DESC_INPUT_TERM_LEN 17 +#define TUD_AUDIO_DESC_INPUT_TERM(_termid, _termtype, _assocTerm, _clkid, _nchannelslogical, _channelcfg, _idxchannelnames, _ctrl, _stridx) \ + TUD_AUDIO_DESC_INPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL, _termid, U16_TO_U8S_LE(_termtype), _assocTerm, _clkid, _nchannelslogical, U32_TO_U8S_LE(_channelcfg), _idxchannelnames, U16_TO_U8S_LE(_ctrl), _stridx + +/* Output Terminal Descriptor(4.7.2.5) */ +#define TUD_AUDIO_DESC_OUTPUT_TERM_LEN 12 +#define TUD_AUDIO_DESC_OUTPUT_TERM(_termid, _termtype, _assocTerm, _srcid, _clkid, _ctrl, _stridx) \ + TUD_AUDIO_DESC_OUTPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL, _termid, U16_TO_U8S_LE(_termtype), _assocTerm, _srcid, _clkid, U16_TO_U8S_LE(_ctrl), _stridx + +/* Feature Unit Descriptor(4.7.2.8) */ +// 1 - Channel +#define TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN 6+(1+1)*4 +#define TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(_unitid, _srcid, _ctrlch0master, _ctrlch1, _stridx) \ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1), _stridx + +// 2 - Channels +#define TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN (6+(2+1)*4) +#define TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(_unitid, _srcid, _ctrlch0master, _ctrlch1, _ctrlch2, _stridx) \ + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1), U32_TO_U8S_LE(_ctrlch2), _stridx +// 4 - Channels +#define TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN (6+(4+1)*4) +#define TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL(_unitid, _srcid, _ctrlch0master, _ctrlch1, _ctrlch2, _ctrlch3, _ctrlch4, _stridx) \ + TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1), U32_TO_U8S_LE(_ctrlch2), U32_TO_U8S_LE(_ctrlch3), U32_TO_U8S_LE(_ctrlch4), _stridx + +// For more channels, add definitions here + +/* Standard AS Interface Descriptor(4.9.1) */ +#define TUD_AUDIO_DESC_STD_AS_INT_LEN 9 +#define TUD_AUDIO_DESC_STD_AS_INT(_itfnum, _altset, _nEPs, _stridx) \ + TUD_AUDIO_DESC_STD_AS_INT_LEN, TUSB_DESC_INTERFACE, _itfnum, _altset, _nEPs, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_STREAMING, AUDIO_INT_PROTOCOL_CODE_V2, _stridx + +/* Class-Specific AS Interface Descriptor(4.9.2) */ +#define TUD_AUDIO_DESC_CS_AS_INT_LEN 16 +#define TUD_AUDIO_DESC_CS_AS_INT(_termid, _ctrl, _formattype, _formats, _nchannelsphysical, _channelcfg, _stridx) \ + TUD_AUDIO_DESC_CS_AS_INT_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AS_INTERFACE_AS_GENERAL, _termid, _ctrl, _formattype, U32_TO_U8S_LE(_formats), _nchannelsphysical, U32_TO_U8S_LE(_channelcfg), _stridx + +/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ +#define TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN 6 +#define TUD_AUDIO_DESC_TYPE_I_FORMAT(_subslotsize, _bitresolution) /* _subslotsize is number of bytes per sample (i.e. subslot) and can be 1,2,3, or 4 */\ + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AS_INTERFACE_FORMAT_TYPE, AUDIO_FORMAT_TYPE_I, _subslotsize, _bitresolution + +/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ +#define TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN 7 +#define TUD_AUDIO_DESC_STD_AS_ISO_EP(_ep, _attr, _maxEPsize, _interval) \ + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN, TUSB_DESC_ENDPOINT, _ep, _attr, U16_TO_U8S_LE(_maxEPsize), _interval + +/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ +#define TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN 8 +#define TUD_AUDIO_DESC_CS_AS_ISO_EP(_attr, _ctrl, _lockdelayunit, _lockdelay) \ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN, TUSB_DESC_CS_ENDPOINT, AUDIO_CS_EP_SUBTYPE_GENERAL, _attr, _ctrl, _lockdelayunit, U16_TO_U8S_LE(_lockdelay) + +/* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */ +#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN 7 +#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_ep, _interval) \ + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_NO_SYNC | TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval + +// AUDIO simple descriptor (UAC2) for 1 microphone input +// - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source + +#define TUD_AUDIO_MIC_ONE_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ + + TUD_AUDIO_DESC_STD_AC_LEN\ + + TUD_AUDIO_DESC_CS_AC_LEN\ + + TUD_AUDIO_DESC_CLK_SRC_LEN\ + + TUD_AUDIO_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) + +#define TUD_AUDIO_MIC_ONE_CH_DESC_N_AS_INT 1 // Number of AS interfaces + +#define TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ + /* Standard Interface Association Descriptor (IAD) */\ + TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + /* Standard AC Interface Descriptor(4.7.1) */\ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ + /* Clock Source Descriptor(4.7.2.1) */\ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ + /* Input Terminal Descriptor(4.7.2.4) */\ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x03, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00),\ + /* Output Terminal Descriptor(4.7.2.5) */\ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + /* Feature Unit Descriptor(4.7.2.8) */\ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */\ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */\ + /* Interface 1, Alternate 1 - alternate interface for data streaming */\ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ + /* Class-Specific AS Interface Descriptor(4.9.2) */\ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x03, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + +// AUDIO simple descriptor (UAC2) for 4 microphone input +// - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source + +#define TUD_AUDIO_MIC_FOUR_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ + + TUD_AUDIO_DESC_STD_AC_LEN\ + + TUD_AUDIO_DESC_CS_AC_LEN\ + + TUD_AUDIO_DESC_CLK_SRC_LEN\ + + TUD_AUDIO_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) + +#define TUD_AUDIO_MIC_FOUR_CH_DESC_N_AS_INT 1 // Number of AS interfaces + +#define TUD_AUDIO_MIC_FOUR_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ + /* Standard Interface Association Descriptor (IAD) */\ + TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + /* Standard AC Interface Descriptor(4.7.1) */\ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ + /* Clock Source Descriptor(4.7.2.1) */\ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ + /* Input Terminal Descriptor(4.7.2.4) */\ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x03, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x04, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00),\ + /* Output Terminal Descriptor(4.7.2.5) */\ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + /* Feature Unit Descriptor(4.7.2.8) */\ + TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch3*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch4*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */\ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */\ + /* Interface 1, Alternate 1 - alternate interface for data streaming */\ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ + /* Class-Specific AS Interface Descriptor(4.9.2) */\ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x03, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x04, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + +// AUDIO simple descriptor (UAC2) for mono speaker +// - 1 Input Terminal, 2 Feature Unit (Mute and Volume Control), 3 Output Terminal, 4 Clock Source + +#define TUD_AUDIO_SPEAKER_MONO_FB_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ + + TUD_AUDIO_DESC_STD_AC_LEN\ + + TUD_AUDIO_DESC_CS_AC_LEN\ + + TUD_AUDIO_DESC_CLK_SRC_LEN\ + + TUD_AUDIO_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\ + + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN) + +#define TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize, _epfb) \ + /* Standard Interface Association Descriptor (IAD) */\ + TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + /* Standard AC Interface Descriptor(4.7.1) */\ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ + /* Clock Source Descriptor(4.7.2.1) */\ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ + /* Input Terminal Descriptor(4.7.2.4) */\ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ + /* Output Terminal Descriptor(4.7.2.5) */\ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + /* Feature Unit Descriptor(4.7.2.8) */\ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ 0 * (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch1*/ 0 * (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */\ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */\ + /* Interface 1, Alternate 1 - alternate interface for data streaming */\ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x02, /*_stridx*/ 0x00),\ + /* Class-Specific AS Interface Descriptor(4.9.2) */\ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\ + /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\ + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_interval*/ 1)\ + +// Calculate wMaxPacketSize of Endpoints +#define TUD_AUDIO_EP_SIZE(_maxFrequency, _nBytesPerSample, _nChannels) \ + ((((_maxFrequency + (TUD_OPT_HIGH_SPEED ? 7999 : 999)) / (TUD_OPT_HIGH_SPEED ? 8000 : 1000)) + 1) * _nBytesPerSample * _nChannels) + + +//--------------------------------------------------------------------+ +// USBTMC/USB488 Descriptor Templates +//--------------------------------------------------------------------+ + +#define TUD_USBTMC_APP_CLASS (TUSB_CLASS_APPLICATION_SPECIFIC) +#define TUD_USBTMC_APP_SUBCLASS 0x03u + +#define TUD_USBTMC_PROTOCOL_STD 0x00u +#define TUD_USBTMC_PROTOCOL_USB488 0x01u + +// Interface number, number of endpoints, EP string index, USB_TMC_PROTOCOL*, bulk-out endpoint ID, +// bulk-in endpoint ID +#define TUD_USBTMC_IF_DESCRIPTOR(_itfnum, _bNumEndpoints, _stridx, _itfProtocol) \ + /* Interface */ \ + 0x09, TUSB_DESC_INTERFACE, _itfnum, 0x00, _bNumEndpoints, TUD_USBTMC_APP_CLASS, TUD_USBTMC_APP_SUBCLASS, _itfProtocol, _stridx + +#define TUD_USBTMC_IF_DESCRIPTOR_LEN 9u + +#define TUD_USBTMC_BULK_DESCRIPTORS(_epout, _epin, _bulk_epsize) \ + /* Endpoint Out */ \ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u, \ + /* Endpoint In */ \ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u + +#define TUD_USBTMC_BULK_DESCRIPTORS_LEN (7u+7u) + +/* optional interrupt endpoint */ \ +// _int_pollingInterval : for LS/FS, expressed in frames (1ms each). 16 may be a good number? +#define TUD_USBTMC_INT_DESCRIPTOR(_ep_interrupt, _ep_interrupt_size, _int_pollingInterval ) \ + 7, TUSB_DESC_ENDPOINT, _ep_interrupt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_interrupt_size), 0x16 + +#define TUD_USBTMC_INT_DESCRIPTOR_LEN (7u) + +//--------------------------------------------------------------------+ +// Vendor Descriptor Templates +//--------------------------------------------------------------------+ + +#define TUD_VENDOR_DESC_LEN (9+7+7) + +// Interface number, string index, EP Out & IN address, EP size +#define TUD_VENDOR_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \ + /* Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_VENDOR_SPECIFIC, 0x00, 0x00, _stridx,\ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0 + +//--------------------------------------------------------------------+ +// DFU Runtime Descriptor Templates +//--------------------------------------------------------------------+ + +#define TUD_DFU_APP_CLASS (TUSB_CLASS_APPLICATION_SPECIFIC) +#define TUD_DFU_APP_SUBCLASS (APP_SUBCLASS_DFU_RUNTIME) + +// Length of template descriptr: 18 bytes +#define TUD_DFU_RT_DESC_LEN (9 + 9) + +// DFU runtime descriptor +// Interface number, string index, attributes, detach timeout, transfer size +#define TUD_DFU_RT_DESCRIPTOR(_itfnum, _stridx, _attr, _timeout, _xfer_size) \ + /* Interface */ \ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUD_DFU_APP_CLASS, TUD_DFU_APP_SUBCLASS, DFU_PROTOCOL_RT, _stridx, \ + /* Function */ \ + 9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0101) + +//--------------------------------------------------------------------+ +// DFU Descriptor Templates +//--------------------------------------------------------------------+ + +// Length of template descriptor: 9 bytes + number of alternatives * 9 +#define TUD_DFU_DESC_LEN(_alt_count) (9 + (_alt_count) * 9) + +// Interface number, Alternate count, starting string index, attributes, detach timeout, transfer size +// Note: Alternate count must be numberic or macro, string index is increased by one for each Alt interface +#define TUD_DFU_DESCRIPTOR(_itfnum, _alt_count, _stridx, _attr, _timeout, _xfer_size) \ + TU_XSTRCAT(_TUD_DFU_ALT_,_alt_count)(_itfnum, 0, _stridx), \ + /* Function */ \ + 9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0101) + +#define _TUD_DFU_ALT(_itfnum, _alt, _stridx) \ + /* Interface */ \ + 9, TUSB_DESC_INTERFACE, _itfnum, _alt, 0, TUD_DFU_APP_CLASS, TUD_DFU_APP_SUBCLASS, DFU_PROTOCOL_DFU, _stridx + +#define _TUD_DFU_ALT_1(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx) + +#define _TUD_DFU_ALT_2(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \ + _TUD_DFU_ALT_1(_itfnum, _alt_count+1, _stridx+1) + +#define _TUD_DFU_ALT_3(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \ + _TUD_DFU_ALT_2(_itfnum, _alt_count+1, _stridx+1) + +#define _TUD_DFU_ALT_4(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \ + _TUD_DFU_ALT_3(_itfnum, _alt_count+1, _stridx+1) + +#define _TUD_DFU_ALT_5(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \ + _TUD_DFU_ALT_4(_itfnum, _alt_count+1, _stridx+1) + +#define _TUD_DFU_ALT_6(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \ + _TUD_DFU_ALT_5(_itfnum, _alt_count+1, _stridx+1) + +#define _TUD_DFU_ALT_7(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \ + _TUD_DFU_ALT_6(_itfnum, _alt_count+1, _stridx+1) + +#define _TUD_DFU_ALT_8(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \ + _TUD_DFU_ALT_7(_itfnum, _alt_count+1, _stridx+1) + +//--------------------------------------------------------------------+ +// CDC-ECM Descriptor Templates +//--------------------------------------------------------------------+ + +// Length of template descriptor: 71 bytes +#define TUD_CDC_ECM_DESC_LEN (8+9+5+5+13+7+9+9+7+7) + +// CDC-ECM Descriptor Template +// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size. +#define TUD_CDC_ECM_DESCRIPTOR(_itfnum, _desc_stridx, _mac_stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize, _maxsegmentsize) \ + /* Interface Association */\ + 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL, 0, 0,\ + /* CDC Control Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL, 0, _desc_stridx,\ + /* CDC-ECM Header */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\ + /* CDC-ECM Union */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\ + /* CDC-ECM Functional Descriptor */\ + 13, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ETHERNET_NETWORKING, _mac_stridx, 0, 0, 0, 0, U16_TO_U8S_LE(_maxsegmentsize), U16_TO_U8S_LE(0), 0,\ + /* Endpoint Notification */\ + 7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 1,\ + /* CDC Data Interface (default inactive) */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 0, TUSB_CLASS_CDC_DATA, 0, 0, 0,\ + /* CDC Data Interface (alternative active) */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 1, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0 + +//--------------------------------------------------------------------+ +// RNDIS Descriptor Templates +//--------------------------------------------------------------------+ + +#if 0 +/* Windows XP */ +#define TUD_RNDIS_ITF_CLASS TUSB_CLASS_CDC +#define TUD_RNDIS_ITF_SUBCLASS CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL +#define TUD_RNDIS_ITF_PROTOCOL 0xFF /* CDC_COMM_PROTOCOL_MICROSOFT_RNDIS */ +#else +/* Windows 7+ */ +#define TUD_RNDIS_ITF_CLASS TUSB_CLASS_WIRELESS_CONTROLLER +#define TUD_RNDIS_ITF_SUBCLASS 0x01 +#define TUD_RNDIS_ITF_PROTOCOL 0x03 +#endif + +// Length of template descriptor: 66 bytes +#define TUD_RNDIS_DESC_LEN (8+9+5+5+4+5+7+9+7+7) + +// RNDIS Descriptor Template +// Interface number, string index, EP notification address and size, EP data address (out, in) and size. +#define TUD_RNDIS_DESCRIPTOR(_itfnum, _stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize) \ + /* Interface Association */\ + 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUD_RNDIS_ITF_CLASS, TUD_RNDIS_ITF_SUBCLASS, TUD_RNDIS_ITF_PROTOCOL, 0,\ + /* CDC Control Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUD_RNDIS_ITF_CLASS, TUD_RNDIS_ITF_SUBCLASS, TUD_RNDIS_ITF_PROTOCOL, _stridx,\ + /* CDC-ACM Header */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0110),\ + /* CDC Call Management */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (uint8_t)((_itfnum) + 1),\ + /* ACM */\ + 4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 0,\ + /* CDC Union */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\ + /* Endpoint Notification */\ + 7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 1,\ + /* CDC Data Interface */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0 + +//--------------------------------------------------------------------+ +// Bluetooth Radio Descriptor Templates +//--------------------------------------------------------------------+ + +#define TUD_BT_APP_CLASS (TUSB_CLASS_WIRELESS_CONTROLLER) +#define TUD_BT_APP_SUBCLASS 0x01 +#define TUD_BT_PROTOCOL_PRIMARY_CONTROLLER 0x01 +#define TUD_BT_PROTOCOL_AMP_CONTROLLER 0x02 + +#ifndef CFG_TUD_BTH_ISO_ALT_COUNT +#define CFG_TUD_BTH_ISO_ALT_COUNT 0 +#endif + +// Length of template descriptor: 38 bytes + number of ISO alternatives * 23 +#define TUD_BTH_DESC_LEN (8 + 9 + 7 + 7 + 7 + (CFG_TUD_BTH_ISO_ALT_COUNT) * (9 + 7 + 7)) + +/* Primary Interface */ +#define TUD_BTH_PRI_ITF(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size) \ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 3, TUD_BT_APP_CLASS, TUD_BT_APP_SUBCLASS, TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, _stridx, \ + /* Endpoint In for events */ \ + 7, TUSB_DESC_ENDPOINT, _ep_evt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_evt_size), _ep_evt_interval, \ + /* Endpoint In for ACL data */ \ + 7, TUSB_DESC_ENDPOINT, _ep_in, TUSB_XFER_BULK, U16_TO_U8S_LE(_ep_size), 1, \ + /* Endpoint Out for ACL data */ \ + 7, TUSB_DESC_ENDPOINT, _ep_out, TUSB_XFER_BULK, U16_TO_U8S_LE(_ep_size), 1 + +#define TUD_BTH_ISO_ITF(_itfnum, _alt, _ep_in, _ep_out, _n) ,\ + /* Interface with 2 endpoints */ \ + 9, TUSB_DESC_INTERFACE, _itfnum, _alt, 2, TUD_BT_APP_CLASS, TUD_BT_APP_SUBCLASS, TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, 0, \ + /* Isochronous endpoints */ \ + 7, TUSB_DESC_ENDPOINT, _ep_in, TUSB_XFER_ISOCHRONOUS, U16_TO_U8S_LE(_n), 1, \ + 7, TUSB_DESC_ENDPOINT, _ep_out, TUSB_XFER_ISOCHRONOUS, U16_TO_U8S_LE(_n), 1 + +#define _FIRST(a, ...) a +#define _REST(a, ...) __VA_ARGS__ + +#define TUD_BTH_ISO_ITF_0(_itfnum, ...) +#define TUD_BTH_ISO_ITF_1(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 1, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) +#define TUD_BTH_ISO_ITF_2(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 2, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \ + TUD_BTH_ISO_ITF_1(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__)) +#define TUD_BTH_ISO_ITF_3(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 3, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \ + TUD_BTH_ISO_ITF_2(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__)) +#define TUD_BTH_ISO_ITF_4(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 4, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \ + TUD_BTH_ISO_ITF_3(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__)) +#define TUD_BTH_ISO_ITF_5(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 5, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \ + TUD_BTH_ISO_ITF_4(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__)) +#define TUD_BTH_ISO_ITF_6(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 6, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \ + TUD_BTH_ISO_ITF_5(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__)) + +#define TUD_BTH_ISO_ITFS(_itfnum, _ep_in, _ep_out, ...) \ + TU_XSTRCAT(TUD_BTH_ISO_ITF_, CFG_TUD_BTH_ISO_ALT_COUNT)(_itfnum, _ep_in, _ep_out, __VA_ARGS__) + +// BT Primary controller descriptor +// Interface number, string index, attributes, event endpoint, event endpoint size, interval, data in, data out, data endpoint size, iso endpoint sizes +// TODO BTH should also use IAD like CDC for composite device +#define TUD_BTH_DESCRIPTOR(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size,...) \ + /* Interface Associate */\ + 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUD_BT_APP_CLASS, TUD_BT_APP_SUBCLASS, TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, 0,\ + TUD_BTH_PRI_ITF(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size) \ + TUD_BTH_ISO_ITFS(_itfnum + 1, _ep_in + 1, _ep_out + 1, __VA_ARGS__) + +//--------------------------------------------------------------------+ +// CDC-NCM Descriptor Templates +//--------------------------------------------------------------------+ + +// Length of template descriptor +#define TUD_CDC_NCM_DESC_LEN (8+9+5+5+13+6+7+9+9+7+7) + +// CDC-ECM Descriptor Template +// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size. +#define TUD_CDC_NCM_DESCRIPTOR(_itfnum, _desc_stridx, _mac_stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize, _maxsegmentsize) \ + /* Interface Association */\ + 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_NETWORK_CONTROL_MODEL, 0, 0,\ + /* CDC Control Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_NETWORK_CONTROL_MODEL, 0, _desc_stridx,\ + /* CDC-NCM Header */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0110),\ + /* CDC-NCM Union */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\ + /* CDC-NCM Functional Descriptor */\ + 13, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ETHERNET_NETWORKING, _mac_stridx, 0, 0, 0, 0, U16_TO_U8S_LE(_maxsegmentsize), U16_TO_U8S_LE(0), 0, \ + /* CDC-NCM Functional Descriptor */\ + 6, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_NCM, U16_TO_U8S_LE(0x0100), 0, \ + /* Endpoint Notification */\ + 7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 50,\ + /* CDC Data Interface (default inactive) */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 0, TUSB_CLASS_CDC_DATA, 0, NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK, 0,\ + /* CDC Data Interface (alternative active) */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 1, 2, TUSB_CLASS_CDC_DATA, 0, NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK, 0,\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0 + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_USBD_H_ */ + +/** @} */ diff --git a/test-devices/composite-stm32/lib/tinyusb/device/usbd_control.c b/test-devices/composite-stm32/lib/tinyusb/device/usbd_control.c new file mode 100644 index 00000000..0995ef66 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/device/usbd_control.c @@ -0,0 +1,233 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUD_ENABLED + +#include "dcd.h" +#include "tusb.h" +#include "device/usbd_pvt.h" + +#if CFG_TUSB_DEBUG >= 2 +extern void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback); +#endif + +enum +{ + EDPT_CTRL_OUT = 0x00, + EDPT_CTRL_IN = 0x80 +}; + +typedef struct +{ + tusb_control_request_t request; + + uint8_t* buffer; + uint16_t data_len; + uint16_t total_xferred; + + usbd_control_xfer_cb_t complete_cb; +} usbd_control_xfer_t; + +static usbd_control_xfer_t _ctrl_xfer; + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN +static uint8_t _usbd_ctrl_buf[CFG_TUD_ENDPOINT0_SIZE]; + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + +// Queue ZLP status transaction +static inline bool _status_stage_xact(uint8_t rhport, tusb_control_request_t const * request) +{ + // Opposite to endpoint in Data Phase + uint8_t const ep_addr = request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN; + return usbd_edpt_xfer(rhport, ep_addr, NULL, 0); +} + +// Status phase +bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request) +{ + _ctrl_xfer.request = (*request); + _ctrl_xfer.buffer = NULL; + _ctrl_xfer.total_xferred = 0; + _ctrl_xfer.data_len = 0; + + return _status_stage_xact(rhport, request); +} + +// Queue a transaction in Data Stage +// Each transaction has up to Endpoint0's max packet size. +// This function can also transfer an zero-length packet +static bool _data_stage_xact(uint8_t rhport) +{ + uint16_t const xact_len = tu_min16(_ctrl_xfer.data_len - _ctrl_xfer.total_xferred, CFG_TUD_ENDPOINT0_SIZE); + + uint8_t ep_addr = EDPT_CTRL_OUT; + + if ( _ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN ) + { + ep_addr = EDPT_CTRL_IN; + if ( xact_len ) memcpy(_usbd_ctrl_buf, _ctrl_xfer.buffer, xact_len); + } + + return usbd_edpt_xfer(rhport, ep_addr, xact_len ? _usbd_ctrl_buf : NULL, xact_len); +} + +// Transmit data to/from the control endpoint. +// If the request's wLength is zero, a status packet is sent instead. +bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len) +{ + _ctrl_xfer.request = (*request); + _ctrl_xfer.buffer = (uint8_t*) buffer; + _ctrl_xfer.total_xferred = 0U; + _ctrl_xfer.data_len = tu_min16(len, request->wLength); + + if (request->wLength > 0U) + { + if(_ctrl_xfer.data_len > 0U) + { + TU_ASSERT(buffer); + } + +// TU_LOG2(" Control total data length is %u bytes\r\n", _ctrl_xfer.data_len); + + // Data stage + TU_ASSERT( _data_stage_xact(rhport) ); + } + else + { + // Status stage + TU_ASSERT( _status_stage_xact(rhport, request) ); + } + + return true; +} + +//--------------------------------------------------------------------+ +// USBD API +//--------------------------------------------------------------------+ + +void usbd_control_reset(void); +void usbd_control_set_request(tusb_control_request_t const *request); +void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp ); +bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); + +void usbd_control_reset(void) +{ + tu_varclr(&_ctrl_xfer); +} + +// Set complete callback +void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp ) +{ + _ctrl_xfer.complete_cb = fp; +} + +// for dcd_set_address where DCD is responsible for status response +void usbd_control_set_request(tusb_control_request_t const *request) +{ + _ctrl_xfer.request = (*request); + _ctrl_xfer.buffer = NULL; + _ctrl_xfer.total_xferred = 0; + _ctrl_xfer.data_len = 0; +} + +// callback when a transaction complete on +// - DATA stage of control endpoint or +// - Status stage +bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) result; + + // Endpoint Address is opposite to direction bit, this is Status Stage complete event + if ( tu_edpt_dir(ep_addr) != _ctrl_xfer.request.bmRequestType_bit.direction ) + { + TU_ASSERT(0 == xferred_bytes); + + // invoke optional dcd hook if available + if (dcd_edpt0_status_complete) dcd_edpt0_status_complete(rhport, &_ctrl_xfer.request); + + if (_ctrl_xfer.complete_cb) + { + // TODO refactor with usbd_driver_print_control_complete_name + _ctrl_xfer.complete_cb(rhport, CONTROL_STAGE_ACK, &_ctrl_xfer.request); + } + + return true; + } + + if ( _ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_OUT ) + { + TU_VERIFY(_ctrl_xfer.buffer); + memcpy(_ctrl_xfer.buffer, _usbd_ctrl_buf, xferred_bytes); + TU_LOG_MEM(2, _usbd_ctrl_buf, xferred_bytes, 2); + } + + _ctrl_xfer.total_xferred += (uint16_t) xferred_bytes; + _ctrl_xfer.buffer += xferred_bytes; + + // Data Stage is complete when all request's length are transferred or + // a short packet is sent including zero-length packet. + if ( (_ctrl_xfer.request.wLength == _ctrl_xfer.total_xferred) || (xferred_bytes < CFG_TUD_ENDPOINT0_SIZE) ) + { + // DATA stage is complete + bool is_ok = true; + + // invoke complete callback if set + // callback can still stall control in status phase e.g out data does not make sense + if ( _ctrl_xfer.complete_cb ) + { + #if CFG_TUSB_DEBUG >= 2 + usbd_driver_print_control_complete_name(_ctrl_xfer.complete_cb); + #endif + + is_ok = _ctrl_xfer.complete_cb(rhport, CONTROL_STAGE_DATA, &_ctrl_xfer.request); + } + + if ( is_ok ) + { + // Send status + TU_ASSERT( _status_stage_xact(rhport, &_ctrl_xfer.request) ); + }else + { + // Stall both IN and OUT control endpoint + dcd_edpt_stall(rhport, EDPT_CTRL_OUT); + dcd_edpt_stall(rhport, EDPT_CTRL_IN); + } + } + else + { + // More data to transfer + TU_ASSERT( _data_stage_xact(rhport) ); + } + + return true; +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/device/usbd_pvt.h b/test-devices/composite-stm32/lib/tinyusb/device/usbd_pvt.h new file mode 100644 index 00000000..6fad46db --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/device/usbd_pvt.h @@ -0,0 +1,121 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ +#ifndef USBD_PVT_H_ +#define USBD_PVT_H_ + +#include "osal/osal.h" +#include "common/tusb_fifo.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Class Driver API +//--------------------------------------------------------------------+ + +typedef struct +{ + #if CFG_TUSB_DEBUG >= 2 + char const* name; + #endif + + void (* init ) (void); + void (* reset ) (uint8_t rhport); + uint16_t (* open ) (uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t max_len); + bool (* control_xfer_cb ) (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + bool (* xfer_cb ) (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); + void (* sof ) (uint8_t rhport, uint32_t frame_count); // optional +} usbd_class_driver_t; + +// Invoked when initializing device stack to get additional class drivers. +// Can optionally implemented by application to extend/overwrite class driver support. +// Note: The drivers array must be accessible at all time when stack is active +usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) TU_ATTR_WEAK; + +typedef bool (*usbd_control_xfer_cb_t)(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + +void usbd_int_set(bool enabled); + +//--------------------------------------------------------------------+ +// USBD Endpoint API +// Note: rhport should be 0 since device stack only support 1 rhport for now +//--------------------------------------------------------------------+ + +// Open an endpoint +bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep); + +// Close an endpoint +void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr); + +// Submit a usb transfer +bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); + +// Submit a usb ISO transfer by use of a FIFO (ring buffer) - all bytes in FIFO get transmitted +bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes); + +// Claim an endpoint before submitting a transfer. +// If caller does not make any transfer, it must release endpoint for others. +bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr); + +// Release claimed endpoint without submitting a transfer +bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr); + +// Check if endpoint is busy transferring +bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr); + +// Stall endpoint +void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr); + +// Clear stalled endpoint +void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr); + +// Check if endpoint is stalled +bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr); + +// Check if endpoint is ready (not busy and not stalled) +TU_ATTR_ALWAYS_INLINE static inline +bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr) +{ + return !usbd_edpt_busy(rhport, ep_addr) && !usbd_edpt_stalled(rhport, ep_addr); +} + +// Enable SOF interrupt +void usbd_sof_enable(uint8_t rhport, bool en); + +/*------------------------------------------------------------------*/ +/* Helper + *------------------------------------------------------------------*/ + +bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in); +void usbd_defer_func( osal_task_func_t func, void* param, bool in_isr ); + + +#ifdef __cplusplus + } +#endif + +#endif /* USBD_PVT_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dcd_dwc2.c b/test-devices/composite-stm32/lib/tinyusb/dwc2/dcd_dwc2.c new file mode 100644 index 00000000..f5ecdfe4 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/dwc2/dcd_dwc2.c @@ -0,0 +1,1351 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 William D. Jones + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2020 Jan Duempelmann + * Copyright (c) 2020 Reinhard Panhuber + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUD_ENABLED && defined(TUP_USBIP_DWC2) + +#include "device/dcd.h" +#include "dwc2_type.h" + +// Following symbols must be defined by port header +// - _dwc2_controller[]: array of controllers +// - DWC2_EP_MAX: largest EP counts of all controllers +// - dwc2_phy_init/dwc2_phy_update: phy init called before and after core reset +// - dwc2_dcd_int_enable/dwc2_dcd_int_disable +// - dwc2_remote_wakeup_delay + +#if defined(TUP_USBIP_DWC2_STM32) + #include "dwc2_stm32.h" +#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + #include "dwc2_esp32.h" +#elif TU_CHECK_MCU(OPT_MCU_GD32VF103) + #include "dwc2_gd32.h" +#elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837) + #include "dwc2_bcm.h" +#elif TU_CHECK_MCU(OPT_MCU_EFM32GG) + #include "dwc2_efm32.h" +#elif TU_CHECK_MCU(OPT_MCU_XMC4000) + #include "dwc2_xmc.h" +#else + #error "Unsupported MCUs" +#endif + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM +//--------------------------------------------------------------------+ + +// DWC2 registers +#define DWC2_REG(_port) ((dwc2_regs_t*) _dwc2_controller[_port].reg_base) + +// Debug level for DWC2 +#define DWC2_DEBUG 2 + +#ifndef dcache_clean +#define dcache_clean(_addr, _size) +#endif + +#ifndef dcache_invalidate +#define dcache_invalidate(_addr, _size) +#endif + +#ifndef dcache_clean_invalidate +#define dcache_clean_invalidate(_addr, _size) +#endif + +static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2]; + +typedef struct { + uint8_t * buffer; + tu_fifo_t * ff; + uint16_t total_len; + uint16_t max_size; + uint8_t interval; +} xfer_ctl_t; + +static xfer_ctl_t xfer_status[DWC2_EP_MAX][2]; +#define XFER_CTL_BASE(_ep, _dir) (&xfer_status[_ep][_dir]) + +// EP0 transfers are limited to 1 packet - larger sizes has to be split +static uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type + +// TX FIFO RAM allocation so far in words - RX FIFO size is readily available from dwc2->grxfsiz +static uint16_t _allocated_fifo_words_tx; // TX FIFO size in words (IN EPs) +static bool _out_ep_closed; // Flag to check if RX FIFO size needs an update (reduce its size) + +// SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by +static bool _sof_en; + +// Calculate the RX FIFO size according to recommendations from reference manual +static inline uint16_t calc_grxfsiz(uint16_t max_ep_size, uint8_t ep_count) +{ + return 15 + 2*(max_ep_size/4) + 2*ep_count; +} + +static void update_grxfsiz(uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + + // Determine largest EP size for RX FIFO + uint16_t max_epsize = 0; + for (uint8_t epnum = 0; epnum < ep_count; epnum++) + { + max_epsize = tu_max16(max_epsize, xfer_status[epnum][TUSB_DIR_OUT].max_size); + } + + // Update size of RX FIFO + dwc2->grxfsiz = calc_grxfsiz(max_epsize, ep_count); +} + +// Start of Bus Reset +static void bus_reset(uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + + tu_memclr(xfer_status, sizeof(xfer_status)); + _out_ep_closed = false; + + _sof_en = false; + + // clear device address + dwc2->dcfg &= ~DCFG_DAD_Msk; + + // 1. NAK for all OUT endpoints + for ( uint8_t n = 0; n < ep_count; n++ ) + { + dwc2->epout[n].doepctl |= DOEPCTL_SNAK; + } + + // 2. Set up interrupt mask + dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos); + dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM; + dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM; + + // "USB Data FIFOs" section in reference manual + // Peripheral FIFO architecture + // + // The FIFO is split up in a lower part where the RX FIFO is located and an upper part where the TX FIFOs start. + // We do this to allow the RX FIFO to grow dynamically which is possible since the free space is located + // between the RX and TX FIFOs. This is required by ISO OUT EPs which need a bigger FIFO than the standard + // configuration done below. + // + // Dynamically FIFO sizes are of interest only for ISO EPs since all others are usually not opened and closed. + // All EPs other than ISO are opened as soon as the driver starts up i.e. when the host sends a + // configure interface command. Hence, all IN EPs other the ISO will be located at the top. IN ISO EPs are usually + // opened when the host sends an additional command: setInterface. At this point in time + // the ISO EP will be located next to the free space and can change its size. In case more IN EPs change its size + // an additional memory + // + // --------------- 320 or 1024 ( 1280 or 4096 bytes ) + // | IN FIFO 0 | + // --------------- (320 or 1024) - 16 + // | IN FIFO 1 | + // --------------- (320 or 1024) - 16 - x + // | . . . . | + // --------------- (320 or 1024) - 16 - x - y - ... - z + // | IN FIFO MAX | + // --------------- + // | FREE | + // --------------- GRXFSIZ + // | OUT FIFO | + // | ( Shared ) | + // --------------- 0 + // + // According to "FIFO RAM allocation" section in RM, FIFO RAM are allocated as follows (each word 32-bits): + // - Each EP IN needs at least max packet size, 16 words is sufficient for EP0 IN + // + // - All EP OUT shared a unique OUT FIFO which uses + // - 13 for setup packets + control words (up to 3 setup packets). + // - 1 for global NAK (not required/used here). + // - Largest-EPsize / 4 + 1. ( FS: 64 bytes, HS: 512 bytes). Recommended is "2 x (Largest-EPsize/4) + 1" + // - 2 for each used OUT endpoint + // + // Therefore GRXFSIZ = 13 + 1 + 1 + 2 x (Largest-EPsize/4) + 2 x EPOUTnum + // - FullSpeed (64 Bytes ): GRXFSIZ = 15 + 2 x 16 + 2 x ep_count = 47 + 2 x ep_count + // - Highspeed (512 bytes): GRXFSIZ = 15 + 2 x 128 + 2 x ep_count = 271 + 2 x ep_count + // + // NOTE: Largest-EPsize & EPOUTnum is actual used endpoints in configuration. Since DCD has no knowledge + // of the overall picture yet. We will use the worst scenario: largest possible + ep_count + // + // For Isochronous, largest EP size can be 1023/1024 for FS/HS respectively. In addition if multiple ISO + // are enabled at least "2 x (Largest-EPsize/4) + 1" are recommended. Maybe provide a macro for application to + // overwrite this. + + // EP0 out max is 64 + dwc2->grxfsiz = calc_grxfsiz(64, ep_count); + + // Setup the control endpoint 0 + _allocated_fifo_words_tx = 16; + + // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word ) + dwc2->dieptxf0 = (16 << DIEPTXF0_TX0FD_Pos) | (_dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx); + + // Fixed control EP0 size to 64 bytes + dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos); + xfer_status[0][TUSB_DIR_OUT].max_size = 64; + xfer_status[0][TUSB_DIR_IN ].max_size = 64; + + dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); + + dwc2->gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT; +} + +static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets, uint16_t total_bytes) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + // EP0 is limited to one packet each xfer + // We use multiple transaction of xfer->max_size length to get a whole transfer done + if ( epnum == 0 ) + { + xfer_ctl_t *const xfer = XFER_CTL_BASE(epnum, dir); + total_bytes = tu_min16(ep0_pending[dir], xfer->max_size); + ep0_pending[dir] -= total_bytes; + } + + // IN and OUT endpoint xfers are interrupt-driven, we just schedule them here. + if ( dir == TUSB_DIR_IN ) + { + dwc2_epin_t* epin = dwc2->epin; + + // A full IN transfer (multiple packets, possibly) triggers XFRC. + epin[epnum].dieptsiz = (num_packets << DIEPTSIZ_PKTCNT_Pos) | + ((total_bytes << DIEPTSIZ_XFRSIZ_Pos) & DIEPTSIZ_XFRSIZ_Msk); + + epin[epnum].diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK; + + // For ISO endpoint set correct odd/even bit for next frame. + if ( (epin[epnum].diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1 ) + { + // Take odd/even bit from frame counter. + uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); + epin[epnum].diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk); + } + // Enable fifo empty interrupt only if there are something to put in the fifo. + if ( total_bytes != 0 ) + { + dwc2->diepempmsk |= (1 << epnum); + } + } + else + { + dwc2_epout_t* epout = dwc2->epout; + + // A full OUT transfer (multiple packets, possibly) triggers XFRC. + epout[epnum].doeptsiz &= ~(DOEPTSIZ_PKTCNT_Msk | DOEPTSIZ_XFRSIZ); + epout[epnum].doeptsiz |= (num_packets << DOEPTSIZ_PKTCNT_Pos) | + ((total_bytes << DOEPTSIZ_XFRSIZ_Pos) & DOEPTSIZ_XFRSIZ_Msk); + + epout[epnum].doepctl |= DOEPCTL_EPENA | DOEPCTL_CNAK; + if ( (epout[epnum].doepctl & DOEPCTL_EPTYP) == DOEPCTL_EPTYP_0 && + XFER_CTL_BASE(epnum, dir)->interval == 1 ) + { + // Take odd/even bit from frame counter. + uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); + epout[epnum].doepctl |= (odd_frame_now ? DOEPCTL_SD0PID_SEVNFRM_Msk : DOEPCTL_SODDFRM_Msk); + } + } +} + +/*------------------------------------------------------------------*/ +/* Controller API + *------------------------------------------------------------------*/ +#if CFG_TUSB_DEBUG >= DWC2_DEBUG +void print_dwc2_info(dwc2_regs_t * dwc2) +{ + dwc2_ghwcfg2_t const * hw_cfg2 = &dwc2->ghwcfg2_bm; + dwc2_ghwcfg3_t const * hw_cfg3 = &dwc2->ghwcfg3_bm; + dwc2_ghwcfg4_t const * hw_cfg4 = &dwc2->ghwcfg4_bm; + +// TU_LOG_HEX(DWC2_DEBUG, dwc2->gotgctl); +// TU_LOG_HEX(DWC2_DEBUG, dwc2->gusbcfg); +// TU_LOG_HEX(DWC2_DEBUG, dwc2->dcfg); + TU_LOG_HEX(DWC2_DEBUG, dwc2->guid); + TU_LOG_HEX(DWC2_DEBUG, dwc2->gsnpsid); + TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg1); + + // HW configure 2 + TU_LOG(DWC2_DEBUG, "\r\n"); + TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg2); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->op_mode ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->arch ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->point2point ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->hs_phy_type ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->fs_phy_type ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->num_dev_ep ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->num_host_ch ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->period_channel_support ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->enable_dynamic_fifo ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->mul_cpu_int ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->nperiod_tx_q_depth ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->host_period_tx_q_depth ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->dev_token_q_depth ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->otg_enable_ic_usb ); + + // HW configure 3 + TU_LOG(DWC2_DEBUG, "\r\n"); + TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg3); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->xfer_size_width ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->packet_size_width ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_enable ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->i2c_enable ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->vendor_ctrl_itf ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->optional_feature_removed ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->synch_reset ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_adp_support ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_enable_hsic ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->battery_charger_support ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->lpm_mode ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->total_fifo_size ); + + // HW configure 4 + TU_LOG(DWC2_DEBUG, "\r\n"); + TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg4); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->num_dev_period_in_ep ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->power_optimized ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->ahb_freq_min ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->hibernation ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->service_interval_mode ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->ipg_isoc_en ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->acg_enable ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->utmi_phy_data_width ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dev_ctrl_ep_num ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->iddg_filter_enabled ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->vbus_valid_filter_enabled ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->a_valid_filter_enabled ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->b_valid_filter_enabled ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dedicated_fifos ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->num_dev_in_eps ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dma_desc_enable ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dma_dynamic ); +} +#endif + +static void reset_core(dwc2_regs_t * dwc2) +{ + // reset core + dwc2->grstctl |= GRSTCTL_CSRST; + + // wait for reset bit is cleared + // TODO version 4.20a should wait for RESET DONE mask + while (dwc2->grstctl & GRSTCTL_CSRST) { } + + // wait for AHB master IDLE + while ( !(dwc2->grstctl & GRSTCTL_AHBIDL) ) { } + + // wait for device mode ? +} + +static bool phy_hs_supported(dwc2_regs_t * dwc2) +{ + // note: esp32 incorrect report its hs_phy_type as utmi +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + return false; +#else + return TUD_OPT_HIGH_SPEED && dwc2->ghwcfg2_bm.hs_phy_type != HS_PHY_TYPE_NONE; +#endif +} + +static void phy_fs_init(dwc2_regs_t * dwc2) +{ + TU_LOG(DWC2_DEBUG, "Fullspeed PHY init\r\n"); + + // Select FS PHY + dwc2->gusbcfg |= GUSBCFG_PHYSEL; + + // MCU specific PHY init before reset + dwc2_phy_init(dwc2, HS_PHY_TYPE_NONE); + + // Reset core after selecting PHY + reset_core(dwc2); + + // USB turnaround time is critical for certification where long cables and 5-Hubs are used. + // So if you need the AHB to run at less than 30 MHz, and if USB turnaround time is not critical, + // these bits can be programmed to a larger value. Default is 5 + dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (5u << GUSBCFG_TRDT_Pos); + + // MCU specific PHY update post reset + dwc2_phy_update(dwc2, HS_PHY_TYPE_NONE); + + // set max speed + dwc2->dcfg = (dwc2->dcfg & ~DCFG_DSPD_Msk) | (DCFG_DSPD_FS << DCFG_DSPD_Pos); +} + +static void phy_hs_init(dwc2_regs_t * dwc2) +{ + uint32_t gusbcfg = dwc2->gusbcfg; + + // De-select FS PHY + gusbcfg &= ~GUSBCFG_PHYSEL; + + if (dwc2->ghwcfg2_bm.hs_phy_type == HS_PHY_TYPE_ULPI) + { + TU_LOG(DWC2_DEBUG, "Highspeed ULPI PHY init\r\n"); + + // Select ULPI + gusbcfg |= GUSBCFG_ULPI_UTMI_SEL; + + // ULPI 8-bit interface, single data rate + gusbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL); + + // default internal VBUS Indicator and Drive + gusbcfg &= ~(GUSBCFG_ULPIEVBUSD | GUSBCFG_ULPIEVBUSI); + + // Disable FS/LS ULPI + gusbcfg &= ~(GUSBCFG_ULPIFSLS | GUSBCFG_ULPICSM); + }else + { + TU_LOG(DWC2_DEBUG, "Highspeed UTMI+ PHY init\r\n"); + + // Select UTMI+ with 8-bit interface + gusbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16); + + // Set 16-bit interface if supported + if (dwc2->ghwcfg4_bm.utmi_phy_data_width) gusbcfg |= GUSBCFG_PHYIF16; + } + + // Apply config + dwc2->gusbcfg = gusbcfg; + + // mcu specific phy init + dwc2_phy_init(dwc2, dwc2->ghwcfg2_bm.hs_phy_type); + + // Reset core after selecting PHY + reset_core(dwc2); + + // Set turn-around, must after core reset otherwise it will be clear + // - 9 if using 8-bit PHY interface + // - 5 if using 16-bit PHY interface + gusbcfg &= ~GUSBCFG_TRDT_Msk; + gusbcfg |= (dwc2->ghwcfg4_bm.utmi_phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos; + dwc2->gusbcfg = gusbcfg; + + // MCU specific PHY update post reset + dwc2_phy_update(dwc2, dwc2->ghwcfg2_bm.hs_phy_type); + + // Set max speed + uint32_t dcfg = dwc2->dcfg; + dcfg &= ~DCFG_DSPD_Msk; + dcfg |= DCFG_DSPD_HS << DCFG_DSPD_Pos; + + // XCVRDLY: transceiver delay between xcvr_sel and txvalid during device chirp is required + // when using with some PHYs such as USB334x (USB3341, USB3343, USB3346, USB3347) + if (dwc2->ghwcfg2_bm.hs_phy_type == HS_PHY_TYPE_ULPI) dcfg |= DCFG_XCVRDLY; + + dwc2->dcfg = dcfg; +} + +static bool check_dwc2(dwc2_regs_t * dwc2) +{ +#if CFG_TUSB_DEBUG >= DWC2_DEBUG + print_dwc2_info(dwc2); +#endif + + // For some reasons: GD32VF103 snpsid and all hwcfg register are always zero (skip it) + (void) dwc2; +#if !TU_CHECK_MCU(OPT_MCU_GD32VF103) + uint32_t const gsnpsid = dwc2->gsnpsid & GSNPSID_ID_MASK; + TU_ASSERT(gsnpsid == DWC2_OTG_ID || gsnpsid == DWC2_FS_IOT_ID || gsnpsid == DWC2_HS_IOT_ID); +#endif + + return true; +} + +void dcd_init (uint8_t rhport) +{ + // Programming model begins in the last section of the chapter on the USB + // peripheral in each Reference Manual. + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + // Check Synopsys ID register, failed if controller clock/power is not enabled + TU_VERIFY(check_dwc2(dwc2), ); + + dcd_disconnect(rhport); + + // max number of endpoints & total_fifo_size are: + // hw_cfg2->num_dev_ep, hw_cfg2->total_fifo_size + + if( phy_hs_supported(dwc2) ) + { + // Highspeed + phy_hs_init(dwc2); + }else + { + // core does not support highspeed or hs-phy is not present + phy_fs_init(dwc2); + } + + // Restart PHY clock + dwc2->pcgctl &= ~(PCGCTL_STOPPCLK | PCGCTL_GATEHCLK | PCGCTL_PWRCLMP | PCGCTL_RSTPDWNMODULE); + + /* Set HS/FS Timeout Calibration to 7 (max available value). + * The number of PHY clocks that the application programs in + * this field is added to the high/full speed interpacket timeout + * duration in the core to account for any additional delays + * introduced by the PHY. This can be required, because the delay + * introduced by the PHY in generating the linestate condition + * can vary from one PHY to another. + */ + dwc2->gusbcfg |= (7ul << GUSBCFG_TOCAL_Pos); + + // Force device mode + dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FHMOD) | GUSBCFG_FDMOD; + + // Clear A override, force B Valid + dwc2->gotgctl = (dwc2->gotgctl & ~GOTGCTL_AVALOEN) | GOTGCTL_BVALOEN | GOTGCTL_BVALOVAL; + + // If USB host misbehaves during status portion of control xfer + // (non zero-length packet), send STALL back and discard. + dwc2->dcfg |= DCFG_NZLSOHSK; + + // Clear all interrupts + dwc2->gintsts |= dwc2->gintsts; + dwc2->gotgint |= dwc2->gotgint; + + // Required as part of core initialization. + // TODO: How should mode mismatch be handled? It will cause + // the core to stop working/require reset. + dwc2->gintmsk = GINTMSK_OTGINT | GINTMSK_MMISM | GINTMSK_RXFLVLM | + GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM; + + // Enable global interrupt + dwc2->gahbcfg |= GAHBCFG_GINT; + + // make sure we are in device mode +// TU_ASSERT(!(dwc2->gintsts & GINTSTS_CMOD), ); + +// TU_LOG_HEX(DWC2_DEBUG, dwc2->gotgctl); +// TU_LOG_HEX(DWC2_DEBUG, dwc2->gusbcfg); +// TU_LOG_HEX(DWC2_DEBUG, dwc2->dcfg); +// TU_LOG_HEX(DWC2_DEBUG, dwc2->gahbcfg); + + dcd_connect(rhport); +} + +void dcd_int_enable (uint8_t rhport) +{ + dwc2_dcd_int_enable(rhport); +} + +void dcd_int_disable (uint8_t rhport) +{ + dwc2_dcd_int_disable(rhport); +} + +void dcd_set_address (uint8_t rhport, uint8_t dev_addr) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2->dcfg = (dwc2->dcfg & ~DCFG_DAD_Msk) | (dev_addr << DCFG_DAD_Pos); + + // Response with status after changing device address + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); +} + +void dcd_remote_wakeup(uint8_t rhport) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + // set remote wakeup + dwc2->dctl |= DCTL_RWUSIG; + + // enable SOF to detect bus resume + dwc2->gintsts = GINTSTS_SOF; + dwc2->gintmsk |= GINTMSK_SOFM; + + // Per specs: remote wakeup signal bit must be clear within 1-15ms + dwc2_remote_wakeup_delay(); + + dwc2->dctl &= ~DCTL_RWUSIG; +} + +void dcd_connect(uint8_t rhport) +{ + (void) rhport; + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2->dctl &= ~DCTL_SDIS; +} + +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2->dctl |= DCTL_SDIS; +} + +// Be advised: audio, video and possibly other iso-ep classes use dcd_sof_enable() to enable/disable its corresponding ISR on purpose! +void dcd_sof_enable(uint8_t rhport, bool en) +{ + (void) rhport; + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + _sof_en = en; + + if (en) + { + dwc2->gintsts = GINTSTS_SOF; + dwc2->gintmsk |= GINTMSK_SOFM; + } + else + { + dwc2->gintmsk &= ~GINTMSK_SOFM; + } +} + +/*------------------------------------------------------------------*/ +/* DCD Endpoint port + *------------------------------------------------------------------*/ + +bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + + uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress); + uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress); + + TU_ASSERT(epnum < ep_count); + + xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); + xfer->max_size = tu_edpt_packet_size(desc_edpt); + xfer->interval = desc_edpt->bInterval; + + uint16_t const fifo_size = tu_div_ceil(xfer->max_size, 4); + + if(dir == TUSB_DIR_OUT) + { + // Calculate required size of RX FIFO + uint16_t const sz = calc_grxfsiz(4*fifo_size, ep_count); + + // If size_rx needs to be extended check if possible and if so enlarge it + if (dwc2->grxfsiz < sz) + { + TU_ASSERT(sz + _allocated_fifo_words_tx <= _dwc2_controller[rhport].ep_fifo_size/4); + + // Enlarge RX FIFO + dwc2->grxfsiz = sz; + } + + dwc2->epout[epnum].doepctl |= (1 << DOEPCTL_USBAEP_Pos) | + (desc_edpt->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) | + (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) | + (xfer->max_size << DOEPCTL_MPSIZ_Pos); + + dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum); + } + else + { + // "USB Data FIFOs" section in reference manual + // Peripheral FIFO architecture + // + // --------------- 320 or 1024 ( 1280 or 4096 bytes ) + // | IN FIFO 0 | + // --------------- (320 or 1024) - 16 + // | IN FIFO 1 | + // --------------- (320 or 1024) - 16 - x + // | . . . . | + // --------------- (320 or 1024) - 16 - x - y - ... - z + // | IN FIFO MAX | + // --------------- + // | FREE | + // --------------- GRXFSIZ + // | OUT FIFO | + // | ( Shared ) | + // --------------- 0 + // + // In FIFO is allocated by following rules: + // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n". + + // Check if free space is available + TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= _dwc2_controller[rhport].ep_fifo_size/4); + + _allocated_fifo_words_tx += fifo_size; + + TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %lu", fifo_size*4, _dwc2_controller[rhport].ep_fifo_size-_allocated_fifo_words_tx*4); + + // DIEPTXF starts at FIFO #1. + // Both TXFD and TXSA are in unit of 32-bit words. + dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | (_dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx); + + dwc2->epin[epnum].diepctl |= (1 << DIEPCTL_USBAEP_Pos) | + (epnum << DIEPCTL_TXFNUM_Pos) | + (desc_edpt->bmAttributes.xfer << DIEPCTL_EPTYP_Pos) | + (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DIEPCTL_SD0PID_SEVNFRM : 0) | + (xfer->max_size << DIEPCTL_MPSIZ_Pos); + + dwc2->daintmsk |= (1 << (DAINTMSK_IEPM_Pos + epnum)); + } + + return true; +} + +// Close all non-control endpoints, cancel all pending transfers if any. +void dcd_edpt_close_all (uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + + // Disable non-control interrupt + dwc2->daintmsk = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos); + + for(uint8_t n = 1; n < ep_count; n++) + { + // disable OUT endpoint + dwc2->epout[n].doepctl = 0; + xfer_status[n][TUSB_DIR_OUT].max_size = 0; + + // disable IN endpoint + dwc2->epin[n].diepctl = 0; + xfer_status[n][TUSB_DIR_IN].max_size = 0; + } + + // reset allocated fifo IN + _allocated_fifo_words_tx = 16; +} + +bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); + xfer->buffer = buffer; + xfer->ff = NULL; + xfer->total_len = total_bytes; + + // EP0 can only handle one packet + if(epnum == 0) + { + ep0_pending[dir] = total_bytes; + + // Schedule the first transaction for EP0 transfer + edpt_schedule_packets(rhport, epnum, dir, 1, ep0_pending[dir]); + } + else + { + uint16_t num_packets = (total_bytes / xfer->max_size); + uint16_t const short_packet_size = total_bytes % xfer->max_size; + + // Zero-size packet is special case. + if ( (short_packet_size > 0) || (total_bytes == 0) ) num_packets++; + + // Schedule packets to be sent within interrupt + edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes); + } + + return true; +} + +// The number of bytes has to be given explicitly to allow more flexible control of how many +// bytes should be written and second to keep the return value free to give back a boolean +// success message. If total_bytes is too big, the FIFO will copy only what is available +// into the USB buffer! +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1 + TU_ASSERT(ff->item_size == 1); + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); + xfer->buffer = NULL; + xfer->ff = ff; + xfer->total_len = total_bytes; + + uint16_t num_packets = (total_bytes / xfer->max_size); + uint16_t const short_packet_size = total_bytes % xfer->max_size; + + // Zero-size packet is special case. + if ( short_packet_size > 0 || (total_bytes == 0) ) num_packets++; + + // Schedule packets to be sent within interrupt + edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes); + + return true; +} + +static void dcd_edpt_disable (uint8_t rhport, uint8_t ep_addr, bool stall) +{ + (void) rhport; + + dwc2_regs_t *dwc2 = DWC2_REG(rhport); + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + if ( dir == TUSB_DIR_IN ) + { + dwc2_epin_t* epin = dwc2->epin; + + // Only disable currently enabled non-control endpoint + if ( (epnum == 0) || !(epin[epnum].diepctl & DIEPCTL_EPENA) ) + { + epin[epnum].diepctl |= DIEPCTL_SNAK | (stall ? DIEPCTL_STALL : 0); + } + else + { + // Stop transmitting packets and NAK IN xfers. + epin[epnum].diepctl |= DIEPCTL_SNAK; + while ( (epin[epnum].diepint & DIEPINT_INEPNE) == 0 ) {} + + // Disable the endpoint. + epin[epnum].diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0); + while ( (epin[epnum].diepint & DIEPINT_EPDISD_Msk) == 0 ) {} + + epin[epnum].diepint = DIEPINT_EPDISD; + } + + // Flush the FIFO, and wait until we have confirmed it cleared. + dwc2->grstctl = ((epnum << GRSTCTL_TXFNUM_Pos) | GRSTCTL_TXFFLSH); + while ( (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) != 0 ) {} + } + else + { + dwc2_epout_t* epout = dwc2->epout; + + // Only disable currently enabled non-control endpoint + if ( (epnum == 0) || !(epout[epnum].doepctl & DOEPCTL_EPENA) ) + { + epout[epnum].doepctl |= stall ? DOEPCTL_STALL : 0; + } + else + { + // Asserting GONAK is required to STALL an OUT endpoint. + // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt + // anyway, and it can't be cleared by user code. If this while loop never + // finishes, we have bigger problems than just the stack. + dwc2->dctl |= DCTL_SGONAK; + while ( (dwc2->gintsts & GINTSTS_BOUTNAKEFF_Msk) == 0 ) {} + + // Ditto here- disable the endpoint. + epout[epnum].doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0); + while ( (epout[epnum].doepint & DOEPINT_EPDISD_Msk) == 0 ) {} + + epout[epnum].doepint = DOEPINT_EPDISD; + + // Allow other OUT endpoints to keep receiving. + dwc2->dctl |= DCTL_CGONAK; + } + } +} + +/** + * Close an endpoint. + */ +void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + dcd_edpt_disable(rhport, ep_addr, false); + + // Update max_size + xfer_status[epnum][dir].max_size = 0; // max_size = 0 marks a disabled EP - required for changing FIFO allocation + + if (dir == TUSB_DIR_IN) + { + uint16_t const fifo_size = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXFD_Msk) >> DIEPTXF_INEPTXFD_Pos; + uint16_t const fifo_start = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXSA_Msk) >> DIEPTXF_INEPTXSA_Pos; + + // For now only the last opened endpoint can be closed without fuss. + TU_ASSERT(fifo_start == _dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx,); + _allocated_fifo_words_tx -= fifo_size; + } + else + { + _out_ep_closed = true; // Set flag such that RX FIFO gets reduced in size once RX FIFO is empty + } +} + +void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) +{ + dcd_edpt_disable(rhport, ep_addr, true); +} + +void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + // Clear stall and reset data toggle + if ( dir == TUSB_DIR_IN ) + { + dwc2->epin[epnum].diepctl &= ~DIEPCTL_STALL; + dwc2->epin[epnum].diepctl |= DIEPCTL_SD0PID_SEVNFRM; + } + else + { + dwc2->epout[epnum].doepctl &= ~DOEPCTL_STALL; + dwc2->epout[epnum].doepctl |= DOEPCTL_SD0PID_SEVNFRM; + } +} + +/*------------------------------------------------------------------*/ + +// Read a single data packet from receive FIFO +static void read_fifo_packet(uint8_t rhport, uint8_t * dst, uint16_t len) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + volatile const uint32_t * rx_fifo = dwc2->fifo[0]; + + // Reading full available 32 bit words from fifo + uint16_t full_words = len >> 2; + while(full_words--) + { + tu_unaligned_write32(dst, *rx_fifo); + dst += 4; + } + + // Read the remaining 1-3 bytes from fifo + uint8_t const bytes_rem = len & 0x03; + if ( bytes_rem != 0 ) + { + uint32_t const tmp = *rx_fifo; + dst[0] = tu_u32_byte0(tmp); + if ( bytes_rem > 1 ) dst[1] = tu_u32_byte1(tmp); + if ( bytes_rem > 2 ) dst[2] = tu_u32_byte2(tmp); + } +} + +// Write a single data packet to EPIN FIFO +static void write_fifo_packet(uint8_t rhport, uint8_t fifo_num, uint8_t const * src, uint16_t len) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + volatile uint32_t * tx_fifo = dwc2->fifo[fifo_num]; + + // Pushing full available 32 bit words to fifo + uint16_t full_words = len >> 2; + while(full_words--) + { + *tx_fifo = tu_unaligned_read32(src); + src += 4; + } + + // Write the remaining 1-3 bytes into fifo + uint8_t const bytes_rem = len & 0x03; + if ( bytes_rem ) + { + uint32_t tmp_word = src[0]; + if ( bytes_rem > 1 ) tmp_word |= (src[1] << 8); + if ( bytes_rem > 2 ) tmp_word |= (src[2] << 16); + + *tx_fifo = tmp_word; + } +} + +static void handle_rxflvl_irq(uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + volatile uint32_t const * rx_fifo = dwc2->fifo[0]; + + // Pop control word off FIFO + uint32_t const ctl_word = dwc2->grxstsp; + uint8_t const pktsts = (ctl_word & GRXSTSP_PKTSTS_Msk ) >> GRXSTSP_PKTSTS_Pos; + uint8_t const epnum = (ctl_word & GRXSTSP_EPNUM_Msk ) >> GRXSTSP_EPNUM_Pos; + uint16_t const bcnt = (ctl_word & GRXSTSP_BCNT_Msk ) >> GRXSTSP_BCNT_Pos; + + dwc2_epout_t* epout = &dwc2->epout[epnum]; + +//#if CFG_TUSB_DEBUG >= DWC2_DEBUG +// const char * pktsts_str[] = +// { +// "ASSERT", "Global NAK (ISR)", "Out Data Received", "Out Transfer Complete (ISR)", +// "Setup Complete (ISR)", "ASSERT", "Setup Data Received" +// }; +// TU_LOG_LOCATION(); +// TU_LOG(DWC2_DEBUG, " EP %02X, Byte Count %u, %s\r\n", epnum, bcnt, pktsts_str[pktsts]); +// TU_LOG(DWC2_DEBUG, " daint = %08lX, doepint = %04X\r\n", (unsigned long) dwc2->daint, (unsigned int) epout->doepint); +//#endif + + switch ( pktsts ) + { + // Global OUT NAK: do nothign + case GRXSTS_PKTSTS_GLOBALOUTNAK: break; + + case GRXSTS_PKTSTS_SETUPRX: + // Setup packet received + + // We can receive up to three setup packets in succession, but + // only the last one is valid. + _setup_packet[0] = (*rx_fifo); + _setup_packet[1] = (*rx_fifo); + break; + + case GRXSTS_PKTSTS_SETUPDONE: + // Setup packet done (Interrupt) + epout->doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); + break; + + case GRXSTS_PKTSTS_OUTRX: + { + // Out packet received + xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); + + // Read packet off RxFIFO + if ( xfer->ff ) + { + // Ring buffer + tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void*) (uintptr_t) rx_fifo, bcnt); + } + else + { + // Linear buffer + read_fifo_packet(rhport, xfer->buffer, bcnt); + + // Increment pointer to xfer data + xfer->buffer += bcnt; + } + + // Truncate transfer length in case of short packet + if ( bcnt < xfer->max_size ) + { + xfer->total_len -= (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos; + if ( epnum == 0 ) + { + xfer->total_len -= ep0_pending[TUSB_DIR_OUT]; + ep0_pending[TUSB_DIR_OUT] = 0; + } + } + } + break; + + // Out packet done (Interrupt) + case GRXSTS_PKTSTS_OUTDONE: + // Occurred on STM32L47 with dwc2 version 3.10a but not found on other version like 2.80a or 3.30a + // May (or not) be 3.10a specific feature/bug or depending on MCU configuration + // XFRC complete is additionally generated when + // - setup packet is received + // - complete the data stage of control write is complete + if ((epnum == 0) && (bcnt == 0) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) + { + uint32_t doepint = epout->doepint; + + if (doepint & (DOEPINT_STPKTRX | DOEPINT_OTEPSPR)) + { + // skip this "no-data" transfer complete event + // Note: STPKTRX will be clear later by setup received handler + uint32_t clear_flags = DOEPINT_XFRC; + + if (doepint & DOEPINT_OTEPSPR) clear_flags |= DOEPINT_OTEPSPR; + + epout->doepint = clear_flags; + + // TU_LOG(DWC2_DEBUG, " FIX extra transfer complete on setup/data compete\r\n"); + } + } + break; + + default: // Invalid + TU_BREAKPOINT(); + break; + } +} + +static void handle_epout_irq (uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + + // DAINT for a given EP clears when DOEPINTx is cleared. + // OEPINT will be cleared when DAINT's out bits are cleared. + for ( uint8_t n = 0; n < ep_count; n++ ) + { + if ( dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + n) ) + { + dwc2_epout_t* epout = &dwc2->epout[n]; + + uint32_t const doepint = epout->doepint; + + // SETUP packet Setup Phase done. + if ( doepint & DOEPINT_STUP ) + { + uint32_t clear_flag = DOEPINT_STUP; + + // STPKTRX is only available for version from 3_00a + if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) + { + clear_flag |= DOEPINT_STPKTRX; + } + + epout->doepint = clear_flag; + dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true); + } + + // OUT XFER complete + if ( epout->doepint & DOEPINT_XFRC ) + { + epout->doepint = DOEPINT_XFRC; + + xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT); + + // EP0 can only handle one packet + if ( (n == 0) && ep0_pending[TUSB_DIR_OUT] ) + { + // Schedule another packet to be received. + edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); + } + else + { + dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true); + } + } + } + } +} + +static void handle_epin_irq (uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + dwc2_epin_t* epin = dwc2->epin; + + // DAINT for a given EP clears when DIEPINTx is cleared. + // IEPINT will be cleared when DAINT's out bits are cleared. + for ( uint8_t n = 0; n < ep_count; n++ ) + { + if ( dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + n) ) + { + // IN XFER complete (entire xfer). + xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_IN); + + if ( epin[n].diepint & DIEPINT_XFRC ) + { + epin[n].diepint = DIEPINT_XFRC; + + // EP0 can only handle one packet + if ( (n == 0) && ep0_pending[TUSB_DIR_IN] ) + { + // Schedule another packet to be transmitted. + edpt_schedule_packets(rhport, n, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]); + } + else + { + dcd_event_xfer_complete(rhport, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); + } + } + + // XFER FIFO empty + if ( (epin[n].diepint & DIEPINT_TXFE) && (dwc2->diepempmsk & (1 << n)) ) + { + // diepint's TXFE bit is read-only, software cannot clear it. + // It will only be cleared by hardware when written bytes is more than + // - 64 bytes or + // - Half of TX FIFO size (configured by DIEPTXF) + + uint16_t remaining_packets = (epin[n].dieptsiz & DIEPTSIZ_PKTCNT_Msk) >> DIEPTSIZ_PKTCNT_Pos; + + // Process every single packet (only whole packets can be written to fifo) + for ( uint16_t i = 0; i < remaining_packets; i++ ) + { + uint16_t const remaining_bytes = (epin[n].dieptsiz & DIEPTSIZ_XFRSIZ_Msk) >> DIEPTSIZ_XFRSIZ_Pos; + + // Packet can not be larger than ep max size + uint16_t const packet_size = tu_min16(remaining_bytes, xfer->max_size); + + // It's only possible to write full packets into FIFO. Therefore DTXFSTS register of current + // EP has to be checked if the buffer can take another WHOLE packet + if ( packet_size > ((epin[n].dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2) ) break; + + // Push packet to Tx-FIFO + if ( xfer->ff ) + { + volatile uint32_t *tx_fifo = dwc2->fifo[n]; + tu_fifo_read_n_const_addr_full_words(xfer->ff, (void*) (uintptr_t) tx_fifo, packet_size); + } + else + { + write_fifo_packet(rhport, n, xfer->buffer, packet_size); + + // Increment pointer to xfer data + xfer->buffer += packet_size; + } + } + + // Turn off TXFE if all bytes are written. + if ( ((epin[n].dieptsiz & DIEPTSIZ_XFRSIZ_Msk) >> DIEPTSIZ_XFRSIZ_Pos) == 0 ) + { + dwc2->diepempmsk &= ~(1 << n); + } + } + } + } +} + +void dcd_int_handler(uint8_t rhport) +{ + dwc2_regs_t *dwc2 = DWC2_REG(rhport); + + uint32_t const int_status = dwc2->gintsts & dwc2->gintmsk; + + if(int_status & GINTSTS_USBRST) + { + // USBRST is start of reset. + dwc2->gintsts = GINTSTS_USBRST; + bus_reset(rhport); + } + + if(int_status & GINTSTS_ENUMDNE) + { + // ENUMDNE is the end of reset where speed of the link is detected + + dwc2->gintsts = GINTSTS_ENUMDNE; + + tusb_speed_t speed; + switch ((dwc2->dsts & DSTS_ENUMSPD_Msk) >> DSTS_ENUMSPD_Pos) + { + case DSTS_ENUMSPD_HS: + speed = TUSB_SPEED_HIGH; + break; + + case DSTS_ENUMSPD_LS: + speed = TUSB_SPEED_LOW; + break; + + case DSTS_ENUMSPD_FS_HSPHY: + case DSTS_ENUMSPD_FS: + default: + speed = TUSB_SPEED_FULL; + break; + } + + dcd_event_bus_reset(rhport, speed, true); + } + + if(int_status & GINTSTS_USBSUSP) + { + dwc2->gintsts = GINTSTS_USBSUSP; + dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); + } + + if(int_status & GINTSTS_WKUINT) + { + dwc2->gintsts = GINTSTS_WKUINT; + dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); + } + + // TODO check GINTSTS_DISCINT for disconnect detection + // if(int_status & GINTSTS_DISCINT) + + if(int_status & GINTSTS_OTGINT) + { + // OTG INT bit is read-only + uint32_t const otg_int = dwc2->gotgint; + + if (otg_int & GOTGINT_SEDET) + { + dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); + } + + dwc2->gotgint = otg_int; + } + + if(int_status & GINTSTS_SOF) + { + dwc2->gotgint = GINTSTS_SOF; + + if (_sof_en) + { + uint32_t frame = (dwc2->dsts & (DSTS_FNSOF)) >> 8; + dcd_event_sof(rhport, frame, true); + } + else + { + // Disable SOF interrupt if SOF was not explicitly enabled. SOF was used for remote wakeup detection + dwc2->gintmsk &= ~GINTMSK_SOFM; + } + + dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true); + } + + // RxFIFO non-empty interrupt handling. + if(int_status & GINTSTS_RXFLVL) + { + // RXFLVL bit is read-only + + // Mask out RXFLVL while reading data from FIFO + dwc2->gintmsk &= ~GINTMSK_RXFLVLM; + + // Loop until all available packets were handled + do + { + handle_rxflvl_irq(rhport); + } while(dwc2->gotgint & GINTSTS_RXFLVL); + + // Manage RX FIFO size + if (_out_ep_closed) + { + update_grxfsiz(rhport); + + // Disable flag + _out_ep_closed = false; + } + + dwc2->gintmsk |= GINTMSK_RXFLVLM; + } + + // OUT endpoint interrupt handling. + if(int_status & GINTSTS_OEPINT) + { + // OEPINT is read-only, clear using DOEPINTn + handle_epout_irq(rhport); + } + + // IN endpoint interrupt handling. + if(int_status & GINTSTS_IEPINT) + { + // IEPINT bit read-only, clear using DIEPINTn + handle_epin_irq(rhport); + } + + // // Check for Incomplete isochronous IN transfer + // if(int_status & GINTSTS_IISOIXFR) { + // printf(" IISOIXFR!\r\n"); + //// TU_LOG(DWC2_DEBUG, " IISOIXFR!\r\n"); + // } +} + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_bcm.h b/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_bcm.h new file mode 100644 index 00000000..732d96ae --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_bcm.h @@ -0,0 +1,89 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_DWC2_BCM_H_ +#define _TUSB_DWC2_BCM_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "broadcom/defines.h" +#include "broadcom/interrupts.h" +#include "broadcom/caches.h" + +#define DWC2_EP_MAX 8 + +static const dwc2_controller_t _dwc2_controller[] = +{ + { .reg_base = USB_OTG_GLOBAL_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 4096 } +}; + +#define dcache_clean(_addr, _size) data_clean(_addr, _size) +#define dcache_invalidate(_addr, _size) data_invalidate(_addr, _size) +#define dcache_clean_invalidate(_addr, _size) data_clean_and_invalidate(_addr, _size) + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_enable(uint8_t rhport) +{ + BP_EnableIRQ(_dwc2_controller[rhport].irqnum); +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_disable (uint8_t rhport) +{ + BP_DisableIRQ(_dwc2_controller[rhport].irqnum); +} + +static inline void dwc2_remote_wakeup_delay(void) +{ + // try to delay for 1 ms + // TODO implement later +} + +// MCU specific PHY init, called BEFORE core reset +static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // nothing to do +} + +// MCU specific PHY update, it is called AFTER init() and core reset +static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // nothing to do +} + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_efm32.h b/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_efm32.h new file mode 100644 index 00000000..0e3570cb --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_efm32.h @@ -0,0 +1,89 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Rafael Silva (@perigoso) + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _DWC2_EFM32_H_ +#define _DWC2_EFM32_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "em_device.h" + +// EFM32 has custom control register before DWC registers +#define DWC2_REG_BASE (USB_BASE + offsetof(USB_TypeDef, GOTGCTL)) +#define DWC2_EP_MAX 7 + +static const dwc2_controller_t _dwc2_controller[] = +{ + { .reg_base = DWC2_REG_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 2048 } +}; + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_enable(uint8_t rhport) +{ + NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum); +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_disable (uint8_t rhport) +{ + NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum); +} + +static inline void dwc2_remote_wakeup_delay(void) +{ + // try to delay for 1 ms +// uint32_t count = SystemCoreClock / 1000; +// while ( count-- ) __NOP(); +} + +// MCU specific PHY init, called BEFORE core reset +static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // Enable PHY + USB->ROUTE = USB_ROUTE_PHYPEN; +} + +// MCU specific PHY update, it is called AFTER init() and core reset +static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // EFM32 Manual: turn around must be 5 (reset & default value) + // dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (5u << GUSBCFG_TRDT_Pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_esp32.h b/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_esp32.h new file mode 100644 index 00000000..c50dd66b --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_esp32.h @@ -0,0 +1,96 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + + +#ifndef _DWC2_ESP32_H_ +#define _DWC2_ESP32_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "esp_intr_alloc.h" +#include "soc/periph_defs.h" +//#include "soc/usb_periph.h" + +#define DWC2_REG_BASE 0x60080000UL +#define DWC2_EP_MAX 6 // USB_OUT_EP_NUM. TODO ESP32Sx only has 5 tx fifo (5 endpoint IN) + +static const dwc2_controller_t _dwc2_controller[] = +{ + { .reg_base = DWC2_REG_BASE, .irqnum = 0, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 1024 } +}; + +static intr_handle_t usb_ih; + +static void dcd_int_handler_wrap(void* arg) +{ + (void) arg; + dcd_int_handler(0); +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_enable (uint8_t rhport) +{ + (void) rhport; + esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_LOWMED, dcd_int_handler_wrap, NULL, &usb_ih); +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_disable (uint8_t rhport) +{ + (void) rhport; + esp_intr_free(usb_ih); +} + +static inline void dwc2_remote_wakeup_delay(void) +{ + vTaskDelay(pdMS_TO_TICKS(1)); +} + +// MCU specific PHY init, called BEFORE core reset +static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // nothing to do +} + +// MCU specific PHY update, it is called AFTER init() and core reset +static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // nothing to do +} + +#ifdef __cplusplus +} +#endif + +#endif /* _DWC2_ESP32_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_gd32.h b/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_gd32.h new file mode 100644 index 00000000..0375fffe --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_gd32.h @@ -0,0 +1,101 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + + +#ifndef DWC2_GD32_H_ +#define DWC2_GD32_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#define DWC2_REG_BASE 0x50000000UL +#define DWC2_EP_MAX 4 + +static const dwc2_controller_t _dwc2_controller[] = +{ + { .reg_base = DWC2_REG_BASE, .irqnum = 86, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 1280 } +}; + +extern uint32_t SystemCoreClock; + +// The GD32VF103 is a RISC-V MCU, which implements the ECLIC Core-Local +// Interrupt Controller by Nuclei. It is nearly API compatible to the +// NVIC used by ARM MCUs. +#define ECLIC_INTERRUPT_ENABLE_BASE 0xD2001001UL + +TU_ATTR_ALWAYS_INLINE +static inline void __eclic_enable_interrupt (uint32_t irq) { + *(volatile uint8_t*)(ECLIC_INTERRUPT_ENABLE_BASE + (irq * 4)) = 1; +} + +TU_ATTR_ALWAYS_INLINE +static inline void __eclic_disable_interrupt (uint32_t irq){ + *(volatile uint8_t*)(ECLIC_INTERRUPT_ENABLE_BASE + (irq * 4)) = 0; +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_enable(uint8_t rhport) +{ + __eclic_enable_interrupt(_dwc2_controller[rhport].irqnum); +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_disable (uint8_t rhport) +{ + __eclic_disable_interrupt(_dwc2_controller[rhport].irqnum); +} + +static inline void dwc2_remote_wakeup_delay(void) +{ + // try to delay for 1 ms + uint32_t count = SystemCoreClock / 1000; + while ( count-- ) __asm volatile ("nop"); +} + +// MCU specific PHY init, called BEFORE core reset +static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // nothing to do +} + +// MCU specific PHY update, it is called AFTER init() and core reset +static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // nothing to do +} + +#ifdef __cplusplus +} +#endif + +#endif /* DWC2_GD32_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_stm32.h b/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_stm32.h new file mode 100644 index 00000000..337f611d --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_stm32.h @@ -0,0 +1,226 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _DWC2_STM32_H_ +#define _DWC2_STM32_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +// EP_MAX : Max number of bi-directional endpoints including EP0 +// EP_FIFO_SIZE : Size of dedicated USB SRAM +#if CFG_TUSB_MCU == OPT_MCU_STM32F1 + #include "stm32f1xx.h" + #define EP_MAX_FS 4 + #define EP_FIFO_SIZE_FS 1280 + +#elif CFG_TUSB_MCU == OPT_MCU_STM32F2 + #include "stm32f2xx.h" + #define EP_MAX_FS USB_OTG_FS_MAX_IN_ENDPOINTS + #define EP_FIFO_SIZE_FS USB_OTG_FS_TOTAL_FIFO_SIZE + + #define EP_MAX_HS USB_OTG_HS_MAX_IN_ENDPOINTS + #define EP_FIFO_SIZE_HS USB_OTG_HS_TOTAL_FIFO_SIZE + +#elif CFG_TUSB_MCU == OPT_MCU_STM32F4 + #include "stm32f4xx.h" + #define EP_MAX_FS USB_OTG_FS_MAX_IN_ENDPOINTS + #define EP_FIFO_SIZE_FS USB_OTG_FS_TOTAL_FIFO_SIZE + + #define EP_MAX_HS USB_OTG_HS_MAX_IN_ENDPOINTS + #define EP_FIFO_SIZE_HS USB_OTG_HS_TOTAL_FIFO_SIZE + +#elif CFG_TUSB_MCU == OPT_MCU_STM32H7 + #include "stm32h7xx.h" + #define EP_MAX_FS 9 + #define EP_FIFO_SIZE_FS 4096 + + #define EP_MAX_HS 9 + #define EP_FIFO_SIZE_HS 4096 + + // NOTE: H7 with only 1 USB port: H72x / H73x / H7Ax / H7Bx + // USB_OTG_FS_PERIPH_BASE and OTG_FS_IRQn not defined + #if (! defined USB2_OTG_FS) + #define USB_OTG_FS_PERIPH_BASE USB1_OTG_HS_PERIPH_BASE + #define OTG_FS_IRQn OTG_HS_IRQn + #endif + +#elif CFG_TUSB_MCU == OPT_MCU_STM32F7 + #include "stm32f7xx.h" + #define EP_MAX_FS 6 + #define EP_FIFO_SIZE_FS 1280 + + #define EP_MAX_HS 9 + #define EP_FIFO_SIZE_HS 4096 + +#elif CFG_TUSB_MCU == OPT_MCU_STM32L4 + #include "stm32l4xx.h" + #define EP_MAX_FS 6 + #define EP_FIFO_SIZE_FS 1280 + +#else + #error "Unsupported MCUs" +#endif + +// OTG HS always has higher number of endpoints than FS +#ifdef USB_OTG_HS_PERIPH_BASE + #define DWC2_EP_MAX EP_MAX_HS +#else + #define DWC2_EP_MAX EP_MAX_FS +#endif + +// On STM32 for consistency we associate +// - Port0 to OTG_FS, and Port1 to OTG_HS +static const dwc2_controller_t _dwc2_controller[] = +{ +#ifdef USB_OTG_FS_PERIPH_BASE + { .reg_base = USB_OTG_FS_PERIPH_BASE, .irqnum = OTG_FS_IRQn, .ep_count = EP_MAX_FS, .ep_fifo_size = EP_FIFO_SIZE_FS }, +#endif + +#ifdef USB_OTG_HS_PERIPH_BASE + { .reg_base = USB_OTG_HS_PERIPH_BASE, .irqnum = OTG_HS_IRQn, .ep_count = EP_MAX_HS, .ep_fifo_size = EP_FIFO_SIZE_HS }, +#endif +}; + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +// SystemCoreClock is alrady included by family header +// extern uint32_t SystemCoreClock; + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_enable(uint8_t rhport) +{ + NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum); +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_disable (uint8_t rhport) +{ + NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum); +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_remote_wakeup_delay(void) +{ + // try to delay for 1 ms + uint32_t count = SystemCoreClock / 1000; + while ( count-- ) __NOP(); +} + +// MCU specific PHY init, called BEFORE core reset +static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + if ( hs_phy_type == HS_PHY_TYPE_NONE ) + { + // Enable on-chip FS PHY + dwc2->stm32_gccfg |= STM32_GCCFG_PWRDWN; + }else + { + // Disable FS PHY + dwc2->stm32_gccfg &= ~STM32_GCCFG_PWRDWN; + + // Enable on-chip HS PHY + if (hs_phy_type == HS_PHY_TYPE_UTMI || hs_phy_type == HS_PHY_TYPE_UTMI_ULPI) + { +#ifdef USB_HS_PHYC + // Enable UTMI HS PHY + dwc2->stm32_gccfg |= STM32_GCCFG_PHYHSEN; + + // Enable LDO + USB_HS_PHYC->USB_HS_PHYC_LDO |= USB_HS_PHYC_LDO_ENABLE; + + // Wait until LDO ready + while ( 0 == (USB_HS_PHYC->USB_HS_PHYC_LDO & USB_HS_PHYC_LDO_STATUS) ) {} + + uint32_t phyc_pll = 0; + + // TODO Try to get HSE_VALUE from registers instead of depending CFLAGS + switch ( HSE_VALUE ) + { + case 12000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_12MHZ ; break; + case 12500000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_12_5MHZ ; break; + case 16000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_16MHZ ; break; + case 24000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_24MHZ ; break; + case 25000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_25MHZ ; break; + case 32000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_Msk ; break; // Value not defined in header + default: + TU_ASSERT(false, ); + } + USB_HS_PHYC->USB_HS_PHYC_PLL = phyc_pll; + + // Control the tuning interface of the High Speed PHY + // Use magic value (USB_HS_PHYC_TUNE_VALUE) from ST driver for F7 + USB_HS_PHYC->USB_HS_PHYC_TUNE |= 0x00000F13U; + + // Enable PLL internal PHY + USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL_PLLEN; +#endif + } + } +} + +// MCU specific PHY update, it is called AFTER init() and core reset +static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + // used to set turnaround time for fullspeed, nothing to do in highspeed mode + if ( hs_phy_type == HS_PHY_TYPE_NONE ) + { + // Turnaround timeout depends on the AHB clock dictated by STM32 Reference Manual + uint32_t turnaround; + + if ( SystemCoreClock >= 32000000u ) + turnaround = 0x6u; + else if ( SystemCoreClock >= 27500000u ) + turnaround = 0x7u; + else if ( SystemCoreClock >= 24000000u ) + turnaround = 0x8u; + else if ( SystemCoreClock >= 21800000u ) + turnaround = 0x9u; + else if ( SystemCoreClock >= 20000000u ) + turnaround = 0xAu; + else if ( SystemCoreClock >= 18500000u ) + turnaround = 0xBu; + else if ( SystemCoreClock >= 17200000u ) + turnaround = 0xCu; + else if ( SystemCoreClock >= 16000000u ) + turnaround = 0xDu; + else if ( SystemCoreClock >= 15000000u ) + turnaround = 0xEu; + else + turnaround = 0xFu; + + dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (turnaround << GUSBCFG_TRDT_Pos); + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* _DWC2_STM32_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_type.h b/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_type.h new file mode 100644 index 00000000..3fc97933 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_type.h @@ -0,0 +1,1739 @@ +/** + * @author MCD Application Team + * Ha Thach (tinyusb.org) + * + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + */ + +#ifndef _TUSB_DWC2_TYPES_H_ +#define _TUSB_DWC2_TYPES_H_ + +#include "stdint.h" + +#ifdef __cplusplus + extern "C" { +#endif + +// Controller +typedef struct +{ + uintptr_t reg_base; + uint32_t irqnum; + uint8_t ep_count; + uint32_t ep_fifo_size; +}dwc2_controller_t; + +/* DWC OTG HW Release versions */ +#define DWC2_CORE_REV_2_71a 0x4f54271a +#define DWC2_CORE_REV_2_72a 0x4f54272a +#define DWC2_CORE_REV_2_80a 0x4f54280a +#define DWC2_CORE_REV_2_90a 0x4f54290a +#define DWC2_CORE_REV_2_91a 0x4f54291a +#define DWC2_CORE_REV_2_92a 0x4f54292a +#define DWC2_CORE_REV_2_94a 0x4f54294a +#define DWC2_CORE_REV_3_00a 0x4f54300a +#define DWC2_CORE_REV_3_10a 0x4f54310a +#define DWC2_CORE_REV_4_00a 0x4f54400a +#define DWC2_CORE_REV_4_20a 0x4f54420a +#define DWC2_FS_IOT_REV_1_00a 0x5531100a +#define DWC2_HS_IOT_REV_1_00a 0x5532100a +#define DWC2_CORE_REV_MASK 0x0000ffff + +/* DWC OTG HW Core ID */ +#define DWC2_OTG_ID 0x4f540000 +#define DWC2_FS_IOT_ID 0x55310000 +#define DWC2_HS_IOT_ID 0x55320000 + +#if 0 +// HS PHY +typedef struct +{ + volatile uint32_t HS_PHYC_PLL; // This register is used to control the PLL of the HS PHY. 000h */ + volatile uint32_t Reserved04; // Reserved 004h */ + volatile uint32_t Reserved08; // Reserved 008h */ + volatile uint32_t HS_PHYC_TUNE; // This register is used to control the tuning interface of the High Speed PHY. 00Ch */ + volatile uint32_t Reserved10; // Reserved 010h */ + volatile uint32_t Reserved14; // Reserved 014h */ + volatile uint32_t HS_PHYC_LDO; // This register is used to control the regulator (LDO). 018h */ +} HS_PHYC_GlobalTypeDef; +#endif + +enum { + HS_PHY_TYPE_NONE = 0 , // not supported + HS_PHY_TYPE_UTMI , // internal PHY (mostly) + HS_PHY_TYPE_ULPI , // external PHY + HS_PHY_TYPE_UTMI_ULPI , +}; + +enum { + FS_PHY_TYPE_NONE = 0, // not supported + FS_PHY_TYPE_DEDICATED, + FS_PHY_TYPE_UTMI, + FS_PHY_TYPE_ULPI, +}; + +typedef struct TU_ATTR_PACKED +{ + uint32_t op_mode : 3; // 0: HNP and SRP | 1: SRP | 2: non-HNP, non-SRP + uint32_t arch : 2; // 0: slave-only | 1: External DMA | 2: Internal DMA | 3: others + uint32_t point2point : 1; // 0: support hub and split | 1: no hub, no split + uint32_t hs_phy_type : 2; // 0: not supported | 1: UTMI+ | 2: ULPI | 3: UTMI+ and ULPI + uint32_t fs_phy_type : 2; // 0: not supported | 1: dedicated | 2: UTMI+ | 3: ULPI + uint32_t num_dev_ep : 4; // Number of device endpoints (not including EP0) + uint32_t num_host_ch : 4; // Number of host channel + uint32_t period_channel_support : 1; // Support Periodic OUT Host Channel + uint32_t enable_dynamic_fifo : 1; // Dynamic FIFO Sizing Enabled + uint32_t mul_cpu_int : 1; // Multi-Processor Interrupt Enabled + uint32_t reserved21 : 1; + uint32_t nperiod_tx_q_depth : 2; // Non-periodic request queue depth: 0 = 2. 1 = 4, 2 = 8 + uint32_t host_period_tx_q_depth : 2; // Host periodic request queue depth: 0 = 2. 1 = 4, 2 = 8 + uint32_t dev_token_q_depth : 5; // Device IN token sequence learning queue depth: 0-30 + uint32_t otg_enable_ic_usb : 1; // IC_USB mode specified for mode of operation +} dwc2_ghwcfg2_t; + +TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg2_t) == 4, "incorrect size"); + +typedef struct TU_ATTR_PACKED +{ + uint32_t xfer_size_width : 4; // Transfer size counter in bits = 11 + n (max 19 bits) + uint32_t packet_size_width : 3; // Packet size counter in bits = 4 + n (max 10 bits) + uint32_t otg_enable : 1; // 1 is OTG capable + uint32_t i2c_enable : 1; // I2C interface is available + uint32_t vendor_ctrl_itf : 1; // Vendor control interface is available + uint32_t optional_feature_removed : 1; // remove User ID, GPIO, SOF toggle & counter + uint32_t synch_reset : 1; // 0: async reset | 1: synch reset + uint32_t otg_adp_support : 1; // ADP logic is present along with HSOTG controller + uint32_t otg_enable_hsic : 1; // 1: HSIC-capable with shared UTMI PHY interface | 0: non-HSIC + uint32_t battery_charger_support : 1; // support battery charger + uint32_t lpm_mode : 1; // LPC mode + uint32_t total_fifo_size : 16; // DFIFO depth value in terms of 32-bit words +}dwc2_ghwcfg3_t; + +TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg3_t) == 4, "incorrect size"); + +typedef struct TU_ATTR_PACKED +{ + uint32_t num_dev_period_in_ep : 4; // Number of Device Periodic IN Endpoints + uint32_t power_optimized : 1; // Partial Power Down Enabled + uint32_t ahb_freq_min : 1; // 1: minimum of AHB frequency is less than 60 MHz + uint32_t hibernation : 1; // Hibernation feature is enabled + uint32_t reserved7 : 3; + uint32_t service_interval_mode : 1; // Service Interval supported + uint32_t ipg_isoc_en : 1; // IPG ISOC supported + uint32_t acg_enable : 1; // ACG enabled + uint32_t reserved13 : 1; + uint32_t utmi_phy_data_width : 2; // 0: 8 bits | 1: 16 bits | 2: 8/16 software selectable + uint32_t dev_ctrl_ep_num : 4; // Number of Device control endpoints in addition to EP0 + uint32_t iddg_filter_enabled : 1; + uint32_t vbus_valid_filter_enabled : 1; + uint32_t a_valid_filter_enabled : 1; + uint32_t b_valid_filter_enabled : 1; + uint32_t dedicated_fifos : 1; // Dedicated tx fifo for device IN Endpoint is enabled + uint32_t num_dev_in_eps : 4; // Number of Device IN Endpoints including EP0 + uint32_t dma_desc_enable : 1; // scatter/gather DMA configuration + uint32_t dma_dynamic : 1; // Dynamic scatter/gather DMA +}dwc2_ghwcfg4_t; + +TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg4_t) == 4, "incorrect size"); + +// Host Channel +typedef struct +{ + volatile uint32_t hcchar; // 500 + 20*ch Host Channel Characteristics + volatile uint32_t hcsplt; // 504 + 20*ch Host Channel Split Control + volatile uint32_t hcint; // 508 + 20*ch Host Channel Interrupt + volatile uint32_t hcintmsk; // 50C + 20*ch Host Channel Interrupt Mask + volatile uint32_t hctsiz; // 510 + 20*ch Host Channel Transfer Size + volatile uint32_t hcdma; // 514 + 20*ch Host Channel DMA Address + uint32_t reserved518; // 518 + 20*ch + volatile uint32_t hcdmab; // 51C + 20*ch Host Channel DMA Address +} dwc2_channel_t; + +// Endpoint IN +typedef struct +{ + volatile uint32_t diepctl; // 900 + 20*ep Device IN Endpoint Control + uint32_t reserved04; // 904 + volatile uint32_t diepint; // 908 + 20*ep Device IN Endpoint Interrupt + uint32_t reserved0c; // 90C + volatile uint32_t dieptsiz; // 910 + 20*ep Device IN Endpoint Transfer Size + volatile uint32_t diepdma; // 914 + 20*ep Device IN Endpoint DMA Address + volatile uint32_t dtxfsts; // 918 + 20*ep Device IN Endpoint Tx FIFO Status + uint32_t reserved1c; // 91C +} dwc2_epin_t; + +// Endpoint OUT +typedef struct +{ + volatile uint32_t doepctl; // B00 + 20*ep Device OUT Endpoint Control + uint32_t reserved04; // B04 + volatile uint32_t doepint; // B08 + 20*ep Device OUT Endpoint Interrupt + uint32_t reserved0c; // B0C + volatile uint32_t doeptsiz; // B10 + 20*ep Device OUT Endpoint Transfer Size + volatile uint32_t doepdma; // B14 + 20*ep Device OUT Endpoint DMA Address + uint32_t reserved18[2]; // B18..B1C +} dwc2_epout_t; + +typedef struct +{ + //------------- Core Global -------------// + volatile uint32_t gotgctl; // 000 OTG Control and Status + volatile uint32_t gotgint; // 004 OTG Interrupt + volatile uint32_t gahbcfg; // 008 AHB Configuration + volatile uint32_t gusbcfg; // 00c USB Configuration + volatile uint32_t grstctl; // 010 Reset + volatile uint32_t gintsts; // 014 Interrupt + volatile uint32_t gintmsk; // 018 Interrupt Mask + volatile uint32_t grxstsr; // 01c Receive Status Debug Read + volatile uint32_t grxstsp; // 020 Receive Status Read/Pop + volatile uint32_t grxfsiz; // 024 Receive FIFO Size +union { + volatile uint32_t dieptxf0; // 028 EP0 Tx FIFO Size + volatile uint32_t gnptxfsiz; // 028 Non-periodic Transmit FIFO Size +}; + volatile uint32_t gnptxsts; // 02c Non-periodic Transmit FIFO/Queue Status + volatile uint32_t gi2cctl; // 030 I2C Address + volatile uint32_t gpvndctl; // 034 PHY Vendor Control +union { + volatile uint32_t ggpio; // 038 General Purpose IO + volatile uint32_t stm32_gccfg; // 038 STM32 General Core Configuration +}; + volatile uint32_t guid; // 03C User (Application programmable) ID + volatile uint32_t gsnpsid; // 040 Synopsys ID + Release version + volatile uint32_t ghwcfg1; // 044 User Hardware Configuration1: endpoint dir (2 bit per ep) +union { + volatile uint32_t ghwcfg2; // 048 User Hardware Configuration2 + dwc2_ghwcfg2_t ghwcfg2_bm; +}; +union { + volatile uint32_t ghwcfg3; // 04C User Hardware Configuration3 + dwc2_ghwcfg3_t ghwcfg3_bm; +}; +union { + volatile uint32_t ghwcfg4; // 050 User Hardware Configuration4 + dwc2_ghwcfg4_t ghwcfg4_bm; +}; + volatile uint32_t glpmcfg; // 054 Core LPM Configuration + volatile uint32_t gpwrdn; // 058 Power Down + volatile uint32_t gdfifocfg; // 05C DFIFO Software Configuration + volatile uint32_t gadpctl; // 060 ADP Timer, Control and Status + uint32_t reserved64[39]; // 064..0FF + volatile uint32_t hptxfsiz; // 100 Host Periodic Tx FIFO Size + volatile uint32_t dieptxf[15]; // 104..13C Device Periodic Transmit FIFO Size + uint32_t reserved140[176]; // 140..3FF + + //------------- Host -------------// + volatile uint32_t hcfg; // 400 Host Configuration + volatile uint32_t hfir; // 404 Host Frame Interval + volatile uint32_t hfnum; // 408 Host Frame Number / Frame Remaining + uint32_t reserved40c; // 40C + volatile uint32_t hptxsts; // 410 Host Periodic TX FIFO / Queue Status + volatile uint32_t haint; // 414 Host All Channels Interrupt + volatile uint32_t haintmsk; // 418 Host All Channels Interrupt Mask + volatile uint32_t hflbaddr; // 41C Host Frame List Base Address + uint32_t reserved420[8]; // 420..43F + volatile uint32_t hprt; // 440 Host Port Control and Status + uint32_t reserved444[47]; // 444..4FF + + //------------- Host Channel -------------// + dwc2_channel_t channel[16]; // 500..6FF Host Channels 0-15 + uint32_t reserved700[64]; // 700..7FF + + //------------- Device -------------// + volatile uint32_t dcfg; // 800 Device Configuration + volatile uint32_t dctl; // 804 Device Control + volatile uint32_t dsts; // 808 Device Status (RO) + uint32_t reserved80c; // 80C + volatile uint32_t diepmsk; // 810 Device IN Endpoint Interrupt Mask + volatile uint32_t doepmsk; // 814 Device OUT Endpoint Interrupt Mask + volatile uint32_t daint; // 818 Device All Endpoints Interrupt + volatile uint32_t daintmsk; // 81C Device All Endpoints Interrupt Mask + volatile uint32_t dtknqr1; // 820 Device IN token sequence learning queue read1 + volatile uint32_t dtknqr2; // 824 Device IN token sequence learning queue read2 + volatile uint32_t dvbusdis; // 828 Device VBUS Discharge Time + volatile uint32_t dvbuspulse; // 82C Device VBUS Pulsing Time + volatile uint32_t dthrctl; // 830 Device threshold Control + volatile uint32_t diepempmsk; // 834 Device IN Endpoint FIFO Empty Interrupt Mask + volatile uint32_t deachint; // 838 Device Each Endpoint Interrupt + volatile uint32_t deachmsk; // 83C Device Each Endpoint Interrupt msk + volatile uint32_t diepeachmsk[16]; // 840..87C Device Each IN Endpoint mask + volatile uint32_t doepeachmsk[16]; // 880..8BF Device Each OUT Endpoint mask + uint32_t reserved8c0[16]; // 8C0..8FF + + //------------- Device Endpoint -------------// + dwc2_epin_t epin[16]; // 900..AFF IN Endpoints + dwc2_epout_t epout[16]; // B00..CFF OUT Endpoints + uint32_t reservedd00[64]; // D00..DFF + + //------------- Power Clock -------------// + volatile uint32_t pcgctl; // E00 Power and Clock Gating Control + volatile uint32_t pcgctl1; // E04 + uint32_t reservede08[126]; // E08..FFF + + //------------- FIFOs -------------// + // Word-accessed only using first pointer since it auto shift + volatile uint32_t fifo[16][0x400]; // 1000..FFFF Endpoint FIFO +} dwc2_regs_t; + +TU_VERIFY_STATIC(offsetof(dwc2_regs_t, hcfg ) == 0x0400, "incorrect size"); +TU_VERIFY_STATIC(offsetof(dwc2_regs_t, channel) == 0x0500, "incorrect size"); +TU_VERIFY_STATIC(offsetof(dwc2_regs_t, dcfg ) == 0x0800, "incorrect size"); +TU_VERIFY_STATIC(offsetof(dwc2_regs_t, epin ) == 0x0900, "incorrect size"); +TU_VERIFY_STATIC(offsetof(dwc2_regs_t, epout ) == 0x0B00, "incorrect size"); +TU_VERIFY_STATIC(offsetof(dwc2_regs_t, pcgctl ) == 0x0E00, "incorrect size"); +TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size"); + +//--------------------------------------------------------------------+ +// Register Bit Definitions +//--------------------------------------------------------------------+ + +/******************** Bit definition for GOTGCTL register ********************/ +#define GOTGCTL_SRQSCS_Pos (0U) +#define GOTGCTL_SRQSCS_Msk (0x1UL << GOTGCTL_SRQSCS_Pos) // 0x00000001 */ +#define GOTGCTL_SRQSCS GOTGCTL_SRQSCS_Msk // Session request success */ +#define GOTGCTL_SRQ_Pos (1U) +#define GOTGCTL_SRQ_Msk (0x1UL << GOTGCTL_SRQ_Pos) // 0x00000002 */ +#define GOTGCTL_SRQ GOTGCTL_SRQ_Msk // Session request */ +#define GOTGCTL_VBVALOEN_Pos (2U) +#define GOTGCTL_VBVALOEN_Msk (0x1UL << GOTGCTL_VBVALOEN_Pos) // 0x00000004 */ +#define GOTGCTL_VBVALOEN GOTGCTL_VBVALOEN_Msk // VBUS valid override enable */ +#define GOTGCTL_VBVALOVAL_Pos (3U) +#define GOTGCTL_VBVALOVAL_Msk (0x1UL << GOTGCTL_VBVALOVAL_Pos) // 0x00000008 */ +#define GOTGCTL_VBVALOVAL GOTGCTL_VBVALOVAL_Msk // VBUS valid override value */ +#define GOTGCTL_AVALOEN_Pos (4U) +#define GOTGCTL_AVALOEN_Msk (0x1UL << GOTGCTL_AVALOEN_Pos) // 0x00000010 */ +#define GOTGCTL_AVALOEN GOTGCTL_AVALOEN_Msk // A-peripheral session valid override enable */ +#define GOTGCTL_AVALOVAL_Pos (5U) +#define GOTGCTL_AVALOVAL_Msk (0x1UL << GOTGCTL_AVALOVAL_Pos) // 0x00000020 */ +#define GOTGCTL_AVALOVAL GOTGCTL_AVALOVAL_Msk // A-peripheral session valid override value */ +#define GOTGCTL_BVALOEN_Pos (6U) +#define GOTGCTL_BVALOEN_Msk (0x1UL << GOTGCTL_BVALOEN_Pos) // 0x00000040 */ +#define GOTGCTL_BVALOEN GOTGCTL_BVALOEN_Msk // B-peripheral session valid override enable */ +#define GOTGCTL_BVALOVAL_Pos (7U) +#define GOTGCTL_BVALOVAL_Msk (0x1UL << GOTGCTL_BVALOVAL_Pos) // 0x00000080 */ +#define GOTGCTL_BVALOVAL GOTGCTL_BVALOVAL_Msk // B-peripheral session valid override value */ +#define GOTGCTL_HNGSCS_Pos (8U) +#define GOTGCTL_HNGSCS_Msk (0x1UL << GOTGCTL_HNGSCS_Pos) // 0x00000100 */ +#define GOTGCTL_HNGSCS GOTGCTL_HNGSCS_Msk // Host set HNP enable */ +#define GOTGCTL_HNPRQ_Pos (9U) +#define GOTGCTL_HNPRQ_Msk (0x1UL << GOTGCTL_HNPRQ_Pos) // 0x00000200 */ +#define GOTGCTL_HNPRQ GOTGCTL_HNPRQ_Msk // HNP request */ +#define GOTGCTL_HSHNPEN_Pos (10U) +#define GOTGCTL_HSHNPEN_Msk (0x1UL << GOTGCTL_HSHNPEN_Pos) // 0x00000400 */ +#define GOTGCTL_HSHNPEN GOTGCTL_HSHNPEN_Msk // Host set HNP enable */ +#define GOTGCTL_DHNPEN_Pos (11U) +#define GOTGCTL_DHNPEN_Msk (0x1UL << GOTGCTL_DHNPEN_Pos) // 0x00000800 */ +#define GOTGCTL_DHNPEN GOTGCTL_DHNPEN_Msk // Device HNP enabled */ +#define GOTGCTL_EHEN_Pos (12U) +#define GOTGCTL_EHEN_Msk (0x1UL << GOTGCTL_EHEN_Pos) // 0x00001000 */ +#define GOTGCTL_EHEN GOTGCTL_EHEN_Msk // Embedded host enable */ +#define GOTGCTL_CIDSTS_Pos (16U) +#define GOTGCTL_CIDSTS_Msk (0x1UL << GOTGCTL_CIDSTS_Pos) // 0x00010000 */ +#define GOTGCTL_CIDSTS GOTGCTL_CIDSTS_Msk // Connector ID status */ +#define GOTGCTL_DBCT_Pos (17U) +#define GOTGCTL_DBCT_Msk (0x1UL << GOTGCTL_DBCT_Pos) // 0x00020000 */ +#define GOTGCTL_DBCT GOTGCTL_DBCT_Msk // Long/short debounce time */ +#define GOTGCTL_ASVLD_Pos (18U) +#define GOTGCTL_ASVLD_Msk (0x1UL << GOTGCTL_ASVLD_Pos) // 0x00040000 */ +#define GOTGCTL_ASVLD GOTGCTL_ASVLD_Msk // A-session valid */ +#define GOTGCTL_BSESVLD_Pos (19U) +#define GOTGCTL_BSESVLD_Msk (0x1UL << GOTGCTL_BSESVLD_Pos) // 0x00080000 */ +#define GOTGCTL_BSESVLD GOTGCTL_BSESVLD_Msk // B-session valid */ +#define GOTGCTL_OTGVER_Pos (20U) +#define GOTGCTL_OTGVER_Msk (0x1UL << GOTGCTL_OTGVER_Pos) // 0x00100000 */ +#define GOTGCTL_OTGVER GOTGCTL_OTGVER_Msk // OTG version */ + +/******************** Bit definition for HCFG register ********************/ +#define HCFG_FSLSPCS_Pos (0U) +#define HCFG_FSLSPCS_Msk (0x3UL << HCFG_FSLSPCS_Pos) // 0x00000003 */ +#define HCFG_FSLSPCS HCFG_FSLSPCS_Msk // FS/LS PHY clock select */ +#define HCFG_FSLSPCS_0 (0x1UL << HCFG_FSLSPCS_Pos) // 0x00000001 */ +#define HCFG_FSLSPCS_1 (0x2UL << HCFG_FSLSPCS_Pos) // 0x00000002 */ +#define HCFG_FSLSS_Pos (2U) +#define HCFG_FSLSS_Msk (0x1UL << HCFG_FSLSS_Pos) // 0x00000004 */ +#define HCFG_FSLSS HCFG_FSLSS_Msk // FS- and LS-only support */ + +/******************** Bit definition for PCGCR register ********************/ +#define PCGCR_STPPCLK_Pos (0U) +#define PCGCR_STPPCLK_Msk (0x1UL << PCGCR_STPPCLK_Pos) // 0x00000001 */ +#define PCGCR_STPPCLK PCGCR_STPPCLK_Msk // Stop PHY clock */ +#define PCGCR_GATEHCLK_Pos (1U) +#define PCGCR_GATEHCLK_Msk (0x1UL << PCGCR_GATEHCLK_Pos) // 0x00000002 */ +#define PCGCR_GATEHCLK PCGCR_GATEHCLK_Msk // Gate HCLK */ +#define PCGCR_PHYSUSP_Pos (4U) +#define PCGCR_PHYSUSP_Msk (0x1UL << PCGCR_PHYSUSP_Pos) // 0x00000010 */ +#define PCGCR_PHYSUSP PCGCR_PHYSUSP_Msk // PHY suspended */ + +/******************** Bit definition for GOTGINT register ********************/ +#define GOTGINT_SEDET_Pos (2U) +#define GOTGINT_SEDET_Msk (0x1UL << GOTGINT_SEDET_Pos) // 0x00000004 */ +#define GOTGINT_SEDET GOTGINT_SEDET_Msk // Session end detected */ +#define GOTGINT_SRSSCHG_Pos (8U) +#define GOTGINT_SRSSCHG_Msk (0x1UL << GOTGINT_SRSSCHG_Pos) // 0x00000100 */ +#define GOTGINT_SRSSCHG GOTGINT_SRSSCHG_Msk // Session request success status change */ +#define GOTGINT_HNSSCHG_Pos (9U) +#define GOTGINT_HNSSCHG_Msk (0x1UL << GOTGINT_HNSSCHG_Pos) // 0x00000200 */ +#define GOTGINT_HNSSCHG GOTGINT_HNSSCHG_Msk // Host negotiation success status change */ +#define GOTGINT_HNGDET_Pos (17U) +#define GOTGINT_HNGDET_Msk (0x1UL << GOTGINT_HNGDET_Pos) // 0x00020000 */ +#define GOTGINT_HNGDET GOTGINT_HNGDET_Msk // Host negotiation detected */ +#define GOTGINT_ADTOCHG_Pos (18U) +#define GOTGINT_ADTOCHG_Msk (0x1UL << GOTGINT_ADTOCHG_Pos) // 0x00040000 */ +#define GOTGINT_ADTOCHG GOTGINT_ADTOCHG_Msk // A-device timeout change */ +#define GOTGINT_DBCDNE_Pos (19U) +#define GOTGINT_DBCDNE_Msk (0x1UL << GOTGINT_DBCDNE_Pos) // 0x00080000 */ +#define GOTGINT_DBCDNE GOTGINT_DBCDNE_Msk // Debounce done */ +#define GOTGINT_IDCHNG_Pos (20U) +#define GOTGINT_IDCHNG_Msk (0x1UL << GOTGINT_IDCHNG_Pos) // 0x00100000 */ +#define GOTGINT_IDCHNG GOTGINT_IDCHNG_Msk // Change in ID pin input value */ + +/******************** Bit definition for DCFG register ********************/ +#define DCFG_DSPD_Pos (0U) +#define DCFG_DSPD_Msk (0x3UL << DCFG_DSPD_Pos) // 0x00000003 +#define DCFG_DSPD_HS 0 // Highspeed +#define DCFG_DSPD_FS_HSPHY 1 // Fullspeed on HS PHY +#define DCFG_DSPD_LS 2 // Lowspeed +#define DCFG_DSPD_FS 3 // Fullspeed on FS PHY + +#define DCFG_NZLSOHSK_Pos (2U) +#define DCFG_NZLSOHSK_Msk (0x1UL << DCFG_NZLSOHSK_Pos) // 0x00000004 */ +#define DCFG_NZLSOHSK DCFG_NZLSOHSK_Msk // Nonzero-length status OUT handshake */ + +#define DCFG_DAD_Pos (4U) +#define DCFG_DAD_Msk (0x7FUL << DCFG_DAD_Pos) // 0x000007F0 */ +#define DCFG_DAD DCFG_DAD_Msk // Device address */ +#define DCFG_DAD_0 (0x01UL << DCFG_DAD_Pos) // 0x00000010 */ +#define DCFG_DAD_1 (0x02UL << DCFG_DAD_Pos) // 0x00000020 */ +#define DCFG_DAD_2 (0x04UL << DCFG_DAD_Pos) // 0x00000040 */ +#define DCFG_DAD_3 (0x08UL << DCFG_DAD_Pos) // 0x00000080 */ +#define DCFG_DAD_4 (0x10UL << DCFG_DAD_Pos) // 0x00000100 */ +#define DCFG_DAD_5 (0x20UL << DCFG_DAD_Pos) // 0x00000200 */ +#define DCFG_DAD_6 (0x40UL << DCFG_DAD_Pos) // 0x00000400 */ + +#define DCFG_PFIVL_Pos (11U) +#define DCFG_PFIVL_Msk (0x3UL << DCFG_PFIVL_Pos) // 0x00001800 */ +#define DCFG_PFIVL DCFG_PFIVL_Msk // Periodic (micro)frame interval */ +#define DCFG_PFIVL_0 (0x1UL << DCFG_PFIVL_Pos) // 0x00000800 */ +#define DCFG_PFIVL_1 (0x2UL << DCFG_PFIVL_Pos) // 0x00001000 */ + +#define DCFG_XCVRDLY_Pos (14U) +#define DCFG_XCVRDLY_Msk (0x1UL << DCFG_XCVRDLY_Pos) /*!< 0x00004000 */ +#define DCFG_XCVRDLY DCFG_XCVRDLY_Msk // Enables delay between xcvr_sel and txvalid during device chirp + +#define DCFG_PERSCHIVL_Pos (24U) +#define DCFG_PERSCHIVL_Msk (0x3UL << DCFG_PERSCHIVL_Pos) // 0x03000000 */ +#define DCFG_PERSCHIVL DCFG_PERSCHIVL_Msk // Periodic scheduling interval */ +#define DCFG_PERSCHIVL_0 (0x1UL << DCFG_PERSCHIVL_Pos) // 0x01000000 */ +#define DCFG_PERSCHIVL_1 (0x2UL << DCFG_PERSCHIVL_Pos) // 0x02000000 */ + +/******************** Bit definition for DCTL register ********************/ +#define DCTL_RWUSIG_Pos (0U) +#define DCTL_RWUSIG_Msk (0x1UL << DCTL_RWUSIG_Pos) // 0x00000001 */ +#define DCTL_RWUSIG DCTL_RWUSIG_Msk // Remote wakeup signaling */ +#define DCTL_SDIS_Pos (1U) +#define DCTL_SDIS_Msk (0x1UL << DCTL_SDIS_Pos) // 0x00000002 */ +#define DCTL_SDIS DCTL_SDIS_Msk // Soft disconnect */ +#define DCTL_GINSTS_Pos (2U) +#define DCTL_GINSTS_Msk (0x1UL << DCTL_GINSTS_Pos) // 0x00000004 */ +#define DCTL_GINSTS DCTL_GINSTS_Msk // Global IN NAK status */ +#define DCTL_GONSTS_Pos (3U) +#define DCTL_GONSTS_Msk (0x1UL << DCTL_GONSTS_Pos) // 0x00000008 */ +#define DCTL_GONSTS DCTL_GONSTS_Msk // Global OUT NAK status */ + +#define DCTL_TCTL_Pos (4U) +#define DCTL_TCTL_Msk (0x7UL << DCTL_TCTL_Pos) // 0x00000070 */ +#define DCTL_TCTL DCTL_TCTL_Msk // Test control */ +#define DCTL_TCTL_0 (0x1UL << DCTL_TCTL_Pos) // 0x00000010 */ +#define DCTL_TCTL_1 (0x2UL << DCTL_TCTL_Pos) // 0x00000020 */ +#define DCTL_TCTL_2 (0x4UL << DCTL_TCTL_Pos) // 0x00000040 */ +#define DCTL_SGINAK_Pos (7U) +#define DCTL_SGINAK_Msk (0x1UL << DCTL_SGINAK_Pos) // 0x00000080 */ +#define DCTL_SGINAK DCTL_SGINAK_Msk // Set global IN NAK */ +#define DCTL_CGINAK_Pos (8U) +#define DCTL_CGINAK_Msk (0x1UL << DCTL_CGINAK_Pos) // 0x00000100 */ +#define DCTL_CGINAK DCTL_CGINAK_Msk // Clear global IN NAK */ +#define DCTL_SGONAK_Pos (9U) +#define DCTL_SGONAK_Msk (0x1UL << DCTL_SGONAK_Pos) // 0x00000200 */ +#define DCTL_SGONAK DCTL_SGONAK_Msk // Set global OUT NAK */ +#define DCTL_CGONAK_Pos (10U) +#define DCTL_CGONAK_Msk (0x1UL << DCTL_CGONAK_Pos) // 0x00000400 */ +#define DCTL_CGONAK DCTL_CGONAK_Msk // Clear global OUT NAK */ +#define DCTL_POPRGDNE_Pos (11U) +#define DCTL_POPRGDNE_Msk (0x1UL << DCTL_POPRGDNE_Pos) // 0x00000800 */ +#define DCTL_POPRGDNE DCTL_POPRGDNE_Msk // Power-on programming done */ + +/******************** Bit definition for HFIR register ********************/ +#define HFIR_FRIVL_Pos (0U) +#define HFIR_FRIVL_Msk (0xFFFFUL << HFIR_FRIVL_Pos) // 0x0000FFFF */ +#define HFIR_FRIVL HFIR_FRIVL_Msk // Frame interval */ + +/******************** Bit definition for HFNUM register ********************/ +#define HFNUM_FRNUM_Pos (0U) +#define HFNUM_FRNUM_Msk (0xFFFFUL << HFNUM_FRNUM_Pos) // 0x0000FFFF */ +#define HFNUM_FRNUM HFNUM_FRNUM_Msk // Frame number */ +#define HFNUM_FTREM_Pos (16U) +#define HFNUM_FTREM_Msk (0xFFFFUL << HFNUM_FTREM_Pos) // 0xFFFF0000 */ +#define HFNUM_FTREM HFNUM_FTREM_Msk // Frame time remaining */ + +/******************** Bit definition for DSTS register ********************/ +#define DSTS_SUSPSTS_Pos (0U) +#define DSTS_SUSPSTS_Msk (0x1UL << DSTS_SUSPSTS_Pos) // 0x00000001 */ +#define DSTS_SUSPSTS DSTS_SUSPSTS_Msk // Suspend status */ +#define DSTS_ENUMSPD_Pos (1U) +#define DSTS_ENUMSPD_Msk (0x3UL << DSTS_ENUMSPD_Pos) // 0x00000006 */ +#define DSTS_ENUMSPD DSTS_ENUMSPD_Msk // Enumerated speed */ +#define DSTS_ENUMSPD_HS 0 // Highspeed +#define DSTS_ENUMSPD_FS_HSPHY 1 // Fullspeed on HS PHY +#define DSTS_ENUMSPD_LS 2 // Lowspeed +#define DSTS_ENUMSPD_FS 3 // Fullspeed on FS PHY + + +#define DSTS_EERR_Pos (3U) +#define DSTS_EERR_Msk (0x1UL << DSTS_EERR_Pos) // 0x00000008 */ +#define DSTS_EERR DSTS_EERR_Msk // Erratic error */ +#define DSTS_FNSOF_Pos (8U) +#define DSTS_FNSOF_Msk (0x3FFFUL << DSTS_FNSOF_Pos) // 0x003FFF00 */ +#define DSTS_FNSOF DSTS_FNSOF_Msk // Frame number of the received SOF */ + +/******************** Bit definition for GAHBCFG register ********************/ +#define GAHBCFG_GINT_Pos (0U) +#define GAHBCFG_GINT_Msk (0x1UL << GAHBCFG_GINT_Pos) // 0x00000001 */ +#define GAHBCFG_GINT GAHBCFG_GINT_Msk // Global interrupt mask */ +#define GAHBCFG_HBSTLEN_Pos (1U) +#define GAHBCFG_HBSTLEN_Msk (0xFUL << GAHBCFG_HBSTLEN_Pos) // 0x0000001E */ +#define GAHBCFG_HBSTLEN GAHBCFG_HBSTLEN_Msk // Burst length/type */ +#define GAHBCFG_HBSTLEN_0 (0x0UL << GAHBCFG_HBSTLEN_Pos) // Single */ +#define GAHBCFG_HBSTLEN_1 (0x1UL << GAHBCFG_HBSTLEN_Pos) // INCR */ +#define GAHBCFG_HBSTLEN_2 (0x3UL << GAHBCFG_HBSTLEN_Pos) // INCR4 */ +#define GAHBCFG_HBSTLEN_3 (0x5UL << GAHBCFG_HBSTLEN_Pos) // INCR8 */ +#define GAHBCFG_HBSTLEN_4 (0x7UL << GAHBCFG_HBSTLEN_Pos) // INCR16 */ +#define GAHBCFG_DMAEN_Pos (5U) +#define GAHBCFG_DMAEN_Msk (0x1UL << GAHBCFG_DMAEN_Pos) // 0x00000020 */ +#define GAHBCFG_DMAEN GAHBCFG_DMAEN_Msk // DMA enable */ +#define GAHBCFG_TXFELVL_Pos (7U) +#define GAHBCFG_TXFELVL_Msk (0x1UL << GAHBCFG_TXFELVL_Pos) // 0x00000080 */ +#define GAHBCFG_TXFELVL GAHBCFG_TXFELVL_Msk // TxFIFO empty level */ +#define GAHBCFG_PTXFELVL_Pos (8U) +#define GAHBCFG_PTXFELVL_Msk (0x1UL << GAHBCFG_PTXFELVL_Pos) // 0x00000100 */ +#define GAHBCFG_PTXFELVL GAHBCFG_PTXFELVL_Msk // Periodic TxFIFO empty level */ + +#define GSNPSID_ID_MASK TU_GENMASK(31, 16) + +/******************** Bit definition for GUSBCFG register ********************/ +#define GUSBCFG_TOCAL_Pos (0U) +#define GUSBCFG_TOCAL_Msk (0x7UL << GUSBCFG_TOCAL_Pos) // 0x00000007 */ +#define GUSBCFG_TOCAL GUSBCFG_TOCAL_Msk // FS timeout calibration */ +#define GUSBCFG_PHYIF16_Pos (3U) +#define GUSBCFG_PHYIF16_Msk (0x1UL << GUSBCFG_PHYIF16_Pos) // 0x00000008 */ +#define GUSBCFG_PHYIF16 GUSBCFG_PHYIF16_Msk // PHY Interface (PHYIf) */ +#define GUSBCFG_ULPI_UTMI_SEL_Pos (4U) +#define GUSBCFG_ULPI_UTMI_SEL_Msk (0x1UL << GUSBCFG_ULPI_UTMI_SEL_Pos) // 0x00000010 */ +#define GUSBCFG_ULPI_UTMI_SEL GUSBCFG_ULPI_UTMI_SEL_Msk // ULPI or UTMI+ Select (ULPI_UTMI_Sel) */ +#define GUSBCFG_PHYSEL_Pos (6U) +#define GUSBCFG_PHYSEL_Msk (0x1UL << GUSBCFG_PHYSEL_Pos) // 0x00000040 */ +#define GUSBCFG_PHYSEL GUSBCFG_PHYSEL_Msk // USB 2.0 high-speed ULPI PHY or USB 1.1 full-speed serial transceiver select */ +#define GUSBCFG_DDRSEL TU_BIT(7) // Single Data Rate (SDR) or Double Data Rate (DDR) or ULPI interface. +#define GUSBCFG_SRPCAP_Pos (8U) +#define GUSBCFG_SRPCAP_Msk (0x1UL << GUSBCFG_SRPCAP_Pos) // 0x00000100 */ +#define GUSBCFG_SRPCAP GUSBCFG_SRPCAP_Msk // SRP-capable */ +#define GUSBCFG_HNPCAP_Pos (9U) +#define GUSBCFG_HNPCAP_Msk (0x1UL << GUSBCFG_HNPCAP_Pos) // 0x00000200 */ +#define GUSBCFG_HNPCAP GUSBCFG_HNPCAP_Msk // HNP-capable */ +#define GUSBCFG_TRDT_Pos (10U) +#define GUSBCFG_TRDT_Msk (0xFUL << GUSBCFG_TRDT_Pos) // 0x00003C00 */ +#define GUSBCFG_TRDT GUSBCFG_TRDT_Msk // USB turnaround time */ +#define GUSBCFG_PHYLPCS_Pos (15U) +#define GUSBCFG_PHYLPCS_Msk (0x1UL << GUSBCFG_PHYLPCS_Pos) // 0x00008000 */ +#define GUSBCFG_PHYLPCS GUSBCFG_PHYLPCS_Msk // PHY Low-power clock select */ +#define GUSBCFG_ULPIFSLS_Pos (17U) +#define GUSBCFG_ULPIFSLS_Msk (0x1UL << GUSBCFG_ULPIFSLS_Pos) // 0x00020000 */ +#define GUSBCFG_ULPIFSLS GUSBCFG_ULPIFSLS_Msk // ULPI FS/LS select */ +#define GUSBCFG_ULPIAR_Pos (18U) +#define GUSBCFG_ULPIAR_Msk (0x1UL << GUSBCFG_ULPIAR_Pos) // 0x00040000 */ +#define GUSBCFG_ULPIAR GUSBCFG_ULPIAR_Msk // ULPI Auto-resume */ +#define GUSBCFG_ULPICSM_Pos (19U) +#define GUSBCFG_ULPICSM_Msk (0x1UL << GUSBCFG_ULPICSM_Pos) // 0x00080000 */ +#define GUSBCFG_ULPICSM GUSBCFG_ULPICSM_Msk // ULPI Clock SuspendM */ +#define GUSBCFG_ULPIEVBUSD_Pos (20U) +#define GUSBCFG_ULPIEVBUSD_Msk (0x1UL << GUSBCFG_ULPIEVBUSD_Pos) // 0x00100000 */ +#define GUSBCFG_ULPIEVBUSD GUSBCFG_ULPIEVBUSD_Msk // ULPI External VBUS Drive */ +#define GUSBCFG_ULPIEVBUSI_Pos (21U) +#define GUSBCFG_ULPIEVBUSI_Msk (0x1UL << GUSBCFG_ULPIEVBUSI_Pos) // 0x00200000 */ +#define GUSBCFG_ULPIEVBUSI GUSBCFG_ULPIEVBUSI_Msk // ULPI external VBUS indicator */ +#define GUSBCFG_TSDPS_Pos (22U) +#define GUSBCFG_TSDPS_Msk (0x1UL << GUSBCFG_TSDPS_Pos) // 0x00400000 */ +#define GUSBCFG_TSDPS GUSBCFG_TSDPS_Msk // TermSel DLine pulsing selection */ +#define GUSBCFG_PCCI_Pos (23U) +#define GUSBCFG_PCCI_Msk (0x1UL << GUSBCFG_PCCI_Pos) // 0x00800000 */ +#define GUSBCFG_PCCI GUSBCFG_PCCI_Msk // Indicator complement */ +#define GUSBCFG_PTCI_Pos (24U) +#define GUSBCFG_PTCI_Msk (0x1UL << GUSBCFG_PTCI_Pos) // 0x01000000 */ +#define GUSBCFG_PTCI GUSBCFG_PTCI_Msk // Indicator pass through */ +#define GUSBCFG_ULPIIPD_Pos (25U) +#define GUSBCFG_ULPIIPD_Msk (0x1UL << GUSBCFG_ULPIIPD_Pos) // 0x02000000 */ +#define GUSBCFG_ULPIIPD GUSBCFG_ULPIIPD_Msk // ULPI interface protect disable */ +#define GUSBCFG_FHMOD_Pos (29U) +#define GUSBCFG_FHMOD_Msk (0x1UL << GUSBCFG_FHMOD_Pos) // 0x20000000 */ +#define GUSBCFG_FHMOD GUSBCFG_FHMOD_Msk // Forced host mode */ +#define GUSBCFG_FDMOD_Pos (30U) +#define GUSBCFG_FDMOD_Msk (0x1UL << GUSBCFG_FDMOD_Pos) // 0x40000000 */ +#define GUSBCFG_FDMOD GUSBCFG_FDMOD_Msk // Forced peripheral mode */ +#define GUSBCFG_CTXPKT_Pos (31U) +#define GUSBCFG_CTXPKT_Msk (0x1UL << GUSBCFG_CTXPKT_Pos) // 0x80000000 */ +#define GUSBCFG_CTXPKT GUSBCFG_CTXPKT_Msk // Corrupt Tx packet */ + +/******************** Bit definition for GRSTCTL register ********************/ +#define GRSTCTL_CSRST_Pos (0U) +#define GRSTCTL_CSRST_Msk (0x1UL << GRSTCTL_CSRST_Pos) // 0x00000001 */ +#define GRSTCTL_CSRST GRSTCTL_CSRST_Msk // Core soft reset */ +#define GRSTCTL_HSRST_Pos (1U) +#define GRSTCTL_HSRST_Msk (0x1UL << GRSTCTL_HSRST_Pos) // 0x00000002 */ +#define GRSTCTL_HSRST GRSTCTL_HSRST_Msk // HCLK soft reset */ +#define GRSTCTL_FCRST_Pos (2U) +#define GRSTCTL_FCRST_Msk (0x1UL << GRSTCTL_FCRST_Pos) // 0x00000004 */ +#define GRSTCTL_FCRST GRSTCTL_FCRST_Msk // Host frame counter reset */ +#define GRSTCTL_RXFFLSH_Pos (4U) +#define GRSTCTL_RXFFLSH_Msk (0x1UL << GRSTCTL_RXFFLSH_Pos) // 0x00000010 */ +#define GRSTCTL_RXFFLSH GRSTCTL_RXFFLSH_Msk // RxFIFO flush */ +#define GRSTCTL_TXFFLSH_Pos (5U) +#define GRSTCTL_TXFFLSH_Msk (0x1UL << GRSTCTL_TXFFLSH_Pos) // 0x00000020 */ +#define GRSTCTL_TXFFLSH GRSTCTL_TXFFLSH_Msk // TxFIFO flush */ +#define GRSTCTL_TXFNUM_Pos (6U) +#define GRSTCTL_TXFNUM_Msk (0x1FUL << GRSTCTL_TXFNUM_Pos) // 0x000007C0 */ +#define GRSTCTL_TXFNUM GRSTCTL_TXFNUM_Msk // TxFIFO number */ +#define GRSTCTL_TXFNUM_0 (0x01UL << GRSTCTL_TXFNUM_Pos) // 0x00000040 */ +#define GRSTCTL_TXFNUM_1 (0x02UL << GRSTCTL_TXFNUM_Pos) // 0x00000080 */ +#define GRSTCTL_TXFNUM_2 (0x04UL << GRSTCTL_TXFNUM_Pos) // 0x00000100 */ +#define GRSTCTL_TXFNUM_3 (0x08UL << GRSTCTL_TXFNUM_Pos) // 0x00000200 */ +#define GRSTCTL_TXFNUM_4 (0x10UL << GRSTCTL_TXFNUM_Pos) // 0x00000400 */ +#define GRSTCTL_CSFTRST_DONE_Pos (29) +#define GRSTCTL_CSFTRST_DONE (1u << GRSTCTL_CSFTRST_DONE_Pos) // Reset Done, only available from v4.20a +#define GRSTCTL_DMAREQ_Pos (30U) +#define GRSTCTL_DMAREQ_Msk (0x1UL << GRSTCTL_DMAREQ_Pos) // 0x40000000 */ +#define GRSTCTL_DMAREQ GRSTCTL_DMAREQ_Msk // DMA request signal */ +#define GRSTCTL_AHBIDL_Pos (31U) +#define GRSTCTL_AHBIDL_Msk (0x1UL << GRSTCTL_AHBIDL_Pos) // 0x80000000 */ +#define GRSTCTL_AHBIDL GRSTCTL_AHBIDL_Msk // AHB master idle */ + +/******************** Bit definition for DIEPMSK register ********************/ +#define DIEPMSK_XFRCM_Pos (0U) +#define DIEPMSK_XFRCM_Msk (0x1UL << DIEPMSK_XFRCM_Pos) // 0x00000001 */ +#define DIEPMSK_XFRCM DIEPMSK_XFRCM_Msk // Transfer completed interrupt mask */ +#define DIEPMSK_EPDM_Pos (1U) +#define DIEPMSK_EPDM_Msk (0x1UL << DIEPMSK_EPDM_Pos) // 0x00000002 */ +#define DIEPMSK_EPDM DIEPMSK_EPDM_Msk // Endpoint disabled interrupt mask */ +#define DIEPMSK_TOM_Pos (3U) +#define DIEPMSK_TOM_Msk (0x1UL << DIEPMSK_TOM_Pos) // 0x00000008 */ +#define DIEPMSK_TOM DIEPMSK_TOM_Msk // Timeout condition mask (nonisochronous endpoints) */ +#define DIEPMSK_ITTXFEMSK_Pos (4U) +#define DIEPMSK_ITTXFEMSK_Msk (0x1UL << DIEPMSK_ITTXFEMSK_Pos) // 0x00000010 */ +#define DIEPMSK_ITTXFEMSK DIEPMSK_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask */ +#define DIEPMSK_INEPNMM_Pos (5U) +#define DIEPMSK_INEPNMM_Msk (0x1UL << DIEPMSK_INEPNMM_Pos) // 0x00000020 */ +#define DIEPMSK_INEPNMM DIEPMSK_INEPNMM_Msk // IN token received with EP mismatch mask */ +#define DIEPMSK_INEPNEM_Pos (6U) +#define DIEPMSK_INEPNEM_Msk (0x1UL << DIEPMSK_INEPNEM_Pos) // 0x00000040 */ +#define DIEPMSK_INEPNEM DIEPMSK_INEPNEM_Msk // IN endpoint NAK effective mask */ +#define DIEPMSK_TXFURM_Pos (8U) +#define DIEPMSK_TXFURM_Msk (0x1UL << DIEPMSK_TXFURM_Pos) // 0x00000100 */ +#define DIEPMSK_TXFURM DIEPMSK_TXFURM_Msk // FIFO underrun mask */ +#define DIEPMSK_BIM_Pos (9U) +#define DIEPMSK_BIM_Msk (0x1UL << DIEPMSK_BIM_Pos) // 0x00000200 */ +#define DIEPMSK_BIM DIEPMSK_BIM_Msk // BNA interrupt mask */ + +/******************** Bit definition for HPTXSTS register ********************/ +#define HPTXSTS_PTXFSAVL_Pos (0U) +#define HPTXSTS_PTXFSAVL_Msk (0xFFFFUL << HPTXSTS_PTXFSAVL_Pos) // 0x0000FFFF */ +#define HPTXSTS_PTXFSAVL HPTXSTS_PTXFSAVL_Msk // Periodic transmit data FIFO space available */ +#define HPTXSTS_PTXQSAV_Pos (16U) +#define HPTXSTS_PTXQSAV_Msk (0xFFUL << HPTXSTS_PTXQSAV_Pos) // 0x00FF0000 */ +#define HPTXSTS_PTXQSAV HPTXSTS_PTXQSAV_Msk // Periodic transmit request queue space available */ +#define HPTXSTS_PTXQSAV_0 (0x01UL << HPTXSTS_PTXQSAV_Pos) // 0x00010000 */ +#define HPTXSTS_PTXQSAV_1 (0x02UL << HPTXSTS_PTXQSAV_Pos) // 0x00020000 */ +#define HPTXSTS_PTXQSAV_2 (0x04UL << HPTXSTS_PTXQSAV_Pos) // 0x00040000 */ +#define HPTXSTS_PTXQSAV_3 (0x08UL << HPTXSTS_PTXQSAV_Pos) // 0x00080000 */ +#define HPTXSTS_PTXQSAV_4 (0x10UL << HPTXSTS_PTXQSAV_Pos) // 0x00100000 */ +#define HPTXSTS_PTXQSAV_5 (0x20UL << HPTXSTS_PTXQSAV_Pos) // 0x00200000 */ +#define HPTXSTS_PTXQSAV_6 (0x40UL << HPTXSTS_PTXQSAV_Pos) // 0x00400000 */ +#define HPTXSTS_PTXQSAV_7 (0x80UL << HPTXSTS_PTXQSAV_Pos) // 0x00800000 */ + +#define HPTXSTS_PTXQTOP_Pos (24U) +#define HPTXSTS_PTXQTOP_Msk (0xFFUL << HPTXSTS_PTXQTOP_Pos) // 0xFF000000 */ +#define HPTXSTS_PTXQTOP HPTXSTS_PTXQTOP_Msk // Top of the periodic transmit request queue */ +#define HPTXSTS_PTXQTOP_0 (0x01UL << HPTXSTS_PTXQTOP_Pos) // 0x01000000 */ +#define HPTXSTS_PTXQTOP_1 (0x02UL << HPTXSTS_PTXQTOP_Pos) // 0x02000000 */ +#define HPTXSTS_PTXQTOP_2 (0x04UL << HPTXSTS_PTXQTOP_Pos) // 0x04000000 */ +#define HPTXSTS_PTXQTOP_3 (0x08UL << HPTXSTS_PTXQTOP_Pos) // 0x08000000 */ +#define HPTXSTS_PTXQTOP_4 (0x10UL << HPTXSTS_PTXQTOP_Pos) // 0x10000000 */ +#define HPTXSTS_PTXQTOP_5 (0x20UL << HPTXSTS_PTXQTOP_Pos) // 0x20000000 */ +#define HPTXSTS_PTXQTOP_6 (0x40UL << HPTXSTS_PTXQTOP_Pos) // 0x40000000 */ +#define HPTXSTS_PTXQTOP_7 (0x80UL << HPTXSTS_PTXQTOP_Pos) // 0x80000000 */ + +/******************** Bit definition for HAINT register ********************/ +#define HAINT_HAINT_Pos (0U) +#define HAINT_HAINT_Msk (0xFFFFUL << HAINT_HAINT_Pos) // 0x0000FFFF */ +#define HAINT_HAINT HAINT_HAINT_Msk // Channel interrupts */ + +/******************** Bit definition for DOEPMSK register ********************/ +#define DOEPMSK_XFRCM_Pos (0U) +#define DOEPMSK_XFRCM_Msk (0x1UL << DOEPMSK_XFRCM_Pos) // 0x00000001 */ +#define DOEPMSK_XFRCM DOEPMSK_XFRCM_Msk // Transfer completed interrupt mask */ +#define DOEPMSK_EPDM_Pos (1U) +#define DOEPMSK_EPDM_Msk (0x1UL << DOEPMSK_EPDM_Pos) // 0x00000002 */ +#define DOEPMSK_EPDM DOEPMSK_EPDM_Msk // Endpoint disabled interrupt mask */ +#define DOEPMSK_AHBERRM_Pos (2U) +#define DOEPMSK_AHBERRM_Msk (0x1UL << DOEPMSK_AHBERRM_Pos) // 0x00000004 */ +#define DOEPMSK_AHBERRM DOEPMSK_AHBERRM_Msk // OUT transaction AHB Error interrupt mask */ +#define DOEPMSK_STUPM_Pos (3U) +#define DOEPMSK_STUPM_Msk (0x1UL << DOEPMSK_STUPM_Pos) // 0x00000008 */ +#define DOEPMSK_STUPM DOEPMSK_STUPM_Msk // SETUP phase done mask */ +#define DOEPMSK_OTEPDM_Pos (4U) +#define DOEPMSK_OTEPDM_Msk (0x1UL << DOEPMSK_OTEPDM_Pos) // 0x00000010 */ +#define DOEPMSK_OTEPDM DOEPMSK_OTEPDM_Msk // OUT token received when endpoint disabled mask */ +#define DOEPMSK_OTEPSPRM_Pos (5U) +#define DOEPMSK_OTEPSPRM_Msk (0x1UL << DOEPMSK_OTEPSPRM_Pos) // 0x00000020 */ +#define DOEPMSK_OTEPSPRM DOEPMSK_OTEPSPRM_Msk // Status Phase Received mask */ +#define DOEPMSK_B2BSTUP_Pos (6U) +#define DOEPMSK_B2BSTUP_Msk (0x1UL << DOEPMSK_B2BSTUP_Pos) // 0x00000040 */ +#define DOEPMSK_B2BSTUP DOEPMSK_B2BSTUP_Msk // Back-to-back SETUP packets received mask */ +#define DOEPMSK_OPEM_Pos (8U) +#define DOEPMSK_OPEM_Msk (0x1UL << DOEPMSK_OPEM_Pos) // 0x00000100 */ +#define DOEPMSK_OPEM DOEPMSK_OPEM_Msk // OUT packet error mask */ +#define DOEPMSK_BOIM_Pos (9U) +#define DOEPMSK_BOIM_Msk (0x1UL << DOEPMSK_BOIM_Pos) // 0x00000200 */ +#define DOEPMSK_BOIM DOEPMSK_BOIM_Msk // BNA interrupt mask */ +#define DOEPMSK_BERRM_Pos (12U) +#define DOEPMSK_BERRM_Msk (0x1UL << DOEPMSK_BERRM_Pos) // 0x00001000 */ +#define DOEPMSK_BERRM DOEPMSK_BERRM_Msk // Babble error interrupt mask */ +#define DOEPMSK_NAKM_Pos (13U) +#define DOEPMSK_NAKM_Msk (0x1UL << DOEPMSK_NAKM_Pos) // 0x00002000 */ +#define DOEPMSK_NAKM DOEPMSK_NAKM_Msk // OUT Packet NAK interrupt mask */ +#define DOEPMSK_NYETM_Pos (14U) +#define DOEPMSK_NYETM_Msk (0x1UL << DOEPMSK_NYETM_Pos) // 0x00004000 */ +#define DOEPMSK_NYETM DOEPMSK_NYETM_Msk // NYET interrupt mask */ + +/******************** Bit definition for GINTSTS register ********************/ +#define GINTSTS_CMOD_Pos (0U) +#define GINTSTS_CMOD_Msk (0x1UL << GINTSTS_CMOD_Pos) // 0x00000001 */ +#define GINTSTS_CMOD GINTSTS_CMOD_Msk // Current mode of operation */ +#define GINTSTS_MMIS_Pos (1U) +#define GINTSTS_MMIS_Msk (0x1UL << GINTSTS_MMIS_Pos) // 0x00000002 */ +#define GINTSTS_MMIS GINTSTS_MMIS_Msk // Mode mismatch interrupt */ +#define GINTSTS_OTGINT_Pos (2U) +#define GINTSTS_OTGINT_Msk (0x1UL << GINTSTS_OTGINT_Pos) // 0x00000004 */ +#define GINTSTS_OTGINT GINTSTS_OTGINT_Msk // OTG interrupt */ +#define GINTSTS_SOF_Pos (3U) +#define GINTSTS_SOF_Msk (0x1UL << GINTSTS_SOF_Pos) // 0x00000008 */ +#define GINTSTS_SOF GINTSTS_SOF_Msk // Start of frame */ +#define GINTSTS_RXFLVL_Pos (4U) +#define GINTSTS_RXFLVL_Msk (0x1UL << GINTSTS_RXFLVL_Pos) // 0x00000010 */ +#define GINTSTS_RXFLVL GINTSTS_RXFLVL_Msk // RxFIFO nonempty */ +#define GINTSTS_NPTXFE_Pos (5U) +#define GINTSTS_NPTXFE_Msk (0x1UL << GINTSTS_NPTXFE_Pos) // 0x00000020 */ +#define GINTSTS_NPTXFE GINTSTS_NPTXFE_Msk // Nonperiodic TxFIFO empty */ +#define GINTSTS_GINAKEFF_Pos (6U) +#define GINTSTS_GINAKEFF_Msk (0x1UL << GINTSTS_GINAKEFF_Pos) // 0x00000040 */ +#define GINTSTS_GINAKEFF GINTSTS_GINAKEFF_Msk // Global IN nonperiodic NAK effective */ +#define GINTSTS_BOUTNAKEFF_Pos (7U) +#define GINTSTS_BOUTNAKEFF_Msk (0x1UL << GINTSTS_BOUTNAKEFF_Pos) // 0x00000080 */ +#define GINTSTS_BOUTNAKEFF GINTSTS_BOUTNAKEFF_Msk // Global OUT NAK effective */ +#define GINTSTS_ESUSP_Pos (10U) +#define GINTSTS_ESUSP_Msk (0x1UL << GINTSTS_ESUSP_Pos) // 0x00000400 */ +#define GINTSTS_ESUSP GINTSTS_ESUSP_Msk // Early suspend */ +#define GINTSTS_USBSUSP_Pos (11U) +#define GINTSTS_USBSUSP_Msk (0x1UL << GINTSTS_USBSUSP_Pos) // 0x00000800 */ +#define GINTSTS_USBSUSP GINTSTS_USBSUSP_Msk // USB suspend */ +#define GINTSTS_USBRST_Pos (12U) +#define GINTSTS_USBRST_Msk (0x1UL << GINTSTS_USBRST_Pos) // 0x00001000 */ +#define GINTSTS_USBRST GINTSTS_USBRST_Msk // USB reset */ +#define GINTSTS_ENUMDNE_Pos (13U) +#define GINTSTS_ENUMDNE_Msk (0x1UL << GINTSTS_ENUMDNE_Pos) // 0x00002000 */ +#define GINTSTS_ENUMDNE GINTSTS_ENUMDNE_Msk // Enumeration done */ +#define GINTSTS_ISOODRP_Pos (14U) +#define GINTSTS_ISOODRP_Msk (0x1UL << GINTSTS_ISOODRP_Pos) // 0x00004000 */ +#define GINTSTS_ISOODRP GINTSTS_ISOODRP_Msk // Isochronous OUT packet dropped interrupt */ +#define GINTSTS_EOPF_Pos (15U) +#define GINTSTS_EOPF_Msk (0x1UL << GINTSTS_EOPF_Pos) // 0x00008000 */ +#define GINTSTS_EOPF GINTSTS_EOPF_Msk // End of periodic frame interrupt */ +#define GINTSTS_IEPINT_Pos (18U) +#define GINTSTS_IEPINT_Msk (0x1UL << GINTSTS_IEPINT_Pos) // 0x00040000 */ +#define GINTSTS_IEPINT GINTSTS_IEPINT_Msk // IN endpoint interrupt */ +#define GINTSTS_OEPINT_Pos (19U) +#define GINTSTS_OEPINT_Msk (0x1UL << GINTSTS_OEPINT_Pos) // 0x00080000 */ +#define GINTSTS_OEPINT GINTSTS_OEPINT_Msk // OUT endpoint interrupt */ +#define GINTSTS_IISOIXFR_Pos (20U) +#define GINTSTS_IISOIXFR_Msk (0x1UL << GINTSTS_IISOIXFR_Pos) // 0x00100000 */ +#define GINTSTS_IISOIXFR GINTSTS_IISOIXFR_Msk // Incomplete isochronous IN transfer */ +#define GINTSTS_PXFR_INCOMPISOOUT_Pos (21U) +#define GINTSTS_PXFR_INCOMPISOOUT_Msk (0x1UL << GINTSTS_PXFR_INCOMPISOOUT_Pos) // 0x00200000 */ +#define GINTSTS_PXFR_INCOMPISOOUT GINTSTS_PXFR_INCOMPISOOUT_Msk // Incomplete periodic transfer */ +#define GINTSTS_DATAFSUSP_Pos (22U) +#define GINTSTS_DATAFSUSP_Msk (0x1UL << GINTSTS_DATAFSUSP_Pos) // 0x00400000 */ +#define GINTSTS_DATAFSUSP GINTSTS_DATAFSUSP_Msk // Data fetch suspended */ +#define GINTSTS_RSTDET_Pos (23U) +#define GINTSTS_RSTDET_Msk (0x1UL << GINTSTS_RSTDET_Pos) // 0x00800000 */ +#define GINTSTS_RSTDET GINTSTS_RSTDET_Msk // Reset detected interrupt */ +#define GINTSTS_HPRTINT_Pos (24U) +#define GINTSTS_HPRTINT_Msk (0x1UL << GINTSTS_HPRTINT_Pos) // 0x01000000 */ +#define GINTSTS_HPRTINT GINTSTS_HPRTINT_Msk // Host port interrupt */ +#define GINTSTS_HCINT_Pos (25U) +#define GINTSTS_HCINT_Msk (0x1UL << GINTSTS_HCINT_Pos) // 0x02000000 */ +#define GINTSTS_HCINT GINTSTS_HCINT_Msk // Host channels interrupt */ +#define GINTSTS_PTXFE_Pos (26U) +#define GINTSTS_PTXFE_Msk (0x1UL << GINTSTS_PTXFE_Pos) // 0x04000000 */ +#define GINTSTS_PTXFE GINTSTS_PTXFE_Msk // Periodic TxFIFO empty */ +#define GINTSTS_LPMINT_Pos (27U) +#define GINTSTS_LPMINT_Msk (0x1UL << GINTSTS_LPMINT_Pos) // 0x08000000 */ +#define GINTSTS_LPMINT GINTSTS_LPMINT_Msk // LPM interrupt */ +#define GINTSTS_CIDSCHG_Pos (28U) +#define GINTSTS_CIDSCHG_Msk (0x1UL << GINTSTS_CIDSCHG_Pos) // 0x10000000 */ +#define GINTSTS_CIDSCHG GINTSTS_CIDSCHG_Msk // Connector ID status change */ +#define GINTSTS_DISCINT_Pos (29U) +#define GINTSTS_DISCINT_Msk (0x1UL << GINTSTS_DISCINT_Pos) // 0x20000000 */ +#define GINTSTS_DISCINT GINTSTS_DISCINT_Msk // Disconnect detected interrupt */ +#define GINTSTS_SRQINT_Pos (30U) +#define GINTSTS_SRQINT_Msk (0x1UL << GINTSTS_SRQINT_Pos) // 0x40000000 */ +#define GINTSTS_SRQINT GINTSTS_SRQINT_Msk // Session request/new session detected interrupt */ +#define GINTSTS_WKUINT_Pos (31U) +#define GINTSTS_WKUINT_Msk (0x1UL << GINTSTS_WKUINT_Pos) // 0x80000000 */ +#define GINTSTS_WKUINT GINTSTS_WKUINT_Msk // Resume/remote wakeup detected interrupt */ + +/******************** Bit definition for GINTMSK register ********************/ +#define GINTMSK_MMISM_Pos (1U) +#define GINTMSK_MMISM_Msk (0x1UL << GINTMSK_MMISM_Pos) // 0x00000002 */ +#define GINTMSK_MMISM GINTMSK_MMISM_Msk // Mode mismatch interrupt mask */ +#define GINTMSK_OTGINT_Pos (2U) +#define GINTMSK_OTGINT_Msk (0x1UL << GINTMSK_OTGINT_Pos) // 0x00000004 */ +#define GINTMSK_OTGINT GINTMSK_OTGINT_Msk // OTG interrupt mask */ +#define GINTMSK_SOFM_Pos (3U) +#define GINTMSK_SOFM_Msk (0x1UL << GINTMSK_SOFM_Pos) // 0x00000008 */ +#define GINTMSK_SOFM GINTMSK_SOFM_Msk // Start of frame mask */ +#define GINTMSK_RXFLVLM_Pos (4U) +#define GINTMSK_RXFLVLM_Msk (0x1UL << GINTMSK_RXFLVLM_Pos) // 0x00000010 */ +#define GINTMSK_RXFLVLM GINTMSK_RXFLVLM_Msk // Receive FIFO nonempty mask */ +#define GINTMSK_NPTXFEM_Pos (5U) +#define GINTMSK_NPTXFEM_Msk (0x1UL << GINTMSK_NPTXFEM_Pos) // 0x00000020 */ +#define GINTMSK_NPTXFEM GINTMSK_NPTXFEM_Msk // Nonperiodic TxFIFO empty mask */ +#define GINTMSK_GINAKEFFM_Pos (6U) +#define GINTMSK_GINAKEFFM_Msk (0x1UL << GINTMSK_GINAKEFFM_Pos) // 0x00000040 */ +#define GINTMSK_GINAKEFFM GINTMSK_GINAKEFFM_Msk // Global nonperiodic IN NAK effective mask */ +#define GINTMSK_GONAKEFFM_Pos (7U) +#define GINTMSK_GONAKEFFM_Msk (0x1UL << GINTMSK_GONAKEFFM_Pos) // 0x00000080 */ +#define GINTMSK_GONAKEFFM GINTMSK_GONAKEFFM_Msk // Global OUT NAK effective mask */ +#define GINTMSK_ESUSPM_Pos (10U) +#define GINTMSK_ESUSPM_Msk (0x1UL << GINTMSK_ESUSPM_Pos) // 0x00000400 */ +#define GINTMSK_ESUSPM GINTMSK_ESUSPM_Msk // Early suspend mask */ +#define GINTMSK_USBSUSPM_Pos (11U) +#define GINTMSK_USBSUSPM_Msk (0x1UL << GINTMSK_USBSUSPM_Pos) // 0x00000800 */ +#define GINTMSK_USBSUSPM GINTMSK_USBSUSPM_Msk // USB suspend mask */ +#define GINTMSK_USBRST_Pos (12U) +#define GINTMSK_USBRST_Msk (0x1UL << GINTMSK_USBRST_Pos) // 0x00001000 */ +#define GINTMSK_USBRST GINTMSK_USBRST_Msk // USB reset mask */ +#define GINTMSK_ENUMDNEM_Pos (13U) +#define GINTMSK_ENUMDNEM_Msk (0x1UL << GINTMSK_ENUMDNEM_Pos) // 0x00002000 */ +#define GINTMSK_ENUMDNEM GINTMSK_ENUMDNEM_Msk // Enumeration done mask */ +#define GINTMSK_ISOODRPM_Pos (14U) +#define GINTMSK_ISOODRPM_Msk (0x1UL << GINTMSK_ISOODRPM_Pos) // 0x00004000 */ +#define GINTMSK_ISOODRPM GINTMSK_ISOODRPM_Msk // Isochronous OUT packet dropped interrupt mask */ +#define GINTMSK_EOPFM_Pos (15U) +#define GINTMSK_EOPFM_Msk (0x1UL << GINTMSK_EOPFM_Pos) // 0x00008000 */ +#define GINTMSK_EOPFM GINTMSK_EOPFM_Msk // End of periodic frame interrupt mask */ +#define GINTMSK_EPMISM_Pos (17U) +#define GINTMSK_EPMISM_Msk (0x1UL << GINTMSK_EPMISM_Pos) // 0x00020000 */ +#define GINTMSK_EPMISM GINTMSK_EPMISM_Msk // Endpoint mismatch interrupt mask */ +#define GINTMSK_IEPINT_Pos (18U) +#define GINTMSK_IEPINT_Msk (0x1UL << GINTMSK_IEPINT_Pos) // 0x00040000 */ +#define GINTMSK_IEPINT GINTMSK_IEPINT_Msk // IN endpoints interrupt mask */ +#define GINTMSK_OEPINT_Pos (19U) +#define GINTMSK_OEPINT_Msk (0x1UL << GINTMSK_OEPINT_Pos) // 0x00080000 */ +#define GINTMSK_OEPINT GINTMSK_OEPINT_Msk // OUT endpoints interrupt mask */ +#define GINTMSK_IISOIXFRM_Pos (20U) +#define GINTMSK_IISOIXFRM_Msk (0x1UL << GINTMSK_IISOIXFRM_Pos) // 0x00100000 */ +#define GINTMSK_IISOIXFRM GINTMSK_IISOIXFRM_Msk // Incomplete isochronous IN transfer mask */ +#define GINTMSK_PXFRM_IISOOXFRM_Pos (21U) +#define GINTMSK_PXFRM_IISOOXFRM_Msk (0x1UL << GINTMSK_PXFRM_IISOOXFRM_Pos) // 0x00200000 */ +#define GINTMSK_PXFRM_IISOOXFRM GINTMSK_PXFRM_IISOOXFRM_Msk // Incomplete periodic transfer mask */ +#define GINTMSK_FSUSPM_Pos (22U) +#define GINTMSK_FSUSPM_Msk (0x1UL << GINTMSK_FSUSPM_Pos) // 0x00400000 */ +#define GINTMSK_FSUSPM GINTMSK_FSUSPM_Msk // Data fetch suspended mask */ +#define GINTMSK_RSTDEM_Pos (23U) +#define GINTMSK_RSTDEM_Msk (0x1UL << GINTMSK_RSTDEM_Pos) // 0x00800000 */ +#define GINTMSK_RSTDEM GINTMSK_RSTDEM_Msk // Reset detected interrupt mask */ +#define GINTMSK_PRTIM_Pos (24U) +#define GINTMSK_PRTIM_Msk (0x1UL << GINTMSK_PRTIM_Pos) // 0x01000000 */ +#define GINTMSK_PRTIM GINTMSK_PRTIM_Msk // Host port interrupt mask */ +#define GINTMSK_HCIM_Pos (25U) +#define GINTMSK_HCIM_Msk (0x1UL << GINTMSK_HCIM_Pos) // 0x02000000 */ +#define GINTMSK_HCIM GINTMSK_HCIM_Msk // Host channels interrupt mask */ +#define GINTMSK_PTXFEM_Pos (26U) +#define GINTMSK_PTXFEM_Msk (0x1UL << GINTMSK_PTXFEM_Pos) // 0x04000000 */ +#define GINTMSK_PTXFEM GINTMSK_PTXFEM_Msk // Periodic TxFIFO empty mask */ +#define GINTMSK_LPMINTM_Pos (27U) +#define GINTMSK_LPMINTM_Msk (0x1UL << GINTMSK_LPMINTM_Pos) // 0x08000000 */ +#define GINTMSK_LPMINTM GINTMSK_LPMINTM_Msk // LPM interrupt Mask */ +#define GINTMSK_CIDSCHGM_Pos (28U) +#define GINTMSK_CIDSCHGM_Msk (0x1UL << GINTMSK_CIDSCHGM_Pos) // 0x10000000 */ +#define GINTMSK_CIDSCHGM GINTMSK_CIDSCHGM_Msk // Connector ID status change mask */ +#define GINTMSK_DISCINT_Pos (29U) +#define GINTMSK_DISCINT_Msk (0x1UL << GINTMSK_DISCINT_Pos) // 0x20000000 */ +#define GINTMSK_DISCINT GINTMSK_DISCINT_Msk // Disconnect detected interrupt mask */ +#define GINTMSK_SRQIM_Pos (30U) +#define GINTMSK_SRQIM_Msk (0x1UL << GINTMSK_SRQIM_Pos) // 0x40000000 */ +#define GINTMSK_SRQIM GINTMSK_SRQIM_Msk // Session request/new session detected interrupt mask */ +#define GINTMSK_WUIM_Pos (31U) +#define GINTMSK_WUIM_Msk (0x1UL << GINTMSK_WUIM_Pos) // 0x80000000 */ +#define GINTMSK_WUIM GINTMSK_WUIM_Msk // Resume/remote wakeup detected interrupt mask */ + +/******************** Bit definition for DAINT register ********************/ +#define DAINT_IEPINT_Pos (0U) +#define DAINT_IEPINT_Msk (0xFFFFUL << DAINT_IEPINT_Pos) // 0x0000FFFF */ +#define DAINT_IEPINT DAINT_IEPINT_Msk // IN endpoint interrupt bits */ +#define DAINT_OEPINT_Pos (16U) +#define DAINT_OEPINT_Msk (0xFFFFUL << DAINT_OEPINT_Pos) // 0xFFFF0000 */ +#define DAINT_OEPINT DAINT_OEPINT_Msk // OUT endpoint interrupt bits */ + +/******************** Bit definition for HAINTMSK register ********************/ +#define HAINTMSK_HAINTM_Pos (0U) +#define HAINTMSK_HAINTM_Msk (0xFFFFUL << HAINTMSK_HAINTM_Pos) // 0x0000FFFF */ +#define HAINTMSK_HAINTM HAINTMSK_HAINTM_Msk // Channel interrupt mask */ + +/******************** Bit definition for GRXSTSP register ********************/ +#define GRXSTSP_EPNUM_Pos (0U) +#define GRXSTSP_EPNUM_Msk (0xFUL << GRXSTSP_EPNUM_Pos) // 0x0000000F */ +#define GRXSTSP_EPNUM GRXSTSP_EPNUM_Msk // IN EP interrupt mask bits */ +#define GRXSTSP_BCNT_Pos (4U) +#define GRXSTSP_BCNT_Msk (0x7FFUL << GRXSTSP_BCNT_Pos) // 0x00007FF0 */ +#define GRXSTSP_BCNT GRXSTSP_BCNT_Msk // OUT EP interrupt mask bits */ +#define GRXSTSP_DPID_Pos (15U) +#define GRXSTSP_DPID_Msk (0x3UL << GRXSTSP_DPID_Pos) // 0x00018000 */ +#define GRXSTSP_DPID GRXSTSP_DPID_Msk // OUT EP interrupt mask bits */ +#define GRXSTSP_PKTSTS_Pos (17U) +#define GRXSTSP_PKTSTS_Msk (0xFUL << GRXSTSP_PKTSTS_Pos) // 0x001E0000 */ +#define GRXSTSP_PKTSTS GRXSTSP_PKTSTS_Msk // OUT EP interrupt mask bits */ + +#define GRXSTS_PKTSTS_GLOBALOUTNAK 1 +#define GRXSTS_PKTSTS_OUTRX 2 +#define GRXSTS_PKTSTS_HCHIN 2 +#define GRXSTS_PKTSTS_OUTDONE 3 +#define GRXSTS_PKTSTS_HCHIN_XFER_COMP 3 +#define GRXSTS_PKTSTS_SETUPDONE 4 +#define GRXSTS_PKTSTS_DATATOGGLEERR 5 +#define GRXSTS_PKTSTS_SETUPRX 6 +#define GRXSTS_PKTSTS_HCHHALTED 7 + + +/******************** Bit definition for DAINTMSK register ********************/ +#define DAINTMSK_IEPM_Pos (0U) +#define DAINTMSK_IEPM_Msk (0xFFFFUL << DAINTMSK_IEPM_Pos) // 0x0000FFFF */ +#define DAINTMSK_IEPM DAINTMSK_IEPM_Msk // IN EP interrupt mask bits */ +#define DAINTMSK_OEPM_Pos (16U) +#define DAINTMSK_OEPM_Msk (0xFFFFUL << DAINTMSK_OEPM_Pos) // 0xFFFF0000 */ +#define DAINTMSK_OEPM DAINTMSK_OEPM_Msk // OUT EP interrupt mask bits */ + +#if 0 +/******************** Bit definition for OTG register ********************/ +#define CHNUM_Pos (0U) +#define CHNUM_Msk (0xFUL << CHNUM_Pos) // 0x0000000F */ +#define CHNUM CHNUM_Msk // Channel number */ +#define CHNUM_0 (0x1UL << CHNUM_Pos) // 0x00000001 */ +#define CHNUM_1 (0x2UL << CHNUM_Pos) // 0x00000002 */ +#define CHNUM_2 (0x4UL << CHNUM_Pos) // 0x00000004 */ +#define CHNUM_3 (0x8UL << CHNUM_Pos) // 0x00000008 */ +#define BCNT_Pos (4U) +#define BCNT_Msk (0x7FFUL << BCNT_Pos) // 0x00007FF0 */ +#define BCNT BCNT_Msk // Byte count */ + +#define DPID_Pos (15U) +#define DPID_Msk (0x3UL << DPID_Pos) // 0x00018000 */ +#define DPID DPID_Msk // Data PID */ +#define DPID_0 (0x1UL << DPID_Pos) // 0x00008000 */ +#define DPID_1 (0x2UL << DPID_Pos) // 0x00010000 */ + +#define PKTSTS_Pos (17U) +#define PKTSTS_Msk (0xFUL << PKTSTS_Pos) // 0x001E0000 */ +#define PKTSTS PKTSTS_Msk // Packet status */ +#define PKTSTS_0 (0x1UL << PKTSTS_Pos) // 0x00020000 */ +#define PKTSTS_1 (0x2UL << PKTSTS_Pos) // 0x00040000 */ +#define PKTSTS_2 (0x4UL << PKTSTS_Pos) // 0x00080000 */ +#define PKTSTS_3 (0x8UL << PKTSTS_Pos) // 0x00100000 */ + +#define EPNUM_Pos (0U) +#define EPNUM_Msk (0xFUL << EPNUM_Pos) // 0x0000000F */ +#define EPNUM EPNUM_Msk // Endpoint number */ +#define EPNUM_0 (0x1UL << EPNUM_Pos) // 0x00000001 */ +#define EPNUM_1 (0x2UL << EPNUM_Pos) // 0x00000002 */ +#define EPNUM_2 (0x4UL << EPNUM_Pos) // 0x00000004 */ +#define EPNUM_3 (0x8UL << EPNUM_Pos) // 0x00000008 */ + +#define FRMNUM_Pos (21U) +#define FRMNUM_Msk (0xFUL << FRMNUM_Pos) // 0x01E00000 */ +#define FRMNUM FRMNUM_Msk // Frame number */ +#define FRMNUM_0 (0x1UL << FRMNUM_Pos) // 0x00200000 */ +#define FRMNUM_1 (0x2UL << FRMNUM_Pos) // 0x00400000 */ +#define FRMNUM_2 (0x4UL << FRMNUM_Pos) // 0x00800000 */ +#define FRMNUM_3 (0x8UL << FRMNUM_Pos) // 0x01000000 */ +#endif + +/******************** Bit definition for GRXFSIZ register ********************/ +#define GRXFSIZ_RXFD_Pos (0U) +#define GRXFSIZ_RXFD_Msk (0xFFFFUL << GRXFSIZ_RXFD_Pos) // 0x0000FFFF */ +#define GRXFSIZ_RXFD GRXFSIZ_RXFD_Msk // RxFIFO depth */ + +/******************** Bit definition for DVBUSDIS register ********************/ +#define DVBUSDIS_VBUSDT_Pos (0U) +#define DVBUSDIS_VBUSDT_Msk (0xFFFFUL << DVBUSDIS_VBUSDT_Pos) // 0x0000FFFF */ +#define DVBUSDIS_VBUSDT DVBUSDIS_VBUSDT_Msk // Device VBUS discharge time */ + +/******************** Bit definition for OTG register ********************/ +#define GNPTXFSIZ_NPTXFSA_Pos (0U) +#define GNPTXFSIZ_NPTXFSA_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFSA_Pos) // 0x0000FFFF */ +#define GNPTXFSIZ_NPTXFSA GNPTXFSIZ_NPTXFSA_Msk // Nonperiodic transmit RAM start address */ +#define GNPTXFSIZ_NPTXFD_Pos (16U) +#define GNPTXFSIZ_NPTXFD_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFD_Pos) // 0xFFFF0000 */ +#define GNPTXFSIZ_NPTXFD GNPTXFSIZ_NPTXFD_Msk // Nonperiodic TxFIFO depth */ +#define DIEPTXF0_TX0FSA_Pos (0U) +#define DIEPTXF0_TX0FSA_Msk (0xFFFFUL << DIEPTXF0_TX0FSA_Pos) // 0x0000FFFF */ +#define DIEPTXF0_TX0FSA DIEPTXF0_TX0FSA_Msk // Endpoint 0 transmit RAM start address */ +#define DIEPTXF0_TX0FD_Pos (16U) +#define DIEPTXF0_TX0FD_Msk (0xFFFFUL << DIEPTXF0_TX0FD_Pos) // 0xFFFF0000 */ +#define DIEPTXF0_TX0FD DIEPTXF0_TX0FD_Msk // Endpoint 0 TxFIFO depth */ + +/******************** Bit definition for DVBUSPULSE register ********************/ +#define DVBUSPULSE_DVBUSP_Pos (0U) +#define DVBUSPULSE_DVBUSP_Msk (0xFFFUL << DVBUSPULSE_DVBUSP_Pos) // 0x00000FFF */ +#define DVBUSPULSE_DVBUSP DVBUSPULSE_DVBUSP_Msk // Device VBUS pulsing time */ + +/******************** Bit definition for GNPTXSTS register ********************/ +#define GNPTXSTS_NPTXFSAV_Pos (0U) +#define GNPTXSTS_NPTXFSAV_Msk (0xFFFFUL << GNPTXSTS_NPTXFSAV_Pos) // 0x0000FFFF */ +#define GNPTXSTS_NPTXFSAV GNPTXSTS_NPTXFSAV_Msk // Nonperiodic TxFIFO space available */ + +#define GNPTXSTS_NPTQXSAV_Pos (16U) +#define GNPTXSTS_NPTQXSAV_Msk (0xFFUL << GNPTXSTS_NPTQXSAV_Pos) // 0x00FF0000 */ +#define GNPTXSTS_NPTQXSAV GNPTXSTS_NPTQXSAV_Msk // Nonperiodic transmit request queue space available */ +#define GNPTXSTS_NPTQXSAV_0 (0x01UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00010000 */ +#define GNPTXSTS_NPTQXSAV_1 (0x02UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00020000 */ +#define GNPTXSTS_NPTQXSAV_2 (0x04UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00040000 */ +#define GNPTXSTS_NPTQXSAV_3 (0x08UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00080000 */ +#define GNPTXSTS_NPTQXSAV_4 (0x10UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00100000 */ +#define GNPTXSTS_NPTQXSAV_5 (0x20UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00200000 */ +#define GNPTXSTS_NPTQXSAV_6 (0x40UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00400000 */ +#define GNPTXSTS_NPTQXSAV_7 (0x80UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00800000 */ + +#define GNPTXSTS_NPTXQTOP_Pos (24U) +#define GNPTXSTS_NPTXQTOP_Msk (0x7FUL << GNPTXSTS_NPTXQTOP_Pos) // 0x7F000000 */ +#define GNPTXSTS_NPTXQTOP GNPTXSTS_NPTXQTOP_Msk // Top of the nonperiodic transmit request queue */ +#define GNPTXSTS_NPTXQTOP_0 (0x01UL << GNPTXSTS_NPTXQTOP_Pos) // 0x01000000 */ +#define GNPTXSTS_NPTXQTOP_1 (0x02UL << GNPTXSTS_NPTXQTOP_Pos) // 0x02000000 */ +#define GNPTXSTS_NPTXQTOP_2 (0x04UL << GNPTXSTS_NPTXQTOP_Pos) // 0x04000000 */ +#define GNPTXSTS_NPTXQTOP_3 (0x08UL << GNPTXSTS_NPTXQTOP_Pos) // 0x08000000 */ +#define GNPTXSTS_NPTXQTOP_4 (0x10UL << GNPTXSTS_NPTXQTOP_Pos) // 0x10000000 */ +#define GNPTXSTS_NPTXQTOP_5 (0x20UL << GNPTXSTS_NPTXQTOP_Pos) // 0x20000000 */ +#define GNPTXSTS_NPTXQTOP_6 (0x40UL << GNPTXSTS_NPTXQTOP_Pos) // 0x40000000 */ + +/******************** Bit definition for DTHRCTL register ********************/ +#define DTHRCTL_NONISOTHREN_Pos (0U) +#define DTHRCTL_NONISOTHREN_Msk (0x1UL << DTHRCTL_NONISOTHREN_Pos) // 0x00000001 */ +#define DTHRCTL_NONISOTHREN DTHRCTL_NONISOTHREN_Msk // Nonisochronous IN endpoints threshold enable */ +#define DTHRCTL_ISOTHREN_Pos (1U) +#define DTHRCTL_ISOTHREN_Msk (0x1UL << DTHRCTL_ISOTHREN_Pos) // 0x00000002 */ +#define DTHRCTL_ISOTHREN DTHRCTL_ISOTHREN_Msk // ISO IN endpoint threshold enable */ + +#define DTHRCTL_TXTHRLEN_Pos (2U) +#define DTHRCTL_TXTHRLEN_Msk (0x1FFUL << DTHRCTL_TXTHRLEN_Pos) // 0x000007FC */ +#define DTHRCTL_TXTHRLEN DTHRCTL_TXTHRLEN_Msk // Transmit threshold length */ +#define DTHRCTL_TXTHRLEN_0 (0x001UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000004 */ +#define DTHRCTL_TXTHRLEN_1 (0x002UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000008 */ +#define DTHRCTL_TXTHRLEN_2 (0x004UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000010 */ +#define DTHRCTL_TXTHRLEN_3 (0x008UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000020 */ +#define DTHRCTL_TXTHRLEN_4 (0x010UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000040 */ +#define DTHRCTL_TXTHRLEN_5 (0x020UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000080 */ +#define DTHRCTL_TXTHRLEN_6 (0x040UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000100 */ +#define DTHRCTL_TXTHRLEN_7 (0x080UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000200 */ +#define DTHRCTL_TXTHRLEN_8 (0x100UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000400 */ +#define DTHRCTL_RXTHREN_Pos (16U) +#define DTHRCTL_RXTHREN_Msk (0x1UL << DTHRCTL_RXTHREN_Pos) // 0x00010000 */ +#define DTHRCTL_RXTHREN DTHRCTL_RXTHREN_Msk // Receive threshold enable */ + +#define DTHRCTL_RXTHRLEN_Pos (17U) +#define DTHRCTL_RXTHRLEN_Msk (0x1FFUL << DTHRCTL_RXTHRLEN_Pos) // 0x03FE0000 */ +#define DTHRCTL_RXTHRLEN DTHRCTL_RXTHRLEN_Msk // Receive threshold length */ +#define DTHRCTL_RXTHRLEN_0 (0x001UL << DTHRCTL_RXTHRLEN_Pos) // 0x00020000 */ +#define DTHRCTL_RXTHRLEN_1 (0x002UL << DTHRCTL_RXTHRLEN_Pos) // 0x00040000 */ +#define DTHRCTL_RXTHRLEN_2 (0x004UL << DTHRCTL_RXTHRLEN_Pos) // 0x00080000 */ +#define DTHRCTL_RXTHRLEN_3 (0x008UL << DTHRCTL_RXTHRLEN_Pos) // 0x00100000 */ +#define DTHRCTL_RXTHRLEN_4 (0x010UL << DTHRCTL_RXTHRLEN_Pos) // 0x00200000 */ +#define DTHRCTL_RXTHRLEN_5 (0x020UL << DTHRCTL_RXTHRLEN_Pos) // 0x00400000 */ +#define DTHRCTL_RXTHRLEN_6 (0x040UL << DTHRCTL_RXTHRLEN_Pos) // 0x00800000 */ +#define DTHRCTL_RXTHRLEN_7 (0x080UL << DTHRCTL_RXTHRLEN_Pos) // 0x01000000 */ +#define DTHRCTL_RXTHRLEN_8 (0x100UL << DTHRCTL_RXTHRLEN_Pos) // 0x02000000 */ +#define DTHRCTL_ARPEN_Pos (27U) +#define DTHRCTL_ARPEN_Msk (0x1UL << DTHRCTL_ARPEN_Pos) // 0x08000000 */ +#define DTHRCTL_ARPEN DTHRCTL_ARPEN_Msk // Arbiter parking enable */ + +/******************** Bit definition for DIEPEMPMSK register ********************/ +#define DIEPEMPMSK_INEPTXFEM_Pos (0U) +#define DIEPEMPMSK_INEPTXFEM_Msk (0xFFFFUL << DIEPEMPMSK_INEPTXFEM_Pos) // 0x0000FFFF */ +#define DIEPEMPMSK_INEPTXFEM DIEPEMPMSK_INEPTXFEM_Msk // IN EP Tx FIFO empty interrupt mask bits */ + +/******************** Bit definition for DEACHINT register ********************/ +#define DEACHINT_IEP1INT_Pos (1U) +#define DEACHINT_IEP1INT_Msk (0x1UL << DEACHINT_IEP1INT_Pos) // 0x00000002 */ +#define DEACHINT_IEP1INT DEACHINT_IEP1INT_Msk // IN endpoint 1interrupt bit */ +#define DEACHINT_OEP1INT_Pos (17U) +#define DEACHINT_OEP1INT_Msk (0x1UL << DEACHINT_OEP1INT_Pos) // 0x00020000 */ +#define DEACHINT_OEP1INT DEACHINT_OEP1INT_Msk // OUT endpoint 1 interrupt bit */ + +/******************** Bit definition for GCCFG register ********************/ +#define STM32_GCCFG_DCDET_Pos (0U) +#define STM32_GCCFG_DCDET_Msk (0x1UL << STM32_GCCFG_DCDET_Pos) // 0x00000001 */ +#define STM32_GCCFG_DCDET STM32_GCCFG_DCDET_Msk // Data contact detection (DCD) status */ +#define STM32_GCCFG_PDET_Pos (1U) +#define STM32_GCCFG_PDET_Msk (0x1UL << STM32_GCCFG_PDET_Pos) // 0x00000002 */ +#define STM32_GCCFG_PDET STM32_GCCFG_PDET_Msk // Primary detection (PD) status */ +#define STM32_GCCFG_SDET_Pos (2U) +#define STM32_GCCFG_SDET_Msk (0x1UL << STM32_GCCFG_SDET_Pos) // 0x00000004 */ +#define STM32_GCCFG_SDET STM32_GCCFG_SDET_Msk // Secondary detection (SD) status */ +#define STM32_GCCFG_PS2DET_Pos (3U) +#define STM32_GCCFG_PS2DET_Msk (0x1UL << STM32_GCCFG_PS2DET_Pos) // 0x00000008 */ +#define STM32_GCCFG_PS2DET STM32_GCCFG_PS2DET_Msk // DM pull-up detection status */ +#define STM32_GCCFG_PWRDWN_Pos (16U) +#define STM32_GCCFG_PWRDWN_Msk (0x1UL << STM32_GCCFG_PWRDWN_Pos) // 0x00010000 */ +#define STM32_GCCFG_PWRDWN STM32_GCCFG_PWRDWN_Msk // Power down */ +#define STM32_GCCFG_BCDEN_Pos (17U) +#define STM32_GCCFG_BCDEN_Msk (0x1UL << STM32_GCCFG_BCDEN_Pos) // 0x00020000 */ +#define STM32_GCCFG_BCDEN STM32_GCCFG_BCDEN_Msk // Battery charging detector (BCD) enable */ +#define STM32_GCCFG_DCDEN_Pos (18U) +#define STM32_GCCFG_DCDEN_Msk (0x1UL << STM32_GCCFG_DCDEN_Pos) // 0x00040000 */ +#define STM32_GCCFG_DCDEN STM32_GCCFG_DCDEN_Msk // Data contact detection (DCD) mode enable*/ +#define STM32_GCCFG_PDEN_Pos (19U) +#define STM32_GCCFG_PDEN_Msk (0x1UL << STM32_GCCFG_PDEN_Pos) // 0x00080000 */ +#define STM32_GCCFG_PDEN STM32_GCCFG_PDEN_Msk // Primary detection (PD) mode enable*/ +#define STM32_GCCFG_SDEN_Pos (20U) +#define STM32_GCCFG_SDEN_Msk (0x1UL << STM32_GCCFG_SDEN_Pos) // 0x00100000 */ +#define STM32_GCCFG_SDEN STM32_GCCFG_SDEN_Msk // Secondary detection (SD) mode enable */ +#define STM32_GCCFG_VBDEN_Pos (21U) +#define STM32_GCCFG_VBDEN_Msk (0x1UL << STM32_GCCFG_VBDEN_Pos) // 0x00200000 */ +#define STM32_GCCFG_VBDEN STM32_GCCFG_VBDEN_Msk // VBUS mode enable */ +#define STM32_GCCFG_OTGIDEN_Pos (22U) +#define STM32_GCCFG_OTGIDEN_Msk (0x1UL << STM32_GCCFG_OTGIDEN_Pos) // 0x00400000 */ +#define STM32_GCCFG_OTGIDEN STM32_GCCFG_OTGIDEN_Msk // OTG Id enable */ +#define STM32_GCCFG_PHYHSEN_Pos (23U) +#define STM32_GCCFG_PHYHSEN_Msk (0x1UL << STM32_GCCFG_PHYHSEN_Pos) // 0x00800000 */ +#define STM32_GCCFG_PHYHSEN STM32_GCCFG_PHYHSEN_Msk // HS PHY enable */ + +/******************** Bit definition for DEACHINTMSK register ********************/ +#define DEACHINTMSK_IEP1INTM_Pos (1U) +#define DEACHINTMSK_IEP1INTM_Msk (0x1UL << DEACHINTMSK_IEP1INTM_Pos) // 0x00000002 */ +#define DEACHINTMSK_IEP1INTM DEACHINTMSK_IEP1INTM_Msk // IN Endpoint 1 interrupt mask bit */ +#define DEACHINTMSK_OEP1INTM_Pos (17U) +#define DEACHINTMSK_OEP1INTM_Msk (0x1UL << DEACHINTMSK_OEP1INTM_Pos) // 0x00020000 */ +#define DEACHINTMSK_OEP1INTM DEACHINTMSK_OEP1INTM_Msk // OUT Endpoint 1 interrupt mask bit */ + +/******************** Bit definition for CID register ********************/ +#define CID_PRODUCT_ID_Pos (0U) +#define CID_PRODUCT_ID_Msk (0xFFFFFFFFUL << CID_PRODUCT_ID_Pos) // 0xFFFFFFFF */ +#define CID_PRODUCT_ID CID_PRODUCT_ID_Msk // Product ID field */ + +/******************** Bit definition for GLPMCFG register ********************/ +#define GLPMCFG_LPMEN_Pos (0U) +#define GLPMCFG_LPMEN_Msk (0x1UL << GLPMCFG_LPMEN_Pos) // 0x00000001 */ +#define GLPMCFG_LPMEN GLPMCFG_LPMEN_Msk // LPM support enable */ +#define GLPMCFG_LPMACK_Pos (1U) +#define GLPMCFG_LPMACK_Msk (0x1UL << GLPMCFG_LPMACK_Pos) // 0x00000002 */ +#define GLPMCFG_LPMACK GLPMCFG_LPMACK_Msk // LPM Token acknowledge enable */ +#define GLPMCFG_BESL_Pos (2U) +#define GLPMCFG_BESL_Msk (0xFUL << GLPMCFG_BESL_Pos) // 0x0000003C */ +#define GLPMCFG_BESL GLPMCFG_BESL_Msk // BESL value received with last ACKed LPM Token */ +#define GLPMCFG_REMWAKE_Pos (6U) +#define GLPMCFG_REMWAKE_Msk (0x1UL << GLPMCFG_REMWAKE_Pos) // 0x00000040 */ +#define GLPMCFG_REMWAKE GLPMCFG_REMWAKE_Msk // bRemoteWake value received with last ACKed LPM Token */ +#define GLPMCFG_L1SSEN_Pos (7U) +#define GLPMCFG_L1SSEN_Msk (0x1UL << GLPMCFG_L1SSEN_Pos) // 0x00000080 */ +#define GLPMCFG_L1SSEN GLPMCFG_L1SSEN_Msk // L1 shallow sleep enable */ +#define GLPMCFG_BESLTHRS_Pos (8U) +#define GLPMCFG_BESLTHRS_Msk (0xFUL << GLPMCFG_BESLTHRS_Pos) // 0x00000F00 */ +#define GLPMCFG_BESLTHRS GLPMCFG_BESLTHRS_Msk // BESL threshold */ +#define GLPMCFG_L1DSEN_Pos (12U) +#define GLPMCFG_L1DSEN_Msk (0x1UL << GLPMCFG_L1DSEN_Pos) // 0x00001000 */ +#define GLPMCFG_L1DSEN GLPMCFG_L1DSEN_Msk // L1 deep sleep enable */ +#define GLPMCFG_LPMRSP_Pos (13U) +#define GLPMCFG_LPMRSP_Msk (0x3UL << GLPMCFG_LPMRSP_Pos) // 0x00006000 */ +#define GLPMCFG_LPMRSP GLPMCFG_LPMRSP_Msk // LPM response */ +#define GLPMCFG_SLPSTS_Pos (15U) +#define GLPMCFG_SLPSTS_Msk (0x1UL << GLPMCFG_SLPSTS_Pos) // 0x00008000 */ +#define GLPMCFG_SLPSTS GLPMCFG_SLPSTS_Msk // Port sleep status */ +#define GLPMCFG_L1RSMOK_Pos (16U) +#define GLPMCFG_L1RSMOK_Msk (0x1UL << GLPMCFG_L1RSMOK_Pos) // 0x00010000 */ +#define GLPMCFG_L1RSMOK GLPMCFG_L1RSMOK_Msk // Sleep State Resume OK */ +#define GLPMCFG_LPMCHIDX_Pos (17U) +#define GLPMCFG_LPMCHIDX_Msk (0xFUL << GLPMCFG_LPMCHIDX_Pos) // 0x001E0000 */ +#define GLPMCFG_LPMCHIDX GLPMCFG_LPMCHIDX_Msk // LPM Channel Index */ +#define GLPMCFG_LPMRCNT_Pos (21U) +#define GLPMCFG_LPMRCNT_Msk (0x7UL << GLPMCFG_LPMRCNT_Pos) // 0x00E00000 */ +#define GLPMCFG_LPMRCNT GLPMCFG_LPMRCNT_Msk // LPM retry count */ +#define GLPMCFG_SNDLPM_Pos (24U) +#define GLPMCFG_SNDLPM_Msk (0x1UL << GLPMCFG_SNDLPM_Pos) // 0x01000000 */ +#define GLPMCFG_SNDLPM GLPMCFG_SNDLPM_Msk // Send LPM transaction */ +#define GLPMCFG_LPMRCNTSTS_Pos (25U) +#define GLPMCFG_LPMRCNTSTS_Msk (0x7UL << GLPMCFG_LPMRCNTSTS_Pos) // 0x0E000000 */ +#define GLPMCFG_LPMRCNTSTS GLPMCFG_LPMRCNTSTS_Msk // LPM retry count status */ +#define GLPMCFG_ENBESL_Pos (28U) +#define GLPMCFG_ENBESL_Msk (0x1UL << GLPMCFG_ENBESL_Pos) // 0x10000000 */ +#define GLPMCFG_ENBESL GLPMCFG_ENBESL_Msk // Enable best effort service latency */ + +/******************** Bit definition for DIEPEACHMSK1 register ********************/ +#define DIEPEACHMSK1_XFRCM_Pos (0U) +#define DIEPEACHMSK1_XFRCM_Msk (0x1UL << DIEPEACHMSK1_XFRCM_Pos) // 0x00000001 */ +#define DIEPEACHMSK1_XFRCM DIEPEACHMSK1_XFRCM_Msk // Transfer completed interrupt mask */ +#define DIEPEACHMSK1_EPDM_Pos (1U) +#define DIEPEACHMSK1_EPDM_Msk (0x1UL << DIEPEACHMSK1_EPDM_Pos) // 0x00000002 */ +#define DIEPEACHMSK1_EPDM DIEPEACHMSK1_EPDM_Msk // Endpoint disabled interrupt mask */ +#define DIEPEACHMSK1_TOM_Pos (3U) +#define DIEPEACHMSK1_TOM_Msk (0x1UL << DIEPEACHMSK1_TOM_Pos) // 0x00000008 */ +#define DIEPEACHMSK1_TOM DIEPEACHMSK1_TOM_Msk // Timeout condition mask (nonisochronous endpoints) */ +#define DIEPEACHMSK1_ITTXFEMSK_Pos (4U) +#define DIEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << DIEPEACHMSK1_ITTXFEMSK_Pos) // 0x00000010 */ +#define DIEPEACHMSK1_ITTXFEMSK DIEPEACHMSK1_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask */ +#define DIEPEACHMSK1_INEPNMM_Pos (5U) +#define DIEPEACHMSK1_INEPNMM_Msk (0x1UL << DIEPEACHMSK1_INEPNMM_Pos) // 0x00000020 */ +#define DIEPEACHMSK1_INEPNMM DIEPEACHMSK1_INEPNMM_Msk // IN token received with EP mismatch mask */ +#define DIEPEACHMSK1_INEPNEM_Pos (6U) +#define DIEPEACHMSK1_INEPNEM_Msk (0x1UL << DIEPEACHMSK1_INEPNEM_Pos) // 0x00000040 */ +#define DIEPEACHMSK1_INEPNEM DIEPEACHMSK1_INEPNEM_Msk // IN endpoint NAK effective mask */ +#define DIEPEACHMSK1_TXFURM_Pos (8U) +#define DIEPEACHMSK1_TXFURM_Msk (0x1UL << DIEPEACHMSK1_TXFURM_Pos) // 0x00000100 */ +#define DIEPEACHMSK1_TXFURM DIEPEACHMSK1_TXFURM_Msk // FIFO underrun mask */ +#define DIEPEACHMSK1_BIM_Pos (9U) +#define DIEPEACHMSK1_BIM_Msk (0x1UL << DIEPEACHMSK1_BIM_Pos) // 0x00000200 */ +#define DIEPEACHMSK1_BIM DIEPEACHMSK1_BIM_Msk // BNA interrupt mask */ +#define DIEPEACHMSK1_NAKM_Pos (13U) +#define DIEPEACHMSK1_NAKM_Msk (0x1UL << DIEPEACHMSK1_NAKM_Pos) // 0x00002000 */ +#define DIEPEACHMSK1_NAKM DIEPEACHMSK1_NAKM_Msk // NAK interrupt mask */ + +/******************** Bit definition for HPRT register ********************/ +#define HPRT_PCSTS_Pos (0U) +#define HPRT_PCSTS_Msk (0x1UL << HPRT_PCSTS_Pos) // 0x00000001 */ +#define HPRT_PCSTS HPRT_PCSTS_Msk // Port connect status */ +#define HPRT_PCDET_Pos (1U) +#define HPRT_PCDET_Msk (0x1UL << HPRT_PCDET_Pos) // 0x00000002 */ +#define HPRT_PCDET HPRT_PCDET_Msk // Port connect detected */ +#define HPRT_PENA_Pos (2U) +#define HPRT_PENA_Msk (0x1UL << HPRT_PENA_Pos) // 0x00000004 */ +#define HPRT_PENA HPRT_PENA_Msk // Port enable */ +#define HPRT_PENCHNG_Pos (3U) +#define HPRT_PENCHNG_Msk (0x1UL << HPRT_PENCHNG_Pos) // 0x00000008 */ +#define HPRT_PENCHNG HPRT_PENCHNG_Msk // Port enable/disable change */ +#define HPRT_POCA_Pos (4U) +#define HPRT_POCA_Msk (0x1UL << HPRT_POCA_Pos) // 0x00000010 */ +#define HPRT_POCA HPRT_POCA_Msk // Port overcurrent active */ +#define HPRT_POCCHNG_Pos (5U) +#define HPRT_POCCHNG_Msk (0x1UL << HPRT_POCCHNG_Pos) // 0x00000020 */ +#define HPRT_POCCHNG HPRT_POCCHNG_Msk // Port overcurrent change */ +#define HPRT_PRES_Pos (6U) +#define HPRT_PRES_Msk (0x1UL << HPRT_PRES_Pos) // 0x00000040 */ +#define HPRT_PRES HPRT_PRES_Msk // Port resume */ +#define HPRT_PSUSP_Pos (7U) +#define HPRT_PSUSP_Msk (0x1UL << HPRT_PSUSP_Pos) // 0x00000080 */ +#define HPRT_PSUSP HPRT_PSUSP_Msk // Port suspend */ +#define HPRT_PRST_Pos (8U) +#define HPRT_PRST_Msk (0x1UL << HPRT_PRST_Pos) // 0x00000100 */ +#define HPRT_PRST HPRT_PRST_Msk // Port reset */ + +#define HPRT_PLSTS_Pos (10U) +#define HPRT_PLSTS_Msk (0x3UL << HPRT_PLSTS_Pos) // 0x00000C00 */ +#define HPRT_PLSTS HPRT_PLSTS_Msk // Port line status */ +#define HPRT_PLSTS_0 (0x1UL << HPRT_PLSTS_Pos) // 0x00000400 */ +#define HPRT_PLSTS_1 (0x2UL << HPRT_PLSTS_Pos) // 0x00000800 */ +#define HPRT_PPWR_Pos (12U) +#define HPRT_PPWR_Msk (0x1UL << HPRT_PPWR_Pos) // 0x00001000 */ +#define HPRT_PPWR HPRT_PPWR_Msk // Port power */ + +#define HPRT_PTCTL_Pos (13U) +#define HPRT_PTCTL_Msk (0xFUL << HPRT_PTCTL_Pos) // 0x0001E000 */ +#define HPRT_PTCTL HPRT_PTCTL_Msk // Port test control */ +#define HPRT_PTCTL_0 (0x1UL << HPRT_PTCTL_Pos) // 0x00002000 */ +#define HPRT_PTCTL_1 (0x2UL << HPRT_PTCTL_Pos) // 0x00004000 */ +#define HPRT_PTCTL_2 (0x4UL << HPRT_PTCTL_Pos) // 0x00008000 */ +#define HPRT_PTCTL_3 (0x8UL << HPRT_PTCTL_Pos) // 0x00010000 */ + +#define HPRT_PSPD_Pos (17U) +#define HPRT_PSPD_Msk (0x3UL << HPRT_PSPD_Pos) // 0x00060000 */ +#define HPRT_PSPD HPRT_PSPD_Msk // Port speed */ +#define HPRT_PSPD_0 (0x1UL << HPRT_PSPD_Pos) // 0x00020000 */ +#define HPRT_PSPD_1 (0x2UL << HPRT_PSPD_Pos) // 0x00040000 */ + +/******************** Bit definition for DOEPEACHMSK1 register ********************/ +#define DOEPEACHMSK1_XFRCM_Pos (0U) +#define DOEPEACHMSK1_XFRCM_Msk (0x1UL << DOEPEACHMSK1_XFRCM_Pos) // 0x00000001 */ +#define DOEPEACHMSK1_XFRCM DOEPEACHMSK1_XFRCM_Msk // Transfer completed interrupt mask */ +#define DOEPEACHMSK1_EPDM_Pos (1U) +#define DOEPEACHMSK1_EPDM_Msk (0x1UL << DOEPEACHMSK1_EPDM_Pos) // 0x00000002 */ +#define DOEPEACHMSK1_EPDM DOEPEACHMSK1_EPDM_Msk // Endpoint disabled interrupt mask */ +#define DOEPEACHMSK1_TOM_Pos (3U) +#define DOEPEACHMSK1_TOM_Msk (0x1UL << DOEPEACHMSK1_TOM_Pos) // 0x00000008 */ +#define DOEPEACHMSK1_TOM DOEPEACHMSK1_TOM_Msk // Timeout condition mask */ +#define DOEPEACHMSK1_ITTXFEMSK_Pos (4U) +#define DOEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << DOEPEACHMSK1_ITTXFEMSK_Pos) // 0x00000010 */ +#define DOEPEACHMSK1_ITTXFEMSK DOEPEACHMSK1_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask */ +#define DOEPEACHMSK1_INEPNMM_Pos (5U) +#define DOEPEACHMSK1_INEPNMM_Msk (0x1UL << DOEPEACHMSK1_INEPNMM_Pos) // 0x00000020 */ +#define DOEPEACHMSK1_INEPNMM DOEPEACHMSK1_INEPNMM_Msk // IN token received with EP mismatch mask */ +#define DOEPEACHMSK1_INEPNEM_Pos (6U) +#define DOEPEACHMSK1_INEPNEM_Msk (0x1UL << DOEPEACHMSK1_INEPNEM_Pos) // 0x00000040 */ +#define DOEPEACHMSK1_INEPNEM DOEPEACHMSK1_INEPNEM_Msk // IN endpoint NAK effective mask */ +#define DOEPEACHMSK1_TXFURM_Pos (8U) +#define DOEPEACHMSK1_TXFURM_Msk (0x1UL << DOEPEACHMSK1_TXFURM_Pos) // 0x00000100 */ +#define DOEPEACHMSK1_TXFURM DOEPEACHMSK1_TXFURM_Msk // OUT packet error mask */ +#define DOEPEACHMSK1_BIM_Pos (9U) +#define DOEPEACHMSK1_BIM_Msk (0x1UL << DOEPEACHMSK1_BIM_Pos) // 0x00000200 */ +#define DOEPEACHMSK1_BIM DOEPEACHMSK1_BIM_Msk // BNA interrupt mask */ +#define DOEPEACHMSK1_BERRM_Pos (12U) +#define DOEPEACHMSK1_BERRM_Msk (0x1UL << DOEPEACHMSK1_BERRM_Pos) // 0x00001000 */ +#define DOEPEACHMSK1_BERRM DOEPEACHMSK1_BERRM_Msk // Bubble error interrupt mask */ +#define DOEPEACHMSK1_NAKM_Pos (13U) +#define DOEPEACHMSK1_NAKM_Msk (0x1UL << DOEPEACHMSK1_NAKM_Pos) // 0x00002000 */ +#define DOEPEACHMSK1_NAKM DOEPEACHMSK1_NAKM_Msk // NAK interrupt mask */ +#define DOEPEACHMSK1_NYETM_Pos (14U) +#define DOEPEACHMSK1_NYETM_Msk (0x1UL << DOEPEACHMSK1_NYETM_Pos) // 0x00004000 */ +#define DOEPEACHMSK1_NYETM DOEPEACHMSK1_NYETM_Msk // NYET interrupt mask */ + +/******************** Bit definition for HPTXFSIZ register ********************/ +#define HPTXFSIZ_PTXSA_Pos (0U) +#define HPTXFSIZ_PTXSA_Msk (0xFFFFUL << HPTXFSIZ_PTXSA_Pos) // 0x0000FFFF */ +#define HPTXFSIZ_PTXSA HPTXFSIZ_PTXSA_Msk // Host periodic TxFIFO start address */ +#define HPTXFSIZ_PTXFD_Pos (16U) +#define HPTXFSIZ_PTXFD_Msk (0xFFFFUL << HPTXFSIZ_PTXFD_Pos) // 0xFFFF0000 */ +#define HPTXFSIZ_PTXFD HPTXFSIZ_PTXFD_Msk // Host periodic TxFIFO depth */ + +/******************** Bit definition for DIEPCTL register ********************/ +#define DIEPCTL_MPSIZ_Pos (0U) +#define DIEPCTL_MPSIZ_Msk (0x7FFUL << DIEPCTL_MPSIZ_Pos) // 0x000007FF */ +#define DIEPCTL_MPSIZ DIEPCTL_MPSIZ_Msk // Maximum packet size */ +#define DIEPCTL_USBAEP_Pos (15U) +#define DIEPCTL_USBAEP_Msk (0x1UL << DIEPCTL_USBAEP_Pos) // 0x00008000 */ +#define DIEPCTL_USBAEP DIEPCTL_USBAEP_Msk // USB active endpoint */ +#define DIEPCTL_EONUM_DPID_Pos (16U) +#define DIEPCTL_EONUM_DPID_Msk (0x1UL << DIEPCTL_EONUM_DPID_Pos) // 0x00010000 */ +#define DIEPCTL_EONUM_DPID DIEPCTL_EONUM_DPID_Msk // Even/odd frame */ +#define DIEPCTL_NAKSTS_Pos (17U) +#define DIEPCTL_NAKSTS_Msk (0x1UL << DIEPCTL_NAKSTS_Pos) // 0x00020000 */ +#define DIEPCTL_NAKSTS DIEPCTL_NAKSTS_Msk // NAK status */ + +#define DIEPCTL_EPTYP_Pos (18U) +#define DIEPCTL_EPTYP_Msk (0x3UL << DIEPCTL_EPTYP_Pos) // 0x000C0000 */ +#define DIEPCTL_EPTYP DIEPCTL_EPTYP_Msk // Endpoint type */ +#define DIEPCTL_EPTYP_0 (0x1UL << DIEPCTL_EPTYP_Pos) // 0x00040000 */ +#define DIEPCTL_EPTYP_1 (0x2UL << DIEPCTL_EPTYP_Pos) // 0x00080000 */ +#define DIEPCTL_STALL_Pos (21U) +#define DIEPCTL_STALL_Msk (0x1UL << DIEPCTL_STALL_Pos) // 0x00200000 */ +#define DIEPCTL_STALL DIEPCTL_STALL_Msk // STALL handshake */ + +#define DIEPCTL_TXFNUM_Pos (22U) +#define DIEPCTL_TXFNUM_Msk (0xFUL << DIEPCTL_TXFNUM_Pos) // 0x03C00000 */ +#define DIEPCTL_TXFNUM DIEPCTL_TXFNUM_Msk // TxFIFO number */ +#define DIEPCTL_TXFNUM_0 (0x1UL << DIEPCTL_TXFNUM_Pos) // 0x00400000 */ +#define DIEPCTL_TXFNUM_1 (0x2UL << DIEPCTL_TXFNUM_Pos) // 0x00800000 */ +#define DIEPCTL_TXFNUM_2 (0x4UL << DIEPCTL_TXFNUM_Pos) // 0x01000000 */ +#define DIEPCTL_TXFNUM_3 (0x8UL << DIEPCTL_TXFNUM_Pos) // 0x02000000 */ +#define DIEPCTL_CNAK_Pos (26U) +#define DIEPCTL_CNAK_Msk (0x1UL << DIEPCTL_CNAK_Pos) // 0x04000000 */ +#define DIEPCTL_CNAK DIEPCTL_CNAK_Msk // Clear NAK */ +#define DIEPCTL_SNAK_Pos (27U) +#define DIEPCTL_SNAK_Msk (0x1UL << DIEPCTL_SNAK_Pos) // 0x08000000 */ +#define DIEPCTL_SNAK DIEPCTL_SNAK_Msk // Set NAK */ +#define DIEPCTL_SD0PID_SEVNFRM_Pos (28U) +#define DIEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << DIEPCTL_SD0PID_SEVNFRM_Pos) // 0x10000000 */ +#define DIEPCTL_SD0PID_SEVNFRM DIEPCTL_SD0PID_SEVNFRM_Msk // Set DATA0 PID */ +#define DIEPCTL_SODDFRM_Pos (29U) +#define DIEPCTL_SODDFRM_Msk (0x1UL << DIEPCTL_SODDFRM_Pos) // 0x20000000 */ +#define DIEPCTL_SODDFRM DIEPCTL_SODDFRM_Msk // Set odd frame */ +#define DIEPCTL_EPDIS_Pos (30U) +#define DIEPCTL_EPDIS_Msk (0x1UL << DIEPCTL_EPDIS_Pos) // 0x40000000 */ +#define DIEPCTL_EPDIS DIEPCTL_EPDIS_Msk // Endpoint disable */ +#define DIEPCTL_EPENA_Pos (31U) +#define DIEPCTL_EPENA_Msk (0x1UL << DIEPCTL_EPENA_Pos) // 0x80000000 */ +#define DIEPCTL_EPENA DIEPCTL_EPENA_Msk // Endpoint enable */ + +/******************** Bit definition for HCCHAR register ********************/ +#define HCCHAR_MPSIZ_Pos (0U) +#define HCCHAR_MPSIZ_Msk (0x7FFUL << HCCHAR_MPSIZ_Pos) // 0x000007FF */ +#define HCCHAR_MPSIZ HCCHAR_MPSIZ_Msk // Maximum packet size */ + +#define HCCHAR_EPNUM_Pos (11U) +#define HCCHAR_EPNUM_Msk (0xFUL << HCCHAR_EPNUM_Pos) // 0x00007800 */ +#define HCCHAR_EPNUM HCCHAR_EPNUM_Msk // Endpoint number */ +#define HCCHAR_EPNUM_0 (0x1UL << HCCHAR_EPNUM_Pos) // 0x00000800 */ +#define HCCHAR_EPNUM_1 (0x2UL << HCCHAR_EPNUM_Pos) // 0x00001000 */ +#define HCCHAR_EPNUM_2 (0x4UL << HCCHAR_EPNUM_Pos) // 0x00002000 */ +#define HCCHAR_EPNUM_3 (0x8UL << HCCHAR_EPNUM_Pos) // 0x00004000 */ +#define HCCHAR_EPDIR_Pos (15U) +#define HCCHAR_EPDIR_Msk (0x1UL << HCCHAR_EPDIR_Pos) // 0x00008000 */ +#define HCCHAR_EPDIR HCCHAR_EPDIR_Msk // Endpoint direction */ +#define HCCHAR_LSDEV_Pos (17U) +#define HCCHAR_LSDEV_Msk (0x1UL << HCCHAR_LSDEV_Pos) // 0x00020000 */ +#define HCCHAR_LSDEV HCCHAR_LSDEV_Msk // Low-speed device */ + +#define HCCHAR_EPTYP_Pos (18U) +#define HCCHAR_EPTYP_Msk (0x3UL << HCCHAR_EPTYP_Pos) // 0x000C0000 */ +#define HCCHAR_EPTYP HCCHAR_EPTYP_Msk // Endpoint type */ +#define HCCHAR_EPTYP_0 (0x1UL << HCCHAR_EPTYP_Pos) // 0x00040000 */ +#define HCCHAR_EPTYP_1 (0x2UL << HCCHAR_EPTYP_Pos) // 0x00080000 */ + +#define HCCHAR_MC_Pos (20U) +#define HCCHAR_MC_Msk (0x3UL << HCCHAR_MC_Pos) // 0x00300000 */ +#define HCCHAR_MC HCCHAR_MC_Msk // Multi Count (MC) / Error Count (EC) */ +#define HCCHAR_MC_0 (0x1UL << HCCHAR_MC_Pos) // 0x00100000 */ +#define HCCHAR_MC_1 (0x2UL << HCCHAR_MC_Pos) // 0x00200000 */ + +#define HCCHAR_DAD_Pos (22U) +#define HCCHAR_DAD_Msk (0x7FUL << HCCHAR_DAD_Pos) // 0x1FC00000 */ +#define HCCHAR_DAD HCCHAR_DAD_Msk // Device address */ +#define HCCHAR_DAD_0 (0x01UL << HCCHAR_DAD_Pos) // 0x00400000 */ +#define HCCHAR_DAD_1 (0x02UL << HCCHAR_DAD_Pos) // 0x00800000 */ +#define HCCHAR_DAD_2 (0x04UL << HCCHAR_DAD_Pos) // 0x01000000 */ +#define HCCHAR_DAD_3 (0x08UL << HCCHAR_DAD_Pos) // 0x02000000 */ +#define HCCHAR_DAD_4 (0x10UL << HCCHAR_DAD_Pos) // 0x04000000 */ +#define HCCHAR_DAD_5 (0x20UL << HCCHAR_DAD_Pos) // 0x08000000 */ +#define HCCHAR_DAD_6 (0x40UL << HCCHAR_DAD_Pos) // 0x10000000 */ +#define HCCHAR_ODDFRM_Pos (29U) +#define HCCHAR_ODDFRM_Msk (0x1UL << HCCHAR_ODDFRM_Pos) // 0x20000000 */ +#define HCCHAR_ODDFRM HCCHAR_ODDFRM_Msk // Odd frame */ +#define HCCHAR_CHDIS_Pos (30U) +#define HCCHAR_CHDIS_Msk (0x1UL << HCCHAR_CHDIS_Pos) // 0x40000000 */ +#define HCCHAR_CHDIS HCCHAR_CHDIS_Msk // Channel disable */ +#define HCCHAR_CHENA_Pos (31U) +#define HCCHAR_CHENA_Msk (0x1UL << HCCHAR_CHENA_Pos) // 0x80000000 */ +#define HCCHAR_CHENA HCCHAR_CHENA_Msk // Channel enable */ + +/******************** Bit definition for HCSPLT register ********************/ + +#define HCSPLT_PRTADDR_Pos (0U) +#define HCSPLT_PRTADDR_Msk (0x7FUL << HCSPLT_PRTADDR_Pos) // 0x0000007F */ +#define HCSPLT_PRTADDR HCSPLT_PRTADDR_Msk // Port address */ +#define HCSPLT_PRTADDR_0 (0x01UL << HCSPLT_PRTADDR_Pos) // 0x00000001 */ +#define HCSPLT_PRTADDR_1 (0x02UL << HCSPLT_PRTADDR_Pos) // 0x00000002 */ +#define HCSPLT_PRTADDR_2 (0x04UL << HCSPLT_PRTADDR_Pos) // 0x00000004 */ +#define HCSPLT_PRTADDR_3 (0x08UL << HCSPLT_PRTADDR_Pos) // 0x00000008 */ +#define HCSPLT_PRTADDR_4 (0x10UL << HCSPLT_PRTADDR_Pos) // 0x00000010 */ +#define HCSPLT_PRTADDR_5 (0x20UL << HCSPLT_PRTADDR_Pos) // 0x00000020 */ +#define HCSPLT_PRTADDR_6 (0x40UL << HCSPLT_PRTADDR_Pos) // 0x00000040 */ + +#define HCSPLT_HUBADDR_Pos (7U) +#define HCSPLT_HUBADDR_Msk (0x7FUL << HCSPLT_HUBADDR_Pos) // 0x00003F80 */ +#define HCSPLT_HUBADDR HCSPLT_HUBADDR_Msk // Hub address */ +#define HCSPLT_HUBADDR_0 (0x01UL << HCSPLT_HUBADDR_Pos) // 0x00000080 */ +#define HCSPLT_HUBADDR_1 (0x02UL << HCSPLT_HUBADDR_Pos) // 0x00000100 */ +#define HCSPLT_HUBADDR_2 (0x04UL << HCSPLT_HUBADDR_Pos) // 0x00000200 */ +#define HCSPLT_HUBADDR_3 (0x08UL << HCSPLT_HUBADDR_Pos) // 0x00000400 */ +#define HCSPLT_HUBADDR_4 (0x10UL << HCSPLT_HUBADDR_Pos) // 0x00000800 */ +#define HCSPLT_HUBADDR_5 (0x20UL << HCSPLT_HUBADDR_Pos) // 0x00001000 */ +#define HCSPLT_HUBADDR_6 (0x40UL << HCSPLT_HUBADDR_Pos) // 0x00002000 */ + +#define HCSPLT_XACTPOS_Pos (14U) +#define HCSPLT_XACTPOS_Msk (0x3UL << HCSPLT_XACTPOS_Pos) // 0x0000C000 */ +#define HCSPLT_XACTPOS HCSPLT_XACTPOS_Msk // XACTPOS */ +#define HCSPLT_XACTPOS_0 (0x1UL << HCSPLT_XACTPOS_Pos) // 0x00004000 */ +#define HCSPLT_XACTPOS_1 (0x2UL << HCSPLT_XACTPOS_Pos) // 0x00008000 */ +#define HCSPLT_COMPLSPLT_Pos (16U) +#define HCSPLT_COMPLSPLT_Msk (0x1UL << HCSPLT_COMPLSPLT_Pos) // 0x00010000 */ +#define HCSPLT_COMPLSPLT HCSPLT_COMPLSPLT_Msk // Do complete split */ +#define HCSPLT_SPLITEN_Pos (31U) +#define HCSPLT_SPLITEN_Msk (0x1UL << HCSPLT_SPLITEN_Pos) // 0x80000000 */ +#define HCSPLT_SPLITEN HCSPLT_SPLITEN_Msk // Split enable */ + +/******************** Bit definition for HCINT register ********************/ +#define HCINT_XFRC_Pos (0U) +#define HCINT_XFRC_Msk (0x1UL << HCINT_XFRC_Pos) // 0x00000001 */ +#define HCINT_XFRC HCINT_XFRC_Msk // Transfer completed */ +#define HCINT_CHH_Pos (1U) +#define HCINT_CHH_Msk (0x1UL << HCINT_CHH_Pos) // 0x00000002 */ +#define HCINT_CHH HCINT_CHH_Msk // Channel halted */ +#define HCINT_AHBERR_Pos (2U) +#define HCINT_AHBERR_Msk (0x1UL << HCINT_AHBERR_Pos) // 0x00000004 */ +#define HCINT_AHBERR HCINT_AHBERR_Msk // AHB error */ +#define HCINT_STALL_Pos (3U) +#define HCINT_STALL_Msk (0x1UL << HCINT_STALL_Pos) // 0x00000008 */ +#define HCINT_STALL HCINT_STALL_Msk // STALL response received interrupt */ +#define HCINT_NAK_Pos (4U) +#define HCINT_NAK_Msk (0x1UL << HCINT_NAK_Pos) // 0x00000010 */ +#define HCINT_NAK HCINT_NAK_Msk // NAK response received interrupt */ +#define HCINT_ACK_Pos (5U) +#define HCINT_ACK_Msk (0x1UL << HCINT_ACK_Pos) // 0x00000020 */ +#define HCINT_ACK HCINT_ACK_Msk // ACK response received/transmitted interrupt */ +#define HCINT_NYET_Pos (6U) +#define HCINT_NYET_Msk (0x1UL << HCINT_NYET_Pos) // 0x00000040 */ +#define HCINT_NYET HCINT_NYET_Msk // Response received interrupt */ +#define HCINT_TXERR_Pos (7U) +#define HCINT_TXERR_Msk (0x1UL << HCINT_TXERR_Pos) // 0x00000080 */ +#define HCINT_TXERR HCINT_TXERR_Msk // Transaction error */ +#define HCINT_BBERR_Pos (8U) +#define HCINT_BBERR_Msk (0x1UL << HCINT_BBERR_Pos) // 0x00000100 */ +#define HCINT_BBERR HCINT_BBERR_Msk // Babble error */ +#define HCINT_FRMOR_Pos (9U) +#define HCINT_FRMOR_Msk (0x1UL << HCINT_FRMOR_Pos) // 0x00000200 */ +#define HCINT_FRMOR HCINT_FRMOR_Msk // Frame overrun */ +#define HCINT_DTERR_Pos (10U) +#define HCINT_DTERR_Msk (0x1UL << HCINT_DTERR_Pos) // 0x00000400 */ +#define HCINT_DTERR HCINT_DTERR_Msk // Data toggle error */ + +/******************** Bit definition for DIEPINT register ********************/ +#define DIEPINT_XFRC_Pos (0U) +#define DIEPINT_XFRC_Msk (0x1UL << DIEPINT_XFRC_Pos) // 0x00000001 */ +#define DIEPINT_XFRC DIEPINT_XFRC_Msk // Transfer completed interrupt */ +#define DIEPINT_EPDISD_Pos (1U) +#define DIEPINT_EPDISD_Msk (0x1UL << DIEPINT_EPDISD_Pos) // 0x00000002 */ +#define DIEPINT_EPDISD DIEPINT_EPDISD_Msk // Endpoint disabled interrupt */ +#define DIEPINT_AHBERR_Pos (2U) +#define DIEPINT_AHBERR_Msk (0x1UL << DIEPINT_AHBERR_Pos) // 0x00000004 */ +#define DIEPINT_AHBERR DIEPINT_AHBERR_Msk // AHB Error (AHBErr) during an IN transaction */ +#define DIEPINT_TOC_Pos (3U) +#define DIEPINT_TOC_Msk (0x1UL << DIEPINT_TOC_Pos) // 0x00000008 */ +#define DIEPINT_TOC DIEPINT_TOC_Msk // Timeout condition */ +#define DIEPINT_ITTXFE_Pos (4U) +#define DIEPINT_ITTXFE_Msk (0x1UL << DIEPINT_ITTXFE_Pos) // 0x00000010 */ +#define DIEPINT_ITTXFE DIEPINT_ITTXFE_Msk // IN token received when TxFIFO is empty */ +#define DIEPINT_INEPNM_Pos (5U) +#define DIEPINT_INEPNM_Msk (0x1UL << DIEPINT_INEPNM_Pos) // 0x00000020 */ +#define DIEPINT_INEPNM DIEPINT_INEPNM_Msk // IN token received with EP mismatch */ +#define DIEPINT_INEPNE_Pos (6U) +#define DIEPINT_INEPNE_Msk (0x1UL << DIEPINT_INEPNE_Pos) // 0x00000040 */ +#define DIEPINT_INEPNE DIEPINT_INEPNE_Msk // IN endpoint NAK effective */ +#define DIEPINT_TXFE_Pos (7U) +#define DIEPINT_TXFE_Msk (0x1UL << DIEPINT_TXFE_Pos) // 0x00000080 */ +#define DIEPINT_TXFE DIEPINT_TXFE_Msk // Transmit FIFO empty */ +#define DIEPINT_TXFIFOUDRN_Pos (8U) +#define DIEPINT_TXFIFOUDRN_Msk (0x1UL << DIEPINT_TXFIFOUDRN_Pos) // 0x00000100 */ +#define DIEPINT_TXFIFOUDRN DIEPINT_TXFIFOUDRN_Msk // Transmit Fifo Underrun */ +#define DIEPINT_BNA_Pos (9U) +#define DIEPINT_BNA_Msk (0x1UL << DIEPINT_BNA_Pos) // 0x00000200 */ +#define DIEPINT_BNA DIEPINT_BNA_Msk // Buffer not available interrupt */ +#define DIEPINT_PKTDRPSTS_Pos (11U) +#define DIEPINT_PKTDRPSTS_Msk (0x1UL << DIEPINT_PKTDRPSTS_Pos) // 0x00000800 */ +#define DIEPINT_PKTDRPSTS DIEPINT_PKTDRPSTS_Msk // Packet dropped status */ +#define DIEPINT_BERR_Pos (12U) +#define DIEPINT_BERR_Msk (0x1UL << DIEPINT_BERR_Pos) // 0x00001000 */ +#define DIEPINT_BERR DIEPINT_BERR_Msk // Babble error interrupt */ +#define DIEPINT_NAK_Pos (13U) +#define DIEPINT_NAK_Msk (0x1UL << DIEPINT_NAK_Pos) // 0x00002000 */ +#define DIEPINT_NAK DIEPINT_NAK_Msk // NAK interrupt */ + +/******************** Bit definition for HCINTMSK register ********************/ +#define HCINTMSK_XFRCM_Pos (0U) +#define HCINTMSK_XFRCM_Msk (0x1UL << HCINTMSK_XFRCM_Pos) // 0x00000001 */ +#define HCINTMSK_XFRCM HCINTMSK_XFRCM_Msk // Transfer completed mask */ +#define HCINTMSK_CHHM_Pos (1U) +#define HCINTMSK_CHHM_Msk (0x1UL << HCINTMSK_CHHM_Pos) // 0x00000002 */ +#define HCINTMSK_CHHM HCINTMSK_CHHM_Msk // Channel halted mask */ +#define HCINTMSK_AHBERR_Pos (2U) +#define HCINTMSK_AHBERR_Msk (0x1UL << HCINTMSK_AHBERR_Pos) // 0x00000004 */ +#define HCINTMSK_AHBERR HCINTMSK_AHBERR_Msk // AHB error */ +#define HCINTMSK_STALLM_Pos (3U) +#define HCINTMSK_STALLM_Msk (0x1UL << HCINTMSK_STALLM_Pos) // 0x00000008 */ +#define HCINTMSK_STALLM HCINTMSK_STALLM_Msk // STALL response received interrupt mask */ +#define HCINTMSK_NAKM_Pos (4U) +#define HCINTMSK_NAKM_Msk (0x1UL << HCINTMSK_NAKM_Pos) // 0x00000010 */ +#define HCINTMSK_NAKM HCINTMSK_NAKM_Msk // NAK response received interrupt mask */ +#define HCINTMSK_ACKM_Pos (5U) +#define HCINTMSK_ACKM_Msk (0x1UL << HCINTMSK_ACKM_Pos) // 0x00000020 */ +#define HCINTMSK_ACKM HCINTMSK_ACKM_Msk // ACK response received/transmitted interrupt mask */ +#define HCINTMSK_NYET_Pos (6U) +#define HCINTMSK_NYET_Msk (0x1UL << HCINTMSK_NYET_Pos) // 0x00000040 */ +#define HCINTMSK_NYET HCINTMSK_NYET_Msk // response received interrupt mask */ +#define HCINTMSK_TXERRM_Pos (7U) +#define HCINTMSK_TXERRM_Msk (0x1UL << HCINTMSK_TXERRM_Pos) // 0x00000080 */ +#define HCINTMSK_TXERRM HCINTMSK_TXERRM_Msk // Transaction error mask */ +#define HCINTMSK_BBERRM_Pos (8U) +#define HCINTMSK_BBERRM_Msk (0x1UL << HCINTMSK_BBERRM_Pos) // 0x00000100 */ +#define HCINTMSK_BBERRM HCINTMSK_BBERRM_Msk // Babble error mask */ +#define HCINTMSK_FRMORM_Pos (9U) +#define HCINTMSK_FRMORM_Msk (0x1UL << HCINTMSK_FRMORM_Pos) // 0x00000200 */ +#define HCINTMSK_FRMORM HCINTMSK_FRMORM_Msk // Frame overrun mask */ +#define HCINTMSK_DTERRM_Pos (10U) +#define HCINTMSK_DTERRM_Msk (0x1UL << HCINTMSK_DTERRM_Pos) // 0x00000400 */ +#define HCINTMSK_DTERRM HCINTMSK_DTERRM_Msk // Data toggle error mask */ + +/******************** Bit definition for DIEPTSIZ register ********************/ + +#define DIEPTSIZ_XFRSIZ_Pos (0U) +#define DIEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << DIEPTSIZ_XFRSIZ_Pos) // 0x0007FFFF */ +#define DIEPTSIZ_XFRSIZ DIEPTSIZ_XFRSIZ_Msk // Transfer size */ +#define DIEPTSIZ_PKTCNT_Pos (19U) +#define DIEPTSIZ_PKTCNT_Msk (0x3FFUL << DIEPTSIZ_PKTCNT_Pos) // 0x1FF80000 */ +#define DIEPTSIZ_PKTCNT DIEPTSIZ_PKTCNT_Msk // Packet count */ +#define DIEPTSIZ_MULCNT_Pos (29U) +#define DIEPTSIZ_MULCNT_Msk (0x3UL << DIEPTSIZ_MULCNT_Pos) // 0x60000000 */ +#define DIEPTSIZ_MULCNT DIEPTSIZ_MULCNT_Msk // Packet count */ + /******************** Bit definition for HCTSIZ register ********************/ +#define HCTSIZ_XFRSIZ_Pos (0U) +#define HCTSIZ_XFRSIZ_Msk (0x7FFFFUL << HCTSIZ_XFRSIZ_Pos) // 0x0007FFFF */ +#define HCTSIZ_XFRSIZ HCTSIZ_XFRSIZ_Msk // Transfer size */ +#define HCTSIZ_PKTCNT_Pos (19U) +#define HCTSIZ_PKTCNT_Msk (0x3FFUL << HCTSIZ_PKTCNT_Pos) // 0x1FF80000 */ +#define HCTSIZ_PKTCNT HCTSIZ_PKTCNT_Msk // Packet count */ +#define HCTSIZ_DOPING_Pos (31U) +#define HCTSIZ_DOPING_Msk (0x1UL << HCTSIZ_DOPING_Pos) // 0x80000000 */ +#define HCTSIZ_DOPING HCTSIZ_DOPING_Msk // Do PING */ +#define HCTSIZ_DPID_Pos (29U) +#define HCTSIZ_DPID_Msk (0x3UL << HCTSIZ_DPID_Pos) // 0x60000000 */ +#define HCTSIZ_DPID HCTSIZ_DPID_Msk // Data PID */ +#define HCTSIZ_DPID_0 (0x1UL << HCTSIZ_DPID_Pos) // 0x20000000 */ +#define HCTSIZ_DPID_1 (0x2UL << HCTSIZ_DPID_Pos) // 0x40000000 */ + +/******************** Bit definition for DIEPDMA register ********************/ +#define DIEPDMA_DMAADDR_Pos (0U) +#define DIEPDMA_DMAADDR_Msk (0xFFFFFFFFUL << DIEPDMA_DMAADDR_Pos) // 0xFFFFFFFF */ +#define DIEPDMA_DMAADDR DIEPDMA_DMAADDR_Msk // DMA address */ + +/******************** Bit definition for HCDMA register ********************/ +#define HCDMA_DMAADDR_Pos (0U) +#define HCDMA_DMAADDR_Msk (0xFFFFFFFFUL << HCDMA_DMAADDR_Pos) // 0xFFFFFFFF */ +#define HCDMA_DMAADDR HCDMA_DMAADDR_Msk // DMA address */ + + /******************** Bit definition for DTXFSTS register ********************/ +#define DTXFSTS_INEPTFSAV_Pos (0U) +#define DTXFSTS_INEPTFSAV_Msk (0xFFFFUL << DTXFSTS_INEPTFSAV_Pos) // 0x0000FFFF */ +#define DTXFSTS_INEPTFSAV DTXFSTS_INEPTFSAV_Msk // IN endpoint TxFIFO space available */ + + /******************** Bit definition for DIEPTXF register ********************/ +#define DIEPTXF_INEPTXSA_Pos (0U) +#define DIEPTXF_INEPTXSA_Msk (0xFFFFUL << DIEPTXF_INEPTXSA_Pos) // 0x0000FFFF */ +#define DIEPTXF_INEPTXSA DIEPTXF_INEPTXSA_Msk // IN endpoint FIFOx transmit RAM start address */ +#define DIEPTXF_INEPTXFD_Pos (16U) +#define DIEPTXF_INEPTXFD_Msk (0xFFFFUL << DIEPTXF_INEPTXFD_Pos) // 0xFFFF0000 */ +#define DIEPTXF_INEPTXFD DIEPTXF_INEPTXFD_Msk // IN endpoint TxFIFO depth */ + +/******************** Bit definition for DOEPCTL register ********************/ +#define DOEPCTL_MPSIZ_Pos (0U) +#define DOEPCTL_MPSIZ_Msk (0x7FFUL << DOEPCTL_MPSIZ_Pos) // 0x000007FF */ +#define DOEPCTL_MPSIZ DOEPCTL_MPSIZ_Msk // Maximum packet size */ //Bit 1 */ +#define DOEPCTL_USBAEP_Pos (15U) +#define DOEPCTL_USBAEP_Msk (0x1UL << DOEPCTL_USBAEP_Pos) // 0x00008000 */ +#define DOEPCTL_USBAEP DOEPCTL_USBAEP_Msk // USB active endpoint */ +#define DOEPCTL_NAKSTS_Pos (17U) +#define DOEPCTL_NAKSTS_Msk (0x1UL << DOEPCTL_NAKSTS_Pos) // 0x00020000 */ +#define DOEPCTL_NAKSTS DOEPCTL_NAKSTS_Msk // NAK status */ +#define DOEPCTL_SD0PID_SEVNFRM_Pos (28U) +#define DOEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << DOEPCTL_SD0PID_SEVNFRM_Pos) // 0x10000000 */ +#define DOEPCTL_SD0PID_SEVNFRM DOEPCTL_SD0PID_SEVNFRM_Msk // Set DATA0 PID */ +#define DOEPCTL_SODDFRM_Pos (29U) +#define DOEPCTL_SODDFRM_Msk (0x1UL << DOEPCTL_SODDFRM_Pos) // 0x20000000 */ +#define DOEPCTL_SODDFRM DOEPCTL_SODDFRM_Msk // Set odd frame */ +#define DOEPCTL_EPTYP_Pos (18U) +#define DOEPCTL_EPTYP_Msk (0x3UL << DOEPCTL_EPTYP_Pos) // 0x000C0000 */ +#define DOEPCTL_EPTYP DOEPCTL_EPTYP_Msk // Endpoint type */ +#define DOEPCTL_EPTYP_0 (0x1UL << DOEPCTL_EPTYP_Pos) // 0x00040000 */ +#define DOEPCTL_EPTYP_1 (0x2UL << DOEPCTL_EPTYP_Pos) // 0x00080000 */ +#define DOEPCTL_SNPM_Pos (20U) +#define DOEPCTL_SNPM_Msk (0x1UL << DOEPCTL_SNPM_Pos) // 0x00100000 */ +#define DOEPCTL_SNPM DOEPCTL_SNPM_Msk // Snoop mode */ +#define DOEPCTL_STALL_Pos (21U) +#define DOEPCTL_STALL_Msk (0x1UL << DOEPCTL_STALL_Pos) // 0x00200000 */ +#define DOEPCTL_STALL DOEPCTL_STALL_Msk // STALL handshake */ +#define DOEPCTL_CNAK_Pos (26U) +#define DOEPCTL_CNAK_Msk (0x1UL << DOEPCTL_CNAK_Pos) // 0x04000000 */ +#define DOEPCTL_CNAK DOEPCTL_CNAK_Msk // Clear NAK */ +#define DOEPCTL_SNAK_Pos (27U) +#define DOEPCTL_SNAK_Msk (0x1UL << DOEPCTL_SNAK_Pos) // 0x08000000 */ +#define DOEPCTL_SNAK DOEPCTL_SNAK_Msk // Set NAK */ +#define DOEPCTL_EPDIS_Pos (30U) +#define DOEPCTL_EPDIS_Msk (0x1UL << DOEPCTL_EPDIS_Pos) // 0x40000000 */ +#define DOEPCTL_EPDIS DOEPCTL_EPDIS_Msk // Endpoint disable */ +#define DOEPCTL_EPENA_Pos (31U) +#define DOEPCTL_EPENA_Msk (0x1UL << DOEPCTL_EPENA_Pos) // 0x80000000 */ +#define DOEPCTL_EPENA DOEPCTL_EPENA_Msk // Endpoint enable */ + +/******************** Bit definition for DOEPINT register ********************/ +#define DOEPINT_XFRC_Pos (0U) +#define DOEPINT_XFRC_Msk (0x1UL << DOEPINT_XFRC_Pos) // 0x00000001 */ +#define DOEPINT_XFRC DOEPINT_XFRC_Msk // Transfer completed interrupt */ +#define DOEPINT_EPDISD_Pos (1U) +#define DOEPINT_EPDISD_Msk (0x1UL << DOEPINT_EPDISD_Pos) // 0x00000002 */ +#define DOEPINT_EPDISD DOEPINT_EPDISD_Msk // Endpoint disabled interrupt */ +#define DOEPINT_AHBERR_Pos (2U) +#define DOEPINT_AHBERR_Msk (0x1UL << DOEPINT_AHBERR_Pos) // 0x00000004 */ +#define DOEPINT_AHBERR DOEPINT_AHBERR_Msk // AHB Error (AHBErr) during an OUT transaction */ +#define DOEPINT_STUP_Pos (3U) +#define DOEPINT_STUP_Msk (0x1UL << DOEPINT_STUP_Pos) // 0x00000008 */ +#define DOEPINT_STUP DOEPINT_STUP_Msk // SETUP phase done */ +#define DOEPINT_OTEPDIS_Pos (4U) +#define DOEPINT_OTEPDIS_Msk (0x1UL << DOEPINT_OTEPDIS_Pos) // 0x00000010 */ +#define DOEPINT_OTEPDIS DOEPINT_OTEPDIS_Msk // OUT token received when endpoint disabled */ +#define DOEPINT_OTEPSPR_Pos (5U) +#define DOEPINT_OTEPSPR_Msk (0x1UL << DOEPINT_OTEPSPR_Pos) // 0x00000020 */ +#define DOEPINT_OTEPSPR DOEPINT_OTEPSPR_Msk // Status Phase Received For Control Write */ +#define DOEPINT_B2BSTUP_Pos (6U) +#define DOEPINT_B2BSTUP_Msk (0x1UL << DOEPINT_B2BSTUP_Pos) // 0x00000040 */ +#define DOEPINT_B2BSTUP DOEPINT_B2BSTUP_Msk // Back-to-back SETUP packets received */ +#define DOEPINT_OUTPKTERR_Pos (8U) +#define DOEPINT_OUTPKTERR_Msk (0x1UL << DOEPINT_OUTPKTERR_Pos) // 0x00000100 */ +#define DOEPINT_OUTPKTERR DOEPINT_OUTPKTERR_Msk // OUT packet error */ +#define DOEPINT_NAK_Pos (13U) +#define DOEPINT_NAK_Msk (0x1UL << DOEPINT_NAK_Pos) // 0x00002000 */ +#define DOEPINT_NAK DOEPINT_NAK_Msk // NAK Packet is transmitted by the device */ +#define DOEPINT_NYET_Pos (14U) +#define DOEPINT_NYET_Msk (0x1UL << DOEPINT_NYET_Pos) // 0x00004000 */ +#define DOEPINT_NYET DOEPINT_NYET_Msk // NYET interrupt */ +#define DOEPINT_STPKTRX_Pos (15U) +#define DOEPINT_STPKTRX_Msk (0x1UL << DOEPINT_STPKTRX_Pos) // 0x00008000 */ +#define DOEPINT_STPKTRX DOEPINT_STPKTRX_Msk // Setup Packet Received */ + +/******************** Bit definition for DOEPTSIZ register ********************/ +#define DOEPTSIZ_XFRSIZ_Pos (0U) +#define DOEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << DOEPTSIZ_XFRSIZ_Pos) // 0x0007FFFF */ +#define DOEPTSIZ_XFRSIZ DOEPTSIZ_XFRSIZ_Msk // Transfer size */ +#define DOEPTSIZ_PKTCNT_Pos (19U) +#define DOEPTSIZ_PKTCNT_Msk (0x3FFUL << DOEPTSIZ_PKTCNT_Pos) // 0x1FF80000 */ +#define DOEPTSIZ_PKTCNT DOEPTSIZ_PKTCNT_Msk // Packet count */ + +#define DOEPTSIZ_STUPCNT_Pos (29U) +#define DOEPTSIZ_STUPCNT_Msk (0x3UL << DOEPTSIZ_STUPCNT_Pos) // 0x60000000 */ +#define DOEPTSIZ_STUPCNT DOEPTSIZ_STUPCNT_Msk // SETUP packet count */ +#define DOEPTSIZ_STUPCNT_0 (0x1UL << DOEPTSIZ_STUPCNT_Pos) // 0x20000000 */ +#define DOEPTSIZ_STUPCNT_1 (0x2UL << DOEPTSIZ_STUPCNT_Pos) // 0x40000000 */ + +/******************** Bit definition for PCGCTL register ********************/ +#define PCGCTL_IF_DEV_MODE TU_BIT(31) +#define PCGCTL_P2HD_PRT_SPD_MASK (0x3ul << 29) +#define PCGCTL_P2HD_PRT_SPD_SHIFT 29 +#define PCGCTL_P2HD_DEV_ENUM_SPD_MASK (0x3ul << 27) +#define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT 27 +#define PCGCTL_MAC_DEV_ADDR_MASK (0x7ful << 20) +#define PCGCTL_MAC_DEV_ADDR_SHIFT 20 +#define PCGCTL_MAX_TERMSEL TU_BIT(19) +#define PCGCTL_MAX_XCVRSELECT_MASK (0x3ul << 17) +#define PCGCTL_MAX_XCVRSELECT_SHIFT 17 +#define PCGCTL_PORT_POWER TU_BIT(16) +#define PCGCTL_PRT_CLK_SEL_MASK (0x3ul << 14) +#define PCGCTL_PRT_CLK_SEL_SHIFT 14 +#define PCGCTL_ESS_REG_RESTORED TU_BIT(13) +#define PCGCTL_EXTND_HIBER_SWITCH TU_BIT(12) +#define PCGCTL_EXTND_HIBER_PWRCLMP TU_BIT(11) +#define PCGCTL_ENBL_EXTND_HIBER TU_BIT(10) +#define PCGCTL_RESTOREMODE TU_BIT(9) +#define PCGCTL_RESETAFTSUSP TU_BIT(8) +#define PCGCTL_DEEP_SLEEP TU_BIT(7) +#define PCGCTL_PHY_IN_SLEEP TU_BIT(6) +#define PCGCTL_ENBL_SLEEP_GATING TU_BIT(5) +#define PCGCTL_RSTPDWNMODULE TU_BIT(3) +#define PCGCTL_PWRCLMP TU_BIT(2) +#define PCGCTL_GATEHCLK TU_BIT(1) +#define PCGCTL_STOPPCLK TU_BIT(0) + +#define PCGCTL1_TIMER (0x3ul << 1) +#define PCGCTL1_GATEEN TU_BIT(0) + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_xmc.h b/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_xmc.h new file mode 100644 index 00000000..63419abf --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_xmc.h @@ -0,0 +1,88 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Rafael Silva (@perigoso) + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _DWC2_XMC_H_ +#define _DWC2_XMC_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "xmc_device.h" + +#define DWC2_EP_MAX 7 + +static const dwc2_controller_t _dwc2_controller[] = +{ + // Note: XMC has some custom control registers before DWC registers + { .reg_base = USB0_BASE, .irqnum = USB0_0_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 2048 } +}; + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_enable(uint8_t rhport) +{ + NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum); +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_disable (uint8_t rhport) +{ + NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum); +} + +static inline void dwc2_remote_wakeup_delay(void) +{ + // try to delay for 1 ms +// uint32_t count = SystemCoreClock / 1000; +// while ( count-- ) __NOP(); +} + +// MCU specific PHY init, called BEFORE core reset +static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // Enable PHY + //USB->ROUTE = USB_ROUTE_PHYPEN; +} + +// MCU specific PHY update, it is called AFTER init() and core reset +static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // XMC Manual: turn around must be 5 (reset & default value) + // dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (5u << GUSBCFG_TRDT_Pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal.h new file mode 100644 index 00000000..9d11866d --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/osal/osal.h @@ -0,0 +1,89 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_OSAL_H_ +#define _TUSB_OSAL_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "common/tusb_common.h" + +// Return immediately +#define OSAL_TIMEOUT_NOTIMEOUT (0) +// Default timeout +#define OSAL_TIMEOUT_NORMAL (10) +// Wait forever +#define OSAL_TIMEOUT_WAIT_FOREVER (UINT32_MAX) + +#define OSAL_TIMEOUT_CONTROL_XFER OSAL_TIMEOUT_WAIT_FOREVER + +typedef void (*osal_task_func_t)( void * ); + +#if CFG_TUSB_OS == OPT_OS_NONE + #include "osal_none.h" +#elif CFG_TUSB_OS == OPT_OS_FREERTOS + #include "osal_freertos.h" +#elif CFG_TUSB_OS == OPT_OS_MYNEWT + #include "osal_mynewt.h" +#elif CFG_TUSB_OS == OPT_OS_PICO + #include "osal_pico.h" +#elif CFG_TUSB_OS == OPT_OS_RTTHREAD + #include "osal_rtthread.h" +#elif CFG_TUSB_OS == OPT_OS_RTX4 + #include "osal_rtx4.h" +#elif CFG_TUSB_OS == OPT_OS_CUSTOM + #include "tusb_os_custom.h" // implemented by application +#else + #error OS is not supported yet +#endif + +//--------------------------------------------------------------------+ +// OSAL Porting API +// Should be implemented as static inline function in osal_port.h header +/* + osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef); + bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr); + bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec); + void osal_semaphore_reset(osal_semaphore_t sem_hdl); // TODO removed + + osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef); + bool osal_mutex_lock (osal_mutex_t sem_hdl, uint32_t msec); + bool osal_mutex_unlock(osal_mutex_t mutex_hdl); + + osal_queue_t osal_queue_create(osal_queue_def_t* qdef); + bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec); + bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr); + bool osal_queue_empty(osal_queue_t qhdl); +*/ +//--------------------------------------------------------------------+ + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_OSAL_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal_freertos.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal_freertos.h new file mode 100644 index 00000000..52db336f --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/osal/osal_freertos.h @@ -0,0 +1,187 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_OSAL_FREERTOS_H_ +#define _TUSB_OSAL_FREERTOS_H_ + +// FreeRTOS Headers +#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,FreeRTOS.h) +#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,semphr.h) +#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,queue.h) +#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,task.h) + +#ifdef __cplusplus +extern "C" { +#endif + +TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec) +{ + if (msec == OSAL_TIMEOUT_WAIT_FOREVER) return portMAX_DELAY; + if (msec == 0) return 0; + + uint32_t ticks = pdMS_TO_TICKS(msec); + + // configTICK_RATE_HZ is less than 1000 and 1 tick > 1 ms + // we still need to delay at least 1 tick + if (ticks == 0) ticks =1 ; + + return ticks; +} + +//--------------------------------------------------------------------+ +// TASK API +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) +{ + vTaskDelay( pdMS_TO_TICKS(msec) ); +} + +//--------------------------------------------------------------------+ +// Semaphore API +//--------------------------------------------------------------------+ +typedef StaticSemaphore_t osal_semaphore_def_t; +typedef SemaphoreHandle_t osal_semaphore_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) +{ + return xSemaphoreCreateBinaryStatic(semdef); +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) +{ + if ( !in_isr ) + { + return xSemaphoreGive(sem_hdl) != 0; + } + else + { + BaseType_t xHigherPriorityTaskWoken; + BaseType_t res = xSemaphoreGiveFromISR(sem_hdl, &xHigherPriorityTaskWoken); + +#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3 + // not needed after https://github.com/espressif/esp-idf/commit/c5fd79547ac9b7bae06fa660e9f814d18d3390b7 + if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR(); +#else + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +#endif + + return res != 0; + } +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) +{ + return xSemaphoreTake(sem_hdl, _osal_ms2tick(msec)); +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) +{ + xQueueReset(sem_hdl); +} + +//--------------------------------------------------------------------+ +// MUTEX API (priority inheritance) +//--------------------------------------------------------------------+ +typedef StaticSemaphore_t osal_mutex_def_t; +typedef SemaphoreHandle_t osal_mutex_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) +{ + return xSemaphoreCreateMutexStatic(mdef); +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) +{ + return osal_semaphore_wait(mutex_hdl, msec); +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) +{ + return xSemaphoreGive(mutex_hdl); +} + +//--------------------------------------------------------------------+ +// QUEUE API +//--------------------------------------------------------------------+ + +// _int_set is not used with an RTOS +#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ + static _type _name##_##buf[_depth];\ + osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf }; + +typedef struct +{ + uint16_t depth; + uint16_t item_sz; + void* buf; + + StaticQueue_t sq; +}osal_queue_def_t; + +typedef QueueHandle_t osal_queue_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) +{ + return xQueueCreateStatic(qdef->depth, qdef->item_sz, (uint8_t*) qdef->buf, &qdef->sq); +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) +{ + return xQueueReceive(qhdl, data, _osal_ms2tick(msec)); +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) +{ + if ( !in_isr ) + { + return xQueueSendToBack(qhdl, data, OSAL_TIMEOUT_WAIT_FOREVER) != 0; + } + else + { + BaseType_t xHigherPriorityTaskWoken; + BaseType_t res = xQueueSendToBackFromISR(qhdl, data, &xHigherPriorityTaskWoken); + +#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3 + // not needed after https://github.com/espressif/esp-idf/commit/c5fd79547ac9b7bae06fa660e9f814d18d3390b7 + if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR(); +#else + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +#endif + + return res != 0; + } +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) +{ + return uxQueueMessagesWaiting(qhdl) == 0; +} + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal_mynewt.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal_mynewt.h new file mode 100644 index 00000000..b8ea2087 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/osal/osal_mynewt.h @@ -0,0 +1,176 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef OSAL_MYNEWT_H_ +#define OSAL_MYNEWT_H_ + +#include "os/os.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// TASK API +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) +{ + os_time_delay( os_time_ms_to_ticks32(msec) ); +} + +//--------------------------------------------------------------------+ +// Semaphore API +//--------------------------------------------------------------------+ +typedef struct os_sem osal_semaphore_def_t; +typedef struct os_sem* osal_semaphore_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) +{ + return (os_sem_init(semdef, 0) == OS_OK) ? (osal_semaphore_t) semdef : NULL; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) +{ + (void) in_isr; + return os_sem_release(sem_hdl) == OS_OK; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) +{ + uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? OS_TIMEOUT_NEVER : os_time_ms_to_ticks32(msec); + return os_sem_pend(sem_hdl, ticks) == OS_OK; +} + +static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) +{ + // TODO implement later +} + +//--------------------------------------------------------------------+ +// MUTEX API (priority inheritance) +//--------------------------------------------------------------------+ +typedef struct os_mutex osal_mutex_def_t; +typedef struct os_mutex* osal_mutex_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) +{ + return (os_mutex_init(mdef) == OS_OK) ? (osal_mutex_t) mdef : NULL; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) +{ + uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? OS_TIMEOUT_NEVER : os_time_ms_to_ticks32(msec); + return os_mutex_pend(mutex_hdl, ticks) == OS_OK; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) +{ + return os_mutex_release(mutex_hdl) == OS_OK; +} + +//--------------------------------------------------------------------+ +// QUEUE API +//--------------------------------------------------------------------+ + +// role device/host is used by OS NONE for mutex (disable usb isr) only +#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ + static _type _name##_##buf[_depth];\ + static struct os_event _name##_##evbuf[_depth];\ + osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf, .evbuf = _name##_##evbuf};\ + +typedef struct +{ + uint16_t depth; + uint16_t item_sz; + void* buf; + void* evbuf; + + struct os_mempool mpool; + struct os_mempool epool; + + struct os_eventq evq; +}osal_queue_def_t; + +typedef osal_queue_def_t* osal_queue_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) +{ + if ( OS_OK != os_mempool_init(&qdef->mpool, qdef->depth, qdef->item_sz, qdef->buf, "usbd queue") ) return NULL; + if ( OS_OK != os_mempool_init(&qdef->epool, qdef->depth, sizeof(struct os_event), qdef->evbuf, "usbd evqueue") ) return NULL; + + os_eventq_init(&qdef->evq); + return (osal_queue_t) qdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) +{ + (void) msec; // os_eventq_get() does not take timeout, always behave as msec = WAIT_FOREVER + + struct os_event* ev; + ev = os_eventq_get(&qhdl->evq); + + memcpy(data, ev->ev_arg, qhdl->item_sz); // copy message + os_memblock_put(&qhdl->mpool, ev->ev_arg); // put back mem block + os_memblock_put(&qhdl->epool, ev); // put back ev block + + return true; +} + +static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) +{ + (void) in_isr; + + // get a block from mem pool for data + void* ptr = os_memblock_get(&qhdl->mpool); + if (!ptr) return false; + memcpy(ptr, data, qhdl->item_sz); + + // get a block from event pool to put into queue + struct os_event* ev = (struct os_event*) os_memblock_get(&qhdl->epool); + if (!ev) + { + os_memblock_put(&qhdl->mpool, ptr); + return false; + } + tu_memclr(ev, sizeof(struct os_event)); + ev->ev_arg = ptr; + + os_eventq_put(&qhdl->evq, ev); + + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) +{ + return STAILQ_EMPTY(&qhdl->evq.evq_list); +} + + +#ifdef __cplusplus + } +#endif + +#endif /* OSAL_MYNEWT_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal_none.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal_none.h new file mode 100644 index 00000000..9c80e454 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/osal/osal_none.h @@ -0,0 +1,181 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_OSAL_NONE_H_ +#define _TUSB_OSAL_NONE_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// TASK API +//--------------------------------------------------------------------+ + + +//--------------------------------------------------------------------+ +// Binary Semaphore API +//--------------------------------------------------------------------+ +typedef struct +{ + volatile uint16_t count; +}osal_semaphore_def_t; + +typedef osal_semaphore_def_t* osal_semaphore_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) +{ + semdef->count = 0; + return semdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) +{ + (void) in_isr; + sem_hdl->count++; + return true; +} + +// TODO blocking for now +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) +{ + (void) msec; + + while (sem_hdl->count == 0) { } + sem_hdl->count--; + + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) +{ + sem_hdl->count = 0; +} + +//--------------------------------------------------------------------+ +// MUTEX API +// Within tinyusb, mutex is never used in ISR context +//--------------------------------------------------------------------+ +typedef osal_semaphore_def_t osal_mutex_def_t; +typedef osal_semaphore_t osal_mutex_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) +{ + mdef->count = 1; + return mdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) +{ + return osal_semaphore_wait(mutex_hdl, msec); +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) +{ + return osal_semaphore_post(mutex_hdl, false); +} + +//--------------------------------------------------------------------+ +// QUEUE API +//--------------------------------------------------------------------+ +#include "common/tusb_fifo.h" + +typedef struct +{ + void (*interrupt_set)(bool); + tu_fifo_t ff; +}osal_queue_def_t; + +typedef osal_queue_def_t* osal_queue_t; + +// _int_set is used as mutex in OS NONE (disable/enable USB ISR) +#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ + uint8_t _name##_buf[_depth*sizeof(_type)]; \ + osal_queue_def_t _name = { \ + .interrupt_set = _int_set, \ + .ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \ + } + +// lock queue by disable USB interrupt +TU_ATTR_ALWAYS_INLINE static inline void _osal_q_lock(osal_queue_t qhdl) +{ + // disable dcd/hcd interrupt + qhdl->interrupt_set(false); +} + +// unlock queue +TU_ATTR_ALWAYS_INLINE static inline void _osal_q_unlock(osal_queue_t qhdl) +{ + // enable dcd/hcd interrupt + qhdl->interrupt_set(true); +} + +TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) +{ + tu_fifo_clear(&qdef->ff); + return (osal_queue_t) qdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) +{ + (void) msec; // not used, always behave as msec = 0 + + _osal_q_lock(qhdl); + bool success = tu_fifo_read(&qhdl->ff, data); + _osal_q_unlock(qhdl); + + return success; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) +{ + if (!in_isr) { + _osal_q_lock(qhdl); + } + + bool success = tu_fifo_write(&qhdl->ff, data); + + if (!in_isr) { + _osal_q_unlock(qhdl); + } + + TU_ASSERT(success); + + return success; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) +{ + // Skip queue lock/unlock since this function is primarily called + // with interrupt disabled before going into low power mode + return tu_fifo_empty(&qhdl->ff); +} + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_OSAL_NONE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal_pico.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal_pico.h new file mode 100644 index 00000000..8b428d64 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/osal/osal_pico.h @@ -0,0 +1,184 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_OSAL_PICO_H_ +#define _TUSB_OSAL_PICO_H_ + +#include "pico/time.h" +#include "pico/sem.h" +#include "pico/mutex.h" +#include "pico/critical_section.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// TASK API +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) +{ + sleep_ms(msec); +} + +//--------------------------------------------------------------------+ +// Binary Semaphore API +//--------------------------------------------------------------------+ +typedef struct semaphore osal_semaphore_def_t, *osal_semaphore_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) +{ + sem_init(semdef, 0, 255); + return semdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) +{ + (void) in_isr; + sem_release(sem_hdl); + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) +{ + return sem_acquire_timeout_ms(sem_hdl, msec); +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) +{ + sem_reset(sem_hdl, 0); +} + +//--------------------------------------------------------------------+ +// MUTEX API +// Within tinyusb, mutex is never used in ISR context +//--------------------------------------------------------------------+ +typedef struct mutex osal_mutex_def_t, *osal_mutex_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) +{ + mutex_init(mdef); + return mdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) +{ + return mutex_enter_timeout_ms(mutex_hdl, msec); +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) +{ + mutex_exit(mutex_hdl); + return true; +} + +//--------------------------------------------------------------------+ +// QUEUE API +//--------------------------------------------------------------------+ +#include "common/tusb_fifo.h" + +typedef struct +{ + tu_fifo_t ff; + struct critical_section critsec; // osal_queue may be used in IRQs, so need critical section +} osal_queue_def_t; + +typedef osal_queue_def_t* osal_queue_t; + +// role device/host is used by OS NONE for mutex (disable usb isr) only +#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ + uint8_t _name##_buf[_depth*sizeof(_type)]; \ + osal_queue_def_t _name = { \ + .ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \ + } + +// lock queue by disable USB interrupt +TU_ATTR_ALWAYS_INLINE static inline void _osal_q_lock(osal_queue_t qhdl) +{ + critical_section_enter_blocking(&qhdl->critsec); +} + +// unlock queue +TU_ATTR_ALWAYS_INLINE static inline void _osal_q_unlock(osal_queue_t qhdl) +{ + critical_section_exit(&qhdl->critsec); +} + +TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) +{ + critical_section_init(&qdef->critsec); + tu_fifo_clear(&qdef->ff); + return (osal_queue_t) qdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) +{ + (void) msec; // not used, always behave as msec = 0 + + // TODO: revisit... docs say that mutexes are never used from IRQ context, + // however osal_queue_recieve may be. therefore my assumption is that + // the fifo mutex is not populated for queues used from an IRQ context + //assert(!qhdl->ff.mutex); + + _osal_q_lock(qhdl); + bool success = tu_fifo_read(&qhdl->ff, data); + _osal_q_unlock(qhdl); + + return success; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) +{ + // TODO: revisit... docs say that mutexes are never used from IRQ context, + // however osal_queue_recieve may be. therefore my assumption is that + // the fifo mutex is not populated for queues used from an IRQ context + //assert(!qhdl->ff.mutex); + (void) in_isr; + + _osal_q_lock(qhdl); + bool success = tu_fifo_write(&qhdl->ff, data); + _osal_q_unlock(qhdl); + + TU_ASSERT(success); + + return success; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) +{ + // TODO: revisit; whether this is true or not currently, tu_fifo_empty is a single + // volatile read. + + // Skip queue lock/unlock since this function is primarily called + // with interrupt disabled before going into low power mode + return tu_fifo_empty(&qhdl->ff); +} + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_OSAL_PICO_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtthread.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtthread.h new file mode 100644 index 00000000..f8452bfb --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtthread.h @@ -0,0 +1,132 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 tfx2001 (2479727366@qq.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_OSAL_RTTHREAD_H_ +#define _TUSB_OSAL_RTTHREAD_H_ + +// RT-Thread Headers +#include "rtthread.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------+ +// TASK API +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) { + rt_thread_mdelay(msec); +} + +//--------------------------------------------------------------------+ +// Semaphore API +//--------------------------------------------------------------------+ +typedef struct rt_semaphore osal_semaphore_def_t; +typedef rt_sem_t osal_semaphore_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t +osal_semaphore_create(osal_semaphore_def_t *semdef) { + rt_sem_init(semdef, "tusb", 0, RT_IPC_FLAG_PRIO); + return semdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) { + (void) in_isr; + return rt_sem_release(sem_hdl) == RT_EOK; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) { + return rt_sem_take(sem_hdl, rt_tick_from_millisecond((rt_int32_t) msec)) == RT_EOK; +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) { + // TODO: implement +} + +//--------------------------------------------------------------------+ +// MUTEX API (priority inheritance) +//--------------------------------------------------------------------+ +typedef struct rt_mutex osal_mutex_def_t; +typedef rt_mutex_t osal_mutex_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) { + rt_mutex_init(mdef, "tusb", RT_IPC_FLAG_PRIO); + return mdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) { + return rt_mutex_take(mutex_hdl, rt_tick_from_millisecond((rt_int32_t) msec)) == RT_EOK; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) { + return rt_mutex_release(mutex_hdl) == RT_EOK; +} + +//--------------------------------------------------------------------+ +// QUEUE API +//--------------------------------------------------------------------+ + +// role device/host is used by OS NONE for mutex (disable usb isr) only +#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ + static _type _name##_##buf[_depth]; \ + osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf }; + +typedef struct { + uint16_t depth; + uint16_t item_sz; + void *buf; + + struct rt_messagequeue sq; +} osal_queue_def_t; + +typedef rt_mq_t osal_queue_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t *qdef) { + rt_mq_init(&(qdef->sq), "tusb", qdef->buf, qdef->item_sz, + qdef->item_sz * qdef->depth, RT_IPC_FLAG_PRIO); + return &(qdef->sq); +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void *data, uint32_t msec) { + + rt_tick_t tick = rt_tick_from_millisecond((rt_int32_t) msec); + return rt_mq_recv(qhdl, data, qhdl->msg_size, tick) == RT_EOK; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const *data, bool in_isr) { + (void) in_isr; + return rt_mq_send(qhdl, (void *)data, qhdl->msg_size) == RT_EOK; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) { + return (qhdl->entry) == 0; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_OSAL_RTTHREAD_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtx4.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtx4.h new file mode 100644 index 00000000..dea1c12c --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtx4.h @@ -0,0 +1,170 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Tian Yunhao (t123yh) + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_OSAL_RTX4_H_ +#define _TUSB_OSAL_RTX4_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------+ +// TASK API +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) +{ + uint16_t hi = msec >> 16; + uint16_t lo = msec; + while (hi--) { + os_dly_wait(0xFFFE); + } + os_dly_wait(lo); +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t msec2wait(uint32_t msec) { + if (msec == OSAL_TIMEOUT_WAIT_FOREVER) + return 0xFFFF; + else if (msec >= 0xFFFE) + return 0xFFFE; + else + return msec; +} + +//--------------------------------------------------------------------+ +// Semaphore API +//--------------------------------------------------------------------+ +typedef OS_SEM osal_semaphore_def_t; +typedef OS_ID osal_semaphore_t; + +TU_ATTR_ALWAYS_INLINE static inline OS_ID osal_semaphore_create(osal_semaphore_def_t* semdef) { + os_sem_init(semdef, 0); + return semdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) { + if ( !in_isr ) { + os_sem_send(sem_hdl); + } else { + isr_sem_send(sem_hdl); + } + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) { + return os_sem_wait(sem_hdl, msec2wait(msec)) != OS_R_TMO; +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) { + // TODO: implement +} + +//--------------------------------------------------------------------+ +// MUTEX API (priority inheritance) +//--------------------------------------------------------------------+ +typedef OS_MUT osal_mutex_def_t; +typedef OS_ID osal_mutex_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) +{ + os_mut_init(mdef); + return mdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) +{ + return os_mut_wait(mutex_hdl, msec2wait(msec)) != OS_R_TMO; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) +{ + return os_mut_release(mutex_hdl) == OS_R_OK; +} + +//--------------------------------------------------------------------+ +// QUEUE API +//--------------------------------------------------------------------+ + +// role device/host is used by OS NONE for mutex (disable usb isr) only +#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ + os_mbx_declare(_name##__mbox, _depth); \ + _declare_box(_name##__pool, sizeof(_type), _depth); \ + osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .pool = _name##__pool, .mbox = _name##__mbox }; + + +typedef struct +{ + uint16_t depth; + uint16_t item_sz; + U32* pool; + U32* mbox; +}osal_queue_def_t; + +typedef osal_queue_def_t* osal_queue_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) +{ + os_mbx_init(qdef->mbox, (qdef->depth + 4) * 4); + _init_box(qdef->pool, ((qdef->item_sz+3)/4)*(qdef->depth) + 3, qdef->item_sz); + return qdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) +{ + void* buf; + os_mbx_wait(qhdl->mbox, &buf, msec2wait(msec)); + memcpy(data, buf, qhdl->item_sz); + _free_box(qhdl->pool, buf); + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) +{ + void* buf = _alloc_box(qhdl->pool); + memcpy(buf, data, qhdl->item_sz); + if ( !in_isr ) + { + os_mbx_send(qhdl->mbox, buf, 0xFFFF); + } + else + { + isr_mbx_send(qhdl->mbox, buf); + } + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) +{ + return os_mbx_check(qhdl->mbox) == qhdl->depth; +} + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c b/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c new file mode 100644 index 00000000..f17176ae --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c @@ -0,0 +1,1162 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Nathan Conrad + * + * Portions: + * Copyright (c) 2016 STMicroelectronics + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/********************************************** + * This driver has been tested with the following MCUs: + * - F070, F072, L053, F042F6 + * + * It also should work with minimal changes for any ST MCU with an "USB A"/"PCD"/"HCD" peripheral. This + * covers: + * + * F04x, F072, F078, 070x6/B 1024 byte buffer + * F102, F103 512 byte buffer; no internal D+ pull-up (maybe many more changes?) + * F302xB/C, F303xB/C, F373 512 byte buffer; no internal D+ pull-up + * F302x6/8, F302xD/E2, F303xD/E 1024 byte buffer; no internal D+ pull-up + * L0x2, L0x3 1024 byte buffer + * L1 512 byte buffer + * L4x2, L4x3 1024 byte buffer + * + * To use this driver, you must: + * - If you are using a device with crystal-less USB, set up the clock recovery system (CRS) + * - Remap pins to be D+/D- on devices that they are shared (for example: F042Fx) + * - This is different to the normal "alternate function" GPIO interface, needs to go through SYSCFG->CFGRx register + * - Enable USB clock; Perhaps use __HAL_RCC_USB_CLK_ENABLE(); + * - (Optionally configure GPIO HAL to tell it the USB driver is using the USB pins) + * - call tusb_init(); + * - periodically call tusb_task(); + * + * Assumptions of the driver: + * - You are not using CAN (it must share the packet buffer) + * - APB clock is >= 10 MHz + * - On some boards, series resistors are required, but not on others. + * - On some boards, D+ pull up resistor (1.5kohm) is required, but not on others. + * - You don't have long-running interrupts; some USB packets must be quickly responded to. + * - You have the ST CMSIS library linked into the project. HAL is not used. + * + * Current driver limitations (i.e., a list of features for you to add): + * - STALL handled, but not tested. + * - Does it work? No clue. + * - All EP BTABLE buffers are created based on max packet size of first EP opened with that address. + * - No isochronous endpoints + * - Endpoint index is the ID of the endpoint + * - This means that priority is given to endpoints with lower ID numbers + * - Code is mixing up EP IX with EP ID. Everywhere. + * - Packet buffer memory is copied in the interrupt. + * - This is better for performance, but means interrupts are disabled for longer + * - DMA may be the best choice, but it could also be pushed to the USBD task. + * - No double-buffering + * - No DMA + * - Minimal error handling + * - Perhaps error interrupts should be reported to the stack, or cause a device reset? + * - Assumes a single USB peripheral; I think that no hardware has multiple so this is fine. + * - Add a callback for enabling/disabling the D+ PU on devices without an internal PU. + * - F3 models use three separate interrupts. I think we could only use the LP interrupt for + * everything? However, the interrupts are configurable so the DisableInt and EnableInt + * below functions could be adjusting the wrong interrupts (if they had been reconfigured) + * - LPM is not used correctly, or at all? + * + * USB documentation and Reference implementations + * - STM32 Reference manuals + * - STM32 USB Hardware Guidelines AN4879 + * + * - STM32 HAL (much of this driver is based on this) + * - libopencm3/lib/stm32/common/st_usbfs_core.c + * - Keil USB Device http://www.keil.com/pack/doc/mw/USB/html/group__usbd.html + * + * - YouTube OpenTechLab 011; https://www.youtube.com/watch?v=4FOkJLp_PUw + * + * Advantages over HAL driver: + * - Tiny (saves RAM, assumes a single USB peripheral) + * + * Notes: + * - The buffer table is allocated as endpoints are opened. The allocation is only + * cleared when the device is reset. This may be bad if the USB device needs + * to be reconfigured. + */ + +#include "tusb_option.h" + +#if defined(STM32F102x6) || defined(STM32F102xB) || \ + defined(STM32F103x6) || defined(STM32F103xB) || \ + defined(STM32F103xE) || defined(STM32F103xG) +#define STM32F1_FSDEV +#endif + +#if CFG_TUD_ENABLED && \ + ( TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32F3, OPT_MCU_STM32L0, OPT_MCU_STM32L1, OPT_MCU_STM32G4, OPT_MCU_STM32WB) || \ + (TU_CHECK_MCU(OPT_MCU_STM32F1) && defined(STM32F1_FSDEV)) \ + ) + +// In order to reduce the dependance on HAL, we undefine this. +// Some definitions are copied to our private include file. +#undef USE_HAL_DRIVER + +#include "device/dcd.h" +#include "dcd_stm32_fsdev_pvt_st.h" + + +/***************************************************** + * Configuration + *****************************************************/ + +// HW supports max of 8 bidirectional endpoints, but this can be reduced to save RAM +// (8u here would mean 8 IN and 8 OUT) +#ifndef MAX_EP_COUNT +# define MAX_EP_COUNT 8U +#endif + +// If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it +// Both of these MUST be a multiple of 2, and are in byte units. +#ifndef DCD_STM32_BTABLE_BASE +# define DCD_STM32_BTABLE_BASE 0U +#endif + +#ifndef DCD_STM32_BTABLE_LENGTH +# define DCD_STM32_BTABLE_LENGTH (PMA_LENGTH - DCD_STM32_BTABLE_BASE) +#endif + +// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval) +// We disable SOF for now until needed later on +#ifndef USE_SOF +# define USE_SOF 0 +#endif + +/*************************************************** + * Checks, structs, defines, function definitions, etc. + */ + +TU_VERIFY_STATIC((MAX_EP_COUNT) <= STFSDEV_EP_COUNT, "Only 8 endpoints supported on the hardware"); + +TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_LENGTH))<=(PMA_LENGTH), + "BTABLE does not fit in PMA RAM"); + +TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligned to 8 bytes"); + +// One of these for every EP IN & OUT, uses a bit of RAM.... +typedef struct +{ + uint8_t * buffer; + // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API + uint16_t total_len; + uint16_t queued_len; + uint16_t pma_ptr; + uint8_t max_packet_size; + uint8_t pma_alloc_size; +} xfer_ctl_t; + +static xfer_ctl_t xfer_status[MAX_EP_COUNT][2]; + +static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t epnum, uint32_t dir) +{ + return &xfer_status[epnum][dir]; +} + +static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6]; + +static uint8_t remoteWakeCountdown; // When wake is requested + +// into the stack. +static void dcd_handle_bus_reset(void); +static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix); +static void dcd_ep_ctr_handler(void); + +// PMA allocation/access +static uint8_t open_ep_count; +static uint16_t ep_buf_ptr; ///< Points to first free memory location +static void dcd_pma_alloc_reset(void); +static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length); +static void dcd_pma_free(uint8_t ep_addr); +static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes); +static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes); + +//static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes); +//static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes); + +// Using a function due to better type checks +// This seems better than having to do type casts everywhere else +static inline void reg16_clear_bits(__IO uint16_t *reg, uint16_t mask) { + *reg = (uint16_t)(*reg & ~mask); +} + +// Bits in ISTR are cleared upon writing 0 +static inline void clear_istr_bits(uint16_t mask) { + USB->ISTR = ~mask; +} + +void dcd_init (uint8_t rhport) +{ + /* Clocks should already be enabled */ + /* Use __HAL_RCC_USB_CLK_ENABLE(); to enable the clocks before calling this function */ + + /* The RM mentions to use a special ordering of PDWN and FRES, but this isn't done in HAL. + * Here, the RM is followed. */ + + for(uint32_t i = 0; i<200; i++) // should be a few us + { + asm("NOP"); + } + // Perform USB peripheral reset + USB->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; + for(uint32_t i = 0; i<200; i++) // should be a few us + { + asm("NOP"); + } + reg16_clear_bits(&USB->CNTR, USB_CNTR_PDWN);// Remove powerdown + // Wait startup time, for F042 and F070, this is <= 1 us. + for(uint32_t i = 0; i<200; i++) // should be a few us + { + asm("NOP"); + } + USB->CNTR = 0; // Enable USB + + USB->BTABLE = DCD_STM32_BTABLE_BASE; + + USB->ISTR = 0; // Clear pending interrupts + + // Reset endpoints to disabled + for(uint32_t i=0; iCNTR |= USB_CNTR_RESETM | (USE_SOF ? USB_CNTR_SOFM : 0) | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; + dcd_handle_bus_reset(); + + // Enable pull-up if supported + if ( dcd_connect ) dcd_connect(rhport); +} + +// Define only on MCU with internal pull-up. BSP can define on MCU without internal PU. +#if defined(USB_BCDR_DPPU) + +// Disable internal D+ PU +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; + USB->BCDR &= ~(USB_BCDR_DPPU); +} + +// Enable internal D+ PU +void dcd_connect(uint8_t rhport) +{ + (void) rhport; + USB->BCDR |= USB_BCDR_DPPU; +} + +#elif defined(SYSCFG_PMC_USB_PU) // works e.g. on STM32L151 +// Disable internal D+ PU +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; + SYSCFG->PMC &= ~(SYSCFG_PMC_USB_PU); +} + +// Enable internal D+ PU +void dcd_connect(uint8_t rhport) +{ + (void) rhport; + SYSCFG->PMC |= SYSCFG_PMC_USB_PU; +} +#endif + +void dcd_sof_enable(uint8_t rhport, bool en) +{ + (void) rhport; + (void) en; + + // TODO implement later +} + +// Enable device interrupt +void dcd_int_enable (uint8_t rhport) +{ + (void)rhport; + // Member here forces write to RAM before allowing ISR to execute + __DSB(); + __ISB(); +#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 + NVIC_EnableIRQ(USB_IRQn); + +#elif CFG_TUSB_MCU == OPT_MCU_STM32L1 + NVIC_EnableIRQ(USB_LP_IRQn); + +#elif CFG_TUSB_MCU == OPT_MCU_STM32F3 + // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from + // shared USB/CAN IRQs to separate CAN and USB IRQs. + // This dynamically checks if this remap is active to enable the right IRQs. + #ifdef SYSCFG_CFGR1_USB_IT_RMP + if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) + { + NVIC_EnableIRQ(USB_HP_IRQn); + NVIC_EnableIRQ(USB_LP_IRQn); + NVIC_EnableIRQ(USBWakeUp_RMP_IRQn); + } + else + #endif + { + NVIC_EnableIRQ(USB_HP_CAN_TX_IRQn); + NVIC_EnableIRQ(USB_LP_CAN_RX0_IRQn); + NVIC_EnableIRQ(USBWakeUp_IRQn); + } +#elif CFG_TUSB_MCU == OPT_MCU_STM32F1 + NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn); + NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn); + NVIC_EnableIRQ(USBWakeUp_IRQn); + +#elif CFG_TUSB_MCU == OPT_MCU_STM32G4 + NVIC_EnableIRQ(USB_HP_IRQn); + NVIC_EnableIRQ(USB_LP_IRQn); + NVIC_EnableIRQ(USBWakeUp_IRQn); + +#elif CFG_TUSB_MCU == OPT_MCU_STM32WB + NVIC_EnableIRQ(USB_HP_IRQn); + NVIC_EnableIRQ(USB_LP_IRQn); + +#else + #error Unknown arch in USB driver +#endif +} + +// Disable device interrupt +void dcd_int_disable(uint8_t rhport) +{ + (void)rhport; + +#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 + NVIC_DisableIRQ(USB_IRQn); +#elif CFG_TUSB_MCU == OPT_MCU_STM32L1 + NVIC_DisableIRQ(USB_LP_IRQn); +#elif CFG_TUSB_MCU == OPT_MCU_STM32F3 + // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from + // shared USB/CAN IRQs to separate CAN and USB IRQs. + // This dynamically checks if this remap is active to disable the right IRQs. + #ifdef SYSCFG_CFGR1_USB_IT_RMP + if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) + { + NVIC_DisableIRQ(USB_HP_IRQn); + NVIC_DisableIRQ(USB_LP_IRQn); + NVIC_DisableIRQ(USBWakeUp_RMP_IRQn); + } + else + #endif + { + NVIC_DisableIRQ(USB_HP_CAN_TX_IRQn); + NVIC_DisableIRQ(USB_LP_CAN_RX0_IRQn); + NVIC_DisableIRQ(USBWakeUp_IRQn); + } +#elif CFG_TUSB_MCU == OPT_MCU_STM32F1 + NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn); + NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn); + NVIC_DisableIRQ(USBWakeUp_IRQn); + +#elif CFG_TUSB_MCU == OPT_MCU_STM32G4 + NVIC_DisableIRQ(USB_HP_IRQn); + NVIC_DisableIRQ(USB_LP_IRQn); + NVIC_DisableIRQ(USBWakeUp_IRQn); + +#elif CFG_TUSB_MCU == OPT_MCU_STM32WB + NVIC_DisableIRQ(USB_HP_IRQn); + NVIC_DisableIRQ(USB_LP_IRQn); + +#else + #error Unknown arch in USB driver +#endif + + // CMSIS has a membar after disabling interrupts +} + +// Receive Set Address request, mcu port must also include status IN response +void dcd_set_address(uint8_t rhport, uint8_t dev_addr) +{ + (void) rhport; + (void) dev_addr; + + // Respond with status + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); + + // DCD can only set address after status for this request is complete. + // do it at dcd_edpt0_status_complete() +} + +void dcd_remote_wakeup(uint8_t rhport) +{ + (void) rhport; + + USB->CNTR |= (uint16_t) USB_CNTR_RESUME; + remoteWakeCountdown = 4u; // required to be 1 to 15 ms, ESOF should trigger every 1ms. +} + +static const tusb_desc_endpoint_t ep0OUT_desc = +{ + .bLength = sizeof(tusb_desc_endpoint_t), + .bDescriptorType = TUSB_DESC_ENDPOINT, + + .bEndpointAddress = 0x00, + .bmAttributes = { .xfer = TUSB_XFER_CONTROL }, + .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE, + .bInterval = 0 +}; + +static const tusb_desc_endpoint_t ep0IN_desc = +{ + .bLength = sizeof(tusb_desc_endpoint_t), + .bDescriptorType = TUSB_DESC_ENDPOINT, + + .bEndpointAddress = 0x80, + .bmAttributes = { .xfer = TUSB_XFER_CONTROL }, + .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE, + .bInterval = 0 +}; + +static void dcd_handle_bus_reset(void) +{ + //__IO uint16_t * const epreg = &(EPREG(0)); + USB->DADDR = 0u; // disable USB peripheral by clearing the EF flag + + // Clear all EPREG (or maybe this is automatic? I'm not sure) + for(uint32_t i=0; iDADDR = USB_DADDR_EF; // Set enable flag, and leaving the device address as zero. +} + +// Handle CTR interrupt for the TX/IN direction +// +// Upon call, (wIstr & USB_ISTR_DIR) == 0U +static void dcd_ep_ctr_tx_handler(uint32_t wIstr) +{ + uint32_t EPindex = wIstr & USB_ISTR_EP_ID; + uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex); + + // Verify the CTR_TX bit is set. This was in the ST Micro code, + // but I'm not sure it's actually necessary? + if((wEPRegVal & USB_EP_CTR_TX) == 0U) + { + return; + } + + /* clear int flag */ + pcd_clear_tx_ep_ctr(USB, EPindex); + + xfer_ctl_t * xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_IN); + if((xfer->total_len != xfer->queued_len)) /* TX not complete */ + { + dcd_transmit_packet(xfer, EPindex); + } + else /* TX Complete */ + { + dcd_event_xfer_complete(0, (uint8_t)(0x80 + EPindex), xfer->total_len, XFER_RESULT_SUCCESS, true); + } +} + +// Handle CTR interrupt for the RX/OUT direction +// +// Upon call, (wIstr & USB_ISTR_DIR) == 0U +static void dcd_ep_ctr_rx_handler(uint32_t wIstr) +{ + uint32_t EPindex = wIstr & USB_ISTR_EP_ID; + uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex); + uint32_t count = pcd_get_ep_rx_cnt(USB,EPindex); + + xfer_ctl_t *xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_OUT); + + // Verify the CTR_RX bit is set. This was in the ST Micro code, + // but I'm not sure it's actually necessary? + if((wEPRegVal & USB_EP_CTR_RX) == 0U) + { + return; + } + + if((EPindex == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) /* Setup packet */ + { + // The setup_received function uses memcpy, so this must first copy the setup data into + // user memory, to allow for the 32-bit access that memcpy performs. + uint8_t userMemBuf[8]; + /* Get SETUP Packet*/ + if(count == 8) // Setup packet should always be 8 bytes. If not, ignore it, and try again. + { + // Must reset EP to NAK (in case it had been stalling) (though, maybe too late here) + pcd_set_ep_rx_status(USB,0u,USB_EP_RX_NAK); + pcd_set_ep_tx_status(USB,0u,USB_EP_TX_NAK); + dcd_read_packet_memory(userMemBuf, *pcd_ep_rx_address_ptr(USB,EPindex), 8); + dcd_event_setup_received(0, (uint8_t*)userMemBuf, true); + } + } + else + { + // Clear RX CTR interrupt flag + if(EPindex != 0u) + { + pcd_clear_rx_ep_ctr(USB, EPindex); + } + + if (count != 0U) + { +#if 0 // TODO support dcd_edpt_xfer_fifo API + if (xfer->ff) + { + dcd_read_packet_memory_ff(xfer->ff, *pcd_ep_rx_address_ptr(USB,EPindex), count); + } + else +#endif + { + dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), *pcd_ep_rx_address_ptr(USB,EPindex), count); + } + + xfer->queued_len = (uint16_t)(xfer->queued_len + count); + } + + if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len)) + { + /* RX COMPLETE */ + dcd_event_xfer_complete(0, EPindex, xfer->queued_len, XFER_RESULT_SUCCESS, true); + // Though the host could still send, we don't know. + // Does the bulk pipe need to be reset to valid to allow for a ZLP? + } + else + { + uint32_t remaining = (uint32_t)xfer->total_len - (uint32_t)xfer->queued_len; + if(remaining >= xfer->max_packet_size) { + pcd_set_ep_rx_cnt(USB, EPindex,xfer->max_packet_size); + } else { + pcd_set_ep_rx_cnt(USB, EPindex,remaining); + } + pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID); + } + } + + // For EP0, prepare to receive another SETUP packet. + // Clear CTR last so that a new packet does not overwrite the packing being read. + // (Based on the docs, it seems SETUP will always be accepted after CTR is cleared) + if(EPindex == 0u) + { + // Always be prepared for a status packet... + pcd_set_ep_rx_cnt(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE); + pcd_clear_rx_ep_ctr(USB, EPindex); + } +} + +static void dcd_ep_ctr_handler(void) +{ + uint32_t wIstr; + + /* stay in loop while pending interrupts */ + while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U) + { + + if ((wIstr & USB_ISTR_DIR) == 0U) /* TX/IN */ + { + dcd_ep_ctr_tx_handler(wIstr); + } + else /* RX/OUT*/ + { + dcd_ep_ctr_rx_handler(wIstr); + } + } +} + +void dcd_int_handler(uint8_t rhport) { + + (void) rhport; + + uint32_t int_status = USB->ISTR; + //const uint32_t handled_ints = USB_ISTR_CTR | USB_ISTR_RESET | USB_ISTR_WKUP + // | USB_ISTR_SUSP | USB_ISTR_SOF | USB_ISTR_ESOF; + // unused IRQs: (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_L1REQ ) + + // The ST driver loops here on the CTR bit, but that loop has been moved into the + // dcd_ep_ctr_handler(), so less need to loop here. The other interrupts shouldn't + // be triggered repeatedly. + + if(int_status & USB_ISTR_RESET) { + // USBRST is start of reset. + clear_istr_bits(USB_ISTR_RESET); + dcd_handle_bus_reset(); + dcd_event_bus_reset(0, TUSB_SPEED_FULL, true); + return; // Don't do the rest of the things here; perhaps they've been cleared? + } + + if (int_status & USB_ISTR_CTR) + { + /* servicing of the endpoint correct transfer interrupt */ + /* clear of the CTR flag into the sub */ + dcd_ep_ctr_handler(); + } + + if (int_status & USB_ISTR_WKUP) + { + reg16_clear_bits(&USB->CNTR, USB_CNTR_LPMODE); + reg16_clear_bits(&USB->CNTR, USB_CNTR_FSUSP); + clear_istr_bits(USB_ISTR_WKUP); + dcd_event_bus_signal(0, DCD_EVENT_RESUME, true); + } + + if (int_status & USB_ISTR_SUSP) + { + /* Suspend is asserted for both suspend and unplug events. without Vbus monitoring, + * these events cannot be differentiated, so we only trigger suspend. */ + + /* Force low-power mode in the macrocell */ + USB->CNTR |= USB_CNTR_FSUSP; + USB->CNTR |= USB_CNTR_LPMODE; + + /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ + clear_istr_bits(USB_ISTR_SUSP); + dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); + } + +#if USE_SOF + if(int_status & USB_ISTR_SOF) { + clear_istr_bits(USB_ISTR_SOF); + dcd_event_bus_signal(0, DCD_EVENT_SOF, true); + } +#endif + + if(int_status & USB_ISTR_ESOF) { + if(remoteWakeCountdown == 1u) + { + USB->CNTR &= (uint16_t)(~USB_CNTR_RESUME); + } + if(remoteWakeCountdown > 0u) + { + remoteWakeCountdown--; + } + clear_istr_bits(USB_ISTR_ESOF); + } +} + +//--------------------------------------------------------------------+ +// Endpoint API +//--------------------------------------------------------------------+ + +// Invoked when a control transfer's status stage is complete. +// May help DCD to prepare for next control transfer, this API is optional. +void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) +{ + (void) rhport; + + if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && + request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && + request->bRequest == TUSB_REQ_SET_ADDRESS ) + { + uint8_t const dev_addr = (uint8_t) request->wValue; + + // Setting new address after the whole request is complete + reg16_clear_bits(&USB->DADDR, USB_DADDR_ADD); + USB->DADDR = (uint16_t)(USB->DADDR | dev_addr); // leave the enable bit set + } +} + +static void dcd_pma_alloc_reset(void) +{ + ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT; // 8 bytes per endpoint (two TX and two RX words, each) + //TU_LOG2("dcd_pma_alloc_reset()\r\n"); + for(uint32_t i=0; ipma_alloc_size = 0U; + xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_alloc_size = 0U; + xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_ptr = 0U; + xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_ptr = 0U; + } +} + +/*** + * Allocate a section of PMA + * + * If the EP number has already been allocated, and the new allocation + * is larger than the old allocation, then this will fail with a TU_ASSERT. + * (This is done to simplify the code. More complicated algorithms could be used) + * + * During failure, TU_ASSERT is used. If this happens, rework/reallocate memory manually. + */ +static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + xfer_ctl_t* epXferCtl = xfer_ctl_ptr(epnum,dir); + + if(epXferCtl->pma_alloc_size != 0U) + { + //TU_LOG2("dcd_pma_alloc(%x,%x)=%x (cached)\r\n",ep_addr,length,epXferCtl->pma_ptr); + // Previously allocated + TU_ASSERT(length <= epXferCtl->pma_alloc_size, 0xFFFF); // Verify no larger than previous alloc + return epXferCtl->pma_ptr; + } + + uint16_t addr = ep_buf_ptr; + ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer + + // Verify no overflow + TU_ASSERT(ep_buf_ptr <= PMA_LENGTH, 0xFFFF); + + epXferCtl->pma_ptr = addr; + epXferCtl->pma_alloc_size = length; + //TU_LOG2("dcd_pma_alloc(%x,%x)=%x\r\n",ep_addr,length,addr); + + return addr; +} + +/*** + * Free a block of PMA space + */ +static void dcd_pma_free(uint8_t ep_addr) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + // Presently, this should never be called for EP0 IN/OUT + TU_ASSERT(open_ep_count > 2, /**/); + TU_ASSERT(xfer_ctl_ptr(epnum,dir)->max_packet_size != 0, /**/); + open_ep_count--; + + // If count is 2, only EP0 should be open, so allocations can be mostly reset. + + if(open_ep_count == 2) + { + ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT + 2*CFG_TUD_ENDPOINT0_SIZE; // 8 bytes per endpoint (two TX and two RX words, each), and EP0 + + // Skip EP0 + for(uint32_t i=1; ipma_alloc_size = 0U; + xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_alloc_size = 0U; + xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_ptr = 0U; + xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_ptr = 0U; + } + } +} + +// The STM32F0 doesn't seem to like |= or &= to manipulate the EP#R registers, +// so I'm using the #define from HAL here, instead. + +bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) +{ + (void)rhport; + uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); + uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); + const uint16_t epMaxPktSize = tu_edpt_packet_size(p_endpoint_desc); + uint16_t pma_addr; + uint32_t wType; + + // Isochronous not supported (yet), and some other driver assumptions. + TU_ASSERT(p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS); + TU_ASSERT(epnum < MAX_EP_COUNT); + + // Set type + switch(p_endpoint_desc->bmAttributes.xfer) { + case TUSB_XFER_CONTROL: + wType = USB_EP_CONTROL; + break; +#if (0) + case TUSB_XFER_ISOCHRONOUS: // FIXME: Not yet supported + wType = USB_EP_ISOCHRONOUS; + break; +#endif + + case TUSB_XFER_BULK: + wType = USB_EP_CONTROL; + break; + + case TUSB_XFER_INTERRUPT: + wType = USB_EP_INTERRUPT; + break; + + default: + TU_ASSERT(false); + } + + pcd_set_eptype(USB, epnum, wType); + pcd_set_ep_address(USB, epnum, epnum); + // Be normal, for now, instead of only accepting zero-byte packets (on control endpoint) + // or being double-buffered (bulk endpoints) + pcd_clear_ep_kind(USB,0); + + pma_addr = dcd_pma_alloc(p_endpoint_desc->bEndpointAddress, epMaxPktSize); + + if(dir == TUSB_DIR_IN) + { + *pcd_ep_tx_address_ptr(USB, epnum) = pma_addr; + pcd_set_ep_tx_cnt(USB, epnum, epMaxPktSize); + pcd_clear_tx_dtog(USB, epnum); + pcd_set_ep_tx_status(USB,epnum,USB_EP_TX_NAK); + } + else + { + *pcd_ep_rx_address_ptr(USB, epnum) = pma_addr; + pcd_set_ep_rx_cnt(USB, epnum, epMaxPktSize); + pcd_clear_rx_dtog(USB, epnum); + pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_NAK); + } + + xfer_ctl_ptr(epnum, dir)->max_packet_size = epMaxPktSize; + + return true; +} + +void dcd_edpt_close_all (uint8_t rhport) +{ + (void) rhport; + // TODO implement dcd_edpt_close_all() +} + +/** + * Close an endpoint. + * + * This function may be called with interrupts enabled or disabled. + * + * This also clears transfers in progress, should there be any. + */ +void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) +{ + (void)rhport; + uint32_t const epnum = tu_edpt_number(ep_addr); + uint32_t const dir = tu_edpt_dir(ep_addr); + + if(dir == TUSB_DIR_IN) + { + pcd_set_ep_tx_status(USB,epnum,USB_EP_TX_DIS); + } + else + { + pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_DIS); + } + + dcd_pma_free(ep_addr); +} + +// Currently, single-buffered, and only 64 bytes at a time (max) + +static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix) +{ + uint16_t len = (uint16_t)(xfer->total_len - xfer->queued_len); + + if(len > xfer->max_packet_size) // max packet size for FS transfer + { + len = xfer->max_packet_size; + } + uint16_t oldAddr = *pcd_ep_tx_address_ptr(USB,ep_ix); + +#if 0 // TODO support dcd_edpt_xfer_fifo API + if (xfer->ff) + { + dcd_write_packet_memory_ff(xfer->ff, oldAddr, len); + } + else +#endif + { + dcd_write_packet_memory(oldAddr, &(xfer->buffer[xfer->queued_len]), len); + } + xfer->queued_len = (uint16_t)(xfer->queued_len + len); + + pcd_set_ep_tx_cnt(USB,ep_ix,len); + pcd_set_ep_tx_status(USB, ep_ix, USB_EP_TX_VALID); +} + +bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir); + + xfer->buffer = buffer; + // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API + xfer->total_len = total_bytes; + xfer->queued_len = 0; + + if ( dir == TUSB_DIR_OUT ) + { + // A setup token can occur immediately after an OUT STATUS packet so make sure we have a valid + // buffer for the control endpoint. + if (epnum == 0 && buffer == NULL) + { + xfer->buffer = (uint8_t*)_setup_packet; + } + if(total_bytes > xfer->max_packet_size) + { + pcd_set_ep_rx_cnt(USB,epnum,xfer->max_packet_size); + } else { + pcd_set_ep_rx_cnt(USB,epnum,total_bytes); + } + pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_VALID); + } + else // IN + { + dcd_transmit_packet(xfer,epnum); + } + return true; +} + +#if 0 // TODO support dcd_edpt_xfer_fifo API +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir); + + xfer->buffer = NULL; + // xfer->ff = ff; // TODO support dcd_edpt_xfer_fifo API + xfer->total_len = total_bytes; + xfer->queued_len = 0; + + if ( dir == TUSB_DIR_OUT ) + { + if(total_bytes > xfer->max_packet_size) + { + pcd_set_ep_rx_cnt(USB,epnum,xfer->max_packet_size); + } else { + pcd_set_ep_rx_cnt(USB,epnum,total_bytes); + } + pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_VALID); + } + else // IN + { + dcd_transmit_packet(xfer,epnum); + } + return true; +} +#endif + +void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) +{ + (void)rhport; + + if (ep_addr & 0x80) + { // IN + pcd_set_ep_tx_status(USB, ep_addr & 0x7F, USB_EP_TX_STALL); + } + else + { // OUT + pcd_set_ep_rx_status(USB, ep_addr, USB_EP_RX_STALL); + } +} + +void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) +{ + (void)rhport; + + if (ep_addr & 0x80) + { // IN + ep_addr &= 0x7F; + + pcd_set_ep_tx_status(USB,ep_addr, USB_EP_TX_NAK); + + /* Reset to DATA0 if clearing stall condition. */ + pcd_clear_tx_dtog(USB,ep_addr); + } + else + { // OUT + /* Reset to DATA0 if clearing stall condition. */ + pcd_clear_rx_dtog(USB,ep_addr); + + pcd_set_ep_rx_status(USB,ep_addr, USB_EP_RX_NAK); + } +} + +// Packet buffer access can only be 8- or 16-bit. +/** + * @brief Copy a buffer from user memory area to packet memory area (PMA). + * This uses byte-access for user memory (so support non-aligned buffers) + * and 16-bit access for packet memory. + * @param dst, byte address in PMA; must be 16-bit aligned + * @param src pointer to user memory area. + * @param wPMABufAddr address into PMA. + * @param wNBytes no. of bytes to be copied. + * @retval None + */ +static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes) +{ + uint32_t n = ((uint32_t)wNBytes + 1U) >> 1U; + uint32_t i; + uint16_t temp1, temp2; + const uint8_t * srcVal; + + // The GCC optimizer will combine access to 32-bit sizes if we let it. Force + // it volatile so that it won't do that. + __IO uint16_t *pdwVal; + + srcVal = src; + pdwVal = &pma[PMA_STRIDE*(dst>>1)]; + + for (i = n; i != 0; i--) + { + temp1 = (uint16_t) *srcVal; + srcVal++; + temp2 = temp1 | ((uint16_t)((uint16_t) ((*srcVal) << 8U))) ; + *pdwVal = temp2; + pdwVal += PMA_STRIDE; + srcVal++; + } + return true; +} + +#if 0 // TODO support dcd_edpt_xfer_fifo API +/** + * @brief Copy from FIFO to packet memory area (PMA). + * Uses byte-access of system memory and 16-bit access of packet memory + * @param wNBytes no. of bytes to be copied. + * @retval None + */ + +// THIS FUNCTION IS UNTESTED + +static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes) +{ + // Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies + // Check for first linear part + void * src; + uint16_t len = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes); // We want to read from the FIFO - THIS FUNCTION CHANGED!!! + TU_VERIFY(len && dcd_write_packet_memory(dst, src, len)); // and write it into the PMA + tu_fifo_advance_read_pointer(ff, len); + + // Check for wrapped part + if (len < wNBytes) + { + // Get remaining wrapped length + uint16_t len2 = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes - len); + TU_VERIFY(len2); + + // Update destination pointer + dst += len; + + // Since PMA is accessed 16-bit wise we need to handle the case when a 16 bit value was split + if (len % 2) // If len is uneven there is a byte left to copy + { + // Since PMA can accessed only 16 bit-wise we copy the last byte again + tu_fifo_backward_read_pointer(ff, 1); // Move one byte back and copy two bytes for the PMA + tu_fifo_read_n(ff, (void *) &pma[PMA_STRIDE*(dst>>1)], 2); // Since EP FIFOs must be of item size 1 this is safe to do + dst++; + len2--; + } + + TU_VERIFY(dcd_write_packet_memory(dst, src, len2)); + tu_fifo_advance_write_pointer(ff, len2); + } + + return true; +} +#endif + +/** + * @brief Copy a buffer from packet memory area (PMA) to user memory area. + * Uses byte-access of system memory and 16-bit access of packet memory + * @param wNBytes no. of bytes to be copied. + * @retval None + */ +static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes) +{ + uint32_t n = (uint32_t)wNBytes >> 1U; + uint32_t i; + // The GCC optimizer will combine access to 32-bit sizes if we let it. Force + // it volatile so that it won't do that. + __IO const uint16_t *pdwVal; + uint32_t temp; + + pdwVal = &pma[PMA_STRIDE*(src>>1)]; + uint8_t *dstVal = (uint8_t*)dst; + + for (i = n; i != 0U; i--) + { + temp = *pdwVal; + pdwVal += PMA_STRIDE; + *dstVal++ = ((temp >> 0) & 0xFF); + *dstVal++ = ((temp >> 8) & 0xFF); + } + + if (wNBytes % 2) + { + temp = *pdwVal; + pdwVal += PMA_STRIDE; + *dstVal++ = ((temp >> 0) & 0xFF); + } + return true; +} + +#if 0 // TODO support dcd_edpt_xfer_fifo API +/** + * @brief Copy a buffer from user packet memory area (PMA) to FIFO. + * Uses byte-access of system memory and 16-bit access of packet memory + * @param wNBytes no. of bytes to be copied. + * @retval None + */ + +// THIS FUNCTION IS UNTESTED + +static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes) +{ + // Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies + // Check for first linear part + void * dst; + uint16_t len = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes); // THIS FUNCTION CHANGED!!!! + TU_VERIFY(len && dcd_read_packet_memory(dst, src, len)); + tu_fifo_advance_write_pointer(ff, len); + + // Check for wrapped part + if (len < wNBytes) + { + // Get remaining wrapped length + uint16_t len2 = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes - len); + TU_VERIFY(len2); + + // Update source pointer + src += len; + + // Since PMA is accessed 16-bit wise we need to handle the case when a 16 bit value was split + if (len % 2) // If len is uneven there is a byte left to copy + { + uint32_t temp = pma[PMA_STRIDE*(src>>1)]; + *((uint8_t *)dst++) = ((temp >> 8) & 0xFF); + src++; + len2--; + } + + TU_VERIFY(dcd_read_packet_memory(dst, src, len2)); + tu_fifo_advance_write_pointer(ff, len2); + } + + return true; +} + +#endif + +#endif + diff --git a/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h b/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h new file mode 100644 index 00000000..bffae450 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h @@ -0,0 +1,422 @@ +/** + ****************************************************************************** + * @file dcd_stm32f0_pvt_st.h + * @brief DCD utilities from ST code + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ *

© parts COPYRIGHT(c) N Conrad

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********/ + +// This file contains source copied from ST's HAL, and thus should have their copyright statement. + +// PMA_LENGTH is PMA buffer size in bytes. +// On 512-byte devices, access with a stride of two words (use every other 16-bit address) +// On 1024-byte devices, access with a stride of one word (use every 16-bit address) + +#ifndef PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ +#define PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ + +#if defined(STM32F042x6) || \ + defined(STM32F070x6) || defined(STM32F070xB) || \ + defined(STM32F072xB) || \ + defined(STM32F078xx) + #include "stm32f0xx.h" + #define PMA_LENGTH (1024u) + // F0x2 models are crystal-less + // All have internal D+ pull-up + // 070RB: 2 x 16 bits/word memory LPM Support, BCD Support + // PMA dedicated to USB (no sharing with CAN) + +#elif defined(STM32F1_FSDEV) + #include "stm32f1xx.h" + #define PMA_LENGTH (512u) + // NO internal Pull-ups + // *B, and *C: 2 x 16 bits/word + + // F1 names this differently from the rest + #define USB_CNTR_LPMODE USB_CNTR_LP_MODE + +#elif defined(STM32F302xB) || defined(STM32F302xC) || \ + defined(STM32F303xB) || defined(STM32F303xC) || \ + defined(STM32F373xC) + #include "stm32f3xx.h" + #define PMA_LENGTH (512u) + // NO internal Pull-ups + // *B, and *C: 1 x 16 bits/word + // PMA dedicated to USB (no sharing with CAN) + +#elif defined(STM32F302x6) || defined(STM32F302x8) || \ + defined(STM32F302xD) || defined(STM32F302xE) || \ + defined(STM32F303xD) || defined(STM32F303xE) + #include "stm32f3xx.h" + #define PMA_LENGTH (1024u) + // NO internal Pull-ups + // *6, *8, *D, and *E: 2 x 16 bits/word LPM Support + // When CAN clock is enabled, USB can use first 768 bytes ONLY. + +#elif CFG_TUSB_MCU == OPT_MCU_STM32L0 + #include "stm32l0xx.h" + #define PMA_LENGTH (1024u) + +#elif CFG_TUSB_MCU == OPT_MCU_STM32L1 + #include "stm32l1xx.h" + #define PMA_LENGTH (512u) + +#elif CFG_TUSB_MCU == OPT_MCU_STM32G4 + #include "stm32g4xx.h" + #define PMA_LENGTH (1024u) + +#elif CFG_TUSB_MCU == OPT_MCU_STM32WB + #include "stm32wbxx.h" + #define PMA_LENGTH (1024u) + /* ST provided header has incorrect value */ + #undef USB_PMAADDR + #define USB_PMAADDR USB1_PMAADDR + +#else + #error You are using an untested or unimplemented STM32 variant. Please update the driver. + // This includes L1x0, L1x1, L1x2, L4x2 and L4x3, G1x1, G1x3, and G1x4 +#endif + +// For purposes of accessing the packet +#if ((PMA_LENGTH) == 512u) + #define PMA_STRIDE (2u) +#elif ((PMA_LENGTH) == 1024u) + #define PMA_STRIDE (1u) +#endif + +// And for type-safety create a new macro for the volatile address of PMAADDR +// The compiler should warn us if we cast it to a non-volatile type? +// Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden) +static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR; + +// prototypes +static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum); +static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum); +static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wRegValue); + + +/* SetENDPOINT */ +static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wRegValue) +{ + __O uint16_t *reg = (__O uint16_t *)((&USBx->EP0R) + bEpNum*2u); + *reg = (uint16_t)wRegValue; +} + +/* GetENDPOINT */ +static inline uint16_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpNum) { + __I uint16_t *reg = (__I uint16_t *)((&USBx->EP0R) + bEpNum*2u); + return *reg; +} + +static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wType) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= (uint32_t)USB_EP_T_MASK; + regVal |= wType; + regVal |= USB_EP_CTR_RX | USB_EP_CTR_TX; // These clear on write0, so must set high + pcd_set_endpoint(USBx, bEpNum, regVal); +} + +static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EP_T_FIELD; + return regVal; +} +/** + * @brief Clears bit CTR_RX / CTR_TX in the endpoint register. + * @param USBx USB peripheral instance register address. + * @param bEpNum Endpoint Number. + * @retval None + */ +static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EPREG_MASK; + regVal &= ~USB_EP_CTR_RX; + regVal |= USB_EP_CTR_TX; // preserve CTR_TX (clears on writing 0) + pcd_set_endpoint(USBx, bEpNum, regVal); +} +static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EPREG_MASK; + regVal &= ~USB_EP_CTR_TX; + regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0) + pcd_set_endpoint(USBx, bEpNum,regVal); +} +/** + * @brief gets counter of the tx buffer. + * @param USBx USB peripheral instance register address. + * @param bEpNum Endpoint Number. + * @retval Counter value + */ +static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpNum) +{ + __I uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpNum); + return *regPtr & 0x3ffU; +} + +static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpNum) +{ + __I uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpNum); + return *regPtr & 0x3ffU; +} + +/** + * @brief Sets counter of rx buffer with no. of blocks. + * @param dwReg Register + * @param wCount Counter. + * @param wNBlocks no. of Blocks. + * @retval None + */ + +static inline void pcd_set_ep_cnt_rx_reg(__O uint16_t * pdwReg, size_t wCount) { + uint32_t wNBlocks; + if(wCount > 62u) + { + wNBlocks = wCount >> 5u; + if((wCount & 0x1fU) == 0u) + { + wNBlocks--; + } + wNBlocks = wNBlocks << 10u; + wNBlocks |= 0x8000u; // Mark block size as 32byte + *pdwReg = (uint16_t)wNBlocks; + } + else + { + wNBlocks = wCount >> 1u; + if((wCount & 0x1U) != 0u) + { + wNBlocks++; + } + *pdwReg = (uint16_t)((wNBlocks) << 10u); + } +} + + +/** + * @brief Sets address in an endpoint register. + * @param USBx USB peripheral instance register address. + * @param bEpNum Endpoint Number. + * @param bAddr Address. + * @retval None + */ +static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t bAddr) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EPREG_MASK; + regVal |= bAddr; + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; + pcd_set_endpoint(USBx, bEpNum,regVal); +} + +static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) +{ + size_t total_word_offset = (((USBx)->BTABLE)>>1) + x; + total_word_offset *= PMA_STRIDE; + return &(pma[total_word_offset]); +} + +// Pointers to the PMA table entries (using the ARM address space) +static inline __IO uint16_t* pcd_ep_tx_address_ptr(USB_TypeDef * USBx, uint32_t bEpNum) +{ + return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 0u); +} +static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum) +{ + return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 1u); +} + +static inline __IO uint16_t* pcd_ep_rx_address_ptr(USB_TypeDef * USBx, uint32_t bEpNum) +{ + return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 2u); +} + +static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum) +{ + return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 3u); +} + +static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wCount) +{ + *pcd_ep_tx_cnt_ptr(USBx, bEpNum) = (uint16_t)wCount; +} + +static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wCount) +{ + __IO uint16_t *pdwReg = pcd_ep_rx_cnt_ptr((USBx),(bEpNum)); + pcd_set_ep_cnt_rx_reg(pdwReg, wCount); +} + +/** + * @brief sets the status for tx transfer (bits STAT_TX[1:0]). + * @param USBx USB peripheral instance register address. + * @param bEpNum Endpoint Number. + * @param wState new state + * @retval None + */ +static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wState) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EPTX_DTOGMASK; + + /* toggle first bit ? */ + if((USB_EPTX_DTOG1 & (wState))!= 0U) + { + regVal ^= USB_EPTX_DTOG1; + } + /* toggle second bit ? */ + if((USB_EPTX_DTOG2 & ((uint32_t)(wState)))!= 0U) + { + regVal ^= USB_EPTX_DTOG2; + } + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; + pcd_set_endpoint(USBx, bEpNum, regVal); +} /* pcd_set_ep_tx_status */ + +/** + * @brief sets the status for rx transfer (bits STAT_TX[1:0]) + * @param USBx USB peripheral instance register address. + * @param bEpNum Endpoint Number. + * @param wState new state + * @retval None + */ + +static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wState) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EPRX_DTOGMASK; + + /* toggle first bit ? */ + if((USB_EPRX_DTOG1 & wState)!= 0U) + { + regVal ^= USB_EPRX_DTOG1; + } + /* toggle second bit ? */ + if((USB_EPRX_DTOG2 & wState)!= 0U) + { + regVal ^= USB_EPRX_DTOG2; + } + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; + pcd_set_endpoint(USBx, bEpNum, regVal); +} /* pcd_set_ep_rx_status */ + +static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + return (regVal & USB_EPRX_STAT) >> (12u); +} /* pcd_get_ep_rx_status */ + + +/** + * @brief Toggles DTOG_RX / DTOG_TX bit in the endpoint register. + * @param USBx USB peripheral instance register address. + * @param bEpNum Endpoint Number. + * @retval None + */ +static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EPREG_MASK; + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_RX; + pcd_set_endpoint(USBx, bEpNum, regVal); +} + +static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EPREG_MASK; + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_TX; + pcd_set_endpoint(USBx, bEpNum, regVal); +} + +/** + * @brief Clears DTOG_RX / DTOG_TX bit in the endpoint register. + * @param USBx USB peripheral instance register address. + * @param bEpNum Endpoint Number. + * @retval None + */ + +static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + if((regVal & USB_EP_DTOG_RX) != 0) + { + pcd_rx_dtog(USBx,bEpNum); + } +} + +static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + if((regVal & USB_EP_DTOG_TX) != 0) + { + pcd_tx_dtog(USBx,bEpNum); + } +} + +/** + * @brief set & clear EP_KIND bit. + * @param USBx USB peripheral instance register address. + * @param bEpNum Endpoint Number. + * @retval None + */ + +static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal |= USB_EP_KIND; + regVal &= USB_EPREG_MASK; + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; + pcd_set_endpoint(USBx, bEpNum, regVal); +} +static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EPKIND_MASK; + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; + pcd_set_endpoint(USBx, bEpNum, regVal); +} + +// This checks if the device has "LPM" +#if defined(USB_ISTR_L1REQ) +#define USB_ISTR_L1REQ_FORCED (USB_ISTR_L1REQ) +#else +#define USB_ISTR_L1REQ_FORCED ((uint16_t)0x0000U) +#endif + +#define USB_ISTR_ALL_EVENTS (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_WKUP | USB_ISTR_SUSP | \ + USB_ISTR_RESET | USB_ISTR_SOF | USB_ISTR_ESOF | USB_ISTR_L1REQ_FORCED ) + +// Number of endpoints in hardware +#define STFSDEV_EP_COUNT (8u) + +#endif /* PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/tusb.c b/test-devices/composite-stm32/lib/tinyusb/tusb.c new file mode 100644 index 00000000..c3787ff8 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/tusb.c @@ -0,0 +1,314 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUH_ENABLED || CFG_TUD_ENABLED + +#include "tusb.h" +#include "common/tusb_private.h" + +// TODO clean up +#if CFG_TUD_ENABLED +#include "device/usbd_pvt.h" +#endif + +bool tusb_init(void) +{ +#if CFG_TUD_ENABLED && defined(TUD_OPT_RHPORT) + // init device stack CFG_TUSB_RHPORTx_MODE must be defined + TU_ASSERT ( tud_init(TUD_OPT_RHPORT) ); +#endif + +#if CFG_TUH_ENABLED && defined(TUH_OPT_RHPORT) + // init host stack CFG_TUSB_RHPORTx_MODE must be defined + TU_ASSERT( tuh_init(TUH_OPT_RHPORT) ); +#endif + + return true; +} + +bool tusb_inited(void) +{ + bool ret = false; + +#if CFG_TUD_ENABLED + ret = ret || tud_inited(); +#endif + +#if CFG_TUH_ENABLED + ret = ret || tuh_inited(); +#endif + + return ret; +} + +//--------------------------------------------------------------------+ +// Internal Helper for both Host and Device stack +//--------------------------------------------------------------------+ + +bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex) +{ + (void) mutex; + +#if TUSB_OPT_MUTEX + // pre-check to help reducing mutex lock + TU_VERIFY((ep_state->busy == 0) && (ep_state->claimed == 0)); + osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); +#endif + + // can only claim the endpoint if it is not busy and not claimed yet. + bool const available = (ep_state->busy == 0) && (ep_state->claimed == 0); + if (available) + { + ep_state->claimed = 1; + } + +#if TUSB_OPT_MUTEX + osal_mutex_unlock(mutex); +#endif + + return available; +} + +bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex) +{ + (void) mutex; + +#if TUSB_OPT_MUTEX + osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); +#endif + + // can only release the endpoint if it is claimed and not busy + bool const ret = (ep_state->claimed == 1) && (ep_state->busy == 0); + if (ret) + { + ep_state->claimed = 0; + } + +#if TUSB_OPT_MUTEX + osal_mutex_unlock(mutex); +#endif + + return ret; +} + +bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed) +{ + uint16_t const max_packet_size = tu_edpt_packet_size(desc_ep); + TU_LOG2(" Open EP %02X with Size = %u\r\n", desc_ep->bEndpointAddress, max_packet_size); + + switch (desc_ep->bmAttributes.xfer) + { + case TUSB_XFER_ISOCHRONOUS: + { + uint16_t const spec_size = (speed == TUSB_SPEED_HIGH ? 1024 : 1023); + TU_ASSERT(max_packet_size <= spec_size); + } + break; + + case TUSB_XFER_BULK: + if (speed == TUSB_SPEED_HIGH) + { + // Bulk highspeed must be EXACTLY 512 + TU_ASSERT(max_packet_size == 512); + }else + { + // TODO Bulk fullspeed can only be 8, 16, 32, 64 + TU_ASSERT(max_packet_size <= 64); + } + break; + + case TUSB_XFER_INTERRUPT: + { + uint16_t const spec_size = (speed == TUSB_SPEED_HIGH ? 1024 : 64); + TU_ASSERT(max_packet_size <= spec_size); + } + break; + + default: return false; + } + + return true; +} + +void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* desc_itf, uint16_t desc_len, uint8_t driver_id) +{ + uint8_t const* p_desc = (uint8_t const*) desc_itf; + uint8_t const* desc_end = p_desc + desc_len; + + while( p_desc < desc_end ) + { + if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + { + uint8_t const ep_addr = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress; + + TU_LOG(2, " Bind EP %02x to driver id %u\r\n", ep_addr, driver_id); + ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)] = driver_id; + } + + p_desc = tu_desc_next(p_desc); + } +} + +uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len) +{ + uint8_t const* p_desc = (uint8_t const*) desc_itf; + uint16_t len = 0; + + while (itf_count--) + { + // Next on interface desc + len += tu_desc_len(desc_itf); + p_desc = tu_desc_next(p_desc); + + while (len < max_len) + { + // return on IAD regardless of itf count + if ( tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION ) return len; + + if ( (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) && + ((tusb_desc_interface_t const*) p_desc)->bAlternateSetting == 0 ) + { + break; + } + + len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + } + + return len; +} + +/*------------------------------------------------------------------*/ +/* Debug + *------------------------------------------------------------------*/ +#if CFG_TUSB_DEBUG +#include + +#if CFG_TUSB_DEBUG >= 2 + +char const* const tu_str_speed[] = { "Full", "Low", "High" }; +char const* const tu_str_std_request[] = +{ + "Get Status" , + "Clear Feature" , + "Reserved" , + "Set Feature" , + "Reserved" , + "Set Address" , + "Get Descriptor" , + "Set Descriptor" , + "Get Configuration" , + "Set Configuration" , + "Get Interface" , + "Set Interface" , + "Synch Frame" +}; + +#endif + +static void dump_str_line(uint8_t const* buf, uint16_t count) +{ + tu_printf(" |"); + + // each line is 16 bytes + for(uint16_t i=0; i 64 + #error Control Endpoint Max Packet Size cannot be larger than 64 +#endif + +#endif /* _TUSB_OPTION_H_ */ + +/** @} */ diff --git a/test-devices/composite-stm32/platformio.ini b/test-devices/composite-stm32/platformio.ini index 7d74ce50..d0c31313 100644 --- a/test-devices/composite-stm32/platformio.ini +++ b/test-devices/composite-stm32/platformio.ini @@ -1,4 +1,31 @@ -[env:composite-stm32] +[common] +tinyusb_flags = + -D CFG_TUD_CDC=1 + -D CFG_VENDOR_ADVANCED=1 + -D CFG_TUSB_RHPORT1_MODE=OPT_MODE_NONE platform = ststm32 +framework = cmsis +debug_tool = stlink + +[env:blackpill-f401cc] +extends = common +board = blackpill_f401cc +build_flags = + ${common.tinyusb_flags} + -D CFG_TUSB_MCU=OPT_MCU_STM32F4 + -D HSE_VALUE=25000000 + +[env:blackpill-f411ce] +extends = common +board = blackpill_f411ce +build_flags = + ${common.tinyusb_flags} + -D CFG_TUSB_MCU=OPT_MCU_STM32F4 + -D HSE_VALUE=25000000 + +[env:bluepill-f103c8] +extends = common board = bluepill_f103c8 -framework = libopencm3 +build_flags = + ${common.tinyusb_flags} + -D CFG_TUSB_MCU=OPT_MCU_STM32F1 diff --git a/test-devices/composite-stm32/save_firmware.sh b/test-devices/composite-stm32/save_firmware.sh new file mode 100755 index 00000000..303a542a --- /dev/null +++ b/test-devices/composite-stm32/save_firmware.sh @@ -0,0 +1,6 @@ +#!/bin/sh +rm -rf .pio +pio run +cp .pio/build/bluepill-f103c8/firmware.bin bin/bluepill-f103c8.bin +cp .pio/build/blackpill-f401cc/firmware.bin bin/blackpill-f401cc.bin +cp .pio/build/blackpill-f411ce/firmware.bin bin/blackpill-f411ce.bin diff --git a/test-devices/composite-stm32/src/board_f1.c b/test-devices/composite-stm32/src/board_f1.c new file mode 100644 index 00000000..e3dc0eb5 --- /dev/null +++ b/test-devices/composite-stm32/src/board_f1.c @@ -0,0 +1,215 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Board specific code for STM32F1 family +// + +#if defined(STM32F1) + +#include +#include "stm32f1xx.h" +#include "device/usbd.h" + + +extern uint32_t SystemCoreClock; +void SystemCoreClockUpdate(void); + + +static inline uint32_t get_reg(__I uint32_t* reg, uint32_t mask) { + return *reg & mask; +} + +static inline void set_reg(__IO uint32_t* reg, uint32_t value, uint32_t mask) { + *reg = (*reg & ~mask) | (value & mask); +} + + +// --- additional RCC constants + +#define RCC_CFGR_PLLSRC_HSI (0 << RCC_CFGR_PLLSRC_Pos) +#define RCC_CFGR_PLLSRC_HSE (1 << RCC_CFGR_PLLSRC_Pos) + +// --- additional SysTick constants + +#define SysTick_CTRL_CLKSOURCE_AHB_DIV8 (0 << SysTick_CTRL_CLKSOURCE_Pos) +#define SysTick_CTRL_CLKSOURCE_AHB (1 << SysTick_CTRL_CLKSOURCE_Pos) + +// --- additional GPIO constants + +#define GPIO_CNF_INPUT_ANALOG 0 +#define GPIO_CNF_INPUT_FLOAT 1 +#define GPIO_CNF_INPUT_PUPD 2 +#define GPIO_CNF_OUTPUT_PUSH_PULL 0 +#define GPIO_CNF_OUTPUT_OPEN_DRAIN 1 +#define GPIO_CNF_OUTPUT_ALT_PUSH_PULL 2 +#define GPIO_CNG_OUTPUT_ALT_OPEN_DRAIN 3 + +#define GPIO_MODE_INPUT 0 +#define GPIO_MODE_OUTPUT_10_MHZ 1 +#define GPIO_MODE_OUTPUT_2_MHZ 2 +#define GPIO_MODE_OUTPUT_50_MHZ 3 + + +static inline void rcc_wait_for_osc_ready(uint32_t rcc_cr_clk_rdy) { + while (get_reg(&RCC->CR, rcc_cr_clk_rdy) == 0) + ; +} + + +static void gpio_set_mode(GPIO_TypeDef* gpioport, int gpio, uint8_t mode, uint8_t cnf) { + + int offset; + __IO uint32_t* reg; + if (gpio < 8) { + offset = 4 * gpio; + reg = &gpioport->CRL; + } else { + offset = 4 * (gpio - 8); + reg = &gpioport->CRH; + } + + set_reg(reg, ((cnf << 2) | mode) << offset, 0xf << offset); +} + +static inline void gpio_set(GPIO_TypeDef* gpioport, int gpio) { + gpioport->BSRR = 1 << gpio; +} + +static inline void gpio_clear(GPIO_TypeDef* gpioport, int gpio) { + gpioport->BSRR = 1 << (gpio + 16); +} + + +static void rcc_clock_setup_in_hse_8mhz_out_72mhz(void) { + + // Enable internal high-speed oscillator + set_reg(&RCC->CR, RCC_CR_HSION, RCC_CR_HSION_Msk); + rcc_wait_for_osc_ready(RCC_CR_HSIRDY); + + // Select HSI as SYSCLK source + set_reg(&RCC->CFGR, RCC_CFGR_SW_HSI, RCC_CFGR_SW_Msk); + + // Enable external high-speed oscillator 8MHz + set_reg(&RCC->CR, RCC_CR_HSEON, RCC_CR_HSEON_Msk); + rcc_wait_for_osc_ready(RCC_CR_HSERDY); + set_reg(&RCC->CFGR, RCC_CFGR_SW_HSE, RCC_CFGR_SW_Msk); + + // Set prescalers for AHB, ADC, APB1, APB2 + set_reg(&RCC->CFGR, RCC_CFGR_HPRE_DIV1 | RCC_CFGR_ADCPRE_DIV8 | RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_PPRE2_DIV1, + RCC_CFGR_HPRE_Msk | RCC_CFGR_ADCPRE_Msk | RCC_CFGR_PPRE1_Msk | RCC_CFGR_PPRE2_Msk); + + // System clock of 72 MHz requires 2 wait states + set_reg(&FLASH->ACR, FLASH_ACR_LATENCY_2, FLASH_ACR_LATENCY_Msk); + + // PLL multiplier 9 (for 72 MHz), HSE as PLL source, no clock predevision + set_reg(&RCC->CFGR, RCC_CFGR_PLLMULL9 | RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLXTPRE_HSE, + RCC_CFGR_PLLMULL_Msk | RCC_CFGR_PLLSRC_Msk | RCC_CFGR_PLLXTPRE_Msk); + + // Enable PLL oscillator and wait for it to stabilize + set_reg(&RCC->CR, RCC_CR_PLLON, RCC_CR_PLLON_Msk); + rcc_wait_for_osc_ready(RCC_CR_PLLRDY); + + // Select PLL as SYSCLK source + set_reg(&RCC->CFGR, RCC_CFGR_SW_PLL, RCC_CFGR_SW_Msk); + + // Update the SystemCoreClock variable used by TinyUSB + SystemCoreClockUpdate(); +} + +static volatile uint32_t millis_count; + +static void systick_init(void) { + + // Initialize SysTick + set_reg(&SysTick->CTRL, SysTick_CTRL_CLKSOURCE_AHB_DIV8, SysTick_CTRL_CLKSOURCE_Msk); + SysTick->LOAD = SystemCoreClock / 8 / 1000 - 1; + + // Enable and start + set_reg(&SysTick->CTRL, SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk, + SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk); +} + + +// --- Serial number --- + +char board_serial_num[13]; + +const static char HEX_DIGITS[] = "0123456789ABCDEF"; + +void put_hex(uint32_t value, char *buf, int len) { + for (int idx = 0; idx < len; idx++) { + buf[idx] = HEX_DIGITS[value >> 28]; + value = value << 4; + } +} + +void usb_init_serial_num() { + __I uint32_t* unique_id =(__I uint32_t*) UID_BASE; + uint32_t id0 = unique_id[0]; + uint32_t id1 = unique_id[1]; + uint32_t id2 = unique_id[2]; + + id0 += id2; + + put_hex(id0, board_serial_num, 8); + put_hex(id1, board_serial_num + 8, 4); + board_serial_num[12] = 0; +} + + +// --- Exported board functions + +void board_init(void) { + + rcc_clock_setup_in_hse_8mhz_out_72mhz(); + systick_init(); + + // clock for GPIOA (USB pins) + RCC->APB2ENR |= RCC_APB2ENR_IOPAEN_Msk; + // clock for GPIOB (LED) + RCC->APB2ENR |= RCC_APB2ENR_IOPBEN_Msk; + // clock for USB + RCC->APB1ENR |= RCC_APB1ENR_USBEN_Msk; + + // LED + gpio_set_mode(GPIOB, 12, GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSH_PULL); + + usb_init_serial_num(); +} + +uint32_t board_millis(void) { + return millis_count; +} + +void board_led_write(bool on) { + if (on) + gpio_set(GPIOB, 12); + else + gpio_clear(GPIOB, 12); +} + + +// --- Interrupt handlers --- + +void SysTick_Handler (void) { + millis_count++; +} + +void USBWakeUp_IRQHandler(void) { + tud_int_handler(0); +} + +void USB_HP_IRQHandler(void) { + tud_int_handler(0); +} + +void USB_LP_IRQHandler(void) { + tud_int_handler(0); +} + +#endif diff --git a/test-devices/composite-stm32/src/board_f4.c b/test-devices/composite-stm32/src/board_f4.c new file mode 100644 index 00000000..6f83803f --- /dev/null +++ b/test-devices/composite-stm32/src/board_f4.c @@ -0,0 +1,281 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Board specific code for STM32F4 family +// + +#if defined(STM32F4xx) + +#include +#include "stm32f4xx.h" +#include "device/usbd.h" + +extern uint32_t SystemCoreClock; +void SystemCoreClockUpdate(void); + + +static inline uint32_t get_reg(__I uint32_t* reg, uint32_t mask) { + return *reg & mask; +} + +static inline void set_reg(__IO uint32_t* reg, uint32_t value, uint32_t mask) { + *reg = (*reg & ~mask) | (value & mask); +} + + +// --- additional PWR constants + +#define PWR_CR_VOS_SCALE3 (1 << PWR_CR_VOS_Pos) +#define PWR_CR_VOS_SCALE2 (2 << PWR_CR_VOS_Pos) +#define PWR_CR_VOS_SCALE1 (3 << PWR_CR_VOS_Pos) + + +// --- additional RCC constants + +typedef struct rcc_clock_setup { + uint8_t pllm; + uint16_t plln; + uint8_t pllp; + uint8_t pllq; + uint32_t pll_source; + uint32_t flash_config; + uint32_t hpre; + uint32_t ppre1; + uint32_t ppre2; + uint32_t voltage_scale; +} rcc_clock_setup_t; + +const rcc_clock_setup_t clock_setup_hse_value_out_84mhz_3v3 = { + .pllm = HSE_VALUE / 1000000, + .plln = 336, + .pllp = 4, + .pllq = 7, + .pll_source = RCC_PLLCFGR_PLLSRC_HSE, + .hpre = RCC_CFGR_HPRE_DIV1, + .ppre1 = RCC_CFGR_PPRE1_DIV2, + .ppre2 = RCC_CFGR_PPRE2_DIV1, + .voltage_scale = PWR_CR_VOS_SCALE1, + .flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_2WS +}; + +// --- additional SysTick constants + +#define SysTick_CTRL_CLKSOURCE_AHB_DIV8 (0 << SysTick_CTRL_CLKSOURCE_Pos) +#define SysTick_CTRL_CLKSOURCE_AHB (1 << SysTick_CTRL_CLKSOURCE_Pos) + +// --- additional GPIO constants + +#define GPIO_PUPD_NO_PULL 0 +#define GPIO_PUPD_PULL_UP 1 +#define GPIO_PUPD_PULL_DOWN 2 + +#define GPIO_MODE_INPUT 0 +#define GPIO_MODE_OUTPUT 1 +#define GPIO_MODE_ALT 2 +#define GPIO_MODE_ANALOG 3 + +#define GPIO_OSPEED_LOW 0 +#define GPIO_OSPEED_MEDIUM 1 +#define GPIO_OSPEED_FAST 2 +#define GPIO_OSPEED_HIGH 3 + + +static inline void rcc_wait_for_osc_ready(uint32_t rcc_cr_clk_rdy) { + while (get_reg(&RCC->CR, rcc_cr_clk_rdy) == 0) + ; +} + +static void gpio_mode_setup(GPIO_TypeDef* gpioport, int gpio, uint8_t mode, uint8_t pull_up_down) { + + int offset = gpio * 2; + set_reg(&gpioport->PUPDR, pull_up_down << offset, 3 << offset); + set_reg(&gpioport->MODER, mode << offset, 3 << offset); +} + +void gpio_set_af(GPIO_TypeDef* gpioport, int gpio, uint8_t alt_func_num) { + + int offset = 4 * gpio; + __IO uint32_t* reg; + if (offset < 32) { + reg = gpioport->AFR; + } else { + reg = gpioport->AFR + 1; + offset -= 32; + } + + set_reg(reg, alt_func_num << offset, 0xf << offset); +} + +static inline void gpio_set_ospeed(GPIO_TypeDef* gpioport, int gpio, uint8_t ospeed) { + int offset = gpio * 2; + set_reg(&gpioport->OSPEEDR, ospeed << offset, 3 << offset); +} + +static inline void gpio_set(GPIO_TypeDef* gpioport, int gpio) { + gpioport->BSRR = 1 << gpio; +} + +static inline void gpio_clear(GPIO_TypeDef* gpioport, int gpio) { + gpioport->BSRR = 1 << (gpio + 16); +} + + +static void rcc_clock_setup_pll(const rcc_clock_setup_t* setup) { + + // Enable internal high-speed oscillator (HSI) + set_reg(&RCC->CR, RCC_CR_HSION, RCC_CR_HSION_Msk); + rcc_wait_for_osc_ready(RCC_CR_HSIRDY); + + // Select HSI as SYSCLK source + set_reg(&RCC->CFGR, RCC_CFGR_SW_HSI, RCC_CFGR_SW_Msk); + + // Enable external high-speed oscillator (HSE) + if (setup->pll_source == RCC_PLLCFGR_PLLSRC_HSE) { + set_reg(&RCC->CR, RCC_CR_HSEON, RCC_CR_HSEON_Msk); + rcc_wait_for_osc_ready(RCC_CR_HSERDY); + } + + // Set the VOS scale mode + set_reg(&RCC->APB1ENR, RCC_APB1ENR_PWREN, RCC_APB1ENR_PWREN_Msk); + set_reg(&PWR->CR, setup->voltage_scale, PWR_CR_VOS_Msk); + + // Set prescalers for AHB, APB1, APB2 + set_reg(&RCC->CFGR, setup->hpre | setup->ppre1 | setup->ppre2, + RCC_CFGR_HPRE_Msk | RCC_CFGR_PPRE1_Msk | RCC_CFGR_PPRE2_Msk); + + // Disable PLL oscillator before changing its configuration + set_reg(&RCC->CR, 0, RCC_CR_PLLON_Msk); + + // Configure the PLL oscillator + int pllp_val = (setup->pllp >> 1) - 1; + RCC->PLLCFGR = setup->pll_source + | (setup->pllm << RCC_PLLCFGR_PLLM_Pos) + | (setup->plln << RCC_PLLCFGR_PLLN_Pos) + | (pllp_val << RCC_PLLCFGR_PLLP_Pos) + | (setup->pllq << RCC_PLLCFGR_PLLQ_Pos); + + // Enable PLL oscillator and wait for it to stabilize + set_reg(&RCC->CR, RCC_CR_PLLON, RCC_CR_PLLON_Msk); + rcc_wait_for_osc_ready(RCC_CR_PLLRDY); + + // Configure flash settings + set_reg(&FLASH->ACR, setup->flash_config, FLASH_ACR_DCEN_Msk | FLASH_ACR_ICEN_Msk | FLASH_ACR_LATENCY_Msk); + + // Select PLL as SYSCLK source + set_reg(&RCC->CFGR, RCC_CFGR_SW_PLL, RCC_CFGR_SW_Msk); + + // Wait for PLL clock to be selected + while (get_reg(&RCC->CFGR, RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL) + ; + + // Disable internal high-speed oscillator + if (setup->pll_source == RCC_PLLCFGR_PLLSRC_HSE) + set_reg(&RCC->CR, 0, RCC_CR_HSION_Msk); + + // Update the SystemCoreClock variable used by TinyUSB + SystemCoreClockUpdate(); +} + +static volatile uint32_t millis_count; + +static void systick_init(void) { + + // Initialize SysTick + SysTick->CTRL = (SysTick->CTRL & ~SysTick_CTRL_CLKSOURCE_Msk) | SysTick_CTRL_CLKSOURCE_AHB_DIV8; + SysTick->LOAD = SystemCoreClock / 8 / 1000 - 1; + + // Enable and start + SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; + SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; +} + + +// --- Serial number --- + +char board_serial_num[13]; + +const static char HEX_DIGITS[] = "0123456789ABCDEF"; + +static void put_hex(uint32_t value, char *buf, int len) { + for (int idx = 0; idx < len; idx++) { + buf[idx] = HEX_DIGITS[value >> 28]; + value = value << 4; + } +} + +static void usb_init_serial_num() { + __I uint32_t* unique_id =(__I uint32_t*) UID_BASE; + uint32_t id0 = unique_id[0]; + uint32_t id1 = unique_id[1]; + uint32_t id2 = unique_id[2]; + + id0 += id2; + + put_hex(id0, board_serial_num, 8); + put_hex(id1, board_serial_num + 8, 4); + board_serial_num[12] = 0; +} + + +// --- Exported board functions + +void board_init(void) { + + rcc_clock_setup_pll(&clock_setup_hse_value_out_84mhz_3v3); + systick_init(); + + // clock for GPIOA (USB pins) + set_reg(&RCC->AHB1ENR, RCC_AHB1ENR_GPIOAEN, RCC_AHB1ENR_GPIOAEN_Msk); + + // Configure USB D+/D- pins + gpio_mode_setup(GPIOA, 11, GPIO_MODE_ALT, GPIO_PUPD_NO_PULL); + gpio_set_af(GPIOA, 11, 10); + gpio_set_ospeed(GPIOA, 11, GPIO_OSPEED_HIGH); + gpio_mode_setup(GPIOA, 12, GPIO_MODE_ALT, GPIO_PUPD_NO_PULL); + gpio_set_af(GPIOA, 12, 10); + gpio_set_ospeed(GPIOA, 12, GPIO_OSPEED_HIGH); + + // clock for USB + set_reg(&RCC->AHB2ENR, RCC_AHB2ENR_OTGFSEN, RCC_AHB2ENR_OTGFSEN_Msk); + + // Disable VBUS sense + set_reg(&USB_OTG_FS->GCCFG, USB_OTG_GCCFG_NOVBUSSENS, + USB_OTG_GCCFG_NOVBUSSENS_Msk | USB_OTG_GCCFG_VBUSASEN_Msk | USB_OTG_GCCFG_VBUSBSEN_Msk); + + // clock for GPIOC (LED) + set_reg(&RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN, RCC_AHB1ENR_GPIOCEN_Msk); + + // LED pin + gpio_mode_setup(GPIOC, 13, GPIO_MODE_OUTPUT, GPIO_PUPD_NO_PULL); + + usb_init_serial_num(); +} + +uint32_t board_millis(void) { + return millis_count; +} + +void board_led_write(bool on) { + if (on) + gpio_set(GPIOC, 13); + else + gpio_clear(GPIOC, 13); +} + + +// --- Interrupt handlers --- + +void SysTick_Handler (void) { + millis_count++; +} + +void OTG_FS_IRQHandler(void) { + tud_int_handler(0); +} + +#endif diff --git a/test-devices/composite-stm32/src/common.cpp b/test-devices/composite-stm32/src/common.cpp deleted file mode 100644 index 5102b6bd..00000000 --- a/test-devices/composite-stm32/src/common.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Commmon functions -// - -#include "common.h" - -#include - -static volatile uint32_t millis_count; - -uint32_t millis() { return millis_count; } - -void delay(uint32_t ms) { - int32_t target_time = millis_count + ms; - while (target_time - (int32_t)millis_count > 0) - ; -} - -void systick_init() { - // Initialize SysTick - systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); - systick_set_reload(rcc_ahb_frequency / 8 / 1000 - 1); - - // Enable and start - systick_interrupt_enable(); - systick_counter_enable(); -} - -// System tick timer interrupt handler -extern "C" void sys_tick_handler() { millis_count++; } diff --git a/test-devices/composite-stm32/src/main.c b/test-devices/composite-stm32/src/main.c new file mode 100644 index 00000000..050c7398 --- /dev/null +++ b/test-devices/composite-stm32/src/main.c @@ -0,0 +1,236 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Board specific function (HAL) +// + +#include +#include +#include + +#include "board.h" +#include "tusb.h" +#include "usb_descriptors.h" +#include "vendor_custom.h" + +// FIFO buffer for loopback data +tu_fifo_t loopback_fifo; +uint8_t loopback_buffer[512]; + +// RX buffer for loopback +uint8_t loopback_rx_buffer[64]; + +// buffer for echoed packet +uint8_t echo_buffer[16]; +int num_echos; + + +// Blink durations +enum { + BLINK_NOT_MOUNTED = 250, + BLINK_MOUNTED = 1000, + BLINK_SUSPENDED = 2500, +}; + +static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; + +static void led_blinking_task(void); +static void cdc_task(void); +static void loopback_init(void); +static void loopback_check_rx(void); +static void loopback_check_tx(void); + + +int main(void) { + + board_init(); + loopback_init(); + + // init device stack + tud_init(BOARD_TUD_RHPORT); + + while (1) { + tud_task(); + cdc_task(); + led_blinking_task(); + } + + return 0; +} + +// --- Loopback + +void loopback_init(void) { + tu_fifo_config(&loopback_fifo, loopback_buffer, sizeof(loopback_buffer), 1, false); +} + +// Check if the next transmission should be started +void loopback_check_tx(void) { + + tu_fifo_buffer_info_t info; + tu_fifo_get_read_info(&loopback_fifo, &info); + + if (info.len_lin > 0 && !cust_vendor_is_transmitting(EP_LOOPBACK_TX)) { + int n = info.len_lin; + if (n > 128) + n = 128; + + cust_vendor_start_transmit(EP_LOOPBACK_TX, info.ptr_lin, n); + } +} + +// Check if receiving should be started again +void loopback_check_rx(void) { + + int n = tu_fifo_remaining(&loopback_fifo); + if (n >= sizeof(loopback_rx_buffer) && !cust_vendor_is_receiving(EP_LOOPBACK_RX)) { + + cust_vendor_prepare_recv(EP_LOOPBACK_RX, loopback_rx_buffer, sizeof(loopback_rx_buffer)); + } +} + +// --- CDC class + +void cdc_task(void) { + // echo all received data + if (!tud_cdc_available()) + return; + + uint8_t buf[64]; + uint32_t n = tud_cdc_read(buf, sizeof(buf)); + + tud_cdc_write(buf, n); + tud_cdc_write_flush(); +} + + +// --- Vendor class callbacks + +// Invoked when new data has been received +void cust_vendor_rx_cb(uint8_t ep_addr, uint32_t recv_bytes) { + tu_fifo_write_n(&loopback_fifo, loopback_rx_buffer, recv_bytes); + loopback_check_rx(); + loopback_check_tx(); +} + +// Invoked when last tx transfer finished +void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes) { + tu_fifo_advance_read_pointer(&loopback_fifo, sent_bytes); + loopback_check_tx(); + loopback_check_rx(); +} + +// Invoked when interface has been opened +void cust_vendor_intf_open_cb(uint8_t intf) { + loopback_check_rx(); +} + + + +// --- Control messages (see README) + +static uint32_t saved_value = 0; + +bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) { + if (stage != CONTROL_STAGE_SETUP) + return true; // nothing to do + + switch (request->bmRequestType_bit.type) { + case TUSB_REQ_TYPE_VENDOR: + + switch (request->bRequest) { + + case 0x01: + if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 0) { + // save value from wValue + saved_value = request->wValue; + return tud_control_status(rhport, request); + } + break; + + case 0x02: + if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 4) { + // receive into `saved_value` + return tud_control_xfer(rhport, request, &saved_value, 4); + } + break; + + case 0x03: + if (request->bmRequestType_bit.direction == TUSB_DIR_IN && request->wLength == 4) { + // transmit from `saved_value` + return tud_control_xfer(rhport, request, &saved_value, 4); + } + break; + + case MSOS_VENDOR_CODE: + if (request->wIndex == 7) { + // Get Microsoft OS 2.0 compatible descriptor + uint16_t total_len; + memcpy(&total_len, desc_ms_os_20 + 8, 2); + return tud_control_xfer(rhport, request, (uint8_t*) desc_ms_os_20, total_len); + } + break; + + default: + break; + } + + default: + break; + } + + // stall unknown request + return false; +} + +// --- Device callbacks + +// Register additional driver +usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) { + *driver_count = 1; + return &cust_vendor_driver; +} + + +// Invoked when device is mounted +void tud_mount_cb(void) { + blink_interval_ms = BLINK_MOUNTED; +} + +// Invoked when device is unmounted +void tud_umount_cb(void) { + blink_interval_ms = BLINK_NOT_MOUNTED; +} + +// Invoked when usb bus is suspended +// remote_wakeup_en: if host allow us to perform remote wakeup +// Within 7ms, device must draw an average of current less than 2.5 mA from bus +void tud_suspend_cb(bool remote_wakeup_en) { + (void) remote_wakeup_en; + blink_interval_ms = BLINK_SUSPENDED; +} + +// Invoked when usb bus is resumed +void tud_resume_cb(void) { + blink_interval_ms = BLINK_MOUNTED; +} + +// --- LED blinking --- + +void led_blinking_task(void) { + static uint32_t start_ms = 0; + static bool led_state = false; + + // Blink every interval ms + if ( board_millis() - start_ms < blink_interval_ms) + return; // not enough time + start_ms += blink_interval_ms; + + board_led_write(led_state); + led_state = 1 - led_state; // toggle +} diff --git a/test-devices/composite-stm32/src/main.cpp b/test-devices/composite-stm32/src/main.cpp deleted file mode 100644 index 20adde7b..00000000 --- a/test-devices/composite-stm32/src/main.cpp +++ /dev/null @@ -1,341 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Main program -// - -#include -#include -#include -#include -#include - -#include - -#include "circ_buf.h" -#include "common.h" -#include "usb_descriptor.h" -#include "usb_bos_desc.h" - -#define USB_CDC_REQ_GET_LINE_CODING 0x21 - -static void on_usb_set_config(usbd_device *usbd_dev, uint16_t wValue); -static usbd_request_return_codes on_vendor_control_request(usbd_device *usbd_dev, usb_setup_data *req, uint8_t **buf, - uint16_t *len, usbd_control_complete_callback *complete); -static usbd_request_return_codes on_class_control_request(usbd_device *usbd_dev, usb_setup_data *req, uint8_t **buf, - uint16_t *len, usbd_control_complete_callback *complete); -static void on_usb_loopback_received(usbd_device *usbd_dev, uint8_t ep); -static void on_usb_loopback_transmitted(usbd_device *usbd_dev, uint8_t ep); -static void on_usb_serial_received(usbd_device *usbd_dev, uint8_t ep); -static void on_usb_serial_transmitted(usbd_device *usbd_dev, uint8_t ep); -static void on_usb_serial_notif_transmitted(usbd_device *usbd_dev, uint8_t ep); -static void on_usb_echo_received(usbd_device *usbd_dev, uint8_t ep); -static void on_usb_echo_transmitted(usbd_device *usbd_dev, uint8_t ep); -static void check_loopback_buffers(); -static void check_serial_buffers(); - -// USB device instance -static usbd_device *usb_device; - -// buffer for control requests -static uint8_t usbd_control_buffer[256]; - -// Circular buffer for loopback test endpoints -static circ_buf<1024> loopback_buffer; - -// Minimum free space in circular buffer for requesting more packets -static constexpr int MIN_FREE_SPACE = 2 * BULK_MAX_PACKET_SIZE; - -// indicates if loopback data is being transmitted -static bool is_loopback_tx = false; - -// indicates if the loopback RX endpoint is forced to NAK to prevent receiving further data -static bool is_loopback_rx_nak = false; - -// value that can be saved and retrieved with control requests -static uint32_t saved_value; - -// echo message -static char echo_msg[INTR_MAX_PACKET_SIZE]; - -// echo message length -static int echo_msg_len; - -// number of echos left to transmit (if > 1, RX endpointed is NAKed) -static int num_echos_left; - -// Circular buffer for serial port -static circ_buf<1024> serial_buffer; - -// indicates if serial data is being transmitted -static bool is_serial_tx = false; - -// indicates if the serial RX endpoint is forced to NAK to prevent receiving further data -static bool is_serial_rx_nak = false; - - -void init() { - // Enable required clocks - rcc_clock_setup_in_hse_8mhz_out_72mhz(); - rcc_periph_clock_enable(RCC_GPIOA); - rcc_periph_clock_enable(RCC_GPIOC); - rcc_periph_clock_enable(RCC_AFIO); - rcc_periph_clock_enable(RCC_SPI1); - rcc_periph_clock_enable(RCC_USB); - - // Initialize systick services - systick_init(); -} - -void usb_init() { - // reset USB peripheral - rcc_periph_reset_pulse(RST_USB); - - // Pull USB D+ (A12) low for 80ms to trigger device reenumeration - gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO12); - gpio_clear(GPIOA, GPIO12); - delay(80); - - usb_init_serial_num(); - - // create USB device - usb_device = usbd_init(&st_usbfs_v1_usb_driver, &usb_device_desc, usb_config_descs, usb_desc_strings, - sizeof(usb_desc_strings) / sizeof(usb_desc_strings[0]), usbd_control_buffer, - sizeof(usbd_control_buffer)); - - // Set callback for config calls - usbd_register_set_config_callback(usb_device, on_usb_set_config); - usb_dev_register_bos(usb_device, bos_descs, sizeof(bos_descs) / sizeof(bos_descs[0]), - msos_desc_set, MSOS_VENDOR_CODE); -} - -// Called when the host connects to the device and selects a configuration -void on_usb_set_config(usbd_device *usbd_dev, __attribute__((unused)) uint16_t wValue) { - usb_dev_register_bos(usb_device, bos_descs, sizeof(bos_descs) / sizeof(bos_descs[0]), - msos_desc_set, MSOS_VENDOR_CODE); - - // register control request handler for vendor specific requests (used for test) - usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_INTERFACE, - USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, on_vendor_control_request); - - // register control request handler for class specific requests (used for CDC ACM) - usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, - USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, on_class_control_request); - - usbd_ep_setup(usbd_dev, EP_CDC_COMM, USB_ENDPOINT_ATTR_INTERRUPT, INTR_MAX_PACKET_SIZE, - on_usb_serial_notif_transmitted); - usbd_ep_setup(usbd_dev, EP_CDC_DATA_RX, USB_ENDPOINT_ATTR_BULK, BULK_MAX_PACKET_SIZE, on_usb_serial_received); - usbd_ep_setup(usbd_dev, EP_CDC_DATA_TX, USB_ENDPOINT_ATTR_BULK, BULK_MAX_PACKET_SIZE, on_usb_serial_transmitted); - - usbd_ep_setup(usbd_dev, EP_LOOPBACK_RX, USB_ENDPOINT_ATTR_BULK, BULK_MAX_PACKET_SIZE, on_usb_loopback_received); - usbd_ep_setup(usbd_dev, EP_LOOPBACK_TX, USB_ENDPOINT_ATTR_BULK, BULK_MAX_PACKET_SIZE, on_usb_loopback_transmitted); - usbd_ep_setup(usbd_dev, EP_ECHO_RX, USB_ENDPOINT_ATTR_INTERRUPT, INTR_MAX_PACKET_SIZE, on_usb_echo_received); - usbd_ep_setup(usbd_dev, EP_ECHO_TX, USB_ENDPOINT_ATTR_INTERRUPT, INTR_MAX_PACKET_SIZE, on_usb_echo_transmitted); - - loopback_buffer.reset(); - is_loopback_tx = false; - is_loopback_rx_nak = false; - num_echos_left = 0; - echo_msg_len = 0; - saved_value = 0; - serial_buffer.reset(); - is_serial_tx = false; - is_serial_rx_nak = false; -} - -// Called when loopback data has been received -void on_usb_loopback_received(usbd_device *usbd_dev, uint8_t ep) { - // Retrieve USB data (has side effect of setting endpoint to VALID) - uint8_t packet[BULK_MAX_PACKET_SIZE] __attribute__((aligned(4))); - int len = usbd_ep_read_packet(usbd_dev, ep, packet, sizeof(packet)); - - // copy data into circular buffer - loopback_buffer.add_data(packet, len); -} - -// Called when loopback data has been transmitted -void on_usb_loopback_transmitted(__attribute__((unused)) usbd_device *usbd_dev, __attribute__((unused)) uint8_t ep) { - is_loopback_tx = false; -} - -void check_loopback_buffers() { - // If RX is stopped and there is sufficient space in the buffer, resume it - if (is_loopback_rx_nak) { - if (loopback_buffer.avail_size() >= MIN_FREE_SPACE) { - usbd_ep_nak_set(usb_device, EP_LOOPBACK_RX, 0); - is_loopback_rx_nak = false; - } - - // If RX is enabled but the space in the buffer is low, stop it - } else { - // check if there is space for less than 2 packets - if (loopback_buffer.avail_size() < MIN_FREE_SPACE) { - // set endpoint from VALID to NAK - usbd_ep_nak_set(usb_device, EP_LOOPBACK_RX, 1); - is_loopback_rx_nak = true; - } - } - - // If no data is being transmitted and there is data in the buffer, transmit a packet - if (!is_loopback_tx && loopback_buffer.data_size() >= 0) { - uint8_t packet[BULK_MAX_PACKET_SIZE] __attribute__((aligned(4))); - int len = loopback_buffer.get_data(packet, BULK_MAX_PACKET_SIZE); - usbd_ep_write_packet(usb_device, EP_LOOPBACK_TX, packet, len); - is_loopback_tx = true; - } -} - -// Called when echo data has been received -void on_usb_echo_received(usbd_device *usbd_dev, uint8_t ep) { - // Retrieve USB data (has side effect of setting endpoint to VALID) - echo_msg_len = usbd_ep_read_packet(usbd_dev, EP_ECHO_RX, echo_msg, sizeof(echo_msg)); - usbd_ep_nak_set(usbd_dev, ep, 1); - - usbd_ep_write_packet(usbd_dev, EP_ECHO_TX, echo_msg, echo_msg_len); - num_echos_left = 2; -} - -// Called when echo data has been transmitted -void on_usb_echo_transmitted(__attribute__((unused)) usbd_device *usbd_dev, __attribute__((unused)) uint8_t ep) { - num_echos_left--; - if (num_echos_left > 0) { - usbd_ep_write_packet(usbd_dev, ep, echo_msg, echo_msg_len); - } else { - usbd_ep_nak_set(usbd_dev, EP_ECHO_RX, 0); - } -} - -// Called when serial data has been received -void on_usb_serial_received(usbd_device *usbd_dev, uint8_t ep) { - // Retrieve USB data (has side effect of setting endpoint to VALID) - uint8_t packet[BULK_MAX_PACKET_SIZE] __attribute__((aligned(4))); - int len = usbd_ep_read_packet(usbd_dev, ep, packet, sizeof(packet)); - - // copy data into circular buffer - serial_buffer.add_data(packet, len); -} - -// Called when serial data has been transmitted -void on_usb_serial_transmitted(__attribute__((unused)) usbd_device *usbd_dev, __attribute__((unused)) uint8_t ep) { - is_serial_tx = false; -} - -// Called when a serial state notification has been transmitted -void on_usb_serial_notif_transmitted(__attribute__((unused)) usbd_device *usbd_dev, - __attribute__((unused)) uint8_t ep) { - // not used -} - -void check_serial_buffers() { - // If RX is stopped and there is sufficient space in the buffer, resume it - if (is_serial_rx_nak) { - if (serial_buffer.avail_size() >= MIN_FREE_SPACE) { - usbd_ep_nak_set(usb_device, EP_CDC_DATA_RX, 0); - is_serial_rx_nak = false; - } - - // If RX is enabled but the space in the buffer is low, stop it - } else { - // check if there is space for less than 2 packets - if (serial_buffer.avail_size() < MIN_FREE_SPACE) { - // set endpoint from VALID to NAK - usbd_ep_nak_set(usb_device, EP_CDC_DATA_RX, 1); - is_serial_rx_nak = true; - } - } - - // If no data is being transmitted and there is data in the buffer, transmit a packet - if (!is_serial_tx && serial_buffer.data_size() >= 0) { - uint8_t packet[BULK_MAX_PACKET_SIZE] __attribute__((aligned(4))); - int len = serial_buffer.get_data(packet, BULK_MAX_PACKET_SIZE); - usbd_ep_write_packet(usb_device, EP_CDC_DATA_TX, packet, len); - is_serial_tx = true; - } -} - -usbd_request_return_codes on_vendor_control_request(__attribute__((unused)) usbd_device *usbd_dev, usb_setup_data *req, - uint8_t **buf, uint16_t *len, - __attribute__((unused)) usbd_control_complete_callback *complete) { - switch (req->bRequest) { - case 1: - if (req->wIndex == 2 && req->wLength == 0) { - saved_value = req->wValue; - return USBD_REQ_HANDLED; - } else { - return USBD_REQ_NOTSUPP; - } - break; - - case 2: - if (req->wIndex == 2 && req->wLength == 4) { - uint32_t *value = reinterpret_cast(*buf); - saved_value = *value; - return USBD_REQ_HANDLED; - } else { - return USBD_REQ_NOTSUPP; - } - break; - - case 3: - if (req->wIndex == 2) { - uint8_t *value = reinterpret_cast(&saved_value); - *len = std::min(*len, (uint16_t)4); - memcpy(*buf, value, *len); - return USBD_REQ_HANDLED; - } else { - return USBD_REQ_NOTSUPP; - } - break; - - default:; // fall through - } - - return USBD_REQ_NEXT_CALLBACK; -} - -// Process ACM requests on control endpoint -usbd_request_return_codes on_class_control_request(__attribute__((unused)) usbd_device *usbd_dev, usb_setup_data *req, - uint8_t **buf, uint16_t *len, - __attribute__((unused)) usbd_control_complete_callback *complete) { - switch (req->bRequest) { - case USB_CDC_REQ_SET_LINE_CODING: - if (*len < sizeof(struct usb_cdc_line_coding)) - return USBD_REQ_NOTSUPP; - - return USBD_REQ_HANDLED; - - case USB_CDC_REQ_GET_LINE_CODING: { - if (*len < sizeof(struct usb_cdc_line_coding)) - return USBD_REQ_NOTSUPP; - - struct usb_cdc_line_coding *line_coding = (struct usb_cdc_line_coding *)*buf; - line_coding->dwDTERate = 115200; - line_coding->bDataBits = 8; - line_coding->bParityType = 0; - line_coding->bCharFormat = 0; - - *len = sizeof(struct usb_cdc_line_coding); - return USBD_REQ_HANDLED; - } - - case USB_CDC_REQ_SET_CONTROL_LINE_STATE: - return USBD_REQ_HANDLED; - } - return USBD_REQ_NEXT_CALLBACK; -} - -int main() { - init(); - usb_init(); - - while (true) { - usbd_poll(usb_device); - check_loopback_buffers(); - check_serial_buffers(); - } -} diff --git a/test-devices/composite-stm32/src/usb_bos.cpp b/test-devices/composite-stm32/src/usb_bos.cpp deleted file mode 100644 index 020c9da8..00000000 --- a/test-devices/composite-stm32/src/usb_bos.cpp +++ /dev/null @@ -1,98 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// USB binary device object store (BOS) -// - -#include "usb_bos.h" -#include - -static uint32_t build_descriptor(uint8_t* buf); -static enum usbd_request_return_codes on_bos_control_request( - usbd_device* usbd_dev, struct usb_setup_data* req, - uint8_t** buf, uint16_t* len, usbd_control_complete_callback* complete); - -static inline int imin(int a, int b) { return a < b ? a : b; } -static inline int descriptor_type(uint16_t wValue) { return wValue >> 8; } -static inline int descriptor_index(uint16_t wValue) { return wValue & 0xFF; } - -static const usb_bos_device_capability_desc* const* bos_descs; -static int num_bos_descs; -static const usb_msos20_desc_set_header* msos_desc_set; -static uint8_t msos_vendor_code; - - -void usb_dev_register_bos(usbd_device* device, - const usb_bos_device_capability_desc* const * descs, int num_descs, - const usb_msos20_desc_set_header* msos_set, uint8_t vendor_code) { - - bos_descs = descs; - num_bos_descs = num_descs; - msos_desc_set = msos_set; - msos_vendor_code = vendor_code; - - usbd_register_control_callback(device, USB_REQ_TYPE_IN | USB_REQ_TYPE_DEVICE, - USB_REQ_TYPE_DIRECTION | USB_REQ_TYPE_RECIPIENT, on_bos_control_request); -} - -#define APPEND_TO_DESC(data_ptr, data_len) \ - memcpy(buf_end, data_ptr, data_len); \ - buf_end += data_len; - -uint32_t build_descriptor(uint8_t* buf) { - uint8_t* buf_end = buf; - - usb_bos_desc root_desc = { - .bLength = sizeof(usb_bos_desc), - .bDescriptorType = USB_DT_BOS, - .wTotalLength = 0, - .bNumDeviceCaps = (uint8_t) num_bos_descs - }; - - APPEND_TO_DESC(&root_desc, sizeof(root_desc)) - - for (int i = 0; i < num_bos_descs; i++) { - APPEND_TO_DESC(bos_descs[i], bos_descs[i]->bLength) - } - - uint32_t length = buf_end - buf; - - // use memcpy() as buffer might not be word aligned - memcpy(buf + 2, &length, sizeof(uint16_t)); - - return length; -} - -#undef APPEND_TO_DESC - -enum usbd_request_return_codes on_bos_control_request( - __attribute__((unused)) usbd_device* dev, struct usb_setup_data* req, uint8_t** buf, uint16_t* len, - __attribute__((unused)) usbd_control_complete_callback* complete) { - - if (req->bmRequestType == (USB_REQ_TYPE_IN | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE)) { - - if (req->bRequest == USB_REQ_GET_DESCRIPTOR && descriptor_type(req->wValue) == USB_DT_BOS) { - - // USB BOS descriptor (incl. Microsoft OS 2.0 platform capability descriptor) - if (descriptor_index(req->wValue) != 0) - return USBD_REQ_NOTSUPP; - *len = imin(*len, build_descriptor(*buf)); - return USBD_REQ_HANDLED; - } - - } else if (req->bmRequestType == (USB_REQ_TYPE_IN | USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE)) { - // Microsoft OS 2.0 descriptor - if (req->bRequest == msos_vendor_code && req->wValue == 0 && req->wIndex == USB_MSOS20_CTRL_INDEX_DESC) { - memcpy(*buf, msos_desc_set, msos_desc.wMSOSDescriptorSetTotalLength); - *len = imin(*len, msos_desc.wMSOSDescriptorSetTotalLength); - return USBD_REQ_HANDLED; - } - } - - return USBD_REQ_NEXT_CALLBACK; -} diff --git a/test-devices/composite-stm32/src/usb_bos_desc.c b/test-devices/composite-stm32/src/usb_bos_desc.c deleted file mode 100644 index eeb6039d..00000000 --- a/test-devices/composite-stm32/src/usb_bos_desc.c +++ /dev/null @@ -1,89 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// USB BOS descriptor to install WinUSB for loopback test interface -// - -#include "usb_bos_desc.h" - -#define DEV_INTF_GUID_NAME u"DeviceInterfaceGUIDs" -#define DEV_INTF_GUID_DATA u"{049CD59E-33EE-4CB2-B0BB-1C49F3CB6358}" - -const struct msos20_desc_set { - usb_msos20_desc_set_header descSetHeader; - usb_msos20_desc_subset_header_config descSubsetConfig; - usb_msos20_desc_subset_header_function descSubsetFunction; - usb_msos20_desc_compatible_id descCompId; - struct { - uint16_t wLength; - uint16_t wDescriptorType; - uint16_t wPropertyDataType; - uint16_t wPropertyNameLength; - uint16_t propertyName[sizeof(DEV_INTF_GUID_NAME) / 2]; - uint16_t wPropertyDataLength; - uint16_t propertyData[sizeof(DEV_INTF_GUID_DATA) / 2 + 1]; - } devIntfGuid; - -} msos_set = { - - .descSetHeader = { - .wLength = sizeof(usb_msos20_desc_set_header), - .wDescriptorType = USB_MSOS20_DT_SET_HEADER_DESCRIPTOR, - .dwWindowsVersion = USB_MSOS20_WIN_VER_8_1, - .wTotalLength = sizeof(msos_set) - }, - .descSubsetConfig = { - .wLength = sizeof(usb_msos20_desc_subset_header_config), - .wDescriptorType = USB_MSOS20_DT_SUBSET_HEADER_CONFIGURATION, - .bConfigurationValue = 0, - .wTotalLength = sizeof(msos_set.descSubsetConfig) + sizeof(msos_set.descSubsetFunction) + - sizeof(msos_set.descCompId) + sizeof(msos_set.devIntfGuid), - }, - .descSubsetFunction = { - .wLength = sizeof(usb_msos20_desc_subset_header_function), - .wDescriptorType = USB_MSOS20_DT_SUBSET_HEADER_FUNCTION, - .bFirstInterface = 2, - .wTotalLength = sizeof(msos_set.descSubsetFunction) + sizeof(msos_set.descCompId) + - sizeof(msos_set.devIntfGuid), - }, - .descCompId = { - .wLength = sizeof(usb_msos20_desc_compatible_id), - .wDescriptorType = USB_MSOS20_DT_FEATURE_COMPATBLE_ID, - .compatibleID = "WINUSB\0\0", - .subCompatibleID = "\0\0\0\0\0\0\0\0" - }, - .devIntfGuid = { - .wLength = sizeof(msos_set.devIntfGuid), - .wDescriptorType = USB_MSOS20_DT_FEATURE_REG_PROPERTY, - .wPropertyDataType = USB_MSOS20_PROP_DATA_TYPE_STRING_MULTI, - .wPropertyNameLength = sizeof(msos_set.devIntfGuid.propertyName), - .propertyName = DEV_INTF_GUID_NAME, - .wPropertyDataLength = sizeof(msos_set.devIntfGuid.propertyData), - .propertyData = DEV_INTF_GUID_DATA "\0" - } -}; - -const usb_msos20_desc_set_header* msos_desc_set = &msos_set.descSetHeader; - -const usb_msos20_platform_desc msos_desc = { - .bLength = sizeof(usb_msos20_platform_desc), - .bDescriptorType = USB_DT_DEVICE_CAPABILITY, - .bDevCapabilityType = USB_DEV_CAPA_PLATFORM, - .bReserved = 0, - .platformCapabilityUUID = USB_PLATFORM_CAPABILITY_MICROSOFT_OS20_UUID, - .dwWindowsVersion = USB_MSOS20_WIN_VER_8_1, - .wMSOSDescriptorSetTotalLength = sizeof(msos_set), - .bMS_VendorCode = MSOS_VENDOR_CODE, - .bAltEnumCode = 0 -}; - -// BOS device capability descriptors -const usb_bos_device_capability_desc* const bos_descs[] = { - // Microsoft OS 2.0 descriptor (for autmatic WinUSB installation) - (const usb_bos_device_capability_desc*)&msos_desc -}; diff --git a/test-devices/composite-stm32/src/usb_descriptor.cpp b/test-devices/composite-stm32/src/usb_descriptor.cpp deleted file mode 100644 index 05827bf5..00000000 --- a/test-devices/composite-stm32/src/usb_descriptor.cpp +++ /dev/null @@ -1,308 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// USB descriptor -// - -#include "usb_descriptor.h" - -#include -#include - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) - -static void put_hex(uint32_t value, char *buf, int len); - -#define USB_VID 0xcafe // Vendor ID -#define USB_PID 0xcea0 // Product ID -#define USB_DEVICE_REL 0x0034 // release 0.3.3 - -// Interface index -#define INTF_CDC_COMM 0 -#define INTF_CDC_DATA 1 -#define INTF_LOOPBACK 2 - -static char serial_num[13]; - -const char *const usb_desc_strings[] = { - "JavaDoesUSB", // USB Manufacturer - "Loopback", // USB Product - serial_num, // Serial number, - "Loopback Serial Port" // Function description -}; - -enum usb_strings_index { // Index of USB strings. Must sync with above, starts from 1. - USB_STRINGS_MANUFACTURER_ID = 1, - USB_STRINGS_PRODUCT_ID, - USB_STRINGS_SERIAL_NUMBER_ID, - USB_STRINGS_SERIAL_PORT_ID, -}; - -typedef struct { - struct usb_cdc_header_descriptor header; - struct usb_cdc_call_management_descriptor call_mgmt; - struct usb_cdc_acm_descriptor acm; - struct usb_cdc_union_descriptor cdc_union; -} __attribute__((packed)) cdcacm_functional_descriptors; - -// --- CDC ACM --- - -// CDC communicatoin endpoint -static const usb_endpoint_descriptor cdc_comm_ep_desc[] = { - { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_CDC_COMM, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = INTR_MAX_PACKET_SIZE, - .bInterval = 32, - .extra = nullptr, - .extralen = 0, - } -}; - -// CDC data endpoints -static const usb_endpoint_descriptor cdc_data_ep_desc[] = { - { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_CDC_DATA_RX, - .bmAttributes = USB_ENDPOINT_ATTR_BULK, - .wMaxPacketSize = BULK_MAX_PACKET_SIZE, - .bInterval = 1, - .extra = nullptr, - .extralen = 0, - }, - { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_CDC_DATA_TX, - .bmAttributes = USB_ENDPOINT_ATTR_BULK, - .wMaxPacketSize = BULK_MAX_PACKET_SIZE, - .bInterval = 1, - .extra = nullptr, - .extralen = 0, - } -}; - -// CDC ACM function descriptor -static const cdcacm_functional_descriptors cdc_func_desc = { - .header = { - .bFunctionLength = sizeof(usb_cdc_header_descriptor), - .bDescriptorType = CS_INTERFACE, - .bDescriptorSubtype = USB_CDC_TYPE_HEADER, - .bcdCDC = 0x0110, - }, - .call_mgmt = { - // see chapter 5.3.1 in PSTN120 - .bFunctionLength = sizeof(usb_cdc_call_management_descriptor), - .bDescriptorType = CS_INTERFACE, - .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, - .bmCapabilities = 0, // no call management - .bDataInterface = INTF_CDC_DATA, - }, - .acm = { - // see chapter 5.3.2 in PSTN120 - .bFunctionLength = sizeof(usb_cdc_acm_descriptor), - .bDescriptorType = CS_INTERFACE, - .bDescriptorSubtype = USB_CDC_TYPE_ACM, - .bmCapabilities = 2, // device supports the request combination of Set_Line_Coding, Set_Control_Line_State, - // Get_Line_Coding, and the notification Serial_State - }, - .cdc_union = { - .bFunctionLength = sizeof(usb_cdc_union_descriptor), - .bDescriptorType = CS_INTERFACE, - .bDescriptorSubtype = USB_CDC_TYPE_UNION, - .bControlInterface = INTF_CDC_COMM, - .bSubordinateInterface0 = INTF_CDC_DATA, - } -}; - -// CDC interfaces descriptors -static const usb_interface_descriptor cdc_comm_if_desc[] = { - { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = INTF_CDC_COMM, - .bAlternateSetting = 0, - .bNumEndpoints = ARRAY_SIZE(cdc_comm_ep_desc), - .bInterfaceClass = USB_CLASS_CDC, - .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, - .bInterfaceProtocol = USB_CDC_PROTOCOL_AT, - .iInterface = 0, - .endpoint = cdc_comm_ep_desc, - .extra = &cdc_func_desc, - .extralen = sizeof(cdc_func_desc), - } -}; - -static const usb_interface_descriptor cdc_data_if_desc[] = { - { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = INTF_CDC_DATA, - .bAlternateSetting = 0, - .bNumEndpoints = ARRAY_SIZE(cdc_data_ep_desc), - .bInterfaceClass = USB_CLASS_DATA, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = 0, - .endpoint = cdc_data_ep_desc, - .extra = nullptr, - .extralen = 0, - } -}; - -// CDC interface association -static const usb_iface_assoc_descriptor cdc_assoc_desc = { - .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, - .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, - .bFirstInterface = INTF_CDC_COMM, - .bInterfaceCount = 2, - .bFunctionClass = USB_CLASS_CDC, - .bFunctionSubClass = USB_CDC_SUBCLASS_ACM, - .bFunctionProtocol = USB_CDC_PROTOCOL_AT, - .iFunction = USB_STRINGS_SERIAL_PORT_ID, -}; - -// --- Loopback test interface --- - -// Test endpoints -static const struct usb_endpoint_descriptor loopback_endpoint_descs[] = { - { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_LOOPBACK_RX, - .bmAttributes = USB_ENDPOINT_ATTR_BULK, - .wMaxPacketSize = BULK_MAX_PACKET_SIZE, - .bInterval = 0, - .extra = nullptr, - .extralen = 0, - }, - { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_LOOPBACK_TX, - .bmAttributes = USB_ENDPOINT_ATTR_BULK, - .wMaxPacketSize = BULK_MAX_PACKET_SIZE, - .bInterval = 0, - .extra = nullptr, - .extralen = 0, - }, - { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_ECHO_RX, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = INTR_MAX_PACKET_SIZE, - .bInterval = 16, - .extra = nullptr, - .extralen = 0, - }, - { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_ECHO_TX, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = INTR_MAX_PACKET_SIZE, - .bInterval = 16, - .extra = nullptr, - .extralen = 0, - }, -}; - -// Test interface -static const struct usb_interface_descriptor loopback_if_descs[] = { - { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = INTF_LOOPBACK, - .bAlternateSetting = 0, - .bNumEndpoints = ARRAY_SIZE(loopback_endpoint_descs), - .bInterfaceClass = USB_CLASS_VENDOR, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, // vendor specific - .iInterface = 0, - .endpoint = loopback_endpoint_descs, - .extra = nullptr, - .extralen = 0, - }, -}; - -static const struct usb_interface usb_interfaces[] = { - { - .cur_altsetting = nullptr, - .num_altsetting = ARRAY_SIZE(cdc_comm_if_desc), - .iface_assoc = &cdc_assoc_desc, - .altsetting = cdc_comm_if_desc, - }, - { - .cur_altsetting = nullptr, - .num_altsetting = ARRAY_SIZE(cdc_data_if_desc), - .iface_assoc = nullptr, - .altsetting = cdc_data_if_desc, - }, - { - .cur_altsetting = nullptr, - .num_altsetting = ARRAY_SIZE(loopback_if_descs), - .iface_assoc = nullptr, - .altsetting = loopback_if_descs, - }, -}; - -const struct usb_config_descriptor usb_config_descs[] = { - { - .bLength = USB_DT_CONFIGURATION_SIZE, - .bDescriptorType = USB_DT_CONFIGURATION, - .wTotalLength = 0, - .bNumInterfaces = ARRAY_SIZE(usb_interfaces), - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = 0x80, // bus-powered, i.e. it draws power from USB bus - .bMaxPower = 0xfa, // 500 mA - .interface = usb_interfaces, - }, -}; - -const struct usb_device_descriptor usb_device_desc = { - .bLength = USB_DT_DEVICE_SIZE, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0210, // USB version 2.1.0 (minimum version for BOS) - .bDeviceClass = 0xef, - .bDeviceSubClass = 0x02, - .bDeviceProtocol = 0x01, - .bMaxPacketSize0 = 64, - .idVendor = USB_VID, - .idProduct = USB_PID, - .bcdDevice = USB_DEVICE_REL, - .iManufacturer = USB_STRINGS_MANUFACTURER_ID, - .iProduct = USB_STRINGS_PRODUCT_ID, - .iSerialNumber = USB_STRINGS_SERIAL_NUMBER_ID, - .bNumConfigurations = ARRAY_SIZE(usb_config_descs), -}; - -void usb_init_serial_num() { - uint32_t id0 = DESIG_UNIQUE_ID0; - uint32_t id1 = DESIG_UNIQUE_ID1; - uint32_t id2 = DESIG_UNIQUE_ID2; - - id0 += id2; - - put_hex(id0, serial_num, 8); - put_hex(id1, serial_num + 8, 4); - serial_num[12] = 0; -} - -const static char HEX_DIGITS[] = "0123456789ABCDEF"; - -void put_hex(uint32_t value, char *buf, int len) { - for (int idx = 0; idx < len; idx++) { - buf[idx] = HEX_DIGITS[value >> 28]; - value = value << 4; - } -} diff --git a/test-devices/composite-stm32/src/usb_descriptors.c b/test-devices/composite-stm32/src/usb_descriptors.c new file mode 100644 index 00000000..8daa3e95 --- /dev/null +++ b/test-devices/composite-stm32/src/usb_descriptors.c @@ -0,0 +1,174 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Board specific function (HAL) +// + +#include "usb_descriptors.h" + +#include "board.h" +#include "tusb.h" +#include "class/cdc/cdc.h" +#include "vendor_custom.h" + + +// --- Device Descriptor --- + +tusb_desc_device_t const desc_device = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0210, // 2.1.0 (minimum for BOS) + + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + + .idVendor = 0xCAFE, + .idProduct = 0xCEA0, + .bcdDevice = 0x0034, // version 0.3.4 + + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + + .bNumConfigurations = 0x01 +}; + +// Invoked when a GET DEVICE DESCRIPTOR request is received. +// Return a pointer to the descriptor. +uint8_t const* tud_descriptor_device_cb(void) { + return (uint8_t const*)&desc_device; +} + + +// --- Configuration Descriptor --- + +enum { + INTF_CDC_COMM = 0, + INTF_CDC_DATA, + INTF_LOOPBACK, + INTF_NUM_TOTAL +}; + +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + 9 + 7 + 7) + +uint8_t const desc_configuration[] = { + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, INTF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 500), + // CDC interfaces + TUD_CDC_DESCRIPTOR(INTF_CDC_COMM, 0, EP_CDC_COMM, 8, EP_CDC_DATA_RX, EP_CDC_DATA_TX, BULK_MAX_PACKET_SIZE), + // Loopback interface + CUSTOM_VENDOR_INTERFACE(INTF_LOOPBACK, 2), + // Loopback endpoint OUT + CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_RX, BULK_MAX_PACKET_SIZE), + // Loopback endpoint IN + CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_TX, BULK_MAX_PACKET_SIZE) +}; + +// Invoked when a GET CONFIGURATION DESCRIPTOR request is recieved. +// Return a pointer to descriptor. +// Descriptor contents must exist long enough for transfer to complete +uint8_t const* tud_descriptor_configuration_cb(uint8_t configuration_index) { + (void)configuration_index; + return desc_configuration; +} + + +// --- BOS Descriptor --- + +#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN) + +#define MS_OS_20_DESC_LEN 0xB2 + +// BOS Descriptor is required for webUSB +uint8_t const desc_bos[] = { + // total length, number of device caps + TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 1), + + // Microsoft OS 2.0 descriptor + TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, MSOS_VENDOR_CODE) +}; + +uint8_t const * tud_descriptor_bos_cb(void) { + return desc_bos; +} + + +uint8_t const desc_ms_os_20[] = { + // Set header: length, type, windows version, total length + U16_TO_U8S_LE(0x000A), U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR), U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(MS_OS_20_DESC_LEN), + + // Configuration subset header: length, type, configuration index, reserved, configuration total length + U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A), + + // Function Subset header: length, type, first interface, reserved, subset length + U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), INTF_LOOPBACK, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08), + + // MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub compatible ID + U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sub-compatible + + // MS OS 2.0 Registry property descriptor: length, type + U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08-0x08-0x14), U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY), + U16_TO_U8S_LE(0x0007), U16_TO_U8S_LE(0x002A), // wPropertyDataType, wPropertyNameLength and PropertyName "DeviceInterfaceGUIDs\0" in UTF-16 + 'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00, + 'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00, + U16_TO_U8S_LE(0x0050), // wPropertyDataLength + //bPropertyData: “{82DF5D1A-BD37-431C-81B7-52EB2093B98F}”. + '{', 0x00, '8', 0x00, '2', 0x00, 'D', 0x00, 'F', 0x00, '5', 0x00, 'D', 0x00, '1', 0x00, 'A', 0x00, '-', 0x00, + 'B', 0x00, 'D', 0x00, '3', 0x00, '7', 0x00, '-', 0x00, '4', 0x00, '3', 0x00, '1', 0x00, 'C', 0x00, '-', 0x00, + '8', 0x00, '1', 0x00, 'B', 0x00, '7', 0x00, '-', 0x00, '5', 0x00, '2', 0x00, 'E', 0x00, 'B', 0x00, '2', 0x00, + '0', 0x00, '9', 0x00, '3', 0x00, 'B', 0x00, '9', 0x00, '8', 0x00, 'F', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +TU_VERIFY_STATIC(sizeof(desc_ms_os_20) == MS_OS_20_DESC_LEN, "Incorrect size"); + + + +// --- String Descriptors --- + +// table with strings +const char* const string_table[] = { + 0, // 0 - supported languages (see below) + "JavaDoesUSB", // 1 - manufacturer + "Loopback", // 2 - product + board_serial_num // 3 - serial number +}; + + +static uint16_t str_desc_buf[32]; + +// Invoked when a GET STRING DESCRIPTOR request is received. +// Return pointer to string descriptor. +uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) { + (void)langid; + + int str_len; + + if (index == 0) { + str_desc_buf[1] = 0x0409; // US English + str_len = 1; + + } else { + if (index >= TU_ARRAY_SIZE(string_table)) + return NULL; + + const char* str = string_table[index]; + str_len = strlen(str); + + // Convert ASCII to UTF-16 + for (uint8_t i = 0; i < str_len; i++) + str_desc_buf[1 + i] = str[i]; + } + + // first byte is length (including header), second byte is string type + str_desc_buf[0] = (uint16_t)((2 * str_len + 2) | (TUSB_DESC_STRING << 8)); + + return str_desc_buf; +} diff --git a/test-devices/composite-stm32/src/vendor_custom.c b/test-devices/composite-stm32/src/vendor_custom.c new file mode 100644 index 00000000..44b2dc26 --- /dev/null +++ b/test-devices/composite-stm32/src/vendor_custom.c @@ -0,0 +1,111 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// USB driver for interfaces with vendor specific class. +// The interface can have any number of Bulk and Interrupt endpoints. +// + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_VENDOR_ADVANCED) + +#include "device/usbd.h" +#include "vendor_custom.h" + + +static void cv_init(void); +static void cv_reset(uint8_t rhport); +static uint16_t cv_open(uint8_t rhport, tusb_desc_interface_t const* desc_intf, uint16_t max_len); +static bool cv_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); + +const usbd_class_driver_t cust_vendor_driver = { + .init = cv_init, + .reset = cv_reset, + .open = cv_open, + .control_xfer_cb = NULL, + .xfer_cb = cv_xfer_cb, + .sof = NULL +}; + + +void cv_init(void) { + // nothing to do +} + +void cv_reset(uint8_t rhport) { + // nothing to do +} + +uint16_t cv_open(uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t max_len) { + + // return 0 if interface class is not "vendor specific" + TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_intf->bInterfaceClass, 0); + + uint8_t const * p_desc = tu_desc_next(desc_intf); + uint8_t const * desc_end = p_desc + max_len; + int num_endpoints = desc_intf->bNumEndpoints; + + // iterate all endpoints + while (num_endpoints > 0 && p_desc < desc_end) { + + // open endpoint + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; + TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); + + p_desc = tu_desc_next(p_desc); + num_endpoints--; + } + + uint16_t processed_bytes = p_desc - (uint8_t const *) desc_intf; + + cust_vendor_intf_open_cb(desc_intf->bInterfaceNumber); + + return processed_bytes; +} + +bool cv_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { + + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { + cust_vendor_tx_cb(ep_addr, xferred_bytes); + + } else { + cust_vendor_rx_cb(ep_addr, xferred_bytes); + } + + return true; +} + +void cust_vendor_prepare_recv(uint8_t ep_addr, void* buf, uint32_t buf_len) { + + uint8_t const rhport = 0; + + if (usbd_edpt_busy(rhport, ep_addr)) + return; + + usbd_edpt_xfer(rhport, ep_addr, buf, buf_len); +} + +void cust_vendor_start_transmit(uint8_t ep_addr, void const * data, uint32_t data_len) { + + uint8_t const rhport = 0; + + if (usbd_edpt_busy(rhport, ep_addr)) + return; + + usbd_edpt_xfer(rhport, ep_addr, (void*) data, data_len); +} + +bool cust_vendor_is_receiving(uint8_t ep_addr) { + return usbd_edpt_busy(0, ep_addr); +} + +bool cust_vendor_is_transmitting(uint8_t ep_addr) { + return usbd_edpt_busy(0, ep_addr); +} + +#endif diff --git a/test-devices/loopback-stm32/README.md b/test-devices/loopback-stm32/README.md index 29105953..c6f7f83e 100644 --- a/test-devices/loopback-stm32/README.md +++ b/test-devices/loopback-stm32/README.md @@ -1,6 +1,14 @@ # Loopback Test Device -For testing the *Java Does USB* library, a dedicated USB test device is needed. This is the code for an STM32F103C8 microcontroller. This microcontroller is found on many inexpensive development board, most notabily on the so called *Blue Pill*. Such boards are available for about 3 USD, including the required ST-Link programmer. +For testing the *Java Does USB* library, a dedicated USB test device is needed. This is the code for STM32 microcontroller. This microcontroller is found on many inexpensive development board, most notabily on the so called *Blue Pill* and *Black Pill* boards. They are available for about 3 USD. + +## Supported boards + +- BlackPill with STM32F401CC microcontroller +- BlackPill with STM32F411CE microcontroller +- BluePill with STM32F103C8 microcontroller + +To upload the firmware, the STM32F4x microcontroller have a built-in USB bootloader. The STM32F1x microcontrollers need an ST-Link debug adapter (or a USB-to-serial converter). ## Test features @@ -15,7 +23,7 @@ For testing the *Java Does USB* library, a dedicated USB test device is needed. | 0x03 | Interrupt | Host to device | 16 bytes | Echo: All packets received on this endpoint are transmitted twice on endpoint 0x83. | | 0x83 | Interrupt | Device to host | 16 bytes | Echo: Transmits all packets received on endpoint 0x03 twice. | -The bulk endpoints 0x01 and 0x82 use an internal buffer of about 1000 bytes. Data up to this amount can be sent and received sequentially. If more data is sent without receiving at the same time, flow control kicks in and endpoint 0x01 will stop receiving data until there is room in the buffer. +The bulk endpoints 0x01 and 0x82 use an internal buffer of about 500 bytes. Data up to this amount can be sent and received sequentially. If more data is sent without receiving at the same time, flow control kicks in and endpoint 0x01 will stop receiving data until there is room in the buffer. ### Control requests @@ -29,26 +37,70 @@ Several vendor-specific control requests are supported for testing: | 0xC1 | 0x03 | 0 | 0 | 4 | *value* (32-bit LE) | Device to host: saved *value* is transmitted | -## Building +## Building the firmware This project requires [PlatformIO](https://platformio.org/). The easiest way to get up and running is to use Visual Studio Code and then install the [PlatformIO IDE extension](https://marketplace.visualstudio.com/items?itemName=platformio.platformio-ide). -After the extension is installed, open this folder and then click checkbox icon (*Build* action) in the status bar. +After the extension is installed, open this folder and select your board type by clicking on "Default (tinyusb-stm32)" in the status bar. Wait until the status bar no longer indicates activity. Then click the checkbox icon (*Build* action) in the status bar. -To upload the code to the microcontroller: +To load the firmware onto the board, either connect it via ST-Link programmer to the 4 pins on the short side of the board or use the built-in USB bootloader (BlackPill only). + +For upload with a ST-Link programmer: - Connect the ST-Link programmer to the development board - Connect the ST-Link programmer to your computer - Click the arrow icon (*Upload* action) in the status bar +For other means of upload, see *Binary releases* below. + + +## Binary releases -## Binary release +The directory `bin` contains a pre-built firmware: -The directory `bin` contains a pre-built firmware. In order to upload it, a utility is needed, either [STM32CubeProgrammer](https://www.st.com/en/development-tools/stm32cubeprog.html) (requires an STM account, does not properly work on macOS) or the [open-source ST-Link command line utility](https://github.com/stlink-org/stlink). See the respective web site for installation instructions. +- `blackpill-f401cc.bin`: Firmware for BlackPill with STM32F401CC microcontroller +- `blackpill-f411ce.bin`: Firmware for BlackPill with STM32F411CE microcontroller +- `bluepill-f103c8.bin`: Firmware for BluePill with STM32F103C8 microcontroller -If the commmand line utility is used, run these commands to upload it: +### Upload using built-in bootloader + +To upload using the BlackPill's built-in bootloader: + +1. Install the *dfu-util* command-line utility (typically using a package manager like *HomeBrew* on macOS, *Chocolatey* on Windows, or *Apt* on Linux). +2. Press the *Boot* button while connecting the board via USB to your computer. By pressing the *Boot* button, the device enters bootloader mode. +3. Verify with `dfu-util --list` that the bootloader is available via USB. If not unplug the device and repeat step 2. +4. Run the below command from the project directory. +5. Unplug and reconnect the board from your computer. The LED should now blink about twice a second. ``` -cd stm32-loopback/bin -st-flash write firmware.bin 0x08000000 +dfu-util --device 0483:df11 --alt 0 --dfuse-address 0x08000000 --reset --download bin/blackpill-fxxx.bin ``` + +Make sure you change the filename `blackpill-fxxx.bin` to the name matching your board. + +If you built the firmware yourself, you will find the firmware file in `.pio/build/blackpill-f401cc/firmware.bin` (and similar for other boards). + +### Upload using ST-Link programmer + +In order to upload it using the ST-Link programmer: + +1. Install the *stlink* command-line utility (typically using a package manager like *HomeBrew* on macOS, *Chocolatey* on Windows, or *Apt* on Linux). +2. Unplug the microcontroller board from your computer (in case it is connected). +3. Connect the ST-Link via jumper wires to your board (4 pins on the short side of the board). +4. Connect the ST-Link via USB cable to your computer. +5. Run the below command from the project directory. +6. Unplug the microcontroller board from the ST-Link and connect it to your computer (via USB). + +``` +st-flash write bin/bluepill-f103c8.bin 0x08000000 +``` + +Make sure you change the filename `bluepill-f103c8.bin` to the name matching your board. + +If you built the firmware yourself, you will find the firmware file in `.pio/build/bluepill-f103c8/firmware.bin` (and similar for other boards). + +## Implementation + +This code uses the CMSIS 5 library (mainly for startup code and register definitions) and TinyUSB for USB. For easier use with PlatformIO, a copy of TinyUSB is integrated into the project. The used TinyUSB code in `lib/tinyusb` is an unmodified subset of the library. + +Since the official TinyUSB vendor class is rather limited, an alternative implementation is provided (see [vendor_custom.h](include/vendor_custom.h) and [vendor_custom.c](src/vendor_custom.c)). \ No newline at end of file diff --git a/test-devices/loopback-stm32/bin/blackpill-f401cc.bin b/test-devices/loopback-stm32/bin/blackpill-f401cc.bin new file mode 100755 index 0000000000000000000000000000000000000000..5b8ca41cd4be36cab0547b99417bcbd87b1ac4cb GIT binary patch literal 9908 zcmbVy4Rljgw(vRk-Xu3oO4FtT{R5KR>VyU{P}DM22{-9&X^Mp+SiyOwtv{(cV}w~6 z@Vy}|&Swic0@XFpe#|JK0t(VFQLB_xU>tu2C!y3=M2C)mSDI08+mzh?=IxWV$~fszmDot$&e*=O&4_St)%efB9r*l-ym_9p6I3;NOD6b$Jm?Nr6T&Y6Pw-_$=Mm!R># z!80{yiqC7mucbly|9@bn=1NqU)*>V}Z?){v(dA#B)oeL_YC zLYtIJ3^I(12vN>*2~{_{04j*SK|M1{GnO{FX-P{n7F{4Y#9ER==}wI+)tO$};yyV* z>(AVyad+A@E?v9M*)QJdUhb}N*H9-08q$!o7?lMzPS$yJL>gFWXG$yFCk8N&7gV65 zBmD#CMW9hY*1*C5lQSSR|Sv?JQ_hl9poghQmdr&SiSH zvy1~?^{#kqMSQ7~Kr#STTv{F-UXkYZkM#B9pRIveQ?q#q!+4&%GqJ{%HjC?`n~U1$ zi!Lrv+oOo)Tm~V@q%p>0Rq;Ip62@2B_7X_Rwmty~wOvB%Cm^)|SvCO){VQ#AO82@_ z-R3ePM_)pY*O%%6yHyX^_4-Nb4B#}DT3nrO<1)Zo(+SchwO#Vn=v^~m#tQciw?WW5 z<_X9&J0%-`_wyO6@B%hZ4kJ#Rav}rgFZ_A>I>u7oi&L*cAH7~~pU?po^uR`R!Gmm> zcP>$(TPd40p&OJ<*MoY9jx2=l*D*2_AhaB@lQGm;=7nr7YEz=$574fuw081_4R-(UdY|ESKU|Bpn!w$9Ban?gj3S ztZn>2r`}=kT0l=;h;!b}pfjB3ikJ&{3GOnoRwxcA*vtl!grx8mzota96iKT_;;}<< z!b?2%T#z=iVU?3IX1X>TluIW#oC6%9;1rLez$XHn^?*kmZuFYRY%u}K_H2RED3 z!WtsMLS)gq6kj9>1dj@6F>N}NVktej@_)QNg?9=k8;HjqjO$F)_b{KmO=#gc);}tQ zbm8W(-b+g^%9f`HS9_^ELx}Fid8r{}$m^l=aznS|4TZCnv97%hj3pYr*pOOkwwQxv z&M4@6W-23RFE${{*WqMmbwifRC|HjnNeX5vFF-$I`8=#DH45fL?^rNP89m!6VuSS< z(Uk)5erbbYJLrPd7Q5+S&QsZ+j`pPY5&%o9-__Z-CCz+*-F`9GYIim>KHQ7LfBu& zQ+=5F>a#m?s_wZ?o~|1dnUc#QGF${bUJiViflmy@Q|u{b1vZc=oK(}Hc+42b2DUvO z8yX)LZ@3~Yac+oPd_uB7hfuBoc1x<$dQ&!N9j|1Rx80Y$-@DHrkIj$wiJTWN&T&M= zKk@@-jDig`^8FEH9tcy;Z1;IpPZv7=H&KFfz!P8q8y1jZI>022THB8L^8_Pc_JGER z-t_?OZ-QhTNh9yZW5dBD#}5A%p6cA(*u+z3Y>gCr>jY16eZ$tQEqsfg>aK5Wh7rE8 zC9B0x*L#X%Kw}%6a>+vZ)%fGMu*H9rpB7F7Pl_WxtO`;45oeQ`+puIC$1R+TJ|eZR zl9?xe>iQbiJW$*&n{9jfMqzJ+Q4|E1G#>I71b>k=U8rv;2p;ku1TCW<_T6d{e9IkfG1N znV%*wXUsw>tR*|XzhQan!G=9Nd#<-(j@v4LpieMLFl)%N+Iy;#a0GYN~p=Hs#8 z_}6s?fhIfj+EFt%-Mvc@nLeJ-l^fO#(h1TOQAXoiv9&>SK`4Us7ZamI&0rd^bd0w;hNeb+?0X zh`3$%urjT~`OQT`VT-%MarZ1Lg0$5|%5a9Gtq-NV5-J6Ze-YDU9KkaFu1_?>-uVYn zxvsn3SAkCYcKCP0KGW+~&e~j8!6WWu9d_|`bUnzq7(scjk=oMe-{IfR>jE!DDEcYb zD_dg=NHrTQt0&9n*R>Y}PBhY67+6b6+_*&{)cc9oxnUffzEIG;w#T!~;0~1e6W|rGxy-K&K%Hw(D;Qwq(^ez^}iVXN2@H+PJN)pq~ zSc_WxYi6zG>+9?=$5Tvi(ZN}lDG)9{88g)D+C70&z|}tB>Ulm{*av(O+iwA_U7J-0 zl4$Yo;+0_eMws#57`0_{!w!FT+n=tW{MTHb_SS}%c+I&jy!MRMy@y8;O8HBd`i#Yg zxQBh;iuZvQe=AmG?eKpiZh_yHtUTYtzWuH*MU``9tIC<}-OMY`DN9krM(f-tauQAK z2nx&$m4RvLCd5FC)il$P%w_DZMr3cLQwBB=GBvxW*wb$xfYu#q= z&SHFXp;v;v>+hZcuy?D@e-Dee)3VZfT28ValBZcM-e)0-RB+GA3hOlIOyI?m-~}Hr z126ZED}fiw1TXX2!V~)%fPFnGqU)LRzkpn(jF5DIoM}{gUFfSEC~Fh3`?67Or(fmBH{Fmg*_WO zRH`l=VEjyl&k}s-_=tFULvl%xgcZnp`7tEDGmgyt;fotw1Bkx(7^&-_h8rrx2A6^F zOX8Fc5;_VeP@w1tPt%cb>Ia*Ugo!;Q)}#w)34Mx*@RRf}ZfH?y&ZVaw`*eV5ts{lkeCaa@uRsA3za{81WUmoxJFBl*S`t7G8fL) zJK=7;vlz~Y0}$tqS=@|}(2%)Ey03n>oNUE~Dhul0T7Thdy~H9tYNQ^d9;arbMN~bt zTh^j@EPWi}ppm`K-LlTm>^UP&^s1pZKKutKvU~_p+24lW7hB3;WI5+0>*72YHzjy{ zg47_(C!UuLR?_nn)D!LcL>oaIb#WMQdsLE(eY?+)i(A4@PShH16-{e@YdKn{B`FFfU_@0k-0sz*-cJ;Gx#ai zTrbQ#S67tXiA?IAR#JBId6Q<{_q74-qq>f%J+577Yc<6A-M!gTjbS_ zB=GF-@`t*ACu;hz=40?3#E%ktEP}I#*#1jO$m30(L;In>T~0%E(wbQv{%LuOuYPeD zzqCR&Nhnwgd(Z^sD3lAZKcxJ5vTy49zpK{+OgvUUl*Um)QqQkJ=NCu)hu?s_79}9_ z;^?b~?F|$1x_zkqE0BB`&IPc;#nEOMxg@Sj%-EHfF(9^sHpXK$Llbj^>*b!6X*=ZUHWQ5 zZx>&!Iy|AdvtS<OqWL!Dm@Yyz(7SK;J&XzViRwN7^f@umzNaS(5+?}FV6sd41@M>JT$!&gr zekjA+G0*`X?OFNJ%PF8$pTX$Ehja zRQ`@3WN7BiLYDA)&}YnqTR+^bj*&TXAaj{kP$l3Gy5X`$I5I=t*eDSD;%YT**f0Q*3k@EAXR$oVq4NBTZe;!n?t`-+H*;uwulvi!e8&O@ zWC9`TZQ{SI!=c6Va=W?OmbQsCfwbu*;Y`zMuxgdX^0`C<3t%F!;El{d4Lg?0J(1pxh;`}dI1rnuMO)`14C3Cw?~ zL~~id`~hG_CdezMQ2=>P49QH1BZ_|2LF(FEzy^?c>Pc*-1h$q*YyewekNRo=w&0jZ z)&$#TV?hQ;$Gcbhk%c{vjg&N-!oyVmS~b0NiOj)mVPgI0@2H2!YYH|QVArarpbhy< z0y;QQ{#KzV~5RVgBA4t~L>URdKcF zRikIQT4Wjh3}8yRsAr`;`r^uqt|fq@iNC+w2AJm< zuCp>KuuC+33TkNI&PgexeLLY=1zeM?eTN;g>h_7ueTcS89gyRnn8zgMRoB+k>g_dE z)$STM)UI^r-m1MYAJcnXL*`J{lOjKX^}8oaYNBDjbAfme3h65fHx8|=Kj zLw(yF`zp6Ipom?ej3}m`7)YYl)jhl6ruCoZyvYXq+ups+@eB08Ln${MhFf<29XB`3 zbG$kD;wHrx^Ah{^Ip8@j-e1i`?79!VAsMa360PK;h{yBz-v7hT7x-QUl}_wo1u`bt zJ7i=zE9aPX`PhJl=>fg{l$=xWj(9=-RmWL5x96CQ(9@YuINkyp2fED;pP%kq4ELVj zC|-w=j=>i_wqB*p?KZwWlC-NdbAOi}VlsGE`tY5-p|i0zLaWMT+JHEv z@TBXux)p6&r%B-C^yTOUk~b0H=1uZ=-p0U))ZgSsBWV>o{8U?V8_sX>qZdqq6*7dx zXA!<>tSUVNc8ChN=y;7C-eVAVLPi-`f)CEN;|U*!P4Iru4jO^sY^?k!!4dJ0+E7?V zi#T{0dJk&S23=iA+MZ(gDx4fCB<;zO!YRK&?qlyb75KR$|8_Uk^sCy|TCFWT>brNd zKt~kRt)cR$Z{_-`85{j2J~%~@w0fi!B&qitDb;&mm&~T;7nRGqj@ELLjy_sNwcLAm;X|~P!k!#R$~-w>x8p(u z+?2oZk(=@?RE_?M?nV(b11Tf+RGbewVBz6K8MMQaD^lDVkzis06ZobCc|ktaW4qhpm?30uymz>Mw5AC4clhYY@94EC1$5e8 zjW~@5_AkMikw$&*_^Ro&E|}YFajd>Od!wRBIjE~qHqC;QN~1@)>Lx|Y-{CHW`n7c_ ziRf4rDaq)b)P@hBei!`6@)yf{OZ0TpN=K#JbF@?dK39y#j*KNc>E`B)m5t7#{paYG zLPw{p%horpg-oZu?rn(jcf%W5YQr8G`POC~lv(Qw*Tf20U~{=ph`+F69m;{4*dpDs z25h>#cNac=g-L^Vk6#0|dzcpT`mw%i{B`G z!B2NXv_B8-%NB83gwMeX zj>$!9~9<`MBW$V^gVaMUZLxoWY*X3-&VBg>LS3KQK0P8;g4oRhll$!K}hHZSTN(ZLMfqs!$21;IUzR^V=e8JR{!YBsiQ7 z&Hl{BsA$XDO(=IUu3=pw}K?V|C+1u z-Lle(hIL2Lj!L*?zHFvf$x9d}RVF5N#!;GBKOQ+<7EVU;GKD4Wv_GXm#(m#VY z1)6QTmHc0YdbUH=40(ZpX5Q3Ipwehd8=1}Zvf!Tp%fiE7El6-$=%@n!pS3l4#}B*$ zk2)1cBtSSGkNsloxR_VFVe3zw@S;XPwVm1tn)g@(KO;=y*bfgYX3(-4|gSP2q z15$>LgRZd+Ot8^w>&3QG$UkK{epVF{nVrjJCY#yD3ZH=FKNZ#1JIl%0Nc4LuMjnmR zXgv1*vCRz~kn5unWd`3tr-ib+u{k+R&9U{z7eKrl^;I|X$!C(`HD3prLl$zz2^zU>|ssW}i)1H8@D%zxF{4|YaqS_4Ur?L6wVwwHMobCuy|ybNSK zQKU$5No`rB^%@=D!RuD?9m!?;viIrGbuaVku;vbJ8ItD8Q$32Xr+u}2ofYmoH+?Hk zwfe;dh>xerGtkxr?6VTo!n$^Nb#u}(E{}( z*S6tQP5fbsW|S&cZJoa$f8k9x-%_w>32%242}n)NLl`69u$n=Li36}ofhilQ>L)6i z)*+orv6)n97*POY8~^ByPaZ>n6sOV4&`KnrJJEc&yIRpLsI=Zz`(c^J?lq=)s)hVnY>nVEE829ZE8@rUnPdIy>Dqrbny-Toq!F(_o{@?;Io<#zZ1 orV&yg)CL>*0u=K9J;TtYo`%?5_+KL(f(#~voU;iW{E-Fz7jfpbd;kCd literal 0 HcmV?d00001 diff --git a/test-devices/loopback-stm32/bin/blackpill-f411ce.bin b/test-devices/loopback-stm32/bin/blackpill-f411ce.bin new file mode 100755 index 0000000000000000000000000000000000000000..2c0ede51034acf7076159f119167b8808f580829 GIT binary patch literal 9912 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 r9U8ziLJEXhVIy}zA^+bq1YLXQ#7r?gK literal 0 HcmV?d00001 diff --git a/test-devices/loopback-stm32/bin/bluepill-f103c8.bin b/test-devices/loopback-stm32/bin/bluepill-f103c8.bin new file mode 100755 index 0000000000000000000000000000000000000000..3415d0d85bee1905fcaf1eb5a84c88e9b81bb5ed GIT binary patch literal 8112 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 RgCG-u`qUB(1RrMbzX2j-N-zKb literal 0 HcmV?d00001 diff --git a/test-devices/loopback-stm32/bin/firmware.bin b/test-devices/loopback-stm32/bin/firmware.bin deleted file mode 100755 index b691999df54fa8bcb7e6a474088f7cf50d5f8842..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6536 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 diff --git a/test-devices/loopback-stm32/bin/save_bin.sh b/test-devices/loopback-stm32/bin/save_bin.sh deleted file mode 100755 index 0e134cfb..00000000 --- a/test-devices/loopback-stm32/bin/save_bin.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -cp ../.pio/build/loopback-stm32/firmware.bin . diff --git a/test-devices/loopback-stm32/bin/upload_firmware.sh b/test-devices/loopback-stm32/bin/upload_firmware.sh deleted file mode 100755 index 20ad778e..00000000 --- a/test-devices/loopback-stm32/bin/upload_firmware.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -st-flash write firmware.bin 0x08000000 diff --git a/test-devices/loopback-stm32/include/board.h b/test-devices/loopback-stm32/include/board.h new file mode 100644 index 00000000..4e032fd4 --- /dev/null +++ b/test-devices/loopback-stm32/include/board.h @@ -0,0 +1,37 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Board specific functions (HAL) +// + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +// Initialize the board +void board_init(void); + +// Set the LED on or off +void board_led_write(bool on); + +// Return the number of milliseconds since a time in the past +uint32_t board_millis(void); + +// USB serial number +extern char board_serial_num[13]; + + +#ifdef __cplusplus +} +#endif diff --git a/test-devices/loopback-stm32/include/circ_buf.h b/test-devices/loopback-stm32/include/circ_buf.h deleted file mode 100644 index 4d9a6970..00000000 --- a/test-devices/loopback-stm32/include/circ_buf.h +++ /dev/null @@ -1,155 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Circular buffer for raw binary data. -// -// The circular buffer allows a reader and writer to -// use the buffer concurrently. -// - -#pragma once - -#include -#include - -#include - -/** - * Circular buffer for raw binary data. - * - * The circular buffer allows a reader and writer to - * use the buffer concurrently. - * - * @param N number of bytes that fit into the buffer - */ -template -struct circ_buf { - private: - static constexpr int BUF_SIZE = N + 1; - - // 0 <= head < BUF_SIZE - // 0 <= tail < BUF_SIZE - // head == tail: buffer is empty - // Therefore, the buffer must never be filled completely. - volatile int buf_head = 0; // updated when adding data - volatile int buf_tail = 0; // updated when removing data - - uint8_t buffer[BUF_SIZE]; - - public: - /// Creates a new instance - circ_buf(); - - /// Returns the maximum number of bytes that can be added to the buffer - int avail_size(); - - /// Returns the number of bytes in the buffer - int data_size(); - - /** - * Gets the oldest data from the buffer and removes it. - * @param buf buffer to copy data to - * @param max_len maximum number of bytes to copy - * @return the effective number of bytes - */ - int get_data(uint8_t *buf, int max_len); - - /** - * Adds data to the buffer - * - * @param buf the buffer with the data - * @param len the number of bytes to add - */ - void add_data(const uint8_t *buf, int len); - - /// Resets (empties) the circular buffer - void reset(); -}; - -template -circ_buf::circ_buf() : buf_head(0), buf_tail(0) {} - -template -int circ_buf::avail_size() { - int head = buf_head; - int tail = buf_tail; - - if (head >= tail) { - return BUF_SIZE - (head - tail) - 1; - } else { - return tail - head - 1; - } -} - -template -int circ_buf::data_size() { - int head = buf_head; - int tail = buf_tail; - - if (head >= tail) { - return head - tail; - } else { - return BUF_SIZE - (tail - head); - } -} - -template -int circ_buf::get_data(uint8_t *buf, int max_len) { - int tail = buf_tail; - int head = buf_head; - - if (tail == head) - return 0; - - // get available data (without wrap around) - int len = (head > tail ? head : BUF_SIZE) - tail; - - // limit data to max_len - len = std::min(len, max_len); - - // copy data - memcpy(buf, buffer + tail, len); - - // update tail - tail += len; - if (tail >= BUF_SIZE) - tail -= BUF_SIZE; - buf_tail = tail; - - // sufficient data or no more data - if (len == max_len || tail != 0) - return len; - - // copy more data - return get_data(buf + len, max_len - len) + len; -} - -template -void circ_buf::add_data(const uint8_t *buf, int len) { - int head = buf_head; - - // copy first part (from head to end of circular buffer) - int n = std::min(len, BUF_SIZE - head); - memcpy(buffer + head, buf, n); - - // copy second part if needed (to start of circular buffer) - if (n < len) - memcpy(buffer, buf + n, len - n); - - // update head - head += len; - if (head >= BUF_SIZE) - head -= BUF_SIZE; - buf_head = head; -} - -template -void circ_buf::reset() { - buf_head = 0; - buf_tail = 0; -} diff --git a/test-devices/loopback-stm32/include/common.h b/test-devices/loopback-stm32/include/common.h deleted file mode 100644 index 427b2eb4..00000000 --- a/test-devices/loopback-stm32/include/common.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Commmon functions -// - -#pragma once - -#include - -/** - * @brief Initializes systick services - */ -void systick_init(); - -/** - * @brief Gets the time. - * - * @return number of milliseconds since a fixed time in the past - */ -uint32_t millis(); - -/** - * @brief Delays execution (busy wait) - * @param ms delay length, in milliseconds - */ -void delay(uint32_t ms); diff --git a/test-devices/loopback-stm32/include/usb_descriptor.h b/test-devices/loopback-stm32/include/usb_descriptors.h similarity index 59% rename from test-devices/loopback-stm32/include/usb_descriptor.h rename to test-devices/loopback-stm32/include/usb_descriptors.h index d200756a..1677a600 100644 --- a/test-devices/loopback-stm32/include/usb_descriptor.h +++ b/test-devices/loopback-stm32/include/usb_descriptors.h @@ -11,7 +11,7 @@ #pragma once -#include +#include #define INTR_MAX_PACKET_SIZE 16 #define BULK_MAX_PACKET_SIZE 64 @@ -22,11 +22,9 @@ #define EP_ECHO_RX 0x03 #define EP_ECHO_TX 0x83 -// USB descriptor string table -extern const char *const usb_desc_strings[4]; -// USB device descriptor -extern const struct usb_device_descriptor usb_device_desc; -// USB device configurations -extern const struct usb_config_descriptor usb_config_descs[]; +#define WCID_VENDOR_CODE 0x37 + +const uint8_t wcid_feature_desc[40]; + void usb_init_serial_num(); diff --git a/test-devices/loopback-stm32/include/vendor_custom.h b/test-devices/loopback-stm32/include/vendor_custom.h new file mode 100644 index 00000000..03976045 --- /dev/null +++ b/test-devices/loopback-stm32/include/vendor_custom.h @@ -0,0 +1,115 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// USB driver for interfaces with vendor specific class. +// The interface can have any number of bulk and interrupt endpoints. +// + +#pragma once + +#include "common/tusb_common.h" +#include "device/usbd_pvt.h" + +// --- Macro to create USB configuration descriptor + +// Interface descriptor: interface number, number of endponts +#define CUSTOM_VENDOR_INTERFACE(_itfnum, _numeps) \ + /* Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, _numeps, TUSB_CLASS_VENDOR_SPECIFIC, 0x00, 0x00, 0 + +// Bulk endpoint descriptor: endpoint address, packet size +#define CUSTOM_VENDOR_BULK_ENDPOINT(_epaddr, _packetsize) \ + /* Endpoint */\ + 7, TUSB_DESC_ENDPOINT, _epaddr, TUSB_XFER_BULK, U16_TO_U8S_LE(_packetsize), 0 + +// Interrupt endpoint descriptor: endpoint address, packet size, interval +#define CUSTOM_VENDOR_INTERRUPT_ENDPOINT(_epaddr, _packetsize, _interval) \ + /* Endpoint */\ + 7, TUSB_DESC_ENDPOINT, _epaddr, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_packetsize), _interval + + +// --- Application API + +/** + * @brief Prepares to recieve data on an OUT endpoint. + * + * The buffer must stay valid until the `cust_vendor_rx_cb()` callback + * reports that data has been received. + * + * If the OUT endpoint is already receiving data, this function does nothing. + * + * @param ep_addr endpoint address (1 to 127) + * @param buf pointer to buffer for received data + * @param buf_len length of buffer + */ +void cust_vendor_prepare_recv(uint8_t ep_addr, void* buf, uint32_t buf_len); + +/** + * @brief Gets if the endpoint is busy receiving data. + * + * @param ep_addr endpoint address (1 to 127) + * @return true if the endpoint is busy receiving + * @return false it the endpoint is idle + */ +bool cust_vendor_is_receiving(uint8_t ep_addr); + +/** + * @brief Transmits data on an IN endpoint. + * + * The data must stay valid until the `cust_vendor_tx_cb()` callback + * reports that the data has been transmitted. + * + * If the IN endpoint is already transmitting data, this function does nothing. + * + * @param ep_addr endpoint address (129 to 255) + * @param data pointer to data to transmit + * @param data_len number of bytes to transmit + */ +void cust_vendor_start_transmit(uint8_t ep_addr, void const * data, uint32_t data_len); + +/** + * @brief Gets if the endpoint is busy transmitting data. + * + * @param ep_addr endpoint address (129 to 255) + * @return true if the endpoint is busy transmitting + * @return false it the endpoint is idle + */ +bool cust_vendor_is_transmitting(uint8_t ep_addr); + + +// --- Application Callback API + +/** + * @brief Invoked when new data has been received on an OUT endpoint. + * + * @param ep_addr endpoint address (1 to 127) + * @param recv_bytes number of received bytes + */ +TU_ATTR_WEAK void cust_vendor_rx_cb(uint8_t ep_addr, uint32_t recv_bytes); + +/** + * @brief Invoked when data has been transmitted on an IN endpoint. + * + * @param ep_addr endpoint address (129 to 255) + * @param sent_bytes number of sent bytes + */ +TU_ATTR_WEAK void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes); + +/** + * @brief Invoked when an interface of this class has been opened. + * + * This function is called as part of a SET CONFIGURATION control request. + * + * @param intf interface number + */ +TU_ATTR_WEAK void cust_vendor_intf_open_cb(uint8_t intf); + + +// --- Driver to be registered in usbd_app_driver_get_cb() + +const usbd_class_driver_t cust_vendor_driver; diff --git a/test-devices/loopback-stm32/include/wcid.h b/test-devices/loopback-stm32/include/wcid.h deleted file mode 100644 index 2c1041ef..00000000 --- a/test-devices/loopback-stm32/include/wcid.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Microsoft WCID descriptors -// - -#pragma once - -#include - -// Register control request handlers for Microsoft WCID descriptors -void register_wcid_desc(usbd_device *usb_dev); diff --git a/test-devices/loopback-stm32/lib/config/tusb_config.h b/test-devices/loopback-stm32/lib/config/tusb_config.h new file mode 100644 index 00000000..1b5a6a01 --- /dev/null +++ b/test-devices/loopback-stm32/lib/config/tusb_config.h @@ -0,0 +1,122 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef _TUSB_CONFIG_H_ +#define _TUSB_CONFIG_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Board Specific Configuration +//--------------------------------------------------------------------+ + +// RHPort number used for device can be defined by board.mk, default to port 0 +#ifndef BOARD_TUD_RHPORT +#define BOARD_TUD_RHPORT 0 +#endif + +// RHPort max operational speed can defined by board.mk +#ifndef BOARD_TUD_MAX_SPEED +#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED +#endif + +//-------------------------------------------------------------------- +// COMMON CONFIGURATION +//-------------------------------------------------------------------- + +// defined by compiler flags for flexibility +#ifndef CFG_TUSB_MCU +#error CFG_TUSB_MCU must be defined +#endif + +#ifndef CFG_TUSB_OS +#define CFG_TUSB_OS OPT_OS_NONE +#endif + +#ifndef CFG_TUSB_DEBUG +#define CFG_TUSB_DEBUG 0 +#endif + +// Enable Device stack +#define CFG_TUD_ENABLED 1 + +// Default is max speed that hardware controller could support with on-chip PHY +#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED + +/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. + * Tinyusb use follows macros to declare transferring memory so that they can be put + * into those specific section. + * e.g + * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) + * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) + */ +#ifndef CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_SECTION +#endif + +#ifndef CFG_TUSB_MEM_ALIGN +#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) +#endif + +//-------------------------------------------------------------------- +// DEVICE CONFIGURATION +//-------------------------------------------------------------------- + +#ifndef CFG_TUD_ENDPOINT0_SIZE +#define CFG_TUD_ENDPOINT0_SIZE 64 +#endif + +//------------- CLASS -------------// +#ifndef CFG_TUD_CDC +#define CFG_TUD_CDC 0 +#endif +#ifndef CFG_TUD_MSC +#define CFG_TUD_MSC 0 +#endif +#ifndef CFG_TUD_HID +#define CFG_TUD_HID 0 +#endif +#ifndef CFG_TUD_MIDI +#define CFG_TUD_MIDI 0 +#endif +#ifndef CFG_TUD_VENDOR +#define CFG_TUD_VENDOR 0 +#endif + +// HID buffer size Should be sufficient to hold ID (if any) + Data +#define CFG_TUD_HID_EP_BUFSIZE 64 + +// Vendor FIFO size of TX and RX +// If not configured vendor endpoints will not be buffered +#define CFG_TUD_VENDOR_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) +#define CFG_TUD_VENDOR_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CONFIG_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/audio/audio.h b/test-devices/loopback-stm32/lib/tinyusb/class/audio/audio.h new file mode 100644 index 00000000..6f9c1a6b --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/audio/audio.h @@ -0,0 +1,933 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2020 Reinhard Panhuber + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup group_class + * \defgroup ClassDriver_Audio Audio + * Currently only MIDI subclass is supported + * @{ */ + +#ifndef _TUSB_AUDIO_H__ +#define _TUSB_AUDIO_H__ + +#include "common/tusb_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Audio Device Class Codes + +/// A.2 - Audio Function Subclass Codes +typedef enum +{ + AUDIO_FUNCTION_SUBCLASS_UNDEFINED = 0x00, +} audio_function_subclass_type_t; + +/// A.3 - Audio Function Protocol Codes +typedef enum +{ + AUDIO_FUNC_PROTOCOL_CODE_UNDEF = 0x00, + AUDIO_FUNC_PROTOCOL_CODE_V2 = 0x20, ///< Version 2.0 +} audio_function_protocol_code_t; + +/// A.5 - Audio Interface Subclass Codes +typedef enum +{ + AUDIO_SUBCLASS_UNDEFINED = 0x00, + AUDIO_SUBCLASS_CONTROL , ///< Audio Control + AUDIO_SUBCLASS_STREAMING , ///< Audio Streaming + AUDIO_SUBCLASS_MIDI_STREAMING , ///< MIDI Streaming +} audio_subclass_type_t; + +/// A.6 - Audio Interface Protocol Codes +typedef enum +{ + AUDIO_INT_PROTOCOL_CODE_UNDEF = 0x00, + AUDIO_INT_PROTOCOL_CODE_V2 = 0x20, ///< Version 2.0 +} audio_interface_protocol_code_t; + +/// A.7 - Audio Function Category Codes +typedef enum +{ + AUDIO_FUNC_UNDEF = 0x00, + AUDIO_FUNC_DESKTOP_SPEAKER = 0x01, + AUDIO_FUNC_HOME_THEATER = 0x02, + AUDIO_FUNC_MICROPHONE = 0x03, + AUDIO_FUNC_HEADSET = 0x04, + AUDIO_FUNC_TELEPHONE = 0x05, + AUDIO_FUNC_CONVERTER = 0x06, + AUDIO_FUNC_SOUND_RECODER = 0x07, + AUDIO_FUNC_IO_BOX = 0x08, + AUDIO_FUNC_MUSICAL_INSTRUMENT = 0x09, + AUDIO_FUNC_PRO_AUDIO = 0x0A, + AUDIO_FUNC_AUDIO_VIDEO = 0x0B, + AUDIO_FUNC_CONTROL_PANEL = 0x0C, + AUDIO_FUNC_OTHER = 0xFF, +} audio_function_code_t; + +/// A.9 - Audio Class-Specific AC Interface Descriptor Subtypes UAC2 +typedef enum +{ + AUDIO_CS_AC_INTERFACE_AC_DESCRIPTOR_UNDEF = 0x00, + AUDIO_CS_AC_INTERFACE_HEADER = 0x01, + AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL = 0x02, + AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL = 0x03, + AUDIO_CS_AC_INTERFACE_MIXER_UNIT = 0x04, + AUDIO_CS_AC_INTERFACE_SELECTOR_UNIT = 0x05, + AUDIO_CS_AC_INTERFACE_FEATURE_UNIT = 0x06, + AUDIO_CS_AC_INTERFACE_EFFECT_UNIT = 0x07, + AUDIO_CS_AC_INTERFACE_PROCESSING_UNIT = 0x08, + AUDIO_CS_AC_INTERFACE_EXTENSION_UNIT = 0x09, + AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE = 0x0A, + AUDIO_CS_AC_INTERFACE_CLOCK_SELECTOR = 0x0B, + AUDIO_CS_AC_INTERFACE_CLOCK_MULTIPLIER = 0x0C, + AUDIO_CS_AC_INTERFACE_SAMPLE_RATE_CONVERTER = 0x0D, +} audio_cs_ac_interface_subtype_t; + +/// A.10 - Audio Class-Specific AS Interface Descriptor Subtypes UAC2 +typedef enum +{ + AUDIO_CS_AS_INTERFACE_AS_DESCRIPTOR_UNDEF = 0x00, + AUDIO_CS_AS_INTERFACE_AS_GENERAL = 0x01, + AUDIO_CS_AS_INTERFACE_FORMAT_TYPE = 0x02, + AUDIO_CS_AS_INTERFACE_ENCODER = 0x03, + AUDIO_CS_AS_INTERFACE_DECODER = 0x04, +} audio_cs_as_interface_subtype_t; + +/// A.11 - Effect Unit Effect Types +typedef enum +{ + AUDIO_EFFECT_TYPE_UNDEF = 0x00, + AUDIO_EFFECT_TYPE_PARAM_EQ_SECTION = 0x01, + AUDIO_EFFECT_TYPE_REVERBERATION = 0x02, + AUDIO_EFFECT_TYPE_MOD_DELAY = 0x03, + AUDIO_EFFECT_TYPE_DYN_RANGE_COMP = 0x04, +} audio_effect_unit_effect_type_t; + +/// A.12 - Processing Unit Process Types +typedef enum +{ + AUDIO_PROCESS_TYPE_UNDEF = 0x00, + AUDIO_PROCESS_TYPE_UP_DOWN_MIX = 0x01, + AUDIO_PROCESS_TYPE_DOLBY_PROLOGIC = 0x02, + AUDIO_PROCESS_TYPE_STEREO_EXTENDER = 0x03, +} audio_processing_unit_process_type_t; + +/// A.13 - Audio Class-Specific EP Descriptor Subtypes UAC2 +typedef enum +{ + AUDIO_CS_EP_SUBTYPE_UNDEF = 0x00, + AUDIO_CS_EP_SUBTYPE_GENERAL = 0x01, +} audio_cs_ep_subtype_t; + +/// A.14 - Audio Class-Specific Request Codes +typedef enum +{ + AUDIO_CS_REQ_UNDEF = 0x00, + AUDIO_CS_REQ_CUR = 0x01, + AUDIO_CS_REQ_RANGE = 0x02, + AUDIO_CS_REQ_MEM = 0x03, +} audio_cs_req_t; + +/// A.17 - Control Selector Codes + +/// A.17.1 - Clock Source Control Selectors +typedef enum +{ + AUDIO_CS_CTRL_UNDEF = 0x00, + AUDIO_CS_CTRL_SAM_FREQ = 0x01, + AUDIO_CS_CTRL_CLK_VALID = 0x02, +} audio_clock_src_control_selector_t; + +/// A.17.2 - Clock Selector Control Selectors +typedef enum +{ + AUDIO_CX_CTRL_UNDEF = 0x00, + AUDIO_CX_CTRL_CONTROL = 0x01, +} audio_clock_sel_control_selector_t; + +/// A.17.3 - Clock Multiplier Control Selectors +typedef enum +{ + AUDIO_CM_CTRL_UNDEF = 0x00, + AUDIO_CM_CTRL_NUMERATOR_CONTROL = 0x01, + AUDIO_CM_CTRL_DENOMINATOR_CONTROL = 0x02, +} audio_clock_mul_control_selector_t; + +/// A.17.4 - Terminal Control Selectors +typedef enum +{ + AUDIO_TE_CTRL_UNDEF = 0x00, + AUDIO_TE_CTRL_COPY_PROTECT = 0x01, + AUDIO_TE_CTRL_CONNECTOR = 0x02, + AUDIO_TE_CTRL_OVERLOAD = 0x03, + AUDIO_TE_CTRL_CLUSTER = 0x04, + AUDIO_TE_CTRL_UNDERFLOW = 0x05, + AUDIO_TE_CTRL_OVERFLOW = 0x06, + AUDIO_TE_CTRL_LATENCY = 0x07, +} audio_terminal_control_selector_t; + +/// A.17.5 - Mixer Control Selectors +typedef enum +{ + AUDIO_MU_CTRL_UNDEF = 0x00, + AUDIO_MU_CTRL_MIXER = 0x01, + AUDIO_MU_CTRL_CLUSTER = 0x02, + AUDIO_MU_CTRL_UNDERFLOW = 0x03, + AUDIO_MU_CTRL_OVERFLOW = 0x04, + AUDIO_MU_CTRL_LATENCY = 0x05, +} audio_mixer_control_selector_t; + +/// A.17.6 - Selector Control Selectors +typedef enum +{ + AUDIO_SU_CTRL_UNDEF = 0x00, + AUDIO_SU_CTRL_SELECTOR = 0x01, + AUDIO_SU_CTRL_LATENCY = 0x02, +} audio_sel_control_selector_t; + +/// A.17.7 - Feature Unit Control Selectors +typedef enum +{ + AUDIO_FU_CTRL_UNDEF = 0x00, + AUDIO_FU_CTRL_MUTE = 0x01, + AUDIO_FU_CTRL_VOLUME = 0x02, + AUDIO_FU_CTRL_BASS = 0x03, + AUDIO_FU_CTRL_MID = 0x04, + AUDIO_FU_CTRL_TREBLE = 0x05, + AUDIO_FU_CTRL_GRAPHIC_EQUALIZER = 0x06, + AUDIO_FU_CTRL_AGC = 0x07, + AUDIO_FU_CTRL_DELAY = 0x08, + AUDIO_FU_CTRL_BASS_BOOST = 0x09, + AUDIO_FU_CTRL_LOUDNESS = 0x0A, + AUDIO_FU_CTRL_INPUT_GAIN = 0x0B, + AUDIO_FU_CTRL_GAIN_PAD = 0x0C, + AUDIO_FU_CTRL_INVERTER = 0x0D, + AUDIO_FU_CTRL_UNDERFLOW = 0x0E, + AUDIO_FU_CTRL_OVERVLOW = 0x0F, + AUDIO_FU_CTRL_LATENCY = 0x10, +} audio_feature_unit_control_selector_t; + +/// A.17.8 Effect Unit Control Selectors + +/// A.17.8.1 Parametric Equalizer Section Effect Unit Control Selectors +typedef enum +{ + AUDIO_PE_CTRL_UNDEF = 0x00, + AUDIO_PE_CTRL_ENABLE = 0x01, + AUDIO_PE_CTRL_CENTERFREQ = 0x02, + AUDIO_PE_CTRL_QFACTOR = 0x03, + AUDIO_PE_CTRL_GAIN = 0x04, + AUDIO_PE_CTRL_UNDERFLOW = 0x05, + AUDIO_PE_CTRL_OVERFLOW = 0x06, + AUDIO_PE_CTRL_LATENCY = 0x07, +} audio_parametric_equalizer_control_selector_t; + +/// A.17.8.2 Reverberation Effect Unit Control Selectors +typedef enum +{ + AUDIO_RV_CTRL_UNDEF = 0x00, + AUDIO_RV_CTRL_ENABLE = 0x01, + AUDIO_RV_CTRL_TYPE = 0x02, + AUDIO_RV_CTRL_LEVEL = 0x03, + AUDIO_RV_CTRL_TIME = 0x04, + AUDIO_RV_CTRL_FEEDBACK = 0x05, + AUDIO_RV_CTRL_PREDELAY = 0x06, + AUDIO_RV_CTRL_DENSITY = 0x07, + AUDIO_RV_CTRL_HIFREQ_ROLLOFF = 0x08, + AUDIO_RV_CTRL_UNDERFLOW = 0x09, + AUDIO_RV_CTRL_OVERFLOW = 0x0A, + AUDIO_RV_CTRL_LATENCY = 0x0B, +} audio_reverberation_effect_control_selector_t; + +/// A.17.8.3 Modulation Delay Effect Unit Control Selectors +typedef enum +{ + AUDIO_MD_CTRL_UNDEF = 0x00, + AUDIO_MD_CTRL_ENABLE = 0x01, + AUDIO_MD_CTRL_BALANCE = 0x02, + AUDIO_MD_CTRL_RATE = 0x03, + AUDIO_MD_CTRL_DEPTH = 0x04, + AUDIO_MD_CTRL_TIME = 0x05, + AUDIO_MD_CTRL_FEEDBACK = 0x06, + AUDIO_MD_CTRL_UNDERFLOW = 0x07, + AUDIO_MD_CTRL_OVERFLOW = 0x08, + AUDIO_MD_CTRL_LATENCY = 0x09, +} audio_modulation_delay_control_selector_t; + +/// A.17.8.4 Dynamic Range Compressor Effect Unit Control Selectors +typedef enum +{ + AUDIO_DR_CTRL_UNDEF = 0x00, + AUDIO_DR_CTRL_ENABLE = 0x01, + AUDIO_DR_CTRL_COMPRESSION_RATE = 0x02, + AUDIO_DR_CTRL_MAXAMPL = 0x03, + AUDIO_DR_CTRL_THRESHOLD = 0x04, + AUDIO_DR_CTRL_ATTACK_TIME = 0x05, + AUDIO_DR_CTRL_RELEASE_TIME = 0x06, + AUDIO_DR_CTRL_UNDERFLOW = 0x07, + AUDIO_DR_CTRL_OVERFLOW = 0x08, + AUDIO_DR_CTRL_LATENCY = 0x09, +} audio_dynamic_range_compression_control_selector_t; + +/// A.17.9 Processing Unit Control Selectors + +/// A.17.9.1 Up/Down-mix Processing Unit Control Selectors +typedef enum +{ + AUDIO_UD_CTRL_UNDEF = 0x00, + AUDIO_UD_CTRL_ENABLE = 0x01, + AUDIO_UD_CTRL_MODE_SELECT = 0x02, + AUDIO_UD_CTRL_CLUSTER = 0x03, + AUDIO_UD_CTRL_UNDERFLOW = 0x04, + AUDIO_UD_CTRL_OVERFLOW = 0x05, + AUDIO_UD_CTRL_LATENCY = 0x06, +} audio_up_down_mix_control_selector_t; + +/// A.17.9.2 Dolby Prologic ™ Processing Unit Control Selectors +typedef enum +{ + AUDIO_DP_CTRL_UNDEF = 0x00, + AUDIO_DP_CTRL_ENABLE = 0x01, + AUDIO_DP_CTRL_MODE_SELECT = 0x02, + AUDIO_DP_CTRL_CLUSTER = 0x03, + AUDIO_DP_CTRL_UNDERFLOW = 0x04, + AUDIO_DP_CTRL_OVERFLOW = 0x05, + AUDIO_DP_CTRL_LATENCY = 0x06, +} audio_dolby_prologic_control_selector_t; + +/// A.17.9.3 Stereo Extender Processing Unit Control Selectors +typedef enum +{ + AUDIO_ST_EXT_CTRL_UNDEF = 0x00, + AUDIO_ST_EXT_CTRL_ENABLE = 0x01, + AUDIO_ST_EXT_CTRL_WIDTH = 0x02, + AUDIO_ST_EXT_CTRL_UNDERFLOW = 0x03, + AUDIO_ST_EXT_CTRL_OVERFLOW = 0x04, + AUDIO_ST_EXT_CTRL_LATENCY = 0x05, +} audio_stereo_extender_control_selector_t; + +/// A.17.10 Extension Unit Control Selectors +typedef enum +{ + AUDIO_XU_CTRL_UNDEF = 0x00, + AUDIO_XU_CTRL_ENABLE = 0x01, + AUDIO_XU_CTRL_CLUSTER = 0x02, + AUDIO_XU_CTRL_UNDERFLOW = 0x03, + AUDIO_XU_CTRL_OVERFLOW = 0x04, + AUDIO_XU_CTRL_LATENCY = 0x05, +} audio_extension_unit_control_selector_t; + +/// A.17.11 AudioStreaming Interface Control Selectors +typedef enum +{ + AUDIO_AS_CTRL_UNDEF = 0x00, + AUDIO_AS_CTRL_ACT_ALT_SETTING = 0x01, + AUDIO_AS_CTRL_VAL_ALT_SETTINGS = 0x02, + AUDIO_AS_CTRL_AUDIO_DATA_FORMAT = 0x03, +} audio_audiostreaming_interface_control_selector_t; + +/// A.17.12 Encoder Control Selectors +typedef enum +{ + AUDIO_EN_CTRL_UNDEF = 0x00, + AUDIO_EN_CTRL_BIT_RATE = 0x01, + AUDIO_EN_CTRL_QUALITY = 0x02, + AUDIO_EN_CTRL_VBR = 0x03, + AUDIO_EN_CTRL_TYPE = 0x04, + AUDIO_EN_CTRL_UNDERFLOW = 0x05, + AUDIO_EN_CTRL_OVERFLOW = 0x06, + AUDIO_EN_CTRL_ENCODER_ERROR = 0x07, + AUDIO_EN_CTRL_PARAM1 = 0x08, + AUDIO_EN_CTRL_PARAM2 = 0x09, + AUDIO_EN_CTRL_PARAM3 = 0x0A, + AUDIO_EN_CTRL_PARAM4 = 0x0B, + AUDIO_EN_CTRL_PARAM5 = 0x0C, + AUDIO_EN_CTRL_PARAM6 = 0x0D, + AUDIO_EN_CTRL_PARAM7 = 0x0E, + AUDIO_EN_CTRL_PARAM8 = 0x0F, +} audio_encoder_control_selector_t; + +/// A.17.13 Decoder Control Selectors + +/// A.17.13.1 MPEG Decoder Control Selectors +typedef enum +{ + AUDIO_MPD_CTRL_UNDEF = 0x00, + AUDIO_MPD_CTRL_DUAL_CHANNEL = 0x01, + AUDIO_MPD_CTRL_SECOND_STEREO = 0x02, + AUDIO_MPD_CTRL_MULTILINGUAL = 0x03, + AUDIO_MPD_CTRL_DYN_RANGE = 0x04, + AUDIO_MPD_CTRL_SCALING = 0x05, + AUDIO_MPD_CTRL_HILO_SCALING = 0x06, + AUDIO_MPD_CTRL_UNDERFLOW = 0x07, + AUDIO_MPD_CTRL_OVERFLOW = 0x08, + AUDIO_MPD_CTRL_DECODER_ERROR = 0x09, +} audio_MPEG_decoder_control_selector_t; + +/// A.17.13.2 AC-3 Decoder Control Selectors +typedef enum +{ + AUDIO_AD_CTRL_UNDEF = 0x00, + AUDIO_AD_CTRL_MODE = 0x01, + AUDIO_AD_CTRL_DYN_RANGE = 0x02, + AUDIO_AD_CTRL_SCALING = 0x03, + AUDIO_AD_CTRL_HILO_SCALING = 0x04, + AUDIO_AD_CTRL_UNDERFLOW = 0x05, + AUDIO_AD_CTRL_OVERFLOW = 0x06, + AUDIO_AD_CTRL_DECODER_ERROR = 0x07, +} audio_AC3_decoder_control_selector_t; + +/// A.17.13.3 WMA Decoder Control Selectors +typedef enum +{ + AUDIO_WD_CTRL_UNDEF = 0x00, + AUDIO_WD_CTRL_UNDERFLOW = 0x01, + AUDIO_WD_CTRL_OVERFLOW = 0x02, + AUDIO_WD_CTRL_DECODER_ERROR = 0x03, +} audio_WMA_decoder_control_selector_t; + +/// A.17.13.4 DTS Decoder Control Selectors +typedef enum +{ + AUDIO_DD_CTRL_UNDEF = 0x00, + AUDIO_DD_CTRL_UNDERFLOW = 0x01, + AUDIO_DD_CTRL_OVERFLOW = 0x02, + AUDIO_DD_CTRL_DECODER_ERROR = 0x03, +} audio_DTS_decoder_control_selector_t; + +/// A.17.14 Endpoint Control Selectors +typedef enum +{ + AUDIO_EP_CTRL_UNDEF = 0x00, + AUDIO_EP_CTRL_PITCH = 0x01, + AUDIO_EP_CTRL_DATA_OVERRUN = 0x02, + AUDIO_EP_CTRL_DATA_UNDERRUN = 0x03, +} audio_EP_control_selector_t; + +/// Terminal Types + +/// 2.1 - Audio Class-Terminal Types UAC2 +typedef enum +{ + AUDIO_TERM_TYPE_USB_UNDEFINED = 0x0100, + AUDIO_TERM_TYPE_USB_STREAMING = 0x0101, + AUDIO_TERM_TYPE_USB_VENDOR_SPEC = 0x01FF, +} audio_terminal_type_t; + +/// 2.2 - Audio Class-Input Terminal Types UAC2 +typedef enum +{ + AUDIO_TERM_TYPE_IN_UNDEFINED = 0x0200, + AUDIO_TERM_TYPE_IN_GENERIC_MIC = 0x0201, + AUDIO_TERM_TYPE_IN_DESKTOP_MIC = 0x0202, + AUDIO_TERM_TYPE_IN_PERSONAL_MIC = 0x0203, + AUDIO_TERM_TYPE_IN_OMNI_MIC = 0x0204, + AUDIO_TERM_TYPE_IN_ARRAY_MIC = 0x0205, + AUDIO_TERM_TYPE_IN_PROC_ARRAY_MIC = 0x0206, +} audio_terminal_input_type_t; + +/// 2.3 - Audio Class-Output Terminal Types UAC2 +typedef enum +{ + AUDIO_TERM_TYPE_OUT_UNDEFINED = 0x0300, + AUDIO_TERM_TYPE_OUT_GENERIC_SPEAKER = 0x0301, + AUDIO_TERM_TYPE_OUT_HEADPHONES = 0x0302, + AUDIO_TERM_TYPE_OUT_HEAD_MNT_DISP_AUIDO = 0x0303, + AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER = 0x0304, + AUDIO_TERM_TYPE_OUT_ROOM_SPEAKER = 0x0305, + AUDIO_TERM_TYPE_OUT_COMMUNICATION_SPEAKER = 0x0306, + AUDIO_TERM_TYPE_OUT_LOW_FRQ_EFFECTS_SPEAKER = 0x0307, +} audio_terminal_output_type_t; + +/// Rest is yet to be implemented + +/// Additional Audio Device Class Codes - Source: Audio Data Formats + +/// A.1 - Audio Class-Format Type Codes UAC2 +typedef enum +{ + AUDIO_FORMAT_TYPE_UNDEFINED = 0x00, + AUDIO_FORMAT_TYPE_I = 0x01, + AUDIO_FORMAT_TYPE_II = 0x02, + AUDIO_FORMAT_TYPE_III = 0x03, + AUDIO_FORMAT_TYPE_IV = 0x04, + AUDIO_EXT_FORMAT_TYPE_I = 0x81, + AUDIO_EXT_FORMAT_TYPE_II = 0x82, + AUDIO_EXT_FORMAT_TYPE_III = 0x83, +} audio_format_type_t; + +// A.2.1 - Audio Class-Audio Data Format Type I UAC2 +typedef enum +{ + AUDIO_DATA_FORMAT_TYPE_I_PCM = (uint32_t) (1 << 0), + AUDIO_DATA_FORMAT_TYPE_I_PCM8 = (uint32_t) (1 << 1), + AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT = (uint32_t) (1 << 2), + AUDIO_DATA_FORMAT_TYPE_I_ALAW = (uint32_t) (1 << 3), + AUDIO_DATA_FORMAT_TYPE_I_MULAW = (uint32_t) (1 << 4), + AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA = 0x80000000, +} audio_data_format_type_I_t; + +/// All remaining definitions are taken from the descriptor descriptions in the UAC2 main specification + +/// Audio Class-Control Values UAC2 +typedef enum +{ + AUDIO_CTRL_NONE = 0x00, ///< No Host access + AUDIO_CTRL_R = 0x01, ///< Host read access only + AUDIO_CTRL_RW = 0x03, ///< Host read write access +} audio_control_t; + +/// Audio Class-Specific AC Interface Descriptor Controls UAC2 +typedef enum +{ + AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS = 0, +} audio_cs_ac_interface_control_pos_t; + +/// Audio Class-Specific AS Interface Descriptor Controls UAC2 +typedef enum +{ + AUDIO_CS_AS_INTERFACE_CTRL_ACTIVE_ALT_SET_POS = 0, + AUDIO_CS_AS_INTERFACE_CTRL_VALID_ALT_SET_POS = 2, +} audio_cs_as_interface_control_pos_t; + +/// Audio Class-Specific AS Isochronous Data EP Attributes UAC2 +typedef enum +{ + AUDIO_CS_AS_ISO_DATA_EP_ATT_MAX_PACKETS_ONLY = 0x80, + AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK = 0x00, +} audio_cs_as_iso_data_ep_attribute_t; + +/// Audio Class-Specific AS Isochronous Data EP Controls UAC2 +typedef enum +{ + AUDIO_CS_AS_ISO_DATA_EP_CTRL_PITCH_POS = 0, + AUDIO_CS_AS_ISO_DATA_EP_CTRL_DATA_OVERRUN_POS = 2, + AUDIO_CS_AS_ISO_DATA_EP_CTRL_DATA_UNDERRUN_POS = 4, +} audio_cs_as_iso_data_ep_control_pos_t; + +/// Audio Class-Specific AS Isochronous Data EP Lock Delay Units UAC2 +typedef enum +{ + AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED = 0x00, + AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC = 0x01, + AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_PCM_SAMPLES = 0x02, +} audio_cs_as_iso_data_ep_lock_delay_unit_t; + +/// Audio Class-Clock Source Attributes UAC2 +typedef enum +{ + AUDIO_CLOCK_SOURCE_ATT_EXT_CLK = 0x00, + AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK = 0x01, + AUDIO_CLOCK_SOURCE_ATT_INT_VAR_CLK = 0x02, + AUDIO_CLOCK_SOURCE_ATT_INT_PRO_CLK = 0x03, + AUDIO_CLOCK_SOURCE_ATT_CLK_SYC_SOF = 0x04, +} audio_clock_source_attribute_t; + +/// Audio Class-Clock Source Controls UAC2 +typedef enum +{ + AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS = 0, + AUDIO_CLOCK_SOURCE_CTRL_CLK_VAL_POS = 2, +} audio_clock_source_control_pos_t; + +/// Audio Class-Clock Selector Controls UAC2 +typedef enum +{ + AUDIO_CLOCK_SELECTOR_CTRL_POS = 0, +} audio_clock_selector_control_pos_t; + +/// Audio Class-Clock Multiplier Controls UAC2 +typedef enum +{ + AUDIO_CLOCK_MULTIPLIER_CTRL_NUMERATOR_POS = 0, + AUDIO_CLOCK_MULTIPLIER_CTRL_DENOMINATOR_POS = 2, +} audio_clock_multiplier_control_pos_t; + +/// Audio Class-Input Terminal Controls UAC2 +typedef enum +{ + AUDIO_IN_TERM_CTRL_CPY_PROT_POS = 0, + AUDIO_IN_TERM_CTRL_CONNECTOR_POS = 2, + AUDIO_IN_TERM_CTRL_OVERLOAD_POS = 4, + AUDIO_IN_TERM_CTRL_CLUSTER_POS = 6, + AUDIO_IN_TERM_CTRL_UNDERFLOW_POS = 8, + AUDIO_IN_TERM_CTRL_OVERFLOW_POS = 10, +} audio_terminal_input_control_pos_t; + +/// Audio Class-Output Terminal Controls UAC2 +typedef enum +{ + AUDIO_OUT_TERM_CTRL_CPY_PROT_POS = 0, + AUDIO_OUT_TERM_CTRL_CONNECTOR_POS = 2, + AUDIO_OUT_TERM_CTRL_OVERLOAD_POS = 4, + AUDIO_OUT_TERM_CTRL_UNDERFLOW_POS = 6, + AUDIO_OUT_TERM_CTRL_OVERFLOW_POS = 8, +} audio_terminal_output_control_pos_t; + +/// Audio Class-Feature Unit Controls UAC2 +typedef enum +{ + AUDIO_FEATURE_UNIT_CTRL_MUTE_POS = 0, + AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS = 2, + AUDIO_FEATURE_UNIT_CTRL_BASS_POS = 4, + AUDIO_FEATURE_UNIT_CTRL_MID_POS = 6, + AUDIO_FEATURE_UNIT_CTRL_TREBLE_POS = 8, + AUDIO_FEATURE_UNIT_CTRL_GRAPHIC_EQU_POS = 10, + AUDIO_FEATURE_UNIT_CTRL_AGC_POS = 12, + AUDIO_FEATURE_UNIT_CTRL_DELAY_POS = 14, + AUDIO_FEATURE_UNIT_CTRL_BASS_BOOST_POS = 16, + AUDIO_FEATURE_UNIT_CTRL_LOUDNESS_POS = 18, + AUDIO_FEATURE_UNIT_CTRL_INPUT_GAIN_POS = 20, + AUDIO_FEATURE_UNIT_CTRL_INPUT_GAIN_PAD_POS = 22, + AUDIO_FEATURE_UNIT_CTRL_PHASE_INV_POS = 24, + AUDIO_FEATURE_UNIT_CTRL_UNDERFLOW_POS = 26, + AUDIO_FEATURE_UNIT_CTRL_OVERFLOW_POS = 28, +} audio_feature_unit_control_pos_t; + +/// Audio Class-Audio Channel Configuration UAC2 +typedef enum +{ + AUDIO_CHANNEL_CONFIG_NON_PREDEFINED = 0x00000000, + AUDIO_CHANNEL_CONFIG_FRONT_LEFT = 0x00000001, + AUDIO_CHANNEL_CONFIG_FRONT_RIGHT = 0x00000002, + AUDIO_CHANNEL_CONFIG_FRONT_CENTER = 0x00000004, + AUDIO_CHANNEL_CONFIG_LOW_FRQ_EFFECTS = 0x00000008, + AUDIO_CHANNEL_CONFIG_BACK_LEFT = 0x00000010, + AUDIO_CHANNEL_CONFIG_BACK_RIGHT = 0x00000020, + AUDIO_CHANNEL_CONFIG_FRONT_LEFT_OF_CENTER = 0x00000040, + AUDIO_CHANNEL_CONFIG_FRONT_RIGHT_OF_CENTER = 0x00000080, + AUDIO_CHANNEL_CONFIG_BACK_CENTER = 0x00000100, + AUDIO_CHANNEL_CONFIG_SIDE_LEFT = 0x00000200, + AUDIO_CHANNEL_CONFIG_SIDE_RIGHT = 0x00000400, + AUDIO_CHANNEL_CONFIG_TOP_CENTER = 0x00000800, + AUDIO_CHANNEL_CONFIG_TOP_FRONT_LEFT = 0x00001000, + AUDIO_CHANNEL_CONFIG_TOP_FRONT_CENTER = 0x00002000, + AUDIO_CHANNEL_CONFIG_TOP_FRONT_RIGHT = 0x00004000, + AUDIO_CHANNEL_CONFIG_TOP_BACK_LEFT = 0x00008000, + AUDIO_CHANNEL_CONFIG_TOP_BACK_CENTER = 0x00010000, + AUDIO_CHANNEL_CONFIG_TOP_BACK_RIGHT = 0x00020000, + AUDIO_CHANNEL_CONFIG_TOP_FRONT_LEFT_OF_CENTER = 0x00040000, + AUDIO_CHANNEL_CONFIG_TOP_FRONT_RIGHT_OF_CENTER = 0x00080000, + AUDIO_CHANNEL_CONFIG_LEFT_LOW_FRQ_EFFECTS = 0x00100000, + AUDIO_CHANNEL_CONFIG_RIGHT_LOW_FRQ_EFFECTS = 0x00200000, + AUDIO_CHANNEL_CONFIG_TOP_SIDE_LEFT = 0x00400000, + AUDIO_CHANNEL_CONFIG_TOP_SIDE_RIGHT = 0x00800000, + AUDIO_CHANNEL_CONFIG_BOTTOM_CENTER = 0x01000000, + AUDIO_CHANNEL_CONFIG_BACK_LEFT_OF_CENTER = 0x02000000, + AUDIO_CHANNEL_CONFIG_BACK_RIGHT_OF_CENTER = 0x04000000, + AUDIO_CHANNEL_CONFIG_RAW_DATA = 0x80000000, +} audio_channel_config_t; + +/// AUDIO Channel Cluster Descriptor (4.1) +typedef struct TU_ATTR_PACKED { + uint8_t bNrChannels; ///< Number of channels currently connected. + audio_channel_config_t bmChannelConfig; ///< Bitmap according to 'audio_channel_config_t' with a 1 set if channel is connected and 0 else. In case channels are non-predefined ignore them here (see UAC2 specification 4.1 Audio Channel Cluster Descriptor. + uint8_t iChannelNames; ///< Index of a string descriptor, describing the name of the first inserted channel with a non-predefined spatial location. +} audio_desc_channel_cluster_t; + +/// AUDIO Class-Specific AC Interface Header Descriptor (4.7.2) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes: 9. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_HEADER. + uint16_t bcdADC ; ///< Audio Device Class Specification Release Number in Binary-Coded Decimal. Value: U16_TO_U8S_LE(0x0200). + uint8_t bCategory ; ///< Constant, indicating the primary use of this audio function, as intended by the manufacturer. See: audio_function_t. + uint16_t wTotalLength ; ///< Total number of bytes returned for the class-specific AudioControl interface descriptor. Includes the combined length of this descriptor header and all Clock Source, Unit and Terminal descriptors. + uint8_t bmControls ; ///< See: audio_cs_ac_interface_control_pos_t. +} audio_desc_cs_ac_interface_t; + +/// AUDIO Clock Source Descriptor (4.7.2.1) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes: 8. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE. + uint8_t bClockID ; ///< Constant uniquely identifying the Clock Source Entity within the audio function. This value is used in all requests to address this Entity. + uint8_t bmAttributes ; ///< See: audio_clock_source_attribute_t. + uint8_t bmControls ; ///< See: audio_clock_source_control_pos_t. + uint8_t bAssocTerminal ; ///< Terminal ID of the Terminal that is associated with this Clock Source. + uint8_t iClockSource ; ///< Index of a string descriptor, describing the Clock Source Entity. +} audio_desc_clock_source_t; + +/// AUDIO Clock Selector Descriptor (4.7.2.2) for ONE pin +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor, in bytes: 7+p. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_SELECTOR. + uint8_t bClockID ; ///< Constant uniquely identifying the Clock Selector Entity within the audio function. This value is used in all requests to address this Entity. + uint8_t bNrInPins ; ///< Number of Input Pins of this Unit: p = 1 thus bNrInPins = 1. + uint8_t baCSourceID ; ///< ID of the Clock Entity to which the first Clock Input Pin of this Clock Selector Entity is connected.. + uint8_t bmControls ; ///< See: audio_clock_selector_control_pos_t. + uint8_t iClockSource ; ///< Index of a string descriptor, describing the Clock Selector Entity. +} audio_desc_clock_selector_t; + +/// AUDIO Clock Selector Descriptor (4.7.2.2) for multiple pins +#define audio_desc_clock_selector_n_t(source_num) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength ; \ + uint8_t bDescriptorType ; \ + uint8_t bDescriptorSubType ; \ + uint8_t bClockID ; \ + uint8_t bNrInPins ; \ + struct TU_ATTR_PACKED { \ + uint8_t baSourceID ; \ + } sourceID[source_num] ; \ + uint8_t bmControls ; \ + uint8_t iClockSource ; \ +} + +/// AUDIO Clock Multiplier Descriptor (4.7.2.3) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor, in bytes: 7. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_MULTIPLIER. + uint8_t bClockID ; ///< Constant uniquely identifying the Clock Multiplier Entity within the audio function. This value is used in all requests to address this Entity. + uint8_t bCSourceID ; ///< ID of the Clock Entity to which the last Clock Input Pin of this Clock Selector Entity is connected. + uint8_t bmControls ; ///< See: audio_clock_multiplier_control_pos_t. + uint8_t iClockSource ; ///< Index of a string descriptor, describing the Clock Multiplier Entity. +} audio_desc_clock_multiplier_t; + +/// AUDIO Input Terminal Descriptor(4.7.2.4) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor, in bytes: 17. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL. + uint16_t wTerminalType ; ///< Constant characterizing the type of Terminal. See: audio_terminal_type_t for USB streaming and audio_terminal_input_type_t for other input types. + uint8_t bAssocTerminal ; ///< ID of the Output Terminal to which this Input Terminal is associated. + uint8_t bCSourceID ; ///< ID of the Clock Entity to which this Input Terminal is connected. + uint8_t bNrChannels ; ///< Number of logical output channels in the Terminal’s output audio channel cluster. + uint32_t bmChannelConfig ; ///< Describes the spatial location of the logical channels. See:audio_channel_config_t. + uint16_t bmControls ; ///< See: audio_terminal_input_control_pos_t. + uint8_t iTerminal ; ///< Index of a string descriptor, describing the Input Terminal. +} audio_desc_input_terminal_t; + +/// AUDIO Output Terminal Descriptor(4.7.2.5) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor, in bytes: 12. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL. + uint8_t bTerminalID ; ///< Constant uniquely identifying the Terminal within the audio function. This value is used in all requests to address this Terminal. + uint16_t wTerminalType ; ///< Constant characterizing the type of Terminal. See: audio_terminal_type_t for USB streaming and audio_terminal_output_type_t for other output types. + uint8_t bAssocTerminal ; ///< Constant, identifying the Input Terminal to which this Output Terminal is associated. + uint8_t bSourceID ; ///< ID of the Unit or Terminal to which this Terminal is connected. + uint8_t bCSourceID ; ///< ID of the Clock Entity to which this Output Terminal is connected. + uint16_t bmControls ; ///< See: audio_terminal_output_type_t. + uint8_t iTerminal ; ///< Index of a string descriptor, describing the Output Terminal. +} audio_desc_output_terminal_t; + +/// AUDIO Feature Unit Descriptor(4.7.2.8) for ONE channel +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor, in bytes: 14. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_FEATURE_UNIT. + uint8_t bUnitID ; ///< Constant uniquely identifying the Unit within the audio function. This value is used in all requests to address this Unit. + uint8_t bSourceID ; ///< ID of the Unit or Terminal to which this Feature Unit is connected. + struct TU_ATTR_PACKED { + uint32_t bmaControls ; ///< See: audio_feature_unit_control_pos_t. Controls0 is master channel 0 (always present) and Controls1 is logical channel 1. + } controls[2] ; + uint8_t iTerminal ; ///< Index of a string descriptor, describing this Feature Unit. +} audio_desc_feature_unit_t; + +/// AUDIO Feature Unit Descriptor(4.7.2.8) for multiple channels +#define audio_desc_feature_unit_n_t(ch_num)\ + struct TU_ATTR_PACKED { \ + uint8_t bLength ; /* 6+(ch_num+1)*4 */\ + uint8_t bDescriptorType ; \ + uint8_t bDescriptorSubType ; \ + uint8_t bUnitID ; \ + uint8_t bSourceID ; \ + struct TU_ATTR_PACKED { \ + uint32_t bmaControls ; \ + } controls[ch_num+1] ; \ + uint8_t iTerminal ; \ +} + +/// AUDIO Class-Specific AS Interface Descriptor(4.9.2) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor, in bytes: 16. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AS_INTERFACE_AS_GENERAL. + uint8_t bTerminalLink ; ///< The Terminal ID of the Terminal to which this interface is connected. + uint8_t bmControls ; ///< See: audio_cs_as_interface_control_pos_t. + uint8_t bFormatType ; ///< Constant identifying the Format Type the AudioStreaming interface is using. See: audio_format_type_t. + uint32_t bmFormats ; ///< The Audio Data Format(s) that can be used to communicate with this interface.See: audio_data_format_type_I_t. + uint8_t bNrChannels ; ///< Number of physical channels in the AS Interface audio channel cluster. + uint32_t bmChannelConfig ; ///< Describes the spatial location of the physical channels. See: audio_channel_config_t. + uint8_t iChannelNames ; ///< Index of a string descriptor, describing the name of the first physical channel. +} audio_desc_cs_as_interface_t; + +/// AUDIO Type I Format Type Descriptor(2.3.1.6 - Audio Formats) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor, in bytes: 6. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AS_INTERFACE_FORMAT_TYPE. + uint8_t bFormatType ; ///< Constant identifying the Format Type the AudioStreaming interface is using. Value: AUDIO_FORMAT_TYPE_I. + uint8_t bSubslotSize ; ///< The number of bytes occupied by one audio subslot. Can be 1, 2, 3 or 4. + uint8_t bBitResolution ; ///< The number of effectively used bits from the available bits in an audio subslot. +} audio_desc_type_I_format_t; + +/// AUDIO Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor, in bytes: 8. + uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_ENDPOINT. + uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_EP_SUBTYPE_GENERAL. + uint8_t bmAttributes ; ///< See: audio_cs_as_iso_data_ep_attribute_t. + uint8_t bmControls ; ///< See: audio_cs_as_iso_data_ep_control_pos_t. + uint8_t bLockDelayUnits ; ///< Indicates the units used for the wLockDelay field. See: audio_cs_as_iso_data_ep_lock_delay_unit_t. + uint16_t wLockDelay ; ///< Indicates the time it takes this endpoint to reliably lock its internal clock recovery circuitry. Units used depend on the value of the bLockDelayUnits field. +} audio_desc_cs_as_iso_data_ep_t; + +// 5.2.2 Control Request Layout +typedef struct TU_ATTR_PACKED +{ + union + { + struct TU_ATTR_PACKED + { + uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t. + uint8_t type : 2; ///< Request type tusb_request_type_t. + uint8_t direction : 1; ///< Direction type. tusb_dir_t + } bmRequestType_bit; + + uint8_t bmRequestType; + }; + + uint8_t bRequest; ///< Request type audio_cs_req_t + uint8_t bChannelNumber; + uint8_t bControlSelector; + union + { + uint8_t bInterface; + uint8_t bEndpoint; + }; + uint8_t bEntityID; + uint16_t wLength; +} audio_control_request_t; + +//// 5.2.3 Control Request Parameter Block Layout + +// 5.2.3.1 1-byte Control CUR Parameter Block +typedef struct TU_ATTR_PACKED +{ + int8_t bCur ; ///< The setting for the CUR attribute of the addressed Control +} audio_control_cur_1_t; + +// 5.2.3.2 2-byte Control CUR Parameter Block +typedef struct TU_ATTR_PACKED +{ + int16_t bCur ; ///< The setting for the CUR attribute of the addressed Control +} audio_control_cur_2_t; + +// 5.2.3.3 4-byte Control CUR Parameter Block +typedef struct TU_ATTR_PACKED +{ + int32_t bCur ; ///< The setting for the CUR attribute of the addressed Control +} audio_control_cur_4_t; + +// Use the following ONLY for RECEIVED data - compiler does not know how many subranges are defined! Use the one below for predefined lengths - or if you know what you are doing do what you like +// 5.2.3.1 1-byte Control RANGE Parameter Block +typedef struct TU_ATTR_PACKED { + uint16_t wNumSubRanges; + struct TU_ATTR_PACKED { + int8_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/ + int8_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/ + uint8_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/ + } subrange[] ; +} audio_control_range_1_t; + +// 5.2.3.2 2-byte Control RANGE Parameter Block +typedef struct TU_ATTR_PACKED { + uint16_t wNumSubRanges; + struct TU_ATTR_PACKED { + int16_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/ + int16_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/ + uint16_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/ + } subrange[] ; +} audio_control_range_2_t; + +// 5.2.3.3 4-byte Control RANGE Parameter Block +typedef struct TU_ATTR_PACKED { + uint16_t wNumSubRanges; + struct TU_ATTR_PACKED { + int32_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/ + int32_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/ + uint32_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/ + } subrange[] ; +} audio_control_range_4_t; + +// 5.2.3.1 1-byte Control RANGE Parameter Block +#define audio_control_range_1_n_t(numSubRanges) \ + struct TU_ATTR_PACKED { \ + uint16_t wNumSubRanges; \ + struct TU_ATTR_PACKED { \ + int8_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/\ + int8_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/\ + uint8_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/\ + } subrange[numSubRanges] ; \ +} + +/// 5.2.3.2 2-byte Control RANGE Parameter Block +#define audio_control_range_2_n_t(numSubRanges) \ + struct TU_ATTR_PACKED { \ + uint16_t wNumSubRanges; \ + struct TU_ATTR_PACKED { \ + int16_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/\ + int16_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/\ + uint16_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/\ + } subrange[numSubRanges]; \ +} + +// 5.2.3.3 4-byte Control RANGE Parameter Block +#define audio_control_range_4_n_t(numSubRanges) \ + struct TU_ATTR_PACKED { \ + uint16_t wNumSubRanges; \ + struct TU_ATTR_PACKED { \ + int32_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/\ + int32_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/\ + uint32_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/\ + } subrange[numSubRanges]; \ +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif + +/** @} */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/audio/audio_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/audio/audio_device.c new file mode 100644 index 00000000..a021755b --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/audio/audio_device.c @@ -0,0 +1,2475 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Reinhard Panhuber, Jerzy Kasenberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/* + * This driver supports at most one out EP, one in EP, one control EP, and one feedback EP and one alternative interface other than zero. Hence, only one input terminal and one output terminal are support, if you need more adjust the driver! + * It supports multiple TX and RX channels. + * + * In case you need more alternate interfaces, you need to define additional defines for this specific alternate interface. Just define them and set them in the set_interface function. + * + * There are three data flow structures currently implemented, where at least one SW-FIFO is used to decouple the asynchronous processes MCU vs. host + * + * 1. Input data -> SW-FIFO -> MCU USB + * + * The most easiest version, available in case the target MCU can handle the software FIFO (SW-FIFO) and if it is implemented in the device driver (if yes then dcd_edpt_xfer_fifo() is available) + * + * 2. Input data -> SW-FIFO -> Linear buffer -> MCU USB + * + * In case the target MCU can not handle a SW-FIFO, a linear buffer is used. This uses the default function dcd_edpt_xfer(). In this case more memory is required. + * + * 3. (Input data 1 | Input data 2 | ... | Input data N) -> (SW-FIFO 1 | SW-FIFO 2 | ... | SW-FIFO N) -> Linear buffer -> MCU USB + * + * This case is used if you have more channels which need to be combined into one stream. Every channel has its own SW-FIFO. All data is encoded into an Linear buffer. + * + * The same holds in the RX case. + * + * */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_AUDIO) + +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "audio_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +// Use ring buffer if it's available, some MCUs need extra RAM requirements +#ifndef TUD_AUDIO_PREFER_RING_BUFFER +#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT +#define TUD_AUDIO_PREFER_RING_BUFFER 0 +#else +#define TUD_AUDIO_PREFER_RING_BUFFER 1 +#endif +#endif + +// Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer +// is available or driver is would need to be changed dramatically + +// Only STM32 synopsys and dcd_transdimension use non-linear buffer for now +// Synopsys detection copied from dcd_synopsys.c (refactor later on) +#if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \ + defined (STM32F107xB) || defined (STM32F107xC) +#define STM32F1_SYNOPSYS +#endif + +#if defined (STM32L475xx) || defined (STM32L476xx) || \ + defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \ + defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || \ + defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx) +#define STM32L4_SYNOPSYS +#endif + +#if (CFG_TUSB_MCU == OPT_MCU_STM32F1 && defined(STM32F1_SYNOPSYS)) || \ + CFG_TUSB_MCU == OPT_MCU_STM32F2 || \ + CFG_TUSB_MCU == OPT_MCU_STM32F4 || \ + CFG_TUSB_MCU == OPT_MCU_STM32F7 || \ + CFG_TUSB_MCU == OPT_MCU_STM32H7 || \ + (CFG_TUSB_MCU == OPT_MCU_STM32L4 && defined(STM32L4_SYNOPSYS)) || \ + CFG_TUSB_MCU == OPT_MCU_RX63X || \ + CFG_TUSB_MCU == OPT_MCU_RX65X || \ + CFG_TUSB_MCU == OPT_MCU_RX72N || \ + CFG_TUSB_MCU == OPT_MCU_GD32VF103 || \ + CFG_TUSB_MCU == OPT_MCU_LPC18XX || \ + CFG_TUSB_MCU == OPT_MCU_LPC43XX || \ + CFG_TUSB_MCU == OPT_MCU_MIMXRT || \ + CFG_TUSB_MCU == OPT_MCU_MSP432E4 +#if TUD_AUDIO_PREFER_RING_BUFFER +#define USE_LINEAR_BUFFER 0 +#else +#define USE_LINEAR_BUFFER 1 +#endif +#else +#define USE_LINEAR_BUFFER 1 +#endif + +// Declaration of buffers + +// Check for maximum supported numbers +#if CFG_TUD_AUDIO > 3 +#error Maximum number of audio functions restricted to three! +#endif + +// EP IN software buffers and mutexes +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING + +// Linear buffer TX in case: +// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR +// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into +#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) +#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX]; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX]; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX]; +#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) + +// EP OUT software buffers and mutexes +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING + +// Linear buffer RX in case: +// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR +// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) +#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX]; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX]; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX]; +#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) + +// Control buffers +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ]; +#if CFG_TUD_AUDIO > 1 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ]; +#endif +#if CFG_TUD_AUDIO > 2 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ]; +#endif + +// Active alternate setting of interfaces +uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT]; +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 +uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT]; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 +uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; +#endif + +// Software encoding/decoding support FIFOs +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING +#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ]; +tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ]; +tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ]; +tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO +#endif +#endif +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING +#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ]; +tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ]; +tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ]; +tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; +#if CFG_FIFO_MUTEX +osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO +#endif +#endif +#endif + +typedef struct +{ + uint8_t rhport; + uint8_t const * p_desc; // Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function + +#if CFG_TUD_AUDIO_ENABLE_EP_IN + uint8_t ep_in; // TX audio data EP. + uint16_t ep_in_sz; // Current size of TX EP + uint8_t ep_in_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to output terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + uint8_t ep_out; // Incoming (into uC) audio data EP. + uint16_t ep_out_sz; // Current size of RX EP + uint8_t ep_out_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to input terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + uint8_t ep_fb; // Feedback EP. +#endif + +#endif + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN + uint8_t ep_int_ctr; // Audio control interrupt EP. +#endif + + /*------------- From this point, data is not cleared by bus reset -------------*/ + + uint16_t desc_length; // Length of audio function descriptor + + // Buffer for control requests + uint8_t * ctrl_buf; + uint8_t ctrl_buf_sz; + + // Current active alternate settings + uint8_t * alt_setting; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! + + // EP Transfer buffers and FIFOs +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +#if !CFG_TUD_AUDIO_ENABLE_DECODING + tu_fifo_t ep_out_ff; +#endif + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + struct { + uint32_t value; // Feedback value for asynchronous mode (in 16.16 format). + uint32_t min_value; // min value according to UAC2 FMT-2.0 section 2.3.1.1. + uint32_t max_value; // max value according to UAC2 FMT-2.0 section 2.3.1.1. + + uint8_t frame_shift; // bInterval-1 in unit of frame (FS), micro-frame (HS) + uint8_t compute_method; + + union { + uint8_t power_of_2; // pre-computed power of 2 shift + float float_const; // pre-computed float constant + + struct { + uint32_t sample_freq; + uint32_t mclk_freq; + }fixed; + +#if 0 // implement later + struct { + uint32_t nominal_value; + uint32_t threshold_bytes; + }fifo_count; +#endif + }compute; + + } feedback; +#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING + tu_fifo_t ep_in_ff; +#endif + + // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74) +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE]; +#endif + + // Decoding parameters - parameters are set when alternate AS interface is set by host + // Coding is currently only supported for EP. Software coding corresponding to AS interfaces without EPs are not supported currently. +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING + audio_format_type_t format_type_rx; + uint8_t n_channels_rx; + +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + audio_data_format_type_I_t format_type_I_rx; + uint8_t n_bytes_per_sampe_rx; + uint8_t n_channels_per_ff_rx; + uint8_t n_ff_used_rx; +#endif +#endif + + // Encoding parameters - parameters are set when alternate AS interface is set by host +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + audio_format_type_t format_type_tx; + uint8_t n_channels_tx; + +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + audio_data_format_type_I_t format_type_I_tx; + uint8_t n_bytes_per_sampe_tx; + uint8_t n_channels_per_ff_tx; + uint8_t n_ff_used_tx; +#endif +#endif + + // Support FIFOs for software encoding and decoding +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING + tu_fifo_t * rx_supp_ff; + uint8_t n_rx_supp_ff; + uint16_t rx_supp_ff_sz_max; +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + tu_fifo_t * tx_supp_ff; + uint8_t n_tx_supp_ff; + uint16_t tx_supp_ff_sz_max; +#endif + + // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR the support FIFOs are used +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) + uint8_t * lin_buf_out; +#define USE_LINEAR_BUFFER_RX 1 +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) + uint8_t * lin_buf_in; +#define USE_LINEAR_BUFFER_TX 1 +#endif + +} audiod_function_t; + +#ifndef USE_LINEAR_BUFFER_TX +#define USE_LINEAR_BUFFER_TX 0 +#endif + +#ifndef USE_LINEAR_BUFFER_RX +#define USE_LINEAR_BUFFER_RX 0 +#endif + +#define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ctrl_buf) + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +CFG_TUSB_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO]; + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received); +#endif + +#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT +static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN +static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t* audio); +#endif + +#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN +static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio); +#endif + +static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request); +static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request); + +static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int); +static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int); +static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id); +static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id); +static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id); +static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio); + +#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING +static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf); + +static inline uint8_t tu_desc_subtype(void const* desc) +{ + return ((uint8_t const*) desc)[2]; +} +#endif + +bool tud_audio_n_mounted(uint8_t func_id) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO); + audiod_function_t* audio = &_audiod_fct[func_id]; + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + if (audio->ep_out == 0) return false; +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN + if (audio->ep_in == 0) return false; +#endif + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN + if (audio->ep_int_ctr == 0) return false; +#endif + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + if (audio->ep_fb == 0) return false; +#endif + + return true; +} + +//--------------------------------------------------------------------+ +// READ API +//--------------------------------------------------------------------+ + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING + +uint16_t tud_audio_n_available(uint8_t func_id) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + return tu_fifo_count(&_audiod_fct[func_id].ep_out_ff); +} + +uint16_t tud_audio_n_read(uint8_t func_id, void* buffer, uint16_t bufsize) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + return tu_fifo_read_n(&_audiod_fct[func_id].ep_out_ff, buffer, bufsize); +} + +bool tud_audio_n_clear_ep_out_ff(uint8_t func_id) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + return tu_fifo_clear(&_audiod_fct[func_id].ep_out_ff); +} + +tu_fifo_t* tud_audio_n_get_ep_out_ff(uint8_t func_id) +{ + if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_out_ff; + return NULL; +} + +#endif + +#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT +// Delete all content in the support RX FIFOs +bool tud_audio_n_clear_rx_support_ff(uint8_t func_id, uint8_t ff_idx) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); + return tu_fifo_clear(&_audiod_fct[func_id].rx_supp_ff[ff_idx]); +} + +uint16_t tud_audio_n_available_support_ff(uint8_t func_id, uint8_t ff_idx) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); + return tu_fifo_count(&_audiod_fct[func_id].rx_supp_ff[ff_idx]); +} + +uint16_t tud_audio_n_read_support_ff(uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); + return tu_fifo_read_n(&_audiod_fct[func_id].rx_supp_ff[ff_idx], buffer, bufsize); +} + +tu_fifo_t* tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx) +{ + if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff) return &_audiod_fct[func_id].rx_supp_ff[ff_idx]; + return NULL; +} +#endif + +// This function is called once an audio packet is received by the USB and is responsible for putting data from USB memory into EP_OUT_FIFO (or support FIFOs + decoding of received stream into audio channels). +// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_DECODING = 0. + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + +static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received) +{ + uint8_t idxItf = 0; + uint8_t const *dummy2; + uint8_t idx_audio_fct = 0; + + if (tud_audio_rx_done_pre_read_cb || tud_audio_rx_done_post_read_cb) + { + idx_audio_fct = audiod_get_audio_fct_idx(audio); + TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2)); + } + + // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO (or decoded into support RX software FIFO) + if (tud_audio_rx_done_pre_read_cb) + { + TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); + } + +#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT + + switch (audio->format_type_rx) + { + case AUDIO_FORMAT_TYPE_UNDEFINED: + // INDIVIDUAL DECODING PROCEDURE REQUIRED HERE! + TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n"); + TU_BREAKPOINT(); + break; + + case AUDIO_FORMAT_TYPE_I: + + switch (audio->format_type_I_rx) + { + case AUDIO_DATA_FORMAT_TYPE_I_PCM: + TU_VERIFY(audiod_decode_type_I_pcm(rhport, audio, n_bytes_received)); + break; + + default: + // DESIRED CFG_TUD_AUDIO_FORMAT_TYPE_I_RX NOT IMPLEMENTED! + TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_RX encoding not implemented!\r\n"); + TU_BREAKPOINT(); + break; + } + break; + + default: + // Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented! + TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented!\r\n"); + TU_BREAKPOINT(); + break; + } + + // Prepare for next transmission + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); + +#else + +#if USE_LINEAR_BUFFER_RX + // Data currently is in linear buffer, copy into EP OUT FIFO + TU_VERIFY(tu_fifo_write_n(&audio->ep_out_ff, audio->lin_buf_out, n_bytes_received)); + + // Schedule for next receive + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); +#else + // Data is already placed in EP FIFO, schedule for next receive + TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false); +#endif + +#endif + + // Call a weak callback here - a possibility for user to get informed decoding was completed + if (tud_audio_rx_done_post_read_cb) + { + TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); + } + + return true; +} + +#endif //CFG_TUD_AUDIO_ENABLE_EP_OUT + +// The following functions are used in case CFG_TUD_AUDIO_ENABLE_DECODING != 0 +#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT + +// Decoding according to 2.3.1.5 Audio Streams + +// Helper function +static inline uint8_t * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesToCopy, void * dst, uint8_t * dst_end, uint8_t * src, uint8_t const n_ff_used) +{ + + // This function is an optimized version of + // while((uint8_t *)dst < dst_end) + // { + // memcpy(dst, src, nBytesToCopy); + // dst = (uint8_t *)dst + nBytesToCopy; + // src += nBytesToCopy * n_ff_used; + // } + + // Optimize for fast half word copies + typedef struct{ + uint16_t val; + } __attribute((__packed__)) unaligned_uint16_t; + + // Optimize for fast word copies + typedef struct{ + uint32_t val; + } __attribute((__packed__)) unaligned_uint32_t; + + switch (nBytesToCopy) + { + case 1: + while((uint8_t *)dst < dst_end) + { + *(uint8_t *)dst++ = *src; + src += n_ff_used; + } + break; + + case 2: + while((uint8_t *)dst < dst_end) + { + *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src; + dst += 2; + src += 2 * n_ff_used; + } + break; + + case 3: + while((uint8_t *)dst < dst_end) + { + // memcpy(dst, src, 3); + // dst = (uint8_t *)dst + 3; + // src += 3 * n_ff_used; + + // TODO: Is there a faster way to copy 3 bytes? + *(uint8_t *)dst++ = *src++; + *(uint8_t *)dst++ = *src++; + *(uint8_t *)dst++ = *src++; + + src += 3 * (n_ff_used - 1); + } + break; + + case 4: + while((uint8_t *)dst < dst_end) + { + *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src; + dst += 4; + src += 4 * n_ff_used; + } + break; + } + + return src; +} + +static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received) +{ + (void) rhport; + + // Determine amount of samples + uint8_t const n_ff_used = audio->n_ff_used_rx; + uint16_t const nBytesPerFFToRead = n_bytes_received / n_ff_used; + uint8_t cnt_ff; + + // Decode + uint8_t * src; + uint8_t * dst_end; + + tu_fifo_buffer_info_t info; + + for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) + { + tu_fifo_get_write_info(&audio->rx_supp_ff[cnt_ff], &info); + + if (info.len_lin != 0) + { + info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin); + src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx]; + dst_end = info.ptr_lin + info.len_lin; + src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_lin, dst_end, src, n_ff_used); + + // Handle wrapped part of FIFO + info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap); + if (info.len_wrap != 0) + { + dst_end = info.ptr_wrap + info.len_wrap; + audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_wrap, dst_end, src, n_ff_used); + } + tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], info.len_lin + info.len_wrap); + } + } + + // Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it + // TU_VERIFY(cnt != n_bytes); + + return true; +} +#endif //CFG_TUD_AUDIO_ENABLE_DECODING + +//--------------------------------------------------------------------+ +// WRITE API +//--------------------------------------------------------------------+ + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING + +/** + * \brief Write data to EP in buffer + * + * Write data to buffer. If it is full, new data can be inserted once a transmit was scheduled. See audiod_tx_done_cb(). + * If TX FIFOs are used, this function is not available in order to not let the user mess up the encoding process. + * + * \param[in] func_id: Index of audio function interface + * \param[in] data: Pointer to data array to be copied from + * \param[in] len: # of array elements to copy + * \return Number of bytes actually written + */ +uint16_t tud_audio_n_write(uint8_t func_id, const void * data, uint16_t len) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + return tu_fifo_write_n(&_audiod_fct[func_id].ep_in_ff, data, len); +} + +bool tud_audio_n_clear_ep_in_ff(uint8_t func_id) // Delete all content in the EP IN FIFO +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + return tu_fifo_clear(&_audiod_fct[func_id].ep_in_ff); +} + +tu_fifo_t* tud_audio_n_get_ep_in_ff(uint8_t func_id) +{ + if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_in_ff; + return NULL; +} + +#endif + +#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN + +uint16_t tud_audio_n_flush_tx_support_ff(uint8_t func_id) // Force all content in the support TX FIFOs to be written into linear buffer and schedule a transmit +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + audiod_function_t* audio = &_audiod_fct[func_id]; + + uint16_t n_bytes_copied = tu_fifo_count(&audio->tx_supp_ff[0]); + + TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio)); + + n_bytes_copied -= tu_fifo_count(&audio->tx_supp_ff[0]); + n_bytes_copied = n_bytes_copied*audio->tx_supp_ff[0].item_size; + + return n_bytes_copied; +} + +bool tud_audio_n_clear_tx_support_ff(uint8_t func_id, uint8_t ff_idx) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff); + return tu_fifo_clear(&_audiod_fct[func_id].tx_supp_ff[ff_idx]); +} + +uint16_t tud_audio_n_write_support_ff(uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff); + return tu_fifo_write_n(&_audiod_fct[func_id].tx_supp_ff[ff_idx], data, len); +} + +tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx) +{ + if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff) return &_audiod_fct[func_id].tx_supp_ff[ff_idx]; + return NULL; +} + +#endif + + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN + +// If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_ctr_done_cb() is called in inform user +uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint16_t len) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + + // We write directly into the EP's buffer - abort if previous transfer not complete + TU_VERIFY(!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr)); + + // Check length + TU_VERIFY(len <= CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE); + + memcpy(_audiod_fct[func_id].ep_int_ctr_buf, buffer, len); + + // Schedule transmit + TU_VERIFY(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr, _audiod_fct[func_id].ep_int_ctr_buf, len)); + + return true; +} + +#endif + + +// This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission. +// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_ENCODING = 0 and use tud_audio_n_write. + +// n_bytes_copied - Informs caller how many bytes were loaded. In case n_bytes_copied = 0, a ZLP is scheduled to inform host no data is available for current frame. +#if CFG_TUD_AUDIO_ENABLE_EP_IN +static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio) +{ + uint8_t idxItf; + uint8_t const *dummy2; + + uint8_t idx_audio_fct = audiod_get_audio_fct_idx(audio); + TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, audio, &idxItf, &dummy2)); + + // Only send something if current alternate interface is not 0 as in this case nothing is to be sent due to UAC2 specifications + if (audio->alt_setting[idxItf] == 0) return false; + + // Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer (in case FIFOs are used) or + // if no FIFOs are used the user may use this call back to load its data into the EP IN buffer by use of tud_audio_n_write_ep_in_buffer(). + if (tud_audio_tx_done_pre_load_cb) TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); + + // Send everything in ISO EP FIFO + uint16_t n_bytes_tx; + + // If support FIFOs are used, encode and schedule transmit +#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN + switch (audio->format_type_tx) + { + case AUDIO_FORMAT_TYPE_UNDEFINED: + // INDIVIDUAL ENCODING PROCEDURE REQUIRED HERE! + TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n"); + TU_BREAKPOINT(); + n_bytes_tx = 0; + break; + + case AUDIO_FORMAT_TYPE_I: + + switch (audio->format_type_I_tx) + { + case AUDIO_DATA_FORMAT_TYPE_I_PCM: + + n_bytes_tx = audiod_encode_type_I_pcm(rhport, audio); + break; + + default: + // YOUR ENCODING IS REQUIRED HERE! + TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_TX encoding not implemented!\r\n"); + TU_BREAKPOINT(); + n_bytes_tx = 0; + break; + } + break; + + default: + // Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented! + TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!\r\n"); + TU_BREAKPOINT(); + n_bytes_tx = 0; + break; + } + + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx)); + +#else + // No support FIFOs, if no linear buffer required schedule transmit, else put data into linear buffer and schedule + + n_bytes_tx = tu_min16(tu_fifo_count(&audio->ep_in_ff), audio->ep_in_sz); // Limit up to max packet size, more can not be done for ISO + +#if USE_LINEAR_BUFFER_TX + tu_fifo_read_n(&audio->ep_in_ff, audio->lin_buf_in, n_bytes_tx); + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx)); +#else + // Send everything in ISO EP FIFO + TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx)); +#endif + +#endif + + // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame + if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); + + return true; +} + +#endif //CFG_TUD_AUDIO_ENABLE_EP_IN + +#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN +// Take samples from the support buffer and encode them into the IN EP software FIFO +// Returns number of bytes written into linear buffer + +/* 2.3.1.7.1 PCM Format +The PCM (Pulse Coded Modulation) format is the most commonly used audio format to represent audio +data streams. The audio data is not compressed and uses a signed two’s-complement fixed point format. It +is left-justified (the sign bit is the Msb) and data is padded with trailing zeros to fill the remaining unused +bits of the subslot. The binary point is located to the right of the sign bit so that all values lie within the +range [-1, +1) + */ + +/* + * This function encodes channels saved within the support FIFOs into one stream by interleaving the PCM samples + * in the support FIFOs according to 2.3.1.5 Audio Streams. It does not control justification (left or right) and + * does not change the number of bytes per sample. + * */ + +// Helper function +static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, uint8_t * src, uint8_t * src_end, uint8_t * dst, uint8_t const n_ff_used) +{ + // Optimize for fast half word copies + typedef struct{ + uint16_t val; + } __attribute((__packed__)) unaligned_uint16_t; + + // Optimize for fast word copies + typedef struct{ + uint32_t val; + } __attribute((__packed__)) unaligned_uint32_t; + + switch (nBytesToCopy) + { + case 1: + while(src < src_end) + { + *dst = *src++; + dst += n_ff_used; + } + break; + + case 2: + while(src < src_end) + { + *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src; + src += 2; + dst += 2 * n_ff_used; + } + break; + + case 3: + while(src < src_end) + { + // memcpy(dst, src, 3); + // src = (uint8_t *)src + 3; + // dst += 3 * n_ff_used; + + // TODO: Is there a faster way to copy 3 bytes? + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + + dst += 3 * (n_ff_used - 1); + } + break; + + case 4: + while(src < src_end) + { + *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src; + src += 4; + dst += 4 * n_ff_used; + } + break; + } + + return dst; +} + +static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio) +{ + // This function relies on the fact that the length of the support FIFOs was configured to be a multiple of the active sample size in bytes s.t. no sample is split within a wrap + // This is ensured within set_interface, where the FIFOs are reconfigured according to this size + + // We encode directly into IN EP's linear buffer - abort if previous transfer not complete + TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); + + // Determine amount of samples + uint8_t const n_ff_used = audio->n_ff_used_tx; + uint16_t const nBytesToCopy = audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx; + uint16_t const capPerFF = audio->ep_in_sz / n_ff_used; // Sample capacity per FIFO in bytes + uint16_t nBytesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]); + uint8_t cnt_ff; + + for (cnt_ff = 1; cnt_ff < n_ff_used; cnt_ff++) + { + uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cnt_ff]); + if (count < nBytesPerFFToSend) + { + nBytesPerFFToSend = count; + } + } + + // Check if there is enough + if (nBytesPerFFToSend == 0) return 0; + + // Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT! + nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, capPerFF); + + // Round to full number of samples (flooring) + nBytesPerFFToSend = (nBytesPerFFToSend / nBytesToCopy) * nBytesToCopy; + + // Encode + uint8_t * dst; + uint8_t * src_end; + + tu_fifo_buffer_info_t info; + + for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) + { + dst = &audio->lin_buf_in[cnt_ff*audio->n_channels_per_ff_tx*audio->n_bytes_per_sampe_tx]; + + tu_fifo_get_read_info(&audio->tx_supp_ff[cnt_ff], &info); + + if (info.len_lin != 0) + { + info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin); // Limit up to desired length + src_end = (uint8_t *)info.ptr_lin + info.len_lin; + dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_lin, src_end, dst, n_ff_used); + + // Limit up to desired length + info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap); + + // Handle wrapped part of FIFO + if (info.len_wrap != 0) + { + src_end = (uint8_t *)info.ptr_wrap + info.len_wrap; + audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_wrap, src_end, dst, n_ff_used); + } + + tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], info.len_lin + info.len_wrap); + } + } + + return nBytesPerFFToSend * n_ff_used; +} +#endif //CFG_TUD_AUDIO_ENABLE_ENCODING + +// This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio) +{ + return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->feedback.value, 4); +} +#endif + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void audiod_init(void) +{ + tu_memclr(_audiod_fct, sizeof(_audiod_fct)); + + for(uint8_t i=0; ictrl_buf = ctrl_buf_1; + audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ; + break; +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ > 0 + case 1: + audio->ctrl_buf = ctrl_buf_2; + audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ > 0 + case 2: + audio->ctrl_buf = ctrl_buf_3; + audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ; + break; +#endif + } + + // Initialize active alternate interface buffers + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0 + case 0: + audio->alt_setting = alt_setting_1; + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 + case 1: + audio->alt_setting = alt_setting_2; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 + case 2: + audio->alt_setting = alt_setting_3; + break; +#endif + } + + // Initialize IN EP FIFO if required +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING + + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 + case 0: + tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_1), NULL); +#endif + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 + case 1: + tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_2), NULL); +#endif + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 + case 2: + tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_3), NULL); +#endif + break; +#endif + } +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING + + // Initialize linear buffers +#if USE_LINEAR_BUFFER_TX + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 + case 0: + audio->lin_buf_in = lin_buf_in_1; + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 + case 1: + audio->lin_buf_in = lin_buf_in_2; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 + case 2: + audio->lin_buf_in = lin_buf_in_3; + break; +#endif + } +#endif // USE_LINEAR_BUFFER_TX + + // Initialize OUT EP FIFO if required +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING + + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 + case 0: + tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_1)); +#endif + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 + case 1: + tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_2)); +#endif + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 + case 2: + tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_3)); +#endif + break; +#endif + } +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING + + // Initialize linear buffers +#if USE_LINEAR_BUFFER_RX + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 + case 0: + audio->lin_buf_out = lin_buf_out_1; + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 + case 1: + audio->lin_buf_out = lin_buf_out_2; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 + case 2: + audio->lin_buf_out = lin_buf_out_3; + break; +#endif + } +#endif // USE_LINEAR_BUFFER_TX + + // Initialize TX support FIFOs if required +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 + case 0: + audio->tx_supp_ff = tx_supp_ff_1; + audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; + audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&tx_supp_ff_1[cnt], tx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&tx_supp_ff_1[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_1[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 + +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + case 1: + audio->tx_supp_ff = tx_supp_ff_2; + audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; + audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&tx_supp_ff_2[cnt], tx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&tx_supp_ff_2[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_2[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 + case 2: + audio->tx_supp_ff = tx_supp_ff_3; + audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; + audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&tx_supp_ff_3[cnt], tx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&tx_supp_ff_3[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_3[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + } +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + + // Set encoding parameters for Type_I formats +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 + case 0: + audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX; + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + case 1: + audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 + case 2: + audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX; + break; +#endif + } +#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + + // Initialize RX support FIFOs if required +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING + + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 + case 0: + audio->rx_supp_ff = rx_supp_ff_1; + audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; + audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&rx_supp_ff_1[cnt], rx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&rx_supp_ff_1[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_1[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 + +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + case 1: + audio->rx_supp_ff = rx_supp_ff_2; + audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; + audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&rx_supp_ff_2[cnt], rx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&rx_supp_ff_2[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_2[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 + case 2: + audio->rx_supp_ff = rx_supp_ff_3; + audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; + audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ; + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; cnt++) + { + tu_fifo_config(&rx_supp_ff_3[cnt], rx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ, 1, true); +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&rx_supp_ff_3[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_3[cnt]), NULL); +#endif + } + + break; +#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + } +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + + // Set encoding parameters for Type_I formats +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 + case 0: + audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX; + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + case 1: + audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 + case 2: + audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX; + break; +#endif + } +#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + } +} + +void audiod_reset(uint8_t rhport) +{ + (void) rhport; + + for(uint8_t i=0; iep_in_ff); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING + tu_fifo_clear(&audio->ep_out_ff); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) + { + tu_fifo_clear(&audio->tx_supp_ff[cnt]); + } +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING + for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) + { + tu_fifo_clear(&audio->rx_supp_ff[cnt]); + } +#endif + } +} + +uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + (void) max_len; + + TU_VERIFY ( TUSB_CLASS_AUDIO == itf_desc->bInterfaceClass && + AUDIO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass); + + // Verify version is correct - this check can be omitted + TU_VERIFY(itf_desc->bInterfaceProtocol == AUDIO_INT_PROTOCOL_CODE_V2); + + // Verify interrupt control EP is enabled if demanded by descriptor - this should be best some static check however - this check can be omitted + if (itf_desc->bNumEndpoints == 1) // 0 or 1 EPs are allowed + { + TU_VERIFY(CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0); + } + + // Alternate setting MUST be zero - this check can be omitted + TU_VERIFY(itf_desc->bAlternateSetting == 0); + + // Find available audio driver interface + uint8_t i; + for (i = 0; i < CFG_TUD_AUDIO; i++) + { + if (!_audiod_fct[i].p_desc) + { + _audiod_fct[i].p_desc = (uint8_t const *)itf_desc; // Save pointer to AC descriptor which is by specification always the first one + _audiod_fct[i].rhport = rhport; + + // Setup descriptor lengths + switch (i) + { + case 0: + _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_1_DESC_LEN; + break; +#if CFG_TUD_AUDIO > 1 + case 1: + _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_2_DESC_LEN; + break; +#endif +#if CFG_TUD_AUDIO > 2 + case 2: + _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_3_DESC_LEN; + break; +#endif + } + + break; + } + } + + // Verify we found a free one + TU_ASSERT( i < CFG_TUD_AUDIO ); + + // This is all we need so far - the EPs are setup by a later set_interface request (as per UAC2 specification) + uint16_t drv_len = _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; // - TUD_AUDIO_DESC_IAD_LEN since tinyUSB already handles the IAD descriptor + + return drv_len; +} + +static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request) +{ + uint8_t const itf = tu_u16_low(p_request->wIndex); + + // Find index of audio streaming interface + uint8_t func_id, idxItf; + uint8_t const *dummy; + + TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &dummy)); + TU_VERIFY(tud_control_xfer(rhport, p_request, &_audiod_fct[func_id].alt_setting[idxItf], 1)); + + TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf, _audiod_fct[func_id].alt_setting[idxItf]); + + return true; +} + +static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request) +{ + (void) rhport; + + // Here we need to do the following: + + // 1. Find the audio driver assigned to the given interface to be set + // Since one audio driver interface has to be able to cover an unknown number of interfaces (AC, AS + its alternate settings), the best memory efficient way to solve this is to always search through the descriptors. + // The audio driver is mapped to an audio function by a reference pointer to the corresponding AC interface of this audio function which serves as a starting point for searching + + // 2. Close EPs which are currently open + // To do so it is not necessary to know the current active alternate interface since we already save the current EP addresses - we simply close them + + // 3. Open new EP + + uint8_t const itf = tu_u16_low(p_request->wIndex); + uint8_t const alt = tu_u16_low(p_request->wValue); + + TU_LOG2(" Set itf: %u - alt: %u\r\n", itf, alt); + + // Find index of audio streaming interface and index of interface + uint8_t func_id, idxItf; + uint8_t const *p_desc; + TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &p_desc)); + + audiod_function_t* audio = &_audiod_fct[func_id]; + + // Look if there is an EP to be closed - for this driver, there are only 3 possible EPs which may be closed (only AS related EPs can be closed, AC EP (if present) is always open) +#if CFG_TUD_AUDIO_ENABLE_EP_IN + if (audio->ep_in_as_intf_num == itf) + { + audio->ep_in_as_intf_num = 0; + usbd_edpt_close(rhport, audio->ep_in); + + // Clear FIFOs, since data is no longer valid +#if !CFG_TUD_AUDIO_ENABLE_ENCODING + tu_fifo_clear(&audio->ep_in_ff); +#else + for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) + { + tu_fifo_clear(&audio->tx_supp_ff[cnt]); + } +#endif + + // Invoke callback - can be used to stop data sampling + if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); + + audio->ep_in = 0; // Necessary? + + } +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + if (audio->ep_out_as_intf_num == itf) + { + audio->ep_out_as_intf_num = 0; + usbd_edpt_close(rhport, audio->ep_out); + + // Clear FIFOs, since data is no longer valid +#if !CFG_TUD_AUDIO_ENABLE_DECODING + tu_fifo_clear(&audio->ep_out_ff); +#else + for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) + { + tu_fifo_clear(&audio->rx_supp_ff[cnt]); + } +#endif + + // Invoke callback - can be used to stop data sampling + if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); + + audio->ep_out = 0; // Necessary? + + // Close corresponding feedback EP +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + usbd_edpt_close(rhport, audio->ep_fb); + audio->ep_fb = 0; + tu_memclr(&audio->feedback, sizeof(audio->feedback)); +#endif + } +#endif + + // Save current alternative interface setting + audio->alt_setting[idxItf] = alt; + + // Open new EP if necessary - EPs are only to be closed or opened for AS interfaces - Look for AS interface with correct alternate interface + // Get pointer at end + uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; + + // p_desc starts at required interface with alternate setting zero + while (p_desc < p_desc_end) + { + // Find correct interface + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == alt) + { +#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING + uint8_t const * p_desc_parse_for_params = p_desc; +#endif + // From this point forward follow the EP descriptors associated to the current alternate setting interface - Open EPs if necessary + uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints; + while (foundEPs < nEps && p_desc < p_desc_end) + { + if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) + { + tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc; + TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); + + uint8_t const ep_addr = desc_ep->bEndpointAddress; + + //TODO: We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND! + usbd_edpt_clear_stall(rhport, ep_addr); + +#if CFG_TUD_AUDIO_ENABLE_EP_IN + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 0x00) // Check if usage is data EP + { + // Save address + audio->ep_in = ep_addr; + audio->ep_in_as_intf_num = itf; + audio->ep_in_sz = tu_edpt_packet_size(desc_ep); + + // If software encoding is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters +#if CFG_TUD_AUDIO_ENABLE_ENCODING + audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf); + + // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / audio->n_bytes_per_sampe_tx) * audio->n_bytes_per_sampe_tx); + for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) + { + tu_fifo_config(&audio->tx_supp_ff[cnt], audio->tx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); + } + audio->n_ff_used_tx = audio->n_channels_tx / audio->n_channels_per_ff_tx; + TU_ASSERT( audio->n_ff_used_tx <= audio->n_tx_supp_ff ); +#endif + +#endif + + // Schedule first transmit if alternate interface is not zero i.e. streaming is disabled - in case no sample data is available a ZLP is loaded + // It is necessary to trigger this here since the refill is done with an RX FIFO empty interrupt which can only trigger if something was in there + TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_fct[func_id])); + } +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + + if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) // Checking usage not necessary + { + // Save address + audio->ep_out = ep_addr; + audio->ep_out_as_intf_num = itf; + audio->ep_out_sz = tu_edpt_packet_size(desc_ep); + +#if CFG_TUD_AUDIO_ENABLE_DECODING + audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf); + + // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sampe_rx) * audio->n_bytes_per_sampe_rx; + for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) + { + tu_fifo_config(&audio->rx_supp_ff[cnt], audio->rx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); + } + audio->n_ff_used_rx = audio->n_channels_rx / audio->n_channels_per_ff_rx; + TU_ASSERT( audio->n_ff_used_rx <= audio->n_rx_supp_ff ); +#endif +#endif + + // Prepare for incoming data +#if USE_LINEAR_BUFFER_RX + TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); +#else + TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false); +#endif + } + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 1) // Check if usage is explicit data feedback + { + audio->ep_fb = ep_addr; + audio->feedback.frame_shift = desc_ep->bInterval -1; + + // Enable SOF interrupt if callback is implemented + if (tud_audio_feedback_interval_isr) usbd_sof_enable(rhport, true); + } +#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT + + foundEPs += 1; + } + p_desc = tu_desc_next(p_desc); + } + + TU_VERIFY(foundEPs == nEps); + + // Invoke one callback for a final set interface + if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + // Prepare feedback computation if callback is available + if (tud_audio_feedback_params_cb) + { + audio_feedback_params_t fb_param; + + tud_audio_feedback_params_cb(func_id, alt, &fb_param); + audio->feedback.compute_method = fb_param.method; + + // Minimal/Maximum value in 16.16 format for full speed (1ms per frame) or high speed (125 us per frame) + uint32_t const frame_div = (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000; + audio->feedback.min_value = (fb_param.sample_freq/frame_div - 1) << 16; + audio->feedback.max_value = (fb_param.sample_freq/frame_div + 1) << 16; + + switch(fb_param.method) + { + case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: + case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT: + case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2: + set_fb_params_freq(audio, fb_param.sample_freq, fb_param.frequency.mclk_freq); + break; + + #if 0 // implement later + case AUDIO_FEEDBACK_METHOD_FIFO_COUNT: + { + uint64_t fb64 = ((uint64_t) fb_param.sample_freq) << 16; + audio->feedback.compute.fifo_count.nominal_value = (uint32_t) (fb64 / frame_div); + audio->feedback.compute.fifo_count.threshold_bytes = fb_param.fifo_count.threshold_bytes; + + tud_audio_fb_set(audio->feedback.compute.fifo_count.nominal_value); + } + break; + #endif + + // nothing to do + default: break; + } + } +#endif + + // We are done - abort loop + break; + } + + // Moving forward + p_desc = tu_desc_next(p_desc); + } + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + // Disable SOF interrupt if no driver has any enabled feedback EP + bool disable = true; + for(uint8_t i=0; i < CFG_TUD_AUDIO; i++) + { + if (_audiod_fct[i].ep_fb != 0) + { + disable = false; + break; + } + } + if (disable) usbd_sof_enable(rhport, false); +#endif + + tud_control_status(rhport, p_request); + + return true; +} + +// Invoked when class request DATA stage is finished. +// return false to stall control EP (e.g Host send non-sense DATA) +static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const * p_request) +{ + // Handle audio class specific set requests + if(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) + { + uint8_t func_id; + + switch (p_request->bmRequestType_bit.recipient) + { + case TUSB_REQ_RCPT_INTERFACE: + { + uint8_t itf = TU_U16_LOW(p_request->wIndex); + uint8_t entityID = TU_U16_HIGH(p_request->wIndex); + + if (entityID != 0) + { + if (tud_audio_set_req_entity_cb) + { + // Check if entity is present and get corresponding driver index + TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); + + // Invoke callback + return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); + } + else + { + TU_LOG2(" No entity set request callback available!\r\n"); + return false; // In case no callback function is present or request can not be conducted we stall it + } + } + else + { + if (tud_audio_set_req_itf_cb) + { + // Find index of audio driver structure and verify interface really exists + TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); + + // Invoke callback + return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); + } + else + { + TU_LOG2(" No interface set request callback available!\r\n"); + return false; // In case no callback function is present or request can not be conducted we stall it + } + } + } + break; + + case TUSB_REQ_RCPT_ENDPOINT: + { + uint8_t ep = TU_U16_LOW(p_request->wIndex); + + if (tud_audio_set_req_ep_cb) + { + // Check if entity is present and get corresponding driver index + TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); + + // Invoke callback + return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); + } + else + { + TU_LOG2(" No EP set request callback available!\r\n"); + return false; // In case no callback function is present or request can not be conducted we stall it + } + } + break; + // Unknown/Unsupported recipient + default: TU_BREAKPOINT(); return false; + } + } + return true; +} + +// Handle class control request +// return false to stall control endpoint (e.g unsupported request) +static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const * p_request) +{ + (void) rhport; + + // Handle standard requests - standard set requests usually have no data stage so we also handle set requests here + if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) + { + switch (p_request->bRequest) + { + case TUSB_REQ_GET_INTERFACE: + return audiod_get_interface(rhport, p_request); + + case TUSB_REQ_SET_INTERFACE: + return audiod_set_interface(rhport, p_request); + + // Unknown/Unsupported request + default: TU_BREAKPOINT(); return false; + } + } + + // Handle class requests + if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) + { + uint8_t itf = TU_U16_LOW(p_request->wIndex); + uint8_t func_id; + + // Conduct checks which depend on the recipient + switch (p_request->bmRequestType_bit.recipient) + { + case TUSB_REQ_RCPT_INTERFACE: + { + uint8_t entityID = TU_U16_HIGH(p_request->wIndex); + + // Verify if entity is present + if (entityID != 0) + { + // Find index of audio driver structure and verify entity really exists + TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); + + // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests + if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) + { + if (tud_audio_get_req_entity_cb) + { + return tud_audio_get_req_entity_cb(rhport, p_request); + } + else + { + TU_LOG2(" No entity get request callback available!\r\n"); + return false; // Stall + } + } + } + else + { + // Find index of audio driver structure and verify interface really exists + TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); + + // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests + if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) + { + if (tud_audio_get_req_itf_cb) + { + return tud_audio_get_req_itf_cb(rhport, p_request); + } + else + { + TU_LOG2(" No interface get request callback available!\r\n"); + return false; // Stall + } + } + } + } + break; + + case TUSB_REQ_RCPT_ENDPOINT: + { + uint8_t ep = TU_U16_LOW(p_request->wIndex); + + // Find index of audio driver structure and verify EP really exists + TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); + + // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests + if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) + { + if (tud_audio_get_req_ep_cb) + { + return tud_audio_get_req_ep_cb(rhport, p_request); + } + else + { + TU_LOG2(" No EP get request callback available!\r\n"); + return false; // Stall + } + } + } + break; + + // Unknown/Unsupported recipient + default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false; + } + + // If we end here, the received request is a set request - we schedule a receive for the data stage and return true here. We handle the rest later in audiod_control_complete() once the data stage was finished + TU_VERIFY(tud_control_xfer(rhport, p_request, _audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz)); + return true; + } + + // There went something wrong - unsupported control request type + TU_BREAKPOINT(); + return false; +} + +bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if ( stage == CONTROL_STAGE_SETUP ) + { + return audiod_control_request(rhport, request); + } + else if ( stage == CONTROL_STAGE_DATA ) + { + return audiod_control_complete(rhport, request); + } + + return true; +} + +bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) result; + (void) xferred_bytes; + + // Search for interface belonging to given end point address and proceed as required + for (uint8_t func_id = 0; func_id < CFG_TUD_AUDIO; func_id++) + { + audiod_function_t* audio = &_audiod_fct[func_id]; + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN + + // Data transmission of control interrupt finished + if (audio->ep_int_ctr == ep_addr) + { + // According to USB2 specification, maximum payload of interrupt EP is 8 bytes on low speed, 64 bytes on full speed, and 1024 bytes on high speed (but only if an alternate interface other than 0 is used - see specification p. 49) + // In case there is nothing to send we have to return a NAK - this is taken care of by PHY ??? + // In case of an erroneous transmission a retransmission is conducted - this is taken care of by PHY ??? + + // I assume here, that things above are handled by PHY + // All transmission is done - what remains to do is to inform job was completed + + if (tud_audio_int_ctr_done_cb) TU_VERIFY(tud_audio_int_ctr_done_cb(rhport, (uint16_t) xferred_bytes)); + } + +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN + + // Data transmission of audio packet finished + if (audio->ep_in == ep_addr && audio->alt_setting != 0) + { + // USB 2.0, section 5.6.4, third paragraph, states "An isochronous endpoint must specify its required bus access period. However, an isochronous endpoint must be prepared to handle poll rates faster than the one specified." + // That paragraph goes on to say "An isochronous IN endpoint must return a zero-length packet whenever data is requested at a faster interval than the specified interval and data is not available." + // This can only be solved reliably if we load a ZLP after every IN transmission since we can not say if the host requests samples earlier than we declared! Once all samples are collected we overwrite the loaded ZLP. + + // Check if there is data to load into EPs buffer - if not load it with ZLP + // Be aware - we as a device are not able to know if the host polls for data with a faster rate as we stated this in the descriptors. Therefore we always have to put something into the EPs buffer. However, once we did that, there is no way of aborting this or replacing what we put into the buffer before! + // This is the only place where we can fill something into the EPs buffer! + + // Load new data + TU_VERIFY(audiod_tx_done_cb(rhport, audio)); + + // Transmission of ZLP is done by audiod_tx_done_cb() + return true; + } +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + + // New audio packet received + if (audio->ep_out == ep_addr) + { + TU_VERIFY(audiod_rx_done_cb(rhport, audio, (uint16_t) xferred_bytes)); + return true; + } + + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + // Transmission of feedback EP finished + if (audio->ep_fb == ep_addr) + { + if (tud_audio_fb_done_cb) tud_audio_fb_done_cb(func_id); + + // Schedule a transmit with the new value if EP is not busy + if (!usbd_edpt_busy(rhport, audio->ep_fb)) + { + // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent + return audiod_fb_send(rhport, audio); + } + } +#endif +#endif + } + + return false; +} + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + +static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq) +{ + // Check if frame interval is within sane limits + // The interval value n_frames was taken from the descriptors within audiod_set_interface() + + // n_frames_min is ceil(2^10 * f_s / f_m) for full speed and ceil(2^13 * f_s / f_m) for high speed + // this lower limit ensures the measures feedback value has sufficient precision + uint32_t const k = (TUSB_SPEED_FULL == tud_speed_get()) ? 10 : 13; + uint32_t const n_frame = (1UL << audio->feedback.frame_shift); + + if ( (((1UL << k) * sample_freq / mclk_freq) + 1) > n_frame ) + { + TU_LOG1(" UAC2 feedback interval too small\r\n"); TU_BREAKPOINT(); return false; + } + + // Check if parameters really allow for a power of two division + if ((mclk_freq % sample_freq) == 0 && tu_is_power_of_two(mclk_freq / sample_freq)) + { + audio->feedback.compute_method = AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2; + audio->feedback.compute.power_of_2 = 16 - audio->feedback.frame_shift - tu_log2(mclk_freq / sample_freq); + } + else if ( audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT) + { + audio->feedback.compute.float_const = (float)sample_freq / mclk_freq * (1UL << (16 - audio->feedback.frame_shift)); + } + else + { + audio->feedback.compute.fixed.sample_freq = sample_freq; + audio->feedback.compute.fixed.mclk_freq = mclk_freq; + } + + return true; +} + +uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles) +{ + audiod_function_t* audio = &_audiod_fct[func_id]; + uint32_t feedback; + + switch (audio->feedback.compute_method) + { + case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2: + feedback = (cycles << audio->feedback.compute.power_of_2); + break; + + case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT: + feedback = (uint32_t) ((float) cycles * audio->feedback.compute.float_const); + break; + + case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: + { + uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - audio->feedback.frame_shift); + feedback = (uint32_t) (fb64 / audio->feedback.compute.fixed.mclk_freq); + } + break; + + default: return 0; + } + + // For Windows: https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/usb-2-0-audio-drivers + // The size of isochronous packets created by the device must be within the limits specified in FMT-2.0 section 2.3.1.1. + // This means that the deviation of actual packet size from nominal size must not exceed +/- one audio slot + // (audio slot = channel count samples). + if ( feedback > audio->feedback.max_value ) feedback = audio->feedback.max_value; + if ( feedback < audio->feedback.min_value ) feedback = audio->feedback.min_value; + + tud_audio_n_fb_set(func_id, feedback); + + return feedback; +} +#endif + +TU_ATTR_FAST_FUNC void audiod_sof_isr (uint8_t rhport, uint32_t frame_count) +{ + (void) rhport; + (void) frame_count; + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + // Determine feedback value - The feedback method is described in 5.12.4.2 of the USB 2.0 spec + // Boiled down, the feedback value Ff = n_samples / (micro)frame. + // Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s) + // The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where P = min( ceil(log2(f_m / f_s)), K) + // feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames + + // Iterate over audio functions and set feedback value + for(uint8_t i=0; i < CFG_TUD_AUDIO; i++) + { + audiod_function_t* audio = &_audiod_fct[i]; + + if (audio->ep_fb != 0) + { + // HS shift need to be adjusted since SOF event is generated for frame only + uint8_t const hs_adjust = (TUSB_SPEED_HIGH == tud_speed_get()) ? 3 : 0; + uint32_t const interval = 1UL << (audio->feedback.frame_shift - hs_adjust); + if ( 0 == (frame_count & (interval-1)) ) + { + if(tud_audio_feedback_interval_isr) tud_audio_feedback_interval_isr(i, frame_count, audio->feedback.frame_shift); + } + } + } +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +} + +bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len) +{ + // Handles only sending of data not receiving + if (p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) return false; + + // Get corresponding driver index + uint8_t func_id; + uint8_t itf = TU_U16_LOW(p_request->wIndex); + + // Conduct checks which depend on the recipient + switch (p_request->bmRequestType_bit.recipient) + { + case TUSB_REQ_RCPT_INTERFACE: + { + uint8_t entityID = TU_U16_HIGH(p_request->wIndex); + + // Verify if entity is present + if (entityID != 0) + { + // Find index of audio driver structure and verify entity really exists + TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); + } + else + { + // Find index of audio driver structure and verify interface really exists + TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); + } + } + break; + + case TUSB_REQ_RCPT_ENDPOINT: + { + uint8_t ep = TU_U16_LOW(p_request->wIndex); + + // Find index of audio driver structure and verify EP really exists + TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); + } + break; + + // Unknown/Unsupported recipient + default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false; + } + + // Crop length + if (len > _audiod_fct[func_id].ctrl_buf_sz) len = _audiod_fct[func_id].ctrl_buf_sz; + + // Copy into buffer + memcpy((void *)_audiod_fct[func_id].ctrl_buf, data, (size_t)len); + + // Schedule transmit + return tud_control_xfer(rhport, p_request, (void*)_audiod_fct[func_id].ctrl_buf, len); +} + +// This helper function finds for a given audio function and AS interface number the index of the attached driver structure, the index of the interface in the audio function +// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and +// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero. +static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int) +{ + if (audio->p_desc) + { + // Get pointer at end + uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; + + // Advance past AC descriptors + uint8_t const *p_desc = tu_desc_next(audio->p_desc); + p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength; + + uint8_t tmp = 0; + while (p_desc < p_desc_end) + { + // We assume the number of alternate settings is increasing thus we return the index of alternate setting zero! + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0) + { + if (((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf) + { + *idxItf = tmp; + *pp_desc_int = p_desc; + return true; + } + // Increase index, bytes read, and pointer + tmp++; + } + p_desc = tu_desc_next(p_desc); + } + } + return false; +} + +// This helper function finds for a given AS interface number the index of the attached driver structure, the index of the interface in the audio function +// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and +// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero. +static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int) +{ + // Loop over audio driver interfaces + uint8_t i; + for (i = 0; i < CFG_TUD_AUDIO; i++) + { + if (audiod_get_AS_interface_index(itf, &_audiod_fct[i], idxItf, pp_desc_int)) + { + *func_id = i; + return true; + } + } + + return false; +} + +// Verify an entity with the given ID exists and returns also the corresponding driver index +static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id) +{ + uint8_t i; + for (i = 0; i < CFG_TUD_AUDIO; i++) + { + // Look for the correct driver by checking if the unique standard AC interface number fits + if (_audiod_fct[i].p_desc && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf) + { + // Get pointers after class specific AC descriptors and end of AC descriptors - entities are defined in between + uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc); // Points to CS AC descriptor + uint8_t const *p_desc_end = ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength + p_desc; + p_desc = tu_desc_next(p_desc); // Get past CS AC descriptor + + while (p_desc < p_desc_end) + { + if (p_desc[3] == entityID) // Entity IDs are always at offset 3 + { + *func_id = i; + return true; + } + p_desc = tu_desc_next(p_desc); + } + } + } + return false; +} + +static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id) +{ + uint8_t i; + for (i = 0; i < CFG_TUD_AUDIO; i++) + { + if (_audiod_fct[i].p_desc) + { + // Get pointer at beginning and end + uint8_t const *p_desc = _audiod_fct[i].p_desc; + uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; + + while (p_desc < p_desc_end) + { + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf) + { + *func_id = i; + return true; + } + p_desc = tu_desc_next(p_desc); + } + } + } + return false; +} + +static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id) +{ + uint8_t i; + for (i = 0; i < CFG_TUD_AUDIO; i++) + { + if (_audiod_fct[i].p_desc) + { + // Get pointer at end + uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length; + + // Advance past AC descriptors - EP we look for are streaming EPs + uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc); + p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength; + + while (p_desc < p_desc_end) + { + if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT && ((tusb_desc_endpoint_t const * )p_desc)->bEndpointAddress == ep) + { + *func_id = i; + return true; + } + p_desc = tu_desc_next(p_desc); + } + } + } + return false; +} + +#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING +// p_desc points to the AS interface of alternate setting zero +// itf is the interface number of the corresponding interface - we check if the interface belongs to EP in or EP out to see if it is a TX or RX parameter +// Currently, only AS interfaces with an EP (in or out) are supposed to be parsed for! +static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf) +{ +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT + if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) return; // Abort, this interface has no EP, this driver does not support this currently +#endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT + if (as_itf != audio->ep_in_as_intf_num) return; +#endif +#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT + if (as_itf != audio->ep_out_as_intf_num) return; +#endif + + p_desc = tu_desc_next(p_desc); // Exclude standard AS interface descriptor of current alternate interface descriptor + + while (p_desc < p_desc_end) + { + // Abort if follow up descriptor is a new standard interface descriptor - indicates the last AS descriptor was already finished + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) break; + + // Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format type and format and also to get number of physical channels + if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL) + { +#if CFG_TUD_AUDIO_ENABLE_EP_IN + if (as_itf == audio->ep_in_as_intf_num) + { + audio->n_channels_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels; + audio->format_type_tx = (audio_format_type_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType); + +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + audio->format_type_I_tx = (audio_data_format_type_I_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats); +#endif + } +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + if (as_itf == audio->ep_out_as_intf_num) + { + audio->n_channels_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels; + audio->format_type_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType; +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + audio->format_type_I_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats; +#endif + } +#endif + } + + // Look for a Type I Format Type Descriptor(2.3.1.6 - Audio Formats) +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_FORMAT_TYPE && ((audio_desc_type_I_format_t const * )p_desc)->bFormatType == AUDIO_FORMAT_TYPE_I) + { +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT + if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) break; // Abort loop, this interface has no EP, this driver does not support this currently +#endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT + if (as_itf != audio->ep_in_as_intf_num) break; +#endif +#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT + if (as_itf != audio->ep_out_as_intf_num) break; +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN + if (as_itf == audio->ep_in_as_intf_num) + { + audio->n_bytes_per_sampe_tx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; + } +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + if (as_itf == audio->ep_out_as_intf_num) + { + audio->n_bytes_per_sampe_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; + } +#endif + } +#endif + + // Other format types are not supported yet + + p_desc = tu_desc_next(p_desc); + } +} +#endif + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + +bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + + // Format the feedback value +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION + if ( TUSB_SPEED_FULL == tud_speed_get() ) + { + uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].feedback.value; + + // For FS format is 10.14 + *(fb++) = (feedback >> 2) & 0xFF; + *(fb++) = (feedback >> 10) & 0xFF; + *(fb++) = (feedback >> 18) & 0xFF; + // 4th byte is needed to work correctly with MS Windows + *fb = 0; + }else +#else + { + // Send value as-is, caller will choose the appropriate format + _audiod_fct[func_id].feedback.value = feedback; + } +#endif + + // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value + if (!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb)) + { + return audiod_fb_send(_audiod_fct[func_id].rhport, &_audiod_fct[func_id]); + } + + return true; +} +#endif + +// No security checks here - internal function only which should always succeed +uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio) +{ + for (uint8_t cnt=0; cnt < CFG_TUD_AUDIO; cnt++) + { + if (&_audiod_fct[cnt] == audio) return cnt; + } + return 0; +} + +#endif //CFG_TUD_ENABLED && CFG_TUD_AUDIO diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/audio/audio_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/audio/audio_device.h new file mode 100644 index 00000000..0ef100fa --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/audio/audio_device.h @@ -0,0 +1,699 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Ha Thach (tinyusb.org) + * Copyright (c) 2020 Reinhard Panhuber + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_AUDIO_DEVICE_H_ +#define _TUSB_AUDIO_DEVICE_H_ + +#include "audio.h" + +//--------------------------------------------------------------------+ +// Class Driver Configuration +//--------------------------------------------------------------------+ + +// All sizes are in bytes! + +#ifndef CFG_TUD_AUDIO_FUNC_1_DESC_LEN +#error You must tell the driver the length of the audio function descriptor including IAD descriptor +#endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_DESC_LEN +#error You must tell the driver the length of the audio function descriptor including IAD descriptor +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_DESC_LEN +#error You must tell the driver the length of the audio function descriptor including IAD descriptor +#endif +#endif + +// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces +#ifndef CFG_TUD_AUDIO_FUNC_1_N_AS_INT +#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! +#endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_N_AS_INT +#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_N_AS_INT +#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! +#endif +#endif + +// Size of control buffer used to receive and send control messages via EP0 - has to be big enough to hold your biggest request structure e.g. range requests with multiple intervals defined or cluster descriptors +#ifndef CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ +#error You must define an audio class control request buffer size! +#endif + +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ +#error You must define an audio class control request buffer size! +#endif +#endif + +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ +#error You must define an audio class control request buffer size! +#endif +#endif + +// End point sizes IN BYTES - Limits: Full Speed <= 1023, High Speed <= 1024 +#ifndef CFG_TUD_AUDIO_ENABLE_EP_IN +#define CFG_TUD_AUDIO_ENABLE_EP_IN 0 // TX +#endif + +#ifndef CFG_TUD_AUDIO_ENABLE_EP_OUT +#define CFG_TUD_AUDIO_ENABLE_EP_OUT 0 // RX +#endif + +// Maximum EP sizes for all alternate AS interface settings - used for checks and buffer allocation +#if CFG_TUD_AUDIO_ENABLE_EP_IN +#ifndef CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX +#error You must tell the driver the biggest EP IN size! +#endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX +#error You must tell the driver the biggest EP IN size! +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX +#error You must tell the driver the biggest EP IN size! +#endif +#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +#ifndef CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX +#error You must tell the driver the biggest EP OUT size! +#endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX +#error You must tell the driver the biggest EP OUT size! +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX +#error You must tell the driver the biggest EP OUT size! +#endif +#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT + +// Software EP FIFO buffer sizes - must be >= max EP SIZEs! +#ifndef CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ 0 +#endif + +#ifndef CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ +#define CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ 0 +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN +#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size +#endif + +#if CFG_TUD_AUDIO > 1 +#if CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size +#endif +#endif + +#if CFG_TUD_AUDIO > 2 +#if CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size +#endif +#endif +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size +#endif + +#if CFG_TUD_AUDIO > 1 +#if CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size +#endif +#endif + +#if CFG_TUD_AUDIO > 2 +#if CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX +#error EP software buffer size MUST BE at least as big as maximum EP size +#endif +#endif +#endif + +// Enable/disable feedback EP (required for asynchronous RX applications) +#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // Feedback - 0 or 1 +#endif + +// Enable/disable conversion from 16.16 to 10.14 format on full-speed devices. See tud_audio_n_fb_set(). +#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION +#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 0 // 0 or 1 +#endif + +// Audio interrupt control EP size - disabled if 0 +#ifndef CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 // Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74) +#endif + +#ifndef CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE +#define CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE 6 // Buffer size of audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74) +#endif + +// Use software encoding/decoding + +// The software coding feature of the driver is not mandatory. It is useful if, for instance, you have two I2S streams which need to be interleaved +// into a single PCM stream as SAMPLE_1 | SAMPLE_2 | SAMPLE_3 | SAMPLE_4. +// +// Currently, only PCM type I encoding/decoding is supported! +// +// If the coding feature is to be used, support FIFOs need to be configured. Their sizes and numbers are defined below. + +// Encoding/decoding is done in software and thus time consuming. If you can encode/decode your stream more efficiently do not use the +// support FIFOs but write/read directly into/from the EP_X_SW_BUFFER_FIFOs using +// - tud_audio_n_write() or +// - tud_audio_n_read(). +// To write/read to/from the support FIFOs use +// - tud_audio_n_write_support_ff() or +// - tud_audio_n_read_support_ff(). +// +// The encoding/decoding format type done is defined below. +// +// The encoding/decoding starts when the private callback functions +// - audio_tx_done_cb() +// - audio_rx_done_cb() +// are invoked. If support FIFOs are used, the corresponding encoding/decoding functions are called from there. +// Once encoding/decoding is done the result is put directly into the EP_X_SW_BUFFER_FIFOs. You can use the public callback functions +// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb() +// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb() +// if you want to get informed what happened. +// +// If you don't use the support FIFOs you may use the public callback functions +// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb() +// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb() +// to write/read from/into the EP_X_SW_BUFFER_FIFOs at the right time. +// +// If you need a different encoding which is not support so far implement it in the +// - audio_tx_done_cb() +// - audio_rx_done_cb() +// functions. + +// Enable encoding/decodings - for these to work, support FIFOs need to be setup in appropriate numbers and size +// The actual coding parameters of active AS alternate interface is parsed from the descriptors + +// The item size of the FIFO is always fixed to one i.e. bytes! Furthermore, the actively used FIFO depth is reconfigured such that the depth is a multiple of the current sample size in order to avoid samples to get split up in case of a wrap in the FIFO ring buffer (depth = (max_depth / sampe_sz) * sampe_sz)! +// This is important to remind in case you use DMAs! If the sample sizes changes, the DMA MUST BE RECONFIGURED just like the FIFOs for a different depth!!! + +// For PCM encoding/decoding + +#ifndef CFG_TUD_AUDIO_ENABLE_ENCODING +#define CFG_TUD_AUDIO_ENABLE_ENCODING 0 +#endif + +#ifndef CFG_TUD_AUDIO_ENABLE_DECODING +#define CFG_TUD_AUDIO_ENABLE_DECODING 0 +#endif + +// This enabling allows to save the current coding parameters e.g. # of bytes per sample etc. - TYPE_I includes common PCM encoding +#ifndef CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING +#define CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING 0 +#endif + +#ifndef CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING +#define CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING 0 +#endif + +// Type I Coding parameters not given within UAC2 descriptors +// It would be possible to allow for a more flexible setting and not fix this parameter as done below. However, this is most often not needed and kept for later if really necessary. The more flexible setting could be implemented within set_interface(), however, how the values are saved per alternate setting is to be determined! +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING +#ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO +#endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO +#endif +#endif +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING +#ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO +#endif +#if CFG_TUD_AUDIO > 1 +#ifndef CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO +#endif +#endif +#if CFG_TUD_AUDIO > 2 +#ifndef CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX +#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO +#endif +#endif +#endif + +// Remaining types not support so far + +// Number of support FIFOs to set up - multiple channels can be handled by one FIFO - very common is two channels per FIFO stemming from one I2S interface +#ifndef CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO 0 +#endif + +#ifndef CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO +#define CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO 0 +#endif + +// Size of support FIFOs IN BYTES - if size > 0 there are as many FIFOs set up as CFG_TUD_AUDIO_FUNC_X_N_TX_SUPP_SW_FIFO and CFG_TUD_AUDIO_FUNC_X_N_RX_SUPP_SW_FIFO +#ifndef CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ 0 // FIFO size - minimum size: ceil(f_s/1000) * max(# of TX channels) / (# of TX support FIFOs) * max(# of bytes per sample) +#endif +#ifndef CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ 0 +#endif + +#ifndef CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ 0 // FIFO size - minimum size: ceil(f_s/1000) * max(# of RX channels) / (# of RX support FIFOs) * max(# of bytes per sample) +#endif +#ifndef CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ 0 +#endif +#ifndef CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ +#define CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ 0 +#endif + +//static_assert(sizeof(tud_audio_desc_lengths) != CFG_TUD_AUDIO, "Supply audio function descriptor pack length!"); + +// Supported types of this driver: +// AUDIO_DATA_FORMAT_TYPE_I_PCM - Required definitions: CFG_TUD_AUDIO_N_CHANNELS and CFG_TUD_AUDIO_BYTES_PER_CHANNEL + +#ifdef __cplusplus +extern "C" { +#endif + +/** \addtogroup AUDIO_Serial Serial + * @{ + * \defgroup AUDIO_Serial_Device Device + * @{ */ + +//--------------------------------------------------------------------+ +// Application API (Multiple Interfaces) +// CFG_TUD_AUDIO > 1 +//--------------------------------------------------------------------+ +bool tud_audio_n_mounted (uint8_t func_id); + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +uint16_t tud_audio_n_available (uint8_t func_id); +uint16_t tud_audio_n_read (uint8_t func_id, void* buffer, uint16_t bufsize); +bool tud_audio_n_clear_ep_out_ff (uint8_t func_id); // Delete all content in the EP OUT FIFO +tu_fifo_t* tud_audio_n_get_ep_out_ff (uint8_t func_id); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING +bool tud_audio_n_clear_rx_support_ff (uint8_t func_id, uint8_t ff_idx); // Delete all content in the support RX FIFOs +uint16_t tud_audio_n_available_support_ff (uint8_t func_id, uint8_t ff_idx); +uint16_t tud_audio_n_read_support_ff (uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize); +tu_fifo_t* tud_audio_n_get_rx_support_ff (uint8_t func_id, uint8_t ff_idx); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +uint16_t tud_audio_n_write (uint8_t func_id, const void * data, uint16_t len); +bool tud_audio_n_clear_ep_in_ff (uint8_t func_id); // Delete all content in the EP IN FIFO +tu_fifo_t* tud_audio_n_get_ep_in_ff (uint8_t func_id); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING +uint16_t tud_audio_n_flush_tx_support_ff (uint8_t func_id); // Force all content in the support TX FIFOs to be written into EP SW FIFO +bool tud_audio_n_clear_tx_support_ff (uint8_t func_id, uint8_t ff_idx); +uint16_t tud_audio_n_write_support_ff (uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len); +tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_idx); +#endif + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +uint16_t tud_audio_int_ctr_n_write (uint8_t func_id, uint8_t const* buffer, uint16_t len); +#endif + +//--------------------------------------------------------------------+ +// Application API (Interface0) +//--------------------------------------------------------------------+ + +static inline bool tud_audio_mounted (void); + +// RX API + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +static inline uint16_t tud_audio_available (void); +static inline bool tud_audio_clear_ep_out_ff (void); // Delete all content in the EP OUT FIFO +static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize); +static inline tu_fifo_t* tud_audio_get_ep_out_ff (void); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING +static inline bool tud_audio_clear_rx_support_ff (uint8_t ff_idx); +static inline uint16_t tud_audio_available_support_ff (uint8_t ff_idx); +static inline uint16_t tud_audio_read_support_ff (uint8_t ff_idx, void* buffer, uint16_t bufsize); +static inline tu_fifo_t* tud_audio_get_rx_support_ff (uint8_t ff_idx); +#endif + +// TX API + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +static inline uint16_t tud_audio_write (const void * data, uint16_t len); +static inline bool tud_audio_clear_ep_in_ff (void); +static inline tu_fifo_t* tud_audio_get_ep_in_ff (void); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING +static inline uint16_t tud_audio_flush_tx_support_ff (void); +static inline uint16_t tud_audio_clear_tx_support_ff (uint8_t ff_idx); +static inline uint16_t tud_audio_write_support_ff (uint8_t ff_idx, const void * data, uint16_t len); +static inline tu_fifo_t* tud_audio_get_tx_support_ff (uint8_t ff_idx); +#endif + +// INT CTR API + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +static inline uint16_t tud_audio_int_ctr_write (uint8_t const* buffer, uint16_t len); +#endif + +// Buffer control EP data and schedule a transmit +// This function is intended to be used if you do not have a persistent buffer or memory location available (e.g. non-local variables) and need to answer onto a +// get request. This function buffers your answer request frame into the control buffer of the corresponding audio driver and schedules a transmit for sending it. +// Since transmission is triggered via interrupts, a persistent memory location is required onto which the buffer pointer in pointing. If you already have such +// available you may directly use 'tud_control_xfer(...)'. In this case data does not need to be copied into an additional buffer and you save some time. +// If the request's wLength is zero, a status packet is sent instead. +bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len); + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ + +#if CFG_TUD_AUDIO_ENABLE_EP_IN +TU_ATTR_WEAK bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting); +TU_ATTR_WEAK bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +TU_ATTR_WEAK bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting); +TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting); +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id); + + +// determined by the user itself and set by use of tud_audio_n_fb_set(). The feedback value may be determined e.g. from some fill status of some FIFO buffer. Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus less CPU load, disadvantage: typically a larger FIFO is needed to compensate for jitter (e.g. 8 frames), i.e. a larger delay is introduced. + +// Feedback value is calculated within the audio driver by use of SOF interrupt. The driver needs information about the master clock f_m from which the audio sample frequency f_s is derived, f_s itself, and the cycle count of f_m at time of the SOF interrupt (e.g. by use of a hardware counter) - see tud_audio_set_fb_params(). Advantage: Reduced jitter in the feedback value computation, hence, the receive FIFO can be smaller (e.g. 2 frames) and thus a smaller delay is possible, disadvantage: higher CPU load due to SOF ISR handling every frame i.e. 1ms or 125us. This option is a great starting point to try the SOF ISR option but depending on your hardware setup (performance of the CPU) it might not work. If so, figure out why and use the next option. (The most critical point is the reading of the cycle counter value of f_m. It is read from within the SOF ISR - see: audiod_sof() -, hence, the ISR must has a high priority such that no software dependent "random" delay i.e. jitter is introduced). + +// Feedback value is determined by the user by use of SOF interrupt. The user may use tud_audio_sof_isr() which is called every SOF (of course only invoked when an alternate interface other than zero was set). The number of frames used to determine the feedback value for the currently active alternate setting can be get by tud_audio_get_fb_n_frames(). The feedback value must be set by use of tud_audio_n_fb_set(). + +// This function is used to provide data rate feedback from an asynchronous sink. Feedback value will be sent at FB endpoint interval till it's changed. +// +// The feedback format is specified to be 16.16 for HS and 10.14 for FS devices (see Universal Serial Bus Specification Revision 2.0 5.12.4.2). By default, +// the choice of format is left to the caller and feedback argument is sent as-is. If CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION is set, then tinyusb +// expects 16.16 format and handles the conversion to 10.14 on FS. +// +// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 devices. On Linux and macOS it seems the +// driver can work with either format. So a good compromise is to keep format correction disabled and stick to 16.16 format. + +// Feedback value can be determined from within the SOF ISR of the audio driver. This should reduce jitter. If the feature is used, the user can not set the feedback value. + +// Determine feedback value - The feedback method is described in 5.12.4.2 of the USB 2.0 spec +// Boiled down, the feedback value Ff = n_samples / (micro)frame. +// Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s) +// The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where P = min( ceil(log2(f_m / f_s)), K) +// feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames + +bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback); +static inline bool tud_audio_fb_set(uint32_t feedback); + +// Update feedback value with passed cycles since last time this update function is called. +// Typically called within tud_audio_sof_isr(). Required tud_audio_feedback_params_cb() is implemented +// This function will also call tud_audio_feedback_set() +// return feedback value in 16.16 for reference (0 for error) +uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles); + +enum { + AUDIO_FEEDBACK_METHOD_DISABLED, + AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED, + AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT, + AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2, + + // impelemnt later + // AUDIO_FEEDBACK_METHOD_FIFO_COUNT +}; + +typedef struct { + uint8_t method; + uint32_t sample_freq; // sample frequency in Hz + + union { + struct { + uint32_t mclk_freq; // Main clock frequency in Hz i.e. master clock to which sample clock is based on + }frequency; + +#if 0 // implement later + struct { + uint32_t threshold_bytes; // minimum number of bytes received to be considered as filled/ready + }fifo_count; +#endif + }; +}audio_feedback_params_t; + +// Invoked when needed to set feedback parameters +TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param); + +// Callback in ISR context, invoked periodically according to feedback endpoint bInterval. +// Could be used to compute and update feedback value, should be placed in RAM if possible +// frame_number : current SOF count +// interval_shift: number of bit shift i.e log2(interval) from Feedback endpoint descriptor +TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift); + +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t n_bytes_copied); +#endif + +// Invoked when audio set interface request received +TU_ATTR_WEAK bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request); + +// Invoked when audio set interface request received which closes an EP +TU_ATTR_WEAK bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request); + +// Invoked when audio class specific set request received for an EP +TU_ATTR_WEAK bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); + +// Invoked when audio class specific set request received for an interface +TU_ATTR_WEAK bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); + +// Invoked when audio class specific set request received for an entity +TU_ATTR_WEAK bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); + +// Invoked when audio class specific get request received for an EP +TU_ATTR_WEAK bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request); + +// Invoked when audio class specific get request received for an interface +TU_ATTR_WEAK bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request); + +// Invoked when audio class specific get request received for an entity +TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request); + +//--------------------------------------------------------------------+ +// Inline Functions +//--------------------------------------------------------------------+ + +static inline bool tud_audio_mounted(void) +{ + return tud_audio_n_mounted(0); +} + +// RX API + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING + +static inline uint16_t tud_audio_available(void) +{ + return tud_audio_n_available(0); +} + +static inline uint16_t tud_audio_read(void* buffer, uint16_t bufsize) +{ + return tud_audio_n_read(0, buffer, bufsize); +} + +static inline bool tud_audio_clear_ep_out_ff(void) +{ + return tud_audio_n_clear_ep_out_ff(0); +} + +static inline tu_fifo_t* tud_audio_get_ep_out_ff(void) +{ + return tud_audio_n_get_ep_out_ff(0); +} + +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING + +static inline bool tud_audio_clear_rx_support_ff(uint8_t ff_idx) +{ + return tud_audio_n_clear_rx_support_ff(0, ff_idx); +} + +static inline uint16_t tud_audio_available_support_ff(uint8_t ff_idx) +{ + return tud_audio_n_available_support_ff(0, ff_idx); +} + +static inline uint16_t tud_audio_read_support_ff(uint8_t ff_idx, void* buffer, uint16_t bufsize) +{ + return tud_audio_n_read_support_ff(0, ff_idx, buffer, bufsize); +} + +static inline tu_fifo_t* tud_audio_get_rx_support_ff(uint8_t ff_idx) +{ + return tud_audio_n_get_rx_support_ff(0, ff_idx); +} + +#endif + +// TX API + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING + +static inline uint16_t tud_audio_write(const void * data, uint16_t len) +{ + return tud_audio_n_write(0, data, len); +} + +static inline bool tud_audio_clear_ep_in_ff(void) +{ + return tud_audio_n_clear_ep_in_ff(0); +} + +static inline tu_fifo_t* tud_audio_get_ep_in_ff(void) +{ + return tud_audio_n_get_ep_in_ff(0); +} + +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING + +static inline uint16_t tud_audio_flush_tx_support_ff(void) +{ + return tud_audio_n_flush_tx_support_ff(0); +} + +static inline uint16_t tud_audio_clear_tx_support_ff(uint8_t ff_idx) +{ + return tud_audio_n_clear_tx_support_ff(0, ff_idx); +} + +static inline uint16_t tud_audio_write_support_ff(uint8_t ff_idx, const void * data, uint16_t len) +{ + return tud_audio_n_write_support_ff(0, ff_idx, data, len); +} + +static inline tu_fifo_t* tud_audio_get_tx_support_ff(uint8_t ff_idx) +{ + return tud_audio_n_get_tx_support_ff(0, ff_idx); +} + +#endif + +#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t len) +{ + return tud_audio_int_ctr_n_write(0, buffer, len); +} +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + +static inline bool tud_audio_fb_set(uint32_t feedback) +{ + return tud_audio_n_fb_set(0, feedback); +} + +#endif + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void audiod_init (void); +void audiod_reset (uint8_t rhport); +uint16_t audiod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +bool audiod_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); +void audiod_sof_isr (uint8_t rhport, uint32_t frame_count); + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_AUDIO_DEVICE_H_ */ + +/** @} */ +/** @} */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.c new file mode 100755 index 00000000..f96bb355 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.c @@ -0,0 +1,260 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Jerzy Kasenberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_BTH) + +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "bth_device.h" +#include + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +typedef struct +{ + uint8_t itf_num; + uint8_t ep_ev; + uint8_t ep_acl_in; + uint8_t ep_acl_out; + uint8_t ep_voice[2]; // Not used yet + uint8_t ep_voice_size[2][CFG_TUD_BTH_ISO_ALT_COUNT]; + + // Endpoint Transfer buffer + CFG_TUSB_MEM_ALIGN bt_hci_cmd_t hci_cmd; + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_BTH_DATA_EPSIZE]; + +} btd_interface_t; + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +CFG_TUSB_MEM_SECTION btd_interface_t _btd_itf; + +static bool bt_tx_data(uint8_t ep, void *data, uint16_t len) +{ + uint8_t const rhport = 0; + + // skip if previous transfer not complete + TU_VERIFY(!usbd_edpt_busy(rhport, ep)); + + TU_ASSERT(usbd_edpt_xfer(rhport, ep, data, len)); + + return true; +} + +//--------------------------------------------------------------------+ +// READ API +//--------------------------------------------------------------------+ + + +//--------------------------------------------------------------------+ +// WRITE API +//--------------------------------------------------------------------+ + +bool tud_bt_event_send(void *event, uint16_t event_len) +{ + return bt_tx_data(_btd_itf.ep_ev, event, event_len); +} + +bool tud_bt_acl_data_send(void *event, uint16_t event_len) +{ + return bt_tx_data(_btd_itf.ep_acl_in, event, event_len); +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void btd_init(void) +{ + tu_memclr(&_btd_itf, sizeof(_btd_itf)); +} + +void btd_reset(uint8_t rhport) +{ + (void)rhport; +} + +uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) +{ + tusb_desc_endpoint_t const *desc_ep; + uint16_t drv_len = 0; + // Size of single alternative of ISO interface + const uint16_t iso_alt_itf_size = sizeof(tusb_desc_interface_t) + 2 * sizeof(tusb_desc_endpoint_t); + // Size of hci interface + const uint16_t hci_itf_size = sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t); + // Ensure this is BT Primary Controller + TU_VERIFY(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass && + TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass && + TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0); + + TU_ASSERT(itf_desc->bNumEndpoints == 3 && max_len >= hci_itf_size); + + _btd_itf.itf_num = itf_desc->bInterfaceNumber; + + desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); + + TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer, 0); + TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); + _btd_itf.ep_ev = desc_ep->bEndpointAddress; + + // Open endpoint pair + TU_ASSERT(usbd_open_edpt_pair(rhport, tu_desc_next(desc_ep), 2, TUSB_XFER_BULK, &_btd_itf.ep_acl_out, + &_btd_itf.ep_acl_in), 0); + + itf_desc = (tusb_desc_interface_t const *)tu_desc_next(tu_desc_next(tu_desc_next(desc_ep))); + + // Prepare for incoming data from host + TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE), 0); + + drv_len = hci_itf_size; + + // Ensure this is still BT Primary Controller + TU_ASSERT(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass && + TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass && + TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0); + TU_ASSERT(itf_desc->bNumEndpoints == 2 && max_len >= iso_alt_itf_size + drv_len); + + uint8_t dir; + + desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc); + TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0); + TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0); + dir = tu_edpt_dir(desc_ep->bEndpointAddress); + _btd_itf.ep_voice[dir] = desc_ep->bEndpointAddress; + // Store endpoint size for alternative + _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); + + desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep); + TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0); + dir = tu_edpt_dir(desc_ep->bEndpointAddress); + _btd_itf.ep_voice[dir] = desc_ep->bEndpointAddress; + // Store endpoint size for alternative + _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); + drv_len += iso_alt_itf_size; + + for (int i = 1; i < CFG_TUD_BTH_ISO_ALT_COUNT && drv_len + iso_alt_itf_size <= max_len; ++i) { + // Make sure rest of alternatives matches + itf_desc = (tusb_desc_interface_t const *)tu_desc_next(desc_ep); + if (itf_desc->bDescriptorType != TUSB_DESC_INTERFACE || + TUSB_CLASS_WIRELESS_CONTROLLER != itf_desc->bInterfaceClass || + TUD_BT_APP_SUBCLASS != itf_desc->bInterfaceSubClass || + TUD_BT_PROTOCOL_PRIMARY_CONTROLLER != itf_desc->bInterfaceProtocol) + { + // Not an Iso interface instance + break; + } + TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0); + + desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc); + dir = tu_edpt_dir(desc_ep->bEndpointAddress); + // Verify that alternative endpoint are same as first ones + TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT && + _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0); + _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); + + desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep); + dir = tu_edpt_dir(desc_ep->bEndpointAddress); + // Verify that alternative endpoint are same as first ones + TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT && + _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0); + _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); + drv_len += iso_alt_itf_size; + } + + return drv_len; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) +{ + (void)rhport; + + if ( stage == CONTROL_STAGE_SETUP ) + { + if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && + request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE) + { + // HCI command packet addressing for single function Primary Controllers + TU_VERIFY(request->bRequest == 0 && request->wValue == 0 && request->wIndex == 0); + } + else if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE) + { + if (request->bRequest == TUSB_REQ_SET_INTERFACE && _btd_itf.itf_num + 1 == request->wIndex) + { + // TODO: Set interface it would involve changing size of endpoint size + } + else + { + // HCI command packet for Primary Controller function in a composite device + TU_VERIFY(request->bRequest == 0 && request->wValue == 0 && request->wIndex == _btd_itf.itf_num); + } + } + else return false; + + return tud_control_xfer(rhport, request, &_btd_itf.hci_cmd, sizeof(_btd_itf.hci_cmd)); + } + else if ( stage == CONTROL_STAGE_DATA ) + { + // Handle class request only + TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); + + if (tud_bt_hci_cmd_cb) tud_bt_hci_cmd_cb(&_btd_itf.hci_cmd, tu_min16(request->wLength, sizeof(_btd_itf.hci_cmd))); + } + + return true; +} + +bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void)result; + + // received new data from host + if (ep_addr == _btd_itf.ep_acl_out) + { + if (tud_bt_acl_data_received_cb) tud_bt_acl_data_received_cb(_btd_itf.epout_buf, xferred_bytes); + + // prepare for next data + TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE)); + } + else if (ep_addr == _btd_itf.ep_ev) + { + if (tud_bt_event_sent_cb) tud_bt_event_sent_cb((uint16_t)xferred_bytes); + } + else if (ep_addr == _btd_itf.ep_acl_in) + { + if (tud_bt_acl_data_sent_cb) tud_bt_acl_data_sent_cb((uint16_t)xferred_bytes); + } + + return true; +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.h new file mode 100755 index 00000000..1b90d091 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.h @@ -0,0 +1,109 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Jerzy Kasenberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_BTH_DEVICE_H_ +#define _TUSB_BTH_DEVICE_H_ + +#include +#include + +//--------------------------------------------------------------------+ +// Class Driver Configuration +//--------------------------------------------------------------------+ +#ifndef CFG_TUD_BTH_EVENT_EPSIZE +#define CFG_TUD_BTH_EVENT_EPSIZE 16 +#endif +#ifndef CFG_TUD_BTH_DATA_EPSIZE +#define CFG_TUD_BTH_DATA_EPSIZE 64 +#endif + +typedef struct TU_ATTR_PACKED +{ + uint16_t op_code; + uint8_t param_length; + uint8_t param[255]; +} bt_hci_cmd_t; + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ + +// Invoked when HCI command was received over USB from Bluetooth host. +// Detailed format is described in Bluetooth core specification Vol 2, +// Part E, 5.4.1. +// Length of the command is from 3 bytes (2 bytes for OpCode, +// 1 byte for parameter total length) to 258. +TU_ATTR_WEAK void tud_bt_hci_cmd_cb(void *hci_cmd, size_t cmd_len); + +// Invoked when ACL data was received over USB from Bluetooth host. +// Detailed format is described in Bluetooth core specification Vol 2, +// Part E, 5.4.2. +// Length is from 4 bytes, (12 bits for Handle, 4 bits for flags +// and 16 bits for data total length) to endpoint size. +TU_ATTR_WEAK void tud_bt_acl_data_received_cb(void *acl_data, uint16_t data_len); + +// Called when event sent with tud_bt_event_send() was delivered to BT stack. +// Controller can release/reuse buffer with Event packet at this point. +TU_ATTR_WEAK void tud_bt_event_sent_cb(uint16_t sent_bytes); + +// Called when ACL data that was sent with tud_bt_acl_data_send() +// was delivered to BT stack. +// Controller can release/reuse buffer with ACL packet at this point. +TU_ATTR_WEAK void tud_bt_acl_data_sent_cb(uint16_t sent_bytes); + +// Bluetooth controller calls this function when it wants to send even packet +// as described in Bluetooth core specification Vol 2, Part E, 5.4.4. +// Event has at least 2 bytes, first is Event code second contains parameter +// total length. Controller can release/reuse event memory after +// tud_bt_event_sent_cb() is called. +bool tud_bt_event_send(void *event, uint16_t event_len); + +// Bluetooth controller calls this to send ACL data packet +// as described in Bluetooth core specification Vol 2, Part E, 5.4.2 +// Minimum length is 4 bytes, (12 bits for Handle, 4 bits for flags +// and 16 bits for data total length). Upper limit is not limited +// to endpoint size since buffer is allocate by controller +// and must not be reused till tud_bt_acl_data_sent_cb() is called. +bool tud_bt_acl_data_send(void *acl_data, uint16_t data_len); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void btd_init (void); +void btd_reset (uint8_t rhport); +uint16_t btd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool btd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); +bool btd_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_BTH_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc.h b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc.h new file mode 100644 index 00000000..e345139e --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc.h @@ -0,0 +1,409 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup group_class + * \defgroup ClassDriver_CDC Communication Device Class (CDC) + * Currently only Abstract Control Model subclass is supported + * @{ */ + +#ifndef _TUSB_CDC_H__ +#define _TUSB_CDC_H__ + +#include "common/tusb_common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** \defgroup ClassDriver_CDC_Common Common Definitions + * @{ */ + +// TODO remove +/// CDC Pipe ID, used to indicate which pipe the API is addressing to (Notification, Out, In) +typedef enum +{ + CDC_PIPE_NOTIFICATION , ///< Notification pipe + CDC_PIPE_DATA_IN , ///< Data in pipe + CDC_PIPE_DATA_OUT , ///< Data out pipe + CDC_PIPE_ERROR , ///< Invalid Pipe ID +}cdc_pipeid_t; + +//--------------------------------------------------------------------+ +// CDC Communication Interface Class +//--------------------------------------------------------------------+ + +/// Communication Interface Subclass Codes +typedef enum +{ + CDC_COMM_SUBCLASS_DIRECT_LINE_CONTROL_MODEL = 0x01 , ///< Direct Line Control Model [USBPSTN1.2] + CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL = 0x02 , ///< Abstract Control Model [USBPSTN1.2] + CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL = 0x03 , ///< Telephone Control Model [USBPSTN1.2] + CDC_COMM_SUBCLASS_MULTICHANNEL_CONTROL_MODEL = 0x04 , ///< Multi-Channel Control Model [USBISDN1.2] + CDC_COMM_SUBCLASS_CAPI_CONTROL_MODEL = 0x05 , ///< CAPI Control Model [USBISDN1.2] + CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL = 0x06 , ///< Ethernet Networking Control Model [USBECM1.2] + CDC_COMM_SUBCLASS_ATM_NETWORKING_CONTROL_MODEL = 0x07 , ///< ATM Networking Control Model [USBATM1.2] + CDC_COMM_SUBCLASS_WIRELESS_HANDSET_CONTROL_MODEL = 0x08 , ///< Wireless Handset Control Model [USBWMC1.1] + CDC_COMM_SUBCLASS_DEVICE_MANAGEMENT = 0x09 , ///< Device Management [USBWMC1.1] + CDC_COMM_SUBCLASS_MOBILE_DIRECT_LINE_MODEL = 0x0A , ///< Mobile Direct Line Model [USBWMC1.1] + CDC_COMM_SUBCLASS_OBEX = 0x0B , ///< OBEX [USBWMC1.1] + CDC_COMM_SUBCLASS_ETHERNET_EMULATION_MODEL = 0x0C , ///< Ethernet Emulation Model [USBEEM1.0] + CDC_COMM_SUBCLASS_NETWORK_CONTROL_MODEL = 0x0D ///< Network Control Model [USBNCM1.0] +} cdc_comm_sublcass_type_t; + +/// Communication Interface Protocol Codes +typedef enum +{ + CDC_COMM_PROTOCOL_NONE = 0x00 , ///< No specific protocol + CDC_COMM_PROTOCOL_ATCOMMAND = 0x01 , ///< AT Commands: V.250 etc + CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101 = 0x02 , ///< AT Commands defined by PCCA-101 + CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101_AND_ANNEXO = 0x03 , ///< AT Commands defined by PCCA-101 & Annex O + CDC_COMM_PROTOCOL_ATCOMMAND_GSM_707 = 0x04 , ///< AT Commands defined by GSM 07.07 + CDC_COMM_PROTOCOL_ATCOMMAND_3GPP_27007 = 0x05 , ///< AT Commands defined by 3GPP 27.007 + CDC_COMM_PROTOCOL_ATCOMMAND_CDMA = 0x06 , ///< AT Commands defined by TIA for CDMA + CDC_COMM_PROTOCOL_ETHERNET_EMULATION_MODEL = 0x07 ///< Ethernet Emulation Model +} cdc_comm_protocol_type_t; + +//------------- SubType Descriptor in COMM Functional Descriptor -------------// +/// Communication Interface SubType Descriptor +typedef enum +{ + CDC_FUNC_DESC_HEADER = 0x00 , ///< Header Functional Descriptor, which marks the beginning of the concatenated set of functional descriptors for the interface. + CDC_FUNC_DESC_CALL_MANAGEMENT = 0x01 , ///< Call Management Functional Descriptor. + CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT = 0x02 , ///< Abstract Control Management Functional Descriptor. + CDC_FUNC_DESC_DIRECT_LINE_MANAGEMENT = 0x03 , ///< Direct Line Management Functional Descriptor. + CDC_FUNC_DESC_TELEPHONE_RINGER = 0x04 , ///< Telephone Ringer Functional Descriptor. + CDC_FUNC_DESC_TELEPHONE_CALL_AND_LINE_STATE_REPORTING_CAPACITY = 0x05 , ///< Telephone Call and Line State Reporting Capabilities Functional Descriptor. + CDC_FUNC_DESC_UNION = 0x06 , ///< Union Functional Descriptor + CDC_FUNC_DESC_COUNTRY_SELECTION = 0x07 , ///< Country Selection Functional Descriptor + CDC_FUNC_DESC_TELEPHONE_OPERATIONAL_MODES = 0x08 , ///< Telephone Operational ModesFunctional Descriptor + CDC_FUNC_DESC_USB_TERMINAL = 0x09 , ///< USB Terminal Functional Descriptor + CDC_FUNC_DESC_NETWORK_CHANNEL_TERMINAL = 0x0A , ///< Network Channel Terminal Descriptor + CDC_FUNC_DESC_PROTOCOL_UNIT = 0x0B , ///< Protocol Unit Functional Descriptor + CDC_FUNC_DESC_EXTENSION_UNIT = 0x0C , ///< Extension Unit Functional Descriptor + CDC_FUNC_DESC_MULTICHANEL_MANAGEMENT = 0x0D , ///< Multi-Channel Management Functional Descriptor + CDC_FUNC_DESC_CAPI_CONTROL_MANAGEMENT = 0x0E , ///< CAPI Control Management Functional Descriptor + CDC_FUNC_DESC_ETHERNET_NETWORKING = 0x0F , ///< Ethernet Networking Functional Descriptor + CDC_FUNC_DESC_ATM_NETWORKING = 0x10 , ///< ATM Networking Functional Descriptor + CDC_FUNC_DESC_WIRELESS_HANDSET_CONTROL_MODEL = 0x11 , ///< Wireless Handset Control Model Functional Descriptor + CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL = 0x12 , ///< Mobile Direct Line Model Functional Descriptor + CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL_DETAIL = 0x13 , ///< MDLM Detail Functional Descriptor + CDC_FUNC_DESC_DEVICE_MANAGEMENT_MODEL = 0x14 , ///< Device Management Model Functional Descriptor + CDC_FUNC_DESC_OBEX = 0x15 , ///< OBEX Functional Descriptor + CDC_FUNC_DESC_COMMAND_SET = 0x16 , ///< Command Set Functional Descriptor + CDC_FUNC_DESC_COMMAND_SET_DETAIL = 0x17 , ///< Command Set Detail Functional Descriptor + CDC_FUNC_DESC_TELEPHONE_CONTROL_MODEL = 0x18 , ///< Telephone Control Model Functional Descriptor + CDC_FUNC_DESC_OBEX_SERVICE_IDENTIFIER = 0x19 , ///< OBEX Service Identifier Functional Descriptor + CDC_FUNC_DESC_NCM = 0x1A , ///< NCM Functional Descriptor +}cdc_func_desc_type_t; + +//--------------------------------------------------------------------+ +// CDC Data Interface Class +//--------------------------------------------------------------------+ + +// SUBCLASS code of Data Interface is not used and should/must be zero + +// Data Interface Protocol Codes +typedef enum{ + CDC_DATA_PROTOCOL_ISDN_BRI = 0x30, ///< Physical interface protocol for ISDN BRI + CDC_DATA_PROTOCOL_HDLC = 0x31, ///< HDLC + CDC_DATA_PROTOCOL_TRANSPARENT = 0x32, ///< Transparent + CDC_DATA_PROTOCOL_Q921_MANAGEMENT = 0x50, ///< Management protocol for Q.921 data link protocol + CDC_DATA_PROTOCOL_Q921_DATA_LINK = 0x51, ///< Data link protocol for Q.931 + CDC_DATA_PROTOCOL_Q921_TEI_MULTIPLEXOR = 0x52, ///< TEI-multiplexor for Q.921 data link protocol + CDC_DATA_PROTOCOL_V42BIS_DATA_COMPRESSION = 0x90, ///< Data compression procedures + CDC_DATA_PROTOCOL_EURO_ISDN = 0x91, ///< Euro-ISDN protocol control + CDC_DATA_PROTOCOL_V24_RATE_ADAPTION_TO_ISDN = 0x92, ///< V.24 rate adaptation to ISDN + CDC_DATA_PROTOCOL_CAPI_COMMAND = 0x93, ///< CAPI Commands + CDC_DATA_PROTOCOL_HOST_BASED_DRIVER = 0xFD, ///< Host based driver. Note: This protocol code should only be used in messages between host and device to identify the host driver portion of a protocol stack. + CDC_DATA_PROTOCOL_IN_PROTOCOL_UNIT_FUNCTIONAL_DESCRIPTOR = 0xFE ///< The protocol(s) are described using a ProtocolUnit Functional Descriptors on Communications Class Interface +}cdc_data_protocol_type_t; + +//--------------------------------------------------------------------+ +// Management Element Request (Control Endpoint) +//--------------------------------------------------------------------+ + +/// Communication Interface Management Element Request Codes +typedef enum +{ + CDC_REQUEST_SEND_ENCAPSULATED_COMMAND = 0x00, ///< is used to issue a command in the format of the supported control protocol of the Communications Class interface + CDC_REQUEST_GET_ENCAPSULATED_RESPONSE = 0x01, ///< is used to request a response in the format of the supported control protocol of the Communications Class interface. + CDC_REQUEST_SET_COMM_FEATURE = 0x02, + CDC_REQUEST_GET_COMM_FEATURE = 0x03, + CDC_REQUEST_CLEAR_COMM_FEATURE = 0x04, + + CDC_REQUEST_SET_AUX_LINE_STATE = 0x10, + CDC_REQUEST_SET_HOOK_STATE = 0x11, + CDC_REQUEST_PULSE_SETUP = 0x12, + CDC_REQUEST_SEND_PULSE = 0x13, + CDC_REQUEST_SET_PULSE_TIME = 0x14, + CDC_REQUEST_RING_AUX_JACK = 0x15, + + CDC_REQUEST_SET_LINE_CODING = 0x20, + CDC_REQUEST_GET_LINE_CODING = 0x21, + CDC_REQUEST_SET_CONTROL_LINE_STATE = 0x22, + CDC_REQUEST_SEND_BREAK = 0x23, + + CDC_REQUEST_SET_RINGER_PARMS = 0x30, + CDC_REQUEST_GET_RINGER_PARMS = 0x31, + CDC_REQUEST_SET_OPERATION_PARMS = 0x32, + CDC_REQUEST_GET_OPERATION_PARMS = 0x33, + CDC_REQUEST_SET_LINE_PARMS = 0x34, + CDC_REQUEST_GET_LINE_PARMS = 0x35, + CDC_REQUEST_DIAL_DIGITS = 0x36, + CDC_REQUEST_SET_UNIT_PARAMETER = 0x37, + CDC_REQUEST_GET_UNIT_PARAMETER = 0x38, + CDC_REQUEST_CLEAR_UNIT_PARAMETER = 0x39, + CDC_REQUEST_GET_PROFILE = 0x3A, + + CDC_REQUEST_SET_ETHERNET_MULTICAST_FILTERS = 0x40, + CDC_REQUEST_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x41, + CDC_REQUEST_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x42, + CDC_REQUEST_SET_ETHERNET_PACKET_FILTER = 0x43, + CDC_REQUEST_GET_ETHERNET_STATISTIC = 0x44, + + CDC_REQUEST_SET_ATM_DATA_FORMAT = 0x50, + CDC_REQUEST_GET_ATM_DEVICE_STATISTICS = 0x51, + CDC_REQUEST_SET_ATM_DEFAULT_VC = 0x52, + CDC_REQUEST_GET_ATM_VC_STATISTICS = 0x53, + + CDC_REQUEST_MDLM_SEMANTIC_MODEL = 0x60, +}cdc_management_request_t; + +//--------------------------------------------------------------------+ +// Management Elemenent Notification (Notification Endpoint) +//--------------------------------------------------------------------+ + +/// 6.3 Notification Codes +typedef enum +{ + CDC_NOTIF_NETWORK_CONNECTION = 0x00, ///< This notification allows the device to notify the host about network connection status. + CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request. + CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08, + CDC_NOTIF_RING_DETECT = 0x09, + CDC_NOTIF_SERIAL_STATE = 0x20, + CDC_NOTIF_CALL_STATE_CHANGE = 0x28, + CDC_NOTIF_LINE_STATE_CHANGE = 0x29, + CDC_NOTIF_CONNECTION_SPEED_CHANGE = 0x2A, ///< This notification allows the device to inform the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred + CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40, +}cdc_notification_request_t; + +//--------------------------------------------------------------------+ +// Class Specific Functional Descriptor (Communication Interface) +//--------------------------------------------------------------------+ + +// Start of all packed definitions for compiler without per-type packed +TU_ATTR_PACKED_BEGIN +TU_ATTR_BIT_FIELD_ORDER_BEGIN + +/// Header Functional Descriptor (Communication Interface) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUNC_DESC_ + uint16_t bcdCDC ; ///< CDC release number in Binary-Coded Decimal +}cdc_desc_func_header_t; + +/// Union Functional Descriptor (Communication Interface) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + uint8_t bControlInterface ; ///< Interface number of Communication Interface + uint8_t bSubordinateInterface ; ///< Array of Interface number of Data Interface +}cdc_desc_func_union_t; + +#define cdc_desc_func_union_n_t(no_slave)\ + struct TU_ATTR_PACKED { \ + uint8_t bLength ;\ + uint8_t bDescriptorType ;\ + uint8_t bDescriptorSubType ;\ + uint8_t bControlInterface ;\ + uint8_t bSubordinateInterface[no_slave] ;\ +} + +/// Country Selection Functional Descriptor (Communication Interface) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + uint8_t iCountryCodeRelDate ; ///< Index of a string giving the release date for the implemented ISO 3166 Country Codes. + uint16_t wCountryCode ; ///< Country code in the format as defined in [ISO3166], release date as specified inoffset 3 for the first supported country. +}cdc_desc_func_country_selection_t; + +#define cdc_desc_func_country_selection_n_t(no_country) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength ;\ + uint8_t bDescriptorType ;\ + uint8_t bDescriptorSubType ;\ + uint8_t iCountryCodeRelDate ;\ + uint16_t wCountryCode[no_country] ;\ +} + +//--------------------------------------------------------------------+ +// PUBLIC SWITCHED TELEPHONE NETWORK (PSTN) SUBCLASS +//--------------------------------------------------------------------+ + +/// \brief Call Management Functional Descriptor +/// \details This functional descriptor describes the processing of calls for the Communications Class interface. +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + + struct { + uint8_t handle_call : 1; ///< 0 - Device sends/receives call management information only over the Communications Class interface. 1 - Device can send/receive call management information over a Data Class interface. + uint8_t send_recv_call : 1; ///< 0 - Device does not handle call management itself. 1 - Device handles call management itself. + uint8_t TU_RESERVED : 6; + } bmCapabilities; + + uint8_t bDataInterface; +}cdc_desc_func_call_management_t; + +typedef struct TU_ATTR_PACKED +{ + uint8_t support_comm_request : 1; ///< Device supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature. + uint8_t support_line_request : 1; ///< Device supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State. + uint8_t support_send_break : 1; ///< Device supports the request Send_Break + uint8_t support_notification_network_connection : 1; ///< Device supports the notification Network_Connection. + uint8_t TU_RESERVED : 4; +}cdc_acm_capability_t; + +TU_VERIFY_STATIC(sizeof(cdc_acm_capability_t) == 1, "mostly problem with compiler"); + +/// Abstract Control Management Functional Descriptor +/// This functional descriptor describes the commands supported by by the Communications Class interface with SubClass code of \ref CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + cdc_acm_capability_t bmCapabilities ; +}cdc_desc_func_acm_t; + +/// \brief Direct Line Management Functional Descriptor +/// \details This functional descriptor describes the commands supported by the Communications Class interface with SubClass code of \ref CDC_FUNC_DESC_DIRECT_LINE_MANAGEMENT +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + struct { + uint8_t require_pulse_setup : 1; ///< Device requires extra Pulse_Setup request during pulse dialing sequence to disengage holding circuit. + uint8_t support_aux_request : 1; ///< Device supports the request combination of Set_Aux_Line_State, Ring_Aux_Jack, and notification Aux_Jack_Hook_State. + uint8_t support_pulse_request : 1; ///< Device supports the request combination of Pulse_Setup, Send_Pulse, and Set_Pulse_Time. + uint8_t TU_RESERVED : 5; + } bmCapabilities; +}cdc_desc_func_direct_line_management_t; + +/// \brief Telephone Ringer Functional Descriptor +/// \details The Telephone Ringer functional descriptor describes the ringer capabilities supported by the Communications Class interface, +/// with the SubClass code of \ref CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + uint8_t bRingerVolSteps ; + uint8_t bNumRingerPatterns ; +}cdc_desc_func_telephone_ringer_t; + +/// \brief Telephone Operational Modes Functional Descriptor +/// \details The Telephone Operational Modes functional descriptor describes the operational modes supported by +/// the Communications Class interface, with the SubClass code of \ref CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + struct { + uint8_t simple_mode : 1; + uint8_t standalone_mode : 1; + uint8_t computer_centric_mode : 1; + uint8_t TU_RESERVED : 5; + } bmCapabilities; +}cdc_desc_func_telephone_operational_modes_t; + +/// \brief Telephone Call and Line State Reporting Capabilities Descriptor +/// \details The Telephone Call and Line State Reporting Capabilities functional descriptor describes the abilities of a +/// telephone device to report optional call and line states. +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + struct { + uint32_t interrupted_dialtone : 1; ///< 0 : Reports only dialtone (does not differentiate between normal and interrupted dialtone). 1 : Reports interrupted dialtone in addition to normal dialtone + uint32_t ringback_busy_fastbusy : 1; ///< 0 : Reports only dialing state. 1 : Reports ringback, busy, and fast busy states. + uint32_t caller_id : 1; ///< 0 : Does not report caller ID. 1 : Reports caller ID information. + uint32_t incoming_distinctive : 1; ///< 0 : Reports only incoming ringing. 1 : Reports incoming distinctive ringing patterns. + uint32_t dual_tone_multi_freq : 1; ///< 0 : Cannot report dual tone multi-frequency (DTMF) digits input remotely over the telephone line. 1 : Can report DTMF digits input remotely over the telephone line. + uint32_t line_state_change : 1; ///< 0 : Does not support line state change notification. 1 : Does support line state change notification + uint32_t TU_RESERVED : 26; + } bmCapabilities; +}cdc_desc_func_telephone_call_state_reporting_capabilities_t; + +// TODO remove +static inline uint8_t cdc_functional_desc_typeof(uint8_t const * p_desc) +{ + return p_desc[2]; +} + +//--------------------------------------------------------------------+ +// Requests +//--------------------------------------------------------------------+ +typedef struct TU_ATTR_PACKED +{ + uint32_t bit_rate; + uint8_t stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits + uint8_t parity; ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space + uint8_t data_bits; ///< can be 5, 6, 7, 8 or 16 +} cdc_line_coding_t; + +TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct"); + +typedef struct TU_ATTR_PACKED +{ + uint16_t dte_is_present : 1; ///< Indicates to DCE if DTE is presentor not. This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR. + uint16_t half_duplex_carrier_control : 1; + uint16_t : 14; +} cdc_line_control_state_t; + +TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct"); + +TU_ATTR_PACKED_END // End of all packed definitions +TU_ATTR_BIT_FIELD_ORDER_END + +#ifdef __cplusplus + } +#endif + +#endif + +/** @} */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.c new file mode 100644 index 00000000..fab6f003 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.c @@ -0,0 +1,486 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_CDC) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "cdc_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +enum +{ + BULK_PACKET_SIZE = (TUD_OPT_HIGH_SPEED ? 512 : 64) +}; + +typedef struct +{ + uint8_t itf_num; + uint8_t ep_notif; + uint8_t ep_in; + uint8_t ep_out; + + // Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) + uint8_t line_state; + + /*------------- From this point, data is not cleared by bus reset -------------*/ + char wanted_char; + cdc_line_coding_t line_coding; + + // FIFO + tu_fifo_t rx_ff; + tu_fifo_t tx_ff; + + uint8_t rx_ff_buf[CFG_TUD_CDC_RX_BUFSIZE]; + uint8_t tx_ff_buf[CFG_TUD_CDC_TX_BUFSIZE]; + +#if CFG_FIFO_MUTEX + osal_mutex_def_t rx_ff_mutex; + osal_mutex_def_t tx_ff_mutex; +#endif + + // Endpoint Transfer buffer + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EP_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CDC_EP_BUFSIZE]; + +}cdcd_interface_t; + +#define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, wanted_char) + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +CFG_TUSB_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; + +static bool _prep_out_transaction (cdcd_interface_t* p_cdc) +{ + uint8_t const rhport = 0; + uint16_t available = tu_fifo_remaining(&p_cdc->rx_ff); + + // Prepare for incoming data but only allow what we can store in the ring buffer. + // TODO Actually we can still carry out the transfer, keeping count of received bytes + // and slowly move it to the FIFO when read(). + // This pre-check reduces endpoint claiming + TU_VERIFY(available >= sizeof(p_cdc->epout_buf)); + + // claim endpoint + TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_out)); + + // fifo can be changed before endpoint is claimed + available = tu_fifo_remaining(&p_cdc->rx_ff); + + if ( available >= sizeof(p_cdc->epout_buf) ) + { + return usbd_edpt_xfer(rhport, p_cdc->ep_out, p_cdc->epout_buf, sizeof(p_cdc->epout_buf)); + }else + { + // Release endpoint since we don't make any transfer + usbd_edpt_release(rhport, p_cdc->ep_out); + + return false; + } +} + +//--------------------------------------------------------------------+ +// APPLICATION API +//--------------------------------------------------------------------+ +bool tud_cdc_n_connected(uint8_t itf) +{ + // DTR (bit 0) active is considered as connected + return tud_ready() && tu_bit_test(_cdcd_itf[itf].line_state, 0); +} + +uint8_t tud_cdc_n_get_line_state (uint8_t itf) +{ + return _cdcd_itf[itf].line_state; +} + +void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding) +{ + (*coding) = _cdcd_itf[itf].line_coding; +} + +void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted) +{ + _cdcd_itf[itf].wanted_char = wanted; +} + + +//--------------------------------------------------------------------+ +// READ API +//--------------------------------------------------------------------+ +uint32_t tud_cdc_n_available(uint8_t itf) +{ + return tu_fifo_count(&_cdcd_itf[itf].rx_ff); +} + +uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize) +{ + cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; + uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, (uint16_t) bufsize); + _prep_out_transaction(p_cdc); + return num_read; +} + +bool tud_cdc_n_peek(uint8_t itf, uint8_t* chr) +{ + return tu_fifo_peek(&_cdcd_itf[itf].rx_ff, chr); +} + +void tud_cdc_n_read_flush (uint8_t itf) +{ + cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; + tu_fifo_clear(&p_cdc->rx_ff); + _prep_out_transaction(p_cdc); +} + +//--------------------------------------------------------------------+ +// WRITE API +//--------------------------------------------------------------------+ +uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) +{ + cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; + uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) bufsize); + + // flush if queue more than packet size + if ( tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE ) + { + tud_cdc_n_write_flush(itf); + } + + return ret; +} + +uint32_t tud_cdc_n_write_flush (uint8_t itf) +{ + cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; + + // Skip if usb is not ready yet + TU_VERIFY( tud_ready(), 0 ); + + // No data to send + if ( !tu_fifo_count(&p_cdc->tx_ff) ) return 0; + + uint8_t const rhport = 0; + + // Claim the endpoint + TU_VERIFY( usbd_edpt_claim(rhport, p_cdc->ep_in), 0 ); + + // Pull data from FIFO + uint16_t const count = tu_fifo_read_n(&p_cdc->tx_ff, p_cdc->epin_buf, sizeof(p_cdc->epin_buf)); + + if ( count ) + { + TU_ASSERT( usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 ); + return count; + }else + { + // Release endpoint since we don't make any transfer + // Note: data is dropped if terminal is not connected + usbd_edpt_release(rhport, p_cdc->ep_in); + return 0; + } +} + +uint32_t tud_cdc_n_write_available (uint8_t itf) +{ + return tu_fifo_remaining(&_cdcd_itf[itf].tx_ff); +} + +bool tud_cdc_n_write_clear (uint8_t itf) +{ + return tu_fifo_clear(&_cdcd_itf[itf].tx_ff); +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void cdcd_init(void) +{ + tu_memclr(_cdcd_itf, sizeof(_cdcd_itf)); + + for(uint8_t i=0; iwanted_char = (char) -1; + + // default line coding is : stop bit = 1, parity = none, data bits = 8 + p_cdc->line_coding.bit_rate = 115200; + p_cdc->line_coding.stop_bits = 0; + p_cdc->line_coding.parity = 0; + p_cdc->line_coding.data_bits = 8; + + // Config RX fifo + tu_fifo_config(&p_cdc->rx_ff, p_cdc->rx_ff_buf, TU_ARRAY_SIZE(p_cdc->rx_ff_buf), 1, false); + + // Config TX fifo as overwritable at initialization and will be changed to non-overwritable + // if terminal supports DTR bit. Without DTR we do not know if data is actually polled by terminal. + // In this way, the most current data is prioritized. + tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, true); + +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, osal_mutex_create(&p_cdc->rx_ff_mutex)); + tu_fifo_config_mutex(&p_cdc->tx_ff, osal_mutex_create(&p_cdc->tx_ff_mutex), NULL); +#endif + } +} + +void cdcd_reset(uint8_t rhport) +{ + (void) rhport; + + for(uint8_t i=0; irx_ff); + tu_fifo_clear(&p_cdc->tx_ff); + tu_fifo_set_overwritable(&p_cdc->tx_ff, true); + } +} + +uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + // Only support ACM subclass + TU_VERIFY( TUSB_CLASS_CDC == itf_desc->bInterfaceClass && + CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass, 0); + + // Find available interface + cdcd_interface_t * p_cdc = NULL; + for(uint8_t cdc_id=0; cdc_iditf_num = itf_desc->bInterfaceNumber; + + uint16_t drv_len = sizeof(tusb_desc_interface_t); + uint8_t const * p_desc = tu_desc_next( itf_desc ); + + // Communication Functional Descriptors + while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) + { + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + { + // notification endpoint + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; + + TU_ASSERT( usbd_edpt_open(rhport, desc_ep), 0 ); + p_cdc->ep_notif = desc_ep->bEndpointAddress; + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + //------------- Data Interface (if any) -------------// + if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && + (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) + { + // next to endpoint descriptor + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + + // Open endpoint pair + TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in), 0 ); + + drv_len += 2*sizeof(tusb_desc_endpoint_t); + } + + // Prepare for incoming data + _prep_out_transaction(p_cdc); + + return drv_len; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + // Handle class request only + TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); + + uint8_t itf = 0; + cdcd_interface_t* p_cdc = _cdcd_itf; + + // Identify which interface to use + for ( ; ; itf++, p_cdc++) + { + if (itf >= TU_ARRAY_SIZE(_cdcd_itf)) return false; + + if ( p_cdc->itf_num == request->wIndex ) break; + } + + switch ( request->bRequest ) + { + case CDC_REQUEST_SET_LINE_CODING: + if (stage == CONTROL_STAGE_SETUP) + { + TU_LOG2(" Set Line Coding\r\n"); + tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); + } + else if ( stage == CONTROL_STAGE_ACK) + { + if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding); + } + break; + + case CDC_REQUEST_GET_LINE_CODING: + if (stage == CONTROL_STAGE_SETUP) + { + TU_LOG2(" Get Line Coding\r\n"); + tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); + } + break; + + case CDC_REQUEST_SET_CONTROL_LINE_STATE: + if (stage == CONTROL_STAGE_SETUP) + { + tud_control_status(rhport, request); + } + else if (stage == CONTROL_STAGE_ACK) + { + // CDC PSTN v1.2 section 6.3.12 + // Bit 0: Indicates if DTE is present or not. + // This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR (Data Terminal Ready) + // Bit 1: Carrier control for half-duplex modems. + // This signal corresponds to V.24 signal 105 and RS-232 signal RTS (Request to Send) + bool const dtr = tu_bit_test(request->wValue, 0); + bool const rts = tu_bit_test(request->wValue, 1); + + p_cdc->line_state = (uint8_t) request->wValue; + + // Disable fifo overwriting if DTR bit is set + tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr); + + TU_LOG2(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); + + // Invoke callback + if ( tud_cdc_line_state_cb ) tud_cdc_line_state_cb(itf, dtr, rts); + } + break; + case CDC_REQUEST_SEND_BREAK: + if (stage == CONTROL_STAGE_SETUP) + { + tud_control_status(rhport, request); + } + else if (stage == CONTROL_STAGE_ACK) + { + TU_LOG2(" Send Break\r\n"); + if ( tud_cdc_send_break_cb ) tud_cdc_send_break_cb(itf, request->wValue); + } + break; + + default: return false; // stall unsupported request + } + + return true; +} + +bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) result; + + uint8_t itf; + cdcd_interface_t* p_cdc; + + // Identify which interface to use + for (itf = 0; itf < CFG_TUD_CDC; itf++) + { + p_cdc = &_cdcd_itf[itf]; + if ( ( ep_addr == p_cdc->ep_out ) || ( ep_addr == p_cdc->ep_in ) ) break; + } + TU_ASSERT(itf < CFG_TUD_CDC); + + // Received new data + if ( ep_addr == p_cdc->ep_out ) + { + tu_fifo_write_n(&p_cdc->rx_ff, &p_cdc->epout_buf, (uint16_t) xferred_bytes); + + // Check for wanted char and invoke callback if needed + if ( tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1) ) + { + for ( uint32_t i = 0; i < xferred_bytes; i++ ) + { + if ( (p_cdc->wanted_char == p_cdc->epout_buf[i]) && !tu_fifo_empty(&p_cdc->rx_ff) ) + { + tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char); + } + } + } + + // invoke receive callback (if there is still data) + if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf); + + // prepare for OUT transaction + _prep_out_transaction(p_cdc); + } + + // Data sent to host, we continue to fetch from tx fifo to send. + // Note: This will cause incorrect baudrate set in line coding. + // Though maybe the baudrate is not really important !!! + if ( ep_addr == p_cdc->ep_in ) + { + // invoke transmit callback to possibly refill tx fifo + if ( tud_cdc_tx_complete_cb ) tud_cdc_tx_complete_cb(itf); + + if ( 0 == tud_cdc_n_write_flush(itf) ) + { + // If there is no data left, a ZLP should be sent if + // xferred_bytes is multiple of EP Packet size and not zero + if ( !tu_fifo_count(&p_cdc->tx_ff) && xferred_bytes && (0 == (xferred_bytes & (BULK_PACKET_SIZE-1))) ) + { + if ( usbd_edpt_claim(rhport, p_cdc->ep_in) ) + { + usbd_edpt_xfer(rhport, p_cdc->ep_in, NULL, 0); + } + } + } + } + + // nothing to do with notif endpoint for now + + return true; +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.h new file mode 100644 index 00000000..fbc7162a --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.h @@ -0,0 +1,260 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_CDC_DEVICE_H_ +#define _TUSB_CDC_DEVICE_H_ + +#include "common/tusb_common.h" +#include "cdc.h" + +//--------------------------------------------------------------------+ +// Class Driver Configuration +//--------------------------------------------------------------------+ +#if !defined(CFG_TUD_CDC_EP_BUFSIZE) && defined(CFG_TUD_CDC_EPSIZE) + #warning CFG_TUD_CDC_EPSIZE is renamed to CFG_TUD_CDC_EP_BUFSIZE, please update to use the new name + #define CFG_TUD_CDC_EP_BUFSIZE CFG_TUD_CDC_EPSIZE +#endif + +#ifndef CFG_TUD_CDC_EP_BUFSIZE + #define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +/** \addtogroup CDC_Serial Serial + * @{ + * \defgroup CDC_Serial_Device Device + * @{ */ + +//--------------------------------------------------------------------+ +// Application API (Multiple Ports) +// CFG_TUD_CDC > 1 +//--------------------------------------------------------------------+ + +// Check if terminal is connected to this port +bool tud_cdc_n_connected (uint8_t itf); + +// Get current line state. Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) +uint8_t tud_cdc_n_get_line_state (uint8_t itf); + +// Get current line encoding: bit rate, stop bits parity etc .. +void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding); + +// Set special character that will trigger tud_cdc_rx_wanted_cb() callback on receiving +void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted); + +// Get the number of bytes available for reading +uint32_t tud_cdc_n_available (uint8_t itf); + +// Read received bytes +uint32_t tud_cdc_n_read (uint8_t itf, void* buffer, uint32_t bufsize); + +// Read a byte, return -1 if there is none +static inline +int32_t tud_cdc_n_read_char (uint8_t itf); + +// Clear the received FIFO +void tud_cdc_n_read_flush (uint8_t itf); + +// Get a byte from FIFO at the specified position without removing it +bool tud_cdc_n_peek (uint8_t itf, uint8_t* ui8); + +// Write bytes to TX FIFO, data may remain in the FIFO for a while +uint32_t tud_cdc_n_write (uint8_t itf, void const* buffer, uint32_t bufsize); + +// Write a byte +static inline +uint32_t tud_cdc_n_write_char (uint8_t itf, char ch); + +// Write a null-terminated string +static inline +uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str); + +// Force sending data if possible, return number of forced bytes +uint32_t tud_cdc_n_write_flush (uint8_t itf); + +// Return the number of bytes (characters) available for writing to TX FIFO buffer in a single n_write operation. +uint32_t tud_cdc_n_write_available (uint8_t itf); + +// Clear the transmit FIFO +bool tud_cdc_n_write_clear (uint8_t itf); + +//--------------------------------------------------------------------+ +// Application API (Single Port) +//--------------------------------------------------------------------+ +static inline bool tud_cdc_connected (void); +static inline uint8_t tud_cdc_get_line_state (void); +static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding); +static inline void tud_cdc_set_wanted_char (char wanted); + +static inline uint32_t tud_cdc_available (void); +static inline int32_t tud_cdc_read_char (void); +static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize); +static inline void tud_cdc_read_flush (void); +static inline bool tud_cdc_peek (uint8_t* ui8); + +static inline uint32_t tud_cdc_write_char (char ch); +static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize); +static inline uint32_t tud_cdc_write_str (char const* str); +static inline uint32_t tud_cdc_write_flush (void); +static inline uint32_t tud_cdc_write_available (void); +static inline bool tud_cdc_write_clear (void); + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ + +// Invoked when received new data +TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf); + +// Invoked when received `wanted_char` +TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char); + +// Invoked when space becomes available in TX buffer +TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf); + +// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE +TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts); + +// Invoked when line coding is change via SET_LINE_CODING +TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding); + +// Invoked when received send break +TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms); + +//--------------------------------------------------------------------+ +// Inline Functions +//--------------------------------------------------------------------+ +static inline int32_t tud_cdc_n_read_char (uint8_t itf) +{ + uint8_t ch; + return tud_cdc_n_read(itf, &ch, 1) ? (int32_t) ch : -1; +} + +static inline uint32_t tud_cdc_n_write_char(uint8_t itf, char ch) +{ + return tud_cdc_n_write(itf, &ch, 1); +} + +static inline uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str) +{ + return tud_cdc_n_write(itf, str, strlen(str)); +} + +static inline bool tud_cdc_connected (void) +{ + return tud_cdc_n_connected(0); +} + +static inline uint8_t tud_cdc_get_line_state (void) +{ + return tud_cdc_n_get_line_state(0); +} + +static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding) +{ + tud_cdc_n_get_line_coding(0, coding); +} + +static inline void tud_cdc_set_wanted_char (char wanted) +{ + tud_cdc_n_set_wanted_char(0, wanted); +} + +static inline uint32_t tud_cdc_available (void) +{ + return tud_cdc_n_available(0); +} + +static inline int32_t tud_cdc_read_char (void) +{ + return tud_cdc_n_read_char(0); +} + +static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize) +{ + return tud_cdc_n_read(0, buffer, bufsize); +} + +static inline void tud_cdc_read_flush (void) +{ + tud_cdc_n_read_flush(0); +} + +static inline bool tud_cdc_peek (uint8_t* ui8) +{ + return tud_cdc_n_peek(0, ui8); +} + +static inline uint32_t tud_cdc_write_char (char ch) +{ + return tud_cdc_n_write_char(0, ch); +} + +static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize) +{ + return tud_cdc_n_write(0, buffer, bufsize); +} + +static inline uint32_t tud_cdc_write_str (char const* str) +{ + return tud_cdc_n_write_str(0, str); +} + +static inline uint32_t tud_cdc_write_flush (void) +{ + return tud_cdc_n_write_flush(0); +} + +static inline uint32_t tud_cdc_write_available(void) +{ + return tud_cdc_n_write_available(0); +} + +static inline bool tud_cdc_write_clear(void) +{ + return tud_cdc_n_write_clear(0); +} + +/** @} */ +/** @} */ + +//--------------------------------------------------------------------+ +// INTERNAL USBD-CLASS DRIVER API +//--------------------------------------------------------------------+ +void cdcd_init (void); +void cdcd_reset (uint8_t rhport); +uint16_t cdcd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool cdcd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +bool cdcd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CDC_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.c b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.c new file mode 100644 index 00000000..ee824cb4 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.c @@ -0,0 +1,260 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUH_ENABLED && CFG_TUH_CDC) + +#include "host/usbh.h" +#include "host/usbh_classdriver.h" + +#include "cdc_host.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +typedef struct { + uint8_t itf_num; + uint8_t itf_protocol; + + uint8_t ep_notif; + uint8_t ep_in; + uint8_t ep_out; + + cdc_acm_capability_t acm_capability; + +} cdch_data_t; + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +static cdch_data_t cdch_data[CFG_TUH_DEVICE_MAX]; + +static inline cdch_data_t* get_itf(uint8_t dev_addr) +{ + return &cdch_data[dev_addr-1]; +} + +bool tuh_cdc_mounted(uint8_t dev_addr) +{ + cdch_data_t* cdc = get_itf(dev_addr); + return cdc->ep_in && cdc->ep_out; +} + +bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid) +{ + if ( !tuh_cdc_mounted(dev_addr) ) return false; + + cdch_data_t const * p_cdc = get_itf(dev_addr); + + switch (pipeid) + { + case CDC_PIPE_NOTIFICATION: + return usbh_edpt_busy(dev_addr, p_cdc->ep_notif ); + + case CDC_PIPE_DATA_IN: + return usbh_edpt_busy(dev_addr, p_cdc->ep_in ); + + case CDC_PIPE_DATA_OUT: + return usbh_edpt_busy(dev_addr, p_cdc->ep_out ); + + default: + return false; + } +} + +//--------------------------------------------------------------------+ +// APPLICATION API (parameter validation needed) +//--------------------------------------------------------------------+ +bool tuh_cdc_serial_is_mounted(uint8_t dev_addr) +{ + // TODO consider all AT Command as serial candidate + return tuh_cdc_mounted(dev_addr) && + (cdch_data[dev_addr-1].itf_protocol <= CDC_COMM_PROTOCOL_ATCOMMAND_CDMA); +} + +bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify) +{ + (void) is_notify; + TU_VERIFY( tuh_cdc_mounted(dev_addr) ); + TU_VERIFY( p_data != NULL && length); + + uint8_t const ep_out = cdch_data[dev_addr-1].ep_out; + if ( usbh_edpt_busy(dev_addr, ep_out) ) return false; + + return usbh_edpt_xfer(dev_addr, ep_out, (void*)(uintptr_t) p_data, (uint16_t) length); +} + +bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify) +{ + (void) is_notify; + TU_VERIFY( tuh_cdc_mounted(dev_addr) ); + TU_VERIFY( p_buffer != NULL && length ); + + uint8_t const ep_in = cdch_data[dev_addr-1].ep_in; + if ( usbh_edpt_busy(dev_addr, ep_in) ) return false; + + return usbh_edpt_xfer(dev_addr, ep_in, p_buffer, (uint16_t) length); +} + +bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb) +{ + cdch_data_t const * p_cdc = get_itf(dev_addr); + + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, + .wValue = tu_htole16((uint16_t) ((dtr ? 1u : 0u) | (rts ? 2u : 0u))), + .wIndex = tu_htole16(p_cdc->itf_num), + .wLength = 0 + }; + + tuh_xfer_t xfer = + { + .daddr = dev_addr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb, + .user_data = 0 + }; + + return tuh_control_xfer(&xfer); +} + +//--------------------------------------------------------------------+ +// USBH-CLASS DRIVER API +//--------------------------------------------------------------------+ +void cdch_init(void) +{ + tu_memclr(cdch_data, sizeof(cdch_data)); +} + +bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) +{ + (void) rhport; + (void) max_len; + + // Only support ACM subclass + // Protocol 0xFF can be RNDIS device for windows XP + TU_VERIFY( TUSB_CLASS_CDC == itf_desc->bInterfaceClass && + CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass && + 0xFF != itf_desc->bInterfaceProtocol); + + cdch_data_t * p_cdc = get_itf(dev_addr); + + p_cdc->itf_num = itf_desc->bInterfaceNumber; + p_cdc->itf_protocol = itf_desc->bInterfaceProtocol; + + //------------- Communication Interface -------------// + uint16_t drv_len = tu_desc_len(itf_desc); + uint8_t const * p_desc = tu_desc_next(itf_desc); + + // Communication Functional Descriptors + while( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) + { + if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) ) + { + // save ACM bmCapabilities + p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities; + } + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + { + // notification endpoint + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; + + TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) ); + p_cdc->ep_notif = desc_ep->bEndpointAddress; + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + //------------- Data Interface (if any) -------------// + if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && + (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) + { + // next to endpoint descriptor + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + + // data endpoints expected to be in pairs + for(uint32_t i=0; i<2; i++) + { + tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; + TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); + + TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); + + if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) + { + p_cdc->ep_in = desc_ep->bEndpointAddress; + }else + { + p_cdc->ep_out = desc_ep->bEndpointAddress; + } + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next( p_desc ); + } + } + + return true; +} + +bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num) +{ + (void) dev_addr; (void) itf_num; + return true; +} + +bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +{ + (void) ep_addr; + tuh_cdc_xfer_isr( dev_addr, event, 0, xferred_bytes ); + return true; +} + +void cdch_close(uint8_t dev_addr) +{ + TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); + + cdch_data_t * p_cdc = get_itf(dev_addr); + tu_memclr(p_cdc, sizeof(cdch_data_t)); +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.h b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.h new file mode 100644 index 00000000..33dbd2ef --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.h @@ -0,0 +1,134 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_CDC_HOST_H_ +#define _TUSB_CDC_HOST_H_ + +#include "cdc.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// CDC APPLICATION PUBLIC API +//--------------------------------------------------------------------+ +/** \ingroup ClassDriver_CDC Communication Device Class (CDC) + * \addtogroup CDC_Serial Serial + * @{ + * \defgroup CDC_Serial_Host Host + * @{ */ + +bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb); + +static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb) +{ + return tuh_cdc_set_control_line_state(dev_addr, true, true, complete_cb); +} + +static inline bool tuh_cdc_disconnect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb) +{ + return tuh_cdc_set_control_line_state(dev_addr, false, false, complete_cb); +} + +/** \brief Check if device support CDC Serial interface or not + * \param[in] dev_addr device address + * \retval true if device supports + * \retval false if device does not support or is not mounted + */ +bool tuh_cdc_serial_is_mounted(uint8_t dev_addr); + +/** \brief Check if the interface is currently busy or not + * \param[in] dev_addr device address + * \param[in] pipeid value from \ref cdc_pipeid_t to indicate target pipe. + * \retval true if the interface is busy, meaning the stack is still transferring/waiting data from/to device + * \retval false if the interface is not busy, meaning the stack successfully transferred data from/to device + * \note This function is used to check if previous transfer is complete (success or error), so that the next transfer + * can be scheduled. User needs to make sure the corresponding interface is mounted + * (by \ref tuh_cdc_serial_is_mounted) before calling this function. + */ +bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid); + +/** \brief Perform USB OUT transfer to device + * \param[in] dev_addr device address + * \param[in] p_data Buffer containing data. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION) + * \param[in] length Number of bytes to be transferred via USB bus + * \retval TUSB_ERROR_NONE on success + * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device + * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request) + * \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct + * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the + * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION. + */ +bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify); + +/** \brief Perform USB IN transfer to get data from device + * \param[in] dev_addr device address + * \param[in] p_buffer Buffer containing received data. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION) + * \param[in] length Number of bytes to be transferred via USB bus + * \retval TUSB_ERROR_NONE on success + * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device + * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request) + * \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct + * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the + * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION. + */ +bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify); + +//--------------------------------------------------------------------+ +// CDC APPLICATION CALLBACKS +//--------------------------------------------------------------------+ + +/** \brief Callback function that is invoked when an transferring event occurred + * \param[in] dev_addr Address of device + * \param[in] event an value from \ref xfer_result_t + * \param[in] pipe_id value from \ref cdc_pipeid_t indicate the pipe + * \param[in] xferred_bytes Number of bytes transferred via USB bus + * \note event can be one of following + * - XFER_RESULT_SUCCESS : previously scheduled transfer completes successfully. + * - XFER_RESULT_FAILED : previously scheduled transfer encountered a transaction error. + * - XFER_RESULT_STALLED : previously scheduled transfer is stalled by device. + * \note + */ +void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes); + +/// @} // group CDC_Serial_Host +/// @} + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void cdch_init (void); +bool cdch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); +bool cdch_set_config (uint8_t dev_addr, uint8_t itf_num); +bool cdch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); +void cdch_close (uint8_t dev_addr); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CDC_HOST_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis.h b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis.h new file mode 100644 index 00000000..e0f129fe --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis.h @@ -0,0 +1,301 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup ClassDriver_CDC Communication Device Class (CDC) + * \defgroup CDC_RNDIS Remote Network Driver Interface Specification (RNDIS) + * @{ + * \defgroup CDC_RNDIS_Common Common Definitions + * @{ */ + +#ifndef _TUSB_CDC_RNDIS_H_ +#define _TUSB_CDC_RNDIS_H_ + +#include "cdc.h" + +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef __CC_ARM +#pragma diag_suppress 66 // Suppress Keil warnings #66-D: enumeration value is out of "int" range +#endif + +/// RNDIS Message Types +typedef enum +{ + RNDIS_MSG_PACKET = 0x00000001UL, ///< The host and device use this to send network data to one another. + + RNDIS_MSG_INITIALIZE = 0x00000002UL, ///< Sent by the host to initialize the device. + RNDIS_MSG_INITIALIZE_CMPLT = 0x80000002UL, ///< Device response to an initialize message. + + RNDIS_MSG_HALT = 0x00000003UL, ///< Sent by the host to halt the device. This does not have a response. It is optional for the device to send this message to the host. + + RNDIS_MSG_QUERY = 0x00000004UL, ///< Sent by the host to send a query OID. + RNDIS_MSG_QUERY_CMPLT = 0x80000004UL, ///< Device response to a query OID. + + RNDIS_MSG_SET = 0x00000005UL, ///< Sent by the host to send a set OID. + RNDIS_MSG_SET_CMPLT = 0x80000005UL, ///< Device response to a set OID. + + RNDIS_MSG_RESET = 0x00000006UL, ///< Sent by the host to perform a soft reset on the device. + RNDIS_MSG_RESET_CMPLT = 0x80000006UL, ///< Device response to reset message. + + RNDIS_MSG_INDICATE_STATUS = 0x00000007UL, ///< Sent by the device to indicate its status or an error when an unrecognized message is received. + + RNDIS_MSG_KEEP_ALIVE = 0x00000008UL, ///< During idle periods, sent every few seconds by the host to check that the device is still responsive. It is optional for the device to send this message to check if the host is active. + RNDIS_MSG_KEEP_ALIVE_CMPLT = 0x80000008UL ///< The device response to a keepalivemessage. The host can respond with this message to a keepalive message from the device when the device implements the optional KeepAliveTimer. +}rndis_msg_type_t; + +/// RNDIS Message Status Values +typedef enum +{ + RNDIS_STATUS_SUCCESS = 0x00000000UL, ///< Success + RNDIS_STATUS_FAILURE = 0xC0000001UL, ///< Unspecified error + RNDIS_STATUS_INVALID_DATA = 0xC0010015UL, ///< Invalid data error + RNDIS_STATUS_NOT_SUPPORTED = 0xC00000BBUL, ///< Unsupported request error + RNDIS_STATUS_MEDIA_CONNECT = 0x4001000BUL, ///< Device is connected to a network medium. + RNDIS_STATUS_MEDIA_DISCONNECT = 0x4001000CUL ///< Device is disconnected from the medium. +}rndis_msg_status_t; + +#ifdef __CC_ARM +#pragma diag_default 66 // return Keil 66 to normal severity +#endif + +//--------------------------------------------------------------------+ +// MESSAGE STRUCTURE +//--------------------------------------------------------------------+ + +//------------- Initialize -------------// +/// \brief Initialize Message +/// \details This message MUST be sent by the host to initialize the device. +typedef struct { + uint32_t type ; ///< Message type, must be \ref RNDIS_MSG_INITIALIZE + uint32_t length ; ///< Message length in bytes, must be 0x18 + uint32_t request_id ; ///< A 32-bit integer value, generated by the host, used to match the host's sent request to the response from the device. + uint32_t major_version ; ///< The major version of the RNDIS Protocol implemented by the host. + uint32_t minor_version ; ///< The minor version of the RNDIS Protocol implemented by the host + uint32_t max_xfer_size ; ///< The maximum size, in bytes, of any single bus data transfer that the host expects to receive from the device. +}rndis_msg_initialize_t; + +/// \brief Initialize Complete Message +/// \details This message MUST be sent by the device in response to an initialize message. +typedef struct { + uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_INITIALIZE_CMPLT + uint32_t length ; ///< Message length in bytes, must be 0x30 + uint32_t request_id ; ///< A 32-bit integer value from \a request_id field of the \ref rndis_msg_initialize_t to which this message is a response. + uint32_t status ; ///< The initialization status of the device, has value from \ref rndis_msg_status_t + uint32_t major_version ; ///< the highest-numbered RNDIS Protocol version supported by the device. + uint32_t minor_version ; ///< the highest-numbered RNDIS Protocol version supported by the device. + uint32_t device_flags ; ///< MUST be set to 0x000000010. Other values are reserved for future use. + uint32_t medium ; ///< is 0x00 for RNDIS_MEDIUM_802_3 + uint32_t max_packet_per_xfer ; ///< The maximum number of concatenated \ref RNDIS_MSG_PACKET messages that the device can handle in a single bus transfer to it. This value MUST be at least 1. + uint32_t max_xfer_size ; ///< The maximum size, in bytes, of any single bus data transfer that the device expects to receive from the host. + uint32_t packet_alignment_factor ; ///< The byte alignment the device expects for each RNDIS message that is part of a multimessage transfer to it. The value is specified as an exponent of 2; for example, the host uses 2{PacketAlignmentFactor} as the alignment value. + uint32_t reserved[2] ; +} rndis_msg_initialize_cmplt_t; + +//------------- Query -------------// +/// \brief Query Message +/// \details This message MUST be sent by the host to query an OID. +typedef struct { + uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_QUERY + uint32_t length ; ///< Message length in bytes, including the header and the \a oid_buffer + uint32_t request_id ; ///< A 32-bit integer value, generated by the host, used to match the host's sent request to the response from the device. + uint32_t oid ; ///< The integer value of the host operating system-defined identifier, for the parameter of the device being queried for. + uint32_t buffer_length ; ///< The length, in bytes, of the input data required for the OID query. This MUST be set to 0 when there is no input data associated with the OID. + uint32_t buffer_offset ; ///< The offset, in bytes, from the beginning of \a request_id field where the input data for the query is located in the message. This value MUST be set to 0 when there is no input data associated with the OID. + uint32_t reserved ; + uint8_t oid_buffer[] ; ///< Flexible array contains the input data supplied by the host, required for the OID query request processing by the device, as per the host NDIS specification. +} rndis_msg_query_t, rndis_msg_set_t; + +TU_VERIFY_STATIC(sizeof(rndis_msg_query_t) == 28, "Make sure flexible array member does not affect layout"); + +/// \brief Query Complete Message +/// \details This message MUST be sent by the device in response to a query OID message. +typedef struct { + uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_QUERY_CMPLT + uint32_t length ; ///< Message length in bytes, including the header and the \a oid_buffer + uint32_t request_id ; ///< A 32-bit integer value from \a request_id field of the \ref rndis_msg_query_t to which this message is a response. + uint32_t status ; ///< The status of processing for the query request, has value from \ref rndis_msg_status_t. + uint32_t buffer_length ; ///< The length, in bytes, of the data in the response to the query. This MUST be set to 0 when there is no OIDInputBuffer. + uint32_t buffer_offset ; ///< The offset, in bytes, from the beginning of \a request_id field where the response data for the query is located in the message. This MUST be set to 0 when there is no \ref oid_buffer. + uint8_t oid_buffer[] ; ///< Flexible array member contains the response data to the OID query request as specified by the host. +} rndis_msg_query_cmplt_t; + +TU_VERIFY_STATIC(sizeof(rndis_msg_query_cmplt_t) == 24, "Make sure flexible array member does not affect layout"); + +//------------- Reset -------------// +/// \brief Reset Message +/// \details This message MUST be sent by the host to perform a soft reset on the device. +typedef struct { + uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_RESET + uint32_t length ; ///< Message length in bytes, MUST be 0x06 + uint32_t reserved ; +} rndis_msg_reset_t; + +/// \brief Reset Complete Message +/// \details This message MUST be sent by the device in response to a reset message. +typedef struct { + uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_RESET_CMPLT + uint32_t length ; ///< Message length in bytes, MUST be 0x10 + uint32_t status ; ///< The status of processing for the \ref rndis_msg_reset_t, has value from \ref rndis_msg_status_t. + uint32_t addressing_reset ; ///< This field indicates whether the addressing information, which is the multicast address list or packet filter, has been lost during the reset operation. This MUST be set to 0x00000001 if the device requires that the host to resend addressing information or MUST be set to zero otherwise. +} rndis_msg_reset_cmplt_t; + +//typedef struct { +// uint32_t type; +// uint32_t length; +// uint32_t status; +// uint32_t buffer_length; +// uint32_t buffer_offset; +// uint32_t diagnostic_status; // optional +// uint32_t diagnostic_error_offset; // optional +// uint32_t status_buffer[0]; // optional +//} rndis_msg_indicate_status_t; + +/// \brief Keep Alive Message +/// \details This message MUST be sent by the host to check that device is still responsive. It is optional for the device to send this message to check if the host is active +typedef struct { + uint32_t type ; ///< Message Type + uint32_t length ; ///< Message length in bytes, MUST be 0x10 + uint32_t request_id ; +} rndis_msg_keep_alive_t, rndis_msg_halt_t; + +/// \brief Set Complete Message +/// \brief This message MUST be sent in response to a the request message +typedef struct { + uint32_t type ; ///< Message Type + uint32_t length ; ///< Message length in bytes, MUST be 0x10 + uint32_t request_id ; ///< must be the same as requesting message + uint32_t status ; ///< The status of processing for the request message request by the device to which this message is the response. +} rndis_msg_set_cmplt_t, rndis_msg_keep_alive_cmplt_t; + +/// \brief Packet Data Message +/// \brief This message MUST be used by the host and the device to send network data to one another. +typedef struct { + uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_PACKET + uint32_t length ; ///< Message length in bytes, The total length of this RNDIS message including the header, payload, and padding. + uint32_t data_offset ; ///< Specifies the offset, in bytes, from the start of this \a data_offset field of this message to the start of the data. This MUST be an integer multiple of 4. + uint32_t data_length ; ///< Specifies the number of bytes in the payload of this message. + uint32_t out_of_band_data_offet ; ///< Specifies the offset, in bytes, of the first out-of-band data record from the start of the DataOffset field in this message. MUST be an integer multiple of 4 when out-of-band data is present or set to 0 otherwise. When there are multiple out-ofband data records, each subsequent record MUST immediately follow the previous out-of-band data record. + uint32_t out_of_band_data_length ; ///< Specifies, in bytes, the total length of the out-of-band data. + uint32_t num_out_of_band_data_elements ; ///< Specifies the number of out-of-band records in this message. + uint32_t per_packet_info_offset ; ///< Specifies the offset, in bytes, of the start of per-packet-info data record from the start of the \a data_offset field in this message. MUST be an integer multiple of 4 when per-packet-info data record is present or MUST be set to 0 otherwise. When there are multiple per-packet-info data records, each subsequent record MUST immediately follow the previous record. + uint32_t per_packet_info_length ; ///< Specifies, in bytes, the total length of per-packetinformation contained in this message. + uint32_t reserved[2] ; + uint32_t payload[0] ; ///< Network data contained in this message. + + // uint8_t padding[0] + // Additional bytes of zeros added at the end of the message to comply with + // the internal and external padding requirements. Internal padding SHOULD be as per the + // specification of the out-of-band data record and per-packet-info data record. The external + //padding size SHOULD be determined based on the PacketAlignmentFactor field specification + //in REMOTE_NDIS_INITIALIZE_CMPLT message by the device, when multiple + //REMOTE_NDIS_PACKET_MSG messages are bundled together in a single bus-native message. + //In this case, all but the very last REMOTE_NDIS_PACKET_MSG MUST respect the + //PacketAlignmentFactor field. + + // rndis_msg_packet_t [0] : (optional) more packet if multiple packet per bus transaction is supported +} rndis_msg_packet_t; + + +typedef struct { + uint32_t size ; ///< Length, in bytes, of this header and appended data and padding. This value MUST be an integer multiple of 4. + uint32_t type ; ///< MUST be as per host operating system specification. + uint32_t offset ; ///< The byte offset from the beginning of this record to the beginning of data. + uint32_t data[0] ; ///< Flexible array contains data +} rndis_msg_out_of_band_data_t, rndis_msg_per_packet_info_t; + +//--------------------------------------------------------------------+ +// NDIS Object ID +//--------------------------------------------------------------------+ + +/// NDIS Object ID +typedef enum +{ + //------------- General Required OIDs -------------// + RNDIS_OID_GEN_SUPPORTED_LIST = 0x00010101, ///< List of supported OIDs + RNDIS_OID_GEN_HARDWARE_STATUS = 0x00010102, ///< Hardware status + RNDIS_OID_GEN_MEDIA_SUPPORTED = 0x00010103, ///< Media types supported (encoded) + RNDIS_OID_GEN_MEDIA_IN_USE = 0x00010104, ///< Media types in use (encoded) + RNDIS_OID_GEN_MAXIMUM_LOOKAHEAD = 0x00010105, ///< + RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE = 0x00010106, ///< Maximum frame size in bytes + RNDIS_OID_GEN_LINK_SPEED = 0x00010107, ///< Link speed in units of 100 bps + RNDIS_OID_GEN_TRANSMIT_BUFFER_SPACE = 0x00010108, ///< Transmit buffer space + RNDIS_OID_GEN_RECEIVE_BUFFER_SPACE = 0x00010109, ///< Receive buffer space + RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE = 0x0001010A, ///< Minimum amount of storage, in bytes, that a single packet occupies in the transmit buffer space of the NIC + RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE = 0x0001010B, ///< Amount of storage, in bytes, that a single packet occupies in the receive buffer space of the NIC + RNDIS_OID_GEN_VENDOR_ID = 0x0001010C, ///< Vendor NIC code + RNDIS_OID_GEN_VENDOR_DESCRIPTION = 0x0001010D, ///< Vendor network card description + RNDIS_OID_GEN_CURRENT_PACKET_FILTER = 0x0001010E, ///< Current packet filter (encoded) + RNDIS_OID_GEN_CURRENT_LOOKAHEAD = 0x0001010F, ///< Current lookahead size in bytes + RNDIS_OID_GEN_DRIVER_VERSION = 0x00010110, ///< NDIS version number used by the driver + RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE = 0x00010111, ///< Maximum total packet length in bytes + RNDIS_OID_GEN_PROTOCOL_OPTIONS = 0x00010112, ///< Optional protocol flags (encoded) + RNDIS_OID_GEN_MAC_OPTIONS = 0x00010113, ///< Optional NIC flags (encoded) + RNDIS_OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114, ///< Whether the NIC is connected to the network + RNDIS_OID_GEN_MAXIMUM_SEND_PACKETS = 0x00010115, ///< The maximum number of send packets the driver can accept per call to its MiniportSendPacketsfunction + + //------------- General Optional OIDs -------------// + RNDIS_OID_GEN_VENDOR_DRIVER_VERSION = 0x00010116, ///< Vendor-assigned version number of the driver + RNDIS_OID_GEN_SUPPORTED_GUIDS = 0x00010117, ///< The custom GUIDs (Globally Unique Identifier) supported by the miniport driver + RNDIS_OID_GEN_NETWORK_LAYER_ADDRESSES = 0x00010118, ///< List of network-layer addresses associated with the binding between a transport and the driver + RNDIS_OID_GEN_TRANSPORT_HEADER_OFFSET = 0x00010119, ///< Size of packets' additional headers + RNDIS_OID_GEN_MEDIA_CAPABILITIES = 0x00010201, ///< + RNDIS_OID_GEN_PHYSICAL_MEDIUM = 0x00010202, ///< Physical media supported by the miniport driver (encoded) + + //------------- 802.3 Objects (Ethernet) -------------// + RNDIS_OID_802_3_PERMANENT_ADDRESS = 0x01010101, ///< Permanent station address + RNDIS_OID_802_3_CURRENT_ADDRESS = 0x01010102, ///< Current station address + RNDIS_OID_802_3_MULTICAST_LIST = 0x01010103, ///< Current multicast address list + RNDIS_OID_802_3_MAXIMUM_LIST_SIZE = 0x01010104, ///< Maximum size of multicast address list +} rndis_oid_type_t; + +/// RNDIS Packet Filter Bits \ref RNDIS_OID_GEN_CURRENT_PACKET_FILTER. +typedef enum +{ + RNDIS_PACKET_TYPE_DIRECTED = 0x00000001, ///< Directed packets. Directed packets contain a destination address equal to the station address of the NIC. + RNDIS_PACKET_TYPE_MULTICAST = 0x00000002, ///< Multicast address packets sent to addresses in the multicast address list. + RNDIS_PACKET_TYPE_ALL_MULTICAST = 0x00000004, ///< All multicast address packets, not just the ones enumerated in the multicast address list. + RNDIS_PACKET_TYPE_BROADCAST = 0x00000008, ///< Broadcast packets. + RNDIS_PACKET_TYPE_SOURCE_ROUTING = 0x00000010, ///< All source routing packets. If the protocol driver sets this bit, the NDIS library attempts to act as a source routing bridge. + RNDIS_PACKET_TYPE_PROMISCUOUS = 0x00000020, ///< Specifies all packets regardless of whether VLAN filtering is enabled or not and whether the VLAN identifier matches or not. + RNDIS_PACKET_TYPE_SMT = 0x00000040, ///< SMT packets that an FDDI NIC receives. + RNDIS_PACKET_TYPE_ALL_LOCAL = 0x00000080, ///< All packets sent by installed protocols and all packets indicated by the NIC that is identified by a given NdisBindingHandle. + RNDIS_PACKET_TYPE_GROUP = 0x00001000, ///< Packets sent to the current group address. + RNDIS_PACKET_TYPE_ALL_FUNCTIONAL = 0x00002000, ///< All functional address packets, not just the ones in the current functional address. + RNDIS_PACKET_TYPE_FUNCTIONAL = 0x00004000, ///< Functional address packets sent to addresses included in the current functional address. + RNDIS_PACKET_TYPE_MAC_FRAME = 0x00008000, ///< NIC driver frames that a Token Ring NIC receives. + RNDIS_PACKET_TYPE_NO_LOCAL = 0x00010000, +} rndis_packet_filter_type_t; + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CDC_RNDIS_H_ */ + +/** @} */ +/** @} */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c new file mode 100644 index 00000000..8f28f51a --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c @@ -0,0 +1,289 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUH_ENABLED && CFG_TUH_CDC && CFG_TUH_CDC_RNDIS) + +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "common/tusb_common.h" +#include "cdc_host.h" +#include "cdc_rndis_host.h" + +#if 0 // TODO remove subtask related macros later +// Sub Task +#define OSAL_SUBTASK_BEGIN +#define OSAL_SUBTASK_END return TUSB_ERROR_NONE; + +#define STASK_RETURN(_error) return _error; +#define STASK_INVOKE(_subtask, _status) (_status) = _subtask +#define STASK_ASSERT(_cond) TU_VERIFY(_cond, TUSB_ERROR_OSAL_TASK_FAILED) +#endif + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +#define RNDIS_MSG_PAYLOAD_MAX (1024*4) + +CFG_TUSB_MEM_SECTION static uint8_t msg_notification[CFG_TUH_DEVICE_MAX][8]; +CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t msg_payload[RNDIS_MSG_PAYLOAD_MAX]; + +static rndish_data_t rndish_data[CFG_TUH_DEVICE_MAX]; + +// TODO Microsoft requires message length for any get command must be at least 4096 bytes + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +static tusb_error_t rndis_body_subtask(void); +static tusb_error_t send_message_get_response_subtask( uint8_t dev_addr, cdch_data_t *p_cdc, + uint8_t * p_mess, uint32_t mess_length, + uint8_t *p_response ); + +//--------------------------------------------------------------------+ +// APPLICATION API +//--------------------------------------------------------------------+ +tusb_error_t tusbh_cdc_rndis_get_mac_addr(uint8_t dev_addr, uint8_t mac_address[6]) +{ + TU_ASSERT( tusbh_cdc_rndis_is_mounted(dev_addr), TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED); + TU_VERIFY( mac_address, TUSB_ERROR_INVALID_PARA); + + memcpy(mac_address, rndish_data[dev_addr-1].mac_address, 6); + + return TUSB_ERROR_NONE; +} + +//--------------------------------------------------------------------+ +// IMPLEMENTATION +//--------------------------------------------------------------------+ + +// To enable the TASK_ASSERT style (quick return on false condition) in a real RTOS, a task must act as a wrapper +// and is used mainly to call subtasks. Within a subtask return statement can be called freely, the task with +// forever loop cannot have any return at all. +OSAL_TASK_FUNCTION(cdch_rndis_task) (void* param;) +{ + OSAL_TASK_BEGIN + rndis_body_subtask(); + OSAL_TASK_END +} + +static tusb_error_t rndis_body_subtask(void) +{ + static uint8_t relative_addr; + + OSAL_SUBTASK_BEGIN + + for (relative_addr = 0; relative_addr < CFG_TUH_DEVICE_MAX; relative_addr++) + { + + } + + osal_task_delay(100); + + OSAL_SUBTASK_END +} + +//--------------------------------------------------------------------+ +// RNDIS-CDC Driver API +//--------------------------------------------------------------------+ +void rndish_init(void) +{ + tu_memclr(rndish_data, sizeof(rndish_data_t)*CFG_TUH_DEVICE_MAX); + + //------------- Task creation -------------// + + //------------- semaphore creation for notificaiton pipe -------------// + for(uint8_t i=0; itype == RNDIS_MSG_INITIALIZE_CMPLT && p_init_cmpt->status == RNDIS_STATUS_SUCCESS && + p_init_cmpt->max_packet_per_xfer == 1 && p_init_cmpt->max_xfer_size <= RNDIS_MSG_PAYLOAD_MAX); + rndish_data[dev_addr-1].max_xfer_size = p_init_cmpt->max_xfer_size; + + //------------- Message Query 802.3 Permanent Address -------------// + memcpy(msg_payload, &msg_query_permanent_addr, sizeof(rndis_msg_query_t)); + tu_memclr(msg_payload + sizeof(rndis_msg_query_t), 6); // 6 bytes for MAC address + + STASK_INVOKE( + send_message_get_response_subtask( dev_addr, p_cdc, + msg_payload, sizeof(rndis_msg_query_t) + 6, + msg_payload), + error + ); + if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error); + + rndis_msg_query_cmplt_t * const p_query_cmpt = (rndis_msg_query_cmplt_t *) msg_payload; + STASK_ASSERT(p_query_cmpt->type == RNDIS_MSG_QUERY_CMPLT && p_query_cmpt->status == RNDIS_STATUS_SUCCESS); + memcpy(rndish_data[dev_addr-1].mac_address, msg_payload + 8 + p_query_cmpt->buffer_offset, 6); + + //------------- Set OID_GEN_CURRENT_PACKET_FILTER to (DIRECTED | MULTICAST | BROADCAST) -------------// + memcpy(msg_payload, &msg_set_packet_filter, sizeof(rndis_msg_set_t)); + tu_memclr(msg_payload + sizeof(rndis_msg_set_t), 4); // 4 bytes for filter flags + ((rndis_msg_set_t*) msg_payload)->oid_buffer[0] = (RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_MULTICAST | RNDIS_PACKET_TYPE_BROADCAST); + + STASK_INVOKE( + send_message_get_response_subtask( dev_addr, p_cdc, + msg_payload, sizeof(rndis_msg_set_t) + 4, + msg_payload), + error + ); + if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error); + + rndis_msg_set_cmplt_t * const p_set_cmpt = (rndis_msg_set_cmplt_t *) msg_payload; + STASK_ASSERT(p_set_cmpt->type == RNDIS_MSG_SET_CMPLT && p_set_cmpt->status == RNDIS_STATUS_SUCCESS); + + tusbh_cdc_rndis_mounted_cb(dev_addr); + + OSAL_SUBTASK_END +} + +void rndish_xfer_isr(cdch_data_t *p_cdc, pipe_handle_t pipe_hdl, xfer_result_t event, uint32_t xferred_bytes) +{ + if ( pipehandle_is_equal(pipe_hdl, p_cdc->pipe_notification) ) + { + osal_semaphore_post( rndish_data[pipe_hdl.dev_addr-1].sem_notification_hdl ); + } +} + +//--------------------------------------------------------------------+ +// INTERNAL & HELPER +//--------------------------------------------------------------------+ +static tusb_error_t send_message_get_response_subtask( uint8_t dev_addr, cdch_data_t *p_cdc, + uint8_t * p_mess, uint32_t mess_length, + uint8_t *p_response) +{ + tusb_error_t error; + + OSAL_SUBTASK_BEGIN + + //------------- Send RNDIS Control Message -------------// + STASK_INVOKE( + usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_OUT, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_INTERFACE), + CDC_REQUEST_SEND_ENCAPSULATED_COMMAND, 0, p_cdc->interface_number, + mess_length, p_mess), + error + ); + if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error); + + //------------- waiting for Response Available notification -------------// + (void) usbh_edpt_xfer(p_cdc->pipe_notification, msg_notification[dev_addr-1], 8); + osal_semaphore_wait(rndish_data[dev_addr-1].sem_notification_hdl, OSAL_TIMEOUT_NORMAL, &error); + if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error); + STASK_ASSERT(msg_notification[dev_addr-1][0] == 1); + + //------------- Get RNDIS Message Initialize Complete -------------// + STASK_INVOKE( + usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_INTERFACE), + CDC_REQUEST_GET_ENCAPSULATED_RESPONSE, 0, p_cdc->interface_number, + RNDIS_MSG_PAYLOAD_MAX, p_response), + error + ); + if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error); + + OSAL_SUBTASK_END +} + +//static tusb_error_t send_process_msg_initialize_subtask(uint8_t dev_addr, cdch_data_t *p_cdc) +//{ +// tusb_error_t error; +// +// OSAL_SUBTASK_BEGIN +// +// *((rndis_msg_initialize_t*) msg_payload) = (rndis_msg_initialize_t) +// { +// .type = RNDIS_MSG_INITIALIZE, +// .length = sizeof(rndis_msg_initialize_t), +// .request_id = 1, // TODO should use some magic number +// .major_version = 1, +// .minor_version = 0, +// .max_xfer_size = 0x4000 // TODO mimic windows +// }; +// +// +// +// OSAL_SUBTASK_END +//} +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.h b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.h new file mode 100644 index 00000000..447cc4e9 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.h @@ -0,0 +1,63 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup CDC_RNDIS + * \defgroup CDC_RNSID_Host Host + * @{ */ + +#ifndef _TUSB_CDC_RNDIS_HOST_H_ +#define _TUSB_CDC_RNDIS_HOST_H_ + +#include "common/tusb_common.h" +#include "host/usbh.h" +#include "cdc_rndis.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// INTERNAL RNDIS-CDC Driver API +//--------------------------------------------------------------------+ +typedef struct { + OSAL_SEM_DEF(semaphore_notification); + osal_semaphore_handle_t sem_notification_hdl; // used to wait on notification pipe + uint32_t max_xfer_size; // got from device's msg initialize complete + uint8_t mac_address[6]; +}rndish_data_t; + +void rndish_init(void); +bool rndish_open_subtask(uint8_t dev_addr, cdch_data_t *p_cdc); +void rndish_xfer_isr(cdch_data_t *p_cdc, pipe_handle_t pipe_hdl, xfer_result_t event, uint32_t xferred_bytes); +void rndish_close(uint8_t dev_addr); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CDC_RNDIS_HOST_H_ */ + +/** @} */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu.h b/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu.h new file mode 100644 index 00000000..114c827b --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu.h @@ -0,0 +1,119 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 XMOS LIMITED + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_DFU_H_ +#define _TUSB_DFU_H_ + +#include "common/tusb_common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Common Definitions +//--------------------------------------------------------------------+ + +// DFU Protocol +typedef enum +{ + DFU_PROTOCOL_RT = 0x01, + DFU_PROTOCOL_DFU = 0x02, +} dfu_protocol_type_t; + +// DFU Descriptor Type +typedef enum +{ + DFU_DESC_FUNCTIONAL = 0x21, +} dfu_descriptor_type_t; + +// DFU Requests +typedef enum { + DFU_REQUEST_DETACH = 0, + DFU_REQUEST_DNLOAD = 1, + DFU_REQUEST_UPLOAD = 2, + DFU_REQUEST_GETSTATUS = 3, + DFU_REQUEST_CLRSTATUS = 4, + DFU_REQUEST_GETSTATE = 5, + DFU_REQUEST_ABORT = 6, +} dfu_requests_t; + +// DFU States +typedef enum { + APP_IDLE = 0, + APP_DETACH = 1, + DFU_IDLE = 2, + DFU_DNLOAD_SYNC = 3, + DFU_DNBUSY = 4, + DFU_DNLOAD_IDLE = 5, + DFU_MANIFEST_SYNC = 6, + DFU_MANIFEST = 7, + DFU_MANIFEST_WAIT_RESET = 8, + DFU_UPLOAD_IDLE = 9, + DFU_ERROR = 10, +} dfu_state_t; + +// DFU Status +typedef enum { + DFU_STATUS_OK = 0x00, + DFU_STATUS_ERR_TARGET = 0x01, + DFU_STATUS_ERR_FILE = 0x02, + DFU_STATUS_ERR_WRITE = 0x03, + DFU_STATUS_ERR_ERASE = 0x04, + DFU_STATUS_ERR_CHECK_ERASED = 0x05, + DFU_STATUS_ERR_PROG = 0x06, + DFU_STATUS_ERR_VERIFY = 0x07, + DFU_STATUS_ERR_ADDRESS = 0x08, + DFU_STATUS_ERR_NOTDONE = 0x09, + DFU_STATUS_ERR_FIRMWARE = 0x0A, + DFU_STATUS_ERR_VENDOR = 0x0B, + DFU_STATUS_ERR_USBR = 0x0C, + DFU_STATUS_ERR_POR = 0x0D, + DFU_STATUS_ERR_UNKNOWN = 0x0E, + DFU_STATUS_ERR_STALLEDPKT = 0x0F, +} dfu_status_t; + +#define DFU_ATTR_CAN_DOWNLOAD (1u << 0) +#define DFU_ATTR_CAN_UPLOAD (1u << 1) +#define DFU_ATTR_MANIFESTATION_TOLERANT (1u << 2) +#define DFU_ATTR_WILL_DETACH (1u << 3) + +// DFU Status Request Payload +typedef struct TU_ATTR_PACKED +{ + uint8_t bStatus; + uint8_t bwPollTimeout[3]; + uint8_t bState; + uint8_t iString; +} dfu_status_response_t; + +TU_VERIFY_STATIC( sizeof(dfu_status_response_t) == 6, "size is not correct"); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_DFU_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_device.c new file mode 100644 index 00000000..aa5891ca --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_device.c @@ -0,0 +1,460 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 XMOS LIMITED + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_DFU) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "dfu_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +typedef struct +{ + uint8_t attrs; + uint8_t alt; + + dfu_state_t state; + dfu_status_t status; + + bool flashing_in_progress; + uint16_t block; + uint16_t length; + + CFG_TUSB_MEM_ALIGN uint8_t transfer_buf[CFG_TUD_DFU_XFER_BUFSIZE]; +} dfu_state_ctx_t; + +// Only a single dfu state is allowed +CFG_TUSB_MEM_SECTION static dfu_state_ctx_t _dfu_ctx; + +static void reset_state(void) +{ + _dfu_ctx.state = DFU_IDLE; + _dfu_ctx.status = DFU_STATUS_OK; + _dfu_ctx.flashing_in_progress = false; +} + +static bool reply_getstatus(uint8_t rhport, tusb_control_request_t const * request, dfu_state_t state, dfu_status_t status, uint32_t timeout); +static bool process_download_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + +//--------------------------------------------------------------------+ +// Debug +//--------------------------------------------------------------------+ +#if CFG_TUSB_DEBUG >= 2 + +static tu_lookup_entry_t const _dfu_request_lookup[] = +{ + { .key = DFU_REQUEST_DETACH , .data = "DETACH" }, + { .key = DFU_REQUEST_DNLOAD , .data = "DNLOAD" }, + { .key = DFU_REQUEST_UPLOAD , .data = "UPLOAD" }, + { .key = DFU_REQUEST_GETSTATUS , .data = "GETSTATUS" }, + { .key = DFU_REQUEST_CLRSTATUS , .data = "CLRSTATUS" }, + { .key = DFU_REQUEST_GETSTATE , .data = "GETSTATE" }, + { .key = DFU_REQUEST_ABORT , .data = "ABORT" }, +}; + +static tu_lookup_table_t const _dfu_request_table = +{ + .count = TU_ARRAY_SIZE(_dfu_request_lookup), + .items = _dfu_request_lookup +}; + +static tu_lookup_entry_t const _dfu_state_lookup[] = +{ + { .key = APP_IDLE , .data = "APP_IDLE" }, + { .key = APP_DETACH , .data = "APP_DETACH" }, + { .key = DFU_IDLE , .data = "IDLE" }, + { .key = DFU_DNLOAD_SYNC , .data = "DNLOAD_SYNC" }, + { .key = DFU_DNBUSY , .data = "DNBUSY" }, + { .key = DFU_DNLOAD_IDLE , .data = "DNLOAD_IDLE" }, + { .key = DFU_MANIFEST_SYNC , .data = "MANIFEST_SYNC" }, + { .key = DFU_MANIFEST , .data = "MANIFEST" }, + { .key = DFU_MANIFEST_WAIT_RESET , .data = "MANIFEST_WAIT_RESET" }, + { .key = DFU_UPLOAD_IDLE , .data = "UPLOAD_IDLE" }, + { .key = DFU_ERROR , .data = "ERROR" }, +}; + +static tu_lookup_table_t const _dfu_state_table = +{ + .count = TU_ARRAY_SIZE(_dfu_state_lookup), + .items = _dfu_state_lookup +}; + +static tu_lookup_entry_t const _dfu_status_lookup[] = +{ + { .key = DFU_STATUS_OK , .data = "OK" }, + { .key = DFU_STATUS_ERR_TARGET , .data = "errTARGET" }, + { .key = DFU_STATUS_ERR_FILE , .data = "errFILE" }, + { .key = DFU_STATUS_ERR_WRITE , .data = "errWRITE" }, + { .key = DFU_STATUS_ERR_ERASE , .data = "errERASE" }, + { .key = DFU_STATUS_ERR_CHECK_ERASED , .data = "errCHECK_ERASED" }, + { .key = DFU_STATUS_ERR_PROG , .data = "errPROG" }, + { .key = DFU_STATUS_ERR_VERIFY , .data = "errVERIFY" }, + { .key = DFU_STATUS_ERR_ADDRESS , .data = "errADDRESS" }, + { .key = DFU_STATUS_ERR_NOTDONE , .data = "errNOTDONE" }, + { .key = DFU_STATUS_ERR_FIRMWARE , .data = "errFIRMWARE" }, + { .key = DFU_STATUS_ERR_VENDOR , .data = "errVENDOR" }, + { .key = DFU_STATUS_ERR_USBR , .data = "errUSBR" }, + { .key = DFU_STATUS_ERR_POR , .data = "errPOR" }, + { .key = DFU_STATUS_ERR_UNKNOWN , .data = "errUNKNOWN" }, + { .key = DFU_STATUS_ERR_STALLEDPKT , .data = "errSTALLEDPKT" }, +}; + +static tu_lookup_table_t const _dfu_status_table = +{ + .count = TU_ARRAY_SIZE(_dfu_status_lookup), + .items = _dfu_status_lookup +}; + +#endif + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void dfu_moded_reset(uint8_t rhport) +{ + (void) rhport; + + _dfu_ctx.attrs = 0; + _dfu_ctx.alt = 0; + + reset_state(); +} + +void dfu_moded_init(void) +{ + dfu_moded_reset(0); +} + +uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + (void) rhport; + + //------------- Interface (with Alt) descriptor -------------// + uint8_t const itf_num = itf_desc->bInterfaceNumber; + uint8_t alt_count = 0; + + uint16_t drv_len = 0; + TU_VERIFY(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS && itf_desc->bInterfaceProtocol == DFU_PROTOCOL_DFU, 0); + + while(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS && itf_desc->bInterfaceProtocol == DFU_PROTOCOL_DFU) + { + TU_ASSERT(max_len > drv_len, 0); + + // Alternate must have the same interface number + TU_ASSERT(itf_desc->bInterfaceNumber == itf_num, 0); + + // Alt should increase by one every time + TU_ASSERT(itf_desc->bAlternateSetting == alt_count, 0); + alt_count++; + + drv_len += tu_desc_len(itf_desc); + itf_desc = (tusb_desc_interface_t const *) tu_desc_next(itf_desc); + } + + //------------- DFU Functional descriptor -------------// + tusb_desc_dfu_functional_t const *func_desc = (tusb_desc_dfu_functional_t const *) itf_desc; + TU_ASSERT(tu_desc_type(func_desc) == TUSB_DESC_FUNCTIONAL, 0); + drv_len += sizeof(tusb_desc_dfu_functional_t); + + _dfu_ctx.attrs = func_desc->bAttributes; + + // CFG_TUD_DFU_XFER_BUFSIZE has to be set to the buffer size used in TUD_DFU_DESCRIPTOR + uint16_t const transfer_size = tu_le16toh( tu_unaligned_read16((uint8_t const*) func_desc + offsetof(tusb_desc_dfu_functional_t, wTransferSize)) ); + TU_ASSERT(transfer_size <= CFG_TUD_DFU_XFER_BUFSIZE, drv_len); + + return drv_len; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); + + TU_LOG2(" DFU State : %s, Status: %s\r\n", tu_lookup_find(&_dfu_state_table, _dfu_ctx.state), tu_lookup_find(&_dfu_status_table, _dfu_ctx.status)); + + if ( request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD ) + { + // Standard request include GET/SET_INTERFACE + switch ( request->bRequest ) + { + case TUSB_REQ_SET_INTERFACE: + if ( stage == CONTROL_STAGE_SETUP ) + { + // Switch Alt interface and reset state machine + _dfu_ctx.alt = (uint8_t) request->wValue; + reset_state(); + return tud_control_status(rhport, request); + } + break; + + case TUSB_REQ_GET_INTERFACE: + if(stage == CONTROL_STAGE_SETUP) + { + return tud_control_xfer(rhport, request, &_dfu_ctx.alt, 1); + } + break; + + // unsupported request + default: return false; + } + } + else if ( request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS ) + { + TU_LOG2(" DFU Request: %s\r\n", tu_lookup_find(&_dfu_request_table, request->bRequest)); + + // Class request + switch ( request->bRequest ) + { + case DFU_REQUEST_DETACH: + if ( stage == CONTROL_STAGE_SETUP ) + { + tud_control_status(rhport, request); + } + else if ( stage == CONTROL_STAGE_ACK ) + { + if ( tud_dfu_detach_cb ) tud_dfu_detach_cb(); + } + break; + + case DFU_REQUEST_CLRSTATUS: + if ( stage == CONTROL_STAGE_SETUP ) + { + reset_state(); + tud_control_status(rhport, request); + } + break; + + case DFU_REQUEST_GETSTATE: + if ( stage == CONTROL_STAGE_SETUP ) + { + tud_control_xfer(rhport, request, &_dfu_ctx.state, 1); + } + break; + + case DFU_REQUEST_ABORT: + if ( stage == CONTROL_STAGE_SETUP ) + { + reset_state(); + tud_control_status(rhport, request); + } + else if ( stage == CONTROL_STAGE_ACK ) + { + if ( tud_dfu_abort_cb ) tud_dfu_abort_cb(_dfu_ctx.alt); + } + break; + + case DFU_REQUEST_UPLOAD: + if ( stage == CONTROL_STAGE_SETUP ) + { + TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_UPLOAD); + TU_VERIFY(tud_dfu_upload_cb); + TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE); + + uint16_t const xfer_len = tud_dfu_upload_cb(_dfu_ctx.alt, request->wValue, _dfu_ctx.transfer_buf, request->wLength); + + return tud_control_xfer(rhport, request, _dfu_ctx.transfer_buf, xfer_len); + } + break; + + case DFU_REQUEST_DNLOAD: + if ( stage == CONTROL_STAGE_SETUP ) + { + TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_DOWNLOAD); + TU_VERIFY(_dfu_ctx.state == DFU_IDLE || _dfu_ctx.state == DFU_DNLOAD_IDLE); + TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE); + + // set to true for both download and manifest + _dfu_ctx.flashing_in_progress = true; + + // save block and length for flashing + _dfu_ctx.block = request->wValue; + _dfu_ctx.length = request->wLength; + + if ( request->wLength ) + { + // Download with payload -> transition to DOWNLOAD SYNC + _dfu_ctx.state = DFU_DNLOAD_SYNC; + return tud_control_xfer(rhport, request, _dfu_ctx.transfer_buf, request->wLength); + } + else + { + // Download is complete -> transition to MANIFEST SYNC + _dfu_ctx.state = DFU_MANIFEST_SYNC; + return tud_control_status(rhport, request); + } + } + break; + + case DFU_REQUEST_GETSTATUS: + switch ( _dfu_ctx.state ) + { + case DFU_DNLOAD_SYNC: + return process_download_get_status(rhport, stage, request); + break; + + case DFU_MANIFEST_SYNC: + return process_manifest_get_status(rhport, stage, request); + break; + + default: + if ( stage == CONTROL_STAGE_SETUP ) return reply_getstatus(rhport, request, _dfu_ctx.state, _dfu_ctx.status, 0); + break; + } + break; + + default: return false; // stall unsupported request + } + }else + { + return false; // unsupported request + } + + return true; +} + +void tud_dfu_finish_flashing(uint8_t status) +{ + _dfu_ctx.flashing_in_progress = false; + + if ( status == DFU_STATUS_OK ) + { + if (_dfu_ctx.state == DFU_DNBUSY) + { + _dfu_ctx.state = DFU_DNLOAD_SYNC; + } + else if (_dfu_ctx.state == DFU_MANIFEST) + { + _dfu_ctx.state = (_dfu_ctx.attrs & DFU_ATTR_MANIFESTATION_TOLERANT) + ? DFU_MANIFEST_SYNC : DFU_MANIFEST_WAIT_RESET; + } + } + else + { + // failed while flashing, move to dfuError + _dfu_ctx.state = DFU_ERROR; + _dfu_ctx.status = (dfu_status_t)status; + } +} + +static bool process_download_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if ( stage == CONTROL_STAGE_SETUP ) + { + // only transition to next state on CONTROL_STAGE_ACK + dfu_state_t next_state; + uint32_t timeout; + + if ( _dfu_ctx.flashing_in_progress ) + { + next_state = DFU_DNBUSY; + timeout = tud_dfu_get_timeout_cb(_dfu_ctx.alt, (uint8_t) next_state); + } + else + { + next_state = DFU_DNLOAD_IDLE; + timeout = 0; + } + + return reply_getstatus(rhport, request, next_state, _dfu_ctx.status, timeout); + } + else if ( stage == CONTROL_STAGE_ACK ) + { + if ( _dfu_ctx.flashing_in_progress ) + { + _dfu_ctx.state = DFU_DNBUSY; + tud_dfu_download_cb(_dfu_ctx.alt, _dfu_ctx.block, _dfu_ctx.transfer_buf, _dfu_ctx.length); + }else + { + _dfu_ctx.state = DFU_DNLOAD_IDLE; + } + } + + return true; +} + +static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if ( stage == CONTROL_STAGE_SETUP ) + { + // only transition to next state on CONTROL_STAGE_ACK + dfu_state_t next_state; + uint32_t timeout; + + if ( _dfu_ctx.flashing_in_progress ) + { + next_state = DFU_MANIFEST; + timeout = tud_dfu_get_timeout_cb(_dfu_ctx.alt, next_state); + } + else + { + next_state = DFU_IDLE; + timeout = 0; + } + + return reply_getstatus(rhport, request, next_state, _dfu_ctx.status, timeout); + } + else if ( stage == CONTROL_STAGE_ACK ) + { + if ( _dfu_ctx.flashing_in_progress ) + { + _dfu_ctx.state = DFU_MANIFEST; + tud_dfu_manifest_cb(_dfu_ctx.alt); + } + else + { + _dfu_ctx.state = DFU_IDLE; + } + } + + return true; +} + +static bool reply_getstatus(uint8_t rhport, tusb_control_request_t const * request, dfu_state_t state, dfu_status_t status, uint32_t timeout) +{ + dfu_status_response_t resp; + resp.bStatus = (uint8_t) status; + resp.bwPollTimeout[0] = TU_U32_BYTE0(timeout); + resp.bwPollTimeout[1] = TU_U32_BYTE1(timeout); + resp.bwPollTimeout[2] = TU_U32_BYTE2(timeout); + resp.bState = (uint8_t) state; + resp.iString = 0; + + return tud_control_xfer(rhport, request, &resp, sizeof(dfu_status_response_t)); +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_device.h new file mode 100644 index 00000000..fecf8596 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_device.h @@ -0,0 +1,98 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 XMOS LIMITED + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_DFU_DEVICE_H_ +#define _TUSB_DFU_DEVICE_H_ + +#include "dfu.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Class Driver Default Configure & Validation +//--------------------------------------------------------------------+ + +#if !defined(CFG_TUD_DFU_XFER_BUFSIZE) + #error "CFG_TUD_DFU_XFER_BUFSIZE must be defined, it has to be set to the buffer size used in TUD_DFU_DESCRIPTOR" +#endif + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + +// Must be called when the application is done with flashing started by +// tud_dfu_download_cb() and tud_dfu_manifest_cb(). +// status is DFU_STATUS_OK if successful, any other error status will cause state to enter dfuError +void tud_dfu_finish_flashing(uint8_t status); + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ + +// Note: alt is used as the partition number, in order to support multiple partitions like FLASH, EEPROM, etc. + +// Invoked right before tud_dfu_download_cb() (state=DFU_DNBUSY) or tud_dfu_manifest_cb() (state=DFU_MANIFEST) +// Application return timeout in milliseconds (bwPollTimeout) for the next download/manifest operation. +// During this period, USB host won't try to communicate with us. +uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state); + +// Invoked when received DFU_DNLOAD (wLength>0) following by DFU_GETSTATUS (state=DFU_DNBUSY) requests +// This callback could be returned before flashing op is complete (async). +// Once finished flashing, application must call tud_dfu_finish_flashing() +void tud_dfu_download_cb (uint8_t alt, uint16_t block_num, uint8_t const *data, uint16_t length); + +// Invoked when download process is complete, received DFU_DNLOAD (wLength=0) following by DFU_GETSTATUS (state=Manifest) +// Application can do checksum, or actual flashing if buffered entire image previously. +// Once finished flashing, application must call tud_dfu_finish_flashing() +void tud_dfu_manifest_cb(uint8_t alt); + +// Invoked when received DFU_UPLOAD request +// Application must populate data with up to length bytes and +// Return the number of written bytes +TU_ATTR_WEAK uint16_t tud_dfu_upload_cb(uint8_t alt, uint16_t block_num, uint8_t* data, uint16_t length); + +// Invoked when a DFU_DETACH request is received +TU_ATTR_WEAK void tud_dfu_detach_cb(void); + +// Invoked when the Host has terminated a download or upload transfer +TU_ATTR_WEAK void tud_dfu_abort_cb(uint8_t alt); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void dfu_moded_init(void); +void dfu_moded_reset(uint8_t rhport); +uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_DFU_MODE_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c new file mode 100644 index 00000000..b9cd6096 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c @@ -0,0 +1,128 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Sylvain Munaut + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_DFU_RUNTIME) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "dfu_rt_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void dfu_rtd_init(void) +{ +} + +void dfu_rtd_reset(uint8_t rhport) +{ + (void) rhport; +} + +uint16_t dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + (void) rhport; + (void) max_len; + + // Ensure this is DFU Runtime + TU_VERIFY((itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS) && + (itf_desc->bInterfaceProtocol == DFU_PROTOCOL_RT), 0); + + uint8_t const * p_desc = tu_desc_next( itf_desc ); + uint16_t drv_len = sizeof(tusb_desc_interface_t); + + if ( TUSB_DESC_FUNCTIONAL == tu_desc_type(p_desc) ) + { + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + return drv_len; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + // nothing to do with DATA or ACK stage + if ( stage != CONTROL_STAGE_SETUP ) return true; + + TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); + + // dfu-util will try to claim the interface with SET_INTERFACE request before sending DFU request + if ( TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type && + TUSB_REQ_SET_INTERFACE == request->bRequest ) + { + tud_control_status(rhport, request); + return true; + } + + // Handle class request only from here + TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); + + switch (request->bRequest) + { + case DFU_REQUEST_DETACH: + { + TU_LOG2(" DFU RT Request: DETACH\r\n"); + tud_control_status(rhport, request); + tud_dfu_runtime_reboot_to_dfu_cb(); + } + break; + + case DFU_REQUEST_GETSTATUS: + { + TU_LOG2(" DFU RT Request: GETSTATUS\r\n"); + dfu_status_response_t resp; + // Status = OK, Poll timeout is ignored during RT, State = APP_IDLE, IString = 0 + memset(&resp, 0x00, sizeof(dfu_status_response_t)); + tud_control_xfer(rhport, request, &resp, sizeof(dfu_status_response_t)); + } + break; + + default: + { + TU_LOG2(" DFU RT Unexpected Request: %d\r\n", request->bRequest); + return false; // stall unsupported request + } + } + + return true; +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.h new file mode 100644 index 00000000..babaa821 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.h @@ -0,0 +1,54 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Sylvain Munaut + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_DFU_RT_DEVICE_H_ +#define _TUSB_DFU_RT_DEVICE_H_ + +#include "dfu.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ +// Invoked when a DFU_DETACH request is received and bitWillDetach is set +void tud_dfu_runtime_reboot_to_dfu_cb(void); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void dfu_rtd_init(void); +void dfu_rtd_reset(uint8_t rhport); +uint16_t dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_DFU_RT_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid.h b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid.h new file mode 100644 index 00000000..44a464be --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid.h @@ -0,0 +1,1122 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup group_class + * \defgroup ClassDriver_HID Human Interface Device (HID) + * @{ */ + +#ifndef _TUSB_HID_H_ +#define _TUSB_HID_H_ + +#include "common/tusb_common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Common Definitions +//--------------------------------------------------------------------+ +/** \defgroup ClassDriver_HID_Common Common Definitions + * @{ */ + +/// USB HID Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength; /**< Numeric expression that is the total size of the HID descriptor */ + uint8_t bDescriptorType; /**< Constant name specifying type of HID descriptor. */ + + uint16_t bcdHID; /**< Numeric expression identifying the HID Class Specification release */ + uint8_t bCountryCode; /**< Numeric expression identifying country code of the localized hardware. */ + uint8_t bNumDescriptors; /**< Numeric expression specifying the number of class descriptors */ + + uint8_t bReportType; /**< Type of HID class report. */ + uint16_t wReportLength; /**< the total size of the Report descriptor. */ +} tusb_hid_descriptor_hid_t; + +/// HID Subclass +typedef enum +{ + HID_SUBCLASS_NONE = 0, ///< No Subclass + HID_SUBCLASS_BOOT = 1 ///< Boot Interface Subclass +}hid_subclass_enum_t; + +/// HID Interface Protocol +typedef enum +{ + HID_ITF_PROTOCOL_NONE = 0, ///< None + HID_ITF_PROTOCOL_KEYBOARD = 1, ///< Keyboard + HID_ITF_PROTOCOL_MOUSE = 2 ///< Mouse +}hid_interface_protocol_enum_t; + +/// HID Descriptor Type +typedef enum +{ + HID_DESC_TYPE_HID = 0x21, ///< HID Descriptor + HID_DESC_TYPE_REPORT = 0x22, ///< Report Descriptor + HID_DESC_TYPE_PHYSICAL = 0x23 ///< Physical Descriptor +}hid_descriptor_enum_t; + +/// HID Request Report Type +typedef enum +{ + HID_REPORT_TYPE_INVALID = 0, + HID_REPORT_TYPE_INPUT, ///< Input + HID_REPORT_TYPE_OUTPUT, ///< Output + HID_REPORT_TYPE_FEATURE ///< Feature +}hid_report_type_t; + +/// HID Class Specific Control Request +typedef enum +{ + HID_REQ_CONTROL_GET_REPORT = 0x01, ///< Get Report + HID_REQ_CONTROL_GET_IDLE = 0x02, ///< Get Idle + HID_REQ_CONTROL_GET_PROTOCOL = 0x03, ///< Get Protocol + HID_REQ_CONTROL_SET_REPORT = 0x09, ///< Set Report + HID_REQ_CONTROL_SET_IDLE = 0x0a, ///< Set Idle + HID_REQ_CONTROL_SET_PROTOCOL = 0x0b ///< Set Protocol +}hid_request_enum_t; + +/// HID Local Code +typedef enum +{ + HID_LOCAL_NotSupported = 0 , ///< NotSupported + HID_LOCAL_Arabic , ///< Arabic + HID_LOCAL_Belgian , ///< Belgian + HID_LOCAL_Canadian_Bilingual , ///< Canadian_Bilingual + HID_LOCAL_Canadian_French , ///< Canadian_French + HID_LOCAL_Czech_Republic , ///< Czech_Republic + HID_LOCAL_Danish , ///< Danish + HID_LOCAL_Finnish , ///< Finnish + HID_LOCAL_French , ///< French + HID_LOCAL_German , ///< German + HID_LOCAL_Greek , ///< Greek + HID_LOCAL_Hebrew , ///< Hebrew + HID_LOCAL_Hungary , ///< Hungary + HID_LOCAL_International , ///< International + HID_LOCAL_Italian , ///< Italian + HID_LOCAL_Japan_Katakana , ///< Japan_Katakana + HID_LOCAL_Korean , ///< Korean + HID_LOCAL_Latin_American , ///< Latin_American + HID_LOCAL_Netherlands_Dutch , ///< Netherlands/Dutch + HID_LOCAL_Norwegian , ///< Norwegian + HID_LOCAL_Persian_Farsi , ///< Persian (Farsi) + HID_LOCAL_Poland , ///< Poland + HID_LOCAL_Portuguese , ///< Portuguese + HID_LOCAL_Russia , ///< Russia + HID_LOCAL_Slovakia , ///< Slovakia + HID_LOCAL_Spanish , ///< Spanish + HID_LOCAL_Swedish , ///< Swedish + HID_LOCAL_Swiss_French , ///< Swiss/French + HID_LOCAL_Swiss_German , ///< Swiss/German + HID_LOCAL_Switzerland , ///< Switzerland + HID_LOCAL_Taiwan , ///< Taiwan + HID_LOCAL_Turkish_Q , ///< Turkish-Q + HID_LOCAL_UK , ///< UK + HID_LOCAL_US , ///< US + HID_LOCAL_Yugoslavia , ///< Yugoslavia + HID_LOCAL_Turkish_F ///< Turkish-F +} hid_local_enum_t; + +// HID protocol value used by GetProtocol / SetProtocol +typedef enum +{ + HID_PROTOCOL_BOOT = 0, + HID_PROTOCOL_REPORT = 1 +} hid_protocol_mode_enum_t; + +/** @} */ + +//--------------------------------------------------------------------+ +// GAMEPAD +//--------------------------------------------------------------------+ +/** \addtogroup ClassDriver_HID_Gamepad Gamepad + * @{ */ + +/* From https://www.kernel.org/doc/html/latest/input/gamepad.html + ____________________________ __ + / [__ZL__] [__ZR__] \ | + / [__ TL __] [__ TR __] \ | Front Triggers + __/________________________________\__ __| + / _ \ | + / /\ __ (N) \ | + / || __ |MO| __ _ _ \ | Main Pad + | <===DP===> |SE| |ST| (W) -|- (E) | | + \ || ___ ___ _ / | + /\ \/ / \ / \ (S) /\ __| + / \________ | LS | ____ | RS | ________/ \ | +| / \ \___/ / \ \___/ / \ | | Control Sticks +| / \_____/ \_____/ \ | __| +| / \ | + \_____/ \_____/ + + |________|______| |______|___________| + D-Pad Left Right Action Pad + Stick Stick + + |_____________| + Menu Pad + + Most gamepads have the following features: + - Action-Pad 4 buttons in diamonds-shape (on the right side) NORTH, SOUTH, WEST and EAST. + - D-Pad (Direction-pad) 4 buttons (on the left side) that point up, down, left and right. + - Menu-Pad Different constellations, but most-times 2 buttons: SELECT - START. + - Analog-Sticks provide freely moveable sticks to control directions, Analog-sticks may also + provide a digital button if you press them. + - Triggers are located on the upper-side of the pad in vertical direction. The upper buttons + are normally named Left- and Right-Triggers, the lower buttons Z-Left and Z-Right. + - Rumble Many devices provide force-feedback features. But are mostly just simple rumble motors. + */ + +/// HID Gamepad Protocol Report. +typedef struct TU_ATTR_PACKED +{ + int8_t x; ///< Delta x movement of left analog-stick + int8_t y; ///< Delta y movement of left analog-stick + int8_t z; ///< Delta z movement of right analog-joystick + int8_t rz; ///< Delta Rz movement of right analog-joystick + int8_t rx; ///< Delta Rx movement of analog left trigger + int8_t ry; ///< Delta Ry movement of analog right trigger + uint8_t hat; ///< Buttons mask for currently pressed buttons in the DPad/hat + uint32_t buttons; ///< Buttons mask for currently pressed buttons +}hid_gamepad_report_t; + +/// Standard Gamepad Buttons Bitmap +typedef enum +{ + GAMEPAD_BUTTON_0 = TU_BIT(0), + GAMEPAD_BUTTON_1 = TU_BIT(1), + GAMEPAD_BUTTON_2 = TU_BIT(2), + GAMEPAD_BUTTON_3 = TU_BIT(3), + GAMEPAD_BUTTON_4 = TU_BIT(4), + GAMEPAD_BUTTON_5 = TU_BIT(5), + GAMEPAD_BUTTON_6 = TU_BIT(6), + GAMEPAD_BUTTON_7 = TU_BIT(7), + GAMEPAD_BUTTON_8 = TU_BIT(8), + GAMEPAD_BUTTON_9 = TU_BIT(9), + GAMEPAD_BUTTON_10 = TU_BIT(10), + GAMEPAD_BUTTON_11 = TU_BIT(11), + GAMEPAD_BUTTON_12 = TU_BIT(12), + GAMEPAD_BUTTON_13 = TU_BIT(13), + GAMEPAD_BUTTON_14 = TU_BIT(14), + GAMEPAD_BUTTON_15 = TU_BIT(15), + GAMEPAD_BUTTON_16 = TU_BIT(16), + GAMEPAD_BUTTON_17 = TU_BIT(17), + GAMEPAD_BUTTON_18 = TU_BIT(18), + GAMEPAD_BUTTON_19 = TU_BIT(19), + GAMEPAD_BUTTON_20 = TU_BIT(20), + GAMEPAD_BUTTON_21 = TU_BIT(21), + GAMEPAD_BUTTON_22 = TU_BIT(22), + GAMEPAD_BUTTON_23 = TU_BIT(23), + GAMEPAD_BUTTON_24 = TU_BIT(24), + GAMEPAD_BUTTON_25 = TU_BIT(25), + GAMEPAD_BUTTON_26 = TU_BIT(26), + GAMEPAD_BUTTON_27 = TU_BIT(27), + GAMEPAD_BUTTON_28 = TU_BIT(28), + GAMEPAD_BUTTON_29 = TU_BIT(29), + GAMEPAD_BUTTON_30 = TU_BIT(30), + GAMEPAD_BUTTON_31 = TU_BIT(31), +}hid_gamepad_button_bm_t; + +/// Standard Gamepad Buttons Naming from Linux input event codes +/// https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h +#define GAMEPAD_BUTTON_A GAMEPAD_BUTTON_0 +#define GAMEPAD_BUTTON_SOUTH GAMEPAD_BUTTON_0 + +#define GAMEPAD_BUTTON_B GAMEPAD_BUTTON_1 +#define GAMEPAD_BUTTON_EAST GAMEPAD_BUTTON_1 + +#define GAMEPAD_BUTTON_C GAMEPAD_BUTTON_2 + +#define GAMEPAD_BUTTON_X GAMEPAD_BUTTON_3 +#define GAMEPAD_BUTTON_NORTH GAMEPAD_BUTTON_3 + +#define GAMEPAD_BUTTON_Y GAMEPAD_BUTTON_4 +#define GAMEPAD_BUTTON_WEST GAMEPAD_BUTTON_4 + +#define GAMEPAD_BUTTON_Z GAMEPAD_BUTTON_5 +#define GAMEPAD_BUTTON_TL GAMEPAD_BUTTON_6 +#define GAMEPAD_BUTTON_TR GAMEPAD_BUTTON_7 +#define GAMEPAD_BUTTON_TL2 GAMEPAD_BUTTON_8 +#define GAMEPAD_BUTTON_TR2 GAMEPAD_BUTTON_9 +#define GAMEPAD_BUTTON_SELECT GAMEPAD_BUTTON_10 +#define GAMEPAD_BUTTON_START GAMEPAD_BUTTON_11 +#define GAMEPAD_BUTTON_MODE GAMEPAD_BUTTON_12 +#define GAMEPAD_BUTTON_THUMBL GAMEPAD_BUTTON_13 +#define GAMEPAD_BUTTON_THUMBR GAMEPAD_BUTTON_14 + +/// Standard Gamepad HAT/DPAD Buttons (from Linux input event codes) +typedef enum +{ + GAMEPAD_HAT_CENTERED = 0, ///< DPAD_CENTERED + GAMEPAD_HAT_UP = 1, ///< DPAD_UP + GAMEPAD_HAT_UP_RIGHT = 2, ///< DPAD_UP_RIGHT + GAMEPAD_HAT_RIGHT = 3, ///< DPAD_RIGHT + GAMEPAD_HAT_DOWN_RIGHT = 4, ///< DPAD_DOWN_RIGHT + GAMEPAD_HAT_DOWN = 5, ///< DPAD_DOWN + GAMEPAD_HAT_DOWN_LEFT = 6, ///< DPAD_DOWN_LEFT + GAMEPAD_HAT_LEFT = 7, ///< DPAD_LEFT + GAMEPAD_HAT_UP_LEFT = 8, ///< DPAD_UP_LEFT +}hid_gamepad_hat_t; + +/// @} + +//--------------------------------------------------------------------+ +// MOUSE +//--------------------------------------------------------------------+ +/** \addtogroup ClassDriver_HID_Mouse Mouse + * @{ */ + +/// Standard HID Boot Protocol Mouse Report. +typedef struct TU_ATTR_PACKED +{ + uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */ + int8_t x; /**< Current delta x movement of the mouse. */ + int8_t y; /**< Current delta y movement on the mouse. */ + int8_t wheel; /**< Current delta wheel movement on the mouse. */ + int8_t pan; // using AC Pan +} hid_mouse_report_t; + +/// Standard Mouse Buttons Bitmap +typedef enum +{ + MOUSE_BUTTON_LEFT = TU_BIT(0), ///< Left button + MOUSE_BUTTON_RIGHT = TU_BIT(1), ///< Right button + MOUSE_BUTTON_MIDDLE = TU_BIT(2), ///< Middle button + MOUSE_BUTTON_BACKWARD = TU_BIT(3), ///< Backward button, + MOUSE_BUTTON_FORWARD = TU_BIT(4), ///< Forward button, +}hid_mouse_button_bm_t; + +/// @} + +//--------------------------------------------------------------------+ +// Keyboard +//--------------------------------------------------------------------+ +/** \addtogroup ClassDriver_HID_Keyboard Keyboard + * @{ */ + +/// Standard HID Boot Protocol Keyboard Report. +typedef struct TU_ATTR_PACKED +{ + uint8_t modifier; /**< Keyboard modifier (KEYBOARD_MODIFIER_* masks). */ + uint8_t reserved; /**< Reserved for OEM use, always set to 0. */ + uint8_t keycode[6]; /**< Key codes of the currently pressed keys. */ +} hid_keyboard_report_t; + +/// Keyboard modifier codes bitmap +typedef enum +{ + KEYBOARD_MODIFIER_LEFTCTRL = TU_BIT(0), ///< Left Control + KEYBOARD_MODIFIER_LEFTSHIFT = TU_BIT(1), ///< Left Shift + KEYBOARD_MODIFIER_LEFTALT = TU_BIT(2), ///< Left Alt + KEYBOARD_MODIFIER_LEFTGUI = TU_BIT(3), ///< Left Window + KEYBOARD_MODIFIER_RIGHTCTRL = TU_BIT(4), ///< Right Control + KEYBOARD_MODIFIER_RIGHTSHIFT = TU_BIT(5), ///< Right Shift + KEYBOARD_MODIFIER_RIGHTALT = TU_BIT(6), ///< Right Alt + KEYBOARD_MODIFIER_RIGHTGUI = TU_BIT(7) ///< Right Window +}hid_keyboard_modifier_bm_t; + +typedef enum +{ + KEYBOARD_LED_NUMLOCK = TU_BIT(0), ///< Num Lock LED + KEYBOARD_LED_CAPSLOCK = TU_BIT(1), ///< Caps Lock LED + KEYBOARD_LED_SCROLLLOCK = TU_BIT(2), ///< Scroll Lock LED + KEYBOARD_LED_COMPOSE = TU_BIT(3), ///< Composition Mode + KEYBOARD_LED_KANA = TU_BIT(4) ///< Kana mode +}hid_keyboard_led_bm_t; + +/// @} + +//--------------------------------------------------------------------+ +// HID KEYCODE +//--------------------------------------------------------------------+ +#define HID_KEY_NONE 0x00 +#define HID_KEY_A 0x04 +#define HID_KEY_B 0x05 +#define HID_KEY_C 0x06 +#define HID_KEY_D 0x07 +#define HID_KEY_E 0x08 +#define HID_KEY_F 0x09 +#define HID_KEY_G 0x0A +#define HID_KEY_H 0x0B +#define HID_KEY_I 0x0C +#define HID_KEY_J 0x0D +#define HID_KEY_K 0x0E +#define HID_KEY_L 0x0F +#define HID_KEY_M 0x10 +#define HID_KEY_N 0x11 +#define HID_KEY_O 0x12 +#define HID_KEY_P 0x13 +#define HID_KEY_Q 0x14 +#define HID_KEY_R 0x15 +#define HID_KEY_S 0x16 +#define HID_KEY_T 0x17 +#define HID_KEY_U 0x18 +#define HID_KEY_V 0x19 +#define HID_KEY_W 0x1A +#define HID_KEY_X 0x1B +#define HID_KEY_Y 0x1C +#define HID_KEY_Z 0x1D +#define HID_KEY_1 0x1E +#define HID_KEY_2 0x1F +#define HID_KEY_3 0x20 +#define HID_KEY_4 0x21 +#define HID_KEY_5 0x22 +#define HID_KEY_6 0x23 +#define HID_KEY_7 0x24 +#define HID_KEY_8 0x25 +#define HID_KEY_9 0x26 +#define HID_KEY_0 0x27 +#define HID_KEY_ENTER 0x28 +#define HID_KEY_ESCAPE 0x29 +#define HID_KEY_BACKSPACE 0x2A +#define HID_KEY_TAB 0x2B +#define HID_KEY_SPACE 0x2C +#define HID_KEY_MINUS 0x2D +#define HID_KEY_EQUAL 0x2E +#define HID_KEY_BRACKET_LEFT 0x2F +#define HID_KEY_BRACKET_RIGHT 0x30 +#define HID_KEY_BACKSLASH 0x31 +#define HID_KEY_EUROPE_1 0x32 +#define HID_KEY_SEMICOLON 0x33 +#define HID_KEY_APOSTROPHE 0x34 +#define HID_KEY_GRAVE 0x35 +#define HID_KEY_COMMA 0x36 +#define HID_KEY_PERIOD 0x37 +#define HID_KEY_SLASH 0x38 +#define HID_KEY_CAPS_LOCK 0x39 +#define HID_KEY_F1 0x3A +#define HID_KEY_F2 0x3B +#define HID_KEY_F3 0x3C +#define HID_KEY_F4 0x3D +#define HID_KEY_F5 0x3E +#define HID_KEY_F6 0x3F +#define HID_KEY_F7 0x40 +#define HID_KEY_F8 0x41 +#define HID_KEY_F9 0x42 +#define HID_KEY_F10 0x43 +#define HID_KEY_F11 0x44 +#define HID_KEY_F12 0x45 +#define HID_KEY_PRINT_SCREEN 0x46 +#define HID_KEY_SCROLL_LOCK 0x47 +#define HID_KEY_PAUSE 0x48 +#define HID_KEY_INSERT 0x49 +#define HID_KEY_HOME 0x4A +#define HID_KEY_PAGE_UP 0x4B +#define HID_KEY_DELETE 0x4C +#define HID_KEY_END 0x4D +#define HID_KEY_PAGE_DOWN 0x4E +#define HID_KEY_ARROW_RIGHT 0x4F +#define HID_KEY_ARROW_LEFT 0x50 +#define HID_KEY_ARROW_DOWN 0x51 +#define HID_KEY_ARROW_UP 0x52 +#define HID_KEY_NUM_LOCK 0x53 +#define HID_KEY_KEYPAD_DIVIDE 0x54 +#define HID_KEY_KEYPAD_MULTIPLY 0x55 +#define HID_KEY_KEYPAD_SUBTRACT 0x56 +#define HID_KEY_KEYPAD_ADD 0x57 +#define HID_KEY_KEYPAD_ENTER 0x58 +#define HID_KEY_KEYPAD_1 0x59 +#define HID_KEY_KEYPAD_2 0x5A +#define HID_KEY_KEYPAD_3 0x5B +#define HID_KEY_KEYPAD_4 0x5C +#define HID_KEY_KEYPAD_5 0x5D +#define HID_KEY_KEYPAD_6 0x5E +#define HID_KEY_KEYPAD_7 0x5F +#define HID_KEY_KEYPAD_8 0x60 +#define HID_KEY_KEYPAD_9 0x61 +#define HID_KEY_KEYPAD_0 0x62 +#define HID_KEY_KEYPAD_DECIMAL 0x63 +#define HID_KEY_EUROPE_2 0x64 +#define HID_KEY_APPLICATION 0x65 +#define HID_KEY_POWER 0x66 +#define HID_KEY_KEYPAD_EQUAL 0x67 +#define HID_KEY_F13 0x68 +#define HID_KEY_F14 0x69 +#define HID_KEY_F15 0x6A +#define HID_KEY_F16 0x6B +#define HID_KEY_F17 0x6C +#define HID_KEY_F18 0x6D +#define HID_KEY_F19 0x6E +#define HID_KEY_F20 0x6F +#define HID_KEY_F21 0x70 +#define HID_KEY_F22 0x71 +#define HID_KEY_F23 0x72 +#define HID_KEY_F24 0x73 +#define HID_KEY_EXECUTE 0x74 +#define HID_KEY_HELP 0x75 +#define HID_KEY_MENU 0x76 +#define HID_KEY_SELECT 0x77 +#define HID_KEY_STOP 0x78 +#define HID_KEY_AGAIN 0x79 +#define HID_KEY_UNDO 0x7A +#define HID_KEY_CUT 0x7B +#define HID_KEY_COPY 0x7C +#define HID_KEY_PASTE 0x7D +#define HID_KEY_FIND 0x7E +#define HID_KEY_MUTE 0x7F +#define HID_KEY_VOLUME_UP 0x80 +#define HID_KEY_VOLUME_DOWN 0x81 +#define HID_KEY_LOCKING_CAPS_LOCK 0x82 +#define HID_KEY_LOCKING_NUM_LOCK 0x83 +#define HID_KEY_LOCKING_SCROLL_LOCK 0x84 +#define HID_KEY_KEYPAD_COMMA 0x85 +#define HID_KEY_KEYPAD_EQUAL_SIGN 0x86 +#define HID_KEY_KANJI1 0x87 +#define HID_KEY_KANJI2 0x88 +#define HID_KEY_KANJI3 0x89 +#define HID_KEY_KANJI4 0x8A +#define HID_KEY_KANJI5 0x8B +#define HID_KEY_KANJI6 0x8C +#define HID_KEY_KANJI7 0x8D +#define HID_KEY_KANJI8 0x8E +#define HID_KEY_KANJI9 0x8F +#define HID_KEY_LANG1 0x90 +#define HID_KEY_LANG2 0x91 +#define HID_KEY_LANG3 0x92 +#define HID_KEY_LANG4 0x93 +#define HID_KEY_LANG5 0x94 +#define HID_KEY_LANG6 0x95 +#define HID_KEY_LANG7 0x96 +#define HID_KEY_LANG8 0x97 +#define HID_KEY_LANG9 0x98 +#define HID_KEY_ALTERNATE_ERASE 0x99 +#define HID_KEY_SYSREQ_ATTENTION 0x9A +#define HID_KEY_CANCEL 0x9B +#define HID_KEY_CLEAR 0x9C +#define HID_KEY_PRIOR 0x9D +#define HID_KEY_RETURN 0x9E +#define HID_KEY_SEPARATOR 0x9F +#define HID_KEY_OUT 0xA0 +#define HID_KEY_OPER 0xA1 +#define HID_KEY_CLEAR_AGAIN 0xA2 +#define HID_KEY_CRSEL_PROPS 0xA3 +#define HID_KEY_EXSEL 0xA4 +// RESERVED 0xA5-DF +#define HID_KEY_CONTROL_LEFT 0xE0 +#define HID_KEY_SHIFT_LEFT 0xE1 +#define HID_KEY_ALT_LEFT 0xE2 +#define HID_KEY_GUI_LEFT 0xE3 +#define HID_KEY_CONTROL_RIGHT 0xE4 +#define HID_KEY_SHIFT_RIGHT 0xE5 +#define HID_KEY_ALT_RIGHT 0xE6 +#define HID_KEY_GUI_RIGHT 0xE7 + + +//--------------------------------------------------------------------+ +// REPORT DESCRIPTOR +//--------------------------------------------------------------------+ + +//------------- ITEM & TAG -------------// +#define HID_REPORT_DATA_0(data) +#define HID_REPORT_DATA_1(data) , data +#define HID_REPORT_DATA_2(data) , U16_TO_U8S_LE(data) +#define HID_REPORT_DATA_3(data) , U32_TO_U8S_LE(data) + +#define HID_REPORT_ITEM(data, tag, type, size) \ + (((tag) << 4) | ((type) << 2) | (size)) HID_REPORT_DATA_##size(data) + +// Report Item Types +enum { + RI_TYPE_MAIN = 0, + RI_TYPE_GLOBAL = 1, + RI_TYPE_LOCAL = 2 +}; + +//------------- Main Items - HID 1.11 section 6.2.2.4 -------------// + +// Report Item Main group +enum { + RI_MAIN_INPUT = 8, + RI_MAIN_OUTPUT = 9, + RI_MAIN_COLLECTION = 10, + RI_MAIN_FEATURE = 11, + RI_MAIN_COLLECTION_END = 12 +}; + +#define HID_INPUT(x) HID_REPORT_ITEM(x, RI_MAIN_INPUT , RI_TYPE_MAIN, 1) +#define HID_OUTPUT(x) HID_REPORT_ITEM(x, RI_MAIN_OUTPUT , RI_TYPE_MAIN, 1) +#define HID_COLLECTION(x) HID_REPORT_ITEM(x, RI_MAIN_COLLECTION , RI_TYPE_MAIN, 1) +#define HID_FEATURE(x) HID_REPORT_ITEM(x, RI_MAIN_FEATURE , RI_TYPE_MAIN, 1) +#define HID_COLLECTION_END HID_REPORT_ITEM(x, RI_MAIN_COLLECTION_END, RI_TYPE_MAIN, 0) + +//------------- Input, Output, Feature - HID 1.11 section 6.2.2.5 -------------// +#define HID_DATA (0<<0) +#define HID_CONSTANT (1<<0) + +#define HID_ARRAY (0<<1) +#define HID_VARIABLE (1<<1) + +#define HID_ABSOLUTE (0<<2) +#define HID_RELATIVE (1<<2) + +#define HID_WRAP_NO (0<<3) +#define HID_WRAP (1<<3) + +#define HID_LINEAR (0<<4) +#define HID_NONLINEAR (1<<4) + +#define HID_PREFERRED_STATE (0<<5) +#define HID_PREFERRED_NO (1<<5) + +#define HID_NO_NULL_POSITION (0<<6) +#define HID_NULL_STATE (1<<6) + +#define HID_NON_VOLATILE (0<<7) +#define HID_VOLATILE (1<<7) + +#define HID_BITFIELD (0<<8) +#define HID_BUFFERED_BYTES (1<<8) + +//------------- Collection Item - HID 1.11 section 6.2.2.6 -------------// +enum { + HID_COLLECTION_PHYSICAL = 0, + HID_COLLECTION_APPLICATION, + HID_COLLECTION_LOGICAL, + HID_COLLECTION_REPORT, + HID_COLLECTION_NAMED_ARRAY, + HID_COLLECTION_USAGE_SWITCH, + HID_COLLECTION_USAGE_MODIFIER +}; + +//------------- Global Items - HID 1.11 section 6.2.2.7 -------------// + +// Report Item Global group +enum { + RI_GLOBAL_USAGE_PAGE = 0, + RI_GLOBAL_LOGICAL_MIN = 1, + RI_GLOBAL_LOGICAL_MAX = 2, + RI_GLOBAL_PHYSICAL_MIN = 3, + RI_GLOBAL_PHYSICAL_MAX = 4, + RI_GLOBAL_UNIT_EXPONENT = 5, + RI_GLOBAL_UNIT = 6, + RI_GLOBAL_REPORT_SIZE = 7, + RI_GLOBAL_REPORT_ID = 8, + RI_GLOBAL_REPORT_COUNT = 9, + RI_GLOBAL_PUSH = 10, + RI_GLOBAL_POP = 11 +}; + +#define HID_USAGE_PAGE(x) HID_REPORT_ITEM(x, RI_GLOBAL_USAGE_PAGE, RI_TYPE_GLOBAL, 1) +#define HID_USAGE_PAGE_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_USAGE_PAGE, RI_TYPE_GLOBAL, n) + +#define HID_LOGICAL_MIN(x) HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MIN, RI_TYPE_GLOBAL, 1) +#define HID_LOGICAL_MIN_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MIN, RI_TYPE_GLOBAL, n) + +#define HID_LOGICAL_MAX(x) HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MAX, RI_TYPE_GLOBAL, 1) +#define HID_LOGICAL_MAX_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MAX, RI_TYPE_GLOBAL, n) + +#define HID_PHYSICAL_MIN(x) HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MIN, RI_TYPE_GLOBAL, 1) +#define HID_PHYSICAL_MIN_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MIN, RI_TYPE_GLOBAL, n) + +#define HID_PHYSICAL_MAX(x) HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MAX, RI_TYPE_GLOBAL, 1) +#define HID_PHYSICAL_MAX_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MAX, RI_TYPE_GLOBAL, n) + +#define HID_UNIT_EXPONENT(x) HID_REPORT_ITEM(x, RI_GLOBAL_UNIT_EXPONENT, RI_TYPE_GLOBAL, 1) +#define HID_UNIT_EXPONENT_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_UNIT_EXPONENT, RI_TYPE_GLOBAL, n) + +#define HID_UNIT(x) HID_REPORT_ITEM(x, RI_GLOBAL_UNIT, RI_TYPE_GLOBAL, 1) +#define HID_UNIT_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_UNIT, RI_TYPE_GLOBAL, n) + +#define HID_REPORT_SIZE(x) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_SIZE, RI_TYPE_GLOBAL, 1) +#define HID_REPORT_SIZE_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_SIZE, RI_TYPE_GLOBAL, n) + +#define HID_REPORT_ID(x) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_ID, RI_TYPE_GLOBAL, 1), +#define HID_REPORT_ID_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_ID, RI_TYPE_GLOBAL, n), + +#define HID_REPORT_COUNT(x) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_COUNT, RI_TYPE_GLOBAL, 1) +#define HID_REPORT_COUNT_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_COUNT, RI_TYPE_GLOBAL, n) + +#define HID_PUSH HID_REPORT_ITEM(x, RI_GLOBAL_PUSH, RI_TYPE_GLOBAL, 0) +#define HID_POP HID_REPORT_ITEM(x, RI_GLOBAL_POP, RI_TYPE_GLOBAL, 0) + +//------------- LOCAL ITEMS 6.2.2.8 -------------// + +enum { + RI_LOCAL_USAGE = 0, + RI_LOCAL_USAGE_MIN = 1, + RI_LOCAL_USAGE_MAX = 2, + RI_LOCAL_DESIGNATOR_INDEX = 3, + RI_LOCAL_DESIGNATOR_MIN = 4, + RI_LOCAL_DESIGNATOR_MAX = 5, + // 6 is reserved + RI_LOCAL_STRING_INDEX = 7, + RI_LOCAL_STRING_MIN = 8, + RI_LOCAL_STRING_MAX = 9, + RI_LOCAL_DELIMITER = 10, +}; + +#define HID_USAGE(x) HID_REPORT_ITEM(x, RI_LOCAL_USAGE, RI_TYPE_LOCAL, 1) +#define HID_USAGE_N(x, n) HID_REPORT_ITEM(x, RI_LOCAL_USAGE, RI_TYPE_LOCAL, n) + +#define HID_USAGE_MIN(x) HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MIN, RI_TYPE_LOCAL, 1) +#define HID_USAGE_MIN_N(x, n) HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MIN, RI_TYPE_LOCAL, n) + +#define HID_USAGE_MAX(x) HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MAX, RI_TYPE_LOCAL, 1) +#define HID_USAGE_MAX_N(x, n) HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MAX, RI_TYPE_LOCAL, n) + +//--------------------------------------------------------------------+ +// Usage Table +//--------------------------------------------------------------------+ + +/// HID Usage Table - Table 1: Usage Page Summary +enum { + HID_USAGE_PAGE_DESKTOP = 0x01, + HID_USAGE_PAGE_SIMULATE = 0x02, + HID_USAGE_PAGE_VIRTUAL_REALITY = 0x03, + HID_USAGE_PAGE_SPORT = 0x04, + HID_USAGE_PAGE_GAME = 0x05, + HID_USAGE_PAGE_GENERIC_DEVICE = 0x06, + HID_USAGE_PAGE_KEYBOARD = 0x07, + HID_USAGE_PAGE_LED = 0x08, + HID_USAGE_PAGE_BUTTON = 0x09, + HID_USAGE_PAGE_ORDINAL = 0x0a, + HID_USAGE_PAGE_TELEPHONY = 0x0b, + HID_USAGE_PAGE_CONSUMER = 0x0c, + HID_USAGE_PAGE_DIGITIZER = 0x0d, + HID_USAGE_PAGE_PID = 0x0f, + HID_USAGE_PAGE_UNICODE = 0x10, + HID_USAGE_PAGE_ALPHA_DISPLAY = 0x14, + HID_USAGE_PAGE_MEDICAL = 0x40, + HID_USAGE_PAGE_MONITOR = 0x80, //0x80 - 0x83 + HID_USAGE_PAGE_POWER = 0x84, // 0x084 - 0x87 + HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c, + HID_USAGE_PAGE_SCALE = 0x8d, + HID_USAGE_PAGE_MSR = 0x8e, + HID_USAGE_PAGE_CAMERA = 0x90, + HID_USAGE_PAGE_ARCADE = 0x91, + HID_USAGE_PAGE_VENDOR = 0xFF00 // 0xFF00 - 0xFFFF +}; + +/// HID Usage Table - Table 6: Generic Desktop Page +enum { + HID_USAGE_DESKTOP_POINTER = 0x01, + HID_USAGE_DESKTOP_MOUSE = 0x02, + HID_USAGE_DESKTOP_JOYSTICK = 0x04, + HID_USAGE_DESKTOP_GAMEPAD = 0x05, + HID_USAGE_DESKTOP_KEYBOARD = 0x06, + HID_USAGE_DESKTOP_KEYPAD = 0x07, + HID_USAGE_DESKTOP_MULTI_AXIS_CONTROLLER = 0x08, + HID_USAGE_DESKTOP_TABLET_PC_SYSTEM = 0x09, + HID_USAGE_DESKTOP_X = 0x30, + HID_USAGE_DESKTOP_Y = 0x31, + HID_USAGE_DESKTOP_Z = 0x32, + HID_USAGE_DESKTOP_RX = 0x33, + HID_USAGE_DESKTOP_RY = 0x34, + HID_USAGE_DESKTOP_RZ = 0x35, + HID_USAGE_DESKTOP_SLIDER = 0x36, + HID_USAGE_DESKTOP_DIAL = 0x37, + HID_USAGE_DESKTOP_WHEEL = 0x38, + HID_USAGE_DESKTOP_HAT_SWITCH = 0x39, + HID_USAGE_DESKTOP_COUNTED_BUFFER = 0x3a, + HID_USAGE_DESKTOP_BYTE_COUNT = 0x3b, + HID_USAGE_DESKTOP_MOTION_WAKEUP = 0x3c, + HID_USAGE_DESKTOP_START = 0x3d, + HID_USAGE_DESKTOP_SELECT = 0x3e, + HID_USAGE_DESKTOP_VX = 0x40, + HID_USAGE_DESKTOP_VY = 0x41, + HID_USAGE_DESKTOP_VZ = 0x42, + HID_USAGE_DESKTOP_VBRX = 0x43, + HID_USAGE_DESKTOP_VBRY = 0x44, + HID_USAGE_DESKTOP_VBRZ = 0x45, + HID_USAGE_DESKTOP_VNO = 0x46, + HID_USAGE_DESKTOP_FEATURE_NOTIFICATION = 0x47, + HID_USAGE_DESKTOP_RESOLUTION_MULTIPLIER = 0x48, + HID_USAGE_DESKTOP_SYSTEM_CONTROL = 0x80, + HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN = 0x81, + HID_USAGE_DESKTOP_SYSTEM_SLEEP = 0x82, + HID_USAGE_DESKTOP_SYSTEM_WAKE_UP = 0x83, + HID_USAGE_DESKTOP_SYSTEM_CONTEXT_MENU = 0x84, + HID_USAGE_DESKTOP_SYSTEM_MAIN_MENU = 0x85, + HID_USAGE_DESKTOP_SYSTEM_APP_MENU = 0x86, + HID_USAGE_DESKTOP_SYSTEM_MENU_HELP = 0x87, + HID_USAGE_DESKTOP_SYSTEM_MENU_EXIT = 0x88, + HID_USAGE_DESKTOP_SYSTEM_MENU_SELECT = 0x89, + HID_USAGE_DESKTOP_SYSTEM_MENU_RIGHT = 0x8A, + HID_USAGE_DESKTOP_SYSTEM_MENU_LEFT = 0x8B, + HID_USAGE_DESKTOP_SYSTEM_MENU_UP = 0x8C, + HID_USAGE_DESKTOP_SYSTEM_MENU_DOWN = 0x8D, + HID_USAGE_DESKTOP_SYSTEM_COLD_RESTART = 0x8E, + HID_USAGE_DESKTOP_SYSTEM_WARM_RESTART = 0x8F, + HID_USAGE_DESKTOP_DPAD_UP = 0x90, + HID_USAGE_DESKTOP_DPAD_DOWN = 0x91, + HID_USAGE_DESKTOP_DPAD_RIGHT = 0x92, + HID_USAGE_DESKTOP_DPAD_LEFT = 0x93, + HID_USAGE_DESKTOP_SYSTEM_DOCK = 0xA0, + HID_USAGE_DESKTOP_SYSTEM_UNDOCK = 0xA1, + HID_USAGE_DESKTOP_SYSTEM_SETUP = 0xA2, + HID_USAGE_DESKTOP_SYSTEM_BREAK = 0xA3, + HID_USAGE_DESKTOP_SYSTEM_DEBUGGER_BREAK = 0xA4, + HID_USAGE_DESKTOP_APPLICATION_BREAK = 0xA5, + HID_USAGE_DESKTOP_APPLICATION_DEBUGGER_BREAK = 0xA6, + HID_USAGE_DESKTOP_SYSTEM_SPEAKER_MUTE = 0xA7, + HID_USAGE_DESKTOP_SYSTEM_HIBERNATE = 0xA8, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INVERT = 0xB0, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INTERNAL = 0xB1, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_EXTERNAL = 0xB2, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_BOTH = 0xB3, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_DUAL = 0xB4, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_TOGGLE_INT_EXT = 0xB5, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_SWAP_PRIMARY_SECONDARY = 0xB6, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_LCD_AUTOSCALE = 0xB7 +}; + + +/// HID Usage Table: Consumer Page (0x0C) +/// Only contains controls that supported by Windows (whole list is too long) +enum +{ + // Generic Control + HID_USAGE_CONSUMER_CONTROL = 0x0001, + + // Power Control + HID_USAGE_CONSUMER_POWER = 0x0030, + HID_USAGE_CONSUMER_RESET = 0x0031, + HID_USAGE_CONSUMER_SLEEP = 0x0032, + + // Screen Brightness + HID_USAGE_CONSUMER_BRIGHTNESS_INCREMENT = 0x006F, + HID_USAGE_CONSUMER_BRIGHTNESS_DECREMENT = 0x0070, + + // These HID usages operate only on mobile systems (battery powered) and + // require Windows 8 (build 8302 or greater). + HID_USAGE_CONSUMER_WIRELESS_RADIO_CONTROLS = 0x000C, + HID_USAGE_CONSUMER_WIRELESS_RADIO_BUTTONS = 0x00C6, + HID_USAGE_CONSUMER_WIRELESS_RADIO_LED = 0x00C7, + HID_USAGE_CONSUMER_WIRELESS_RADIO_SLIDER_SWITCH = 0x00C8, + + // Media Control + HID_USAGE_CONSUMER_PLAY_PAUSE = 0x00CD, + HID_USAGE_CONSUMER_SCAN_NEXT = 0x00B5, + HID_USAGE_CONSUMER_SCAN_PREVIOUS = 0x00B6, + HID_USAGE_CONSUMER_STOP = 0x00B7, + HID_USAGE_CONSUMER_VOLUME = 0x00E0, + HID_USAGE_CONSUMER_MUTE = 0x00E2, + HID_USAGE_CONSUMER_BASS = 0x00E3, + HID_USAGE_CONSUMER_TREBLE = 0x00E4, + HID_USAGE_CONSUMER_BASS_BOOST = 0x00E5, + HID_USAGE_CONSUMER_VOLUME_INCREMENT = 0x00E9, + HID_USAGE_CONSUMER_VOLUME_DECREMENT = 0x00EA, + HID_USAGE_CONSUMER_BASS_INCREMENT = 0x0152, + HID_USAGE_CONSUMER_BASS_DECREMENT = 0x0153, + HID_USAGE_CONSUMER_TREBLE_INCREMENT = 0x0154, + HID_USAGE_CONSUMER_TREBLE_DECREMENT = 0x0155, + + // Application Launcher + HID_USAGE_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION = 0x0183, + HID_USAGE_CONSUMER_AL_EMAIL_READER = 0x018A, + HID_USAGE_CONSUMER_AL_CALCULATOR = 0x0192, + HID_USAGE_CONSUMER_AL_LOCAL_BROWSER = 0x0194, + + // Browser/Explorer Specific + HID_USAGE_CONSUMER_AC_SEARCH = 0x0221, + HID_USAGE_CONSUMER_AC_HOME = 0x0223, + HID_USAGE_CONSUMER_AC_BACK = 0x0224, + HID_USAGE_CONSUMER_AC_FORWARD = 0x0225, + HID_USAGE_CONSUMER_AC_STOP = 0x0226, + HID_USAGE_CONSUMER_AC_REFRESH = 0x0227, + HID_USAGE_CONSUMER_AC_BOOKMARKS = 0x022A, + + // Mouse Horizontal scroll + HID_USAGE_CONSUMER_AC_PAN = 0x0238, +}; + +/*-------------------------------------------------------------------- + * ASCII to KEYCODE Conversion + * Expand to array of [128][2] (shift, keycode) + * + * Usage: example to convert input chr into keyboard report (modifier + keycode) + * + * uint8_t const conv_table[128][2] = { HID_ASCII_TO_KEYCODE }; + * + * uint8_t keycode[6] = { 0 }; + * uint8_t modifier = 0; + * + * if ( conv_table[chr][0] ) modifier = KEYBOARD_MODIFIER_LEFTSHIFT; + * keycode[0] = conv_table[chr][1]; + * tud_hid_keyboard_report(report_id, modifier, keycode); + * + *--------------------------------------------------------------------*/ +#define HID_ASCII_TO_KEYCODE \ + {0, 0 }, /* 0x00 Null */ \ + {0, 0 }, /* 0x01 */ \ + {0, 0 }, /* 0x02 */ \ + {0, 0 }, /* 0x03 */ \ + {0, 0 }, /* 0x04 */ \ + {0, 0 }, /* 0x05 */ \ + {0, 0 }, /* 0x06 */ \ + {0, 0 }, /* 0x07 */ \ + {0, HID_KEY_BACKSPACE }, /* 0x08 Backspace */ \ + {0, HID_KEY_TAB }, /* 0x09 Tab */ \ + {0, HID_KEY_ENTER }, /* 0x0A Line Feed */ \ + {0, 0 }, /* 0x0B */ \ + {0, 0 }, /* 0x0C */ \ + {0, HID_KEY_ENTER }, /* 0x0D CR */ \ + {0, 0 }, /* 0x0E */ \ + {0, 0 }, /* 0x0F */ \ + {0, 0 }, /* 0x10 */ \ + {0, 0 }, /* 0x11 */ \ + {0, 0 }, /* 0x12 */ \ + {0, 0 }, /* 0x13 */ \ + {0, 0 }, /* 0x14 */ \ + {0, 0 }, /* 0x15 */ \ + {0, 0 }, /* 0x16 */ \ + {0, 0 }, /* 0x17 */ \ + {0, 0 }, /* 0x18 */ \ + {0, 0 }, /* 0x19 */ \ + {0, 0 }, /* 0x1A */ \ + {0, HID_KEY_ESCAPE }, /* 0x1B Escape */ \ + {0, 0 }, /* 0x1C */ \ + {0, 0 }, /* 0x1D */ \ + {0, 0 }, /* 0x1E */ \ + {0, 0 }, /* 0x1F */ \ + \ + {0, HID_KEY_SPACE }, /* 0x20 */ \ + {1, HID_KEY_1 }, /* 0x21 ! */ \ + {1, HID_KEY_APOSTROPHE }, /* 0x22 " */ \ + {1, HID_KEY_3 }, /* 0x23 # */ \ + {1, HID_KEY_4 }, /* 0x24 $ */ \ + {1, HID_KEY_5 }, /* 0x25 % */ \ + {1, HID_KEY_7 }, /* 0x26 & */ \ + {0, HID_KEY_APOSTROPHE }, /* 0x27 ' */ \ + {1, HID_KEY_9 }, /* 0x28 ( */ \ + {1, HID_KEY_0 }, /* 0x29 ) */ \ + {1, HID_KEY_8 }, /* 0x2A * */ \ + {1, HID_KEY_EQUAL }, /* 0x2B + */ \ + {0, HID_KEY_COMMA }, /* 0x2C , */ \ + {0, HID_KEY_MINUS }, /* 0x2D - */ \ + {0, HID_KEY_PERIOD }, /* 0x2E . */ \ + {0, HID_KEY_SLASH }, /* 0x2F / */ \ + {0, HID_KEY_0 }, /* 0x30 0 */ \ + {0, HID_KEY_1 }, /* 0x31 1 */ \ + {0, HID_KEY_2 }, /* 0x32 2 */ \ + {0, HID_KEY_3 }, /* 0x33 3 */ \ + {0, HID_KEY_4 }, /* 0x34 4 */ \ + {0, HID_KEY_5 }, /* 0x35 5 */ \ + {0, HID_KEY_6 }, /* 0x36 6 */ \ + {0, HID_KEY_7 }, /* 0x37 7 */ \ + {0, HID_KEY_8 }, /* 0x38 8 */ \ + {0, HID_KEY_9 }, /* 0x39 9 */ \ + {1, HID_KEY_SEMICOLON }, /* 0x3A : */ \ + {0, HID_KEY_SEMICOLON }, /* 0x3B ; */ \ + {1, HID_KEY_COMMA }, /* 0x3C < */ \ + {0, HID_KEY_EQUAL }, /* 0x3D = */ \ + {1, HID_KEY_PERIOD }, /* 0x3E > */ \ + {1, HID_KEY_SLASH }, /* 0x3F ? */ \ + \ + {1, HID_KEY_2 }, /* 0x40 @ */ \ + {1, HID_KEY_A }, /* 0x41 A */ \ + {1, HID_KEY_B }, /* 0x42 B */ \ + {1, HID_KEY_C }, /* 0x43 C */ \ + {1, HID_KEY_D }, /* 0x44 D */ \ + {1, HID_KEY_E }, /* 0x45 E */ \ + {1, HID_KEY_F }, /* 0x46 F */ \ + {1, HID_KEY_G }, /* 0x47 G */ \ + {1, HID_KEY_H }, /* 0x48 H */ \ + {1, HID_KEY_I }, /* 0x49 I */ \ + {1, HID_KEY_J }, /* 0x4A J */ \ + {1, HID_KEY_K }, /* 0x4B K */ \ + {1, HID_KEY_L }, /* 0x4C L */ \ + {1, HID_KEY_M }, /* 0x4D M */ \ + {1, HID_KEY_N }, /* 0x4E N */ \ + {1, HID_KEY_O }, /* 0x4F O */ \ + {1, HID_KEY_P }, /* 0x50 P */ \ + {1, HID_KEY_Q }, /* 0x51 Q */ \ + {1, HID_KEY_R }, /* 0x52 R */ \ + {1, HID_KEY_S }, /* 0x53 S */ \ + {1, HID_KEY_T }, /* 0x55 T */ \ + {1, HID_KEY_U }, /* 0x55 U */ \ + {1, HID_KEY_V }, /* 0x56 V */ \ + {1, HID_KEY_W }, /* 0x57 W */ \ + {1, HID_KEY_X }, /* 0x58 X */ \ + {1, HID_KEY_Y }, /* 0x59 Y */ \ + {1, HID_KEY_Z }, /* 0x5A Z */ \ + {0, HID_KEY_BRACKET_LEFT }, /* 0x5B [ */ \ + {0, HID_KEY_BACKSLASH }, /* 0x5C '\' */ \ + {0, HID_KEY_BRACKET_RIGHT }, /* 0x5D ] */ \ + {1, HID_KEY_6 }, /* 0x5E ^ */ \ + {1, HID_KEY_MINUS }, /* 0x5F _ */ \ + \ + {0, HID_KEY_GRAVE }, /* 0x60 ` */ \ + {0, HID_KEY_A }, /* 0x61 a */ \ + {0, HID_KEY_B }, /* 0x62 b */ \ + {0, HID_KEY_C }, /* 0x63 c */ \ + {0, HID_KEY_D }, /* 0x66 d */ \ + {0, HID_KEY_E }, /* 0x65 e */ \ + {0, HID_KEY_F }, /* 0x66 f */ \ + {0, HID_KEY_G }, /* 0x67 g */ \ + {0, HID_KEY_H }, /* 0x68 h */ \ + {0, HID_KEY_I }, /* 0x69 i */ \ + {0, HID_KEY_J }, /* 0x6A j */ \ + {0, HID_KEY_K }, /* 0x6B k */ \ + {0, HID_KEY_L }, /* 0x6C l */ \ + {0, HID_KEY_M }, /* 0x6D m */ \ + {0, HID_KEY_N }, /* 0x6E n */ \ + {0, HID_KEY_O }, /* 0x6F o */ \ + {0, HID_KEY_P }, /* 0x70 p */ \ + {0, HID_KEY_Q }, /* 0x71 q */ \ + {0, HID_KEY_R }, /* 0x72 r */ \ + {0, HID_KEY_S }, /* 0x73 s */ \ + {0, HID_KEY_T }, /* 0x75 t */ \ + {0, HID_KEY_U }, /* 0x75 u */ \ + {0, HID_KEY_V }, /* 0x76 v */ \ + {0, HID_KEY_W }, /* 0x77 w */ \ + {0, HID_KEY_X }, /* 0x78 x */ \ + {0, HID_KEY_Y }, /* 0x79 y */ \ + {0, HID_KEY_Z }, /* 0x7A z */ \ + {1, HID_KEY_BRACKET_LEFT }, /* 0x7B { */ \ + {1, HID_KEY_BACKSLASH }, /* 0x7C | */ \ + {1, HID_KEY_BRACKET_RIGHT }, /* 0x7D } */ \ + {1, HID_KEY_GRAVE }, /* 0x7E ~ */ \ + {0, HID_KEY_DELETE } /* 0x7F Delete */ \ + +/*-------------------------------------------------------------------- + * KEYCODE to Ascii Conversion + * Expand to array of [128][2] (ascii without shift, ascii with shift) + * + * Usage: example to convert ascii from keycode (key) and shift modifier (shift). + * Here we assume key < 128 ( printable ) + * + * uint8_t const conv_table[128][2] = { HID_KEYCODE_TO_ASCII }; + * char ch = shift ? conv_table[chr][1] : conv_table[chr][0]; + * + *--------------------------------------------------------------------*/ +#define HID_KEYCODE_TO_ASCII \ + {0 , 0 }, /* 0x00 */ \ + {0 , 0 }, /* 0x01 */ \ + {0 , 0 }, /* 0x02 */ \ + {0 , 0 }, /* 0x03 */ \ + {'a' , 'A' }, /* 0x04 */ \ + {'b' , 'B' }, /* 0x05 */ \ + {'c' , 'C' }, /* 0x06 */ \ + {'d' , 'D' }, /* 0x07 */ \ + {'e' , 'E' }, /* 0x08 */ \ + {'f' , 'F' }, /* 0x09 */ \ + {'g' , 'G' }, /* 0x0a */ \ + {'h' , 'H' }, /* 0x0b */ \ + {'i' , 'I' }, /* 0x0c */ \ + {'j' , 'J' }, /* 0x0d */ \ + {'k' , 'K' }, /* 0x0e */ \ + {'l' , 'L' }, /* 0x0f */ \ + {'m' , 'M' }, /* 0x10 */ \ + {'n' , 'N' }, /* 0x11 */ \ + {'o' , 'O' }, /* 0x12 */ \ + {'p' , 'P' }, /* 0x13 */ \ + {'q' , 'Q' }, /* 0x14 */ \ + {'r' , 'R' }, /* 0x15 */ \ + {'s' , 'S' }, /* 0x16 */ \ + {'t' , 'T' }, /* 0x17 */ \ + {'u' , 'U' }, /* 0x18 */ \ + {'v' , 'V' }, /* 0x19 */ \ + {'w' , 'W' }, /* 0x1a */ \ + {'x' , 'X' }, /* 0x1b */ \ + {'y' , 'Y' }, /* 0x1c */ \ + {'z' , 'Z' }, /* 0x1d */ \ + {'1' , '!' }, /* 0x1e */ \ + {'2' , '@' }, /* 0x1f */ \ + {'3' , '#' }, /* 0x20 */ \ + {'4' , '$' }, /* 0x21 */ \ + {'5' , '%' }, /* 0x22 */ \ + {'6' , '^' }, /* 0x23 */ \ + {'7' , '&' }, /* 0x24 */ \ + {'8' , '*' }, /* 0x25 */ \ + {'9' , '(' }, /* 0x26 */ \ + {'0' , ')' }, /* 0x27 */ \ + {'\r' , '\r' }, /* 0x28 */ \ + {'\x1b', '\x1b' }, /* 0x29 */ \ + {'\b' , '\b' }, /* 0x2a */ \ + {'\t' , '\t' }, /* 0x2b */ \ + {' ' , ' ' }, /* 0x2c */ \ + {'-' , '_' }, /* 0x2d */ \ + {'=' , '+' }, /* 0x2e */ \ + {'[' , '{' }, /* 0x2f */ \ + {']' , '}' }, /* 0x30 */ \ + {'\\' , '|' }, /* 0x31 */ \ + {'#' , '~' }, /* 0x32 */ \ + {';' , ':' }, /* 0x33 */ \ + {'\'' , '\"' }, /* 0x34 */ \ + {'`' , '~' }, /* 0x35 */ \ + {',' , '<' }, /* 0x36 */ \ + {'.' , '>' }, /* 0x37 */ \ + {'/' , '?' }, /* 0x38 */ \ + \ + {0 , 0 }, /* 0x39 */ \ + {0 , 0 }, /* 0x3a */ \ + {0 , 0 }, /* 0x3b */ \ + {0 , 0 }, /* 0x3c */ \ + {0 , 0 }, /* 0x3d */ \ + {0 , 0 }, /* 0x3e */ \ + {0 , 0 }, /* 0x3f */ \ + {0 , 0 }, /* 0x40 */ \ + {0 , 0 }, /* 0x41 */ \ + {0 , 0 }, /* 0x42 */ \ + {0 , 0 }, /* 0x43 */ \ + {0 , 0 }, /* 0x44 */ \ + {0 , 0 }, /* 0x45 */ \ + {0 , 0 }, /* 0x46 */ \ + {0 , 0 }, /* 0x47 */ \ + {0 , 0 }, /* 0x48 */ \ + {0 , 0 }, /* 0x49 */ \ + {0 , 0 }, /* 0x4a */ \ + {0 , 0 }, /* 0x4b */ \ + {0 , 0 }, /* 0x4c */ \ + {0 , 0 }, /* 0x4d */ \ + {0 , 0 }, /* 0x4e */ \ + {0 , 0 }, /* 0x4f */ \ + {0 , 0 }, /* 0x50 */ \ + {0 , 0 }, /* 0x51 */ \ + {0 , 0 }, /* 0x52 */ \ + {0 , 0 }, /* 0x53 */ \ + \ + {'/' , '/' }, /* 0x54 */ \ + {'*' , '*' }, /* 0x55 */ \ + {'-' , '-' }, /* 0x56 */ \ + {'+' , '+' }, /* 0x57 */ \ + {'\r' , '\r' }, /* 0x58 */ \ + {'1' , 0 }, /* 0x59 */ \ + {'2' , 0 }, /* 0x5a */ \ + {'3' , 0 }, /* 0x5b */ \ + {'4' , 0 }, /* 0x5c */ \ + {'5' , '5' }, /* 0x5d */ \ + {'6' , 0 }, /* 0x5e */ \ + {'7' , 0 }, /* 0x5f */ \ + {'8' , 0 }, /* 0x60 */ \ + {'9' , 0 }, /* 0x61 */ \ + {'0' , 0 }, /* 0x62 */ \ + {'.' , 0 }, /* 0x63 */ \ + {0 , 0 }, /* 0x64 */ \ + {0 , 0 }, /* 0x65 */ \ + {0 , 0 }, /* 0x66 */ \ + {'=' , '=' }, /* 0x67 */ \ + + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_HID_H__ */ + +/// @} diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.c new file mode 100644 index 00000000..8077e4de --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.c @@ -0,0 +1,419 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_HID) + +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "hid_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +typedef struct +{ + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; // optional Out endpoint + uint8_t itf_protocol; // Boot mouse or keyboard + + uint8_t protocol_mode; // Boot (0) or Report protocol (1) + uint8_t idle_rate; // up to application to handle idle rate + uint16_t report_desc_len; + + CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE]; + + // TODO save hid descriptor since host can specifically request this after enumeration + // Note: HID descriptor may be not available from application after enumeration + tusb_hid_descriptor_hid_t const * hid_descriptor; +} hidd_interface_t; + +CFG_TUSB_MEM_SECTION static hidd_interface_t _hidd_itf[CFG_TUD_HID]; + +/*------------- Helpers -------------*/ +static inline uint8_t get_index_by_itfnum(uint8_t itf_num) +{ + for (uint8_t i=0; i < CFG_TUD_HID; i++ ) + { + if ( itf_num == _hidd_itf[i].itf_num ) return i; + } + + return 0xFF; +} + +//--------------------------------------------------------------------+ +// APPLICATION API +//--------------------------------------------------------------------+ +bool tud_hid_n_ready(uint8_t instance) +{ + uint8_t const rhport = 0; + uint8_t const ep_in = _hidd_itf[instance].ep_in; + return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(rhport, ep_in); +} + +bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint16_t len) +{ + uint8_t const rhport = 0; + hidd_interface_t * p_hid = &_hidd_itf[instance]; + + // claim endpoint + TU_VERIFY( usbd_edpt_claim(rhport, p_hid->ep_in) ); + + // prepare data + if (report_id) + { + len = tu_min16(len, CFG_TUD_HID_EP_BUFSIZE-1); + + p_hid->epin_buf[0] = report_id; + memcpy(p_hid->epin_buf+1, report, len); + len++; + }else + { + // If report id = 0, skip ID field + len = tu_min16(len, CFG_TUD_HID_EP_BUFSIZE); + memcpy(p_hid->epin_buf, report, len); + } + + return usbd_edpt_xfer(rhport, p_hid->ep_in, p_hid->epin_buf, len); +} + +uint8_t tud_hid_n_interface_protocol(uint8_t instance) +{ + return _hidd_itf[instance].itf_protocol; +} + +uint8_t tud_hid_n_get_protocol(uint8_t instance) +{ + return _hidd_itf[instance].protocol_mode; +} + +bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6]) +{ + hid_keyboard_report_t report; + + report.modifier = modifier; + report.reserved = 0; + + if ( keycode ) + { + memcpy(report.keycode, keycode, 6); + }else + { + tu_memclr(report.keycode, 6); + } + + return tud_hid_n_report(instance, report_id, &report, sizeof(report)); +} + +bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, + uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) +{ + hid_mouse_report_t report = + { + .buttons = buttons, + .x = x, + .y = y, + .wheel = vertical, + .pan = horizontal + }; + + return tud_hid_n_report(instance, report_id, &report, sizeof(report)); +} + +bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, + int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) +{ + hid_gamepad_report_t report = + { + .x = x, + .y = y, + .z = z, + .rz = rz, + .rx = rx, + .ry = ry, + .hat = hat, + .buttons = buttons, + }; + + return tud_hid_n_report(instance, report_id, &report, sizeof(report)); +} + +//--------------------------------------------------------------------+ +// USBD-CLASS API +//--------------------------------------------------------------------+ +void hidd_init(void) +{ + hidd_reset(0); +} + +void hidd_reset(uint8_t rhport) +{ + (void) rhport; + tu_memclr(_hidd_itf, sizeof(_hidd_itf)); +} + +uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) +{ + TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0); + + // len = interface + hid + n*endpoints + uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); + TU_ASSERT(max_len >= drv_len, 0); + + // Find available interface + hidd_interface_t * p_hid = NULL; + uint8_t hid_id; + for(hid_id=0; hid_idhid_descriptor = (tusb_hid_descriptor_hid_t const *) p_desc; + + //------------- Endpoint Descriptor -------------// + p_desc = tu_desc_next(p_desc); + TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_INTERRUPT, &p_hid->ep_out, &p_hid->ep_in), 0); + + if ( desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT ) p_hid->itf_protocol = desc_itf->bInterfaceProtocol; + + p_hid->protocol_mode = HID_PROTOCOL_REPORT; // Per Specs: default is report mode + p_hid->itf_num = desc_itf->bInterfaceNumber; + + // Use offsetof to avoid pointer to the odd/misaligned address + p_hid->report_desc_len = tu_unaligned_read16((uint8_t const*) p_hid->hid_descriptor + offsetof(tusb_hid_descriptor_hid_t, wReportLength)); + + // Prepare for output endpoint + if (p_hid->ep_out) + { + if ( !usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)) ) + { + TU_LOG_FAILED(); + TU_BREAKPOINT(); + } + } + + return drv_len; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); + + uint8_t const hid_itf = get_index_by_itfnum((uint8_t) request->wIndex); + TU_VERIFY(hid_itf < CFG_TUD_HID); + + hidd_interface_t* p_hid = &_hidd_itf[hid_itf]; + + if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) + { + //------------- STD Request -------------// + if ( stage == CONTROL_STAGE_SETUP ) + { + uint8_t const desc_type = tu_u16_high(request->wValue); + //uint8_t const desc_index = tu_u16_low (request->wValue); + + if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_HID) + { + TU_VERIFY(p_hid->hid_descriptor); + TU_VERIFY(tud_control_xfer(rhport, request, (void*)(uintptr_t) p_hid->hid_descriptor, p_hid->hid_descriptor->bLength)); + } + else if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT) + { + uint8_t const * desc_report = tud_hid_descriptor_report_cb(hid_itf); + tud_control_xfer(rhport, request, (void*)(uintptr_t) desc_report, p_hid->report_desc_len); + } + else + { + return false; // stall unsupported request + } + } + } + else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) + { + //------------- Class Specific Request -------------// + switch( request->bRequest ) + { + case HID_REQ_CONTROL_GET_REPORT: + if ( stage == CONTROL_STAGE_SETUP ) + { + uint8_t const report_type = tu_u16_high(request->wValue); + uint8_t const report_id = tu_u16_low(request->wValue); + + uint8_t* report_buf = p_hid->epin_buf; + uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); + + uint16_t xferlen = 0; + + // If host request a specific Report ID, add ID to as 1 byte of response + if ( (report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1) ) + { + *report_buf++ = report_id; + req_len--; + + xferlen++; + } + + xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len); + TU_ASSERT( xferlen > 0 ); + + tud_control_xfer(rhport, request, p_hid->epin_buf, xferlen); + } + break; + + case HID_REQ_CONTROL_SET_REPORT: + if ( stage == CONTROL_STAGE_SETUP ) + { + TU_VERIFY(request->wLength <= sizeof(p_hid->epout_buf)); + tud_control_xfer(rhport, request, p_hid->epout_buf, request->wLength); + } + else if ( stage == CONTROL_STAGE_ACK ) + { + uint8_t const report_type = tu_u16_high(request->wValue); + uint8_t const report_id = tu_u16_low(request->wValue); + + uint8_t const* report_buf = p_hid->epout_buf; + uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); + + // If host request a specific Report ID, extract report ID in buffer before invoking callback + if ( (report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0]) ) + { + report_buf++; + report_len--; + } + + tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, report_len); + } + break; + + case HID_REQ_CONTROL_SET_IDLE: + if ( stage == CONTROL_STAGE_SETUP ) + { + p_hid->idle_rate = tu_u16_high(request->wValue); + if ( tud_hid_set_idle_cb ) + { + // stall request if callback return false + TU_VERIFY( tud_hid_set_idle_cb( hid_itf, p_hid->idle_rate) ); + } + + tud_control_status(rhport, request); + } + break; + + case HID_REQ_CONTROL_GET_IDLE: + if ( stage == CONTROL_STAGE_SETUP ) + { + // TODO idle rate of report + tud_control_xfer(rhport, request, &p_hid->idle_rate, 1); + } + break; + + case HID_REQ_CONTROL_GET_PROTOCOL: + if ( stage == CONTROL_STAGE_SETUP ) + { + tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1); + } + break; + + case HID_REQ_CONTROL_SET_PROTOCOL: + if ( stage == CONTROL_STAGE_SETUP ) + { + tud_control_status(rhport, request); + } + else if ( stage == CONTROL_STAGE_ACK ) + { + p_hid->protocol_mode = (uint8_t) request->wValue; + if (tud_hid_set_protocol_cb) + { + tud_hid_set_protocol_cb(hid_itf, p_hid->protocol_mode); + } + } + break; + + default: return false; // stall unsupported request + } + }else + { + return false; // stall unsupported request + } + + return true; +} + +bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) result; + + uint8_t instance = 0; + hidd_interface_t * p_hid = _hidd_itf; + + // Identify which interface to use + for (instance = 0; instance < CFG_TUD_HID; instance++) + { + p_hid = &_hidd_itf[instance]; + if ( (ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in) ) break; + } + TU_ASSERT(instance < CFG_TUD_HID); + + // Sent report successfully + if (ep_addr == p_hid->ep_in) + { + if (tud_hid_report_complete_cb) + { + tud_hid_report_complete_cb(instance, p_hid->epin_buf, (/*uint16_t*/ uint8_t) xferred_bytes); + } + } + // Received report + else if (ep_addr == p_hid->ep_out) + { + tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, (uint16_t) xferred_bytes); + TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))); + } + + return true; +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.h new file mode 100644 index 00000000..3143b102 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.h @@ -0,0 +1,393 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_HID_DEVICE_H_ +#define _TUSB_HID_DEVICE_H_ + +#include "hid.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Class Driver Default Configure & Validation +//--------------------------------------------------------------------+ + +#if !defined(CFG_TUD_HID_EP_BUFSIZE) & defined(CFG_TUD_HID_BUFSIZE) + // TODO warn user to use new name later on + // #warning CFG_TUD_HID_BUFSIZE is renamed to CFG_TUD_HID_EP_BUFSIZE, please update to use the new name + #define CFG_TUD_HID_EP_BUFSIZE CFG_TUD_HID_BUFSIZE +#endif + +#ifndef CFG_TUD_HID_EP_BUFSIZE + #define CFG_TUD_HID_EP_BUFSIZE 64 +#endif + +//--------------------------------------------------------------------+ +// Application API (Multiple Instances) +// CFG_TUD_HID > 1 +//--------------------------------------------------------------------+ + +// Check if the interface is ready to use +bool tud_hid_n_ready(uint8_t instance); + +// Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values +uint8_t tud_hid_n_interface_protocol(uint8_t instance); + +// Get current active protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) +uint8_t tud_hid_n_get_protocol(uint8_t instance); + +// Send report to host +bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint16_t len); + +// KEYBOARD: convenient helper to send keyboard report if application +// use template layout report as defined by hid_keyboard_report_t +bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6]); + +// MOUSE: convenient helper to send mouse report if application +// use template layout report as defined by hid_mouse_report_t +bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal); + +// Gamepad: convenient helper to send gamepad report if application +// use template layout report TUD_HID_REPORT_DESC_GAMEPAD +bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); + +//--------------------------------------------------------------------+ +// Application API (Single Port) +//--------------------------------------------------------------------+ +static inline bool tud_hid_ready(void); +static inline uint8_t tud_hid_interface_protocol(void); +static inline uint8_t tud_hid_get_protocol(void); +static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len); +static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]); +static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal); +static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); + +//--------------------------------------------------------------------+ +// Callbacks (Weak is optional) +//--------------------------------------------------------------------+ + +// Invoked when received GET HID REPORT DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance); + +// Invoked when received GET_REPORT control request +// Application must fill buffer report's content and return its length. +// Return zero will cause the stack to STALL request +uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen); + +// Invoked when received SET_REPORT control request or +// received data on OUT endpoint ( Report ID = 0, Type = 0 ) +void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize); + +// Invoked when received SET_PROTOCOL request +// protocol is either HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) +TU_ATTR_WEAK void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol); + +// Invoked when received SET_IDLE request. return false will stall the request +// - Idle Rate = 0 : only send report if there is changes, i.e skip duplication +// - Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms). +TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate); + +// Invoked when sent REPORT successfully to host +// Application can use this to send the next report +// Note: For composite reports, report[0] is report ID +TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, /*uint16_t*/ uint8_t len ); + + +//--------------------------------------------------------------------+ +// Inline Functions +//--------------------------------------------------------------------+ +static inline bool tud_hid_ready(void) +{ + return tud_hid_n_ready(0); +} + +static inline uint8_t tud_hid_interface_protocol(void) +{ + return tud_hid_n_interface_protocol(0); +} + +static inline uint8_t tud_hid_get_protocol(void) +{ + return tud_hid_n_get_protocol(0); +} + +static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len) +{ + return tud_hid_n_report(0, report_id, report, len); +} + +static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]) +{ + return tud_hid_n_keyboard_report(0, report_id, modifier, keycode); +} + +static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) +{ + return tud_hid_n_mouse_report(0, report_id, buttons, x, y, vertical, horizontal); +} + +static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) +{ + return tud_hid_n_gamepad_report(0, report_id, x, y, z, rz, rx, ry, hat, buttons); +} + +/* --------------------------------------------------------------------+ + * HID Report Descriptor Template + * + * Convenient for declaring popular HID device (keyboard, mouse, consumer, + * gamepad etc...). Templates take "HID_REPORT_ID(n)" as input, leave + * empty if multiple reports is not used + * + * - Only 1 report: no parameter + * uint8_t const report_desc[] = { TUD_HID_REPORT_DESC_KEYBOARD() }; + * + * - Multiple Reports: "HID_REPORT_ID(ID)" must be passed to template + * uint8_t const report_desc[] = + * { + * TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(1) ) , + * TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(2) ) + * }; + *--------------------------------------------------------------------*/ + +// Keyboard Report Descriptor Template +#define TUD_HID_REPORT_DESC_KEYBOARD(...) \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_KEYBOARD ) ,\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ + __VA_ARGS__ \ + /* 8 bits Modifier Keys (Shfit, Control, Alt) */ \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\ + HID_USAGE_MIN ( 224 ) ,\ + HID_USAGE_MAX ( 231 ) ,\ + HID_LOGICAL_MIN ( 0 ) ,\ + HID_LOGICAL_MAX ( 1 ) ,\ + HID_REPORT_COUNT ( 8 ) ,\ + HID_REPORT_SIZE ( 1 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + /* 8 bit reserved */ \ + HID_REPORT_COUNT ( 1 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_INPUT ( HID_CONSTANT ) ,\ + /* Output 5-bit LED Indicator Kana | Compose | ScrollLock | CapsLock | NumLock */ \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_LED ) ,\ + HID_USAGE_MIN ( 1 ) ,\ + HID_USAGE_MAX ( 5 ) ,\ + HID_REPORT_COUNT ( 5 ) ,\ + HID_REPORT_SIZE ( 1 ) ,\ + HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + /* led padding */ \ + HID_REPORT_COUNT ( 1 ) ,\ + HID_REPORT_SIZE ( 3 ) ,\ + HID_OUTPUT ( HID_CONSTANT ) ,\ + /* 6-byte Keycodes */ \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\ + HID_USAGE_MIN ( 0 ) ,\ + HID_USAGE_MAX_N ( 255, 2 ) ,\ + HID_LOGICAL_MIN ( 0 ) ,\ + HID_LOGICAL_MAX_N( 255, 2 ) ,\ + HID_REPORT_COUNT ( 6 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\ + HID_COLLECTION_END \ + +// Mouse Report Descriptor Template +#define TUD_HID_REPORT_DESC_MOUSE(...) \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ) ,\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ + __VA_ARGS__ \ + HID_USAGE ( HID_USAGE_DESKTOP_POINTER ) ,\ + HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\ + HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\ + HID_USAGE_MIN ( 1 ) ,\ + HID_USAGE_MAX ( 5 ) ,\ + HID_LOGICAL_MIN ( 0 ) ,\ + HID_LOGICAL_MAX ( 1 ) ,\ + /* Left, Right, Middle, Backward, Forward buttons */ \ + HID_REPORT_COUNT( 5 ) ,\ + HID_REPORT_SIZE ( 1 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + /* 3 bit padding */ \ + HID_REPORT_COUNT( 1 ) ,\ + HID_REPORT_SIZE ( 3 ) ,\ + HID_INPUT ( HID_CONSTANT ) ,\ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + /* X, Y position [-127, 127] */ \ + HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\ + HID_LOGICAL_MIN ( 0x81 ) ,\ + HID_LOGICAL_MAX ( 0x7f ) ,\ + HID_REPORT_COUNT( 2 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\ + /* Verital wheel scroll [-127, 127] */ \ + HID_USAGE ( HID_USAGE_DESKTOP_WHEEL ) ,\ + HID_LOGICAL_MIN ( 0x81 ) ,\ + HID_LOGICAL_MAX ( 0x7f ) ,\ + HID_REPORT_COUNT( 1 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\ + HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ), \ + /* Horizontal wheel scroll [-127, 127] */ \ + HID_USAGE_N ( HID_USAGE_CONSUMER_AC_PAN, 2 ), \ + HID_LOGICAL_MIN ( 0x81 ), \ + HID_LOGICAL_MAX ( 0x7f ), \ + HID_REPORT_COUNT( 1 ), \ + HID_REPORT_SIZE ( 8 ), \ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), \ + HID_COLLECTION_END , \ + HID_COLLECTION_END \ + +// Consumer Control Report Descriptor Template +#define TUD_HID_REPORT_DESC_CONSUMER(...) \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ) ,\ + HID_USAGE ( HID_USAGE_CONSUMER_CONTROL ) ,\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ + __VA_ARGS__ \ + HID_LOGICAL_MIN ( 0x00 ) ,\ + HID_LOGICAL_MAX_N( 0x03FF, 2 ) ,\ + HID_USAGE_MIN ( 0x00 ) ,\ + HID_USAGE_MAX_N ( 0x03FF, 2 ) ,\ + HID_REPORT_COUNT ( 1 ) ,\ + HID_REPORT_SIZE ( 16 ) ,\ + HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\ + HID_COLLECTION_END \ + +/* System Control Report Descriptor Template + * 0x00 - do nothing + * 0x01 - Power Off + * 0x02 - Standby + * 0x03 - Wake Host + */ +#define TUD_HID_REPORT_DESC_SYSTEM_CONTROL(...) \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_CONTROL ) ,\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ + __VA_ARGS__ \ + /* 2 bit system power control */ \ + HID_LOGICAL_MIN ( 1 ) ,\ + HID_LOGICAL_MAX ( 3 ) ,\ + HID_REPORT_COUNT ( 1 ) ,\ + HID_REPORT_SIZE ( 2 ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_SLEEP ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_WAKE_UP ) ,\ + HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\ + /* 6 bit padding */ \ + HID_REPORT_COUNT ( 1 ) ,\ + HID_REPORT_SIZE ( 6 ) ,\ + HID_INPUT ( HID_CONSTANT ) ,\ + HID_COLLECTION_END \ + +// Gamepad Report Descriptor Template +// with 32 buttons, 2 joysticks and 1 hat/dpad with following layout +// | X | Y | Z | Rz | Rx | Ry (1 byte each) | hat/DPAD (1 byte) | Button Map (4 bytes) | +#define TUD_HID_REPORT_DESC_GAMEPAD(...) \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_GAMEPAD ) ,\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ + __VA_ARGS__ \ + /* 8 bit X, Y, Z, Rz, Rx, Ry (min -127, max 127 ) */ \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_Z ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_RZ ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_RX ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_RY ) ,\ + HID_LOGICAL_MIN ( 0x81 ) ,\ + HID_LOGICAL_MAX ( 0x7f ) ,\ + HID_REPORT_COUNT ( 6 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + /* 8 bit DPad/Hat Button Map */ \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_HAT_SWITCH ) ,\ + HID_LOGICAL_MIN ( 1 ) ,\ + HID_LOGICAL_MAX ( 8 ) ,\ + HID_PHYSICAL_MIN ( 0 ) ,\ + HID_PHYSICAL_MAX_N ( 315, 2 ) ,\ + HID_REPORT_COUNT ( 1 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + /* 32 bit Button Map */ \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\ + HID_USAGE_MIN ( 1 ) ,\ + HID_USAGE_MAX ( 32 ) ,\ + HID_LOGICAL_MIN ( 0 ) ,\ + HID_LOGICAL_MAX ( 1 ) ,\ + HID_REPORT_COUNT ( 32 ) ,\ + HID_REPORT_SIZE ( 1 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + HID_COLLECTION_END \ + +// HID Generic Input & Output +// - 1st parameter is report size (mandatory) +// - 2nd parameter is report id HID_REPORT_ID(n) (optional) +#define TUD_HID_REPORT_DESC_GENERIC_INOUT(report_size, ...) \ + HID_USAGE_PAGE_N ( HID_USAGE_PAGE_VENDOR, 2 ),\ + HID_USAGE ( 0x01 ),\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ),\ + /* Report ID if any */\ + __VA_ARGS__ \ + /* Input */ \ + HID_USAGE ( 0x02 ),\ + HID_LOGICAL_MIN ( 0x00 ),\ + HID_LOGICAL_MAX_N ( 0xff, 2 ),\ + HID_REPORT_SIZE ( 8 ),\ + HID_REPORT_COUNT( report_size ),\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\ + /* Output */ \ + HID_USAGE ( 0x03 ),\ + HID_LOGICAL_MIN ( 0x00 ),\ + HID_LOGICAL_MAX_N ( 0xff, 2 ),\ + HID_REPORT_SIZE ( 8 ),\ + HID_REPORT_COUNT( report_size ),\ + HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\ + HID_COLLECTION_END \ + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void hidd_init (void); +void hidd_reset (uint8_t rhport); +uint16_t hidd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +bool hidd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_HID_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.c b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.c new file mode 100644 index 00000000..ca745464 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.c @@ -0,0 +1,676 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUH_ENABLED && CFG_TUH_HID) + +#include "host/usbh.h" +#include "host/usbh_classdriver.h" + +#include "hid_host.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +typedef struct +{ + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; + + uint8_t itf_protocol; // None, Keyboard, Mouse + uint8_t protocol_mode; // Boot (0) or Report protocol (1) + + uint8_t report_desc_type; + uint16_t report_desc_len; + + uint16_t epin_size; + uint16_t epout_size; + + uint8_t epin_buf[CFG_TUH_HID_EPIN_BUFSIZE]; + uint8_t epout_buf[CFG_TUH_HID_EPOUT_BUFSIZE]; +} hidh_interface_t; + +typedef struct +{ + uint8_t inst_count; + hidh_interface_t instances[CFG_TUH_HID]; +} hidh_device_t; + +static hidh_device_t _hidh_dev[CFG_TUH_DEVICE_MAX]; + +//------------- Internal prototypes -------------// + +// Get HID device & interface +TU_ATTR_ALWAYS_INLINE static inline hidh_device_t* get_dev(uint8_t dev_addr); +TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_instance(uint8_t dev_addr, uint8_t instance); +static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf); +static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr); + +//--------------------------------------------------------------------+ +// Interface API +//--------------------------------------------------------------------+ + +uint8_t tuh_hid_instance_count(uint8_t dev_addr) +{ + return get_dev(dev_addr)->inst_count; +} + +bool tuh_hid_mounted(uint8_t dev_addr, uint8_t instance) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + return (hid_itf->ep_in != 0) || (hid_itf->ep_out != 0); +} + +uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + return hid_itf->itf_protocol; +} + +//--------------------------------------------------------------------+ +// Control Endpoint API +//--------------------------------------------------------------------+ + +uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + return hid_itf->protocol_mode; +} + +static void set_protocol_complete(tuh_xfer_t* xfer) +{ + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const daddr = xfer->daddr; + uint8_t const instance = get_instance_id_by_itfnum(daddr, itf_num); + hidh_interface_t* hid_itf = get_instance(daddr, instance); + + if (XFER_RESULT_SUCCESS == xfer->result) + { + hid_itf->protocol_mode = (uint8_t) tu_le16toh(xfer->setup->wValue); + } + + if (tuh_hid_set_protocol_complete_cb) + { + tuh_hid_set_protocol_complete_cb(daddr, instance, hid_itf->protocol_mode); + } +} + + +static bool _hidh_set_protocol(uint8_t dev_addr, uint8_t itf_num, uint8_t protocol, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + TU_LOG2("HID Set Protocol = %d\r\n", protocol); + + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = HID_REQ_CONTROL_SET_PROTOCOL, + .wValue = protocol, + .wIndex = itf_num, + .wLength = 0 + }; + + tuh_xfer_t xfer = + { + .daddr = dev_addr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb, + .user_data = user_data + }; + + TU_ASSERT( tuh_control_xfer(&xfer) ); + return true; +} + +bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + TU_VERIFY(hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE); + + return _hidh_set_protocol(dev_addr, hid_itf->itf_num, protocol, set_protocol_complete, 0); +} + +static void set_report_complete(tuh_xfer_t* xfer) +{ + TU_LOG2("HID Set Report complete\r\n"); + + if (tuh_hid_set_report_complete_cb) + { + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const instance = get_instance_id_by_itfnum(xfer->daddr, itf_num); + + uint8_t const report_type = tu_u16_high(xfer->setup->wValue); + uint8_t const report_id = tu_u16_low(xfer->setup->wValue); + + tuh_hid_set_report_complete_cb(xfer->daddr, instance, report_id, report_type, + (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0); + } +} + +bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + TU_LOG2("HID Set Report: id = %u, type = %u, len = %u\r\n", report_id, report_type, len); + + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = HID_REQ_CONTROL_SET_REPORT, + .wValue = tu_u16(report_type, report_id), + .wIndex = hid_itf->itf_num, + .wLength = len + }; + + tuh_xfer_t xfer = + { + .daddr = dev_addr, + .ep_addr = 0, + .setup = &request, + .buffer = report, + .complete_cb = set_report_complete, + .user_data = 0 + }; + + TU_ASSERT( tuh_control_xfer(&xfer) ); + return true; +} + +static bool _hidh_set_idle(uint8_t dev_addr, uint8_t itf_num, uint16_t idle_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + // SET IDLE request, device can stall if not support this request + TU_LOG2("HID Set Idle \r\n"); + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = HID_REQ_CONTROL_SET_IDLE, + .wValue = idle_rate, + .wIndex = itf_num, + .wLength = 0 + }; + + tuh_xfer_t xfer = + { + .daddr = dev_addr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb, + .user_data = user_data + }; + + TU_ASSERT( tuh_control_xfer(&xfer) ); + + return true; +} + +//--------------------------------------------------------------------+ +// Interrupt Endpoint API +//--------------------------------------------------------------------+ + +bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + + // claim endpoint + TU_VERIFY( usbh_edpt_claim(dev_addr, hid_itf->ep_in) ); + + if ( !usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size) ) + { + usbh_edpt_claim(dev_addr, hid_itf->ep_in); + return false; + } + + return true; +} + +//bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance) +//{ +// TU_VERIFY(tuh_n_hid_n_mounted(dev_addr, instance)); +// +// hidh_interface_t* hid_itf = get_instance(dev_addr, instance); +// return !usbh_edpt_busy(dev_addr, hid_itf->ep_in); +//} + +//void tuh_hid_send_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t const* report, uint16_t len); + +//--------------------------------------------------------------------+ +// USBH API +//--------------------------------------------------------------------+ +void hidh_init(void) +{ + tu_memclr(_hidh_dev, sizeof(_hidh_dev)); +} + +bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) result; + + uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const instance = get_instance_id_by_epaddr(dev_addr, ep_addr); + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + + if ( dir == TUSB_DIR_IN ) + { + TU_LOG2(" Get Report callback (%u, %u)\r\n", dev_addr, instance); + TU_LOG3_MEM(hid_itf->epin_buf, xferred_bytes, 2); + tuh_hid_report_received_cb(dev_addr, instance, hid_itf->epin_buf, (uint16_t) xferred_bytes); + }else + { + if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(dev_addr, instance, hid_itf->epout_buf, (uint16_t) xferred_bytes); + } + + return true; +} + +void hidh_close(uint8_t dev_addr) +{ + TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); + + hidh_device_t* hid_dev = get_dev(dev_addr); + + if (tuh_hid_umount_cb) + { + for (uint8_t inst = 0; inst < hid_dev->inst_count; inst++ ) tuh_hid_umount_cb(dev_addr, inst); + } + + tu_memclr(hid_dev, sizeof(hidh_device_t)); +} + +//--------------------------------------------------------------------+ +// Enumeration +//--------------------------------------------------------------------+ + +bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) +{ + (void) rhport; + (void) max_len; + + TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass); + + TU_LOG2("[%u] HID opening Interface %u\r\n", dev_addr, desc_itf->bInterfaceNumber); + + // len = interface + hid + n*endpoints + uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); + TU_ASSERT(max_len >= drv_len); + + uint8_t const *p_desc = (uint8_t const *) desc_itf; + + //------------- HID descriptor -------------// + p_desc = tu_desc_next(p_desc); + tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc; + TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType); + + // not enough interface, try to increase CFG_TUH_HID + // TODO multiple devices + hidh_device_t* hid_dev = get_dev(dev_addr); + TU_ASSERT(hid_dev->inst_count < CFG_TUH_HID, 0); + + hidh_interface_t* hid_itf = get_instance(dev_addr, hid_dev->inst_count); + + //------------- Endpoint Descriptors -------------// + p_desc = tu_desc_next(p_desc); + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; + + for(int i = 0; i < desc_itf->bNumEndpoints; i++) + { + TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType); + TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) ); + + if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) + { + hid_itf->ep_in = desc_ep->bEndpointAddress; + hid_itf->epin_size = tu_edpt_packet_size(desc_ep); + } + else + { + hid_itf->ep_out = desc_ep->bEndpointAddress; + hid_itf->epout_size = tu_edpt_packet_size(desc_ep); + } + + p_desc = tu_desc_next(p_desc); + desc_ep = (tusb_desc_endpoint_t const *) p_desc; + } + + hid_dev->inst_count++; + + hid_itf->itf_num = desc_itf->bInterfaceNumber; + + // Assume bNumDescriptors = 1 + hid_itf->report_desc_type = desc_hid->bReportType; + hid_itf->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength); + + // Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config + hid_itf->protocol_mode = HID_PROTOCOL_BOOT; + if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass ) hid_itf->itf_protocol = desc_itf->bInterfaceProtocol; + + return true; +} + +//--------------------------------------------------------------------+ +// Set Configure +//--------------------------------------------------------------------+ + +enum { + CONFG_SET_IDLE, + CONFIG_SET_PROTOCOL, + CONFIG_GET_REPORT_DESC, + CONFIG_COMPLETE +}; + +static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len); +static void process_set_config(tuh_xfer_t* xfer); + +bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num) +{ + tusb_control_request_t request; + request.wIndex = tu_htole16((uint16_t) itf_num); + + tuh_xfer_t xfer; + xfer.daddr = dev_addr; + xfer.result = XFER_RESULT_SUCCESS; + xfer.setup = &request; + xfer.user_data = CONFG_SET_IDLE; + + // fake request to kick-off the set config process + process_set_config(&xfer); + + return true; +} + +static void process_set_config(tuh_xfer_t* xfer) +{ + // Stall is a valid response for SET_IDLE, therefore we could ignore its result + if ( xfer->setup->bRequest != HID_REQ_CONTROL_SET_IDLE ) + { + TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, ); + } + + uintptr_t const state = xfer->user_data; + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const daddr = xfer->daddr; + + uint8_t const instance = get_instance_id_by_itfnum(daddr, itf_num); + hidh_interface_t* hid_itf = get_instance(daddr, instance); + + switch(state) + { + case CONFG_SET_IDLE: + { + // Idle rate = 0 mean only report when there is changes + const uint16_t idle_rate = 0; + const uintptr_t next_state = (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? CONFIG_SET_PROTOCOL : CONFIG_GET_REPORT_DESC; + _hidh_set_idle(daddr, itf_num, idle_rate, process_set_config, next_state); + } + break; + + case CONFIG_SET_PROTOCOL: + _hidh_set_protocol(daddr, hid_itf->itf_num, HID_PROTOCOL_BOOT, process_set_config, CONFIG_GET_REPORT_DESC); + break; + + case CONFIG_GET_REPORT_DESC: + // Get Report Descriptor if possible + // using usbh enumeration buffer since report descriptor can be very long + if( hid_itf->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE ) + { + TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", hid_itf->report_desc_len); + + // Driver is mounted without report descriptor + config_driver_mount_complete(daddr, instance, NULL, 0); + }else + { + tuh_descriptor_get_hid_report(daddr, itf_num, hid_itf->report_desc_type, 0, usbh_get_enum_buf(), hid_itf->report_desc_len, process_set_config, CONFIG_COMPLETE); + } + break; + + case CONFIG_COMPLETE: + { + uint8_t const* desc_report = usbh_get_enum_buf(); + uint16_t const desc_len = tu_le16toh(xfer->setup->wLength); + + config_driver_mount_complete(daddr, instance, desc_report, desc_len); + } + break; + + default: break; + } +} + +static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + + // enumeration is complete + tuh_hid_mount_cb(dev_addr, instance, desc_report, desc_len); + + // notify usbh that driver enumeration is complete + usbh_driver_set_config_complete(dev_addr, hid_itf->itf_num); +} + +//--------------------------------------------------------------------+ +// Report Descriptor Parser +//--------------------------------------------------------------------+ + +uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) +{ + // Report Item 6.2.2.2 USB HID 1.11 + union TU_ATTR_PACKED + { + uint8_t byte; + struct TU_ATTR_PACKED + { + uint8_t size : 2; + uint8_t type : 2; + uint8_t tag : 4; + }; + } header; + + tu_memclr(report_info_arr, arr_count*sizeof(tuh_hid_report_info_t)); + + uint8_t report_num = 0; + tuh_hid_report_info_t* info = report_info_arr; + + // current parsed report count & size from descriptor +// uint8_t ri_report_count = 0; +// uint8_t ri_report_size = 0; + + uint8_t ri_collection_depth = 0; + + while(desc_len && report_num < arr_count) + { + header.byte = *desc_report++; + desc_len--; + + uint8_t const tag = header.tag; + uint8_t const type = header.type; + uint8_t const size = header.size; + + uint8_t const data8 = desc_report[0]; + + TU_LOG(3, "tag = %d, type = %d, size = %d, data = ", tag, type, size); + for(uint32_t i=0; iusage_page, desc_report, size); + break; + + case RI_GLOBAL_LOGICAL_MIN : break; + case RI_GLOBAL_LOGICAL_MAX : break; + case RI_GLOBAL_PHYSICAL_MIN : break; + case RI_GLOBAL_PHYSICAL_MAX : break; + + case RI_GLOBAL_REPORT_ID: + info->report_id = data8; + break; + + case RI_GLOBAL_REPORT_SIZE: +// ri_report_size = data8; + break; + + case RI_GLOBAL_REPORT_COUNT: +// ri_report_count = data8; + break; + + case RI_GLOBAL_UNIT_EXPONENT : break; + case RI_GLOBAL_UNIT : break; + case RI_GLOBAL_PUSH : break; + case RI_GLOBAL_POP : break; + + default: break; + } + break; + + case RI_TYPE_LOCAL: + switch(tag) + { + case RI_LOCAL_USAGE: + // only take in account the "usage" before starting REPORT ID + if ( ri_collection_depth == 0 ) info->usage = data8; + break; + + case RI_LOCAL_USAGE_MIN : break; + case RI_LOCAL_USAGE_MAX : break; + case RI_LOCAL_DESIGNATOR_INDEX : break; + case RI_LOCAL_DESIGNATOR_MIN : break; + case RI_LOCAL_DESIGNATOR_MAX : break; + case RI_LOCAL_STRING_INDEX : break; + case RI_LOCAL_STRING_MIN : break; + case RI_LOCAL_STRING_MAX : break; + case RI_LOCAL_DELIMITER : break; + default: break; + } + break; + + // error + default: break; + } + + desc_report += size; + desc_len -= size; + } + + for ( uint8_t i = 0; i < report_num; i++ ) + { + info = report_info_arr+i; + TU_LOG2("%u: id = %u, usage_page = %u, usage = %u\r\n", i, info->report_id, info->usage_page, info->usage); + } + + return report_num; +} + +//--------------------------------------------------------------------+ +// Helper +//--------------------------------------------------------------------+ + +// Get Device by address +TU_ATTR_ALWAYS_INLINE static inline hidh_device_t* get_dev(uint8_t dev_addr) +{ + return &_hidh_dev[dev_addr-1]; +} + +// Get Interface by instance number +TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_instance(uint8_t dev_addr, uint8_t instance) +{ + return &_hidh_dev[dev_addr-1].instances[instance]; +} + +// Get instance ID by interface number +static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf) +{ + for ( uint8_t inst = 0; inst < CFG_TUH_HID; inst++ ) + { + hidh_interface_t *hid = get_instance(dev_addr, inst); + + if ( (hid->itf_num == itf) && (hid->ep_in || hid->ep_out) ) return inst; + } + + return 0xff; +} + +// Get instance ID by endpoint address +static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr) +{ + for ( uint8_t inst = 0; inst < CFG_TUH_HID; inst++ ) + { + hidh_interface_t *hid = get_instance(dev_addr, inst); + + if ( (ep_addr == hid->ep_in) || ( ep_addr == hid->ep_out) ) return inst; + } + + return 0xff; +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.h b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.h new file mode 100644 index 00000000..fe09b03b --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.h @@ -0,0 +1,152 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_HID_HOST_H_ +#define _TUSB_HID_HOST_H_ + +#include "hid.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Class Driver Configuration +//--------------------------------------------------------------------+ + +// TODO Highspeed interrupt can be up to 512 bytes +#ifndef CFG_TUH_HID_EPIN_BUFSIZE +#define CFG_TUH_HID_EPIN_BUFSIZE 64 +#endif + +#ifndef CFG_TUH_HID_EPOUT_BUFSIZE +#define CFG_TUH_HID_EPOUT_BUFSIZE 64 +#endif + + +typedef struct +{ + uint8_t report_id; + uint8_t usage; + uint16_t usage_page; + + // TODO still use the endpoint size for now +// uint8_t in_len; // length of IN report +// uint8_t out_len; // length of OUT report +} tuh_hid_report_info_t; + +//--------------------------------------------------------------------+ +// Interface API +//--------------------------------------------------------------------+ + +// Get the number of HID instances +uint8_t tuh_hid_instance_count(uint8_t dev_addr); + +// Check if HID instance is mounted +bool tuh_hid_mounted(uint8_t dev_addr, uint8_t instance); + +// Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values +uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance); + +// Parse report descriptor into array of report_info struct and return number of reports. +// For complicated report, application should write its own parser. +uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED; + +//--------------------------------------------------------------------+ +// Control Endpoint API +//--------------------------------------------------------------------+ + +// Get current protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) +// Note: Device will be initialized in Boot protocol for simplicity. +// Application can use set_protocol() to switch back to Report protocol. +uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance); + +// Set protocol to HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) +// This function is only supported by Boot interface (tuh_n_hid_interface_protocol() != NONE) +bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol); + +// Set Report using control endpoint +// report_type is either Intput, Output or Feature, (value from hid_report_type_t) +bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, void* report, uint16_t len); + +//--------------------------------------------------------------------+ +// Interrupt Endpoint API +//--------------------------------------------------------------------+ + +// Check if the interface is ready to use +//bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance); + +// Try to receive next report on Interrupt Endpoint. Immediately return +// - true If succeeded, tuh_hid_report_received_cb() callback will be invoked when report is available +// - false if failed to queue the transfer e.g endpoint is busy +bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance); + +// Send report using interrupt endpoint +// If report_id > 0 (composite), it will be sent as 1st byte, then report contents. Otherwise only report content is sent. +//void tuh_hid_send_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t const* report, uint16_t len); + +//--------------------------------------------------------------------+ +// Callbacks (Weak is optional) +//--------------------------------------------------------------------+ + +// Invoked when device with hid interface is mounted +// Report descriptor is also available for use. tuh_hid_parse_report_descriptor() +// can be used to parse common/simple enough descriptor. +// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped +// therefore report_desc = NULL, desc_len = 0 +void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report_desc, uint16_t desc_len); + +// Invoked when device with hid interface is un-mounted +TU_ATTR_WEAK void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance); + +// Invoked when received report from device via interrupt endpoint +// Note: if there is report ID (composite), it is 1st byte of report +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); + +// Invoked when sent report to device successfully via interrupt endpoint +TU_ATTR_WEAK void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); + +// Invoked when Sent Report to device via either control endpoint +// len = 0 indicate there is error in the transfer e.g stalled response +TU_ATTR_WEAK void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len); + +// Invoked when Set Protocol request is complete +TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t protocol); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void hidh_init (void); +bool hidh_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); +bool hidh_set_config (uint8_t dev_addr, uint8_t itf_num); +bool hidh_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); +void hidh_close (uint8_t dev_addr); + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_HID_HOST_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi.h b/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi.h new file mode 100644 index 00000000..74dc4174 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi.h @@ -0,0 +1,212 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup group_class + * \defgroup ClassDriver_CDC Communication Device Class (CDC) + * Currently only Abstract Control Model subclass is supported + * @{ */ + +#ifndef _TUSB_MIDI_H__ +#define _TUSB_MIDI_H__ + +#include "common/tusb_common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Class Specific Descriptor +//--------------------------------------------------------------------+ + +typedef enum +{ + MIDI_CS_INTERFACE_HEADER = 0x01, + MIDI_CS_INTERFACE_IN_JACK = 0x02, + MIDI_CS_INTERFACE_OUT_JACK = 0x03, + MIDI_CS_INTERFACE_ELEMENT = 0x04, +} midi_cs_interface_subtype_t; + +typedef enum +{ + MIDI_CS_ENDPOINT_GENERAL = 0x01 +} midi_cs_endpoint_subtype_t; + +typedef enum +{ + MIDI_JACK_EMBEDDED = 0x01, + MIDI_JACK_EXTERNAL = 0x02 +} midi_jack_type_t; + +typedef enum +{ + MIDI_CIN_MISC = 0, + MIDI_CIN_CABLE_EVENT = 1, + MIDI_CIN_SYSCOM_2BYTE = 2, // 2 byte system common message e.g MTC, SongSelect + MIDI_CIN_SYSCOM_3BYTE = 3, // 3 byte system common message e.g SPP + MIDI_CIN_SYSEX_START = 4, // SysEx starts or continue + MIDI_CIN_SYSEX_END_1BYTE = 5, // SysEx ends with 1 data, or 1 byte system common message + MIDI_CIN_SYSEX_END_2BYTE = 6, // SysEx ends with 2 data + MIDI_CIN_SYSEX_END_3BYTE = 7, // SysEx ends with 3 data + MIDI_CIN_NOTE_ON = 8, + MIDI_CIN_NOTE_OFF = 9, + MIDI_CIN_POLY_KEYPRESS = 10, + MIDI_CIN_CONTROL_CHANGE = 11, + MIDI_CIN_PROGRAM_CHANGE = 12, + MIDI_CIN_CHANNEL_PRESSURE = 13, + MIDI_CIN_PITCH_BEND_CHANGE = 14, + MIDI_CIN_1BYTE_DATA = 15 +} midi_code_index_number_t; + +// MIDI 1.0 status byte +enum +{ + //------------- System Exclusive -------------// + MIDI_STATUS_SYSEX_START = 0xF0, + MIDI_STATUS_SYSEX_END = 0xF7, + + //------------- System Common -------------// + MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME = 0xF1, + MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER = 0xF2, + MIDI_STATUS_SYSCOM_SONG_SELECT = 0xF3, + // F4, F5 is undefined + MIDI_STATUS_SYSCOM_TUNE_REQUEST = 0xF6, + + //------------- System RealTime -------------// + MIDI_STATUS_SYSREAL_TIMING_CLOCK = 0xF8, + // 0xF9 is undefined + MIDI_STATUS_SYSREAL_START = 0xFA, + MIDI_STATUS_SYSREAL_CONTINUE = 0xFB, + MIDI_STATUS_SYSREAL_STOP = 0xFC, + // 0xFD is undefined + MIDI_STATUS_SYSREAL_ACTIVE_SENSING = 0xFE, + MIDI_STATUS_SYSREAL_SYSTEM_RESET = 0xFF, +}; + +/// MIDI Interface Header Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType + uint16_t bcdMSC ; ///< MidiStreaming SubClass release number in Binary-Coded Decimal + uint16_t wTotalLength ; +} midi_desc_header_t; + +/// MIDI In Jack Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType + uint8_t bJackType ; ///< Embedded or External + uint8_t bJackID ; ///< Unique ID for MIDI IN Jack + uint8_t iJack ; ///< string descriptor +} midi_desc_in_jack_t; + + +/// MIDI Out Jack Descriptor with single pin +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType + uint8_t bJackType ; ///< Embedded or External + uint8_t bJackID ; ///< Unique ID for MIDI IN Jack + uint8_t bNrInputPins; + + uint8_t baSourceID; + uint8_t baSourcePin; + + uint8_t iJack ; ///< string descriptor +} midi_desc_out_jack_t ; + +/// MIDI Out Jack Descriptor with multiple pins +#define midi_desc_out_jack_n_t(input_num) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength ; \ + uint8_t bDescriptorType ; \ + uint8_t bDescriptorSubType ; \ + uint8_t bJackType ; \ + uint8_t bJackID ; \ + uint8_t bNrInputPins ; \ + struct TU_ATTR_PACKED { \ + uint8_t baSourceID; \ + uint8_t baSourcePin; \ + } pins[input_num]; \ + uint8_t iJack ; \ + } + +/// MIDI Element Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType + uint8_t bElementID; + + uint8_t bNrInputPins; + uint8_t baSourceID; + uint8_t baSourcePin; + + uint8_t bNrOutputPins; + uint8_t bInTerminalLink; + uint8_t bOutTerminalLink; + uint8_t bElCapsSize; + + uint16_t bmElementCaps; + uint8_t iElement; +} midi_desc_element_t; + +/// MIDI Element Descriptor with multiple pins +#define midi_desc_element_n_t(input_num) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint8_t bDescriptorSubType; \ + uint8_t bElementID; \ + uint8_t bNrInputPins; \ + struct TU_ATTR_PACKED { \ + uint8_t baSourceID; \ + uint8_t baSourcePin; \ + } pins[input_num]; \ + uint8_t bNrOutputPins; \ + uint8_t bInTerminalLink; \ + uint8_t bOutTerminalLink; \ + uint8_t bElCapsSize; \ + uint16_t bmElementCaps; \ + uint8_t iElement; \ + } + +/** @} */ + +#ifdef __cplusplus + } +#endif + +#endif + +/** @} */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.c new file mode 100644 index 00000000..de41706e --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.c @@ -0,0 +1,545 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_MIDI) + +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "midi_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +typedef struct +{ + uint8_t buffer[4]; + uint8_t index; + uint8_t total; +}midid_stream_t; + +typedef struct +{ + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; + + // For Stream read()/write() API + // Messages are always 4 bytes long, queue them for reading and writing so the + // callers can use the Stream interface with single-byte read/write calls. + midid_stream_t stream_write; + midid_stream_t stream_read; + + /*------------- From this point, data is not cleared by bus reset -------------*/ + // FIFO + tu_fifo_t rx_ff; + tu_fifo_t tx_ff; + uint8_t rx_ff_buf[CFG_TUD_MIDI_RX_BUFSIZE]; + uint8_t tx_ff_buf[CFG_TUD_MIDI_TX_BUFSIZE]; + + #if CFG_FIFO_MUTEX + osal_mutex_def_t rx_ff_mutex; + osal_mutex_def_t tx_ff_mutex; + #endif + + // Endpoint Transfer buffer + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_MIDI_EP_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_MIDI_EP_BUFSIZE]; + +} midid_interface_t; + +#define ITF_MEM_RESET_SIZE offsetof(midid_interface_t, rx_ff) + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +CFG_TUSB_MEM_SECTION midid_interface_t _midid_itf[CFG_TUD_MIDI]; + +bool tud_midi_n_mounted (uint8_t itf) +{ + midid_interface_t* midi = &_midid_itf[itf]; + return midi->ep_in && midi->ep_out; +} + +static void _prep_out_transaction (midid_interface_t* p_midi) +{ + uint8_t const rhport = 0; + uint16_t available = tu_fifo_remaining(&p_midi->rx_ff); + + // Prepare for incoming data but only allow what we can store in the ring buffer. + // TODO Actually we can still carry out the transfer, keeping count of received bytes + // and slowly move it to the FIFO when read(). + // This pre-check reduces endpoint claiming + TU_VERIFY(available >= sizeof(p_midi->epout_buf), ); + + // claim endpoint + TU_VERIFY(usbd_edpt_claim(rhport, p_midi->ep_out), ); + + // fifo can be changed before endpoint is claimed + available = tu_fifo_remaining(&p_midi->rx_ff); + + if ( available >= sizeof(p_midi->epout_buf) ) { + usbd_edpt_xfer(rhport, p_midi->ep_out, p_midi->epout_buf, sizeof(p_midi->epout_buf)); + }else + { + // Release endpoint since we don't make any transfer + usbd_edpt_release(rhport, p_midi->ep_out); + } +} + +//--------------------------------------------------------------------+ +// READ API +//--------------------------------------------------------------------+ +uint32_t tud_midi_n_available(uint8_t itf, uint8_t cable_num) +{ + (void) cable_num; + + midid_interface_t* midi = &_midid_itf[itf]; + midid_stream_t const* stream = &midi->stream_read; + + // when using with packet API stream total & index are both zero + return tu_fifo_count(&midi->rx_ff) + (uint8_t) (stream->total - stream->index); +} + +uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize) +{ + (void) cable_num; + TU_VERIFY(bufsize, 0); + + uint8_t* buf8 = (uint8_t*) buffer; + + midid_interface_t* midi = &_midid_itf[itf]; + midid_stream_t* stream = &midi->stream_read; + + uint32_t total_read = 0; + while( bufsize ) + { + // Get new packet from fifo, then set packet expected bytes + if ( stream->total == 0 ) + { + // return if there is no more data from fifo + if ( !tud_midi_n_packet_read(itf, stream->buffer) ) return total_read; + + uint8_t const code_index = stream->buffer[0] & 0x0f; + + // MIDI 1.0 Table 4-1: Code Index Number Classifications + switch(code_index) + { + case MIDI_CIN_MISC: + case MIDI_CIN_CABLE_EVENT: + // These are reserved and unused, possibly issue somewhere, skip this packet + return 0; + break; + + case MIDI_CIN_SYSEX_END_1BYTE: + case MIDI_CIN_1BYTE_DATA: + stream->total = 1; + break; + + case MIDI_CIN_SYSCOM_2BYTE : + case MIDI_CIN_SYSEX_END_2BYTE : + case MIDI_CIN_PROGRAM_CHANGE : + case MIDI_CIN_CHANNEL_PRESSURE : + stream->total = 2; + break; + + default: + stream->total = 3; + break; + } + } + + // Copy data up to bufsize + uint8_t const count = (uint8_t) tu_min32(stream->total - stream->index, bufsize); + + // Skip the header (1st byte) in the buffer + memcpy(buf8, stream->buffer + 1 + stream->index, count); + + total_read += count; + stream->index += count; + buf8 += count; + bufsize -= count; + + // complete current event packet, reset stream + if ( stream->total == stream->index ) + { + stream->index = 0; + stream->total = 0; + } + } + + return total_read; +} + +bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]) +{ + midid_interface_t* midi = &_midid_itf[itf]; + TU_VERIFY(midi->ep_out); + + uint32_t const num_read = tu_fifo_read_n(&midi->rx_ff, packet, 4); + _prep_out_transaction(midi); + return (num_read == 4); +} + +//--------------------------------------------------------------------+ +// WRITE API +//--------------------------------------------------------------------+ + +static uint32_t write_flush(midid_interface_t* midi) +{ + // No data to send + if ( !tu_fifo_count(&midi->tx_ff) ) return 0; + + uint8_t const rhport = 0; + + // skip if previous transfer not complete + TU_VERIFY( usbd_edpt_claim(rhport, midi->ep_in), 0 ); + + uint16_t count = tu_fifo_read_n(&midi->tx_ff, midi->epin_buf, CFG_TUD_MIDI_EP_BUFSIZE); + + if (count) + { + TU_ASSERT( usbd_edpt_xfer(rhport, midi->ep_in, midi->epin_buf, count), 0 ); + return count; + }else + { + // Release endpoint since we don't make any transfer + usbd_edpt_release(rhport, midi->ep_in); + return 0; + } +} + +uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) +{ + midid_interface_t* midi = &_midid_itf[itf]; + TU_VERIFY(midi->ep_in, 0); + + midid_stream_t* stream = &midi->stream_write; + + uint32_t i = 0; + while ( (i < bufsize) && (tu_fifo_remaining(&midi->tx_ff) >= 4) ) + { + uint8_t const data = buffer[i]; + i++; + + if ( stream->index == 0 ) + { + //------------- New event packet -------------// + + uint8_t const msg = data >> 4; + + stream->index = 2; + stream->buffer[1] = data; + + // Check to see if we're still in a SysEx transmit. + if ( stream->buffer[0] == MIDI_CIN_SYSEX_START ) + { + if ( data == MIDI_STATUS_SYSEX_END ) + { + stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; + stream->total = 2; + } + else + { + stream->total = 4; + } + } + else if ( (msg >= 0x8 && msg <= 0xB) || msg == 0xE ) + { + // Channel Voice Messages + stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg); + stream->total = 4; + } + else if ( msg == 0xC || msg == 0xD) + { + // Channel Voice Messages, two-byte variants (Program Change and Channel Pressure) + stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg); + stream->total = 3; + } + else if ( msg == 0xf ) + { + // System message + if ( data == MIDI_STATUS_SYSEX_START ) + { + stream->buffer[0] = MIDI_CIN_SYSEX_START; + stream->total = 4; + } + else if ( data == MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME || data == MIDI_STATUS_SYSCOM_SONG_SELECT ) + { + stream->buffer[0] = MIDI_CIN_SYSCOM_2BYTE; + stream->total = 3; + } + else if ( data == MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER ) + { + stream->buffer[0] = MIDI_CIN_SYSCOM_3BYTE; + stream->total = 4; + } + else + { + stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; + stream->total = 2; + } + } + else + { + // Pack individual bytes if we don't support packing them into words. + stream->buffer[0] = (uint8_t) (cable_num << 4 | 0xf); + stream->buffer[2] = 0; + stream->buffer[3] = 0; + stream->index = 2; + stream->total = 2; + } + } + else + { + //------------- On-going (buffering) packet -------------// + + TU_ASSERT(stream->index < 4, i); + stream->buffer[stream->index] = data; + stream->index++; + + // See if this byte ends a SysEx. + if ( stream->buffer[0] == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END ) + { + stream->buffer[0] = MIDI_CIN_SYSEX_START + (stream->index - 1); + stream->total = stream->index; + } + } + + // Send out packet + if ( stream->index == stream->total ) + { + // zeroes unused bytes + for(uint8_t idx = stream->total; idx < 4; idx++) stream->buffer[idx] = 0; + + uint16_t const count = tu_fifo_write_n(&midi->tx_ff, stream->buffer, 4); + + // complete current event packet, reset stream + stream->index = stream->total = 0; + + // FIFO overflown, since we already check fifo remaining. It is probably race condition + TU_ASSERT(count == 4, i); + } + } + + write_flush(midi); + + return i; +} + +bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]) +{ + midid_interface_t* midi = &_midid_itf[itf]; + TU_VERIFY(midi->ep_in); + + if (tu_fifo_remaining(&midi->tx_ff) < 4) return false; + + tu_fifo_write_n(&midi->tx_ff, packet, 4); + write_flush(midi); + + return true; +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void midid_init(void) +{ + tu_memclr(_midid_itf, sizeof(_midid_itf)); + + for(uint8_t i=0; irx_ff, midi->rx_ff_buf, CFG_TUD_MIDI_RX_BUFSIZE, 1, false); // true, true + tu_fifo_config(&midi->tx_ff, midi->tx_ff_buf, CFG_TUD_MIDI_TX_BUFSIZE, 1, false); // OBVS. + + #if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&midi->rx_ff, NULL, osal_mutex_create(&midi->rx_ff_mutex)); + tu_fifo_config_mutex(&midi->tx_ff, osal_mutex_create(&midi->tx_ff_mutex), NULL); + #endif + } +} + +void midid_reset(uint8_t rhport) +{ + (void) rhport; + + for(uint8_t i=0; irx_ff); + tu_fifo_clear(&midi->tx_ff); + } +} + +uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) +{ + // 1st Interface is Audio Control v1 + TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass && + AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass && + AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_itf->bInterfaceProtocol, 0); + + uint16_t drv_len = tu_desc_len(desc_itf); + uint8_t const * p_desc = tu_desc_next(desc_itf); + + // Skip Class Specific descriptors + while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) + { + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + // 2nd Interface is MIDI Streaming + TU_VERIFY(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); + tusb_desc_interface_t const * desc_midi = (tusb_desc_interface_t const *) p_desc; + + TU_VERIFY(TUSB_CLASS_AUDIO == desc_midi->bInterfaceClass && + AUDIO_SUBCLASS_MIDI_STREAMING == desc_midi->bInterfaceSubClass && + AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_midi->bInterfaceProtocol, 0); + + // Find available interface + midid_interface_t * p_midi = NULL; + for(uint8_t i=0; iitf_num = desc_midi->bInterfaceNumber; + (void) p_midi->itf_num; + + // next descriptor + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + + // Find and open endpoint descriptors + uint8_t found_endpoints = 0; + while ( (found_endpoints < desc_midi->bNumEndpoints) && (drv_len <= max_len) ) + { + if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + { + TU_ASSERT(usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0); + uint8_t ep_addr = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; + + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) + { + p_midi->ep_in = ep_addr; + } else { + p_midi->ep_out = ep_addr; + } + + // Class Specific MIDI Stream endpoint descriptor + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + + found_endpoints += 1; + } + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + // Prepare for incoming data + _prep_out_transaction(p_midi); + + return drv_len; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool midid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + (void) rhport; + (void) stage; + (void) request; + + // driver doesn't support any request yet + return false; +} + +bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) result; + (void) rhport; + + uint8_t itf; + midid_interface_t* p_midi; + + // Identify which interface to use + for (itf = 0; itf < CFG_TUD_MIDI; itf++) + { + p_midi = &_midid_itf[itf]; + if ( ( ep_addr == p_midi->ep_out ) || ( ep_addr == p_midi->ep_in ) ) break; + } + TU_ASSERT(itf < CFG_TUD_MIDI); + + // receive new data + if ( ep_addr == p_midi->ep_out ) + { + tu_fifo_write_n(&p_midi->rx_ff, p_midi->epout_buf, (uint16_t) xferred_bytes); + + // invoke receive callback if available + if (tud_midi_rx_cb) tud_midi_rx_cb(itf); + + // prepare for next + // TODO for now ep_out is not used by public API therefore there is no race condition, + // and does not need to claim like ep_in + _prep_out_transaction(p_midi); + } + else if ( ep_addr == p_midi->ep_in ) + { + if (0 == write_flush(p_midi)) + { + // If there is no data left, a ZLP should be sent if + // xferred_bytes is multiple of EP size and not zero + if ( !tu_fifo_count(&p_midi->tx_ff) && xferred_bytes && (0 == (xferred_bytes % CFG_TUD_MIDI_EP_BUFSIZE)) ) + { + if ( usbd_edpt_claim(rhport, p_midi->ep_in) ) + { + usbd_edpt_xfer(rhport, p_midi->ep_in, NULL, 0); + } + } + } + } + + return true; +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.h new file mode 100644 index 00000000..211edc8d --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.h @@ -0,0 +1,173 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_MIDI_DEVICE_H_ +#define _TUSB_MIDI_DEVICE_H_ + +#include "class/audio/audio.h" +#include "midi.h" + +//--------------------------------------------------------------------+ +// Class Driver Configuration +//--------------------------------------------------------------------+ + +#if !defined(CFG_TUD_MIDI_EP_BUFSIZE) && defined(CFG_TUD_MIDI_EPSIZE) + #warning CFG_TUD_MIDI_EPSIZE is renamed to CFG_TUD_MIDI_EP_BUFSIZE, please update to use the new name + #define CFG_TUD_MIDI_EP_BUFSIZE CFG_TUD_MIDI_EPSIZE +#endif + +#ifndef CFG_TUD_MIDI_EP_BUFSIZE + #define CFG_TUD_MIDI_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +/** \addtogroup MIDI_Serial Serial + * @{ + * \defgroup MIDI_Serial_Device Device + * @{ */ + +//--------------------------------------------------------------------+ +// Application API (Multiple Interfaces) +// CFG_TUD_MIDI > 1 +//--------------------------------------------------------------------+ + +// Check if midi interface is mounted +bool tud_midi_n_mounted (uint8_t itf); + +// Get the number of bytes available for reading +uint32_t tud_midi_n_available (uint8_t itf, uint8_t cable_num); + +// Read byte stream (legacy) +uint32_t tud_midi_n_stream_read (uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize); + +// Write byte Stream (legacy) +uint32_t tud_midi_n_stream_write (uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); + +// Read event packet (4 bytes) +bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]); + +// Write event packet (4 bytes) +bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]); + +//--------------------------------------------------------------------+ +// Application API (Single Interface) +//--------------------------------------------------------------------+ +static inline bool tud_midi_mounted (void); +static inline uint32_t tud_midi_available (void); + +static inline uint32_t tud_midi_stream_read (void* buffer, uint32_t bufsize); +static inline uint32_t tud_midi_stream_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); + +static inline bool tud_midi_packet_read (uint8_t packet[4]); +static inline bool tud_midi_packet_write (uint8_t const packet[4]); + +//------------- Deprecated API name -------------// +// TODO remove after 0.10.0 release + +TU_ATTR_DEPRECATED("tud_midi_read() is renamed to tud_midi_stream_read()") +static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize) +{ + return tud_midi_stream_read(buffer, bufsize); +} + +TU_ATTR_DEPRECATED("tud_midi_write() is renamed to tud_midi_stream_write()") +static inline uint32_t tud_midi_write(uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) +{ + return tud_midi_stream_write(cable_num, buffer, bufsize); +} + + +TU_ATTR_DEPRECATED("tud_midi_send() is renamed to tud_midi_packet_write()") +static inline bool tud_midi_send(uint8_t packet[4]) +{ + return tud_midi_packet_write(packet); +} + +TU_ATTR_DEPRECATED("tud_midi_receive() is renamed to tud_midi_packet_read()") +static inline bool tud_midi_receive(uint8_t packet[4]) +{ + return tud_midi_packet_read(packet); +} + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tud_midi_rx_cb(uint8_t itf); + +//--------------------------------------------------------------------+ +// Inline Functions +//--------------------------------------------------------------------+ + +static inline bool tud_midi_mounted (void) +{ + return tud_midi_n_mounted(0); +} + +static inline uint32_t tud_midi_available (void) +{ + return tud_midi_n_available(0, 0); +} + +static inline uint32_t tud_midi_stream_read (void* buffer, uint32_t bufsize) +{ + return tud_midi_n_stream_read(0, 0, buffer, bufsize); +} + +static inline uint32_t tud_midi_stream_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) +{ + return tud_midi_n_stream_write(0, cable_num, buffer, bufsize); +} + +static inline bool tud_midi_packet_read (uint8_t packet[4]) +{ + return tud_midi_n_packet_read(0, packet); +} + +static inline bool tud_midi_packet_write (uint8_t const packet[4]) +{ + return tud_midi_n_packet_write(0, packet); +} + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void midid_init (void); +void midid_reset (uint8_t rhport); +uint16_t midid_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool midid_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +bool midid_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_MIDI_DEVICE_H_ */ + +/** @} */ +/** @} */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc.h b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc.h new file mode 100644 index 00000000..84b6e4d7 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc.h @@ -0,0 +1,382 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_MSC_H_ +#define _TUSB_MSC_H_ + +#include "common/tusb_common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Mass Storage Class Constant +//--------------------------------------------------------------------+ +/// MassStorage Subclass +typedef enum +{ + MSC_SUBCLASS_RBC = 1 , ///< Reduced Block Commands (RBC) T10 Project 1240-D + MSC_SUBCLASS_SFF_MMC , ///< SFF-8020i, MMC-2 (ATAPI). Typically used by a CD/DVD device + MSC_SUBCLASS_QIC , ///< QIC-157. Typically used by a tape device + MSC_SUBCLASS_UFI , ///< UFI. Typically used by Floppy Disk Drive (FDD) device + MSC_SUBCLASS_SFF , ///< SFF-8070i. Can be used by Floppy Disk Drive (FDD) device + MSC_SUBCLASS_SCSI ///< SCSI transparent command set +}msc_subclass_type_t; + +enum { + MSC_CBW_SIGNATURE = 0x43425355, ///< Constant value of 43425355h (little endian) + MSC_CSW_SIGNATURE = 0x53425355 ///< Constant value of 53425355h (little endian) +}; + +/// \brief MassStorage Protocol. +/// \details CBI only approved to use with full-speed floopy disk & should not used with highspeed or device other than floopy +typedef enum +{ + MSC_PROTOCOL_CBI = 0 , ///< Control/Bulk/Interrupt protocol (with command completion interrupt) + MSC_PROTOCOL_CBI_NO_INTERRUPT = 1 , ///< Control/Bulk/Interrupt protocol (without command completion interrupt) + MSC_PROTOCOL_BOT = 0x50 ///< Bulk-Only Transport +}msc_protocol_type_t; + +/// MassStorage Class-Specific Control Request +typedef enum +{ + MSC_REQ_GET_MAX_LUN = 254, ///< The Get Max LUN device request is used to determine the number of logical units supported by the device. Logical Unit Numbers on the device shall be numbered contiguously starting from LUN 0 to a maximum LUN of 15 + MSC_REQ_RESET = 255 ///< This request is used to reset the mass storage device and its associated interface. This class-specific request shall ready the device for the next CBW from the host. +}msc_request_type_t; + +/// \brief Command Block Status Values +/// \details Indicates the success or failure of the command. The device shall set this byte to zero if the command completed +/// successfully. A non-zero value shall indicate a failure during command execution according to the following +typedef enum +{ + MSC_CSW_STATUS_PASSED = 0 , ///< MSC_CSW_STATUS_PASSED + MSC_CSW_STATUS_FAILED , ///< MSC_CSW_STATUS_FAILED + MSC_CSW_STATUS_PHASE_ERROR ///< MSC_CSW_STATUS_PHASE_ERROR +}msc_csw_status_t; + +/// Command Block Wrapper +typedef struct TU_ATTR_PACKED +{ + uint32_t signature; ///< Signature that helps identify this data packet as a CBW. The signature field shall contain the value 43425355h (little endian), indicating a CBW. + uint32_t tag; ///< Tag sent by the host. The device shall echo the contents of this field back to the host in the dCSWTagfield of the associated CSW. The dCSWTagpositively associates a CSW with the corresponding CBW. + uint32_t total_bytes; ///< The number of bytes of data that the host expects to transfer on the Bulk-In or Bulk-Out endpoint (as indicated by the Direction bit) during the execution of this command. If this field is zero, the device and the host shall transfer no data between the CBW and the associated CSW, and the device shall ignore the value of the Direction bit in bmCBWFlags. + uint8_t dir; ///< Bit 7 of this field define transfer direction \n - 0 : Data-Out from host to the device. \n - 1 : Data-In from the device to the host. + uint8_t lun; ///< The device Logical Unit Number (LUN) to which the command block is being sent. For devices that support multiple LUNs, the host shall place into this field the LUN to which this command block is addressed. Otherwise, the host shall set this field to zero. + uint8_t cmd_len; ///< The valid length of the CBWCBin bytes. This defines the valid length of the command block. The only legal values are 1 through 16 + uint8_t command[16]; ///< The command block to be executed by the device. The device shall interpret the first cmd_len bytes in this field as a command block +}msc_cbw_t; + +TU_VERIFY_STATIC(sizeof(msc_cbw_t) == 31, "size is not correct"); + +/// Command Status Wrapper +typedef struct TU_ATTR_PACKED +{ + uint32_t signature ; ///< Signature that helps identify this data packet as a CSW. The signature field shall contain the value 53425355h (little endian), indicating CSW. + uint32_t tag ; ///< The device shall set this field to the value received in the dCBWTag of the associated CBW. + uint32_t data_residue ; ///< For Data-Out the device shall report in the dCSWDataResiduethe difference between the amount of data expected as stated in the dCBWDataTransferLength, and the actual amount of data processed by the device. For Data-In the device shall report in the dCSWDataResiduethe difference between the amount of data expected as stated in the dCBWDataTransferLengthand the actual amount of relevant data sent by the device + uint8_t status ; ///< indicates the success or failure of the command. Values from \ref msc_csw_status_t +}msc_csw_t; + +TU_VERIFY_STATIC(sizeof(msc_csw_t) == 13, "size is not correct"); + +//--------------------------------------------------------------------+ +// SCSI Constant +//--------------------------------------------------------------------+ + +/// SCSI Command Operation Code +typedef enum +{ + SCSI_CMD_TEST_UNIT_READY = 0x00, ///< The SCSI Test Unit Ready command is used to determine if a device is ready to transfer data (read/write), i.e. if a disk has spun up, if a tape is loaded and ready etc. The device does not perform a self-test operation. + SCSI_CMD_INQUIRY = 0x12, ///< The SCSI Inquiry command is used to obtain basic information from a target device. + SCSI_CMD_MODE_SELECT_6 = 0x15, ///< provides a means for the application client to specify medium, logical unit, or peripheral device parameters to the device server. Device servers that implement the MODE SELECT(6) command shall also implement the MODE SENSE(6) command. Application clients should issue MODE SENSE(6) prior to each MODE SELECT(6) to determine supported mode pages, page lengths, and other parameters. + SCSI_CMD_MODE_SENSE_6 = 0x1A, ///< provides a means for a device server to report parameters to an application client. It is a complementary command to the MODE SELECT(6) command. Device servers that implement the MODE SENSE(6) command shall also implement the MODE SELECT(6) command. + SCSI_CMD_START_STOP_UNIT = 0x1B, + SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1E, + SCSI_CMD_READ_CAPACITY_10 = 0x25, ///< The SCSI Read Capacity command is used to obtain data capacity information from a target device. + SCSI_CMD_REQUEST_SENSE = 0x03, ///< The SCSI Request Sense command is part of the SCSI computer protocol standard. This command is used to obtain sense data -- status/error information -- from a target device. + SCSI_CMD_READ_FORMAT_CAPACITY = 0x23, ///< The command allows the Host to request a list of the possible format capacities for an installed writable media. This command also has the capability to report the writable capacity for a media when it is installed + SCSI_CMD_READ_10 = 0x28, ///< The READ (10) command requests that the device server read the specified logical block(s) and transfer them to the data-in buffer. + SCSI_CMD_WRITE_10 = 0x2A, ///< The WRITE (10) command requests thatthe device server transfer the specified logical block(s) from the data-out buffer and write them. +}scsi_cmd_type_t; + +/// SCSI Sense Key +typedef enum +{ + SCSI_SENSE_NONE = 0x00, ///< no specific Sense Key. This would be the case for a successful command + SCSI_SENSE_RECOVERED_ERROR = 0x01, ///< ndicates the last command completed successfully with some recovery action performed by the disc drive. + SCSI_SENSE_NOT_READY = 0x02, ///< Indicates the logical unit addressed cannot be accessed. + SCSI_SENSE_MEDIUM_ERROR = 0x03, ///< Indicates the command terminated with a non-recovered error condition. + SCSI_SENSE_HARDWARE_ERROR = 0x04, ///< Indicates the disc drive detected a nonrecoverable hardware failure while performing the command or during a self test. + SCSI_SENSE_ILLEGAL_REQUEST = 0x05, ///< Indicates an illegal parameter in the command descriptor block or in the additional parameters + SCSI_SENSE_UNIT_ATTENTION = 0x06, ///< Indicates the disc drive may have been reset. + SCSI_SENSE_DATA_PROTECT = 0x07, ///< Indicates that a command that reads or writes the medium was attempted on a block that is protected from this operation. The read or write operation is not performed. + SCSI_SENSE_FIRMWARE_ERROR = 0x08, ///< Vendor specific sense key. + SCSI_SENSE_ABORTED_COMMAND = 0x0b, ///< Indicates the disc drive aborted the command. + SCSI_SENSE_EQUAL = 0x0c, ///< Indicates a SEARCH DATA command has satisfied an equal comparison. + SCSI_SENSE_VOLUME_OVERFLOW = 0x0d, ///< Indicates a buffered peripheral device has reached the end of medium partition and data remains in the buffer that has not been written to the medium. + SCSI_SENSE_MISCOMPARE = 0x0e ///< ndicates that the source data did not match the data read from the medium. +}scsi_sense_key_type_t; + +//--------------------------------------------------------------------+ +// SCSI Primary Command (SPC-4) +//--------------------------------------------------------------------+ + +/// SCSI Test Unit Ready Command +typedef struct TU_ATTR_PACKED +{ + uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_TEST_UNIT_READY + uint8_t lun ; ///< Logical Unit + uint8_t reserved[3] ; + uint8_t control ; +} scsi_test_unit_ready_t; + +TU_VERIFY_STATIC(sizeof(scsi_test_unit_ready_t) == 6, "size is not correct"); + +/// SCSI Inquiry Command +typedef struct TU_ATTR_PACKED +{ + uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_INQUIRY + uint8_t reserved1 ; + uint8_t page_code ; + uint8_t reserved2 ; + uint8_t alloc_length ; ///< specifies the maximum number of bytes that USB host has allocated in the Data-In Buffer. An allocation length of zero specifies that no data shall be transferred. + uint8_t control ; +} scsi_inquiry_t, scsi_request_sense_t; + +TU_VERIFY_STATIC(sizeof(scsi_inquiry_t) == 6, "size is not correct"); + +/// SCSI Inquiry Response Data +typedef struct TU_ATTR_PACKED +{ + uint8_t peripheral_device_type : 5; + uint8_t peripheral_qualifier : 3; + + uint8_t : 7; + uint8_t is_removable : 1; + + uint8_t version; + + uint8_t response_data_format : 4; + uint8_t hierarchical_support : 1; + uint8_t normal_aca : 1; + uint8_t : 2; + + uint8_t additional_length; + + uint8_t protect : 1; + uint8_t : 2; + uint8_t third_party_copy : 1; + uint8_t target_port_group_support : 2; + uint8_t access_control_coordinator : 1; + uint8_t scc_support : 1; + + uint8_t addr16 : 1; + uint8_t : 3; + uint8_t multi_port : 1; + uint8_t : 1; // vendor specific + uint8_t enclosure_service : 1; + uint8_t : 1; + + uint8_t : 1; // vendor specific + uint8_t cmd_que : 1; + uint8_t : 2; + uint8_t sync : 1; + uint8_t wbus16 : 1; + uint8_t : 2; + + uint8_t vendor_id[8] ; ///< 8 bytes of ASCII data identifying the vendor of the product. + uint8_t product_id[16]; ///< 16 bytes of ASCII data defined by the vendor. + uint8_t product_rev[4]; ///< 4 bytes of ASCII data defined by the vendor. +} scsi_inquiry_resp_t; + +TU_VERIFY_STATIC(sizeof(scsi_inquiry_resp_t) == 36, "size is not correct"); + + +typedef struct TU_ATTR_PACKED +{ + uint8_t response_code : 7; ///< 70h - current errors, Fixed Format 71h - deferred errors, Fixed Format + uint8_t valid : 1; + + uint8_t reserved; + + uint8_t sense_key : 4; + uint8_t : 1; + uint8_t ili : 1; ///< Incorrect length indicator + uint8_t end_of_medium : 1; + uint8_t filemark : 1; + + uint32_t information; + uint8_t add_sense_len; + uint32_t command_specific_info; + uint8_t add_sense_code; + uint8_t add_sense_qualifier; + uint8_t field_replaceable_unit_code; + + uint8_t sense_key_specific[3]; ///< sense key specific valid bit is bit 7 of key[0], aka MSB in Big Endian layout + +} scsi_sense_fixed_resp_t; + +TU_VERIFY_STATIC(sizeof(scsi_sense_fixed_resp_t) == 18, "size is not correct"); + +typedef struct TU_ATTR_PACKED +{ + uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_MODE_SENSE_6 + + uint8_t : 3; + uint8_t disable_block_descriptor : 1; + uint8_t : 4; + + uint8_t page_code : 6; + uint8_t page_control : 2; + + uint8_t subpage_code; + uint8_t alloc_length; + uint8_t control; +} scsi_mode_sense6_t; + +TU_VERIFY_STATIC( sizeof(scsi_mode_sense6_t) == 6, "size is not correct"); + +// This is only a Mode parameter header(6). +typedef struct TU_ATTR_PACKED +{ + uint8_t data_len; + uint8_t medium_type; + + uint8_t reserved : 7; + bool write_protected : 1; + + uint8_t block_descriptor_len; +} scsi_mode_sense6_resp_t; + +TU_VERIFY_STATIC( sizeof(scsi_mode_sense6_resp_t) == 4, "size is not correct"); + +typedef struct TU_ATTR_PACKED +{ + uint8_t cmd_code; ///< SCSI OpCode for \ref SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL + uint8_t reserved[3]; + uint8_t prohibit_removal; + uint8_t control; +} scsi_prevent_allow_medium_removal_t; + +TU_VERIFY_STATIC( sizeof(scsi_prevent_allow_medium_removal_t) == 6, "size is not correct"); + +typedef struct TU_ATTR_PACKED +{ + uint8_t cmd_code; + + uint8_t immded : 1; + uint8_t : 7; + + uint8_t TU_RESERVED; + + uint8_t power_condition_mod : 4; + uint8_t : 4; + + uint8_t start : 1; + uint8_t load_eject : 1; + uint8_t no_flush : 1; + uint8_t : 1; + uint8_t power_condition : 4; + + uint8_t control; +} scsi_start_stop_unit_t; + +TU_VERIFY_STATIC( sizeof(scsi_start_stop_unit_t) == 6, "size is not correct"); + +//--------------------------------------------------------------------+ +// SCSI MMC +//--------------------------------------------------------------------+ +/// SCSI Read Format Capacity: Write Capacity +typedef struct TU_ATTR_PACKED +{ + uint8_t cmd_code; + uint8_t reserved[6]; + uint16_t alloc_length; + uint8_t control; +} scsi_read_format_capacity_t; + +TU_VERIFY_STATIC( sizeof(scsi_read_format_capacity_t) == 10, "size is not correct"); + +typedef struct TU_ATTR_PACKED{ + uint8_t reserved[3]; + uint8_t list_length; /// must be 8*n, length in bytes of formattable capacity descriptor followed it. + + uint32_t block_num; /// Number of Logical Blocks + uint8_t descriptor_type; // 00: reserved, 01 unformatted media , 10 Formatted media, 11 No media present + + uint8_t reserved2; + uint16_t block_size_u16; + +} scsi_read_format_capacity_data_t; + +TU_VERIFY_STATIC( sizeof(scsi_read_format_capacity_data_t) == 12, "size is not correct"); + +//--------------------------------------------------------------------+ +// SCSI Block Command (SBC-3) +// NOTE: All data in SCSI command are in Big Endian +//--------------------------------------------------------------------+ + +/// SCSI Read Capacity 10 Command: Read Capacity +typedef struct TU_ATTR_PACKED +{ + uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_READ_CAPACITY_10 + uint8_t reserved1 ; + uint32_t lba ; ///< The first Logical Block Address (LBA) accessed by this command + uint16_t reserved2 ; + uint8_t partial_medium_indicator ; + uint8_t control ; +} scsi_read_capacity10_t; + +TU_VERIFY_STATIC(sizeof(scsi_read_capacity10_t) == 10, "size is not correct"); + +/// SCSI Read Capacity 10 Response Data +typedef struct { + uint32_t last_lba ; ///< The last Logical Block Address of the device + uint32_t block_size ; ///< Block size in bytes +} scsi_read_capacity10_resp_t; + +TU_VERIFY_STATIC(sizeof(scsi_read_capacity10_resp_t) == 8, "size is not correct"); + +/// SCSI Read 10 Command +typedef struct TU_ATTR_PACKED +{ + uint8_t cmd_code ; ///< SCSI OpCode + uint8_t reserved ; // has LUN according to wiki + uint32_t lba ; ///< The first Logical Block Address (LBA) accessed by this command + uint8_t reserved2 ; + uint16_t block_count ; ///< Number of Blocks used by this command + uint8_t control ; +} scsi_read10_t, scsi_write10_t; + +TU_VERIFY_STATIC(sizeof(scsi_read10_t) == 10, "size is not correct"); +TU_VERIFY_STATIC(sizeof(scsi_write10_t) == 10, "size is not correct"); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_MSC_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.c new file mode 100644 index 00000000..00b0a1d0 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.c @@ -0,0 +1,952 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_MSC) + +#include "device/dcd.h" // for faking dcd_event_xfer_complete +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "msc_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +// Can be selectively disabled to reduce logging when troubleshooting other driver +#define MSC_DEBUG 2 + +enum +{ + MSC_STAGE_CMD = 0, + MSC_STAGE_DATA, + MSC_STAGE_STATUS, + MSC_STAGE_STATUS_SENT, + MSC_STAGE_NEED_RESET, +}; + +typedef struct +{ + // TODO optimize alignment + CFG_TUSB_MEM_ALIGN msc_cbw_t cbw; + CFG_TUSB_MEM_ALIGN msc_csw_t csw; + + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; + + // Bulk Only Transfer (BOT) Protocol + uint8_t stage; + uint32_t total_len; // byte to be transferred, can be smaller than total_bytes in cbw + uint32_t xferred_len; // numbered of bytes transferred so far in the Data Stage + + // Sense Response Data + uint8_t sense_key; + uint8_t add_sense_code; + uint8_t add_sense_qualifier; +}mscd_interface_t; + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static mscd_interface_t _mscd_itf; +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _mscd_buf[CFG_TUD_MSC_EP_BUFSIZE]; + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize); +static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc); + +static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc); +static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes); + +TU_ATTR_ALWAYS_INLINE static inline bool is_data_in(uint8_t dir) +{ + return tu_bit_test(dir, 7); +} + +static inline bool send_csw(uint8_t rhport, mscd_interface_t* p_msc) +{ + // Data residue is always = host expect - actual transferred + p_msc->csw.data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len; + + p_msc->stage = MSC_STAGE_STATUS_SENT; + return usbd_edpt_xfer(rhport, p_msc->ep_in , (uint8_t*) &p_msc->csw, sizeof(msc_csw_t)); +} + +static inline bool prepare_cbw(uint8_t rhport, mscd_interface_t* p_msc) +{ + p_msc->stage = MSC_STAGE_CMD; + return usbd_edpt_xfer(rhport, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)); +} + +static void fail_scsi_op(uint8_t rhport, mscd_interface_t* p_msc, uint8_t status) +{ + msc_cbw_t const * p_cbw = &p_msc->cbw; + msc_csw_t * p_csw = &p_msc->csw; + + p_csw->status = status; + p_csw->data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len; + p_msc->stage = MSC_STAGE_STATUS; + + // failed but sense key is not set: default to Illegal Request + if ( p_msc->sense_key == 0 ) tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); + + // If there is data stage and not yet complete, stall it + if ( p_cbw->total_bytes && p_csw->data_residue ) + { + if ( is_data_in(p_cbw->dir) ) + { + usbd_edpt_stall(rhport, p_msc->ep_in); + } + else + { + usbd_edpt_stall(rhport, p_msc->ep_out); + } + } +} + +static inline uint32_t rdwr10_get_lba(uint8_t const command[]) +{ + // use offsetof to avoid pointer to the odd/unaligned address + uint32_t const lba = tu_unaligned_read32(command + offsetof(scsi_write10_t, lba)); + + // lba is in Big Endian + return tu_ntohl(lba); +} + +static inline uint16_t rdwr10_get_blockcount(msc_cbw_t const* cbw) +{ + uint16_t const block_count = tu_unaligned_read16(cbw->command + offsetof(scsi_write10_t, block_count)); + return tu_ntohs(block_count); +} + +static inline uint16_t rdwr10_get_blocksize(msc_cbw_t const* cbw) +{ + // first extract block count in the command + uint16_t const block_count = rdwr10_get_blockcount(cbw); + + // invalid block count + if (block_count == 0) return 0; + + return (uint16_t) (cbw->total_bytes / block_count); +} + +uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw) +{ + uint8_t status = MSC_CSW_STATUS_PASSED; + uint16_t const block_count = rdwr10_get_blockcount(cbw); + + if ( cbw->total_bytes == 0 ) + { + if ( block_count ) + { + TU_LOG(MSC_DEBUG, " SCSI case 2 (Hn < Di) or case 3 (Hn < Do) \r\n"); + status = MSC_CSW_STATUS_PHASE_ERROR; + }else + { + // no data transfer, only exist in complaint test suite + } + }else + { + if ( SCSI_CMD_READ_10 == cbw->command[0] && !is_data_in(cbw->dir) ) + { + TU_LOG(MSC_DEBUG, " SCSI case 10 (Ho <> Di)\r\n"); + status = MSC_CSW_STATUS_PHASE_ERROR; + } + else if ( SCSI_CMD_WRITE_10 == cbw->command[0] && is_data_in(cbw->dir) ) + { + TU_LOG(MSC_DEBUG, " SCSI case 8 (Hi <> Do)\r\n"); + status = MSC_CSW_STATUS_PHASE_ERROR; + } + else if ( 0 == block_count ) + { + TU_LOG(MSC_DEBUG, " SCSI case 4 Hi > Dn (READ10) or case 9 Ho > Dn (WRITE10) \r\n"); + status = MSC_CSW_STATUS_FAILED; + } + else if ( cbw->total_bytes / block_count == 0 ) + { + TU_LOG(MSC_DEBUG, " Computed block size = 0. SCSI case 7 Hi < Di (READ10) or case 13 Ho < Do (WRIT10)\r\n"); + status = MSC_CSW_STATUS_PHASE_ERROR; + } + } + + return status; +} + +//--------------------------------------------------------------------+ +// Debug +//--------------------------------------------------------------------+ +#if CFG_TUSB_DEBUG >= 2 + +TU_ATTR_UNUSED static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] = +{ + { .key = SCSI_CMD_TEST_UNIT_READY , .data = "Test Unit Ready" }, + { .key = SCSI_CMD_INQUIRY , .data = "Inquiry" }, + { .key = SCSI_CMD_MODE_SELECT_6 , .data = "Mode_Select 6" }, + { .key = SCSI_CMD_MODE_SENSE_6 , .data = "Mode_Sense 6" }, + { .key = SCSI_CMD_START_STOP_UNIT , .data = "Start Stop Unit" }, + { .key = SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL , .data = "Prevent/Allow Medium Removal" }, + { .key = SCSI_CMD_READ_CAPACITY_10 , .data = "Read Capacity10" }, + { .key = SCSI_CMD_REQUEST_SENSE , .data = "Request Sense" }, + { .key = SCSI_CMD_READ_FORMAT_CAPACITY , .data = "Read Format Capacity" }, + { .key = SCSI_CMD_READ_10 , .data = "Read10" }, + { .key = SCSI_CMD_WRITE_10 , .data = "Write10" } +}; + +TU_ATTR_UNUSED static tu_lookup_table_t const _msc_scsi_cmd_table = +{ + .count = TU_ARRAY_SIZE(_msc_scsi_cmd_lookup), + .items = _msc_scsi_cmd_lookup +}; + +#endif + +//--------------------------------------------------------------------+ +// APPLICATION API +//--------------------------------------------------------------------+ +bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier) +{ + (void) lun; + + _mscd_itf.sense_key = sense_key; + _mscd_itf.add_sense_code = add_sense_code; + _mscd_itf.add_sense_qualifier = add_sense_qualifier; + + return true; +} + +static inline void set_sense_medium_not_present(uint8_t lun) +{ + // default sense is NOT READY, MEDIUM NOT PRESENT + tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00); +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void mscd_init(void) +{ + tu_memclr(&_mscd_itf, sizeof(mscd_interface_t)); +} + +void mscd_reset(uint8_t rhport) +{ + (void) rhport; + tu_memclr(&_mscd_itf, sizeof(mscd_interface_t)); +} + +uint16_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + // only support SCSI's BOT protocol + TU_VERIFY(TUSB_CLASS_MSC == itf_desc->bInterfaceClass && + MSC_SUBCLASS_SCSI == itf_desc->bInterfaceSubClass && + MSC_PROTOCOL_BOT == itf_desc->bInterfaceProtocol, 0); + + // msc driver length is fixed + uint16_t const drv_len = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t); + + // Max length must be at least 1 interface + 2 endpoints + TU_ASSERT(max_len >= drv_len, 0); + + mscd_interface_t * p_msc = &_mscd_itf; + p_msc->itf_num = itf_desc->bInterfaceNumber; + + // Open endpoint pair + TU_ASSERT( usbd_open_edpt_pair(rhport, tu_desc_next(itf_desc), 2, TUSB_XFER_BULK, &p_msc->ep_out, &p_msc->ep_in), 0 ); + + // Prepare for Command Block Wrapper + TU_ASSERT( prepare_cbw(rhport, p_msc), drv_len); + + return drv_len; +} + +static void proc_bot_reset(mscd_interface_t* p_msc) +{ + p_msc->stage = MSC_STAGE_CMD; + p_msc->total_len = 0; + p_msc->xferred_len = 0; + + p_msc->sense_key = 0; + p_msc->add_sense_code = 0; + p_msc->add_sense_qualifier = 0; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + // nothing to do with DATA & ACK stage + if (stage != CONTROL_STAGE_SETUP) return true; + + mscd_interface_t* p_msc = &_mscd_itf; + + // Clear Endpoint Feature (stall) for recovery + if ( TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type && + TUSB_REQ_RCPT_ENDPOINT == request->bmRequestType_bit.recipient && + TUSB_REQ_CLEAR_FEATURE == request->bRequest && + TUSB_REQ_FEATURE_EDPT_HALT == request->wValue ) + { + uint8_t const ep_addr = tu_u16_low(request->wIndex); + + if ( p_msc->stage == MSC_STAGE_NEED_RESET ) + { + // reset recovery is required to recover from this stage + // Clear Stall request cannot resolve this -> continue to stall endpoint + usbd_edpt_stall(rhport, ep_addr); + } + else + { + if ( ep_addr == p_msc->ep_in ) + { + if ( p_msc->stage == MSC_STAGE_STATUS ) + { + // resume sending SCSI status if we are in this stage previously before stalled + TU_ASSERT( send_csw(rhport, p_msc) ); + } + } + else if ( ep_addr == p_msc->ep_out ) + { + if ( p_msc->stage == MSC_STAGE_CMD ) + { + // part of reset recovery (probably due to invalid CBW) -> prepare for new command + // Note: skip if already queued previously + if ( usbd_edpt_ready(rhport, p_msc->ep_out) ) + { + TU_ASSERT( prepare_cbw(rhport, p_msc) ); + } + } + } + } + + return true; + } + + // From this point only handle class request only + TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); + + switch ( request->bRequest ) + { + case MSC_REQ_RESET: + TU_LOG(MSC_DEBUG, " MSC BOT Reset\r\n"); + TU_VERIFY(request->wValue == 0 && request->wLength == 0); + + // driver state reset + proc_bot_reset(p_msc); + + tud_control_status(rhport, request); + break; + + case MSC_REQ_GET_MAX_LUN: + { + TU_LOG(MSC_DEBUG, " MSC Get Max Lun\r\n"); + TU_VERIFY(request->wValue == 0 && request->wLength == 1); + + uint8_t maxlun = 1; + if (tud_msc_get_maxlun_cb) maxlun = tud_msc_get_maxlun_cb(); + TU_VERIFY(maxlun); + + // MAX LUN is minus 1 by specs + maxlun--; + + tud_control_xfer(rhport, request, &maxlun, 1); + } + break; + + default: return false; // stall unsupported request + } + + return true; +} + +bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +{ + (void) event; + + mscd_interface_t* p_msc = &_mscd_itf; + msc_cbw_t const * p_cbw = &p_msc->cbw; + msc_csw_t * p_csw = &p_msc->csw; + + switch (p_msc->stage) + { + case MSC_STAGE_CMD: + //------------- new CBW received -------------// + // Complete IN while waiting for CMD is usually Status of previous SCSI op, ignore it + if(ep_addr != p_msc->ep_out) return true; + + if ( !(xferred_bytes == sizeof(msc_cbw_t) && p_cbw->signature == MSC_CBW_SIGNATURE) ) + { + TU_LOG(MSC_DEBUG, " SCSI CBW is not valid\r\n"); + + // BOT 6.6.1 If CBW is not valid stall both endpoints until reset recovery + p_msc->stage = MSC_STAGE_NEED_RESET; + + // invalid CBW stall both endpoints + usbd_edpt_stall(rhport, p_msc->ep_in); + usbd_edpt_stall(rhport, p_msc->ep_out); + + return false; + } + + TU_LOG(MSC_DEBUG, " SCSI Command [Lun%u]: %s\r\n", p_cbw->lun, tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0])); + //TU_LOG_MEM(MSC_DEBUG, p_cbw, xferred_bytes, 2); + + p_csw->signature = MSC_CSW_SIGNATURE; + p_csw->tag = p_cbw->tag; + p_csw->data_residue = 0; + p_csw->status = MSC_CSW_STATUS_PASSED; + + /*------------- Parse command and prepare DATA -------------*/ + p_msc->stage = MSC_STAGE_DATA; + p_msc->total_len = p_cbw->total_bytes; + p_msc->xferred_len = 0; + + // Read10 or Write10 + if ( (SCSI_CMD_READ_10 == p_cbw->command[0]) || (SCSI_CMD_WRITE_10 == p_cbw->command[0]) ) + { + uint8_t const status = rdwr10_validate_cmd(p_cbw); + + if ( status != MSC_CSW_STATUS_PASSED) + { + fail_scsi_op(rhport, p_msc, status); + }else if ( p_cbw->total_bytes ) + { + if (SCSI_CMD_READ_10 == p_cbw->command[0]) + { + proc_read10_cmd(rhport, p_msc); + }else + { + proc_write10_cmd(rhport, p_msc); + } + }else + { + // no data transfer, only exist in complaint test suite + p_msc->stage = MSC_STAGE_STATUS; + } + } + else + { + // For other SCSI commands + // 1. OUT : queue transfer (invoke app callback after done) + // 2. IN & Zero: Process if is built-in, else Invoke app callback. Skip DATA if zero length + if ( (p_cbw->total_bytes > 0 ) && !is_data_in(p_cbw->dir) ) + { + if (p_cbw->total_bytes > sizeof(_mscd_buf)) + { + TU_LOG(MSC_DEBUG, " SCSI reject non READ10/WRITE10 with large data\r\n"); + fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + }else + { + // Didn't check for case 9 (Ho > Dn), which requires examining scsi command first + // but it is OK to just receive data then responded with failed status + TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, (uint16_t) p_msc->total_len) ); + } + }else + { + // First process if it is a built-in commands + int32_t resplen = proc_builtin_scsi(p_cbw->lun, p_cbw->command, _mscd_buf, sizeof(_mscd_buf)); + + // Invoke user callback if not built-in + if ( (resplen < 0) && (p_msc->sense_key == 0) ) + { + resplen = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, (uint16_t) p_msc->total_len); + } + + if ( resplen < 0 ) + { + // unsupported command + TU_LOG(MSC_DEBUG, " SCSI unsupported or failed command\r\n"); + fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + } + else if (resplen == 0) + { + if (p_cbw->total_bytes) + { + // 6.7 The 13 Cases: case 4 (Hi > Dn) + // TU_LOG(MSC_DEBUG, " SCSI case 4 (Hi > Dn): %lu\r\n", p_cbw->total_bytes); + fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + }else + { + // case 1 Hn = Dn: all good + p_msc->stage = MSC_STAGE_STATUS; + } + } + else + { + if ( p_cbw->total_bytes == 0 ) + { + // 6.7 The 13 Cases: case 2 (Hn < Di) + // TU_LOG(MSC_DEBUG, " SCSI case 2 (Hn < Di): %lu\r\n", p_cbw->total_bytes); + fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + }else + { + // cannot return more than host expect + p_msc->total_len = tu_min32((uint32_t) resplen, p_cbw->total_bytes); + TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, (uint16_t) p_msc->total_len) ); + } + } + } + } + break; + + case MSC_STAGE_DATA: + TU_LOG(MSC_DEBUG, " SCSI Data [Lun%u]\r\n", p_cbw->lun); + //TU_LOG_MEM(MSC_DEBUG, _mscd_buf, xferred_bytes, 2); + + if (SCSI_CMD_READ_10 == p_cbw->command[0]) + { + p_msc->xferred_len += xferred_bytes; + + if ( p_msc->xferred_len >= p_msc->total_len ) + { + // Data Stage is complete + p_msc->stage = MSC_STAGE_STATUS; + }else + { + proc_read10_cmd(rhport, p_msc); + } + } + else if (SCSI_CMD_WRITE_10 == p_cbw->command[0]) + { + proc_write10_new_data(rhport, p_msc, xferred_bytes); + } + else + { + p_msc->xferred_len += xferred_bytes; + + // OUT transfer, invoke callback if needed + if ( !is_data_in(p_cbw->dir) ) + { + int32_t cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, (uint16_t) p_msc->total_len); + + if ( cb_result < 0 ) + { + // unsupported command + TU_LOG(MSC_DEBUG, " SCSI unsupported command\r\n"); + fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + }else + { + // TODO haven't implement this scenario any further yet + } + } + + if ( p_msc->xferred_len >= p_msc->total_len ) + { + // Data Stage is complete + p_msc->stage = MSC_STAGE_STATUS; + } + else + { + // This scenario with command that take more than one transfer is already rejected at Command stage + TU_BREAKPOINT(); + } + } + break; + + case MSC_STAGE_STATUS: + // processed immediately after this switch, supposedly to be empty + break; + + case MSC_STAGE_STATUS_SENT: + // Wait for the Status phase to complete + if( (ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t)) ) + { + TU_LOG(MSC_DEBUG, " SCSI Status [Lun%u] = %u\r\n", p_cbw->lun, p_csw->status); + // TU_LOG_MEM(MSC_DEBUG, p_csw, xferred_bytes, 2); + + // Invoke complete callback if defined + // Note: There is racing issue with samd51 + qspi flash testing with arduino + // if complete_cb() is invoked after queuing the status. + switch(p_cbw->command[0]) + { + case SCSI_CMD_READ_10: + if ( tud_msc_read10_complete_cb ) tud_msc_read10_complete_cb(p_cbw->lun); + break; + + case SCSI_CMD_WRITE_10: + if ( tud_msc_write10_complete_cb ) tud_msc_write10_complete_cb(p_cbw->lun); + break; + + default: + if ( tud_msc_scsi_complete_cb ) tud_msc_scsi_complete_cb(p_cbw->lun, p_cbw->command); + break; + } + + TU_ASSERT( prepare_cbw(rhport, p_msc) ); + }else + { + // Any xfer ended here is consider unknown error, ignore it + TU_LOG1(" Warning expect SCSI Status but received unknown data\r\n"); + } + break; + + default : break; + } + + if ( p_msc->stage == MSC_STAGE_STATUS ) + { + // skip status if epin is currently stalled, will do it when received Clear Stall request + if ( !usbd_edpt_stalled(rhport, p_msc->ep_in) ) + { + if ( (p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir) ) + { + // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status + // TU_LOG(MSC_DEBUG, " SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len); + usbd_edpt_stall(rhport, p_msc->ep_in); + }else + { + TU_ASSERT( send_csw(rhport, p_msc) ); + } + } + + #if TU_CHECK_MCU(OPT_MCU_CXD56) + // WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD. + // There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and + // hope everything will work + if ( usbd_edpt_stalled(rhport, p_msc->ep_in) ) + { + usbd_edpt_clear_stall(rhport, p_msc->ep_in); + send_csw(rhport, p_msc); + } + #endif + } + + return true; +} + +/*------------------------------------------------------------------*/ +/* SCSI Command Process + *------------------------------------------------------------------*/ + +// return response's length (copied to buffer). Negative if it is not an built-in command or indicate Failed status (CSW) +// In case of a failed status, sense key must be set for reason of failure +static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize) +{ + (void) bufsize; // TODO refractor later + int32_t resplen; + + mscd_interface_t* p_msc = &_mscd_itf; + + switch ( scsi_cmd[0] ) + { + case SCSI_CMD_TEST_UNIT_READY: + resplen = 0; + if ( !tud_msc_test_unit_ready_cb(lun) ) + { + // Failed status response + resplen = - 1; + + // set default sense if not set by callback + if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); + } + break; + + case SCSI_CMD_START_STOP_UNIT: + resplen = 0; + + if (tud_msc_start_stop_cb) + { + scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const *) scsi_cmd; + if ( !tud_msc_start_stop_cb(lun, start_stop->power_condition, start_stop->start, start_stop->load_eject) ) + { + // Failed status response + resplen = - 1; + + // set default sense if not set by callback + if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); + } + } + break; + + case SCSI_CMD_READ_CAPACITY_10: + { + uint32_t block_count; + uint32_t block_size; + uint16_t block_size_u16; + + tud_msc_capacity_cb(lun, &block_count, &block_size_u16); + block_size = (uint32_t) block_size_u16; + + // Invalid block size/count from callback, possibly unit is not ready + // stall this request, set sense key to NOT READY + if (block_count == 0 || block_size == 0) + { + resplen = -1; + + // set default sense if not set by callback + if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); + }else + { + scsi_read_capacity10_resp_t read_capa10; + + read_capa10.last_lba = tu_htonl(block_count-1); + read_capa10.block_size = tu_htonl(block_size); + + resplen = sizeof(read_capa10); + memcpy(buffer, &read_capa10, (size_t) resplen); + } + } + break; + + case SCSI_CMD_READ_FORMAT_CAPACITY: + { + scsi_read_format_capacity_data_t read_fmt_capa = + { + .list_length = 8, + .block_num = 0, + .descriptor_type = 2, // formatted media + .block_size_u16 = 0 + }; + + uint32_t block_count; + uint16_t block_size; + + tud_msc_capacity_cb(lun, &block_count, &block_size); + + // Invalid block size/count from callback, possibly unit is not ready + // stall this request, set sense key to NOT READY + if (block_count == 0 || block_size == 0) + { + resplen = -1; + + // set default sense if not set by callback + if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); + }else + { + read_fmt_capa.block_num = tu_htonl(block_count); + read_fmt_capa.block_size_u16 = tu_htons(block_size); + + resplen = sizeof(read_fmt_capa); + memcpy(buffer, &read_fmt_capa, (size_t) resplen); + } + } + break; + + case SCSI_CMD_INQUIRY: + { + scsi_inquiry_resp_t inquiry_rsp = + { + .is_removable = 1, + .version = 2, + .response_data_format = 2, + .additional_length = sizeof(scsi_inquiry_resp_t) - 5, + }; + + // vendor_id, product_id, product_rev is space padded string + memset(inquiry_rsp.vendor_id , ' ', sizeof(inquiry_rsp.vendor_id)); + memset(inquiry_rsp.product_id , ' ', sizeof(inquiry_rsp.product_id)); + memset(inquiry_rsp.product_rev, ' ', sizeof(inquiry_rsp.product_rev)); + + tud_msc_inquiry_cb(lun, inquiry_rsp.vendor_id, inquiry_rsp.product_id, inquiry_rsp.product_rev); + + resplen = sizeof(inquiry_rsp); + memcpy(buffer, &inquiry_rsp, (size_t) resplen); + } + break; + + case SCSI_CMD_MODE_SENSE_6: + { + scsi_mode_sense6_resp_t mode_resp = + { + .data_len = 3, + .medium_type = 0, + .write_protected = false, + .reserved = 0, + .block_descriptor_len = 0 // no block descriptor are included + }; + + bool writable = true; + if ( tud_msc_is_writable_cb ) + { + writable = tud_msc_is_writable_cb(lun); + } + + mode_resp.write_protected = !writable; + + resplen = sizeof(mode_resp); + memcpy(buffer, &mode_resp, (size_t) resplen); + } + break; + + case SCSI_CMD_REQUEST_SENSE: + { + scsi_sense_fixed_resp_t sense_rsp = + { + .response_code = 0x70, // current, fixed format + .valid = 1 + }; + + sense_rsp.add_sense_len = sizeof(scsi_sense_fixed_resp_t) - 8; + sense_rsp.sense_key = (uint8_t) (p_msc->sense_key & 0x0F); + sense_rsp.add_sense_code = p_msc->add_sense_code; + sense_rsp.add_sense_qualifier = p_msc->add_sense_qualifier; + + resplen = sizeof(sense_rsp); + memcpy(buffer, &sense_rsp, (size_t) resplen); + + // request sense callback could overwrite the sense data + if (tud_msc_request_sense_cb) + { + resplen = tud_msc_request_sense_cb(lun, buffer, (uint16_t) bufsize); + } + + // Clear sense data after copy + tud_msc_set_sense(lun, 0, 0, 0); + } + break; + + default: resplen = -1; break; + } + + return resplen; +} + +static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc) +{ + msc_cbw_t const * p_cbw = &p_msc->cbw; + + // block size already verified not zero + uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); + + // Adjust lba with transferred bytes + uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz); + + // remaining bytes capped at class buffer + int32_t nbytes = (int32_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len); + + // Application can consume smaller bytes + uint32_t const offset = p_msc->xferred_len % block_sz; + nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_buf, (uint32_t) nbytes); + + if ( nbytes < 0 ) + { + // negative means error -> endpoint is stalled & status in CSW set to failed + TU_LOG(MSC_DEBUG, " tud_msc_read10_cb() return -1\r\n"); + + // set sense + set_sense_medium_not_present(p_cbw->lun); + + fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + } + else if ( nbytes == 0 ) + { + // zero means not ready -> simulate an transfer complete so that this driver callback will fired again + dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false); + } + else + { + TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, (uint16_t) nbytes), ); + } +} + +static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc) +{ + msc_cbw_t const * p_cbw = &p_msc->cbw; + bool writable = true; + + if ( tud_msc_is_writable_cb ) + { + writable = tud_msc_is_writable_cb(p_cbw->lun); + } + + if ( !writable ) + { + // Not writable, complete this SCSI op with error + // Sense = Write protected + tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_DATA_PROTECT, 0x27, 0x00); + fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + return; + } + + // remaining bytes capped at class buffer + uint16_t nbytes = (uint16_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len); + + // Write10 callback will be called later when usb transfer complete + TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, nbytes), ); +} + +// process new data arrived from WRITE10 +static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes) +{ + msc_cbw_t const * p_cbw = &p_msc->cbw; + + // block size already verified not zero + uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); + + // Adjust lba with transferred bytes + uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz); + + // Invoke callback to consume new data + uint32_t const offset = p_msc->xferred_len % block_sz; + int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_buf, xferred_bytes); + + if ( nbytes < 0 ) + { + // negative means error -> failed this scsi op + TU_LOG(MSC_DEBUG, " tud_msc_write10_cb() return -1\r\n"); + + // update actual byte before failed + p_msc->xferred_len += xferred_bytes; + + // Set sense + set_sense_medium_not_present(p_cbw->lun); + + fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + }else + { + // Application consume less than what we got (including zero) + if ( (uint32_t) nbytes < xferred_bytes ) + { + uint32_t const left_over = xferred_bytes - (uint32_t) nbytes; + if ( nbytes > 0 ) + { + p_msc->xferred_len += (uint16_t) nbytes; + memmove(_mscd_buf, _mscd_buf+nbytes, left_over); + } + + // simulate an transfer complete with adjusted parameters --> callback will be invoked with adjusted parameter + dcd_event_xfer_complete(rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false); + } + else + { + // Application consume all bytes in our buffer + p_msc->xferred_len += xferred_bytes; + + if ( p_msc->xferred_len >= p_msc->total_len ) + { + // Data Stage is complete + p_msc->stage = MSC_STAGE_STATUS; + }else + { + // prepare to receive more data from host + proc_write10_cmd(rhport, p_msc); + } + } + } +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.h new file mode 100644 index 00000000..5839b168 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.h @@ -0,0 +1,162 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_MSC_DEVICE_H_ +#define _TUSB_MSC_DEVICE_H_ + +#include "common/tusb_common.h" +#include "msc.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Class Driver Configuration +//--------------------------------------------------------------------+ + +#if !defined(CFG_TUD_MSC_EP_BUFSIZE) & defined(CFG_TUD_MSC_BUFSIZE) + // TODO warn user to use new name later on + // #warning CFG_TUD_MSC_BUFSIZE is renamed to CFG_TUD_MSC_EP_BUFSIZE, please update to use the new name + #define CFG_TUD_MSC_EP_BUFSIZE CFG_TUD_MSC_BUFSIZE +#endif + +#ifndef CFG_TUD_MSC_EP_BUFSIZE + #error CFG_TUD_MSC_EP_BUFSIZE must be defined, value of a block size should work well, the more the better +#endif + +TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct"); + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + +// Set SCSI sense response +bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier); + +//--------------------------------------------------------------------+ +// Application Callbacks (WEAK is optional) +//--------------------------------------------------------------------+ + +// Invoked when received SCSI READ10 command +// - Address = lba * BLOCK_SIZE + offset +// - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. +// +// - Application fill the buffer (up to bufsize) with address contents and return number of read byte. If +// - read < bufsize : These bytes are transferred first and callback invoked again for remaining data. +// +// - read == 0 : Indicate application is not ready yet e.g disk I/O busy. +// Callback invoked again with the same parameters later on. +// +// - read < 0 : Indicate application error e.g invalid address. This request will be STALLed +// and return failed status in command status wrapper phase. +int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); + +// Invoked when received SCSI WRITE10 command +// - Address = lba * BLOCK_SIZE + offset +// - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. +// +// - Application write data from buffer to address contents (up to bufsize) and return number of written byte. If +// - write < bufsize : callback invoked again with remaining data later on. +// +// - write == 0 : Indicate application is not ready yet e.g disk I/O busy. +// Callback invoked again with the same parameters later on. +// +// - write < 0 : Indicate application error e.g invalid address. This request will be STALLed +// and return failed status in command status wrapper phase. +// +// TODO change buffer to const uint8_t* +int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize); + +// Invoked when received SCSI_CMD_INQUIRY +// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]); + +// Invoked when received Test Unit Ready command. +// return true allowing host to read/write this LUN e.g SD card inserted +bool tud_msc_test_unit_ready_cb(uint8_t lun); + +// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size +// Application update block count and block size +void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size); + +/** + * Invoked when received an SCSI command not in built-in list below. + * - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, TEST_UNIT_READY, START_STOP_UNIT, MODE_SENSE6, REQUEST_SENSE + * - READ10 and WRITE10 has their own callbacks + * + * \param[in] lun Logical unit number + * \param[in] scsi_cmd SCSI command contents which application must examine to response accordingly + * \param[out] buffer Buffer for SCSI Data Stage. + * - For INPUT: application must fill this with response. + * - For OUTPUT it holds the Data from host + * \param[in] bufsize Buffer's length. + * + * \return Actual bytes processed, can be zero for no-data command. + * \retval negative Indicate error e.g unsupported command, tinyusb will \b STALL the corresponding + * endpoint and return failed status in command status wrapper phase. + */ +int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize); + +/*------------- Optional callbacks -------------*/ + +// Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation +TU_ATTR_WEAK uint8_t tud_msc_get_maxlun_cb(void); + +// Invoked when received Start Stop Unit command +// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage +// - Start = 1 : active mode, if load_eject = 1 : load disk storage +TU_ATTR_WEAK bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject); + +// Invoked when received REQUEST_SENSE +TU_ATTR_WEAK int32_t tud_msc_request_sense_cb(uint8_t lun, void* buffer, uint16_t bufsize); + +// Invoked when Read10 command is complete +TU_ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun); + +// Invoke when Write10 command is complete, can be used to flush flash caching +TU_ATTR_WEAK void tud_msc_write10_complete_cb(uint8_t lun); + +// Invoked when command in tud_msc_scsi_cb is complete +TU_ATTR_WEAK void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16]); + +// Invoked to check if device is writable as part of SCSI WRITE10 +TU_ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void mscd_init (void); +void mscd_reset (uint8_t rhport); +uint16_t mscd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool mscd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * p_request); +bool mscd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_MSC_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.c b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.c new file mode 100644 index 00000000..934f79ff --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.c @@ -0,0 +1,499 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUH_ENABLED && CFG_TUH_MSC + +#include "host/usbh.h" +#include "host/usbh_classdriver.h" + +#include "msc_host.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +enum +{ + MSC_STAGE_IDLE = 0, + MSC_STAGE_CMD, + MSC_STAGE_DATA, + MSC_STAGE_STATUS, +}; + +typedef struct +{ + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; + + uint8_t max_lun; + + volatile bool configured; // Receive SET_CONFIGURE + volatile bool mounted; // Enumeration is complete + + struct { + uint32_t block_size; + uint32_t block_count; + } capacity[CFG_TUH_MSC_MAXLUN]; + + //------------- SCSI -------------// + uint8_t stage; + void* buffer; + tuh_msc_complete_cb_t complete_cb; + + msc_cbw_t cbw; + msc_csw_t csw; +}msch_interface_t; + +CFG_TUSB_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUH_DEVICE_MAX]; + +// buffer used to read scsi information when mounted +// largest response data currently is inquiry TODO Inquiry is not part of enum anymore +CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) +static uint8_t _msch_buffer[sizeof(scsi_inquiry_resp_t)]; + +TU_ATTR_ALWAYS_INLINE +static inline msch_interface_t* get_itf(uint8_t dev_addr) +{ + return &_msch_itf[dev_addr-1]; +} + +//--------------------------------------------------------------------+ +// PUBLIC API +//--------------------------------------------------------------------+ +uint8_t tuh_msc_get_maxlun(uint8_t dev_addr) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + return p_msc->max_lun; +} + +uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + return p_msc->capacity[lun].block_count; +} + +uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + return p_msc->capacity[lun].block_size; +} + +bool tuh_msc_mounted(uint8_t dev_addr) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + return p_msc->mounted; +} + +bool tuh_msc_ready(uint8_t dev_addr) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + return p_msc->mounted && !usbh_edpt_busy(dev_addr, p_msc->ep_in); +} + +//--------------------------------------------------------------------+ +// PUBLIC API: SCSI COMMAND +//--------------------------------------------------------------------+ +static inline void cbw_init(msc_cbw_t *cbw, uint8_t lun) +{ + tu_memclr(cbw, sizeof(msc_cbw_t)); + cbw->signature = MSC_CBW_SIGNATURE; + cbw->tag = 0x54555342; // TUSB + cbw->lun = lun; +} + +bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + TU_VERIFY(p_msc->configured); + + // TODO claim endpoint + + p_msc->cbw = *cbw; + p_msc->stage = MSC_STAGE_CMD; + p_msc->buffer = data; + p_msc->complete_cb = complete_cb; + + TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t))); + + return true; +} + +bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + TU_VERIFY(p_msc->configured); + + msc_cbw_t cbw; + cbw_init(&cbw, lun); + + cbw.total_bytes = sizeof(scsi_read_capacity10_resp_t); + cbw.dir = TUSB_DIR_IN_MASK; + cbw.cmd_len = sizeof(scsi_read_capacity10_t); + cbw.command[0] = SCSI_CMD_READ_CAPACITY_10; + + return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb); +} + +bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + TU_VERIFY(p_msc->mounted); + + msc_cbw_t cbw; + cbw_init(&cbw, lun); + + cbw.total_bytes = sizeof(scsi_inquiry_resp_t); + cbw.dir = TUSB_DIR_IN_MASK; + cbw.cmd_len = sizeof(scsi_inquiry_t); + + scsi_inquiry_t const cmd_inquiry = + { + .cmd_code = SCSI_CMD_INQUIRY, + .alloc_length = sizeof(scsi_inquiry_resp_t) + }; + memcpy(cbw.command, &cmd_inquiry, cbw.cmd_len); + + return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb); +} + +bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + TU_VERIFY(p_msc->configured); + + msc_cbw_t cbw; + cbw_init(&cbw, lun); + + cbw.total_bytes = 0; + cbw.dir = TUSB_DIR_OUT; + cbw.cmd_len = sizeof(scsi_test_unit_ready_t); + cbw.command[0] = SCSI_CMD_TEST_UNIT_READY; + cbw.command[1] = lun; // according to wiki TODO need verification + + return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb); +} + +bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb) +{ + msc_cbw_t cbw; + cbw_init(&cbw, lun); + + cbw.total_bytes = 18; // TODO sense response + cbw.dir = TUSB_DIR_IN_MASK; + cbw.cmd_len = sizeof(scsi_request_sense_t); + + scsi_request_sense_t const cmd_request_sense = + { + .cmd_code = SCSI_CMD_REQUEST_SENSE, + .alloc_length = 18 + }; + + memcpy(cbw.command, &cmd_request_sense, cbw.cmd_len); + + return tuh_msc_scsi_command(dev_addr, &cbw, resposne, complete_cb); +} + +bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + TU_VERIFY(p_msc->mounted); + + msc_cbw_t cbw; + cbw_init(&cbw, lun); + + cbw.total_bytes = block_count*p_msc->capacity[lun].block_size; + cbw.dir = TUSB_DIR_IN_MASK; + cbw.cmd_len = sizeof(scsi_read10_t); + + scsi_read10_t const cmd_read10 = + { + .cmd_code = SCSI_CMD_READ_10, + .lba = tu_htonl(lba), + .block_count = tu_htons(block_count) + }; + + memcpy(cbw.command, &cmd_read10, cbw.cmd_len); + + return tuh_msc_scsi_command(dev_addr, &cbw, buffer, complete_cb); +} + +bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + TU_VERIFY(p_msc->mounted); + + msc_cbw_t cbw; + cbw_init(&cbw, lun); + + cbw.total_bytes = block_count*p_msc->capacity[lun].block_size; + cbw.dir = TUSB_DIR_OUT; + cbw.cmd_len = sizeof(scsi_write10_t); + + scsi_write10_t const cmd_write10 = + { + .cmd_code = SCSI_CMD_WRITE_10, + .lba = tu_htonl(lba), + .block_count = tu_htons(block_count) + }; + + memcpy(cbw.command, &cmd_write10, cbw.cmd_len); + + return tuh_msc_scsi_command(dev_addr, &cbw, (void*)(uintptr_t) buffer, complete_cb); +} + +#if 0 +// MSC interface Reset (not used now) +bool tuh_msc_reset(uint8_t dev_addr) +{ + tusb_control_request_t const new_request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = MSC_REQ_RESET, + .wValue = 0, + .wIndex = p_msc->itf_num, + .wLength = 0 + }; + TU_ASSERT( usbh_control_xfer( dev_addr, &new_request, NULL ) ); +} +#endif + +//--------------------------------------------------------------------+ +// CLASS-USBH API +//--------------------------------------------------------------------+ +void msch_init(void) +{ + tu_memclr(_msch_itf, sizeof(_msch_itf)); +} + +void msch_close(uint8_t dev_addr) +{ + TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); + + msch_interface_t* p_msc = get_itf(dev_addr); + + // invoke Application Callback + if (p_msc->mounted && tuh_msc_umount_cb) tuh_msc_umount_cb(dev_addr); + + tu_memclr(p_msc, sizeof(msch_interface_t)); +} + +bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + msc_cbw_t const * cbw = &p_msc->cbw; + msc_csw_t * csw = &p_msc->csw; + + switch (p_msc->stage) + { + case MSC_STAGE_CMD: + // Must be Command Block + TU_ASSERT(ep_addr == p_msc->ep_out && event == XFER_RESULT_SUCCESS && xferred_bytes == sizeof(msc_cbw_t)); + + if ( cbw->total_bytes && p_msc->buffer ) + { + // Data stage if any + p_msc->stage = MSC_STAGE_DATA; + + uint8_t const ep_data = (cbw->dir & TUSB_DIR_IN_MASK) ? p_msc->ep_in : p_msc->ep_out; + TU_ASSERT(usbh_edpt_xfer(dev_addr, ep_data, p_msc->buffer, (uint16_t) cbw->total_bytes)); + }else + { + // Status stage + p_msc->stage = MSC_STAGE_STATUS; + TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t))); + } + break; + + case MSC_STAGE_DATA: + // Status stage + p_msc->stage = MSC_STAGE_STATUS; + TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t))); + break; + + case MSC_STAGE_STATUS: + // SCSI op is complete + p_msc->stage = MSC_STAGE_IDLE; + + if (p_msc->complete_cb) p_msc->complete_cb(dev_addr, cbw, csw); + break; + + // unknown state + default: break; + } + + return true; +} + +//--------------------------------------------------------------------+ +// MSC Enumeration +//--------------------------------------------------------------------+ + +static void config_get_maxlun_complete (tuh_xfer_t* xfer); +static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); +static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); +static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); + +bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) +{ + (void) rhport; + TU_VERIFY (MSC_SUBCLASS_SCSI == desc_itf->bInterfaceSubClass && + MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol); + + // msc driver length is fixed + uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); + TU_ASSERT(drv_len <= max_len); + + msch_interface_t* p_msc = get_itf(dev_addr); + tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(desc_itf); + + for(uint32_t i=0; i<2; i++) + { + TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer); + TU_ASSERT(tuh_edpt_open(dev_addr, ep_desc)); + + if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN ) + { + p_msc->ep_in = ep_desc->bEndpointAddress; + }else + { + p_msc->ep_out = ep_desc->bEndpointAddress; + } + + ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(ep_desc); + } + + p_msc->itf_num = desc_itf->bInterfaceNumber; + + return true; +} + +bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + TU_ASSERT(p_msc->itf_num == itf_num); + + p_msc->configured = true; + + //------------- Get Max Lun -------------// + TU_LOG2("MSC Get Max Lun\r\n"); + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN + }, + .bRequest = MSC_REQ_GET_MAX_LUN, + .wValue = 0, + .wIndex = itf_num, + .wLength = 1 + }; + + tuh_xfer_t xfer = + { + .daddr = dev_addr, + .ep_addr = 0, + .setup = &request, + .buffer = &p_msc->max_lun, + .complete_cb = config_get_maxlun_complete, + .user_data = 0 + }; + TU_ASSERT(tuh_control_xfer(&xfer)); + + return true; +} + +static void config_get_maxlun_complete (tuh_xfer_t* xfer) +{ + uint8_t const daddr = xfer->daddr; + msch_interface_t* p_msc = get_itf(daddr); + + // STALL means zero + p_msc->max_lun = (XFER_RESULT_SUCCESS == xfer->result) ? _msch_buffer[0] : 0; + p_msc->max_lun++; // MAX LUN is minus 1 by specs + + // TODO multiple LUN support + TU_LOG2("SCSI Test Unit Ready\r\n"); + uint8_t const lun = 0; + tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete); +} + +static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +{ + if (csw->status == 0) + { + // Unit is ready, read its capacity + TU_LOG2("SCSI Read Capacity\r\n"); + tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete); + }else + { + // Note: During enumeration, some device fails Test Unit Ready and require a few retries + // with Request Sense to start working !! + // TODO limit number of retries + TU_LOG2("SCSI Request Sense\r\n"); + TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, _msch_buffer, config_request_sense_complete)); + } + + return true; +} + +static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +{ + TU_ASSERT(csw->status == 0); + TU_ASSERT(tuh_msc_test_unit_ready(dev_addr, cbw->lun, config_test_unit_ready_complete)); + return true; +} + +static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +{ + TU_ASSERT(csw->status == 0); + + msch_interface_t* p_msc = get_itf(dev_addr); + + // Capacity response field: Block size and Last LBA are both Big-Endian + scsi_read_capacity10_resp_t* resp = (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer); + p_msc->capacity[cbw->lun].block_count = tu_ntohl(resp->last_lba) + 1; + p_msc->capacity[cbw->lun].block_size = tu_ntohl(resp->block_size); + + // Mark enumeration is complete + p_msc->mounted = true; + if (tuh_msc_mount_cb) tuh_msc_mount_cb(dev_addr); + + // notify usbh that driver enumeration is complete + usbh_driver_set_config_complete(dev_addr, p_msc->itf_num); + + return true; +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.h b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.h new file mode 100644 index 00000000..7718ad4f --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.h @@ -0,0 +1,119 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_MSC_HOST_H_ +#define _TUSB_MSC_HOST_H_ + +#include "msc.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Class Driver Configuration +//--------------------------------------------------------------------+ + +#ifndef CFG_TUH_MSC_MAXLUN +#define CFG_TUH_MSC_MAXLUN 4 +#endif + +typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + +// Check if device supports MassStorage interface. +// This function true after tuh_msc_mounted_cb() and false after tuh_msc_unmounted_cb() +bool tuh_msc_mounted(uint8_t dev_addr); + +// Check if the interface is currently ready or busy transferring data +bool tuh_msc_ready(uint8_t dev_addr); + +// Get Max Lun +uint8_t tuh_msc_get_maxlun(uint8_t dev_addr); + +// Get number of block +uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun); + +// Get block size in bytes +uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun); + +// Perform a full SCSI command (cbw, data, csw) in non-blocking manner. +// Complete callback is invoked when SCSI op is complete. +// return true if success, false if there is already pending operation. +bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb); + +// Perform SCSI Inquiry command +// Complete callback is invoked when SCSI op is complete. +bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb); + +// Perform SCSI Test Unit Ready command +// Complete callback is invoked when SCSI op is complete. +bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb); + +// Perform SCSI Request Sense 10 command +// Complete callback is invoked when SCSI op is complete. +bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb); + +// Perform SCSI Read 10 command. Read n blocks starting from LBA to buffer +// Complete callback is invoked when SCSI op is complete. +bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb); + +// Perform SCSI Write 10 command. Write n blocks starting from LBA to device +// Complete callback is invoked when SCSI op is complete. +bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb); + +// Perform SCSI Read Capacity 10 command +// Complete callback is invoked when SCSI op is complete. +// Note: during enumeration, host stack already carried out this request. Application can retrieve capacity by +// simply call tuh_msc_get_block_count() and tuh_msc_get_block_size() +bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb); + +//------------- Application Callback -------------// + +// Invoked when a device with MassStorage interface is mounted +TU_ATTR_WEAK void tuh_msc_mount_cb(uint8_t dev_addr); + +// Invoked when a device with MassStorage interface is unmounted +TU_ATTR_WEAK void tuh_msc_umount_cb(uint8_t dev_addr); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ + +void msch_init (void); +bool msch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); +bool msch_set_config (uint8_t dev_addr, uint8_t itf_num); +void msch_close (uint8_t dev_addr); +bool msch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_MSC_HOST_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/net/ecm_rndis_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/net/ecm_rndis_device.c new file mode 100644 index 00000000..5f316762 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/net/ecm_rndis_device.c @@ -0,0 +1,447 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Peter Lawrence + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if ( CFG_TUD_ENABLED && CFG_TUD_ECM_RNDIS ) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "net_device.h" +#include "rndis_protocol.h" + +void rndis_class_set_handler(uint8_t *data, int size); /* found in ./misc/networking/rndis_reports.c */ + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +typedef struct +{ + uint8_t itf_num; // Index number of Management Interface, +1 for Data Interface + uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active + + uint8_t ep_notif; + uint8_t ep_in; + uint8_t ep_out; + + bool ecm_mode; + + // Endpoint descriptor use to open/close when receving SetInterface + // TODO since configuration descriptor may not be long-lived memory, we should + // keep a copy of endpoint attribute instead + uint8_t const * ecm_desc_epdata; + +} netd_interface_t; + +#define CFG_TUD_NET_PACKET_PREFIX_LEN sizeof(rndis_data_packet_t) +#define CFG_TUD_NET_PACKET_SUFFIX_LEN 0 + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t received[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t transmitted[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; + +struct ecm_notify_struct +{ + tusb_control_request_t header; + uint32_t downlink, uplink; +}; + +static const struct ecm_notify_struct ecm_notify_nc = +{ + .header = { + .bmRequestType = 0xA1, + .bRequest = 0 /* NETWORK_CONNECTION aka NetworkConnection */, + .wValue = 1 /* Connected */, + .wLength = 0, + }, +}; + +static const struct ecm_notify_struct ecm_notify_csc = +{ + .header = { + .bmRequestType = 0xA1, + .bRequest = 0x2A /* CONNECTION_SPEED_CHANGE aka ConnectionSpeedChange */, + .wLength = 8, + }, + .downlink = 9728000, + .uplink = 9728000, +}; + +// TODO remove CFG_TUSB_MEM_SECTION, control internal buffer is already in this special section +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static union +{ + uint8_t rndis_buf[120]; + struct ecm_notify_struct ecm_buf; +} notify; + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +// TODO remove CFG_TUSB_MEM_SECTION +CFG_TUSB_MEM_SECTION static netd_interface_t _netd_itf; + +static bool can_xmit; + +void tud_network_recv_renew(void) +{ + usbd_edpt_xfer(0, _netd_itf.ep_out, received, sizeof(received)); +} + +static void do_in_xfer(uint8_t *buf, uint16_t len) +{ + can_xmit = false; + usbd_edpt_xfer(0, _netd_itf.ep_in, buf, len); +} + +void netd_report(uint8_t *buf, uint16_t len) +{ + uint8_t const rhport = 0; + + // skip if previous report not yet acknowledged by host + if ( usbd_edpt_busy(rhport, _netd_itf.ep_notif) ) return; + usbd_edpt_xfer(rhport, _netd_itf.ep_notif, buf, len); +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void netd_init(void) +{ + tu_memclr(&_netd_itf, sizeof(_netd_itf)); +} + +void netd_reset(uint8_t rhport) +{ + (void) rhport; + + netd_init(); +} + +uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + bool const is_rndis = (TUD_RNDIS_ITF_CLASS == itf_desc->bInterfaceClass && + TUD_RNDIS_ITF_SUBCLASS == itf_desc->bInterfaceSubClass && + TUD_RNDIS_ITF_PROTOCOL == itf_desc->bInterfaceProtocol); + + bool const is_ecm = (TUSB_CLASS_CDC == itf_desc->bInterfaceClass && + CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL == itf_desc->bInterfaceSubClass && + 0x00 == itf_desc->bInterfaceProtocol); + + TU_VERIFY(is_rndis || is_ecm, 0); + + // confirm interface hasn't already been allocated + TU_ASSERT(0 == _netd_itf.ep_notif, 0); + + // sanity check the descriptor + _netd_itf.ecm_mode = is_ecm; + + //------------- Management Interface -------------// + _netd_itf.itf_num = itf_desc->bInterfaceNumber; + + uint16_t drv_len = sizeof(tusb_desc_interface_t); + uint8_t const * p_desc = tu_desc_next( itf_desc ); + + // Communication Functional Descriptors + while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) + { + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + // notification endpoint (if any) + if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + { + TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 ); + + _netd_itf.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + //------------- Data Interface -------------// + // - RNDIS Data followed immediately by a pair of endpoints + // - CDC-ECM data interface has 2 alternate settings + // - 0 : zero endpoints for inactive (default) + // - 1 : IN & OUT endpoints for active networking + TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); + + do + { + tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc; + TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass, 0); + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + }while( _netd_itf.ecm_mode && (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (drv_len <= max_len) ); + + // Pair of endpoints + TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0); + + if ( _netd_itf.ecm_mode ) + { + // ECM by default is in-active, save the endpoint attribute + // to open later when received setInterface + _netd_itf.ecm_desc_epdata = p_desc; + }else + { + // Open endpoint pair for RNDIS + TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in), 0 ); + + tud_network_init_cb(); + + // we are ready to transmit a packet + can_xmit = true; + + // prepare for incoming packets + tud_network_recv_renew(); + } + + drv_len += 2*sizeof(tusb_desc_endpoint_t); + + return drv_len; +} + +static void ecm_report(bool nc) +{ + notify.ecm_buf = (nc) ? ecm_notify_nc : ecm_notify_csc; + notify.ecm_buf.header.wIndex = _netd_itf.itf_num; + netd_report((uint8_t *)¬ify.ecm_buf, (nc) ? sizeof(notify.ecm_buf.header) : sizeof(notify.ecm_buf)); +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if ( stage == CONTROL_STAGE_SETUP ) + { + switch ( request->bmRequestType_bit.type ) + { + case TUSB_REQ_TYPE_STANDARD: + switch ( request->bRequest ) + { + case TUSB_REQ_GET_INTERFACE: + { + uint8_t const req_itfnum = (uint8_t) request->wIndex; + TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum); + + tud_control_xfer(rhport, request, &_netd_itf.itf_data_alt, 1); + } + break; + + case TUSB_REQ_SET_INTERFACE: + { + uint8_t const req_itfnum = (uint8_t) request->wIndex; + uint8_t const req_alt = (uint8_t) request->wValue; + + // Only valid for Data Interface with Alternate is either 0 or 1 + TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum && req_alt < 2); + + // ACM-ECM only: qequest to enable/disable network activities + TU_VERIFY(_netd_itf.ecm_mode); + + _netd_itf.itf_data_alt = req_alt; + + if ( _netd_itf.itf_data_alt ) + { + // TODO since we don't actually close endpoint + // hack here to not re-open it + if ( _netd_itf.ep_in == 0 && _netd_itf.ep_out == 0 ) + { + TU_ASSERT(_netd_itf.ecm_desc_epdata); + TU_ASSERT( usbd_open_edpt_pair(rhport, _netd_itf.ecm_desc_epdata, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in) ); + + // TODO should be merge with RNDIS's after endpoint opened + // Also should have opposite callback for application to disable network !! + tud_network_init_cb(); + can_xmit = true; // we are ready to transmit a packet + tud_network_recv_renew(); // prepare for incoming packets + } + }else + { + // TODO close the endpoint pair + // For now pretend that we did, this should have no harm since host won't try to + // communicate with the endpoints again + // _netd_itf.ep_in = _netd_itf.ep_out = 0 + } + + tud_control_status(rhport, request); + } + break; + + // unsupported request + default: return false; + } + break; + + case TUSB_REQ_TYPE_CLASS: + TU_VERIFY (_netd_itf.itf_num == request->wIndex); + + if (_netd_itf.ecm_mode) + { + /* the only required CDC-ECM Management Element Request is SetEthernetPacketFilter */ + if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest) + { + tud_control_xfer(rhport, request, NULL, 0); + ecm_report(true); + } + } + else + { + if (request->bmRequestType_bit.direction == TUSB_DIR_IN) + { + rndis_generic_msg_t *rndis_msg = (rndis_generic_msg_t *) ((void*) notify.rndis_buf); + uint32_t msglen = tu_le32toh(rndis_msg->MessageLength); + TU_ASSERT(msglen <= sizeof(notify.rndis_buf)); + tud_control_xfer(rhport, request, notify.rndis_buf, (uint16_t) msglen); + } + else + { + tud_control_xfer(rhport, request, notify.rndis_buf, (uint16_t) sizeof(notify.rndis_buf)); + } + } + break; + + // unsupported request + default: return false; + } + } + else if ( stage == CONTROL_STAGE_DATA ) + { + // Handle RNDIS class control OUT only + if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && + request->bmRequestType_bit.direction == TUSB_DIR_OUT && + _netd_itf.itf_num == request->wIndex) + { + if ( !_netd_itf.ecm_mode ) + { + rndis_class_set_handler(notify.rndis_buf, request->wLength); + } + } + } + + return true; +} + +static void handle_incoming_packet(uint32_t len) +{ + uint8_t *pnt = received; + uint32_t size = 0; + + if (_netd_itf.ecm_mode) + { + size = len; + } + else + { + rndis_data_packet_t *r = (rndis_data_packet_t *) ((void*) pnt); + if (len >= sizeof(rndis_data_packet_t)) + if ( (r->MessageType == REMOTE_NDIS_PACKET_MSG) && (r->MessageLength <= len)) + if ( (r->DataOffset + offsetof(rndis_data_packet_t, DataOffset) + r->DataLength) <= len) + { + pnt = &received[r->DataOffset + offsetof(rndis_data_packet_t, DataOffset)]; + size = r->DataLength; + } + } + + if (!tud_network_recv_cb(pnt, (uint16_t) size)) + { + /* if a buffer was never handled by user code, we must renew on the user's behalf */ + tud_network_recv_renew(); + } +} + +bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) rhport; + (void) result; + + /* new packet received */ + if ( ep_addr == _netd_itf.ep_out ) + { + handle_incoming_packet(xferred_bytes); + } + + /* data transmission finished */ + if ( ep_addr == _netd_itf.ep_in ) + { + /* TinyUSB requires the class driver to implement ZLP (since ZLP usage is class-specific) */ + + if ( xferred_bytes && (0 == (xferred_bytes % CFG_TUD_NET_ENDPOINT_SIZE)) ) + { + do_in_xfer(NULL, 0); /* a ZLP is needed */ + } + else + { + /* we're finally finished */ + can_xmit = true; + } + } + + if ( _netd_itf.ecm_mode && (ep_addr == _netd_itf.ep_notif) ) + { + if (sizeof(notify.ecm_buf.header) == xferred_bytes) ecm_report(false); + } + + return true; +} + +bool tud_network_can_xmit(uint16_t size) +{ + (void)size; + + return can_xmit; +} + +void tud_network_xmit(void *ref, uint16_t arg) +{ + uint8_t *data; + uint16_t len; + + if (!can_xmit) + return; + + len = (_netd_itf.ecm_mode) ? 0 : CFG_TUD_NET_PACKET_PREFIX_LEN; + data = transmitted + len; + + len += tud_network_xmit_cb(data, ref, arg); + + if (!_netd_itf.ecm_mode) + { + rndis_data_packet_t *hdr = (rndis_data_packet_t *) ((void*) transmitted); + memset(hdr, 0, sizeof(rndis_data_packet_t)); + hdr->MessageType = REMOTE_NDIS_PACKET_MSG; + hdr->MessageLength = len; + hdr->DataOffset = sizeof(rndis_data_packet_t) - offsetof(rndis_data_packet_t, DataOffset); + hdr->DataLength = len - sizeof(rndis_data_packet_t); + } + + do_in_xfer(transmitted, len); +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/net/ncm.h b/test-devices/loopback-stm32/lib/tinyusb/class/net/ncm.h new file mode 100644 index 00000000..96ba11fb --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/net/ncm.h @@ -0,0 +1,69 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + + +#ifndef _TUSB_NCM_H_ +#define _TUSB_NCM_H_ + +#include "common/tusb_common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +// Table 4.3 Data Class Interface Protocol Codes +typedef enum +{ + NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK = 0x01 +} ncm_data_interface_protocol_code_t; + + +// Table 6.2 Class-Specific Request Codes for Network Control Model subclass +typedef enum +{ + NCM_SET_ETHERNET_MULTICAST_FILTERS = 0x40, + NCM_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x41, + NCM_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x42, + NCM_SET_ETHERNET_PACKET_FILTER = 0x43, + NCM_GET_ETHERNET_STATISTIC = 0x44, + NCM_GET_NTB_PARAMETERS = 0x80, + NCM_GET_NET_ADDRESS = 0x81, + NCM_SET_NET_ADDRESS = 0x82, + NCM_GET_NTB_FORMAT = 0x83, + NCM_SET_NTB_FORMAT = 0x84, + NCM_GET_NTB_INPUT_SIZE = 0x85, + NCM_SET_NTB_INPUT_SIZE = 0x86, + NCM_GET_MAX_DATAGRAM_SIZE = 0x87, + NCM_SET_MAX_DATAGRAM_SIZE = 0x88, + NCM_GET_CRC_MODE = 0x89, + NCM_SET_CRC_MODE = 0x8A, +} ncm_request_code_t; + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/net/ncm_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/net/ncm_device.c new file mode 100644 index 00000000..00892b49 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/net/ncm_device.c @@ -0,0 +1,511 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Jacob Berg Potter + * Copyright (c) 2020 Peter Lawrence + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if ( CFG_TUD_ENABLED && CFG_TUD_NCM ) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" +#include "net_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +#define NTH16_SIGNATURE 0x484D434E +#define NDP16_SIGNATURE_NCM0 0x304D434E +#define NDP16_SIGNATURE_NCM1 0x314D434E + +typedef struct TU_ATTR_PACKED +{ + uint16_t wLength; + uint16_t bmNtbFormatsSupported; + uint32_t dwNtbInMaxSize; + uint16_t wNdbInDivisor; + uint16_t wNdbInPayloadRemainder; + uint16_t wNdbInAlignment; + uint16_t wReserved; + uint32_t dwNtbOutMaxSize; + uint16_t wNdbOutDivisor; + uint16_t wNdbOutPayloadRemainder; + uint16_t wNdbOutAlignment; + uint16_t wNtbOutMaxDatagrams; +} ntb_parameters_t; + +typedef struct TU_ATTR_PACKED +{ + uint32_t dwSignature; + uint16_t wHeaderLength; + uint16_t wSequence; + uint16_t wBlockLength; + uint16_t wNdpIndex; +} nth16_t; + +typedef struct TU_ATTR_PACKED +{ + uint16_t wDatagramIndex; + uint16_t wDatagramLength; +} ndp16_datagram_t; + +typedef struct TU_ATTR_PACKED +{ + uint32_t dwSignature; + uint16_t wLength; + uint16_t wNextNdpIndex; + ndp16_datagram_t datagram[]; +} ndp16_t; + +typedef union TU_ATTR_PACKED { + struct { + nth16_t nth; + ndp16_t ndp; + }; + uint8_t data[CFG_TUD_NCM_IN_NTB_MAX_SIZE]; +} transmit_ntb_t; + +struct ecm_notify_struct +{ + tusb_control_request_t header; + uint32_t downlink, uplink; +}; + +typedef struct +{ + uint8_t itf_num; // Index number of Management Interface, +1 for Data Interface + uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active + + uint8_t ep_notif; + uint8_t ep_in; + uint8_t ep_out; + + const ndp16_t *ndp; + uint8_t num_datagrams, current_datagram_index; + + enum { + REPORT_SPEED, + REPORT_CONNECTED, + REPORT_DONE + } report_state; + bool report_pending; + + uint8_t current_ntb; // Index in transmit_ntb[] that is currently being filled with datagrams + uint8_t datagram_count; // Number of datagrams in transmit_ntb[current_ntb] + uint16_t next_datagram_offset; // Offset in transmit_ntb[current_ntb].data to place the next datagram + uint16_t ntb_in_size; // Maximum size of transmitted (IN to host) NTBs; initially CFG_TUD_NCM_IN_NTB_MAX_SIZE + uint8_t max_datagrams_per_ntb; // Maximum number of datagrams per NTB; initially CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB + + uint16_t nth_sequence; // Sequence number counter for transmitted NTBs + + bool transferring; + +} ncm_interface_t; + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static const ntb_parameters_t ntb_parameters = { + .wLength = sizeof(ntb_parameters_t), + .bmNtbFormatsSupported = 0x01, + .dwNtbInMaxSize = CFG_TUD_NCM_IN_NTB_MAX_SIZE, + .wNdbInDivisor = 4, + .wNdbInPayloadRemainder = 0, + .wNdbInAlignment = CFG_TUD_NCM_ALIGNMENT, + .wReserved = 0, + .dwNtbOutMaxSize = CFG_TUD_NCM_OUT_NTB_MAX_SIZE, + .wNdbOutDivisor = 4, + .wNdbOutPayloadRemainder = 0, + .wNdbOutAlignment = CFG_TUD_NCM_ALIGNMENT, + .wNtbOutMaxDatagrams = 0 +}; + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static transmit_ntb_t transmit_ntb[2]; + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t receive_ntb[CFG_TUD_NCM_OUT_NTB_MAX_SIZE]; + +static ncm_interface_t ncm_interface; + +/* + * Set up the NTB state in ncm_interface to be ready to add datagrams. + */ +static void ncm_prepare_for_tx(void) { + ncm_interface.datagram_count = 0; + // datagrams start after all the headers + ncm_interface.next_datagram_offset = sizeof(nth16_t) + sizeof(ndp16_t) + + ((CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB + 1) * sizeof(ndp16_datagram_t)); +} + +/* + * If not already transmitting, start sending the current NTB to the host and swap buffers + * to start filling the other one with datagrams. + */ +static void ncm_start_tx(void) { + if (ncm_interface.transferring) { + return; + } + + transmit_ntb_t *ntb = &transmit_ntb[ncm_interface.current_ntb]; + size_t ntb_length = ncm_interface.next_datagram_offset; + + // Fill in NTB header + ntb->nth.dwSignature = NTH16_SIGNATURE; + ntb->nth.wHeaderLength = sizeof(nth16_t); + ntb->nth.wSequence = ncm_interface.nth_sequence++; + ntb->nth.wBlockLength = ntb_length; + ntb->nth.wNdpIndex = sizeof(nth16_t); + + // Fill in NDP16 header and terminator + ntb->ndp.dwSignature = NDP16_SIGNATURE_NCM0; + ntb->ndp.wLength = sizeof(ndp16_t) + (ncm_interface.datagram_count + 1) * sizeof(ndp16_datagram_t); + ntb->ndp.wNextNdpIndex = 0; + ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramIndex = 0; + ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramLength = 0; + + // Kick off an endpoint transfer + usbd_edpt_xfer(0, ncm_interface.ep_in, ntb->data, ntb_length); + ncm_interface.transferring = true; + + // Swap to the other NTB and clear it out + ncm_interface.current_ntb = 1 - ncm_interface.current_ntb; + ncm_prepare_for_tx(); +} + +static struct ecm_notify_struct ncm_notify_connected = +{ + .header = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN + }, + .bRequest = CDC_NOTIF_NETWORK_CONNECTION, + .wValue = 1 /* Connected */, + .wLength = 0, + }, +}; + +static struct ecm_notify_struct ncm_notify_speed_change = +{ + .header = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN + }, + .bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE, + .wLength = 8, + }, + .downlink = 10000000, + .uplink = 10000000, +}; + +void tud_network_recv_renew(void) +{ + if (!ncm_interface.num_datagrams) + { + usbd_edpt_xfer(0, ncm_interface.ep_out, receive_ntb, sizeof(receive_ntb)); + return; + } + + const ndp16_t *ndp = ncm_interface.ndp; + const int i = ncm_interface.current_datagram_index; + ncm_interface.current_datagram_index++; + ncm_interface.num_datagrams--; + + tud_network_recv_cb(receive_ntb + ndp->datagram[i].wDatagramIndex, ndp->datagram[i].wDatagramLength); +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ + +void netd_init(void) +{ + tu_memclr(&ncm_interface, sizeof(ncm_interface)); + ncm_interface.ntb_in_size = CFG_TUD_NCM_IN_NTB_MAX_SIZE; + ncm_interface.max_datagrams_per_ntb = CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB; + ncm_prepare_for_tx(); +} + +void netd_reset(uint8_t rhport) +{ + (void) rhport; + + netd_init(); +} + +uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + // confirm interface hasn't already been allocated + TU_ASSERT(0 == ncm_interface.ep_notif, 0); + + //------------- Management Interface -------------// + ncm_interface.itf_num = itf_desc->bInterfaceNumber; + + uint16_t drv_len = sizeof(tusb_desc_interface_t); + uint8_t const * p_desc = tu_desc_next( itf_desc ); + + // Communication Functional Descriptors + while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) + { + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + // notification endpoint (if any) + if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + { + TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 ); + + ncm_interface.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + //------------- Data Interface -------------// + // - CDC-NCM data interface has 2 alternate settings + // - 0 : zero endpoints for inactive (default) + // - 1 : IN & OUT endpoints for transfer of NTBs + TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); + + do + { + tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc; + TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass, 0); + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } while((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (drv_len <= max_len)); + + // Pair of endpoints + TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0); + + TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &ncm_interface.ep_out, &ncm_interface.ep_in) ); + + drv_len += 2*sizeof(tusb_desc_endpoint_t); + + return drv_len; +} + +static void ncm_report(void) +{ + uint8_t const rhport = 0; + if (ncm_interface.report_state == REPORT_SPEED) { + ncm_notify_speed_change.header.wIndex = ncm_interface.itf_num; + usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_speed_change, sizeof(ncm_notify_speed_change)); + ncm_interface.report_state = REPORT_CONNECTED; + ncm_interface.report_pending = true; + } else if (ncm_interface.report_state == REPORT_CONNECTED) { + ncm_notify_connected.header.wIndex = ncm_interface.itf_num; + usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_connected, sizeof(ncm_notify_connected)); + ncm_interface.report_state = REPORT_DONE; + ncm_interface.report_pending = true; + } +} + +TU_ATTR_WEAK void tud_network_link_state_cb(bool state) +{ + (void)state; +} + +// Handle class control request +// return false to stall control endpoint (e.g unsupported request) +bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if ( stage != CONTROL_STAGE_SETUP ) return true; + + switch ( request->bmRequestType_bit.type ) + { + case TUSB_REQ_TYPE_STANDARD: + switch ( request->bRequest ) + { + case TUSB_REQ_GET_INTERFACE: + { + uint8_t const req_itfnum = (uint8_t) request->wIndex; + TU_VERIFY(ncm_interface.itf_num + 1 == req_itfnum); + + tud_control_xfer(rhport, request, &ncm_interface.itf_data_alt, 1); + } + break; + + case TUSB_REQ_SET_INTERFACE: + { + uint8_t const req_itfnum = (uint8_t) request->wIndex; + uint8_t const req_alt = (uint8_t) request->wValue; + + // Only valid for Data Interface with Alternate is either 0 or 1 + TU_VERIFY(ncm_interface.itf_num + 1 == req_itfnum && req_alt < 2); + + if (req_alt != ncm_interface.itf_data_alt) { + ncm_interface.itf_data_alt = req_alt; + + if (ncm_interface.itf_data_alt) { + if (!usbd_edpt_busy(rhport, ncm_interface.ep_out)) { + tud_network_recv_renew(); // prepare for incoming datagrams + } + if (!ncm_interface.report_pending) { + ncm_report(); + } + } + + tud_network_link_state_cb(ncm_interface.itf_data_alt); + } + + tud_control_status(rhport, request); + } + break; + + // unsupported request + default: return false; + } + break; + + case TUSB_REQ_TYPE_CLASS: + TU_VERIFY (ncm_interface.itf_num == request->wIndex); + + if (NCM_GET_NTB_PARAMETERS == request->bRequest) + { + tud_control_xfer(rhport, request, (void*)&ntb_parameters, sizeof(ntb_parameters)); + } + + break; + + // unsupported request + default: return false; + } + + return true; +} + +static void handle_incoming_datagram(uint32_t len) +{ + uint32_t size = len; + + if (len == 0) { + return; + } + + TU_ASSERT(size >= sizeof(nth16_t), ); + + const nth16_t *hdr = (const nth16_t *)receive_ntb; + TU_ASSERT(hdr->dwSignature == NTH16_SIGNATURE, ); + TU_ASSERT(hdr->wNdpIndex >= sizeof(nth16_t) && (hdr->wNdpIndex + sizeof(ndp16_t)) <= len, ); + + const ndp16_t *ndp = (const ndp16_t *)(receive_ntb + hdr->wNdpIndex); + TU_ASSERT(ndp->dwSignature == NDP16_SIGNATURE_NCM0 || ndp->dwSignature == NDP16_SIGNATURE_NCM1, ); + TU_ASSERT(hdr->wNdpIndex + ndp->wLength <= len, ); + + int num_datagrams = (ndp->wLength - 12) / 4; + ncm_interface.current_datagram_index = 0; + ncm_interface.num_datagrams = 0; + ncm_interface.ndp = ndp; + for (int i = 0; i < num_datagrams && ndp->datagram[i].wDatagramIndex && ndp->datagram[i].wDatagramLength; i++) + { + ncm_interface.num_datagrams++; + } + + tud_network_recv_renew(); +} + +bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) rhport; + (void) result; + + /* new datagram receive_ntb */ + if (ep_addr == ncm_interface.ep_out ) + { + handle_incoming_datagram(xferred_bytes); + } + + /* data transmission finished */ + if (ep_addr == ncm_interface.ep_in ) + { + if (ncm_interface.transferring) { + ncm_interface.transferring = false; + } + + // If there are datagrams queued up that we tried to send while this NTB was being emitted, send them now + if (ncm_interface.datagram_count && ncm_interface.itf_data_alt == 1) { + ncm_start_tx(); + } + } + + if (ep_addr == ncm_interface.ep_notif ) + { + ncm_interface.report_pending = false; + ncm_report(); + } + + return true; +} + +// poll network driver for its ability to accept another packet to transmit +bool tud_network_can_xmit(uint16_t size) +{ + TU_VERIFY(ncm_interface.itf_data_alt == 1); + + if (ncm_interface.datagram_count >= ncm_interface.max_datagrams_per_ntb) { + TU_LOG2("NTB full [by count]\r\n"); + return false; + } + + size_t next_datagram_offset = ncm_interface.next_datagram_offset; + if (next_datagram_offset + size > ncm_interface.ntb_in_size) { + TU_LOG2("ntb full [by size]\r\n"); + return false; + } + + return true; +} + +void tud_network_xmit(void *ref, uint16_t arg) +{ + transmit_ntb_t *ntb = &transmit_ntb[ncm_interface.current_ntb]; + size_t next_datagram_offset = ncm_interface.next_datagram_offset; + + uint16_t size = tud_network_xmit_cb(ntb->data + next_datagram_offset, ref, arg); + + ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramIndex = ncm_interface.next_datagram_offset; + ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramLength = size; + + ncm_interface.datagram_count++; + next_datagram_offset += size; + + // round up so the next datagram is aligned correctly + next_datagram_offset += (CFG_TUD_NCM_ALIGNMENT - 1); + next_datagram_offset -= (next_datagram_offset % CFG_TUD_NCM_ALIGNMENT); + + ncm_interface.next_datagram_offset = next_datagram_offset; + + ncm_start_tx(); +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/net/net_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/net/net_device.h new file mode 100644 index 00000000..6e294465 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/net/net_device.h @@ -0,0 +1,118 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Peter Lawrence + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_NET_DEVICE_H_ +#define _TUSB_NET_DEVICE_H_ + +#include "class/cdc/cdc.h" + +#if CFG_TUD_ECM_RNDIS && CFG_TUD_NCM +#error "Cannot enable both ECM_RNDIS and NCM network drivers" +#endif + +#include "ncm.h" + +/* declared here, NOT in usb_descriptors.c, so that the driver can intelligently ZLP as needed */ +#define CFG_TUD_NET_ENDPOINT_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) + +/* Maximum Transmission Unit (in bytes) of the network, including Ethernet header */ +#ifndef CFG_TUD_NET_MTU +#define CFG_TUD_NET_MTU 1514 +#endif + +#ifndef CFG_TUD_NCM_IN_NTB_MAX_SIZE +#define CFG_TUD_NCM_IN_NTB_MAX_SIZE 3200 +#endif + +#ifndef CFG_TUD_NCM_OUT_NTB_MAX_SIZE +#define CFG_TUD_NCM_OUT_NTB_MAX_SIZE 3200 +#endif + +#ifndef CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB +#define CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB 8 +#endif + +#ifndef CFG_TUD_NCM_ALIGNMENT +#define CFG_TUD_NCM_ALIGNMENT 4 +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + +// indicate to network driver that client has finished with the packet provided to network_recv_cb() +void tud_network_recv_renew(void); + +// poll network driver for its ability to accept another packet to transmit +bool tud_network_can_xmit(uint16_t size); + +// if network_can_xmit() returns true, network_xmit() can be called once +void tud_network_xmit(void *ref, uint16_t arg); + +//--------------------------------------------------------------------+ +// Application Callbacks (WEAK is optional) +//--------------------------------------------------------------------+ + +// client must provide this: return false if the packet buffer was not accepted +bool tud_network_recv_cb(const uint8_t *src, uint16_t size); + +// client must provide this: copy from network stack packet pointer to dst +uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg); + +//------------- ECM/RNDIS -------------// + +// client must provide this: initialize any network state back to the beginning +void tud_network_init_cb(void); + +// client must provide this: 48-bit MAC address +// TODO removed later since it is not part of tinyusb stack +extern const uint8_t tud_network_mac_address[6]; + +//------------- NCM -------------// + +// callback to client providing optional indication of internal state of network driver +void tud_network_link_state_cb(bool state); + +//--------------------------------------------------------------------+ +// INTERNAL USBD-CLASS DRIVER API +//--------------------------------------------------------------------+ +void netd_init (void); +void netd_reset (uint8_t rhport); +uint16_t netd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +bool netd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); +void netd_report (uint8_t *buf, uint16_t len); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_NET_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc.h b/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc.h new file mode 100644 index 00000000..e7016ae2 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc.h @@ -0,0 +1,319 @@ + +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 N Conrad + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_USBTMC_H__ +#define _TUSB_USBTMC_H__ + +#include "common/tusb_common.h" + + +/* Implements USBTMC Revision 1.0, April 14, 2003 + + String descriptors must have a "LANGID=0x409"/US English string. + Characters must be 0x20 (' ') to 0x7E ('~') ASCII, + But MUST not contain: "/:?\* + Also must not have leading or trailing space (' ') + Device descriptor must state USB version 0x0200 or greater + + If USB488DeviceCapabilites.D2 = 1 (SR1), then there must be a INT endpoint. +*/ + +#define USBTMC_VERSION 0x0100 +#define USBTMC_488_VERSION 0x0100 + +typedef enum { + USBTMC_MSGID_DEV_DEP_MSG_OUT = 1u, + USBTMC_MSGID_DEV_DEP_MSG_IN = 2u, + USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT = 126u, + USBTMC_MSGID_VENDOR_SPECIFIC_IN = 127u, + USBTMC_MSGID_USB488_TRIGGER = 128u, +} usbtmc_msgid_enum; + +/// \brief Message header (For BULK OUT and BULK IN); 4 bytes +typedef struct TU_ATTR_PACKED +{ + uint8_t MsgID ; ///< Message type ID (usbtmc_msgid_enum) + uint8_t bTag ; ///< Transfer ID 1<=bTag<=255 + uint8_t bTagInverse ; ///< Complement of the tag + uint8_t _reserved ; ///< Must be 0x00 +} usbtmc_msg_header_t; + +typedef struct TU_ATTR_PACKED +{ + usbtmc_msg_header_t header; + uint8_t data[8]; +} usbtmc_msg_generic_t; + +/* Uses on the bulk-out endpoint: */ +// Next 8 bytes are message-specific +typedef struct TU_ATTR_PACKED { + usbtmc_msg_header_t header ; ///< Header + uint32_t TransferSize ; ///< Transfer size; LSB first + struct TU_ATTR_PACKED + { + unsigned int EOM : 1 ; ///< EOM set on last byte + } bmTransferAttributes; + uint8_t _reserved[3]; +} usbtmc_msg_request_dev_dep_out; + +TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_dev_dep_out) == 12u, "struct wrong length"); + +// Next 8 bytes are message-specific +typedef struct TU_ATTR_PACKED +{ + usbtmc_msg_header_t header ; ///< Header + uint32_t TransferSize ; ///< Transfer size; LSB first + struct TU_ATTR_PACKED + { + unsigned int TermCharEnabled : 1 ; ///< "The Bulk-IN transfer must terminate on the specified TermChar."; CAPABILITIES must list TermChar + } bmTransferAttributes; + uint8_t TermChar; + uint8_t _reserved[2]; +} usbtmc_msg_request_dev_dep_in; + +TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_dev_dep_in) == 12u, "struct wrong length"); + +/* Bulk-in headers */ + +typedef struct TU_ATTR_PACKED +{ + usbtmc_msg_header_t header; + uint32_t TransferSize; + struct TU_ATTR_PACKED + { + uint8_t EOM: 1; ///< Last byte of transfer is the end of the message + uint8_t UsingTermChar: 1; ///< Support TermChar && Request.TermCharEnabled && last char in transfer is TermChar + } bmTransferAttributes; + uint8_t _reserved[3]; +} usbtmc_msg_dev_dep_msg_in_header_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_msg_dev_dep_msg_in_header_t) == 12u, "struct wrong length"); + +/* Unsupported vendor things.... Are these ever used?*/ + +typedef struct TU_ATTR_PACKED +{ + usbtmc_msg_header_t header ; ///< Header + uint32_t TransferSize ; ///< Transfer size; LSB first + uint8_t _reserved[4]; +} usbtmc_msg_request_vendor_specific_out; + + +TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_vendor_specific_out) == 12u, "struct wrong length"); + +typedef struct TU_ATTR_PACKED +{ + usbtmc_msg_header_t header ; ///< Header + uint32_t TransferSize ; ///< Transfer size; LSB first + uint8_t _reserved[4]; +} usbtmc_msg_request_vendor_specific_in; + +TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_vendor_specific_in) == 12u, "struct wrong length"); + +// Control request type should use tusb_control_request_t + +/* +typedef struct TU_ATTR_PACKED { + struct { + unsigned int Recipient : 5 ; ///< EOM set on last byte + unsigned int Type : 2 ; ///< EOM set on last byte + unsigned int DirectionToHost : 1 ; ///< 0 is OUT, 1 is IN + } bmRequestType; + uint8_t bRequest ; ///< If bmRequestType.Type = Class, see usmtmc_request_type_enum + uint16_t wValue ; + uint16_t wIndex ; + uint16_t wLength ; // Number of bytes in data stage +} usbtmc_class_specific_control_req; + +*/ +// bulk-in protocol errors +enum { + USBTMC_BULK_IN_ERR_INCOMPLETE_HEADER = 1u, + USBTMC_BULK_IN_ERR_UNSUPPORTED = 2u, + USBTMC_BULK_IN_ERR_BAD_PARAMETER = 3u, + USBTMC_BULK_IN_ERR_DATA_TOO_SHORT = 4u, + USBTMC_BULK_IN_ERR_DATA_TOO_LONG = 5u, +}; +// bult-in halt errors +enum { + USBTMC_BULK_IN_ERR = 1u, ///< receives a USBTMC command message that expects a response while a + /// Bulk-IN transfer is in progress +}; + +typedef enum { + USBTMC_bREQUEST_INITIATE_ABORT_BULK_OUT = 1u, + USBTMC_bREQUEST_CHECK_ABORT_BULK_OUT_STATUS = 2u, + USBTMC_bREQUEST_INITIATE_ABORT_BULK_IN = 3u, + USBTMC_bREQUEST_CHECK_ABORT_BULK_IN_STATUS = 4u, + USBTMC_bREQUEST_INITIATE_CLEAR = 5u, + USBTMC_bREQUEST_CHECK_CLEAR_STATUS = 6u, + USBTMC_bREQUEST_GET_CAPABILITIES = 7u, + + USBTMC_bREQUEST_INDICATOR_PULSE = 64u, // Optional + + /****** USBTMC 488 *************/ + USB488_bREQUEST_READ_STATUS_BYTE = 128u, + USB488_bREQUEST_REN_CONTROL = 160u, + USB488_bREQUEST_GO_TO_LOCAL = 161u, + USB488_bREQUEST_LOCAL_LOCKOUT = 162u, + +} usmtmc_request_type_enum; + +typedef enum { + USBTMC_STATUS_SUCCESS = 0x01, + USBTMC_STATUS_PENDING = 0x02, + USBTMC_STATUS_FAILED = 0x80, + USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS = 0x81, + USBTMC_STATUS_SPLIT_NOT_IN_PROGRESS = 0x82, + USBTMC_STATUS_SPLIT_IN_PROGRESS = 0x83, + + /****** USBTMC 488 *************/ + USB488_STATUS_INTERRUPT_IN_BUSY = 0x20 +} usbtmc_status_enum; + +/************************************************************ + * Control Responses + */ + +typedef struct TU_ATTR_PACKED { + uint8_t USBTMC_status; ///< usbtmc_status_enum + uint8_t _reserved; + uint16_t bcdUSBTMC; ///< USBTMC_VERSION + + struct TU_ATTR_PACKED + { + unsigned int listenOnly :1; + unsigned int talkOnly :1; + unsigned int supportsIndicatorPulse :1; + } bmIntfcCapabilities; + struct TU_ATTR_PACKED + { + unsigned int canEndBulkInOnTermChar :1; + } bmDevCapabilities; + uint8_t _reserved2[6]; + uint8_t _reserved3[12]; +} usbtmc_response_capabilities_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_response_capabilities_t) == 0x18, "struct wrong length"); + +typedef struct TU_ATTR_PACKED +{ + uint8_t USBTMC_status; + struct TU_ATTR_PACKED + { + unsigned int BulkInFifoBytes :1; + } bmClear; +} usbtmc_get_clear_status_rsp_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_get_clear_status_rsp_t) == 2u, "struct wrong length"); + +// Used for both abort bulk IN and bulk OUT +typedef struct TU_ATTR_PACKED +{ + uint8_t USBTMC_status; + uint8_t bTag; +} usbtmc_initiate_abort_rsp_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_get_clear_status_rsp_t) == 2u, "struct wrong length"); + +// Used for both check_abort_bulk_in_status and check_abort_bulk_out_status +typedef struct TU_ATTR_PACKED +{ + uint8_t USBTMC_status; + struct TU_ATTR_PACKED + { + unsigned int BulkInFifoBytes : 1; ///< Has queued data or a short packet that is queued + } bmAbortBulkIn; + uint8_t _reserved[2]; ///< Must be zero + uint32_t NBYTES_RXD_TXD; +} usbtmc_check_abort_bulk_rsp_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_check_abort_bulk_rsp_t) == 8u, "struct wrong length"); + +typedef struct TU_ATTR_PACKED +{ + uint8_t USBTMC_status; ///< usbtmc_status_enum + uint8_t _reserved; + uint16_t bcdUSBTMC; ///< USBTMC_VERSION + + struct TU_ATTR_PACKED + { + unsigned int listenOnly :1; + unsigned int talkOnly :1; + unsigned int supportsIndicatorPulse :1; + } bmIntfcCapabilities; + + struct TU_ATTR_PACKED + { + unsigned int canEndBulkInOnTermChar :1; + } bmDevCapabilities; + + uint8_t _reserved2[6]; + uint16_t bcdUSB488; + + struct TU_ATTR_PACKED + { + unsigned int is488_2 :1; + unsigned int supportsREN_GTL_LLO :1; + unsigned int supportsTrigger :1; + } bmIntfcCapabilities488; + + struct TU_ATTR_PACKED + { + unsigned int SCPI :1; + unsigned int SR1 :1; + unsigned int RL1 :1; + unsigned int DT1 :1; + } bmDevCapabilities488; + uint8_t _reserved3[8]; +} usbtmc_response_capabilities_488_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_response_capabilities_488_t) == 0x18, "struct wrong length"); + +typedef struct TU_ATTR_PACKED +{ + uint8_t USBTMC_status; + uint8_t bTag; + uint8_t statusByte; +} usbtmc_read_stb_rsp_488_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_rsp_488_t) == 3u, "struct wrong length"); + +typedef struct TU_ATTR_PACKED +{ + struct TU_ATTR_PACKED + { + unsigned int bTag : 7; + unsigned int one : 1; + } bNotify1; + uint8_t StatusByte; +} usbtmc_read_stb_interrupt_488_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_interrupt_488_t) == 2u, "struct wrong length"); + +#endif + diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c new file mode 100644 index 00000000..af4a9273 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c @@ -0,0 +1,886 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Nathan Conrad + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/* + * This library is not fully reentrant, though it is reentrant from the view + * of either the application layer or the USB stack. Due to its locking, + * it is not safe to call its functions from interrupts. + * + * The one exception is that its functions may not be called from the application + * until the USB stack is initialized. This should not be a problem since the + * device shouldn't be sending messages until it receives a request from the + * host. + */ + + +/* + * In the case of single-CPU "no OS", this task is never preempted other than by + * interrupts, and the USBTMC code isn't called by interrupts, so all is OK. For "no OS", + * the mutex structure's main effect is to disable the USB interrupts. + * With an OS, this class driver uses the OSAL to perform locking. The code uses a single lock + * and does not call outside of this class with a lock held, so deadlocks won't happen. + */ + +//Limitations: +// "vendor-specific" commands are not handled. +// Dealing with "termchar" must be handled by the application layer, +// though additional error checking is does in this module. +// talkOnly and listenOnly are NOT supported. They're not permitted +// in USB488, anyway. + +/* Supported: + * + * Notification pulse + * Trigger + * Read status byte (both by interrupt endpoint and control message) + * + */ + + +// TODO: +// USBTMC 3.2.2 error conditions not strictly followed +// No local lock-out, REN, or GTL. +// Clear message available status byte at the correct time? (488 4.3.1.3) +// Ability to defer status byte transmission +// Transmission of status byte in response to USB488 SRQ condition + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_USBTMC) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "usbtmc_device.h" + +#ifdef xDEBUG +#include "uart_util.h" +static char logMsg[150]; +#endif + +// Buffer size must be an exact multiple of the max packet size for both +// bulk (up to 64 bytes for FS, 512 bytes for HS). In addation, this driver +// imposes a minimum buffer size of 32 bytes. +#define USBTMCD_BUFFER_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) + +/* + * The state machine does not allow simultaneous reading and writing. This is + * consistent with USBTMC. + */ + +typedef enum +{ + STATE_CLOSED, // Endpoints have not yet been opened since USB reset + STATE_NAK, // Bulk-out endpoint is in NAK state. + STATE_IDLE, // Bulk-out endpoint is waiting for CMD. + STATE_RCV, // Bulk-out is receiving DEV_DEP message + STATE_TX_REQUESTED, + STATE_TX_INITIATED, + STATE_TX_SHORTED, + STATE_CLEARING, + STATE_ABORTING_BULK_IN, + STATE_ABORTING_BULK_IN_SHORTED, // aborting, and short packet has been queued for transmission + STATE_ABORTING_BULK_IN_ABORTED, // aborting, and short packet has been transmitted + STATE_ABORTING_BULK_OUT, + STATE_NUM_STATES +} usbtmcd_state_enum; + +#if (CFG_TUD_USBTMC_ENABLE_488) + typedef usbtmc_response_capabilities_488_t usbtmc_capabilities_specific_t; +#else + typedef usbtmc_response_capabilities_t usbtmc_capabilities_specific_t; +#endif + + +typedef struct +{ + volatile usbtmcd_state_enum state; + + uint8_t itf_id; + uint8_t rhport; + uint8_t ep_bulk_in; + uint8_t ep_bulk_out; + uint8_t ep_int_in; + // IN buffer is only used for first packet, not the remainder + // in order to deal with prepending header + CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_in_buf[USBTMCD_BUFFER_SIZE]; + uint32_t ep_bulk_in_wMaxPacketSize; + // OUT buffer receives one packet at a time + CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_out_buf[USBTMCD_BUFFER_SIZE]; + uint32_t ep_bulk_out_wMaxPacketSize; + + uint32_t transfer_size_remaining; // also used for requested length for bulk IN. + uint32_t transfer_size_sent; // To keep track of data bytes that have been queued in FIFO (not header bytes) + + uint8_t lastBulkOutTag; // used for aborts (mostly) + uint8_t lastBulkInTag; // used for aborts (mostly) + + uint8_t const * devInBuffer; // pointer to application-layer used for transmissions + + usbtmc_capabilities_specific_t const * capabilities; +} usbtmc_interface_state_t; + +CFG_TUSB_MEM_SECTION static usbtmc_interface_state_t usbtmc_state = +{ + .itf_id = 0xFF, +}; + +// We need all headers to fit in a single packet in this implementation, 32 bytes will fit all standard USBTMC headers +TU_VERIFY_STATIC(USBTMCD_BUFFER_SIZE >= 32u,"USBTMC dev buffer size too small"); + +static bool handle_devMsgOutStart(uint8_t rhport, void *data, size_t len); +static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t packetLen); + +static uint8_t termChar; +static uint8_t termCharRequested = false; + +osal_mutex_def_t usbtmcLockBuffer; +static osal_mutex_t usbtmcLock; + +// Our own private lock, mostly for the state variable. +#define criticalEnter() do {osal_mutex_lock(usbtmcLock,OSAL_TIMEOUT_WAIT_FOREVER); } while (0) +#define criticalLeave() do {osal_mutex_unlock(usbtmcLock); } while (0) + +bool atomicChangeState(usbtmcd_state_enum expectedState, usbtmcd_state_enum newState) +{ + bool ret = true; + criticalEnter(); + usbtmcd_state_enum oldState = usbtmc_state.state; + if (oldState == expectedState) + { + usbtmc_state.state = newState; + } + else + { + ret = false; + } + criticalLeave(); + return ret; +} + +// called from app +// We keep a reference to the buffer, so it MUST not change until the app is +// notified that the transfer is complete. +// length of data is specified in the hdr. + +// We can't just send the whole thing at once because we need to concatanate the +// header with the data. +bool tud_usbtmc_transmit_dev_msg_data( + const void * data, size_t len, + bool endOfMessage, + bool usingTermChar) +{ + const unsigned int txBufLen = sizeof(usbtmc_state.ep_bulk_in_buf); + +#ifndef NDEBUG + TU_ASSERT(len > 0u); + TU_ASSERT(len <= usbtmc_state.transfer_size_remaining); + TU_ASSERT(usbtmc_state.transfer_size_sent == 0u); + if(usingTermChar) + { + TU_ASSERT(usbtmc_state.capabilities->bmDevCapabilities.canEndBulkInOnTermChar); + TU_ASSERT(termCharRequested); + TU_ASSERT(((uint8_t const*)data)[len-1u] == termChar); + } +#endif + + TU_VERIFY(usbtmc_state.state == STATE_TX_REQUESTED); + usbtmc_msg_dev_dep_msg_in_header_t *hdr = (usbtmc_msg_dev_dep_msg_in_header_t*)usbtmc_state.ep_bulk_in_buf; + tu_varclr(hdr); + hdr->header.MsgID = USBTMC_MSGID_DEV_DEP_MSG_IN; + hdr->header.bTag = usbtmc_state.lastBulkInTag; + hdr->header.bTagInverse = (uint8_t)~(usbtmc_state.lastBulkInTag); + hdr->TransferSize = len; + hdr->bmTransferAttributes.EOM = endOfMessage; + hdr->bmTransferAttributes.UsingTermChar = usingTermChar; + + // Copy in the header + const size_t headerLen = sizeof(*hdr); + const size_t dataLen = ((headerLen + hdr->TransferSize) <= txBufLen) ? + len : (txBufLen - headerLen); + const size_t packetLen = headerLen + dataLen; + + memcpy((uint8_t*)(usbtmc_state.ep_bulk_in_buf) + headerLen, data, dataLen); + usbtmc_state.transfer_size_remaining = len - dataLen; + usbtmc_state.transfer_size_sent = dataLen; + usbtmc_state.devInBuffer = (uint8_t const*) data + (dataLen); + + bool stateChanged = + atomicChangeState(STATE_TX_REQUESTED, (packetLen >= txBufLen) ? STATE_TX_INITIATED : STATE_TX_SHORTED); + TU_VERIFY(stateChanged); + TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf, (uint16_t)packetLen)); + return true; +} + +void usbtmcd_init_cb(void) +{ + usbtmc_state.capabilities = tud_usbtmc_get_capabilities_cb(); +#ifndef NDEBUG +# if CFG_TUD_USBTMC_ENABLE_488 + if (usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger) { + TU_ASSERT(&tud_usbtmc_msg_trigger_cb != NULL,); + } + // Per USB488 spec: table 8 + TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.listenOnly,); + TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.talkOnly,); +# endif + if (usbtmc_state.capabilities->bmIntfcCapabilities.supportsIndicatorPulse) { + TU_ASSERT(&tud_usbtmc_indicator_pulse_cb != NULL,); + } +#endif + + usbtmcLock = osal_mutex_create(&usbtmcLockBuffer); +} + +uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + (void)rhport; + + uint16_t drv_len; + uint8_t const * p_desc; + uint8_t found_endpoints = 0; + + TU_VERIFY(itf_desc->bInterfaceClass == TUD_USBTMC_APP_CLASS , 0); + TU_VERIFY(itf_desc->bInterfaceSubClass == TUD_USBTMC_APP_SUBCLASS, 0); + +#ifndef NDEBUG + // Only 2 or 3 endpoints are allowed for USBTMC. + TU_ASSERT((itf_desc->bNumEndpoints == 2) || (itf_desc->bNumEndpoints ==3), 0); +#endif + + TU_ASSERT(usbtmc_state.state == STATE_CLOSED, 0); + + // Interface + drv_len = 0u; + p_desc = (uint8_t const *) itf_desc; + + usbtmc_state.itf_id = itf_desc->bInterfaceNumber; + usbtmc_state.rhport = rhport; + + while (found_endpoints < itf_desc->bNumEndpoints && drv_len <= max_len) + { + if ( TUSB_DESC_ENDPOINT == p_desc[DESC_OFFSET_TYPE]) + { + tusb_desc_endpoint_t const *ep_desc = (tusb_desc_endpoint_t const *)p_desc; + switch(ep_desc->bmAttributes.xfer) { + case TUSB_XFER_BULK: + // Ensure buffer is an exact multiple of the maxPacketSize + TU_ASSERT((USBTMCD_BUFFER_SIZE % tu_edpt_packet_size(ep_desc)) == 0, 0); + if (tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN) + { + usbtmc_state.ep_bulk_in = ep_desc->bEndpointAddress; + usbtmc_state.ep_bulk_in_wMaxPacketSize = tu_edpt_packet_size(ep_desc); + } else { + usbtmc_state.ep_bulk_out = ep_desc->bEndpointAddress; + usbtmc_state.ep_bulk_out_wMaxPacketSize = tu_edpt_packet_size(ep_desc); + } + + break; + case TUSB_XFER_INTERRUPT: +#ifndef NDEBUG + TU_ASSERT(tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN, 0); + TU_ASSERT(usbtmc_state.ep_int_in == 0, 0); +#endif + usbtmc_state.ep_int_in = ep_desc->bEndpointAddress; + break; + default: + TU_ASSERT(false, 0); + } + TU_ASSERT( usbd_edpt_open(rhport, ep_desc), 0); + found_endpoints++; + } + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + // bulk endpoints are required, but interrupt IN is optional +#ifndef NDEBUG + TU_ASSERT(usbtmc_state.ep_bulk_in != 0, 0); + TU_ASSERT(usbtmc_state.ep_bulk_out != 0, 0); + if (itf_desc->bNumEndpoints == 2) + { + TU_ASSERT(usbtmc_state.ep_int_in == 0, 0); + } + else if (itf_desc->bNumEndpoints == 3) + { + TU_ASSERT(usbtmc_state.ep_int_in != 0, 0); + } +#if (CFG_TUD_USBTMC_ENABLE_488) + if(usbtmc_state.capabilities->bmIntfcCapabilities488.is488_2 || + usbtmc_state.capabilities->bmDevCapabilities488.SR1) + { + TU_ASSERT(usbtmc_state.ep_int_in != 0, 0); + } +#endif +#endif + atomicChangeState(STATE_CLOSED, STATE_NAK); + tud_usbtmc_open_cb(itf_desc->iInterface); + + return drv_len; +} +// Tell USBTMC class to set its bulk-in EP to ACK so that it can +// receive USBTMC commands. +// Returns false if it was already in an ACK state or is busy +// processing a command (such as a clear). Returns true if it was +// in the NAK state and successfully transitioned to the ACK wait +// state. +bool tud_usbtmc_start_bus_read() +{ + usbtmcd_state_enum oldState = usbtmc_state.state; + switch(oldState) + { + // These may transition to IDLE + case STATE_NAK: + case STATE_ABORTING_BULK_IN_ABORTED: + TU_VERIFY(atomicChangeState(oldState, STATE_IDLE)); + break; + // When receiving, let it remain receiving + case STATE_RCV: + break; + default: + TU_VERIFY(false); + } + TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, 64)); + return true; +} + +void usbtmcd_reset_cb(uint8_t rhport) +{ + (void)rhport; + usbtmc_capabilities_specific_t const * capabilities = tud_usbtmc_get_capabilities_cb(); + + criticalEnter(); + tu_varclr(&usbtmc_state); + usbtmc_state.capabilities = capabilities; + usbtmc_state.itf_id = 0xFFu; + criticalLeave(); +} + +static bool handle_devMsgOutStart(uint8_t rhport, void *data, size_t len) +{ + (void)rhport; + // return true upon failure, as we can assume error is being handled elsewhere. + TU_VERIFY(atomicChangeState(STATE_IDLE, STATE_RCV), true); + usbtmc_state.transfer_size_sent = 0u; + + // must be a header, should have been confirmed before calling here. + usbtmc_msg_request_dev_dep_out *msg = (usbtmc_msg_request_dev_dep_out*)data; + usbtmc_state.transfer_size_remaining = msg->TransferSize; + TU_VERIFY(tud_usbtmc_msgBulkOut_start_cb(msg)); + + TU_VERIFY(handle_devMsgOut(rhport, (uint8_t*)data + sizeof(*msg), len - sizeof(*msg), len)); + usbtmc_state.lastBulkOutTag = msg->header.bTag; + return true; +} + +static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t packetLen) +{ + (void)rhport; + // return true upon failure, as we can assume error is being handled elsewhere. + TU_VERIFY(usbtmc_state.state == STATE_RCV,true); + + bool shortPacket = (packetLen < usbtmc_state.ep_bulk_out_wMaxPacketSize); + + // Packet is to be considered complete when we get enough data or at a short packet. + bool atEnd = false; + if(len >= usbtmc_state.transfer_size_remaining || shortPacket) + { + atEnd = true; + TU_VERIFY(atomicChangeState(STATE_RCV, STATE_NAK)); + } + + len = tu_min32(len, usbtmc_state.transfer_size_remaining); + + usbtmc_state.transfer_size_remaining -= len; + usbtmc_state.transfer_size_sent += len; + + // App may (should?) call the wait_for_bus() command at this point + if(!tud_usbtmc_msg_data_cb(data, len, atEnd)) + { + // TODO: Go to an error state upon failure other than just stalling the EP? + return false; + } + + + return true; +} + +static bool handle_devMsgIn(void *data, size_t len) +{ + TU_VERIFY(len == sizeof(usbtmc_msg_request_dev_dep_in)); + usbtmc_msg_request_dev_dep_in *msg = (usbtmc_msg_request_dev_dep_in*)data; + bool stateChanged = atomicChangeState(STATE_IDLE, STATE_TX_REQUESTED); + TU_VERIFY(stateChanged); + usbtmc_state.lastBulkInTag = msg->header.bTag; + usbtmc_state.transfer_size_remaining = msg->TransferSize; + usbtmc_state.transfer_size_sent = 0u; + + termCharRequested = msg->bmTransferAttributes.TermCharEnabled; + termChar = msg->TermChar; + + if(termCharRequested) + TU_VERIFY(usbtmc_state.capabilities->bmDevCapabilities.canEndBulkInOnTermChar); + + TU_VERIFY(tud_usbtmc_msgBulkIn_request_cb(msg)); + return true; +} + +bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + TU_VERIFY(result == XFER_RESULT_SUCCESS); + //uart_tx_str_sync("TMC XFER CB\r\n"); + if(usbtmc_state.state == STATE_CLEARING) { + return true; /* I think we can ignore everything here */ + } + + if(ep_addr == usbtmc_state.ep_bulk_out) + { + usbtmc_msg_generic_t *msg = NULL; + + switch(usbtmc_state.state) + { + case STATE_IDLE: + TU_VERIFY(xferred_bytes >= sizeof(usbtmc_msg_generic_t)); + msg = (usbtmc_msg_generic_t*)(usbtmc_state.ep_bulk_out_buf); + uint8_t invInvTag = (uint8_t)~(msg->header.bTagInverse); + TU_VERIFY(msg->header.bTag == invInvTag); + TU_VERIFY(msg->header.bTag != 0x00); + + switch(msg->header.MsgID) { + case USBTMC_MSGID_DEV_DEP_MSG_OUT: + if(!handle_devMsgOutStart(rhport, msg, xferred_bytes)) + { + usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); + TU_VERIFY(false); + } + break; + + case USBTMC_MSGID_DEV_DEP_MSG_IN: + TU_VERIFY(handle_devMsgIn(msg, xferred_bytes)); + break; + +#if (CFG_TUD_USBTMC_ENABLE_488) + case USBTMC_MSGID_USB488_TRIGGER: + // Spec says we halt the EP if we didn't declare we support it. + TU_VERIFY(usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger); + TU_VERIFY(tud_usbtmc_msg_trigger_cb(msg)); + + break; +#endif + case USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT: + case USBTMC_MSGID_VENDOR_SPECIFIC_IN: + default: + usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); + TU_VERIFY(false); + return false; + } + return true; + + case STATE_RCV: + if(!handle_devMsgOut(rhport, usbtmc_state.ep_bulk_out_buf, xferred_bytes, xferred_bytes)) + { + usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); + TU_VERIFY(false); + } + return true; + + case STATE_ABORTING_BULK_OUT: + TU_VERIFY(false); + return false; // Should be stalled by now, shouldn't have received a packet. + + case STATE_TX_REQUESTED: + case STATE_TX_INITIATED: + case STATE_ABORTING_BULK_IN: + case STATE_ABORTING_BULK_IN_SHORTED: + case STATE_ABORTING_BULK_IN_ABORTED: + default: + TU_VERIFY(false); + } + } + else if(ep_addr == usbtmc_state.ep_bulk_in) + { + switch(usbtmc_state.state) { + case STATE_TX_SHORTED: + TU_VERIFY(atomicChangeState(STATE_TX_SHORTED, STATE_NAK)); + TU_VERIFY(tud_usbtmc_msgBulkIn_complete_cb()); + break; + + case STATE_TX_INITIATED: + if(usbtmc_state.transfer_size_remaining >= sizeof(usbtmc_state.ep_bulk_in_buf)) + { + // FIXME! This removes const below! + TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, + (void*)(uintptr_t) usbtmc_state.devInBuffer, sizeof(usbtmc_state.ep_bulk_in_buf))); + usbtmc_state.devInBuffer += sizeof(usbtmc_state.ep_bulk_in_buf); + usbtmc_state.transfer_size_remaining -= sizeof(usbtmc_state.ep_bulk_in_buf); + usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.ep_bulk_in_buf); + } + else // last packet + { + size_t packetLen = usbtmc_state.transfer_size_remaining; + memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, usbtmc_state.transfer_size_remaining); + usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.transfer_size_remaining); + usbtmc_state.transfer_size_remaining = 0; + usbtmc_state.devInBuffer = NULL; + TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf, (uint16_t)packetLen) ); + if(((packetLen % usbtmc_state.ep_bulk_in_wMaxPacketSize) != 0) || (packetLen == 0 )) + { + usbtmc_state.state = STATE_TX_SHORTED; + } + } + return true; + + case STATE_ABORTING_BULK_IN: + // need to send short packet (ZLP?) + TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,(uint16_t)0u)); + usbtmc_state.state = STATE_ABORTING_BULK_IN_SHORTED; + return true; + + case STATE_ABORTING_BULK_IN_SHORTED: + /* Done. :)*/ + usbtmc_state.state = STATE_ABORTING_BULK_IN_ABORTED; + return true; + + default: + TU_ASSERT(false); + return false; + } + } + else if (ep_addr == usbtmc_state.ep_int_in) { + // Good? + return true; + } + return false; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + // nothing to do with DATA and ACK stage + if ( stage != CONTROL_STAGE_SETUP ) return true; + + uint8_t tmcStatusCode = USBTMC_STATUS_FAILED; +#if (CFG_TUD_USBTMC_ENABLE_488) + uint8_t bTag; +#endif + + if((request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) && + (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_ENDPOINT) && + (request->bRequest == TUSB_REQ_CLEAR_FEATURE) && + (request->wValue == TUSB_REQ_FEATURE_EDPT_HALT)) + { + uint32_t ep_addr = (request->wIndex); + + // At this point, a transfer MAY be in progress. Based on USB spec, when clearing bulk EP HALT, + // the EP transfer buffer needs to be cleared and DTOG needs to be reset, even if + // the EP is not halted. The only USBD API interface to do this is to stall and then unstall the EP. + if(ep_addr == usbtmc_state.ep_bulk_out) + { + criticalEnter(); + usbd_edpt_stall(rhport, (uint8_t)ep_addr); + usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr); + usbtmc_state.state = STATE_NAK; // USBD core has placed EP in NAK state for us + criticalLeave(); + tud_usbtmc_bulkOut_clearFeature_cb(); + } + else if (ep_addr == usbtmc_state.ep_bulk_in) + { + usbd_edpt_stall(rhport, (uint8_t)ep_addr); + usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr); + tud_usbtmc_bulkIn_clearFeature_cb(); + } + else if ((usbtmc_state.ep_int_in != 0) && (ep_addr == usbtmc_state.ep_int_in)) + { + // Clearing interrupt in EP + usbd_edpt_stall(rhport, (uint8_t)ep_addr); + usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr); + } + else + { + return false; + } + return true; + } + + // Otherwise, we only handle class requests. + if(request->bmRequestType_bit.type != TUSB_REQ_TYPE_CLASS) + { + return false; + } + + // Verification that we own the interface is unneeded since it's been routed to us specifically. + + switch(request->bRequest) + { + // USBTMC required requests + case USBTMC_bREQUEST_INITIATE_ABORT_BULK_OUT: + { + usbtmc_initiate_abort_rsp_t rsp = { + .bTag = usbtmc_state.lastBulkOutTag, + }; + TU_VERIFY(request->bmRequestType == 0xA2); // in,class,interface + TU_VERIFY(request->wLength == sizeof(rsp)); + TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_out); + + // wValue is the requested bTag to abort + if(usbtmc_state.state != STATE_RCV) + { + rsp.USBTMC_status = USBTMC_STATUS_FAILED; + } + else if(usbtmc_state.lastBulkOutTag == (request->wValue & 0x7Fu)) + { + rsp.USBTMC_status = USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS; + } + else + { + rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; + // Check if we've queued a short packet + criticalEnter(); + usbtmc_state.state = STATE_ABORTING_BULK_OUT; + criticalLeave(); + TU_VERIFY(tud_usbtmc_initiate_abort_bulk_out_cb(&(rsp.USBTMC_status))); + usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); + } + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); + return true; + } + + case USBTMC_bREQUEST_CHECK_ABORT_BULK_OUT_STATUS: + { + usbtmc_check_abort_bulk_rsp_t rsp = { + .USBTMC_status = USBTMC_STATUS_SUCCESS, + .NBYTES_RXD_TXD = usbtmc_state.transfer_size_sent + }; + TU_VERIFY(request->bmRequestType == 0xA2); // in,class,EP + TU_VERIFY(request->wLength == sizeof(rsp)); + TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_out); + TU_VERIFY(tud_usbtmc_check_abort_bulk_out_cb(&rsp)); + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); + return true; + } + + case USBTMC_bREQUEST_INITIATE_ABORT_BULK_IN: + { + usbtmc_initiate_abort_rsp_t rsp = { + .bTag = usbtmc_state.lastBulkInTag, + }; + TU_VERIFY(request->bmRequestType == 0xA2); // in,class,interface + TU_VERIFY(request->wLength == sizeof(rsp)); + TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_in); + // wValue is the requested bTag to abort + if((usbtmc_state.state == STATE_TX_REQUESTED || usbtmc_state.state == STATE_TX_INITIATED) && + usbtmc_state.lastBulkInTag == (request->wValue & 0x7Fu)) + { + rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; + usbtmc_state.transfer_size_remaining = 0u; + // Check if we've queued a short packet + criticalEnter(); + usbtmc_state.state = ((usbtmc_state.transfer_size_sent % usbtmc_state.ep_bulk_in_wMaxPacketSize) == 0) ? + STATE_ABORTING_BULK_IN : STATE_ABORTING_BULK_IN_SHORTED; + criticalLeave(); + if(usbtmc_state.transfer_size_sent == 0) + { + // Send short packet, nothing is in the buffer yet + TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,(uint16_t)0u)); + usbtmc_state.state = STATE_ABORTING_BULK_IN_SHORTED; + } + TU_VERIFY(tud_usbtmc_initiate_abort_bulk_in_cb(&(rsp.USBTMC_status))); + } + else if((usbtmc_state.state == STATE_TX_REQUESTED || usbtmc_state.state == STATE_TX_INITIATED)) + { // FIXME: Unsure how to check if the OUT endpoint fifo is non-empty.... + rsp.USBTMC_status = USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS; + } + else + { + rsp.USBTMC_status = USBTMC_STATUS_FAILED; + } + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); + return true; + } + + case USBTMC_bREQUEST_CHECK_ABORT_BULK_IN_STATUS: + { + TU_VERIFY(request->bmRequestType == 0xA2); // in,class,EP + TU_VERIFY(request->wLength == 8u); + + usbtmc_check_abort_bulk_rsp_t rsp = + { + .USBTMC_status = USBTMC_STATUS_FAILED, + .bmAbortBulkIn = + { + .BulkInFifoBytes = (usbtmc_state.state != STATE_ABORTING_BULK_IN_ABORTED) + }, + .NBYTES_RXD_TXD = usbtmc_state.transfer_size_sent, + }; + TU_VERIFY(tud_usbtmc_check_abort_bulk_in_cb(&rsp)); + criticalEnter(); + switch(usbtmc_state.state) + { + case STATE_ABORTING_BULK_IN_ABORTED: + rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; + usbtmc_state.state = STATE_IDLE; + break; + case STATE_ABORTING_BULK_IN: + case STATE_ABORTING_BULK_OUT: + rsp.USBTMC_status = USBTMC_STATUS_PENDING; + break; + default: + break; + } + criticalLeave(); + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); + + return true; + } + + case USBTMC_bREQUEST_INITIATE_CLEAR: + { + TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface + TU_VERIFY(request->wLength == sizeof(tmcStatusCode)); + // After receiving an INITIATE_CLEAR request, the device must Halt the Bulk-OUT endpoint, queue the + // control endpoint response shown in Table 31, and clear all input buffers and output buffers. + usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); + usbtmc_state.transfer_size_remaining = 0; + criticalEnter(); + usbtmc_state.state = STATE_CLEARING; + criticalLeave(); + TU_VERIFY(tud_usbtmc_initiate_clear_cb(&tmcStatusCode)); + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&tmcStatusCode,sizeof(tmcStatusCode))); + return true; + } + + case USBTMC_bREQUEST_CHECK_CLEAR_STATUS: + { + TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface + usbtmc_get_clear_status_rsp_t clearStatusRsp = {0}; + TU_VERIFY(request->wLength == sizeof(clearStatusRsp)); + + if(usbd_edpt_busy(rhport, usbtmc_state.ep_bulk_in)) + { + // Stuff stuck in TX buffer? + clearStatusRsp.bmClear.BulkInFifoBytes = 1; + clearStatusRsp.USBTMC_status = USBTMC_STATUS_PENDING; + } + else + { + // Let app check if it's clear + TU_VERIFY(tud_usbtmc_check_clear_cb(&clearStatusRsp)); + } + if(clearStatusRsp.USBTMC_status == USBTMC_STATUS_SUCCESS) + { + criticalEnter(); + usbtmc_state.state = STATE_IDLE; + criticalLeave(); + } + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&clearStatusRsp,sizeof(clearStatusRsp))); + return true; + } + + case USBTMC_bREQUEST_GET_CAPABILITIES: + { + TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface + TU_VERIFY(request->wLength == sizeof(*(usbtmc_state.capabilities))); + TU_VERIFY(tud_control_xfer(rhport, request, (void*)(uintptr_t) usbtmc_state.capabilities, sizeof(*usbtmc_state.capabilities))); + return true; + } + // USBTMC Optional Requests + + case USBTMC_bREQUEST_INDICATOR_PULSE: // Optional + { + TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface + TU_VERIFY(request->wLength == sizeof(tmcStatusCode)); + TU_VERIFY(usbtmc_state.capabilities->bmIntfcCapabilities.supportsIndicatorPulse); + TU_VERIFY(tud_usbtmc_indicator_pulse_cb(request, &tmcStatusCode)); + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&tmcStatusCode, sizeof(tmcStatusCode))); + return true; + } +#if (CFG_TUD_USBTMC_ENABLE_488) + + // USB488 required requests + case USB488_bREQUEST_READ_STATUS_BYTE: + { + usbtmc_read_stb_rsp_488_t rsp; + TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface + TU_VERIFY(request->wLength == sizeof(rsp)); // in,class,interface + + bTag = request->wValue & 0x7F; + TU_VERIFY(request->bmRequestType == 0xA1); + TU_VERIFY((request->wValue & (~0x7F)) == 0u); // Other bits are required to be zero (USB488v1.0 Table 11) + TU_VERIFY(bTag >= 0x02 && bTag <= 127); + TU_VERIFY(request->wIndex == usbtmc_state.itf_id); + TU_VERIFY(request->wLength == 0x0003); + rsp.bTag = (uint8_t)bTag; + if(usbtmc_state.ep_int_in != 0) + { + rsp.statusByte = 0x00; // Use interrupt endpoint, instead. Must be 0x00 (USB488v1.0 4.3.1.2) + if(usbd_edpt_busy(rhport, usbtmc_state.ep_int_in)) + { + rsp.USBTMC_status = USB488_STATUS_INTERRUPT_IN_BUSY; + } + else + { + rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; + usbtmc_read_stb_interrupt_488_t intMsg = + { + .bNotify1 = { + .one = 1, + .bTag = bTag & 0x7Fu, + }, + .StatusByte = tud_usbtmc_get_stb_cb(&(rsp.USBTMC_status)) + }; + // Must be queued before control request response sent (USB488v1.0 4.3.1.2) + usbd_edpt_xfer(rhport, usbtmc_state.ep_int_in, (void*)&intMsg, sizeof(intMsg)); + } + } + else + { + rsp.statusByte = tud_usbtmc_get_stb_cb(&(rsp.USBTMC_status)); + } + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp, sizeof(rsp))); + return true; + } + // USB488 optional requests + case USB488_bREQUEST_REN_CONTROL: + case USB488_bREQUEST_GO_TO_LOCAL: + case USB488_bREQUEST_LOCAL_LOCKOUT: + { + TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface + TU_VERIFY(false); + return false; + } +#endif + + default: + TU_VERIFY(false); + return false; + } + TU_VERIFY(false); +} + +#endif /* CFG_TUD_TSMC */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h new file mode 100644 index 00000000..144b3315 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h @@ -0,0 +1,112 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 N Conrad + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + + +#ifndef CLASS_USBTMC_USBTMC_DEVICE_H_ +#define CLASS_USBTMC_USBTMC_DEVICE_H_ + +#include "usbtmc.h" + +// Enable 488 mode by default +#if !defined(CFG_TUD_USBTMC_ENABLE_488) +#define CFG_TUD_USBTMC_ENABLE_488 (1) +#endif + +/*********************************************** + * Functions to be implemeted by the class implementation + */ + +// In order to proceed, app must call call tud_usbtmc_start_bus_read(rhport) during or soon after: +// * tud_usbtmc_open_cb +// * tud_usbtmc_msg_data_cb +// * tud_usbtmc_msgBulkIn_complete_cb +// * tud_usbtmc_msg_trigger_cb +// * (successful) tud_usbtmc_check_abort_bulk_out_cb +// * (successful) tud_usbtmc_check_abort_bulk_in_cb +// * (successful) tud_usmtmc_bulkOut_clearFeature_cb + +#if (CFG_TUD_USBTMC_ENABLE_488) +usbtmc_response_capabilities_488_t const * tud_usbtmc_get_capabilities_cb(void); +#else +usbtmc_response_capabilities_t const * tud_usbtmc_get_capabilities_cb(void); +#endif + +void tud_usbtmc_open_cb(uint8_t interface_id); + +bool tud_usbtmc_msgBulkOut_start_cb(usbtmc_msg_request_dev_dep_out const * msgHeader); +// transfer_complete does not imply that a message is complete. +bool tud_usbtmc_msg_data_cb( void *data, size_t len, bool transfer_complete); +void tud_usbtmc_bulkOut_clearFeature_cb(void); // Notice to clear and abort the pending BULK out transfer + +bool tud_usbtmc_msgBulkIn_request_cb(usbtmc_msg_request_dev_dep_in const * request); +bool tud_usbtmc_msgBulkIn_complete_cb(void); +void tud_usbtmc_bulkIn_clearFeature_cb(void); // Notice to clear and abort the pending BULK out transfer + +bool tud_usbtmc_initiate_abort_bulk_in_cb(uint8_t *tmcResult); +bool tud_usbtmc_initiate_abort_bulk_out_cb(uint8_t *tmcResult); +bool tud_usbtmc_initiate_clear_cb(uint8_t *tmcResult); + +bool tud_usbtmc_check_abort_bulk_in_cb(usbtmc_check_abort_bulk_rsp_t *rsp); +bool tud_usbtmc_check_abort_bulk_out_cb(usbtmc_check_abort_bulk_rsp_t *rsp); +bool tud_usbtmc_check_clear_cb(usbtmc_get_clear_status_rsp_t *rsp); + +// Indicator pulse should be 0.5 to 1.0 seconds long +TU_ATTR_WEAK bool tud_usbtmc_indicator_pulse_cb(tusb_control_request_t const * msg, uint8_t *tmcResult); + +#if (CFG_TUD_USBTMC_ENABLE_488) +uint8_t tud_usbtmc_get_stb_cb(uint8_t *tmcResult); +TU_ATTR_WEAK bool tud_usbtmc_msg_trigger_cb(usbtmc_msg_generic_t* msg); +//TU_ATTR_WEAK bool tud_usbtmc_app_go_to_local_cb(); +#endif + +/******************************************* + * Called from app + * + * We keep a reference to the buffer, so it MUST not change until the app is + * notified that the transfer is complete. + ******************************************/ + +bool tud_usbtmc_transmit_dev_msg_data( + const void * data, size_t len, + bool endOfMessage, bool usingTermChar); + +bool tud_usbtmc_start_bus_read(void); + + +/* "callbacks" from USB device core */ + +uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +void usbtmcd_reset_cb(uint8_t rhport); +bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); +bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +void usbtmcd_init_cb(void); + +/************************************************************ + * USBTMC Descriptor Templates + *************************************************************/ + + +#endif /* CLASS_USBTMC_USBTMC_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.c new file mode 100644 index 00000000..3b81a108 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.c @@ -0,0 +1,272 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_VENDOR) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "vendor_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +typedef struct +{ + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; + + /*------------- From this point, data is not cleared by bus reset -------------*/ + tu_fifo_t rx_ff; + tu_fifo_t tx_ff; + + uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE]; + uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE]; + +#if CFG_FIFO_MUTEX + osal_mutex_def_t rx_ff_mutex; + osal_mutex_def_t tx_ff_mutex; +#endif + + // Endpoint Transfer buffer + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_VENDOR_EPSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_VENDOR_EPSIZE]; +} vendord_interface_t; + +CFG_TUSB_MEM_SECTION static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR]; + +#define ITF_MEM_RESET_SIZE offsetof(vendord_interface_t, rx_ff) + + +bool tud_vendor_n_mounted (uint8_t itf) +{ + return _vendord_itf[itf].ep_in && _vendord_itf[itf].ep_out; +} + +uint32_t tud_vendor_n_available (uint8_t itf) +{ + return tu_fifo_count(&_vendord_itf[itf].rx_ff); +} + +bool tud_vendor_n_peek(uint8_t itf, uint8_t* u8) +{ + return tu_fifo_peek(&_vendord_itf[itf].rx_ff, u8); +} + +//--------------------------------------------------------------------+ +// Read API +//--------------------------------------------------------------------+ +static void _prep_out_transaction (vendord_interface_t* p_itf) +{ + uint8_t const rhport = 0; + + // skip if previous transfer not complete + if ( usbd_edpt_busy(rhport, p_itf->ep_out) ) return; + + // Prepare for incoming data but only allow what we can store in the ring buffer. + uint16_t max_read = tu_fifo_remaining(&p_itf->rx_ff); + if ( max_read >= CFG_TUD_VENDOR_EPSIZE ) + { + usbd_edpt_xfer(rhport, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE); + } +} + +uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize) +{ + vendord_interface_t* p_itf = &_vendord_itf[itf]; + uint32_t num_read = tu_fifo_read_n(&p_itf->rx_ff, buffer, (uint16_t) bufsize); + _prep_out_transaction(p_itf); + return num_read; +} + +void tud_vendor_n_read_flush (uint8_t itf) +{ + vendord_interface_t* p_itf = &_vendord_itf[itf]; + tu_fifo_clear(&p_itf->rx_ff); + _prep_out_transaction(p_itf); +} + +//--------------------------------------------------------------------+ +// Write API +//--------------------------------------------------------------------+ +static uint16_t maybe_transmit(vendord_interface_t* p_itf) +{ + uint8_t const rhport = 0; + + // skip if previous transfer not complete + TU_VERIFY( !usbd_edpt_busy(rhport, p_itf->ep_in) ); + + uint16_t count = tu_fifo_read_n(&p_itf->tx_ff, p_itf->epin_buf, CFG_TUD_VENDOR_EPSIZE); + if (count > 0) + { + TU_ASSERT( usbd_edpt_xfer(rhport, p_itf->ep_in, p_itf->epin_buf, count) ); + } + return count; +} + +uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize) +{ + vendord_interface_t* p_itf = &_vendord_itf[itf]; + uint16_t ret = tu_fifo_write_n(&p_itf->tx_ff, buffer, (uint16_t) bufsize); + if (tu_fifo_count(&p_itf->tx_ff) >= CFG_TUD_VENDOR_EPSIZE) { + maybe_transmit(p_itf); + } + return ret; +} + +uint32_t tud_vendor_n_flush (uint8_t itf) +{ + vendord_interface_t* p_itf = &_vendord_itf[itf]; + uint32_t ret = maybe_transmit(p_itf); + + return ret; +} + +uint32_t tud_vendor_n_write_available (uint8_t itf) +{ + return tu_fifo_remaining(&_vendord_itf[itf].tx_ff); +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void vendord_init(void) +{ + tu_memclr(_vendord_itf, sizeof(_vendord_itf)); + + for(uint8_t i=0; irx_ff, p_itf->rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, 1, false); + tu_fifo_config(&p_itf->tx_ff, p_itf->tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, 1, false); + +#if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&p_itf->rx_ff, NULL, osal_mutex_create(&p_itf->rx_ff_mutex)); + tu_fifo_config_mutex(&p_itf->tx_ff, osal_mutex_create(&p_itf->tx_ff_mutex), NULL); +#endif + } +} + +void vendord_reset(uint8_t rhport) +{ + (void) rhport; + + for(uint8_t i=0; irx_ff); + tu_fifo_clear(&p_itf->tx_ff); + } +} + +uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) +{ + TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0); + + uint8_t const * p_desc = tu_desc_next(desc_itf); + uint8_t const * desc_end = p_desc + max_len; + + // Find available interface + vendord_interface_t* p_vendor = NULL; + for(uint8_t i=0; iitf_num = desc_itf->bInterfaceNumber; + if (desc_itf->bNumEndpoints) + { + // skip non-endpoint descriptors + while ( (TUSB_DESC_ENDPOINT != tu_desc_type(p_desc)) && (p_desc < desc_end) ) + { + p_desc = tu_desc_next(p_desc); + } + + // Open endpoint pair with usbd helper + TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_BULK, &p_vendor->ep_out, &p_vendor->ep_in), 0); + + p_desc += desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t); + + // Prepare for incoming data + if ( p_vendor->ep_out ) + { + TU_ASSERT(usbd_edpt_xfer(rhport, p_vendor->ep_out, p_vendor->epout_buf, sizeof(p_vendor->epout_buf)), 0); + } + + if ( p_vendor->ep_in ) maybe_transmit(p_vendor); + } + + return (uint16_t) ((uintptr_t) p_desc - (uintptr_t) desc_itf); +} + +bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) rhport; + (void) result; + + uint8_t itf = 0; + vendord_interface_t* p_itf = _vendord_itf; + + for ( ; ; itf++, p_itf++) + { + if (itf >= TU_ARRAY_SIZE(_vendord_itf)) return false; + + if ( ( ep_addr == p_itf->ep_out ) || ( ep_addr == p_itf->ep_in ) ) break; + } + + if ( ep_addr == p_itf->ep_out ) + { + // Receive new data + tu_fifo_write_n(&p_itf->rx_ff, p_itf->epout_buf, (uint16_t) xferred_bytes); + + // Invoked callback if any + if (tud_vendor_rx_cb) tud_vendor_rx_cb(itf); + + _prep_out_transaction(p_itf); + } + else if ( ep_addr == p_itf->ep_in ) + { + if (tud_vendor_tx_cb) tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes); + // Send complete, try to send more if possible + maybe_transmit(p_itf); + } + + return true; +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.h new file mode 100644 index 00000000..4a873e5f --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.h @@ -0,0 +1,145 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_VENDOR_DEVICE_H_ +#define _TUSB_VENDOR_DEVICE_H_ + +#include "common/tusb_common.h" + +#ifndef CFG_TUD_VENDOR_EPSIZE +#define CFG_TUD_VENDOR_EPSIZE 64 +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Application API (Multiple Interfaces) +//--------------------------------------------------------------------+ +bool tud_vendor_n_mounted (uint8_t itf); + +uint32_t tud_vendor_n_available (uint8_t itf); +uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize); +bool tud_vendor_n_peek (uint8_t itf, uint8_t* ui8); +void tud_vendor_n_read_flush (uint8_t itf); + +uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize); +uint32_t tud_vendor_n_write_available (uint8_t itf); + +static inline +uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str); +uint32_t tud_vendor_n_flush (uint8_t itf); + +//--------------------------------------------------------------------+ +// Application API (Single Port) +//--------------------------------------------------------------------+ +static inline bool tud_vendor_mounted (void); +static inline uint32_t tud_vendor_available (void); +static inline uint32_t tud_vendor_read (void* buffer, uint32_t bufsize); +static inline bool tud_vendor_peek (uint8_t* ui8); +static inline void tud_vendor_read_flush (void); +static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize); +static inline uint32_t tud_vendor_write_str (char const* str); +static inline uint32_t tud_vendor_write_available (void); +static inline uint32_t tud_vendor_flush (void); + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ + +// Invoked when received new data +TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf); +// Invoked when last rx transfer finished +TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes); + +//--------------------------------------------------------------------+ +// Inline Functions +//--------------------------------------------------------------------+ + +static inline uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str) +{ + return tud_vendor_n_write(itf, str, strlen(str)); +} + +static inline bool tud_vendor_mounted (void) +{ + return tud_vendor_n_mounted(0); +} + +static inline uint32_t tud_vendor_available (void) +{ + return tud_vendor_n_available(0); +} + +static inline uint32_t tud_vendor_read (void* buffer, uint32_t bufsize) +{ + return tud_vendor_n_read(0, buffer, bufsize); +} + +static inline bool tud_vendor_peek (uint8_t* ui8) +{ + return tud_vendor_n_peek(0, ui8); +} + +static inline void tud_vendor_read_flush(void) +{ + tud_vendor_n_read_flush(0); +} + +static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize) +{ + return tud_vendor_n_write(0, buffer, bufsize); +} + +static inline uint32_t tud_vendor_write_str (char const* str) +{ + return tud_vendor_n_write_str(0, str); +} + +static inline uint32_t tud_vendor_write_available (void) +{ + return tud_vendor_n_write_available(0); +} + +static inline uint32_t tud_vendor_flush (void) +{ + return tud_vendor_n_flush(0); +} + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void vendord_init(void); +void vendord_reset(uint8_t rhport); +uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_VENDOR_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.c b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.c new file mode 100644 index 00000000..dbea1228 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.c @@ -0,0 +1,146 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUH_ENABLED && CFG_TUH_VENDOR) + +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "host/usbh.h" +#include "vendor_host.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +custom_interface_info_t custom_interface[CFG_TUH_DEVICE_MAX]; + +static tusb_error_t cush_validate_paras(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length) +{ + if ( !tusbh_custom_is_mounted(dev_addr, vendor_id, product_id) ) + { + return TUSB_ERROR_DEVICE_NOT_READY; + } + + TU_ASSERT( p_buffer != NULL && length != 0, TUSB_ERROR_INVALID_PARA); + + return TUSB_ERROR_NONE; +} +//--------------------------------------------------------------------+ +// APPLICATION API (need to check parameters) +//--------------------------------------------------------------------+ +tusb_error_t tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length) +{ + TU_ASSERT_ERR( cush_validate_paras(dev_addr, vendor_id, product_id, p_buffer, length) ); + + if ( !hcd_pipe_is_idle(custom_interface[dev_addr-1].pipe_in) ) + { + return TUSB_ERROR_INTERFACE_IS_BUSY; + } + + (void) usbh_edpt_xfer( custom_interface[dev_addr-1].pipe_in, p_buffer, length); + + return TUSB_ERROR_NONE; +} + +tusb_error_t tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length) +{ + TU_ASSERT_ERR( cush_validate_paras(dev_addr, vendor_id, product_id, p_data, length) ); + + if ( !hcd_pipe_is_idle(custom_interface[dev_addr-1].pipe_out) ) + { + return TUSB_ERROR_INTERFACE_IS_BUSY; + } + + (void) usbh_edpt_xfer( custom_interface[dev_addr-1].pipe_out, p_data, length); + + return TUSB_ERROR_NONE; +} + +//--------------------------------------------------------------------+ +// USBH-CLASS API +//--------------------------------------------------------------------+ +void cush_init(void) +{ + tu_memclr(&custom_interface, sizeof(custom_interface_info_t) * CFG_TUH_DEVICE_MAX); +} + +tusb_error_t cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length) +{ + // FIXME quick hack to test lpc1k custom class with 2 bulk endpoints + uint8_t const *p_desc = (uint8_t const *) p_interface_desc; + p_desc = tu_desc_next(p_desc); + + //------------- Bulk Endpoints Descriptor -------------// + for(uint32_t i=0; i<2; i++) + { + tusb_desc_endpoint_t const *p_endpoint = (tusb_desc_endpoint_t const *) p_desc; + TU_ASSERT(TUSB_DESC_ENDPOINT == p_endpoint->bDescriptorType, TUSB_ERROR_INVALID_PARA); + + pipe_handle_t * p_pipe_hdl = ( p_endpoint->bEndpointAddress & TUSB_DIR_IN_MASK ) ? + &custom_interface[dev_addr-1].pipe_in : &custom_interface[dev_addr-1].pipe_out; + *p_pipe_hdl = usbh_edpt_open(dev_addr, p_endpoint, TUSB_CLASS_VENDOR_SPECIFIC); + TU_ASSERT ( pipehandle_is_valid(*p_pipe_hdl), TUSB_ERROR_HCD_OPEN_PIPE_FAILED ); + + p_desc = tu_desc_next(p_desc); + } + + (*p_length) = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t); + return TUSB_ERROR_NONE; +} + +void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event) +{ + +} + +void cush_close(uint8_t dev_addr) +{ + tusb_error_t err1, err2; + custom_interface_info_t * p_interface = &custom_interface[dev_addr-1]; + + // TODO re-consider to check pipe valid before calling pipe_close + if( pipehandle_is_valid( p_interface->pipe_in ) ) + { + err1 = hcd_pipe_close( p_interface->pipe_in ); + } + + if ( pipehandle_is_valid( p_interface->pipe_out ) ) + { + err2 = hcd_pipe_close( p_interface->pipe_out ); + } + + tu_memclr(p_interface, sizeof(custom_interface_info_t)); + + TU_ASSERT(err1 == TUSB_ERROR_NONE && err2 == TUSB_ERROR_NONE, (void) 0 ); +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.h b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.h new file mode 100644 index 00000000..65223fbc --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.h @@ -0,0 +1,67 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_VENDOR_HOST_H_ +#define _TUSB_VENDOR_HOST_H_ + +#include "common/tusb_common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +typedef struct { + pipe_handle_t pipe_in; + pipe_handle_t pipe_out; +}custom_interface_info_t; + +//--------------------------------------------------------------------+ +// USBH-CLASS DRIVER API +//--------------------------------------------------------------------+ +static inline bool tusbh_custom_is_mounted(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id) +{ + (void) vendor_id; // TODO check this later + (void) product_id; +// return (tusbh_device_get_mounted_class_flag(dev_addr) & TU_BIT(TUSB_CLASS_MAPPED_INDEX_END-1) ) != 0; + return false; +} + +bool tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length); +bool tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void cush_init(void); +bool cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length); +void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event); +void cush_close(uint8_t dev_addr); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_VENDOR_HOST_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/video/video.h b/test-devices/loopback-stm32/lib/tinyusb/class/video/video.h new file mode 100644 index 00000000..84474654 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/video/video.h @@ -0,0 +1,480 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Koji KITAYAMA + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef TUSB_VIDEO_H_ +#define TUSB_VIDEO_H_ + +#include "common/tusb_common.h" + +// Table 3-19 Color Matching Descriptor +typedef enum { + VIDEO_COLOR_PRIMARIES_UNDEFINED = 0x00, + VIDEO_COLOR_PRIMARIES_BT709, // sRGB (default) + VIDEO_COLOR_PRIMARIES_BT470_2M, + VIDEO_COLOR_PRIMARIES_BT470_2BG, + VIDEO_COLOR_PRIMARIES_SMPTE170M, + VIDEO_COLOR_PRIMARIES_SMPTE240M, +} video_color_primaries_t; + +// Table 3-19 Color Matching Descriptor +typedef enum { + VIDEO_COLOR_XFER_CH_UNDEFINED = 0x00, + VIDEO_COLOR_XFER_CH_BT709, // default + VIDEO_COLOR_XFER_CH_BT470_2M, + VIDEO_COLOR_XFER_CH_BT470_2BG, + VIDEO_COLOR_XFER_CH_SMPTE170M, + VIDEO_COLOR_XFER_CH_SMPTE240M, + VIDEO_COLOR_XFER_CH_LINEAR, + VIDEO_COLOR_XFER_CH_SRGB, +} video_color_transfer_characteristics_t; + +// Table 3-19 Color Matching Descriptor +typedef enum { + VIDEO_COLOR_COEF_UNDEFINED = 0x00, + VIDEO_COLOR_COEF_BT709, + VIDEO_COLOR_COEF_FCC, + VIDEO_COLOR_COEF_BT470_2BG, + VIDEO_COLOR_COEF_SMPTE170M, // BT.601 default + VIDEO_COLOR_COEF_SMPTE240M, +} video_color_matrix_coefficients_t; + +/* 4.2.1.2 Request Error Code Control */ +typedef enum { + VIDEO_ERROR_NONE = 0, /* The request succeeded. */ + VIDEO_ERROR_NOT_READY, + VIDEO_ERROR_WRONG_STATE, + VIDEO_ERROR_POWER, + VIDEO_ERROR_OUT_OF_RANGE, + VIDEO_ERROR_INVALID_UNIT, + VIDEO_ERROR_INVALID_CONTROL, + VIDEO_ERROR_INVALID_REQUEST, + VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE, + VIDEO_ERROR_UNKNOWN = 0xFF, +} video_error_code_t; + +/* A.2 Interface Subclass */ +typedef enum { + VIDEO_SUBCLASS_UNDEFINED = 0x00, + VIDEO_SUBCLASS_CONTROL, + VIDEO_SUBCLASS_STREAMING, + VIDEO_SUBCLASS_INTERFACE_COLLECTION, +} video_subclass_type_t; + +/* A.3 Interface Protocol */ +typedef enum { + VIDEO_ITF_PROTOCOL_UNDEFINED = 0x00, + VIDEO_ITF_PROTOCOL_15, +} video_interface_protocol_code_t; + +/* A.5 Class-Specific VideoControl Interface Descriptor Subtypes */ +typedef enum { + VIDEO_CS_ITF_VC_UNDEFINED = 0x00, + VIDEO_CS_ITF_VC_HEADER, + VIDEO_CS_ITF_VC_INPUT_TERMINAL, + VIDEO_CS_ITF_VC_OUTPUT_TERMINAL, + VIDEO_CS_ITF_VC_SELECTOR_UNIT, + VIDEO_CS_ITF_VC_PROCESSING_UNIT, + VIDEO_CS_ITF_VC_EXTENSION_UNIT, + VIDEO_CS_ITF_VC_ENCODING_UNIT, + VIDEO_CS_ITF_VC_MAX, +} video_cs_vc_interface_subtype_t; + +/* A.6 Class-Specific VideoStreaming Interface Descriptor Subtypes */ +typedef enum { + VIDEO_CS_ITF_VS_UNDEFINED = 0x00, + VIDEO_CS_ITF_VS_INPUT_HEADER = 0x01, + VIDEO_CS_ITF_VS_OUTPUT_HEADER = 0x02, + VIDEO_CS_ITF_VS_STILL_IMAGE_FRAME = 0x03, + VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED = 0x04, + VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED = 0x05, + VIDEO_CS_ITF_VS_FORMAT_MJPEG = 0x06, + VIDEO_CS_ITF_VS_FRAME_MJPEG = 0x07, + VIDEO_CS_ITF_VS_FORMAT_MPEG2TS = 0x0A, + VIDEO_CS_ITF_VS_FORMAT_DV = 0x0C, + VIDEO_CS_ITF_VS_COLORFORMAT = 0x0D, + VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED = 0x10, + VIDEO_CS_ITF_VS_FRAME_FRAME_BASED = 0x11, + VIDEO_CS_ITF_VS_FORMAT_STREAM_BASED = 0x12, + VIDEO_CS_ITF_VS_FORMAT_H264 = 0x13, + VIDEO_CS_ITF_VS_FRAME_H264 = 0x14, + VIDEO_CS_ITF_VS_FORMAT_H264_SIMULCAST = 0x15, + VIDEO_CS_ITF_VS_FORMAT_VP8 = 0x16, + VIDEO_CS_ITF_VS_FRAME_VP8 = 0x17, + VIDEO_CS_ITF_VS_FORMAT_VP8_SIMULCAST = 0x18, +} video_cs_vs_interface_subtype_t; + +/* A.7. Class-Specific Endpoint Descriptor Subtypes */ +typedef enum { + VIDEO_CS_EP_UNDEFINED = 0x00, + VIDEO_CS_EP_GENERAL, + VIDEO_CS_EP_ENDPOINT, + VIDEO_CS_EP_INTERRUPT +} video_cs_ep_subtype_t; + +/* A.8 Class-Specific Request Codes */ +typedef enum { + VIDEO_REQUEST_UNDEFINED = 0x00, + VIDEO_REQUEST_SET_CUR = 0x01, + VIDEO_REQUEST_SET_CUR_ALL = 0x11, + VIDEO_REQUEST_GET_CUR = 0x81, + VIDEO_REQUEST_GET_MIN = 0x82, + VIDEO_REQUEST_GET_MAX = 0x83, + VIDEO_REQUEST_GET_RES = 0x84, + VIDEO_REQUEST_GET_LEN = 0x85, + VIDEO_REQUEST_GET_INFO = 0x86, + VIDEO_REQUEST_GET_DEF = 0x87, + VIDEO_REQUEST_GET_CUR_ALL = 0x91, + VIDEO_REQUEST_GET_MIN_ALL = 0x92, + VIDEO_REQUEST_GET_MAX_ALL = 0x93, + VIDEO_REQUEST_GET_RES_ALL = 0x94, + VIDEO_REQUEST_GET_DEF_ALL = 0x97 +} video_control_request_t; + +/* A.9.1 VideoControl Interface Control Selectors */ +typedef enum { + VIDEO_VC_CTL_UNDEFINED = 0x00, + VIDEO_VC_CTL_VIDEO_POWER_MODE, + VIDEO_VC_CTL_REQUEST_ERROR_CODE, +} video_interface_control_selector_t; + +/* A.9.8 VideoStreaming Interface Control Selectors */ +typedef enum { + VIDEO_VS_CTL_UNDEFINED = 0x00, + VIDEO_VS_CTL_PROBE, + VIDEO_VS_CTL_COMMIT, + VIDEO_VS_CTL_STILL_PROBE, + VIDEO_VS_CTL_STILL_COMMIT, + VIDEO_VS_CTL_STILL_IMAGE_TRIGGER, + VIDEO_VS_CTL_STREAM_ERROR_CODE, + VIDEO_VS_CTL_GENERATE_KEY_FRAME, + VIDEO_VS_CTL_UPDATE_FRAME_SEGMENT, + VIDEO_VS_CTL_SYNCH_DELAY_CONTROL, +} video_interface_streaming_selector_t; + +/* B. Terminal Types */ +typedef enum { + // Terminal + VIDEO_TT_VENDOR_SPECIFIC = 0x0100, + VIDEO_TT_STREAMING = 0x0101, + + // Input + VIDEO_ITT_VENDOR_SPECIFIC = 0x0200, + VIDEO_ITT_CAMERA = 0x0201, + VIDEO_ITT_MEDIA_TRANSPORT_INPUT = 0x0202, + + // Output + VIDEO_OTT_VENDOR_SPECIFIC = 0x0300, + VIDEO_OTT_DISPLAY = 0x0301, + VIDEO_OTT_MEDIA_TRANSPORT_OUTPUT = 0x0302, + + // External + VIDEO_ETT_VENDOR_SPEIFIC = 0x0400, + VIDEO_ETT_COMPOSITE_CONNECTOR = 0x0401, + VIDEO_ETT_SVIDEO_CONNECTOR = 0x0402, + VIDEO_ETT_COMPONENT_CONNECTOR = 0x0403, +} video_terminal_type_t; + +//--------------------------------------------------------------------+ +// Descriptors +//--------------------------------------------------------------------+ + +/* 2.3.4.2 */ +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint16_t bcdUVC; + uint16_t wTotalLength; + uint32_t dwClockFrequency; + uint8_t bInCollection; + uint8_t baInterfaceNr[]; +} tusb_desc_cs_video_ctl_itf_hdr_t; + +/* 2.4.3.3 */ +typedef struct TU_ATTR_PACKED { + uint8_t bHeaderLength; + union { + uint8_t bmHeaderInfo; + struct { + uint8_t FrameID: 1; + uint8_t EndOfFrame: 1; + uint8_t PresentationTime: 1; + uint8_t SourceClockReference: 1; + uint8_t PayloadSpecific: 1; + uint8_t StillImage: 1; + uint8_t Error: 1; + uint8_t EndOfHeader: 1; + }; + }; +} tusb_video_payload_header_t; + +/* 3.9.2.1 */ +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bNumFormats; + uint16_t wTotalLength; + uint8_t bEndpointAddress; + uint8_t bmInfo; + uint8_t bTerminalLink; + uint8_t bStillCaptureMethod; + uint8_t bTriggerSupport; + uint8_t bTriggerUsage; + uint8_t bControlSize; + uint8_t bmaControls[]; +} tusb_desc_cs_video_stm_itf_in_hdr_t; + +/* 3.9.2.2 */ +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bNumFormats; + uint16_t wTotalLength; + uint8_t bEndpointAddress; + uint8_t bTerminalLink; + uint8_t bControlSize; + uint8_t bmaControls[]; +} tusb_desc_cs_video_stm_itf_out_hdr_t; + +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bNumFormats; + uint16_t wTotalLength; + uint8_t bEndpointAddress; + union { + struct { + uint8_t bmInfo; + uint8_t bTerminalLink; + uint8_t bStillCaptureMethod; + uint8_t bTriggerSupport; + uint8_t bTriggerUsage; + uint8_t bControlSize; + uint8_t bmaControls[]; + } input; + struct { + uint8_t bEndpointAddress; + uint8_t bTerminalLink; + uint8_t bControlSize; + uint8_t bmaControls[]; + } output; + }; +} tusb_desc_cs_video_stm_itf_hdr_t; + +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFormatIndex; + uint8_t bNumFrameDescriptors; + uint8_t guidFormat[16]; + uint8_t bBitsPerPixel; + uint8_t bDefaultFrameIndex; + uint8_t bAspectRatioX; + uint8_t bAspectRatioY; + uint8_t bmInterlaceFlags; + uint8_t bCopyProtect; +} tusb_desc_cs_video_fmt_uncompressed_t; + +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFrameIndex; + uint8_t bmCapabilities; + uint16_t wWidth; + uint16_t wHeight; + uint32_t dwMinBitRate; + uint32_t dwMaxBitRate; + uint32_t dwMaxVideoFrameBufferSize; /* deprecated */ + uint32_t dwDefaultFrameInterval; + uint8_t bFrameIntervalType; + uint32_t dwFrameInterval[]; +} tusb_desc_cs_video_frm_uncompressed_t; + +//--------------------------------------------------------------------+ +// Requests +//--------------------------------------------------------------------+ + +/* 4.3.1.1 */ +typedef struct TU_ATTR_PACKED { + union { + uint8_t bmHint; + struct TU_ATTR_PACKED { + uint16_t dwFrameInterval: 1; + uint16_t wKeyFrameRatel : 1; + uint16_t wPFrameRate : 1; + uint16_t wCompQuality : 1; + uint16_t wCompWindowSize: 1; + uint16_t : 0; + } Hint; + }; + uint8_t bFormatIndex; + uint8_t bFrameIndex; + uint32_t dwFrameInterval; + uint16_t wKeyFrameRate; + uint16_t wPFrameRate; + uint16_t wCompQuality; + uint16_t wCompWindowSize; + uint16_t wDelay; + uint32_t dwMaxVideoFrameSize; + uint32_t dwMaxPayloadTransferSize; + uint32_t dwClockFrequency; + union { + uint8_t bmFramingInfo; + struct TU_ATTR_PACKED { + uint8_t FrameID : 1; + uint8_t EndOfFrame: 1; + uint8_t EndOfSlice: 1; + uint8_t : 0; + } FramingInfo; + }; + uint8_t bPreferedVersion; + uint8_t bMinVersion; + uint8_t bMaxVersion; + uint8_t bUsage; + uint8_t bBitDepthLuma; + uint8_t bmSettings; + uint8_t bMaxNumberOfRefFramesPlus1; + uint16_t bmRateControlModes; + uint64_t bmLayoutPerStream; +} video_probe_and_commit_control_t; + +TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not correct"); + +#define TUD_VIDEO_DESC_IAD_LEN 8 +#define TUD_VIDEO_DESC_STD_VC_LEN 9 +#define TUD_VIDEO_DESC_CS_VC_LEN 12 +#define TUD_VIDEO_DESC_INPUT_TERM_LEN 8 +#define TUD_VIDEO_DESC_OUTPUT_TERM_LEN 9 +#define TUD_VIDEO_DESC_CAMERA_TERM_LEN 18 +#define TUD_VIDEO_DESC_STD_VS_LEN 9 +#define TUD_VIDEO_DESC_CS_VS_IN_LEN 13 +#define TUD_VIDEO_DESC_CS_VS_OUT_LEN 9 +#define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN 27 +#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN 38 +#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN 26 +#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN 6 + +/* 2.2 compression formats */ +#define TUD_VIDEO_GUID_YUY2 0x59,0x55,0x59,0x32,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 +#define TUD_VIDEO_GUID_NV12 0x4E,0x56,0x31,0x32,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 +#define TUD_VIDEO_GUID_M420 0x4D,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 +#define TUD_VIDEO_GUID_I420 0x49,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 + +#define TUD_VIDEO_DESC_IAD(_firstitfs, _nitfs, _stridx) \ + TUD_VIDEO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, \ + _firstitfs, _nitfs, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_INTERFACE_COLLECTION, \ + VIDEO_ITF_PROTOCOL_UNDEFINED, _stridx + +#define TUD_VIDEO_DESC_STD_VC(_itfnum, _nEPs, _stridx) \ + TUD_VIDEO_DESC_STD_VC_LEN, TUSB_DESC_INTERFACE, _itfnum, /* fixed to zero */ 0x00, \ + _nEPs, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_CONTROL, VIDEO_ITF_PROTOCOL_15, _stridx + +/* 3.7.2 */ +#define TUD_VIDEO_DESC_CS_VC(_bcdUVC, _totallen, _clkfreq, ...) \ + TUD_VIDEO_DESC_CS_VC_LEN + (TU_ARGS_NUM(__VA_ARGS__)), TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_HEADER, \ + U16_TO_U8S_LE(_bcdUVC), U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VC_LEN + (TU_ARGS_NUM(__VA_ARGS__))), \ + U32_TO_U8S_LE(_clkfreq), TU_ARGS_NUM(__VA_ARGS__), __VA_ARGS__ + +/* 3.7.2.1 */ +#define TUD_VIDEO_DESC_INPUT_TERM(_tid, _tt, _at, _stridx) \ + TUD_VIDEO_DESC_INPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_INPUT_TERMINAL, \ + _tid, U16_TO_U8S_LE(_tt), _at, _stridx + +/* 3.7.2.2 */ +#define TUD_VIDEO_DESC_OUTPUT_TERM(_tid, _tt, _at, _srcid, _stridx) \ + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_OUTPUT_TERMINAL, \ + _tid, U16_TO_U8S_LE(_tt), _at, _srcid, _stridx + +/* 3.7.2.3 */ +#define TUD_VIDEO_DESC_CAMERA_TERM(_tid, _at, _stridx, _focal_min, _focal_max, _focal, _ctls) \ + TUD_VIDEO_DESC_CAMERA_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_INPUT_TERMINAL, \ + _tid, U16_TO_U8S_LE(VIDEO_ITT_CAMERA), _at, _stridx, \ + U16_TO_U8S_LE(_focal_min), U16_TO_U8S_LE(_focal_max), U16_TO_U8S_LE(_focal), 3, \ + TU_U32_BYTE0(_ctls), TU_U32_BYTE1(_ctls), TU_U32_BYTE2(_ctls) + +/* 3.9.1 */ +#define TUD_VIDEO_DESC_STD_VS(_itfnum, _alt, _epn, _stridx) \ + TUD_VIDEO_DESC_STD_VS_LEN, TUSB_DESC_INTERFACE, _itfnum, _alt, \ + _epn, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_STREAMING, VIDEO_ITF_PROTOCOL_15, _stridx + +/* 3.9.2.1 */ +#define TUD_VIDEO_DESC_CS_VS_INPUT(_numfmt, _totallen, _ep, _inf, _termlnk, _sticaptmeth, _trgspt, _trgusg, ...) \ + TUD_VIDEO_DESC_CS_VS_IN_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__)), TUSB_DESC_CS_INTERFACE, \ + VIDEO_CS_ITF_VS_INPUT_HEADER, _numfmt, \ + U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VS_IN_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__))), \ + _ep, _inf, _termlnk, _sticaptmeth, _trgspt, _trgusg, (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ + +/* 3.9.2.2 */ +#define TUD_VIDEO_DESC_CS_VS_OUTPUT(_numfmt, _totallen, _ep, _inf, _termlnk, ...) \ + TUD_VIDEO_DESC_CS_VS_OUT_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__)), TUSB_DESC_CS_INTERFACE, \ + VIDEO_CS_ITF_VS_OUTPUT_HEADER, _numfmt, \ + U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VS_OUT_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__))), \ + _ep, _inf, _termlnk, (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ + +/* Uncompressed 3.1.1 */ +#define TUD_VIDEO_GUID(_g0,_g1,_g2,_g3,_g4,_g5,_g6,_g7,_g8,_g9,_g10,_g11,_g12,_g13,_g14,_g15) _g0,_g1,_g2,_g3,_g4,_g5,_g6,_g7,_g8,_g9,_g10,_g11,_g12,_g13,_g14,_g15 + +#define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR(_fmtidx, _numfrmdesc, \ + _guid, _bitsperpix, _frmidx, _asrx, _asry, _interlace, _cp) \ + TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED, \ + _fmtidx, _numfrmdesc, TUD_VIDEO_GUID(_guid), \ + _bitsperpix, _frmidx, _asrx, _asry, _interlace, _cp + +/* Uncompressed 3.1.2 Table 3-3 */ +#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, _minfrminterval, _maxfrminterval, _frmintervalstep) \ + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, \ + _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ + U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), 0, \ + U32_TO_U8S_LE(_minfrminterval), U32_TO_U8S_LE(_maxfrminterval), U32_TO_U8S_LE(_frmintervalstep) + +/* Uncompressed 3.1.2 Table 3-4 */ +#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, ...) \ + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN + (TU_ARGS_NUM(__VA_ARGS__)) * 4, \ + TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, \ + _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ + U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ + +/* 3.9.2.6 */ +#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(_color, _trns, _mat) \ + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN, \ + TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_COLORFORMAT, \ + _color, _trns, _mat + +/* 3.10.1.1 */ +#define TUD_VIDEO_DESC_EP_ISO(_ep, _epsize, _ep_interval) \ + 7, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS,\ + U16_TO_U8S_LE(_epsize), _ep_interval + +/* 3.10.1.2 */ +#define TUD_VIDEO_DESC_EP_BULK(_ep, _epsize, _ep_interval) \ + 7, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), _ep_interval + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.c new file mode 100644 index 00000000..7636db5f --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.c @@ -0,0 +1,1151 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Koji KITAYAMA + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_VIDEO && CFG_TUD_VIDEO_STREAMING) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "video_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +typedef struct { + tusb_desc_interface_t std; + tusb_desc_cs_video_ctl_itf_hdr_t ctl; +} tusb_desc_vc_itf_t; + +typedef struct { + tusb_desc_interface_t std; + tusb_desc_cs_video_stm_itf_hdr_t stm; +} tusb_desc_vs_itf_t; + +typedef union { + tusb_desc_cs_video_ctl_itf_hdr_t ctl; + tusb_desc_cs_video_stm_itf_hdr_t stm; +} tusb_desc_video_itf_hdr_t; + +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bEntityId; +} tusb_desc_cs_video_entity_itf_t; + +/* video streaming interface */ +typedef struct TU_ATTR_PACKED { + uint8_t index_vc; /* index of bound video control interface */ + uint8_t index_vs; /* index from the video control interface */ + struct { + uint16_t beg; /* Offset of the begging of video streaming interface descriptor */ + uint16_t end; /* Offset of the end of video streaming interface descriptor */ + uint16_t cur; /* Offset of the current settings */ + uint16_t ep[2]; /* Offset of endpoint descriptors. 0: streaming, 1: still capture */ + } desc; + uint8_t *buffer; /* frame buffer. assume linear buffer. no support for stride access */ + uint32_t bufsize; /* frame buffer size */ + uint32_t offset; /* offset for the next payload transfer */ + uint32_t max_payload_transfer_size; + uint8_t error_code;/* error code */ + /*------------- From this point, data is not cleared by bus reset -------------*/ + CFG_TUSB_MEM_ALIGN uint8_t ep_buf[CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE]; /* EP transfer buffer for streaming */ +} videod_streaming_interface_t; + +/* video control interface */ +typedef struct TU_ATTR_PACKED { + void const *beg; /* The head of the first video control interface descriptor */ + uint16_t len; /* Byte length of the descriptors */ + uint16_t cur; /* offset for current video control interface */ + uint8_t stm[CFG_TUD_VIDEO_STREAMING]; /* Indices of streaming interface */ + uint8_t error_code; /* error code */ + uint8_t power_mode; + + /*------------- From this point, data is not cleared by bus reset -------------*/ + // CFG_TUSB_MEM_ALIGN uint8_t ctl_buf[64]; /* EP transfer buffer for interrupt transfer */ + +} videod_interface_t; + +#define ITF_STM_MEM_RESET_SIZE offsetof(videod_streaming_interface_t, ep_buf) + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +CFG_TUSB_MEM_SECTION static videod_interface_t _videod_itf[CFG_TUD_VIDEO]; +CFG_TUSB_MEM_SECTION static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING]; + +static uint8_t const _cap_get = 0x1u; /* support for GET */ +static uint8_t const _cap_get_set = 0x3u; /* support for GET and SET */ + +/** Get interface number from the interface descriptor + * + * @param[in] desc interface descriptor + * + * @return bInterfaceNumber */ +static inline uint8_t _desc_itfnum(void const *desc) +{ + return ((uint8_t const*)desc)[2]; +} + +/** Get endpoint address from the endpoint descriptor + * + * @param[in] desc endpoint descriptor + * + * @return bEndpointAddress */ +static inline uint8_t _desc_ep_addr(void const *desc) +{ + return ((uint8_t const*)desc)[2]; +} + +/** Get instance of streaming interface + * + * @param[in] ctl_idx instance number of video control + * @param[in] stm_idx index number of streaming interface + * + * @return instance */ +static videod_streaming_interface_t* _get_instance_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) +{ + videod_interface_t *ctl = &_videod_itf[ctl_idx]; + if (!ctl->beg) return NULL; + videod_streaming_interface_t *stm = &_videod_streaming_itf[ctl->stm[stm_idx]]; + if (!stm->desc.beg) return NULL; + return stm; +} + +static tusb_desc_vc_itf_t const* _get_desc_vc(videod_interface_t const *self) +{ + return (tusb_desc_vc_itf_t const *)(self->beg + self->cur); +} + +static tusb_desc_vs_itf_t const* _get_desc_vs(videod_streaming_interface_t const *self) +{ + if (!self->desc.cur) return NULL; + void const *desc = _videod_itf[self->index_vc].beg; + return (tusb_desc_vs_itf_t const*)(desc + self->desc.cur); +} + +/** Find the first descriptor of a given type + * + * @param[in] beg The head of descriptor byte array. + * @param[in] end The tail of descriptor byte array. + * @param[in] desc_type The target descriptor type. + * + * @return The pointer for interface descriptor. + * @retval end did not found interface descriptor */ +static void const* _find_desc(void const *beg, void const *end, uint_fast8_t desc_type) +{ + void const *cur = beg; + while ((cur < end) && (desc_type != tu_desc_type(cur))) { + cur = tu_desc_next(cur); + } + return cur; +} + +/** Find the first descriptor specified by the arguments + * + * @param[in] beg The head of descriptor byte array. + * @param[in] end The tail of descriptor byte array. + * @param[in] desc_type The target descriptor type + * @param[in] element_0 The target element following the desc_type + * @param[in] element_1 The target element following the element_0 + * + * @return The pointer for interface descriptor. + * @retval end did not found interface descriptor */ +static void const* _find_desc_3(void const *beg, void const *end, + uint_fast8_t desc_type, + uint_fast8_t element_0, + uint_fast8_t element_1) +{ + for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, desc_type)) { + uint8_t const *p = (uint8_t const *)cur; + if ((p[2] == element_0) && (p[3] == element_1)) { + return cur; + } + cur = tu_desc_next(cur); + } + return end; +} + +/** Return the next interface descriptor which has another interface number. + * + * @param[in] beg The head of descriptor byte array. + * @param[in] end The tail of descriptor byte array. + * + * @return The pointer for interface descriptor. + * @retval end did not found interface descriptor */ +static void const* _next_desc_itf(void const *beg, void const *end) +{ + void const *cur = beg; + uint_fast8_t itfnum = ((tusb_desc_interface_t const*)cur)->bInterfaceNumber; + while ((cur < end) && + (itfnum == ((tusb_desc_interface_t const*)cur)->bInterfaceNumber)) { + cur = _find_desc(tu_desc_next(cur), end, TUSB_DESC_INTERFACE); + } + return cur; +} + +/** Find the first interface descriptor with the specified interface number and alternate setting number. + * + * @param[in] beg The head of descriptor byte array. + * @param[in] end The tail of descriptor byte array. + * @param[in] itfnum The target interface number. + * @param[in] altnum The target alternate setting number. + * + * @return The pointer for interface descriptor. + * @retval end did not found interface descriptor */ +static inline void const* _find_desc_itf(void const *beg, void const *end, uint_fast8_t itfnum, uint_fast8_t altnum) +{ + return _find_desc_3(beg, end, TUSB_DESC_INTERFACE, itfnum, altnum); +} + +/** Find the first endpoint descriptor belonging to the current interface descriptor. + * + * The search range is from `beg` to `end` or the next interface descriptor. + * + * @param[in] beg The head of descriptor byte array. + * @param[in] end The tail of descriptor byte array. + * + * @return The pointer for endpoint descriptor. + * @retval end did not found endpoint descriptor */ +static void const* _find_desc_ep(void const *beg, void const *end) +{ + for (void const *cur = beg; cur < end; cur = tu_desc_next(cur)) { + uint_fast8_t desc_type = tu_desc_type(cur); + if (TUSB_DESC_ENDPOINT == desc_type) return cur; + if (TUSB_DESC_INTERFACE == desc_type) break; + } + return end; +} + +/** Find the first entity descriptor with the entity ID + * specified by the argument belonging to the current video control descriptor. + * + * @param[in] desc The video control interface descriptor. + * @param[in] entityid The target entity id. + * + * @return The pointer for interface descriptor. + * @retval end did not found interface descriptor */ +static void const* _find_desc_entity(void const *desc, uint_fast8_t entityid) +{ + tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const*)desc; + void const *beg = vc; + void const *end = beg + vc->std.bLength + vc->ctl.wTotalLength; + for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) { + tusb_desc_cs_video_entity_itf_t const *itf = (tusb_desc_cs_video_entity_itf_t const *)cur; + if ((VIDEO_CS_ITF_VC_INPUT_TERMINAL <= itf->bDescriptorSubtype + && itf->bDescriptorSubtype < VIDEO_CS_ITF_VC_MAX) + && itf->bEntityId == entityid) { + return itf; + } + cur = tu_desc_next(cur); + } + return end; +} + +/** Return the end of the video streaming descriptor. */ +static inline void const* _end_of_streaming_descriptor(void const *desc) +{ + tusb_desc_vs_itf_t const *vs = (tusb_desc_vs_itf_t const *)desc; + return desc + vs->std.bLength + vs->stm.wTotalLength; +} + +/** Find the first format descriptor with the specified format number. */ +static inline tusb_desc_cs_video_fmt_uncompressed_t const *_find_desc_format(void const *beg, void const *end, uint_fast8_t fmtnum) +{ + return (tusb_desc_cs_video_fmt_uncompressed_t const*) + _find_desc_3(beg, end, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED, fmtnum); +} + +/** Find the first frame descriptor with the specified format number. */ +static inline tusb_desc_cs_video_frm_uncompressed_t const *_find_desc_frame(void const *beg, void const *end, uint_fast8_t frmnum) +{ + return (tusb_desc_cs_video_frm_uncompressed_t const*) + _find_desc_3(beg, end, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, frmnum); +} + +/** Set uniquely determined values to variables that have not been set + * + * @param[in,out] param Target */ +static bool _update_streaming_parameters(videod_streaming_interface_t const *stm, + video_probe_and_commit_control_t *param) +{ + tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); + uint_fast8_t fmtnum = param->bFormatIndex; + TU_ASSERT(vs && fmtnum <= vs->stm.bNumFormats); + if (!fmtnum) { + if (1 < vs->stm.bNumFormats) return true; /* Need to negotiate all variables. */ + fmtnum = 1; + param->bFormatIndex = 1; + } + + /* Set the parameters determined by the format */ + param->wKeyFrameRate = 1; + param->wPFrameRate = 0; + param->wCompQuality = 1; /* 1 to 10000 */ + param->wCompWindowSize = 1; /* GOP size? */ + param->wDelay = 0; /* milliseconds */ + param->dwClockFrequency = 27000000; /* same as MPEG-2 system time clock */ + param->bmFramingInfo = 0x3; /* enables FrameID and EndOfFrame */ + param->bPreferedVersion = 1; + param->bMinVersion = 1; + param->bMaxVersion = 1; + param->bUsage = 0; + param->bBitDepthLuma = 8; + + void const *end = _end_of_streaming_descriptor(vs); + tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); + TU_ASSERT(fmt != end); + uint_fast8_t frmnum = param->bFrameIndex; + TU_ASSERT(frmnum <= fmt->bNumFrameDescriptors); + if (!frmnum) { + if (1 < fmt->bNumFrameDescriptors) return true; + frmnum = 1; + param->bFrameIndex = 1; + } + tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); + TU_ASSERT(frm != end); + + /* Set the parameters determined by the frame */ + uint_fast32_t frame_size = param->dwMaxVideoFrameSize; + if (!frame_size) { + frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->bBitsPerPixel / 8; + param->dwMaxVideoFrameSize = frame_size; + } + + uint_fast32_t interval = param->dwFrameInterval; + if (!interval) { + if ((1 < frm->bFrameIntervalType) || + ((0 == frm->bFrameIntervalType) && (frm->dwFrameInterval[1] != frm->dwFrameInterval[0]))) { + return true; + } + interval = frm->dwFrameInterval[0]; + param->dwFrameInterval = interval; + } + uint_fast32_t interval_ms = interval / 10000; + TU_ASSERT(interval_ms); + uint_fast32_t payload_size = (frame_size + interval_ms - 1) / interval_ms + 2; + param->dwMaxPayloadTransferSize = payload_size; + return true; +} + +/** Set the minimum, maximum, default values or resolutions to variables which need to negotiate with the host + * + * @param[in] request GET_MAX, GET_MIN, GET_RES or GET_DEF + * @param[in,out] param Target + */ +static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *stm, uint_fast8_t request, + video_probe_and_commit_control_t *param) +{ + uint_fast8_t const fmtnum = param->bFormatIndex; + if (!fmtnum) { + switch (request) { + case VIDEO_REQUEST_GET_MAX: + param->bFormatIndex = _get_desc_vs(stm)->stm.bNumFormats; + break; + case VIDEO_REQUEST_GET_MIN: + case VIDEO_REQUEST_GET_DEF: + param->bFormatIndex = 1; + break; + default: return false; + } + /* Set the parameters determined by the format */ + param->wKeyFrameRate = 1; + param->wPFrameRate = 0; + param->wCompQuality = 1; /* 1 to 10000 */ + param->wCompWindowSize = 1; /* GOP size? */ + param->wDelay = 0; /* milliseconds */ + param->dwClockFrequency = 27000000; /* same as MPEG-2 system time clock */ + param->bmFramingInfo = 0x3; /* enables FrameID and EndOfFrame */ + param->bPreferedVersion = 1; + param->bMinVersion = 1; + param->bMaxVersion = 1; + param->bUsage = 0; + param->bBitDepthLuma = 8; + return true; + } + + uint_fast8_t frmnum = param->bFrameIndex; + if (!frmnum) { + tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); + TU_ASSERT(vs); + void const *end = _end_of_streaming_descriptor(vs); + tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); + switch (request) { + case VIDEO_REQUEST_GET_MAX: + frmnum = fmt->bNumFrameDescriptors; + break; + case VIDEO_REQUEST_GET_MIN: + frmnum = 1; + break; + case VIDEO_REQUEST_GET_DEF: + frmnum = fmt->bDefaultFrameIndex; + break; + default: return false; + } + param->bFrameIndex = (uint8_t) frmnum; + /* Set the parameters determined by the frame */ + tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); + param->dwMaxVideoFrameSize = (uint32_t) (frm->wWidth * frm->wHeight * fmt->bBitsPerPixel / 8); + return true; + } + + if (!param->dwFrameInterval) { + tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); + TU_ASSERT(vs); + void const *end = _end_of_streaming_descriptor(vs); + tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); + tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); + + uint_fast32_t interval, interval_ms; + switch (request) { + case VIDEO_REQUEST_GET_MAX: + { + uint_fast32_t min_interval, max_interval; + uint_fast8_t num_intervals = frm->bFrameIntervalType; + max_interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1]; + min_interval = frm->dwFrameInterval[0]; + interval = max_interval; + interval_ms = min_interval / 10000; + } + break; + case VIDEO_REQUEST_GET_MIN: + { + uint_fast32_t min_interval, max_interval; + uint_fast8_t num_intervals = frm->bFrameIntervalType; + max_interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1]; + min_interval = frm->dwFrameInterval[0]; + interval = min_interval; + interval_ms = max_interval / 10000; + } + break; + case VIDEO_REQUEST_GET_DEF: + interval = frm->dwDefaultFrameInterval; + interval_ms = interval / 10000; + break; + case VIDEO_REQUEST_GET_RES: + { + uint_fast8_t num_intervals = frm->bFrameIntervalType; + if (num_intervals) { + interval = 0; + } else { + interval = frm->dwFrameInterval[2]; + interval_ms = interval / 10000; + } + } + break; + default: return false; + } + param->dwFrameInterval = interval; + if (!interval) { + param->dwMaxPayloadTransferSize = 0; + } else { + uint_fast32_t frame_size = param->dwMaxVideoFrameSize; + if (!interval_ms) { + param->dwMaxPayloadTransferSize = frame_size + 2; + } else { + param->dwMaxPayloadTransferSize = (frame_size + interval_ms - 1) / interval_ms + 2; + } + } + return true; + } + return true; +} + +/** Close current video control interface. + * + * @param[in,out] self Video control interface context. + * @param[in] altnum The target alternate setting number. */ +static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self) +{ + tusb_desc_vc_itf_t const *vc = _get_desc_vc(self); + /* The next descriptor after the class-specific VC interface header descriptor. */ + void const *cur = (void const*)vc + vc->std.bLength + vc->ctl.bLength; + /* The end of the video control interface descriptor. */ + void const *end = (void const*)vc + vc->std.bLength + vc->ctl.wTotalLength; + if (vc->std.bNumEndpoints) { + /* Find the notification endpoint descriptor. */ + cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT); + TU_ASSERT(cur < end); + tusb_desc_endpoint_t const *notif = (tusb_desc_endpoint_t const *)cur; + usbd_edpt_close(rhport, notif->bEndpointAddress); + } + self->cur = 0; + return true; +} + +/** Set the alternate setting to own video control interface. + * + * @param[in,out] self Video control interface context. + * @param[in] altnum The target alternate setting number. */ +static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t altnum) +{ + TU_LOG2(" open VC %d\n", altnum); + void const *beg = self->beg; + void const *end = beg + self->len; + /* The first descriptor is a video control interface descriptor. */ + void const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); + TU_LOG2(" cur %d\n", cur - beg); + TU_VERIFY(cur < end); + + tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const *)cur; + TU_LOG2(" bInCollection %d\n", vc->ctl.bInCollection); + /* Support for up to 2 streaming interfaces only. */ + TU_ASSERT(vc->ctl.bInCollection <= CFG_TUD_VIDEO_STREAMING); + + /* Update to point the end of the video control interface descriptor. */ + end = cur + vc->std.bLength + vc->ctl.wTotalLength; + /* Advance to the next descriptor after the class-specific VC interface header descriptor. */ + cur += vc->std.bLength + vc->ctl.bLength; + TU_LOG2(" bNumEndpoints %d\n", vc->std.bNumEndpoints); + /* Open the notification endpoint if it exist. */ + if (vc->std.bNumEndpoints) { + /* Support for 1 endpoint only. */ + TU_VERIFY(1 == vc->std.bNumEndpoints); + /* Find the notification endpoint descriptor. */ + cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT); + TU_VERIFY(cur < end); + tusb_desc_endpoint_t const *notif = (tusb_desc_endpoint_t const *)cur; + /* Open the notification endpoint */ + TU_ASSERT(usbd_edpt_open(rhport, notif)); + } + self->cur = (uint16_t) ((void const*)vc - beg); + return true; +} + +/** Set the alternate setting to own video streaming interface. + * + * @param[in,out] stm Streaming interface context. + * @param[in] altnum The target alternate setting number. */ +static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint_fast8_t altnum) +{ + uint_fast8_t i; + TU_LOG2(" reopen VS %d\n", altnum); + void const *desc = _videod_itf[stm->index_vc].beg; + + /* Close endpoints of previous settings. */ + for (i = 0; i < TU_ARRAY_SIZE(stm->desc.ep); ++i) { + uint_fast16_t ofs_ep = stm->desc.ep[i]; + if (!ofs_ep) break; + uint8_t ep_adr = _desc_ep_addr(desc + ofs_ep); + usbd_edpt_close(rhport, ep_adr); + stm->desc.ep[i] = 0; + TU_LOG2(" close EP%02x\n", ep_adr); + } + /* clear transfer management information */ + stm->buffer = NULL; + stm->bufsize = 0; + stm->offset = 0; + + /* Find a alternate interface */ + void const *beg = desc + stm->desc.beg; + void const *end = desc + stm->desc.end; + void const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); + TU_VERIFY(cur < end); + uint_fast8_t numeps = ((tusb_desc_interface_t const *)cur)->bNumEndpoints; + TU_ASSERT(numeps <= TU_ARRAY_SIZE(stm->desc.ep)); + stm->desc.cur = (uint16_t) (cur - desc); /* Save the offset of the new settings */ + if (!altnum) { + /* initialize streaming settings */ + stm->max_payload_transfer_size = 0; + video_probe_and_commit_control_t *param = + (video_probe_and_commit_control_t *)&stm->ep_buf; + tu_memclr(param, sizeof(*param)); + return _update_streaming_parameters(stm, param); + } + /* Open endpoints of the new settings. */ + for (i = 0, cur = tu_desc_next(cur); i < numeps; ++i, cur = tu_desc_next(cur)) { + cur = _find_desc_ep(cur, end); + TU_ASSERT(cur < end); + tusb_desc_endpoint_t const *ep = (tusb_desc_endpoint_t const*)cur; + if (!stm->max_payload_transfer_size) { + video_probe_and_commit_control_t const *param = (video_probe_and_commit_control_t const*)&stm->ep_buf; + uint_fast32_t max_size = param->dwMaxPayloadTransferSize; + if ((TUSB_XFER_ISOCHRONOUS == ep->bmAttributes.xfer) && + (tu_edpt_packet_size(ep) < max_size)) + { + /* FS must be less than or equal to max packet size */ + return false; + } + /* Set the negotiated value */ + stm->max_payload_transfer_size = max_size; + } + TU_ASSERT(usbd_edpt_open(rhport, ep)); + stm->desc.ep[i] = (uint16_t) (cur - desc); + TU_LOG2(" open EP%02x\n", _desc_ep_addr(cur)); + } + /* initialize payload header */ + tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf; + hdr->bHeaderLength = sizeof(*hdr); + hdr->bmHeaderInfo = 0; + + return true; +} + +/** Prepare the next packet payload. */ +static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm) +{ + uint_fast16_t remaining = stm->bufsize - stm->offset; + uint_fast16_t hdr_len = stm->ep_buf[0]; + uint_fast16_t pkt_len = stm->max_payload_transfer_size; + if (hdr_len + remaining < pkt_len) { + pkt_len = hdr_len + remaining; + } + uint_fast16_t data_len = pkt_len - hdr_len; + memcpy(&stm->ep_buf[hdr_len], stm->buffer + stm->offset, data_len); + stm->offset += data_len; + remaining -= data_len; + if (!remaining) { + tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf; + hdr->EndOfFrame = 1; + } + return hdr_len + data_len; +} + +/** Handle a standard request to the video control interface. */ +static int handle_video_ctl_std_req(uint8_t rhport, uint8_t stage, + tusb_control_request_t const *request, + uint_fast8_t ctl_idx) +{ + switch (request->bRequest) { + case TUSB_REQ_GET_INTERFACE: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); + tusb_desc_vc_itf_t const *vc = _get_desc_vc(&_videod_itf[ctl_idx]); + TU_VERIFY(vc, VIDEO_ERROR_UNKNOWN); + + uint8_t alt_num = vc->std.bAlternateSetting; + + TU_VERIFY(tud_control_xfer(rhport, request, &alt_num, sizeof(alt_num)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case TUSB_REQ_SET_INTERFACE: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(0 == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(_close_vc_itf(rhport, &_videod_itf[ctl_idx]), VIDEO_ERROR_UNKNOWN); + TU_VERIFY(_open_vc_itf(rhport, &_videod_itf[ctl_idx], request->wValue), VIDEO_ERROR_UNKNOWN); + tud_control_status(rhport, request); + } + return VIDEO_ERROR_NONE; + + default: /* Unknown/Unsupported request */ + TU_BREAKPOINT(); + return VIDEO_ERROR_INVALID_REQUEST; + } +} + +static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage, + tusb_control_request_t const *request, + uint_fast8_t ctl_idx) +{ + videod_interface_t *self = &_videod_itf[ctl_idx]; + + /* 4.2.1 Interface Control Request */ + switch (TU_U16_HIGH(request->wValue)) { + case VIDEO_VC_CTL_VIDEO_POWER_MODE: + switch (request->bRequest) { + case VIDEO_REQUEST_SET_CUR: + if (stage == CONTROL_STAGE_SETUP) { + TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, &self->power_mode, sizeof(self->power_mode)), VIDEO_ERROR_UNKNOWN); + } else if (stage == CONTROL_STAGE_ACK) { + if (tud_video_power_mode_cb) return tud_video_power_mode_cb(ctl_idx, self->power_mode); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_CUR: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, &self->power_mode, sizeof(self->power_mode)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_INFO: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + default: break; + } + break; + + case VIDEO_VC_CTL_REQUEST_ERROR_CODE: + switch (request->bRequest) { + case VIDEO_REQUEST_GET_CUR: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(tud_control_xfer(rhport, request, &self->error_code, sizeof(uint8_t)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_INFO: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get, sizeof(_cap_get)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + default: break; + } + break; + + default: break; + } + + /* Unknown/Unsupported request */ + TU_BREAKPOINT(); + return VIDEO_ERROR_INVALID_REQUEST; +} + +static int handle_video_ctl_req(uint8_t rhport, uint8_t stage, + tusb_control_request_t const *request, + uint_fast8_t ctl_idx) +{ + uint_fast8_t entity_id; + switch (request->bmRequestType_bit.type) { + case TUSB_REQ_TYPE_STANDARD: + return handle_video_ctl_std_req(rhport, stage, request, ctl_idx); + + case TUSB_REQ_TYPE_CLASS: + entity_id = TU_U16_HIGH(request->wIndex); + if (!entity_id) { + return handle_video_ctl_cs_req(rhport, stage, request, ctl_idx); + } else { + TU_VERIFY(_find_desc_entity(_get_desc_vc(&_videod_itf[ctl_idx]), entity_id), VIDEO_ERROR_INVALID_REQUEST); + return VIDEO_ERROR_NONE; + } + + default: + return VIDEO_ERROR_INVALID_REQUEST; + } +} + +static int handle_video_stm_std_req(uint8_t rhport, uint8_t stage, + tusb_control_request_t const *request, + uint_fast8_t stm_idx) +{ + videod_streaming_interface_t *self = &_videod_streaming_itf[stm_idx]; + switch (request->bRequest) { + case TUSB_REQ_GET_INTERFACE: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); + tusb_desc_vs_itf_t const *vs = _get_desc_vs(self); + TU_VERIFY(vs, VIDEO_ERROR_UNKNOWN); + uint8_t alt_num = vs->std.bAlternateSetting; + + TU_VERIFY(tud_control_xfer(rhport, request, &alt_num, sizeof(alt_num)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case TUSB_REQ_SET_INTERFACE: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(_open_vs_itf(rhport, self, request->wValue), VIDEO_ERROR_UNKNOWN); + tud_control_status(rhport, request); + } + return VIDEO_ERROR_NONE; + + default: /* Unknown/Unsupported request */ + TU_BREAKPOINT(); + return VIDEO_ERROR_INVALID_REQUEST; + } +} + +static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, + tusb_control_request_t const *request, + uint_fast8_t stm_idx) +{ + (void)rhport; + videod_streaming_interface_t *self = &_videod_streaming_itf[stm_idx]; + + /* 4.2.1 Interface Control Request */ + switch (TU_U16_HIGH(request->wValue)) { + case VIDEO_VS_CTL_STREAM_ERROR_CODE: + switch (request->bRequest) { + case VIDEO_REQUEST_GET_CUR: + if (stage == CONTROL_STAGE_SETUP) + { + /* TODO */ + TU_VERIFY(tud_control_xfer(rhport, request, &self->error_code, sizeof(uint8_t)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_INFO: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get, sizeof(_cap_get)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + default: break; + } + break; + + case VIDEO_VS_CTL_PROBE: + switch (request->bRequest) { + case VIDEO_REQUEST_SET_CUR: + if (stage == CONTROL_STAGE_SETUP) { + TU_VERIFY(sizeof(video_probe_and_commit_control_t) == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), + VIDEO_ERROR_UNKNOWN); + } else if (stage == CONTROL_STAGE_ACK) { + TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf), + VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_CUR: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_MIN: + case VIDEO_REQUEST_GET_MAX: + case VIDEO_REQUEST_GET_RES: + case VIDEO_REQUEST_GET_DEF: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN); + video_probe_and_commit_control_t tmp; + tmp = *(video_probe_and_commit_control_t*)&self->ep_buf; + TU_VERIFY(_negotiate_streaming_parameters(self, request->bRequest, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); + TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_LEN: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN); + uint16_t len = sizeof(video_probe_and_commit_control_t); + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_INFO: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + default: break; + } + break; + + case VIDEO_VS_CTL_COMMIT: + switch (request->bRequest) { + case VIDEO_REQUEST_SET_CUR: + if (stage == CONTROL_STAGE_SETUP) { + TU_VERIFY(sizeof(video_probe_and_commit_control_t) == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); + } else if (stage == CONTROL_STAGE_ACK) { + TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); + if (tud_video_commit_cb) { + return tud_video_commit_cb(self->index_vc, self->index_vs, (video_probe_and_commit_control_t*)self->ep_buf); + } + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_CUR: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_LEN: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN); + uint16_t len = sizeof(video_probe_and_commit_control_t); + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + case VIDEO_REQUEST_GET_INFO: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + + default: break; + } + break; + + case VIDEO_VS_CTL_STILL_PROBE: + case VIDEO_VS_CTL_STILL_COMMIT: + case VIDEO_VS_CTL_STILL_IMAGE_TRIGGER: + case VIDEO_VS_CTL_GENERATE_KEY_FRAME: + case VIDEO_VS_CTL_UPDATE_FRAME_SEGMENT: + case VIDEO_VS_CTL_SYNCH_DELAY_CONTROL: + /* TODO */ + break; + + default: break; + } + + /* Unknown/Unsupported request */ + TU_BREAKPOINT(); + return VIDEO_ERROR_INVALID_REQUEST; +} + +static int handle_video_stm_req(uint8_t rhport, uint8_t stage, + tusb_control_request_t const *request, + uint_fast8_t stm_idx) +{ + switch (request->bmRequestType_bit.type) { + case TUSB_REQ_TYPE_STANDARD: + return handle_video_stm_std_req(rhport, stage, request, stm_idx); + + case TUSB_REQ_TYPE_CLASS: + if (TU_U16_HIGH(request->wIndex)) return VIDEO_ERROR_INVALID_REQUEST; + return handle_video_stm_cs_req(rhport, stage, request, stm_idx); + + default: return VIDEO_ERROR_INVALID_REQUEST; + } + return VIDEO_ERROR_UNKNOWN; +} + +//--------------------------------------------------------------------+ +// APPLICATION API +//--------------------------------------------------------------------+ + +bool tud_video_n_connected(uint_fast8_t ctl_idx) +{ + TU_ASSERT(ctl_idx < CFG_TUD_VIDEO); + videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, 0); + if (stm) return true; + return false; +} + +bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) +{ + TU_ASSERT(ctl_idx < CFG_TUD_VIDEO); + TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING); + videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx); + if (!stm || !stm->desc.ep[0]) return false; + return true; +} + +bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *buffer, size_t bufsize) +{ + TU_ASSERT(ctl_idx < CFG_TUD_VIDEO); + TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING); + if (!buffer || !bufsize) return false; + videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx); + if (!stm || !stm->desc.ep[0] || stm->buffer) return false; + + /* Find EP address */ + void const *desc = _videod_itf[stm->index_vc].beg; + uint8_t ep_addr = 0; + for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { + uint_fast16_t ofs_ep = stm->desc.ep[i]; + if (!ofs_ep) continue; + ep_addr = _desc_ep_addr(desc + ofs_ep); + break; + } + if (!ep_addr) return false; + + TU_VERIFY( usbd_edpt_claim(0, ep_addr) ); + /* update the packet header */ + tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf; + hdr->FrameID ^= 1; + hdr->EndOfFrame = 0; + /* update the packet data */ + stm->buffer = (uint8_t*)buffer; + stm->bufsize = bufsize; + uint_fast16_t pkt_len = _prepare_in_payload(stm); + TU_ASSERT( usbd_edpt_xfer(0, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0); + return true; +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void videod_init(void) +{ + for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) { + videod_interface_t* ctl = &_videod_itf[i]; + tu_memclr(ctl, sizeof(*ctl)); + } + for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { + videod_streaming_interface_t *stm = &_videod_streaming_itf[i]; + tu_memclr(stm, ITF_STM_MEM_RESET_SIZE); + } +} + +void videod_reset(uint8_t rhport) +{ + (void) rhport; + for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) { + videod_interface_t* ctl = &_videod_itf[i]; + tu_memclr(ctl, sizeof(*ctl)); + } + for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { + videod_streaming_interface_t *stm = &_videod_streaming_itf[i]; + tu_memclr(stm, ITF_STM_MEM_RESET_SIZE); + } +} + +uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + TU_VERIFY((TUSB_CLASS_VIDEO == itf_desc->bInterfaceClass) && + (VIDEO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass) && + (VIDEO_ITF_PROTOCOL_15 == itf_desc->bInterfaceProtocol), 0); + + /* Find available interface */ + videod_interface_t *self = NULL; + uint8_t ctl_idx; + for (ctl_idx = 0; ctl_idx < CFG_TUD_VIDEO; ++ctl_idx) { + if (_videod_itf[ctl_idx].beg) continue; + self = &_videod_itf[ctl_idx]; + break; + } + TU_ASSERT(ctl_idx < CFG_TUD_VIDEO, 0); + + void const *end = (void const*)itf_desc + max_len; + self->beg = itf_desc; + self->len = max_len; + /*------------- Video Control Interface -------------*/ + TU_VERIFY(_open_vc_itf(rhport, self, 0), 0); + tusb_desc_vc_itf_t const *vc = _get_desc_vc(self); + uint_fast8_t bInCollection = vc->ctl.bInCollection; + /* Find the end of the video interface descriptor */ + void const *cur = _next_desc_itf(itf_desc, end); + for (uint8_t stm_idx = 0; stm_idx < bInCollection; ++stm_idx) { + videod_streaming_interface_t *stm = NULL; + /* find free streaming interface handle */ + for (uint8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { + if (_videod_streaming_itf[i].desc.beg) continue; + stm = &_videod_streaming_itf[i]; + self->stm[stm_idx] = i; + break; + } + TU_ASSERT(stm, 0); + stm->index_vc = ctl_idx; + stm->index_vs = stm_idx; + stm->desc.beg = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); + cur = _next_desc_itf(cur, end); + stm->desc.end = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); + } + self->len = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); + return (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + int err; + TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); + uint_fast8_t itfnum = tu_u16_low(request->wIndex); + + /* Identify which control interface to use */ + uint_fast8_t itf; + for (itf = 0; itf < CFG_TUD_VIDEO; ++itf) { + void const *desc = _videod_itf[itf].beg; + if (!desc) continue; + if (itfnum == _desc_itfnum(desc)) break; + } + + if (itf < CFG_TUD_VIDEO) { + err = handle_video_ctl_req(rhport, stage, request, itf); + _videod_itf[itf].error_code = (uint8_t)err; + if (err) return false; + return true; + } + + /* Identify which streaming interface to use */ + for (itf = 0; itf < CFG_TUD_VIDEO_STREAMING; ++itf) { + videod_streaming_interface_t *stm = &_videod_streaming_itf[itf]; + if (!stm->desc.beg) continue; + void const *desc = _videod_itf[stm->index_vc].beg; + if (itfnum == _desc_itfnum(desc + stm->desc.beg)) break; + } + + if (itf < CFG_TUD_VIDEO_STREAMING) { + err = handle_video_stm_req(rhport, stage, request, itf); + _videod_streaming_itf[itf].error_code = (uint8_t)err; + if (err) return false; + return true; + } + return false; +} + +bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void)result; (void)xferred_bytes; + + /* find streaming handle */ + uint_fast8_t itf; + videod_interface_t *ctl; + videod_streaming_interface_t *stm; + for (itf = 0; itf < CFG_TUD_VIDEO_STREAMING; ++itf) { + stm = &_videod_streaming_itf[itf]; + uint_fast16_t const ep_ofs = stm->desc.ep[0]; + if (!ep_ofs) continue; + ctl = &_videod_itf[stm->index_vc]; + void const *desc = ctl->beg; + if (ep_addr == _desc_ep_addr(desc + ep_ofs)) break; + } + + TU_ASSERT(itf < CFG_TUD_VIDEO_STREAMING); + if (stm->offset < stm->bufsize) { + /* Claim the endpoint */ + TU_VERIFY( usbd_edpt_claim(rhport, ep_addr), 0); + uint_fast16_t pkt_len = _prepare_in_payload(stm); + TU_ASSERT( usbd_edpt_xfer(rhport, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0); + } else { + stm->buffer = NULL; + stm->bufsize = 0; + stm->offset = 0; + if (tud_video_frame_xfer_complete_cb) { + tud_video_frame_xfer_complete_cb(stm->index_vc, stm->index_vs); + } + } + return true; +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.h new file mode 100644 index 00000000..ee2fcb9d --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.h @@ -0,0 +1,97 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2021 Koji KITAYAMA + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef TUSB_VIDEO_DEVICE_H_ +#define TUSB_VIDEO_DEVICE_H_ + +#include "common/tusb_common.h" +#include "video.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Application API (Multiple Ports) +// CFG_TUD_VIDEO > 1 +//--------------------------------------------------------------------+ + +/** Return true if streaming + * + * @param[in] ctl_idx Destination control interface index + * @param[in] stm_idx Destination streaming interface index */ +bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx); + +/** Transfer a frame + * + * @param[in] ctl_idx Destination control interface index + * @param[in] stm_idx Destination streaming interface index + * @param[in] buffer Frame buffer. The caller must not use this buffer until the operation is completed. + * @param[in] bufsize Byte size of the frame buffer */ +bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *buffer, size_t bufsize); + +/*------------- Optional callbacks -------------*/ +/** Invoked when compeletion of a frame transfer + * + * @param[in] ctl_idx Destination control interface index + * @param[in] stm_idx Destination streaming interface index */ +TU_ATTR_WEAK void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx); + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ + +/** Invoked when SET_POWER_MODE request received + * + * @param[in] ctl_idx Destination control interface index + * @param[in] stm_idx Destination streaming interface index + * @return video_error_code_t */ +TU_ATTR_WEAK int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod); + +/** Invoked when VS_COMMIT_CONTROL(SET_CUR) request received + * + * @param[in] ctl_idx Destination control interface index + * @param[in] stm_idx Destination streaming interface index + * @param[in] parameters Video streaming parameters + * @return video_error_code_t */ +TU_ATTR_WEAK int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, + video_probe_and_commit_control_t const *parameters); + +//--------------------------------------------------------------------+ +// INTERNAL USBD-CLASS DRIVER API +//--------------------------------------------------------------------+ +void videod_init (void); +void videod_reset (uint8_t rhport); +uint16_t videod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +bool videod_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_common.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_common.h new file mode 100644 index 00000000..b1ee40a1 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_common.h @@ -0,0 +1,266 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_COMMON_H_ +#define _TUSB_COMMON_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Macros Helper +//--------------------------------------------------------------------+ +#define TU_ARRAY_SIZE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) ) +#define TU_MIN(_x, _y) ( ( (_x) < (_y) ) ? (_x) : (_y) ) +#define TU_MAX(_x, _y) ( ( (_x) > (_y) ) ? (_x) : (_y) ) + +#define TU_U16(_high, _low) ((uint16_t) (((_high) << 8) | (_low))) +#define TU_U16_HIGH(_u16) ((uint8_t) (((_u16) >> 8) & 0x00ff)) +#define TU_U16_LOW(_u16) ((uint8_t) ((_u16) & 0x00ff)) +#define U16_TO_U8S_BE(_u16) TU_U16_HIGH(_u16), TU_U16_LOW(_u16) +#define U16_TO_U8S_LE(_u16) TU_U16_LOW(_u16), TU_U16_HIGH(_u16) + +#define TU_U32_BYTE3(_u32) ((uint8_t) ((((uint32_t) _u32) >> 24) & 0x000000ff)) // MSB +#define TU_U32_BYTE2(_u32) ((uint8_t) ((((uint32_t) _u32) >> 16) & 0x000000ff)) +#define TU_U32_BYTE1(_u32) ((uint8_t) ((((uint32_t) _u32) >> 8) & 0x000000ff)) +#define TU_U32_BYTE0(_u32) ((uint8_t) (((uint32_t) _u32) & 0x000000ff)) // LSB + +#define U32_TO_U8S_BE(_u32) TU_U32_BYTE3(_u32), TU_U32_BYTE2(_u32), TU_U32_BYTE1(_u32), TU_U32_BYTE0(_u32) +#define U32_TO_U8S_LE(_u32) TU_U32_BYTE0(_u32), TU_U32_BYTE1(_u32), TU_U32_BYTE2(_u32), TU_U32_BYTE3(_u32) + +#define TU_BIT(n) (1UL << (n)) +#define TU_GENMASK(h, l) ( (UINT32_MAX << (l)) & (UINT32_MAX >> (31 - (h))) ) + +//--------------------------------------------------------------------+ +// Includes +//--------------------------------------------------------------------+ + +// Standard Headers +#include +#include +#include +#include +#include + +// Tinyusb Common Headers +#include "tusb_option.h" +#include "tusb_compiler.h" +#include "tusb_verify.h" +#include "tusb_types.h" +#include "tusb_debug.h" + +#include "tusb_timeout.h" // TODO remove + +//--------------------------------------------------------------------+ +// Internal Inline Functions +//--------------------------------------------------------------------+ + +//------------- Mem -------------// +#define tu_memclr(buffer, size) memset((buffer), 0, (size)) +#define tu_varclr(_var) tu_memclr(_var, sizeof(*(_var))) + +//------------- Bytes -------------// +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_u32(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0) +{ + return ( ((uint32_t) b3) << 24) | ( ((uint32_t) b2) << 16) | ( ((uint32_t) b1) << 8) | b0; +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u16(uint8_t high, uint8_t low) +{ + return (uint16_t) ((((uint16_t) high) << 8) | low); +} + +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u32_byte3(uint32_t ui32) { return TU_U32_BYTE3(ui32); } +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u32_byte2(uint32_t ui32) { return TU_U32_BYTE2(ui32); } +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u32_byte1(uint32_t ui32) { return TU_U32_BYTE1(ui32); } +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u32_byte0(uint32_t ui32) { return TU_U32_BYTE0(ui32); } + +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u32_high16(uint32_t ui32) { return (uint16_t) (ui32 >> 16); } +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u32_low16 (uint32_t ui32) { return (uint16_t) (ui32 & 0x0000ffffu); } + +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u16_high(uint16_t ui16) { return TU_U16_HIGH(ui16); } +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u16_low (uint16_t ui16) { return TU_U16_LOW(ui16); } + +//------------- Bits -------------// +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_bit_set (uint32_t value, uint8_t pos) { return value | TU_BIT(pos); } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_bit_clear(uint32_t value, uint8_t pos) { return value & (~TU_BIT(pos)); } +TU_ATTR_ALWAYS_INLINE static inline bool tu_bit_test (uint32_t value, uint8_t pos) { return (value & TU_BIT(pos)) ? true : false; } + +//------------- Min -------------// +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_min8 (uint8_t x, uint8_t y ) { return (x < y) ? x : y; } +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_min16 (uint16_t x, uint16_t y) { return (x < y) ? x : y; } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_min32 (uint32_t x, uint32_t y) { return (x < y) ? x : y; } + +//------------- Max -------------// +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_max8 (uint8_t x, uint8_t y ) { return (x > y) ? x : y; } +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_max16 (uint16_t x, uint16_t y) { return (x > y) ? x : y; } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_max32 (uint32_t x, uint32_t y) { return (x > y) ? x : y; } + +//------------- Align -------------// +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align(uint32_t value, uint32_t alignment) +{ + return value & ((uint32_t) ~(alignment-1)); +} + +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align16 (uint32_t value) { return (value & 0xFFFFFFF0UL); } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align32 (uint32_t value) { return (value & 0xFFFFFFE0UL); } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align4k (uint32_t value) { return (value & 0xFFFFF000UL); } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_offset4k(uint32_t value) { return (value & 0xFFFUL); } + +//------------- Mathematics -------------// +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_div_ceil(uint32_t v, uint32_t d) { return (v + d -1)/d; } + +// log2 of a value is its MSB's position +// TODO use clz TODO remove +static inline uint8_t tu_log2(uint32_t value) +{ + uint8_t result = 0; + while (value >>= 1) { result++; } + return result; +} + +//static inline uint8_t tu_log2(uint32_t value) +//{ +// return sizeof(uint32_t) * CHAR_BIT - __builtin_clz(x) - 1; +//} + +static inline bool tu_is_power_of_two(uint32_t value) +{ + return (value != 0) && ((value & (value - 1)) == 0); +} + +//------------- Unaligned Access -------------// +#if TUP_ARCH_STRICT_ALIGN + +// Rely on compiler to generate correct code for unaligned access +typedef struct { uint16_t val; } TU_ATTR_PACKED tu_unaligned_uint16_t; +typedef struct { uint32_t val; } TU_ATTR_PACKED tu_unaligned_uint32_t; + +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32(const void* mem) +{ + tu_unaligned_uint32_t const* ua32 = (tu_unaligned_uint32_t const*) mem; + return ua32->val; +} + +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32(void* mem, uint32_t value) +{ + tu_unaligned_uint32_t* ua32 = (tu_unaligned_uint32_t*) mem; + ua32->val = value; +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16(const void* mem) +{ + tu_unaligned_uint16_t const* ua16 = (tu_unaligned_uint16_t const*) mem; + return ua16->val; +} + +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void* mem, uint16_t value) +{ + tu_unaligned_uint16_t* ua16 = (tu_unaligned_uint16_t*) mem; + ua16->val = value; +} + +#elif TUP_MCU_STRICT_ALIGN + +// MCU such as LPC_IP3511 Highspeed cannot access unaligned memory on USB_RAM although it is ARM M4. +// We have to manually pick up bytes since tu_unaligned_uint32_t will still generate unaligned code +// NOTE: volatile cast to memory to prevent compiler to optimize and generate unaligned code +// TODO Big Endian may need minor changes +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32(const void* mem) +{ + volatile uint8_t const* buf8 = (uint8_t const*) mem; + return tu_u32(buf8[3], buf8[2], buf8[1], buf8[0]); +} + +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32(void* mem, uint32_t value) +{ + volatile uint8_t* buf8 = (uint8_t*) mem; + buf8[0] = tu_u32_byte0(value); + buf8[1] = tu_u32_byte1(value); + buf8[2] = tu_u32_byte2(value); + buf8[3] = tu_u32_byte3(value); +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16(const void* mem) +{ + volatile uint8_t const* buf8 = (uint8_t const*) mem; + return tu_u16(buf8[1], buf8[0]); +} + +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void* mem, uint16_t value) +{ + volatile uint8_t* buf8 = (uint8_t*) mem; + buf8[0] = tu_u16_low(value); + buf8[1] = tu_u16_high(value); +} + + +#else + +// MCU that could access unaligned memory natively +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32 (const void* mem) { return *((uint32_t const *) mem); } +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16 (const void* mem) { return *((uint16_t const *) mem); } + +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32 (void* mem, uint32_t value ) { *((uint32_t*) mem) = value; } +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16 (void* mem, uint16_t value ) { *((uint16_t*) mem) = value; } + +#endif + +// To be removed +//------------- Binary constant -------------// +#if defined(__GNUC__) && !defined(__CC_ARM) + +#define TU_BIN8(x) ((uint8_t) (0b##x)) +#define TU_BIN16(b1, b2) ((uint16_t) (0b##b1##b2)) +#define TU_BIN32(b1, b2, b3, b4) ((uint32_t) (0b##b1##b2##b3##b4)) + +#else + +// internal macro of B8, B16, B32 +#define _B8__(x) (((x&0x0000000FUL)?1:0) \ + +((x&0x000000F0UL)?2:0) \ + +((x&0x00000F00UL)?4:0) \ + +((x&0x0000F000UL)?8:0) \ + +((x&0x000F0000UL)?16:0) \ + +((x&0x00F00000UL)?32:0) \ + +((x&0x0F000000UL)?64:0) \ + +((x&0xF0000000UL)?128:0)) + +#define TU_BIN8(d) ((uint8_t) _B8__(0x##d##UL)) +#define TU_BIN16(dmsb,dlsb) (((uint16_t)TU_BIN8(dmsb)<<8) + TU_BIN8(dlsb)) +#define TU_BIN32(dmsb,db2,db3,dlsb) \ + (((uint32_t)TU_BIN8(dmsb)<<24) \ + + ((uint32_t)TU_BIN8(db2)<<16) \ + + ((uint32_t)TU_BIN8(db3)<<8) \ + + TU_BIN8(dlsb)) +#endif + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_COMMON_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_compiler.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_compiler.h new file mode 100644 index 00000000..2c30daf6 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_compiler.h @@ -0,0 +1,274 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup Group_Common + * \defgroup Group_Compiler Compiler + * \brief Group_Compiler brief + * @{ */ + +#ifndef _TUSB_COMPILER_H_ +#define _TUSB_COMPILER_H_ + +#define TU_TOKEN(x) x +#define TU_STRING(x) #x ///< stringify without expand +#define TU_XSTRING(x) TU_STRING(x) ///< expand then stringify + +#define TU_STRCAT(a, b) a##b ///< concat without expand +#define TU_STRCAT3(a, b, c) a##b##c ///< concat without expand + +#define TU_XSTRCAT(a, b) TU_STRCAT(a, b) ///< expand then concat +#define TU_XSTRCAT3(a, b, c) TU_STRCAT3(a, b, c) ///< expand then concat 3 tokens + +#define TU_INCLUDE_PATH(_dir,_file) TU_XSTRING( TU_TOKEN(_dir)TU_TOKEN(_file) ) + +#if defined __COUNTER__ && __COUNTER__ != __COUNTER__ + #define _TU_COUNTER_ __COUNTER__ +#else + #define _TU_COUNTER_ __LINE__ +#endif + +// Compile-time Assert +#if defined (__cplusplus) && __cplusplus >= 201103L + #define TU_VERIFY_STATIC static_assert +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define TU_VERIFY_STATIC _Static_assert +#elif defined(__CCRX__) + #define TU_VERIFY_STATIC(const_expr, _mess) typedef char TU_XSTRCAT(Line, __LINE__)[(const_expr) ? 1 : 0]; +#else + #define TU_VERIFY_STATIC(const_expr, _mess) enum { TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1/(!!(const_expr)) } +#endif + +// for declaration of reserved field, make use of _TU_COUNTER_ +#define TU_RESERVED TU_XSTRCAT(reserved, _TU_COUNTER_) + +#define TU_LITTLE_ENDIAN (0x12u) +#define TU_BIG_ENDIAN (0x21u) + +/*------------------------------------------------------------------*/ +/* Count number of arguments of __VA_ARGS__ + * - reference https://stackoverflow.com/questions/2124339/c-preprocessor-va-args-number-of-arguments + * - _GET_NTH_ARG() takes args >= N (64) but only expand to Nth one (64th) + * - _RSEQ_N() is reverse sequential to N to add padding to have + * Nth position is the same as the number of arguments + * - ##__VA_ARGS__ is used to deal with 0 paramerter (swallows comma) + *------------------------------------------------------------------*/ +#if !defined(__CCRX__) +#define TU_ARGS_NUM(...) _TU_NARG(_0, ##__VA_ARGS__,_RSEQ_N()) +#else +#define TU_ARGS_NUM(...) _TU_NARG(_0, __VA_ARGS__,_RSEQ_N()) +#endif + +#define _TU_NARG(...) _GET_NTH_ARG(__VA_ARGS__) +#define _GET_NTH_ARG( \ + _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ + _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ + _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ + _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ + _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ + _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ + _61,_62,_63,N,...) N +#define _RSEQ_N() \ + 62,61,60, \ + 59,58,57,56,55,54,53,52,51,50, \ + 49,48,47,46,45,44,43,42,41,40, \ + 39,38,37,36,35,34,33,32,31,30, \ + 29,28,27,26,25,24,23,22,21,20, \ + 19,18,17,16,15,14,13,12,11,10, \ + 9,8,7,6,5,4,3,2,1,0 + +// Apply an macro X to each of the arguments with an separated of choice +#define TU_ARGS_APPLY(_X, _s, ...) TU_XSTRCAT(_TU_ARGS_APPLY_, TU_ARGS_NUM(__VA_ARGS__))(_X, _s, __VA_ARGS__) + +#define _TU_ARGS_APPLY_1(_X, _s, _a1) _X(_a1) +#define _TU_ARGS_APPLY_2(_X, _s, _a1, _a2) _X(_a1) _s _X(_a2) +#define _TU_ARGS_APPLY_3(_X, _s, _a1, _a2, _a3) _X(_a1) _s _TU_ARGS_APPLY_2(_X, _s, _a2, _a3) +#define _TU_ARGS_APPLY_4(_X, _s, _a1, _a2, _a3, _a4) _X(_a1) _s _TU_ARGS_APPLY_3(_X, _s, _a2, _a3, _a4) +#define _TU_ARGS_APPLY_5(_X, _s, _a1, _a2, _a3, _a4, _a5) _X(_a1) _s _TU_ARGS_APPLY_4(_X, _s, _a2, _a3, _a4, _a5) +#define _TU_ARGS_APPLY_6(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6) _X(_a1) _s _TU_ARGS_APPLY_5(_X, _s, _a2, _a3, _a4, _a5, _a6) +#define _TU_ARGS_APPLY_7(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6, _a7) _X(_a1) _s _TU_ARGS_APPLY_6(_X, _s, _a2, _a3, _a4, _a5, _a6, _a7) +#define _TU_ARGS_APPLY_8(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6, _a7, _a8) _X(_a1) _s _TU_ARGS_APPLY_7(_X, _s, _a2, _a3, _a4, _a5, _a6, _a7, _a8) + +//--------------------------------------------------------------------+ +// Compiler porting with Attribute and Endian +//--------------------------------------------------------------------+ + +// TODO refactor since __attribute__ is supported across many compiler +#if defined(__GNUC__) + #define TU_ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes))) + #define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name))) + #define TU_ATTR_PACKED __attribute__ ((packed)) + #define TU_ATTR_WEAK __attribute__ ((weak)) + #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) + #define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used + #define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused + #define TU_ATTR_USED __attribute__ ((used)) // Function/Variable is meant to be used + + #define TU_ATTR_PACKED_BEGIN + #define TU_ATTR_PACKED_END + #define TU_ATTR_BIT_FIELD_ORDER_BEGIN + #define TU_ATTR_BIT_FIELD_ORDER_END + + #if __has_attribute(__fallthrough__) + #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough)) + #else + #define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */ + #endif + + // Endian conversion use well-known host to network (big endian) naming + #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + #define TU_BYTE_ORDER TU_LITTLE_ENDIAN + #else + #define TU_BYTE_ORDER TU_BIG_ENDIAN + #endif + + #define TU_BSWAP16(u16) (__builtin_bswap16(u16)) + #define TU_BSWAP32(u32) (__builtin_bswap32(u32)) + + #ifndef __ARMCC_VERSION + // List of obsolete callback function that is renamed and should not be defined. + // Put it here since only gcc support this pragma + #pragma GCC poison tud_vendor_control_request_cb + #endif + +#elif defined(__TI_COMPILER_VERSION__) + #define TU_ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes))) + #define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name))) + #define TU_ATTR_PACKED __attribute__ ((packed)) + #define TU_ATTR_WEAK __attribute__ ((weak)) + #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) + #define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used + #define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused + #define TU_ATTR_USED __attribute__ ((used)) + #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough)) + + #define TU_ATTR_PACKED_BEGIN + #define TU_ATTR_PACKED_END + #define TU_ATTR_BIT_FIELD_ORDER_BEGIN + #define TU_ATTR_BIT_FIELD_ORDER_END + + // __BYTE_ORDER is defined in the TI ARM compiler, but not MSP430 (which is little endian) + #if ((__BYTE_ORDER__) == (__ORDER_LITTLE_ENDIAN__)) || defined(__MSP430__) + #define TU_BYTE_ORDER TU_LITTLE_ENDIAN + #else + #define TU_BYTE_ORDER TU_BIG_ENDIAN + #endif + + #define TU_BSWAP16(u16) (__builtin_bswap16(u16)) + #define TU_BSWAP32(u32) (__builtin_bswap32(u32)) + +#elif defined(__ICCARM__) + #include + #define TU_ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes))) + #define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name))) + #define TU_ATTR_PACKED __attribute__ ((packed)) + #define TU_ATTR_WEAK __attribute__ ((weak)) + #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) + #define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used + #define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused + #define TU_ATTR_USED __attribute__ ((used)) // Function/Variable is meant to be used + #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough)) + + #define TU_ATTR_PACKED_BEGIN + #define TU_ATTR_PACKED_END + #define TU_ATTR_BIT_FIELD_ORDER_BEGIN + #define TU_ATTR_BIT_FIELD_ORDER_END + + // Endian conversion use well-known host to network (big endian) naming + #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + #define TU_BYTE_ORDER TU_LITTLE_ENDIAN + #else + #define TU_BYTE_ORDER TU_BIG_ENDIAN + #endif + + #define TU_BSWAP16(u16) (__iar_builtin_REV16(u16)) + #define TU_BSWAP32(u32) (__iar_builtin_REV(u32)) + +#elif defined(__CCRX__) + #define TU_ATTR_ALIGNED(Bytes) + #define TU_ATTR_SECTION(sec_name) + #define TU_ATTR_PACKED + #define TU_ATTR_WEAK + #define TU_ATTR_ALWAYS_INLINE + #define TU_ATTR_DEPRECATED(mess) + #define TU_ATTR_UNUSED + #define TU_ATTR_USED + #define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */ + + #define TU_ATTR_PACKED_BEGIN _Pragma("pack") + #define TU_ATTR_PACKED_END _Pragma("packoption") + #define TU_ATTR_BIT_FIELD_ORDER_BEGIN _Pragma("bit_order right") + #define TU_ATTR_BIT_FIELD_ORDER_END _Pragma("bit_order") + + // Endian conversion use well-known host to network (big endian) naming + #if defined(__LIT) + #define TU_BYTE_ORDER TU_LITTLE_ENDIAN + #else + #define TU_BYTE_ORDER TU_BIG_ENDIAN + #endif + + #define TU_BSWAP16(u16) ((unsigned short)_builtin_revw((unsigned long)u16)) + #define TU_BSWAP32(u32) (_builtin_revl(u32)) + +#else + #error "Compiler attribute porting is required" +#endif + + +#if (TU_BYTE_ORDER == TU_LITTLE_ENDIAN) + + #define tu_htons(u16) (TU_BSWAP16(u16)) + #define tu_ntohs(u16) (TU_BSWAP16(u16)) + + #define tu_htonl(u32) (TU_BSWAP32(u32)) + #define tu_ntohl(u32) (TU_BSWAP32(u32)) + + #define tu_htole16(u16) (u16) + #define tu_le16toh(u16) (u16) + + #define tu_htole32(u32) (u32) + #define tu_le32toh(u32) (u32) + +#elif (TU_BYTE_ORDER == TU_BIG_ENDIAN) + + #define tu_htons(u16) (u16) + #define tu_ntohs(u16) (u16) + + #define tu_htonl(u32) (u32) + #define tu_ntohl(u32) (u32) + + #define tu_htole16(u16) (TU_BSWAP16(u16)) + #define tu_le16toh(u16) (TU_BSWAP16(u16)) + + #define tu_htole32(u32) (TU_BSWAP32(u32)) + #define tu_le32toh(u32) (TU_BSWAP32(u32)) + +#else + #error Byte order is undefined +#endif + +#endif /* _TUSB_COMPILER_H_ */ + +/// @} diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_debug.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_debug.h new file mode 100644 index 00000000..ac5bee6e --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_debug.h @@ -0,0 +1,178 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2022, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_DEBUG_H_ +#define _TUSB_DEBUG_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Debug +//--------------------------------------------------------------------+ + +// CFG_TUSB_DEBUG for debugging +// 0 : no debug +// 1 : print error +// 2 : print warning +// 3 : print info +#if CFG_TUSB_DEBUG + +// Enum to String for debugging purposes +#if CFG_TUSB_DEBUG >= 2 +extern char const* const tu_str_speed[]; +extern char const* const tu_str_std_request[]; +#endif + +void tu_print_mem(void const *buf, uint32_t count, uint8_t indent); + +#ifdef CFG_TUSB_DEBUG_PRINTF + extern int CFG_TUSB_DEBUG_PRINTF(const char *format, ...); + #define tu_printf CFG_TUSB_DEBUG_PRINTF +#else + #define tu_printf printf +#endif + +static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) +{ + for(uint32_t i=0; i= 2 + #define TU_LOG2 TU_LOG1 + #define TU_LOG2_MEM TU_LOG1_MEM + #define TU_LOG2_ARR TU_LOG1_ARR + #define TU_LOG2_VAR TU_LOG1_VAR + #define TU_LOG2_INT TU_LOG1_INT + #define TU_LOG2_HEX TU_LOG1_HEX +#endif + +// Log Level 3: Info +#if CFG_TUSB_DEBUG >= 3 + #define TU_LOG3 TU_LOG1 + #define TU_LOG3_MEM TU_LOG1_MEM + #define TU_LOG3_ARR TU_LOG1_ARR + #define TU_LOG3_VAR TU_LOG1_VAR + #define TU_LOG3_INT TU_LOG1_INT + #define TU_LOG3_HEX TU_LOG1_HEX +#endif + +typedef struct +{ + uint32_t key; + const char* data; +} tu_lookup_entry_t; + +typedef struct +{ + uint16_t count; + tu_lookup_entry_t const* items; +} tu_lookup_table_t; + +static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) +{ + static char not_found[11]; + + for(uint16_t i=0; icount; i++) + { + if (p_table->items[i].key == key) return p_table->items[i].data; + } + + // not found return the key value in hex + snprintf(not_found, sizeof(not_found), "0x%08lX", (unsigned long) key); + + return not_found; +} + +#endif // CFG_TUSB_DEBUG + +#ifndef TU_LOG + #define TU_LOG(n, ...) + #define TU_LOG_MEM(n, ...) + #define TU_LOG_VAR(n, ...) + #define TU_LOG_INT(n, ...) + #define TU_LOG_HEX(n, ...) + #define TU_LOG_LOCATION() + #define TU_LOG_FAILED() +#endif + +// TODO replace all TU_LOGn with TU_LOG(n) + +#define TU_LOG0(...) +#define TU_LOG0_MEM(...) +#define TU_LOG0_VAR(...) +#define TU_LOG0_INT(...) +#define TU_LOG0_HEX(...) + +#ifndef TU_LOG1 + #define TU_LOG1(...) + #define TU_LOG1_MEM(...) + #define TU_LOG1_VAR(...) + #define TU_LOG1_INT(...) + #define TU_LOG1_HEX(...) +#endif + +#ifndef TU_LOG2 + #define TU_LOG2(...) + #define TU_LOG2_MEM(...) + #define TU_LOG2_VAR(...) + #define TU_LOG2_INT(...) + #define TU_LOG2_HEX(...) +#endif + +#ifndef TU_LOG3 + #define TU_LOG3(...) + #define TU_LOG3_MEM(...) + #define TU_LOG3_VAR(...) + #define TU_LOG3_INT(...) + #define TU_LOG3_HEX(...) +#endif + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_DEBUG_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.c b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.c new file mode 100644 index 00000000..895b9208 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.c @@ -0,0 +1,1007 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2020 Reinhard Panhuber - rework to unmasked pointers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "osal/osal.h" +#include "tusb_fifo.h" + +// Supress IAR warning +// Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement +#if defined(__ICCARM__) +#pragma diag_suppress = Pa082 +#endif + +// implement mutex lock and unlock +#if CFG_FIFO_MUTEX + +static inline void _ff_lock(tu_fifo_mutex_t mutex) +{ + if (mutex) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); +} + +static inline void _ff_unlock(tu_fifo_mutex_t mutex) +{ + if (mutex) osal_mutex_unlock(mutex); +} + +#else + +#define _ff_lock(_mutex) +#define _ff_unlock(_mutex) + +#endif + +/** \enum tu_fifo_copy_mode_t + * \brief Write modes intended to allow special read and write functions to be able to + * copy data to and from USB hardware FIFOs as needed for e.g. STM32s and others + */ +typedef enum +{ + TU_FIFO_COPY_INC, ///< Copy from/to an increasing source/destination address - default mode + TU_FIFO_COPY_CST_FULL_WORDS, ///< Copy from/to a constant source/destination address - required for e.g. STM32 to write into USB hardware FIFO +} tu_fifo_copy_mode_t; + +bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable) +{ + if (depth > 0x8000) return false; // Maximum depth is 2^15 items + + _ff_lock(f->mutex_wr); + _ff_lock(f->mutex_rd); + + f->buffer = (uint8_t*) buffer; + f->depth = depth; + f->item_size = item_size; + f->overwritable = overwritable; + + // Limit index space to 2*depth - this allows for a fast "modulo" calculation + // but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable + // only if overflow happens once (important for unsupervised DMA applications) + f->max_pointer_idx = (uint16_t) (2*depth - 1); + f->non_used_index_space = UINT16_MAX - f->max_pointer_idx; + + f->rd_idx = f->wr_idx = 0; + + _ff_unlock(f->mutex_wr); + _ff_unlock(f->mutex_rd); + + return true; +} + +// Static functions are intended to work on local variables +static inline uint16_t _ff_mod(uint16_t idx, uint16_t depth) +{ + while ( idx >= depth) idx -= depth; + return idx; +} + +// Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address +// Code adapted from dcd_synopsis.c +// TODO generalize with configurable 1 byte or 4 byte each read +static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t len) +{ + volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf; + + // Reading full available 32 bit words from const app address + uint16_t full_words = len >> 2; + while(full_words--) + { + tu_unaligned_write32(ff_buf, *rx_fifo); + ff_buf += 4; + } + + // Read the remaining 1-3 bytes from const app address + uint8_t const bytes_rem = len & 0x03; + if ( bytes_rem ) + { + uint32_t tmp32 = *rx_fifo; + memcpy(ff_buf, &tmp32, bytes_rem); + } +} + +// Intended to be used to write to hardware USB FIFO in e.g. STM32 +// where all data is written to a constant address in full word copies +static void _ff_pull_const_addr(void * app_buf, const uint8_t * ff_buf, uint16_t len) +{ + volatile uint32_t * tx_fifo = (volatile uint32_t *) app_buf; + + // Pushing full available 32 bit words to const app address + uint16_t full_words = len >> 2; + while(full_words--) + { + *tx_fifo = tu_unaligned_read32(ff_buf); + ff_buf += 4; + } + + // Write the remaining 1-3 bytes into const app address + uint8_t const bytes_rem = len & 0x03; + if ( bytes_rem ) + { + uint32_t tmp32 = 0; + memcpy(&tmp32, ff_buf, bytes_rem); + + *tx_fifo = tmp32; + } +} + +// send one item to FIFO WITHOUT updating write pointer +static inline void _ff_push(tu_fifo_t* f, void const * app_buf, uint16_t rel) +{ + memcpy(f->buffer + (rel * f->item_size), app_buf, f->item_size); +} + +// send n items to FIFO WITHOUT updating write pointer +static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode) +{ + uint16_t const nLin = f->depth - rel; + uint16_t const nWrap = n - nLin; + + uint16_t nLin_bytes = nLin * f->item_size; + uint16_t nWrap_bytes = nWrap * f->item_size; + + // current buffer of fifo + uint8_t* ff_buf = f->buffer + (rel * f->item_size); + + switch (copy_mode) + { + case TU_FIFO_COPY_INC: + if(n <= nLin) + { + // Linear only + memcpy(ff_buf, app_buf, n*f->item_size); + } + else + { + // Wrap around + + // Write data to linear part of buffer + memcpy(ff_buf, app_buf, nLin_bytes); + + // Write data wrapped around + memcpy(f->buffer, ((uint8_t const*) app_buf) + nLin_bytes, nWrap_bytes); + } + break; + + case TU_FIFO_COPY_CST_FULL_WORDS: + // Intended for hardware buffers from which it can be read word by word only + if(n <= nLin) + { + // Linear only + _ff_push_const_addr(ff_buf, app_buf, n*f->item_size); + } + else + { + // Wrap around case + + // Write full words to linear part of buffer + uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC; + _ff_push_const_addr(ff_buf, app_buf, nLin_4n_bytes); + ff_buf += nLin_4n_bytes; + + // There could be odd 1-3 bytes before the wrap-around boundary + volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf; + uint8_t rem = nLin_bytes & 0x03; + if (rem > 0) + { + uint8_t remrem = (uint8_t) tu_min16(nWrap_bytes, 4-rem); + nWrap_bytes -= remrem; + + uint32_t tmp32 = *rx_fifo; + uint8_t * src_u8 = ((uint8_t *) &tmp32); + + // Write 1-3 bytes before wrapped boundary + while(rem--) *ff_buf++ = *src_u8++; + + // Read more bytes to beginning to complete a word + ff_buf = f->buffer; + while(remrem--) *ff_buf++ = *src_u8++; + } + else + { + ff_buf = f->buffer; // wrap around to beginning + } + + // Write data wrapped part + if (nWrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, nWrap_bytes); + } + break; + } +} + +// get one item from FIFO WITHOUT updating read pointer +static inline void _ff_pull(tu_fifo_t* f, void * app_buf, uint16_t rel) +{ + memcpy(app_buf, f->buffer + (rel * f->item_size), f->item_size); +} + +// get n items from FIFO WITHOUT updating read pointer +static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode) +{ + uint16_t const nLin = f->depth - rel; + uint16_t const nWrap = n - nLin; // only used if wrapped + + uint16_t nLin_bytes = nLin * f->item_size; + uint16_t nWrap_bytes = nWrap * f->item_size; + + // current buffer of fifo + uint8_t* ff_buf = f->buffer + (rel * f->item_size); + + switch (copy_mode) + { + case TU_FIFO_COPY_INC: + if ( n <= nLin ) + { + // Linear only + memcpy(app_buf, ff_buf, n*f->item_size); + } + else + { + // Wrap around + + // Read data from linear part of buffer + memcpy(app_buf, ff_buf, nLin_bytes); + + // Read data wrapped part + memcpy((uint8_t*) app_buf + nLin_bytes, f->buffer, nWrap_bytes); + } + break; + + case TU_FIFO_COPY_CST_FULL_WORDS: + if ( n <= nLin ) + { + // Linear only + _ff_pull_const_addr(app_buf, ff_buf, n*f->item_size); + } + else + { + // Wrap around case + + // Read full words from linear part of buffer + uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC; + _ff_pull_const_addr(app_buf, ff_buf, nLin_4n_bytes); + ff_buf += nLin_4n_bytes; + + // There could be odd 1-3 bytes before the wrap-around boundary + volatile uint32_t * tx_fifo = (volatile uint32_t *) app_buf; + uint8_t rem = nLin_bytes & 0x03; + if (rem > 0) + { + uint8_t remrem = (uint8_t) tu_min16(nWrap_bytes, 4-rem); + nWrap_bytes -= remrem; + + uint32_t tmp32=0; + uint8_t * dst_u8 = (uint8_t *)&tmp32; + + // Read 1-3 bytes before wrapped boundary + while(rem--) *dst_u8++ = *ff_buf++; + + // Read more bytes from beginning to complete a word + ff_buf = f->buffer; + while(remrem--) *dst_u8++ = *ff_buf++; + + *tx_fifo = tmp32; + } + else + { + ff_buf = f->buffer; // wrap around to beginning + } + + // Read data wrapped part + if (nWrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, nWrap_bytes); + } + break; + + default: break; + } +} + +// Advance an absolute pointer +static uint16_t advance_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) +{ + // We limit the index space of p such that a correct wrap around happens + // Check for a wrap around or if we are in unused index space - This has to be checked first!! + // We are exploiting the wrap around to the correct index + if ((p > (uint16_t)(p + offset)) || ((uint16_t)(p + offset) > f->max_pointer_idx)) + { + p = (uint16_t) ((p + offset) + f->non_used_index_space); + } + else + { + p += offset; + } + return p; +} + +// Backward an absolute pointer +static uint16_t backward_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) +{ + // We limit the index space of p such that a correct wrap around happens + // Check for a wrap around or if we are in unused index space - This has to be checked first!! + // We are exploiting the wrap around to the correct index + if ((p < (uint16_t)(p - offset)) || ((uint16_t)(p - offset) > f->max_pointer_idx)) + { + p = (uint16_t) ((p - offset) - f->non_used_index_space); + } + else + { + p -= offset; + } + return p; +} + +// get relative from absolute pointer +static uint16_t get_relative_pointer(tu_fifo_t* f, uint16_t p) +{ + return _ff_mod(p, f->depth); +} + +// Works on local copies of w and r - return only the difference and as such can be used to determine an overflow +static inline uint16_t _tu_fifo_count(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) +{ + uint16_t cnt = wAbs-rAbs; + + // In case we have non-power of two depth we need a further modification + if (rAbs > wAbs) cnt -= f->non_used_index_space; + + return cnt; +} + +// Works on local copies of w and r +static inline bool _tu_fifo_empty(uint16_t wAbs, uint16_t rAbs) +{ + return wAbs == rAbs; +} + +// Works on local copies of w and r +static inline bool _tu_fifo_full(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) +{ + return (_tu_fifo_count(f, wAbs, rAbs) == f->depth); +} + +// Works on local copies of w and r +// BE AWARE - THIS FUNCTION MIGHT NOT GIVE A CORRECT ANSWERE IN CASE WRITE POINTER "OVERFLOWS" +// Only one overflow is allowed for this function to work e.g. if depth = 100, you must not +// write more than 2*depth-1 items in one rush without updating write pointer. Otherwise +// write pointer wraps and you pointer states are messed up. This can only happen if you +// use DMAs, write functions do not allow such an error. +static inline bool _tu_fifo_overflowed(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) +{ + return (_tu_fifo_count(f, wAbs, rAbs) > f->depth); +} + +// Works on local copies of w +// For more details see _tu_fifo_overflow()! +static inline void _tu_fifo_correct_read_pointer(tu_fifo_t* f, uint16_t wAbs) +{ + f->rd_idx = backward_pointer(f, wAbs, f->depth); +} + +// Works on local copies of w and r +// Must be protected by mutexes since in case of an overflow read pointer gets modified +static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wAbs, uint16_t rAbs) +{ + uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs); + + // Check overflow and correct if required + if (cnt > f->depth) + { + _tu_fifo_correct_read_pointer(f, wAbs); + cnt = f->depth; + } + + // Skip beginning of buffer + if (cnt == 0) return false; + + uint16_t rRel = get_relative_pointer(f, rAbs); + + // Peek data + _ff_pull(f, p_buffer, rRel); + + return true; +} + +// Works on local copies of w and r +// Must be protected by mutexes since in case of an overflow read pointer gets modified +static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t wAbs, uint16_t rAbs, tu_fifo_copy_mode_t copy_mode) +{ + uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs); + + // Check overflow and correct if required + if (cnt > f->depth) + { + _tu_fifo_correct_read_pointer(f, wAbs); + rAbs = f->rd_idx; + cnt = f->depth; + } + + // Skip beginning of buffer + if (cnt == 0) return 0; + + // Check if we can read something at and after offset - if too less is available we read what remains + if (cnt < n) n = cnt; + + uint16_t rRel = get_relative_pointer(f, rAbs); + + // Peek data + _ff_pull_n(f, p_buffer, n, rRel, copy_mode); + + return n; +} + +// Works on local copies of w and r +static inline uint16_t _tu_fifo_remaining(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) +{ + return f->depth - _tu_fifo_count(f, wAbs, rAbs); +} + +static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu_fifo_copy_mode_t copy_mode) +{ + if ( n == 0 ) return 0; + + _ff_lock(f->mutex_wr); + + uint16_t w = f->wr_idx, r = f->rd_idx; + uint8_t const* buf8 = (uint8_t const*) data; + + if (!f->overwritable) + { + // Not overwritable limit up to full + n = tu_min16(n, _tu_fifo_remaining(f, w, r)); + } + else if (n >= f->depth) + { + // Only copy last part + buf8 = buf8 + (n - f->depth) * f->item_size; + n = f->depth; + + // We start writing at the read pointer's position since we fill the complete + // buffer and we do not want to modify the read pointer within a write function! + // This would end up in a race condition with read functions! + w = r; + } + + uint16_t wRel = get_relative_pointer(f, w); + + // Write data + _ff_push_n(f, buf8, n, wRel, copy_mode); + + // Advance pointer + f->wr_idx = advance_pointer(f, w, n); + + _ff_unlock(f->mutex_wr); + + return n; +} + +static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo_copy_mode_t copy_mode) +{ + _ff_lock(f->mutex_rd); + + // Peek the data + // f->rd_idx might get modified in case of an overflow so we can not use a local variable + n = _tu_fifo_peek_n(f, buffer, n, f->wr_idx, f->rd_idx, copy_mode); + + // Advance read pointer + f->rd_idx = advance_pointer(f, f->rd_idx, n); + + _ff_unlock(f->mutex_rd); + return n; +} + +/******************************************************************************/ +/*! + @brief Get number of items in FIFO. + + As this function only reads the read and write pointers once, this function is + reentrant and thus thread and ISR save without any mutexes. In case an + overflow occurred, this function return f.depth at maximum. Overflows are + checked and corrected for in the read functions! + + @param[in] f + Pointer to the FIFO buffer to manipulate + + @returns Number of items in FIFO + */ +/******************************************************************************/ +uint16_t tu_fifo_count(tu_fifo_t* f) +{ + return tu_min16(_tu_fifo_count(f, f->wr_idx, f->rd_idx), f->depth); +} + +/******************************************************************************/ +/*! + @brief Check if FIFO is empty. + + As this function only reads the read and write pointers once, this function is + reentrant and thus thread and ISR save without any mutexes. + + @param[in] f + Pointer to the FIFO buffer to manipulate + + @returns Number of items in FIFO + */ +/******************************************************************************/ +bool tu_fifo_empty(tu_fifo_t* f) +{ + return _tu_fifo_empty(f->wr_idx, f->rd_idx); +} + +/******************************************************************************/ +/*! + @brief Check if FIFO is full. + + As this function only reads the read and write pointers once, this function is + reentrant and thus thread and ISR save without any mutexes. + + @param[in] f + Pointer to the FIFO buffer to manipulate + + @returns Number of items in FIFO + */ +/******************************************************************************/ +bool tu_fifo_full(tu_fifo_t* f) +{ + return _tu_fifo_full(f, f->wr_idx, f->rd_idx); +} + +/******************************************************************************/ +/*! + @brief Get remaining space in FIFO. + + As this function only reads the read and write pointers once, this function is + reentrant and thus thread and ISR save without any mutexes. + + @param[in] f + Pointer to the FIFO buffer to manipulate + + @returns Number of items in FIFO + */ +/******************************************************************************/ +uint16_t tu_fifo_remaining(tu_fifo_t* f) +{ + return _tu_fifo_remaining(f, f->wr_idx, f->rd_idx); +} + +/******************************************************************************/ +/*! + @brief Check if overflow happened. + + BE AWARE - THIS FUNCTION MIGHT NOT GIVE A CORRECT ANSWERE IN CASE WRITE POINTER "OVERFLOWS" + Only one overflow is allowed for this function to work e.g. if depth = 100, you must not + write more than 2*depth-1 items in one rush without updating write pointer. Otherwise + write pointer wraps and your pointer states are messed up. This can only happen if you + use DMAs, write functions do not allow such an error. Avoid such nasty things! + + All reading functions (read, peek) check for overflows and correct read pointer on their own such + that latest items are read. + If required (e.g. for DMA use) you can also correct the read pointer by + tu_fifo_correct_read_pointer(). + + @param[in] f + Pointer to the FIFO buffer to manipulate + + @returns True if overflow happened + */ +/******************************************************************************/ +bool tu_fifo_overflowed(tu_fifo_t* f) +{ + return _tu_fifo_overflowed(f, f->wr_idx, f->rd_idx); +} + +// Only use in case tu_fifo_overflow() returned true! +void tu_fifo_correct_read_pointer(tu_fifo_t* f) +{ + _ff_lock(f->mutex_rd); + _tu_fifo_correct_read_pointer(f, f->wr_idx); + _ff_unlock(f->mutex_rd); +} + +/******************************************************************************/ +/*! + @brief Read one element out of the buffer. + + This function will return the element located at the array index of the + read pointer, and then increment the read pointer index. + This function checks for an overflow and corrects read pointer if required. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] buffer + Pointer to the place holder for data read from the buffer + + @returns TRUE if the queue is not empty + */ +/******************************************************************************/ +bool tu_fifo_read(tu_fifo_t* f, void * buffer) +{ + _ff_lock(f->mutex_rd); + + // Peek the data + // f->rd_idx might get modified in case of an overflow so we can not use a local variable + bool ret = _tu_fifo_peek(f, buffer, f->wr_idx, f->rd_idx); + + // Advance pointer + f->rd_idx = advance_pointer(f, f->rd_idx, ret); + + _ff_unlock(f->mutex_rd); + return ret; +} + +/******************************************************************************/ +/*! + @brief This function will read n elements from the array index specified by + the read pointer and increment the read index. + This function checks for an overflow and corrects read pointer if required. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] buffer + The pointer to data location + @param[in] n + Number of element that buffer can afford + + @returns number of items read from the FIFO + */ +/******************************************************************************/ +uint16_t tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n) +{ + return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_INC); +} + +uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t* f, void * buffer, uint16_t n) +{ + return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_CST_FULL_WORDS); +} + +/******************************************************************************/ +/*! + @brief Read one item without removing it from the FIFO. + This function checks for an overflow and corrects read pointer if required. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] offset + Position to read from in the FIFO buffer with respect to read pointer + @param[in] p_buffer + Pointer to the place holder for data read from the buffer + + @returns TRUE if the queue is not empty + */ +/******************************************************************************/ +bool tu_fifo_peek(tu_fifo_t* f, void * p_buffer) +{ + _ff_lock(f->mutex_rd); + bool ret = _tu_fifo_peek(f, p_buffer, f->wr_idx, f->rd_idx); + _ff_unlock(f->mutex_rd); + return ret; +} + +/******************************************************************************/ +/*! + @brief Read n items without removing it from the FIFO + This function checks for an overflow and corrects read pointer if required. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] p_buffer + Pointer to the place holder for data read from the buffer + @param[in] n + Number of items to peek + + @returns Number of bytes written to p_buffer + */ +/******************************************************************************/ +uint16_t tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n) +{ + _ff_lock(f->mutex_rd); + uint16_t ret = _tu_fifo_peek_n(f, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_COPY_INC); + _ff_unlock(f->mutex_rd); + return ret; +} + +/******************************************************************************/ +/*! + @brief Write one element into the buffer. + + This function will write one element into the array index specified by + the write pointer and increment the write index. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] data + The byte to add to the FIFO + + @returns TRUE if the data was written to the FIFO (overwrittable + FIFO will always return TRUE) + */ +/******************************************************************************/ +bool tu_fifo_write(tu_fifo_t* f, const void * data) +{ + _ff_lock(f->mutex_wr); + + bool ret; + uint16_t const w = f->wr_idx; + + if ( _tu_fifo_full(f, w, f->rd_idx) && !f->overwritable ) + { + ret = false; + }else + { + uint16_t wRel = get_relative_pointer(f, w); + + // Write data + _ff_push(f, data, wRel); + + // Advance pointer + f->wr_idx = advance_pointer(f, w, 1); + + ret = true; + } + + _ff_unlock(f->mutex_wr); + + return ret; +} + +/******************************************************************************/ +/*! + @brief This function will write n elements into the array index specified by + the write pointer and increment the write index. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] data + The pointer to data to add to the FIFO + @param[in] count + Number of element + @return Number of written elements + */ +/******************************************************************************/ +uint16_t tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n) +{ + return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_INC); +} + +/******************************************************************************/ +/*! + @brief This function will write n elements into the array index specified by + the write pointer and increment the write index. The source address will + not be incremented which is useful for reading from registers. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] data + The pointer to data to add to the FIFO + @param[in] count + Number of element + @return Number of written elements + */ +/******************************************************************************/ +uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t* f, const void * data, uint16_t n) +{ + return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_CST_FULL_WORDS); +} + +/******************************************************************************/ +/*! + @brief Clear the fifo read and write pointers + + @param[in] f + Pointer to the FIFO buffer to manipulate + */ +/******************************************************************************/ +bool tu_fifo_clear(tu_fifo_t *f) +{ + _ff_lock(f->mutex_wr); + _ff_lock(f->mutex_rd); + + f->rd_idx = f->wr_idx = 0; + f->max_pointer_idx = (uint16_t) (2*f->depth-1); + f->non_used_index_space = UINT16_MAX - f->max_pointer_idx; + + _ff_unlock(f->mutex_wr); + _ff_unlock(f->mutex_rd); + return true; +} + +/******************************************************************************/ +/*! + @brief Change the fifo mode to overwritable or not overwritable + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] overwritable + Overwritable mode the fifo is set to + */ +/******************************************************************************/ +bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) +{ + _ff_lock(f->mutex_wr); + _ff_lock(f->mutex_rd); + + f->overwritable = overwritable; + + _ff_unlock(f->mutex_wr); + _ff_unlock(f->mutex_rd); + + return true; +} + +/******************************************************************************/ +/*! + @brief Advance write pointer - intended to be used in combination with DMA. + It is possible to fill the FIFO by use of a DMA in circular mode. Within + DMA ISRs you may update the write pointer to be able to read from the FIFO. + As long as the DMA is the only process writing into the FIFO this is safe + to use. + + USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE! + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] n + Number of items the write pointer moves forward + */ +/******************************************************************************/ +void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n) +{ + f->wr_idx = advance_pointer(f, f->wr_idx, n); +} + +/******************************************************************************/ +/*! + @brief Advance read pointer - intended to be used in combination with DMA. + It is possible to read from the FIFO by use of a DMA in linear mode. Within + DMA ISRs you may update the read pointer to be able to again write into the + FIFO. As long as the DMA is the only process reading from the FIFO this is + safe to use. + + USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE! + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] n + Number of items the read pointer moves forward + */ +/******************************************************************************/ +void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n) +{ + f->rd_idx = advance_pointer(f, f->rd_idx, n); +} + +/******************************************************************************/ +/*! + @brief Get read info + + Returns the length and pointer from which bytes can be read in a linear manner. + This is of major interest for DMA transmissions. If returned length is zero the + corresponding pointer is invalid. + The read pointer does NOT get advanced, use tu_fifo_advance_read_pointer() to + do so! + @param[in] f + Pointer to FIFO + @param[out] *info + Pointer to struct which holds the desired infos + */ +/******************************************************************************/ +void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) +{ + // Operate on temporary values in case they change in between + uint16_t w = f->wr_idx, r = f->rd_idx; + + uint16_t cnt = _tu_fifo_count(f, w, r); + + // Check overflow and correct if required - may happen in case a DMA wrote too fast + if (cnt > f->depth) + { + _ff_lock(f->mutex_rd); + _tu_fifo_correct_read_pointer(f, w); + _ff_unlock(f->mutex_rd); + r = f->rd_idx; + cnt = f->depth; + } + + // Check if fifo is empty + if (cnt == 0) + { + info->len_lin = 0; + info->len_wrap = 0; + info->ptr_lin = NULL; + info->ptr_wrap = NULL; + return; + } + + // Get relative pointers + w = get_relative_pointer(f, w); + r = get_relative_pointer(f, r); + + // Copy pointer to buffer to start reading from + info->ptr_lin = &f->buffer[r]; + + // Check if there is a wrap around necessary + if (w > r) { + // Non wrapping case + info->len_lin = cnt; + info->len_wrap = 0; + info->ptr_wrap = NULL; + } + else + { + info->len_lin = f->depth - r; // Also the case if FIFO was full + info->len_wrap = cnt - info->len_lin; + info->ptr_wrap = f->buffer; + } +} + +/******************************************************************************/ +/*! + @brief Get linear write info + + Returns the length and pointer to which bytes can be written into FIFO in a linear manner. + This is of major interest for DMA transmissions not using circular mode. If a returned length is zero the + corresponding pointer is invalid. The returned lengths summed up are the currently free space in the FIFO. + The write pointer does NOT get advanced, use tu_fifo_advance_write_pointer() to do so! + TAKE CARE TO NOT OVERFLOW THE BUFFER MORE THAN TWO TIMES THE FIFO DEPTH - IT CAN NOT RECOVERE OTHERWISE! + @param[in] f + Pointer to FIFO + @param[out] *info + Pointer to struct which holds the desired infos + */ +/******************************************************************************/ +void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) +{ + uint16_t w = f->wr_idx, r = f->rd_idx; + uint16_t free = _tu_fifo_remaining(f, w, r); + + if (free == 0) + { + info->len_lin = 0; + info->len_wrap = 0; + info->ptr_lin = NULL; + info->ptr_wrap = NULL; + return; + } + + // Get relative pointers + w = get_relative_pointer(f, w); + r = get_relative_pointer(f, r); + + // Copy pointer to buffer to start writing to + info->ptr_lin = &f->buffer[w]; + + if (w < r) + { + // Non wrapping case + info->len_lin = r-w; + info->len_wrap = 0; + info->ptr_wrap = NULL; + } + else + { + info->len_lin = f->depth - w; + info->len_wrap = free - info->len_lin; // Remaining length - n already was limited to free or FIFO depth + info->ptr_wrap = f->buffer; // Always start of buffer + } +} diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.h new file mode 100644 index 00000000..18db289a --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.h @@ -0,0 +1,151 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2020 Reinhard Panhuber - rework to unmasked pointers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_FIFO_H_ +#define _TUSB_FIFO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// Due to the use of unmasked pointers, this FIFO does not suffer from loosing +// one item slice. Furthermore, write and read operations are completely +// decoupled as write and read functions do not modify a common state. Henceforth, +// writing or reading from the FIFO within an ISR is safe as long as no other +// process (thread or ISR) interferes. +// Also, this FIFO is ready to be used in combination with a DMA as the write and +// read pointers can be updated from within a DMA ISR. Overflows are detectable +// within a certain number (see tu_fifo_overflow()). + +#include "common/tusb_common.h" + +// mutex is only needed for RTOS +// for OS None, we don't get preempted +#define CFG_FIFO_MUTEX (CFG_TUSB_OS != OPT_OS_NONE) + +#if CFG_FIFO_MUTEX +#include "osal/osal.h" +#define tu_fifo_mutex_t osal_mutex_t +#endif + +typedef struct +{ + uint8_t* buffer ; ///< buffer pointer + uint16_t depth ; ///< max items + uint16_t item_size ; ///< size of each item + bool overwritable ; + + uint16_t non_used_index_space ; ///< required for non-power-of-two buffer length + uint16_t max_pointer_idx ; ///< maximum absolute pointer index + + volatile uint16_t wr_idx ; ///< write pointer + volatile uint16_t rd_idx ; ///< read pointer + +#if CFG_FIFO_MUTEX + tu_fifo_mutex_t mutex_wr; + tu_fifo_mutex_t mutex_rd; +#endif + +} tu_fifo_t; + +typedef struct +{ + uint16_t len_lin ; ///< linear length in item size + uint16_t len_wrap ; ///< wrapped length in item size + void * ptr_lin ; ///< linear part start pointer + void * ptr_wrap ; ///< wrapped part start pointer +} tu_fifo_buffer_info_t; + +#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable) \ +{ \ + .buffer = _buffer, \ + .depth = _depth, \ + .item_size = sizeof(_type), \ + .overwritable = _overwritable, \ + .non_used_index_space = UINT16_MAX - (2*(_depth)-1), \ + .max_pointer_idx = 2*(_depth)-1, \ +} + +#define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \ + uint8_t _name##_buf[_depth*sizeof(_type)]; \ + tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _type, _overwritable) + + +bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable); +bool tu_fifo_clear(tu_fifo_t *f); +bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable); + +#if CFG_FIFO_MUTEX +TU_ATTR_ALWAYS_INLINE static inline +void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t write_mutex_hdl, tu_fifo_mutex_t read_mutex_hdl) +{ + f->mutex_wr = write_mutex_hdl; + f->mutex_rd = read_mutex_hdl; +} +#endif + +bool tu_fifo_write (tu_fifo_t* f, void const * p_data); +uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * p_data, uint16_t n); +uint16_t tu_fifo_write_n_const_addr_full_words (tu_fifo_t* f, const void * data, uint16_t n); + +bool tu_fifo_read (tu_fifo_t* f, void * p_buffer); +uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t n); +uint16_t tu_fifo_read_n_const_addr_full_words (tu_fifo_t* f, void * buffer, uint16_t n); + +bool tu_fifo_peek (tu_fifo_t* f, void * p_buffer); +uint16_t tu_fifo_peek_n (tu_fifo_t* f, void * p_buffer, uint16_t n); + +uint16_t tu_fifo_count (tu_fifo_t* f); +uint16_t tu_fifo_remaining (tu_fifo_t* f); +bool tu_fifo_empty (tu_fifo_t* f); +bool tu_fifo_full (tu_fifo_t* f); +bool tu_fifo_overflowed (tu_fifo_t* f); +void tu_fifo_correct_read_pointer (tu_fifo_t* f); + +TU_ATTR_ALWAYS_INLINE static inline +uint16_t tu_fifo_depth(tu_fifo_t* f) +{ + return f->depth; +} + +// Pointer modifications intended to be used in combinations with DMAs. +// USE WITH CARE - NO SAFTY CHECKS CONDUCTED HERE! NOT MUTEX PROTECTED! +void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n); +void tu_fifo_advance_read_pointer (tu_fifo_t *f, uint16_t n); + +// If you want to read/write from/to the FIFO by use of a DMA, you may need to conduct two copies +// to handle a possible wrapping part. These functions deliver a pointer to start +// reading/writing from/to and a valid linear length along which no wrap occurs. +void tu_fifo_get_read_info (tu_fifo_t *f, tu_fifo_buffer_info_t *info); +void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info); + + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_FIFO_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_mcu.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_mcu.h new file mode 100644 index 00000000..baa82fc1 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_mcu.h @@ -0,0 +1,289 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef TUSB_MCU_H_ +#define TUSB_MCU_H_ + +//--------------------------------------------------------------------+ +// Port Specific +// TUP stand for TinyUSB Port (can be renamed) +//--------------------------------------------------------------------+ + +//------------- Unaligned Memory Access -------------// + +// ARMv7+ (M3-M7, M23-M33) can access unaligned memory +#if (defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) + #define TUP_ARCH_STRICT_ALIGN 0 +#else + #define TUP_ARCH_STRICT_ALIGN 1 +#endif + +/* USB Controller Attributes for Device, Host or MCU (both) + * - ENDPOINT_MAX: max (logical) number of endpoint + * - ENDPOINT_EXCLUSIVE_NUMBER: endpoint number with different direction IN and OUT aren't allowed, + * e.g EP1 OUT & EP1 IN cannot exist together + * - RHPORT_HIGHSPEED: support highspeed with on-chip PHY + */ + +//------------- NXP -------------// +#if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX) + #define TUP_DCD_ENDPOINT_MAX 5 + +#elif TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX) + #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_USBIP_OHCI + +#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX) + // TODO USB0 has 6, USB1 has 4 + #define TUP_USBIP_CHIPIDEA_HS + #define TUP_USBIP_EHCI + + #define TUP_DCD_ENDPOINT_MAX 6 + #define TUP_RHPORT_HIGHSPEED 1 // Port0 HS, Port1 FS + +#elif TU_CHECK_MCU(OPT_MCU_LPC51UXX) + #define TUP_DCD_ENDPOINT_MAX 5 + +#elif TU_CHECK_MCU(OPT_MCU_LPC54XXX) + // TODO USB0 has 5, USB1 has 6 + #define TUP_DCD_ENDPOINT_MAX 6 + +#elif TU_CHECK_MCU(OPT_MCU_LPC55XX) + // TODO USB0 has 5, USB1 has 6 + #define TUP_DCD_ENDPOINT_MAX 6 + +#elif TU_CHECK_MCU(OPT_MCU_MIMXRT) + #define TUP_USBIP_CHIPIDEA_HS + #define TUP_USBIP_EHCI + + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_RHPORT_HIGHSPEED 1 // Port0 HS, Port1 HS + +#elif TU_CHECK_MCU(OPT_MCU_MKL25ZXX, OPT_MCU_K32L2BXX) + #define TUP_DCD_ENDPOINT_MAX 16 + +#elif TU_CHECK_MCU(OPT_MCU_MM32F327X) + #define TUP_DCD_ENDPOINT_MAX 16 + +//------------- Nordic -------------// +#elif TU_CHECK_MCU(OPT_MCU_NRF5X) + // 8 CBI + 1 ISO + #define TUP_DCD_ENDPOINT_MAX 9 + +//------------- Microchip -------------// +#elif TU_CHECK_MCU(OPT_MCU_SAMD21, OPT_MCU_SAMD51, OPT_MCU_SAME5X) || \ + TU_CHECK_MCU(OPT_MCU_SAMD11, OPT_MCU_SAML21, OPT_MCU_SAML22) + #define TUP_DCD_ENDPOINT_MAX 8 + +#elif TU_CHECK_MCU(OPT_MCU_SAMG) + #define TUP_DCD_ENDPOINT_MAX 6 + #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + +#elif TU_CHECK_MCU(OPT_MCU_SAMX7X) + #define TUP_DCD_ENDPOINT_MAX 10 + #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + +#elif TU_CHECK_MCU(OPT_MCU_PIC32MZ) + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + +//------------- ST -------------// +#elif TU_CHECK_MCU(OPT_MCU_STM32F0) + #define TUP_DCD_ENDPOINT_MAX 8 + +#elif TU_CHECK_MCU(OPT_MCU_STM32F1) + #if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \ + defined (STM32F107xB) || defined (STM32F107xC) + #define TUP_USBIP_DWC2 + #define TUP_USBIP_DWC2_STM32 + + #define TUP_DCD_ENDPOINT_MAX 4 + #else + #define TUP_DCD_ENDPOINT_MAX 8 + #endif + +#elif TU_CHECK_MCU(OPT_MCU_STM32F2) + #define TUP_USBIP_DWC2 + #define TUP_USBIP_DWC2_STM32 + + // FS has 4 ep, HS has 5 ep + #define TUP_DCD_ENDPOINT_MAX 6 + +#elif TU_CHECK_MCU(OPT_MCU_STM32F3) + #define TUP_DCD_ENDPOINT_MAX 8 + +#elif TU_CHECK_MCU(OPT_MCU_STM32F4) + #define TUP_USBIP_DWC2 + #define TUP_USBIP_DWC2_STM32 + + // For most mcu, FS has 4, HS has 6. TODO 446/469/479 HS has 9 + #define TUP_DCD_ENDPOINT_MAX 6 + +#elif TU_CHECK_MCU(OPT_MCU_STM32F7) + #define TUP_USBIP_DWC2 + #define TUP_USBIP_DWC2_STM32 + + // FS has 6, HS has 9 + #define TUP_DCD_ENDPOINT_MAX 9 + + // MCU with on-chip HS Phy + #if defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F733xx) + #define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS + #endif + +#elif TU_CHECK_MCU(OPT_MCU_STM32H7) + #define TUP_USBIP_DWC2 + #define TUP_USBIP_DWC2_STM32 + + #define TUP_DCD_ENDPOINT_MAX 9 + +#elif TU_CHECK_MCU(OPT_MCU_STM32G4) + #define TUP_DCD_ENDPOINT_MAX 8 + +#elif TU_CHECK_MCU(OPT_MCU_STM32L0, OPT_MCU_STM32L1) + #define TUP_DCD_ENDPOINT_MAX 8 + +#elif TU_CHECK_MCU(OPT_MCU_STM32L4) + #if defined (STM32L475xx) || defined (STM32L476xx) || \ + defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \ + defined (STM32L4A6xx) || defined (STM32L4P5xx) || defined (STM32L4Q5xx) || \ + defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || \ + defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx) + #define TUP_USBIP_DWC2 + #define TUP_USBIP_DWC2_STM32 + + #define TUP_DCD_ENDPOINT_MAX 6 + #else + #define TUP_DCD_ENDPOINT_MAX 8 + #endif + +#elif TU_CHECK_MCU(OPT_MCU_STM32WB) + #define TUP_DCD_ENDPOINT_MAX 8 + +//------------- Sony -------------// +#elif TU_CHECK_MCU(OPT_MCU_CXD56) + #define TUP_DCD_ENDPOINT_MAX 7 + #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + +//------------- TI -------------// +#elif TU_CHECK_MCU(OPT_MCU_MSP430x5xx) + #define TUP_DCD_ENDPOINT_MAX 8 + +#elif TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129) + #define TUP_DCD_ENDPOINT_MAX 8 + +//------------- ValentyUSB -------------// +#elif TU_CHECK_MCU(OPT_MCU_VALENTYUSB_EPTRI) + #define TUP_DCD_ENDPOINT_MAX 16 + +//------------- Nuvoton -------------// +#elif TU_CHECK_MCU(OPT_MCU_NUC121, OPT_MCU_NUC126) + #define TUP_DCD_ENDPOINT_MAX 8 + +#elif TU_CHECK_MCU(OPT_MCU_NUC120) + #define TUP_DCD_ENDPOINT_MAX 6 + +#elif TU_CHECK_MCU(OPT_MCU_NUC505) + #define TUP_DCD_ENDPOINT_MAX 12 + #define TUP_RHPORT_HIGHSPEED 1 + +//------------- Espressif -------------// +#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + #define TUP_USBIP_DWC2 + #define TUP_DCD_ENDPOINT_MAX 6 + +//------------- Dialog -------------// +#elif TU_CHECK_MCU(OPT_MCU_DA1469X) + #define TUP_DCD_ENDPOINT_MAX 4 + +//------------- Raspberry Pi -------------// +#elif TU_CHECK_MCU(OPT_MCU_RP2040) + #define TUP_DCD_ENDPOINT_MAX 16 + + #define TU_ATTR_FAST_FUNC __attribute__((section(".time_critical.tinyusb"))) + +//------------- Silabs -------------// +#elif TU_CHECK_MCU(OPT_MCU_EFM32GG) + #define TUP_USBIP_DWC2 + #define TUP_DCD_ENDPOINT_MAX 7 + +//------------- Renesas -------------// +#elif TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N) + #define TUP_DCD_ENDPOINT_MAX 10 + +//------------- GigaDevice -------------// +#elif TU_CHECK_MCU(OPT_MCU_GD32VF103) + #define TUP_USBIP_DWC2 + #define TUP_DCD_ENDPOINT_MAX 4 + +//------------- Broadcom -------------// +#elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837) + #define TUP_USBIP_DWC2 + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_RHPORT_HIGHSPEED 1 + +//------------- Broadcom -------------// +#elif TU_CHECK_MCU(OPT_MCU_XMC4000) + #define TUP_USBIP_DWC2 + #define TUP_DCD_ENDPOINT_MAX 8 + +//------------- BridgeTek -------------// +#elif TU_CHECK_MCU(OPT_MCU_FT90X) + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_RHPORT_HIGHSPEED 1 + +#elif TU_CHECK_MCU(OPT_MCU_FT93X) + #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_RHPORT_HIGHSPEED 1 + +//------------ Allwinner -------------// +#elif TU_CHECK_MCU(OPT_MCU_F1C100S) + #define TUP_DCD_ENDPOINT_MAX 4 + +#endif + +//--------------------------------------------------------------------+ +// Default Values +//--------------------------------------------------------------------+ + +#ifndef TUP_DCD_ENDPOINT_MAX + #warning "TUP_DCD_ENDPOINT_MAX is not defined for this MCU, default to 8" + #define TUP_DCD_ENDPOINT_MAX 8 +#endif + +// Default to fullspeed if not defined +#ifndef TUP_RHPORT_HIGHSPEED + #define TUP_RHPORT_HIGHSPEED 0 +#endif + +// fast function, normally mean placing function in SRAM +#ifndef TU_ATTR_FAST_FUNC + #define TU_ATTR_FAST_FUNC +#endif + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_private.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_private.h new file mode 100644 index 00000000..b34506f6 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_private.h @@ -0,0 +1,65 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2022, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + + +#ifndef _TUSB_PRIVATE_H_ +#define _TUSB_PRIVATE_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +typedef struct TU_ATTR_PACKED +{ + volatile uint8_t busy : 1; + volatile uint8_t stalled : 1; + volatile uint8_t claimed : 1; +}tu_edpt_state_t; + +//--------------------------------------------------------------------+ +// Internal Helper used by Host and Device Stack +//--------------------------------------------------------------------+ + +// Check if endpoint descriptor is valid per USB specs +bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed); + +// Bind all endpoint of a interface descriptor to class driver +void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* p_desc, uint16_t desc_len, uint8_t driver_id); + +// Calculate total length of n interfaces (depending on IAD) +uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len); + +// Claim an endpoint with provided mutex +bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex); + +// Release an endpoint with provided mutex +bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_PRIVATE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_timeout.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_timeout.h new file mode 100644 index 00000000..ce53955f --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_timeout.h @@ -0,0 +1,80 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup Group_Common Common Files + * \defgroup Group_TimeoutTimer timeout timer + * @{ */ + +#ifndef _TUSB_TIMEOUT_H_ +#define _TUSB_TIMEOUT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uint32_t start; + uint32_t interval; +}tu_timeout_t; + +#if 0 + +extern uint32_t tusb_hal_millis(void); + +static inline void tu_timeout_set(tu_timeout_t* tt, uint32_t msec) +{ + tt->interval = msec; + tt->start = tusb_hal_millis(); +} + +static inline bool tu_timeout_expired(tu_timeout_t* tt) +{ + return ( tusb_hal_millis() - tt->start ) >= tt->interval; +} + +// For used with periodic event to prevent drift +static inline void tu_timeout_reset(tu_timeout_t* tt) +{ + tt->start += tt->interval; +} + +static inline void tu_timeout_restart(tu_timeout_t* tt) +{ + tt->start = tusb_hal_millis(); +} + +#endif + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_TIMEOUT_H_ */ + +/** @} */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_types.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_types.h new file mode 100644 index 00000000..1f2a38d4 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_types.h @@ -0,0 +1,541 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/** \ingroup group_usb_definitions + * \defgroup USBDef_Type USB Types + * @{ */ + +#ifndef _TUSB_TYPES_H_ +#define _TUSB_TYPES_H_ + +#include +#include +#include "tusb_compiler.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/*------------------------------------------------------------------*/ +/* CONSTANTS + *------------------------------------------------------------------*/ + +/// defined base on EHCI specs value for Endpoint Speed +typedef enum +{ + TUSB_SPEED_FULL = 0, + TUSB_SPEED_LOW = 1, + TUSB_SPEED_HIGH = 2, + TUSB_SPEED_INVALID = 0xff, +}tusb_speed_t; + +/// defined base on USB Specs Endpoint's bmAttributes +typedef enum +{ + TUSB_XFER_CONTROL = 0 , + TUSB_XFER_ISOCHRONOUS , + TUSB_XFER_BULK , + TUSB_XFER_INTERRUPT +}tusb_xfer_type_t; + +typedef enum +{ + TUSB_DIR_OUT = 0, + TUSB_DIR_IN = 1, + + TUSB_DIR_IN_MASK = 0x80 +}tusb_dir_t; + +/// Isochronous End Point Attributes +typedef enum +{ + TUSB_ISO_EP_ATT_NO_SYNC = 0x00, + TUSB_ISO_EP_ATT_ASYNCHRONOUS = 0x04, + TUSB_ISO_EP_ATT_ADAPTIVE = 0x08, + TUSB_ISO_EP_ATT_SYNCHRONOUS = 0x0C, + TUSB_ISO_EP_ATT_DATA = 0x00, ///< Data End Point + TUSB_ISO_EP_ATT_EXPLICIT_FB = 0x10, ///< Feedback End Point + TUSB_ISO_EP_ATT_IMPLICIT_FB = 0x20, ///< Data endpoint that also serves as an implicit feedback +}tusb_iso_ep_attribute_t; + +/// USB Descriptor Types +typedef enum +{ + TUSB_DESC_DEVICE = 0x01, + TUSB_DESC_CONFIGURATION = 0x02, + TUSB_DESC_STRING = 0x03, + TUSB_DESC_INTERFACE = 0x04, + TUSB_DESC_ENDPOINT = 0x05, + TUSB_DESC_DEVICE_QUALIFIER = 0x06, + TUSB_DESC_OTHER_SPEED_CONFIG = 0x07, + TUSB_DESC_INTERFACE_POWER = 0x08, + TUSB_DESC_OTG = 0x09, + TUSB_DESC_DEBUG = 0x0A, + TUSB_DESC_INTERFACE_ASSOCIATION = 0x0B, + + TUSB_DESC_BOS = 0x0F, + TUSB_DESC_DEVICE_CAPABILITY = 0x10, + + TUSB_DESC_FUNCTIONAL = 0x21, + + // Class Specific Descriptor + TUSB_DESC_CS_DEVICE = 0x21, + TUSB_DESC_CS_CONFIGURATION = 0x22, + TUSB_DESC_CS_STRING = 0x23, + TUSB_DESC_CS_INTERFACE = 0x24, + TUSB_DESC_CS_ENDPOINT = 0x25, + + TUSB_DESC_SUPERSPEED_ENDPOINT_COMPANION = 0x30, + TUSB_DESC_SUPERSPEED_ISO_ENDPOINT_COMPANION = 0x31 +}tusb_desc_type_t; + +typedef enum +{ + TUSB_REQ_GET_STATUS = 0 , + TUSB_REQ_CLEAR_FEATURE = 1 , + TUSB_REQ_RESERVED = 2 , + TUSB_REQ_SET_FEATURE = 3 , + TUSB_REQ_RESERVED2 = 4 , + TUSB_REQ_SET_ADDRESS = 5 , + TUSB_REQ_GET_DESCRIPTOR = 6 , + TUSB_REQ_SET_DESCRIPTOR = 7 , + TUSB_REQ_GET_CONFIGURATION = 8 , + TUSB_REQ_SET_CONFIGURATION = 9 , + TUSB_REQ_GET_INTERFACE = 10 , + TUSB_REQ_SET_INTERFACE = 11 , + TUSB_REQ_SYNCH_FRAME = 12 +}tusb_request_code_t; + +typedef enum +{ + TUSB_REQ_FEATURE_EDPT_HALT = 0, + TUSB_REQ_FEATURE_REMOTE_WAKEUP = 1, + TUSB_REQ_FEATURE_TEST_MODE = 2 +}tusb_request_feature_selector_t; + +typedef enum +{ + TUSB_REQ_TYPE_STANDARD = 0, + TUSB_REQ_TYPE_CLASS, + TUSB_REQ_TYPE_VENDOR, + TUSB_REQ_TYPE_INVALID +} tusb_request_type_t; + +typedef enum +{ + TUSB_REQ_RCPT_DEVICE =0, + TUSB_REQ_RCPT_INTERFACE, + TUSB_REQ_RCPT_ENDPOINT, + TUSB_REQ_RCPT_OTHER +} tusb_request_recipient_t; + +// https://www.usb.org/defined-class-codes +typedef enum +{ + TUSB_CLASS_UNSPECIFIED = 0 , + TUSB_CLASS_AUDIO = 1 , + TUSB_CLASS_CDC = 2 , + TUSB_CLASS_HID = 3 , + TUSB_CLASS_RESERVED_4 = 4 , + TUSB_CLASS_PHYSICAL = 5 , + TUSB_CLASS_IMAGE = 6 , + TUSB_CLASS_PRINTER = 7 , + TUSB_CLASS_MSC = 8 , + TUSB_CLASS_HUB = 9 , + TUSB_CLASS_CDC_DATA = 10 , + TUSB_CLASS_SMART_CARD = 11 , + TUSB_CLASS_RESERVED_12 = 12 , + TUSB_CLASS_CONTENT_SECURITY = 13 , + TUSB_CLASS_VIDEO = 14 , + TUSB_CLASS_PERSONAL_HEALTHCARE = 15 , + TUSB_CLASS_AUDIO_VIDEO = 16 , + + TUSB_CLASS_DIAGNOSTIC = 0xDC , + TUSB_CLASS_WIRELESS_CONTROLLER = 0xE0 , + TUSB_CLASS_MISC = 0xEF , + TUSB_CLASS_APPLICATION_SPECIFIC = 0xFE , + TUSB_CLASS_VENDOR_SPECIFIC = 0xFF +}tusb_class_code_t; + +typedef enum +{ + MISC_SUBCLASS_COMMON = 2 +}misc_subclass_type_t; + +typedef enum +{ + MISC_PROTOCOL_IAD = 1 +}misc_protocol_type_t; + +typedef enum +{ + APP_SUBCLASS_USBTMC = 0x03, + APP_SUBCLASS_DFU_RUNTIME = 0x01 +} app_subclass_type_t; + +typedef enum +{ + DEVICE_CAPABILITY_WIRELESS_USB = 0x01, + DEVICE_CAPABILITY_USB20_EXTENSION = 0x02, + DEVICE_CAPABILITY_SUPERSPEED_USB = 0x03, + DEVICE_CAPABILITY_CONTAINER_id = 0x04, + DEVICE_CAPABILITY_PLATFORM = 0x05, + DEVICE_CAPABILITY_POWER_DELIVERY = 0x06, + DEVICE_CAPABILITY_BATTERY_INFO = 0x07, + DEVICE_CAPABILITY_PD_CONSUMER_PORT = 0x08, + DEVICE_CAPABILITY_PD_PROVIDER_PORT = 0x09, + DEVICE_CAPABILITY_SUPERSPEED_PLUS = 0x0A, + DEVICE_CAPABILITY_PRECESION_TIME_MEASUREMENT = 0x0B, + DEVICE_CAPABILITY_WIRELESS_USB_EXT = 0x0C, + DEVICE_CAPABILITY_BILLBOARD = 0x0D, + DEVICE_CAPABILITY_AUTHENTICATION = 0x0E, + DEVICE_CAPABILITY_BILLBOARD_EX = 0x0F, + DEVICE_CAPABILITY_CONFIGURATION_SUMMARY = 0x10 +}device_capability_type_t; + +enum { + TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = TU_BIT(5), + TUSB_DESC_CONFIG_ATT_SELF_POWERED = TU_BIT(6), +}; + +#define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2) + +typedef enum +{ + XFER_RESULT_SUCCESS, + XFER_RESULT_FAILED, + XFER_RESULT_STALLED, + XFER_RESULT_TIMEOUT, + XFER_RESULT_INVALID +}xfer_result_t; + +enum // TODO remove +{ + DESC_OFFSET_LEN = 0, + DESC_OFFSET_TYPE = 1 +}; + +enum +{ + INTERFACE_INVALID_NUMBER = 0xff +}; + + +typedef enum +{ + MS_OS_20_SET_HEADER_DESCRIPTOR = 0x00, + MS_OS_20_SUBSET_HEADER_CONFIGURATION = 0x01, + MS_OS_20_SUBSET_HEADER_FUNCTION = 0x02, + MS_OS_20_FEATURE_COMPATBLE_ID = 0x03, + MS_OS_20_FEATURE_REG_PROPERTY = 0x04, + MS_OS_20_FEATURE_MIN_RESUME_TIME = 0x05, + MS_OS_20_FEATURE_MODEL_ID = 0x06, + MS_OS_20_FEATURE_CCGP_DEVICE = 0x07, + MS_OS_20_FEATURE_VENDOR_REVISION = 0x08 +} microsoft_os_20_type_t; + +enum +{ + CONTROL_STAGE_IDLE, + CONTROL_STAGE_SETUP, + CONTROL_STAGE_DATA, + CONTROL_STAGE_ACK +}; + +//--------------------------------------------------------------------+ +// USB Descriptors +//--------------------------------------------------------------------+ + +// Start of all packed definitions for compiler without per-type packed +TU_ATTR_PACKED_BEGIN +TU_ATTR_BIT_FIELD_ORDER_BEGIN + +/// USB Device Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< DEVICE Descriptor Type. + uint16_t bcdUSB ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). This field identifies the release of the USB Specification with which the device and its descriptors are compliant. + + uint8_t bDeviceClass ; ///< Class code (assigned by the USB-IF). \li If this field is reset to zero, each interface within a configuration specifies its own class information and the various interfaces operate independently. \li If this field is set to a value between 1 and FEH, the device supports different class specifications on different interfaces and the interfaces may not operate independently. This value identifies the class definition used for the aggregate interfaces. \li If this field is set to FFH, the device class is vendor-specific. + uint8_t bDeviceSubClass ; ///< Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass field. \li If the bDeviceClass field is reset to zero, this field must also be reset to zero. \li If the bDeviceClass field is not set to FFH, all values are reserved for assignment by the USB-IF. + uint8_t bDeviceProtocol ; ///< Protocol code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass and the bDeviceSubClass fields. If a device supports class-specific protocols on a device basis as opposed to an interface basis, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use class-specific protocols on a device basis. However, it may use classspecific protocols on an interface basis. \li If this field is set to FFH, the device uses a vendor-specific protocol on a device basis. + uint8_t bMaxPacketSize0 ; ///< Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid). For HS devices is fixed to 64. + + uint16_t idVendor ; ///< Vendor ID (assigned by the USB-IF). + uint16_t idProduct ; ///< Product ID (assigned by the manufacturer). + uint16_t bcdDevice ; ///< Device release number in binary-coded decimal. + uint8_t iManufacturer ; ///< Index of string descriptor describing manufacturer. + uint8_t iProduct ; ///< Index of string descriptor describing product. + uint8_t iSerialNumber ; ///< Index of string descriptor describing the device's serial number. + + uint8_t bNumConfigurations ; ///< Number of possible configurations. +} tusb_desc_device_t; + +TU_VERIFY_STATIC( sizeof(tusb_desc_device_t) == 18, "size is not correct"); + +// USB Binary Device Object Store (BOS) Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes + uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type + uint16_t wTotalLength ; ///< Total length of data returned for this descriptor + uint8_t bNumDeviceCaps ; ///< Number of device capability descriptors in the BOS +} tusb_desc_bos_t; + +TU_VERIFY_STATIC( sizeof(tusb_desc_bos_t) == 5, "size is not correct"); + +/// USB Configuration Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes + uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type + uint16_t wTotalLength ; ///< Total length of data returned for this configuration. Includes the combined length of all descriptors (configuration, interface, endpoint, and class- or vendor-specific) returned for this configuration. + + uint8_t bNumInterfaces ; ///< Number of interfaces supported by this configuration + uint8_t bConfigurationValue ; ///< Value to use as an argument to the SetConfiguration() request to select this configuration. + uint8_t iConfiguration ; ///< Index of string descriptor describing this configuration + uint8_t bmAttributes ; ///< Configuration characteristics \n D7: Reserved (set to one)\n D6: Self-powered \n D5: Remote Wakeup \n D4...0: Reserved (reset to zero) \n D7 is reserved and must be set to one for historical reasons. \n A device configuration that uses power from the bus and a local source reports a non-zero value in bMaxPower to indicate the amount of bus power required and sets D6. The actual power source at runtime may be determined using the GetStatus(DEVICE) request (see USB 2.0 spec Section 9.4.5). \n If a device configuration supports remote wakeup, D5 is set to one. + uint8_t bMaxPower ; ///< Maximum power consumption of the USB device from the bus in this specific configuration when the device is fully operational. Expressed in 2 mA units (i.e., 50 = 100 mA). +} tusb_desc_configuration_t; + +TU_VERIFY_STATIC( sizeof(tusb_desc_configuration_t) == 9, "size is not correct"); + +/// USB Interface Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes + uint8_t bDescriptorType ; ///< INTERFACE Descriptor Type + + uint8_t bInterfaceNumber ; ///< Number of this interface. Zero-based value identifying the index in the array of concurrent interfaces supported by this configuration. + uint8_t bAlternateSetting ; ///< Value used to select this alternate setting for the interface identified in the prior field + uint8_t bNumEndpoints ; ///< Number of endpoints used by this interface (excluding endpoint zero). If this value is zero, this interface only uses the Default Control Pipe. + uint8_t bInterfaceClass ; ///< Class code (assigned by the USB-IF). \li A value of zero is reserved for future standardization. \li If this field is set to FFH, the interface class is vendor-specific. \li All other values are reserved for assignment by the USB-IF. + uint8_t bInterfaceSubClass ; ///< Subclass code (assigned by the USB-IF). \n These codes are qualified by the value of the bInterfaceClass field. \li If the bInterfaceClass field is reset to zero, this field must also be reset to zero. \li If the bInterfaceClass field is not set to FFH, all values are reserved for assignment by the USB-IF. + uint8_t bInterfaceProtocol ; ///< Protocol code (assigned by the USB). \n These codes are qualified by the value of the bInterfaceClass and the bInterfaceSubClass fields. If an interface supports class-specific requests, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use a class-specific protocol on this interface. \li If this field is set to FFH, the device uses a vendor-specific protocol for this interface. + uint8_t iInterface ; ///< Index of string descriptor describing this interface +} tusb_desc_interface_t; + +TU_VERIFY_STATIC( sizeof(tusb_desc_interface_t) == 9, "size is not correct"); + +/// USB Endpoint Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; // Size of this descriptor in bytes + uint8_t bDescriptorType ; // ENDPOINT Descriptor Type + + uint8_t bEndpointAddress ; // The address of the endpoint + + struct TU_ATTR_PACKED { + uint8_t xfer : 2; // Control, ISO, Bulk, Interrupt + uint8_t sync : 2; // None, Asynchronous, Adaptive, Synchronous + uint8_t usage : 2; // Data, Feedback, Implicit feedback + uint8_t : 2; + } bmAttributes; + + uint16_t wMaxPacketSize ; // Bit 10..0 : max packet size, bit 12..11 additional transaction per highspeed micro-frame + uint8_t bInterval ; // Polling interval, in frames or microframes depending on the operating speed +} tusb_desc_endpoint_t; + +TU_VERIFY_STATIC( sizeof(tusb_desc_endpoint_t) == 7, "size is not correct"); + +/// USB Other Speed Configuration Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of descriptor + uint8_t bDescriptorType ; ///< Other_speed_Configuration Type + uint16_t wTotalLength ; ///< Total length of data returned + + uint8_t bNumInterfaces ; ///< Number of interfaces supported by this speed configuration + uint8_t bConfigurationValue ; ///< Value to use to select configuration + uint8_t iConfiguration ; ///< Index of string descriptor + uint8_t bmAttributes ; ///< Same as Configuration descriptor + uint8_t bMaxPower ; ///< Same as Configuration descriptor +} tusb_desc_other_speed_t; + +/// USB Device Qualifier Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of descriptor + uint8_t bDescriptorType ; ///< Device Qualifier Type + uint16_t bcdUSB ; ///< USB specification version number (e.g., 0200H for V2.00) + + uint8_t bDeviceClass ; ///< Class Code + uint8_t bDeviceSubClass ; ///< SubClass Code + uint8_t bDeviceProtocol ; ///< Protocol Code + + uint8_t bMaxPacketSize0 ; ///< Maximum packet size for other speed + uint8_t bNumConfigurations ; ///< Number of Other-speed Configurations + uint8_t bReserved ; ///< Reserved for future use, must be zero +} tusb_desc_device_qualifier_t; + +TU_VERIFY_STATIC( sizeof(tusb_desc_device_qualifier_t) == 10, "size is not correct"); + +/// USB Interface Association Descriptor (IAD ECN) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of descriptor + uint8_t bDescriptorType ; ///< Other_speed_Configuration Type + + uint8_t bFirstInterface ; ///< Index of the first associated interface. + uint8_t bInterfaceCount ; ///< Total number of associated interfaces. + + uint8_t bFunctionClass ; ///< Interface class ID. + uint8_t bFunctionSubClass ; ///< Interface subclass ID. + uint8_t bFunctionProtocol ; ///< Interface protocol ID. + + uint8_t iFunction ; ///< Index of the string descriptor describing the interface association. +} tusb_desc_interface_assoc_t; + +// USB String Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength ; ///< Size of this descriptor in bytes + uint8_t bDescriptorType ; ///< Descriptor Type + uint16_t unicode_string[]; +} tusb_desc_string_t; + +// USB Binary Device Object Store (BOS) +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength; + uint8_t bDescriptorType ; + uint8_t bDevCapabilityType; + uint8_t bReserved; + uint8_t PlatformCapabilityUUID[16]; + uint8_t CapabilityData[]; +} tusb_desc_bos_platform_t; + +// USB WebuSB URL Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bScheme; + char url[]; +} tusb_desc_webusb_url_t; + +// DFU Functional Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength; + uint8_t bDescriptorType; + + union { + struct TU_ATTR_PACKED { + uint8_t bitCanDnload : 1; + uint8_t bitCanUpload : 1; + uint8_t bitManifestationTolerant : 1; + uint8_t bitWillDetach : 1; + uint8_t reserved : 4; + } bmAttributes; + + uint8_t bAttributes; + }; + + uint16_t wDetachTimeOut; + uint16_t wTransferSize; + uint16_t bcdDFUVersion; +} tusb_desc_dfu_functional_t; + +/*------------------------------------------------------------------*/ +/* Types + *------------------------------------------------------------------*/ +typedef struct TU_ATTR_PACKED{ + union { + struct TU_ATTR_PACKED { + uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t. + uint8_t type : 2; ///< Request type tusb_request_type_t. + uint8_t direction : 1; ///< Direction type. tusb_dir_t + } bmRequestType_bit; + + uint8_t bmRequestType; + }; + + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} tusb_control_request_t; + +TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "size is not correct"); + + +TU_ATTR_PACKED_END // End of all packed definitions +TU_ATTR_BIT_FIELD_ORDER_END + +//--------------------------------------------------------------------+ +// Endpoint helper +//--------------------------------------------------------------------+ + +// Get direction from Endpoint address +TU_ATTR_ALWAYS_INLINE static inline tusb_dir_t tu_edpt_dir(uint8_t addr) +{ + return (addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; +} + +// Get Endpoint number from address +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_number(uint8_t addr) +{ + return (uint8_t)(addr & (~TUSB_DIR_IN_MASK)); +} + +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir) +{ + return (uint8_t)(num | (dir ? TUSB_DIR_IN_MASK : 0)); +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep) +{ + return tu_le16toh(desc_ep->wMaxPacketSize) & TU_GENMASK(10, 0); +} + +//--------------------------------------------------------------------+ +// Descriptor helper +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline uint8_t const * tu_desc_next(void const* desc) +{ + uint8_t const* desc8 = (uint8_t const*) desc; + return desc8 + desc8[DESC_OFFSET_LEN]; +} + +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_type(void const* desc) +{ + return ((uint8_t const*) desc)[DESC_OFFSET_TYPE]; +} + +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc) +{ + return ((uint8_t const*) desc)[DESC_OFFSET_LEN]; +} + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_TYPES_H_ */ + +/** @} */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_verify.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_verify.h new file mode 100644 index 00000000..a52a6d26 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_verify.h @@ -0,0 +1,156 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ +#ifndef TUSB_VERIFY_H_ +#define TUSB_VERIFY_H_ + +#include +#include +#include "tusb_option.h" +#include "tusb_compiler.h" + +/*------------------------------------------------------------------*/ +/* This file use an advanced macro technique to mimic the default parameter + * as C++ for the sake of code simplicity. Beware of a headache macro + * manipulation that you are told to stay away. + * + * This contains macros for both VERIFY and ASSERT: + * + * VERIFY: Used when there is an error condition which is not the + * fault of the MCU. For example, bounds checking on data + * sent to the micro over USB should use this function. + * Another example is checking for buffer overflows, where + * returning from the active function causes a NAK. + * + * ASSERT: Used for error conditions that are caused by MCU firmware + * bugs. This is used to discover bugs in the code more + * quickly. One example would be adding assertions in library + * function calls to confirm a function's (untainted) + * parameters are valid. + * + * The difference in behavior is that ASSERT triggers a breakpoint while + * verify does not. + * + * #define TU_VERIFY(cond) if(cond) return false; + * #define TU_VERIFY(cond,ret) if(cond) return ret; + * + * #define TU_VERIFY_HDLR(cond,handler) if(cond) {handler; return false;} + * #define TU_VERIFY_HDLR(cond,ret,handler) if(cond) {handler; return ret;} + * + * #define TU_ASSERT(cond) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return false;} + * #define TU_ASSERT(cond,ret) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return ret;} + * + *------------------------------------------------------------------*/ + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// TU_VERIFY Helper +//--------------------------------------------------------------------+ + +#if CFG_TUSB_DEBUG + #include + #define _MESS_FAILED() tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__) +#else + #define _MESS_FAILED() do {} while (0) +#endif + +// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7, M33 +#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__) + #define TU_BREAKPOINT() do \ + { \ + volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \ + if ( (*ARM_CM_DHCSR) & 1UL ) __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */ \ + } while(0) + +#elif defined(__riscv) + #define TU_BREAKPOINT() do { __asm("ebreak\n"); } while(0) + +#elif defined(_mips) + #define TU_BREAKPOINT() do { __asm("sdbbp 0"); } while (0) + +#else + #define TU_BREAKPOINT() do {} while (0) +#endif + +/*------------------------------------------------------------------*/ +/* Macro Generator + *------------------------------------------------------------------*/ + +// Helper to implement optional parameter for TU_VERIFY Macro family +#define _GET_3RD_ARG(arg1, arg2, arg3, ...) arg3 +#define _GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4 + +/*------------- Generator for TU_VERIFY and TU_VERIFY_HDLR -------------*/ +#define TU_VERIFY_DEFINE(_cond, _handler, _ret) do \ +{ \ + if ( !(_cond) ) { _handler; return _ret; } \ +} while(0) + +/*------------------------------------------------------------------*/ +/* TU_VERIFY + * - TU_VERIFY_1ARGS : return false if failed + * - TU_VERIFY_2ARGS : return provided value if failed + *------------------------------------------------------------------*/ +#define TU_VERIFY_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, , false) +#define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, , _ret) + +#define TU_VERIFY(...) _GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, UNUSED)(__VA_ARGS__) + + +/*------------------------------------------------------------------*/ +/* TU_VERIFY WITH HANDLER + * - TU_VERIFY_HDLR_2ARGS : execute handler, return false if failed + * - TU_VERIFY_HDLR_3ARGS : execute handler, return provided error if failed + *------------------------------------------------------------------*/ +#define TU_VERIFY_HDLR_2ARGS(_cond, _handler) TU_VERIFY_DEFINE(_cond, _handler, false) +#define TU_VERIFY_HDLR_3ARGS(_cond, _handler, _ret) TU_VERIFY_DEFINE(_cond, _handler, _ret) + +#define TU_VERIFY_HDLR(...) _GET_4TH_ARG(__VA_ARGS__, TU_VERIFY_HDLR_3ARGS, TU_VERIFY_HDLR_2ARGS,UNUSED)(__VA_ARGS__) + +/*------------------------------------------------------------------*/ +/* ASSERT + * basically TU_VERIFY with TU_BREAKPOINT() as handler + * - 1 arg : return false if failed + * - 2 arg : return error if failed + *------------------------------------------------------------------*/ +#define ASSERT_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), false) +#define ASSERT_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), _ret) + +#ifndef TU_ASSERT +#define TU_ASSERT(...) _GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS,UNUSED)(__VA_ARGS__) +#endif + +/*------------------------------------------------------------------*/ +/* ASSERT HDLR + *------------------------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif /* TUSB_VERIFY_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/device/dcd.h b/test-devices/loopback-stm32/lib/tinyusb/device/dcd.h new file mode 100644 index 00000000..c1780f65 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/device/dcd.h @@ -0,0 +1,224 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_DCD_H_ +#define _TUSB_DCD_H_ + +#include "common/tusb_common.h" +#include "osal/osal.h" +#include "common/tusb_fifo.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Configuration +//--------------------------------------------------------------------+ + +#ifndef CFG_TUD_ENDPPOINT_MAX + #define CFG_TUD_ENDPPOINT_MAX TUP_DCD_ENDPOINT_MAX +#endif + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF PROTYPES +//--------------------------------------------------------------------+ + +typedef enum +{ + DCD_EVENT_INVALID = 0, + DCD_EVENT_BUS_RESET, + DCD_EVENT_UNPLUGGED, + DCD_EVENT_SOF, + DCD_EVENT_SUSPEND, // TODO LPM Sleep L1 support + DCD_EVENT_RESUME, + + DCD_EVENT_SETUP_RECEIVED, + DCD_EVENT_XFER_COMPLETE, + + // Not an DCD event, just a convenient way to defer ISR function + USBD_EVENT_FUNC_CALL, + + DCD_EVENT_COUNT +} dcd_eventid_t; + +typedef struct TU_ATTR_ALIGNED(4) +{ + uint8_t rhport; + uint8_t event_id; + + union + { + // BUS RESET + struct { + tusb_speed_t speed; + } bus_reset; + + // SOF + struct { + uint32_t frame_count; + }sof; + + // SETUP_RECEIVED + tusb_control_request_t setup_received; + + // XFER_COMPLETE + struct { + uint8_t ep_addr; + uint8_t result; + uint32_t len; + }xfer_complete; + + // FUNC_CALL + struct { + void (*func) (void*); + void* param; + }func_call; + }; +} dcd_event_t; + +//TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct"); + +//--------------------------------------------------------------------+ +// Controller API +//--------------------------------------------------------------------+ + +// Initialize controller to device mode +void dcd_init (uint8_t rhport); + +// Interrupt Handler +void dcd_int_handler(uint8_t rhport); + +// Enable device interrupt +void dcd_int_enable (uint8_t rhport); + +// Disable device interrupt +void dcd_int_disable(uint8_t rhport); + +// Receive Set Address request, mcu port must also include status IN response +void dcd_set_address(uint8_t rhport, uint8_t dev_addr); + +// Wake up host +void dcd_remote_wakeup(uint8_t rhport); + +// Connect by enabling internal pull-up resistor on D+/D- +void dcd_connect(uint8_t rhport) TU_ATTR_WEAK; + +// Disconnect by disabling internal pull-up resistor on D+/D- +void dcd_disconnect(uint8_t rhport) TU_ATTR_WEAK; + +// Enable/Disable Start-of-frame interrupt. Default is disabled +void dcd_sof_enable(uint8_t rhport, bool en); + +//--------------------------------------------------------------------+ +// Endpoint API +//--------------------------------------------------------------------+ + +// Invoked when a control transfer's status stage is complete. +// May help DCD to prepare for next control transfer, this API is optional. +void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) TU_ATTR_WEAK; + +// Configure endpoint's registers according to descriptor +bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_ep); + +// Close all non-control endpoints, cancel all pending transfers if any. +// Invoked when switching from a non-zero Configuration by SET_CONFIGURE therefore +// required for multiple configuration support. +void dcd_edpt_close_all (uint8_t rhport); + +// Close an endpoint. +// Since it is weak, caller must TU_ASSERT this function's existence before calling it. +void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK; + +// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack +bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); + +// Submit an transfer using fifo, When complete dcd_event_xfer_complete() is invoked to notify the stack +// This API is optional, may be useful for register-based for transferring data. +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) TU_ATTR_WEAK; + +// Stall endpoint, any queuing transfer should be removed from endpoint +void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); + +// clear stall, data toggle is also reset to DATA0 +// This API never calls with control endpoints, since it is auto cleared when receiving setup packet +void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr); + +//--------------------------------------------------------------------+ +// Event API (implemented by stack) +//--------------------------------------------------------------------+ + +// Called by DCD to notify device stack +extern void dcd_event_handler(dcd_event_t const * event, bool in_isr); + +// helper to send bus signal event +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = eid }; + dcd_event_handler(&event, in_isr); +} + +// helper to send bus reset event +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_reset (uint8_t rhport, tusb_speed_t speed, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_BUS_RESET }; + event.bus_reset.speed = speed; + dcd_event_handler(&event, in_isr); +} + +// helper to send setup received +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SETUP_RECEIVED }; + memcpy(&event.setup_received, setup, 8); + + dcd_event_handler(&event, in_isr); +} + +// helper to send transfer complete event +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_XFER_COMPLETE }; + + event.xfer_complete.ep_addr = ep_addr; + event.xfer_complete.len = xferred_bytes; + event.xfer_complete.result = result; + + dcd_event_handler(&event, in_isr); +} + +static inline void dcd_event_sof(uint8_t rhport, uint32_t frame_count, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SOF }; + event.sof.frame_count = frame_count; + dcd_event_handler(&event, in_isr); +} + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_DCD_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/device/usbd.c b/test-devices/loopback-stm32/lib/tinyusb/device/usbd.c new file mode 100644 index 00000000..c199e647 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/device/usbd.c @@ -0,0 +1,1389 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUD_ENABLED + +#include "device/dcd.h" +#include "tusb.h" +#include "common/tusb_private.h" + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +//--------------------------------------------------------------------+ +// USBD Configuration +//--------------------------------------------------------------------+ + +// Debug level of USBD +#define USBD_DBG 2 + +#ifndef CFG_TUD_TASK_QUEUE_SZ + #define CFG_TUD_TASK_QUEUE_SZ 16 +#endif + +//--------------------------------------------------------------------+ +// Device Data +//--------------------------------------------------------------------+ + +// Invalid driver ID in itf2drv[] ep2drv[][] mapping +enum { DRVID_INVALID = 0xFFu }; + +typedef struct +{ + struct TU_ATTR_PACKED + { + volatile uint8_t connected : 1; + volatile uint8_t addressed : 1; + volatile uint8_t suspended : 1; + + uint8_t remote_wakeup_en : 1; // enable/disable by host + uint8_t remote_wakeup_support : 1; // configuration descriptor's attribute + uint8_t self_powered : 1; // configuration descriptor's attribute + }; + + volatile uint8_t cfg_num; // current active configuration (0x00 is not configured) + uint8_t speed; + + uint8_t itf2drv[CFG_TUD_INTERFACE_MAX]; // map interface number to driver (0xff is invalid) + uint8_t ep2drv[CFG_TUD_ENDPPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid ), can use only 4-bit each + + tu_edpt_state_t ep_status[CFG_TUD_ENDPPOINT_MAX][2]; + +}usbd_device_t; + +static usbd_device_t _usbd_dev; + +//--------------------------------------------------------------------+ +// Class Driver +//--------------------------------------------------------------------+ +#if CFG_TUSB_DEBUG >= 2 + #define DRIVER_NAME(_name) .name = _name, +#else + #define DRIVER_NAME(_name) +#endif + +// Built-in class drivers +static usbd_class_driver_t const _usbd_driver[] = +{ + #if CFG_TUD_CDC + { + DRIVER_NAME("CDC") + .init = cdcd_init, + .reset = cdcd_reset, + .open = cdcd_open, + .control_xfer_cb = cdcd_control_xfer_cb, + .xfer_cb = cdcd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_MSC + { + DRIVER_NAME("MSC") + .init = mscd_init, + .reset = mscd_reset, + .open = mscd_open, + .control_xfer_cb = mscd_control_xfer_cb, + .xfer_cb = mscd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_HID + { + DRIVER_NAME("HID") + .init = hidd_init, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hidd_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_AUDIO + { + DRIVER_NAME("AUDIO") + .init = audiod_init, + .reset = audiod_reset, + .open = audiod_open, + .control_xfer_cb = audiod_control_xfer_cb, + .xfer_cb = audiod_xfer_cb, + .sof = audiod_sof_isr + }, + #endif + + #if CFG_TUD_VIDEO + { + DRIVER_NAME("VIDEO") + .init = videod_init, + .reset = videod_reset, + .open = videod_open, + .control_xfer_cb = videod_control_xfer_cb, + .xfer_cb = videod_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_MIDI + { + DRIVER_NAME("MIDI") + .init = midid_init, + .open = midid_open, + .reset = midid_reset, + .control_xfer_cb = midid_control_xfer_cb, + .xfer_cb = midid_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_VENDOR + { + DRIVER_NAME("VENDOR") + .init = vendord_init, + .reset = vendord_reset, + .open = vendord_open, + .control_xfer_cb = tud_vendor_control_xfer_cb, + .xfer_cb = vendord_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_USBTMC + { + DRIVER_NAME("TMC") + .init = usbtmcd_init_cb, + .reset = usbtmcd_reset_cb, + .open = usbtmcd_open_cb, + .control_xfer_cb = usbtmcd_control_xfer_cb, + .xfer_cb = usbtmcd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_DFU_RUNTIME + { + DRIVER_NAME("DFU-RUNTIME") + .init = dfu_rtd_init, + .reset = dfu_rtd_reset, + .open = dfu_rtd_open, + .control_xfer_cb = dfu_rtd_control_xfer_cb, + .xfer_cb = NULL, + .sof = NULL + }, + #endif + + #if CFG_TUD_DFU + { + DRIVER_NAME("DFU") + .init = dfu_moded_init, + .reset = dfu_moded_reset, + .open = dfu_moded_open, + .control_xfer_cb = dfu_moded_control_xfer_cb, + .xfer_cb = NULL, + .sof = NULL + }, + #endif + + #if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM + { + DRIVER_NAME("NET") + .init = netd_init, + .reset = netd_reset, + .open = netd_open, + .control_xfer_cb = netd_control_xfer_cb, + .xfer_cb = netd_xfer_cb, + .sof = NULL, + }, + #endif + + #if CFG_TUD_BTH + { + DRIVER_NAME("BTH") + .init = btd_init, + .reset = btd_reset, + .open = btd_open, + .control_xfer_cb = btd_control_xfer_cb, + .xfer_cb = btd_xfer_cb, + .sof = NULL + }, + #endif +}; + +enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(_usbd_driver) }; + +// Additional class drivers implemented by application +static usbd_class_driver_t const * _app_driver = NULL; +static uint8_t _app_driver_count = 0; + +// virtually joins built-in and application drivers together. +// Application is positioned first to allow overwriting built-in ones. +static inline usbd_class_driver_t const * get_driver(uint8_t drvid) +{ + // Application drivers + if ( usbd_app_driver_get_cb ) + { + if ( drvid < _app_driver_count ) return &_app_driver[drvid]; + drvid -= _app_driver_count; + } + + // Built-in drivers + if (drvid < BUILTIN_DRIVER_COUNT) return &_usbd_driver[drvid]; + + return NULL; +} + +#define TOTAL_DRIVER_COUNT (_app_driver_count + BUILTIN_DRIVER_COUNT) + +//--------------------------------------------------------------------+ +// DCD Event +//--------------------------------------------------------------------+ + +enum { RHPORT_INVALID = 0xFFu }; +static uint8_t _usbd_rhport = RHPORT_INVALID; + +// Event queue +// usbd_int_set() is used as mutex in OS NONE config +OSAL_QUEUE_DEF(usbd_int_set, _usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t); +static osal_queue_t _usbd_q; + +// Mutex for claiming endpoint, only needed when using with preempted RTOS +#if CFG_TUSB_OS != OPT_OS_NONE +static osal_mutex_def_t _ubsd_mutexdef; +static osal_mutex_t _usbd_mutex; +#endif + + +//--------------------------------------------------------------------+ +// Prototypes +//--------------------------------------------------------------------+ +static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request); +static bool process_set_config(uint8_t rhport, uint8_t cfg_num); +static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request); + +// from usbd_control.c +void usbd_control_reset(void); +void usbd_control_set_request(tusb_control_request_t const *request); +void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp ); +bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); + + +//--------------------------------------------------------------------+ +// Debug +//--------------------------------------------------------------------+ +#if CFG_TUSB_DEBUG >= 2 +static char const* const _usbd_event_str[DCD_EVENT_COUNT] = +{ + "Invalid" , + "Bus Reset" , + "Unplugged" , + "SOF" , + "Suspend" , + "Resume" , + "Setup Received" , + "Xfer Complete" , + "Func Call" +}; + +// for usbd_control to print the name of control complete driver +void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback) +{ + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) + { + usbd_class_driver_t const * driver = get_driver(i); + if ( driver && driver->control_xfer_cb == callback ) + { + TU_LOG(USBD_DBG, " %s control complete\r\n", driver->name); + return; + } + } +} + +#endif + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ +tusb_speed_t tud_speed_get(void) +{ + return (tusb_speed_t) _usbd_dev.speed; +} + +bool tud_connected(void) +{ + return _usbd_dev.connected; +} + +bool tud_mounted(void) +{ + return _usbd_dev.cfg_num ? true : false; +} + +bool tud_suspended(void) +{ + return _usbd_dev.suspended; +} + +bool tud_remote_wakeup(void) +{ + // only wake up host if this feature is supported and enabled and we are suspended + TU_VERIFY (_usbd_dev.suspended && _usbd_dev.remote_wakeup_support && _usbd_dev.remote_wakeup_en ); + dcd_remote_wakeup(_usbd_rhport); + return true; +} + +bool tud_disconnect(void) +{ + TU_VERIFY(dcd_disconnect); + dcd_disconnect(_usbd_rhport); + return true; +} + +bool tud_connect(void) +{ + TU_VERIFY(dcd_connect); + dcd_connect(_usbd_rhport); + return true; +} + +//--------------------------------------------------------------------+ +// USBD Task +//--------------------------------------------------------------------+ +bool tud_inited(void) +{ + return _usbd_rhport != RHPORT_INVALID; +} + +bool tud_init (uint8_t rhport) +{ + // skip if already initialized + if ( tud_inited() ) return true; + + TU_LOG(USBD_DBG, "USBD init on controller %u\r\n", rhport); + TU_LOG_INT(USBD_DBG, sizeof(usbd_device_t)); + + tu_varclr(&_usbd_dev); + +#if CFG_TUSB_OS != OPT_OS_NONE + // Init device mutex + _usbd_mutex = osal_mutex_create(&_ubsd_mutexdef); + TU_ASSERT(_usbd_mutex); +#endif + + // Init device queue & task + _usbd_q = osal_queue_create(&_usbd_qdef); + TU_ASSERT(_usbd_q); + + // Get application driver if available + if ( usbd_app_driver_get_cb ) + { + _app_driver = usbd_app_driver_get_cb(&_app_driver_count); + } + + // Init class drivers + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) + { + usbd_class_driver_t const * driver = get_driver(i); + TU_ASSERT(driver); + TU_LOG(USBD_DBG, "%s init\r\n", driver->name); + driver->init(); + } + + _usbd_rhport = rhport; + + // Init device controller driver + dcd_init(rhport); + dcd_int_enable(rhport); + + return true; +} + +static void configuration_reset(uint8_t rhport) +{ + for ( uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++ ) + { + usbd_class_driver_t const * driver = get_driver(i); + TU_ASSERT(driver, ); + driver->reset(rhport); + } + + tu_varclr(&_usbd_dev); + memset(_usbd_dev.itf2drv, DRVID_INVALID, sizeof(_usbd_dev.itf2drv)); // invalid mapping + memset(_usbd_dev.ep2drv , DRVID_INVALID, sizeof(_usbd_dev.ep2drv )); // invalid mapping +} + +static void usbd_reset(uint8_t rhport) +{ + configuration_reset(rhport); + usbd_control_reset(); +} + +bool tud_task_event_ready(void) +{ + // Skip if stack is not initialized + if ( !tusb_inited() ) return false; + + return !osal_queue_empty(_usbd_q); +} + +/* USB Device Driver task + * This top level thread manages all device controller event and delegates events to class-specific drivers. + * This should be called periodically within the mainloop or rtos thread. + * + @code + int main(void) + { + application_init(); + tusb_init(); + + while(1) // the mainloop + { + application_code(); + tud_task(); // tinyusb device task + } + } + @endcode + */ +void tud_task_ext(uint32_t timeout_ms, bool in_isr) +{ + (void) in_isr; // not implemented yet + + // Skip if stack is not initialized + if ( !tusb_inited() ) return; + + // Loop until there is no more events in the queue + while (1) + { + dcd_event_t event; + if ( !osal_queue_receive(_usbd_q, &event, timeout_ms) ) return; + +#if CFG_TUSB_DEBUG >= 2 + if (event.event_id == DCD_EVENT_SETUP_RECEIVED) TU_LOG(USBD_DBG, "\r\n"); // extra line for setup + TU_LOG(USBD_DBG, "USBD %s ", event.event_id < DCD_EVENT_COUNT ? _usbd_event_str[event.event_id] : "CORRUPTED"); +#endif + + switch ( event.event_id ) + { + case DCD_EVENT_BUS_RESET: + TU_LOG(USBD_DBG, ": %s Speed\r\n", tu_str_speed[event.bus_reset.speed]); + usbd_reset(event.rhport); + _usbd_dev.speed = event.bus_reset.speed; + break; + + case DCD_EVENT_UNPLUGGED: + TU_LOG(USBD_DBG, "\r\n"); + usbd_reset(event.rhport); + + // invoke callback + if (tud_umount_cb) tud_umount_cb(); + break; + + case DCD_EVENT_SETUP_RECEIVED: + TU_LOG_VAR(USBD_DBG, &event.setup_received); + TU_LOG(USBD_DBG, "\r\n"); + + // Mark as connected after receiving 1st setup packet. + // But it is easier to set it every time instead of wasting time to check then set + _usbd_dev.connected = 1; + + // mark both in & out control as free + _usbd_dev.ep_status[0][TUSB_DIR_OUT].busy = false; + _usbd_dev.ep_status[0][TUSB_DIR_OUT].claimed = 0; + _usbd_dev.ep_status[0][TUSB_DIR_IN ].busy = false; + _usbd_dev.ep_status[0][TUSB_DIR_IN ].claimed = 0; + + // Process control request + if ( !process_control_request(event.rhport, &event.setup_received) ) + { + TU_LOG(USBD_DBG, " Stall EP0\r\n"); + // Failed -> stall both control endpoint IN and OUT + dcd_edpt_stall(event.rhport, 0); + dcd_edpt_stall(event.rhport, 0 | TUSB_DIR_IN_MASK); + } + break; + + case DCD_EVENT_XFER_COMPLETE: + { + // Invoke the class callback associated with the endpoint address + uint8_t const ep_addr = event.xfer_complete.ep_addr; + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const ep_dir = tu_edpt_dir(ep_addr); + + TU_LOG(USBD_DBG, "on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len); + + _usbd_dev.ep_status[epnum][ep_dir].busy = false; + _usbd_dev.ep_status[epnum][ep_dir].claimed = 0; + + if ( 0 == epnum ) + { + usbd_control_xfer_cb(event.rhport, ep_addr, (xfer_result_t)event.xfer_complete.result, event.xfer_complete.len); + } + else + { + usbd_class_driver_t const * driver = get_driver( _usbd_dev.ep2drv[epnum][ep_dir] ); + TU_ASSERT(driver, ); + + TU_LOG(USBD_DBG, " %s xfer callback\r\n", driver->name); + driver->xfer_cb(event.rhport, ep_addr, (xfer_result_t)event.xfer_complete.result, event.xfer_complete.len); + } + } + break; + + case DCD_EVENT_SUSPEND: + // NOTE: When plugging/unplugging device, the D+/D- state are unstable and + // can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ), which result in a series of event + // e.g suspend -> resume -> unplug/plug. Skip suspend/resume if not connected + if ( _usbd_dev.connected ) + { + TU_LOG(USBD_DBG, ": Remote Wakeup = %u\r\n", _usbd_dev.remote_wakeup_en); + if (tud_suspend_cb) tud_suspend_cb(_usbd_dev.remote_wakeup_en); + }else + { + TU_LOG(USBD_DBG, " Skipped\r\n"); + } + break; + + case DCD_EVENT_RESUME: + if ( _usbd_dev.connected ) + { + TU_LOG(USBD_DBG, "\r\n"); + if (tud_resume_cb) tud_resume_cb(); + }else + { + TU_LOG(USBD_DBG, " Skipped\r\n"); + } + break; + + case USBD_EVENT_FUNC_CALL: + TU_LOG(USBD_DBG, "\r\n"); + if ( event.func_call.func ) event.func_call.func(event.func_call.param); + break; + + case DCD_EVENT_SOF: + default: + TU_BREAKPOINT(); + break; + } + +#if CFG_TUSB_OS != OPT_OS_NONE && CFG_TUSB_OS != OPT_OS_PICO + // return if there is no more events, for application to run other background + if (osal_queue_empty(_usbd_q)) return; +#endif + } +} + +//--------------------------------------------------------------------+ +// Control Request Parser & Handling +//--------------------------------------------------------------------+ + +// Helper to invoke class driver control request handler +static bool invoke_class_control(uint8_t rhport, usbd_class_driver_t const * driver, tusb_control_request_t const * request) +{ + usbd_control_set_complete_callback(driver->control_xfer_cb); + TU_LOG(USBD_DBG, " %s control request\r\n", driver->name); + return driver->control_xfer_cb(rhport, CONTROL_STAGE_SETUP, request); +} + +// This handles the actual request and its response. +// return false will cause its caller to stall control endpoint +static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request) +{ + usbd_control_set_complete_callback(NULL); + + TU_ASSERT(p_request->bmRequestType_bit.type < TUSB_REQ_TYPE_INVALID); + + // Vendor request + if ( p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR ) + { + TU_VERIFY(tud_vendor_control_xfer_cb); + + usbd_control_set_complete_callback(tud_vendor_control_xfer_cb); + return tud_vendor_control_xfer_cb(rhport, CONTROL_STAGE_SETUP, p_request); + } + +#if CFG_TUSB_DEBUG >= 2 + if (TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type && p_request->bRequest <= TUSB_REQ_SYNCH_FRAME) + { + TU_LOG(USBD_DBG, " %s", tu_str_std_request[p_request->bRequest]); + if (TUSB_REQ_GET_DESCRIPTOR != p_request->bRequest) TU_LOG(USBD_DBG, "\r\n"); + } +#endif + + switch ( p_request->bmRequestType_bit.recipient ) + { + //------------- Device Requests e.g in enumeration -------------// + case TUSB_REQ_RCPT_DEVICE: + if ( TUSB_REQ_TYPE_CLASS == p_request->bmRequestType_bit.type ) + { + uint8_t const itf = tu_u16_low(p_request->wIndex); + TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv)); + + usbd_class_driver_t const * driver = get_driver(_usbd_dev.itf2drv[itf]); + TU_VERIFY(driver); + + // forward to class driver: "non-STD request to Interface" + return invoke_class_control(rhport, driver, p_request); + } + + if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) + { + // Non standard request is not supported + TU_BREAKPOINT(); + return false; + } + + switch ( p_request->bRequest ) + { + case TUSB_REQ_SET_ADDRESS: + // Depending on mcu, status phase could be sent either before or after changing device address, + // or even require stack to not response with status at all + // Therefore DCD must take full responsibility to response and include zlp status packet if needed. + usbd_control_set_request(p_request); // set request since DCD has no access to tud_control_status() API + dcd_set_address(rhport, (uint8_t) p_request->wValue); + // skip tud_control_status() + _usbd_dev.addressed = 1; + break; + + case TUSB_REQ_GET_CONFIGURATION: + { + uint8_t cfg_num = _usbd_dev.cfg_num; + tud_control_xfer(rhport, p_request, &cfg_num, 1); + } + break; + + case TUSB_REQ_SET_CONFIGURATION: + { + uint8_t const cfg_num = (uint8_t) p_request->wValue; + + // Only process if new configure is different + if (_usbd_dev.cfg_num != cfg_num) + { + if ( _usbd_dev.cfg_num ) + { + // already configured: need to clear all endpoints and driver first + TU_LOG(USBD_DBG, " Clear current Configuration (%u) before switching\r\n", _usbd_dev.cfg_num); + + // close all non-control endpoints, cancel all pending transfers if any + dcd_edpt_close_all(rhport); + + // close all drivers and current configured state except bus speed + uint8_t const speed = _usbd_dev.speed; + configuration_reset(rhport); + + _usbd_dev.speed = speed; // restore speed + } + + // switch to new configuration if not zero + if ( cfg_num ) TU_ASSERT( process_set_config(rhport, cfg_num) ); + } + + _usbd_dev.cfg_num = cfg_num; + tud_control_status(rhport, p_request); + } + break; + + case TUSB_REQ_GET_DESCRIPTOR: + TU_VERIFY( process_get_descriptor(rhport, p_request) ); + break; + + case TUSB_REQ_SET_FEATURE: + // Only support remote wakeup for device feature + TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue); + + TU_LOG(USBD_DBG, " Enable Remote Wakeup\r\n"); + + // Host may enable remote wake up before suspending especially HID device + _usbd_dev.remote_wakeup_en = true; + tud_control_status(rhport, p_request); + break; + + case TUSB_REQ_CLEAR_FEATURE: + // Only support remote wakeup for device feature + TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue); + + TU_LOG(USBD_DBG, " Disable Remote Wakeup\r\n"); + + // Host may disable remote wake up after resuming + _usbd_dev.remote_wakeup_en = false; + tud_control_status(rhport, p_request); + break; + + case TUSB_REQ_GET_STATUS: + { + // Device status bit mask + // - Bit 0: Self Powered + // - Bit 1: Remote Wakeup enabled + uint16_t status = (uint16_t) ((_usbd_dev.self_powered ? 1u : 0u) | (_usbd_dev.remote_wakeup_en ? 2u : 0u)); + tud_control_xfer(rhport, p_request, &status, 2); + } + break; + + // Unknown/Unsupported request + default: TU_BREAKPOINT(); return false; + } + break; + + //------------- Class/Interface Specific Request -------------// + case TUSB_REQ_RCPT_INTERFACE: + { + uint8_t const itf = tu_u16_low(p_request->wIndex); + TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv)); + + usbd_class_driver_t const * driver = get_driver(_usbd_dev.itf2drv[itf]); + TU_VERIFY(driver); + + // all requests to Interface (STD or Class) is forwarded to class driver. + // notable requests are: GET HID REPORT DESCRIPTOR, SET_INTERFACE, GET_INTERFACE + if ( !invoke_class_control(rhport, driver, p_request) ) + { + // For GET_INTERFACE and SET_INTERFACE, it is mandatory to respond even if the class + // driver doesn't use alternate settings or implement this + TU_VERIFY(TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type); + + switch(p_request->bRequest) + { + case TUSB_REQ_GET_INTERFACE: + case TUSB_REQ_SET_INTERFACE: + // Clear complete callback if driver set since it can also stall the request. + usbd_control_set_complete_callback(NULL); + + if (TUSB_REQ_GET_INTERFACE == p_request->bRequest) + { + uint8_t alternate = 0; + tud_control_xfer(rhport, p_request, &alternate, 1); + }else + { + tud_control_status(rhport, p_request); + } + break; + + default: return false; + } + } + } + break; + + //------------- Endpoint Request -------------// + case TUSB_REQ_RCPT_ENDPOINT: + { + uint8_t const ep_addr = tu_u16_low(p_request->wIndex); + uint8_t const ep_num = tu_edpt_number(ep_addr); + uint8_t const ep_dir = tu_edpt_dir(ep_addr); + + TU_ASSERT(ep_num < TU_ARRAY_SIZE(_usbd_dev.ep2drv) ); + + usbd_class_driver_t const * driver = get_driver(_usbd_dev.ep2drv[ep_num][ep_dir]); + + if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) + { + // Forward class request to its driver + TU_VERIFY(driver); + return invoke_class_control(rhport, driver, p_request); + } + else + { + // Handle STD request to endpoint + switch ( p_request->bRequest ) + { + case TUSB_REQ_GET_STATUS: + { + uint16_t status = usbd_edpt_stalled(rhport, ep_addr) ? 0x0001 : 0x0000; + tud_control_xfer(rhport, p_request, &status, 2); + } + break; + + case TUSB_REQ_CLEAR_FEATURE: + case TUSB_REQ_SET_FEATURE: + { + if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) + { + if ( TUSB_REQ_CLEAR_FEATURE == p_request->bRequest ) + { + usbd_edpt_clear_stall(rhport, ep_addr); + }else + { + usbd_edpt_stall(rhport, ep_addr); + } + } + + if (driver) + { + // Some classes such as USBTMC needs to clear/re-init its buffer when receiving CLEAR_FEATURE request + // We will also forward std request targeted endpoint to class drivers as well + + // STD request must always be ACKed regardless of driver returned value + // Also clear complete callback if driver set since it can also stall the request. + (void) invoke_class_control(rhport, driver, p_request); + usbd_control_set_complete_callback(NULL); + + // skip ZLP status if driver already did that + if ( !_usbd_dev.ep_status[0][TUSB_DIR_IN].busy ) tud_control_status(rhport, p_request); + } + } + break; + + // Unknown/Unsupported request + default: TU_BREAKPOINT(); return false; + } + } + } + break; + + // Unknown recipient + default: TU_BREAKPOINT(); return false; + } + + return true; +} + +// Process Set Configure Request +// This function parse configuration descriptor & open drivers accordingly +static bool process_set_config(uint8_t rhport, uint8_t cfg_num) +{ + // index is cfg_num-1 + tusb_desc_configuration_t const * desc_cfg = (tusb_desc_configuration_t const *) tud_descriptor_configuration_cb(cfg_num-1); + TU_ASSERT(desc_cfg != NULL && desc_cfg->bDescriptorType == TUSB_DESC_CONFIGURATION); + + // Parse configuration descriptor + _usbd_dev.remote_wakeup_support = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP) ? 1u : 0u; + _usbd_dev.self_powered = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_SELF_POWERED ) ? 1u : 0u; + + // Parse interface descriptor + uint8_t const * p_desc = ((uint8_t const*) desc_cfg) + sizeof(tusb_desc_configuration_t); + uint8_t const * desc_end = ((uint8_t const*) desc_cfg) + tu_le16toh(desc_cfg->wTotalLength); + + while( p_desc < desc_end ) + { + uint8_t assoc_itf_count = 1; + + // Class will always starts with Interface Association (if any) and then Interface descriptor + if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) ) + { + tusb_desc_interface_assoc_t const * desc_iad = (tusb_desc_interface_assoc_t const *) p_desc; + assoc_itf_count = desc_iad->bInterfaceCount; + + p_desc = tu_desc_next(p_desc); // next to Interface + + // IAD's first interface number and class should match with opened interface + //TU_ASSERT(desc_iad->bFirstInterface == desc_itf->bInterfaceNumber && + // desc_iad->bFunctionClass == desc_itf->bInterfaceClass); + } + + TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) ); + tusb_desc_interface_t const * desc_itf = (tusb_desc_interface_t const*) p_desc; + + // Find driver for this interface + uint16_t const remaining_len = (uint16_t) (desc_end-p_desc); + uint8_t drv_id; + for (drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) + { + usbd_class_driver_t const *driver = get_driver(drv_id); + TU_ASSERT(driver); + uint16_t const drv_len = driver->open(rhport, desc_itf, remaining_len); + + if ( (sizeof(tusb_desc_interface_t) <= drv_len) && (drv_len <= remaining_len) ) + { + // Open successfully + TU_LOG(USBD_DBG, " %s opened\r\n", driver->name); + + // Some drivers use 2 or more interfaces but may not have IAD e.g MIDI (always) or + // BTH (even CDC) with class in device descriptor (single interface) + if ( assoc_itf_count == 1) + { + #if CFG_TUD_CDC + if ( driver->open == cdcd_open ) assoc_itf_count = 2; + #endif + + #if CFG_TUD_MIDI + if ( driver->open == midid_open ) assoc_itf_count = 2; + #endif + + #if CFG_TUD_BTH && CFG_TUD_BTH_ISO_ALT_COUNT + if ( driver->open == btd_open ) assoc_itf_count = 2; + #endif + } + + // bind (associated) interfaces to found driver + for(uint8_t i=0; ibInterfaceNumber+i; + + // Interface number must not be used already + TU_ASSERT(DRVID_INVALID == _usbd_dev.itf2drv[itf_num]); + _usbd_dev.itf2drv[itf_num] = drv_id; + } + + // bind all endpoints to found driver + tu_edpt_bind_driver(_usbd_dev.ep2drv, desc_itf, drv_len, drv_id); + + // next Interface + p_desc += drv_len; + + break; // exit driver find loop + } + } + + // Failed if there is no supported drivers + TU_ASSERT(drv_id < TOTAL_DRIVER_COUNT); + } + + // invoke callback + if (tud_mount_cb) tud_mount_cb(); + + return true; +} + +// return descriptor's buffer and update desc_len +static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request) +{ + tusb_desc_type_t const desc_type = (tusb_desc_type_t) tu_u16_high(p_request->wValue); + uint8_t const desc_index = tu_u16_low( p_request->wValue ); + + switch(desc_type) + { + case TUSB_DESC_DEVICE: + { + TU_LOG(USBD_DBG, " Device\r\n"); + + void* desc_device = (void*) (uintptr_t) tud_descriptor_device_cb(); + + // Only response with exactly 1 Packet if: not addressed and host requested more data than device descriptor has. + // This only happens with the very first get device descriptor and EP0 size = 8 or 16. + if ((CFG_TUD_ENDPOINT0_SIZE < sizeof(tusb_desc_device_t)) && !_usbd_dev.addressed && + ((tusb_control_request_t const*) p_request)->wLength > sizeof(tusb_desc_device_t)) + { + // Hack here: we modify the request length to prevent usbd_control response with zlp + // since we are responding with 1 packet & less data than wLength. + tusb_control_request_t mod_request = *p_request; + mod_request.wLength = CFG_TUD_ENDPOINT0_SIZE; + + return tud_control_xfer(rhport, &mod_request, desc_device, CFG_TUD_ENDPOINT0_SIZE); + }else + { + return tud_control_xfer(rhport, p_request, desc_device, sizeof(tusb_desc_device_t)); + } + } + // break; // unreachable + + case TUSB_DESC_BOS: + { + TU_LOG(USBD_DBG, " BOS\r\n"); + + // requested by host if USB > 2.0 ( i.e 2.1 or 3.x ) + if (!tud_descriptor_bos_cb) return false; + + uintptr_t desc_bos = (uintptr_t) tud_descriptor_bos_cb(); + TU_ASSERT(desc_bos); + + // Use offsetof to avoid pointer to the odd/misaligned address + uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_bos + offsetof(tusb_desc_bos_t, wTotalLength))) ); + + return tud_control_xfer(rhport, p_request, (void*) desc_bos, total_len); + } + // break; // unreachable + + case TUSB_DESC_CONFIGURATION: + case TUSB_DESC_OTHER_SPEED_CONFIG: + { + uintptr_t desc_config; + + if ( desc_type == TUSB_DESC_CONFIGURATION ) + { + TU_LOG(USBD_DBG, " Configuration[%u]\r\n", desc_index); + desc_config = (uintptr_t) tud_descriptor_configuration_cb(desc_index); + }else + { + // Host only request this after getting Device Qualifier descriptor + TU_LOG(USBD_DBG, " Other Speed Configuration\r\n"); + TU_VERIFY( tud_descriptor_other_speed_configuration_cb ); + desc_config = (uintptr_t) tud_descriptor_other_speed_configuration_cb(desc_index); + } + + TU_ASSERT(desc_config); + + // Use offsetof to avoid pointer to the odd/misaligned address + uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_config + offsetof(tusb_desc_configuration_t, wTotalLength))) ); + + return tud_control_xfer(rhport, p_request, (void*) desc_config, total_len); + } + // break; // unreachable + + case TUSB_DESC_STRING: + { + TU_LOG(USBD_DBG, " String[%u]\r\n", desc_index); + + // String Descriptor always uses the desc set from user + uint8_t const* desc_str = (uint8_t const*) tud_descriptor_string_cb(desc_index, tu_le16toh(p_request->wIndex)); + TU_VERIFY(desc_str); + + // first byte of descriptor is its size + return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_str, tu_desc_len(desc_str)); + } + // break; // unreachable + + case TUSB_DESC_DEVICE_QUALIFIER: + { + TU_LOG(USBD_DBG, " Device Qualifier\r\n"); + + TU_VERIFY( tud_descriptor_device_qualifier_cb ); + + uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb(); + TU_VERIFY(desc_qualifier); + + // first byte of descriptor is its size + return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_qualifier, tu_desc_len(desc_qualifier)); + } + // break; // unreachable + + default: return false; + } +} + +//--------------------------------------------------------------------+ +// DCD Event Handler +//--------------------------------------------------------------------+ +TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const * event, bool in_isr) +{ + switch (event->event_id) + { + case DCD_EVENT_UNPLUGGED: + _usbd_dev.connected = 0; + _usbd_dev.addressed = 0; + _usbd_dev.cfg_num = 0; + _usbd_dev.suspended = 0; + osal_queue_send(_usbd_q, event, in_isr); + break; + + case DCD_EVENT_SUSPEND: + // NOTE: When plugging/unplugging device, the D+/D- state are unstable and + // can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ). + // In addition, some MCUs such as SAMD or boards that haven no VBUS detection cannot distinguish + // suspended vs disconnected. We will skip handling SUSPEND/RESUME event if not currently connected + if ( _usbd_dev.connected ) + { + _usbd_dev.suspended = 1; + osal_queue_send(_usbd_q, event, in_isr); + } + break; + + case DCD_EVENT_RESUME: + // skip event if not connected (especially required for SAMD) + if ( _usbd_dev.connected ) + { + _usbd_dev.suspended = 0; + osal_queue_send(_usbd_q, event, in_isr); + } + break; + + case DCD_EVENT_SOF: + // SOF driver handler in ISR context + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) + { + usbd_class_driver_t const * driver = get_driver(i); + if (driver && driver->sof) + { + driver->sof(event->rhport, event->sof.frame_count); + } + } + + // Some MCUs after running dcd_remote_wakeup() does not have way to detect the end of remote wakeup + // which last 1-15 ms. DCD can use SOF as a clear indicator that bus is back to operational + if ( _usbd_dev.suspended ) + { + _usbd_dev.suspended = 0; + + dcd_event_t const event_resume = { .rhport = event->rhport, .event_id = DCD_EVENT_RESUME }; + osal_queue_send(_usbd_q, &event_resume, in_isr); + } + + // skip osal queue for SOF in usbd task + break; + + default: + osal_queue_send(_usbd_q, event, in_isr); + break; + } +} + +//--------------------------------------------------------------------+ +// USBD API For Class Driver +//--------------------------------------------------------------------+ + +void usbd_int_set(bool enabled) +{ + if (enabled) + { + dcd_int_enable(_usbd_rhport); + }else + { + dcd_int_disable(_usbd_rhport); + } +} + +// Parse consecutive endpoint descriptors (IN & OUT) +bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in) +{ + for(int i=0; ibDescriptorType && xfer_type == desc_ep->bmAttributes.xfer); + TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); + + if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) + { + (*ep_in) = desc_ep->bEndpointAddress; + }else + { + (*ep_out) = desc_ep->bEndpointAddress; + } + + p_desc = tu_desc_next(p_desc); + } + + return true; +} + +// Helper to defer an isr function +void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr) +{ + dcd_event_t event = + { + .rhport = 0, + .event_id = USBD_EVENT_FUNC_CALL, + }; + + event.func_call.func = func; + event.func_call.param = param; + + dcd_event_handler(&event, in_isr); +} + +//--------------------------------------------------------------------+ +// USBD Endpoint API +//--------------------------------------------------------------------+ + +bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) +{ + rhport = _usbd_rhport; + + TU_ASSERT(tu_edpt_number(desc_ep->bEndpointAddress) < CFG_TUD_ENDPPOINT_MAX); + TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed)); + + return dcd_edpt_open(rhport, desc_ep); +} + +bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + + // TODO add this check later, also make sure we don't starve an out endpoint while suspending + // TU_VERIFY(tud_ready()); + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir]; + +#if TUSB_OPT_MUTEX + return tu_edpt_claim(ep_state, _usbd_mutex); +#else + return tu_edpt_claim(ep_state, NULL); +#endif +} + +bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir]; + +#if TUSB_OPT_MUTEX + return tu_edpt_release(ep_state, _usbd_mutex); +#else + return tu_edpt_release(ep_state, NULL); +#endif +} + +bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +{ + rhport = _usbd_rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + // TODO skip ready() check for now since enumeration also use this API + // TU_VERIFY(tud_ready()); + + TU_LOG(USBD_DBG, " Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes); + + // Attempt to transfer on a busy endpoint, sound like an race condition ! + TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0); + + // Set busy first since the actual transfer can be complete before dcd_edpt_xfer() + // could return and USBD task can preempt and clear the busy + _usbd_dev.ep_status[epnum][dir].busy = true; + + if ( dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes) ) + { + return true; + }else + { + // DCD error, mark endpoint as ready to allow next transfer + _usbd_dev.ep_status[epnum][dir].busy = false; + _usbd_dev.ep_status[epnum][dir].claimed = 0; + TU_LOG(USBD_DBG, "FAILED\r\n"); + TU_BREAKPOINT(); + return false; + } +} + +// The number of bytes has to be given explicitly to allow more flexible control of how many +// bytes should be written and second to keep the return value free to give back a boolean +// success message. If total_bytes is too big, the FIFO will copy only what is available +// into the USB buffer! +bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + rhport = _usbd_rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + TU_LOG(USBD_DBG, " Queue ISO EP %02X with %u bytes ... ", ep_addr, total_bytes); + + // Attempt to transfer on a busy endpoint, sound like an race condition ! + TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0); + + // Set busy first since the actual transfer can be complete before dcd_edpt_xfer() could return + // and usbd task can preempt and clear the busy + _usbd_dev.ep_status[epnum][dir].busy = true; + + if (dcd_edpt_xfer_fifo(rhport, ep_addr, ff, total_bytes)) + { + TU_LOG(USBD_DBG, "OK\r\n"); + return true; + }else + { + // DCD error, mark endpoint as ready to allow next transfer + _usbd_dev.ep_status[epnum][dir].busy = false; + _usbd_dev.ep_status[epnum][dir].claimed = 0; + TU_LOG(USBD_DBG, "failed\r\n"); + TU_BREAKPOINT(); + return false; + } +} + +bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + return _usbd_dev.ep_status[epnum][dir].busy; +} + +void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr) +{ + rhport = _usbd_rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + // only stalled if currently cleared + if ( !_usbd_dev.ep_status[epnum][dir].stalled ) + { + TU_LOG(USBD_DBG, " Stall EP %02X\r\n", ep_addr); + dcd_edpt_stall(rhport, ep_addr); + _usbd_dev.ep_status[epnum][dir].stalled = true; + _usbd_dev.ep_status[epnum][dir].busy = true; + } +} + +void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) +{ + rhport = _usbd_rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + // only clear if currently stalled + if ( _usbd_dev.ep_status[epnum][dir].stalled ) + { + TU_LOG(USBD_DBG, " Clear Stall EP %02X\r\n", ep_addr); + dcd_edpt_clear_stall(rhport, ep_addr); + _usbd_dev.ep_status[epnum][dir].stalled = false; + _usbd_dev.ep_status[epnum][dir].busy = false; + } +} + +bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + return _usbd_dev.ep_status[epnum][dir].stalled; +} + +/** + * usbd_edpt_close will disable an endpoint. + * + * In progress transfers on this EP may be delivered after this call. + * + */ +void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) +{ + rhport = _usbd_rhport; + + TU_ASSERT(dcd_edpt_close, /**/); + TU_LOG(USBD_DBG, " CLOSING Endpoint: 0x%02X\r\n", ep_addr); + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + dcd_edpt_close(rhport, ep_addr); + _usbd_dev.ep_status[epnum][dir].stalled = false; + _usbd_dev.ep_status[epnum][dir].busy = false; + _usbd_dev.ep_status[epnum][dir].claimed = false; + + return; +} + +void usbd_sof_enable(uint8_t rhport, bool en) +{ + rhport = _usbd_rhport; + + // TODO: Check needed if all drivers including the user sof_cb does not need an active SOF ISR any more. + // Only if all drivers switched off SOF calls the SOF interrupt may be disabled + dcd_sof_enable(rhport, en); +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/device/usbd.h b/test-devices/loopback-stm32/lib/tinyusb/device/usbd.h new file mode 100644 index 00000000..17b4d927 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/device/usbd.h @@ -0,0 +1,865 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_USBD_H_ +#define _TUSB_USBD_H_ + +#include "common/tusb_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + +// Init device stack +bool tud_init (uint8_t rhport); + +// Check if device stack is already initialized +bool tud_inited(void); + +// Task function should be called in main/rtos loop, extended version of tud_task() +// - timeout_ms: millisecond to wait, zero = no wait, 0xFFFFFFFF = wait forever +// - in_isr: if function is called in ISR +void tud_task_ext(uint32_t timeout_ms, bool in_isr); + +// Task function should be called in main/rtos loop +TU_ATTR_ALWAYS_INLINE static inline +void tud_task (void) +{ + tud_task_ext(UINT32_MAX, false); +} + +// Check if there is pending events need processing by tud_task() +bool tud_task_event_ready(void); + +#ifndef _TUSB_DCD_H_ +extern void dcd_int_handler(uint8_t rhport); +#endif + +// Interrupt handler, name alias to DCD +#define tud_int_handler dcd_int_handler + +// Get current bus speed +tusb_speed_t tud_speed_get(void); + +// Check if device is connected (may not mounted/configured yet) +// True if just got out of Bus Reset and received the very first data from host +bool tud_connected(void); + +// Check if device is connected and configured +bool tud_mounted(void); + +// Check if device is suspended +bool tud_suspended(void); + +// Check if device is ready to transfer +TU_ATTR_ALWAYS_INLINE static inline +bool tud_ready(void) +{ + return tud_mounted() && !tud_suspended(); +} + +// Remote wake up host, only if suspended and enabled by host +bool tud_remote_wakeup(void); + +// Enable pull-up resistor on D+ D- +// Return false on unsupported MCUs +bool tud_disconnect(void); + +// Disable pull-up resistor on D+ D- +// Return false on unsupported MCUs +bool tud_connect(void); + +// Carry out Data and Status stage of control transfer +// - If len = 0, it is equivalent to sending status only +// - If len > wLength : it will be truncated +bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len); + +// Send STATUS (zero length) packet +bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request); + +//--------------------------------------------------------------------+ +// Application Callbacks (WEAK is optional) +//--------------------------------------------------------------------+ + +// Invoked when received GET DEVICE DESCRIPTOR request +// Application return pointer to descriptor +uint8_t const * tud_descriptor_device_cb(void); + +// Invoked when received GET CONFIGURATION DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +uint8_t const * tud_descriptor_configuration_cb(uint8_t index); + +// Invoked when received GET STRING DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid); + +// Invoked when received GET BOS DESCRIPTOR request +// Application return pointer to descriptor +TU_ATTR_WEAK uint8_t const * tud_descriptor_bos_cb(void); + +// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. +// device_qualifier descriptor describes information about a high-speed capable device that would +// change if the device were operating at the other speed. If not highspeed capable stall this request. +TU_ATTR_WEAK uint8_t const* tud_descriptor_device_qualifier_cb(void); + +// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa +TU_ATTR_WEAK uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index); + +// Invoked when device is mounted (configured) +TU_ATTR_WEAK void tud_mount_cb(void); + +// Invoked when device is unmounted +TU_ATTR_WEAK void tud_umount_cb(void); + +// Invoked when usb bus is suspended +// Within 7ms, device must draw an average of current less than 2.5 mA from bus +TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en); + +// Invoked when usb bus is resumed +TU_ATTR_WEAK void tud_resume_cb(void); + +// Invoked when received control request with VENDOR TYPE +TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + +//--------------------------------------------------------------------+ +// Binary Device Object Store (BOS) Descriptor Templates +//--------------------------------------------------------------------+ + +#define TUD_BOS_DESC_LEN 5 + +// total length, number of device caps +#define TUD_BOS_DESCRIPTOR(_total_len, _caps_num) \ + 5, TUSB_DESC_BOS, U16_TO_U8S_LE(_total_len), _caps_num + +// Device Capability Platform 128-bit UUID + Data +#define TUD_BOS_PLATFORM_DESCRIPTOR(...) \ + 4+TU_ARGS_NUM(__VA_ARGS__), TUSB_DESC_DEVICE_CAPABILITY, DEVICE_CAPABILITY_PLATFORM, 0x00, __VA_ARGS__ + +//------------- WebUSB BOS Platform -------------// + +// Descriptor Length +#define TUD_BOS_WEBUSB_DESC_LEN 24 + +// Vendor Code, iLandingPage +#define TUD_BOS_WEBUSB_DESCRIPTOR(_vendor_code, _ipage) \ + TUD_BOS_PLATFORM_DESCRIPTOR(TUD_BOS_WEBUSB_UUID, U16_TO_U8S_LE(0x0100), _vendor_code, _ipage) + +#define TUD_BOS_WEBUSB_UUID \ + 0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, \ + 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65 + +//------------- Microsoft OS 2.0 Platform -------------// +#define TUD_BOS_MICROSOFT_OS_DESC_LEN 28 + +// Total Length of descriptor set, vendor code +#define TUD_BOS_MS_OS_20_DESCRIPTOR(_desc_set_len, _vendor_code) \ + TUD_BOS_PLATFORM_DESCRIPTOR(TUD_BOS_MS_OS_20_UUID, U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(_desc_set_len), _vendor_code, 0) + +#define TUD_BOS_MS_OS_20_UUID \ + 0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, \ + 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F + +//--------------------------------------------------------------------+ +// Configuration Descriptor Templates +//--------------------------------------------------------------------+ + +#define TUD_CONFIG_DESC_LEN (9) + +// Config number, interface count, string index, total length, attribute, power in mA +#define TUD_CONFIG_DESCRIPTOR(config_num, _itfcount, _stridx, _total_len, _attribute, _power_ma) \ + 9, TUSB_DESC_CONFIGURATION, U16_TO_U8S_LE(_total_len), _itfcount, config_num, _stridx, TU_BIT(7) | _attribute, (_power_ma)/2 + +//--------------------------------------------------------------------+ +// CDC Descriptor Templates +//--------------------------------------------------------------------+ + +// Length of template descriptor: 66 bytes +#define TUD_CDC_DESC_LEN (8+9+5+5+4+5+7+9+7+7) + +// CDC Descriptor Template +// Interface number, string index, EP notification address and size, EP data address (out, in) and size. +#define TUD_CDC_DESCRIPTOR(_itfnum, _stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize) \ + /* Interface Associate */\ + 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_NONE, 0,\ + /* CDC Control Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_NONE, _stridx,\ + /* CDC Header */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\ + /* CDC Call */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (uint8_t)((_itfnum) + 1),\ + /* CDC ACM: support line request */\ + 4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 2,\ + /* CDC Union */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\ + /* Endpoint Notification */\ + 7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 16,\ + /* CDC Data Interface */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0 + +//--------------------------------------------------------------------+ +// MSC Descriptor Templates +//--------------------------------------------------------------------+ + +// Length of template descriptor: 23 bytes +#define TUD_MSC_DESC_LEN (9 + 7 + 7) + +// Interface number, string index, EP Out & EP In address, EP size +#define TUD_MSC_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \ + /* Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_MSC, MSC_SUBCLASS_SCSI, MSC_PROTOCOL_BOT, _stridx,\ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0 + + +//--------------------------------------------------------------------+ +// HID Descriptor Templates +//--------------------------------------------------------------------+ + +// Length of template descriptor: 25 bytes +#define TUD_HID_DESC_LEN (9 + 9 + 7) + +// HID Input only descriptor +// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval +#define TUD_HID_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epin, _epsize, _ep_interval) \ + /* Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? (uint8_t)HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\ + /* HID descriptor */\ + 9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval + +// Length of template descriptor: 32 bytes +#define TUD_HID_INOUT_DESC_LEN (9 + 9 + 7 + 7) + +// HID Input & Output descriptor +// Interface number, string index, protocol, report descriptor len, EP OUT & IN address, size & polling interval +#define TUD_HID_INOUT_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epout, _epin, _epsize, _ep_interval) \ + /* Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? (uint8_t)HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\ + /* HID descriptor */\ + 9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval, \ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval + +//--------------------------------------------------------------------+ +// MIDI Descriptor Templates +// Note: MIDI v1.0 is based on Audio v1.0 +//--------------------------------------------------------------------+ + +#define TUD_MIDI_DESC_HEAD_LEN (9 + 9 + 9 + 7) +#define TUD_MIDI_DESC_HEAD(_itfnum, _stridx, _numcables) \ + /* Audio Control (AC) Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_FUNC_PROTOCOL_CODE_UNDEF, _stridx,\ + /* AC Header */\ + 9, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(0x0009), 1, (uint8_t)((_itfnum) + 1),\ + /* MIDI Streaming (MS) Interface */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum) + 1), 0, 2, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_MIDI_STREAMING, AUDIO_FUNC_PROTOCOL_CODE_UNDEF, 0,\ + /* MS Header */\ + 7, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(7 + (_numcables) * TUD_MIDI_DESC_JACK_LEN) + +#define TUD_MIDI_JACKID_IN_EMB(_cablenum) \ + (uint8_t)(((_cablenum) - 1) * 4 + 1) + +#define TUD_MIDI_JACKID_IN_EXT(_cablenum) \ + (uint8_t)(((_cablenum) - 1) * 4 + 2) + +#define TUD_MIDI_JACKID_OUT_EMB(_cablenum) \ + (uint8_t)(((_cablenum) - 1) * 4 + 3) + +#define TUD_MIDI_JACKID_OUT_EXT(_cablenum) \ + (uint8_t)(((_cablenum) - 1) * 4 + 4) + +#define TUD_MIDI_DESC_JACK_LEN (6 + 6 + 9 + 9) +#define TUD_MIDI_DESC_JACK(_cablenum) \ + /* MS In Jack (Embedded) */\ + 6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_IN_EMB(_cablenum), 0,\ + /* MS In Jack (External) */\ + 6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_IN_EXT(_cablenum), 0,\ + /* MS Out Jack (Embedded), connected to In Jack External */\ + 9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_OUT_EMB(_cablenum), 1, TUD_MIDI_JACKID_IN_EXT(_cablenum), 1, 0,\ + /* MS Out Jack (External), connected to In Jack Embedded */\ + 9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_OUT_EXT(_cablenum), 1, TUD_MIDI_JACKID_IN_EMB(_cablenum), 1, 0 + +#define TUD_MIDI_DESC_EP_LEN(_numcables) (9 + 4 + (_numcables)) +#define TUD_MIDI_DESC_EP(_epout, _epsize, _numcables) \ + /* Endpoint: Note Audio v1.0's endpoint has 9 bytes instead of 7 */\ + 9, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0, 0, 0, \ + /* MS Endpoint (connected to embedded jack) */\ + (uint8_t)(4 + (_numcables)), TUSB_DESC_CS_ENDPOINT, MIDI_CS_ENDPOINT_GENERAL, _numcables + +// Length of template descriptor (88 bytes) +#define TUD_MIDI_DESC_LEN (TUD_MIDI_DESC_HEAD_LEN + TUD_MIDI_DESC_JACK_LEN + TUD_MIDI_DESC_EP_LEN(1) * 2) + +// MIDI simple descriptor +// - 1 Embedded Jack In connected to 1 External Jack Out +// - 1 Embedded Jack out connected to 1 External Jack In +#define TUD_MIDI_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \ + TUD_MIDI_DESC_HEAD(_itfnum, _stridx, 1),\ + TUD_MIDI_DESC_JACK(1),\ + TUD_MIDI_DESC_EP(_epout, _epsize, 1),\ + TUD_MIDI_JACKID_IN_EMB(1),\ + TUD_MIDI_DESC_EP(_epin, _epsize, 1),\ + TUD_MIDI_JACKID_OUT_EMB(1) + +//--------------------------------------------------------------------+ +// Audio v2.0 Descriptor Templates +//--------------------------------------------------------------------+ + +/* Standard Interface Association Descriptor (IAD) */ +#define TUD_AUDIO_DESC_IAD_LEN 8 +#define TUD_AUDIO_DESC_IAD(_firstitfs, _nitfs, _stridx) \ + TUD_AUDIO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, _firstitfs, _nitfs, TUSB_CLASS_AUDIO, AUDIO_FUNCTION_SUBCLASS_UNDEFINED, AUDIO_FUNC_PROTOCOL_CODE_V2, _stridx + +/* Standard AC Interface Descriptor(4.7.1) */ +#define TUD_AUDIO_DESC_STD_AC_LEN 9 +#define TUD_AUDIO_DESC_STD_AC(_itfnum, _nEPs, _stridx) /* _nEPs is 0 or 1 */\ + TUD_AUDIO_DESC_STD_AC_LEN, TUSB_DESC_INTERFACE, _itfnum, /* fixed to zero */ 0x00, _nEPs, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_INT_PROTOCOL_CODE_V2, _stridx + +/* Class-Specific AC Interface Header Descriptor(4.7.2) */ +#define TUD_AUDIO_DESC_CS_AC_LEN 9 +#define TUD_AUDIO_DESC_CS_AC(_bcdADC, _category, _totallen, _ctrl) /* _bcdADC : Audio Device Class Specification Release Number in Binary-Coded Decimal, _category : see audio_function_t, _totallen : Total number of bytes returned for the class-specific AudioControl interface i.e. Clock Source, Unit and Terminal descriptors - Do not include TUD_AUDIO_DESC_CS_AC_LEN, we already do this here*/ \ + TUD_AUDIO_DESC_CS_AC_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_HEADER, U16_TO_U8S_LE(_bcdADC), _category, U16_TO_U8S_LE(_totallen + TUD_AUDIO_DESC_CS_AC_LEN), _ctrl + +/* Clock Source Descriptor(4.7.2.1) */ +#define TUD_AUDIO_DESC_CLK_SRC_LEN 8 +#define TUD_AUDIO_DESC_CLK_SRC(_clkid, _attr, _ctrl, _assocTerm, _stridx) \ + TUD_AUDIO_DESC_CLK_SRC_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE, _clkid, _attr, _ctrl, _assocTerm, _stridx + +/* Input Terminal Descriptor(4.7.2.4) */ +#define TUD_AUDIO_DESC_INPUT_TERM_LEN 17 +#define TUD_AUDIO_DESC_INPUT_TERM(_termid, _termtype, _assocTerm, _clkid, _nchannelslogical, _channelcfg, _idxchannelnames, _ctrl, _stridx) \ + TUD_AUDIO_DESC_INPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL, _termid, U16_TO_U8S_LE(_termtype), _assocTerm, _clkid, _nchannelslogical, U32_TO_U8S_LE(_channelcfg), _idxchannelnames, U16_TO_U8S_LE(_ctrl), _stridx + +/* Output Terminal Descriptor(4.7.2.5) */ +#define TUD_AUDIO_DESC_OUTPUT_TERM_LEN 12 +#define TUD_AUDIO_DESC_OUTPUT_TERM(_termid, _termtype, _assocTerm, _srcid, _clkid, _ctrl, _stridx) \ + TUD_AUDIO_DESC_OUTPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL, _termid, U16_TO_U8S_LE(_termtype), _assocTerm, _srcid, _clkid, U16_TO_U8S_LE(_ctrl), _stridx + +/* Feature Unit Descriptor(4.7.2.8) */ +// 1 - Channel +#define TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN 6+(1+1)*4 +#define TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(_unitid, _srcid, _ctrlch0master, _ctrlch1, _stridx) \ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1), _stridx + +// 2 - Channels +#define TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN (6+(2+1)*4) +#define TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(_unitid, _srcid, _ctrlch0master, _ctrlch1, _ctrlch2, _stridx) \ + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1), U32_TO_U8S_LE(_ctrlch2), _stridx +// 4 - Channels +#define TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN (6+(4+1)*4) +#define TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL(_unitid, _srcid, _ctrlch0master, _ctrlch1, _ctrlch2, _ctrlch3, _ctrlch4, _stridx) \ + TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1), U32_TO_U8S_LE(_ctrlch2), U32_TO_U8S_LE(_ctrlch3), U32_TO_U8S_LE(_ctrlch4), _stridx + +// For more channels, add definitions here + +/* Standard AS Interface Descriptor(4.9.1) */ +#define TUD_AUDIO_DESC_STD_AS_INT_LEN 9 +#define TUD_AUDIO_DESC_STD_AS_INT(_itfnum, _altset, _nEPs, _stridx) \ + TUD_AUDIO_DESC_STD_AS_INT_LEN, TUSB_DESC_INTERFACE, _itfnum, _altset, _nEPs, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_STREAMING, AUDIO_INT_PROTOCOL_CODE_V2, _stridx + +/* Class-Specific AS Interface Descriptor(4.9.2) */ +#define TUD_AUDIO_DESC_CS_AS_INT_LEN 16 +#define TUD_AUDIO_DESC_CS_AS_INT(_termid, _ctrl, _formattype, _formats, _nchannelsphysical, _channelcfg, _stridx) \ + TUD_AUDIO_DESC_CS_AS_INT_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AS_INTERFACE_AS_GENERAL, _termid, _ctrl, _formattype, U32_TO_U8S_LE(_formats), _nchannelsphysical, U32_TO_U8S_LE(_channelcfg), _stridx + +/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ +#define TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN 6 +#define TUD_AUDIO_DESC_TYPE_I_FORMAT(_subslotsize, _bitresolution) /* _subslotsize is number of bytes per sample (i.e. subslot) and can be 1,2,3, or 4 */\ + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AS_INTERFACE_FORMAT_TYPE, AUDIO_FORMAT_TYPE_I, _subslotsize, _bitresolution + +/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ +#define TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN 7 +#define TUD_AUDIO_DESC_STD_AS_ISO_EP(_ep, _attr, _maxEPsize, _interval) \ + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN, TUSB_DESC_ENDPOINT, _ep, _attr, U16_TO_U8S_LE(_maxEPsize), _interval + +/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ +#define TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN 8 +#define TUD_AUDIO_DESC_CS_AS_ISO_EP(_attr, _ctrl, _lockdelayunit, _lockdelay) \ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN, TUSB_DESC_CS_ENDPOINT, AUDIO_CS_EP_SUBTYPE_GENERAL, _attr, _ctrl, _lockdelayunit, U16_TO_U8S_LE(_lockdelay) + +/* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */ +#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN 7 +#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_ep, _interval) \ + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_NO_SYNC | TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval + +// AUDIO simple descriptor (UAC2) for 1 microphone input +// - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source + +#define TUD_AUDIO_MIC_ONE_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ + + TUD_AUDIO_DESC_STD_AC_LEN\ + + TUD_AUDIO_DESC_CS_AC_LEN\ + + TUD_AUDIO_DESC_CLK_SRC_LEN\ + + TUD_AUDIO_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) + +#define TUD_AUDIO_MIC_ONE_CH_DESC_N_AS_INT 1 // Number of AS interfaces + +#define TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ + /* Standard Interface Association Descriptor (IAD) */\ + TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + /* Standard AC Interface Descriptor(4.7.1) */\ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ + /* Clock Source Descriptor(4.7.2.1) */\ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ + /* Input Terminal Descriptor(4.7.2.4) */\ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x03, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00),\ + /* Output Terminal Descriptor(4.7.2.5) */\ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + /* Feature Unit Descriptor(4.7.2.8) */\ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */\ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */\ + /* Interface 1, Alternate 1 - alternate interface for data streaming */\ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ + /* Class-Specific AS Interface Descriptor(4.9.2) */\ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x03, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + +// AUDIO simple descriptor (UAC2) for 4 microphone input +// - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source + +#define TUD_AUDIO_MIC_FOUR_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ + + TUD_AUDIO_DESC_STD_AC_LEN\ + + TUD_AUDIO_DESC_CS_AC_LEN\ + + TUD_AUDIO_DESC_CLK_SRC_LEN\ + + TUD_AUDIO_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) + +#define TUD_AUDIO_MIC_FOUR_CH_DESC_N_AS_INT 1 // Number of AS interfaces + +#define TUD_AUDIO_MIC_FOUR_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ + /* Standard Interface Association Descriptor (IAD) */\ + TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + /* Standard AC Interface Descriptor(4.7.1) */\ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ + /* Clock Source Descriptor(4.7.2.1) */\ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ + /* Input Terminal Descriptor(4.7.2.4) */\ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x03, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x04, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00),\ + /* Output Terminal Descriptor(4.7.2.5) */\ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + /* Feature Unit Descriptor(4.7.2.8) */\ + TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch3*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch4*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */\ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */\ + /* Interface 1, Alternate 1 - alternate interface for data streaming */\ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ + /* Class-Specific AS Interface Descriptor(4.9.2) */\ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x03, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x04, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + +// AUDIO simple descriptor (UAC2) for mono speaker +// - 1 Input Terminal, 2 Feature Unit (Mute and Volume Control), 3 Output Terminal, 4 Clock Source + +#define TUD_AUDIO_SPEAKER_MONO_FB_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ + + TUD_AUDIO_DESC_STD_AC_LEN\ + + TUD_AUDIO_DESC_CS_AC_LEN\ + + TUD_AUDIO_DESC_CLK_SRC_LEN\ + + TUD_AUDIO_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\ + + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN) + +#define TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize, _epfb) \ + /* Standard Interface Association Descriptor (IAD) */\ + TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + /* Standard AC Interface Descriptor(4.7.1) */\ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ + /* Clock Source Descriptor(4.7.2.1) */\ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ + /* Input Terminal Descriptor(4.7.2.4) */\ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ + /* Output Terminal Descriptor(4.7.2.5) */\ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + /* Feature Unit Descriptor(4.7.2.8) */\ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ 0 * (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch1*/ 0 * (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */\ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */\ + /* Interface 1, Alternate 1 - alternate interface for data streaming */\ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x02, /*_stridx*/ 0x00),\ + /* Class-Specific AS Interface Descriptor(4.9.2) */\ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\ + /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\ + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_interval*/ 1)\ + +// Calculate wMaxPacketSize of Endpoints +#define TUD_AUDIO_EP_SIZE(_maxFrequency, _nBytesPerSample, _nChannels) \ + ((((_maxFrequency + (TUD_OPT_HIGH_SPEED ? 7999 : 999)) / (TUD_OPT_HIGH_SPEED ? 8000 : 1000)) + 1) * _nBytesPerSample * _nChannels) + + +//--------------------------------------------------------------------+ +// USBTMC/USB488 Descriptor Templates +//--------------------------------------------------------------------+ + +#define TUD_USBTMC_APP_CLASS (TUSB_CLASS_APPLICATION_SPECIFIC) +#define TUD_USBTMC_APP_SUBCLASS 0x03u + +#define TUD_USBTMC_PROTOCOL_STD 0x00u +#define TUD_USBTMC_PROTOCOL_USB488 0x01u + +// Interface number, number of endpoints, EP string index, USB_TMC_PROTOCOL*, bulk-out endpoint ID, +// bulk-in endpoint ID +#define TUD_USBTMC_IF_DESCRIPTOR(_itfnum, _bNumEndpoints, _stridx, _itfProtocol) \ + /* Interface */ \ + 0x09, TUSB_DESC_INTERFACE, _itfnum, 0x00, _bNumEndpoints, TUD_USBTMC_APP_CLASS, TUD_USBTMC_APP_SUBCLASS, _itfProtocol, _stridx + +#define TUD_USBTMC_IF_DESCRIPTOR_LEN 9u + +#define TUD_USBTMC_BULK_DESCRIPTORS(_epout, _epin, _bulk_epsize) \ + /* Endpoint Out */ \ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u, \ + /* Endpoint In */ \ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u + +#define TUD_USBTMC_BULK_DESCRIPTORS_LEN (7u+7u) + +/* optional interrupt endpoint */ \ +// _int_pollingInterval : for LS/FS, expressed in frames (1ms each). 16 may be a good number? +#define TUD_USBTMC_INT_DESCRIPTOR(_ep_interrupt, _ep_interrupt_size, _int_pollingInterval ) \ + 7, TUSB_DESC_ENDPOINT, _ep_interrupt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_interrupt_size), 0x16 + +#define TUD_USBTMC_INT_DESCRIPTOR_LEN (7u) + +//--------------------------------------------------------------------+ +// Vendor Descriptor Templates +//--------------------------------------------------------------------+ + +#define TUD_VENDOR_DESC_LEN (9+7+7) + +// Interface number, string index, EP Out & IN address, EP size +#define TUD_VENDOR_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \ + /* Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_VENDOR_SPECIFIC, 0x00, 0x00, _stridx,\ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0 + +//--------------------------------------------------------------------+ +// DFU Runtime Descriptor Templates +//--------------------------------------------------------------------+ + +#define TUD_DFU_APP_CLASS (TUSB_CLASS_APPLICATION_SPECIFIC) +#define TUD_DFU_APP_SUBCLASS (APP_SUBCLASS_DFU_RUNTIME) + +// Length of template descriptr: 18 bytes +#define TUD_DFU_RT_DESC_LEN (9 + 9) + +// DFU runtime descriptor +// Interface number, string index, attributes, detach timeout, transfer size +#define TUD_DFU_RT_DESCRIPTOR(_itfnum, _stridx, _attr, _timeout, _xfer_size) \ + /* Interface */ \ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUD_DFU_APP_CLASS, TUD_DFU_APP_SUBCLASS, DFU_PROTOCOL_RT, _stridx, \ + /* Function */ \ + 9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0101) + +//--------------------------------------------------------------------+ +// DFU Descriptor Templates +//--------------------------------------------------------------------+ + +// Length of template descriptor: 9 bytes + number of alternatives * 9 +#define TUD_DFU_DESC_LEN(_alt_count) (9 + (_alt_count) * 9) + +// Interface number, Alternate count, starting string index, attributes, detach timeout, transfer size +// Note: Alternate count must be numberic or macro, string index is increased by one for each Alt interface +#define TUD_DFU_DESCRIPTOR(_itfnum, _alt_count, _stridx, _attr, _timeout, _xfer_size) \ + TU_XSTRCAT(_TUD_DFU_ALT_,_alt_count)(_itfnum, 0, _stridx), \ + /* Function */ \ + 9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0101) + +#define _TUD_DFU_ALT(_itfnum, _alt, _stridx) \ + /* Interface */ \ + 9, TUSB_DESC_INTERFACE, _itfnum, _alt, 0, TUD_DFU_APP_CLASS, TUD_DFU_APP_SUBCLASS, DFU_PROTOCOL_DFU, _stridx + +#define _TUD_DFU_ALT_1(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx) + +#define _TUD_DFU_ALT_2(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \ + _TUD_DFU_ALT_1(_itfnum, _alt_count+1, _stridx+1) + +#define _TUD_DFU_ALT_3(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \ + _TUD_DFU_ALT_2(_itfnum, _alt_count+1, _stridx+1) + +#define _TUD_DFU_ALT_4(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \ + _TUD_DFU_ALT_3(_itfnum, _alt_count+1, _stridx+1) + +#define _TUD_DFU_ALT_5(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \ + _TUD_DFU_ALT_4(_itfnum, _alt_count+1, _stridx+1) + +#define _TUD_DFU_ALT_6(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \ + _TUD_DFU_ALT_5(_itfnum, _alt_count+1, _stridx+1) + +#define _TUD_DFU_ALT_7(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \ + _TUD_DFU_ALT_6(_itfnum, _alt_count+1, _stridx+1) + +#define _TUD_DFU_ALT_8(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \ + _TUD_DFU_ALT_7(_itfnum, _alt_count+1, _stridx+1) + +//--------------------------------------------------------------------+ +// CDC-ECM Descriptor Templates +//--------------------------------------------------------------------+ + +// Length of template descriptor: 71 bytes +#define TUD_CDC_ECM_DESC_LEN (8+9+5+5+13+7+9+9+7+7) + +// CDC-ECM Descriptor Template +// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size. +#define TUD_CDC_ECM_DESCRIPTOR(_itfnum, _desc_stridx, _mac_stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize, _maxsegmentsize) \ + /* Interface Association */\ + 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL, 0, 0,\ + /* CDC Control Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL, 0, _desc_stridx,\ + /* CDC-ECM Header */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\ + /* CDC-ECM Union */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\ + /* CDC-ECM Functional Descriptor */\ + 13, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ETHERNET_NETWORKING, _mac_stridx, 0, 0, 0, 0, U16_TO_U8S_LE(_maxsegmentsize), U16_TO_U8S_LE(0), 0,\ + /* Endpoint Notification */\ + 7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 1,\ + /* CDC Data Interface (default inactive) */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 0, TUSB_CLASS_CDC_DATA, 0, 0, 0,\ + /* CDC Data Interface (alternative active) */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 1, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0 + +//--------------------------------------------------------------------+ +// RNDIS Descriptor Templates +//--------------------------------------------------------------------+ + +#if 0 +/* Windows XP */ +#define TUD_RNDIS_ITF_CLASS TUSB_CLASS_CDC +#define TUD_RNDIS_ITF_SUBCLASS CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL +#define TUD_RNDIS_ITF_PROTOCOL 0xFF /* CDC_COMM_PROTOCOL_MICROSOFT_RNDIS */ +#else +/* Windows 7+ */ +#define TUD_RNDIS_ITF_CLASS TUSB_CLASS_WIRELESS_CONTROLLER +#define TUD_RNDIS_ITF_SUBCLASS 0x01 +#define TUD_RNDIS_ITF_PROTOCOL 0x03 +#endif + +// Length of template descriptor: 66 bytes +#define TUD_RNDIS_DESC_LEN (8+9+5+5+4+5+7+9+7+7) + +// RNDIS Descriptor Template +// Interface number, string index, EP notification address and size, EP data address (out, in) and size. +#define TUD_RNDIS_DESCRIPTOR(_itfnum, _stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize) \ + /* Interface Association */\ + 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUD_RNDIS_ITF_CLASS, TUD_RNDIS_ITF_SUBCLASS, TUD_RNDIS_ITF_PROTOCOL, 0,\ + /* CDC Control Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUD_RNDIS_ITF_CLASS, TUD_RNDIS_ITF_SUBCLASS, TUD_RNDIS_ITF_PROTOCOL, _stridx,\ + /* CDC-ACM Header */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0110),\ + /* CDC Call Management */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (uint8_t)((_itfnum) + 1),\ + /* ACM */\ + 4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 0,\ + /* CDC Union */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\ + /* Endpoint Notification */\ + 7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 1,\ + /* CDC Data Interface */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0 + +//--------------------------------------------------------------------+ +// Bluetooth Radio Descriptor Templates +//--------------------------------------------------------------------+ + +#define TUD_BT_APP_CLASS (TUSB_CLASS_WIRELESS_CONTROLLER) +#define TUD_BT_APP_SUBCLASS 0x01 +#define TUD_BT_PROTOCOL_PRIMARY_CONTROLLER 0x01 +#define TUD_BT_PROTOCOL_AMP_CONTROLLER 0x02 + +#ifndef CFG_TUD_BTH_ISO_ALT_COUNT +#define CFG_TUD_BTH_ISO_ALT_COUNT 0 +#endif + +// Length of template descriptor: 38 bytes + number of ISO alternatives * 23 +#define TUD_BTH_DESC_LEN (8 + 9 + 7 + 7 + 7 + (CFG_TUD_BTH_ISO_ALT_COUNT) * (9 + 7 + 7)) + +/* Primary Interface */ +#define TUD_BTH_PRI_ITF(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size) \ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 3, TUD_BT_APP_CLASS, TUD_BT_APP_SUBCLASS, TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, _stridx, \ + /* Endpoint In for events */ \ + 7, TUSB_DESC_ENDPOINT, _ep_evt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_evt_size), _ep_evt_interval, \ + /* Endpoint In for ACL data */ \ + 7, TUSB_DESC_ENDPOINT, _ep_in, TUSB_XFER_BULK, U16_TO_U8S_LE(_ep_size), 1, \ + /* Endpoint Out for ACL data */ \ + 7, TUSB_DESC_ENDPOINT, _ep_out, TUSB_XFER_BULK, U16_TO_U8S_LE(_ep_size), 1 + +#define TUD_BTH_ISO_ITF(_itfnum, _alt, _ep_in, _ep_out, _n) ,\ + /* Interface with 2 endpoints */ \ + 9, TUSB_DESC_INTERFACE, _itfnum, _alt, 2, TUD_BT_APP_CLASS, TUD_BT_APP_SUBCLASS, TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, 0, \ + /* Isochronous endpoints */ \ + 7, TUSB_DESC_ENDPOINT, _ep_in, TUSB_XFER_ISOCHRONOUS, U16_TO_U8S_LE(_n), 1, \ + 7, TUSB_DESC_ENDPOINT, _ep_out, TUSB_XFER_ISOCHRONOUS, U16_TO_U8S_LE(_n), 1 + +#define _FIRST(a, ...) a +#define _REST(a, ...) __VA_ARGS__ + +#define TUD_BTH_ISO_ITF_0(_itfnum, ...) +#define TUD_BTH_ISO_ITF_1(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 1, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) +#define TUD_BTH_ISO_ITF_2(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 2, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \ + TUD_BTH_ISO_ITF_1(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__)) +#define TUD_BTH_ISO_ITF_3(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 3, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \ + TUD_BTH_ISO_ITF_2(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__)) +#define TUD_BTH_ISO_ITF_4(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 4, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \ + TUD_BTH_ISO_ITF_3(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__)) +#define TUD_BTH_ISO_ITF_5(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 5, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \ + TUD_BTH_ISO_ITF_4(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__)) +#define TUD_BTH_ISO_ITF_6(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 6, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \ + TUD_BTH_ISO_ITF_5(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__)) + +#define TUD_BTH_ISO_ITFS(_itfnum, _ep_in, _ep_out, ...) \ + TU_XSTRCAT(TUD_BTH_ISO_ITF_, CFG_TUD_BTH_ISO_ALT_COUNT)(_itfnum, _ep_in, _ep_out, __VA_ARGS__) + +// BT Primary controller descriptor +// Interface number, string index, attributes, event endpoint, event endpoint size, interval, data in, data out, data endpoint size, iso endpoint sizes +// TODO BTH should also use IAD like CDC for composite device +#define TUD_BTH_DESCRIPTOR(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size,...) \ + /* Interface Associate */\ + 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUD_BT_APP_CLASS, TUD_BT_APP_SUBCLASS, TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, 0,\ + TUD_BTH_PRI_ITF(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size) \ + TUD_BTH_ISO_ITFS(_itfnum + 1, _ep_in + 1, _ep_out + 1, __VA_ARGS__) + +//--------------------------------------------------------------------+ +// CDC-NCM Descriptor Templates +//--------------------------------------------------------------------+ + +// Length of template descriptor +#define TUD_CDC_NCM_DESC_LEN (8+9+5+5+13+6+7+9+9+7+7) + +// CDC-ECM Descriptor Template +// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size. +#define TUD_CDC_NCM_DESCRIPTOR(_itfnum, _desc_stridx, _mac_stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize, _maxsegmentsize) \ + /* Interface Association */\ + 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_NETWORK_CONTROL_MODEL, 0, 0,\ + /* CDC Control Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_NETWORK_CONTROL_MODEL, 0, _desc_stridx,\ + /* CDC-NCM Header */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0110),\ + /* CDC-NCM Union */\ + 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\ + /* CDC-NCM Functional Descriptor */\ + 13, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ETHERNET_NETWORKING, _mac_stridx, 0, 0, 0, 0, U16_TO_U8S_LE(_maxsegmentsize), U16_TO_U8S_LE(0), 0, \ + /* CDC-NCM Functional Descriptor */\ + 6, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_NCM, U16_TO_U8S_LE(0x0100), 0, \ + /* Endpoint Notification */\ + 7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 50,\ + /* CDC Data Interface (default inactive) */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 0, TUSB_CLASS_CDC_DATA, 0, NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK, 0,\ + /* CDC Data Interface (alternative active) */\ + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 1, 2, TUSB_CLASS_CDC_DATA, 0, NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK, 0,\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0 + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_USBD_H_ */ + +/** @} */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/device/usbd_control.c b/test-devices/loopback-stm32/lib/tinyusb/device/usbd_control.c new file mode 100644 index 00000000..0995ef66 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/device/usbd_control.c @@ -0,0 +1,233 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUD_ENABLED + +#include "dcd.h" +#include "tusb.h" +#include "device/usbd_pvt.h" + +#if CFG_TUSB_DEBUG >= 2 +extern void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback); +#endif + +enum +{ + EDPT_CTRL_OUT = 0x00, + EDPT_CTRL_IN = 0x80 +}; + +typedef struct +{ + tusb_control_request_t request; + + uint8_t* buffer; + uint16_t data_len; + uint16_t total_xferred; + + usbd_control_xfer_cb_t complete_cb; +} usbd_control_xfer_t; + +static usbd_control_xfer_t _ctrl_xfer; + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN +static uint8_t _usbd_ctrl_buf[CFG_TUD_ENDPOINT0_SIZE]; + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + +// Queue ZLP status transaction +static inline bool _status_stage_xact(uint8_t rhport, tusb_control_request_t const * request) +{ + // Opposite to endpoint in Data Phase + uint8_t const ep_addr = request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN; + return usbd_edpt_xfer(rhport, ep_addr, NULL, 0); +} + +// Status phase +bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request) +{ + _ctrl_xfer.request = (*request); + _ctrl_xfer.buffer = NULL; + _ctrl_xfer.total_xferred = 0; + _ctrl_xfer.data_len = 0; + + return _status_stage_xact(rhport, request); +} + +// Queue a transaction in Data Stage +// Each transaction has up to Endpoint0's max packet size. +// This function can also transfer an zero-length packet +static bool _data_stage_xact(uint8_t rhport) +{ + uint16_t const xact_len = tu_min16(_ctrl_xfer.data_len - _ctrl_xfer.total_xferred, CFG_TUD_ENDPOINT0_SIZE); + + uint8_t ep_addr = EDPT_CTRL_OUT; + + if ( _ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN ) + { + ep_addr = EDPT_CTRL_IN; + if ( xact_len ) memcpy(_usbd_ctrl_buf, _ctrl_xfer.buffer, xact_len); + } + + return usbd_edpt_xfer(rhport, ep_addr, xact_len ? _usbd_ctrl_buf : NULL, xact_len); +} + +// Transmit data to/from the control endpoint. +// If the request's wLength is zero, a status packet is sent instead. +bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len) +{ + _ctrl_xfer.request = (*request); + _ctrl_xfer.buffer = (uint8_t*) buffer; + _ctrl_xfer.total_xferred = 0U; + _ctrl_xfer.data_len = tu_min16(len, request->wLength); + + if (request->wLength > 0U) + { + if(_ctrl_xfer.data_len > 0U) + { + TU_ASSERT(buffer); + } + +// TU_LOG2(" Control total data length is %u bytes\r\n", _ctrl_xfer.data_len); + + // Data stage + TU_ASSERT( _data_stage_xact(rhport) ); + } + else + { + // Status stage + TU_ASSERT( _status_stage_xact(rhport, request) ); + } + + return true; +} + +//--------------------------------------------------------------------+ +// USBD API +//--------------------------------------------------------------------+ + +void usbd_control_reset(void); +void usbd_control_set_request(tusb_control_request_t const *request); +void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp ); +bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); + +void usbd_control_reset(void) +{ + tu_varclr(&_ctrl_xfer); +} + +// Set complete callback +void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp ) +{ + _ctrl_xfer.complete_cb = fp; +} + +// for dcd_set_address where DCD is responsible for status response +void usbd_control_set_request(tusb_control_request_t const *request) +{ + _ctrl_xfer.request = (*request); + _ctrl_xfer.buffer = NULL; + _ctrl_xfer.total_xferred = 0; + _ctrl_xfer.data_len = 0; +} + +// callback when a transaction complete on +// - DATA stage of control endpoint or +// - Status stage +bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) result; + + // Endpoint Address is opposite to direction bit, this is Status Stage complete event + if ( tu_edpt_dir(ep_addr) != _ctrl_xfer.request.bmRequestType_bit.direction ) + { + TU_ASSERT(0 == xferred_bytes); + + // invoke optional dcd hook if available + if (dcd_edpt0_status_complete) dcd_edpt0_status_complete(rhport, &_ctrl_xfer.request); + + if (_ctrl_xfer.complete_cb) + { + // TODO refactor with usbd_driver_print_control_complete_name + _ctrl_xfer.complete_cb(rhport, CONTROL_STAGE_ACK, &_ctrl_xfer.request); + } + + return true; + } + + if ( _ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_OUT ) + { + TU_VERIFY(_ctrl_xfer.buffer); + memcpy(_ctrl_xfer.buffer, _usbd_ctrl_buf, xferred_bytes); + TU_LOG_MEM(2, _usbd_ctrl_buf, xferred_bytes, 2); + } + + _ctrl_xfer.total_xferred += (uint16_t) xferred_bytes; + _ctrl_xfer.buffer += xferred_bytes; + + // Data Stage is complete when all request's length are transferred or + // a short packet is sent including zero-length packet. + if ( (_ctrl_xfer.request.wLength == _ctrl_xfer.total_xferred) || (xferred_bytes < CFG_TUD_ENDPOINT0_SIZE) ) + { + // DATA stage is complete + bool is_ok = true; + + // invoke complete callback if set + // callback can still stall control in status phase e.g out data does not make sense + if ( _ctrl_xfer.complete_cb ) + { + #if CFG_TUSB_DEBUG >= 2 + usbd_driver_print_control_complete_name(_ctrl_xfer.complete_cb); + #endif + + is_ok = _ctrl_xfer.complete_cb(rhport, CONTROL_STAGE_DATA, &_ctrl_xfer.request); + } + + if ( is_ok ) + { + // Send status + TU_ASSERT( _status_stage_xact(rhport, &_ctrl_xfer.request) ); + }else + { + // Stall both IN and OUT control endpoint + dcd_edpt_stall(rhport, EDPT_CTRL_OUT); + dcd_edpt_stall(rhport, EDPT_CTRL_IN); + } + } + else + { + // More data to transfer + TU_ASSERT( _data_stage_xact(rhport) ); + } + + return true; +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/device/usbd_pvt.h b/test-devices/loopback-stm32/lib/tinyusb/device/usbd_pvt.h new file mode 100644 index 00000000..6fad46db --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/device/usbd_pvt.h @@ -0,0 +1,121 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ +#ifndef USBD_PVT_H_ +#define USBD_PVT_H_ + +#include "osal/osal.h" +#include "common/tusb_fifo.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Class Driver API +//--------------------------------------------------------------------+ + +typedef struct +{ + #if CFG_TUSB_DEBUG >= 2 + char const* name; + #endif + + void (* init ) (void); + void (* reset ) (uint8_t rhport); + uint16_t (* open ) (uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t max_len); + bool (* control_xfer_cb ) (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + bool (* xfer_cb ) (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); + void (* sof ) (uint8_t rhport, uint32_t frame_count); // optional +} usbd_class_driver_t; + +// Invoked when initializing device stack to get additional class drivers. +// Can optionally implemented by application to extend/overwrite class driver support. +// Note: The drivers array must be accessible at all time when stack is active +usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) TU_ATTR_WEAK; + +typedef bool (*usbd_control_xfer_cb_t)(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + +void usbd_int_set(bool enabled); + +//--------------------------------------------------------------------+ +// USBD Endpoint API +// Note: rhport should be 0 since device stack only support 1 rhport for now +//--------------------------------------------------------------------+ + +// Open an endpoint +bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep); + +// Close an endpoint +void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr); + +// Submit a usb transfer +bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); + +// Submit a usb ISO transfer by use of a FIFO (ring buffer) - all bytes in FIFO get transmitted +bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes); + +// Claim an endpoint before submitting a transfer. +// If caller does not make any transfer, it must release endpoint for others. +bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr); + +// Release claimed endpoint without submitting a transfer +bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr); + +// Check if endpoint is busy transferring +bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr); + +// Stall endpoint +void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr); + +// Clear stalled endpoint +void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr); + +// Check if endpoint is stalled +bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr); + +// Check if endpoint is ready (not busy and not stalled) +TU_ATTR_ALWAYS_INLINE static inline +bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr) +{ + return !usbd_edpt_busy(rhport, ep_addr) && !usbd_edpt_stalled(rhport, ep_addr); +} + +// Enable SOF interrupt +void usbd_sof_enable(uint8_t rhport, bool en); + +/*------------------------------------------------------------------*/ +/* Helper + *------------------------------------------------------------------*/ + +bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in); +void usbd_defer_func( osal_task_func_t func, void* param, bool in_isr ); + + +#ifdef __cplusplus + } +#endif + +#endif /* USBD_PVT_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c new file mode 100644 index 00000000..f5ecdfe4 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c @@ -0,0 +1,1351 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 William D. Jones + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2020 Jan Duempelmann + * Copyright (c) 2020 Reinhard Panhuber + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUD_ENABLED && defined(TUP_USBIP_DWC2) + +#include "device/dcd.h" +#include "dwc2_type.h" + +// Following symbols must be defined by port header +// - _dwc2_controller[]: array of controllers +// - DWC2_EP_MAX: largest EP counts of all controllers +// - dwc2_phy_init/dwc2_phy_update: phy init called before and after core reset +// - dwc2_dcd_int_enable/dwc2_dcd_int_disable +// - dwc2_remote_wakeup_delay + +#if defined(TUP_USBIP_DWC2_STM32) + #include "dwc2_stm32.h" +#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + #include "dwc2_esp32.h" +#elif TU_CHECK_MCU(OPT_MCU_GD32VF103) + #include "dwc2_gd32.h" +#elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837) + #include "dwc2_bcm.h" +#elif TU_CHECK_MCU(OPT_MCU_EFM32GG) + #include "dwc2_efm32.h" +#elif TU_CHECK_MCU(OPT_MCU_XMC4000) + #include "dwc2_xmc.h" +#else + #error "Unsupported MCUs" +#endif + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM +//--------------------------------------------------------------------+ + +// DWC2 registers +#define DWC2_REG(_port) ((dwc2_regs_t*) _dwc2_controller[_port].reg_base) + +// Debug level for DWC2 +#define DWC2_DEBUG 2 + +#ifndef dcache_clean +#define dcache_clean(_addr, _size) +#endif + +#ifndef dcache_invalidate +#define dcache_invalidate(_addr, _size) +#endif + +#ifndef dcache_clean_invalidate +#define dcache_clean_invalidate(_addr, _size) +#endif + +static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2]; + +typedef struct { + uint8_t * buffer; + tu_fifo_t * ff; + uint16_t total_len; + uint16_t max_size; + uint8_t interval; +} xfer_ctl_t; + +static xfer_ctl_t xfer_status[DWC2_EP_MAX][2]; +#define XFER_CTL_BASE(_ep, _dir) (&xfer_status[_ep][_dir]) + +// EP0 transfers are limited to 1 packet - larger sizes has to be split +static uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type + +// TX FIFO RAM allocation so far in words - RX FIFO size is readily available from dwc2->grxfsiz +static uint16_t _allocated_fifo_words_tx; // TX FIFO size in words (IN EPs) +static bool _out_ep_closed; // Flag to check if RX FIFO size needs an update (reduce its size) + +// SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by +static bool _sof_en; + +// Calculate the RX FIFO size according to recommendations from reference manual +static inline uint16_t calc_grxfsiz(uint16_t max_ep_size, uint8_t ep_count) +{ + return 15 + 2*(max_ep_size/4) + 2*ep_count; +} + +static void update_grxfsiz(uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + + // Determine largest EP size for RX FIFO + uint16_t max_epsize = 0; + for (uint8_t epnum = 0; epnum < ep_count; epnum++) + { + max_epsize = tu_max16(max_epsize, xfer_status[epnum][TUSB_DIR_OUT].max_size); + } + + // Update size of RX FIFO + dwc2->grxfsiz = calc_grxfsiz(max_epsize, ep_count); +} + +// Start of Bus Reset +static void bus_reset(uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + + tu_memclr(xfer_status, sizeof(xfer_status)); + _out_ep_closed = false; + + _sof_en = false; + + // clear device address + dwc2->dcfg &= ~DCFG_DAD_Msk; + + // 1. NAK for all OUT endpoints + for ( uint8_t n = 0; n < ep_count; n++ ) + { + dwc2->epout[n].doepctl |= DOEPCTL_SNAK; + } + + // 2. Set up interrupt mask + dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos); + dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM; + dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM; + + // "USB Data FIFOs" section in reference manual + // Peripheral FIFO architecture + // + // The FIFO is split up in a lower part where the RX FIFO is located and an upper part where the TX FIFOs start. + // We do this to allow the RX FIFO to grow dynamically which is possible since the free space is located + // between the RX and TX FIFOs. This is required by ISO OUT EPs which need a bigger FIFO than the standard + // configuration done below. + // + // Dynamically FIFO sizes are of interest only for ISO EPs since all others are usually not opened and closed. + // All EPs other than ISO are opened as soon as the driver starts up i.e. when the host sends a + // configure interface command. Hence, all IN EPs other the ISO will be located at the top. IN ISO EPs are usually + // opened when the host sends an additional command: setInterface. At this point in time + // the ISO EP will be located next to the free space and can change its size. In case more IN EPs change its size + // an additional memory + // + // --------------- 320 or 1024 ( 1280 or 4096 bytes ) + // | IN FIFO 0 | + // --------------- (320 or 1024) - 16 + // | IN FIFO 1 | + // --------------- (320 or 1024) - 16 - x + // | . . . . | + // --------------- (320 or 1024) - 16 - x - y - ... - z + // | IN FIFO MAX | + // --------------- + // | FREE | + // --------------- GRXFSIZ + // | OUT FIFO | + // | ( Shared ) | + // --------------- 0 + // + // According to "FIFO RAM allocation" section in RM, FIFO RAM are allocated as follows (each word 32-bits): + // - Each EP IN needs at least max packet size, 16 words is sufficient for EP0 IN + // + // - All EP OUT shared a unique OUT FIFO which uses + // - 13 for setup packets + control words (up to 3 setup packets). + // - 1 for global NAK (not required/used here). + // - Largest-EPsize / 4 + 1. ( FS: 64 bytes, HS: 512 bytes). Recommended is "2 x (Largest-EPsize/4) + 1" + // - 2 for each used OUT endpoint + // + // Therefore GRXFSIZ = 13 + 1 + 1 + 2 x (Largest-EPsize/4) + 2 x EPOUTnum + // - FullSpeed (64 Bytes ): GRXFSIZ = 15 + 2 x 16 + 2 x ep_count = 47 + 2 x ep_count + // - Highspeed (512 bytes): GRXFSIZ = 15 + 2 x 128 + 2 x ep_count = 271 + 2 x ep_count + // + // NOTE: Largest-EPsize & EPOUTnum is actual used endpoints in configuration. Since DCD has no knowledge + // of the overall picture yet. We will use the worst scenario: largest possible + ep_count + // + // For Isochronous, largest EP size can be 1023/1024 for FS/HS respectively. In addition if multiple ISO + // are enabled at least "2 x (Largest-EPsize/4) + 1" are recommended. Maybe provide a macro for application to + // overwrite this. + + // EP0 out max is 64 + dwc2->grxfsiz = calc_grxfsiz(64, ep_count); + + // Setup the control endpoint 0 + _allocated_fifo_words_tx = 16; + + // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word ) + dwc2->dieptxf0 = (16 << DIEPTXF0_TX0FD_Pos) | (_dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx); + + // Fixed control EP0 size to 64 bytes + dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos); + xfer_status[0][TUSB_DIR_OUT].max_size = 64; + xfer_status[0][TUSB_DIR_IN ].max_size = 64; + + dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); + + dwc2->gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT; +} + +static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets, uint16_t total_bytes) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + // EP0 is limited to one packet each xfer + // We use multiple transaction of xfer->max_size length to get a whole transfer done + if ( epnum == 0 ) + { + xfer_ctl_t *const xfer = XFER_CTL_BASE(epnum, dir); + total_bytes = tu_min16(ep0_pending[dir], xfer->max_size); + ep0_pending[dir] -= total_bytes; + } + + // IN and OUT endpoint xfers are interrupt-driven, we just schedule them here. + if ( dir == TUSB_DIR_IN ) + { + dwc2_epin_t* epin = dwc2->epin; + + // A full IN transfer (multiple packets, possibly) triggers XFRC. + epin[epnum].dieptsiz = (num_packets << DIEPTSIZ_PKTCNT_Pos) | + ((total_bytes << DIEPTSIZ_XFRSIZ_Pos) & DIEPTSIZ_XFRSIZ_Msk); + + epin[epnum].diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK; + + // For ISO endpoint set correct odd/even bit for next frame. + if ( (epin[epnum].diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1 ) + { + // Take odd/even bit from frame counter. + uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); + epin[epnum].diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk); + } + // Enable fifo empty interrupt only if there are something to put in the fifo. + if ( total_bytes != 0 ) + { + dwc2->diepempmsk |= (1 << epnum); + } + } + else + { + dwc2_epout_t* epout = dwc2->epout; + + // A full OUT transfer (multiple packets, possibly) triggers XFRC. + epout[epnum].doeptsiz &= ~(DOEPTSIZ_PKTCNT_Msk | DOEPTSIZ_XFRSIZ); + epout[epnum].doeptsiz |= (num_packets << DOEPTSIZ_PKTCNT_Pos) | + ((total_bytes << DOEPTSIZ_XFRSIZ_Pos) & DOEPTSIZ_XFRSIZ_Msk); + + epout[epnum].doepctl |= DOEPCTL_EPENA | DOEPCTL_CNAK; + if ( (epout[epnum].doepctl & DOEPCTL_EPTYP) == DOEPCTL_EPTYP_0 && + XFER_CTL_BASE(epnum, dir)->interval == 1 ) + { + // Take odd/even bit from frame counter. + uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); + epout[epnum].doepctl |= (odd_frame_now ? DOEPCTL_SD0PID_SEVNFRM_Msk : DOEPCTL_SODDFRM_Msk); + } + } +} + +/*------------------------------------------------------------------*/ +/* Controller API + *------------------------------------------------------------------*/ +#if CFG_TUSB_DEBUG >= DWC2_DEBUG +void print_dwc2_info(dwc2_regs_t * dwc2) +{ + dwc2_ghwcfg2_t const * hw_cfg2 = &dwc2->ghwcfg2_bm; + dwc2_ghwcfg3_t const * hw_cfg3 = &dwc2->ghwcfg3_bm; + dwc2_ghwcfg4_t const * hw_cfg4 = &dwc2->ghwcfg4_bm; + +// TU_LOG_HEX(DWC2_DEBUG, dwc2->gotgctl); +// TU_LOG_HEX(DWC2_DEBUG, dwc2->gusbcfg); +// TU_LOG_HEX(DWC2_DEBUG, dwc2->dcfg); + TU_LOG_HEX(DWC2_DEBUG, dwc2->guid); + TU_LOG_HEX(DWC2_DEBUG, dwc2->gsnpsid); + TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg1); + + // HW configure 2 + TU_LOG(DWC2_DEBUG, "\r\n"); + TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg2); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->op_mode ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->arch ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->point2point ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->hs_phy_type ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->fs_phy_type ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->num_dev_ep ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->num_host_ch ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->period_channel_support ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->enable_dynamic_fifo ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->mul_cpu_int ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->nperiod_tx_q_depth ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->host_period_tx_q_depth ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->dev_token_q_depth ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->otg_enable_ic_usb ); + + // HW configure 3 + TU_LOG(DWC2_DEBUG, "\r\n"); + TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg3); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->xfer_size_width ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->packet_size_width ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_enable ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->i2c_enable ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->vendor_ctrl_itf ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->optional_feature_removed ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->synch_reset ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_adp_support ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_enable_hsic ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->battery_charger_support ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->lpm_mode ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->total_fifo_size ); + + // HW configure 4 + TU_LOG(DWC2_DEBUG, "\r\n"); + TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg4); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->num_dev_period_in_ep ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->power_optimized ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->ahb_freq_min ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->hibernation ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->service_interval_mode ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->ipg_isoc_en ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->acg_enable ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->utmi_phy_data_width ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dev_ctrl_ep_num ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->iddg_filter_enabled ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->vbus_valid_filter_enabled ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->a_valid_filter_enabled ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->b_valid_filter_enabled ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dedicated_fifos ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->num_dev_in_eps ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dma_desc_enable ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dma_dynamic ); +} +#endif + +static void reset_core(dwc2_regs_t * dwc2) +{ + // reset core + dwc2->grstctl |= GRSTCTL_CSRST; + + // wait for reset bit is cleared + // TODO version 4.20a should wait for RESET DONE mask + while (dwc2->grstctl & GRSTCTL_CSRST) { } + + // wait for AHB master IDLE + while ( !(dwc2->grstctl & GRSTCTL_AHBIDL) ) { } + + // wait for device mode ? +} + +static bool phy_hs_supported(dwc2_regs_t * dwc2) +{ + // note: esp32 incorrect report its hs_phy_type as utmi +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + return false; +#else + return TUD_OPT_HIGH_SPEED && dwc2->ghwcfg2_bm.hs_phy_type != HS_PHY_TYPE_NONE; +#endif +} + +static void phy_fs_init(dwc2_regs_t * dwc2) +{ + TU_LOG(DWC2_DEBUG, "Fullspeed PHY init\r\n"); + + // Select FS PHY + dwc2->gusbcfg |= GUSBCFG_PHYSEL; + + // MCU specific PHY init before reset + dwc2_phy_init(dwc2, HS_PHY_TYPE_NONE); + + // Reset core after selecting PHY + reset_core(dwc2); + + // USB turnaround time is critical for certification where long cables and 5-Hubs are used. + // So if you need the AHB to run at less than 30 MHz, and if USB turnaround time is not critical, + // these bits can be programmed to a larger value. Default is 5 + dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (5u << GUSBCFG_TRDT_Pos); + + // MCU specific PHY update post reset + dwc2_phy_update(dwc2, HS_PHY_TYPE_NONE); + + // set max speed + dwc2->dcfg = (dwc2->dcfg & ~DCFG_DSPD_Msk) | (DCFG_DSPD_FS << DCFG_DSPD_Pos); +} + +static void phy_hs_init(dwc2_regs_t * dwc2) +{ + uint32_t gusbcfg = dwc2->gusbcfg; + + // De-select FS PHY + gusbcfg &= ~GUSBCFG_PHYSEL; + + if (dwc2->ghwcfg2_bm.hs_phy_type == HS_PHY_TYPE_ULPI) + { + TU_LOG(DWC2_DEBUG, "Highspeed ULPI PHY init\r\n"); + + // Select ULPI + gusbcfg |= GUSBCFG_ULPI_UTMI_SEL; + + // ULPI 8-bit interface, single data rate + gusbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL); + + // default internal VBUS Indicator and Drive + gusbcfg &= ~(GUSBCFG_ULPIEVBUSD | GUSBCFG_ULPIEVBUSI); + + // Disable FS/LS ULPI + gusbcfg &= ~(GUSBCFG_ULPIFSLS | GUSBCFG_ULPICSM); + }else + { + TU_LOG(DWC2_DEBUG, "Highspeed UTMI+ PHY init\r\n"); + + // Select UTMI+ with 8-bit interface + gusbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16); + + // Set 16-bit interface if supported + if (dwc2->ghwcfg4_bm.utmi_phy_data_width) gusbcfg |= GUSBCFG_PHYIF16; + } + + // Apply config + dwc2->gusbcfg = gusbcfg; + + // mcu specific phy init + dwc2_phy_init(dwc2, dwc2->ghwcfg2_bm.hs_phy_type); + + // Reset core after selecting PHY + reset_core(dwc2); + + // Set turn-around, must after core reset otherwise it will be clear + // - 9 if using 8-bit PHY interface + // - 5 if using 16-bit PHY interface + gusbcfg &= ~GUSBCFG_TRDT_Msk; + gusbcfg |= (dwc2->ghwcfg4_bm.utmi_phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos; + dwc2->gusbcfg = gusbcfg; + + // MCU specific PHY update post reset + dwc2_phy_update(dwc2, dwc2->ghwcfg2_bm.hs_phy_type); + + // Set max speed + uint32_t dcfg = dwc2->dcfg; + dcfg &= ~DCFG_DSPD_Msk; + dcfg |= DCFG_DSPD_HS << DCFG_DSPD_Pos; + + // XCVRDLY: transceiver delay between xcvr_sel and txvalid during device chirp is required + // when using with some PHYs such as USB334x (USB3341, USB3343, USB3346, USB3347) + if (dwc2->ghwcfg2_bm.hs_phy_type == HS_PHY_TYPE_ULPI) dcfg |= DCFG_XCVRDLY; + + dwc2->dcfg = dcfg; +} + +static bool check_dwc2(dwc2_regs_t * dwc2) +{ +#if CFG_TUSB_DEBUG >= DWC2_DEBUG + print_dwc2_info(dwc2); +#endif + + // For some reasons: GD32VF103 snpsid and all hwcfg register are always zero (skip it) + (void) dwc2; +#if !TU_CHECK_MCU(OPT_MCU_GD32VF103) + uint32_t const gsnpsid = dwc2->gsnpsid & GSNPSID_ID_MASK; + TU_ASSERT(gsnpsid == DWC2_OTG_ID || gsnpsid == DWC2_FS_IOT_ID || gsnpsid == DWC2_HS_IOT_ID); +#endif + + return true; +} + +void dcd_init (uint8_t rhport) +{ + // Programming model begins in the last section of the chapter on the USB + // peripheral in each Reference Manual. + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + // Check Synopsys ID register, failed if controller clock/power is not enabled + TU_VERIFY(check_dwc2(dwc2), ); + + dcd_disconnect(rhport); + + // max number of endpoints & total_fifo_size are: + // hw_cfg2->num_dev_ep, hw_cfg2->total_fifo_size + + if( phy_hs_supported(dwc2) ) + { + // Highspeed + phy_hs_init(dwc2); + }else + { + // core does not support highspeed or hs-phy is not present + phy_fs_init(dwc2); + } + + // Restart PHY clock + dwc2->pcgctl &= ~(PCGCTL_STOPPCLK | PCGCTL_GATEHCLK | PCGCTL_PWRCLMP | PCGCTL_RSTPDWNMODULE); + + /* Set HS/FS Timeout Calibration to 7 (max available value). + * The number of PHY clocks that the application programs in + * this field is added to the high/full speed interpacket timeout + * duration in the core to account for any additional delays + * introduced by the PHY. This can be required, because the delay + * introduced by the PHY in generating the linestate condition + * can vary from one PHY to another. + */ + dwc2->gusbcfg |= (7ul << GUSBCFG_TOCAL_Pos); + + // Force device mode + dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FHMOD) | GUSBCFG_FDMOD; + + // Clear A override, force B Valid + dwc2->gotgctl = (dwc2->gotgctl & ~GOTGCTL_AVALOEN) | GOTGCTL_BVALOEN | GOTGCTL_BVALOVAL; + + // If USB host misbehaves during status portion of control xfer + // (non zero-length packet), send STALL back and discard. + dwc2->dcfg |= DCFG_NZLSOHSK; + + // Clear all interrupts + dwc2->gintsts |= dwc2->gintsts; + dwc2->gotgint |= dwc2->gotgint; + + // Required as part of core initialization. + // TODO: How should mode mismatch be handled? It will cause + // the core to stop working/require reset. + dwc2->gintmsk = GINTMSK_OTGINT | GINTMSK_MMISM | GINTMSK_RXFLVLM | + GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM; + + // Enable global interrupt + dwc2->gahbcfg |= GAHBCFG_GINT; + + // make sure we are in device mode +// TU_ASSERT(!(dwc2->gintsts & GINTSTS_CMOD), ); + +// TU_LOG_HEX(DWC2_DEBUG, dwc2->gotgctl); +// TU_LOG_HEX(DWC2_DEBUG, dwc2->gusbcfg); +// TU_LOG_HEX(DWC2_DEBUG, dwc2->dcfg); +// TU_LOG_HEX(DWC2_DEBUG, dwc2->gahbcfg); + + dcd_connect(rhport); +} + +void dcd_int_enable (uint8_t rhport) +{ + dwc2_dcd_int_enable(rhport); +} + +void dcd_int_disable (uint8_t rhport) +{ + dwc2_dcd_int_disable(rhport); +} + +void dcd_set_address (uint8_t rhport, uint8_t dev_addr) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2->dcfg = (dwc2->dcfg & ~DCFG_DAD_Msk) | (dev_addr << DCFG_DAD_Pos); + + // Response with status after changing device address + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); +} + +void dcd_remote_wakeup(uint8_t rhport) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + // set remote wakeup + dwc2->dctl |= DCTL_RWUSIG; + + // enable SOF to detect bus resume + dwc2->gintsts = GINTSTS_SOF; + dwc2->gintmsk |= GINTMSK_SOFM; + + // Per specs: remote wakeup signal bit must be clear within 1-15ms + dwc2_remote_wakeup_delay(); + + dwc2->dctl &= ~DCTL_RWUSIG; +} + +void dcd_connect(uint8_t rhport) +{ + (void) rhport; + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2->dctl &= ~DCTL_SDIS; +} + +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2->dctl |= DCTL_SDIS; +} + +// Be advised: audio, video and possibly other iso-ep classes use dcd_sof_enable() to enable/disable its corresponding ISR on purpose! +void dcd_sof_enable(uint8_t rhport, bool en) +{ + (void) rhport; + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + _sof_en = en; + + if (en) + { + dwc2->gintsts = GINTSTS_SOF; + dwc2->gintmsk |= GINTMSK_SOFM; + } + else + { + dwc2->gintmsk &= ~GINTMSK_SOFM; + } +} + +/*------------------------------------------------------------------*/ +/* DCD Endpoint port + *------------------------------------------------------------------*/ + +bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + + uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress); + uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress); + + TU_ASSERT(epnum < ep_count); + + xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); + xfer->max_size = tu_edpt_packet_size(desc_edpt); + xfer->interval = desc_edpt->bInterval; + + uint16_t const fifo_size = tu_div_ceil(xfer->max_size, 4); + + if(dir == TUSB_DIR_OUT) + { + // Calculate required size of RX FIFO + uint16_t const sz = calc_grxfsiz(4*fifo_size, ep_count); + + // If size_rx needs to be extended check if possible and if so enlarge it + if (dwc2->grxfsiz < sz) + { + TU_ASSERT(sz + _allocated_fifo_words_tx <= _dwc2_controller[rhport].ep_fifo_size/4); + + // Enlarge RX FIFO + dwc2->grxfsiz = sz; + } + + dwc2->epout[epnum].doepctl |= (1 << DOEPCTL_USBAEP_Pos) | + (desc_edpt->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) | + (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) | + (xfer->max_size << DOEPCTL_MPSIZ_Pos); + + dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum); + } + else + { + // "USB Data FIFOs" section in reference manual + // Peripheral FIFO architecture + // + // --------------- 320 or 1024 ( 1280 or 4096 bytes ) + // | IN FIFO 0 | + // --------------- (320 or 1024) - 16 + // | IN FIFO 1 | + // --------------- (320 or 1024) - 16 - x + // | . . . . | + // --------------- (320 or 1024) - 16 - x - y - ... - z + // | IN FIFO MAX | + // --------------- + // | FREE | + // --------------- GRXFSIZ + // | OUT FIFO | + // | ( Shared ) | + // --------------- 0 + // + // In FIFO is allocated by following rules: + // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n". + + // Check if free space is available + TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= _dwc2_controller[rhport].ep_fifo_size/4); + + _allocated_fifo_words_tx += fifo_size; + + TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %lu", fifo_size*4, _dwc2_controller[rhport].ep_fifo_size-_allocated_fifo_words_tx*4); + + // DIEPTXF starts at FIFO #1. + // Both TXFD and TXSA are in unit of 32-bit words. + dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | (_dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx); + + dwc2->epin[epnum].diepctl |= (1 << DIEPCTL_USBAEP_Pos) | + (epnum << DIEPCTL_TXFNUM_Pos) | + (desc_edpt->bmAttributes.xfer << DIEPCTL_EPTYP_Pos) | + (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DIEPCTL_SD0PID_SEVNFRM : 0) | + (xfer->max_size << DIEPCTL_MPSIZ_Pos); + + dwc2->daintmsk |= (1 << (DAINTMSK_IEPM_Pos + epnum)); + } + + return true; +} + +// Close all non-control endpoints, cancel all pending transfers if any. +void dcd_edpt_close_all (uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + + // Disable non-control interrupt + dwc2->daintmsk = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos); + + for(uint8_t n = 1; n < ep_count; n++) + { + // disable OUT endpoint + dwc2->epout[n].doepctl = 0; + xfer_status[n][TUSB_DIR_OUT].max_size = 0; + + // disable IN endpoint + dwc2->epin[n].diepctl = 0; + xfer_status[n][TUSB_DIR_IN].max_size = 0; + } + + // reset allocated fifo IN + _allocated_fifo_words_tx = 16; +} + +bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); + xfer->buffer = buffer; + xfer->ff = NULL; + xfer->total_len = total_bytes; + + // EP0 can only handle one packet + if(epnum == 0) + { + ep0_pending[dir] = total_bytes; + + // Schedule the first transaction for EP0 transfer + edpt_schedule_packets(rhport, epnum, dir, 1, ep0_pending[dir]); + } + else + { + uint16_t num_packets = (total_bytes / xfer->max_size); + uint16_t const short_packet_size = total_bytes % xfer->max_size; + + // Zero-size packet is special case. + if ( (short_packet_size > 0) || (total_bytes == 0) ) num_packets++; + + // Schedule packets to be sent within interrupt + edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes); + } + + return true; +} + +// The number of bytes has to be given explicitly to allow more flexible control of how many +// bytes should be written and second to keep the return value free to give back a boolean +// success message. If total_bytes is too big, the FIFO will copy only what is available +// into the USB buffer! +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1 + TU_ASSERT(ff->item_size == 1); + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); + xfer->buffer = NULL; + xfer->ff = ff; + xfer->total_len = total_bytes; + + uint16_t num_packets = (total_bytes / xfer->max_size); + uint16_t const short_packet_size = total_bytes % xfer->max_size; + + // Zero-size packet is special case. + if ( short_packet_size > 0 || (total_bytes == 0) ) num_packets++; + + // Schedule packets to be sent within interrupt + edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes); + + return true; +} + +static void dcd_edpt_disable (uint8_t rhport, uint8_t ep_addr, bool stall) +{ + (void) rhport; + + dwc2_regs_t *dwc2 = DWC2_REG(rhport); + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + if ( dir == TUSB_DIR_IN ) + { + dwc2_epin_t* epin = dwc2->epin; + + // Only disable currently enabled non-control endpoint + if ( (epnum == 0) || !(epin[epnum].diepctl & DIEPCTL_EPENA) ) + { + epin[epnum].diepctl |= DIEPCTL_SNAK | (stall ? DIEPCTL_STALL : 0); + } + else + { + // Stop transmitting packets and NAK IN xfers. + epin[epnum].diepctl |= DIEPCTL_SNAK; + while ( (epin[epnum].diepint & DIEPINT_INEPNE) == 0 ) {} + + // Disable the endpoint. + epin[epnum].diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0); + while ( (epin[epnum].diepint & DIEPINT_EPDISD_Msk) == 0 ) {} + + epin[epnum].diepint = DIEPINT_EPDISD; + } + + // Flush the FIFO, and wait until we have confirmed it cleared. + dwc2->grstctl = ((epnum << GRSTCTL_TXFNUM_Pos) | GRSTCTL_TXFFLSH); + while ( (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) != 0 ) {} + } + else + { + dwc2_epout_t* epout = dwc2->epout; + + // Only disable currently enabled non-control endpoint + if ( (epnum == 0) || !(epout[epnum].doepctl & DOEPCTL_EPENA) ) + { + epout[epnum].doepctl |= stall ? DOEPCTL_STALL : 0; + } + else + { + // Asserting GONAK is required to STALL an OUT endpoint. + // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt + // anyway, and it can't be cleared by user code. If this while loop never + // finishes, we have bigger problems than just the stack. + dwc2->dctl |= DCTL_SGONAK; + while ( (dwc2->gintsts & GINTSTS_BOUTNAKEFF_Msk) == 0 ) {} + + // Ditto here- disable the endpoint. + epout[epnum].doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0); + while ( (epout[epnum].doepint & DOEPINT_EPDISD_Msk) == 0 ) {} + + epout[epnum].doepint = DOEPINT_EPDISD; + + // Allow other OUT endpoints to keep receiving. + dwc2->dctl |= DCTL_CGONAK; + } + } +} + +/** + * Close an endpoint. + */ +void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + dcd_edpt_disable(rhport, ep_addr, false); + + // Update max_size + xfer_status[epnum][dir].max_size = 0; // max_size = 0 marks a disabled EP - required for changing FIFO allocation + + if (dir == TUSB_DIR_IN) + { + uint16_t const fifo_size = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXFD_Msk) >> DIEPTXF_INEPTXFD_Pos; + uint16_t const fifo_start = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXSA_Msk) >> DIEPTXF_INEPTXSA_Pos; + + // For now only the last opened endpoint can be closed without fuss. + TU_ASSERT(fifo_start == _dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx,); + _allocated_fifo_words_tx -= fifo_size; + } + else + { + _out_ep_closed = true; // Set flag such that RX FIFO gets reduced in size once RX FIFO is empty + } +} + +void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) +{ + dcd_edpt_disable(rhport, ep_addr, true); +} + +void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + // Clear stall and reset data toggle + if ( dir == TUSB_DIR_IN ) + { + dwc2->epin[epnum].diepctl &= ~DIEPCTL_STALL; + dwc2->epin[epnum].diepctl |= DIEPCTL_SD0PID_SEVNFRM; + } + else + { + dwc2->epout[epnum].doepctl &= ~DOEPCTL_STALL; + dwc2->epout[epnum].doepctl |= DOEPCTL_SD0PID_SEVNFRM; + } +} + +/*------------------------------------------------------------------*/ + +// Read a single data packet from receive FIFO +static void read_fifo_packet(uint8_t rhport, uint8_t * dst, uint16_t len) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + volatile const uint32_t * rx_fifo = dwc2->fifo[0]; + + // Reading full available 32 bit words from fifo + uint16_t full_words = len >> 2; + while(full_words--) + { + tu_unaligned_write32(dst, *rx_fifo); + dst += 4; + } + + // Read the remaining 1-3 bytes from fifo + uint8_t const bytes_rem = len & 0x03; + if ( bytes_rem != 0 ) + { + uint32_t const tmp = *rx_fifo; + dst[0] = tu_u32_byte0(tmp); + if ( bytes_rem > 1 ) dst[1] = tu_u32_byte1(tmp); + if ( bytes_rem > 2 ) dst[2] = tu_u32_byte2(tmp); + } +} + +// Write a single data packet to EPIN FIFO +static void write_fifo_packet(uint8_t rhport, uint8_t fifo_num, uint8_t const * src, uint16_t len) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + volatile uint32_t * tx_fifo = dwc2->fifo[fifo_num]; + + // Pushing full available 32 bit words to fifo + uint16_t full_words = len >> 2; + while(full_words--) + { + *tx_fifo = tu_unaligned_read32(src); + src += 4; + } + + // Write the remaining 1-3 bytes into fifo + uint8_t const bytes_rem = len & 0x03; + if ( bytes_rem ) + { + uint32_t tmp_word = src[0]; + if ( bytes_rem > 1 ) tmp_word |= (src[1] << 8); + if ( bytes_rem > 2 ) tmp_word |= (src[2] << 16); + + *tx_fifo = tmp_word; + } +} + +static void handle_rxflvl_irq(uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + volatile uint32_t const * rx_fifo = dwc2->fifo[0]; + + // Pop control word off FIFO + uint32_t const ctl_word = dwc2->grxstsp; + uint8_t const pktsts = (ctl_word & GRXSTSP_PKTSTS_Msk ) >> GRXSTSP_PKTSTS_Pos; + uint8_t const epnum = (ctl_word & GRXSTSP_EPNUM_Msk ) >> GRXSTSP_EPNUM_Pos; + uint16_t const bcnt = (ctl_word & GRXSTSP_BCNT_Msk ) >> GRXSTSP_BCNT_Pos; + + dwc2_epout_t* epout = &dwc2->epout[epnum]; + +//#if CFG_TUSB_DEBUG >= DWC2_DEBUG +// const char * pktsts_str[] = +// { +// "ASSERT", "Global NAK (ISR)", "Out Data Received", "Out Transfer Complete (ISR)", +// "Setup Complete (ISR)", "ASSERT", "Setup Data Received" +// }; +// TU_LOG_LOCATION(); +// TU_LOG(DWC2_DEBUG, " EP %02X, Byte Count %u, %s\r\n", epnum, bcnt, pktsts_str[pktsts]); +// TU_LOG(DWC2_DEBUG, " daint = %08lX, doepint = %04X\r\n", (unsigned long) dwc2->daint, (unsigned int) epout->doepint); +//#endif + + switch ( pktsts ) + { + // Global OUT NAK: do nothign + case GRXSTS_PKTSTS_GLOBALOUTNAK: break; + + case GRXSTS_PKTSTS_SETUPRX: + // Setup packet received + + // We can receive up to three setup packets in succession, but + // only the last one is valid. + _setup_packet[0] = (*rx_fifo); + _setup_packet[1] = (*rx_fifo); + break; + + case GRXSTS_PKTSTS_SETUPDONE: + // Setup packet done (Interrupt) + epout->doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); + break; + + case GRXSTS_PKTSTS_OUTRX: + { + // Out packet received + xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); + + // Read packet off RxFIFO + if ( xfer->ff ) + { + // Ring buffer + tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void*) (uintptr_t) rx_fifo, bcnt); + } + else + { + // Linear buffer + read_fifo_packet(rhport, xfer->buffer, bcnt); + + // Increment pointer to xfer data + xfer->buffer += bcnt; + } + + // Truncate transfer length in case of short packet + if ( bcnt < xfer->max_size ) + { + xfer->total_len -= (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos; + if ( epnum == 0 ) + { + xfer->total_len -= ep0_pending[TUSB_DIR_OUT]; + ep0_pending[TUSB_DIR_OUT] = 0; + } + } + } + break; + + // Out packet done (Interrupt) + case GRXSTS_PKTSTS_OUTDONE: + // Occurred on STM32L47 with dwc2 version 3.10a but not found on other version like 2.80a or 3.30a + // May (or not) be 3.10a specific feature/bug or depending on MCU configuration + // XFRC complete is additionally generated when + // - setup packet is received + // - complete the data stage of control write is complete + if ((epnum == 0) && (bcnt == 0) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) + { + uint32_t doepint = epout->doepint; + + if (doepint & (DOEPINT_STPKTRX | DOEPINT_OTEPSPR)) + { + // skip this "no-data" transfer complete event + // Note: STPKTRX will be clear later by setup received handler + uint32_t clear_flags = DOEPINT_XFRC; + + if (doepint & DOEPINT_OTEPSPR) clear_flags |= DOEPINT_OTEPSPR; + + epout->doepint = clear_flags; + + // TU_LOG(DWC2_DEBUG, " FIX extra transfer complete on setup/data compete\r\n"); + } + } + break; + + default: // Invalid + TU_BREAKPOINT(); + break; + } +} + +static void handle_epout_irq (uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + + // DAINT for a given EP clears when DOEPINTx is cleared. + // OEPINT will be cleared when DAINT's out bits are cleared. + for ( uint8_t n = 0; n < ep_count; n++ ) + { + if ( dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + n) ) + { + dwc2_epout_t* epout = &dwc2->epout[n]; + + uint32_t const doepint = epout->doepint; + + // SETUP packet Setup Phase done. + if ( doepint & DOEPINT_STUP ) + { + uint32_t clear_flag = DOEPINT_STUP; + + // STPKTRX is only available for version from 3_00a + if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) + { + clear_flag |= DOEPINT_STPKTRX; + } + + epout->doepint = clear_flag; + dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true); + } + + // OUT XFER complete + if ( epout->doepint & DOEPINT_XFRC ) + { + epout->doepint = DOEPINT_XFRC; + + xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT); + + // EP0 can only handle one packet + if ( (n == 0) && ep0_pending[TUSB_DIR_OUT] ) + { + // Schedule another packet to be received. + edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); + } + else + { + dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true); + } + } + } + } +} + +static void handle_epin_irq (uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + dwc2_epin_t* epin = dwc2->epin; + + // DAINT for a given EP clears when DIEPINTx is cleared. + // IEPINT will be cleared when DAINT's out bits are cleared. + for ( uint8_t n = 0; n < ep_count; n++ ) + { + if ( dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + n) ) + { + // IN XFER complete (entire xfer). + xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_IN); + + if ( epin[n].diepint & DIEPINT_XFRC ) + { + epin[n].diepint = DIEPINT_XFRC; + + // EP0 can only handle one packet + if ( (n == 0) && ep0_pending[TUSB_DIR_IN] ) + { + // Schedule another packet to be transmitted. + edpt_schedule_packets(rhport, n, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]); + } + else + { + dcd_event_xfer_complete(rhport, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); + } + } + + // XFER FIFO empty + if ( (epin[n].diepint & DIEPINT_TXFE) && (dwc2->diepempmsk & (1 << n)) ) + { + // diepint's TXFE bit is read-only, software cannot clear it. + // It will only be cleared by hardware when written bytes is more than + // - 64 bytes or + // - Half of TX FIFO size (configured by DIEPTXF) + + uint16_t remaining_packets = (epin[n].dieptsiz & DIEPTSIZ_PKTCNT_Msk) >> DIEPTSIZ_PKTCNT_Pos; + + // Process every single packet (only whole packets can be written to fifo) + for ( uint16_t i = 0; i < remaining_packets; i++ ) + { + uint16_t const remaining_bytes = (epin[n].dieptsiz & DIEPTSIZ_XFRSIZ_Msk) >> DIEPTSIZ_XFRSIZ_Pos; + + // Packet can not be larger than ep max size + uint16_t const packet_size = tu_min16(remaining_bytes, xfer->max_size); + + // It's only possible to write full packets into FIFO. Therefore DTXFSTS register of current + // EP has to be checked if the buffer can take another WHOLE packet + if ( packet_size > ((epin[n].dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2) ) break; + + // Push packet to Tx-FIFO + if ( xfer->ff ) + { + volatile uint32_t *tx_fifo = dwc2->fifo[n]; + tu_fifo_read_n_const_addr_full_words(xfer->ff, (void*) (uintptr_t) tx_fifo, packet_size); + } + else + { + write_fifo_packet(rhport, n, xfer->buffer, packet_size); + + // Increment pointer to xfer data + xfer->buffer += packet_size; + } + } + + // Turn off TXFE if all bytes are written. + if ( ((epin[n].dieptsiz & DIEPTSIZ_XFRSIZ_Msk) >> DIEPTSIZ_XFRSIZ_Pos) == 0 ) + { + dwc2->diepempmsk &= ~(1 << n); + } + } + } + } +} + +void dcd_int_handler(uint8_t rhport) +{ + dwc2_regs_t *dwc2 = DWC2_REG(rhport); + + uint32_t const int_status = dwc2->gintsts & dwc2->gintmsk; + + if(int_status & GINTSTS_USBRST) + { + // USBRST is start of reset. + dwc2->gintsts = GINTSTS_USBRST; + bus_reset(rhport); + } + + if(int_status & GINTSTS_ENUMDNE) + { + // ENUMDNE is the end of reset where speed of the link is detected + + dwc2->gintsts = GINTSTS_ENUMDNE; + + tusb_speed_t speed; + switch ((dwc2->dsts & DSTS_ENUMSPD_Msk) >> DSTS_ENUMSPD_Pos) + { + case DSTS_ENUMSPD_HS: + speed = TUSB_SPEED_HIGH; + break; + + case DSTS_ENUMSPD_LS: + speed = TUSB_SPEED_LOW; + break; + + case DSTS_ENUMSPD_FS_HSPHY: + case DSTS_ENUMSPD_FS: + default: + speed = TUSB_SPEED_FULL; + break; + } + + dcd_event_bus_reset(rhport, speed, true); + } + + if(int_status & GINTSTS_USBSUSP) + { + dwc2->gintsts = GINTSTS_USBSUSP; + dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); + } + + if(int_status & GINTSTS_WKUINT) + { + dwc2->gintsts = GINTSTS_WKUINT; + dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); + } + + // TODO check GINTSTS_DISCINT for disconnect detection + // if(int_status & GINTSTS_DISCINT) + + if(int_status & GINTSTS_OTGINT) + { + // OTG INT bit is read-only + uint32_t const otg_int = dwc2->gotgint; + + if (otg_int & GOTGINT_SEDET) + { + dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); + } + + dwc2->gotgint = otg_int; + } + + if(int_status & GINTSTS_SOF) + { + dwc2->gotgint = GINTSTS_SOF; + + if (_sof_en) + { + uint32_t frame = (dwc2->dsts & (DSTS_FNSOF)) >> 8; + dcd_event_sof(rhport, frame, true); + } + else + { + // Disable SOF interrupt if SOF was not explicitly enabled. SOF was used for remote wakeup detection + dwc2->gintmsk &= ~GINTMSK_SOFM; + } + + dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true); + } + + // RxFIFO non-empty interrupt handling. + if(int_status & GINTSTS_RXFLVL) + { + // RXFLVL bit is read-only + + // Mask out RXFLVL while reading data from FIFO + dwc2->gintmsk &= ~GINTMSK_RXFLVLM; + + // Loop until all available packets were handled + do + { + handle_rxflvl_irq(rhport); + } while(dwc2->gotgint & GINTSTS_RXFLVL); + + // Manage RX FIFO size + if (_out_ep_closed) + { + update_grxfsiz(rhport); + + // Disable flag + _out_ep_closed = false; + } + + dwc2->gintmsk |= GINTMSK_RXFLVLM; + } + + // OUT endpoint interrupt handling. + if(int_status & GINTSTS_OEPINT) + { + // OEPINT is read-only, clear using DOEPINTn + handle_epout_irq(rhport); + } + + // IN endpoint interrupt handling. + if(int_status & GINTSTS_IEPINT) + { + // IEPINT bit read-only, clear using DIEPINTn + handle_epin_irq(rhport); + } + + // // Check for Incomplete isochronous IN transfer + // if(int_status & GINTSTS_IISOIXFR) { + // printf(" IISOIXFR!\r\n"); + //// TU_LOG(DWC2_DEBUG, " IISOIXFR!\r\n"); + // } +} + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_bcm.h b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_bcm.h new file mode 100644 index 00000000..732d96ae --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_bcm.h @@ -0,0 +1,89 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_DWC2_BCM_H_ +#define _TUSB_DWC2_BCM_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "broadcom/defines.h" +#include "broadcom/interrupts.h" +#include "broadcom/caches.h" + +#define DWC2_EP_MAX 8 + +static const dwc2_controller_t _dwc2_controller[] = +{ + { .reg_base = USB_OTG_GLOBAL_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 4096 } +}; + +#define dcache_clean(_addr, _size) data_clean(_addr, _size) +#define dcache_invalidate(_addr, _size) data_invalidate(_addr, _size) +#define dcache_clean_invalidate(_addr, _size) data_clean_and_invalidate(_addr, _size) + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_enable(uint8_t rhport) +{ + BP_EnableIRQ(_dwc2_controller[rhport].irqnum); +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_disable (uint8_t rhport) +{ + BP_DisableIRQ(_dwc2_controller[rhport].irqnum); +} + +static inline void dwc2_remote_wakeup_delay(void) +{ + // try to delay for 1 ms + // TODO implement later +} + +// MCU specific PHY init, called BEFORE core reset +static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // nothing to do +} + +// MCU specific PHY update, it is called AFTER init() and core reset +static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // nothing to do +} + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_efm32.h b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_efm32.h new file mode 100644 index 00000000..0e3570cb --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_efm32.h @@ -0,0 +1,89 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Rafael Silva (@perigoso) + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _DWC2_EFM32_H_ +#define _DWC2_EFM32_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "em_device.h" + +// EFM32 has custom control register before DWC registers +#define DWC2_REG_BASE (USB_BASE + offsetof(USB_TypeDef, GOTGCTL)) +#define DWC2_EP_MAX 7 + +static const dwc2_controller_t _dwc2_controller[] = +{ + { .reg_base = DWC2_REG_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 2048 } +}; + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_enable(uint8_t rhport) +{ + NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum); +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_disable (uint8_t rhport) +{ + NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum); +} + +static inline void dwc2_remote_wakeup_delay(void) +{ + // try to delay for 1 ms +// uint32_t count = SystemCoreClock / 1000; +// while ( count-- ) __NOP(); +} + +// MCU specific PHY init, called BEFORE core reset +static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // Enable PHY + USB->ROUTE = USB_ROUTE_PHYPEN; +} + +// MCU specific PHY update, it is called AFTER init() and core reset +static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // EFM32 Manual: turn around must be 5 (reset & default value) + // dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (5u << GUSBCFG_TRDT_Pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_esp32.h b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_esp32.h new file mode 100644 index 00000000..c50dd66b --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_esp32.h @@ -0,0 +1,96 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + + +#ifndef _DWC2_ESP32_H_ +#define _DWC2_ESP32_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "esp_intr_alloc.h" +#include "soc/periph_defs.h" +//#include "soc/usb_periph.h" + +#define DWC2_REG_BASE 0x60080000UL +#define DWC2_EP_MAX 6 // USB_OUT_EP_NUM. TODO ESP32Sx only has 5 tx fifo (5 endpoint IN) + +static const dwc2_controller_t _dwc2_controller[] = +{ + { .reg_base = DWC2_REG_BASE, .irqnum = 0, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 1024 } +}; + +static intr_handle_t usb_ih; + +static void dcd_int_handler_wrap(void* arg) +{ + (void) arg; + dcd_int_handler(0); +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_enable (uint8_t rhport) +{ + (void) rhport; + esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_LOWMED, dcd_int_handler_wrap, NULL, &usb_ih); +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_disable (uint8_t rhport) +{ + (void) rhport; + esp_intr_free(usb_ih); +} + +static inline void dwc2_remote_wakeup_delay(void) +{ + vTaskDelay(pdMS_TO_TICKS(1)); +} + +// MCU specific PHY init, called BEFORE core reset +static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // nothing to do +} + +// MCU specific PHY update, it is called AFTER init() and core reset +static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // nothing to do +} + +#ifdef __cplusplus +} +#endif + +#endif /* _DWC2_ESP32_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_gd32.h b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_gd32.h new file mode 100644 index 00000000..0375fffe --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_gd32.h @@ -0,0 +1,101 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + + +#ifndef DWC2_GD32_H_ +#define DWC2_GD32_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#define DWC2_REG_BASE 0x50000000UL +#define DWC2_EP_MAX 4 + +static const dwc2_controller_t _dwc2_controller[] = +{ + { .reg_base = DWC2_REG_BASE, .irqnum = 86, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 1280 } +}; + +extern uint32_t SystemCoreClock; + +// The GD32VF103 is a RISC-V MCU, which implements the ECLIC Core-Local +// Interrupt Controller by Nuclei. It is nearly API compatible to the +// NVIC used by ARM MCUs. +#define ECLIC_INTERRUPT_ENABLE_BASE 0xD2001001UL + +TU_ATTR_ALWAYS_INLINE +static inline void __eclic_enable_interrupt (uint32_t irq) { + *(volatile uint8_t*)(ECLIC_INTERRUPT_ENABLE_BASE + (irq * 4)) = 1; +} + +TU_ATTR_ALWAYS_INLINE +static inline void __eclic_disable_interrupt (uint32_t irq){ + *(volatile uint8_t*)(ECLIC_INTERRUPT_ENABLE_BASE + (irq * 4)) = 0; +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_enable(uint8_t rhport) +{ + __eclic_enable_interrupt(_dwc2_controller[rhport].irqnum); +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_disable (uint8_t rhport) +{ + __eclic_disable_interrupt(_dwc2_controller[rhport].irqnum); +} + +static inline void dwc2_remote_wakeup_delay(void) +{ + // try to delay for 1 ms + uint32_t count = SystemCoreClock / 1000; + while ( count-- ) __asm volatile ("nop"); +} + +// MCU specific PHY init, called BEFORE core reset +static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // nothing to do +} + +// MCU specific PHY update, it is called AFTER init() and core reset +static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // nothing to do +} + +#ifdef __cplusplus +} +#endif + +#endif /* DWC2_GD32_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_stm32.h b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_stm32.h new file mode 100644 index 00000000..337f611d --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_stm32.h @@ -0,0 +1,226 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _DWC2_STM32_H_ +#define _DWC2_STM32_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +// EP_MAX : Max number of bi-directional endpoints including EP0 +// EP_FIFO_SIZE : Size of dedicated USB SRAM +#if CFG_TUSB_MCU == OPT_MCU_STM32F1 + #include "stm32f1xx.h" + #define EP_MAX_FS 4 + #define EP_FIFO_SIZE_FS 1280 + +#elif CFG_TUSB_MCU == OPT_MCU_STM32F2 + #include "stm32f2xx.h" + #define EP_MAX_FS USB_OTG_FS_MAX_IN_ENDPOINTS + #define EP_FIFO_SIZE_FS USB_OTG_FS_TOTAL_FIFO_SIZE + + #define EP_MAX_HS USB_OTG_HS_MAX_IN_ENDPOINTS + #define EP_FIFO_SIZE_HS USB_OTG_HS_TOTAL_FIFO_SIZE + +#elif CFG_TUSB_MCU == OPT_MCU_STM32F4 + #include "stm32f4xx.h" + #define EP_MAX_FS USB_OTG_FS_MAX_IN_ENDPOINTS + #define EP_FIFO_SIZE_FS USB_OTG_FS_TOTAL_FIFO_SIZE + + #define EP_MAX_HS USB_OTG_HS_MAX_IN_ENDPOINTS + #define EP_FIFO_SIZE_HS USB_OTG_HS_TOTAL_FIFO_SIZE + +#elif CFG_TUSB_MCU == OPT_MCU_STM32H7 + #include "stm32h7xx.h" + #define EP_MAX_FS 9 + #define EP_FIFO_SIZE_FS 4096 + + #define EP_MAX_HS 9 + #define EP_FIFO_SIZE_HS 4096 + + // NOTE: H7 with only 1 USB port: H72x / H73x / H7Ax / H7Bx + // USB_OTG_FS_PERIPH_BASE and OTG_FS_IRQn not defined + #if (! defined USB2_OTG_FS) + #define USB_OTG_FS_PERIPH_BASE USB1_OTG_HS_PERIPH_BASE + #define OTG_FS_IRQn OTG_HS_IRQn + #endif + +#elif CFG_TUSB_MCU == OPT_MCU_STM32F7 + #include "stm32f7xx.h" + #define EP_MAX_FS 6 + #define EP_FIFO_SIZE_FS 1280 + + #define EP_MAX_HS 9 + #define EP_FIFO_SIZE_HS 4096 + +#elif CFG_TUSB_MCU == OPT_MCU_STM32L4 + #include "stm32l4xx.h" + #define EP_MAX_FS 6 + #define EP_FIFO_SIZE_FS 1280 + +#else + #error "Unsupported MCUs" +#endif + +// OTG HS always has higher number of endpoints than FS +#ifdef USB_OTG_HS_PERIPH_BASE + #define DWC2_EP_MAX EP_MAX_HS +#else + #define DWC2_EP_MAX EP_MAX_FS +#endif + +// On STM32 for consistency we associate +// - Port0 to OTG_FS, and Port1 to OTG_HS +static const dwc2_controller_t _dwc2_controller[] = +{ +#ifdef USB_OTG_FS_PERIPH_BASE + { .reg_base = USB_OTG_FS_PERIPH_BASE, .irqnum = OTG_FS_IRQn, .ep_count = EP_MAX_FS, .ep_fifo_size = EP_FIFO_SIZE_FS }, +#endif + +#ifdef USB_OTG_HS_PERIPH_BASE + { .reg_base = USB_OTG_HS_PERIPH_BASE, .irqnum = OTG_HS_IRQn, .ep_count = EP_MAX_HS, .ep_fifo_size = EP_FIFO_SIZE_HS }, +#endif +}; + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +// SystemCoreClock is alrady included by family header +// extern uint32_t SystemCoreClock; + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_enable(uint8_t rhport) +{ + NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum); +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_disable (uint8_t rhport) +{ + NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum); +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_remote_wakeup_delay(void) +{ + // try to delay for 1 ms + uint32_t count = SystemCoreClock / 1000; + while ( count-- ) __NOP(); +} + +// MCU specific PHY init, called BEFORE core reset +static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + if ( hs_phy_type == HS_PHY_TYPE_NONE ) + { + // Enable on-chip FS PHY + dwc2->stm32_gccfg |= STM32_GCCFG_PWRDWN; + }else + { + // Disable FS PHY + dwc2->stm32_gccfg &= ~STM32_GCCFG_PWRDWN; + + // Enable on-chip HS PHY + if (hs_phy_type == HS_PHY_TYPE_UTMI || hs_phy_type == HS_PHY_TYPE_UTMI_ULPI) + { +#ifdef USB_HS_PHYC + // Enable UTMI HS PHY + dwc2->stm32_gccfg |= STM32_GCCFG_PHYHSEN; + + // Enable LDO + USB_HS_PHYC->USB_HS_PHYC_LDO |= USB_HS_PHYC_LDO_ENABLE; + + // Wait until LDO ready + while ( 0 == (USB_HS_PHYC->USB_HS_PHYC_LDO & USB_HS_PHYC_LDO_STATUS) ) {} + + uint32_t phyc_pll = 0; + + // TODO Try to get HSE_VALUE from registers instead of depending CFLAGS + switch ( HSE_VALUE ) + { + case 12000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_12MHZ ; break; + case 12500000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_12_5MHZ ; break; + case 16000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_16MHZ ; break; + case 24000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_24MHZ ; break; + case 25000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_25MHZ ; break; + case 32000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_Msk ; break; // Value not defined in header + default: + TU_ASSERT(false, ); + } + USB_HS_PHYC->USB_HS_PHYC_PLL = phyc_pll; + + // Control the tuning interface of the High Speed PHY + // Use magic value (USB_HS_PHYC_TUNE_VALUE) from ST driver for F7 + USB_HS_PHYC->USB_HS_PHYC_TUNE |= 0x00000F13U; + + // Enable PLL internal PHY + USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL_PLLEN; +#endif + } + } +} + +// MCU specific PHY update, it is called AFTER init() and core reset +static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + // used to set turnaround time for fullspeed, nothing to do in highspeed mode + if ( hs_phy_type == HS_PHY_TYPE_NONE ) + { + // Turnaround timeout depends on the AHB clock dictated by STM32 Reference Manual + uint32_t turnaround; + + if ( SystemCoreClock >= 32000000u ) + turnaround = 0x6u; + else if ( SystemCoreClock >= 27500000u ) + turnaround = 0x7u; + else if ( SystemCoreClock >= 24000000u ) + turnaround = 0x8u; + else if ( SystemCoreClock >= 21800000u ) + turnaround = 0x9u; + else if ( SystemCoreClock >= 20000000u ) + turnaround = 0xAu; + else if ( SystemCoreClock >= 18500000u ) + turnaround = 0xBu; + else if ( SystemCoreClock >= 17200000u ) + turnaround = 0xCu; + else if ( SystemCoreClock >= 16000000u ) + turnaround = 0xDu; + else if ( SystemCoreClock >= 15000000u ) + turnaround = 0xEu; + else + turnaround = 0xFu; + + dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (turnaround << GUSBCFG_TRDT_Pos); + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* _DWC2_STM32_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_type.h b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_type.h new file mode 100644 index 00000000..3fc97933 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_type.h @@ -0,0 +1,1739 @@ +/** + * @author MCD Application Team + * Ha Thach (tinyusb.org) + * + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + */ + +#ifndef _TUSB_DWC2_TYPES_H_ +#define _TUSB_DWC2_TYPES_H_ + +#include "stdint.h" + +#ifdef __cplusplus + extern "C" { +#endif + +// Controller +typedef struct +{ + uintptr_t reg_base; + uint32_t irqnum; + uint8_t ep_count; + uint32_t ep_fifo_size; +}dwc2_controller_t; + +/* DWC OTG HW Release versions */ +#define DWC2_CORE_REV_2_71a 0x4f54271a +#define DWC2_CORE_REV_2_72a 0x4f54272a +#define DWC2_CORE_REV_2_80a 0x4f54280a +#define DWC2_CORE_REV_2_90a 0x4f54290a +#define DWC2_CORE_REV_2_91a 0x4f54291a +#define DWC2_CORE_REV_2_92a 0x4f54292a +#define DWC2_CORE_REV_2_94a 0x4f54294a +#define DWC2_CORE_REV_3_00a 0x4f54300a +#define DWC2_CORE_REV_3_10a 0x4f54310a +#define DWC2_CORE_REV_4_00a 0x4f54400a +#define DWC2_CORE_REV_4_20a 0x4f54420a +#define DWC2_FS_IOT_REV_1_00a 0x5531100a +#define DWC2_HS_IOT_REV_1_00a 0x5532100a +#define DWC2_CORE_REV_MASK 0x0000ffff + +/* DWC OTG HW Core ID */ +#define DWC2_OTG_ID 0x4f540000 +#define DWC2_FS_IOT_ID 0x55310000 +#define DWC2_HS_IOT_ID 0x55320000 + +#if 0 +// HS PHY +typedef struct +{ + volatile uint32_t HS_PHYC_PLL; // This register is used to control the PLL of the HS PHY. 000h */ + volatile uint32_t Reserved04; // Reserved 004h */ + volatile uint32_t Reserved08; // Reserved 008h */ + volatile uint32_t HS_PHYC_TUNE; // This register is used to control the tuning interface of the High Speed PHY. 00Ch */ + volatile uint32_t Reserved10; // Reserved 010h */ + volatile uint32_t Reserved14; // Reserved 014h */ + volatile uint32_t HS_PHYC_LDO; // This register is used to control the regulator (LDO). 018h */ +} HS_PHYC_GlobalTypeDef; +#endif + +enum { + HS_PHY_TYPE_NONE = 0 , // not supported + HS_PHY_TYPE_UTMI , // internal PHY (mostly) + HS_PHY_TYPE_ULPI , // external PHY + HS_PHY_TYPE_UTMI_ULPI , +}; + +enum { + FS_PHY_TYPE_NONE = 0, // not supported + FS_PHY_TYPE_DEDICATED, + FS_PHY_TYPE_UTMI, + FS_PHY_TYPE_ULPI, +}; + +typedef struct TU_ATTR_PACKED +{ + uint32_t op_mode : 3; // 0: HNP and SRP | 1: SRP | 2: non-HNP, non-SRP + uint32_t arch : 2; // 0: slave-only | 1: External DMA | 2: Internal DMA | 3: others + uint32_t point2point : 1; // 0: support hub and split | 1: no hub, no split + uint32_t hs_phy_type : 2; // 0: not supported | 1: UTMI+ | 2: ULPI | 3: UTMI+ and ULPI + uint32_t fs_phy_type : 2; // 0: not supported | 1: dedicated | 2: UTMI+ | 3: ULPI + uint32_t num_dev_ep : 4; // Number of device endpoints (not including EP0) + uint32_t num_host_ch : 4; // Number of host channel + uint32_t period_channel_support : 1; // Support Periodic OUT Host Channel + uint32_t enable_dynamic_fifo : 1; // Dynamic FIFO Sizing Enabled + uint32_t mul_cpu_int : 1; // Multi-Processor Interrupt Enabled + uint32_t reserved21 : 1; + uint32_t nperiod_tx_q_depth : 2; // Non-periodic request queue depth: 0 = 2. 1 = 4, 2 = 8 + uint32_t host_period_tx_q_depth : 2; // Host periodic request queue depth: 0 = 2. 1 = 4, 2 = 8 + uint32_t dev_token_q_depth : 5; // Device IN token sequence learning queue depth: 0-30 + uint32_t otg_enable_ic_usb : 1; // IC_USB mode specified for mode of operation +} dwc2_ghwcfg2_t; + +TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg2_t) == 4, "incorrect size"); + +typedef struct TU_ATTR_PACKED +{ + uint32_t xfer_size_width : 4; // Transfer size counter in bits = 11 + n (max 19 bits) + uint32_t packet_size_width : 3; // Packet size counter in bits = 4 + n (max 10 bits) + uint32_t otg_enable : 1; // 1 is OTG capable + uint32_t i2c_enable : 1; // I2C interface is available + uint32_t vendor_ctrl_itf : 1; // Vendor control interface is available + uint32_t optional_feature_removed : 1; // remove User ID, GPIO, SOF toggle & counter + uint32_t synch_reset : 1; // 0: async reset | 1: synch reset + uint32_t otg_adp_support : 1; // ADP logic is present along with HSOTG controller + uint32_t otg_enable_hsic : 1; // 1: HSIC-capable with shared UTMI PHY interface | 0: non-HSIC + uint32_t battery_charger_support : 1; // support battery charger + uint32_t lpm_mode : 1; // LPC mode + uint32_t total_fifo_size : 16; // DFIFO depth value in terms of 32-bit words +}dwc2_ghwcfg3_t; + +TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg3_t) == 4, "incorrect size"); + +typedef struct TU_ATTR_PACKED +{ + uint32_t num_dev_period_in_ep : 4; // Number of Device Periodic IN Endpoints + uint32_t power_optimized : 1; // Partial Power Down Enabled + uint32_t ahb_freq_min : 1; // 1: minimum of AHB frequency is less than 60 MHz + uint32_t hibernation : 1; // Hibernation feature is enabled + uint32_t reserved7 : 3; + uint32_t service_interval_mode : 1; // Service Interval supported + uint32_t ipg_isoc_en : 1; // IPG ISOC supported + uint32_t acg_enable : 1; // ACG enabled + uint32_t reserved13 : 1; + uint32_t utmi_phy_data_width : 2; // 0: 8 bits | 1: 16 bits | 2: 8/16 software selectable + uint32_t dev_ctrl_ep_num : 4; // Number of Device control endpoints in addition to EP0 + uint32_t iddg_filter_enabled : 1; + uint32_t vbus_valid_filter_enabled : 1; + uint32_t a_valid_filter_enabled : 1; + uint32_t b_valid_filter_enabled : 1; + uint32_t dedicated_fifos : 1; // Dedicated tx fifo for device IN Endpoint is enabled + uint32_t num_dev_in_eps : 4; // Number of Device IN Endpoints including EP0 + uint32_t dma_desc_enable : 1; // scatter/gather DMA configuration + uint32_t dma_dynamic : 1; // Dynamic scatter/gather DMA +}dwc2_ghwcfg4_t; + +TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg4_t) == 4, "incorrect size"); + +// Host Channel +typedef struct +{ + volatile uint32_t hcchar; // 500 + 20*ch Host Channel Characteristics + volatile uint32_t hcsplt; // 504 + 20*ch Host Channel Split Control + volatile uint32_t hcint; // 508 + 20*ch Host Channel Interrupt + volatile uint32_t hcintmsk; // 50C + 20*ch Host Channel Interrupt Mask + volatile uint32_t hctsiz; // 510 + 20*ch Host Channel Transfer Size + volatile uint32_t hcdma; // 514 + 20*ch Host Channel DMA Address + uint32_t reserved518; // 518 + 20*ch + volatile uint32_t hcdmab; // 51C + 20*ch Host Channel DMA Address +} dwc2_channel_t; + +// Endpoint IN +typedef struct +{ + volatile uint32_t diepctl; // 900 + 20*ep Device IN Endpoint Control + uint32_t reserved04; // 904 + volatile uint32_t diepint; // 908 + 20*ep Device IN Endpoint Interrupt + uint32_t reserved0c; // 90C + volatile uint32_t dieptsiz; // 910 + 20*ep Device IN Endpoint Transfer Size + volatile uint32_t diepdma; // 914 + 20*ep Device IN Endpoint DMA Address + volatile uint32_t dtxfsts; // 918 + 20*ep Device IN Endpoint Tx FIFO Status + uint32_t reserved1c; // 91C +} dwc2_epin_t; + +// Endpoint OUT +typedef struct +{ + volatile uint32_t doepctl; // B00 + 20*ep Device OUT Endpoint Control + uint32_t reserved04; // B04 + volatile uint32_t doepint; // B08 + 20*ep Device OUT Endpoint Interrupt + uint32_t reserved0c; // B0C + volatile uint32_t doeptsiz; // B10 + 20*ep Device OUT Endpoint Transfer Size + volatile uint32_t doepdma; // B14 + 20*ep Device OUT Endpoint DMA Address + uint32_t reserved18[2]; // B18..B1C +} dwc2_epout_t; + +typedef struct +{ + //------------- Core Global -------------// + volatile uint32_t gotgctl; // 000 OTG Control and Status + volatile uint32_t gotgint; // 004 OTG Interrupt + volatile uint32_t gahbcfg; // 008 AHB Configuration + volatile uint32_t gusbcfg; // 00c USB Configuration + volatile uint32_t grstctl; // 010 Reset + volatile uint32_t gintsts; // 014 Interrupt + volatile uint32_t gintmsk; // 018 Interrupt Mask + volatile uint32_t grxstsr; // 01c Receive Status Debug Read + volatile uint32_t grxstsp; // 020 Receive Status Read/Pop + volatile uint32_t grxfsiz; // 024 Receive FIFO Size +union { + volatile uint32_t dieptxf0; // 028 EP0 Tx FIFO Size + volatile uint32_t gnptxfsiz; // 028 Non-periodic Transmit FIFO Size +}; + volatile uint32_t gnptxsts; // 02c Non-periodic Transmit FIFO/Queue Status + volatile uint32_t gi2cctl; // 030 I2C Address + volatile uint32_t gpvndctl; // 034 PHY Vendor Control +union { + volatile uint32_t ggpio; // 038 General Purpose IO + volatile uint32_t stm32_gccfg; // 038 STM32 General Core Configuration +}; + volatile uint32_t guid; // 03C User (Application programmable) ID + volatile uint32_t gsnpsid; // 040 Synopsys ID + Release version + volatile uint32_t ghwcfg1; // 044 User Hardware Configuration1: endpoint dir (2 bit per ep) +union { + volatile uint32_t ghwcfg2; // 048 User Hardware Configuration2 + dwc2_ghwcfg2_t ghwcfg2_bm; +}; +union { + volatile uint32_t ghwcfg3; // 04C User Hardware Configuration3 + dwc2_ghwcfg3_t ghwcfg3_bm; +}; +union { + volatile uint32_t ghwcfg4; // 050 User Hardware Configuration4 + dwc2_ghwcfg4_t ghwcfg4_bm; +}; + volatile uint32_t glpmcfg; // 054 Core LPM Configuration + volatile uint32_t gpwrdn; // 058 Power Down + volatile uint32_t gdfifocfg; // 05C DFIFO Software Configuration + volatile uint32_t gadpctl; // 060 ADP Timer, Control and Status + uint32_t reserved64[39]; // 064..0FF + volatile uint32_t hptxfsiz; // 100 Host Periodic Tx FIFO Size + volatile uint32_t dieptxf[15]; // 104..13C Device Periodic Transmit FIFO Size + uint32_t reserved140[176]; // 140..3FF + + //------------- Host -------------// + volatile uint32_t hcfg; // 400 Host Configuration + volatile uint32_t hfir; // 404 Host Frame Interval + volatile uint32_t hfnum; // 408 Host Frame Number / Frame Remaining + uint32_t reserved40c; // 40C + volatile uint32_t hptxsts; // 410 Host Periodic TX FIFO / Queue Status + volatile uint32_t haint; // 414 Host All Channels Interrupt + volatile uint32_t haintmsk; // 418 Host All Channels Interrupt Mask + volatile uint32_t hflbaddr; // 41C Host Frame List Base Address + uint32_t reserved420[8]; // 420..43F + volatile uint32_t hprt; // 440 Host Port Control and Status + uint32_t reserved444[47]; // 444..4FF + + //------------- Host Channel -------------// + dwc2_channel_t channel[16]; // 500..6FF Host Channels 0-15 + uint32_t reserved700[64]; // 700..7FF + + //------------- Device -------------// + volatile uint32_t dcfg; // 800 Device Configuration + volatile uint32_t dctl; // 804 Device Control + volatile uint32_t dsts; // 808 Device Status (RO) + uint32_t reserved80c; // 80C + volatile uint32_t diepmsk; // 810 Device IN Endpoint Interrupt Mask + volatile uint32_t doepmsk; // 814 Device OUT Endpoint Interrupt Mask + volatile uint32_t daint; // 818 Device All Endpoints Interrupt + volatile uint32_t daintmsk; // 81C Device All Endpoints Interrupt Mask + volatile uint32_t dtknqr1; // 820 Device IN token sequence learning queue read1 + volatile uint32_t dtknqr2; // 824 Device IN token sequence learning queue read2 + volatile uint32_t dvbusdis; // 828 Device VBUS Discharge Time + volatile uint32_t dvbuspulse; // 82C Device VBUS Pulsing Time + volatile uint32_t dthrctl; // 830 Device threshold Control + volatile uint32_t diepempmsk; // 834 Device IN Endpoint FIFO Empty Interrupt Mask + volatile uint32_t deachint; // 838 Device Each Endpoint Interrupt + volatile uint32_t deachmsk; // 83C Device Each Endpoint Interrupt msk + volatile uint32_t diepeachmsk[16]; // 840..87C Device Each IN Endpoint mask + volatile uint32_t doepeachmsk[16]; // 880..8BF Device Each OUT Endpoint mask + uint32_t reserved8c0[16]; // 8C0..8FF + + //------------- Device Endpoint -------------// + dwc2_epin_t epin[16]; // 900..AFF IN Endpoints + dwc2_epout_t epout[16]; // B00..CFF OUT Endpoints + uint32_t reservedd00[64]; // D00..DFF + + //------------- Power Clock -------------// + volatile uint32_t pcgctl; // E00 Power and Clock Gating Control + volatile uint32_t pcgctl1; // E04 + uint32_t reservede08[126]; // E08..FFF + + //------------- FIFOs -------------// + // Word-accessed only using first pointer since it auto shift + volatile uint32_t fifo[16][0x400]; // 1000..FFFF Endpoint FIFO +} dwc2_regs_t; + +TU_VERIFY_STATIC(offsetof(dwc2_regs_t, hcfg ) == 0x0400, "incorrect size"); +TU_VERIFY_STATIC(offsetof(dwc2_regs_t, channel) == 0x0500, "incorrect size"); +TU_VERIFY_STATIC(offsetof(dwc2_regs_t, dcfg ) == 0x0800, "incorrect size"); +TU_VERIFY_STATIC(offsetof(dwc2_regs_t, epin ) == 0x0900, "incorrect size"); +TU_VERIFY_STATIC(offsetof(dwc2_regs_t, epout ) == 0x0B00, "incorrect size"); +TU_VERIFY_STATIC(offsetof(dwc2_regs_t, pcgctl ) == 0x0E00, "incorrect size"); +TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size"); + +//--------------------------------------------------------------------+ +// Register Bit Definitions +//--------------------------------------------------------------------+ + +/******************** Bit definition for GOTGCTL register ********************/ +#define GOTGCTL_SRQSCS_Pos (0U) +#define GOTGCTL_SRQSCS_Msk (0x1UL << GOTGCTL_SRQSCS_Pos) // 0x00000001 */ +#define GOTGCTL_SRQSCS GOTGCTL_SRQSCS_Msk // Session request success */ +#define GOTGCTL_SRQ_Pos (1U) +#define GOTGCTL_SRQ_Msk (0x1UL << GOTGCTL_SRQ_Pos) // 0x00000002 */ +#define GOTGCTL_SRQ GOTGCTL_SRQ_Msk // Session request */ +#define GOTGCTL_VBVALOEN_Pos (2U) +#define GOTGCTL_VBVALOEN_Msk (0x1UL << GOTGCTL_VBVALOEN_Pos) // 0x00000004 */ +#define GOTGCTL_VBVALOEN GOTGCTL_VBVALOEN_Msk // VBUS valid override enable */ +#define GOTGCTL_VBVALOVAL_Pos (3U) +#define GOTGCTL_VBVALOVAL_Msk (0x1UL << GOTGCTL_VBVALOVAL_Pos) // 0x00000008 */ +#define GOTGCTL_VBVALOVAL GOTGCTL_VBVALOVAL_Msk // VBUS valid override value */ +#define GOTGCTL_AVALOEN_Pos (4U) +#define GOTGCTL_AVALOEN_Msk (0x1UL << GOTGCTL_AVALOEN_Pos) // 0x00000010 */ +#define GOTGCTL_AVALOEN GOTGCTL_AVALOEN_Msk // A-peripheral session valid override enable */ +#define GOTGCTL_AVALOVAL_Pos (5U) +#define GOTGCTL_AVALOVAL_Msk (0x1UL << GOTGCTL_AVALOVAL_Pos) // 0x00000020 */ +#define GOTGCTL_AVALOVAL GOTGCTL_AVALOVAL_Msk // A-peripheral session valid override value */ +#define GOTGCTL_BVALOEN_Pos (6U) +#define GOTGCTL_BVALOEN_Msk (0x1UL << GOTGCTL_BVALOEN_Pos) // 0x00000040 */ +#define GOTGCTL_BVALOEN GOTGCTL_BVALOEN_Msk // B-peripheral session valid override enable */ +#define GOTGCTL_BVALOVAL_Pos (7U) +#define GOTGCTL_BVALOVAL_Msk (0x1UL << GOTGCTL_BVALOVAL_Pos) // 0x00000080 */ +#define GOTGCTL_BVALOVAL GOTGCTL_BVALOVAL_Msk // B-peripheral session valid override value */ +#define GOTGCTL_HNGSCS_Pos (8U) +#define GOTGCTL_HNGSCS_Msk (0x1UL << GOTGCTL_HNGSCS_Pos) // 0x00000100 */ +#define GOTGCTL_HNGSCS GOTGCTL_HNGSCS_Msk // Host set HNP enable */ +#define GOTGCTL_HNPRQ_Pos (9U) +#define GOTGCTL_HNPRQ_Msk (0x1UL << GOTGCTL_HNPRQ_Pos) // 0x00000200 */ +#define GOTGCTL_HNPRQ GOTGCTL_HNPRQ_Msk // HNP request */ +#define GOTGCTL_HSHNPEN_Pos (10U) +#define GOTGCTL_HSHNPEN_Msk (0x1UL << GOTGCTL_HSHNPEN_Pos) // 0x00000400 */ +#define GOTGCTL_HSHNPEN GOTGCTL_HSHNPEN_Msk // Host set HNP enable */ +#define GOTGCTL_DHNPEN_Pos (11U) +#define GOTGCTL_DHNPEN_Msk (0x1UL << GOTGCTL_DHNPEN_Pos) // 0x00000800 */ +#define GOTGCTL_DHNPEN GOTGCTL_DHNPEN_Msk // Device HNP enabled */ +#define GOTGCTL_EHEN_Pos (12U) +#define GOTGCTL_EHEN_Msk (0x1UL << GOTGCTL_EHEN_Pos) // 0x00001000 */ +#define GOTGCTL_EHEN GOTGCTL_EHEN_Msk // Embedded host enable */ +#define GOTGCTL_CIDSTS_Pos (16U) +#define GOTGCTL_CIDSTS_Msk (0x1UL << GOTGCTL_CIDSTS_Pos) // 0x00010000 */ +#define GOTGCTL_CIDSTS GOTGCTL_CIDSTS_Msk // Connector ID status */ +#define GOTGCTL_DBCT_Pos (17U) +#define GOTGCTL_DBCT_Msk (0x1UL << GOTGCTL_DBCT_Pos) // 0x00020000 */ +#define GOTGCTL_DBCT GOTGCTL_DBCT_Msk // Long/short debounce time */ +#define GOTGCTL_ASVLD_Pos (18U) +#define GOTGCTL_ASVLD_Msk (0x1UL << GOTGCTL_ASVLD_Pos) // 0x00040000 */ +#define GOTGCTL_ASVLD GOTGCTL_ASVLD_Msk // A-session valid */ +#define GOTGCTL_BSESVLD_Pos (19U) +#define GOTGCTL_BSESVLD_Msk (0x1UL << GOTGCTL_BSESVLD_Pos) // 0x00080000 */ +#define GOTGCTL_BSESVLD GOTGCTL_BSESVLD_Msk // B-session valid */ +#define GOTGCTL_OTGVER_Pos (20U) +#define GOTGCTL_OTGVER_Msk (0x1UL << GOTGCTL_OTGVER_Pos) // 0x00100000 */ +#define GOTGCTL_OTGVER GOTGCTL_OTGVER_Msk // OTG version */ + +/******************** Bit definition for HCFG register ********************/ +#define HCFG_FSLSPCS_Pos (0U) +#define HCFG_FSLSPCS_Msk (0x3UL << HCFG_FSLSPCS_Pos) // 0x00000003 */ +#define HCFG_FSLSPCS HCFG_FSLSPCS_Msk // FS/LS PHY clock select */ +#define HCFG_FSLSPCS_0 (0x1UL << HCFG_FSLSPCS_Pos) // 0x00000001 */ +#define HCFG_FSLSPCS_1 (0x2UL << HCFG_FSLSPCS_Pos) // 0x00000002 */ +#define HCFG_FSLSS_Pos (2U) +#define HCFG_FSLSS_Msk (0x1UL << HCFG_FSLSS_Pos) // 0x00000004 */ +#define HCFG_FSLSS HCFG_FSLSS_Msk // FS- and LS-only support */ + +/******************** Bit definition for PCGCR register ********************/ +#define PCGCR_STPPCLK_Pos (0U) +#define PCGCR_STPPCLK_Msk (0x1UL << PCGCR_STPPCLK_Pos) // 0x00000001 */ +#define PCGCR_STPPCLK PCGCR_STPPCLK_Msk // Stop PHY clock */ +#define PCGCR_GATEHCLK_Pos (1U) +#define PCGCR_GATEHCLK_Msk (0x1UL << PCGCR_GATEHCLK_Pos) // 0x00000002 */ +#define PCGCR_GATEHCLK PCGCR_GATEHCLK_Msk // Gate HCLK */ +#define PCGCR_PHYSUSP_Pos (4U) +#define PCGCR_PHYSUSP_Msk (0x1UL << PCGCR_PHYSUSP_Pos) // 0x00000010 */ +#define PCGCR_PHYSUSP PCGCR_PHYSUSP_Msk // PHY suspended */ + +/******************** Bit definition for GOTGINT register ********************/ +#define GOTGINT_SEDET_Pos (2U) +#define GOTGINT_SEDET_Msk (0x1UL << GOTGINT_SEDET_Pos) // 0x00000004 */ +#define GOTGINT_SEDET GOTGINT_SEDET_Msk // Session end detected */ +#define GOTGINT_SRSSCHG_Pos (8U) +#define GOTGINT_SRSSCHG_Msk (0x1UL << GOTGINT_SRSSCHG_Pos) // 0x00000100 */ +#define GOTGINT_SRSSCHG GOTGINT_SRSSCHG_Msk // Session request success status change */ +#define GOTGINT_HNSSCHG_Pos (9U) +#define GOTGINT_HNSSCHG_Msk (0x1UL << GOTGINT_HNSSCHG_Pos) // 0x00000200 */ +#define GOTGINT_HNSSCHG GOTGINT_HNSSCHG_Msk // Host negotiation success status change */ +#define GOTGINT_HNGDET_Pos (17U) +#define GOTGINT_HNGDET_Msk (0x1UL << GOTGINT_HNGDET_Pos) // 0x00020000 */ +#define GOTGINT_HNGDET GOTGINT_HNGDET_Msk // Host negotiation detected */ +#define GOTGINT_ADTOCHG_Pos (18U) +#define GOTGINT_ADTOCHG_Msk (0x1UL << GOTGINT_ADTOCHG_Pos) // 0x00040000 */ +#define GOTGINT_ADTOCHG GOTGINT_ADTOCHG_Msk // A-device timeout change */ +#define GOTGINT_DBCDNE_Pos (19U) +#define GOTGINT_DBCDNE_Msk (0x1UL << GOTGINT_DBCDNE_Pos) // 0x00080000 */ +#define GOTGINT_DBCDNE GOTGINT_DBCDNE_Msk // Debounce done */ +#define GOTGINT_IDCHNG_Pos (20U) +#define GOTGINT_IDCHNG_Msk (0x1UL << GOTGINT_IDCHNG_Pos) // 0x00100000 */ +#define GOTGINT_IDCHNG GOTGINT_IDCHNG_Msk // Change in ID pin input value */ + +/******************** Bit definition for DCFG register ********************/ +#define DCFG_DSPD_Pos (0U) +#define DCFG_DSPD_Msk (0x3UL << DCFG_DSPD_Pos) // 0x00000003 +#define DCFG_DSPD_HS 0 // Highspeed +#define DCFG_DSPD_FS_HSPHY 1 // Fullspeed on HS PHY +#define DCFG_DSPD_LS 2 // Lowspeed +#define DCFG_DSPD_FS 3 // Fullspeed on FS PHY + +#define DCFG_NZLSOHSK_Pos (2U) +#define DCFG_NZLSOHSK_Msk (0x1UL << DCFG_NZLSOHSK_Pos) // 0x00000004 */ +#define DCFG_NZLSOHSK DCFG_NZLSOHSK_Msk // Nonzero-length status OUT handshake */ + +#define DCFG_DAD_Pos (4U) +#define DCFG_DAD_Msk (0x7FUL << DCFG_DAD_Pos) // 0x000007F0 */ +#define DCFG_DAD DCFG_DAD_Msk // Device address */ +#define DCFG_DAD_0 (0x01UL << DCFG_DAD_Pos) // 0x00000010 */ +#define DCFG_DAD_1 (0x02UL << DCFG_DAD_Pos) // 0x00000020 */ +#define DCFG_DAD_2 (0x04UL << DCFG_DAD_Pos) // 0x00000040 */ +#define DCFG_DAD_3 (0x08UL << DCFG_DAD_Pos) // 0x00000080 */ +#define DCFG_DAD_4 (0x10UL << DCFG_DAD_Pos) // 0x00000100 */ +#define DCFG_DAD_5 (0x20UL << DCFG_DAD_Pos) // 0x00000200 */ +#define DCFG_DAD_6 (0x40UL << DCFG_DAD_Pos) // 0x00000400 */ + +#define DCFG_PFIVL_Pos (11U) +#define DCFG_PFIVL_Msk (0x3UL << DCFG_PFIVL_Pos) // 0x00001800 */ +#define DCFG_PFIVL DCFG_PFIVL_Msk // Periodic (micro)frame interval */ +#define DCFG_PFIVL_0 (0x1UL << DCFG_PFIVL_Pos) // 0x00000800 */ +#define DCFG_PFIVL_1 (0x2UL << DCFG_PFIVL_Pos) // 0x00001000 */ + +#define DCFG_XCVRDLY_Pos (14U) +#define DCFG_XCVRDLY_Msk (0x1UL << DCFG_XCVRDLY_Pos) /*!< 0x00004000 */ +#define DCFG_XCVRDLY DCFG_XCVRDLY_Msk // Enables delay between xcvr_sel and txvalid during device chirp + +#define DCFG_PERSCHIVL_Pos (24U) +#define DCFG_PERSCHIVL_Msk (0x3UL << DCFG_PERSCHIVL_Pos) // 0x03000000 */ +#define DCFG_PERSCHIVL DCFG_PERSCHIVL_Msk // Periodic scheduling interval */ +#define DCFG_PERSCHIVL_0 (0x1UL << DCFG_PERSCHIVL_Pos) // 0x01000000 */ +#define DCFG_PERSCHIVL_1 (0x2UL << DCFG_PERSCHIVL_Pos) // 0x02000000 */ + +/******************** Bit definition for DCTL register ********************/ +#define DCTL_RWUSIG_Pos (0U) +#define DCTL_RWUSIG_Msk (0x1UL << DCTL_RWUSIG_Pos) // 0x00000001 */ +#define DCTL_RWUSIG DCTL_RWUSIG_Msk // Remote wakeup signaling */ +#define DCTL_SDIS_Pos (1U) +#define DCTL_SDIS_Msk (0x1UL << DCTL_SDIS_Pos) // 0x00000002 */ +#define DCTL_SDIS DCTL_SDIS_Msk // Soft disconnect */ +#define DCTL_GINSTS_Pos (2U) +#define DCTL_GINSTS_Msk (0x1UL << DCTL_GINSTS_Pos) // 0x00000004 */ +#define DCTL_GINSTS DCTL_GINSTS_Msk // Global IN NAK status */ +#define DCTL_GONSTS_Pos (3U) +#define DCTL_GONSTS_Msk (0x1UL << DCTL_GONSTS_Pos) // 0x00000008 */ +#define DCTL_GONSTS DCTL_GONSTS_Msk // Global OUT NAK status */ + +#define DCTL_TCTL_Pos (4U) +#define DCTL_TCTL_Msk (0x7UL << DCTL_TCTL_Pos) // 0x00000070 */ +#define DCTL_TCTL DCTL_TCTL_Msk // Test control */ +#define DCTL_TCTL_0 (0x1UL << DCTL_TCTL_Pos) // 0x00000010 */ +#define DCTL_TCTL_1 (0x2UL << DCTL_TCTL_Pos) // 0x00000020 */ +#define DCTL_TCTL_2 (0x4UL << DCTL_TCTL_Pos) // 0x00000040 */ +#define DCTL_SGINAK_Pos (7U) +#define DCTL_SGINAK_Msk (0x1UL << DCTL_SGINAK_Pos) // 0x00000080 */ +#define DCTL_SGINAK DCTL_SGINAK_Msk // Set global IN NAK */ +#define DCTL_CGINAK_Pos (8U) +#define DCTL_CGINAK_Msk (0x1UL << DCTL_CGINAK_Pos) // 0x00000100 */ +#define DCTL_CGINAK DCTL_CGINAK_Msk // Clear global IN NAK */ +#define DCTL_SGONAK_Pos (9U) +#define DCTL_SGONAK_Msk (0x1UL << DCTL_SGONAK_Pos) // 0x00000200 */ +#define DCTL_SGONAK DCTL_SGONAK_Msk // Set global OUT NAK */ +#define DCTL_CGONAK_Pos (10U) +#define DCTL_CGONAK_Msk (0x1UL << DCTL_CGONAK_Pos) // 0x00000400 */ +#define DCTL_CGONAK DCTL_CGONAK_Msk // Clear global OUT NAK */ +#define DCTL_POPRGDNE_Pos (11U) +#define DCTL_POPRGDNE_Msk (0x1UL << DCTL_POPRGDNE_Pos) // 0x00000800 */ +#define DCTL_POPRGDNE DCTL_POPRGDNE_Msk // Power-on programming done */ + +/******************** Bit definition for HFIR register ********************/ +#define HFIR_FRIVL_Pos (0U) +#define HFIR_FRIVL_Msk (0xFFFFUL << HFIR_FRIVL_Pos) // 0x0000FFFF */ +#define HFIR_FRIVL HFIR_FRIVL_Msk // Frame interval */ + +/******************** Bit definition for HFNUM register ********************/ +#define HFNUM_FRNUM_Pos (0U) +#define HFNUM_FRNUM_Msk (0xFFFFUL << HFNUM_FRNUM_Pos) // 0x0000FFFF */ +#define HFNUM_FRNUM HFNUM_FRNUM_Msk // Frame number */ +#define HFNUM_FTREM_Pos (16U) +#define HFNUM_FTREM_Msk (0xFFFFUL << HFNUM_FTREM_Pos) // 0xFFFF0000 */ +#define HFNUM_FTREM HFNUM_FTREM_Msk // Frame time remaining */ + +/******************** Bit definition for DSTS register ********************/ +#define DSTS_SUSPSTS_Pos (0U) +#define DSTS_SUSPSTS_Msk (0x1UL << DSTS_SUSPSTS_Pos) // 0x00000001 */ +#define DSTS_SUSPSTS DSTS_SUSPSTS_Msk // Suspend status */ +#define DSTS_ENUMSPD_Pos (1U) +#define DSTS_ENUMSPD_Msk (0x3UL << DSTS_ENUMSPD_Pos) // 0x00000006 */ +#define DSTS_ENUMSPD DSTS_ENUMSPD_Msk // Enumerated speed */ +#define DSTS_ENUMSPD_HS 0 // Highspeed +#define DSTS_ENUMSPD_FS_HSPHY 1 // Fullspeed on HS PHY +#define DSTS_ENUMSPD_LS 2 // Lowspeed +#define DSTS_ENUMSPD_FS 3 // Fullspeed on FS PHY + + +#define DSTS_EERR_Pos (3U) +#define DSTS_EERR_Msk (0x1UL << DSTS_EERR_Pos) // 0x00000008 */ +#define DSTS_EERR DSTS_EERR_Msk // Erratic error */ +#define DSTS_FNSOF_Pos (8U) +#define DSTS_FNSOF_Msk (0x3FFFUL << DSTS_FNSOF_Pos) // 0x003FFF00 */ +#define DSTS_FNSOF DSTS_FNSOF_Msk // Frame number of the received SOF */ + +/******************** Bit definition for GAHBCFG register ********************/ +#define GAHBCFG_GINT_Pos (0U) +#define GAHBCFG_GINT_Msk (0x1UL << GAHBCFG_GINT_Pos) // 0x00000001 */ +#define GAHBCFG_GINT GAHBCFG_GINT_Msk // Global interrupt mask */ +#define GAHBCFG_HBSTLEN_Pos (1U) +#define GAHBCFG_HBSTLEN_Msk (0xFUL << GAHBCFG_HBSTLEN_Pos) // 0x0000001E */ +#define GAHBCFG_HBSTLEN GAHBCFG_HBSTLEN_Msk // Burst length/type */ +#define GAHBCFG_HBSTLEN_0 (0x0UL << GAHBCFG_HBSTLEN_Pos) // Single */ +#define GAHBCFG_HBSTLEN_1 (0x1UL << GAHBCFG_HBSTLEN_Pos) // INCR */ +#define GAHBCFG_HBSTLEN_2 (0x3UL << GAHBCFG_HBSTLEN_Pos) // INCR4 */ +#define GAHBCFG_HBSTLEN_3 (0x5UL << GAHBCFG_HBSTLEN_Pos) // INCR8 */ +#define GAHBCFG_HBSTLEN_4 (0x7UL << GAHBCFG_HBSTLEN_Pos) // INCR16 */ +#define GAHBCFG_DMAEN_Pos (5U) +#define GAHBCFG_DMAEN_Msk (0x1UL << GAHBCFG_DMAEN_Pos) // 0x00000020 */ +#define GAHBCFG_DMAEN GAHBCFG_DMAEN_Msk // DMA enable */ +#define GAHBCFG_TXFELVL_Pos (7U) +#define GAHBCFG_TXFELVL_Msk (0x1UL << GAHBCFG_TXFELVL_Pos) // 0x00000080 */ +#define GAHBCFG_TXFELVL GAHBCFG_TXFELVL_Msk // TxFIFO empty level */ +#define GAHBCFG_PTXFELVL_Pos (8U) +#define GAHBCFG_PTXFELVL_Msk (0x1UL << GAHBCFG_PTXFELVL_Pos) // 0x00000100 */ +#define GAHBCFG_PTXFELVL GAHBCFG_PTXFELVL_Msk // Periodic TxFIFO empty level */ + +#define GSNPSID_ID_MASK TU_GENMASK(31, 16) + +/******************** Bit definition for GUSBCFG register ********************/ +#define GUSBCFG_TOCAL_Pos (0U) +#define GUSBCFG_TOCAL_Msk (0x7UL << GUSBCFG_TOCAL_Pos) // 0x00000007 */ +#define GUSBCFG_TOCAL GUSBCFG_TOCAL_Msk // FS timeout calibration */ +#define GUSBCFG_PHYIF16_Pos (3U) +#define GUSBCFG_PHYIF16_Msk (0x1UL << GUSBCFG_PHYIF16_Pos) // 0x00000008 */ +#define GUSBCFG_PHYIF16 GUSBCFG_PHYIF16_Msk // PHY Interface (PHYIf) */ +#define GUSBCFG_ULPI_UTMI_SEL_Pos (4U) +#define GUSBCFG_ULPI_UTMI_SEL_Msk (0x1UL << GUSBCFG_ULPI_UTMI_SEL_Pos) // 0x00000010 */ +#define GUSBCFG_ULPI_UTMI_SEL GUSBCFG_ULPI_UTMI_SEL_Msk // ULPI or UTMI+ Select (ULPI_UTMI_Sel) */ +#define GUSBCFG_PHYSEL_Pos (6U) +#define GUSBCFG_PHYSEL_Msk (0x1UL << GUSBCFG_PHYSEL_Pos) // 0x00000040 */ +#define GUSBCFG_PHYSEL GUSBCFG_PHYSEL_Msk // USB 2.0 high-speed ULPI PHY or USB 1.1 full-speed serial transceiver select */ +#define GUSBCFG_DDRSEL TU_BIT(7) // Single Data Rate (SDR) or Double Data Rate (DDR) or ULPI interface. +#define GUSBCFG_SRPCAP_Pos (8U) +#define GUSBCFG_SRPCAP_Msk (0x1UL << GUSBCFG_SRPCAP_Pos) // 0x00000100 */ +#define GUSBCFG_SRPCAP GUSBCFG_SRPCAP_Msk // SRP-capable */ +#define GUSBCFG_HNPCAP_Pos (9U) +#define GUSBCFG_HNPCAP_Msk (0x1UL << GUSBCFG_HNPCAP_Pos) // 0x00000200 */ +#define GUSBCFG_HNPCAP GUSBCFG_HNPCAP_Msk // HNP-capable */ +#define GUSBCFG_TRDT_Pos (10U) +#define GUSBCFG_TRDT_Msk (0xFUL << GUSBCFG_TRDT_Pos) // 0x00003C00 */ +#define GUSBCFG_TRDT GUSBCFG_TRDT_Msk // USB turnaround time */ +#define GUSBCFG_PHYLPCS_Pos (15U) +#define GUSBCFG_PHYLPCS_Msk (0x1UL << GUSBCFG_PHYLPCS_Pos) // 0x00008000 */ +#define GUSBCFG_PHYLPCS GUSBCFG_PHYLPCS_Msk // PHY Low-power clock select */ +#define GUSBCFG_ULPIFSLS_Pos (17U) +#define GUSBCFG_ULPIFSLS_Msk (0x1UL << GUSBCFG_ULPIFSLS_Pos) // 0x00020000 */ +#define GUSBCFG_ULPIFSLS GUSBCFG_ULPIFSLS_Msk // ULPI FS/LS select */ +#define GUSBCFG_ULPIAR_Pos (18U) +#define GUSBCFG_ULPIAR_Msk (0x1UL << GUSBCFG_ULPIAR_Pos) // 0x00040000 */ +#define GUSBCFG_ULPIAR GUSBCFG_ULPIAR_Msk // ULPI Auto-resume */ +#define GUSBCFG_ULPICSM_Pos (19U) +#define GUSBCFG_ULPICSM_Msk (0x1UL << GUSBCFG_ULPICSM_Pos) // 0x00080000 */ +#define GUSBCFG_ULPICSM GUSBCFG_ULPICSM_Msk // ULPI Clock SuspendM */ +#define GUSBCFG_ULPIEVBUSD_Pos (20U) +#define GUSBCFG_ULPIEVBUSD_Msk (0x1UL << GUSBCFG_ULPIEVBUSD_Pos) // 0x00100000 */ +#define GUSBCFG_ULPIEVBUSD GUSBCFG_ULPIEVBUSD_Msk // ULPI External VBUS Drive */ +#define GUSBCFG_ULPIEVBUSI_Pos (21U) +#define GUSBCFG_ULPIEVBUSI_Msk (0x1UL << GUSBCFG_ULPIEVBUSI_Pos) // 0x00200000 */ +#define GUSBCFG_ULPIEVBUSI GUSBCFG_ULPIEVBUSI_Msk // ULPI external VBUS indicator */ +#define GUSBCFG_TSDPS_Pos (22U) +#define GUSBCFG_TSDPS_Msk (0x1UL << GUSBCFG_TSDPS_Pos) // 0x00400000 */ +#define GUSBCFG_TSDPS GUSBCFG_TSDPS_Msk // TermSel DLine pulsing selection */ +#define GUSBCFG_PCCI_Pos (23U) +#define GUSBCFG_PCCI_Msk (0x1UL << GUSBCFG_PCCI_Pos) // 0x00800000 */ +#define GUSBCFG_PCCI GUSBCFG_PCCI_Msk // Indicator complement */ +#define GUSBCFG_PTCI_Pos (24U) +#define GUSBCFG_PTCI_Msk (0x1UL << GUSBCFG_PTCI_Pos) // 0x01000000 */ +#define GUSBCFG_PTCI GUSBCFG_PTCI_Msk // Indicator pass through */ +#define GUSBCFG_ULPIIPD_Pos (25U) +#define GUSBCFG_ULPIIPD_Msk (0x1UL << GUSBCFG_ULPIIPD_Pos) // 0x02000000 */ +#define GUSBCFG_ULPIIPD GUSBCFG_ULPIIPD_Msk // ULPI interface protect disable */ +#define GUSBCFG_FHMOD_Pos (29U) +#define GUSBCFG_FHMOD_Msk (0x1UL << GUSBCFG_FHMOD_Pos) // 0x20000000 */ +#define GUSBCFG_FHMOD GUSBCFG_FHMOD_Msk // Forced host mode */ +#define GUSBCFG_FDMOD_Pos (30U) +#define GUSBCFG_FDMOD_Msk (0x1UL << GUSBCFG_FDMOD_Pos) // 0x40000000 */ +#define GUSBCFG_FDMOD GUSBCFG_FDMOD_Msk // Forced peripheral mode */ +#define GUSBCFG_CTXPKT_Pos (31U) +#define GUSBCFG_CTXPKT_Msk (0x1UL << GUSBCFG_CTXPKT_Pos) // 0x80000000 */ +#define GUSBCFG_CTXPKT GUSBCFG_CTXPKT_Msk // Corrupt Tx packet */ + +/******************** Bit definition for GRSTCTL register ********************/ +#define GRSTCTL_CSRST_Pos (0U) +#define GRSTCTL_CSRST_Msk (0x1UL << GRSTCTL_CSRST_Pos) // 0x00000001 */ +#define GRSTCTL_CSRST GRSTCTL_CSRST_Msk // Core soft reset */ +#define GRSTCTL_HSRST_Pos (1U) +#define GRSTCTL_HSRST_Msk (0x1UL << GRSTCTL_HSRST_Pos) // 0x00000002 */ +#define GRSTCTL_HSRST GRSTCTL_HSRST_Msk // HCLK soft reset */ +#define GRSTCTL_FCRST_Pos (2U) +#define GRSTCTL_FCRST_Msk (0x1UL << GRSTCTL_FCRST_Pos) // 0x00000004 */ +#define GRSTCTL_FCRST GRSTCTL_FCRST_Msk // Host frame counter reset */ +#define GRSTCTL_RXFFLSH_Pos (4U) +#define GRSTCTL_RXFFLSH_Msk (0x1UL << GRSTCTL_RXFFLSH_Pos) // 0x00000010 */ +#define GRSTCTL_RXFFLSH GRSTCTL_RXFFLSH_Msk // RxFIFO flush */ +#define GRSTCTL_TXFFLSH_Pos (5U) +#define GRSTCTL_TXFFLSH_Msk (0x1UL << GRSTCTL_TXFFLSH_Pos) // 0x00000020 */ +#define GRSTCTL_TXFFLSH GRSTCTL_TXFFLSH_Msk // TxFIFO flush */ +#define GRSTCTL_TXFNUM_Pos (6U) +#define GRSTCTL_TXFNUM_Msk (0x1FUL << GRSTCTL_TXFNUM_Pos) // 0x000007C0 */ +#define GRSTCTL_TXFNUM GRSTCTL_TXFNUM_Msk // TxFIFO number */ +#define GRSTCTL_TXFNUM_0 (0x01UL << GRSTCTL_TXFNUM_Pos) // 0x00000040 */ +#define GRSTCTL_TXFNUM_1 (0x02UL << GRSTCTL_TXFNUM_Pos) // 0x00000080 */ +#define GRSTCTL_TXFNUM_2 (0x04UL << GRSTCTL_TXFNUM_Pos) // 0x00000100 */ +#define GRSTCTL_TXFNUM_3 (0x08UL << GRSTCTL_TXFNUM_Pos) // 0x00000200 */ +#define GRSTCTL_TXFNUM_4 (0x10UL << GRSTCTL_TXFNUM_Pos) // 0x00000400 */ +#define GRSTCTL_CSFTRST_DONE_Pos (29) +#define GRSTCTL_CSFTRST_DONE (1u << GRSTCTL_CSFTRST_DONE_Pos) // Reset Done, only available from v4.20a +#define GRSTCTL_DMAREQ_Pos (30U) +#define GRSTCTL_DMAREQ_Msk (0x1UL << GRSTCTL_DMAREQ_Pos) // 0x40000000 */ +#define GRSTCTL_DMAREQ GRSTCTL_DMAREQ_Msk // DMA request signal */ +#define GRSTCTL_AHBIDL_Pos (31U) +#define GRSTCTL_AHBIDL_Msk (0x1UL << GRSTCTL_AHBIDL_Pos) // 0x80000000 */ +#define GRSTCTL_AHBIDL GRSTCTL_AHBIDL_Msk // AHB master idle */ + +/******************** Bit definition for DIEPMSK register ********************/ +#define DIEPMSK_XFRCM_Pos (0U) +#define DIEPMSK_XFRCM_Msk (0x1UL << DIEPMSK_XFRCM_Pos) // 0x00000001 */ +#define DIEPMSK_XFRCM DIEPMSK_XFRCM_Msk // Transfer completed interrupt mask */ +#define DIEPMSK_EPDM_Pos (1U) +#define DIEPMSK_EPDM_Msk (0x1UL << DIEPMSK_EPDM_Pos) // 0x00000002 */ +#define DIEPMSK_EPDM DIEPMSK_EPDM_Msk // Endpoint disabled interrupt mask */ +#define DIEPMSK_TOM_Pos (3U) +#define DIEPMSK_TOM_Msk (0x1UL << DIEPMSK_TOM_Pos) // 0x00000008 */ +#define DIEPMSK_TOM DIEPMSK_TOM_Msk // Timeout condition mask (nonisochronous endpoints) */ +#define DIEPMSK_ITTXFEMSK_Pos (4U) +#define DIEPMSK_ITTXFEMSK_Msk (0x1UL << DIEPMSK_ITTXFEMSK_Pos) // 0x00000010 */ +#define DIEPMSK_ITTXFEMSK DIEPMSK_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask */ +#define DIEPMSK_INEPNMM_Pos (5U) +#define DIEPMSK_INEPNMM_Msk (0x1UL << DIEPMSK_INEPNMM_Pos) // 0x00000020 */ +#define DIEPMSK_INEPNMM DIEPMSK_INEPNMM_Msk // IN token received with EP mismatch mask */ +#define DIEPMSK_INEPNEM_Pos (6U) +#define DIEPMSK_INEPNEM_Msk (0x1UL << DIEPMSK_INEPNEM_Pos) // 0x00000040 */ +#define DIEPMSK_INEPNEM DIEPMSK_INEPNEM_Msk // IN endpoint NAK effective mask */ +#define DIEPMSK_TXFURM_Pos (8U) +#define DIEPMSK_TXFURM_Msk (0x1UL << DIEPMSK_TXFURM_Pos) // 0x00000100 */ +#define DIEPMSK_TXFURM DIEPMSK_TXFURM_Msk // FIFO underrun mask */ +#define DIEPMSK_BIM_Pos (9U) +#define DIEPMSK_BIM_Msk (0x1UL << DIEPMSK_BIM_Pos) // 0x00000200 */ +#define DIEPMSK_BIM DIEPMSK_BIM_Msk // BNA interrupt mask */ + +/******************** Bit definition for HPTXSTS register ********************/ +#define HPTXSTS_PTXFSAVL_Pos (0U) +#define HPTXSTS_PTXFSAVL_Msk (0xFFFFUL << HPTXSTS_PTXFSAVL_Pos) // 0x0000FFFF */ +#define HPTXSTS_PTXFSAVL HPTXSTS_PTXFSAVL_Msk // Periodic transmit data FIFO space available */ +#define HPTXSTS_PTXQSAV_Pos (16U) +#define HPTXSTS_PTXQSAV_Msk (0xFFUL << HPTXSTS_PTXQSAV_Pos) // 0x00FF0000 */ +#define HPTXSTS_PTXQSAV HPTXSTS_PTXQSAV_Msk // Periodic transmit request queue space available */ +#define HPTXSTS_PTXQSAV_0 (0x01UL << HPTXSTS_PTXQSAV_Pos) // 0x00010000 */ +#define HPTXSTS_PTXQSAV_1 (0x02UL << HPTXSTS_PTXQSAV_Pos) // 0x00020000 */ +#define HPTXSTS_PTXQSAV_2 (0x04UL << HPTXSTS_PTXQSAV_Pos) // 0x00040000 */ +#define HPTXSTS_PTXQSAV_3 (0x08UL << HPTXSTS_PTXQSAV_Pos) // 0x00080000 */ +#define HPTXSTS_PTXQSAV_4 (0x10UL << HPTXSTS_PTXQSAV_Pos) // 0x00100000 */ +#define HPTXSTS_PTXQSAV_5 (0x20UL << HPTXSTS_PTXQSAV_Pos) // 0x00200000 */ +#define HPTXSTS_PTXQSAV_6 (0x40UL << HPTXSTS_PTXQSAV_Pos) // 0x00400000 */ +#define HPTXSTS_PTXQSAV_7 (0x80UL << HPTXSTS_PTXQSAV_Pos) // 0x00800000 */ + +#define HPTXSTS_PTXQTOP_Pos (24U) +#define HPTXSTS_PTXQTOP_Msk (0xFFUL << HPTXSTS_PTXQTOP_Pos) // 0xFF000000 */ +#define HPTXSTS_PTXQTOP HPTXSTS_PTXQTOP_Msk // Top of the periodic transmit request queue */ +#define HPTXSTS_PTXQTOP_0 (0x01UL << HPTXSTS_PTXQTOP_Pos) // 0x01000000 */ +#define HPTXSTS_PTXQTOP_1 (0x02UL << HPTXSTS_PTXQTOP_Pos) // 0x02000000 */ +#define HPTXSTS_PTXQTOP_2 (0x04UL << HPTXSTS_PTXQTOP_Pos) // 0x04000000 */ +#define HPTXSTS_PTXQTOP_3 (0x08UL << HPTXSTS_PTXQTOP_Pos) // 0x08000000 */ +#define HPTXSTS_PTXQTOP_4 (0x10UL << HPTXSTS_PTXQTOP_Pos) // 0x10000000 */ +#define HPTXSTS_PTXQTOP_5 (0x20UL << HPTXSTS_PTXQTOP_Pos) // 0x20000000 */ +#define HPTXSTS_PTXQTOP_6 (0x40UL << HPTXSTS_PTXQTOP_Pos) // 0x40000000 */ +#define HPTXSTS_PTXQTOP_7 (0x80UL << HPTXSTS_PTXQTOP_Pos) // 0x80000000 */ + +/******************** Bit definition for HAINT register ********************/ +#define HAINT_HAINT_Pos (0U) +#define HAINT_HAINT_Msk (0xFFFFUL << HAINT_HAINT_Pos) // 0x0000FFFF */ +#define HAINT_HAINT HAINT_HAINT_Msk // Channel interrupts */ + +/******************** Bit definition for DOEPMSK register ********************/ +#define DOEPMSK_XFRCM_Pos (0U) +#define DOEPMSK_XFRCM_Msk (0x1UL << DOEPMSK_XFRCM_Pos) // 0x00000001 */ +#define DOEPMSK_XFRCM DOEPMSK_XFRCM_Msk // Transfer completed interrupt mask */ +#define DOEPMSK_EPDM_Pos (1U) +#define DOEPMSK_EPDM_Msk (0x1UL << DOEPMSK_EPDM_Pos) // 0x00000002 */ +#define DOEPMSK_EPDM DOEPMSK_EPDM_Msk // Endpoint disabled interrupt mask */ +#define DOEPMSK_AHBERRM_Pos (2U) +#define DOEPMSK_AHBERRM_Msk (0x1UL << DOEPMSK_AHBERRM_Pos) // 0x00000004 */ +#define DOEPMSK_AHBERRM DOEPMSK_AHBERRM_Msk // OUT transaction AHB Error interrupt mask */ +#define DOEPMSK_STUPM_Pos (3U) +#define DOEPMSK_STUPM_Msk (0x1UL << DOEPMSK_STUPM_Pos) // 0x00000008 */ +#define DOEPMSK_STUPM DOEPMSK_STUPM_Msk // SETUP phase done mask */ +#define DOEPMSK_OTEPDM_Pos (4U) +#define DOEPMSK_OTEPDM_Msk (0x1UL << DOEPMSK_OTEPDM_Pos) // 0x00000010 */ +#define DOEPMSK_OTEPDM DOEPMSK_OTEPDM_Msk // OUT token received when endpoint disabled mask */ +#define DOEPMSK_OTEPSPRM_Pos (5U) +#define DOEPMSK_OTEPSPRM_Msk (0x1UL << DOEPMSK_OTEPSPRM_Pos) // 0x00000020 */ +#define DOEPMSK_OTEPSPRM DOEPMSK_OTEPSPRM_Msk // Status Phase Received mask */ +#define DOEPMSK_B2BSTUP_Pos (6U) +#define DOEPMSK_B2BSTUP_Msk (0x1UL << DOEPMSK_B2BSTUP_Pos) // 0x00000040 */ +#define DOEPMSK_B2BSTUP DOEPMSK_B2BSTUP_Msk // Back-to-back SETUP packets received mask */ +#define DOEPMSK_OPEM_Pos (8U) +#define DOEPMSK_OPEM_Msk (0x1UL << DOEPMSK_OPEM_Pos) // 0x00000100 */ +#define DOEPMSK_OPEM DOEPMSK_OPEM_Msk // OUT packet error mask */ +#define DOEPMSK_BOIM_Pos (9U) +#define DOEPMSK_BOIM_Msk (0x1UL << DOEPMSK_BOIM_Pos) // 0x00000200 */ +#define DOEPMSK_BOIM DOEPMSK_BOIM_Msk // BNA interrupt mask */ +#define DOEPMSK_BERRM_Pos (12U) +#define DOEPMSK_BERRM_Msk (0x1UL << DOEPMSK_BERRM_Pos) // 0x00001000 */ +#define DOEPMSK_BERRM DOEPMSK_BERRM_Msk // Babble error interrupt mask */ +#define DOEPMSK_NAKM_Pos (13U) +#define DOEPMSK_NAKM_Msk (0x1UL << DOEPMSK_NAKM_Pos) // 0x00002000 */ +#define DOEPMSK_NAKM DOEPMSK_NAKM_Msk // OUT Packet NAK interrupt mask */ +#define DOEPMSK_NYETM_Pos (14U) +#define DOEPMSK_NYETM_Msk (0x1UL << DOEPMSK_NYETM_Pos) // 0x00004000 */ +#define DOEPMSK_NYETM DOEPMSK_NYETM_Msk // NYET interrupt mask */ + +/******************** Bit definition for GINTSTS register ********************/ +#define GINTSTS_CMOD_Pos (0U) +#define GINTSTS_CMOD_Msk (0x1UL << GINTSTS_CMOD_Pos) // 0x00000001 */ +#define GINTSTS_CMOD GINTSTS_CMOD_Msk // Current mode of operation */ +#define GINTSTS_MMIS_Pos (1U) +#define GINTSTS_MMIS_Msk (0x1UL << GINTSTS_MMIS_Pos) // 0x00000002 */ +#define GINTSTS_MMIS GINTSTS_MMIS_Msk // Mode mismatch interrupt */ +#define GINTSTS_OTGINT_Pos (2U) +#define GINTSTS_OTGINT_Msk (0x1UL << GINTSTS_OTGINT_Pos) // 0x00000004 */ +#define GINTSTS_OTGINT GINTSTS_OTGINT_Msk // OTG interrupt */ +#define GINTSTS_SOF_Pos (3U) +#define GINTSTS_SOF_Msk (0x1UL << GINTSTS_SOF_Pos) // 0x00000008 */ +#define GINTSTS_SOF GINTSTS_SOF_Msk // Start of frame */ +#define GINTSTS_RXFLVL_Pos (4U) +#define GINTSTS_RXFLVL_Msk (0x1UL << GINTSTS_RXFLVL_Pos) // 0x00000010 */ +#define GINTSTS_RXFLVL GINTSTS_RXFLVL_Msk // RxFIFO nonempty */ +#define GINTSTS_NPTXFE_Pos (5U) +#define GINTSTS_NPTXFE_Msk (0x1UL << GINTSTS_NPTXFE_Pos) // 0x00000020 */ +#define GINTSTS_NPTXFE GINTSTS_NPTXFE_Msk // Nonperiodic TxFIFO empty */ +#define GINTSTS_GINAKEFF_Pos (6U) +#define GINTSTS_GINAKEFF_Msk (0x1UL << GINTSTS_GINAKEFF_Pos) // 0x00000040 */ +#define GINTSTS_GINAKEFF GINTSTS_GINAKEFF_Msk // Global IN nonperiodic NAK effective */ +#define GINTSTS_BOUTNAKEFF_Pos (7U) +#define GINTSTS_BOUTNAKEFF_Msk (0x1UL << GINTSTS_BOUTNAKEFF_Pos) // 0x00000080 */ +#define GINTSTS_BOUTNAKEFF GINTSTS_BOUTNAKEFF_Msk // Global OUT NAK effective */ +#define GINTSTS_ESUSP_Pos (10U) +#define GINTSTS_ESUSP_Msk (0x1UL << GINTSTS_ESUSP_Pos) // 0x00000400 */ +#define GINTSTS_ESUSP GINTSTS_ESUSP_Msk // Early suspend */ +#define GINTSTS_USBSUSP_Pos (11U) +#define GINTSTS_USBSUSP_Msk (0x1UL << GINTSTS_USBSUSP_Pos) // 0x00000800 */ +#define GINTSTS_USBSUSP GINTSTS_USBSUSP_Msk // USB suspend */ +#define GINTSTS_USBRST_Pos (12U) +#define GINTSTS_USBRST_Msk (0x1UL << GINTSTS_USBRST_Pos) // 0x00001000 */ +#define GINTSTS_USBRST GINTSTS_USBRST_Msk // USB reset */ +#define GINTSTS_ENUMDNE_Pos (13U) +#define GINTSTS_ENUMDNE_Msk (0x1UL << GINTSTS_ENUMDNE_Pos) // 0x00002000 */ +#define GINTSTS_ENUMDNE GINTSTS_ENUMDNE_Msk // Enumeration done */ +#define GINTSTS_ISOODRP_Pos (14U) +#define GINTSTS_ISOODRP_Msk (0x1UL << GINTSTS_ISOODRP_Pos) // 0x00004000 */ +#define GINTSTS_ISOODRP GINTSTS_ISOODRP_Msk // Isochronous OUT packet dropped interrupt */ +#define GINTSTS_EOPF_Pos (15U) +#define GINTSTS_EOPF_Msk (0x1UL << GINTSTS_EOPF_Pos) // 0x00008000 */ +#define GINTSTS_EOPF GINTSTS_EOPF_Msk // End of periodic frame interrupt */ +#define GINTSTS_IEPINT_Pos (18U) +#define GINTSTS_IEPINT_Msk (0x1UL << GINTSTS_IEPINT_Pos) // 0x00040000 */ +#define GINTSTS_IEPINT GINTSTS_IEPINT_Msk // IN endpoint interrupt */ +#define GINTSTS_OEPINT_Pos (19U) +#define GINTSTS_OEPINT_Msk (0x1UL << GINTSTS_OEPINT_Pos) // 0x00080000 */ +#define GINTSTS_OEPINT GINTSTS_OEPINT_Msk // OUT endpoint interrupt */ +#define GINTSTS_IISOIXFR_Pos (20U) +#define GINTSTS_IISOIXFR_Msk (0x1UL << GINTSTS_IISOIXFR_Pos) // 0x00100000 */ +#define GINTSTS_IISOIXFR GINTSTS_IISOIXFR_Msk // Incomplete isochronous IN transfer */ +#define GINTSTS_PXFR_INCOMPISOOUT_Pos (21U) +#define GINTSTS_PXFR_INCOMPISOOUT_Msk (0x1UL << GINTSTS_PXFR_INCOMPISOOUT_Pos) // 0x00200000 */ +#define GINTSTS_PXFR_INCOMPISOOUT GINTSTS_PXFR_INCOMPISOOUT_Msk // Incomplete periodic transfer */ +#define GINTSTS_DATAFSUSP_Pos (22U) +#define GINTSTS_DATAFSUSP_Msk (0x1UL << GINTSTS_DATAFSUSP_Pos) // 0x00400000 */ +#define GINTSTS_DATAFSUSP GINTSTS_DATAFSUSP_Msk // Data fetch suspended */ +#define GINTSTS_RSTDET_Pos (23U) +#define GINTSTS_RSTDET_Msk (0x1UL << GINTSTS_RSTDET_Pos) // 0x00800000 */ +#define GINTSTS_RSTDET GINTSTS_RSTDET_Msk // Reset detected interrupt */ +#define GINTSTS_HPRTINT_Pos (24U) +#define GINTSTS_HPRTINT_Msk (0x1UL << GINTSTS_HPRTINT_Pos) // 0x01000000 */ +#define GINTSTS_HPRTINT GINTSTS_HPRTINT_Msk // Host port interrupt */ +#define GINTSTS_HCINT_Pos (25U) +#define GINTSTS_HCINT_Msk (0x1UL << GINTSTS_HCINT_Pos) // 0x02000000 */ +#define GINTSTS_HCINT GINTSTS_HCINT_Msk // Host channels interrupt */ +#define GINTSTS_PTXFE_Pos (26U) +#define GINTSTS_PTXFE_Msk (0x1UL << GINTSTS_PTXFE_Pos) // 0x04000000 */ +#define GINTSTS_PTXFE GINTSTS_PTXFE_Msk // Periodic TxFIFO empty */ +#define GINTSTS_LPMINT_Pos (27U) +#define GINTSTS_LPMINT_Msk (0x1UL << GINTSTS_LPMINT_Pos) // 0x08000000 */ +#define GINTSTS_LPMINT GINTSTS_LPMINT_Msk // LPM interrupt */ +#define GINTSTS_CIDSCHG_Pos (28U) +#define GINTSTS_CIDSCHG_Msk (0x1UL << GINTSTS_CIDSCHG_Pos) // 0x10000000 */ +#define GINTSTS_CIDSCHG GINTSTS_CIDSCHG_Msk // Connector ID status change */ +#define GINTSTS_DISCINT_Pos (29U) +#define GINTSTS_DISCINT_Msk (0x1UL << GINTSTS_DISCINT_Pos) // 0x20000000 */ +#define GINTSTS_DISCINT GINTSTS_DISCINT_Msk // Disconnect detected interrupt */ +#define GINTSTS_SRQINT_Pos (30U) +#define GINTSTS_SRQINT_Msk (0x1UL << GINTSTS_SRQINT_Pos) // 0x40000000 */ +#define GINTSTS_SRQINT GINTSTS_SRQINT_Msk // Session request/new session detected interrupt */ +#define GINTSTS_WKUINT_Pos (31U) +#define GINTSTS_WKUINT_Msk (0x1UL << GINTSTS_WKUINT_Pos) // 0x80000000 */ +#define GINTSTS_WKUINT GINTSTS_WKUINT_Msk // Resume/remote wakeup detected interrupt */ + +/******************** Bit definition for GINTMSK register ********************/ +#define GINTMSK_MMISM_Pos (1U) +#define GINTMSK_MMISM_Msk (0x1UL << GINTMSK_MMISM_Pos) // 0x00000002 */ +#define GINTMSK_MMISM GINTMSK_MMISM_Msk // Mode mismatch interrupt mask */ +#define GINTMSK_OTGINT_Pos (2U) +#define GINTMSK_OTGINT_Msk (0x1UL << GINTMSK_OTGINT_Pos) // 0x00000004 */ +#define GINTMSK_OTGINT GINTMSK_OTGINT_Msk // OTG interrupt mask */ +#define GINTMSK_SOFM_Pos (3U) +#define GINTMSK_SOFM_Msk (0x1UL << GINTMSK_SOFM_Pos) // 0x00000008 */ +#define GINTMSK_SOFM GINTMSK_SOFM_Msk // Start of frame mask */ +#define GINTMSK_RXFLVLM_Pos (4U) +#define GINTMSK_RXFLVLM_Msk (0x1UL << GINTMSK_RXFLVLM_Pos) // 0x00000010 */ +#define GINTMSK_RXFLVLM GINTMSK_RXFLVLM_Msk // Receive FIFO nonempty mask */ +#define GINTMSK_NPTXFEM_Pos (5U) +#define GINTMSK_NPTXFEM_Msk (0x1UL << GINTMSK_NPTXFEM_Pos) // 0x00000020 */ +#define GINTMSK_NPTXFEM GINTMSK_NPTXFEM_Msk // Nonperiodic TxFIFO empty mask */ +#define GINTMSK_GINAKEFFM_Pos (6U) +#define GINTMSK_GINAKEFFM_Msk (0x1UL << GINTMSK_GINAKEFFM_Pos) // 0x00000040 */ +#define GINTMSK_GINAKEFFM GINTMSK_GINAKEFFM_Msk // Global nonperiodic IN NAK effective mask */ +#define GINTMSK_GONAKEFFM_Pos (7U) +#define GINTMSK_GONAKEFFM_Msk (0x1UL << GINTMSK_GONAKEFFM_Pos) // 0x00000080 */ +#define GINTMSK_GONAKEFFM GINTMSK_GONAKEFFM_Msk // Global OUT NAK effective mask */ +#define GINTMSK_ESUSPM_Pos (10U) +#define GINTMSK_ESUSPM_Msk (0x1UL << GINTMSK_ESUSPM_Pos) // 0x00000400 */ +#define GINTMSK_ESUSPM GINTMSK_ESUSPM_Msk // Early suspend mask */ +#define GINTMSK_USBSUSPM_Pos (11U) +#define GINTMSK_USBSUSPM_Msk (0x1UL << GINTMSK_USBSUSPM_Pos) // 0x00000800 */ +#define GINTMSK_USBSUSPM GINTMSK_USBSUSPM_Msk // USB suspend mask */ +#define GINTMSK_USBRST_Pos (12U) +#define GINTMSK_USBRST_Msk (0x1UL << GINTMSK_USBRST_Pos) // 0x00001000 */ +#define GINTMSK_USBRST GINTMSK_USBRST_Msk // USB reset mask */ +#define GINTMSK_ENUMDNEM_Pos (13U) +#define GINTMSK_ENUMDNEM_Msk (0x1UL << GINTMSK_ENUMDNEM_Pos) // 0x00002000 */ +#define GINTMSK_ENUMDNEM GINTMSK_ENUMDNEM_Msk // Enumeration done mask */ +#define GINTMSK_ISOODRPM_Pos (14U) +#define GINTMSK_ISOODRPM_Msk (0x1UL << GINTMSK_ISOODRPM_Pos) // 0x00004000 */ +#define GINTMSK_ISOODRPM GINTMSK_ISOODRPM_Msk // Isochronous OUT packet dropped interrupt mask */ +#define GINTMSK_EOPFM_Pos (15U) +#define GINTMSK_EOPFM_Msk (0x1UL << GINTMSK_EOPFM_Pos) // 0x00008000 */ +#define GINTMSK_EOPFM GINTMSK_EOPFM_Msk // End of periodic frame interrupt mask */ +#define GINTMSK_EPMISM_Pos (17U) +#define GINTMSK_EPMISM_Msk (0x1UL << GINTMSK_EPMISM_Pos) // 0x00020000 */ +#define GINTMSK_EPMISM GINTMSK_EPMISM_Msk // Endpoint mismatch interrupt mask */ +#define GINTMSK_IEPINT_Pos (18U) +#define GINTMSK_IEPINT_Msk (0x1UL << GINTMSK_IEPINT_Pos) // 0x00040000 */ +#define GINTMSK_IEPINT GINTMSK_IEPINT_Msk // IN endpoints interrupt mask */ +#define GINTMSK_OEPINT_Pos (19U) +#define GINTMSK_OEPINT_Msk (0x1UL << GINTMSK_OEPINT_Pos) // 0x00080000 */ +#define GINTMSK_OEPINT GINTMSK_OEPINT_Msk // OUT endpoints interrupt mask */ +#define GINTMSK_IISOIXFRM_Pos (20U) +#define GINTMSK_IISOIXFRM_Msk (0x1UL << GINTMSK_IISOIXFRM_Pos) // 0x00100000 */ +#define GINTMSK_IISOIXFRM GINTMSK_IISOIXFRM_Msk // Incomplete isochronous IN transfer mask */ +#define GINTMSK_PXFRM_IISOOXFRM_Pos (21U) +#define GINTMSK_PXFRM_IISOOXFRM_Msk (0x1UL << GINTMSK_PXFRM_IISOOXFRM_Pos) // 0x00200000 */ +#define GINTMSK_PXFRM_IISOOXFRM GINTMSK_PXFRM_IISOOXFRM_Msk // Incomplete periodic transfer mask */ +#define GINTMSK_FSUSPM_Pos (22U) +#define GINTMSK_FSUSPM_Msk (0x1UL << GINTMSK_FSUSPM_Pos) // 0x00400000 */ +#define GINTMSK_FSUSPM GINTMSK_FSUSPM_Msk // Data fetch suspended mask */ +#define GINTMSK_RSTDEM_Pos (23U) +#define GINTMSK_RSTDEM_Msk (0x1UL << GINTMSK_RSTDEM_Pos) // 0x00800000 */ +#define GINTMSK_RSTDEM GINTMSK_RSTDEM_Msk // Reset detected interrupt mask */ +#define GINTMSK_PRTIM_Pos (24U) +#define GINTMSK_PRTIM_Msk (0x1UL << GINTMSK_PRTIM_Pos) // 0x01000000 */ +#define GINTMSK_PRTIM GINTMSK_PRTIM_Msk // Host port interrupt mask */ +#define GINTMSK_HCIM_Pos (25U) +#define GINTMSK_HCIM_Msk (0x1UL << GINTMSK_HCIM_Pos) // 0x02000000 */ +#define GINTMSK_HCIM GINTMSK_HCIM_Msk // Host channels interrupt mask */ +#define GINTMSK_PTXFEM_Pos (26U) +#define GINTMSK_PTXFEM_Msk (0x1UL << GINTMSK_PTXFEM_Pos) // 0x04000000 */ +#define GINTMSK_PTXFEM GINTMSK_PTXFEM_Msk // Periodic TxFIFO empty mask */ +#define GINTMSK_LPMINTM_Pos (27U) +#define GINTMSK_LPMINTM_Msk (0x1UL << GINTMSK_LPMINTM_Pos) // 0x08000000 */ +#define GINTMSK_LPMINTM GINTMSK_LPMINTM_Msk // LPM interrupt Mask */ +#define GINTMSK_CIDSCHGM_Pos (28U) +#define GINTMSK_CIDSCHGM_Msk (0x1UL << GINTMSK_CIDSCHGM_Pos) // 0x10000000 */ +#define GINTMSK_CIDSCHGM GINTMSK_CIDSCHGM_Msk // Connector ID status change mask */ +#define GINTMSK_DISCINT_Pos (29U) +#define GINTMSK_DISCINT_Msk (0x1UL << GINTMSK_DISCINT_Pos) // 0x20000000 */ +#define GINTMSK_DISCINT GINTMSK_DISCINT_Msk // Disconnect detected interrupt mask */ +#define GINTMSK_SRQIM_Pos (30U) +#define GINTMSK_SRQIM_Msk (0x1UL << GINTMSK_SRQIM_Pos) // 0x40000000 */ +#define GINTMSK_SRQIM GINTMSK_SRQIM_Msk // Session request/new session detected interrupt mask */ +#define GINTMSK_WUIM_Pos (31U) +#define GINTMSK_WUIM_Msk (0x1UL << GINTMSK_WUIM_Pos) // 0x80000000 */ +#define GINTMSK_WUIM GINTMSK_WUIM_Msk // Resume/remote wakeup detected interrupt mask */ + +/******************** Bit definition for DAINT register ********************/ +#define DAINT_IEPINT_Pos (0U) +#define DAINT_IEPINT_Msk (0xFFFFUL << DAINT_IEPINT_Pos) // 0x0000FFFF */ +#define DAINT_IEPINT DAINT_IEPINT_Msk // IN endpoint interrupt bits */ +#define DAINT_OEPINT_Pos (16U) +#define DAINT_OEPINT_Msk (0xFFFFUL << DAINT_OEPINT_Pos) // 0xFFFF0000 */ +#define DAINT_OEPINT DAINT_OEPINT_Msk // OUT endpoint interrupt bits */ + +/******************** Bit definition for HAINTMSK register ********************/ +#define HAINTMSK_HAINTM_Pos (0U) +#define HAINTMSK_HAINTM_Msk (0xFFFFUL << HAINTMSK_HAINTM_Pos) // 0x0000FFFF */ +#define HAINTMSK_HAINTM HAINTMSK_HAINTM_Msk // Channel interrupt mask */ + +/******************** Bit definition for GRXSTSP register ********************/ +#define GRXSTSP_EPNUM_Pos (0U) +#define GRXSTSP_EPNUM_Msk (0xFUL << GRXSTSP_EPNUM_Pos) // 0x0000000F */ +#define GRXSTSP_EPNUM GRXSTSP_EPNUM_Msk // IN EP interrupt mask bits */ +#define GRXSTSP_BCNT_Pos (4U) +#define GRXSTSP_BCNT_Msk (0x7FFUL << GRXSTSP_BCNT_Pos) // 0x00007FF0 */ +#define GRXSTSP_BCNT GRXSTSP_BCNT_Msk // OUT EP interrupt mask bits */ +#define GRXSTSP_DPID_Pos (15U) +#define GRXSTSP_DPID_Msk (0x3UL << GRXSTSP_DPID_Pos) // 0x00018000 */ +#define GRXSTSP_DPID GRXSTSP_DPID_Msk // OUT EP interrupt mask bits */ +#define GRXSTSP_PKTSTS_Pos (17U) +#define GRXSTSP_PKTSTS_Msk (0xFUL << GRXSTSP_PKTSTS_Pos) // 0x001E0000 */ +#define GRXSTSP_PKTSTS GRXSTSP_PKTSTS_Msk // OUT EP interrupt mask bits */ + +#define GRXSTS_PKTSTS_GLOBALOUTNAK 1 +#define GRXSTS_PKTSTS_OUTRX 2 +#define GRXSTS_PKTSTS_HCHIN 2 +#define GRXSTS_PKTSTS_OUTDONE 3 +#define GRXSTS_PKTSTS_HCHIN_XFER_COMP 3 +#define GRXSTS_PKTSTS_SETUPDONE 4 +#define GRXSTS_PKTSTS_DATATOGGLEERR 5 +#define GRXSTS_PKTSTS_SETUPRX 6 +#define GRXSTS_PKTSTS_HCHHALTED 7 + + +/******************** Bit definition for DAINTMSK register ********************/ +#define DAINTMSK_IEPM_Pos (0U) +#define DAINTMSK_IEPM_Msk (0xFFFFUL << DAINTMSK_IEPM_Pos) // 0x0000FFFF */ +#define DAINTMSK_IEPM DAINTMSK_IEPM_Msk // IN EP interrupt mask bits */ +#define DAINTMSK_OEPM_Pos (16U) +#define DAINTMSK_OEPM_Msk (0xFFFFUL << DAINTMSK_OEPM_Pos) // 0xFFFF0000 */ +#define DAINTMSK_OEPM DAINTMSK_OEPM_Msk // OUT EP interrupt mask bits */ + +#if 0 +/******************** Bit definition for OTG register ********************/ +#define CHNUM_Pos (0U) +#define CHNUM_Msk (0xFUL << CHNUM_Pos) // 0x0000000F */ +#define CHNUM CHNUM_Msk // Channel number */ +#define CHNUM_0 (0x1UL << CHNUM_Pos) // 0x00000001 */ +#define CHNUM_1 (0x2UL << CHNUM_Pos) // 0x00000002 */ +#define CHNUM_2 (0x4UL << CHNUM_Pos) // 0x00000004 */ +#define CHNUM_3 (0x8UL << CHNUM_Pos) // 0x00000008 */ +#define BCNT_Pos (4U) +#define BCNT_Msk (0x7FFUL << BCNT_Pos) // 0x00007FF0 */ +#define BCNT BCNT_Msk // Byte count */ + +#define DPID_Pos (15U) +#define DPID_Msk (0x3UL << DPID_Pos) // 0x00018000 */ +#define DPID DPID_Msk // Data PID */ +#define DPID_0 (0x1UL << DPID_Pos) // 0x00008000 */ +#define DPID_1 (0x2UL << DPID_Pos) // 0x00010000 */ + +#define PKTSTS_Pos (17U) +#define PKTSTS_Msk (0xFUL << PKTSTS_Pos) // 0x001E0000 */ +#define PKTSTS PKTSTS_Msk // Packet status */ +#define PKTSTS_0 (0x1UL << PKTSTS_Pos) // 0x00020000 */ +#define PKTSTS_1 (0x2UL << PKTSTS_Pos) // 0x00040000 */ +#define PKTSTS_2 (0x4UL << PKTSTS_Pos) // 0x00080000 */ +#define PKTSTS_3 (0x8UL << PKTSTS_Pos) // 0x00100000 */ + +#define EPNUM_Pos (0U) +#define EPNUM_Msk (0xFUL << EPNUM_Pos) // 0x0000000F */ +#define EPNUM EPNUM_Msk // Endpoint number */ +#define EPNUM_0 (0x1UL << EPNUM_Pos) // 0x00000001 */ +#define EPNUM_1 (0x2UL << EPNUM_Pos) // 0x00000002 */ +#define EPNUM_2 (0x4UL << EPNUM_Pos) // 0x00000004 */ +#define EPNUM_3 (0x8UL << EPNUM_Pos) // 0x00000008 */ + +#define FRMNUM_Pos (21U) +#define FRMNUM_Msk (0xFUL << FRMNUM_Pos) // 0x01E00000 */ +#define FRMNUM FRMNUM_Msk // Frame number */ +#define FRMNUM_0 (0x1UL << FRMNUM_Pos) // 0x00200000 */ +#define FRMNUM_1 (0x2UL << FRMNUM_Pos) // 0x00400000 */ +#define FRMNUM_2 (0x4UL << FRMNUM_Pos) // 0x00800000 */ +#define FRMNUM_3 (0x8UL << FRMNUM_Pos) // 0x01000000 */ +#endif + +/******************** Bit definition for GRXFSIZ register ********************/ +#define GRXFSIZ_RXFD_Pos (0U) +#define GRXFSIZ_RXFD_Msk (0xFFFFUL << GRXFSIZ_RXFD_Pos) // 0x0000FFFF */ +#define GRXFSIZ_RXFD GRXFSIZ_RXFD_Msk // RxFIFO depth */ + +/******************** Bit definition for DVBUSDIS register ********************/ +#define DVBUSDIS_VBUSDT_Pos (0U) +#define DVBUSDIS_VBUSDT_Msk (0xFFFFUL << DVBUSDIS_VBUSDT_Pos) // 0x0000FFFF */ +#define DVBUSDIS_VBUSDT DVBUSDIS_VBUSDT_Msk // Device VBUS discharge time */ + +/******************** Bit definition for OTG register ********************/ +#define GNPTXFSIZ_NPTXFSA_Pos (0U) +#define GNPTXFSIZ_NPTXFSA_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFSA_Pos) // 0x0000FFFF */ +#define GNPTXFSIZ_NPTXFSA GNPTXFSIZ_NPTXFSA_Msk // Nonperiodic transmit RAM start address */ +#define GNPTXFSIZ_NPTXFD_Pos (16U) +#define GNPTXFSIZ_NPTXFD_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFD_Pos) // 0xFFFF0000 */ +#define GNPTXFSIZ_NPTXFD GNPTXFSIZ_NPTXFD_Msk // Nonperiodic TxFIFO depth */ +#define DIEPTXF0_TX0FSA_Pos (0U) +#define DIEPTXF0_TX0FSA_Msk (0xFFFFUL << DIEPTXF0_TX0FSA_Pos) // 0x0000FFFF */ +#define DIEPTXF0_TX0FSA DIEPTXF0_TX0FSA_Msk // Endpoint 0 transmit RAM start address */ +#define DIEPTXF0_TX0FD_Pos (16U) +#define DIEPTXF0_TX0FD_Msk (0xFFFFUL << DIEPTXF0_TX0FD_Pos) // 0xFFFF0000 */ +#define DIEPTXF0_TX0FD DIEPTXF0_TX0FD_Msk // Endpoint 0 TxFIFO depth */ + +/******************** Bit definition for DVBUSPULSE register ********************/ +#define DVBUSPULSE_DVBUSP_Pos (0U) +#define DVBUSPULSE_DVBUSP_Msk (0xFFFUL << DVBUSPULSE_DVBUSP_Pos) // 0x00000FFF */ +#define DVBUSPULSE_DVBUSP DVBUSPULSE_DVBUSP_Msk // Device VBUS pulsing time */ + +/******************** Bit definition for GNPTXSTS register ********************/ +#define GNPTXSTS_NPTXFSAV_Pos (0U) +#define GNPTXSTS_NPTXFSAV_Msk (0xFFFFUL << GNPTXSTS_NPTXFSAV_Pos) // 0x0000FFFF */ +#define GNPTXSTS_NPTXFSAV GNPTXSTS_NPTXFSAV_Msk // Nonperiodic TxFIFO space available */ + +#define GNPTXSTS_NPTQXSAV_Pos (16U) +#define GNPTXSTS_NPTQXSAV_Msk (0xFFUL << GNPTXSTS_NPTQXSAV_Pos) // 0x00FF0000 */ +#define GNPTXSTS_NPTQXSAV GNPTXSTS_NPTQXSAV_Msk // Nonperiodic transmit request queue space available */ +#define GNPTXSTS_NPTQXSAV_0 (0x01UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00010000 */ +#define GNPTXSTS_NPTQXSAV_1 (0x02UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00020000 */ +#define GNPTXSTS_NPTQXSAV_2 (0x04UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00040000 */ +#define GNPTXSTS_NPTQXSAV_3 (0x08UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00080000 */ +#define GNPTXSTS_NPTQXSAV_4 (0x10UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00100000 */ +#define GNPTXSTS_NPTQXSAV_5 (0x20UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00200000 */ +#define GNPTXSTS_NPTQXSAV_6 (0x40UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00400000 */ +#define GNPTXSTS_NPTQXSAV_7 (0x80UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00800000 */ + +#define GNPTXSTS_NPTXQTOP_Pos (24U) +#define GNPTXSTS_NPTXQTOP_Msk (0x7FUL << GNPTXSTS_NPTXQTOP_Pos) // 0x7F000000 */ +#define GNPTXSTS_NPTXQTOP GNPTXSTS_NPTXQTOP_Msk // Top of the nonperiodic transmit request queue */ +#define GNPTXSTS_NPTXQTOP_0 (0x01UL << GNPTXSTS_NPTXQTOP_Pos) // 0x01000000 */ +#define GNPTXSTS_NPTXQTOP_1 (0x02UL << GNPTXSTS_NPTXQTOP_Pos) // 0x02000000 */ +#define GNPTXSTS_NPTXQTOP_2 (0x04UL << GNPTXSTS_NPTXQTOP_Pos) // 0x04000000 */ +#define GNPTXSTS_NPTXQTOP_3 (0x08UL << GNPTXSTS_NPTXQTOP_Pos) // 0x08000000 */ +#define GNPTXSTS_NPTXQTOP_4 (0x10UL << GNPTXSTS_NPTXQTOP_Pos) // 0x10000000 */ +#define GNPTXSTS_NPTXQTOP_5 (0x20UL << GNPTXSTS_NPTXQTOP_Pos) // 0x20000000 */ +#define GNPTXSTS_NPTXQTOP_6 (0x40UL << GNPTXSTS_NPTXQTOP_Pos) // 0x40000000 */ + +/******************** Bit definition for DTHRCTL register ********************/ +#define DTHRCTL_NONISOTHREN_Pos (0U) +#define DTHRCTL_NONISOTHREN_Msk (0x1UL << DTHRCTL_NONISOTHREN_Pos) // 0x00000001 */ +#define DTHRCTL_NONISOTHREN DTHRCTL_NONISOTHREN_Msk // Nonisochronous IN endpoints threshold enable */ +#define DTHRCTL_ISOTHREN_Pos (1U) +#define DTHRCTL_ISOTHREN_Msk (0x1UL << DTHRCTL_ISOTHREN_Pos) // 0x00000002 */ +#define DTHRCTL_ISOTHREN DTHRCTL_ISOTHREN_Msk // ISO IN endpoint threshold enable */ + +#define DTHRCTL_TXTHRLEN_Pos (2U) +#define DTHRCTL_TXTHRLEN_Msk (0x1FFUL << DTHRCTL_TXTHRLEN_Pos) // 0x000007FC */ +#define DTHRCTL_TXTHRLEN DTHRCTL_TXTHRLEN_Msk // Transmit threshold length */ +#define DTHRCTL_TXTHRLEN_0 (0x001UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000004 */ +#define DTHRCTL_TXTHRLEN_1 (0x002UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000008 */ +#define DTHRCTL_TXTHRLEN_2 (0x004UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000010 */ +#define DTHRCTL_TXTHRLEN_3 (0x008UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000020 */ +#define DTHRCTL_TXTHRLEN_4 (0x010UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000040 */ +#define DTHRCTL_TXTHRLEN_5 (0x020UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000080 */ +#define DTHRCTL_TXTHRLEN_6 (0x040UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000100 */ +#define DTHRCTL_TXTHRLEN_7 (0x080UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000200 */ +#define DTHRCTL_TXTHRLEN_8 (0x100UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000400 */ +#define DTHRCTL_RXTHREN_Pos (16U) +#define DTHRCTL_RXTHREN_Msk (0x1UL << DTHRCTL_RXTHREN_Pos) // 0x00010000 */ +#define DTHRCTL_RXTHREN DTHRCTL_RXTHREN_Msk // Receive threshold enable */ + +#define DTHRCTL_RXTHRLEN_Pos (17U) +#define DTHRCTL_RXTHRLEN_Msk (0x1FFUL << DTHRCTL_RXTHRLEN_Pos) // 0x03FE0000 */ +#define DTHRCTL_RXTHRLEN DTHRCTL_RXTHRLEN_Msk // Receive threshold length */ +#define DTHRCTL_RXTHRLEN_0 (0x001UL << DTHRCTL_RXTHRLEN_Pos) // 0x00020000 */ +#define DTHRCTL_RXTHRLEN_1 (0x002UL << DTHRCTL_RXTHRLEN_Pos) // 0x00040000 */ +#define DTHRCTL_RXTHRLEN_2 (0x004UL << DTHRCTL_RXTHRLEN_Pos) // 0x00080000 */ +#define DTHRCTL_RXTHRLEN_3 (0x008UL << DTHRCTL_RXTHRLEN_Pos) // 0x00100000 */ +#define DTHRCTL_RXTHRLEN_4 (0x010UL << DTHRCTL_RXTHRLEN_Pos) // 0x00200000 */ +#define DTHRCTL_RXTHRLEN_5 (0x020UL << DTHRCTL_RXTHRLEN_Pos) // 0x00400000 */ +#define DTHRCTL_RXTHRLEN_6 (0x040UL << DTHRCTL_RXTHRLEN_Pos) // 0x00800000 */ +#define DTHRCTL_RXTHRLEN_7 (0x080UL << DTHRCTL_RXTHRLEN_Pos) // 0x01000000 */ +#define DTHRCTL_RXTHRLEN_8 (0x100UL << DTHRCTL_RXTHRLEN_Pos) // 0x02000000 */ +#define DTHRCTL_ARPEN_Pos (27U) +#define DTHRCTL_ARPEN_Msk (0x1UL << DTHRCTL_ARPEN_Pos) // 0x08000000 */ +#define DTHRCTL_ARPEN DTHRCTL_ARPEN_Msk // Arbiter parking enable */ + +/******************** Bit definition for DIEPEMPMSK register ********************/ +#define DIEPEMPMSK_INEPTXFEM_Pos (0U) +#define DIEPEMPMSK_INEPTXFEM_Msk (0xFFFFUL << DIEPEMPMSK_INEPTXFEM_Pos) // 0x0000FFFF */ +#define DIEPEMPMSK_INEPTXFEM DIEPEMPMSK_INEPTXFEM_Msk // IN EP Tx FIFO empty interrupt mask bits */ + +/******************** Bit definition for DEACHINT register ********************/ +#define DEACHINT_IEP1INT_Pos (1U) +#define DEACHINT_IEP1INT_Msk (0x1UL << DEACHINT_IEP1INT_Pos) // 0x00000002 */ +#define DEACHINT_IEP1INT DEACHINT_IEP1INT_Msk // IN endpoint 1interrupt bit */ +#define DEACHINT_OEP1INT_Pos (17U) +#define DEACHINT_OEP1INT_Msk (0x1UL << DEACHINT_OEP1INT_Pos) // 0x00020000 */ +#define DEACHINT_OEP1INT DEACHINT_OEP1INT_Msk // OUT endpoint 1 interrupt bit */ + +/******************** Bit definition for GCCFG register ********************/ +#define STM32_GCCFG_DCDET_Pos (0U) +#define STM32_GCCFG_DCDET_Msk (0x1UL << STM32_GCCFG_DCDET_Pos) // 0x00000001 */ +#define STM32_GCCFG_DCDET STM32_GCCFG_DCDET_Msk // Data contact detection (DCD) status */ +#define STM32_GCCFG_PDET_Pos (1U) +#define STM32_GCCFG_PDET_Msk (0x1UL << STM32_GCCFG_PDET_Pos) // 0x00000002 */ +#define STM32_GCCFG_PDET STM32_GCCFG_PDET_Msk // Primary detection (PD) status */ +#define STM32_GCCFG_SDET_Pos (2U) +#define STM32_GCCFG_SDET_Msk (0x1UL << STM32_GCCFG_SDET_Pos) // 0x00000004 */ +#define STM32_GCCFG_SDET STM32_GCCFG_SDET_Msk // Secondary detection (SD) status */ +#define STM32_GCCFG_PS2DET_Pos (3U) +#define STM32_GCCFG_PS2DET_Msk (0x1UL << STM32_GCCFG_PS2DET_Pos) // 0x00000008 */ +#define STM32_GCCFG_PS2DET STM32_GCCFG_PS2DET_Msk // DM pull-up detection status */ +#define STM32_GCCFG_PWRDWN_Pos (16U) +#define STM32_GCCFG_PWRDWN_Msk (0x1UL << STM32_GCCFG_PWRDWN_Pos) // 0x00010000 */ +#define STM32_GCCFG_PWRDWN STM32_GCCFG_PWRDWN_Msk // Power down */ +#define STM32_GCCFG_BCDEN_Pos (17U) +#define STM32_GCCFG_BCDEN_Msk (0x1UL << STM32_GCCFG_BCDEN_Pos) // 0x00020000 */ +#define STM32_GCCFG_BCDEN STM32_GCCFG_BCDEN_Msk // Battery charging detector (BCD) enable */ +#define STM32_GCCFG_DCDEN_Pos (18U) +#define STM32_GCCFG_DCDEN_Msk (0x1UL << STM32_GCCFG_DCDEN_Pos) // 0x00040000 */ +#define STM32_GCCFG_DCDEN STM32_GCCFG_DCDEN_Msk // Data contact detection (DCD) mode enable*/ +#define STM32_GCCFG_PDEN_Pos (19U) +#define STM32_GCCFG_PDEN_Msk (0x1UL << STM32_GCCFG_PDEN_Pos) // 0x00080000 */ +#define STM32_GCCFG_PDEN STM32_GCCFG_PDEN_Msk // Primary detection (PD) mode enable*/ +#define STM32_GCCFG_SDEN_Pos (20U) +#define STM32_GCCFG_SDEN_Msk (0x1UL << STM32_GCCFG_SDEN_Pos) // 0x00100000 */ +#define STM32_GCCFG_SDEN STM32_GCCFG_SDEN_Msk // Secondary detection (SD) mode enable */ +#define STM32_GCCFG_VBDEN_Pos (21U) +#define STM32_GCCFG_VBDEN_Msk (0x1UL << STM32_GCCFG_VBDEN_Pos) // 0x00200000 */ +#define STM32_GCCFG_VBDEN STM32_GCCFG_VBDEN_Msk // VBUS mode enable */ +#define STM32_GCCFG_OTGIDEN_Pos (22U) +#define STM32_GCCFG_OTGIDEN_Msk (0x1UL << STM32_GCCFG_OTGIDEN_Pos) // 0x00400000 */ +#define STM32_GCCFG_OTGIDEN STM32_GCCFG_OTGIDEN_Msk // OTG Id enable */ +#define STM32_GCCFG_PHYHSEN_Pos (23U) +#define STM32_GCCFG_PHYHSEN_Msk (0x1UL << STM32_GCCFG_PHYHSEN_Pos) // 0x00800000 */ +#define STM32_GCCFG_PHYHSEN STM32_GCCFG_PHYHSEN_Msk // HS PHY enable */ + +/******************** Bit definition for DEACHINTMSK register ********************/ +#define DEACHINTMSK_IEP1INTM_Pos (1U) +#define DEACHINTMSK_IEP1INTM_Msk (0x1UL << DEACHINTMSK_IEP1INTM_Pos) // 0x00000002 */ +#define DEACHINTMSK_IEP1INTM DEACHINTMSK_IEP1INTM_Msk // IN Endpoint 1 interrupt mask bit */ +#define DEACHINTMSK_OEP1INTM_Pos (17U) +#define DEACHINTMSK_OEP1INTM_Msk (0x1UL << DEACHINTMSK_OEP1INTM_Pos) // 0x00020000 */ +#define DEACHINTMSK_OEP1INTM DEACHINTMSK_OEP1INTM_Msk // OUT Endpoint 1 interrupt mask bit */ + +/******************** Bit definition for CID register ********************/ +#define CID_PRODUCT_ID_Pos (0U) +#define CID_PRODUCT_ID_Msk (0xFFFFFFFFUL << CID_PRODUCT_ID_Pos) // 0xFFFFFFFF */ +#define CID_PRODUCT_ID CID_PRODUCT_ID_Msk // Product ID field */ + +/******************** Bit definition for GLPMCFG register ********************/ +#define GLPMCFG_LPMEN_Pos (0U) +#define GLPMCFG_LPMEN_Msk (0x1UL << GLPMCFG_LPMEN_Pos) // 0x00000001 */ +#define GLPMCFG_LPMEN GLPMCFG_LPMEN_Msk // LPM support enable */ +#define GLPMCFG_LPMACK_Pos (1U) +#define GLPMCFG_LPMACK_Msk (0x1UL << GLPMCFG_LPMACK_Pos) // 0x00000002 */ +#define GLPMCFG_LPMACK GLPMCFG_LPMACK_Msk // LPM Token acknowledge enable */ +#define GLPMCFG_BESL_Pos (2U) +#define GLPMCFG_BESL_Msk (0xFUL << GLPMCFG_BESL_Pos) // 0x0000003C */ +#define GLPMCFG_BESL GLPMCFG_BESL_Msk // BESL value received with last ACKed LPM Token */ +#define GLPMCFG_REMWAKE_Pos (6U) +#define GLPMCFG_REMWAKE_Msk (0x1UL << GLPMCFG_REMWAKE_Pos) // 0x00000040 */ +#define GLPMCFG_REMWAKE GLPMCFG_REMWAKE_Msk // bRemoteWake value received with last ACKed LPM Token */ +#define GLPMCFG_L1SSEN_Pos (7U) +#define GLPMCFG_L1SSEN_Msk (0x1UL << GLPMCFG_L1SSEN_Pos) // 0x00000080 */ +#define GLPMCFG_L1SSEN GLPMCFG_L1SSEN_Msk // L1 shallow sleep enable */ +#define GLPMCFG_BESLTHRS_Pos (8U) +#define GLPMCFG_BESLTHRS_Msk (0xFUL << GLPMCFG_BESLTHRS_Pos) // 0x00000F00 */ +#define GLPMCFG_BESLTHRS GLPMCFG_BESLTHRS_Msk // BESL threshold */ +#define GLPMCFG_L1DSEN_Pos (12U) +#define GLPMCFG_L1DSEN_Msk (0x1UL << GLPMCFG_L1DSEN_Pos) // 0x00001000 */ +#define GLPMCFG_L1DSEN GLPMCFG_L1DSEN_Msk // L1 deep sleep enable */ +#define GLPMCFG_LPMRSP_Pos (13U) +#define GLPMCFG_LPMRSP_Msk (0x3UL << GLPMCFG_LPMRSP_Pos) // 0x00006000 */ +#define GLPMCFG_LPMRSP GLPMCFG_LPMRSP_Msk // LPM response */ +#define GLPMCFG_SLPSTS_Pos (15U) +#define GLPMCFG_SLPSTS_Msk (0x1UL << GLPMCFG_SLPSTS_Pos) // 0x00008000 */ +#define GLPMCFG_SLPSTS GLPMCFG_SLPSTS_Msk // Port sleep status */ +#define GLPMCFG_L1RSMOK_Pos (16U) +#define GLPMCFG_L1RSMOK_Msk (0x1UL << GLPMCFG_L1RSMOK_Pos) // 0x00010000 */ +#define GLPMCFG_L1RSMOK GLPMCFG_L1RSMOK_Msk // Sleep State Resume OK */ +#define GLPMCFG_LPMCHIDX_Pos (17U) +#define GLPMCFG_LPMCHIDX_Msk (0xFUL << GLPMCFG_LPMCHIDX_Pos) // 0x001E0000 */ +#define GLPMCFG_LPMCHIDX GLPMCFG_LPMCHIDX_Msk // LPM Channel Index */ +#define GLPMCFG_LPMRCNT_Pos (21U) +#define GLPMCFG_LPMRCNT_Msk (0x7UL << GLPMCFG_LPMRCNT_Pos) // 0x00E00000 */ +#define GLPMCFG_LPMRCNT GLPMCFG_LPMRCNT_Msk // LPM retry count */ +#define GLPMCFG_SNDLPM_Pos (24U) +#define GLPMCFG_SNDLPM_Msk (0x1UL << GLPMCFG_SNDLPM_Pos) // 0x01000000 */ +#define GLPMCFG_SNDLPM GLPMCFG_SNDLPM_Msk // Send LPM transaction */ +#define GLPMCFG_LPMRCNTSTS_Pos (25U) +#define GLPMCFG_LPMRCNTSTS_Msk (0x7UL << GLPMCFG_LPMRCNTSTS_Pos) // 0x0E000000 */ +#define GLPMCFG_LPMRCNTSTS GLPMCFG_LPMRCNTSTS_Msk // LPM retry count status */ +#define GLPMCFG_ENBESL_Pos (28U) +#define GLPMCFG_ENBESL_Msk (0x1UL << GLPMCFG_ENBESL_Pos) // 0x10000000 */ +#define GLPMCFG_ENBESL GLPMCFG_ENBESL_Msk // Enable best effort service latency */ + +/******************** Bit definition for DIEPEACHMSK1 register ********************/ +#define DIEPEACHMSK1_XFRCM_Pos (0U) +#define DIEPEACHMSK1_XFRCM_Msk (0x1UL << DIEPEACHMSK1_XFRCM_Pos) // 0x00000001 */ +#define DIEPEACHMSK1_XFRCM DIEPEACHMSK1_XFRCM_Msk // Transfer completed interrupt mask */ +#define DIEPEACHMSK1_EPDM_Pos (1U) +#define DIEPEACHMSK1_EPDM_Msk (0x1UL << DIEPEACHMSK1_EPDM_Pos) // 0x00000002 */ +#define DIEPEACHMSK1_EPDM DIEPEACHMSK1_EPDM_Msk // Endpoint disabled interrupt mask */ +#define DIEPEACHMSK1_TOM_Pos (3U) +#define DIEPEACHMSK1_TOM_Msk (0x1UL << DIEPEACHMSK1_TOM_Pos) // 0x00000008 */ +#define DIEPEACHMSK1_TOM DIEPEACHMSK1_TOM_Msk // Timeout condition mask (nonisochronous endpoints) */ +#define DIEPEACHMSK1_ITTXFEMSK_Pos (4U) +#define DIEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << DIEPEACHMSK1_ITTXFEMSK_Pos) // 0x00000010 */ +#define DIEPEACHMSK1_ITTXFEMSK DIEPEACHMSK1_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask */ +#define DIEPEACHMSK1_INEPNMM_Pos (5U) +#define DIEPEACHMSK1_INEPNMM_Msk (0x1UL << DIEPEACHMSK1_INEPNMM_Pos) // 0x00000020 */ +#define DIEPEACHMSK1_INEPNMM DIEPEACHMSK1_INEPNMM_Msk // IN token received with EP mismatch mask */ +#define DIEPEACHMSK1_INEPNEM_Pos (6U) +#define DIEPEACHMSK1_INEPNEM_Msk (0x1UL << DIEPEACHMSK1_INEPNEM_Pos) // 0x00000040 */ +#define DIEPEACHMSK1_INEPNEM DIEPEACHMSK1_INEPNEM_Msk // IN endpoint NAK effective mask */ +#define DIEPEACHMSK1_TXFURM_Pos (8U) +#define DIEPEACHMSK1_TXFURM_Msk (0x1UL << DIEPEACHMSK1_TXFURM_Pos) // 0x00000100 */ +#define DIEPEACHMSK1_TXFURM DIEPEACHMSK1_TXFURM_Msk // FIFO underrun mask */ +#define DIEPEACHMSK1_BIM_Pos (9U) +#define DIEPEACHMSK1_BIM_Msk (0x1UL << DIEPEACHMSK1_BIM_Pos) // 0x00000200 */ +#define DIEPEACHMSK1_BIM DIEPEACHMSK1_BIM_Msk // BNA interrupt mask */ +#define DIEPEACHMSK1_NAKM_Pos (13U) +#define DIEPEACHMSK1_NAKM_Msk (0x1UL << DIEPEACHMSK1_NAKM_Pos) // 0x00002000 */ +#define DIEPEACHMSK1_NAKM DIEPEACHMSK1_NAKM_Msk // NAK interrupt mask */ + +/******************** Bit definition for HPRT register ********************/ +#define HPRT_PCSTS_Pos (0U) +#define HPRT_PCSTS_Msk (0x1UL << HPRT_PCSTS_Pos) // 0x00000001 */ +#define HPRT_PCSTS HPRT_PCSTS_Msk // Port connect status */ +#define HPRT_PCDET_Pos (1U) +#define HPRT_PCDET_Msk (0x1UL << HPRT_PCDET_Pos) // 0x00000002 */ +#define HPRT_PCDET HPRT_PCDET_Msk // Port connect detected */ +#define HPRT_PENA_Pos (2U) +#define HPRT_PENA_Msk (0x1UL << HPRT_PENA_Pos) // 0x00000004 */ +#define HPRT_PENA HPRT_PENA_Msk // Port enable */ +#define HPRT_PENCHNG_Pos (3U) +#define HPRT_PENCHNG_Msk (0x1UL << HPRT_PENCHNG_Pos) // 0x00000008 */ +#define HPRT_PENCHNG HPRT_PENCHNG_Msk // Port enable/disable change */ +#define HPRT_POCA_Pos (4U) +#define HPRT_POCA_Msk (0x1UL << HPRT_POCA_Pos) // 0x00000010 */ +#define HPRT_POCA HPRT_POCA_Msk // Port overcurrent active */ +#define HPRT_POCCHNG_Pos (5U) +#define HPRT_POCCHNG_Msk (0x1UL << HPRT_POCCHNG_Pos) // 0x00000020 */ +#define HPRT_POCCHNG HPRT_POCCHNG_Msk // Port overcurrent change */ +#define HPRT_PRES_Pos (6U) +#define HPRT_PRES_Msk (0x1UL << HPRT_PRES_Pos) // 0x00000040 */ +#define HPRT_PRES HPRT_PRES_Msk // Port resume */ +#define HPRT_PSUSP_Pos (7U) +#define HPRT_PSUSP_Msk (0x1UL << HPRT_PSUSP_Pos) // 0x00000080 */ +#define HPRT_PSUSP HPRT_PSUSP_Msk // Port suspend */ +#define HPRT_PRST_Pos (8U) +#define HPRT_PRST_Msk (0x1UL << HPRT_PRST_Pos) // 0x00000100 */ +#define HPRT_PRST HPRT_PRST_Msk // Port reset */ + +#define HPRT_PLSTS_Pos (10U) +#define HPRT_PLSTS_Msk (0x3UL << HPRT_PLSTS_Pos) // 0x00000C00 */ +#define HPRT_PLSTS HPRT_PLSTS_Msk // Port line status */ +#define HPRT_PLSTS_0 (0x1UL << HPRT_PLSTS_Pos) // 0x00000400 */ +#define HPRT_PLSTS_1 (0x2UL << HPRT_PLSTS_Pos) // 0x00000800 */ +#define HPRT_PPWR_Pos (12U) +#define HPRT_PPWR_Msk (0x1UL << HPRT_PPWR_Pos) // 0x00001000 */ +#define HPRT_PPWR HPRT_PPWR_Msk // Port power */ + +#define HPRT_PTCTL_Pos (13U) +#define HPRT_PTCTL_Msk (0xFUL << HPRT_PTCTL_Pos) // 0x0001E000 */ +#define HPRT_PTCTL HPRT_PTCTL_Msk // Port test control */ +#define HPRT_PTCTL_0 (0x1UL << HPRT_PTCTL_Pos) // 0x00002000 */ +#define HPRT_PTCTL_1 (0x2UL << HPRT_PTCTL_Pos) // 0x00004000 */ +#define HPRT_PTCTL_2 (0x4UL << HPRT_PTCTL_Pos) // 0x00008000 */ +#define HPRT_PTCTL_3 (0x8UL << HPRT_PTCTL_Pos) // 0x00010000 */ + +#define HPRT_PSPD_Pos (17U) +#define HPRT_PSPD_Msk (0x3UL << HPRT_PSPD_Pos) // 0x00060000 */ +#define HPRT_PSPD HPRT_PSPD_Msk // Port speed */ +#define HPRT_PSPD_0 (0x1UL << HPRT_PSPD_Pos) // 0x00020000 */ +#define HPRT_PSPD_1 (0x2UL << HPRT_PSPD_Pos) // 0x00040000 */ + +/******************** Bit definition for DOEPEACHMSK1 register ********************/ +#define DOEPEACHMSK1_XFRCM_Pos (0U) +#define DOEPEACHMSK1_XFRCM_Msk (0x1UL << DOEPEACHMSK1_XFRCM_Pos) // 0x00000001 */ +#define DOEPEACHMSK1_XFRCM DOEPEACHMSK1_XFRCM_Msk // Transfer completed interrupt mask */ +#define DOEPEACHMSK1_EPDM_Pos (1U) +#define DOEPEACHMSK1_EPDM_Msk (0x1UL << DOEPEACHMSK1_EPDM_Pos) // 0x00000002 */ +#define DOEPEACHMSK1_EPDM DOEPEACHMSK1_EPDM_Msk // Endpoint disabled interrupt mask */ +#define DOEPEACHMSK1_TOM_Pos (3U) +#define DOEPEACHMSK1_TOM_Msk (0x1UL << DOEPEACHMSK1_TOM_Pos) // 0x00000008 */ +#define DOEPEACHMSK1_TOM DOEPEACHMSK1_TOM_Msk // Timeout condition mask */ +#define DOEPEACHMSK1_ITTXFEMSK_Pos (4U) +#define DOEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << DOEPEACHMSK1_ITTXFEMSK_Pos) // 0x00000010 */ +#define DOEPEACHMSK1_ITTXFEMSK DOEPEACHMSK1_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask */ +#define DOEPEACHMSK1_INEPNMM_Pos (5U) +#define DOEPEACHMSK1_INEPNMM_Msk (0x1UL << DOEPEACHMSK1_INEPNMM_Pos) // 0x00000020 */ +#define DOEPEACHMSK1_INEPNMM DOEPEACHMSK1_INEPNMM_Msk // IN token received with EP mismatch mask */ +#define DOEPEACHMSK1_INEPNEM_Pos (6U) +#define DOEPEACHMSK1_INEPNEM_Msk (0x1UL << DOEPEACHMSK1_INEPNEM_Pos) // 0x00000040 */ +#define DOEPEACHMSK1_INEPNEM DOEPEACHMSK1_INEPNEM_Msk // IN endpoint NAK effective mask */ +#define DOEPEACHMSK1_TXFURM_Pos (8U) +#define DOEPEACHMSK1_TXFURM_Msk (0x1UL << DOEPEACHMSK1_TXFURM_Pos) // 0x00000100 */ +#define DOEPEACHMSK1_TXFURM DOEPEACHMSK1_TXFURM_Msk // OUT packet error mask */ +#define DOEPEACHMSK1_BIM_Pos (9U) +#define DOEPEACHMSK1_BIM_Msk (0x1UL << DOEPEACHMSK1_BIM_Pos) // 0x00000200 */ +#define DOEPEACHMSK1_BIM DOEPEACHMSK1_BIM_Msk // BNA interrupt mask */ +#define DOEPEACHMSK1_BERRM_Pos (12U) +#define DOEPEACHMSK1_BERRM_Msk (0x1UL << DOEPEACHMSK1_BERRM_Pos) // 0x00001000 */ +#define DOEPEACHMSK1_BERRM DOEPEACHMSK1_BERRM_Msk // Bubble error interrupt mask */ +#define DOEPEACHMSK1_NAKM_Pos (13U) +#define DOEPEACHMSK1_NAKM_Msk (0x1UL << DOEPEACHMSK1_NAKM_Pos) // 0x00002000 */ +#define DOEPEACHMSK1_NAKM DOEPEACHMSK1_NAKM_Msk // NAK interrupt mask */ +#define DOEPEACHMSK1_NYETM_Pos (14U) +#define DOEPEACHMSK1_NYETM_Msk (0x1UL << DOEPEACHMSK1_NYETM_Pos) // 0x00004000 */ +#define DOEPEACHMSK1_NYETM DOEPEACHMSK1_NYETM_Msk // NYET interrupt mask */ + +/******************** Bit definition for HPTXFSIZ register ********************/ +#define HPTXFSIZ_PTXSA_Pos (0U) +#define HPTXFSIZ_PTXSA_Msk (0xFFFFUL << HPTXFSIZ_PTXSA_Pos) // 0x0000FFFF */ +#define HPTXFSIZ_PTXSA HPTXFSIZ_PTXSA_Msk // Host periodic TxFIFO start address */ +#define HPTXFSIZ_PTXFD_Pos (16U) +#define HPTXFSIZ_PTXFD_Msk (0xFFFFUL << HPTXFSIZ_PTXFD_Pos) // 0xFFFF0000 */ +#define HPTXFSIZ_PTXFD HPTXFSIZ_PTXFD_Msk // Host periodic TxFIFO depth */ + +/******************** Bit definition for DIEPCTL register ********************/ +#define DIEPCTL_MPSIZ_Pos (0U) +#define DIEPCTL_MPSIZ_Msk (0x7FFUL << DIEPCTL_MPSIZ_Pos) // 0x000007FF */ +#define DIEPCTL_MPSIZ DIEPCTL_MPSIZ_Msk // Maximum packet size */ +#define DIEPCTL_USBAEP_Pos (15U) +#define DIEPCTL_USBAEP_Msk (0x1UL << DIEPCTL_USBAEP_Pos) // 0x00008000 */ +#define DIEPCTL_USBAEP DIEPCTL_USBAEP_Msk // USB active endpoint */ +#define DIEPCTL_EONUM_DPID_Pos (16U) +#define DIEPCTL_EONUM_DPID_Msk (0x1UL << DIEPCTL_EONUM_DPID_Pos) // 0x00010000 */ +#define DIEPCTL_EONUM_DPID DIEPCTL_EONUM_DPID_Msk // Even/odd frame */ +#define DIEPCTL_NAKSTS_Pos (17U) +#define DIEPCTL_NAKSTS_Msk (0x1UL << DIEPCTL_NAKSTS_Pos) // 0x00020000 */ +#define DIEPCTL_NAKSTS DIEPCTL_NAKSTS_Msk // NAK status */ + +#define DIEPCTL_EPTYP_Pos (18U) +#define DIEPCTL_EPTYP_Msk (0x3UL << DIEPCTL_EPTYP_Pos) // 0x000C0000 */ +#define DIEPCTL_EPTYP DIEPCTL_EPTYP_Msk // Endpoint type */ +#define DIEPCTL_EPTYP_0 (0x1UL << DIEPCTL_EPTYP_Pos) // 0x00040000 */ +#define DIEPCTL_EPTYP_1 (0x2UL << DIEPCTL_EPTYP_Pos) // 0x00080000 */ +#define DIEPCTL_STALL_Pos (21U) +#define DIEPCTL_STALL_Msk (0x1UL << DIEPCTL_STALL_Pos) // 0x00200000 */ +#define DIEPCTL_STALL DIEPCTL_STALL_Msk // STALL handshake */ + +#define DIEPCTL_TXFNUM_Pos (22U) +#define DIEPCTL_TXFNUM_Msk (0xFUL << DIEPCTL_TXFNUM_Pos) // 0x03C00000 */ +#define DIEPCTL_TXFNUM DIEPCTL_TXFNUM_Msk // TxFIFO number */ +#define DIEPCTL_TXFNUM_0 (0x1UL << DIEPCTL_TXFNUM_Pos) // 0x00400000 */ +#define DIEPCTL_TXFNUM_1 (0x2UL << DIEPCTL_TXFNUM_Pos) // 0x00800000 */ +#define DIEPCTL_TXFNUM_2 (0x4UL << DIEPCTL_TXFNUM_Pos) // 0x01000000 */ +#define DIEPCTL_TXFNUM_3 (0x8UL << DIEPCTL_TXFNUM_Pos) // 0x02000000 */ +#define DIEPCTL_CNAK_Pos (26U) +#define DIEPCTL_CNAK_Msk (0x1UL << DIEPCTL_CNAK_Pos) // 0x04000000 */ +#define DIEPCTL_CNAK DIEPCTL_CNAK_Msk // Clear NAK */ +#define DIEPCTL_SNAK_Pos (27U) +#define DIEPCTL_SNAK_Msk (0x1UL << DIEPCTL_SNAK_Pos) // 0x08000000 */ +#define DIEPCTL_SNAK DIEPCTL_SNAK_Msk // Set NAK */ +#define DIEPCTL_SD0PID_SEVNFRM_Pos (28U) +#define DIEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << DIEPCTL_SD0PID_SEVNFRM_Pos) // 0x10000000 */ +#define DIEPCTL_SD0PID_SEVNFRM DIEPCTL_SD0PID_SEVNFRM_Msk // Set DATA0 PID */ +#define DIEPCTL_SODDFRM_Pos (29U) +#define DIEPCTL_SODDFRM_Msk (0x1UL << DIEPCTL_SODDFRM_Pos) // 0x20000000 */ +#define DIEPCTL_SODDFRM DIEPCTL_SODDFRM_Msk // Set odd frame */ +#define DIEPCTL_EPDIS_Pos (30U) +#define DIEPCTL_EPDIS_Msk (0x1UL << DIEPCTL_EPDIS_Pos) // 0x40000000 */ +#define DIEPCTL_EPDIS DIEPCTL_EPDIS_Msk // Endpoint disable */ +#define DIEPCTL_EPENA_Pos (31U) +#define DIEPCTL_EPENA_Msk (0x1UL << DIEPCTL_EPENA_Pos) // 0x80000000 */ +#define DIEPCTL_EPENA DIEPCTL_EPENA_Msk // Endpoint enable */ + +/******************** Bit definition for HCCHAR register ********************/ +#define HCCHAR_MPSIZ_Pos (0U) +#define HCCHAR_MPSIZ_Msk (0x7FFUL << HCCHAR_MPSIZ_Pos) // 0x000007FF */ +#define HCCHAR_MPSIZ HCCHAR_MPSIZ_Msk // Maximum packet size */ + +#define HCCHAR_EPNUM_Pos (11U) +#define HCCHAR_EPNUM_Msk (0xFUL << HCCHAR_EPNUM_Pos) // 0x00007800 */ +#define HCCHAR_EPNUM HCCHAR_EPNUM_Msk // Endpoint number */ +#define HCCHAR_EPNUM_0 (0x1UL << HCCHAR_EPNUM_Pos) // 0x00000800 */ +#define HCCHAR_EPNUM_1 (0x2UL << HCCHAR_EPNUM_Pos) // 0x00001000 */ +#define HCCHAR_EPNUM_2 (0x4UL << HCCHAR_EPNUM_Pos) // 0x00002000 */ +#define HCCHAR_EPNUM_3 (0x8UL << HCCHAR_EPNUM_Pos) // 0x00004000 */ +#define HCCHAR_EPDIR_Pos (15U) +#define HCCHAR_EPDIR_Msk (0x1UL << HCCHAR_EPDIR_Pos) // 0x00008000 */ +#define HCCHAR_EPDIR HCCHAR_EPDIR_Msk // Endpoint direction */ +#define HCCHAR_LSDEV_Pos (17U) +#define HCCHAR_LSDEV_Msk (0x1UL << HCCHAR_LSDEV_Pos) // 0x00020000 */ +#define HCCHAR_LSDEV HCCHAR_LSDEV_Msk // Low-speed device */ + +#define HCCHAR_EPTYP_Pos (18U) +#define HCCHAR_EPTYP_Msk (0x3UL << HCCHAR_EPTYP_Pos) // 0x000C0000 */ +#define HCCHAR_EPTYP HCCHAR_EPTYP_Msk // Endpoint type */ +#define HCCHAR_EPTYP_0 (0x1UL << HCCHAR_EPTYP_Pos) // 0x00040000 */ +#define HCCHAR_EPTYP_1 (0x2UL << HCCHAR_EPTYP_Pos) // 0x00080000 */ + +#define HCCHAR_MC_Pos (20U) +#define HCCHAR_MC_Msk (0x3UL << HCCHAR_MC_Pos) // 0x00300000 */ +#define HCCHAR_MC HCCHAR_MC_Msk // Multi Count (MC) / Error Count (EC) */ +#define HCCHAR_MC_0 (0x1UL << HCCHAR_MC_Pos) // 0x00100000 */ +#define HCCHAR_MC_1 (0x2UL << HCCHAR_MC_Pos) // 0x00200000 */ + +#define HCCHAR_DAD_Pos (22U) +#define HCCHAR_DAD_Msk (0x7FUL << HCCHAR_DAD_Pos) // 0x1FC00000 */ +#define HCCHAR_DAD HCCHAR_DAD_Msk // Device address */ +#define HCCHAR_DAD_0 (0x01UL << HCCHAR_DAD_Pos) // 0x00400000 */ +#define HCCHAR_DAD_1 (0x02UL << HCCHAR_DAD_Pos) // 0x00800000 */ +#define HCCHAR_DAD_2 (0x04UL << HCCHAR_DAD_Pos) // 0x01000000 */ +#define HCCHAR_DAD_3 (0x08UL << HCCHAR_DAD_Pos) // 0x02000000 */ +#define HCCHAR_DAD_4 (0x10UL << HCCHAR_DAD_Pos) // 0x04000000 */ +#define HCCHAR_DAD_5 (0x20UL << HCCHAR_DAD_Pos) // 0x08000000 */ +#define HCCHAR_DAD_6 (0x40UL << HCCHAR_DAD_Pos) // 0x10000000 */ +#define HCCHAR_ODDFRM_Pos (29U) +#define HCCHAR_ODDFRM_Msk (0x1UL << HCCHAR_ODDFRM_Pos) // 0x20000000 */ +#define HCCHAR_ODDFRM HCCHAR_ODDFRM_Msk // Odd frame */ +#define HCCHAR_CHDIS_Pos (30U) +#define HCCHAR_CHDIS_Msk (0x1UL << HCCHAR_CHDIS_Pos) // 0x40000000 */ +#define HCCHAR_CHDIS HCCHAR_CHDIS_Msk // Channel disable */ +#define HCCHAR_CHENA_Pos (31U) +#define HCCHAR_CHENA_Msk (0x1UL << HCCHAR_CHENA_Pos) // 0x80000000 */ +#define HCCHAR_CHENA HCCHAR_CHENA_Msk // Channel enable */ + +/******************** Bit definition for HCSPLT register ********************/ + +#define HCSPLT_PRTADDR_Pos (0U) +#define HCSPLT_PRTADDR_Msk (0x7FUL << HCSPLT_PRTADDR_Pos) // 0x0000007F */ +#define HCSPLT_PRTADDR HCSPLT_PRTADDR_Msk // Port address */ +#define HCSPLT_PRTADDR_0 (0x01UL << HCSPLT_PRTADDR_Pos) // 0x00000001 */ +#define HCSPLT_PRTADDR_1 (0x02UL << HCSPLT_PRTADDR_Pos) // 0x00000002 */ +#define HCSPLT_PRTADDR_2 (0x04UL << HCSPLT_PRTADDR_Pos) // 0x00000004 */ +#define HCSPLT_PRTADDR_3 (0x08UL << HCSPLT_PRTADDR_Pos) // 0x00000008 */ +#define HCSPLT_PRTADDR_4 (0x10UL << HCSPLT_PRTADDR_Pos) // 0x00000010 */ +#define HCSPLT_PRTADDR_5 (0x20UL << HCSPLT_PRTADDR_Pos) // 0x00000020 */ +#define HCSPLT_PRTADDR_6 (0x40UL << HCSPLT_PRTADDR_Pos) // 0x00000040 */ + +#define HCSPLT_HUBADDR_Pos (7U) +#define HCSPLT_HUBADDR_Msk (0x7FUL << HCSPLT_HUBADDR_Pos) // 0x00003F80 */ +#define HCSPLT_HUBADDR HCSPLT_HUBADDR_Msk // Hub address */ +#define HCSPLT_HUBADDR_0 (0x01UL << HCSPLT_HUBADDR_Pos) // 0x00000080 */ +#define HCSPLT_HUBADDR_1 (0x02UL << HCSPLT_HUBADDR_Pos) // 0x00000100 */ +#define HCSPLT_HUBADDR_2 (0x04UL << HCSPLT_HUBADDR_Pos) // 0x00000200 */ +#define HCSPLT_HUBADDR_3 (0x08UL << HCSPLT_HUBADDR_Pos) // 0x00000400 */ +#define HCSPLT_HUBADDR_4 (0x10UL << HCSPLT_HUBADDR_Pos) // 0x00000800 */ +#define HCSPLT_HUBADDR_5 (0x20UL << HCSPLT_HUBADDR_Pos) // 0x00001000 */ +#define HCSPLT_HUBADDR_6 (0x40UL << HCSPLT_HUBADDR_Pos) // 0x00002000 */ + +#define HCSPLT_XACTPOS_Pos (14U) +#define HCSPLT_XACTPOS_Msk (0x3UL << HCSPLT_XACTPOS_Pos) // 0x0000C000 */ +#define HCSPLT_XACTPOS HCSPLT_XACTPOS_Msk // XACTPOS */ +#define HCSPLT_XACTPOS_0 (0x1UL << HCSPLT_XACTPOS_Pos) // 0x00004000 */ +#define HCSPLT_XACTPOS_1 (0x2UL << HCSPLT_XACTPOS_Pos) // 0x00008000 */ +#define HCSPLT_COMPLSPLT_Pos (16U) +#define HCSPLT_COMPLSPLT_Msk (0x1UL << HCSPLT_COMPLSPLT_Pos) // 0x00010000 */ +#define HCSPLT_COMPLSPLT HCSPLT_COMPLSPLT_Msk // Do complete split */ +#define HCSPLT_SPLITEN_Pos (31U) +#define HCSPLT_SPLITEN_Msk (0x1UL << HCSPLT_SPLITEN_Pos) // 0x80000000 */ +#define HCSPLT_SPLITEN HCSPLT_SPLITEN_Msk // Split enable */ + +/******************** Bit definition for HCINT register ********************/ +#define HCINT_XFRC_Pos (0U) +#define HCINT_XFRC_Msk (0x1UL << HCINT_XFRC_Pos) // 0x00000001 */ +#define HCINT_XFRC HCINT_XFRC_Msk // Transfer completed */ +#define HCINT_CHH_Pos (1U) +#define HCINT_CHH_Msk (0x1UL << HCINT_CHH_Pos) // 0x00000002 */ +#define HCINT_CHH HCINT_CHH_Msk // Channel halted */ +#define HCINT_AHBERR_Pos (2U) +#define HCINT_AHBERR_Msk (0x1UL << HCINT_AHBERR_Pos) // 0x00000004 */ +#define HCINT_AHBERR HCINT_AHBERR_Msk // AHB error */ +#define HCINT_STALL_Pos (3U) +#define HCINT_STALL_Msk (0x1UL << HCINT_STALL_Pos) // 0x00000008 */ +#define HCINT_STALL HCINT_STALL_Msk // STALL response received interrupt */ +#define HCINT_NAK_Pos (4U) +#define HCINT_NAK_Msk (0x1UL << HCINT_NAK_Pos) // 0x00000010 */ +#define HCINT_NAK HCINT_NAK_Msk // NAK response received interrupt */ +#define HCINT_ACK_Pos (5U) +#define HCINT_ACK_Msk (0x1UL << HCINT_ACK_Pos) // 0x00000020 */ +#define HCINT_ACK HCINT_ACK_Msk // ACK response received/transmitted interrupt */ +#define HCINT_NYET_Pos (6U) +#define HCINT_NYET_Msk (0x1UL << HCINT_NYET_Pos) // 0x00000040 */ +#define HCINT_NYET HCINT_NYET_Msk // Response received interrupt */ +#define HCINT_TXERR_Pos (7U) +#define HCINT_TXERR_Msk (0x1UL << HCINT_TXERR_Pos) // 0x00000080 */ +#define HCINT_TXERR HCINT_TXERR_Msk // Transaction error */ +#define HCINT_BBERR_Pos (8U) +#define HCINT_BBERR_Msk (0x1UL << HCINT_BBERR_Pos) // 0x00000100 */ +#define HCINT_BBERR HCINT_BBERR_Msk // Babble error */ +#define HCINT_FRMOR_Pos (9U) +#define HCINT_FRMOR_Msk (0x1UL << HCINT_FRMOR_Pos) // 0x00000200 */ +#define HCINT_FRMOR HCINT_FRMOR_Msk // Frame overrun */ +#define HCINT_DTERR_Pos (10U) +#define HCINT_DTERR_Msk (0x1UL << HCINT_DTERR_Pos) // 0x00000400 */ +#define HCINT_DTERR HCINT_DTERR_Msk // Data toggle error */ + +/******************** Bit definition for DIEPINT register ********************/ +#define DIEPINT_XFRC_Pos (0U) +#define DIEPINT_XFRC_Msk (0x1UL << DIEPINT_XFRC_Pos) // 0x00000001 */ +#define DIEPINT_XFRC DIEPINT_XFRC_Msk // Transfer completed interrupt */ +#define DIEPINT_EPDISD_Pos (1U) +#define DIEPINT_EPDISD_Msk (0x1UL << DIEPINT_EPDISD_Pos) // 0x00000002 */ +#define DIEPINT_EPDISD DIEPINT_EPDISD_Msk // Endpoint disabled interrupt */ +#define DIEPINT_AHBERR_Pos (2U) +#define DIEPINT_AHBERR_Msk (0x1UL << DIEPINT_AHBERR_Pos) // 0x00000004 */ +#define DIEPINT_AHBERR DIEPINT_AHBERR_Msk // AHB Error (AHBErr) during an IN transaction */ +#define DIEPINT_TOC_Pos (3U) +#define DIEPINT_TOC_Msk (0x1UL << DIEPINT_TOC_Pos) // 0x00000008 */ +#define DIEPINT_TOC DIEPINT_TOC_Msk // Timeout condition */ +#define DIEPINT_ITTXFE_Pos (4U) +#define DIEPINT_ITTXFE_Msk (0x1UL << DIEPINT_ITTXFE_Pos) // 0x00000010 */ +#define DIEPINT_ITTXFE DIEPINT_ITTXFE_Msk // IN token received when TxFIFO is empty */ +#define DIEPINT_INEPNM_Pos (5U) +#define DIEPINT_INEPNM_Msk (0x1UL << DIEPINT_INEPNM_Pos) // 0x00000020 */ +#define DIEPINT_INEPNM DIEPINT_INEPNM_Msk // IN token received with EP mismatch */ +#define DIEPINT_INEPNE_Pos (6U) +#define DIEPINT_INEPNE_Msk (0x1UL << DIEPINT_INEPNE_Pos) // 0x00000040 */ +#define DIEPINT_INEPNE DIEPINT_INEPNE_Msk // IN endpoint NAK effective */ +#define DIEPINT_TXFE_Pos (7U) +#define DIEPINT_TXFE_Msk (0x1UL << DIEPINT_TXFE_Pos) // 0x00000080 */ +#define DIEPINT_TXFE DIEPINT_TXFE_Msk // Transmit FIFO empty */ +#define DIEPINT_TXFIFOUDRN_Pos (8U) +#define DIEPINT_TXFIFOUDRN_Msk (0x1UL << DIEPINT_TXFIFOUDRN_Pos) // 0x00000100 */ +#define DIEPINT_TXFIFOUDRN DIEPINT_TXFIFOUDRN_Msk // Transmit Fifo Underrun */ +#define DIEPINT_BNA_Pos (9U) +#define DIEPINT_BNA_Msk (0x1UL << DIEPINT_BNA_Pos) // 0x00000200 */ +#define DIEPINT_BNA DIEPINT_BNA_Msk // Buffer not available interrupt */ +#define DIEPINT_PKTDRPSTS_Pos (11U) +#define DIEPINT_PKTDRPSTS_Msk (0x1UL << DIEPINT_PKTDRPSTS_Pos) // 0x00000800 */ +#define DIEPINT_PKTDRPSTS DIEPINT_PKTDRPSTS_Msk // Packet dropped status */ +#define DIEPINT_BERR_Pos (12U) +#define DIEPINT_BERR_Msk (0x1UL << DIEPINT_BERR_Pos) // 0x00001000 */ +#define DIEPINT_BERR DIEPINT_BERR_Msk // Babble error interrupt */ +#define DIEPINT_NAK_Pos (13U) +#define DIEPINT_NAK_Msk (0x1UL << DIEPINT_NAK_Pos) // 0x00002000 */ +#define DIEPINT_NAK DIEPINT_NAK_Msk // NAK interrupt */ + +/******************** Bit definition for HCINTMSK register ********************/ +#define HCINTMSK_XFRCM_Pos (0U) +#define HCINTMSK_XFRCM_Msk (0x1UL << HCINTMSK_XFRCM_Pos) // 0x00000001 */ +#define HCINTMSK_XFRCM HCINTMSK_XFRCM_Msk // Transfer completed mask */ +#define HCINTMSK_CHHM_Pos (1U) +#define HCINTMSK_CHHM_Msk (0x1UL << HCINTMSK_CHHM_Pos) // 0x00000002 */ +#define HCINTMSK_CHHM HCINTMSK_CHHM_Msk // Channel halted mask */ +#define HCINTMSK_AHBERR_Pos (2U) +#define HCINTMSK_AHBERR_Msk (0x1UL << HCINTMSK_AHBERR_Pos) // 0x00000004 */ +#define HCINTMSK_AHBERR HCINTMSK_AHBERR_Msk // AHB error */ +#define HCINTMSK_STALLM_Pos (3U) +#define HCINTMSK_STALLM_Msk (0x1UL << HCINTMSK_STALLM_Pos) // 0x00000008 */ +#define HCINTMSK_STALLM HCINTMSK_STALLM_Msk // STALL response received interrupt mask */ +#define HCINTMSK_NAKM_Pos (4U) +#define HCINTMSK_NAKM_Msk (0x1UL << HCINTMSK_NAKM_Pos) // 0x00000010 */ +#define HCINTMSK_NAKM HCINTMSK_NAKM_Msk // NAK response received interrupt mask */ +#define HCINTMSK_ACKM_Pos (5U) +#define HCINTMSK_ACKM_Msk (0x1UL << HCINTMSK_ACKM_Pos) // 0x00000020 */ +#define HCINTMSK_ACKM HCINTMSK_ACKM_Msk // ACK response received/transmitted interrupt mask */ +#define HCINTMSK_NYET_Pos (6U) +#define HCINTMSK_NYET_Msk (0x1UL << HCINTMSK_NYET_Pos) // 0x00000040 */ +#define HCINTMSK_NYET HCINTMSK_NYET_Msk // response received interrupt mask */ +#define HCINTMSK_TXERRM_Pos (7U) +#define HCINTMSK_TXERRM_Msk (0x1UL << HCINTMSK_TXERRM_Pos) // 0x00000080 */ +#define HCINTMSK_TXERRM HCINTMSK_TXERRM_Msk // Transaction error mask */ +#define HCINTMSK_BBERRM_Pos (8U) +#define HCINTMSK_BBERRM_Msk (0x1UL << HCINTMSK_BBERRM_Pos) // 0x00000100 */ +#define HCINTMSK_BBERRM HCINTMSK_BBERRM_Msk // Babble error mask */ +#define HCINTMSK_FRMORM_Pos (9U) +#define HCINTMSK_FRMORM_Msk (0x1UL << HCINTMSK_FRMORM_Pos) // 0x00000200 */ +#define HCINTMSK_FRMORM HCINTMSK_FRMORM_Msk // Frame overrun mask */ +#define HCINTMSK_DTERRM_Pos (10U) +#define HCINTMSK_DTERRM_Msk (0x1UL << HCINTMSK_DTERRM_Pos) // 0x00000400 */ +#define HCINTMSK_DTERRM HCINTMSK_DTERRM_Msk // Data toggle error mask */ + +/******************** Bit definition for DIEPTSIZ register ********************/ + +#define DIEPTSIZ_XFRSIZ_Pos (0U) +#define DIEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << DIEPTSIZ_XFRSIZ_Pos) // 0x0007FFFF */ +#define DIEPTSIZ_XFRSIZ DIEPTSIZ_XFRSIZ_Msk // Transfer size */ +#define DIEPTSIZ_PKTCNT_Pos (19U) +#define DIEPTSIZ_PKTCNT_Msk (0x3FFUL << DIEPTSIZ_PKTCNT_Pos) // 0x1FF80000 */ +#define DIEPTSIZ_PKTCNT DIEPTSIZ_PKTCNT_Msk // Packet count */ +#define DIEPTSIZ_MULCNT_Pos (29U) +#define DIEPTSIZ_MULCNT_Msk (0x3UL << DIEPTSIZ_MULCNT_Pos) // 0x60000000 */ +#define DIEPTSIZ_MULCNT DIEPTSIZ_MULCNT_Msk // Packet count */ + /******************** Bit definition for HCTSIZ register ********************/ +#define HCTSIZ_XFRSIZ_Pos (0U) +#define HCTSIZ_XFRSIZ_Msk (0x7FFFFUL << HCTSIZ_XFRSIZ_Pos) // 0x0007FFFF */ +#define HCTSIZ_XFRSIZ HCTSIZ_XFRSIZ_Msk // Transfer size */ +#define HCTSIZ_PKTCNT_Pos (19U) +#define HCTSIZ_PKTCNT_Msk (0x3FFUL << HCTSIZ_PKTCNT_Pos) // 0x1FF80000 */ +#define HCTSIZ_PKTCNT HCTSIZ_PKTCNT_Msk // Packet count */ +#define HCTSIZ_DOPING_Pos (31U) +#define HCTSIZ_DOPING_Msk (0x1UL << HCTSIZ_DOPING_Pos) // 0x80000000 */ +#define HCTSIZ_DOPING HCTSIZ_DOPING_Msk // Do PING */ +#define HCTSIZ_DPID_Pos (29U) +#define HCTSIZ_DPID_Msk (0x3UL << HCTSIZ_DPID_Pos) // 0x60000000 */ +#define HCTSIZ_DPID HCTSIZ_DPID_Msk // Data PID */ +#define HCTSIZ_DPID_0 (0x1UL << HCTSIZ_DPID_Pos) // 0x20000000 */ +#define HCTSIZ_DPID_1 (0x2UL << HCTSIZ_DPID_Pos) // 0x40000000 */ + +/******************** Bit definition for DIEPDMA register ********************/ +#define DIEPDMA_DMAADDR_Pos (0U) +#define DIEPDMA_DMAADDR_Msk (0xFFFFFFFFUL << DIEPDMA_DMAADDR_Pos) // 0xFFFFFFFF */ +#define DIEPDMA_DMAADDR DIEPDMA_DMAADDR_Msk // DMA address */ + +/******************** Bit definition for HCDMA register ********************/ +#define HCDMA_DMAADDR_Pos (0U) +#define HCDMA_DMAADDR_Msk (0xFFFFFFFFUL << HCDMA_DMAADDR_Pos) // 0xFFFFFFFF */ +#define HCDMA_DMAADDR HCDMA_DMAADDR_Msk // DMA address */ + + /******************** Bit definition for DTXFSTS register ********************/ +#define DTXFSTS_INEPTFSAV_Pos (0U) +#define DTXFSTS_INEPTFSAV_Msk (0xFFFFUL << DTXFSTS_INEPTFSAV_Pos) // 0x0000FFFF */ +#define DTXFSTS_INEPTFSAV DTXFSTS_INEPTFSAV_Msk // IN endpoint TxFIFO space available */ + + /******************** Bit definition for DIEPTXF register ********************/ +#define DIEPTXF_INEPTXSA_Pos (0U) +#define DIEPTXF_INEPTXSA_Msk (0xFFFFUL << DIEPTXF_INEPTXSA_Pos) // 0x0000FFFF */ +#define DIEPTXF_INEPTXSA DIEPTXF_INEPTXSA_Msk // IN endpoint FIFOx transmit RAM start address */ +#define DIEPTXF_INEPTXFD_Pos (16U) +#define DIEPTXF_INEPTXFD_Msk (0xFFFFUL << DIEPTXF_INEPTXFD_Pos) // 0xFFFF0000 */ +#define DIEPTXF_INEPTXFD DIEPTXF_INEPTXFD_Msk // IN endpoint TxFIFO depth */ + +/******************** Bit definition for DOEPCTL register ********************/ +#define DOEPCTL_MPSIZ_Pos (0U) +#define DOEPCTL_MPSIZ_Msk (0x7FFUL << DOEPCTL_MPSIZ_Pos) // 0x000007FF */ +#define DOEPCTL_MPSIZ DOEPCTL_MPSIZ_Msk // Maximum packet size */ //Bit 1 */ +#define DOEPCTL_USBAEP_Pos (15U) +#define DOEPCTL_USBAEP_Msk (0x1UL << DOEPCTL_USBAEP_Pos) // 0x00008000 */ +#define DOEPCTL_USBAEP DOEPCTL_USBAEP_Msk // USB active endpoint */ +#define DOEPCTL_NAKSTS_Pos (17U) +#define DOEPCTL_NAKSTS_Msk (0x1UL << DOEPCTL_NAKSTS_Pos) // 0x00020000 */ +#define DOEPCTL_NAKSTS DOEPCTL_NAKSTS_Msk // NAK status */ +#define DOEPCTL_SD0PID_SEVNFRM_Pos (28U) +#define DOEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << DOEPCTL_SD0PID_SEVNFRM_Pos) // 0x10000000 */ +#define DOEPCTL_SD0PID_SEVNFRM DOEPCTL_SD0PID_SEVNFRM_Msk // Set DATA0 PID */ +#define DOEPCTL_SODDFRM_Pos (29U) +#define DOEPCTL_SODDFRM_Msk (0x1UL << DOEPCTL_SODDFRM_Pos) // 0x20000000 */ +#define DOEPCTL_SODDFRM DOEPCTL_SODDFRM_Msk // Set odd frame */ +#define DOEPCTL_EPTYP_Pos (18U) +#define DOEPCTL_EPTYP_Msk (0x3UL << DOEPCTL_EPTYP_Pos) // 0x000C0000 */ +#define DOEPCTL_EPTYP DOEPCTL_EPTYP_Msk // Endpoint type */ +#define DOEPCTL_EPTYP_0 (0x1UL << DOEPCTL_EPTYP_Pos) // 0x00040000 */ +#define DOEPCTL_EPTYP_1 (0x2UL << DOEPCTL_EPTYP_Pos) // 0x00080000 */ +#define DOEPCTL_SNPM_Pos (20U) +#define DOEPCTL_SNPM_Msk (0x1UL << DOEPCTL_SNPM_Pos) // 0x00100000 */ +#define DOEPCTL_SNPM DOEPCTL_SNPM_Msk // Snoop mode */ +#define DOEPCTL_STALL_Pos (21U) +#define DOEPCTL_STALL_Msk (0x1UL << DOEPCTL_STALL_Pos) // 0x00200000 */ +#define DOEPCTL_STALL DOEPCTL_STALL_Msk // STALL handshake */ +#define DOEPCTL_CNAK_Pos (26U) +#define DOEPCTL_CNAK_Msk (0x1UL << DOEPCTL_CNAK_Pos) // 0x04000000 */ +#define DOEPCTL_CNAK DOEPCTL_CNAK_Msk // Clear NAK */ +#define DOEPCTL_SNAK_Pos (27U) +#define DOEPCTL_SNAK_Msk (0x1UL << DOEPCTL_SNAK_Pos) // 0x08000000 */ +#define DOEPCTL_SNAK DOEPCTL_SNAK_Msk // Set NAK */ +#define DOEPCTL_EPDIS_Pos (30U) +#define DOEPCTL_EPDIS_Msk (0x1UL << DOEPCTL_EPDIS_Pos) // 0x40000000 */ +#define DOEPCTL_EPDIS DOEPCTL_EPDIS_Msk // Endpoint disable */ +#define DOEPCTL_EPENA_Pos (31U) +#define DOEPCTL_EPENA_Msk (0x1UL << DOEPCTL_EPENA_Pos) // 0x80000000 */ +#define DOEPCTL_EPENA DOEPCTL_EPENA_Msk // Endpoint enable */ + +/******************** Bit definition for DOEPINT register ********************/ +#define DOEPINT_XFRC_Pos (0U) +#define DOEPINT_XFRC_Msk (0x1UL << DOEPINT_XFRC_Pos) // 0x00000001 */ +#define DOEPINT_XFRC DOEPINT_XFRC_Msk // Transfer completed interrupt */ +#define DOEPINT_EPDISD_Pos (1U) +#define DOEPINT_EPDISD_Msk (0x1UL << DOEPINT_EPDISD_Pos) // 0x00000002 */ +#define DOEPINT_EPDISD DOEPINT_EPDISD_Msk // Endpoint disabled interrupt */ +#define DOEPINT_AHBERR_Pos (2U) +#define DOEPINT_AHBERR_Msk (0x1UL << DOEPINT_AHBERR_Pos) // 0x00000004 */ +#define DOEPINT_AHBERR DOEPINT_AHBERR_Msk // AHB Error (AHBErr) during an OUT transaction */ +#define DOEPINT_STUP_Pos (3U) +#define DOEPINT_STUP_Msk (0x1UL << DOEPINT_STUP_Pos) // 0x00000008 */ +#define DOEPINT_STUP DOEPINT_STUP_Msk // SETUP phase done */ +#define DOEPINT_OTEPDIS_Pos (4U) +#define DOEPINT_OTEPDIS_Msk (0x1UL << DOEPINT_OTEPDIS_Pos) // 0x00000010 */ +#define DOEPINT_OTEPDIS DOEPINT_OTEPDIS_Msk // OUT token received when endpoint disabled */ +#define DOEPINT_OTEPSPR_Pos (5U) +#define DOEPINT_OTEPSPR_Msk (0x1UL << DOEPINT_OTEPSPR_Pos) // 0x00000020 */ +#define DOEPINT_OTEPSPR DOEPINT_OTEPSPR_Msk // Status Phase Received For Control Write */ +#define DOEPINT_B2BSTUP_Pos (6U) +#define DOEPINT_B2BSTUP_Msk (0x1UL << DOEPINT_B2BSTUP_Pos) // 0x00000040 */ +#define DOEPINT_B2BSTUP DOEPINT_B2BSTUP_Msk // Back-to-back SETUP packets received */ +#define DOEPINT_OUTPKTERR_Pos (8U) +#define DOEPINT_OUTPKTERR_Msk (0x1UL << DOEPINT_OUTPKTERR_Pos) // 0x00000100 */ +#define DOEPINT_OUTPKTERR DOEPINT_OUTPKTERR_Msk // OUT packet error */ +#define DOEPINT_NAK_Pos (13U) +#define DOEPINT_NAK_Msk (0x1UL << DOEPINT_NAK_Pos) // 0x00002000 */ +#define DOEPINT_NAK DOEPINT_NAK_Msk // NAK Packet is transmitted by the device */ +#define DOEPINT_NYET_Pos (14U) +#define DOEPINT_NYET_Msk (0x1UL << DOEPINT_NYET_Pos) // 0x00004000 */ +#define DOEPINT_NYET DOEPINT_NYET_Msk // NYET interrupt */ +#define DOEPINT_STPKTRX_Pos (15U) +#define DOEPINT_STPKTRX_Msk (0x1UL << DOEPINT_STPKTRX_Pos) // 0x00008000 */ +#define DOEPINT_STPKTRX DOEPINT_STPKTRX_Msk // Setup Packet Received */ + +/******************** Bit definition for DOEPTSIZ register ********************/ +#define DOEPTSIZ_XFRSIZ_Pos (0U) +#define DOEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << DOEPTSIZ_XFRSIZ_Pos) // 0x0007FFFF */ +#define DOEPTSIZ_XFRSIZ DOEPTSIZ_XFRSIZ_Msk // Transfer size */ +#define DOEPTSIZ_PKTCNT_Pos (19U) +#define DOEPTSIZ_PKTCNT_Msk (0x3FFUL << DOEPTSIZ_PKTCNT_Pos) // 0x1FF80000 */ +#define DOEPTSIZ_PKTCNT DOEPTSIZ_PKTCNT_Msk // Packet count */ + +#define DOEPTSIZ_STUPCNT_Pos (29U) +#define DOEPTSIZ_STUPCNT_Msk (0x3UL << DOEPTSIZ_STUPCNT_Pos) // 0x60000000 */ +#define DOEPTSIZ_STUPCNT DOEPTSIZ_STUPCNT_Msk // SETUP packet count */ +#define DOEPTSIZ_STUPCNT_0 (0x1UL << DOEPTSIZ_STUPCNT_Pos) // 0x20000000 */ +#define DOEPTSIZ_STUPCNT_1 (0x2UL << DOEPTSIZ_STUPCNT_Pos) // 0x40000000 */ + +/******************** Bit definition for PCGCTL register ********************/ +#define PCGCTL_IF_DEV_MODE TU_BIT(31) +#define PCGCTL_P2HD_PRT_SPD_MASK (0x3ul << 29) +#define PCGCTL_P2HD_PRT_SPD_SHIFT 29 +#define PCGCTL_P2HD_DEV_ENUM_SPD_MASK (0x3ul << 27) +#define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT 27 +#define PCGCTL_MAC_DEV_ADDR_MASK (0x7ful << 20) +#define PCGCTL_MAC_DEV_ADDR_SHIFT 20 +#define PCGCTL_MAX_TERMSEL TU_BIT(19) +#define PCGCTL_MAX_XCVRSELECT_MASK (0x3ul << 17) +#define PCGCTL_MAX_XCVRSELECT_SHIFT 17 +#define PCGCTL_PORT_POWER TU_BIT(16) +#define PCGCTL_PRT_CLK_SEL_MASK (0x3ul << 14) +#define PCGCTL_PRT_CLK_SEL_SHIFT 14 +#define PCGCTL_ESS_REG_RESTORED TU_BIT(13) +#define PCGCTL_EXTND_HIBER_SWITCH TU_BIT(12) +#define PCGCTL_EXTND_HIBER_PWRCLMP TU_BIT(11) +#define PCGCTL_ENBL_EXTND_HIBER TU_BIT(10) +#define PCGCTL_RESTOREMODE TU_BIT(9) +#define PCGCTL_RESETAFTSUSP TU_BIT(8) +#define PCGCTL_DEEP_SLEEP TU_BIT(7) +#define PCGCTL_PHY_IN_SLEEP TU_BIT(6) +#define PCGCTL_ENBL_SLEEP_GATING TU_BIT(5) +#define PCGCTL_RSTPDWNMODULE TU_BIT(3) +#define PCGCTL_PWRCLMP TU_BIT(2) +#define PCGCTL_GATEHCLK TU_BIT(1) +#define PCGCTL_STOPPCLK TU_BIT(0) + +#define PCGCTL1_TIMER (0x3ul << 1) +#define PCGCTL1_GATEEN TU_BIT(0) + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_xmc.h b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_xmc.h new file mode 100644 index 00000000..63419abf --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_xmc.h @@ -0,0 +1,88 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Rafael Silva (@perigoso) + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _DWC2_XMC_H_ +#define _DWC2_XMC_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "xmc_device.h" + +#define DWC2_EP_MAX 7 + +static const dwc2_controller_t _dwc2_controller[] = +{ + // Note: XMC has some custom control registers before DWC registers + { .reg_base = USB0_BASE, .irqnum = USB0_0_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 2048 } +}; + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_enable(uint8_t rhport) +{ + NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum); +} + +TU_ATTR_ALWAYS_INLINE +static inline void dwc2_dcd_int_disable (uint8_t rhport) +{ + NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum); +} + +static inline void dwc2_remote_wakeup_delay(void) +{ + // try to delay for 1 ms +// uint32_t count = SystemCoreClock / 1000; +// while ( count-- ) __NOP(); +} + +// MCU specific PHY init, called BEFORE core reset +static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // Enable PHY + //USB->ROUTE = USB_ROUTE_PHYPEN; +} + +// MCU specific PHY update, it is called AFTER init() and core reset +static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) +{ + (void) dwc2; + (void) hs_phy_type; + + // XMC Manual: turn around must be 5 (reset & default value) + // dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (5u << GUSBCFG_TRDT_Pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal.h new file mode 100644 index 00000000..9d11866d --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/osal/osal.h @@ -0,0 +1,89 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_OSAL_H_ +#define _TUSB_OSAL_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "common/tusb_common.h" + +// Return immediately +#define OSAL_TIMEOUT_NOTIMEOUT (0) +// Default timeout +#define OSAL_TIMEOUT_NORMAL (10) +// Wait forever +#define OSAL_TIMEOUT_WAIT_FOREVER (UINT32_MAX) + +#define OSAL_TIMEOUT_CONTROL_XFER OSAL_TIMEOUT_WAIT_FOREVER + +typedef void (*osal_task_func_t)( void * ); + +#if CFG_TUSB_OS == OPT_OS_NONE + #include "osal_none.h" +#elif CFG_TUSB_OS == OPT_OS_FREERTOS + #include "osal_freertos.h" +#elif CFG_TUSB_OS == OPT_OS_MYNEWT + #include "osal_mynewt.h" +#elif CFG_TUSB_OS == OPT_OS_PICO + #include "osal_pico.h" +#elif CFG_TUSB_OS == OPT_OS_RTTHREAD + #include "osal_rtthread.h" +#elif CFG_TUSB_OS == OPT_OS_RTX4 + #include "osal_rtx4.h" +#elif CFG_TUSB_OS == OPT_OS_CUSTOM + #include "tusb_os_custom.h" // implemented by application +#else + #error OS is not supported yet +#endif + +//--------------------------------------------------------------------+ +// OSAL Porting API +// Should be implemented as static inline function in osal_port.h header +/* + osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef); + bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr); + bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec); + void osal_semaphore_reset(osal_semaphore_t sem_hdl); // TODO removed + + osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef); + bool osal_mutex_lock (osal_mutex_t sem_hdl, uint32_t msec); + bool osal_mutex_unlock(osal_mutex_t mutex_hdl); + + osal_queue_t osal_queue_create(osal_queue_def_t* qdef); + bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec); + bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr); + bool osal_queue_empty(osal_queue_t qhdl); +*/ +//--------------------------------------------------------------------+ + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_OSAL_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_freertos.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_freertos.h new file mode 100644 index 00000000..52db336f --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_freertos.h @@ -0,0 +1,187 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_OSAL_FREERTOS_H_ +#define _TUSB_OSAL_FREERTOS_H_ + +// FreeRTOS Headers +#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,FreeRTOS.h) +#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,semphr.h) +#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,queue.h) +#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,task.h) + +#ifdef __cplusplus +extern "C" { +#endif + +TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec) +{ + if (msec == OSAL_TIMEOUT_WAIT_FOREVER) return portMAX_DELAY; + if (msec == 0) return 0; + + uint32_t ticks = pdMS_TO_TICKS(msec); + + // configTICK_RATE_HZ is less than 1000 and 1 tick > 1 ms + // we still need to delay at least 1 tick + if (ticks == 0) ticks =1 ; + + return ticks; +} + +//--------------------------------------------------------------------+ +// TASK API +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) +{ + vTaskDelay( pdMS_TO_TICKS(msec) ); +} + +//--------------------------------------------------------------------+ +// Semaphore API +//--------------------------------------------------------------------+ +typedef StaticSemaphore_t osal_semaphore_def_t; +typedef SemaphoreHandle_t osal_semaphore_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) +{ + return xSemaphoreCreateBinaryStatic(semdef); +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) +{ + if ( !in_isr ) + { + return xSemaphoreGive(sem_hdl) != 0; + } + else + { + BaseType_t xHigherPriorityTaskWoken; + BaseType_t res = xSemaphoreGiveFromISR(sem_hdl, &xHigherPriorityTaskWoken); + +#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3 + // not needed after https://github.com/espressif/esp-idf/commit/c5fd79547ac9b7bae06fa660e9f814d18d3390b7 + if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR(); +#else + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +#endif + + return res != 0; + } +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) +{ + return xSemaphoreTake(sem_hdl, _osal_ms2tick(msec)); +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) +{ + xQueueReset(sem_hdl); +} + +//--------------------------------------------------------------------+ +// MUTEX API (priority inheritance) +//--------------------------------------------------------------------+ +typedef StaticSemaphore_t osal_mutex_def_t; +typedef SemaphoreHandle_t osal_mutex_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) +{ + return xSemaphoreCreateMutexStatic(mdef); +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) +{ + return osal_semaphore_wait(mutex_hdl, msec); +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) +{ + return xSemaphoreGive(mutex_hdl); +} + +//--------------------------------------------------------------------+ +// QUEUE API +//--------------------------------------------------------------------+ + +// _int_set is not used with an RTOS +#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ + static _type _name##_##buf[_depth];\ + osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf }; + +typedef struct +{ + uint16_t depth; + uint16_t item_sz; + void* buf; + + StaticQueue_t sq; +}osal_queue_def_t; + +typedef QueueHandle_t osal_queue_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) +{ + return xQueueCreateStatic(qdef->depth, qdef->item_sz, (uint8_t*) qdef->buf, &qdef->sq); +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) +{ + return xQueueReceive(qhdl, data, _osal_ms2tick(msec)); +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) +{ + if ( !in_isr ) + { + return xQueueSendToBack(qhdl, data, OSAL_TIMEOUT_WAIT_FOREVER) != 0; + } + else + { + BaseType_t xHigherPriorityTaskWoken; + BaseType_t res = xQueueSendToBackFromISR(qhdl, data, &xHigherPriorityTaskWoken); + +#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3 + // not needed after https://github.com/espressif/esp-idf/commit/c5fd79547ac9b7bae06fa660e9f814d18d3390b7 + if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR(); +#else + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +#endif + + return res != 0; + } +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) +{ + return uxQueueMessagesWaiting(qhdl) == 0; +} + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_mynewt.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_mynewt.h new file mode 100644 index 00000000..b8ea2087 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_mynewt.h @@ -0,0 +1,176 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef OSAL_MYNEWT_H_ +#define OSAL_MYNEWT_H_ + +#include "os/os.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// TASK API +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) +{ + os_time_delay( os_time_ms_to_ticks32(msec) ); +} + +//--------------------------------------------------------------------+ +// Semaphore API +//--------------------------------------------------------------------+ +typedef struct os_sem osal_semaphore_def_t; +typedef struct os_sem* osal_semaphore_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) +{ + return (os_sem_init(semdef, 0) == OS_OK) ? (osal_semaphore_t) semdef : NULL; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) +{ + (void) in_isr; + return os_sem_release(sem_hdl) == OS_OK; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) +{ + uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? OS_TIMEOUT_NEVER : os_time_ms_to_ticks32(msec); + return os_sem_pend(sem_hdl, ticks) == OS_OK; +} + +static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) +{ + // TODO implement later +} + +//--------------------------------------------------------------------+ +// MUTEX API (priority inheritance) +//--------------------------------------------------------------------+ +typedef struct os_mutex osal_mutex_def_t; +typedef struct os_mutex* osal_mutex_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) +{ + return (os_mutex_init(mdef) == OS_OK) ? (osal_mutex_t) mdef : NULL; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) +{ + uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? OS_TIMEOUT_NEVER : os_time_ms_to_ticks32(msec); + return os_mutex_pend(mutex_hdl, ticks) == OS_OK; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) +{ + return os_mutex_release(mutex_hdl) == OS_OK; +} + +//--------------------------------------------------------------------+ +// QUEUE API +//--------------------------------------------------------------------+ + +// role device/host is used by OS NONE for mutex (disable usb isr) only +#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ + static _type _name##_##buf[_depth];\ + static struct os_event _name##_##evbuf[_depth];\ + osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf, .evbuf = _name##_##evbuf};\ + +typedef struct +{ + uint16_t depth; + uint16_t item_sz; + void* buf; + void* evbuf; + + struct os_mempool mpool; + struct os_mempool epool; + + struct os_eventq evq; +}osal_queue_def_t; + +typedef osal_queue_def_t* osal_queue_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) +{ + if ( OS_OK != os_mempool_init(&qdef->mpool, qdef->depth, qdef->item_sz, qdef->buf, "usbd queue") ) return NULL; + if ( OS_OK != os_mempool_init(&qdef->epool, qdef->depth, sizeof(struct os_event), qdef->evbuf, "usbd evqueue") ) return NULL; + + os_eventq_init(&qdef->evq); + return (osal_queue_t) qdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) +{ + (void) msec; // os_eventq_get() does not take timeout, always behave as msec = WAIT_FOREVER + + struct os_event* ev; + ev = os_eventq_get(&qhdl->evq); + + memcpy(data, ev->ev_arg, qhdl->item_sz); // copy message + os_memblock_put(&qhdl->mpool, ev->ev_arg); // put back mem block + os_memblock_put(&qhdl->epool, ev); // put back ev block + + return true; +} + +static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) +{ + (void) in_isr; + + // get a block from mem pool for data + void* ptr = os_memblock_get(&qhdl->mpool); + if (!ptr) return false; + memcpy(ptr, data, qhdl->item_sz); + + // get a block from event pool to put into queue + struct os_event* ev = (struct os_event*) os_memblock_get(&qhdl->epool); + if (!ev) + { + os_memblock_put(&qhdl->mpool, ptr); + return false; + } + tu_memclr(ev, sizeof(struct os_event)); + ev->ev_arg = ptr; + + os_eventq_put(&qhdl->evq, ev); + + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) +{ + return STAILQ_EMPTY(&qhdl->evq.evq_list); +} + + +#ifdef __cplusplus + } +#endif + +#endif /* OSAL_MYNEWT_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_none.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_none.h new file mode 100644 index 00000000..9c80e454 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_none.h @@ -0,0 +1,181 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_OSAL_NONE_H_ +#define _TUSB_OSAL_NONE_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// TASK API +//--------------------------------------------------------------------+ + + +//--------------------------------------------------------------------+ +// Binary Semaphore API +//--------------------------------------------------------------------+ +typedef struct +{ + volatile uint16_t count; +}osal_semaphore_def_t; + +typedef osal_semaphore_def_t* osal_semaphore_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) +{ + semdef->count = 0; + return semdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) +{ + (void) in_isr; + sem_hdl->count++; + return true; +} + +// TODO blocking for now +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) +{ + (void) msec; + + while (sem_hdl->count == 0) { } + sem_hdl->count--; + + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) +{ + sem_hdl->count = 0; +} + +//--------------------------------------------------------------------+ +// MUTEX API +// Within tinyusb, mutex is never used in ISR context +//--------------------------------------------------------------------+ +typedef osal_semaphore_def_t osal_mutex_def_t; +typedef osal_semaphore_t osal_mutex_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) +{ + mdef->count = 1; + return mdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) +{ + return osal_semaphore_wait(mutex_hdl, msec); +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) +{ + return osal_semaphore_post(mutex_hdl, false); +} + +//--------------------------------------------------------------------+ +// QUEUE API +//--------------------------------------------------------------------+ +#include "common/tusb_fifo.h" + +typedef struct +{ + void (*interrupt_set)(bool); + tu_fifo_t ff; +}osal_queue_def_t; + +typedef osal_queue_def_t* osal_queue_t; + +// _int_set is used as mutex in OS NONE (disable/enable USB ISR) +#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ + uint8_t _name##_buf[_depth*sizeof(_type)]; \ + osal_queue_def_t _name = { \ + .interrupt_set = _int_set, \ + .ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \ + } + +// lock queue by disable USB interrupt +TU_ATTR_ALWAYS_INLINE static inline void _osal_q_lock(osal_queue_t qhdl) +{ + // disable dcd/hcd interrupt + qhdl->interrupt_set(false); +} + +// unlock queue +TU_ATTR_ALWAYS_INLINE static inline void _osal_q_unlock(osal_queue_t qhdl) +{ + // enable dcd/hcd interrupt + qhdl->interrupt_set(true); +} + +TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) +{ + tu_fifo_clear(&qdef->ff); + return (osal_queue_t) qdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) +{ + (void) msec; // not used, always behave as msec = 0 + + _osal_q_lock(qhdl); + bool success = tu_fifo_read(&qhdl->ff, data); + _osal_q_unlock(qhdl); + + return success; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) +{ + if (!in_isr) { + _osal_q_lock(qhdl); + } + + bool success = tu_fifo_write(&qhdl->ff, data); + + if (!in_isr) { + _osal_q_unlock(qhdl); + } + + TU_ASSERT(success); + + return success; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) +{ + // Skip queue lock/unlock since this function is primarily called + // with interrupt disabled before going into low power mode + return tu_fifo_empty(&qhdl->ff); +} + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_OSAL_NONE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_pico.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_pico.h new file mode 100644 index 00000000..8b428d64 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_pico.h @@ -0,0 +1,184 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_OSAL_PICO_H_ +#define _TUSB_OSAL_PICO_H_ + +#include "pico/time.h" +#include "pico/sem.h" +#include "pico/mutex.h" +#include "pico/critical_section.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// TASK API +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) +{ + sleep_ms(msec); +} + +//--------------------------------------------------------------------+ +// Binary Semaphore API +//--------------------------------------------------------------------+ +typedef struct semaphore osal_semaphore_def_t, *osal_semaphore_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) +{ + sem_init(semdef, 0, 255); + return semdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) +{ + (void) in_isr; + sem_release(sem_hdl); + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) +{ + return sem_acquire_timeout_ms(sem_hdl, msec); +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) +{ + sem_reset(sem_hdl, 0); +} + +//--------------------------------------------------------------------+ +// MUTEX API +// Within tinyusb, mutex is never used in ISR context +//--------------------------------------------------------------------+ +typedef struct mutex osal_mutex_def_t, *osal_mutex_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) +{ + mutex_init(mdef); + return mdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) +{ + return mutex_enter_timeout_ms(mutex_hdl, msec); +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) +{ + mutex_exit(mutex_hdl); + return true; +} + +//--------------------------------------------------------------------+ +// QUEUE API +//--------------------------------------------------------------------+ +#include "common/tusb_fifo.h" + +typedef struct +{ + tu_fifo_t ff; + struct critical_section critsec; // osal_queue may be used in IRQs, so need critical section +} osal_queue_def_t; + +typedef osal_queue_def_t* osal_queue_t; + +// role device/host is used by OS NONE for mutex (disable usb isr) only +#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ + uint8_t _name##_buf[_depth*sizeof(_type)]; \ + osal_queue_def_t _name = { \ + .ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \ + } + +// lock queue by disable USB interrupt +TU_ATTR_ALWAYS_INLINE static inline void _osal_q_lock(osal_queue_t qhdl) +{ + critical_section_enter_blocking(&qhdl->critsec); +} + +// unlock queue +TU_ATTR_ALWAYS_INLINE static inline void _osal_q_unlock(osal_queue_t qhdl) +{ + critical_section_exit(&qhdl->critsec); +} + +TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) +{ + critical_section_init(&qdef->critsec); + tu_fifo_clear(&qdef->ff); + return (osal_queue_t) qdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) +{ + (void) msec; // not used, always behave as msec = 0 + + // TODO: revisit... docs say that mutexes are never used from IRQ context, + // however osal_queue_recieve may be. therefore my assumption is that + // the fifo mutex is not populated for queues used from an IRQ context + //assert(!qhdl->ff.mutex); + + _osal_q_lock(qhdl); + bool success = tu_fifo_read(&qhdl->ff, data); + _osal_q_unlock(qhdl); + + return success; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) +{ + // TODO: revisit... docs say that mutexes are never used from IRQ context, + // however osal_queue_recieve may be. therefore my assumption is that + // the fifo mutex is not populated for queues used from an IRQ context + //assert(!qhdl->ff.mutex); + (void) in_isr; + + _osal_q_lock(qhdl); + bool success = tu_fifo_write(&qhdl->ff, data); + _osal_q_unlock(qhdl); + + TU_ASSERT(success); + + return success; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) +{ + // TODO: revisit; whether this is true or not currently, tu_fifo_empty is a single + // volatile read. + + // Skip queue lock/unlock since this function is primarily called + // with interrupt disabled before going into low power mode + return tu_fifo_empty(&qhdl->ff); +} + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_OSAL_PICO_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtthread.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtthread.h new file mode 100644 index 00000000..f8452bfb --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtthread.h @@ -0,0 +1,132 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 tfx2001 (2479727366@qq.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_OSAL_RTTHREAD_H_ +#define _TUSB_OSAL_RTTHREAD_H_ + +// RT-Thread Headers +#include "rtthread.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------+ +// TASK API +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) { + rt_thread_mdelay(msec); +} + +//--------------------------------------------------------------------+ +// Semaphore API +//--------------------------------------------------------------------+ +typedef struct rt_semaphore osal_semaphore_def_t; +typedef rt_sem_t osal_semaphore_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t +osal_semaphore_create(osal_semaphore_def_t *semdef) { + rt_sem_init(semdef, "tusb", 0, RT_IPC_FLAG_PRIO); + return semdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) { + (void) in_isr; + return rt_sem_release(sem_hdl) == RT_EOK; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) { + return rt_sem_take(sem_hdl, rt_tick_from_millisecond((rt_int32_t) msec)) == RT_EOK; +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) { + // TODO: implement +} + +//--------------------------------------------------------------------+ +// MUTEX API (priority inheritance) +//--------------------------------------------------------------------+ +typedef struct rt_mutex osal_mutex_def_t; +typedef rt_mutex_t osal_mutex_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) { + rt_mutex_init(mdef, "tusb", RT_IPC_FLAG_PRIO); + return mdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) { + return rt_mutex_take(mutex_hdl, rt_tick_from_millisecond((rt_int32_t) msec)) == RT_EOK; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) { + return rt_mutex_release(mutex_hdl) == RT_EOK; +} + +//--------------------------------------------------------------------+ +// QUEUE API +//--------------------------------------------------------------------+ + +// role device/host is used by OS NONE for mutex (disable usb isr) only +#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ + static _type _name##_##buf[_depth]; \ + osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf }; + +typedef struct { + uint16_t depth; + uint16_t item_sz; + void *buf; + + struct rt_messagequeue sq; +} osal_queue_def_t; + +typedef rt_mq_t osal_queue_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t *qdef) { + rt_mq_init(&(qdef->sq), "tusb", qdef->buf, qdef->item_sz, + qdef->item_sz * qdef->depth, RT_IPC_FLAG_PRIO); + return &(qdef->sq); +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void *data, uint32_t msec) { + + rt_tick_t tick = rt_tick_from_millisecond((rt_int32_t) msec); + return rt_mq_recv(qhdl, data, qhdl->msg_size, tick) == RT_EOK; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const *data, bool in_isr) { + (void) in_isr; + return rt_mq_send(qhdl, (void *)data, qhdl->msg_size) == RT_EOK; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) { + return (qhdl->entry) == 0; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_OSAL_RTTHREAD_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtx4.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtx4.h new file mode 100644 index 00000000..dea1c12c --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtx4.h @@ -0,0 +1,170 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Tian Yunhao (t123yh) + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_OSAL_RTX4_H_ +#define _TUSB_OSAL_RTX4_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------+ +// TASK API +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) +{ + uint16_t hi = msec >> 16; + uint16_t lo = msec; + while (hi--) { + os_dly_wait(0xFFFE); + } + os_dly_wait(lo); +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t msec2wait(uint32_t msec) { + if (msec == OSAL_TIMEOUT_WAIT_FOREVER) + return 0xFFFF; + else if (msec >= 0xFFFE) + return 0xFFFE; + else + return msec; +} + +//--------------------------------------------------------------------+ +// Semaphore API +//--------------------------------------------------------------------+ +typedef OS_SEM osal_semaphore_def_t; +typedef OS_ID osal_semaphore_t; + +TU_ATTR_ALWAYS_INLINE static inline OS_ID osal_semaphore_create(osal_semaphore_def_t* semdef) { + os_sem_init(semdef, 0); + return semdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) { + if ( !in_isr ) { + os_sem_send(sem_hdl); + } else { + isr_sem_send(sem_hdl); + } + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) { + return os_sem_wait(sem_hdl, msec2wait(msec)) != OS_R_TMO; +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) { + // TODO: implement +} + +//--------------------------------------------------------------------+ +// MUTEX API (priority inheritance) +//--------------------------------------------------------------------+ +typedef OS_MUT osal_mutex_def_t; +typedef OS_ID osal_mutex_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) +{ + os_mut_init(mdef); + return mdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) +{ + return os_mut_wait(mutex_hdl, msec2wait(msec)) != OS_R_TMO; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) +{ + return os_mut_release(mutex_hdl) == OS_R_OK; +} + +//--------------------------------------------------------------------+ +// QUEUE API +//--------------------------------------------------------------------+ + +// role device/host is used by OS NONE for mutex (disable usb isr) only +#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ + os_mbx_declare(_name##__mbox, _depth); \ + _declare_box(_name##__pool, sizeof(_type), _depth); \ + osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .pool = _name##__pool, .mbox = _name##__mbox }; + + +typedef struct +{ + uint16_t depth; + uint16_t item_sz; + U32* pool; + U32* mbox; +}osal_queue_def_t; + +typedef osal_queue_def_t* osal_queue_t; + +TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) +{ + os_mbx_init(qdef->mbox, (qdef->depth + 4) * 4); + _init_box(qdef->pool, ((qdef->item_sz+3)/4)*(qdef->depth) + 3, qdef->item_sz); + return qdef; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) +{ + void* buf; + os_mbx_wait(qhdl->mbox, &buf, msec2wait(msec)); + memcpy(data, buf, qhdl->item_sz); + _free_box(qhdl->pool, buf); + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) +{ + void* buf = _alloc_box(qhdl->pool); + memcpy(buf, data, qhdl->item_sz); + if ( !in_isr ) + { + os_mbx_send(qhdl->mbox, buf, 0xFFFF); + } + else + { + isr_mbx_send(qhdl->mbox, buf); + } + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) +{ + return os_mbx_check(qhdl->mbox) == qhdl->depth; +} + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c b/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c new file mode 100644 index 00000000..f17176ae --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c @@ -0,0 +1,1162 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Nathan Conrad + * + * Portions: + * Copyright (c) 2016 STMicroelectronics + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/********************************************** + * This driver has been tested with the following MCUs: + * - F070, F072, L053, F042F6 + * + * It also should work with minimal changes for any ST MCU with an "USB A"/"PCD"/"HCD" peripheral. This + * covers: + * + * F04x, F072, F078, 070x6/B 1024 byte buffer + * F102, F103 512 byte buffer; no internal D+ pull-up (maybe many more changes?) + * F302xB/C, F303xB/C, F373 512 byte buffer; no internal D+ pull-up + * F302x6/8, F302xD/E2, F303xD/E 1024 byte buffer; no internal D+ pull-up + * L0x2, L0x3 1024 byte buffer + * L1 512 byte buffer + * L4x2, L4x3 1024 byte buffer + * + * To use this driver, you must: + * - If you are using a device with crystal-less USB, set up the clock recovery system (CRS) + * - Remap pins to be D+/D- on devices that they are shared (for example: F042Fx) + * - This is different to the normal "alternate function" GPIO interface, needs to go through SYSCFG->CFGRx register + * - Enable USB clock; Perhaps use __HAL_RCC_USB_CLK_ENABLE(); + * - (Optionally configure GPIO HAL to tell it the USB driver is using the USB pins) + * - call tusb_init(); + * - periodically call tusb_task(); + * + * Assumptions of the driver: + * - You are not using CAN (it must share the packet buffer) + * - APB clock is >= 10 MHz + * - On some boards, series resistors are required, but not on others. + * - On some boards, D+ pull up resistor (1.5kohm) is required, but not on others. + * - You don't have long-running interrupts; some USB packets must be quickly responded to. + * - You have the ST CMSIS library linked into the project. HAL is not used. + * + * Current driver limitations (i.e., a list of features for you to add): + * - STALL handled, but not tested. + * - Does it work? No clue. + * - All EP BTABLE buffers are created based on max packet size of first EP opened with that address. + * - No isochronous endpoints + * - Endpoint index is the ID of the endpoint + * - This means that priority is given to endpoints with lower ID numbers + * - Code is mixing up EP IX with EP ID. Everywhere. + * - Packet buffer memory is copied in the interrupt. + * - This is better for performance, but means interrupts are disabled for longer + * - DMA may be the best choice, but it could also be pushed to the USBD task. + * - No double-buffering + * - No DMA + * - Minimal error handling + * - Perhaps error interrupts should be reported to the stack, or cause a device reset? + * - Assumes a single USB peripheral; I think that no hardware has multiple so this is fine. + * - Add a callback for enabling/disabling the D+ PU on devices without an internal PU. + * - F3 models use three separate interrupts. I think we could only use the LP interrupt for + * everything? However, the interrupts are configurable so the DisableInt and EnableInt + * below functions could be adjusting the wrong interrupts (if they had been reconfigured) + * - LPM is not used correctly, or at all? + * + * USB documentation and Reference implementations + * - STM32 Reference manuals + * - STM32 USB Hardware Guidelines AN4879 + * + * - STM32 HAL (much of this driver is based on this) + * - libopencm3/lib/stm32/common/st_usbfs_core.c + * - Keil USB Device http://www.keil.com/pack/doc/mw/USB/html/group__usbd.html + * + * - YouTube OpenTechLab 011; https://www.youtube.com/watch?v=4FOkJLp_PUw + * + * Advantages over HAL driver: + * - Tiny (saves RAM, assumes a single USB peripheral) + * + * Notes: + * - The buffer table is allocated as endpoints are opened. The allocation is only + * cleared when the device is reset. This may be bad if the USB device needs + * to be reconfigured. + */ + +#include "tusb_option.h" + +#if defined(STM32F102x6) || defined(STM32F102xB) || \ + defined(STM32F103x6) || defined(STM32F103xB) || \ + defined(STM32F103xE) || defined(STM32F103xG) +#define STM32F1_FSDEV +#endif + +#if CFG_TUD_ENABLED && \ + ( TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32F3, OPT_MCU_STM32L0, OPT_MCU_STM32L1, OPT_MCU_STM32G4, OPT_MCU_STM32WB) || \ + (TU_CHECK_MCU(OPT_MCU_STM32F1) && defined(STM32F1_FSDEV)) \ + ) + +// In order to reduce the dependance on HAL, we undefine this. +// Some definitions are copied to our private include file. +#undef USE_HAL_DRIVER + +#include "device/dcd.h" +#include "dcd_stm32_fsdev_pvt_st.h" + + +/***************************************************** + * Configuration + *****************************************************/ + +// HW supports max of 8 bidirectional endpoints, but this can be reduced to save RAM +// (8u here would mean 8 IN and 8 OUT) +#ifndef MAX_EP_COUNT +# define MAX_EP_COUNT 8U +#endif + +// If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it +// Both of these MUST be a multiple of 2, and are in byte units. +#ifndef DCD_STM32_BTABLE_BASE +# define DCD_STM32_BTABLE_BASE 0U +#endif + +#ifndef DCD_STM32_BTABLE_LENGTH +# define DCD_STM32_BTABLE_LENGTH (PMA_LENGTH - DCD_STM32_BTABLE_BASE) +#endif + +// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval) +// We disable SOF for now until needed later on +#ifndef USE_SOF +# define USE_SOF 0 +#endif + +/*************************************************** + * Checks, structs, defines, function definitions, etc. + */ + +TU_VERIFY_STATIC((MAX_EP_COUNT) <= STFSDEV_EP_COUNT, "Only 8 endpoints supported on the hardware"); + +TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_LENGTH))<=(PMA_LENGTH), + "BTABLE does not fit in PMA RAM"); + +TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligned to 8 bytes"); + +// One of these for every EP IN & OUT, uses a bit of RAM.... +typedef struct +{ + uint8_t * buffer; + // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API + uint16_t total_len; + uint16_t queued_len; + uint16_t pma_ptr; + uint8_t max_packet_size; + uint8_t pma_alloc_size; +} xfer_ctl_t; + +static xfer_ctl_t xfer_status[MAX_EP_COUNT][2]; + +static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t epnum, uint32_t dir) +{ + return &xfer_status[epnum][dir]; +} + +static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6]; + +static uint8_t remoteWakeCountdown; // When wake is requested + +// into the stack. +static void dcd_handle_bus_reset(void); +static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix); +static void dcd_ep_ctr_handler(void); + +// PMA allocation/access +static uint8_t open_ep_count; +static uint16_t ep_buf_ptr; ///< Points to first free memory location +static void dcd_pma_alloc_reset(void); +static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length); +static void dcd_pma_free(uint8_t ep_addr); +static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes); +static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes); + +//static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes); +//static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes); + +// Using a function due to better type checks +// This seems better than having to do type casts everywhere else +static inline void reg16_clear_bits(__IO uint16_t *reg, uint16_t mask) { + *reg = (uint16_t)(*reg & ~mask); +} + +// Bits in ISTR are cleared upon writing 0 +static inline void clear_istr_bits(uint16_t mask) { + USB->ISTR = ~mask; +} + +void dcd_init (uint8_t rhport) +{ + /* Clocks should already be enabled */ + /* Use __HAL_RCC_USB_CLK_ENABLE(); to enable the clocks before calling this function */ + + /* The RM mentions to use a special ordering of PDWN and FRES, but this isn't done in HAL. + * Here, the RM is followed. */ + + for(uint32_t i = 0; i<200; i++) // should be a few us + { + asm("NOP"); + } + // Perform USB peripheral reset + USB->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; + for(uint32_t i = 0; i<200; i++) // should be a few us + { + asm("NOP"); + } + reg16_clear_bits(&USB->CNTR, USB_CNTR_PDWN);// Remove powerdown + // Wait startup time, for F042 and F070, this is <= 1 us. + for(uint32_t i = 0; i<200; i++) // should be a few us + { + asm("NOP"); + } + USB->CNTR = 0; // Enable USB + + USB->BTABLE = DCD_STM32_BTABLE_BASE; + + USB->ISTR = 0; // Clear pending interrupts + + // Reset endpoints to disabled + for(uint32_t i=0; iCNTR |= USB_CNTR_RESETM | (USE_SOF ? USB_CNTR_SOFM : 0) | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; + dcd_handle_bus_reset(); + + // Enable pull-up if supported + if ( dcd_connect ) dcd_connect(rhport); +} + +// Define only on MCU with internal pull-up. BSP can define on MCU without internal PU. +#if defined(USB_BCDR_DPPU) + +// Disable internal D+ PU +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; + USB->BCDR &= ~(USB_BCDR_DPPU); +} + +// Enable internal D+ PU +void dcd_connect(uint8_t rhport) +{ + (void) rhport; + USB->BCDR |= USB_BCDR_DPPU; +} + +#elif defined(SYSCFG_PMC_USB_PU) // works e.g. on STM32L151 +// Disable internal D+ PU +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; + SYSCFG->PMC &= ~(SYSCFG_PMC_USB_PU); +} + +// Enable internal D+ PU +void dcd_connect(uint8_t rhport) +{ + (void) rhport; + SYSCFG->PMC |= SYSCFG_PMC_USB_PU; +} +#endif + +void dcd_sof_enable(uint8_t rhport, bool en) +{ + (void) rhport; + (void) en; + + // TODO implement later +} + +// Enable device interrupt +void dcd_int_enable (uint8_t rhport) +{ + (void)rhport; + // Member here forces write to RAM before allowing ISR to execute + __DSB(); + __ISB(); +#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 + NVIC_EnableIRQ(USB_IRQn); + +#elif CFG_TUSB_MCU == OPT_MCU_STM32L1 + NVIC_EnableIRQ(USB_LP_IRQn); + +#elif CFG_TUSB_MCU == OPT_MCU_STM32F3 + // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from + // shared USB/CAN IRQs to separate CAN and USB IRQs. + // This dynamically checks if this remap is active to enable the right IRQs. + #ifdef SYSCFG_CFGR1_USB_IT_RMP + if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) + { + NVIC_EnableIRQ(USB_HP_IRQn); + NVIC_EnableIRQ(USB_LP_IRQn); + NVIC_EnableIRQ(USBWakeUp_RMP_IRQn); + } + else + #endif + { + NVIC_EnableIRQ(USB_HP_CAN_TX_IRQn); + NVIC_EnableIRQ(USB_LP_CAN_RX0_IRQn); + NVIC_EnableIRQ(USBWakeUp_IRQn); + } +#elif CFG_TUSB_MCU == OPT_MCU_STM32F1 + NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn); + NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn); + NVIC_EnableIRQ(USBWakeUp_IRQn); + +#elif CFG_TUSB_MCU == OPT_MCU_STM32G4 + NVIC_EnableIRQ(USB_HP_IRQn); + NVIC_EnableIRQ(USB_LP_IRQn); + NVIC_EnableIRQ(USBWakeUp_IRQn); + +#elif CFG_TUSB_MCU == OPT_MCU_STM32WB + NVIC_EnableIRQ(USB_HP_IRQn); + NVIC_EnableIRQ(USB_LP_IRQn); + +#else + #error Unknown arch in USB driver +#endif +} + +// Disable device interrupt +void dcd_int_disable(uint8_t rhport) +{ + (void)rhport; + +#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 + NVIC_DisableIRQ(USB_IRQn); +#elif CFG_TUSB_MCU == OPT_MCU_STM32L1 + NVIC_DisableIRQ(USB_LP_IRQn); +#elif CFG_TUSB_MCU == OPT_MCU_STM32F3 + // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from + // shared USB/CAN IRQs to separate CAN and USB IRQs. + // This dynamically checks if this remap is active to disable the right IRQs. + #ifdef SYSCFG_CFGR1_USB_IT_RMP + if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) + { + NVIC_DisableIRQ(USB_HP_IRQn); + NVIC_DisableIRQ(USB_LP_IRQn); + NVIC_DisableIRQ(USBWakeUp_RMP_IRQn); + } + else + #endif + { + NVIC_DisableIRQ(USB_HP_CAN_TX_IRQn); + NVIC_DisableIRQ(USB_LP_CAN_RX0_IRQn); + NVIC_DisableIRQ(USBWakeUp_IRQn); + } +#elif CFG_TUSB_MCU == OPT_MCU_STM32F1 + NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn); + NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn); + NVIC_DisableIRQ(USBWakeUp_IRQn); + +#elif CFG_TUSB_MCU == OPT_MCU_STM32G4 + NVIC_DisableIRQ(USB_HP_IRQn); + NVIC_DisableIRQ(USB_LP_IRQn); + NVIC_DisableIRQ(USBWakeUp_IRQn); + +#elif CFG_TUSB_MCU == OPT_MCU_STM32WB + NVIC_DisableIRQ(USB_HP_IRQn); + NVIC_DisableIRQ(USB_LP_IRQn); + +#else + #error Unknown arch in USB driver +#endif + + // CMSIS has a membar after disabling interrupts +} + +// Receive Set Address request, mcu port must also include status IN response +void dcd_set_address(uint8_t rhport, uint8_t dev_addr) +{ + (void) rhport; + (void) dev_addr; + + // Respond with status + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); + + // DCD can only set address after status for this request is complete. + // do it at dcd_edpt0_status_complete() +} + +void dcd_remote_wakeup(uint8_t rhport) +{ + (void) rhport; + + USB->CNTR |= (uint16_t) USB_CNTR_RESUME; + remoteWakeCountdown = 4u; // required to be 1 to 15 ms, ESOF should trigger every 1ms. +} + +static const tusb_desc_endpoint_t ep0OUT_desc = +{ + .bLength = sizeof(tusb_desc_endpoint_t), + .bDescriptorType = TUSB_DESC_ENDPOINT, + + .bEndpointAddress = 0x00, + .bmAttributes = { .xfer = TUSB_XFER_CONTROL }, + .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE, + .bInterval = 0 +}; + +static const tusb_desc_endpoint_t ep0IN_desc = +{ + .bLength = sizeof(tusb_desc_endpoint_t), + .bDescriptorType = TUSB_DESC_ENDPOINT, + + .bEndpointAddress = 0x80, + .bmAttributes = { .xfer = TUSB_XFER_CONTROL }, + .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE, + .bInterval = 0 +}; + +static void dcd_handle_bus_reset(void) +{ + //__IO uint16_t * const epreg = &(EPREG(0)); + USB->DADDR = 0u; // disable USB peripheral by clearing the EF flag + + // Clear all EPREG (or maybe this is automatic? I'm not sure) + for(uint32_t i=0; iDADDR = USB_DADDR_EF; // Set enable flag, and leaving the device address as zero. +} + +// Handle CTR interrupt for the TX/IN direction +// +// Upon call, (wIstr & USB_ISTR_DIR) == 0U +static void dcd_ep_ctr_tx_handler(uint32_t wIstr) +{ + uint32_t EPindex = wIstr & USB_ISTR_EP_ID; + uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex); + + // Verify the CTR_TX bit is set. This was in the ST Micro code, + // but I'm not sure it's actually necessary? + if((wEPRegVal & USB_EP_CTR_TX) == 0U) + { + return; + } + + /* clear int flag */ + pcd_clear_tx_ep_ctr(USB, EPindex); + + xfer_ctl_t * xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_IN); + if((xfer->total_len != xfer->queued_len)) /* TX not complete */ + { + dcd_transmit_packet(xfer, EPindex); + } + else /* TX Complete */ + { + dcd_event_xfer_complete(0, (uint8_t)(0x80 + EPindex), xfer->total_len, XFER_RESULT_SUCCESS, true); + } +} + +// Handle CTR interrupt for the RX/OUT direction +// +// Upon call, (wIstr & USB_ISTR_DIR) == 0U +static void dcd_ep_ctr_rx_handler(uint32_t wIstr) +{ + uint32_t EPindex = wIstr & USB_ISTR_EP_ID; + uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex); + uint32_t count = pcd_get_ep_rx_cnt(USB,EPindex); + + xfer_ctl_t *xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_OUT); + + // Verify the CTR_RX bit is set. This was in the ST Micro code, + // but I'm not sure it's actually necessary? + if((wEPRegVal & USB_EP_CTR_RX) == 0U) + { + return; + } + + if((EPindex == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) /* Setup packet */ + { + // The setup_received function uses memcpy, so this must first copy the setup data into + // user memory, to allow for the 32-bit access that memcpy performs. + uint8_t userMemBuf[8]; + /* Get SETUP Packet*/ + if(count == 8) // Setup packet should always be 8 bytes. If not, ignore it, and try again. + { + // Must reset EP to NAK (in case it had been stalling) (though, maybe too late here) + pcd_set_ep_rx_status(USB,0u,USB_EP_RX_NAK); + pcd_set_ep_tx_status(USB,0u,USB_EP_TX_NAK); + dcd_read_packet_memory(userMemBuf, *pcd_ep_rx_address_ptr(USB,EPindex), 8); + dcd_event_setup_received(0, (uint8_t*)userMemBuf, true); + } + } + else + { + // Clear RX CTR interrupt flag + if(EPindex != 0u) + { + pcd_clear_rx_ep_ctr(USB, EPindex); + } + + if (count != 0U) + { +#if 0 // TODO support dcd_edpt_xfer_fifo API + if (xfer->ff) + { + dcd_read_packet_memory_ff(xfer->ff, *pcd_ep_rx_address_ptr(USB,EPindex), count); + } + else +#endif + { + dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), *pcd_ep_rx_address_ptr(USB,EPindex), count); + } + + xfer->queued_len = (uint16_t)(xfer->queued_len + count); + } + + if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len)) + { + /* RX COMPLETE */ + dcd_event_xfer_complete(0, EPindex, xfer->queued_len, XFER_RESULT_SUCCESS, true); + // Though the host could still send, we don't know. + // Does the bulk pipe need to be reset to valid to allow for a ZLP? + } + else + { + uint32_t remaining = (uint32_t)xfer->total_len - (uint32_t)xfer->queued_len; + if(remaining >= xfer->max_packet_size) { + pcd_set_ep_rx_cnt(USB, EPindex,xfer->max_packet_size); + } else { + pcd_set_ep_rx_cnt(USB, EPindex,remaining); + } + pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID); + } + } + + // For EP0, prepare to receive another SETUP packet. + // Clear CTR last so that a new packet does not overwrite the packing being read. + // (Based on the docs, it seems SETUP will always be accepted after CTR is cleared) + if(EPindex == 0u) + { + // Always be prepared for a status packet... + pcd_set_ep_rx_cnt(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE); + pcd_clear_rx_ep_ctr(USB, EPindex); + } +} + +static void dcd_ep_ctr_handler(void) +{ + uint32_t wIstr; + + /* stay in loop while pending interrupts */ + while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U) + { + + if ((wIstr & USB_ISTR_DIR) == 0U) /* TX/IN */ + { + dcd_ep_ctr_tx_handler(wIstr); + } + else /* RX/OUT*/ + { + dcd_ep_ctr_rx_handler(wIstr); + } + } +} + +void dcd_int_handler(uint8_t rhport) { + + (void) rhport; + + uint32_t int_status = USB->ISTR; + //const uint32_t handled_ints = USB_ISTR_CTR | USB_ISTR_RESET | USB_ISTR_WKUP + // | USB_ISTR_SUSP | USB_ISTR_SOF | USB_ISTR_ESOF; + // unused IRQs: (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_L1REQ ) + + // The ST driver loops here on the CTR bit, but that loop has been moved into the + // dcd_ep_ctr_handler(), so less need to loop here. The other interrupts shouldn't + // be triggered repeatedly. + + if(int_status & USB_ISTR_RESET) { + // USBRST is start of reset. + clear_istr_bits(USB_ISTR_RESET); + dcd_handle_bus_reset(); + dcd_event_bus_reset(0, TUSB_SPEED_FULL, true); + return; // Don't do the rest of the things here; perhaps they've been cleared? + } + + if (int_status & USB_ISTR_CTR) + { + /* servicing of the endpoint correct transfer interrupt */ + /* clear of the CTR flag into the sub */ + dcd_ep_ctr_handler(); + } + + if (int_status & USB_ISTR_WKUP) + { + reg16_clear_bits(&USB->CNTR, USB_CNTR_LPMODE); + reg16_clear_bits(&USB->CNTR, USB_CNTR_FSUSP); + clear_istr_bits(USB_ISTR_WKUP); + dcd_event_bus_signal(0, DCD_EVENT_RESUME, true); + } + + if (int_status & USB_ISTR_SUSP) + { + /* Suspend is asserted for both suspend and unplug events. without Vbus monitoring, + * these events cannot be differentiated, so we only trigger suspend. */ + + /* Force low-power mode in the macrocell */ + USB->CNTR |= USB_CNTR_FSUSP; + USB->CNTR |= USB_CNTR_LPMODE; + + /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ + clear_istr_bits(USB_ISTR_SUSP); + dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); + } + +#if USE_SOF + if(int_status & USB_ISTR_SOF) { + clear_istr_bits(USB_ISTR_SOF); + dcd_event_bus_signal(0, DCD_EVENT_SOF, true); + } +#endif + + if(int_status & USB_ISTR_ESOF) { + if(remoteWakeCountdown == 1u) + { + USB->CNTR &= (uint16_t)(~USB_CNTR_RESUME); + } + if(remoteWakeCountdown > 0u) + { + remoteWakeCountdown--; + } + clear_istr_bits(USB_ISTR_ESOF); + } +} + +//--------------------------------------------------------------------+ +// Endpoint API +//--------------------------------------------------------------------+ + +// Invoked when a control transfer's status stage is complete. +// May help DCD to prepare for next control transfer, this API is optional. +void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) +{ + (void) rhport; + + if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && + request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && + request->bRequest == TUSB_REQ_SET_ADDRESS ) + { + uint8_t const dev_addr = (uint8_t) request->wValue; + + // Setting new address after the whole request is complete + reg16_clear_bits(&USB->DADDR, USB_DADDR_ADD); + USB->DADDR = (uint16_t)(USB->DADDR | dev_addr); // leave the enable bit set + } +} + +static void dcd_pma_alloc_reset(void) +{ + ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT; // 8 bytes per endpoint (two TX and two RX words, each) + //TU_LOG2("dcd_pma_alloc_reset()\r\n"); + for(uint32_t i=0; ipma_alloc_size = 0U; + xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_alloc_size = 0U; + xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_ptr = 0U; + xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_ptr = 0U; + } +} + +/*** + * Allocate a section of PMA + * + * If the EP number has already been allocated, and the new allocation + * is larger than the old allocation, then this will fail with a TU_ASSERT. + * (This is done to simplify the code. More complicated algorithms could be used) + * + * During failure, TU_ASSERT is used. If this happens, rework/reallocate memory manually. + */ +static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + xfer_ctl_t* epXferCtl = xfer_ctl_ptr(epnum,dir); + + if(epXferCtl->pma_alloc_size != 0U) + { + //TU_LOG2("dcd_pma_alloc(%x,%x)=%x (cached)\r\n",ep_addr,length,epXferCtl->pma_ptr); + // Previously allocated + TU_ASSERT(length <= epXferCtl->pma_alloc_size, 0xFFFF); // Verify no larger than previous alloc + return epXferCtl->pma_ptr; + } + + uint16_t addr = ep_buf_ptr; + ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer + + // Verify no overflow + TU_ASSERT(ep_buf_ptr <= PMA_LENGTH, 0xFFFF); + + epXferCtl->pma_ptr = addr; + epXferCtl->pma_alloc_size = length; + //TU_LOG2("dcd_pma_alloc(%x,%x)=%x\r\n",ep_addr,length,addr); + + return addr; +} + +/*** + * Free a block of PMA space + */ +static void dcd_pma_free(uint8_t ep_addr) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + // Presently, this should never be called for EP0 IN/OUT + TU_ASSERT(open_ep_count > 2, /**/); + TU_ASSERT(xfer_ctl_ptr(epnum,dir)->max_packet_size != 0, /**/); + open_ep_count--; + + // If count is 2, only EP0 should be open, so allocations can be mostly reset. + + if(open_ep_count == 2) + { + ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT + 2*CFG_TUD_ENDPOINT0_SIZE; // 8 bytes per endpoint (two TX and two RX words, each), and EP0 + + // Skip EP0 + for(uint32_t i=1; ipma_alloc_size = 0U; + xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_alloc_size = 0U; + xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_ptr = 0U; + xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_ptr = 0U; + } + } +} + +// The STM32F0 doesn't seem to like |= or &= to manipulate the EP#R registers, +// so I'm using the #define from HAL here, instead. + +bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) +{ + (void)rhport; + uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); + uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); + const uint16_t epMaxPktSize = tu_edpt_packet_size(p_endpoint_desc); + uint16_t pma_addr; + uint32_t wType; + + // Isochronous not supported (yet), and some other driver assumptions. + TU_ASSERT(p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS); + TU_ASSERT(epnum < MAX_EP_COUNT); + + // Set type + switch(p_endpoint_desc->bmAttributes.xfer) { + case TUSB_XFER_CONTROL: + wType = USB_EP_CONTROL; + break; +#if (0) + case TUSB_XFER_ISOCHRONOUS: // FIXME: Not yet supported + wType = USB_EP_ISOCHRONOUS; + break; +#endif + + case TUSB_XFER_BULK: + wType = USB_EP_CONTROL; + break; + + case TUSB_XFER_INTERRUPT: + wType = USB_EP_INTERRUPT; + break; + + default: + TU_ASSERT(false); + } + + pcd_set_eptype(USB, epnum, wType); + pcd_set_ep_address(USB, epnum, epnum); + // Be normal, for now, instead of only accepting zero-byte packets (on control endpoint) + // or being double-buffered (bulk endpoints) + pcd_clear_ep_kind(USB,0); + + pma_addr = dcd_pma_alloc(p_endpoint_desc->bEndpointAddress, epMaxPktSize); + + if(dir == TUSB_DIR_IN) + { + *pcd_ep_tx_address_ptr(USB, epnum) = pma_addr; + pcd_set_ep_tx_cnt(USB, epnum, epMaxPktSize); + pcd_clear_tx_dtog(USB, epnum); + pcd_set_ep_tx_status(USB,epnum,USB_EP_TX_NAK); + } + else + { + *pcd_ep_rx_address_ptr(USB, epnum) = pma_addr; + pcd_set_ep_rx_cnt(USB, epnum, epMaxPktSize); + pcd_clear_rx_dtog(USB, epnum); + pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_NAK); + } + + xfer_ctl_ptr(epnum, dir)->max_packet_size = epMaxPktSize; + + return true; +} + +void dcd_edpt_close_all (uint8_t rhport) +{ + (void) rhport; + // TODO implement dcd_edpt_close_all() +} + +/** + * Close an endpoint. + * + * This function may be called with interrupts enabled or disabled. + * + * This also clears transfers in progress, should there be any. + */ +void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) +{ + (void)rhport; + uint32_t const epnum = tu_edpt_number(ep_addr); + uint32_t const dir = tu_edpt_dir(ep_addr); + + if(dir == TUSB_DIR_IN) + { + pcd_set_ep_tx_status(USB,epnum,USB_EP_TX_DIS); + } + else + { + pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_DIS); + } + + dcd_pma_free(ep_addr); +} + +// Currently, single-buffered, and only 64 bytes at a time (max) + +static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix) +{ + uint16_t len = (uint16_t)(xfer->total_len - xfer->queued_len); + + if(len > xfer->max_packet_size) // max packet size for FS transfer + { + len = xfer->max_packet_size; + } + uint16_t oldAddr = *pcd_ep_tx_address_ptr(USB,ep_ix); + +#if 0 // TODO support dcd_edpt_xfer_fifo API + if (xfer->ff) + { + dcd_write_packet_memory_ff(xfer->ff, oldAddr, len); + } + else +#endif + { + dcd_write_packet_memory(oldAddr, &(xfer->buffer[xfer->queued_len]), len); + } + xfer->queued_len = (uint16_t)(xfer->queued_len + len); + + pcd_set_ep_tx_cnt(USB,ep_ix,len); + pcd_set_ep_tx_status(USB, ep_ix, USB_EP_TX_VALID); +} + +bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir); + + xfer->buffer = buffer; + // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API + xfer->total_len = total_bytes; + xfer->queued_len = 0; + + if ( dir == TUSB_DIR_OUT ) + { + // A setup token can occur immediately after an OUT STATUS packet so make sure we have a valid + // buffer for the control endpoint. + if (epnum == 0 && buffer == NULL) + { + xfer->buffer = (uint8_t*)_setup_packet; + } + if(total_bytes > xfer->max_packet_size) + { + pcd_set_ep_rx_cnt(USB,epnum,xfer->max_packet_size); + } else { + pcd_set_ep_rx_cnt(USB,epnum,total_bytes); + } + pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_VALID); + } + else // IN + { + dcd_transmit_packet(xfer,epnum); + } + return true; +} + +#if 0 // TODO support dcd_edpt_xfer_fifo API +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir); + + xfer->buffer = NULL; + // xfer->ff = ff; // TODO support dcd_edpt_xfer_fifo API + xfer->total_len = total_bytes; + xfer->queued_len = 0; + + if ( dir == TUSB_DIR_OUT ) + { + if(total_bytes > xfer->max_packet_size) + { + pcd_set_ep_rx_cnt(USB,epnum,xfer->max_packet_size); + } else { + pcd_set_ep_rx_cnt(USB,epnum,total_bytes); + } + pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_VALID); + } + else // IN + { + dcd_transmit_packet(xfer,epnum); + } + return true; +} +#endif + +void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) +{ + (void)rhport; + + if (ep_addr & 0x80) + { // IN + pcd_set_ep_tx_status(USB, ep_addr & 0x7F, USB_EP_TX_STALL); + } + else + { // OUT + pcd_set_ep_rx_status(USB, ep_addr, USB_EP_RX_STALL); + } +} + +void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) +{ + (void)rhport; + + if (ep_addr & 0x80) + { // IN + ep_addr &= 0x7F; + + pcd_set_ep_tx_status(USB,ep_addr, USB_EP_TX_NAK); + + /* Reset to DATA0 if clearing stall condition. */ + pcd_clear_tx_dtog(USB,ep_addr); + } + else + { // OUT + /* Reset to DATA0 if clearing stall condition. */ + pcd_clear_rx_dtog(USB,ep_addr); + + pcd_set_ep_rx_status(USB,ep_addr, USB_EP_RX_NAK); + } +} + +// Packet buffer access can only be 8- or 16-bit. +/** + * @brief Copy a buffer from user memory area to packet memory area (PMA). + * This uses byte-access for user memory (so support non-aligned buffers) + * and 16-bit access for packet memory. + * @param dst, byte address in PMA; must be 16-bit aligned + * @param src pointer to user memory area. + * @param wPMABufAddr address into PMA. + * @param wNBytes no. of bytes to be copied. + * @retval None + */ +static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes) +{ + uint32_t n = ((uint32_t)wNBytes + 1U) >> 1U; + uint32_t i; + uint16_t temp1, temp2; + const uint8_t * srcVal; + + // The GCC optimizer will combine access to 32-bit sizes if we let it. Force + // it volatile so that it won't do that. + __IO uint16_t *pdwVal; + + srcVal = src; + pdwVal = &pma[PMA_STRIDE*(dst>>1)]; + + for (i = n; i != 0; i--) + { + temp1 = (uint16_t) *srcVal; + srcVal++; + temp2 = temp1 | ((uint16_t)((uint16_t) ((*srcVal) << 8U))) ; + *pdwVal = temp2; + pdwVal += PMA_STRIDE; + srcVal++; + } + return true; +} + +#if 0 // TODO support dcd_edpt_xfer_fifo API +/** + * @brief Copy from FIFO to packet memory area (PMA). + * Uses byte-access of system memory and 16-bit access of packet memory + * @param wNBytes no. of bytes to be copied. + * @retval None + */ + +// THIS FUNCTION IS UNTESTED + +static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes) +{ + // Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies + // Check for first linear part + void * src; + uint16_t len = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes); // We want to read from the FIFO - THIS FUNCTION CHANGED!!! + TU_VERIFY(len && dcd_write_packet_memory(dst, src, len)); // and write it into the PMA + tu_fifo_advance_read_pointer(ff, len); + + // Check for wrapped part + if (len < wNBytes) + { + // Get remaining wrapped length + uint16_t len2 = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes - len); + TU_VERIFY(len2); + + // Update destination pointer + dst += len; + + // Since PMA is accessed 16-bit wise we need to handle the case when a 16 bit value was split + if (len % 2) // If len is uneven there is a byte left to copy + { + // Since PMA can accessed only 16 bit-wise we copy the last byte again + tu_fifo_backward_read_pointer(ff, 1); // Move one byte back and copy two bytes for the PMA + tu_fifo_read_n(ff, (void *) &pma[PMA_STRIDE*(dst>>1)], 2); // Since EP FIFOs must be of item size 1 this is safe to do + dst++; + len2--; + } + + TU_VERIFY(dcd_write_packet_memory(dst, src, len2)); + tu_fifo_advance_write_pointer(ff, len2); + } + + return true; +} +#endif + +/** + * @brief Copy a buffer from packet memory area (PMA) to user memory area. + * Uses byte-access of system memory and 16-bit access of packet memory + * @param wNBytes no. of bytes to be copied. + * @retval None + */ +static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes) +{ + uint32_t n = (uint32_t)wNBytes >> 1U; + uint32_t i; + // The GCC optimizer will combine access to 32-bit sizes if we let it. Force + // it volatile so that it won't do that. + __IO const uint16_t *pdwVal; + uint32_t temp; + + pdwVal = &pma[PMA_STRIDE*(src>>1)]; + uint8_t *dstVal = (uint8_t*)dst; + + for (i = n; i != 0U; i--) + { + temp = *pdwVal; + pdwVal += PMA_STRIDE; + *dstVal++ = ((temp >> 0) & 0xFF); + *dstVal++ = ((temp >> 8) & 0xFF); + } + + if (wNBytes % 2) + { + temp = *pdwVal; + pdwVal += PMA_STRIDE; + *dstVal++ = ((temp >> 0) & 0xFF); + } + return true; +} + +#if 0 // TODO support dcd_edpt_xfer_fifo API +/** + * @brief Copy a buffer from user packet memory area (PMA) to FIFO. + * Uses byte-access of system memory and 16-bit access of packet memory + * @param wNBytes no. of bytes to be copied. + * @retval None + */ + +// THIS FUNCTION IS UNTESTED + +static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes) +{ + // Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies + // Check for first linear part + void * dst; + uint16_t len = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes); // THIS FUNCTION CHANGED!!!! + TU_VERIFY(len && dcd_read_packet_memory(dst, src, len)); + tu_fifo_advance_write_pointer(ff, len); + + // Check for wrapped part + if (len < wNBytes) + { + // Get remaining wrapped length + uint16_t len2 = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes - len); + TU_VERIFY(len2); + + // Update source pointer + src += len; + + // Since PMA is accessed 16-bit wise we need to handle the case when a 16 bit value was split + if (len % 2) // If len is uneven there is a byte left to copy + { + uint32_t temp = pma[PMA_STRIDE*(src>>1)]; + *((uint8_t *)dst++) = ((temp >> 8) & 0xFF); + src++; + len2--; + } + + TU_VERIFY(dcd_read_packet_memory(dst, src, len2)); + tu_fifo_advance_write_pointer(ff, len2); + } + + return true; +} + +#endif + +#endif + diff --git a/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h b/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h new file mode 100644 index 00000000..bffae450 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h @@ -0,0 +1,422 @@ +/** + ****************************************************************************** + * @file dcd_stm32f0_pvt_st.h + * @brief DCD utilities from ST code + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ *

© parts COPYRIGHT(c) N Conrad

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********/ + +// This file contains source copied from ST's HAL, and thus should have their copyright statement. + +// PMA_LENGTH is PMA buffer size in bytes. +// On 512-byte devices, access with a stride of two words (use every other 16-bit address) +// On 1024-byte devices, access with a stride of one word (use every 16-bit address) + +#ifndef PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ +#define PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ + +#if defined(STM32F042x6) || \ + defined(STM32F070x6) || defined(STM32F070xB) || \ + defined(STM32F072xB) || \ + defined(STM32F078xx) + #include "stm32f0xx.h" + #define PMA_LENGTH (1024u) + // F0x2 models are crystal-less + // All have internal D+ pull-up + // 070RB: 2 x 16 bits/word memory LPM Support, BCD Support + // PMA dedicated to USB (no sharing with CAN) + +#elif defined(STM32F1_FSDEV) + #include "stm32f1xx.h" + #define PMA_LENGTH (512u) + // NO internal Pull-ups + // *B, and *C: 2 x 16 bits/word + + // F1 names this differently from the rest + #define USB_CNTR_LPMODE USB_CNTR_LP_MODE + +#elif defined(STM32F302xB) || defined(STM32F302xC) || \ + defined(STM32F303xB) || defined(STM32F303xC) || \ + defined(STM32F373xC) + #include "stm32f3xx.h" + #define PMA_LENGTH (512u) + // NO internal Pull-ups + // *B, and *C: 1 x 16 bits/word + // PMA dedicated to USB (no sharing with CAN) + +#elif defined(STM32F302x6) || defined(STM32F302x8) || \ + defined(STM32F302xD) || defined(STM32F302xE) || \ + defined(STM32F303xD) || defined(STM32F303xE) + #include "stm32f3xx.h" + #define PMA_LENGTH (1024u) + // NO internal Pull-ups + // *6, *8, *D, and *E: 2 x 16 bits/word LPM Support + // When CAN clock is enabled, USB can use first 768 bytes ONLY. + +#elif CFG_TUSB_MCU == OPT_MCU_STM32L0 + #include "stm32l0xx.h" + #define PMA_LENGTH (1024u) + +#elif CFG_TUSB_MCU == OPT_MCU_STM32L1 + #include "stm32l1xx.h" + #define PMA_LENGTH (512u) + +#elif CFG_TUSB_MCU == OPT_MCU_STM32G4 + #include "stm32g4xx.h" + #define PMA_LENGTH (1024u) + +#elif CFG_TUSB_MCU == OPT_MCU_STM32WB + #include "stm32wbxx.h" + #define PMA_LENGTH (1024u) + /* ST provided header has incorrect value */ + #undef USB_PMAADDR + #define USB_PMAADDR USB1_PMAADDR + +#else + #error You are using an untested or unimplemented STM32 variant. Please update the driver. + // This includes L1x0, L1x1, L1x2, L4x2 and L4x3, G1x1, G1x3, and G1x4 +#endif + +// For purposes of accessing the packet +#if ((PMA_LENGTH) == 512u) + #define PMA_STRIDE (2u) +#elif ((PMA_LENGTH) == 1024u) + #define PMA_STRIDE (1u) +#endif + +// And for type-safety create a new macro for the volatile address of PMAADDR +// The compiler should warn us if we cast it to a non-volatile type? +// Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden) +static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR; + +// prototypes +static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum); +static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum); +static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wRegValue); + + +/* SetENDPOINT */ +static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wRegValue) +{ + __O uint16_t *reg = (__O uint16_t *)((&USBx->EP0R) + bEpNum*2u); + *reg = (uint16_t)wRegValue; +} + +/* GetENDPOINT */ +static inline uint16_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpNum) { + __I uint16_t *reg = (__I uint16_t *)((&USBx->EP0R) + bEpNum*2u); + return *reg; +} + +static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wType) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= (uint32_t)USB_EP_T_MASK; + regVal |= wType; + regVal |= USB_EP_CTR_RX | USB_EP_CTR_TX; // These clear on write0, so must set high + pcd_set_endpoint(USBx, bEpNum, regVal); +} + +static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EP_T_FIELD; + return regVal; +} +/** + * @brief Clears bit CTR_RX / CTR_TX in the endpoint register. + * @param USBx USB peripheral instance register address. + * @param bEpNum Endpoint Number. + * @retval None + */ +static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EPREG_MASK; + regVal &= ~USB_EP_CTR_RX; + regVal |= USB_EP_CTR_TX; // preserve CTR_TX (clears on writing 0) + pcd_set_endpoint(USBx, bEpNum, regVal); +} +static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EPREG_MASK; + regVal &= ~USB_EP_CTR_TX; + regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0) + pcd_set_endpoint(USBx, bEpNum,regVal); +} +/** + * @brief gets counter of the tx buffer. + * @param USBx USB peripheral instance register address. + * @param bEpNum Endpoint Number. + * @retval Counter value + */ +static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpNum) +{ + __I uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpNum); + return *regPtr & 0x3ffU; +} + +static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpNum) +{ + __I uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpNum); + return *regPtr & 0x3ffU; +} + +/** + * @brief Sets counter of rx buffer with no. of blocks. + * @param dwReg Register + * @param wCount Counter. + * @param wNBlocks no. of Blocks. + * @retval None + */ + +static inline void pcd_set_ep_cnt_rx_reg(__O uint16_t * pdwReg, size_t wCount) { + uint32_t wNBlocks; + if(wCount > 62u) + { + wNBlocks = wCount >> 5u; + if((wCount & 0x1fU) == 0u) + { + wNBlocks--; + } + wNBlocks = wNBlocks << 10u; + wNBlocks |= 0x8000u; // Mark block size as 32byte + *pdwReg = (uint16_t)wNBlocks; + } + else + { + wNBlocks = wCount >> 1u; + if((wCount & 0x1U) != 0u) + { + wNBlocks++; + } + *pdwReg = (uint16_t)((wNBlocks) << 10u); + } +} + + +/** + * @brief Sets address in an endpoint register. + * @param USBx USB peripheral instance register address. + * @param bEpNum Endpoint Number. + * @param bAddr Address. + * @retval None + */ +static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t bAddr) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EPREG_MASK; + regVal |= bAddr; + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; + pcd_set_endpoint(USBx, bEpNum,regVal); +} + +static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) +{ + size_t total_word_offset = (((USBx)->BTABLE)>>1) + x; + total_word_offset *= PMA_STRIDE; + return &(pma[total_word_offset]); +} + +// Pointers to the PMA table entries (using the ARM address space) +static inline __IO uint16_t* pcd_ep_tx_address_ptr(USB_TypeDef * USBx, uint32_t bEpNum) +{ + return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 0u); +} +static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum) +{ + return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 1u); +} + +static inline __IO uint16_t* pcd_ep_rx_address_ptr(USB_TypeDef * USBx, uint32_t bEpNum) +{ + return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 2u); +} + +static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum) +{ + return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 3u); +} + +static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wCount) +{ + *pcd_ep_tx_cnt_ptr(USBx, bEpNum) = (uint16_t)wCount; +} + +static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wCount) +{ + __IO uint16_t *pdwReg = pcd_ep_rx_cnt_ptr((USBx),(bEpNum)); + pcd_set_ep_cnt_rx_reg(pdwReg, wCount); +} + +/** + * @brief sets the status for tx transfer (bits STAT_TX[1:0]). + * @param USBx USB peripheral instance register address. + * @param bEpNum Endpoint Number. + * @param wState new state + * @retval None + */ +static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wState) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EPTX_DTOGMASK; + + /* toggle first bit ? */ + if((USB_EPTX_DTOG1 & (wState))!= 0U) + { + regVal ^= USB_EPTX_DTOG1; + } + /* toggle second bit ? */ + if((USB_EPTX_DTOG2 & ((uint32_t)(wState)))!= 0U) + { + regVal ^= USB_EPTX_DTOG2; + } + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; + pcd_set_endpoint(USBx, bEpNum, regVal); +} /* pcd_set_ep_tx_status */ + +/** + * @brief sets the status for rx transfer (bits STAT_TX[1:0]) + * @param USBx USB peripheral instance register address. + * @param bEpNum Endpoint Number. + * @param wState new state + * @retval None + */ + +static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wState) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EPRX_DTOGMASK; + + /* toggle first bit ? */ + if((USB_EPRX_DTOG1 & wState)!= 0U) + { + regVal ^= USB_EPRX_DTOG1; + } + /* toggle second bit ? */ + if((USB_EPRX_DTOG2 & wState)!= 0U) + { + regVal ^= USB_EPRX_DTOG2; + } + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; + pcd_set_endpoint(USBx, bEpNum, regVal); +} /* pcd_set_ep_rx_status */ + +static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + return (regVal & USB_EPRX_STAT) >> (12u); +} /* pcd_get_ep_rx_status */ + + +/** + * @brief Toggles DTOG_RX / DTOG_TX bit in the endpoint register. + * @param USBx USB peripheral instance register address. + * @param bEpNum Endpoint Number. + * @retval None + */ +static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EPREG_MASK; + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_RX; + pcd_set_endpoint(USBx, bEpNum, regVal); +} + +static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EPREG_MASK; + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_TX; + pcd_set_endpoint(USBx, bEpNum, regVal); +} + +/** + * @brief Clears DTOG_RX / DTOG_TX bit in the endpoint register. + * @param USBx USB peripheral instance register address. + * @param bEpNum Endpoint Number. + * @retval None + */ + +static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + if((regVal & USB_EP_DTOG_RX) != 0) + { + pcd_rx_dtog(USBx,bEpNum); + } +} + +static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + if((regVal & USB_EP_DTOG_TX) != 0) + { + pcd_tx_dtog(USBx,bEpNum); + } +} + +/** + * @brief set & clear EP_KIND bit. + * @param USBx USB peripheral instance register address. + * @param bEpNum Endpoint Number. + * @retval None + */ + +static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal |= USB_EP_KIND; + regVal &= USB_EPREG_MASK; + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; + pcd_set_endpoint(USBx, bEpNum, regVal); +} +static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpNum) +{ + uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + regVal &= USB_EPKIND_MASK; + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; + pcd_set_endpoint(USBx, bEpNum, regVal); +} + +// This checks if the device has "LPM" +#if defined(USB_ISTR_L1REQ) +#define USB_ISTR_L1REQ_FORCED (USB_ISTR_L1REQ) +#else +#define USB_ISTR_L1REQ_FORCED ((uint16_t)0x0000U) +#endif + +#define USB_ISTR_ALL_EVENTS (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_WKUP | USB_ISTR_SUSP | \ + USB_ISTR_RESET | USB_ISTR_SOF | USB_ISTR_ESOF | USB_ISTR_L1REQ_FORCED ) + +// Number of endpoints in hardware +#define STFSDEV_EP_COUNT (8u) + +#endif /* PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/tusb.c b/test-devices/loopback-stm32/lib/tinyusb/tusb.c new file mode 100644 index 00000000..c3787ff8 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/tusb.c @@ -0,0 +1,314 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUH_ENABLED || CFG_TUD_ENABLED + +#include "tusb.h" +#include "common/tusb_private.h" + +// TODO clean up +#if CFG_TUD_ENABLED +#include "device/usbd_pvt.h" +#endif + +bool tusb_init(void) +{ +#if CFG_TUD_ENABLED && defined(TUD_OPT_RHPORT) + // init device stack CFG_TUSB_RHPORTx_MODE must be defined + TU_ASSERT ( tud_init(TUD_OPT_RHPORT) ); +#endif + +#if CFG_TUH_ENABLED && defined(TUH_OPT_RHPORT) + // init host stack CFG_TUSB_RHPORTx_MODE must be defined + TU_ASSERT( tuh_init(TUH_OPT_RHPORT) ); +#endif + + return true; +} + +bool tusb_inited(void) +{ + bool ret = false; + +#if CFG_TUD_ENABLED + ret = ret || tud_inited(); +#endif + +#if CFG_TUH_ENABLED + ret = ret || tuh_inited(); +#endif + + return ret; +} + +//--------------------------------------------------------------------+ +// Internal Helper for both Host and Device stack +//--------------------------------------------------------------------+ + +bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex) +{ + (void) mutex; + +#if TUSB_OPT_MUTEX + // pre-check to help reducing mutex lock + TU_VERIFY((ep_state->busy == 0) && (ep_state->claimed == 0)); + osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); +#endif + + // can only claim the endpoint if it is not busy and not claimed yet. + bool const available = (ep_state->busy == 0) && (ep_state->claimed == 0); + if (available) + { + ep_state->claimed = 1; + } + +#if TUSB_OPT_MUTEX + osal_mutex_unlock(mutex); +#endif + + return available; +} + +bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex) +{ + (void) mutex; + +#if TUSB_OPT_MUTEX + osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); +#endif + + // can only release the endpoint if it is claimed and not busy + bool const ret = (ep_state->claimed == 1) && (ep_state->busy == 0); + if (ret) + { + ep_state->claimed = 0; + } + +#if TUSB_OPT_MUTEX + osal_mutex_unlock(mutex); +#endif + + return ret; +} + +bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed) +{ + uint16_t const max_packet_size = tu_edpt_packet_size(desc_ep); + TU_LOG2(" Open EP %02X with Size = %u\r\n", desc_ep->bEndpointAddress, max_packet_size); + + switch (desc_ep->bmAttributes.xfer) + { + case TUSB_XFER_ISOCHRONOUS: + { + uint16_t const spec_size = (speed == TUSB_SPEED_HIGH ? 1024 : 1023); + TU_ASSERT(max_packet_size <= spec_size); + } + break; + + case TUSB_XFER_BULK: + if (speed == TUSB_SPEED_HIGH) + { + // Bulk highspeed must be EXACTLY 512 + TU_ASSERT(max_packet_size == 512); + }else + { + // TODO Bulk fullspeed can only be 8, 16, 32, 64 + TU_ASSERT(max_packet_size <= 64); + } + break; + + case TUSB_XFER_INTERRUPT: + { + uint16_t const spec_size = (speed == TUSB_SPEED_HIGH ? 1024 : 64); + TU_ASSERT(max_packet_size <= spec_size); + } + break; + + default: return false; + } + + return true; +} + +void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* desc_itf, uint16_t desc_len, uint8_t driver_id) +{ + uint8_t const* p_desc = (uint8_t const*) desc_itf; + uint8_t const* desc_end = p_desc + desc_len; + + while( p_desc < desc_end ) + { + if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + { + uint8_t const ep_addr = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress; + + TU_LOG(2, " Bind EP %02x to driver id %u\r\n", ep_addr, driver_id); + ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)] = driver_id; + } + + p_desc = tu_desc_next(p_desc); + } +} + +uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len) +{ + uint8_t const* p_desc = (uint8_t const*) desc_itf; + uint16_t len = 0; + + while (itf_count--) + { + // Next on interface desc + len += tu_desc_len(desc_itf); + p_desc = tu_desc_next(p_desc); + + while (len < max_len) + { + // return on IAD regardless of itf count + if ( tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION ) return len; + + if ( (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) && + ((tusb_desc_interface_t const*) p_desc)->bAlternateSetting == 0 ) + { + break; + } + + len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + } + + return len; +} + +/*------------------------------------------------------------------*/ +/* Debug + *------------------------------------------------------------------*/ +#if CFG_TUSB_DEBUG +#include + +#if CFG_TUSB_DEBUG >= 2 + +char const* const tu_str_speed[] = { "Full", "Low", "High" }; +char const* const tu_str_std_request[] = +{ + "Get Status" , + "Clear Feature" , + "Reserved" , + "Set Feature" , + "Reserved" , + "Set Address" , + "Get Descriptor" , + "Set Descriptor" , + "Get Configuration" , + "Set Configuration" , + "Get Interface" , + "Set Interface" , + "Synch Frame" +}; + +#endif + +static void dump_str_line(uint8_t const* buf, uint16_t count) +{ + tu_printf(" |"); + + // each line is 16 bytes + for(uint16_t i=0; i 64 + #error Control Endpoint Max Packet Size cannot be larger than 64 +#endif + +#endif /* _TUSB_OPTION_H_ */ + +/** @} */ diff --git a/test-devices/loopback-stm32/platformio.ini b/test-devices/loopback-stm32/platformio.ini index d586996e..11624366 100644 --- a/test-devices/loopback-stm32/platformio.ini +++ b/test-devices/loopback-stm32/platformio.ini @@ -1,4 +1,30 @@ -[env:loopback-stm32] +[common] +tinyusb_flags = + -D CFG_VENDOR_ADVANCED=1 + -D CFG_TUSB_RHPORT1_MODE=OPT_MODE_NONE platform = ststm32 +framework = cmsis +debug_tool = stlink + +[env:blackpill-f401cc] +extends = common +board = blackpill_f401cc +build_flags = + ${common.tinyusb_flags} + -D CFG_TUSB_MCU=OPT_MCU_STM32F4 + -D HSE_VALUE=25000000 + +[env:blackpill-f411ce] +extends = common +board = blackpill_f411ce +build_flags = + ${common.tinyusb_flags} + -D CFG_TUSB_MCU=OPT_MCU_STM32F4 + -D HSE_VALUE=25000000 + +[env:bluepill-f103c8] +extends = common board = bluepill_f103c8 -framework = libopencm3 +build_flags = + ${common.tinyusb_flags} + -D CFG_TUSB_MCU=OPT_MCU_STM32F1 diff --git a/test-devices/loopback-stm32/save_firmware.sh b/test-devices/loopback-stm32/save_firmware.sh new file mode 100755 index 00000000..303a542a --- /dev/null +++ b/test-devices/loopback-stm32/save_firmware.sh @@ -0,0 +1,6 @@ +#!/bin/sh +rm -rf .pio +pio run +cp .pio/build/bluepill-f103c8/firmware.bin bin/bluepill-f103c8.bin +cp .pio/build/blackpill-f401cc/firmware.bin bin/blackpill-f401cc.bin +cp .pio/build/blackpill-f411ce/firmware.bin bin/blackpill-f411ce.bin diff --git a/test-devices/loopback-stm32/src/board_f1.c b/test-devices/loopback-stm32/src/board_f1.c new file mode 100644 index 00000000..e3dc0eb5 --- /dev/null +++ b/test-devices/loopback-stm32/src/board_f1.c @@ -0,0 +1,215 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Board specific code for STM32F1 family +// + +#if defined(STM32F1) + +#include +#include "stm32f1xx.h" +#include "device/usbd.h" + + +extern uint32_t SystemCoreClock; +void SystemCoreClockUpdate(void); + + +static inline uint32_t get_reg(__I uint32_t* reg, uint32_t mask) { + return *reg & mask; +} + +static inline void set_reg(__IO uint32_t* reg, uint32_t value, uint32_t mask) { + *reg = (*reg & ~mask) | (value & mask); +} + + +// --- additional RCC constants + +#define RCC_CFGR_PLLSRC_HSI (0 << RCC_CFGR_PLLSRC_Pos) +#define RCC_CFGR_PLLSRC_HSE (1 << RCC_CFGR_PLLSRC_Pos) + +// --- additional SysTick constants + +#define SysTick_CTRL_CLKSOURCE_AHB_DIV8 (0 << SysTick_CTRL_CLKSOURCE_Pos) +#define SysTick_CTRL_CLKSOURCE_AHB (1 << SysTick_CTRL_CLKSOURCE_Pos) + +// --- additional GPIO constants + +#define GPIO_CNF_INPUT_ANALOG 0 +#define GPIO_CNF_INPUT_FLOAT 1 +#define GPIO_CNF_INPUT_PUPD 2 +#define GPIO_CNF_OUTPUT_PUSH_PULL 0 +#define GPIO_CNF_OUTPUT_OPEN_DRAIN 1 +#define GPIO_CNF_OUTPUT_ALT_PUSH_PULL 2 +#define GPIO_CNG_OUTPUT_ALT_OPEN_DRAIN 3 + +#define GPIO_MODE_INPUT 0 +#define GPIO_MODE_OUTPUT_10_MHZ 1 +#define GPIO_MODE_OUTPUT_2_MHZ 2 +#define GPIO_MODE_OUTPUT_50_MHZ 3 + + +static inline void rcc_wait_for_osc_ready(uint32_t rcc_cr_clk_rdy) { + while (get_reg(&RCC->CR, rcc_cr_clk_rdy) == 0) + ; +} + + +static void gpio_set_mode(GPIO_TypeDef* gpioport, int gpio, uint8_t mode, uint8_t cnf) { + + int offset; + __IO uint32_t* reg; + if (gpio < 8) { + offset = 4 * gpio; + reg = &gpioport->CRL; + } else { + offset = 4 * (gpio - 8); + reg = &gpioport->CRH; + } + + set_reg(reg, ((cnf << 2) | mode) << offset, 0xf << offset); +} + +static inline void gpio_set(GPIO_TypeDef* gpioport, int gpio) { + gpioport->BSRR = 1 << gpio; +} + +static inline void gpio_clear(GPIO_TypeDef* gpioport, int gpio) { + gpioport->BSRR = 1 << (gpio + 16); +} + + +static void rcc_clock_setup_in_hse_8mhz_out_72mhz(void) { + + // Enable internal high-speed oscillator + set_reg(&RCC->CR, RCC_CR_HSION, RCC_CR_HSION_Msk); + rcc_wait_for_osc_ready(RCC_CR_HSIRDY); + + // Select HSI as SYSCLK source + set_reg(&RCC->CFGR, RCC_CFGR_SW_HSI, RCC_CFGR_SW_Msk); + + // Enable external high-speed oscillator 8MHz + set_reg(&RCC->CR, RCC_CR_HSEON, RCC_CR_HSEON_Msk); + rcc_wait_for_osc_ready(RCC_CR_HSERDY); + set_reg(&RCC->CFGR, RCC_CFGR_SW_HSE, RCC_CFGR_SW_Msk); + + // Set prescalers for AHB, ADC, APB1, APB2 + set_reg(&RCC->CFGR, RCC_CFGR_HPRE_DIV1 | RCC_CFGR_ADCPRE_DIV8 | RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_PPRE2_DIV1, + RCC_CFGR_HPRE_Msk | RCC_CFGR_ADCPRE_Msk | RCC_CFGR_PPRE1_Msk | RCC_CFGR_PPRE2_Msk); + + // System clock of 72 MHz requires 2 wait states + set_reg(&FLASH->ACR, FLASH_ACR_LATENCY_2, FLASH_ACR_LATENCY_Msk); + + // PLL multiplier 9 (for 72 MHz), HSE as PLL source, no clock predevision + set_reg(&RCC->CFGR, RCC_CFGR_PLLMULL9 | RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLXTPRE_HSE, + RCC_CFGR_PLLMULL_Msk | RCC_CFGR_PLLSRC_Msk | RCC_CFGR_PLLXTPRE_Msk); + + // Enable PLL oscillator and wait for it to stabilize + set_reg(&RCC->CR, RCC_CR_PLLON, RCC_CR_PLLON_Msk); + rcc_wait_for_osc_ready(RCC_CR_PLLRDY); + + // Select PLL as SYSCLK source + set_reg(&RCC->CFGR, RCC_CFGR_SW_PLL, RCC_CFGR_SW_Msk); + + // Update the SystemCoreClock variable used by TinyUSB + SystemCoreClockUpdate(); +} + +static volatile uint32_t millis_count; + +static void systick_init(void) { + + // Initialize SysTick + set_reg(&SysTick->CTRL, SysTick_CTRL_CLKSOURCE_AHB_DIV8, SysTick_CTRL_CLKSOURCE_Msk); + SysTick->LOAD = SystemCoreClock / 8 / 1000 - 1; + + // Enable and start + set_reg(&SysTick->CTRL, SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk, + SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk); +} + + +// --- Serial number --- + +char board_serial_num[13]; + +const static char HEX_DIGITS[] = "0123456789ABCDEF"; + +void put_hex(uint32_t value, char *buf, int len) { + for (int idx = 0; idx < len; idx++) { + buf[idx] = HEX_DIGITS[value >> 28]; + value = value << 4; + } +} + +void usb_init_serial_num() { + __I uint32_t* unique_id =(__I uint32_t*) UID_BASE; + uint32_t id0 = unique_id[0]; + uint32_t id1 = unique_id[1]; + uint32_t id2 = unique_id[2]; + + id0 += id2; + + put_hex(id0, board_serial_num, 8); + put_hex(id1, board_serial_num + 8, 4); + board_serial_num[12] = 0; +} + + +// --- Exported board functions + +void board_init(void) { + + rcc_clock_setup_in_hse_8mhz_out_72mhz(); + systick_init(); + + // clock for GPIOA (USB pins) + RCC->APB2ENR |= RCC_APB2ENR_IOPAEN_Msk; + // clock for GPIOB (LED) + RCC->APB2ENR |= RCC_APB2ENR_IOPBEN_Msk; + // clock for USB + RCC->APB1ENR |= RCC_APB1ENR_USBEN_Msk; + + // LED + gpio_set_mode(GPIOB, 12, GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSH_PULL); + + usb_init_serial_num(); +} + +uint32_t board_millis(void) { + return millis_count; +} + +void board_led_write(bool on) { + if (on) + gpio_set(GPIOB, 12); + else + gpio_clear(GPIOB, 12); +} + + +// --- Interrupt handlers --- + +void SysTick_Handler (void) { + millis_count++; +} + +void USBWakeUp_IRQHandler(void) { + tud_int_handler(0); +} + +void USB_HP_IRQHandler(void) { + tud_int_handler(0); +} + +void USB_LP_IRQHandler(void) { + tud_int_handler(0); +} + +#endif diff --git a/test-devices/loopback-stm32/src/board_f4.c b/test-devices/loopback-stm32/src/board_f4.c new file mode 100644 index 00000000..6f83803f --- /dev/null +++ b/test-devices/loopback-stm32/src/board_f4.c @@ -0,0 +1,281 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Board specific code for STM32F4 family +// + +#if defined(STM32F4xx) + +#include +#include "stm32f4xx.h" +#include "device/usbd.h" + +extern uint32_t SystemCoreClock; +void SystemCoreClockUpdate(void); + + +static inline uint32_t get_reg(__I uint32_t* reg, uint32_t mask) { + return *reg & mask; +} + +static inline void set_reg(__IO uint32_t* reg, uint32_t value, uint32_t mask) { + *reg = (*reg & ~mask) | (value & mask); +} + + +// --- additional PWR constants + +#define PWR_CR_VOS_SCALE3 (1 << PWR_CR_VOS_Pos) +#define PWR_CR_VOS_SCALE2 (2 << PWR_CR_VOS_Pos) +#define PWR_CR_VOS_SCALE1 (3 << PWR_CR_VOS_Pos) + + +// --- additional RCC constants + +typedef struct rcc_clock_setup { + uint8_t pllm; + uint16_t plln; + uint8_t pllp; + uint8_t pllq; + uint32_t pll_source; + uint32_t flash_config; + uint32_t hpre; + uint32_t ppre1; + uint32_t ppre2; + uint32_t voltage_scale; +} rcc_clock_setup_t; + +const rcc_clock_setup_t clock_setup_hse_value_out_84mhz_3v3 = { + .pllm = HSE_VALUE / 1000000, + .plln = 336, + .pllp = 4, + .pllq = 7, + .pll_source = RCC_PLLCFGR_PLLSRC_HSE, + .hpre = RCC_CFGR_HPRE_DIV1, + .ppre1 = RCC_CFGR_PPRE1_DIV2, + .ppre2 = RCC_CFGR_PPRE2_DIV1, + .voltage_scale = PWR_CR_VOS_SCALE1, + .flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_2WS +}; + +// --- additional SysTick constants + +#define SysTick_CTRL_CLKSOURCE_AHB_DIV8 (0 << SysTick_CTRL_CLKSOURCE_Pos) +#define SysTick_CTRL_CLKSOURCE_AHB (1 << SysTick_CTRL_CLKSOURCE_Pos) + +// --- additional GPIO constants + +#define GPIO_PUPD_NO_PULL 0 +#define GPIO_PUPD_PULL_UP 1 +#define GPIO_PUPD_PULL_DOWN 2 + +#define GPIO_MODE_INPUT 0 +#define GPIO_MODE_OUTPUT 1 +#define GPIO_MODE_ALT 2 +#define GPIO_MODE_ANALOG 3 + +#define GPIO_OSPEED_LOW 0 +#define GPIO_OSPEED_MEDIUM 1 +#define GPIO_OSPEED_FAST 2 +#define GPIO_OSPEED_HIGH 3 + + +static inline void rcc_wait_for_osc_ready(uint32_t rcc_cr_clk_rdy) { + while (get_reg(&RCC->CR, rcc_cr_clk_rdy) == 0) + ; +} + +static void gpio_mode_setup(GPIO_TypeDef* gpioport, int gpio, uint8_t mode, uint8_t pull_up_down) { + + int offset = gpio * 2; + set_reg(&gpioport->PUPDR, pull_up_down << offset, 3 << offset); + set_reg(&gpioport->MODER, mode << offset, 3 << offset); +} + +void gpio_set_af(GPIO_TypeDef* gpioport, int gpio, uint8_t alt_func_num) { + + int offset = 4 * gpio; + __IO uint32_t* reg; + if (offset < 32) { + reg = gpioport->AFR; + } else { + reg = gpioport->AFR + 1; + offset -= 32; + } + + set_reg(reg, alt_func_num << offset, 0xf << offset); +} + +static inline void gpio_set_ospeed(GPIO_TypeDef* gpioport, int gpio, uint8_t ospeed) { + int offset = gpio * 2; + set_reg(&gpioport->OSPEEDR, ospeed << offset, 3 << offset); +} + +static inline void gpio_set(GPIO_TypeDef* gpioport, int gpio) { + gpioport->BSRR = 1 << gpio; +} + +static inline void gpio_clear(GPIO_TypeDef* gpioport, int gpio) { + gpioport->BSRR = 1 << (gpio + 16); +} + + +static void rcc_clock_setup_pll(const rcc_clock_setup_t* setup) { + + // Enable internal high-speed oscillator (HSI) + set_reg(&RCC->CR, RCC_CR_HSION, RCC_CR_HSION_Msk); + rcc_wait_for_osc_ready(RCC_CR_HSIRDY); + + // Select HSI as SYSCLK source + set_reg(&RCC->CFGR, RCC_CFGR_SW_HSI, RCC_CFGR_SW_Msk); + + // Enable external high-speed oscillator (HSE) + if (setup->pll_source == RCC_PLLCFGR_PLLSRC_HSE) { + set_reg(&RCC->CR, RCC_CR_HSEON, RCC_CR_HSEON_Msk); + rcc_wait_for_osc_ready(RCC_CR_HSERDY); + } + + // Set the VOS scale mode + set_reg(&RCC->APB1ENR, RCC_APB1ENR_PWREN, RCC_APB1ENR_PWREN_Msk); + set_reg(&PWR->CR, setup->voltage_scale, PWR_CR_VOS_Msk); + + // Set prescalers for AHB, APB1, APB2 + set_reg(&RCC->CFGR, setup->hpre | setup->ppre1 | setup->ppre2, + RCC_CFGR_HPRE_Msk | RCC_CFGR_PPRE1_Msk | RCC_CFGR_PPRE2_Msk); + + // Disable PLL oscillator before changing its configuration + set_reg(&RCC->CR, 0, RCC_CR_PLLON_Msk); + + // Configure the PLL oscillator + int pllp_val = (setup->pllp >> 1) - 1; + RCC->PLLCFGR = setup->pll_source + | (setup->pllm << RCC_PLLCFGR_PLLM_Pos) + | (setup->plln << RCC_PLLCFGR_PLLN_Pos) + | (pllp_val << RCC_PLLCFGR_PLLP_Pos) + | (setup->pllq << RCC_PLLCFGR_PLLQ_Pos); + + // Enable PLL oscillator and wait for it to stabilize + set_reg(&RCC->CR, RCC_CR_PLLON, RCC_CR_PLLON_Msk); + rcc_wait_for_osc_ready(RCC_CR_PLLRDY); + + // Configure flash settings + set_reg(&FLASH->ACR, setup->flash_config, FLASH_ACR_DCEN_Msk | FLASH_ACR_ICEN_Msk | FLASH_ACR_LATENCY_Msk); + + // Select PLL as SYSCLK source + set_reg(&RCC->CFGR, RCC_CFGR_SW_PLL, RCC_CFGR_SW_Msk); + + // Wait for PLL clock to be selected + while (get_reg(&RCC->CFGR, RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL) + ; + + // Disable internal high-speed oscillator + if (setup->pll_source == RCC_PLLCFGR_PLLSRC_HSE) + set_reg(&RCC->CR, 0, RCC_CR_HSION_Msk); + + // Update the SystemCoreClock variable used by TinyUSB + SystemCoreClockUpdate(); +} + +static volatile uint32_t millis_count; + +static void systick_init(void) { + + // Initialize SysTick + SysTick->CTRL = (SysTick->CTRL & ~SysTick_CTRL_CLKSOURCE_Msk) | SysTick_CTRL_CLKSOURCE_AHB_DIV8; + SysTick->LOAD = SystemCoreClock / 8 / 1000 - 1; + + // Enable and start + SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; + SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; +} + + +// --- Serial number --- + +char board_serial_num[13]; + +const static char HEX_DIGITS[] = "0123456789ABCDEF"; + +static void put_hex(uint32_t value, char *buf, int len) { + for (int idx = 0; idx < len; idx++) { + buf[idx] = HEX_DIGITS[value >> 28]; + value = value << 4; + } +} + +static void usb_init_serial_num() { + __I uint32_t* unique_id =(__I uint32_t*) UID_BASE; + uint32_t id0 = unique_id[0]; + uint32_t id1 = unique_id[1]; + uint32_t id2 = unique_id[2]; + + id0 += id2; + + put_hex(id0, board_serial_num, 8); + put_hex(id1, board_serial_num + 8, 4); + board_serial_num[12] = 0; +} + + +// --- Exported board functions + +void board_init(void) { + + rcc_clock_setup_pll(&clock_setup_hse_value_out_84mhz_3v3); + systick_init(); + + // clock for GPIOA (USB pins) + set_reg(&RCC->AHB1ENR, RCC_AHB1ENR_GPIOAEN, RCC_AHB1ENR_GPIOAEN_Msk); + + // Configure USB D+/D- pins + gpio_mode_setup(GPIOA, 11, GPIO_MODE_ALT, GPIO_PUPD_NO_PULL); + gpio_set_af(GPIOA, 11, 10); + gpio_set_ospeed(GPIOA, 11, GPIO_OSPEED_HIGH); + gpio_mode_setup(GPIOA, 12, GPIO_MODE_ALT, GPIO_PUPD_NO_PULL); + gpio_set_af(GPIOA, 12, 10); + gpio_set_ospeed(GPIOA, 12, GPIO_OSPEED_HIGH); + + // clock for USB + set_reg(&RCC->AHB2ENR, RCC_AHB2ENR_OTGFSEN, RCC_AHB2ENR_OTGFSEN_Msk); + + // Disable VBUS sense + set_reg(&USB_OTG_FS->GCCFG, USB_OTG_GCCFG_NOVBUSSENS, + USB_OTG_GCCFG_NOVBUSSENS_Msk | USB_OTG_GCCFG_VBUSASEN_Msk | USB_OTG_GCCFG_VBUSBSEN_Msk); + + // clock for GPIOC (LED) + set_reg(&RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN, RCC_AHB1ENR_GPIOCEN_Msk); + + // LED pin + gpio_mode_setup(GPIOC, 13, GPIO_MODE_OUTPUT, GPIO_PUPD_NO_PULL); + + usb_init_serial_num(); +} + +uint32_t board_millis(void) { + return millis_count; +} + +void board_led_write(bool on) { + if (on) + gpio_set(GPIOC, 13); + else + gpio_clear(GPIOC, 13); +} + + +// --- Interrupt handlers --- + +void SysTick_Handler (void) { + millis_count++; +} + +void OTG_FS_IRQHandler(void) { + tud_int_handler(0); +} + +#endif diff --git a/test-devices/loopback-stm32/src/common.cpp b/test-devices/loopback-stm32/src/common.cpp deleted file mode 100644 index 5102b6bd..00000000 --- a/test-devices/loopback-stm32/src/common.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Commmon functions -// - -#include "common.h" - -#include - -static volatile uint32_t millis_count; - -uint32_t millis() { return millis_count; } - -void delay(uint32_t ms) { - int32_t target_time = millis_count + ms; - while (target_time - (int32_t)millis_count > 0) - ; -} - -void systick_init() { - // Initialize SysTick - systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); - systick_set_reload(rcc_ahb_frequency / 8 / 1000 - 1); - - // Enable and start - systick_interrupt_enable(); - systick_counter_enable(); -} - -// System tick timer interrupt handler -extern "C" void sys_tick_handler() { millis_count++; } diff --git a/test-devices/loopback-stm32/src/main.c b/test-devices/loopback-stm32/src/main.c new file mode 100644 index 00000000..9771dba1 --- /dev/null +++ b/test-devices/loopback-stm32/src/main.c @@ -0,0 +1,234 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Board specific function (HAL) +// + +#include +#include +#include + +#include "board.h" +#include "tusb.h" +#include "usb_descriptors.h" +#include "vendor_custom.h" + +// FIFO buffer for loopback data +tu_fifo_t loopback_fifo; +uint8_t loopback_buffer[512]; + +// RX buffer for loopback +uint8_t loopback_rx_buffer[64]; + +// buffer for echoed packet +uint8_t echo_buffer[16]; +int num_echos; + + +// Blink durations +enum { + BLINK_NOT_MOUNTED = 250, + BLINK_MOUNTED = 1000, + BLINK_SUSPENDED = 2500, +}; + +static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; + +static void led_blinking_task(void); +static void loopback_init(void); +static void loopback_check_rx(void); +static void loopback_check_tx(void); + + +int main(void) { + + board_init(); + loopback_init(); + + // init device stack + tud_init(BOARD_TUD_RHPORT); + + while (1) { + tud_task(); + led_blinking_task(); + } + + return 0; +} + +// --- Loopback + +void loopback_init(void) { + tu_fifo_config(&loopback_fifo, loopback_buffer, sizeof(loopback_buffer), 1, false); +} + +// Check if the next transmission should be started +void loopback_check_tx(void) { + + tu_fifo_buffer_info_t info; + tu_fifo_get_read_info(&loopback_fifo, &info); + + if (info.len_lin > 0 && !cust_vendor_is_transmitting(EP_LOOPBACK_TX)) { + int n = info.len_lin; + if (n > 128) + n = 128; + + cust_vendor_start_transmit(EP_LOOPBACK_TX, info.ptr_lin, n); + } +} + +// Check if receiving should be started again +void loopback_check_rx(void) { + + int n = tu_fifo_remaining(&loopback_fifo); + if (n >= sizeof(loopback_rx_buffer) && !cust_vendor_is_receiving(EP_LOOPBACK_RX)) { + + cust_vendor_prepare_recv(EP_LOOPBACK_RX, loopback_rx_buffer, sizeof(loopback_rx_buffer)); + } +} + + +// --- Vendor class callbacks + +// Invoked when new data has been received +void cust_vendor_rx_cb(uint8_t ep_addr, uint32_t recv_bytes) { + if (ep_addr == EP_LOOPBACK_RX) { + tu_fifo_write_n(&loopback_fifo, loopback_rx_buffer, recv_bytes); + loopback_check_rx(); + loopback_check_tx(); + + } else if (ep_addr == EP_ECHO_RX) { + num_echos = 2; + cust_vendor_start_transmit(EP_ECHO_TX, echo_buffer, recv_bytes); + } +} + +// Invoked when last tx transfer finished +void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes) { + if (ep_addr == EP_LOOPBACK_TX) { + tu_fifo_advance_read_pointer(&loopback_fifo, sent_bytes); + loopback_check_tx(); + loopback_check_rx(); + + } else if (ep_addr == EP_ECHO_TX) { + num_echos--; + if (num_echos > 0) { + cust_vendor_start_transmit(EP_ECHO_TX, echo_buffer, sent_bytes); + } else { + cust_vendor_prepare_recv(EP_ECHO_RX, echo_buffer, sizeof(echo_buffer)); + } + } +} + +// Invoked when interface has been opened +void cust_vendor_intf_open_cb(uint8_t intf) { + loopback_check_rx(); + cust_vendor_prepare_recv(EP_ECHO_RX, echo_buffer, sizeof(echo_buffer)); +} + + + +// --- Control messages (see README) + +static uint32_t saved_value = 0; + +bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) { + if (stage != CONTROL_STAGE_SETUP) + return true; // nothing to do + + if (request->bmRequestType_bit.type != TUSB_REQ_TYPE_VENDOR) + return false; // stall unknown request + + switch (request->bRequest) { + + case 0x01: + if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 0) { + // save value from wValue + saved_value = request->wValue; + return tud_control_status(rhport, request); + } + break; + + case 0x02: + if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 4) { + // receive into `saved_value` + return tud_control_xfer(rhport, request, &saved_value, 4); + } + break; + + case 0x03: + if (request->bmRequestType_bit.direction == TUSB_DIR_IN && request->wLength == 4) { + // transmit from `saved_value` + return tud_control_xfer(rhport, request, &saved_value, 4); + } + break; + + // Microsoft WCID descriptor (for automatic WinUSB installation) + case WCID_VENDOR_CODE: + if (request->bmRequestType_bit.direction == TUSB_DIR_IN && request->wIndex == 0x0004) { + // transmit WCID feature descriptor + int len = sizeof(wcid_feature_desc); + if (len >= request->wLength) + len = request->wLength; + return tud_control_xfer(rhport, request, (void*) wcid_feature_desc, len); + } + + default: + break; + } + + // stall unknown request + return false; +} + +// --- Device callbacks + +// Register additional driver +usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) { + *driver_count = 1; + return &cust_vendor_driver; +} + + +// Invoked when device is mounted +void tud_mount_cb(void) { + blink_interval_ms = BLINK_MOUNTED; +} + +// Invoked when device is unmounted +void tud_umount_cb(void) { + blink_interval_ms = BLINK_NOT_MOUNTED; +} + +// Invoked when usb bus is suspended +// remote_wakeup_en: if host allow us to perform remote wakeup +// Within 7ms, device must draw an average of current less than 2.5 mA from bus +void tud_suspend_cb(bool remote_wakeup_en) { + (void) remote_wakeup_en; + blink_interval_ms = BLINK_SUSPENDED; +} + +// Invoked when usb bus is resumed +void tud_resume_cb(void) { + blink_interval_ms = BLINK_MOUNTED; +} + +// --- LED blinking --- + +void led_blinking_task(void) { + static uint32_t start_ms = 0; + static bool led_state = false; + + // Blink every interval ms + if ( board_millis() - start_ms < blink_interval_ms) + return; // not enough time + start_ms += blink_interval_ms; + + board_led_write(led_state); + led_state = 1 - led_state; // toggle +} diff --git a/test-devices/loopback-stm32/src/main.cpp b/test-devices/loopback-stm32/src/main.cpp deleted file mode 100644 index 8d049e4a..00000000 --- a/test-devices/loopback-stm32/src/main.cpp +++ /dev/null @@ -1,233 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Main program -// - -#include -#include -#include -#include - -#include - -#include "circ_buf.h" -#include "common.h" -#include "usb_descriptor.h" -#include "wcid.h" - -static void on_usb_set_config(usbd_device *usbd_dev, uint16_t wValue); -static usbd_request_return_codes on_usb_control_request(usbd_device *usbd_dev, usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete); -static void on_usb_loopback_received(usbd_device *usbd_dev, uint8_t ep); -static void on_usb_loopback_transmitted(usbd_device *usbd_dev, uint8_t ep); -static void on_usb_echo_received(usbd_device *usbd_dev, uint8_t ep); -static void on_usb_echo_transmitted(usbd_device *usbd_dev, uint8_t ep); -static void check_buffers(); - -// USB device instance -static usbd_device *usb_device; - -// buffer for control requests -static uint8_t usbd_control_buffer[256]; - -// Circular buffer for data -static circ_buf<1024> buffer; - -// Minimum free space in circular buffer for requesting more packets -static constexpr int MIN_FREE_SPACE = 2 * BULK_MAX_PACKET_SIZE; - -// indicates if loopback data is being transmitted -static bool is_loopback_tx = false; - -// indicates if the loopback RX endpoint is forced to NAK to prevent receiving further data -static bool is_loopback_rx_nak = false; - -// value that can be saved and retrieved with control requests -static uint32_t saved_value; - -// echo message -static char echo_msg[INTR_MAX_PACKET_SIZE]; - -// echo message length -static int echo_msg_len; - -// number of echos left to transmit (if > 1, RX endpointed is NAKed) -static int num_echos_left; - - -void init() { - // Enable required clocks - rcc_clock_setup_in_hse_8mhz_out_72mhz(); - rcc_periph_clock_enable(RCC_GPIOA); - rcc_periph_clock_enable(RCC_GPIOC); - rcc_periph_clock_enable(RCC_AFIO); - rcc_periph_clock_enable(RCC_SPI1); - rcc_periph_clock_enable(RCC_USB); - - // Initialize systick services - systick_init(); -} - -void usb_init() { - // reset USB peripheral - rcc_periph_reset_pulse(RST_USB); - - // Pull USB D+ (A12) low for 80ms to trigger device reenumeration - gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO12); - gpio_clear(GPIOA, GPIO12); - delay(80); - - usb_init_serial_num(); - - // create USB device - usb_device = usbd_init(&st_usbfs_v1_usb_driver, &usb_device_desc, usb_config_descs, usb_desc_strings, - sizeof(usb_desc_strings) / sizeof(usb_desc_strings[0]), usbd_control_buffer, - sizeof(usbd_control_buffer)); - - // Set callback for config calls - usbd_register_set_config_callback(usb_device, on_usb_set_config); - register_wcid_desc(usb_device); -} - -// Called when the host connects to the device and selects a configuration -void on_usb_set_config(usbd_device *usbd_dev, __attribute__((unused)) uint16_t wValue) { - register_wcid_desc(usbd_dev); - usbd_register_control_callback(usbd_dev, - USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_INTERFACE, - USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - on_usb_control_request); - usbd_ep_setup(usbd_dev, EP_LOOPBACK_RX, USB_ENDPOINT_ATTR_BULK, BULK_MAX_PACKET_SIZE, on_usb_loopback_received); - usbd_ep_setup(usbd_dev, EP_LOOPBACK_TX, USB_ENDPOINT_ATTR_BULK, BULK_MAX_PACKET_SIZE, on_usb_loopback_transmitted); - usbd_ep_setup(usbd_dev, EP_ECHO_RX, USB_ENDPOINT_ATTR_INTERRUPT, INTR_MAX_PACKET_SIZE, on_usb_echo_received); - usbd_ep_setup(usbd_dev, EP_ECHO_TX, USB_ENDPOINT_ATTR_INTERRUPT, INTR_MAX_PACKET_SIZE, on_usb_echo_transmitted); - - buffer.reset(); - is_loopback_tx = false; - is_loopback_rx_nak = false; - num_echos_left = 0; - echo_msg_len = 0; - saved_value = 0; -} - -// Called when loopback data has been received -void on_usb_loopback_received(usbd_device *usbd_dev, uint8_t ep) { - // Retrieve USB data (has side effect of setting endpoint to VALID) - uint8_t packet[BULK_MAX_PACKET_SIZE] __attribute__((aligned(4))); - int len = usbd_ep_read_packet(usbd_dev, ep, packet, sizeof(packet)); - - // copy data into circular buffer - buffer.add_data(packet, len); - -} - -// Called when loopback data has been transmitted -void on_usb_loopback_transmitted(__attribute__((unused)) usbd_device *usbd_dev, __attribute__((unused)) uint8_t ep) { - is_loopback_tx = false; -} - -void check_buffers() { - - // If RX is stopped and there is sufficient space in the buffer, resume it - if (is_loopback_rx_nak) { - if (buffer.avail_size() >= MIN_FREE_SPACE) { - usbd_ep_nak_set(usb_device, EP_LOOPBACK_RX, 0); - is_loopback_rx_nak = false; - } - - // If RX is enabled but the space in the buffer is low, stop it - } else { - // check if there is space for less than 2 packets - if (buffer.avail_size() < MIN_FREE_SPACE) { - // set endpoint from VALID to NAK - usbd_ep_nak_set(usb_device, EP_LOOPBACK_RX, 1); - is_loopback_rx_nak = true; - } - } - - // If no data is being transmitted and there is data in the buffer, transmit a packet - if (!is_loopback_tx && buffer.data_size() >= 0) { - uint8_t packet[BULK_MAX_PACKET_SIZE] __attribute__((aligned(4))); - int len = buffer.get_data(packet, BULK_MAX_PACKET_SIZE); - usbd_ep_write_packet(usb_device, EP_LOOPBACK_TX, packet, len); - is_loopback_tx = true; - } -} - -// Called when echo data has been received -void on_usb_echo_received(usbd_device *usbd_dev,uint8_t ep) { - // Retrieve USB data (has side effect of setting endpoint to VALID) - echo_msg_len = usbd_ep_read_packet(usbd_dev, EP_ECHO_RX, echo_msg, sizeof(echo_msg)); - usbd_ep_nak_set(usbd_dev, ep, 1); - - usbd_ep_write_packet(usbd_dev, EP_ECHO_TX, echo_msg, echo_msg_len); - num_echos_left = 2; -} - -// Called when echo data has been transmitted -void on_usb_echo_transmitted(__attribute__((unused)) usbd_device *usbd_dev, __attribute__((unused)) uint8_t ep) { - num_echos_left--; - if (num_echos_left > 0) { - usbd_ep_write_packet(usbd_dev, ep, echo_msg, echo_msg_len); - } else { - usbd_ep_nak_set(usbd_dev, EP_ECHO_RX, 0); - } -} - - -usbd_request_return_codes on_usb_control_request( - __attribute__((unused)) usbd_device *usbd_dev, usb_setup_data *req, - uint8_t **buf, uint16_t *len, __attribute__((unused)) usbd_control_complete_callback *complete) { - - switch (req->bRequest) { - case 1: - if (req->wIndex == 0 && req->wLength == 0) { - saved_value = req->wValue; - return USBD_REQ_HANDLED; - } else { - return USBD_REQ_NOTSUPP; - } - break; - - case 2: - if (req->wIndex == 0 && req->wLength == 4) { - uint32_t* value = reinterpret_cast(*buf); - saved_value = *value; - return USBD_REQ_HANDLED; - } else { - return USBD_REQ_NOTSUPP; - } - break; - - case 3: - if (req->wIndex == 0) { - uint8_t* value = reinterpret_cast(&saved_value); - *len = std::min(*len, (uint16_t) 4); - memcpy(*buf, value, *len); - return USBD_REQ_HANDLED; - } else { - return USBD_REQ_NOTSUPP; - } - break; - - default: - ; // fall through - } - - return USBD_REQ_NEXT_CALLBACK; -} - - -int main() { - init(); - usb_init(); - - while (true) { - usbd_poll(usb_device); - check_buffers(); - } -} diff --git a/test-devices/loopback-stm32/src/usb_descriptor.cpp b/test-devices/loopback-stm32/src/usb_descriptor.cpp deleted file mode 100644 index 7c26184c..00000000 --- a/test-devices/loopback-stm32/src/usb_descriptor.cpp +++ /dev/null @@ -1,158 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// USB descriptor -// - -#include "usb_descriptor.h" - -#include - -static void put_hex(uint32_t value, char *buf, int len); - -#define USB_VID 0xcafe // Vendor ID -#define USB_PID 0xceaf // Product ID -#define USB_DEVICE_REL 0x0071 // release 0.7.1 - -// Interface index -#define INTF_LOOPBACK 0 - -static char serial_num[13]; - -const char *const usb_desc_strings[] = { - "JavaDoesUSB", // USB Manufacturer - "Loopback", // USB Product - serial_num, // Serial number -}; - -enum usb_strings_index { // Index of USB strings. Must sync with above, starts from 1. - USB_STRINGS_MANUFACTURER_ID = 1, - USB_STRINGS_PRODUCT_ID, - USB_STRINGS_SERIAL_NUMBER_ID, -}; - -static const struct usb_endpoint_descriptor comm_endpoint_descs[] = { - { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_LOOPBACK_RX, - .bmAttributes = USB_ENDPOINT_ATTR_BULK, - .wMaxPacketSize = BULK_MAX_PACKET_SIZE, - .bInterval = 0, - .extra = nullptr, - .extralen = 0, - }, - { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_LOOPBACK_TX, - .bmAttributes = USB_ENDPOINT_ATTR_BULK, - .wMaxPacketSize = BULK_MAX_PACKET_SIZE, - .bInterval = 0, - .extra = nullptr, - .extralen = 0, - }, - { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_ECHO_RX, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = INTR_MAX_PACKET_SIZE, - .bInterval = 16, - .extra = nullptr, - .extralen = 0, - }, - { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_ECHO_TX, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = INTR_MAX_PACKET_SIZE, - .bInterval = 16, - .extra = nullptr, - .extralen = 0, - }, -}; - -static const struct usb_interface_descriptor comm_if_descs[] = { - { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = INTF_LOOPBACK, - .bAlternateSetting = 0, - .bNumEndpoints = sizeof(comm_endpoint_descs) / sizeof(comm_endpoint_descs[0]), - .bInterfaceClass = USB_CLASS_VENDOR, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, // vendor specific - .iInterface = 0, - .endpoint = comm_endpoint_descs, - .extra = nullptr, - .extralen = 0, - }, -}; - -static const struct usb_interface usb_interfaces[] = { - { - .cur_altsetting = nullptr, - .num_altsetting = sizeof(comm_if_descs) / sizeof(comm_if_descs[0]), - .iface_assoc = nullptr, - .altsetting = comm_if_descs, - }, -}; - -const struct usb_config_descriptor usb_config_descs[] = { - { - .bLength = USB_DT_CONFIGURATION_SIZE, - .bDescriptorType = USB_DT_CONFIGURATION, - .wTotalLength = 0, - .bNumInterfaces = sizeof(usb_interfaces) / sizeof(usb_interfaces[0]), - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = 0x80, // bus-powered, i.e. it draws power from USB bus - .bMaxPower = 0xfa, // 500 mA - .interface = usb_interfaces, - }, -}; - -const struct usb_device_descriptor usb_device_desc = { - .bLength = USB_DT_DEVICE_SIZE, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0200, // USB version 2.00 - .bDeviceClass = USB_CLASS_VENDOR, - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, // no class specific protocol - .bMaxPacketSize0 = BULK_MAX_PACKET_SIZE, - .idVendor = USB_VID, - .idProduct = USB_PID, - .bcdDevice = USB_DEVICE_REL, - .iManufacturer = USB_STRINGS_MANUFACTURER_ID, - .iProduct = USB_STRINGS_PRODUCT_ID, - .iSerialNumber = USB_STRINGS_SERIAL_NUMBER_ID, - .bNumConfigurations = sizeof(usb_config_descs) / sizeof(usb_config_descs[0]), -}; - -void usb_init_serial_num() { - uint32_t id0 = DESIG_UNIQUE_ID0; - uint32_t id1 = DESIG_UNIQUE_ID1; - uint32_t id2 = DESIG_UNIQUE_ID2; - - id0 += id2; - - put_hex(id0, serial_num, 8); - put_hex(id1, serial_num + 8, 4); - serial_num[12] = 0; -} - -const static char HEX_DIGITS[] = "0123456789ABCDEF"; - -void put_hex(uint32_t value, char *buf, int len) { - for (int idx = 0; idx < len; idx++) { - buf[idx] = HEX_DIGITS[value >> 28]; - value = value << 4; - } -} diff --git a/test-devices/loopback-stm32/src/usb_descriptors.c b/test-devices/loopback-stm32/src/usb_descriptors.c new file mode 100644 index 00000000..79120672 --- /dev/null +++ b/test-devices/loopback-stm32/src/usb_descriptors.c @@ -0,0 +1,151 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Board specific function (HAL) +// + +#include "usb_descriptors.h" + +#include "board.h" +#include "tusb.h" +#include "vendor_custom.h" + + +// --- Device Descriptor --- + +tusb_desc_device_t const desc_device = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + + .bDeviceClass = TUSB_CLASS_VENDOR_SPECIFIC, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + + .idVendor = 0xCAFE, + .idProduct = 0xCEAF, + .bcdDevice = 0x0071, // version 0.7.1 + + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + + .bNumConfigurations = 0x01 +}; + +// Invoked when a GET DEVICE DESCRIPTOR request is received. +// Return a pointer to the descriptor. +uint8_t const* tud_descriptor_device_cb(void) { + return (uint8_t const*)&desc_device; +} + + +// --- Configuration Descriptor --- + +enum { + INTF_LOOPBACK = 0, + INTF_NUM_TOTAL +}; + +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + 9 + 7 + 7 + 7 + 7) + +uint8_t const desc_configuration[] = { + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, INTF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 500), + // Loopback interface + CUSTOM_VENDOR_INTERFACE(0, 4), + // Loopback endpoint OUT + CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_RX, BULK_MAX_PACKET_SIZE), + // Loopback endpoint IN + CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_TX, BULK_MAX_PACKET_SIZE), + // Echo endpoint OUT + CUSTOM_VENDOR_INTERRUPT_ENDPOINT(EP_ECHO_RX, INTR_MAX_PACKET_SIZE, 16), + // Echo endpoint IN + CUSTOM_VENDOR_INTERRUPT_ENDPOINT(EP_ECHO_TX, INTR_MAX_PACKET_SIZE, 16) +}; + +// Invoked when a GET CONFIGURATION DESCRIPTOR request is recieved. +// Return a pointer to descriptor. +// Descriptor contents must exist long enough for transfer to complete +uint8_t const* tud_descriptor_configuration_cb(uint8_t configuration_index) { + (void)configuration_index; + return desc_configuration; +} + + +// --- String Descriptors --- + +// table with strings +const char* const string_table[] = { + 0, // 0 - supported languages (see below) + "JavaDoesUSB", // 1 - manufacturer + "Loopback", // 2 - product + board_serial_num // 3 - serial number +}; + +// Microsoft WCID (Microsoft OS 1.0 Descriptors) string descriptor (for string index 0xee) +// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors +static const uint8_t msft_sig_desc[] = { + 0x12, // length = 18 bytes + TUSB_DESC_STRING, // descriptor type string + 'M', 0, 'S', 0, 'F', 0, 'T', 0, // 'M', 'S', 'F', 'T' + '1', 0, '0', 0, '0', 0, // '1', '0', '0' + WCID_VENDOR_CODE, // vendor code + 0 // padding +}; + + +static uint16_t str_desc_buf[32]; + +// Invoked when a GET STRING DESCRIPTOR request is received. +// Return pointer to string descriptor. +uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) { + (void)langid; + + int str_len; + + if (index == 0) { + str_desc_buf[1] = 0x0409; // US English + str_len = 1; + + } else if (index == 0xee) { + return (const uint16_t*) msft_sig_desc; + + } else { + if (index >= TU_ARRAY_SIZE(string_table)) + return NULL; + + const char* str = string_table[index]; + str_len = strlen(str); + + // Convert ASCII to UTF-16 + for (uint8_t i = 0; i < str_len; i++) + str_desc_buf[1 + i] = str[i]; + } + + // first byte is length (including header), second byte is string type + str_desc_buf[0] = (uint16_t)((2 * str_len + 2) | (TUSB_DESC_STRING << 8)); + + return str_desc_buf; +} + +// --- Microsoft WCID feature descriptor --- + +const uint8_t wcid_feature_desc[] = { + 0x28, 0x00, 0x00, 0x00, // length = 40 bytes + 0x00, 0x01, // version 1.0 (in BCD) + 0x04, 0x00, // compatibility descriptor index 0x0004 + 0x01, // number of sections + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved (7 bytes) + 0x00, // interface number 0 + 0x01, // reserved + 0x57, 0x49, 0x4E, 0x55, 0x53, 0x42, 0x00, 0x00, // Compatible ID "WINUSB\0\0" + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Subcompatible ID (unused) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // reserved 6 bytes +}; diff --git a/test-devices/loopback-stm32/src/vendor_custom.c b/test-devices/loopback-stm32/src/vendor_custom.c new file mode 100644 index 00000000..44b2dc26 --- /dev/null +++ b/test-devices/loopback-stm32/src/vendor_custom.c @@ -0,0 +1,111 @@ +// +// Java Does USB +// Loopback device for testing +// +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// USB driver for interfaces with vendor specific class. +// The interface can have any number of Bulk and Interrupt endpoints. +// + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_VENDOR_ADVANCED) + +#include "device/usbd.h" +#include "vendor_custom.h" + + +static void cv_init(void); +static void cv_reset(uint8_t rhport); +static uint16_t cv_open(uint8_t rhport, tusb_desc_interface_t const* desc_intf, uint16_t max_len); +static bool cv_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); + +const usbd_class_driver_t cust_vendor_driver = { + .init = cv_init, + .reset = cv_reset, + .open = cv_open, + .control_xfer_cb = NULL, + .xfer_cb = cv_xfer_cb, + .sof = NULL +}; + + +void cv_init(void) { + // nothing to do +} + +void cv_reset(uint8_t rhport) { + // nothing to do +} + +uint16_t cv_open(uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t max_len) { + + // return 0 if interface class is not "vendor specific" + TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_intf->bInterfaceClass, 0); + + uint8_t const * p_desc = tu_desc_next(desc_intf); + uint8_t const * desc_end = p_desc + max_len; + int num_endpoints = desc_intf->bNumEndpoints; + + // iterate all endpoints + while (num_endpoints > 0 && p_desc < desc_end) { + + // open endpoint + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; + TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); + + p_desc = tu_desc_next(p_desc); + num_endpoints--; + } + + uint16_t processed_bytes = p_desc - (uint8_t const *) desc_intf; + + cust_vendor_intf_open_cb(desc_intf->bInterfaceNumber); + + return processed_bytes; +} + +bool cv_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { + + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { + cust_vendor_tx_cb(ep_addr, xferred_bytes); + + } else { + cust_vendor_rx_cb(ep_addr, xferred_bytes); + } + + return true; +} + +void cust_vendor_prepare_recv(uint8_t ep_addr, void* buf, uint32_t buf_len) { + + uint8_t const rhport = 0; + + if (usbd_edpt_busy(rhport, ep_addr)) + return; + + usbd_edpt_xfer(rhport, ep_addr, buf, buf_len); +} + +void cust_vendor_start_transmit(uint8_t ep_addr, void const * data, uint32_t data_len) { + + uint8_t const rhport = 0; + + if (usbd_edpt_busy(rhport, ep_addr)) + return; + + usbd_edpt_xfer(rhport, ep_addr, (void*) data, data_len); +} + +bool cust_vendor_is_receiving(uint8_t ep_addr) { + return usbd_edpt_busy(0, ep_addr); +} + +bool cust_vendor_is_transmitting(uint8_t ep_addr) { + return usbd_edpt_busy(0, ep_addr); +} + +#endif diff --git a/test-devices/loopback-stm32/src/wcid.cpp b/test-devices/loopback-stm32/src/wcid.cpp deleted file mode 100644 index 2c284f36..00000000 --- a/test-devices/loopback-stm32/src/wcid.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// -// Java Does USB -// Loopback device for testing -// -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Microsoft WCID descriptors -// - -#include - -#include - -static usbd_request_return_codes msft_string_desc(usbd_device *usbd_dev, usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete); -static usbd_request_return_codes msft_feature_desc(usbd_device *usbd_dev, usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete); - -// Registers additional control request handlers to implement -// See https://github.com/pbatard/libwdi/wiki/WCID-Devices -void register_wcid_desc(usbd_device *usb_dev) { - usbd_register_control_callback(usb_dev, - USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - msft_string_desc); - usbd_register_control_callback(usb_dev, - USB_REQ_TYPE_VENDOR, USB_REQ_TYPE_TYPE, - msft_feature_desc); -} - -#define WCID_VENDOR_CODE 0x37 - -// Microsoft WCID string descriptor (string index 0xee) -static const uint8_t msft_sig_desc[] = { - 0x12, // length = 18 bytes - USB_DT_STRING, // descriptor type string - 'M', 0, 'S', 0, 'F', 0, 'T', 0, // 'M', 'S', 'F', 'T' - '1', 0, '0', 0, '0', 0, // '1', '0', '0' - WCID_VENDOR_CODE, // vendor code - 0 // padding -}; - -// Microsoft WCID feature descriptor (index 0x0004) -static const uint8_t wcid_feature_desc[] = { - 0x28, 0x00, 0x00, 0x00, // length = 40 bytes - 0x00, 0x01, // version 1.0 (in BCD) - 0x04, 0x00, // compatibility descriptor index 0x0004 - 0x01, // number of sections - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved (7 bytes) - 0x00, // interface number 0 - 0x01, // reserved - 0x57, 0x49, 0x4E, 0x55, 0x53, 0x42, 0x00, 0x00, // Compatible ID "WINUSB\0\0" - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Subcompatible ID (unused) - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // reserved 6 bytes -}; - -usbd_request_return_codes msft_string_desc(__attribute__((unused)) usbd_device *usbd_dev, usb_setup_data *req, - uint8_t **buf, uint16_t *len, - __attribute__((unused)) usbd_control_complete_callback *complete) { - // 0x03: descriptor type string - // 0xee: Microsoft WCID string index - if (req->bRequest == USB_REQ_GET_DESCRIPTOR && req->wValue == 0x03ee) { - *buf = const_cast(reinterpret_cast(&msft_sig_desc)); - *len = std::min(*len, (uint16_t)msft_sig_desc[0]); - return USBD_REQ_HANDLED; - } - - return USBD_REQ_NEXT_CALLBACK; -} - -usbd_request_return_codes msft_feature_desc(__attribute__((unused)) usbd_device *usbd_dev, usb_setup_data *req, - uint8_t **buf, uint16_t *len, - __attribute__((unused)) usbd_control_complete_callback *complete) { - // 0x0004: Microsoft WCID index for feature descriptor - if (req->bRequest == WCID_VENDOR_CODE && req->wIndex == 0x0004) { - *buf = const_cast(reinterpret_cast(&wcid_feature_desc)); - *len = std::min(*len, (uint16_t)wcid_feature_desc[0]); - return USBD_REQ_HANDLED; - } - - return USBD_REQ_NEXT_CALLBACK; -} From bdb37419c1b1cda2ea56e2a4d75fe0379873af62 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 7 Oct 2022 21:25:53 +0200 Subject: [PATCH 105/433] Unit tests compatible with new composite device --- .../net/codecrete/usb/DescriptionTest.java | 28 +++++++++++-------- .../codecrete/usb/InterruptTransferTest.java | 4 +++ .../net/codecrete/usb/TestDeviceBase.java | 16 +++++------ 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index d30433b3..6ffff7a9 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -74,9 +74,11 @@ void alternateInterfaceDescriptor_isCorrect() { @Test void endpointDescriptors_areCorrect() { + boolean isLoopbackDevice = testDevice.productId() == PID_LOOPBACK; + var altIntf = testDevice.interfaces().get(interfaceNumber).alternate(); assertNotNull(altIntf.endpoints()); - assertEquals(4, altIntf.endpoints().size()); + assertEquals(isLoopbackDevice ? 4 : 2, altIntf.endpoints().size()); var endpoint = altIntf.endpoints().get(0); assertEquals(1, endpoint.number()); @@ -90,16 +92,18 @@ void endpointDescriptors_areCorrect() { assertEquals(USBTransferType.BULK, endpoint.transferType()); assertEquals(64, endpoint.packetSize()); - endpoint = altIntf.endpoints().get(2); - assertEquals(3, endpoint.number()); - assertEquals(USBDirection.OUT, endpoint.direction()); - assertEquals(USBTransferType.INTERRUPT, endpoint.transferType()); - assertEquals(16, endpoint.packetSize()); - - endpoint = altIntf.endpoints().get(3); - assertEquals(3, endpoint.number()); - assertEquals(USBDirection.IN, endpoint.direction()); - assertEquals(USBTransferType.INTERRUPT, endpoint.transferType()); - assertEquals(16, endpoint.packetSize()); + if (isLoopbackDevice) { + endpoint = altIntf.endpoints().get(2); + assertEquals(3, endpoint.number()); + assertEquals(USBDirection.OUT, endpoint.direction()); + assertEquals(USBTransferType.INTERRUPT, endpoint.transferType()); + assertEquals(16, endpoint.packetSize()); + + endpoint = altIntf.endpoints().get(3); + assertEquals(3, endpoint.number()); + assertEquals(USBDirection.IN, endpoint.direction()); + assertEquals(USBTransferType.INTERRUPT, endpoint.transferType()); + assertEquals(16, endpoint.packetSize()); + } } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java index 6298e637..1d0a0c6d 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java @@ -9,6 +9,7 @@ package net.codecrete.usb; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertArrayEquals; @@ -17,6 +18,9 @@ public class InterruptTransferTest extends TestDeviceBase { @Test void smallTransfer_succeeds() { + Assumptions.assumeTrue(testDevice.productId() == PID_LOOPBACK, + "Interrupt transfer only supported by loopback test device"); + byte[] sampleData = generateRandomBytes(12, 293872394); testDevice.transferOut(ECHO_EP_OUT, sampleData); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index 94275a5e..640f4b9e 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -19,17 +19,17 @@ */ public class TestDeviceBase { /** - * Simple test device vendor ID + * Loopback test device vendor ID */ - static final int VID_SIMPLE = 0xcafe; + static final int VID_LOOPBACK = 0xcafe; /** - * Simple test device product ID + * Loopback test device product ID */ - static final int PID_SIMPLE = 0xceaf; + static final int PID_LOOPBACK = 0xceaf; /** - * Simple test device loopback interface number + * Loopback test device loopback interface number */ - static final int LOOPBACK_INTF_SIMPLE = 0; + static final int LOOPBACK_INTF_LOOPBACK = 0; /** * Composite test device vendor ID */ @@ -59,14 +59,14 @@ public class TestDeviceBase { static USBDevice getDevice() { var device = USB.getDevice(new USBDeviceFilter(VID_COMPOSITE, PID_COMPOSITE)); if (device == null) - device = USB.getDevice(new USBDeviceFilter(VID_SIMPLE, PID_SIMPLE)); + device = USB.getDevice(new USBDeviceFilter(VID_LOOPBACK, PID_LOOPBACK)); if (device == null) throw new IllegalStateException("No test device connected"); return device; } static int getInterfaceNumber(USBDevice device) { - return device.productId() == PID_COMPOSITE ? LOOPBACK_INTF_COMPOSITE : LOOPBACK_INTF_SIMPLE; + return device.productId() == PID_COMPOSITE ? LOOPBACK_INTF_COMPOSITE : LOOPBACK_INTF_LOOPBACK; } @BeforeAll From ba0b39921e313eca700bb6d4ea45a84d3823c711 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 7 Oct 2022 21:29:32 +0200 Subject: [PATCH 106/433] Increase test device version --- .../net/codecrete/usb/DescriptionTest.java | 2 +- .../composite-stm32/bin/blackpill-f401cc.bin | Bin 11468 -> 11468 bytes .../composite-stm32/bin/blackpill-f411ce.bin | Bin 11472 -> 11472 bytes .../composite-stm32/bin/bluepill-f103c8.bin | Bin 10028 -> 10028 bytes .../composite-stm32/src/usb_descriptors.c | 2 +- .../loopback-stm32/bin/blackpill-f401cc.bin | Bin 9908 -> 9908 bytes .../loopback-stm32/bin/blackpill-f411ce.bin | Bin 9912 -> 9912 bytes .../loopback-stm32/bin/bluepill-f103c8.bin | Bin 8112 -> 8112 bytes .../loopback-stm32/src/usb_descriptors.c | 2 +- 9 files changed, 3 insertions(+), 3 deletions(-) diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index 6ffff7a9..e43c633a 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -44,7 +44,7 @@ void deviceInfo_isCorrect() { assertEquals(0, testDevice.deviceVersion().major()); assertEquals(isComposite ? 3 : 7, testDevice.deviceVersion().minor()); - assertEquals(isComposite ? 4 : 1, testDevice.deviceVersion().subminor()); + assertEquals(isComposite ? 5 : 2, testDevice.deviceVersion().subminor()); } @Test diff --git a/test-devices/composite-stm32/bin/blackpill-f401cc.bin b/test-devices/composite-stm32/bin/blackpill-f401cc.bin index e09bfae6ea72119f780f86487b3db5bdf750de89..83cbff5aa8e261f934f62f3f7eb26f6d98f0743f 100755 GIT binary patch delta 14 VcmX>Tc_wm0gEph-=0Tc_wm0gEphd=0^t# diff --git a/test-devices/composite-stm32/src/usb_descriptors.c b/test-devices/composite-stm32/src/usb_descriptors.c index 8daa3e95..63c7f69b 100644 --- a/test-devices/composite-stm32/src/usb_descriptors.c +++ b/test-devices/composite-stm32/src/usb_descriptors.c @@ -31,7 +31,7 @@ tusb_desc_device_t const desc_device = { .idVendor = 0xCAFE, .idProduct = 0xCEA0, - .bcdDevice = 0x0034, // version 0.3.4 + .bcdDevice = 0x0035, // version 0.3.5 .iManufacturer = 0x01, .iProduct = 0x02, diff --git a/test-devices/loopback-stm32/bin/blackpill-f401cc.bin b/test-devices/loopback-stm32/bin/blackpill-f401cc.bin index 5b8ca41cd4be36cab0547b99417bcbd87b1ac4cb..37161c7e7d92d0314506ba164c444f4830910c78 100755 GIT binary patch delta 13 VcmdnuyTy0IZ&k*k$$wOL001u-2C@JE delta 13 VcmdnuyTy0IZ&k*^$$wOL001u&2C)DD diff --git a/test-devices/loopback-stm32/bin/blackpill-f411ce.bin b/test-devices/loopback-stm32/bin/blackpill-f411ce.bin index 2c0ede51034acf7076159f119167b8808f580829..3e961f054be4290c3af44997df40cbb2185f78e8 100755 GIT binary patch delta 12 TcmdntyTf Date: Sun, 9 Oct 2022 13:35:29 +0200 Subject: [PATCH 107/433] Make configuration descriptor available --- java-does-usb/pom.xml | 2 +- .../net/codecrete/usb/USBControlTransfer.java | 18 +++++++++------ .../java/net/codecrete/usb/USBDevice.java | 7 ++++++ .../main/java/net/codecrete/usb/Version.java | 22 +++++++++++++++++++ .../codecrete/usb/common/USBDeviceImpl.java | 22 +++++++++++++++---- .../codecrete/usb/linux/LinuxUSBDevice.java | 9 ++++---- .../codecrete/usb/macos/MacosUSBDevice.java | 11 ++++------ .../usb/windows/WindowsUSBDevice.java | 4 +--- .../net/codecrete/usb/DescriptionTest.java | 13 +++++++++++ 9 files changed, 81 insertions(+), 27 deletions(-) diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 5b6c4ace..4d59e801 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 0.3.0 + 0.3.1-SNAPSHOT 19 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java index ba5678f1..fee95c38 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java @@ -12,13 +12,17 @@ *

* See USB specification for additional information *

+ *

+ * For control requests directed to an interface or endpoint, + * the lower byte of {@code index} contains the interface or endpoint number. + *

* - * @param requestType request type - * @param recipient recipient - * @param request request code - * @param value value - * @param index index + * @param requestType request type (bits 5 and 6 of {@code bmRequestType}) + * @param recipient recipient (bits 0–4 of {@code bmRequestType}) + * @param request request code ({@code bRequest}) + * @param value value ({@code wValue}) + * @param index index ({@code wIndex}). */ -public record USBControlTransfer(USBRequestType requestType, USBRecipient recipient, byte request, short value, - short index) { +public record USBControlTransfer(USBRequestType requestType, USBRecipient recipient, int request, int value, + int index) { } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index 5b664945..9101a59d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -207,4 +207,11 @@ public interface USBDevice { * @return received data */ byte[] transferIn(int endpointNumber, int maxLength); + + /** + * Gets the configuration descriptor. + * + * @return the configuration descriptor (as a byte array) + */ + byte[] configurationDescriptor(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/Version.java b/java-does-usb/src/main/java/net/codecrete/usb/Version.java index dc4a314d..88267a4e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/Version.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/Version.java @@ -14,18 +14,40 @@ public final class Version { private final int bcdVersion; + /** + * Creates a new instance. + *

+ * {@code bcdVersion} contains the version: the high byte is the major + * version. The low byte is split into two nibbles (4 bits), the high one + * is minor version, the low one is the subminor version. As an example, + * 0x0321 represents the version 3.2.1. + *

+ * @param bcdVersion version, encoded as described above + */ public Version(int bcdVersion) { this.bcdVersion = bcdVersion; } + /** + * Major version + * @return major version + */ public int major() { return bcdVersion >> 8; } + /** + * Minor version + * @return minor version + */ public int minor() { return (bcdVersion >> 4) & 0x0f; } + /** + * Subminor version + * @return subminor version + */ public int subminor() { return bcdVersion & 0x0f; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 2df47caf..0d26ecc4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -11,10 +11,13 @@ import net.codecrete.usb.usbstandard.DeviceDescriptor; import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; import java.util.Collections; import java.util.List; import java.util.function.Function; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; + public abstract class USBDeviceImpl implements USBDevice { protected final Object id_; @@ -30,6 +33,7 @@ public abstract class USBDeviceImpl implements USBDevice { protected Version deviceVersion_; protected List interfaces_; + protected byte[] configurationDescriptor_; /** * Creates a new instance. @@ -107,6 +111,9 @@ public int protocolCode() { @Override public Version deviceVersion() { return deviceVersion_; } + @Override + public byte[] configurationDescriptor() { return configurationDescriptor_; } + public Object getUniqueId() { return id_; } @@ -122,7 +129,18 @@ public void setFromDeviceDescriptor(MemorySegment descriptor) { protocolCode_ = deviceDescriptor.deviceProtocol() & 255; usbVersion_ = new Version(deviceDescriptor.usbVersion()); deviceVersion_ = new Version(deviceDescriptor.deviceVersion()); + } + /** + * Sets the configuration descriptor and derives the interface and endpoint descriptions. + * @param descriptor configuration descriptor + * @return parsed configuration + */ + protected Configuration setConfigurationDescriptor(MemorySegment descriptor) { + configurationDescriptor_ = descriptor.toArray(JAVA_BYTE); + var configuration = ConfigurationParser.parseConfigurationDescriptor(descriptor); + interfaces_ = configuration.interfaces(); + return configuration; } /** @@ -170,10 +188,6 @@ public List interfaces() { return Collections.unmodifiableList(interfaces_); } - public void setInterfaces(List interfaces) { - interfaces_ = interfaces; - } - @Override public abstract void claimInterface(int interfaceNumber); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 395d8a73..d78f6b78 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -60,8 +60,7 @@ private void loadDescription(String path) { // skip to configuration descriptor var configDesc = session.allocateArray(JAVA_BYTE, descriptors.length - 18); configDesc.copyFrom(descriptorsSegment.asSlice(DeviceDescriptor.LAYOUT.byteSize())); - var configuration = ConfigurationParser.parseConfigurationDescriptor(configDesc); - setInterfaces(configuration.interfaces()); + setConfigurationDescriptor(configDesc); } } @@ -137,9 +136,9 @@ private MemorySegment createCtrlTransfer(MemorySession session, USBDirection dir var bmRequest = (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); usbdevfs_ctrltransfer.bRequestType$set(ctrlTransfer, (byte) bmRequest); - usbdevfs_ctrltransfer.bRequest$set(ctrlTransfer, setup.request()); - usbdevfs_ctrltransfer.wValue$set(ctrlTransfer, setup.value()); - usbdevfs_ctrltransfer.wIndex$set(ctrlTransfer, setup.index()); + usbdevfs_ctrltransfer.bRequest$set(ctrlTransfer, (byte) setup.request()); + usbdevfs_ctrltransfer.wValue$set(ctrlTransfer, (short) setup.value()); + usbdevfs_ctrltransfer.wIndex$set(ctrlTransfer, (short) setup.index()); usbdevfs_ctrltransfer.wLength$set(ctrlTransfer, (short) data.byteSize()); usbdevfs_ctrltransfer.data$set(ctrlTransfer, data.address()); return ctrlTransfer; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index f8ec4c3c..5e72907e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -11,7 +11,6 @@ import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBException; import net.codecrete.usb.USBTransferType; -import net.codecrete.usb.common.ConfigurationParser; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.usbstandard.ConfigurationDescriptor; import net.codecrete.usb.macos.gen.iokit.IOKit; @@ -107,10 +106,8 @@ private void loadDescription() { var configDesc = MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), totalLength, session); - var configuration = ConfigurationParser.parseConfigurationDescriptor(configDesc); - + var configuration = setConfigurationDescriptor(configDesc); configurationValue = 255 & configuration.configValue(); - setInterfaces(configuration.interfaces()); } catch (Throwable e) { configurationValue = 0; @@ -271,9 +268,9 @@ private static MemorySegment createDeviceRequest(MemorySession session, USBDirec var bmRequestType = (direction == USBDirection.IN ? 0x80 : 0x00) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); IOUSBDevRequest.bmRequestType$set(deviceRequest, (byte) bmRequestType); - IOUSBDevRequest.bRequest$set(deviceRequest, setup.request()); - IOUSBDevRequest.wValue$set(deviceRequest, setup.value()); - IOUSBDevRequest.wIndex$set(deviceRequest, setup.index()); + IOUSBDevRequest.bRequest$set(deviceRequest, (byte) setup.request()); + IOUSBDevRequest.wValue$set(deviceRequest, (short) setup.value()); + IOUSBDevRequest.wIndex$set(deviceRequest, (short) setup.index()); IOUSBDevRequest.wLength$set(deviceRequest, (short) data.byteSize()); IOUSBDevRequest.pData$set(deviceRequest, data.address()); return deviceRequest; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 2db379bb..004b2269 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -8,7 +8,6 @@ package net.codecrete.usb.windows; import net.codecrete.usb.*; -import net.codecrete.usb.common.ConfigurationParser; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.usbstandard.SetupPacket; import net.codecrete.usb.windows.gen.kernel32.Kernel32; @@ -38,8 +37,7 @@ public class WindowsUSBDevice extends USBDeviceImpl { } private void readDescription(MemorySegment configDesc, String devicePath, Map children) { - var configuration = ConfigurationParser.parseConfigurationDescriptor(configDesc); - setInterfaces(configuration.interfaces()); + var configuration = setConfigurationDescriptor(configDesc); // build list of interface handles interfaceHandles_ = new ArrayList<>(); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index e43c633a..f1ace49f 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -106,4 +106,17 @@ void endpointDescriptors_areCorrect() { assertEquals(16, endpoint.packetSize()); } } + + @Test + void configurationDescription_isAvailable() { + boolean isLoopbackDevice = testDevice.productId() == PID_LOOPBACK; + int expectedLength = isLoopbackDevice ? 46 : 98; + + byte[] configDesc = testDevice.configurationDescriptor(); + assertNotNull(configDesc); + assertEquals(expectedLength, configDesc.length); + assertEquals(2, configDesc[1]); + assertEquals((byte) expectedLength, configDesc[2]); + assertEquals((byte) 0, configDesc[3]); + } } From 2994ea62183f2601c159a7321842f66b00c5a310 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sun, 9 Oct 2022 13:35:56 +0200 Subject: [PATCH 108/433] Add STM32 DFU upload --- examples/stm_dfu/README.md | 64 +++ examples/stm_dfu/pom.xml | 85 ++++ .../main/java/net/codecrete/usb/dfu/DFU.java | 76 ++++ .../java/net/codecrete/usb/dfu/DFUDevice.java | 365 ++++++++++++++++++ .../net/codecrete/usb/dfu/DFUException.java | 31 ++ .../net/codecrete/usb/dfu/DFURequest.java | 28 ++ .../java/net/codecrete/usb/dfu/DFUStatus.java | 25 ++ .../net/codecrete/usb/dfu/DeviceState.java | 44 +++ .../net/codecrete/usb/dfu/DeviceStatus.java | 44 +++ .../main/java/net/codecrete/usb/dfu/Page.java | 54 +++ .../java/net/codecrete/usb/dfu/STM32.java | 15 + .../java/net/codecrete/usb/dfu/Segment.java | 178 +++++++++ 12 files changed, 1009 insertions(+) create mode 100644 examples/stm_dfu/README.md create mode 100644 examples/stm_dfu/pom.xml create mode 100644 examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFU.java create mode 100644 examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java create mode 100644 examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUException.java create mode 100644 examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFURequest.java create mode 100644 examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUStatus.java create mode 100644 examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DeviceState.java create mode 100644 examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DeviceStatus.java create mode 100644 examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Page.java create mode 100644 examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/STM32.java create mode 100644 examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Segment.java diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md new file mode 100644 index 00000000..9f19a4dc --- /dev/null +++ b/examples/stm_dfu/README.md @@ -0,0 +1,64 @@ +# Device Firmware Upload (DFU) for STM32 + +This sample programs implements firmware upload for STM32 microcontrollers with the built-in DFU mode. + +Even though the DFU + +## Prerequisites + +- Java 19 +- Apache Maven +- 64-bit operating system (Windows, macOS, Linux) + +## How to run + +### Install Java 19 + +Check that *Java 19* is installed: + +```shell +$ java -version +``` + +If not, download and install it, e.g. from [Azul](https://www.azul.com/downloads/?package=jdk). + +### Install Maven + +Check that *Maven* is installed: + +```shell +$ mvn -version +``` + +If it is not present, install it, typically using package manager like *Homebrew* on macOS, *Chocolately* on Windows and *apt* on Linux. + +### Build the application + +Since the *java-does-usb* library is not yet available on Maven Central, it must be built locally: + +```shell +$ mvn clean package +``` + +The result will be put in your local Maven repository. + +### Run the application + +- Connect an STM32 development board (like a BlackPill board) to your computer while pressing the *Boot* button. +- Ensure that it is DFU mode by checking macOS *System Information* or Windows *Device Manager*. The device should appear as "STM32 BOOTLOADER". +- Run the command below (adapting the file path depending on your specific board). + +```shell +$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.3.1.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin +DFU device found with serial 36C730037136. +Target memory segment: Internal Flash +Erasing page at 0x8000000 (size 0x4000) +Writing data at 0x8000000 (size 0x800) +Writing data at 0x8000800 (size 0x800) +Writing data at 0x8001000 (size 0x800) +Writing data at 0x8001800 (size 0x800) +Writing data at 0x8002000 (size 0x800) +Writing data at 0x8002800 (size 0x4cc) +Firmware successfully downloaded and verified +DFU mode exited and firmware started +``` diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml new file mode 100644 index 00000000..e973c20b --- /dev/null +++ b/examples/stm_dfu/pom.xml @@ -0,0 +1,85 @@ + + + 4.0.0 + + net.codecrete.usb.examples + stm_dfu + 0.3.1 + + stm_dfu + https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu + + + + net.codecrete.usb + java-does-usb + 0.3.1-SNAPSHOT + + + + + + + maven-clean-plugin + 3.1.0 + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + 19 + --enable-preview + 19 + 19 + + + + maven-jar-plugin + 3.0.2 + + + maven-surefire-plugin + 2.22.2 + + + maven-shade-plugin + 3.3.0 + + + package + + shade + + + + + + + *:* + + module-info.class + META-INF/MANIFEST.MF + + + + + + net.codecrete.usb.dfu.DFU + + + false + + + + + + + 19 + 19 + UTF-8 + + diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFU.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFU.java new file mode 100644 index 00000000..0c785461 --- /dev/null +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFU.java @@ -0,0 +1,76 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.dfu; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * Command line application for upload firmware to STM32. + *

+ * Only the STM32 variant of the DFU protocol is supported. + * Only binary firmware format is supported (no .hex or .dfu files). + *

+ */ +public class DFU { + + /** + * Main function + * @param args arguments (path to firmware) + */ + public static void main(String[] args) { + // check for single parameter + if (args.length != 1) { + System.err.println("Usage: dfu_upload "); + System.exit(1); + return; + } + + // read firmware file + byte[] firmware; + try { + firmware = Files.readAllBytes(Path.of(args[0])); + } catch (IOException e) { + System.err.printf("Error: Cannot read firmware file %s%n", args[0]); + System.exit(2); + return; + } + + // check for single DFU device + var devices = DFUDevice.getAll(); + if (devices.isEmpty()) { + System.err.println("Error: No STM32 DFU device connected (or not in DFU mode)"); + System.exit(4); + return; + } else if (devices.size() > 1) { + System.err.println("Error: Multiple STM32 DFU devices connected. Please connect only one."); + System.exit(4); + return; + } + var device = devices.get(0); + System.out.printf("DFU device found with serial %s.%n", device.serialNumber()); + + // download and verify firmware + try { + device.open(); + device.download(firmware); + device.verify(firmware); + System.out.println("Firmware successfully downloaded and verified"); + + device.startApplication(); + System.out.println("DFU mode exited and firmware started"); + + device.close(); + + } catch (DFUException e) { + System.err.println("Error: " + e.getMessage()); + System.exit(3); + } + } +} diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java new file mode 100644 index 00000000..6ce3c233 --- /dev/null +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java @@ -0,0 +1,365 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.dfu; + +import net.codecrete.usb.*; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * DFU device. + *

+ * Implements the main DFU operations like download, upload etc. + *

+ */ +public class DFUDevice { + + private final USBDevice usbDevice_; + private final int interfaceNumber_; + private final int transferSize_; + private final Version dfuVersion_; + + private List segments_; + + /** + * Gets all connected DFU devices + * @return List of DFU devices + */ + public static List getAll() { + return USB.getAllDevices().stream() + .filter(DFUDevice::hasDFUDescriptor) + .map(DFUDevice::new) + .collect(Collectors.toList()); + } + + /** + * Checks if the device has a DFU functional descriptor. + * @param device USB device + * @return {@code true} if it has a DFU descriptor, {@code false} otherwise + */ + public static boolean hasDFUDescriptor(USBDevice device) { + return getDFUDescriptorOffset(device.configurationDescriptor()) > 0 + && getDFUInterfaceNumber(device) >= 0; + } + + /** + * Gets the offset of the DFU functional descriptor within the USB configuration descriptor. + * @param descriptor USB configuration descriptor + * @return descriptor offset (in bytes), or -1 if not found + */ + public static int getDFUDescriptorOffset(byte[] descriptor) { + int offset = 0; + while (offset < descriptor.length) { + if (descriptor[offset + 1] == 0x21) + return offset; + offset += descriptor[offset] & 255; + } + return -1; + } + + /** + * Gets the DFU interface number. + * @param device the USB device + * @return the interface number, of -1 if not found + */ + public static int getDFUInterfaceNumber(USBDevice device) { + for (var intf : device.interfaces()) { + var alt = intf.alternate(); + if (alt.classCode() == 0xFE && alt.subclassCode() == 0x01 && alt.protocolCode() == 0x02) + return intf.number(); + } + + return -1; + } + + /** + * Creates a new DFUDevice instance. + *

+ * The specified USB device must have a DFU descriptor and a DFU interface. + *

+ * @param usbDevice the USB device + */ + public DFUDevice(USBDevice usbDevice) { + usbDevice_ = usbDevice; + interfaceNumber_ = getDFUInterfaceNumber(usbDevice); + + var configDesc = usbDevice.configurationDescriptor(); + int offset = getDFUDescriptorOffset(configDesc); + assert offset > 0; + + transferSize_ = getInt16(configDesc, offset + 5); + dfuVersion_ = new Version(getInt16(configDesc, offset + 7)); + } + + /** + * Gets the DFU protocol version. + * @return the protocol version + */ + public Version dfuVersion() { + return dfuVersion_; + } + + /** + * Gets the device serial number. + * @return the serial number + */ + public String serialNumber() { + return usbDevice_.serialNumber(); + } + + /** + * Opens the DFU device for communication. + */ + public void open() { + usbDevice_.open(); + usbDevice_.claimInterface(interfaceNumber_); + segments_ = Segment.getSegments(usbDevice_, interfaceNumber_); + clearErrorIfNeeded(); + } + + /** + * Closes the DFU device. + */ + public void close() { + usbDevice_.close(); + } + + /** + * Clears an error status. + */ + public void clearStatus() { + var setup = new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, DFURequest.CLEAR_STATUS.value(), 0, interfaceNumber_); + usbDevice_.controlTransferOut(setup, null); + } + + /** + * Aborts the download mode. + */ + public void abort() { + var setup = new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, DFURequest.ABORT.value(), 0, interfaceNumber_); + usbDevice_.controlTransferOut(setup, null); + } + + /** + * Gets the full DFU status + * @return the status + */ + public DFUStatus getStatus() { + var setup = new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, DFURequest.GET_STATUS.value(), 0, interfaceNumber_); + return DFUStatus.fromBytes(usbDevice_.controlTransferIn(setup, 6)); + } + + /** + * Reads from the device flash memory. + * @param address the memory start address + * @param length the length of memory to read + * @return the read data + */ + public byte[] read(int address, int length) { + expectState(DeviceState.DFU_IDLE, DeviceState.DFU_DNLOAD_IDLE); + setAddress(address); + exitDownloadMode(); + + expectState(DeviceState.DFU_IDLE, DeviceState.DFU_UPLOAD_IDLE); + + var result = new byte[length]; + + // read full chunks + int offset = 0; + int blockNum = 2; + while (offset < length) { + int chunkSize = Math.min(transferSize_, length - offset); + var setup = new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, DFURequest.UPLOAD.value(), blockNum, interfaceNumber_); + var chunk = usbDevice_.controlTransferIn(setup, chunkSize); + System.arraycopy(chunk, 0, result, offset, chunkSize); + offset += chunkSize; + blockNum += 1; + } + + // request zero lenght chunk to exit out of upload mode + var setup = new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, DFURequest.UPLOAD.value(), blockNum, interfaceNumber_); + usbDevice_.controlTransferIn(setup, 0); + + return result; + } + + public void verify(byte[] firmware) { + byte[] firmware2 = read(STM32.FLASH_BASE_ADDRESS, firmware.length); + if (!Arrays.equals(firmware, firmware2)) + throw new DFUException("Verification failed - content differs"); + } + + public void download(byte[] firmware) { + int length = firmware.length; + + // validate start and end address exist and are writable + int startAddress = STM32.FLASH_BASE_ADDRESS; + var firstPage = getWritablePage(startAddress); + getWritablePage(startAddress + length); + + // TODO: select alternate interface settings + System.out.printf("Target memory segment: %s%n", firstPage.segment().name()); + + // erase if needed + if (firstPage.isErasable()) + erase(startAddress, length); + + // download firmware + setAddress(startAddress); + + int offset = 0; + int transaction = 2; + while (offset < length) { + int chunkSize = Math.min(length - offset, transferSize_); + + byte[] chunk = new byte[chunkSize]; + System.arraycopy(firmware, offset, chunk, 0, chunkSize); + + System.out.printf("Writing data at 0x%x (size 0x%x)%n", startAddress + offset, chunkSize); + var setup = new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, DFURequest.DOWNLOAD.value(), transaction, interfaceNumber_); + usbDevice_.controlTransferOut(setup, chunk); + + finishDownloadCommand("writing data"); + + offset += chunkSize; + transaction += 1; + } + + exitDownloadMode(); + } + + /** + * Erases the specified range. + *

+ * Only applicable to erasable sector, i.e. flash memory. + *

+ *

+ * Only entire pages can be erase. If start and end address to not fall onto + * page boundaries, this method will extend the range to be erased. + *

+ * @param startAddress the start address of the range + * @param length the length of the range + */ + public void erase(int startAddress, int length) { + int endAddress = startAddress + length; + + while (startAddress < endAddress) { + var page = findPage(startAddress); + if (page == null) + throw new DFUException(String.format("No valid memory segment at address 0x%x", startAddress)); + if (!page.isErasable()) + throw new DFUException(String.format("Page at address 0x%x is not erasable", startAddress)); + + System.out.printf("Erasing page at 0x%x (size 0x%x)%n", page.startAddress(), page.pageSize()); + erasePage(page.startAddress()); + startAddress = page.endAddress(); + } + } + + public void erasePage(int address) { + execDownloadCommandWithAddress((byte) 0x41, "erasing page", address); + } + + public void setAddress(int address) { + execDownloadCommandWithAddress((byte) 0x21, "setting address", address); + } + + private void execDownloadCommandWithAddress(byte command, String action, int address) { + var setup = new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, DFURequest.DOWNLOAD.value(), 0, interfaceNumber_); + var data = new byte[] { + command, + (byte) address, + (byte) (address >> 8), + (byte) (address >> 16), + (byte) (address >> 24) + }; + usbDevice_.controlTransferOut(setup, data); + + finishDownloadCommand(action); + } + + private void finishDownloadCommand(String action) { + var status = getStatus(); + if (status.state() != DeviceState.DFU_DNBUSY) + throw new DFUException("Unexpected state for " + action); + + sleep(status.pollTimeout()); + + status = getStatus(); + if (status.status() != DeviceStatus.OK) + throw new DFUException("Unexpected state after " + action); + + sleep(status.pollTimeout()); + } + + private Page getWritablePage(int address) { + var page = findPage(address); + if (page == null) + throw new DFUException(String.format("No valid memory segment at address 0x%x", address)); + if (!page.isWritable()) + throw new DFUException(String.format("Page at address 0x%x is not writable", address)); + return page; + } + + private Page findPage(int address) { + return Segment.findPage(segments_, address); + } + + private void exitDownloadMode() { + abort(); + + var status = getStatus(); + if (status.state() != DeviceState.DFU_IDLE) + throw new DFUException("Unexpected state after exiting from download mode"); + + sleep(status.pollTimeout()); + } + + public void startApplication() { + expectState(DeviceState.DFU_IDLE, DeviceState.DFU_DNLOAD_IDLE); + + var setup = new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, DFURequest.DOWNLOAD.value(), 2, interfaceNumber_); + usbDevice_.controlTransferOut(setup, null); + + var status = getStatus(); + if (status.state() != DeviceState.DFU_MANIFEST) + throw new DFUException("Exiting DFU mode and starting firmware has failed"); + } + + private void clearErrorIfNeeded() { + var status = getStatus(); + if (status.status() != DeviceStatus.OK) { + clearStatus(); + sleep(status.pollTimeout()); + status = getStatus(); + if (status.status() != DeviceStatus.OK) + throw new DFUException("Cannot clear error status"); + } + } + + private void expectState(DeviceState state1, DeviceState state2) { + var status = getStatus(); + if (status.state() != state1 && status.state() != state2) + throw new DFUException( + String.format("Expected state %s or %s but got %s", state1, state2, status.state())); + } + + private int getInt16(byte[] config, int offset) { + return (config[offset] & 0xff) + 256 * (config[offset + 1] & 0xff); + } + + private static void sleep(int millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + throw new DFUException("Sleep failed", e); + } + } +} diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUException.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUException.java new file mode 100644 index 00000000..eaa4a111 --- /dev/null +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUException.java @@ -0,0 +1,31 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.dfu; + +/** + * DFU exception thrown if a DFU operation fails. + */ +public class DFUException extends RuntimeException { + + /** + * Creates a new instance with the given message + * @param message the message + */ + DFUException(String message) { + super(message); + } + + /** + * Creates a new instance with the given message and cause + * @param message the message + * @param cause the exception causing the DFU operation to fail + */ + DFUException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFURequest.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFURequest.java new file mode 100644 index 00000000..00607e37 --- /dev/null +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFURequest.java @@ -0,0 +1,28 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.dfu; + +/** + * DFU request. + *

+ * See USB Device Class Specification for Device Firmware Upgrade, version 1.1. + *

+ */ +public enum DFURequest { + DETACH, + DOWNLOAD, + UPLOAD, + GET_STATUS, + CLEAR_STATUS, + GET_STATE, + ABORT; + + public int value() { + return ordinal(); + } +} diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUStatus.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUStatus.java new file mode 100644 index 00000000..4cd6e967 --- /dev/null +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUStatus.java @@ -0,0 +1,25 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.dfu; + +/** + * DFU GET_STATUS response. + *

+ * See USB Device Class Specification for Device Firmware Upgrade, version 1.1. + *

+ */ +public record DFUStatus(DeviceStatus status, int pollTimeout, DeviceState state, int iString) { + + public static DFUStatus fromBytes(byte[] data) { + var status = DeviceStatus.fromValue(data[0]); + var pollTimeout = (data[1] & 0xff) + 256 * (data[2] & 0xff) + 256 * 256 * (data[3] & 0xff); + var state = DeviceState.fromValue(data[4]); + var iString = data[5] & 0x55; + return new DFUStatus(status, pollTimeout, state, iString); + } +} diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DeviceState.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DeviceState.java new file mode 100644 index 00000000..759da304 --- /dev/null +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DeviceState.java @@ -0,0 +1,44 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.dfu; + +/** + * DFU device state. + *

+ * See USB Device Class Specification for Device Firmware Upgrade, version 1.1. + *

+ */ +public enum DeviceState { + APP_IDLE, // Device is running its normal application. + APP_DETACH, // Device is running its normal application, has received the DFU_DETACH request, + // and is waiting for a USB reset. + DFU_IDLE, // Device is operating in the DFU mode and is waiting for requests. + DFU_DNLOAD_SYNC, // Device has received a block and is waiting for the host to solicit the status via DFU_GETSTATUS. + DFU_DNBUSY, // Device is programming a control-write block into its nonvolatile memories. + DFU_DNLOAD_IDLE, // Device is processing a download operation. Expecting DFU_DNLOAD requests. + DFU_MANIFEST_SYNC, // Device has received the final block of firmware from the host and is waiting for receipt of + // DFU_GETSTATUS to begin the Manifestation phase; or device has completed the Manifestation phase and is + // waiting for receipt of DFU_GETSTATUS. (Devices that can enter this state after the Manifestation phase + // set bmAttributes bit bitManifestationTolerant to 1.) + DFU_MANIFEST, // Device is in the Manifestation phase. (Not all devices will be able to respond to DFU_GETSTATUS + // when in this state.) + DFU_MANIFEST_WAIT_RESET, // Device has programmed its memories and is waiting for a USB reset or a power on reset. + // (Devices that must enter this state clear bitManifestationTolerant to 0.) + DFU_UPLOAD_IDLE, // The device is processing an upload operation. Expecting DFU_UPLOAD requests. + DFU_ERROR; // An error has occurred. Awaiting the DFU_CLRSTATUS request. + + public byte value() { + return (byte) ordinal(); + } + + private static final DeviceState[] values = values(); + + public static DeviceState fromValue(byte value) { + return values[value]; + } +} diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DeviceStatus.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DeviceStatus.java new file mode 100644 index 00000000..9ae30d63 --- /dev/null +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DeviceStatus.java @@ -0,0 +1,44 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.dfu; + +/** + * DFU device status. + *

+ * See USB Device Class Specification for Device Firmware Upgrade, version 1.1. + *

+ */ +public enum DeviceStatus { + + OK, // No error condition is present + ERR_TARGET, // File is not targeted for use by this device. + ERR_FILE, // File is for this device but fails some vendor-specific verification test. + ERR_WRITE, // Device is unable to write memory. + ERR_ERASE, // Memory erase function failed. + ERR_CHECK_ERASED, // Memory erase check failed. + ERR_PROG, // Program memory function failed. + ERR_VERIFY, // Programmed memory failed verification. + ERR_ADDRESS, // Cannot program memory due to received address that is out of range. + ERR_NOTDONE, // Received DFU_DNLOAD with wLength = 0, but device does not think it has all of the data yet. + ERR_FIRMWARE, // Device’s firmware is corrupt. It cannot return to run-time (non-DFU) operations. + ERR_VENDOR, // iString indicates a vendor-specific error. + ERR_USBR, // Device detected unexpected USB reset signaling. + ERR_POR, // Device detected unexpected power on reset. + ERR_UNKNOWN, // Something went wrong, but the device does not know what it was. + ERR_STALLEDPKT; // Device stalled an unexpected request. + + public byte value() { + return (byte) ordinal(); + } + + private static final DeviceStatus[] values = values(); + + public static DeviceStatus fromValue(byte value) { + return values[value]; + } +} diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Page.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Page.java new file mode 100644 index 00000000..d7d90b31 --- /dev/null +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Page.java @@ -0,0 +1,54 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.dfu; + +/** + * Page of flash memory, RAM or other type of memory. + *

+ * If count is > 1, it represents a sector consisting of multiple equal pages. + *

+ * @param segment the memory segment this page belongs to + * @param startAddress start address + * @param count number of pages + * @param pageSize page size (in bytes) + * @param attributes page attributes + */ +public record Page(Segment segment, int startAddress, int count, int pageSize, int attributes) { + + /** + * Gets the end address of the page or sector. + * @return the end address + */ + public int endAddress() { + return startAddress + count * pageSize; + } + + /** + * Indicates if the page or sector is readable. + * @return {@code true} if it is readable + */ + public boolean isReadable() { + return (attributes & 1) != 0; + } + + /** + * Indicates if the page or sector is erasable. + * @return {@code true} if it is erasable + */ + public boolean isErasable() { + return (attributes & 2) != 0; + } + + /** + * Indicates if the page or sector is writable. + * @return {@code true} if it is writable + */ + public boolean isWritable() { + return (attributes & 4) != 0; + } +} diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/STM32.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/STM32.java new file mode 100644 index 00000000..a157ca55 --- /dev/null +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/STM32.java @@ -0,0 +1,15 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.dfu; + +/** + * STM32 specific constants + */ +public class STM32 { + public static final int FLASH_BASE_ADDRESS = 0x08000000; +} diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Segment.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Segment.java new file mode 100644 index 00000000..eef8d1fc --- /dev/null +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Segment.java @@ -0,0 +1,178 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.dfu; + +import net.codecrete.usb.USBControlTransfer; +import net.codecrete.usb.USBDevice; +import net.codecrete.usb.USBRecipient; +import net.codecrete.usb.USBRequestType; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a memory segment of the USB device, be it flash memory, RAM or any other type. + */ +public class Segment { + + /** + * Derives the segments from the USB interface description. + * @param device the USB device + * @param interfaceNumber the number of the DFU USB interface + * @return list of segments + */ + public static List getSegments(USBDevice device, int interfaceNumber) { + var result = new ArrayList(); + + // STM uses multiple alternate interface settings to represent segments. + // The alternate interface settings name describes the sectors within the segment. + var configDesc = device.configurationDescriptor(); + int offset = 0; + while (offset < configDesc.length) { + if (configDesc[offset + 1] == 4 && (configDesc[offset + 2] & 0xff) == interfaceNumber) { + int altSetting = configDesc[offset + 3] & 0xff; + int stringIndex = configDesc[offset + 8] & 0xff; + var altSettingName = getStringDescriptor(device, stringIndex); + result.add(new Segment(altSetting, altSettingName)); + } + offset += configDesc[offset] & 0xff; + } + + return result; + } + + /** + * Retrieves a USB string. + * @param device the USB device + * @param index the index of the string descriptor + * @return the string + */ + private static String getStringDescriptor(USBDevice device, int index) { + var setup = new USBControlTransfer(USBRequestType.STANDARD, USBRecipient.DEVICE, 6, (3 << 8) | index, 0); + byte[] stringDesc = device.controlTransferIn(setup, 255); + int descLen = stringDesc[0] & 0xff; + return new String(stringDesc, 2, descLen - 2, StandardCharsets.UTF_16LE); + } + + /** + * Gets the page for the specified address. + * @param segments the list of segments + * @param address the address + * @return the page, or {@code null} if not found + */ + public static Page findPage(List segments, int address) { + for (var seg : segments) { + for (var sec : seg.sectors()) { + if (address >= sec.startAddress() && address < sec.endAddress()) { + int offset = address - sec.startAddress(); + int pageNum = offset / sec.pageSize(); + return new Page(seg, sec.startAddress() + pageNum * sec.pageSize(), 1, sec.pageSize(), sec.attributes()); + } + } + } + + return null; + } + + private final int altSetting_; + private final String name_; + + private final List sectors_; + + + /** + * Creates a new instance. + *

+ * The segment descriptor is the name of the USB alternate interface setting. + *

+ * @param altSetting alternate interface setting number + * @param segmentDesc segment descriptor + */ + private Segment(int altSetting, String segmentDesc) { + // The format is described in "UM0424 STM32 USB-FS-Device development kit", ch. 10.3.2 + altSetting_ = altSetting; + sectors_ = new ArrayList(); + int offset = segmentDesc.indexOf('/', 1); + name_ = segmentDesc.substring(1, offset).trim(); + + int startAddress = 0; + while (offset < segmentDesc.length()) { + // parse start address + if (segmentDesc.charAt(offset) == '/') { + int addressEnd = segmentDesc.indexOf('/', offset + 1); + startAddress = (int) Long.parseLong(segmentDesc.substring(offset + 3, addressEnd), 16); + offset = addressEnd + 1; + continue; + } + + // skip comma + if (segmentDesc.charAt(offset) == ',') + offset += 1; + + // parse count + int countEnd = segmentDesc.indexOf('*', offset); + int count = Integer.parseInt(segmentDesc.substring(offset, countEnd)); + offset = countEnd + 1; + + // parse sector size + int sizeEnd = offset; + while (Character.isDigit(segmentDesc.charAt(sizeEnd))) + sizeEnd += 1; + int size = Integer.parseInt(segmentDesc.substring(offset, sizeEnd)); + offset = sizeEnd; + + // skip whitespace + while (segmentDesc.charAt(offset) == ' ') + offset += 1; + + // parse unit + char unitChar = segmentDesc.charAt(offset); + if (unitChar == 'B') { + offset += 1; + } else if (unitChar == 'K') { + size *= 1024; + offset += 1; + } else if (unitChar == 'M') { + size *= 1024 * 1024; + offset += 1; + } + + // parse sector attributes + int sectorAttrs = segmentDesc.charAt(offset) - 0x40; + offset += 1; + + sectors_.add(new Page(this, startAddress, count, size, sectorAttrs)); + startAddress += size; + } + } + + /** + * Gets the alternative interface setting number + * @return the setting number + */ + public int altSetting() { + return altSetting_; + } + + /** + * Gets the segment name. + * @return the name + */ + public String name() { + return name_; + } + + /** + * Gets the sectors withing the segment + * @return list of sectors + */ + public List sectors() { + return sectors_; + } +} From bef8d86ea151a389064ac03ce1b2ccea4420936c Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Thu, 13 Oct 2022 23:55:39 +0200 Subject: [PATCH 109/433] Input/output stream for bulk endpoint --- .../codecrete/usb/USBAlternateInterface.java | 9 ++ .../java/net/codecrete/usb/USBDevice.java | 39 +++++++- .../usb/common/EndpointInputStream.java | 81 +++++++++++++++++ .../usb/common/EndpointOutputStream.java | 87 ++++++++++++++++++ .../usb/common/USBAlternateInterfaceImpl.java | 9 ++ .../codecrete/usb/common/USBDeviceImpl.java | 27 ++++-- .../java/net/codecrete/usb/StreamTest.java | 90 +++++++++++++++++++ 7 files changed, 334 insertions(+), 8 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java index 40041360..1d665230 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java @@ -66,4 +66,13 @@ public interface USBAlternateInterface { * @return a list of endpoints. */ List endpoints(); + + /** + * Gets the endpoint with the specified number and direction. + * @param endpointNumber endpoint number (in the range between 1 and 127, without the direction bit) + * @param direction endpoint direction + * @return the endpoint, or {@code null} if no endpoint with the given number and direction exists + */ + USBEndpoint getEndpoint(int endpointNumber, USBDirection direction); + } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index 9101a59d..6f4f1f0a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -7,6 +7,8 @@ package net.codecrete.usb; +import java.io.InputStream; +import java.io.OutputStream; import java.util.List; /** @@ -121,6 +123,13 @@ public interface USBDevice { */ List interfaces(); + /** + * Gets the interface with the specified number. + * @param interfaceNumber the interface number + * @return the interface, or {@code null} if no interface with the given number exists + */ + USBInterface getInterface(int interfaceNumber); + /** * Claims the specified interface for exclusive use. * @@ -196,7 +205,8 @@ public interface USBDevice { * Receives data from this device. *

* This method blocks until at least a packet has been received or an error has occurred. - * The minimum value for {@code maxLength} is the maximum size of packets sent on the endpoint. + * {@code maxLength} must be long enough to hold the full data packet transmitted by the device. + * To be on the safe side, it should be equal or greater than the endpoint's maximum packet size. *

*

* This method can receive data from bulk and interrupt endpoints. @@ -208,6 +218,33 @@ public interface USBDevice { */ byte[] transferIn(int endpointNumber, int maxLength); + /** + * Opens a new output stream to send data to a bulk endpoint. + *

+ * All data written to this output stream is sent to the specified bulk endpoint. + * If {@link #transferOut(int, byte[])} and a output stream or multiple output streams + * are used concurrently for the same endpoint, the behavior is unpredictable. + *

+ * + * @param endpointNumber bulk endpoint number (in the range between 1 and 127) + * @return the new output stream + */ + OutputStream openOutputStream(int endpointNumber); + + /** + * Opens a new input stream to receive data from a bulk endpoint. + *

+ * All data received from the specified bulk endpoint can be read using this input stream. + *

+ *

+ * If {@link #transferIn(int, int)} and an input stream or multiple input streams + * are used concurrently for the same endpoint, the behavior is unpredictable. + *

+ * @param endpointNumber bulk endpoint number (in the range between 1 and 127, i.e. without the direction bit) + * @return the new input stream + */ + InputStream openInputStream(int endpointNumber); + /** * Gets the configuration descriptor. * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java new file mode 100644 index 00000000..a605a682 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -0,0 +1,81 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +import net.codecrete.usb.USBDevice; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Input stream receiving data from a USB bulk endpoint. + *

+ * The input stream tries to receive a packet at a time. + *

+ */ +public class EndpointInputStream extends InputStream { + + private USBDevice device_; + private final int endpointNumber_; + private final int packetSize_; + private byte[] packet_; + private int readOffset_; + + EndpointInputStream(USBDevice device, int endpointNumber, int packetSize) { + device_ = device; + endpointNumber_ = endpointNumber; + packetSize_ = packetSize; + } + + @Override + public int read() throws IOException { + if (device_ == null) + throw new IOException("Bulk endpoint input stream has been closed"); + + if (available() == 0) + receiveMoreData(); + + int b = packet_[readOffset_] & 0xff; + readOffset_ += 1; + return b; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (device_ == null) + throw new IOException("Bulk endpoint input stream has been closed"); + + if (available() == 0) + receiveMoreData(); + + int n = Math.min(len, packet_.length - readOffset_); + System.arraycopy(packet_, readOffset_, b, off, n); + readOffset_ += n; + + return n; + } + + @Override + public int available() throws IOException { + return (packet_ != null ? packet_.length : 0) - readOffset_; + } + + private void receiveMoreData() throws IOException { + if (device_ == null) + throw new IOException("Bulk endpoint input stream has been closed"); + + readOffset_ = 0; + packet_ = device_.transferIn(endpointNumber_, packetSize_); + } + + @Override + public void close() throws IOException { + device_ = null; + packet_ = null; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java new file mode 100644 index 00000000..d5771015 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -0,0 +1,87 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +import net.codecrete.usb.USBDevice; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Arrays; + +/** + * Output stream transmitting data to a USB bulk endpoint. + *

+ * The output stream uses a buffer that fits a single data packet. + *

+ */ +public class EndpointOutputStream extends OutputStream { + + private USBDevice device_; + private final int endpointNumber_; + private byte[] buffer_; + private int bufferedBytes_; + + EndpointOutputStream(USBDevice device, int endpointNumber, int packetSize) { + device_ = device; + endpointNumber_ = endpointNumber; + buffer_ = new byte[packetSize]; + } + + @Override + public void write(int b) throws IOException { + if (device_ == null) + throw new IOException("Bulk endpoint output stream has been closed"); + + buffer_[bufferedBytes_] = (byte)b; + bufferedBytes_ += 1; + if (bufferedBytes_ == buffer_.length) + flush(); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (device_ == null) + throw new IOException("Bulk endpoint output stream has been closed"); + + while (len > 0) { + int chunkSize = Math.min(len, buffer_.length - bufferedBytes_); + System.arraycopy(b, off, buffer_, bufferedBytes_, chunkSize); + bufferedBytes_ += chunkSize; + off += chunkSize; + len -= chunkSize; + + if (bufferedBytes_ == buffer_.length) + flush(); + } + } + + @Override + public void flush() throws IOException { + if (device_ == null) + throw new IOException("Bulk endpoint output stream has been closed"); + + if (bufferedBytes_ == 0) + return; + + byte[] data; + if (bufferedBytes_ < buffer_.length) { + data = Arrays.copyOfRange(buffer_, 0, bufferedBytes_); + } else { + data = buffer_; + } + device_.transferOut(endpointNumber_, data); + bufferedBytes_ = 0; + } + + @Override + public void close() throws IOException { + flush(); + buffer_ = null; + device_ = null; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java index 4bc5c9d2..d3c2456f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java @@ -8,6 +8,7 @@ package net.codecrete.usb.common; import net.codecrete.usb.USBAlternateInterface; +import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBEndpoint; import java.util.Collections; @@ -58,4 +59,12 @@ public List endpoints() { void addEndpoint(USBEndpoint endpoint) { endpoints_.add(endpoint); } + + @Override + public USBEndpoint getEndpoint(int endpointNumber, USBDirection direction) { + return endpoints_ + .stream().filter((ep) -> ep.number() == endpointNumber && ep.direction() == direction) + .findFirst() + .orElse(null); + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 0d26ecc4..3aa2708c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -10,6 +10,8 @@ import net.codecrete.usb.*; import net.codecrete.usb.usbstandard.DeviceDescriptor; +import java.io.InputStream; +import java.io.OutputStream; import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; import java.util.Collections; @@ -204,13 +206,8 @@ public void setClaimed(int interfaceNumber, boolean claimed) { throw new USBException("Internal error (interface not found)"); } - /** - * Returns the interface with the specified number. - * - * @param interfaceNumber the interface number - * @return the interface - */ - protected USBInterfaceImpl getInterface(int interfaceNumber) { + @Override + public USBInterfaceImpl getInterface(int interfaceNumber) { return (USBInterfaceImpl) interfaces_.stream().filter((intf) -> intf.number() == interfaceNumber).findFirst().orElse(null); } @@ -316,6 +313,22 @@ protected int getInterfaceNumber(int endpointNumber) { @Override public abstract byte[] transferIn(int endpointNumber, int maxLength); + @Override + public OutputStream openOutputStream(int endpointNumber) { + // check that endpoint number is valid + var endpointInfo = getEndpoint(endpointNumber, USBDirection.OUT, USBTransferType.BULK, null); + var endpoint = getInterface(endpointInfo.interfaceNumber).alternate().getEndpoint(endpointNumber, USBDirection.OUT); + return new EndpointOutputStream(this, endpointNumber, endpoint.packetSize()); + } + + @Override + public InputStream openInputStream(int endpointNumber) { + // check that endpoint number is valid + var endpointInfo = getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, null); + var endpoint = getInterface(endpointInfo.interfaceNumber).alternate().getEndpoint(endpointNumber, USBDirection.IN); + return new EndpointInputStream(this, endpointNumber, endpoint.packetSize()); + } + @Override public boolean equals(Object o) { if (this == o) diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java new file mode 100644 index 00000000..aa5ea0d5 --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java @@ -0,0 +1,90 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Unit test for bulk transfer +// + +package net.codecrete.usb; + +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.concurrent.CompletableFuture; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +public class StreamTest extends TestDeviceBase { + + @Test + void smallTransfer_succeeds() { + byte[] sampleData = generateRandomBytes(12, 293872394); + writeBytes(sampleData, 100); + byte[] data = readBytes(sampleData.length); + assertArrayEquals(sampleData, data); + } + + @Test + void mediumTransfer_succeeds() { + // This synchronous approach should work as the test device + // has an internal buffer of about 500 bytes. + byte[] sampleData = generateRandomBytes(140, 97333894); + writeBytes(sampleData, 30); + byte[] data = readBytes(sampleData.length); + assertArrayEquals(sampleData, data); + } + + @Test + void largeTransferSmallChunks_succeeds() throws Throwable { + final int numBytes = 230763; + byte[] sampleData = generateRandomBytes(numBytes, 3829007493L); + var writer = CompletableFuture.runAsync(() -> writeBytes(sampleData, 20)); + var reader = CompletableFuture.supplyAsync(() -> readBytes(numBytes)); + CompletableFuture.allOf(writer, reader).join(); + if (reader.isCompletedExceptionally()) + throw reader.exceptionNow(); + assertArrayEquals(sampleData, reader.resultNow()); + } + + @Test + void largeTransferBigChunks_succeeds() throws Throwable { + final int numBytes = 230763; + byte[] sampleData = generateRandomBytes(numBytes, 3829007493L); + var writer = CompletableFuture.runAsync(() -> writeBytes(sampleData, 150)); + var reader = CompletableFuture.supplyAsync(() -> readBytes(numBytes)); + CompletableFuture.allOf(writer, reader).join(); + if (reader.isCompletedExceptionally()) + throw reader.exceptionNow(); + assertArrayEquals(sampleData, reader.resultNow()); + } + + static void writeBytes(byte[] data, int chunkSize) { + try (var os = testDevice.openOutputStream(LOOPBACK_EP_OUT)) { + int numBytes = 0; + while (numBytes < data.length) { + int size = Math.min(chunkSize, data.length - numBytes); + os.write(data, numBytes, size); + numBytes += size; + } + + } catch (IOException e) { + throw new RuntimeException(e); + } + } + static byte[] readBytes(int numBytes) { + var buffer = new byte[numBytes]; + try (var is = testDevice.openInputStream(LOOPBACK_EP_IN)) { + int bytesRead = 0; + while (bytesRead < numBytes) { + bytesRead += is.read(buffer, bytesRead, numBytes - bytesRead); + } + + } catch (IOException e) { + throw new RuntimeException(e); + } + return buffer; + } +} From d328d10728883c73c5c9385c072040922868e063 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 14 Oct 2022 13:53:29 +0200 Subject: [PATCH 110/433] Transfer in/out with timeout (MacOS / bulk endpoint only) --- java-does-usb/jextract/macos/gen_macos.sh | 1 + .../net/codecrete/usb/TimeoutException.java | 23 +++++++++ .../java/net/codecrete/usb/USBDevice.java | 36 ++++++++++++++ .../codecrete/usb/common/USBDeviceImpl.java | 7 ++- .../codecrete/usb/linux/LinuxUSBDevice.java | 10 ++++ .../net/codecrete/usb/macos/IoKitUSB.java | 15 ++++++ .../codecrete/usb/macos/MacosUSBDevice.java | 37 +++++++++++---- .../codecrete/usb/macos/gen/iokit/IOKit.java | 3 ++ .../usb/windows/WindowsUSBDevice.java | 10 ++++ .../java/net/codecrete/usb/TimeoutTest.java | 47 +++++++++++++++++++ 10 files changed, 180 insertions(+), 9 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/TimeoutException.java create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index c90d5cbe..fd4cb061 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -57,6 +57,7 @@ $JEXTRACT --source --output ../../src/main/java \ --include-typedef IOUSBDevRequest \ --include-struct IOUSBInterfaceStruct942 \ --include-typedef IOUSBInterfaceInterface \ + --include-macro kIOUSBTransactionTimeout \ iokit_helper.h # mach.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/TimeoutException.java b/java-does-usb/src/main/java/net/codecrete/usb/TimeoutException.java new file mode 100644 index 00000000..2b17a751 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/TimeoutException.java @@ -0,0 +1,23 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb; + +/** + * Exception thrown if a USB operation times out. + */ +public class TimeoutException extends USBException { + + /** + * Creates a new instance with a message. + * + * @param message the message + */ + public TimeoutException(String message) { + super(message); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index 6f4f1f0a..04d311c8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -201,6 +201,22 @@ public interface USBDevice { */ void transferOut(int endpointNumber, byte[] data); + /** + * Sends data to this device. + *

+ * This method blocks until the data has been sent, the timeout period has expired + * or an error has occurred. If the timeout expires, a {@link TimeoutException} is thrown. + *

+ *

+ * This method can send data to bulk and interrupt endpoints. + *

+ * + * @param endpointNumber the endpoint number (in the range between 1 and 127) + * @param timeout the timeout period, in milliseconds + * @param data data to send + */ + void transferOut(int endpointNumber, byte[] data, int timeout); + /** * Receives data from this device. *

@@ -217,6 +233,26 @@ public interface USBDevice { * @return received data */ byte[] transferIn(int endpointNumber, int maxLength); + /** + * Receives data from this device. + *

+ * This method blocks until at least a packet has been received, the timeout period has expired + * or an error has occurred. If the timeout expired, a {@link TimeoutException} is thrown. + *

+ *

+ * {@code maxLength} must be long enough to hold the full data packet transmitted by the device. + * To be on the safe side, it should be equal or greater than the endpoint's maximum packet size. + *

+ *

+ * This method can receive data from bulk and interrupt endpoints. + *

+ * + * @param endpointNumber the endpoint number (in the range between 1 and 127, i.e. without the direction bit) + * @param maxLength the maximum data length to receive (in number of bytes) + * @param timeout the timeout period, in milliseconds + * @return received data + */ + byte[] transferIn(int endpointNumber, int maxLength, int timeout); /** * Opens a new output stream to send data to a bulk endpoint. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 3aa2708c..759d2463 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -306,13 +306,18 @@ protected int getInterfaceNumber(int endpointNumber) { @Override public abstract void controlTransferOut(USBControlTransfer setup, byte[] data); - @Override public abstract void transferOut(int endpointNumber, byte[] data); + @Override + public abstract void transferOut(int endpointNumber, byte[] data, int timeout); + @Override public abstract byte[] transferIn(int endpointNumber, int maxLength); + @Override + public abstract byte[] transferIn(int endpointNumber, int maxLength, int timeout); + @Override public OutputStream openOutputStream(int endpointNumber) { // check that endpoint number is valid diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index d78f6b78..c2fb29a5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -198,6 +198,11 @@ public void transferOut(int endpointNumber, byte[] data) { } } + @Override + public void transferOut(int endpointNumber, byte[] data, int timeout) { + throw new IllegalStateException("Not implemented yet"); + } + @Override public byte[] transferIn(int endpointNumber, int maxLength) { var endpointAddress = getEndpointAddress(endpointNumber, USBDirection.IN, @@ -216,4 +221,9 @@ public byte[] transferIn(int endpointNumber, int maxLength) { return buffer.asSlice(0, res).toArray(JAVA_BYTE); } } + + @Override + public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { + throw new IllegalStateException("not implemented yet"); + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index 4ac6d155..23547eee 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -139,10 +139,25 @@ public static int ReadPipe(MemoryAddress self, byte pipeRef, MemoryAddress buf, } } + // IOReturn (* ReadPipeTO)(void* self, UInt8 pipeRef, void* buf, UInt32* size, UInt32 noDataTimeout, UInt32 completionTimeout); + public static int ReadPipeTO(MemoryAddress self, byte pipeRef, MemoryAddress buf, MemoryAddress sizeHolder, int noDataTimeout, int completionTimeout) { + try (var session = MemorySession.openConfined()) { + return IOUSBInterfaceInterface.ReadPipeTO(getVtable(self, session), session) + .apply(self, pipeRef, buf, sizeHolder, noDataTimeout, completionTimeout); + } + } + // IOReturn (*WritePipe)(void *self, UInt8 pipeRef, void *buf, UInt32 size); public static int WritePipe(MemoryAddress self, byte pipeRef, MemoryAddress buf, int size) { try (var session = MemorySession.openConfined()) { return IOUSBInterfaceInterface.WritePipe(getVtable(self, session), session).apply(self, pipeRef, buf, size); } } + + // IOReturn (* WritePipeTO)(void* self, UInt8 pipeRef, void* buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout); + public static int WritePipeTO(MemoryAddress self, byte pipeRef, MemoryAddress buf, int size, int noDataTimeout, int completionTimeout) { + try (var session = MemorySession.openConfined()) { + return IOUSBInterfaceInterface.WritePipeTO(getVtable(self, session), session).apply(self, pipeRef, buf, size, noDataTimeout, completionTimeout); + } + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 5e72907e..b1992bb8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -7,10 +7,7 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.USBControlTransfer; -import net.codecrete.usb.USBDirection; -import net.codecrete.usb.USBException; -import net.codecrete.usb.USBTransferType; +import net.codecrete.usb.*; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.usbstandard.ConfigurationDescriptor; import net.codecrete.usb.macos.gen.iokit.IOKit; @@ -309,6 +306,11 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { @Override public void transferOut(int endpointNumber, byte[] data) { + transferOut(endpointNumber, data, -1); + } + + @Override + public void transferOut(int endpointNumber, byte[] data, int timeout) { var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); @@ -316,8 +318,15 @@ public void transferOut(int endpointNumber, byte[] data) { try (var session = MemorySession.openConfined()) { var nativeData = session.allocateArray(JAVA_BYTE, data.length); nativeData.copyFrom(MemorySegment.ofArray(data)); - int ret = IoKitUSB.WritePipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, - nativeData.address(), data.length); + int ret; + if (timeout < 0) { + ret = IoKitUSB.WritePipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), data.length); + } else { + ret = IoKitUSB.WritePipeTO(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), + data.length, timeout, timeout); + if (ret == IOKit.kIOUSBTransactionTimeout()) + throw new TimeoutException("Transfer out aborted due to timeout"); + } if (ret != 0) throw new MacosUSBException(String.format("Sending data to endpoint %d failed", endpointNumber), ret); } @@ -325,6 +334,11 @@ public void transferOut(int endpointNumber, byte[] data) { @Override public byte[] transferIn(int endpointNumber, int maxLength) { + return transferIn(endpointNumber, maxLength, -1); + } + + @Override + public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); @@ -332,8 +346,15 @@ public byte[] transferIn(int endpointNumber, int maxLength) { try (var session = MemorySession.openConfined()) { var nativeData = session.allocateArray(JAVA_BYTE, maxLength); var sizeHolder = session.allocate(JAVA_INT, maxLength); - int ret = IoKitUSB.ReadPipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, - nativeData.address(), sizeHolder.address()); + int ret; + if (timeout < 0) { + ret = IoKitUSB.ReadPipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), sizeHolder.address()); + } else { + ret = IoKitUSB.ReadPipeTO(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), + sizeHolder.address(), timeout, timeout); + if (ret == IOKit.kIOUSBTransactionTimeout()) + throw new TimeoutException("Transfer in aborted due to timeout"); + } if (ret != 0) throw new MacosUSBException(String.format("Receiving data from endpoint %d failed", endpointNumber), ret); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java index 59ebcf8b..c14b91e2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java @@ -153,6 +153,9 @@ public static int IOCreatePlugInInterfaceForService ( int service, Addressable throw new AssertionError("should not reach here", ex$); } } + public static int kIOUSBTransactionTimeout() { + return (int)-536854447L; + } public static MemorySegment kIOFirstMatchNotification() { return constants$1.kIOFirstMatchNotification$SEGMENT; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 004b2269..703f26c3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -242,6 +242,11 @@ public void transferOut(int endpointNumber, byte[] data) { } } + @Override + public void transferOut(int endpointNumber, byte[] data, int timeout) { + throw new IllegalStateException("Not implemented yet"); + } + @Override public byte[] transferIn(int endpointNumber, int maxLength) { var endpoint = getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); @@ -260,6 +265,11 @@ public byte[] transferIn(int endpointNumber, int maxLength) { } } + @Override + public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { + throw new IllegalStateException("not implemented yet"); + } + private InterfaceHandle getInterfaceHandle(int interfaceNumber) { for (var intfHandle : interfaceHandles_) { if (intfHandle.interfaceNumber == interfaceNumber) diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java new file mode 100644 index 00000000..309ef43f --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java @@ -0,0 +1,47 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Unit tests for USB device enumeration +// + +package net.codecrete.usb; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +import static org.junit.jupiter.api.Assertions.*; + +public class TimeoutTest extends TestDeviceBase { + + @Test + @Timeout(1) + void bulkTransferIn_timesOut() { + assertThrows(TimeoutException.class, () -> { + testDevice.transferIn(LOOPBACK_EP_IN, 64, 200); + }); + } + + @Test + @Timeout(1) + void bulkTransferOut_timesOut() { + // The test device has an internal buffer of about 500 bytes + assertThrows(TimeoutException.class, () -> { + byte[] data = generateRandomBytes(100, 9383073929L); + for (int i = 0; i < 12; i++) { + testDevice.transferOut(LOOPBACK_EP_OUT, data, 200); + } + }); + + // drain data in loopback loop + while (true) { + try { + testDevice.transferIn(LOOPBACK_EP_IN, 64, 200); + } catch (TimeoutException e) { + break; + } + } + } +} From f2cf1e114462da0d1fac00acc4c5cdcb27baf55f Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 14 Oct 2022 20:46:43 +0200 Subject: [PATCH 111/433] Interrupt transfer with timeout (MacOS) --- java-does-usb/jextract/macos/gen_macos.sh | 1 + .../net/codecrete/usb/macos/IoKitUSB.java | 7 ++ .../codecrete/usb/macos/MacosUSBDevice.java | 88 ++++++++++++++++++- .../codecrete/usb/macos/gen/iokit/IOKit.java | 3 + .../java/net/codecrete/usb/TimeoutTest.java | 57 ++++++++++-- 5 files changed, 149 insertions(+), 7 deletions(-) diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index fd4cb061..7a87c055 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -58,6 +58,7 @@ $JEXTRACT --source --output ../../src/main/java \ --include-struct IOUSBInterfaceStruct942 \ --include-typedef IOUSBInterfaceInterface \ --include-macro kIOUSBTransactionTimeout \ + --include-macro kIOReturnAborted \ iokit_helper.h # mach.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index 23547eee..5fa3b2ec 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -160,4 +160,11 @@ public static int WritePipeTO(MemoryAddress self, byte pipeRef, MemoryAddress bu return IOUSBInterfaceInterface.WritePipeTO(getVtable(self, session), session).apply(self, pipeRef, buf, size, noDataTimeout, completionTimeout); } } + + // IOReturn (* AbortPipe)(void* self, UInt8 pipeRef); + public static int AbortPipe(MemoryAddress self, byte pipeRef) { + try (var session = MemorySession.openConfined()) { + return IOUSBInterfaceInterface.AbortPipe(getVtable(self, session), session).apply(self, pipeRef); + } + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index b1992bb8..3765fde6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -21,6 +21,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; import static java.lang.foreign.MemoryAddress.ofLong; import static java.lang.foreign.ValueLayout.*; @@ -32,6 +36,8 @@ public class MacosUSBDevice extends USBDeviceImpl { private List claimedInterfaces; private Map endpoints; + private ScheduledExecutorService scheduledExecutorService; + MacosUSBDevice(MemoryAddress device, Object id, int vendorId, int productId) { super(id, vendorId, productId); this.device = device; @@ -319,14 +325,29 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { var nativeData = session.allocateArray(JAVA_BYTE, data.length); nativeData.copyFrom(MemorySegment.ofArray(data)); int ret; + if (timeout < 0) { + // transfer without timeout ret = IoKitUSB.WritePipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), data.length); - } else { + + } else if (endpointInfo.transferType == USBTransferType.BULK) { + + // bulk transfer with timeout ret = IoKitUSB.WritePipeTO(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), data.length, timeout, timeout); if (ret == IOKit.kIOUSBTransactionTimeout()) throw new TimeoutException("Transfer out aborted due to timeout"); + + } else { + + // interrupt transfer with timeout + var transferTimeout = new TransferTimeout(endpointInfo, timeout); + ret = IoKitUSB.WritePipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), data.length); + if (ret == IOKit.kIOReturnAborted()) + throw new TimeoutException("Transfer out aborted due to timeout"); + transferTimeout.markCompleted(); } + if (ret != 0) throw new MacosUSBException(String.format("Sending data to endpoint %d failed", endpointNumber), ret); } @@ -347,13 +368,27 @@ public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { var nativeData = session.allocateArray(JAVA_BYTE, maxLength); var sizeHolder = session.allocate(JAVA_INT, maxLength); int ret; + if (timeout < 0) { + // transfer without timeout ret = IoKitUSB.ReadPipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), sizeHolder.address()); - } else { + + } else if (endpointInfo.transferType == USBTransferType.BULK) { + + // bulk transfer with timeout ret = IoKitUSB.ReadPipeTO(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), sizeHolder.address(), timeout, timeout); if (ret == IOKit.kIOUSBTransactionTimeout()) throw new TimeoutException("Transfer in aborted due to timeout"); + + } else { + + // interrupt transfer with timeout + var transferTimeout = new TransferTimeout(endpointInfo, timeout); + ret = IoKitUSB.ReadPipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), sizeHolder.address()); + if (ret == IOKit.kIOReturnAborted()) + throw new TimeoutException("Transfer in aborted due to timeout"); + transferTimeout.markCompleted(); } if (ret != 0) throw new MacosUSBException(String.format("Receiving data from endpoint %d failed", endpointNumber), @@ -368,6 +403,12 @@ public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { } } + synchronized ScheduledExecutorService getScheduledExecutorService() { + if (scheduledExecutorService == null) + scheduledExecutorService = Executors.newScheduledThreadPool(1); + return scheduledExecutorService; + } + private static USBTransferType getTransferType(byte macosTransferType) { return switch (macosTransferType) { case 1 -> USBTransferType.ISOCHRONOUS; @@ -388,4 +429,47 @@ MemoryAddress interfacAddress() { return ofLong(interfaceAddr); } } + + /** + * Manages the timeout for a USB transfer. + *

+ * Not used for bulk transfers as IOKit offers suitable functions ({@code WritePipeTO()}, {@code ReadPipeTO()}). + *

+ */ + class TransferTimeout { + /** + * Schedules a timeout for the specified endpoint. + *

+ * If the timeout expires, the transfer is aborted. + *

+ * @param endpointInfo endpoint information + * @param timeout timeout, in milliseconds + */ + TransferTimeout(EndpointInfo endpointInfo, int timeout) { + this.endpointInfo = endpointInfo; + future = getScheduledExecutorService().schedule(this::abort, timeout, TimeUnit.MILLISECONDS); + } + + private synchronized void abort() { + if (completed) + return; + int ret = IoKitUSB.AbortPipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex()); + if (ret != 0) + throw new MacosUSBException("Failed to abort USB transfer after timeout", ret); + } + + /** + * Marks the transfer as completed and cancels the timeout. + */ + synchronized void markCompleted() { + if (completed) + return; + completed = true; + future.cancel(false); + } + + ScheduledFuture future; + EndpointInfo endpointInfo; + boolean completed; + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java index c14b91e2..b5ab2e35 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java @@ -153,6 +153,9 @@ public static int IOCreatePlugInInterfaceForService ( int service, Addressable throw new AssertionError("should not reach here", ex$); } } + public static int kIOReturnAborted() { + return (int)-536870165L; + } public static int kIOUSBTransactionTimeout() { return (int)-536854447L; } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java index 309ef43f..c418071c 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java @@ -9,15 +9,19 @@ package net.codecrete.usb; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; +import java.io.ByteArrayOutputStream; +import java.util.concurrent.TimeUnit; + import static org.junit.jupiter.api.Assertions.*; public class TimeoutTest extends TestDeviceBase { @Test - @Timeout(1) + @Timeout(value = 1, unit = TimeUnit.SECONDS) void bulkTransferIn_timesOut() { assertThrows(TimeoutException.class, () -> { testDevice.transferIn(LOOPBACK_EP_IN, 64, 200); @@ -25,12 +29,27 @@ void bulkTransferIn_timesOut() { } @Test - @Timeout(1) + @Timeout(value = 1, unit = TimeUnit.SECONDS) + void bulkTransfer_doesNotTimeOut() { + byte[] data = generateRandomBytes(20, 7280277392L); + testDevice.transferOut(LOOPBACK_EP_OUT, data); + + byte[] received = testDevice.transferIn(LOOPBACK_EP_IN, 64, 200); + assertArrayEquals(data, received); + + } + + @Test + @Timeout(value = 1, unit = TimeUnit.SECONDS) void bulkTransferOut_timesOut() { - // The test device has an internal buffer of about 500 bytes + // The test device has an internal buffer of about 500 bytes. + // So the first transfer should not time out. + + byte[] data = generateRandomBytes(100, 9383073929L); + testDevice.transferOut(LOOPBACK_EP_OUT, data, 200); + assertThrows(TimeoutException.class, () -> { - byte[] data = generateRandomBytes(100, 9383073929L); - for (int i = 0; i < 12; i++) { + for (int i = 0; i < 10; i++) { testDevice.transferOut(LOOPBACK_EP_OUT, data, 200); } }); @@ -44,4 +63,32 @@ void bulkTransferOut_timesOut() { } } } + + @Test + @Timeout(value = 1, unit = TimeUnit.SECONDS) + void interruptTransferIn_timesOut() { + Assumptions.assumeTrue(testDevice.productId() == PID_LOOPBACK, + "Interrupt transfer only supported by loopback test device"); + + assertThrows(TimeoutException.class, () -> { + testDevice.transferIn(ECHO_EP_IN, 16, 200); + }); + } + + @Test + void interruptTransfer_doesNotTimeOut() { + Assumptions.assumeTrue(testDevice.productId() == PID_LOOPBACK, + "Interrupt transfer only supported by loopback test device"); + + byte[] sampleData = generateRandomBytes(12, 293872394); + testDevice.transferOut(ECHO_EP_OUT, sampleData, 200); + + // receive first echo + byte[] echo = testDevice.transferIn(ECHO_EP_IN, ECHO_MAX_PACKET_SIZE, 200); + assertArrayEquals(sampleData, echo); + + // receive second echo + echo = testDevice.transferIn(ECHO_EP_IN, ECHO_MAX_PACKET_SIZE, 200); + assertArrayEquals(sampleData, echo); + } } From 5a889257def4dc2d49a4df4cf0cc0355134652bf Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 14 Oct 2022 20:47:02 +0200 Subject: [PATCH 112/433] MacOS reference code: extended pipe info --- reference/macos/USB/usb_device.cpp | 43 +++++++++++++++++------------- reference/macos/USB/usb_device.hpp | 14 +++++++--- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/reference/macos/USB/usb_device.cpp b/reference/macos/USB/usb_device.cpp index 1c6c7f83..1ecd27b2 100644 --- a/reference/macos/USB/usb_device.cpp +++ b/reference/macos/USB/usb_device.cpp @@ -124,15 +124,18 @@ void usb_device::claim_interface(int interface_number) { ret = (*interface)->GetNumEndpoints(interface, &num_pipes); usb_error::check(ret, "internal error (GetNumEndpoints)"); - endpoint_addresses_.clear(); + pipes_.clear(); for (int i = 1; i <= num_pipes; i++) { UInt8 direction = 0; UInt8 number = 0; + UInt8 transfer_type = 0; UInt8 ignore = 0; UInt16 ignore2 = 0; - ret = (*interface)->GetPipeProperties(interface, i, &direction, &number, &ignore, &ignore2, &ignore); + ret = (*interface)->GetPipeProperties(interface, i, &direction, &number, &transfer_type, &ignore2, &ignore); usb_error::check(ret, "internal error (GetPipeProperties)"); - endpoint_addresses_.push_back((direction << 7) | number); + pipe_info pipe{(UInt8) i, (uint8_t)((direction << 7) | number), transfer_type}; + ; + pipes_.push_back(pipe); } interface_ = interface; @@ -146,20 +149,23 @@ void usb_device::release_interface() { (*interface_)->USBInterfaceClose(interface_); (*interface_)->Release(interface_); interface_ = nullptr; - endpoint_addresses_.clear(); + pipes_.clear(); } std::vector usb_device::transfer_in(int endpoint_number, int data_len, int timeout) { if (interface_ == nullptr) throw usb_error("no interface has been claimed"); + + auto pipe = ep_in_pipe(endpoint_number); UInt32 size = data_len; std::vector data(data_len); IOReturn ret; - if (timeout != 0) - ret = (*interface_)->ReadPipeTO(interface_, ep_in_pipe(endpoint_number), data.data(), &size, timeout, timeout); - else - ret = (*interface_)->ReadPipe(interface_, ep_in_pipe(endpoint_number), data.data(), &size); + if (timeout != 0) { + ret = (*interface_)->ReadPipeTO(interface_, pipe->pipe_index, data.data(), &size, timeout, timeout); + } else { + ret = (*interface_)->ReadPipe(interface_, pipe->pipe_index, data.data(), &size); + } if (ret != kIOReturnSuccess) { if (ret == kIOUSBTransactionTimeout) @@ -178,9 +184,9 @@ void usb_device::transfer_out(int endpoint_number, const std::vector& d IOReturn ret; if (timeout != 0) - ret = (*interface_)->WritePipeTO(interface_, ep_out_pipe(endpoint_number), const_cast(data.data()), static_cast(data.size()), timeout, timeout); + ret = (*interface_)->WritePipeTO(interface_, ep_out_pipe(endpoint_number)->pipe_index, const_cast(data.data()), static_cast(data.size()), timeout, timeout); else - ret = (*interface_)->WritePipe(interface_, ep_out_pipe(endpoint_number), const_cast(data.data()), static_cast(data.size())); + ret = (*interface_)->WritePipe(interface_, ep_out_pipe(endpoint_number)->pipe_index, const_cast(data.data()), static_cast(data.size())); if (ret != kIOReturnSuccess) { if (ret == kIOUSBTransactionTimeout) @@ -247,18 +253,19 @@ std::vector usb_device::control_transfer_in(const usb_control_request& return data; } -UInt8 usb_device::ep_to_pipe(int endpoint_address) { - auto it = std::find (endpoint_addresses_.begin(), endpoint_addresses_.end(), endpoint_address); - if (it != endpoint_addresses_.end()) - return std::distance(endpoint_addresses_.begin(), it) + 1; +const pipe_info* usb_device::get_pipe(int endpoint_address) { + auto it = std::find_if(pipes_.begin(), pipes_.end(), + [endpoint_address](const pipe_info& pipe){ return pipe.endpoint_address == endpoint_address; }); + if (it != pipes_.end()) + return &*it; throw usb_error("invalid endpoint number"); } -UInt8 usb_device::ep_out_pipe(int endpoint_number) { - return ep_to_pipe(endpoint_number); + const pipe_info* usb_device::ep_out_pipe(int endpoint_number) { + return get_pipe(endpoint_number); } -UInt8 usb_device::ep_in_pipe(int endpoint_number) { - return ep_to_pipe(endpoint_number + 128); + const pipe_info* usb_device::ep_in_pipe(int endpoint_number) { + return get_pipe(endpoint_number + 128); } diff --git a/reference/macos/USB/usb_device.hpp b/reference/macos/USB/usb_device.hpp index f6c729f8..2963420c 100644 --- a/reference/macos/USB/usb_device.hpp +++ b/reference/macos/USB/usb_device.hpp @@ -68,6 +68,12 @@ struct usb_control_request { } }; +struct pipe_info { + UInt8 pipe_index; + uint8_t endpoint_address; + uint8_t transfer_type; +}; + /** * USB device. @@ -190,16 +196,16 @@ class usb_device { private: usb_device(io_service_t service, IOUSBDeviceInterface** device, uint64_t entry_id, int vendor_id, int product_id); uint64_t entry_id() const { return entry_id_; } - UInt8 ep_to_pipe(int endpoint_address); - UInt8 ep_out_pipe(int endpoint_number); - UInt8 ep_in_pipe(int endpoint_number); + const pipe_info* get_pipe(int endpoint_address); + const pipe_info* ep_in_pipe(int endpoint_address); + const pipe_info* ep_out_pipe(int endpoint_address); int control_transfer_core(const usb_control_request& request, uint8_t* data, int timeout); uint64_t entry_id_; IOUSBDeviceInterface** device_; bool is_open_; IOUSBInterfaceInterface** interface_; - std::vector endpoint_addresses_; + std::vector pipes_; int product_id_; int vendor_id_; From 7c5d687e0694280e84bb123563d0c88cc11eda80 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 15 Oct 2022 08:17:37 +0200 Subject: [PATCH 113/433] Transfer in/out with timeout (Windows) --- java-does-usb/jextract/windows/gen_win.cmd | 3 ++ .../java/net/codecrete/usb/USBDevice.java | 4 +- .../codecrete/usb/macos/MacosUSBDevice.java | 4 +- .../usb/windows/WindowsUSBDevice.java | 50 ++++++++++++++----- .../usb/windows/gen/kernel32/Kernel32.java | 3 ++ .../usb/windows/gen/winusb/WinUSB.java | 16 +++++- .../usb/windows/gen/winusb/constants$0.java | 19 ++++--- .../usb/windows/gen/winusb/constants$1.java | 12 +++++ 8 files changed, 84 insertions(+), 27 deletions(-) diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index c69865d2..df77355b 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -20,6 +20,7 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-macro ERROR_MORE_DATA ^ --include-macro ERROR_INSUFFICIENT_BUFFER ^ --include-macro ERROR_FILE_NOT_FOUND ^ + --include-macro ERROR_SEM_TIMEOUT ^ --include-macro GENERIC_READ ^ --include-macro GENERIC_WRITE ^ --include-macro FILE_SHARE_READ ^ @@ -128,6 +129,8 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-function WinUsb_WritePipe ^ --include-function WinUsb_ReadPipe ^ --include-function WinUsb_GetAssociatedInterface ^ + --include-function WinUsb_SetPipePolicy ^ + --include-macro PIPE_TRANSFER_TIMEOUT ^ windows_headers.h call %JEXTRACT% --source --output ../../src/main/java ^ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index 04d311c8..8881bb60 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -212,7 +212,7 @@ public interface USBDevice { *

* * @param endpointNumber the endpoint number (in the range between 1 and 127) - * @param timeout the timeout period, in milliseconds + * @param timeout the timeout period, in milliseconds (0 for no timeout) * @param data data to send */ void transferOut(int endpointNumber, byte[] data, int timeout); @@ -249,7 +249,7 @@ public interface USBDevice { * * @param endpointNumber the endpoint number (in the range between 1 and 127, i.e. without the direction bit) * @param maxLength the maximum data length to receive (in number of bytes) - * @param timeout the timeout period, in milliseconds + * @param timeout the timeout period, in milliseconds (0 for no timeout) * @return received data */ byte[] transferIn(int endpointNumber, int maxLength, int timeout); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 3765fde6..a08b10bb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -326,7 +326,7 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { nativeData.copyFrom(MemorySegment.ofArray(data)); int ret; - if (timeout < 0) { + if (timeout <= 0) { // transfer without timeout ret = IoKitUSB.WritePipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), data.length); @@ -369,7 +369,7 @@ public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { var sizeHolder = session.allocate(JAVA_INT, maxLength); int ret; - if (timeout < 0) { + if (timeout <= 0) { // transfer without timeout ret = IoKitUSB.ReadPipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), sizeHolder.address()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 703f26c3..2e8da861 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -9,6 +9,7 @@ import net.codecrete.usb.*; import net.codecrete.usb.common.USBDeviceImpl; +import net.codecrete.usb.macos.gen.iokit.IOKit; import net.codecrete.usb.usbstandard.SetupPacket; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.winusb.WinUSB; @@ -226,50 +227,75 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { @Override public void transferOut(int endpointNumber, byte[] data) { + transferOut(endpointNumber, data, 0); + } + + @Override + public void transferOut(int endpointNumber, byte[] data, int timeout) { checkIsOpen(); var endpoint = getEndpoint(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var session = MemorySession.openConfined()) { + // set timeout + var timeoutHolder = session.allocate(JAVA_INT, timeout); + if (WinUSB.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), + WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder) == 0) + throw new WindowsUSBException("Setting timeout failed", Kernel32.GetLastError()); + + // copy data to native heap var buffer = session.allocate(data.length); buffer.copyFrom(MemorySegment.ofArray(data)); var lengthHolder = session.allocate(JAVA_INT); + // send data if (WinUSB.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, (int) buffer.byteSize(), - lengthHolder, NULL) == 0) - throw new WindowsUSBException("Bulk/interrupt transfer OUT failed", Kernel32.GetLastError()); + lengthHolder, NULL) == 0) { + int err = Kernel32.GetLastError(); + if (err == Kernel32.ERROR_SEM_TIMEOUT()) + throw new TimeoutException("Transfer out aborted due to timeout"); + throw new WindowsUSBException("Bulk/interrupt transfer OUT failed", err); + } } } @Override - public void transferOut(int endpointNumber, byte[] data, int timeout) { - throw new IllegalStateException("Not implemented yet"); + public byte[] transferIn(int endpointNumber, int maxLength) { + return transferIn(endpointNumber, maxLength, 0); } @Override - public byte[] transferIn(int endpointNumber, int maxLength) { + public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { var endpoint = getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var session = MemorySession.openConfined()) { + // set timeout + var timeoutHolder = session.allocate(JAVA_INT, timeout); + if (WinUSB.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), + WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder) == 0) + throw new WindowsUSBException("Setting timeout failed", Kernel32.GetLastError()); + + // create native heap buffer for data var buffer = session.allocate(maxLength); var lengthHolder = session.allocate(JAVA_INT); + // receive data if (WinUSB.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, (int) buffer.byteSize(), - lengthHolder, NULL) == 0) - throw new WindowsUSBException("Bulk/interrupt transfer IN failed", Kernel32.GetLastError()); + lengthHolder, NULL) == 0) { + int err = Kernel32.GetLastError(); + if (err == Kernel32.ERROR_SEM_TIMEOUT()) + throw new TimeoutException("Transfer in aborted due to timeout"); + throw new WindowsUSBException("Bulk/interrupt transfer IN failed", err); + } + // copy data int len = lengthHolder.get(JAVA_INT, 0); return buffer.asSlice(0, len).toArray(JAVA_BYTE); } } - @Override - public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { - throw new IllegalStateException("not implemented yet"); - } - private InterfaceHandle getInterfaceHandle(int interfaceNumber) { for (var intfHandle : interfaceHandles_) { if (intfHandle.interfaceNumber == interfaceNumber) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java index f4de7118..e91ab190 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -131,6 +131,9 @@ public static int ERROR_SUCCESS() { public static int ERROR_FILE_NOT_FOUND() { return (int)2L; } + public static int ERROR_SEM_TIMEOUT() { + return (int)121L; + } public static int ERROR_INSUFFICIENT_BUFFER() { return (int)122L; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java index f3cc4111..a218a6d8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java @@ -18,6 +18,9 @@ public class WinUSB { public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static int PIPE_TRANSFER_TIMEOUT() { + return (int)3L; + } public static MethodHandle WinUsb_Initialize$MH() { return RuntimeHelper.requireNonNull(constants$0.WinUsb_Initialize$MH,"WinUsb_Initialize"); } @@ -62,6 +65,17 @@ public static int WinUsb_GetDescriptor ( Addressable InterfaceHandle, byte Desc throw new AssertionError("should not reach here", ex$); } } + public static MethodHandle WinUsb_SetPipePolicy$MH() { + return RuntimeHelper.requireNonNull(constants$0.WinUsb_SetPipePolicy$MH,"WinUsb_SetPipePolicy"); + } + public static int WinUsb_SetPipePolicy ( Addressable InterfaceHandle, byte PipeID, int PolicyType, int ValueLength, Addressable Value) { + var mh$ = WinUsb_SetPipePolicy$MH(); + try { + return (int)mh$.invokeExact(InterfaceHandle, PipeID, PolicyType, ValueLength, Value); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static MethodHandle WinUsb_ReadPipe$MH() { return RuntimeHelper.requireNonNull(constants$0.WinUsb_ReadPipe$MH,"WinUsb_ReadPipe"); } @@ -74,7 +88,7 @@ public static int WinUsb_ReadPipe ( Addressable InterfaceHandle, byte PipeID, } } public static MethodHandle WinUsb_WritePipe$MH() { - return RuntimeHelper.requireNonNull(constants$0.WinUsb_WritePipe$MH,"WinUsb_WritePipe"); + return RuntimeHelper.requireNonNull(constants$1.WinUsb_WritePipe$MH,"WinUsb_WritePipe"); } public static int WinUsb_WritePipe ( Addressable InterfaceHandle, byte PipeID, Addressable Buffer, int BufferLength, Addressable LengthTransferred, Addressable Overlapped) { var mh$ = WinUsb_WritePipe$MH(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java index 66a14d35..18a072c8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java @@ -43,19 +43,18 @@ class constants$0 { "WinUsb_GetDescriptor", constants$0.WinUsb_GetDescriptor$FUNC ); - static final FunctionDescriptor WinUsb_ReadPipe$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + static final FunctionDescriptor WinUsb_SetPipePolicy$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle WinUsb_ReadPipe$MH = RuntimeHelper.downcallHandle( - "WinUsb_ReadPipe", - constants$0.WinUsb_ReadPipe$FUNC + static final MethodHandle WinUsb_SetPipePolicy$MH = RuntimeHelper.downcallHandle( + "WinUsb_SetPipePolicy", + constants$0.WinUsb_SetPipePolicy$FUNC ); - static final FunctionDescriptor WinUsb_WritePipe$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + static final FunctionDescriptor WinUsb_ReadPipe$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_CHAR$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -63,9 +62,9 @@ class constants$0 { Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle WinUsb_WritePipe$MH = RuntimeHelper.downcallHandle( - "WinUsb_WritePipe", - constants$0.WinUsb_WritePipe$FUNC + static final MethodHandle WinUsb_ReadPipe$MH = RuntimeHelper.downcallHandle( + "WinUsb_ReadPipe", + constants$0.WinUsb_ReadPipe$FUNC ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java index 123b8fad..08552176 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java @@ -7,6 +7,18 @@ import java.lang.invoke.MethodHandle; class constants$1 { + static final FunctionDescriptor WinUsb_WritePipe$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle WinUsb_WritePipe$MH = RuntimeHelper.downcallHandle( + "WinUsb_WritePipe", + constants$1.WinUsb_WritePipe$FUNC + ); static final FunctionDescriptor WinUsb_ControlTransfer$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, MemoryLayout.structLayout( From 3de278ec3cd0a478a40e2dac5f9a2cfe1a57adcb Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 15 Oct 2022 10:39:58 +0200 Subject: [PATCH 114/433] Bulk/interrupt transfer with timeout (Linux) --- java-does-usb/jextract/linux/gen_linux.sh | 1 + .../codecrete/usb/common/USBDeviceImpl.java | 8 +++- .../codecrete/usb/linux/LinuxUSBDevice.java | 45 +++++++++---------- .../codecrete/usb/linux/gen/errno/errno.java | 3 ++ .../codecrete/usb/macos/MacosUSBDevice.java | 10 ----- .../usb/windows/WindowsUSBDevice.java | 10 ----- 6 files changed, 30 insertions(+), 47 deletions(-) diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index cd7ece06..09930002 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -15,6 +15,7 @@ $JEXTRACT --source --output ../../src/main/java \ --header-class-name errno \ --target-package net.codecrete.usb.linux.gen.errno \ --include-function __errno_location \ + --include-macro ETIMEDOUT \ /usr/include/errno.h # ioctl.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 759d2463..3197357f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -307,13 +307,17 @@ protected int getInterfaceNumber(int endpointNumber) { public abstract void controlTransferOut(USBControlTransfer setup, byte[] data); @Override - public abstract void transferOut(int endpointNumber, byte[] data); + public void transferOut(int endpointNumber, byte[] data) { + transferOut(endpointNumber, data, 0); + } @Override public abstract void transferOut(int endpointNumber, byte[] data, int timeout); @Override - public abstract byte[] transferIn(int endpointNumber, int maxLength); + public byte[] transferIn(int endpointNumber, int maxLength) { + return transferIn(endpointNumber, maxLength, 0); + } @Override public abstract byte[] transferIn(int endpointNumber, int maxLength, int timeout); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index c2fb29a5..6ea0f309 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -7,11 +7,9 @@ package net.codecrete.usb.linux; -import net.codecrete.usb.USBControlTransfer; -import net.codecrete.usb.USBDirection; -import net.codecrete.usb.USBException; -import net.codecrete.usb.USBTransferType; +import net.codecrete.usb.*; import net.codecrete.usb.common.*; +import net.codecrete.usb.linux.gen.errno.errno; import net.codecrete.usb.usbstandard.DeviceDescriptor; import net.codecrete.usb.linux.gen.fcntl.fcntl; import net.codecrete.usb.linux.gen.ioctl.ioctl; @@ -173,57 +171,54 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { } } - private MemorySegment createBulkTransfer(MemorySession session, byte endpointAddress, MemorySegment data) { + private MemorySegment createBulkTransfer(MemorySession session, byte endpointAddress, MemorySegment data, int timeout) { var transfer = session.allocate(usbdevfs_bulktransfer.$LAYOUT()); usbdevfs_bulktransfer.ep$set(transfer, 255 & endpointAddress); usbdevfs_bulktransfer.len$set(transfer, (int) data.byteSize()); usbdevfs_bulktransfer.data$set(transfer, data.address()); + usbdevfs_bulktransfer.timeout$set(transfer, timeout); return transfer; } @Override - public void transferOut(int endpointNumber, byte[] data) { + public void transferOut(int endpointNumber, byte[] data, int timeout) { var endpointAddress = getEndpointAddress(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); try (var session = MemorySession.openConfined()) { var buffer = session.allocate(data.length); buffer.copyFrom(MemorySegment.ofArray(data)); - var transfer = createBulkTransfer(session, endpointAddress, buffer); + var transfer = createBulkTransfer(session, endpointAddress, buffer, timeout); int res = ioctl.ioctl(fd, USBDevFS.BULK, transfer.address()); - if (res < 0) - throw new USBException(String.format("USB OUT transfer on endpoint %d failed", endpointNumber), - IO.getErrno()); + if (res < 0) { + int err = IO.getErrno(); + if (err == errno.ETIMEDOUT()) + throw new TimeoutException("Transfer out aborted due to timeout"); + throw new USBException(String.format("USB OUT transfer on endpoint %d failed", endpointNumber), err); + } } } @Override - public void transferOut(int endpointNumber, byte[] data, int timeout) { - throw new IllegalStateException("Not implemented yet"); - } - - @Override - public byte[] transferIn(int endpointNumber, int maxLength) { + public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { var endpointAddress = getEndpointAddress(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); try (var session = MemorySession.openConfined()) { var buffer = session.allocate(maxLength); - var transfer = createBulkTransfer(session, endpointAddress, buffer); + var transfer = createBulkTransfer(session, endpointAddress, buffer, timeout); int res = ioctl.ioctl(fd, USBDevFS.BULK, transfer.address()); - if (res < 0) - throw new USBException(String.format("USB IN transfer on endpoint %d failed", endpointNumber), - IO.getErrno()); + if (res < 0) { + int err = IO.getErrno(); + if (err == errno.ETIMEDOUT()) + throw new TimeoutException("Transfer in aborted due to timeout"); + throw new USBException(String.format("USB IN transfer on endpoint %d failed", endpointNumber), err); + } return buffer.asSlice(0, res).toArray(JAVA_BYTE); } } - - @Override - public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { - throw new IllegalStateException("not implemented yet"); - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java index ddc5d6e8..e043d7e9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -17,6 +17,9 @@ public class errno { public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static int ETIMEDOUT() { + return (int)110L; + } public static MethodHandle __errno_location$MH() { return RuntimeHelper.requireNonNull(constants$0.__errno_location$MH,"__errno_location"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index a08b10bb..fb63038c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -310,11 +310,6 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { } } - @Override - public void transferOut(int endpointNumber, byte[] data) { - transferOut(endpointNumber, data, -1); - } - @Override public void transferOut(int endpointNumber, byte[] data, int timeout) { @@ -353,11 +348,6 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { } } - @Override - public byte[] transferIn(int endpointNumber, int maxLength) { - return transferIn(endpointNumber, maxLength, -1); - } - @Override public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 2e8da861..258f10a0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -225,11 +225,6 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { } } - @Override - public void transferOut(int endpointNumber, byte[] data) { - transferOut(endpointNumber, data, 0); - } - @Override public void transferOut(int endpointNumber, byte[] data, int timeout) { checkIsOpen(); @@ -260,11 +255,6 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { } } - @Override - public byte[] transferIn(int endpointNumber, int maxLength) { - return transferIn(endpointNumber, maxLength, 0); - } - @Override public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { var endpoint = getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); From 828fe058c99721ed79390e721ac9fabcce4ce45c Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 15 Oct 2022 16:16:13 +0200 Subject: [PATCH 115/433] Test device can be reset --- README.md | 6 +-- .../net/codecrete/usb/DescriptionTest.java | 15 +++---- .../codecrete/usb/InterruptTransferTest.java | 2 +- .../net/codecrete/usb/TestDeviceBase.java | 43 +++++++++++++++++++ .../java/net/codecrete/usb/TimeoutTest.java | 4 +- test-devices/composite-stm32/src/main.c | 27 +++++++++--- .../composite-stm32/src/usb_descriptors.c | 4 +- .../loopback-stm32/.vscode/settings.json | 6 +++ test-devices/loopback-stm32/README.md | 1 + test-devices/loopback-stm32/src/main.c | 24 ++++++++++- .../loopback-stm32/src/usb_descriptors.c | 2 +- 11 files changed, 108 insertions(+), 26 deletions(-) create mode 100644 test-devices/loopback-stm32/.vscode/settings.json diff --git a/README.md b/README.md index 2c30dfb9..39423b3d 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ It has been tested with Azul Zulu 19.0.77 EA 34. - Single API for all operating systems (similar to WebUSB API) - Enumeration of USB devices -- Control, bulk and interrupt transfer +- Control, bulk and interrupt transfers (optionally with timeout) - Notifications about connected/disconnected devices - Descriptive information about interfaces, settings and endpoints - Support fo composite devices and interface association @@ -32,15 +32,13 @@ It has been tested with Azul Zulu 19.0.77 EA 34. ### To do -- Transfers with time-out -- Device and USB protocol revision - Alternate interface settings - Isochronous transfer ### Not planned - Changing configuration: The library selects the first configuration. Changing configurations is rarely used and not supported on Windows. -- USB 3.0 streams: Not supported on Windows. +- USB 3.0 streams: Not supported on Windows (limitation of WinUSB). - Providing information about USB buses, controllers and hubs diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index f1ace49f..34820380 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -21,7 +21,7 @@ public class DescriptionTest extends TestDeviceBase { @Test void deviceInfo_isCorrect() { assertEquals("JavaDoesUSB", testDevice.manufacturer()); - assertEquals("Loopback", testDevice.product()); + assertEquals(isLoopbackDevice() ? "Loopback" : "Composite", testDevice.product()); assertEquals(12, testDevice.serialNumber().length()); if (interfaceNumber == 2) { @@ -36,7 +36,7 @@ void deviceInfo_isCorrect() { assertEquals(0x00, testDevice.protocolCode()); } - boolean isComposite = pid == TestDeviceBase.PID_COMPOSITE; + boolean isComposite = isCompositeDevce(); assertEquals(2, testDevice.usbVersion().major()); assertEquals(isComposite ? 1 : 0, testDevice.usbVersion().minor()); @@ -44,7 +44,7 @@ void deviceInfo_isCorrect() { assertEquals(0, testDevice.deviceVersion().major()); assertEquals(isComposite ? 3 : 7, testDevice.deviceVersion().minor()); - assertEquals(isComposite ? 5 : 2, testDevice.deviceVersion().subminor()); + assertEquals(isComposite ? 6 : 3, testDevice.deviceVersion().subminor()); } @Test @@ -74,11 +74,9 @@ void alternateInterfaceDescriptor_isCorrect() { @Test void endpointDescriptors_areCorrect() { - boolean isLoopbackDevice = testDevice.productId() == PID_LOOPBACK; - var altIntf = testDevice.interfaces().get(interfaceNumber).alternate(); assertNotNull(altIntf.endpoints()); - assertEquals(isLoopbackDevice ? 4 : 2, altIntf.endpoints().size()); + assertEquals(isLoopbackDevice() ? 4 : 2, altIntf.endpoints().size()); var endpoint = altIntf.endpoints().get(0); assertEquals(1, endpoint.number()); @@ -92,7 +90,7 @@ void endpointDescriptors_areCorrect() { assertEquals(USBTransferType.BULK, endpoint.transferType()); assertEquals(64, endpoint.packetSize()); - if (isLoopbackDevice) { + if (isLoopbackDevice()) { endpoint = altIntf.endpoints().get(2); assertEquals(3, endpoint.number()); assertEquals(USBDirection.OUT, endpoint.direction()); @@ -109,8 +107,7 @@ void endpointDescriptors_areCorrect() { @Test void configurationDescription_isAvailable() { - boolean isLoopbackDevice = testDevice.productId() == PID_LOOPBACK; - int expectedLength = isLoopbackDevice ? 46 : 98; + int expectedLength = isLoopbackDevice() ? 46 : 98; byte[] configDesc = testDevice.configurationDescriptor(); assertNotNull(configDesc); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java index 1d0a0c6d..d3ff2ee5 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java @@ -18,7 +18,7 @@ public class InterruptTransferTest extends TestDeviceBase { @Test void smallTransfer_succeeds() { - Assumptions.assumeTrue(testDevice.productId() == PID_LOOPBACK, + Assumptions.assumeTrue(isLoopbackDevice(), "Interrupt transfer only supported by loopback test device"); byte[] sampleData = generateRandomBytes(12, 293872394); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index 640f4b9e..87089c57 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -78,6 +78,8 @@ static void openDevice() { testDevice.open(); testDevice.claimInterface(interfaceNumber); + + resetDevice(); } @AfterAll @@ -88,6 +90,47 @@ static void closeDevice() { } } + static boolean isLoopbackDevice() { + return pid == PID_LOOPBACK; + } + + static boolean isCompositeDevce() { + return pid == PID_COMPOSITE; + } + + private static void resetDevice() { + // reset buffers + resetBuffers(); + + // drain loopback data + while (true) { + try { + testDevice.transferIn(LOOPBACK_EP_IN, LOOPBACK_MAX_PACKET_SIZE, 1); + } catch (TimeoutException e) { + break; + } + } + + // drain interrupt data + if (isLoopbackDevice()) { + while (true) { + try { + testDevice.transferIn(ECHO_EP_IN, ECHO_MAX_PACKET_SIZE, 1); + } catch (TimeoutException e) { + break; + } + } + } + + // reset buffers again + resetBuffers(); + } + + static void resetBuffers() { + testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, + (byte) 0x04, (short) 0, (short) interfaceNumber), null); + } + static byte[] generateRandomBytes(int numBytes, long seed) { var random = new Random(seed); var bytes = new byte[numBytes]; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java index c418071c..1e847fdf 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java @@ -67,7 +67,7 @@ void bulkTransferOut_timesOut() { @Test @Timeout(value = 1, unit = TimeUnit.SECONDS) void interruptTransferIn_timesOut() { - Assumptions.assumeTrue(testDevice.productId() == PID_LOOPBACK, + Assumptions.assumeTrue(isLoopbackDevice(), "Interrupt transfer only supported by loopback test device"); assertThrows(TimeoutException.class, () -> { @@ -77,7 +77,7 @@ void interruptTransferIn_timesOut() { @Test void interruptTransfer_doesNotTimeOut() { - Assumptions.assumeTrue(testDevice.productId() == PID_LOOPBACK, + Assumptions.assumeTrue(isLoopbackDevice(), "Interrupt transfer only supported by loopback test device"); byte[] sampleData = generateRandomBytes(12, 293872394); diff --git a/test-devices/composite-stm32/src/main.c b/test-devices/composite-stm32/src/main.c index 050c7398..0f8826ad 100644 --- a/test-devices/composite-stm32/src/main.c +++ b/test-devices/composite-stm32/src/main.c @@ -25,11 +25,6 @@ uint8_t loopback_buffer[512]; // RX buffer for loopback uint8_t loopback_rx_buffer[64]; -// buffer for echoed packet -uint8_t echo_buffer[16]; -int num_echos; - - // Blink durations enum { BLINK_NOT_MOUNTED = 250, @@ -44,6 +39,7 @@ static void cdc_task(void); static void loopback_init(void); static void loopback_check_rx(void); static void loopback_check_tx(void); +static void reset_buffers(void); int main(void) { @@ -63,6 +59,11 @@ int main(void) { return 0; } +// reset device in predictable state +void reset_buffers(void) { + tu_fifo_clear(&loopback_fifo); +} + // --- Loopback void loopback_init(void) { @@ -120,7 +121,14 @@ void cust_vendor_rx_cb(uint8_t ep_addr, uint32_t recv_bytes) { // Invoked when last tx transfer finished void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes) { - tu_fifo_advance_read_pointer(&loopback_fifo, sent_bytes); + // If buffer has been reset in the mean time, + // we might not be able to advance it fully or at all. + int max_advance = tu_fifo_count(&loopback_fifo); + if (sent_bytes > max_advance) + sent_bytes = max_advance; + if (sent_bytes > 0) + tu_fifo_advance_read_pointer(&loopback_fifo, sent_bytes); + loopback_check_tx(); loopback_check_rx(); } @@ -167,6 +175,13 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ } break; + case 0x04: + if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 0) { + reset_buffers(); + return tud_control_status(rhport, request); + } + break; + case MSOS_VENDOR_CODE: if (request->wIndex == 7) { // Get Microsoft OS 2.0 compatible descriptor diff --git a/test-devices/composite-stm32/src/usb_descriptors.c b/test-devices/composite-stm32/src/usb_descriptors.c index 63c7f69b..25b8f78c 100644 --- a/test-devices/composite-stm32/src/usb_descriptors.c +++ b/test-devices/composite-stm32/src/usb_descriptors.c @@ -31,7 +31,7 @@ tusb_desc_device_t const desc_device = { .idVendor = 0xCAFE, .idProduct = 0xCEA0, - .bcdDevice = 0x0035, // version 0.3.5 + .bcdDevice = 0x0036, // version 0.3.6 .iManufacturer = 0x01, .iProduct = 0x02, @@ -137,7 +137,7 @@ TU_VERIFY_STATIC(sizeof(desc_ms_os_20) == MS_OS_20_DESC_LEN, "Incorrect size"); const char* const string_table[] = { 0, // 0 - supported languages (see below) "JavaDoesUSB", // 1 - manufacturer - "Loopback", // 2 - product + "Composite", // 2 - product board_serial_num // 3 - serial number }; diff --git a/test-devices/loopback-stm32/.vscode/settings.json b/test-devices/loopback-stm32/.vscode/settings.json new file mode 100644 index 00000000..0b167675 --- /dev/null +++ b/test-devices/loopback-stm32/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "files.associations": { + "usbd.h": "c", + "usbd_pvt.h": "c" + } +} \ No newline at end of file diff --git a/test-devices/loopback-stm32/README.md b/test-devices/loopback-stm32/README.md index c6f7f83e..b466526c 100644 --- a/test-devices/loopback-stm32/README.md +++ b/test-devices/loopback-stm32/README.md @@ -35,6 +35,7 @@ Several vendor-specific control requests are supported for testing: | 0x41 | 0x01 | *value* | 0 | 0 | none | Host to device: *value* is saved in device | | 0x41 | 0x02 | 0 | 0 | 4 | *value* (32-bit LE) | Host to device: *value* is saved in device | | 0xC1 | 0x03 | 0 | 0 | 4 | *value* (32-bit LE) | Device to host: saved *value* is transmitted | +| 0x41 | 0x04 | 0 | 0 | 0 | none | Reset internal buffers. Used to put device in a predicatable state. | ## Building the firmware diff --git a/test-devices/loopback-stm32/src/main.c b/test-devices/loopback-stm32/src/main.c index 9771dba1..14e35bba 100644 --- a/test-devices/loopback-stm32/src/main.c +++ b/test-devices/loopback-stm32/src/main.c @@ -43,6 +43,7 @@ static void led_blinking_task(void); static void loopback_init(void); static void loopback_check_rx(void); static void loopback_check_tx(void); +static void reset_buffers(void); int main(void) { @@ -61,6 +62,12 @@ int main(void) { return 0; } +// reset device in predictable state +void reset_buffers(void) { + tu_fifo_clear(&loopback_fifo); + num_echos = 0; +} + // --- Loopback void loopback_init(void) { @@ -111,7 +118,15 @@ void cust_vendor_rx_cb(uint8_t ep_addr, uint32_t recv_bytes) { // Invoked when last tx transfer finished void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes) { if (ep_addr == EP_LOOPBACK_TX) { - tu_fifo_advance_read_pointer(&loopback_fifo, sent_bytes); + + // If buffer has been reset in the mean time, + // we might not be able to advance it fully or at all. + int max_advance = tu_fifo_count(&loopback_fifo); + if (sent_bytes > max_advance) + sent_bytes = max_advance; + if (sent_bytes > 0) + tu_fifo_advance_read_pointer(&loopback_fifo, sent_bytes); + loopback_check_tx(); loopback_check_rx(); @@ -167,6 +182,13 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ return tud_control_xfer(rhport, request, &saved_value, 4); } break; + + case 0x04: + if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 0) { + reset_buffers(); + return tud_control_status(rhport, request); + } + break; // Microsoft WCID descriptor (for automatic WinUSB installation) case WCID_VENDOR_CODE: diff --git a/test-devices/loopback-stm32/src/usb_descriptors.c b/test-devices/loopback-stm32/src/usb_descriptors.c index 568f56bd..84b1691b 100644 --- a/test-devices/loopback-stm32/src/usb_descriptors.c +++ b/test-devices/loopback-stm32/src/usb_descriptors.c @@ -30,7 +30,7 @@ tusb_desc_device_t const desc_device = { .idVendor = 0xCAFE, .idProduct = 0xCEAF, - .bcdDevice = 0x0072, // version 0.7.2 + .bcdDevice = 0x0073, // version 0.7.3 .iManufacturer = 0x01, .iProduct = 0x02, From 50b204dc465ac9ef0bee2434c22cda2eb372c452 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Tue, 18 Oct 2022 20:44:57 +0200 Subject: [PATCH 116/433] Alternate interface selection (macOS) --- .../java/net/codecrete/usb/dfu/DFUDevice.java | 2 +- .../java/net/codecrete/usb/USBDevice.java | 10 ++ .../java/net/codecrete/usb/USBInterface.java | 8 ++ .../usb/common/USBInterfaceImpl.java | 11 +- .../codecrete/usb/linux/LinuxUSBDevice.java | 5 + .../net/codecrete/usb/macos/IoKitUSB.java | 7 ++ .../codecrete/usb/macos/MacosUSBDevice.java | 28 ++++- .../usb/windows/WindowsUSBDevice.java | 5 + .../codecrete/usb/AlternateInterfaceTest.java | 72 ++++++++++++ .../net/codecrete/usb/DescriptionTest.java | 29 ++++- .../java/net/codecrete/usb/StreamTest.java | 1 - .../net/codecrete/usb/TestDeviceBase.java | 3 + .../java/net/codecrete/usb/TimeoutTest.java | 4 +- reference/macos/USB/usb_device.cpp | 38 ++++--- reference/macos/USB/usb_device.hpp | 10 ++ test-devices/loopback-stm32/README.md | 7 ++ .../loopback-stm32/include/vendor_custom.h | 15 +++ .../lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c | 3 + test-devices/loopback-stm32/src/main.c | 9 ++ .../loopback-stm32/src/usb_descriptors.c | 12 +- .../loopback-stm32/src/vendor_custom.c | 105 +++++++++++++++--- 21 files changed, 346 insertions(+), 38 deletions(-) create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java index 6ce3c233..f5b12f88 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java @@ -204,7 +204,7 @@ public void download(byte[] firmware) { var firstPage = getWritablePage(startAddress); getWritablePage(startAddress + length); - // TODO: select alternate interface settings + usbDevice_.selectAlternateSetting(interfaceNumber_, firstPage.segment().altSetting()); System.out.printf("Target memory segment: %s%n", firstPage.segment().name()); // erase if needed diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index 8881bb60..f7d2b61a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -137,6 +137,16 @@ public interface USBDevice { */ void claimInterface(int interfaceNumber); + /** + * Selects the alternate settings for the specified interface. + *

+ * The device must be open and the interface must be claimed for exclusive access. + *

+ * @param interfaceNumber interface number + * @param alternateNumber alternate setting number + */ + void selectAlternateSetting(int interfaceNumber, int alternateNumber); + /** * Releases the specified interface from exclusive use. * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java index bfb5f68a..2d6e7f54 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java @@ -44,6 +44,14 @@ public interface USBInterface { */ USBAlternateInterface alternate(); + /** + * Gets the alternate interface settings with the specified number. + * + * @param alternateNumber alternate setting number + * @return alternate interface setting + */ + USBAlternateInterface getAlternate(int alternateNumber); + /** * Gets all alternate settings of this interface. * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java index 7ff8c970..2cf7b634 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java @@ -16,7 +16,7 @@ public class USBInterfaceImpl implements USBInterface { private final int number_; - private final USBAlternateInterface alternate_; + private USBAlternateInterface alternate_; private final List alternates_; private boolean isClaimed_; @@ -46,6 +46,11 @@ public USBAlternateInterface alternate() { return alternate_; } + @Override + public USBAlternateInterface getAlternate(int alternateNumber) { + return alternates_.stream().filter((alt) -> alt.number() == alternateNumber).findFirst().orElse(null); + } + @Override public List alternates() { return Collections.unmodifiableList(alternates_); @@ -54,4 +59,8 @@ public List alternates() { void addAlternate(USBAlternateInterface alt) { alternates_.add(alt); } + + public void setAlternate(USBAlternateInterface alternate) { + alternate_ = alternate; + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 6ea0f309..bddd9484 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -110,6 +110,11 @@ public void claimInterface(int interfaceNumber) { } } + @Override + public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { + throw new IllegalStateException("not implemented"); + } + public void releaseInterface(int interfaceNumber) { checkIsOpen(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index 5fa3b2ec..e89fe509 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -167,4 +167,11 @@ public static int AbortPipe(MemoryAddress self, byte pipeRef) { return IOUSBInterfaceInterface.AbortPipe(getVtable(self, session), session).apply(self, pipeRef); } } + + // IOReturn (*SetAlternateInterface)(void *self, UInt8 alternateSetting); + public static int SetAlternateInterface(MemoryAddress self, byte alternateSetting) { + try (var session = MemorySession.openConfined()) { + return IOUSBInterfaceInterface.SetAlternateInterface(getVtable(self, session), session).apply(self, alternateSetting); + } + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index fb63038c..a39e2ec4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -181,6 +181,31 @@ public void claimInterface(int interfaceNumber) { updateEndpointList(); } + public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { + // check interface + var intf = getInterface(interfaceNumber); + if (intf == null) + throw new MacosUSBException(String.format("Interface %d does not exist", interfaceNumber)); + if (!intf.isClaimed()) + throw new MacosUSBException(String.format("Interface %d has not been claimed", interfaceNumber)); + + // check alternate setting + var altSetting = intf.getAlternate(alternateNumber); + if (altSetting == null) + throw new MacosUSBException(String.format("Interface %d does not have an alternate interface setting %d", + interfaceNumber, alternateNumber)); + + var intfInfo = claimedInterfaces.stream() + .filter((interf) -> interf.interfaceNumber() == interfaceNumber).findFirst().get(); + + int ret = IoKitUSB.SetAlternateInterface(intfInfo.asAddress(), (byte) alternateNumber); + if (ret != 0) + throw new MacosUSBException("Failed to set alternate interface", ret); + + intf.setAlternate(altSetting); + updateEndpointList(); + } + public void releaseInterface(int interfaceNumber) { checkIsOpen(); @@ -192,7 +217,8 @@ public void releaseInterface(int interfaceNumber) { var interfaceInfo = interfaceInfoOptional.get(); int ret = IoKitUSB.USBInterfaceClose(interfaceInfo.asAddress()); - if (ret != 0) throw new MacosUSBException("Failed to release interface", ret); + if (ret != 0) + throw new MacosUSBException("Failed to release interface", ret); claimedInterfaces.remove(interfaceInfo); IoKitUSB.Release(interfaceInfo.asAddress()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 258f10a0..909604e3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -145,6 +145,11 @@ public void claimInterface(int interfaceNumber) { setClaimed(interfaceNumber, true); } + @Override + public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { + throw new IllegalStateException("not implemented"); + } + public void releaseInterface(int interfaceNumber) { checkIsOpen(); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java new file mode 100644 index 00000000..89259f2e --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java @@ -0,0 +1,72 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Unit test for bulk transfer +// + +package net.codecrete.usb; + +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class AlternateInterfaceTest extends TestDeviceBase { + + @BeforeAll + static void precondition() { + Assumptions.assumeTrue(isLoopbackDevice(), + "Alternate interface only supported by loopback test device"); + } + + @Test + void selectAlternateIntf_succeeds() { + + testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 1); + + var altIntf = testDevice.getInterface(LOOPBACK_INTF_LOOPBACK).alternate(); + assertNotNull(altIntf); + assertEquals(2, altIntf.endpoints().size()); + assertEquals(0xff, altIntf.classCode()); + + testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 0); + } + + @Test + void selectInvalidAlternateIntf_fails() { + assertThrows(USBException.class, () -> { + testDevice.selectAlternateSetting(1, 0); + }); + + assertThrows(USBException.class, () -> { + testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 2); + }); + } + + @Test + void transferOnValidEndpoint_succeeds() { + testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 1); + + byte[] sampleData = generateRandomBytes(12, 293872394); + testDevice.transferOut(LOOPBACK_EP_OUT, sampleData); + var received = testDevice.transferIn(LOOPBACK_EP_IN, 64); + assertArrayEquals(sampleData, received); + } + + @Test + void transferOnInvalidEndpoint_fails() { + testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 1); + + assertThrows(USBException.class, () -> { + testDevice.transferOut(ECHO_EP_OUT, new byte[] { 1, 2, 3 }); + }); + + assertThrows(USBException.class, () -> { + testDevice.transferIn(ECHO_EP_IN, 16); + }); + } +} diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index 34820380..7a532f24 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -63,13 +63,22 @@ void alternateInterfaceDescriptor_isCorrect() { var intf = testDevice.interfaces().get(interfaceNumber); var altIntf = intf.alternate(); assertNotNull(intf.alternates()); - assertEquals(1, intf.alternates().size()); + assertEquals(isLoopbackDevice() ? 2 : 1, intf.alternates().size()); assertSame(intf.alternates().get(0), altIntf); assertEquals(0, altIntf.number()); assertEquals(0xff, altIntf.classCode()); assertEquals(0x00, altIntf.subclassCode()); assertEquals(0x00, altIntf.protocolCode()); + + if (isLoopbackDevice()) { + altIntf = intf.alternates().get(1); + assertEquals(1, altIntf.number()); + + assertEquals(0xff, altIntf.classCode()); + assertEquals(0x00, altIntf.subclassCode()); + assertEquals(0x00, altIntf.protocolCode()); + } } @Test @@ -102,12 +111,28 @@ void endpointDescriptors_areCorrect() { assertEquals(USBDirection.IN, endpoint.direction()); assertEquals(USBTransferType.INTERRUPT, endpoint.transferType()); assertEquals(16, endpoint.packetSize()); + + // test alternate interface 1 + altIntf = testDevice.interfaces().get(interfaceNumber).alternates().get(1); + assertEquals(2, altIntf.endpoints().size()); + + endpoint = altIntf.endpoints().get(0); + assertEquals(1, endpoint.number()); + assertEquals(USBDirection.OUT, endpoint.direction()); + assertEquals(USBTransferType.BULK, endpoint.transferType()); + assertEquals(64, endpoint.packetSize()); + + endpoint = altIntf.endpoints().get(1); + assertEquals(2, endpoint.number()); + assertEquals(USBDirection.IN, endpoint.direction()); + assertEquals(USBTransferType.BULK, endpoint.transferType()); + assertEquals(64, endpoint.packetSize()); } } @Test void configurationDescription_isAvailable() { - int expectedLength = isLoopbackDevice() ? 46 : 98; + int expectedLength = isLoopbackDevice() ? 69 : 98; byte[] configDesc = testDevice.configurationDescriptor(); assertNotNull(configDesc); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java index aa5ea0d5..65c1d99b 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java @@ -11,7 +11,6 @@ import org.junit.jupiter.api.Test; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.concurrent.CompletableFuture; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index 87089c57..23c9af8f 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -99,6 +99,9 @@ static boolean isCompositeDevce() { } private static void resetDevice() { + if (isLoopbackDevice()) + testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 0); + // reset buffers resetBuffers(); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java index 1e847fdf..a9e42024 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java @@ -13,10 +13,10 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; -import java.io.ByteArrayOutputStream; import java.util.concurrent.TimeUnit; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class TimeoutTest extends TestDeviceBase { diff --git a/reference/macos/USB/usb_device.cpp b/reference/macos/USB/usb_device.cpp index 1ecd27b2..14c18f8d 100644 --- a/reference/macos/USB/usb_device.cpp +++ b/reference/macos/USB/usb_device.cpp @@ -120,8 +120,30 @@ void usb_device::claim_interface(int interface_number) { ret = (*interface)->USBInterfaceOpen(interface); usb_error::check(ret, "failed to open USB interface"); + build_pipe_info(interface); + + interface_ = interface; + (*interface_)->AddRef(interface_); +} + +void usb_device::release_interface() { + if (interface_ == nullptr) + throw usb_error("no interface has been claimed"); + + (*interface_)->USBInterfaceClose(interface_); + (*interface_)->Release(interface_); + interface_ = nullptr; + pipes_.clear(); +} + +void usb_device::select_alternate_interface(int alternate_setting) { + (*interface_)->SetAlternateInterface(interface_, (UInt8) alternate_setting); + build_pipe_info(interface_); +} + +void usb_device::build_pipe_info(IOUSBInterfaceInterface** interface) { UInt8 num_pipes = 0; - ret = (*interface)->GetNumEndpoints(interface, &num_pipes); + IOReturn ret = (*interface)->GetNumEndpoints(interface, &num_pipes); usb_error::check(ret, "internal error (GetNumEndpoints)"); pipes_.clear(); @@ -133,24 +155,12 @@ void usb_device::claim_interface(int interface_number) { UInt16 ignore2 = 0; ret = (*interface)->GetPipeProperties(interface, i, &direction, &number, &transfer_type, &ignore2, &ignore); usb_error::check(ret, "internal error (GetPipeProperties)"); + pipe_info pipe{(UInt8) i, (uint8_t)((direction << 7) | number), transfer_type}; - ; pipes_.push_back(pipe); } - - interface_ = interface; - (*interface_)->AddRef(interface_); } -void usb_device::release_interface() { - if (interface_ == nullptr) - throw usb_error("no interface has been claimed"); - - (*interface_)->USBInterfaceClose(interface_); - (*interface_)->Release(interface_); - interface_ = nullptr; - pipes_.clear(); -} std::vector usb_device::transfer_in(int endpoint_number, int data_len, int timeout) { if (interface_ == nullptr) diff --git a/reference/macos/USB/usb_device.hpp b/reference/macos/USB/usb_device.hpp index 2963420c..4ca1acca 100644 --- a/reference/macos/USB/usb_device.hpp +++ b/reference/macos/USB/usb_device.hpp @@ -120,6 +120,15 @@ class usb_device { */ void release_interface(); + /** + * Select an alternate interface setting. + * + * The affected interface must have been claimed. + * + *@param alternate_setting alternate setting number + */ + void select_alternate_interface(int alternate_setting); + /** * Receives data from a bulk or interrupt endpoint. * @@ -196,6 +205,7 @@ class usb_device { private: usb_device(io_service_t service, IOUSBDeviceInterface** device, uint64_t entry_id, int vendor_id, int product_id); uint64_t entry_id() const { return entry_id_; } + void build_pipe_info(IOUSBInterfaceInterface** intf); const pipe_info* get_pipe(int endpoint_address); const pipe_info* ep_in_pipe(int endpoint_address); const pipe_info* ep_out_pipe(int endpoint_address); diff --git a/test-devices/loopback-stm32/README.md b/test-devices/loopback-stm32/README.md index b466526c..a30ffa10 100644 --- a/test-devices/loopback-stm32/README.md +++ b/test-devices/loopback-stm32/README.md @@ -37,6 +37,13 @@ Several vendor-specific control requests are supported for testing: | 0xC1 | 0x03 | 0 | 0 | 4 | *value* (32-bit LE) | Device to host: saved *value* is transmitted | | 0x41 | 0x04 | 0 | 0 | 0 | none | Reset internal buffers. Used to put device in a predicatable state. | +### Alternate interfaces + +Two alternate interfaces are implemented: + +- Alternate 0 (default): all endpoints are available +- Alternate 1: only the control endpoint and the bulk endpoints (0x01 and 0x82) are available + ## Building the firmware diff --git a/test-devices/loopback-stm32/include/vendor_custom.h b/test-devices/loopback-stm32/include/vendor_custom.h index 03976045..d51c9783 100644 --- a/test-devices/loopback-stm32/include/vendor_custom.h +++ b/test-devices/loopback-stm32/include/vendor_custom.h @@ -22,6 +22,11 @@ /* Interface */\ 9, TUSB_DESC_INTERFACE, _itfnum, 0, _numeps, TUSB_CLASS_VENDOR_SPECIFIC, 0x00, 0x00, 0 +// Interface descriptor: interface number, number of endponts +#define CUSTOM_VENDOR_INTERFACE_ALT(_itfnum, _altnum, _numeps) \ + /* Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, _altnum, _numeps, TUSB_CLASS_VENDOR_SPECIFIC, 0x00, 0x00, 0 + // Bulk endpoint descriptor: endpoint address, packet size #define CUSTOM_VENDOR_BULK_ENDPOINT(_epaddr, _packetsize) \ /* Endpoint */\ @@ -109,6 +114,16 @@ TU_ATTR_WEAK void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes); */ TU_ATTR_WEAK void cust_vendor_intf_open_cb(uint8_t intf); +/** + * @brief Invoked when an alternate interface has been selected. + * + * This function is called as part of a SET INTERFACE control request. + * + * @param intf interface number + * @param alt alternate interface number + */ +TU_ATTR_WEAK void cust_vendor_alt_intf_selected_cb(uint8_t intf, uint8_t alt); + // --- Driver to be registered in usbd_app_driver_get_cb() diff --git a/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c b/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c index f17176ae..83768689 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c +++ b/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c @@ -683,6 +683,7 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * re static void dcd_pma_alloc_reset(void) { + open_ep_count = 0; ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT; // 8 bytes per endpoint (two TX and two RX words, each) //TU_LOG2("dcd_pma_alloc_reset()\r\n"); for(uint32_t i=0; ipma_alloc_size != 0U) { //TU_LOG2("dcd_pma_alloc(%x,%x)=%x (cached)\r\n",ep_addr,length,epXferCtl->pma_ptr); diff --git a/test-devices/loopback-stm32/src/main.c b/test-devices/loopback-stm32/src/main.c index 14e35bba..a8d52015 100644 --- a/test-devices/loopback-stm32/src/main.c +++ b/test-devices/loopback-stm32/src/main.c @@ -146,6 +146,15 @@ void cust_vendor_intf_open_cb(uint8_t intf) { cust_vendor_prepare_recv(EP_ECHO_RX, echo_buffer, sizeof(echo_buffer)); } +// Invoked when an alternate interface has been selected +void cust_vendor_alt_intf_selected_cb(uint8_t intf, uint8_t alt) { + reset_buffers(); + loopback_check_rx(); + if (alt == 0) + cust_vendor_prepare_recv(EP_ECHO_RX, echo_buffer, sizeof(echo_buffer)); +} + + // --- Control messages (see README) diff --git a/test-devices/loopback-stm32/src/usb_descriptors.c b/test-devices/loopback-stm32/src/usb_descriptors.c index 84b1691b..52bb0ad8 100644 --- a/test-devices/loopback-stm32/src/usb_descriptors.c +++ b/test-devices/loopback-stm32/src/usb_descriptors.c @@ -53,12 +53,12 @@ enum { INTF_NUM_TOTAL }; -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + 9 + 7 + 7 + 7 + 7) +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + 9 + 4 * 7 + 9 + 2 * 7) uint8_t const desc_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA TUD_CONFIG_DESCRIPTOR(1, INTF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 500), - // Loopback interface + // Loopback interface (alternate 0) CUSTOM_VENDOR_INTERFACE(0, 4), // Loopback endpoint OUT CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_RX, BULK_MAX_PACKET_SIZE), @@ -67,7 +67,13 @@ uint8_t const desc_configuration[] = { // Echo endpoint OUT CUSTOM_VENDOR_INTERRUPT_ENDPOINT(EP_ECHO_RX, INTR_MAX_PACKET_SIZE, 16), // Echo endpoint IN - CUSTOM_VENDOR_INTERRUPT_ENDPOINT(EP_ECHO_TX, INTR_MAX_PACKET_SIZE, 16) + CUSTOM_VENDOR_INTERRUPT_ENDPOINT(EP_ECHO_TX, INTR_MAX_PACKET_SIZE, 16), + // Loopback interface (alternate 1) + CUSTOM_VENDOR_INTERFACE_ALT(0, 1, 2), + // Loopback endpoint OUT + CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_RX, BULK_MAX_PACKET_SIZE), + // Loopback endpoint IN + CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_TX, BULK_MAX_PACKET_SIZE) }; // Invoked when a GET CONFIGURATION DESCRIPTOR request is recieved. diff --git a/test-devices/loopback-stm32/src/vendor_custom.c b/test-devices/loopback-stm32/src/vendor_custom.c index 44b2dc26..54b9903a 100644 --- a/test-devices/loopback-stm32/src/vendor_custom.c +++ b/test-devices/loopback-stm32/src/vendor_custom.c @@ -9,6 +9,8 @@ // USB driver for interfaces with vendor specific class. // The interface can have any number of Bulk and Interrupt endpoints. // +// Alternate interfaces are supported. +// #include "tusb_option.h" @@ -21,17 +23,27 @@ static void cv_init(void); static void cv_reset(uint8_t rhport); static uint16_t cv_open(uint8_t rhport, tusb_desc_interface_t const* desc_intf, uint16_t max_len); +static bool cv_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); static bool cv_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); +static uint16_t setup_endpoints(uint8_t rhport, tusb_desc_interface_t const* desc_intf, uint16_t max_len, uint8_t alt_num); +static void close_endpoints(); const usbd_class_driver_t cust_vendor_driver = { .init = cv_init, .reset = cv_reset, .open = cv_open, - .control_xfer_cb = NULL, + .control_xfer_cb = cv_control_xfer, .xfer_cb = cv_xfer_cb, .sof = NULL }; +// bit map indicating open endpoints +static uint8_t cv_eps_open[8]; +static int cv_num_eps_open; +static uint8_t cv_alternate_setting; +static tusb_desc_interface_t const * cv_intf_desc; +static uint16_t cv_intf_desc_len; + void cv_init(void) { // nothing to do @@ -41,33 +53,100 @@ void cv_reset(uint8_t rhport) { // nothing to do } +// Open interface is the descriptor matches this class uint16_t cv_open(uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t max_len) { - // return 0 if interface class is not "vendor specific" - TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_intf->bInterfaceClass, 0); + int ret = setup_endpoints(rhport, desc_intf, max_len, 0); - uint8_t const * p_desc = tu_desc_next(desc_intf); - uint8_t const * desc_end = p_desc + max_len; - int num_endpoints = desc_intf->bNumEndpoints; + if (ret != 0) + cust_vendor_intf_open_cb(desc_intf->bInterfaceNumber); - // iterate all endpoints - while (num_endpoints > 0 && p_desc < desc_end) { + return ret; +} - // open endpoint - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; - TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); +// Setup endpoints for the given alternate interface. +// Endpoints details are extracted from the configuration descriptor +// returns: number of processed bytes +uint16_t setup_endpoints(uint8_t rhport, tusb_desc_interface_t const* desc_intf, uint16_t max_len, uint8_t alt_num) { + + uint8_t const * p_desc = (uint8_t const *) desc_intf; + uint8_t const * p_desc_end = p_desc + max_len; + + // process the interface descriptor including all alternate interface descriptors + while (p_desc < p_desc_end) { + + // check for interface descriptor with class "vendor specific" + tusb_desc_interface_t const * desc_if = (tusb_desc_interface_t const *) p_desc; + if (desc_if->bDescriptorType != TUSB_DESC_INTERFACE || desc_if->bInterfaceClass != TUSB_CLASS_VENDOR_SPECIFIC + || desc_if->bInterfaceNumber != desc_intf->bInterfaceNumber) + break; + + uint8_t curr_alt_num = desc_if->bAlternateSetting; + if (curr_alt_num == alt_num) { + // desired alternate interface found + close_endpoints(); + cv_alternate_setting = alt_num; + } p_desc = tu_desc_next(p_desc); - num_endpoints--; + + // iterate endpoints + while (p_desc < p_desc_end) { + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; + if (desc_ep->bDescriptorType != TUSB_DESC_ENDPOINT) + break; + + // open endpoint if it is for selected alternate setting + if (curr_alt_num == alt_num) { + TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); + + // remember open endpoints + cv_eps_open[cv_num_eps_open] = desc_ep->bEndpointAddress; + cv_num_eps_open += 1; + } + + p_desc = tu_desc_next(p_desc); + } } uint16_t processed_bytes = p_desc - (uint8_t const *) desc_intf; - cust_vendor_intf_open_cb(desc_intf->bInterfaceNumber); + if (processed_bytes > 0) { + // remember interface descriptor + cv_intf_desc = desc_intf; + cv_intf_desc_len = processed_bytes; + } return processed_bytes; } +void close_endpoints() { + // close in reverse order + while (cv_num_eps_open > 0) { + cv_num_eps_open -= 1; + usbd_edpt_close(0, cv_eps_open[cv_num_eps_open]); + } +} + +bool cv_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) { + TU_VERIFY(TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type); + + if (request->bRequest == TUSB_REQ_GET_INTERFACE) { + tud_control_xfer(rhport, request, &cv_alternate_setting, 1); + return true; + + } else if (request->bRequest == TUSB_REQ_SET_INTERFACE) { + uint8_t alt_num = request->wValue; + setup_endpoints(0, cv_intf_desc, cv_intf_desc_len, alt_num); + if (cust_vendor_alt_intf_selected_cb != NULL) + cust_vendor_alt_intf_selected_cb((uint8_t) request->wIndex, alt_num); + tud_control_status(rhport, request); + return true; + } + + return false; +} + bool cv_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { From 6871e52c6092c281b61f95f7868080957f39e47e Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Tue, 18 Oct 2022 22:03:34 +0200 Subject: [PATCH 117/433] Update test device firmware --- .../composite-stm32/bin/blackpill-f401cc.bin | Bin 11468 -> 11520 bytes .../composite-stm32/bin/blackpill-f411ce.bin | Bin 11472 -> 11524 bytes .../composite-stm32/bin/bluepill-f103c8.bin | Bin 10028 -> 10080 bytes .../loopback-stm32/bin/blackpill-f401cc.bin | Bin 9908 -> 10508 bytes .../loopback-stm32/bin/blackpill-f411ce.bin | Bin 9912 -> 10512 bytes .../loopback-stm32/bin/bluepill-f103c8.bin | Bin 8112 -> 8760 bytes 6 files changed, 0 insertions(+), 0 deletions(-) diff --git a/test-devices/composite-stm32/bin/blackpill-f401cc.bin b/test-devices/composite-stm32/bin/blackpill-f401cc.bin index 83cbff5aa8e261f934f62f3f7eb26f6d98f0743f..4e4e714fbd6b416271786d6cafa0a01ecd2b27d1 100755 GIT binary patch delta 982 zcmZuvTSyd982-=ftaG$BO7pUAwzIok)FY;3MFq88oL#jDx;zv_N%#;X4QQY*x^@A3 zh%P6H9=bx1P?Swu7%WRzP$9HKK^Kdpqy#etEY~4*`bWpN4t)RjpYwn7o&U@^eS2g3 z?mr|&KTCnqxU0_B?W%D_?~Ou?CICkusa+Sy6n8w6uJb(&R&^zJjFk_L+&WmA-1(&Q>~> zwDs6LT|X}y(hOOg^b?p78mQ9Y-n zcXU&Zz$ATFi;I<~-0umSmlBvS1@gK9k(H*lGE?WB5*yPCYXj{{&gp`I3no+m`_=!Z z6WFkxTeq{b@L)hm45?va+$VI$GK9~{CzKunDL2-B~HnI^2XkKd9QVVW+z&h&UBpnU}77l=FB-31XMcqDBsd(1_y@sYgt zrT#*o9>j1SP}4iZFY|$}ck*wTr?vC>>q%Y-dKn`yP@e(R>-c)J_}7AUYtNwiG2$KK z4?5WxcGhO+|Km&A9`76>w*lSo=}r%OhgCSQ){gn!3FH~yzW5EsfS=j9e_5tcvU6 zGCuVVx0>VfKK54FxW6h5;7-gAkvM4Yr&CjczkT4G1lk$BE{T=I^+tR*(h;w@c2u|Z z@1GKWhIo)@f`&j_H@&HHR*s<7s{505UZIglsrR%Fv`tBx3b9U`T>bHv6aek;Z^yP~ z&G3VVXysFYCtCEjfjTc2H}eBJ7v}|!sfr!DnD8fJ8(a6U~|_y=u)1%aBZy<>QCvz=3H*z&Pi83bx zl9J~YIn$u%S=KEoKeG0%o`5~-$Y0jM56YL9W8I*9%FYWl?d&dZ^920&iN@~z74t7& zcMHm^tcXV{XOuom8GG^d9g+O^!@=_k;46VdWIha`aIlRn6zfY*;i_4cTKv_=j*F{F z4eJ$U*LM7A;b1sO12o|b3>WhmqtIv&iKdJ~HOq+#*`V6!PmxGhTq`45mDEfN3# diff --git a/test-devices/composite-stm32/bin/blackpill-f411ce.bin b/test-devices/composite-stm32/bin/blackpill-f411ce.bin index bd6cb34c0e2479661051643dded1411d34fdd56b..7509f97c83a22babf31c76be5ba32703b224ec05 100755 GIT binary patch delta 986 zcmZuvTSyd982-=MndWF0QcGR8ZAZ6@b;^vii$Pi1?5aU@dB`9N!UrFufqE#Y>?UkM zbU6e;&<%PJdeDZYEViX2TBB&Uh%OdwbTNu*!f2gpoBq-1t%2|V{xj!0-~V&YpKLz3 zq3bFkrsyF)jE_m3f8K8}uUL8rfU4urLf!pW^2~YoUxs1c4lwf(S4_&j*sSq$6&qW?{mw` z@> zNy>dmP;1f>pP8)ZR!T$^{v%b=SgI8qDo&rUpc43({znnupHdT>)mMMh9=pK-uX^MrNYJB0 zSPz{N??%<-U&0+{)#&mJE^3qt;uoz-&>z9~)g$MpgoREHzPkVZt^dcTjb`s?IA(IJ5p5(oz$UlJyUVq=i9~dTt@>p@cXe zC?W}?C$Nbic}o`{iPdFmFZc<+k3 zt!?_&ZLQl|+{Sd&?Lxf8LA;F(-a))}8}D=Zd=9X02!AfHn~2@w$gJs;TJrIcWgK4^ NgI;Mn;5ypKe*wa5Kf3?` delta 896 zcmZuvT}TvB6h3!$#+lU&a?@os+tJOk9g&q-Ec;Q>cGon7EJ#zd6eFbEm%@j@s4O)k z>e@pO`4p6ppiNS%E@C1j1np)~CJPH0sbNi6>X5dbvGJ{k@B7ZZ-?`@;F6U}RpuG1P zAw$$hl91n#f@I4IC{I+l#VC|3b zkZw?BR{hJYqqgs|2+9ST&zZ97Rj#*cnf>iCfGG3}9#C>tbJL?I31(EN4qsj>TSP?v zjF1OPu21lLXbWd^&aH?pQ0o4eOG=f915${RxD5EBT&?NLOJ%yXxLRep8J8CIsv0-Y z5NB(y#6DWD5*(RD6e5KF_Q$M;D*~l-HL}zd(Yi&JE)8pWKN-z$Lm!kA=$_Zz8^f^X zN0zP)lbwzyoNKcyJ7{VeUC1{v5*I9MVx;7N;RBI21VEI+2FVsEl+^klZRMrKpy^PG z%hYBL-&Vl^(zmIJR*=31Hx?ghO{__AIfjTr2mX2CsZXt}6bkbAB7M#2(w&KqKfVyr zG30f(OMpKIBC#2~;PJZasD&?xYr@#*iaM*uLy`Q5f|mpo7{v6Mah|_MFZ)hY3Am%?-me3h`|I9#&x}G1|dd| zWsG0QTdflD! zytSH;PWf<3HVSP?EkmA6y@`CrhOz9oEnr!>Z#&P%-p4BIcu2?W3&cr%(&)jG#zya{ zleG9%gHS|AGInrTaUfLE`3&=42?8D7 diff --git a/test-devices/composite-stm32/bin/bluepill-f103c8.bin b/test-devices/composite-stm32/bin/bluepill-f103c8.bin index edc272d13a5c08efbe11ae275998916ebb306e06..a88d6ef5720729f07de7fab528aac76019038071 100755 GIT binary patch delta 909 zcmZuvT}TvB6h3!$X1!|~imvNlIR31EQ)wVk7Pys;tN8<#P!ED&LK5PHO8SzTN=gLP z^kDQu5rqpqxD87fZ2RC#hQThrXa=p6D1|a)wGL|2ncelRhwq+q&-dN$-g`K&8iEZ| z2MMW@50MO9Ye+?!O9Qo8ld4Y^00jU(FNzEDGxD5VlB<|p(xY@RZKVCmJ3X}R(?gmM zAj`AQNnD_=?s~V_(l+-E9@IOUV;Xln^I))e(l?l6)CM(fs%4Aa9x(w=J=6(m({4p! z>>@#~M=PE7u2F|0$5dnNFHTeMhegD_ zjvU5i}Jyj&hP4>C%SQm9vbu+Z>U5hcr4C1^#8c? z^mL(*7gOCsui5a+^iU_N6Hq-VL!J( zg#CU-$nXPS9%O}Lf2E)W8;*1 z$wAadZzJrNrLSYG@EO@cF}^m!O-8xECv`QVnhSf(1~`1|`i`MpS|z;XP0t7HEPfh4 zM{-RPIHl@eSd;H_jzo%yQFv*O#8G*LDQ6@I3};>ZIYw%vVBH8 z)72?;b$9f%hkXF%ut^JuGVJbEyrCO$8)4AB(O6G`K1R$UIxRqpV&(7o`I*ZJKqoky PIEX`WP|u25>KOk4--RPm delta 854 zcmZuve@GK?6o22_ZGBfJ%G&1qk+&_Uc10H?r6QYXr}M|eBErD3q(BT@LE(Q%L2X0? z9fBnkQ9%O*?b;uPYsCoqqrhQ*SQ0FPeh|f()I7|tcY6NU!RPyV?|t6)y?1vn6B-Lm z>>#8-+DVG=3=+TVx(do6HQYqYfdT-x&A@5tF1bepX+Ps70lAOqB_}(dYT4zamQ|Ag zrSVP8BnHasmBbP&^iE#nKsm1lrqJVaTw|5tPthN4qoRZ0k@o0o+7kmH@N5)Sk(J zhl%O-F_noiqHay7`q?iaUP*R_vadnR9BNitKpnA?w zuO?wt*Rq$Bq*8cn7Pp9d)3(9XV!e&w&FO=K3|}&1nj?J93~+qL#CvBNc{MFXHt@gG zwidT&i#jtmR1kpwF+Upt{#*J$b0oLbEeg|xJw&e~hsF`?OoE5G^gjG*NCD z%Iv#^&x8}E!%d&c0KXJ)#A^yebGYf5^upYb{|2MFch=xe$z|C^Mx~&|TQcDT8g9bB zDAKq~Oj%7cS~jQ=jwZBhl@zt`q)v`oMyl;J8NqeFu4dX*CJZ6 zkd6+t_1L=qKVEjqo&pDB|A5tS8CM^@!zB98<@Um5Lh|Kc@vO;`#TQn5vWNT0ZU%jI z4X~2CY>`w+c3(wPr@jReoX5jK52a_{esZmoy{s;281g!u7 diff --git a/test-devices/loopback-stm32/bin/blackpill-f401cc.bin b/test-devices/loopback-stm32/bin/blackpill-f401cc.bin index 37161c7e7d92d0314506ba164c444f4830910c78..9af958a0c4e718fc9480bcd2800c893fcdd1a689 100755 GIT binary patch delta 2821 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 G$@>@cEefmv delta 2264 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 Date: Tue, 18 Oct 2022 21:15:12 +0200 Subject: [PATCH 118/433] Alternate interface settings (Windows) --- java-does-usb/jextract/windows/gen_win.cmd | 1 + .../usb/windows/WindowsUSBDevice.java | 20 +++++++++++++++++-- .../usb/windows/gen/winusb/WinUSB.java | 13 +++++++++++- .../usb/windows/gen/winusb/constants$0.java | 20 ++++++++----------- .../usb/windows/gen/winusb/constants$1.java | 12 +++++++++++ 5 files changed, 51 insertions(+), 15 deletions(-) diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index df77355b..cd2e2c97 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -130,6 +130,7 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-function WinUsb_ReadPipe ^ --include-function WinUsb_GetAssociatedInterface ^ --include-function WinUsb_SetPipePolicy ^ + --include-function WinUsb_SetCurrentAlternateSetting ^ --include-macro PIPE_TRANSFER_TIMEOUT ^ windows_headers.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 909604e3..8d7cf02e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -9,7 +9,6 @@ import net.codecrete.usb.*; import net.codecrete.usb.common.USBDeviceImpl; -import net.codecrete.usb.macos.gen.iokit.IOKit; import net.codecrete.usb.usbstandard.SetupPacket; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.winusb.WinUSB; @@ -147,7 +146,24 @@ public void claimInterface(int interfaceNumber) { @Override public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { - throw new IllegalStateException("not implemented"); + checkIsOpen(); + + var intfHandle = getInterfaceHandle(interfaceNumber); + if (intfHandle.interfaceHandle == null) + throw new USBException(String.format("Interface %d has not been claimed", interfaceNumber)); + + var intf = getInterface(interfaceNumber); + + // check alternate setting + var altSetting = intf.getAlternate(alternateNumber); + if (altSetting == null) + throw new WindowsUSBException(String.format("Interface %d does not have an alternate interface setting %d", + interfaceNumber, alternateNumber)); + + if (WinUSB.WinUsb_SetCurrentAlternateSetting(intfHandle.interfaceHandle, (byte) alternateNumber) == 0) + throw new WindowsUSBException("Failed to set alternate interface", Kernel32.GetLastError()); + + intf.setAlternate(altSetting); } public void releaseInterface(int interfaceNumber) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java index a218a6d8..1ad0a068 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java @@ -65,6 +65,17 @@ public static int WinUsb_GetDescriptor ( Addressable InterfaceHandle, byte Desc throw new AssertionError("should not reach here", ex$); } } + public static MethodHandle WinUsb_SetCurrentAlternateSetting$MH() { + return RuntimeHelper.requireNonNull(constants$0.WinUsb_SetCurrentAlternateSetting$MH,"WinUsb_SetCurrentAlternateSetting"); + } + public static int WinUsb_SetCurrentAlternateSetting ( Addressable InterfaceHandle, byte SettingNumber) { + var mh$ = WinUsb_SetCurrentAlternateSetting$MH(); + try { + return (int)mh$.invokeExact(InterfaceHandle, SettingNumber); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static MethodHandle WinUsb_SetPipePolicy$MH() { return RuntimeHelper.requireNonNull(constants$0.WinUsb_SetPipePolicy$MH,"WinUsb_SetPipePolicy"); } @@ -77,7 +88,7 @@ public static int WinUsb_SetPipePolicy ( Addressable InterfaceHandle, byte Pipe } } public static MethodHandle WinUsb_ReadPipe$MH() { - return RuntimeHelper.requireNonNull(constants$0.WinUsb_ReadPipe$MH,"WinUsb_ReadPipe"); + return RuntimeHelper.requireNonNull(constants$1.WinUsb_ReadPipe$MH,"WinUsb_ReadPipe"); } public static int WinUsb_ReadPipe ( Addressable InterfaceHandle, byte PipeID, Addressable Buffer, int BufferLength, Addressable LengthTransferred, Addressable Overlapped) { var mh$ = WinUsb_ReadPipe$MH(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java index 18a072c8..0845afad 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java @@ -43,6 +43,14 @@ class constants$0 { "WinUsb_GetDescriptor", constants$0.WinUsb_GetDescriptor$FUNC ); + static final FunctionDescriptor WinUsb_SetCurrentAlternateSetting$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT + ); + static final MethodHandle WinUsb_SetCurrentAlternateSetting$MH = RuntimeHelper.downcallHandle( + "WinUsb_SetCurrentAlternateSetting", + constants$0.WinUsb_SetCurrentAlternateSetting$FUNC + ); static final FunctionDescriptor WinUsb_SetPipePolicy$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_CHAR$LAYOUT, @@ -54,18 +62,6 @@ class constants$0 { "WinUsb_SetPipePolicy", constants$0.WinUsb_SetPipePolicy$FUNC ); - static final FunctionDescriptor WinUsb_ReadPipe$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle WinUsb_ReadPipe$MH = RuntimeHelper.downcallHandle( - "WinUsb_ReadPipe", - constants$0.WinUsb_ReadPipe$FUNC - ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java index 08552176..2c874c1d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java @@ -7,6 +7,18 @@ import java.lang.invoke.MethodHandle; class constants$1 { + static final FunctionDescriptor WinUsb_ReadPipe$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle WinUsb_ReadPipe$MH = RuntimeHelper.downcallHandle( + "WinUsb_ReadPipe", + constants$1.WinUsb_ReadPipe$FUNC + ); static final FunctionDescriptor WinUsb_WritePipe$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_CHAR$LAYOUT, From defa52e08275ca00733040e087c6602fbeebb54d Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 18 Oct 2022 23:35:23 +0200 Subject: [PATCH 119/433] Set alternate interface (Linux) --- java-does-usb/jextract/linux/gen_linux.sh | 2 + .../codecrete/usb/linux/LinuxUSBDevice.java | 27 ++++++++- .../net/codecrete/usb/linux/USBDevFS.java | 2 + .../usbdevice_fs/usbdevfs_setinterface.java | 56 +++++++++++++++++++ reference/linux/usb_device.cpp | 2 + 5 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index 09930002..69c26c84 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -48,10 +48,12 @@ $JEXTRACT --source --output ../../src/main/java \ --target-package net.codecrete.usb.linux.gen.usbdevice_fs \ --include-struct usbdevfs_bulktransfer \ --include-struct usbdevfs_ctrltransfer \ + --include-struct usbdevfs_setinterface \ --include-macro USBDEVFS_CONTROL \ --include-macro USBDEVFS_BULK \ --include-macro USBDEVFS_CLAIMINTERFACE \ --include-macro USBDEVFS_RELEASEINTERFACE \ + --include-macro USBDEVFS_SETINTERFACE \ /usr/include/linux/usbdevice_fs.h # libudev.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index bddd9484..f1d87790 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -10,6 +10,8 @@ import net.codecrete.usb.*; import net.codecrete.usb.common.*; import net.codecrete.usb.linux.gen.errno.errno; +import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_setinterface; +import net.codecrete.usb.macos.MacosUSBException; import net.codecrete.usb.usbstandard.DeviceDescriptor; import net.codecrete.usb.linux.gen.fcntl.fcntl; import net.codecrete.usb.linux.gen.ioctl.ioctl; @@ -112,7 +114,30 @@ public void claimInterface(int interfaceNumber) { @Override public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { - throw new IllegalStateException("not implemented"); + checkIsOpen(); + + var intf = getInterface(interfaceNumber); + if (intf == null) + throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); + if (!intf.isClaimed()) + throw new USBException(String.format("Interface %d has not been claimed", interfaceNumber)); + + // check alternate setting + var altSetting = intf.getAlternate(alternateNumber); + if (altSetting == null) + throw new MacosUSBException(String.format("Interface %d does not have an alternate interface setting %d", + interfaceNumber, alternateNumber)); + + try (var session = MemorySession.openConfined()) { + var setIntfSegment = session.allocate(usbdevfs_setinterface.$LAYOUT()); + usbdevfs_setinterface.interface_$set(setIntfSegment, interfaceNumber); + usbdevfs_setinterface.altsetting$set(setIntfSegment, alternateNumber); + int ret = ioctl.ioctl(fd, USBDevFS.SETINTERFACE, setIntfSegment.address()); + if (ret != 0) + throw new USBException("Failed to set alternate interface", IO.getErrno()); + } + + intf.setAlternate(altSetting); } public void releaseInterface(int interfaceNumber) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java index 96b6c011..cf74b496 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java @@ -16,4 +16,6 @@ public class USBDevFS { public static final long BULK = 0xc0185502; public static final long CLAIMINTERFACE = 0x8004550F; public static final long RELEASEINTERFACE = 0x80045510; + + public static final long SETINTERFACE = 0x80085504; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java new file mode 100644 index 00000000..0aec7f05 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java @@ -0,0 +1,56 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +public class usbdevfs_setinterface { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_INT$LAYOUT.withName("interface"), + Constants$root.C_INT$LAYOUT.withName("altsetting") + ).withName("usbdevfs_setinterface"); + public static MemoryLayout $LAYOUT() { + return usbdevfs_setinterface.$struct$LAYOUT; + } + static final VarHandle interface_$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("interface")); + public static VarHandle interface_$VH() { + return usbdevfs_setinterface.interface_$VH; + } + public static int interface_$get(MemorySegment seg) { + return (int)usbdevfs_setinterface.interface_$VH.get(seg); + } + public static void interface_$set( MemorySegment seg, int x) { + usbdevfs_setinterface.interface_$VH.set(seg, x); + } + public static int interface_$get(MemorySegment seg, long index) { + return (int)usbdevfs_setinterface.interface_$VH.get(seg.asSlice(index*sizeof())); + } + public static void interface_$set(MemorySegment seg, long index, int x) { + usbdevfs_setinterface.interface_$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle altsetting$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("altsetting")); + public static VarHandle altsetting$VH() { + return usbdevfs_setinterface.altsetting$VH; + } + public static int altsetting$get(MemorySegment seg) { + return (int)usbdevfs_setinterface.altsetting$VH.get(seg); + } + public static void altsetting$set( MemorySegment seg, int x) { + usbdevfs_setinterface.altsetting$VH.set(seg, x); + } + public static int altsetting$get(MemorySegment seg, long index) { + return (int)usbdevfs_setinterface.altsetting$VH.get(seg.asSlice(index*sizeof())); + } + public static void altsetting$set(MemorySegment seg, long index, int x) { + usbdevfs_setinterface.altsetting$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/reference/linux/usb_device.cpp b/reference/linux/usb_device.cpp index 711ad252..bd997d42 100644 --- a/reference/linux/usb_device.cpp +++ b/reference/linux/usb_device.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -46,6 +47,7 @@ bool usb_device::is_open() const { } void usb_device::open() { + std::cout << USBDEVFS_SETINTERFACE << std::endl; if (is_open()) throw usb_error("USB device is already open", 0); From 43a24c7bb7c8200dd97f335b80180f486603b482 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 18 Oct 2022 23:36:55 +0200 Subject: [PATCH 120/433] Undo reference code modification --- reference/linux/usb_device.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/reference/linux/usb_device.cpp b/reference/linux/usb_device.cpp index bd997d42..711ad252 100644 --- a/reference/linux/usb_device.cpp +++ b/reference/linux/usb_device.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include @@ -47,7 +46,6 @@ bool usb_device::is_open() const { } void usb_device::open() { - std::cout << USBDEVFS_SETINTERFACE << std::endl; if (is_open()) throw usb_error("USB device is already open", 0); From a54db76503d4c8a25fbc4d1065a822c86d1d8990 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 21 Oct 2022 13:35:41 +0200 Subject: [PATCH 121/433] Clear halt (macOS) --- .../java/net/codecrete/usb/USBDevice.java | 15 +++++ .../codecrete/usb/common/USBDeviceImpl.java | 5 ++ .../net/codecrete/usb/macos/IoKitUSB.java | 7 +++ .../codecrete/usb/macos/MacosUSBDevice.java | 10 ++++ .../codecrete/usb/AlternateInterfaceTest.java | 2 +- .../net/codecrete/usb/DescriptionTest.java | 2 +- .../codecrete/usb/DeviceLifecycleTest.java | 2 +- .../codecrete/usb/InterruptTransferTest.java | 2 +- .../codecrete/usb/InvalidOperationTest.java | 2 +- .../java/net/codecrete/usb/StallTest.java | 60 +++++++++++++++++++ .../java/net/codecrete/usb/StreamTest.java | 2 +- .../net/codecrete/usb/TestDeviceBase.java | 2 +- .../java/net/codecrete/usb/TimeoutTest.java | 2 +- 13 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/StallTest.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index f7d2b61a..686c7780 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -291,6 +291,21 @@ public interface USBDevice { */ InputStream openInputStream(int endpointNumber); + /** + * Clears an endpoint's halt condition. + *

+ * An endpoint is halted (aka stalled) if an error occurs in the communication. Before the + * communication can resume, the halt condition must be cleared. A halt condition can exist + * in a single direction only. + *

+ *

+ * Control endpoint 0 will never be halted. + *

+ * @param direction endpoint direction + * @param endpointNumber endpoint number (in the range between 1 and 127) + */ + void clearHalt(USBDirection direction, int endpointNumber); + /** * Gets the configuration descriptor. * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 3197357f..df35f04a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -322,6 +322,11 @@ public byte[] transferIn(int endpointNumber, int maxLength) { @Override public abstract byte[] transferIn(int endpointNumber, int maxLength, int timeout); + @Override + public void clearHalt(USBDirection direction, int endpointNumber) { + throw new IllegalStateException("not implemented"); + } + @Override public OutputStream openOutputStream(int endpointNumber) { // check that endpoint number is valid diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index e89fe509..768294c9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -174,4 +174,11 @@ public static int SetAlternateInterface(MemoryAddress self, byte alternateSettin return IOUSBInterfaceInterface.SetAlternateInterface(getVtable(self, session), session).apply(self, alternateSetting); } } + + // IOReturn (* ClearPipeStall)(void* self, UInt8 pipeRef); + public static int ClearPipeStall(MemoryAddress self, byte pipeRef) { + try (var session = MemorySession.openConfined()) { + return IOUSBInterfaceInterface.ClearPipeStall(getVtable(self, session), session).apply(self, pipeRef); + } + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index a39e2ec4..9c1c4143 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -419,6 +419,16 @@ public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { } } + @Override + public void clearHalt(USBDirection direction, int endpointNumber) { + var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.IN, + USBTransferType.BULK, USBTransferType.INTERRUPT); + + int ret = IoKitUSB.ClearPipeStall(endpointInfo.interfacAddress(), endpointInfo.pipeIndex); + if (ret != 0) + throw new MacosUSBException("Clearing halt condition failed", ret); + } + synchronized ScheduledExecutorService getScheduledExecutorService() { if (scheduledExecutorService == null) scheduledExecutorService = Executors.newScheduledThreadPool(1); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java index 89259f2e..b1ecd715 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Unit test for bulk transfer +// Unit test for changing alternate interface setting // package net.codecrete.usb; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index 7a532f24..d9fb79d9 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Unit tests for USB device enumeration +// Unit tests for checking descriptive device information // package net.codecrete.usb; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java index c9aa23be..d53a8c3c 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Unit test for bulk transfer +// Unit test for device lifecycle (open/close, claim/release) // package net.codecrete.usb; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java index d3ff2ee5..ec1a616c 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Unit test for bulk transfer +// Unit test for interrupt transfers // package net.codecrete.usb; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java index e2d5326e..cb8e2e0d 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Unit test for bulk transfer +// Unit test for invalid operations (invalid interface number, invalid endpoint number etc.) // package net.codecrete.usb; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java new file mode 100644 index 00000000..b1f59104 --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java @@ -0,0 +1,60 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Unit test for data overruns +// + +package net.codecrete.usb; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; + +public class StallTest extends TestDeviceBase { + + @Test + void stallOnBulkTransfer_throws() { + byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + testDevice.transferOut(LOOPBACK_EP_OUT, data); + Assertions.assertThrows(USBException.class, () -> { + testDevice.transferIn(LOOPBACK_EP_IN, 5); + }); + + testDevice.clearHalt(USBDirection.IN, LOOPBACK_EP_IN); + + var receivedData = testDevice.transferIn(LOOPBACK_EP_IN, 20); + Assertions.assertArrayEquals(data, receivedData); + } + + @Test + void stallOnInterruptTransfer_throws() { + Assumptions.assumeTrue(isLoopbackDevice(), + "Interrupt transfer only supported by loopback test device"); + + byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; + testDevice.transferOut(ECHO_EP_OUT, data); + Assertions.assertThrows(USBException.class, () -> { + testDevice.transferIn(ECHO_EP_IN, 4); + }); + + testDevice.clearHalt(USBDirection.IN, ECHO_EP_IN); + + // first echo + var receivedData = testDevice.transferIn(ECHO_EP_IN, 20); + Assertions.assertArrayEquals(data, receivedData); + + // second echo + receivedData = testDevice.transferIn(ECHO_EP_IN, 20); + Assertions.assertArrayEquals(data, receivedData); + } + + @Test + void invalidControlTransfer_throws() { + Assertions.assertThrows(USBException.class, () -> { + testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x08, (short) 0, (short) interfaceNumber), 2); + }); + } +} diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java index 65c1d99b..fe1ffdfb 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Unit test for bulk transfer +// Unit test for bulk transfer with input/output streams // package net.codecrete.usb; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index 23c9af8f..9aab941c 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Unit tests for USB device enumeration +// Base class for unit tests using the connected test device // package net.codecrete.usb; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java index a9e42024..5c6701db 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Unit tests for USB device enumeration +// Unit tests for transfers with timeout // package net.codecrete.usb; From 9a75413908d402b0128ff5541a1a161cac722c98 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 21 Oct 2022 13:43:17 +0200 Subject: [PATCH 122/433] Clear halt with control message (macOS) --- .../src/main/java/net/codecrete/usb/macos/IoKitUSB.java | 7 ++++--- .../main/java/net/codecrete/usb/macos/MacosUSBDevice.java | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index 768294c9..e368c7e6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -9,6 +9,7 @@ import net.codecrete.usb.macos.gen.iokit.IOUSBDeviceInterface; import net.codecrete.usb.macos.gen.iokit.IOUSBInterfaceInterface; +import net.codecrete.usb.macos.gen.iokit.IOUSBInterfaceStruct942; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; @@ -175,10 +176,10 @@ public static int SetAlternateInterface(MemoryAddress self, byte alternateSettin } } - // IOReturn (* ClearPipeStall)(void* self, UInt8 pipeRef); - public static int ClearPipeStall(MemoryAddress self, byte pipeRef) { + // IOReturn (* ClearPipeStallBothEnds)(void* self, UInt8 pipeRef); + public static int ClearPipeStallBothEnds(MemoryAddress self, byte pipeRef) { try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface.ClearPipeStall(getVtable(self, session), session).apply(self, pipeRef); + return IOUSBInterfaceStruct942.ClearPipeStallBothEnds(getVtable(self, session), session).apply(self, pipeRef); } } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 9c1c4143..3b2365e9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -424,7 +424,7 @@ public void clearHalt(USBDirection direction, int endpointNumber) { var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); - int ret = IoKitUSB.ClearPipeStall(endpointInfo.interfacAddress(), endpointInfo.pipeIndex); + int ret = IoKitUSB.ClearPipeStallBothEnds(endpointInfo.interfacAddress(), endpointInfo.pipeIndex); if (ret != 0) throw new MacosUSBException("Clearing halt condition failed", ret); } From 86abe86b8bb9780a1f0b23d1663c95a8cb3b49c3 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 21 Oct 2022 22:09:00 +0200 Subject: [PATCH 123/433] Handle halt and clear stall in test devices --- .../composite-stm32/bin/blackpill-f401cc.bin | Bin 11520 -> 11596 bytes .../composite-stm32/bin/blackpill-f411ce.bin | Bin 11524 -> 11600 bytes .../composite-stm32/bin/bluepill-f103c8.bin | Bin 10080 -> 10156 bytes .../composite-stm32/{include => src}/board.h | 0 test-devices/composite-stm32/src/main.c | 16 ++++-- .../{include => src}/usb_descriptors.h | 0 .../composite-stm32/src/vendor_custom.c | 18 ++++++- .../{include => src}/vendor_custom.h | 9 ++++ .../loopback-stm32/bin/blackpill-f401cc.bin | Bin 10508 -> 10592 bytes .../loopback-stm32/bin/blackpill-f411ce.bin | Bin 10512 -> 10596 bytes .../loopback-stm32/bin/bluepill-f103c8.bin | Bin 8760 -> 8844 bytes .../loopback-stm32/{include => src}/board.h | 0 test-devices/loopback-stm32/src/main.c | 51 ++++++++++++++---- .../{include => src}/usb_descriptors.h | 0 .../loopback-stm32/src/vendor_custom.c | 8 +++ .../{include => src}/vendor_custom.h | 9 ++++ 16 files changed, 96 insertions(+), 15 deletions(-) rename test-devices/composite-stm32/{include => src}/board.h (100%) rename test-devices/composite-stm32/{include => src}/usb_descriptors.h (100%) rename test-devices/composite-stm32/{include => src}/vendor_custom.h (93%) rename test-devices/loopback-stm32/{include => src}/board.h (100%) rename test-devices/loopback-stm32/{include => src}/usb_descriptors.h (100%) rename test-devices/loopback-stm32/{include => src}/vendor_custom.h (94%) diff --git a/test-devices/composite-stm32/bin/blackpill-f401cc.bin b/test-devices/composite-stm32/bin/blackpill-f401cc.bin index 4e4e714fbd6b416271786d6cafa0a01ecd2b27d1..652cb537176bcd2b5ec0eaf3a1b6fb68b593d556 100755 GIT binary patch delta 988 zcmZuvU2GIp6h3EWe{Rc9wr!T~vclfosW7zNv>^gD{&b;nc1uk_qlDI2f9ofLu?A zxN;PCnt7#7!G3Yw)7d*%0Ep(7rEv^wy=s*_?R#@09PF>k$w^XN8O=6-QOL%n@AI%8GwHv&o5Ib48(oWynBEugMUj}S5`*Ev{lotNlUqTknt=fu~(2woI(zBRF?O3cuW zD+|aomai3Pe&DhIYH9}3nN(2({atl;=$}e;bcqMWet#P_h*7_`dz!K`sZ5F)EFU($ ztx>04=TR3qvs|any}Qsb)L{2xARm}{VF+7S%t&YV^(OPPJCMI4SgJZiaOXgp?H8g zCziSmh+z1M=jJI0Waz zGN&kkgcw;nD`{7>`GJaV+#EBUC5w^x^OAmwzc1-EO)B%O_NVM>9$)A4tmIVeA(|5A`Q|CybcVL!JHl@Y@E>W= yIl=}8>=yAnK|bR58eost0vjOIECY5ySgq?HnW(4j^8ydRa*8RsQ5j0dCEN#hPBY5@ delta 858 zcmZuvZAep57=F*)bvv4hX}Zmu+jT3QZlaY+;18G8R2GC$kW$eIe+Wr~6qHbBA3uxe zL=hx~zmzmTZbJ;lsO%HblECZ(v=WUuxP8do%59xv^Ir#^^SsY{o^#&k$C+&KGz>pL zhLu9V*sF31BdS_e&CpNqU?0$B0T5RT$qcGW-L(etSlC?+fW(hBV&bkLUh;Cq9NIz_ z`O12yAHe9{RD=3K=Ayn3Uvg^Xya@8uuzj2=k-Oz7?DKm}tmg?Q3?C2ie@ay#VlS=% z`EaDtk~D|tSxdNN+-~A)k?32-c982yM?!uX9}yiOcSf}b4$83-$VGB#2&nsP_~eM) z#PzefJ&h@j4~yk5IoW$}v+-AMN+PvP(d~O^1)3E^W=3X}8*1Fu*GYk9@8&*w z!jvP<+ewF}80C;bjTv1eZ!{Un#W5seUrZ5Vzn6#wTaZ<%!_$c=DH_0&2*ei@1EeVZ zJK9Q&8Anix)SA(%LiaLvia-|Nu>K#v)B>)E*I#I@Xi2*67`jc) z=qgbI8PfG+7SIWD5awNK!20+!J#pzP>MqlZV-&L#tMpNZK)ko1|Hn6}C#rmorkgoO z(tMW_td+m+-H$2@B&ZkAG)c@hqUTaU_Bo^vMw%9rokH7tP1kDUVA{IXH5gUC5uaer zY@~76H)D%METekAv?|PU+=Pux8D<#u8VlEzai?LzM*Ryg&pQESADs#DyUjAEdQ90} zO`QfYi#nxp@dRRgBe$F}nKB(>WHMi2G-_r_Qg8dghDg8j)O_k&`tAna*`!qKGgNk( p_Sz`Eav(mUxt>sbisyYA=bl8sK?;2mU>`+0Ni51oF0!LY_zUTv7|8$t diff --git a/test-devices/composite-stm32/bin/blackpill-f411ce.bin b/test-devices/composite-stm32/bin/blackpill-f411ce.bin index 7509f97c83a22babf31c76be5ba32703b224ec05..1cd4ed5b4e8a2111676a9da22442410722250361 100755 GIT binary patch delta 880 zcmZvae@IhN6vxkb+up8*p-$T`YES3f!)<6k39P1Bn_^akL9L7+qYR|=hh#;V6(Ix_ zT?h)Ipa?_~=fg^Ann7Ywq!NjVU{EdpFkWG8E8V)c)_-02-p@IgbIZ52x4&!i007TT(F zt}a@Te4yS<7`JRwlO>RcY9I!z`g(kSs4QP-=kcw$&@T9Rq{jK)L8o-(c$wP7rCC4b zZ*PPX|OR4%10-XnpNiE+9O+mSPia)EA?H-qhRi4IR`QHaU_gk#I7a zmHZhoG#k|YnAwv#THB27jM43FhkG@uO(VF(QC+1Jy3+QfI~grVO1{i6Nb?cm`x!YX z0-@7-8Ffk;d7YNw&;xmiAPqCk(~ntS5$JgKPIM?9Lz4z&dS^*1o}&(9OW{!qkUFMP zBao^T%_blh&415Uve<8;FN}Nf40W2kxPcxr-OMd#6VzFlKEWn0Pfcr}W^-xd6uYQr zjhsxISyQf37W1=z`TrPU_Y%>eM7CYquaE84_%nZ5Le zc+V&PH4;&U4w`M)p}aSrLL8-aRwKTmO;&sEX=Vvhi`%SWd7X0KIxYw~9(rNf7)QWX z^e3~e;OMhiEIA$^+G;?{uCbVQZG|dmo-zjgIUePUZ6C5SWozCVPI@7K2gkeoOB_e+ zJX8AZ-}nHfyHM0FE?~|6N%km1MMJpyG5bk|nLY?0O)yWBOdbN{JL41+w>+B$WPLi2 T2BwTfK%UbeHbKIw7b>E&CyHKVA4)^0)kaosB4&8f1GY-q81C<4A9pZvBxDuo$ z(xEOYXXBg~q>~B5mTgk96zoVUivi7UmG=cI3z%-jZj+gA#;aH_WaWL9d{kGV7Gl#_ z_2Y}zs~tm}*BI!y%hG-a$ySY#v}u~GHwU|9C$NTEH(6aHCXxWKH%w$|rnIBhrg) zIY(4zGl}GNpljrip}mkd1J+YT@&Lz8fB4D(*psrSsl8wzdB)x73TZWZP%{yYS99I8 zgER+WzXq^1)y+!$rcK)~&<`I{O;E|SsG>+Jw(S3pmuXHS`Z=-ZIRni-cB&6x^~EFL}1L6{GaW!W4wr20-Rrp%}ZKml)M!O2Ma`{f*cB6Bjpf zdl4-mUb0sxB%y*G3JUpi3hwcWC+b#xSGtOcLJgbwjuuJKAu3B7G-YNTL=UKIGAk7pN zN|H;U`9}#6jZ&PCWh2%zj0y~N6_kbGKcW30yfS${f9!Ri&HuXax!-fnJMWxx?|X~Y z&uYet0R~A4BAWd`VImB# zS(2jdPf4HtI9ww$`n+SSTMsLIBF8(THz)KvJyrRNnpigbRr!{PL~R;Xz9E8-nd_v4 z1FGCgPj-%;jF{Q8@Pb@sbKni>Ve?GJZ5Qw3zb^q7PFx^S*2?(3l8cn!uc_YlC7_ zvbOhPTqikoOpzhU2D#|n-l+*yE>Jn%oIu>x66QCSEG)w0w!sIi5Hk!LO-bs10K~ng zG>}H~8aT*lOFbloh^0jbe&V#h<$}NkXF#5hw4JQnaxPXGLN3RN?#nNyrj&~q8hX5*slLSy-ssd^2gME zH^XNvc2=UI@;{HpQgV`%IdVWG^$sUY3N4Oq$ojh7@WWJ@)Anso`&!+oc_+1YG$nr~ z)@+Zx&_FLey|ft>I-k)XRA+Ah3<#mzPdc_$`v!uGTh*I7sJTm*;PSkKBMurWpd6)AI(`*o#`=Ds(%4HbRT~J delta 811 zcmZvZUr1AN6vuyOcX$3~3R|#0I>qbebhShu3@U;x#XH4+5egNJ3VTpwv{0#D@?TOB zLh>WXEK105k>C_KSxTnj^j*{V_S!We)xIffLK^nF1V+D3VRtS|f`(7q|t;7}aM-ScK;Rai1w!BxFcH z1$ky{fryYWb~A8+beM)9Ok~p?=Q}IHu8r5OU(lv#Z&4wj0YC zJ&EQ?!)}4olPO6g7jvCvla79A`lyqy(y0@y@Hlr1pjvpCx4^LO5`>F{0QXm$T|v!# zjtK$hCpbD!|9_EELDzPT7VD%8QPi5Gs=Kc&o30(yiGk@k|3yq^YyAF+rtpe&jj LQwq{!C{+Ie?4SuU diff --git a/test-devices/composite-stm32/include/board.h b/test-devices/composite-stm32/src/board.h similarity index 100% rename from test-devices/composite-stm32/include/board.h rename to test-devices/composite-stm32/src/board.h diff --git a/test-devices/composite-stm32/src/main.c b/test-devices/composite-stm32/src/main.c index 0f8826ad..47b50e19 100644 --- a/test-devices/composite-stm32/src/main.c +++ b/test-devices/composite-stm32/src/main.c @@ -89,10 +89,8 @@ void loopback_check_tx(void) { void loopback_check_rx(void) { int n = tu_fifo_remaining(&loopback_fifo); - if (n >= sizeof(loopback_rx_buffer) && !cust_vendor_is_receiving(EP_LOOPBACK_RX)) { - + if (n >= sizeof(loopback_rx_buffer) && !cust_vendor_is_receiving(EP_LOOPBACK_RX)) cust_vendor_prepare_recv(EP_LOOPBACK_RX, loopback_rx_buffer, sizeof(loopback_rx_buffer)); - } } // --- CDC class @@ -138,6 +136,18 @@ void cust_vendor_intf_open_cb(uint8_t intf) { loopback_check_rx(); } +void cust_vendor_halt_cleared_cb(uint8_t ep_addr) { + switch (ep_addr) { + case EP_LOOPBACK_RX: + loopback_check_rx(); + break; + case EP_LOOPBACK_TX: + loopback_check_tx(); + break; + default: + break; + } +} // --- Control messages (see README) diff --git a/test-devices/composite-stm32/include/usb_descriptors.h b/test-devices/composite-stm32/src/usb_descriptors.h similarity index 100% rename from test-devices/composite-stm32/include/usb_descriptors.h rename to test-devices/composite-stm32/src/usb_descriptors.h diff --git a/test-devices/composite-stm32/src/vendor_custom.c b/test-devices/composite-stm32/src/vendor_custom.c index 44b2dc26..36fe96ed 100644 --- a/test-devices/composite-stm32/src/vendor_custom.c +++ b/test-devices/composite-stm32/src/vendor_custom.c @@ -21,13 +21,14 @@ static void cv_init(void); static void cv_reset(uint8_t rhport); static uint16_t cv_open(uint8_t rhport, tusb_desc_interface_t const* desc_intf, uint16_t max_len); +static bool cv_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); static bool cv_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); const usbd_class_driver_t cust_vendor_driver = { .init = cv_init, .reset = cv_reset, .open = cv_open, - .control_xfer_cb = NULL, + .control_xfer_cb = cv_control_xfer, .xfer_cb = cv_xfer_cb, .sof = NULL }; @@ -68,6 +69,21 @@ uint16_t cv_open(uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16 return processed_bytes; } +bool cv_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) { + TU_VERIFY(TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type); + + if (request->bRequest == TUSB_REQ_CLEAR_FEATURE + && request->wValue == TUSB_REQ_FEATURE_EDPT_HALT + && request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_ENDPOINT + && cust_vendor_halt_cleared_cb != NULL) { + uint8_t const ep_addr = tu_u16_low(request->wIndex); + cust_vendor_halt_cleared_cb(ep_addr); + return true; + } + + return false; +} + bool cv_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { diff --git a/test-devices/composite-stm32/include/vendor_custom.h b/test-devices/composite-stm32/src/vendor_custom.h similarity index 93% rename from test-devices/composite-stm32/include/vendor_custom.h rename to test-devices/composite-stm32/src/vendor_custom.h index 03976045..4d976a1a 100644 --- a/test-devices/composite-stm32/include/vendor_custom.h +++ b/test-devices/composite-stm32/src/vendor_custom.h @@ -109,6 +109,15 @@ TU_ATTR_WEAK void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes); */ TU_ATTR_WEAK void cust_vendor_intf_open_cb(uint8_t intf); +/** + * @brief Invoked when an endpoint's halt condition has been cleared. + * + * This function is called as part of a SET FEATURE control request. + * + * @param ep_addr endpoint address + */ +TU_ATTR_WEAK void cust_vendor_halt_cleared_cb(uint8_t ep_addr); + // --- Driver to be registered in usbd_app_driver_get_cb() diff --git a/test-devices/loopback-stm32/bin/blackpill-f401cc.bin b/test-devices/loopback-stm32/bin/blackpill-f401cc.bin index 9af958a0c4e718fc9480bcd2800c893fcdd1a689..e5b18a7bf37e57d0163bca4a964196b63099d6b7 100755 GIT binary patch delta 1383 zcmZuxeQZ-z6hHU9e%y|Y721w{lA1Gvzs5OMx@CO!+ zcB~;O#t6wZfM{^hkVqndtyU>Xc_?DShq5<@iU^J%bo@blap)`C==HpP#D9Fr@BQvM z_uO;O`Q_xkw`OF`kuOQLR|ZPcVz{bb42i+RW6(phfS(K?d1W?4+N;lwgZ{(aXaImn zkJbalU8!ycU}eohudqT+eI+ysLWj(5S{{pw#{p{6bAsd`=-*9d^OmL!{k;8XiY;spRYnpR{rE8_#)=Zeb^kF?-56Mo@FMJKsN=@&0(?MxtM9<( z(vUOgd}7{{p#L}_DWH4qm9B!?)jDqi{jCBw65JnYj-066)joE?)gi_F-Q0+CUo4>$ z(HFgyYr~voA*)aZ3!(!-WSTD0-W@0k#^;1UmnXTgmz#BS<4skRsb&iciz>Tq;fn5Q z?2=9rjH0wacocl=p8NaG<>aGj?G{CuZEJCS<#2?Q}&^ye z0^d-bQ|h?mSQ$-ov>6v^`jio!*+Tg#pXpMkn`Xrjxxedl1iwa`B+>3z4mZ z(Lk?k8BE9yTybN$%8do86-D=FxY4c(Q}W;a4aZ_iX;L3eTNSqw&|ER5+n!!~>S(#` z>hSfX#eZ2V>8w>`B|92zBf569!ZtRnCm*pLuEc$3%YbGO z2V965-r)v%!!zys4A)-Q>_GL~FycYh*mjSv^&vdF0g*r) z##|=$%=l*Q|KpVy!;Mjv^E8l)%u`lFPNyCy+e*9zV~oFkqcmI<`_&%*d*dNz82qhw zUOiMW{^ab;f@bS&y!##_%+EfaHW?d>Ti1 K4gSrKBmM<{o7^@4 delta 1298 zcmZuxZA@EL7(VCrwmogfT4>7(RJf(gUTEBq=|UU|f#tTPAOSO6)J-Dlx*22R5AFU~ zK0;EBahM|}Gn#Dwn2|`SRl1~hx@1}67e!`*gjr=!)EIBZ^j1KQ@7+dpi6?pPbKduy z^PKlN_uQN7dA(=yBV2jeg9u4#f)#O1K;!>#4GoYqf+iv)T=vje+*)~d9m${k74{*7 zg;fy|7!_)6W0R*1+z^-ZBtGW$aGdO+EBr&zd61||n*8`2lHb`(7x?=A_>h3)j`fxl zL;`nupl&=fP_5>g*0qyI3jBu1A%P@`AIaQivuK>hFjl`_pK7V*16W9}k`^S}&y%z| zZw@0tpF}lG`CtpZh232@(2M4P#c$~>ei+H;qZ@*RWc;_e1G&0nR*&RkTTD64yrG8B zh4RtXwQsElg^0J0DPznX8J4le9sW7r1j4F#2Uz0)2LV_lNuy-UzBXm@n*vC-ZZc(p zsl_nmR7N9`tUk!O%KC-{UEo%US5hRcK^c*D>UKq~;AU{+Oskj?Bu9L3$_z0EiQ^z) z0f}g4SS-n!+N~jc0C}x_+C`(Jj_6^l@sy=n8_ay5f++M4m2g5=kZSwBQ_Qr|=JKGJRlGvY9`y@eP%1LGly5r-qd!-9gOnG~& zR%(P5qii{kgll<0`Y8_v!Q8umGk~}bs!sA!k%T2Alu9UJF#5E3jCPyn@m1=z9KvIX zLCX~m_tHnLBY1)?T8DSPT#CpufNm?`Hs5bU4@zJexEMcnsJD_?dOW( zdPL;kP;MFaJWJ>8?&f8fZ-(`I0gr>0iZ_;*;xly!Qb^d6k2$4jg5LgLlZ zli0}=ZQ+GwbFd=vy*~QKa}$;z@;2W%Ho+8Jpp}jWZ5nF$iXL+Kus!jfV~OKtL^@P4 zt5UDC?q=j{*gvDb;~!Cu4v4{l5ozM#BSAahFP39f@KhTE`~xR>wjBTf diff --git a/test-devices/loopback-stm32/bin/blackpill-f411ce.bin b/test-devices/loopback-stm32/bin/blackpill-f411ce.bin index 12c711f71ea1de34f871796c794e190c296bca21..3c24192618332fa2e1be671168fa5f2758e9ef01 100755 GIT binary patch delta 1303 zcmZuxZA@EL7=F)fd+#kDwzDmxP}kdahKmJdEE4>rW6N!!&KVL^G+R&;S3?%7KalB< zI+|%U!H^uI%eG9iKZYMmfTqd7)H^pdS#(HY=r-JhOe|=~u5RWsz#iYrN9GT2^4#aV z?|sj6p7WlQ+uQPM%fK1JNirQFWd{978n=A61lq+ru@C?!1uH=W0BPGgz(VV|ZmwQV zjc^ZgTv(>Ro1b)>z69{53&W%zw69k(i{_eF2D>HDI_XY}BmU}=WnkZ;dAW)MNlc4j z(5hA%%D_&Tt84hkWHxVf_Ck8=l7!fl@-6aB&5GjvBz;ca`2u)?t1Xk}Hv16?X zM}ZMgomf|j@F0XVY-9Q-dH9(4_uhs#ZB6#Deb1(+K^uK^SyDiA{bPFye0w!k1KK-z zrYBe+S{prE*4ub%!m(TG3bZpl&iq{ojhOtg`CJf1tLTiy8P9$=R1hv~0!?0F`cY>1 zWcu5xNfxtwgxgxy&PUwsYuV4#yY4sKb<6g2kz&slaqGb*;C zq8$}G)PyW#EzORo5tGLpXy`4~o{1anFvP?()7#dU?@$5kX(3#MJDXqTBY-xT-poA1 zYho|r#Ep3-xoC{LOk~SgEYvNV#}cv?M@-+LGJUgZ!6pZWnck>!tL?t?GameEYe{7+ zZBd-`Cg0}%=1eJn{nCx3IWUziZuTj%l9`JIiI$}=39hP6bl_9Aw9CpbIU>a}pw7vF z=Zqa(_fGt#7=&XXdnG+3G+IyMXCrK*3&IX^p8CWJ-(}1VAY!3dNL0kMTRCqvjWIo! zCz6<9`d9Qd@gQlYKZ#y)jOya9_{qGa)MpmcjxLAR&I^iD*`96fDyZhO#P3FvpiM9$ zEoKUsd7n~`GfuJD9H}nOK9h_N zn>4S93tZ0@gh8Gf>rJlJP3G`+=4zC2XAaa}+~WyEA7YpXaVFJoea=EIP-446zNb^R zR&pV=-9E{Y-BfTKA;)QtBXR!^B_L)H{SL%B_c%eEcdg|<$MF~RVdp+_lu~B{d6rH% z`-^7<5VZxEb|X*H4_y9+Cvffo#QTU8Y8g1bp4*83k3(3)^f~&6tC~zwcZnBGK2mas zc=Gx!_WGk{i2vPj+8%*G!|em7^ZHFjM>p5F5Y-ao#{0ntMy`umC delta 1181 zcmZuvUu;uV96smvw)eEP^p3V$SLSxxPJ3q+=4Qx@iyMQSw(Edw%NBzIjhJj;(8i~t zi3?1~Fi~p`n9TS94<=w-vaPw1Ej9&7d@w%PIZVa^iVVyAmm8Vfy3HMb7uW-d4`06X z``zF9&i9>j7kaWi;}@{-ZG=tZfJr~#j@q-!NdMxWbPORu`CUZ>A*9qlz^cf$3de+n zNN!r#EC@>x_N(}O^;{mII?Wl!=aK&LYQ8Ks9+)_$AiaxivwDVFm#yP_%i@YEAcbfo zj&xzQO?Av+m}p#XoN5n=39RIAlXj&0rb*tMo5e_xG*r)x&)3i?9NxWz-f$=6xV*Ds z7t*I!6pD2Gue%Ecck8?n=>u!r80FEyrooGWY{#ANJv)?4G{ue6Jlvld*0Cj=UM#hO zuqoaJVMM?V09J|SppN3Zlg_v^fppI*H^#VWh8rIgEGj8VNg-IB8dhwH`xdWEkvuA> ztlL&K)2j!wFv#-MNz6l72sDh#U|i_T8ZAbt)-Jt^xo2Q|M)aMHOc zIb=;(Ah-;{vs1FE3hulBKY(c5*w5vVaBs%EoVTaUzO32fk3jrOE9CJc3I!l#7k}m< zu|p4wF`smxI(NZuyFPn!M2yZCU7bOyf{}DP)(h-I$@k`~H;=UF$21mA()OMrAN9V3)z)%3F6@*OvR zTf+*;bK^1_C5Leflk9bPghlMzhsM_w+LAA8-i%jIi4yhEV6ivjh}w!cT+!KJrsP;D z=bh22V*iLMv7ysGxN+p}WHVJLH;!;;GCXl^$5aNLeT;^yd;P zWFf*QfHMHi2HrH0x+tbdsiY|9a>T57l=Zpi@O8FD?!%+GR5+eE^=%+=k9iS6-IT%9}XzbOc_Dm$@h#-u$pPu#0&noOFm2?S>0 z<-{byffr`VV#{`2uzUraj?JpMKWp}37|ZRd-D)yBQP*SA)w=ghI;89~=^N!`pxox* zU*J5?IMpCW^~oyl8Uc25qA$ara~BMqKtIW~CjC)%K=7~8vK zJK2}F7GAR;kx%gfWV~KzmrK6Ku(xxmC7qe)J32f}u;{nX@R?#>J-~(QqR3~PW5Zmq zHaY^kkHlvLk2T1E>6<~?9!QD;&jYBQOHs3$qPMYk$4&I&`k(+8H55bz8NIjHZCkf} z{Z=IHFlY-hPW?^IIQ2#EkDjg_?OeFv>=I+X2sQUpZ*0WCj92|FHwrb2jcf%itUwol z=5>pQ4cA84a7|<-`hoWEG;7Tc%R;J55p)N% z_s7y$r>u!e_2kf$9sDPtVh>alpklu^B6E7twuYQh{E!nGd^xTOcjPG+<6+(>SFi7f z=MYj{pbVy!3&>-GHmDh*8$jG*v8VoXj*-ibY9> z{Oqp@)clRk!Az+oHY_RkL}cY^4vT6AX##w+0LWRCw>Sv)GAatF{x%QU&UV_rlHeDD zJ4BALt+;`F%Qi>|j$DGc>R0`|!l!DKFYQd0nz>~x@)>HLAuet}I#`IM%flO@l?Jv} zWYHIy`TSe>!SpU9p3B1zF@7N@xJTpfFN;cBCZBS~IK^p1*h*!y-V-ZnVs-4T2}z*f zMvBFJrnJeW_at1wyF%Bed`d;a9&J&m`3iN0y^~{!M&qI_4GL)s`z|1K~FJZnSz;baegfx-JoW7!-& zL^wwe-k0oiT(n>-X%!CRUUEiwV358#^5@_Vld;kwulT>REE6G9mI+HXERLCudysp|pTd(glH+2VTKBDs^tU91J) zNRC(K7`7K4wcC??v##0Zh=9Gu9`d!Av;7Xw{TE3|o64Iw#BTy@JmT*LHj`UYgU#+h K{3ww;RsR4qeYSJ} delta 1161 zcmZvce@vT27{~A0w{PG6g13F?7>tegeT&jrhv+m})JVhNpcGxqGGnF_CW{u6C3XH& zV_2tXRuwbMxtS$Shx{Q+Mg*D~YIyAkf0=1q9VAXOC3CYFGxH{6zFj*wpLei7Onj5i zd-ptd_r2$N?s7xz(`^&?W6QEkn{ch!bm1pz1{l)!+=_QpsYpNw$qnmt(-Az1-L%~j zz;)?Kj5U{}9fEw%>W;8MM5f1EH zMu#dRViFchWtkv-=k1CoE1s(CM#?UoH6#6t6=ob~q1Z#QbG5^*H!ezTaw62rj1O5L zF{oo}ApU1z2t-ZsZpe=V+5j9BGEU;mzc=OTbVZQcCVNqQZd*#1kbk^3l*E+qC|8@TN6c_p>uaF>dcWF!UFxI`(HT;eF ze4&>AVg8R4YWgm3ha^Tzd{iM@dV}P*0+!ddTvg~{zSVIE zhD~!D{g&U3Tj&bksGJ4g+d#Y{-XRbnQ$yw))(gz|YZc3a#*8`IZa=6b%89HuS{JL* zG3UF0zR{M7$MB=s=aGEA2)980kzTa#OirxIWQSJFR3+@BO7G?TM9J??I756M2fSTd zp&k;$a#3@Is`JmJJduj7f2Ot*U&;}a2{T@2u4rI#EcGBcH^qz-t6RwqSh2Wzt$^gK z1({qapxiJd_X%(s*l&ZVGaT^{Opv^RpmbK4v*LC-;J%DMrO$cx;P&*SXTgFu(4*o9 zxS#sHNALMkLc%HFT@hGsU-cs4yl>6-KJ-7Mv)+C90Im16V3qdxMm+m@B%P18|Fw-UhZ$ed*Q9NDl#WRC_~Z1f^bW3>DZX?~jBZN& zY){^Naa@d|P|NZQ!= sizeof(loopback_rx_buffer) && !cust_vendor_is_receiving(EP_LOOPBACK_RX)) { - + if (n >= sizeof(loopback_rx_buffer) && !cust_vendor_is_receiving(EP_LOOPBACK_RX)) cust_vendor_prepare_recv(EP_LOOPBACK_RX, loopback_rx_buffer, sizeof(loopback_rx_buffer)); +} + + +// --- Echo + +void echo_update_state(void) { + if (num_echos > 0) { + cust_vendor_start_transmit(EP_ECHO_TX, echo_buffer, echo_buffer_len); + } else { + cust_vendor_prepare_recv(EP_ECHO_RX, echo_buffer, sizeof(echo_buffer)); } } @@ -111,7 +122,8 @@ void cust_vendor_rx_cb(uint8_t ep_addr, uint32_t recv_bytes) { } else if (ep_addr == EP_ECHO_RX) { num_echos = 2; - cust_vendor_start_transmit(EP_ECHO_TX, echo_buffer, recv_bytes); + echo_buffer_len = recv_bytes; + echo_update_state(); } } @@ -132,18 +144,14 @@ void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes) { } else if (ep_addr == EP_ECHO_TX) { num_echos--; - if (num_echos > 0) { - cust_vendor_start_transmit(EP_ECHO_TX, echo_buffer, sent_bytes); - } else { - cust_vendor_prepare_recv(EP_ECHO_RX, echo_buffer, sizeof(echo_buffer)); - } + echo_update_state(); } } // Invoked when interface has been opened void cust_vendor_intf_open_cb(uint8_t intf) { loopback_check_rx(); - cust_vendor_prepare_recv(EP_ECHO_RX, echo_buffer, sizeof(echo_buffer)); + echo_update_state(); } // Invoked when an alternate interface has been selected @@ -151,10 +159,29 @@ void cust_vendor_alt_intf_selected_cb(uint8_t intf, uint8_t alt) { reset_buffers(); loopback_check_rx(); if (alt == 0) - cust_vendor_prepare_recv(EP_ECHO_RX, echo_buffer, sizeof(echo_buffer)); + echo_update_state(); } - +void cust_vendor_halt_cleared_cb(uint8_t ep_addr) { + switch (ep_addr) { + case EP_LOOPBACK_RX: + loopback_check_rx(); + break; + case EP_LOOPBACK_TX: + loopback_check_tx(); + break; + case EP_ECHO_RX: + if (num_echos == 0) + echo_update_state(); + break; + case EP_ECHO_TX: + if (num_echos > 0) + echo_update_state(); + break; + default: + break; + } +} // --- Control messages (see README) @@ -217,6 +244,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ return false; } + // --- Device callbacks // Register additional driver @@ -249,6 +277,7 @@ void tud_resume_cb(void) { blink_interval_ms = BLINK_MOUNTED; } + // --- LED blinking --- void led_blinking_task(void) { diff --git a/test-devices/loopback-stm32/include/usb_descriptors.h b/test-devices/loopback-stm32/src/usb_descriptors.h similarity index 100% rename from test-devices/loopback-stm32/include/usb_descriptors.h rename to test-devices/loopback-stm32/src/usb_descriptors.h diff --git a/test-devices/loopback-stm32/src/vendor_custom.c b/test-devices/loopback-stm32/src/vendor_custom.c index 54b9903a..64563de8 100644 --- a/test-devices/loopback-stm32/src/vendor_custom.c +++ b/test-devices/loopback-stm32/src/vendor_custom.c @@ -142,6 +142,14 @@ bool cv_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const cust_vendor_alt_intf_selected_cb((uint8_t) request->wIndex, alt_num); tud_control_status(rhport, request); return true; + + } else if (request->bRequest == TUSB_REQ_CLEAR_FEATURE + && request->wValue == TUSB_REQ_FEATURE_EDPT_HALT + && request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_ENDPOINT + && cust_vendor_halt_cleared_cb != NULL) { + uint8_t const ep_addr = tu_u16_low(request->wIndex); + cust_vendor_halt_cleared_cb(ep_addr); + return true; } return false; diff --git a/test-devices/loopback-stm32/include/vendor_custom.h b/test-devices/loopback-stm32/src/vendor_custom.h similarity index 94% rename from test-devices/loopback-stm32/include/vendor_custom.h rename to test-devices/loopback-stm32/src/vendor_custom.h index d51c9783..556678c8 100644 --- a/test-devices/loopback-stm32/include/vendor_custom.h +++ b/test-devices/loopback-stm32/src/vendor_custom.h @@ -124,6 +124,15 @@ TU_ATTR_WEAK void cust_vendor_intf_open_cb(uint8_t intf); */ TU_ATTR_WEAK void cust_vendor_alt_intf_selected_cb(uint8_t intf, uint8_t alt); +/** + * @brief Invoked when an endpoint's halt condition has been cleared. + * + * This function is called as part of a SET FEATURE control request. + * + * @param ep_addr endpoint address + */ +TU_ATTR_WEAK void cust_vendor_halt_cleared_cb(uint8_t ep_addr); + // --- Driver to be registered in usbd_app_driver_get_cb() From 6d91440d2834108974565ec1459442f95332b583 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 21 Oct 2022 22:09:30 +0200 Subject: [PATCH 124/433] Explicitly stall endpoints for stall test --- .../codecrete/usb/macos/MacosUSBDevice.java | 2 +- .../java/net/codecrete/usb/StallTest.java | 54 ++++++++++--------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 3b2365e9..8f052dac 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -421,7 +421,7 @@ public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { @Override public void clearHalt(USBDirection direction, int endpointNumber) { - var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.IN, + var endpointInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); int ret = IoKitUSB.ClearPipeStallBothEnds(endpointInfo.interfacAddress(), endpointInfo.pipeIndex); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java index b1f59104..9025935f 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java @@ -9,52 +9,56 @@ package net.codecrete.usb; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + public class StallTest extends TestDeviceBase { @Test - void stallOnBulkTransfer_throws() { + void stalledBulkTransferOut_recovers() { + haltEndpoint(USBDirection.OUT, LOOPBACK_EP_OUT); + byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - testDevice.transferOut(LOOPBACK_EP_OUT, data); - Assertions.assertThrows(USBException.class, () -> { - testDevice.transferIn(LOOPBACK_EP_IN, 5); + assertThrows(USBException.class, () -> { + testDevice.transferOut(LOOPBACK_EP_OUT, data); }); - testDevice.clearHalt(USBDirection.IN, LOOPBACK_EP_IN); + testDevice.clearHalt(USBDirection.OUT, LOOPBACK_EP_OUT); + testDevice.transferOut(LOOPBACK_EP_OUT, data); var receivedData = testDevice.transferIn(LOOPBACK_EP_IN, 20); - Assertions.assertArrayEquals(data, receivedData); + assertArrayEquals(data, receivedData); } @Test - void stallOnInterruptTransfer_throws() { - Assumptions.assumeTrue(isLoopbackDevice(), - "Interrupt transfer only supported by loopback test device"); - - byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; - testDevice.transferOut(ECHO_EP_OUT, data); - Assertions.assertThrows(USBException.class, () -> { - testDevice.transferIn(ECHO_EP_IN, 4); - }); + void stalledBulkTransferIn_recovers() { + haltEndpoint(USBDirection.IN, LOOPBACK_EP_IN); - testDevice.clearHalt(USBDirection.IN, ECHO_EP_IN); + assertThrows(USBException.class, () -> { + testDevice.transferIn(LOOPBACK_EP_IN, LOOPBACK_MAX_PACKET_SIZE); + }); - // first echo - var receivedData = testDevice.transferIn(ECHO_EP_IN, 20); - Assertions.assertArrayEquals(data, receivedData); + testDevice.clearHalt(USBDirection.IN, LOOPBACK_EP_IN); - // second echo - receivedData = testDevice.transferIn(ECHO_EP_IN, 20); - Assertions.assertArrayEquals(data, receivedData); + byte[] data = new byte[] { 9, 8, 7, 6, 5, 4, 3, 2 }; + testDevice.transferOut(LOOPBACK_EP_OUT, data); + var receivedData = testDevice.transferIn(LOOPBACK_EP_IN, 20); + assertArrayEquals(data, receivedData); } @Test void invalidControlTransfer_throws() { - Assertions.assertThrows(USBException.class, () -> { + assertThrows(USBException.class, () -> { testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x08, (short) 0, (short) interfaceNumber), 2); }); } + + void haltEndpoint(USBDirection direction, int endpointNumber) { + final int SET_FEATURE = 0x03; + final int ENDPOINT_HALT = 0x00; + int endpointAddress = (direction == USBDirection.IN ? 0x80 : 0x00) | endpointNumber; + testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.STANDARD, USBRecipient.ENDPOINT, SET_FEATURE, ENDPOINT_HALT, endpointAddress), null); + } } From c4abf4db1d944623e7f2d3eda7a7e83effd59d76 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 21 Oct 2022 22:19:11 +0200 Subject: [PATCH 125/433] Clear halt (Windows) --- java-does-usb/jextract/windows/gen_win.cmd | 1 + .../net/codecrete/usb/common/USBDeviceImpl.java | 4 ++-- .../net/codecrete/usb/windows/WindowsUSBDevice.java | 13 +++++++++++-- .../codecrete/usb/windows/gen/winusb/WinUSB.java | 11 +++++++++++ .../usb/windows/gen/winusb/constants$1.java | 8 ++++++++ 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index cd2e2c97..431e8ef8 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -131,6 +131,7 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-function WinUsb_GetAssociatedInterface ^ --include-function WinUsb_SetPipePolicy ^ --include-function WinUsb_SetCurrentAlternateSetting ^ + --include-function WinUsb_ResetPipe ^ --include-macro PIPE_TRANSFER_TIMEOUT ^ windows_headers.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index df35f04a..7d6b246e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -284,14 +284,14 @@ protected void throwInvalidEndpointException(int endpointNumber, USBDirection di direction.name())); } - protected int getInterfaceNumber(int endpointNumber) { + protected int getInterfaceNumber(USBDirection direction, int endpointNumber) { if (endpointNumber < 1 || endpointNumber > 127) return -1; for (var intf : interfaces_) { if (intf.isClaimed()) { for (var ep : intf.alternate().endpoints()) { - if (ep.number() == endpointNumber) + if (ep.number() == endpointNumber && ep.direction() == direction) return intf.number(); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 8d7cf02e..35bce986 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -307,6 +307,14 @@ public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { } } + @Override + public void clearHalt(USBDirection direction, int endpointNumber) { + var endpoint = getEndpoint(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); + var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); + if (WinUSB.WinUsb_ResetPipe(intfHandle.interfaceHandle, endpoint.endpointAddress()) == 0) + throw new WindowsUSBException("Clearing halt failed", Kernel32.GetLastError()); + } + private InterfaceHandle getInterfaceHandle(int interfaceNumber) { for (var intfHandle : interfaceHandles_) { if (intfHandle.interfaceNumber == interfaceNumber) @@ -327,9 +335,10 @@ private InterfaceHandle findControlTransferInterface(USBControlTransfer setup) { } else if (setup.recipient() == USBRecipient.ENDPOINT) { - endpointNumber = setup.index() & 0xff; + endpointNumber = setup.index() & 0x7f; + var direction = (setup.index() & 0x80) != 0 ? USBDirection.IN : USBDirection.OUT; if (endpointNumber != 0) { - interfaceNumber = getInterfaceNumber(endpointNumber); + interfaceNumber = getInterfaceNumber(direction, endpointNumber); if (interfaceNumber == -1) throw new USBException(String.format("Invalid endpoint number %d or interface not claimed", endpointNumber)); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java index 1ad0a068..6c3f0b9f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java @@ -120,6 +120,17 @@ public static int WinUsb_ControlTransfer ( Addressable InterfaceHandle, MemoryS throw new AssertionError("should not reach here", ex$); } } + public static MethodHandle WinUsb_ResetPipe$MH() { + return RuntimeHelper.requireNonNull(constants$1.WinUsb_ResetPipe$MH,"WinUsb_ResetPipe"); + } + public static int WinUsb_ResetPipe ( Addressable InterfaceHandle, byte PipeID) { + var mh$ = WinUsb_ResetPipe$MH(); + try { + return (int)mh$.invokeExact(InterfaceHandle, PipeID); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java index 2c874c1d..a085bc95 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java @@ -49,6 +49,14 @@ class constants$1 { "WinUsb_ControlTransfer", constants$1.WinUsb_ControlTransfer$FUNC ); + static final FunctionDescriptor WinUsb_ResetPipe$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT + ); + static final MethodHandle WinUsb_ResetPipe$MH = RuntimeHelper.downcallHandle( + "WinUsb_ResetPipe", + constants$1.WinUsb_ResetPipe$FUNC + ); } From f2dc4790443869a76c92d5d32ae4f5ac273a4984 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 21 Oct 2022 23:16:01 +0200 Subject: [PATCH 126/433] Clear halt (Linux) --- java-does-usb/jextract/linux/gen_linux.sh | 8 + .../codecrete/usb/common/USBDeviceImpl.java | 5 - .../java/net/codecrete/usb/linux/Linux.java | 16 ++ .../codecrete/usb/linux/LinuxUSBDevice.java | 30 ++- .../usb/linux/LinuxUSBException.java | 23 ++ .../net/codecrete/usb/linux/USBDevFS.java | 2 +- .../usb/linux/gen/string/Constants$root.java | 19 ++ .../usb/linux/gen/string/RuntimeHelper.java | 216 ++++++++++++++++++ .../usb/linux/gen/string/constants$0.java | 18 ++ .../usb/linux/gen/string/string.java | 33 +++ 10 files changed, 356 insertions(+), 14 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/RuntimeHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index 69c26c84..4743e3e7 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -18,6 +18,13 @@ $JEXTRACT --source --output ../../src/main/java \ --include-macro ETIMEDOUT \ /usr/include/errno.h +# string.h +$JEXTRACT --source --output ../../src/main/java \ + --header-class-name string \ + --target-package net.codecrete.usb.linux.gen.string \ + --include-function strerror \ + /usr/include/string.h + # ioctl.h $JEXTRACT --source --output ../../src/main/java \ --header-class-name ioctl \ @@ -54,6 +61,7 @@ $JEXTRACT --source --output ../../src/main/java \ --include-macro USBDEVFS_CLAIMINTERFACE \ --include-macro USBDEVFS_RELEASEINTERFACE \ --include-macro USBDEVFS_SETINTERFACE \ + --include-macro USBDEVFS_CLEAR_HALT \ /usr/include/linux/usbdevice_fs.h # libudev.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 7d6b246e..7d9c06ef 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -322,11 +322,6 @@ public byte[] transferIn(int endpointNumber, int maxLength) { @Override public abstract byte[] transferIn(int endpointNumber, int maxLength, int timeout); - @Override - public void clearHalt(USBDirection direction, int endpointNumber) { - throw new IllegalStateException("not implemented"); - } - @Override public OutputStream openOutputStream(int endpointNumber) { // check that endpoint number is valid diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java index 8d759c0e..18f3d536 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java @@ -7,6 +7,8 @@ package net.codecrete.usb.linux; +import net.codecrete.usb.linux.gen.string.string; + import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySession; @@ -33,4 +35,18 @@ public static String createStringFromAddress(MemoryAddress str) { return ret.getUtf8String(0); } } + + /** + * Gets the error message for the specified error code (returned by {@code errno}). + * + * @param err error code + * @return error message + */ + public static String getErrorMessage(int err) { + try (var session = MemorySession.openConfined()) { + var messageAddr = string.strerror(err); + var message = MemorySegment.ofAddress(messageAddr, 4000, session); + return message.getUtf8String(0); + } + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index f1d87790..7d7b04eb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -78,7 +78,7 @@ public void open() { var pathUtf8 = session.allocateUtf8String(id_.toString()); fd = fcntl.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC()); if (fd == -1) - throw new USBException("Cannot open USB device", IO.getErrno()); + throw new LinuxUSBException("Cannot open USB device", IO.getErrno()); } } @@ -107,7 +107,7 @@ public void claimInterface(int interfaceNumber) { var intfNumSegment = session.allocate(JAVA_INT, interfaceNumber); int ret = ioctl.ioctl(fd, USBDevFS.CLAIMINTERFACE, intfNumSegment.address()); if (ret != 0) - throw new USBException("Cannot claim USB interface", IO.getErrno()); + throw new LinuxUSBException("Cannot claim USB interface", IO.getErrno()); setClaimed(interfaceNumber, true); } } @@ -134,7 +134,7 @@ public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { usbdevfs_setinterface.altsetting$set(setIntfSegment, alternateNumber); int ret = ioctl.ioctl(fd, USBDevFS.SETINTERFACE, setIntfSegment.address()); if (ret != 0) - throw new USBException("Failed to set alternate interface", IO.getErrno()); + throw new LinuxUSBException("Failed to set alternate interface", IO.getErrno()); } intf.setAlternate(altSetting); @@ -153,7 +153,7 @@ public void releaseInterface(int interfaceNumber) { var intfNumSegment = session.allocate(JAVA_INT, interfaceNumber); int ret = ioctl.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment.address()); if (ret != 0) - throw new USBException("Cannot release USB interface", IO.getErrno()); + throw new LinuxUSBException("Cannot release USB interface", IO.getErrno()); setClaimed(interfaceNumber, false); } } @@ -180,7 +180,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { int res = ioctl.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer.address()); if (res < 0) - throw new USBException("Control IN transfer failed", IO.getErrno()); + throw new LinuxUSBException("Control IN transfer failed", IO.getErrno()); return data.asSlice(0, res).toArray(JAVA_BYTE); } @@ -197,7 +197,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { int res = ioctl.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer.address()); if (res < 0) - throw new USBException("Control OUT transfer failed", IO.getErrno()); + throw new LinuxUSBException("Control OUT transfer failed", IO.getErrno()); } } @@ -225,7 +225,7 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { int err = IO.getErrno(); if (err == errno.ETIMEDOUT()) throw new TimeoutException("Transfer out aborted due to timeout"); - throw new USBException(String.format("USB OUT transfer on endpoint %d failed", endpointNumber), err); + throw new LinuxUSBException(String.format("USB OUT transfer on endpoint %d failed", endpointNumber), err); } } } @@ -245,10 +245,24 @@ public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { int err = IO.getErrno(); if (err == errno.ETIMEDOUT()) throw new TimeoutException("Transfer in aborted due to timeout"); - throw new USBException(String.format("USB IN transfer on endpoint %d failed", endpointNumber), err); + throw new LinuxUSBException(String.format("USB IN transfer on endpoint %d failed", endpointNumber), err); } return buffer.asSlice(0, res).toArray(JAVA_BYTE); } } + + @Override + public void clearHalt(USBDirection direction, int endpointNumber) { + var endpointAddress = getEndpointAddress(endpointNumber, direction, + USBTransferType.BULK, USBTransferType.INTERRUPT); + + try (var session = MemorySession.openConfined()) { + var endpointAddrSegment = session.allocate(JAVA_INT, endpointAddress & 0xff); + int res = ioctl.ioctl(fd, USBDevFS.CLEAR_HALT, endpointAddrSegment.address()); + if (res < 0) + throw new LinuxUSBException("Clearing halt failed", IO.getErrno()); + } + } + } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java new file mode 100644 index 00000000..94f969df --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java @@ -0,0 +1,23 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +package net.codecrete.usb.linux; + +import net.codecrete.usb.USBException; + +public class LinuxUSBException extends USBException { + public LinuxUSBException(String message) { + super(message); + } + + public LinuxUSBException(String message, int errorCode) { + super(String.format("%s - %s", message, Linux.getErrorMessage(errorCode)), errorCode); + } + + public LinuxUSBException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java index cf74b496..5c0bd3fc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java @@ -16,6 +16,6 @@ public class USBDevFS { public static final long BULK = 0xc0185502; public static final long CLAIMINTERFACE = 0x8004550F; public static final long RELEASEINTERFACE = 0x80045510; - public static final long SETINTERFACE = 0x80085504; + public static final long CLEAR_HALT = 0x80045515; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/Constants$root.java new file mode 100644 index 00000000..93e06058 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/Constants$root.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.string; + +import static java.lang.foreign.ValueLayout.*; +public class Constants$root { + + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); + static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); + static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/RuntimeHelper.java new file mode 100644 index 00000000..6314d452 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/RuntimeHelper.java @@ -0,0 +1,216 @@ +package net.codecrete.usb.linux.gen.string; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private RuntimeHelper() {} + private final static Linker LINKER = Linker.nativeLinker(); + private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private final static SymbolLookup SYMBOL_LOOKUP; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + + static { + + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + } + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + } + + static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.lookup(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, session); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + } + + // Internals only below this point + + private static class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + if (mtype.returnType().equals(MemorySegment.class)) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return (ret || valueLayout.carrier() != MemoryAddress.class) ? + valueLayout.carrier() : Addressable.class; + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + if (mh.type().returnType() == MemorySegment.class) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (MemoryAddress.class.isAssignableFrom(c)) { + return MemoryAddress.class; + } + if (MemorySegment.class.isAssignableFrom(c)) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (MemoryAddress.class.isAssignableFrom(c)) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/constants$0.java new file mode 100644 index 00000000..1953dd0d --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/constants$0.java @@ -0,0 +1,18 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.string; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +class constants$0 { + + static final FunctionDescriptor strerror$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle strerror$MH = RuntimeHelper.downcallHandle( + "strerror", + constants$0.strerror$FUNC + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java new file mode 100644 index 00000000..37dcf414 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java @@ -0,0 +1,33 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.string; + +import java.lang.foreign.MemoryAddress; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.*; +public class string { + + /* package-private */ string() {} + public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static MethodHandle strerror$MH() { + return RuntimeHelper.requireNonNull(constants$0.strerror$MH,"strerror"); + } + public static MemoryAddress strerror ( int __errnum) { + var mh$ = strerror$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(__errnum); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } +} + + From 02594a905122091e5d9ebb4bbfd3178ceed96269 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 21 Oct 2022 23:19:02 +0200 Subject: [PATCH 127/433] Update progress information --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 39423b3d..d37de01b 100644 --- a/README.md +++ b/README.md @@ -27,17 +27,16 @@ It has been tested with Azul Zulu 19.0.77 EA 34. - Control, bulk and interrupt transfers (optionally with timeout) - Notifications about connected/disconnected devices - Descriptive information about interfaces, settings and endpoints -- Support fo composite devices and interface association +- Support for alternate interface settings, composite devices and interface association - Published on Maven Central ### To do -- Alternate interface settings - Isochronous transfer ### Not planned -- Changing configuration: The library selects the first configuration. Changing configurations is rarely used and not supported on Windows. +- Changing configuration: The library selects the first configuration. Changing configurations is rarely used and not supported on Windows (limitation of WinUSB). - USB 3.0 streams: Not supported on Windows (limitation of WinUSB). - Providing information about USB buses, controllers and hubs From 9ee5439c99509b9860904d42a91bccc9199b820e Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 22 Oct 2022 11:13:04 +0200 Subject: [PATCH 128/433] Refactor macOS exceptions --- java-does-usb/jextract/macos/gen_macos.sh | 1 + .../java/net/codecrete/usb/USBDevice.java | 4 +- .../net/codecrete/usb/USBStallException.java | 30 ++++ ...xception.java => USBTimeoutException.java} | 4 +- .../java/net/codecrete/usb/linux/Linux.java | 6 +- .../codecrete/usb/linux/LinuxUSBDevice.java | 4 +- .../codecrete/usb/macos/MacosUSBDevice.java | 165 ++++++------------ .../usb/macos/MacosUSBDeviceRegistry.java | 5 +- .../usb/macos/MacosUSBException.java | 20 ++- .../codecrete/usb/macos/TransferTimeout.java | 67 +++++++ .../codecrete/usb/macos/gen/iokit/IOKit.java | 3 + .../usb/windows/WindowsUSBDevice.java | 4 +- .../java/net/codecrete/usb/StallTest.java | 6 +- .../net/codecrete/usb/TestDeviceBase.java | 4 +- .../java/net/codecrete/usb/TimeoutTest.java | 8 +- 15 files changed, 194 insertions(+), 137 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/USBStallException.java rename java-does-usb/src/main/java/net/codecrete/usb/{TimeoutException.java => USBTimeoutException.java} (77%) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index 7a87c055..034c2af1 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -59,6 +59,7 @@ $JEXTRACT --source --output ../../src/main/java \ --include-typedef IOUSBInterfaceInterface \ --include-macro kIOUSBTransactionTimeout \ --include-macro kIOReturnAborted \ + --include-macro kIOUSBPipeStalled \ iokit_helper.h # mach.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index 686c7780..bd54417a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -215,7 +215,7 @@ public interface USBDevice { * Sends data to this device. *

* This method blocks until the data has been sent, the timeout period has expired - * or an error has occurred. If the timeout expires, a {@link TimeoutException} is thrown. + * or an error has occurred. If the timeout expires, a {@link USBTimeoutException} is thrown. *

*

* This method can send data to bulk and interrupt endpoints. @@ -247,7 +247,7 @@ public interface USBDevice { * Receives data from this device. *

* This method blocks until at least a packet has been received, the timeout period has expired - * or an error has occurred. If the timeout expired, a {@link TimeoutException} is thrown. + * or an error has occurred. If the timeout expired, a {@link USBTimeoutException} is thrown. *

*

* {@code maxLength} must be long enough to hold the full data packet transmitted by the device. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBStallException.java b/java-does-usb/src/main/java/net/codecrete/usb/USBStallException.java new file mode 100644 index 00000000..2b986a23 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBStallException.java @@ -0,0 +1,30 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb; + +/** + * Exception thrown if a communication on a USB endpoint failed. + *

+ * If a USB endpoint stalls, it is halted and the halt condition must be cleared + * using {@link USBDevice#clearHalt(USBDirection, int)} before communication can resume. + *

+ *

+ * If the control endpoint 0 stalls, it throws this exception but is not halted. + *

+ */ +public class USBStallException extends USBException { + + /** + * Creates a new instance with a message. + * + * @param message the message + */ + public USBStallException(String message) { + super(message); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/TimeoutException.java b/java-does-usb/src/main/java/net/codecrete/usb/USBTimeoutException.java similarity index 77% rename from java-does-usb/src/main/java/net/codecrete/usb/TimeoutException.java rename to java-does-usb/src/main/java/net/codecrete/usb/USBTimeoutException.java index 2b17a751..3b18558f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/TimeoutException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBTimeoutException.java @@ -10,14 +10,14 @@ /** * Exception thrown if a USB operation times out. */ -public class TimeoutException extends USBException { +public class USBTimeoutException extends USBException { /** * Creates a new instance with a message. * * @param message the message */ - public TimeoutException(String message) { + public USBTimeoutException(String message) { super(message); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java index 18f3d536..8c6723f6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java @@ -43,10 +43,6 @@ public static String createStringFromAddress(MemoryAddress str) { * @return error message */ public static String getErrorMessage(int err) { - try (var session = MemorySession.openConfined()) { - var messageAddr = string.strerror(err); - var message = MemorySegment.ofAddress(messageAddr, 4000, session); - return message.getUtf8String(0); - } + return string.strerror(err).getUtf8String(0); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 7d7b04eb..3f53e5cc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -224,7 +224,7 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { if (res < 0) { int err = IO.getErrno(); if (err == errno.ETIMEDOUT()) - throw new TimeoutException("Transfer out aborted due to timeout"); + throw new USBTimeoutException("Transfer out aborted due to timeout"); throw new LinuxUSBException(String.format("USB OUT transfer on endpoint %d failed", endpointNumber), err); } } @@ -244,7 +244,7 @@ public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { if (res < 0) { int err = IO.getErrno(); if (err == errno.ETIMEDOUT()) - throw new TimeoutException("Transfer in aborted due to timeout"); + throw new USBTimeoutException("Transfer in aborted due to timeout"); throw new LinuxUSBException(String.format("USB IN transfer on endpoint %d failed", endpointNumber), err); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 8f052dac..a7b0a489 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -21,13 +21,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; import static java.lang.foreign.MemoryAddress.ofLong; import static java.lang.foreign.ValueLayout.*; +import static net.codecrete.usb.macos.MacosUSBException.throwException; public class MacosUSBDevice extends USBDeviceImpl { @@ -36,8 +33,6 @@ public class MacosUSBDevice extends USBDeviceImpl { private List claimedInterfaces; private Map endpoints; - private ScheduledExecutorService scheduledExecutorService; - MacosUSBDevice(MemoryAddress device, Object id, int vendorId, int productId) { super(id, vendorId, productId); this.device = device; @@ -55,17 +50,17 @@ public boolean isOpen() { @Override public void open() { if (isOpen()) - throw new USBException("the device is already open"); + throwException("the device is already open"); // open device int ret = IoKitUSB.USBDeviceOpen(device); if (ret != 0) - throw new MacosUSBException("unable to open USB device", ret); + throwException(ret, "unable to open USB device"); // set configuration ret = IoKitUSB.SetConfiguration(device, (byte) configurationValue); if (ret != 0) - throw new MacosUSBException("failed to set configuration", ret); + throwException(ret, "failed to set configuration"); claimedInterfaces = new ArrayList<>(); updateEndpointList(); @@ -95,27 +90,23 @@ void closeFully() { private void loadDescription() { try (var session = MemorySession.openConfined()) { - try { - // retrieve information of first configuration - var descPtrHolder = session.allocate(ADDRESS); - int ret = IoKitUSB.GetConfigurationDescriptorPtr(device, (byte) 0, descPtrHolder.address()); - if (ret != 0) - throw new MacosUSBException("failed to query first configuration", ret); + configurationValue = 0; - // get value of first configuration - var configDescHeader = new ConfigurationDescriptor(MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), - ConfigurationDescriptor.LAYOUT.byteSize(), session)); - int totalLength = configDescHeader.totalLength(); - var configDesc = MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), - totalLength, session); + // retrieve information of first configuration + var descPtrHolder = session.allocate(ADDRESS); + int ret = IoKitUSB.GetConfigurationDescriptorPtr(device, (byte) 0, descPtrHolder.address()); + if (ret != 0) + throwException(ret, "failed to query first configuration"); - var configuration = setConfigurationDescriptor(configDesc); - configurationValue = 255 & configuration.configValue(); + // get value of first configuration + var configDescHeader = new ConfigurationDescriptor(MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), + ConfigurationDescriptor.LAYOUT.byteSize(), session)); + int totalLength = configDescHeader.totalLength(); + var configDesc = MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), + totalLength, session); - } catch (Throwable e) { - configurationValue = 0; - throw e; - } + var configuration = setConfigurationDescriptor(configDesc); + configurationValue = 255 & configuration.configValue(); } } @@ -131,7 +122,8 @@ private InterfaceInfo findInterface(int interfaceNumber) { var iterHolder = outerSession.allocate(JAVA_INT); int ret = IoKitUSB.CreateInterfaceIterator(device, request.address(), iterHolder.address()); final var iter = iterHolder.get(JAVA_INT, 0); - if (ret != 0) throw new RuntimeException("CreateInterfaceIterator failed"); + if (ret != 0) + throwException("CreateInterfaceIterator failed"); outerSession.addCloseAction(() -> IOKit.IOObjectRelease(iter)); int service; @@ -157,7 +149,8 @@ private InterfaceInfo findInterface(int interfaceNumber) { } } - throw new MacosUSBException(String.format("Invalid interface number: %d", interfaceNumber)); + throwException("Invalid interface number: %d", interfaceNumber); + throw new AssertionError("not reached"); } public void claimInterface(int interfaceNumber) { @@ -168,7 +161,7 @@ public void claimInterface(int interfaceNumber) { try { var ret = IoKitUSB.USBInterfaceOpen(interfaceInfo.asAddress()); if (ret != 0) - throw new MacosUSBException("Failed to claim interface", ret); + throwException(ret, "Failed to claim interface"); setClaimed(interfaceNumber, true); } catch (Throwable t) { @@ -185,22 +178,21 @@ public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { // check interface var intf = getInterface(interfaceNumber); if (intf == null) - throw new MacosUSBException(String.format("Interface %d does not exist", interfaceNumber)); + throwException("Interface %d does not exist", interfaceNumber); if (!intf.isClaimed()) - throw new MacosUSBException(String.format("Interface %d has not been claimed", interfaceNumber)); + throwException("Interface %d has not been claimed", interfaceNumber); // check alternate setting var altSetting = intf.getAlternate(alternateNumber); if (altSetting == null) - throw new MacosUSBException(String.format("Interface %d does not have an alternate interface setting %d", - interfaceNumber, alternateNumber)); + throwException("Interface %d does not have an alternate interface setting %d", interfaceNumber, alternateNumber); var intfInfo = claimedInterfaces.stream() .filter((interf) -> interf.interfaceNumber() == interfaceNumber).findFirst().get(); int ret = IoKitUSB.SetAlternateInterface(intfInfo.asAddress(), (byte) alternateNumber); if (ret != 0) - throw new MacosUSBException("Failed to set alternate interface", ret); + throwException(ret, "Failed to set alternate interface"); intf.setAlternate(altSetting); updateEndpointList(); @@ -212,13 +204,13 @@ public void releaseInterface(int interfaceNumber) { var interfaceInfoOptional = claimedInterfaces.stream().filter(info -> info.interfaceNumber == interfaceNumber).findFirst(); if (interfaceInfoOptional.isEmpty()) - throw new MacosUSBException(String.format("Invalid interface number: %d", interfaceNumber)); + throwException("Invalid interface number: %d", interfaceNumber); var interfaceInfo = interfaceInfoOptional.get(); int ret = IoKitUSB.USBInterfaceClose(interfaceInfo.asAddress()); if (ret != 0) - throw new MacosUSBException("Failed to release interface", ret); + throwException(ret, "Failed to release interface"); claimedInterfaces.remove(interfaceInfo); IoKitUSB.Release(interfaceInfo.asAddress()); @@ -244,7 +236,7 @@ private void updateEndpointList() { var numEndpointsHolder = session.allocate(JAVA_BYTE); int ret = IoKitUSB.GetNumEndpoints(intf, numEndpointsHolder.address()); if (ret != 0) - throw new MacosUSBException("Failed to get number of endpoints", ret); + throwException(ret, "Failed to get number of endpoints"); int numEndpoints = numEndpointsHolder.get(JAVA_BYTE, 0) & 255; for (int pipeIndex = 1; pipeIndex <= numEndpoints; pipeIndex++) { @@ -258,7 +250,8 @@ private void updateEndpointList() { ret = IoKitUSB.GetPipeProperties(intf, (byte) pipeIndex, directionHolder.address(), numberHolder.address(), transferTypeHolder.address(), maxPacketSizeHolder.address(), intervalHolder.address()); - if (ret != 0) throw new MacosUSBException("Failed to get pipe properties", ret); + if (ret != 0) + throwException(ret, "Failed to get pipe properties"); int endpointNumber = numberHolder.get(JAVA_BYTE, 0) & 255; int direction = directionHolder.get(JAVA_BYTE, 0) & 255; @@ -286,9 +279,11 @@ private EndpointInfo getEndpointInfo(int endpointNumber, USBDirection direction, transferTypeDesc = transferType1.name(); else transferTypeDesc = String.format("%s or %s", transferType1.name(), transferType2.name()); - throw new USBException(String.format("Endpoint number %d does not exist, is not part of a claimed interface " + - "or is not valid for %s transfer in %s direction", endpointNumber, transferTypeDesc, - direction.name())); + + throwException( + "Endpoint number %d does not exist, is not part of a claimed interface or is not valid for %s transfer in %s direction", + endpointNumber, transferTypeDesc, direction.name()); + throw new AssertionError("not reached"); } private static MemorySegment createDeviceRequest(MemorySession session, USBDirection direction, @@ -314,7 +309,8 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { var deviceRequest = createDeviceRequest(session, USBDirection.IN, setup, data); int ret = IoKitUSB.DeviceRequest(device, deviceRequest.address()); - if (ret != 0) throw new MacosUSBException("Control IN transfer failed", ret); + if (ret != 0) + throwException(ret, "Control IN transfer failed"); int lenDone = IOUSBDevRequest.wLenDone$get(deviceRequest); return data.asSlice(0, lenDone).toArray(JAVA_BYTE); @@ -332,7 +328,8 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { var deviceRequest = createDeviceRequest(session, USBDirection.OUT, setup, dataSegment); int ret = IoKitUSB.DeviceRequest(device, deviceRequest.address()); - if (ret != 0) throw new MacosUSBException("Control IN transfer failed", ret); + if (ret != 0) + throwException(ret, "Control IN transfer failed"); } } @@ -349,28 +346,28 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { if (timeout <= 0) { // transfer without timeout - ret = IoKitUSB.WritePipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), data.length); + ret = IoKitUSB.WritePipe(endpointInfo.interfaceAddress(), endpointInfo.pipeIndex, nativeData.address(), data.length); } else if (endpointInfo.transferType == USBTransferType.BULK) { // bulk transfer with timeout - ret = IoKitUSB.WritePipeTO(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), + ret = IoKitUSB.WritePipeTO(endpointInfo.interfaceAddress(), endpointInfo.pipeIndex, nativeData.address(), data.length, timeout, timeout); if (ret == IOKit.kIOUSBTransactionTimeout()) - throw new TimeoutException("Transfer out aborted due to timeout"); + throw new USBTimeoutException("Transfer out aborted due to timeout"); } else { // interrupt transfer with timeout var transferTimeout = new TransferTimeout(endpointInfo, timeout); - ret = IoKitUSB.WritePipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), data.length); + ret = IoKitUSB.WritePipe(endpointInfo.interfaceAddress(), endpointInfo.pipeIndex, nativeData.address(), data.length); if (ret == IOKit.kIOReturnAborted()) - throw new TimeoutException("Transfer out aborted due to timeout"); + throw new USBTimeoutException("Transfer out aborted due to timeout"); transferTimeout.markCompleted(); } if (ret != 0) - throw new MacosUSBException(String.format("Sending data to endpoint %d failed", endpointNumber), ret); + throwException(ret, "Sending data to endpoint %d failed", endpointNumber); } } @@ -387,28 +384,27 @@ public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { if (timeout <= 0) { // transfer without timeout - ret = IoKitUSB.ReadPipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), sizeHolder.address()); + ret = IoKitUSB.ReadPipe(endpointInfo.interfaceAddress(), endpointInfo.pipeIndex, nativeData.address(), sizeHolder.address()); } else if (endpointInfo.transferType == USBTransferType.BULK) { // bulk transfer with timeout - ret = IoKitUSB.ReadPipeTO(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), + ret = IoKitUSB.ReadPipeTO(endpointInfo.interfaceAddress(), endpointInfo.pipeIndex, nativeData.address(), sizeHolder.address(), timeout, timeout); if (ret == IOKit.kIOUSBTransactionTimeout()) - throw new TimeoutException("Transfer in aborted due to timeout"); + throw new USBTimeoutException("Transfer in aborted due to timeout"); } else { // interrupt transfer with timeout var transferTimeout = new TransferTimeout(endpointInfo, timeout); - ret = IoKitUSB.ReadPipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex, nativeData.address(), sizeHolder.address()); + ret = IoKitUSB.ReadPipe(endpointInfo.interfaceAddress(), endpointInfo.pipeIndex, nativeData.address(), sizeHolder.address()); if (ret == IOKit.kIOReturnAborted()) - throw new TimeoutException("Transfer in aborted due to timeout"); + throw new USBTimeoutException("Transfer in aborted due to timeout"); transferTimeout.markCompleted(); } if (ret != 0) - throw new MacosUSBException(String.format("Receiving data from endpoint %d failed", endpointNumber), - ret); + throwException(ret, "Receiving data from endpoint %d failed", endpointNumber); int size = sizeHolder.get(JAVA_INT, 0); var result = new byte[size]; @@ -424,15 +420,9 @@ public void clearHalt(USBDirection direction, int endpointNumber) { var endpointInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); - int ret = IoKitUSB.ClearPipeStallBothEnds(endpointInfo.interfacAddress(), endpointInfo.pipeIndex); + int ret = IoKitUSB.ClearPipeStallBothEnds(endpointInfo.interfaceAddress(), endpointInfo.pipeIndex); if (ret != 0) - throw new MacosUSBException("Clearing halt condition failed", ret); - } - - synchronized ScheduledExecutorService getScheduledExecutorService() { - if (scheduledExecutorService == null) - scheduledExecutorService = Executors.newScheduledThreadPool(1); - return scheduledExecutorService; + throwException(ret, "Clearing halt condition failed"); } private static USBTransferType getTransferType(byte macosTransferType) { @@ -451,51 +441,8 @@ MemoryAddress asAddress() { } record EndpointInfo(long interfaceAddr, byte pipeIndex, USBTransferType transferType) { - MemoryAddress interfacAddress() { + MemoryAddress interfaceAddress() { return ofLong(interfaceAddr); } } - - /** - * Manages the timeout for a USB transfer. - *

- * Not used for bulk transfers as IOKit offers suitable functions ({@code WritePipeTO()}, {@code ReadPipeTO()}). - *

- */ - class TransferTimeout { - /** - * Schedules a timeout for the specified endpoint. - *

- * If the timeout expires, the transfer is aborted. - *

- * @param endpointInfo endpoint information - * @param timeout timeout, in milliseconds - */ - TransferTimeout(EndpointInfo endpointInfo, int timeout) { - this.endpointInfo = endpointInfo; - future = getScheduledExecutorService().schedule(this::abort, timeout, TimeUnit.MILLISECONDS); - } - - private synchronized void abort() { - if (completed) - return; - int ret = IoKitUSB.AbortPipe(endpointInfo.interfacAddress(), endpointInfo.pipeIndex()); - if (ret != 0) - throw new MacosUSBException("Failed to abort USB transfer after timeout", ret); - } - - /** - * Marks the transfer as completed and cancels the timeout. - */ - synchronized void markCompleted() { - if (completed) - return; - completed = true; - future.cancel(false); - } - - ScheduledFuture future; - EndpointInfo endpointInfo; - boolean completed; - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index c9848989..327d650d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -21,6 +21,7 @@ import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.*; +import static net.codecrete.usb.macos.MacosUSBException.throwException; /** * MacOS implementation of USB device registry. @@ -102,7 +103,7 @@ private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { var entryIdHolder = session.allocate(JAVA_LONG); int ret = IOKit.IORegistryEntryGetRegistryEntryID(service, entryIdHolder); if (ret != 0) - throw new MacosUSBException("IORegistryEntryGetRegistryEntryID failed", ret); + throwException(ret, "IORegistryEntryGetRegistryEntryID failed"); var entryId = entryIdHolder.get(JAVA_LONG, 0); // call consumer to process device @@ -189,7 +190,7 @@ private int setupNotification(MemorySession session, MemoryAddress notifyPort, M int ret = IOKit.IOServiceAddMatchingNotification(notifyPort, notificationType, matchingDict, onDeviceCallbackStub, NULL, deviceIterHolder); if (ret != 0) - throw new MacosUSBException("IOServiceAddMatchingNotification failed", ret); + throwException(ret, "IOServiceAddMatchingNotification failed"); return deviceIterHolder.get(JAVA_INT, 0); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java index 3d59df8d..60b3d85e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java @@ -7,6 +7,8 @@ package net.codecrete.usb.macos; import net.codecrete.usb.USBException; +import net.codecrete.usb.USBStallException; +import net.codecrete.usb.macos.gen.iokit.IOKit; import net.codecrete.usb.macos.gen.mach.mach; public class MacosUSBException extends USBException { @@ -18,12 +20,22 @@ public MacosUSBException(String message, int errorCode) { super(String.format("%s - %s", message, machErrorMessage(errorCode)), errorCode); } - public MacosUSBException(String message, Throwable cause) { - super(message, cause); - } - private static String machErrorMessage(int errorCode) { var msg = mach.mach_error_string(errorCode); return msg.getUtf8String(0); } + + static void throwException(int errorCode, String message, Object... args) { + var formattedMessage = String.format(message, args); + if (errorCode == IOKit.kIOUSBPipeStalled()) { + throw new USBStallException(formattedMessage); + } else { + throw new MacosUSBException(formattedMessage, errorCode); + } + } + + static void throwException(String message, Object... args) { + throw new MacosUSBException(String.format(message, args)); + } + } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java new file mode 100644 index 00000000..edc3d465 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java @@ -0,0 +1,67 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.macos; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import static net.codecrete.usb.macos.MacosUSBException.throwException; + +/** + * Manages the timeout for a USB transfer. + *

+ * Not used for bulk transfers as IOKit offers suitable functions ({@code WritePipeTO()}, {@code ReadPipeTO()}). + *

+ */ +class TransferTimeout { + /** + * Schedules a timeout for the specified endpoint. + *

+ * If the timeout expires, the transfer is aborted. + *

+ * + * @param endpointInfo endpoint information + * @param timeout timeout, in milliseconds + */ + TransferTimeout(MacosUSBDevice.EndpointInfo endpointInfo, int timeout) { + this.endpointInfo = endpointInfo; + future = getScheduledExecutorService().schedule(this::abort, timeout, TimeUnit.MILLISECONDS); + } + + private synchronized void abort() { + if (completed) + return; + int ret = IoKitUSB.AbortPipe(endpointInfo.interfaceAddress(), endpointInfo.pipeIndex()); + if (ret != 0) + throwException(ret, "Failed to abort USB transfer after timeout"); + } + + /** + * Marks the transfer as completed and cancels the timeout. + */ + synchronized void markCompleted() { + if (completed) + return; + completed = true; + future.cancel(false); + } + + static synchronized ScheduledExecutorService getScheduledExecutorService() { + if (scheduledExecutorService == null) + scheduledExecutorService = Executors.newScheduledThreadPool(1); + return scheduledExecutorService; + } + + ScheduledFuture future; + MacosUSBDevice.EndpointInfo endpointInfo; + boolean completed; + + private static ScheduledExecutorService scheduledExecutorService; +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java index b5ab2e35..ecfae851 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java @@ -156,6 +156,9 @@ public static int IOCreatePlugInInterfaceForService ( int service, Addressable public static int kIOReturnAborted() { return (int)-536870165L; } + public static int kIOUSBPipeStalled() { + return (int)-536854449L; + } public static int kIOUSBTransactionTimeout() { return (int)-536854447L; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 35bce986..71543e59 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -270,7 +270,7 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { lengthHolder, NULL) == 0) { int err = Kernel32.GetLastError(); if (err == Kernel32.ERROR_SEM_TIMEOUT()) - throw new TimeoutException("Transfer out aborted due to timeout"); + throw new USBTimeoutException("Transfer out aborted due to timeout"); throw new WindowsUSBException("Bulk/interrupt transfer OUT failed", err); } } @@ -297,7 +297,7 @@ public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { lengthHolder, NULL) == 0) { int err = Kernel32.GetLastError(); if (err == Kernel32.ERROR_SEM_TIMEOUT()) - throw new TimeoutException("Transfer in aborted due to timeout"); + throw new USBTimeoutException("Transfer in aborted due to timeout"); throw new WindowsUSBException("Bulk/interrupt transfer IN failed", err); } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java index 9025935f..64cfb93f 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java @@ -21,7 +21,7 @@ void stalledBulkTransferOut_recovers() { haltEndpoint(USBDirection.OUT, LOOPBACK_EP_OUT); byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - assertThrows(USBException.class, () -> { + assertThrows(USBStallException.class, () -> { testDevice.transferOut(LOOPBACK_EP_OUT, data); }); @@ -36,7 +36,7 @@ void stalledBulkTransferOut_recovers() { void stalledBulkTransferIn_recovers() { haltEndpoint(USBDirection.IN, LOOPBACK_EP_IN); - assertThrows(USBException.class, () -> { + assertThrows(USBStallException.class, () -> { testDevice.transferIn(LOOPBACK_EP_IN, LOOPBACK_MAX_PACKET_SIZE); }); @@ -50,7 +50,7 @@ void stalledBulkTransferIn_recovers() { @Test void invalidControlTransfer_throws() { - assertThrows(USBException.class, () -> { + assertThrows(USBStallException.class, () -> { testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x08, (short) 0, (short) interfaceNumber), 2); }); } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index 9aab941c..b5ff79c4 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -109,7 +109,7 @@ private static void resetDevice() { while (true) { try { testDevice.transferIn(LOOPBACK_EP_IN, LOOPBACK_MAX_PACKET_SIZE, 1); - } catch (TimeoutException e) { + } catch (USBTimeoutException e) { break; } } @@ -119,7 +119,7 @@ private static void resetDevice() { while (true) { try { testDevice.transferIn(ECHO_EP_IN, ECHO_MAX_PACKET_SIZE, 1); - } catch (TimeoutException e) { + } catch (USBTimeoutException e) { break; } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java index 5c6701db..dbd89a27 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java @@ -23,7 +23,7 @@ public class TimeoutTest extends TestDeviceBase { @Test @Timeout(value = 1, unit = TimeUnit.SECONDS) void bulkTransferIn_timesOut() { - assertThrows(TimeoutException.class, () -> { + assertThrows(USBTimeoutException.class, () -> { testDevice.transferIn(LOOPBACK_EP_IN, 64, 200); }); } @@ -48,7 +48,7 @@ void bulkTransferOut_timesOut() { byte[] data = generateRandomBytes(100, 9383073929L); testDevice.transferOut(LOOPBACK_EP_OUT, data, 200); - assertThrows(TimeoutException.class, () -> { + assertThrows(USBTimeoutException.class, () -> { for (int i = 0; i < 10; i++) { testDevice.transferOut(LOOPBACK_EP_OUT, data, 200); } @@ -58,7 +58,7 @@ void bulkTransferOut_timesOut() { while (true) { try { testDevice.transferIn(LOOPBACK_EP_IN, 64, 200); - } catch (TimeoutException e) { + } catch (USBTimeoutException e) { break; } } @@ -70,7 +70,7 @@ void interruptTransferIn_timesOut() { Assumptions.assumeTrue(isLoopbackDevice(), "Interrupt transfer only supported by loopback test device"); - assertThrows(TimeoutException.class, () -> { + assertThrows(USBTimeoutException.class, () -> { testDevice.transferIn(ECHO_EP_IN, 16, 200); }); } From c1d498aaf524dbb383bc162d7eb7cc0a9e98c512 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 22 Oct 2022 11:36:29 +0200 Subject: [PATCH 129/433] Implement zero-length packets --- .../java/net/codecrete/usb/BulkTransferTest.java | 13 ++++++++++++- test-devices/loopback-stm32/src/main.c | 5 +++++ test-devices/loopback-stm32/src/vendor_custom.c | 6 +++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java index db0aafad..ccf0ad1e 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java @@ -15,7 +15,7 @@ import java.util.Arrays; import java.util.concurrent.CompletableFuture; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.*; public class BulkTransferTest extends TestDeviceBase { @@ -37,6 +37,17 @@ void mediumTransfer_succeeds() { assertArrayEquals(sampleData, data); } + @Test + void transferWithZLP_succeeds() { + byte[] sampleData = generateRandomBytes(64, 97333894); + writeBytes(sampleData); + byte[] data = testDevice.transferIn(LOOPBACK_EP_IN, LOOPBACK_MAX_PACKET_SIZE); + assertArrayEquals(sampleData, data); + data = testDevice.transferIn(LOOPBACK_EP_IN, LOOPBACK_MAX_PACKET_SIZE); + assertNotNull(data); + assertEquals(0, data.length); + } + @Test void largeTransfer_succeeds() throws Throwable { final int numBytes = 230763; diff --git a/test-devices/loopback-stm32/src/main.c b/test-devices/loopback-stm32/src/main.c index 0d72ba00..4262e03c 100644 --- a/test-devices/loopback-stm32/src/main.c +++ b/test-devices/loopback-stm32/src/main.c @@ -142,6 +142,11 @@ void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes) { loopback_check_tx(); loopback_check_rx(); + // check ZLP + if ((sent_bytes & (BULK_MAX_PACKET_SIZE - 1)) == 0 + && !cust_vendor_is_transmitting(ep_addr)) + cust_vendor_start_transmit(EP_LOOPBACK_TX, NULL, 0); + } else if (ep_addr == EP_ECHO_TX) { num_echos--; echo_update_state(); diff --git a/test-devices/loopback-stm32/src/vendor_custom.c b/test-devices/loopback-stm32/src/vendor_custom.c index 64563de8..8e41d6ac 100644 --- a/test-devices/loopback-stm32/src/vendor_custom.c +++ b/test-devices/loopback-stm32/src/vendor_custom.c @@ -37,10 +37,14 @@ const usbd_class_driver_t cust_vendor_driver = { .sof = NULL }; -// bit map indicating open endpoints +// open endpoints static uint8_t cv_eps_open[8]; static int cv_num_eps_open; + +// current alternate setting static uint8_t cv_alternate_setting; + +// interface descriptor (length covers all alternate interfaces and endpoints) static tusb_desc_interface_t const * cv_intf_desc; static uint16_t cv_intf_desc_len; From 9008f534dd476a37261e7f84b54dba58b4a36eb4 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 22 Oct 2022 10:29:04 +0200 Subject: [PATCH 130/433] Refactor Windows exceptions --- java-does-usb/jextract/windows/gen_win.cmd | 1 + .../usb/common/ConfigurationParser.java | 5 +- .../codecrete/usb/common/USBDeviceImpl.java | 1 - .../codecrete/usb/linux/LinuxUSBDevice.java | 10 ++-- .../codecrete/usb/macos/MacosUSBDevice.java | 7 ++- .../usb/macos/MacosUSBException.java | 30 ++++++++-- .../codecrete/usb/windows/DeviceProperty.java | 26 ++++----- .../usb/windows/WindowsUSBDevice.java | 46 +++++++-------- .../usb/windows/WindowsUSBDeviceRegistry.java | 33 ++++++----- .../usb/windows/WindowsUSBException.java | 56 +++++++++++++++++-- .../usb/windows/gen/kernel32/Kernel32.java | 3 + 11 files changed, 149 insertions(+), 69 deletions(-) diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index 431e8ef8..71202ab6 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -21,6 +21,7 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-macro ERROR_INSUFFICIENT_BUFFER ^ --include-macro ERROR_FILE_NOT_FOUND ^ --include-macro ERROR_SEM_TIMEOUT ^ + --include-macro ERROR_GEN_FAILURE ^ --include-macro GENERIC_READ ^ --include-macro GENERIC_WRITE ^ --include-macro FILE_SHARE_READ ^ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java index 8476e91f..a73e6082 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java @@ -7,7 +7,10 @@ package net.codecrete.usb.common; -import net.codecrete.usb.*; +import net.codecrete.usb.USBAlternateInterface; +import net.codecrete.usb.USBDirection; +import net.codecrete.usb.USBException; +import net.codecrete.usb.USBTransferType; import net.codecrete.usb.usbstandard.ConfigurationDescriptor; import net.codecrete.usb.usbstandard.EndpointDescriptor; import net.codecrete.usb.usbstandard.InterfaceAssociationDescriptor; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 7d9c06ef..33db5a21 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -13,7 +13,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.util.Collections; import java.util.List; import java.util.function.Function; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 3f53e5cc..310e4f4e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -8,16 +8,16 @@ package net.codecrete.usb.linux; import net.codecrete.usb.*; -import net.codecrete.usb.common.*; +import net.codecrete.usb.common.USBDeviceImpl; +import net.codecrete.usb.common.USBInterfaceImpl; import net.codecrete.usb.linux.gen.errno.errno; -import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_setinterface; -import net.codecrete.usb.macos.MacosUSBException; -import net.codecrete.usb.usbstandard.DeviceDescriptor; import net.codecrete.usb.linux.gen.fcntl.fcntl; import net.codecrete.usb.linux.gen.ioctl.ioctl; import net.codecrete.usb.linux.gen.unistd.unistd; import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_bulktransfer; import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_ctrltransfer; +import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_setinterface; +import net.codecrete.usb.usbstandard.DeviceDescriptor; import java.io.IOException; import java.lang.foreign.MemorySegment; @@ -125,7 +125,7 @@ public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { // check alternate setting var altSetting = intf.getAlternate(alternateNumber); if (altSetting == null) - throw new MacosUSBException(String.format("Interface %d does not have an alternate interface setting %d", + throw new USBException(String.format("Interface %d does not have an alternate interface setting %d", interfaceNumber, alternateNumber)); try (var session = MemorySession.openConfined()) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index a7b0a489..105420e6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -7,12 +7,15 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.*; +import net.codecrete.usb.USBControlTransfer; +import net.codecrete.usb.USBDirection; +import net.codecrete.usb.USBTimeoutException; +import net.codecrete.usb.USBTransferType; import net.codecrete.usb.common.USBDeviceImpl; -import net.codecrete.usb.usbstandard.ConfigurationDescriptor; import net.codecrete.usb.macos.gen.iokit.IOKit; import net.codecrete.usb.macos.gen.iokit.IOUSBDevRequest; import net.codecrete.usb.macos.gen.iokit.IOUSBFindInterfaceRequest; +import net.codecrete.usb.usbstandard.ConfigurationDescriptor; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java index 60b3d85e..c8965f9e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java @@ -11,11 +11,19 @@ import net.codecrete.usb.macos.gen.iokit.IOKit; import net.codecrete.usb.macos.gen.mach.mach; +/** + * Exception thrown if a macOS specific error occurs. + */ public class MacosUSBException extends USBException { - public MacosUSBException(String message) { - super(message); - } + /** + * Creates a new instance. + *

+ * The message for the macOS error code is looked up and appended to the message. + *

+ * @param message exception message + * @param errorCode macOS error code (usually returned by macOS functions) + */ public MacosUSBException(String message, int errorCode) { super(String.format("%s - %s", message, machErrorMessage(errorCode)), errorCode); } @@ -25,6 +33,15 @@ private static String machErrorMessage(int errorCode) { return msg.getUtf8String(0); } + /** + * Throws an exception for the specified macOS error code. + *

+ * The message for the macOS error code is looked up and appended to the message. + *

+ * @param errorCode macOS error code (usually returned by macOS functions) + * @param message exception message format ({@link String#format(String, Object...)} style) + * @param args arguments for exception message + */ static void throwException(int errorCode, String message, Object... args) { var formattedMessage = String.format(message, args); if (errorCode == IOKit.kIOUSBPipeStalled()) { @@ -34,8 +51,13 @@ static void throwException(int errorCode, String message, Object... args) { } } + /** + * Throws a USB exception. + * @param message exception message format ({@link String#format(String, Object...)} style) + * @param args arguments for exception message + */ static void throwException(String message, Object... args) { - throw new MacosUSBException(String.format(message, args)); + throw new USBException(String.format(message, args)); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index a57aa7b3..c393d985 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -7,7 +7,6 @@ package net.codecrete.usb.windows; -import net.codecrete.usb.USBException; import net.codecrete.usb.windows.gen.advapi32.Advapi32; import net.codecrete.usb.windows.gen.kernel32.GUID; import net.codecrete.usb.windows.gen.kernel32.Kernel32; @@ -24,6 +23,8 @@ import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.JAVA_CHAR; import static java.lang.foreign.ValueLayout.JAVA_INT; +import static net.codecrete.usb.windows.WindowsUSBException.throwException; +import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; /** * Device property GUIDs and functions @@ -60,10 +61,10 @@ public static int getDeviceIntProperty(Addressable devInfo, Addressable devInfoD var propertyValueHolder = session.allocate(JAVA_INT); if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0) == 0) - throw new WindowsUSBException("Internal error (SetupDiGetDevicePropertyW)", Kernel32.GetLastError()); + throwLastError("Internal error (SetupDiGetDevicePropertyW)"); if (propertyTypeHolder.get(JAVA_INT, 0) != SetupAPI.DEVPROP_TYPE_UINT32()) - throw new USBException("Internal error (expected property type UINT32)"); + throwException("Internal error (expected property type UINT32)"); return propertyValueHolder.get(JAVA_INT, 0); } @@ -97,19 +98,18 @@ private static MemorySegment getProperty(Addressable devInfo, Addressable devInf // TODO: Reactivate when proper GetLastError() handling is available // int err = Kernel32.GetLastError(); // if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) - // throw new WindowsUSBException("Internal error (SetupDiGetDevicePropertyW)", Kernel32 - // .GetLastError()); + // throwLastError("Internal error (SetupDiGetDevicePropertyW)"); } if (propertyTypeHolder.get(JAVA_INT, 0) != propertyType) - throw new USBException("Internal error (unexpected property type)"); + throwException("Internal error (unexpected property type)"); int stringLen = requiredSizeHolder.get(JAVA_INT, 0) / 2 - 1; var propertyValueHolder = session.allocateArray(JAVA_CHAR, stringLen + 1); if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0) == 0) - throw new WindowsUSBException("Internal error (SetupDiGetDevicePropertyW)", Kernel32.GetLastError()); + throwLastError("Internal error (SetupDiGetDevicePropertyW)"); return propertyValueHolder; } @@ -120,7 +120,7 @@ public static List findDeviceInterfaceGUIDs(MemoryAddress devInfoSetHand var regKey = SetupAPI.SetupDiOpenDevRegKey(devInfoSetHandle, devInfo, SetupAPI.DICS_FLAG_GLOBAL(), 0, SetupAPI.DIREG_DEV(), Advapi32.KEY_READ()); if (Win.IsInvalidHandle(regKey)) - throw new WindowsUSBException("Cannot open device registry key", Kernel32.GetLastError()); + throwLastError("Cannot open device registry key"); session.addCloseAction(() -> Advapi32.RegCloseKey(regKey)); // read registry value (without buffer, to query length) @@ -131,14 +131,14 @@ public static List findDeviceInterfaceGUIDs(MemoryAddress devInfoSetHand if (res == Kernel32.ERROR_FILE_NOT_FOUND()) return List.of(); // no device interface GUIDs if (res != 0 && res != Kernel32.ERROR_MORE_DATA()) - throw new WindowsUSBException("Internal error (RegQueryValueExW)", res); + throwException(res, "Internal error (RegQueryValueExW)"); // read registry value (with buffer) var valueSize = valueSizeHolder.get(JAVA_INT, 0); var value = session.allocate(valueSize); res = Advapi32.RegQueryValueExW(regKey, keyNameSegment, NULL, valueTypeHolder, value, valueSizeHolder); if (res != 0) - throw new WindowsUSBException("Internal error (RegQueryValueExW)", res); + throwException(res, "Internal error (RegQueryValueExW)"); return Win.createStringListFromSegment(value); } @@ -150,7 +150,7 @@ public static String getDevicePath(String instanceID, Addressable interfaceGuid) final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(interfaceGuid, instanceIDSegment, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); if (Win.IsInvalidHandle(devInfoSetHandle)) - throw new USBException("internal error (SetupDiGetClassDevsW)"); + throwException("internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left session.addCloseAction(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); @@ -159,7 +159,7 @@ public static String getDevicePath(String instanceID, Addressable interfaceGuid) var devIntfData = session.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); if (SetupAPI.SetupDiEnumDeviceInterfaces(devInfoSetHandle, NULL, interfaceGuid, 0, devIntfData) == 0) - throw new USBException("internal error (SetupDiEnumDeviceInterfaces)"); + throwException("internal error (SetupDiEnumDeviceInterfaces)"); // get device path // (SP_DEVICE_INTERFACE_DETAIL_DATA_W is of variable length and requires a bigger allocation so @@ -171,7 +171,7 @@ public static String getDevicePath(String instanceID, Addressable interfaceGuid) int intfDetailDataSize = (int) intfDetailData.byteSize(); if (SetupAPI.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, intfDetailData, intfDetailDataSize, NULL, NULL) == 0) - throw new WindowsUSBException("Internal error (SetupDiGetDeviceInterfaceDetailW)", Kernel32.GetLastError()); + throwLastError("Internal error (SetupDiGetDeviceInterfaceDetailW)"); return Win.createStringFromSegment(intfDetailData.asSlice(devicePathOffset)); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 71543e59..08cf029d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -22,6 +22,8 @@ import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.*; +import static net.codecrete.usb.windows.WindowsUSBException.throwException; +import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; /** * Windows implementation for USB device. @@ -74,7 +76,7 @@ public boolean isOpen() { @Override public void open() { if (isOpen()) - throw new USBException("the device is already open"); + throwException("the device is already open"); isOpen_ = true; } @@ -97,14 +99,14 @@ public void claimInterface(int interfaceNumber) { var intfHandle = getInterfaceHandle(interfaceNumber); if (intfHandle.interfaceHandle != null) - throw new USBException(String.format("Interface %d has already been claimed", interfaceNumber)); + throwException("Interface %d has already been claimed", interfaceNumber); var firstIntfHandle = intfHandle; if (intfHandle.firstInterfaceNumber != interfaceNumber) firstIntfHandle = getInterfaceHandle(intfHandle.firstInterfaceNumber); if (firstIntfHandle.devicePath == null) - throw new USBException(String.format("Interface number %d cannot be claimed (non WinUSB device?)", interfaceNumber)); + throwException("Interface number %d cannot be claimed (non WinUSB device?)", interfaceNumber); try (var session = MemorySession.openConfined()) { @@ -118,8 +120,7 @@ public void claimInterface(int interfaceNumber) { Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), NULL); if (Win.IsInvalidHandle(deviceHandle)) - throw new WindowsUSBException( - String.format("Cannot open USB device %s", firstIntfHandle.devicePath), Kernel32.GetLastError()); + throwLastError("Cannot open USB device %s", firstIntfHandle.devicePath); } else { deviceHandle = firstIntfHandle.deviceHandle; } @@ -128,7 +129,7 @@ public void claimInterface(int interfaceNumber) { // open interface var interfaceHandleHolder = session.allocate(ADDRESS); if (WinUSB.WinUsb_Initialize(deviceHandle, interfaceHandleHolder) == 0) - throw new WindowsUSBException("Cannot open WinUSB device", Kernel32.GetLastError()); + throwLastError("Cannot open WinUSB device"); var interfaceHandle = interfaceHandleHolder.get(ADDRESS, 0); firstIntfHandle.deviceHandle = deviceHandle; @@ -150,18 +151,17 @@ public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { var intfHandle = getInterfaceHandle(interfaceNumber); if (intfHandle.interfaceHandle == null) - throw new USBException(String.format("Interface %d has not been claimed", interfaceNumber)); + throwException("Interface %d has not been claimed", interfaceNumber); var intf = getInterface(interfaceNumber); // check alternate setting var altSetting = intf.getAlternate(alternateNumber); if (altSetting == null) - throw new WindowsUSBException(String.format("Interface %d does not have an alternate interface setting %d", - interfaceNumber, alternateNumber)); + throwException("Interface %d does not have an alternate interface setting %d", interfaceNumber, alternateNumber); if (WinUSB.WinUsb_SetCurrentAlternateSetting(intfHandle.interfaceHandle, (byte) alternateNumber) == 0) - throw new WindowsUSBException("Failed to set alternate interface", Kernel32.GetLastError()); + throwLastError("Failed to set alternate interface"); intf.setAlternate(altSetting); } @@ -171,7 +171,7 @@ public void releaseInterface(int interfaceNumber) { var intfHandle = getInterfaceHandle(interfaceNumber); if (intfHandle.interfaceHandle == null) - throw new USBException(String.format("Interface %d has not been claimed", interfaceNumber)); + throwException("Interface %d has not been claimed", interfaceNumber); var firstIntfHandle = intfHandle; if (intfHandle.firstInterfaceNumber != interfaceNumber) @@ -216,7 +216,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { if (WinUSB.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) - throw new WindowsUSBException("Control transfer IN failed", Kernel32.GetLastError()); + throwLastError("Control transfer IN failed"); int rxLength = lengthHolder.get(JAVA_INT, 0); return buffer.asSlice(0, rxLength).toArray(JAVA_BYTE); @@ -242,7 +242,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { if (WinUSB.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) - throw new WindowsUSBException("Control transfer OUT failed", Kernel32.GetLastError()); + throwLastError("Control transfer OUT failed"); } } @@ -258,7 +258,7 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { var timeoutHolder = session.allocate(JAVA_INT, timeout); if (WinUSB.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder) == 0) - throw new WindowsUSBException("Setting timeout failed", Kernel32.GetLastError()); + throwLastError("Setting timeout failed"); // copy data to native heap var buffer = session.allocate(data.length); @@ -271,7 +271,7 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { int err = Kernel32.GetLastError(); if (err == Kernel32.ERROR_SEM_TIMEOUT()) throw new USBTimeoutException("Transfer out aborted due to timeout"); - throw new WindowsUSBException("Bulk/interrupt transfer OUT failed", err); + throwException(err, "Bulk/interrupt transfer OUT failed"); } } } @@ -286,7 +286,7 @@ public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { var timeoutHolder = session.allocate(JAVA_INT, timeout); if (WinUSB.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder) == 0) - throw new WindowsUSBException("Setting timeout failed", Kernel32.GetLastError()); + throwLastError("Setting timeout failed"); // create native heap buffer for data var buffer = session.allocate(maxLength); @@ -298,7 +298,7 @@ public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { int err = Kernel32.GetLastError(); if (err == Kernel32.ERROR_SEM_TIMEOUT()) throw new USBTimeoutException("Transfer in aborted due to timeout"); - throw new WindowsUSBException("Bulk/interrupt transfer IN failed", err); + throwException(err, "Bulk/interrupt transfer IN failed"); } // copy data @@ -312,7 +312,7 @@ public void clearHalt(USBDirection direction, int endpointNumber) { var endpoint = getEndpoint(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); if (WinUSB.WinUsb_ResetPipe(intfHandle.interfaceHandle, endpoint.endpointAddress()) == 0) - throw new WindowsUSBException("Clearing halt failed", Kernel32.GetLastError()); + throwLastError("Clearing halt failed"); } private InterfaceHandle getInterfaceHandle(int interfaceNumber) { @@ -321,7 +321,8 @@ private InterfaceHandle getInterfaceHandle(int interfaceNumber) { return intfHandle; } - throw new USBException(String.format("Invalid interface number: %s", interfaceNumber)); + throwException("Invalid interface number: %s", interfaceNumber); + throw new AssertionError("not reached"); } private InterfaceHandle findControlTransferInterface(USBControlTransfer setup) { @@ -340,14 +341,14 @@ private InterfaceHandle findControlTransferInterface(USBControlTransfer setup) { if (endpointNumber != 0) { interfaceNumber = getInterfaceNumber(direction, endpointNumber); if (interfaceNumber == -1) - throw new USBException(String.format("Invalid endpoint number %d or interface not claimed", endpointNumber)); + throwException("Invalid endpoint number %d or interface not claimed", endpointNumber); } } if (interfaceNumber >= 0) { var intfHandle = getInterfaceHandle(interfaceNumber); if (intfHandle.interfaceHandle == null) - throw new USBException(String.format("Interface number %d has not been claimed", interfaceNumber)); + throwException("Interface number %d has not been claimed", interfaceNumber); return intfHandle; } @@ -357,6 +358,7 @@ private InterfaceHandle findControlTransferInterface(USBControlTransfer setup) { return intfHandle; } - throw new USBException("Control transfer failed as no interface has been claimed"); + throwException("Control transfer failed as no interface has been claimed"); + throw new AssertionError("not reached"); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 1e3369a7..b1acd063 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -8,8 +8,9 @@ package net.codecrete.usb.windows; import net.codecrete.usb.USBDevice; -import net.codecrete.usb.USBException; -import net.codecrete.usb.common.*; +import net.codecrete.usb.common.ForeignMemory; +import net.codecrete.usb.common.USBDeviceImpl; +import net.codecrete.usb.common.USBDeviceRegistry; import net.codecrete.usb.usbstandard.ConfigurationDescriptor; import net.codecrete.usb.usbstandard.DeviceDescriptor; import net.codecrete.usb.usbstandard.SetupPacket; @@ -35,6 +36,8 @@ import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.usbstandard.Constants.*; +import static net.codecrete.usb.windows.WindowsUSBException.throwException; +import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; /** * Windows implementation of USB device registry. @@ -76,7 +79,7 @@ protected void monitorDevices() { hwnd = User32.CreateWindowExW(0, className, windowName, 0, 0, 0, 0, 0, User32.HWND_MESSAGE(), NULL, instance, NULL); if (hwnd == NULL) - throw new WindowsUSBException("internal error (CreateWindowExW)", Kernel32.GetLastError()); + throwLastError("internal error (CreateWindowExW)"); // configure notifications var notificationFilter = session.allocate(DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); @@ -88,7 +91,7 @@ protected void monitorDevices() { var notifyHandle = User32.RegisterDeviceNotificationW(hwnd, notificationFilter, User32.DEVICE_NOTIFY_WINDOW_HANDLE()); if (notifyHandle == NULL) - throw new WindowsUSBException("internal error (RegisterDeviceNotificationW)", Kernel32.GetLastError()); + throwLastError("internal error (RegisterDeviceNotificationW)"); // initial device enumeration enumeratePresentDevices(); @@ -115,7 +118,7 @@ private void enumeratePresentDevices() { final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); if (Win.IsInvalidHandle(devInfoSetHandle)) - throw new USBException("internal error (SetupDiGetClassDevsW)"); + throwException("internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left outerSession.addCloseAction(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); @@ -135,7 +138,7 @@ private void enumeratePresentDevices() { // TODO: Remove check for ERROR_SUCCESS if proper GetLastError() handling is available if (err == Kernel32.ERROR_NO_MORE_ITEMS() || err == Kernel32.ERROR_SUCCESS()) break; - throw new USBException("Internal error (SetupDiEnumDeviceInfo) "); + throwException("Internal error (SetupDiEnumDeviceInfo) "); } var instanceID = DeviceProperty.getDeviceStringProperty(devInfoSetHandle, devInfo, @@ -172,7 +175,7 @@ private Map enumerateChildren(List childrenIds) { // create device info set var devInfoSetHandle = SetupAPI.SetupDiCreateDeviceInfoList(NULL, NULL); if (Win.IsInvalidHandle(devInfoSetHandle)) - throw new WindowsUSBException("Cannot create device info list", Kernel32.GetLastError()); + throwLastError("Cannot create device info list"); session.addCloseAction(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); // get device info for child @@ -180,7 +183,7 @@ private Map enumerateChildren(List childrenIds) { SP_DEVINFO_DATA.cbSize$set(devInfo, (int) devInfo.byteSize()); var instanceIdSegment = Win.createSegmentFromString(instanceId, session); if (SetupAPI.SetupDiOpenDeviceInfoW(devInfoSetHandle, instanceIdSegment, NULL, 0, devInfo) == 0) - throw new WindowsUSBException("Internal error (SetupDiOpenDeviceInfoW)", Kernel32.GetLastError()); + throwLastError("Internal error (SetupDiOpenDeviceInfoW)"); // get hardware IDs (to extract interface number) var hardwareIds = DeviceProperty.getDeviceStringListProperty(devInfoSetHandle, devInfo, @@ -229,7 +232,7 @@ private USBDevice createDeviceFromDeviceInfo(MemoryAddress devInfoSetHandle, Mem hubHandle = Kernel32.CreateFileW(hubPathSeg, Kernel32.GENERIC_WRITE(), Kernel32.FILE_SHARE_WRITE(), NULL, Kernel32.OPEN_EXISTING(), 0, NULL); if (Win.IsInvalidHandle(hubHandle)) - throw new USBException("Cannot open USB hub", Kernel32.GetLastError()); + throwLastError("Cannot open USB hub"); hubHandles.put(hubPath, hubHandle); } @@ -266,7 +269,7 @@ private USBDevice createDevice(String devicePath, Map children, var sizeHolder = session.allocate(JAVA_INT); if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), connInfo , (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL) == 0) - throw new WindowsUSBException("Internal error (cannot get device descriptor)", Kernel32.GetLastError()); + throwLastError("Internal error (cannot get device descriptor)"); var descriptorSegment = USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(connInfo); var deviceDescriptor = new DeviceDescriptor(descriptorSegment); @@ -311,7 +314,7 @@ private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, in var effectiveSizeHolder = session.allocate(JAVA_INT); if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION(), descriptorRequest, size, descriptorRequest, size, effectiveSizeHolder, NULL) == 0) - throw new WindowsUSBException(String.format("Cannot retrieve descriptor %d", index), Kernel32.GetLastError()); + throwLastError("Cannot retrieve descriptor %d", index); // determine size of descriptor int expectedSize; @@ -327,7 +330,7 @@ private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, in var effectiveSize = effectiveSizeHolder.get(JAVA_INT, 0) - USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset; if (effectiveSize != expectedSize) { if (requestSize != 0) - throw new USBException("Unexpected descriptor size"); + throwException("Unexpected descriptor size"); // repeat with correct size return getDescriptor(hubHandle, usbPortNumber, descriptorType, index, languageID, expectedSize, session); @@ -381,7 +384,7 @@ private void onDeviceConnected(String devicePath) { final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); if (Win.IsInvalidHandle(devInfoSetHandle)) - throw new WindowsUSBException("internal error (SetupDiGetClassDevsW)", Kernel32.GetLastError()); + throwLastError("internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left session.addCloseAction(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); @@ -390,7 +393,7 @@ private void onDeviceConnected(String devicePath) { SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); var devicePathSegment = Win.createSegmentFromString(devicePath, session); if (SetupAPI.SetupDiOpenDeviceInterfaceW(devInfoSetHandle, devicePathSegment, 0, devIntfData) == 0) - throw new WindowsUSBException("internal error (SetupDiOpenDeviceInterfaceW)", Kernel32.GetLastError()); + throwLastError("internal error (SetupDiOpenDeviceInterfaceW)"); ForeignMemory.addCloseAction(devIntfData, (segment) -> SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSetHandle, segment)); @@ -399,7 +402,7 @@ private void onDeviceConnected(String devicePath) { if (SetupAPI.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, NULL, 0, NULL, devInfo) == 0) { int err = Kernel32.GetLastError(); if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) - throw new USBException("internal error (SetupDiGetDeviceInterfaceDetailW)", err); + throwException(err, "internal error (SetupDiGetDeviceInterfaceDetailW)"); } // ensure all hubs are closed later diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java index c6463801..c17bde26 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java @@ -7,6 +7,7 @@ package net.codecrete.usb.windows; import net.codecrete.usb.USBException; +import net.codecrete.usb.USBStallException; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import java.lang.foreign.MemorySegment; @@ -15,17 +16,60 @@ import static java.lang.foreign.MemoryAddress.NULL; import static java.lang.foreign.ValueLayout.ADDRESS; +/** + * Exception thrown if a Windows specific error occurs. + */ public class WindowsUSBException extends USBException { - public WindowsUSBException(String message) { - super(message); - } + /** + * Creates a new instance. + *

+ * The message for the Windows error code is looked up and appended to the message. + *

+ * @param message exception message + * @param errorCode Windows error code (usually returned from {@code GetLastError()}) + */ public WindowsUSBException(String message, int errorCode) { - super(String.format("%s - %s", message, getErrorMessage(errorCode)), errorCode); + super(String.format("%s. %s", message, getErrorMessage(errorCode)), errorCode); + } + + /** + * Throws an exception for the specified Windows error code. + *

+ * The message for the Windows error code is looked up and appended to the message. + *

+ * @param errorCode Windows error code (usually returned from {@code GetLastError()}) + * @param message exception message format ({@link String#format(String, Object...)} style) + * @param args arguments for exception message + */ + static void throwException(int errorCode, String message, Object... args) { + var formattedMessage = String.format(message, args); + if (errorCode == Kernel32.ERROR_GEN_FAILURE()) { + throw new USBStallException(formattedMessage); + } else { + throw new WindowsUSBException(formattedMessage, errorCode); + } + } + + /** + * Throws a USB exception. + * @param message exception message format ({@link String#format(String, Object...)} style) + * @param args arguments for exception message + */ + static void throwException(String message, Object... args) { + throw new USBException(String.format(message, args)); } - public WindowsUSBException(String message, Throwable cause) { - super(message, cause); + /** + * Throws an exception for the last error. + *

+ * The message of the last Windows error code is looked up and appended to the message. + *

+ * @param message exception message format ({@link String#format(String, Object...)} style) + * @param args arguments for exception message + */ + static void throwLastError(String message, Object... args) { + throwException(Kernel32.GetLastError(), message, args); } private static String getErrorMessage(int errorCode) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java index e91ab190..60a5a926 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -131,6 +131,9 @@ public static int ERROR_SUCCESS() { public static int ERROR_FILE_NOT_FOUND() { return (int)2L; } + public static int ERROR_GEN_FAILURE() { + return (int)31L; + } public static int ERROR_SEM_TIMEOUT() { return (int)121L; } From 873209ae6e4688d090f2a9fa3409e24af7c2c4e0 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 22 Oct 2022 12:46:07 +0200 Subject: [PATCH 131/433] Refactor exceptions (Linux) --- java-does-usb/jextract/linux/gen_linux.sh | 1 + .../codecrete/usb/linux/LinuxUSBDevice.java | 37 ++++++------ .../usb/linux/LinuxUSBDeviceRegistry.java | 20 +++---- .../usb/linux/LinuxUSBException.java | 58 +++++++++++++++++-- .../codecrete/usb/linux/gen/errno/errno.java | 3 + .../usb/macos/MacosUSBException.java | 2 +- 6 files changed, 86 insertions(+), 35 deletions(-) diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index 4743e3e7..82f41980 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -16,6 +16,7 @@ $JEXTRACT --source --output ../../src/main/java \ --target-package net.codecrete.usb.linux.gen.errno \ --include-function __errno_location \ --include-macro ETIMEDOUT \ + --include-macro EPIPE \ /usr/include/errno.h # string.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 310e4f4e..af4a67f8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -27,6 +27,8 @@ import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_INT; +import static net.codecrete.usb.linux.LinuxUSBException.throwException; +import static net.codecrete.usb.linux.LinuxUSBException.throwLastError; public class LinuxUSBDevice extends USBDeviceImpl { @@ -72,13 +74,13 @@ public boolean isOpen() { @Override public void open() { if (isOpen()) - throw new USBException("the device is already open"); + throwException("the device is already open"); try (var session = MemorySession.openConfined()) { var pathUtf8 = session.allocateUtf8String(id_.toString()); fd = fcntl.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC()); if (fd == -1) - throw new LinuxUSBException("Cannot open USB device", IO.getErrno()); + throwLastError("Cannot open USB device"); } } @@ -99,15 +101,15 @@ public void claimInterface(int interfaceNumber) { var intf = getInterface(interfaceNumber); if (intf == null) - throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); + throwException("Invalid interface number: %d", interfaceNumber); if (intf.isClaimed()) - throw new USBException(String.format("Interface %d has already been claimed", interfaceNumber)); + throwException("Interface %d has already been claimed", interfaceNumber); try (var session = MemorySession.openConfined()) { var intfNumSegment = session.allocate(JAVA_INT, interfaceNumber); int ret = ioctl.ioctl(fd, USBDevFS.CLAIMINTERFACE, intfNumSegment.address()); if (ret != 0) - throw new LinuxUSBException("Cannot claim USB interface", IO.getErrno()); + throwLastError("Cannot claim USB interface"); setClaimed(interfaceNumber, true); } } @@ -118,15 +120,14 @@ public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { var intf = getInterface(interfaceNumber); if (intf == null) - throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); + throwException("Invalid interface number: %d", interfaceNumber); if (!intf.isClaimed()) - throw new USBException(String.format("Interface %d has not been claimed", interfaceNumber)); + throwException("Interface %d has not been claimed", interfaceNumber); // check alternate setting var altSetting = intf.getAlternate(alternateNumber); if (altSetting == null) - throw new USBException(String.format("Interface %d does not have an alternate interface setting %d", - interfaceNumber, alternateNumber)); + throwException("Interface %d does not have an alternate interface setting %d", interfaceNumber, alternateNumber); try (var session = MemorySession.openConfined()) { var setIntfSegment = session.allocate(usbdevfs_setinterface.$LAYOUT()); @@ -134,7 +135,7 @@ public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { usbdevfs_setinterface.altsetting$set(setIntfSegment, alternateNumber); int ret = ioctl.ioctl(fd, USBDevFS.SETINTERFACE, setIntfSegment.address()); if (ret != 0) - throw new LinuxUSBException("Failed to set alternate interface", IO.getErrno()); + throwLastError("Failed to set alternate interface"); } intf.setAlternate(altSetting); @@ -145,15 +146,15 @@ public void releaseInterface(int interfaceNumber) { var intf = getInterface(interfaceNumber); if (intf == null) - throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); + throwException("Invalid interface number: %d", interfaceNumber); if (!intf.isClaimed()) - throw new USBException(String.format("Interface %d has not been claimed", interfaceNumber)); + throwException("Interface %d has not been claimed", interfaceNumber); try (var session = MemorySession.openConfined()) { var intfNumSegment = session.allocate(JAVA_INT, interfaceNumber); int ret = ioctl.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment.address()); if (ret != 0) - throw new LinuxUSBException("Cannot release USB interface", IO.getErrno()); + throwLastError("Cannot release USB interface"); setClaimed(interfaceNumber, false); } } @@ -180,7 +181,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { int res = ioctl.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer.address()); if (res < 0) - throw new LinuxUSBException("Control IN transfer failed", IO.getErrno()); + throwLastError("Control IN transfer failed"); return data.asSlice(0, res).toArray(JAVA_BYTE); } @@ -197,7 +198,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { int res = ioctl.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer.address()); if (res < 0) - throw new LinuxUSBException("Control OUT transfer failed", IO.getErrno()); + throwLastError("Control OUT transfer failed"); } } @@ -225,7 +226,7 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { int err = IO.getErrno(); if (err == errno.ETIMEDOUT()) throw new USBTimeoutException("Transfer out aborted due to timeout"); - throw new LinuxUSBException(String.format("USB OUT transfer on endpoint %d failed", endpointNumber), err); + throwException(err, "USB OUT transfer on endpoint %d failed", endpointNumber); } } } @@ -245,7 +246,7 @@ public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { int err = IO.getErrno(); if (err == errno.ETIMEDOUT()) throw new USBTimeoutException("Transfer in aborted due to timeout"); - throw new LinuxUSBException(String.format("USB IN transfer on endpoint %d failed", endpointNumber), err); + throwException(err, "USB IN transfer on endpoint %d failed", endpointNumber); } return buffer.asSlice(0, res).toArray(JAVA_BYTE); @@ -261,7 +262,7 @@ public void clearHalt(USBDirection direction, int endpointNumber) { var endpointAddrSegment = session.allocate(JAVA_INT, endpointAddress & 0xff); int res = ioctl.ioctl(fd, USBDevFS.CLEAR_HALT, endpointAddrSegment.address()); if (res < 0) - throw new LinuxUSBException("Clearing halt failed", IO.getErrno()); + throwLastError("Clearing halt failed"); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 6c9bd1b5..c242b181 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -8,7 +8,6 @@ package net.codecrete.usb.linux; import net.codecrete.usb.USBDevice; -import net.codecrete.usb.USBException; import net.codecrete.usb.common.USBDeviceRegistry; import net.codecrete.usb.linux.gen.poll.poll; import net.codecrete.usb.linux.gen.poll.pollfd; @@ -22,6 +21,7 @@ import java.util.List; import static java.lang.foreign.MemoryAddress.NULL; +import static net.codecrete.usb.linux.LinuxUSBException.throwException; /** * Linux implementation of USB device registry. @@ -42,21 +42,21 @@ protected void monitorDevices() { // setup udev monitor var udevInstance = udev.udev_new(); if (udevInstance == NULL) - throw new USBException("internal error (udev_new)"); + throwException("internal error (udev_new)"); monitor = udev.udev_monitor_new_from_netlink(udevInstance, MONITOR_NAME); if (monitor == NULL) - throw new USBException("internal error (udev_monitor_new_from_netlink)"); + throwException("internal error (udev_monitor_new_from_netlink)"); if (udev.udev_monitor_filter_add_match_subsystem_devtype(monitor, SUBSYSTEM_USB, DEVTYPE_USB_DEVICE) < 0) - throw new USBException("internal error (udev_monitor_filter_add_match_subsystem_devtype)"); + throwException("internal error (udev_monitor_filter_add_match_subsystem_devtype)"); if (udev.udev_monitor_enable_receiving(monitor) < 0) - throw new USBException("internal error (udev_monitor_enable_receiving)"); + throwException("internal error (udev_monitor_enable_receiving)"); fd = udev.udev_monitor_get_fd(monitor); if (fd < 0) - throw new USBException("internal error (udev_monitor_get_fd)"); + throwException("internal error (udev_monitor_get_fd)"); // create initial list of devices var deviceList = enumeratePresentDevices(udevInstance); @@ -101,15 +101,15 @@ private List enumeratePresentDevices(Addressable udevInstance) { // create device enumerator var enumerate = udev.udev_enumerate_new(udevInstance); if (enumerate == NULL) - throw new USBException("internal error (udev_enumerate_new)"); + throwException("internal error (udev_enumerate_new)"); outerSession.addCloseAction(() -> udev.udev_enumerate_unref(enumerate)); if (udev.udev_enumerate_add_match_subsystem(enumerate, SUBSYSTEM_USB) < 0) - throw new USBException("internal error (udev_enumerate_add_match_subsystem)"); + throwException("internal error (udev_enumerate_add_match_subsystem)"); if (udev.udev_enumerate_scan_devices(enumerate) < 0) - throw new USBException("internal error (udev_enumerate_scan_devices)"); + throwException("internal error (udev_enumerate_scan_devices)"); // enumerate devices for (var entry = udev.udev_enumerate_get_list_entry(enumerate); entry != NULL; entry = @@ -237,6 +237,6 @@ private static void waitForFileDescriptor(int fd, MemorySession session) { pollfd.events$set(fds, (short) poll.POLLIN()); int res = poll.poll(fds, 1, -1); if (res < 0) - throw new USBException("internal error (poll)"); + throwException("internal error (poll)"); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java index 94f969df..dd1c061c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java @@ -7,17 +7,63 @@ package net.codecrete.usb.linux; import net.codecrete.usb.USBException; +import net.codecrete.usb.USBStallException; +import net.codecrete.usb.linux.gen.errno.errno; +/** + * Exception thrown if a Linux specific error occurs. + */ public class LinuxUSBException extends USBException { - public LinuxUSBException(String message) { - super(message); - } + /** + * Creates a new instance. + *

+ * The message for the Linux error code is looked up and appended to the message. + *

+ * @param message exception message + * @param errorCode Linux error code (returned by {@code errno}) + */ public LinuxUSBException(String message, int errorCode) { - super(String.format("%s - %s", message, Linux.getErrorMessage(errorCode)), errorCode); + super(String.format("%s. %s", message, Linux.getErrorMessage(errorCode)), errorCode); + } + + /** + * Throws an exception for the specified Linux error code. + *

+ * The message for the Linux error code is looked up and appended to the message. + *

+ * @param errorCode Linux error code (returned by {@code errno}) + * @param message exception message format ({@link String#format(String, Object...)} style) + * @param args arguments for exception message + */ + static void throwException(int errorCode, String message, Object... args) { + var formattedMessage = String.format(message, args); + if (errorCode == errno.EPIPE()) { + throw new USBStallException(formattedMessage); + } else { + throw new LinuxUSBException(formattedMessage, errorCode); + } } - public LinuxUSBException(String message, Throwable cause) { - super(message, cause); + /** + * Throws a USB exception. + * @param message exception message format ({@link String#format(String, Object...)} style) + * @param args arguments for exception message + */ + static void throwException(String message, Object... args) { + throw new USBException(String.format(message, args)); } + + /** + * Throws an exception for the last error. + *

+ * The message of the last Linux error code is looked ({@code errno}) up and appended to the message. + *

+ * @param message exception message format ({@link String#format(String, Object...)} style) + * @param args arguments for exception message + */ + static void throwLastError(String message, Object... args) { + throwException(IO.getErrno(), message, args); + } + } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java index e043d7e9..1d7415bc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -17,6 +17,9 @@ public class errno { public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static int EPIPE() { + return (int)32L; + } public static int ETIMEDOUT() { return (int)110L; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java index c8965f9e..eec54c27 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java @@ -25,7 +25,7 @@ public class MacosUSBException extends USBException { * @param errorCode macOS error code (usually returned by macOS functions) */ public MacosUSBException(String message, int errorCode) { - super(String.format("%s - %s", message, machErrorMessage(errorCode)), errorCode); + super(String.format("%s. %s", message, machErrorMessage(errorCode)), errorCode); } private static String machErrorMessage(int errorCode) { From 425b35d4cbb816afc867e80438d48fadf461bed5 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 22 Oct 2022 14:26:04 +0200 Subject: [PATCH 132/433] Input stream skips zero-length packets --- .../usb/common/EndpointInputStream.java | 5 ++- .../java/net/codecrete/usb/StreamTest.java | 41 +++++++++++++++---- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index a605a682..e50ca09e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -70,7 +70,10 @@ private void receiveMoreData() throws IOException { throw new IOException("Bulk endpoint input stream has been closed"); readOffset_ = 0; - packet_ = device_.transferIn(endpointNumber_, packetSize_); + // skip zero-length packets + do { + packet_ = device_.transferIn(endpointNumber_, packetSize_); + } while (packet_.length == 0); } @Override diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java index fe1ffdfb..4b456f76 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java @@ -12,9 +12,11 @@ import org.junit.jupiter.api.Test; import java.io.IOException; +import java.util.Arrays; import java.util.concurrent.CompletableFuture; import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class StreamTest extends TestDeviceBase { @@ -37,14 +39,29 @@ void mediumTransfer_succeeds() { } @Test - void largeTransferSmallChunks_succeeds() throws Throwable { - final int numBytes = 230763; + void transferWithZLP_succeeds() throws Throwable { + final byte[] sampleData = generateRandomBytes(2 * LOOPBACK_MAX_PACKET_SIZE, 197007894); + var writer = CompletableFuture.runAsync(() -> { + testDevice.transferOut(LOOPBACK_EP_OUT, Arrays.copyOfRange(sampleData, 0, LOOPBACK_MAX_PACKET_SIZE)); + sleep(200); + testDevice.transferOut(LOOPBACK_EP_OUT, Arrays.copyOfRange(sampleData, LOOPBACK_MAX_PACKET_SIZE, 2 * LOOPBACK_MAX_PACKET_SIZE)); + }); + + var reader = CompletableFuture.supplyAsync(() -> readBytes(sampleData.length)); + + CompletableFuture.allOf(writer, reader).join(); + + assertArrayEquals(sampleData, reader.resultNow()); + } + + @Test + void largeTransferSmallChunks_succeeds() { + final int numBytes = 23076; byte[] sampleData = generateRandomBytes(numBytes, 3829007493L); var writer = CompletableFuture.runAsync(() -> writeBytes(sampleData, 20)); var reader = CompletableFuture.supplyAsync(() -> readBytes(numBytes)); - CompletableFuture.allOf(writer, reader).join(); - if (reader.isCompletedExceptionally()) - throw reader.exceptionNow(); + var allFutures = CompletableFuture.allOf(writer, reader); + allFutures.join(); assertArrayEquals(sampleData, reader.resultNow()); } @@ -55,8 +72,6 @@ void largeTransferBigChunks_succeeds() throws Throwable { var writer = CompletableFuture.runAsync(() -> writeBytes(sampleData, 150)); var reader = CompletableFuture.supplyAsync(() -> readBytes(numBytes)); CompletableFuture.allOf(writer, reader).join(); - if (reader.isCompletedExceptionally()) - throw reader.exceptionNow(); assertArrayEquals(sampleData, reader.resultNow()); } @@ -78,7 +93,9 @@ static byte[] readBytes(int numBytes) { try (var is = testDevice.openInputStream(LOOPBACK_EP_IN)) { int bytesRead = 0; while (bytesRead < numBytes) { - bytesRead += is.read(buffer, bytesRead, numBytes - bytesRead); + int n = is.read(buffer, bytesRead, numBytes - bytesRead); + assertTrue(n > 0); + bytesRead += n; } } catch (IOException e) { @@ -86,4 +103,12 @@ static byte[] readBytes(int numBytes) { } return buffer; } + + private static void sleep(int millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } } From 768ccd868f8d79304e1f63c8b8135687b0cca47e Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 22 Oct 2022 15:11:02 +0200 Subject: [PATCH 133/433] Simplify transferIn() method --- .../java/net/codecrete/usb/USBDevice.java | 19 +++++++------ .../codecrete/usb/common/USBDeviceImpl.java | 13 +++++---- .../codecrete/usb/linux/LinuxUSBDevice.java | 8 +++--- .../codecrete/usb/macos/MacosUSBDevice.java | 28 ++++++++++--------- .../usb/windows/WindowsUSBDevice.java | 4 +-- .../net/codecrete/usb/TestDeviceBase.java | 4 +-- .../java/net/codecrete/usb/TimeoutTest.java | 12 ++++---- 7 files changed, 46 insertions(+), 42 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index bd54417a..6ae61af8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -231,18 +231,20 @@ public interface USBDevice { * Receives data from this device. *

* This method blocks until at least a packet has been received or an error has occurred. - * {@code maxLength} must be long enough to hold the full data packet transmitted by the device. - * To be on the safe side, it should be equal or greater than the endpoint's maximum packet size. + *

+ *

+ * The returned data is the payload of a packet. It can have a length of 0 if the USB device + * sends zero-length packets to indicate the end of a data unit. *

*

* This method can receive data from bulk and interrupt endpoints. *

* * @param endpointNumber endpoint number (in the range between 1 and 127, i.e. without the direction bit) - * @param maxLength the maximum data length to receive (in number of bytes) * @return received data */ - byte[] transferIn(int endpointNumber, int maxLength); + byte[] transferIn(int endpointNumber); + /** * Receives data from this device. *

@@ -250,19 +252,18 @@ public interface USBDevice { * or an error has occurred. If the timeout expired, a {@link USBTimeoutException} is thrown. *

*

- * {@code maxLength} must be long enough to hold the full data packet transmitted by the device. - * To be on the safe side, it should be equal or greater than the endpoint's maximum packet size. + * The returned data is the payload of a packet. It can have a length of 0 if the USB device + * sends zero-length packets to indicate the end of a data unit. *

*

* This method can receive data from bulk and interrupt endpoints. *

* * @param endpointNumber the endpoint number (in the range between 1 and 127, i.e. without the direction bit) - * @param maxLength the maximum data length to receive (in number of bytes) * @param timeout the timeout period, in milliseconds (0 for no timeout) * @return received data */ - byte[] transferIn(int endpointNumber, int maxLength, int timeout); + byte[] transferIn(int endpointNumber, int timeout); /** * Opens a new output stream to send data to a bulk endpoint. @@ -283,7 +284,7 @@ public interface USBDevice { * All data received from the specified bulk endpoint can be read using this input stream. *

*

- * If {@link #transferIn(int, int)} and an input stream or multiple input streams + * If {@link #transferIn(int)} and an input stream or multiple input streams * are used concurrently for the same endpoint, the behavior is unpredictable. *

* @param endpointNumber bulk endpoint number (in the range between 1 and 127, i.e. without the direction bit) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 33db5a21..76d5aa26 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -237,7 +237,7 @@ protected byte getEndpointAddress(int endpointNumber, USBDirection direction, } throwInvalidEndpointException(endpointNumber, direction, transferType1, transferType2); - return 0; // will never be reached + throw new AssertionError("not reached"); } /** @@ -261,7 +261,8 @@ protected EndpointInfo getEndpoint(int endpointNumber, USBDirection direction, if (ep.number() == endpointNumber && ep.direction() == direction && (ep.transferType() == transferType1 || ep.transferType() == transferType2)) return new EndpointInfo(intf.number(), ep.number(), - (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0))); + (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)), + ep.packetSize()); } } } @@ -314,12 +315,12 @@ public void transferOut(int endpointNumber, byte[] data) { public abstract void transferOut(int endpointNumber, byte[] data, int timeout); @Override - public byte[] transferIn(int endpointNumber, int maxLength) { - return transferIn(endpointNumber, maxLength, 0); + public byte[] transferIn(int endpointNumber) { + return transferIn(endpointNumber, 0); } @Override - public abstract byte[] transferIn(int endpointNumber, int maxLength, int timeout); + public abstract byte[] transferIn(int endpointNumber, int timeout); @Override public OutputStream openOutputStream(int endpointNumber) { @@ -357,6 +358,6 @@ public String toString() { return "VID: 0x" + String.format("%04x", vendorId_) + ", PID: 0x" + String.format("%04x", productId_) + ", " + "manufacturer: " + manufacturer_ + ", product: " + product_ + ", serial: " + serialNumber_ + ", ID: " + id_; } - public record EndpointInfo(int interfaceNumber, int endpointNumber, byte endpointAddress) { + public record EndpointInfo(int interfaceNumber, int endpointNumber, byte endpointAddress, int packetSize) { } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index af4a67f8..ef60c7e2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -232,14 +232,14 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { } @Override - public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { - var endpointAddress = getEndpointAddress(endpointNumber, USBDirection.IN, + public byte[] transferIn(int endpointNumber, int timeout) { + var endpoint = getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); try (var session = MemorySession.openConfined()) { - var buffer = session.allocate(maxLength); + var buffer = session.allocate(endpoint.packetSize()); - var transfer = createBulkTransfer(session, endpointAddress, buffer, timeout); + var transfer = createBulkTransfer(session, endpoint.endpointAddress(), buffer, timeout); int res = ioctl.ioctl(fd, USBDevFS.BULK, transfer.address()); if (res < 0) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 105420e6..a3ae9491 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -256,11 +256,13 @@ private void updateEndpointList() { if (ret != 0) throwException(ret, "Failed to get pipe properties"); - int endpointNumber = numberHolder.get(JAVA_BYTE, 0) & 255; - int direction = directionHolder.get(JAVA_BYTE, 0) & 255; + int endpointNumber = numberHolder.get(JAVA_BYTE, 0) & 0xff; + int direction = directionHolder.get(JAVA_BYTE, 0) & 0xff; byte endpointAddress = (byte) (endpointNumber | (direction << 7)); byte transferType = transferTypeHolder.get(JAVA_BYTE, 0); - var endpointInfo = new EndpointInfo(interfaceInfo.addr, (byte) pipeIndex, getTransferType(transferType)); + int maxPacketSize = maxPacketSizeHolder.get(JAVA_SHORT, 0) & 0xffff; + var endpointInfo = new EndpointInfo(interfaceInfo.addr, (byte) pipeIndex, + getTransferType(transferType), maxPacketSize); endpoints.put(endpointAddress, endpointInfo); } } @@ -375,24 +377,24 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { } @Override - public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { + public byte[] transferIn(int endpointNumber, int timeout) { - var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.IN, + var endpoint = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); try (var session = MemorySession.openConfined()) { - var nativeData = session.allocateArray(JAVA_BYTE, maxLength); - var sizeHolder = session.allocate(JAVA_INT, maxLength); + var nativeData = session.allocateArray(JAVA_BYTE, endpoint.packetSize()); + var sizeHolder = session.allocate(JAVA_INT, endpoint.packetSize()); int ret; if (timeout <= 0) { // transfer without timeout - ret = IoKitUSB.ReadPipe(endpointInfo.interfaceAddress(), endpointInfo.pipeIndex, nativeData.address(), sizeHolder.address()); + ret = IoKitUSB.ReadPipe(endpoint.interfaceAddress(), endpoint.pipeIndex, nativeData.address(), sizeHolder.address()); - } else if (endpointInfo.transferType == USBTransferType.BULK) { + } else if (endpoint.transferType == USBTransferType.BULK) { // bulk transfer with timeout - ret = IoKitUSB.ReadPipeTO(endpointInfo.interfaceAddress(), endpointInfo.pipeIndex, nativeData.address(), + ret = IoKitUSB.ReadPipeTO(endpoint.interfaceAddress(), endpoint.pipeIndex, nativeData.address(), sizeHolder.address(), timeout, timeout); if (ret == IOKit.kIOUSBTransactionTimeout()) throw new USBTimeoutException("Transfer in aborted due to timeout"); @@ -400,8 +402,8 @@ public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { } else { // interrupt transfer with timeout - var transferTimeout = new TransferTimeout(endpointInfo, timeout); - ret = IoKitUSB.ReadPipe(endpointInfo.interfaceAddress(), endpointInfo.pipeIndex, nativeData.address(), sizeHolder.address()); + var transferTimeout = new TransferTimeout(endpoint, timeout); + ret = IoKitUSB.ReadPipe(endpoint.interfaceAddress(), endpoint.pipeIndex, nativeData.address(), sizeHolder.address()); if (ret == IOKit.kIOReturnAborted()) throw new USBTimeoutException("Transfer in aborted due to timeout"); transferTimeout.markCompleted(); @@ -443,7 +445,7 @@ MemoryAddress asAddress() { } } - record EndpointInfo(long interfaceAddr, byte pipeIndex, USBTransferType transferType) { + record EndpointInfo(long interfaceAddr, byte pipeIndex, USBTransferType transferType, int packetSize) { MemoryAddress interfaceAddress() { return ofLong(interfaceAddr); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 08cf029d..c7d2cc62 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -277,7 +277,7 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { } @Override - public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { + public byte[] transferIn(int endpointNumber, int timeout) { var endpoint = getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); @@ -289,7 +289,7 @@ public byte[] transferIn(int endpointNumber, int maxLength, int timeout) { throwLastError("Setting timeout failed"); // create native heap buffer for data - var buffer = session.allocate(maxLength); + var buffer = session.allocate(endpoint.packetSize()); var lengthHolder = session.allocate(JAVA_INT); // receive data diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index b5ff79c4..a52f0ec6 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -108,7 +108,7 @@ private static void resetDevice() { // drain loopback data while (true) { try { - testDevice.transferIn(LOOPBACK_EP_IN, LOOPBACK_MAX_PACKET_SIZE, 1); + testDevice.transferIn(LOOPBACK_EP_IN, 1); } catch (USBTimeoutException e) { break; } @@ -118,7 +118,7 @@ private static void resetDevice() { if (isLoopbackDevice()) { while (true) { try { - testDevice.transferIn(ECHO_EP_IN, ECHO_MAX_PACKET_SIZE, 1); + testDevice.transferIn(ECHO_EP_IN, 1); } catch (USBTimeoutException e) { break; } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java index dbd89a27..94d0b72d 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java @@ -24,7 +24,7 @@ public class TimeoutTest extends TestDeviceBase { @Timeout(value = 1, unit = TimeUnit.SECONDS) void bulkTransferIn_timesOut() { assertThrows(USBTimeoutException.class, () -> { - testDevice.transferIn(LOOPBACK_EP_IN, 64, 200); + testDevice.transferIn(LOOPBACK_EP_IN, 200); }); } @@ -34,7 +34,7 @@ void bulkTransfer_doesNotTimeOut() { byte[] data = generateRandomBytes(20, 7280277392L); testDevice.transferOut(LOOPBACK_EP_OUT, data); - byte[] received = testDevice.transferIn(LOOPBACK_EP_IN, 64, 200); + byte[] received = testDevice.transferIn(LOOPBACK_EP_IN, 200); assertArrayEquals(data, received); } @@ -57,7 +57,7 @@ void bulkTransferOut_timesOut() { // drain data in loopback loop while (true) { try { - testDevice.transferIn(LOOPBACK_EP_IN, 64, 200); + testDevice.transferIn(LOOPBACK_EP_IN, 200); } catch (USBTimeoutException e) { break; } @@ -71,7 +71,7 @@ void interruptTransferIn_timesOut() { "Interrupt transfer only supported by loopback test device"); assertThrows(USBTimeoutException.class, () -> { - testDevice.transferIn(ECHO_EP_IN, 16, 200); + testDevice.transferIn(ECHO_EP_IN, 200); }); } @@ -84,11 +84,11 @@ void interruptTransfer_doesNotTimeOut() { testDevice.transferOut(ECHO_EP_OUT, sampleData, 200); // receive first echo - byte[] echo = testDevice.transferIn(ECHO_EP_IN, ECHO_MAX_PACKET_SIZE, 200); + byte[] echo = testDevice.transferIn(ECHO_EP_IN, 200); assertArrayEquals(sampleData, echo); // receive second echo - echo = testDevice.transferIn(ECHO_EP_IN, ECHO_MAX_PACKET_SIZE, 200); + echo = testDevice.transferIn(ECHO_EP_IN, 200); assertArrayEquals(sampleData, echo); } } From 48c633bbfa8c7f03504161f143671018d1ec8021 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 22 Oct 2022 15:22:52 +0200 Subject: [PATCH 134/433] Minor cleanup --- .../net/codecrete/usb/macos/TransferTimeout.java | 6 +++--- .../codecrete/usb/AlternateInterfaceTest.java | 16 ++++------------ .../test/java/net/codecrete/usb/StallTest.java | 14 +++++--------- .../test/java/net/codecrete/usb/StreamTest.java | 4 ++-- .../test/java/net/codecrete/usb/TimeoutTest.java | 8 ++------ 5 files changed, 16 insertions(+), 32 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java index edc3d465..e736f505 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java @@ -59,9 +59,9 @@ static synchronized ScheduledExecutorService getScheduledExecutorService() { return scheduledExecutorService; } - ScheduledFuture future; - MacosUSBDevice.EndpointInfo endpointInfo; - boolean completed; + private final ScheduledFuture future; + private final MacosUSBDevice.EndpointInfo endpointInfo; + private boolean completed; private static ScheduledExecutorService scheduledExecutorService; } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java index b1ecd715..df8beea7 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java @@ -38,13 +38,9 @@ void selectAlternateIntf_succeeds() { @Test void selectInvalidAlternateIntf_fails() { - assertThrows(USBException.class, () -> { - testDevice.selectAlternateSetting(1, 0); - }); + assertThrows(USBException.class, () -> testDevice.selectAlternateSetting(1, 0)); - assertThrows(USBException.class, () -> { - testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 2); - }); + assertThrows(USBException.class, () -> testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 2)); } @Test @@ -61,12 +57,8 @@ void transferOnValidEndpoint_succeeds() { void transferOnInvalidEndpoint_fails() { testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 1); - assertThrows(USBException.class, () -> { - testDevice.transferOut(ECHO_EP_OUT, new byte[] { 1, 2, 3 }); - }); + assertThrows(USBException.class, () -> testDevice.transferOut(ECHO_EP_OUT, new byte[] { 1, 2, 3 })); - assertThrows(USBException.class, () -> { - testDevice.transferIn(ECHO_EP_IN, 16); - }); + assertThrows(USBException.class, () -> testDevice.transferIn(ECHO_EP_IN, 16)); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java index 64cfb93f..a7f91361 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java @@ -21,9 +21,7 @@ void stalledBulkTransferOut_recovers() { haltEndpoint(USBDirection.OUT, LOOPBACK_EP_OUT); byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - assertThrows(USBStallException.class, () -> { - testDevice.transferOut(LOOPBACK_EP_OUT, data); - }); + assertThrows(USBStallException.class, () -> testDevice.transferOut(LOOPBACK_EP_OUT, data)); testDevice.clearHalt(USBDirection.OUT, LOOPBACK_EP_OUT); @@ -36,9 +34,7 @@ void stalledBulkTransferOut_recovers() { void stalledBulkTransferIn_recovers() { haltEndpoint(USBDirection.IN, LOOPBACK_EP_IN); - assertThrows(USBStallException.class, () -> { - testDevice.transferIn(LOOPBACK_EP_IN, LOOPBACK_MAX_PACKET_SIZE); - }); + assertThrows(USBStallException.class, () -> testDevice.transferIn(LOOPBACK_EP_IN, LOOPBACK_MAX_PACKET_SIZE)); testDevice.clearHalt(USBDirection.IN, LOOPBACK_EP_IN); @@ -50,9 +46,9 @@ void stalledBulkTransferIn_recovers() { @Test void invalidControlTransfer_throws() { - assertThrows(USBStallException.class, () -> { - testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x08, (short) 0, (short) interfaceNumber), 2); - }); + assertThrows(USBStallException.class, () -> testDevice.controlTransferIn( + new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x08, + (short) 0, (short) interfaceNumber), 2)); } void haltEndpoint(USBDirection direction, int endpointNumber) { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java index 4b456f76..665d365f 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java @@ -39,7 +39,7 @@ void mediumTransfer_succeeds() { } @Test - void transferWithZLP_succeeds() throws Throwable { + void transferWithZLP_succeeds() { final byte[] sampleData = generateRandomBytes(2 * LOOPBACK_MAX_PACKET_SIZE, 197007894); var writer = CompletableFuture.runAsync(() -> { testDevice.transferOut(LOOPBACK_EP_OUT, Arrays.copyOfRange(sampleData, 0, LOOPBACK_MAX_PACKET_SIZE)); @@ -66,7 +66,7 @@ void largeTransferSmallChunks_succeeds() { } @Test - void largeTransferBigChunks_succeeds() throws Throwable { + void largeTransferBigChunks_succeeds() { final int numBytes = 230763; byte[] sampleData = generateRandomBytes(numBytes, 3829007493L); var writer = CompletableFuture.runAsync(() -> writeBytes(sampleData, 150)); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java index 94d0b72d..c4dac1de 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java @@ -23,9 +23,7 @@ public class TimeoutTest extends TestDeviceBase { @Test @Timeout(value = 1, unit = TimeUnit.SECONDS) void bulkTransferIn_timesOut() { - assertThrows(USBTimeoutException.class, () -> { - testDevice.transferIn(LOOPBACK_EP_IN, 200); - }); + assertThrows(USBTimeoutException.class, () -> testDevice.transferIn(LOOPBACK_EP_IN, 200)); } @Test @@ -70,9 +68,7 @@ void interruptTransferIn_timesOut() { Assumptions.assumeTrue(isLoopbackDevice(), "Interrupt transfer only supported by loopback test device"); - assertThrows(USBTimeoutException.class, () -> { - testDevice.transferIn(ECHO_EP_IN, 200); - }); + assertThrows(USBTimeoutException.class, () -> testDevice.transferIn(ECHO_EP_IN, 200)); } @Test From dc2597d646fdabccc4fa5091b5ca399f1dc123fb Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 22 Oct 2022 15:36:48 +0200 Subject: [PATCH 135/433] ZLP handling for composite test device --- .../composite-stm32/bin/blackpill-f401cc.bin | Bin 11596 -> 11620 bytes .../composite-stm32/bin/blackpill-f411ce.bin | Bin 11600 -> 11624 bytes .../composite-stm32/bin/bluepill-f103c8.bin | Bin 10156 -> 10180 bytes test-devices/composite-stm32/src/main.c | 5 +++++ .../loopback-stm32/bin/blackpill-f401cc.bin | Bin 10592 -> 10616 bytes .../loopback-stm32/bin/blackpill-f411ce.bin | Bin 10596 -> 10620 bytes .../loopback-stm32/bin/bluepill-f103c8.bin | Bin 8844 -> 8868 bytes 7 files changed, 5 insertions(+) diff --git a/test-devices/composite-stm32/bin/blackpill-f401cc.bin b/test-devices/composite-stm32/bin/blackpill-f401cc.bin index 652cb537176bcd2b5ec0eaf3a1b6fb68b593d556..ae324548b89dc3edb59d1c37349f4befb7b06681 100755 GIT binary patch delta 766 zcmZuvT}TvB6h3!$*15a>kcsHFsdslZr)<+obH%_lX?CSxjp#u`N}>n~T7#$_78a8r zA|ft5L|}*%SwybWBKxo`1W^wPN<;_+Js9{RjabYMx=!bkzIEaI&UfxT^PMwyW_Dm{ zVCo&I>1zT?(~c9~l%v-XeY*xpngv`c0PEumq^I=a1{gC|JOV&inEND7F6(KjSt7Ui zPr0i9+7m_Y1r;j}S(2t^h?ZRrg~jysnNU{v*yi;dQKk72L_A`fS8}!)yvGwtGg0^(B|w(>f>Pn~*o4unZ94gi z(oSyc4RqaA)}a8MCBQx*b_DeUJ2gT&^cxj7<%T=EfDR*KRX_)~Vz3(MGta-h2-rZ@u~hj8&BV_l zmS`}9`LO=S`&A+;pR4_hJYLr%blqWO!o0{etcs|58#_lZJodF?;B)@d$iBcs7owX2bs<)_rXp^jrw|E*uNdfe N?g}=N5By-z`xjfu=uQ9t delta 774 zcmZuvT}TvB6h3!m*1fA4YqIES=G|Sz^=DBiSw+OPrP*C93VNtDA|rf?V0;KMs5X0u z9zy8SgFRGGL=uwQw3QFbKqVFUU`5Ej2`SWrFrhR%q)z9SzIEX{-#KT#``yExyF55Q zIP-$kb+rPeIeDNqE2re-vo*-jJm3lgurB_I#LLqgV7{`o1OQ=S9*{UWrst$~i45@- zr7t~V0MzHol4J_Z@K(O4bezkMGcaG;v01E`G?{66Vq}7%_t#)zsOt$y6{OZB-pUYC0VdAm(5ZP(5i6Wn)2U zO62!#X-ZN>X4)b?cJ#1ij!$1B$H zIz@GRn@9K^cRQ)%bM8>x0`AfhT7s%H=U3l)knnpycfF9arUp3Gh{(rr8%;S1KAETeu`n?gL$^ej>lb?%9SKO53H^^GTs~=%!2=VIEfhZDR2_DDT9h$)S zF@(8Z*RY1RdPS34DQD=ig9g2^^*!l)jd%JEv5f!rE6%ZqXr@4aA{P*1#vdM_-K9W> S5uP%jb371fBGWt-sr>^{U*}2y diff --git a/test-devices/composite-stm32/bin/blackpill-f411ce.bin b/test-devices/composite-stm32/bin/blackpill-f411ce.bin index 1cd4ed5b4e8a2111676a9da22442410722250361..30c116f80a570aea73f41f8b023394a8f4a184d2 100755 GIT binary patch delta 773 zcmZuuT}TvB82#?-%8_WARktw z9wH(xJwymd(pg}jQWHnOTRINB|)*&foauM_EQ=lFPPWv9*d+T zr957S8Kf|OA($1FhUBXiC!YMWz>R6njd{LccWwmH(P0WoFin)qb|h-e+?*16%~M5Y;TNNmT^O=h*zbibs$&jIu^0r?~1L|E&nQV8kO z?p5Cv0}tzf&LBo>fZizbnOdL=o};y4)RUUKwwJiaFh&0hxu}NEy{)a$9Y~$ottc%`OOMA~YhQesx zf}A)Er0&|6ycqH8f^7|1jfGf~Tth-yk330`o;P(Pu?^oS)`0&B)|4N$R?@tS(OTh@ zLv)?TykkVQ%GM90>l=R89O9P%@(#|ji?~FAx)6KCStTdXtB3?5PzrR5xxy_CpQ`Xb RN+4H28Qv$yy~SH`z(&(%h0x=SF>HGV=FgQOe~hTHQb$*MASnqq@a56AzBY11s2+4 zgv5csUJ8mpdU0J=35`KLq);IJAtZzzgtiCaM%3MK^Y*(m-@5Sme!u7NJKuA-h15!F z;T7T`zKCt4UohTqrULrQa#{rtlo0m|98YPBLXUtKc~KmeujT=~S!WXGK@V=_N@DMY z%!~s13m&t%!cWV#h4GTOxxWq+mSsuMZ&Zhaj#Z?I2j$+ys81Y4C0Afk&~Nc+TVP;c zRY`#UWUKkuaoy~N4%Aa6py|2t`ApO&%vFn|HI2!mQ?o z_em~X=Oa?QsniV&l4|LyftR<&?T z1U)fo(Kq1x^?G1^wZ;iPB}Wdf(Xd2^1H=dwSwtvXd)w>(`48=<>=ZmxR0g%rx?qgf z<66`1uL8PxanC2xoVVM`-hR?{rA>B+fr&=}TTg#1i3j4kQ1^yBt-7@n$~i>0mgyKI z<3-;|(xJ{-(hr@KwT`Y|RI7OclGxBiE!zaOz1{C{;5GfzC1PCwWtHCXjR-Sfzsc7K a>zNyNU_%aI6GVd(*fRHr1DN4s;kLix8_Tra1Ki(pOgWed)dE+uY8di<+|DRa#i~;BD?;{{-iDo-eANwJ3I+ zbR<2B_v%Z6E?#iB(pMEe+`ef-RQfc9#sS-E99C-}wpcZRH!7|1y^R3GgW@q1I3G^(>lgwhUv;37qbq z#%2RqN4}wv;CrjKtN$07k!=r1z5z5QtsxHZq7E8!2e$wU#>1|4m+~M&=shE={gK-q yVYAEFi+VLYkT=6%ec|IC|D+1J_X zUP2zQC>g|kj3nd*3yjlNE`67kh(@YxR0xuf+GSy!Tr7RC&8}{nmJTpf-<%;8FkEZR zjuacOO{rkKvyu(0RH0nh^HMJac<+VfsGjdg-Dwe2TBjK>uJsa;O-lsN9$K+R^CwLv z1L7F3Z?UKpj1TwJ6d3o{yeE7oeaEwg9fO_380i2i%GQNiG9XlV{=^b0LW*aG#rIci zMml`vde1f=+uYSQ3p&5`DB`ZmnJwtL`se9LL|0S(+T>el{Vle61=Vg;-_~JWZ<{xD z5)l@skX+g}^EmN27I!>XF6{;!095Wuf?^Ibxpb1PIF5Ku;R&yPhyKMD8+Gm@c{bq; z?udnf=F+(|P0{*5YEBjxZ8KyOl{RhD!|Kk1#G|#H^Rlbu0Q!}H`WZQ^&AN{f($ZX8 z?@1wX0O*Pz=&S;CxgRTDphNw94)gC?)0-el8%>Nh{0L!O?i(u1<3AL?isDDed*llm zaTfZ$jrxD_hF0|Z1ZCKXqxBcRz(R9bt8MENQqtaR|0X)}d{C{Zu1c-~rW;Ia#n3!C q;K$Z3WIujh5xwppOUN^12I1Ca3iKDE$Uqy&1e*+pNt9K>gMR@R1mcAN diff --git a/test-devices/composite-stm32/src/main.c b/test-devices/composite-stm32/src/main.c index 47b50e19..10f12572 100644 --- a/test-devices/composite-stm32/src/main.c +++ b/test-devices/composite-stm32/src/main.c @@ -129,6 +129,11 @@ void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes) { loopback_check_tx(); loopback_check_rx(); + + // check ZLP + if ((sent_bytes & (BULK_MAX_PACKET_SIZE - 1)) == 0 + && !cust_vendor_is_transmitting(ep_addr)) + cust_vendor_start_transmit(EP_LOOPBACK_TX, NULL, 0); } // Invoked when interface has been opened diff --git a/test-devices/loopback-stm32/bin/blackpill-f401cc.bin b/test-devices/loopback-stm32/bin/blackpill-f401cc.bin index e5b18a7bf37e57d0163bca4a964196b63099d6b7..2f8fcc6e86ce3b2831a4e0e0d25ac231104f1d79 100755 GIT binary patch delta 795 zcmZuvUr19?7(eIU-R-O;TWm9JTf1|{wk#C1G#ojSw%HWZvOiQTkjjUI(NhqCv!ur! z4iXYQhy?Yd^EP6|8uSOBMy{wZk!BJp6kL(G+nk-gTl&_4-|u(6-*@kKzVmVNy@lSX zC)m;CMT8{zh%Lc)@ZrfdG(^$}mKPzhiRN&7#itUIv&C2lAuOJxE{@_(DaqAy_&oil zX*+9tfsiw42;;{{o-L;fnuh+wu!!X0QXmD9$c+u{eUurhQN3#=Vd_Fbv%Zf*B1w`k zl3U7c-feRja+gaDsX&dU1B>Zp50)YUOo`Hj)@nG+>?!qYrgYPs z)@}4;m}1BX5!*mriYW&vuS-;yVYp!!F9>M1Dy{{b>O&NIk}S3=%he;rA?6 zB9a57&45iEw;-}%{pUT0{ab0o62cWl9U}5il;01!Lg%dRLp|`r4ZwZC3=~i?x#?}i z|I>5Qfl3>v6$m0$LQho%aa?*(wZvgRjoaP>_u1>zy}i-l_raYPQC<^4c-NVC1x<@v z=J=POv5=qU>^revTCqnlNXPDG5E^%$0RG^-3w%k80>2UaA?Oq&ZW-j z7o^0k0Hqoqk|KONADr5NQ5pkW3V`fp3F5cUr9hwG90~vs`8X@%7^zb=u9_n!*ovjO zo1XzF)v|-+3FvRPVo6I)U*xt7`i+z?ij~ZTM~^&?kCtb=t0`f+CuvDnaUfHT20^dd zYF4rq2=*?dYNEb!OFNNcYt#pNGaD94vRhs`(BrXR$tDG_^J7|W1KqWqdkV_V=w=P* zx7f09k|?ag+BD)w*fDb={jgPu%WXxGvFA3d3%5+8%Z#l#e5P?NKCXxfp~KmqsY#Rb zl4;zGJ7Sp^G%=WiH~vgpLr`9f(;cQex|?69I!hj4W_PqW2f9h9H7f76S9fP(-cD<;L45(Vs zcaC^iSo(rI=&sD{-L=T`Zs~x>3)B(g9vSP*}M1 zEb@BkUF2c87kN?c!*)yA28OHkp7*@H4zu>rz--E@FoVDLf&Esh^M)zV5k!{_=pbT@ N)q5+*0_*Wge*q|+@~Qv; diff --git a/test-devices/loopback-stm32/bin/blackpill-f411ce.bin b/test-devices/loopback-stm32/bin/blackpill-f411ce.bin index 3c24192618332fa2e1be671168fa5f2758e9ef01..ec368a08f5f3eb3d31e738973a36666199a1824a 100755 GIT binary patch delta 748 zcmZutUr19?82`@Qz1vwPTWpDQGw)oo4HFF`6(Mg)+iZzuN%{~IgfJ+WJ@qD8BYf)N zJV``|^x&IzS#^VTsU9jqaEgRVl=Me^5H5sVb+glVL*IJ%{eIu~o$vhko%5ro*faf- zkY=V4Kk_1JFa5j=#_Ucy4j{;VtVUp@Th)Ymfef$>vCZdt4N#RWNsuWp=8Cy(v0-p# zR0d;|os~Rww|AxKYujSsga9(l(gYaI#kRtY)U#ZWV_*dLTo)nOW$*?t9u30JXYdR!JMl3wDWyg9gq%Aky)4oW^L@7klTl&2e+( z50Pn(n^|?7rihfc1Km;goL42Xs`k3-2};KO)mF1s26Pee#)H_`r(U3Bzt*u{P{+J+ zQo82=YHY%{lc<~Q%h6CvFD{KBo*+JsE_rR$4N$=DE}@H zg=PE;$o+v@s}3|GYXQGc!EX_hKq~s?x5egmL$JL?O~(~=Gms)gQ9F+{p|DKVW#px* zhsZbN6!J%T5RdDEztLO`9)E8u?MANyTwz<`HE9{Y?-yH*)E^ngK#vf^PM~9m$1E5P KlP%T}_5TG_@cEzs delta 721 zcmZuuT}V@57=FKVcD8To@WgS>wb_oEc*YEc5h)f<#hs-=WJFkmg;Yie^QJDkh$Ycg zbn#tu5k_5wcUy-+r#Ou=h=|M)LR~~jiS9x;5^>bcPVfAIF1mQ0=X?L2@2@oUb140c z5Si&DfILt7JnuKa{IH%>0XR9vnmI-~G@WbXNP-m{-G2ThKqy<8Ak$#JDH&^y_R-8O z8O&>}N01I&+7Qy`)*QuF4rH382{2nr-Act5f*ofz+VxnY<0z4hWf}vso27*M%AV&U z=6I|}*t8IqW{YwhOz&p(F=#k$+U;Q8V2eUOQCP&;byLiH(DQ!rQLmDd<8_(TQ#Z!G zl5L%`jb$-rTUT?FiYqS+NMq%gbV=uJ>v~Q!$|tJXI+bk=V=vw61rW2YL>2B>C^`qB zaW8fc*g<{U>+C;syizsCu}!B`9nIO6FDDEJ#v;0H^|FvF<6l+)FAMVSE~JT1LL#Y( ztl;W%Kg4P|8fFJ+l+3Uzw58!Q=F*6ynpA0=X8rLQH$P`vOMi$=4cmI9W#|YIbSKaS z&0BF=An&yC>NbKhC4S?ZKh^>@5YrN3NAK1EEqJ$cPjLN0dt9Ru&!P*cxdPw)sPpW% zx2f|84qQguL1<`D#)F;QZu~!0wG*`gPFO`F!Y1leGOp=$KREoHslX@XiD0C>4n~pl z!2t3~&_@(as2?FH7xx`PVN;=#$g81y$SHXQc|jh%sk4H h@ERX$maQvodr}nWBx2YNbOLdkb%tBWS9T#B_zR0F=!yUU diff --git a/test-devices/loopback-stm32/bin/bluepill-f103c8.bin b/test-devices/loopback-stm32/bin/bluepill-f103c8.bin index ee8d6eab3cb2ad4da3dc4781508dfe2725f00b67..154e0977909f4e69e248e451682e845d2078d216 100755 GIT binary patch delta 674 zcmZutOK4L;6rFjWWYU8i zmRV&fD%f4)kVVAsKoM~v7`hNC72Q}t3U8yYNvh+0wb{8ibMHAbbMBeBpLmj3I*9Q! z9mEQ(89ZiV9O+kDg;bd?V1|n{A%yTdXl!Kx!n7^oO0XNY5t>dl%c$dgD8Z$5k<7 z@^LyS`R&;kZdJ;Nz=!Chw6`zT2_%u8+jM4~r(7pda6;!%q`##LQUc$kAEl8?O4AFz z?e?8x5lu=CR3ANe0YBg2#w6#)EPrh2ZJJqDT0*i26Wwu~H2M4b?TEE$a_NLOk4L=I z+_^jVw1aa$}0l$UgfhAJ}r>#ss}3hg@O!54$FhEBOO;ZXBgduJ%V% z1P?`lt_u!{1(YtNPScX*xb1Tg5tCKuJ4*~J^tUA(+yysu&YJZq!)9I)&wujL1{ANR~zXfR%Q{FqEp}hqzDaMZ^a9=>~ZJ)m0B7L)*Opy?rNp zzC4k2M=$)_h#O_`M!A& zzZIX@PDp~c5+ANf5_LYb!5mr2c4v5==p@bK!WNR%PYXk2F!ju~Du!(>830X_H3>2f zrnp>Ol)^)Wt9~%gmt#|?{KB2lZI6smt-5!rOeY2wrOG7%{A`jXz`S0GhSt3&cy_ED zo+{3>SWFX>RUPH6Qe#cWQ$>@KBI*|2CpCM66@M3){mZrcYY)`*Lg1ijhryiYc_~iL z@V8R?6=lwixj)PIJ41%QtD%s4;zWI~lU30E0xfJIB8`A|%M`0_=4!ScfWUEC_J2ezOB`=}sR>#PS@(<=Xj{Fg`n;Mq&uc?U4_ z2YjBzupDnzgL}@R>n>s%QNn~OUajt}>HpP>`VBQG(0ds8m>22~lYmY)$bzu2QLk Date: Sat, 22 Oct 2022 17:16:11 +0200 Subject: [PATCH 136/433] Fix old use of transferIn() --- .../java/net/codecrete/usb/common/EndpointInputStream.java | 6 ++---- .../main/java/net/codecrete/usb/common/USBDeviceImpl.java | 5 ++--- .../test/java/net/codecrete/usb/AlternateInterfaceTest.java | 4 ++-- .../src/test/java/net/codecrete/usb/BulkTransferTest.java | 6 +++--- .../test/java/net/codecrete/usb/InterruptTransferTest.java | 4 ++-- .../test/java/net/codecrete/usb/InvalidOperationTest.java | 6 +++--- .../src/test/java/net/codecrete/usb/StallTest.java | 6 +++--- 7 files changed, 17 insertions(+), 20 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index e50ca09e..2992d55d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -22,14 +22,12 @@ public class EndpointInputStream extends InputStream { private USBDevice device_; private final int endpointNumber_; - private final int packetSize_; private byte[] packet_; private int readOffset_; - EndpointInputStream(USBDevice device, int endpointNumber, int packetSize) { + EndpointInputStream(USBDevice device, int endpointNumber) { device_ = device; endpointNumber_ = endpointNumber; - packetSize_ = packetSize; } @Override @@ -72,7 +70,7 @@ private void receiveMoreData() throws IOException { readOffset_ = 0; // skip zero-length packets do { - packet_ = device_.transferIn(endpointNumber_, packetSize_); + packet_ = device_.transferIn(endpointNumber_); } while (packet_.length == 0); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 76d5aa26..74e063dd 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -333,9 +333,8 @@ public OutputStream openOutputStream(int endpointNumber) { @Override public InputStream openInputStream(int endpointNumber) { // check that endpoint number is valid - var endpointInfo = getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, null); - var endpoint = getInterface(endpointInfo.interfaceNumber).alternate().getEndpoint(endpointNumber, USBDirection.IN); - return new EndpointInputStream(this, endpointNumber, endpoint.packetSize()); + getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, null); + return new EndpointInputStream(this, endpointNumber); } @Override diff --git a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java index df8beea7..d13d4a6a 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java @@ -49,7 +49,7 @@ void transferOnValidEndpoint_succeeds() { byte[] sampleData = generateRandomBytes(12, 293872394); testDevice.transferOut(LOOPBACK_EP_OUT, sampleData); - var received = testDevice.transferIn(LOOPBACK_EP_IN, 64); + var received = testDevice.transferIn(LOOPBACK_EP_IN); assertArrayEquals(sampleData, received); } @@ -59,6 +59,6 @@ void transferOnInvalidEndpoint_fails() { assertThrows(USBException.class, () -> testDevice.transferOut(ECHO_EP_OUT, new byte[] { 1, 2, 3 })); - assertThrows(USBException.class, () -> testDevice.transferIn(ECHO_EP_IN, 16)); + assertThrows(USBException.class, () -> testDevice.transferIn(ECHO_EP_IN)); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java index ccf0ad1e..62b46b27 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java @@ -41,9 +41,9 @@ void mediumTransfer_succeeds() { void transferWithZLP_succeeds() { byte[] sampleData = generateRandomBytes(64, 97333894); writeBytes(sampleData); - byte[] data = testDevice.transferIn(LOOPBACK_EP_IN, LOOPBACK_MAX_PACKET_SIZE); + byte[] data = testDevice.transferIn(LOOPBACK_EP_IN); assertArrayEquals(sampleData, data); - data = testDevice.transferIn(LOOPBACK_EP_IN, LOOPBACK_MAX_PACKET_SIZE); + data = testDevice.transferIn(LOOPBACK_EP_IN); assertNotNull(data); assertEquals(0, data.length); } @@ -73,7 +73,7 @@ static byte[] readBytes(int numBytes) { var buffer = new ByteArrayOutputStream(); int bytesRead = 0; while (bytesRead < numBytes) { - byte[] data = testDevice.transferIn(LOOPBACK_EP_IN, LOOPBACK_MAX_PACKET_SIZE); + byte[] data = testDevice.transferIn(LOOPBACK_EP_IN); buffer.writeBytes(data); bytesRead += data.length; } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java index ec1a616c..d91d20e9 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java @@ -25,11 +25,11 @@ void smallTransfer_succeeds() { testDevice.transferOut(ECHO_EP_OUT, sampleData); // receive first echo - byte[] echo = testDevice.transferIn(ECHO_EP_IN, ECHO_MAX_PACKET_SIZE); + byte[] echo = testDevice.transferIn(ECHO_EP_IN); assertArrayEquals(sampleData, echo); // receive second echo - echo = testDevice.transferIn(ECHO_EP_IN, ECHO_MAX_PACKET_SIZE); + echo = testDevice.transferIn(ECHO_EP_IN); assertArrayEquals(sampleData, echo); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java index cb8e2e0d..41e3c1e5 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java @@ -40,10 +40,10 @@ void invalidEndpoint_throws() { Assertions.assertThrows(USBException.class, () -> testDevice.transferOut(4, data)); - Assertions.assertThrows(USBException.class, () -> testDevice.transferIn(1, 64)); + Assertions.assertThrows(USBException.class, () -> testDevice.transferIn(1)); - Assertions.assertThrows(USBException.class, () -> testDevice.transferIn(0, 64)); + Assertions.assertThrows(USBException.class, () -> testDevice.transferIn(0)); - Assertions.assertThrows(USBException.class, () -> testDevice.transferIn(5, 64)); + Assertions.assertThrows(USBException.class, () -> testDevice.transferIn(5)); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java index a7f91361..11620938 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java @@ -26,7 +26,7 @@ void stalledBulkTransferOut_recovers() { testDevice.clearHalt(USBDirection.OUT, LOOPBACK_EP_OUT); testDevice.transferOut(LOOPBACK_EP_OUT, data); - var receivedData = testDevice.transferIn(LOOPBACK_EP_IN, 20); + var receivedData = testDevice.transferIn(LOOPBACK_EP_IN); assertArrayEquals(data, receivedData); } @@ -34,13 +34,13 @@ void stalledBulkTransferOut_recovers() { void stalledBulkTransferIn_recovers() { haltEndpoint(USBDirection.IN, LOOPBACK_EP_IN); - assertThrows(USBStallException.class, () -> testDevice.transferIn(LOOPBACK_EP_IN, LOOPBACK_MAX_PACKET_SIZE)); + assertThrows(USBStallException.class, () -> testDevice.transferIn(LOOPBACK_EP_IN)); testDevice.clearHalt(USBDirection.IN, LOOPBACK_EP_IN); byte[] data = new byte[] { 9, 8, 7, 6, 5, 4, 3, 2 }; testDevice.transferOut(LOOPBACK_EP_OUT, data); - var receivedData = testDevice.transferIn(LOOPBACK_EP_IN, 20); + var receivedData = testDevice.transferIn(LOOPBACK_EP_IN); assertArrayEquals(data, receivedData); } From 2ebba9306ecbf9ec5a0e4fb0737211251a768ef9 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 22 Oct 2022 17:16:39 +0200 Subject: [PATCH 137/433] Upgrade version to 0.4.0 --- examples/bulk_transfer/README.md | 2 +- examples/bulk_transfer/pom.xml | 4 ++-- .../main/java/net/codecrete/usb/examples/BulkTransfer.java | 2 +- examples/enumerate/README.md | 2 +- examples/enumerate/pom.xml | 4 ++-- examples/monitor/README.md | 2 +- examples/monitor/pom.xml | 4 ++-- examples/stm_dfu/README.md | 2 +- examples/stm_dfu/pom.xml | 4 ++-- java-does-usb/pom.xml | 2 +- 10 files changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index 8168582c..1d6c4105 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -50,7 +50,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] --------------< net.codecrete.usb.examples:bulk-transfer >-------------- -[INFO] Building bulk-transfer 0.3-SNAPSHOT +[INFO] Building bulk-transfer 0.4.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ bulk-transfer --- diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index 30ae7f23..bdca1f9d 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples bulk-transfer - 0.3.0 + 0.4.0 bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.3.0 + 0.4.0 diff --git a/examples/bulk_transfer/src/main/java/net/codecrete/usb/examples/BulkTransfer.java b/examples/bulk_transfer/src/main/java/net/codecrete/usb/examples/BulkTransfer.java index 34a27e95..37e8f2e3 100644 --- a/examples/bulk_transfer/src/main/java/net/codecrete/usb/examples/BulkTransfer.java +++ b/examples/bulk_transfer/src/main/java/net/codecrete/usb/examples/BulkTransfer.java @@ -34,7 +34,7 @@ public static void main(String[] args) { device.transferOut(ENDPOINT_OUT, data); System.out.println(data.length + " bytes sent."); - data = device.transferIn(ENDPOINT_IN, 64); + data = device.transferIn(ENDPOINT_IN); System.out.println(data.length + " bytes received."); device.close(); diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index 0ad96ce1..cca63589 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -49,7 +49,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] ----------------< net.codecrete.usb.examples:enumerate >---------------- -[INFO] Building enumerate 0.3-SNAPSHOT +[INFO] Building enumerate 0.4.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ enumerate --- diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index 2e254974..efb357c2 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples enumerate - 0.3.0 + 0.4.0 enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.3.0 + 0.4.0 diff --git a/examples/monitor/README.md b/examples/monitor/README.md index 33acf3ba..b207c2a9 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -49,7 +49,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -----------------< net.codecrete.usb.examples:monitor >----------------- -[INFO] Building monitor 0.3-SNAPSHOT +[INFO] Building monitor 0.4.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ monitor --- diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index 6f0f8e1a..b54370a7 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples monitor - 0.3.0 + 0.4.0 monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.3.0 + 0.4.0 diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index 9f19a4dc..5b89c062 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -49,7 +49,7 @@ The result will be put in your local Maven repository. - Run the command below (adapting the file path depending on your specific board). ```shell -$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.3.1.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin +$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.4.0.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin DFU device found with serial 36C730037136. Target memory segment: Internal Flash Erasing page at 0x8000000 (size 0x4000) diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index e973c20b..f876b116 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples stm_dfu - 0.3.1 + 0.4.0 stm_dfu https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu @@ -13,7 +13,7 @@ net.codecrete.usb java-does-usb - 0.3.1-SNAPSHOT + 0.4.0 diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 4d59e801..d706ef0d 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 0.3.1-SNAPSHOT + 0.4.0 19 From 0bc9ec5c92364a864cafbefa4e16a1d8c4de8196 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 22 Oct 2022 18:21:24 +0200 Subject: [PATCH 138/433] Update README --- README.md | 106 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 64 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index d37de01b..46c5db82 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,14 @@ -# Java Does USB: USB library for Java +# Java Does USB: USB Library for Java [![javadoc](https://javadoc.io/badge2/net.codecrete.usb/java-does-usb/javadoc.svg)](https://javadoc.io/doc/net.codecrete.usb/java-does-usb) -*Java Does USB* is a library for working with USB devices from Java. It allows to query information about all conntected USB devices and to communicate with USB devices using custom / vendor specific protocols. (It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc.) - -The library uses the [Foreign Function & Memory API](https://github.com/openjdk/panama-foreign) to access native APIs of the underlying operating system. It only uses Java code and does not need JNI or any native third-party library. - -The Foreign Function & Memory API (aka as project Panama) is in preview and will be introduced in a future Java version. Currently, it can be tested with Java 19 Early Access (with preview features enabled). - - -## Prerequisite - -- Java 19, preview features enabled (available at https://www.azul.com/downloads/?package=jdk) -- Windows (x86 64-bit), macOS (x86 64-bit, ARM 64-bit) or Linux 64 bit (x86 64-bit, ARM 64-bit) - -It has been tested with Azul Zulu 19.0.77 EA 34. +*Java Does USB* is a library for working with USB devices. It allows to query information about all conntected USB devices and to communicate with USB devices using custom / vendor specific protocols. (It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc.) +The library uses the [Foreign Function & Memory API](https://github.com/openjdk/panama-foreign) to access native APIs of the underlying operating system. It only uses Java code and does not need JNI or any native third-party library. The *Foreign Function & Memory API* (aka as project Panama) is in preview and will be introduced in a future Java version. Currently, it can be tested with Java 19 (with preview features enabled). ## Features -### Implemented - - Single API for all operating systems (similar to WebUSB API) - Enumeration of USB devices - Control, bulk and interrupt transfers (optionally with timeout) @@ -30,7 +17,7 @@ It has been tested with Azul Zulu 19.0.77 EA 34. - Support for alternate interface settings, composite devices and interface association - Published on Maven Central -### To do +### Planned - Isochronous transfer @@ -41,21 +28,76 @@ It has been tested with Azul Zulu 19.0.77 EA 34. - Providing information about USB buses, controllers and hubs -## Platform-specific considerations +## Getting Started + +The library is available at Maven Central. To use it, just add it to your Maven or Gradle project. + +If you are using Maven, add the below dependency to your pom.xml: + +```xml + + net.codecrete.usb + java-does-usb + 0.4.0 + +``` + +If you are using Gradle, add the below dependency to your build.gradle file: + +```groovy +compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '0.4.0' +``` + +```java +package net.codecrete.usb.sample; + +import net.codecrete.usb.USB; + +public class EnumerateDevices { + + public static void main(String[] args) { + for (var device : USB.getAllDevices()) { + System.out.println(device); + } + } +} +``` + + +## Documentation + +- [Javadoc](https://javadoc.io/doc/net.codecrete.usb/java-does-usb) + + +## Examples + +- [Bulk Transfer](examples/bulk_transfer/) demonstrates how to find a USB device, open it and communicate using bulk transfer. +- [Enumeration](examples/enumerate/) lists all connected USB devices and displays information about interfaces and endpoints. +- [Monitor](examples/monitor/) lists the connected USB devices and then monitors for USB devices being connected and disconnnected. + + +## Prerequisite + +- Java 19, preview features enabled (available at https://www.azul.com/downloads/?package=jdk) +- Windows (x86 64-bit), macOS (x86 64-bit, ARM 64-bit) or Linux 64 bit (x86 64-bit, ARM 64-bit) + + + +## Platform-specific Considerations ### macOS -No special considerations apply. Using this library, a Java application can connect to any USB device and claim any interfaces that aren't claimed by an operating system driver or another application. +No special considerations apply. Using this library, a Java application can connect to any USB device and claim any interfaces that isn't claimed by an operating system driver or another application. ### Linux *libudev* is used to discover and monitor USB devices. It is closely tied to *systemd*. So the library only runs on Linux distributions with *systemd* and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfill this requirement. -Similar to macOS, a Java application can connect to any USB device and claim any interfaces that aren't claimed by an operating system driver or another application. +Similar to macOS, a Java application can connect to any USB device and claim any interfaces that isn't claimed by an operating system driver or another application. -Most Linux distributions by default set up user accounts without the permission to access USB devices directly. The *udev* system daemon is responsible for assigning permissions to USB devices. It can be configured to assign specific permissions or ownership. +Most Linux distributions by default set up user accounts without the permission to access USB devices directly. The *udev* system daemon is responsible for assigning permissions to USB devices. It can be configured to assign specific permissions or ownership: Create a file called `/etc/udev/rules.d/80-javadoesusb-udev.rules` with the below content: @@ -63,7 +105,7 @@ Create a file called `/etc/udev/rules.d/80-javadoesusb-udev.rules` with the belo SUBSYSTEM=="usb", ATTRS{idVendor}=="cafe", MODE="0666" ``` -This adds the rule to assign permission mode 0666 to all USB devices with vendor ID `0xCAFE`. This unregistered vendor ID is used by test device. +This adds the rule to assign permission mode 0666 to all USB devices with vendor ID `0xCAFE`. This unregistered vendor ID is used by the test devices. ### Windows @@ -85,20 +127,6 @@ The Foreign Function & Memory API has not been implemented for 32-bit operating -## Documentation - -- [Javadoc](https://javadoc.io/doc/net.codecrete.usb/java-does-usb) - - - -## Examples - -- [Bulk Transfer](examples/bulk_transfer/) demonstrates how to find a USB device, open it and communicate using bulk transfer. -- [Enumeration](examples/enumerate/) lists all connected USB devices and displays information about interfaces and endpoints. -- [Monitor](examples/monitor/) lists the connected USB devices and then monitors for USB devices being connected and disconnnected. - - - ## Code generation Many bindings for the native APIs have been generated with *jextract*. See the [jextract](java-does-usb/jextract) subdirectory for more information. @@ -126,9 +154,3 @@ Or (if modules are ignored): ``` --enable-preview --enable-native-access=ALL-UNNAMED ``` - -If you don't have the test device, you can get a glimpse at the library running the below command. It enumerates all connected USB devices. - -``` -MAVEN_OPTS="--enable-preview --enable-native-access=ALL-UNNAMED" mvn install exec:java -Dexec.classpathScope="test" -DskipTests -Dexec.mainClass="net.codecrete.usb.sample.EnumerateDevices" -``` From b7df92cd1bbe081a03ecb0c48778cff134009377 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sun, 23 Oct 2022 10:56:41 +0200 Subject: [PATCH 139/433] More README updates --- README.md | 1 + examples/bulk_transfer/README.md | 11 ----------- examples/enumerate/README.md | 11 ----------- examples/monitor/README.md | 11 ----------- examples/stm_dfu/README.md | 20 ++++++++++++++------ 5 files changed, 15 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 46c5db82..71c6d61a 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ public class EnumerateDevices { - [Bulk Transfer](examples/bulk_transfer/) demonstrates how to find a USB device, open it and communicate using bulk transfer. - [Enumeration](examples/enumerate/) lists all connected USB devices and displays information about interfaces and endpoints. - [Monitor](examples/monitor/) lists the connected USB devices and then monitors for USB devices being connected and disconnnected. +- [Device Firmware Upload (DFU) for STM32](examples/stm_dfu) uploads firmware to STM32 microcontrollers supporting the built-in DFU mode. ## Prerequisite diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index 1d6c4105..64386371 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -31,17 +31,6 @@ $ mvn -version If it is not present, install it, typically using package manager like *Homebrew* on macOS, *Chocolately* on Windows and *apt* on Linux. -### Create the *java-does-usb* library - -Since the *java-does-usb* library is not yet available on Maven Central, it must be built locally: - -```shell -$ cd JavaDoesUSB/java-does-usb -$ mvn install -``` - -The result will be put in your local Maven repository. - ### Run the sample ```shell diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index cca63589..acf5247d 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -30,17 +30,6 @@ $ mvn -version If it is not present, install it, typically using package manager like *Homebrew* on macOS, *Chocolately* on Windows and *apt* on Linux. -### Create the *java-does-usb* library - -Since the *java-does-usb* library is not yet available on Maven Central, it must be built locally: - -```shell -$ cd JavaDoesUSB/java-does-usb -$ mvn install -``` - -The result will be put in your local Maven repository. - ### Run the sample ```shell diff --git a/examples/monitor/README.md b/examples/monitor/README.md index b207c2a9..5f0c6d81 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -30,17 +30,6 @@ $ mvn -version If it is not present, install it, typically using package manager like *Homebrew* on macOS, *Chocolately* on Windows and *apt* on Linux. -### Create the *java-does-usb* library - -Since the *java-does-usb* library is not yet available on Maven Central, it must be built locally: - -```shell -$ cd JavaDoesUSB/java-does-usb -$ mvn install -``` - -The result will be put in your local Maven repository. - ### Run the sample ```shell diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index 5b89c062..25bd2c3e 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -34,19 +34,27 @@ If it is not present, install it, typically using package manager like *Homebrew ### Build the application -Since the *java-does-usb* library is not yet available on Maven Central, it must be built locally: - ```shell $ mvn clean package ``` -The result will be put in your local Maven repository. - -### Run the application +### Put the STM32 development board in DFU mode - Connect an STM32 development board (like a BlackPill board) to your computer while pressing the *Boot* button. - Ensure that it is DFU mode by checking macOS *System Information* or Windows *Device Manager*. The device should appear as "STM32 BOOTLOADER". -- Run the command below (adapting the file path depending on your specific board). + +On Windows, the *WinUSB* driver must be installed. See https://github.com/manuelbl/JavaDoesUSB/wiki/DFU-on-Windows for additional information. + +On many Linux distributions, the default permissions of USB devices do not allow access. To change it, create a file `/etc/udev/rules.d/50-stm-dfu.rules` with the below content: + +```text +SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE="0666" +``` + + +### Run the application + +Run the command below (adapting the file path depending on your specific board): ```shell $ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.4.0.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin From 2e939fe99cf376f094efe1602e9cb4f55adbd217 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sun, 23 Oct 2022 11:25:18 +0200 Subject: [PATCH 140/433] Fix issue with missing device version (MacBook Pro x86) --- .../java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 327d650d..d10a0a9f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -169,7 +169,7 @@ private USBDevice createDevice(Long entryID, int service, MemoryAddress deviceIn Integer usbVersion = IoKitHelper.getPropertyInt(service, "bcdUSB"); Integer deviceVersion = IoKitHelper.getPropertyInt(service, "bcdDevice"); //noinspection ConstantConditions - device.setVersions(usbVersion, deviceVersion); + device.setVersions(usbVersion, deviceVersion != null ? deviceVersion : 0); return device; } From 77801a46fee2b9aca64c49a1eae3688ec1ca2d50 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sun, 23 Oct 2022 14:05:57 +0200 Subject: [PATCH 141/433] Workaround for errno being overwritten by JVM (Linux) --- .../main/java/net/codecrete/usb/linux/LinuxUSBDevice.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index ef60c7e2..f82d6e94 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -226,6 +226,9 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { int err = IO.getErrno(); if (err == errno.ETIMEDOUT()) throw new USBTimeoutException("Transfer out aborted due to timeout"); + // TODO: remove below code if 'errno' is no longer overwritten by JVM + if (err == 2) + throw new USBTimeoutException("Transfer in aborted due to timeout"); throwException(err, "USB OUT transfer on endpoint %d failed", endpointNumber); } } @@ -246,6 +249,9 @@ public byte[] transferIn(int endpointNumber, int timeout) { int err = IO.getErrno(); if (err == errno.ETIMEDOUT()) throw new USBTimeoutException("Transfer in aborted due to timeout"); + // TODO: remove below code if 'errno' is no longer overwritten by JVM + if (err == 2) + throw new USBTimeoutException("Transfer in aborted due to timeout"); throwException(err, "USB IN transfer on endpoint %d failed", endpointNumber); } From b0071153c08aa91669d26bf2d43e6c0ce2588799 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 24 Oct 2022 14:45:49 +0200 Subject: [PATCH 142/433] Catch exception of notification handlers --- README.md | 2 +- .../src/main/java/net/codecrete/usb/USB.java | 5 +++++ .../net/codecrete/usb/USBControlTransfer.java | 9 +++++---- .../usb/common/USBDeviceRegistry.java | 20 +++++++++++++++++-- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 71c6d61a..304c1d94 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ *Java Does USB* is a library for working with USB devices. It allows to query information about all conntected USB devices and to communicate with USB devices using custom / vendor specific protocols. (It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc.) -The library uses the [Foreign Function & Memory API](https://github.com/openjdk/panama-foreign) to access native APIs of the underlying operating system. It only uses Java code and does not need JNI or any native third-party library. The *Foreign Function & Memory API* (aka as project Panama) is in preview and will be introduced in a future Java version. Currently, it can be tested with Java 19 (with preview features enabled). +The library uses the [Foreign Function & Memory API](https://github.com/openjdk/panama-foreign) to access native APIs of the underlying operating system. It only uses Java code and does not need JNI or any native third-party library. The *Foreign Function & Memory API* (aka as project Panama) is in preview and will be introduced in a future Java version. Currently, it can be used with Java 19 (with preview features enabled). ## Features diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USB.java b/java-does-usb/src/main/java/net/codecrete/usb/USB.java index d39007c0..ab37236e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USB.java @@ -117,6 +117,11 @@ public static void setOnDeviceConnected(Consumer handler) { /** * Sets the handler to be called when a USB device is disconnected. + *

+ * When the handler is called, the {@link USBDevice} instance has already been closed. + * Descriptive information (such as vendor and product ID, serial number, interfaces, endpoints) + * can still be accessed. + *

* * @param handler handler function, or {@code null} to remove a previous handler */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java index fee95c38..f354fdcd 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java @@ -10,7 +10,8 @@ /** * USB control transfer parameters. *

- * See USB specification for additional information + * See description of "Setup Data" in the chapter "USB Device Requests" of the + * USB specification for additional information. *

*

* For control requests directed to an interface or endpoint, @@ -19,9 +20,9 @@ * * @param requestType request type (bits 5 and 6 of {@code bmRequestType}) * @param recipient recipient (bits 0–4 of {@code bmRequestType}) - * @param request request code ({@code bRequest}) - * @param value value ({@code wValue}) - * @param index index ({@code wIndex}). + * @param request request code (value between 0 and 255, called {@code bRequest} in USB specification) + * @param value value (value between 0 and 65535, called {@code wValue} in USB specification) + * @param index index (value between 0 and 65535, called {@code wIndex} in USB specification). */ public record USBControlTransfer(USBRequestType requestType, USBRecipient recipient, int request, int value, int index) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index a7818bfe..92b9e466 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -82,13 +82,29 @@ public void setOnDeviceDisconnected(Consumer handler) { } protected void emitOnDeviceConnected(USBDevice device) { - if (onDeviceConnectedHandler != null) + if (onDeviceConnectedHandler == null) + return; + + try { onDeviceConnectedHandler.accept(device); + + } catch (Throwable e) { + System.err.println("Warning: [JavaDoesUSB] unhandled exception in 'onDeviceConnected' handler - ignoring"); + e.printStackTrace(System.err); + } } protected void emitOnDeviceDisconnected(USBDevice device) { - if (onDeviceDisconnectedHandler != null) + if (onDeviceDisconnectedHandler == null) + return; + + try { onDeviceDisconnectedHandler.accept(device); + + } catch (Throwable e) { + System.err.println("Warning: [JavaDoesUSB] unhandled exception in 'onDeviceDisconnected' handler - ignoring"); + e.printStackTrace(System.err); + } } /** From e41304a77db17721cabfe8e18a7638d314183e5f Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 24 Oct 2022 17:08:46 +0200 Subject: [PATCH 143/433] Reduce code size by using older IOKit interfaces (macOS) --- java-does-usb/jextract/macos/gen_macos.sh | 8 +- .../net/codecrete/usb/macos/IoKitUSB.java | 47 +- ...face.java => IOUSBDeviceInterface100.java} | 2 +- .../macos/gen/iokit/IOUSBDeviceStruct100.java | 1316 ++++++++++ .../macos/gen/iokit/IOUSBDeviceStruct942.java | 2317 ----------------- ...e.java => IOUSBInterfaceInterface190.java} | 2 +- ...t942.java => IOUSBInterfaceStruct190.java} | 2106 +++------------ 7 files changed, 1738 insertions(+), 4060 deletions(-) rename java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/{IOUSBDeviceInterface.java => IOUSBDeviceInterface100.java} (52%) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct100.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct942.java rename java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/{IOUSBInterfaceInterface.java => IOUSBInterfaceInterface190.java} (50%) rename java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/{IOUSBInterfaceStruct942.java => IOUSBInterfaceStruct190.java} (51%) diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index 034c2af1..949b727f 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -50,13 +50,13 @@ $JEXTRACT --source --output ../../src/main/java \ --include-function IORegistryEntryGetRegistryEntryID \ --include-function IOServiceAddMatchingNotification \ --include-function IOServiceMatching \ - --include-struct IOUSBDeviceStruct942 \ - --include-typedef IOUSBDeviceInterface \ + --include-struct IOUSBDeviceStruct100 \ + --include-typedef IOUSBDeviceInterface100 \ --include-macro kIOUSBFindInterfaceDontCare \ --include-typedef IOUSBFindInterfaceRequest \ --include-typedef IOUSBDevRequest \ - --include-struct IOUSBInterfaceStruct942 \ - --include-typedef IOUSBInterfaceInterface \ + --include-struct IOUSBInterfaceStruct190 \ + --include-typedef IOUSBInterfaceInterface190 \ --include-macro kIOUSBTransactionTimeout \ --include-macro kIOReturnAborted \ --include-macro kIOUSBPipeStalled \ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index e368c7e6..61b9f941 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -7,9 +7,8 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.macos.gen.iokit.IOUSBDeviceInterface; -import net.codecrete.usb.macos.gen.iokit.IOUSBInterfaceInterface; -import net.codecrete.usb.macos.gen.iokit.IOUSBInterfaceStruct942; +import net.codecrete.usb.macos.gen.iokit.IOUSBDeviceInterface100; +import net.codecrete.usb.macos.gen.iokit.IOUSBInterfaceInterface190; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; @@ -32,35 +31,35 @@ private static MemorySegment getVtable(MemoryAddress self, MemorySession session // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); public static int QueryInterface(MemoryAddress self, MemorySegment iid, MemoryAddress ppv) { try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface.QueryInterface(getVtable(self, session), session).apply(self, iid, ppv); + return IOUSBDeviceInterface100.QueryInterface(getVtable(self, session), session).apply(self, iid, ppv); } } // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); public static int AddRef(MemoryAddress self) { try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface.AddRef(getVtable(self, session), session).apply(self); + return IOUSBDeviceInterface100.AddRef(getVtable(self, session), session).apply(self); } } // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer) public static int Release(MemoryAddress self) { try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface.Release(getVtable(self, session), session).apply(self); + return IOUSBDeviceInterface100.Release(getVtable(self, session), session).apply(self); } } // IOReturn (*USBDeviceOpen)(void *self); public static int USBDeviceOpen(MemoryAddress self) { try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface.USBDeviceOpen(getVtable(self, session), session).apply(self); + return IOUSBDeviceInterface100.USBDeviceOpen(getVtable(self, session), session).apply(self); } } // IOReturn (*USBDeviceClose)(void *self); public static int USBDeviceClose(MemoryAddress self) { try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface.USBDeviceClose(getVtable(self, session), session).apply(self); + return IOUSBDeviceInterface100.USBDeviceClose(getVtable(self, session), session).apply(self); } } @@ -68,56 +67,56 @@ public static int USBDeviceClose(MemoryAddress self) { public static int GetConfigurationDescriptorPtr(MemoryAddress self, byte configIndex, MemoryAddress descHolder) { try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface.GetConfigurationDescriptorPtr(getVtable(self, session), session).apply(self, configIndex, descHolder); + return IOUSBDeviceInterface100.GetConfigurationDescriptorPtr(getVtable(self, session), session).apply(self, configIndex, descHolder); } } // IOReturn (*SetConfiguration)(void *self, UInt8 configNum); public static int SetConfiguration(MemoryAddress self, byte configValue) { try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface.SetConfiguration(getVtable(self, session), session).apply(self, configValue); + return IOUSBDeviceInterface100.SetConfiguration(getVtable(self, session), session).apply(self, configValue); } } // IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter); public static int CreateInterfaceIterator(MemoryAddress self, MemoryAddress req, MemoryAddress iter) { try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface.CreateInterfaceIterator(getVtable(self, session), session).apply(self, req, iter); + return IOUSBDeviceInterface100.CreateInterfaceIterator(getVtable(self, session), session).apply(self, req, iter); } } // IOReturn (*DeviceRequest)(void *self, IOUSBDevRequest *req); public static int DeviceRequest(MemoryAddress self, MemoryAddress deviceRequest) { try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface.DeviceRequest(getVtable(self, session), session).apply(self, deviceRequest); + return IOUSBDeviceInterface100.DeviceRequest(getVtable(self, session), session).apply(self, deviceRequest); } } // IOReturn (*USBInterfaceOpen)(void *self);; public static int USBInterfaceOpen(MemoryAddress self) { try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface.USBInterfaceOpen(getVtable(self, session), session).apply(self); + return IOUSBInterfaceInterface190.USBInterfaceOpen(getVtable(self, session), session).apply(self); } } // IOReturn (*USBInterfaceClose)(void *self);; public static int USBInterfaceClose(MemoryAddress self) { try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface.USBInterfaceClose(getVtable(self, session), session).apply(self); + return IOUSBInterfaceInterface190.USBInterfaceClose(getVtable(self, session), session).apply(self); } } // IOReturn (*GetInterfaceNumber)(void *self, UInt8 *intfNumber); public static int GetInterfaceNumber(MemoryAddress self, MemoryAddress intfNumberHolder) { try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface.GetInterfaceNumber(getVtable(self, session), session).apply(self, intfNumberHolder); + return IOUSBInterfaceInterface190.GetInterfaceNumber(getVtable(self, session), session).apply(self, intfNumberHolder); } } // IOReturn (*GetNumEndpoints)(void *self, UInt8 *intfNumEndpoints); public static int GetNumEndpoints(MemoryAddress self, MemoryAddress intfNumEndpointsHolder) { try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface.GetNumEndpoints(getVtable(self, session), session).apply(self, intfNumEndpointsHolder); + return IOUSBInterfaceInterface190.GetNumEndpoints(getVtable(self, session), session).apply(self, intfNumEndpointsHolder); } } @@ -127,7 +126,7 @@ public static int GetPipeProperties(MemoryAddress self, byte pipeRef, MemoryAddr MemoryAddress numberHolder, MemoryAddress transferTypeHolder, MemoryAddress maxPacketSizeHolder, MemoryAddress intervalHolder) { try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface.GetPipeProperties(getVtable(self, session), session).apply(self, pipeRef, + return IOUSBInterfaceInterface190.GetPipeProperties(getVtable(self, session), session).apply(self, pipeRef, directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); } } @@ -135,7 +134,7 @@ public static int GetPipeProperties(MemoryAddress self, byte pipeRef, MemoryAddr // IOReturn (*ReadPipe)(void *self, UInt8 pipeRef, void *buf, UInt32 *size); public static int ReadPipe(MemoryAddress self, byte pipeRef, MemoryAddress buf, MemoryAddress sizeHolder) { try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface.ReadPipe(getVtable(self, session), session) + return IOUSBInterfaceInterface190.ReadPipe(getVtable(self, session), session) .apply(self, pipeRef, buf, sizeHolder); } } @@ -143,7 +142,7 @@ public static int ReadPipe(MemoryAddress self, byte pipeRef, MemoryAddress buf, // IOReturn (* ReadPipeTO)(void* self, UInt8 pipeRef, void* buf, UInt32* size, UInt32 noDataTimeout, UInt32 completionTimeout); public static int ReadPipeTO(MemoryAddress self, byte pipeRef, MemoryAddress buf, MemoryAddress sizeHolder, int noDataTimeout, int completionTimeout) { try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface.ReadPipeTO(getVtable(self, session), session) + return IOUSBInterfaceInterface190.ReadPipeTO(getVtable(self, session), session) .apply(self, pipeRef, buf, sizeHolder, noDataTimeout, completionTimeout); } } @@ -151,35 +150,35 @@ public static int ReadPipeTO(MemoryAddress self, byte pipeRef, MemoryAddress buf // IOReturn (*WritePipe)(void *self, UInt8 pipeRef, void *buf, UInt32 size); public static int WritePipe(MemoryAddress self, byte pipeRef, MemoryAddress buf, int size) { try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface.WritePipe(getVtable(self, session), session).apply(self, pipeRef, buf, size); + return IOUSBInterfaceInterface190.WritePipe(getVtable(self, session), session).apply(self, pipeRef, buf, size); } } // IOReturn (* WritePipeTO)(void* self, UInt8 pipeRef, void* buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout); public static int WritePipeTO(MemoryAddress self, byte pipeRef, MemoryAddress buf, int size, int noDataTimeout, int completionTimeout) { try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface.WritePipeTO(getVtable(self, session), session).apply(self, pipeRef, buf, size, noDataTimeout, completionTimeout); + return IOUSBInterfaceInterface190.WritePipeTO(getVtable(self, session), session).apply(self, pipeRef, buf, size, noDataTimeout, completionTimeout); } } // IOReturn (* AbortPipe)(void* self, UInt8 pipeRef); public static int AbortPipe(MemoryAddress self, byte pipeRef) { try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface.AbortPipe(getVtable(self, session), session).apply(self, pipeRef); + return IOUSBInterfaceInterface190.AbortPipe(getVtable(self, session), session).apply(self, pipeRef); } } // IOReturn (*SetAlternateInterface)(void *self, UInt8 alternateSetting); public static int SetAlternateInterface(MemoryAddress self, byte alternateSetting) { try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface.SetAlternateInterface(getVtable(self, session), session).apply(self, alternateSetting); + return IOUSBInterfaceInterface190.SetAlternateInterface(getVtable(self, session), session).apply(self, alternateSetting); } } // IOReturn (* ClearPipeStallBothEnds)(void* self, UInt8 pipeRef); public static int ClearPipeStallBothEnds(MemoryAddress self, byte pipeRef) { try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceStruct942.ClearPipeStallBothEnds(getVtable(self, session), session).apply(self, pipeRef); + return IOUSBInterfaceInterface190.ClearPipeStallBothEnds(getVtable(self, session), session).apply(self, pipeRef); } } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface100.java similarity index 52% rename from java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface.java rename to java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface100.java index 955982bc..0944f0ea 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface100.java @@ -2,7 +2,7 @@ package net.codecrete.usb.macos.gen.iokit; -public class IOUSBDeviceInterface extends IOUSBDeviceStruct942 { +public class IOUSBDeviceInterface100 extends IOUSBDeviceStruct100 { } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct100.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct100.java new file mode 100644 index 00000000..e02bbfb7 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct100.java @@ -0,0 +1,1316 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +public class IOUSBDeviceStruct100 { + + static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_POINTER$LAYOUT.withName("_reserved"), + Constants$root.C_POINTER$LAYOUT.withName("QueryInterface"), + Constants$root.C_POINTER$LAYOUT.withName("AddRef"), + Constants$root.C_POINTER$LAYOUT.withName("Release"), + Constants$root.C_POINTER$LAYOUT.withName("CreateDeviceAsyncEventSource"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceAsyncEventSource"), + Constants$root.C_POINTER$LAYOUT.withName("CreateDeviceAsyncPort"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceAsyncPort"), + Constants$root.C_POINTER$LAYOUT.withName("USBDeviceOpen"), + Constants$root.C_POINTER$LAYOUT.withName("USBDeviceClose"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceClass"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceSubClass"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceProtocol"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceVendor"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceProduct"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceReleaseNumber"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceAddress"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceBusPowerAvailable"), + Constants$root.C_POINTER$LAYOUT.withName("GetDeviceSpeed"), + Constants$root.C_POINTER$LAYOUT.withName("GetNumberOfConfigurations"), + Constants$root.C_POINTER$LAYOUT.withName("GetLocationID"), + Constants$root.C_POINTER$LAYOUT.withName("GetConfigurationDescriptorPtr"), + Constants$root.C_POINTER$LAYOUT.withName("GetConfiguration"), + Constants$root.C_POINTER$LAYOUT.withName("SetConfiguration"), + Constants$root.C_POINTER$LAYOUT.withName("GetBusFrameNumber"), + Constants$root.C_POINTER$LAYOUT.withName("ResetDevice"), + Constants$root.C_POINTER$LAYOUT.withName("DeviceRequest"), + Constants$root.C_POINTER$LAYOUT.withName("DeviceRequestAsync"), + Constants$root.C_POINTER$LAYOUT.withName("CreateInterfaceIterator") + ).withName("IOUSBDeviceStruct100"); + public static MemoryLayout $LAYOUT() { + return IOUSBDeviceStruct100.$struct$LAYOUT; + } + static final VarHandle _reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("_reserved")); + public static VarHandle _reserved$VH() { + return IOUSBDeviceStruct100._reserved$VH; + } + public static MemoryAddress _reserved$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100._reserved$VH.get(seg); + } + public static void _reserved$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100._reserved$VH.set(seg, x); + } + public static MemoryAddress _reserved$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100._reserved$VH.get(seg.asSlice(index*sizeof())); + } + public static void _reserved$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100._reserved$VH.set(seg.asSlice(index*sizeof()), x); + } + static final FunctionDescriptor QueryInterface$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("byte0"), + Constants$root.C_CHAR$LAYOUT.withName("byte1"), + Constants$root.C_CHAR$LAYOUT.withName("byte2"), + Constants$root.C_CHAR$LAYOUT.withName("byte3"), + Constants$root.C_CHAR$LAYOUT.withName("byte4"), + Constants$root.C_CHAR$LAYOUT.withName("byte5"), + Constants$root.C_CHAR$LAYOUT.withName("byte6"), + Constants$root.C_CHAR$LAYOUT.withName("byte7"), + Constants$root.C_CHAR$LAYOUT.withName("byte8"), + Constants$root.C_CHAR$LAYOUT.withName("byte9"), + Constants$root.C_CHAR$LAYOUT.withName("byte10"), + Constants$root.C_CHAR$LAYOUT.withName("byte11"), + Constants$root.C_CHAR$LAYOUT.withName("byte12"), + Constants$root.C_CHAR$LAYOUT.withName("byte13"), + Constants$root.C_CHAR$LAYOUT.withName("byte14"), + Constants$root.C_CHAR$LAYOUT.withName("byte15") + ), + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle QueryInterface$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.QueryInterface$FUNC + ); + public interface QueryInterface { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(QueryInterface fi, MemorySession session) { + return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOUSBDeviceStruct100.QueryInterface$FUNC, session); + } + static QueryInterface ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBDeviceStruct100.QueryInterface$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle QueryInterface$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("QueryInterface")); + public static VarHandle QueryInterface$VH() { + return IOUSBDeviceStruct100.QueryInterface$VH; + } + public static MemoryAddress QueryInterface$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.QueryInterface$VH.get(seg); + } + public static void QueryInterface$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.QueryInterface$VH.set(seg, x); + } + public static MemoryAddress QueryInterface$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.QueryInterface$VH.get(seg.asSlice(index*sizeof())); + } + public static void QueryInterface$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.QueryInterface$VH.set(seg.asSlice(index*sizeof()), x); + } + public static QueryInterface QueryInterface (MemorySegment segment, MemorySession session) { + return QueryInterface.ofAddress(QueryInterface$get(segment), session); + } + static final FunctionDescriptor AddRef$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle AddRef$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.AddRef$FUNC + ); + public interface AddRef { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(AddRef fi, MemorySession session) { + return RuntimeHelper.upcallStub(AddRef.class, fi, IOUSBDeviceStruct100.AddRef$FUNC, session); + } + static AddRef ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBDeviceStruct100.AddRef$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle AddRef$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AddRef")); + public static VarHandle AddRef$VH() { + return IOUSBDeviceStruct100.AddRef$VH; + } + public static MemoryAddress AddRef$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.AddRef$VH.get(seg); + } + public static void AddRef$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.AddRef$VH.set(seg, x); + } + public static MemoryAddress AddRef$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.AddRef$VH.get(seg.asSlice(index*sizeof())); + } + public static void AddRef$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.AddRef$VH.set(seg.asSlice(index*sizeof()), x); + } + public static AddRef AddRef (MemorySegment segment, MemorySession session) { + return AddRef.ofAddress(AddRef$get(segment), session); + } + static final FunctionDescriptor Release$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle Release$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.Release$FUNC + ); + public interface Release { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(Release fi, MemorySession session) { + return RuntimeHelper.upcallStub(Release.class, fi, IOUSBDeviceStruct100.Release$FUNC, session); + } + static Release ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBDeviceStruct100.Release$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle Release$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Release")); + public static VarHandle Release$VH() { + return IOUSBDeviceStruct100.Release$VH; + } + public static MemoryAddress Release$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.Release$VH.get(seg); + } + public static void Release$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.Release$VH.set(seg, x); + } + public static MemoryAddress Release$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.Release$VH.get(seg.asSlice(index*sizeof())); + } + public static void Release$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.Release$VH.set(seg.asSlice(index*sizeof()), x); + } + public static Release Release (MemorySegment segment, MemorySession session) { + return Release.ofAddress(Release$get(segment), session); + } + static final FunctionDescriptor CreateDeviceAsyncEventSource$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CreateDeviceAsyncEventSource$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$FUNC + ); + public interface CreateDeviceAsyncEventSource { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(CreateDeviceAsyncEventSource fi, MemorySession session) { + return RuntimeHelper.upcallStub(CreateDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$FUNC, session); + } + static CreateDeviceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle CreateDeviceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateDeviceAsyncEventSource")); + public static VarHandle CreateDeviceAsyncEventSource$VH() { + return IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$VH; + } + public static MemoryAddress CreateDeviceAsyncEventSource$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$VH.get(seg); + } + public static void CreateDeviceAsyncEventSource$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$VH.set(seg, x); + } + public static MemoryAddress CreateDeviceAsyncEventSource$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + } + public static void CreateDeviceAsyncEventSource$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); + } + public static CreateDeviceAsyncEventSource CreateDeviceAsyncEventSource (MemorySegment segment, MemorySession session) { + return CreateDeviceAsyncEventSource.ofAddress(CreateDeviceAsyncEventSource$get(segment), session); + } + static final FunctionDescriptor GetDeviceAsyncEventSource$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceAsyncEventSource$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.GetDeviceAsyncEventSource$FUNC + ); + public interface GetDeviceAsyncEventSource { + + java.lang.foreign.Addressable apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(GetDeviceAsyncEventSource fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct100.GetDeviceAsyncEventSource$FUNC, session); + } + static GetDeviceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (java.lang.foreign.Addressable)(java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceAsyncEventSource$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncEventSource")); + public static VarHandle GetDeviceAsyncEventSource$VH() { + return IOUSBDeviceStruct100.GetDeviceAsyncEventSource$VH; + } + public static MemoryAddress GetDeviceAsyncEventSource$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceAsyncEventSource$VH.get(seg); + } + public static void GetDeviceAsyncEventSource$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceAsyncEventSource$VH.set(seg, x); + } + public static MemoryAddress GetDeviceAsyncEventSource$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceAsyncEventSource$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceAsyncEventSource GetDeviceAsyncEventSource (MemorySegment segment, MemorySession session) { + return GetDeviceAsyncEventSource.ofAddress(GetDeviceAsyncEventSource$get(segment), session); + } + static final FunctionDescriptor CreateDeviceAsyncPort$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CreateDeviceAsyncPort$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.CreateDeviceAsyncPort$FUNC + ); + public interface CreateDeviceAsyncPort { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(CreateDeviceAsyncPort fi, MemorySession session) { + return RuntimeHelper.upcallStub(CreateDeviceAsyncPort.class, fi, IOUSBDeviceStruct100.CreateDeviceAsyncPort$FUNC, session); + } + static CreateDeviceAsyncPort ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct100.CreateDeviceAsyncPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle CreateDeviceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateDeviceAsyncPort")); + public static VarHandle CreateDeviceAsyncPort$VH() { + return IOUSBDeviceStruct100.CreateDeviceAsyncPort$VH; + } + public static MemoryAddress CreateDeviceAsyncPort$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.CreateDeviceAsyncPort$VH.get(seg); + } + public static void CreateDeviceAsyncPort$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.CreateDeviceAsyncPort$VH.set(seg, x); + } + public static MemoryAddress CreateDeviceAsyncPort$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.CreateDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + } + public static void CreateDeviceAsyncPort$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.CreateDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); + } + public static CreateDeviceAsyncPort CreateDeviceAsyncPort (MemorySegment segment, MemorySession session) { + return CreateDeviceAsyncPort.ofAddress(CreateDeviceAsyncPort$get(segment), session); + } + static final FunctionDescriptor GetDeviceAsyncPort$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceAsyncPort$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.GetDeviceAsyncPort$FUNC + ); + public interface GetDeviceAsyncPort { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(GetDeviceAsyncPort fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceAsyncPort.class, fi, IOUSBDeviceStruct100.GetDeviceAsyncPort$FUNC, session); + } + static GetDeviceAsyncPort ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBDeviceStruct100.GetDeviceAsyncPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncPort")); + public static VarHandle GetDeviceAsyncPort$VH() { + return IOUSBDeviceStruct100.GetDeviceAsyncPort$VH; + } + public static MemoryAddress GetDeviceAsyncPort$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceAsyncPort$VH.get(seg); + } + public static void GetDeviceAsyncPort$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceAsyncPort$VH.set(seg, x); + } + public static MemoryAddress GetDeviceAsyncPort$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceAsyncPort$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceAsyncPort GetDeviceAsyncPort (MemorySegment segment, MemorySession session) { + return GetDeviceAsyncPort.ofAddress(GetDeviceAsyncPort$get(segment), session); + } + static final FunctionDescriptor USBDeviceOpen$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBDeviceOpen$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.USBDeviceOpen$FUNC + ); + public interface USBDeviceOpen { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(USBDeviceOpen fi, MemorySession session) { + return RuntimeHelper.upcallStub(USBDeviceOpen.class, fi, IOUSBDeviceStruct100.USBDeviceOpen$FUNC, session); + } + static USBDeviceOpen ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBDeviceStruct100.USBDeviceOpen$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBDeviceOpen$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceOpen")); + public static VarHandle USBDeviceOpen$VH() { + return IOUSBDeviceStruct100.USBDeviceOpen$VH; + } + public static MemoryAddress USBDeviceOpen$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.USBDeviceOpen$VH.get(seg); + } + public static void USBDeviceOpen$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.USBDeviceOpen$VH.set(seg, x); + } + public static MemoryAddress USBDeviceOpen$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.USBDeviceOpen$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBDeviceOpen$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.USBDeviceOpen$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBDeviceOpen USBDeviceOpen (MemorySegment segment, MemorySession session) { + return USBDeviceOpen.ofAddress(USBDeviceOpen$get(segment), session); + } + static final FunctionDescriptor USBDeviceClose$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBDeviceClose$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.USBDeviceClose$FUNC + ); + public interface USBDeviceClose { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(USBDeviceClose fi, MemorySession session) { + return RuntimeHelper.upcallStub(USBDeviceClose.class, fi, IOUSBDeviceStruct100.USBDeviceClose$FUNC, session); + } + static USBDeviceClose ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBDeviceStruct100.USBDeviceClose$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBDeviceClose$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceClose")); + public static VarHandle USBDeviceClose$VH() { + return IOUSBDeviceStruct100.USBDeviceClose$VH; + } + public static MemoryAddress USBDeviceClose$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.USBDeviceClose$VH.get(seg); + } + public static void USBDeviceClose$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.USBDeviceClose$VH.set(seg, x); + } + public static MemoryAddress USBDeviceClose$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.USBDeviceClose$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBDeviceClose$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.USBDeviceClose$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBDeviceClose USBDeviceClose (MemorySegment segment, MemorySession session) { + return USBDeviceClose.ofAddress(USBDeviceClose$get(segment), session); + } + static final FunctionDescriptor GetDeviceClass$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceClass$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.GetDeviceClass$FUNC + ); + public interface GetDeviceClass { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceClass fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceClass.class, fi, IOUSBDeviceStruct100.GetDeviceClass$FUNC, session); + } + static GetDeviceClass ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct100.GetDeviceClass$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceClass")); + public static VarHandle GetDeviceClass$VH() { + return IOUSBDeviceStruct100.GetDeviceClass$VH; + } + public static MemoryAddress GetDeviceClass$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceClass$VH.get(seg); + } + public static void GetDeviceClass$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceClass$VH.set(seg, x); + } + public static MemoryAddress GetDeviceClass$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceClass$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceClass$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceClass$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceClass GetDeviceClass (MemorySegment segment, MemorySession session) { + return GetDeviceClass.ofAddress(GetDeviceClass$get(segment), session); + } + static final FunctionDescriptor GetDeviceSubClass$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceSubClass$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.GetDeviceSubClass$FUNC + ); + public interface GetDeviceSubClass { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceSubClass fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceSubClass.class, fi, IOUSBDeviceStruct100.GetDeviceSubClass$FUNC, session); + } + static GetDeviceSubClass ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct100.GetDeviceSubClass$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceSubClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceSubClass")); + public static VarHandle GetDeviceSubClass$VH() { + return IOUSBDeviceStruct100.GetDeviceSubClass$VH; + } + public static MemoryAddress GetDeviceSubClass$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceSubClass$VH.get(seg); + } + public static void GetDeviceSubClass$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceSubClass$VH.set(seg, x); + } + public static MemoryAddress GetDeviceSubClass$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceSubClass$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceSubClass$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceSubClass$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceSubClass GetDeviceSubClass (MemorySegment segment, MemorySession session) { + return GetDeviceSubClass.ofAddress(GetDeviceSubClass$get(segment), session); + } + static final FunctionDescriptor GetDeviceProtocol$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceProtocol$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.GetDeviceProtocol$FUNC + ); + public interface GetDeviceProtocol { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceProtocol fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceProtocol.class, fi, IOUSBDeviceStruct100.GetDeviceProtocol$FUNC, session); + } + static GetDeviceProtocol ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct100.GetDeviceProtocol$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceProtocol$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProtocol")); + public static VarHandle GetDeviceProtocol$VH() { + return IOUSBDeviceStruct100.GetDeviceProtocol$VH; + } + public static MemoryAddress GetDeviceProtocol$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceProtocol$VH.get(seg); + } + public static void GetDeviceProtocol$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceProtocol$VH.set(seg, x); + } + public static MemoryAddress GetDeviceProtocol$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceProtocol$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceProtocol$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceProtocol$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceProtocol GetDeviceProtocol (MemorySegment segment, MemorySession session) { + return GetDeviceProtocol.ofAddress(GetDeviceProtocol$get(segment), session); + } + static final FunctionDescriptor GetDeviceVendor$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceVendor$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.GetDeviceVendor$FUNC + ); + public interface GetDeviceVendor { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceVendor fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceVendor.class, fi, IOUSBDeviceStruct100.GetDeviceVendor$FUNC, session); + } + static GetDeviceVendor ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct100.GetDeviceVendor$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceVendor$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceVendor")); + public static VarHandle GetDeviceVendor$VH() { + return IOUSBDeviceStruct100.GetDeviceVendor$VH; + } + public static MemoryAddress GetDeviceVendor$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceVendor$VH.get(seg); + } + public static void GetDeviceVendor$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceVendor$VH.set(seg, x); + } + public static MemoryAddress GetDeviceVendor$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceVendor$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceVendor$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceVendor$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceVendor GetDeviceVendor (MemorySegment segment, MemorySession session) { + return GetDeviceVendor.ofAddress(GetDeviceVendor$get(segment), session); + } + static final FunctionDescriptor GetDeviceProduct$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceProduct$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.GetDeviceProduct$FUNC + ); + public interface GetDeviceProduct { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceProduct fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceProduct.class, fi, IOUSBDeviceStruct100.GetDeviceProduct$FUNC, session); + } + static GetDeviceProduct ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct100.GetDeviceProduct$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceProduct$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProduct")); + public static VarHandle GetDeviceProduct$VH() { + return IOUSBDeviceStruct100.GetDeviceProduct$VH; + } + public static MemoryAddress GetDeviceProduct$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceProduct$VH.get(seg); + } + public static void GetDeviceProduct$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceProduct$VH.set(seg, x); + } + public static MemoryAddress GetDeviceProduct$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceProduct$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceProduct$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceProduct$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceProduct GetDeviceProduct (MemorySegment segment, MemorySession session) { + return GetDeviceProduct.ofAddress(GetDeviceProduct$get(segment), session); + } + static final FunctionDescriptor GetDeviceReleaseNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceReleaseNumber$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.GetDeviceReleaseNumber$FUNC + ); + public interface GetDeviceReleaseNumber { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceReleaseNumber fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceReleaseNumber.class, fi, IOUSBDeviceStruct100.GetDeviceReleaseNumber$FUNC, session); + } + static GetDeviceReleaseNumber ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct100.GetDeviceReleaseNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceReleaseNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceReleaseNumber")); + public static VarHandle GetDeviceReleaseNumber$VH() { + return IOUSBDeviceStruct100.GetDeviceReleaseNumber$VH; + } + public static MemoryAddress GetDeviceReleaseNumber$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceReleaseNumber$VH.get(seg); + } + public static void GetDeviceReleaseNumber$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceReleaseNumber$VH.set(seg, x); + } + public static MemoryAddress GetDeviceReleaseNumber$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceReleaseNumber$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceReleaseNumber$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceReleaseNumber$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceReleaseNumber GetDeviceReleaseNumber (MemorySegment segment, MemorySession session) { + return GetDeviceReleaseNumber.ofAddress(GetDeviceReleaseNumber$get(segment), session); + } + static final FunctionDescriptor GetDeviceAddress$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceAddress$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.GetDeviceAddress$FUNC + ); + public interface GetDeviceAddress { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceAddress fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceAddress.class, fi, IOUSBDeviceStruct100.GetDeviceAddress$FUNC, session); + } + static GetDeviceAddress ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct100.GetDeviceAddress$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceAddress$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAddress")); + public static VarHandle GetDeviceAddress$VH() { + return IOUSBDeviceStruct100.GetDeviceAddress$VH; + } + public static MemoryAddress GetDeviceAddress$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceAddress$VH.get(seg); + } + public static void GetDeviceAddress$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceAddress$VH.set(seg, x); + } + public static MemoryAddress GetDeviceAddress$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceAddress$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceAddress$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceAddress$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceAddress GetDeviceAddress (MemorySegment segment, MemorySession session) { + return GetDeviceAddress.ofAddress(GetDeviceAddress$get(segment), session); + } + static final FunctionDescriptor GetDeviceBusPowerAvailable$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceBusPowerAvailable$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$FUNC + ); + public interface GetDeviceBusPowerAvailable { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceBusPowerAvailable fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceBusPowerAvailable.class, fi, IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$FUNC, session); + } + static GetDeviceBusPowerAvailable ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceBusPowerAvailable$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceBusPowerAvailable")); + public static VarHandle GetDeviceBusPowerAvailable$VH() { + return IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$VH; + } + public static MemoryAddress GetDeviceBusPowerAvailable$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$VH.get(seg); + } + public static void GetDeviceBusPowerAvailable$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$VH.set(seg, x); + } + public static MemoryAddress GetDeviceBusPowerAvailable$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceBusPowerAvailable$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceBusPowerAvailable GetDeviceBusPowerAvailable (MemorySegment segment, MemorySession session) { + return GetDeviceBusPowerAvailable.ofAddress(GetDeviceBusPowerAvailable$get(segment), session); + } + static final FunctionDescriptor GetDeviceSpeed$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetDeviceSpeed$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.GetDeviceSpeed$FUNC + ); + public interface GetDeviceSpeed { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetDeviceSpeed fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetDeviceSpeed.class, fi, IOUSBDeviceStruct100.GetDeviceSpeed$FUNC, session); + } + static GetDeviceSpeed ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct100.GetDeviceSpeed$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetDeviceSpeed$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceSpeed")); + public static VarHandle GetDeviceSpeed$VH() { + return IOUSBDeviceStruct100.GetDeviceSpeed$VH; + } + public static MemoryAddress GetDeviceSpeed$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceSpeed$VH.get(seg); + } + public static void GetDeviceSpeed$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceSpeed$VH.set(seg, x); + } + public static MemoryAddress GetDeviceSpeed$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceSpeed$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetDeviceSpeed$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.GetDeviceSpeed$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetDeviceSpeed GetDeviceSpeed (MemorySegment segment, MemorySession session) { + return GetDeviceSpeed.ofAddress(GetDeviceSpeed$get(segment), session); + } + static final FunctionDescriptor GetNumberOfConfigurations$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetNumberOfConfigurations$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.GetNumberOfConfigurations$FUNC + ); + public interface GetNumberOfConfigurations { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetNumberOfConfigurations fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetNumberOfConfigurations.class, fi, IOUSBDeviceStruct100.GetNumberOfConfigurations$FUNC, session); + } + static GetNumberOfConfigurations ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct100.GetNumberOfConfigurations$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetNumberOfConfigurations$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetNumberOfConfigurations")); + public static VarHandle GetNumberOfConfigurations$VH() { + return IOUSBDeviceStruct100.GetNumberOfConfigurations$VH; + } + public static MemoryAddress GetNumberOfConfigurations$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetNumberOfConfigurations$VH.get(seg); + } + public static void GetNumberOfConfigurations$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.GetNumberOfConfigurations$VH.set(seg, x); + } + public static MemoryAddress GetNumberOfConfigurations$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetNumberOfConfigurations$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetNumberOfConfigurations$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.GetNumberOfConfigurations$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetNumberOfConfigurations GetNumberOfConfigurations (MemorySegment segment, MemorySession session) { + return GetNumberOfConfigurations.ofAddress(GetNumberOfConfigurations$get(segment), session); + } + static final FunctionDescriptor GetLocationID$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetLocationID$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.GetLocationID$FUNC + ); + public interface GetLocationID { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetLocationID fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetLocationID.class, fi, IOUSBDeviceStruct100.GetLocationID$FUNC, session); + } + static GetLocationID ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct100.GetLocationID$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetLocationID$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetLocationID")); + public static VarHandle GetLocationID$VH() { + return IOUSBDeviceStruct100.GetLocationID$VH; + } + public static MemoryAddress GetLocationID$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetLocationID$VH.get(seg); + } + public static void GetLocationID$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.GetLocationID$VH.set(seg, x); + } + public static MemoryAddress GetLocationID$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetLocationID$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetLocationID$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.GetLocationID$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetLocationID GetLocationID (MemorySegment segment, MemorySession session) { + return GetLocationID.ofAddress(GetLocationID$get(segment), session); + } + static final FunctionDescriptor GetConfigurationDescriptorPtr$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetConfigurationDescriptorPtr$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$FUNC + ); + public interface GetConfigurationDescriptorPtr { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(GetConfigurationDescriptorPtr fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetConfigurationDescriptorPtr.class, fi, IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$FUNC, session); + } + static GetConfigurationDescriptorPtr ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetConfigurationDescriptorPtr$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetConfigurationDescriptorPtr")); + public static VarHandle GetConfigurationDescriptorPtr$VH() { + return IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$VH; + } + public static MemoryAddress GetConfigurationDescriptorPtr$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$VH.get(seg); + } + public static void GetConfigurationDescriptorPtr$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$VH.set(seg, x); + } + public static MemoryAddress GetConfigurationDescriptorPtr$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetConfigurationDescriptorPtr$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetConfigurationDescriptorPtr GetConfigurationDescriptorPtr (MemorySegment segment, MemorySession session) { + return GetConfigurationDescriptorPtr.ofAddress(GetConfigurationDescriptorPtr$get(segment), session); + } + static final FunctionDescriptor GetConfiguration$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetConfiguration$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.GetConfiguration$FUNC + ); + public interface GetConfiguration { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(GetConfiguration fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetConfiguration.class, fi, IOUSBDeviceStruct100.GetConfiguration$FUNC, session); + } + static GetConfiguration ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct100.GetConfiguration$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetConfiguration$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetConfiguration")); + public static VarHandle GetConfiguration$VH() { + return IOUSBDeviceStruct100.GetConfiguration$VH; + } + public static MemoryAddress GetConfiguration$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetConfiguration$VH.get(seg); + } + public static void GetConfiguration$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.GetConfiguration$VH.set(seg, x); + } + public static MemoryAddress GetConfiguration$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetConfiguration$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetConfiguration$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.GetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetConfiguration GetConfiguration (MemorySegment segment, MemorySession session) { + return GetConfiguration.ofAddress(GetConfiguration$get(segment), session); + } + static final FunctionDescriptor SetConfiguration$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT + ); + static final MethodHandle SetConfiguration$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.SetConfiguration$FUNC + ); + public interface SetConfiguration { + + int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); + static MemorySegment allocate(SetConfiguration fi, MemorySession session) { + return RuntimeHelper.upcallStub(SetConfiguration.class, fi, IOUSBDeviceStruct100.SetConfiguration$FUNC, session); + } + static SetConfiguration ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { + try { + return (int)IOUSBDeviceStruct100.SetConfiguration$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle SetConfiguration$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetConfiguration")); + public static VarHandle SetConfiguration$VH() { + return IOUSBDeviceStruct100.SetConfiguration$VH; + } + public static MemoryAddress SetConfiguration$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.SetConfiguration$VH.get(seg); + } + public static void SetConfiguration$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.SetConfiguration$VH.set(seg, x); + } + public static MemoryAddress SetConfiguration$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.SetConfiguration$VH.get(seg.asSlice(index*sizeof())); + } + public static void SetConfiguration$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.SetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); + } + public static SetConfiguration SetConfiguration (MemorySegment segment, MemorySession session) { + return SetConfiguration.ofAddress(SetConfiguration$get(segment), session); + } + static final FunctionDescriptor GetBusFrameNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle GetBusFrameNumber$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.GetBusFrameNumber$FUNC + ); + public interface GetBusFrameNumber { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(GetBusFrameNumber fi, MemorySession session) { + return RuntimeHelper.upcallStub(GetBusFrameNumber.class, fi, IOUSBDeviceStruct100.GetBusFrameNumber$FUNC, session); + } + static GetBusFrameNumber ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBDeviceStruct100.GetBusFrameNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle GetBusFrameNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBusFrameNumber")); + public static VarHandle GetBusFrameNumber$VH() { + return IOUSBDeviceStruct100.GetBusFrameNumber$VH; + } + public static MemoryAddress GetBusFrameNumber$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetBusFrameNumber$VH.get(seg); + } + public static void GetBusFrameNumber$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.GetBusFrameNumber$VH.set(seg, x); + } + public static MemoryAddress GetBusFrameNumber$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetBusFrameNumber$VH.get(seg.asSlice(index*sizeof())); + } + public static void GetBusFrameNumber$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.GetBusFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); + } + public static GetBusFrameNumber GetBusFrameNumber (MemorySegment segment, MemorySession session) { + return GetBusFrameNumber.ofAddress(GetBusFrameNumber$get(segment), session); + } + static final FunctionDescriptor ResetDevice$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle ResetDevice$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.ResetDevice$FUNC + ); + public interface ResetDevice { + + int apply(java.lang.foreign.MemoryAddress _x0); + static MemorySegment allocate(ResetDevice fi, MemorySession session) { + return RuntimeHelper.upcallStub(ResetDevice.class, fi, IOUSBDeviceStruct100.ResetDevice$FUNC, session); + } + static ResetDevice ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0) -> { + try { + return (int)IOUSBDeviceStruct100.ResetDevice$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle ResetDevice$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ResetDevice")); + public static VarHandle ResetDevice$VH() { + return IOUSBDeviceStruct100.ResetDevice$VH; + } + public static MemoryAddress ResetDevice$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.ResetDevice$VH.get(seg); + } + public static void ResetDevice$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.ResetDevice$VH.set(seg, x); + } + public static MemoryAddress ResetDevice$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.ResetDevice$VH.get(seg.asSlice(index*sizeof())); + } + public static void ResetDevice$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.ResetDevice$VH.set(seg.asSlice(index*sizeof()), x); + } + public static ResetDevice ResetDevice (MemorySegment segment, MemorySession session) { + return ResetDevice.ofAddress(ResetDevice$get(segment), session); + } + static final FunctionDescriptor DeviceRequest$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle DeviceRequest$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.DeviceRequest$FUNC + ); + public interface DeviceRequest { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); + static MemorySegment allocate(DeviceRequest fi, MemorySession session) { + return RuntimeHelper.upcallStub(DeviceRequest.class, fi, IOUSBDeviceStruct100.DeviceRequest$FUNC, session); + } + static DeviceRequest ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + try { + return (int)IOUSBDeviceStruct100.DeviceRequest$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle DeviceRequest$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequest")); + public static VarHandle DeviceRequest$VH() { + return IOUSBDeviceStruct100.DeviceRequest$VH; + } + public static MemoryAddress DeviceRequest$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.DeviceRequest$VH.get(seg); + } + public static void DeviceRequest$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.DeviceRequest$VH.set(seg, x); + } + public static MemoryAddress DeviceRequest$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.DeviceRequest$VH.get(seg.asSlice(index*sizeof())); + } + public static void DeviceRequest$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.DeviceRequest$VH.set(seg.asSlice(index*sizeof()), x); + } + public static DeviceRequest DeviceRequest (MemorySegment segment, MemorySession session) { + return DeviceRequest.ofAddress(DeviceRequest$get(segment), session); + } + static final FunctionDescriptor DeviceRequestAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle DeviceRequestAsync$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.DeviceRequestAsync$FUNC + ); + public interface DeviceRequestAsync { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3); + static MemorySegment allocate(DeviceRequestAsync fi, MemorySession session) { + return RuntimeHelper.upcallStub(DeviceRequestAsync.class, fi, IOUSBDeviceStruct100.DeviceRequestAsync$FUNC, session); + } + static DeviceRequestAsync ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3) -> { + try { + return (int)IOUSBDeviceStruct100.DeviceRequestAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle DeviceRequestAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestAsync")); + public static VarHandle DeviceRequestAsync$VH() { + return IOUSBDeviceStruct100.DeviceRequestAsync$VH; + } + public static MemoryAddress DeviceRequestAsync$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.DeviceRequestAsync$VH.get(seg); + } + public static void DeviceRequestAsync$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.DeviceRequestAsync$VH.set(seg, x); + } + public static MemoryAddress DeviceRequestAsync$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.DeviceRequestAsync$VH.get(seg.asSlice(index*sizeof())); + } + public static void DeviceRequestAsync$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.DeviceRequestAsync$VH.set(seg.asSlice(index*sizeof()), x); + } + public static DeviceRequestAsync DeviceRequestAsync (MemorySegment segment, MemorySession session) { + return DeviceRequestAsync.ofAddress(DeviceRequestAsync$get(segment), session); + } + static final FunctionDescriptor CreateInterfaceIterator$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CreateInterfaceIterator$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct100.CreateInterfaceIterator$FUNC + ); + public interface CreateInterfaceIterator { + + int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); + static MemorySegment allocate(CreateInterfaceIterator fi, MemorySession session) { + return RuntimeHelper.upcallStub(CreateInterfaceIterator.class, fi, IOUSBDeviceStruct100.CreateInterfaceIterator$FUNC, session); + } + static CreateInterfaceIterator ofAddress(MemoryAddress addr, MemorySession session) { + MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); + return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { + try { + return (int)IOUSBDeviceStruct100.CreateInterfaceIterator$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle CreateInterfaceIterator$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceIterator")); + public static VarHandle CreateInterfaceIterator$VH() { + return IOUSBDeviceStruct100.CreateInterfaceIterator$VH; + } + public static MemoryAddress CreateInterfaceIterator$get(MemorySegment seg) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.CreateInterfaceIterator$VH.get(seg); + } + public static void CreateInterfaceIterator$set( MemorySegment seg, MemoryAddress x) { + IOUSBDeviceStruct100.CreateInterfaceIterator$VH.set(seg, x); + } + public static MemoryAddress CreateInterfaceIterator$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.CreateInterfaceIterator$VH.get(seg.asSlice(index*sizeof())); + } + public static void CreateInterfaceIterator$set(MemorySegment seg, long index, MemoryAddress x) { + IOUSBDeviceStruct100.CreateInterfaceIterator$VH.set(seg.asSlice(index*sizeof()), x); + } + public static CreateInterfaceIterator CreateInterfaceIterator (MemorySegment segment, MemorySession session) { + return CreateInterfaceIterator.ofAddress(CreateInterfaceIterator$get(segment), session); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct942.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct942.java deleted file mode 100644 index 064a6458..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct942.java +++ /dev/null @@ -1,2317 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -public class IOUSBDeviceStruct942 { - - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_POINTER$LAYOUT.withName("_reserved"), - Constants$root.C_POINTER$LAYOUT.withName("QueryInterface"), - Constants$root.C_POINTER$LAYOUT.withName("AddRef"), - Constants$root.C_POINTER$LAYOUT.withName("Release"), - Constants$root.C_POINTER$LAYOUT.withName("CreateDeviceAsyncEventSource"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceAsyncEventSource"), - Constants$root.C_POINTER$LAYOUT.withName("CreateDeviceAsyncPort"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceAsyncPort"), - Constants$root.C_POINTER$LAYOUT.withName("USBDeviceOpen"), - Constants$root.C_POINTER$LAYOUT.withName("USBDeviceClose"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceClass"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceSubClass"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceProtocol"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceVendor"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceProduct"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceReleaseNumber"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceAddress"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceBusPowerAvailable"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceSpeed"), - Constants$root.C_POINTER$LAYOUT.withName("GetNumberOfConfigurations"), - Constants$root.C_POINTER$LAYOUT.withName("GetLocationID"), - Constants$root.C_POINTER$LAYOUT.withName("GetConfigurationDescriptorPtr"), - Constants$root.C_POINTER$LAYOUT.withName("GetConfiguration"), - Constants$root.C_POINTER$LAYOUT.withName("SetConfiguration"), - Constants$root.C_POINTER$LAYOUT.withName("GetBusFrameNumber"), - Constants$root.C_POINTER$LAYOUT.withName("ResetDevice"), - Constants$root.C_POINTER$LAYOUT.withName("DeviceRequest"), - Constants$root.C_POINTER$LAYOUT.withName("DeviceRequestAsync"), - Constants$root.C_POINTER$LAYOUT.withName("CreateInterfaceIterator"), - Constants$root.C_POINTER$LAYOUT.withName("USBDeviceOpenSeize"), - Constants$root.C_POINTER$LAYOUT.withName("DeviceRequestTO"), - Constants$root.C_POINTER$LAYOUT.withName("DeviceRequestAsyncTO"), - Constants$root.C_POINTER$LAYOUT.withName("USBDeviceSuspend"), - Constants$root.C_POINTER$LAYOUT.withName("USBDeviceAbortPipeZero"), - Constants$root.C_POINTER$LAYOUT.withName("USBGetManufacturerStringIndex"), - Constants$root.C_POINTER$LAYOUT.withName("USBGetProductStringIndex"), - Constants$root.C_POINTER$LAYOUT.withName("USBGetSerialNumberStringIndex"), - Constants$root.C_POINTER$LAYOUT.withName("USBDeviceReEnumerate"), - Constants$root.C_POINTER$LAYOUT.withName("GetBusMicroFrameNumber"), - Constants$root.C_POINTER$LAYOUT.withName("GetIOUSBLibVersion"), - Constants$root.C_POINTER$LAYOUT.withName("GetBusFrameNumberWithTime"), - Constants$root.C_POINTER$LAYOUT.withName("GetUSBDeviceInformation"), - Constants$root.C_POINTER$LAYOUT.withName("RequestExtraPower"), - Constants$root.C_POINTER$LAYOUT.withName("ReturnExtraPower"), - Constants$root.C_POINTER$LAYOUT.withName("GetExtraPowerAllocated"), - Constants$root.C_POINTER$LAYOUT.withName("GetBandwidthAvailableForDevice"), - Constants$root.C_POINTER$LAYOUT.withName("SetConfigurationV2"), - Constants$root.C_POINTER$LAYOUT.withName("RegisterForNotification"), - Constants$root.C_POINTER$LAYOUT.withName("UnregisterNotification"), - Constants$root.C_POINTER$LAYOUT.withName("AcknowledgeNotification"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceAsyncNotificationPort") - ).withName("IOUSBDeviceStruct942"); - public static MemoryLayout $LAYOUT() { - return IOUSBDeviceStruct942.$struct$LAYOUT; - } - static final VarHandle _reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("_reserved")); - public static VarHandle _reserved$VH() { - return IOUSBDeviceStruct942._reserved$VH; - } - public static MemoryAddress _reserved$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942._reserved$VH.get(seg); - } - public static void _reserved$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942._reserved$VH.set(seg, x); - } - public static MemoryAddress _reserved$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942._reserved$VH.get(seg.asSlice(index*sizeof())); - } - public static void _reserved$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942._reserved$VH.set(seg.asSlice(index*sizeof()), x); - } - static final FunctionDescriptor QueryInterface$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("byte0"), - Constants$root.C_CHAR$LAYOUT.withName("byte1"), - Constants$root.C_CHAR$LAYOUT.withName("byte2"), - Constants$root.C_CHAR$LAYOUT.withName("byte3"), - Constants$root.C_CHAR$LAYOUT.withName("byte4"), - Constants$root.C_CHAR$LAYOUT.withName("byte5"), - Constants$root.C_CHAR$LAYOUT.withName("byte6"), - Constants$root.C_CHAR$LAYOUT.withName("byte7"), - Constants$root.C_CHAR$LAYOUT.withName("byte8"), - Constants$root.C_CHAR$LAYOUT.withName("byte9"), - Constants$root.C_CHAR$LAYOUT.withName("byte10"), - Constants$root.C_CHAR$LAYOUT.withName("byte11"), - Constants$root.C_CHAR$LAYOUT.withName("byte12"), - Constants$root.C_CHAR$LAYOUT.withName("byte13"), - Constants$root.C_CHAR$LAYOUT.withName("byte14"), - Constants$root.C_CHAR$LAYOUT.withName("byte15") - ), - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle QueryInterface$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.QueryInterface$FUNC - ); - public interface QueryInterface { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(QueryInterface fi, MemorySession session) { - return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOUSBDeviceStruct942.QueryInterface$FUNC, session); - } - static QueryInterface ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemoryAddress __x2) -> { - try { - return (int)IOUSBDeviceStruct942.QueryInterface$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle QueryInterface$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("QueryInterface")); - public static VarHandle QueryInterface$VH() { - return IOUSBDeviceStruct942.QueryInterface$VH; - } - public static MemoryAddress QueryInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.QueryInterface$VH.get(seg); - } - public static void QueryInterface$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.QueryInterface$VH.set(seg, x); - } - public static MemoryAddress QueryInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.QueryInterface$VH.get(seg.asSlice(index*sizeof())); - } - public static void QueryInterface$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.QueryInterface$VH.set(seg.asSlice(index*sizeof()), x); - } - public static QueryInterface QueryInterface (MemorySegment segment, MemorySession session) { - return QueryInterface.ofAddress(QueryInterface$get(segment), session); - } - static final FunctionDescriptor AddRef$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle AddRef$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.AddRef$FUNC - ); - public interface AddRef { - - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(AddRef fi, MemorySession session) { - return RuntimeHelper.upcallStub(AddRef.class, fi, IOUSBDeviceStruct942.AddRef$FUNC, session); - } - static AddRef ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { - try { - return (int)IOUSBDeviceStruct942.AddRef$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle AddRef$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AddRef")); - public static VarHandle AddRef$VH() { - return IOUSBDeviceStruct942.AddRef$VH; - } - public static MemoryAddress AddRef$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.AddRef$VH.get(seg); - } - public static void AddRef$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.AddRef$VH.set(seg, x); - } - public static MemoryAddress AddRef$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.AddRef$VH.get(seg.asSlice(index*sizeof())); - } - public static void AddRef$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.AddRef$VH.set(seg.asSlice(index*sizeof()), x); - } - public static AddRef AddRef (MemorySegment segment, MemorySession session) { - return AddRef.ofAddress(AddRef$get(segment), session); - } - static final FunctionDescriptor Release$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle Release$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.Release$FUNC - ); - public interface Release { - - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(Release fi, MemorySession session) { - return RuntimeHelper.upcallStub(Release.class, fi, IOUSBDeviceStruct942.Release$FUNC, session); - } - static Release ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { - try { - return (int)IOUSBDeviceStruct942.Release$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle Release$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Release")); - public static VarHandle Release$VH() { - return IOUSBDeviceStruct942.Release$VH; - } - public static MemoryAddress Release$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.Release$VH.get(seg); - } - public static void Release$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.Release$VH.set(seg, x); - } - public static MemoryAddress Release$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.Release$VH.get(seg.asSlice(index*sizeof())); - } - public static void Release$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.Release$VH.set(seg.asSlice(index*sizeof()), x); - } - public static Release Release (MemorySegment segment, MemorySession session) { - return Release.ofAddress(Release$get(segment), session); - } - static final FunctionDescriptor CreateDeviceAsyncEventSource$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle CreateDeviceAsyncEventSource$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.CreateDeviceAsyncEventSource$FUNC - ); - public interface CreateDeviceAsyncEventSource { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(CreateDeviceAsyncEventSource fi, MemorySession session) { - return RuntimeHelper.upcallStub(CreateDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct942.CreateDeviceAsyncEventSource$FUNC, session); - } - static CreateDeviceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.CreateDeviceAsyncEventSource$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle CreateDeviceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateDeviceAsyncEventSource")); - public static VarHandle CreateDeviceAsyncEventSource$VH() { - return IOUSBDeviceStruct942.CreateDeviceAsyncEventSource$VH; - } - public static MemoryAddress CreateDeviceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.CreateDeviceAsyncEventSource$VH.get(seg); - } - public static void CreateDeviceAsyncEventSource$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.CreateDeviceAsyncEventSource$VH.set(seg, x); - } - public static MemoryAddress CreateDeviceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.CreateDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); - } - public static void CreateDeviceAsyncEventSource$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.CreateDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); - } - public static CreateDeviceAsyncEventSource CreateDeviceAsyncEventSource (MemorySegment segment, MemorySession session) { - return CreateDeviceAsyncEventSource.ofAddress(CreateDeviceAsyncEventSource$get(segment), session); - } - static final FunctionDescriptor GetDeviceAsyncEventSource$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceAsyncEventSource$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetDeviceAsyncEventSource$FUNC - ); - public interface GetDeviceAsyncEventSource { - - java.lang.foreign.Addressable apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(GetDeviceAsyncEventSource fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct942.GetDeviceAsyncEventSource$FUNC, session); - } - static GetDeviceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { - try { - return (java.lang.foreign.Addressable)(java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAsyncEventSource$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetDeviceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncEventSource")); - public static VarHandle GetDeviceAsyncEventSource$VH() { - return IOUSBDeviceStruct942.GetDeviceAsyncEventSource$VH; - } - public static MemoryAddress GetDeviceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAsyncEventSource$VH.get(seg); - } - public static void GetDeviceAsyncEventSource$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceAsyncEventSource$VH.set(seg, x); - } - public static MemoryAddress GetDeviceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceAsyncEventSource$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceAsyncEventSource GetDeviceAsyncEventSource (MemorySegment segment, MemorySession session) { - return GetDeviceAsyncEventSource.ofAddress(GetDeviceAsyncEventSource$get(segment), session); - } - static final FunctionDescriptor CreateDeviceAsyncPort$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle CreateDeviceAsyncPort$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.CreateDeviceAsyncPort$FUNC - ); - public interface CreateDeviceAsyncPort { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(CreateDeviceAsyncPort fi, MemorySession session) { - return RuntimeHelper.upcallStub(CreateDeviceAsyncPort.class, fi, IOUSBDeviceStruct942.CreateDeviceAsyncPort$FUNC, session); - } - static CreateDeviceAsyncPort ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.CreateDeviceAsyncPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle CreateDeviceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateDeviceAsyncPort")); - public static VarHandle CreateDeviceAsyncPort$VH() { - return IOUSBDeviceStruct942.CreateDeviceAsyncPort$VH; - } - public static MemoryAddress CreateDeviceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.CreateDeviceAsyncPort$VH.get(seg); - } - public static void CreateDeviceAsyncPort$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.CreateDeviceAsyncPort$VH.set(seg, x); - } - public static MemoryAddress CreateDeviceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.CreateDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); - } - public static void CreateDeviceAsyncPort$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.CreateDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); - } - public static CreateDeviceAsyncPort CreateDeviceAsyncPort (MemorySegment segment, MemorySession session) { - return CreateDeviceAsyncPort.ofAddress(CreateDeviceAsyncPort$get(segment), session); - } - static final FunctionDescriptor GetDeviceAsyncPort$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceAsyncPort$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetDeviceAsyncPort$FUNC - ); - public interface GetDeviceAsyncPort { - - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(GetDeviceAsyncPort fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceAsyncPort.class, fi, IOUSBDeviceStruct942.GetDeviceAsyncPort$FUNC, session); - } - static GetDeviceAsyncPort ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { - try { - return (int)IOUSBDeviceStruct942.GetDeviceAsyncPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetDeviceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncPort")); - public static VarHandle GetDeviceAsyncPort$VH() { - return IOUSBDeviceStruct942.GetDeviceAsyncPort$VH; - } - public static MemoryAddress GetDeviceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAsyncPort$VH.get(seg); - } - public static void GetDeviceAsyncPort$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceAsyncPort$VH.set(seg, x); - } - public static MemoryAddress GetDeviceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceAsyncPort$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceAsyncPort GetDeviceAsyncPort (MemorySegment segment, MemorySession session) { - return GetDeviceAsyncPort.ofAddress(GetDeviceAsyncPort$get(segment), session); - } - static final FunctionDescriptor USBDeviceOpen$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBDeviceOpen$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.USBDeviceOpen$FUNC - ); - public interface USBDeviceOpen { - - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(USBDeviceOpen fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBDeviceOpen.class, fi, IOUSBDeviceStruct942.USBDeviceOpen$FUNC, session); - } - static USBDeviceOpen ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { - try { - return (int)IOUSBDeviceStruct942.USBDeviceOpen$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle USBDeviceOpen$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceOpen")); - public static VarHandle USBDeviceOpen$VH() { - return IOUSBDeviceStruct942.USBDeviceOpen$VH; - } - public static MemoryAddress USBDeviceOpen$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceOpen$VH.get(seg); - } - public static void USBDeviceOpen$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.USBDeviceOpen$VH.set(seg, x); - } - public static MemoryAddress USBDeviceOpen$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceOpen$VH.get(seg.asSlice(index*sizeof())); - } - public static void USBDeviceOpen$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.USBDeviceOpen$VH.set(seg.asSlice(index*sizeof()), x); - } - public static USBDeviceOpen USBDeviceOpen (MemorySegment segment, MemorySession session) { - return USBDeviceOpen.ofAddress(USBDeviceOpen$get(segment), session); - } - static final FunctionDescriptor USBDeviceClose$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBDeviceClose$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.USBDeviceClose$FUNC - ); - public interface USBDeviceClose { - - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(USBDeviceClose fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBDeviceClose.class, fi, IOUSBDeviceStruct942.USBDeviceClose$FUNC, session); - } - static USBDeviceClose ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { - try { - return (int)IOUSBDeviceStruct942.USBDeviceClose$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle USBDeviceClose$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceClose")); - public static VarHandle USBDeviceClose$VH() { - return IOUSBDeviceStruct942.USBDeviceClose$VH; - } - public static MemoryAddress USBDeviceClose$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceClose$VH.get(seg); - } - public static void USBDeviceClose$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.USBDeviceClose$VH.set(seg, x); - } - public static MemoryAddress USBDeviceClose$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceClose$VH.get(seg.asSlice(index*sizeof())); - } - public static void USBDeviceClose$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.USBDeviceClose$VH.set(seg.asSlice(index*sizeof()), x); - } - public static USBDeviceClose USBDeviceClose (MemorySegment segment, MemorySession session) { - return USBDeviceClose.ofAddress(USBDeviceClose$get(segment), session); - } - static final FunctionDescriptor GetDeviceClass$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceClass$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetDeviceClass$FUNC - ); - public interface GetDeviceClass { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceClass fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceClass.class, fi, IOUSBDeviceStruct942.GetDeviceClass$FUNC, session); - } - static GetDeviceClass ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.GetDeviceClass$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetDeviceClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceClass")); - public static VarHandle GetDeviceClass$VH() { - return IOUSBDeviceStruct942.GetDeviceClass$VH; - } - public static MemoryAddress GetDeviceClass$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceClass$VH.get(seg); - } - public static void GetDeviceClass$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceClass$VH.set(seg, x); - } - public static MemoryAddress GetDeviceClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceClass$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceClass$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceClass$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceClass GetDeviceClass (MemorySegment segment, MemorySession session) { - return GetDeviceClass.ofAddress(GetDeviceClass$get(segment), session); - } - static final FunctionDescriptor GetDeviceSubClass$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceSubClass$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetDeviceSubClass$FUNC - ); - public interface GetDeviceSubClass { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceSubClass fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceSubClass.class, fi, IOUSBDeviceStruct942.GetDeviceSubClass$FUNC, session); - } - static GetDeviceSubClass ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.GetDeviceSubClass$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetDeviceSubClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceSubClass")); - public static VarHandle GetDeviceSubClass$VH() { - return IOUSBDeviceStruct942.GetDeviceSubClass$VH; - } - public static MemoryAddress GetDeviceSubClass$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceSubClass$VH.get(seg); - } - public static void GetDeviceSubClass$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceSubClass$VH.set(seg, x); - } - public static MemoryAddress GetDeviceSubClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceSubClass$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceSubClass$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceSubClass$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceSubClass GetDeviceSubClass (MemorySegment segment, MemorySession session) { - return GetDeviceSubClass.ofAddress(GetDeviceSubClass$get(segment), session); - } - static final FunctionDescriptor GetDeviceProtocol$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceProtocol$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetDeviceProtocol$FUNC - ); - public interface GetDeviceProtocol { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceProtocol fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceProtocol.class, fi, IOUSBDeviceStruct942.GetDeviceProtocol$FUNC, session); - } - static GetDeviceProtocol ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.GetDeviceProtocol$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetDeviceProtocol$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProtocol")); - public static VarHandle GetDeviceProtocol$VH() { - return IOUSBDeviceStruct942.GetDeviceProtocol$VH; - } - public static MemoryAddress GetDeviceProtocol$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceProtocol$VH.get(seg); - } - public static void GetDeviceProtocol$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceProtocol$VH.set(seg, x); - } - public static MemoryAddress GetDeviceProtocol$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceProtocol$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceProtocol$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceProtocol$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceProtocol GetDeviceProtocol (MemorySegment segment, MemorySession session) { - return GetDeviceProtocol.ofAddress(GetDeviceProtocol$get(segment), session); - } - static final FunctionDescriptor GetDeviceVendor$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceVendor$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetDeviceVendor$FUNC - ); - public interface GetDeviceVendor { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceVendor fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceVendor.class, fi, IOUSBDeviceStruct942.GetDeviceVendor$FUNC, session); - } - static GetDeviceVendor ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.GetDeviceVendor$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetDeviceVendor$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceVendor")); - public static VarHandle GetDeviceVendor$VH() { - return IOUSBDeviceStruct942.GetDeviceVendor$VH; - } - public static MemoryAddress GetDeviceVendor$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceVendor$VH.get(seg); - } - public static void GetDeviceVendor$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceVendor$VH.set(seg, x); - } - public static MemoryAddress GetDeviceVendor$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceVendor$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceVendor$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceVendor$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceVendor GetDeviceVendor (MemorySegment segment, MemorySession session) { - return GetDeviceVendor.ofAddress(GetDeviceVendor$get(segment), session); - } - static final FunctionDescriptor GetDeviceProduct$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceProduct$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetDeviceProduct$FUNC - ); - public interface GetDeviceProduct { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceProduct fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceProduct.class, fi, IOUSBDeviceStruct942.GetDeviceProduct$FUNC, session); - } - static GetDeviceProduct ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.GetDeviceProduct$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetDeviceProduct$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProduct")); - public static VarHandle GetDeviceProduct$VH() { - return IOUSBDeviceStruct942.GetDeviceProduct$VH; - } - public static MemoryAddress GetDeviceProduct$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceProduct$VH.get(seg); - } - public static void GetDeviceProduct$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceProduct$VH.set(seg, x); - } - public static MemoryAddress GetDeviceProduct$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceProduct$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceProduct$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceProduct$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceProduct GetDeviceProduct (MemorySegment segment, MemorySession session) { - return GetDeviceProduct.ofAddress(GetDeviceProduct$get(segment), session); - } - static final FunctionDescriptor GetDeviceReleaseNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceReleaseNumber$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetDeviceReleaseNumber$FUNC - ); - public interface GetDeviceReleaseNumber { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceReleaseNumber fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceReleaseNumber.class, fi, IOUSBDeviceStruct942.GetDeviceReleaseNumber$FUNC, session); - } - static GetDeviceReleaseNumber ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.GetDeviceReleaseNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetDeviceReleaseNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceReleaseNumber")); - public static VarHandle GetDeviceReleaseNumber$VH() { - return IOUSBDeviceStruct942.GetDeviceReleaseNumber$VH; - } - public static MemoryAddress GetDeviceReleaseNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceReleaseNumber$VH.get(seg); - } - public static void GetDeviceReleaseNumber$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceReleaseNumber$VH.set(seg, x); - } - public static MemoryAddress GetDeviceReleaseNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceReleaseNumber$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceReleaseNumber$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceReleaseNumber$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceReleaseNumber GetDeviceReleaseNumber (MemorySegment segment, MemorySession session) { - return GetDeviceReleaseNumber.ofAddress(GetDeviceReleaseNumber$get(segment), session); - } - static final FunctionDescriptor GetDeviceAddress$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceAddress$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetDeviceAddress$FUNC - ); - public interface GetDeviceAddress { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceAddress fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceAddress.class, fi, IOUSBDeviceStruct942.GetDeviceAddress$FUNC, session); - } - static GetDeviceAddress ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.GetDeviceAddress$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetDeviceAddress$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAddress")); - public static VarHandle GetDeviceAddress$VH() { - return IOUSBDeviceStruct942.GetDeviceAddress$VH; - } - public static MemoryAddress GetDeviceAddress$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAddress$VH.get(seg); - } - public static void GetDeviceAddress$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceAddress$VH.set(seg, x); - } - public static MemoryAddress GetDeviceAddress$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAddress$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceAddress$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceAddress$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceAddress GetDeviceAddress (MemorySegment segment, MemorySession session) { - return GetDeviceAddress.ofAddress(GetDeviceAddress$get(segment), session); - } - static final FunctionDescriptor GetDeviceBusPowerAvailable$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceBusPowerAvailable$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetDeviceBusPowerAvailable$FUNC - ); - public interface GetDeviceBusPowerAvailable { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceBusPowerAvailable fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceBusPowerAvailable.class, fi, IOUSBDeviceStruct942.GetDeviceBusPowerAvailable$FUNC, session); - } - static GetDeviceBusPowerAvailable ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.GetDeviceBusPowerAvailable$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetDeviceBusPowerAvailable$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceBusPowerAvailable")); - public static VarHandle GetDeviceBusPowerAvailable$VH() { - return IOUSBDeviceStruct942.GetDeviceBusPowerAvailable$VH; - } - public static MemoryAddress GetDeviceBusPowerAvailable$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceBusPowerAvailable$VH.get(seg); - } - public static void GetDeviceBusPowerAvailable$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceBusPowerAvailable$VH.set(seg, x); - } - public static MemoryAddress GetDeviceBusPowerAvailable$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceBusPowerAvailable$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceBusPowerAvailable$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceBusPowerAvailable$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceBusPowerAvailable GetDeviceBusPowerAvailable (MemorySegment segment, MemorySession session) { - return GetDeviceBusPowerAvailable.ofAddress(GetDeviceBusPowerAvailable$get(segment), session); - } - static final FunctionDescriptor GetDeviceSpeed$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceSpeed$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetDeviceSpeed$FUNC - ); - public interface GetDeviceSpeed { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceSpeed fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceSpeed.class, fi, IOUSBDeviceStruct942.GetDeviceSpeed$FUNC, session); - } - static GetDeviceSpeed ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.GetDeviceSpeed$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetDeviceSpeed$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceSpeed")); - public static VarHandle GetDeviceSpeed$VH() { - return IOUSBDeviceStruct942.GetDeviceSpeed$VH; - } - public static MemoryAddress GetDeviceSpeed$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceSpeed$VH.get(seg); - } - public static void GetDeviceSpeed$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceSpeed$VH.set(seg, x); - } - public static MemoryAddress GetDeviceSpeed$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceSpeed$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceSpeed$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceSpeed$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceSpeed GetDeviceSpeed (MemorySegment segment, MemorySession session) { - return GetDeviceSpeed.ofAddress(GetDeviceSpeed$get(segment), session); - } - static final FunctionDescriptor GetNumberOfConfigurations$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetNumberOfConfigurations$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetNumberOfConfigurations$FUNC - ); - public interface GetNumberOfConfigurations { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetNumberOfConfigurations fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetNumberOfConfigurations.class, fi, IOUSBDeviceStruct942.GetNumberOfConfigurations$FUNC, session); - } - static GetNumberOfConfigurations ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.GetNumberOfConfigurations$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetNumberOfConfigurations$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetNumberOfConfigurations")); - public static VarHandle GetNumberOfConfigurations$VH() { - return IOUSBDeviceStruct942.GetNumberOfConfigurations$VH; - } - public static MemoryAddress GetNumberOfConfigurations$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetNumberOfConfigurations$VH.get(seg); - } - public static void GetNumberOfConfigurations$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetNumberOfConfigurations$VH.set(seg, x); - } - public static MemoryAddress GetNumberOfConfigurations$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetNumberOfConfigurations$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetNumberOfConfigurations$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetNumberOfConfigurations$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetNumberOfConfigurations GetNumberOfConfigurations (MemorySegment segment, MemorySession session) { - return GetNumberOfConfigurations.ofAddress(GetNumberOfConfigurations$get(segment), session); - } - static final FunctionDescriptor GetLocationID$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetLocationID$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetLocationID$FUNC - ); - public interface GetLocationID { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetLocationID fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetLocationID.class, fi, IOUSBDeviceStruct942.GetLocationID$FUNC, session); - } - static GetLocationID ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.GetLocationID$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetLocationID$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetLocationID")); - public static VarHandle GetLocationID$VH() { - return IOUSBDeviceStruct942.GetLocationID$VH; - } - public static MemoryAddress GetLocationID$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetLocationID$VH.get(seg); - } - public static void GetLocationID$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetLocationID$VH.set(seg, x); - } - public static MemoryAddress GetLocationID$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetLocationID$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetLocationID$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetLocationID$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetLocationID GetLocationID (MemorySegment segment, MemorySession session) { - return GetLocationID.ofAddress(GetLocationID$get(segment), session); - } - static final FunctionDescriptor GetConfigurationDescriptorPtr$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetConfigurationDescriptorPtr$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetConfigurationDescriptorPtr$FUNC - ); - public interface GetConfigurationDescriptorPtr { - - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(GetConfigurationDescriptorPtr fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetConfigurationDescriptorPtr.class, fi, IOUSBDeviceStruct942.GetConfigurationDescriptorPtr$FUNC, session); - } - static GetConfigurationDescriptorPtr ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2) -> { - try { - return (int)IOUSBDeviceStruct942.GetConfigurationDescriptorPtr$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetConfigurationDescriptorPtr$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetConfigurationDescriptorPtr")); - public static VarHandle GetConfigurationDescriptorPtr$VH() { - return IOUSBDeviceStruct942.GetConfigurationDescriptorPtr$VH; - } - public static MemoryAddress GetConfigurationDescriptorPtr$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetConfigurationDescriptorPtr$VH.get(seg); - } - public static void GetConfigurationDescriptorPtr$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetConfigurationDescriptorPtr$VH.set(seg, x); - } - public static MemoryAddress GetConfigurationDescriptorPtr$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetConfigurationDescriptorPtr$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetConfigurationDescriptorPtr$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetConfigurationDescriptorPtr$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetConfigurationDescriptorPtr GetConfigurationDescriptorPtr (MemorySegment segment, MemorySession session) { - return GetConfigurationDescriptorPtr.ofAddress(GetConfigurationDescriptorPtr$get(segment), session); - } - static final FunctionDescriptor GetConfiguration$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetConfiguration$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetConfiguration$FUNC - ); - public interface GetConfiguration { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetConfiguration fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetConfiguration.class, fi, IOUSBDeviceStruct942.GetConfiguration$FUNC, session); - } - static GetConfiguration ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.GetConfiguration$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetConfiguration$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetConfiguration")); - public static VarHandle GetConfiguration$VH() { - return IOUSBDeviceStruct942.GetConfiguration$VH; - } - public static MemoryAddress GetConfiguration$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetConfiguration$VH.get(seg); - } - public static void GetConfiguration$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetConfiguration$VH.set(seg, x); - } - public static MemoryAddress GetConfiguration$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetConfiguration$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetConfiguration$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetConfiguration GetConfiguration (MemorySegment segment, MemorySession session) { - return GetConfiguration.ofAddress(GetConfiguration$get(segment), session); - } - static final FunctionDescriptor SetConfiguration$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT - ); - static final MethodHandle SetConfiguration$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.SetConfiguration$FUNC - ); - public interface SetConfiguration { - - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); - static MemorySegment allocate(SetConfiguration fi, MemorySession session) { - return RuntimeHelper.upcallStub(SetConfiguration.class, fi, IOUSBDeviceStruct942.SetConfiguration$FUNC, session); - } - static SetConfiguration ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { - try { - return (int)IOUSBDeviceStruct942.SetConfiguration$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle SetConfiguration$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetConfiguration")); - public static VarHandle SetConfiguration$VH() { - return IOUSBDeviceStruct942.SetConfiguration$VH; - } - public static MemoryAddress SetConfiguration$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.SetConfiguration$VH.get(seg); - } - public static void SetConfiguration$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.SetConfiguration$VH.set(seg, x); - } - public static MemoryAddress SetConfiguration$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.SetConfiguration$VH.get(seg.asSlice(index*sizeof())); - } - public static void SetConfiguration$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.SetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); - } - public static SetConfiguration SetConfiguration (MemorySegment segment, MemorySession session) { - return SetConfiguration.ofAddress(SetConfiguration$get(segment), session); - } - static final FunctionDescriptor GetBusFrameNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetBusFrameNumber$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetBusFrameNumber$FUNC - ); - public interface GetBusFrameNumber { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(GetBusFrameNumber fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetBusFrameNumber.class, fi, IOUSBDeviceStruct942.GetBusFrameNumber$FUNC, session); - } - static GetBusFrameNumber ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { - try { - return (int)IOUSBDeviceStruct942.GetBusFrameNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetBusFrameNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBusFrameNumber")); - public static VarHandle GetBusFrameNumber$VH() { - return IOUSBDeviceStruct942.GetBusFrameNumber$VH; - } - public static MemoryAddress GetBusFrameNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetBusFrameNumber$VH.get(seg); - } - public static void GetBusFrameNumber$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetBusFrameNumber$VH.set(seg, x); - } - public static MemoryAddress GetBusFrameNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetBusFrameNumber$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetBusFrameNumber$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetBusFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetBusFrameNumber GetBusFrameNumber (MemorySegment segment, MemorySession session) { - return GetBusFrameNumber.ofAddress(GetBusFrameNumber$get(segment), session); - } - static final FunctionDescriptor ResetDevice$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle ResetDevice$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.ResetDevice$FUNC - ); - public interface ResetDevice { - - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(ResetDevice fi, MemorySession session) { - return RuntimeHelper.upcallStub(ResetDevice.class, fi, IOUSBDeviceStruct942.ResetDevice$FUNC, session); - } - static ResetDevice ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { - try { - return (int)IOUSBDeviceStruct942.ResetDevice$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle ResetDevice$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ResetDevice")); - public static VarHandle ResetDevice$VH() { - return IOUSBDeviceStruct942.ResetDevice$VH; - } - public static MemoryAddress ResetDevice$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.ResetDevice$VH.get(seg); - } - public static void ResetDevice$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.ResetDevice$VH.set(seg, x); - } - public static MemoryAddress ResetDevice$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.ResetDevice$VH.get(seg.asSlice(index*sizeof())); - } - public static void ResetDevice$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.ResetDevice$VH.set(seg.asSlice(index*sizeof()), x); - } - public static ResetDevice ResetDevice (MemorySegment segment, MemorySession session) { - return ResetDevice.ofAddress(ResetDevice$get(segment), session); - } - static final FunctionDescriptor DeviceRequest$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle DeviceRequest$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.DeviceRequest$FUNC - ); - public interface DeviceRequest { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(DeviceRequest fi, MemorySession session) { - return RuntimeHelper.upcallStub(DeviceRequest.class, fi, IOUSBDeviceStruct942.DeviceRequest$FUNC, session); - } - static DeviceRequest ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.DeviceRequest$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle DeviceRequest$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequest")); - public static VarHandle DeviceRequest$VH() { - return IOUSBDeviceStruct942.DeviceRequest$VH; - } - public static MemoryAddress DeviceRequest$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.DeviceRequest$VH.get(seg); - } - public static void DeviceRequest$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.DeviceRequest$VH.set(seg, x); - } - public static MemoryAddress DeviceRequest$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.DeviceRequest$VH.get(seg.asSlice(index*sizeof())); - } - public static void DeviceRequest$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.DeviceRequest$VH.set(seg.asSlice(index*sizeof()), x); - } - public static DeviceRequest DeviceRequest (MemorySegment segment, MemorySession session) { - return DeviceRequest.ofAddress(DeviceRequest$get(segment), session); - } - static final FunctionDescriptor DeviceRequestAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle DeviceRequestAsync$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.DeviceRequestAsync$FUNC - ); - public interface DeviceRequestAsync { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3); - static MemorySegment allocate(DeviceRequestAsync fi, MemorySession session) { - return RuntimeHelper.upcallStub(DeviceRequestAsync.class, fi, IOUSBDeviceStruct942.DeviceRequestAsync$FUNC, session); - } - static DeviceRequestAsync ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3) -> { - try { - return (int)IOUSBDeviceStruct942.DeviceRequestAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle DeviceRequestAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestAsync")); - public static VarHandle DeviceRequestAsync$VH() { - return IOUSBDeviceStruct942.DeviceRequestAsync$VH; - } - public static MemoryAddress DeviceRequestAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.DeviceRequestAsync$VH.get(seg); - } - public static void DeviceRequestAsync$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.DeviceRequestAsync$VH.set(seg, x); - } - public static MemoryAddress DeviceRequestAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.DeviceRequestAsync$VH.get(seg.asSlice(index*sizeof())); - } - public static void DeviceRequestAsync$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.DeviceRequestAsync$VH.set(seg.asSlice(index*sizeof()), x); - } - public static DeviceRequestAsync DeviceRequestAsync (MemorySegment segment, MemorySession session) { - return DeviceRequestAsync.ofAddress(DeviceRequestAsync$get(segment), session); - } - static final FunctionDescriptor CreateInterfaceIterator$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle CreateInterfaceIterator$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.CreateInterfaceIterator$FUNC - ); - public interface CreateInterfaceIterator { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(CreateInterfaceIterator fi, MemorySession session) { - return RuntimeHelper.upcallStub(CreateInterfaceIterator.class, fi, IOUSBDeviceStruct942.CreateInterfaceIterator$FUNC, session); - } - static CreateInterfaceIterator ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { - try { - return (int)IOUSBDeviceStruct942.CreateInterfaceIterator$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle CreateInterfaceIterator$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceIterator")); - public static VarHandle CreateInterfaceIterator$VH() { - return IOUSBDeviceStruct942.CreateInterfaceIterator$VH; - } - public static MemoryAddress CreateInterfaceIterator$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.CreateInterfaceIterator$VH.get(seg); - } - public static void CreateInterfaceIterator$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.CreateInterfaceIterator$VH.set(seg, x); - } - public static MemoryAddress CreateInterfaceIterator$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.CreateInterfaceIterator$VH.get(seg.asSlice(index*sizeof())); - } - public static void CreateInterfaceIterator$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.CreateInterfaceIterator$VH.set(seg.asSlice(index*sizeof()), x); - } - public static CreateInterfaceIterator CreateInterfaceIterator (MemorySegment segment, MemorySession session) { - return CreateInterfaceIterator.ofAddress(CreateInterfaceIterator$get(segment), session); - } - static final FunctionDescriptor USBDeviceOpenSeize$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBDeviceOpenSeize$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.USBDeviceOpenSeize$FUNC - ); - public interface USBDeviceOpenSeize { - - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(USBDeviceOpenSeize fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBDeviceOpenSeize.class, fi, IOUSBDeviceStruct942.USBDeviceOpenSeize$FUNC, session); - } - static USBDeviceOpenSeize ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { - try { - return (int)IOUSBDeviceStruct942.USBDeviceOpenSeize$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle USBDeviceOpenSeize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceOpenSeize")); - public static VarHandle USBDeviceOpenSeize$VH() { - return IOUSBDeviceStruct942.USBDeviceOpenSeize$VH; - } - public static MemoryAddress USBDeviceOpenSeize$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceOpenSeize$VH.get(seg); - } - public static void USBDeviceOpenSeize$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.USBDeviceOpenSeize$VH.set(seg, x); - } - public static MemoryAddress USBDeviceOpenSeize$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceOpenSeize$VH.get(seg.asSlice(index*sizeof())); - } - public static void USBDeviceOpenSeize$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.USBDeviceOpenSeize$VH.set(seg.asSlice(index*sizeof()), x); - } - public static USBDeviceOpenSeize USBDeviceOpenSeize (MemorySegment segment, MemorySession session) { - return USBDeviceOpenSeize.ofAddress(USBDeviceOpenSeize$get(segment), session); - } - static final FunctionDescriptor DeviceRequestTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle DeviceRequestTO$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.DeviceRequestTO$FUNC - ); - public interface DeviceRequestTO { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(DeviceRequestTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(DeviceRequestTO.class, fi, IOUSBDeviceStruct942.DeviceRequestTO$FUNC, session); - } - static DeviceRequestTO ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.DeviceRequestTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle DeviceRequestTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestTO")); - public static VarHandle DeviceRequestTO$VH() { - return IOUSBDeviceStruct942.DeviceRequestTO$VH; - } - public static MemoryAddress DeviceRequestTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.DeviceRequestTO$VH.get(seg); - } - public static void DeviceRequestTO$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.DeviceRequestTO$VH.set(seg, x); - } - public static MemoryAddress DeviceRequestTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.DeviceRequestTO$VH.get(seg.asSlice(index*sizeof())); - } - public static void DeviceRequestTO$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.DeviceRequestTO$VH.set(seg.asSlice(index*sizeof()), x); - } - public static DeviceRequestTO DeviceRequestTO (MemorySegment segment, MemorySession session) { - return DeviceRequestTO.ofAddress(DeviceRequestTO$get(segment), session); - } - static final FunctionDescriptor DeviceRequestAsyncTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle DeviceRequestAsyncTO$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.DeviceRequestAsyncTO$FUNC - ); - public interface DeviceRequestAsyncTO { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3); - static MemorySegment allocate(DeviceRequestAsyncTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(DeviceRequestAsyncTO.class, fi, IOUSBDeviceStruct942.DeviceRequestAsyncTO$FUNC, session); - } - static DeviceRequestAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3) -> { - try { - return (int)IOUSBDeviceStruct942.DeviceRequestAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle DeviceRequestAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestAsyncTO")); - public static VarHandle DeviceRequestAsyncTO$VH() { - return IOUSBDeviceStruct942.DeviceRequestAsyncTO$VH; - } - public static MemoryAddress DeviceRequestAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.DeviceRequestAsyncTO$VH.get(seg); - } - public static void DeviceRequestAsyncTO$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.DeviceRequestAsyncTO$VH.set(seg, x); - } - public static MemoryAddress DeviceRequestAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.DeviceRequestAsyncTO$VH.get(seg.asSlice(index*sizeof())); - } - public static void DeviceRequestAsyncTO$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.DeviceRequestAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); - } - public static DeviceRequestAsyncTO DeviceRequestAsyncTO (MemorySegment segment, MemorySession session) { - return DeviceRequestAsyncTO.ofAddress(DeviceRequestAsyncTO$get(segment), session); - } - static final FunctionDescriptor USBDeviceSuspend$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT - ); - static final MethodHandle USBDeviceSuspend$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.USBDeviceSuspend$FUNC - ); - public interface USBDeviceSuspend { - - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); - static MemorySegment allocate(USBDeviceSuspend fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBDeviceSuspend.class, fi, IOUSBDeviceStruct942.USBDeviceSuspend$FUNC, session); - } - static USBDeviceSuspend ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { - try { - return (int)IOUSBDeviceStruct942.USBDeviceSuspend$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle USBDeviceSuspend$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceSuspend")); - public static VarHandle USBDeviceSuspend$VH() { - return IOUSBDeviceStruct942.USBDeviceSuspend$VH; - } - public static MemoryAddress USBDeviceSuspend$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceSuspend$VH.get(seg); - } - public static void USBDeviceSuspend$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.USBDeviceSuspend$VH.set(seg, x); - } - public static MemoryAddress USBDeviceSuspend$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceSuspend$VH.get(seg.asSlice(index*sizeof())); - } - public static void USBDeviceSuspend$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.USBDeviceSuspend$VH.set(seg.asSlice(index*sizeof()), x); - } - public static USBDeviceSuspend USBDeviceSuspend (MemorySegment segment, MemorySession session) { - return USBDeviceSuspend.ofAddress(USBDeviceSuspend$get(segment), session); - } - static final FunctionDescriptor USBDeviceAbortPipeZero$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBDeviceAbortPipeZero$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.USBDeviceAbortPipeZero$FUNC - ); - public interface USBDeviceAbortPipeZero { - - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(USBDeviceAbortPipeZero fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBDeviceAbortPipeZero.class, fi, IOUSBDeviceStruct942.USBDeviceAbortPipeZero$FUNC, session); - } - static USBDeviceAbortPipeZero ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { - try { - return (int)IOUSBDeviceStruct942.USBDeviceAbortPipeZero$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle USBDeviceAbortPipeZero$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceAbortPipeZero")); - public static VarHandle USBDeviceAbortPipeZero$VH() { - return IOUSBDeviceStruct942.USBDeviceAbortPipeZero$VH; - } - public static MemoryAddress USBDeviceAbortPipeZero$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceAbortPipeZero$VH.get(seg); - } - public static void USBDeviceAbortPipeZero$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.USBDeviceAbortPipeZero$VH.set(seg, x); - } - public static MemoryAddress USBDeviceAbortPipeZero$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceAbortPipeZero$VH.get(seg.asSlice(index*sizeof())); - } - public static void USBDeviceAbortPipeZero$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.USBDeviceAbortPipeZero$VH.set(seg.asSlice(index*sizeof()), x); - } - public static USBDeviceAbortPipeZero USBDeviceAbortPipeZero (MemorySegment segment, MemorySession session) { - return USBDeviceAbortPipeZero.ofAddress(USBDeviceAbortPipeZero$get(segment), session); - } - static final FunctionDescriptor USBGetManufacturerStringIndex$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBGetManufacturerStringIndex$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.USBGetManufacturerStringIndex$FUNC - ); - public interface USBGetManufacturerStringIndex { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(USBGetManufacturerStringIndex fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBGetManufacturerStringIndex.class, fi, IOUSBDeviceStruct942.USBGetManufacturerStringIndex$FUNC, session); - } - static USBGetManufacturerStringIndex ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.USBGetManufacturerStringIndex$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle USBGetManufacturerStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBGetManufacturerStringIndex")); - public static VarHandle USBGetManufacturerStringIndex$VH() { - return IOUSBDeviceStruct942.USBGetManufacturerStringIndex$VH; - } - public static MemoryAddress USBGetManufacturerStringIndex$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBGetManufacturerStringIndex$VH.get(seg); - } - public static void USBGetManufacturerStringIndex$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.USBGetManufacturerStringIndex$VH.set(seg, x); - } - public static MemoryAddress USBGetManufacturerStringIndex$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBGetManufacturerStringIndex$VH.get(seg.asSlice(index*sizeof())); - } - public static void USBGetManufacturerStringIndex$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.USBGetManufacturerStringIndex$VH.set(seg.asSlice(index*sizeof()), x); - } - public static USBGetManufacturerStringIndex USBGetManufacturerStringIndex (MemorySegment segment, MemorySession session) { - return USBGetManufacturerStringIndex.ofAddress(USBGetManufacturerStringIndex$get(segment), session); - } - static final FunctionDescriptor USBGetProductStringIndex$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBGetProductStringIndex$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.USBGetProductStringIndex$FUNC - ); - public interface USBGetProductStringIndex { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(USBGetProductStringIndex fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBGetProductStringIndex.class, fi, IOUSBDeviceStruct942.USBGetProductStringIndex$FUNC, session); - } - static USBGetProductStringIndex ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.USBGetProductStringIndex$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle USBGetProductStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBGetProductStringIndex")); - public static VarHandle USBGetProductStringIndex$VH() { - return IOUSBDeviceStruct942.USBGetProductStringIndex$VH; - } - public static MemoryAddress USBGetProductStringIndex$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBGetProductStringIndex$VH.get(seg); - } - public static void USBGetProductStringIndex$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.USBGetProductStringIndex$VH.set(seg, x); - } - public static MemoryAddress USBGetProductStringIndex$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBGetProductStringIndex$VH.get(seg.asSlice(index*sizeof())); - } - public static void USBGetProductStringIndex$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.USBGetProductStringIndex$VH.set(seg.asSlice(index*sizeof()), x); - } - public static USBGetProductStringIndex USBGetProductStringIndex (MemorySegment segment, MemorySession session) { - return USBGetProductStringIndex.ofAddress(USBGetProductStringIndex$get(segment), session); - } - static final FunctionDescriptor USBGetSerialNumberStringIndex$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBGetSerialNumberStringIndex$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.USBGetSerialNumberStringIndex$FUNC - ); - public interface USBGetSerialNumberStringIndex { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(USBGetSerialNumberStringIndex fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBGetSerialNumberStringIndex.class, fi, IOUSBDeviceStruct942.USBGetSerialNumberStringIndex$FUNC, session); - } - static USBGetSerialNumberStringIndex ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.USBGetSerialNumberStringIndex$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle USBGetSerialNumberStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBGetSerialNumberStringIndex")); - public static VarHandle USBGetSerialNumberStringIndex$VH() { - return IOUSBDeviceStruct942.USBGetSerialNumberStringIndex$VH; - } - public static MemoryAddress USBGetSerialNumberStringIndex$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBGetSerialNumberStringIndex$VH.get(seg); - } - public static void USBGetSerialNumberStringIndex$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.USBGetSerialNumberStringIndex$VH.set(seg, x); - } - public static MemoryAddress USBGetSerialNumberStringIndex$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBGetSerialNumberStringIndex$VH.get(seg.asSlice(index*sizeof())); - } - public static void USBGetSerialNumberStringIndex$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.USBGetSerialNumberStringIndex$VH.set(seg.asSlice(index*sizeof()), x); - } - public static USBGetSerialNumberStringIndex USBGetSerialNumberStringIndex (MemorySegment segment, MemorySession session) { - return USBGetSerialNumberStringIndex.ofAddress(USBGetSerialNumberStringIndex$get(segment), session); - } - static final FunctionDescriptor USBDeviceReEnumerate$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle USBDeviceReEnumerate$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.USBDeviceReEnumerate$FUNC - ); - public interface USBDeviceReEnumerate { - - int apply(java.lang.foreign.MemoryAddress _x0, int _x1); - static MemorySegment allocate(USBDeviceReEnumerate fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBDeviceReEnumerate.class, fi, IOUSBDeviceStruct942.USBDeviceReEnumerate$FUNC, session); - } - static USBDeviceReEnumerate ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, int __x1) -> { - try { - return (int)IOUSBDeviceStruct942.USBDeviceReEnumerate$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle USBDeviceReEnumerate$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceReEnumerate")); - public static VarHandle USBDeviceReEnumerate$VH() { - return IOUSBDeviceStruct942.USBDeviceReEnumerate$VH; - } - public static MemoryAddress USBDeviceReEnumerate$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceReEnumerate$VH.get(seg); - } - public static void USBDeviceReEnumerate$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.USBDeviceReEnumerate$VH.set(seg, x); - } - public static MemoryAddress USBDeviceReEnumerate$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.USBDeviceReEnumerate$VH.get(seg.asSlice(index*sizeof())); - } - public static void USBDeviceReEnumerate$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.USBDeviceReEnumerate$VH.set(seg.asSlice(index*sizeof()), x); - } - public static USBDeviceReEnumerate USBDeviceReEnumerate (MemorySegment segment, MemorySession session) { - return USBDeviceReEnumerate.ofAddress(USBDeviceReEnumerate$get(segment), session); - } - static final FunctionDescriptor GetBusMicroFrameNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetBusMicroFrameNumber$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetBusMicroFrameNumber$FUNC - ); - public interface GetBusMicroFrameNumber { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(GetBusMicroFrameNumber fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetBusMicroFrameNumber.class, fi, IOUSBDeviceStruct942.GetBusMicroFrameNumber$FUNC, session); - } - static GetBusMicroFrameNumber ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { - try { - return (int)IOUSBDeviceStruct942.GetBusMicroFrameNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetBusMicroFrameNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBusMicroFrameNumber")); - public static VarHandle GetBusMicroFrameNumber$VH() { - return IOUSBDeviceStruct942.GetBusMicroFrameNumber$VH; - } - public static MemoryAddress GetBusMicroFrameNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetBusMicroFrameNumber$VH.get(seg); - } - public static void GetBusMicroFrameNumber$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetBusMicroFrameNumber$VH.set(seg, x); - } - public static MemoryAddress GetBusMicroFrameNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetBusMicroFrameNumber$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetBusMicroFrameNumber$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetBusMicroFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetBusMicroFrameNumber GetBusMicroFrameNumber (MemorySegment segment, MemorySession session) { - return GetBusMicroFrameNumber.ofAddress(GetBusMicroFrameNumber$get(segment), session); - } - static final FunctionDescriptor GetIOUSBLibVersion$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetIOUSBLibVersion$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetIOUSBLibVersion$FUNC - ); - public interface GetIOUSBLibVersion { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(GetIOUSBLibVersion fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetIOUSBLibVersion.class, fi, IOUSBDeviceStruct942.GetIOUSBLibVersion$FUNC, session); - } - static GetIOUSBLibVersion ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { - try { - return (int)IOUSBDeviceStruct942.GetIOUSBLibVersion$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetIOUSBLibVersion$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetIOUSBLibVersion")); - public static VarHandle GetIOUSBLibVersion$VH() { - return IOUSBDeviceStruct942.GetIOUSBLibVersion$VH; - } - public static MemoryAddress GetIOUSBLibVersion$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetIOUSBLibVersion$VH.get(seg); - } - public static void GetIOUSBLibVersion$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetIOUSBLibVersion$VH.set(seg, x); - } - public static MemoryAddress GetIOUSBLibVersion$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetIOUSBLibVersion$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetIOUSBLibVersion$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetIOUSBLibVersion$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetIOUSBLibVersion GetIOUSBLibVersion (MemorySegment segment, MemorySession session) { - return GetIOUSBLibVersion.ofAddress(GetIOUSBLibVersion$get(segment), session); - } - static final FunctionDescriptor GetBusFrameNumberWithTime$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetBusFrameNumberWithTime$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetBusFrameNumberWithTime$FUNC - ); - public interface GetBusFrameNumberWithTime { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(GetBusFrameNumberWithTime fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetBusFrameNumberWithTime.class, fi, IOUSBDeviceStruct942.GetBusFrameNumberWithTime$FUNC, session); - } - static GetBusFrameNumberWithTime ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { - try { - return (int)IOUSBDeviceStruct942.GetBusFrameNumberWithTime$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetBusFrameNumberWithTime$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBusFrameNumberWithTime")); - public static VarHandle GetBusFrameNumberWithTime$VH() { - return IOUSBDeviceStruct942.GetBusFrameNumberWithTime$VH; - } - public static MemoryAddress GetBusFrameNumberWithTime$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetBusFrameNumberWithTime$VH.get(seg); - } - public static void GetBusFrameNumberWithTime$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetBusFrameNumberWithTime$VH.set(seg, x); - } - public static MemoryAddress GetBusFrameNumberWithTime$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetBusFrameNumberWithTime$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetBusFrameNumberWithTime$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetBusFrameNumberWithTime$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetBusFrameNumberWithTime GetBusFrameNumberWithTime (MemorySegment segment, MemorySession session) { - return GetBusFrameNumberWithTime.ofAddress(GetBusFrameNumberWithTime$get(segment), session); - } - static final FunctionDescriptor GetUSBDeviceInformation$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetUSBDeviceInformation$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetUSBDeviceInformation$FUNC - ); - public interface GetUSBDeviceInformation { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetUSBDeviceInformation fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetUSBDeviceInformation.class, fi, IOUSBDeviceStruct942.GetUSBDeviceInformation$FUNC, session); - } - static GetUSBDeviceInformation ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.GetUSBDeviceInformation$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetUSBDeviceInformation$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetUSBDeviceInformation")); - public static VarHandle GetUSBDeviceInformation$VH() { - return IOUSBDeviceStruct942.GetUSBDeviceInformation$VH; - } - public static MemoryAddress GetUSBDeviceInformation$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetUSBDeviceInformation$VH.get(seg); - } - public static void GetUSBDeviceInformation$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetUSBDeviceInformation$VH.set(seg, x); - } - public static MemoryAddress GetUSBDeviceInformation$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetUSBDeviceInformation$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetUSBDeviceInformation$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetUSBDeviceInformation$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetUSBDeviceInformation GetUSBDeviceInformation (MemorySegment segment, MemorySession session) { - return GetUSBDeviceInformation.ofAddress(GetUSBDeviceInformation$get(segment), session); - } - static final FunctionDescriptor RequestExtraPower$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle RequestExtraPower$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.RequestExtraPower$FUNC - ); - public interface RequestExtraPower { - - int apply(java.lang.foreign.MemoryAddress _x0, int _x1, int _x2, java.lang.foreign.MemoryAddress _x3); - static MemorySegment allocate(RequestExtraPower fi, MemorySession session) { - return RuntimeHelper.upcallStub(RequestExtraPower.class, fi, IOUSBDeviceStruct942.RequestExtraPower$FUNC, session); - } - static RequestExtraPower ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, int __x1, int __x2, java.lang.foreign.MemoryAddress __x3) -> { - try { - return (int)IOUSBDeviceStruct942.RequestExtraPower$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, (java.lang.foreign.Addressable)__x3); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle RequestExtraPower$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("RequestExtraPower")); - public static VarHandle RequestExtraPower$VH() { - return IOUSBDeviceStruct942.RequestExtraPower$VH; - } - public static MemoryAddress RequestExtraPower$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.RequestExtraPower$VH.get(seg); - } - public static void RequestExtraPower$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.RequestExtraPower$VH.set(seg, x); - } - public static MemoryAddress RequestExtraPower$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.RequestExtraPower$VH.get(seg.asSlice(index*sizeof())); - } - public static void RequestExtraPower$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.RequestExtraPower$VH.set(seg.asSlice(index*sizeof()), x); - } - public static RequestExtraPower RequestExtraPower (MemorySegment segment, MemorySession session) { - return RequestExtraPower.ofAddress(RequestExtraPower$get(segment), session); - } - static final FunctionDescriptor ReturnExtraPower$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle ReturnExtraPower$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.ReturnExtraPower$FUNC - ); - public interface ReturnExtraPower { - - int apply(java.lang.foreign.MemoryAddress _x0, int _x1, int _x2); - static MemorySegment allocate(ReturnExtraPower fi, MemorySession session) { - return RuntimeHelper.upcallStub(ReturnExtraPower.class, fi, IOUSBDeviceStruct942.ReturnExtraPower$FUNC, session); - } - static ReturnExtraPower ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, int __x1, int __x2) -> { - try { - return (int)IOUSBDeviceStruct942.ReturnExtraPower$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle ReturnExtraPower$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReturnExtraPower")); - public static VarHandle ReturnExtraPower$VH() { - return IOUSBDeviceStruct942.ReturnExtraPower$VH; - } - public static MemoryAddress ReturnExtraPower$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.ReturnExtraPower$VH.get(seg); - } - public static void ReturnExtraPower$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.ReturnExtraPower$VH.set(seg, x); - } - public static MemoryAddress ReturnExtraPower$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.ReturnExtraPower$VH.get(seg.asSlice(index*sizeof())); - } - public static void ReturnExtraPower$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.ReturnExtraPower$VH.set(seg.asSlice(index*sizeof()), x); - } - public static ReturnExtraPower ReturnExtraPower (MemorySegment segment, MemorySession session) { - return ReturnExtraPower.ofAddress(ReturnExtraPower$get(segment), session); - } - static final FunctionDescriptor GetExtraPowerAllocated$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetExtraPowerAllocated$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetExtraPowerAllocated$FUNC - ); - public interface GetExtraPowerAllocated { - - int apply(java.lang.foreign.MemoryAddress _x0, int _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(GetExtraPowerAllocated fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetExtraPowerAllocated.class, fi, IOUSBDeviceStruct942.GetExtraPowerAllocated$FUNC, session); - } - static GetExtraPowerAllocated ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, int __x1, java.lang.foreign.MemoryAddress __x2) -> { - try { - return (int)IOUSBDeviceStruct942.GetExtraPowerAllocated$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetExtraPowerAllocated$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetExtraPowerAllocated")); - public static VarHandle GetExtraPowerAllocated$VH() { - return IOUSBDeviceStruct942.GetExtraPowerAllocated$VH; - } - public static MemoryAddress GetExtraPowerAllocated$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetExtraPowerAllocated$VH.get(seg); - } - public static void GetExtraPowerAllocated$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetExtraPowerAllocated$VH.set(seg, x); - } - public static MemoryAddress GetExtraPowerAllocated$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetExtraPowerAllocated$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetExtraPowerAllocated$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetExtraPowerAllocated$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetExtraPowerAllocated GetExtraPowerAllocated (MemorySegment segment, MemorySession session) { - return GetExtraPowerAllocated.ofAddress(GetExtraPowerAllocated$get(segment), session); - } - static final FunctionDescriptor GetBandwidthAvailableForDevice$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetBandwidthAvailableForDevice$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetBandwidthAvailableForDevice$FUNC - ); - public interface GetBandwidthAvailableForDevice { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetBandwidthAvailableForDevice fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetBandwidthAvailableForDevice.class, fi, IOUSBDeviceStruct942.GetBandwidthAvailableForDevice$FUNC, session); - } - static GetBandwidthAvailableForDevice ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBDeviceStruct942.GetBandwidthAvailableForDevice$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetBandwidthAvailableForDevice$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBandwidthAvailableForDevice")); - public static VarHandle GetBandwidthAvailableForDevice$VH() { - return IOUSBDeviceStruct942.GetBandwidthAvailableForDevice$VH; - } - public static MemoryAddress GetBandwidthAvailableForDevice$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetBandwidthAvailableForDevice$VH.get(seg); - } - public static void GetBandwidthAvailableForDevice$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetBandwidthAvailableForDevice$VH.set(seg, x); - } - public static MemoryAddress GetBandwidthAvailableForDevice$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetBandwidthAvailableForDevice$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetBandwidthAvailableForDevice$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetBandwidthAvailableForDevice$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetBandwidthAvailableForDevice GetBandwidthAvailableForDevice (MemorySegment segment, MemorySession session) { - return GetBandwidthAvailableForDevice.ofAddress(GetBandwidthAvailableForDevice$get(segment), session); - } - static final FunctionDescriptor SetConfigurationV2$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_BOOL$LAYOUT, - Constants$root.C_BOOL$LAYOUT - ); - static final MethodHandle SetConfigurationV2$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.SetConfigurationV2$FUNC - ); - public interface SetConfigurationV2 { - - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, boolean _x2, boolean _x3); - static MemorySegment allocate(SetConfigurationV2 fi, MemorySession session) { - return RuntimeHelper.upcallStub(SetConfigurationV2.class, fi, IOUSBDeviceStruct942.SetConfigurationV2$FUNC, session); - } - static SetConfigurationV2 ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, boolean __x2, boolean __x3) -> { - try { - return (int)IOUSBDeviceStruct942.SetConfigurationV2$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, __x3); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle SetConfigurationV2$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetConfigurationV2")); - public static VarHandle SetConfigurationV2$VH() { - return IOUSBDeviceStruct942.SetConfigurationV2$VH; - } - public static MemoryAddress SetConfigurationV2$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.SetConfigurationV2$VH.get(seg); - } - public static void SetConfigurationV2$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.SetConfigurationV2$VH.set(seg, x); - } - public static MemoryAddress SetConfigurationV2$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.SetConfigurationV2$VH.get(seg.asSlice(index*sizeof())); - } - public static void SetConfigurationV2$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.SetConfigurationV2$VH.set(seg.asSlice(index*sizeof()), x); - } - public static SetConfigurationV2 SetConfigurationV2 (MemorySegment segment, MemorySession session) { - return SetConfigurationV2.ofAddress(SetConfigurationV2$get(segment), session); - } - static final FunctionDescriptor RegisterForNotification$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle RegisterForNotification$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.RegisterForNotification$FUNC - ); - public interface RegisterForNotification { - - int apply(java.lang.foreign.MemoryAddress _x0, long _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, java.lang.foreign.MemoryAddress _x4); - static MemorySegment allocate(RegisterForNotification fi, MemorySession session) { - return RuntimeHelper.upcallStub(RegisterForNotification.class, fi, IOUSBDeviceStruct942.RegisterForNotification$FUNC, session); - } - static RegisterForNotification ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, long __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, java.lang.foreign.MemoryAddress __x4) -> { - try { - return (int)IOUSBDeviceStruct942.RegisterForNotification$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle RegisterForNotification$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("RegisterForNotification")); - public static VarHandle RegisterForNotification$VH() { - return IOUSBDeviceStruct942.RegisterForNotification$VH; - } - public static MemoryAddress RegisterForNotification$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.RegisterForNotification$VH.get(seg); - } - public static void RegisterForNotification$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.RegisterForNotification$VH.set(seg, x); - } - public static MemoryAddress RegisterForNotification$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.RegisterForNotification$VH.get(seg.asSlice(index*sizeof())); - } - public static void RegisterForNotification$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.RegisterForNotification$VH.set(seg.asSlice(index*sizeof()), x); - } - public static RegisterForNotification RegisterForNotification (MemorySegment segment, MemorySession session) { - return RegisterForNotification.ofAddress(RegisterForNotification$get(segment), session); - } - static final FunctionDescriptor UnregisterNotification$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle UnregisterNotification$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.UnregisterNotification$FUNC - ); - public interface UnregisterNotification { - - int apply(java.lang.foreign.MemoryAddress _x0, long _x1); - static MemorySegment allocate(UnregisterNotification fi, MemorySession session) { - return RuntimeHelper.upcallStub(UnregisterNotification.class, fi, IOUSBDeviceStruct942.UnregisterNotification$FUNC, session); - } - static UnregisterNotification ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, long __x1) -> { - try { - return (int)IOUSBDeviceStruct942.UnregisterNotification$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle UnregisterNotification$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("UnregisterNotification")); - public static VarHandle UnregisterNotification$VH() { - return IOUSBDeviceStruct942.UnregisterNotification$VH; - } - public static MemoryAddress UnregisterNotification$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.UnregisterNotification$VH.get(seg); - } - public static void UnregisterNotification$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.UnregisterNotification$VH.set(seg, x); - } - public static MemoryAddress UnregisterNotification$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.UnregisterNotification$VH.get(seg.asSlice(index*sizeof())); - } - public static void UnregisterNotification$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.UnregisterNotification$VH.set(seg.asSlice(index*sizeof()), x); - } - public static UnregisterNotification UnregisterNotification (MemorySegment segment, MemorySession session) { - return UnregisterNotification.ofAddress(UnregisterNotification$get(segment), session); - } - static final FunctionDescriptor AcknowledgeNotification$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle AcknowledgeNotification$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.AcknowledgeNotification$FUNC - ); - public interface AcknowledgeNotification { - - int apply(java.lang.foreign.MemoryAddress _x0, long _x1); - static MemorySegment allocate(AcknowledgeNotification fi, MemorySession session) { - return RuntimeHelper.upcallStub(AcknowledgeNotification.class, fi, IOUSBDeviceStruct942.AcknowledgeNotification$FUNC, session); - } - static AcknowledgeNotification ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, long __x1) -> { - try { - return (int)IOUSBDeviceStruct942.AcknowledgeNotification$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle AcknowledgeNotification$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AcknowledgeNotification")); - public static VarHandle AcknowledgeNotification$VH() { - return IOUSBDeviceStruct942.AcknowledgeNotification$VH; - } - public static MemoryAddress AcknowledgeNotification$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.AcknowledgeNotification$VH.get(seg); - } - public static void AcknowledgeNotification$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.AcknowledgeNotification$VH.set(seg, x); - } - public static MemoryAddress AcknowledgeNotification$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.AcknowledgeNotification$VH.get(seg.asSlice(index*sizeof())); - } - public static void AcknowledgeNotification$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.AcknowledgeNotification$VH.set(seg.asSlice(index*sizeof()), x); - } - public static AcknowledgeNotification AcknowledgeNotification (MemorySegment segment, MemorySession session) { - return AcknowledgeNotification.ofAddress(AcknowledgeNotification$get(segment), session); - } - static final FunctionDescriptor GetDeviceAsyncNotificationPort$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceAsyncNotificationPort$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct942.GetDeviceAsyncNotificationPort$FUNC - ); - public interface GetDeviceAsyncNotificationPort { - - java.lang.foreign.Addressable apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(GetDeviceAsyncNotificationPort fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceAsyncNotificationPort.class, fi, IOUSBDeviceStruct942.GetDeviceAsyncNotificationPort$FUNC, session); - } - static GetDeviceAsyncNotificationPort ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { - try { - return (java.lang.foreign.Addressable)(java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAsyncNotificationPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetDeviceAsyncNotificationPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncNotificationPort")); - public static VarHandle GetDeviceAsyncNotificationPort$VH() { - return IOUSBDeviceStruct942.GetDeviceAsyncNotificationPort$VH; - } - public static MemoryAddress GetDeviceAsyncNotificationPort$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAsyncNotificationPort$VH.get(seg); - } - public static void GetDeviceAsyncNotificationPort$set( MemorySegment seg, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceAsyncNotificationPort$VH.set(seg, x); - } - public static MemoryAddress GetDeviceAsyncNotificationPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct942.GetDeviceAsyncNotificationPort$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceAsyncNotificationPort$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBDeviceStruct942.GetDeviceAsyncNotificationPort$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceAsyncNotificationPort GetDeviceAsyncNotificationPort (MemorySegment segment, MemorySession session) { - return GetDeviceAsyncNotificationPort.ofAddress(GetDeviceAsyncNotificationPort$get(segment), session); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface190.java similarity index 50% rename from java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface.java rename to java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface190.java index 11bc0952..53199116 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface190.java @@ -2,7 +2,7 @@ package net.codecrete.usb.macos.gen.iokit; -public class IOUSBInterfaceInterface extends IOUSBInterfaceStruct942 { +public class IOUSBInterfaceInterface190 extends IOUSBInterfaceStruct190 { } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct942.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java similarity index 51% rename from java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct942.java rename to java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java index 26284e6f..320879fc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct942.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java @@ -5,7 +5,7 @@ import java.lang.foreign.*; import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; -public class IOUSBInterfaceStruct942 { +public class IOUSBInterfaceStruct190 { static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_POINTER$LAYOUT.withName("_reserved"), @@ -56,54 +56,26 @@ public class IOUSBInterfaceStruct942 { Constants$root.C_POINTER$LAYOUT.withName("ClearPipeStallBothEnds"), Constants$root.C_POINTER$LAYOUT.withName("SetPipePolicy"), Constants$root.C_POINTER$LAYOUT.withName("GetBandwidthAvailable"), - Constants$root.C_POINTER$LAYOUT.withName("GetEndpointProperties"), - Constants$root.C_POINTER$LAYOUT.withName("LowLatencyReadIsochPipeAsync"), - Constants$root.C_POINTER$LAYOUT.withName("LowLatencyWriteIsochPipeAsync"), - Constants$root.C_POINTER$LAYOUT.withName("LowLatencyCreateBuffer"), - Constants$root.C_POINTER$LAYOUT.withName("LowLatencyDestroyBuffer"), - Constants$root.C_POINTER$LAYOUT.withName("GetBusMicroFrameNumber"), - Constants$root.C_POINTER$LAYOUT.withName("GetFrameListTime"), - Constants$root.C_POINTER$LAYOUT.withName("GetIOUSBLibVersion"), - Constants$root.C_POINTER$LAYOUT.withName("FindNextAssociatedDescriptor"), - Constants$root.C_POINTER$LAYOUT.withName("FindNextAltInterface"), - Constants$root.C_POINTER$LAYOUT.withName("GetBusFrameNumberWithTime"), - Constants$root.C_POINTER$LAYOUT.withName("GetPipePropertiesV2"), - Constants$root.C_POINTER$LAYOUT.withName("GetPipePropertiesV3"), - Constants$root.C_POINTER$LAYOUT.withName("GetEndpointPropertiesV3"), - Constants$root.C_POINTER$LAYOUT.withName("SupportsStreams"), - Constants$root.C_POINTER$LAYOUT.withName("CreateStreams"), - Constants$root.C_POINTER$LAYOUT.withName("GetConfiguredStreams"), - Constants$root.C_POINTER$LAYOUT.withName("ReadStreamsPipeTO"), - Constants$root.C_POINTER$LAYOUT.withName("WriteStreamsPipeTO"), - Constants$root.C_POINTER$LAYOUT.withName("ReadStreamsPipeAsyncTO"), - Constants$root.C_POINTER$LAYOUT.withName("WriteStreamsPipeAsyncTO"), - Constants$root.C_POINTER$LAYOUT.withName("AbortStreamsPipe"), - Constants$root.C_POINTER$LAYOUT.withName("RegisterForNotification"), - Constants$root.C_POINTER$LAYOUT.withName("UnregisterNotification"), - Constants$root.C_POINTER$LAYOUT.withName("AcknowledgeNotification"), - Constants$root.C_POINTER$LAYOUT.withName("RegisterDriver"), - Constants$root.C_POINTER$LAYOUT.withName("SetDeviceIdlePolicy"), - Constants$root.C_POINTER$LAYOUT.withName("SetPipeIdlePolicy"), - Constants$root.C_POINTER$LAYOUT.withName("GetInterfaceAsyncNotificationPort") - ).withName("IOUSBInterfaceStruct942"); + Constants$root.C_POINTER$LAYOUT.withName("GetEndpointProperties") + ).withName("IOUSBInterfaceStruct190"); public static MemoryLayout $LAYOUT() { - return IOUSBInterfaceStruct942.$struct$LAYOUT; + return IOUSBInterfaceStruct190.$struct$LAYOUT; } static final VarHandle _reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("_reserved")); public static VarHandle _reserved$VH() { - return IOUSBInterfaceStruct942._reserved$VH; + return IOUSBInterfaceStruct190._reserved$VH; } public static MemoryAddress _reserved$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942._reserved$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190._reserved$VH.get(seg); } public static void _reserved$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942._reserved$VH.set(seg, x); + IOUSBInterfaceStruct190._reserved$VH.set(seg, x); } public static MemoryAddress _reserved$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942._reserved$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190._reserved$VH.get(seg.asSlice(index*sizeof())); } public static void _reserved$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942._reserved$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190._reserved$VH.set(seg.asSlice(index*sizeof()), x); } static final FunctionDescriptor QueryInterface$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -128,19 +100,19 @@ public class IOUSBInterfaceStruct942 { Constants$root.C_POINTER$LAYOUT ); static final MethodHandle QueryInterface$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.QueryInterface$FUNC + IOUSBInterfaceStruct190.QueryInterface$FUNC ); public interface QueryInterface { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemoryAddress _x2); static MemorySegment allocate(QueryInterface fi, MemorySession session) { - return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOUSBInterfaceStruct942.QueryInterface$FUNC, session); + return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOUSBInterfaceStruct190.QueryInterface$FUNC, session); } static QueryInterface ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemoryAddress __x2) -> { try { - return (int)IOUSBInterfaceStruct942.QueryInterface$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + return (int)IOUSBInterfaceStruct190.QueryInterface$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -150,19 +122,19 @@ static QueryInterface ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle QueryInterface$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("QueryInterface")); public static VarHandle QueryInterface$VH() { - return IOUSBInterfaceStruct942.QueryInterface$VH; + return IOUSBInterfaceStruct190.QueryInterface$VH; } public static MemoryAddress QueryInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.QueryInterface$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.QueryInterface$VH.get(seg); } public static void QueryInterface$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.QueryInterface$VH.set(seg, x); + IOUSBInterfaceStruct190.QueryInterface$VH.set(seg, x); } public static MemoryAddress QueryInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.QueryInterface$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.QueryInterface$VH.get(seg.asSlice(index*sizeof())); } public static void QueryInterface$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.QueryInterface$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.QueryInterface$VH.set(seg.asSlice(index*sizeof()), x); } public static QueryInterface QueryInterface (MemorySegment segment, MemorySession session) { return QueryInterface.ofAddress(QueryInterface$get(segment), session); @@ -171,19 +143,19 @@ public static QueryInterface QueryInterface (MemorySegment segment, MemorySessio Constants$root.C_POINTER$LAYOUT ); static final MethodHandle AddRef$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.AddRef$FUNC + IOUSBInterfaceStruct190.AddRef$FUNC ); public interface AddRef { int apply(java.lang.foreign.MemoryAddress _x0); static MemorySegment allocate(AddRef fi, MemorySession session) { - return RuntimeHelper.upcallStub(AddRef.class, fi, IOUSBInterfaceStruct942.AddRef$FUNC, session); + return RuntimeHelper.upcallStub(AddRef.class, fi, IOUSBInterfaceStruct190.AddRef$FUNC, session); } static AddRef ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0) -> { try { - return (int)IOUSBInterfaceStruct942.AddRef$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBInterfaceStruct190.AddRef$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -193,19 +165,19 @@ static AddRef ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle AddRef$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AddRef")); public static VarHandle AddRef$VH() { - return IOUSBInterfaceStruct942.AddRef$VH; + return IOUSBInterfaceStruct190.AddRef$VH; } public static MemoryAddress AddRef$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.AddRef$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.AddRef$VH.get(seg); } public static void AddRef$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.AddRef$VH.set(seg, x); + IOUSBInterfaceStruct190.AddRef$VH.set(seg, x); } public static MemoryAddress AddRef$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.AddRef$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.AddRef$VH.get(seg.asSlice(index*sizeof())); } public static void AddRef$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.AddRef$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.AddRef$VH.set(seg.asSlice(index*sizeof()), x); } public static AddRef AddRef (MemorySegment segment, MemorySession session) { return AddRef.ofAddress(AddRef$get(segment), session); @@ -214,19 +186,19 @@ public static AddRef AddRef (MemorySegment segment, MemorySession session) { Constants$root.C_POINTER$LAYOUT ); static final MethodHandle Release$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.Release$FUNC + IOUSBInterfaceStruct190.Release$FUNC ); public interface Release { int apply(java.lang.foreign.MemoryAddress _x0); static MemorySegment allocate(Release fi, MemorySession session) { - return RuntimeHelper.upcallStub(Release.class, fi, IOUSBInterfaceStruct942.Release$FUNC, session); + return RuntimeHelper.upcallStub(Release.class, fi, IOUSBInterfaceStruct190.Release$FUNC, session); } static Release ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0) -> { try { - return (int)IOUSBInterfaceStruct942.Release$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBInterfaceStruct190.Release$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -236,19 +208,19 @@ static Release ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle Release$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Release")); public static VarHandle Release$VH() { - return IOUSBInterfaceStruct942.Release$VH; + return IOUSBInterfaceStruct190.Release$VH; } public static MemoryAddress Release$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.Release$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.Release$VH.get(seg); } public static void Release$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.Release$VH.set(seg, x); + IOUSBInterfaceStruct190.Release$VH.set(seg, x); } public static MemoryAddress Release$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.Release$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.Release$VH.get(seg.asSlice(index*sizeof())); } public static void Release$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.Release$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.Release$VH.set(seg.asSlice(index*sizeof()), x); } public static Release Release (MemorySegment segment, MemorySession session) { return Release.ofAddress(Release$get(segment), session); @@ -258,19 +230,19 @@ public static Release Release (MemorySegment segment, MemorySession session) { Constants$root.C_POINTER$LAYOUT ); static final MethodHandle CreateInterfaceAsyncEventSource$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.CreateInterfaceAsyncEventSource$FUNC + IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$FUNC ); public interface CreateInterfaceAsyncEventSource { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); static MemorySegment allocate(CreateInterfaceAsyncEventSource fi, MemorySession session) { - return RuntimeHelper.upcallStub(CreateInterfaceAsyncEventSource.class, fi, IOUSBInterfaceStruct942.CreateInterfaceAsyncEventSource$FUNC, session); + return RuntimeHelper.upcallStub(CreateInterfaceAsyncEventSource.class, fi, IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$FUNC, session); } static CreateInterfaceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { try { - return (int)IOUSBInterfaceStruct942.CreateInterfaceAsyncEventSource$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -280,19 +252,19 @@ static CreateInterfaceAsyncEventSource ofAddress(MemoryAddress addr, MemorySessi static final VarHandle CreateInterfaceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceAsyncEventSource")); public static VarHandle CreateInterfaceAsyncEventSource$VH() { - return IOUSBInterfaceStruct942.CreateInterfaceAsyncEventSource$VH; + return IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$VH; } public static MemoryAddress CreateInterfaceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.CreateInterfaceAsyncEventSource$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$VH.get(seg); } public static void CreateInterfaceAsyncEventSource$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.CreateInterfaceAsyncEventSource$VH.set(seg, x); + IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$VH.set(seg, x); } public static MemoryAddress CreateInterfaceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.CreateInterfaceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); } public static void CreateInterfaceAsyncEventSource$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.CreateInterfaceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); } public static CreateInterfaceAsyncEventSource CreateInterfaceAsyncEventSource (MemorySegment segment, MemorySession session) { return CreateInterfaceAsyncEventSource.ofAddress(CreateInterfaceAsyncEventSource$get(segment), session); @@ -301,19 +273,19 @@ public static CreateInterfaceAsyncEventSource CreateInterfaceAsyncEventSource (M Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetInterfaceAsyncEventSource$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetInterfaceAsyncEventSource$FUNC + IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$FUNC ); public interface GetInterfaceAsyncEventSource { java.lang.foreign.Addressable apply(java.lang.foreign.MemoryAddress _x0); static MemorySegment allocate(GetInterfaceAsyncEventSource fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetInterfaceAsyncEventSource.class, fi, IOUSBInterfaceStruct942.GetInterfaceAsyncEventSource$FUNC, session); + return RuntimeHelper.upcallStub(GetInterfaceAsyncEventSource.class, fi, IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$FUNC, session); } static GetInterfaceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0) -> { try { - return (java.lang.foreign.Addressable)(java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceAsyncEventSource$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (java.lang.foreign.Addressable)(java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -323,19 +295,19 @@ static GetInterfaceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession static final VarHandle GetInterfaceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceAsyncEventSource")); public static VarHandle GetInterfaceAsyncEventSource$VH() { - return IOUSBInterfaceStruct942.GetInterfaceAsyncEventSource$VH; + return IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$VH; } public static MemoryAddress GetInterfaceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceAsyncEventSource$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$VH.get(seg); } public static void GetInterfaceAsyncEventSource$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetInterfaceAsyncEventSource$VH.set(seg, x); + IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$VH.set(seg, x); } public static MemoryAddress GetInterfaceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); } public static void GetInterfaceAsyncEventSource$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetInterfaceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); } public static GetInterfaceAsyncEventSource GetInterfaceAsyncEventSource (MemorySegment segment, MemorySession session) { return GetInterfaceAsyncEventSource.ofAddress(GetInterfaceAsyncEventSource$get(segment), session); @@ -345,19 +317,19 @@ public static GetInterfaceAsyncEventSource GetInterfaceAsyncEventSource (MemoryS Constants$root.C_POINTER$LAYOUT ); static final MethodHandle CreateInterfaceAsyncPort$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.CreateInterfaceAsyncPort$FUNC + IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$FUNC ); public interface CreateInterfaceAsyncPort { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); static MemorySegment allocate(CreateInterfaceAsyncPort fi, MemorySession session) { - return RuntimeHelper.upcallStub(CreateInterfaceAsyncPort.class, fi, IOUSBInterfaceStruct942.CreateInterfaceAsyncPort$FUNC, session); + return RuntimeHelper.upcallStub(CreateInterfaceAsyncPort.class, fi, IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$FUNC, session); } static CreateInterfaceAsyncPort ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { try { - return (int)IOUSBInterfaceStruct942.CreateInterfaceAsyncPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -367,19 +339,19 @@ static CreateInterfaceAsyncPort ofAddress(MemoryAddress addr, MemorySession sess static final VarHandle CreateInterfaceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceAsyncPort")); public static VarHandle CreateInterfaceAsyncPort$VH() { - return IOUSBInterfaceStruct942.CreateInterfaceAsyncPort$VH; + return IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$VH; } public static MemoryAddress CreateInterfaceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.CreateInterfaceAsyncPort$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$VH.get(seg); } public static void CreateInterfaceAsyncPort$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.CreateInterfaceAsyncPort$VH.set(seg, x); + IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$VH.set(seg, x); } public static MemoryAddress CreateInterfaceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.CreateInterfaceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$VH.get(seg.asSlice(index*sizeof())); } public static void CreateInterfaceAsyncPort$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.CreateInterfaceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); } public static CreateInterfaceAsyncPort CreateInterfaceAsyncPort (MemorySegment segment, MemorySession session) { return CreateInterfaceAsyncPort.ofAddress(CreateInterfaceAsyncPort$get(segment), session); @@ -388,19 +360,19 @@ public static CreateInterfaceAsyncPort CreateInterfaceAsyncPort (MemorySegment s Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetInterfaceAsyncPort$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetInterfaceAsyncPort$FUNC + IOUSBInterfaceStruct190.GetInterfaceAsyncPort$FUNC ); public interface GetInterfaceAsyncPort { int apply(java.lang.foreign.MemoryAddress _x0); static MemorySegment allocate(GetInterfaceAsyncPort fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetInterfaceAsyncPort.class, fi, IOUSBInterfaceStruct942.GetInterfaceAsyncPort$FUNC, session); + return RuntimeHelper.upcallStub(GetInterfaceAsyncPort.class, fi, IOUSBInterfaceStruct190.GetInterfaceAsyncPort$FUNC, session); } static GetInterfaceAsyncPort ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0) -> { try { - return (int)IOUSBInterfaceStruct942.GetInterfaceAsyncPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBInterfaceStruct190.GetInterfaceAsyncPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -410,19 +382,19 @@ static GetInterfaceAsyncPort ofAddress(MemoryAddress addr, MemorySession session static final VarHandle GetInterfaceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceAsyncPort")); public static VarHandle GetInterfaceAsyncPort$VH() { - return IOUSBInterfaceStruct942.GetInterfaceAsyncPort$VH; + return IOUSBInterfaceStruct190.GetInterfaceAsyncPort$VH; } public static MemoryAddress GetInterfaceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceAsyncPort$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceAsyncPort$VH.get(seg); } public static void GetInterfaceAsyncPort$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetInterfaceAsyncPort$VH.set(seg, x); + IOUSBInterfaceStruct190.GetInterfaceAsyncPort$VH.set(seg, x); } public static MemoryAddress GetInterfaceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceAsyncPort$VH.get(seg.asSlice(index*sizeof())); } public static void GetInterfaceAsyncPort$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetInterfaceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetInterfaceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); } public static GetInterfaceAsyncPort GetInterfaceAsyncPort (MemorySegment segment, MemorySession session) { return GetInterfaceAsyncPort.ofAddress(GetInterfaceAsyncPort$get(segment), session); @@ -431,19 +403,19 @@ public static GetInterfaceAsyncPort GetInterfaceAsyncPort (MemorySegment segment Constants$root.C_POINTER$LAYOUT ); static final MethodHandle USBInterfaceOpen$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.USBInterfaceOpen$FUNC + IOUSBInterfaceStruct190.USBInterfaceOpen$FUNC ); public interface USBInterfaceOpen { int apply(java.lang.foreign.MemoryAddress _x0); static MemorySegment allocate(USBInterfaceOpen fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBInterfaceOpen.class, fi, IOUSBInterfaceStruct942.USBInterfaceOpen$FUNC, session); + return RuntimeHelper.upcallStub(USBInterfaceOpen.class, fi, IOUSBInterfaceStruct190.USBInterfaceOpen$FUNC, session); } static USBInterfaceOpen ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0) -> { try { - return (int)IOUSBInterfaceStruct942.USBInterfaceOpen$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBInterfaceStruct190.USBInterfaceOpen$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -453,19 +425,19 @@ static USBInterfaceOpen ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle USBInterfaceOpen$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceOpen")); public static VarHandle USBInterfaceOpen$VH() { - return IOUSBInterfaceStruct942.USBInterfaceOpen$VH; + return IOUSBInterfaceStruct190.USBInterfaceOpen$VH; } public static MemoryAddress USBInterfaceOpen$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.USBInterfaceOpen$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.USBInterfaceOpen$VH.get(seg); } public static void USBInterfaceOpen$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.USBInterfaceOpen$VH.set(seg, x); + IOUSBInterfaceStruct190.USBInterfaceOpen$VH.set(seg, x); } public static MemoryAddress USBInterfaceOpen$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.USBInterfaceOpen$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.USBInterfaceOpen$VH.get(seg.asSlice(index*sizeof())); } public static void USBInterfaceOpen$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.USBInterfaceOpen$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.USBInterfaceOpen$VH.set(seg.asSlice(index*sizeof()), x); } public static USBInterfaceOpen USBInterfaceOpen (MemorySegment segment, MemorySession session) { return USBInterfaceOpen.ofAddress(USBInterfaceOpen$get(segment), session); @@ -474,19 +446,19 @@ public static USBInterfaceOpen USBInterfaceOpen (MemorySegment segment, MemorySe Constants$root.C_POINTER$LAYOUT ); static final MethodHandle USBInterfaceClose$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.USBInterfaceClose$FUNC + IOUSBInterfaceStruct190.USBInterfaceClose$FUNC ); public interface USBInterfaceClose { int apply(java.lang.foreign.MemoryAddress _x0); static MemorySegment allocate(USBInterfaceClose fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBInterfaceClose.class, fi, IOUSBInterfaceStruct942.USBInterfaceClose$FUNC, session); + return RuntimeHelper.upcallStub(USBInterfaceClose.class, fi, IOUSBInterfaceStruct190.USBInterfaceClose$FUNC, session); } static USBInterfaceClose ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0) -> { try { - return (int)IOUSBInterfaceStruct942.USBInterfaceClose$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBInterfaceStruct190.USBInterfaceClose$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -496,19 +468,19 @@ static USBInterfaceClose ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle USBInterfaceClose$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceClose")); public static VarHandle USBInterfaceClose$VH() { - return IOUSBInterfaceStruct942.USBInterfaceClose$VH; + return IOUSBInterfaceStruct190.USBInterfaceClose$VH; } public static MemoryAddress USBInterfaceClose$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.USBInterfaceClose$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.USBInterfaceClose$VH.get(seg); } public static void USBInterfaceClose$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.USBInterfaceClose$VH.set(seg, x); + IOUSBInterfaceStruct190.USBInterfaceClose$VH.set(seg, x); } public static MemoryAddress USBInterfaceClose$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.USBInterfaceClose$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.USBInterfaceClose$VH.get(seg.asSlice(index*sizeof())); } public static void USBInterfaceClose$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.USBInterfaceClose$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.USBInterfaceClose$VH.set(seg.asSlice(index*sizeof()), x); } public static USBInterfaceClose USBInterfaceClose (MemorySegment segment, MemorySession session) { return USBInterfaceClose.ofAddress(USBInterfaceClose$get(segment), session); @@ -518,19 +490,19 @@ public static USBInterfaceClose USBInterfaceClose (MemorySegment segment, Memory Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetInterfaceClass$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetInterfaceClass$FUNC + IOUSBInterfaceStruct190.GetInterfaceClass$FUNC ); public interface GetInterfaceClass { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); static MemorySegment allocate(GetInterfaceClass fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetInterfaceClass.class, fi, IOUSBInterfaceStruct942.GetInterfaceClass$FUNC, session); + return RuntimeHelper.upcallStub(GetInterfaceClass.class, fi, IOUSBInterfaceStruct190.GetInterfaceClass$FUNC, session); } static GetInterfaceClass ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { try { - return (int)IOUSBInterfaceStruct942.GetInterfaceClass$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetInterfaceClass$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -540,19 +512,19 @@ static GetInterfaceClass ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle GetInterfaceClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceClass")); public static VarHandle GetInterfaceClass$VH() { - return IOUSBInterfaceStruct942.GetInterfaceClass$VH; + return IOUSBInterfaceStruct190.GetInterfaceClass$VH; } public static MemoryAddress GetInterfaceClass$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceClass$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceClass$VH.get(seg); } public static void GetInterfaceClass$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetInterfaceClass$VH.set(seg, x); + IOUSBInterfaceStruct190.GetInterfaceClass$VH.set(seg, x); } public static MemoryAddress GetInterfaceClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceClass$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceClass$VH.get(seg.asSlice(index*sizeof())); } public static void GetInterfaceClass$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetInterfaceClass$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetInterfaceClass$VH.set(seg.asSlice(index*sizeof()), x); } public static GetInterfaceClass GetInterfaceClass (MemorySegment segment, MemorySession session) { return GetInterfaceClass.ofAddress(GetInterfaceClass$get(segment), session); @@ -562,19 +534,19 @@ public static GetInterfaceClass GetInterfaceClass (MemorySegment segment, Memory Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetInterfaceSubClass$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetInterfaceSubClass$FUNC + IOUSBInterfaceStruct190.GetInterfaceSubClass$FUNC ); public interface GetInterfaceSubClass { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); static MemorySegment allocate(GetInterfaceSubClass fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetInterfaceSubClass.class, fi, IOUSBInterfaceStruct942.GetInterfaceSubClass$FUNC, session); + return RuntimeHelper.upcallStub(GetInterfaceSubClass.class, fi, IOUSBInterfaceStruct190.GetInterfaceSubClass$FUNC, session); } static GetInterfaceSubClass ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { try { - return (int)IOUSBInterfaceStruct942.GetInterfaceSubClass$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetInterfaceSubClass$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -584,19 +556,19 @@ static GetInterfaceSubClass ofAddress(MemoryAddress addr, MemorySession session) static final VarHandle GetInterfaceSubClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceSubClass")); public static VarHandle GetInterfaceSubClass$VH() { - return IOUSBInterfaceStruct942.GetInterfaceSubClass$VH; + return IOUSBInterfaceStruct190.GetInterfaceSubClass$VH; } public static MemoryAddress GetInterfaceSubClass$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceSubClass$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceSubClass$VH.get(seg); } public static void GetInterfaceSubClass$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetInterfaceSubClass$VH.set(seg, x); + IOUSBInterfaceStruct190.GetInterfaceSubClass$VH.set(seg, x); } public static MemoryAddress GetInterfaceSubClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceSubClass$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceSubClass$VH.get(seg.asSlice(index*sizeof())); } public static void GetInterfaceSubClass$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetInterfaceSubClass$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetInterfaceSubClass$VH.set(seg.asSlice(index*sizeof()), x); } public static GetInterfaceSubClass GetInterfaceSubClass (MemorySegment segment, MemorySession session) { return GetInterfaceSubClass.ofAddress(GetInterfaceSubClass$get(segment), session); @@ -606,19 +578,19 @@ public static GetInterfaceSubClass GetInterfaceSubClass (MemorySegment segment, Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetInterfaceProtocol$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetInterfaceProtocol$FUNC + IOUSBInterfaceStruct190.GetInterfaceProtocol$FUNC ); public interface GetInterfaceProtocol { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); static MemorySegment allocate(GetInterfaceProtocol fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetInterfaceProtocol.class, fi, IOUSBInterfaceStruct942.GetInterfaceProtocol$FUNC, session); + return RuntimeHelper.upcallStub(GetInterfaceProtocol.class, fi, IOUSBInterfaceStruct190.GetInterfaceProtocol$FUNC, session); } static GetInterfaceProtocol ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { try { - return (int)IOUSBInterfaceStruct942.GetInterfaceProtocol$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetInterfaceProtocol$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -628,19 +600,19 @@ static GetInterfaceProtocol ofAddress(MemoryAddress addr, MemorySession session) static final VarHandle GetInterfaceProtocol$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceProtocol")); public static VarHandle GetInterfaceProtocol$VH() { - return IOUSBInterfaceStruct942.GetInterfaceProtocol$VH; + return IOUSBInterfaceStruct190.GetInterfaceProtocol$VH; } public static MemoryAddress GetInterfaceProtocol$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceProtocol$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceProtocol$VH.get(seg); } public static void GetInterfaceProtocol$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetInterfaceProtocol$VH.set(seg, x); + IOUSBInterfaceStruct190.GetInterfaceProtocol$VH.set(seg, x); } public static MemoryAddress GetInterfaceProtocol$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceProtocol$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceProtocol$VH.get(seg.asSlice(index*sizeof())); } public static void GetInterfaceProtocol$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetInterfaceProtocol$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetInterfaceProtocol$VH.set(seg.asSlice(index*sizeof()), x); } public static GetInterfaceProtocol GetInterfaceProtocol (MemorySegment segment, MemorySession session) { return GetInterfaceProtocol.ofAddress(GetInterfaceProtocol$get(segment), session); @@ -650,19 +622,19 @@ public static GetInterfaceProtocol GetInterfaceProtocol (MemorySegment segment, Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceVendor$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetDeviceVendor$FUNC + IOUSBInterfaceStruct190.GetDeviceVendor$FUNC ); public interface GetDeviceVendor { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); static MemorySegment allocate(GetDeviceVendor fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceVendor.class, fi, IOUSBInterfaceStruct942.GetDeviceVendor$FUNC, session); + return RuntimeHelper.upcallStub(GetDeviceVendor.class, fi, IOUSBInterfaceStruct190.GetDeviceVendor$FUNC, session); } static GetDeviceVendor ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { try { - return (int)IOUSBInterfaceStruct942.GetDeviceVendor$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetDeviceVendor$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -672,19 +644,19 @@ static GetDeviceVendor ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle GetDeviceVendor$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceVendor")); public static VarHandle GetDeviceVendor$VH() { - return IOUSBInterfaceStruct942.GetDeviceVendor$VH; + return IOUSBInterfaceStruct190.GetDeviceVendor$VH; } public static MemoryAddress GetDeviceVendor$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetDeviceVendor$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetDeviceVendor$VH.get(seg); } public static void GetDeviceVendor$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetDeviceVendor$VH.set(seg, x); + IOUSBInterfaceStruct190.GetDeviceVendor$VH.set(seg, x); } public static MemoryAddress GetDeviceVendor$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetDeviceVendor$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetDeviceVendor$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceVendor$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetDeviceVendor$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetDeviceVendor$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceVendor GetDeviceVendor (MemorySegment segment, MemorySession session) { return GetDeviceVendor.ofAddress(GetDeviceVendor$get(segment), session); @@ -694,19 +666,19 @@ public static GetDeviceVendor GetDeviceVendor (MemorySegment segment, MemorySess Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceProduct$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetDeviceProduct$FUNC + IOUSBInterfaceStruct190.GetDeviceProduct$FUNC ); public interface GetDeviceProduct { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); static MemorySegment allocate(GetDeviceProduct fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceProduct.class, fi, IOUSBInterfaceStruct942.GetDeviceProduct$FUNC, session); + return RuntimeHelper.upcallStub(GetDeviceProduct.class, fi, IOUSBInterfaceStruct190.GetDeviceProduct$FUNC, session); } static GetDeviceProduct ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { try { - return (int)IOUSBInterfaceStruct942.GetDeviceProduct$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetDeviceProduct$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -716,19 +688,19 @@ static GetDeviceProduct ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle GetDeviceProduct$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProduct")); public static VarHandle GetDeviceProduct$VH() { - return IOUSBInterfaceStruct942.GetDeviceProduct$VH; + return IOUSBInterfaceStruct190.GetDeviceProduct$VH; } public static MemoryAddress GetDeviceProduct$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetDeviceProduct$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetDeviceProduct$VH.get(seg); } public static void GetDeviceProduct$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetDeviceProduct$VH.set(seg, x); + IOUSBInterfaceStruct190.GetDeviceProduct$VH.set(seg, x); } public static MemoryAddress GetDeviceProduct$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetDeviceProduct$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetDeviceProduct$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceProduct$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetDeviceProduct$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetDeviceProduct$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceProduct GetDeviceProduct (MemorySegment segment, MemorySession session) { return GetDeviceProduct.ofAddress(GetDeviceProduct$get(segment), session); @@ -738,19 +710,19 @@ public static GetDeviceProduct GetDeviceProduct (MemorySegment segment, MemorySe Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceReleaseNumber$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetDeviceReleaseNumber$FUNC + IOUSBInterfaceStruct190.GetDeviceReleaseNumber$FUNC ); public interface GetDeviceReleaseNumber { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); static MemorySegment allocate(GetDeviceReleaseNumber fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceReleaseNumber.class, fi, IOUSBInterfaceStruct942.GetDeviceReleaseNumber$FUNC, session); + return RuntimeHelper.upcallStub(GetDeviceReleaseNumber.class, fi, IOUSBInterfaceStruct190.GetDeviceReleaseNumber$FUNC, session); } static GetDeviceReleaseNumber ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { try { - return (int)IOUSBInterfaceStruct942.GetDeviceReleaseNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetDeviceReleaseNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -760,19 +732,19 @@ static GetDeviceReleaseNumber ofAddress(MemoryAddress addr, MemorySession sessio static final VarHandle GetDeviceReleaseNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceReleaseNumber")); public static VarHandle GetDeviceReleaseNumber$VH() { - return IOUSBInterfaceStruct942.GetDeviceReleaseNumber$VH; + return IOUSBInterfaceStruct190.GetDeviceReleaseNumber$VH; } public static MemoryAddress GetDeviceReleaseNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetDeviceReleaseNumber$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetDeviceReleaseNumber$VH.get(seg); } public static void GetDeviceReleaseNumber$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetDeviceReleaseNumber$VH.set(seg, x); + IOUSBInterfaceStruct190.GetDeviceReleaseNumber$VH.set(seg, x); } public static MemoryAddress GetDeviceReleaseNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetDeviceReleaseNumber$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetDeviceReleaseNumber$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceReleaseNumber$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetDeviceReleaseNumber$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetDeviceReleaseNumber$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceReleaseNumber GetDeviceReleaseNumber (MemorySegment segment, MemorySession session) { return GetDeviceReleaseNumber.ofAddress(GetDeviceReleaseNumber$get(segment), session); @@ -782,19 +754,19 @@ public static GetDeviceReleaseNumber GetDeviceReleaseNumber (MemorySegment segme Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetConfigurationValue$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetConfigurationValue$FUNC + IOUSBInterfaceStruct190.GetConfigurationValue$FUNC ); public interface GetConfigurationValue { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); static MemorySegment allocate(GetConfigurationValue fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetConfigurationValue.class, fi, IOUSBInterfaceStruct942.GetConfigurationValue$FUNC, session); + return RuntimeHelper.upcallStub(GetConfigurationValue.class, fi, IOUSBInterfaceStruct190.GetConfigurationValue$FUNC, session); } static GetConfigurationValue ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { try { - return (int)IOUSBInterfaceStruct942.GetConfigurationValue$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetConfigurationValue$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -804,19 +776,19 @@ static GetConfigurationValue ofAddress(MemoryAddress addr, MemorySession session static final VarHandle GetConfigurationValue$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetConfigurationValue")); public static VarHandle GetConfigurationValue$VH() { - return IOUSBInterfaceStruct942.GetConfigurationValue$VH; + return IOUSBInterfaceStruct190.GetConfigurationValue$VH; } public static MemoryAddress GetConfigurationValue$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetConfigurationValue$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetConfigurationValue$VH.get(seg); } public static void GetConfigurationValue$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetConfigurationValue$VH.set(seg, x); + IOUSBInterfaceStruct190.GetConfigurationValue$VH.set(seg, x); } public static MemoryAddress GetConfigurationValue$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetConfigurationValue$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetConfigurationValue$VH.get(seg.asSlice(index*sizeof())); } public static void GetConfigurationValue$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetConfigurationValue$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetConfigurationValue$VH.set(seg.asSlice(index*sizeof()), x); } public static GetConfigurationValue GetConfigurationValue (MemorySegment segment, MemorySession session) { return GetConfigurationValue.ofAddress(GetConfigurationValue$get(segment), session); @@ -826,19 +798,19 @@ public static GetConfigurationValue GetConfigurationValue (MemorySegment segment Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetInterfaceNumber$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetInterfaceNumber$FUNC + IOUSBInterfaceStruct190.GetInterfaceNumber$FUNC ); public interface GetInterfaceNumber { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); static MemorySegment allocate(GetInterfaceNumber fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetInterfaceNumber.class, fi, IOUSBInterfaceStruct942.GetInterfaceNumber$FUNC, session); + return RuntimeHelper.upcallStub(GetInterfaceNumber.class, fi, IOUSBInterfaceStruct190.GetInterfaceNumber$FUNC, session); } static GetInterfaceNumber ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { try { - return (int)IOUSBInterfaceStruct942.GetInterfaceNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetInterfaceNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -848,19 +820,19 @@ static GetInterfaceNumber ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle GetInterfaceNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceNumber")); public static VarHandle GetInterfaceNumber$VH() { - return IOUSBInterfaceStruct942.GetInterfaceNumber$VH; + return IOUSBInterfaceStruct190.GetInterfaceNumber$VH; } public static MemoryAddress GetInterfaceNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceNumber$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceNumber$VH.get(seg); } public static void GetInterfaceNumber$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetInterfaceNumber$VH.set(seg, x); + IOUSBInterfaceStruct190.GetInterfaceNumber$VH.set(seg, x); } public static MemoryAddress GetInterfaceNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceNumber$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceNumber$VH.get(seg.asSlice(index*sizeof())); } public static void GetInterfaceNumber$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetInterfaceNumber$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetInterfaceNumber$VH.set(seg.asSlice(index*sizeof()), x); } public static GetInterfaceNumber GetInterfaceNumber (MemorySegment segment, MemorySession session) { return GetInterfaceNumber.ofAddress(GetInterfaceNumber$get(segment), session); @@ -870,19 +842,19 @@ public static GetInterfaceNumber GetInterfaceNumber (MemorySegment segment, Memo Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetAlternateSetting$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetAlternateSetting$FUNC + IOUSBInterfaceStruct190.GetAlternateSetting$FUNC ); public interface GetAlternateSetting { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); static MemorySegment allocate(GetAlternateSetting fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetAlternateSetting.class, fi, IOUSBInterfaceStruct942.GetAlternateSetting$FUNC, session); + return RuntimeHelper.upcallStub(GetAlternateSetting.class, fi, IOUSBInterfaceStruct190.GetAlternateSetting$FUNC, session); } static GetAlternateSetting ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { try { - return (int)IOUSBInterfaceStruct942.GetAlternateSetting$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetAlternateSetting$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -892,19 +864,19 @@ static GetAlternateSetting ofAddress(MemoryAddress addr, MemorySession session) static final VarHandle GetAlternateSetting$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetAlternateSetting")); public static VarHandle GetAlternateSetting$VH() { - return IOUSBInterfaceStruct942.GetAlternateSetting$VH; + return IOUSBInterfaceStruct190.GetAlternateSetting$VH; } public static MemoryAddress GetAlternateSetting$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetAlternateSetting$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetAlternateSetting$VH.get(seg); } public static void GetAlternateSetting$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetAlternateSetting$VH.set(seg, x); + IOUSBInterfaceStruct190.GetAlternateSetting$VH.set(seg, x); } public static MemoryAddress GetAlternateSetting$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetAlternateSetting$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetAlternateSetting$VH.get(seg.asSlice(index*sizeof())); } public static void GetAlternateSetting$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetAlternateSetting$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetAlternateSetting$VH.set(seg.asSlice(index*sizeof()), x); } public static GetAlternateSetting GetAlternateSetting (MemorySegment segment, MemorySession session) { return GetAlternateSetting.ofAddress(GetAlternateSetting$get(segment), session); @@ -914,19 +886,19 @@ public static GetAlternateSetting GetAlternateSetting (MemorySegment segment, Me Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetNumEndpoints$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetNumEndpoints$FUNC + IOUSBInterfaceStruct190.GetNumEndpoints$FUNC ); public interface GetNumEndpoints { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); static MemorySegment allocate(GetNumEndpoints fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetNumEndpoints.class, fi, IOUSBInterfaceStruct942.GetNumEndpoints$FUNC, session); + return RuntimeHelper.upcallStub(GetNumEndpoints.class, fi, IOUSBInterfaceStruct190.GetNumEndpoints$FUNC, session); } static GetNumEndpoints ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { try { - return (int)IOUSBInterfaceStruct942.GetNumEndpoints$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetNumEndpoints$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -936,19 +908,19 @@ static GetNumEndpoints ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle GetNumEndpoints$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetNumEndpoints")); public static VarHandle GetNumEndpoints$VH() { - return IOUSBInterfaceStruct942.GetNumEndpoints$VH; + return IOUSBInterfaceStruct190.GetNumEndpoints$VH; } public static MemoryAddress GetNumEndpoints$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetNumEndpoints$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetNumEndpoints$VH.get(seg); } public static void GetNumEndpoints$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetNumEndpoints$VH.set(seg, x); + IOUSBInterfaceStruct190.GetNumEndpoints$VH.set(seg, x); } public static MemoryAddress GetNumEndpoints$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetNumEndpoints$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetNumEndpoints$VH.get(seg.asSlice(index*sizeof())); } public static void GetNumEndpoints$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetNumEndpoints$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetNumEndpoints$VH.set(seg.asSlice(index*sizeof()), x); } public static GetNumEndpoints GetNumEndpoints (MemorySegment segment, MemorySession session) { return GetNumEndpoints.ofAddress(GetNumEndpoints$get(segment), session); @@ -958,19 +930,19 @@ public static GetNumEndpoints GetNumEndpoints (MemorySegment segment, MemorySess Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetLocationID$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetLocationID$FUNC + IOUSBInterfaceStruct190.GetLocationID$FUNC ); public interface GetLocationID { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); static MemorySegment allocate(GetLocationID fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetLocationID.class, fi, IOUSBInterfaceStruct942.GetLocationID$FUNC, session); + return RuntimeHelper.upcallStub(GetLocationID.class, fi, IOUSBInterfaceStruct190.GetLocationID$FUNC, session); } static GetLocationID ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { try { - return (int)IOUSBInterfaceStruct942.GetLocationID$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetLocationID$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -980,19 +952,19 @@ static GetLocationID ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle GetLocationID$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetLocationID")); public static VarHandle GetLocationID$VH() { - return IOUSBInterfaceStruct942.GetLocationID$VH; + return IOUSBInterfaceStruct190.GetLocationID$VH; } public static MemoryAddress GetLocationID$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetLocationID$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetLocationID$VH.get(seg); } public static void GetLocationID$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetLocationID$VH.set(seg, x); + IOUSBInterfaceStruct190.GetLocationID$VH.set(seg, x); } public static MemoryAddress GetLocationID$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetLocationID$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetLocationID$VH.get(seg.asSlice(index*sizeof())); } public static void GetLocationID$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetLocationID$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetLocationID$VH.set(seg.asSlice(index*sizeof()), x); } public static GetLocationID GetLocationID (MemorySegment segment, MemorySession session) { return GetLocationID.ofAddress(GetLocationID$get(segment), session); @@ -1002,19 +974,19 @@ public static GetLocationID GetLocationID (MemorySegment segment, MemorySession Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDevice$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetDevice$FUNC + IOUSBInterfaceStruct190.GetDevice$FUNC ); public interface GetDevice { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); static MemorySegment allocate(GetDevice fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDevice.class, fi, IOUSBInterfaceStruct942.GetDevice$FUNC, session); + return RuntimeHelper.upcallStub(GetDevice.class, fi, IOUSBInterfaceStruct190.GetDevice$FUNC, session); } static GetDevice ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { try { - return (int)IOUSBInterfaceStruct942.GetDevice$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetDevice$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1024,19 +996,19 @@ static GetDevice ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle GetDevice$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDevice")); public static VarHandle GetDevice$VH() { - return IOUSBInterfaceStruct942.GetDevice$VH; + return IOUSBInterfaceStruct190.GetDevice$VH; } public static MemoryAddress GetDevice$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetDevice$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetDevice$VH.get(seg); } public static void GetDevice$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetDevice$VH.set(seg, x); + IOUSBInterfaceStruct190.GetDevice$VH.set(seg, x); } public static MemoryAddress GetDevice$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetDevice$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetDevice$VH.get(seg.asSlice(index*sizeof())); } public static void GetDevice$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetDevice$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetDevice$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDevice GetDevice (MemorySegment segment, MemorySession session) { return GetDevice.ofAddress(GetDevice$get(segment), session); @@ -1046,19 +1018,19 @@ public static GetDevice GetDevice (MemorySegment segment, MemorySession session) Constants$root.C_CHAR$LAYOUT ); static final MethodHandle SetAlternateInterface$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.SetAlternateInterface$FUNC + IOUSBInterfaceStruct190.SetAlternateInterface$FUNC ); public interface SetAlternateInterface { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); static MemorySegment allocate(SetAlternateInterface fi, MemorySession session) { - return RuntimeHelper.upcallStub(SetAlternateInterface.class, fi, IOUSBInterfaceStruct942.SetAlternateInterface$FUNC, session); + return RuntimeHelper.upcallStub(SetAlternateInterface.class, fi, IOUSBInterfaceStruct190.SetAlternateInterface$FUNC, session); } static SetAlternateInterface ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct942.SetAlternateInterface$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + return (int)IOUSBInterfaceStruct190.SetAlternateInterface$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1068,19 +1040,19 @@ static SetAlternateInterface ofAddress(MemoryAddress addr, MemorySession session static final VarHandle SetAlternateInterface$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetAlternateInterface")); public static VarHandle SetAlternateInterface$VH() { - return IOUSBInterfaceStruct942.SetAlternateInterface$VH; + return IOUSBInterfaceStruct190.SetAlternateInterface$VH; } public static MemoryAddress SetAlternateInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SetAlternateInterface$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.SetAlternateInterface$VH.get(seg); } public static void SetAlternateInterface$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.SetAlternateInterface$VH.set(seg, x); + IOUSBInterfaceStruct190.SetAlternateInterface$VH.set(seg, x); } public static MemoryAddress SetAlternateInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SetAlternateInterface$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.SetAlternateInterface$VH.get(seg.asSlice(index*sizeof())); } public static void SetAlternateInterface$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.SetAlternateInterface$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.SetAlternateInterface$VH.set(seg.asSlice(index*sizeof()), x); } public static SetAlternateInterface SetAlternateInterface (MemorySegment segment, MemorySession session) { return SetAlternateInterface.ofAddress(SetAlternateInterface$get(segment), session); @@ -1091,19 +1063,19 @@ public static SetAlternateInterface SetAlternateInterface (MemorySegment segment Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetBusFrameNumber$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetBusFrameNumber$FUNC + IOUSBInterfaceStruct190.GetBusFrameNumber$FUNC ); public interface GetBusFrameNumber { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); static MemorySegment allocate(GetBusFrameNumber fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetBusFrameNumber.class, fi, IOUSBInterfaceStruct942.GetBusFrameNumber$FUNC, session); + return RuntimeHelper.upcallStub(GetBusFrameNumber.class, fi, IOUSBInterfaceStruct190.GetBusFrameNumber$FUNC, session); } static GetBusFrameNumber ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { try { - return (int)IOUSBInterfaceStruct942.GetBusFrameNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); + return (int)IOUSBInterfaceStruct190.GetBusFrameNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1113,19 +1085,19 @@ static GetBusFrameNumber ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle GetBusFrameNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBusFrameNumber")); public static VarHandle GetBusFrameNumber$VH() { - return IOUSBInterfaceStruct942.GetBusFrameNumber$VH; + return IOUSBInterfaceStruct190.GetBusFrameNumber$VH; } public static MemoryAddress GetBusFrameNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetBusFrameNumber$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetBusFrameNumber$VH.get(seg); } public static void GetBusFrameNumber$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetBusFrameNumber$VH.set(seg, x); + IOUSBInterfaceStruct190.GetBusFrameNumber$VH.set(seg, x); } public static MemoryAddress GetBusFrameNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetBusFrameNumber$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetBusFrameNumber$VH.get(seg.asSlice(index*sizeof())); } public static void GetBusFrameNumber$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetBusFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetBusFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); } public static GetBusFrameNumber GetBusFrameNumber (MemorySegment segment, MemorySession session) { return GetBusFrameNumber.ofAddress(GetBusFrameNumber$get(segment), session); @@ -1136,19 +1108,19 @@ public static GetBusFrameNumber GetBusFrameNumber (MemorySegment segment, Memory Constants$root.C_POINTER$LAYOUT ); static final MethodHandle ControlRequest$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.ControlRequest$FUNC + IOUSBInterfaceStruct190.ControlRequest$FUNC ); public interface ControlRequest { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2); static MemorySegment allocate(ControlRequest fi, MemorySession session) { - return RuntimeHelper.upcallStub(ControlRequest.class, fi, IOUSBInterfaceStruct942.ControlRequest$FUNC, session); + return RuntimeHelper.upcallStub(ControlRequest.class, fi, IOUSBInterfaceStruct190.ControlRequest$FUNC, session); } static ControlRequest ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2) -> { try { - return (int)IOUSBInterfaceStruct942.ControlRequest$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + return (int)IOUSBInterfaceStruct190.ControlRequest$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1158,19 +1130,19 @@ static ControlRequest ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle ControlRequest$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ControlRequest")); public static VarHandle ControlRequest$VH() { - return IOUSBInterfaceStruct942.ControlRequest$VH; + return IOUSBInterfaceStruct190.ControlRequest$VH; } public static MemoryAddress ControlRequest$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ControlRequest$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ControlRequest$VH.get(seg); } public static void ControlRequest$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.ControlRequest$VH.set(seg, x); + IOUSBInterfaceStruct190.ControlRequest$VH.set(seg, x); } public static MemoryAddress ControlRequest$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ControlRequest$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ControlRequest$VH.get(seg.asSlice(index*sizeof())); } public static void ControlRequest$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.ControlRequest$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.ControlRequest$VH.set(seg.asSlice(index*sizeof()), x); } public static ControlRequest ControlRequest (MemorySegment segment, MemorySession session) { return ControlRequest.ofAddress(ControlRequest$get(segment), session); @@ -1183,19 +1155,19 @@ public static ControlRequest ControlRequest (MemorySegment segment, MemorySessio Constants$root.C_POINTER$LAYOUT ); static final MethodHandle ControlRequestAsync$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.ControlRequestAsync$FUNC + IOUSBInterfaceStruct190.ControlRequestAsync$FUNC ); public interface ControlRequestAsync { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, java.lang.foreign.MemoryAddress _x4); static MemorySegment allocate(ControlRequestAsync fi, MemorySession session) { - return RuntimeHelper.upcallStub(ControlRequestAsync.class, fi, IOUSBInterfaceStruct942.ControlRequestAsync$FUNC, session); + return RuntimeHelper.upcallStub(ControlRequestAsync.class, fi, IOUSBInterfaceStruct190.ControlRequestAsync$FUNC, session); } static ControlRequestAsync ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, java.lang.foreign.MemoryAddress __x4) -> { try { - return (int)IOUSBInterfaceStruct942.ControlRequestAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4); + return (int)IOUSBInterfaceStruct190.ControlRequestAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1205,19 +1177,19 @@ static ControlRequestAsync ofAddress(MemoryAddress addr, MemorySession session) static final VarHandle ControlRequestAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ControlRequestAsync")); public static VarHandle ControlRequestAsync$VH() { - return IOUSBInterfaceStruct942.ControlRequestAsync$VH; + return IOUSBInterfaceStruct190.ControlRequestAsync$VH; } public static MemoryAddress ControlRequestAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ControlRequestAsync$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ControlRequestAsync$VH.get(seg); } public static void ControlRequestAsync$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.ControlRequestAsync$VH.set(seg, x); + IOUSBInterfaceStruct190.ControlRequestAsync$VH.set(seg, x); } public static MemoryAddress ControlRequestAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ControlRequestAsync$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ControlRequestAsync$VH.get(seg.asSlice(index*sizeof())); } public static void ControlRequestAsync$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.ControlRequestAsync$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.ControlRequestAsync$VH.set(seg.asSlice(index*sizeof()), x); } public static ControlRequestAsync ControlRequestAsync (MemorySegment segment, MemorySession session) { return ControlRequestAsync.ofAddress(ControlRequestAsync$get(segment), session); @@ -1232,19 +1204,19 @@ public static ControlRequestAsync ControlRequestAsync (MemorySegment segment, Me Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetPipeProperties$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetPipeProperties$FUNC + IOUSBInterfaceStruct190.GetPipeProperties$FUNC ); public interface GetPipeProperties { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, java.lang.foreign.MemoryAddress _x4, java.lang.foreign.MemoryAddress _x5, java.lang.foreign.MemoryAddress _x6); static MemorySegment allocate(GetPipeProperties fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetPipeProperties.class, fi, IOUSBInterfaceStruct942.GetPipeProperties$FUNC, session); + return RuntimeHelper.upcallStub(GetPipeProperties.class, fi, IOUSBInterfaceStruct190.GetPipeProperties$FUNC, session); } static GetPipeProperties ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, java.lang.foreign.MemoryAddress __x4, java.lang.foreign.MemoryAddress __x5, java.lang.foreign.MemoryAddress __x6) -> { try { - return (int)IOUSBInterfaceStruct942.GetPipeProperties$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6); + return (int)IOUSBInterfaceStruct190.GetPipeProperties$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1254,19 +1226,19 @@ static GetPipeProperties ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle GetPipeProperties$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetPipeProperties")); public static VarHandle GetPipeProperties$VH() { - return IOUSBInterfaceStruct942.GetPipeProperties$VH; + return IOUSBInterfaceStruct190.GetPipeProperties$VH; } public static MemoryAddress GetPipeProperties$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetPipeProperties$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetPipeProperties$VH.get(seg); } public static void GetPipeProperties$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetPipeProperties$VH.set(seg, x); + IOUSBInterfaceStruct190.GetPipeProperties$VH.set(seg, x); } public static MemoryAddress GetPipeProperties$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetPipeProperties$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetPipeProperties$VH.get(seg.asSlice(index*sizeof())); } public static void GetPipeProperties$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetPipeProperties$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetPipeProperties$VH.set(seg.asSlice(index*sizeof()), x); } public static GetPipeProperties GetPipeProperties (MemorySegment segment, MemorySession session) { return GetPipeProperties.ofAddress(GetPipeProperties$get(segment), session); @@ -1276,19 +1248,19 @@ public static GetPipeProperties GetPipeProperties (MemorySegment segment, Memory Constants$root.C_CHAR$LAYOUT ); static final MethodHandle GetPipeStatus$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetPipeStatus$FUNC + IOUSBInterfaceStruct190.GetPipeStatus$FUNC ); public interface GetPipeStatus { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); static MemorySegment allocate(GetPipeStatus fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetPipeStatus.class, fi, IOUSBInterfaceStruct942.GetPipeStatus$FUNC, session); + return RuntimeHelper.upcallStub(GetPipeStatus.class, fi, IOUSBInterfaceStruct190.GetPipeStatus$FUNC, session); } static GetPipeStatus ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct942.GetPipeStatus$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + return (int)IOUSBInterfaceStruct190.GetPipeStatus$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1298,19 +1270,19 @@ static GetPipeStatus ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle GetPipeStatus$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetPipeStatus")); public static VarHandle GetPipeStatus$VH() { - return IOUSBInterfaceStruct942.GetPipeStatus$VH; + return IOUSBInterfaceStruct190.GetPipeStatus$VH; } public static MemoryAddress GetPipeStatus$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetPipeStatus$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetPipeStatus$VH.get(seg); } public static void GetPipeStatus$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetPipeStatus$VH.set(seg, x); + IOUSBInterfaceStruct190.GetPipeStatus$VH.set(seg, x); } public static MemoryAddress GetPipeStatus$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetPipeStatus$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetPipeStatus$VH.get(seg.asSlice(index*sizeof())); } public static void GetPipeStatus$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetPipeStatus$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetPipeStatus$VH.set(seg.asSlice(index*sizeof()), x); } public static GetPipeStatus GetPipeStatus (MemorySegment segment, MemorySession session) { return GetPipeStatus.ofAddress(GetPipeStatus$get(segment), session); @@ -1320,19 +1292,19 @@ public static GetPipeStatus GetPipeStatus (MemorySegment segment, MemorySession Constants$root.C_CHAR$LAYOUT ); static final MethodHandle AbortPipe$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.AbortPipe$FUNC + IOUSBInterfaceStruct190.AbortPipe$FUNC ); public interface AbortPipe { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); static MemorySegment allocate(AbortPipe fi, MemorySession session) { - return RuntimeHelper.upcallStub(AbortPipe.class, fi, IOUSBInterfaceStruct942.AbortPipe$FUNC, session); + return RuntimeHelper.upcallStub(AbortPipe.class, fi, IOUSBInterfaceStruct190.AbortPipe$FUNC, session); } static AbortPipe ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct942.AbortPipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + return (int)IOUSBInterfaceStruct190.AbortPipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1342,19 +1314,19 @@ static AbortPipe ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle AbortPipe$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AbortPipe")); public static VarHandle AbortPipe$VH() { - return IOUSBInterfaceStruct942.AbortPipe$VH; + return IOUSBInterfaceStruct190.AbortPipe$VH; } public static MemoryAddress AbortPipe$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.AbortPipe$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.AbortPipe$VH.get(seg); } public static void AbortPipe$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.AbortPipe$VH.set(seg, x); + IOUSBInterfaceStruct190.AbortPipe$VH.set(seg, x); } public static MemoryAddress AbortPipe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.AbortPipe$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.AbortPipe$VH.get(seg.asSlice(index*sizeof())); } public static void AbortPipe$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.AbortPipe$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.AbortPipe$VH.set(seg.asSlice(index*sizeof()), x); } public static AbortPipe AbortPipe (MemorySegment segment, MemorySession session) { return AbortPipe.ofAddress(AbortPipe$get(segment), session); @@ -1364,19 +1336,19 @@ public static AbortPipe AbortPipe (MemorySegment segment, MemorySession session) Constants$root.C_CHAR$LAYOUT ); static final MethodHandle ResetPipe$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.ResetPipe$FUNC + IOUSBInterfaceStruct190.ResetPipe$FUNC ); public interface ResetPipe { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); static MemorySegment allocate(ResetPipe fi, MemorySession session) { - return RuntimeHelper.upcallStub(ResetPipe.class, fi, IOUSBInterfaceStruct942.ResetPipe$FUNC, session); + return RuntimeHelper.upcallStub(ResetPipe.class, fi, IOUSBInterfaceStruct190.ResetPipe$FUNC, session); } static ResetPipe ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct942.ResetPipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + return (int)IOUSBInterfaceStruct190.ResetPipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1386,19 +1358,19 @@ static ResetPipe ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle ResetPipe$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ResetPipe")); public static VarHandle ResetPipe$VH() { - return IOUSBInterfaceStruct942.ResetPipe$VH; + return IOUSBInterfaceStruct190.ResetPipe$VH; } public static MemoryAddress ResetPipe$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ResetPipe$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ResetPipe$VH.get(seg); } public static void ResetPipe$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.ResetPipe$VH.set(seg, x); + IOUSBInterfaceStruct190.ResetPipe$VH.set(seg, x); } public static MemoryAddress ResetPipe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ResetPipe$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ResetPipe$VH.get(seg.asSlice(index*sizeof())); } public static void ResetPipe$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.ResetPipe$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.ResetPipe$VH.set(seg.asSlice(index*sizeof()), x); } public static ResetPipe ResetPipe (MemorySegment segment, MemorySession session) { return ResetPipe.ofAddress(ResetPipe$get(segment), session); @@ -1408,19 +1380,19 @@ public static ResetPipe ResetPipe (MemorySegment segment, MemorySession session) Constants$root.C_CHAR$LAYOUT ); static final MethodHandle ClearPipeStall$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.ClearPipeStall$FUNC + IOUSBInterfaceStruct190.ClearPipeStall$FUNC ); public interface ClearPipeStall { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); static MemorySegment allocate(ClearPipeStall fi, MemorySession session) { - return RuntimeHelper.upcallStub(ClearPipeStall.class, fi, IOUSBInterfaceStruct942.ClearPipeStall$FUNC, session); + return RuntimeHelper.upcallStub(ClearPipeStall.class, fi, IOUSBInterfaceStruct190.ClearPipeStall$FUNC, session); } static ClearPipeStall ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct942.ClearPipeStall$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + return (int)IOUSBInterfaceStruct190.ClearPipeStall$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1430,19 +1402,19 @@ static ClearPipeStall ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle ClearPipeStall$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ClearPipeStall")); public static VarHandle ClearPipeStall$VH() { - return IOUSBInterfaceStruct942.ClearPipeStall$VH; + return IOUSBInterfaceStruct190.ClearPipeStall$VH; } public static MemoryAddress ClearPipeStall$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ClearPipeStall$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ClearPipeStall$VH.get(seg); } public static void ClearPipeStall$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.ClearPipeStall$VH.set(seg, x); + IOUSBInterfaceStruct190.ClearPipeStall$VH.set(seg, x); } public static MemoryAddress ClearPipeStall$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ClearPipeStall$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ClearPipeStall$VH.get(seg.asSlice(index*sizeof())); } public static void ClearPipeStall$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.ClearPipeStall$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.ClearPipeStall$VH.set(seg.asSlice(index*sizeof()), x); } public static ClearPipeStall ClearPipeStall (MemorySegment segment, MemorySession session) { return ClearPipeStall.ofAddress(ClearPipeStall$get(segment), session); @@ -1454,19 +1426,19 @@ public static ClearPipeStall ClearPipeStall (MemorySegment segment, MemorySessio Constants$root.C_POINTER$LAYOUT ); static final MethodHandle ReadPipe$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.ReadPipe$FUNC + IOUSBInterfaceStruct190.ReadPipe$FUNC ); public interface ReadPipe { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3); static MemorySegment allocate(ReadPipe fi, MemorySession session) { - return RuntimeHelper.upcallStub(ReadPipe.class, fi, IOUSBInterfaceStruct942.ReadPipe$FUNC, session); + return RuntimeHelper.upcallStub(ReadPipe.class, fi, IOUSBInterfaceStruct190.ReadPipe$FUNC, session); } static ReadPipe ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3) -> { try { - return (int)IOUSBInterfaceStruct942.ReadPipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3); + return (int)IOUSBInterfaceStruct190.ReadPipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1476,19 +1448,19 @@ static ReadPipe ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle ReadPipe$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadPipe")); public static VarHandle ReadPipe$VH() { - return IOUSBInterfaceStruct942.ReadPipe$VH; + return IOUSBInterfaceStruct190.ReadPipe$VH; } public static MemoryAddress ReadPipe$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadPipe$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadPipe$VH.get(seg); } public static void ReadPipe$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.ReadPipe$VH.set(seg, x); + IOUSBInterfaceStruct190.ReadPipe$VH.set(seg, x); } public static MemoryAddress ReadPipe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadPipe$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadPipe$VH.get(seg.asSlice(index*sizeof())); } public static void ReadPipe$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.ReadPipe$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.ReadPipe$VH.set(seg.asSlice(index*sizeof()), x); } public static ReadPipe ReadPipe (MemorySegment segment, MemorySession session) { return ReadPipe.ofAddress(ReadPipe$get(segment), session); @@ -1500,19 +1472,19 @@ public static ReadPipe ReadPipe (MemorySegment segment, MemorySession session) { Constants$root.C_INT$LAYOUT ); static final MethodHandle WritePipe$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.WritePipe$FUNC + IOUSBInterfaceStruct190.WritePipe$FUNC ); public interface WritePipe { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3); static MemorySegment allocate(WritePipe fi, MemorySession session) { - return RuntimeHelper.upcallStub(WritePipe.class, fi, IOUSBInterfaceStruct942.WritePipe$FUNC, session); + return RuntimeHelper.upcallStub(WritePipe.class, fi, IOUSBInterfaceStruct190.WritePipe$FUNC, session); } static WritePipe ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3) -> { try { - return (int)IOUSBInterfaceStruct942.WritePipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3); + return (int)IOUSBInterfaceStruct190.WritePipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1522,19 +1494,19 @@ static WritePipe ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle WritePipe$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WritePipe")); public static VarHandle WritePipe$VH() { - return IOUSBInterfaceStruct942.WritePipe$VH; + return IOUSBInterfaceStruct190.WritePipe$VH; } public static MemoryAddress WritePipe$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WritePipe$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WritePipe$VH.get(seg); } public static void WritePipe$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.WritePipe$VH.set(seg, x); + IOUSBInterfaceStruct190.WritePipe$VH.set(seg, x); } public static MemoryAddress WritePipe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WritePipe$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WritePipe$VH.get(seg.asSlice(index*sizeof())); } public static void WritePipe$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.WritePipe$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.WritePipe$VH.set(seg.asSlice(index*sizeof()), x); } public static WritePipe WritePipe (MemorySegment segment, MemorySession session) { return WritePipe.ofAddress(WritePipe$get(segment), session); @@ -1548,19 +1520,19 @@ public static WritePipe WritePipe (MemorySegment segment, MemorySession session) Constants$root.C_POINTER$LAYOUT ); static final MethodHandle ReadPipeAsync$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.ReadPipeAsync$FUNC + IOUSBInterfaceStruct190.ReadPipeAsync$FUNC ); public interface ReadPipeAsync { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3, java.lang.foreign.MemoryAddress _x4, java.lang.foreign.MemoryAddress _x5); static MemorySegment allocate(ReadPipeAsync fi, MemorySession session) { - return RuntimeHelper.upcallStub(ReadPipeAsync.class, fi, IOUSBInterfaceStruct942.ReadPipeAsync$FUNC, session); + return RuntimeHelper.upcallStub(ReadPipeAsync.class, fi, IOUSBInterfaceStruct190.ReadPipeAsync$FUNC, session); } static ReadPipeAsync ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3, java.lang.foreign.MemoryAddress __x4, java.lang.foreign.MemoryAddress __x5) -> { try { - return (int)IOUSBInterfaceStruct942.ReadPipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5); + return (int)IOUSBInterfaceStruct190.ReadPipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1570,19 +1542,19 @@ static ReadPipeAsync ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle ReadPipeAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadPipeAsync")); public static VarHandle ReadPipeAsync$VH() { - return IOUSBInterfaceStruct942.ReadPipeAsync$VH; + return IOUSBInterfaceStruct190.ReadPipeAsync$VH; } public static MemoryAddress ReadPipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadPipeAsync$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadPipeAsync$VH.get(seg); } public static void ReadPipeAsync$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.ReadPipeAsync$VH.set(seg, x); + IOUSBInterfaceStruct190.ReadPipeAsync$VH.set(seg, x); } public static MemoryAddress ReadPipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadPipeAsync$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadPipeAsync$VH.get(seg.asSlice(index*sizeof())); } public static void ReadPipeAsync$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.ReadPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.ReadPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); } public static ReadPipeAsync ReadPipeAsync (MemorySegment segment, MemorySession session) { return ReadPipeAsync.ofAddress(ReadPipeAsync$get(segment), session); @@ -1596,19 +1568,19 @@ public static ReadPipeAsync ReadPipeAsync (MemorySegment segment, MemorySession Constants$root.C_POINTER$LAYOUT ); static final MethodHandle WritePipeAsync$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.WritePipeAsync$FUNC + IOUSBInterfaceStruct190.WritePipeAsync$FUNC ); public interface WritePipeAsync { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3, java.lang.foreign.MemoryAddress _x4, java.lang.foreign.MemoryAddress _x5); static MemorySegment allocate(WritePipeAsync fi, MemorySession session) { - return RuntimeHelper.upcallStub(WritePipeAsync.class, fi, IOUSBInterfaceStruct942.WritePipeAsync$FUNC, session); + return RuntimeHelper.upcallStub(WritePipeAsync.class, fi, IOUSBInterfaceStruct190.WritePipeAsync$FUNC, session); } static WritePipeAsync ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3, java.lang.foreign.MemoryAddress __x4, java.lang.foreign.MemoryAddress __x5) -> { try { - return (int)IOUSBInterfaceStruct942.WritePipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5); + return (int)IOUSBInterfaceStruct190.WritePipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1618,19 +1590,19 @@ static WritePipeAsync ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle WritePipeAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WritePipeAsync")); public static VarHandle WritePipeAsync$VH() { - return IOUSBInterfaceStruct942.WritePipeAsync$VH; + return IOUSBInterfaceStruct190.WritePipeAsync$VH; } public static MemoryAddress WritePipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WritePipeAsync$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WritePipeAsync$VH.get(seg); } public static void WritePipeAsync$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.WritePipeAsync$VH.set(seg, x); + IOUSBInterfaceStruct190.WritePipeAsync$VH.set(seg, x); } public static MemoryAddress WritePipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WritePipeAsync$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WritePipeAsync$VH.get(seg.asSlice(index*sizeof())); } public static void WritePipeAsync$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.WritePipeAsync$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.WritePipeAsync$VH.set(seg.asSlice(index*sizeof()), x); } public static WritePipeAsync WritePipeAsync (MemorySegment segment, MemorySession session) { return WritePipeAsync.ofAddress(WritePipeAsync$get(segment), session); @@ -1646,19 +1618,19 @@ public static WritePipeAsync WritePipeAsync (MemorySegment segment, MemorySessio Constants$root.C_POINTER$LAYOUT ); static final MethodHandle ReadIsochPipeAsync$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.ReadIsochPipeAsync$FUNC + IOUSBInterfaceStruct190.ReadIsochPipeAsync$FUNC ); public interface ReadIsochPipeAsync { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, long _x3, int _x4, java.lang.foreign.MemoryAddress _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7); static MemorySegment allocate(ReadIsochPipeAsync fi, MemorySession session) { - return RuntimeHelper.upcallStub(ReadIsochPipeAsync.class, fi, IOUSBInterfaceStruct942.ReadIsochPipeAsync$FUNC, session); + return RuntimeHelper.upcallStub(ReadIsochPipeAsync.class, fi, IOUSBInterfaceStruct190.ReadIsochPipeAsync$FUNC, session); } static ReadIsochPipeAsync ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, long __x3, int __x4, java.lang.foreign.MemoryAddress __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7) -> { try { - return (int)IOUSBInterfaceStruct942.ReadIsochPipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7); + return (int)IOUSBInterfaceStruct190.ReadIsochPipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1668,19 +1640,19 @@ static ReadIsochPipeAsync ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle ReadIsochPipeAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadIsochPipeAsync")); public static VarHandle ReadIsochPipeAsync$VH() { - return IOUSBInterfaceStruct942.ReadIsochPipeAsync$VH; + return IOUSBInterfaceStruct190.ReadIsochPipeAsync$VH; } public static MemoryAddress ReadIsochPipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadIsochPipeAsync$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadIsochPipeAsync$VH.get(seg); } public static void ReadIsochPipeAsync$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.ReadIsochPipeAsync$VH.set(seg, x); + IOUSBInterfaceStruct190.ReadIsochPipeAsync$VH.set(seg, x); } public static MemoryAddress ReadIsochPipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadIsochPipeAsync$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadIsochPipeAsync$VH.get(seg.asSlice(index*sizeof())); } public static void ReadIsochPipeAsync$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.ReadIsochPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.ReadIsochPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); } public static ReadIsochPipeAsync ReadIsochPipeAsync (MemorySegment segment, MemorySession session) { return ReadIsochPipeAsync.ofAddress(ReadIsochPipeAsync$get(segment), session); @@ -1696,19 +1668,19 @@ public static ReadIsochPipeAsync ReadIsochPipeAsync (MemorySegment segment, Memo Constants$root.C_POINTER$LAYOUT ); static final MethodHandle WriteIsochPipeAsync$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.WriteIsochPipeAsync$FUNC + IOUSBInterfaceStruct190.WriteIsochPipeAsync$FUNC ); public interface WriteIsochPipeAsync { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, long _x3, int _x4, java.lang.foreign.MemoryAddress _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7); static MemorySegment allocate(WriteIsochPipeAsync fi, MemorySession session) { - return RuntimeHelper.upcallStub(WriteIsochPipeAsync.class, fi, IOUSBInterfaceStruct942.WriteIsochPipeAsync$FUNC, session); + return RuntimeHelper.upcallStub(WriteIsochPipeAsync.class, fi, IOUSBInterfaceStruct190.WriteIsochPipeAsync$FUNC, session); } static WriteIsochPipeAsync ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, long __x3, int __x4, java.lang.foreign.MemoryAddress __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7) -> { try { - return (int)IOUSBInterfaceStruct942.WriteIsochPipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7); + return (int)IOUSBInterfaceStruct190.WriteIsochPipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1718,19 +1690,19 @@ static WriteIsochPipeAsync ofAddress(MemoryAddress addr, MemorySession session) static final VarHandle WriteIsochPipeAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WriteIsochPipeAsync")); public static VarHandle WriteIsochPipeAsync$VH() { - return IOUSBInterfaceStruct942.WriteIsochPipeAsync$VH; + return IOUSBInterfaceStruct190.WriteIsochPipeAsync$VH; } public static MemoryAddress WriteIsochPipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WriteIsochPipeAsync$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WriteIsochPipeAsync$VH.get(seg); } public static void WriteIsochPipeAsync$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.WriteIsochPipeAsync$VH.set(seg, x); + IOUSBInterfaceStruct190.WriteIsochPipeAsync$VH.set(seg, x); } public static MemoryAddress WriteIsochPipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WriteIsochPipeAsync$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WriteIsochPipeAsync$VH.get(seg.asSlice(index*sizeof())); } public static void WriteIsochPipeAsync$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.WriteIsochPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.WriteIsochPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); } public static WriteIsochPipeAsync WriteIsochPipeAsync (MemorySegment segment, MemorySession session) { return WriteIsochPipeAsync.ofAddress(WriteIsochPipeAsync$get(segment), session); @@ -1741,19 +1713,19 @@ public static WriteIsochPipeAsync WriteIsochPipeAsync (MemorySegment segment, Me Constants$root.C_POINTER$LAYOUT ); static final MethodHandle ControlRequestTO$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.ControlRequestTO$FUNC + IOUSBInterfaceStruct190.ControlRequestTO$FUNC ); public interface ControlRequestTO { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2); static MemorySegment allocate(ControlRequestTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(ControlRequestTO.class, fi, IOUSBInterfaceStruct942.ControlRequestTO$FUNC, session); + return RuntimeHelper.upcallStub(ControlRequestTO.class, fi, IOUSBInterfaceStruct190.ControlRequestTO$FUNC, session); } static ControlRequestTO ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2) -> { try { - return (int)IOUSBInterfaceStruct942.ControlRequestTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + return (int)IOUSBInterfaceStruct190.ControlRequestTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1763,19 +1735,19 @@ static ControlRequestTO ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle ControlRequestTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ControlRequestTO")); public static VarHandle ControlRequestTO$VH() { - return IOUSBInterfaceStruct942.ControlRequestTO$VH; + return IOUSBInterfaceStruct190.ControlRequestTO$VH; } public static MemoryAddress ControlRequestTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ControlRequestTO$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ControlRequestTO$VH.get(seg); } public static void ControlRequestTO$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.ControlRequestTO$VH.set(seg, x); + IOUSBInterfaceStruct190.ControlRequestTO$VH.set(seg, x); } public static MemoryAddress ControlRequestTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ControlRequestTO$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ControlRequestTO$VH.get(seg.asSlice(index*sizeof())); } public static void ControlRequestTO$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.ControlRequestTO$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.ControlRequestTO$VH.set(seg.asSlice(index*sizeof()), x); } public static ControlRequestTO ControlRequestTO (MemorySegment segment, MemorySession session) { return ControlRequestTO.ofAddress(ControlRequestTO$get(segment), session); @@ -1788,19 +1760,19 @@ public static ControlRequestTO ControlRequestTO (MemorySegment segment, MemorySe Constants$root.C_POINTER$LAYOUT ); static final MethodHandle ControlRequestAsyncTO$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.ControlRequestAsyncTO$FUNC + IOUSBInterfaceStruct190.ControlRequestAsyncTO$FUNC ); public interface ControlRequestAsyncTO { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, java.lang.foreign.MemoryAddress _x4); static MemorySegment allocate(ControlRequestAsyncTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(ControlRequestAsyncTO.class, fi, IOUSBInterfaceStruct942.ControlRequestAsyncTO$FUNC, session); + return RuntimeHelper.upcallStub(ControlRequestAsyncTO.class, fi, IOUSBInterfaceStruct190.ControlRequestAsyncTO$FUNC, session); } static ControlRequestAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, java.lang.foreign.MemoryAddress __x4) -> { try { - return (int)IOUSBInterfaceStruct942.ControlRequestAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4); + return (int)IOUSBInterfaceStruct190.ControlRequestAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1810,19 +1782,19 @@ static ControlRequestAsyncTO ofAddress(MemoryAddress addr, MemorySession session static final VarHandle ControlRequestAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ControlRequestAsyncTO")); public static VarHandle ControlRequestAsyncTO$VH() { - return IOUSBInterfaceStruct942.ControlRequestAsyncTO$VH; + return IOUSBInterfaceStruct190.ControlRequestAsyncTO$VH; } public static MemoryAddress ControlRequestAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ControlRequestAsyncTO$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ControlRequestAsyncTO$VH.get(seg); } public static void ControlRequestAsyncTO$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.ControlRequestAsyncTO$VH.set(seg, x); + IOUSBInterfaceStruct190.ControlRequestAsyncTO$VH.set(seg, x); } public static MemoryAddress ControlRequestAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ControlRequestAsyncTO$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ControlRequestAsyncTO$VH.get(seg.asSlice(index*sizeof())); } public static void ControlRequestAsyncTO$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.ControlRequestAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.ControlRequestAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); } public static ControlRequestAsyncTO ControlRequestAsyncTO (MemorySegment segment, MemorySession session) { return ControlRequestAsyncTO.ofAddress(ControlRequestAsyncTO$get(segment), session); @@ -1836,19 +1808,19 @@ public static ControlRequestAsyncTO ControlRequestAsyncTO (MemorySegment segment Constants$root.C_INT$LAYOUT ); static final MethodHandle ReadPipeTO$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.ReadPipeTO$FUNC + IOUSBInterfaceStruct190.ReadPipeTO$FUNC ); public interface ReadPipeTO { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, int _x4, int _x5); static MemorySegment allocate(ReadPipeTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(ReadPipeTO.class, fi, IOUSBInterfaceStruct942.ReadPipeTO$FUNC, session); + return RuntimeHelper.upcallStub(ReadPipeTO.class, fi, IOUSBInterfaceStruct190.ReadPipeTO$FUNC, session); } static ReadPipeTO ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, int __x4, int __x5) -> { try { - return (int)IOUSBInterfaceStruct942.ReadPipeTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, __x4, __x5); + return (int)IOUSBInterfaceStruct190.ReadPipeTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, __x4, __x5); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1858,19 +1830,19 @@ static ReadPipeTO ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle ReadPipeTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadPipeTO")); public static VarHandle ReadPipeTO$VH() { - return IOUSBInterfaceStruct942.ReadPipeTO$VH; + return IOUSBInterfaceStruct190.ReadPipeTO$VH; } public static MemoryAddress ReadPipeTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadPipeTO$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadPipeTO$VH.get(seg); } public static void ReadPipeTO$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.ReadPipeTO$VH.set(seg, x); + IOUSBInterfaceStruct190.ReadPipeTO$VH.set(seg, x); } public static MemoryAddress ReadPipeTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadPipeTO$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadPipeTO$VH.get(seg.asSlice(index*sizeof())); } public static void ReadPipeTO$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.ReadPipeTO$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.ReadPipeTO$VH.set(seg.asSlice(index*sizeof()), x); } public static ReadPipeTO ReadPipeTO (MemorySegment segment, MemorySession session) { return ReadPipeTO.ofAddress(ReadPipeTO$get(segment), session); @@ -1884,19 +1856,19 @@ public static ReadPipeTO ReadPipeTO (MemorySegment segment, MemorySession sessio Constants$root.C_INT$LAYOUT ); static final MethodHandle WritePipeTO$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.WritePipeTO$FUNC + IOUSBInterfaceStruct190.WritePipeTO$FUNC ); public interface WritePipeTO { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3, int _x4, int _x5); static MemorySegment allocate(WritePipeTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(WritePipeTO.class, fi, IOUSBInterfaceStruct942.WritePipeTO$FUNC, session); + return RuntimeHelper.upcallStub(WritePipeTO.class, fi, IOUSBInterfaceStruct190.WritePipeTO$FUNC, session); } static WritePipeTO ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3, int __x4, int __x5) -> { try { - return (int)IOUSBInterfaceStruct942.WritePipeTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, __x5); + return (int)IOUSBInterfaceStruct190.WritePipeTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, __x5); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1906,19 +1878,19 @@ static WritePipeTO ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle WritePipeTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WritePipeTO")); public static VarHandle WritePipeTO$VH() { - return IOUSBInterfaceStruct942.WritePipeTO$VH; + return IOUSBInterfaceStruct190.WritePipeTO$VH; } public static MemoryAddress WritePipeTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WritePipeTO$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WritePipeTO$VH.get(seg); } public static void WritePipeTO$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.WritePipeTO$VH.set(seg, x); + IOUSBInterfaceStruct190.WritePipeTO$VH.set(seg, x); } public static MemoryAddress WritePipeTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WritePipeTO$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WritePipeTO$VH.get(seg.asSlice(index*sizeof())); } public static void WritePipeTO$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.WritePipeTO$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.WritePipeTO$VH.set(seg.asSlice(index*sizeof()), x); } public static WritePipeTO WritePipeTO (MemorySegment segment, MemorySession session) { return WritePipeTO.ofAddress(WritePipeTO$get(segment), session); @@ -1934,19 +1906,19 @@ public static WritePipeTO WritePipeTO (MemorySegment segment, MemorySession sess Constants$root.C_POINTER$LAYOUT ); static final MethodHandle ReadPipeAsyncTO$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.ReadPipeAsyncTO$FUNC + IOUSBInterfaceStruct190.ReadPipeAsyncTO$FUNC ); public interface ReadPipeAsyncTO { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3, int _x4, int _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7); static MemorySegment allocate(ReadPipeAsyncTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(ReadPipeAsyncTO.class, fi, IOUSBInterfaceStruct942.ReadPipeAsyncTO$FUNC, session); + return RuntimeHelper.upcallStub(ReadPipeAsyncTO.class, fi, IOUSBInterfaceStruct190.ReadPipeAsyncTO$FUNC, session); } static ReadPipeAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3, int __x4, int __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7) -> { try { - return (int)IOUSBInterfaceStruct942.ReadPipeAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, __x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7); + return (int)IOUSBInterfaceStruct190.ReadPipeAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, __x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1956,19 +1928,19 @@ static ReadPipeAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle ReadPipeAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadPipeAsyncTO")); public static VarHandle ReadPipeAsyncTO$VH() { - return IOUSBInterfaceStruct942.ReadPipeAsyncTO$VH; + return IOUSBInterfaceStruct190.ReadPipeAsyncTO$VH; } public static MemoryAddress ReadPipeAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadPipeAsyncTO$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadPipeAsyncTO$VH.get(seg); } public static void ReadPipeAsyncTO$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.ReadPipeAsyncTO$VH.set(seg, x); + IOUSBInterfaceStruct190.ReadPipeAsyncTO$VH.set(seg, x); } public static MemoryAddress ReadPipeAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadPipeAsyncTO$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadPipeAsyncTO$VH.get(seg.asSlice(index*sizeof())); } public static void ReadPipeAsyncTO$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.ReadPipeAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.ReadPipeAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); } public static ReadPipeAsyncTO ReadPipeAsyncTO (MemorySegment segment, MemorySession session) { return ReadPipeAsyncTO.ofAddress(ReadPipeAsyncTO$get(segment), session); @@ -1984,19 +1956,19 @@ public static ReadPipeAsyncTO ReadPipeAsyncTO (MemorySegment segment, MemorySess Constants$root.C_POINTER$LAYOUT ); static final MethodHandle WritePipeAsyncTO$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.WritePipeAsyncTO$FUNC + IOUSBInterfaceStruct190.WritePipeAsyncTO$FUNC ); public interface WritePipeAsyncTO { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3, int _x4, int _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7); static MemorySegment allocate(WritePipeAsyncTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(WritePipeAsyncTO.class, fi, IOUSBInterfaceStruct942.WritePipeAsyncTO$FUNC, session); + return RuntimeHelper.upcallStub(WritePipeAsyncTO.class, fi, IOUSBInterfaceStruct190.WritePipeAsyncTO$FUNC, session); } static WritePipeAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3, int __x4, int __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7) -> { try { - return (int)IOUSBInterfaceStruct942.WritePipeAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, __x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7); + return (int)IOUSBInterfaceStruct190.WritePipeAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, __x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2006,19 +1978,19 @@ static WritePipeAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle WritePipeAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WritePipeAsyncTO")); public static VarHandle WritePipeAsyncTO$VH() { - return IOUSBInterfaceStruct942.WritePipeAsyncTO$VH; + return IOUSBInterfaceStruct190.WritePipeAsyncTO$VH; } public static MemoryAddress WritePipeAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WritePipeAsyncTO$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WritePipeAsyncTO$VH.get(seg); } public static void WritePipeAsyncTO$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.WritePipeAsyncTO$VH.set(seg, x); + IOUSBInterfaceStruct190.WritePipeAsyncTO$VH.set(seg, x); } public static MemoryAddress WritePipeAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WritePipeAsyncTO$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WritePipeAsyncTO$VH.get(seg.asSlice(index*sizeof())); } public static void WritePipeAsyncTO$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.WritePipeAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.WritePipeAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); } public static WritePipeAsyncTO WritePipeAsyncTO (MemorySegment segment, MemorySession session) { return WritePipeAsyncTO.ofAddress(WritePipeAsyncTO$get(segment), session); @@ -2028,19 +2000,19 @@ public static WritePipeAsyncTO WritePipeAsyncTO (MemorySegment segment, MemorySe Constants$root.C_POINTER$LAYOUT ); static final MethodHandle USBInterfaceGetStringIndex$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.USBInterfaceGetStringIndex$FUNC + IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$FUNC ); public interface USBInterfaceGetStringIndex { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); static MemorySegment allocate(USBInterfaceGetStringIndex fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBInterfaceGetStringIndex.class, fi, IOUSBInterfaceStruct942.USBInterfaceGetStringIndex$FUNC, session); + return RuntimeHelper.upcallStub(USBInterfaceGetStringIndex.class, fi, IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$FUNC, session); } static USBInterfaceGetStringIndex ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { try { - return (int)IOUSBInterfaceStruct942.USBInterfaceGetStringIndex$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2050,19 +2022,19 @@ static USBInterfaceGetStringIndex ofAddress(MemoryAddress addr, MemorySession se static final VarHandle USBInterfaceGetStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceGetStringIndex")); public static VarHandle USBInterfaceGetStringIndex$VH() { - return IOUSBInterfaceStruct942.USBInterfaceGetStringIndex$VH; + return IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$VH; } public static MemoryAddress USBInterfaceGetStringIndex$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.USBInterfaceGetStringIndex$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$VH.get(seg); } public static void USBInterfaceGetStringIndex$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.USBInterfaceGetStringIndex$VH.set(seg, x); + IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$VH.set(seg, x); } public static MemoryAddress USBInterfaceGetStringIndex$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.USBInterfaceGetStringIndex$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$VH.get(seg.asSlice(index*sizeof())); } public static void USBInterfaceGetStringIndex$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.USBInterfaceGetStringIndex$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$VH.set(seg.asSlice(index*sizeof()), x); } public static USBInterfaceGetStringIndex USBInterfaceGetStringIndex (MemorySegment segment, MemorySession session) { return USBInterfaceGetStringIndex.ofAddress(USBInterfaceGetStringIndex$get(segment), session); @@ -2071,19 +2043,19 @@ public static USBInterfaceGetStringIndex USBInterfaceGetStringIndex (MemorySegme Constants$root.C_POINTER$LAYOUT ); static final MethodHandle USBInterfaceOpenSeize$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.USBInterfaceOpenSeize$FUNC + IOUSBInterfaceStruct190.USBInterfaceOpenSeize$FUNC ); public interface USBInterfaceOpenSeize { int apply(java.lang.foreign.MemoryAddress _x0); static MemorySegment allocate(USBInterfaceOpenSeize fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBInterfaceOpenSeize.class, fi, IOUSBInterfaceStruct942.USBInterfaceOpenSeize$FUNC, session); + return RuntimeHelper.upcallStub(USBInterfaceOpenSeize.class, fi, IOUSBInterfaceStruct190.USBInterfaceOpenSeize$FUNC, session); } static USBInterfaceOpenSeize ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0) -> { try { - return (int)IOUSBInterfaceStruct942.USBInterfaceOpenSeize$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBInterfaceStruct190.USBInterfaceOpenSeize$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2093,19 +2065,19 @@ static USBInterfaceOpenSeize ofAddress(MemoryAddress addr, MemorySession session static final VarHandle USBInterfaceOpenSeize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceOpenSeize")); public static VarHandle USBInterfaceOpenSeize$VH() { - return IOUSBInterfaceStruct942.USBInterfaceOpenSeize$VH; + return IOUSBInterfaceStruct190.USBInterfaceOpenSeize$VH; } public static MemoryAddress USBInterfaceOpenSeize$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.USBInterfaceOpenSeize$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.USBInterfaceOpenSeize$VH.get(seg); } public static void USBInterfaceOpenSeize$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.USBInterfaceOpenSeize$VH.set(seg, x); + IOUSBInterfaceStruct190.USBInterfaceOpenSeize$VH.set(seg, x); } public static MemoryAddress USBInterfaceOpenSeize$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.USBInterfaceOpenSeize$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.USBInterfaceOpenSeize$VH.get(seg.asSlice(index*sizeof())); } public static void USBInterfaceOpenSeize$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.USBInterfaceOpenSeize$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.USBInterfaceOpenSeize$VH.set(seg.asSlice(index*sizeof()), x); } public static USBInterfaceOpenSeize USBInterfaceOpenSeize (MemorySegment segment, MemorySession session) { return USBInterfaceOpenSeize.ofAddress(USBInterfaceOpenSeize$get(segment), session); @@ -2115,19 +2087,19 @@ public static USBInterfaceOpenSeize USBInterfaceOpenSeize (MemorySegment segment Constants$root.C_CHAR$LAYOUT ); static final MethodHandle ClearPipeStallBothEnds$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.ClearPipeStallBothEnds$FUNC + IOUSBInterfaceStruct190.ClearPipeStallBothEnds$FUNC ); public interface ClearPipeStallBothEnds { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); static MemorySegment allocate(ClearPipeStallBothEnds fi, MemorySession session) { - return RuntimeHelper.upcallStub(ClearPipeStallBothEnds.class, fi, IOUSBInterfaceStruct942.ClearPipeStallBothEnds$FUNC, session); + return RuntimeHelper.upcallStub(ClearPipeStallBothEnds.class, fi, IOUSBInterfaceStruct190.ClearPipeStallBothEnds$FUNC, session); } static ClearPipeStallBothEnds ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct942.ClearPipeStallBothEnds$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + return (int)IOUSBInterfaceStruct190.ClearPipeStallBothEnds$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2137,19 +2109,19 @@ static ClearPipeStallBothEnds ofAddress(MemoryAddress addr, MemorySession sessio static final VarHandle ClearPipeStallBothEnds$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ClearPipeStallBothEnds")); public static VarHandle ClearPipeStallBothEnds$VH() { - return IOUSBInterfaceStruct942.ClearPipeStallBothEnds$VH; + return IOUSBInterfaceStruct190.ClearPipeStallBothEnds$VH; } public static MemoryAddress ClearPipeStallBothEnds$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ClearPipeStallBothEnds$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ClearPipeStallBothEnds$VH.get(seg); } public static void ClearPipeStallBothEnds$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.ClearPipeStallBothEnds$VH.set(seg, x); + IOUSBInterfaceStruct190.ClearPipeStallBothEnds$VH.set(seg, x); } public static MemoryAddress ClearPipeStallBothEnds$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ClearPipeStallBothEnds$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ClearPipeStallBothEnds$VH.get(seg.asSlice(index*sizeof())); } public static void ClearPipeStallBothEnds$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.ClearPipeStallBothEnds$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.ClearPipeStallBothEnds$VH.set(seg.asSlice(index*sizeof()), x); } public static ClearPipeStallBothEnds ClearPipeStallBothEnds (MemorySegment segment, MemorySession session) { return ClearPipeStallBothEnds.ofAddress(ClearPipeStallBothEnds$get(segment), session); @@ -2161,19 +2133,19 @@ public static ClearPipeStallBothEnds ClearPipeStallBothEnds (MemorySegment segme Constants$root.C_CHAR$LAYOUT ); static final MethodHandle SetPipePolicy$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.SetPipePolicy$FUNC + IOUSBInterfaceStruct190.SetPipePolicy$FUNC ); public interface SetPipePolicy { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, short _x2, byte _x3); static MemorySegment allocate(SetPipePolicy fi, MemorySession session) { - return RuntimeHelper.upcallStub(SetPipePolicy.class, fi, IOUSBInterfaceStruct942.SetPipePolicy$FUNC, session); + return RuntimeHelper.upcallStub(SetPipePolicy.class, fi, IOUSBInterfaceStruct190.SetPipePolicy$FUNC, session); } static SetPipePolicy ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1, short __x2, byte __x3) -> { try { - return (int)IOUSBInterfaceStruct942.SetPipePolicy$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, __x3); + return (int)IOUSBInterfaceStruct190.SetPipePolicy$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, __x3); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2183,19 +2155,19 @@ static SetPipePolicy ofAddress(MemoryAddress addr, MemorySession session) { static final VarHandle SetPipePolicy$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetPipePolicy")); public static VarHandle SetPipePolicy$VH() { - return IOUSBInterfaceStruct942.SetPipePolicy$VH; + return IOUSBInterfaceStruct190.SetPipePolicy$VH; } public static MemoryAddress SetPipePolicy$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SetPipePolicy$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.SetPipePolicy$VH.get(seg); } public static void SetPipePolicy$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.SetPipePolicy$VH.set(seg, x); + IOUSBInterfaceStruct190.SetPipePolicy$VH.set(seg, x); } public static MemoryAddress SetPipePolicy$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SetPipePolicy$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.SetPipePolicy$VH.get(seg.asSlice(index*sizeof())); } public static void SetPipePolicy$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.SetPipePolicy$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.SetPipePolicy$VH.set(seg.asSlice(index*sizeof()), x); } public static SetPipePolicy SetPipePolicy (MemorySegment segment, MemorySession session) { return SetPipePolicy.ofAddress(SetPipePolicy$get(segment), session); @@ -2205,19 +2177,19 @@ public static SetPipePolicy SetPipePolicy (MemorySegment segment, MemorySession Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetBandwidthAvailable$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetBandwidthAvailable$FUNC + IOUSBInterfaceStruct190.GetBandwidthAvailable$FUNC ); public interface GetBandwidthAvailable { int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); static MemorySegment allocate(GetBandwidthAvailable fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetBandwidthAvailable.class, fi, IOUSBInterfaceStruct942.GetBandwidthAvailable$FUNC, session); + return RuntimeHelper.upcallStub(GetBandwidthAvailable.class, fi, IOUSBInterfaceStruct190.GetBandwidthAvailable$FUNC, session); } static GetBandwidthAvailable ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { try { - return (int)IOUSBInterfaceStruct942.GetBandwidthAvailable$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetBandwidthAvailable$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2227,19 +2199,19 @@ static GetBandwidthAvailable ofAddress(MemoryAddress addr, MemorySession session static final VarHandle GetBandwidthAvailable$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBandwidthAvailable")); public static VarHandle GetBandwidthAvailable$VH() { - return IOUSBInterfaceStruct942.GetBandwidthAvailable$VH; + return IOUSBInterfaceStruct190.GetBandwidthAvailable$VH; } public static MemoryAddress GetBandwidthAvailable$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetBandwidthAvailable$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetBandwidthAvailable$VH.get(seg); } public static void GetBandwidthAvailable$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetBandwidthAvailable$VH.set(seg, x); + IOUSBInterfaceStruct190.GetBandwidthAvailable$VH.set(seg, x); } public static MemoryAddress GetBandwidthAvailable$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetBandwidthAvailable$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetBandwidthAvailable$VH.get(seg.asSlice(index*sizeof())); } public static void GetBandwidthAvailable$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetBandwidthAvailable$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetBandwidthAvailable$VH.set(seg.asSlice(index*sizeof()), x); } public static GetBandwidthAvailable GetBandwidthAvailable (MemorySegment segment, MemorySession session) { return GetBandwidthAvailable.ofAddress(GetBandwidthAvailable$get(segment), session); @@ -2254,19 +2226,19 @@ public static GetBandwidthAvailable GetBandwidthAvailable (MemorySegment segment Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetEndpointProperties$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetEndpointProperties$FUNC + IOUSBInterfaceStruct190.GetEndpointProperties$FUNC ); public interface GetEndpointProperties { int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, byte _x2, byte _x3, java.lang.foreign.MemoryAddress _x4, java.lang.foreign.MemoryAddress _x5, java.lang.foreign.MemoryAddress _x6); static MemorySegment allocate(GetEndpointProperties fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetEndpointProperties.class, fi, IOUSBInterfaceStruct942.GetEndpointProperties$FUNC, session); + return RuntimeHelper.upcallStub(GetEndpointProperties.class, fi, IOUSBInterfaceStruct190.GetEndpointProperties$FUNC, session); } static GetEndpointProperties ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress __x0, byte __x1, byte __x2, byte __x3, java.lang.foreign.MemoryAddress __x4, java.lang.foreign.MemoryAddress __x5, java.lang.foreign.MemoryAddress __x6) -> { try { - return (int)IOUSBInterfaceStruct942.GetEndpointProperties$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, __x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6); + return (int)IOUSBInterfaceStruct190.GetEndpointProperties$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, __x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2276,1315 +2248,23 @@ static GetEndpointProperties ofAddress(MemoryAddress addr, MemorySession session static final VarHandle GetEndpointProperties$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetEndpointProperties")); public static VarHandle GetEndpointProperties$VH() { - return IOUSBInterfaceStruct942.GetEndpointProperties$VH; + return IOUSBInterfaceStruct190.GetEndpointProperties$VH; } public static MemoryAddress GetEndpointProperties$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetEndpointProperties$VH.get(seg); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetEndpointProperties$VH.get(seg); } public static void GetEndpointProperties$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetEndpointProperties$VH.set(seg, x); + IOUSBInterfaceStruct190.GetEndpointProperties$VH.set(seg, x); } public static MemoryAddress GetEndpointProperties$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetEndpointProperties$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetEndpointProperties$VH.get(seg.asSlice(index*sizeof())); } public static void GetEndpointProperties$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetEndpointProperties$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBInterfaceStruct190.GetEndpointProperties$VH.set(seg.asSlice(index*sizeof()), x); } public static GetEndpointProperties GetEndpointProperties (MemorySegment segment, MemorySession session) { return GetEndpointProperties.ofAddress(GetEndpointProperties$get(segment), session); } - static final FunctionDescriptor LowLatencyReadIsochPipeAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle LowLatencyReadIsochPipeAsync$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.LowLatencyReadIsochPipeAsync$FUNC - ); - public interface LowLatencyReadIsochPipeAsync { - - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, long _x3, int _x4, int _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7, java.lang.foreign.MemoryAddress _x8); - static MemorySegment allocate(LowLatencyReadIsochPipeAsync fi, MemorySession session) { - return RuntimeHelper.upcallStub(LowLatencyReadIsochPipeAsync.class, fi, IOUSBInterfaceStruct942.LowLatencyReadIsochPipeAsync$FUNC, session); - } - static LowLatencyReadIsochPipeAsync ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, long __x3, int __x4, int __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7, java.lang.foreign.MemoryAddress __x8) -> { - try { - return (int)IOUSBInterfaceStruct942.LowLatencyReadIsochPipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, __x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7, (java.lang.foreign.Addressable)__x8); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle LowLatencyReadIsochPipeAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("LowLatencyReadIsochPipeAsync")); - public static VarHandle LowLatencyReadIsochPipeAsync$VH() { - return IOUSBInterfaceStruct942.LowLatencyReadIsochPipeAsync$VH; - } - public static MemoryAddress LowLatencyReadIsochPipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.LowLatencyReadIsochPipeAsync$VH.get(seg); - } - public static void LowLatencyReadIsochPipeAsync$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.LowLatencyReadIsochPipeAsync$VH.set(seg, x); - } - public static MemoryAddress LowLatencyReadIsochPipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.LowLatencyReadIsochPipeAsync$VH.get(seg.asSlice(index*sizeof())); - } - public static void LowLatencyReadIsochPipeAsync$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.LowLatencyReadIsochPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); - } - public static LowLatencyReadIsochPipeAsync LowLatencyReadIsochPipeAsync (MemorySegment segment, MemorySession session) { - return LowLatencyReadIsochPipeAsync.ofAddress(LowLatencyReadIsochPipeAsync$get(segment), session); - } - static final FunctionDescriptor LowLatencyWriteIsochPipeAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle LowLatencyWriteIsochPipeAsync$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.LowLatencyWriteIsochPipeAsync$FUNC - ); - public interface LowLatencyWriteIsochPipeAsync { - - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, long _x3, int _x4, int _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7, java.lang.foreign.MemoryAddress _x8); - static MemorySegment allocate(LowLatencyWriteIsochPipeAsync fi, MemorySession session) { - return RuntimeHelper.upcallStub(LowLatencyWriteIsochPipeAsync.class, fi, IOUSBInterfaceStruct942.LowLatencyWriteIsochPipeAsync$FUNC, session); - } - static LowLatencyWriteIsochPipeAsync ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, long __x3, int __x4, int __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7, java.lang.foreign.MemoryAddress __x8) -> { - try { - return (int)IOUSBInterfaceStruct942.LowLatencyWriteIsochPipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, __x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7, (java.lang.foreign.Addressable)__x8); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle LowLatencyWriteIsochPipeAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("LowLatencyWriteIsochPipeAsync")); - public static VarHandle LowLatencyWriteIsochPipeAsync$VH() { - return IOUSBInterfaceStruct942.LowLatencyWriteIsochPipeAsync$VH; - } - public static MemoryAddress LowLatencyWriteIsochPipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.LowLatencyWriteIsochPipeAsync$VH.get(seg); - } - public static void LowLatencyWriteIsochPipeAsync$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.LowLatencyWriteIsochPipeAsync$VH.set(seg, x); - } - public static MemoryAddress LowLatencyWriteIsochPipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.LowLatencyWriteIsochPipeAsync$VH.get(seg.asSlice(index*sizeof())); - } - public static void LowLatencyWriteIsochPipeAsync$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.LowLatencyWriteIsochPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); - } - public static LowLatencyWriteIsochPipeAsync LowLatencyWriteIsochPipeAsync (MemorySegment segment, MemorySession session) { - return LowLatencyWriteIsochPipeAsync.ofAddress(LowLatencyWriteIsochPipeAsync$get(segment), session); - } - static final FunctionDescriptor LowLatencyCreateBuffer$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle LowLatencyCreateBuffer$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.LowLatencyCreateBuffer$FUNC - ); - public interface LowLatencyCreateBuffer { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, int _x2, int _x3); - static MemorySegment allocate(LowLatencyCreateBuffer fi, MemorySession session) { - return RuntimeHelper.upcallStub(LowLatencyCreateBuffer.class, fi, IOUSBInterfaceStruct942.LowLatencyCreateBuffer$FUNC, session); - } - static LowLatencyCreateBuffer ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, int __x2, int __x3) -> { - try { - return (int)IOUSBInterfaceStruct942.LowLatencyCreateBuffer$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, __x2, __x3); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle LowLatencyCreateBuffer$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("LowLatencyCreateBuffer")); - public static VarHandle LowLatencyCreateBuffer$VH() { - return IOUSBInterfaceStruct942.LowLatencyCreateBuffer$VH; - } - public static MemoryAddress LowLatencyCreateBuffer$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.LowLatencyCreateBuffer$VH.get(seg); - } - public static void LowLatencyCreateBuffer$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.LowLatencyCreateBuffer$VH.set(seg, x); - } - public static MemoryAddress LowLatencyCreateBuffer$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.LowLatencyCreateBuffer$VH.get(seg.asSlice(index*sizeof())); - } - public static void LowLatencyCreateBuffer$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.LowLatencyCreateBuffer$VH.set(seg.asSlice(index*sizeof()), x); - } - public static LowLatencyCreateBuffer LowLatencyCreateBuffer (MemorySegment segment, MemorySession session) { - return LowLatencyCreateBuffer.ofAddress(LowLatencyCreateBuffer$get(segment), session); - } - static final FunctionDescriptor LowLatencyDestroyBuffer$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle LowLatencyDestroyBuffer$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.LowLatencyDestroyBuffer$FUNC - ); - public interface LowLatencyDestroyBuffer { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(LowLatencyDestroyBuffer fi, MemorySession session) { - return RuntimeHelper.upcallStub(LowLatencyDestroyBuffer.class, fi, IOUSBInterfaceStruct942.LowLatencyDestroyBuffer$FUNC, session); - } - static LowLatencyDestroyBuffer ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBInterfaceStruct942.LowLatencyDestroyBuffer$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle LowLatencyDestroyBuffer$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("LowLatencyDestroyBuffer")); - public static VarHandle LowLatencyDestroyBuffer$VH() { - return IOUSBInterfaceStruct942.LowLatencyDestroyBuffer$VH; - } - public static MemoryAddress LowLatencyDestroyBuffer$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.LowLatencyDestroyBuffer$VH.get(seg); - } - public static void LowLatencyDestroyBuffer$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.LowLatencyDestroyBuffer$VH.set(seg, x); - } - public static MemoryAddress LowLatencyDestroyBuffer$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.LowLatencyDestroyBuffer$VH.get(seg.asSlice(index*sizeof())); - } - public static void LowLatencyDestroyBuffer$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.LowLatencyDestroyBuffer$VH.set(seg.asSlice(index*sizeof()), x); - } - public static LowLatencyDestroyBuffer LowLatencyDestroyBuffer (MemorySegment segment, MemorySession session) { - return LowLatencyDestroyBuffer.ofAddress(LowLatencyDestroyBuffer$get(segment), session); - } - static final FunctionDescriptor GetBusMicroFrameNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetBusMicroFrameNumber$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetBusMicroFrameNumber$FUNC - ); - public interface GetBusMicroFrameNumber { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(GetBusMicroFrameNumber fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetBusMicroFrameNumber.class, fi, IOUSBInterfaceStruct942.GetBusMicroFrameNumber$FUNC, session); - } - static GetBusMicroFrameNumber ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { - try { - return (int)IOUSBInterfaceStruct942.GetBusMicroFrameNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetBusMicroFrameNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBusMicroFrameNumber")); - public static VarHandle GetBusMicroFrameNumber$VH() { - return IOUSBInterfaceStruct942.GetBusMicroFrameNumber$VH; - } - public static MemoryAddress GetBusMicroFrameNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetBusMicroFrameNumber$VH.get(seg); - } - public static void GetBusMicroFrameNumber$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetBusMicroFrameNumber$VH.set(seg, x); - } - public static MemoryAddress GetBusMicroFrameNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetBusMicroFrameNumber$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetBusMicroFrameNumber$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetBusMicroFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetBusMicroFrameNumber GetBusMicroFrameNumber (MemorySegment segment, MemorySession session) { - return GetBusMicroFrameNumber.ofAddress(GetBusMicroFrameNumber$get(segment), session); - } - static final FunctionDescriptor GetFrameListTime$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetFrameListTime$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetFrameListTime$FUNC - ); - public interface GetFrameListTime { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetFrameListTime fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetFrameListTime.class, fi, IOUSBInterfaceStruct942.GetFrameListTime$FUNC, session); - } - static GetFrameListTime ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBInterfaceStruct942.GetFrameListTime$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetFrameListTime$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetFrameListTime")); - public static VarHandle GetFrameListTime$VH() { - return IOUSBInterfaceStruct942.GetFrameListTime$VH; - } - public static MemoryAddress GetFrameListTime$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetFrameListTime$VH.get(seg); - } - public static void GetFrameListTime$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetFrameListTime$VH.set(seg, x); - } - public static MemoryAddress GetFrameListTime$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetFrameListTime$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetFrameListTime$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetFrameListTime$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetFrameListTime GetFrameListTime (MemorySegment segment, MemorySession session) { - return GetFrameListTime.ofAddress(GetFrameListTime$get(segment), session); - } - static final FunctionDescriptor GetIOUSBLibVersion$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetIOUSBLibVersion$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetIOUSBLibVersion$FUNC - ); - public interface GetIOUSBLibVersion { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(GetIOUSBLibVersion fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetIOUSBLibVersion.class, fi, IOUSBInterfaceStruct942.GetIOUSBLibVersion$FUNC, session); - } - static GetIOUSBLibVersion ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { - try { - return (int)IOUSBInterfaceStruct942.GetIOUSBLibVersion$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetIOUSBLibVersion$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetIOUSBLibVersion")); - public static VarHandle GetIOUSBLibVersion$VH() { - return IOUSBInterfaceStruct942.GetIOUSBLibVersion$VH; - } - public static MemoryAddress GetIOUSBLibVersion$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetIOUSBLibVersion$VH.get(seg); - } - public static void GetIOUSBLibVersion$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetIOUSBLibVersion$VH.set(seg, x); - } - public static MemoryAddress GetIOUSBLibVersion$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetIOUSBLibVersion$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetIOUSBLibVersion$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetIOUSBLibVersion$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetIOUSBLibVersion GetIOUSBLibVersion (MemorySegment segment, MemorySession session) { - return GetIOUSBLibVersion.ofAddress(GetIOUSBLibVersion$get(segment), session); - } - static final FunctionDescriptor FindNextAssociatedDescriptor$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT - ); - static final MethodHandle FindNextAssociatedDescriptor$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.FindNextAssociatedDescriptor$FUNC - ); - public interface FindNextAssociatedDescriptor { - - java.lang.foreign.Addressable apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, byte _x2); - static MemorySegment allocate(FindNextAssociatedDescriptor fi, MemorySession session) { - return RuntimeHelper.upcallStub(FindNextAssociatedDescriptor.class, fi, IOUSBInterfaceStruct942.FindNextAssociatedDescriptor$FUNC, session); - } - static FindNextAssociatedDescriptor ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, byte __x2) -> { - try { - return (java.lang.foreign.Addressable)(java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.FindNextAssociatedDescriptor$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, __x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle FindNextAssociatedDescriptor$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("FindNextAssociatedDescriptor")); - public static VarHandle FindNextAssociatedDescriptor$VH() { - return IOUSBInterfaceStruct942.FindNextAssociatedDescriptor$VH; - } - public static MemoryAddress FindNextAssociatedDescriptor$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.FindNextAssociatedDescriptor$VH.get(seg); - } - public static void FindNextAssociatedDescriptor$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.FindNextAssociatedDescriptor$VH.set(seg, x); - } - public static MemoryAddress FindNextAssociatedDescriptor$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.FindNextAssociatedDescriptor$VH.get(seg.asSlice(index*sizeof())); - } - public static void FindNextAssociatedDescriptor$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.FindNextAssociatedDescriptor$VH.set(seg.asSlice(index*sizeof()), x); - } - public static FindNextAssociatedDescriptor FindNextAssociatedDescriptor (MemorySegment segment, MemorySession session) { - return FindNextAssociatedDescriptor.ofAddress(FindNextAssociatedDescriptor$get(segment), session); - } - static final FunctionDescriptor FindNextAltInterface$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle FindNextAltInterface$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.FindNextAltInterface$FUNC - ); - public interface FindNextAltInterface { - - java.lang.foreign.Addressable apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(FindNextAltInterface fi, MemorySession session) { - return RuntimeHelper.upcallStub(FindNextAltInterface.class, fi, IOUSBInterfaceStruct942.FindNextAltInterface$FUNC, session); - } - static FindNextAltInterface ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { - try { - return (java.lang.foreign.Addressable)(java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.FindNextAltInterface$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle FindNextAltInterface$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("FindNextAltInterface")); - public static VarHandle FindNextAltInterface$VH() { - return IOUSBInterfaceStruct942.FindNextAltInterface$VH; - } - public static MemoryAddress FindNextAltInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.FindNextAltInterface$VH.get(seg); - } - public static void FindNextAltInterface$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.FindNextAltInterface$VH.set(seg, x); - } - public static MemoryAddress FindNextAltInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.FindNextAltInterface$VH.get(seg.asSlice(index*sizeof())); - } - public static void FindNextAltInterface$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.FindNextAltInterface$VH.set(seg.asSlice(index*sizeof()), x); - } - public static FindNextAltInterface FindNextAltInterface (MemorySegment segment, MemorySession session) { - return FindNextAltInterface.ofAddress(FindNextAltInterface$get(segment), session); - } - static final FunctionDescriptor GetBusFrameNumberWithTime$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetBusFrameNumberWithTime$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetBusFrameNumberWithTime$FUNC - ); - public interface GetBusFrameNumberWithTime { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(GetBusFrameNumberWithTime fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetBusFrameNumberWithTime.class, fi, IOUSBInterfaceStruct942.GetBusFrameNumberWithTime$FUNC, session); - } - static GetBusFrameNumberWithTime ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { - try { - return (int)IOUSBInterfaceStruct942.GetBusFrameNumberWithTime$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetBusFrameNumberWithTime$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBusFrameNumberWithTime")); - public static VarHandle GetBusFrameNumberWithTime$VH() { - return IOUSBInterfaceStruct942.GetBusFrameNumberWithTime$VH; - } - public static MemoryAddress GetBusFrameNumberWithTime$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetBusFrameNumberWithTime$VH.get(seg); - } - public static void GetBusFrameNumberWithTime$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetBusFrameNumberWithTime$VH.set(seg, x); - } - public static MemoryAddress GetBusFrameNumberWithTime$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetBusFrameNumberWithTime$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetBusFrameNumberWithTime$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetBusFrameNumberWithTime$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetBusFrameNumberWithTime GetBusFrameNumberWithTime (MemorySegment segment, MemorySession session) { - return GetBusFrameNumberWithTime.ofAddress(GetBusFrameNumberWithTime$get(segment), session); - } - static final FunctionDescriptor GetPipePropertiesV2$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetPipePropertiesV2$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetPipePropertiesV2$FUNC - ); - public interface GetPipePropertiesV2 { - - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, java.lang.foreign.MemoryAddress _x4, java.lang.foreign.MemoryAddress _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7, java.lang.foreign.MemoryAddress _x8, java.lang.foreign.MemoryAddress _x9); - static MemorySegment allocate(GetPipePropertiesV2 fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetPipePropertiesV2.class, fi, IOUSBInterfaceStruct942.GetPipePropertiesV2$FUNC, session); - } - static GetPipePropertiesV2 ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, java.lang.foreign.MemoryAddress __x4, java.lang.foreign.MemoryAddress __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7, java.lang.foreign.MemoryAddress __x8, java.lang.foreign.MemoryAddress __x9) -> { - try { - return (int)IOUSBInterfaceStruct942.GetPipePropertiesV2$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7, (java.lang.foreign.Addressable)__x8, (java.lang.foreign.Addressable)__x9); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetPipePropertiesV2$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetPipePropertiesV2")); - public static VarHandle GetPipePropertiesV2$VH() { - return IOUSBInterfaceStruct942.GetPipePropertiesV2$VH; - } - public static MemoryAddress GetPipePropertiesV2$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetPipePropertiesV2$VH.get(seg); - } - public static void GetPipePropertiesV2$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetPipePropertiesV2$VH.set(seg, x); - } - public static MemoryAddress GetPipePropertiesV2$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetPipePropertiesV2$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetPipePropertiesV2$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetPipePropertiesV2$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetPipePropertiesV2 GetPipePropertiesV2 (MemorySegment segment, MemorySession session) { - return GetPipePropertiesV2.ofAddress(GetPipePropertiesV2$get(segment), session); - } - static final FunctionDescriptor GetPipePropertiesV3$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetPipePropertiesV3$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetPipePropertiesV3$FUNC - ); - public interface GetPipePropertiesV3 { - - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(GetPipePropertiesV3 fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetPipePropertiesV3.class, fi, IOUSBInterfaceStruct942.GetPipePropertiesV3$FUNC, session); - } - static GetPipePropertiesV3 ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2) -> { - try { - return (int)IOUSBInterfaceStruct942.GetPipePropertiesV3$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetPipePropertiesV3$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetPipePropertiesV3")); - public static VarHandle GetPipePropertiesV3$VH() { - return IOUSBInterfaceStruct942.GetPipePropertiesV3$VH; - } - public static MemoryAddress GetPipePropertiesV3$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetPipePropertiesV3$VH.get(seg); - } - public static void GetPipePropertiesV3$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetPipePropertiesV3$VH.set(seg, x); - } - public static MemoryAddress GetPipePropertiesV3$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetPipePropertiesV3$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetPipePropertiesV3$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetPipePropertiesV3$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetPipePropertiesV3 GetPipePropertiesV3 (MemorySegment segment, MemorySession session) { - return GetPipePropertiesV3.ofAddress(GetPipePropertiesV3$get(segment), session); - } - static final FunctionDescriptor GetEndpointPropertiesV3$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetEndpointPropertiesV3$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetEndpointPropertiesV3$FUNC - ); - public interface GetEndpointPropertiesV3 { - - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetEndpointPropertiesV3 fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetEndpointPropertiesV3.class, fi, IOUSBInterfaceStruct942.GetEndpointPropertiesV3$FUNC, session); - } - static GetEndpointPropertiesV3 ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { - try { - return (int)IOUSBInterfaceStruct942.GetEndpointPropertiesV3$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetEndpointPropertiesV3$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetEndpointPropertiesV3")); - public static VarHandle GetEndpointPropertiesV3$VH() { - return IOUSBInterfaceStruct942.GetEndpointPropertiesV3$VH; - } - public static MemoryAddress GetEndpointPropertiesV3$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetEndpointPropertiesV3$VH.get(seg); - } - public static void GetEndpointPropertiesV3$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetEndpointPropertiesV3$VH.set(seg, x); - } - public static MemoryAddress GetEndpointPropertiesV3$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetEndpointPropertiesV3$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetEndpointPropertiesV3$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetEndpointPropertiesV3$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetEndpointPropertiesV3 GetEndpointPropertiesV3 (MemorySegment segment, MemorySession session) { - return GetEndpointPropertiesV3.ofAddress(GetEndpointPropertiesV3$get(segment), session); - } - static final FunctionDescriptor SupportsStreams$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle SupportsStreams$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.SupportsStreams$FUNC - ); - public interface SupportsStreams { - - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(SupportsStreams fi, MemorySession session) { - return RuntimeHelper.upcallStub(SupportsStreams.class, fi, IOUSBInterfaceStruct942.SupportsStreams$FUNC, session); - } - static SupportsStreams ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2) -> { - try { - return (int)IOUSBInterfaceStruct942.SupportsStreams$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle SupportsStreams$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SupportsStreams")); - public static VarHandle SupportsStreams$VH() { - return IOUSBInterfaceStruct942.SupportsStreams$VH; - } - public static MemoryAddress SupportsStreams$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SupportsStreams$VH.get(seg); - } - public static void SupportsStreams$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.SupportsStreams$VH.set(seg, x); - } - public static MemoryAddress SupportsStreams$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SupportsStreams$VH.get(seg.asSlice(index*sizeof())); - } - public static void SupportsStreams$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.SupportsStreams$VH.set(seg.asSlice(index*sizeof()), x); - } - public static SupportsStreams SupportsStreams (MemorySegment segment, MemorySession session) { - return SupportsStreams.ofAddress(SupportsStreams$get(segment), session); - } - static final FunctionDescriptor CreateStreams$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle CreateStreams$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.CreateStreams$FUNC - ); - public interface CreateStreams { - - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, int _x2); - static MemorySegment allocate(CreateStreams fi, MemorySession session) { - return RuntimeHelper.upcallStub(CreateStreams.class, fi, IOUSBInterfaceStruct942.CreateStreams$FUNC, session); - } - static CreateStreams ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, int __x2) -> { - try { - return (int)IOUSBInterfaceStruct942.CreateStreams$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle CreateStreams$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateStreams")); - public static VarHandle CreateStreams$VH() { - return IOUSBInterfaceStruct942.CreateStreams$VH; - } - public static MemoryAddress CreateStreams$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.CreateStreams$VH.get(seg); - } - public static void CreateStreams$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.CreateStreams$VH.set(seg, x); - } - public static MemoryAddress CreateStreams$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.CreateStreams$VH.get(seg.asSlice(index*sizeof())); - } - public static void CreateStreams$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.CreateStreams$VH.set(seg.asSlice(index*sizeof()), x); - } - public static CreateStreams CreateStreams (MemorySegment segment, MemorySession session) { - return CreateStreams.ofAddress(CreateStreams$get(segment), session); - } - static final FunctionDescriptor GetConfiguredStreams$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetConfiguredStreams$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetConfiguredStreams$FUNC - ); - public interface GetConfiguredStreams { - - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(GetConfiguredStreams fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetConfiguredStreams.class, fi, IOUSBInterfaceStruct942.GetConfiguredStreams$FUNC, session); - } - static GetConfiguredStreams ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2) -> { - try { - return (int)IOUSBInterfaceStruct942.GetConfiguredStreams$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetConfiguredStreams$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetConfiguredStreams")); - public static VarHandle GetConfiguredStreams$VH() { - return IOUSBInterfaceStruct942.GetConfiguredStreams$VH; - } - public static MemoryAddress GetConfiguredStreams$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetConfiguredStreams$VH.get(seg); - } - public static void GetConfiguredStreams$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetConfiguredStreams$VH.set(seg, x); - } - public static MemoryAddress GetConfiguredStreams$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetConfiguredStreams$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetConfiguredStreams$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetConfiguredStreams$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetConfiguredStreams GetConfiguredStreams (MemorySegment segment, MemorySession session) { - return GetConfiguredStreams.ofAddress(GetConfiguredStreams$get(segment), session); - } - static final FunctionDescriptor ReadStreamsPipeTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle ReadStreamsPipeTO$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.ReadStreamsPipeTO$FUNC - ); - public interface ReadStreamsPipeTO { - - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, int _x2, java.lang.foreign.MemoryAddress _x3, java.lang.foreign.MemoryAddress _x4, int _x5, int _x6); - static MemorySegment allocate(ReadStreamsPipeTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(ReadStreamsPipeTO.class, fi, IOUSBInterfaceStruct942.ReadStreamsPipeTO$FUNC, session); - } - static ReadStreamsPipeTO ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, int __x2, java.lang.foreign.MemoryAddress __x3, java.lang.foreign.MemoryAddress __x4, int __x5, int __x6) -> { - try { - return (int)IOUSBInterfaceStruct942.ReadStreamsPipeTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4, __x5, __x6); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle ReadStreamsPipeTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadStreamsPipeTO")); - public static VarHandle ReadStreamsPipeTO$VH() { - return IOUSBInterfaceStruct942.ReadStreamsPipeTO$VH; - } - public static MemoryAddress ReadStreamsPipeTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadStreamsPipeTO$VH.get(seg); - } - public static void ReadStreamsPipeTO$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.ReadStreamsPipeTO$VH.set(seg, x); - } - public static MemoryAddress ReadStreamsPipeTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadStreamsPipeTO$VH.get(seg.asSlice(index*sizeof())); - } - public static void ReadStreamsPipeTO$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.ReadStreamsPipeTO$VH.set(seg.asSlice(index*sizeof()), x); - } - public static ReadStreamsPipeTO ReadStreamsPipeTO (MemorySegment segment, MemorySession session) { - return ReadStreamsPipeTO.ofAddress(ReadStreamsPipeTO$get(segment), session); - } - static final FunctionDescriptor WriteStreamsPipeTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle WriteStreamsPipeTO$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.WriteStreamsPipeTO$FUNC - ); - public interface WriteStreamsPipeTO { - - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, int _x2, java.lang.foreign.MemoryAddress _x3, int _x4, int _x5, int _x6); - static MemorySegment allocate(WriteStreamsPipeTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(WriteStreamsPipeTO.class, fi, IOUSBInterfaceStruct942.WriteStreamsPipeTO$FUNC, session); - } - static WriteStreamsPipeTO ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, int __x2, java.lang.foreign.MemoryAddress __x3, int __x4, int __x5, int __x6) -> { - try { - return (int)IOUSBInterfaceStruct942.WriteStreamsPipeTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, (java.lang.foreign.Addressable)__x3, __x4, __x5, __x6); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle WriteStreamsPipeTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WriteStreamsPipeTO")); - public static VarHandle WriteStreamsPipeTO$VH() { - return IOUSBInterfaceStruct942.WriteStreamsPipeTO$VH; - } - public static MemoryAddress WriteStreamsPipeTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WriteStreamsPipeTO$VH.get(seg); - } - public static void WriteStreamsPipeTO$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.WriteStreamsPipeTO$VH.set(seg, x); - } - public static MemoryAddress WriteStreamsPipeTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WriteStreamsPipeTO$VH.get(seg.asSlice(index*sizeof())); - } - public static void WriteStreamsPipeTO$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.WriteStreamsPipeTO$VH.set(seg.asSlice(index*sizeof()), x); - } - public static WriteStreamsPipeTO WriteStreamsPipeTO (MemorySegment segment, MemorySession session) { - return WriteStreamsPipeTO.ofAddress(WriteStreamsPipeTO$get(segment), session); - } - static final FunctionDescriptor ReadStreamsPipeAsyncTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle ReadStreamsPipeAsyncTO$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.ReadStreamsPipeAsyncTO$FUNC - ); - public interface ReadStreamsPipeAsyncTO { - - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, int _x2, java.lang.foreign.MemoryAddress _x3, int _x4, int _x5, int _x6, java.lang.foreign.MemoryAddress _x7, java.lang.foreign.MemoryAddress _x8); - static MemorySegment allocate(ReadStreamsPipeAsyncTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(ReadStreamsPipeAsyncTO.class, fi, IOUSBInterfaceStruct942.ReadStreamsPipeAsyncTO$FUNC, session); - } - static ReadStreamsPipeAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, int __x2, java.lang.foreign.MemoryAddress __x3, int __x4, int __x5, int __x6, java.lang.foreign.MemoryAddress __x7, java.lang.foreign.MemoryAddress __x8) -> { - try { - return (int)IOUSBInterfaceStruct942.ReadStreamsPipeAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, (java.lang.foreign.Addressable)__x3, __x4, __x5, __x6, (java.lang.foreign.Addressable)__x7, (java.lang.foreign.Addressable)__x8); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle ReadStreamsPipeAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadStreamsPipeAsyncTO")); - public static VarHandle ReadStreamsPipeAsyncTO$VH() { - return IOUSBInterfaceStruct942.ReadStreamsPipeAsyncTO$VH; - } - public static MemoryAddress ReadStreamsPipeAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadStreamsPipeAsyncTO$VH.get(seg); - } - public static void ReadStreamsPipeAsyncTO$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.ReadStreamsPipeAsyncTO$VH.set(seg, x); - } - public static MemoryAddress ReadStreamsPipeAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.ReadStreamsPipeAsyncTO$VH.get(seg.asSlice(index*sizeof())); - } - public static void ReadStreamsPipeAsyncTO$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.ReadStreamsPipeAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); - } - public static ReadStreamsPipeAsyncTO ReadStreamsPipeAsyncTO (MemorySegment segment, MemorySession session) { - return ReadStreamsPipeAsyncTO.ofAddress(ReadStreamsPipeAsyncTO$get(segment), session); - } - static final FunctionDescriptor WriteStreamsPipeAsyncTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle WriteStreamsPipeAsyncTO$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.WriteStreamsPipeAsyncTO$FUNC - ); - public interface WriteStreamsPipeAsyncTO { - - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, int _x2, java.lang.foreign.MemoryAddress _x3, int _x4, int _x5, int _x6, java.lang.foreign.MemoryAddress _x7, java.lang.foreign.MemoryAddress _x8); - static MemorySegment allocate(WriteStreamsPipeAsyncTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(WriteStreamsPipeAsyncTO.class, fi, IOUSBInterfaceStruct942.WriteStreamsPipeAsyncTO$FUNC, session); - } - static WriteStreamsPipeAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, int __x2, java.lang.foreign.MemoryAddress __x3, int __x4, int __x5, int __x6, java.lang.foreign.MemoryAddress __x7, java.lang.foreign.MemoryAddress __x8) -> { - try { - return (int)IOUSBInterfaceStruct942.WriteStreamsPipeAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, (java.lang.foreign.Addressable)__x3, __x4, __x5, __x6, (java.lang.foreign.Addressable)__x7, (java.lang.foreign.Addressable)__x8); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle WriteStreamsPipeAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WriteStreamsPipeAsyncTO")); - public static VarHandle WriteStreamsPipeAsyncTO$VH() { - return IOUSBInterfaceStruct942.WriteStreamsPipeAsyncTO$VH; - } - public static MemoryAddress WriteStreamsPipeAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WriteStreamsPipeAsyncTO$VH.get(seg); - } - public static void WriteStreamsPipeAsyncTO$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.WriteStreamsPipeAsyncTO$VH.set(seg, x); - } - public static MemoryAddress WriteStreamsPipeAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.WriteStreamsPipeAsyncTO$VH.get(seg.asSlice(index*sizeof())); - } - public static void WriteStreamsPipeAsyncTO$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.WriteStreamsPipeAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); - } - public static WriteStreamsPipeAsyncTO WriteStreamsPipeAsyncTO (MemorySegment segment, MemorySession session) { - return WriteStreamsPipeAsyncTO.ofAddress(WriteStreamsPipeAsyncTO$get(segment), session); - } - static final FunctionDescriptor AbortStreamsPipe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle AbortStreamsPipe$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.AbortStreamsPipe$FUNC - ); - public interface AbortStreamsPipe { - - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, int _x2); - static MemorySegment allocate(AbortStreamsPipe fi, MemorySession session) { - return RuntimeHelper.upcallStub(AbortStreamsPipe.class, fi, IOUSBInterfaceStruct942.AbortStreamsPipe$FUNC, session); - } - static AbortStreamsPipe ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, int __x2) -> { - try { - return (int)IOUSBInterfaceStruct942.AbortStreamsPipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle AbortStreamsPipe$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AbortStreamsPipe")); - public static VarHandle AbortStreamsPipe$VH() { - return IOUSBInterfaceStruct942.AbortStreamsPipe$VH; - } - public static MemoryAddress AbortStreamsPipe$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.AbortStreamsPipe$VH.get(seg); - } - public static void AbortStreamsPipe$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.AbortStreamsPipe$VH.set(seg, x); - } - public static MemoryAddress AbortStreamsPipe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.AbortStreamsPipe$VH.get(seg.asSlice(index*sizeof())); - } - public static void AbortStreamsPipe$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.AbortStreamsPipe$VH.set(seg.asSlice(index*sizeof()), x); - } - public static AbortStreamsPipe AbortStreamsPipe (MemorySegment segment, MemorySession session) { - return AbortStreamsPipe.ofAddress(AbortStreamsPipe$get(segment), session); - } - static final FunctionDescriptor RegisterForNotification$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle RegisterForNotification$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.RegisterForNotification$FUNC - ); - public interface RegisterForNotification { - - int apply(java.lang.foreign.MemoryAddress _x0, long _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, java.lang.foreign.MemoryAddress _x4); - static MemorySegment allocate(RegisterForNotification fi, MemorySession session) { - return RuntimeHelper.upcallStub(RegisterForNotification.class, fi, IOUSBInterfaceStruct942.RegisterForNotification$FUNC, session); - } - static RegisterForNotification ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, long __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, java.lang.foreign.MemoryAddress __x4) -> { - try { - return (int)IOUSBInterfaceStruct942.RegisterForNotification$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle RegisterForNotification$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("RegisterForNotification")); - public static VarHandle RegisterForNotification$VH() { - return IOUSBInterfaceStruct942.RegisterForNotification$VH; - } - public static MemoryAddress RegisterForNotification$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.RegisterForNotification$VH.get(seg); - } - public static void RegisterForNotification$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.RegisterForNotification$VH.set(seg, x); - } - public static MemoryAddress RegisterForNotification$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.RegisterForNotification$VH.get(seg.asSlice(index*sizeof())); - } - public static void RegisterForNotification$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.RegisterForNotification$VH.set(seg.asSlice(index*sizeof()), x); - } - public static RegisterForNotification RegisterForNotification (MemorySegment segment, MemorySession session) { - return RegisterForNotification.ofAddress(RegisterForNotification$get(segment), session); - } - static final FunctionDescriptor UnregisterNotification$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle UnregisterNotification$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.UnregisterNotification$FUNC - ); - public interface UnregisterNotification { - - int apply(java.lang.foreign.MemoryAddress _x0, long _x1); - static MemorySegment allocate(UnregisterNotification fi, MemorySession session) { - return RuntimeHelper.upcallStub(UnregisterNotification.class, fi, IOUSBInterfaceStruct942.UnregisterNotification$FUNC, session); - } - static UnregisterNotification ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, long __x1) -> { - try { - return (int)IOUSBInterfaceStruct942.UnregisterNotification$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle UnregisterNotification$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("UnregisterNotification")); - public static VarHandle UnregisterNotification$VH() { - return IOUSBInterfaceStruct942.UnregisterNotification$VH; - } - public static MemoryAddress UnregisterNotification$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.UnregisterNotification$VH.get(seg); - } - public static void UnregisterNotification$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.UnregisterNotification$VH.set(seg, x); - } - public static MemoryAddress UnregisterNotification$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.UnregisterNotification$VH.get(seg.asSlice(index*sizeof())); - } - public static void UnregisterNotification$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.UnregisterNotification$VH.set(seg.asSlice(index*sizeof()), x); - } - public static UnregisterNotification UnregisterNotification (MemorySegment segment, MemorySession session) { - return UnregisterNotification.ofAddress(UnregisterNotification$get(segment), session); - } - static final FunctionDescriptor AcknowledgeNotification$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle AcknowledgeNotification$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.AcknowledgeNotification$FUNC - ); - public interface AcknowledgeNotification { - - int apply(java.lang.foreign.MemoryAddress _x0, long _x1); - static MemorySegment allocate(AcknowledgeNotification fi, MemorySession session) { - return RuntimeHelper.upcallStub(AcknowledgeNotification.class, fi, IOUSBInterfaceStruct942.AcknowledgeNotification$FUNC, session); - } - static AcknowledgeNotification ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, long __x1) -> { - try { - return (int)IOUSBInterfaceStruct942.AcknowledgeNotification$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle AcknowledgeNotification$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AcknowledgeNotification")); - public static VarHandle AcknowledgeNotification$VH() { - return IOUSBInterfaceStruct942.AcknowledgeNotification$VH; - } - public static MemoryAddress AcknowledgeNotification$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.AcknowledgeNotification$VH.get(seg); - } - public static void AcknowledgeNotification$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.AcknowledgeNotification$VH.set(seg, x); - } - public static MemoryAddress AcknowledgeNotification$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.AcknowledgeNotification$VH.get(seg.asSlice(index*sizeof())); - } - public static void AcknowledgeNotification$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.AcknowledgeNotification$VH.set(seg.asSlice(index*sizeof()), x); - } - public static AcknowledgeNotification AcknowledgeNotification (MemorySegment segment, MemorySession session) { - return AcknowledgeNotification.ofAddress(AcknowledgeNotification$get(segment), session); - } - static final FunctionDescriptor RegisterDriver$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle RegisterDriver$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.RegisterDriver$FUNC - ); - public interface RegisterDriver { - - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(RegisterDriver fi, MemorySession session) { - return RuntimeHelper.upcallStub(RegisterDriver.class, fi, IOUSBInterfaceStruct942.RegisterDriver$FUNC, session); - } - static RegisterDriver ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { - try { - return (int)IOUSBInterfaceStruct942.RegisterDriver$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle RegisterDriver$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("RegisterDriver")); - public static VarHandle RegisterDriver$VH() { - return IOUSBInterfaceStruct942.RegisterDriver$VH; - } - public static MemoryAddress RegisterDriver$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.RegisterDriver$VH.get(seg); - } - public static void RegisterDriver$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.RegisterDriver$VH.set(seg, x); - } - public static MemoryAddress RegisterDriver$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.RegisterDriver$VH.get(seg.asSlice(index*sizeof())); - } - public static void RegisterDriver$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.RegisterDriver$VH.set(seg.asSlice(index*sizeof()), x); - } - public static RegisterDriver RegisterDriver (MemorySegment segment, MemorySession session) { - return RegisterDriver.ofAddress(RegisterDriver$get(segment), session); - } - static final FunctionDescriptor SetDeviceIdlePolicy$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle SetDeviceIdlePolicy$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.SetDeviceIdlePolicy$FUNC - ); - public interface SetDeviceIdlePolicy { - - int apply(java.lang.foreign.MemoryAddress _x0, int _x1); - static MemorySegment allocate(SetDeviceIdlePolicy fi, MemorySession session) { - return RuntimeHelper.upcallStub(SetDeviceIdlePolicy.class, fi, IOUSBInterfaceStruct942.SetDeviceIdlePolicy$FUNC, session); - } - static SetDeviceIdlePolicy ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, int __x1) -> { - try { - return (int)IOUSBInterfaceStruct942.SetDeviceIdlePolicy$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle SetDeviceIdlePolicy$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetDeviceIdlePolicy")); - public static VarHandle SetDeviceIdlePolicy$VH() { - return IOUSBInterfaceStruct942.SetDeviceIdlePolicy$VH; - } - public static MemoryAddress SetDeviceIdlePolicy$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SetDeviceIdlePolicy$VH.get(seg); - } - public static void SetDeviceIdlePolicy$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.SetDeviceIdlePolicy$VH.set(seg, x); - } - public static MemoryAddress SetDeviceIdlePolicy$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SetDeviceIdlePolicy$VH.get(seg.asSlice(index*sizeof())); - } - public static void SetDeviceIdlePolicy$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.SetDeviceIdlePolicy$VH.set(seg.asSlice(index*sizeof()), x); - } - public static SetDeviceIdlePolicy SetDeviceIdlePolicy (MemorySegment segment, MemorySession session) { - return SetDeviceIdlePolicy.ofAddress(SetDeviceIdlePolicy$get(segment), session); - } - static final FunctionDescriptor SetPipeIdlePolicy$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle SetPipeIdlePolicy$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.SetPipeIdlePolicy$FUNC - ); - public interface SetPipeIdlePolicy { - - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, int _x2); - static MemorySegment allocate(SetPipeIdlePolicy fi, MemorySession session) { - return RuntimeHelper.upcallStub(SetPipeIdlePolicy.class, fi, IOUSBInterfaceStruct942.SetPipeIdlePolicy$FUNC, session); - } - static SetPipeIdlePolicy ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, int __x2) -> { - try { - return (int)IOUSBInterfaceStruct942.SetPipeIdlePolicy$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle SetPipeIdlePolicy$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetPipeIdlePolicy")); - public static VarHandle SetPipeIdlePolicy$VH() { - return IOUSBInterfaceStruct942.SetPipeIdlePolicy$VH; - } - public static MemoryAddress SetPipeIdlePolicy$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SetPipeIdlePolicy$VH.get(seg); - } - public static void SetPipeIdlePolicy$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.SetPipeIdlePolicy$VH.set(seg, x); - } - public static MemoryAddress SetPipeIdlePolicy$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.SetPipeIdlePolicy$VH.get(seg.asSlice(index*sizeof())); - } - public static void SetPipeIdlePolicy$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.SetPipeIdlePolicy$VH.set(seg.asSlice(index*sizeof()), x); - } - public static SetPipeIdlePolicy SetPipeIdlePolicy (MemorySegment segment, MemorySession session) { - return SetPipeIdlePolicy.ofAddress(SetPipeIdlePolicy$get(segment), session); - } - static final FunctionDescriptor GetInterfaceAsyncNotificationPort$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetInterfaceAsyncNotificationPort$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct942.GetInterfaceAsyncNotificationPort$FUNC - ); - public interface GetInterfaceAsyncNotificationPort { - - java.lang.foreign.Addressable apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(GetInterfaceAsyncNotificationPort fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetInterfaceAsyncNotificationPort.class, fi, IOUSBInterfaceStruct942.GetInterfaceAsyncNotificationPort$FUNC, session); - } - static GetInterfaceAsyncNotificationPort ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { - try { - return (java.lang.foreign.Addressable)(java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceAsyncNotificationPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } - } - - static final VarHandle GetInterfaceAsyncNotificationPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceAsyncNotificationPort")); - public static VarHandle GetInterfaceAsyncNotificationPort$VH() { - return IOUSBInterfaceStruct942.GetInterfaceAsyncNotificationPort$VH; - } - public static MemoryAddress GetInterfaceAsyncNotificationPort$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceAsyncNotificationPort$VH.get(seg); - } - public static void GetInterfaceAsyncNotificationPort$set( MemorySegment seg, MemoryAddress x) { - IOUSBInterfaceStruct942.GetInterfaceAsyncNotificationPort$VH.set(seg, x); - } - public static MemoryAddress GetInterfaceAsyncNotificationPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct942.GetInterfaceAsyncNotificationPort$VH.get(seg.asSlice(index*sizeof())); - } - public static void GetInterfaceAsyncNotificationPort$set(MemorySegment seg, long index, MemoryAddress x) { - IOUSBInterfaceStruct942.GetInterfaceAsyncNotificationPort$VH.set(seg.asSlice(index*sizeof()), x); - } - public static GetInterfaceAsyncNotificationPort GetInterfaceAsyncNotificationPort (MemorySegment segment, MemorySession session) { - return GetInterfaceAsyncNotificationPort.ofAddress(GetInterfaceAsyncNotificationPort$get(segment), session); - } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { From 8240c2f955ab9642c980f8512b55da4d46db59af Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 24 Oct 2022 18:19:38 +0200 Subject: [PATCH 144/433] Simplify code (Linux) --- .../main/java/net/codecrete/usb/linux/Linux.java | 16 ---------------- .../usb/linux/LinuxUSBDeviceRegistry.java | 4 ++-- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java index 8c6723f6..a3036fbc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java @@ -20,22 +20,6 @@ */ public class Linux { - /** - * Creates a Java string as a copy of the null-terminated UTF-8 string. - * - * @param str the memory address pointing to string - * @return the Java string, or {@code null} if the memory address is 0 - */ - public static String createStringFromAddress(MemoryAddress str) { - try (var session = MemorySession.openConfined()) { - if (str == NULL) - return null; - - var ret = MemorySegment.ofAddress(str, 2000, session); - return ret.getUtf8String(0); - } - } - /** * Gets the error message for the specified error code (returned by {@code errno}). * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index c242b181..6837fa34 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -218,11 +218,11 @@ private static String getDeviceAttribute(Addressable udevDevice, String attribut } private static String getDeviceName(Addressable udevDevice) { - return Linux.createStringFromAddress(udev.udev_device_get_devnode(udevDevice)); + return udev.udev_device_get_devnode(udevDevice).getUtf8String(0); } private static String getDeviceAction(Addressable udevDevice) { - return Linux.createStringFromAddress(udev.udev_device_get_action(udevDevice)); + return udev.udev_device_get_action(udevDevice).getUtf8String(0); } /** From ad44fe2544fb37e4ab5bbe4343c9d9efb30990da Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 25 Oct 2022 15:56:20 +0200 Subject: [PATCH 145/433] Windows reference code: fetch product names --- reference/windows/USB/usb_device.cpp | 7 +++ reference/windows/USB/usb_device.hpp | 1 + reference/windows/USB/usb_registry.cpp | 66 +++++++++++++++++++++++++- reference/windows/USB/usb_registry.hpp | 3 ++ 4 files changed, 76 insertions(+), 1 deletion(-) diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp index 78e007d6..9f322573 100644 --- a/reference/windows/USB/usb_device.cpp +++ b/reference/windows/USB/usb_device.cpp @@ -22,6 +22,13 @@ usb_device::usb_device(const std::wstring& device_path, int vendor_id, int produ //serial_number_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBSerialNumberString)); } +void usb_device::set_product_names(const std::string& manufacturer, const std::string& product, const std::string& serial_number) { + manufacturer_ = manufacturer; + product_ = product; + serial_number_ = serial_number; +} + + usb_device::~usb_device() { close(); } diff --git a/reference/windows/USB/usb_device.hpp b/reference/windows/USB/usb_device.hpp index bc5c9efa..81ac6c3d 100644 --- a/reference/windows/USB/usb_device.hpp +++ b/reference/windows/USB/usb_device.hpp @@ -192,6 +192,7 @@ class usb_device { private: usb_device(const std::wstring& device_path, int vendor_id, int product_id); + void set_product_names(const std::string& manufacturer, const std::string& product, const std::string& serial_number); int control_transfer_core(const usb_control_request& request, uint8_t* data, int timeout); const wchar_t* device_path() { return device_path_.c_str(); } diff --git a/reference/windows/USB/usb_registry.cpp b/reference/windows/USB/usb_registry.cpp index c508e59f..c19deb16 100644 --- a/reference/windows/USB/usb_registry.cpp +++ b/reference/windows/USB/usb_registry.cpp @@ -174,6 +174,11 @@ std::shared_ptr usb_registry::create_device(HDEVINFO dev_info_set_hd // Create new device std::shared_ptr device(new usb_device(path, conn_info.DeviceDescriptor.idVendor, conn_info.DeviceDescriptor.idProduct)); + device->set_product_names( + get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iManufacturer), + get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iProduct), + get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iSerialNumber) + ); return device; } @@ -355,4 +360,63 @@ std::wstring usb_registry::get_device_path(const std::wstring& instance_id, cons throw usb_error("Internal error (SetupDiGetDeviceInterfaceDetailA)", GetLastError()); return intf_detail_data->DevicePath; -} \ No newline at end of file +} + +std::vector usb_registry::get_descriptor(HANDLE hub_handle, ULONG usb_port_num, uint16_t descriptor_type, int index, int language_id, int request_size) { + int size = sizeof(USB_DESCRIPTOR_REQUEST) + (request_size != 0 ? request_size : 256); + uint8_t* descriptor_request_buffer = new uint8_t[size]; + auto dev_info_set_guard = make_scope_exit([descriptor_request_buffer]() { + delete [] descriptor_request_buffer; + }); + + // setup request data structure + USB_DESCRIPTOR_REQUEST* descriptor_request = reinterpret_cast(descriptor_request_buffer); + descriptor_request->ConnectionIndex = usb_port_num; + descriptor_request->SetupPacket.bmRequest = 0x80; // device-to-host / type standard / recipient device + descriptor_request->SetupPacket.bRequest = 0x06; // GET_DESCRIPTOR + descriptor_request->SetupPacket.wValue = (descriptor_type << 8) | index; + descriptor_request->SetupPacket.wIndex = language_id; + descriptor_request->SetupPacket.wLength = static_cast(size - sizeof(USB_DESCRIPTOR_REQUEST)); + + // get descriptor + DWORD bytesReturned = 0; + if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, descriptor_request, size, descriptor_request, size, &bytesReturned, nullptr)) + throw usb_error("Cannot retrieve descriptor (DeviceIoControl)", GetLastError()); + + // determine expected size of descriptor + int expected_size; + if (descriptor_type != USB_CONFIGURATION_DESCRIPTOR_TYPE) { + expected_size = descriptor_request->Data[0]; + } else { + expected_size = *reinterpret_cast(descriptor_request->Data); + } + + // check against effective size + int effective_size = bytesReturned - sizeof(USB_DESCRIPTOR_REQUEST); + if (effective_size != expected_size) { + if (request_size != 0) + throw usb_error("Unexpected descriptor size"); + + // repeat with correct size + return get_descriptor(hub_handle, usb_port_num, descriptor_type, index, language_id, expected_size); + } + + return std::vector(descriptor_request->Data, descriptor_request->Data + effective_size); +} + +std::string usb_registry::get_string(HANDLE hub_handle, ULONG usb_port_num, int index) { + if (index == 0) + return ""; + + std::vector str_desc_raw = get_descriptor(hub_handle, usb_port_num, USB_STRING_DESCRIPTOR_TYPE, index, 0x0409); + USB_STRING_DESCRIPTOR* str_desc = reinterpret_cast(str_desc_raw.data()); + + // required length of UTF-8 string + int len = WideCharToMultiByte(CP_UTF8, 0, str_desc->bString, str_desc->bLength / 2 - 1, nullptr, 0, nullptr, nullptr); + + // conver to UTF-8 + std::string result; + result.resize(len, 'x'); + WideCharToMultiByte(CP_UTF8, 0, str_desc->bString, str_desc->bLength / 2 - 1, &result[0], len, nullptr, nullptr); + return result; +} diff --git a/reference/windows/USB/usb_registry.hpp b/reference/windows/USB/usb_registry.hpp index 5b2d967f..554943ec 100644 --- a/reference/windows/USB/usb_registry.hpp +++ b/reference/windows/USB/usb_registry.hpp @@ -61,6 +61,9 @@ class usb_registry { static std::wstring get_device_property_string(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key); static std::wstring get_device_path(const std::wstring& instance_id, const GUID* interface_guid); + static std::vector get_descriptor(HANDLE hub_handle, ULONG usb_port_num, uint16_t descriptor_type, int index, int language_id, int request_size = 0); + static std::string get_string(HANDLE hub_handle, ULONG usb_port_num, int index); + std::vector devices; std::function on_connected_callback; From 4433899d0c1f73013b82ecde9d5ab174b7ae08b4 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 28 Oct 2022 06:38:29 +0200 Subject: [PATCH 146/433] Enhanced Windows reference code --- .../usb/common/ConfigurationParser.java | 5 +- .../usb/windows/WindowsUSBDevice.java | 17 +- reference/windows/USB/USB.vcxproj | 8 + reference/windows/USB/USB.vcxproj.filters | 18 ++ reference/windows/USB/assertion.cpp | 2 +- reference/windows/USB/assertion.hpp | 2 +- reference/windows/USB/config_parser.cpp | 194 +++++++++++++ reference/windows/USB/config_parser.hpp | 31 ++ reference/windows/USB/configuration.cpp | 50 ++++ reference/windows/USB/configuration.hpp | 148 ++++++++++ reference/windows/USB/main.cpp | 2 +- reference/windows/USB/scope.hpp | 2 +- reference/windows/USB/tests.cpp | 4 +- reference/windows/USB/tests.hpp | 2 +- reference/windows/USB/usb_device.cpp | 268 ++++++++++++++---- reference/windows/USB/usb_device.hpp | 52 +++- reference/windows/USB/usb_device_info.cpp | 216 ++++++++++++++ reference/windows/USB/usb_device_info.hpp | 146 ++++++++++ reference/windows/USB/usb_error.cpp | 2 +- reference/windows/USB/usb_error.hpp | 2 +- reference/windows/USB/usb_registry.cpp | 204 +++++-------- reference/windows/USB/usb_registry.hpp | 11 +- 22 files changed, 1157 insertions(+), 229 deletions(-) create mode 100644 reference/windows/USB/config_parser.cpp create mode 100644 reference/windows/USB/config_parser.hpp create mode 100644 reference/windows/USB/configuration.cpp create mode 100644 reference/windows/USB/configuration.hpp create mode 100644 reference/windows/USB/usb_device_info.cpp create mode 100644 reference/windows/USB/usb_device_info.hpp diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java index a73e6082..6d3433c2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java @@ -54,7 +54,6 @@ public Configuration parse() { parseHeader(); USBAlternateInterfaceImpl lastAlternate = null; - USBEndpointImpl lastEndpoint; int offset = peekDescLength(0); while (offset < descriptor.byteSize()) { @@ -81,9 +80,9 @@ public Configuration parse() { } } else if (descType == ENDPOINT_DESCRIPTOR_TYPE) { - lastEndpoint = parseEndpoint(offset); + var endpoint = parseEndpoint(offset); if (lastAlternate != null) - lastAlternate.addEndpoint(lastEndpoint); + lastAlternate.addEndpoint(endpoint); } else if (descType == INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE) { parseIAD(offset); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index c7d2cc62..51f7123b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -49,21 +49,14 @@ private void readDescription(MemorySegment configDesc, String devicePath, Map + + + + + + @@ -60,6 +66,7 @@ true v143 Unicode + false Application @@ -120,6 +127,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true + EnableFastChecks Console diff --git a/reference/windows/USB/USB.vcxproj.filters b/reference/windows/USB/USB.vcxproj.filters index ffebc144..289ec490 100644 --- a/reference/windows/USB/USB.vcxproj.filters +++ b/reference/windows/USB/USB.vcxproj.filters @@ -33,6 +33,15 @@ Source Files + + Source Files + + + Source Files + + + Source Files + @@ -53,5 +62,14 @@ Header Files + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file diff --git a/reference/windows/USB/assertion.cpp b/reference/windows/USB/assertion.cpp index 2a60687a..4ffa1205 100644 --- a/reference/windows/USB/assertion.cpp +++ b/reference/windows/USB/assertion.cpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Windows // #include "assertion.hpp" diff --git a/reference/windows/USB/assertion.hpp b/reference/windows/USB/assertion.hpp index 4c458fd3..2e6f709c 100644 --- a/reference/windows/USB/assertion.hpp +++ b/reference/windows/USB/assertion.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Windows // #pragma once diff --git a/reference/windows/USB/config_parser.cpp b/reference/windows/USB/config_parser.cpp new file mode 100644 index 00000000..a7276978 --- /dev/null +++ b/reference/windows/USB/config_parser.cpp @@ -0,0 +1,194 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for Windows +// + +#include "config_parser.hpp" +#include "usb_error.hpp" + + +// --- USB descriptor types + +enum class usb_descriptor_type : uint8_t { + configuration = 0x02, + string = 0x03, + interface = 0x04, + endpoint = 0x05, + interface_association = 0x0b +}; + + +// --- USB configuration descriptor + +#pragma pack(push, 1) + +struct usb_config_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; +}; + +#pragma pack(pop) + + +// --- USB interface descriptor + +#pragma pack(push, 1) + +struct usb_interface_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +}; + +#pragma pack(pop) + + +// --- USB interface association descriptor + +#pragma pack(push, 1) + +struct usb_interface_association_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bFirstInterface; + uint8_t bInterfaceCount; + uint8_t bFunctionClass; + uint8_t bFunctionSubClass; + uint8_t bFunctionProtocol; + uint8_t iFunction; +}; + +#pragma pack(pop) + + +// --- USB endpoint descriptor + +#pragma pack(push, 1) + + struct usb_endpoint_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; + }; + +#pragma pack(pop) + + +// --- Configuration parser + + static int peek_desc_length(const uint8_t* desc, int offset) { return desc[offset]; } + static usb_descriptor_type peek_desc_type(const uint8_t* desc, int offset) { return static_cast(desc[offset + 1]); } + + + config_parser::config_parser() + : configuration_value(0) { } + +void config_parser::parse(const std::vector& config_desc) +{ + const uint8_t* desc = &config_desc[0]; + int desc_len = static_cast(config_desc.size()); + + const usb_config_desc* header = reinterpret_cast(desc); + if (desc_len <= sizeof(usb_config_desc) + || header->bDescriptorType != static_cast(usb_descriptor_type::configuration) + || header->wTotalLength != desc_len) + throw usb_error("Invalid configuration descriptor"); + + configuration_value = header->bConfigurationValue; + + int offset = peek_desc_length(desc, 0); + usb_alternate_interface* last_alternate = nullptr; + + while (offset + 2 < desc_len) { + + int len = peek_desc_length(desc, offset); + usb_descriptor_type type = peek_desc_type(desc, offset); + + if (offset + len > desc_len) + break; + + if (type == usb_descriptor_type::interface_association) { + + const usb_interface_association_desc* ia_desc = reinterpret_cast(desc + offset); + functions.push_back(usb_composite_function(ia_desc->bFirstInterface, ia_desc->bInterfaceCount, + ia_desc->bFunctionClass, ia_desc->bFunctionSubClass, ia_desc->bFunctionProtocol)); + last_alternate = nullptr; + + } else if (type == usb_descriptor_type::interface) { + + const usb_interface_desc* intf_desc = reinterpret_cast(desc + offset); + int number = intf_desc->bInterfaceNumber; + + // If there is no interface with this number yet, it's a new interface + // and not just an additional alternate interface. + auto intf = get_interface(number); + if (intf == nullptr) { + interfaces.push_back(usb_interface(number)); + intf = &interfaces.back(); + } + + // add alternate interface + last_alternate = intf->add_alternate(usb_alternate_interface(intf_desc->bAlternateSetting, + intf_desc->bInterfaceClass, intf_desc->bInterfaceSubClass, intf_desc->bInterfaceProtocol)); + + // If there is no function for this interface, there was not preceeding IAD. + // So create a new function with a single interface. + if (get_function(intf->number()) == nullptr) + functions.push_back(usb_composite_function(intf->number(), 1, last_alternate->class_code(), last_alternate->subclass_code(), last_alternate->protocol_code())); + + } else if (type == usb_descriptor_type::endpoint) { + + if (last_alternate == nullptr) + throw usb_error("invalid configuration descriptor"); + + const usb_endpoint_desc* ep_desc = reinterpret_cast(desc + offset); + last_alternate->add_endpoint(usb_endpoint(ep_desc->bEndpointAddress & 0x7f, static_cast(ep_desc->bEndpointAddress & 0x80), + static_cast(ep_desc->bmAttributes & 0x03), ep_desc->wMaxPacketSize)); + } + + offset += len; + } + + if (offset != desc_len) + throw usb_error("invalid configuration descriptor"); + + desc = nullptr; + desc_len = 0; +} + +usb_interface* config_parser::get_interface(int number) { + auto iter = std::find_if(interfaces.begin(), interfaces.end(), [number](const usb_interface& itf) { return itf.number() == number; }); + if (iter == interfaces.end()) + return nullptr; + + return &*iter; +} + +usb_composite_function* config_parser::get_function(int intf_number) { + auto iter = std::find_if(functions.begin(), functions.end(), [intf_number](const usb_composite_function& f) { + return intf_number >= f.first_interface() && intf_number < f.first_interface() + f.num_interfaces(); + }); + if (iter == functions.end()) + return nullptr; + + return &*iter; +} diff --git a/reference/windows/USB/config_parser.hpp b/reference/windows/USB/config_parser.hpp new file mode 100644 index 00000000..438ee657 --- /dev/null +++ b/reference/windows/USB/config_parser.hpp @@ -0,0 +1,31 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for Windows +// + +#pragma once + +#include +#include "configuration.hpp" + +///

+/// Parses a USB configuration descriptor. +/// +class config_parser { +public: + config_parser(); + void parse(const std::vector& config_desc); + + uint8_t configuration_value; + + std::vector interfaces; + std::vector functions; + +private: + usb_interface* get_interface(int number); + usb_composite_function* get_function(int intf_number); +}; diff --git a/reference/windows/USB/configuration.cpp b/reference/windows/USB/configuration.cpp new file mode 100644 index 00000000..a0f2fe75 --- /dev/null +++ b/reference/windows/USB/configuration.cpp @@ -0,0 +1,50 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for Windows +// + +#include "configuration.hpp" + +// --- usb_endpoint + +usb_endpoint::usb_endpoint(int number, usb_direction direction, usb_transfer_type transfer_type, int packet_size) + : number_(number), direction_(direction), transfer_type_(transfer_type), packet_size_(packet_size) { } + + +// --- usb_alternate_interface + +usb_alternate_interface::usb_alternate_interface(int number, int class_code, int subclass_code, int protocol_code) + : number_(number), class_code_(class_code), subclass_code_(subclass_code), protocol_code_(protocol_code) { } + +void usb_alternate_interface::add_endpoint(usb_endpoint&& endpoint) { + endpoints_.push_back(std::move(endpoint)); +} + + +// --- usb_interface + +usb_interface::usb_interface(int number) + : number_(number), is_claimed_(false), alternate_index_(0) { } + +void usb_interface::set_claimed(bool claimed) { + is_claimed_ = claimed; +} + +usb_alternate_interface* usb_interface::add_alternate(usb_alternate_interface&& alternate) { + alternates_.push_back(std::move(alternate)); + return &alternates_.back(); +} + +void usb_interface::set_alternate(int index) { + alternate_index_ = index; +} + + +// --- usb_composite_function + +usb_composite_function::usb_composite_function(int first_interface, int num_interfaces, int class_code, int subclass_code, int protocol_code) + : first_interface_(first_interface), num_interfaces_(num_interfaces), class_code_(class_code), subclass_code_(subclass_code), protocol_code_(protocol_code) { } diff --git a/reference/windows/USB/configuration.hpp b/reference/windows/USB/configuration.hpp new file mode 100644 index 00000000..b36f1421 --- /dev/null +++ b/reference/windows/USB/configuration.hpp @@ -0,0 +1,148 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for Windows +// + +#pragma once + +#include +#include + +/// USB endpoint direction +enum class usb_direction : uint8_t { + /// Direction OUT: host to device + out = 0x00, + /// Direction IN: device to host + in = 0x80 +}; + +/// USB endpoint transfer type +enum class usb_transfer_type : uint8_t { + /// Control transfer + control = 0x00, + /// Isochronous transfer + isochronous = 0x01, + /// Bulk transfer + bulk = 0x02, + /// Interrupt transfer + interrupt = 0x03 +}; + +/// +/// USB endpoint +/// +struct usb_endpoint { +public: + /// Endpoint number + int number() const { return number_; } + /// Endpoint direction + usb_direction direction() const { return direction_; } + /// Endpoint transfer type + usb_transfer_type transfer_type() const { return transfer_type_; } + /// Maximum packet size + int packet_size() const { return packet_size_; } + +private: + usb_endpoint(int number, usb_direction direction, usb_transfer_type transfer_type, int packet_size); + + int number_; + usb_direction direction_; + usb_transfer_type transfer_type_; + int packet_size_; + + friend class config_parser; +}; + +/// +/// USB alternate interface +/// +struct usb_alternate_interface { +public: + /// Alternate number + int number() const { return number_; } + /// Interface class code + int class_code() const { return class_code_; } + /// Interface subclass code + int subclass_code() const { return subclass_code_; } + /// Interface protocol code + int protocol_code() const { return protocol_code_; } + /// List of endpoints + const std::vector& endpoints() const { return endpoints_; } + +private: + usb_alternate_interface(int number, int class_code, int subclass_code, int protocol_code); + void add_endpoint(usb_endpoint&& endpoint); + + int number_; + int class_code_; + int subclass_code_; + int protocol_code_; + std::vector endpoints_; + + friend class config_parser; +}; + +/// +/// USB interface +/// +struct usb_interface { +public: + /// Interface number + int number() const { return number_; } + /// Indicates if interface has been claimed + bool is_claimed() const { return is_claimed_; } + /// Currently selected alternate interface + const usb_alternate_interface& alternate() const { return alternates_[alternate_index_]; } + /// List of all alternate interfaces of this interfaces + const std::vector& alternates() const { return alternates_; } + +private: + usb_interface(int number); + void set_claimed(bool claimed); + usb_alternate_interface* add_alternate(usb_alternate_interface&& alternate); + void set_alternate(int index); + + int number_; + bool is_claimed_; + int alternate_index_; + std::vector alternates_; + + friend class config_parser; + friend class usb_device; +}; + +/// +/// USB composite function +/// +/// For a composite USB device, the composite function describes a single function. +/// A compsite function consists of a single or multiple consecutive interfaces. +/// +/// +struct usb_composite_function { +public: + /// Number of first interface + int first_interface() const { return first_interface_; } + /// Number of interfaces + int num_interfaces() const { return num_interfaces_; } + /// Function class code + int class_code() const { return class_code_; } + /// Function subclass code + int subclass_code() const { return subclass_code_; } + /// Function protocol code + int protocol_code() const { return protocol_code_; } + +private: + usb_composite_function(int first_interface, int num_interfaces, int class_code, int subclass_code, int protocol_code); + + int first_interface_; + int num_interfaces_; + int class_code_; + int subclass_code_; + int protocol_code_; + + friend class config_parser; +}; \ No newline at end of file diff --git a/reference/windows/USB/main.cpp b/reference/windows/USB/main.cpp index 64e85de5..a70bc471 100644 --- a/reference/windows/USB/main.cpp +++ b/reference/windows/USB/main.cpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Windows // #include "tests.hpp" diff --git a/reference/windows/USB/scope.hpp b/reference/windows/USB/scope.hpp index 53e3e39f..55fdd505 100644 --- a/reference/windows/USB/scope.hpp +++ b/reference/windows/USB/scope.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Windows // #pragma once diff --git a/reference/windows/USB/tests.cpp b/reference/windows/USB/tests.cpp index 73d7da40..e1f337ce 100644 --- a/reference/windows/USB/tests.cpp +++ b/reference/windows/USB/tests.cpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Windows // #include "tests.hpp" @@ -48,7 +48,7 @@ void tests::test_current_device() { test_control_transfers(); test_bulk_transfers(); - test_device->release_interface(); + test_device->release_interface(0); test_device->close(); std::cout << "Test completed" << std::endl; } diff --git a/reference/windows/USB/tests.hpp b/reference/windows/USB/tests.hpp index 992de2b9..04a2ff88 100644 --- a/reference/windows/USB/tests.hpp +++ b/reference/windows/USB/tests.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Windows // #pragma once diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp index 9f322573..e61a281e 100644 --- a/reference/windows/USB/usb_device.cpp +++ b/reference/windows/USB/usb_device.cpp @@ -4,22 +4,25 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Windows // #include "usb_device.hpp" #include "usb_error.hpp" #include "scope.hpp" +#include "config_parser.hpp" #include -usb_device::usb_device(const std::wstring& device_path, int vendor_id, int product_id) -: device_path_(device_path), device_handle_(nullptr), interface_handle_(nullptr), - vendor_id_(vendor_id), product_id_(product_id), is_open_(false) { - - //manufacturer_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBVendorString)); - //product_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBProductString)); - //serial_number_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBSerialNumberString)); +usb_device::usb_device(std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, std::map&& children) +: vendor_id_(vendor_id), product_id_(product_id), is_open_(false), device_path_(std::move(device_path)) { + + config_parser parser{}; + parser.parse(config_desc); + interfaces_ = std::move(parser.interfaces); + functions_ = std::move(parser.functions); + + build_handles(device_path_, std::move(children)); } void usb_device::set_product_names(const std::string& manufacturer, const std::string& product, const std::string& serial_number) { @@ -28,6 +31,23 @@ void usb_device::set_product_names(const std::string& manufacturer, const std::s serial_number_ = serial_number; } +void usb_device::build_handles(const std::wstring& device_path, std::map&& children) { + for (const usb_interface& intf : interfaces_) { + int intf_number = intf.number(); + auto function = get_function(intf_number); + + std::wstring path; + if (function->first_interface() == intf_number) { + if (children.size() > 0) { + path = std::move(children[intf_number]); + } else { + path = device_path; + } + } + + interface_handles_.push_back(interface_handle(intf_number, function->first_interface(), std::move(path))); + } +} usb_device::~usb_device() { close(); @@ -61,66 +81,95 @@ void usb_device::open() { void usb_device::close() { if (!is_open()) return; - - if (interface_handle_ != nullptr) - release_interface(); + + for (auto& itf : interfaces_) + if (itf.is_claimed()) + release_interface(itf.number()); is_open_ = false; } void usb_device::claim_interface(int interface_number) { - - if (interface_handle_ != nullptr) - throw usb_error("an interface has already been claimed"); - - auto handle = CreateFileW(device_path_.c_str(), - GENERIC_WRITE | GENERIC_READ, - FILE_SHARE_WRITE | FILE_SHARE_READ, - nullptr, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, - nullptr); - if (handle == INVALID_HANDLE_VALUE) - usb_error::throw_error("Cannot open USB device"); + if (!is_open()) + throw usb_error("USB device is not open"); - if (!WinUsb_Initialize(handle, &interface_handle_)) { - CloseHandle(handle); + usb_interface* intf = get_interface(interface_number); + if (intf == nullptr) + throw usb_error("no such interface"); + if (intf->is_claimed()) + throw usb_error("interface has already been claimed"); + + interface_handle* intf_handle = get_interface_handle(interface_number); + interface_handle* first_intf_handle = get_interface_handle(intf_handle->first_interface_num); + + // open device if needed + if (first_intf_handle->device_handle == nullptr) { + first_intf_handle->device_handle = CreateFileW(first_intf_handle->device_path.c_str(), + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE | FILE_SHARE_READ, + nullptr, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + nullptr); + if (first_intf_handle->device_handle == INVALID_HANDLE_VALUE) + usb_error::throw_error("Cannot open USB device"); + } + + // open interface + if (!WinUsb_Initialize(first_intf_handle->device_handle, &intf_handle->intf_handle)) { + if (first_intf_handle->device_open_count == 0) { + CloseHandle(first_intf_handle->device_handle); + first_intf_handle->device_handle = nullptr; + } usb_error::throw_error("Cannot open USB device"); return; } - device_handle_ = handle; + first_intf_handle->device_open_count += 1; + intf->set_claimed(true); } -void usb_device::release_interface() { - if (interface_handle_ == nullptr) - throw usb_error("no interface has been claimed"); +void usb_device::release_interface(int interface_number) { - if (interface_handle_ != nullptr) { - WinUsb_Free(interface_handle_); - interface_handle_ = nullptr; - } - if (device_handle_ != nullptr) { - CloseHandle(device_handle_); - device_handle_ = nullptr; + if (!is_open()) + throw usb_error("USB device is not open"); + + usb_interface* intf = get_interface(interface_number); + if (intf == nullptr) + throw usb_error("no such interface"); + if (!intf->is_claimed()) + throw usb_error("interface has not been claimed"); + + interface_handle* intf_handle = get_interface_handle(interface_number); + interface_handle* first_intf_handle = get_interface_handle(intf_handle->first_interface_num); + + // close interface + WinUsb_Free(intf_handle->intf_handle); + intf_handle->intf_handle = nullptr; + intf->set_claimed(false); + + // close device if needed + first_intf_handle->device_open_count -= 1; + if (first_intf_handle->device_open_count == 0) { + CloseHandle(first_intf_handle->device_handle); + first_intf_handle->device_handle = nullptr; } } std::vector usb_device::transfer_in(int endpoint_number, int data_len, int timeout) { - if (interface_handle_ == nullptr) - throw usb_error("no interface has been claimed"); - UCHAR endpoint_address = endpoint_number + 128; + auto intf_handle = check_valid_endpoint(usb_direction::in, endpoint_number)->intf_handle; + UCHAR endpoint_address = ep_address(usb_direction::in, endpoint_number); ULONG value = timeout; - if (!WinUsb_SetPipePolicy(interface_handle_, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) + if (!WinUsb_SetPipePolicy(intf_handle, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) usb_error::throw_error("Failed to set endpoint timeout"); std::vector data(data_len); DWORD len = 0; - if (!WinUsb_ReadPipe(interface_handle_, endpoint_address, static_cast(data.data()), data_len, &len, nullptr)) + if (!WinUsb_ReadPipe(intf_handle, endpoint_address, static_cast(data.data()), data_len, &len, nullptr)) usb_error::throw_error("Cannot receive from USB endpoint"); data.resize(len); @@ -128,17 +177,16 @@ std::vector usb_device::transfer_in(int endpoint_number, int data_len, } void usb_device::transfer_out(int endpoint_number, const std::vector& data, int timeout) { - if (interface_handle_ == nullptr) - throw usb_error("no interface has been claimed"); - UCHAR endpoint_address = endpoint_number; + auto intf_handle = check_valid_endpoint(usb_direction::out, endpoint_number)->intf_handle; + UCHAR endpoint_address = ep_address(usb_direction::out, endpoint_number); ULONG value = timeout; - if (!WinUsb_SetPipePolicy(interface_handle_, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) + if (!WinUsb_SetPipePolicy(intf_handle, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) usb_error::throw_error("Failed to set endpoint timeout"); DWORD len = 0; - if (!WinUsb_WritePipe(interface_handle_, endpoint_address, const_cast(data.data()), static_cast(data.size()), &len, nullptr)) + if (!WinUsb_WritePipe(intf_handle, endpoint_address, const_cast(data.data()), static_cast(data.size()), &len, nullptr)) usb_error::throw_error("Failed to transmit to USB endpoint"); } @@ -146,9 +194,11 @@ int usb_device::control_transfer_core(const usb_control_request &request, uint8_ if (!is_open()) throw usb_error("USB device is not open"); + + auto handle = get_control_transfer_interface_handle(request)->intf_handle; ULONG value = timeout; - if (!WinUsb_SetPipePolicy(interface_handle_, 0, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) + if (!WinUsb_SetPipePolicy(handle, 0, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) usb_error::throw_error("Failed to set endpoint timeout"); WINUSB_SETUP_PACKET setup_packet = { 0 }; @@ -159,27 +209,71 @@ int usb_device::control_transfer_core(const usb_control_request &request, uint8_ setup_packet.Length = request.wLength; DWORD len = 0; - if (!WinUsb_ControlTransfer(interface_handle_, setup_packet, data, request.wLength, &len, nullptr)) + if (!WinUsb_ControlTransfer(handle, setup_packet, data, request.wLength, &len, nullptr)) usb_error::throw_error("Control transfer failed"); return len; } -void usb_device::control_transfer(const usb_control_request& request, int timeout ) { +usb_device::interface_handle* usb_device::get_control_transfer_interface_handle(const usb_control_request& request) { + usb_request_type recipient = static_cast(static_cast(request.bmRequestType) | 0x03); + int recipient_index = request.wIndex & 0xff; + + int intf_num = -1; + if (recipient == usb_request_type::recipient_interface) { + + intf_num = recipient_index; + + } else if (recipient == usb_request_type::recipient_endpoint) { + + int endpoint_number = recipient_index & 0x7f; + usb_direction direction = static_cast(recipient_index & 0x80); + if (endpoint_number != 0) { + usb_interface* intf = get_endpoint_interface(direction, endpoint_number); + if (intf == nullptr ) + throw usb_error("invalid endpoint number for control request"); + intf_num = intf->number(); + } + + } + + // for control transfer to device, use any claimed interface + if (intf_num < 0) { + for (auto& intf : interfaces_) { + if (intf.is_claimed()) { + intf_num = intf.number(); + break; + } + } + } + + if (intf_num >= 0) { + usb_interface* intf = get_interface(intf_num); + if (intf == nullptr) + throw usb_error("invalid interface number for control request"); + if (!intf->is_claimed()) + throw usb_error("interface for control request has not been claimed"); + return get_interface_handle(intf_num); + } + + throw usb_error("no interface has been claimed"); +} + +void usb_device::control_transfer(const usb_control_request& request, int timeout) { if (request.wLength != 0) throw usb_error("'control_transfer' only supports request without data phase but 'wLength' != 0"); control_transfer_core(request, nullptr, timeout); } -void usb_device::control_transfer_out(const usb_control_request& request, const std::vector& data, int timeout ) { +void usb_device::control_transfer_out(const usb_control_request& request, const std::vector& data, int timeout) { if ((request.bmRequestType & 0x80) != 0) throw usb_error("direction mismatch between 'control_transfer_out' and direction bit in 'bmRequestType'"); control_transfer_core(request, const_cast(data.data()), timeout); } -std::vector usb_device::control_transfer_in(const usb_control_request& request, int timeout ) { +std::vector usb_device::control_transfer_in(const usb_control_request& request, int timeout) { if ((request.bmRequestType & 0x80) == 0) throw usb_error("direction mismatch between 'control_transfer_in' and direction bit in 'bmRequestType'"); @@ -188,3 +282,73 @@ std::vector usb_device::control_transfer_in(const usb_control_request& data.resize(request.wLength); return data; } + +usb_composite_function* usb_device::get_function(int intf_number) { + auto iter = std::find_if(functions_.begin(), functions_.end(), [intf_number](const usb_composite_function& f) { + return intf_number >= f.first_interface() && intf_number < f.first_interface() + f.num_interfaces(); + }); + + if (iter == functions_.end()) + return nullptr; + + return &*iter; +} + +usb_device::interface_handle* usb_device::get_interface_handle(int intf_number) { + for (auto& intf : interface_handles_) + if (intf.interface_num == intf_number) + return &intf; + + return nullptr; +} + +usb_interface* usb_device::get_interface(int intf_number) { + for (auto& intf : interfaces_) + if (intf.number() == intf_number) + return &intf; + + return nullptr; +} + +usb_interface* usb_device::get_endpoint_interface(usb_direction direction, int endpoint_number) { + for (auto& intf : interfaces_) + for (auto& ep : intf.alternate().endpoints()) + if (ep.number() == endpoint_number && ep.direction() == direction) + return &intf; + + return nullptr; +} + +const usb_endpoint* usb_device::get_endpoint(usb_direction direction, int endpoint_number) { + for (auto& intf : interfaces_) + for (auto& ep : intf.alternate().endpoints()) + if (ep.number() == endpoint_number && ep.direction() == direction) + return &ep; + + return nullptr; +} + +usb_device::interface_handle* usb_device::check_valid_endpoint(usb_direction direction, int endpoint_number) { + + if (!is_open()) + throw usb_error("USB device is not open"); + + const usb_endpoint* ep = get_endpoint(direction, endpoint_number); + if (ep == nullptr) + throw usb_error("no such endpoint"); + if (ep->transfer_type() != usb_transfer_type::bulk && ep->transfer_type() != usb_transfer_type::interrupt) + throw usb_error("invalid transfer type for operation"); + + usb_interface* intf = get_endpoint_interface(direction, endpoint_number); + if (!intf->is_claimed()) + throw usb_error("endpoint's interface has not been claimed"); + + return get_interface_handle(intf->number()); +} + + +// --- interface_handle + +usb_device::interface_handle::interface_handle(int intf_num, int first_num, std::wstring&& path) + : interface_num(intf_num), first_interface_num(first_num), device_path(std::move(path)), + device_handle(nullptr), intf_handle(nullptr), device_open_count(0) { } diff --git a/reference/windows/USB/usb_device.hpp b/reference/windows/USB/usb_device.hpp index 81ac6c3d..1c8918dc 100644 --- a/reference/windows/USB/usb_device.hpp +++ b/reference/windows/USB/usb_device.hpp @@ -4,11 +4,12 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Windows // #pragma once +#include #include #include #include @@ -20,6 +21,8 @@ #undef LowSpeed #include +#include "configuration.hpp" + /** * USB control request type. @@ -113,9 +116,11 @@ class usb_device { void claim_interface(int interface_number); /** - * Releases the claimed interface. + * Releases a claimed interface. + * + * @param interface_number interface number */ - void release_interface(); + void release_interface(int interface_number); /** * Receives data from a bulk or interrupt endpoint. @@ -190,23 +195,52 @@ class usb_device { */ std::vector control_transfer_in(const usb_control_request& request, int timeout = 0); + /** + * Get the list of USB interfaces. + */ + const std::vector& interfaces() const { return interfaces_; } + private: - usb_device(const std::wstring& device_path, int vendor_id, int product_id); + struct interface_handle { + int interface_num; + int first_interface_num; + std::wstring device_path; + HANDLE device_handle; + WINUSB_INTERFACE_HANDLE intf_handle; + int device_open_count; + + interface_handle(int intf_num, int first_num, std::wstring&& path); + }; + + usb_device(std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, std::map&& children); void set_product_names(const std::string& manufacturer, const std::string& product, const std::string& serial_number); + void build_handles(const std::wstring& device_path, std::map&& children); + int control_transfer_core(const usb_control_request& request, uint8_t* data, int timeout); - const wchar_t* device_path() { return device_path_.c_str(); } + usb_composite_function* get_function(int intf_number); + + interface_handle* get_interface_handle(int intf_number); + usb_interface* get_interface(int intf_number); + usb_interface* get_endpoint_interface(usb_direction direction, int endpoint_number); + const usb_endpoint* get_endpoint(usb_direction direction, int endpoint_number); + interface_handle* get_control_transfer_interface_handle(const usb_control_request& request); + interface_handle* check_valid_endpoint(usb_direction direction, int endpoint_number); + static uint8_t ep_address(usb_direction direction, int endpoint_number) { + return static_cast(direction) | static_cast(endpoint_number); + } - std::wstring device_path_; - HANDLE device_handle_; - WINUSB_INTERFACE_HANDLE interface_handle_; bool is_open_; int product_id_; int vendor_id_; + std::wstring device_path_; std::string manufacturer_; std::string product_; std::string serial_number_; - + + std::vector interfaces_; + std::vector functions_; + std::vector interface_handles_; friend class usb_registry; }; diff --git a/reference/windows/USB/usb_device_info.cpp b/reference/windows/USB/usb_device_info.cpp new file mode 100644 index 00000000..2cf73039 --- /dev/null +++ b/reference/windows/USB/usb_device_info.cpp @@ -0,0 +1,216 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for Windows +// + +#include "usb_device_info.hpp" +#include "scope.hpp" +#include "usb_error.hpp" +#include +#include +#include +#include + + +std::wstring usb_device_info::get_device_path(const std::wstring& instance_id, const GUID* interface_guid) { + + // get device info set for instance + HDEVINFO dev_info_set_hdl = SetupDiGetClassDevsW(interface_guid, instance_id.c_str(), nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (dev_info_set_hdl == INVALID_HANDLE_VALUE) + usb_error::throw_error("internal error (SetupDiGetClassDevsW)"); + + // ensure the result is destroyed when the scope is left + auto dev_info_set_guard = make_scope_exit([dev_info_set_hdl]() { + SetupDiDestroyDeviceInfoList(dev_info_set_hdl); + }); + + // retrieve first element of enumeration + SP_DEVICE_INTERFACE_DATA dev_intf_data = { sizeof(dev_intf_data) }; + if (!SetupDiEnumDeviceInterfaces(dev_info_set_hdl, nullptr, interface_guid, 0, &dev_intf_data)) + usb_error::throw_error("internal error (SetupDiEnumDeviceInterfaces)"); + + // retrieve path + uint8_t dev_path_buf[MAX_PATH * sizeof(WCHAR) + sizeof(DWORD)]; + memset(dev_path_buf, 0, sizeof(dev_path_buf)); + PSP_DEVICE_INTERFACE_DETAIL_DATA_W intf_detail_data = reinterpret_cast(dev_path_buf); + intf_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); + if (!SetupDiGetDeviceInterfaceDetailW(dev_info_set_hdl, &dev_intf_data, intf_detail_data, sizeof(dev_path_buf), nullptr, nullptr)) + throw usb_error("Internal error (SetupDiGetDeviceInterfaceDetailA)", GetLastError()); + + return intf_detail_data->DevicePath; +} + +uint32_t usb_device_info::get_device_property_int(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { + // query property value + DEVPROPTYPE property_type; + uint32_t property_value = -1; + if (!SetupDiGetDevicePropertyW(dev_info, dev_info_data, prop_key, &property_type, reinterpret_cast(&property_value), sizeof(property_value), nullptr, 0)) + usb_error::throw_error("internal error (SetupDiGetDevicePropertyW)"); + + // check property type + if (property_type != DEVPROP_TYPE_UINT32) + throw usb_error("internal error (SetupDiGetDevicePropertyW)"); + + return property_value; +} + +std::vector usb_device_info::get_device_property_variable_length(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key, DEVPROPTYPE expected_type) { + + // query length + DWORD required_size = 0; + DEVPROPTYPE property_type; + if (!SetupDiGetDevicePropertyW(dev_info, dev_info_data, prop_key, &property_type, nullptr, 0, &required_size, 0)) { + DWORD err = GetLastError(); + if (err != ERROR_INSUFFICIENT_BUFFER) + throw usb_error("internal error (SetupDiGetDevicePropertyW)", err); + } + + // check property type + if (property_type != expected_type) + throw usb_error("internal error (SetupDiGetDevicePropertyW)"); + + // query property value + std::vector property_value; + property_value.resize(required_size); + if (!SetupDiGetDevicePropertyW(dev_info, dev_info_data, prop_key, &property_type, &property_value[0], required_size, nullptr, 0)) + usb_error::throw_error("internal error (SetupDiGetDevicePropertyW)"); + + return property_value; +} + +std::wstring usb_device_info::get_device_property_string(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { + + auto property_value = get_device_property_variable_length(dev_info, dev_info_data, prop_key, DEVPROP_TYPE_STRING); + return std::wstring(reinterpret_cast(&property_value[0])); +} + +std::vector usb_device_info::get_device_property_string_list(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { + auto property_value = get_device_property_variable_length(dev_info, dev_info_data, prop_key, DEVPROP_TYPE_STRING | DEVPROP_TYPEMOD_LIST); + return split_string_list(reinterpret_cast(&property_value[0])); +} + +std::vector usb_device_info::split_string_list(const wchar_t* str_list_raw) { + std::vector str_list; + int offset = 0; + while (str_list_raw[offset] != L'\0') { + str_list.push_back(str_list_raw + offset); + offset += static_cast(str_list.back().length()) + 1; + } + + return str_list; +} + +std::vector usb_device_info::get_descriptor(HANDLE hub_handle, ULONG usb_port_num, uint16_t descriptor_type, int index, int language_id, int request_size) { + int size = sizeof(USB_DESCRIPTOR_REQUEST) + (request_size != 0 ? request_size : 256); + uint8_t* descriptor_request_buffer = new uint8_t[size]; + auto dev_info_set_guard = make_scope_exit([descriptor_request_buffer]() { + delete[] descriptor_request_buffer; + }); + + // setup request data structure + USB_DESCRIPTOR_REQUEST* descriptor_request = reinterpret_cast(descriptor_request_buffer); + descriptor_request->ConnectionIndex = usb_port_num; + descriptor_request->SetupPacket.bmRequest = 0x80; // device-to-host / type standard / recipient device + descriptor_request->SetupPacket.bRequest = 0x06; // GET_DESCRIPTOR + descriptor_request->SetupPacket.wValue = (descriptor_type << 8) | index; + descriptor_request->SetupPacket.wIndex = language_id; + descriptor_request->SetupPacket.wLength = static_cast(size - sizeof(USB_DESCRIPTOR_REQUEST)); + + // get descriptor + DWORD bytesReturned = 0; + if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, descriptor_request, size, descriptor_request, size, &bytesReturned, nullptr)) + throw usb_error("Cannot retrieve descriptor (DeviceIoControl)", GetLastError()); + + // determine expected size of descriptor + int expected_size; + if (descriptor_type != USB_CONFIGURATION_DESCRIPTOR_TYPE) { + expected_size = descriptor_request->Data[0]; + } + else { + auto config_desc = reinterpret_cast(descriptor_request->Data); + expected_size = config_desc->wTotalLength; + } + + // check against effective size + int effective_size = bytesReturned - sizeof(USB_DESCRIPTOR_REQUEST); + if (effective_size < expected_size) { + if (request_size != 0) + throw usb_error("Unexpected descriptor size"); + + // repeat with larger size + return get_descriptor(hub_handle, usb_port_num, descriptor_type, index, language_id, expected_size); + } + + return std::vector(descriptor_request->Data, descriptor_request->Data + effective_size); +} + +std::string usb_device_info::get_string(HANDLE hub_handle, ULONG usb_port_num, int index) { + if (index == 0) + return ""; + + std::vector str_desc_raw = get_descriptor(hub_handle, usb_port_num, USB_STRING_DESCRIPTOR_TYPE, index, 0x0409); + USB_STRING_DESCRIPTOR* str_desc = reinterpret_cast(str_desc_raw.data()); + + // required length of UTF-8 string + int len = WideCharToMultiByte(CP_UTF8, 0, str_desc->bString, str_desc->bLength / 2 - 1, nullptr, 0, nullptr, nullptr); + + // convert to UTF-8 + std::string result; + result.resize(len, 'x'); + WideCharToMultiByte(CP_UTF8, 0, str_desc->bString, str_desc->bLength / 2 - 1, &result[0], len, nullptr, nullptr); + return result; +} + +bool usb_device_info::is_composite_device(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data) { + std::wstring device_service = usb_device_info::get_device_property_string(dev_info, dev_info_data, &DEVPKEY_Device_Service); + return lstrcmpiW(device_service.c_str(), L"usbccgp") == 0; +} + +static const std::wregex multiple_interface_pattern(L"USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); + +int usb_device_info::get_first_interface(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data) { + // Also see https://docs.microsoft.com/en-us/windows-hardware/drivers/install/standard-usb-identifiers#multiple-interface-usb-devices + + auto hardware_ids = usb_device_info::get_device_property_string_list(dev_info, dev_info_data, &DEVPKEY_Device_HardwareIds); + + for (const std::wstring& id : hardware_ids) { + auto matches = std::wsmatch{}; + if (std::regex_search(id, matches, multiple_interface_pattern)) + return std::stoul(matches[1].str(), nullptr, 16); + } + + return -1; +} + +std::vector usb_device_info::find_device_interface_guids(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data) { + HKEY reg_key = SetupDiOpenDevRegKey(dev_info, dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); + if (reg_key == INVALID_HANDLE_VALUE) + throw usb_error("Cannot open device registry key", GetLastError()); + + auto reg_key_guard = make_scope_exit([reg_key]() { + RegCloseKey(reg_key); + }); + + // read registry value (without buffer, to query length) + DWORD value_type = 0; + DWORD value_size = 0; + LSTATUS res = RegQueryValueExW(reg_key, L"DeviceInterfaceGUIDs", nullptr, &value_type, nullptr, &value_size); + if (res == ERROR_FILE_NOT_FOUND) + return std::vector(); + if (res != 0 && res != ERROR_MORE_DATA) + throw usb_error("Internal error (RegQueryValueExW)", res); + + std::vector str_list_raw; + str_list_raw.resize(value_size); + + // read registry value (with buffer) + res = RegQueryValueExW(reg_key, L"DeviceInterfaceGUIDs", nullptr, &value_type, &str_list_raw[0], &value_size); + if (res != 0) + throw usb_error("Internal error (RegQueryValueExW)", res); + + return split_string_list(reinterpret_cast(&str_list_raw[0])); +} diff --git a/reference/windows/USB/usb_device_info.hpp b/reference/windows/USB/usb_device_info.hpp new file mode 100644 index 00000000..042e004c --- /dev/null +++ b/reference/windows/USB/usb_device_info.hpp @@ -0,0 +1,146 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for Windows +// + +#pragma once + +#include +#include +#include +#undef min +#undef max +#undef LowSpeed +#include + +/// +/// Helper class for querying device information. +/// +class usb_device_info +{ +private: + /// + /// Get a device property of integer type. + /// + /// handle of device information set containing the device + /// pointer to device information structure representing the device + /// property key + /// property integer value + static uint32_t get_device_property_int(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key); + + /// + /// Get a device property of string type. + /// + /// handle of device information set containing the device + /// pointer to device information structure representing the device + /// property key + /// property string value + static std::wstring get_device_property_string(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key); + + /// + /// Get a device property of variable length. + /// + /// handle of device information set containing the device + /// pointer to device information structure representing the device + /// property key + /// expected property type (use DEVPROP_TYPE_xxx constants) + /// property value as byte array + static std::vector get_device_property_variable_length(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key, DEVPROPTYPE expected_type); + + /// + /// Get a device property of string list type. + /// + /// handle of device information set containing the device + /// pointer to device information structure representing the device + /// property key + /// property value as vector of strings + static std::vector get_device_property_string_list(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key); + + /// + /// Split the string list into a vector of strings + /// + /// The provides string list is a concatenation of null-terminated string, terminated with an additional zero-length string. + /// + /// + /// string list + /// vector of strings + static std::vector split_string_list(const wchar_t* string_list); + + /// + /// Get device path for the specified device instance and device interface class. + /// + /// device instance ID + /// device interface class GUID + /// device path + static std::wstring get_device_path(const std::wstring& instance_id, const GUID* interface_guid); + + /// + /// Get a USB descriptor. + /// + /// The descriptor is retrieved via the USB hub (the USB device's parent) so it can be + /// access for USB devices that are already opened by another application. + /// + /// + /// handle of USB hub + /// device's port number (at hub) + /// descriptor type (use USB_xxx_DESCRIPTOR_TYPE constants) + /// descriptor index + /// language ID + /// intial size to request + /// descriptor as byte array + static std::vector get_descriptor(HANDLE hub_handle, ULONG usb_port_num, uint16_t descriptor_type, int index, int language_id, int request_size = 0); + + /// + /// Get USB string with the specified index. + /// + /// The string descriptor is retrieved via the USB hub (the USB device's parent) so it can be + /// access for USB devices that are already opened by another application. + /// + /// + /// For string index 0, an empty string is returned. + /// + /// + /// handle of USB hub + /// device's port number (at hub) + /// string index + /// string + static std::string get_string(HANDLE hub_handle, ULONG usb_port_num, int index); + + /// + /// Query if device is a composite USB device. + /// + /// A composite device consists of multiple interfaces appearing as separate devices + /// in Windows. In the Setup API, they are represented as child devices. + /// + /// + /// handle of device information set containing the device + /// pointer to device information structure representing the device + /// true if device is a composite device, false otherwise + static bool is_composite_device(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data); + + /// + /// Get the number of the first USB interface. + /// + /// The first interface number is relevant for child devices of composite devices. + /// + /// + /// handle of device information set containing the device + /// pointer to device information structure representing the device + /// + static int get_first_interface(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data); + + /// + /// Get the device's interface GUIDs. + /// + /// handle of device information set containing the device + /// pointer to device information structure representing the device + /// vector of GUIDs + static std::vector find_device_interface_guids(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data); + + friend class usb_registry; +}; + diff --git a/reference/windows/USB/usb_error.cpp b/reference/windows/USB/usb_error.cpp index 660b3e4c..7fdd7329 100644 --- a/reference/windows/USB/usb_error.cpp +++ b/reference/windows/USB/usb_error.cpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Windows // #include "usb_error.hpp" diff --git a/reference/windows/USB/usb_error.hpp b/reference/windows/USB/usb_error.hpp index ed529720..7f83beae 100644 --- a/reference/windows/USB/usb_error.hpp +++ b/reference/windows/USB/usb_error.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Windows // #pragma once diff --git a/reference/windows/USB/usb_registry.cpp b/reference/windows/USB/usb_registry.cpp index c19deb16..11fcec07 100644 --- a/reference/windows/USB/usb_registry.cpp +++ b/reference/windows/USB/usb_registry.cpp @@ -4,11 +4,12 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Windows // #include "usb_registry.hpp" #include "usb_device.hpp" +#include "usb_device_info.hpp" #include "usb_error.hpp" #include "scope.hpp" @@ -148,11 +149,11 @@ void usb_registry::detect_present_devices() { std::shared_ptr usb_registry::create_device(HDEVINFO dev_info_set_hdl, SP_DEVINFO_DATA* dev_info) { - DWORD usb_port_num = get_device_property_int(dev_info_set_hdl, dev_info, &DEVPKEY_Device_Address); - std::wstring instance_id = get_device_property_string(dev_info_set_hdl, dev_info, &DEVPKEY_Device_InstanceId); - std::wstring parent_instance_id = get_device_property_string(dev_info_set_hdl, dev_info, &DEVPKEY_Device_Parent); + DWORD usb_port_num = usb_device_info::get_device_property_int(dev_info_set_hdl, dev_info, &DEVPKEY_Device_Address); + std::wstring instance_id = usb_device_info::get_device_property_string(dev_info_set_hdl, dev_info, &DEVPKEY_Device_InstanceId); + std::wstring parent_instance_id = usb_device_info::get_device_property_string(dev_info_set_hdl, dev_info, &DEVPKEY_Device_Parent); - std::wstring hub_path = get_device_path(parent_instance_id, &GUID_DEVINTERFACE_USB_HUB); + std::wstring hub_path = usb_device_info::get_device_path(parent_instance_id, &GUID_DEVINTERFACE_USB_HUB); // open parent (hub) HANDLE hub_handle = CreateFileW(hub_path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); @@ -163,7 +164,12 @@ std::shared_ptr usb_registry::create_device(HDEVINFO dev_info_set_hd CloseHandle(hub_handle); }); - auto path = get_device_path(instance_id, &GUID_DEVINTERFACE_USB_DEVICE); + // check for composite device + std::map children{}; + if (usb_device_info::is_composite_device(dev_info_set_hdl, dev_info)) + children = enumerate_child_devices(usb_device_info::get_device_property_string_list(dev_info_set_hdl, dev_info, &DEVPKEY_Device_Children)); + + auto path = usb_device_info::get_device_path(instance_id, &GUID_DEVINTERFACE_USB_DEVICE); // get device descriptor USB_NODE_CONNECTION_INFORMATION_EX conn_info = { 0 }; @@ -172,16 +178,67 @@ std::shared_ptr usb_registry::create_device(HDEVINFO dev_info_set_hd if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, sizeof(conn_info), &conn_info, sizeof(conn_info), &size, nullptr)) usb_error::throw_error("Internal error (cannot get device descriptor)"); + // get configuration descriptor + auto config_desc = usb_device_info::get_descriptor(hub_handle, usb_port_num, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0); + // Create new device - std::shared_ptr device(new usb_device(path, conn_info.DeviceDescriptor.idVendor, conn_info.DeviceDescriptor.idProduct)); + std::shared_ptr device(new usb_device(std::move(path), conn_info.DeviceDescriptor.idVendor, conn_info.DeviceDescriptor.idProduct, config_desc, std::move(children))); device->set_product_names( - get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iManufacturer), - get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iProduct), - get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iSerialNumber) + usb_device_info::get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iManufacturer), + usb_device_info::get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iProduct), + usb_device_info::get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iSerialNumber) ); return device; } +std::map usb_registry::enumerate_child_devices(const std::vector child_ids) { + + std::map children{}; + + for (const std::wstring& child_instance_id : child_ids) { + HDEVINFO dev_info_set_hdl = SetupDiCreateDeviceInfoList(NULL, NULL); + if (dev_info_set_hdl == INVALID_HANDLE_VALUE) + throw usb_error("internal error (SetupDiGetClassDevsA)", GetLastError()); + + // ensure the result id destroyed when the scope is left + auto dev_info_set_guard = make_scope_exit([dev_info_set_hdl]() { + SetupDiDestroyDeviceInfoList(dev_info_set_hdl); + }); + + // get device info for child + SP_DEVINFO_DATA dev_info = { sizeof(dev_info) }; + if (!SetupDiOpenDeviceInfoW(dev_info_set_hdl, child_instance_id.c_str(), nullptr, 0, &dev_info)) + throw usb_error("internal error (SetupDiOpenDeviceInfoW)", GetLastError()); + + // get first interface number + int interface_number = usb_device_info::get_first_interface(dev_info_set_hdl, &dev_info); + if (interface_number == -1) + continue; + + // get device interface GUIDs + auto device_guids = usb_device_info::find_device_interface_guids(dev_info_set_hdl, &dev_info); + + CLSID clsid{}; + // use GUIDs to get device path + for (const std::wstring& guid : device_guids) { + if (CLSIDFromString(guid.c_str(), &clsid) != NOERROR) + continue; + + try { + auto device_path = usb_device_info::get_device_path(child_instance_id.c_str(), &clsid); + children[interface_number] = device_path; + break; + + } catch (usb_error&) { + // ignore and try next one + } + } + } + + return children; +} + + LRESULT usb_registry::handle_windows_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { usb_registry* self = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); @@ -274,7 +331,7 @@ void usb_registry::on_device_connected(const WCHAR* path) { void usb_registry::on_device_disconnected(const WCHAR* path) { // find device in device list - auto it = std::find_if(devices.cbegin(), devices.cend(), [path](auto device) { return lstrcmpiW(path, device->device_path()) == 0; }); + auto it = std::find_if(devices.cbegin(), devices.cend(), [path](auto device) { return lstrcmpiW(path, device->device_path_.c_str()) == 0; }); if (it == devices.cend()) return; // not part of the device list @@ -295,128 +352,3 @@ void usb_registry::on_device_disconnected(const WCHAR* path) { } } } - -uint32_t usb_registry::get_device_property_int(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { - // query property value - DEVPROPTYPE property_type; - uint32_t property_value = -1; - if (!SetupDiGetDevicePropertyW(dev_info, dev_info_data, prop_key, &property_type, reinterpret_cast(&property_value), sizeof(property_value), nullptr, 0)) - usb_error::throw_error("internal error (SetupDiGetDevicePropertyW)"); - - // check property type - if (property_type != DEVPROP_TYPE_UINT32) - throw usb_error("internal error (SetupDiGetDevicePropertyW)"); - - return property_value; -} - -std::wstring usb_registry::get_device_property_string(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { - - // query length - DWORD required_size = 0; - DEVPROPTYPE property_type; - if (!SetupDiGetDevicePropertyW(dev_info, dev_info_data, prop_key, &property_type, nullptr, 0, &required_size, 0)) { - DWORD err = GetLastError(); - if (err != ERROR_INSUFFICIENT_BUFFER) - throw usb_error("internal error (SetupDiGetDevicePropertyW)", err); - } - - // check property type - if (property_type != DEVPROP_TYPE_STRING) - throw usb_error("internal error (SetupDiGetDevicePropertyW)"); - - // query property value - std::wstring property_value; - property_value.resize(required_size / sizeof(WCHAR)); - if (!SetupDiGetDevicePropertyW(dev_info, dev_info_data, prop_key, &property_type, reinterpret_cast(&property_value[0]), required_size, nullptr, 0)) - usb_error::throw_error("internal error (SetupDiGetDevicePropertyW)"); - - return property_value; -} - -std::wstring usb_registry::get_device_path(const std::wstring& instance_id, const GUID* interface_guid) { - - // get device info set for instance - HDEVINFO dev_info_set_hdl = SetupDiGetClassDevsW(interface_guid, instance_id.c_str(), nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); - if (dev_info_set_hdl == INVALID_HANDLE_VALUE) - usb_error::throw_error("internal error (SetupDiGetClassDevsW)"); - - // ensure the result is destroyed when the scope is left - auto dev_info_set_guard = make_scope_exit([dev_info_set_hdl]() { - SetupDiDestroyDeviceInfoList(dev_info_set_hdl); - }); - - // retrieve first element of enumeration - SP_DEVICE_INTERFACE_DATA dev_intf_data = { sizeof(dev_intf_data) }; - if (!SetupDiEnumDeviceInterfaces(dev_info_set_hdl, nullptr, interface_guid, 0, &dev_intf_data)) - usb_error::throw_error("internal error (SetupDiEnumDeviceInterfaces)"); - - // retrieve path - uint8_t dev_path_buf[MAX_PATH * sizeof(WCHAR) + sizeof(DWORD)]; - memset(dev_path_buf, 0, sizeof(dev_path_buf)); - PSP_DEVICE_INTERFACE_DETAIL_DATA_W intf_detail_data = reinterpret_cast(dev_path_buf); - intf_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); - if (!SetupDiGetDeviceInterfaceDetailW(dev_info_set_hdl, &dev_intf_data, intf_detail_data, sizeof(dev_path_buf), nullptr, nullptr)) - throw usb_error("Internal error (SetupDiGetDeviceInterfaceDetailA)", GetLastError()); - - return intf_detail_data->DevicePath; -} - -std::vector usb_registry::get_descriptor(HANDLE hub_handle, ULONG usb_port_num, uint16_t descriptor_type, int index, int language_id, int request_size) { - int size = sizeof(USB_DESCRIPTOR_REQUEST) + (request_size != 0 ? request_size : 256); - uint8_t* descriptor_request_buffer = new uint8_t[size]; - auto dev_info_set_guard = make_scope_exit([descriptor_request_buffer]() { - delete [] descriptor_request_buffer; - }); - - // setup request data structure - USB_DESCRIPTOR_REQUEST* descriptor_request = reinterpret_cast(descriptor_request_buffer); - descriptor_request->ConnectionIndex = usb_port_num; - descriptor_request->SetupPacket.bmRequest = 0x80; // device-to-host / type standard / recipient device - descriptor_request->SetupPacket.bRequest = 0x06; // GET_DESCRIPTOR - descriptor_request->SetupPacket.wValue = (descriptor_type << 8) | index; - descriptor_request->SetupPacket.wIndex = language_id; - descriptor_request->SetupPacket.wLength = static_cast(size - sizeof(USB_DESCRIPTOR_REQUEST)); - - // get descriptor - DWORD bytesReturned = 0; - if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, descriptor_request, size, descriptor_request, size, &bytesReturned, nullptr)) - throw usb_error("Cannot retrieve descriptor (DeviceIoControl)", GetLastError()); - - // determine expected size of descriptor - int expected_size; - if (descriptor_type != USB_CONFIGURATION_DESCRIPTOR_TYPE) { - expected_size = descriptor_request->Data[0]; - } else { - expected_size = *reinterpret_cast(descriptor_request->Data); - } - - // check against effective size - int effective_size = bytesReturned - sizeof(USB_DESCRIPTOR_REQUEST); - if (effective_size != expected_size) { - if (request_size != 0) - throw usb_error("Unexpected descriptor size"); - - // repeat with correct size - return get_descriptor(hub_handle, usb_port_num, descriptor_type, index, language_id, expected_size); - } - - return std::vector(descriptor_request->Data, descriptor_request->Data + effective_size); -} - -std::string usb_registry::get_string(HANDLE hub_handle, ULONG usb_port_num, int index) { - if (index == 0) - return ""; - - std::vector str_desc_raw = get_descriptor(hub_handle, usb_port_num, USB_STRING_DESCRIPTOR_TYPE, index, 0x0409); - USB_STRING_DESCRIPTOR* str_desc = reinterpret_cast(str_desc_raw.data()); - - // required length of UTF-8 string - int len = WideCharToMultiByte(CP_UTF8, 0, str_desc->bString, str_desc->bLength / 2 - 1, nullptr, 0, nullptr, nullptr); - - // conver to UTF-8 - std::string result; - result.resize(len, 'x'); - WideCharToMultiByte(CP_UTF8, 0, str_desc->bString, str_desc->bLength / 2 - 1, &result[0], len, nullptr, nullptr); - return result; -} diff --git a/reference/windows/USB/usb_registry.hpp b/reference/windows/USB/usb_registry.hpp index 554943ec..a15dbe2f 100644 --- a/reference/windows/USB/usb_registry.hpp +++ b/reference/windows/USB/usb_registry.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Windows // #pragma once @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -49,6 +50,7 @@ class usb_registry { void monitor(); void detect_present_devices(); + std::map enumerate_child_devices(const std::vector child_ids); void on_device_connected(const WCHAR* path); void on_device_disconnected(const WCHAR* path); @@ -57,13 +59,6 @@ class usb_registry { static LRESULT handle_windows_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); std::shared_ptr create_device(HDEVINFO dev_info_set_hdl, SP_DEVINFO_DATA* dev_info); - static uint32_t get_device_property_int(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key); - static std::wstring get_device_property_string(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key); - static std::wstring get_device_path(const std::wstring& instance_id, const GUID* interface_guid); - - static std::vector get_descriptor(HANDLE hub_handle, ULONG usb_port_num, uint16_t descriptor_type, int index, int language_id, int request_size = 0); - static std::string get_string(HANDLE hub_handle, ULONG usb_port_num, int index); - std::vector devices; std::function on_connected_callback; From 47d85bcce2e12fd9c1a59486a98073c89beb27e1 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 28 Oct 2022 14:25:40 +0200 Subject: [PATCH 147/433] Enhanced macOS reference code --- reference/.vscode/settings.json | 5 + reference/macos/USB/assertion.cpp | 4 +- reference/macos/USB/assertion.hpp | 2 +- reference/macos/USB/config_parser.cpp | 188 +++++++++++++++++ reference/macos/USB/config_parser.hpp | 31 +++ reference/macos/USB/configuration.cpp | 50 +++++ reference/macos/USB/configuration.hpp | 148 ++++++++++++++ reference/macos/USB/main.cpp | 2 +- reference/macos/USB/scope.hpp | 2 +- reference/macos/USB/tests.cpp | 86 ++++---- reference/macos/USB/tests.hpp | 2 +- reference/macos/USB/usb_device.cpp | 189 +++++++++++++----- reference/macos/USB/usb_device.hpp | 47 +++-- reference/macos/usb.xcodeproj/project.pbxproj | 12 ++ reference/windows/USB/assertion.cpp | 2 +- reference/windows/USB/assertion.hpp | 2 +- reference/windows/USB/config_parser.cpp | 24 +-- reference/windows/USB/config_parser.hpp | 4 +- reference/windows/USB/configuration.cpp | 2 +- reference/windows/USB/configuration.hpp | 4 +- reference/windows/USB/main.cpp | 2 +- reference/windows/USB/scope.hpp | 2 +- reference/windows/USB/tests.cpp | 4 +- reference/windows/USB/tests.hpp | 2 +- reference/windows/USB/usb_device.cpp | 6 +- reference/windows/USB/usb_device.hpp | 11 +- 26 files changed, 680 insertions(+), 153 deletions(-) create mode 100644 reference/.vscode/settings.json create mode 100644 reference/macos/USB/config_parser.cpp create mode 100644 reference/macos/USB/config_parser.hpp create mode 100644 reference/macos/USB/configuration.cpp create mode 100644 reference/macos/USB/configuration.hpp diff --git a/reference/.vscode/settings.json b/reference/.vscode/settings.json new file mode 100644 index 00000000..a3b2b51f --- /dev/null +++ b/reference/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "vector": "cpp" + } +} \ No newline at end of file diff --git a/reference/macos/USB/assertion.cpp b/reference/macos/USB/assertion.cpp index 4e3111b5..eb55f334 100644 --- a/reference/macos/USB/assertion.cpp +++ b/reference/macos/USB/assertion.cpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code common for Linux / macOS / Windows // #include "assertion.hpp" @@ -40,7 +40,7 @@ void assert_equals(unsigned long expected, unsigned long actual, const char* mes char buf[50]; snprintf(buf, sizeof(buf), "expected: %lud, actual: %lud", expected, actual); failed(buf, message); - } + } } void assert_equals(const std::vector& expected, const std::vector& actual, const char* message) { diff --git a/reference/macos/USB/assertion.hpp b/reference/macos/USB/assertion.hpp index 09968407..a6ed23b6 100644 --- a/reference/macos/USB/assertion.hpp +++ b/reference/macos/USB/assertion.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code common for Linux / macOS / Windows // #pragma once diff --git a/reference/macos/USB/config_parser.cpp b/reference/macos/USB/config_parser.cpp new file mode 100644 index 00000000..2d75f475 --- /dev/null +++ b/reference/macos/USB/config_parser.cpp @@ -0,0 +1,188 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#include "config_parser.hpp" +#include "usb_error.hpp" + + +// --- USB descriptor types + +enum class usb_descriptor_type : uint8_t { + configuration = 0x02, + string = 0x03, + interface = 0x04, + endpoint = 0x05, + interface_association = 0x0b +}; + + +// --- USB configuration descriptor + +#pragma pack(push, 1) + +struct usb_config_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; +}; + +#pragma pack(pop) + + +// --- USB interface descriptor + +#pragma pack(push, 1) + +struct usb_interface_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +}; + +#pragma pack(pop) + + +// --- USB interface association descriptor + +#pragma pack(push, 1) + +struct usb_interface_association_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bFirstInterface; + uint8_t bInterfaceCount; + uint8_t bFunctionClass; + uint8_t bFunctionSubClass; + uint8_t bFunctionProtocol; + uint8_t iFunction; +}; + +#pragma pack(pop) + + +// --- USB endpoint descriptor + +#pragma pack(push, 1) + + struct usb_endpoint_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; + }; + +#pragma pack(pop) + + +// --- Configuration parser + + static int peek_desc_length(const uint8_t* desc, int offset) { return desc[offset]; } + static usb_descriptor_type peek_desc_type(const uint8_t* desc, int offset) { return static_cast(desc[offset + 1]); } + + + config_parser::config_parser() + : configuration_value(0) { } + +void config_parser::parse(const uint8_t* config_desc, int desc_len) +{ + const usb_config_desc* header = reinterpret_cast(config_desc); + if (desc_len <= sizeof(usb_config_desc) + || header->bDescriptorType != static_cast(usb_descriptor_type::configuration) + || header->wTotalLength != desc_len) + throw usb_error("Invalid configuration descriptor"); + + configuration_value = header->bConfigurationValue; + + int offset = peek_desc_length(config_desc, 0); + usb_alternate_interface* last_alternate = nullptr; + + while (offset + 2 < desc_len) { + + int len = peek_desc_length(config_desc, offset); + usb_descriptor_type type = peek_desc_type(config_desc, offset); + + if (offset + len > desc_len) + break; + + if (type == usb_descriptor_type::interface_association) { + + const usb_interface_association_desc* ia_desc = reinterpret_cast(config_desc + offset); + functions.push_back(usb_composite_function(ia_desc->bFirstInterface, ia_desc->bInterfaceCount, + ia_desc->bFunctionClass, ia_desc->bFunctionSubClass, ia_desc->bFunctionProtocol)); + last_alternate = nullptr; + + } else if (type == usb_descriptor_type::interface) { + + const usb_interface_desc* intf_desc = reinterpret_cast(config_desc + offset); + int number = intf_desc->bInterfaceNumber; + + // If there is no interface with this number yet, it's a new interface + // and not just an additional alternate interface. + auto intf = get_interface(number); + if (intf == nullptr) { + interfaces.push_back(usb_interface(number)); + intf = &interfaces.back(); + } + + // add alternate interface + last_alternate = intf->add_alternate(usb_alternate_interface(intf_desc->bAlternateSetting, + intf_desc->bInterfaceClass, intf_desc->bInterfaceSubClass, intf_desc->bInterfaceProtocol)); + + // If there is no function for this interface, there was not preceeding IAD. + // So create a new function with a single interface. + if (get_function(intf->number()) == nullptr) + functions.push_back(usb_composite_function(intf->number(), 1, last_alternate->class_code(), last_alternate->subclass_code(), last_alternate->protocol_code())); + + } else if (type == usb_descriptor_type::endpoint) { + + if (last_alternate == nullptr) + throw usb_error("invalid configuration descriptor"); + + const usb_endpoint_desc* ep_desc = reinterpret_cast(config_desc + offset); + last_alternate->add_endpoint(usb_endpoint(ep_desc->bEndpointAddress & 0x7f, static_cast(ep_desc->bEndpointAddress & 0x80), + static_cast(ep_desc->bmAttributes & 0x03), ep_desc->wMaxPacketSize)); + } + + offset += len; + } + + if (offset != desc_len) + throw usb_error("invalid configuration descriptor"); +} + +usb_interface* config_parser::get_interface(int number) { + auto iter = std::find_if(interfaces.begin(), interfaces.end(), [number](const usb_interface& itf) { return itf.number() == number; }); + if (iter == interfaces.end()) + return nullptr; + + return &*iter; +} + +usb_composite_function* config_parser::get_function(int intf_number) { + auto iter = std::find_if(functions.begin(), functions.end(), [intf_number](const usb_composite_function& f) { + return intf_number >= f.first_interface() && intf_number < f.first_interface() + f.num_interfaces(); + }); + if (iter == functions.end()) + return nullptr; + + return &*iter; +} diff --git a/reference/macos/USB/config_parser.hpp b/reference/macos/USB/config_parser.hpp new file mode 100644 index 00000000..04f6615c --- /dev/null +++ b/reference/macos/USB/config_parser.hpp @@ -0,0 +1,31 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#pragma once + +#include +#include "configuration.hpp" + +/// +/// Parses a USB configuration descriptor. +/// +class config_parser { +public: + config_parser(); + void parse(const uint8_t* config_desc, int desc_len); + + uint8_t configuration_value; + + std::vector interfaces; + std::vector functions; + +private: + usb_interface* get_interface(int number); + usb_composite_function* get_function(int intf_number); +}; diff --git a/reference/macos/USB/configuration.cpp b/reference/macos/USB/configuration.cpp new file mode 100644 index 00000000..6e2e4f31 --- /dev/null +++ b/reference/macos/USB/configuration.cpp @@ -0,0 +1,50 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#include "configuration.hpp" + +// --- usb_endpoint + +usb_endpoint::usb_endpoint(int number, usb_direction direction, usb_transfer_type transfer_type, int packet_size) + : number_(number), direction_(direction), transfer_type_(transfer_type), packet_size_(packet_size) { } + + +// --- usb_alternate_interface + +usb_alternate_interface::usb_alternate_interface(int number, int class_code, int subclass_code, int protocol_code) + : number_(number), class_code_(class_code), subclass_code_(subclass_code), protocol_code_(protocol_code) { } + +void usb_alternate_interface::add_endpoint(usb_endpoint&& endpoint) { + endpoints_.push_back(std::move(endpoint)); +} + + +// --- usb_interface + +usb_interface::usb_interface(int number) + : number_(number), is_claimed_(false), alternate_index_(0) { } + +void usb_interface::set_claimed(bool claimed) { + is_claimed_ = claimed; +} + +usb_alternate_interface* usb_interface::add_alternate(usb_alternate_interface&& alternate) { + alternates_.push_back(std::move(alternate)); + return &alternates_.back(); +} + +void usb_interface::set_alternate(int index) { + alternate_index_ = index; +} + + +// --- usb_composite_function + +usb_composite_function::usb_composite_function(int first_interface, int num_interfaces, int class_code, int subclass_code, int protocol_code) + : first_interface_(first_interface), num_interfaces_(num_interfaces), class_code_(class_code), subclass_code_(subclass_code), protocol_code_(protocol_code) { } diff --git a/reference/macos/USB/configuration.hpp b/reference/macos/USB/configuration.hpp new file mode 100644 index 00000000..91f22aed --- /dev/null +++ b/reference/macos/USB/configuration.hpp @@ -0,0 +1,148 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#pragma once + +#include +#include + +/// USB endpoint direction +enum class usb_direction : uint8_t { + /// Direction OUT: host to device + out = 0x00, + /// Direction IN: device to host + in = 0x80 +}; + +/// USB endpoint transfer type +enum class usb_transfer_type : uint8_t { + /// Control transfer + control = 0x00, + /// Isochronous transfer + isochronous = 0x01, + /// Bulk transfer + bulk = 0x02, + /// Interrupt transfer + interrupt = 0x03 +}; + +/// +/// USB endpoint +/// +struct usb_endpoint { +public: + /// Endpoint number + int number() const { return number_; } + /// Endpoint direction + usb_direction direction() const { return direction_; } + /// Endpoint transfer type + usb_transfer_type transfer_type() const { return transfer_type_; } + /// Maximum packet size + int packet_size() const { return packet_size_; } + +private: + usb_endpoint(int number, usb_direction direction, usb_transfer_type transfer_type, int packet_size); + + int number_; + usb_direction direction_; + usb_transfer_type transfer_type_; + int packet_size_; + + friend class config_parser; +}; + +/// +/// USB alternate interface +/// +struct usb_alternate_interface { +public: + /// Alternate number + int number() const { return number_; } + /// Interface class code + int class_code() const { return class_code_; } + /// Interface subclass code + int subclass_code() const { return subclass_code_; } + /// Interface protocol code + int protocol_code() const { return protocol_code_; } + /// List of endpoints + const std::vector& endpoints() const { return endpoints_; } + +private: + usb_alternate_interface(int number, int class_code, int subclass_code, int protocol_code); + void add_endpoint(usb_endpoint&& endpoint); + + int number_; + int class_code_; + int subclass_code_; + int protocol_code_; + std::vector endpoints_; + + friend class config_parser; +}; + +/// +/// USB interface +/// +struct usb_interface { +public: + /// Interface number + int number() const { return number_; } + /// Indicates if interface has been claimed + bool is_claimed() const { return is_claimed_; } + /// Currently selected alternate interface + const usb_alternate_interface& alternate() const { return alternates_[alternate_index_]; } + /// List of all alternate interfaces of this interfaces + const std::vector& alternates() const { return alternates_; } + +private: + usb_interface(int number); + void set_claimed(bool claimed); + usb_alternate_interface* add_alternate(usb_alternate_interface&& alternate); + void set_alternate(int index); + + int number_; + bool is_claimed_; + int alternate_index_; + std::vector alternates_; + + friend class config_parser; + friend class usb_device; +}; + +/// +/// USB composite function +/// +/// For a composite USB device, the composite function describes a single function. +/// A compsite function consists of a single or multiple consecutive interfaces. +/// +/// +struct usb_composite_function { +public: + /// Number of first interface + int first_interface() const { return first_interface_; } + /// Number of interfaces + int num_interfaces() const { return num_interfaces_; } + /// Function class code + int class_code() const { return class_code_; } + /// Function subclass code + int subclass_code() const { return subclass_code_; } + /// Function protocol code + int protocol_code() const { return protocol_code_; } + +private: + usb_composite_function(int first_interface, int num_interfaces, int class_code, int subclass_code, int protocol_code); + + int first_interface_; + int num_interfaces_; + int class_code_; + int subclass_code_; + int protocol_code_; + + friend class config_parser; +}; diff --git a/reference/macos/USB/main.cpp b/reference/macos/USB/main.cpp index 64e85de5..cbb3747c 100644 --- a/reference/macos/USB/main.cpp +++ b/reference/macos/USB/main.cpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code common for Linux / macOS / Windows // #include "tests.hpp" diff --git a/reference/macos/USB/scope.hpp b/reference/macos/USB/scope.hpp index 53e3e39f..85998dba 100644 --- a/reference/macos/USB/scope.hpp +++ b/reference/macos/USB/scope.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code common for Linux / macOS / Windows // #pragma once diff --git a/reference/macos/USB/tests.cpp b/reference/macos/USB/tests.cpp index 6b53c83f..657195ef 100644 --- a/reference/macos/USB/tests.cpp +++ b/reference/macos/USB/tests.cpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code common for Linux / macOS / Windows // #include "tests.hpp" @@ -13,6 +13,10 @@ #include #include +#undef min +#undef max + + using random_ushort_engine = std::independent_bits_engine< std::default_random_engine, 16, unsigned short>; @@ -20,14 +24,14 @@ using random_ushort_engine = std::independent_bits_engine< void tests::run() { registry.start(); - for (auto device : registry.get_devices()) { + for (auto& device : registry.get_devices()) { std::cout << "Present: " << device->description() << std::endl; } registry.set_on_device_connected([this](auto device) { on_device_connected(device); }); registry.set_on_device_disconnected([this](auto device) { on_device_disconnected(device); }); - for (auto device : registry.get_devices()) + for (auto& device : registry.get_devices()) on_device(device); std::cout << "Press RETURN to quit" << std::endl; @@ -36,53 +40,52 @@ void tests::run() { } void tests::test_current_device() { - std::cout << "Found test device" << std::endl; - test_device->open(); - test_device->claim_interface(0); - - test_control_transfers(); - test_bulk_transfers(); - - test_device->release_interface(); - test_device->close(); - std::cout << "Test completed" << std::endl; + try { + std::cout << "Found test device" << std::endl; + test_device->open(); + test_device->claim_interface(0); + + test_control_transfers(); + test_bulk_transfers(); + + test_device->release_interface(0); + test_device->close(); + std::cout << "Test completed" << std::endl; + } + catch (const std::exception& e) { + std::cout << "Test failed: " << e.what() << std::endl; + } } void tests::test_control_transfers() { - usb_control_request request_set_value_no_data = { - .bmRequestType = usb_control_request::request_type(usb_request_type::direction_out, - usb_request_type::type_vendor, - usb_request_type::recipient_interface), - .bRequest = 0x01, - .wValue = 0x9a41, - .wIndex = 0, // interface number - .wLength = 0 - }; + usb_control_request request_set_value_no_data = { 0 }; + request_set_value_no_data.bmRequestType = usb_control_request::request_type(usb_request_type::direction_out, + usb_request_type::type_vendor, usb_request_type::recipient_interface); + request_set_value_no_data.bRequest = 0x01; + request_set_value_no_data.wValue = 0x9a41; + request_set_value_no_data.wIndex = 0; // interface number + request_set_value_no_data.wLength = 0; test_device->control_transfer(request_set_value_no_data); - usb_control_request request_get_data = { - .bmRequestType = usb_control_request::request_type(usb_request_type::direction_in, - usb_request_type::type_vendor, - usb_request_type::recipient_interface), - .bRequest = 0x03, - .wValue = 0, - .wIndex = 0, // interface number - .wLength = 4 - }; + usb_control_request request_get_data = { 0 }; + request_get_data.bmRequestType = usb_control_request::request_type(usb_request_type::direction_in, + usb_request_type::type_vendor, usb_request_type::recipient_interface); + request_get_data.bRequest = 0x03; + request_get_data.wValue = 0; + request_get_data.wIndex = 0; // interface number + request_get_data.wLength = 4; auto data = test_device->control_transfer_in(request_get_data); std::vector expected_data{ 0x41, 0x9a, 0x00, 0x00 }; assert_equals(expected_data, data); std::vector sent_value{ 0x83, 0x03, 0xda, 0x3d }; - usb_control_request request_set_value_data = { - .bmRequestType = usb_control_request::request_type(usb_request_type::direction_out, - usb_request_type::type_vendor, - usb_request_type::recipient_interface), - .bRequest = 0x02, - .wValue = 0, - .wIndex = 0, // interface number - .wLength = static_cast(sent_value.size()) - }; + usb_control_request request_set_value_data = { 0 }; + request_set_value_data.bmRequestType = usb_control_request::request_type(usb_request_type::direction_out, + usb_request_type::type_vendor, usb_request_type::recipient_interface); + request_set_value_data.bRequest = 0x02; + request_set_value_data.wValue = 0; + request_set_value_data.wIndex = 0; // interface number + request_set_value_data.wLength = static_cast(sent_value.size()); test_device->control_transfer_out(request_set_value_data, sent_value); data = test_device->control_transfer_in(request_get_data); @@ -106,7 +109,7 @@ void tests::test_loopback(int num_bytes) { // read in separate thread std::thread reader([this, &rx_data, num_bytes]() { - int bytes_read = 0; + size_t bytes_read = 0; while (bytes_read < num_bytes) { auto data = test_device->transfer_in(2, 64); rx_data.insert(rx_data.end(), data.begin(), data.end()); @@ -156,7 +159,6 @@ std::vector tests::random_bytes(int num) { return std::vector(p, p + num); } - bool tests::is_test_device(usb_device_ptr device) { return device->vendor_id() == 0xcafe && device->product_id() == 0xceaf; } diff --git a/reference/macos/USB/tests.hpp b/reference/macos/USB/tests.hpp index 992de2b9..344f495f 100644 --- a/reference/macos/USB/tests.hpp +++ b/reference/macos/USB/tests.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code common for Linux / macOS / Windows // #pragma once diff --git a/reference/macos/USB/usb_device.cpp b/reference/macos/USB/usb_device.cpp index 14c18f8d..2d7824c2 100644 --- a/reference/macos/USB/usb_device.cpp +++ b/reference/macos/USB/usb_device.cpp @@ -11,25 +11,37 @@ #include "usb_error.hpp" #include "scope.hpp" #include "iokit_helper.hpp" +#include "config_parser.hpp" #include #include usb_device::usb_device(io_service_t service, IOUSBDeviceInterface** device, uint64_t entry_id, int vendor_id, int product_id) -: entry_id_(entry_id), device_(device), interface_(nullptr), vendor_id_(vendor_id), product_id_(product_id), is_open_(false) { - - (*device)->AddRef(device); +: entry_id_(entry_id), device_(device), vendor_id_(vendor_id), product_id_(product_id), is_open_(false) { manufacturer_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBVendorString)); product_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBProductString)); serial_number_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBSerialNumberString)); + + load_configuration(device); + + (*device)->AddRef(device); } usb_device::~usb_device() { close(); } +void usb_device::load_configuration(IOUSBDeviceInterface** device) { + IOUSBConfigurationDescriptorPtr desc = nullptr; + (*device)->GetConfigurationDescriptorPtr(device, 0, &desc); + + config_parser parser{}; + parser.parse(reinterpret_cast(desc), desc->wTotalLength); + interfaces_ = std::move(parser.interfaces); +} + std::string usb_device::description() const { const char* fmt = "VID: 0x%04x, PID: 0x%04x, manufacturer: %s, product: %s, serial: %s"; @@ -44,6 +56,10 @@ std::string usb_device::description() const { return desc; } +const std::vector& usb_device::interfaces() const { + return interfaces_; +} + bool usb_device::is_open() const { return is_open_; } @@ -74,8 +90,12 @@ void usb_device::close() { void usb_device::claim_interface(int interface_number) { - if (interface_ != nullptr) - throw usb_error("an interface has already been claimed"); + if (claimed_interfaces_.find(interface_number) != claimed_interfaces_.end()) + throw usb_error("interface has already been claimed"); + + usb_interface* uintf = get_interface(interface_number); + if (uintf == nullptr) + throw usb_error("no such interface"); // find interface IOUSBFindInterfaceRequest request; @@ -113,68 +133,99 @@ void usb_device::claim_interface(int interface_number) { } if (interface == nullptr) - throw usb_error("no USB interface found for given number"); + throw usb_error("internal error"); auto interface_guard = make_scope_exit([interface]() { (*interface)->Release(interface); }); ret = (*interface)->USBInterfaceOpen(interface); usb_error::check(ret, "failed to open USB interface"); - build_pipe_info(interface); - - interface_ = interface; - (*interface_)->AddRef(interface_); + (*interface)->AddRef(interface); + claimed_interfaces_[interface_number] = interface; + uintf->set_claimed(true); + build_pipe_info(); } -void usb_device::release_interface() { - if (interface_ == nullptr) - throw usb_error("no interface has been claimed"); +void usb_device::release_interface(int interface_number) { - (*interface_)->USBInterfaceClose(interface_); - (*interface_)->Release(interface_); - interface_ = nullptr; - pipes_.clear(); + usb_interface* uintf = get_interface(interface_number); + if (uintf == nullptr) + throw usb_error("no such interface"); + + auto iter = claimed_interfaces_.find(interface_number); + if (iter == claimed_interfaces_.end()) + throw usb_error("interface has been claimed"); + + IOUSBInterfaceInterface** interface = (*iter).second; + claimed_interfaces_.erase(iter); + uintf->set_claimed(false); + + (*interface)->USBInterfaceClose(interface); + (*interface)->Release(interface); + + build_pipe_info(); } -void usb_device::select_alternate_interface(int alternate_setting) { - (*interface_)->SetAlternateInterface(interface_, (UInt8) alternate_setting); - build_pipe_info(interface_); -} +void usb_device::select_alternate_interface(int interface_number, int alternate_setting) { + + usb_interface* uintf = get_interface(interface_number); + if (uintf == nullptr) + throw usb_error("no such interface"); + + int alt_index = get_alternate_index(interface_number, alternate_setting); + if (alt_index == -1) + throw usb_error("no such alternate setting"); -void usb_device::build_pipe_info(IOUSBInterfaceInterface** interface) { - UInt8 num_pipes = 0; - IOReturn ret = (*interface)->GetNumEndpoints(interface, &num_pipes); - usb_error::check(ret, "internal error (GetNumEndpoints)"); + auto iter = claimed_interfaces_.find(interface_number); + if (iter == claimed_interfaces_.end()) + throw usb_error("interface has not been claimed"); + + IOUSBInterfaceInterface** interface = iter->second; + (*interface)->SetAlternateInterface(interface, (UInt8) alternate_setting); + uintf->set_alternate(alt_index); + + build_pipe_info(); +} +void usb_device::build_pipe_info() { pipes_.clear(); - for (int i = 1; i <= num_pipes; i++) { - UInt8 direction = 0; - UInt8 number = 0; - UInt8 transfer_type = 0; - UInt8 ignore = 0; - UInt16 ignore2 = 0; - ret = (*interface)->GetPipeProperties(interface, i, &direction, &number, &transfer_type, &ignore2, &ignore); - usb_error::check(ret, "internal error (GetPipeProperties)"); - - pipe_info pipe{(UInt8) i, (uint8_t)((direction << 7) | number), transfer_type}; - pipes_.push_back(pipe); + + for (auto& intf : claimed_interfaces_) { + IOUSBInterfaceInterface** interface = intf.second; + + UInt8 num_pipes = 0; + IOReturn ret = (*interface)->GetNumEndpoints(interface, &num_pipes); + usb_error::check(ret, "internal error (GetNumEndpoints)"); + + for (int i = 1; i <= num_pipes; i++) { + UInt8 direction = 0; + UInt8 number = 0; + UInt8 transfer_type = 0; + UInt8 ignore = 0; + UInt16 ignore2 = 0; + ret = (*interface)->GetPipeProperties(interface, i, &direction, &number, &transfer_type, &ignore2, &ignore); + usb_error::check(ret, "internal error (GetPipeProperties)"); + + uint8_t addr = static_cast((direction << 7) | number); + usb_transfer_type type = static_cast(transfer_type); // both enumeration use the same value as the USB standard + pipe_info pipe{static_cast(i), addr, type, intf.first}; + pipes_.push_back(std::move(pipe)); + } } } std::vector usb_device::transfer_in(int endpoint_number, int data_len, int timeout) { - if (interface_ == nullptr) - throw usb_error("no interface has been claimed"); - auto pipe = ep_in_pipe(endpoint_number); + IOUSBInterfaceInterface** interface = claimed_interfaces_[pipe->interface_number]; UInt32 size = data_len; std::vector data(data_len); IOReturn ret; if (timeout != 0) { - ret = (*interface_)->ReadPipeTO(interface_, pipe->pipe_index, data.data(), &size, timeout, timeout); + ret = (*interface)->ReadPipeTO(interface, pipe->pipe_index, data.data(), &size, timeout, timeout); } else { - ret = (*interface_)->ReadPipe(interface_, pipe->pipe_index, data.data(), &size); + ret = (*interface)->ReadPipe(interface, pipe->pipe_index, data.data(), &size); } if (ret != kIOReturnSuccess) { @@ -189,14 +240,14 @@ std::vector usb_device::transfer_in(int endpoint_number, int data_len, } void usb_device::transfer_out(int endpoint_number, const std::vector& data, int timeout) { - if (interface_ == nullptr) - throw usb_error("no interface has been claimed"); + auto pipe = ep_out_pipe(endpoint_number); + IOUSBInterfaceInterface** interface = claimed_interfaces_[pipe->interface_number]; IOReturn ret; if (timeout != 0) - ret = (*interface_)->WritePipeTO(interface_, ep_out_pipe(endpoint_number)->pipe_index, const_cast(data.data()), static_cast(data.size()), timeout, timeout); + ret = (*interface)->WritePipeTO(interface, pipe->pipe_index, const_cast(data.data()), static_cast(data.size()), timeout, timeout); else - ret = (*interface_)->WritePipe(interface_, ep_out_pipe(endpoint_number)->pipe_index, const_cast(data.data()), static_cast(data.size())); + ret = (*interface)->WritePipe(interface, pipe->pipe_index, const_cast(data.data()), static_cast(data.size())); if (ret != kIOReturnSuccess) { if (ret == kIOUSBTransactionTimeout) @@ -263,19 +314,55 @@ std::vector usb_device::control_transfer_in(const usb_control_request& return data; } -const pipe_info* usb_device::get_pipe(int endpoint_address) { +const usb_device::pipe_info* usb_device::get_pipe(int endpoint_address) { auto it = std::find_if(pipes_.begin(), pipes_.end(), [endpoint_address](const pipe_info& pipe){ return pipe.endpoint_address == endpoint_address; }); - if (it != pipes_.end()) - return &*it; + if (it != pipes_.end()) { + const pipe_info* pi = &*it; + if (pi->transfer_type != usb_transfer_type::bulk && pi->transfer_type != usb_transfer_type::interrupt) + throw usb_error("invalid transfer type for endpoint"); + return pi; + } + + // good error message + for (usb_interface& intf : interfaces_) { + for (const usb_endpoint& ep : intf.alternate().endpoints()) { + int addr = ep.number(); + if (ep.direction() == usb_direction::in) + addr += 128; + if (addr == endpoint_address) + throw usb_error("endpoint's interface has not been claimed"); + } + } - throw usb_error("invalid endpoint number"); + throw usb_error("no such endpoint"); } - const pipe_info* usb_device::ep_out_pipe(int endpoint_number) { + const usb_device::pipe_info* usb_device::ep_out_pipe(int endpoint_number) { return get_pipe(endpoint_number); } - const pipe_info* usb_device::ep_in_pipe(int endpoint_number) { + const usb_device::pipe_info* usb_device::ep_in_pipe(int endpoint_number) { return get_pipe(endpoint_number + 128); } + +usb_interface* usb_device::get_interface(int interface_number) { + for (usb_interface& intf : interfaces_) + if (intf.number() == interface_number) + return &intf; + + return nullptr; +} + +int usb_device::get_alternate_index(int interface_number, int alternate_setting) { + for (usb_interface& intf : interfaces_) { + if (intf.number() == interface_number) { + for (int i = 0; i < intf.alternates().size(); i++) { + if (intf.alternates()[i].number() == alternate_setting) + return i; + } + } + } + + return -1; +} diff --git a/reference/macos/USB/usb_device.hpp b/reference/macos/USB/usb_device.hpp index 4ca1acca..a32baed2 100644 --- a/reference/macos/USB/usb_device.hpp +++ b/reference/macos/USB/usb_device.hpp @@ -12,11 +12,14 @@ #include #include +#include #include #include #include #include +#include "configuration.hpp" + /** * USB control request type. @@ -68,12 +71,6 @@ struct usb_control_request { } }; -struct pipe_info { - UInt8 pipe_index; - uint8_t endpoint_address; - uint8_t transfer_type; -}; - /** * USB device. @@ -96,7 +93,9 @@ class usb_device { std::string serial_number() const { return serial_number_; } /// Descriptive string including VID, PID, manufacturer, product name and serial number std::string description() const; - + /// List of interfaces + const std::vector& interfaces() const; + /// Opens the device for communication void open(); @@ -109,25 +108,26 @@ class usb_device { /** * Claims an interface * - * A single interface can be claimed. - * * @param interface_number interface number */ void claim_interface(int interface_number); /** - * Releases the claimed interface. + * Releases a claimed interface. + * + * @param interface_number interface number */ - void release_interface(); + void release_interface(int interface_number); /** * Select an alternate interface setting. * - * The affected interface must have been claimed. + * The interface must have been claimed. * - *@param alternate_setting alternate setting number + * @param interface_number interface number + * @param alternate_setting alternate setting number */ - void select_alternate_interface(int alternate_setting); + void select_alternate_interface(int interface_number, int alternate_setting); /** * Receives data from a bulk or interrupt endpoint. @@ -203,20 +203,31 @@ class usb_device { std::vector control_transfer_in(const usb_control_request& request, int timeout = 0); private: + struct pipe_info { + uint8_t pipe_index; + uint8_t endpoint_address; + usb_transfer_type transfer_type; + int interface_number; + }; + usb_device(io_service_t service, IOUSBDeviceInterface** device, uint64_t entry_id, int vendor_id, int product_id); uint64_t entry_id() const { return entry_id_; } - void build_pipe_info(IOUSBInterfaceInterface** intf); + void build_pipe_info(); const pipe_info* get_pipe(int endpoint_address); const pipe_info* ep_in_pipe(int endpoint_address); const pipe_info* ep_out_pipe(int endpoint_address); int control_transfer_core(const usb_control_request& request, uint8_t* data, int timeout); - + void load_configuration(IOUSBDeviceInterface** device); + usb_interface* get_interface(int interface_number); + int get_alternate_index(int interface_number, int alternate_setting); + uint64_t entry_id_; IOUSBDeviceInterface** device_; bool is_open_; - IOUSBInterfaceInterface** interface_; std::vector pipes_; - + std::map claimed_interfaces_; + std::vector interfaces_; + int product_id_; int vendor_id_; std::string manufacturer_; diff --git a/reference/macos/usb.xcodeproj/project.pbxproj b/reference/macos/usb.xcodeproj/project.pbxproj index 6028251f..a00db96b 100644 --- a/reference/macos/usb.xcodeproj/project.pbxproj +++ b/reference/macos/usb.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 64835E60290BCA9F00113E4E /* config_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64835E5D290BCA9F00113E4E /* config_parser.cpp */; }; + 64835E61290BCA9F00113E4E /* configuration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64835E5F290BCA9F00113E4E /* configuration.cpp */; }; 64937C6428D5EBF1009BD0C2 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64937C6328D5EBF1009BD0C2 /* main.cpp */; }; 64937C7228D5ED1F009BD0C2 /* usb_registry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64937C6B28D5ED1F009BD0C2 /* usb_registry.cpp */; }; 64937C7328D5ED1F009BD0C2 /* iokit_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64937C6C28D5ED1F009BD0C2 /* iokit_helper.cpp */; }; @@ -31,6 +33,10 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 64835E5C290BCA9F00113E4E /* configuration.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = configuration.hpp; sourceTree = ""; }; + 64835E5D290BCA9F00113E4E /* config_parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = config_parser.cpp; sourceTree = ""; }; + 64835E5E290BCA9F00113E4E /* config_parser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = config_parser.hpp; sourceTree = ""; }; + 64835E5F290BCA9F00113E4E /* configuration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = configuration.cpp; sourceTree = ""; }; 64937C6028D5EBF1009BD0C2 /* USB */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = USB; sourceTree = BUILT_PRODUCTS_DIR; }; 64937C6328D5EBF1009BD0C2 /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; 64937C6B28D5ED1F009BD0C2 /* usb_registry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = usb_registry.cpp; sourceTree = ""; }; @@ -83,6 +89,10 @@ 64937C6228D5EBF1009BD0C2 /* USB */ = { isa = PBXGroup; children = ( + 64835E5D290BCA9F00113E4E /* config_parser.cpp */, + 64835E5E290BCA9F00113E4E /* config_parser.hpp */, + 64835E5F290BCA9F00113E4E /* configuration.cpp */, + 64835E5C290BCA9F00113E4E /* configuration.hpp */, 64937C8328D71D31009BD0C2 /* assertion.hpp */, 64937C8228D71D31009BD0C2 /* assertion.cpp */, 64937C6D28D5ED1F009BD0C2 /* iokit_helper.hpp */, @@ -169,8 +179,10 @@ files = ( 64937C7328D5ED1F009BD0C2 /* iokit_helper.cpp in Sources */, 64937C8428D71D31009BD0C2 /* assertion.cpp in Sources */, + 64835E61290BCA9F00113E4E /* configuration.cpp in Sources */, 64937C7928D5FE6D009BD0C2 /* usb_device.cpp in Sources */, 64937C7228D5ED1F009BD0C2 /* usb_registry.cpp in Sources */, + 64835E60290BCA9F00113E4E /* config_parser.cpp in Sources */, 64937C6428D5EBF1009BD0C2 /* main.cpp in Sources */, 64937C7628D5ED8D009BD0C2 /* usb_error.cpp in Sources */, 64937C8128D6F9DE009BD0C2 /* tests.cpp in Sources */, diff --git a/reference/windows/USB/assertion.cpp b/reference/windows/USB/assertion.cpp index 4ffa1205..d3cb93c3 100644 --- a/reference/windows/USB/assertion.cpp +++ b/reference/windows/USB/assertion.cpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for Windows +// Reference C++ code common for Linux / macOS / Windows // #include "assertion.hpp" diff --git a/reference/windows/USB/assertion.hpp b/reference/windows/USB/assertion.hpp index 2e6f709c..a97dfa30 100644 --- a/reference/windows/USB/assertion.hpp +++ b/reference/windows/USB/assertion.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for Windows +// Reference C++ code common for Linux / macOS / Windows // #pragma once diff --git a/reference/windows/USB/config_parser.cpp b/reference/windows/USB/config_parser.cpp index a7276978..2d75f475 100644 --- a/reference/windows/USB/config_parser.cpp +++ b/reference/windows/USB/config_parser.cpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for Windows +// Reference C++ code common for Linux / macOS / Windows // #include "config_parser.hpp" @@ -102,12 +102,9 @@ struct usb_interface_association_desc { config_parser::config_parser() : configuration_value(0) { } -void config_parser::parse(const std::vector& config_desc) +void config_parser::parse(const uint8_t* config_desc, int desc_len) { - const uint8_t* desc = &config_desc[0]; - int desc_len = static_cast(config_desc.size()); - - const usb_config_desc* header = reinterpret_cast(desc); + const usb_config_desc* header = reinterpret_cast(config_desc); if (desc_len <= sizeof(usb_config_desc) || header->bDescriptorType != static_cast(usb_descriptor_type::configuration) || header->wTotalLength != desc_len) @@ -115,27 +112,27 @@ void config_parser::parse(const std::vector& config_desc) configuration_value = header->bConfigurationValue; - int offset = peek_desc_length(desc, 0); + int offset = peek_desc_length(config_desc, 0); usb_alternate_interface* last_alternate = nullptr; while (offset + 2 < desc_len) { - int len = peek_desc_length(desc, offset); - usb_descriptor_type type = peek_desc_type(desc, offset); + int len = peek_desc_length(config_desc, offset); + usb_descriptor_type type = peek_desc_type(config_desc, offset); if (offset + len > desc_len) break; if (type == usb_descriptor_type::interface_association) { - const usb_interface_association_desc* ia_desc = reinterpret_cast(desc + offset); + const usb_interface_association_desc* ia_desc = reinterpret_cast(config_desc + offset); functions.push_back(usb_composite_function(ia_desc->bFirstInterface, ia_desc->bInterfaceCount, ia_desc->bFunctionClass, ia_desc->bFunctionSubClass, ia_desc->bFunctionProtocol)); last_alternate = nullptr; } else if (type == usb_descriptor_type::interface) { - const usb_interface_desc* intf_desc = reinterpret_cast(desc + offset); + const usb_interface_desc* intf_desc = reinterpret_cast(config_desc + offset); int number = intf_desc->bInterfaceNumber; // If there is no interface with this number yet, it's a new interface @@ -160,7 +157,7 @@ void config_parser::parse(const std::vector& config_desc) if (last_alternate == nullptr) throw usb_error("invalid configuration descriptor"); - const usb_endpoint_desc* ep_desc = reinterpret_cast(desc + offset); + const usb_endpoint_desc* ep_desc = reinterpret_cast(config_desc + offset); last_alternate->add_endpoint(usb_endpoint(ep_desc->bEndpointAddress & 0x7f, static_cast(ep_desc->bEndpointAddress & 0x80), static_cast(ep_desc->bmAttributes & 0x03), ep_desc->wMaxPacketSize)); } @@ -170,9 +167,6 @@ void config_parser::parse(const std::vector& config_desc) if (offset != desc_len) throw usb_error("invalid configuration descriptor"); - - desc = nullptr; - desc_len = 0; } usb_interface* config_parser::get_interface(int number) { diff --git a/reference/windows/USB/config_parser.hpp b/reference/windows/USB/config_parser.hpp index 438ee657..04f6615c 100644 --- a/reference/windows/USB/config_parser.hpp +++ b/reference/windows/USB/config_parser.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for Windows +// Reference C++ code common for Linux / macOS / Windows // #pragma once @@ -18,7 +18,7 @@ class config_parser { public: config_parser(); - void parse(const std::vector& config_desc); + void parse(const uint8_t* config_desc, int desc_len); uint8_t configuration_value; diff --git a/reference/windows/USB/configuration.cpp b/reference/windows/USB/configuration.cpp index a0f2fe75..6e2e4f31 100644 --- a/reference/windows/USB/configuration.cpp +++ b/reference/windows/USB/configuration.cpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for Windows +// Reference C++ code common for Linux / macOS / Windows // #include "configuration.hpp" diff --git a/reference/windows/USB/configuration.hpp b/reference/windows/USB/configuration.hpp index b36f1421..91f22aed 100644 --- a/reference/windows/USB/configuration.hpp +++ b/reference/windows/USB/configuration.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for Windows +// Reference C++ code common for Linux / macOS / Windows // #pragma once @@ -145,4 +145,4 @@ struct usb_composite_function { int protocol_code_; friend class config_parser; -}; \ No newline at end of file +}; diff --git a/reference/windows/USB/main.cpp b/reference/windows/USB/main.cpp index a70bc471..cbb3747c 100644 --- a/reference/windows/USB/main.cpp +++ b/reference/windows/USB/main.cpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for Windows +// Reference C++ code common for Linux / macOS / Windows // #include "tests.hpp" diff --git a/reference/windows/USB/scope.hpp b/reference/windows/USB/scope.hpp index 55fdd505..85998dba 100644 --- a/reference/windows/USB/scope.hpp +++ b/reference/windows/USB/scope.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for Windows +// Reference C++ code common for Linux / macOS / Windows // #pragma once diff --git a/reference/windows/USB/tests.cpp b/reference/windows/USB/tests.cpp index e1f337ce..657195ef 100644 --- a/reference/windows/USB/tests.cpp +++ b/reference/windows/USB/tests.cpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for Windows +// Reference C++ code common for Linux / macOS / Windows // #include "tests.hpp" @@ -18,7 +18,7 @@ using random_ushort_engine = std::independent_bits_engine< - std::default_random_engine, CHAR_BIT, unsigned short>; + std::default_random_engine, 16, unsigned short>; void tests::run() { diff --git a/reference/windows/USB/tests.hpp b/reference/windows/USB/tests.hpp index 04a2ff88..344f495f 100644 --- a/reference/windows/USB/tests.hpp +++ b/reference/windows/USB/tests.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for Windows +// Reference C++ code common for Linux / macOS / Windows // #pragma once diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp index e61a281e..bb6596c8 100644 --- a/reference/windows/USB/usb_device.cpp +++ b/reference/windows/USB/usb_device.cpp @@ -18,7 +18,7 @@ usb_device::usb_device(std::wstring&& device_path, int vendor_id, int product_id : vendor_id_(vendor_id), product_id_(product_id), is_open_(false), device_path_(std::move(device_path)) { config_parser parser{}; - parser.parse(config_desc); + parser.parse(config_desc.data(), config_desc.size()); interfaces_ = std::move(parser.interfaces); functions_ = std::move(parser.functions); @@ -67,6 +67,10 @@ std::string usb_device::description() const { return desc; } +const std::vector& usb_device::interfaces() const { + return interfaces_; +} + bool usb_device::is_open() const { return is_open_; } diff --git a/reference/windows/USB/usb_device.hpp b/reference/windows/USB/usb_device.hpp index 1c8918dc..d26242a2 100644 --- a/reference/windows/USB/usb_device.hpp +++ b/reference/windows/USB/usb_device.hpp @@ -96,7 +96,9 @@ class usb_device { std::string serial_number() const { return serial_number_; } /// Descriptive string including VID, PID, manufacturer, product name and serial number std::string description() const; - + /// List of interfaces + const std::vector& interfaces() const; + /// Opens the device for communication void open(); @@ -109,8 +111,6 @@ class usb_device { /** * Claims an interface * - * A single interface can be claimed. - * * @param interface_number interface number */ void claim_interface(int interface_number); @@ -195,11 +195,6 @@ class usb_device { */ std::vector control_transfer_in(const usb_control_request& request, int timeout = 0); - /** - * Get the list of USB interfaces. - */ - const std::vector& interfaces() const { return interfaces_; } - private: struct interface_handle { int interface_num; From c642b41d34e0788c4f00723626e0f4a63b5d3224 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 28 Oct 2022 17:17:07 +0200 Subject: [PATCH 148/433] Enhanced Linux reference code --- reference/.vscode/settings.json | 60 +++++++++- reference/linux/CMakeLists.txt | 2 + reference/linux/assertion.cpp | 2 +- reference/linux/assertion.hpp | 2 +- reference/linux/config_parser.cpp | 189 ++++++++++++++++++++++++++++++ reference/linux/config_parser.hpp | 31 +++++ reference/linux/configuration.cpp | 50 ++++++++ reference/linux/configuration.hpp | 148 +++++++++++++++++++++++ reference/linux/main.cpp | 2 +- reference/linux/scope.hpp | 2 +- reference/linux/tests.cpp | 82 +++++++------ reference/linux/tests.hpp | 2 +- reference/linux/usb_device.cpp | 120 +++++++++++++++---- reference/linux/usb_device.hpp | 22 +++- reference/linux/usb_error.cpp | 2 +- reference/linux/usb_error.hpp | 6 +- reference/linux/usb_registry.cpp | 10 +- reference/linux/usb_registry.hpp | 2 +- reference/macos/USB/assertion.hpp | 1 + reference/macos/USB/usb_error.hpp | 4 +- 20 files changed, 656 insertions(+), 83 deletions(-) create mode 100644 reference/linux/config_parser.cpp create mode 100644 reference/linux/config_parser.hpp create mode 100644 reference/linux/configuration.cpp create mode 100644 reference/linux/configuration.hpp diff --git a/reference/.vscode/settings.json b/reference/.vscode/settings.json index a3b2b51f..de1cf8d1 100644 --- a/reference/.vscode/settings.json +++ b/reference/.vscode/settings.json @@ -1,5 +1,63 @@ { "files.associations": { - "vector": "cpp" + "vector": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "cinttypes": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "map": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "ratio": "cpp", + "regex": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "semaphore": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "typeinfo": "cpp" } } \ No newline at end of file diff --git a/reference/linux/CMakeLists.txt b/reference/linux/CMakeLists.txt index 925a2428..2682fa62 100644 --- a/reference/linux/CMakeLists.txt +++ b/reference/linux/CMakeLists.txt @@ -9,6 +9,8 @@ find_package(Threads REQUIRED) set(SOURCES assertion.cpp assertion.hpp + config_parser.cpp config_parser.hpp + configuration.cpp configuration.hpp main.cpp scope.hpp tests.cpp tests.hpp diff --git a/reference/linux/assertion.cpp b/reference/linux/assertion.cpp index 4e3111b5..71aef91f 100644 --- a/reference/linux/assertion.cpp +++ b/reference/linux/assertion.cpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code common for Linux / macOS / Windows // #include "assertion.hpp" diff --git a/reference/linux/assertion.hpp b/reference/linux/assertion.hpp index 1d763e13..75d089fd 100644 --- a/reference/linux/assertion.hpp +++ b/reference/linux/assertion.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code common for Linux / macOS / Windows // #pragma once diff --git a/reference/linux/config_parser.cpp b/reference/linux/config_parser.cpp new file mode 100644 index 00000000..66b13ec2 --- /dev/null +++ b/reference/linux/config_parser.cpp @@ -0,0 +1,189 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#include "config_parser.hpp" +#include "usb_error.hpp" +#include + + +// --- USB descriptor types + +enum class usb_descriptor_type : uint8_t { + configuration = 0x02, + string = 0x03, + interface = 0x04, + endpoint = 0x05, + interface_association = 0x0b +}; + + +// --- USB configuration descriptor + +#pragma pack(push, 1) + +struct usb_config_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; +}; + +#pragma pack(pop) + + +// --- USB interface descriptor + +#pragma pack(push, 1) + +struct usb_interface_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +}; + +#pragma pack(pop) + + +// --- USB interface association descriptor + +#pragma pack(push, 1) + +struct usb_interface_association_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bFirstInterface; + uint8_t bInterfaceCount; + uint8_t bFunctionClass; + uint8_t bFunctionSubClass; + uint8_t bFunctionProtocol; + uint8_t iFunction; +}; + +#pragma pack(pop) + + +// --- USB endpoint descriptor + +#pragma pack(push, 1) + + struct usb_endpoint_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; + }; + +#pragma pack(pop) + + +// --- Configuration parser + + static int peek_desc_length(const uint8_t* desc, int offset) { return desc[offset]; } + static usb_descriptor_type peek_desc_type(const uint8_t* desc, int offset) { return static_cast(desc[offset + 1]); } + + + config_parser::config_parser() + : configuration_value(0) { } + +void config_parser::parse(const uint8_t* config_desc, int desc_len) +{ + const usb_config_desc* header = reinterpret_cast(config_desc); + if (desc_len <= sizeof(usb_config_desc) + || header->bDescriptorType != static_cast(usb_descriptor_type::configuration) + || header->wTotalLength != desc_len) + throw usb_error("Invalid configuration descriptor"); + + configuration_value = header->bConfigurationValue; + + int offset = peek_desc_length(config_desc, 0); + usb_alternate_interface* last_alternate = nullptr; + + while (offset + 2 < desc_len) { + + int len = peek_desc_length(config_desc, offset); + usb_descriptor_type type = peek_desc_type(config_desc, offset); + + if (offset + len > desc_len) + break; + + if (type == usb_descriptor_type::interface_association) { + + const usb_interface_association_desc* ia_desc = reinterpret_cast(config_desc + offset); + functions.push_back(usb_composite_function(ia_desc->bFirstInterface, ia_desc->bInterfaceCount, + ia_desc->bFunctionClass, ia_desc->bFunctionSubClass, ia_desc->bFunctionProtocol)); + last_alternate = nullptr; + + } else if (type == usb_descriptor_type::interface) { + + const usb_interface_desc* intf_desc = reinterpret_cast(config_desc + offset); + int number = intf_desc->bInterfaceNumber; + + // If there is no interface with this number yet, it's a new interface + // and not just an additional alternate interface. + auto intf = get_interface(number); + if (intf == nullptr) { + interfaces.push_back(usb_interface(number)); + intf = &interfaces.back(); + } + + // add alternate interface + last_alternate = intf->add_alternate(usb_alternate_interface(intf_desc->bAlternateSetting, + intf_desc->bInterfaceClass, intf_desc->bInterfaceSubClass, intf_desc->bInterfaceProtocol)); + + // If there is no function for this interface, there was not preceeding IAD. + // So create a new function with a single interface. + if (get_function(intf->number()) == nullptr) + functions.push_back(usb_composite_function(intf->number(), 1, last_alternate->class_code(), last_alternate->subclass_code(), last_alternate->protocol_code())); + + } else if (type == usb_descriptor_type::endpoint) { + + if (last_alternate == nullptr) + throw usb_error("invalid configuration descriptor"); + + const usb_endpoint_desc* ep_desc = reinterpret_cast(config_desc + offset); + last_alternate->add_endpoint(usb_endpoint(ep_desc->bEndpointAddress & 0x7f, static_cast(ep_desc->bEndpointAddress & 0x80), + static_cast(ep_desc->bmAttributes & 0x03), ep_desc->wMaxPacketSize)); + } + + offset += len; + } + + if (offset != desc_len) + throw usb_error("invalid configuration descriptor"); +} + +usb_interface* config_parser::get_interface(int number) { + auto iter = std::find_if(interfaces.begin(), interfaces.end(), [number](const usb_interface& itf) { return itf.number() == number; }); + if (iter == interfaces.end()) + return nullptr; + + return &*iter; +} + +usb_composite_function* config_parser::get_function(int intf_number) { + auto iter = std::find_if(functions.begin(), functions.end(), [intf_number](const usb_composite_function& f) { + return intf_number >= f.first_interface() && intf_number < f.first_interface() + f.num_interfaces(); + }); + if (iter == functions.end()) + return nullptr; + + return &*iter; +} diff --git a/reference/linux/config_parser.hpp b/reference/linux/config_parser.hpp new file mode 100644 index 00000000..04f6615c --- /dev/null +++ b/reference/linux/config_parser.hpp @@ -0,0 +1,31 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#pragma once + +#include +#include "configuration.hpp" + +/// +/// Parses a USB configuration descriptor. +/// +class config_parser { +public: + config_parser(); + void parse(const uint8_t* config_desc, int desc_len); + + uint8_t configuration_value; + + std::vector interfaces; + std::vector functions; + +private: + usb_interface* get_interface(int number); + usb_composite_function* get_function(int intf_number); +}; diff --git a/reference/linux/configuration.cpp b/reference/linux/configuration.cpp new file mode 100644 index 00000000..6e2e4f31 --- /dev/null +++ b/reference/linux/configuration.cpp @@ -0,0 +1,50 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#include "configuration.hpp" + +// --- usb_endpoint + +usb_endpoint::usb_endpoint(int number, usb_direction direction, usb_transfer_type transfer_type, int packet_size) + : number_(number), direction_(direction), transfer_type_(transfer_type), packet_size_(packet_size) { } + + +// --- usb_alternate_interface + +usb_alternate_interface::usb_alternate_interface(int number, int class_code, int subclass_code, int protocol_code) + : number_(number), class_code_(class_code), subclass_code_(subclass_code), protocol_code_(protocol_code) { } + +void usb_alternate_interface::add_endpoint(usb_endpoint&& endpoint) { + endpoints_.push_back(std::move(endpoint)); +} + + +// --- usb_interface + +usb_interface::usb_interface(int number) + : number_(number), is_claimed_(false), alternate_index_(0) { } + +void usb_interface::set_claimed(bool claimed) { + is_claimed_ = claimed; +} + +usb_alternate_interface* usb_interface::add_alternate(usb_alternate_interface&& alternate) { + alternates_.push_back(std::move(alternate)); + return &alternates_.back(); +} + +void usb_interface::set_alternate(int index) { + alternate_index_ = index; +} + + +// --- usb_composite_function + +usb_composite_function::usb_composite_function(int first_interface, int num_interfaces, int class_code, int subclass_code, int protocol_code) + : first_interface_(first_interface), num_interfaces_(num_interfaces), class_code_(class_code), subclass_code_(subclass_code), protocol_code_(protocol_code) { } diff --git a/reference/linux/configuration.hpp b/reference/linux/configuration.hpp new file mode 100644 index 00000000..91f22aed --- /dev/null +++ b/reference/linux/configuration.hpp @@ -0,0 +1,148 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#pragma once + +#include +#include + +/// USB endpoint direction +enum class usb_direction : uint8_t { + /// Direction OUT: host to device + out = 0x00, + /// Direction IN: device to host + in = 0x80 +}; + +/// USB endpoint transfer type +enum class usb_transfer_type : uint8_t { + /// Control transfer + control = 0x00, + /// Isochronous transfer + isochronous = 0x01, + /// Bulk transfer + bulk = 0x02, + /// Interrupt transfer + interrupt = 0x03 +}; + +/// +/// USB endpoint +/// +struct usb_endpoint { +public: + /// Endpoint number + int number() const { return number_; } + /// Endpoint direction + usb_direction direction() const { return direction_; } + /// Endpoint transfer type + usb_transfer_type transfer_type() const { return transfer_type_; } + /// Maximum packet size + int packet_size() const { return packet_size_; } + +private: + usb_endpoint(int number, usb_direction direction, usb_transfer_type transfer_type, int packet_size); + + int number_; + usb_direction direction_; + usb_transfer_type transfer_type_; + int packet_size_; + + friend class config_parser; +}; + +/// +/// USB alternate interface +/// +struct usb_alternate_interface { +public: + /// Alternate number + int number() const { return number_; } + /// Interface class code + int class_code() const { return class_code_; } + /// Interface subclass code + int subclass_code() const { return subclass_code_; } + /// Interface protocol code + int protocol_code() const { return protocol_code_; } + /// List of endpoints + const std::vector& endpoints() const { return endpoints_; } + +private: + usb_alternate_interface(int number, int class_code, int subclass_code, int protocol_code); + void add_endpoint(usb_endpoint&& endpoint); + + int number_; + int class_code_; + int subclass_code_; + int protocol_code_; + std::vector endpoints_; + + friend class config_parser; +}; + +/// +/// USB interface +/// +struct usb_interface { +public: + /// Interface number + int number() const { return number_; } + /// Indicates if interface has been claimed + bool is_claimed() const { return is_claimed_; } + /// Currently selected alternate interface + const usb_alternate_interface& alternate() const { return alternates_[alternate_index_]; } + /// List of all alternate interfaces of this interfaces + const std::vector& alternates() const { return alternates_; } + +private: + usb_interface(int number); + void set_claimed(bool claimed); + usb_alternate_interface* add_alternate(usb_alternate_interface&& alternate); + void set_alternate(int index); + + int number_; + bool is_claimed_; + int alternate_index_; + std::vector alternates_; + + friend class config_parser; + friend class usb_device; +}; + +/// +/// USB composite function +/// +/// For a composite USB device, the composite function describes a single function. +/// A compsite function consists of a single or multiple consecutive interfaces. +/// +/// +struct usb_composite_function { +public: + /// Number of first interface + int first_interface() const { return first_interface_; } + /// Number of interfaces + int num_interfaces() const { return num_interfaces_; } + /// Function class code + int class_code() const { return class_code_; } + /// Function subclass code + int subclass_code() const { return subclass_code_; } + /// Function protocol code + int protocol_code() const { return protocol_code_; } + +private: + usb_composite_function(int first_interface, int num_interfaces, int class_code, int subclass_code, int protocol_code); + + int first_interface_; + int num_interfaces_; + int class_code_; + int subclass_code_; + int protocol_code_; + + friend class config_parser; +}; diff --git a/reference/linux/main.cpp b/reference/linux/main.cpp index 64e85de5..cbb3747c 100644 --- a/reference/linux/main.cpp +++ b/reference/linux/main.cpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code common for Linux / macOS / Windows // #include "tests.hpp" diff --git a/reference/linux/scope.hpp b/reference/linux/scope.hpp index 53e3e39f..85998dba 100644 --- a/reference/linux/scope.hpp +++ b/reference/linux/scope.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code common for Linux / macOS / Windows // #pragma once diff --git a/reference/linux/tests.cpp b/reference/linux/tests.cpp index 6b53c83f..144586f1 100644 --- a/reference/linux/tests.cpp +++ b/reference/linux/tests.cpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code common for Linux / macOS / Windows // #include "tests.hpp" @@ -20,14 +20,14 @@ using random_ushort_engine = std::independent_bits_engine< void tests::run() { registry.start(); - for (auto device : registry.get_devices()) { + for (auto& device : registry.get_devices()) { std::cout << "Present: " << device->description() << std::endl; } registry.set_on_device_connected([this](auto device) { on_device_connected(device); }); registry.set_on_device_disconnected([this](auto device) { on_device_disconnected(device); }); - for (auto device : registry.get_devices()) + for (auto& device : registry.get_devices()) on_device(device); std::cout << "Press RETURN to quit" << std::endl; @@ -36,53 +36,52 @@ void tests::run() { } void tests::test_current_device() { - std::cout << "Found test device" << std::endl; - test_device->open(); - test_device->claim_interface(0); - - test_control_transfers(); - test_bulk_transfers(); - - test_device->release_interface(); - test_device->close(); - std::cout << "Test completed" << std::endl; + try { + std::cout << "Found test device" << std::endl; + test_device->open(); + test_device->claim_interface(0); + + test_control_transfers(); + test_bulk_transfers(); + + test_device->release_interface(0); + test_device->close(); + std::cout << "Test completed" << std::endl; + } + catch (const std::exception& e) { + std::cout << "Test failed: " << e.what() << std::endl; + } } void tests::test_control_transfers() { - usb_control_request request_set_value_no_data = { - .bmRequestType = usb_control_request::request_type(usb_request_type::direction_out, - usb_request_type::type_vendor, - usb_request_type::recipient_interface), - .bRequest = 0x01, - .wValue = 0x9a41, - .wIndex = 0, // interface number - .wLength = 0 - }; + usb_control_request request_set_value_no_data = { 0 }; + request_set_value_no_data.bmRequestType = usb_control_request::request_type(usb_request_type::direction_out, + usb_request_type::type_vendor, usb_request_type::recipient_interface); + request_set_value_no_data.bRequest = 0x01; + request_set_value_no_data.wValue = 0x9a41; + request_set_value_no_data.wIndex = 0; // interface number + request_set_value_no_data.wLength = 0; test_device->control_transfer(request_set_value_no_data); - usb_control_request request_get_data = { - .bmRequestType = usb_control_request::request_type(usb_request_type::direction_in, - usb_request_type::type_vendor, - usb_request_type::recipient_interface), - .bRequest = 0x03, - .wValue = 0, - .wIndex = 0, // interface number - .wLength = 4 - }; + usb_control_request request_get_data = { 0 }; + request_get_data.bmRequestType = usb_control_request::request_type(usb_request_type::direction_in, + usb_request_type::type_vendor, usb_request_type::recipient_interface); + request_get_data.bRequest = 0x03; + request_get_data.wValue = 0; + request_get_data.wIndex = 0; // interface number + request_get_data.wLength = 4; auto data = test_device->control_transfer_in(request_get_data); std::vector expected_data{ 0x41, 0x9a, 0x00, 0x00 }; assert_equals(expected_data, data); std::vector sent_value{ 0x83, 0x03, 0xda, 0x3d }; - usb_control_request request_set_value_data = { - .bmRequestType = usb_control_request::request_type(usb_request_type::direction_out, - usb_request_type::type_vendor, - usb_request_type::recipient_interface), - .bRequest = 0x02, - .wValue = 0, - .wIndex = 0, // interface number - .wLength = static_cast(sent_value.size()) - }; + usb_control_request request_set_value_data = { 0 }; + request_set_value_data.bmRequestType = usb_control_request::request_type(usb_request_type::direction_out, + usb_request_type::type_vendor, usb_request_type::recipient_interface); + request_set_value_data.bRequest = 0x02; + request_set_value_data.wValue = 0; + request_set_value_data.wIndex = 0; // interface number + request_set_value_data.wLength = static_cast(sent_value.size()); test_device->control_transfer_out(request_set_value_data, sent_value); data = test_device->control_transfer_in(request_get_data); @@ -106,7 +105,7 @@ void tests::test_loopback(int num_bytes) { // read in separate thread std::thread reader([this, &rx_data, num_bytes]() { - int bytes_read = 0; + size_t bytes_read = 0; while (bytes_read < num_bytes) { auto data = test_device->transfer_in(2, 64); rx_data.insert(rx_data.end(), data.begin(), data.end()); @@ -156,7 +155,6 @@ std::vector tests::random_bytes(int num) { return std::vector(p, p + num); } - bool tests::is_test_device(usb_device_ptr device) { return device->vendor_id() == 0xcafe && device->product_id() == 0xceaf; } diff --git a/reference/linux/tests.hpp b/reference/linux/tests.hpp index 992de2b9..344f495f 100644 --- a/reference/linux/tests.hpp +++ b/reference/linux/tests.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code common for Linux / macOS / Windows // #pragma once diff --git a/reference/linux/usb_device.cpp b/reference/linux/usb_device.cpp index 711ad252..905d24ec 100644 --- a/reference/linux/usb_device.cpp +++ b/reference/linux/usb_device.cpp @@ -4,12 +4,13 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Linux // #include "usb_device.hpp" #include "usb_error.hpp" #include "scope.hpp" +#include "config_parser.hpp" #include #include @@ -17,9 +18,12 @@ #include #include +#include + usb_device::usb_device(const char* path, int vendor_id, int product_id) -: path_(path), fd_(-1), claimed_interface_(-1), vendor_id_(vendor_id), product_id_(product_id) { +: path_(path), fd_(-1), vendor_id_(vendor_id), product_id_(product_id) { + read_descriptor(); } usb_device::~usb_device() { @@ -27,6 +31,32 @@ usb_device::~usb_device() { close(); } +void usb_device::set_product_strings(const char* manufacturer, const char* product, const char* serial_number) { + manufacturer_ = manufacturer != nullptr ? manufacturer : ""; + product_ = product != nullptr ? product : ""; + serial_number_ = serial_number != nullptr ? serial_number : ""; +} + +void usb_device::read_descriptor() { + // read device and configuration descriptor + std::vector descriptors{}; + { + std::ifstream file(path(), std::ios::binary); + uint8_t buf[256]; + while (!file.eof()) { + file.read(reinterpret_cast(buf), sizeof(buf)); + if (file.bad()) + throw usb_error("failed to read device and configuration descriptor"); + descriptors.insert(descriptors.end(), buf, buf + file.gcount()); + } + } + + int config_desc_offset = descriptors[0]; + config_parser parser{}; + parser.parse(descriptors.data() + config_desc_offset, descriptors.size() - config_desc_offset); + interfaces_ = std::move(parser.interfaces); +} + std::string usb_device::description() const { const char* fmt = "VID: 0x%04x, PID: 0x%04x, manufacturer: %s, product: %s, serial: %s"; @@ -41,6 +71,10 @@ std::string usb_device::description() const { return desc; } +const std::vector& usb_device::interfaces() const { + return interfaces_; +} + bool usb_device::is_open() const { return fd_ >= 0; } @@ -57,10 +91,12 @@ void usb_device::open() { void usb_device::close() { if (!is_open()) return; + + for (auto& intf : interfaces_) + intf.set_claimed(false); - if (claimed_interface_ >= 0) - release_interface(); - + claimed_interfaces_.clear(); + int ret = ::close(fd_); fd_ = -1; if (ret != 0) @@ -68,31 +104,48 @@ void usb_device::close() { } void usb_device::claim_interface(int interface_number) { - - if (claimed_interface_ >= 0) - throw usb_error("an interface has already been claimed"); + + if (!is_open()) + throw usb_error("device is not open"); + + usb_interface* intf = get_interface(interface_number); + if (intf == nullptr) + throw usb_error("no such interface"); + + if (intf->is_claimed()) + throw usb_error("interface has already been claimed"); int result = ioctl(fd_, USBDEVFS_CLAIMINTERFACE, &interface_number); if (result < 0) - usb_error::throw_error("Failed to claim interface 0"); + usb_error::throw_error("Failed to claim interface"); - claimed_interface_ = interface_number; + claimed_interfaces_.insert(interface_number); + intf->set_claimed(true); } -void usb_device::release_interface() { - if (claimed_interface_ < 0) - throw usb_error("no interface has been claimed"); - - int result = ioctl(fd_, USBDEVFS_RELEASEINTERFACE, &claimed_interface_); +void usb_device::release_interface(int interface_number) { + + if (!is_open()) + throw usb_error("device is not open"); + + usb_interface* intf = get_interface(interface_number); + if (intf == nullptr) + throw usb_error("no such interface"); + + if (!intf->is_claimed()) + throw usb_error("interface has not been claimed"); + + int result = ioctl(fd_, USBDEVFS_RELEASEINTERFACE, &interface_number); if (result < 0) usb_error::throw_error("Failed to release interface"); - claimed_interface_ = -1; + intf->set_claimed(false); + claimed_interfaces_.erase(interface_number); } std::vector usb_device::transfer_in(int endpoint_number, int data_len, int timeout) { - if (claimed_interface_ < 0) - throw usb_error("no interface has been claimed"); + + check_endpoint(usb_direction::in, endpoint_number); std::vector data(data_len); @@ -111,8 +164,8 @@ std::vector usb_device::transfer_in(int endpoint_number, int data_len, } void usb_device::transfer_out(int endpoint_number, const std::vector& data, int timeout) { - if (claimed_interface_ < 0) - throw usb_error("no interface has been claimed"); + + check_endpoint(usb_direction::out, endpoint_number); struct usbdevfs_bulktransfer transfer = {0}; transfer.ep = endpoint_number; @@ -169,3 +222,30 @@ std::vector usb_device::control_transfer_in(const usb_control_request& data.resize(request.wLength); return data; } + +usb_interface* usb_device::get_interface(int number) { + for (auto& intf : interfaces_) + if (intf.number() == number) + return &intf; + return nullptr; +} + +const usb_endpoint* usb_device::check_endpoint(usb_direction direction, int endpoint_number) { + + if (!is_open()) + throw usb_error("device is not open"); + + for (auto& intf : interfaces_) { + for (auto& ep : intf.alternate().endpoints()) { + if (ep.direction() == direction && ep.number() == endpoint_number) { + if (!intf.is_claimed()) + throw usb_error("interface has not been claimed"); + if (ep.transfer_type() != usb_transfer_type::bulk && ep.transfer_type() != usb_transfer_type::interrupt) + throw usb_error("invalid endpoint transfer type for operation"); + return &ep; + } + } + } + + throw usb_error("no such endpoint"); +} diff --git a/reference/linux/usb_device.hpp b/reference/linux/usb_device.hpp index 30a27445..e9048ace 100644 --- a/reference/linux/usb_device.hpp +++ b/reference/linux/usb_device.hpp @@ -4,16 +4,19 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Linux // #pragma once #include +#include #include #include #include +#include "configuration.hpp" + /** * USB control request type. @@ -87,6 +90,8 @@ class usb_device { std::string serial_number() const { return serial_number_; } /// Descriptive string including VID, PID, manufacturer, product name and serial number std::string description() const; + /// List of interfaces + const std::vector& interfaces() const; /// Opens the device for communication void open(); @@ -100,16 +105,16 @@ class usb_device { /** * Claims an interface * - * A single interface can be claimed. - * * @param interface_number interface number */ void claim_interface(int interface_number); /** - * Releases the claimed interface. + * Releases a claimed interface. + * + * @param interface_number interface number */ - void release_interface(); + void release_interface(int interface_number); /** * Receives data from a bulk or interrupt endpoint. @@ -186,12 +191,17 @@ class usb_device { private: usb_device(const char* path, int vendor_id, int product_id); + void set_product_strings(const char* manufacturer, const char* product, const char* serial_number); const char* path() const { return path_.c_str(); } int control_transfer_core(const usb_control_request& request, uint8_t* data, int timeout); + void read_descriptor(); + usb_interface* get_interface(int number); + const usb_endpoint* check_endpoint(usb_direction direction, int endpoint_number); std::string path_; int fd_; - int claimed_interface_; + std::set claimed_interfaces_; + std::vector interfaces_; int product_id_; int vendor_id_; diff --git a/reference/linux/usb_error.cpp b/reference/linux/usb_error.cpp index 8228ba2d..6bcc5003 100644 --- a/reference/linux/usb_error.cpp +++ b/reference/linux/usb_error.cpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Linux // #include "usb_error.hpp" diff --git a/reference/linux/usb_error.hpp b/reference/linux/usb_error.hpp index f1a846db..e3a6553c 100644 --- a/reference/linux/usb_error.hpp +++ b/reference/linux/usb_error.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Linux // #pragma once @@ -18,8 +18,8 @@ class usb_error : public std::exception { /** * Creates a new instance. * - *@param message error message - *@param code a Mach error code, or 0 if no Mach code is available + * @param message error message + * @param code a Mach error code, or 0 if no Mach code is available */ usb_error(const char* message, int code = 0) noexcept; diff --git a/reference/linux/usb_registry.cpp b/reference/linux/usb_registry.cpp index 784ea172..d1e04a54 100644 --- a/reference/linux/usb_registry.cpp +++ b/reference/linux/usb_registry.cpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Linux // #include "usb_registry.hpp" @@ -224,5 +224,11 @@ std::shared_ptr usb_registry::create_device(udev_device* udev_dev) { if (vendor_id == 0 || product_id == 0) return nullptr; - return std::shared_ptr(new usb_device(path, vendor_id, product_id)); + std::shared_ptr device(new usb_device(path, vendor_id, product_id)); + device->set_product_strings( + udev_device_get_sysattr_value(udev_dev, "manufacturer"), + udev_device_get_sysattr_value(udev_dev, "product"), + udev_device_get_sysattr_value(udev_dev, "serial") + ); + return device; } diff --git a/reference/linux/usb_registry.hpp b/reference/linux/usb_registry.hpp index c17384d2..e4dda808 100644 --- a/reference/linux/usb_registry.hpp +++ b/reference/linux/usb_registry.hpp @@ -4,7 +4,7 @@ // Licensed under MIT License // https://opensource.org/licenses/MIT // -// Reference C++ code for macOS +// Reference C++ code for Linux // #pragma once diff --git a/reference/macos/USB/assertion.hpp b/reference/macos/USB/assertion.hpp index a6ed23b6..75d089fd 100644 --- a/reference/macos/USB/assertion.hpp +++ b/reference/macos/USB/assertion.hpp @@ -9,6 +9,7 @@ #pragma once +#include #include #include diff --git a/reference/macos/USB/usb_error.hpp b/reference/macos/USB/usb_error.hpp index 83c35739..895ea33c 100644 --- a/reference/macos/USB/usb_error.hpp +++ b/reference/macos/USB/usb_error.hpp @@ -18,8 +18,8 @@ class usb_error : public std::exception { /** * Creates a new instance. * - *@param message error message - *@param code a Mach error code, or 0 if no Mach code is available + * @param message error message + * @param code a Mach error code, or 0 if no Mach code is available */ usb_error(const char* message, int code = 0) noexcept; From 86208ee30bbc351822e78db7d383105286169a47 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 29 Oct 2022 10:08:10 +0200 Subject: [PATCH 149/433] Fix bug in test device --- .../loopback-stm32/src/vendor_custom.c | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/test-devices/loopback-stm32/src/vendor_custom.c b/test-devices/loopback-stm32/src/vendor_custom.c index 8e41d6ac..18819811 100644 --- a/test-devices/loopback-stm32/src/vendor_custom.c +++ b/test-devices/loopback-stm32/src/vendor_custom.c @@ -136,16 +136,20 @@ bool cv_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const TU_VERIFY(TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type); if (request->bRequest == TUSB_REQ_GET_INTERFACE) { - tud_control_xfer(rhport, request, &cv_alternate_setting, 1); - return true; + if (stage == CONTROL_STAGE_SETUP) { + tud_control_xfer(rhport, request, &cv_alternate_setting, 1); + } + return true; // indicate that request has been handled } else if (request->bRequest == TUSB_REQ_SET_INTERFACE) { - uint8_t alt_num = request->wValue; - setup_endpoints(0, cv_intf_desc, cv_intf_desc_len, alt_num); - if (cust_vendor_alt_intf_selected_cb != NULL) - cust_vendor_alt_intf_selected_cb((uint8_t) request->wIndex, alt_num); - tud_control_status(rhport, request); - return true; + if (stage == CONTROL_STAGE_SETUP) { + uint8_t alt_num = request->wValue; + setup_endpoints(0, cv_intf_desc, cv_intf_desc_len, alt_num); + if (cust_vendor_alt_intf_selected_cb != NULL) + cust_vendor_alt_intf_selected_cb((uint8_t) request->wIndex, alt_num); + tud_control_status(rhport, request); + } + return true; // indicate that request has been handled } else if (request->bRequest == TUSB_REQ_CLEAR_FEATURE && request->wValue == TUSB_REQ_FEATURE_EDPT_HALT @@ -153,7 +157,7 @@ bool cv_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const && cust_vendor_halt_cleared_cb != NULL) { uint8_t const ep_addr = tu_u16_low(request->wIndex); cust_vendor_halt_cleared_cb(ep_addr); - return true; + return true; // ignored by caller } return false; From 8ea10b564b6603b2a6e4a64d8339070a2f8cb013 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 29 Oct 2022 10:16:08 +0200 Subject: [PATCH 150/433] Improve robustness of Windows reference code --- reference/windows/USB/usb_device.cpp | 2 +- reference/windows/USB/usb_device_info.cpp | 17 +++-- reference/windows/USB/usb_error.cpp | 2 + reference/windows/USB/usb_registry.cpp | 84 ++++++++++++++--------- 4 files changed, 66 insertions(+), 39 deletions(-) diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp index bb6596c8..647ba804 100644 --- a/reference/windows/USB/usb_device.cpp +++ b/reference/windows/USB/usb_device.cpp @@ -18,7 +18,7 @@ usb_device::usb_device(std::wstring&& device_path, int vendor_id, int product_id : vendor_id_(vendor_id), product_id_(product_id), is_open_(false), device_path_(std::move(device_path)) { config_parser parser{}; - parser.parse(config_desc.data(), config_desc.size()); + parser.parse(config_desc.data(), static_cast(config_desc.size())); interfaces_ = std::move(parser.interfaces); functions_ = std::move(parser.functions); diff --git a/reference/windows/USB/usb_device_info.cpp b/reference/windows/USB/usb_device_info.cpp index 2cf73039..a2fe48d8 100644 --- a/reference/windows/USB/usb_device_info.cpp +++ b/reference/windows/USB/usb_device_info.cpp @@ -65,6 +65,8 @@ std::vector usb_device_info::get_device_property_variable_length(HDEVIN DEVPROPTYPE property_type; if (!SetupDiGetDevicePropertyW(dev_info, dev_info_data, prop_key, &property_type, nullptr, 0, &required_size, 0)) { DWORD err = GetLastError(); + if (err == ERROR_NOT_FOUND) + return {}; if (err != ERROR_INSUFFICIENT_BUFFER) throw usb_error("internal error (SetupDiGetDevicePropertyW)", err); } @@ -85,11 +87,15 @@ std::vector usb_device_info::get_device_property_variable_length(HDEVIN std::wstring usb_device_info::get_device_property_string(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { auto property_value = get_device_property_variable_length(dev_info, dev_info_data, prop_key, DEVPROP_TYPE_STRING); + if (property_value.size() == 0) + return L""; return std::wstring(reinterpret_cast(&property_value[0])); } std::vector usb_device_info::get_device_property_string_list(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { auto property_value = get_device_property_variable_length(dev_info, dev_info_data, prop_key, DEVPROP_TYPE_STRING | DEVPROP_TYPEMOD_LIST); + if (property_value.size() == 0) + return {}; return split_string_list(reinterpret_cast(&property_value[0])); } @@ -105,7 +111,7 @@ std::vector usb_device_info::split_string_list(const wchar_t* str_ } std::vector usb_device_info::get_descriptor(HANDLE hub_handle, ULONG usb_port_num, uint16_t descriptor_type, int index, int language_id, int request_size) { - int size = sizeof(USB_DESCRIPTOR_REQUEST) + (request_size != 0 ? request_size : 256); + int size = sizeof(USB_DESCRIPTOR_REQUEST) + (request_size != 0 ? request_size : 255); uint8_t* descriptor_request_buffer = new uint8_t[size]; auto dev_info_set_guard = make_scope_exit([descriptor_request_buffer]() { delete[] descriptor_request_buffer; @@ -124,6 +130,10 @@ std::vector usb_device_info::get_descriptor(HANDLE hub_handle, ULONG us DWORD bytesReturned = 0; if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, descriptor_request, size, descriptor_request, size, &bytesReturned, nullptr)) throw usb_error("Cannot retrieve descriptor (DeviceIoControl)", GetLastError()); + int data_size = bytesReturned - sizeof(USB_DESCRIPTOR_REQUEST); + + if (data_size <= 2) + throw usb_error("invalid descriptor"); // determine expected size of descriptor int expected_size; @@ -136,8 +146,7 @@ std::vector usb_device_info::get_descriptor(HANDLE hub_handle, ULONG us } // check against effective size - int effective_size = bytesReturned - sizeof(USB_DESCRIPTOR_REQUEST); - if (effective_size < expected_size) { + if (data_size < expected_size) { if (request_size != 0) throw usb_error("Unexpected descriptor size"); @@ -145,7 +154,7 @@ std::vector usb_device_info::get_descriptor(HANDLE hub_handle, ULONG us return get_descriptor(hub_handle, usb_port_num, descriptor_type, index, language_id, expected_size); } - return std::vector(descriptor_request->Data, descriptor_request->Data + effective_size); + return std::vector(descriptor_request->Data, descriptor_request->Data + data_size); } std::string usb_device_info::get_string(HANDLE hub_handle, ULONG usb_port_num, int index) { diff --git a/reference/windows/USB/usb_error.cpp b/reference/windows/USB/usb_error.cpp index 7fdd7329..c57e0a8b 100644 --- a/reference/windows/USB/usb_error.cpp +++ b/reference/windows/USB/usb_error.cpp @@ -37,6 +37,8 @@ std::string usb_error::full_message(const char* message, int code) { size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, code, 0, (LPSTR)&messageBuffer, 0, NULL); + while (size > 0 && (messageBuffer[size - 1] == L'\r' || messageBuffer[size - 1] == '\n')) + size--; std::string msg(message); msg += " ("; diff --git a/reference/windows/USB/usb_registry.cpp b/reference/windows/USB/usb_registry.cpp index 11fcec07..1076cc8f 100644 --- a/reference/windows/USB/usb_registry.cpp +++ b/reference/windows/USB/usb_registry.cpp @@ -277,42 +277,50 @@ bool usb_registry::handle_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lP DEV_BROADCAST_DEVICEINTERFACE_W* broadcast = reinterpret_cast(lParam); if (wParam == DBT_DEVICEARRIVAL) { on_device_connected(broadcast->dbcc_name); - } - else { + } else { on_device_disconnected(broadcast->dbcc_name); } return true; } void usb_registry::on_device_connected(const WCHAR* path) { - // get as set of all USB devices present - HDEVINFO dev_info_set_hdl = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); - if (dev_info_set_hdl == INVALID_HANDLE_VALUE) - usb_error::throw_error("internal error (SetupDiGetClassDevsW)"); - // ensure the result is destroyed when the scope is left - auto dev_info_set_guard = make_scope_exit([dev_info_set_hdl]() { - SetupDiDestroyDeviceInfoList(dev_info_set_hdl); - }); + usb_device_ptr device; + try { + // get as set of all USB devices present + HDEVINFO dev_info_set_hdl = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (dev_info_set_hdl == INVALID_HANDLE_VALUE) + usb_error::throw_error("internal error (SetupDiGetClassDevsW)"); - SP_DEVICE_INTERFACE_DATA dev_intf_data = { sizeof(dev_intf_data) }; - if (!SetupDiOpenDeviceInterfaceW(dev_info_set_hdl, path, 0, &dev_intf_data)) - usb_error::throw_error("internal error (SetupDiOpenDeviceInterfaceW)"); + // ensure the result is destroyed when the scope is left + auto dev_info_set_guard = make_scope_exit([dev_info_set_hdl]() { + SetupDiDestroyDeviceInfoList(dev_info_set_hdl); + }); - auto dev_intf_data_guard = make_scope_exit([dev_info_set_hdl, &dev_intf_data]() { - SetupDiDeleteDeviceInterfaceData(dev_info_set_hdl, &dev_intf_data); - }); + SP_DEVICE_INTERFACE_DATA dev_intf_data = { sizeof(dev_intf_data) }; + if (!SetupDiOpenDeviceInterfaceW(dev_info_set_hdl, path, 0, &dev_intf_data)) + usb_error::throw_error("internal error (SetupDiOpenDeviceInterfaceW)"); - SP_DEVINFO_DATA dev_info = { sizeof(dev_info) }; - if (!SetupDiGetDeviceInterfaceDetailW(dev_info_set_hdl, &dev_intf_data, nullptr, 0, nullptr, &dev_info)) { - DWORD err = GetLastError(); - if (err != ERROR_INSUFFICIENT_BUFFER) - throw usb_error("internal error (SetupDiGetDeviceInterfaceDetailW)", err); - } + auto dev_intf_data_guard = make_scope_exit([dev_info_set_hdl, &dev_intf_data]() { + SetupDiDeleteDeviceInterfaceData(dev_info_set_hdl, &dev_intf_data); + }); - // create new device - auto device = create_device(dev_info_set_hdl, &dev_info); - devices.push_back(device); + SP_DEVINFO_DATA dev_info = { sizeof(dev_info) }; + if (!SetupDiGetDeviceInterfaceDetailW(dev_info_set_hdl, &dev_intf_data, nullptr, 0, nullptr, &dev_info)) { + DWORD err = GetLastError(); + if (err != ERROR_INSUFFICIENT_BUFFER) + throw usb_error("internal error (SetupDiGetDeviceInterfaceDetailW)", err); + } + + // create new device + device = create_device(dev_info_set_hdl, &dev_info); + devices.push_back(device); + } + catch (const std::exception& e) { + std::cerr << "Exception while connecting device: " << e.what() << std::endl; + std::cerr << "Ignoring." << std::endl; + return; + } // Call callback function if (on_connected_callback != nullptr) { @@ -320,24 +328,32 @@ void usb_registry::on_device_connected(const WCHAR* path) { on_connected_callback(device); } catch (const std::exception& e) { - std::cerr << "Unhandled exception: " << e.what() << std::endl; + std::cerr << "Unhandled exception in callback: " << e.what() << std::endl; } catch (...) { - std::cerr << "Unhandled exception (not derived from std::exception)" << std::endl; + std::cerr << "Unhandled exception in callback (not derived from std::exception)" << std::endl; } } } void usb_registry::on_device_disconnected(const WCHAR* path) { - // find device in device list - auto it = std::find_if(devices.cbegin(), devices.cend(), [path](auto device) { return lstrcmpiW(path, device->device_path_.c_str()) == 0; }); - if (it == devices.cend()) - return; // not part of the device list + usb_device_ptr device; + try { + // find device in device list + auto it = std::find_if(devices.cbegin(), devices.cend(), [path](auto device) { return lstrcmpiW(path, device->device_path_.c_str()) == 0; }); + if (it == devices.cend()) + return; // not part of the device list - // remove from device list - usb_device_ptr device = *it; - devices.erase(it); + // remove from device list + device = *it; + devices.erase(it); + } + catch (const std::exception& e) { + std::cerr << "Exception while disconnecting device: " << e.what() << std::endl; + std::cerr << "Ignoring." << std::endl; + return; + } // call callback function if (on_disconnected_callback != nullptr) { From b2cd0675d169c95a4aae4ddf07bfd8054ca601b5 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Wed, 2 Nov 2022 20:57:58 +0100 Subject: [PATCH 151/433] Test device with USB high speed --- .../java/net/codecrete/usb/USBDevice.java | 10 + .../codecrete/usb/common/USBDeviceImpl.java | 11 + .../net/codecrete/usb/BulkTransferTest.java | 5 +- .../net/codecrete/usb/DescriptionTest.java | 10 +- .../java/net/codecrete/usb/TimeoutTest.java | 2 +- .../loopback-stm32/bin/blackpill-f401cc.bin | Bin 10616 -> 10724 bytes .../loopback-stm32/bin/blackpill-f411ce.bin | Bin 10620 -> 10728 bytes .../loopback-stm32/bin/bluepill-f103c8.bin | Bin 8868 -> 8972 bytes .../loopback-stm32/bin/disco_f723ie.bin | Bin 0 -> 11396 bytes .../lib/{config => tinyusb}/tusb_config.h | 0 test-devices/loopback-stm32/platformio.ini | 10 + test-devices/loopback-stm32/save_firmware.sh | 1 + test-devices/loopback-stm32/src/board_f1.c | 2 +- test-devices/loopback-stm32/src/board_f4.c | 2 +- test-devices/loopback-stm32/src/board_f7.c | 302 ++++++++++++++++++ test-devices/loopback-stm32/src/main.c | 17 +- .../loopback-stm32/src/usb_descriptors.c | 82 ++++- .../loopback-stm32/src/usb_descriptors.h | 1 - .../loopback-stm32/src/vendor_custom.c | 30 +- .../loopback-stm32/src/vendor_custom.h | 9 + 20 files changed, 463 insertions(+), 31 deletions(-) create mode 100755 test-devices/loopback-stm32/bin/disco_f723ie.bin rename test-devices/loopback-stm32/lib/{config => tinyusb}/tusb_config.h (100%) create mode 100644 test-devices/loopback-stm32/src/board_f7.c diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index 6ae61af8..a0f28721 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -125,11 +125,21 @@ public interface USBDevice { /** * Gets the interface with the specified number. + * * @param interfaceNumber the interface number * @return the interface, or {@code null} if no interface with the given number exists */ USBInterface getInterface(int interfaceNumber); + /** + * Gets the endpoint with the specified number. + * + * @param direction the endpoint direction + * @param endpointNumber the endpoint number (between 1 and 127) + * @return the endpoint, or {@code null} if no endpoint with the given direction and number exists + */ + USBEndpoint getEndpoint(USBDirection direction, int endpointNumber); + /** * Claims the specified interface for exclusive use. * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 74e063dd..9921cdff 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -210,6 +210,17 @@ public USBInterfaceImpl getInterface(int interfaceNumber) { return (USBInterfaceImpl) interfaces_.stream().filter((intf) -> intf.number() == interfaceNumber).findFirst().orElse(null); } + @Override + public USBEndpoint getEndpoint(USBDirection direction, int endpointNumber) { + for (var intf : interfaces_) { + for (var endpoint : intf.alternate().endpoints()) { + if (endpoint.direction() == direction && endpoint.number() == endpointNumber) + return endpoint; + } + } + return null; + } + /** * Checks if the specified endpoint is valid for communication and returns the endpoint address. * diff --git a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java index 62b46b27..7e53460b 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java @@ -39,8 +39,9 @@ void mediumTransfer_succeeds() { @Test void transferWithZLP_succeeds() { - byte[] sampleData = generateRandomBytes(64, 97333894); - writeBytes(sampleData); + var inEndpoint = testDevice.getEndpoint(USBDirection.IN, LOOPBACK_EP_IN); + byte[] sampleData = generateRandomBytes(inEndpoint.packetSize(), 97333894); + testDevice.transferOut(LOOPBACK_EP_OUT, sampleData); byte[] data = testDevice.transferIn(LOOPBACK_EP_IN); assertArrayEquals(sampleData, data); data = testDevice.transferIn(LOOPBACK_EP_IN); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index d9fb79d9..2393d69a 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -44,7 +44,7 @@ void deviceInfo_isCorrect() { assertEquals(0, testDevice.deviceVersion().major()); assertEquals(isComposite ? 3 : 7, testDevice.deviceVersion().minor()); - assertEquals(isComposite ? 6 : 3, testDevice.deviceVersion().subminor()); + assertEquals(isComposite ? 6 : 4, testDevice.deviceVersion().subminor()); } @Test @@ -91,13 +91,13 @@ void endpointDescriptors_areCorrect() { assertEquals(1, endpoint.number()); assertEquals(USBDirection.OUT, endpoint.direction()); assertEquals(USBTransferType.BULK, endpoint.transferType()); - assertEquals(64, endpoint.packetSize()); + assertTrue(endpoint.packetSize() == 64 || endpoint.packetSize() == 512); endpoint = altIntf.endpoints().get(1); assertEquals(2, endpoint.number()); assertEquals(USBDirection.IN, endpoint.direction()); assertEquals(USBTransferType.BULK, endpoint.transferType()); - assertEquals(64, endpoint.packetSize()); + assertTrue(endpoint.packetSize() == 64 || endpoint.packetSize() == 512); if (isLoopbackDevice()) { endpoint = altIntf.endpoints().get(2); @@ -120,13 +120,13 @@ void endpointDescriptors_areCorrect() { assertEquals(1, endpoint.number()); assertEquals(USBDirection.OUT, endpoint.direction()); assertEquals(USBTransferType.BULK, endpoint.transferType()); - assertEquals(64, endpoint.packetSize()); + assertTrue(endpoint.packetSize() == 64 || endpoint.packetSize() == 512); endpoint = altIntf.endpoints().get(1); assertEquals(2, endpoint.number()); assertEquals(USBDirection.IN, endpoint.direction()); assertEquals(USBTransferType.BULK, endpoint.transferType()); - assertEquals(64, endpoint.packetSize()); + assertTrue(endpoint.packetSize() == 64 || endpoint.packetSize() == 512); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java index c4dac1de..79645270 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java @@ -47,7 +47,7 @@ void bulkTransferOut_timesOut() { testDevice.transferOut(LOOPBACK_EP_OUT, data, 200); assertThrows(USBTimeoutException.class, () -> { - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 50; i++) { testDevice.transferOut(LOOPBACK_EP_OUT, data, 200); } }); diff --git a/test-devices/loopback-stm32/bin/blackpill-f401cc.bin b/test-devices/loopback-stm32/bin/blackpill-f401cc.bin index 2f8fcc6e86ce3b2831a4e0e0d25ac231104f1d79..faebe40689bfbc6d616dd4a93e53dcac150a8dbf 100755 GIT binary patch delta 2085 zcmZuyeQaA-6+id+>$$O$7duXD$7!D9(l|8>Swg`mLP_2B#i`q5qm$UQLcA7K^U>jH zL%15nA>On|8*0a$gw}~|8AZwjRpWS;>MpJe6Y5}eu@DyM(3+Er*%jDtijE`<9*`|*Wv5lU49$n$8aHE)lSH$hvh7AwZC zOm+-4##ZA6l&%<2I=vc!HzJdzHbr=u-#xx+oRaS8TVl-#2$|A1%`wZMH<7{Xkqc6r zanOL&-~}knqmu>162g*)ZA^b*4PGLF;eW&7xs>7Ye5?Q2+pO>*37Te;17ktsY$j+$is|ek z(>)~JKbS9OqS`-EKR#s&U?(a=hU*-{Fk|Zj6>(2RSPEf z%e&^7U)dTDDj%1LoWzDEaOk2qaGRbtJ!a^MvG#IoCZ9S4}7{zdN>d&ryg+hTkA zVbthCBnOfMq9W!!$~#uWEYq*85m_uUJ-fDAzHd<<{`}C#m3K$S6ua_@a?)*6W+LL% zc=PBq1ivu5J=PN69&?ZGxOF6D4Bb|bVB0nIjnr>arz1=1OBKVZ>w8UV5007dMoTPH zfvG^sx5pQoiF}m);Bd;c<3siO-hk>?9#9AcEmRoeLS_LQ&dTZQLRxt z`#P}O%Z$jCVohfwa#z&vk2mad4LZiHiTUY(!u0PlM=X$?9QP}irkVc4T89!wowwP1 znRM2viSb0iptTx=&`s4Eh2US)vy7R((5(ty(Ved(hfvn7+C`o?=YIpELwcN5~B#n{FLC^i0H{ z8uxWqoFElR&u3*DFA*;XFAY_;93px8t1TJNlWRdm;8lNa-g{>HW;uesq6*QD(!QE3 zsimLR93W-dXFEYAY0>r-@_bIWWeE8reY*CF06?R4vULUHoI3#o3EsaMdbWOm6zQG% zM{#}75x_O;@Y0ix7NpKPdU0KJgh-OQoR1J6{ekmY@+7_E%xoWS0`aSejt0cN-R=VM zJB=H>cBFe<^wow#sC>7fk95*r*F*~sjR)WoLF54pVrnL&c~Y}<#ns$bL<41n1&#Kg zagJuBIdAj)|Mtsx&-6?5VB>w{Ed6O?E1AemG(Jtpd$h&fL@v{v?$CPf+^rv7-cOIY z2kgu8Mj$c|jQ-9&Y+gbN2yOIqk|ny=^F3U%9;cnNNzDBie^QpH>S;p$qUW7j&gUk9 ze}rD}{>?gx&%i_YZ!$zDn%~2|9`l88ec9K8>lI(Khu<4xK)ersP%(ygYl7kTxF-iD zbEIX2kjdO*Tfa=~T#6g!mip(U6Q$Pd*p~r#>{X;NhjiB%lVveo^L-koKbPh3L1+jq0)14jd YzHdk%N;Z%suwl_|vDWqC0ia3vFC?qkr~m)} delta 1980 zcmZuyYj7LY6+U@s*@2Ett0LMRXi7?J@KzciqL*zlV0GI$ec>(~h?G*vv{VVMM0ag1-z`Z4_J z&V2WA?sw1m&e^+n|8ryJhQU!%x;_9rpD@WKL#8HEre;Bir`SOQq+TCRs|9Z7J0PI#AqSOc&PcrLtyo-@~V+1~_MnaGKd!=R1N zr84GF=TMIbTF-1ai8GOVvU~L*rMuj)?U}U<-jOk1Uc-UNC-?|xHFI@=>+Flh2oK4tJe!-zJyBnm;xX{&5&DvtIdyZNXCxh4^IY8#G%l8;0;!i%sa zpn~atorlMXzvUwAu{Sv)j%Md|pq;ubN}&0Ev~LApi^f8rJvh(wUKWh5jUFrBSAXH8 zt3iwh+nL_Q{PA9mnEbKnbQpcE;b@uF+qHg<=}$02AJhM!m;$_NmAUfbcB|}ZU$j1} z{G@tWR8PQ>$dyV|7v}riL0e_+>ahx8Pj*O=dAgvQKQLAoD@$IDRtfv zHs)i=-hfTDY;i?X&1fROaG}26D2@~;MtO`Ne1hrCOS0M&07t?W$;C{kFI#0mc}(BL zyh+0$(_3)o;y${K$doYGiDr*l&U!;i`LsfHl+#+~*memozDF%^PV+AGr=B!~{ zHDt2xFsu^*Ecg9ltSp}KIW4BLkIe*q+`QO@1FNbHMrv-JC`Qag1W6Qnlx!EO&>31TKiZ1_xtS;J-)25@swfkw7d&hu*nRa%6b5< zpndsz3}45LVyuHEyutKYg$`!#Afr^s=_PyUV>w0SPI@?JhzN9hZZr8WJ)HYT@*=Gi zHj;-%I)q+A-lykQjL}iMn049){L2{o5It?b#bS&G=tjp*`$kqId)tdJ!J-J$Kc+|U z>m9(=e<6O_BRE^g3-k`>!=#N)JN?2k!>IYo)RWgp253j#c5G95er*4px4~j?L>v{< z4X#qOwYq}jZo1cX8)=}Et_R3dv?ITF)mMeUtB8~fvDEkH1OH>eqV07Yf0|FT3wDqv z=+1&Vax;CgpufwIX9T!}X&EA_v7cT_@fg}unLIFM-(GfXc*W|vA5OnQ`mfKFYoJ_@ zA?`;!g*c8O4IEjrEzkd7za2SDKcC6-b5i!%KhfibSCG%?OyNrM!H7_FKk-~(cb&7# zCGk_XuJ3mZIAjRcUEDb^uYXJX-NA)=88R(A@C9_j-6-r87ln&PBDC7mVx7W~2DHa> zC7Gf_o?X5L18&MM2Oq)fE2My8*of@zFs_U#dQEW=a$AevS+UFoe9+0Nk~3Mg_-|>z z`+O4>ydRNTI^hjsYbjla?Z(m)kFjo+ffV0*B4e)EtZ}Bdv5z&@j_fXNBcyg@tZV}j z43?qX@D!p>v2nrgZx?1AVw+_XjvDBDq946Zi*3&3s3Ei)`_|Iid^e)A0bhzE*U?=S zSCuYP)*_|WaI^pitjB)SNUEZfBZJged2g0sSj?cm^0=@Sl`LZ${e9q9^y`4+B)~C% z@cf5IKKUIG&O~UaYE9NZ@Phl&xajDwtAftIVAcPI*qsIZ1BfSSe^sURJ3H`UGySBh F@PC5bwAKIs diff --git a/test-devices/loopback-stm32/bin/blackpill-f411ce.bin b/test-devices/loopback-stm32/bin/blackpill-f411ce.bin index ec368a08f5f3eb3d31e738973a36666199a1824a..429a99607b6209a710cd79178dae95b03af181b3 100755 GIT binary patch delta 2073 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 H^H%)|N7td_ delta 1828 zcmZuxeN0nV6u-BhuRv)_3oW$T*A`=EC05NQZrMO4kB`bAe#C9+Rz+PGUDoM852q>W zjJV0fTusEx>6k9)Bm-)bp{vC#i`kc<>i$p^NrtIrA?fDFE3M=1Tt4DId&%$KbIv{I z+}}C(-gi(qUD-VsV?QauRv2q=Sy7mxYhbY3U6c29v&t4q|5t2<7Ms5b2?+qPG;Md zR(7vTDKa}{i02|)HA=Q+%G_DEFsyA(d;6jfxbkwRyoTw%i(HiX6$8{hYXEtacU3-h zO;KPktk#7t>Ya)jIf#ocqS!`o3IMhOP_a5fB@0DIu&e$t+NP_~!$u1;ynvF8&vNT> z-_R{Xj`}3^qU6RBPMrqahX%)EAp#+h5kwF$=LHMrb+H`>mxaWHEsl2>GUTR z?wCTb^?cQ<1APNzTt%t$0sUHKinE>#j>!ZOI-@Vg0@Hu*+v`@xnXag-H3sl2M&P?O zrjMc+W63t*p#HikTJOT~=p*Xt9H`!%K~5#mqta{CHj$D_^$Uk^8oK#si^4M)cL;7Fr#AW^SdNn}@{uav6G^Ll z4q>L>E!<0BJ_xMbaHXoDXVdJkOCChk!Kwz*qk27S$N?7)v~~v>S1rI+GG9GAWPy+* zECj29Rh+;@3WXmv@&PIhj$@vSQYkW?PLw=M)$bOx!f_!-xR>heF0TLFa-l+f!*6Zw z4TPP(8GfhF((E2?6cwJw@x~_V`8(brek&fY7>yrE$(si%Rq??TT$eePI~L#G6guS+ zZA&jy+_~Nu5|y4?@qx;xP+v9l?bD3dXYknqrX*J64WP@>2dP8&<-WCu|CJ?3j*Q<< zKq_yCm|lq&g3Ws?!3%#SQ0y?&{RQ9@pbd~5MZ>3IE{!0UR-n=esu1)&og$UK9Os47 zXewe9)k4Ua^s7w5{P-#{t3(yYuEJUe(3nLrpNeLeD#)mo=j9UF7CG+7yvXM=CE7*4HJ@^3W(!V8BWC&+Ch*y)NhW)dwCd6p~ zPxJue)cDygV#Iz3=o=a`MulHHS+v?Dh4PAO4 z@{~P(r;AG8kbC(h6D?sxB0%CNQdqD;yVyQSjb~IzQ$f9I1f&!q*9sQk5rWNI9L&Ii zOitv$@NcrgV`et&v#e+TgAvkdHiPdO^VQsGUriC>QYgH`vQ4g8juF2S&_JG8*BF@A zFlG4=-gh9p-ZoFJSplX)hbUc1+U?u5%!zF|8CJ-zQ8KAC+{Bx)R)nZ&>?9`~8;Q{= z7%-Aigv!T%`R>|wgk^F}-gM5@$iO!jU?QzfkD*eHxGKO54skC6YRJ#d**1q3acv63 R>roCuXqehzWFMqM{{bL?hjah{ diff --git a/test-devices/loopback-stm32/bin/disco_f723ie.bin b/test-devices/loopback-stm32/bin/disco_f723ie.bin new file mode 100755 index 0000000000000000000000000000000000000000..f64e4b6b00a0001917abee78b03106d539b4f470 GIT binary patch literal 11396 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 +#include "stm32f7xx.h" +#include "device/usbd.h" + +extern uint32_t SystemCoreClock; +void SystemCoreClockUpdate(void); + + +static inline uint32_t get_reg(__I uint32_t* reg, uint32_t mask) { + return *reg & mask; +} + +static inline void set_reg(__IO uint32_t* reg, uint32_t value, uint32_t mask) { + *reg = (*reg & ~mask) | (value & mask); +} + + +// --- additional PWR constants + +#define PWR_CR1_VOS_SCALE3 (1 << PWR_CR1_VOS_Pos) +#define PWR_CR1_VOS_SCALE2 (2 << PWR_CR1_VOS_Pos) +#define PWR_CR1_VOS_SCALE1 (3 << PWR_CR1_VOS_Pos) + + +// --- additional RCC constants + +typedef struct rcc_clock_setup { + uint8_t pllm; + uint16_t plln; + uint8_t pllp; + uint8_t pllq; + uint32_t hpre; + uint32_t ppre1; + uint32_t ppre2; + uint32_t voltage_scale; + uint8_t overdrive; + uint8_t flash_wait_states; +} rcc_clock_setup_t; + +const rcc_clock_setup_t clock_setup_hse_216mhz_3v3 = { + .pllm = HSE_VALUE / 1000000, + .plln = 432, + .pllp = 2, + .pllq = 9, + .hpre = RCC_CFGR_HPRE_DIV1, + .ppre1 = RCC_CFGR_PPRE1_DIV4, + .ppre2 = RCC_CFGR_PPRE2_DIV2, + .voltage_scale = PWR_CR1_VOS_SCALE1, + .overdrive = 1, + .flash_wait_states = 7 +}; + +// --- additional SysTick constants + +#define SysTick_CTRL_CLKSOURCE_AHB_DIV8 (0 << SysTick_CTRL_CLKSOURCE_Pos) +#define SysTick_CTRL_CLKSOURCE_AHB (1 << SysTick_CTRL_CLKSOURCE_Pos) + +// --- additional GPIO constants + +#define GPIO_PUPD_NO_PULL 0 +#define GPIO_PUPD_PULL_UP 1 +#define GPIO_PUPD_PULL_DOWN 2 + +#define GPIO_MODE_INPUT 0 +#define GPIO_MODE_OUTPUT 1 +#define GPIO_MODE_ALT 2 +#define GPIO_MODE_ANALOG 3 + +#define GPIO_OSPEED_LOW 0 +#define GPIO_OSPEED_MEDIUM 1 +#define GPIO_OSPEED_FAST 2 +#define GPIO_OSPEED_HIGH 3 + + +static inline void rcc_wait_for_osc_ready(uint32_t rcc_cr_clk_rdy) { + while (get_reg(&RCC->CR, rcc_cr_clk_rdy) == 0) + ; +} + +static void gpio_mode_setup(GPIO_TypeDef* gpioport, int gpio, uint8_t mode, uint8_t pull_up_down) { + + int offset = gpio * 2; + set_reg(&gpioport->PUPDR, pull_up_down << offset, 3 << offset); + set_reg(&gpioport->MODER, mode << offset, 3 << offset); +} + +void gpio_set_af(GPIO_TypeDef* gpioport, int gpio, uint8_t alt_func_num) { + + int offset = 4 * gpio; + __IO uint32_t* reg; + if (offset < 32) { + reg = gpioport->AFR; + } else { + reg = gpioport->AFR + 1; + offset -= 32; + } + + set_reg(reg, alt_func_num << offset, 0xf << offset); +} + +static inline void gpio_set_ospeed(GPIO_TypeDef* gpioport, int gpio, uint8_t ospeed) { + int offset = gpio * 2; + set_reg(&gpioport->OSPEEDR, ospeed << offset, 3 << offset); +} + +static inline void gpio_set(GPIO_TypeDef* gpioport, int gpio) { + gpioport->BSRR = 1 << gpio; +} + +static inline void gpio_clear(GPIO_TypeDef* gpioport, int gpio) { + gpioport->BSRR = 1 << (gpio + 16); +} + + +static void rcc_clock_setup_hse(const rcc_clock_setup_t* setup) { + + // Enable internal high-speed oscillator (HSI) + set_reg(&RCC->CR, RCC_CR_HSION, RCC_CR_HSION_Msk); + rcc_wait_for_osc_ready(RCC_CR_HSIRDY); + + // Select HSI as SYSCLK source + set_reg(&RCC->CFGR, RCC_CFGR_SW_HSI, RCC_CFGR_SW_Msk); + + // Enable external high-speed oscillator (HSE) + set_reg(&RCC->CR, RCC_CR_HSEON, RCC_CR_HSEON_Msk); + rcc_wait_for_osc_ready(RCC_CR_HSERDY); + + // Set voltage scaling + set_reg(&RCC->APB1ENR, RCC_APB1ENR_PWREN, RCC_APB1ENR_PWREN_Msk); + set_reg(&PWR->CR1, setup->voltage_scale, PWR_CR1_VOS_Msk); + + // Overdrive + if (setup->overdrive) { + set_reg(&PWR->CR1, PWR_CR1_ODEN, PWR_CR1_ODEN_Msk); + while (get_reg(&PWR->CSR1, PWR_CSR1_ODRDY_Msk) == 0); + set_reg(&PWR->CR1, PWR_CR1_ODSWEN, PWR_CR1_ODSWEN_Msk); + while (get_reg(&PWR->CSR1, PWR_CSR1_ODSWRDY_Msk) == 0); + } + + // Set prescalers for AHB, APB1, APB2 + set_reg(&RCC->CFGR, setup->hpre | setup->ppre1 | setup->ppre2, + RCC_CFGR_HPRE_Msk | RCC_CFGR_PPRE1_Msk | RCC_CFGR_PPRE2_Msk); + + // Disable PLL oscillator before changing its configuration + set_reg(&RCC->CR, 0, RCC_CR_PLLON_Msk); + + // Configure the PLL oscillator + int pllp_val = (setup->pllp >> 1) - 1; + RCC->PLLCFGR = RCC_PLLCFGR_PLLSRC_HSE + | (setup->pllm << RCC_PLLCFGR_PLLM_Pos) + | (setup->plln << RCC_PLLCFGR_PLLN_Pos) + | (pllp_val << RCC_PLLCFGR_PLLP_Pos) + | (setup->pllq << RCC_PLLCFGR_PLLQ_Pos); + + // Enable PLL oscillator and wait for it to stabilize + set_reg(&RCC->CR, RCC_CR_PLLON, RCC_CR_PLLON_Msk); + rcc_wait_for_osc_ready(RCC_CR_PLLRDY); + + // Configure flash settings + set_reg(&FLASH->ACR, (setup->flash_wait_states << FLASH_ACR_LATENCY_Pos) | FLASH_ACR_ARTEN | FLASH_ACR_PRFTEN, + FLASH_ACR_ARTEN_Msk | FLASH_ACR_PRFTEN_Msk | FLASH_ACR_LATENCY_Msk); + + // Select PLL as SYSCLK source + set_reg(&RCC->CFGR, RCC_CFGR_SW_PLL, RCC_CFGR_SW_Msk); + + // Wait for PLL clock to be selected + while (get_reg(&RCC->CFGR, RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL) + ; + + // Disable internal high-speed oscillator + set_reg(&RCC->CR, 0, RCC_CR_HSION_Msk); + + // Update the SystemCoreClock variable used by TinyUSB + SystemCoreClockUpdate(); +} + +static volatile uint32_t millis_count; + +static void systick_init(void) { + + // Initialize SysTick + SysTick->CTRL = (SysTick->CTRL & ~SysTick_CTRL_CLKSOURCE_Msk) | SysTick_CTRL_CLKSOURCE_AHB_DIV8; + SysTick->LOAD = SystemCoreClock / 8 / 1000 - 1; + + // Enable and start + SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; + SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; +} + + +// --- Serial number --- + +char board_serial_num[13]; + +const static char HEX_DIGITS[] = "0123456789ABCDEF"; + +static void put_hex(uint32_t value, char *buf, int len) { + for (int idx = 0; idx < len; idx++) { + buf[idx] = HEX_DIGITS[value >> 28]; + value = value << 4; + } +} + +static void usb_init_serial_num() { + __I uint32_t* unique_id =(__I uint32_t*) UID_BASE; + uint32_t id0 = unique_id[0]; + uint32_t id1 = unique_id[1]; + uint32_t id2 = unique_id[2]; + + id0 += id2; + + put_hex(id0, board_serial_num, 8); + put_hex(id1, board_serial_num + 8, 4); + board_serial_num[12] = 0; +} + + +// --- Exported board functions + +void board_init(void) { + + rcc_clock_setup_hse(&clock_setup_hse_216mhz_3v3); + systick_init(); + + // clock for GPIOB (USB pins) + set_reg(&RCC->AHB1ENR, RCC_AHB1ENR_GPIOBEN, RCC_AHB1ENR_GPIOBEN_Msk); + + // Configure USB D+/D- pins + gpio_mode_setup(GPIOB, 14, GPIO_MODE_ALT, GPIO_PUPD_NO_PULL); + gpio_set_af(GPIOB, 14, 10); + gpio_set_ospeed(GPIOB, 14, GPIO_OSPEED_HIGH); + gpio_mode_setup(GPIOB, 15, GPIO_MODE_ALT, GPIO_PUPD_NO_PULL); + gpio_set_af(GPIOB, 15, 10); + gpio_set_ospeed(GPIOB, 15, GPIO_OSPEED_HIGH); + + // Configure VBUS sense + set_reg(&USB_OTG_HS->GCCFG, USB_OTG_GCCFG_VBDEN, USB_OTG_GCCFG_VBDEN_Msk); + + gpio_mode_setup(GPIOB, 14, GPIO_MODE_ALT, GPIO_PUPD_PULL_UP); + gpio_set_af(GPIOB, 14, 10); + gpio_set_ospeed(GPIOB, 14, GPIO_OSPEED_HIGH); + + set_reg(&RCC->APB2ENR, RCC_APB2ENR_OTGPHYCEN, RCC_APB2ENR_OTGPHYCEN_Msk); + set_reg(&RCC->AHB1ENR, RCC_AHB1ENR_OTGHSULPIEN, RCC_AHB1ENR_OTGHSULPIEN_Msk); + set_reg(&RCC->AHB1ENR, RCC_AHB1ENR_OTGHSEN, RCC_AHB1ENR_OTGHSEN_Msk); + + // No VBUS sense + set_reg(&USB_OTG_HS->GCCFG, 0, USB_OTG_GCCFG_VBDEN_Msk); + + // B-peripheral session valid override enable + set_reg(&USB_OTG_HS->GOTGCTL, USB_OTG_GOTGCTL_BVALOEN, USB_OTG_GOTGCTL_BVALOEN_Msk); + set_reg(&USB_OTG_HS->GOTGCTL, USB_OTG_GOTGCTL_BVALOVAL, USB_OTG_GOTGCTL_BVALOVAL_Msk); + + // Force device mode + set_reg(&USB_OTG_HS->GUSBCFG, 0, USB_OTG_GUSBCFG_FHMOD_Msk); + set_reg(&USB_OTG_HS->GUSBCFG, USB_OTG_GUSBCFG_FDMOD, USB_OTG_GUSBCFG_FDMOD_Msk); + + // clock for GPIOB (LED) + set_reg(&RCC->AHB1ENR, RCC_AHB1ENR_GPIOBEN, RCC_AHB1ENR_GPIOBEN_Msk); + + // LED pin + gpio_mode_setup(GPIOB, 1, GPIO_MODE_OUTPUT, GPIO_PUPD_NO_PULL); + + usb_init_serial_num(); +} + +uint32_t board_millis(void) { + return millis_count; +} + +void board_led_write(bool on) { + if (on) + gpio_set(GPIOB, 1); + else + gpio_clear(GPIOB, 1); +} + + +// --- Interrupt handlers --- + +void SysTick_Handler (void) { + millis_count++; +} + +void OTG_HS_IRQHandler(void) { + tud_int_handler(1); +} + +#endif diff --git a/test-devices/loopback-stm32/src/main.c b/test-devices/loopback-stm32/src/main.c index 4262e03c..b4978f78 100644 --- a/test-devices/loopback-stm32/src/main.c +++ b/test-devices/loopback-stm32/src/main.c @@ -20,10 +20,10 @@ // FIFO buffer for loopback data tu_fifo_t loopback_fifo; -uint8_t loopback_buffer[512]; +uint8_t loopback_buffer[2048]; // RX buffer for loopback -uint8_t loopback_rx_buffer[64]; +uint8_t loopback_rx_buffer[512]; // buffer for echoed packet uint8_t echo_buffer[16]; @@ -84,8 +84,9 @@ void loopback_check_tx(void) { if (info.len_lin > 0 && !cust_vendor_is_transmitting(EP_LOOPBACK_TX)) { int n = info.len_lin; - if (n > 128) - n = 128; + int max_size = 2 * cust_vendor_packet_size(EP_LOOPBACK_RX); + if (n > max_size) + n = max_size; cust_vendor_start_transmit(EP_LOOPBACK_TX, info.ptr_lin, n); } @@ -95,8 +96,9 @@ void loopback_check_tx(void) { void loopback_check_rx(void) { int n = tu_fifo_remaining(&loopback_fifo); - if (n >= sizeof(loopback_rx_buffer) && !cust_vendor_is_receiving(EP_LOOPBACK_RX)) - cust_vendor_prepare_recv(EP_LOOPBACK_RX, loopback_rx_buffer, sizeof(loopback_rx_buffer)); + uint16_t packet_size = cust_vendor_packet_size(EP_LOOPBACK_RX); + if (n >= packet_size && !cust_vendor_is_receiving(EP_LOOPBACK_RX)) + cust_vendor_prepare_recv(EP_LOOPBACK_RX, loopback_rx_buffer, packet_size); } @@ -143,7 +145,8 @@ void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes) { loopback_check_rx(); // check ZLP - if ((sent_bytes & (BULK_MAX_PACKET_SIZE - 1)) == 0 + uint16_t packet_size = cust_vendor_packet_size(EP_LOOPBACK_TX); + if ((sent_bytes & (packet_size - 1)) == 0 && !cust_vendor_is_transmitting(ep_addr)) cust_vendor_start_transmit(EP_LOOPBACK_TX, NULL, 0); diff --git a/test-devices/loopback-stm32/src/usb_descriptors.c b/test-devices/loopback-stm32/src/usb_descriptors.c index 52bb0ad8..49893982 100644 --- a/test-devices/loopback-stm32/src/usb_descriptors.c +++ b/test-devices/loopback-stm32/src/usb_descriptors.c @@ -30,7 +30,7 @@ tusb_desc_device_t const desc_device = { .idVendor = 0xCAFE, .idProduct = 0xCEAF, - .bcdDevice = 0x0073, // version 0.7.3 + .bcdDevice = 0x0074, // version 0.7.4 .iManufacturer = 0x01, .iProduct = 0x02, @@ -55,15 +55,15 @@ enum { #define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + 9 + 4 * 7 + 9 + 2 * 7) -uint8_t const desc_configuration[] = { +uint8_t const desc_fs_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA TUD_CONFIG_DESCRIPTOR(1, INTF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 500), // Loopback interface (alternate 0) CUSTOM_VENDOR_INTERFACE(0, 4), // Loopback endpoint OUT - CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_RX, BULK_MAX_PACKET_SIZE), + CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_RX, 64), // Loopback endpoint IN - CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_TX, BULK_MAX_PACKET_SIZE), + CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_TX, 64), // Echo endpoint OUT CUSTOM_VENDOR_INTERRUPT_ENDPOINT(EP_ECHO_RX, INTR_MAX_PACKET_SIZE, 16), // Echo endpoint IN @@ -71,17 +71,85 @@ uint8_t const desc_configuration[] = { // Loopback interface (alternate 1) CUSTOM_VENDOR_INTERFACE_ALT(0, 1, 2), // Loopback endpoint OUT - CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_RX, BULK_MAX_PACKET_SIZE), + CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_RX, 64), // Loopback endpoint IN - CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_TX, BULK_MAX_PACKET_SIZE) + CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_TX, 64) }; +#if TUD_OPT_HIGH_SPEED + +uint8_t const desc_hs_configuration[] = { + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, INTF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 500), + // Loopback interface (alternate 0) + CUSTOM_VENDOR_INTERFACE(0, 4), + // Loopback endpoint OUT + CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_RX, 512), + // Loopback endpoint IN + CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_TX, 512), + // Echo endpoint OUT + CUSTOM_VENDOR_INTERRUPT_ENDPOINT(EP_ECHO_RX, INTR_MAX_PACKET_SIZE, 8), + // Echo endpoint IN + CUSTOM_VENDOR_INTERRUPT_ENDPOINT(EP_ECHO_TX, INTR_MAX_PACKET_SIZE, 8), + // Loopback interface (alternate 1) + CUSTOM_VENDOR_INTERFACE_ALT(0, 1, 2), + // Loopback endpoint OUT + CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_RX, 512), + // Loopback endpoint IN + CUSTOM_VENDOR_BULK_ENDPOINT(EP_LOOPBACK_TX, 512) +}; + +// device qualifier (same values as device descriptor where possible) +tusb_desc_device_qualifier_t const desc_device_qualifier = +{ + .bLength = sizeof(tusb_desc_device_qualifier_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + + .bDeviceClass = TUSB_CLASS_VENDOR_SPECIFIC, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .bNumConfigurations = 0x01, + .bReserved = 0x00 +}; + +// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. +// device_qualifier descriptor describes information about a high-speed capable device that would +// change if the device were operating at the other speed. If not highspeed capable stall this request. +uint8_t const* tud_descriptor_device_qualifier_cb(void) +{ + return (uint8_t const*) &desc_device_qualifier; +} + +// Invoked when received GET OTHER SPEED CONFIGURATION DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa +uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) +{ + (void) index; // for multiple configurations + + // if link speed is high return fullspeed config, and vice versa + return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration; +} + +#endif + + // Invoked when a GET CONFIGURATION DESCRIPTOR request is recieved. // Return a pointer to descriptor. // Descriptor contents must exist long enough for transfer to complete uint8_t const* tud_descriptor_configuration_cb(uint8_t configuration_index) { (void)configuration_index; - return desc_configuration; + +#if TUD_OPT_HIGH_SPEED + // Although we are highspeed, host may be fullspeed. + return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration; +#else + return desc_fs_configuration; +#endif } diff --git a/test-devices/loopback-stm32/src/usb_descriptors.h b/test-devices/loopback-stm32/src/usb_descriptors.h index 1677a600..ad7af02b 100644 --- a/test-devices/loopback-stm32/src/usb_descriptors.h +++ b/test-devices/loopback-stm32/src/usb_descriptors.h @@ -14,7 +14,6 @@ #include #define INTR_MAX_PACKET_SIZE 16 -#define BULK_MAX_PACKET_SIZE 64 // Endpoints #define EP_LOOPBACK_RX 0x01 diff --git a/test-devices/loopback-stm32/src/vendor_custom.c b/test-devices/loopback-stm32/src/vendor_custom.c index 18819811..4aae61e4 100644 --- a/test-devices/loopback-stm32/src/vendor_custom.c +++ b/test-devices/loopback-stm32/src/vendor_custom.c @@ -39,6 +39,7 @@ const usbd_class_driver_t cust_vendor_driver = { // open endpoints static uint8_t cv_eps_open[8]; +static uint16_t cv_eps_packet_size[8]; static int cv_num_eps_open; // current alternate setting @@ -106,6 +107,7 @@ uint16_t setup_endpoints(uint8_t rhport, tusb_desc_interface_t const* desc_intf, // remember open endpoints cv_eps_open[cv_num_eps_open] = desc_ep->bEndpointAddress; + cv_eps_packet_size[cv_num_eps_open] = desc_ep->wMaxPacketSize; cv_num_eps_open += 1; } @@ -125,10 +127,13 @@ uint16_t setup_endpoints(uint8_t rhport, tusb_desc_interface_t const* desc_intf, } void close_endpoints() { + + uint8_t const rhport = BOARD_TUD_RHPORT; + // close in reverse order while (cv_num_eps_open > 0) { cv_num_eps_open -= 1; - usbd_edpt_close(0, cv_eps_open[cv_num_eps_open]); + usbd_edpt_close(rhport, cv_eps_open[cv_num_eps_open]); } } @@ -144,7 +149,7 @@ bool cv_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const } else if (request->bRequest == TUSB_REQ_SET_INTERFACE) { if (stage == CONTROL_STAGE_SETUP) { uint8_t alt_num = request->wValue; - setup_endpoints(0, cv_intf_desc, cv_intf_desc_len, alt_num); + setup_endpoints(rhport, cv_intf_desc, cv_intf_desc_len, alt_num); if (cust_vendor_alt_intf_selected_cb != NULL) cust_vendor_alt_intf_selected_cb((uint8_t) request->wIndex, alt_num); tud_control_status(rhport, request); @@ -177,7 +182,7 @@ bool cv_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t void cust_vendor_prepare_recv(uint8_t ep_addr, void* buf, uint32_t buf_len) { - uint8_t const rhport = 0; + uint8_t const rhport = BOARD_TUD_RHPORT; if (usbd_edpt_busy(rhport, ep_addr)) return; @@ -187,7 +192,7 @@ void cust_vendor_prepare_recv(uint8_t ep_addr, void* buf, uint32_t buf_len) { void cust_vendor_start_transmit(uint8_t ep_addr, void const * data, uint32_t data_len) { - uint8_t const rhport = 0; + uint8_t const rhport = BOARD_TUD_RHPORT; if (usbd_edpt_busy(rhport, ep_addr)) return; @@ -196,11 +201,24 @@ void cust_vendor_start_transmit(uint8_t ep_addr, void const * data, uint32_t dat } bool cust_vendor_is_receiving(uint8_t ep_addr) { - return usbd_edpt_busy(0, ep_addr); + + uint8_t const rhport = BOARD_TUD_RHPORT; + + return usbd_edpt_busy(rhport, ep_addr); } bool cust_vendor_is_transmitting(uint8_t ep_addr) { - return usbd_edpt_busy(0, ep_addr); + + uint8_t const rhport = BOARD_TUD_RHPORT; + + return usbd_edpt_busy(rhport, ep_addr); +} + +uint16_t cust_vendor_packet_size(uint8_t ep_addr) { + for (int i = 0; i < cv_num_eps_open; i++) + if (cv_eps_open[i] == ep_addr) + return cv_eps_packet_size[i]; + return 1; } #endif diff --git a/test-devices/loopback-stm32/src/vendor_custom.h b/test-devices/loopback-stm32/src/vendor_custom.h index 556678c8..5fd14836 100644 --- a/test-devices/loopback-stm32/src/vendor_custom.h +++ b/test-devices/loopback-stm32/src/vendor_custom.h @@ -86,6 +86,15 @@ void cust_vendor_start_transmit(uint8_t ep_addr, void const * data, uint32_t dat */ bool cust_vendor_is_transmitting(uint8_t ep_addr); +/** + * @brief Gets the endpoint packet size. + * + * @param ep_addr endpoint address (1 to 255) + * @return int packet size, in bytes + */ +uint16_t cust_vendor_packet_size(uint8_t ep_addr); + + // --- Application Callback API From 3f29b234bb9ec606ffa55d678082d54ef71112a8 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Fri, 4 Nov 2022 16:41:13 +0100 Subject: [PATCH 152/433] Speed test (macOS) --- reference/macos/USB/prng.cpp | 80 +++++++++++ reference/macos/USB/prng.hpp | 72 ++++++++++ reference/macos/USB/speed_test.cpp | 126 ++++++++++++++++++ reference/macos/USB/speed_test.hpp | 38 ++++++ reference/macos/USB/tests.cpp | 11 +- reference/macos/USB/tests.hpp | 1 + reference/macos/USB/usb_device.cpp | 50 +++++-- reference/macos/USB/usb_device.hpp | 31 +++-- reference/macos/usb.xcodeproj/project.pbxproj | 20 ++- .../xcshareddata/xcschemes/USB.xcscheme | 2 +- 10 files changed, 407 insertions(+), 24 deletions(-) create mode 100644 reference/macos/USB/prng.cpp create mode 100644 reference/macos/USB/prng.hpp create mode 100644 reference/macos/USB/speed_test.cpp create mode 100644 reference/macos/USB/speed_test.hpp diff --git a/reference/macos/USB/prng.cpp b/reference/macos/USB/prng.cpp new file mode 100644 index 00000000..c9cd0b1a --- /dev/null +++ b/reference/macos/USB/prng.cpp @@ -0,0 +1,80 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#include "prng.hpp" + +prng::prng(uint32_t init) : state(init), nbytes(0), bits(0) {} + +void prng::reset(uint32_t init) +{ + state = init; + nbytes = 0; + bits = 0; +} + +uint32_t prng::next() +{ + uint32_t x = state; + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + state = x; + return x; +} + +void prng::fill(uint8_t *buf, int len) +{ + for (int i = 0; i < len; i++) + { + if (nbytes == 0) + { + bits = next(); + nbytes = 4; + } + buf[i] = bits; + bits >>= 8; + nbytes--; + } +} + +void prng::fill(std::vector& buf, int len) +{ + if (len == -1 || len > buf.size()) + len = static_cast(buf.size()); + + fill(buf.data(), len); +} + +int prng::verify(const uint8_t *buf, int len) +{ + for (int i = 0; i < len; i++) + { + if (nbytes == 0) + { + bits = next(); + nbytes = 4; + } + + if (buf[i] != (uint8_t)bits) + return i; + + bits >>= 8; + nbytes--; + } + + return -1; +} + +int prng::verify(const std::vector &buf, int len) +{ + if (len == -1 || len > buf.size()) + len = static_cast(buf.size()); + + return verify(buf.data(), len); +} diff --git a/reference/macos/USB/prng.hpp b/reference/macos/USB/prng.hpp new file mode 100644 index 00000000..5214dfa6 --- /dev/null +++ b/reference/macos/USB/prng.hpp @@ -0,0 +1,72 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#pragma once + +#include +#include + +/** + * Pseudo Random Number Generator + */ +struct prng +{ + /** + * Constructs a new instance + * @param init initial value + */ + prng(uint32_t init); + + /** + * Returns the next pseudo random value + * @return pseudo random value + */ + uint32_t next(); + + /** + * Fills the buffer with pseudo random data + * @param buf buffer receiving the random data + * @param len length of the buffer (in bytes) + */ + void fill(uint8_t *buf, int len); + + /** + * Fills the buffer with pseudo random data + * @param buf buffer receiving the random data + * @param len number of bytes to fill (-1 for entire buffer) + */ + void fill(std::vector& buf, int len = -1); + + /** + * Verifies that the passed data matches the next bytes of the sequence. + * @param buf buffer with data to verify + * @param len length of the buffer (in bytes) + * @return -1 if they match, otherwise the position of the difference + */ + int verify(const uint8_t *buf, int len); + + /** + * Verifies that the passed data matches the next bytes of the sequence. + * @param buf buffer with data to verify + * @param len number of bytes to verify (-1 for entire buffer) + * @return -1 if they match, otherwise the position of the difference + */ + int verify(const std::vector& buf, int len = -1); + + /** + * Resets the generator to its initial state. + * @param init initial value + */ + void reset(uint32_t init); + +private: + uint32_t state; + int nbytes; + uint32_t bits; +}; diff --git a/reference/macos/USB/speed_test.cpp b/reference/macos/USB/speed_test.cpp new file mode 100644 index 00000000..40141d8f --- /dev/null +++ b/reference/macos/USB/speed_test.cpp @@ -0,0 +1,126 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#include "speed_test.hpp" + +#include "prng.hpp" +#include "usb_error.hpp" + +#include +#include +#include +#include + + +static constexpr uint32_t PRNG_INIT = 0x7b; + + +speed_test::speed_test(usb_device_ptr device, int ep_out, int ep_in) +: device_(device), ep_out_(ep_out), ep_in_(ep_in) { } + +void speed_test::run(int num_bytes) { + reset_buffers(); + start_measurement(); + + std::thread sender(&speed_test::transmit, this, num_bytes / 2); + bool successful = receive(num_bytes / 2); + sender.join(); + + if (successful) + stop_measurement(); +} + +bool speed_test::transmit(int num_bytes) { + + prng seq(PRNG_INIT); + + std::vector buf(2048); + int pos = 0; + + while (num_bytes > 0) { + int n = std::min(num_bytes, static_cast(buf.size())); + try { + seq.fill(buf, n); + device_->transfer_out(ep_out_, buf, n); + + } catch (usb_error& error) { + std::cerr << std::endl << "ERROR: " << error.what() << " (writing at pos " << pos << ")" << std::endl; + return false; + } + + num_bytes -= n; + pos += n; + update_progress(n); + } + + return true; +} + +bool speed_test::receive(int num_bytes) { + + prng seq(PRNG_INIT); + int pos = 0; + + while (num_bytes > 0) { + int n; + try { + std::vector data = device_->transfer_in(ep_in_); + n = std::min(num_bytes, static_cast(data.size())); + int p = seq.verify(data, n); + if (p != -1) { + std::cerr << std::endl << "Invalid data received at pos " << (pos + p) << std::endl; + return false; + } + + } catch (usb_error& error) { + std::cerr << std::endl << "ERROR: " << error.what() << " (reading at pos " << pos << ")" << std::endl; + return false; + } + + num_bytes -= n; + pos += n; + + update_progress(n); + } + + return true; +} + +void speed_test::reset_buffers() { + usb_control_request request_set_value_no_data = { 0 }; + request_set_value_no_data.bmRequestType = usb_control_request::request_type(usb_request_type::direction_out, + usb_request_type::type_vendor, usb_request_type::recipient_interface); + request_set_value_no_data.bRequest = 0x04; + request_set_value_no_data.wIndex = 0; // interface number + device_->control_transfer(request_set_value_no_data); + +} + + +// --- throughput measurement --- + +void speed_test::start_measurement() { + start_time = std::chrono::high_resolution_clock::now(); + processed_bytes = 0; +} + +void speed_test::update_progress(int n) { + std::lock_guard lockGuard(progress_mutex); + processed_bytes += n; +} + +int speed_test::stop_measurement() { + auto end_time = std::chrono::high_resolution_clock::now(); + std::chrono::duration dur = end_time - start_time; + double thr = processed_bytes / dur.count(); + + std::cout << "Throughput: " << std::fixed << std::setprecision(1) << thr << " kByte/s" << std::endl; + + return (int)(thr * 1000); +} diff --git a/reference/macos/USB/speed_test.hpp b/reference/macos/USB/speed_test.hpp new file mode 100644 index 00000000..99f19277 --- /dev/null +++ b/reference/macos/USB/speed_test.hpp @@ -0,0 +1,38 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#pragma once + +#include "usb_device.hpp" + +#include +#include + +class speed_test { +public: + speed_test(usb_device_ptr device, int ep_out, int ep_in); + void run(int num_bytes); + +private: + void reset_buffers(); + bool transmit(int num_bytes); + bool receive(int num_bytes); + + void start_measurement(); + void update_progress(int n); + int stop_measurement(); + + usb_device_ptr device_; + int ep_out_; + int ep_in_; + + std::chrono::time_point start_time; + int processed_bytes; + std::mutex progress_mutex; +}; diff --git a/reference/macos/USB/tests.cpp b/reference/macos/USB/tests.cpp index 657195ef..529e7328 100644 --- a/reference/macos/USB/tests.cpp +++ b/reference/macos/USB/tests.cpp @@ -9,6 +9,7 @@ #include "tests.hpp" #include "assertion.hpp" +#include "speed_test.hpp" #include #include @@ -47,6 +48,7 @@ void tests::test_current_device() { test_control_transfers(); test_bulk_transfers(); + test_speed(); test_device->release_interface(0); test_device->close(); @@ -111,7 +113,7 @@ void tests::test_loopback(int num_bytes) { std::thread reader([this, &rx_data, num_bytes]() { size_t bytes_read = 0; while (bytes_read < num_bytes) { - auto data = test_device->transfer_in(2, 64); + auto data = test_device->transfer_in(2); rx_data.insert(rx_data.end(), data.begin(), data.end()); bytes_read += data.size(); } @@ -134,6 +136,13 @@ void tests::test_loopback(int num_bytes) { assert_equals(random_data, rx_data); } +void tests::test_speed() { + int packet_size = test_device->get_endpoint(usb_direction::out, 1)->packet_size(); + + speed_test test(test_device, 1, 2); + test.run(packet_size == 512 ? 20000000 : 2000000); +} + void tests::on_device(usb_device_ptr device) { if (is_test_device(device)) { test_device = device; diff --git a/reference/macos/USB/tests.hpp b/reference/macos/USB/tests.hpp index 344f495f..11cf328f 100644 --- a/reference/macos/USB/tests.hpp +++ b/reference/macos/USB/tests.hpp @@ -20,6 +20,7 @@ class tests { void test_current_device(); void test_control_transfers(); void test_bulk_transfers(); + void test_speed(); void test_loopback(int num_bytes); diff --git a/reference/macos/USB/usb_device.cpp b/reference/macos/USB/usb_device.cpp index 2d7824c2..70e7dcee 100644 --- a/reference/macos/USB/usb_device.cpp +++ b/reference/macos/USB/usb_device.cpp @@ -60,6 +60,27 @@ const std::vector& usb_device::interfaces() const { return interfaces_; } +const usb_interface* usb_device::get_interface(int interface_number) const { + for (const usb_interface& intf : interfaces_) { + if (intf.number() == interface_number) + return &intf; + } + + return nullptr; +} + +const usb_endpoint* usb_device::get_endpoint(usb_direction direction, int endpoint_number) const { + for (const usb_interface& intf : interfaces_) { + for (const usb_endpoint& ep : intf.alternate().endpoints()) { + if (ep.direction() == direction && ep.number() == endpoint_number) + return &ep; + } + } + + return nullptr; +} + + bool usb_device::is_open() const { return is_open_; } @@ -93,7 +114,7 @@ void usb_device::claim_interface(int interface_number) { if (claimed_interfaces_.find(interface_number) != claimed_interfaces_.end()) throw usb_error("interface has already been claimed"); - usb_interface* uintf = get_interface(interface_number); + usb_interface* uintf = get_intf_ptr(interface_number); if (uintf == nullptr) throw usb_error("no such interface"); @@ -148,7 +169,7 @@ void usb_device::claim_interface(int interface_number) { void usb_device::release_interface(int interface_number) { - usb_interface* uintf = get_interface(interface_number); + usb_interface* uintf = get_intf_ptr(interface_number); if (uintf == nullptr) throw usb_error("no such interface"); @@ -168,7 +189,7 @@ void usb_device::release_interface(int interface_number) { void usb_device::select_alternate_interface(int interface_number, int alternate_setting) { - usb_interface* uintf = get_interface(interface_number); + usb_interface* uintf = get_intf_ptr(interface_number); if (uintf == nullptr) throw usb_error("no such interface"); @@ -201,26 +222,26 @@ void usb_device::build_pipe_info() { UInt8 direction = 0; UInt8 number = 0; UInt8 transfer_type = 0; + UInt16 packet_size = 0; UInt8 ignore = 0; - UInt16 ignore2 = 0; - ret = (*interface)->GetPipeProperties(interface, i, &direction, &number, &transfer_type, &ignore2, &ignore); + ret = (*interface)->GetPipeProperties(interface, i, &direction, &number, &transfer_type, &packet_size, &ignore); usb_error::check(ret, "internal error (GetPipeProperties)"); uint8_t addr = static_cast((direction << 7) | number); usb_transfer_type type = static_cast(transfer_type); // both enumeration use the same value as the USB standard - pipe_info pipe{static_cast(i), addr, type, intf.first}; + pipe_info pipe{static_cast(i), addr, packet_size, type, intf.first}; pipes_.push_back(std::move(pipe)); } } } -std::vector usb_device::transfer_in(int endpoint_number, int data_len, int timeout) { +std::vector usb_device::transfer_in(int endpoint_number, int timeout) { auto pipe = ep_in_pipe(endpoint_number); IOUSBInterfaceInterface** interface = claimed_interfaces_[pipe->interface_number]; - UInt32 size = data_len; - std::vector data(data_len); + UInt32 size = pipe->packet_size; + std::vector data(size); IOReturn ret; if (timeout != 0) { ret = (*interface)->ReadPipeTO(interface, pipe->pipe_index, data.data(), &size, timeout, timeout); @@ -239,15 +260,18 @@ std::vector usb_device::transfer_in(int endpoint_number, int data_len, return data; } -void usb_device::transfer_out(int endpoint_number, const std::vector& data, int timeout) { +void usb_device::transfer_out(int endpoint_number, const std::vector& data, int len, int timeout) { + if (len < 0 || len > data.size()) + len = static_cast(data.size()); + auto pipe = ep_out_pipe(endpoint_number); IOUSBInterfaceInterface** interface = claimed_interfaces_[pipe->interface_number]; IOReturn ret; if (timeout != 0) - ret = (*interface)->WritePipeTO(interface, pipe->pipe_index, const_cast(data.data()), static_cast(data.size()), timeout, timeout); + ret = (*interface)->WritePipeTO(interface, pipe->pipe_index, const_cast(data.data()), len, timeout, timeout); else - ret = (*interface)->WritePipe(interface, pipe->pipe_index, const_cast(data.data()), static_cast(data.size())); + ret = (*interface)->WritePipe(interface, pipe->pipe_index, const_cast(data.data()), len); if (ret != kIOReturnSuccess) { if (ret == kIOUSBTransactionTimeout) @@ -346,7 +370,7 @@ const usb_device::pipe_info* usb_device::get_pipe(int endpoint_address) { return get_pipe(endpoint_number + 128); } -usb_interface* usb_device::get_interface(int interface_number) { +usb_interface* usb_device::get_intf_ptr(int interface_number) { for (usb_interface& intf : interfaces_) if (intf.number() == interface_number) return &intf; diff --git a/reference/macos/USB/usb_device.hpp b/reference/macos/USB/usb_device.hpp index a32baed2..44c79b7e 100644 --- a/reference/macos/USB/usb_device.hpp +++ b/reference/macos/USB/usb_device.hpp @@ -95,6 +95,23 @@ class usb_device { std::string description() const; /// List of interfaces const std::vector& interfaces() const; + + /** + * Get the USB interface. + * + * @param interface_number interface number + * @return interface or `nullptr` if no such interface exists + */ + const usb_interface* get_interface(int interface_number) const; + + /** + * Get a USB endpoint. + * + * @param direction endpoint direction + * @param endpoint_number endpoint number (between 1 and 127) + * @return endpoint or `nullptr` if endpoint does not exist + */ + const usb_endpoint* get_endpoint(usb_direction direction, int endpoint_number) const; /// Opens the device for communication void open(); @@ -133,10 +150,7 @@ class usb_device { * Receives data from a bulk or interrupt endpoint. * * The amount of bytes read will be influced by the underlying USB packets. - * If a short packet is sent, the function will return after having read fewer bytes - * than specified. The function will fail if a bigger packet has been received than - * will fit into the given buffer. So the specified data length should be big enough for - * the maximum packet size (64 bytes for full-speed USB). + * It can be 0 (if the device sends a ZLP) up to the maximum packet size. * * The timeout specifies the maximum time it may take to complete the operation. * If the operation does not complete within that time, the function returns after reading @@ -145,11 +159,10 @@ class usb_device { * Interrupt endpoints do not support timeouts. Thus, 0 has to be specified. * * @param endpoint_number endpoint number (between 1 and 127) - * @param data_len maximum length to read (in bytes) * @param timeout timeout (in ms, 0 for no timeout) * @return received data */ - std::vector transfer_in(int endpoint_number, int data_len, int timeout = 0); + std::vector transfer_in(int endpoint_number, int timeout = 0); /** * Transmits data to a bulk or interrupt endpoint. @@ -162,9 +175,10 @@ class usb_device { * * @param endpoint_number endpoint number (between 1 and 127) * @param data data to transmit + * @param len data length, in bytes (-1 for entire data vector) * @param timeout timeout (in ms, 0 for no timeout) */ - void transfer_out(int endpoint_number, const std::vector& data, int timeout = 0); + void transfer_out(int endpoint_number, const std::vector& data, int len = -1, int timeout = 0); /** * Send a control request with no Data phase. @@ -206,6 +220,7 @@ class usb_device { struct pipe_info { uint8_t pipe_index; uint8_t endpoint_address; + uint16_t packet_size; usb_transfer_type transfer_type; int interface_number; }; @@ -218,7 +233,7 @@ class usb_device { const pipe_info* ep_out_pipe(int endpoint_address); int control_transfer_core(const usb_control_request& request, uint8_t* data, int timeout); void load_configuration(IOUSBDeviceInterface** device); - usb_interface* get_interface(int interface_number); + usb_interface* get_intf_ptr(int interface_number); int get_alternate_index(int interface_number, int alternate_setting); uint64_t entry_id_; diff --git a/reference/macos/usb.xcodeproj/project.pbxproj b/reference/macos/usb.xcodeproj/project.pbxproj index a00db96b..0a38e428 100644 --- a/reference/macos/usb.xcodeproj/project.pbxproj +++ b/reference/macos/usb.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 64292E7329144D6C004F6169 /* prng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64292E7129144D6C004F6169 /* prng.cpp */; }; + 64292E7629144DE1004F6169 /* speed_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64292E7429144DE1004F6169 /* speed_test.cpp */; }; 64835E60290BCA9F00113E4E /* config_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64835E5D290BCA9F00113E4E /* config_parser.cpp */; }; 64835E61290BCA9F00113E4E /* configuration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64835E5F290BCA9F00113E4E /* configuration.cpp */; }; 64937C6428D5EBF1009BD0C2 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64937C6328D5EBF1009BD0C2 /* main.cpp */; }; @@ -33,6 +35,10 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 64292E7129144D6C004F6169 /* prng.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = prng.cpp; sourceTree = ""; }; + 64292E7229144D6C004F6169 /* prng.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = prng.hpp; sourceTree = ""; }; + 64292E7429144DE1004F6169 /* speed_test.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = speed_test.cpp; sourceTree = ""; }; + 64292E7529144DE1004F6169 /* speed_test.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = speed_test.hpp; sourceTree = ""; }; 64835E5C290BCA9F00113E4E /* configuration.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = configuration.hpp; sourceTree = ""; }; 64835E5D290BCA9F00113E4E /* config_parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = config_parser.cpp; sourceTree = ""; }; 64835E5E290BCA9F00113E4E /* config_parser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = config_parser.hpp; sourceTree = ""; }; @@ -107,6 +113,10 @@ 64937C7728D5FE6D009BD0C2 /* usb_device.cpp */, 64937C6E28D5ED1F009BD0C2 /* usb_registry.hpp */, 64937C6B28D5ED1F009BD0C2 /* usb_registry.cpp */, + 64292E7129144D6C004F6169 /* prng.cpp */, + 64292E7229144D6C004F6169 /* prng.hpp */, + 64292E7429144DE1004F6169 /* speed_test.cpp */, + 64292E7529144DE1004F6169 /* speed_test.hpp */, ); path = USB; sourceTree = ""; @@ -147,7 +157,7 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = 1; - LastUpgradeCheck = 1400; + LastUpgradeCheck = 1410; TargetAttributes = { 64937C5F28D5EBF1009BD0C2 = { CreatedOnToolsVersion = 14.0; @@ -185,6 +195,8 @@ 64835E60290BCA9F00113E4E /* config_parser.cpp in Sources */, 64937C6428D5EBF1009BD0C2 /* main.cpp in Sources */, 64937C7628D5ED8D009BD0C2 /* usb_error.cpp in Sources */, + 64292E7329144D6C004F6169 /* prng.cpp in Sources */, + 64292E7629144DE1004F6169 /* speed_test.cpp in Sources */, 64937C8128D6F9DE009BD0C2 /* tests.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -225,6 +237,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -283,6 +296,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -305,7 +319,9 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; + DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 4H9ZA7X4C4; ENABLE_HARDENED_RUNTIME = YES; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -316,7 +332,9 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; + DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 4H9ZA7X4C4; ENABLE_HARDENED_RUNTIME = YES; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/reference/macos/usb.xcodeproj/xcshareddata/xcschemes/USB.xcscheme b/reference/macos/usb.xcodeproj/xcshareddata/xcschemes/USB.xcscheme index 46c6a98b..8630fdad 100644 --- a/reference/macos/usb.xcodeproj/xcshareddata/xcschemes/USB.xcscheme +++ b/reference/macos/usb.xcodeproj/xcshareddata/xcschemes/USB.xcscheme @@ -1,6 +1,6 @@ Date: Fri, 4 Nov 2022 16:42:45 +0100 Subject: [PATCH 153/433] Test device loopback directly from/to FIFO --- .../lib/tinyusb/common/tusb_fifo.c | 8 +- .../lib/tinyusb/dwc2/dcd_dwc2.c | 8 +- .../lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c | 104 +++++++++--------- test-devices/loopback-stm32/src/main.c | 37 ++----- .../loopback-stm32/src/vendor_custom.c | 21 ++++ .../loopback-stm32/src/vendor_custom.h | 28 +++++ 6 files changed, 121 insertions(+), 85 deletions(-) diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.c b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.c index 895b9208..b9bcdc7a 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.c +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.c @@ -105,8 +105,8 @@ static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf; // Reading full available 32 bit words from const app address - uint16_t full_words = len >> 2; - while(full_words--) + uint8_t * ff_buf_end = ff_buf + (len & 0xfffc); + while(ff_buf < ff_buf_end) { tu_unaligned_write32(ff_buf, *rx_fifo); ff_buf += 4; @@ -128,8 +128,8 @@ static void _ff_pull_const_addr(void * app_buf, const uint8_t * ff_buf, uint16_t volatile uint32_t * tx_fifo = (volatile uint32_t *) app_buf; // Pushing full available 32 bit words to const app address - uint16_t full_words = len >> 2; - while(full_words--) + const uint8_t * ff_buf_end = ff_buf + (len & 0xfffc); + while(ff_buf < ff_buf_end) { *tx_fifo = tu_unaligned_read32(ff_buf); ff_buf += 4; diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c index f5ecdfe4..98166e7e 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c +++ b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c @@ -931,8 +931,8 @@ static void read_fifo_packet(uint8_t rhport, uint8_t * dst, uint16_t len) volatile const uint32_t * rx_fifo = dwc2->fifo[0]; // Reading full available 32 bit words from fifo - uint16_t full_words = len >> 2; - while(full_words--) + uint8_t * dst_end = dst + (len & 0xfffc); + while(dst < dst_end) { tu_unaligned_write32(dst, *rx_fifo); dst += 4; @@ -958,8 +958,8 @@ static void write_fifo_packet(uint8_t rhport, uint8_t fifo_num, uint8_t const * volatile uint32_t * tx_fifo = dwc2->fifo[fifo_num]; // Pushing full available 32 bit words to fifo - uint16_t full_words = len >> 2; - while(full_words--) + const uint8_t * src_end = src + (len & 0xfffc); + while(src < src_end) { *tx_fifo = tu_unaligned_read32(src); src += 4; diff --git a/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c b/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c index 83768689..6550d568 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c +++ b/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c @@ -163,7 +163,7 @@ TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligne typedef struct { uint8_t * buffer; - // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API + tu_fifo_t * ff; uint16_t total_len; uint16_t queued_len; uint16_t pma_ptr; @@ -196,8 +196,8 @@ static void dcd_pma_free(uint8_t ep_addr); static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes); static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes); -//static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes); -//static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes); +static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes); +static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes); // Using a function due to better type checks // This seems better than having to do type casts everywhere else @@ -526,13 +526,11 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr) if (count != 0U) { -#if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { dcd_read_packet_memory_ff(xfer->ff, *pcd_ep_rx_address_ptr(USB,EPindex), count); } else -#endif { dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), *pcd_ep_rx_address_ptr(USB,EPindex), count); } @@ -873,13 +871,11 @@ static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix) } uint16_t oldAddr = *pcd_ep_tx_address_ptr(USB,ep_ix); -#if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { dcd_write_packet_memory_ff(xfer->ff, oldAddr, len); } else -#endif { dcd_write_packet_memory(oldAddr, &(xfer->buffer[xfer->queued_len]), len); } @@ -899,7 +895,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir); xfer->buffer = buffer; - // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API + xfer->ff = NULL; xfer->total_len = total_bytes; xfer->queued_len = 0; @@ -926,7 +922,6 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t return true; } -#if 0 // TODO support dcd_edpt_xfer_fifo API bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void) rhport; @@ -937,7 +932,7 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir); xfer->buffer = NULL; - // xfer->ff = ff; // TODO support dcd_edpt_xfer_fifo API + xfer->ff = ff; xfer->total_len = total_bytes; xfer->queued_len = 0; @@ -957,7 +952,6 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 } return true; } -#endif void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) { @@ -1032,52 +1026,58 @@ static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, si return true; } -#if 0 // TODO support dcd_edpt_xfer_fifo API /** * @brief Copy from FIFO to packet memory area (PMA). * Uses byte-access of system memory and 16-bit access of packet memory * @param wNBytes no. of bytes to be copied. * @retval None */ - -// THIS FUNCTION IS UNTESTED - static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes) { // Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies + // Check for first linear part - void * src; - uint16_t len = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes); // We want to read from the FIFO - THIS FUNCTION CHANGED!!! - TU_VERIFY(len && dcd_write_packet_memory(dst, src, len)); // and write it into the PMA - tu_fifo_advance_read_pointer(ff, len); + tu_fifo_buffer_info_t info; + tu_fifo_get_read_info(ff, &info); + + uint16_t lenLin = tu_min16(info.len_lin, wNBytes); + TU_VERIFY(lenLin && dcd_write_packet_memory(dst, info.ptr_lin, lenLin)); // and write it into the PMA // Check for wrapped part - if (len < wNBytes) + uint16_t lenWrap = 0; + if (lenLin < wNBytes) { - // Get remaining wrapped length - uint16_t len2 = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes - len); - TU_VERIFY(len2); + TU_VERIFY(info.len_wrap); // Update destination pointer - dst += len; + dst += lenLin; + + // Get destination pointer + uint8_t * src = info.ptr_wrap; + + // Length of second, wrapped part + lenWrap = tu_min16(info.len_wrap, wNBytes - lenLin); // Since PMA is accessed 16-bit wise we need to handle the case when a 16 bit value was split - if (len % 2) // If len is uneven there is a byte left to copy + if (lenLin % 2) // If len is uneven there is a byte left to copy { // Since PMA can accessed only 16 bit-wise we copy the last byte again - tu_fifo_backward_read_pointer(ff, 1); // Move one byte back and copy two bytes for the PMA - tu_fifo_read_n(ff, (void *) &pma[PMA_STRIDE*(dst>>1)], 2); // Since EP FIFOs must be of item size 1 this is safe to do + uint32_t temp = ((uint8_t*)info.ptr_lin)[lenLin - 1] | ((*src) << 8); + pma[PMA_STRIDE*(dst>>1)] = temp; dst++; - len2--; + src++; + lenLin++; + lenWrap--; } - TU_VERIFY(dcd_write_packet_memory(dst, src, len2)); - tu_fifo_advance_write_pointer(ff, len2); + TU_VERIFY(dcd_write_packet_memory(dst, src, lenWrap)); // write it into the PMA } + // update the PMA write pointer + tu_fifo_advance_read_pointer(ff, lenLin + lenWrap); + return true; } -#endif /** * @brief Copy a buffer from packet memory area (PMA) to user memory area. @@ -1114,52 +1114,52 @@ static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wN return true; } -#if 0 // TODO support dcd_edpt_xfer_fifo API /** * @brief Copy a buffer from user packet memory area (PMA) to FIFO. * Uses byte-access of system memory and 16-bit access of packet memory * @param wNBytes no. of bytes to be copied. * @retval None */ - -// THIS FUNCTION IS UNTESTED - static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes) { // Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies // Check for first linear part - void * dst; - uint16_t len = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes); // THIS FUNCTION CHANGED!!!! - TU_VERIFY(len && dcd_read_packet_memory(dst, src, len)); - tu_fifo_advance_write_pointer(ff, len); + tu_fifo_buffer_info_t info; + tu_fifo_get_write_info(ff, &info); + uint16_t lenLin = tu_min16(info.len_lin, wNBytes); + TU_VERIFY(lenLin && dcd_read_packet_memory(info.ptr_lin, src, lenLin)); // Check for wrapped part - if (len < wNBytes) + uint16_t lenWrap = 0; + if (lenLin < wNBytes) { - // Get remaining wrapped length - uint16_t len2 = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes - len); - TU_VERIFY(len2); - // Update source pointer - src += len; + src += lenLin; + + // Get destination pointer + uint8_t * dst = info.ptr_wrap; + + // Length of second, wrapped part + lenWrap = tu_min16(info.len_wrap, wNBytes - lenLin); // Since PMA is accessed 16-bit wise we need to handle the case when a 16 bit value was split - if (len % 2) // If len is uneven there is a byte left to copy + if (lenLin % 2) // If len is uneven there is a byte left to copy { uint32_t temp = pma[PMA_STRIDE*(src>>1)]; - *((uint8_t *)dst++) = ((temp >> 8) & 0xFF); + *dst = temp >> 8; src++; - len2--; + dst++; + lenLin++; + lenWrap--; } - TU_VERIFY(dcd_read_packet_memory(dst, src, len2)); - tu_fifo_advance_write_pointer(ff, len2); + TU_VERIFY(dcd_read_packet_memory(dst, src, lenWrap)); } + tu_fifo_advance_write_pointer(ff, lenLin + lenWrap); + return true; } #endif -#endif - diff --git a/test-devices/loopback-stm32/src/main.c b/test-devices/loopback-stm32/src/main.c index b4978f78..4107ef29 100644 --- a/test-devices/loopback-stm32/src/main.c +++ b/test-devices/loopback-stm32/src/main.c @@ -20,10 +20,9 @@ // FIFO buffer for loopback data tu_fifo_t loopback_fifo; -uint8_t loopback_buffer[2048]; +uint8_t loopback_buffer[2048] __attribute__ ((aligned(4))); -// RX buffer for loopback -uint8_t loopback_rx_buffer[512]; +uint16_t bulk_packet_size = 64; // buffer for echoed packet uint8_t echo_buffer[16]; @@ -79,26 +78,23 @@ void loopback_init(void) { // Check if the next transmission should be started void loopback_check_tx(void) { - tu_fifo_buffer_info_t info; - tu_fifo_get_read_info(&loopback_fifo, &info); + uint16_t n = tu_fifo_count(&loopback_fifo); - if (info.len_lin > 0 && !cust_vendor_is_transmitting(EP_LOOPBACK_TX)) { - int n = info.len_lin; - int max_size = 2 * cust_vendor_packet_size(EP_LOOPBACK_RX); + if (n > 0 && !cust_vendor_is_transmitting(EP_LOOPBACK_TX)) { + uint16_t max_size = 2 * bulk_packet_size; if (n > max_size) n = max_size; - cust_vendor_start_transmit(EP_LOOPBACK_TX, info.ptr_lin, n); + cust_vendor_start_transmit_fifo(EP_LOOPBACK_TX, &loopback_fifo, n); } } // Check if receiving should be started again void loopback_check_rx(void) { - int n = tu_fifo_remaining(&loopback_fifo); - uint16_t packet_size = cust_vendor_packet_size(EP_LOOPBACK_RX); - if (n >= packet_size && !cust_vendor_is_receiving(EP_LOOPBACK_RX)) - cust_vendor_prepare_recv(EP_LOOPBACK_RX, loopback_rx_buffer, packet_size); + uint16_t n = tu_fifo_remaining(&loopback_fifo); + if (n >= bulk_packet_size && !cust_vendor_is_receiving(EP_LOOPBACK_RX)) + cust_vendor_prepare_recv_fifo(EP_LOOPBACK_RX, &loopback_fifo, bulk_packet_size); } @@ -118,7 +114,6 @@ void echo_update_state(void) { // Invoked when new data has been received void cust_vendor_rx_cb(uint8_t ep_addr, uint32_t recv_bytes) { if (ep_addr == EP_LOOPBACK_RX) { - tu_fifo_write_n(&loopback_fifo, loopback_rx_buffer, recv_bytes); loopback_check_rx(); loopback_check_tx(); @@ -132,21 +127,11 @@ void cust_vendor_rx_cb(uint8_t ep_addr, uint32_t recv_bytes) { // Invoked when last tx transfer finished void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes) { if (ep_addr == EP_LOOPBACK_TX) { - - // If buffer has been reset in the mean time, - // we might not be able to advance it fully or at all. - int max_advance = tu_fifo_count(&loopback_fifo); - if (sent_bytes > max_advance) - sent_bytes = max_advance; - if (sent_bytes > 0) - tu_fifo_advance_read_pointer(&loopback_fifo, sent_bytes); - loopback_check_tx(); loopback_check_rx(); // check ZLP - uint16_t packet_size = cust_vendor_packet_size(EP_LOOPBACK_TX); - if ((sent_bytes & (packet_size - 1)) == 0 + if ((sent_bytes & (bulk_packet_size - 1)) == 0 && !cust_vendor_is_transmitting(ep_addr)) cust_vendor_start_transmit(EP_LOOPBACK_TX, NULL, 0); @@ -158,6 +143,7 @@ void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes) { // Invoked when interface has been opened void cust_vendor_intf_open_cb(uint8_t intf) { + bulk_packet_size = cust_vendor_packet_size(EP_LOOPBACK_RX); loopback_check_rx(); echo_update_state(); } @@ -165,6 +151,7 @@ void cust_vendor_intf_open_cb(uint8_t intf) { // Invoked when an alternate interface has been selected void cust_vendor_alt_intf_selected_cb(uint8_t intf, uint8_t alt) { reset_buffers(); + bulk_packet_size = cust_vendor_packet_size(EP_LOOPBACK_RX); loopback_check_rx(); if (alt == 0) echo_update_state(); diff --git a/test-devices/loopback-stm32/src/vendor_custom.c b/test-devices/loopback-stm32/src/vendor_custom.c index 4aae61e4..21f6903f 100644 --- a/test-devices/loopback-stm32/src/vendor_custom.c +++ b/test-devices/loopback-stm32/src/vendor_custom.c @@ -190,6 +190,16 @@ void cust_vendor_prepare_recv(uint8_t ep_addr, void* buf, uint32_t buf_len) { usbd_edpt_xfer(rhport, ep_addr, buf, buf_len); } +void cust_vendor_prepare_recv_fifo(uint8_t ep_addr, tu_fifo_t * fifo, uint32_t buf_len) { + uint8_t const rhport = BOARD_TUD_RHPORT; + + if (usbd_edpt_busy(rhport, ep_addr)) + return; + + usbd_edpt_xfer_fifo(rhport, ep_addr, fifo, buf_len); +} + + void cust_vendor_start_transmit(uint8_t ep_addr, void const * data, uint32_t data_len) { uint8_t const rhport = BOARD_TUD_RHPORT; @@ -200,6 +210,17 @@ void cust_vendor_start_transmit(uint8_t ep_addr, void const * data, uint32_t dat usbd_edpt_xfer(rhport, ep_addr, (void*) data, data_len); } +void cust_vendor_start_transmit_fifo(uint8_t ep_addr, tu_fifo_t * fifo, uint32_t data_len) { + + uint8_t const rhport = BOARD_TUD_RHPORT; + + if (usbd_edpt_busy(rhport, ep_addr)) + return; + + usbd_edpt_xfer_fifo(rhport, ep_addr, (void*) fifo, data_len); +} + + bool cust_vendor_is_receiving(uint8_t ep_addr) { uint8_t const rhport = BOARD_TUD_RHPORT; diff --git a/test-devices/loopback-stm32/src/vendor_custom.h b/test-devices/loopback-stm32/src/vendor_custom.h index 5fd14836..c80abf0a 100644 --- a/test-devices/loopback-stm32/src/vendor_custom.h +++ b/test-devices/loopback-stm32/src/vendor_custom.h @@ -54,6 +54,20 @@ */ void cust_vendor_prepare_recv(uint8_t ep_addr, void* buf, uint32_t buf_len); +/** + * @brief Prepares to recieve data on an OUT endpoint using a FIFO buffer. + * + * The FIFO buffer must have sufficient space to receive the data. + * It's write pointer will updated before the `cust_vendor_rx_cb()` callback is called. + * + * If the OUT endpoint is already receiving data, this function does nothing. + * + * @param ep_addr endpoint address (1 to 127) + * @param fifo pointer to FIFO buffer + * @param buf_len length of buffer + */ +void cust_vendor_prepare_recv_fifo(uint8_t ep_addr, tu_fifo_t * fifo, uint32_t buf_len); + /** * @brief Gets if the endpoint is busy receiving data. * @@ -77,6 +91,20 @@ bool cust_vendor_is_receiving(uint8_t ep_addr); */ void cust_vendor_start_transmit(uint8_t ep_addr, void const * data, uint32_t data_len); +/** + * @brief Transmits data on an IN endpoint using a FIFO buffer. + * + * The data in the FIFO buffer must stay valid until the `cust_vendor_tx_cb()` callback. + * Before the callback, FIFO read pointer is updated. + * + * If the IN endpoint is already transmitting data, this function does nothing. + * + * @param ep_addr endpoint address (129 to 255) + * @param fifo pointer to FIFO buffer + * @param data_len number of bytes to transmit + */ +void cust_vendor_start_transmit_fifo(uint8_t ep_addr, tu_fifo_t * fifo, uint32_t data_len); + /** * @brief Gets if the endpoint is busy transmitting data. * From 6a75d23c8179c73939009176d243634de9bb9b44 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 5 Nov 2022 11:23:49 +0100 Subject: [PATCH 154/433] Minor fixes --- reference/macos/USB/usb_device.cpp | 15 ++++++++++++++- reference/macos/USB/usb_error.cpp | 2 ++ test-devices/loopback-stm32/platformio.ini | 2 +- test-devices/loopback-stm32/src/board_f7.c | 18 ++++++++---------- .../loopback-stm32/src/vendor_custom.c | 3 ++- 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/reference/macos/USB/usb_device.cpp b/reference/macos/USB/usb_device.cpp index 70e7dcee..af49ac0c 100644 --- a/reference/macos/USB/usb_device.cpp +++ b/reference/macos/USB/usb_device.cpp @@ -15,7 +15,9 @@ #include +#include #include +#include usb_device::usb_device(io_service_t service, IOUSBDeviceInterface** device, uint64_t entry_id, int vendor_id, int product_id) : entry_id_(entry_id), device_(device), vendor_id_(vendor_id), product_id_(product_id), is_open_(false) { @@ -89,7 +91,18 @@ void usb_device::open() { if (is_open()) throw new usb_error("USB device is already open", 0); - IOReturn ret = (*device_)->USBDeviceOpen(device_); + // try multiple times to fight race conditions + int tries = 0; + IOReturn ret = 0; + while (tries < 3) { + ret = (*device_)->USBDeviceOpen(device_); + if (ret != kIOReturnExclusiveAccess) + break; + + // sleep and try again + tries += 1; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } usb_error::check(ret, "unable to open USB device"); ret = (*device_)->SetConfiguration(device_, 1); diff --git a/reference/macos/USB/usb_error.cpp b/reference/macos/USB/usb_error.cpp index b24aec03..82ec0b1e 100644 --- a/reference/macos/USB/usb_error.cpp +++ b/reference/macos/USB/usb_error.cpp @@ -37,6 +37,8 @@ std::string usb_error::full_message(const char* message, int code) { std::string msg(message); msg += " ("; msg += mach_error_string(code); + msg += " - code "; + msg += std::to_string(code); msg += ")"; return msg; diff --git a/test-devices/loopback-stm32/platformio.ini b/test-devices/loopback-stm32/platformio.ini index cf6dcbdb..5f2375ab 100644 --- a/test-devices/loopback-stm32/platformio.ini +++ b/test-devices/loopback-stm32/platformio.ini @@ -1,6 +1,6 @@ [common] tinyusb_flags = - -D CFG_VENDOR_ADVANCED=1 + -D CFG_VENDOR_CUSTOM=1 -D CFG_TUSB_RHPORT1_MODE=OPT_MODE_NONE platform = ststm32 framework = cmsis diff --git a/test-devices/loopback-stm32/src/board_f7.c b/test-devices/loopback-stm32/src/board_f7.c index fae9fd90..96229409 100644 --- a/test-devices/loopback-stm32/src/board_f7.c +++ b/test-devices/loopback-stm32/src/board_f7.c @@ -246,23 +246,21 @@ void board_init(void) { gpio_set_af(GPIOB, 15, 10); gpio_set_ospeed(GPIOB, 15, GPIO_OSPEED_HIGH); - // Configure VBUS sense - set_reg(&USB_OTG_HS->GCCFG, USB_OTG_GCCFG_VBDEN, USB_OTG_GCCFG_VBDEN_Msk); - - gpio_mode_setup(GPIOB, 14, GPIO_MODE_ALT, GPIO_PUPD_PULL_UP); - gpio_set_af(GPIOB, 14, 10); - gpio_set_ospeed(GPIOB, 14, GPIO_OSPEED_HIGH); - set_reg(&RCC->APB2ENR, RCC_APB2ENR_OTGPHYCEN, RCC_APB2ENR_OTGPHYCEN_Msk); set_reg(&RCC->AHB1ENR, RCC_AHB1ENR_OTGHSULPIEN, RCC_AHB1ENR_OTGHSULPIEN_Msk); set_reg(&RCC->AHB1ENR, RCC_AHB1ENR_OTGHSEN, RCC_AHB1ENR_OTGHSEN_Msk); - // No VBUS sense - set_reg(&USB_OTG_HS->GCCFG, 0, USB_OTG_GCCFG_VBDEN_Msk); +#if 0 + // Configure hardware VBUS sense (using PB13) + set_reg(&USB_OTG_HS->GCCFG, USB_OTG_GCCFG_VBDEN, USB_OTG_GCCFG_VBDEN_Msk); + gpio_mode_setup(GPIOB, 13, GPIO_MODE_INPUT, GPIO_PUPD_NO_PULL); - // B-peripheral session valid override enable +#else + // Configure no VBUS sense + set_reg(&USB_OTG_HS->GCCFG, 0, USB_OTG_GCCFG_VBDEN_Msk); set_reg(&USB_OTG_HS->GOTGCTL, USB_OTG_GOTGCTL_BVALOEN, USB_OTG_GOTGCTL_BVALOEN_Msk); set_reg(&USB_OTG_HS->GOTGCTL, USB_OTG_GOTGCTL_BVALOVAL, USB_OTG_GOTGCTL_BVALOVAL_Msk); +#endif // Force device mode set_reg(&USB_OTG_HS->GUSBCFG, 0, USB_OTG_GUSBCFG_FHMOD_Msk); diff --git a/test-devices/loopback-stm32/src/vendor_custom.c b/test-devices/loopback-stm32/src/vendor_custom.c index 21f6903f..0a29ce18 100644 --- a/test-devices/loopback-stm32/src/vendor_custom.c +++ b/test-devices/loopback-stm32/src/vendor_custom.c @@ -14,7 +14,7 @@ #include "tusb_option.h" -#if (CFG_TUD_ENABLED && CFG_VENDOR_ADVANCED) +#if (CFG_TUD_ENABLED && CFG_VENDOR_CUSTOM) #include "device/usbd.h" #include "vendor_custom.h" @@ -61,6 +61,7 @@ void cv_reset(uint8_t rhport) { // Open interface is the descriptor matches this class uint16_t cv_open(uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t max_len) { + cv_num_eps_open = 0; int ret = setup_endpoints(rhport, desc_intf, max_len, 0); if (ret != 0) From b4bd2c05f4f32e965fc22da14fcc289d3eb4708d Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 5 Nov 2022 11:32:37 +0100 Subject: [PATCH 155/433] Updated firmware binaries --- .../loopback-stm32/bin/blackpill-f401cc.bin | Bin 10724 -> 10740 bytes .../loopback-stm32/bin/blackpill-f411ce.bin | Bin 10728 -> 10744 bytes .../loopback-stm32/bin/bluepill-f103c8.bin | Bin 8972 -> 9236 bytes .../loopback-stm32/bin/disco_f723ie.bin | Bin 11396 -> 11360 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/test-devices/loopback-stm32/bin/blackpill-f401cc.bin b/test-devices/loopback-stm32/bin/blackpill-f401cc.bin index faebe40689bfbc6d616dd4a93e53dcac150a8dbf..cc7407b7a1943f0bcda40462606782b5b1e4fa2c 100755 GIT binary patch delta 4069 zcmZWs4RjONm40tVvPOScwrniP79MGAEF)MP@+WGtII8`Y%+s?G<%;g z=_adluJ6oy_vgF!-Fx5o(}yP>?tC2=`Vis~{9gAVj*GEUZWmk4R&|V{DAz~V7sCGQ zWDu9nvri%U+|6($LYO~Oj5yfjsWzqaCbEQS#wUAXjKH{uG2#OVtwtPEb{_27wrKfS za)dxPUO{f?iXs)DgLo`&I);!fW~oB*Pp5TaOII_GFDDtQ9W7-j+Wl(K7w5(1 z?!L>mGP=9_OmwJ_z=13D42b{uO`BI&&B9aVn<#!6pkD)$febNJpefHM(F<6pnLwMRhk!+YrUxhq1vQ~oRSCX3YGtD1b66$w79~?htuizW~wVLvjCNw@HV^#=X zNn`;C3S>2kAYKRPtAMbNi|Ge7rB&;@%$0#cob_>odWrG6YITyc_SWjJ<8T^Zfot{! zVmi?(+Ci^QqmHdoZVN8;2eSq#FzX~EHuhqX7yB*;AOkbK&-e_3`jz$&F13TjKpi-G zIv(hwDWnl|F`BrEo2=xBYRbA3|-~0ougUgtRhRx1PM;vK?JpW0H&VOOh zy3!;10CKnt%cJDDA=|%iDoyf;^J;zKr3B`~kb)Me zG4l8V88NzZ{$9(Jgs!$0kJ#U>DL+USivdXGequG{M;=R_PaytW!X^$Ts0-?fy8L|_ z;%0!tsWZkR;^%@+!E{M)Pxk`RlS&YhkGvJ``?`ev8xkWRp(%fWGZ>9iD@bOJYRY8X z7ULwY+C`oK7^@&P+sKG{L$N(Zt+ExngQk>4 z{eU^d?7u%{F)K-}Swdi6`hwJ3ig6LyY01H#ll_*TnGel)#idXXn(_|0!@3ynBz4x@ z>{{(yVu8$>^C!1YZ4~bi%V2*U*=bD_7A5&+9~{Bsu@hVM+wlCeSI{~g?5;|Bw&_I% zx!Ve;K&dQFI7I01MrvHjk6K%%#j+ zjl7h}8*fKZkXrPm77M>x1Zlm5VSWzctUx#IKyz>Li&=VgU!G(b=`z?_c9{W`$k^Ax(Lg z#OE%;Z;{XE=Hm`x&1tY-gDP1*vGEX1f$jiJLNVEzQ_tL(BG+@)<7Of`?sJZ4|M*!t z#PFdZa^oM`ZIJcl6ZP#$Wr*x^_*11vW3WOjZZhIhM`To?F4)s<=f?KW--* zoVnH&N28uEAqg@Bsv}L#MXc|rOuC#K?wp*G6FRsgE*L%=LdQOxm7&J7yvT#$GvUGb zEj{?0sG~I~llxpbSSH_geTQK+a>%s=KSw@x37$u$qHx|w-Y|7ELBq1bgrW|qF$6yy zDa^fOJPen@dbmc`5NqB$_%IpC^TS`g`%d_~)Sc_3`#K3>*ZTKVU4WMP?|_FZ5BEIg z-h}btp0o4r#a1ds?NUn>B!jO^*=sz1EF>aRQb++6l^20y zucj1|I**h>NV~I7(&HVS-{0^=Lsx^PENddVsaa%4^-Qa{Y@lW$`taj*Ia^{?Q8*SP z2d56NM1nosv(g@ZUqwFeL~`>f;2(Cs7(~|xqct+NpHlMzM&Xp26*#5Z0tY0UH-cQz z#rL*JPj2qn3|dPCxF=5O;NexW*n3ChK=hS)PY0jAA42dL+s>-<`LpT*zFqwreurA{ z>JGKgwnO!mB$bboygqXXzRwFdBD-Duol4xP(hmg?n|1YWk zn&cbFx`@F(^kis@A${nZMwzdP{wn!otzcL%#0ihrHb9Rcf6c)ADi@$`k@x??J~3_; z*iPmme%IVCB@$`%n?phr&JVUI6t_QYo6TO6(q~V&m3r!QYJZ zR=Bo~sJ7fSu3g=(CZ-id{4WifC1=YTSDVVgz~p#Wl)%Ke-O{wIR|8c5m0%mH0!|yz zBeQtDYUHc+)z*v(aJ718&^gSu+GQ5a8KADQ<)Ga|5ie=4!@5E^f3mtGJ(w?+jBt zw$)Wp1w7K3U_(K;uP#9h$RC+l*TJUvnvT*R?N~{IkuM+U_(0`KtFH5mJ-B>A?6Avx zdRE*cVBx=D{l3J%!>AjEnYy$C9lIwnXEd0HmmF11{q-vX@p^GtVm7y7qH<9*|9bcH zDd>^$6y}90%(PAk5}T-Bj*XHr+koZ_tfl?!@@%@|vq$ zKu6L>IW~>lD?#TP^DA_F^C!2Clc4vUzaesBJd^eJQWL^eGkXd+zN`1o3sZPYE9&G3 zc5OHB`YU1pYBLBl4-|G%IW&DVv7q6p?H*}Y_cr)X(~8^h_2#x&q;x}!xG zZ*45Q%9d5ZM~SK8TXh!_55tG^yDCETW;2$ot)b)hc3skuJgu=PsbrCZMSa$ja8=x< zx5-a^3FCvXvJq&Q{GiyM@iJVuuK?{ZBCZ{1AK6!2WGaKJ?Q}ZgvP|UN;<^6|8XE@l delta 4160 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 diff --git a/test-devices/loopback-stm32/bin/blackpill-f411ce.bin b/test-devices/loopback-stm32/bin/blackpill-f411ce.bin index 429a99607b6209a710cd79178dae95b03af181b3..3e3c413974a4d8b7ff4b5600e9b058d60738aa14 100755 GIT binary patch delta 4066 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 delta 4039 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 diff --git a/test-devices/loopback-stm32/bin/bluepill-f103c8.bin b/test-devices/loopback-stm32/bin/bluepill-f103c8.bin index 318ad3b0c6d17d4b63c862761c01ab159c3302a1..ea177727ff2765c9a5e005631641ca5c4edf69ac 100755 GIT binary patch delta 4201 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 d_IZK_A+*N!o)ocrxQ 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 Jj3nnQ{a-I+Dr5iv diff --git a/test-devices/loopback-stm32/bin/disco_f723ie.bin b/test-devices/loopback-stm32/bin/disco_f723ie.bin index f64e4b6b00a0001917abee78b03106d539b4f470..0b9f2baf13e0d2248d571c13d1aaf76622012dea 100755 GIT binary patch delta 4527 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 QcTzJCms=BgreN&<00`riga7~l delta 4663 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 OG^`fWZxZ}ep#KA=-QTnT From c1250da48779b6629ff4c9138bcfefd67da9a192 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sat, 5 Nov 2022 11:47:01 +0100 Subject: [PATCH 156/433] Cleaner API (reference code macOS) --- reference/macos/USB/configuration.cpp | 4 ++++ reference/macos/USB/configuration.hpp | 11 ++++++++++- reference/macos/USB/tests.cpp | 2 +- reference/macos/USB/usb_device.cpp | 12 ++++++------ reference/macos/USB/usb_device.hpp | 4 ++-- 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/reference/macos/USB/configuration.cpp b/reference/macos/USB/configuration.cpp index 6e2e4f31..37f244d5 100644 --- a/reference/macos/USB/configuration.cpp +++ b/reference/macos/USB/configuration.cpp @@ -14,6 +14,8 @@ usb_endpoint::usb_endpoint(int number, usb_direction direction, usb_transfer_type transfer_type, int packet_size) : number_(number), direction_(direction), transfer_type_(transfer_type), packet_size_(packet_size) { } +usb_endpoint usb_endpoint::invalid(-1, usb_direction::out, usb_transfer_type::bulk, 0); + // --- usb_alternate_interface @@ -43,6 +45,8 @@ void usb_interface::set_alternate(int index) { alternate_index_ = index; } +usb_interface usb_interface::invalid(-1); + // --- usb_composite_function diff --git a/reference/macos/USB/configuration.hpp b/reference/macos/USB/configuration.hpp index 91f22aed..efd59973 100644 --- a/reference/macos/USB/configuration.hpp +++ b/reference/macos/USB/configuration.hpp @@ -45,6 +45,8 @@ struct usb_endpoint { usb_transfer_type transfer_type() const { return transfer_type_; } /// Maximum packet size int packet_size() const { return packet_size_; } + /// Indicates if this endpoint is valid (or a return value indicating an error) + bool is_valid() const { return number_ >= 0; } private: usb_endpoint(int number, usb_direction direction, usb_transfer_type transfer_type, int packet_size); @@ -53,8 +55,11 @@ struct usb_endpoint { usb_direction direction_; usb_transfer_type transfer_type_; int packet_size_; + + static usb_endpoint invalid; friend class config_parser; + friend class usb_device; }; ///
@@ -97,6 +102,8 @@ struct usb_interface { bool is_claimed() const { return is_claimed_; } /// Currently selected alternate interface const usb_alternate_interface& alternate() const { return alternates_[alternate_index_]; } + /// Indicates if this interface is valid (or a return value indicating an error) + bool is_valid() const { return number_ >= 0; } /// List of all alternate interfaces of this interfaces const std::vector& alternates() const { return alternates_; } @@ -105,11 +112,13 @@ struct usb_interface { void set_claimed(bool claimed); usb_alternate_interface* add_alternate(usb_alternate_interface&& alternate); void set_alternate(int index); - + int number_; bool is_claimed_; int alternate_index_; std::vector alternates_; + + static usb_interface invalid; friend class config_parser; friend class usb_device; diff --git a/reference/macos/USB/tests.cpp b/reference/macos/USB/tests.cpp index 529e7328..894da2e1 100644 --- a/reference/macos/USB/tests.cpp +++ b/reference/macos/USB/tests.cpp @@ -137,7 +137,7 @@ void tests::test_loopback(int num_bytes) { } void tests::test_speed() { - int packet_size = test_device->get_endpoint(usb_direction::out, 1)->packet_size(); + int packet_size = test_device->get_endpoint(usb_direction::out, 1).packet_size(); speed_test test(test_device, 1, 2); test.run(packet_size == 512 ? 20000000 : 2000000); diff --git a/reference/macos/USB/usb_device.cpp b/reference/macos/USB/usb_device.cpp index af49ac0c..f285600c 100644 --- a/reference/macos/USB/usb_device.cpp +++ b/reference/macos/USB/usb_device.cpp @@ -62,24 +62,24 @@ const std::vector& usb_device::interfaces() const { return interfaces_; } -const usb_interface* usb_device::get_interface(int interface_number) const { +const usb_interface& usb_device::get_interface(int interface_number) const { for (const usb_interface& intf : interfaces_) { if (intf.number() == interface_number) - return &intf; + return intf; } - return nullptr; + return usb_interface::invalid; } -const usb_endpoint* usb_device::get_endpoint(usb_direction direction, int endpoint_number) const { +const usb_endpoint& usb_device::get_endpoint(usb_direction direction, int endpoint_number) const { for (const usb_interface& intf : interfaces_) { for (const usb_endpoint& ep : intf.alternate().endpoints()) { if (ep.direction() == direction && ep.number() == endpoint_number) - return &ep; + return ep; } } - return nullptr; + return usb_endpoint::invalid; } diff --git a/reference/macos/USB/usb_device.hpp b/reference/macos/USB/usb_device.hpp index 44c79b7e..4960974b 100644 --- a/reference/macos/USB/usb_device.hpp +++ b/reference/macos/USB/usb_device.hpp @@ -102,7 +102,7 @@ class usb_device { * @param interface_number interface number * @return interface or `nullptr` if no such interface exists */ - const usb_interface* get_interface(int interface_number) const; + const usb_interface& get_interface(int interface_number) const; /** * Get a USB endpoint. @@ -111,7 +111,7 @@ class usb_device { * @param endpoint_number endpoint number (between 1 and 127) * @return endpoint or `nullptr` if endpoint does not exist */ - const usb_endpoint* get_endpoint(usb_direction direction, int endpoint_number) const; + const usb_endpoint& get_endpoint(usb_direction direction, int endpoint_number) const; /// Opens the device for communication void open(); From 5cae95cf31ddd1fe68553415407abca8dc1d726b Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 6 Nov 2022 16:20:33 +0100 Subject: [PATCH 157/433] Windows reference code in par with macOS --- reference/windows/USB/USB.vcxproj | 4 + reference/windows/USB/USB.vcxproj.filters | 12 +++ reference/windows/USB/configuration.cpp | 14 +++ reference/windows/USB/configuration.hpp | 16 ++- reference/windows/USB/prng.cpp | 80 ++++++++++++++ reference/windows/USB/prng.hpp | 72 +++++++++++++ reference/windows/USB/speed_test.cpp | 126 ++++++++++++++++++++++ reference/windows/USB/speed_test.hpp | 38 +++++++ reference/windows/USB/tests.cpp | 11 +- reference/windows/USB/tests.hpp | 1 + reference/windows/USB/usb_device.cpp | 48 ++++++--- reference/windows/USB/usb_device.hpp | 32 ++++-- 12 files changed, 431 insertions(+), 23 deletions(-) create mode 100644 reference/windows/USB/prng.cpp create mode 100644 reference/windows/USB/prng.hpp create mode 100644 reference/windows/USB/speed_test.cpp create mode 100644 reference/windows/USB/speed_test.hpp diff --git a/reference/windows/USB/USB.vcxproj b/reference/windows/USB/USB.vcxproj index 604600e6..b0ed58d6 100644 --- a/reference/windows/USB/USB.vcxproj +++ b/reference/windows/USB/USB.vcxproj @@ -23,6 +23,8 @@ + + @@ -33,7 +35,9 @@ + + diff --git a/reference/windows/USB/USB.vcxproj.filters b/reference/windows/USB/USB.vcxproj.filters index 289ec490..865a9487 100644 --- a/reference/windows/USB/USB.vcxproj.filters +++ b/reference/windows/USB/USB.vcxproj.filters @@ -42,6 +42,12 @@ Source Files + + Source Files + + + Source Files + @@ -71,5 +77,11 @@ Header Files + + Header Files + + + Header Files + \ No newline at end of file diff --git a/reference/windows/USB/configuration.cpp b/reference/windows/USB/configuration.cpp index 6e2e4f31..3db7235c 100644 --- a/reference/windows/USB/configuration.cpp +++ b/reference/windows/USB/configuration.cpp @@ -14,6 +14,8 @@ usb_endpoint::usb_endpoint(int number, usb_direction direction, usb_transfer_type transfer_type, int packet_size) : number_(number), direction_(direction), transfer_type_(transfer_type), packet_size_(packet_size) { } +usb_endpoint usb_endpoint::invalid(-1, usb_direction::out, usb_transfer_type::bulk, 0); + // --- usb_alternate_interface @@ -25,15 +27,25 @@ void usb_alternate_interface::add_endpoint(usb_endpoint&& endpoint) { } +usb_alternate_interface usb_alternate_interface::invalid(-1, 0, 0, 0); + + // --- usb_interface usb_interface::usb_interface(int number) : number_(number), is_claimed_(false), alternate_index_(0) { } +const usb_alternate_interface& usb_interface::alternate() const { + if (alternate_index_ < 0 || alternate_index_ >= alternates_.size()) + return usb_alternate_interface::invalid; + return alternates_[alternate_index_]; +} + void usb_interface::set_claimed(bool claimed) { is_claimed_ = claimed; } + usb_alternate_interface* usb_interface::add_alternate(usb_alternate_interface&& alternate) { alternates_.push_back(std::move(alternate)); return &alternates_.back(); @@ -43,6 +55,8 @@ void usb_interface::set_alternate(int index) { alternate_index_ = index; } +usb_interface usb_interface::invalid(-1); + // --- usb_composite_function diff --git a/reference/windows/USB/configuration.hpp b/reference/windows/USB/configuration.hpp index 91f22aed..5f3dedc9 100644 --- a/reference/windows/USB/configuration.hpp +++ b/reference/windows/USB/configuration.hpp @@ -45,6 +45,8 @@ struct usb_endpoint { usb_transfer_type transfer_type() const { return transfer_type_; } /// Maximum packet size int packet_size() const { return packet_size_; } + /// Indicates if this endpoint is valid (or a return value indicating an error) + bool is_valid() const { return number_ >= 0; } private: usb_endpoint(int number, usb_direction direction, usb_transfer_type transfer_type, int packet_size); @@ -54,7 +56,10 @@ struct usb_endpoint { usb_transfer_type transfer_type_; int packet_size_; + static usb_endpoint invalid; + friend class config_parser; + friend class usb_device; }; /// @@ -72,6 +77,8 @@ struct usb_alternate_interface { int protocol_code() const { return protocol_code_; } /// List of endpoints const std::vector& endpoints() const { return endpoints_; } + /// Indicates if this alternate interface is valid (or a return value indicating an error) + bool is_valid() const { return number_ >= 0; } private: usb_alternate_interface(int number, int class_code, int subclass_code, int protocol_code); @@ -83,7 +90,10 @@ struct usb_alternate_interface { int protocol_code_; std::vector endpoints_; + static usb_alternate_interface invalid; + friend class config_parser; + friend struct usb_interface; }; /// @@ -96,7 +106,9 @@ struct usb_interface { /// Indicates if interface has been claimed bool is_claimed() const { return is_claimed_; } /// Currently selected alternate interface - const usb_alternate_interface& alternate() const { return alternates_[alternate_index_]; } + const usb_alternate_interface& alternate() const; + /// Indicates if this interface is valid (or a return value indicating an error) + bool is_valid() const { return number_ >= 0; } /// List of all alternate interfaces of this interfaces const std::vector& alternates() const { return alternates_; } @@ -111,6 +123,8 @@ struct usb_interface { int alternate_index_; std::vector alternates_; + static usb_interface invalid; + friend class config_parser; friend class usb_device; }; diff --git a/reference/windows/USB/prng.cpp b/reference/windows/USB/prng.cpp new file mode 100644 index 00000000..c9cd0b1a --- /dev/null +++ b/reference/windows/USB/prng.cpp @@ -0,0 +1,80 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#include "prng.hpp" + +prng::prng(uint32_t init) : state(init), nbytes(0), bits(0) {} + +void prng::reset(uint32_t init) +{ + state = init; + nbytes = 0; + bits = 0; +} + +uint32_t prng::next() +{ + uint32_t x = state; + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + state = x; + return x; +} + +void prng::fill(uint8_t *buf, int len) +{ + for (int i = 0; i < len; i++) + { + if (nbytes == 0) + { + bits = next(); + nbytes = 4; + } + buf[i] = bits; + bits >>= 8; + nbytes--; + } +} + +void prng::fill(std::vector& buf, int len) +{ + if (len == -1 || len > buf.size()) + len = static_cast(buf.size()); + + fill(buf.data(), len); +} + +int prng::verify(const uint8_t *buf, int len) +{ + for (int i = 0; i < len; i++) + { + if (nbytes == 0) + { + bits = next(); + nbytes = 4; + } + + if (buf[i] != (uint8_t)bits) + return i; + + bits >>= 8; + nbytes--; + } + + return -1; +} + +int prng::verify(const std::vector &buf, int len) +{ + if (len == -1 || len > buf.size()) + len = static_cast(buf.size()); + + return verify(buf.data(), len); +} diff --git a/reference/windows/USB/prng.hpp b/reference/windows/USB/prng.hpp new file mode 100644 index 00000000..5214dfa6 --- /dev/null +++ b/reference/windows/USB/prng.hpp @@ -0,0 +1,72 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#pragma once + +#include +#include + +/** + * Pseudo Random Number Generator + */ +struct prng +{ + /** + * Constructs a new instance + * @param init initial value + */ + prng(uint32_t init); + + /** + * Returns the next pseudo random value + * @return pseudo random value + */ + uint32_t next(); + + /** + * Fills the buffer with pseudo random data + * @param buf buffer receiving the random data + * @param len length of the buffer (in bytes) + */ + void fill(uint8_t *buf, int len); + + /** + * Fills the buffer with pseudo random data + * @param buf buffer receiving the random data + * @param len number of bytes to fill (-1 for entire buffer) + */ + void fill(std::vector& buf, int len = -1); + + /** + * Verifies that the passed data matches the next bytes of the sequence. + * @param buf buffer with data to verify + * @param len length of the buffer (in bytes) + * @return -1 if they match, otherwise the position of the difference + */ + int verify(const uint8_t *buf, int len); + + /** + * Verifies that the passed data matches the next bytes of the sequence. + * @param buf buffer with data to verify + * @param len number of bytes to verify (-1 for entire buffer) + * @return -1 if they match, otherwise the position of the difference + */ + int verify(const std::vector& buf, int len = -1); + + /** + * Resets the generator to its initial state. + * @param init initial value + */ + void reset(uint32_t init); + +private: + uint32_t state; + int nbytes; + uint32_t bits; +}; diff --git a/reference/windows/USB/speed_test.cpp b/reference/windows/USB/speed_test.cpp new file mode 100644 index 00000000..40141d8f --- /dev/null +++ b/reference/windows/USB/speed_test.cpp @@ -0,0 +1,126 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#include "speed_test.hpp" + +#include "prng.hpp" +#include "usb_error.hpp" + +#include +#include +#include +#include + + +static constexpr uint32_t PRNG_INIT = 0x7b; + + +speed_test::speed_test(usb_device_ptr device, int ep_out, int ep_in) +: device_(device), ep_out_(ep_out), ep_in_(ep_in) { } + +void speed_test::run(int num_bytes) { + reset_buffers(); + start_measurement(); + + std::thread sender(&speed_test::transmit, this, num_bytes / 2); + bool successful = receive(num_bytes / 2); + sender.join(); + + if (successful) + stop_measurement(); +} + +bool speed_test::transmit(int num_bytes) { + + prng seq(PRNG_INIT); + + std::vector buf(2048); + int pos = 0; + + while (num_bytes > 0) { + int n = std::min(num_bytes, static_cast(buf.size())); + try { + seq.fill(buf, n); + device_->transfer_out(ep_out_, buf, n); + + } catch (usb_error& error) { + std::cerr << std::endl << "ERROR: " << error.what() << " (writing at pos " << pos << ")" << std::endl; + return false; + } + + num_bytes -= n; + pos += n; + update_progress(n); + } + + return true; +} + +bool speed_test::receive(int num_bytes) { + + prng seq(PRNG_INIT); + int pos = 0; + + while (num_bytes > 0) { + int n; + try { + std::vector data = device_->transfer_in(ep_in_); + n = std::min(num_bytes, static_cast(data.size())); + int p = seq.verify(data, n); + if (p != -1) { + std::cerr << std::endl << "Invalid data received at pos " << (pos + p) << std::endl; + return false; + } + + } catch (usb_error& error) { + std::cerr << std::endl << "ERROR: " << error.what() << " (reading at pos " << pos << ")" << std::endl; + return false; + } + + num_bytes -= n; + pos += n; + + update_progress(n); + } + + return true; +} + +void speed_test::reset_buffers() { + usb_control_request request_set_value_no_data = { 0 }; + request_set_value_no_data.bmRequestType = usb_control_request::request_type(usb_request_type::direction_out, + usb_request_type::type_vendor, usb_request_type::recipient_interface); + request_set_value_no_data.bRequest = 0x04; + request_set_value_no_data.wIndex = 0; // interface number + device_->control_transfer(request_set_value_no_data); + +} + + +// --- throughput measurement --- + +void speed_test::start_measurement() { + start_time = std::chrono::high_resolution_clock::now(); + processed_bytes = 0; +} + +void speed_test::update_progress(int n) { + std::lock_guard lockGuard(progress_mutex); + processed_bytes += n; +} + +int speed_test::stop_measurement() { + auto end_time = std::chrono::high_resolution_clock::now(); + std::chrono::duration dur = end_time - start_time; + double thr = processed_bytes / dur.count(); + + std::cout << "Throughput: " << std::fixed << std::setprecision(1) << thr << " kByte/s" << std::endl; + + return (int)(thr * 1000); +} diff --git a/reference/windows/USB/speed_test.hpp b/reference/windows/USB/speed_test.hpp new file mode 100644 index 00000000..99f19277 --- /dev/null +++ b/reference/windows/USB/speed_test.hpp @@ -0,0 +1,38 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#pragma once + +#include "usb_device.hpp" + +#include +#include + +class speed_test { +public: + speed_test(usb_device_ptr device, int ep_out, int ep_in); + void run(int num_bytes); + +private: + void reset_buffers(); + bool transmit(int num_bytes); + bool receive(int num_bytes); + + void start_measurement(); + void update_progress(int n); + int stop_measurement(); + + usb_device_ptr device_; + int ep_out_; + int ep_in_; + + std::chrono::time_point start_time; + int processed_bytes; + std::mutex progress_mutex; +}; diff --git a/reference/windows/USB/tests.cpp b/reference/windows/USB/tests.cpp index 657195ef..894da2e1 100644 --- a/reference/windows/USB/tests.cpp +++ b/reference/windows/USB/tests.cpp @@ -9,6 +9,7 @@ #include "tests.hpp" #include "assertion.hpp" +#include "speed_test.hpp" #include #include @@ -47,6 +48,7 @@ void tests::test_current_device() { test_control_transfers(); test_bulk_transfers(); + test_speed(); test_device->release_interface(0); test_device->close(); @@ -111,7 +113,7 @@ void tests::test_loopback(int num_bytes) { std::thread reader([this, &rx_data, num_bytes]() { size_t bytes_read = 0; while (bytes_read < num_bytes) { - auto data = test_device->transfer_in(2, 64); + auto data = test_device->transfer_in(2); rx_data.insert(rx_data.end(), data.begin(), data.end()); bytes_read += data.size(); } @@ -134,6 +136,13 @@ void tests::test_loopback(int num_bytes) { assert_equals(random_data, rx_data); } +void tests::test_speed() { + int packet_size = test_device->get_endpoint(usb_direction::out, 1).packet_size(); + + speed_test test(test_device, 1, 2); + test.run(packet_size == 512 ? 20000000 : 2000000); +} + void tests::on_device(usb_device_ptr device) { if (is_test_device(device)) { test_device = device; diff --git a/reference/windows/USB/tests.hpp b/reference/windows/USB/tests.hpp index 344f495f..11cf328f 100644 --- a/reference/windows/USB/tests.hpp +++ b/reference/windows/USB/tests.hpp @@ -20,6 +20,7 @@ class tests { void test_current_device(); void test_control_transfers(); void test_bulk_transfers(); + void test_speed(); void test_loopback(int num_bytes); diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp index 647ba804..f36af0dd 100644 --- a/reference/windows/USB/usb_device.cpp +++ b/reference/windows/USB/usb_device.cpp @@ -71,6 +71,27 @@ const std::vector& usb_device::interfaces() const { return interfaces_; } +const usb_interface& usb_device::get_interface(int interface_number) const { + for (const usb_interface& intf : interfaces_) { + if (intf.number() == interface_number) + return intf; + } + + return usb_interface::invalid; +} + +const usb_endpoint& usb_device::get_endpoint(usb_direction direction, int endpoint_number) const { + for (const usb_interface& intf : interfaces_) { + for (const usb_endpoint& ep : intf.alternate().endpoints()) { + if (ep.direction() == direction && ep.number() == endpoint_number) + return ep; + } + } + + return usb_endpoint::invalid; +} + + bool usb_device::is_open() const { return is_open_; } @@ -98,7 +119,7 @@ void usb_device::claim_interface(int interface_number) { if (!is_open()) throw usb_error("USB device is not open"); - usb_interface* intf = get_interface(interface_number); + usb_interface* intf = get_intf_ptr(interface_number); if (intf == nullptr) throw usb_error("no such interface"); if (intf->is_claimed()) @@ -139,7 +160,7 @@ void usb_device::release_interface(int interface_number) { if (!is_open()) throw usb_error("USB device is not open"); - usb_interface* intf = get_interface(interface_number); + usb_interface* intf = get_intf_ptr(interface_number); if (intf == nullptr) throw usb_error("no such interface"); if (!intf->is_claimed()) @@ -161,26 +182,29 @@ void usb_device::release_interface(int interface_number) { } } -std::vector usb_device::transfer_in(int endpoint_number, int data_len, int timeout) { +std::vector usb_device::transfer_in(int endpoint_number, int timeout) { auto intf_handle = check_valid_endpoint(usb_direction::in, endpoint_number)->intf_handle; UCHAR endpoint_address = ep_address(usb_direction::in, endpoint_number); + auto endpoint = get_endpoint_ptr(usb_direction::in, endpoint_number); ULONG value = timeout; if (!WinUsb_SetPipePolicy(intf_handle, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) usb_error::throw_error("Failed to set endpoint timeout"); - std::vector data(data_len); + std::vector data(endpoint->packet_size()); DWORD len = 0; - if (!WinUsb_ReadPipe(intf_handle, endpoint_address, static_cast(data.data()), data_len, &len, nullptr)) + if (!WinUsb_ReadPipe(intf_handle, endpoint_address, static_cast(data.data()), endpoint->packet_size(), &len, nullptr)) usb_error::throw_error("Cannot receive from USB endpoint"); data.resize(len); return data; } -void usb_device::transfer_out(int endpoint_number, const std::vector& data, int timeout) { +void usb_device::transfer_out(int endpoint_number, const std::vector& data, int len, int timeout) { + if (len < 0 || len > data.size()) + len = static_cast(data.size()); auto intf_handle = check_valid_endpoint(usb_direction::out, endpoint_number)->intf_handle; UCHAR endpoint_address = ep_address(usb_direction::out, endpoint_number); @@ -189,8 +213,8 @@ void usb_device::transfer_out(int endpoint_number, const std::vector& d if (!WinUsb_SetPipePolicy(intf_handle, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) usb_error::throw_error("Failed to set endpoint timeout"); - DWORD len = 0; - if (!WinUsb_WritePipe(intf_handle, endpoint_address, const_cast(data.data()), static_cast(data.size()), &len, nullptr)) + DWORD tlen = 0; + if (!WinUsb_WritePipe(intf_handle, endpoint_address, const_cast(data.data()), len, &tlen, nullptr)) usb_error::throw_error("Failed to transmit to USB endpoint"); } @@ -252,7 +276,7 @@ usb_device::interface_handle* usb_device::get_control_transfer_interface_handle( } if (intf_num >= 0) { - usb_interface* intf = get_interface(intf_num); + usb_interface* intf = get_intf_ptr(intf_num); if (intf == nullptr) throw usb_error("invalid interface number for control request"); if (!intf->is_claimed()) @@ -306,7 +330,7 @@ usb_device::interface_handle* usb_device::get_interface_handle(int intf_number) return nullptr; } -usb_interface* usb_device::get_interface(int intf_number) { +usb_interface* usb_device::get_intf_ptr(int intf_number) { for (auto& intf : interfaces_) if (intf.number() == intf_number) return &intf; @@ -323,7 +347,7 @@ usb_interface* usb_device::get_endpoint_interface(usb_direction direction, int e return nullptr; } -const usb_endpoint* usb_device::get_endpoint(usb_direction direction, int endpoint_number) { +const usb_endpoint* usb_device::get_endpoint_ptr(usb_direction direction, int endpoint_number) { for (auto& intf : interfaces_) for (auto& ep : intf.alternate().endpoints()) if (ep.number() == endpoint_number && ep.direction() == direction) @@ -337,7 +361,7 @@ usb_device::interface_handle* usb_device::check_valid_endpoint(usb_direction dir if (!is_open()) throw usb_error("USB device is not open"); - const usb_endpoint* ep = get_endpoint(direction, endpoint_number); + const usb_endpoint* ep = get_endpoint_ptr(direction, endpoint_number); if (ep == nullptr) throw usb_error("no such endpoint"); if (ep->transfer_type() != usb_transfer_type::bulk && ep->transfer_type() != usb_transfer_type::interrupt) diff --git a/reference/windows/USB/usb_device.hpp b/reference/windows/USB/usb_device.hpp index d26242a2..08d23a06 100644 --- a/reference/windows/USB/usb_device.hpp +++ b/reference/windows/USB/usb_device.hpp @@ -99,6 +99,23 @@ class usb_device { /// List of interfaces const std::vector& interfaces() const; + /** + * Get the USB interface. + * + * @param interface_number interface number + * @return interface or `nullptr` if no such interface exists + */ + const usb_interface& get_interface(int interface_number) const; + + /** + * Get a USB endpoint. + * + * @param direction endpoint direction + * @param endpoint_number endpoint number (between 1 and 127) + * @return endpoint or `nullptr` if endpoint does not exist + */ + const usb_endpoint& get_endpoint(usb_direction direction, int endpoint_number) const; + /// Opens the device for communication void open(); @@ -126,10 +143,7 @@ class usb_device { * Receives data from a bulk or interrupt endpoint. * * The amount of bytes read will be influced by the underlying USB packets. - * If a short packet is sent, the function will return after having read fewer bytes - * than specified. The function will fail if a bigger packet has been received than - * will fit into the given buffer. So the specified data length should be big enough for - * the maximum packet size (64 bytes for full-speed USB). + * It can be 0 (if the device sends a ZLP) up to the maximum packet size. * * The timeout specifies the maximum time it may take to complete the operation. * If the operation does not complete within that time, the function returns after reading @@ -138,11 +152,10 @@ class usb_device { * Interrupt endpoints do not support timeouts. Thus, 0 has to be specified. * * @param endpoint_number endpoint number (between 1 and 127) - * @param data_len maximum length to read (in bytes) * @param timeout timeout (in ms, 0 for no timeout) * @return received data */ - std::vector transfer_in(int endpoint_number, int data_len, int timeout = 0); + std::vector transfer_in(int endpoint_number, int timeout = 0); /** * Transmits data to a bulk or interrupt endpoint. @@ -155,9 +168,10 @@ class usb_device { * * @param endpoint_number endpoint number (between 1 and 127) * @param data data to transmit + * @param len data length, in bytes (-1 for entire data vector) * @param timeout timeout (in ms, 0 for no timeout) */ - void transfer_out(int endpoint_number, const std::vector& data, int timeout = 0); + void transfer_out(int endpoint_number, const std::vector& data, int len = -1, int timeout = 0); /** * Send a control request with no Data phase. @@ -215,9 +229,9 @@ class usb_device { usb_composite_function* get_function(int intf_number); interface_handle* get_interface_handle(int intf_number); - usb_interface* get_interface(int intf_number); + usb_interface* get_intf_ptr(int intf_number); usb_interface* get_endpoint_interface(usb_direction direction, int endpoint_number); - const usb_endpoint* get_endpoint(usb_direction direction, int endpoint_number); + const usb_endpoint* get_endpoint_ptr(usb_direction direction, int endpoint_number); interface_handle* get_control_transfer_interface_handle(const usb_control_request& request); interface_handle* check_valid_endpoint(usb_direction direction, int endpoint_number); static uint8_t ep_address(usb_direction direction, int endpoint_number) { From 09fcef91163f300623883012866574e8e798c6a5 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 6 Nov 2022 16:38:06 +0100 Subject: [PATCH 158/433] Linux refernce code on par with Windows --- reference/linux/CMakeLists.txt | 2 + reference/linux/configuration.cpp | 14 ++++ reference/linux/configuration.hpp | 16 +++- reference/linux/prng.cpp | 80 +++++++++++++++++++ reference/linux/prng.hpp | 72 +++++++++++++++++ reference/linux/speed_test.cpp | 126 ++++++++++++++++++++++++++++++ reference/linux/speed_test.hpp | 38 +++++++++ reference/linux/tests.cpp | 11 ++- reference/linux/tests.hpp | 1 + reference/linux/usb_device.cpp | 39 +++++++-- reference/linux/usb_device.hpp | 30 +++++-- 11 files changed, 411 insertions(+), 18 deletions(-) create mode 100644 reference/linux/prng.cpp create mode 100644 reference/linux/prng.hpp create mode 100644 reference/linux/speed_test.cpp create mode 100644 reference/linux/speed_test.hpp diff --git a/reference/linux/CMakeLists.txt b/reference/linux/CMakeLists.txt index 2682fa62..d6596572 100644 --- a/reference/linux/CMakeLists.txt +++ b/reference/linux/CMakeLists.txt @@ -12,7 +12,9 @@ set(SOURCES config_parser.cpp config_parser.hpp configuration.cpp configuration.hpp main.cpp + prng.cpp prng.hpp scope.hpp + speed_test.cpp speed_test.hpp tests.cpp tests.hpp usb_device.cpp usb_device.hpp usb_error.cpp usb_error.hpp diff --git a/reference/linux/configuration.cpp b/reference/linux/configuration.cpp index 6e2e4f31..3db7235c 100644 --- a/reference/linux/configuration.cpp +++ b/reference/linux/configuration.cpp @@ -14,6 +14,8 @@ usb_endpoint::usb_endpoint(int number, usb_direction direction, usb_transfer_type transfer_type, int packet_size) : number_(number), direction_(direction), transfer_type_(transfer_type), packet_size_(packet_size) { } +usb_endpoint usb_endpoint::invalid(-1, usb_direction::out, usb_transfer_type::bulk, 0); + // --- usb_alternate_interface @@ -25,15 +27,25 @@ void usb_alternate_interface::add_endpoint(usb_endpoint&& endpoint) { } +usb_alternate_interface usb_alternate_interface::invalid(-1, 0, 0, 0); + + // --- usb_interface usb_interface::usb_interface(int number) : number_(number), is_claimed_(false), alternate_index_(0) { } +const usb_alternate_interface& usb_interface::alternate() const { + if (alternate_index_ < 0 || alternate_index_ >= alternates_.size()) + return usb_alternate_interface::invalid; + return alternates_[alternate_index_]; +} + void usb_interface::set_claimed(bool claimed) { is_claimed_ = claimed; } + usb_alternate_interface* usb_interface::add_alternate(usb_alternate_interface&& alternate) { alternates_.push_back(std::move(alternate)); return &alternates_.back(); @@ -43,6 +55,8 @@ void usb_interface::set_alternate(int index) { alternate_index_ = index; } +usb_interface usb_interface::invalid(-1); + // --- usb_composite_function diff --git a/reference/linux/configuration.hpp b/reference/linux/configuration.hpp index 91f22aed..5f3dedc9 100644 --- a/reference/linux/configuration.hpp +++ b/reference/linux/configuration.hpp @@ -45,6 +45,8 @@ struct usb_endpoint { usb_transfer_type transfer_type() const { return transfer_type_; } /// Maximum packet size int packet_size() const { return packet_size_; } + /// Indicates if this endpoint is valid (or a return value indicating an error) + bool is_valid() const { return number_ >= 0; } private: usb_endpoint(int number, usb_direction direction, usb_transfer_type transfer_type, int packet_size); @@ -54,7 +56,10 @@ struct usb_endpoint { usb_transfer_type transfer_type_; int packet_size_; + static usb_endpoint invalid; + friend class config_parser; + friend class usb_device; }; /// @@ -72,6 +77,8 @@ struct usb_alternate_interface { int protocol_code() const { return protocol_code_; } /// List of endpoints const std::vector& endpoints() const { return endpoints_; } + /// Indicates if this alternate interface is valid (or a return value indicating an error) + bool is_valid() const { return number_ >= 0; } private: usb_alternate_interface(int number, int class_code, int subclass_code, int protocol_code); @@ -83,7 +90,10 @@ struct usb_alternate_interface { int protocol_code_; std::vector endpoints_; + static usb_alternate_interface invalid; + friend class config_parser; + friend struct usb_interface; }; /// @@ -96,7 +106,9 @@ struct usb_interface { /// Indicates if interface has been claimed bool is_claimed() const { return is_claimed_; } /// Currently selected alternate interface - const usb_alternate_interface& alternate() const { return alternates_[alternate_index_]; } + const usb_alternate_interface& alternate() const; + /// Indicates if this interface is valid (or a return value indicating an error) + bool is_valid() const { return number_ >= 0; } /// List of all alternate interfaces of this interfaces const std::vector& alternates() const { return alternates_; } @@ -111,6 +123,8 @@ struct usb_interface { int alternate_index_; std::vector alternates_; + static usb_interface invalid; + friend class config_parser; friend class usb_device; }; diff --git a/reference/linux/prng.cpp b/reference/linux/prng.cpp new file mode 100644 index 00000000..c9cd0b1a --- /dev/null +++ b/reference/linux/prng.cpp @@ -0,0 +1,80 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#include "prng.hpp" + +prng::prng(uint32_t init) : state(init), nbytes(0), bits(0) {} + +void prng::reset(uint32_t init) +{ + state = init; + nbytes = 0; + bits = 0; +} + +uint32_t prng::next() +{ + uint32_t x = state; + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + state = x; + return x; +} + +void prng::fill(uint8_t *buf, int len) +{ + for (int i = 0; i < len; i++) + { + if (nbytes == 0) + { + bits = next(); + nbytes = 4; + } + buf[i] = bits; + bits >>= 8; + nbytes--; + } +} + +void prng::fill(std::vector& buf, int len) +{ + if (len == -1 || len > buf.size()) + len = static_cast(buf.size()); + + fill(buf.data(), len); +} + +int prng::verify(const uint8_t *buf, int len) +{ + for (int i = 0; i < len; i++) + { + if (nbytes == 0) + { + bits = next(); + nbytes = 4; + } + + if (buf[i] != (uint8_t)bits) + return i; + + bits >>= 8; + nbytes--; + } + + return -1; +} + +int prng::verify(const std::vector &buf, int len) +{ + if (len == -1 || len > buf.size()) + len = static_cast(buf.size()); + + return verify(buf.data(), len); +} diff --git a/reference/linux/prng.hpp b/reference/linux/prng.hpp new file mode 100644 index 00000000..5214dfa6 --- /dev/null +++ b/reference/linux/prng.hpp @@ -0,0 +1,72 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#pragma once + +#include +#include + +/** + * Pseudo Random Number Generator + */ +struct prng +{ + /** + * Constructs a new instance + * @param init initial value + */ + prng(uint32_t init); + + /** + * Returns the next pseudo random value + * @return pseudo random value + */ + uint32_t next(); + + /** + * Fills the buffer with pseudo random data + * @param buf buffer receiving the random data + * @param len length of the buffer (in bytes) + */ + void fill(uint8_t *buf, int len); + + /** + * Fills the buffer with pseudo random data + * @param buf buffer receiving the random data + * @param len number of bytes to fill (-1 for entire buffer) + */ + void fill(std::vector& buf, int len = -1); + + /** + * Verifies that the passed data matches the next bytes of the sequence. + * @param buf buffer with data to verify + * @param len length of the buffer (in bytes) + * @return -1 if they match, otherwise the position of the difference + */ + int verify(const uint8_t *buf, int len); + + /** + * Verifies that the passed data matches the next bytes of the sequence. + * @param buf buffer with data to verify + * @param len number of bytes to verify (-1 for entire buffer) + * @return -1 if they match, otherwise the position of the difference + */ + int verify(const std::vector& buf, int len = -1); + + /** + * Resets the generator to its initial state. + * @param init initial value + */ + void reset(uint32_t init); + +private: + uint32_t state; + int nbytes; + uint32_t bits; +}; diff --git a/reference/linux/speed_test.cpp b/reference/linux/speed_test.cpp new file mode 100644 index 00000000..40141d8f --- /dev/null +++ b/reference/linux/speed_test.cpp @@ -0,0 +1,126 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#include "speed_test.hpp" + +#include "prng.hpp" +#include "usb_error.hpp" + +#include +#include +#include +#include + + +static constexpr uint32_t PRNG_INIT = 0x7b; + + +speed_test::speed_test(usb_device_ptr device, int ep_out, int ep_in) +: device_(device), ep_out_(ep_out), ep_in_(ep_in) { } + +void speed_test::run(int num_bytes) { + reset_buffers(); + start_measurement(); + + std::thread sender(&speed_test::transmit, this, num_bytes / 2); + bool successful = receive(num_bytes / 2); + sender.join(); + + if (successful) + stop_measurement(); +} + +bool speed_test::transmit(int num_bytes) { + + prng seq(PRNG_INIT); + + std::vector buf(2048); + int pos = 0; + + while (num_bytes > 0) { + int n = std::min(num_bytes, static_cast(buf.size())); + try { + seq.fill(buf, n); + device_->transfer_out(ep_out_, buf, n); + + } catch (usb_error& error) { + std::cerr << std::endl << "ERROR: " << error.what() << " (writing at pos " << pos << ")" << std::endl; + return false; + } + + num_bytes -= n; + pos += n; + update_progress(n); + } + + return true; +} + +bool speed_test::receive(int num_bytes) { + + prng seq(PRNG_INIT); + int pos = 0; + + while (num_bytes > 0) { + int n; + try { + std::vector data = device_->transfer_in(ep_in_); + n = std::min(num_bytes, static_cast(data.size())); + int p = seq.verify(data, n); + if (p != -1) { + std::cerr << std::endl << "Invalid data received at pos " << (pos + p) << std::endl; + return false; + } + + } catch (usb_error& error) { + std::cerr << std::endl << "ERROR: " << error.what() << " (reading at pos " << pos << ")" << std::endl; + return false; + } + + num_bytes -= n; + pos += n; + + update_progress(n); + } + + return true; +} + +void speed_test::reset_buffers() { + usb_control_request request_set_value_no_data = { 0 }; + request_set_value_no_data.bmRequestType = usb_control_request::request_type(usb_request_type::direction_out, + usb_request_type::type_vendor, usb_request_type::recipient_interface); + request_set_value_no_data.bRequest = 0x04; + request_set_value_no_data.wIndex = 0; // interface number + device_->control_transfer(request_set_value_no_data); + +} + + +// --- throughput measurement --- + +void speed_test::start_measurement() { + start_time = std::chrono::high_resolution_clock::now(); + processed_bytes = 0; +} + +void speed_test::update_progress(int n) { + std::lock_guard lockGuard(progress_mutex); + processed_bytes += n; +} + +int speed_test::stop_measurement() { + auto end_time = std::chrono::high_resolution_clock::now(); + std::chrono::duration dur = end_time - start_time; + double thr = processed_bytes / dur.count(); + + std::cout << "Throughput: " << std::fixed << std::setprecision(1) << thr << " kByte/s" << std::endl; + + return (int)(thr * 1000); +} diff --git a/reference/linux/speed_test.hpp b/reference/linux/speed_test.hpp new file mode 100644 index 00000000..99f19277 --- /dev/null +++ b/reference/linux/speed_test.hpp @@ -0,0 +1,38 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#pragma once + +#include "usb_device.hpp" + +#include +#include + +class speed_test { +public: + speed_test(usb_device_ptr device, int ep_out, int ep_in); + void run(int num_bytes); + +private: + void reset_buffers(); + bool transmit(int num_bytes); + bool receive(int num_bytes); + + void start_measurement(); + void update_progress(int n); + int stop_measurement(); + + usb_device_ptr device_; + int ep_out_; + int ep_in_; + + std::chrono::time_point start_time; + int processed_bytes; + std::mutex progress_mutex; +}; diff --git a/reference/linux/tests.cpp b/reference/linux/tests.cpp index 144586f1..9113dc53 100644 --- a/reference/linux/tests.cpp +++ b/reference/linux/tests.cpp @@ -9,6 +9,7 @@ #include "tests.hpp" #include "assertion.hpp" +#include "speed_test.hpp" #include #include @@ -43,6 +44,7 @@ void tests::test_current_device() { test_control_transfers(); test_bulk_transfers(); + test_speed(); test_device->release_interface(0); test_device->close(); @@ -107,7 +109,7 @@ void tests::test_loopback(int num_bytes) { std::thread reader([this, &rx_data, num_bytes]() { size_t bytes_read = 0; while (bytes_read < num_bytes) { - auto data = test_device->transfer_in(2, 64); + auto data = test_device->transfer_in(2); rx_data.insert(rx_data.end(), data.begin(), data.end()); bytes_read += data.size(); } @@ -130,6 +132,13 @@ void tests::test_loopback(int num_bytes) { assert_equals(random_data, rx_data); } +void tests::test_speed() { + int packet_size = test_device->get_endpoint(usb_direction::out, 1).packet_size(); + + speed_test test(test_device, 1, 2); + test.run(packet_size == 512 ? 20000000 : 2000000); +} + void tests::on_device(usb_device_ptr device) { if (is_test_device(device)) { test_device = device; diff --git a/reference/linux/tests.hpp b/reference/linux/tests.hpp index 344f495f..11cf328f 100644 --- a/reference/linux/tests.hpp +++ b/reference/linux/tests.hpp @@ -20,6 +20,7 @@ class tests { void test_current_device(); void test_control_transfers(); void test_bulk_transfers(); + void test_speed(); void test_loopback(int num_bytes); diff --git a/reference/linux/usb_device.cpp b/reference/linux/usb_device.cpp index 905d24ec..5ee5c765 100644 --- a/reference/linux/usb_device.cpp +++ b/reference/linux/usb_device.cpp @@ -75,6 +75,27 @@ const std::vector& usb_device::interfaces() const { return interfaces_; } +const usb_interface& usb_device::get_interface(int interface_number) const { + for (const usb_interface& intf : interfaces_) { + if (intf.number() == interface_number) + return intf; + } + + return usb_interface::invalid; +} + +const usb_endpoint& usb_device::get_endpoint(usb_direction direction, int endpoint_number) const { + for (const usb_interface& intf : interfaces_) { + for (const usb_endpoint& ep : intf.alternate().endpoints()) { + if (ep.direction() == direction && ep.number() == endpoint_number) + return ep; + } + } + + return usb_endpoint::invalid; +} + + bool usb_device::is_open() const { return fd_ >= 0; } @@ -108,7 +129,7 @@ void usb_device::claim_interface(int interface_number) { if (!is_open()) throw usb_error("device is not open"); - usb_interface* intf = get_interface(interface_number); + usb_interface* intf = get_intf_ptr(interface_number); if (intf == nullptr) throw usb_error("no such interface"); @@ -128,7 +149,7 @@ void usb_device::release_interface(int interface_number) { if (!is_open()) throw usb_error("device is not open"); - usb_interface* intf = get_interface(interface_number); + usb_interface* intf = get_intf_ptr(interface_number); if (intf == nullptr) throw usb_error("no such interface"); @@ -143,15 +164,15 @@ void usb_device::release_interface(int interface_number) { claimed_interfaces_.erase(interface_number); } -std::vector usb_device::transfer_in(int endpoint_number, int data_len, int timeout) { +std::vector usb_device::transfer_in(int endpoint_number, int timeout) { - check_endpoint(usb_direction::in, endpoint_number); + auto ep = check_endpoint(usb_direction::in, endpoint_number); - std::vector data(data_len); + std::vector data(ep->packet_size()); struct usbdevfs_bulktransfer transfer = {0}; transfer.ep = endpoint_number + 128; - transfer.len = data_len; + transfer.len = ep->packet_size(); transfer.timeout = timeout; transfer.data = data.data(); @@ -163,7 +184,9 @@ std::vector usb_device::transfer_in(int endpoint_number, int data_len, return data; } -void usb_device::transfer_out(int endpoint_number, const std::vector& data, int timeout) { +void usb_device::transfer_out(int endpoint_number, const std::vector& data, int len, int timeout) { + if (len < 0 || len > data.size()) + len = static_cast(data.size()); check_endpoint(usb_direction::out, endpoint_number); @@ -223,7 +246,7 @@ std::vector usb_device::control_transfer_in(const usb_control_request& return data; } -usb_interface* usb_device::get_interface(int number) { +usb_interface* usb_device::get_intf_ptr(int number) { for (auto& intf : interfaces_) if (intf.number() == number) return &intf; diff --git a/reference/linux/usb_device.hpp b/reference/linux/usb_device.hpp index e9048ace..d9aca1a9 100644 --- a/reference/linux/usb_device.hpp +++ b/reference/linux/usb_device.hpp @@ -93,6 +93,23 @@ class usb_device { /// List of interfaces const std::vector& interfaces() const; + /** + * Get the USB interface. + * + * @param interface_number interface number + * @return interface or `nullptr` if no such interface exists + */ + const usb_interface& get_interface(int interface_number) const; + + /** + * Get a USB endpoint. + * + * @param direction endpoint direction + * @param endpoint_number endpoint number (between 1 and 127) + * @return endpoint or `nullptr` if endpoint does not exist + */ + const usb_endpoint& get_endpoint(usb_direction direction, int endpoint_number) const; + /// Opens the device for communication void open(); @@ -120,10 +137,7 @@ class usb_device { * Receives data from a bulk or interrupt endpoint. * * The amount of bytes read will be influced by the underlying USB packets. - * If a short packet is sent, the function will return after having read fewer bytes - * than specified. The function will fail if a bigger packet has been received than - * will fit into the given buffer. So the specified data length should be big enough for - * the maximum packet size (64 bytes for full-speed USB). + * It can be 0 (if the device sends a ZLP) up to the maximum packet size. * * The timeout specifies the maximum time it may take to complete the operation. * If the operation does not complete within that time, the function returns after reading @@ -132,11 +146,10 @@ class usb_device { * Interrupt endpoints do not support timeouts. Thus, 0 has to be specified. * * @param endpoint_number endpoint number (between 1 and 127) - * @param data_len maximum length to read (in bytes) * @param timeout timeout (in ms, 0 for no timeout) * @return received data */ - std::vector transfer_in(int endpoint_number, int data_len, int timeout = 0); + std::vector transfer_in(int endpoint_number, int timeout = 0); /** * Transmits data to a bulk or interrupt endpoint. @@ -149,9 +162,10 @@ class usb_device { * * @param endpoint_number endpoint number (between 1 and 127) * @param data data to transmit + * @param len data length, in bytes (-1 for entire data vector) * @param timeout timeout (in ms, 0 for no timeout) */ - void transfer_out(int endpoint_number, const std::vector& data, int timeout = 0); + void transfer_out(int endpoint_number, const std::vector& data, int len = -1, int timeout = 0); /** * Send a control request with no Data phase. @@ -195,7 +209,7 @@ class usb_device { const char* path() const { return path_.c_str(); } int control_transfer_core(const usb_control_request& request, uint8_t* data, int timeout); void read_descriptor(); - usb_interface* get_interface(int number); + usb_interface* get_intf_ptr(int number); const usb_endpoint* check_endpoint(usb_direction direction, int endpoint_number); std::string path_; From e7d67e2d7459491a0b5c68046e09d450ad8b694d Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Sun, 6 Nov 2022 20:22:21 +0100 Subject: [PATCH 159/433] macOS reference code on par with others --- reference/macos/USB/configuration.cpp | 10 ++++++++++ reference/macos/USB/configuration.hpp | 13 +++++++++---- reference/macos/USB/usb_device.hpp | 2 +- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/reference/macos/USB/configuration.cpp b/reference/macos/USB/configuration.cpp index 37f244d5..3db7235c 100644 --- a/reference/macos/USB/configuration.cpp +++ b/reference/macos/USB/configuration.cpp @@ -27,15 +27,25 @@ void usb_alternate_interface::add_endpoint(usb_endpoint&& endpoint) { } +usb_alternate_interface usb_alternate_interface::invalid(-1, 0, 0, 0); + + // --- usb_interface usb_interface::usb_interface(int number) : number_(number), is_claimed_(false), alternate_index_(0) { } +const usb_alternate_interface& usb_interface::alternate() const { + if (alternate_index_ < 0 || alternate_index_ >= alternates_.size()) + return usb_alternate_interface::invalid; + return alternates_[alternate_index_]; +} + void usb_interface::set_claimed(bool claimed) { is_claimed_ = claimed; } + usb_alternate_interface* usb_interface::add_alternate(usb_alternate_interface&& alternate) { alternates_.push_back(std::move(alternate)); return &alternates_.back(); diff --git a/reference/macos/USB/configuration.hpp b/reference/macos/USB/configuration.hpp index efd59973..5f3dedc9 100644 --- a/reference/macos/USB/configuration.hpp +++ b/reference/macos/USB/configuration.hpp @@ -55,7 +55,7 @@ struct usb_endpoint { usb_direction direction_; usb_transfer_type transfer_type_; int packet_size_; - + static usb_endpoint invalid; friend class config_parser; @@ -77,6 +77,8 @@ struct usb_alternate_interface { int protocol_code() const { return protocol_code_; } /// List of endpoints const std::vector& endpoints() const { return endpoints_; } + /// Indicates if this alternate interface is valid (or a return value indicating an error) + bool is_valid() const { return number_ >= 0; } private: usb_alternate_interface(int number, int class_code, int subclass_code, int protocol_code); @@ -88,7 +90,10 @@ struct usb_alternate_interface { int protocol_code_; std::vector endpoints_; + static usb_alternate_interface invalid; + friend class config_parser; + friend struct usb_interface; }; /// @@ -101,7 +106,7 @@ struct usb_interface { /// Indicates if interface has been claimed bool is_claimed() const { return is_claimed_; } /// Currently selected alternate interface - const usb_alternate_interface& alternate() const { return alternates_[alternate_index_]; } + const usb_alternate_interface& alternate() const; /// Indicates if this interface is valid (or a return value indicating an error) bool is_valid() const { return number_ >= 0; } /// List of all alternate interfaces of this interfaces @@ -112,12 +117,12 @@ struct usb_interface { void set_claimed(bool claimed); usb_alternate_interface* add_alternate(usb_alternate_interface&& alternate); void set_alternate(int index); - + int number_; bool is_claimed_; int alternate_index_; std::vector alternates_; - + static usb_interface invalid; friend class config_parser; diff --git a/reference/macos/USB/usb_device.hpp b/reference/macos/USB/usb_device.hpp index 4960974b..e601ea29 100644 --- a/reference/macos/USB/usb_device.hpp +++ b/reference/macos/USB/usb_device.hpp @@ -95,7 +95,7 @@ class usb_device { std::string description() const; /// List of interfaces const std::vector& interfaces() const; - + /** * Get the USB interface. * From 524b8cd34d062afd8398a67c1b286efea0b111ee Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 7 Nov 2022 21:08:39 +0100 Subject: [PATCH 160/433] Test device: Enable caches --- test-devices/loopback-stm32/src/board_f7.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test-devices/loopback-stm32/src/board_f7.c b/test-devices/loopback-stm32/src/board_f7.c index 96229409..bdff30b4 100644 --- a/test-devices/loopback-stm32/src/board_f7.c +++ b/test-devices/loopback-stm32/src/board_f7.c @@ -232,6 +232,15 @@ static void usb_init_serial_num() { void board_init(void) { + // Enable CPU instruction cache + SCB_EnableICache(); + // Enable CPU data cache + SCB_EnableDCache(); + // Enable ART accelerator + //set_reg(&FLASH->ACR, FLASH_ACR_ARTEN, FLASH_ACR_ARTEN_Msk); + // Enable instruction prefetch + //set_reg(&FLASH->ACR, FLASH_ACR_PRFTEN, FLASH_ACR_PRFTEN_Msk); + rcc_clock_setup_hse(&clock_setup_hse_216mhz_3v3); systick_init(); From 3450dfc6ac654ef7670f807eafa2845e182c6663 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 26 Dec 2022 11:55:37 +0100 Subject: [PATCH 161/433] Fix TinyUSB interrupt handling --- test-devices/composite-stm32/lib/tinyusb/dwc2/dcd_dwc2.c | 2 +- test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dcd_dwc2.c b/test-devices/composite-stm32/lib/tinyusb/dwc2/dcd_dwc2.c index f5ecdfe4..7765afd8 100644 --- a/test-devices/composite-stm32/lib/tinyusb/dwc2/dcd_dwc2.c +++ b/test-devices/composite-stm32/lib/tinyusb/dwc2/dcd_dwc2.c @@ -1313,7 +1313,7 @@ void dcd_int_handler(uint8_t rhport) do { handle_rxflvl_irq(rhport); - } while(dwc2->gotgint & GINTSTS_RXFLVL); + } while(dwc2->gintsts & GINTSTS_RXFLVL); // Manage RX FIFO size if (_out_ep_closed) diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c index 98166e7e..ef703d29 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c +++ b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c @@ -1313,7 +1313,7 @@ void dcd_int_handler(uint8_t rhport) do { handle_rxflvl_irq(rhport); - } while(dwc2->gotgint & GINTSTS_RXFLVL); + } while(dwc2->gintsts & GINTSTS_RXFLVL); // Manage RX FIFO size if (_out_ep_closed) From 97308ecb34bfb457f4c1cfb2317f37ccd1fd2b01 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 26 Dec 2022 11:58:02 +0100 Subject: [PATCH 162/433] Throw by value --- reference/linux/assertion.cpp | 2 +- reference/macos/USB/assertion.cpp | 2 +- reference/macos/USB/usb_device.cpp | 2 +- reference/windows/USB/assertion.cpp | 2 +- reference/windows/USB/usb_device.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/reference/linux/assertion.cpp b/reference/linux/assertion.cpp index 71aef91f..eed1265f 100644 --- a/reference/linux/assertion.cpp +++ b/reference/linux/assertion.cpp @@ -16,7 +16,7 @@ static void failed(const char* check, const char* message) { if (message == nullptr) message = "Check failed"; std::cerr << message << ": " << check << std::endl; - throw new check_failed_error(); + throw check_failed_error(); } void assert_equals(int expected, int actual, const char* message) { diff --git a/reference/macos/USB/assertion.cpp b/reference/macos/USB/assertion.cpp index eb55f334..c978c8cb 100644 --- a/reference/macos/USB/assertion.cpp +++ b/reference/macos/USB/assertion.cpp @@ -16,7 +16,7 @@ static void failed(const char* check, const char* message) { if (message == nullptr) message = "Check failed"; std::cerr << message << ": " << check << std::endl; - throw new check_failed_error(); + throw check_failed_error(); } void assert_equals(int expected, int actual, const char* message) { diff --git a/reference/macos/USB/usb_device.cpp b/reference/macos/USB/usb_device.cpp index f285600c..78869df8 100644 --- a/reference/macos/USB/usb_device.cpp +++ b/reference/macos/USB/usb_device.cpp @@ -89,7 +89,7 @@ bool usb_device::is_open() const { void usb_device::open() { if (is_open()) - throw new usb_error("USB device is already open", 0); + throw usb_error("USB device is already open", 0); // try multiple times to fight race conditions int tries = 0; diff --git a/reference/windows/USB/assertion.cpp b/reference/windows/USB/assertion.cpp index d3cb93c3..cc8be65b 100644 --- a/reference/windows/USB/assertion.cpp +++ b/reference/windows/USB/assertion.cpp @@ -16,7 +16,7 @@ static void failed(const char* check, const char* message) { if (message == nullptr) message = "Check failed"; std::cerr << message << ": " << check << std::endl; - throw new check_failed_error(); + throw check_failed_error(); } void assert_equals(int expected, int actual, const char* message) { diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp index f36af0dd..25ab8787 100644 --- a/reference/windows/USB/usb_device.cpp +++ b/reference/windows/USB/usb_device.cpp @@ -98,7 +98,7 @@ bool usb_device::is_open() const { void usb_device::open() { if (is_open()) - throw new usb_error("USB device is already open", 0); + throw usb_error("USB device is already open", 0); is_open_ = true; } From ac01700bcb9b598b9327acab1c3d204a52cc4e63 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 26 Dec 2022 12:09:13 +0100 Subject: [PATCH 163/433] Precompiled firmware --- .../composite-stm32/bin/blackpill-f401cc.bin | Bin 11620 -> 11620 bytes .../loopback-stm32/bin/blackpill-f401cc.bin | Bin 10740 -> 10740 bytes .../loopback-stm32/bin/blackpill-f411ce.bin | Bin 10744 -> 10744 bytes .../loopback-stm32/bin/disco_f723ie.bin | Bin 11360 -> 11504 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/test-devices/composite-stm32/bin/blackpill-f401cc.bin b/test-devices/composite-stm32/bin/blackpill-f401cc.bin index ae324548b89dc3edb59d1c37349f4befb7b06681..3e2f142ad4dd479b717041324ebac075fbf9c0d3 100755 GIT binary patch delta 14 VcmaD7^(1P8wHjmQW*apPb^tMc1v~%% delta 14 VcmaD7^(1P8wHjl_W*apPb^tMW1v>x$ diff --git a/test-devices/loopback-stm32/bin/blackpill-f401cc.bin b/test-devices/loopback-stm32/bin/blackpill-f401cc.bin index cc7407b7a1943f0bcda40462606782b5b1e4fa2c..872fca7e598a7376bf37fec25385ce4e8f4648da 100755 GIT binary patch delta 14 Vcmewo{3Un;y9#6GW)77%tN<}W1*8A~ delta 14 Vcmewo{3Un;y9#5*W)77%tN<}Q1)~4} diff --git a/test-devices/loopback-stm32/bin/blackpill-f411ce.bin b/test-devices/loopback-stm32/bin/blackpill-f411ce.bin index 3e3c413974a4d8b7ff4b5600e9b058d60738aa14..6d848f7a377c768736f4c0e1d2e50e99efeea1a9 100755 GIT binary patch delta 14 Vcmewn{3Cb+w+dtCW*(I{tN=0I1+)MF delta 14 Vcmewn{3Cb+w+ds%W*(I{tN=0C1+xGE diff --git a/test-devices/loopback-stm32/bin/disco_f723ie.bin b/test-devices/loopback-stm32/bin/disco_f723ie.bin index 0b9f2baf13e0d2248d571c13d1aaf76622012dea..76dd788b5b0994b41910ced54300bfd6f9f8624b 100755 GIT binary patch delta 960 zcmZuwTSyd97(Qpt?0R<7bX;`Ryv*)kNwb=lZf42q((3MNru&jgG1AK{Wo|(|1?`d# zDU{WTqKC>Z21QUYMD$Rm23@2F6$t{t>LC)0u@&1)w0|O=BtBAmKZYXoDT3ufNUW7vE?1pYv4Hg8e7FW7 zUVO#cImRh6<4Ea=_@f7bmQd;}DiuchV+}q1v5uah_-^M4ZwXaHt)*=xzU2>wY_pNF zf|0>^XR(nTjYo<-bCbu0Vz2q3*sij^gjP(Z%!vhFhqrDDCE#*2<8}|ml_L$=b0cDf zZAMJ~`ukhKkVgfn;9v1GenB1f5FL|%+ossmYY7YE-GNNip%a{`q^JWPJR2#gatlhQ z&#GP|3*((Wst$TMJF_l!*C8@`1+@z= zj2~bVM3!3oO1({0>LfUaO9=ZU1`uyWHzQ$LzUlkA{rD;Jj8 zZPR-!Xi;-A$h#1&gVEjNkaz)rB@#xp;hIw}c9&M?M`7AV$bL^9>0f>lKM8OJiTx?w z3@?3p1@a%6V6mG%0=vQrEoIow+ANZJHwdqDY2B8q*ep;)eN-!2wa9ZN7Og0y5*z-I zu#3-soPlT`;B*?I=l=Mk>4=WlmvcS9Z)zXXYVhiM3!*w)BMNdmENrvgxh)@dGypmP zmq5Y5$v?T3_Lf?!LWJzxi%FTr+6 z`=LB7m2x=5#I>g&xU=>hNqP>7D|n%uUcUvK%OSPX#oow8sX10e^8iV!5G@2atjy}# ZmhBT@lNE_6C=njv1Sfv|ka zKuk^_5R}+kP?TH-`7pnNA|#MRq97VbL=V9o3YuT*Khn1j{67Bw^XGRje~#9d?!DJc zKI&##>M{AIV>j{Lk~dyNX_AXLXSfco{nZ9a&=i8>L&*Kc%SuR_d1Du8c{}kCLcF_? z4G~6Gyo_))f$^|K*-kD8I1O_Vzg4y>Q--~@v4~wM)i`XI1!XaSHxt#Zev3TXVNxD) zduyW|R9OlTEfH(;o8$z;ydB?SPF~8p4r!%YV%Q?zU{SsRUt?E!N$d>|c3G9dP7%Ig zm9twHvjdS!n>$f=(4lxVo;c)wmgHM;7u(_`b3^u-vI_s>5A^t(*;!pVu49*V(PDR4 zlGhb?m#F1)Rl#*xRB|q$@ti0-*;`#5+t)Raw3pTEzv4dCVmMA5D-xoeu!R={x$gt8 z$i-26JhUybCSzN91{RkqIT)i!r2X3E!d!%$$)6X3MM0V}LqEo*jW%5joSCJJwRn(a zjG}%4>PM35Fg?Zk+Xh5u4eDIp0Z*o>Iw!Q?oE})Z`SOY)L<<1>ClSSm`lA5RR@=W` z7Q9s*E)3ygDT=7}8>KT4_mZ-AHc!(7n3@NC2N+;7hmFJDQT;!ivZ Date: Mon, 26 Dec 2022 12:09:27 +0100 Subject: [PATCH 164/433] Precompiled firmware --- .../composite-stm32/bin/blackpill-f411ce.bin | Bin 11624 -> 11624 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test-devices/composite-stm32/bin/blackpill-f411ce.bin b/test-devices/composite-stm32/bin/blackpill-f411ce.bin index 30c116f80a570aea73f41f8b023394a8f4a184d2..58ed2e6fab02117d79b3cf873a5637b00dfaad35 100755 GIT binary patch delta 14 VcmaD6^&)D6y&7ZYW(PG5b^tOO1xx?{ delta 14 VcmaD6^&)D6y&7Z2W(PG5b^tOI1xo+` From 6d00f4c25af9657843063b60ee371e9b0dda9cd9 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 26 Dec 2022 12:09:50 +0100 Subject: [PATCH 165/433] Fix crash if monitor wasn't started --- reference/macos/USB/usb_registry.cpp | 6 +++--- reference/macos/USB/usb_registry.hpp | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/reference/macos/USB/usb_registry.cpp b/reference/macos/USB/usb_registry.cpp index bee6b975..fda37b13 100644 --- a/reference/macos/USB/usb_registry.cpp +++ b/reference/macos/USB/usb_registry.cpp @@ -35,10 +35,10 @@ usb_registry::~usb_registry() { device_disconnected_iter = 0; } - CFRunLoopStop(run_loop); - monitor_thread.join(); - if (notify_port != nullptr) { + CFRunLoopStop(run_loop); + monitor_thread.join(); + IONotificationPortDestroy(notify_port); notify_port = nullptr; } diff --git a/reference/macos/USB/usb_registry.hpp b/reference/macos/USB/usb_registry.hpp index 9fd820fc..0f66c724 100644 --- a/reference/macos/USB/usb_registry.hpp +++ b/reference/macos/USB/usb_registry.hpp @@ -37,6 +37,9 @@ class usb_registry { /// Starts the registry void start(); + /// Indicates if the registry has been started + bool isStarted() { return notify_port != nullptr; } + /// Gets the currently connected devices. std::vector> get_devices(); From 51345833574b99c206e52bf52bafd8c49c801958 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 26 Dec 2022 18:00:27 +0100 Subject: [PATCH 166/433] Upgrade macOS code to JDK 20 --- java-does-usb/jextract/macos/gen_macos.sh | 18 +- java-does-usb/pom.xml | 14 +- .../src/main/java/net/codecrete/usb/USB.java | 10 +- .../codecrete/usb/common/ForeignMemory.java | 31 +- .../codecrete/usb/common/ScopeCleanup.java | 50 + .../usb/macos/CoreFoundationHelper.java | 19 +- .../net/codecrete/usb/macos/IoKitHelper.java | 99 +- .../net/codecrete/usb/macos/IoKitUSB.java | 148 +- .../codecrete/usb/macos/MacosUSBDevice.java | 142 +- .../usb/macos/MacosUSBDeviceRegistry.java | 37 +- .../codecrete/usb/macos/TransferTimeout.java | 2 +- .../java/net/codecrete/usb/macos/UUID.java | 12 +- .../usb/macos/gen/corefoundation/CFRange.java | 42 +- .../macos/gen/corefoundation/CFUUIDBytes.java | 252 +- .../gen/corefoundation/Constants$root.java | 22 +- .../gen/corefoundation/CoreFoundation.java | 121 +- .../gen/corefoundation/RuntimeHelper.java | 65 +- .../macos/gen/corefoundation/constants$0.java | 4 +- .../macos/gen/corefoundation/constants$1.java | 4 +- .../macos/gen/corefoundation/constants$2.java | 4 +- .../usb/macos/gen/iokit/Constants$root.java | 22 +- .../macos/gen/iokit/IOCFPlugInInterface.java | 9 +- .../gen/iokit/IOCFPlugInInterfaceStruct.java | 369 ++- .../codecrete/usb/macos/gen/iokit/IOKit.java | 159 +- .../usb/macos/gen/iokit/IOUSBDevRequest.java | 129 +- .../gen/iokit/IOUSBDeviceInterface100.java | 9 +- .../macos/gen/iokit/IOUSBDeviceStruct100.java | 1439 ++++++---- .../gen/iokit/IOUSBFindInterfaceRequest.java | 72 +- .../gen/iokit/IOUSBInterfaceInterface190.java | 9 +- .../gen/iokit/IOUSBInterfaceStruct190.java | 2439 +++++++++++------ .../usb/macos/gen/iokit/RuntimeHelper.java | 65 +- .../usb/macos/gen/iokit/constants$0.java | 8 +- .../usb/macos/gen/iokit/constants$1.java | 4 +- .../usb/macos/gen/iokit/constants$2.java | 4 +- .../usb/macos/gen/mach/Constants$root.java | 22 +- .../usb/macos/gen/mach/RuntimeHelper.java | 63 +- .../usb/macos/gen/mach/constants$0.java | 4 +- .../codecrete/usb/macos/gen/mach/mach.java | 28 +- .../usb/usbstandard/SetupPacket.java | 8 +- 39 files changed, 4060 insertions(+), 1898 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index 949b727f..dfc6b75f 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -1,6 +1,6 @@ #!/bin/sh -JEXTRACT=../../../../jextract-19/bin/jextract +JEXTRACT=../../../../jextract/build/jextract/bin/jextract # If SDK_DIR is changed, it needs to be changed in compile_flags.txt as well. SDK_DIR=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk @@ -25,7 +25,7 @@ $JEXTRACT --source --output ../../src/main/java \ --include-function CFRunLoopAddSource \ --include-function CFRunLoopRun \ --include-function CFUUIDGetUUIDBytes \ - --include-macro kCFNumberSInt32Type \ + --include-constant kCFNumberSInt32Type \ cf_helper.h # IOKit @@ -35,9 +35,9 @@ $JEXTRACT --source --output ../../src/main/java \ --header-class-name IOKit \ --target-package net.codecrete.usb.macos.gen.iokit \ --include-var kIOMasterPortDefault \ - --include-macro kIOUSBDeviceClassName \ - --include-macro kIOFirstMatchNotification \ - --include-macro kIOTerminatedNotification \ + --include-constant kIOUSBDeviceClassName \ + --include-constant kIOFirstMatchNotification \ + --include-constant kIOTerminatedNotification \ --include-var kCFRunLoopDefaultMode \ --include-struct IOCFPlugInInterfaceStruct \ --include-typedef IOCFPlugInInterface \ @@ -52,14 +52,14 @@ $JEXTRACT --source --output ../../src/main/java \ --include-function IOServiceMatching \ --include-struct IOUSBDeviceStruct100 \ --include-typedef IOUSBDeviceInterface100 \ - --include-macro kIOUSBFindInterfaceDontCare \ + --include-constant kIOUSBFindInterfaceDontCare \ --include-typedef IOUSBFindInterfaceRequest \ --include-typedef IOUSBDevRequest \ --include-struct IOUSBInterfaceStruct190 \ --include-typedef IOUSBInterfaceInterface190 \ - --include-macro kIOUSBTransactionTimeout \ - --include-macro kIOReturnAborted \ - --include-macro kIOUSBPipeStalled \ + --include-constant kIOUSBTransactionTimeout \ + --include-constant kIOReturnAborted \ + --include-constant kIOUSBPipeStalled \ iokit_helper.h # mach.h diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index d706ef0d..7229e43f 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,11 +6,11 @@ net.codecrete.usb java-does-usb - 0.4.0 + 0.5.0 - 19 - 19 + 20 + 20 UTF-8 @@ -56,10 +56,10 @@ maven-compiler-plugin 3.10.1 - 19 + 20 --enable-preview - 19 - 19 + 20 + 20 @@ -83,7 +83,7 @@ - 19 + 20 --enable-preview ${java.home}/bin/javadoc diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USB.java b/java-does-usb/src/main/java/net/codecrete/usb/USB.java index ab37236e..39cd7d8a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USB.java @@ -8,9 +8,7 @@ package net.codecrete.usb; import net.codecrete.usb.common.USBDeviceRegistry; -import net.codecrete.usb.linux.LinuxUSBDeviceRegistry; import net.codecrete.usb.macos.MacosUSBDeviceRegistry; -import net.codecrete.usb.windows.WindowsUSBDeviceRegistry; import java.util.List; import java.util.function.Consumer; @@ -28,10 +26,10 @@ private static USBDeviceRegistry createInstance() { USBDeviceRegistry impl; if (osName.equals("Mac OS X") && (osArch.equals("x86_64") || osArch.equals("aarch64"))) { impl = new MacosUSBDeviceRegistry(); - } else if (osName.startsWith("Windows") && osArch.equals("amd64")) { - impl = new WindowsUSBDeviceRegistry(); - } else if (osName.equals("Linux") && (osArch.equals("amd64") || osArch.equals("aarch64"))) { - impl = new LinuxUSBDeviceRegistry(); +// } else if (osName.startsWith("Windows") && osArch.equals("amd64")) { +// impl = new WindowsUSBDeviceRegistry(); +// } else if (osName.equals("Linux") && (osArch.equals("amd64") || osArch.equals("aarch64"))) { +// impl = new LinuxUSBDeviceRegistry(); } else { throw new UnsupportedOperationException(String.format("JavaCanDoUsb is not implemented for architecture " + "%s/%s", osName, osArch)); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java index 8f3b53ed..fc248790 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java @@ -7,36 +7,15 @@ package net.codecrete.usb.common; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; -import java.util.function.Consumer; +import java.lang.foreign.ValueLayout; -/** - * Helper functions for the foreign memory API. - */ public class ForeignMemory { - /** - * Adds a custom cleanup action which will be execution when the session of the - * specified memory segment ends. + * A value layout constant whose size is the same as that of a machine address. *

- * Note that the {@code segment}'s session will already be closed. The {@code segment} - * can no longer be used for function call. For that reason, the cleanup - * action is passed a copy of the segment (separate Java instance pointing to the - * same native memory). + * {@code MemorySegment} instances created by dereferencing an address of this type + * will have length {@code Long.MAX_VALUE}/ *

- * @param segment the segment to be accessed during the cleanup - * @param action the cleanup action */ - public static void addCloseAction(MemorySegment segment, Consumer action) { - var size = segment.byteSize(); - var address = segment.address(); - Runnable closeAction = () -> { - try (MemorySession closingSession = MemorySession.openConfined()) { - var dup = MemorySegment.ofAddress(address, size, closingSession); - action.accept(dup); - } - }; - segment.session().addCloseAction(closeAction); - } + public static ValueLayout.OfAddress UNBOUNDED_ADDRESS = ValueLayout.ADDRESS.asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java new file mode 100644 index 00000000..b9760bf7 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java @@ -0,0 +1,50 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +import java.util.ArrayList; + +/** + * Auto closeable actions for clean up. + * + *

+ * Multiple cleanup actions can be registered and will + * be executed when this object is closed. They are run + * in the reverse order they are registered. + *

+ *

+ * Use with {@code try (...)} clause: + *

+ *
+ * try (var cleanup = new ScopeCleanup()) {
+ *     var service = ...;
+ *     cleanup.add(() -> releaseService(service));
+ *
+ *     ...more code...
+ * }
+ * 
+ */ +public class ScopeCleanup implements AutoCloseable { + + private final ArrayList cleanupActions= new ArrayList<>(); + + /** + * Registers a cleanup action to be run later. + * @param cleanupAction cleanup action + */ + public void add(Runnable cleanupAction) { + cleanupActions.add(cleanupAction); + } + + @Override + public void close() { + var size = cleanupActions.size(); + for (int i = size - 1; i >= 0; i--) + cleanupActions.get(i).run(); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java index 6c663f8a..c952c612 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java @@ -10,11 +10,10 @@ import net.codecrete.usb.macos.gen.corefoundation.CFRange; import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; -import java.lang.foreign.MemoryAddress; +import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; -import static java.lang.foreign.MemoryAddress.NULL; +import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.JAVA_CHAR; /** @@ -28,13 +27,13 @@ public class CoreFoundationHelper { * @param string the string to copy ({@code CFStringRef}) * @return copied string */ - public static String stringFromCFStringRef(MemoryAddress string) { + public static String stringFromCFStringRef(MemorySegment string) { - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined()) { long strLen = CoreFoundation.CFStringGetLength(string); - var buffer = session.allocateArray(JAVA_CHAR, strLen); - var range = session.allocate(CFRange.$LAYOUT()); + var buffer = arena.allocateArray(JAVA_CHAR, strLen); + var range = arena.allocate(CFRange.$LAYOUT()); CFRange.location$set(range, 0); CFRange.length$set(range, strLen); CoreFoundation.CFStringGetCharacters(string, range, buffer); @@ -55,10 +54,10 @@ public static String stringFromCFStringRef(MemoryAddress string) { * @param string the string * @return {@code CFStringRef} */ - public static MemoryAddress createCFStringRef(String string) { - try (var session = MemorySession.openConfined()) { + public static MemorySegment createCFStringRef(String string) { + try (var arena = Arena.openConfined()) { char[] charArray = string.toCharArray(); - var chars = session.allocateArray(JAVA_CHAR, charArray.length); + var chars = arena.allocateArray(JAVA_CHAR, charArray.length); chars.copyFrom(MemorySegment.ofArray(charArray)); return CoreFoundation.CFStringCreateWithCharacters(NULL, chars, string.length()); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index 4e03bda3..c74d5d00 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -7,15 +7,14 @@ package net.codecrete.usb.macos; +import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; import net.codecrete.usb.macos.gen.iokit.IOKit; -import java.lang.foreign.Addressable; -import java.lang.foreign.MemoryAddress; +import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; -import static java.lang.foreign.MemoryAddress.NULL; +import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.ADDRESS; import static java.lang.foreign.ValueLayout.JAVA_INT; @@ -23,23 +22,23 @@ * Constants and helper functions for the IOKit framework. */ public class IoKitHelper { - public static final MemoryAddress kIOUSBDeviceUserClientTypeID = UUID.CreateCFUUID( + public static final MemorySegment kIOUSBDeviceUserClientTypeID = UUID.CreateCFUUID( new byte[]{(byte) 0x9d, (byte) 0xc7, (byte) 0xb7, (byte) 0x80, (byte) 0x9e, (byte) 0xc0, (byte) 0x11, (byte) 0xD4, (byte) 0xa5, (byte) 0x4f, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61}); - public static final MemoryAddress kIOUSBInterfaceUserClientTypeID = UUID.CreateCFUUID( + public static final MemorySegment kIOUSBInterfaceUserClientTypeID = UUID.CreateCFUUID( new byte[]{(byte) 0x2d, (byte) 0x97, (byte) 0x86, (byte) 0xc6, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, (byte) 0xad, (byte) 0x51, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61}); - public static final MemoryAddress kIOUSBDeviceInterfaceID100 = UUID.CreateCFUUID( + public static final MemorySegment kIOUSBDeviceInterfaceID100 = UUID.CreateCFUUID( new byte[]{(byte) 0x5c, (byte) 0x81, (byte) 0x87, (byte) 0xd0, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, (byte) 0x8b, (byte) 0x45, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61}); - public static final MemoryAddress kIOUSBInterfaceInterfaceID100 = UUID.CreateCFUUID( + public static final MemorySegment kIOUSBInterfaceInterfaceID100 = UUID.CreateCFUUID( new byte[]{(byte) 0x73, (byte) 0xc9, (byte) 0x7a, (byte) 0xe8, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, (byte) 0xb1, (byte) 0xd0, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61}); - public static final MemoryAddress kIOCFPlugInInterfaceID = UUID.CreateCFUUID( + public static final MemorySegment kIOCFPlugInInterfaceID = UUID.CreateCFUUID( new byte[]{(byte) 0xC2, (byte) 0x44, (byte) 0xE8, (byte) 0x58, (byte) 0x10, (byte) 0x9C, (byte) 0x11, (byte) 0xD4, (byte) 0x91, (byte) 0xD4, (byte) 0x00, (byte) 0x50, (byte) 0xE4, (byte) 0xC6, (byte) 0x42, (byte) 0x6F}); @@ -56,23 +55,23 @@ public class IoKitHelper { * @param interfaceId the interface ID * @return the interface, or null if the plugin type or interface is not available */ - public static MemoryAddress getInterface(int service, Addressable pluginType, MemoryAddress interfaceId) { - try (var session = MemorySession.openConfined()) { + public static MemorySegment getInterface(int service, MemorySegment pluginType, MemorySegment interfaceId) { + try (var arena = Arena.openConfined()) { // MemorySegment for holding IOCFPlugInInterface** - var plugHolder = session.allocate(ADDRESS, NULL); + var plugHolder = arena.allocate(ADDRESS, NULL); // MemorySegment for holding score - var score = session.allocate(JAVA_INT, 0); + var score = arena.allocate(JAVA_INT, 0); int ret = IOKit.IOCreatePlugInInterfaceForService(service, pluginType, kIOCFPlugInInterfaceID, plugHolder, score); if (ret != 0) return null; - var plug = (MemoryAddress) plugHolder.get(ADDRESS, 0); + var plug = plugHolder.get(ADDRESS, 0); - // MemorySegment for holding xxxInterface** - var intfHolder = session.allocate(ADDRESS, NULL); // UUID bytes - var refiid = CoreFoundation.CFUUIDGetUUIDBytes(session, interfaceId); - ret = IoKitUSB.QueryInterface(plug, refiid, intfHolder.address()); + var refiid = CoreFoundation.CFUUIDGetUUIDBytes(arena, interfaceId); + // MemorySegment for holding xxxInterface** + var intfHolder = arena.allocate(ADDRESS, NULL); + ret = IoKitUSB.QueryInterface(plug, refiid, intfHolder); IoKitUSB.Release(plug); if (ret != 0) return null; @@ -92,24 +91,24 @@ public static MemoryAddress getInterface(int service, Addressable pluginType, Me */ public static Integer getPropertyInt(int service, String key) { - var cfKey = CoreFoundationHelper.createCFStringRef(key); - var value = IOKit.IORegistryEntryCreateCFProperty(service, cfKey, NULL, 0); - if (value == NULL) - return null; + try (var cleanup = new ScopeCleanup()) { + var value = getPropertyValue(service, key, cleanup); + if (value == null) + return null; - Integer result = null; - var type = CoreFoundation.CFGetTypeID(value); - if (type == CoreFoundation.CFNumberGetTypeID()) { + Integer result = null; + var type = CoreFoundation.CFGetTypeID(value); + if (type == CoreFoundation.CFNumberGetTypeID()) { - try (var session = MemorySession.openConfined()) { - var numberValue = session.allocate(JAVA_INT, 0); - if (CoreFoundation.CFNumberGetValue(value, CoreFoundation.kCFNumberSInt32Type(), numberValue) != 0) - result = numberValue.get(JAVA_INT, 0); + try (var arena = Arena.openConfined()) { + var numberValue = arena.allocate(JAVA_INT, 0); + if (CoreFoundation.CFNumberGetValue(value, CoreFoundation.kCFNumberSInt32Type(), numberValue) != 0) + result = numberValue.get(JAVA_INT, 0); + } } - } - CoreFoundation.CFRelease(value); - return result; + return result; + } } /** @@ -124,26 +123,38 @@ public static Integer getPropertyInt(int service, String key) { */ public static String getPropertyString(int service, String key) { + try (var cleanup = new ScopeCleanup()) { + var value = getPropertyValue(service, key, cleanup); + if (value == null) + return null; + + String result = null; + var type = CoreFoundation.CFGetTypeID(value); + if (type == CoreFoundation.CFStringGetTypeID()) + result = CoreFoundationHelper.stringFromCFStringRef(value); + + return result; + } + } + + private static MemorySegment getPropertyValue(int service, String key, ScopeCleanup cleanup) { var cfKey = CoreFoundationHelper.createCFStringRef(key); + cleanup.add(() -> CoreFoundation.CFRelease(cfKey)); + var value = IOKit.IORegistryEntryCreateCFProperty(service, cfKey, NULL, 0); - if (value == NULL) + if (value.address() == 0) return null; + cleanup.add(() -> CoreFoundation.CFRelease(value)); - String result = null; - var type = CoreFoundation.CFGetTypeID(value); - if (type == CoreFoundation.CFStringGetTypeID()) - result = CoreFoundationHelper.stringFromCFStringRef(value); - - CoreFoundation.CFRelease(value); - return result; + return value; } // debugging aid - public static int getRefCount(MemoryAddress self) { - try (var session = MemorySession.openConfined()) { - var object = MemorySegment.ofAddress(self, 16, session); + public static int getRefCount(MemorySegment self) { + try (var arena = Arena.openConfined()) { + var object = MemorySegment.ofAddress(self.address(), 16, arena.scope()); var dataAddr = object.get(ADDRESS, ADDRESS.byteSize()); - var data = MemorySegment.ofAddress(dataAddr, 12, session); + var data = MemorySegment.ofAddress(dataAddr.address(), 12, arena.scope()); return data.get(JAVA_INT, 8); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index 61b9f941..96bb9f33 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -10,175 +10,131 @@ import net.codecrete.usb.macos.gen.iokit.IOUSBDeviceInterface100; import net.codecrete.usb.macos.gen.iokit.IOUSBInterfaceInterface190; -import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; +import java.lang.foreign.SegmentScope; import static java.lang.foreign.ValueLayout.ADDRESS; +import static net.codecrete.usb.common.ForeignMemory.UNBOUNDED_ADDRESS; /** * Helper functions to call the virtual methods of IOKit USB interfaces. */ public class IoKitUSB { - private static MemorySegment getVtable(MemoryAddress self, MemorySession session) { - var object = MemorySegment.ofAddress(self, ADDRESS.byteSize(), session); - var vtableAddr = object.get(ADDRESS, 0); + private static MemorySegment getVtable(MemorySegment self) { + var object = MemorySegment.ofAddress(self.address(), ADDRESS.byteSize(), SegmentScope.global()); // 800: size of biggest vtable and then some - return MemorySegment.ofAddress(vtableAddr, 800, session); + return object.get(UNBOUNDED_ADDRESS, 0).asSlice(0, 800); } // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); - public static int QueryInterface(MemoryAddress self, MemorySegment iid, MemoryAddress ppv) { - try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface100.QueryInterface(getVtable(self, session), session).apply(self, iid, ppv); - } + public static int QueryInterface(MemorySegment self, MemorySegment iid, MemorySegment ppv) { + return IOUSBDeviceInterface100.QueryInterface(getVtable(self), SegmentScope.global()).apply(self, iid, ppv); } // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); - public static int AddRef(MemoryAddress self) { - try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface100.AddRef(getVtable(self, session), session).apply(self); - } + public static int AddRef(MemorySegment self) { + return IOUSBDeviceInterface100.AddRef(getVtable(self), SegmentScope.global()).apply(self); } // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer) - public static int Release(MemoryAddress self) { - try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface100.Release(getVtable(self, session), session).apply(self); - } + public static int Release(MemorySegment self) { + return IOUSBDeviceInterface100.Release(getVtable(self), SegmentScope.global()).apply(self); } // IOReturn (*USBDeviceOpen)(void *self); - public static int USBDeviceOpen(MemoryAddress self) { - try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface100.USBDeviceOpen(getVtable(self, session), session).apply(self); - } + public static int USBDeviceOpen(MemorySegment self) { + return IOUSBDeviceInterface100.USBDeviceOpen(getVtable(self), SegmentScope.global()).apply(self); } // IOReturn (*USBDeviceClose)(void *self); - public static int USBDeviceClose(MemoryAddress self) { - try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface100.USBDeviceClose(getVtable(self, session), session).apply(self); - } + public static int USBDeviceClose(MemorySegment self) { + return IOUSBDeviceInterface100.USBDeviceClose(getVtable(self), SegmentScope.global()).apply(self); } // IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc); - public static int GetConfigurationDescriptorPtr(MemoryAddress self, byte configIndex, - MemoryAddress descHolder) { - try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface100.GetConfigurationDescriptorPtr(getVtable(self, session), session).apply(self, configIndex, descHolder); - } + public static int GetConfigurationDescriptorPtr(MemorySegment self, byte configIndex, MemorySegment descHolder) { + return IOUSBDeviceInterface100.GetConfigurationDescriptorPtr(getVtable(self), SegmentScope.global()).apply(self, configIndex, descHolder); } // IOReturn (*SetConfiguration)(void *self, UInt8 configNum); - public static int SetConfiguration(MemoryAddress self, byte configValue) { - try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface100.SetConfiguration(getVtable(self, session), session).apply(self, configValue); - } + public static int SetConfiguration(MemorySegment self, byte configValue) { + return IOUSBDeviceInterface100.SetConfiguration(getVtable(self), SegmentScope.global()).apply(self, configValue); } // IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter); - public static int CreateInterfaceIterator(MemoryAddress self, MemoryAddress req, MemoryAddress iter) { - try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface100.CreateInterfaceIterator(getVtable(self, session), session).apply(self, req, iter); - } + public static int CreateInterfaceIterator(MemorySegment self, MemorySegment req, MemorySegment iter) { + return IOUSBDeviceInterface100.CreateInterfaceIterator(getVtable(self), SegmentScope.global()).apply(self, req, iter); } // IOReturn (*DeviceRequest)(void *self, IOUSBDevRequest *req); - public static int DeviceRequest(MemoryAddress self, MemoryAddress deviceRequest) { - try (var session = MemorySession.openConfined()) { - return IOUSBDeviceInterface100.DeviceRequest(getVtable(self, session), session).apply(self, deviceRequest); - } + public static int DeviceRequest(MemorySegment self, MemorySegment deviceRequest) { + return IOUSBDeviceInterface100.DeviceRequest(getVtable(self), SegmentScope.global()).apply(self, deviceRequest); } // IOReturn (*USBInterfaceOpen)(void *self);; - public static int USBInterfaceOpen(MemoryAddress self) { - try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface190.USBInterfaceOpen(getVtable(self, session), session).apply(self); - } + public static int USBInterfaceOpen(MemorySegment self) { + return IOUSBInterfaceInterface190.USBInterfaceOpen(getVtable(self), SegmentScope.global()).apply(self); } // IOReturn (*USBInterfaceClose)(void *self);; - public static int USBInterfaceClose(MemoryAddress self) { - try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface190.USBInterfaceClose(getVtable(self, session), session).apply(self); - } + public static int USBInterfaceClose(MemorySegment self) { + return IOUSBInterfaceInterface190.USBInterfaceClose(getVtable(self), SegmentScope.global()).apply(self); } // IOReturn (*GetInterfaceNumber)(void *self, UInt8 *intfNumber); - public static int GetInterfaceNumber(MemoryAddress self, MemoryAddress intfNumberHolder) { - try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface190.GetInterfaceNumber(getVtable(self, session), session).apply(self, intfNumberHolder); - } + public static int GetInterfaceNumber(MemorySegment self, MemorySegment intfNumberHolder) { + return IOUSBInterfaceInterface190.GetInterfaceNumber(getVtable(self), SegmentScope.global()).apply(self, intfNumberHolder); } // IOReturn (*GetNumEndpoints)(void *self, UInt8 *intfNumEndpoints); - public static int GetNumEndpoints(MemoryAddress self, MemoryAddress intfNumEndpointsHolder) { - try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface190.GetNumEndpoints(getVtable(self, session), session).apply(self, intfNumEndpointsHolder); - } + public static int GetNumEndpoints(MemorySegment self, MemorySegment intfNumEndpointsHolder) { + return IOUSBInterfaceInterface190.GetNumEndpoints(getVtable(self), SegmentScope.global()).apply(self, intfNumEndpointsHolder); } // IOReturn (*GetPipeProperties)(void *self, UInt8 pipeRef, UInt8 *direction, UInt8 *number, UInt8 *transferType, // UInt16 *maxPacketSize, UInt8 *interval); - public static int GetPipeProperties(MemoryAddress self, byte pipeRef, MemoryAddress directionHolder, - MemoryAddress numberHolder, MemoryAddress transferTypeHolder, - MemoryAddress maxPacketSizeHolder, MemoryAddress intervalHolder) { - try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface190.GetPipeProperties(getVtable(self, session), session).apply(self, pipeRef, - directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); - } + public static int GetPipeProperties(MemorySegment self, byte pipeRef, MemorySegment directionHolder, + MemorySegment numberHolder, MemorySegment transferTypeHolder, + MemorySegment maxPacketSizeHolder, MemorySegment intervalHolder) { + return IOUSBInterfaceInterface190.GetPipeProperties(getVtable(self), SegmentScope.global()).apply(self, pipeRef, + directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); } // IOReturn (*ReadPipe)(void *self, UInt8 pipeRef, void *buf, UInt32 *size); - public static int ReadPipe(MemoryAddress self, byte pipeRef, MemoryAddress buf, MemoryAddress sizeHolder) { - try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface190.ReadPipe(getVtable(self, session), session) - .apply(self, pipeRef, buf, sizeHolder); - } + public static int ReadPipe(MemorySegment self, byte pipeRef, MemorySegment buf, MemorySegment sizeHolder) { + return IOUSBInterfaceInterface190.ReadPipe(getVtable(self), SegmentScope.global()) + .apply(self, pipeRef, buf, sizeHolder); } // IOReturn (* ReadPipeTO)(void* self, UInt8 pipeRef, void* buf, UInt32* size, UInt32 noDataTimeout, UInt32 completionTimeout); - public static int ReadPipeTO(MemoryAddress self, byte pipeRef, MemoryAddress buf, MemoryAddress sizeHolder, int noDataTimeout, int completionTimeout) { - try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface190.ReadPipeTO(getVtable(self, session), session) - .apply(self, pipeRef, buf, sizeHolder, noDataTimeout, completionTimeout); - } + public static int ReadPipeTO(MemorySegment self, byte pipeRef, MemorySegment buf, MemorySegment sizeHolder, int noDataTimeout, int completionTimeout) { + return IOUSBInterfaceInterface190.ReadPipeTO(getVtable(self), SegmentScope.global()) + .apply(self, pipeRef, buf, sizeHolder, noDataTimeout, completionTimeout); } // IOReturn (*WritePipe)(void *self, UInt8 pipeRef, void *buf, UInt32 size); - public static int WritePipe(MemoryAddress self, byte pipeRef, MemoryAddress buf, int size) { - try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface190.WritePipe(getVtable(self, session), session).apply(self, pipeRef, buf, size); - } + public static int WritePipe(MemorySegment self, byte pipeRef, MemorySegment buf, int size) { + return IOUSBInterfaceInterface190.WritePipe(getVtable(self), SegmentScope.global()).apply(self, pipeRef, buf, size); } // IOReturn (* WritePipeTO)(void* self, UInt8 pipeRef, void* buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout); - public static int WritePipeTO(MemoryAddress self, byte pipeRef, MemoryAddress buf, int size, int noDataTimeout, int completionTimeout) { - try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface190.WritePipeTO(getVtable(self, session), session).apply(self, pipeRef, buf, size, noDataTimeout, completionTimeout); - } + public static int WritePipeTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, int noDataTimeout, int completionTimeout) { + return IOUSBInterfaceInterface190.WritePipeTO(getVtable(self), SegmentScope.global()).apply(self, pipeRef, buf, size, noDataTimeout, completionTimeout); } // IOReturn (* AbortPipe)(void* self, UInt8 pipeRef); - public static int AbortPipe(MemoryAddress self, byte pipeRef) { - try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface190.AbortPipe(getVtable(self, session), session).apply(self, pipeRef); - } + public static int AbortPipe(MemorySegment self, byte pipeRef) { + return IOUSBInterfaceInterface190.AbortPipe(getVtable(self), SegmentScope.global()).apply(self, pipeRef); } // IOReturn (*SetAlternateInterface)(void *self, UInt8 alternateSetting); - public static int SetAlternateInterface(MemoryAddress self, byte alternateSetting) { - try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface190.SetAlternateInterface(getVtable(self, session), session).apply(self, alternateSetting); - } + public static int SetAlternateInterface(MemorySegment self, byte alternateSetting) { + return IOUSBInterfaceInterface190.SetAlternateInterface(getVtable(self), SegmentScope.global()).apply(self, alternateSetting); } // IOReturn (* ClearPipeStallBothEnds)(void* self, UInt8 pipeRef); - public static int ClearPipeStallBothEnds(MemoryAddress self, byte pipeRef) { - try (var session = MemorySession.openConfined()) { - return IOUSBInterfaceInterface190.ClearPipeStallBothEnds(getVtable(self, session), session).apply(self, pipeRef); - } + public static int ClearPipeStallBothEnds(MemorySegment self, byte pipeRef) { + return IOUSBInterfaceInterface190.ClearPipeStallBothEnds(getVtable(self), SegmentScope.global()).apply(self, pipeRef); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index a3ae9491..e163c4f7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -11,32 +11,32 @@ import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBTimeoutException; import net.codecrete.usb.USBTransferType; +import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.macos.gen.iokit.IOKit; import net.codecrete.usb.macos.gen.iokit.IOUSBDevRequest; import net.codecrete.usb.macos.gen.iokit.IOUSBFindInterfaceRequest; import net.codecrete.usb.usbstandard.ConfigurationDescriptor; -import java.lang.foreign.MemoryAddress; +import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import static java.lang.foreign.MemoryAddress.ofLong; import static java.lang.foreign.ValueLayout.*; +import static net.codecrete.usb.common.ForeignMemory.UNBOUNDED_ADDRESS; import static net.codecrete.usb.macos.MacosUSBException.throwException; public class MacosUSBDevice extends USBDeviceImpl { - private final MemoryAddress device; + private final MemorySegment device; private int configurationValue; private List claimedInterfaces; private Map endpoints; - MacosUSBDevice(MemoryAddress device, Object id, int vendorId, int productId) { + MacosUSBDevice(MemorySegment device, Object id, int vendorId, int productId) { super(id, vendorId, productId); this.device = device; @@ -75,8 +75,8 @@ public void close() { return; for (InterfaceInfo interfaceInfo : claimedInterfaces) { - IoKitUSB.USBInterfaceClose(interfaceInfo.asAddress()); - IoKitUSB.Release(interfaceInfo.asAddress()); + IoKitUSB.USBInterfaceClose(interfaceInfo.segment()); + IoKitUSB.Release(interfaceInfo.segment()); setClaimed(interfaceInfo.interfaceNumber, false); } @@ -91,22 +91,21 @@ void closeFully() { } private void loadDescription() { - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined()) { configurationValue = 0; // retrieve information of first configuration - var descPtrHolder = session.allocate(ADDRESS); - int ret = IoKitUSB.GetConfigurationDescriptorPtr(device, (byte) 0, descPtrHolder.address()); + var descPtrHolder = arena.allocate(ADDRESS); + int ret = IoKitUSB.GetConfigurationDescriptorPtr(device, (byte) 0, descPtrHolder); if (ret != 0) throwException(ret, "failed to query first configuration"); // get value of first configuration - var configDescHeader = new ConfigurationDescriptor(MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), - ConfigurationDescriptor.LAYOUT.byteSize(), session)); + var configDesc = descPtrHolder.get(UNBOUNDED_ADDRESS, 0); + var configDescHeader = new ConfigurationDescriptor(configDesc); int totalLength = configDescHeader.totalLength(); - var configDesc = MemorySegment.ofAddress(descPtrHolder.get(ADDRESS, 0), - totalLength, session); + configDesc = configDesc.asSlice(0, totalLength); var configuration = setConfigurationDescriptor(configDesc); configurationValue = 255 & configuration.configValue(); @@ -115,39 +114,39 @@ private void loadDescription() { private InterfaceInfo findInterface(int interfaceNumber) { - try (var outerSession = MemorySession.openConfined()) { - var request = outerSession.allocate(IOUSBFindInterfaceRequest.$LAYOUT()); + try (var outerArena = Arena.openConfined(); var outerCleanup = new ScopeCleanup()) { + var request = outerArena.allocate(IOUSBFindInterfaceRequest.$LAYOUT()); IOUSBFindInterfaceRequest.bInterfaceClass$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); IOUSBFindInterfaceRequest.bInterfaceSubClass$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); IOUSBFindInterfaceRequest.bInterfaceProtocol$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); IOUSBFindInterfaceRequest.bAlternateSetting$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); - var iterHolder = outerSession.allocate(JAVA_INT); - int ret = IoKitUSB.CreateInterfaceIterator(device, request.address(), iterHolder.address()); + var iterHolder = outerArena.allocate(JAVA_INT); + int ret = IoKitUSB.CreateInterfaceIterator(device, request, iterHolder); final var iter = iterHolder.get(JAVA_INT, 0); if (ret != 0) throwException("CreateInterfaceIterator failed"); - outerSession.addCloseAction(() -> IOKit.IOObjectRelease(iter)); + outerCleanup.add(() -> IOKit.IOObjectRelease(iter)); int service; while ((service = IOKit.IOIteratorNext(iter)) != 0) { - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined(); var cleanup = new ScopeCleanup()) { final int service_final = service; - session.addCloseAction(() -> IOKit.IOObjectRelease(service_final)); + cleanup.add(() -> IOKit.IOObjectRelease(service_final)); - final MemoryAddress intf = IoKitHelper.getInterface(service, + final var intf = IoKitHelper.getInterface(service, IoKitHelper.kIOUSBInterfaceUserClientTypeID, IoKitHelper.kIOUSBInterfaceInterfaceID100); if (intf == null) continue; - var intfNumberHolder = session.allocate(JAVA_INT); - IoKitUSB.GetInterfaceNumber(intf, intfNumberHolder.address()); + var intfNumberHolder = arena.allocate(JAVA_INT); + IoKitUSB.GetInterfaceNumber(intf, intfNumberHolder); if (intfNumberHolder.get(JAVA_INT, 0) != interfaceNumber) { IoKitUSB.Release(intf); continue; } - return new InterfaceInfo(intf.toRawLongValue(), interfaceNumber); + return new InterfaceInfo(intf, interfaceNumber); } } } @@ -162,13 +161,13 @@ public void claimInterface(int interfaceNumber) { var interfaceInfo = findInterface(interfaceNumber); try { - var ret = IoKitUSB.USBInterfaceOpen(interfaceInfo.asAddress()); + var ret = IoKitUSB.USBInterfaceOpen(interfaceInfo.segment()); if (ret != 0) throwException(ret, "Failed to claim interface"); setClaimed(interfaceNumber, true); } catch (Throwable t) { - IoKitUSB.Release(interfaceInfo.asAddress()); + IoKitUSB.Release(interfaceInfo.segment()); throw t; } @@ -193,7 +192,7 @@ public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { var intfInfo = claimedInterfaces.stream() .filter((interf) -> interf.interfaceNumber() == interfaceNumber).findFirst().get(); - int ret = IoKitUSB.SetAlternateInterface(intfInfo.asAddress(), (byte) alternateNumber); + int ret = IoKitUSB.SetAlternateInterface(intfInfo.segment(), (byte) alternateNumber); if (ret != 0) throwException(ret, "Failed to set alternate interface"); @@ -211,12 +210,12 @@ public void releaseInterface(int interfaceNumber) { var interfaceInfo = interfaceInfoOptional.get(); - int ret = IoKitUSB.USBInterfaceClose(interfaceInfo.asAddress()); + int ret = IoKitUSB.USBInterfaceClose(interfaceInfo.segment()); if (ret != 0) throwException(ret, "Failed to release interface"); claimedInterfaces.remove(interfaceInfo); - IoKitUSB.Release(interfaceInfo.asAddress()); + IoKitUSB.Release(interfaceInfo.segment()); setClaimed(interfaceNumber, false); updateEndpointList(); @@ -233,26 +232,25 @@ private void updateEndpointList() { endpoints = new HashMap<>(); for (InterfaceInfo interfaceInfo : claimedInterfaces) { - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined()) { - var intf = interfaceInfo.asAddress(); - var numEndpointsHolder = session.allocate(JAVA_BYTE); - int ret = IoKitUSB.GetNumEndpoints(intf, numEndpointsHolder.address()); + var intf = interfaceInfo.segment(); + var numEndpointsHolder = arena.allocate(JAVA_BYTE); + int ret = IoKitUSB.GetNumEndpoints(intf, numEndpointsHolder); if (ret != 0) throwException(ret, "Failed to get number of endpoints"); int numEndpoints = numEndpointsHolder.get(JAVA_BYTE, 0) & 255; for (int pipeIndex = 1; pipeIndex <= numEndpoints; pipeIndex++) { - var directionHolder = session.allocate(JAVA_BYTE); - var numberHolder = session.allocate(JAVA_BYTE); - var transferTypeHolder = session.allocate(JAVA_BYTE); - var maxPacketSizeHolder = session.allocate(JAVA_SHORT); - var intervalHolder = session.allocate(JAVA_BYTE); + var directionHolder = arena.allocate(JAVA_BYTE); + var numberHolder = arena.allocate(JAVA_BYTE); + var transferTypeHolder = arena.allocate(JAVA_BYTE); + var maxPacketSizeHolder = arena.allocate(JAVA_SHORT); + var intervalHolder = arena.allocate(JAVA_BYTE); - ret = IoKitUSB.GetPipeProperties(intf, (byte) pipeIndex, directionHolder.address(), - numberHolder.address(), transferTypeHolder.address(), maxPacketSizeHolder.address(), - intervalHolder.address()); + ret = IoKitUSB.GetPipeProperties(intf, (byte) pipeIndex, directionHolder, numberHolder, + transferTypeHolder, maxPacketSizeHolder, intervalHolder); if (ret != 0) throwException(ret, "Failed to get pipe properties"); @@ -261,7 +259,7 @@ private void updateEndpointList() { byte endpointAddress = (byte) (endpointNumber | (direction << 7)); byte transferType = transferTypeHolder.get(JAVA_BYTE, 0); int maxPacketSize = maxPacketSizeHolder.get(JAVA_SHORT, 0) & 0xffff; - var endpointInfo = new EndpointInfo(interfaceInfo.addr, (byte) pipeIndex, + var endpointInfo = new EndpointInfo(interfaceInfo.segment(), (byte) pipeIndex, getTransferType(transferType), maxPacketSize); endpoints.put(endpointAddress, endpointInfo); } @@ -291,9 +289,9 @@ private EndpointInfo getEndpointInfo(int endpointNumber, USBDirection direction, throw new AssertionError("not reached"); } - private static MemorySegment createDeviceRequest(MemorySession session, USBDirection direction, + private static MemorySegment createDeviceRequest(Arena arena, USBDirection direction, USBControlTransfer setup, MemorySegment data) { - var deviceRequest = session.allocate(IOUSBDevRequest.$LAYOUT()); + var deviceRequest = arena.allocate(IOUSBDevRequest.$LAYOUT()); var bmRequestType = (direction == USBDirection.IN ? 0x80 : 0x00) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); IOUSBDevRequest.bmRequestType$set(deviceRequest, (byte) bmRequestType); @@ -301,7 +299,7 @@ private static MemorySegment createDeviceRequest(MemorySession session, USBDirec IOUSBDevRequest.wValue$set(deviceRequest, (short) setup.value()); IOUSBDevRequest.wIndex$set(deviceRequest, (short) setup.index()); IOUSBDevRequest.wLength$set(deviceRequest, (short) data.byteSize()); - IOUSBDevRequest.pData$set(deviceRequest, data.address()); + IOUSBDevRequest.pData$set(deviceRequest, data); return deviceRequest; } @@ -309,11 +307,11 @@ private static MemorySegment createDeviceRequest(MemorySession session, USBDirec public byte[] controlTransferIn(USBControlTransfer setup, int length) { checkIsOpen(); - try (var session = MemorySession.openConfined()) { - var data = session.allocate(length); - var deviceRequest = createDeviceRequest(session, USBDirection.IN, setup, data); + try (var arena = Arena.openConfined()) { + var data = arena.allocate(length); + var deviceRequest = createDeviceRequest(arena, USBDirection.IN, setup, data); - int ret = IoKitUSB.DeviceRequest(device, deviceRequest.address()); + int ret = IoKitUSB.DeviceRequest(device, deviceRequest); if (ret != 0) throwException(ret, "Control IN transfer failed"); @@ -326,13 +324,13 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { public void controlTransferOut(USBControlTransfer setup, byte[] data) { checkIsOpen(); - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined()) { int dataLength = data != null ? data.length : 0; - var dataSegment = session.allocate(dataLength); + var dataSegment = arena.allocate(dataLength); if (dataLength > 0) dataSegment.copyFrom(MemorySegment.ofArray(data)); - var deviceRequest = createDeviceRequest(session, USBDirection.OUT, setup, dataSegment); + var deviceRequest = createDeviceRequest(arena, USBDirection.OUT, setup, dataSegment); - int ret = IoKitUSB.DeviceRequest(device, deviceRequest.address()); + int ret = IoKitUSB.DeviceRequest(device, deviceRequest); if (ret != 0) throwException(ret, "Control IN transfer failed"); } @@ -344,19 +342,19 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); - try (var session = MemorySession.openConfined()) { - var nativeData = session.allocateArray(JAVA_BYTE, data.length); + try (var arena = Arena.openConfined()) { + var nativeData = arena.allocateArray(JAVA_BYTE, data.length); nativeData.copyFrom(MemorySegment.ofArray(data)); int ret; if (timeout <= 0) { // transfer without timeout - ret = IoKitUSB.WritePipe(endpointInfo.interfaceAddress(), endpointInfo.pipeIndex, nativeData.address(), data.length); + ret = IoKitUSB.WritePipe(endpointInfo.segment(), endpointInfo.pipeIndex, nativeData, data.length); } else if (endpointInfo.transferType == USBTransferType.BULK) { // bulk transfer with timeout - ret = IoKitUSB.WritePipeTO(endpointInfo.interfaceAddress(), endpointInfo.pipeIndex, nativeData.address(), + ret = IoKitUSB.WritePipeTO(endpointInfo.segment(), endpointInfo.pipeIndex, nativeData, data.length, timeout, timeout); if (ret == IOKit.kIOUSBTransactionTimeout()) throw new USBTimeoutException("Transfer out aborted due to timeout"); @@ -365,7 +363,7 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { // interrupt transfer with timeout var transferTimeout = new TransferTimeout(endpointInfo, timeout); - ret = IoKitUSB.WritePipe(endpointInfo.interfaceAddress(), endpointInfo.pipeIndex, nativeData.address(), data.length); + ret = IoKitUSB.WritePipe(endpointInfo.segment(), endpointInfo.pipeIndex, nativeData, data.length); if (ret == IOKit.kIOReturnAborted()) throw new USBTimeoutException("Transfer out aborted due to timeout"); transferTimeout.markCompleted(); @@ -382,20 +380,20 @@ public byte[] transferIn(int endpointNumber, int timeout) { var endpoint = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); - try (var session = MemorySession.openConfined()) { - var nativeData = session.allocateArray(JAVA_BYTE, endpoint.packetSize()); - var sizeHolder = session.allocate(JAVA_INT, endpoint.packetSize()); + try (var arena = Arena.openConfined()) { + var nativeData = arena.allocateArray(JAVA_BYTE, endpoint.packetSize()); + var sizeHolder = arena.allocate(JAVA_INT, endpoint.packetSize()); int ret; if (timeout <= 0) { // transfer without timeout - ret = IoKitUSB.ReadPipe(endpoint.interfaceAddress(), endpoint.pipeIndex, nativeData.address(), sizeHolder.address()); + ret = IoKitUSB.ReadPipe(endpoint.segment(), endpoint.pipeIndex, nativeData, sizeHolder); } else if (endpoint.transferType == USBTransferType.BULK) { // bulk transfer with timeout - ret = IoKitUSB.ReadPipeTO(endpoint.interfaceAddress(), endpoint.pipeIndex, nativeData.address(), - sizeHolder.address(), timeout, timeout); + ret = IoKitUSB.ReadPipeTO(endpoint.segment(), endpoint.pipeIndex, nativeData, + sizeHolder, timeout, timeout); if (ret == IOKit.kIOUSBTransactionTimeout()) throw new USBTimeoutException("Transfer in aborted due to timeout"); @@ -403,7 +401,7 @@ public byte[] transferIn(int endpointNumber, int timeout) { // interrupt transfer with timeout var transferTimeout = new TransferTimeout(endpoint, timeout); - ret = IoKitUSB.ReadPipe(endpoint.interfaceAddress(), endpoint.pipeIndex, nativeData.address(), sizeHolder.address()); + ret = IoKitUSB.ReadPipe(endpoint.segment(), endpoint.pipeIndex, nativeData, sizeHolder); if (ret == IOKit.kIOReturnAborted()) throw new USBTimeoutException("Transfer in aborted due to timeout"); transferTimeout.markCompleted(); @@ -425,7 +423,7 @@ public void clearHalt(USBDirection direction, int endpointNumber) { var endpointInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); - int ret = IoKitUSB.ClearPipeStallBothEnds(endpointInfo.interfaceAddress(), endpointInfo.pipeIndex); + int ret = IoKitUSB.ClearPipeStallBothEnds(endpointInfo.segment(), endpointInfo.pipeIndex); if (ret != 0) throwException(ret, "Clearing halt condition failed"); } @@ -439,15 +437,9 @@ private static USBTransferType getTransferType(byte macosTransferType) { }; } - record InterfaceInfo(long addr, int interfaceNumber) { - MemoryAddress asAddress() { - return ofLong(addr); - } + record InterfaceInfo(MemorySegment segment, int interfaceNumber) { } - record EndpointInfo(long interfaceAddr, byte pipeIndex, USBTransferType transferType, int packetSize) { - MemoryAddress interfaceAddress() { - return ofLong(interfaceAddr); - } + record EndpointInfo(MemorySegment segment, byte pipeIndex, USBTransferType transferType, int packetSize) { } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index d10a0a9f..adcb8809 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -8,6 +8,7 @@ package net.codecrete.usb.macos; import net.codecrete.usb.USBDevice; +import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.common.USBDeviceRegistry; import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; import net.codecrete.usb.macos.gen.iokit.IOKit; @@ -19,7 +20,7 @@ import java.util.ArrayList; import java.util.function.Consumer; -import static java.lang.foreign.MemoryAddress.NULL; +import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.macos.MacosUSBException.throwException; @@ -38,7 +39,7 @@ public class MacosUSBDeviceRegistry extends USBDeviceRegistry { protected void monitorDevices() { // as the method runs forever, there is no need to clean up one-time allocations - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined()) { try { @@ -50,8 +51,8 @@ protected void monitorDevices() { // setup notification for connected devices var onDeviceConnectedMH = MethodHandles.lookup().findVirtual(MacosUSBDeviceRegistry.class, - "onDevicesConnected", MethodType.methodType(void.class, MemoryAddress.class, int.class)); - int deviceConnectedIter = setupNotification(session, notifyPort, IOKit.kIOFirstMatchNotification(), + "onDevicesConnected", MethodType.methodType(void.class, MemorySegment.class, int.class)); + int deviceConnectedIter = setupNotification(arena, notifyPort, IOKit.kIOFirstMatchNotification(), onDeviceConnectedMH); // iterate current devices in order to arm the notifications (and build initial device list) @@ -61,8 +62,8 @@ protected void monitorDevices() { // setup notification for disconnected devices var onDeviceDisconnectedMH = MethodHandles.lookup().findVirtual(MacosUSBDeviceRegistry.class, - "onDevicesDisconnected", MethodType.methodType(void.class, MemoryAddress.class, int.class)); - int deviceDisconnectedIter = setupNotification(session, notifyPort, IOKit.kIOTerminatedNotification(), + "onDevicesDisconnected", MethodType.methodType(void.class, MemorySegment.class, int.class)); + int deviceDisconnectedIter = setupNotification(arena, notifyPort, IOKit.kIOTerminatedNotification(), onDeviceDisconnectedMH); // iterate current devices in order to arm the notifications @@ -88,19 +89,19 @@ private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { int svc; while ((svc = IOKit.IOIteratorNext(iterator)) != 0) { - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined(); var cleanup = new ScopeCleanup()) { final int service = svc; - session.addCloseAction(() -> IOKit.IOObjectRelease(service)); + cleanup.add(() -> IOKit.IOObjectRelease(service)); var device = IoKitHelper.getInterface(service, IoKitHelper.kIOUSBDeviceUserClientTypeID, IoKitHelper.kIOUSBDeviceInterfaceID100); if (device != null) - session.addCloseAction(() -> IoKitUSB.Release(device)); + cleanup.add(() -> IoKitUSB.Release(device)); // get entry ID (as unique ID) - var entryIdHolder = session.allocate(JAVA_LONG); + var entryIdHolder = arena.allocate(JAVA_LONG); int ret = IOKit.IORegistryEntryGetRegistryEntryID(service, entryIdHolder); if (ret != 0) throwException(ret, "IORegistryEntryGetRegistryEntryID failed"); @@ -138,7 +139,7 @@ private void iterateDevices(int iterator, Consumer consumer) { }); } - private USBDevice createDevice(Long entryID, int service, MemoryAddress deviceIntf, VidPid info) { + private USBDevice createDevice(Long entryID, int service, MemorySegment deviceIntf, VidPid info) { if (deviceIntf == null) return null; @@ -174,19 +175,19 @@ private USBDevice createDevice(Long entryID, int service, MemoryAddress deviceIn return device; } - private int setupNotification(MemorySession session, MemoryAddress notifyPort, MemorySegment notificationType, + private int setupNotification(Arena arena, MemorySegment notifyPort, MemorySegment notificationType, MethodHandle callback) { // new matching dictionary for (dis)connected device notifications - MemoryAddress matchingDict = IOKit.IOServiceMatching(IOKit.kIOUSBDeviceClassName()); + var matchingDict = IOKit.IOServiceMatching(IOKit.kIOUSBDeviceClassName()); // create callback stub var onDeviceCallbackStub = Linker.nativeLinker().upcallStub(callback.bindTo(this), - FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT), session); + FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT), SegmentScope.global()); // Set up a notification to be called when a device is first matched / terminated by I/O Kit. // This method consumes the matchingDict reference. - var deviceIterHolder = session.allocate(JAVA_INT); + var deviceIterHolder = arena.allocate(JAVA_INT); int ret = IOKit.IOServiceAddMatchingNotification(notifyPort, notificationType, matchingDict, onDeviceCallbackStub, NULL, deviceIterHolder); if (ret != 0) @@ -204,7 +205,7 @@ private int setupNotification(MemorySession session, MemoryAddress notifyPort, M * @param ignoredRefCon ignored parameter * @param iterator device iterator */ - private void onDevicesConnected(MemoryAddress ignoredRefCon, int iterator) { + private void onDevicesConnected(MemorySegment ignoredRefCon, int iterator) { // process device iterator for connected devices iterateDevices(iterator, this::addDevice); @@ -219,7 +220,7 @@ private void onDevicesConnected(MemoryAddress ignoredRefCon, int iterator) { * @param ignoredRefCon ignored parameter * @param iterator device iterator */ - private void onDevicesDisconnected(MemoryAddress ignoredRefCon, int iterator) { + private void onDevicesDisconnected(MemorySegment ignoredRefCon, int iterator) { // process device iterator for disconnected devices iterateDevices(iterator, (entryId, service, deviceIntf) -> { @@ -240,7 +241,7 @@ private void onDevicesDisconnected(MemoryAddress ignoredRefCon, int iterator) { @FunctionalInterface interface IOKitDeviceConsumer { - void accept(long entryId, int service, MemoryAddress deviceIntf); + void accept(long entryId, int service, MemorySegment deviceIntf); } static class VidPid { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java index e736f505..4343871c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java @@ -38,7 +38,7 @@ class TransferTimeout { private synchronized void abort() { if (completed) return; - int ret = IoKitUSB.AbortPipe(endpointInfo.interfaceAddress(), endpointInfo.pipeIndex()); + int ret = IoKitUSB.AbortPipe(endpointInfo.segment(), endpointInfo.pipeIndex()); if (ret != 0) throwException(ret, "Failed to abort USB transfer after timeout"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java index cccaa04c..dfc7678a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java @@ -9,10 +9,10 @@ import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; -import java.lang.foreign.MemoryAddress; -import java.lang.foreign.MemorySession; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; -import static java.lang.foreign.MemoryAddress.NULL; +import static java.lang.foreign.MemorySegment.NULL; /** * Memory layouts and helpers for CFUUID. @@ -24,9 +24,9 @@ public class UUID { * @param bytes UUID as 16 bytes * @return the CFUUID */ - public static MemoryAddress CreateCFUUID(byte[] bytes) { - try (var session = MemorySession.openConfined()) { - var uuidBytes = session.allocate(16); + public static MemorySegment CreateCFUUID(byte[] bytes) { + try (var arena = Arena.openConfined()) { + var uuidBytes = arena.allocate(16); uuidBytes.asByteBuffer().put(bytes); return CoreFoundation.CFUUIDCreateFromUUIDBytes(NULL, uuidBytes); } catch (Throwable t) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java index d53e92ea..ef744683 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java @@ -4,9 +4,17 @@ import java.lang.foreign.*; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct { + * CFIndex location; + * CFIndex length; + * }; + * } + */ public class CFRange { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_LONG_LONG$LAYOUT.withName("location"), Constants$root.C_LONG_LONG$LAYOUT.withName("length") ); @@ -17,10 +25,22 @@ public class CFRange { public static VarHandle location$VH() { return CFRange.location$VH; } + /** + * Getter for field: + * {@snippet : + * CFIndex location; + * } + */ public static long location$get(MemorySegment seg) { return (long)CFRange.location$VH.get(seg); } - public static void location$set( MemorySegment seg, long x) { + /** + * Setter for field: + * {@snippet : + * CFIndex location; + * } + */ + public static void location$set(MemorySegment seg, long x) { CFRange.location$VH.set(seg, x); } public static long location$get(MemorySegment seg, long index) { @@ -33,10 +53,22 @@ public class CFRange { public static VarHandle length$VH() { return CFRange.length$VH; } + /** + * Getter for field: + * {@snippet : + * CFIndex length; + * } + */ public static long length$get(MemorySegment seg) { return (long)CFRange.length$VH.get(seg); } - public static void length$set( MemorySegment seg, long x) { + /** + * Setter for field: + * {@snippet : + * CFIndex length; + * } + */ + public static void length$set(MemorySegment seg, long x) { CFRange.length$VH.set(seg, x); } public static long length$get(MemorySegment seg, long index) { @@ -47,10 +79,10 @@ public class CFRange { } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java index f69fbaa5..f2f406e2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java @@ -4,9 +4,31 @@ import java.lang.foreign.*; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct { + * UInt8 byte0; + * UInt8 byte1; + * UInt8 byte2; + * UInt8 byte3; + * UInt8 byte4; + * UInt8 byte5; + * UInt8 byte6; + * UInt8 byte7; + * UInt8 byte8; + * UInt8 byte9; + * UInt8 byte10; + * UInt8 byte11; + * UInt8 byte12; + * UInt8 byte13; + * UInt8 byte14; + * UInt8 byte15; + * }; + * } + */ public class CFUUIDBytes { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_CHAR$LAYOUT.withName("byte0"), Constants$root.C_CHAR$LAYOUT.withName("byte1"), Constants$root.C_CHAR$LAYOUT.withName("byte2"), @@ -31,10 +53,22 @@ public class CFUUIDBytes { public static VarHandle byte0$VH() { return CFUUIDBytes.byte0$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 byte0; + * } + */ public static byte byte0$get(MemorySegment seg) { return (byte)CFUUIDBytes.byte0$VH.get(seg); } - public static void byte0$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 byte0; + * } + */ + public static void byte0$set(MemorySegment seg, byte x) { CFUUIDBytes.byte0$VH.set(seg, x); } public static byte byte0$get(MemorySegment seg, long index) { @@ -47,10 +81,22 @@ public class CFUUIDBytes { public static VarHandle byte1$VH() { return CFUUIDBytes.byte1$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 byte1; + * } + */ public static byte byte1$get(MemorySegment seg) { return (byte)CFUUIDBytes.byte1$VH.get(seg); } - public static void byte1$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 byte1; + * } + */ + public static void byte1$set(MemorySegment seg, byte x) { CFUUIDBytes.byte1$VH.set(seg, x); } public static byte byte1$get(MemorySegment seg, long index) { @@ -63,10 +109,22 @@ public class CFUUIDBytes { public static VarHandle byte2$VH() { return CFUUIDBytes.byte2$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 byte2; + * } + */ public static byte byte2$get(MemorySegment seg) { return (byte)CFUUIDBytes.byte2$VH.get(seg); } - public static void byte2$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 byte2; + * } + */ + public static void byte2$set(MemorySegment seg, byte x) { CFUUIDBytes.byte2$VH.set(seg, x); } public static byte byte2$get(MemorySegment seg, long index) { @@ -79,10 +137,22 @@ public class CFUUIDBytes { public static VarHandle byte3$VH() { return CFUUIDBytes.byte3$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 byte3; + * } + */ public static byte byte3$get(MemorySegment seg) { return (byte)CFUUIDBytes.byte3$VH.get(seg); } - public static void byte3$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 byte3; + * } + */ + public static void byte3$set(MemorySegment seg, byte x) { CFUUIDBytes.byte3$VH.set(seg, x); } public static byte byte3$get(MemorySegment seg, long index) { @@ -95,10 +165,22 @@ public class CFUUIDBytes { public static VarHandle byte4$VH() { return CFUUIDBytes.byte4$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 byte4; + * } + */ public static byte byte4$get(MemorySegment seg) { return (byte)CFUUIDBytes.byte4$VH.get(seg); } - public static void byte4$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 byte4; + * } + */ + public static void byte4$set(MemorySegment seg, byte x) { CFUUIDBytes.byte4$VH.set(seg, x); } public static byte byte4$get(MemorySegment seg, long index) { @@ -111,10 +193,22 @@ public class CFUUIDBytes { public static VarHandle byte5$VH() { return CFUUIDBytes.byte5$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 byte5; + * } + */ public static byte byte5$get(MemorySegment seg) { return (byte)CFUUIDBytes.byte5$VH.get(seg); } - public static void byte5$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 byte5; + * } + */ + public static void byte5$set(MemorySegment seg, byte x) { CFUUIDBytes.byte5$VH.set(seg, x); } public static byte byte5$get(MemorySegment seg, long index) { @@ -127,10 +221,22 @@ public class CFUUIDBytes { public static VarHandle byte6$VH() { return CFUUIDBytes.byte6$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 byte6; + * } + */ public static byte byte6$get(MemorySegment seg) { return (byte)CFUUIDBytes.byte6$VH.get(seg); } - public static void byte6$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 byte6; + * } + */ + public static void byte6$set(MemorySegment seg, byte x) { CFUUIDBytes.byte6$VH.set(seg, x); } public static byte byte6$get(MemorySegment seg, long index) { @@ -143,10 +249,22 @@ public class CFUUIDBytes { public static VarHandle byte7$VH() { return CFUUIDBytes.byte7$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 byte7; + * } + */ public static byte byte7$get(MemorySegment seg) { return (byte)CFUUIDBytes.byte7$VH.get(seg); } - public static void byte7$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 byte7; + * } + */ + public static void byte7$set(MemorySegment seg, byte x) { CFUUIDBytes.byte7$VH.set(seg, x); } public static byte byte7$get(MemorySegment seg, long index) { @@ -159,10 +277,22 @@ public class CFUUIDBytes { public static VarHandle byte8$VH() { return CFUUIDBytes.byte8$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 byte8; + * } + */ public static byte byte8$get(MemorySegment seg) { return (byte)CFUUIDBytes.byte8$VH.get(seg); } - public static void byte8$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 byte8; + * } + */ + public static void byte8$set(MemorySegment seg, byte x) { CFUUIDBytes.byte8$VH.set(seg, x); } public static byte byte8$get(MemorySegment seg, long index) { @@ -175,10 +305,22 @@ public class CFUUIDBytes { public static VarHandle byte9$VH() { return CFUUIDBytes.byte9$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 byte9; + * } + */ public static byte byte9$get(MemorySegment seg) { return (byte)CFUUIDBytes.byte9$VH.get(seg); } - public static void byte9$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 byte9; + * } + */ + public static void byte9$set(MemorySegment seg, byte x) { CFUUIDBytes.byte9$VH.set(seg, x); } public static byte byte9$get(MemorySegment seg, long index) { @@ -191,10 +333,22 @@ public class CFUUIDBytes { public static VarHandle byte10$VH() { return CFUUIDBytes.byte10$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 byte10; + * } + */ public static byte byte10$get(MemorySegment seg) { return (byte)CFUUIDBytes.byte10$VH.get(seg); } - public static void byte10$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 byte10; + * } + */ + public static void byte10$set(MemorySegment seg, byte x) { CFUUIDBytes.byte10$VH.set(seg, x); } public static byte byte10$get(MemorySegment seg, long index) { @@ -207,10 +361,22 @@ public class CFUUIDBytes { public static VarHandle byte11$VH() { return CFUUIDBytes.byte11$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 byte11; + * } + */ public static byte byte11$get(MemorySegment seg) { return (byte)CFUUIDBytes.byte11$VH.get(seg); } - public static void byte11$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 byte11; + * } + */ + public static void byte11$set(MemorySegment seg, byte x) { CFUUIDBytes.byte11$VH.set(seg, x); } public static byte byte11$get(MemorySegment seg, long index) { @@ -223,10 +389,22 @@ public class CFUUIDBytes { public static VarHandle byte12$VH() { return CFUUIDBytes.byte12$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 byte12; + * } + */ public static byte byte12$get(MemorySegment seg) { return (byte)CFUUIDBytes.byte12$VH.get(seg); } - public static void byte12$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 byte12; + * } + */ + public static void byte12$set(MemorySegment seg, byte x) { CFUUIDBytes.byte12$VH.set(seg, x); } public static byte byte12$get(MemorySegment seg, long index) { @@ -239,10 +417,22 @@ public class CFUUIDBytes { public static VarHandle byte13$VH() { return CFUUIDBytes.byte13$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 byte13; + * } + */ public static byte byte13$get(MemorySegment seg) { return (byte)CFUUIDBytes.byte13$VH.get(seg); } - public static void byte13$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 byte13; + * } + */ + public static void byte13$set(MemorySegment seg, byte x) { CFUUIDBytes.byte13$VH.set(seg, x); } public static byte byte13$get(MemorySegment seg, long index) { @@ -255,10 +445,22 @@ public class CFUUIDBytes { public static VarHandle byte14$VH() { return CFUUIDBytes.byte14$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 byte14; + * } + */ public static byte byte14$get(MemorySegment seg) { return (byte)CFUUIDBytes.byte14$VH.get(seg); } - public static void byte14$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 byte14; + * } + */ + public static void byte14$set(MemorySegment seg, byte x) { CFUUIDBytes.byte14$VH.set(seg, x); } public static byte byte14$get(MemorySegment seg, long index) { @@ -271,10 +473,22 @@ public class CFUUIDBytes { public static VarHandle byte15$VH() { return CFUUIDBytes.byte15$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 byte15; + * } + */ public static byte byte15$get(MemorySegment seg) { return (byte)CFUUIDBytes.byte15$VH.get(seg); } - public static void byte15$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 byte15; + * } + */ + public static void byte15$set(MemorySegment seg, byte x) { CFUUIDBytes.byte15$VH.set(seg, x); } public static byte byte15$get(MemorySegment seg, long index) { @@ -285,10 +499,10 @@ public class CFUUIDBytes { } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/Constants$root.java index 0755ccbe..5de30387 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.macos.gen.corefoundation; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfLong C_LONG$LAYOUT = JAVA_LONG; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java index 2e501cd5..32901212 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java @@ -2,8 +2,6 @@ package net.codecrete.usb.macos.gen.corefoundation; -import java.lang.foreign.Addressable; -import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; import java.lang.invoke.MethodHandle; @@ -11,19 +9,23 @@ import static java.lang.foreign.ValueLayout.*; public class CoreFoundation { - /* package-private */ CoreFoundation() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; public static MethodHandle CFGetTypeID$MH() { return RuntimeHelper.requireNonNull(constants$0.CFGetTypeID$MH,"CFGetTypeID"); } - public static long CFGetTypeID ( Addressable cf) { + /** + * {@snippet : + * CFTypeID CFGetTypeID(CFTypeRef cf); + * } + */ + public static long CFGetTypeID(MemorySegment cf) { var mh$ = CFGetTypeID$MH(); try { return (long)mh$.invokeExact(cf); @@ -34,7 +36,12 @@ public static long CFGetTypeID ( Addressable cf) { public static MethodHandle CFRelease$MH() { return RuntimeHelper.requireNonNull(constants$0.CFRelease$MH,"CFRelease"); } - public static void CFRelease ( Addressable cf) { + /** + * {@snippet : + * void CFRelease(CFTypeRef cf); + * } + */ + public static void CFRelease(MemorySegment cf) { var mh$ = CFRelease$MH(); try { mh$.invokeExact(cf); @@ -45,7 +52,12 @@ public static void CFRelease ( Addressable cf) { public static MethodHandle CFStringGetTypeID$MH() { return RuntimeHelper.requireNonNull(constants$0.CFStringGetTypeID$MH,"CFStringGetTypeID"); } - public static long CFStringGetTypeID () { + /** + * {@snippet : + * CFTypeID CFStringGetTypeID(); + * } + */ + public static long CFStringGetTypeID() { var mh$ = CFStringGetTypeID$MH(); try { return (long)mh$.invokeExact(); @@ -56,10 +68,15 @@ public static long CFStringGetTypeID () { public static MethodHandle CFStringCreateWithCharacters$MH() { return RuntimeHelper.requireNonNull(constants$0.CFStringCreateWithCharacters$MH,"CFStringCreateWithCharacters"); } - public static MemoryAddress CFStringCreateWithCharacters ( Addressable alloc, Addressable chars, long numChars) { + /** + * {@snippet : + * CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, const UniChar* chars, CFIndex numChars); + * } + */ + public static MemorySegment CFStringCreateWithCharacters(MemorySegment alloc, MemorySegment chars, long numChars) { var mh$ = CFStringCreateWithCharacters$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(alloc, chars, numChars); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(alloc, chars, numChars); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -67,7 +84,12 @@ public static MemoryAddress CFStringCreateWithCharacters ( Addressable alloc, A public static MethodHandle CFStringGetLength$MH() { return RuntimeHelper.requireNonNull(constants$0.CFStringGetLength$MH,"CFStringGetLength"); } - public static long CFStringGetLength ( Addressable theString) { + /** + * {@snippet : + * CFIndex CFStringGetLength(CFStringRef theString); + * } + */ + public static long CFStringGetLength(MemorySegment theString) { var mh$ = CFStringGetLength$MH(); try { return (long)mh$.invokeExact(theString); @@ -78,7 +100,12 @@ public static long CFStringGetLength ( Addressable theString) { public static MethodHandle CFStringGetCharacters$MH() { return RuntimeHelper.requireNonNull(constants$0.CFStringGetCharacters$MH,"CFStringGetCharacters"); } - public static void CFStringGetCharacters ( Addressable theString, MemorySegment range, Addressable buffer) { + /** + * {@snippet : + * void CFStringGetCharacters(CFStringRef theString, CFRange range, UniChar* buffer); + * } + */ + public static void CFStringGetCharacters(MemorySegment theString, MemorySegment range, MemorySegment buffer) { var mh$ = CFStringGetCharacters$MH(); try { mh$.invokeExact(theString, range, buffer); @@ -86,13 +113,23 @@ public static void CFStringGetCharacters ( Addressable theString, MemorySegment throw new AssertionError("should not reach here", ex$); } } + /** + * {@snippet : + * enum .kCFNumberSInt32Type = 3; + * } + */ public static int kCFNumberSInt32Type() { return (int)3L; } public static MethodHandle CFNumberGetTypeID$MH() { return RuntimeHelper.requireNonNull(constants$1.CFNumberGetTypeID$MH,"CFNumberGetTypeID"); } - public static long CFNumberGetTypeID () { + /** + * {@snippet : + * CFTypeID CFNumberGetTypeID(); + * } + */ + public static long CFNumberGetTypeID() { var mh$ = CFNumberGetTypeID$MH(); try { return (long)mh$.invokeExact(); @@ -103,7 +140,12 @@ public static long CFNumberGetTypeID () { public static MethodHandle CFNumberGetValue$MH() { return RuntimeHelper.requireNonNull(constants$1.CFNumberGetValue$MH,"CFNumberGetValue"); } - public static byte CFNumberGetValue ( Addressable number, long theType, Addressable valuePtr) { + /** + * {@snippet : + * Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void* valuePtr); + * } + */ + public static byte CFNumberGetValue(MemorySegment number, long theType, MemorySegment valuePtr) { var mh$ = CFNumberGetValue$MH(); try { return (byte)mh$.invokeExact(number, theType, valuePtr); @@ -114,10 +156,15 @@ public static byte CFNumberGetValue ( Addressable number, long theType, Addres public static MethodHandle CFRunLoopGetCurrent$MH() { return RuntimeHelper.requireNonNull(constants$1.CFRunLoopGetCurrent$MH,"CFRunLoopGetCurrent"); } - public static MemoryAddress CFRunLoopGetCurrent () { + /** + * {@snippet : + * CFRunLoopRef CFRunLoopGetCurrent(); + * } + */ + public static MemorySegment CFRunLoopGetCurrent() { var mh$ = CFRunLoopGetCurrent$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -125,7 +172,12 @@ public static MemoryAddress CFRunLoopGetCurrent () { public static MethodHandle CFRunLoopRun$MH() { return RuntimeHelper.requireNonNull(constants$1.CFRunLoopRun$MH,"CFRunLoopRun"); } - public static void CFRunLoopRun () { + /** + * {@snippet : + * void CFRunLoopRun(); + * } + */ + public static void CFRunLoopRun() { var mh$ = CFRunLoopRun$MH(); try { mh$.invokeExact(); @@ -136,7 +188,12 @@ public static void CFRunLoopRun () { public static MethodHandle CFRunLoopAddSource$MH() { return RuntimeHelper.requireNonNull(constants$1.CFRunLoopAddSource$MH,"CFRunLoopAddSource"); } - public static void CFRunLoopAddSource ( Addressable rl, Addressable source, Addressable mode) { + /** + * {@snippet : + * void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode); + * } + */ + public static void CFRunLoopAddSource(MemorySegment rl, MemorySegment source, MemorySegment mode) { var mh$ = CFRunLoopAddSource$MH(); try { mh$.invokeExact(rl, source, mode); @@ -147,7 +204,12 @@ public static void CFRunLoopAddSource ( Addressable rl, Addressable source, Ad public static MethodHandle CFUUIDGetUUIDBytes$MH() { return RuntimeHelper.requireNonNull(constants$1.CFUUIDGetUUIDBytes$MH,"CFUUIDGetUUIDBytes"); } - public static MemorySegment CFUUIDGetUUIDBytes ( SegmentAllocator allocator, Addressable uuid) { + /** + * {@snippet : + * CFUUIDBytes CFUUIDGetUUIDBytes(CFUUIDRef uuid); + * } + */ + public static MemorySegment CFUUIDGetUUIDBytes(SegmentAllocator allocator, MemorySegment uuid) { var mh$ = CFUUIDGetUUIDBytes$MH(); try { return (java.lang.foreign.MemorySegment)mh$.invokeExact(allocator, uuid); @@ -158,10 +220,15 @@ public static MemorySegment CFUUIDGetUUIDBytes ( SegmentAllocator allocator, Ad public static MethodHandle CFUUIDCreateFromUUIDBytes$MH() { return RuntimeHelper.requireNonNull(constants$2.CFUUIDCreateFromUUIDBytes$MH,"CFUUIDCreateFromUUIDBytes"); } - public static MemoryAddress CFUUIDCreateFromUUIDBytes ( Addressable alloc, MemorySegment bytes) { + /** + * {@snippet : + * CFUUIDRef CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc, CFUUIDBytes bytes); + * } + */ + public static MemorySegment CFUUIDCreateFromUUIDBytes(MemorySegment alloc, MemorySegment bytes) { var mh$ = CFUUIDCreateFromUUIDBytes$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(alloc, bytes); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(alloc, bytes); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java index 868a5980..d4f89117 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java @@ -10,22 +10,25 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { // System.loadLibrary("CoreFoundation.framework"); // SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SymbolLookup loaderLookup = SymbolLookup.libraryLookup("CoreFoundation.framework/CoreFoundation", MemorySession.openImplicit()); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SymbolLookup loaderLookup = SymbolLookup.libraryLookup("CoreFoundation.framework/CoreFoundation", SegmentScope.global()); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -33,45 +36,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -97,7 +98,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -107,8 +110,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -143,7 +145,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -193,10 +197,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -207,7 +208,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$0.java index 08d7d3ea..6a64bbf2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$0.java @@ -5,8 +5,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.MemoryLayout; import java.lang.invoke.MethodHandle; -class constants$0 { +final class constants$0 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} static final FunctionDescriptor CFGetTypeID$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT ); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java index 16dac46b..90825ba1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java @@ -5,8 +5,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.MemoryLayout; import java.lang.invoke.MethodHandle; -class constants$1 { +final class constants$1 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$1() {} static final FunctionDescriptor CFNumberGetTypeID$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT); static final MethodHandle CFNumberGetTypeID$MH = RuntimeHelper.downcallHandle( "CFNumberGetTypeID", diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java index 9558038b..2bfd6b76 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java @@ -5,8 +5,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.MemoryLayout; import java.lang.invoke.MethodHandle; -class constants$2 { +final class constants$2 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$2() {} static final FunctionDescriptor CFUUIDCreateFromUUIDBytes$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT, MemoryLayout.structLayout( diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/Constants$root.java index baa3d26a..7c6305d6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.macos.gen.iokit; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfLong C_LONG$LAYOUT = JAVA_LONG; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterface.java index 401ce8fc..0b23bb51 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterface.java @@ -2,8 +2,15 @@ package net.codecrete.usb.macos.gen.iokit; -public class IOCFPlugInInterface extends IOCFPlugInInterfaceStruct { +/** + * {@snippet : + * typedef struct IOCFPlugInInterfaceStruct IOCFPlugInInterface; + * } + */ +public final class IOCFPlugInInterface extends IOCFPlugInInterfaceStruct { + // Suppresses default constructor, ensuring non-instantiability. + private IOCFPlugInInterface() {} } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java index 5f9e0c79..5aadda09 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java @@ -5,9 +5,24 @@ import java.lang.foreign.*; import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct IOCFPlugInInterfaceStruct { + * void* _reserved; + * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * ULONG (*AddRef)(void*); + * ULONG (*Release)(void*); + * UInt16 version; + * UInt16 revision; + * IOReturn (*Probe)(void*,CFDictionaryRef,io_service_t,SInt32*); + * IOReturn (*Start)(void*,CFDictionaryRef,io_service_t); + * IOReturn (*Stop)(void*); + * }; + * } + */ public class IOCFPlugInInterfaceStruct { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_POINTER$LAYOUT.withName("_reserved"), Constants$root.C_POINTER$LAYOUT.withName("QueryInterface"), Constants$root.C_POINTER$LAYOUT.withName("AddRef"), @@ -26,16 +41,28 @@ public class IOCFPlugInInterfaceStruct { public static VarHandle _reserved$VH() { return IOCFPlugInInterfaceStruct._reserved$VH; } - public static MemoryAddress _reserved$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct._reserved$VH.get(seg); - } - public static void _reserved$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * void* _reserved; + * } + */ + public static MemorySegment _reserved$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct._reserved$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * void* _reserved; + * } + */ + public static void _reserved$set(MemorySegment seg, MemorySegment x) { IOCFPlugInInterfaceStruct._reserved$VH.set(seg, x); } - public static MemoryAddress _reserved$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct._reserved$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment _reserved$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct._reserved$VH.get(seg.asSlice(index*sizeof())); } - public static void _reserved$set(MemorySegment seg, long index, MemoryAddress x) { + public static void _reserved$set(MemorySegment seg, long index, MemorySegment x) { IOCFPlugInInterfaceStruct._reserved$VH.set(seg.asSlice(index*sizeof()), x); } static final FunctionDescriptor QueryInterface$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, @@ -63,17 +90,22 @@ public class IOCFPlugInInterfaceStruct { static final MethodHandle QueryInterface$MH = RuntimeHelper.downcallHandle( IOCFPlugInInterfaceStruct.QueryInterface$FUNC ); + /** + * {@snippet : + * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * } + */ public interface QueryInterface { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(QueryInterface fi, MemorySession session) { - return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOCFPlugInInterfaceStruct.QueryInterface$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); + static MemorySegment allocate(QueryInterface fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOCFPlugInInterfaceStruct.QueryInterface$FUNC, scope); } - static QueryInterface ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemoryAddress __x2) -> { + static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOCFPlugInInterfaceStruct.QueryInterface$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + return (int)IOCFPlugInInterfaceStruct.QueryInterface$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -85,20 +117,32 @@ static QueryInterface ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle QueryInterface$VH() { return IOCFPlugInInterfaceStruct.QueryInterface$VH; } - public static MemoryAddress QueryInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.QueryInterface$VH.get(seg); - } - public static void QueryInterface$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * } + */ + public static MemorySegment QueryInterface$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.QueryInterface$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * } + */ + public static void QueryInterface$set(MemorySegment seg, MemorySegment x) { IOCFPlugInInterfaceStruct.QueryInterface$VH.set(seg, x); } - public static MemoryAddress QueryInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.QueryInterface$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment QueryInterface$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.QueryInterface$VH.get(seg.asSlice(index*sizeof())); } - public static void QueryInterface$set(MemorySegment seg, long index, MemoryAddress x) { + public static void QueryInterface$set(MemorySegment seg, long index, MemorySegment x) { IOCFPlugInInterfaceStruct.QueryInterface$VH.set(seg.asSlice(index*sizeof()), x); } - public static QueryInterface QueryInterface (MemorySegment segment, MemorySession session) { - return QueryInterface.ofAddress(QueryInterface$get(segment), session); + public static QueryInterface QueryInterface(MemorySegment segment, SegmentScope scope) { + return QueryInterface.ofAddress(QueryInterface$get(segment), scope); } static final FunctionDescriptor AddRef$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -106,17 +150,22 @@ public static QueryInterface QueryInterface (MemorySegment segment, MemorySessio static final MethodHandle AddRef$MH = RuntimeHelper.downcallHandle( IOCFPlugInInterfaceStruct.AddRef$FUNC ); + /** + * {@snippet : + * ULONG (*AddRef)(void*); + * } + */ public interface AddRef { - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(AddRef fi, MemorySession session) { - return RuntimeHelper.upcallStub(AddRef.class, fi, IOCFPlugInInterfaceStruct.AddRef$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(AddRef fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(AddRef.class, fi, IOCFPlugInInterfaceStruct.AddRef$FUNC, scope); } - static AddRef ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { + static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOCFPlugInInterfaceStruct.AddRef$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOCFPlugInInterfaceStruct.AddRef$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -128,20 +177,32 @@ static AddRef ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle AddRef$VH() { return IOCFPlugInInterfaceStruct.AddRef$VH; } - public static MemoryAddress AddRef$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.AddRef$VH.get(seg); - } - public static void AddRef$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * ULONG (*AddRef)(void*); + * } + */ + public static MemorySegment AddRef$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.AddRef$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * ULONG (*AddRef)(void*); + * } + */ + public static void AddRef$set(MemorySegment seg, MemorySegment x) { IOCFPlugInInterfaceStruct.AddRef$VH.set(seg, x); } - public static MemoryAddress AddRef$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.AddRef$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment AddRef$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.AddRef$VH.get(seg.asSlice(index*sizeof())); } - public static void AddRef$set(MemorySegment seg, long index, MemoryAddress x) { + public static void AddRef$set(MemorySegment seg, long index, MemorySegment x) { IOCFPlugInInterfaceStruct.AddRef$VH.set(seg.asSlice(index*sizeof()), x); } - public static AddRef AddRef (MemorySegment segment, MemorySession session) { - return AddRef.ofAddress(AddRef$get(segment), session); + public static AddRef AddRef(MemorySegment segment, SegmentScope scope) { + return AddRef.ofAddress(AddRef$get(segment), scope); } static final FunctionDescriptor Release$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -149,17 +210,22 @@ public static AddRef AddRef (MemorySegment segment, MemorySession session) { static final MethodHandle Release$MH = RuntimeHelper.downcallHandle( IOCFPlugInInterfaceStruct.Release$FUNC ); + /** + * {@snippet : + * ULONG (*Release)(void*); + * } + */ public interface Release { - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(Release fi, MemorySession session) { - return RuntimeHelper.upcallStub(Release.class, fi, IOCFPlugInInterfaceStruct.Release$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(Release fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(Release.class, fi, IOCFPlugInInterfaceStruct.Release$FUNC, scope); } - static Release ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { + static Release ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOCFPlugInInterfaceStruct.Release$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOCFPlugInInterfaceStruct.Release$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -171,29 +237,53 @@ static Release ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle Release$VH() { return IOCFPlugInInterfaceStruct.Release$VH; } - public static MemoryAddress Release$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.Release$VH.get(seg); - } - public static void Release$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * ULONG (*Release)(void*); + * } + */ + public static MemorySegment Release$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.Release$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * ULONG (*Release)(void*); + * } + */ + public static void Release$set(MemorySegment seg, MemorySegment x) { IOCFPlugInInterfaceStruct.Release$VH.set(seg, x); } - public static MemoryAddress Release$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.Release$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment Release$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.Release$VH.get(seg.asSlice(index*sizeof())); } - public static void Release$set(MemorySegment seg, long index, MemoryAddress x) { + public static void Release$set(MemorySegment seg, long index, MemorySegment x) { IOCFPlugInInterfaceStruct.Release$VH.set(seg.asSlice(index*sizeof()), x); } - public static Release Release (MemorySegment segment, MemorySession session) { - return Release.ofAddress(Release$get(segment), session); + public static Release Release(MemorySegment segment, SegmentScope scope) { + return Release.ofAddress(Release$get(segment), scope); } static final VarHandle version$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("version")); public static VarHandle version$VH() { return IOCFPlugInInterfaceStruct.version$VH; } + /** + * Getter for field: + * {@snippet : + * UInt16 version; + * } + */ public static short version$get(MemorySegment seg) { return (short)IOCFPlugInInterfaceStruct.version$VH.get(seg); } - public static void version$set( MemorySegment seg, short x) { + /** + * Setter for field: + * {@snippet : + * UInt16 version; + * } + */ + public static void version$set(MemorySegment seg, short x) { IOCFPlugInInterfaceStruct.version$VH.set(seg, x); } public static short version$get(MemorySegment seg, long index) { @@ -206,10 +296,22 @@ public static Release Release (MemorySegment segment, MemorySession session) { public static VarHandle revision$VH() { return IOCFPlugInInterfaceStruct.revision$VH; } + /** + * Getter for field: + * {@snippet : + * UInt16 revision; + * } + */ public static short revision$get(MemorySegment seg) { return (short)IOCFPlugInInterfaceStruct.revision$VH.get(seg); } - public static void revision$set( MemorySegment seg, short x) { + /** + * Setter for field: + * {@snippet : + * UInt16 revision; + * } + */ + public static void revision$set(MemorySegment seg, short x) { IOCFPlugInInterfaceStruct.revision$VH.set(seg, x); } public static short revision$get(MemorySegment seg, long index) { @@ -227,17 +329,22 @@ public static Release Release (MemorySegment segment, MemorySession session) { static final MethodHandle Probe$MH = RuntimeHelper.downcallHandle( IOCFPlugInInterfaceStruct.Probe$FUNC ); + /** + * {@snippet : + * IOReturn (*Probe)(void*,CFDictionaryRef,io_service_t,SInt32*); + * } + */ public interface Probe { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, int _x2, java.lang.foreign.MemoryAddress _x3); - static MemorySegment allocate(Probe fi, MemorySession session) { - return RuntimeHelper.upcallStub(Probe.class, fi, IOCFPlugInInterfaceStruct.Probe$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, int _x2, java.lang.foreign.MemorySegment _x3); + static MemorySegment allocate(Probe fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(Probe.class, fi, IOCFPlugInInterfaceStruct.Probe$FUNC, scope); } - static Probe ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, int __x2, java.lang.foreign.MemoryAddress __x3) -> { + static Probe ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, int __x2, java.lang.foreign.MemorySegment __x3) -> { try { - return (int)IOCFPlugInInterfaceStruct.Probe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, __x2, (java.lang.foreign.Addressable)__x3); + return (int)IOCFPlugInInterfaceStruct.Probe$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -249,20 +356,32 @@ static Probe ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle Probe$VH() { return IOCFPlugInInterfaceStruct.Probe$VH; } - public static MemoryAddress Probe$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.Probe$VH.get(seg); - } - public static void Probe$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*Probe)(void*,CFDictionaryRef,io_service_t,SInt32*); + * } + */ + public static MemorySegment Probe$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.Probe$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*Probe)(void*,CFDictionaryRef,io_service_t,SInt32*); + * } + */ + public static void Probe$set(MemorySegment seg, MemorySegment x) { IOCFPlugInInterfaceStruct.Probe$VH.set(seg, x); } - public static MemoryAddress Probe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.Probe$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment Probe$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.Probe$VH.get(seg.asSlice(index*sizeof())); } - public static void Probe$set(MemorySegment seg, long index, MemoryAddress x) { + public static void Probe$set(MemorySegment seg, long index, MemorySegment x) { IOCFPlugInInterfaceStruct.Probe$VH.set(seg.asSlice(index*sizeof()), x); } - public static Probe Probe (MemorySegment segment, MemorySession session) { - return Probe.ofAddress(Probe$get(segment), session); + public static Probe Probe(MemorySegment segment, SegmentScope scope) { + return Probe.ofAddress(Probe$get(segment), scope); } static final FunctionDescriptor Start$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -272,17 +391,22 @@ public static Probe Probe (MemorySegment segment, MemorySession session) { static final MethodHandle Start$MH = RuntimeHelper.downcallHandle( IOCFPlugInInterfaceStruct.Start$FUNC ); + /** + * {@snippet : + * IOReturn (*Start)(void*,CFDictionaryRef,io_service_t); + * } + */ public interface Start { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, int _x2); - static MemorySegment allocate(Start fi, MemorySession session) { - return RuntimeHelper.upcallStub(Start.class, fi, IOCFPlugInInterfaceStruct.Start$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, int _x2); + static MemorySegment allocate(Start fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(Start.class, fi, IOCFPlugInInterfaceStruct.Start$FUNC, scope); } - static Start ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, int __x2) -> { + static Start ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, int __x2) -> { try { - return (int)IOCFPlugInInterfaceStruct.Start$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, __x2); + return (int)IOCFPlugInInterfaceStruct.Start$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -294,20 +418,32 @@ static Start ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle Start$VH() { return IOCFPlugInInterfaceStruct.Start$VH; } - public static MemoryAddress Start$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.Start$VH.get(seg); - } - public static void Start$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*Start)(void*,CFDictionaryRef,io_service_t); + * } + */ + public static MemorySegment Start$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.Start$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*Start)(void*,CFDictionaryRef,io_service_t); + * } + */ + public static void Start$set(MemorySegment seg, MemorySegment x) { IOCFPlugInInterfaceStruct.Start$VH.set(seg, x); } - public static MemoryAddress Start$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.Start$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment Start$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.Start$VH.get(seg.asSlice(index*sizeof())); } - public static void Start$set(MemorySegment seg, long index, MemoryAddress x) { + public static void Start$set(MemorySegment seg, long index, MemorySegment x) { IOCFPlugInInterfaceStruct.Start$VH.set(seg.asSlice(index*sizeof()), x); } - public static Start Start (MemorySegment segment, MemorySession session) { - return Start.ofAddress(Start$get(segment), session); + public static Start Start(MemorySegment segment, SegmentScope scope) { + return Start.ofAddress(Start$get(segment), scope); } static final FunctionDescriptor Stop$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -315,17 +451,22 @@ public static Start Start (MemorySegment segment, MemorySession session) { static final MethodHandle Stop$MH = RuntimeHelper.downcallHandle( IOCFPlugInInterfaceStruct.Stop$FUNC ); + /** + * {@snippet : + * IOReturn (*Stop)(void*); + * } + */ public interface Stop { - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(Stop fi, MemorySession session) { - return RuntimeHelper.upcallStub(Stop.class, fi, IOCFPlugInInterfaceStruct.Stop$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(Stop fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(Stop.class, fi, IOCFPlugInInterfaceStruct.Stop$FUNC, scope); } - static Stop ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { + static Stop ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOCFPlugInInterfaceStruct.Stop$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOCFPlugInInterfaceStruct.Stop$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -337,27 +478,39 @@ static Stop ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle Stop$VH() { return IOCFPlugInInterfaceStruct.Stop$VH; } - public static MemoryAddress Stop$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.Stop$VH.get(seg); - } - public static void Stop$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*Stop)(void*); + * } + */ + public static MemorySegment Stop$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.Stop$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*Stop)(void*); + * } + */ + public static void Stop$set(MemorySegment seg, MemorySegment x) { IOCFPlugInInterfaceStruct.Stop$VH.set(seg, x); } - public static MemoryAddress Stop$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOCFPlugInInterfaceStruct.Stop$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment Stop$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.Stop$VH.get(seg.asSlice(index*sizeof())); } - public static void Stop$set(MemorySegment seg, long index, MemoryAddress x) { + public static void Stop$set(MemorySegment seg, long index, MemorySegment x) { IOCFPlugInInterfaceStruct.Stop$VH.set(seg.asSlice(index*sizeof()), x); } - public static Stop Stop (MemorySegment segment, MemorySession session) { - return Stop.ofAddress(Stop$get(segment), session); + public static Stop Stop(MemorySegment segment, SegmentScope scope) { + return Stop.ofAddress(Stop$get(segment), scope); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java index ecfae851..bec09c37 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java @@ -2,8 +2,6 @@ package net.codecrete.usb.macos.gen.iokit; -import java.lang.foreign.Addressable; -import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; @@ -12,15 +10,19 @@ import static java.lang.foreign.ValueLayout.*; public class IOKit { - /* package-private */ IOKit() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + /** + * {@snippet : + * enum .kIOUSBFindInterfaceDontCare = 65535; + * } + */ public static int kIOUSBFindInterfaceDontCare() { return (int)65535L; } @@ -33,10 +35,22 @@ public static int kIOUSBFindInterfaceDontCare() { public static MemorySegment kCFRunLoopDefaultMode$SEGMENT() { return RuntimeHelper.requireNonNull(constants$0.kCFRunLoopDefaultMode$SEGMENT,"kCFRunLoopDefaultMode"); } - public static MemoryAddress kCFRunLoopDefaultMode$get() { - return (java.lang.foreign.MemoryAddress) constants$0.kCFRunLoopDefaultMode$VH.get(RuntimeHelper.requireNonNull(constants$0.kCFRunLoopDefaultMode$SEGMENT, "kCFRunLoopDefaultMode")); - } - public static void kCFRunLoopDefaultMode$set( MemoryAddress x) { + /** + * Getter for variable: + * {@snippet : + * const CFRunLoopMode kCFRunLoopDefaultMode; + * } + */ + public static MemorySegment kCFRunLoopDefaultMode$get() { + return (java.lang.foreign.MemorySegment) constants$0.kCFRunLoopDefaultMode$VH.get(RuntimeHelper.requireNonNull(constants$0.kCFRunLoopDefaultMode$SEGMENT, "kCFRunLoopDefaultMode")); + } + /** + * Setter for variable: + * {@snippet : + * const CFRunLoopMode kCFRunLoopDefaultMode; + * } + */ + public static void kCFRunLoopDefaultMode$set(MemorySegment x) { constants$0.kCFRunLoopDefaultMode$VH.set(RuntimeHelper.requireNonNull(constants$0.kCFRunLoopDefaultMode$SEGMENT, "kCFRunLoopDefaultMode"), x); } public static MemoryLayout kIOMasterPortDefault$LAYOUT() { @@ -48,19 +62,36 @@ public static int kIOUSBFindInterfaceDontCare() { public static MemorySegment kIOMasterPortDefault$SEGMENT() { return RuntimeHelper.requireNonNull(constants$0.kIOMasterPortDefault$SEGMENT,"kIOMasterPortDefault"); } + /** + * Getter for variable: + * {@snippet : + * const mach_port_t kIOMasterPortDefault; + * } + */ public static int kIOMasterPortDefault$get() { return (int) constants$0.kIOMasterPortDefault$VH.get(RuntimeHelper.requireNonNull(constants$0.kIOMasterPortDefault$SEGMENT, "kIOMasterPortDefault")); } - public static void kIOMasterPortDefault$set( int x) { + /** + * Setter for variable: + * {@snippet : + * const mach_port_t kIOMasterPortDefault; + * } + */ + public static void kIOMasterPortDefault$set(int x) { constants$0.kIOMasterPortDefault$VH.set(RuntimeHelper.requireNonNull(constants$0.kIOMasterPortDefault$SEGMENT, "kIOMasterPortDefault"), x); } public static MethodHandle IONotificationPortCreate$MH() { return RuntimeHelper.requireNonNull(constants$0.IONotificationPortCreate$MH,"IONotificationPortCreate"); } - public static MemoryAddress IONotificationPortCreate ( int mainPort) { + /** + * {@snippet : + * IONotificationPortRef IONotificationPortCreate(mach_port_t mainPort); + * } + */ + public static MemorySegment IONotificationPortCreate(int mainPort) { var mh$ = IONotificationPortCreate$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(mainPort); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(mainPort); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -68,10 +99,15 @@ public static MemoryAddress IONotificationPortCreate ( int mainPort) { public static MethodHandle IONotificationPortGetRunLoopSource$MH() { return RuntimeHelper.requireNonNull(constants$0.IONotificationPortGetRunLoopSource$MH,"IONotificationPortGetRunLoopSource"); } - public static MemoryAddress IONotificationPortGetRunLoopSource ( Addressable notify) { + /** + * {@snippet : + * CFRunLoopSourceRef IONotificationPortGetRunLoopSource(IONotificationPortRef notify); + * } + */ + public static MemorySegment IONotificationPortGetRunLoopSource(MemorySegment notify) { var mh$ = IONotificationPortGetRunLoopSource$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(notify); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(notify); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -79,7 +115,12 @@ public static MemoryAddress IONotificationPortGetRunLoopSource ( Addressable not public static MethodHandle IOObjectRelease$MH() { return RuntimeHelper.requireNonNull(constants$0.IOObjectRelease$MH,"IOObjectRelease"); } - public static int IOObjectRelease ( int object) { + /** + * {@snippet : + * kern_return_t IOObjectRelease(io_object_t object); + * } + */ + public static int IOObjectRelease(int object) { var mh$ = IOObjectRelease$MH(); try { return (int)mh$.invokeExact(object); @@ -90,7 +131,12 @@ public static int IOObjectRelease ( int object) { public static MethodHandle IOIteratorNext$MH() { return RuntimeHelper.requireNonNull(constants$0.IOIteratorNext$MH,"IOIteratorNext"); } - public static int IOIteratorNext ( int iterator) { + /** + * {@snippet : + * io_object_t IOIteratorNext(io_iterator_t iterator); + * } + */ + public static int IOIteratorNext(int iterator) { var mh$ = IOIteratorNext$MH(); try { return (int)mh$.invokeExact(iterator); @@ -101,7 +147,12 @@ public static int IOIteratorNext ( int iterator) { public static MethodHandle IOServiceAddMatchingNotification$MH() { return RuntimeHelper.requireNonNull(constants$1.IOServiceAddMatchingNotification$MH,"IOServiceAddMatchingNotification"); } - public static int IOServiceAddMatchingNotification ( Addressable notifyPort, Addressable notificationType, Addressable matching, Addressable callback, Addressable refCon, Addressable notification) { + /** + * {@snippet : + * kern_return_t IOServiceAddMatchingNotification(IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void* refCon, io_iterator_t* notification); + * } + */ + public static int IOServiceAddMatchingNotification(MemorySegment notifyPort, MemorySegment notificationType, MemorySegment matching, MemorySegment callback, MemorySegment refCon, MemorySegment notification) { var mh$ = IOServiceAddMatchingNotification$MH(); try { return (int)mh$.invokeExact(notifyPort, notificationType, matching, callback, refCon, notification); @@ -112,7 +163,12 @@ public static int IOServiceAddMatchingNotification ( Addressable notifyPort, Ad public static MethodHandle IORegistryEntryGetRegistryEntryID$MH() { return RuntimeHelper.requireNonNull(constants$1.IORegistryEntryGetRegistryEntryID$MH,"IORegistryEntryGetRegistryEntryID"); } - public static int IORegistryEntryGetRegistryEntryID ( int entry, Addressable entryID) { + /** + * {@snippet : + * kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t* entryID); + * } + */ + public static int IORegistryEntryGetRegistryEntryID(int entry, MemorySegment entryID) { var mh$ = IORegistryEntryGetRegistryEntryID$MH(); try { return (int)mh$.invokeExact(entry, entryID); @@ -123,10 +179,15 @@ public static int IORegistryEntryGetRegistryEntryID ( int entry, Addressable en public static MethodHandle IORegistryEntryCreateCFProperty$MH() { return RuntimeHelper.requireNonNull(constants$1.IORegistryEntryCreateCFProperty$MH,"IORegistryEntryCreateCFProperty"); } - public static MemoryAddress IORegistryEntryCreateCFProperty ( int entry, Addressable key, Addressable allocator, int options) { + /** + * {@snippet : + * CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options); + * } + */ + public static MemorySegment IORegistryEntryCreateCFProperty(int entry, MemorySegment key, MemorySegment allocator, int options) { var mh$ = IORegistryEntryCreateCFProperty$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(entry, key, allocator, options); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(entry, key, allocator, options); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -134,10 +195,15 @@ public static MemoryAddress IORegistryEntryCreateCFProperty ( int entry, Addres public static MethodHandle IOServiceMatching$MH() { return RuntimeHelper.requireNonNull(constants$1.IOServiceMatching$MH,"IOServiceMatching"); } - public static MemoryAddress IOServiceMatching ( Addressable name) { + /** + * {@snippet : + * CFMutableDictionaryRef IOServiceMatching(char* name); + * } + */ + public static MemorySegment IOServiceMatching(MemorySegment name) { var mh$ = IOServiceMatching$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(name); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(name); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -145,7 +211,12 @@ public static MemoryAddress IOServiceMatching ( Addressable name) { public static MethodHandle IOCreatePlugInInterfaceForService$MH() { return RuntimeHelper.requireNonNull(constants$1.IOCreatePlugInInterfaceForService$MH,"IOCreatePlugInInterfaceForService"); } - public static int IOCreatePlugInInterfaceForService ( int service, Addressable pluginType, Addressable interfaceType, Addressable theInterface, Addressable theScore) { + /** + * {@snippet : + * kern_return_t IOCreatePlugInInterfaceForService(io_service_t service, CFUUIDRef pluginType, CFUUIDRef interfaceType, IOCFPlugInInterface*** theInterface, SInt32* theScore); + * } + */ + public static int IOCreatePlugInInterfaceForService(int service, MemorySegment pluginType, MemorySegment interfaceType, MemorySegment theInterface, MemorySegment theScore) { var mh$ = IOCreatePlugInInterfaceForService$MH(); try { return (int)mh$.invokeExact(service, pluginType, interfaceType, theInterface, theScore); @@ -153,21 +224,51 @@ public static int IOCreatePlugInInterfaceForService ( int service, Addressable throw new AssertionError("should not reach here", ex$); } } + /** + * {@snippet : + * #define kIOReturnAborted -536870165 + * } + */ public static int kIOReturnAborted() { return (int)-536870165L; } + /** + * {@snippet : + * #define kIOUSBPipeStalled -536854449 + * } + */ public static int kIOUSBPipeStalled() { return (int)-536854449L; } + /** + * {@snippet : + * #define kIOUSBTransactionTimeout -536854447 + * } + */ public static int kIOUSBTransactionTimeout() { return (int)-536854447L; } + /** + * {@snippet : + * #define kIOFirstMatchNotification "IOServiceFirstMatch" + * } + */ public static MemorySegment kIOFirstMatchNotification() { return constants$1.kIOFirstMatchNotification$SEGMENT; } + /** + * {@snippet : + * #define kIOTerminatedNotification "IOServiceTerminate" + * } + */ public static MemorySegment kIOTerminatedNotification() { return constants$2.kIOTerminatedNotification$SEGMENT; } + /** + * {@snippet : + * #define kIOUSBDeviceClassName "IOUSBDevice" + * } + */ public static MemorySegment kIOUSBDeviceClassName() { return constants$2.kIOUSBDeviceClassName$SEGMENT; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java index e376cdda..17780c2f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java @@ -4,9 +4,22 @@ import java.lang.foreign.*; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct { + * UInt8 bmRequestType; + * UInt8 bRequest; + * UInt16 wValue; + * UInt16 wIndex; + * UInt16 wLength; + * void* pData; + * UInt32 wLenDone; + * }; + * } + */ public class IOUSBDevRequest { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_CHAR$LAYOUT.withName("bmRequestType"), Constants$root.C_CHAR$LAYOUT.withName("bRequest"), Constants$root.C_SHORT$LAYOUT.withName("wValue"), @@ -23,10 +36,22 @@ public class IOUSBDevRequest { public static VarHandle bmRequestType$VH() { return IOUSBDevRequest.bmRequestType$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 bmRequestType; + * } + */ public static byte bmRequestType$get(MemorySegment seg) { return (byte)IOUSBDevRequest.bmRequestType$VH.get(seg); } - public static void bmRequestType$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 bmRequestType; + * } + */ + public static void bmRequestType$set(MemorySegment seg, byte x) { IOUSBDevRequest.bmRequestType$VH.set(seg, x); } public static byte bmRequestType$get(MemorySegment seg, long index) { @@ -39,10 +64,22 @@ public class IOUSBDevRequest { public static VarHandle bRequest$VH() { return IOUSBDevRequest.bRequest$VH; } + /** + * Getter for field: + * {@snippet : + * UInt8 bRequest; + * } + */ public static byte bRequest$get(MemorySegment seg) { return (byte)IOUSBDevRequest.bRequest$VH.get(seg); } - public static void bRequest$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * UInt8 bRequest; + * } + */ + public static void bRequest$set(MemorySegment seg, byte x) { IOUSBDevRequest.bRequest$VH.set(seg, x); } public static byte bRequest$get(MemorySegment seg, long index) { @@ -55,10 +92,22 @@ public class IOUSBDevRequest { public static VarHandle wValue$VH() { return IOUSBDevRequest.wValue$VH; } + /** + * Getter for field: + * {@snippet : + * UInt16 wValue; + * } + */ public static short wValue$get(MemorySegment seg) { return (short)IOUSBDevRequest.wValue$VH.get(seg); } - public static void wValue$set( MemorySegment seg, short x) { + /** + * Setter for field: + * {@snippet : + * UInt16 wValue; + * } + */ + public static void wValue$set(MemorySegment seg, short x) { IOUSBDevRequest.wValue$VH.set(seg, x); } public static short wValue$get(MemorySegment seg, long index) { @@ -71,10 +120,22 @@ public class IOUSBDevRequest { public static VarHandle wIndex$VH() { return IOUSBDevRequest.wIndex$VH; } + /** + * Getter for field: + * {@snippet : + * UInt16 wIndex; + * } + */ public static short wIndex$get(MemorySegment seg) { return (short)IOUSBDevRequest.wIndex$VH.get(seg); } - public static void wIndex$set( MemorySegment seg, short x) { + /** + * Setter for field: + * {@snippet : + * UInt16 wIndex; + * } + */ + public static void wIndex$set(MemorySegment seg, short x) { IOUSBDevRequest.wIndex$VH.set(seg, x); } public static short wIndex$get(MemorySegment seg, long index) { @@ -87,10 +148,22 @@ public class IOUSBDevRequest { public static VarHandle wLength$VH() { return IOUSBDevRequest.wLength$VH; } + /** + * Getter for field: + * {@snippet : + * UInt16 wLength; + * } + */ public static short wLength$get(MemorySegment seg) { return (short)IOUSBDevRequest.wLength$VH.get(seg); } - public static void wLength$set( MemorySegment seg, short x) { + /** + * Setter for field: + * {@snippet : + * UInt16 wLength; + * } + */ + public static void wLength$set(MemorySegment seg, short x) { IOUSBDevRequest.wLength$VH.set(seg, x); } public static short wLength$get(MemorySegment seg, long index) { @@ -103,26 +176,50 @@ public class IOUSBDevRequest { public static VarHandle pData$VH() { return IOUSBDevRequest.pData$VH; } - public static MemoryAddress pData$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDevRequest.pData$VH.get(seg); - } - public static void pData$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * void* pData; + * } + */ + public static MemorySegment pData$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDevRequest.pData$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * void* pData; + * } + */ + public static void pData$set(MemorySegment seg, MemorySegment x) { IOUSBDevRequest.pData$VH.set(seg, x); } - public static MemoryAddress pData$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDevRequest.pData$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment pData$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDevRequest.pData$VH.get(seg.asSlice(index*sizeof())); } - public static void pData$set(MemorySegment seg, long index, MemoryAddress x) { + public static void pData$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDevRequest.pData$VH.set(seg.asSlice(index*sizeof()), x); } static final VarHandle wLenDone$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("wLenDone")); public static VarHandle wLenDone$VH() { return IOUSBDevRequest.wLenDone$VH; } + /** + * Getter for field: + * {@snippet : + * UInt32 wLenDone; + * } + */ public static int wLenDone$get(MemorySegment seg) { return (int)IOUSBDevRequest.wLenDone$VH.get(seg); } - public static void wLenDone$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * UInt32 wLenDone; + * } + */ + public static void wLenDone$set(MemorySegment seg, int x) { IOUSBDevRequest.wLenDone$VH.set(seg, x); } public static int wLenDone$get(MemorySegment seg, long index) { @@ -133,10 +230,10 @@ public class IOUSBDevRequest { } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface100.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface100.java index 0944f0ea..c1618c86 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface100.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface100.java @@ -2,8 +2,15 @@ package net.codecrete.usb.macos.gen.iokit; -public class IOUSBDeviceInterface100 extends IOUSBDeviceStruct100 { +/** + * {@snippet : + * typedef struct IOUSBDeviceStruct100 IOUSBDeviceInterface100; + * } + */ +public final class IOUSBDeviceInterface100 extends IOUSBDeviceStruct100 { + // Suppresses default constructor, ensuring non-instantiability. + private IOUSBDeviceInterface100() {} } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct100.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct100.java index e02bbfb7..d3a40366 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct100.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct100.java @@ -5,9 +5,44 @@ import java.lang.foreign.*; import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct IOUSBDeviceStruct100 { + * void* _reserved; + * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * ULONG (*AddRef)(void*); + * ULONG (*Release)(void*); + * IOReturn (*CreateDeviceAsyncEventSource)(void*,CFRunLoopSourceRef*); + * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void*); + * IOReturn (*CreateDeviceAsyncPort)(void*,mach_port_t*); + * mach_port_t (*GetDeviceAsyncPort)(void*); + * IOReturn (*USBDeviceOpen)(void*); + * IOReturn (*USBDeviceClose)(void*); + * IOReturn (*GetDeviceClass)(void*,UInt8*); + * IOReturn (*GetDeviceSubClass)(void*,UInt8*); + * IOReturn (*GetDeviceProtocol)(void*,UInt8*); + * IOReturn (*GetDeviceVendor)(void*,UInt16*); + * IOReturn (*GetDeviceProduct)(void*,UInt16*); + * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); + * IOReturn (*GetDeviceAddress)(void*,USBDeviceAddress*); + * IOReturn (*GetDeviceBusPowerAvailable)(void*,UInt32*); + * IOReturn (*GetDeviceSpeed)(void*,UInt8*); + * IOReturn (*GetNumberOfConfigurations)(void*,UInt8*); + * IOReturn (*GetLocationID)(void*,UInt32*); + * IOReturn (*GetConfigurationDescriptorPtr)(void*,UInt8,IOUSBConfigurationDescriptorPtr*); + * IOReturn (*GetConfiguration)(void*,UInt8*); + * IOReturn (*SetConfiguration)(void*,UInt8); + * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); + * IOReturn (*ResetDevice)(void*); + * IOReturn (*DeviceRequest)(void*,IOUSBDevRequest*); + * IOReturn (*DeviceRequestAsync)(void*,IOUSBDevRequest*,IOAsyncCallback1,void*); + * IOReturn (*CreateInterfaceIterator)(void*,IOUSBFindInterfaceRequest*,io_iterator_t*); + * }; + * } + */ public class IOUSBDeviceStruct100 { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_POINTER$LAYOUT.withName("_reserved"), Constants$root.C_POINTER$LAYOUT.withName("QueryInterface"), Constants$root.C_POINTER$LAYOUT.withName("AddRef"), @@ -45,16 +80,28 @@ public class IOUSBDeviceStruct100 { public static VarHandle _reserved$VH() { return IOUSBDeviceStruct100._reserved$VH; } - public static MemoryAddress _reserved$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100._reserved$VH.get(seg); - } - public static void _reserved$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * void* _reserved; + * } + */ + public static MemorySegment _reserved$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100._reserved$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * void* _reserved; + * } + */ + public static void _reserved$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100._reserved$VH.set(seg, x); } - public static MemoryAddress _reserved$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100._reserved$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment _reserved$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100._reserved$VH.get(seg.asSlice(index*sizeof())); } - public static void _reserved$set(MemorySegment seg, long index, MemoryAddress x) { + public static void _reserved$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100._reserved$VH.set(seg.asSlice(index*sizeof()), x); } static final FunctionDescriptor QueryInterface$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, @@ -82,17 +129,22 @@ public class IOUSBDeviceStruct100 { static final MethodHandle QueryInterface$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.QueryInterface$FUNC ); + /** + * {@snippet : + * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * } + */ public interface QueryInterface { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(QueryInterface fi, MemorySession session) { - return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOUSBDeviceStruct100.QueryInterface$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); + static MemorySegment allocate(QueryInterface fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOUSBDeviceStruct100.QueryInterface$FUNC, scope); } - static QueryInterface ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemoryAddress __x2) -> { + static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBDeviceStruct100.QueryInterface$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + return (int)IOUSBDeviceStruct100.QueryInterface$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -104,20 +156,32 @@ static QueryInterface ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle QueryInterface$VH() { return IOUSBDeviceStruct100.QueryInterface$VH; } - public static MemoryAddress QueryInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.QueryInterface$VH.get(seg); - } - public static void QueryInterface$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * } + */ + public static MemorySegment QueryInterface$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.QueryInterface$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * } + */ + public static void QueryInterface$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.QueryInterface$VH.set(seg, x); } - public static MemoryAddress QueryInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.QueryInterface$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment QueryInterface$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.QueryInterface$VH.get(seg.asSlice(index*sizeof())); } - public static void QueryInterface$set(MemorySegment seg, long index, MemoryAddress x) { + public static void QueryInterface$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.QueryInterface$VH.set(seg.asSlice(index*sizeof()), x); } - public static QueryInterface QueryInterface (MemorySegment segment, MemorySession session) { - return QueryInterface.ofAddress(QueryInterface$get(segment), session); + public static QueryInterface QueryInterface(MemorySegment segment, SegmentScope scope) { + return QueryInterface.ofAddress(QueryInterface$get(segment), scope); } static final FunctionDescriptor AddRef$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -125,17 +189,22 @@ public static QueryInterface QueryInterface (MemorySegment segment, MemorySessio static final MethodHandle AddRef$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.AddRef$FUNC ); + /** + * {@snippet : + * ULONG (*AddRef)(void*); + * } + */ public interface AddRef { - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(AddRef fi, MemorySession session) { - return RuntimeHelper.upcallStub(AddRef.class, fi, IOUSBDeviceStruct100.AddRef$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(AddRef fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(AddRef.class, fi, IOUSBDeviceStruct100.AddRef$FUNC, scope); } - static AddRef ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { + static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct100.AddRef$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBDeviceStruct100.AddRef$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -147,20 +216,32 @@ static AddRef ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle AddRef$VH() { return IOUSBDeviceStruct100.AddRef$VH; } - public static MemoryAddress AddRef$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.AddRef$VH.get(seg); - } - public static void AddRef$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * ULONG (*AddRef)(void*); + * } + */ + public static MemorySegment AddRef$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.AddRef$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * ULONG (*AddRef)(void*); + * } + */ + public static void AddRef$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.AddRef$VH.set(seg, x); } - public static MemoryAddress AddRef$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.AddRef$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment AddRef$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.AddRef$VH.get(seg.asSlice(index*sizeof())); } - public static void AddRef$set(MemorySegment seg, long index, MemoryAddress x) { + public static void AddRef$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.AddRef$VH.set(seg.asSlice(index*sizeof()), x); } - public static AddRef AddRef (MemorySegment segment, MemorySession session) { - return AddRef.ofAddress(AddRef$get(segment), session); + public static AddRef AddRef(MemorySegment segment, SegmentScope scope) { + return AddRef.ofAddress(AddRef$get(segment), scope); } static final FunctionDescriptor Release$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -168,17 +249,22 @@ public static AddRef AddRef (MemorySegment segment, MemorySession session) { static final MethodHandle Release$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.Release$FUNC ); + /** + * {@snippet : + * ULONG (*Release)(void*); + * } + */ public interface Release { - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(Release fi, MemorySession session) { - return RuntimeHelper.upcallStub(Release.class, fi, IOUSBDeviceStruct100.Release$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(Release fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(Release.class, fi, IOUSBDeviceStruct100.Release$FUNC, scope); } - static Release ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { + static Release ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct100.Release$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBDeviceStruct100.Release$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -190,20 +276,32 @@ static Release ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle Release$VH() { return IOUSBDeviceStruct100.Release$VH; } - public static MemoryAddress Release$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.Release$VH.get(seg); - } - public static void Release$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * ULONG (*Release)(void*); + * } + */ + public static MemorySegment Release$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.Release$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * ULONG (*Release)(void*); + * } + */ + public static void Release$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.Release$VH.set(seg, x); } - public static MemoryAddress Release$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.Release$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment Release$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.Release$VH.get(seg.asSlice(index*sizeof())); } - public static void Release$set(MemorySegment seg, long index, MemoryAddress x) { + public static void Release$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.Release$VH.set(seg.asSlice(index*sizeof()), x); } - public static Release Release (MemorySegment segment, MemorySession session) { - return Release.ofAddress(Release$get(segment), session); + public static Release Release(MemorySegment segment, SegmentScope scope) { + return Release.ofAddress(Release$get(segment), scope); } static final FunctionDescriptor CreateDeviceAsyncEventSource$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -212,17 +310,22 @@ public static Release Release (MemorySegment segment, MemorySession session) { static final MethodHandle CreateDeviceAsyncEventSource$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$FUNC ); + /** + * {@snippet : + * IOReturn (*CreateDeviceAsyncEventSource)(void*,CFRunLoopSourceRef*); + * } + */ public interface CreateDeviceAsyncEventSource { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(CreateDeviceAsyncEventSource fi, MemorySession session) { - return RuntimeHelper.upcallStub(CreateDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(CreateDeviceAsyncEventSource fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(CreateDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$FUNC, scope); } - static CreateDeviceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static CreateDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -234,20 +337,32 @@ static CreateDeviceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession public static VarHandle CreateDeviceAsyncEventSource$VH() { return IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$VH; } - public static MemoryAddress CreateDeviceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$VH.get(seg); - } - public static void CreateDeviceAsyncEventSource$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*CreateDeviceAsyncEventSource)(void*,CFRunLoopSourceRef*); + * } + */ + public static MemorySegment CreateDeviceAsyncEventSource$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*CreateDeviceAsyncEventSource)(void*,CFRunLoopSourceRef*); + * } + */ + public static void CreateDeviceAsyncEventSource$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$VH.set(seg, x); } - public static MemoryAddress CreateDeviceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment CreateDeviceAsyncEventSource$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); } - public static void CreateDeviceAsyncEventSource$set(MemorySegment seg, long index, MemoryAddress x) { + public static void CreateDeviceAsyncEventSource$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); } - public static CreateDeviceAsyncEventSource CreateDeviceAsyncEventSource (MemorySegment segment, MemorySession session) { - return CreateDeviceAsyncEventSource.ofAddress(CreateDeviceAsyncEventSource$get(segment), session); + public static CreateDeviceAsyncEventSource CreateDeviceAsyncEventSource(MemorySegment segment, SegmentScope scope) { + return CreateDeviceAsyncEventSource.ofAddress(CreateDeviceAsyncEventSource$get(segment), scope); } static final FunctionDescriptor GetDeviceAsyncEventSource$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -255,17 +370,22 @@ public static CreateDeviceAsyncEventSource CreateDeviceAsyncEventSource (MemoryS static final MethodHandle GetDeviceAsyncEventSource$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.GetDeviceAsyncEventSource$FUNC ); + /** + * {@snippet : + * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void*); + * } + */ public interface GetDeviceAsyncEventSource { - java.lang.foreign.Addressable apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(GetDeviceAsyncEventSource fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct100.GetDeviceAsyncEventSource$FUNC, session); + java.lang.foreign.MemorySegment apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(GetDeviceAsyncEventSource fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct100.GetDeviceAsyncEventSource$FUNC, scope); } - static GetDeviceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { + static GetDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { try { - return (java.lang.foreign.Addressable)(java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceAsyncEventSource$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceAsyncEventSource$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -277,20 +397,32 @@ static GetDeviceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession ses public static VarHandle GetDeviceAsyncEventSource$VH() { return IOUSBDeviceStruct100.GetDeviceAsyncEventSource$VH; } - public static MemoryAddress GetDeviceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceAsyncEventSource$VH.get(seg); - } - public static void GetDeviceAsyncEventSource$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void*); + * } + */ + public static MemorySegment GetDeviceAsyncEventSource$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceAsyncEventSource$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void*); + * } + */ + public static void GetDeviceAsyncEventSource$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceAsyncEventSource$VH.set(seg, x); } - public static MemoryAddress GetDeviceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetDeviceAsyncEventSource$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); } - public static void GetDeviceAsyncEventSource$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetDeviceAsyncEventSource$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceAsyncEventSource GetDeviceAsyncEventSource (MemorySegment segment, MemorySession session) { - return GetDeviceAsyncEventSource.ofAddress(GetDeviceAsyncEventSource$get(segment), session); + public static GetDeviceAsyncEventSource GetDeviceAsyncEventSource(MemorySegment segment, SegmentScope scope) { + return GetDeviceAsyncEventSource.ofAddress(GetDeviceAsyncEventSource$get(segment), scope); } static final FunctionDescriptor CreateDeviceAsyncPort$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -299,17 +431,22 @@ public static GetDeviceAsyncEventSource GetDeviceAsyncEventSource (MemorySegment static final MethodHandle CreateDeviceAsyncPort$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.CreateDeviceAsyncPort$FUNC ); + /** + * {@snippet : + * IOReturn (*CreateDeviceAsyncPort)(void*,mach_port_t*); + * } + */ public interface CreateDeviceAsyncPort { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(CreateDeviceAsyncPort fi, MemorySession session) { - return RuntimeHelper.upcallStub(CreateDeviceAsyncPort.class, fi, IOUSBDeviceStruct100.CreateDeviceAsyncPort$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(CreateDeviceAsyncPort fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(CreateDeviceAsyncPort.class, fi, IOUSBDeviceStruct100.CreateDeviceAsyncPort$FUNC, scope); } - static CreateDeviceAsyncPort ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static CreateDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.CreateDeviceAsyncPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBDeviceStruct100.CreateDeviceAsyncPort$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -321,20 +458,32 @@ static CreateDeviceAsyncPort ofAddress(MemoryAddress addr, MemorySession session public static VarHandle CreateDeviceAsyncPort$VH() { return IOUSBDeviceStruct100.CreateDeviceAsyncPort$VH; } - public static MemoryAddress CreateDeviceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.CreateDeviceAsyncPort$VH.get(seg); - } - public static void CreateDeviceAsyncPort$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*CreateDeviceAsyncPort)(void*,mach_port_t*); + * } + */ + public static MemorySegment CreateDeviceAsyncPort$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.CreateDeviceAsyncPort$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*CreateDeviceAsyncPort)(void*,mach_port_t*); + * } + */ + public static void CreateDeviceAsyncPort$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.CreateDeviceAsyncPort$VH.set(seg, x); } - public static MemoryAddress CreateDeviceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.CreateDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment CreateDeviceAsyncPort$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.CreateDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); } - public static void CreateDeviceAsyncPort$set(MemorySegment seg, long index, MemoryAddress x) { + public static void CreateDeviceAsyncPort$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.CreateDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); } - public static CreateDeviceAsyncPort CreateDeviceAsyncPort (MemorySegment segment, MemorySession session) { - return CreateDeviceAsyncPort.ofAddress(CreateDeviceAsyncPort$get(segment), session); + public static CreateDeviceAsyncPort CreateDeviceAsyncPort(MemorySegment segment, SegmentScope scope) { + return CreateDeviceAsyncPort.ofAddress(CreateDeviceAsyncPort$get(segment), scope); } static final FunctionDescriptor GetDeviceAsyncPort$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -342,17 +491,22 @@ public static CreateDeviceAsyncPort CreateDeviceAsyncPort (MemorySegment segment static final MethodHandle GetDeviceAsyncPort$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.GetDeviceAsyncPort$FUNC ); + /** + * {@snippet : + * mach_port_t (*GetDeviceAsyncPort)(void*); + * } + */ public interface GetDeviceAsyncPort { - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(GetDeviceAsyncPort fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceAsyncPort.class, fi, IOUSBDeviceStruct100.GetDeviceAsyncPort$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(GetDeviceAsyncPort fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetDeviceAsyncPort.class, fi, IOUSBDeviceStruct100.GetDeviceAsyncPort$FUNC, scope); } - static GetDeviceAsyncPort ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { + static GetDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceAsyncPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBDeviceStruct100.GetDeviceAsyncPort$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -364,20 +518,32 @@ static GetDeviceAsyncPort ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetDeviceAsyncPort$VH() { return IOUSBDeviceStruct100.GetDeviceAsyncPort$VH; } - public static MemoryAddress GetDeviceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceAsyncPort$VH.get(seg); - } - public static void GetDeviceAsyncPort$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * mach_port_t (*GetDeviceAsyncPort)(void*); + * } + */ + public static MemorySegment GetDeviceAsyncPort$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceAsyncPort$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * mach_port_t (*GetDeviceAsyncPort)(void*); + * } + */ + public static void GetDeviceAsyncPort$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceAsyncPort$VH.set(seg, x); } - public static MemoryAddress GetDeviceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetDeviceAsyncPort$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); } - public static void GetDeviceAsyncPort$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetDeviceAsyncPort$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceAsyncPort GetDeviceAsyncPort (MemorySegment segment, MemorySession session) { - return GetDeviceAsyncPort.ofAddress(GetDeviceAsyncPort$get(segment), session); + public static GetDeviceAsyncPort GetDeviceAsyncPort(MemorySegment segment, SegmentScope scope) { + return GetDeviceAsyncPort.ofAddress(GetDeviceAsyncPort$get(segment), scope); } static final FunctionDescriptor USBDeviceOpen$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -385,17 +551,22 @@ public static GetDeviceAsyncPort GetDeviceAsyncPort (MemorySegment segment, Memo static final MethodHandle USBDeviceOpen$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.USBDeviceOpen$FUNC ); + /** + * {@snippet : + * IOReturn (*USBDeviceOpen)(void*); + * } + */ public interface USBDeviceOpen { - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(USBDeviceOpen fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBDeviceOpen.class, fi, IOUSBDeviceStruct100.USBDeviceOpen$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(USBDeviceOpen fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(USBDeviceOpen.class, fi, IOUSBDeviceStruct100.USBDeviceOpen$FUNC, scope); } - static USBDeviceOpen ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { + static USBDeviceOpen ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct100.USBDeviceOpen$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBDeviceStruct100.USBDeviceOpen$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -407,20 +578,32 @@ static USBDeviceOpen ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle USBDeviceOpen$VH() { return IOUSBDeviceStruct100.USBDeviceOpen$VH; } - public static MemoryAddress USBDeviceOpen$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.USBDeviceOpen$VH.get(seg); - } - public static void USBDeviceOpen$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*USBDeviceOpen)(void*); + * } + */ + public static MemorySegment USBDeviceOpen$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.USBDeviceOpen$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*USBDeviceOpen)(void*); + * } + */ + public static void USBDeviceOpen$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.USBDeviceOpen$VH.set(seg, x); } - public static MemoryAddress USBDeviceOpen$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.USBDeviceOpen$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment USBDeviceOpen$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.USBDeviceOpen$VH.get(seg.asSlice(index*sizeof())); } - public static void USBDeviceOpen$set(MemorySegment seg, long index, MemoryAddress x) { + public static void USBDeviceOpen$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.USBDeviceOpen$VH.set(seg.asSlice(index*sizeof()), x); } - public static USBDeviceOpen USBDeviceOpen (MemorySegment segment, MemorySession session) { - return USBDeviceOpen.ofAddress(USBDeviceOpen$get(segment), session); + public static USBDeviceOpen USBDeviceOpen(MemorySegment segment, SegmentScope scope) { + return USBDeviceOpen.ofAddress(USBDeviceOpen$get(segment), scope); } static final FunctionDescriptor USBDeviceClose$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -428,17 +611,22 @@ public static USBDeviceOpen USBDeviceOpen (MemorySegment segment, MemorySession static final MethodHandle USBDeviceClose$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.USBDeviceClose$FUNC ); + /** + * {@snippet : + * IOReturn (*USBDeviceClose)(void*); + * } + */ public interface USBDeviceClose { - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(USBDeviceClose fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBDeviceClose.class, fi, IOUSBDeviceStruct100.USBDeviceClose$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(USBDeviceClose fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(USBDeviceClose.class, fi, IOUSBDeviceStruct100.USBDeviceClose$FUNC, scope); } - static USBDeviceClose ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { + static USBDeviceClose ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct100.USBDeviceClose$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBDeviceStruct100.USBDeviceClose$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -450,20 +638,32 @@ static USBDeviceClose ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle USBDeviceClose$VH() { return IOUSBDeviceStruct100.USBDeviceClose$VH; } - public static MemoryAddress USBDeviceClose$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.USBDeviceClose$VH.get(seg); - } - public static void USBDeviceClose$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*USBDeviceClose)(void*); + * } + */ + public static MemorySegment USBDeviceClose$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.USBDeviceClose$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*USBDeviceClose)(void*); + * } + */ + public static void USBDeviceClose$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.USBDeviceClose$VH.set(seg, x); } - public static MemoryAddress USBDeviceClose$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.USBDeviceClose$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment USBDeviceClose$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.USBDeviceClose$VH.get(seg.asSlice(index*sizeof())); } - public static void USBDeviceClose$set(MemorySegment seg, long index, MemoryAddress x) { + public static void USBDeviceClose$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.USBDeviceClose$VH.set(seg.asSlice(index*sizeof()), x); } - public static USBDeviceClose USBDeviceClose (MemorySegment segment, MemorySession session) { - return USBDeviceClose.ofAddress(USBDeviceClose$get(segment), session); + public static USBDeviceClose USBDeviceClose(MemorySegment segment, SegmentScope scope) { + return USBDeviceClose.ofAddress(USBDeviceClose$get(segment), scope); } static final FunctionDescriptor GetDeviceClass$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -472,17 +672,22 @@ public static USBDeviceClose USBDeviceClose (MemorySegment segment, MemorySessio static final MethodHandle GetDeviceClass$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.GetDeviceClass$FUNC ); + /** + * {@snippet : + * IOReturn (*GetDeviceClass)(void*,UInt8*); + * } + */ public interface GetDeviceClass { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceClass fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceClass.class, fi, IOUSBDeviceStruct100.GetDeviceClass$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetDeviceClass fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetDeviceClass.class, fi, IOUSBDeviceStruct100.GetDeviceClass$FUNC, scope); } - static GetDeviceClass ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetDeviceClass ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceClass$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBDeviceStruct100.GetDeviceClass$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -494,20 +699,32 @@ static GetDeviceClass ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetDeviceClass$VH() { return IOUSBDeviceStruct100.GetDeviceClass$VH; } - public static MemoryAddress GetDeviceClass$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceClass$VH.get(seg); - } - public static void GetDeviceClass$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetDeviceClass)(void*,UInt8*); + * } + */ + public static MemorySegment GetDeviceClass$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceClass$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetDeviceClass)(void*,UInt8*); + * } + */ + public static void GetDeviceClass$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceClass$VH.set(seg, x); } - public static MemoryAddress GetDeviceClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceClass$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetDeviceClass$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceClass$VH.get(seg.asSlice(index*sizeof())); } - public static void GetDeviceClass$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetDeviceClass$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceClass$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceClass GetDeviceClass (MemorySegment segment, MemorySession session) { - return GetDeviceClass.ofAddress(GetDeviceClass$get(segment), session); + public static GetDeviceClass GetDeviceClass(MemorySegment segment, SegmentScope scope) { + return GetDeviceClass.ofAddress(GetDeviceClass$get(segment), scope); } static final FunctionDescriptor GetDeviceSubClass$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -516,17 +733,22 @@ public static GetDeviceClass GetDeviceClass (MemorySegment segment, MemorySessio static final MethodHandle GetDeviceSubClass$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.GetDeviceSubClass$FUNC ); + /** + * {@snippet : + * IOReturn (*GetDeviceSubClass)(void*,UInt8*); + * } + */ public interface GetDeviceSubClass { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceSubClass fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceSubClass.class, fi, IOUSBDeviceStruct100.GetDeviceSubClass$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetDeviceSubClass fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetDeviceSubClass.class, fi, IOUSBDeviceStruct100.GetDeviceSubClass$FUNC, scope); } - static GetDeviceSubClass ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetDeviceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceSubClass$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBDeviceStruct100.GetDeviceSubClass$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -538,20 +760,32 @@ static GetDeviceSubClass ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetDeviceSubClass$VH() { return IOUSBDeviceStruct100.GetDeviceSubClass$VH; } - public static MemoryAddress GetDeviceSubClass$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceSubClass$VH.get(seg); - } - public static void GetDeviceSubClass$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetDeviceSubClass)(void*,UInt8*); + * } + */ + public static MemorySegment GetDeviceSubClass$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceSubClass$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetDeviceSubClass)(void*,UInt8*); + * } + */ + public static void GetDeviceSubClass$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceSubClass$VH.set(seg, x); } - public static MemoryAddress GetDeviceSubClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceSubClass$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetDeviceSubClass$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceSubClass$VH.get(seg.asSlice(index*sizeof())); } - public static void GetDeviceSubClass$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetDeviceSubClass$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceSubClass$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceSubClass GetDeviceSubClass (MemorySegment segment, MemorySession session) { - return GetDeviceSubClass.ofAddress(GetDeviceSubClass$get(segment), session); + public static GetDeviceSubClass GetDeviceSubClass(MemorySegment segment, SegmentScope scope) { + return GetDeviceSubClass.ofAddress(GetDeviceSubClass$get(segment), scope); } static final FunctionDescriptor GetDeviceProtocol$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -560,17 +794,22 @@ public static GetDeviceSubClass GetDeviceSubClass (MemorySegment segment, Memory static final MethodHandle GetDeviceProtocol$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.GetDeviceProtocol$FUNC ); + /** + * {@snippet : + * IOReturn (*GetDeviceProtocol)(void*,UInt8*); + * } + */ public interface GetDeviceProtocol { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceProtocol fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceProtocol.class, fi, IOUSBDeviceStruct100.GetDeviceProtocol$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetDeviceProtocol fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetDeviceProtocol.class, fi, IOUSBDeviceStruct100.GetDeviceProtocol$FUNC, scope); } - static GetDeviceProtocol ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetDeviceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceProtocol$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBDeviceStruct100.GetDeviceProtocol$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -582,20 +821,32 @@ static GetDeviceProtocol ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetDeviceProtocol$VH() { return IOUSBDeviceStruct100.GetDeviceProtocol$VH; } - public static MemoryAddress GetDeviceProtocol$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceProtocol$VH.get(seg); - } - public static void GetDeviceProtocol$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetDeviceProtocol)(void*,UInt8*); + * } + */ + public static MemorySegment GetDeviceProtocol$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceProtocol$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetDeviceProtocol)(void*,UInt8*); + * } + */ + public static void GetDeviceProtocol$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceProtocol$VH.set(seg, x); } - public static MemoryAddress GetDeviceProtocol$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceProtocol$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetDeviceProtocol$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceProtocol$VH.get(seg.asSlice(index*sizeof())); } - public static void GetDeviceProtocol$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetDeviceProtocol$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceProtocol$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceProtocol GetDeviceProtocol (MemorySegment segment, MemorySession session) { - return GetDeviceProtocol.ofAddress(GetDeviceProtocol$get(segment), session); + public static GetDeviceProtocol GetDeviceProtocol(MemorySegment segment, SegmentScope scope) { + return GetDeviceProtocol.ofAddress(GetDeviceProtocol$get(segment), scope); } static final FunctionDescriptor GetDeviceVendor$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -604,17 +855,22 @@ public static GetDeviceProtocol GetDeviceProtocol (MemorySegment segment, Memory static final MethodHandle GetDeviceVendor$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.GetDeviceVendor$FUNC ); + /** + * {@snippet : + * IOReturn (*GetDeviceVendor)(void*,UInt16*); + * } + */ public interface GetDeviceVendor { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceVendor fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceVendor.class, fi, IOUSBDeviceStruct100.GetDeviceVendor$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetDeviceVendor fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetDeviceVendor.class, fi, IOUSBDeviceStruct100.GetDeviceVendor$FUNC, scope); } - static GetDeviceVendor ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceVendor$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBDeviceStruct100.GetDeviceVendor$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -626,20 +882,32 @@ static GetDeviceVendor ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetDeviceVendor$VH() { return IOUSBDeviceStruct100.GetDeviceVendor$VH; } - public static MemoryAddress GetDeviceVendor$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceVendor$VH.get(seg); - } - public static void GetDeviceVendor$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetDeviceVendor)(void*,UInt16*); + * } + */ + public static MemorySegment GetDeviceVendor$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceVendor$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetDeviceVendor)(void*,UInt16*); + * } + */ + public static void GetDeviceVendor$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceVendor$VH.set(seg, x); } - public static MemoryAddress GetDeviceVendor$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceVendor$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetDeviceVendor$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceVendor$VH.get(seg.asSlice(index*sizeof())); } - public static void GetDeviceVendor$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetDeviceVendor$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceVendor$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceVendor GetDeviceVendor (MemorySegment segment, MemorySession session) { - return GetDeviceVendor.ofAddress(GetDeviceVendor$get(segment), session); + public static GetDeviceVendor GetDeviceVendor(MemorySegment segment, SegmentScope scope) { + return GetDeviceVendor.ofAddress(GetDeviceVendor$get(segment), scope); } static final FunctionDescriptor GetDeviceProduct$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -648,17 +916,22 @@ public static GetDeviceVendor GetDeviceVendor (MemorySegment segment, MemorySess static final MethodHandle GetDeviceProduct$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.GetDeviceProduct$FUNC ); + /** + * {@snippet : + * IOReturn (*GetDeviceProduct)(void*,UInt16*); + * } + */ public interface GetDeviceProduct { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceProduct fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceProduct.class, fi, IOUSBDeviceStruct100.GetDeviceProduct$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetDeviceProduct fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetDeviceProduct.class, fi, IOUSBDeviceStruct100.GetDeviceProduct$FUNC, scope); } - static GetDeviceProduct ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceProduct$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBDeviceStruct100.GetDeviceProduct$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -670,20 +943,32 @@ static GetDeviceProduct ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetDeviceProduct$VH() { return IOUSBDeviceStruct100.GetDeviceProduct$VH; } - public static MemoryAddress GetDeviceProduct$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceProduct$VH.get(seg); - } - public static void GetDeviceProduct$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetDeviceProduct)(void*,UInt16*); + * } + */ + public static MemorySegment GetDeviceProduct$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceProduct$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetDeviceProduct)(void*,UInt16*); + * } + */ + public static void GetDeviceProduct$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceProduct$VH.set(seg, x); } - public static MemoryAddress GetDeviceProduct$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceProduct$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetDeviceProduct$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceProduct$VH.get(seg.asSlice(index*sizeof())); } - public static void GetDeviceProduct$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetDeviceProduct$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceProduct$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceProduct GetDeviceProduct (MemorySegment segment, MemorySession session) { - return GetDeviceProduct.ofAddress(GetDeviceProduct$get(segment), session); + public static GetDeviceProduct GetDeviceProduct(MemorySegment segment, SegmentScope scope) { + return GetDeviceProduct.ofAddress(GetDeviceProduct$get(segment), scope); } static final FunctionDescriptor GetDeviceReleaseNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -692,17 +977,22 @@ public static GetDeviceProduct GetDeviceProduct (MemorySegment segment, MemorySe static final MethodHandle GetDeviceReleaseNumber$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.GetDeviceReleaseNumber$FUNC ); + /** + * {@snippet : + * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); + * } + */ public interface GetDeviceReleaseNumber { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceReleaseNumber fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceReleaseNumber.class, fi, IOUSBDeviceStruct100.GetDeviceReleaseNumber$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetDeviceReleaseNumber fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetDeviceReleaseNumber.class, fi, IOUSBDeviceStruct100.GetDeviceReleaseNumber$FUNC, scope); } - static GetDeviceReleaseNumber ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceReleaseNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBDeviceStruct100.GetDeviceReleaseNumber$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -714,20 +1004,32 @@ static GetDeviceReleaseNumber ofAddress(MemoryAddress addr, MemorySession sessio public static VarHandle GetDeviceReleaseNumber$VH() { return IOUSBDeviceStruct100.GetDeviceReleaseNumber$VH; } - public static MemoryAddress GetDeviceReleaseNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceReleaseNumber$VH.get(seg); - } - public static void GetDeviceReleaseNumber$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); + * } + */ + public static MemorySegment GetDeviceReleaseNumber$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceReleaseNumber$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); + * } + */ + public static void GetDeviceReleaseNumber$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceReleaseNumber$VH.set(seg, x); } - public static MemoryAddress GetDeviceReleaseNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceReleaseNumber$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetDeviceReleaseNumber$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceReleaseNumber$VH.get(seg.asSlice(index*sizeof())); } - public static void GetDeviceReleaseNumber$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetDeviceReleaseNumber$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceReleaseNumber$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceReleaseNumber GetDeviceReleaseNumber (MemorySegment segment, MemorySession session) { - return GetDeviceReleaseNumber.ofAddress(GetDeviceReleaseNumber$get(segment), session); + public static GetDeviceReleaseNumber GetDeviceReleaseNumber(MemorySegment segment, SegmentScope scope) { + return GetDeviceReleaseNumber.ofAddress(GetDeviceReleaseNumber$get(segment), scope); } static final FunctionDescriptor GetDeviceAddress$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -736,17 +1038,22 @@ public static GetDeviceReleaseNumber GetDeviceReleaseNumber (MemorySegment segme static final MethodHandle GetDeviceAddress$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.GetDeviceAddress$FUNC ); + /** + * {@snippet : + * IOReturn (*GetDeviceAddress)(void*,USBDeviceAddress*); + * } + */ public interface GetDeviceAddress { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceAddress fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceAddress.class, fi, IOUSBDeviceStruct100.GetDeviceAddress$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetDeviceAddress fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetDeviceAddress.class, fi, IOUSBDeviceStruct100.GetDeviceAddress$FUNC, scope); } - static GetDeviceAddress ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetDeviceAddress ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceAddress$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBDeviceStruct100.GetDeviceAddress$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -758,20 +1065,32 @@ static GetDeviceAddress ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetDeviceAddress$VH() { return IOUSBDeviceStruct100.GetDeviceAddress$VH; } - public static MemoryAddress GetDeviceAddress$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceAddress$VH.get(seg); - } - public static void GetDeviceAddress$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetDeviceAddress)(void*,USBDeviceAddress*); + * } + */ + public static MemorySegment GetDeviceAddress$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceAddress$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetDeviceAddress)(void*,USBDeviceAddress*); + * } + */ + public static void GetDeviceAddress$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceAddress$VH.set(seg, x); } - public static MemoryAddress GetDeviceAddress$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceAddress$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetDeviceAddress$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceAddress$VH.get(seg.asSlice(index*sizeof())); } - public static void GetDeviceAddress$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetDeviceAddress$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceAddress$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceAddress GetDeviceAddress (MemorySegment segment, MemorySession session) { - return GetDeviceAddress.ofAddress(GetDeviceAddress$get(segment), session); + public static GetDeviceAddress GetDeviceAddress(MemorySegment segment, SegmentScope scope) { + return GetDeviceAddress.ofAddress(GetDeviceAddress$get(segment), scope); } static final FunctionDescriptor GetDeviceBusPowerAvailable$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -780,17 +1099,22 @@ public static GetDeviceAddress GetDeviceAddress (MemorySegment segment, MemorySe static final MethodHandle GetDeviceBusPowerAvailable$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$FUNC ); + /** + * {@snippet : + * IOReturn (*GetDeviceBusPowerAvailable)(void*,UInt32*); + * } + */ public interface GetDeviceBusPowerAvailable { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceBusPowerAvailable fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceBusPowerAvailable.class, fi, IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetDeviceBusPowerAvailable fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetDeviceBusPowerAvailable.class, fi, IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$FUNC, scope); } - static GetDeviceBusPowerAvailable ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetDeviceBusPowerAvailable ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -802,20 +1126,32 @@ static GetDeviceBusPowerAvailable ofAddress(MemoryAddress addr, MemorySession se public static VarHandle GetDeviceBusPowerAvailable$VH() { return IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$VH; } - public static MemoryAddress GetDeviceBusPowerAvailable$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$VH.get(seg); - } - public static void GetDeviceBusPowerAvailable$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetDeviceBusPowerAvailable)(void*,UInt32*); + * } + */ + public static MemorySegment GetDeviceBusPowerAvailable$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetDeviceBusPowerAvailable)(void*,UInt32*); + * } + */ + public static void GetDeviceBusPowerAvailable$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$VH.set(seg, x); } - public static MemoryAddress GetDeviceBusPowerAvailable$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetDeviceBusPowerAvailable$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$VH.get(seg.asSlice(index*sizeof())); } - public static void GetDeviceBusPowerAvailable$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetDeviceBusPowerAvailable$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceBusPowerAvailable GetDeviceBusPowerAvailable (MemorySegment segment, MemorySession session) { - return GetDeviceBusPowerAvailable.ofAddress(GetDeviceBusPowerAvailable$get(segment), session); + public static GetDeviceBusPowerAvailable GetDeviceBusPowerAvailable(MemorySegment segment, SegmentScope scope) { + return GetDeviceBusPowerAvailable.ofAddress(GetDeviceBusPowerAvailable$get(segment), scope); } static final FunctionDescriptor GetDeviceSpeed$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -824,17 +1160,22 @@ public static GetDeviceBusPowerAvailable GetDeviceBusPowerAvailable (MemorySegme static final MethodHandle GetDeviceSpeed$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.GetDeviceSpeed$FUNC ); + /** + * {@snippet : + * IOReturn (*GetDeviceSpeed)(void*,UInt8*); + * } + */ public interface GetDeviceSpeed { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceSpeed fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceSpeed.class, fi, IOUSBDeviceStruct100.GetDeviceSpeed$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetDeviceSpeed fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetDeviceSpeed.class, fi, IOUSBDeviceStruct100.GetDeviceSpeed$FUNC, scope); } - static GetDeviceSpeed ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetDeviceSpeed ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceSpeed$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBDeviceStruct100.GetDeviceSpeed$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -846,20 +1187,32 @@ static GetDeviceSpeed ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetDeviceSpeed$VH() { return IOUSBDeviceStruct100.GetDeviceSpeed$VH; } - public static MemoryAddress GetDeviceSpeed$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceSpeed$VH.get(seg); - } - public static void GetDeviceSpeed$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetDeviceSpeed)(void*,UInt8*); + * } + */ + public static MemorySegment GetDeviceSpeed$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceSpeed$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetDeviceSpeed)(void*,UInt8*); + * } + */ + public static void GetDeviceSpeed$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceSpeed$VH.set(seg, x); } - public static MemoryAddress GetDeviceSpeed$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetDeviceSpeed$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetDeviceSpeed$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceSpeed$VH.get(seg.asSlice(index*sizeof())); } - public static void GetDeviceSpeed$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetDeviceSpeed$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.GetDeviceSpeed$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceSpeed GetDeviceSpeed (MemorySegment segment, MemorySession session) { - return GetDeviceSpeed.ofAddress(GetDeviceSpeed$get(segment), session); + public static GetDeviceSpeed GetDeviceSpeed(MemorySegment segment, SegmentScope scope) { + return GetDeviceSpeed.ofAddress(GetDeviceSpeed$get(segment), scope); } static final FunctionDescriptor GetNumberOfConfigurations$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -868,17 +1221,22 @@ public static GetDeviceSpeed GetDeviceSpeed (MemorySegment segment, MemorySessio static final MethodHandle GetNumberOfConfigurations$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.GetNumberOfConfigurations$FUNC ); + /** + * {@snippet : + * IOReturn (*GetNumberOfConfigurations)(void*,UInt8*); + * } + */ public interface GetNumberOfConfigurations { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetNumberOfConfigurations fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetNumberOfConfigurations.class, fi, IOUSBDeviceStruct100.GetNumberOfConfigurations$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetNumberOfConfigurations fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetNumberOfConfigurations.class, fi, IOUSBDeviceStruct100.GetNumberOfConfigurations$FUNC, scope); } - static GetNumberOfConfigurations ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetNumberOfConfigurations ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetNumberOfConfigurations$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBDeviceStruct100.GetNumberOfConfigurations$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -890,20 +1248,32 @@ static GetNumberOfConfigurations ofAddress(MemoryAddress addr, MemorySession ses public static VarHandle GetNumberOfConfigurations$VH() { return IOUSBDeviceStruct100.GetNumberOfConfigurations$VH; } - public static MemoryAddress GetNumberOfConfigurations$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetNumberOfConfigurations$VH.get(seg); - } - public static void GetNumberOfConfigurations$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetNumberOfConfigurations)(void*,UInt8*); + * } + */ + public static MemorySegment GetNumberOfConfigurations$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetNumberOfConfigurations$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetNumberOfConfigurations)(void*,UInt8*); + * } + */ + public static void GetNumberOfConfigurations$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.GetNumberOfConfigurations$VH.set(seg, x); } - public static MemoryAddress GetNumberOfConfigurations$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetNumberOfConfigurations$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetNumberOfConfigurations$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetNumberOfConfigurations$VH.get(seg.asSlice(index*sizeof())); } - public static void GetNumberOfConfigurations$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetNumberOfConfigurations$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.GetNumberOfConfigurations$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetNumberOfConfigurations GetNumberOfConfigurations (MemorySegment segment, MemorySession session) { - return GetNumberOfConfigurations.ofAddress(GetNumberOfConfigurations$get(segment), session); + public static GetNumberOfConfigurations GetNumberOfConfigurations(MemorySegment segment, SegmentScope scope) { + return GetNumberOfConfigurations.ofAddress(GetNumberOfConfigurations$get(segment), scope); } static final FunctionDescriptor GetLocationID$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -912,17 +1282,22 @@ public static GetNumberOfConfigurations GetNumberOfConfigurations (MemorySegment static final MethodHandle GetLocationID$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.GetLocationID$FUNC ); + /** + * {@snippet : + * IOReturn (*GetLocationID)(void*,UInt32*); + * } + */ public interface GetLocationID { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetLocationID fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetLocationID.class, fi, IOUSBDeviceStruct100.GetLocationID$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetLocationID fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetLocationID.class, fi, IOUSBDeviceStruct100.GetLocationID$FUNC, scope); } - static GetLocationID ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetLocationID$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBDeviceStruct100.GetLocationID$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -934,20 +1309,32 @@ static GetLocationID ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetLocationID$VH() { return IOUSBDeviceStruct100.GetLocationID$VH; } - public static MemoryAddress GetLocationID$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetLocationID$VH.get(seg); - } - public static void GetLocationID$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetLocationID)(void*,UInt32*); + * } + */ + public static MemorySegment GetLocationID$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetLocationID$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetLocationID)(void*,UInt32*); + * } + */ + public static void GetLocationID$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.GetLocationID$VH.set(seg, x); } - public static MemoryAddress GetLocationID$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetLocationID$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetLocationID$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetLocationID$VH.get(seg.asSlice(index*sizeof())); } - public static void GetLocationID$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetLocationID$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.GetLocationID$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetLocationID GetLocationID (MemorySegment segment, MemorySession session) { - return GetLocationID.ofAddress(GetLocationID$get(segment), session); + public static GetLocationID GetLocationID(MemorySegment segment, SegmentScope scope) { + return GetLocationID.ofAddress(GetLocationID$get(segment), scope); } static final FunctionDescriptor GetConfigurationDescriptorPtr$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -957,17 +1344,22 @@ public static GetLocationID GetLocationID (MemorySegment segment, MemorySession static final MethodHandle GetConfigurationDescriptorPtr$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$FUNC ); + /** + * {@snippet : + * IOReturn (*GetConfigurationDescriptorPtr)(void*,UInt8,IOUSBConfigurationDescriptorPtr*); + * } + */ public interface GetConfigurationDescriptorPtr { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(GetConfigurationDescriptorPtr fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetConfigurationDescriptorPtr.class, fi, IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2); + static MemorySegment allocate(GetConfigurationDescriptorPtr fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetConfigurationDescriptorPtr.class, fi, IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$FUNC, scope); } - static GetConfigurationDescriptorPtr ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2) -> { + static GetConfigurationDescriptorPtr ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + return (int)IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -979,20 +1371,32 @@ static GetConfigurationDescriptorPtr ofAddress(MemoryAddress addr, MemorySession public static VarHandle GetConfigurationDescriptorPtr$VH() { return IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$VH; } - public static MemoryAddress GetConfigurationDescriptorPtr$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$VH.get(seg); - } - public static void GetConfigurationDescriptorPtr$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetConfigurationDescriptorPtr)(void*,UInt8,IOUSBConfigurationDescriptorPtr*); + * } + */ + public static MemorySegment GetConfigurationDescriptorPtr$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetConfigurationDescriptorPtr)(void*,UInt8,IOUSBConfigurationDescriptorPtr*); + * } + */ + public static void GetConfigurationDescriptorPtr$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$VH.set(seg, x); } - public static MemoryAddress GetConfigurationDescriptorPtr$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetConfigurationDescriptorPtr$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$VH.get(seg.asSlice(index*sizeof())); } - public static void GetConfigurationDescriptorPtr$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetConfigurationDescriptorPtr$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetConfigurationDescriptorPtr GetConfigurationDescriptorPtr (MemorySegment segment, MemorySession session) { - return GetConfigurationDescriptorPtr.ofAddress(GetConfigurationDescriptorPtr$get(segment), session); + public static GetConfigurationDescriptorPtr GetConfigurationDescriptorPtr(MemorySegment segment, SegmentScope scope) { + return GetConfigurationDescriptorPtr.ofAddress(GetConfigurationDescriptorPtr$get(segment), scope); } static final FunctionDescriptor GetConfiguration$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1001,17 +1405,22 @@ public static GetConfigurationDescriptorPtr GetConfigurationDescriptorPtr (Memor static final MethodHandle GetConfiguration$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.GetConfiguration$FUNC ); + /** + * {@snippet : + * IOReturn (*GetConfiguration)(void*,UInt8*); + * } + */ public interface GetConfiguration { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetConfiguration fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetConfiguration.class, fi, IOUSBDeviceStruct100.GetConfiguration$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetConfiguration fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetConfiguration.class, fi, IOUSBDeviceStruct100.GetConfiguration$FUNC, scope); } - static GetConfiguration ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetConfiguration$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBDeviceStruct100.GetConfiguration$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1023,20 +1432,32 @@ static GetConfiguration ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetConfiguration$VH() { return IOUSBDeviceStruct100.GetConfiguration$VH; } - public static MemoryAddress GetConfiguration$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetConfiguration$VH.get(seg); - } - public static void GetConfiguration$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetConfiguration)(void*,UInt8*); + * } + */ + public static MemorySegment GetConfiguration$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetConfiguration$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetConfiguration)(void*,UInt8*); + * } + */ + public static void GetConfiguration$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.GetConfiguration$VH.set(seg, x); } - public static MemoryAddress GetConfiguration$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetConfiguration$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetConfiguration$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetConfiguration$VH.get(seg.asSlice(index*sizeof())); } - public static void GetConfiguration$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetConfiguration$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.GetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetConfiguration GetConfiguration (MemorySegment segment, MemorySession session) { - return GetConfiguration.ofAddress(GetConfiguration$get(segment), session); + public static GetConfiguration GetConfiguration(MemorySegment segment, SegmentScope scope) { + return GetConfiguration.ofAddress(GetConfiguration$get(segment), scope); } static final FunctionDescriptor SetConfiguration$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1045,17 +1466,22 @@ public static GetConfiguration GetConfiguration (MemorySegment segment, MemorySe static final MethodHandle SetConfiguration$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.SetConfiguration$FUNC ); + /** + * {@snippet : + * IOReturn (*SetConfiguration)(void*,UInt8); + * } + */ public interface SetConfiguration { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); - static MemorySegment allocate(SetConfiguration fi, MemorySession session) { - return RuntimeHelper.upcallStub(SetConfiguration.class, fi, IOUSBDeviceStruct100.SetConfiguration$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1); + static MemorySegment allocate(SetConfiguration fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(SetConfiguration.class, fi, IOUSBDeviceStruct100.SetConfiguration$FUNC, scope); } - static SetConfiguration ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { + static SetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBDeviceStruct100.SetConfiguration$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + return (int)IOUSBDeviceStruct100.SetConfiguration$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1067,20 +1493,32 @@ static SetConfiguration ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle SetConfiguration$VH() { return IOUSBDeviceStruct100.SetConfiguration$VH; } - public static MemoryAddress SetConfiguration$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.SetConfiguration$VH.get(seg); - } - public static void SetConfiguration$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*SetConfiguration)(void*,UInt8); + * } + */ + public static MemorySegment SetConfiguration$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.SetConfiguration$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*SetConfiguration)(void*,UInt8); + * } + */ + public static void SetConfiguration$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.SetConfiguration$VH.set(seg, x); } - public static MemoryAddress SetConfiguration$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.SetConfiguration$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment SetConfiguration$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.SetConfiguration$VH.get(seg.asSlice(index*sizeof())); } - public static void SetConfiguration$set(MemorySegment seg, long index, MemoryAddress x) { + public static void SetConfiguration$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.SetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); } - public static SetConfiguration SetConfiguration (MemorySegment segment, MemorySession session) { - return SetConfiguration.ofAddress(SetConfiguration$get(segment), session); + public static SetConfiguration SetConfiguration(MemorySegment segment, SegmentScope scope) { + return SetConfiguration.ofAddress(SetConfiguration$get(segment), scope); } static final FunctionDescriptor GetBusFrameNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1090,17 +1528,22 @@ public static SetConfiguration SetConfiguration (MemorySegment segment, MemorySe static final MethodHandle GetBusFrameNumber$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.GetBusFrameNumber$FUNC ); + /** + * {@snippet : + * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); + * } + */ public interface GetBusFrameNumber { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(GetBusFrameNumber fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetBusFrameNumber.class, fi, IOUSBDeviceStruct100.GetBusFrameNumber$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); + static MemorySegment allocate(GetBusFrameNumber fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetBusFrameNumber.class, fi, IOUSBDeviceStruct100.GetBusFrameNumber$FUNC, scope); } - static GetBusFrameNumber ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { + static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBDeviceStruct100.GetBusFrameNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); + return (int)IOUSBDeviceStruct100.GetBusFrameNumber$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1112,20 +1555,32 @@ static GetBusFrameNumber ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetBusFrameNumber$VH() { return IOUSBDeviceStruct100.GetBusFrameNumber$VH; } - public static MemoryAddress GetBusFrameNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetBusFrameNumber$VH.get(seg); - } - public static void GetBusFrameNumber$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); + * } + */ + public static MemorySegment GetBusFrameNumber$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetBusFrameNumber$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); + * } + */ + public static void GetBusFrameNumber$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.GetBusFrameNumber$VH.set(seg, x); } - public static MemoryAddress GetBusFrameNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.GetBusFrameNumber$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetBusFrameNumber$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetBusFrameNumber$VH.get(seg.asSlice(index*sizeof())); } - public static void GetBusFrameNumber$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetBusFrameNumber$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.GetBusFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetBusFrameNumber GetBusFrameNumber (MemorySegment segment, MemorySession session) { - return GetBusFrameNumber.ofAddress(GetBusFrameNumber$get(segment), session); + public static GetBusFrameNumber GetBusFrameNumber(MemorySegment segment, SegmentScope scope) { + return GetBusFrameNumber.ofAddress(GetBusFrameNumber$get(segment), scope); } static final FunctionDescriptor ResetDevice$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -1133,17 +1588,22 @@ public static GetBusFrameNumber GetBusFrameNumber (MemorySegment segment, Memory static final MethodHandle ResetDevice$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.ResetDevice$FUNC ); + /** + * {@snippet : + * IOReturn (*ResetDevice)(void*); + * } + */ public interface ResetDevice { - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(ResetDevice fi, MemorySession session) { - return RuntimeHelper.upcallStub(ResetDevice.class, fi, IOUSBDeviceStruct100.ResetDevice$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(ResetDevice fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(ResetDevice.class, fi, IOUSBDeviceStruct100.ResetDevice$FUNC, scope); } - static ResetDevice ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { + static ResetDevice ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct100.ResetDevice$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBDeviceStruct100.ResetDevice$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1155,20 +1615,32 @@ static ResetDevice ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle ResetDevice$VH() { return IOUSBDeviceStruct100.ResetDevice$VH; } - public static MemoryAddress ResetDevice$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.ResetDevice$VH.get(seg); - } - public static void ResetDevice$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*ResetDevice)(void*); + * } + */ + public static MemorySegment ResetDevice$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.ResetDevice$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*ResetDevice)(void*); + * } + */ + public static void ResetDevice$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.ResetDevice$VH.set(seg, x); } - public static MemoryAddress ResetDevice$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.ResetDevice$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment ResetDevice$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.ResetDevice$VH.get(seg.asSlice(index*sizeof())); } - public static void ResetDevice$set(MemorySegment seg, long index, MemoryAddress x) { + public static void ResetDevice$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.ResetDevice$VH.set(seg.asSlice(index*sizeof()), x); } - public static ResetDevice ResetDevice (MemorySegment segment, MemorySession session) { - return ResetDevice.ofAddress(ResetDevice$get(segment), session); + public static ResetDevice ResetDevice(MemorySegment segment, SegmentScope scope) { + return ResetDevice.ofAddress(ResetDevice$get(segment), scope); } static final FunctionDescriptor DeviceRequest$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1177,17 +1649,22 @@ public static ResetDevice ResetDevice (MemorySegment segment, MemorySession sess static final MethodHandle DeviceRequest$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.DeviceRequest$FUNC ); + /** + * {@snippet : + * IOReturn (*DeviceRequest)(void*,IOUSBDevRequest*); + * } + */ public interface DeviceRequest { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(DeviceRequest fi, MemorySession session) { - return RuntimeHelper.upcallStub(DeviceRequest.class, fi, IOUSBDeviceStruct100.DeviceRequest$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(DeviceRequest fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(DeviceRequest.class, fi, IOUSBDeviceStruct100.DeviceRequest$FUNC, scope); } - static DeviceRequest ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static DeviceRequest ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.DeviceRequest$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBDeviceStruct100.DeviceRequest$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1199,20 +1676,32 @@ static DeviceRequest ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle DeviceRequest$VH() { return IOUSBDeviceStruct100.DeviceRequest$VH; } - public static MemoryAddress DeviceRequest$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.DeviceRequest$VH.get(seg); - } - public static void DeviceRequest$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*DeviceRequest)(void*,IOUSBDevRequest*); + * } + */ + public static MemorySegment DeviceRequest$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.DeviceRequest$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*DeviceRequest)(void*,IOUSBDevRequest*); + * } + */ + public static void DeviceRequest$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.DeviceRequest$VH.set(seg, x); } - public static MemoryAddress DeviceRequest$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.DeviceRequest$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment DeviceRequest$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.DeviceRequest$VH.get(seg.asSlice(index*sizeof())); } - public static void DeviceRequest$set(MemorySegment seg, long index, MemoryAddress x) { + public static void DeviceRequest$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.DeviceRequest$VH.set(seg.asSlice(index*sizeof()), x); } - public static DeviceRequest DeviceRequest (MemorySegment segment, MemorySession session) { - return DeviceRequest.ofAddress(DeviceRequest$get(segment), session); + public static DeviceRequest DeviceRequest(MemorySegment segment, SegmentScope scope) { + return DeviceRequest.ofAddress(DeviceRequest$get(segment), scope); } static final FunctionDescriptor DeviceRequestAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1223,17 +1712,22 @@ public static DeviceRequest DeviceRequest (MemorySegment segment, MemorySession static final MethodHandle DeviceRequestAsync$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.DeviceRequestAsync$FUNC ); + /** + * {@snippet : + * IOReturn (*DeviceRequestAsync)(void*,IOUSBDevRequest*,IOAsyncCallback1,void*); + * } + */ public interface DeviceRequestAsync { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3); - static MemorySegment allocate(DeviceRequestAsync fi, MemorySession session) { - return RuntimeHelper.upcallStub(DeviceRequestAsync.class, fi, IOUSBDeviceStruct100.DeviceRequestAsync$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3); + static MemorySegment allocate(DeviceRequestAsync fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(DeviceRequestAsync.class, fi, IOUSBDeviceStruct100.DeviceRequestAsync$FUNC, scope); } - static DeviceRequestAsync ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3) -> { + static DeviceRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3) -> { try { - return (int)IOUSBDeviceStruct100.DeviceRequestAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3); + return (int)IOUSBDeviceStruct100.DeviceRequestAsync$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1245,20 +1739,32 @@ static DeviceRequestAsync ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle DeviceRequestAsync$VH() { return IOUSBDeviceStruct100.DeviceRequestAsync$VH; } - public static MemoryAddress DeviceRequestAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.DeviceRequestAsync$VH.get(seg); - } - public static void DeviceRequestAsync$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*DeviceRequestAsync)(void*,IOUSBDevRequest*,IOAsyncCallback1,void*); + * } + */ + public static MemorySegment DeviceRequestAsync$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.DeviceRequestAsync$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*DeviceRequestAsync)(void*,IOUSBDevRequest*,IOAsyncCallback1,void*); + * } + */ + public static void DeviceRequestAsync$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.DeviceRequestAsync$VH.set(seg, x); } - public static MemoryAddress DeviceRequestAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.DeviceRequestAsync$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment DeviceRequestAsync$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.DeviceRequestAsync$VH.get(seg.asSlice(index*sizeof())); } - public static void DeviceRequestAsync$set(MemorySegment seg, long index, MemoryAddress x) { + public static void DeviceRequestAsync$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.DeviceRequestAsync$VH.set(seg.asSlice(index*sizeof()), x); } - public static DeviceRequestAsync DeviceRequestAsync (MemorySegment segment, MemorySession session) { - return DeviceRequestAsync.ofAddress(DeviceRequestAsync$get(segment), session); + public static DeviceRequestAsync DeviceRequestAsync(MemorySegment segment, SegmentScope scope) { + return DeviceRequestAsync.ofAddress(DeviceRequestAsync$get(segment), scope); } static final FunctionDescriptor CreateInterfaceIterator$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1268,17 +1774,22 @@ public static DeviceRequestAsync DeviceRequestAsync (MemorySegment segment, Memo static final MethodHandle CreateInterfaceIterator$MH = RuntimeHelper.downcallHandle( IOUSBDeviceStruct100.CreateInterfaceIterator$FUNC ); + /** + * {@snippet : + * IOReturn (*CreateInterfaceIterator)(void*,IOUSBFindInterfaceRequest*,io_iterator_t*); + * } + */ public interface CreateInterfaceIterator { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(CreateInterfaceIterator fi, MemorySession session) { - return RuntimeHelper.upcallStub(CreateInterfaceIterator.class, fi, IOUSBDeviceStruct100.CreateInterfaceIterator$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); + static MemorySegment allocate(CreateInterfaceIterator fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(CreateInterfaceIterator.class, fi, IOUSBDeviceStruct100.CreateInterfaceIterator$FUNC, scope); } - static CreateInterfaceIterator ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { + static CreateInterfaceIterator ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBDeviceStruct100.CreateInterfaceIterator$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); + return (int)IOUSBDeviceStruct100.CreateInterfaceIterator$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1290,27 +1801,39 @@ static CreateInterfaceIterator ofAddress(MemoryAddress addr, MemorySession sessi public static VarHandle CreateInterfaceIterator$VH() { return IOUSBDeviceStruct100.CreateInterfaceIterator$VH; } - public static MemoryAddress CreateInterfaceIterator$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.CreateInterfaceIterator$VH.get(seg); - } - public static void CreateInterfaceIterator$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*CreateInterfaceIterator)(void*,IOUSBFindInterfaceRequest*,io_iterator_t*); + * } + */ + public static MemorySegment CreateInterfaceIterator$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.CreateInterfaceIterator$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*CreateInterfaceIterator)(void*,IOUSBFindInterfaceRequest*,io_iterator_t*); + * } + */ + public static void CreateInterfaceIterator$set(MemorySegment seg, MemorySegment x) { IOUSBDeviceStruct100.CreateInterfaceIterator$VH.set(seg, x); } - public static MemoryAddress CreateInterfaceIterator$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBDeviceStruct100.CreateInterfaceIterator$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment CreateInterfaceIterator$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.CreateInterfaceIterator$VH.get(seg.asSlice(index*sizeof())); } - public static void CreateInterfaceIterator$set(MemorySegment seg, long index, MemoryAddress x) { + public static void CreateInterfaceIterator$set(MemorySegment seg, long index, MemorySegment x) { IOUSBDeviceStruct100.CreateInterfaceIterator$VH.set(seg.asSlice(index*sizeof()), x); } - public static CreateInterfaceIterator CreateInterfaceIterator (MemorySegment segment, MemorySession session) { - return CreateInterfaceIterator.ofAddress(CreateInterfaceIterator$get(segment), session); + public static CreateInterfaceIterator CreateInterfaceIterator(MemorySegment segment, SegmentScope scope) { + return CreateInterfaceIterator.ofAddress(CreateInterfaceIterator$get(segment), scope); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java index e4e95f67..3a54b981 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java @@ -4,9 +4,19 @@ import java.lang.foreign.*; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct { + * UInt16 bInterfaceClass; + * UInt16 bInterfaceSubClass; + * UInt16 bInterfaceProtocol; + * UInt16 bAlternateSetting; + * }; + * } + */ public class IOUSBFindInterfaceRequest { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_SHORT$LAYOUT.withName("bInterfaceClass"), Constants$root.C_SHORT$LAYOUT.withName("bInterfaceSubClass"), Constants$root.C_SHORT$LAYOUT.withName("bInterfaceProtocol"), @@ -19,10 +29,22 @@ public class IOUSBFindInterfaceRequest { public static VarHandle bInterfaceClass$VH() { return IOUSBFindInterfaceRequest.bInterfaceClass$VH; } + /** + * Getter for field: + * {@snippet : + * UInt16 bInterfaceClass; + * } + */ public static short bInterfaceClass$get(MemorySegment seg) { return (short)IOUSBFindInterfaceRequest.bInterfaceClass$VH.get(seg); } - public static void bInterfaceClass$set( MemorySegment seg, short x) { + /** + * Setter for field: + * {@snippet : + * UInt16 bInterfaceClass; + * } + */ + public static void bInterfaceClass$set(MemorySegment seg, short x) { IOUSBFindInterfaceRequest.bInterfaceClass$VH.set(seg, x); } public static short bInterfaceClass$get(MemorySegment seg, long index) { @@ -35,10 +57,22 @@ public class IOUSBFindInterfaceRequest { public static VarHandle bInterfaceSubClass$VH() { return IOUSBFindInterfaceRequest.bInterfaceSubClass$VH; } + /** + * Getter for field: + * {@snippet : + * UInt16 bInterfaceSubClass; + * } + */ public static short bInterfaceSubClass$get(MemorySegment seg) { return (short)IOUSBFindInterfaceRequest.bInterfaceSubClass$VH.get(seg); } - public static void bInterfaceSubClass$set( MemorySegment seg, short x) { + /** + * Setter for field: + * {@snippet : + * UInt16 bInterfaceSubClass; + * } + */ + public static void bInterfaceSubClass$set(MemorySegment seg, short x) { IOUSBFindInterfaceRequest.bInterfaceSubClass$VH.set(seg, x); } public static short bInterfaceSubClass$get(MemorySegment seg, long index) { @@ -51,10 +85,22 @@ public class IOUSBFindInterfaceRequest { public static VarHandle bInterfaceProtocol$VH() { return IOUSBFindInterfaceRequest.bInterfaceProtocol$VH; } + /** + * Getter for field: + * {@snippet : + * UInt16 bInterfaceProtocol; + * } + */ public static short bInterfaceProtocol$get(MemorySegment seg) { return (short)IOUSBFindInterfaceRequest.bInterfaceProtocol$VH.get(seg); } - public static void bInterfaceProtocol$set( MemorySegment seg, short x) { + /** + * Setter for field: + * {@snippet : + * UInt16 bInterfaceProtocol; + * } + */ + public static void bInterfaceProtocol$set(MemorySegment seg, short x) { IOUSBFindInterfaceRequest.bInterfaceProtocol$VH.set(seg, x); } public static short bInterfaceProtocol$get(MemorySegment seg, long index) { @@ -67,10 +113,22 @@ public class IOUSBFindInterfaceRequest { public static VarHandle bAlternateSetting$VH() { return IOUSBFindInterfaceRequest.bAlternateSetting$VH; } + /** + * Getter for field: + * {@snippet : + * UInt16 bAlternateSetting; + * } + */ public static short bAlternateSetting$get(MemorySegment seg) { return (short)IOUSBFindInterfaceRequest.bAlternateSetting$VH.get(seg); } - public static void bAlternateSetting$set( MemorySegment seg, short x) { + /** + * Setter for field: + * {@snippet : + * UInt16 bAlternateSetting; + * } + */ + public static void bAlternateSetting$set(MemorySegment seg, short x) { IOUSBFindInterfaceRequest.bAlternateSetting$VH.set(seg, x); } public static short bAlternateSetting$get(MemorySegment seg, long index) { @@ -81,10 +139,10 @@ public class IOUSBFindInterfaceRequest { } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface190.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface190.java index 53199116..44ead20b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface190.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface190.java @@ -2,8 +2,15 @@ package net.codecrete.usb.macos.gen.iokit; -public class IOUSBInterfaceInterface190 extends IOUSBInterfaceStruct190 { +/** + * {@snippet : + * typedef struct IOUSBInterfaceStruct190 IOUSBInterfaceInterface190; + * } + */ +public final class IOUSBInterfaceInterface190 extends IOUSBInterfaceStruct190 { + // Suppresses default constructor, ensuring non-instantiability. + private IOUSBInterfaceInterface190() {} } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java index 320879fc..e4a85020 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java @@ -5,9 +5,64 @@ import java.lang.foreign.*; import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct IOUSBInterfaceStruct190 { + * void* _reserved; + * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * ULONG (*AddRef)(void*); + * ULONG (*Release)(void*); + * IOReturn (*CreateInterfaceAsyncEventSource)(void*,CFRunLoopSourceRef*); + * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void*); + * IOReturn (*CreateInterfaceAsyncPort)(void*,mach_port_t*); + * mach_port_t (*GetInterfaceAsyncPort)(void*); + * IOReturn (*USBInterfaceOpen)(void*); + * IOReturn (*USBInterfaceClose)(void*); + * IOReturn (*GetInterfaceClass)(void*,UInt8*); + * IOReturn (*GetInterfaceSubClass)(void*,UInt8*); + * IOReturn (*GetInterfaceProtocol)(void*,UInt8*); + * IOReturn (*GetDeviceVendor)(void*,UInt16*); + * IOReturn (*GetDeviceProduct)(void*,UInt16*); + * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); + * IOReturn (*GetConfigurationValue)(void*,UInt8*); + * IOReturn (*GetInterfaceNumber)(void*,UInt8*); + * IOReturn (*GetAlternateSetting)(void*,UInt8*); + * IOReturn (*GetNumEndpoints)(void*,UInt8*); + * IOReturn (*GetLocationID)(void*,UInt32*); + * IOReturn (*GetDevice)(void*,io_service_t*); + * IOReturn (*SetAlternateInterface)(void*,UInt8); + * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); + * IOReturn (*ControlRequest)(void*,UInt8,IOUSBDevRequest*); + * IOReturn (*ControlRequestAsync)(void*,UInt8,IOUSBDevRequest*,IOAsyncCallback1,void*); + * IOReturn (*GetPipeProperties)(void*,UInt8,UInt8*,UInt8*,UInt8*,UInt16*,UInt8*); + * IOReturn (*GetPipeStatus)(void*,UInt8); + * IOReturn (*AbortPipe)(void*,UInt8); + * IOReturn (*ResetPipe)(void*,UInt8); + * IOReturn (*ClearPipeStall)(void*,UInt8); + * IOReturn (*ReadPipe)(void*,UInt8,void*,UInt32*); + * IOReturn (*WritePipe)(void*,UInt8,void*,UInt32); + * IOReturn (*ReadPipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); + * IOReturn (*WritePipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); + * IOReturn (*ReadIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); + * IOReturn (*WriteIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); + * IOReturn (*ControlRequestTO)(void*,UInt8,IOUSBDevRequestTO*); + * IOReturn (*ControlRequestAsyncTO)(void*,UInt8,IOUSBDevRequestTO*,IOAsyncCallback1,void*); + * IOReturn (*ReadPipeTO)(void*,UInt8,void*,UInt32*,UInt32,UInt32); + * IOReturn (*WritePipeTO)(void*,UInt8,void*,UInt32,UInt32,UInt32); + * IOReturn (*ReadPipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); + * IOReturn (*WritePipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); + * IOReturn (*USBInterfaceGetStringIndex)(void*,UInt8*); + * IOReturn (*USBInterfaceOpenSeize)(void*); + * IOReturn (*ClearPipeStallBothEnds)(void*,UInt8); + * IOReturn (*SetPipePolicy)(void*,UInt8,UInt16,UInt8); + * IOReturn (*GetBandwidthAvailable)(void*,UInt32*); + * IOReturn (*GetEndpointProperties)(void*,UInt8,UInt8,UInt8,UInt8*,UInt16*,UInt8*); + * }; + * } + */ public class IOUSBInterfaceStruct190 { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_POINTER$LAYOUT.withName("_reserved"), Constants$root.C_POINTER$LAYOUT.withName("QueryInterface"), Constants$root.C_POINTER$LAYOUT.withName("AddRef"), @@ -65,16 +120,28 @@ public class IOUSBInterfaceStruct190 { public static VarHandle _reserved$VH() { return IOUSBInterfaceStruct190._reserved$VH; } - public static MemoryAddress _reserved$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190._reserved$VH.get(seg); - } - public static void _reserved$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * void* _reserved; + * } + */ + public static MemorySegment _reserved$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190._reserved$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * void* _reserved; + * } + */ + public static void _reserved$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190._reserved$VH.set(seg, x); } - public static MemoryAddress _reserved$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190._reserved$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment _reserved$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190._reserved$VH.get(seg.asSlice(index*sizeof())); } - public static void _reserved$set(MemorySegment seg, long index, MemoryAddress x) { + public static void _reserved$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190._reserved$VH.set(seg.asSlice(index*sizeof()), x); } static final FunctionDescriptor QueryInterface$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, @@ -102,17 +169,22 @@ public class IOUSBInterfaceStruct190 { static final MethodHandle QueryInterface$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.QueryInterface$FUNC ); + /** + * {@snippet : + * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * } + */ public interface QueryInterface { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(QueryInterface fi, MemorySession session) { - return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOUSBInterfaceStruct190.QueryInterface$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); + static MemorySegment allocate(QueryInterface fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOUSBInterfaceStruct190.QueryInterface$FUNC, scope); } - static QueryInterface ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemoryAddress __x2) -> { + static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBInterfaceStruct190.QueryInterface$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + return (int)IOUSBInterfaceStruct190.QueryInterface$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -124,20 +196,32 @@ static QueryInterface ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle QueryInterface$VH() { return IOUSBInterfaceStruct190.QueryInterface$VH; } - public static MemoryAddress QueryInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.QueryInterface$VH.get(seg); - } - public static void QueryInterface$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * } + */ + public static MemorySegment QueryInterface$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.QueryInterface$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * } + */ + public static void QueryInterface$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.QueryInterface$VH.set(seg, x); } - public static MemoryAddress QueryInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.QueryInterface$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment QueryInterface$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.QueryInterface$VH.get(seg.asSlice(index*sizeof())); } - public static void QueryInterface$set(MemorySegment seg, long index, MemoryAddress x) { + public static void QueryInterface$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.QueryInterface$VH.set(seg.asSlice(index*sizeof()), x); } - public static QueryInterface QueryInterface (MemorySegment segment, MemorySession session) { - return QueryInterface.ofAddress(QueryInterface$get(segment), session); + public static QueryInterface QueryInterface(MemorySegment segment, SegmentScope scope) { + return QueryInterface.ofAddress(QueryInterface$get(segment), scope); } static final FunctionDescriptor AddRef$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -145,17 +229,22 @@ public static QueryInterface QueryInterface (MemorySegment segment, MemorySessio static final MethodHandle AddRef$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.AddRef$FUNC ); + /** + * {@snippet : + * ULONG (*AddRef)(void*); + * } + */ public interface AddRef { - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(AddRef fi, MemorySession session) { - return RuntimeHelper.upcallStub(AddRef.class, fi, IOUSBInterfaceStruct190.AddRef$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(AddRef fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(AddRef.class, fi, IOUSBInterfaceStruct190.AddRef$FUNC, scope); } - static AddRef ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { + static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBInterfaceStruct190.AddRef$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBInterfaceStruct190.AddRef$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -167,20 +256,32 @@ static AddRef ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle AddRef$VH() { return IOUSBInterfaceStruct190.AddRef$VH; } - public static MemoryAddress AddRef$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.AddRef$VH.get(seg); - } - public static void AddRef$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * ULONG (*AddRef)(void*); + * } + */ + public static MemorySegment AddRef$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.AddRef$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * ULONG (*AddRef)(void*); + * } + */ + public static void AddRef$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.AddRef$VH.set(seg, x); } - public static MemoryAddress AddRef$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.AddRef$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment AddRef$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.AddRef$VH.get(seg.asSlice(index*sizeof())); } - public static void AddRef$set(MemorySegment seg, long index, MemoryAddress x) { + public static void AddRef$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.AddRef$VH.set(seg.asSlice(index*sizeof()), x); } - public static AddRef AddRef (MemorySegment segment, MemorySession session) { - return AddRef.ofAddress(AddRef$get(segment), session); + public static AddRef AddRef(MemorySegment segment, SegmentScope scope) { + return AddRef.ofAddress(AddRef$get(segment), scope); } static final FunctionDescriptor Release$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -188,17 +289,22 @@ public static AddRef AddRef (MemorySegment segment, MemorySession session) { static final MethodHandle Release$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.Release$FUNC ); + /** + * {@snippet : + * ULONG (*Release)(void*); + * } + */ public interface Release { - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(Release fi, MemorySession session) { - return RuntimeHelper.upcallStub(Release.class, fi, IOUSBInterfaceStruct190.Release$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(Release fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(Release.class, fi, IOUSBInterfaceStruct190.Release$FUNC, scope); } - static Release ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { + static Release ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBInterfaceStruct190.Release$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBInterfaceStruct190.Release$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -210,20 +316,32 @@ static Release ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle Release$VH() { return IOUSBInterfaceStruct190.Release$VH; } - public static MemoryAddress Release$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.Release$VH.get(seg); - } - public static void Release$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * ULONG (*Release)(void*); + * } + */ + public static MemorySegment Release$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.Release$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * ULONG (*Release)(void*); + * } + */ + public static void Release$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.Release$VH.set(seg, x); } - public static MemoryAddress Release$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.Release$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment Release$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.Release$VH.get(seg.asSlice(index*sizeof())); } - public static void Release$set(MemorySegment seg, long index, MemoryAddress x) { + public static void Release$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.Release$VH.set(seg.asSlice(index*sizeof()), x); } - public static Release Release (MemorySegment segment, MemorySession session) { - return Release.ofAddress(Release$get(segment), session); + public static Release Release(MemorySegment segment, SegmentScope scope) { + return Release.ofAddress(Release$get(segment), scope); } static final FunctionDescriptor CreateInterfaceAsyncEventSource$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -232,17 +350,22 @@ public static Release Release (MemorySegment segment, MemorySession session) { static final MethodHandle CreateInterfaceAsyncEventSource$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$FUNC ); + /** + * {@snippet : + * IOReturn (*CreateInterfaceAsyncEventSource)(void*,CFRunLoopSourceRef*); + * } + */ public interface CreateInterfaceAsyncEventSource { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(CreateInterfaceAsyncEventSource fi, MemorySession session) { - return RuntimeHelper.upcallStub(CreateInterfaceAsyncEventSource.class, fi, IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(CreateInterfaceAsyncEventSource fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(CreateInterfaceAsyncEventSource.class, fi, IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$FUNC, scope); } - static CreateInterfaceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static CreateInterfaceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -254,20 +377,32 @@ static CreateInterfaceAsyncEventSource ofAddress(MemoryAddress addr, MemorySessi public static VarHandle CreateInterfaceAsyncEventSource$VH() { return IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$VH; } - public static MemoryAddress CreateInterfaceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$VH.get(seg); - } - public static void CreateInterfaceAsyncEventSource$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*CreateInterfaceAsyncEventSource)(void*,CFRunLoopSourceRef*); + * } + */ + public static MemorySegment CreateInterfaceAsyncEventSource$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*CreateInterfaceAsyncEventSource)(void*,CFRunLoopSourceRef*); + * } + */ + public static void CreateInterfaceAsyncEventSource$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$VH.set(seg, x); } - public static MemoryAddress CreateInterfaceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment CreateInterfaceAsyncEventSource$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); } - public static void CreateInterfaceAsyncEventSource$set(MemorySegment seg, long index, MemoryAddress x) { + public static void CreateInterfaceAsyncEventSource$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); } - public static CreateInterfaceAsyncEventSource CreateInterfaceAsyncEventSource (MemorySegment segment, MemorySession session) { - return CreateInterfaceAsyncEventSource.ofAddress(CreateInterfaceAsyncEventSource$get(segment), session); + public static CreateInterfaceAsyncEventSource CreateInterfaceAsyncEventSource(MemorySegment segment, SegmentScope scope) { + return CreateInterfaceAsyncEventSource.ofAddress(CreateInterfaceAsyncEventSource$get(segment), scope); } static final FunctionDescriptor GetInterfaceAsyncEventSource$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -275,17 +410,22 @@ public static CreateInterfaceAsyncEventSource CreateInterfaceAsyncEventSource (M static final MethodHandle GetInterfaceAsyncEventSource$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$FUNC ); + /** + * {@snippet : + * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void*); + * } + */ public interface GetInterfaceAsyncEventSource { - java.lang.foreign.Addressable apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(GetInterfaceAsyncEventSource fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetInterfaceAsyncEventSource.class, fi, IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$FUNC, session); + java.lang.foreign.MemorySegment apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(GetInterfaceAsyncEventSource fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetInterfaceAsyncEventSource.class, fi, IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$FUNC, scope); } - static GetInterfaceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { + static GetInterfaceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { try { - return (java.lang.foreign.Addressable)(java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -297,20 +437,32 @@ static GetInterfaceAsyncEventSource ofAddress(MemoryAddress addr, MemorySession public static VarHandle GetInterfaceAsyncEventSource$VH() { return IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$VH; } - public static MemoryAddress GetInterfaceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$VH.get(seg); - } - public static void GetInterfaceAsyncEventSource$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void*); + * } + */ + public static MemorySegment GetInterfaceAsyncEventSource$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void*); + * } + */ + public static void GetInterfaceAsyncEventSource$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$VH.set(seg, x); } - public static MemoryAddress GetInterfaceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetInterfaceAsyncEventSource$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); } - public static void GetInterfaceAsyncEventSource$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetInterfaceAsyncEventSource$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetInterfaceAsyncEventSource GetInterfaceAsyncEventSource (MemorySegment segment, MemorySession session) { - return GetInterfaceAsyncEventSource.ofAddress(GetInterfaceAsyncEventSource$get(segment), session); + public static GetInterfaceAsyncEventSource GetInterfaceAsyncEventSource(MemorySegment segment, SegmentScope scope) { + return GetInterfaceAsyncEventSource.ofAddress(GetInterfaceAsyncEventSource$get(segment), scope); } static final FunctionDescriptor CreateInterfaceAsyncPort$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -319,17 +471,22 @@ public static GetInterfaceAsyncEventSource GetInterfaceAsyncEventSource (MemoryS static final MethodHandle CreateInterfaceAsyncPort$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$FUNC ); + /** + * {@snippet : + * IOReturn (*CreateInterfaceAsyncPort)(void*,mach_port_t*); + * } + */ public interface CreateInterfaceAsyncPort { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(CreateInterfaceAsyncPort fi, MemorySession session) { - return RuntimeHelper.upcallStub(CreateInterfaceAsyncPort.class, fi, IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(CreateInterfaceAsyncPort fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(CreateInterfaceAsyncPort.class, fi, IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$FUNC, scope); } - static CreateInterfaceAsyncPort ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static CreateInterfaceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -341,20 +498,32 @@ static CreateInterfaceAsyncPort ofAddress(MemoryAddress addr, MemorySession sess public static VarHandle CreateInterfaceAsyncPort$VH() { return IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$VH; } - public static MemoryAddress CreateInterfaceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$VH.get(seg); - } - public static void CreateInterfaceAsyncPort$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*CreateInterfaceAsyncPort)(void*,mach_port_t*); + * } + */ + public static MemorySegment CreateInterfaceAsyncPort$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*CreateInterfaceAsyncPort)(void*,mach_port_t*); + * } + */ + public static void CreateInterfaceAsyncPort$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$VH.set(seg, x); } - public static MemoryAddress CreateInterfaceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment CreateInterfaceAsyncPort$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$VH.get(seg.asSlice(index*sizeof())); } - public static void CreateInterfaceAsyncPort$set(MemorySegment seg, long index, MemoryAddress x) { + public static void CreateInterfaceAsyncPort$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); } - public static CreateInterfaceAsyncPort CreateInterfaceAsyncPort (MemorySegment segment, MemorySession session) { - return CreateInterfaceAsyncPort.ofAddress(CreateInterfaceAsyncPort$get(segment), session); + public static CreateInterfaceAsyncPort CreateInterfaceAsyncPort(MemorySegment segment, SegmentScope scope) { + return CreateInterfaceAsyncPort.ofAddress(CreateInterfaceAsyncPort$get(segment), scope); } static final FunctionDescriptor GetInterfaceAsyncPort$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -362,17 +531,22 @@ public static CreateInterfaceAsyncPort CreateInterfaceAsyncPort (MemorySegment s static final MethodHandle GetInterfaceAsyncPort$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetInterfaceAsyncPort$FUNC ); + /** + * {@snippet : + * mach_port_t (*GetInterfaceAsyncPort)(void*); + * } + */ public interface GetInterfaceAsyncPort { - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(GetInterfaceAsyncPort fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetInterfaceAsyncPort.class, fi, IOUSBInterfaceStruct190.GetInterfaceAsyncPort$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(GetInterfaceAsyncPort fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetInterfaceAsyncPort.class, fi, IOUSBInterfaceStruct190.GetInterfaceAsyncPort$FUNC, scope); } - static GetInterfaceAsyncPort ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { + static GetInterfaceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBInterfaceStruct190.GetInterfaceAsyncPort$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBInterfaceStruct190.GetInterfaceAsyncPort$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -384,20 +558,32 @@ static GetInterfaceAsyncPort ofAddress(MemoryAddress addr, MemorySession session public static VarHandle GetInterfaceAsyncPort$VH() { return IOUSBInterfaceStruct190.GetInterfaceAsyncPort$VH; } - public static MemoryAddress GetInterfaceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceAsyncPort$VH.get(seg); - } - public static void GetInterfaceAsyncPort$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * mach_port_t (*GetInterfaceAsyncPort)(void*); + * } + */ + public static MemorySegment GetInterfaceAsyncPort$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceAsyncPort$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * mach_port_t (*GetInterfaceAsyncPort)(void*); + * } + */ + public static void GetInterfaceAsyncPort$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetInterfaceAsyncPort$VH.set(seg, x); } - public static MemoryAddress GetInterfaceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetInterfaceAsyncPort$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceAsyncPort$VH.get(seg.asSlice(index*sizeof())); } - public static void GetInterfaceAsyncPort$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetInterfaceAsyncPort$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetInterfaceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetInterfaceAsyncPort GetInterfaceAsyncPort (MemorySegment segment, MemorySession session) { - return GetInterfaceAsyncPort.ofAddress(GetInterfaceAsyncPort$get(segment), session); + public static GetInterfaceAsyncPort GetInterfaceAsyncPort(MemorySegment segment, SegmentScope scope) { + return GetInterfaceAsyncPort.ofAddress(GetInterfaceAsyncPort$get(segment), scope); } static final FunctionDescriptor USBInterfaceOpen$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -405,17 +591,22 @@ public static GetInterfaceAsyncPort GetInterfaceAsyncPort (MemorySegment segment static final MethodHandle USBInterfaceOpen$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.USBInterfaceOpen$FUNC ); + /** + * {@snippet : + * IOReturn (*USBInterfaceOpen)(void*); + * } + */ public interface USBInterfaceOpen { - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(USBInterfaceOpen fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBInterfaceOpen.class, fi, IOUSBInterfaceStruct190.USBInterfaceOpen$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(USBInterfaceOpen fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(USBInterfaceOpen.class, fi, IOUSBInterfaceStruct190.USBInterfaceOpen$FUNC, scope); } - static USBInterfaceOpen ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { + static USBInterfaceOpen ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBInterfaceStruct190.USBInterfaceOpen$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBInterfaceStruct190.USBInterfaceOpen$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -427,20 +618,32 @@ static USBInterfaceOpen ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle USBInterfaceOpen$VH() { return IOUSBInterfaceStruct190.USBInterfaceOpen$VH; } - public static MemoryAddress USBInterfaceOpen$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.USBInterfaceOpen$VH.get(seg); - } - public static void USBInterfaceOpen$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*USBInterfaceOpen)(void*); + * } + */ + public static MemorySegment USBInterfaceOpen$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.USBInterfaceOpen$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*USBInterfaceOpen)(void*); + * } + */ + public static void USBInterfaceOpen$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.USBInterfaceOpen$VH.set(seg, x); } - public static MemoryAddress USBInterfaceOpen$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.USBInterfaceOpen$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment USBInterfaceOpen$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.USBInterfaceOpen$VH.get(seg.asSlice(index*sizeof())); } - public static void USBInterfaceOpen$set(MemorySegment seg, long index, MemoryAddress x) { + public static void USBInterfaceOpen$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.USBInterfaceOpen$VH.set(seg.asSlice(index*sizeof()), x); } - public static USBInterfaceOpen USBInterfaceOpen (MemorySegment segment, MemorySession session) { - return USBInterfaceOpen.ofAddress(USBInterfaceOpen$get(segment), session); + public static USBInterfaceOpen USBInterfaceOpen(MemorySegment segment, SegmentScope scope) { + return USBInterfaceOpen.ofAddress(USBInterfaceOpen$get(segment), scope); } static final FunctionDescriptor USBInterfaceClose$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -448,17 +651,22 @@ public static USBInterfaceOpen USBInterfaceOpen (MemorySegment segment, MemorySe static final MethodHandle USBInterfaceClose$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.USBInterfaceClose$FUNC ); + /** + * {@snippet : + * IOReturn (*USBInterfaceClose)(void*); + * } + */ public interface USBInterfaceClose { - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(USBInterfaceClose fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBInterfaceClose.class, fi, IOUSBInterfaceStruct190.USBInterfaceClose$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(USBInterfaceClose fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(USBInterfaceClose.class, fi, IOUSBInterfaceStruct190.USBInterfaceClose$FUNC, scope); } - static USBInterfaceClose ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { + static USBInterfaceClose ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBInterfaceStruct190.USBInterfaceClose$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBInterfaceStruct190.USBInterfaceClose$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -470,20 +678,32 @@ static USBInterfaceClose ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle USBInterfaceClose$VH() { return IOUSBInterfaceStruct190.USBInterfaceClose$VH; } - public static MemoryAddress USBInterfaceClose$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.USBInterfaceClose$VH.get(seg); - } - public static void USBInterfaceClose$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*USBInterfaceClose)(void*); + * } + */ + public static MemorySegment USBInterfaceClose$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.USBInterfaceClose$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*USBInterfaceClose)(void*); + * } + */ + public static void USBInterfaceClose$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.USBInterfaceClose$VH.set(seg, x); } - public static MemoryAddress USBInterfaceClose$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.USBInterfaceClose$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment USBInterfaceClose$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.USBInterfaceClose$VH.get(seg.asSlice(index*sizeof())); } - public static void USBInterfaceClose$set(MemorySegment seg, long index, MemoryAddress x) { + public static void USBInterfaceClose$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.USBInterfaceClose$VH.set(seg.asSlice(index*sizeof()), x); } - public static USBInterfaceClose USBInterfaceClose (MemorySegment segment, MemorySession session) { - return USBInterfaceClose.ofAddress(USBInterfaceClose$get(segment), session); + public static USBInterfaceClose USBInterfaceClose(MemorySegment segment, SegmentScope scope) { + return USBInterfaceClose.ofAddress(USBInterfaceClose$get(segment), scope); } static final FunctionDescriptor GetInterfaceClass$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -492,17 +712,22 @@ public static USBInterfaceClose USBInterfaceClose (MemorySegment segment, Memory static final MethodHandle GetInterfaceClass$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetInterfaceClass$FUNC ); + /** + * {@snippet : + * IOReturn (*GetInterfaceClass)(void*,UInt8*); + * } + */ public interface GetInterfaceClass { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetInterfaceClass fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetInterfaceClass.class, fi, IOUSBInterfaceStruct190.GetInterfaceClass$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetInterfaceClass fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetInterfaceClass.class, fi, IOUSBInterfaceStruct190.GetInterfaceClass$FUNC, scope); } - static GetInterfaceClass ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetInterfaceClass ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetInterfaceClass$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetInterfaceClass$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -514,20 +739,32 @@ static GetInterfaceClass ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetInterfaceClass$VH() { return IOUSBInterfaceStruct190.GetInterfaceClass$VH; } - public static MemoryAddress GetInterfaceClass$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceClass$VH.get(seg); - } - public static void GetInterfaceClass$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetInterfaceClass)(void*,UInt8*); + * } + */ + public static MemorySegment GetInterfaceClass$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceClass$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetInterfaceClass)(void*,UInt8*); + * } + */ + public static void GetInterfaceClass$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetInterfaceClass$VH.set(seg, x); } - public static MemoryAddress GetInterfaceClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceClass$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetInterfaceClass$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceClass$VH.get(seg.asSlice(index*sizeof())); } - public static void GetInterfaceClass$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetInterfaceClass$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetInterfaceClass$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetInterfaceClass GetInterfaceClass (MemorySegment segment, MemorySession session) { - return GetInterfaceClass.ofAddress(GetInterfaceClass$get(segment), session); + public static GetInterfaceClass GetInterfaceClass(MemorySegment segment, SegmentScope scope) { + return GetInterfaceClass.ofAddress(GetInterfaceClass$get(segment), scope); } static final FunctionDescriptor GetInterfaceSubClass$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -536,17 +773,22 @@ public static GetInterfaceClass GetInterfaceClass (MemorySegment segment, Memory static final MethodHandle GetInterfaceSubClass$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetInterfaceSubClass$FUNC ); + /** + * {@snippet : + * IOReturn (*GetInterfaceSubClass)(void*,UInt8*); + * } + */ public interface GetInterfaceSubClass { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetInterfaceSubClass fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetInterfaceSubClass.class, fi, IOUSBInterfaceStruct190.GetInterfaceSubClass$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetInterfaceSubClass fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetInterfaceSubClass.class, fi, IOUSBInterfaceStruct190.GetInterfaceSubClass$FUNC, scope); } - static GetInterfaceSubClass ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetInterfaceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetInterfaceSubClass$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetInterfaceSubClass$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -558,20 +800,32 @@ static GetInterfaceSubClass ofAddress(MemoryAddress addr, MemorySession session) public static VarHandle GetInterfaceSubClass$VH() { return IOUSBInterfaceStruct190.GetInterfaceSubClass$VH; } - public static MemoryAddress GetInterfaceSubClass$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceSubClass$VH.get(seg); - } - public static void GetInterfaceSubClass$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetInterfaceSubClass)(void*,UInt8*); + * } + */ + public static MemorySegment GetInterfaceSubClass$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceSubClass$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetInterfaceSubClass)(void*,UInt8*); + * } + */ + public static void GetInterfaceSubClass$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetInterfaceSubClass$VH.set(seg, x); } - public static MemoryAddress GetInterfaceSubClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceSubClass$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetInterfaceSubClass$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceSubClass$VH.get(seg.asSlice(index*sizeof())); } - public static void GetInterfaceSubClass$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetInterfaceSubClass$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetInterfaceSubClass$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetInterfaceSubClass GetInterfaceSubClass (MemorySegment segment, MemorySession session) { - return GetInterfaceSubClass.ofAddress(GetInterfaceSubClass$get(segment), session); + public static GetInterfaceSubClass GetInterfaceSubClass(MemorySegment segment, SegmentScope scope) { + return GetInterfaceSubClass.ofAddress(GetInterfaceSubClass$get(segment), scope); } static final FunctionDescriptor GetInterfaceProtocol$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -580,17 +834,22 @@ public static GetInterfaceSubClass GetInterfaceSubClass (MemorySegment segment, static final MethodHandle GetInterfaceProtocol$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetInterfaceProtocol$FUNC ); + /** + * {@snippet : + * IOReturn (*GetInterfaceProtocol)(void*,UInt8*); + * } + */ public interface GetInterfaceProtocol { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetInterfaceProtocol fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetInterfaceProtocol.class, fi, IOUSBInterfaceStruct190.GetInterfaceProtocol$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetInterfaceProtocol fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetInterfaceProtocol.class, fi, IOUSBInterfaceStruct190.GetInterfaceProtocol$FUNC, scope); } - static GetInterfaceProtocol ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetInterfaceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetInterfaceProtocol$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetInterfaceProtocol$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -602,20 +861,32 @@ static GetInterfaceProtocol ofAddress(MemoryAddress addr, MemorySession session) public static VarHandle GetInterfaceProtocol$VH() { return IOUSBInterfaceStruct190.GetInterfaceProtocol$VH; } - public static MemoryAddress GetInterfaceProtocol$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceProtocol$VH.get(seg); - } - public static void GetInterfaceProtocol$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetInterfaceProtocol)(void*,UInt8*); + * } + */ + public static MemorySegment GetInterfaceProtocol$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceProtocol$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetInterfaceProtocol)(void*,UInt8*); + * } + */ + public static void GetInterfaceProtocol$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetInterfaceProtocol$VH.set(seg, x); } - public static MemoryAddress GetInterfaceProtocol$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceProtocol$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetInterfaceProtocol$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceProtocol$VH.get(seg.asSlice(index*sizeof())); } - public static void GetInterfaceProtocol$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetInterfaceProtocol$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetInterfaceProtocol$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetInterfaceProtocol GetInterfaceProtocol (MemorySegment segment, MemorySession session) { - return GetInterfaceProtocol.ofAddress(GetInterfaceProtocol$get(segment), session); + public static GetInterfaceProtocol GetInterfaceProtocol(MemorySegment segment, SegmentScope scope) { + return GetInterfaceProtocol.ofAddress(GetInterfaceProtocol$get(segment), scope); } static final FunctionDescriptor GetDeviceVendor$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -624,17 +895,22 @@ public static GetInterfaceProtocol GetInterfaceProtocol (MemorySegment segment, static final MethodHandle GetDeviceVendor$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetDeviceVendor$FUNC ); + /** + * {@snippet : + * IOReturn (*GetDeviceVendor)(void*,UInt16*); + * } + */ public interface GetDeviceVendor { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceVendor fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceVendor.class, fi, IOUSBInterfaceStruct190.GetDeviceVendor$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetDeviceVendor fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetDeviceVendor.class, fi, IOUSBInterfaceStruct190.GetDeviceVendor$FUNC, scope); } - static GetDeviceVendor ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetDeviceVendor$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetDeviceVendor$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -646,20 +922,32 @@ static GetDeviceVendor ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetDeviceVendor$VH() { return IOUSBInterfaceStruct190.GetDeviceVendor$VH; } - public static MemoryAddress GetDeviceVendor$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetDeviceVendor$VH.get(seg); - } - public static void GetDeviceVendor$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetDeviceVendor)(void*,UInt16*); + * } + */ + public static MemorySegment GetDeviceVendor$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetDeviceVendor$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetDeviceVendor)(void*,UInt16*); + * } + */ + public static void GetDeviceVendor$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetDeviceVendor$VH.set(seg, x); } - public static MemoryAddress GetDeviceVendor$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetDeviceVendor$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetDeviceVendor$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetDeviceVendor$VH.get(seg.asSlice(index*sizeof())); } - public static void GetDeviceVendor$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetDeviceVendor$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetDeviceVendor$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceVendor GetDeviceVendor (MemorySegment segment, MemorySession session) { - return GetDeviceVendor.ofAddress(GetDeviceVendor$get(segment), session); + public static GetDeviceVendor GetDeviceVendor(MemorySegment segment, SegmentScope scope) { + return GetDeviceVendor.ofAddress(GetDeviceVendor$get(segment), scope); } static final FunctionDescriptor GetDeviceProduct$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -668,17 +956,22 @@ public static GetDeviceVendor GetDeviceVendor (MemorySegment segment, MemorySess static final MethodHandle GetDeviceProduct$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetDeviceProduct$FUNC ); + /** + * {@snippet : + * IOReturn (*GetDeviceProduct)(void*,UInt16*); + * } + */ public interface GetDeviceProduct { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceProduct fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceProduct.class, fi, IOUSBInterfaceStruct190.GetDeviceProduct$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetDeviceProduct fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetDeviceProduct.class, fi, IOUSBInterfaceStruct190.GetDeviceProduct$FUNC, scope); } - static GetDeviceProduct ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetDeviceProduct$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetDeviceProduct$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -690,20 +983,32 @@ static GetDeviceProduct ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetDeviceProduct$VH() { return IOUSBInterfaceStruct190.GetDeviceProduct$VH; } - public static MemoryAddress GetDeviceProduct$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetDeviceProduct$VH.get(seg); - } - public static void GetDeviceProduct$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetDeviceProduct)(void*,UInt16*); + * } + */ + public static MemorySegment GetDeviceProduct$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetDeviceProduct$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetDeviceProduct)(void*,UInt16*); + * } + */ + public static void GetDeviceProduct$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetDeviceProduct$VH.set(seg, x); } - public static MemoryAddress GetDeviceProduct$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetDeviceProduct$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetDeviceProduct$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetDeviceProduct$VH.get(seg.asSlice(index*sizeof())); } - public static void GetDeviceProduct$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetDeviceProduct$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetDeviceProduct$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceProduct GetDeviceProduct (MemorySegment segment, MemorySession session) { - return GetDeviceProduct.ofAddress(GetDeviceProduct$get(segment), session); + public static GetDeviceProduct GetDeviceProduct(MemorySegment segment, SegmentScope scope) { + return GetDeviceProduct.ofAddress(GetDeviceProduct$get(segment), scope); } static final FunctionDescriptor GetDeviceReleaseNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -712,17 +1017,22 @@ public static GetDeviceProduct GetDeviceProduct (MemorySegment segment, MemorySe static final MethodHandle GetDeviceReleaseNumber$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetDeviceReleaseNumber$FUNC ); + /** + * {@snippet : + * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); + * } + */ public interface GetDeviceReleaseNumber { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDeviceReleaseNumber fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDeviceReleaseNumber.class, fi, IOUSBInterfaceStruct190.GetDeviceReleaseNumber$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetDeviceReleaseNumber fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetDeviceReleaseNumber.class, fi, IOUSBInterfaceStruct190.GetDeviceReleaseNumber$FUNC, scope); } - static GetDeviceReleaseNumber ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetDeviceReleaseNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetDeviceReleaseNumber$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -734,20 +1044,32 @@ static GetDeviceReleaseNumber ofAddress(MemoryAddress addr, MemorySession sessio public static VarHandle GetDeviceReleaseNumber$VH() { return IOUSBInterfaceStruct190.GetDeviceReleaseNumber$VH; } - public static MemoryAddress GetDeviceReleaseNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetDeviceReleaseNumber$VH.get(seg); - } - public static void GetDeviceReleaseNumber$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); + * } + */ + public static MemorySegment GetDeviceReleaseNumber$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetDeviceReleaseNumber$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); + * } + */ + public static void GetDeviceReleaseNumber$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetDeviceReleaseNumber$VH.set(seg, x); } - public static MemoryAddress GetDeviceReleaseNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetDeviceReleaseNumber$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetDeviceReleaseNumber$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetDeviceReleaseNumber$VH.get(seg.asSlice(index*sizeof())); } - public static void GetDeviceReleaseNumber$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetDeviceReleaseNumber$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetDeviceReleaseNumber$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceReleaseNumber GetDeviceReleaseNumber (MemorySegment segment, MemorySession session) { - return GetDeviceReleaseNumber.ofAddress(GetDeviceReleaseNumber$get(segment), session); + public static GetDeviceReleaseNumber GetDeviceReleaseNumber(MemorySegment segment, SegmentScope scope) { + return GetDeviceReleaseNumber.ofAddress(GetDeviceReleaseNumber$get(segment), scope); } static final FunctionDescriptor GetConfigurationValue$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -756,17 +1078,22 @@ public static GetDeviceReleaseNumber GetDeviceReleaseNumber (MemorySegment segme static final MethodHandle GetConfigurationValue$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetConfigurationValue$FUNC ); + /** + * {@snippet : + * IOReturn (*GetConfigurationValue)(void*,UInt8*); + * } + */ public interface GetConfigurationValue { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetConfigurationValue fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetConfigurationValue.class, fi, IOUSBInterfaceStruct190.GetConfigurationValue$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetConfigurationValue fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetConfigurationValue.class, fi, IOUSBInterfaceStruct190.GetConfigurationValue$FUNC, scope); } - static GetConfigurationValue ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetConfigurationValue ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetConfigurationValue$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetConfigurationValue$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -778,20 +1105,32 @@ static GetConfigurationValue ofAddress(MemoryAddress addr, MemorySession session public static VarHandle GetConfigurationValue$VH() { return IOUSBInterfaceStruct190.GetConfigurationValue$VH; } - public static MemoryAddress GetConfigurationValue$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetConfigurationValue$VH.get(seg); - } - public static void GetConfigurationValue$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetConfigurationValue)(void*,UInt8*); + * } + */ + public static MemorySegment GetConfigurationValue$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetConfigurationValue$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetConfigurationValue)(void*,UInt8*); + * } + */ + public static void GetConfigurationValue$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetConfigurationValue$VH.set(seg, x); } - public static MemoryAddress GetConfigurationValue$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetConfigurationValue$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetConfigurationValue$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetConfigurationValue$VH.get(seg.asSlice(index*sizeof())); } - public static void GetConfigurationValue$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetConfigurationValue$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetConfigurationValue$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetConfigurationValue GetConfigurationValue (MemorySegment segment, MemorySession session) { - return GetConfigurationValue.ofAddress(GetConfigurationValue$get(segment), session); + public static GetConfigurationValue GetConfigurationValue(MemorySegment segment, SegmentScope scope) { + return GetConfigurationValue.ofAddress(GetConfigurationValue$get(segment), scope); } static final FunctionDescriptor GetInterfaceNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -800,17 +1139,22 @@ public static GetConfigurationValue GetConfigurationValue (MemorySegment segment static final MethodHandle GetInterfaceNumber$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetInterfaceNumber$FUNC ); + /** + * {@snippet : + * IOReturn (*GetInterfaceNumber)(void*,UInt8*); + * } + */ public interface GetInterfaceNumber { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetInterfaceNumber fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetInterfaceNumber.class, fi, IOUSBInterfaceStruct190.GetInterfaceNumber$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetInterfaceNumber fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetInterfaceNumber.class, fi, IOUSBInterfaceStruct190.GetInterfaceNumber$FUNC, scope); } - static GetInterfaceNumber ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetInterfaceNumber ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetInterfaceNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetInterfaceNumber$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -822,20 +1166,32 @@ static GetInterfaceNumber ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetInterfaceNumber$VH() { return IOUSBInterfaceStruct190.GetInterfaceNumber$VH; } - public static MemoryAddress GetInterfaceNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceNumber$VH.get(seg); - } - public static void GetInterfaceNumber$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetInterfaceNumber)(void*,UInt8*); + * } + */ + public static MemorySegment GetInterfaceNumber$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceNumber$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetInterfaceNumber)(void*,UInt8*); + * } + */ + public static void GetInterfaceNumber$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetInterfaceNumber$VH.set(seg, x); } - public static MemoryAddress GetInterfaceNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetInterfaceNumber$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetInterfaceNumber$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceNumber$VH.get(seg.asSlice(index*sizeof())); } - public static void GetInterfaceNumber$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetInterfaceNumber$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetInterfaceNumber$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetInterfaceNumber GetInterfaceNumber (MemorySegment segment, MemorySession session) { - return GetInterfaceNumber.ofAddress(GetInterfaceNumber$get(segment), session); + public static GetInterfaceNumber GetInterfaceNumber(MemorySegment segment, SegmentScope scope) { + return GetInterfaceNumber.ofAddress(GetInterfaceNumber$get(segment), scope); } static final FunctionDescriptor GetAlternateSetting$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -844,17 +1200,22 @@ public static GetInterfaceNumber GetInterfaceNumber (MemorySegment segment, Memo static final MethodHandle GetAlternateSetting$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetAlternateSetting$FUNC ); + /** + * {@snippet : + * IOReturn (*GetAlternateSetting)(void*,UInt8*); + * } + */ public interface GetAlternateSetting { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetAlternateSetting fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetAlternateSetting.class, fi, IOUSBInterfaceStruct190.GetAlternateSetting$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetAlternateSetting fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetAlternateSetting.class, fi, IOUSBInterfaceStruct190.GetAlternateSetting$FUNC, scope); } - static GetAlternateSetting ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetAlternateSetting ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetAlternateSetting$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetAlternateSetting$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -866,20 +1227,32 @@ static GetAlternateSetting ofAddress(MemoryAddress addr, MemorySession session) public static VarHandle GetAlternateSetting$VH() { return IOUSBInterfaceStruct190.GetAlternateSetting$VH; } - public static MemoryAddress GetAlternateSetting$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetAlternateSetting$VH.get(seg); - } - public static void GetAlternateSetting$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetAlternateSetting)(void*,UInt8*); + * } + */ + public static MemorySegment GetAlternateSetting$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetAlternateSetting$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetAlternateSetting)(void*,UInt8*); + * } + */ + public static void GetAlternateSetting$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetAlternateSetting$VH.set(seg, x); } - public static MemoryAddress GetAlternateSetting$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetAlternateSetting$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetAlternateSetting$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetAlternateSetting$VH.get(seg.asSlice(index*sizeof())); } - public static void GetAlternateSetting$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetAlternateSetting$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetAlternateSetting$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetAlternateSetting GetAlternateSetting (MemorySegment segment, MemorySession session) { - return GetAlternateSetting.ofAddress(GetAlternateSetting$get(segment), session); + public static GetAlternateSetting GetAlternateSetting(MemorySegment segment, SegmentScope scope) { + return GetAlternateSetting.ofAddress(GetAlternateSetting$get(segment), scope); } static final FunctionDescriptor GetNumEndpoints$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -888,17 +1261,22 @@ public static GetAlternateSetting GetAlternateSetting (MemorySegment segment, Me static final MethodHandle GetNumEndpoints$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetNumEndpoints$FUNC ); + /** + * {@snippet : + * IOReturn (*GetNumEndpoints)(void*,UInt8*); + * } + */ public interface GetNumEndpoints { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetNumEndpoints fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetNumEndpoints.class, fi, IOUSBInterfaceStruct190.GetNumEndpoints$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetNumEndpoints fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetNumEndpoints.class, fi, IOUSBInterfaceStruct190.GetNumEndpoints$FUNC, scope); } - static GetNumEndpoints ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetNumEndpoints ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetNumEndpoints$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetNumEndpoints$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -910,20 +1288,32 @@ static GetNumEndpoints ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetNumEndpoints$VH() { return IOUSBInterfaceStruct190.GetNumEndpoints$VH; } - public static MemoryAddress GetNumEndpoints$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetNumEndpoints$VH.get(seg); - } - public static void GetNumEndpoints$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetNumEndpoints)(void*,UInt8*); + * } + */ + public static MemorySegment GetNumEndpoints$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetNumEndpoints$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetNumEndpoints)(void*,UInt8*); + * } + */ + public static void GetNumEndpoints$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetNumEndpoints$VH.set(seg, x); } - public static MemoryAddress GetNumEndpoints$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetNumEndpoints$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetNumEndpoints$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetNumEndpoints$VH.get(seg.asSlice(index*sizeof())); } - public static void GetNumEndpoints$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetNumEndpoints$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetNumEndpoints$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetNumEndpoints GetNumEndpoints (MemorySegment segment, MemorySession session) { - return GetNumEndpoints.ofAddress(GetNumEndpoints$get(segment), session); + public static GetNumEndpoints GetNumEndpoints(MemorySegment segment, SegmentScope scope) { + return GetNumEndpoints.ofAddress(GetNumEndpoints$get(segment), scope); } static final FunctionDescriptor GetLocationID$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -932,17 +1322,22 @@ public static GetNumEndpoints GetNumEndpoints (MemorySegment segment, MemorySess static final MethodHandle GetLocationID$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetLocationID$FUNC ); + /** + * {@snippet : + * IOReturn (*GetLocationID)(void*,UInt32*); + * } + */ public interface GetLocationID { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetLocationID fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetLocationID.class, fi, IOUSBInterfaceStruct190.GetLocationID$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetLocationID fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetLocationID.class, fi, IOUSBInterfaceStruct190.GetLocationID$FUNC, scope); } - static GetLocationID ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetLocationID$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetLocationID$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -954,20 +1349,32 @@ static GetLocationID ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetLocationID$VH() { return IOUSBInterfaceStruct190.GetLocationID$VH; } - public static MemoryAddress GetLocationID$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetLocationID$VH.get(seg); - } - public static void GetLocationID$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetLocationID)(void*,UInt32*); + * } + */ + public static MemorySegment GetLocationID$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetLocationID$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetLocationID)(void*,UInt32*); + * } + */ + public static void GetLocationID$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetLocationID$VH.set(seg, x); } - public static MemoryAddress GetLocationID$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetLocationID$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetLocationID$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetLocationID$VH.get(seg.asSlice(index*sizeof())); } - public static void GetLocationID$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetLocationID$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetLocationID$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetLocationID GetLocationID (MemorySegment segment, MemorySession session) { - return GetLocationID.ofAddress(GetLocationID$get(segment), session); + public static GetLocationID GetLocationID(MemorySegment segment, SegmentScope scope) { + return GetLocationID.ofAddress(GetLocationID$get(segment), scope); } static final FunctionDescriptor GetDevice$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -976,17 +1383,22 @@ public static GetLocationID GetLocationID (MemorySegment segment, MemorySession static final MethodHandle GetDevice$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetDevice$FUNC ); + /** + * {@snippet : + * IOReturn (*GetDevice)(void*,io_service_t*); + * } + */ public interface GetDevice { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetDevice fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetDevice.class, fi, IOUSBInterfaceStruct190.GetDevice$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetDevice fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetDevice.class, fi, IOUSBInterfaceStruct190.GetDevice$FUNC, scope); } - static GetDevice ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetDevice ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetDevice$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetDevice$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -998,20 +1410,32 @@ static GetDevice ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetDevice$VH() { return IOUSBInterfaceStruct190.GetDevice$VH; } - public static MemoryAddress GetDevice$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetDevice$VH.get(seg); - } - public static void GetDevice$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetDevice)(void*,io_service_t*); + * } + */ + public static MemorySegment GetDevice$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetDevice$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetDevice)(void*,io_service_t*); + * } + */ + public static void GetDevice$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetDevice$VH.set(seg, x); } - public static MemoryAddress GetDevice$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetDevice$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetDevice$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetDevice$VH.get(seg.asSlice(index*sizeof())); } - public static void GetDevice$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetDevice$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetDevice$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetDevice GetDevice (MemorySegment segment, MemorySession session) { - return GetDevice.ofAddress(GetDevice$get(segment), session); + public static GetDevice GetDevice(MemorySegment segment, SegmentScope scope) { + return GetDevice.ofAddress(GetDevice$get(segment), scope); } static final FunctionDescriptor SetAlternateInterface$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1020,17 +1444,22 @@ public static GetDevice GetDevice (MemorySegment segment, MemorySession session) static final MethodHandle SetAlternateInterface$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.SetAlternateInterface$FUNC ); + /** + * {@snippet : + * IOReturn (*SetAlternateInterface)(void*,UInt8); + * } + */ public interface SetAlternateInterface { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); - static MemorySegment allocate(SetAlternateInterface fi, MemorySession session) { - return RuntimeHelper.upcallStub(SetAlternateInterface.class, fi, IOUSBInterfaceStruct190.SetAlternateInterface$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1); + static MemorySegment allocate(SetAlternateInterface fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(SetAlternateInterface.class, fi, IOUSBInterfaceStruct190.SetAlternateInterface$FUNC, scope); } - static SetAlternateInterface ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { + static SetAlternateInterface ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct190.SetAlternateInterface$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + return (int)IOUSBInterfaceStruct190.SetAlternateInterface$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1042,20 +1471,32 @@ static SetAlternateInterface ofAddress(MemoryAddress addr, MemorySession session public static VarHandle SetAlternateInterface$VH() { return IOUSBInterfaceStruct190.SetAlternateInterface$VH; } - public static MemoryAddress SetAlternateInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.SetAlternateInterface$VH.get(seg); - } - public static void SetAlternateInterface$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*SetAlternateInterface)(void*,UInt8); + * } + */ + public static MemorySegment SetAlternateInterface$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.SetAlternateInterface$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*SetAlternateInterface)(void*,UInt8); + * } + */ + public static void SetAlternateInterface$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.SetAlternateInterface$VH.set(seg, x); } - public static MemoryAddress SetAlternateInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.SetAlternateInterface$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment SetAlternateInterface$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.SetAlternateInterface$VH.get(seg.asSlice(index*sizeof())); } - public static void SetAlternateInterface$set(MemorySegment seg, long index, MemoryAddress x) { + public static void SetAlternateInterface$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.SetAlternateInterface$VH.set(seg.asSlice(index*sizeof()), x); } - public static SetAlternateInterface SetAlternateInterface (MemorySegment segment, MemorySession session) { - return SetAlternateInterface.ofAddress(SetAlternateInterface$get(segment), session); + public static SetAlternateInterface SetAlternateInterface(MemorySegment segment, SegmentScope scope) { + return SetAlternateInterface.ofAddress(SetAlternateInterface$get(segment), scope); } static final FunctionDescriptor GetBusFrameNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1065,17 +1506,22 @@ public static SetAlternateInterface SetAlternateInterface (MemorySegment segment static final MethodHandle GetBusFrameNumber$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetBusFrameNumber$FUNC ); + /** + * {@snippet : + * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); + * } + */ public interface GetBusFrameNumber { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(GetBusFrameNumber fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetBusFrameNumber.class, fi, IOUSBInterfaceStruct190.GetBusFrameNumber$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); + static MemorySegment allocate(GetBusFrameNumber fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetBusFrameNumber.class, fi, IOUSBInterfaceStruct190.GetBusFrameNumber$FUNC, scope); } - static GetBusFrameNumber ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1, java.lang.foreign.MemoryAddress __x2) -> { + static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBInterfaceStruct190.GetBusFrameNumber$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1, (java.lang.foreign.Addressable)__x2); + return (int)IOUSBInterfaceStruct190.GetBusFrameNumber$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1087,20 +1533,32 @@ static GetBusFrameNumber ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetBusFrameNumber$VH() { return IOUSBInterfaceStruct190.GetBusFrameNumber$VH; } - public static MemoryAddress GetBusFrameNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetBusFrameNumber$VH.get(seg); - } - public static void GetBusFrameNumber$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); + * } + */ + public static MemorySegment GetBusFrameNumber$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetBusFrameNumber$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); + * } + */ + public static void GetBusFrameNumber$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetBusFrameNumber$VH.set(seg, x); } - public static MemoryAddress GetBusFrameNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetBusFrameNumber$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetBusFrameNumber$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetBusFrameNumber$VH.get(seg.asSlice(index*sizeof())); } - public static void GetBusFrameNumber$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetBusFrameNumber$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetBusFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetBusFrameNumber GetBusFrameNumber (MemorySegment segment, MemorySession session) { - return GetBusFrameNumber.ofAddress(GetBusFrameNumber$get(segment), session); + public static GetBusFrameNumber GetBusFrameNumber(MemorySegment segment, SegmentScope scope) { + return GetBusFrameNumber.ofAddress(GetBusFrameNumber$get(segment), scope); } static final FunctionDescriptor ControlRequest$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1110,17 +1568,22 @@ public static GetBusFrameNumber GetBusFrameNumber (MemorySegment segment, Memory static final MethodHandle ControlRequest$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.ControlRequest$FUNC ); + /** + * {@snippet : + * IOReturn (*ControlRequest)(void*,UInt8,IOUSBDevRequest*); + * } + */ public interface ControlRequest { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(ControlRequest fi, MemorySession session) { - return RuntimeHelper.upcallStub(ControlRequest.class, fi, IOUSBInterfaceStruct190.ControlRequest$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2); + static MemorySegment allocate(ControlRequest fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(ControlRequest.class, fi, IOUSBInterfaceStruct190.ControlRequest$FUNC, scope); } - static ControlRequest ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2) -> { + static ControlRequest ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBInterfaceStruct190.ControlRequest$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + return (int)IOUSBInterfaceStruct190.ControlRequest$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1132,20 +1595,32 @@ static ControlRequest ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle ControlRequest$VH() { return IOUSBInterfaceStruct190.ControlRequest$VH; } - public static MemoryAddress ControlRequest$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ControlRequest$VH.get(seg); - } - public static void ControlRequest$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*ControlRequest)(void*,UInt8,IOUSBDevRequest*); + * } + */ + public static MemorySegment ControlRequest$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ControlRequest$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*ControlRequest)(void*,UInt8,IOUSBDevRequest*); + * } + */ + public static void ControlRequest$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.ControlRequest$VH.set(seg, x); } - public static MemoryAddress ControlRequest$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ControlRequest$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment ControlRequest$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ControlRequest$VH.get(seg.asSlice(index*sizeof())); } - public static void ControlRequest$set(MemorySegment seg, long index, MemoryAddress x) { + public static void ControlRequest$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.ControlRequest$VH.set(seg.asSlice(index*sizeof()), x); } - public static ControlRequest ControlRequest (MemorySegment segment, MemorySession session) { - return ControlRequest.ofAddress(ControlRequest$get(segment), session); + public static ControlRequest ControlRequest(MemorySegment segment, SegmentScope scope) { + return ControlRequest.ofAddress(ControlRequest$get(segment), scope); } static final FunctionDescriptor ControlRequestAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1157,17 +1632,22 @@ public static ControlRequest ControlRequest (MemorySegment segment, MemorySessio static final MethodHandle ControlRequestAsync$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.ControlRequestAsync$FUNC ); + /** + * {@snippet : + * IOReturn (*ControlRequestAsync)(void*,UInt8,IOUSBDevRequest*,IOAsyncCallback1,void*); + * } + */ public interface ControlRequestAsync { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, java.lang.foreign.MemoryAddress _x4); - static MemorySegment allocate(ControlRequestAsync fi, MemorySession session) { - return RuntimeHelper.upcallStub(ControlRequestAsync.class, fi, IOUSBInterfaceStruct190.ControlRequestAsync$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3, java.lang.foreign.MemorySegment _x4); + static MemorySegment allocate(ControlRequestAsync fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(ControlRequestAsync.class, fi, IOUSBInterfaceStruct190.ControlRequestAsync$FUNC, scope); } - static ControlRequestAsync ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, java.lang.foreign.MemoryAddress __x4) -> { + static ControlRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3, java.lang.foreign.MemorySegment __x4) -> { try { - return (int)IOUSBInterfaceStruct190.ControlRequestAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4); + return (int)IOUSBInterfaceStruct190.ControlRequestAsync$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1179,20 +1659,32 @@ static ControlRequestAsync ofAddress(MemoryAddress addr, MemorySession session) public static VarHandle ControlRequestAsync$VH() { return IOUSBInterfaceStruct190.ControlRequestAsync$VH; } - public static MemoryAddress ControlRequestAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ControlRequestAsync$VH.get(seg); - } - public static void ControlRequestAsync$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*ControlRequestAsync)(void*,UInt8,IOUSBDevRequest*,IOAsyncCallback1,void*); + * } + */ + public static MemorySegment ControlRequestAsync$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ControlRequestAsync$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*ControlRequestAsync)(void*,UInt8,IOUSBDevRequest*,IOAsyncCallback1,void*); + * } + */ + public static void ControlRequestAsync$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.ControlRequestAsync$VH.set(seg, x); } - public static MemoryAddress ControlRequestAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ControlRequestAsync$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment ControlRequestAsync$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ControlRequestAsync$VH.get(seg.asSlice(index*sizeof())); } - public static void ControlRequestAsync$set(MemorySegment seg, long index, MemoryAddress x) { + public static void ControlRequestAsync$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.ControlRequestAsync$VH.set(seg.asSlice(index*sizeof()), x); } - public static ControlRequestAsync ControlRequestAsync (MemorySegment segment, MemorySession session) { - return ControlRequestAsync.ofAddress(ControlRequestAsync$get(segment), session); + public static ControlRequestAsync ControlRequestAsync(MemorySegment segment, SegmentScope scope) { + return ControlRequestAsync.ofAddress(ControlRequestAsync$get(segment), scope); } static final FunctionDescriptor GetPipeProperties$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1206,17 +1698,22 @@ public static ControlRequestAsync ControlRequestAsync (MemorySegment segment, Me static final MethodHandle GetPipeProperties$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetPipeProperties$FUNC ); + /** + * {@snippet : + * IOReturn (*GetPipeProperties)(void*,UInt8,UInt8*,UInt8*,UInt8*,UInt16*,UInt8*); + * } + */ public interface GetPipeProperties { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, java.lang.foreign.MemoryAddress _x4, java.lang.foreign.MemoryAddress _x5, java.lang.foreign.MemoryAddress _x6); - static MemorySegment allocate(GetPipeProperties fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetPipeProperties.class, fi, IOUSBInterfaceStruct190.GetPipeProperties$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3, java.lang.foreign.MemorySegment _x4, java.lang.foreign.MemorySegment _x5, java.lang.foreign.MemorySegment _x6); + static MemorySegment allocate(GetPipeProperties fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetPipeProperties.class, fi, IOUSBInterfaceStruct190.GetPipeProperties$FUNC, scope); } - static GetPipeProperties ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, java.lang.foreign.MemoryAddress __x4, java.lang.foreign.MemoryAddress __x5, java.lang.foreign.MemoryAddress __x6) -> { + static GetPipeProperties ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3, java.lang.foreign.MemorySegment __x4, java.lang.foreign.MemorySegment __x5, java.lang.foreign.MemorySegment __x6) -> { try { - return (int)IOUSBInterfaceStruct190.GetPipeProperties$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6); + return (int)IOUSBInterfaceStruct190.GetPipeProperties$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1228,20 +1725,32 @@ static GetPipeProperties ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetPipeProperties$VH() { return IOUSBInterfaceStruct190.GetPipeProperties$VH; } - public static MemoryAddress GetPipeProperties$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetPipeProperties$VH.get(seg); - } - public static void GetPipeProperties$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetPipeProperties)(void*,UInt8,UInt8*,UInt8*,UInt8*,UInt16*,UInt8*); + * } + */ + public static MemorySegment GetPipeProperties$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetPipeProperties$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetPipeProperties)(void*,UInt8,UInt8*,UInt8*,UInt8*,UInt16*,UInt8*); + * } + */ + public static void GetPipeProperties$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetPipeProperties$VH.set(seg, x); } - public static MemoryAddress GetPipeProperties$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetPipeProperties$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetPipeProperties$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetPipeProperties$VH.get(seg.asSlice(index*sizeof())); } - public static void GetPipeProperties$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetPipeProperties$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetPipeProperties$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetPipeProperties GetPipeProperties (MemorySegment segment, MemorySession session) { - return GetPipeProperties.ofAddress(GetPipeProperties$get(segment), session); + public static GetPipeProperties GetPipeProperties(MemorySegment segment, SegmentScope scope) { + return GetPipeProperties.ofAddress(GetPipeProperties$get(segment), scope); } static final FunctionDescriptor GetPipeStatus$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1250,17 +1759,22 @@ public static GetPipeProperties GetPipeProperties (MemorySegment segment, Memory static final MethodHandle GetPipeStatus$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetPipeStatus$FUNC ); + /** + * {@snippet : + * IOReturn (*GetPipeStatus)(void*,UInt8); + * } + */ public interface GetPipeStatus { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); - static MemorySegment allocate(GetPipeStatus fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetPipeStatus.class, fi, IOUSBInterfaceStruct190.GetPipeStatus$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1); + static MemorySegment allocate(GetPipeStatus fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetPipeStatus.class, fi, IOUSBInterfaceStruct190.GetPipeStatus$FUNC, scope); } - static GetPipeStatus ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { + static GetPipeStatus ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetPipeStatus$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + return (int)IOUSBInterfaceStruct190.GetPipeStatus$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1272,20 +1786,32 @@ static GetPipeStatus ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle GetPipeStatus$VH() { return IOUSBInterfaceStruct190.GetPipeStatus$VH; } - public static MemoryAddress GetPipeStatus$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetPipeStatus$VH.get(seg); - } - public static void GetPipeStatus$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetPipeStatus)(void*,UInt8); + * } + */ + public static MemorySegment GetPipeStatus$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetPipeStatus$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetPipeStatus)(void*,UInt8); + * } + */ + public static void GetPipeStatus$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetPipeStatus$VH.set(seg, x); } - public static MemoryAddress GetPipeStatus$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetPipeStatus$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetPipeStatus$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetPipeStatus$VH.get(seg.asSlice(index*sizeof())); } - public static void GetPipeStatus$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetPipeStatus$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetPipeStatus$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetPipeStatus GetPipeStatus (MemorySegment segment, MemorySession session) { - return GetPipeStatus.ofAddress(GetPipeStatus$get(segment), session); + public static GetPipeStatus GetPipeStatus(MemorySegment segment, SegmentScope scope) { + return GetPipeStatus.ofAddress(GetPipeStatus$get(segment), scope); } static final FunctionDescriptor AbortPipe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1294,17 +1820,22 @@ public static GetPipeStatus GetPipeStatus (MemorySegment segment, MemorySession static final MethodHandle AbortPipe$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.AbortPipe$FUNC ); + /** + * {@snippet : + * IOReturn (*AbortPipe)(void*,UInt8); + * } + */ public interface AbortPipe { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); - static MemorySegment allocate(AbortPipe fi, MemorySession session) { - return RuntimeHelper.upcallStub(AbortPipe.class, fi, IOUSBInterfaceStruct190.AbortPipe$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1); + static MemorySegment allocate(AbortPipe fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(AbortPipe.class, fi, IOUSBInterfaceStruct190.AbortPipe$FUNC, scope); } - static AbortPipe ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { + static AbortPipe ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct190.AbortPipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + return (int)IOUSBInterfaceStruct190.AbortPipe$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1316,20 +1847,32 @@ static AbortPipe ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle AbortPipe$VH() { return IOUSBInterfaceStruct190.AbortPipe$VH; } - public static MemoryAddress AbortPipe$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.AbortPipe$VH.get(seg); - } - public static void AbortPipe$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*AbortPipe)(void*,UInt8); + * } + */ + public static MemorySegment AbortPipe$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.AbortPipe$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*AbortPipe)(void*,UInt8); + * } + */ + public static void AbortPipe$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.AbortPipe$VH.set(seg, x); } - public static MemoryAddress AbortPipe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.AbortPipe$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment AbortPipe$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.AbortPipe$VH.get(seg.asSlice(index*sizeof())); } - public static void AbortPipe$set(MemorySegment seg, long index, MemoryAddress x) { + public static void AbortPipe$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.AbortPipe$VH.set(seg.asSlice(index*sizeof()), x); } - public static AbortPipe AbortPipe (MemorySegment segment, MemorySession session) { - return AbortPipe.ofAddress(AbortPipe$get(segment), session); + public static AbortPipe AbortPipe(MemorySegment segment, SegmentScope scope) { + return AbortPipe.ofAddress(AbortPipe$get(segment), scope); } static final FunctionDescriptor ResetPipe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1338,17 +1881,22 @@ public static AbortPipe AbortPipe (MemorySegment segment, MemorySession session) static final MethodHandle ResetPipe$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.ResetPipe$FUNC ); + /** + * {@snippet : + * IOReturn (*ResetPipe)(void*,UInt8); + * } + */ public interface ResetPipe { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); - static MemorySegment allocate(ResetPipe fi, MemorySession session) { - return RuntimeHelper.upcallStub(ResetPipe.class, fi, IOUSBInterfaceStruct190.ResetPipe$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1); + static MemorySegment allocate(ResetPipe fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(ResetPipe.class, fi, IOUSBInterfaceStruct190.ResetPipe$FUNC, scope); } - static ResetPipe ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { + static ResetPipe ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct190.ResetPipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + return (int)IOUSBInterfaceStruct190.ResetPipe$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1360,20 +1908,32 @@ static ResetPipe ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle ResetPipe$VH() { return IOUSBInterfaceStruct190.ResetPipe$VH; } - public static MemoryAddress ResetPipe$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ResetPipe$VH.get(seg); - } - public static void ResetPipe$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*ResetPipe)(void*,UInt8); + * } + */ + public static MemorySegment ResetPipe$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ResetPipe$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*ResetPipe)(void*,UInt8); + * } + */ + public static void ResetPipe$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.ResetPipe$VH.set(seg, x); } - public static MemoryAddress ResetPipe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ResetPipe$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment ResetPipe$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ResetPipe$VH.get(seg.asSlice(index*sizeof())); } - public static void ResetPipe$set(MemorySegment seg, long index, MemoryAddress x) { + public static void ResetPipe$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.ResetPipe$VH.set(seg.asSlice(index*sizeof()), x); } - public static ResetPipe ResetPipe (MemorySegment segment, MemorySession session) { - return ResetPipe.ofAddress(ResetPipe$get(segment), session); + public static ResetPipe ResetPipe(MemorySegment segment, SegmentScope scope) { + return ResetPipe.ofAddress(ResetPipe$get(segment), scope); } static final FunctionDescriptor ClearPipeStall$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1382,17 +1942,22 @@ public static ResetPipe ResetPipe (MemorySegment segment, MemorySession session) static final MethodHandle ClearPipeStall$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.ClearPipeStall$FUNC ); + /** + * {@snippet : + * IOReturn (*ClearPipeStall)(void*,UInt8); + * } + */ public interface ClearPipeStall { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); - static MemorySegment allocate(ClearPipeStall fi, MemorySession session) { - return RuntimeHelper.upcallStub(ClearPipeStall.class, fi, IOUSBInterfaceStruct190.ClearPipeStall$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1); + static MemorySegment allocate(ClearPipeStall fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(ClearPipeStall.class, fi, IOUSBInterfaceStruct190.ClearPipeStall$FUNC, scope); } - static ClearPipeStall ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { + static ClearPipeStall ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct190.ClearPipeStall$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + return (int)IOUSBInterfaceStruct190.ClearPipeStall$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1404,20 +1969,32 @@ static ClearPipeStall ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle ClearPipeStall$VH() { return IOUSBInterfaceStruct190.ClearPipeStall$VH; } - public static MemoryAddress ClearPipeStall$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ClearPipeStall$VH.get(seg); - } - public static void ClearPipeStall$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*ClearPipeStall)(void*,UInt8); + * } + */ + public static MemorySegment ClearPipeStall$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ClearPipeStall$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*ClearPipeStall)(void*,UInt8); + * } + */ + public static void ClearPipeStall$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.ClearPipeStall$VH.set(seg, x); } - public static MemoryAddress ClearPipeStall$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ClearPipeStall$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment ClearPipeStall$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ClearPipeStall$VH.get(seg.asSlice(index*sizeof())); } - public static void ClearPipeStall$set(MemorySegment seg, long index, MemoryAddress x) { + public static void ClearPipeStall$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.ClearPipeStall$VH.set(seg.asSlice(index*sizeof()), x); } - public static ClearPipeStall ClearPipeStall (MemorySegment segment, MemorySession session) { - return ClearPipeStall.ofAddress(ClearPipeStall$get(segment), session); + public static ClearPipeStall ClearPipeStall(MemorySegment segment, SegmentScope scope) { + return ClearPipeStall.ofAddress(ClearPipeStall$get(segment), scope); } static final FunctionDescriptor ReadPipe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1428,17 +2005,22 @@ public static ClearPipeStall ClearPipeStall (MemorySegment segment, MemorySessio static final MethodHandle ReadPipe$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.ReadPipe$FUNC ); + /** + * {@snippet : + * IOReturn (*ReadPipe)(void*,UInt8,void*,UInt32*); + * } + */ public interface ReadPipe { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3); - static MemorySegment allocate(ReadPipe fi, MemorySession session) { - return RuntimeHelper.upcallStub(ReadPipe.class, fi, IOUSBInterfaceStruct190.ReadPipe$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3); + static MemorySegment allocate(ReadPipe fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(ReadPipe.class, fi, IOUSBInterfaceStruct190.ReadPipe$FUNC, scope); } - static ReadPipe ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3) -> { + static ReadPipe ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3) -> { try { - return (int)IOUSBInterfaceStruct190.ReadPipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3); + return (int)IOUSBInterfaceStruct190.ReadPipe$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1450,20 +2032,32 @@ static ReadPipe ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle ReadPipe$VH() { return IOUSBInterfaceStruct190.ReadPipe$VH; } - public static MemoryAddress ReadPipe$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadPipe$VH.get(seg); - } - public static void ReadPipe$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*ReadPipe)(void*,UInt8,void*,UInt32*); + * } + */ + public static MemorySegment ReadPipe$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadPipe$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*ReadPipe)(void*,UInt8,void*,UInt32*); + * } + */ + public static void ReadPipe$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.ReadPipe$VH.set(seg, x); } - public static MemoryAddress ReadPipe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadPipe$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment ReadPipe$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadPipe$VH.get(seg.asSlice(index*sizeof())); } - public static void ReadPipe$set(MemorySegment seg, long index, MemoryAddress x) { + public static void ReadPipe$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.ReadPipe$VH.set(seg.asSlice(index*sizeof()), x); } - public static ReadPipe ReadPipe (MemorySegment segment, MemorySession session) { - return ReadPipe.ofAddress(ReadPipe$get(segment), session); + public static ReadPipe ReadPipe(MemorySegment segment, SegmentScope scope) { + return ReadPipe.ofAddress(ReadPipe$get(segment), scope); } static final FunctionDescriptor WritePipe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1474,17 +2068,22 @@ public static ReadPipe ReadPipe (MemorySegment segment, MemorySession session) { static final MethodHandle WritePipe$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.WritePipe$FUNC ); + /** + * {@snippet : + * IOReturn (*WritePipe)(void*,UInt8,void*,UInt32); + * } + */ public interface WritePipe { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3); - static MemorySegment allocate(WritePipe fi, MemorySession session) { - return RuntimeHelper.upcallStub(WritePipe.class, fi, IOUSBInterfaceStruct190.WritePipe$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3); + static MemorySegment allocate(WritePipe fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(WritePipe.class, fi, IOUSBInterfaceStruct190.WritePipe$FUNC, scope); } - static WritePipe ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3) -> { + static WritePipe ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3) -> { try { - return (int)IOUSBInterfaceStruct190.WritePipe$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3); + return (int)IOUSBInterfaceStruct190.WritePipe$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1496,20 +2095,32 @@ static WritePipe ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle WritePipe$VH() { return IOUSBInterfaceStruct190.WritePipe$VH; } - public static MemoryAddress WritePipe$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WritePipe$VH.get(seg); - } - public static void WritePipe$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*WritePipe)(void*,UInt8,void*,UInt32); + * } + */ + public static MemorySegment WritePipe$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WritePipe$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*WritePipe)(void*,UInt8,void*,UInt32); + * } + */ + public static void WritePipe$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.WritePipe$VH.set(seg, x); } - public static MemoryAddress WritePipe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WritePipe$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment WritePipe$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WritePipe$VH.get(seg.asSlice(index*sizeof())); } - public static void WritePipe$set(MemorySegment seg, long index, MemoryAddress x) { + public static void WritePipe$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.WritePipe$VH.set(seg.asSlice(index*sizeof()), x); } - public static WritePipe WritePipe (MemorySegment segment, MemorySession session) { - return WritePipe.ofAddress(WritePipe$get(segment), session); + public static WritePipe WritePipe(MemorySegment segment, SegmentScope scope) { + return WritePipe.ofAddress(WritePipe$get(segment), scope); } static final FunctionDescriptor ReadPipeAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1522,17 +2133,22 @@ public static WritePipe WritePipe (MemorySegment segment, MemorySession session) static final MethodHandle ReadPipeAsync$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.ReadPipeAsync$FUNC ); + /** + * {@snippet : + * IOReturn (*ReadPipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); + * } + */ public interface ReadPipeAsync { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3, java.lang.foreign.MemoryAddress _x4, java.lang.foreign.MemoryAddress _x5); - static MemorySegment allocate(ReadPipeAsync fi, MemorySession session) { - return RuntimeHelper.upcallStub(ReadPipeAsync.class, fi, IOUSBInterfaceStruct190.ReadPipeAsync$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3, java.lang.foreign.MemorySegment _x4, java.lang.foreign.MemorySegment _x5); + static MemorySegment allocate(ReadPipeAsync fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(ReadPipeAsync.class, fi, IOUSBInterfaceStruct190.ReadPipeAsync$FUNC, scope); } - static ReadPipeAsync ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3, java.lang.foreign.MemoryAddress __x4, java.lang.foreign.MemoryAddress __x5) -> { + static ReadPipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3, java.lang.foreign.MemorySegment __x4, java.lang.foreign.MemorySegment __x5) -> { try { - return (int)IOUSBInterfaceStruct190.ReadPipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5); + return (int)IOUSBInterfaceStruct190.ReadPipeAsync$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1544,20 +2160,32 @@ static ReadPipeAsync ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle ReadPipeAsync$VH() { return IOUSBInterfaceStruct190.ReadPipeAsync$VH; } - public static MemoryAddress ReadPipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadPipeAsync$VH.get(seg); - } - public static void ReadPipeAsync$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*ReadPipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); + * } + */ + public static MemorySegment ReadPipeAsync$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadPipeAsync$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*ReadPipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); + * } + */ + public static void ReadPipeAsync$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.ReadPipeAsync$VH.set(seg, x); } - public static MemoryAddress ReadPipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadPipeAsync$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment ReadPipeAsync$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadPipeAsync$VH.get(seg.asSlice(index*sizeof())); } - public static void ReadPipeAsync$set(MemorySegment seg, long index, MemoryAddress x) { + public static void ReadPipeAsync$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.ReadPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); } - public static ReadPipeAsync ReadPipeAsync (MemorySegment segment, MemorySession session) { - return ReadPipeAsync.ofAddress(ReadPipeAsync$get(segment), session); + public static ReadPipeAsync ReadPipeAsync(MemorySegment segment, SegmentScope scope) { + return ReadPipeAsync.ofAddress(ReadPipeAsync$get(segment), scope); } static final FunctionDescriptor WritePipeAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1570,17 +2198,22 @@ public static ReadPipeAsync ReadPipeAsync (MemorySegment segment, MemorySession static final MethodHandle WritePipeAsync$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.WritePipeAsync$FUNC ); + /** + * {@snippet : + * IOReturn (*WritePipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); + * } + */ public interface WritePipeAsync { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3, java.lang.foreign.MemoryAddress _x4, java.lang.foreign.MemoryAddress _x5); - static MemorySegment allocate(WritePipeAsync fi, MemorySession session) { - return RuntimeHelper.upcallStub(WritePipeAsync.class, fi, IOUSBInterfaceStruct190.WritePipeAsync$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3, java.lang.foreign.MemorySegment _x4, java.lang.foreign.MemorySegment _x5); + static MemorySegment allocate(WritePipeAsync fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(WritePipeAsync.class, fi, IOUSBInterfaceStruct190.WritePipeAsync$FUNC, scope); } - static WritePipeAsync ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3, java.lang.foreign.MemoryAddress __x4, java.lang.foreign.MemoryAddress __x5) -> { + static WritePipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3, java.lang.foreign.MemorySegment __x4, java.lang.foreign.MemorySegment __x5) -> { try { - return (int)IOUSBInterfaceStruct190.WritePipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5); + return (int)IOUSBInterfaceStruct190.WritePipeAsync$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1592,20 +2225,32 @@ static WritePipeAsync ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle WritePipeAsync$VH() { return IOUSBInterfaceStruct190.WritePipeAsync$VH; } - public static MemoryAddress WritePipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WritePipeAsync$VH.get(seg); - } - public static void WritePipeAsync$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*WritePipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); + * } + */ + public static MemorySegment WritePipeAsync$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WritePipeAsync$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*WritePipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); + * } + */ + public static void WritePipeAsync$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.WritePipeAsync$VH.set(seg, x); } - public static MemoryAddress WritePipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WritePipeAsync$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment WritePipeAsync$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WritePipeAsync$VH.get(seg.asSlice(index*sizeof())); } - public static void WritePipeAsync$set(MemorySegment seg, long index, MemoryAddress x) { + public static void WritePipeAsync$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.WritePipeAsync$VH.set(seg.asSlice(index*sizeof()), x); } - public static WritePipeAsync WritePipeAsync (MemorySegment segment, MemorySession session) { - return WritePipeAsync.ofAddress(WritePipeAsync$get(segment), session); + public static WritePipeAsync WritePipeAsync(MemorySegment segment, SegmentScope scope) { + return WritePipeAsync.ofAddress(WritePipeAsync$get(segment), scope); } static final FunctionDescriptor ReadIsochPipeAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1620,17 +2265,22 @@ public static WritePipeAsync WritePipeAsync (MemorySegment segment, MemorySessio static final MethodHandle ReadIsochPipeAsync$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.ReadIsochPipeAsync$FUNC ); + /** + * {@snippet : + * IOReturn (*ReadIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); + * } + */ public interface ReadIsochPipeAsync { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, long _x3, int _x4, java.lang.foreign.MemoryAddress _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7); - static MemorySegment allocate(ReadIsochPipeAsync fi, MemorySession session) { - return RuntimeHelper.upcallStub(ReadIsochPipeAsync.class, fi, IOUSBInterfaceStruct190.ReadIsochPipeAsync$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, long _x3, int _x4, java.lang.foreign.MemorySegment _x5, java.lang.foreign.MemorySegment _x6, java.lang.foreign.MemorySegment _x7); + static MemorySegment allocate(ReadIsochPipeAsync fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(ReadIsochPipeAsync.class, fi, IOUSBInterfaceStruct190.ReadIsochPipeAsync$FUNC, scope); } - static ReadIsochPipeAsync ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, long __x3, int __x4, java.lang.foreign.MemoryAddress __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7) -> { + static ReadIsochPipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, long __x3, int __x4, java.lang.foreign.MemorySegment __x5, java.lang.foreign.MemorySegment __x6, java.lang.foreign.MemorySegment __x7) -> { try { - return (int)IOUSBInterfaceStruct190.ReadIsochPipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7); + return (int)IOUSBInterfaceStruct190.ReadIsochPipeAsync$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1642,20 +2292,32 @@ static ReadIsochPipeAsync ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle ReadIsochPipeAsync$VH() { return IOUSBInterfaceStruct190.ReadIsochPipeAsync$VH; } - public static MemoryAddress ReadIsochPipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadIsochPipeAsync$VH.get(seg); - } - public static void ReadIsochPipeAsync$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*ReadIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); + * } + */ + public static MemorySegment ReadIsochPipeAsync$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadIsochPipeAsync$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*ReadIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); + * } + */ + public static void ReadIsochPipeAsync$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.ReadIsochPipeAsync$VH.set(seg, x); } - public static MemoryAddress ReadIsochPipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadIsochPipeAsync$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment ReadIsochPipeAsync$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadIsochPipeAsync$VH.get(seg.asSlice(index*sizeof())); } - public static void ReadIsochPipeAsync$set(MemorySegment seg, long index, MemoryAddress x) { + public static void ReadIsochPipeAsync$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.ReadIsochPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); } - public static ReadIsochPipeAsync ReadIsochPipeAsync (MemorySegment segment, MemorySession session) { - return ReadIsochPipeAsync.ofAddress(ReadIsochPipeAsync$get(segment), session); + public static ReadIsochPipeAsync ReadIsochPipeAsync(MemorySegment segment, SegmentScope scope) { + return ReadIsochPipeAsync.ofAddress(ReadIsochPipeAsync$get(segment), scope); } static final FunctionDescriptor WriteIsochPipeAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1670,17 +2332,22 @@ public static ReadIsochPipeAsync ReadIsochPipeAsync (MemorySegment segment, Memo static final MethodHandle WriteIsochPipeAsync$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.WriteIsochPipeAsync$FUNC ); + /** + * {@snippet : + * IOReturn (*WriteIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); + * } + */ public interface WriteIsochPipeAsync { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, long _x3, int _x4, java.lang.foreign.MemoryAddress _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7); - static MemorySegment allocate(WriteIsochPipeAsync fi, MemorySession session) { - return RuntimeHelper.upcallStub(WriteIsochPipeAsync.class, fi, IOUSBInterfaceStruct190.WriteIsochPipeAsync$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, long _x3, int _x4, java.lang.foreign.MemorySegment _x5, java.lang.foreign.MemorySegment _x6, java.lang.foreign.MemorySegment _x7); + static MemorySegment allocate(WriteIsochPipeAsync fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(WriteIsochPipeAsync.class, fi, IOUSBInterfaceStruct190.WriteIsochPipeAsync$FUNC, scope); } - static WriteIsochPipeAsync ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, long __x3, int __x4, java.lang.foreign.MemoryAddress __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7) -> { + static WriteIsochPipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, long __x3, int __x4, java.lang.foreign.MemorySegment __x5, java.lang.foreign.MemorySegment __x6, java.lang.foreign.MemorySegment __x7) -> { try { - return (int)IOUSBInterfaceStruct190.WriteIsochPipeAsync$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7); + return (int)IOUSBInterfaceStruct190.WriteIsochPipeAsync$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1692,20 +2359,32 @@ static WriteIsochPipeAsync ofAddress(MemoryAddress addr, MemorySession session) public static VarHandle WriteIsochPipeAsync$VH() { return IOUSBInterfaceStruct190.WriteIsochPipeAsync$VH; } - public static MemoryAddress WriteIsochPipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WriteIsochPipeAsync$VH.get(seg); - } - public static void WriteIsochPipeAsync$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*WriteIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); + * } + */ + public static MemorySegment WriteIsochPipeAsync$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WriteIsochPipeAsync$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*WriteIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); + * } + */ + public static void WriteIsochPipeAsync$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.WriteIsochPipeAsync$VH.set(seg, x); } - public static MemoryAddress WriteIsochPipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WriteIsochPipeAsync$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment WriteIsochPipeAsync$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WriteIsochPipeAsync$VH.get(seg.asSlice(index*sizeof())); } - public static void WriteIsochPipeAsync$set(MemorySegment seg, long index, MemoryAddress x) { + public static void WriteIsochPipeAsync$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.WriteIsochPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); } - public static WriteIsochPipeAsync WriteIsochPipeAsync (MemorySegment segment, MemorySession session) { - return WriteIsochPipeAsync.ofAddress(WriteIsochPipeAsync$get(segment), session); + public static WriteIsochPipeAsync WriteIsochPipeAsync(MemorySegment segment, SegmentScope scope) { + return WriteIsochPipeAsync.ofAddress(WriteIsochPipeAsync$get(segment), scope); } static final FunctionDescriptor ControlRequestTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1715,17 +2394,22 @@ public static WriteIsochPipeAsync WriteIsochPipeAsync (MemorySegment segment, Me static final MethodHandle ControlRequestTO$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.ControlRequestTO$FUNC ); + /** + * {@snippet : + * IOReturn (*ControlRequestTO)(void*,UInt8,IOUSBDevRequestTO*); + * } + */ public interface ControlRequestTO { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2); - static MemorySegment allocate(ControlRequestTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(ControlRequestTO.class, fi, IOUSBInterfaceStruct190.ControlRequestTO$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2); + static MemorySegment allocate(ControlRequestTO fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(ControlRequestTO.class, fi, IOUSBInterfaceStruct190.ControlRequestTO$FUNC, scope); } - static ControlRequestTO ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2) -> { + static ControlRequestTO ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBInterfaceStruct190.ControlRequestTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2); + return (int)IOUSBInterfaceStruct190.ControlRequestTO$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1737,20 +2421,32 @@ static ControlRequestTO ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle ControlRequestTO$VH() { return IOUSBInterfaceStruct190.ControlRequestTO$VH; } - public static MemoryAddress ControlRequestTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ControlRequestTO$VH.get(seg); - } - public static void ControlRequestTO$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*ControlRequestTO)(void*,UInt8,IOUSBDevRequestTO*); + * } + */ + public static MemorySegment ControlRequestTO$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ControlRequestTO$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*ControlRequestTO)(void*,UInt8,IOUSBDevRequestTO*); + * } + */ + public static void ControlRequestTO$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.ControlRequestTO$VH.set(seg, x); } - public static MemoryAddress ControlRequestTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ControlRequestTO$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment ControlRequestTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ControlRequestTO$VH.get(seg.asSlice(index*sizeof())); } - public static void ControlRequestTO$set(MemorySegment seg, long index, MemoryAddress x) { + public static void ControlRequestTO$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.ControlRequestTO$VH.set(seg.asSlice(index*sizeof()), x); } - public static ControlRequestTO ControlRequestTO (MemorySegment segment, MemorySession session) { - return ControlRequestTO.ofAddress(ControlRequestTO$get(segment), session); + public static ControlRequestTO ControlRequestTO(MemorySegment segment, SegmentScope scope) { + return ControlRequestTO.ofAddress(ControlRequestTO$get(segment), scope); } static final FunctionDescriptor ControlRequestAsyncTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1762,17 +2458,22 @@ public static ControlRequestTO ControlRequestTO (MemorySegment segment, MemorySe static final MethodHandle ControlRequestAsyncTO$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.ControlRequestAsyncTO$FUNC ); + /** + * {@snippet : + * IOReturn (*ControlRequestAsyncTO)(void*,UInt8,IOUSBDevRequestTO*,IOAsyncCallback1,void*); + * } + */ public interface ControlRequestAsyncTO { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, java.lang.foreign.MemoryAddress _x4); - static MemorySegment allocate(ControlRequestAsyncTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(ControlRequestAsyncTO.class, fi, IOUSBInterfaceStruct190.ControlRequestAsyncTO$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3, java.lang.foreign.MemorySegment _x4); + static MemorySegment allocate(ControlRequestAsyncTO fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(ControlRequestAsyncTO.class, fi, IOUSBInterfaceStruct190.ControlRequestAsyncTO$FUNC, scope); } - static ControlRequestAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, java.lang.foreign.MemoryAddress __x4) -> { + static ControlRequestAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3, java.lang.foreign.MemorySegment __x4) -> { try { - return (int)IOUSBInterfaceStruct190.ControlRequestAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, (java.lang.foreign.Addressable)__x4); + return (int)IOUSBInterfaceStruct190.ControlRequestAsyncTO$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1784,20 +2485,32 @@ static ControlRequestAsyncTO ofAddress(MemoryAddress addr, MemorySession session public static VarHandle ControlRequestAsyncTO$VH() { return IOUSBInterfaceStruct190.ControlRequestAsyncTO$VH; } - public static MemoryAddress ControlRequestAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ControlRequestAsyncTO$VH.get(seg); - } - public static void ControlRequestAsyncTO$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*ControlRequestAsyncTO)(void*,UInt8,IOUSBDevRequestTO*,IOAsyncCallback1,void*); + * } + */ + public static MemorySegment ControlRequestAsyncTO$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ControlRequestAsyncTO$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*ControlRequestAsyncTO)(void*,UInt8,IOUSBDevRequestTO*,IOAsyncCallback1,void*); + * } + */ + public static void ControlRequestAsyncTO$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.ControlRequestAsyncTO$VH.set(seg, x); } - public static MemoryAddress ControlRequestAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ControlRequestAsyncTO$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment ControlRequestAsyncTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ControlRequestAsyncTO$VH.get(seg.asSlice(index*sizeof())); } - public static void ControlRequestAsyncTO$set(MemorySegment seg, long index, MemoryAddress x) { + public static void ControlRequestAsyncTO$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.ControlRequestAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); } - public static ControlRequestAsyncTO ControlRequestAsyncTO (MemorySegment segment, MemorySession session) { - return ControlRequestAsyncTO.ofAddress(ControlRequestAsyncTO$get(segment), session); + public static ControlRequestAsyncTO ControlRequestAsyncTO(MemorySegment segment, SegmentScope scope) { + return ControlRequestAsyncTO.ofAddress(ControlRequestAsyncTO$get(segment), scope); } static final FunctionDescriptor ReadPipeTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1810,17 +2523,22 @@ public static ControlRequestAsyncTO ControlRequestAsyncTO (MemorySegment segment static final MethodHandle ReadPipeTO$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.ReadPipeTO$FUNC ); + /** + * {@snippet : + * IOReturn (*ReadPipeTO)(void*,UInt8,void*,UInt32*,UInt32,UInt32); + * } + */ public interface ReadPipeTO { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, java.lang.foreign.MemoryAddress _x3, int _x4, int _x5); - static MemorySegment allocate(ReadPipeTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(ReadPipeTO.class, fi, IOUSBInterfaceStruct190.ReadPipeTO$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3, int _x4, int _x5); + static MemorySegment allocate(ReadPipeTO fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(ReadPipeTO.class, fi, IOUSBInterfaceStruct190.ReadPipeTO$FUNC, scope); } - static ReadPipeTO ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, java.lang.foreign.MemoryAddress __x3, int __x4, int __x5) -> { + static ReadPipeTO ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3, int __x4, int __x5) -> { try { - return (int)IOUSBInterfaceStruct190.ReadPipeTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, (java.lang.foreign.Addressable)__x3, __x4, __x5); + return (int)IOUSBInterfaceStruct190.ReadPipeTO$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1832,20 +2550,32 @@ static ReadPipeTO ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle ReadPipeTO$VH() { return IOUSBInterfaceStruct190.ReadPipeTO$VH; } - public static MemoryAddress ReadPipeTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadPipeTO$VH.get(seg); - } - public static void ReadPipeTO$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*ReadPipeTO)(void*,UInt8,void*,UInt32*,UInt32,UInt32); + * } + */ + public static MemorySegment ReadPipeTO$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadPipeTO$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*ReadPipeTO)(void*,UInt8,void*,UInt32*,UInt32,UInt32); + * } + */ + public static void ReadPipeTO$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.ReadPipeTO$VH.set(seg, x); } - public static MemoryAddress ReadPipeTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadPipeTO$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment ReadPipeTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadPipeTO$VH.get(seg.asSlice(index*sizeof())); } - public static void ReadPipeTO$set(MemorySegment seg, long index, MemoryAddress x) { + public static void ReadPipeTO$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.ReadPipeTO$VH.set(seg.asSlice(index*sizeof()), x); } - public static ReadPipeTO ReadPipeTO (MemorySegment segment, MemorySession session) { - return ReadPipeTO.ofAddress(ReadPipeTO$get(segment), session); + public static ReadPipeTO ReadPipeTO(MemorySegment segment, SegmentScope scope) { + return ReadPipeTO.ofAddress(ReadPipeTO$get(segment), scope); } static final FunctionDescriptor WritePipeTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1858,17 +2588,22 @@ public static ReadPipeTO ReadPipeTO (MemorySegment segment, MemorySession sessio static final MethodHandle WritePipeTO$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.WritePipeTO$FUNC ); + /** + * {@snippet : + * IOReturn (*WritePipeTO)(void*,UInt8,void*,UInt32,UInt32,UInt32); + * } + */ public interface WritePipeTO { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3, int _x4, int _x5); - static MemorySegment allocate(WritePipeTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(WritePipeTO.class, fi, IOUSBInterfaceStruct190.WritePipeTO$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3, int _x4, int _x5); + static MemorySegment allocate(WritePipeTO fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(WritePipeTO.class, fi, IOUSBInterfaceStruct190.WritePipeTO$FUNC, scope); } - static WritePipeTO ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3, int __x4, int __x5) -> { + static WritePipeTO ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3, int __x4, int __x5) -> { try { - return (int)IOUSBInterfaceStruct190.WritePipeTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, __x5); + return (int)IOUSBInterfaceStruct190.WritePipeTO$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1880,20 +2615,32 @@ static WritePipeTO ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle WritePipeTO$VH() { return IOUSBInterfaceStruct190.WritePipeTO$VH; } - public static MemoryAddress WritePipeTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WritePipeTO$VH.get(seg); - } - public static void WritePipeTO$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*WritePipeTO)(void*,UInt8,void*,UInt32,UInt32,UInt32); + * } + */ + public static MemorySegment WritePipeTO$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WritePipeTO$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*WritePipeTO)(void*,UInt8,void*,UInt32,UInt32,UInt32); + * } + */ + public static void WritePipeTO$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.WritePipeTO$VH.set(seg, x); } - public static MemoryAddress WritePipeTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WritePipeTO$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment WritePipeTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WritePipeTO$VH.get(seg.asSlice(index*sizeof())); } - public static void WritePipeTO$set(MemorySegment seg, long index, MemoryAddress x) { + public static void WritePipeTO$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.WritePipeTO$VH.set(seg.asSlice(index*sizeof()), x); } - public static WritePipeTO WritePipeTO (MemorySegment segment, MemorySession session) { - return WritePipeTO.ofAddress(WritePipeTO$get(segment), session); + public static WritePipeTO WritePipeTO(MemorySegment segment, SegmentScope scope) { + return WritePipeTO.ofAddress(WritePipeTO$get(segment), scope); } static final FunctionDescriptor ReadPipeAsyncTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1908,17 +2655,22 @@ public static WritePipeTO WritePipeTO (MemorySegment segment, MemorySession sess static final MethodHandle ReadPipeAsyncTO$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.ReadPipeAsyncTO$FUNC ); + /** + * {@snippet : + * IOReturn (*ReadPipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); + * } + */ public interface ReadPipeAsyncTO { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3, int _x4, int _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7); - static MemorySegment allocate(ReadPipeAsyncTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(ReadPipeAsyncTO.class, fi, IOUSBInterfaceStruct190.ReadPipeAsyncTO$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3, int _x4, int _x5, java.lang.foreign.MemorySegment _x6, java.lang.foreign.MemorySegment _x7); + static MemorySegment allocate(ReadPipeAsyncTO fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(ReadPipeAsyncTO.class, fi, IOUSBInterfaceStruct190.ReadPipeAsyncTO$FUNC, scope); } - static ReadPipeAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3, int __x4, int __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7) -> { + static ReadPipeAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3, int __x4, int __x5, java.lang.foreign.MemorySegment __x6, java.lang.foreign.MemorySegment __x7) -> { try { - return (int)IOUSBInterfaceStruct190.ReadPipeAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, __x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7); + return (int)IOUSBInterfaceStruct190.ReadPipeAsyncTO$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1930,20 +2682,32 @@ static ReadPipeAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle ReadPipeAsyncTO$VH() { return IOUSBInterfaceStruct190.ReadPipeAsyncTO$VH; } - public static MemoryAddress ReadPipeAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadPipeAsyncTO$VH.get(seg); - } - public static void ReadPipeAsyncTO$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*ReadPipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); + * } + */ + public static MemorySegment ReadPipeAsyncTO$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadPipeAsyncTO$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*ReadPipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); + * } + */ + public static void ReadPipeAsyncTO$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.ReadPipeAsyncTO$VH.set(seg, x); } - public static MemoryAddress ReadPipeAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ReadPipeAsyncTO$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment ReadPipeAsyncTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadPipeAsyncTO$VH.get(seg.asSlice(index*sizeof())); } - public static void ReadPipeAsyncTO$set(MemorySegment seg, long index, MemoryAddress x) { + public static void ReadPipeAsyncTO$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.ReadPipeAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); } - public static ReadPipeAsyncTO ReadPipeAsyncTO (MemorySegment segment, MemorySession session) { - return ReadPipeAsyncTO.ofAddress(ReadPipeAsyncTO$get(segment), session); + public static ReadPipeAsyncTO ReadPipeAsyncTO(MemorySegment segment, SegmentScope scope) { + return ReadPipeAsyncTO.ofAddress(ReadPipeAsyncTO$get(segment), scope); } static final FunctionDescriptor WritePipeAsyncTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -1958,17 +2722,22 @@ public static ReadPipeAsyncTO ReadPipeAsyncTO (MemorySegment segment, MemorySess static final MethodHandle WritePipeAsyncTO$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.WritePipeAsyncTO$FUNC ); + /** + * {@snippet : + * IOReturn (*WritePipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); + * } + */ public interface WritePipeAsyncTO { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, java.lang.foreign.MemoryAddress _x2, int _x3, int _x4, int _x5, java.lang.foreign.MemoryAddress _x6, java.lang.foreign.MemoryAddress _x7); - static MemorySegment allocate(WritePipeAsyncTO fi, MemorySession session) { - return RuntimeHelper.upcallStub(WritePipeAsyncTO.class, fi, IOUSBInterfaceStruct190.WritePipeAsyncTO$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3, int _x4, int _x5, java.lang.foreign.MemorySegment _x6, java.lang.foreign.MemorySegment _x7); + static MemorySegment allocate(WritePipeAsyncTO fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(WritePipeAsyncTO.class, fi, IOUSBInterfaceStruct190.WritePipeAsyncTO$FUNC, scope); } - static WritePipeAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, java.lang.foreign.MemoryAddress __x2, int __x3, int __x4, int __x5, java.lang.foreign.MemoryAddress __x6, java.lang.foreign.MemoryAddress __x7) -> { + static WritePipeAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3, int __x4, int __x5, java.lang.foreign.MemorySegment __x6, java.lang.foreign.MemorySegment __x7) -> { try { - return (int)IOUSBInterfaceStruct190.WritePipeAsyncTO$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, (java.lang.foreign.Addressable)__x2, __x3, __x4, __x5, (java.lang.foreign.Addressable)__x6, (java.lang.foreign.Addressable)__x7); + return (int)IOUSBInterfaceStruct190.WritePipeAsyncTO$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1980,20 +2749,32 @@ static WritePipeAsyncTO ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle WritePipeAsyncTO$VH() { return IOUSBInterfaceStruct190.WritePipeAsyncTO$VH; } - public static MemoryAddress WritePipeAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WritePipeAsyncTO$VH.get(seg); - } - public static void WritePipeAsyncTO$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*WritePipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); + * } + */ + public static MemorySegment WritePipeAsyncTO$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WritePipeAsyncTO$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*WritePipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); + * } + */ + public static void WritePipeAsyncTO$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.WritePipeAsyncTO$VH.set(seg, x); } - public static MemoryAddress WritePipeAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.WritePipeAsyncTO$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment WritePipeAsyncTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WritePipeAsyncTO$VH.get(seg.asSlice(index*sizeof())); } - public static void WritePipeAsyncTO$set(MemorySegment seg, long index, MemoryAddress x) { + public static void WritePipeAsyncTO$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.WritePipeAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); } - public static WritePipeAsyncTO WritePipeAsyncTO (MemorySegment segment, MemorySession session) { - return WritePipeAsyncTO.ofAddress(WritePipeAsyncTO$get(segment), session); + public static WritePipeAsyncTO WritePipeAsyncTO(MemorySegment segment, SegmentScope scope) { + return WritePipeAsyncTO.ofAddress(WritePipeAsyncTO$get(segment), scope); } static final FunctionDescriptor USBInterfaceGetStringIndex$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -2002,17 +2783,22 @@ public static WritePipeAsyncTO WritePipeAsyncTO (MemorySegment segment, MemorySe static final MethodHandle USBInterfaceGetStringIndex$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$FUNC ); + /** + * {@snippet : + * IOReturn (*USBInterfaceGetStringIndex)(void*,UInt8*); + * } + */ public interface USBInterfaceGetStringIndex { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(USBInterfaceGetStringIndex fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBInterfaceGetStringIndex.class, fi, IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(USBInterfaceGetStringIndex fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(USBInterfaceGetStringIndex.class, fi, IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$FUNC, scope); } - static USBInterfaceGetStringIndex ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static USBInterfaceGetStringIndex ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2024,20 +2810,32 @@ static USBInterfaceGetStringIndex ofAddress(MemoryAddress addr, MemorySession se public static VarHandle USBInterfaceGetStringIndex$VH() { return IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$VH; } - public static MemoryAddress USBInterfaceGetStringIndex$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$VH.get(seg); - } - public static void USBInterfaceGetStringIndex$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*USBInterfaceGetStringIndex)(void*,UInt8*); + * } + */ + public static MemorySegment USBInterfaceGetStringIndex$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*USBInterfaceGetStringIndex)(void*,UInt8*); + * } + */ + public static void USBInterfaceGetStringIndex$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$VH.set(seg, x); } - public static MemoryAddress USBInterfaceGetStringIndex$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment USBInterfaceGetStringIndex$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$VH.get(seg.asSlice(index*sizeof())); } - public static void USBInterfaceGetStringIndex$set(MemorySegment seg, long index, MemoryAddress x) { + public static void USBInterfaceGetStringIndex$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$VH.set(seg.asSlice(index*sizeof()), x); } - public static USBInterfaceGetStringIndex USBInterfaceGetStringIndex (MemorySegment segment, MemorySession session) { - return USBInterfaceGetStringIndex.ofAddress(USBInterfaceGetStringIndex$get(segment), session); + public static USBInterfaceGetStringIndex USBInterfaceGetStringIndex(MemorySegment segment, SegmentScope scope) { + return USBInterfaceGetStringIndex.ofAddress(USBInterfaceGetStringIndex$get(segment), scope); } static final FunctionDescriptor USBInterfaceOpenSeize$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -2045,17 +2843,22 @@ public static USBInterfaceGetStringIndex USBInterfaceGetStringIndex (MemorySegme static final MethodHandle USBInterfaceOpenSeize$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.USBInterfaceOpenSeize$FUNC ); + /** + * {@snippet : + * IOReturn (*USBInterfaceOpenSeize)(void*); + * } + */ public interface USBInterfaceOpenSeize { - int apply(java.lang.foreign.MemoryAddress _x0); - static MemorySegment allocate(USBInterfaceOpenSeize fi, MemorySession session) { - return RuntimeHelper.upcallStub(USBInterfaceOpenSeize.class, fi, IOUSBInterfaceStruct190.USBInterfaceOpenSeize$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(USBInterfaceOpenSeize fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(USBInterfaceOpenSeize.class, fi, IOUSBInterfaceStruct190.USBInterfaceOpenSeize$FUNC, scope); } - static USBInterfaceOpenSeize ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0) -> { + static USBInterfaceOpenSeize ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBInterfaceStruct190.USBInterfaceOpenSeize$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0); + return (int)IOUSBInterfaceStruct190.USBInterfaceOpenSeize$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2067,20 +2870,32 @@ static USBInterfaceOpenSeize ofAddress(MemoryAddress addr, MemorySession session public static VarHandle USBInterfaceOpenSeize$VH() { return IOUSBInterfaceStruct190.USBInterfaceOpenSeize$VH; } - public static MemoryAddress USBInterfaceOpenSeize$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.USBInterfaceOpenSeize$VH.get(seg); - } - public static void USBInterfaceOpenSeize$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*USBInterfaceOpenSeize)(void*); + * } + */ + public static MemorySegment USBInterfaceOpenSeize$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.USBInterfaceOpenSeize$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*USBInterfaceOpenSeize)(void*); + * } + */ + public static void USBInterfaceOpenSeize$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.USBInterfaceOpenSeize$VH.set(seg, x); } - public static MemoryAddress USBInterfaceOpenSeize$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.USBInterfaceOpenSeize$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment USBInterfaceOpenSeize$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.USBInterfaceOpenSeize$VH.get(seg.asSlice(index*sizeof())); } - public static void USBInterfaceOpenSeize$set(MemorySegment seg, long index, MemoryAddress x) { + public static void USBInterfaceOpenSeize$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.USBInterfaceOpenSeize$VH.set(seg.asSlice(index*sizeof()), x); } - public static USBInterfaceOpenSeize USBInterfaceOpenSeize (MemorySegment segment, MemorySession session) { - return USBInterfaceOpenSeize.ofAddress(USBInterfaceOpenSeize$get(segment), session); + public static USBInterfaceOpenSeize USBInterfaceOpenSeize(MemorySegment segment, SegmentScope scope) { + return USBInterfaceOpenSeize.ofAddress(USBInterfaceOpenSeize$get(segment), scope); } static final FunctionDescriptor ClearPipeStallBothEnds$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -2089,17 +2904,22 @@ public static USBInterfaceOpenSeize USBInterfaceOpenSeize (MemorySegment segment static final MethodHandle ClearPipeStallBothEnds$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.ClearPipeStallBothEnds$FUNC ); + /** + * {@snippet : + * IOReturn (*ClearPipeStallBothEnds)(void*,UInt8); + * } + */ public interface ClearPipeStallBothEnds { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1); - static MemorySegment allocate(ClearPipeStallBothEnds fi, MemorySession session) { - return RuntimeHelper.upcallStub(ClearPipeStallBothEnds.class, fi, IOUSBInterfaceStruct190.ClearPipeStallBothEnds$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1); + static MemorySegment allocate(ClearPipeStallBothEnds fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(ClearPipeStallBothEnds.class, fi, IOUSBInterfaceStruct190.ClearPipeStallBothEnds$FUNC, scope); } - static ClearPipeStallBothEnds ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1) -> { + static ClearPipeStallBothEnds ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct190.ClearPipeStallBothEnds$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1); + return (int)IOUSBInterfaceStruct190.ClearPipeStallBothEnds$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2111,20 +2931,32 @@ static ClearPipeStallBothEnds ofAddress(MemoryAddress addr, MemorySession sessio public static VarHandle ClearPipeStallBothEnds$VH() { return IOUSBInterfaceStruct190.ClearPipeStallBothEnds$VH; } - public static MemoryAddress ClearPipeStallBothEnds$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ClearPipeStallBothEnds$VH.get(seg); - } - public static void ClearPipeStallBothEnds$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*ClearPipeStallBothEnds)(void*,UInt8); + * } + */ + public static MemorySegment ClearPipeStallBothEnds$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ClearPipeStallBothEnds$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*ClearPipeStallBothEnds)(void*,UInt8); + * } + */ + public static void ClearPipeStallBothEnds$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.ClearPipeStallBothEnds$VH.set(seg, x); } - public static MemoryAddress ClearPipeStallBothEnds$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.ClearPipeStallBothEnds$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment ClearPipeStallBothEnds$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ClearPipeStallBothEnds$VH.get(seg.asSlice(index*sizeof())); } - public static void ClearPipeStallBothEnds$set(MemorySegment seg, long index, MemoryAddress x) { + public static void ClearPipeStallBothEnds$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.ClearPipeStallBothEnds$VH.set(seg.asSlice(index*sizeof()), x); } - public static ClearPipeStallBothEnds ClearPipeStallBothEnds (MemorySegment segment, MemorySession session) { - return ClearPipeStallBothEnds.ofAddress(ClearPipeStallBothEnds$get(segment), session); + public static ClearPipeStallBothEnds ClearPipeStallBothEnds(MemorySegment segment, SegmentScope scope) { + return ClearPipeStallBothEnds.ofAddress(ClearPipeStallBothEnds$get(segment), scope); } static final FunctionDescriptor SetPipePolicy$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -2135,17 +2967,22 @@ public static ClearPipeStallBothEnds ClearPipeStallBothEnds (MemorySegment segme static final MethodHandle SetPipePolicy$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.SetPipePolicy$FUNC ); + /** + * {@snippet : + * IOReturn (*SetPipePolicy)(void*,UInt8,UInt16,UInt8); + * } + */ public interface SetPipePolicy { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, short _x2, byte _x3); - static MemorySegment allocate(SetPipePolicy fi, MemorySession session) { - return RuntimeHelper.upcallStub(SetPipePolicy.class, fi, IOUSBInterfaceStruct190.SetPipePolicy$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, short _x2, byte _x3); + static MemorySegment allocate(SetPipePolicy fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(SetPipePolicy.class, fi, IOUSBInterfaceStruct190.SetPipePolicy$FUNC, scope); } - static SetPipePolicy ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, short __x2, byte __x3) -> { + static SetPipePolicy ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, short __x2, byte __x3) -> { try { - return (int)IOUSBInterfaceStruct190.SetPipePolicy$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, __x3); + return (int)IOUSBInterfaceStruct190.SetPipePolicy$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2157,20 +2994,32 @@ static SetPipePolicy ofAddress(MemoryAddress addr, MemorySession session) { public static VarHandle SetPipePolicy$VH() { return IOUSBInterfaceStruct190.SetPipePolicy$VH; } - public static MemoryAddress SetPipePolicy$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.SetPipePolicy$VH.get(seg); - } - public static void SetPipePolicy$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*SetPipePolicy)(void*,UInt8,UInt16,UInt8); + * } + */ + public static MemorySegment SetPipePolicy$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.SetPipePolicy$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*SetPipePolicy)(void*,UInt8,UInt16,UInt8); + * } + */ + public static void SetPipePolicy$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.SetPipePolicy$VH.set(seg, x); } - public static MemoryAddress SetPipePolicy$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.SetPipePolicy$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment SetPipePolicy$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.SetPipePolicy$VH.get(seg.asSlice(index*sizeof())); } - public static void SetPipePolicy$set(MemorySegment seg, long index, MemoryAddress x) { + public static void SetPipePolicy$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.SetPipePolicy$VH.set(seg.asSlice(index*sizeof()), x); } - public static SetPipePolicy SetPipePolicy (MemorySegment segment, MemorySession session) { - return SetPipePolicy.ofAddress(SetPipePolicy$get(segment), session); + public static SetPipePolicy SetPipePolicy(MemorySegment segment, SegmentScope scope) { + return SetPipePolicy.ofAddress(SetPipePolicy$get(segment), scope); } static final FunctionDescriptor GetBandwidthAvailable$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -2179,17 +3028,22 @@ public static SetPipePolicy SetPipePolicy (MemorySegment segment, MemorySession static final MethodHandle GetBandwidthAvailable$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetBandwidthAvailable$FUNC ); + /** + * {@snippet : + * IOReturn (*GetBandwidthAvailable)(void*,UInt32*); + * } + */ public interface GetBandwidthAvailable { - int apply(java.lang.foreign.MemoryAddress _x0, java.lang.foreign.MemoryAddress _x1); - static MemorySegment allocate(GetBandwidthAvailable fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetBandwidthAvailable.class, fi, IOUSBInterfaceStruct190.GetBandwidthAvailable$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(GetBandwidthAvailable fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetBandwidthAvailable.class, fi, IOUSBInterfaceStruct190.GetBandwidthAvailable$FUNC, scope); } - static GetBandwidthAvailable ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, java.lang.foreign.MemoryAddress __x1) -> { + static GetBandwidthAvailable ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetBandwidthAvailable$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, (java.lang.foreign.Addressable)__x1); + return (int)IOUSBInterfaceStruct190.GetBandwidthAvailable$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2201,20 +3055,32 @@ static GetBandwidthAvailable ofAddress(MemoryAddress addr, MemorySession session public static VarHandle GetBandwidthAvailable$VH() { return IOUSBInterfaceStruct190.GetBandwidthAvailable$VH; } - public static MemoryAddress GetBandwidthAvailable$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetBandwidthAvailable$VH.get(seg); - } - public static void GetBandwidthAvailable$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetBandwidthAvailable)(void*,UInt32*); + * } + */ + public static MemorySegment GetBandwidthAvailable$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetBandwidthAvailable$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetBandwidthAvailable)(void*,UInt32*); + * } + */ + public static void GetBandwidthAvailable$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetBandwidthAvailable$VH.set(seg, x); } - public static MemoryAddress GetBandwidthAvailable$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetBandwidthAvailable$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetBandwidthAvailable$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetBandwidthAvailable$VH.get(seg.asSlice(index*sizeof())); } - public static void GetBandwidthAvailable$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetBandwidthAvailable$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetBandwidthAvailable$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetBandwidthAvailable GetBandwidthAvailable (MemorySegment segment, MemorySession session) { - return GetBandwidthAvailable.ofAddress(GetBandwidthAvailable$get(segment), session); + public static GetBandwidthAvailable GetBandwidthAvailable(MemorySegment segment, SegmentScope scope) { + return GetBandwidthAvailable.ofAddress(GetBandwidthAvailable$get(segment), scope); } static final FunctionDescriptor GetEndpointProperties$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -2228,17 +3094,22 @@ public static GetBandwidthAvailable GetBandwidthAvailable (MemorySegment segment static final MethodHandle GetEndpointProperties$MH = RuntimeHelper.downcallHandle( IOUSBInterfaceStruct190.GetEndpointProperties$FUNC ); + /** + * {@snippet : + * IOReturn (*GetEndpointProperties)(void*,UInt8,UInt8,UInt8,UInt8*,UInt16*,UInt8*); + * } + */ public interface GetEndpointProperties { - int apply(java.lang.foreign.MemoryAddress _x0, byte _x1, byte _x2, byte _x3, java.lang.foreign.MemoryAddress _x4, java.lang.foreign.MemoryAddress _x5, java.lang.foreign.MemoryAddress _x6); - static MemorySegment allocate(GetEndpointProperties fi, MemorySession session) { - return RuntimeHelper.upcallStub(GetEndpointProperties.class, fi, IOUSBInterfaceStruct190.GetEndpointProperties$FUNC, session); + int apply(java.lang.foreign.MemorySegment _x0, byte _x1, byte _x2, byte _x3, java.lang.foreign.MemorySegment _x4, java.lang.foreign.MemorySegment _x5, java.lang.foreign.MemorySegment _x6); + static MemorySegment allocate(GetEndpointProperties fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(GetEndpointProperties.class, fi, IOUSBInterfaceStruct190.GetEndpointProperties$FUNC, scope); } - static GetEndpointProperties ofAddress(MemoryAddress addr, MemorySession session) { - MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); - return (java.lang.foreign.MemoryAddress __x0, byte __x1, byte __x2, byte __x3, java.lang.foreign.MemoryAddress __x4, java.lang.foreign.MemoryAddress __x5, java.lang.foreign.MemoryAddress __x6) -> { + static GetEndpointProperties ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1, byte __x2, byte __x3, java.lang.foreign.MemorySegment __x4, java.lang.foreign.MemorySegment __x5, java.lang.foreign.MemorySegment __x6) -> { try { - return (int)IOUSBInterfaceStruct190.GetEndpointProperties$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)__x0, __x1, __x2, __x3, (java.lang.foreign.Addressable)__x4, (java.lang.foreign.Addressable)__x5, (java.lang.foreign.Addressable)__x6); + return (int)IOUSBInterfaceStruct190.GetEndpointProperties$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2250,27 +3121,39 @@ static GetEndpointProperties ofAddress(MemoryAddress addr, MemorySession session public static VarHandle GetEndpointProperties$VH() { return IOUSBInterfaceStruct190.GetEndpointProperties$VH; } - public static MemoryAddress GetEndpointProperties$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetEndpointProperties$VH.get(seg); - } - public static void GetEndpointProperties$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * IOReturn (*GetEndpointProperties)(void*,UInt8,UInt8,UInt8,UInt8*,UInt16*,UInt8*); + * } + */ + public static MemorySegment GetEndpointProperties$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetEndpointProperties$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*GetEndpointProperties)(void*,UInt8,UInt8,UInt8,UInt8*,UInt16*,UInt8*); + * } + */ + public static void GetEndpointProperties$set(MemorySegment seg, MemorySegment x) { IOUSBInterfaceStruct190.GetEndpointProperties$VH.set(seg, x); } - public static MemoryAddress GetEndpointProperties$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)IOUSBInterfaceStruct190.GetEndpointProperties$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment GetEndpointProperties$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetEndpointProperties$VH.get(seg.asSlice(index*sizeof())); } - public static void GetEndpointProperties$set(MemorySegment seg, long index, MemoryAddress x) { + public static void GetEndpointProperties$set(MemorySegment seg, long index, MemorySegment x) { IOUSBInterfaceStruct190.GetEndpointProperties$VH.set(seg.asSlice(index*sizeof()), x); } - public static GetEndpointProperties GetEndpointProperties (MemorySegment segment, MemorySession session) { - return GetEndpointProperties.ofAddress(GetEndpointProperties$get(segment), session); + public static GetEndpointProperties GetEndpointProperties(MemorySegment segment, SegmentScope scope) { + return GetEndpointProperties.ofAddress(GetEndpointProperties$get(segment), scope); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java index 18defbd9..c691bfb5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java @@ -10,22 +10,25 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { // System.loadLibrary("IOKit.framework"); // SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SymbolLookup loaderLookup = SymbolLookup.libraryLookup("IOKit.framework/IOKit", MemorySession.openImplicit()); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SymbolLookup loaderLookup = SymbolLookup.libraryLookup("IOKit.framework/IOKit", SegmentScope.global()); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -33,45 +36,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -97,7 +98,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -107,8 +110,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -143,7 +145,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -193,10 +197,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -207,7 +208,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java index 75a6b3ae..3343291a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java @@ -9,12 +9,14 @@ import static java.lang.foreign.ValueLayout.OfAddress; import static java.lang.foreign.ValueLayout.OfInt; -class constants$0 { +final class constants$0 { - static final OfAddress kCFRunLoopDefaultMode$LAYOUT = Constants$root.C_POINTER$LAYOUT; + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} + static final OfAddress kCFRunLoopDefaultMode$LAYOUT = Constants$root.C_POINTER$LAYOUT; static final VarHandle kCFRunLoopDefaultMode$VH = constants$0.kCFRunLoopDefaultMode$LAYOUT.varHandle(); static final MemorySegment kCFRunLoopDefaultMode$SEGMENT = RuntimeHelper.lookupGlobalVariable("kCFRunLoopDefaultMode", constants$0.kCFRunLoopDefaultMode$LAYOUT); - static final OfInt kIOMasterPortDefault$LAYOUT = Constants$root.C_INT$LAYOUT; + static final OfInt kIOMasterPortDefault$LAYOUT = Constants$root.C_INT$LAYOUT; static final VarHandle kIOMasterPortDefault$VH = constants$0.kIOMasterPortDefault$LAYOUT.varHandle(); static final MemorySegment kIOMasterPortDefault$SEGMENT = RuntimeHelper.lookupGlobalVariable("kIOMasterPortDefault", constants$0.kIOMasterPortDefault$LAYOUT); static final FunctionDescriptor IONotificationPortCreate$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$1.java index f6bb1dbf..f75879ac 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$1.java @@ -5,8 +5,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; -class constants$1 { +final class constants$1 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$1() {} static final FunctionDescriptor IOServiceAddMatchingNotification$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT, diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$2.java index c82ad78e..a61ef756 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$2.java @@ -3,8 +3,10 @@ package net.codecrete.usb.macos.gen.iokit; import java.lang.foreign.MemorySegment; -class constants$2 { +final class constants$2 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$2() {} static final MemorySegment kIOTerminatedNotification$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("IOServiceTerminate"); static final MemorySegment kIOUSBDeviceClassName$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("IOUSBDevice"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java index 7ac0bc7e..59e45ac5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.macos.gen.mach; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfLong C_LONG$LAYOUT = JAVA_LONG; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java index cb43e170..0b83f5a7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java @@ -10,21 +10,24 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -32,45 +35,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -96,7 +97,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -106,8 +109,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -142,7 +144,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -192,10 +196,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -206,7 +207,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java index 00707d13..a75c9930 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$0 { +final class constants$0 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} static final FunctionDescriptor mach_error_string$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, Constants$root.C_INT$LAYOUT ); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java index 6b42d952..3d065d4c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java @@ -2,28 +2,32 @@ package net.codecrete.usb.macos.gen.mach; -import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class mach { - /* package-private */ mach() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; public static MethodHandle mach_error_string$MH() { return RuntimeHelper.requireNonNull(constants$0.mach_error_string$MH,"mach_error_string"); } - public static MemoryAddress mach_error_string ( int error_value) { + /** + * {@snippet : + * char* mach_error_string(mach_error_t error_value); + * } + */ + public static MemorySegment mach_error_string(int error_value) { var mh$ = mach_error_string$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(error_value); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(error_value); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java index afb022c7..b1109a3e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java @@ -1,8 +1,8 @@ package net.codecrete.usb.usbstandard; +import java.lang.foreign.Arena; import java.lang.foreign.GroupLayout; import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; import java.lang.invoke.VarHandle; import static java.lang.foreign.MemoryLayout.PathElement.groupElement; @@ -29,10 +29,10 @@ public SetupPacket(MemorySegment descriptor) { /** * Creates a setup packet by allocating a native memory segment. * - * @param session memory session + * @param arena arena */ - public SetupPacket(MemorySession session) { - this.descriptor = session.allocate(LAYOUT); + public SetupPacket(Arena arena) { + this.descriptor = arena.allocate(LAYOUT); } /** From 63aa45de1a538bb128db154abe70c6bf5b8e6355 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 26 Dec 2022 23:04:43 +0100 Subject: [PATCH 167/433] Upgrade Linux code to JDK 20 --- java-does-usb/jextract/linux/gen_linux.sh | 24 +-- .../src/main/java/net/codecrete/usb/USB.java | 5 +- .../main/java/net/codecrete/usb/linux/IO.java | 12 +- .../java/net/codecrete/usb/linux/Linux.java | 6 - .../codecrete/usb/linux/LinuxUSBDevice.java | 64 +++---- .../usb/linux/LinuxUSBDeviceRegistry.java | 72 +++---- .../net/codecrete/usb/linux/USBDevFS.java | 12 +- .../usb/linux/gen/errno/Constants$root.java | 22 ++- .../usb/linux/gen/errno/RuntimeHelper.java | 63 +++--- .../usb/linux/gen/errno/constants$0.java | 4 +- .../codecrete/usb/linux/gen/errno/errno.java | 38 ++-- .../usb/linux/gen/fcntl/Constants$root.java | 22 ++- .../usb/linux/gen/fcntl/RuntimeHelper.java | 63 +++--- .../usb/linux/gen/fcntl/constants$0.java | 4 +- .../codecrete/usb/linux/gen/fcntl/fcntl.java | 36 ++-- .../usb/linux/gen/ioctl/Constants$root.java | 22 ++- .../usb/linux/gen/ioctl/RuntimeHelper.java | 63 +++--- .../usb/linux/gen/ioctl/constants$0.java | 4 +- .../codecrete/usb/linux/gen/ioctl/ioctl.java | 24 ++- .../usb/linux/gen/poll/Constants$root.java | 22 ++- .../usb/linux/gen/poll/RuntimeHelper.java | 63 +++--- .../usb/linux/gen/poll/constants$0.java | 4 +- .../codecrete/usb/linux/gen/poll/poll.java | 31 +-- .../codecrete/usb/linux/gen/poll/pollfd.java | 57 +++++- .../usb/linux/gen/string/Constants$root.java | 22 ++- .../usb/linux/gen/string/RuntimeHelper.java | 63 +++--- .../usb/linux/gen/string/constants$0.java | 4 +- .../usb/linux/gen/string/string.java | 28 +-- .../usb/linux/gen/udev/Constants$root.java | 22 ++- .../usb/linux/gen/udev/RuntimeHelper.java | 65 +++---- .../usb/linux/gen/udev/constants$0.java | 4 +- .../usb/linux/gen/udev/constants$1.java | 4 +- .../usb/linux/gen/udev/constants$2.java | 4 +- .../usb/linux/gen/udev/constants$3.java | 4 +- .../codecrete/usb/linux/gen/udev/udev.java | 181 +++++++++++++----- .../usb/linux/gen/unistd/Constants$root.java | 22 ++- .../usb/linux/gen/unistd/RuntimeHelper.java | 63 +++--- .../usb/linux/gen/unistd/constants$0.java | 4 +- .../usb/linux/gen/unistd/unistd.java | 24 ++- .../gen/usbdevice_fs/Constants$root.java | 22 ++- .../linux/gen/usbdevice_fs/RuntimeHelper.java | 63 +++--- .../usbdevice_fs/usbdevfs_bulktransfer.java | 84 ++++++-- .../usbdevice_fs/usbdevfs_ctrltransfer.java | 129 +++++++++++-- .../usbdevice_fs/usbdevfs_setinterface.java | 42 +++- .../linux/gen/usbdevice_fs/usbdevice_fs.java | 17 +- 45 files changed, 1005 insertions(+), 603 deletions(-) diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index 82f41980..87af35ea 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -1,6 +1,6 @@ #!/bin/sh -JEXTRACT=../../../../jextract-19/bin/jextract +JEXTRACT=../../../../jextract/build/jextract/bin/jextract # sd-device.h (install libsystemd-dev if file is missing) # Error: /usr/include/inttypes.h:290:8: error: unknown type name 'intmax_t' @@ -15,8 +15,8 @@ $JEXTRACT --source --output ../../src/main/java \ --header-class-name errno \ --target-package net.codecrete.usb.linux.gen.errno \ --include-function __errno_location \ - --include-macro ETIMEDOUT \ - --include-macro EPIPE \ + --include-constant ETIMEDOUT \ + --include-constant EPIPE \ /usr/include/errno.h # string.h @@ -38,8 +38,8 @@ $JEXTRACT --source --output ../../src/main/java \ --header-class-name fcntl \ --target-package net.codecrete.usb.linux.gen.fcntl \ --include-function open \ - --include-macro O_CLOEXEC \ - --include-macro O_RDWR \ + --include-constant O_CLOEXEC \ + --include-constant O_RDWR \ /usr/include/fcntl.h # unistd.h @@ -57,12 +57,12 @@ $JEXTRACT --source --output ../../src/main/java \ --include-struct usbdevfs_bulktransfer \ --include-struct usbdevfs_ctrltransfer \ --include-struct usbdevfs_setinterface \ - --include-macro USBDEVFS_CONTROL \ - --include-macro USBDEVFS_BULK \ - --include-macro USBDEVFS_CLAIMINTERFACE \ - --include-macro USBDEVFS_RELEASEINTERFACE \ - --include-macro USBDEVFS_SETINTERFACE \ - --include-macro USBDEVFS_CLEAR_HALT \ + --include-constant USBDEVFS_CONTROL \ + --include-constant USBDEVFS_BULK \ + --include-constant USBDEVFS_CLAIMINTERFACE \ + --include-constant USBDEVFS_RELEASEINTERFACE \ + --include-constant USBDEVFS_SETINTERFACE \ + --include-constant USBDEVFS_CLEAR_HALT \ /usr/include/linux/usbdevice_fs.h # libudev.h @@ -98,6 +98,6 @@ $JEXTRACT --source --output ../../src/main/java \ --target-package net.codecrete.usb.linux.gen.poll \ --include-function poll \ --include-struct pollfd \ - --include-macro POLLIN \ + --include-constant POLLIN \ /usr/include/poll.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USB.java b/java-does-usb/src/main/java/net/codecrete/usb/USB.java index 39cd7d8a..4de40d70 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USB.java @@ -8,6 +8,7 @@ package net.codecrete.usb; import net.codecrete.usb.common.USBDeviceRegistry; +import net.codecrete.usb.linux.LinuxUSBDeviceRegistry; import net.codecrete.usb.macos.MacosUSBDeviceRegistry; import java.util.List; @@ -28,8 +29,8 @@ private static USBDeviceRegistry createInstance() { impl = new MacosUSBDeviceRegistry(); // } else if (osName.startsWith("Windows") && osArch.equals("amd64")) { // impl = new WindowsUSBDeviceRegistry(); -// } else if (osName.equals("Linux") && (osArch.equals("amd64") || osArch.equals("aarch64"))) { -// impl = new LinuxUSBDeviceRegistry(); + } else if (osName.equals("Linux") && (osArch.equals("amd64") || osArch.equals("aarch64"))) { + impl = new LinuxUSBDeviceRegistry(); } else { throw new UnsupportedOperationException(String.format("JavaCanDoUsb is not implemented for architecture " + "%s/%s", osName, osArch)); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java index 68792634..54c308b7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java @@ -9,21 +9,11 @@ import net.codecrete.usb.linux.gen.errno.errno; -import java.lang.foreign.MemoryAddress; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; - import static java.lang.foreign.ValueLayout.JAVA_INT; public class IO { public static int getErrno() { - try (var session = MemorySession.openConfined()) { - var location = (MemoryAddress) errno.__errno_location(); - var errnoSegment = MemorySegment.ofAddress(location, JAVA_INT.byteSize(), session); - return errnoSegment.get(JAVA_INT, 0); - } catch (Throwable e) { - throw new RuntimeException(e); - } + return errno.__errno_location().get(JAVA_INT, 0); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java index a3036fbc..de361a0d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java @@ -9,12 +9,6 @@ import net.codecrete.usb.linux.gen.string.string; -import java.lang.foreign.MemoryAddress; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; - -import static java.lang.foreign.MemoryAddress.NULL; - /** * Helper functions for Linux */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index f82d6e94..22e8cc30 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -20,8 +20,8 @@ import net.codecrete.usb.usbstandard.DeviceDescriptor; import java.io.IOException; +import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; import java.nio.file.Files; import java.nio.file.Path; @@ -50,17 +50,17 @@ private void loadDescription(String path) { // `descriptors` contains the device descriptor followed by the configuration descriptor // (including the interface descriptors, endpoint descriptors etc.) - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined()) { var descriptorsSegment = MemorySegment.ofArray(descriptors); // split off device descriptor (and copy it to fix alignment issues) - var deviceDesc = session.allocate(DeviceDescriptor.LAYOUT); + var deviceDesc = arena.allocate(DeviceDescriptor.LAYOUT); deviceDesc.copyFrom(descriptorsSegment.asSlice(0, DeviceDescriptor.LAYOUT.byteSize())); setFromDeviceDescriptor(deviceDesc); // skip to configuration descriptor - var configDesc = session.allocateArray(JAVA_BYTE, descriptors.length - 18); + var configDesc = arena.allocateArray(JAVA_BYTE, descriptors.length - 18); configDesc.copyFrom(descriptorsSegment.asSlice(DeviceDescriptor.LAYOUT.byteSize())); setConfigurationDescriptor(configDesc); } @@ -76,8 +76,8 @@ public void open() { if (isOpen()) throwException("the device is already open"); - try (var session = MemorySession.openConfined()) { - var pathUtf8 = session.allocateUtf8String(id_.toString()); + try (var arena = Arena.openConfined()) { + var pathUtf8 = arena.allocateUtf8String(id_.toString()); fd = fcntl.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC()); if (fd == -1) throwLastError("Cannot open USB device"); @@ -105,8 +105,8 @@ public void claimInterface(int interfaceNumber) { if (intf.isClaimed()) throwException("Interface %d has already been claimed", interfaceNumber); - try (var session = MemorySession.openConfined()) { - var intfNumSegment = session.allocate(JAVA_INT, interfaceNumber); + try (var arena = Arena.openConfined()) { + var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); int ret = ioctl.ioctl(fd, USBDevFS.CLAIMINTERFACE, intfNumSegment.address()); if (ret != 0) throwLastError("Cannot claim USB interface"); @@ -129,8 +129,8 @@ public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { if (altSetting == null) throwException("Interface %d does not have an alternate interface setting %d", interfaceNumber, alternateNumber); - try (var session = MemorySession.openConfined()) { - var setIntfSegment = session.allocate(usbdevfs_setinterface.$LAYOUT()); + try (var arena = Arena.openConfined()) { + var setIntfSegment = arena.allocate(usbdevfs_setinterface.$LAYOUT()); usbdevfs_setinterface.interface_$set(setIntfSegment, interfaceNumber); usbdevfs_setinterface.altsetting$set(setIntfSegment, alternateNumber); int ret = ioctl.ioctl(fd, USBDevFS.SETINTERFACE, setIntfSegment.address()); @@ -150,8 +150,8 @@ public void releaseInterface(int interfaceNumber) { if (!intf.isClaimed()) throwException("Interface %d has not been claimed", interfaceNumber); - try (var session = MemorySession.openConfined()) { - var intfNumSegment = session.allocate(JAVA_INT, interfaceNumber); + try (var arena = Arena.openConfined()) { + var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); int ret = ioctl.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment.address()); if (ret != 0) throwLastError("Cannot release USB interface"); @@ -159,9 +159,9 @@ public void releaseInterface(int interfaceNumber) { } } - private MemorySegment createCtrlTransfer(MemorySession session, USBDirection direction, USBControlTransfer setup, + private MemorySegment createCtrlTransfer(Arena arena, USBDirection direction, USBControlTransfer setup, MemorySegment data) { - var ctrlTransfer = session.allocate(usbdevfs_ctrltransfer.$LAYOUT()); + var ctrlTransfer = arena.allocate(usbdevfs_ctrltransfer.$LAYOUT()); var bmRequest = (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); usbdevfs_ctrltransfer.bRequestType$set(ctrlTransfer, (byte) bmRequest); @@ -169,15 +169,15 @@ private MemorySegment createCtrlTransfer(MemorySession session, USBDirection dir usbdevfs_ctrltransfer.wValue$set(ctrlTransfer, (short) setup.value()); usbdevfs_ctrltransfer.wIndex$set(ctrlTransfer, (short) setup.index()); usbdevfs_ctrltransfer.wLength$set(ctrlTransfer, (short) data.byteSize()); - usbdevfs_ctrltransfer.data$set(ctrlTransfer, data.address()); + usbdevfs_ctrltransfer.data$set(ctrlTransfer, data); return ctrlTransfer; } @Override public byte[] controlTransferIn(USBControlTransfer setup, int length) { - try (var session = MemorySession.openConfined()) { - var data = session.allocate(length); - var ctrlTransfer = createCtrlTransfer(session, USBDirection.IN, setup, data); + try (var arena = Arena.openConfined()) { + var data = arena.allocate(length); + var ctrlTransfer = createCtrlTransfer(arena, USBDirection.IN, setup, data); int res = ioctl.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer.address()); if (res < 0) @@ -189,12 +189,12 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { @Override public void controlTransferOut(USBControlTransfer setup, byte[] data) { - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined()) { int dataLength = data != null ? data.length : 0; - var buffer = session.allocate(dataLength); + var buffer = arena.allocate(dataLength); if (dataLength != 0) buffer.copyFrom(MemorySegment.ofArray(data)); - var ctrlTransfer = createCtrlTransfer(session, USBDirection.OUT, setup, buffer); + var ctrlTransfer = createCtrlTransfer(arena, USBDirection.OUT, setup, buffer); int res = ioctl.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer.address()); if (res < 0) @@ -202,11 +202,11 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { } } - private MemorySegment createBulkTransfer(MemorySession session, byte endpointAddress, MemorySegment data, int timeout) { - var transfer = session.allocate(usbdevfs_bulktransfer.$LAYOUT()); + private MemorySegment createBulkTransfer(Arena arena, byte endpointAddress, MemorySegment data, int timeout) { + var transfer = arena.allocate(usbdevfs_bulktransfer.$LAYOUT()); usbdevfs_bulktransfer.ep$set(transfer, 255 & endpointAddress); usbdevfs_bulktransfer.len$set(transfer, (int) data.byteSize()); - usbdevfs_bulktransfer.data$set(transfer, data.address()); + usbdevfs_bulktransfer.data$set(transfer, data); usbdevfs_bulktransfer.timeout$set(transfer, timeout); return transfer; } @@ -216,10 +216,10 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { var endpointAddress = getEndpointAddress(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); - try (var session = MemorySession.openConfined()) { - var buffer = session.allocate(data.length); + try (var arena = Arena.openConfined()) { + var buffer = arena.allocate(data.length); buffer.copyFrom(MemorySegment.ofArray(data)); - var transfer = createBulkTransfer(session, endpointAddress, buffer, timeout); + var transfer = createBulkTransfer(arena, endpointAddress, buffer, timeout); int res = ioctl.ioctl(fd, USBDevFS.BULK, transfer.address()); if (res < 0) { @@ -239,10 +239,10 @@ public byte[] transferIn(int endpointNumber, int timeout) { var endpoint = getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); - try (var session = MemorySession.openConfined()) { - var buffer = session.allocate(endpoint.packetSize()); + try (var arena = Arena.openConfined()) { + var buffer = arena.allocate(endpoint.packetSize()); - var transfer = createBulkTransfer(session, endpoint.endpointAddress(), buffer, timeout); + var transfer = createBulkTransfer(arena, endpoint.endpointAddress(), buffer, timeout); int res = ioctl.ioctl(fd, USBDevFS.BULK, transfer.address()); if (res < 0) { @@ -264,8 +264,8 @@ public void clearHalt(USBDirection direction, int endpointNumber) { var endpointAddress = getEndpointAddress(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); - try (var session = MemorySession.openConfined()) { - var endpointAddrSegment = session.allocate(JAVA_INT, endpointAddress & 0xff); + try (var arena = Arena.openConfined()) { + var endpointAddrSegment = arena.allocate(JAVA_INT, endpointAddress & 0xff); int res = ioctl.ioctl(fd, USBDevFS.CLEAR_HALT, endpointAddrSegment.address()); if (res < 0) throwLastError("Clearing halt failed"); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 6837fa34..fcd87714 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -8,19 +8,19 @@ package net.codecrete.usb.linux; import net.codecrete.usb.USBDevice; +import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.common.USBDeviceRegistry; import net.codecrete.usb.linux.gen.poll.poll; import net.codecrete.usb.linux.gen.poll.pollfd; import net.codecrete.usb.linux.gen.udev.udev; -import java.lang.foreign.Addressable; -import java.lang.foreign.MemoryAddress; +import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SegmentScope; import java.util.ArrayList; import java.util.List; -import static java.lang.foreign.MemoryAddress.NULL; import static net.codecrete.usb.linux.LinuxUSBException.throwException; /** @@ -28,24 +28,25 @@ */ public class LinuxUSBDeviceRegistry extends USBDeviceRegistry { - private static final MemorySegment SUBSYSTEM_USB = MemorySession.global().allocateUtf8String("usb"); - private static final MemorySegment MONITOR_NAME = MemorySession.global().allocateUtf8String("udev"); - private static final MemorySegment DEVTYPE_USB_DEVICE = MemorySession.global().allocateUtf8String("usb_device"); + private static final SegmentAllocator GLOBAL_ALLOCATOR = SegmentAllocator.nativeAllocator(SegmentScope.global()); + private static final MemorySegment SUBSYSTEM_USB = GLOBAL_ALLOCATOR.allocateUtf8String("usb"); + private static final MemorySegment MONITOR_NAME = GLOBAL_ALLOCATOR.allocateUtf8String("udev"); + private static final MemorySegment DEVTYPE_USB_DEVICE = GLOBAL_ALLOCATOR.allocateUtf8String("usb_device"); @Override protected void monitorDevices() { int fd; - MemoryAddress monitor; + MemorySegment monitor; try { // setup udev monitor var udevInstance = udev.udev_new(); - if (udevInstance == NULL) + if (udevInstance.address() == 0) throwException("internal error (udev_new)"); monitor = udev.udev_monitor_new_from_netlink(udevInstance, MONITOR_NAME); - if (monitor == NULL) + if (monitor.address() == 0) throwException("internal error (udev_monitor_new_from_netlink)"); if (udev.udev_monitor_filter_add_match_subsystem_devtype(monitor, SUBSYSTEM_USB, DEVTYPE_USB_DEVICE) < 0) @@ -70,17 +71,17 @@ protected void monitorDevices() { // monitor device changes //noinspection InfiniteLoopStatement while (true) { - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined(); var cleanup = new ScopeCleanup()) { // wait for next change - waitForFileDescriptor(fd, session); + waitForFileDescriptor(fd, arena); // retrieve change var udevDevice = udev.udev_monitor_receive_device(monitor); if (udevDevice == null) continue; // shouldn't happen - session.addCloseAction(() -> udev.udev_device_unref(udevDevice)); + cleanup.add(() -> udev.udev_device_unref(udevDevice)); // get details var action = getDeviceAction(udevDevice); @@ -94,16 +95,16 @@ protected void monitorDevices() { } } - private List enumeratePresentDevices(Addressable udevInstance) { + private List enumeratePresentDevices(MemorySegment udevInstance) { List result = new ArrayList<>(); - try (var outerSession = MemorySession.openConfined()) { + try (var outerCleanup = new ScopeCleanup()) { // create device enumerator var enumerate = udev.udev_enumerate_new(udevInstance); - if (enumerate == NULL) + if (enumerate.address() == 0) throwException("internal error (udev_enumerate_new)"); - outerSession.addCloseAction(() -> udev.udev_enumerate_unref(enumerate)); + outerCleanup.add(() -> udev.udev_enumerate_unref(enumerate)); if (udev.udev_enumerate_add_match_subsystem(enumerate, SUBSYSTEM_USB) < 0) throwException("internal error (udev_enumerate_add_match_subsystem)"); @@ -112,22 +113,22 @@ private List enumeratePresentDevices(Addressable udevInstance) { throwException("internal error (udev_enumerate_scan_devices)"); // enumerate devices - for (var entry = udev.udev_enumerate_get_list_entry(enumerate); entry != NULL; entry = + for (var entry = udev.udev_enumerate_get_list_entry(enumerate); entry.address() != 0; entry = udev.udev_list_entry_get_next(entry)) { - try (var session = MemorySession.openConfined()) { + try (var cleanup = new ScopeCleanup()) { var path = udev.udev_list_entry_get_name(entry); - if (path == NULL) + if (path.address() == 0) continue; // get device handle var dev = udev.udev_device_new_from_syspath(udevInstance, path); - if (dev == NULL) + if (dev.address() == 0) continue; // ensure the device is released - session.addCloseAction(() -> udev.udev_device_unref(dev)); + cleanup.add(() -> udev.udev_device_unref(dev)); // get device details var device = getDeviceDetails(dev); @@ -140,14 +141,14 @@ private List enumeratePresentDevices(Addressable udevInstance) { return result; } - private void onDeviceConnected(MemoryAddress udevDevice) { + private void onDeviceConnected(MemorySegment udevDevice) { var device = getDeviceDetails(udevDevice); if (device != null) addDevice(device); } - private void onDeviceDisconnected(MemoryAddress udevDevice) { + private void onDeviceDisconnected(MemorySegment udevDevice) { var devPath = getDeviceName(udevDevice); if (devPath == null) @@ -166,7 +167,7 @@ private void onDeviceDisconnected(MemoryAddress udevDevice) { * @param udevDevice the device (udev_device*) * @return the device instance */ - private static USBDevice getDeviceDetails(MemoryAddress udevDevice) { + private static USBDevice getDeviceDetails(MemorySegment udevDevice) { int vendorId = 0; int productId = 0; @@ -205,23 +206,22 @@ private static USBDevice getDeviceDetails(MemoryAddress udevDevice) { } } - private static String getDeviceAttribute(Addressable udevDevice, String attribute) { - try (var session = MemorySession.openConfined()) { - var sysattr = session.allocateUtf8String(attribute); - var valueAddr = udev.udev_device_get_sysattr_value(udevDevice, sysattr); - if (valueAddr == NULL) + private static String getDeviceAttribute(MemorySegment udevDevice, String attribute) { + try (var arena = Arena.openConfined()) { + var sysattr = arena.allocateUtf8String(attribute); + var value = udev.udev_device_get_sysattr_value(udevDevice, sysattr); + if (value.address() == 0) return null; - var value = MemorySegment.ofAddress(valueAddr, 2000, session); return value.getUtf8String(0); } } - private static String getDeviceName(Addressable udevDevice) { + private static String getDeviceName(MemorySegment udevDevice) { return udev.udev_device_get_devnode(udevDevice).getUtf8String(0); } - private static String getDeviceAction(Addressable udevDevice) { + private static String getDeviceAction(MemorySegment udevDevice) { return udev.udev_device_get_action(udevDevice).getUtf8String(0); } @@ -229,10 +229,10 @@ private static String getDeviceAction(Addressable udevDevice) { * Waits until the specified file descriptor becomes ready for reading. * * @param fd the file descriptor - * @param session a memory session for allocating memory + * @param arena an arena for allocating memory */ - private static void waitForFileDescriptor(int fd, MemorySession session) { - var fds = session.allocate(pollfd.$LAYOUT()); + private static void waitForFileDescriptor(int fd, Arena arena) { + var fds = arena.allocate(pollfd.$LAYOUT()); pollfd.fd$set(fds, fd); pollfd.events$set(fds, (short) poll.POLLIN()); int res = poll.poll(fds, 1, -1); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java index 5c0bd3fc..2e579017 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java @@ -12,10 +12,10 @@ */ public class USBDevFS { - public static final long CONTROL = 0xc0185500; - public static final long BULK = 0xc0185502; - public static final long CLAIMINTERFACE = 0x8004550F; - public static final long RELEASEINTERFACE = 0x80045510; - public static final long SETINTERFACE = 0x80085504; - public static final long CLEAR_HALT = 0x80045515; + public static final long CONTROL = 0xc0185500L; + public static final long BULK = 0xc0185502L; + public static final long CLAIMINTERFACE = 0x8004550FL; + public static final long RELEASEINTERFACE = 0x80045510L; + public static final long SETINTERFACE = 0x80085504L; + public static final long CLEAR_HALT = 0x80045515L; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/Constants$root.java index 73adc572..495f0826 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.linux.gen.errno; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfLong C_LONG$LAYOUT = JAVA_LONG; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/RuntimeHelper.java index 282b5dfb..df62e601 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/RuntimeHelper.java @@ -10,21 +10,24 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -32,45 +35,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -96,7 +97,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -106,8 +109,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -142,7 +144,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -192,10 +196,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -206,7 +207,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java index cb3211ae..5fc22cee 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$0 { +final class constants$0 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} static final FunctionDescriptor __errno_location$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT); static final MethodHandle __errno_location$MH = RuntimeHelper.downcallHandle( "__errno_location", diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java index 1d7415bc..f3f25c95 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -2,34 +2,48 @@ package net.codecrete.usb.linux.gen.errno; -import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class errno { - /* package-private */ errno() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + /** + * {@snippet : + * #define EPIPE 32 + * } + */ public static int EPIPE() { return (int)32L; } + /** + * {@snippet : + * #define ETIMEDOUT 110 + * } + */ public static int ETIMEDOUT() { return (int)110L; } public static MethodHandle __errno_location$MH() { return RuntimeHelper.requireNonNull(constants$0.__errno_location$MH,"__errno_location"); } - public static MemoryAddress __errno_location () { + /** + * {@snippet : + * int* __errno_location(); + * } + */ + public static MemorySegment __errno_location() { var mh$ = __errno_location$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/Constants$root.java index c938e854..0d01265b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.linux.gen.fcntl; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfLong C_LONG$LAYOUT = JAVA_LONG; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/RuntimeHelper.java index 48c09b33..a8fb98e4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/RuntimeHelper.java @@ -10,21 +10,24 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -32,45 +35,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -96,7 +97,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -106,8 +109,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -142,7 +144,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -192,10 +196,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -206,7 +207,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java index 517dcb8f..c02210dd 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$0 { +final class constants$0 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} static final FunctionDescriptor open$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_INT$LAYOUT diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java index 41eb1e0c..388f45cf 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java @@ -2,28 +2,37 @@ package net.codecrete.usb.linux.gen.fcntl; -import java.lang.foreign.Addressable; +import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class fcntl { - /* package-private */ fcntl() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + /** + * {@snippet : + * #define O_RDWR 2 + * } + */ public static int O_RDWR() { return (int)2L; } public static MethodHandle open$MH() { return RuntimeHelper.requireNonNull(constants$0.open$MH,"open"); } - public static int open ( Addressable __file, int __oflag, Object... x2) { + /** + * {@snippet : + * int open(char* __file, int __oflag,...); + * } + */ + public static int open(MemorySegment __file, int __oflag, Object... x2) { var mh$ = open$MH(); try { return (int)mh$.invokeExact(__file, __oflag, x2); @@ -31,6 +40,11 @@ public static int open ( Addressable __file, int __oflag, Object... x2) { throw new AssertionError("should not reach here", ex$); } } + /** + * {@snippet : + * #define O_CLOEXEC 524288 + * } + */ public static int O_CLOEXEC() { return (int)524288L; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/Constants$root.java index c9e48345..78cd5fc9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.linux.gen.ioctl; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfLong C_LONG$LAYOUT = JAVA_LONG; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/RuntimeHelper.java index e7740016..4793bce4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/RuntimeHelper.java @@ -10,21 +10,24 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -32,45 +35,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -96,7 +97,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -106,8 +109,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -142,7 +144,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -192,10 +196,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -206,7 +207,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/constants$0.java index e68a7892..f22a30d1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/constants$0.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$0 { +final class constants$0 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} static final FunctionDescriptor ioctl$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_INT$LAYOUT, Constants$root.C_LONG_LONG$LAYOUT diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/ioctl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/ioctl.java index cbe51a0b..72a6f793 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/ioctl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/ioctl.java @@ -7,19 +7,23 @@ import static java.lang.foreign.ValueLayout.*; public class ioctl { - /* package-private */ ioctl() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; public static MethodHandle ioctl$MH() { return RuntimeHelper.requireNonNull(constants$0.ioctl$MH,"ioctl"); } - public static int ioctl ( int __fd, long __request, Object... x2) { + /** + * {@snippet : + * int ioctl(int __fd, unsigned long __request,...); + * } + */ + public static int ioctl(int __fd, long __request, Object... x2) { var mh$ = ioctl$MH(); try { return (int)mh$.invokeExact(__fd, __request, x2); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/Constants$root.java index 80ad3009..3445f223 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.linux.gen.poll; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfLong C_LONG$LAYOUT = JAVA_LONG; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/RuntimeHelper.java index e5aded55..7903bdec 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/RuntimeHelper.java @@ -10,21 +10,24 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -32,45 +35,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -96,7 +97,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -106,8 +109,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -142,7 +144,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -192,10 +196,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -206,7 +207,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java index 5ec525aa..910ee5dc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$0 { +final class constants$0 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} static final FunctionDescriptor poll$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_LONG_LONG$LAYOUT, diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java index 22cd1353..8fd51513 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java @@ -2,28 +2,37 @@ package net.codecrete.usb.linux.gen.poll; -import java.lang.foreign.Addressable; +import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class poll { - /* package-private */ poll() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + /** + * {@snippet : + * #define POLLIN 1 + * } + */ public static int POLLIN() { return (int)1L; } public static MethodHandle poll$MH() { return RuntimeHelper.requireNonNull(constants$0.poll$MH,"poll"); } - public static int poll ( Addressable __fds, long __nfds, int __timeout) { + /** + * {@snippet : + * int poll(struct pollfd* __fds, nfds_t __nfds, int __timeout); + * } + */ + public static int poll(MemorySegment __fds, long __nfds, int __timeout) { var mh$ = poll$MH(); try { return (int)mh$.invokeExact(__fds, __nfds, __timeout); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java index b96bf436..fe79fb38 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java @@ -4,9 +4,18 @@ import java.lang.foreign.*; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct pollfd { + * int fd; + * short events; + * short revents; + * }; + * } + */ public class pollfd { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_INT$LAYOUT.withName("fd"), Constants$root.C_SHORT$LAYOUT.withName("events"), Constants$root.C_SHORT$LAYOUT.withName("revents") @@ -18,10 +27,22 @@ public class pollfd { public static VarHandle fd$VH() { return pollfd.fd$VH; } + /** + * Getter for field: + * {@snippet : + * int fd; + * } + */ public static int fd$get(MemorySegment seg) { return (int)pollfd.fd$VH.get(seg); } - public static void fd$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * int fd; + * } + */ + public static void fd$set(MemorySegment seg, int x) { pollfd.fd$VH.set(seg, x); } public static int fd$get(MemorySegment seg, long index) { @@ -34,10 +55,22 @@ public class pollfd { public static VarHandle events$VH() { return pollfd.events$VH; } + /** + * Getter for field: + * {@snippet : + * short events; + * } + */ public static short events$get(MemorySegment seg) { return (short)pollfd.events$VH.get(seg); } - public static void events$set( MemorySegment seg, short x) { + /** + * Setter for field: + * {@snippet : + * short events; + * } + */ + public static void events$set(MemorySegment seg, short x) { pollfd.events$VH.set(seg, x); } public static short events$get(MemorySegment seg, long index) { @@ -50,10 +83,22 @@ public class pollfd { public static VarHandle revents$VH() { return pollfd.revents$VH; } + /** + * Getter for field: + * {@snippet : + * short revents; + * } + */ public static short revents$get(MemorySegment seg) { return (short)pollfd.revents$VH.get(seg); } - public static void revents$set( MemorySegment seg, short x) { + /** + * Setter for field: + * {@snippet : + * short revents; + * } + */ + public static void revents$set(MemorySegment seg, short x) { pollfd.revents$VH.set(seg, x); } public static short revents$get(MemorySegment seg, long index) { @@ -64,10 +109,10 @@ public class pollfd { } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/Constants$root.java index 93e06058..1f613abd 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.linux.gen.string; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfLong C_LONG$LAYOUT = JAVA_LONG; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/RuntimeHelper.java index 6314d452..c0f67e19 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/RuntimeHelper.java @@ -10,21 +10,24 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -32,45 +35,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -96,7 +97,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -106,8 +109,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -142,7 +144,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -192,10 +196,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -206,7 +207,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/constants$0.java index 1953dd0d..dd5b8842 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/constants$0.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$0 { +final class constants$0 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} static final FunctionDescriptor strerror$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, Constants$root.C_INT$LAYOUT ); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java index 37dcf414..f123addd 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java @@ -2,28 +2,32 @@ package net.codecrete.usb.linux.gen.string; -import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class string { - /* package-private */ string() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; public static MethodHandle strerror$MH() { return RuntimeHelper.requireNonNull(constants$0.strerror$MH,"strerror"); } - public static MemoryAddress strerror ( int __errnum) { + /** + * {@snippet : + * char* strerror(int __errnum); + * } + */ + public static MemorySegment strerror(int __errnum) { var mh$ = strerror$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(__errnum); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(__errnum); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/Constants$root.java index 2a06330e..c5a7e16a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.linux.gen.udev; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfLong C_LONG$LAYOUT = JAVA_LONG; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java index 775c0b6c..9529b895 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java @@ -10,22 +10,25 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { // System.loadLibrary("udev"); // SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so", MemorySession.openImplicit()); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so", SegmentScope.global()); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -33,45 +36,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -97,7 +98,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -107,8 +110,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -143,7 +145,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -193,10 +197,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -207,7 +208,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java index 962ea187..4e98a486 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$0 { +final class constants$0 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} static final FunctionDescriptor udev_new$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT); static final MethodHandle udev_new$MH = RuntimeHelper.downcallHandle( "udev_new", diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java index 986a90d3..cb5309af 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$1 { +final class constants$1 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$1() {} static final FunctionDescriptor udev_device_get_devnode$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT ); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$2.java index 47b95ed6..a8a06524 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$2.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$2 { +final class constants$2 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$2() {} static final FunctionDescriptor udev_monitor_receive_device$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT ); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$3.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$3.java index 862a7270..4478b0f9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$3.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$3.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$3 { +final class constants$3 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$3() {} static final FunctionDescriptor udev_enumerate_get_list_entry$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT ); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java index ea5160ae..2e40e26f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java @@ -2,29 +2,32 @@ package net.codecrete.usb.linux.gen.udev; -import java.lang.foreign.Addressable; -import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class udev { - /* package-private */ udev() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; public static MethodHandle udev_new$MH() { return RuntimeHelper.requireNonNull(constants$0.udev_new$MH,"udev_new"); } - public static MemoryAddress udev_new () { + /** + * {@snippet : + * struct udev* udev_new(); + * } + */ + public static MemorySegment udev_new() { var mh$ = udev_new$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -32,10 +35,15 @@ public static MemoryAddress udev_new () { public static MethodHandle udev_list_entry_get_next$MH() { return RuntimeHelper.requireNonNull(constants$0.udev_list_entry_get_next$MH,"udev_list_entry_get_next"); } - public static MemoryAddress udev_list_entry_get_next ( Addressable list_entry) { + /** + * {@snippet : + * struct udev_list_entry* udev_list_entry_get_next(struct udev_list_entry* list_entry); + * } + */ + public static MemorySegment udev_list_entry_get_next(MemorySegment list_entry) { var mh$ = udev_list_entry_get_next$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(list_entry); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(list_entry); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -43,10 +51,15 @@ public static MemoryAddress udev_list_entry_get_next ( Addressable list_entry) { public static MethodHandle udev_list_entry_get_name$MH() { return RuntimeHelper.requireNonNull(constants$0.udev_list_entry_get_name$MH,"udev_list_entry_get_name"); } - public static MemoryAddress udev_list_entry_get_name ( Addressable list_entry) { + /** + * {@snippet : + * char* udev_list_entry_get_name(struct udev_list_entry* list_entry); + * } + */ + public static MemorySegment udev_list_entry_get_name(MemorySegment list_entry) { var mh$ = udev_list_entry_get_name$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(list_entry); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(list_entry); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -54,10 +67,15 @@ public static MemoryAddress udev_list_entry_get_name ( Addressable list_entry) { public static MethodHandle udev_device_unref$MH() { return RuntimeHelper.requireNonNull(constants$0.udev_device_unref$MH,"udev_device_unref"); } - public static MemoryAddress udev_device_unref ( Addressable udev_device) { + /** + * {@snippet : + * struct udev_device* udev_device_unref(struct udev_device* udev_device); + * } + */ + public static MemorySegment udev_device_unref(MemorySegment udev_device) { var mh$ = udev_device_unref$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev_device); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev_device); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -65,10 +83,15 @@ public static MemoryAddress udev_device_unref ( Addressable udev_device) { public static MethodHandle udev_device_new_from_syspath$MH() { return RuntimeHelper.requireNonNull(constants$0.udev_device_new_from_syspath$MH,"udev_device_new_from_syspath"); } - public static MemoryAddress udev_device_new_from_syspath ( Addressable udev, Addressable syspath) { + /** + * {@snippet : + * struct udev_device* udev_device_new_from_syspath(struct udev* udev, char* syspath); + * } + */ + public static MemorySegment udev_device_new_from_syspath(MemorySegment udev, MemorySegment syspath) { var mh$ = udev_device_new_from_syspath$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev, syspath); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev, syspath); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -76,10 +99,15 @@ public static MemoryAddress udev_device_new_from_syspath ( Addressable udev, Ad public static MethodHandle udev_device_get_devtype$MH() { return RuntimeHelper.requireNonNull(constants$0.udev_device_get_devtype$MH,"udev_device_get_devtype"); } - public static MemoryAddress udev_device_get_devtype ( Addressable udev_device) { + /** + * {@snippet : + * char* udev_device_get_devtype(struct udev_device* udev_device); + * } + */ + public static MemorySegment udev_device_get_devtype(MemorySegment udev_device) { var mh$ = udev_device_get_devtype$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev_device); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev_device); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -87,10 +115,15 @@ public static MemoryAddress udev_device_get_devtype ( Addressable udev_device) { public static MethodHandle udev_device_get_devnode$MH() { return RuntimeHelper.requireNonNull(constants$1.udev_device_get_devnode$MH,"udev_device_get_devnode"); } - public static MemoryAddress udev_device_get_devnode ( Addressable udev_device) { + /** + * {@snippet : + * char* udev_device_get_devnode(struct udev_device* udev_device); + * } + */ + public static MemorySegment udev_device_get_devnode(MemorySegment udev_device) { var mh$ = udev_device_get_devnode$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev_device); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev_device); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -98,10 +131,15 @@ public static MemoryAddress udev_device_get_devnode ( Addressable udev_device) { public static MethodHandle udev_device_get_action$MH() { return RuntimeHelper.requireNonNull(constants$1.udev_device_get_action$MH,"udev_device_get_action"); } - public static MemoryAddress udev_device_get_action ( Addressable udev_device) { + /** + * {@snippet : + * char* udev_device_get_action(struct udev_device* udev_device); + * } + */ + public static MemorySegment udev_device_get_action(MemorySegment udev_device) { var mh$ = udev_device_get_action$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev_device); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev_device); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -109,10 +147,15 @@ public static MemoryAddress udev_device_get_action ( Addressable udev_device) { public static MethodHandle udev_device_get_sysattr_value$MH() { return RuntimeHelper.requireNonNull(constants$1.udev_device_get_sysattr_value$MH,"udev_device_get_sysattr_value"); } - public static MemoryAddress udev_device_get_sysattr_value ( Addressable udev_device, Addressable sysattr) { + /** + * {@snippet : + * char* udev_device_get_sysattr_value(struct udev_device* udev_device, char* sysattr); + * } + */ + public static MemorySegment udev_device_get_sysattr_value(MemorySegment udev_device, MemorySegment sysattr) { var mh$ = udev_device_get_sysattr_value$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev_device, sysattr); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev_device, sysattr); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -120,10 +163,15 @@ public static MemoryAddress udev_device_get_sysattr_value ( Addressable udev_dev public static MethodHandle udev_monitor_new_from_netlink$MH() { return RuntimeHelper.requireNonNull(constants$1.udev_monitor_new_from_netlink$MH,"udev_monitor_new_from_netlink"); } - public static MemoryAddress udev_monitor_new_from_netlink ( Addressable udev, Addressable name) { + /** + * {@snippet : + * struct udev_monitor* udev_monitor_new_from_netlink(struct udev* udev, char* name); + * } + */ + public static MemorySegment udev_monitor_new_from_netlink(MemorySegment udev, MemorySegment name) { var mh$ = udev_monitor_new_from_netlink$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev, name); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev, name); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -131,7 +179,12 @@ public static MemoryAddress udev_monitor_new_from_netlink ( Addressable udev, A public static MethodHandle udev_monitor_enable_receiving$MH() { return RuntimeHelper.requireNonNull(constants$1.udev_monitor_enable_receiving$MH,"udev_monitor_enable_receiving"); } - public static int udev_monitor_enable_receiving ( Addressable udev_monitor) { + /** + * {@snippet : + * int udev_monitor_enable_receiving(struct udev_monitor* udev_monitor); + * } + */ + public static int udev_monitor_enable_receiving(MemorySegment udev_monitor) { var mh$ = udev_monitor_enable_receiving$MH(); try { return (int)mh$.invokeExact(udev_monitor); @@ -142,7 +195,12 @@ public static int udev_monitor_enable_receiving ( Addressable udev_monitor) { public static MethodHandle udev_monitor_get_fd$MH() { return RuntimeHelper.requireNonNull(constants$1.udev_monitor_get_fd$MH,"udev_monitor_get_fd"); } - public static int udev_monitor_get_fd ( Addressable udev_monitor) { + /** + * {@snippet : + * int udev_monitor_get_fd(struct udev_monitor* udev_monitor); + * } + */ + public static int udev_monitor_get_fd(MemorySegment udev_monitor) { var mh$ = udev_monitor_get_fd$MH(); try { return (int)mh$.invokeExact(udev_monitor); @@ -153,10 +211,15 @@ public static int udev_monitor_get_fd ( Addressable udev_monitor) { public static MethodHandle udev_monitor_receive_device$MH() { return RuntimeHelper.requireNonNull(constants$2.udev_monitor_receive_device$MH,"udev_monitor_receive_device"); } - public static MemoryAddress udev_monitor_receive_device ( Addressable udev_monitor) { + /** + * {@snippet : + * struct udev_device* udev_monitor_receive_device(struct udev_monitor* udev_monitor); + * } + */ + public static MemorySegment udev_monitor_receive_device(MemorySegment udev_monitor) { var mh$ = udev_monitor_receive_device$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev_monitor); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev_monitor); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -164,7 +227,12 @@ public static MemoryAddress udev_monitor_receive_device ( Addressable udev_monit public static MethodHandle udev_monitor_filter_add_match_subsystem_devtype$MH() { return RuntimeHelper.requireNonNull(constants$2.udev_monitor_filter_add_match_subsystem_devtype$MH,"udev_monitor_filter_add_match_subsystem_devtype"); } - public static int udev_monitor_filter_add_match_subsystem_devtype ( Addressable udev_monitor, Addressable subsystem, Addressable devtype) { + /** + * {@snippet : + * int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor* udev_monitor, char* subsystem, char* devtype); + * } + */ + public static int udev_monitor_filter_add_match_subsystem_devtype(MemorySegment udev_monitor, MemorySegment subsystem, MemorySegment devtype) { var mh$ = udev_monitor_filter_add_match_subsystem_devtype$MH(); try { return (int)mh$.invokeExact(udev_monitor, subsystem, devtype); @@ -175,10 +243,15 @@ public static int udev_monitor_filter_add_match_subsystem_devtype ( Addressable public static MethodHandle udev_enumerate_unref$MH() { return RuntimeHelper.requireNonNull(constants$2.udev_enumerate_unref$MH,"udev_enumerate_unref"); } - public static MemoryAddress udev_enumerate_unref ( Addressable udev_enumerate) { + /** + * {@snippet : + * struct udev_enumerate* udev_enumerate_unref(struct udev_enumerate* udev_enumerate); + * } + */ + public static MemorySegment udev_enumerate_unref(MemorySegment udev_enumerate) { var mh$ = udev_enumerate_unref$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev_enumerate); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev_enumerate); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -186,10 +259,15 @@ public static MemoryAddress udev_enumerate_unref ( Addressable udev_enumerate) { public static MethodHandle udev_enumerate_new$MH() { return RuntimeHelper.requireNonNull(constants$2.udev_enumerate_new$MH,"udev_enumerate_new"); } - public static MemoryAddress udev_enumerate_new ( Addressable udev) { + /** + * {@snippet : + * struct udev_enumerate* udev_enumerate_new(struct udev* udev); + * } + */ + public static MemorySegment udev_enumerate_new(MemorySegment udev) { var mh$ = udev_enumerate_new$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -197,7 +275,12 @@ public static MemoryAddress udev_enumerate_new ( Addressable udev) { public static MethodHandle udev_enumerate_add_match_subsystem$MH() { return RuntimeHelper.requireNonNull(constants$2.udev_enumerate_add_match_subsystem$MH,"udev_enumerate_add_match_subsystem"); } - public static int udev_enumerate_add_match_subsystem ( Addressable udev_enumerate, Addressable subsystem) { + /** + * {@snippet : + * int udev_enumerate_add_match_subsystem(struct udev_enumerate* udev_enumerate, char* subsystem); + * } + */ + public static int udev_enumerate_add_match_subsystem(MemorySegment udev_enumerate, MemorySegment subsystem) { var mh$ = udev_enumerate_add_match_subsystem$MH(); try { return (int)mh$.invokeExact(udev_enumerate, subsystem); @@ -208,7 +291,12 @@ public static int udev_enumerate_add_match_subsystem ( Addressable udev_enumerat public static MethodHandle udev_enumerate_scan_devices$MH() { return RuntimeHelper.requireNonNull(constants$2.udev_enumerate_scan_devices$MH,"udev_enumerate_scan_devices"); } - public static int udev_enumerate_scan_devices ( Addressable udev_enumerate) { + /** + * {@snippet : + * int udev_enumerate_scan_devices(struct udev_enumerate* udev_enumerate); + * } + */ + public static int udev_enumerate_scan_devices(MemorySegment udev_enumerate) { var mh$ = udev_enumerate_scan_devices$MH(); try { return (int)mh$.invokeExact(udev_enumerate); @@ -219,10 +307,15 @@ public static int udev_enumerate_scan_devices ( Addressable udev_enumerate) { public static MethodHandle udev_enumerate_get_list_entry$MH() { return RuntimeHelper.requireNonNull(constants$3.udev_enumerate_get_list_entry$MH,"udev_enumerate_get_list_entry"); } - public static MemoryAddress udev_enumerate_get_list_entry ( Addressable udev_enumerate) { + /** + * {@snippet : + * struct udev_list_entry* udev_enumerate_get_list_entry(struct udev_enumerate* udev_enumerate); + * } + */ + public static MemorySegment udev_enumerate_get_list_entry(MemorySegment udev_enumerate) { var mh$ = udev_enumerate_get_list_entry$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(udev_enumerate); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev_enumerate); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/Constants$root.java index 1fe4e3c0..3113cb6a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.linux.gen.unistd; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfLong C_LONG$LAYOUT = JAVA_LONG; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/RuntimeHelper.java index b771271b..46a7b0b5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/RuntimeHelper.java @@ -10,21 +10,24 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -32,45 +35,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -96,7 +97,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -106,8 +109,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -142,7 +144,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -192,10 +196,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -206,7 +207,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java index 26995ca4..119099ac 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$0 { +final class constants$0 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} static final FunctionDescriptor close$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_INT$LAYOUT ); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java index 74045e41..18b6db19 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java @@ -7,19 +7,23 @@ import static java.lang.foreign.ValueLayout.*; public class unistd { - /* package-private */ unistd() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; public static MethodHandle close$MH() { return RuntimeHelper.requireNonNull(constants$0.close$MH,"close"); } - public static int close ( int __fd) { + /** + * {@snippet : + * int close(int __fd); + * } + */ + public static int close(int __fd) { var mh$ = close$MH(); try { return (int)mh$.invokeExact(__fd); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/Constants$root.java index e013f088..8ef9a790 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfLong C_LONG$LAYOUT = JAVA_LONG; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/RuntimeHelper.java index 8d30b2af..dea9a0d2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/RuntimeHelper.java @@ -10,21 +10,24 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -32,45 +35,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -96,7 +97,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -106,8 +109,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -142,7 +144,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -192,10 +196,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -206,7 +207,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java index 670dc414..f8688893 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java @@ -4,9 +4,19 @@ import java.lang.foreign.*; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct usbdevfs_bulktransfer { + * unsigned int ep; + * unsigned int len; + * unsigned int timeout; + * void* data; + * }; + * } + */ public class usbdevfs_bulktransfer { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_INT$LAYOUT.withName("ep"), Constants$root.C_INT$LAYOUT.withName("len"), Constants$root.C_INT$LAYOUT.withName("timeout"), @@ -20,10 +30,22 @@ public class usbdevfs_bulktransfer { public static VarHandle ep$VH() { return usbdevfs_bulktransfer.ep$VH; } + /** + * Getter for field: + * {@snippet : + * unsigned int ep; + * } + */ public static int ep$get(MemorySegment seg) { return (int)usbdevfs_bulktransfer.ep$VH.get(seg); } - public static void ep$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * unsigned int ep; + * } + */ + public static void ep$set(MemorySegment seg, int x) { usbdevfs_bulktransfer.ep$VH.set(seg, x); } public static int ep$get(MemorySegment seg, long index) { @@ -36,10 +58,22 @@ public class usbdevfs_bulktransfer { public static VarHandle len$VH() { return usbdevfs_bulktransfer.len$VH; } + /** + * Getter for field: + * {@snippet : + * unsigned int len; + * } + */ public static int len$get(MemorySegment seg) { return (int)usbdevfs_bulktransfer.len$VH.get(seg); } - public static void len$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * unsigned int len; + * } + */ + public static void len$set(MemorySegment seg, int x) { usbdevfs_bulktransfer.len$VH.set(seg, x); } public static int len$get(MemorySegment seg, long index) { @@ -52,10 +86,22 @@ public class usbdevfs_bulktransfer { public static VarHandle timeout$VH() { return usbdevfs_bulktransfer.timeout$VH; } + /** + * Getter for field: + * {@snippet : + * unsigned int timeout; + * } + */ public static int timeout$get(MemorySegment seg) { return (int)usbdevfs_bulktransfer.timeout$VH.get(seg); } - public static void timeout$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * unsigned int timeout; + * } + */ + public static void timeout$set(MemorySegment seg, int x) { usbdevfs_bulktransfer.timeout$VH.set(seg, x); } public static int timeout$get(MemorySegment seg, long index) { @@ -68,24 +114,36 @@ public class usbdevfs_bulktransfer { public static VarHandle data$VH() { return usbdevfs_bulktransfer.data$VH; } - public static MemoryAddress data$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)usbdevfs_bulktransfer.data$VH.get(seg); - } - public static void data$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * void* data; + * } + */ + public static MemorySegment data$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)usbdevfs_bulktransfer.data$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * void* data; + * } + */ + public static void data$set(MemorySegment seg, MemorySegment x) { usbdevfs_bulktransfer.data$VH.set(seg, x); } - public static MemoryAddress data$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)usbdevfs_bulktransfer.data$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment data$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)usbdevfs_bulktransfer.data$VH.get(seg.asSlice(index*sizeof())); } - public static void data$set(MemorySegment seg, long index, MemoryAddress x) { + public static void data$set(MemorySegment seg, long index, MemorySegment x) { usbdevfs_bulktransfer.data$VH.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java index 2dd9c901..78e0ae34 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java @@ -4,9 +4,22 @@ import java.lang.foreign.*; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct usbdevfs_ctrltransfer { + * __u8 bRequestType; + * __u8 bRequest; + * __u16 wValue; + * __u16 wIndex; + * __u16 wLength; + * __u32 timeout; + * void* data; + * }; + * } + */ public class usbdevfs_ctrltransfer { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_CHAR$LAYOUT.withName("bRequestType"), Constants$root.C_CHAR$LAYOUT.withName("bRequest"), Constants$root.C_SHORT$LAYOUT.withName("wValue"), @@ -23,10 +36,22 @@ public class usbdevfs_ctrltransfer { public static VarHandle bRequestType$VH() { return usbdevfs_ctrltransfer.bRequestType$VH; } + /** + * Getter for field: + * {@snippet : + * __u8 bRequestType; + * } + */ public static byte bRequestType$get(MemorySegment seg) { return (byte)usbdevfs_ctrltransfer.bRequestType$VH.get(seg); } - public static void bRequestType$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * __u8 bRequestType; + * } + */ + public static void bRequestType$set(MemorySegment seg, byte x) { usbdevfs_ctrltransfer.bRequestType$VH.set(seg, x); } public static byte bRequestType$get(MemorySegment seg, long index) { @@ -39,10 +64,22 @@ public class usbdevfs_ctrltransfer { public static VarHandle bRequest$VH() { return usbdevfs_ctrltransfer.bRequest$VH; } + /** + * Getter for field: + * {@snippet : + * __u8 bRequest; + * } + */ public static byte bRequest$get(MemorySegment seg) { return (byte)usbdevfs_ctrltransfer.bRequest$VH.get(seg); } - public static void bRequest$set( MemorySegment seg, byte x) { + /** + * Setter for field: + * {@snippet : + * __u8 bRequest; + * } + */ + public static void bRequest$set(MemorySegment seg, byte x) { usbdevfs_ctrltransfer.bRequest$VH.set(seg, x); } public static byte bRequest$get(MemorySegment seg, long index) { @@ -55,10 +92,22 @@ public class usbdevfs_ctrltransfer { public static VarHandle wValue$VH() { return usbdevfs_ctrltransfer.wValue$VH; } + /** + * Getter for field: + * {@snippet : + * __u16 wValue; + * } + */ public static short wValue$get(MemorySegment seg) { return (short)usbdevfs_ctrltransfer.wValue$VH.get(seg); } - public static void wValue$set( MemorySegment seg, short x) { + /** + * Setter for field: + * {@snippet : + * __u16 wValue; + * } + */ + public static void wValue$set(MemorySegment seg, short x) { usbdevfs_ctrltransfer.wValue$VH.set(seg, x); } public static short wValue$get(MemorySegment seg, long index) { @@ -71,10 +120,22 @@ public class usbdevfs_ctrltransfer { public static VarHandle wIndex$VH() { return usbdevfs_ctrltransfer.wIndex$VH; } + /** + * Getter for field: + * {@snippet : + * __u16 wIndex; + * } + */ public static short wIndex$get(MemorySegment seg) { return (short)usbdevfs_ctrltransfer.wIndex$VH.get(seg); } - public static void wIndex$set( MemorySegment seg, short x) { + /** + * Setter for field: + * {@snippet : + * __u16 wIndex; + * } + */ + public static void wIndex$set(MemorySegment seg, short x) { usbdevfs_ctrltransfer.wIndex$VH.set(seg, x); } public static short wIndex$get(MemorySegment seg, long index) { @@ -87,10 +148,22 @@ public class usbdevfs_ctrltransfer { public static VarHandle wLength$VH() { return usbdevfs_ctrltransfer.wLength$VH; } + /** + * Getter for field: + * {@snippet : + * __u16 wLength; + * } + */ public static short wLength$get(MemorySegment seg) { return (short)usbdevfs_ctrltransfer.wLength$VH.get(seg); } - public static void wLength$set( MemorySegment seg, short x) { + /** + * Setter for field: + * {@snippet : + * __u16 wLength; + * } + */ + public static void wLength$set(MemorySegment seg, short x) { usbdevfs_ctrltransfer.wLength$VH.set(seg, x); } public static short wLength$get(MemorySegment seg, long index) { @@ -103,10 +176,22 @@ public class usbdevfs_ctrltransfer { public static VarHandle timeout$VH() { return usbdevfs_ctrltransfer.timeout$VH; } + /** + * Getter for field: + * {@snippet : + * __u32 timeout; + * } + */ public static int timeout$get(MemorySegment seg) { return (int)usbdevfs_ctrltransfer.timeout$VH.get(seg); } - public static void timeout$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * __u32 timeout; + * } + */ + public static void timeout$set(MemorySegment seg, int x) { usbdevfs_ctrltransfer.timeout$VH.set(seg, x); } public static int timeout$get(MemorySegment seg, long index) { @@ -119,24 +204,36 @@ public class usbdevfs_ctrltransfer { public static VarHandle data$VH() { return usbdevfs_ctrltransfer.data$VH; } - public static MemoryAddress data$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)usbdevfs_ctrltransfer.data$VH.get(seg); - } - public static void data$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * void* data; + * } + */ + public static MemorySegment data$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)usbdevfs_ctrltransfer.data$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * void* data; + * } + */ + public static void data$set(MemorySegment seg, MemorySegment x) { usbdevfs_ctrltransfer.data$VH.set(seg, x); } - public static MemoryAddress data$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)usbdevfs_ctrltransfer.data$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment data$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)usbdevfs_ctrltransfer.data$VH.get(seg.asSlice(index*sizeof())); } - public static void data$set(MemorySegment seg, long index, MemoryAddress x) { + public static void data$set(MemorySegment seg, long index, MemorySegment x) { usbdevfs_ctrltransfer.data$VH.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java index 0aec7f05..ea8ac910 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java @@ -4,9 +4,17 @@ import java.lang.foreign.*; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct usbdevfs_setinterface { + * unsigned int interface; + * unsigned int altsetting; + * }; + * } + */ public class usbdevfs_setinterface { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_INT$LAYOUT.withName("interface"), Constants$root.C_INT$LAYOUT.withName("altsetting") ).withName("usbdevfs_setinterface"); @@ -17,10 +25,22 @@ public class usbdevfs_setinterface { public static VarHandle interface_$VH() { return usbdevfs_setinterface.interface_$VH; } + /** + * Getter for field: + * {@snippet : + * unsigned int interface; + * } + */ public static int interface_$get(MemorySegment seg) { return (int)usbdevfs_setinterface.interface_$VH.get(seg); } - public static void interface_$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * unsigned int interface; + * } + */ + public static void interface_$set(MemorySegment seg, int x) { usbdevfs_setinterface.interface_$VH.set(seg, x); } public static int interface_$get(MemorySegment seg, long index) { @@ -33,10 +53,22 @@ public class usbdevfs_setinterface { public static VarHandle altsetting$VH() { return usbdevfs_setinterface.altsetting$VH; } + /** + * Getter for field: + * {@snippet : + * unsigned int altsetting; + * } + */ public static int altsetting$get(MemorySegment seg) { return (int)usbdevfs_setinterface.altsetting$VH.get(seg); } - public static void altsetting$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * unsigned int altsetting; + * } + */ + public static void altsetting$set(MemorySegment seg, int x) { usbdevfs_setinterface.altsetting$VH.set(seg, x); } public static int altsetting$get(MemorySegment seg, long index) { @@ -47,10 +79,10 @@ public class usbdevfs_setinterface { } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java index e396cb35..38e0d938 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java @@ -5,15 +5,14 @@ import static java.lang.foreign.ValueLayout.*; public class usbdevice_fs { - /* package-private */ usbdevice_fs() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; + public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; } From aab42337237c65dbef7d89e29038eec3c558ad6d Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 27 Dec 2022 10:30:40 +0100 Subject: [PATCH 168/433] Upgrade Windows code to JDK 20 --- java-does-usb/jextract/windows/gen_win.cmd | 74 ++--- .../src/main/java/net/codecrete/usb/USB.java | 5 +- .../codecrete/usb/windows/DeviceProperty.java | 111 +++---- .../usb/windows/InterfaceHandle.java | 6 +- .../java/net/codecrete/usb/windows/Win.java | 22 +- .../usb/windows/WindowsUSBDevice.java | 49 ++- .../usb/windows/WindowsUSBDeviceRegistry.java | 142 +++++---- .../usb/windows/WindowsUSBException.java | 11 +- .../usb/windows/gen/advapi32/Advapi32.java | 43 ++- .../windows/gen/advapi32/Constants$root.java | 22 +- .../windows/gen/advapi32/RuntimeHelper.java | 63 ++-- .../usb/windows/gen/advapi32/constants$0.java | 4 +- .../windows/gen/kernel32/Constants$root.java | 22 +- .../usb/windows/gen/kernel32/GUID.java | 9 +- .../usb/windows/gen/kernel32/Kernel32.java | 160 ++++++++-- .../windows/gen/kernel32/RuntimeHelper.java | 63 ++-- .../usb/windows/gen/kernel32/_GUID.java | 58 +++- .../usb/windows/gen/kernel32/constants$0.java | 4 +- .../usb/windows/gen/kernel32/constants$1.java | 4 +- .../usb/windows/gen/ole32/Constants$root.java | 22 +- .../usb/windows/gen/ole32/Ole32.java | 26 +- .../usb/windows/gen/ole32/RuntimeHelper.java | 63 ++-- .../usb/windows/gen/ole32/constants$0.java | 4 +- .../windows/gen/setupapi/Constants$root.java | 22 +- .../windows/gen/setupapi/RuntimeHelper.java | 63 ++-- .../setupapi/SP_DEVICE_INTERFACE_DATA.java | 9 +- .../SP_DEVICE_INTERFACE_DETAIL_DATA_W.java | 9 +- .../windows/gen/setupapi/SP_DEVINFO_DATA.java | 9 +- .../usb/windows/gen/setupapi/SetupAPI.java | 150 +++++++-- .../setupapi/_SP_DEVICE_INTERFACE_DATA.java | 58 +++- .../_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java | 28 +- .../gen/setupapi/_SP_DEVINFO_DATA.java | 58 +++- .../usb/windows/gen/setupapi/constants$0.java | 4 +- .../usb/windows/gen/setupapi/constants$1.java | 4 +- .../windows/gen/stdlib/Constants$root.java | 22 +- .../usb/windows/gen/stdlib/RuntimeHelper.java | 63 ++-- .../usb/windows/gen/stdlib/StdLib.java | 26 +- .../usb/windows/gen/stdlib/constants$0.java | 4 +- .../windows/gen/usbioctl/Constants$root.java | 22 +- .../windows/gen/usbioctl/RuntimeHelper.java | 63 ++-- .../usb/windows/gen/usbioctl/USBIoctl.java | 27 +- .../windows/gen/user32/Constants$root.java | 22 +- .../DEV_BROADCAST_DEVICEINTERFACE_W.java | 9 +- .../windows/gen/user32/DEV_BROADCAST_HDR.java | 9 +- .../codecrete/usb/windows/gen/user32/MSG.java | 9 +- .../usb/windows/gen/user32/RuntimeHelper.java | 63 ++-- .../usb/windows/gen/user32/User32.java | 91 ++++-- .../usb/windows/gen/user32/WNDCLASSEXW.java | 9 +- .../_DEV_BROADCAST_DEVICEINTERFACE_W.java | 59 +++- .../gen/user32/_DEV_BROADCAST_HDR.java | 57 +++- .../usb/windows/gen/user32/constants$0.java | 8 +- .../usb/windows/gen/user32/tagMSG.java | 100 +++++- .../windows/gen/user32/tagWNDCLASSEXW.java | 288 ++++++++++++++---- .../windows/gen/winusb/Constants$root.java | 22 +- .../usb/windows/gen/winusb/RuntimeHelper.java | 63 ++-- .../usb/windows/gen/winusb/WinUSB.java | 93 ++++-- .../usb/windows/gen/winusb/constants$0.java | 4 +- .../usb/windows/gen/winusb/constants$1.java | 4 +- 58 files changed, 1740 insertions(+), 798 deletions(-) diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index 71202ab6..522ae134 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -1,4 +1,4 @@ -set JEXTRACT=..\..\..\..\jextract-19\bin\jextract.bat +set JEXTRACT=..\..\..\..\jextract\build\jextract\bin\jextract.bat set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 call %JEXTRACT% --source --output ../../src/main/java ^ @@ -15,23 +15,23 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-function GetModuleHandleW ^ --include-function FormatMessageW ^ --include-function LocalFree ^ - --include-macro ERROR_SUCCESS ^ - --include-macro ERROR_NO_MORE_ITEMS ^ - --include-macro ERROR_MORE_DATA ^ - --include-macro ERROR_INSUFFICIENT_BUFFER ^ - --include-macro ERROR_FILE_NOT_FOUND ^ - --include-macro ERROR_SEM_TIMEOUT ^ - --include-macro ERROR_GEN_FAILURE ^ - --include-macro GENERIC_READ ^ - --include-macro GENERIC_WRITE ^ - --include-macro FILE_SHARE_READ ^ - --include-macro FILE_SHARE_WRITE ^ - --include-macro FILE_ATTRIBUTE_NORMAL ^ - --include-macro FILE_FLAG_OVERLAPPED ^ - --include-macro OPEN_EXISTING ^ - --include-macro FORMAT_MESSAGE_ALLOCATE_BUFFER ^ - --include-macro FORMAT_MESSAGE_FROM_SYSTEM ^ - --include-macro FORMAT_MESSAGE_IGNORE_INSERTS ^ + --include-constant ERROR_SUCCESS ^ + --include-constant ERROR_NO_MORE_ITEMS ^ + --include-constant ERROR_MORE_DATA ^ + --include-constant ERROR_INSUFFICIENT_BUFFER ^ + --include-constant ERROR_FILE_NOT_FOUND ^ + --include-constant ERROR_SEM_TIMEOUT ^ + --include-constant ERROR_GEN_FAILURE ^ + --include-constant GENERIC_READ ^ + --include-constant GENERIC_WRITE ^ + --include-constant FILE_SHARE_READ ^ + --include-constant FILE_SHARE_WRITE ^ + --include-constant FILE_ATTRIBUTE_NORMAL ^ + --include-constant FILE_FLAG_OVERLAPPED ^ + --include-constant OPEN_EXISTING ^ + --include-constant FORMAT_MESSAGE_ALLOCATE_BUFFER ^ + --include-constant FORMAT_MESSAGE_FROM_SYSTEM ^ + --include-constant FORMAT_MESSAGE_IGNORE_INSERTS ^ --include-struct _GUID ^ --include-typedef GUID ^ windows_headers.h @@ -61,14 +61,14 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-typedef SP_DEVICE_INTERFACE_DATA ^ --include-struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W ^ --include-typedef SP_DEVICE_INTERFACE_DETAIL_DATA_W ^ - --include-macro DIGCF_PRESENT ^ - --include-macro DIGCF_DEVICEINTERFACE ^ - --include-macro SPDRP_ADDRESS ^ - --include-macro DEVPROP_TYPE_UINT32 ^ - --include-macro DEVPROP_TYPE_STRING ^ - --include-macro DEVPROP_TYPEMOD_LIST ^ - --include-macro DICS_FLAG_GLOBAL ^ - --include-macro DIREG_DEV ^ + --include-constant DIGCF_PRESENT ^ + --include-constant DIGCF_DEVICEINTERFACE ^ + --include-constant SPDRP_ADDRESS ^ + --include-constant DEVPROP_TYPE_UINT32 ^ + --include-constant DEVPROP_TYPE_STRING ^ + --include-constant DEVPROP_TYPEMOD_LIST ^ + --include-constant DICS_FLAG_GLOBAL ^ + --include-constant DIREG_DEV ^ windows_headers.h call %JEXTRACT% --source --output ../../src/main/java ^ @@ -84,8 +84,8 @@ call %JEXTRACT% --source --output ../../src/main/java ^ -I "%SDK_DIR%\shared" ^ --header-class-name USBIoctl ^ --target-package net.codecrete.usb.windows.gen.usbioctl ^ - --include-macro IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX ^ - --include-macro IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION ^ + --include-constant IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX ^ + --include-constant IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION ^ windows_headers.h call %JEXTRACT% --source --output ../../src/main/java ^ @@ -100,12 +100,12 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-function RegisterDeviceNotificationW ^ --include-function GetMessageW ^ --include-function DefWindowProcW ^ - --include-macro DEVICE_NOTIFY_WINDOW_HANDLE ^ - --include-macro HWND_MESSAGE ^ - --include-macro WM_DEVICECHANGE ^ - --include-macro DBT_DEVICEARRIVAL ^ - --include-macro DBT_DEVICEREMOVECOMPLETE ^ - --include-macro DBT_DEVTYP_DEVICEINTERFACE ^ + --include-constant DEVICE_NOTIFY_WINDOW_HANDLE ^ + --include-constant HWND_MESSAGE ^ + --include-constant WM_DEVICECHANGE ^ + --include-constant DBT_DEVICEARRIVAL ^ + --include-constant DBT_DEVICEREMOVECOMPLETE ^ + --include-constant DBT_DEVTYP_DEVICEINTERFACE ^ --include-struct tagMSG ^ --include-typedef MSG ^ --include-struct tagWNDCLASSEXW ^ @@ -133,7 +133,7 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-function WinUsb_SetPipePolicy ^ --include-function WinUsb_SetCurrentAlternateSetting ^ --include-function WinUsb_ResetPipe ^ - --include-macro PIPE_TRANSFER_TIMEOUT ^ + --include-constant PIPE_TRANSFER_TIMEOUT ^ windows_headers.h call %JEXTRACT% --source --output ../../src/main/java ^ @@ -145,8 +145,8 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --target-package net.codecrete.usb.windows.gen.advapi32 ^ --include-function RegQueryValueExW ^ --include-function RegCloseKey ^ - --include-macro REG_MULTI_SZ ^ - --include-macro KEY_READ ^ + --include-constant REG_MULTI_SZ ^ + --include-constant KEY_READ ^ windows_headers.h call %JEXTRACT% --source --output ../../src/main/java ^ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USB.java b/java-does-usb/src/main/java/net/codecrete/usb/USB.java index 4de40d70..ab37236e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USB.java @@ -10,6 +10,7 @@ import net.codecrete.usb.common.USBDeviceRegistry; import net.codecrete.usb.linux.LinuxUSBDeviceRegistry; import net.codecrete.usb.macos.MacosUSBDeviceRegistry; +import net.codecrete.usb.windows.WindowsUSBDeviceRegistry; import java.util.List; import java.util.function.Consumer; @@ -27,8 +28,8 @@ private static USBDeviceRegistry createInstance() { USBDeviceRegistry impl; if (osName.equals("Mac OS X") && (osArch.equals("x86_64") || osArch.equals("aarch64"))) { impl = new MacosUSBDeviceRegistry(); -// } else if (osName.startsWith("Windows") && osArch.equals("amd64")) { -// impl = new WindowsUSBDeviceRegistry(); + } else if (osName.startsWith("Windows") && osArch.equals("amd64")) { + impl = new WindowsUSBDeviceRegistry(); } else if (osName.equals("Linux") && (osArch.equals("amd64") || osArch.equals("aarch64"))) { impl = new LinuxUSBDeviceRegistry(); } else { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index c393d985..4013793d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -7,6 +7,7 @@ package net.codecrete.usb.windows; +import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.windows.gen.advapi32.Advapi32; import net.codecrete.usb.windows.gen.kernel32.GUID; import net.codecrete.usb.windows.gen.kernel32.Kernel32; @@ -14,13 +15,11 @@ import net.codecrete.usb.windows.gen.setupapi.SP_DEVICE_INTERFACE_DETAIL_DATA_W; import net.codecrete.usb.windows.gen.setupapi.SetupAPI; -import java.lang.foreign.Addressable; -import java.lang.foreign.MemoryAddress; +import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; import java.util.List; -import static java.lang.foreign.MemoryAddress.NULL; +import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.JAVA_CHAR; import static java.lang.foreign.ValueLayout.JAVA_INT; import static net.codecrete.usb.windows.WindowsUSBException.throwException; @@ -55,10 +54,10 @@ public class DeviceProperty { (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50, (byte) 0xe0, 3); - public static int getDeviceIntProperty(Addressable devInfo, Addressable devInfoData, Addressable propertyKey) { - try (var session = MemorySession.openConfined()) { - var propertyTypeHolder = session.allocate(JAVA_INT); - var propertyValueHolder = session.allocate(JAVA_INT); + public static int getDeviceIntProperty(MemorySegment devInfo, MemorySegment devInfoData, MemorySegment propertyKey) { + try (var arena = Arena.openConfined()) { + var propertyTypeHolder = arena.allocate(JAVA_INT); + var propertyValueHolder = arena.allocate(JAVA_INT); if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0) == 0) throwLastError("Internal error (SetupDiGetDevicePropertyW)"); @@ -70,29 +69,29 @@ public static int getDeviceIntProperty(Addressable devInfo, Addressable devInfoD } } - public static String getDeviceStringProperty(Addressable devInfo, Addressable devInfoData, - Addressable propertyKey) { - try (var session = MemorySession.openConfined()) { + public static String getDeviceStringProperty(MemorySegment devInfo, MemorySegment devInfoData, + MemorySegment propertyKey) { + try (var arena = Arena.openConfined()) { var propertyValue = getProperty(devInfo, devInfoData, propertyKey, - SetupAPI.DEVPROP_TYPE_STRING(), session); + SetupAPI.DEVPROP_TYPE_STRING(), arena); return Win.createStringFromSegment(propertyValue); } } - public static List getDeviceStringListProperty(Addressable devInfo, Addressable devInfoData, - Addressable propertyKey) { - try (var session = MemorySession.openConfined()) { + public static List getDeviceStringListProperty(MemorySegment devInfo, MemorySegment devInfoData, + MemorySegment propertyKey) { + try (var arena = Arena.openConfined()) { var propertyValue = getProperty(devInfo, devInfoData, propertyKey, - SetupAPI.DEVPROP_TYPE_STRING() | SetupAPI.DEVPROP_TYPEMOD_LIST(), session); + SetupAPI.DEVPROP_TYPE_STRING() | SetupAPI.DEVPROP_TYPEMOD_LIST(), arena); return Win.createStringListFromSegment(propertyValue); } } - private static MemorySegment getProperty(Addressable devInfo, Addressable devInfoData, Addressable propertyKey, - int propertyType, MemorySession session) { - var propertyTypeHolder = session.allocate(JAVA_INT); - var requiredSizeHolder = session.allocate(JAVA_INT); + private static MemorySegment getProperty(MemorySegment devInfo, MemorySegment devInfoData, MemorySegment propertyKey, + int propertyType, Arena arena) { + var propertyTypeHolder = arena.allocate(JAVA_INT); + var requiredSizeHolder = arena.allocate(JAVA_INT); if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, NULL, 0, requiredSizeHolder, 0) == 0) { // TODO: Reactivate when proper GetLastError() handling is available @@ -106,7 +105,7 @@ private static MemorySegment getProperty(Addressable devInfo, Addressable devInf int stringLen = requiredSizeHolder.get(JAVA_INT, 0) / 2 - 1; - var propertyValueHolder = session.allocateArray(JAVA_CHAR, stringLen + 1); + var propertyValueHolder = arena.allocateArray(JAVA_CHAR, stringLen + 1); if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0) == 0) throwLastError("Internal error (SetupDiGetDevicePropertyW)"); @@ -114,49 +113,51 @@ private static MemorySegment getProperty(Addressable devInfo, Addressable devInf return propertyValueHolder; } - public static List findDeviceInterfaceGUIDs(MemoryAddress devInfoSetHandle, MemorySegment devInfo, MemorySession session) { - - // open device registry key - var regKey = SetupAPI.SetupDiOpenDevRegKey(devInfoSetHandle, devInfo, SetupAPI.DICS_FLAG_GLOBAL(), - 0, SetupAPI.DIREG_DEV(), Advapi32.KEY_READ()); - if (Win.IsInvalidHandle(regKey)) - throwLastError("Cannot open device registry key"); - session.addCloseAction(() -> Advapi32.RegCloseKey(regKey)); - - // read registry value (without buffer, to query length) - var keyNameSegment = Win.createSegmentFromString("DeviceInterfaceGUIDs", session); - var valueTypeHolder = session.allocate(JAVA_INT); - var valueSizeHolder = session.allocate(JAVA_INT); - var res = Advapi32.RegQueryValueExW(regKey, keyNameSegment, NULL, valueTypeHolder, NULL, valueSizeHolder); - if (res == Kernel32.ERROR_FILE_NOT_FOUND()) - return List.of(); // no device interface GUIDs - if (res != 0 && res != Kernel32.ERROR_MORE_DATA()) - throwException(res, "Internal error (RegQueryValueExW)"); - - // read registry value (with buffer) - var valueSize = valueSizeHolder.get(JAVA_INT, 0); - var value = session.allocate(valueSize); - res = Advapi32.RegQueryValueExW(regKey, keyNameSegment, NULL, valueTypeHolder, value, valueSizeHolder); - if (res != 0) - throwException(res, "Internal error (RegQueryValueExW)"); - - return Win.createStringListFromSegment(value); + public static List findDeviceInterfaceGUIDs(MemorySegment devInfoSetHandle, MemorySegment devInfo, Arena arena) { + + try (var cleanup = new ScopeCleanup()) { + // open device registry key + var regKey = SetupAPI.SetupDiOpenDevRegKey(devInfoSetHandle, devInfo, SetupAPI.DICS_FLAG_GLOBAL(), + 0, SetupAPI.DIREG_DEV(), Advapi32.KEY_READ()); + if (Win.IsInvalidHandle(regKey)) + throwLastError("Cannot open device registry key"); + cleanup.add(() -> Advapi32.RegCloseKey(regKey)); + + // read registry value (without buffer, to query length) + var keyNameSegment = Win.createSegmentFromString("DeviceInterfaceGUIDs", arena); + var valueTypeHolder = arena.allocate(JAVA_INT); + var valueSizeHolder = arena.allocate(JAVA_INT); + var res = Advapi32.RegQueryValueExW(regKey, keyNameSegment, NULL, valueTypeHolder, NULL, valueSizeHolder); + if (res == Kernel32.ERROR_FILE_NOT_FOUND()) + return List.of(); // no device interface GUIDs + if (res != 0 && res != Kernel32.ERROR_MORE_DATA()) + throwException(res, "Internal error (RegQueryValueExW)"); + + // read registry value (with buffer) + var valueSize = valueSizeHolder.get(JAVA_INT, 0); + var value = arena.allocate(valueSize); + res = Advapi32.RegQueryValueExW(regKey, keyNameSegment, NULL, valueTypeHolder, value, valueSizeHolder); + if (res != 0) + throwException(res, "Internal error (RegQueryValueExW)"); + + return Win.createStringListFromSegment(value); + } } - public static String getDevicePath(String instanceID, Addressable interfaceGuid) { - try (var session = MemorySession.openConfined()) { + public static String getDevicePath(String instanceID, MemorySegment interfaceGuid) { + try (var arena = Arena.openConfined(); var cleanup = new ScopeCleanup()) { // get device info set for instance - var instanceIDSegment = Win.createSegmentFromString(instanceID, session); + var instanceIDSegment = Win.createSegmentFromString(instanceID, arena); final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(interfaceGuid, instanceIDSegment, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); if (Win.IsInvalidHandle(devInfoSetHandle)) throwException("internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left - session.addCloseAction(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); + cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); // retrieve first element of enumeration - var devIntfData = session.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); + var devIntfData = arena.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); if (SetupAPI.SetupDiEnumDeviceInterfaces(devInfoSetHandle, NULL, interfaceGuid, 0, devIntfData) == 0) throwException("internal error (SetupDiEnumDeviceInterfaces)"); @@ -165,7 +166,7 @@ public static String getDevicePath(String instanceID, Addressable interfaceGuid) // (SP_DEVICE_INTERFACE_DETAIL_DATA_W is of variable length and requires a bigger allocation so // the device path fits) final int devicePathOffset = 4; - var intfDetailData = session.allocate(4 + 260 * 2); + var intfDetailData = arena.allocate(4 + 260 * 2); SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$set(intfDetailData, (int) SP_DEVICE_INTERFACE_DETAIL_DATA_W.sizeof()); int intfDetailDataSize = (int) intfDetailData.byteSize(); @@ -180,7 +181,7 @@ public static String getDevicePath(String instanceID, Addressable interfaceGuid) public static MemorySegment createDEVPROPKEY(int data1, short data2, short data3, byte data4_0, byte data4_1, byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6 , byte data4_7, int pid) { - var propKey = MemorySession.global().allocate(GUID.sizeof() + JAVA_INT.byteSize()); + var propKey = Win.GLOBAL_ALLOCATOR.allocate(GUID.sizeof() + JAVA_INT.byteSize()); Win.setGUID(propKey, data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4, data4_5, data4_6, data4_7); propKey.set(JAVA_INT, 16, pid); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java index 0ef4fa98..f359d92b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java @@ -7,7 +7,7 @@ package net.codecrete.usb.windows; -import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; /** * Handles for WinUSB devices and interfaces @@ -34,11 +34,11 @@ class InterfaceHandle { * This is only used for the first interface in a composite function. *

*/ - MemoryAddress deviceHandle; + MemorySegment deviceHandle; /** * The WinUSB handle of the interface. */ - MemoryAddress interfaceHandle; + MemorySegment interfaceHandle; /** * Count indicating how many interface depend on the device being open. */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index ac2e51a0..fed79474 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -10,10 +10,7 @@ import net.codecrete.usb.windows.gen.kernel32.GUID; import net.codecrete.usb.windows.gen.stdlib.StdLib; -import java.lang.foreign.MemoryAddress; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; -import java.lang.foreign.ValueLayout; +import java.lang.foreign.*; import java.util.ArrayList; import java.util.List; @@ -25,14 +22,19 @@ */ public class Win { + /** + * Global native memory segment allocator. + */ + public static final SegmentAllocator GLOBAL_ALLOCATOR = SegmentAllocator.nativeAllocator(SegmentScope.global()); + /** * Checks if a Windows handle is invalid. * * @param handle Windows handle * @return {@code true} if the handle is invalid, {@code false} otherwise */ - public static boolean IsInvalidHandle(MemoryAddress handle) { - return handle.toRawLongValue() == -1L; + public static boolean IsInvalidHandle(MemorySegment handle) { + return handle.address() == -1L; } /** @@ -42,12 +44,12 @@ public static boolean IsInvalidHandle(MemoryAddress handle) { *

* * @param str the string to copy - * @param session the memory session for the memory segment + * @param arena the arena for the memory segment * @return the resulting memory segment */ - public static MemorySegment createSegmentFromString(String str, MemorySession session) { + public static MemorySegment createSegmentFromString(String str, Arena arena) { // allocate segment (including space for terminating null) - var segment = session.allocateArray(ValueLayout.JAVA_CHAR, str.length() + 1); + var segment = arena.allocateArray(ValueLayout.JAVA_CHAR, str.length() + 1); // copy characters segment.copyFrom(MemorySegment.ofArray(str.toCharArray())); return segment; @@ -107,7 +109,7 @@ public static List createStringListFromSegment(MemorySegment segment) { public static MemorySegment CreateGUID(int data1, short data2, short data3, byte data4_0, byte data4_1, byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7) { - var guid = MemorySegment.allocateNative(GUID.$LAYOUT(), MemorySession.global()); + var guid = GLOBAL_ALLOCATOR.allocate(GUID.$LAYOUT()); setGUID(guid, data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4, data4_5, data4_6, data4_7); return guid; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 51f7123b..8f50e7ca 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -13,14 +13,13 @@ import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.winusb.WinUSB; -import java.lang.foreign.MemoryAddress; +import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; import java.util.ArrayList; import java.util.List; import java.util.Map; -import static java.lang.foreign.MemoryAddress.NULL; +import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.windows.WindowsUSBException.throwException; import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; @@ -101,13 +100,13 @@ public void claimInterface(int interfaceNumber) { if (firstIntfHandle.devicePath == null) throwException("Interface number %d cannot be claimed (non WinUSB device?)", interfaceNumber); - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined()) { - MemoryAddress deviceHandle; + MemorySegment deviceHandle; // open Windows device if needed if (firstIntfHandle.deviceHandle == null) { - var pathSegment = Win.createSegmentFromString(firstIntfHandle.devicePath, session); + var pathSegment = Win.createSegmentFromString(firstIntfHandle.devicePath, arena); deviceHandle = Kernel32.CreateFileW(pathSegment, Kernel32.GENERIC_WRITE() | Kernel32.GENERIC_READ(), Kernel32.FILE_SHARE_WRITE() | Kernel32.FILE_SHARE_READ(), NULL, Kernel32.OPEN_EXISTING(), Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), NULL); @@ -120,7 +119,7 @@ public void claimInterface(int interfaceNumber) { try { // open interface - var interfaceHandleHolder = session.allocate(ADDRESS); + var interfaceHandleHolder = arena.allocate(ADDRESS); if (WinUSB.WinUsb_Initialize(deviceHandle, interfaceHandleHolder) == 0) throwLastError("Cannot open WinUSB device"); var interfaceHandle = interfaceHandleHolder.get(ADDRESS, 0); @@ -184,9 +183,9 @@ public void releaseInterface(int interfaceNumber) { setClaimed(interfaceNumber, false); } - private MemorySegment createSetupPacket(MemorySession session, USBDirection direction, USBControlTransfer setup, + private MemorySegment createSetupPacket(Arena arena, USBDirection direction, USBControlTransfer setup, MemorySegment data) { - var setupPacket = new SetupPacket(session); + var setupPacket = new SetupPacket(arena); var bmRequest = (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); setupPacket.setRequestType(bmRequest); @@ -202,10 +201,10 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { checkIsOpen(); var intfHandle = findControlTransferInterface(setup); - try (var session = MemorySession.openConfined()) { - var buffer = session.allocate(length); - var setupPacket = createSetupPacket(session, USBDirection.IN, setup, buffer); - var lengthHolder = session.allocate(JAVA_INT); + try (var arena = Arena.openConfined()) { + var buffer = arena.allocate(length); + var setupPacket = createSetupPacket(arena, USBDirection.IN, setup, buffer); + var lengthHolder = arena.allocate(JAVA_INT); if (WinUSB.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) @@ -221,17 +220,17 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { checkIsOpen(); var intfHandle = findControlTransferInterface(setup); - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined()) { // copy data to native memory int dataLength = data != null ? data.length : 0; - MemorySegment buffer = session.allocate(dataLength); + MemorySegment buffer = arena.allocate(dataLength); if (dataLength != 0) buffer.copyFrom(MemorySegment.ofArray(data)); // create setup packet - var setupPacket = createSetupPacket(session, USBDirection.OUT, setup, buffer); - var lengthHolder = session.allocate(JAVA_INT); + var setupPacket = createSetupPacket(arena, USBDirection.OUT, setup, buffer); + var lengthHolder = arena.allocate(JAVA_INT); if (WinUSB.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer, (int) buffer.byteSize(), lengthHolder, NULL) == 0) @@ -246,17 +245,17 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { var endpoint = getEndpoint(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined()) { // set timeout - var timeoutHolder = session.allocate(JAVA_INT, timeout); + var timeoutHolder = arena.allocate(JAVA_INT, timeout); if (WinUSB.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder) == 0) throwLastError("Setting timeout failed"); // copy data to native heap - var buffer = session.allocate(data.length); + var buffer = arena.allocate(data.length); buffer.copyFrom(MemorySegment.ofArray(data)); - var lengthHolder = session.allocate(JAVA_INT); + var lengthHolder = arena.allocate(JAVA_INT); // send data if (WinUSB.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, (int) buffer.byteSize(), @@ -274,16 +273,16 @@ public byte[] transferIn(int endpointNumber, int timeout) { var endpoint = getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined()) { // set timeout - var timeoutHolder = session.allocate(JAVA_INT, timeout); + var timeoutHolder = arena.allocate(JAVA_INT, timeout); if (WinUSB.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder) == 0) throwLastError("Setting timeout failed"); // create native heap buffer for data - var buffer = session.allocate(endpoint.packetSize()); - var lengthHolder = session.allocate(JAVA_INT); + var buffer = arena.allocate(endpoint.packetSize()); + var lengthHolder = arena.allocate(JAVA_INT); // receive data if (WinUSB.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, (int) buffer.byteSize(), diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index b1acd063..a1f2cb9b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -8,7 +8,7 @@ package net.codecrete.usb.windows; import net.codecrete.usb.USBDevice; -import net.codecrete.usb.common.ForeignMemory; +import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.common.USBDeviceRegistry; import net.codecrete.usb.usbstandard.ConfigurationDescriptor; @@ -24,7 +24,10 @@ import net.codecrete.usb.windows.gen.usbioctl.USBIoctl; import net.codecrete.usb.windows.gen.user32.*; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.ArrayList; @@ -33,7 +36,7 @@ import java.util.Map; import java.util.regex.Pattern; -import static java.lang.foreign.MemoryAddress.NULL; +import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.usbstandard.Constants.*; import static net.codecrete.usb.windows.WindowsUSBException.throwException; @@ -51,28 +54,28 @@ public class WindowsUSBDeviceRegistry extends USBDeviceRegistry { @Override protected void monitorDevices() { - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined()) { - Addressable hwnd; + MemorySegment hwnd; try { - final var className = Win.createSegmentFromString("USB_MONITOR", session); - final var windowName = Win.createSegmentFromString("USB device monitor", session); + final var className = Win.createSegmentFromString("USB_MONITOR", arena); + final var windowName = Win.createSegmentFromString("USB device monitor", arena); final var instance = Kernel32.GetModuleHandleW(NULL); // create upcall for handling window messages var handleWindowMessageMH = MethodHandles.lookup().findVirtual(WindowsUSBDeviceRegistry.class, - "handleWindowMessage", MethodType.methodType(long.class, MemoryAddress.class, int.class, + "handleWindowMessage", MethodType.methodType(long.class, MemorySegment.class, int.class, long.class, long.class)).bindTo(this); var handleWindowMessageStub = Linker.nativeLinker().upcallStub(handleWindowMessageMH, - FunctionDescriptor.of(JAVA_LONG, ADDRESS, JAVA_INT, JAVA_LONG, JAVA_LONG), session); + FunctionDescriptor.of(JAVA_LONG, ADDRESS, JAVA_INT, JAVA_LONG, JAVA_LONG), arena.scope()); // register window class - var wx = session.allocate(WNDCLASSEXW.$LAYOUT()); + var wx = arena.allocate(WNDCLASSEXW.$LAYOUT()); WNDCLASSEXW.cbSize$set(wx, (int) wx.byteSize()); - WNDCLASSEXW.lpfnWndProc$set(wx, handleWindowMessageStub.address()); + WNDCLASSEXW.lpfnWndProc$set(wx, handleWindowMessageStub); WNDCLASSEXW.hInstance$set(wx, instance); - WNDCLASSEXW.lpszClassName$set(wx, className.address()); + WNDCLASSEXW.lpszClassName$set(wx, className); User32.RegisterClassExW(wx); // create message-only window @@ -82,7 +85,7 @@ protected void monitorDevices() { throwLastError("internal error (CreateWindowExW)"); // configure notifications - var notificationFilter = session.allocate(DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); + var notificationFilter = arena.allocate(DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$set(notificationFilter, (int) notificationFilter.byteSize()); DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$set(notificationFilter, User32.DBT_DEVTYP_DEVICEINTERFACE()); @@ -102,7 +105,7 @@ protected void monitorDevices() { } // process messages - var msg = session.allocate(MSG.$LAYOUT()); + var msg = arena.allocate(MSG.$LAYOUT()); //noinspection StatementWithEmptyBody while (User32.GetMessageW(msg, hwnd, 0, 0) > 0) ; // do nothing @@ -112,7 +115,7 @@ protected void monitorDevices() { private void enumeratePresentDevices() { List deviceList = new ArrayList<>(); - try (var outerSession = MemorySession.openConfined()) { + try (var outerArena = Arena.openConfined(); var outerCleanup = new ScopeCleanup()) { // get device information set of all USB devices present final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, @@ -121,14 +124,14 @@ private void enumeratePresentDevices() { throwException("internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left - outerSession.addCloseAction(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); + outerCleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); - var devInfo = MemorySegment.allocateNative(SP_DEVINFO_DATA.$LAYOUT(), outerSession); + var devInfo = outerArena.allocate(SP_DEVINFO_DATA.$LAYOUT()); SP_DEVINFO_DATA.cbSize$set(devInfo, (int) SP_DEVINFO_DATA.$LAYOUT().byteSize()); // ensure all hubs are closed later - final var hubHandles = new HashMap(); - outerSession.addCloseAction(() -> hubHandles.forEach((path, handle) -> Kernel32.CloseHandle(handle))); + final var hubHandles = new HashMap(); + outerCleanup.add(() -> hubHandles.forEach((path, handle) -> Kernel32.CloseHandle(handle))); // iterate all devices for (int i = 0; true; i++) { @@ -171,17 +174,17 @@ private Map enumerateChildren(List childrenIds) { // iterate all children for (var instanceId : childrenIds) { - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined(); var cleanup = new ScopeCleanup()) { // create device info set var devInfoSetHandle = SetupAPI.SetupDiCreateDeviceInfoList(NULL, NULL); if (Win.IsInvalidHandle(devInfoSetHandle)) throwLastError("Cannot create device info list"); - session.addCloseAction(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); + cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); // get device info for child - var devInfo = session.allocate(SP_DEVINFO_DATA.$LAYOUT()); + var devInfo = arena.allocate(SP_DEVINFO_DATA.$LAYOUT()); SP_DEVINFO_DATA.cbSize$set(devInfo, (int) devInfo.byteSize()); - var instanceIdSegment = Win.createSegmentFromString(instanceId, session); + var instanceIdSegment = Win.createSegmentFromString(instanceId, arena); if (SetupAPI.SetupDiOpenDeviceInfoW(devInfoSetHandle, instanceIdSegment, NULL, 0, devInfo) == 0) throwLastError("Internal error (SetupDiOpenDeviceInfoW)"); @@ -192,12 +195,12 @@ private Map enumerateChildren(List childrenIds) { if (interfaceNumber == -1) continue; - var guids = DeviceProperty.findDeviceInterfaceGUIDs(devInfoSetHandle, devInfo, session); + var guids = DeviceProperty.findDeviceInterfaceGUIDs(devInfoSetHandle, devInfo, arena); for (var guid : guids) { // check for Class GUID - var guidSegment = Win.createSegmentFromString(guid, session); - var clsid = session.allocate(GUID.$LAYOUT()); + var guidSegment = Win.createSegmentFromString(guid, arena); + var clsid = arena.allocate(GUID.$LAYOUT()); if (Ole32.CLSIDFromString(guidSegment, clsid) != 0) continue; @@ -215,9 +218,9 @@ private Map enumerateChildren(List childrenIds) { return children; } - private USBDevice createDeviceFromDeviceInfo(MemoryAddress devInfoSetHandle, MemorySegment devInfo, - String devicePath, HashMap hubHandles) { - try (var session = MemorySession.openConfined()) { + private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSetHandle, MemorySegment devInfo, + String devicePath, HashMap hubHandles) { + try (var arena = Arena.openConfined()) { var usbPortNum = DeviceProperty.getDeviceIntProperty(devInfoSetHandle, devInfo, DeviceProperty.DEVPKEY_Device_Address); @@ -228,7 +231,7 @@ private USBDevice createDeviceFromDeviceInfo(MemoryAddress devInfoSetHandle, Mem // open hub if not open yet var hubHandle = hubHandles.get(hubPath); if (hubHandle == null) { - var hubPathSeg = Win.createSegmentFromString(hubPath, session); + var hubPathSeg = Win.createSegmentFromString(hubPath, arena); hubHandle = Kernel32.CreateFileW(hubPathSeg, Kernel32.GENERIC_WRITE(), Kernel32.FILE_SHARE_WRITE(), NULL, Kernel32.OPEN_EXISTING(), 0, NULL); if (Win.IsInvalidHandle(hubHandle)) @@ -259,14 +262,14 @@ private USBDevice createDeviceFromDeviceInfo(MemoryAddress devInfoSetHandle, Mem * @param usbPortNum the USB port number * @return the {@code USBDevice} instance */ - private USBDevice createDevice(String devicePath, Map children, MemoryAddress hubHandle, int usbPortNum) { + private USBDevice createDevice(String devicePath, Map children, MemorySegment hubHandle, int usbPortNum) { - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined()) { // get device descriptor - var connInfo = session.allocate(USBHelper.USB_NODE_CONNECTION_INFORMATION_EX$Struct); + var connInfo = arena.allocate(USBHelper.USB_NODE_CONNECTION_INFORMATION_EX$Struct); USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex.set(connInfo, usbPortNum); - var sizeHolder = session.allocate(JAVA_INT); + var sizeHolder = arena.allocate(JAVA_INT); if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), connInfo , (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL) == 0) throwLastError("Internal error (cannot get device descriptor)"); @@ -277,8 +280,7 @@ private USBDevice createDevice(String devicePath, Map children, int vendorId = deviceDescriptor.vendorID(); int productId = deviceDescriptor.productID(); - var configDesc = getDescriptor(hubHandle, usbPortNum, CONFIGURATION_DESCRIPTOR_TYPE, 0, - (short) 0, session); + var configDesc = getDescriptor(hubHandle, usbPortNum, CONFIGURATION_DESCRIPTOR_TYPE, 0, (short) 0, arena); var device = new WindowsUSBDevice(devicePath, children, vendorId, productId, configDesc); device.setFromDeviceDescriptor(descriptorSegment); @@ -288,19 +290,19 @@ private USBDevice createDevice(String devicePath, Map children, } } - private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, int descriptorType, int index, - short languageID, MemorySession session) { - return getDescriptor(hubHandle, usbPortNumber, descriptorType, index, languageID, 0, session); + private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, int descriptorType, int index, + short languageID, Arena arena) { + return getDescriptor(hubHandle, usbPortNumber, descriptorType, index, languageID, 0, arena); } - private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, int descriptorType, int index, - short languageID, int requestSize, MemorySession session) { + private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, int descriptorType, int index, + short languageID, int requestSize, Arena arena) { int size = requestSize != 0 ? requestSize + (int) USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset : 256; // create descriptor requests - var descriptorRequest = session.allocate(size); + var descriptorRequest = arena.allocate(size); USBHelper.USB_DESCRIPTOR_REQUEST_ConnectionIndex.set(descriptorRequest, usbPortNumber); var setupPacket = new SetupPacket(descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_SetupPacket$Offset, SetupPacket.LAYOUT.byteSize())); @@ -311,7 +313,7 @@ private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, in setupPacket.setLength(size - (int)USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset); // execute request - var effectiveSizeHolder = session.allocate(JAVA_INT); + var effectiveSizeHolder = arena.allocate(JAVA_INT); if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION(), descriptorRequest, size, descriptorRequest, size, effectiveSizeHolder, NULL) == 0) throwLastError("Cannot retrieve descriptor %d", index); @@ -333,43 +335,39 @@ private MemorySegment getDescriptor(Addressable hubHandle, int usbPortNumber, in throwException("Unexpected descriptor size"); // repeat with correct size - return getDescriptor(hubHandle, usbPortNumber, descriptorType, index, languageID, expectedSize, session); + return getDescriptor(hubHandle, usbPortNumber, descriptorType, index, languageID, expectedSize, arena); } return descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, effectiveSize); } - private String getStringDescriptor(Addressable hubHandle, int usbPortNumber, int index) { + private String getStringDescriptor(MemorySegment hubHandle, int usbPortNumber, int index) { if (index == 0) return null; - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined()) { var stringDesc = new StringDescriptor(getDescriptor(hubHandle, usbPortNumber, STRING_DESCRIPTOR_TYPE, index, - DEFAULT_LANGUAGE, session)); + DEFAULT_LANGUAGE, arena)); return stringDesc.string(); } } - private long handleWindowMessage(MemoryAddress hWnd, int uMsg, long wParam, long lParam) { + private long handleWindowMessage(MemorySegment hWnd, int uMsg, long wParam, long lParam) { // check for message related to connecting/disconnecting devices if (uMsg == User32.WM_DEVICECHANGE() && (wParam == User32.DBT_DEVICEARRIVAL() || wParam == User32.DBT_DEVICEREMOVECOMPLETE())) { - try (var session = MemorySession.openConfined()) { - var data = MemorySegment.ofAddress(MemoryAddress.ofLong(lParam), - DEV_BROADCAST_DEVICEINTERFACE_W.sizeof(), session); - if (DEV_BROADCAST_HDR.dbch_devicetype$get(data) == User32.DBT_DEVTYP_DEVICEINTERFACE()) { - - // get device path - var nameSlice = - MemorySegment.ofAddress(DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address(), - 500, session); - var devicePath = Win.createStringFromSegment(nameSlice); - if (wParam == User32.DBT_DEVICEARRIVAL()) - onDeviceConnected(devicePath); - else - onDeviceDisconnected(devicePath); - return 0; - } + var data = MemorySegment.ofAddress(lParam, DEV_BROADCAST_DEVICEINTERFACE_W.sizeof()); + if (DEV_BROADCAST_HDR.dbch_devicetype$get(data) == User32.DBT_DEVTYP_DEVICEINTERFACE()) { + + // get device path + var nameSlice = MemorySegment.ofAddress( + DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address(), 500); + var devicePath = Win.createStringFromSegment(nameSlice); + if (wParam == User32.DBT_DEVICEARRIVAL()) + onDeviceConnected(devicePath); + else + onDeviceDisconnected(devicePath); + return 0; } } @@ -378,7 +376,7 @@ private long handleWindowMessage(MemoryAddress hWnd, int uMsg, long wParam, long } private void onDeviceConnected(String devicePath) { - try (var session = MemorySession.openConfined()) { + try (var arena = Arena.openConfined(); var cleanup = new ScopeCleanup()) { // get device information set of all USB devices present final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, @@ -387,17 +385,17 @@ private void onDeviceConnected(String devicePath) { throwLastError("internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left - session.addCloseAction(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); + cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); - var devIntfData = session.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); + var devIntfData = arena.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); - var devicePathSegment = Win.createSegmentFromString(devicePath, session); + var devicePathSegment = Win.createSegmentFromString(devicePath, arena); if (SetupAPI.SetupDiOpenDeviceInterfaceW(devInfoSetHandle, devicePathSegment, 0, devIntfData) == 0) throwLastError("internal error (SetupDiOpenDeviceInterfaceW)"); - ForeignMemory.addCloseAction(devIntfData, (segment) -> SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSetHandle, segment)); + cleanup.add(() -> SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSetHandle, devIntfData)); - var devInfo = session.allocate(SP_DEVINFO_DATA.$LAYOUT()); + var devInfo = arena.allocate(SP_DEVINFO_DATA.$LAYOUT()); SP_DEVINFO_DATA.cbSize$set(devInfo, (int) devInfo.byteSize()); if (SetupAPI.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, NULL, 0, NULL, devInfo) == 0) { int err = Kernel32.GetLastError(); @@ -406,8 +404,8 @@ private void onDeviceConnected(String devicePath) { } // ensure all hubs are closed later - final var hubHandles = new HashMap(); - session.addCloseAction(() -> hubHandles.forEach((path, handle) -> Kernel32.CloseHandle(handle))); + final var hubHandles = new HashMap(); + cleanup.add(() -> hubHandles.forEach((path, handle) -> Kernel32.CloseHandle(handle))); try { // create device instance diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java index c17bde26..21e3c695 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java @@ -10,10 +10,9 @@ import net.codecrete.usb.USBStallException; import net.codecrete.usb.windows.gen.kernel32.Kernel32; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; +import java.lang.foreign.Arena; -import static java.lang.foreign.MemoryAddress.NULL; +import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.ADDRESS; /** @@ -73,13 +72,13 @@ static void throwLastError(String message, Object... args) { } private static String getErrorMessage(int errorCode) { - try (var session = MemorySession.openConfined()) { - var messagePointerHolder = session.allocate(ADDRESS); + try (var arena = Arena.openConfined()) { + var messagePointerHolder = arena.allocate(ADDRESS); Kernel32.FormatMessageW(Kernel32.FORMAT_MESSAGE_ALLOCATE_BUFFER() | Kernel32.FORMAT_MESSAGE_FROM_SYSTEM() | Kernel32.FORMAT_MESSAGE_IGNORE_INSERTS(), NULL, errorCode, 0, messagePointerHolder, 0, NULL); var messagePointer = messagePointerHolder.get(ADDRESS, 0); - String message = Win.createStringFromSegment(MemorySegment.ofAddress(messagePointer, 4000, session)); + String message = Win.createStringFromSegment(messagePointer); Kernel32.LocalFree(messagePointer); return message.trim(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java index d65c860a..03c1a902 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java @@ -2,25 +2,29 @@ package net.codecrete.usb.windows.gen.advapi32; -import java.lang.foreign.Addressable; +import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class Advapi32 { - /* package-private */ Advapi32() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; public static MethodHandle RegCloseKey$MH() { return RuntimeHelper.requireNonNull(constants$0.RegCloseKey$MH,"RegCloseKey"); } - public static int RegCloseKey ( Addressable hKey) { + /** + * {@snippet : + * LSTATUS RegCloseKey(HKEY hKey); + * } + */ + public static int RegCloseKey(MemorySegment hKey) { var mh$ = RegCloseKey$MH(); try { return (int)mh$.invokeExact(hKey); @@ -31,7 +35,12 @@ public static int RegCloseKey ( Addressable hKey) { public static MethodHandle RegQueryValueExW$MH() { return RuntimeHelper.requireNonNull(constants$0.RegQueryValueExW$MH,"RegQueryValueExW"); } - public static int RegQueryValueExW ( Addressable hKey, Addressable lpValueName, Addressable lpReserved, Addressable lpType, Addressable lpData, Addressable lpcbData) { + /** + * {@snippet : + * LSTATUS RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData); + * } + */ + public static int RegQueryValueExW(MemorySegment hKey, MemorySegment lpValueName, MemorySegment lpReserved, MemorySegment lpType, MemorySegment lpData, MemorySegment lpcbData) { var mh$ = RegQueryValueExW$MH(); try { return (int)mh$.invokeExact(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); @@ -39,9 +48,19 @@ public static int RegQueryValueExW ( Addressable hKey, Addressable lpValueName, throw new AssertionError("should not reach here", ex$); } } + /** + * {@snippet : + * #define KEY_READ 131097 + * } + */ public static int KEY_READ() { return (int)131097L; } + /** + * {@snippet : + * #define REG_MULTI_SZ 7 + * } + */ public static int REG_MULTI_SZ() { return (int)7L; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Constants$root.java index e1a30f5a..0f7077fb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.windows.gen.advapi32; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfInt C_LONG$LAYOUT = JAVA_INT; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java index 707bc5cb..1a4c2ea6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java @@ -10,21 +10,24 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { System.loadLibrary("Advapi32"); SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -32,45 +35,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -96,7 +97,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -106,8 +109,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -142,7 +144,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -192,10 +196,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -206,7 +207,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/constants$0.java index d7b38ce0..0d959825 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/constants$0.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$0 { +final class constants$0 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} static final FunctionDescriptor RegCloseKey$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT ); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Constants$root.java index bfc827c7..a523ae8e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.windows.gen.kernel32; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfInt C_LONG$LAYOUT = JAVA_INT; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/GUID.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/GUID.java index ea550f1d..85b02bc1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/GUID.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/GUID.java @@ -2,8 +2,15 @@ package net.codecrete.usb.windows.gen.kernel32; -public class GUID extends _GUID { +/** + * {@snippet : + * typedef struct _GUID GUID; + * } + */ +public final class GUID extends _GUID { + // Suppresses default constructor, ensuring non-instantiability. + private GUID() {} } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java index 60a5a926..24089e82 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -2,53 +2,96 @@ package net.codecrete.usb.windows.gen.kernel32; -import java.lang.foreign.Addressable; -import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class Kernel32 { - /* package-private */ Kernel32() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + /** + * {@snippet : + * #define FILE_SHARE_READ 1 + * } + */ public static int FILE_SHARE_READ() { return (int)1L; } + /** + * {@snippet : + * #define FILE_SHARE_WRITE 2 + * } + */ public static int FILE_SHARE_WRITE() { return (int)2L; } + /** + * {@snippet : + * #define FILE_ATTRIBUTE_NORMAL 128 + * } + */ public static int FILE_ATTRIBUTE_NORMAL() { return (int)128L; } + /** + * {@snippet : + * #define OPEN_EXISTING 3 + * } + */ public static int OPEN_EXISTING() { return (int)3L; } + /** + * {@snippet : + * #define FILE_FLAG_OVERLAPPED 1073741824 + * } + */ public static int FILE_FLAG_OVERLAPPED() { return (int)1073741824L; } + /** + * {@snippet : + * #define FORMAT_MESSAGE_ALLOCATE_BUFFER 256 + * } + */ public static int FORMAT_MESSAGE_ALLOCATE_BUFFER() { return (int)256L; } + /** + * {@snippet : + * #define FORMAT_MESSAGE_IGNORE_INSERTS 512 + * } + */ public static int FORMAT_MESSAGE_IGNORE_INSERTS() { return (int)512L; } + /** + * {@snippet : + * #define FORMAT_MESSAGE_FROM_SYSTEM 4096 + * } + */ public static int FORMAT_MESSAGE_FROM_SYSTEM() { return (int)4096L; } public static MethodHandle CreateFileW$MH() { return RuntimeHelper.requireNonNull(constants$0.CreateFileW$MH,"CreateFileW"); } - public static MemoryAddress CreateFileW ( Addressable lpFileName, int dwDesiredAccess, int dwShareMode, Addressable lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, Addressable hTemplateFile) { + /** + * {@snippet : + * HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); + * } + */ + public static MemorySegment CreateFileW(MemorySegment lpFileName, int dwDesiredAccess, int dwShareMode, MemorySegment lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, MemorySegment hTemplateFile) { var mh$ = CreateFileW$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -56,7 +99,12 @@ public static MemoryAddress CreateFileW ( Addressable lpFileName, int dwDesired public static MethodHandle CloseHandle$MH() { return RuntimeHelper.requireNonNull(constants$0.CloseHandle$MH,"CloseHandle"); } - public static int CloseHandle ( Addressable hObject) { + /** + * {@snippet : + * BOOL CloseHandle(HANDLE hObject); + * } + */ + public static int CloseHandle(MemorySegment hObject) { var mh$ = CloseHandle$MH(); try { return (int)mh$.invokeExact(hObject); @@ -67,7 +115,12 @@ public static int CloseHandle ( Addressable hObject) { public static MethodHandle GetLastError$MH() { return RuntimeHelper.requireNonNull(constants$0.GetLastError$MH,"GetLastError"); } - public static int GetLastError () { + /** + * {@snippet : + * DWORD GetLastError(); + * } + */ + public static int GetLastError() { var mh$ = GetLastError$MH(); try { return (int)mh$.invokeExact(); @@ -78,7 +131,12 @@ public static int GetLastError () { public static MethodHandle DeviceIoControl$MH() { return RuntimeHelper.requireNonNull(constants$0.DeviceIoControl$MH,"DeviceIoControl"); } - public static int DeviceIoControl ( Addressable hDevice, int dwIoControlCode, Addressable lpInBuffer, int nInBufferSize, Addressable lpOutBuffer, int nOutBufferSize, Addressable lpBytesReturned, Addressable lpOverlapped) { + /** + * {@snippet : + * BOOL DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped); + * } + */ + public static int DeviceIoControl(MemorySegment hDevice, int dwIoControlCode, MemorySegment lpInBuffer, int nInBufferSize, MemorySegment lpOutBuffer, int nOutBufferSize, MemorySegment lpBytesReturned, MemorySegment lpOverlapped) { var mh$ = DeviceIoControl$MH(); try { return (int)mh$.invokeExact(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); @@ -89,10 +147,15 @@ public static int DeviceIoControl ( Addressable hDevice, int dwIoControlCode, public static MethodHandle GetModuleHandleW$MH() { return RuntimeHelper.requireNonNull(constants$0.GetModuleHandleW$MH,"GetModuleHandleW"); } - public static MemoryAddress GetModuleHandleW ( Addressable lpModuleName) { + /** + * {@snippet : + * HMODULE GetModuleHandleW(LPCWSTR lpModuleName); + * } + */ + public static MemorySegment GetModuleHandleW(MemorySegment lpModuleName) { var mh$ = GetModuleHandleW$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(lpModuleName); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(lpModuleName); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -100,10 +163,15 @@ public static MemoryAddress GetModuleHandleW ( Addressable lpModuleName) { public static MethodHandle LocalFree$MH() { return RuntimeHelper.requireNonNull(constants$0.LocalFree$MH,"LocalFree"); } - public static MemoryAddress LocalFree ( Addressable hMem) { + /** + * {@snippet : + * HLOCAL LocalFree(HLOCAL hMem); + * } + */ + public static MemorySegment LocalFree(MemorySegment hMem) { var mh$ = LocalFree$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(hMem); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(hMem); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -111,7 +179,12 @@ public static MemoryAddress LocalFree ( Addressable hMem) { public static MethodHandle FormatMessageW$MH() { return RuntimeHelper.requireNonNull(constants$1.FormatMessageW$MH,"FormatMessageW"); } - public static int FormatMessageW ( int dwFlags, Addressable lpSource, int dwMessageId, int dwLanguageId, Addressable lpBuffer, int nSize, Addressable Arguments) { + /** + * {@snippet : + * DWORD FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list* Arguments); + * } + */ + public static int FormatMessageW(int dwFlags, MemorySegment lpSource, int dwMessageId, int dwLanguageId, MemorySegment lpBuffer, int nSize, MemorySegment Arguments) { var mh$ = FormatMessageW$MH(); try { return (int)mh$.invokeExact(dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments); @@ -119,30 +192,75 @@ public static int FormatMessageW ( int dwFlags, Addressable lpSource, int dwMe throw new AssertionError("should not reach here", ex$); } } + /** + * {@snippet : + * #define GENERIC_READ 2147483648 + * } + */ public static int GENERIC_READ() { return (int)2147483648L; } + /** + * {@snippet : + * #define GENERIC_WRITE 1073741824 + * } + */ public static int GENERIC_WRITE() { return (int)1073741824L; } + /** + * {@snippet : + * #define ERROR_SUCCESS 0 + * } + */ public static int ERROR_SUCCESS() { return (int)0L; } + /** + * {@snippet : + * #define ERROR_FILE_NOT_FOUND 2 + * } + */ public static int ERROR_FILE_NOT_FOUND() { return (int)2L; } + /** + * {@snippet : + * #define ERROR_GEN_FAILURE 31 + * } + */ public static int ERROR_GEN_FAILURE() { return (int)31L; } + /** + * {@snippet : + * #define ERROR_SEM_TIMEOUT 121 + * } + */ public static int ERROR_SEM_TIMEOUT() { return (int)121L; } + /** + * {@snippet : + * #define ERROR_INSUFFICIENT_BUFFER 122 + * } + */ public static int ERROR_INSUFFICIENT_BUFFER() { return (int)122L; } + /** + * {@snippet : + * #define ERROR_MORE_DATA 234 + * } + */ public static int ERROR_MORE_DATA() { return (int)234L; } + /** + * {@snippet : + * #define ERROR_NO_MORE_ITEMS 259 + * } + */ public static int ERROR_NO_MORE_ITEMS() { return (int)259L; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java index 2ed328fb..75671ff6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java @@ -10,21 +10,24 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { System.loadLibrary("Kernel32"); SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -32,45 +35,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -96,7 +97,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -106,8 +109,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -142,7 +144,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -192,10 +196,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -206,7 +207,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java index 98826c26..8378c2cb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java @@ -4,9 +4,19 @@ import java.lang.foreign.*; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct _GUID { + * unsigned long Data1; + * unsigned short Data2; + * unsigned short Data3; + * unsigned char Data4[8]; + * }; + * } + */ public class _GUID { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_LONG$LAYOUT.withName("Data1"), Constants$root.C_SHORT$LAYOUT.withName("Data2"), Constants$root.C_SHORT$LAYOUT.withName("Data3"), @@ -19,10 +29,22 @@ public class _GUID { public static VarHandle Data1$VH() { return _GUID.Data1$VH; } + /** + * Getter for field: + * {@snippet : + * unsigned long Data1; + * } + */ public static int Data1$get(MemorySegment seg) { return (int)_GUID.Data1$VH.get(seg); } - public static void Data1$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * unsigned long Data1; + * } + */ + public static void Data1$set(MemorySegment seg, int x) { _GUID.Data1$VH.set(seg, x); } public static int Data1$get(MemorySegment seg, long index) { @@ -35,10 +57,22 @@ public class _GUID { public static VarHandle Data2$VH() { return _GUID.Data2$VH; } + /** + * Getter for field: + * {@snippet : + * unsigned short Data2; + * } + */ public static short Data2$get(MemorySegment seg) { return (short)_GUID.Data2$VH.get(seg); } - public static void Data2$set( MemorySegment seg, short x) { + /** + * Setter for field: + * {@snippet : + * unsigned short Data2; + * } + */ + public static void Data2$set(MemorySegment seg, short x) { _GUID.Data2$VH.set(seg, x); } public static short Data2$get(MemorySegment seg, long index) { @@ -51,10 +85,22 @@ public class _GUID { public static VarHandle Data3$VH() { return _GUID.Data3$VH; } + /** + * Getter for field: + * {@snippet : + * unsigned short Data3; + * } + */ public static short Data3$get(MemorySegment seg) { return (short)_GUID.Data3$VH.get(seg); } - public static void Data3$set( MemorySegment seg, short x) { + /** + * Setter for field: + * {@snippet : + * unsigned short Data3; + * } + */ + public static void Data3$set(MemorySegment seg, short x) { _GUID.Data3$VH.set(seg, x); } public static short Data3$get(MemorySegment seg, long index) { @@ -68,10 +114,10 @@ public class _GUID { } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java index 60564f7a..b6ca6311 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$0 { +final class constants$0 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} static final FunctionDescriptor CreateFileW$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_LONG$LAYOUT, diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java index 1c4e52c7..306521b3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$1 { +final class constants$1 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$1() {} static final FunctionDescriptor FormatMessageW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Constants$root.java index b87f060d..73537493 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.windows.gen.ole32; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfInt C_LONG$LAYOUT = JAVA_INT; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java index f52d7fbe..50284a0c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java @@ -2,25 +2,29 @@ package net.codecrete.usb.windows.gen.ole32; -import java.lang.foreign.Addressable; +import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class Ole32 { - /* package-private */ Ole32() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; public static MethodHandle CLSIDFromString$MH() { return RuntimeHelper.requireNonNull(constants$0.CLSIDFromString$MH,"CLSIDFromString"); } - public static int CLSIDFromString ( Addressable lpsz, Addressable pclsid) { + /** + * {@snippet : + * HRESULT CLSIDFromString(LPCOLESTR lpsz, LPCLSID pclsid); + * } + */ + public static int CLSIDFromString(MemorySegment lpsz, MemorySegment pclsid) { var mh$ = CLSIDFromString$MH(); try { return (int)mh$.invokeExact(lpsz, pclsid); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java index cd067be7..311819e6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java @@ -10,21 +10,24 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { System.loadLibrary("Ole32"); SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -32,45 +35,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -96,7 +97,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -106,8 +109,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -142,7 +144,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -192,10 +196,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -206,7 +207,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/constants$0.java index b42663eb..9f9b0a6d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/constants$0.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$0 { +final class constants$0 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} static final FunctionDescriptor CLSIDFromString$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/Constants$root.java index b6bb6431..6d0aae8c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.windows.gen.setupapi; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfInt C_LONG$LAYOUT = JAVA_INT; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java index 55f8e04a..4380383f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java @@ -10,21 +10,24 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { System.loadLibrary("SetupAPI"); SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -32,45 +35,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -96,7 +97,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -106,8 +109,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -142,7 +144,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -192,10 +196,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -206,7 +207,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DATA.java index 95322b6e..13425fec 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DATA.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DATA.java @@ -2,8 +2,15 @@ package net.codecrete.usb.windows.gen.setupapi; -public class SP_DEVICE_INTERFACE_DATA extends _SP_DEVICE_INTERFACE_DATA { +/** + * {@snippet : + * typedef struct _SP_DEVICE_INTERFACE_DATA SP_DEVICE_INTERFACE_DATA; + * } + */ +public final class SP_DEVICE_INTERFACE_DATA extends _SP_DEVICE_INTERFACE_DATA { + // Suppresses default constructor, ensuring non-instantiability. + private SP_DEVICE_INTERFACE_DATA() {} } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java index 77a1e06d..7a9f76bc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java @@ -2,8 +2,15 @@ package net.codecrete.usb.windows.gen.setupapi; -public class SP_DEVICE_INTERFACE_DETAIL_DATA_W extends _SP_DEVICE_INTERFACE_DETAIL_DATA_W { +/** + * {@snippet : + * typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W SP_DEVICE_INTERFACE_DETAIL_DATA_W; + * } + */ +public final class SP_DEVICE_INTERFACE_DETAIL_DATA_W extends _SP_DEVICE_INTERFACE_DETAIL_DATA_W { + // Suppresses default constructor, ensuring non-instantiability. + private SP_DEVICE_INTERFACE_DETAIL_DATA_W() {} } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVINFO_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVINFO_DATA.java index 89a49f0d..ebc94bce 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVINFO_DATA.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVINFO_DATA.java @@ -2,8 +2,15 @@ package net.codecrete.usb.windows.gen.setupapi; -public class SP_DEVINFO_DATA extends _SP_DEVINFO_DATA { +/** + * {@snippet : + * typedef struct _SP_DEVINFO_DATA SP_DEVINFO_DATA; + * } + */ +public final class SP_DEVINFO_DATA extends _SP_DEVINFO_DATA { + // Suppresses default constructor, ensuring non-instantiability. + private SP_DEVINFO_DATA() {} } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java index f860b4ec..91fafb58 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java @@ -2,50 +2,88 @@ package net.codecrete.usb.windows.gen.setupapi; -import java.lang.foreign.Addressable; -import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class SetupAPI { - /* package-private */ SetupAPI() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + /** + * {@snippet : + * #define DEVPROP_TYPEMOD_LIST 8192 + * } + */ public static int DEVPROP_TYPEMOD_LIST() { return (int)8192L; } + /** + * {@snippet : + * #define DEVPROP_TYPE_UINT32 7 + * } + */ public static int DEVPROP_TYPE_UINT32() { return (int)7L; } + /** + * {@snippet : + * #define DEVPROP_TYPE_STRING 18 + * } + */ public static int DEVPROP_TYPE_STRING() { return (int)18L; } + /** + * {@snippet : + * #define DICS_FLAG_GLOBAL 1 + * } + */ public static int DICS_FLAG_GLOBAL() { return (int)1L; } + /** + * {@snippet : + * #define DIGCF_PRESENT 2 + * } + */ public static int DIGCF_PRESENT() { return (int)2L; } + /** + * {@snippet : + * #define DIGCF_DEVICEINTERFACE 16 + * } + */ public static int DIGCF_DEVICEINTERFACE() { return (int)16L; } + /** + * {@snippet : + * #define DIREG_DEV 1 + * } + */ public static int DIREG_DEV() { return (int)1L; } public static MethodHandle SetupDiCreateDeviceInfoList$MH() { return RuntimeHelper.requireNonNull(constants$0.SetupDiCreateDeviceInfoList$MH,"SetupDiCreateDeviceInfoList"); } - public static MemoryAddress SetupDiCreateDeviceInfoList ( Addressable ClassGuid, Addressable hwndParent) { + /** + * {@snippet : + * HDEVINFO SetupDiCreateDeviceInfoList(const GUID* ClassGuid, HWND hwndParent); + * } + */ + public static MemorySegment SetupDiCreateDeviceInfoList(MemorySegment ClassGuid, MemorySegment hwndParent) { var mh$ = SetupDiCreateDeviceInfoList$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(ClassGuid, hwndParent); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(ClassGuid, hwndParent); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -53,7 +91,12 @@ public static MemoryAddress SetupDiCreateDeviceInfoList ( Addressable ClassGuid, public static MethodHandle SetupDiOpenDeviceInfoW$MH() { return RuntimeHelper.requireNonNull(constants$0.SetupDiOpenDeviceInfoW$MH,"SetupDiOpenDeviceInfoW"); } - public static int SetupDiOpenDeviceInfoW ( Addressable DeviceInfoSet, Addressable DeviceInstanceId, Addressable hwndParent, int OpenFlags, Addressable DeviceInfoData) { + /** + * {@snippet : + * BOOL SetupDiOpenDeviceInfoW(HDEVINFO DeviceInfoSet, PCWSTR DeviceInstanceId, HWND hwndParent, DWORD OpenFlags, PSP_DEVINFO_DATA DeviceInfoData); + * } + */ + public static int SetupDiOpenDeviceInfoW(MemorySegment DeviceInfoSet, MemorySegment DeviceInstanceId, MemorySegment hwndParent, int OpenFlags, MemorySegment DeviceInfoData) { var mh$ = SetupDiOpenDeviceInfoW$MH(); try { return (int)mh$.invokeExact(DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData); @@ -64,7 +107,12 @@ public static int SetupDiOpenDeviceInfoW ( Addressable DeviceInfoSet, Addressab public static MethodHandle SetupDiEnumDeviceInfo$MH() { return RuntimeHelper.requireNonNull(constants$0.SetupDiEnumDeviceInfo$MH,"SetupDiEnumDeviceInfo"); } - public static int SetupDiEnumDeviceInfo ( Addressable DeviceInfoSet, int MemberIndex, Addressable DeviceInfoData) { + /** + * {@snippet : + * BOOL SetupDiEnumDeviceInfo(HDEVINFO DeviceInfoSet, DWORD MemberIndex, PSP_DEVINFO_DATA DeviceInfoData); + * } + */ + public static int SetupDiEnumDeviceInfo(MemorySegment DeviceInfoSet, int MemberIndex, MemorySegment DeviceInfoData) { var mh$ = SetupDiEnumDeviceInfo$MH(); try { return (int)mh$.invokeExact(DeviceInfoSet, MemberIndex, DeviceInfoData); @@ -75,7 +123,12 @@ public static int SetupDiEnumDeviceInfo ( Addressable DeviceInfoSet, int Member public static MethodHandle SetupDiDestroyDeviceInfoList$MH() { return RuntimeHelper.requireNonNull(constants$0.SetupDiDestroyDeviceInfoList$MH,"SetupDiDestroyDeviceInfoList"); } - public static int SetupDiDestroyDeviceInfoList ( Addressable DeviceInfoSet) { + /** + * {@snippet : + * BOOL SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet); + * } + */ + public static int SetupDiDestroyDeviceInfoList(MemorySegment DeviceInfoSet) { var mh$ = SetupDiDestroyDeviceInfoList$MH(); try { return (int)mh$.invokeExact(DeviceInfoSet); @@ -86,7 +139,12 @@ public static int SetupDiDestroyDeviceInfoList ( Addressable DeviceInfoSet) { public static MethodHandle SetupDiEnumDeviceInterfaces$MH() { return RuntimeHelper.requireNonNull(constants$0.SetupDiEnumDeviceInterfaces$MH,"SetupDiEnumDeviceInterfaces"); } - public static int SetupDiEnumDeviceInterfaces ( Addressable DeviceInfoSet, Addressable DeviceInfoData, Addressable InterfaceClassGuid, int MemberIndex, Addressable DeviceInterfaceData) { + /** + * {@snippet : + * BOOL SetupDiEnumDeviceInterfaces(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, const GUID* InterfaceClassGuid, DWORD MemberIndex, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData); + * } + */ + public static int SetupDiEnumDeviceInterfaces(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, MemorySegment InterfaceClassGuid, int MemberIndex, MemorySegment DeviceInterfaceData) { var mh$ = SetupDiEnumDeviceInterfaces$MH(); try { return (int)mh$.invokeExact(DeviceInfoSet, DeviceInfoData, InterfaceClassGuid, MemberIndex, DeviceInterfaceData); @@ -97,7 +155,12 @@ public static int SetupDiEnumDeviceInterfaces ( Addressable DeviceInfoSet, Addr public static MethodHandle SetupDiOpenDeviceInterfaceW$MH() { return RuntimeHelper.requireNonNull(constants$0.SetupDiOpenDeviceInterfaceW$MH,"SetupDiOpenDeviceInterfaceW"); } - public static int SetupDiOpenDeviceInterfaceW ( Addressable DeviceInfoSet, Addressable DevicePath, int OpenFlags, Addressable DeviceInterfaceData) { + /** + * {@snippet : + * BOOL SetupDiOpenDeviceInterfaceW(HDEVINFO DeviceInfoSet, PCWSTR DevicePath, DWORD OpenFlags, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData); + * } + */ + public static int SetupDiOpenDeviceInterfaceW(MemorySegment DeviceInfoSet, MemorySegment DevicePath, int OpenFlags, MemorySegment DeviceInterfaceData) { var mh$ = SetupDiOpenDeviceInterfaceW$MH(); try { return (int)mh$.invokeExact(DeviceInfoSet, DevicePath, OpenFlags, DeviceInterfaceData); @@ -108,7 +171,12 @@ public static int SetupDiOpenDeviceInterfaceW ( Addressable DeviceInfoSet, Addr public static MethodHandle SetupDiDeleteDeviceInterfaceData$MH() { return RuntimeHelper.requireNonNull(constants$1.SetupDiDeleteDeviceInterfaceData$MH,"SetupDiDeleteDeviceInterfaceData"); } - public static int SetupDiDeleteDeviceInterfaceData ( Addressable DeviceInfoSet, Addressable DeviceInterfaceData) { + /** + * {@snippet : + * BOOL SetupDiDeleteDeviceInterfaceData(HDEVINFO DeviceInfoSet, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData); + * } + */ + public static int SetupDiDeleteDeviceInterfaceData(MemorySegment DeviceInfoSet, MemorySegment DeviceInterfaceData) { var mh$ = SetupDiDeleteDeviceInterfaceData$MH(); try { return (int)mh$.invokeExact(DeviceInfoSet, DeviceInterfaceData); @@ -119,7 +187,12 @@ public static int SetupDiDeleteDeviceInterfaceData ( Addressable DeviceInfoSet, public static MethodHandle SetupDiGetDeviceInterfaceDetailW$MH() { return RuntimeHelper.requireNonNull(constants$1.SetupDiGetDeviceInterfaceDetailW$MH,"SetupDiGetDeviceInterfaceDetailW"); } - public static int SetupDiGetDeviceInterfaceDetailW ( Addressable DeviceInfoSet, Addressable DeviceInterfaceData, Addressable DeviceInterfaceDetailData, int DeviceInterfaceDetailDataSize, Addressable RequiredSize, Addressable DeviceInfoData) { + /** + * {@snippet : + * BOOL SetupDiGetDeviceInterfaceDetailW(HDEVINFO DeviceInfoSet, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData, DWORD DeviceInterfaceDetailDataSize, PDWORD RequiredSize, PSP_DEVINFO_DATA DeviceInfoData); + * } + */ + public static int SetupDiGetDeviceInterfaceDetailW(MemorySegment DeviceInfoSet, MemorySegment DeviceInterfaceData, MemorySegment DeviceInterfaceDetailData, int DeviceInterfaceDetailDataSize, MemorySegment RequiredSize, MemorySegment DeviceInfoData) { var mh$ = SetupDiGetDeviceInterfaceDetailW$MH(); try { return (int)mh$.invokeExact(DeviceInfoSet, DeviceInterfaceData, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData); @@ -130,10 +203,15 @@ public static int SetupDiGetDeviceInterfaceDetailW ( Addressable DeviceInfoSet, public static MethodHandle SetupDiGetClassDevsW$MH() { return RuntimeHelper.requireNonNull(constants$1.SetupDiGetClassDevsW$MH,"SetupDiGetClassDevsW"); } - public static MemoryAddress SetupDiGetClassDevsW ( Addressable ClassGuid, Addressable Enumerator, Addressable hwndParent, int Flags) { + /** + * {@snippet : + * HDEVINFO SetupDiGetClassDevsW(const GUID* ClassGuid, PCWSTR Enumerator, HWND hwndParent, DWORD Flags); + * } + */ + public static MemorySegment SetupDiGetClassDevsW(MemorySegment ClassGuid, MemorySegment Enumerator, MemorySegment hwndParent, int Flags) { var mh$ = SetupDiGetClassDevsW$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(ClassGuid, Enumerator, hwndParent, Flags); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(ClassGuid, Enumerator, hwndParent, Flags); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -141,10 +219,15 @@ public static MemoryAddress SetupDiGetClassDevsW ( Addressable ClassGuid, Addre public static MethodHandle SetupDiOpenDevRegKey$MH() { return RuntimeHelper.requireNonNull(constants$1.SetupDiOpenDevRegKey$MH,"SetupDiOpenDevRegKey"); } - public static MemoryAddress SetupDiOpenDevRegKey ( Addressable DeviceInfoSet, Addressable DeviceInfoData, int Scope, int HwProfile, int KeyType, int samDesired) { + /** + * {@snippet : + * HKEY SetupDiOpenDevRegKey(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Scope, DWORD HwProfile, DWORD KeyType, REGSAM samDesired); + * } + */ + public static MemorySegment SetupDiOpenDevRegKey(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, int Scope, int HwProfile, int KeyType, int samDesired) { var mh$ = SetupDiOpenDevRegKey$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(DeviceInfoSet, DeviceInfoData, Scope, HwProfile, KeyType, samDesired); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(DeviceInfoSet, DeviceInfoData, Scope, HwProfile, KeyType, samDesired); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -152,7 +235,12 @@ public static MemoryAddress SetupDiOpenDevRegKey ( Addressable DeviceInfoSet, A public static MethodHandle SetupDiGetDevicePropertyW$MH() { return RuntimeHelper.requireNonNull(constants$1.SetupDiGetDevicePropertyW$MH,"SetupDiGetDevicePropertyW"); } - public static int SetupDiGetDevicePropertyW ( Addressable DeviceInfoSet, Addressable DeviceInfoData, Addressable PropertyKey, Addressable PropertyType, Addressable PropertyBuffer, int PropertyBufferSize, Addressable RequiredSize, int Flags) { + /** + * {@snippet : + * BOOL SetupDiGetDevicePropertyW(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, const DEVPROPKEY* PropertyKey, DEVPROPTYPE* PropertyType, PBYTE PropertyBuffer, DWORD PropertyBufferSize, PDWORD RequiredSize, DWORD Flags); + * } + */ + public static int SetupDiGetDevicePropertyW(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, MemorySegment PropertyKey, MemorySegment PropertyType, MemorySegment PropertyBuffer, int PropertyBufferSize, MemorySegment RequiredSize, int Flags) { var mh$ = SetupDiGetDevicePropertyW$MH(); try { return (int)mh$.invokeExact(DeviceInfoSet, DeviceInfoData, PropertyKey, PropertyType, PropertyBuffer, PropertyBufferSize, RequiredSize, Flags); @@ -163,7 +251,12 @@ public static int SetupDiGetDevicePropertyW ( Addressable DeviceInfoSet, Addres public static MethodHandle SetupDiGetDeviceRegistryPropertyW$MH() { return RuntimeHelper.requireNonNull(constants$1.SetupDiGetDeviceRegistryPropertyW$MH,"SetupDiGetDeviceRegistryPropertyW"); } - public static int SetupDiGetDeviceRegistryPropertyW ( Addressable DeviceInfoSet, Addressable DeviceInfoData, int Property, Addressable PropertyRegDataType, Addressable PropertyBuffer, int PropertyBufferSize, Addressable RequiredSize) { + /** + * {@snippet : + * BOOL SetupDiGetDeviceRegistryPropertyW(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, PDWORD PropertyRegDataType, PBYTE PropertyBuffer, DWORD PropertyBufferSize, PDWORD RequiredSize); + * } + */ + public static int SetupDiGetDeviceRegistryPropertyW(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, int Property, MemorySegment PropertyRegDataType, MemorySegment PropertyBuffer, int PropertyBufferSize, MemorySegment RequiredSize) { var mh$ = SetupDiGetDeviceRegistryPropertyW$MH(); try { return (int)mh$.invokeExact(DeviceInfoSet, DeviceInfoData, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize); @@ -171,6 +264,11 @@ public static int SetupDiGetDeviceRegistryPropertyW ( Addressable DeviceInfoSet, throw new AssertionError("should not reach here", ex$); } } + /** + * {@snippet : + * #define SPDRP_ADDRESS 28 + * } + */ public static int SPDRP_ADDRESS() { return (int)28L; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java index de057457..9bc40ea2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java @@ -4,9 +4,19 @@ import java.lang.foreign.*; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct _SP_DEVICE_INTERFACE_DATA { + * DWORD cbSize; + * GUID InterfaceClassGuid; + * DWORD Flags; + * ULONG_PTR Reserved; + * }; + * } + */ public class _SP_DEVICE_INTERFACE_DATA { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_LONG$LAYOUT.withName("cbSize"), MemoryLayout.structLayout( Constants$root.C_LONG$LAYOUT.withName("Data1"), @@ -24,10 +34,22 @@ public class _SP_DEVICE_INTERFACE_DATA { public static VarHandle cbSize$VH() { return _SP_DEVICE_INTERFACE_DATA.cbSize$VH; } + /** + * Getter for field: + * {@snippet : + * DWORD cbSize; + * } + */ public static int cbSize$get(MemorySegment seg) { return (int)_SP_DEVICE_INTERFACE_DATA.cbSize$VH.get(seg); } - public static void cbSize$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * DWORD cbSize; + * } + */ + public static void cbSize$set(MemorySegment seg, int x) { _SP_DEVICE_INTERFACE_DATA.cbSize$VH.set(seg, x); } public static int cbSize$get(MemorySegment seg, long index) { @@ -43,10 +65,22 @@ public class _SP_DEVICE_INTERFACE_DATA { public static VarHandle Flags$VH() { return _SP_DEVICE_INTERFACE_DATA.Flags$VH; } + /** + * Getter for field: + * {@snippet : + * DWORD Flags; + * } + */ public static int Flags$get(MemorySegment seg) { return (int)_SP_DEVICE_INTERFACE_DATA.Flags$VH.get(seg); } - public static void Flags$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * DWORD Flags; + * } + */ + public static void Flags$set(MemorySegment seg, int x) { _SP_DEVICE_INTERFACE_DATA.Flags$VH.set(seg, x); } public static int Flags$get(MemorySegment seg, long index) { @@ -59,10 +93,22 @@ public class _SP_DEVICE_INTERFACE_DATA { public static VarHandle Reserved$VH() { return _SP_DEVICE_INTERFACE_DATA.Reserved$VH; } + /** + * Getter for field: + * {@snippet : + * ULONG_PTR Reserved; + * } + */ public static long Reserved$get(MemorySegment seg) { return (long)_SP_DEVICE_INTERFACE_DATA.Reserved$VH.get(seg); } - public static void Reserved$set( MemorySegment seg, long x) { + /** + * Setter for field: + * {@snippet : + * ULONG_PTR Reserved; + * } + */ + public static void Reserved$set(MemorySegment seg, long x) { _SP_DEVICE_INTERFACE_DATA.Reserved$VH.set(seg, x); } public static long Reserved$get(MemorySegment seg, long index) { @@ -73,10 +119,10 @@ public class _SP_DEVICE_INTERFACE_DATA { } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java index bc3ac979..6f9b55e4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java @@ -4,9 +4,17 @@ import java.lang.foreign.*; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W { + * DWORD cbSize; + * WCHAR DevicePath[1]; + * }; + * } + */ public class _SP_DEVICE_INTERFACE_DETAIL_DATA_W { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_LONG$LAYOUT.withName("cbSize"), MemoryLayout.sequenceLayout(1, Constants$root.C_SHORT$LAYOUT).withName("DevicePath"), MemoryLayout.paddingLayout(16) @@ -18,10 +26,22 @@ public class _SP_DEVICE_INTERFACE_DETAIL_DATA_W { public static VarHandle cbSize$VH() { return _SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$VH; } + /** + * Getter for field: + * {@snippet : + * DWORD cbSize; + * } + */ public static int cbSize$get(MemorySegment seg) { return (int)_SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$VH.get(seg); } - public static void cbSize$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * DWORD cbSize; + * } + */ + public static void cbSize$set(MemorySegment seg, int x) { _SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$VH.set(seg, x); } public static int cbSize$get(MemorySegment seg, long index) { @@ -35,10 +55,10 @@ public class _SP_DEVICE_INTERFACE_DETAIL_DATA_W { } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java index dbba0ab5..375bb2a9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java @@ -4,9 +4,19 @@ import java.lang.foreign.*; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct _SP_DEVINFO_DATA { + * DWORD cbSize; + * GUID ClassGuid; + * DWORD DevInst; + * ULONG_PTR Reserved; + * }; + * } + */ public class _SP_DEVINFO_DATA { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_LONG$LAYOUT.withName("cbSize"), MemoryLayout.structLayout( Constants$root.C_LONG$LAYOUT.withName("Data1"), @@ -24,10 +34,22 @@ public class _SP_DEVINFO_DATA { public static VarHandle cbSize$VH() { return _SP_DEVINFO_DATA.cbSize$VH; } + /** + * Getter for field: + * {@snippet : + * DWORD cbSize; + * } + */ public static int cbSize$get(MemorySegment seg) { return (int)_SP_DEVINFO_DATA.cbSize$VH.get(seg); } - public static void cbSize$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * DWORD cbSize; + * } + */ + public static void cbSize$set(MemorySegment seg, int x) { _SP_DEVINFO_DATA.cbSize$VH.set(seg, x); } public static int cbSize$get(MemorySegment seg, long index) { @@ -43,10 +65,22 @@ public class _SP_DEVINFO_DATA { public static VarHandle DevInst$VH() { return _SP_DEVINFO_DATA.DevInst$VH; } + /** + * Getter for field: + * {@snippet : + * DWORD DevInst; + * } + */ public static int DevInst$get(MemorySegment seg) { return (int)_SP_DEVINFO_DATA.DevInst$VH.get(seg); } - public static void DevInst$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * DWORD DevInst; + * } + */ + public static void DevInst$set(MemorySegment seg, int x) { _SP_DEVINFO_DATA.DevInst$VH.set(seg, x); } public static int DevInst$get(MemorySegment seg, long index) { @@ -59,10 +93,22 @@ public class _SP_DEVINFO_DATA { public static VarHandle Reserved$VH() { return _SP_DEVINFO_DATA.Reserved$VH; } + /** + * Getter for field: + * {@snippet : + * ULONG_PTR Reserved; + * } + */ public static long Reserved$get(MemorySegment seg) { return (long)_SP_DEVINFO_DATA.Reserved$VH.get(seg); } - public static void Reserved$set( MemorySegment seg, long x) { + /** + * Setter for field: + * {@snippet : + * ULONG_PTR Reserved; + * } + */ + public static void Reserved$set(MemorySegment seg, long x) { _SP_DEVINFO_DATA.Reserved$VH.set(seg, x); } public static long Reserved$get(MemorySegment seg, long index) { @@ -73,10 +119,10 @@ public class _SP_DEVINFO_DATA { } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java index 60b0522a..4b375872 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$0 { +final class constants$0 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} static final FunctionDescriptor SetupDiCreateDeviceInfoList$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java index 1cadf471..bec4f318 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$1 { +final class constants$1 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$1() {} static final FunctionDescriptor SetupDiDeleteDeviceInterfaceData$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/Constants$root.java index 80f6c451..01ae179c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.windows.gen.stdlib; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfInt C_LONG$LAYOUT = JAVA_INT; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/RuntimeHelper.java index ffabd418..56e1248c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/RuntimeHelper.java @@ -10,21 +10,24 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -32,45 +35,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -96,7 +97,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -106,8 +109,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -142,7 +144,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -192,10 +196,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -206,7 +207,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/StdLib.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/StdLib.java index e76fe363..08c5b6a8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/StdLib.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/StdLib.java @@ -2,25 +2,29 @@ package net.codecrete.usb.windows.gen.stdlib; -import java.lang.foreign.Addressable; +import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class StdLib { - /* package-private */ StdLib() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; public static MethodHandle wcslen$MH() { return RuntimeHelper.requireNonNull(constants$0.wcslen$MH,"wcslen"); } - public static long wcslen ( Addressable _String) { + /** + * {@snippet : + * unsigned long long wcslen(const wchar_t* _String); + * } + */ + public static long wcslen(MemorySegment _String) { var mh$ = wcslen$MH(); try { return (long)mh$.invokeExact(_String); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/constants$0.java index 5ca00b1c..8c197603 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/constants$0.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$0 { +final class constants$0 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} static final FunctionDescriptor wcslen$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT ); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/Constants$root.java index 66ce20c5..e7c4dd8b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.windows.gen.usbioctl; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfInt C_LONG$LAYOUT = JAVA_INT; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java index 5e1c6f71..12f2bba9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java @@ -10,21 +10,24 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -32,45 +35,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -96,7 +97,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -106,8 +109,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -142,7 +144,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -192,10 +196,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -206,7 +207,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java index bbb4e966..34449de5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java @@ -5,18 +5,27 @@ import static java.lang.foreign.ValueLayout.*; public class USBIoctl { - /* package-private */ USBIoctl() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + /** + * {@snippet : + * #define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 2229264 + * } + */ public static int IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION() { return (int)2229264L; } + /** + * {@snippet : + * #define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX 2229320 + * } + */ public static int IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX() { return (int)2229320L; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/Constants$root.java index 91462c49..7aabbc3e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.windows.gen.user32; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfInt C_LONG$LAYOUT = JAVA_INT; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_DEVICEINTERFACE_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_DEVICEINTERFACE_W.java index 42c68946..e13c9de5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_DEVICEINTERFACE_W.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_DEVICEINTERFACE_W.java @@ -2,8 +2,15 @@ package net.codecrete.usb.windows.gen.user32; -public class DEV_BROADCAST_DEVICEINTERFACE_W extends _DEV_BROADCAST_DEVICEINTERFACE_W { +/** + * {@snippet : + * typedef struct _DEV_BROADCAST_DEVICEINTERFACE_W DEV_BROADCAST_DEVICEINTERFACE_W; + * } + */ +public final class DEV_BROADCAST_DEVICEINTERFACE_W extends _DEV_BROADCAST_DEVICEINTERFACE_W { + // Suppresses default constructor, ensuring non-instantiability. + private DEV_BROADCAST_DEVICEINTERFACE_W() {} } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_HDR.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_HDR.java index bc2a60af..684c0ac3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_HDR.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_HDR.java @@ -2,8 +2,15 @@ package net.codecrete.usb.windows.gen.user32; -public class DEV_BROADCAST_HDR extends _DEV_BROADCAST_HDR { +/** + * {@snippet : + * typedef struct _DEV_BROADCAST_HDR DEV_BROADCAST_HDR; + * } + */ +public final class DEV_BROADCAST_HDR extends _DEV_BROADCAST_HDR { + // Suppresses default constructor, ensuring non-instantiability. + private DEV_BROADCAST_HDR() {} } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/MSG.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/MSG.java index 2cff5412..1717dd43 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/MSG.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/MSG.java @@ -2,8 +2,15 @@ package net.codecrete.usb.windows.gen.user32; -public class MSG extends tagMSG { +/** + * {@snippet : + * typedef struct tagMSG MSG; + * } + */ +public final class MSG extends tagMSG { + // Suppresses default constructor, ensuring non-instantiability. + private MSG() {} } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java index 6da1ee8a..24cd8ed6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java @@ -10,21 +10,24 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { System.loadLibrary("User32"); SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -32,45 +35,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -96,7 +97,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -106,8 +109,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -142,7 +144,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -192,10 +196,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -206,7 +207,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java index 92a80196..57f923ab 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java @@ -2,41 +2,69 @@ package net.codecrete.usb.windows.gen.user32; -import java.lang.foreign.Addressable; -import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class User32 { - /* package-private */ User32() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + /** + * {@snippet : + * #define WM_DEVICECHANGE 537 + * } + */ public static int WM_DEVICECHANGE() { return (int)537L; } + /** + * {@snippet : + * #define DEVICE_NOTIFY_WINDOW_HANDLE 0 + * } + */ public static int DEVICE_NOTIFY_WINDOW_HANDLE() { return (int)0L; } + /** + * {@snippet : + * #define DBT_DEVICEARRIVAL 32768 + * } + */ public static int DBT_DEVICEARRIVAL() { return (int)32768L; } + /** + * {@snippet : + * #define DBT_DEVICEREMOVECOMPLETE 32772 + * } + */ public static int DBT_DEVICEREMOVECOMPLETE() { return (int)32772L; } + /** + * {@snippet : + * #define DBT_DEVTYP_DEVICEINTERFACE 5 + * } + */ public static int DBT_DEVTYP_DEVICEINTERFACE() { return (int)5L; } public static MethodHandle GetMessageW$MH() { return RuntimeHelper.requireNonNull(constants$0.GetMessageW$MH,"GetMessageW"); } - public static int GetMessageW ( Addressable lpMsg, Addressable hWnd, int wMsgFilterMin, int wMsgFilterMax) { + /** + * {@snippet : + * BOOL GetMessageW(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax); + * } + */ + public static int GetMessageW(MemorySegment lpMsg, MemorySegment hWnd, int wMsgFilterMin, int wMsgFilterMax) { var mh$ = GetMessageW$MH(); try { return (int)mh$.invokeExact(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); @@ -47,10 +75,15 @@ public static int GetMessageW ( Addressable lpMsg, Addressable hWnd, int wMsgF public static MethodHandle RegisterDeviceNotificationW$MH() { return RuntimeHelper.requireNonNull(constants$0.RegisterDeviceNotificationW$MH,"RegisterDeviceNotificationW"); } - public static MemoryAddress RegisterDeviceNotificationW ( Addressable hRecipient, Addressable NotificationFilter, int Flags) { + /** + * {@snippet : + * HDEVNOTIFY RegisterDeviceNotificationW(HANDLE hRecipient, LPVOID NotificationFilter, DWORD Flags); + * } + */ + public static MemorySegment RegisterDeviceNotificationW(MemorySegment hRecipient, MemorySegment NotificationFilter, int Flags) { var mh$ = RegisterDeviceNotificationW$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(hRecipient, NotificationFilter, Flags); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(hRecipient, NotificationFilter, Flags); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -58,7 +91,12 @@ public static MemoryAddress RegisterDeviceNotificationW ( Addressable hRecipient public static MethodHandle DefWindowProcW$MH() { return RuntimeHelper.requireNonNull(constants$0.DefWindowProcW$MH,"DefWindowProcW"); } - public static long DefWindowProcW ( Addressable hWnd, int Msg, long wParam, long lParam) { + /** + * {@snippet : + * LRESULT DefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); + * } + */ + public static long DefWindowProcW(MemorySegment hWnd, int Msg, long wParam, long lParam) { var mh$ = DefWindowProcW$MH(); try { return (long)mh$.invokeExact(hWnd, Msg, wParam, lParam); @@ -69,7 +107,12 @@ public static long DefWindowProcW ( Addressable hWnd, int Msg, long wParam, l public static MethodHandle RegisterClassExW$MH() { return RuntimeHelper.requireNonNull(constants$0.RegisterClassExW$MH,"RegisterClassExW"); } - public static short RegisterClassExW ( Addressable x0) { + /** + * {@snippet : + * ATOM RegisterClassExW(const WNDCLASSEXW*); + * } + */ + public static short RegisterClassExW(MemorySegment x0) { var mh$ = RegisterClassExW$MH(); try { return (short)mh$.invokeExact(x0); @@ -80,15 +123,25 @@ public static short RegisterClassExW ( Addressable x0) { public static MethodHandle CreateWindowExW$MH() { return RuntimeHelper.requireNonNull(constants$0.CreateWindowExW$MH,"CreateWindowExW"); } - public static MemoryAddress CreateWindowExW ( int dwExStyle, Addressable lpClassName, Addressable lpWindowName, int dwStyle, int X, int Y, int nWidth, int nHeight, Addressable hWndParent, Addressable hMenu, Addressable hInstance, Addressable lpParam) { + /** + * {@snippet : + * HWND CreateWindowExW(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam); + * } + */ + public static MemorySegment CreateWindowExW(int dwExStyle, MemorySegment lpClassName, MemorySegment lpWindowName, int dwStyle, int X, int Y, int nWidth, int nHeight, MemorySegment hWndParent, MemorySegment hMenu, MemorySegment hInstance, MemorySegment lpParam) { var mh$ = CreateWindowExW$MH(); try { - return (java.lang.foreign.MemoryAddress)mh$.invokeExact(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + return (java.lang.foreign.MemorySegment)mh$.invokeExact(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } } - public static MemoryAddress HWND_MESSAGE() { + /** + * {@snippet : + * #define HWND_MESSAGE -3 + * } + */ + public static MemorySegment HWND_MESSAGE() { return constants$0.HWND_MESSAGE$ADDR; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/WNDCLASSEXW.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/WNDCLASSEXW.java index b09b0cfc..aa336e43 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/WNDCLASSEXW.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/WNDCLASSEXW.java @@ -2,8 +2,15 @@ package net.codecrete.usb.windows.gen.user32; -public class WNDCLASSEXW extends tagWNDCLASSEXW { +/** + * {@snippet : + * typedef struct tagWNDCLASSEXW WNDCLASSEXW; + * } + */ +public final class WNDCLASSEXW extends tagWNDCLASSEXW { + // Suppresses default constructor, ensuring non-instantiability. + private WNDCLASSEXW() {} } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java index 3a3548fc..b525ec13 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java @@ -4,9 +4,20 @@ import java.lang.foreign.*; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct _DEV_BROADCAST_DEVICEINTERFACE_W { + * DWORD dbcc_size; + * DWORD dbcc_devicetype; + * DWORD dbcc_reserved; + * GUID dbcc_classguid; + * wchar_t dbcc_name[1]; + * }; + * } + */ public class _DEV_BROADCAST_DEVICEINTERFACE_W { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_LONG$LAYOUT.withName("dbcc_size"), Constants$root.C_LONG$LAYOUT.withName("dbcc_devicetype"), Constants$root.C_LONG$LAYOUT.withName("dbcc_reserved"), @@ -26,10 +37,22 @@ public class _DEV_BROADCAST_DEVICEINTERFACE_W { public static VarHandle dbcc_size$VH() { return _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$VH; } + /** + * Getter for field: + * {@snippet : + * DWORD dbcc_size; + * } + */ public static int dbcc_size$get(MemorySegment seg) { return (int)_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$VH.get(seg); } - public static void dbcc_size$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * DWORD dbcc_size; + * } + */ + public static void dbcc_size$set(MemorySegment seg, int x) { _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$VH.set(seg, x); } public static int dbcc_size$get(MemorySegment seg, long index) { @@ -42,10 +65,22 @@ public class _DEV_BROADCAST_DEVICEINTERFACE_W { public static VarHandle dbcc_devicetype$VH() { return _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$VH; } + /** + * Getter for field: + * {@snippet : + * DWORD dbcc_devicetype; + * } + */ public static int dbcc_devicetype$get(MemorySegment seg) { return (int)_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$VH.get(seg); } - public static void dbcc_devicetype$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * DWORD dbcc_devicetype; + * } + */ + public static void dbcc_devicetype$set(MemorySegment seg, int x) { _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$VH.set(seg, x); } public static int dbcc_devicetype$get(MemorySegment seg, long index) { @@ -58,10 +93,22 @@ public class _DEV_BROADCAST_DEVICEINTERFACE_W { public static VarHandle dbcc_reserved$VH() { return _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_reserved$VH; } + /** + * Getter for field: + * {@snippet : + * DWORD dbcc_reserved; + * } + */ public static int dbcc_reserved$get(MemorySegment seg) { return (int)_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_reserved$VH.get(seg); } - public static void dbcc_reserved$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * DWORD dbcc_reserved; + * } + */ + public static void dbcc_reserved$set(MemorySegment seg, int x) { _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_reserved$VH.set(seg, x); } public static int dbcc_reserved$get(MemorySegment seg, long index) { @@ -78,10 +125,10 @@ public class _DEV_BROADCAST_DEVICEINTERFACE_W { } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java index 85d5840e..d037452d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java @@ -4,9 +4,18 @@ import java.lang.foreign.*; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct _DEV_BROADCAST_HDR { + * DWORD dbch_size; + * DWORD dbch_devicetype; + * DWORD dbch_reserved; + * }; + * } + */ public class _DEV_BROADCAST_HDR { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_LONG$LAYOUT.withName("dbch_size"), Constants$root.C_LONG$LAYOUT.withName("dbch_devicetype"), Constants$root.C_LONG$LAYOUT.withName("dbch_reserved") @@ -18,10 +27,22 @@ public class _DEV_BROADCAST_HDR { public static VarHandle dbch_size$VH() { return _DEV_BROADCAST_HDR.dbch_size$VH; } + /** + * Getter for field: + * {@snippet : + * DWORD dbch_size; + * } + */ public static int dbch_size$get(MemorySegment seg) { return (int)_DEV_BROADCAST_HDR.dbch_size$VH.get(seg); } - public static void dbch_size$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * DWORD dbch_size; + * } + */ + public static void dbch_size$set(MemorySegment seg, int x) { _DEV_BROADCAST_HDR.dbch_size$VH.set(seg, x); } public static int dbch_size$get(MemorySegment seg, long index) { @@ -34,10 +55,22 @@ public class _DEV_BROADCAST_HDR { public static VarHandle dbch_devicetype$VH() { return _DEV_BROADCAST_HDR.dbch_devicetype$VH; } + /** + * Getter for field: + * {@snippet : + * DWORD dbch_devicetype; + * } + */ public static int dbch_devicetype$get(MemorySegment seg) { return (int)_DEV_BROADCAST_HDR.dbch_devicetype$VH.get(seg); } - public static void dbch_devicetype$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * DWORD dbch_devicetype; + * } + */ + public static void dbch_devicetype$set(MemorySegment seg, int x) { _DEV_BROADCAST_HDR.dbch_devicetype$VH.set(seg, x); } public static int dbch_devicetype$get(MemorySegment seg, long index) { @@ -50,10 +83,22 @@ public class _DEV_BROADCAST_HDR { public static VarHandle dbch_reserved$VH() { return _DEV_BROADCAST_HDR.dbch_reserved$VH; } + /** + * Getter for field: + * {@snippet : + * DWORD dbch_reserved; + * } + */ public static int dbch_reserved$get(MemorySegment seg) { return (int)_DEV_BROADCAST_HDR.dbch_reserved$VH.get(seg); } - public static void dbch_reserved$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * DWORD dbch_reserved; + * } + */ + public static void dbch_reserved$set(MemorySegment seg, int x) { _DEV_BROADCAST_HDR.dbch_reserved$VH.set(seg, x); } public static int dbch_reserved$get(MemorySegment seg, long index) { @@ -64,10 +109,10 @@ public class _DEV_BROADCAST_HDR { } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java index f137ae31..99958f5f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java @@ -3,10 +3,12 @@ package net.codecrete.usb.windows.gen.user32; import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryAddress; +import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; -class constants$0 { +final class constants$0 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} static final FunctionDescriptor GetMessageW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -61,7 +63,7 @@ class constants$0 { "CreateWindowExW", constants$0.CreateWindowExW$FUNC ); - static final MemoryAddress HWND_MESSAGE$ADDR = MemoryAddress.ofLong(-3L); + static final MemorySegment HWND_MESSAGE$ADDR = MemorySegment.ofAddress(-3L); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java index 1fad57f8..afb5ad7a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java @@ -4,9 +4,21 @@ import java.lang.foreign.*; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct tagMSG { + * HWND hwnd; + * UINT message; + * WPARAM wParam; + * LPARAM lParam; + * DWORD time; + * POINT pt; + * }; + * } + */ public class tagMSG { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_POINTER$LAYOUT.withName("hwnd"), Constants$root.C_LONG$LAYOUT.withName("message"), MemoryLayout.paddingLayout(32), @@ -26,26 +38,50 @@ public class tagMSG { public static VarHandle hwnd$VH() { return tagMSG.hwnd$VH; } - public static MemoryAddress hwnd$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)tagMSG.hwnd$VH.get(seg); - } - public static void hwnd$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * HWND hwnd; + * } + */ + public static MemorySegment hwnd$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)tagMSG.hwnd$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * HWND hwnd; + * } + */ + public static void hwnd$set(MemorySegment seg, MemorySegment x) { tagMSG.hwnd$VH.set(seg, x); } - public static MemoryAddress hwnd$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)tagMSG.hwnd$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment hwnd$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)tagMSG.hwnd$VH.get(seg.asSlice(index*sizeof())); } - public static void hwnd$set(MemorySegment seg, long index, MemoryAddress x) { + public static void hwnd$set(MemorySegment seg, long index, MemorySegment x) { tagMSG.hwnd$VH.set(seg.asSlice(index*sizeof()), x); } static final VarHandle message$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("message")); public static VarHandle message$VH() { return tagMSG.message$VH; } + /** + * Getter for field: + * {@snippet : + * UINT message; + * } + */ public static int message$get(MemorySegment seg) { return (int)tagMSG.message$VH.get(seg); } - public static void message$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * UINT message; + * } + */ + public static void message$set(MemorySegment seg, int x) { tagMSG.message$VH.set(seg, x); } public static int message$get(MemorySegment seg, long index) { @@ -58,10 +94,22 @@ public class tagMSG { public static VarHandle wParam$VH() { return tagMSG.wParam$VH; } + /** + * Getter for field: + * {@snippet : + * WPARAM wParam; + * } + */ public static long wParam$get(MemorySegment seg) { return (long)tagMSG.wParam$VH.get(seg); } - public static void wParam$set( MemorySegment seg, long x) { + /** + * Setter for field: + * {@snippet : + * WPARAM wParam; + * } + */ + public static void wParam$set(MemorySegment seg, long x) { tagMSG.wParam$VH.set(seg, x); } public static long wParam$get(MemorySegment seg, long index) { @@ -74,10 +122,22 @@ public class tagMSG { public static VarHandle lParam$VH() { return tagMSG.lParam$VH; } + /** + * Getter for field: + * {@snippet : + * LPARAM lParam; + * } + */ public static long lParam$get(MemorySegment seg) { return (long)tagMSG.lParam$VH.get(seg); } - public static void lParam$set( MemorySegment seg, long x) { + /** + * Setter for field: + * {@snippet : + * LPARAM lParam; + * } + */ + public static void lParam$set(MemorySegment seg, long x) { tagMSG.lParam$VH.set(seg, x); } public static long lParam$get(MemorySegment seg, long index) { @@ -90,10 +150,22 @@ public class tagMSG { public static VarHandle time$VH() { return tagMSG.time$VH; } + /** + * Getter for field: + * {@snippet : + * DWORD time; + * } + */ public static int time$get(MemorySegment seg) { return (int)tagMSG.time$VH.get(seg); } - public static void time$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * DWORD time; + * } + */ + public static void time$set(MemorySegment seg, int x) { tagMSG.time$VH.set(seg, x); } public static int time$get(MemorySegment seg, long index) { @@ -107,10 +179,10 @@ public class tagMSG { } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java index 9612b1a7..7a7b1859 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java @@ -4,9 +4,27 @@ import java.lang.foreign.*; import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct tagWNDCLASSEXW { + * UINT cbSize; + * UINT style; + * WNDPROC lpfnWndProc; + * int cbClsExtra; + * int cbWndExtra; + * HINSTANCE hInstance; + * HICON hIcon; + * HCURSOR hCursor; + * HBRUSH hbrBackground; + * LPCWSTR lpszMenuName; + * LPCWSTR lpszClassName; + * HICON hIconSm; + * }; + * } + */ public class tagWNDCLASSEXW { - static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_LONG$LAYOUT.withName("cbSize"), Constants$root.C_LONG$LAYOUT.withName("style"), Constants$root.C_POINTER$LAYOUT.withName("lpfnWndProc"), @@ -27,10 +45,22 @@ public class tagWNDCLASSEXW { public static VarHandle cbSize$VH() { return tagWNDCLASSEXW.cbSize$VH; } + /** + * Getter for field: + * {@snippet : + * UINT cbSize; + * } + */ public static int cbSize$get(MemorySegment seg) { return (int)tagWNDCLASSEXW.cbSize$VH.get(seg); } - public static void cbSize$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * UINT cbSize; + * } + */ + public static void cbSize$set(MemorySegment seg, int x) { tagWNDCLASSEXW.cbSize$VH.set(seg, x); } public static int cbSize$get(MemorySegment seg, long index) { @@ -43,10 +73,22 @@ public class tagWNDCLASSEXW { public static VarHandle style$VH() { return tagWNDCLASSEXW.style$VH; } + /** + * Getter for field: + * {@snippet : + * UINT style; + * } + */ public static int style$get(MemorySegment seg) { return (int)tagWNDCLASSEXW.style$VH.get(seg); } - public static void style$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * UINT style; + * } + */ + public static void style$set(MemorySegment seg, int x) { tagWNDCLASSEXW.style$VH.set(seg, x); } public static int style$get(MemorySegment seg, long index) { @@ -59,26 +101,50 @@ public class tagWNDCLASSEXW { public static VarHandle lpfnWndProc$VH() { return tagWNDCLASSEXW.lpfnWndProc$VH; } - public static MemoryAddress lpfnWndProc$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.lpfnWndProc$VH.get(seg); - } - public static void lpfnWndProc$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * WNDPROC lpfnWndProc; + * } + */ + public static MemorySegment lpfnWndProc$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.lpfnWndProc$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * WNDPROC lpfnWndProc; + * } + */ + public static void lpfnWndProc$set(MemorySegment seg, MemorySegment x) { tagWNDCLASSEXW.lpfnWndProc$VH.set(seg, x); } - public static MemoryAddress lpfnWndProc$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.lpfnWndProc$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment lpfnWndProc$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.lpfnWndProc$VH.get(seg.asSlice(index*sizeof())); } - public static void lpfnWndProc$set(MemorySegment seg, long index, MemoryAddress x) { + public static void lpfnWndProc$set(MemorySegment seg, long index, MemorySegment x) { tagWNDCLASSEXW.lpfnWndProc$VH.set(seg.asSlice(index*sizeof()), x); } static final VarHandle cbClsExtra$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("cbClsExtra")); public static VarHandle cbClsExtra$VH() { return tagWNDCLASSEXW.cbClsExtra$VH; } + /** + * Getter for field: + * {@snippet : + * int cbClsExtra; + * } + */ public static int cbClsExtra$get(MemorySegment seg) { return (int)tagWNDCLASSEXW.cbClsExtra$VH.get(seg); } - public static void cbClsExtra$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * int cbClsExtra; + * } + */ + public static void cbClsExtra$set(MemorySegment seg, int x) { tagWNDCLASSEXW.cbClsExtra$VH.set(seg, x); } public static int cbClsExtra$get(MemorySegment seg, long index) { @@ -91,10 +157,22 @@ public class tagWNDCLASSEXW { public static VarHandle cbWndExtra$VH() { return tagWNDCLASSEXW.cbWndExtra$VH; } + /** + * Getter for field: + * {@snippet : + * int cbWndExtra; + * } + */ public static int cbWndExtra$get(MemorySegment seg) { return (int)tagWNDCLASSEXW.cbWndExtra$VH.get(seg); } - public static void cbWndExtra$set( MemorySegment seg, int x) { + /** + * Setter for field: + * {@snippet : + * int cbWndExtra; + * } + */ + public static void cbWndExtra$set(MemorySegment seg, int x) { tagWNDCLASSEXW.cbWndExtra$VH.set(seg, x); } public static int cbWndExtra$get(MemorySegment seg, long index) { @@ -107,120 +185,204 @@ public class tagWNDCLASSEXW { public static VarHandle hInstance$VH() { return tagWNDCLASSEXW.hInstance$VH; } - public static MemoryAddress hInstance$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hInstance$VH.get(seg); - } - public static void hInstance$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * HINSTANCE hInstance; + * } + */ + public static MemorySegment hInstance$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hInstance$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * HINSTANCE hInstance; + * } + */ + public static void hInstance$set(MemorySegment seg, MemorySegment x) { tagWNDCLASSEXW.hInstance$VH.set(seg, x); } - public static MemoryAddress hInstance$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hInstance$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment hInstance$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hInstance$VH.get(seg.asSlice(index*sizeof())); } - public static void hInstance$set(MemorySegment seg, long index, MemoryAddress x) { + public static void hInstance$set(MemorySegment seg, long index, MemorySegment x) { tagWNDCLASSEXW.hInstance$VH.set(seg.asSlice(index*sizeof()), x); } static final VarHandle hIcon$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hIcon")); public static VarHandle hIcon$VH() { return tagWNDCLASSEXW.hIcon$VH; } - public static MemoryAddress hIcon$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hIcon$VH.get(seg); - } - public static void hIcon$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * HICON hIcon; + * } + */ + public static MemorySegment hIcon$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hIcon$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * HICON hIcon; + * } + */ + public static void hIcon$set(MemorySegment seg, MemorySegment x) { tagWNDCLASSEXW.hIcon$VH.set(seg, x); } - public static MemoryAddress hIcon$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hIcon$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment hIcon$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hIcon$VH.get(seg.asSlice(index*sizeof())); } - public static void hIcon$set(MemorySegment seg, long index, MemoryAddress x) { + public static void hIcon$set(MemorySegment seg, long index, MemorySegment x) { tagWNDCLASSEXW.hIcon$VH.set(seg.asSlice(index*sizeof()), x); } static final VarHandle hCursor$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hCursor")); public static VarHandle hCursor$VH() { return tagWNDCLASSEXW.hCursor$VH; } - public static MemoryAddress hCursor$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hCursor$VH.get(seg); - } - public static void hCursor$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * HCURSOR hCursor; + * } + */ + public static MemorySegment hCursor$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hCursor$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * HCURSOR hCursor; + * } + */ + public static void hCursor$set(MemorySegment seg, MemorySegment x) { tagWNDCLASSEXW.hCursor$VH.set(seg, x); } - public static MemoryAddress hCursor$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hCursor$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment hCursor$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hCursor$VH.get(seg.asSlice(index*sizeof())); } - public static void hCursor$set(MemorySegment seg, long index, MemoryAddress x) { + public static void hCursor$set(MemorySegment seg, long index, MemorySegment x) { tagWNDCLASSEXW.hCursor$VH.set(seg.asSlice(index*sizeof()), x); } static final VarHandle hbrBackground$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hbrBackground")); public static VarHandle hbrBackground$VH() { return tagWNDCLASSEXW.hbrBackground$VH; } - public static MemoryAddress hbrBackground$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hbrBackground$VH.get(seg); - } - public static void hbrBackground$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * HBRUSH hbrBackground; + * } + */ + public static MemorySegment hbrBackground$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hbrBackground$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * HBRUSH hbrBackground; + * } + */ + public static void hbrBackground$set(MemorySegment seg, MemorySegment x) { tagWNDCLASSEXW.hbrBackground$VH.set(seg, x); } - public static MemoryAddress hbrBackground$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hbrBackground$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment hbrBackground$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hbrBackground$VH.get(seg.asSlice(index*sizeof())); } - public static void hbrBackground$set(MemorySegment seg, long index, MemoryAddress x) { + public static void hbrBackground$set(MemorySegment seg, long index, MemorySegment x) { tagWNDCLASSEXW.hbrBackground$VH.set(seg.asSlice(index*sizeof()), x); } static final VarHandle lpszMenuName$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("lpszMenuName")); public static VarHandle lpszMenuName$VH() { return tagWNDCLASSEXW.lpszMenuName$VH; } - public static MemoryAddress lpszMenuName$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.lpszMenuName$VH.get(seg); - } - public static void lpszMenuName$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * LPCWSTR lpszMenuName; + * } + */ + public static MemorySegment lpszMenuName$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.lpszMenuName$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * LPCWSTR lpszMenuName; + * } + */ + public static void lpszMenuName$set(MemorySegment seg, MemorySegment x) { tagWNDCLASSEXW.lpszMenuName$VH.set(seg, x); } - public static MemoryAddress lpszMenuName$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.lpszMenuName$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment lpszMenuName$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.lpszMenuName$VH.get(seg.asSlice(index*sizeof())); } - public static void lpszMenuName$set(MemorySegment seg, long index, MemoryAddress x) { + public static void lpszMenuName$set(MemorySegment seg, long index, MemorySegment x) { tagWNDCLASSEXW.lpszMenuName$VH.set(seg.asSlice(index*sizeof()), x); } static final VarHandle lpszClassName$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("lpszClassName")); public static VarHandle lpszClassName$VH() { return tagWNDCLASSEXW.lpszClassName$VH; } - public static MemoryAddress lpszClassName$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.lpszClassName$VH.get(seg); - } - public static void lpszClassName$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * LPCWSTR lpszClassName; + * } + */ + public static MemorySegment lpszClassName$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.lpszClassName$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * LPCWSTR lpszClassName; + * } + */ + public static void lpszClassName$set(MemorySegment seg, MemorySegment x) { tagWNDCLASSEXW.lpszClassName$VH.set(seg, x); } - public static MemoryAddress lpszClassName$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.lpszClassName$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment lpszClassName$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.lpszClassName$VH.get(seg.asSlice(index*sizeof())); } - public static void lpszClassName$set(MemorySegment seg, long index, MemoryAddress x) { + public static void lpszClassName$set(MemorySegment seg, long index, MemorySegment x) { tagWNDCLASSEXW.lpszClassName$VH.set(seg.asSlice(index*sizeof()), x); } static final VarHandle hIconSm$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hIconSm")); public static VarHandle hIconSm$VH() { return tagWNDCLASSEXW.hIconSm$VH; } - public static MemoryAddress hIconSm$get(MemorySegment seg) { - return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hIconSm$VH.get(seg); - } - public static void hIconSm$set( MemorySegment seg, MemoryAddress x) { + /** + * Getter for field: + * {@snippet : + * HICON hIconSm; + * } + */ + public static MemorySegment hIconSm$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hIconSm$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * HICON hIconSm; + * } + */ + public static void hIconSm$set(MemorySegment seg, MemorySegment x) { tagWNDCLASSEXW.hIconSm$VH.set(seg, x); } - public static MemoryAddress hIconSm$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemoryAddress)tagWNDCLASSEXW.hIconSm$VH.get(seg.asSlice(index*sizeof())); + public static MemorySegment hIconSm$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hIconSm$VH.get(seg.asSlice(index*sizeof())); } - public static void hIconSm$set(MemorySegment seg, long index, MemoryAddress x) { + public static void hIconSm$set(MemorySegment seg, long index, MemorySegment x) { tagWNDCLASSEXW.hIconSm$VH.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemoryAddress addr, MemorySession session) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, session); } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/Constants$root.java index 3568e394..840db08a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/Constants$root.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/Constants$root.java @@ -3,17 +3,19 @@ package net.codecrete.usb.windows.gen.winusb; import static java.lang.foreign.ValueLayout.*; -public class Constants$root { +final class Constants$root { - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfInt C_LONG$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfInt C_LONG$LAYOUT = JAVA_INT; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java index f4a55475..8b0bda65 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java @@ -10,21 +10,24 @@ final class RuntimeHelper { - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); static { System.loadLibrary("Winusb"); SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + static T requireNonNull(T obj, String symbolName) { if (obj == null) { throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); @@ -32,45 +35,43 @@ static T requireNonNull(T obj, String symbolName) { return obj; } - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); } - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> LINKER.downcallHandle(addr, fdesc)). orElse(null); } - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { return LINKER.downcallHandle(fdesc); } - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). map(addr -> VarargsInvoker.make(addr, fdesc)). orElse(null); } - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); + return LINKER.upcallStub(handle, fdesc, scope); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); } // Internals only below this point - private static class VarargsInvoker { + private static final class VarargsInvoker { private static final MethodHandle INVOKE_MH; private final MemorySegment symbol; private final FunctionDescriptor function; @@ -96,7 +97,9 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { mtype = mtype.appendParameterTypes(carrier(layout, false)); } mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); @@ -106,8 +109,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { static Class carrier(MemoryLayout layout, boolean ret) { if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; + return valueLayout.carrier(); } else if (layout instanceof GroupLayout) { return MemorySegment.class; } else { @@ -142,7 +144,9 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.ofVoid(argLayouts) : FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { mh = mh.bindTo(allocator); } // flatten argument list so that it can be passed to an asSpreader MH @@ -192,10 +196,7 @@ private Class normalize(Class c) { if (c.isPrimitive()) { return promote(c); } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { + if (c == MemorySegment.class) { return MemorySegment.class; } throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); @@ -206,7 +207,7 @@ private MemoryLayout variadicLayout(Class c) { return JAVA_LONG; } else if (c == double.class) { return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { + } else if (c == MemorySegment.class) { return ADDRESS; } else { throw new IllegalArgumentException("Unhandled variadic argument class: " + c); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java index 6c3f0b9f..444f9385 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java @@ -2,29 +2,37 @@ package net.codecrete.usb.windows.gen.winusb; -import java.lang.foreign.Addressable; import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class WinUSB { - /* package-private */ WinUSB() {} - public static OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + /** + * {@snippet : + * #define PIPE_TRANSFER_TIMEOUT 3 + * } + */ public static int PIPE_TRANSFER_TIMEOUT() { return (int)3L; } public static MethodHandle WinUsb_Initialize$MH() { return RuntimeHelper.requireNonNull(constants$0.WinUsb_Initialize$MH,"WinUsb_Initialize"); } - public static int WinUsb_Initialize ( Addressable DeviceHandle, Addressable InterfaceHandle) { + /** + * {@snippet : + * BOOL WinUsb_Initialize(HANDLE DeviceHandle, PWINUSB_INTERFACE_HANDLE InterfaceHandle); + * } + */ + public static int WinUsb_Initialize(MemorySegment DeviceHandle, MemorySegment InterfaceHandle) { var mh$ = WinUsb_Initialize$MH(); try { return (int)mh$.invokeExact(DeviceHandle, InterfaceHandle); @@ -35,7 +43,12 @@ public static int WinUsb_Initialize ( Addressable DeviceHandle, Addressable Int public static MethodHandle WinUsb_Free$MH() { return RuntimeHelper.requireNonNull(constants$0.WinUsb_Free$MH,"WinUsb_Free"); } - public static int WinUsb_Free ( Addressable InterfaceHandle) { + /** + * {@snippet : + * BOOL WinUsb_Free(WINUSB_INTERFACE_HANDLE InterfaceHandle); + * } + */ + public static int WinUsb_Free(MemorySegment InterfaceHandle) { var mh$ = WinUsb_Free$MH(); try { return (int)mh$.invokeExact(InterfaceHandle); @@ -46,7 +59,12 @@ public static int WinUsb_Free ( Addressable InterfaceHandle) { public static MethodHandle WinUsb_GetAssociatedInterface$MH() { return RuntimeHelper.requireNonNull(constants$0.WinUsb_GetAssociatedInterface$MH,"WinUsb_GetAssociatedInterface"); } - public static int WinUsb_GetAssociatedInterface ( Addressable InterfaceHandle, byte AssociatedInterfaceIndex, Addressable AssociatedInterfaceHandle) { + /** + * {@snippet : + * BOOL WinUsb_GetAssociatedInterface(WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR AssociatedInterfaceIndex, PWINUSB_INTERFACE_HANDLE AssociatedInterfaceHandle); + * } + */ + public static int WinUsb_GetAssociatedInterface(MemorySegment InterfaceHandle, byte AssociatedInterfaceIndex, MemorySegment AssociatedInterfaceHandle) { var mh$ = WinUsb_GetAssociatedInterface$MH(); try { return (int)mh$.invokeExact(InterfaceHandle, AssociatedInterfaceIndex, AssociatedInterfaceHandle); @@ -57,7 +75,12 @@ public static int WinUsb_GetAssociatedInterface ( Addressable InterfaceHandle, public static MethodHandle WinUsb_GetDescriptor$MH() { return RuntimeHelper.requireNonNull(constants$0.WinUsb_GetDescriptor$MH,"WinUsb_GetDescriptor"); } - public static int WinUsb_GetDescriptor ( Addressable InterfaceHandle, byte DescriptorType, byte Index, short LanguageID, Addressable Buffer, int BufferLength, Addressable LengthTransferred) { + /** + * {@snippet : + * BOOL WinUsb_GetDescriptor(WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR DescriptorType, UCHAR Index, USHORT LanguageID, PUCHAR Buffer, ULONG BufferLength, PULONG LengthTransferred); + * } + */ + public static int WinUsb_GetDescriptor(MemorySegment InterfaceHandle, byte DescriptorType, byte Index, short LanguageID, MemorySegment Buffer, int BufferLength, MemorySegment LengthTransferred) { var mh$ = WinUsb_GetDescriptor$MH(); try { return (int)mh$.invokeExact(InterfaceHandle, DescriptorType, Index, LanguageID, Buffer, BufferLength, LengthTransferred); @@ -68,7 +91,12 @@ public static int WinUsb_GetDescriptor ( Addressable InterfaceHandle, byte Desc public static MethodHandle WinUsb_SetCurrentAlternateSetting$MH() { return RuntimeHelper.requireNonNull(constants$0.WinUsb_SetCurrentAlternateSetting$MH,"WinUsb_SetCurrentAlternateSetting"); } - public static int WinUsb_SetCurrentAlternateSetting ( Addressable InterfaceHandle, byte SettingNumber) { + /** + * {@snippet : + * BOOL WinUsb_SetCurrentAlternateSetting(WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR SettingNumber); + * } + */ + public static int WinUsb_SetCurrentAlternateSetting(MemorySegment InterfaceHandle, byte SettingNumber) { var mh$ = WinUsb_SetCurrentAlternateSetting$MH(); try { return (int)mh$.invokeExact(InterfaceHandle, SettingNumber); @@ -79,7 +107,12 @@ public static int WinUsb_SetCurrentAlternateSetting ( Addressable InterfaceHandl public static MethodHandle WinUsb_SetPipePolicy$MH() { return RuntimeHelper.requireNonNull(constants$0.WinUsb_SetPipePolicy$MH,"WinUsb_SetPipePolicy"); } - public static int WinUsb_SetPipePolicy ( Addressable InterfaceHandle, byte PipeID, int PolicyType, int ValueLength, Addressable Value) { + /** + * {@snippet : + * BOOL WinUsb_SetPipePolicy(WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR PipeID, ULONG PolicyType, ULONG ValueLength, PVOID Value); + * } + */ + public static int WinUsb_SetPipePolicy(MemorySegment InterfaceHandle, byte PipeID, int PolicyType, int ValueLength, MemorySegment Value) { var mh$ = WinUsb_SetPipePolicy$MH(); try { return (int)mh$.invokeExact(InterfaceHandle, PipeID, PolicyType, ValueLength, Value); @@ -90,7 +123,12 @@ public static int WinUsb_SetPipePolicy ( Addressable InterfaceHandle, byte Pipe public static MethodHandle WinUsb_ReadPipe$MH() { return RuntimeHelper.requireNonNull(constants$1.WinUsb_ReadPipe$MH,"WinUsb_ReadPipe"); } - public static int WinUsb_ReadPipe ( Addressable InterfaceHandle, byte PipeID, Addressable Buffer, int BufferLength, Addressable LengthTransferred, Addressable Overlapped) { + /** + * {@snippet : + * BOOL WinUsb_ReadPipe(WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR PipeID, PUCHAR Buffer, ULONG BufferLength, PULONG LengthTransferred, LPOVERLAPPED Overlapped); + * } + */ + public static int WinUsb_ReadPipe(MemorySegment InterfaceHandle, byte PipeID, MemorySegment Buffer, int BufferLength, MemorySegment LengthTransferred, MemorySegment Overlapped) { var mh$ = WinUsb_ReadPipe$MH(); try { return (int)mh$.invokeExact(InterfaceHandle, PipeID, Buffer, BufferLength, LengthTransferred, Overlapped); @@ -101,7 +139,12 @@ public static int WinUsb_ReadPipe ( Addressable InterfaceHandle, byte PipeID, public static MethodHandle WinUsb_WritePipe$MH() { return RuntimeHelper.requireNonNull(constants$1.WinUsb_WritePipe$MH,"WinUsb_WritePipe"); } - public static int WinUsb_WritePipe ( Addressable InterfaceHandle, byte PipeID, Addressable Buffer, int BufferLength, Addressable LengthTransferred, Addressable Overlapped) { + /** + * {@snippet : + * BOOL WinUsb_WritePipe(WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR PipeID, PUCHAR Buffer, ULONG BufferLength, PULONG LengthTransferred, LPOVERLAPPED Overlapped); + * } + */ + public static int WinUsb_WritePipe(MemorySegment InterfaceHandle, byte PipeID, MemorySegment Buffer, int BufferLength, MemorySegment LengthTransferred, MemorySegment Overlapped) { var mh$ = WinUsb_WritePipe$MH(); try { return (int)mh$.invokeExact(InterfaceHandle, PipeID, Buffer, BufferLength, LengthTransferred, Overlapped); @@ -112,7 +155,12 @@ public static int WinUsb_WritePipe ( Addressable InterfaceHandle, byte PipeID, public static MethodHandle WinUsb_ControlTransfer$MH() { return RuntimeHelper.requireNonNull(constants$1.WinUsb_ControlTransfer$MH,"WinUsb_ControlTransfer"); } - public static int WinUsb_ControlTransfer ( Addressable InterfaceHandle, MemorySegment SetupPacket, Addressable Buffer, int BufferLength, Addressable LengthTransferred, Addressable Overlapped) { + /** + * {@snippet : + * BOOL WinUsb_ControlTransfer(WINUSB_INTERFACE_HANDLE InterfaceHandle, WINUSB_SETUP_PACKET SetupPacket, PUCHAR Buffer, ULONG BufferLength, PULONG LengthTransferred, LPOVERLAPPED Overlapped); + * } + */ + public static int WinUsb_ControlTransfer(MemorySegment InterfaceHandle, MemorySegment SetupPacket, MemorySegment Buffer, int BufferLength, MemorySegment LengthTransferred, MemorySegment Overlapped) { var mh$ = WinUsb_ControlTransfer$MH(); try { return (int)mh$.invokeExact(InterfaceHandle, SetupPacket, Buffer, BufferLength, LengthTransferred, Overlapped); @@ -123,7 +171,12 @@ public static int WinUsb_ControlTransfer ( Addressable InterfaceHandle, MemoryS public static MethodHandle WinUsb_ResetPipe$MH() { return RuntimeHelper.requireNonNull(constants$1.WinUsb_ResetPipe$MH,"WinUsb_ResetPipe"); } - public static int WinUsb_ResetPipe ( Addressable InterfaceHandle, byte PipeID) { + /** + * {@snippet : + * BOOL WinUsb_ResetPipe(WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR PipeID); + * } + */ + public static int WinUsb_ResetPipe(MemorySegment InterfaceHandle, byte PipeID) { var mh$ = WinUsb_ResetPipe$MH(); try { return (int)mh$.invokeExact(InterfaceHandle, PipeID); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java index 0845afad..95c57ad9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java @@ -4,8 +4,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -class constants$0 { +final class constants$0 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} static final FunctionDescriptor WinUsb_Initialize$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java index a085bc95..06bbbb9c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java @@ -5,8 +5,10 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.MemoryLayout; import java.lang.invoke.MethodHandle; -class constants$1 { +final class constants$1 { + // Suppresses default constructor, ensuring non-instantiability. + private constants$1() {} static final FunctionDescriptor WinUsb_ReadPipe$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_CHAR$LAYOUT, From f820aa256ca4246712ae3c82b5fbb1bcca5e0a8a Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Tue, 27 Dec 2022 15:52:22 +0100 Subject: [PATCH 169/433] Improve macOS code --- README.md | 4 +- java-does-usb/jextract/README.md | 2 +- .../usb/common/EndpointInputStream.java | 2 + .../codecrete/usb/common/ForeignMemory.java | 15 ++- .../codecrete/usb/common/ScopeCleanup.java | 2 +- .../usb/linux/LinuxUSBDeviceRegistry.java | 8 +- .../usb/macos/CoreFoundationHelper.java | 39 +++--- .../net/codecrete/usb/macos/IoKitHelper.java | 75 +++++------ .../net/codecrete/usb/macos/IoKitUSB.java | 4 +- .../codecrete/usb/macos/MacosUSBDevice.java | 123 +++++++++--------- .../usb/macos/MacosUSBDeviceRegistry.java | 95 ++++++++------ .../codecrete/usb/macos/TransferTimeout.java | 2 +- .../java/net/codecrete/usb/macos/UUID.java | 2 +- 13 files changed, 194 insertions(+), 179 deletions(-) diff --git a/README.md b/README.md index 304c1d94..166ae481 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Java Does USB: USB Library for Java +> **Development branch for JDK 20** + [![javadoc](https://javadoc.io/badge2/net.codecrete.usb/java-does-usb/javadoc.svg)](https://javadoc.io/doc/net.codecrete.usb/java-does-usb) *Java Does USB* is a library for working with USB devices. It allows to query information about all conntected USB devices and to communicate with USB devices using custom / vendor specific protocols. (It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc.) @@ -79,7 +81,7 @@ public class EnumerateDevices { ## Prerequisite -- Java 19, preview features enabled (available at https://www.azul.com/downloads/?package=jdk) +- Java 20, preview features enabled (available at https://www.azul.com/downloads/?package=jdk) - Windows (x86 64-bit), macOS (x86 64-bit, ARM 64-bit) or Linux 64 bit (x86 64-bit, ARM 64-bit) diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index cfd1632c..f89193ef 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -92,7 +92,7 @@ The known limitations are: *jextract* generates a comprehensive set of methods for each function, struct, struct member etc. Most of it will not be used as a typical application just uses a subset of struct members, might only read or write them etc. So a considerable amount of code is generated. For some types, it's a bit excessive. -The worst example is [`IOUSBInterfaceStruct942`](https://github.com/manuelbl/JavaDoesUSB/blob/main/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct942.java) (macOS). This is a `struct` consisting of about 75 member functions. It's bascially a vtable of a C++ class. *jextract* generates the same number of classes plus a huge class for the struct itself. The total code size (compiled) for this single `struct` is over 300 kByte. +The worst example is [`IOUSBInterfaceStruct100`](https://github.com/manuelbl/JavaDoesUSB/blob/main/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct100.java) (macOS). This is a `struct` consisting of about 75 member functions. It's bascially a vtable of a C++ class. *jextract* generates the same number of classes plus a huge class for the struct itself. The total code size (compiled) for this single `struct` is over 300 kByte. The table below shows statictics for version 0.2.0 of the library: diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index 2992d55d..0d829206 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -58,6 +58,7 @@ public int read(byte[] b, int off, int len) throws IOException { return n; } + @SuppressWarnings("RedundantThrows") @Override public int available() throws IOException { return (packet_ != null ? packet_.length : 0) - readOffset_; @@ -74,6 +75,7 @@ private void receiveMoreData() throws IOException { } while (packet_.length == 0); } + @SuppressWarnings("RedundantThrows") @Override public void close() throws IOException { device_ = null; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java index fc248790..c10a4fa2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java @@ -7,6 +7,7 @@ package net.codecrete.usb.common; +import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; public class ForeignMemory { @@ -17,5 +18,17 @@ public class ForeignMemory { * will have length {@code Long.MAX_VALUE}/ *

*/ - public static ValueLayout.OfAddress UNBOUNDED_ADDRESS = ValueLayout.ADDRESS.asUnbounded(); + public static final ValueLayout.OfAddress UNBOUNDED_ADDRESS = ValueLayout.ADDRESS.asUnbounded(); + + /** + * Dereferences the address at the start of the memory segment and returns the result as + * a memory segment of the specified length. + * + * @param segment the memory segment with the pointer at offset 0 + * @param byteSize the length + * @return the dereferenced memory segment + */ + public static MemorySegment deref(MemorySegment segment, long byteSize) { + return segment.get(UNBOUNDED_ADDRESS, 0).asSlice(0, byteSize); + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java index b9760bf7..d0ec9a60 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java @@ -10,7 +10,7 @@ import java.util.ArrayList; /** - * Auto closeable actions for clean up. + * Auto closeable object for clean up actions. * *

* Multiple cleanup actions can be registered and will diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index fcd87714..6c0541d2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -28,10 +28,10 @@ */ public class LinuxUSBDeviceRegistry extends USBDeviceRegistry { - private static final SegmentAllocator GLOBAL_ALLOCATOR = SegmentAllocator.nativeAllocator(SegmentScope.global()); - private static final MemorySegment SUBSYSTEM_USB = GLOBAL_ALLOCATOR.allocateUtf8String("usb"); - private static final MemorySegment MONITOR_NAME = GLOBAL_ALLOCATOR.allocateUtf8String("udev"); - private static final MemorySegment DEVTYPE_USB_DEVICE = GLOBAL_ALLOCATOR.allocateUtf8String("usb_device"); + private final SegmentAllocator GLOBAL_ALLOCATOR = SegmentAllocator.nativeAllocator(SegmentScope.global()); + private final MemorySegment SUBSYSTEM_USB = GLOBAL_ALLOCATOR.allocateUtf8String("usb"); + private final MemorySegment MONITOR_NAME = GLOBAL_ALLOCATOR.allocateUtf8String("udev"); + private final MemorySegment DEVTYPE_USB_DEVICE = GLOBAL_ALLOCATOR.allocateUtf8String("usb_device"); @Override protected void monitorDevices() { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java index c952c612..c403ede2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java @@ -12,6 +12,7 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.JAVA_CHAR; @@ -25,23 +26,18 @@ public class CoreFoundationHelper { * Gets Java string as a copy of the {@code CFStringRef}. * * @param string the string to copy ({@code CFStringRef}) + * @param arena the arena to allocate memory * @return copied string */ - public static String stringFromCFStringRef(MemorySegment string) { - - try (var arena = Arena.openConfined()) { - - long strLen = CoreFoundation.CFStringGetLength(string); - var buffer = arena.allocateArray(JAVA_CHAR, strLen); - var range = arena.allocate(CFRange.$LAYOUT()); - CFRange.location$set(range, 0); - CFRange.length$set(range, strLen); - CoreFoundation.CFStringGetCharacters(string, range, buffer); - return new String(buffer.toArray(JAVA_CHAR)); - - } catch (Throwable t) { - throw new RuntimeException(t); - } + public static String stringFromCFStringRef(MemorySegment string, Arena arena) { + + long strLen = CoreFoundation.CFStringGetLength(string); + var buffer = arena.allocateArray(JAVA_CHAR, strLen); + var range = arena.allocate(CFRange.$LAYOUT()); + CFRange.location$set(range, 0); + CFRange.length$set(range, strLen); + CoreFoundation.CFStringGetCharacters(string, range, buffer); + return new String(buffer.toArray(JAVA_CHAR)); } /** @@ -52,14 +48,13 @@ public static String stringFromCFStringRef(MemorySegment string) { *

* * @param string the string + * @param allocator the allocator for allocating memory * @return {@code CFStringRef} */ - public static MemorySegment createCFStringRef(String string) { - try (var arena = Arena.openConfined()) { - char[] charArray = string.toCharArray(); - var chars = arena.allocateArray(JAVA_CHAR, charArray.length); - chars.copyFrom(MemorySegment.ofArray(charArray)); - return CoreFoundation.CFStringCreateWithCharacters(NULL, chars, string.length()); - } + public static MemorySegment createCFStringRef(String string, SegmentAllocator allocator) { + char[] charArray = string.toCharArray(); + var chars = allocator.allocateArray(JAVA_CHAR, charArray.length); + chars.copyFrom(MemorySegment.ofArray(charArray)); + return CoreFoundation.CFStringCreateWithCharacters(NULL, chars, string.length()); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index c74d5d00..c3ebd907 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -7,12 +7,12 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; import net.codecrete.usb.macos.gen.iokit.IOKit; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentScope; import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.ADDRESS; @@ -87,28 +87,26 @@ public static MemorySegment getInterface(int service, MemorySegment pluginType, * * @param service the service * @param key the property key + * @param arena the arena for allocating memory * @return the property value, or {@code null} if the service doesn't have the property */ - public static Integer getPropertyInt(int service, String key) { + public static Integer getPropertyInt(int service, MemorySegment key, Arena arena) { - try (var cleanup = new ScopeCleanup()) { - var value = getPropertyValue(service, key, cleanup); - if (value == null) - return null; + var value = IOKit.IORegistryEntryCreateCFProperty(service, key, NULL, 0); + if (value.address() == 0) + return null; - Integer result = null; - var type = CoreFoundation.CFGetTypeID(value); - if (type == CoreFoundation.CFNumberGetTypeID()) { + Integer result = null; + var type = CoreFoundation.CFGetTypeID(value); + if (type == CoreFoundation.CFNumberGetTypeID()) { + var numberValue = arena.allocate(JAVA_INT, 0); + if (CoreFoundation.CFNumberGetValue(value, CoreFoundation.kCFNumberSInt32Type(), numberValue) != 0) + result = numberValue.get(JAVA_INT, 0); + } - try (var arena = Arena.openConfined()) { - var numberValue = arena.allocate(JAVA_INT, 0); - if (CoreFoundation.CFNumberGetValue(value, CoreFoundation.kCFNumberSInt32Type(), numberValue) != 0) - result = numberValue.get(JAVA_INT, 0); - } - } + CoreFoundation.CFRelease(value); - return result; - } + return result; } /** @@ -119,43 +117,30 @@ public static Integer getPropertyInt(int service, String key) { * * @param service the service * @param key the property key + * @param arena the arena for allocating memory * @return the property value, or {@code null} if the service doesn't have the property */ - public static String getPropertyString(int service, String key) { - - try (var cleanup = new ScopeCleanup()) { - var value = getPropertyValue(service, key, cleanup); - if (value == null) - return null; - - String result = null; - var type = CoreFoundation.CFGetTypeID(value); - if (type == CoreFoundation.CFStringGetTypeID()) - result = CoreFoundationHelper.stringFromCFStringRef(value); + public static String getPropertyString(int service, MemorySegment key, Arena arena) { - return result; - } - } - - private static MemorySegment getPropertyValue(int service, String key, ScopeCleanup cleanup) { - var cfKey = CoreFoundationHelper.createCFStringRef(key); - cleanup.add(() -> CoreFoundation.CFRelease(cfKey)); - - var value = IOKit.IORegistryEntryCreateCFProperty(service, cfKey, NULL, 0); + var value = IOKit.IORegistryEntryCreateCFProperty(service, key, NULL, 0); if (value.address() == 0) return null; - cleanup.add(() -> CoreFoundation.CFRelease(value)); - return value; + String result = null; + var type = CoreFoundation.CFGetTypeID(value); + if (type == CoreFoundation.CFStringGetTypeID()) + result = CoreFoundationHelper.stringFromCFStringRef(value, arena); + + CoreFoundation.CFRelease(value); + + return result; } // debugging aid public static int getRefCount(MemorySegment self) { - try (var arena = Arena.openConfined()) { - var object = MemorySegment.ofAddress(self.address(), 16, arena.scope()); - var dataAddr = object.get(ADDRESS, ADDRESS.byteSize()); - var data = MemorySegment.ofAddress(dataAddr.address(), 12, arena.scope()); - return data.get(JAVA_INT, 8); - } + var object = MemorySegment.ofAddress(self.address(), 16, SegmentScope.global()); + var dataAddr = object.get(ADDRESS, ADDRESS.byteSize()); + var data = MemorySegment.ofAddress(dataAddr.address(), 12, SegmentScope.global()); + return data.get(JAVA_INT, 8); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index 96bb9f33..8af9151e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -7,6 +7,7 @@ package net.codecrete.usb.macos; +import net.codecrete.usb.common.ForeignMemory; import net.codecrete.usb.macos.gen.iokit.IOUSBDeviceInterface100; import net.codecrete.usb.macos.gen.iokit.IOUSBInterfaceInterface190; @@ -14,7 +15,6 @@ import java.lang.foreign.SegmentScope; import static java.lang.foreign.ValueLayout.ADDRESS; -import static net.codecrete.usb.common.ForeignMemory.UNBOUNDED_ADDRESS; /** * Helper functions to call the virtual methods of IOKit USB interfaces. @@ -24,7 +24,7 @@ public class IoKitUSB { private static MemorySegment getVtable(MemorySegment self) { var object = MemorySegment.ofAddress(self.address(), ADDRESS.byteSize(), SegmentScope.global()); // 800: size of biggest vtable and then some - return object.get(UNBOUNDED_ADDRESS, 0).asSlice(0, 800); + return ForeignMemory.deref(object, 800); } // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index e163c4f7..7c1875df 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -11,6 +11,7 @@ import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBTimeoutException; import net.codecrete.usb.USBTransferType; +import net.codecrete.usb.common.ForeignMemory; import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.macos.gen.iokit.IOKit; @@ -26,22 +27,21 @@ import java.util.Map; import static java.lang.foreign.ValueLayout.*; -import static net.codecrete.usb.common.ForeignMemory.UNBOUNDED_ADDRESS; import static net.codecrete.usb.macos.MacosUSBException.throwException; public class MacosUSBDevice extends USBDeviceImpl { - private final MemorySegment device; + private MemorySegment device; private int configurationValue; private List claimedInterfaces; private Map endpoints; MacosUSBDevice(MemorySegment device, Object id, int vendorId, int productId) { super(id, vendorId, productId); - this.device = device; - loadDescription(); + loadDescription(device); + this.device = device; IoKitUSB.AddRef(device); } @@ -60,12 +60,13 @@ public void open() { if (ret != 0) throwException(ret, "unable to open USB device"); + claimedInterfaces = new ArrayList<>(); + // set configuration ret = IoKitUSB.SetConfiguration(device, (byte) configurationValue); if (ret != 0) throwException(ret, "failed to set configuration"); - claimedInterfaces = new ArrayList<>(); updateEndpointList(); } @@ -75,8 +76,8 @@ public void close() { return; for (InterfaceInfo interfaceInfo : claimedInterfaces) { - IoKitUSB.USBInterfaceClose(interfaceInfo.segment()); - IoKitUSB.Release(interfaceInfo.segment()); + IoKitUSB.USBInterfaceClose(interfaceInfo.iokitInterface()); + IoKitUSB.Release(interfaceInfo.iokitInterface()); setClaimed(interfaceInfo.interfaceNumber, false); } @@ -88,9 +89,10 @@ public void close() { void closeFully() { close(); IoKitUSB.Release(device); + device = null; } - private void loadDescription() { + private void loadDescription(MemorySegment device) { try (var arena = Arena.openConfined()) { configurationValue = 0; @@ -101,11 +103,9 @@ private void loadDescription() { if (ret != 0) throwException(ret, "failed to query first configuration"); - // get value of first configuration - var configDesc = descPtrHolder.get(UNBOUNDED_ADDRESS, 0); + var configDesc = ForeignMemory.deref(descPtrHolder, 999999); var configDescHeader = new ConfigurationDescriptor(configDesc); - int totalLength = configDescHeader.totalLength(); - configDesc = configDesc.asSlice(0, totalLength); + configDesc = configDesc.asSlice(0, configDescHeader.totalLength()); var configuration = setConfigurationDescriptor(configDesc); configurationValue = 255 & configuration.configValue(); @@ -114,38 +114,42 @@ private void loadDescription() { private InterfaceInfo findInterface(int interfaceNumber) { - try (var outerArena = Arena.openConfined(); var outerCleanup = new ScopeCleanup()) { - var request = outerArena.allocate(IOUSBFindInterfaceRequest.$LAYOUT()); + try (var arena = Arena.openConfined(); var outerCleanup = new ScopeCleanup()) { + var request = arena.allocate(IOUSBFindInterfaceRequest.$LAYOUT()); IOUSBFindInterfaceRequest.bInterfaceClass$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); IOUSBFindInterfaceRequest.bInterfaceSubClass$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); IOUSBFindInterfaceRequest.bInterfaceProtocol$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); IOUSBFindInterfaceRequest.bAlternateSetting$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); - var iterHolder = outerArena.allocate(JAVA_INT); + var iterHolder = arena.allocate(JAVA_INT); int ret = IoKitUSB.CreateInterfaceIterator(device, request, iterHolder); - final var iter = iterHolder.get(JAVA_INT, 0); if (ret != 0) throwException("CreateInterfaceIterator failed"); + + final var iter = iterHolder.get(JAVA_INT, 0); outerCleanup.add(() -> IOKit.IOObjectRelease(iter)); + var intfNumberHolder = arena.allocate(JAVA_INT); + int service; while ((service = IOKit.IOIteratorNext(iter)) != 0) { - try (var arena = Arena.openConfined(); var cleanup = new ScopeCleanup()) { + try (var cleanup = new ScopeCleanup()) { final int service_final = service; cleanup.add(() -> IOKit.IOObjectRelease(service_final)); final var intf = IoKitHelper.getInterface(service, IoKitHelper.kIOUSBInterfaceUserClientTypeID, IoKitHelper.kIOUSBInterfaceInterfaceID100); - if (intf == null) continue; + if (intf == null) + continue; + + cleanup.add(() -> IoKitUSB.Release(intf)); - var intfNumberHolder = arena.allocate(JAVA_INT); IoKitUSB.GetInterfaceNumber(intf, intfNumberHolder); - if (intfNumberHolder.get(JAVA_INT, 0) != interfaceNumber) { - IoKitUSB.Release(intf); + if (intfNumberHolder.get(JAVA_INT, 0) != interfaceNumber) continue; - } + IoKitUSB.AddRef(intf); return new InterfaceInfo(intf, interfaceNumber); } } @@ -158,21 +162,20 @@ private InterfaceInfo findInterface(int interfaceNumber) { public void claimInterface(int interfaceNumber) { checkIsOpen(); - var interfaceInfo = findInterface(interfaceNumber); + try (var cleanup = new ScopeCleanup()) { + + var interfaceInfo = findInterface(interfaceNumber); + cleanup.add(() -> IoKitUSB.Release(interfaceInfo.iokitInterface())); - try { - var ret = IoKitUSB.USBInterfaceOpen(interfaceInfo.segment()); + var ret = IoKitUSB.USBInterfaceOpen(interfaceInfo.iokitInterface()); if (ret != 0) throwException(ret, "Failed to claim interface"); - setClaimed(interfaceNumber, true); - } catch (Throwable t) { - IoKitUSB.Release(interfaceInfo.segment()); - throw t; + IoKitUSB.AddRef(interfaceInfo.iokitInterface()); + claimedInterfaces.add(interfaceInfo); + setClaimed(interfaceNumber, true); } - claimedInterfaces.add(interfaceInfo); - updateEndpointList(); } @@ -192,7 +195,7 @@ public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { var intfInfo = claimedInterfaces.stream() .filter((interf) -> interf.interfaceNumber() == interfaceNumber).findFirst().get(); - int ret = IoKitUSB.SetAlternateInterface(intfInfo.segment(), (byte) alternateNumber); + int ret = IoKitUSB.SetAlternateInterface(intfInfo.iokitInterface(), (byte) alternateNumber); if (ret != 0) throwException(ret, "Failed to set alternate interface"); @@ -210,12 +213,12 @@ public void releaseInterface(int interfaceNumber) { var interfaceInfo = interfaceInfoOptional.get(); - int ret = IoKitUSB.USBInterfaceClose(interfaceInfo.segment()); + int ret = IoKitUSB.USBInterfaceClose(interfaceInfo.iokitInterface()); if (ret != 0) throwException(ret, "Failed to release interface"); claimedInterfaces.remove(interfaceInfo); - IoKitUSB.Release(interfaceInfo.segment()); + IoKitUSB.Release(interfaceInfo.iokitInterface()); setClaimed(interfaceNumber, false); updateEndpointList(); @@ -231,10 +234,17 @@ public void releaseInterface(int interfaceNumber) { private void updateEndpointList() { endpoints = new HashMap<>(); - for (InterfaceInfo interfaceInfo : claimedInterfaces) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.openConfined()) { + + var directionHolder = arena.allocate(JAVA_BYTE); + var numberHolder = arena.allocate(JAVA_BYTE); + var transferTypeHolder = arena.allocate(JAVA_BYTE); + var maxPacketSizeHolder = arena.allocate(JAVA_SHORT); + var intervalHolder = arena.allocate(JAVA_BYTE); - var intf = interfaceInfo.segment(); + for (InterfaceInfo interfaceInfo : claimedInterfaces) { + + var intf = interfaceInfo.iokitInterface(); var numEndpointsHolder = arena.allocate(JAVA_BYTE); int ret = IoKitUSB.GetNumEndpoints(intf, numEndpointsHolder); if (ret != 0) @@ -243,12 +253,6 @@ private void updateEndpointList() { for (int pipeIndex = 1; pipeIndex <= numEndpoints; pipeIndex++) { - var directionHolder = arena.allocate(JAVA_BYTE); - var numberHolder = arena.allocate(JAVA_BYTE); - var transferTypeHolder = arena.allocate(JAVA_BYTE); - var maxPacketSizeHolder = arena.allocate(JAVA_SHORT); - var intervalHolder = arena.allocate(JAVA_BYTE); - ret = IoKitUSB.GetPipeProperties(intf, (byte) pipeIndex, directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); if (ret != 0) @@ -259,7 +263,7 @@ private void updateEndpointList() { byte endpointAddress = (byte) (endpointNumber | (direction << 7)); byte transferType = transferTypeHolder.get(JAVA_BYTE, 0); int maxPacketSize = maxPacketSizeHolder.get(JAVA_SHORT, 0) & 0xffff; - var endpointInfo = new EndpointInfo(interfaceInfo.segment(), (byte) pipeIndex, + var endpointInfo = new EndpointInfo(interfaceInfo.iokitInterface(), (byte) pipeIndex, getTransferType(transferType), maxPacketSize); endpoints.put(endpointAddress, endpointInfo); } @@ -327,12 +331,13 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { try (var arena = Arena.openConfined()) { int dataLength = data != null ? data.length : 0; var dataSegment = arena.allocate(dataLength); - if (dataLength > 0) dataSegment.copyFrom(MemorySegment.ofArray(data)); + if (dataLength > 0) + dataSegment.copyFrom(MemorySegment.ofArray(data)); var deviceRequest = createDeviceRequest(arena, USBDirection.OUT, setup, dataSegment); int ret = IoKitUSB.DeviceRequest(device, deviceRequest); if (ret != 0) - throwException(ret, "Control IN transfer failed"); + throwException(ret, "Control OUT transfer failed"); } } @@ -345,16 +350,16 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { try (var arena = Arena.openConfined()) { var nativeData = arena.allocateArray(JAVA_BYTE, data.length); nativeData.copyFrom(MemorySegment.ofArray(data)); - int ret; + int ret; if (timeout <= 0) { // transfer without timeout - ret = IoKitUSB.WritePipe(endpointInfo.segment(), endpointInfo.pipeIndex, nativeData, data.length); + ret = IoKitUSB.WritePipe(endpointInfo.iokitInterface(), endpointInfo.pipeIndex, nativeData, data.length); } else if (endpointInfo.transferType == USBTransferType.BULK) { // bulk transfer with timeout - ret = IoKitUSB.WritePipeTO(endpointInfo.segment(), endpointInfo.pipeIndex, nativeData, + ret = IoKitUSB.WritePipeTO(endpointInfo.iokitInterface(), endpointInfo.pipeIndex, nativeData, data.length, timeout, timeout); if (ret == IOKit.kIOUSBTransactionTimeout()) throw new USBTimeoutException("Transfer out aborted due to timeout"); @@ -363,7 +368,7 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { // interrupt transfer with timeout var transferTimeout = new TransferTimeout(endpointInfo, timeout); - ret = IoKitUSB.WritePipe(endpointInfo.segment(), endpointInfo.pipeIndex, nativeData, data.length); + ret = IoKitUSB.WritePipe(endpointInfo.iokitInterface(), endpointInfo.pipeIndex, nativeData, data.length); if (ret == IOKit.kIOReturnAborted()) throw new USBTimeoutException("Transfer out aborted due to timeout"); transferTimeout.markCompleted(); @@ -387,12 +392,12 @@ public byte[] transferIn(int endpointNumber, int timeout) { if (timeout <= 0) { // transfer without timeout - ret = IoKitUSB.ReadPipe(endpoint.segment(), endpoint.pipeIndex, nativeData, sizeHolder); + ret = IoKitUSB.ReadPipe(endpoint.iokitInterface(), endpoint.pipeIndex, nativeData, sizeHolder); } else if (endpoint.transferType == USBTransferType.BULK) { // bulk transfer with timeout - ret = IoKitUSB.ReadPipeTO(endpoint.segment(), endpoint.pipeIndex, nativeData, + ret = IoKitUSB.ReadPipeTO(endpoint.iokitInterface(), endpoint.pipeIndex, nativeData, sizeHolder, timeout, timeout); if (ret == IOKit.kIOUSBTransactionTimeout()) throw new USBTimeoutException("Transfer in aborted due to timeout"); @@ -401,7 +406,7 @@ public byte[] transferIn(int endpointNumber, int timeout) { // interrupt transfer with timeout var transferTimeout = new TransferTimeout(endpoint, timeout); - ret = IoKitUSB.ReadPipe(endpoint.segment(), endpoint.pipeIndex, nativeData, sizeHolder); + ret = IoKitUSB.ReadPipe(endpoint.iokitInterface(), endpoint.pipeIndex, nativeData, sizeHolder); if (ret == IOKit.kIOReturnAborted()) throw new USBTimeoutException("Transfer in aborted due to timeout"); transferTimeout.markCompleted(); @@ -410,11 +415,7 @@ public byte[] transferIn(int endpointNumber, int timeout) { throwException(ret, "Receiving data from endpoint %d failed", endpointNumber); int size = sizeHolder.get(JAVA_INT, 0); - var result = new byte[size]; - var resultSegment = MemorySegment.ofArray(result); - resultSegment.copyFrom(nativeData.asSlice(0, size)); - - return result; + return nativeData.asSlice(0, size).toArray(JAVA_BYTE); } } @@ -423,7 +424,7 @@ public void clearHalt(USBDirection direction, int endpointNumber) { var endpointInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); - int ret = IoKitUSB.ClearPipeStallBothEnds(endpointInfo.segment(), endpointInfo.pipeIndex); + int ret = IoKitUSB.ClearPipeStallBothEnds(endpointInfo.iokitInterface(), endpointInfo.pipeIndex); if (ret != 0) throwException(ret, "Clearing halt condition failed"); } @@ -437,9 +438,9 @@ private static USBTransferType getTransferType(byte macosTransferType) { }; } - record InterfaceInfo(MemorySegment segment, int interfaceNumber) { + record InterfaceInfo(MemorySegment iokitInterface, int interfaceNumber) { } - record EndpointInfo(MemorySegment segment, byte pipeIndex, USBTransferType transferType, int packetSize) { + record EndpointInfo(MemorySegment iokitInterface, byte pipeIndex, USBTransferType transferType, int packetSize) { } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index adcb8809..ae157a21 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -29,6 +29,20 @@ */ public class MacosUSBDeviceRegistry extends USBDeviceRegistry { + private final SegmentAllocator GLOBAL_ALLOCATOR = SegmentAllocator.nativeAllocator(SegmentScope.global()); + + private final MemorySegment KEY_ID_VENDOR = CoreFoundationHelper.createCFStringRef("idVendor", GLOBAL_ALLOCATOR); + private final MemorySegment KEY_ID_PRODUCT = CoreFoundationHelper.createCFStringRef("idProduct", GLOBAL_ALLOCATOR); + private final MemorySegment KEY_VENDOR = CoreFoundationHelper.createCFStringRef("kUSBVendorString", GLOBAL_ALLOCATOR); + private final MemorySegment KEY_PRODUCT = CoreFoundationHelper.createCFStringRef("kUSBProductString", GLOBAL_ALLOCATOR); + private final MemorySegment KEY_SERIAL_NUM = CoreFoundationHelper.createCFStringRef("kUSBSerialNumberString", GLOBAL_ALLOCATOR); + private final MemorySegment KEY_DEVICE_CLASS = CoreFoundationHelper.createCFStringRef("bDeviceClass", GLOBAL_ALLOCATOR); + private final MemorySegment KEY_DEVICE_SUBCLASS = CoreFoundationHelper.createCFStringRef("bDeviceSubClass", GLOBAL_ALLOCATOR); + private final MemorySegment KEY_DEVICE_PROTOCOL = CoreFoundationHelper.createCFStringRef("bDeviceProtocol", GLOBAL_ALLOCATOR); + private final MemorySegment KEY_USB_BCD = CoreFoundationHelper.createCFStringRef("bcdUSB", GLOBAL_ALLOCATOR); + private final MemorySegment KEY_DEVICE_BCD = CoreFoundationHelper.createCFStringRef("bcdDevice", GLOBAL_ALLOCATOR); + + /** * Monitors the USB devices. *

@@ -87,28 +101,29 @@ protected void monitorDevices() { */ private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { - int svc; - while ((svc = IOKit.IOIteratorNext(iterator)) != 0) { - try (var arena = Arena.openConfined(); var cleanup = new ScopeCleanup()) { + try (var arena = Arena.openConfined()) { + var entryIdHolder = arena.allocate(JAVA_LONG); - final int service = svc; - cleanup.add(() -> IOKit.IOObjectRelease(service)); + int svc; + while ((svc = IOKit.IOIteratorNext(iterator)) != 0) { + try (var cleanup = new ScopeCleanup()) { - var device = IoKitHelper.getInterface(service, IoKitHelper.kIOUSBDeviceUserClientTypeID, - IoKitHelper.kIOUSBDeviceInterfaceID100); + final int service = svc; + cleanup.add(() -> IOKit.IOObjectRelease(service)); - if (device != null) - cleanup.add(() -> IoKitUSB.Release(device)); + var device = IoKitHelper.getInterface(service, IoKitHelper.kIOUSBDeviceUserClientTypeID, IoKitHelper.kIOUSBDeviceInterfaceID100); + if (device != null) + cleanup.add(() -> IoKitUSB.Release(device)); - // get entry ID (as unique ID) - var entryIdHolder = arena.allocate(JAVA_LONG); - int ret = IOKit.IORegistryEntryGetRegistryEntryID(service, entryIdHolder); - if (ret != 0) - throwException(ret, "IORegistryEntryGetRegistryEntryID failed"); - var entryId = entryIdHolder.get(JAVA_LONG, 0); + // get entry ID (as unique ID) + int ret = IOKit.IORegistryEntryGetRegistryEntryID(service, entryIdHolder); + if (ret != 0) + throwException(ret, "IORegistryEntryGetRegistryEntryID failed"); + var entryId = entryIdHolder.get(JAVA_LONG, 0); - // call consumer to process device - consumer.accept(entryId, service, device); + // call consumer to process device + consumer.accept(entryId, service, device); + } } } } @@ -144,35 +159,37 @@ private USBDevice createDevice(Long entryID, int service, MemorySegment deviceIn if (deviceIntf == null) return null; - Integer vendorId = IoKitHelper.getPropertyInt(service, "idVendor"); - Integer productId = IoKitHelper.getPropertyInt(service, "idProduct"); - if (vendorId == null || productId == null) - return null; + try (var arena = Arena.openConfined()) { - info.vid = vendorId; - info.pid = productId; + Integer vendorId = IoKitHelper.getPropertyInt(service, KEY_ID_VENDOR, arena); + Integer productId = IoKitHelper.getPropertyInt(service, KEY_ID_PRODUCT, arena); + if (vendorId == null || productId == null) + return null; - var device = new MacosUSBDevice(deviceIntf, entryID, vendorId, productId); + info.vid = vendorId; + info.pid = productId; - String manufacturer = IoKitHelper.getPropertyString(service, "kUSBVendorString"); - String product = IoKitHelper.getPropertyString(service, "kUSBProductString"); - String serial = IoKitHelper.getPropertyString(service, "kUSBSerialNumberString"); + var device = new MacosUSBDevice(deviceIntf, entryID, vendorId, productId); - device.setProductStrings(manufacturer, product, serial); + String manufacturer = IoKitHelper.getPropertyString(service, KEY_VENDOR, arena); + String product = IoKitHelper.getPropertyString(service, KEY_PRODUCT, arena); + String serial = IoKitHelper.getPropertyString(service, KEY_SERIAL_NUM, arena); - Integer classCode = IoKitHelper.getPropertyInt(service, "bDeviceClass"); - Integer subclassCode = IoKitHelper.getPropertyInt(service, "bDeviceSubClass"); - Integer protocolCode = IoKitHelper.getPropertyInt(service, "bDeviceProtocol"); + device.setProductStrings(manufacturer, product, serial); - device.setClassCodes(classCode != null ? classCode : 0, subclassCode != null ? subclassCode : 0, - protocolCode != null ? protocolCode : 0); + Integer classCode = IoKitHelper.getPropertyInt(service, KEY_DEVICE_CLASS, arena); + Integer subclassCode = IoKitHelper.getPropertyInt(service, KEY_DEVICE_SUBCLASS, arena); + Integer protocolCode = IoKitHelper.getPropertyInt(service, KEY_DEVICE_PROTOCOL, arena); - Integer usbVersion = IoKitHelper.getPropertyInt(service, "bcdUSB"); - Integer deviceVersion = IoKitHelper.getPropertyInt(service, "bcdDevice"); - //noinspection ConstantConditions - device.setVersions(usbVersion, deviceVersion != null ? deviceVersion : 0); + device.setClassCodes(classCode != null ? classCode : 0, subclassCode != null ? subclassCode : 0, protocolCode != null ? protocolCode : 0); - return device; + Integer usbVersion = IoKitHelper.getPropertyInt(service, KEY_USB_BCD, arena); + Integer deviceVersion = IoKitHelper.getPropertyInt(service, KEY_DEVICE_BCD, arena); + //noinspection DataFlowIssue + device.setVersions(usbVersion, deviceVersion != null ? deviceVersion : 0); + + return device; + } } private int setupNotification(Arena arena, MemorySegment notifyPort, MemorySegment notificationType, @@ -220,7 +237,7 @@ private void onDevicesConnected(MemorySegment ignoredRefCon, int iterator) { * @param ignoredRefCon ignored parameter * @param iterator device iterator */ - private void onDevicesDisconnected(MemorySegment ignoredRefCon, int iterator) { + private void onDevicesDisconnected(@SuppressWarnings("SameParameterValue") MemorySegment ignoredRefCon, int iterator) { // process device iterator for disconnected devices iterateDevices(iterator, (entryId, service, deviceIntf) -> { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java index 4343871c..9abe7cc2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java @@ -38,7 +38,7 @@ class TransferTimeout { private synchronized void abort() { if (completed) return; - int ret = IoKitUSB.AbortPipe(endpointInfo.segment(), endpointInfo.pipeIndex()); + int ret = IoKitUSB.AbortPipe(endpointInfo.iokitInterface(), endpointInfo.pipeIndex()); if (ret != 0) throwException(ret, "Failed to abort USB transfer after timeout"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java index dfc7678a..bf40c7c1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java @@ -27,7 +27,7 @@ public class UUID { public static MemorySegment CreateCFUUID(byte[] bytes) { try (var arena = Arena.openConfined()) { var uuidBytes = arena.allocate(16); - uuidBytes.asByteBuffer().put(bytes); + uuidBytes.copyFrom(MemorySegment.ofArray(bytes)); return CoreFoundation.CFUUIDCreateFromUUIDBytes(NULL, uuidBytes); } catch (Throwable t) { throw new RuntimeException(t); From 2e1ec089d28995f94151acab7a03432a2694b44b Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 27 Dec 2022 21:49:59 +0100 Subject: [PATCH 170/433] Improve/simplify Linux code --- java-does-usb/jextract/linux/gen_linux.sh | 9 - .../usb/common/ConfigurationParser.java | 7 +- .../main/java/net/codecrete/usb/linux/IO.java | 60 ++++- .../codecrete/usb/linux/LinuxUSBDevice.java | 74 +++--- .../usb/linux/LinuxUSBDeviceRegistry.java | 29 +-- .../usb/linux/LinuxUSBException.java | 10 +- .../usb/linux/gen/errno/constants$0.java | 18 -- .../codecrete/usb/linux/gen/errno/errno.java | 19 -- .../usb/linux/gen/fcntl/constants$0.java | 21 -- .../codecrete/usb/linux/gen/fcntl/fcntl.java | 19 -- .../usb/linux/gen/ioctl/Constants$root.java | 21 -- .../usb/linux/gen/ioctl/RuntimeHelper.java | 217 ------------------ .../usb/linux/gen/ioctl/constants$0.java | 21 -- .../codecrete/usb/linux/gen/ioctl/ioctl.java | 36 --- .../usbstandard/ConfigurationDescriptor.java | 2 +- .../usb/usbstandard/DeviceDescriptor.java | 8 +- .../usb/usbstandard/EndpointDescriptor.java | 4 + .../InterfaceAssociationDescriptor.java | 4 + .../usb/usbstandard/InterfaceDescriptor.java | 4 + 19 files changed, 131 insertions(+), 452 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/Constants$root.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/ioctl.java diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index 87af35ea..efa5dc6e 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -14,7 +14,6 @@ JEXTRACT=../../../../jextract/build/jextract/bin/jextract $JEXTRACT --source --output ../../src/main/java \ --header-class-name errno \ --target-package net.codecrete.usb.linux.gen.errno \ - --include-function __errno_location \ --include-constant ETIMEDOUT \ --include-constant EPIPE \ /usr/include/errno.h @@ -26,18 +25,10 @@ $JEXTRACT --source --output ../../src/main/java \ --include-function strerror \ /usr/include/string.h -# ioctl.h -$JEXTRACT --source --output ../../src/main/java \ - --header-class-name ioctl \ - --target-package net.codecrete.usb.linux.gen.ioctl \ - --include-function ioctl \ - /usr/include/x86_64-linux-gnu/sys/ioctl.h - # fcntl.h $JEXTRACT --source --output ../../src/main/java \ --header-class-name fcntl \ --target-package net.codecrete.usb.linux.gen.fcntl \ - --include-function open \ --include-constant O_CLOEXEC \ --include-constant O_RDWR \ /usr/include/fcntl.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java index 6d3433c2..7063962e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java @@ -107,7 +107,7 @@ private void parseHeader() { } private USBInterfaceImpl parseInterface(int offset) { - var desc = new InterfaceDescriptor(descriptor.asSlice(offset, InterfaceDescriptor.LAYOUT.byteSize())); + var desc = new InterfaceDescriptor(descriptor, offset); var alternate = new USBAlternateInterfaceImpl(desc.alternateSetting(), desc.interfaceClass(), desc.interfaceSubClass(), desc.interfaceProtocol(), new ArrayList<>()); var alternates = new ArrayList(); @@ -116,15 +116,14 @@ private USBInterfaceImpl parseInterface(int offset) { } private void parseIAD(int offset) { - var desc = new InterfaceAssociationDescriptor( - descriptor.asSlice(offset, InterfaceAssociationDescriptor.LAYOUT.byteSize())); + var desc = new InterfaceAssociationDescriptor(descriptor, offset); var function = new CompositeFunction(desc.firstInterface(), desc.interfaceCount(), desc.functionClass(), desc.functionSubClass(), desc.functionProtocol()); configuration.addFunction(function); } private USBEndpointImpl parseEndpoint(int offset) { - var desc = new EndpointDescriptor(descriptor.asSlice(offset, EndpointDescriptor.LAYOUT.byteSize())); + var desc = new EndpointDescriptor(descriptor, offset); var address = desc.endpointAddress(); return new USBEndpointImpl(getEndpointNumber(address), getEndpointDirection(address), getEndpointType(desc.attributes()), desc.maxPacketSize()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java index 54c308b7..9b597ed9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java @@ -7,13 +7,65 @@ package net.codecrete.usb.linux; -import net.codecrete.usb.linux.gen.errno.errno; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; -import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.*; public class IO { - public static int getErrno() { - return errno.__errno_location().get(JAVA_INT, 0); + /** + * Call state for capturing the {@code errno} value. + */ + public static final Linker.Option.CaptureCallState ERRNO_STATE = Linker.Option.captureCallState("errno"); + + private static final VarHandle callState_errno$VH = ERRNO_STATE.layout().varHandle(MemoryLayout.PathElement.groupElement("errno")); + + private static final Linker linker = Linker.nativeLinker(); + private static final FunctionDescriptor ioctl$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_LONG, ADDRESS); + private static final MethodHandle ioctl$MH = linker.downcallHandle(linker.defaultLookup().find("ioctl").get(), ioctl$FUNC, ERRNO_STATE); + private static final FunctionDescriptor open$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT); + private static final MethodHandle open$MH = linker.downcallHandle(linker.defaultLookup().find("open").get(), open$FUNC, ERRNO_STATE); + + /** + * {@snippet lang=c : + * int ioctl(int fd, unsigned long request, ...); + * } + */ + public static int ioctl(int fd, long request, MemorySegment segment, MemorySegment errno) { + try { + return (int)ioctl$MH.invokeExact(errno, fd, request, segment); + } catch (Throwable ex) { + throw new AssertionError("should not reach here", ex); + } + } + + /** + * {@snippet lang=c : + * int open(char* file, int oflag, ...); + * } + */ + public static int open(MemorySegment file, int oflag, MemorySegment errno) { + try { + return (int)open$MH.invokeExact(errno, file, oflag); + } catch (Throwable ex) { + throw new AssertionError("should not reach here", ex); + } + } + + /** + * Gets the error code from the memory segment. + *

+ * The memory segment is assumed to have the layout {@link #ERRNO_STATE}. + *

+ * @param errno memory segment with error code + * @return error code + */ + public static int getErrno(MemorySegment errno) { + return (int) callState_errno$VH.get(errno); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 22e8cc30..43cf8cca 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -12,7 +12,6 @@ import net.codecrete.usb.common.USBInterfaceImpl; import net.codecrete.usb.linux.gen.errno.errno; import net.codecrete.usb.linux.gen.fcntl.fcntl; -import net.codecrete.usb.linux.gen.ioctl.ioctl; import net.codecrete.usb.linux.gen.unistd.unistd; import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_bulktransfer; import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_ctrltransfer; @@ -49,21 +48,9 @@ private void loadDescription(String path) { // `descriptors` contains the device descriptor followed by the configuration descriptor // (including the interface descriptors, endpoint descriptors etc.) - - try (var arena = Arena.openConfined()) { - var descriptorsSegment = MemorySegment.ofArray(descriptors); - - // split off device descriptor (and copy it to fix alignment issues) - var deviceDesc = arena.allocate(DeviceDescriptor.LAYOUT); - deviceDesc.copyFrom(descriptorsSegment.asSlice(0, DeviceDescriptor.LAYOUT.byteSize())); - - setFromDeviceDescriptor(deviceDesc); - - // skip to configuration descriptor - var configDesc = arena.allocateArray(JAVA_BYTE, descriptors.length - 18); - configDesc.copyFrom(descriptorsSegment.asSlice(DeviceDescriptor.LAYOUT.byteSize())); - setConfigurationDescriptor(configDesc); - } + var descriptorsSegment = MemorySegment.ofArray(descriptors); + setFromDeviceDescriptor(descriptorsSegment); + setConfigurationDescriptor(descriptorsSegment.asSlice(DeviceDescriptor.LAYOUT.byteSize())); } @Override @@ -78,9 +65,10 @@ public void open() { try (var arena = Arena.openConfined()) { var pathUtf8 = arena.allocateUtf8String(id_.toString()); - fd = fcntl.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC()); + var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + fd = IO.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC(), errnoState); if (fd == -1) - throwLastError("Cannot open USB device"); + throwLastError(errnoState, "Cannot open USB device"); } } @@ -107,9 +95,10 @@ public void claimInterface(int interfaceNumber) { try (var arena = Arena.openConfined()) { var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); - int ret = ioctl.ioctl(fd, USBDevFS.CLAIMINTERFACE, intfNumSegment.address()); + var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + int ret = IO.ioctl(fd, USBDevFS.CLAIMINTERFACE, intfNumSegment, errnoState); if (ret != 0) - throwLastError("Cannot claim USB interface"); + throwLastError(errnoState, "Cannot claim USB interface"); setClaimed(interfaceNumber, true); } } @@ -133,9 +122,10 @@ public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { var setIntfSegment = arena.allocate(usbdevfs_setinterface.$LAYOUT()); usbdevfs_setinterface.interface_$set(setIntfSegment, interfaceNumber); usbdevfs_setinterface.altsetting$set(setIntfSegment, alternateNumber); - int ret = ioctl.ioctl(fd, USBDevFS.SETINTERFACE, setIntfSegment.address()); + var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + int ret = IO.ioctl(fd, USBDevFS.SETINTERFACE, setIntfSegment, errnoState); if (ret != 0) - throwLastError("Failed to set alternate interface"); + throwLastError(errnoState, "Failed to set alternate interface"); } intf.setAlternate(altSetting); @@ -152,9 +142,10 @@ public void releaseInterface(int interfaceNumber) { try (var arena = Arena.openConfined()) { var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); - int ret = ioctl.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment.address()); + var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + int ret = IO.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment, errnoState); if (ret != 0) - throwLastError("Cannot release USB interface"); + throwLastError(errnoState, "Cannot release USB interface"); setClaimed(interfaceNumber, false); } } @@ -179,9 +170,10 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { var data = arena.allocate(length); var ctrlTransfer = createCtrlTransfer(arena, USBDirection.IN, setup, data); - int res = ioctl.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer.address()); + var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + int res = IO.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer, errnoState); if (res < 0) - throwLastError("Control IN transfer failed"); + throwLastError(errnoState, "Control IN transfer failed"); return data.asSlice(0, res).toArray(JAVA_BYTE); } @@ -196,9 +188,10 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { buffer.copyFrom(MemorySegment.ofArray(data)); var ctrlTransfer = createCtrlTransfer(arena, USBDirection.OUT, setup, buffer); - int res = ioctl.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer.address()); + var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + int res = IO.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer, errnoState); if (res < 0) - throwLastError("Control OUT transfer failed"); + throwLastError(errnoState, "Control OUT transfer failed"); } } @@ -221,15 +214,13 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { buffer.copyFrom(MemorySegment.ofArray(data)); var transfer = createBulkTransfer(arena, endpointAddress, buffer, timeout); - int res = ioctl.ioctl(fd, USBDevFS.BULK, transfer.address()); + var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + int res = IO.ioctl(fd, USBDevFS.BULK, transfer, errnoState); if (res < 0) { - int err = IO.getErrno(); + int err = IO.getErrno(errnoState); if (err == errno.ETIMEDOUT()) throw new USBTimeoutException("Transfer out aborted due to timeout"); - // TODO: remove below code if 'errno' is no longer overwritten by JVM - if (err == 2) - throw new USBTimeoutException("Transfer in aborted due to timeout"); - throwException(err, "USB OUT transfer on endpoint %d failed", endpointNumber); + throwLastError(errnoState, "USB OUT transfer on endpoint %d failed", endpointNumber); } } } @@ -244,15 +235,13 @@ public byte[] transferIn(int endpointNumber, int timeout) { var transfer = createBulkTransfer(arena, endpoint.endpointAddress(), buffer, timeout); - int res = ioctl.ioctl(fd, USBDevFS.BULK, transfer.address()); + var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + int res = IO.ioctl(fd, USBDevFS.BULK, transfer, errnoState); if (res < 0) { - int err = IO.getErrno(); + int err = IO.getErrno(errnoState); if (err == errno.ETIMEDOUT()) throw new USBTimeoutException("Transfer in aborted due to timeout"); - // TODO: remove below code if 'errno' is no longer overwritten by JVM - if (err == 2) - throw new USBTimeoutException("Transfer in aborted due to timeout"); - throwException(err, "USB IN transfer on endpoint %d failed", endpointNumber); + throwLastError(errnoState, "USB IN transfer on endpoint %d failed", endpointNumber); } return buffer.asSlice(0, res).toArray(JAVA_BYTE); @@ -266,9 +255,10 @@ public void clearHalt(USBDirection direction, int endpointNumber) { try (var arena = Arena.openConfined()) { var endpointAddrSegment = arena.allocate(JAVA_INT, endpointAddress & 0xff); - int res = ioctl.ioctl(fd, USBDevFS.CLEAR_HALT, endpointAddrSegment.address()); + var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + int res = IO.ioctl(fd, USBDevFS.CLEAR_HALT, endpointAddrSegment, errnoState); if (res < 0) - throwLastError("Clearing halt failed"); + throwLastError(errnoState, "Clearing halt failed"); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 6c0541d2..3063e054 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -33,6 +33,12 @@ public class LinuxUSBDeviceRegistry extends USBDeviceRegistry { private final MemorySegment MONITOR_NAME = GLOBAL_ALLOCATOR.allocateUtf8String("udev"); private final MemorySegment DEVTYPE_USB_DEVICE = GLOBAL_ALLOCATOR.allocateUtf8String("usb_device"); + private final MemorySegment ATTR_ID_VENDOR = GLOBAL_ALLOCATOR.allocateUtf8String("idVendor"); + private final MemorySegment ATTR_ID_PRODUCT = GLOBAL_ALLOCATOR.allocateUtf8String("idProduct"); + private final MemorySegment ATTR_MANUFACTURER = GLOBAL_ALLOCATOR.allocateUtf8String("manufacturer"); + private final MemorySegment ATTR_PRODUCT = GLOBAL_ALLOCATOR.allocateUtf8String("product"); + private final MemorySegment ATTR_SERIAL = GLOBAL_ALLOCATOR.allocateUtf8String("serial"); + @Override protected void monitorDevices() { @@ -167,18 +173,18 @@ private void onDeviceDisconnected(MemorySegment udevDevice) { * @param udevDevice the device (udev_device*) * @return the device instance */ - private static USBDevice getDeviceDetails(MemorySegment udevDevice) { + private USBDevice getDeviceDetails(MemorySegment udevDevice) { int vendorId = 0; int productId = 0; try { // retrieve device attributes - String idVendor = getDeviceAttribute(udevDevice, "idVendor"); + String idVendor = getDeviceAttribute(udevDevice, ATTR_ID_VENDOR); if (idVendor == null) return null; - String idProduct = getDeviceAttribute(udevDevice, "idProduct"); + String idProduct = getDeviceAttribute(udevDevice, ATTR_ID_PRODUCT); if (idProduct == null) return null; @@ -193,8 +199,8 @@ private static USBDevice getDeviceDetails(MemorySegment udevDevice) { // create device instance var device = new LinuxUSBDevice(devPath, vendorId, productId); - device.setProductStrings(getDeviceAttribute(udevDevice, "manufacturer"), - getDeviceAttribute(udevDevice, "product"), getDeviceAttribute(udevDevice, "serial")); + device.setProductStrings(getDeviceAttribute(udevDevice, ATTR_MANUFACTURER), + getDeviceAttribute(udevDevice, ATTR_PRODUCT), getDeviceAttribute(udevDevice, ATTR_SERIAL)); return device; @@ -206,15 +212,12 @@ private static USBDevice getDeviceDetails(MemorySegment udevDevice) { } } - private static String getDeviceAttribute(MemorySegment udevDevice, String attribute) { - try (var arena = Arena.openConfined()) { - var sysattr = arena.allocateUtf8String(attribute); - var value = udev.udev_device_get_sysattr_value(udevDevice, sysattr); - if (value.address() == 0) - return null; + private static String getDeviceAttribute(MemorySegment udevDevice, MemorySegment attribute) { + var value = udev.udev_device_get_sysattr_value(udevDevice, attribute); + if (value.address() == 0) + return null; - return value.getUtf8String(0); - } + return value.getUtf8String(0); } private static String getDeviceName(MemorySegment udevDevice) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java index dd1c061c..88eff822 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java @@ -10,6 +10,8 @@ import net.codecrete.usb.USBStallException; import net.codecrete.usb.linux.gen.errno.errno; +import java.lang.foreign.MemorySegment; + /** * Exception thrown if a Linux specific error occurs. */ @@ -57,13 +59,15 @@ static void throwException(String message, Object... args) { /** * Throws an exception for the last error. *

- * The message of the last Linux error code is looked ({@code errno}) up and appended to the message. + * The message of the last Linux error code is provided in a memory segment with the layout + * {@link IO#ERRNO_STATE}. *

+ * @param errno segment with lat error code * @param message exception message format ({@link String#format(String, Object...)} style) * @param args arguments for exception message */ - static void throwLastError(String message, Object... args) { - throwException(IO.getErrno(), message, args); + static void throwLastError(MemorySegment errno, String message, Object... args) { + throwException(IO.getErrno(errno), message, args); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java deleted file mode 100644 index 5fc22cee..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java +++ /dev/null @@ -1,18 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.errno; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final FunctionDescriptor __errno_location$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT); - static final MethodHandle __errno_location$MH = RuntimeHelper.downcallHandle( - "__errno_location", - constants$0.__errno_location$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java index f3f25c95..a8cd6a61 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -2,9 +2,6 @@ package net.codecrete.usb.linux.gen.errno; -import java.lang.foreign.MemorySegment; -import java.lang.invoke.MethodHandle; - import static java.lang.foreign.ValueLayout.*; public class errno { @@ -32,22 +29,6 @@ public static int EPIPE() { public static int ETIMEDOUT() { return (int)110L; } - public static MethodHandle __errno_location$MH() { - return RuntimeHelper.requireNonNull(constants$0.__errno_location$MH,"__errno_location"); - } - /** - * {@snippet : - * int* __errno_location(); - * } - */ - public static MemorySegment __errno_location() { - var mh$ = __errno_location$MH(); - try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java deleted file mode 100644 index c02210dd..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.fcntl; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final FunctionDescriptor open$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle open$MH = RuntimeHelper.downcallHandleVariadic( - "open", - constants$0.open$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java index 388f45cf..4dcd2d69 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java @@ -2,9 +2,6 @@ package net.codecrete.usb.linux.gen.fcntl; -import java.lang.foreign.MemorySegment; -import java.lang.invoke.MethodHandle; - import static java.lang.foreign.ValueLayout.*; public class fcntl { @@ -24,22 +21,6 @@ public class fcntl { public static int O_RDWR() { return (int)2L; } - public static MethodHandle open$MH() { - return RuntimeHelper.requireNonNull(constants$0.open$MH,"open"); - } - /** - * {@snippet : - * int open(char* __file, int __oflag,...); - * } - */ - public static int open(MemorySegment __file, int __oflag, Object... x2) { - var mh$ = open$MH(); - try { - return (int)mh$.invokeExact(__file, __oflag, x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } /** * {@snippet : * #define O_CLOEXEC 524288 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/Constants$root.java deleted file mode 100644 index 78cd5fc9..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.ioctl; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfLong C_LONG$LAYOUT = JAVA_LONG; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/RuntimeHelper.java deleted file mode 100644 index 4793bce4..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/RuntimeHelper.java +++ /dev/null @@ -1,217 +0,0 @@ -package net.codecrete.usb.linux.gen.ioctl; -// Generated by jextract - -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.*; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); - - static { - - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { - try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/constants$0.java deleted file mode 100644 index f22a30d1..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/constants$0.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.ioctl; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final FunctionDescriptor ioctl$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle ioctl$MH = RuntimeHelper.downcallHandleVariadic( - "ioctl", - constants$0.ioctl$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/ioctl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/ioctl.java deleted file mode 100644 index 72a6f793..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/ioctl/ioctl.java +++ /dev/null @@ -1,36 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.ioctl; - -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.*; -public class ioctl { - - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; - public static MethodHandle ioctl$MH() { - return RuntimeHelper.requireNonNull(constants$0.ioctl$MH,"ioctl"); - } - /** - * {@snippet : - * int ioctl(int __fd, unsigned long __request,...); - * } - */ - public static int ioctl(int __fd, long __request, Object... x2) { - var mh$ = ioctl$MH(); - try { - return (int)mh$.invokeExact(__fd, __request, x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java index c832b5fb..6cb9001b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java @@ -68,7 +68,7 @@ public int maxPower() { public static final GroupLayout LAYOUT = structLayout( JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName("bDescriptorType"), - JAVA_SHORT.withName("wTotalLength"), + JAVA_SHORT.withBitAlignment(8).withName("wTotalLength"), JAVA_BYTE.withName("bNumInterfaces"), JAVA_BYTE.withName("bConfigurationValue"), JAVA_BYTE.withName("iConfiguration"), diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java index 856106e1..eaaa83c3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java @@ -86,14 +86,14 @@ public int iSerialNumber() { public static final GroupLayout LAYOUT = structLayout( JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName("bDescriptorType"), - JAVA_SHORT.withName("bcdUSB"), + JAVA_SHORT.withBitAlignment(8).withName("bcdUSB"), JAVA_BYTE.withName("bDeviceClass"), JAVA_BYTE.withName("bDeviceSubClass"), JAVA_BYTE.withName("bDeviceProtocol"), JAVA_BYTE.withName("bMaxPacketSize0"), - JAVA_SHORT.withName("idVendor"), - JAVA_SHORT.withName("idProduct"), - JAVA_SHORT.withName("bcdDevice"), + JAVA_SHORT.withBitAlignment(8).withName("idVendor"), + JAVA_SHORT.withBitAlignment(8).withName("idProduct"), + JAVA_SHORT.withBitAlignment(8).withName("bcdDevice"), JAVA_BYTE.withName("iManufacturer"), JAVA_BYTE.withName("iProduct"), JAVA_BYTE.withName("iSerialNumber"), diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java index acc345b0..ae6b82a1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java @@ -27,6 +27,10 @@ public EndpointDescriptor(MemorySegment descriptor) { this.descriptor = descriptor; } + public EndpointDescriptor(MemorySegment segment, long offset) { + this(segment.asSlice(offset, LAYOUT.byteSize())); + } + public int endpointAddress() { return 0xff & (byte) bEndpointAddress$VH.get(descriptor); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java index dd312d3d..d5fc5b73 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java @@ -26,6 +26,10 @@ public InterfaceAssociationDescriptor(MemorySegment descriptor) { this.descriptor = descriptor; } + public InterfaceAssociationDescriptor(MemorySegment segment, long offset) { + this(segment.asSlice(offset, LAYOUT.byteSize())); + } + public int firstInterface() { return 0xff & (byte) bFirstInterface$VH.get(descriptor); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java index d7f8746f..04668e37 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java @@ -26,6 +26,10 @@ public InterfaceDescriptor(MemorySegment descriptor) { this.descriptor = descriptor; } + public InterfaceDescriptor(MemorySegment segment, long offset) { + this(segment.asSlice(offset, LAYOUT.byteSize())); + } + public int interfaceNumber() { return 0xff & (byte) bInterfaceNumber$VH.get(descriptor); } From 555f63041433489bf06944d0c61af8b8adac895f Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Tue, 27 Dec 2022 22:22:51 +0100 Subject: [PATCH 171/433] Mention JDK 20 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 304c1d94..69297fc1 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ public class EnumerateDevices { - Java 19, preview features enabled (available at https://www.azul.com/downloads/?package=jdk) - Windows (x86 64-bit), macOS (x86 64-bit, ARM 64-bit) or Linux 64 bit (x86 64-bit, ARM 64-bit) +For a version compatible with JDK 20, see the branch `jdk20`. ## Platform-specific Considerations From 3ae870ddc8e2e47e38f01ff0989a79dd5e52f11b Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 28 Dec 2022 20:17:37 +0100 Subject: [PATCH 172/433] Use capture state for GetLastError (part 1) --- java-does-usb/jextract/windows/gen_win.cmd | 13 +- .../main/java/net/codecrete/usb/linux/IO.java | 4 +- .../codecrete/usb/windows/DeviceProperty.java | 149 ++++++++++----- .../net/codecrete/usb/windows/USBHelper.java | 2 +- .../java/net/codecrete/usb/windows/Win.java | 16 ++ .../usb/windows/WindowsUSBDeviceRegistry.java | 86 ++++++--- .../usb/windows/WindowsUSBException.java | 19 +- .../usb/windows/gen/kernel32/Kernel32.java | 8 + .../usb/windows/gen/setupapi/DEVPROPKEY.java | 16 ++ .../usb/windows/gen/setupapi/SetupAPI.java | 100 +--------- .../usb/windows/gen/setupapi/_DEVPROPKEY.java | 68 +++++++ .../usb/windows/gen/setupapi/constants$0.java | 37 ++-- .../usb/windows/gen/setupapi/constants$1.java | 82 -------- .../usb/windows/gen/user32/User32.java | 64 ------- .../usb/windows/gen/user32/constants$0.java | 44 ----- .../usb/windows/winsdk/SetupAPI2.java | 179 ++++++++++++++++++ .../codecrete/usb/windows/winsdk/User32B.java | 128 +++++++++++++ 17 files changed, 620 insertions(+), 395 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/DEVPROPKEY.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index 522ae134..a09c5d30 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -22,6 +22,7 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-constant ERROR_FILE_NOT_FOUND ^ --include-constant ERROR_SEM_TIMEOUT ^ --include-constant ERROR_GEN_FAILURE ^ + --include-constant ERROR_NOT_FOUND ^ --include-constant GENERIC_READ ^ --include-constant GENERIC_WRITE ^ --include-constant FILE_SHARE_READ ^ @@ -43,17 +44,11 @@ call %JEXTRACT% --source --output ../../src/main/java ^ -l SetupAPI ^ --header-class-name SetupAPI ^ --target-package net.codecrete.usb.windows.gen.setupapi ^ - --include-function SetupDiGetClassDevsW ^ --include-function SetupDiDestroyDeviceInfoList ^ - --include-function SetupDiEnumDeviceInfo ^ - --include-function SetupDiEnumDeviceInterfaces ^ - --include-function SetupDiGetDeviceInterfaceDetailW ^ --include-function SetupDiGetDeviceRegistryPropertyW ^ - --include-function SetupDiGetDevicePropertyW ^ --include-function SetupDiOpenDeviceInterfaceW ^ --include-function SetupDiCreateDeviceInfoList ^ --include-function SetupDiOpenDeviceInfoW ^ - --include-function SetupDiOpenDevRegKey ^ --include-function SetupDiDeleteDeviceInterfaceData ^ --include-struct _SP_DEVINFO_DATA ^ --include-typedef SP_DEVINFO_DATA ^ @@ -61,6 +56,8 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-typedef SP_DEVICE_INTERFACE_DATA ^ --include-struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W ^ --include-typedef SP_DEVICE_INTERFACE_DETAIL_DATA_W ^ + --include-struct _DEVPROPKEY ^ + --include-typedef DEVPROPKEY ^ --include-constant DIGCF_PRESENT ^ --include-constant DIGCF_DEVICEINTERFACE ^ --include-constant SPDRP_ADDRESS ^ @@ -95,10 +92,6 @@ call %JEXTRACT% --source --output ../../src/main/java ^ -l User32 ^ --header-class-name User32 ^ --target-package net.codecrete.usb.windows.gen.user32 ^ - --include-function RegisterClassExW ^ - --include-function CreateWindowExW ^ - --include-function RegisterDeviceNotificationW ^ - --include-function GetMessageW ^ --include-function DefWindowProcW ^ --include-constant DEVICE_NOTIFY_WINDOW_HANDLE ^ --include-constant HWND_MESSAGE ^ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java index 9b597ed9..880c9a9a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java @@ -40,7 +40,7 @@ public static int ioctl(int fd, long request, MemorySegment segment, MemorySegme try { return (int)ioctl$MH.invokeExact(errno, fd, request, segment); } catch (Throwable ex) { - throw new AssertionError("should not reach here", ex); + throw new RuntimeException(ex); } } @@ -53,7 +53,7 @@ public static int open(MemorySegment file, int oflag, MemorySegment errno) { try { return (int)open$MH.invokeExact(errno, file, oflag); } catch (Throwable ex) { - throw new AssertionError("should not reach here", ex); + throw new RuntimeException(ex); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index 4013793d..3a244cff 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -9,11 +9,12 @@ import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.windows.gen.advapi32.Advapi32; -import net.codecrete.usb.windows.gen.kernel32.GUID; import net.codecrete.usb.windows.gen.kernel32.Kernel32; +import net.codecrete.usb.windows.gen.setupapi.DEVPROPKEY; import net.codecrete.usb.windows.gen.setupapi.SP_DEVICE_INTERFACE_DATA; import net.codecrete.usb.windows.gen.setupapi.SP_DEVICE_INTERFACE_DETAIL_DATA_W; import net.codecrete.usb.windows.gen.setupapi.SetupAPI; +import net.codecrete.usb.windows.winsdk.SetupAPI2; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; @@ -31,36 +32,44 @@ public class DeviceProperty { public static final MemorySegment DEVPKEY_Device_Address = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, - (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50 - , (byte) 0xe0, 30); + (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, + (byte) 0x46, (byte) 0xa8, (byte) 0x50, (byte) 0xe0, 30); public static final MemorySegment DEVPKEY_Device_InstanceId = createDEVPROPKEY(0x78c34fc8, (short) 0x104a, - (short) 0x4aca, (byte) 0x9e, (byte) 0xa4, (byte) 0x52, (byte) 0x4d, (byte) 0x52, (byte) 0x99, (byte) 0x6e - , (byte) 0x57, 256); + (short) 0x4aca, (byte) 0x9e, (byte) 0xa4, (byte) 0x52, (byte) 0x4d, + (byte) 0x52, (byte) 0x99, (byte) 0x6e, (byte) 0x57, 256); public static final MemorySegment DEVPKEY_Device_Parent = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, - (short) 0x4706, (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, (byte) 0x80, (byte) 0x08, (byte) 0xa5 - , (byte) 0xa7, 8); + (short) 0x4706, (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, + (byte) 0x80, (byte) 0x08, (byte) 0xa5, (byte) 0xa7, 8); public static final MemorySegment DEVPKEY_Device_Service = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, - (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50, - (byte) 0xe0, 6); + (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, + (byte) 0x46, (byte) 0xa8, (byte) 0x50, (byte) 0xe0, 6); public static final MemorySegment DEVPKEY_Device_Children = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, - (short) 0x4706, (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, (byte) 0x80, (byte) 0x08, (byte) 0xa5, - (byte) 0xa7, 9); + (short) 0x4706, (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, + (byte) 0x80, (byte) 0x08, (byte) 0xa5, (byte) 0xa7, 9); public static final MemorySegment DEVPKEY_Device_HardwareIds = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, - (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50, - (byte) 0xe0, 3); - + (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, + (byte) 0x46, (byte) 0xa8, (byte) 0x50, (byte) 0xe0, 3); + + /** + * Gets the device property with integer type. + * @param devInfo device information set containing the device + * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the device in the information set + * @param propertyKey property key (of type {@code DEVPKEY}) + * @return property value + */ public static int getDeviceIntProperty(MemorySegment devInfo, MemorySegment devInfoData, MemorySegment propertyKey) { try (var arena = Arena.openConfined()) { var propertyTypeHolder = arena.allocate(JAVA_INT); var propertyValueHolder = arena.allocate(JAVA_INT); - if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, - propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0) == 0) - throwLastError("Internal error (SetupDiGetDevicePropertyW)"); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + if (SetupAPI2.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, + propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, lastErrorState) == 0) + throwLastError(lastErrorState, "Internal error (SetupDiGetDevicePropertyW)"); if (propertyTypeHolder.get(JAVA_INT, 0) != SetupAPI.DEVPROP_TYPE_UINT32()) throwException("Internal error (expected property type UINT32)"); @@ -69,35 +78,56 @@ public static int getDeviceIntProperty(MemorySegment devInfo, MemorySegment devI } } + /** + * Gets the device property with string type. + * @param devInfo device information set containing the device + * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the device in the information set + * @param propertyKey property key (of type {@code DEVPKEY}) + * @return property value + */ public static String getDeviceStringProperty(MemorySegment devInfo, MemorySegment devInfoData, MemorySegment propertyKey) { try (var arena = Arena.openConfined()) { - var propertyValue = getProperty(devInfo, devInfoData, propertyKey, - SetupAPI.DEVPROP_TYPE_STRING(), arena); + var propertyValue = getVariableLengthProperty(devInfo, devInfoData, propertyKey, SetupAPI.DEVPROP_TYPE_STRING(), arena); + if (propertyValue == null) + return null; return Win.createStringFromSegment(propertyValue); } } + /** + * Gets the device property with string list type. + * @param devInfo device information set containing the device + * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the device in the information set + * @param propertyKey property key (of type {@code DEVPKEY}) + * @return property value + */ public static List getDeviceStringListProperty(MemorySegment devInfo, MemorySegment devInfoData, MemorySegment propertyKey) { try (var arena = Arena.openConfined()) { - var propertyValue = getProperty(devInfo, devInfoData, propertyKey, + var propertyValue = getVariableLengthProperty(devInfo, devInfoData, propertyKey, SetupAPI.DEVPROP_TYPE_STRING() | SetupAPI.DEVPROP_TYPEMOD_LIST(), arena); + if (propertyValue == null) + return null; return Win.createStringListFromSegment(propertyValue); } } - private static MemorySegment getProperty(MemorySegment devInfo, MemorySegment devInfoData, MemorySegment propertyKey, - int propertyType, Arena arena) { + private static MemorySegment getVariableLengthProperty(MemorySegment devInfo, MemorySegment devInfoData, MemorySegment propertyKey, + int propertyType, Arena arena) { + + // query length (thus no buffer) var propertyTypeHolder = arena.allocate(JAVA_INT); var requiredSizeHolder = arena.allocate(JAVA_INT); - if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, NULL, 0, - requiredSizeHolder, 0) == 0) { - // TODO: Reactivate when proper GetLastError() handling is available - // int err = Kernel32.GetLastError(); - // if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) - // throwLastError("Internal error (SetupDiGetDevicePropertyW)"); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + if (SetupAPI2.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, NULL, 0, + requiredSizeHolder, 0, lastErrorState) == 0) { + int err = Win.getLastError(lastErrorState); + if (err == Kernel32.ERROR_NOT_FOUND()) + return null; + if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) + throwException(err, "Internal error (SetupDiGetDevicePropertyW)"); } if (propertyTypeHolder.get(JAVA_INT, 0) != propertyType) @@ -105,22 +135,34 @@ private static MemorySegment getProperty(MemorySegment devInfo, MemorySegment de int stringLen = requiredSizeHolder.get(JAVA_INT, 0) / 2 - 1; + // allocate buffer var propertyValueHolder = arena.allocateArray(JAVA_CHAR, stringLen + 1); - if (SetupAPI.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, - propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0) == 0) - throwLastError("Internal error (SetupDiGetDevicePropertyW)"); + + // get property value + if (SetupAPI2.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, + propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, lastErrorState) == 0) + throwLastError(lastErrorState, "Internal error (SetupDiGetDevicePropertyW)"); return propertyValueHolder; } + /** + * Gets a list of {@code DeviceInterfaceGUIDs} from device-specific configuration information in the registry. + * @param devInfoSetHandle device information set containing the device + * @param devInfo {@code SP_DEVINFO_DATA} structure specifying the device in the information set + * @param arena arena for allocating memory + * @return list of GUIDs + */ public static List findDeviceInterfaceGUIDs(MemorySegment devInfoSetHandle, MemorySegment devInfo, Arena arena) { try (var cleanup = new ScopeCleanup()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + // open device registry key - var regKey = SetupAPI.SetupDiOpenDevRegKey(devInfoSetHandle, devInfo, SetupAPI.DICS_FLAG_GLOBAL(), - 0, SetupAPI.DIREG_DEV(), Advapi32.KEY_READ()); + var regKey = SetupAPI2.SetupDiOpenDevRegKey(devInfoSetHandle, devInfo, SetupAPI.DICS_FLAG_GLOBAL(), + 0, SetupAPI.DIREG_DEV(), Advapi32.KEY_READ(), lastErrorState); if (Win.IsInvalidHandle(regKey)) - throwLastError("Cannot open device registry key"); + throwLastError(lastErrorState, "Cannot open device registry key"); cleanup.add(() -> Advapi32.RegCloseKey(regKey)); // read registry value (without buffer, to query length) @@ -144,14 +186,22 @@ public static List findDeviceInterfaceGUIDs(MemorySegment devInfoSetHand } } + /** + * Gets the device path for the device with the given device instance ID and device interface class. + * @param instanceID device instance ID + * @param interfaceGuid device interface class + * @return the device path + */ public static String getDevicePath(String instanceID, MemorySegment interfaceGuid) { try (var arena = Arena.openConfined(); var cleanup = new ScopeCleanup()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + // get device info set for instance var instanceIDSegment = Win.createSegmentFromString(instanceID, arena); - final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(interfaceGuid, instanceIDSegment, NULL, - SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); + final var devInfoSetHandle = SetupAPI2.SetupDiGetClassDevsW(interfaceGuid, instanceIDSegment, NULL, + SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), lastErrorState); if (Win.IsInvalidHandle(devInfoSetHandle)) - throwException("internal error (SetupDiGetClassDevsW)"); + throwLastError(lastErrorState, "internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); @@ -159,8 +209,9 @@ public static String getDevicePath(String instanceID, MemorySegment interfaceGui // retrieve first element of enumeration var devIntfData = arena.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); - if (SetupAPI.SetupDiEnumDeviceInterfaces(devInfoSetHandle, NULL, interfaceGuid, 0, devIntfData) == 0) - throwException("internal error (SetupDiEnumDeviceInterfaces)"); + if (SetupAPI2.SetupDiEnumDeviceInterfaces(devInfoSetHandle, NULL, interfaceGuid, 0, + devIntfData, lastErrorState) == 0) + throwLastError(lastErrorState, "internal error (SetupDiEnumDeviceInterfaces)"); // get device path // (SP_DEVICE_INTERFACE_DETAIL_DATA_W is of variable length and requires a bigger allocation so @@ -170,22 +221,20 @@ public static String getDevicePath(String instanceID, MemorySegment interfaceGui SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$set(intfDetailData, (int) SP_DEVICE_INTERFACE_DETAIL_DATA_W.sizeof()); int intfDetailDataSize = (int) intfDetailData.byteSize(); - if (SetupAPI.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, intfDetailData, - intfDetailDataSize, NULL, NULL) == 0) - throwLastError("Internal error (SetupDiGetDeviceInterfaceDetailW)"); + if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, intfDetailData, + intfDetailDataSize, NULL, NULL, lastErrorState) == 0) + throwLastError(lastErrorState, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); return Win.createStringFromSegment(intfDetailData.asSlice(devicePathOffset)); } } - public static MemorySegment createDEVPROPKEY(int data1, short data2, short data3, byte data4_0, byte data4_1, - byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6 - , byte data4_7, int pid) { - var propKey = Win.GLOBAL_ALLOCATOR.allocate(GUID.sizeof() + JAVA_INT.byteSize()); - Win.setGUID(propKey, data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4, data4_5, data4_6, - data4_7); - propKey.set(JAVA_INT, 16, pid); + private static MemorySegment createDEVPROPKEY(int data1, short data2, short data3, byte data4_0, byte data4_1, + byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7, int pid) { + var propKey = Win.GLOBAL_ALLOCATOR.allocate(DEVPROPKEY.$LAYOUT()); + Win.setGUID(DEVPROPKEY.fmtid$slice(propKey), + data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4, data4_5, data4_6, data4_7); + DEVPROPKEY.pid$set(propKey, pid); return propKey; } - } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java index 53ba0dfc..cd77f42d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java @@ -50,7 +50,7 @@ public class USBHelper { JAVA_BYTE.withName("CurrentConfigurationValue"), JAVA_BYTE.withName("Speed"), JAVA_BYTE.withName("DeviceIsHub"), - JAVA_SHORT.withName("DeviceAddress"), + JAVA_SHORT.withBitAlignment(8).withName("DeviceAddress"), JAVA_INT.withName("NumberOfOpenPipes"), JAVA_INT.withName("ConnectionStatus") // USB_PIPE_INFO PipeList[0] diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index fed79474..b44b9e8d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -11,6 +11,7 @@ import net.codecrete.usb.windows.gen.stdlib.StdLib; import java.lang.foreign.*; +import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.List; @@ -27,6 +28,21 @@ public class Win { */ public static final SegmentAllocator GLOBAL_ALLOCATOR = SegmentAllocator.nativeAllocator(SegmentScope.global()); + /** + * Call state for capturing the {@code GetLastError()} value. + */ + public static final Linker.Option.CaptureCallState LAST_ERROR_STATE = Linker.Option.captureCallState("GetLastError"); + + private static final VarHandle callState_GetLastError$VH = LAST_ERROR_STATE.layout().varHandle(MemoryLayout.PathElement.groupElement("GetLastError")); + + /** + * Returns the error code captured using the call state {@link #LAST_ERROR_STATE}. + * @param callState the call state + * @return the error code + */ + public static int getLastError(MemorySegment callState) { + return (int) callState_GetLastError$VH.get(callState); + } /** * Checks if a Windows handle is invalid. * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index a1f2cb9b..5de5b731 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -23,6 +23,8 @@ import net.codecrete.usb.windows.gen.setupapi.SetupAPI; import net.codecrete.usb.windows.gen.usbioctl.USBIoctl; import net.codecrete.usb.windows.gen.user32.*; +import net.codecrete.usb.windows.winsdk.SetupAPI2; +import net.codecrete.usb.windows.winsdk.User32B; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; @@ -57,6 +59,7 @@ protected void monitorDevices() { try (var arena = Arena.openConfined()) { MemorySegment hwnd; + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); try { final var className = Win.createSegmentFromString("USB_MONITOR", arena); @@ -76,13 +79,15 @@ protected void monitorDevices() { WNDCLASSEXW.lpfnWndProc$set(wx, handleWindowMessageStub); WNDCLASSEXW.hInstance$set(wx, instance); WNDCLASSEXW.lpszClassName$set(wx, className); - User32.RegisterClassExW(wx); + var atom = User32B.RegisterClassExW(wx, lastErrorState); + if (atom == 0) + throwLastError(lastErrorState, "Internal error (RegisterClassExW)"); // create message-only window - hwnd = User32.CreateWindowExW(0, className, windowName, 0, 0, 0, 0, 0, User32.HWND_MESSAGE(), NULL, - instance, NULL); - if (hwnd == NULL) - throwLastError("internal error (CreateWindowExW)"); + hwnd = User32B.CreateWindowExW(0, className, windowName, 0, 0, 0, 0, 0, + User32.HWND_MESSAGE(), NULL, instance, NULL, lastErrorState); + if (hwnd.address() == 0) + throwLastError(lastErrorState, "internal error (CreateWindowExW)"); // configure notifications var notificationFilter = arena.allocate(DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); @@ -91,10 +96,10 @@ protected void monitorDevices() { User32.DBT_DEVTYP_DEVICEINTERFACE()); DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid$slice(notificationFilter).copyFrom(USBHelper.GUID_DEVINTERFACE_USB_DEVICE); - var notifyHandle = User32.RegisterDeviceNotificationW(hwnd, notificationFilter, - User32.DEVICE_NOTIFY_WINDOW_HANDLE()); - if (notifyHandle == NULL) - throwLastError("internal error (RegisterDeviceNotificationW)"); + var notifyHandle = User32B.RegisterDeviceNotificationW(hwnd, notificationFilter, + User32.DEVICE_NOTIFY_WINDOW_HANDLE(), lastErrorState); + if (notifyHandle.address() == 0) + throwLastError(lastErrorState, "internal error (RegisterDeviceNotificationW)"); // initial device enumeration enumeratePresentDevices(); @@ -106,9 +111,13 @@ protected void monitorDevices() { // process messages var msg = arena.allocate(MSG.$LAYOUT()); + int err; //noinspection StatementWithEmptyBody - while (User32.GetMessageW(msg, hwnd, 0, 0) > 0) + while ((err = User32B.GetMessageW(msg, hwnd, 0, 0, lastErrorState)) > 0) ; // do nothing + + if (err == -1) + throwLastError(lastErrorState, "Internal error (GetMessageW)"); } } @@ -117,11 +126,13 @@ private void enumeratePresentDevices() { List deviceList = new ArrayList<>(); try (var outerArena = Arena.openConfined(); var outerCleanup = new ScopeCleanup()) { + var lastErrorState = outerArena.allocate(Win.LAST_ERROR_STATE.layout()); + // get device information set of all USB devices present - final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, - NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); + final var devInfoSetHandle = SetupAPI2.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, + NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), lastErrorState); if (Win.IsInvalidHandle(devInfoSetHandle)) - throwException("internal error (SetupDiGetClassDevsW)"); + throwLastError(lastErrorState, "internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left outerCleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); @@ -136,12 +147,11 @@ private void enumeratePresentDevices() { // iterate all devices for (int i = 0; true; i++) { - if (SetupAPI.SetupDiEnumDeviceInfo(devInfoSetHandle, i, devInfo) == 0) { - int err = Kernel32.GetLastError(); - // TODO: Remove check for ERROR_SUCCESS if proper GetLastError() handling is available - if (err == Kernel32.ERROR_NO_MORE_ITEMS() || err == Kernel32.ERROR_SUCCESS()) + if (SetupAPI2.SetupDiEnumDeviceInfo(devInfoSetHandle, i, devInfo, lastErrorState) == 0) { + int err = Win.getLastError(lastErrorState); + if (err == Kernel32.ERROR_NO_MORE_ITEMS()) break; - throwException("Internal error (SetupDiEnumDeviceInfo) "); + throwLastError(lastErrorState, "Internal error (SetupDiEnumDeviceInfo)"); } var instanceID = DeviceProperty.getDeviceStringProperty(devInfoSetHandle, devInfo, @@ -245,8 +255,31 @@ private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSetHandle, Mem Map children = null; if (isCompositeDevice(deviceService)) { - children = enumerateChildren(DeviceProperty.getDeviceStringListProperty(devInfoSetHandle, devInfo, - DeviceProperty.DEVPKEY_Device_Children)); + + // For certain devices, it seems to take some time until DEVPKEY_Device_Children + // entry is present. So we retry a few times if needed and pause in between. + List childrenInstanceIDs = null; + int numTries = 5; + while (true) { + numTries -= 1; + childrenInstanceIDs = DeviceProperty.getDeviceStringListProperty(devInfoSetHandle, devInfo, + DeviceProperty.DEVPKEY_Device_Children); + if (childrenInstanceIDs != null || numTries == 0) + break; + + // sleep and retry + try { + Thread.sleep(200); + } catch (InterruptedException e) { + // ignore + } + } + + if (childrenInstanceIDs == null) { + System.err.printf("Info: [JavaDoesUSB] cannot get device children of device %s%n", devicePath); + } else { + children = enumerateChildren(childrenInstanceIDs); + } } return createDevice(devicePath, children, hubHandle, usbPortNum); @@ -378,11 +411,13 @@ private long handleWindowMessage(MemorySegment hWnd, int uMsg, long wParam, long private void onDeviceConnected(String devicePath) { try (var arena = Arena.openConfined(); var cleanup = new ScopeCleanup()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + // get device information set of all USB devices present - final var devInfoSetHandle = SetupAPI.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, - NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE()); + final var devInfoSetHandle = SetupAPI2.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, + NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), lastErrorState); if (Win.IsInvalidHandle(devInfoSetHandle)) - throwLastError("internal error (SetupDiGetClassDevsW)"); + throwLastError(lastErrorState, "internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); @@ -397,8 +432,9 @@ private void onDeviceConnected(String devicePath) { var devInfo = arena.allocate(SP_DEVINFO_DATA.$LAYOUT()); SP_DEVINFO_DATA.cbSize$set(devInfo, (int) devInfo.byteSize()); - if (SetupAPI.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, NULL, 0, NULL, devInfo) == 0) { - int err = Kernel32.GetLastError(); + if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, NULL, 0, + NULL, devInfo, lastErrorState) == 0) { + int err = Win.getLastError(lastErrorState); if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) throwException(err, "internal error (SetupDiGetDeviceInterfaceDetailW)"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java index 21e3c695..6e0cb690 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java @@ -8,9 +8,11 @@ import net.codecrete.usb.USBException; import net.codecrete.usb.USBStallException; +import net.codecrete.usb.common.ForeignMemory; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.ADDRESS; @@ -71,13 +73,28 @@ static void throwLastError(String message, Object... args) { throwException(Kernel32.GetLastError(), message, args); } + /** + * Throws an exception for the last error. + *

+ * The last Windows error code is taken from the call capture state + * {@link Win.LAST_ERROR_STATE} provided as the first parameter. + *

+ * + * @param lastErrorState call capture state containing last error code + * @param message exception message format ({@link String#format(String, Object...)} style) + * @param args arguments for exception message + */ + static void throwLastError(MemorySegment lastErrorState, String message, Object... args) { + throwException(Win.getLastError(lastErrorState), message, args); + } + private static String getErrorMessage(int errorCode) { try (var arena = Arena.openConfined()) { var messagePointerHolder = arena.allocate(ADDRESS); Kernel32.FormatMessageW(Kernel32.FORMAT_MESSAGE_ALLOCATE_BUFFER() | Kernel32.FORMAT_MESSAGE_FROM_SYSTEM() | Kernel32.FORMAT_MESSAGE_IGNORE_INSERTS(), NULL, errorCode, 0, messagePointerHolder, 0, NULL); - var messagePointer = messagePointerHolder.get(ADDRESS, 0); + var messagePointer = messagePointerHolder.get(ForeignMemory.UNBOUNDED_ADDRESS, 0); String message = Win.createStringFromSegment(messagePointer); Kernel32.LocalFree(messagePointer); return message.trim(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java index 24089e82..9cc743a7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -264,6 +264,14 @@ public static int ERROR_MORE_DATA() { public static int ERROR_NO_MORE_ITEMS() { return (int)259L; } + /** + * {@snippet : + * #define ERROR_NOT_FOUND 1168 + * } + */ + public static int ERROR_NOT_FOUND() { + return (int)1168L; + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/DEVPROPKEY.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/DEVPROPKEY.java new file mode 100644 index 00000000..8162d9a9 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/DEVPROPKEY.java @@ -0,0 +1,16 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.setupapi; + +/** + * {@snippet : + * typedef struct _DEVPROPKEY DEVPROPKEY; + * } + */ +public final class DEVPROPKEY extends _DEVPROPKEY { + + // Suppresses default constructor, ensuring non-instantiability. + private DEVPROPKEY() {} +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java index 91fafb58..6cc609d7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java @@ -104,22 +104,6 @@ public static int SetupDiOpenDeviceInfoW(MemorySegment DeviceInfoSet, MemorySegm throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle SetupDiEnumDeviceInfo$MH() { - return RuntimeHelper.requireNonNull(constants$0.SetupDiEnumDeviceInfo$MH,"SetupDiEnumDeviceInfo"); - } - /** - * {@snippet : - * BOOL SetupDiEnumDeviceInfo(HDEVINFO DeviceInfoSet, DWORD MemberIndex, PSP_DEVINFO_DATA DeviceInfoData); - * } - */ - public static int SetupDiEnumDeviceInfo(MemorySegment DeviceInfoSet, int MemberIndex, MemorySegment DeviceInfoData) { - var mh$ = SetupDiEnumDeviceInfo$MH(); - try { - return (int)mh$.invokeExact(DeviceInfoSet, MemberIndex, DeviceInfoData); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } public static MethodHandle SetupDiDestroyDeviceInfoList$MH() { return RuntimeHelper.requireNonNull(constants$0.SetupDiDestroyDeviceInfoList$MH,"SetupDiDestroyDeviceInfoList"); } @@ -136,22 +120,6 @@ public static int SetupDiDestroyDeviceInfoList(MemorySegment DeviceInfoSet) { throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle SetupDiEnumDeviceInterfaces$MH() { - return RuntimeHelper.requireNonNull(constants$0.SetupDiEnumDeviceInterfaces$MH,"SetupDiEnumDeviceInterfaces"); - } - /** - * {@snippet : - * BOOL SetupDiEnumDeviceInterfaces(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, const GUID* InterfaceClassGuid, DWORD MemberIndex, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData); - * } - */ - public static int SetupDiEnumDeviceInterfaces(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, MemorySegment InterfaceClassGuid, int MemberIndex, MemorySegment DeviceInterfaceData) { - var mh$ = SetupDiEnumDeviceInterfaces$MH(); - try { - return (int)mh$.invokeExact(DeviceInfoSet, DeviceInfoData, InterfaceClassGuid, MemberIndex, DeviceInterfaceData); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } public static MethodHandle SetupDiOpenDeviceInterfaceW$MH() { return RuntimeHelper.requireNonNull(constants$0.SetupDiOpenDeviceInterfaceW$MH,"SetupDiOpenDeviceInterfaceW"); } @@ -169,7 +137,7 @@ public static int SetupDiOpenDeviceInterfaceW(MemorySegment DeviceInfoSet, Memor } } public static MethodHandle SetupDiDeleteDeviceInterfaceData$MH() { - return RuntimeHelper.requireNonNull(constants$1.SetupDiDeleteDeviceInterfaceData$MH,"SetupDiDeleteDeviceInterfaceData"); + return RuntimeHelper.requireNonNull(constants$0.SetupDiDeleteDeviceInterfaceData$MH,"SetupDiDeleteDeviceInterfaceData"); } /** * {@snippet : @@ -184,72 +152,8 @@ public static int SetupDiDeleteDeviceInterfaceData(MemorySegment DeviceInfoSet, throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle SetupDiGetDeviceInterfaceDetailW$MH() { - return RuntimeHelper.requireNonNull(constants$1.SetupDiGetDeviceInterfaceDetailW$MH,"SetupDiGetDeviceInterfaceDetailW"); - } - /** - * {@snippet : - * BOOL SetupDiGetDeviceInterfaceDetailW(HDEVINFO DeviceInfoSet, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData, DWORD DeviceInterfaceDetailDataSize, PDWORD RequiredSize, PSP_DEVINFO_DATA DeviceInfoData); - * } - */ - public static int SetupDiGetDeviceInterfaceDetailW(MemorySegment DeviceInfoSet, MemorySegment DeviceInterfaceData, MemorySegment DeviceInterfaceDetailData, int DeviceInterfaceDetailDataSize, MemorySegment RequiredSize, MemorySegment DeviceInfoData) { - var mh$ = SetupDiGetDeviceInterfaceDetailW$MH(); - try { - return (int)mh$.invokeExact(DeviceInfoSet, DeviceInterfaceData, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle SetupDiGetClassDevsW$MH() { - return RuntimeHelper.requireNonNull(constants$1.SetupDiGetClassDevsW$MH,"SetupDiGetClassDevsW"); - } - /** - * {@snippet : - * HDEVINFO SetupDiGetClassDevsW(const GUID* ClassGuid, PCWSTR Enumerator, HWND hwndParent, DWORD Flags); - * } - */ - public static MemorySegment SetupDiGetClassDevsW(MemorySegment ClassGuid, MemorySegment Enumerator, MemorySegment hwndParent, int Flags) { - var mh$ = SetupDiGetClassDevsW$MH(); - try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(ClassGuid, Enumerator, hwndParent, Flags); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle SetupDiOpenDevRegKey$MH() { - return RuntimeHelper.requireNonNull(constants$1.SetupDiOpenDevRegKey$MH,"SetupDiOpenDevRegKey"); - } - /** - * {@snippet : - * HKEY SetupDiOpenDevRegKey(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Scope, DWORD HwProfile, DWORD KeyType, REGSAM samDesired); - * } - */ - public static MemorySegment SetupDiOpenDevRegKey(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, int Scope, int HwProfile, int KeyType, int samDesired) { - var mh$ = SetupDiOpenDevRegKey$MH(); - try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(DeviceInfoSet, DeviceInfoData, Scope, HwProfile, KeyType, samDesired); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle SetupDiGetDevicePropertyW$MH() { - return RuntimeHelper.requireNonNull(constants$1.SetupDiGetDevicePropertyW$MH,"SetupDiGetDevicePropertyW"); - } - /** - * {@snippet : - * BOOL SetupDiGetDevicePropertyW(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, const DEVPROPKEY* PropertyKey, DEVPROPTYPE* PropertyType, PBYTE PropertyBuffer, DWORD PropertyBufferSize, PDWORD RequiredSize, DWORD Flags); - * } - */ - public static int SetupDiGetDevicePropertyW(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, MemorySegment PropertyKey, MemorySegment PropertyType, MemorySegment PropertyBuffer, int PropertyBufferSize, MemorySegment RequiredSize, int Flags) { - var mh$ = SetupDiGetDevicePropertyW$MH(); - try { - return (int)mh$.invokeExact(DeviceInfoSet, DeviceInfoData, PropertyKey, PropertyType, PropertyBuffer, PropertyBufferSize, RequiredSize, Flags); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } public static MethodHandle SetupDiGetDeviceRegistryPropertyW$MH() { - return RuntimeHelper.requireNonNull(constants$1.SetupDiGetDeviceRegistryPropertyW$MH,"SetupDiGetDeviceRegistryPropertyW"); + return RuntimeHelper.requireNonNull(constants$0.SetupDiGetDeviceRegistryPropertyW$MH,"SetupDiGetDeviceRegistryPropertyW"); } /** * {@snippet : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java new file mode 100644 index 00000000..d1bdbfa4 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java @@ -0,0 +1,68 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.setupapi; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct _DEVPROPKEY { + * DEVPROPGUID fmtid; + * DEVPROPID pid; + * }; + * } + */ +public class _DEVPROPKEY { + + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( + MemoryLayout.structLayout( + Constants$root.C_LONG$LAYOUT.withName("Data1"), + Constants$root.C_SHORT$LAYOUT.withName("Data2"), + Constants$root.C_SHORT$LAYOUT.withName("Data3"), + MemoryLayout.sequenceLayout(8, Constants$root.C_CHAR$LAYOUT).withName("Data4") + ).withName("fmtid"), + Constants$root.C_LONG$LAYOUT.withName("pid") + ).withName("_DEVPROPKEY"); + public static MemoryLayout $LAYOUT() { + return _DEVPROPKEY.$struct$LAYOUT; + } + public static MemorySegment fmtid$slice(MemorySegment seg) { + return seg.asSlice(0, 16); + } + static final VarHandle pid$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("pid")); + public static VarHandle pid$VH() { + return _DEVPROPKEY.pid$VH; + } + /** + * Getter for field: + * {@snippet : + * DEVPROPID pid; + * } + */ + public static int pid$get(MemorySegment seg) { + return (int)_DEVPROPKEY.pid$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * DEVPROPID pid; + * } + */ + public static void pid$set(MemorySegment seg, int x) { + _DEVPROPKEY.pid$VH.set(seg, x); + } + public static int pid$get(MemorySegment seg, long index) { + return (int)_DEVPROPKEY.pid$VH.get(seg.asSlice(index*sizeof())); + } + public static void pid$set(MemorySegment seg, long index, int x) { + _DEVPROPKEY.pid$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java index 4b375872..c0abf521 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java @@ -27,15 +27,6 @@ final class constants$0 { "SetupDiOpenDeviceInfoW", constants$0.SetupDiOpenDeviceInfoW$FUNC ); - static final FunctionDescriptor SetupDiEnumDeviceInfo$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle SetupDiEnumDeviceInfo$MH = RuntimeHelper.downcallHandle( - "SetupDiEnumDeviceInfo", - constants$0.SetupDiEnumDeviceInfo$FUNC - ); static final FunctionDescriptor SetupDiDestroyDeviceInfoList$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT ); @@ -43,26 +34,36 @@ final class constants$0 { "SetupDiDestroyDeviceInfoList", constants$0.SetupDiDestroyDeviceInfoList$FUNC ); - static final FunctionDescriptor SetupDiEnumDeviceInterfaces$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, + static final FunctionDescriptor SetupDiOpenDeviceInterfaceW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle SetupDiEnumDeviceInterfaces$MH = RuntimeHelper.downcallHandle( - "SetupDiEnumDeviceInterfaces", - constants$0.SetupDiEnumDeviceInterfaces$FUNC + static final MethodHandle SetupDiOpenDeviceInterfaceW$MH = RuntimeHelper.downcallHandle( + "SetupDiOpenDeviceInterfaceW", + constants$0.SetupDiOpenDeviceInterfaceW$FUNC ); - static final FunctionDescriptor SetupDiOpenDeviceInterfaceW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + static final FunctionDescriptor SetupDiDeleteDeviceInterfaceData$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle SetupDiDeleteDeviceInterfaceData$MH = RuntimeHelper.downcallHandle( + "SetupDiDeleteDeviceInterfaceData", + constants$0.SetupDiDeleteDeviceInterfaceData$FUNC + ); + static final FunctionDescriptor SetupDiGetDeviceRegistryPropertyW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle SetupDiOpenDeviceInterfaceW$MH = RuntimeHelper.downcallHandle( - "SetupDiOpenDeviceInterfaceW", - constants$0.SetupDiOpenDeviceInterfaceW$FUNC + static final MethodHandle SetupDiGetDeviceRegistryPropertyW$MH = RuntimeHelper.downcallHandle( + "SetupDiGetDeviceRegistryPropertyW", + constants$0.SetupDiGetDeviceRegistryPropertyW$FUNC ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java deleted file mode 100644 index bec4f318..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java +++ /dev/null @@ -1,82 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.setupapi; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -final class constants$1 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$1() {} - static final FunctionDescriptor SetupDiDeleteDeviceInterfaceData$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle SetupDiDeleteDeviceInterfaceData$MH = RuntimeHelper.downcallHandle( - "SetupDiDeleteDeviceInterfaceData", - constants$1.SetupDiDeleteDeviceInterfaceData$FUNC - ); - static final FunctionDescriptor SetupDiGetDeviceInterfaceDetailW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle SetupDiGetDeviceInterfaceDetailW$MH = RuntimeHelper.downcallHandle( - "SetupDiGetDeviceInterfaceDetailW", - constants$1.SetupDiGetDeviceInterfaceDetailW$FUNC - ); - static final FunctionDescriptor SetupDiGetClassDevsW$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT - ); - static final MethodHandle SetupDiGetClassDevsW$MH = RuntimeHelper.downcallHandle( - "SetupDiGetClassDevsW", - constants$1.SetupDiGetClassDevsW$FUNC - ); - static final FunctionDescriptor SetupDiOpenDevRegKey$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT - ); - static final MethodHandle SetupDiOpenDevRegKey$MH = RuntimeHelper.downcallHandle( - "SetupDiOpenDevRegKey", - constants$1.SetupDiOpenDevRegKey$FUNC - ); - static final FunctionDescriptor SetupDiGetDevicePropertyW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT - ); - static final MethodHandle SetupDiGetDevicePropertyW$MH = RuntimeHelper.downcallHandle( - "SetupDiGetDevicePropertyW", - constants$1.SetupDiGetDevicePropertyW$FUNC - ); - static final FunctionDescriptor SetupDiGetDeviceRegistryPropertyW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle SetupDiGetDeviceRegistryPropertyW$MH = RuntimeHelper.downcallHandle( - "SetupDiGetDeviceRegistryPropertyW", - constants$1.SetupDiGetDeviceRegistryPropertyW$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java index 57f923ab..2b2267a2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java @@ -56,38 +56,6 @@ public static int DBT_DEVICEREMOVECOMPLETE() { public static int DBT_DEVTYP_DEVICEINTERFACE() { return (int)5L; } - public static MethodHandle GetMessageW$MH() { - return RuntimeHelper.requireNonNull(constants$0.GetMessageW$MH,"GetMessageW"); - } - /** - * {@snippet : - * BOOL GetMessageW(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax); - * } - */ - public static int GetMessageW(MemorySegment lpMsg, MemorySegment hWnd, int wMsgFilterMin, int wMsgFilterMax) { - var mh$ = GetMessageW$MH(); - try { - return (int)mh$.invokeExact(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle RegisterDeviceNotificationW$MH() { - return RuntimeHelper.requireNonNull(constants$0.RegisterDeviceNotificationW$MH,"RegisterDeviceNotificationW"); - } - /** - * {@snippet : - * HDEVNOTIFY RegisterDeviceNotificationW(HANDLE hRecipient, LPVOID NotificationFilter, DWORD Flags); - * } - */ - public static MemorySegment RegisterDeviceNotificationW(MemorySegment hRecipient, MemorySegment NotificationFilter, int Flags) { - var mh$ = RegisterDeviceNotificationW$MH(); - try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(hRecipient, NotificationFilter, Flags); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } public static MethodHandle DefWindowProcW$MH() { return RuntimeHelper.requireNonNull(constants$0.DefWindowProcW$MH,"DefWindowProcW"); } @@ -104,38 +72,6 @@ public static long DefWindowProcW(MemorySegment hWnd, int Msg, long wParam, long throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle RegisterClassExW$MH() { - return RuntimeHelper.requireNonNull(constants$0.RegisterClassExW$MH,"RegisterClassExW"); - } - /** - * {@snippet : - * ATOM RegisterClassExW(const WNDCLASSEXW*); - * } - */ - public static short RegisterClassExW(MemorySegment x0) { - var mh$ = RegisterClassExW$MH(); - try { - return (short)mh$.invokeExact(x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle CreateWindowExW$MH() { - return RuntimeHelper.requireNonNull(constants$0.CreateWindowExW$MH,"CreateWindowExW"); - } - /** - * {@snippet : - * HWND CreateWindowExW(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam); - * } - */ - public static MemorySegment CreateWindowExW(int dwExStyle, MemorySegment lpClassName, MemorySegment lpWindowName, int dwStyle, int X, int Y, int nWidth, int nHeight, MemorySegment hWndParent, MemorySegment hMenu, MemorySegment hInstance, MemorySegment lpParam) { - var mh$ = CreateWindowExW$MH(); - try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } /** * {@snippet : * #define HWND_MESSAGE -3 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java index 99958f5f..196a0ea1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java @@ -9,25 +9,6 @@ final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} - static final FunctionDescriptor GetMessageW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT - ); - static final MethodHandle GetMessageW$MH = RuntimeHelper.downcallHandle( - "GetMessageW", - constants$0.GetMessageW$FUNC - ); - static final FunctionDescriptor RegisterDeviceNotificationW$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT - ); - static final MethodHandle RegisterDeviceNotificationW$MH = RuntimeHelper.downcallHandle( - "RegisterDeviceNotificationW", - constants$0.RegisterDeviceNotificationW$FUNC - ); static final FunctionDescriptor DefWindowProcW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_LONG$LAYOUT, @@ -38,31 +19,6 @@ final class constants$0 { "DefWindowProcW", constants$0.DefWindowProcW$FUNC ); - static final FunctionDescriptor RegisterClassExW$FUNC = FunctionDescriptor.of(Constants$root.C_SHORT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle RegisterClassExW$MH = RuntimeHelper.downcallHandle( - "RegisterClassExW", - constants$0.RegisterClassExW$FUNC - ); - static final FunctionDescriptor CreateWindowExW$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle CreateWindowExW$MH = RuntimeHelper.downcallHandle( - "CreateWindowExW", - constants$0.CreateWindowExW$FUNC - ); static final MemorySegment HWND_MESSAGE$ADDR = MemorySegment.ofAddress(-3L); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java new file mode 100644 index 00000000..860483a8 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java @@ -0,0 +1,179 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +package net.codecrete.usb.windows.winsdk; + +import net.codecrete.usb.windows.Win; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; + +/** + * Native function calls for SetupAPI. + *

+ * This code is manually created to include the additional parameters for capturing + * {@code GetLastError()} until jextract catches up and can generate the corresponding code. + *

+ */ +public class SetupAPI2 { + + static { + System.loadLibrary("SetupAPI"); + } + + private static final Linker LINKER = Linker.nativeLinker(); + private static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup(); + + private static final FunctionDescriptor SetupDiGetDevicePropertyW$FUNC = + FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS, JAVA_INT); + + private static final MethodHandle SetupDiGetDevicePropertyW$MH = LINKER.downcallHandle( + LOOKUP.find("SetupDiGetDevicePropertyW").get(), + SetupDiGetDevicePropertyW$FUNC, + Win.LAST_ERROR_STATE + ); + + private static final FunctionDescriptor SetupDiEnumDeviceInfo$FUNC = + FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT, ADDRESS); + + private static final MethodHandle SetupDiEnumDeviceInfo$MH = LINKER.downcallHandle( + LOOKUP.find("SetupDiEnumDeviceInfo").get(), + SetupDiEnumDeviceInfo$FUNC, + Win.LAST_ERROR_STATE + ); + + private static final FunctionDescriptor SetupDiOpenDevRegKey$FUNC = + FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, JAVA_INT, JAVA_INT, JAVA_INT, JAVA_INT); + + private static final MethodHandle SetupDiOpenDevRegKey$MH = LINKER.downcallHandle( + LOOKUP.find("SetupDiOpenDevRegKey").get(), + SetupDiOpenDevRegKey$FUNC, + Win.LAST_ERROR_STATE + ); + + private static final FunctionDescriptor SetupDiGetClassDevsW$FUNC = + FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, ADDRESS, JAVA_INT); + + private static final MethodHandle SetupDiGetClassDevsW$MH = LINKER.downcallHandle( + LOOKUP.find("SetupDiGetClassDevsW").get(), + SetupDiGetClassDevsW$FUNC, + Win.LAST_ERROR_STATE + ); + + private static final FunctionDescriptor SetupDiEnumDeviceInterfaces$FUNC = + FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS); + + private static final MethodHandle SetupDiEnumDeviceInterfaces$MH = LINKER.downcallHandle( + LOOKUP.find("SetupDiEnumDeviceInterfaces").get(), + SetupDiEnumDeviceInterfaces$FUNC, + Win.LAST_ERROR_STATE + ); + + private static final FunctionDescriptor SetupDiGetDeviceInterfaceDetailW$FUNC = + FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); + + private static final MethodHandle SetupDiGetDeviceInterfaceDetailW$MH = LINKER.downcallHandle( + LOOKUP.find("SetupDiGetDeviceInterfaceDetailW").get(), + SetupDiGetDeviceInterfaceDetailW$FUNC, + Win.LAST_ERROR_STATE + ); + + + /** + * {@snippet lang=c : + * BOOL SetupDiGetDevicePropertyW(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, const DEVPROPKEY* PropertyKey, DEVPROPTYPE* PropertyType, PBYTE PropertyBuffer, DWORD PropertyBufferSize, PDWORD RequiredSize, DWORD Flags); + * } + */ + public static int SetupDiGetDevicePropertyW(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, + MemorySegment PropertyKey, MemorySegment PropertyType, + MemorySegment PropertyBuffer, int PropertyBufferSize, + MemorySegment RequiredSize, int Flags, + MemorySegment lastErrorState) { + try { + return (int)SetupDiGetDevicePropertyW$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, + PropertyKey, PropertyType, PropertyBuffer, PropertyBufferSize, RequiredSize, Flags); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + /** + * {@snippet lang=c : + * BOOL SetupDiEnumDeviceInfo(HDEVINFO DeviceInfoSet, DWORD MemberIndex, PSP_DEVINFO_DATA DeviceInfoData); + * } + */ + public static int SetupDiEnumDeviceInfo(MemorySegment DeviceInfoSet, int MemberIndex, MemorySegment DeviceInfoData, + MemorySegment lastErrorState) { + try { + return (int)SetupDiEnumDeviceInfo$MH.invokeExact(lastErrorState, DeviceInfoSet, MemberIndex, DeviceInfoData); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + /** + * {@snippet lang=c : + * HDEVINFO SetupDiGetClassDevsW(const GUID* ClassGuid, PCWSTR Enumerator, HWND hwndParent, DWORD Flags); + * } + */ + public static MemorySegment SetupDiOpenDevRegKey(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, + int Scope, int HwProfile, int KeyType, int samDesired, + MemorySegment lastErrorState) { + try { + return (MemorySegment)SetupDiOpenDevRegKey$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, Scope, HwProfile, KeyType, samDesired); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + public static MemorySegment SetupDiGetClassDevsW(MemorySegment ClassGuid, MemorySegment Enumerator, + MemorySegment hwndParent, int Flags, MemorySegment lastErrorState) { + try { + return (MemorySegment)SetupDiGetClassDevsW$MH.invokeExact(lastErrorState, ClassGuid, Enumerator, hwndParent, Flags); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + /** + * {@snippet : + * BOOL SetupDiEnumDeviceInterfaces(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, const GUID* InterfaceClassGuid, DWORD MemberIndex, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData); + * } + */ + public static int SetupDiEnumDeviceInterfaces(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, + MemorySegment InterfaceClassGuid, int MemberIndex, + MemorySegment DeviceInterfaceData, MemorySegment lastErrorState) { + try { + return (int)SetupDiEnumDeviceInterfaces$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, + InterfaceClassGuid, MemberIndex, DeviceInterfaceData); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + /** + * {@snippet : + * BOOL SetupDiGetDeviceInterfaceDetailW(HDEVINFO DeviceInfoSet, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData, DWORD DeviceInterfaceDetailDataSize, PDWORD RequiredSize, PSP_DEVINFO_DATA DeviceInfoData); + * } + */ + public static int SetupDiGetDeviceInterfaceDetailW(MemorySegment DeviceInfoSet, MemorySegment DeviceInterfaceData, + MemorySegment DeviceInterfaceDetailData, int DeviceInterfaceDetailDataSize, + MemorySegment RequiredSize, MemorySegment DeviceInfoData, + MemorySegment lastErrorState) { + try { + return (int)SetupDiGetDeviceInterfaceDetailW$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInterfaceData, + DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java new file mode 100644 index 00000000..f5b488b0 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java @@ -0,0 +1,128 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +package net.codecrete.usb.windows.winsdk; + +import net.codecrete.usb.windows.Win; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.*; + +/** + * Native function calls for User32. + *

+ * This code is manually created to include the additional parameters for capturing + * {@code GetLastError()} until jextract catches up and can generate the corresponding code. + *

+ */ +public class User32B { + + static { + System.loadLibrary("User32"); + } + + private static final Linker LINKER = Linker.nativeLinker(); + private static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup(); + + private static final FunctionDescriptor RegisterClassExW$FUNC = FunctionDescriptor.of(JAVA_SHORT, ADDRESS); + + private static final MethodHandle RegisterClassExW$MH = LINKER.downcallHandle( + LOOKUP.find("RegisterClassExW").get(), + RegisterClassExW$FUNC, + Win.LAST_ERROR_STATE + ); + + private static final FunctionDescriptor CreateWindowExW$FUNC = + FunctionDescriptor.of(ADDRESS, JAVA_INT, ADDRESS, ADDRESS, JAVA_INT, JAVA_INT, JAVA_INT, JAVA_INT, + JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS); + + private static final MethodHandle CreateWindowExW$MH = LINKER.downcallHandle( + LOOKUP.find("CreateWindowExW").get(), + CreateWindowExW$FUNC, + Win.LAST_ERROR_STATE + ); + + private static final FunctionDescriptor RegisterDeviceNotificationW$FUNC = + FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, JAVA_INT); + + private static final MethodHandle RegisterDeviceNotificationW$MH = LINKER.downcallHandle( + LOOKUP.find("RegisterDeviceNotificationW").get(), + RegisterDeviceNotificationW$FUNC, + Win.LAST_ERROR_STATE + ); + + private static final FunctionDescriptor GetMessageW$FUNC = + FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, JAVA_INT, JAVA_INT); + + private static final MethodHandle GetMessageW$MH = LINKER.downcallHandle( + LOOKUP.find("GetMessageW").get(), + GetMessageW$FUNC, + Win.LAST_ERROR_STATE + ); + + /** + * {@snippet : + * ATOM RegisterClassExW(const WNDCLASSEXW* unnamedParam1); + * } + */ + public static short RegisterClassExW(MemorySegment unnamedParam1, MemorySegment lastErrorState) { + try { + return (short)RegisterClassExW$MH.invokeExact(lastErrorState, unnamedParam1); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + /** + * {@snippet : + * HWND CreateWindowExW(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam); + * } + */ + public static MemorySegment CreateWindowExW(int dwExStyle, MemorySegment lpClassName, MemorySegment lpWindowName, + int dwStyle, int X, int Y, int nWidth, int nHeight, + MemorySegment hWndParent, MemorySegment hMenu, MemorySegment hInstance, + MemorySegment lpParam, MemorySegment lastErrorState) { + try { + return (MemorySegment)CreateWindowExW$MH.invokeExact(lastErrorState, dwExStyle, lpClassName, lpWindowName, + dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + /** + * {@snippet : + * HDEVNOTIFY RegisterDeviceNotificationW(HANDLE hRecipient, LPVOID NotificationFilter, DWORD Flags); + * } + */ + public static MemorySegment RegisterDeviceNotificationW(MemorySegment hRecipient, MemorySegment NotificationFilter, + int Flags, MemorySegment lastErrorState) { + try { + return (MemorySegment)RegisterDeviceNotificationW$MH.invokeExact(lastErrorState, hRecipient, NotificationFilter, Flags); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + /** + * {@snippet : + * BOOL GetMessageW(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax); + * } + */ + public static int GetMessageW(MemorySegment lpMsg, MemorySegment hWnd, int wMsgFilterMin, int wMsgFilterMax, + MemorySegment lastErrorState) { + try { + return (int)GetMessageW$MH.invokeExact(lastErrorState, lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } +} From c4e2b04b9c922f5ff7c7dadcb23f648a7cb7da75 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 28 Dec 2022 22:01:17 +0100 Subject: [PATCH 173/433] Use capture state for GetLastError (part 2) --- java-does-usb/jextract/windows/gen_win.cmd | 18 -- .../usbstandard/ConfigurationDescriptor.java | 5 +- .../usb/usbstandard/DeviceDescriptor.java | 11 +- .../usb/usbstandard/EndpointDescriptor.java | 5 +- .../net/codecrete/usb/windows/USBHelper.java | 2 +- .../usb/windows/WindowsUSBDevice.java | 78 +++++---- .../usb/windows/WindowsUSBDeviceRegistry.java | 81 +++++---- .../usb/windows/WindowsUSBException.java | 12 -- .../usb/windows/gen/advapi32/Advapi32.java | 8 - .../usb/windows/gen/kernel32/Kernel32.java | 50 +----- .../usb/windows/gen/kernel32/constants$0.java | 45 ++--- .../usb/windows/gen/setupapi/SetupAPI.java | 72 -------- .../usb/windows/gen/setupapi/constants$0.java | 42 ----- .../usb/windows/gen/winusb/WinUSB.java | 144 ---------------- .../usb/windows/gen/winusb/constants$0.java | 49 ------ .../usb/windows/winsdk/Kernel32B.java | 75 +++++++++ .../usb/windows/winsdk/SetupAPI2.java | 156 ++++++++++------- .../codecrete/usb/windows/winsdk/User32B.java | 72 +++----- .../codecrete/usb/windows/winsdk/WinUSB2.java | 158 ++++++++++++++++++ 19 files changed, 474 insertions(+), 609 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index a09c5d30..f916dfc0 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -8,10 +8,7 @@ call %JEXTRACT% --source --output ../../src/main/java ^ -l Kernel32 ^ --header-class-name Kernel32 ^ --target-package net.codecrete.usb.windows.gen.kernel32 ^ - --include-function CreateFileW ^ --include-function CloseHandle ^ - --include-function DeviceIoControl ^ - --include-function GetLastError ^ --include-function GetModuleHandleW ^ --include-function FormatMessageW ^ --include-function LocalFree ^ @@ -45,10 +42,6 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --header-class-name SetupAPI ^ --target-package net.codecrete.usb.windows.gen.setupapi ^ --include-function SetupDiDestroyDeviceInfoList ^ - --include-function SetupDiGetDeviceRegistryPropertyW ^ - --include-function SetupDiOpenDeviceInterfaceW ^ - --include-function SetupDiCreateDeviceInfoList ^ - --include-function SetupDiOpenDeviceInfoW ^ --include-function SetupDiDeleteDeviceInterfaceData ^ --include-struct _SP_DEVINFO_DATA ^ --include-typedef SP_DEVINFO_DATA ^ @@ -60,7 +53,6 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-typedef DEVPROPKEY ^ --include-constant DIGCF_PRESENT ^ --include-constant DIGCF_DEVICEINTERFACE ^ - --include-constant SPDRP_ADDRESS ^ --include-constant DEVPROP_TYPE_UINT32 ^ --include-constant DEVPROP_TYPE_STRING ^ --include-constant DEVPROP_TYPEMOD_LIST ^ @@ -116,16 +108,7 @@ call %JEXTRACT% --source --output ../../src/main/java ^ -l Winusb ^ --header-class-name WinUSB ^ --target-package net.codecrete.usb.windows.gen.winusb ^ - --include-function WinUsb_Initialize ^ --include-function WinUsb_Free ^ - --include-function WinUsb_GetDescriptor ^ - --include-function WinUsb_ControlTransfer ^ - --include-function WinUsb_WritePipe ^ - --include-function WinUsb_ReadPipe ^ - --include-function WinUsb_GetAssociatedInterface ^ - --include-function WinUsb_SetPipePolicy ^ - --include-function WinUsb_SetCurrentAlternateSetting ^ - --include-function WinUsb_ResetPipe ^ --include-constant PIPE_TRANSFER_TIMEOUT ^ windows_headers.h @@ -138,7 +121,6 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --target-package net.codecrete.usb.windows.gen.advapi32 ^ --include-function RegQueryValueExW ^ --include-function RegCloseKey ^ - --include-constant REG_MULTI_SZ ^ --include-constant KEY_READ ^ windows_headers.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java index 6cb9001b..924f019d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java @@ -13,8 +13,7 @@ import static java.lang.foreign.MemoryLayout.PathElement.groupElement; import static java.lang.foreign.MemoryLayout.structLayout; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; +import static java.lang.foreign.ValueLayout.*; /** * USB configuration descriptor @@ -68,7 +67,7 @@ public int maxPower() { public static final GroupLayout LAYOUT = structLayout( JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName("bDescriptorType"), - JAVA_SHORT.withBitAlignment(8).withName("wTotalLength"), + JAVA_SHORT_UNALIGNED.withName("wTotalLength"), JAVA_BYTE.withName("bNumInterfaces"), JAVA_BYTE.withName("bConfigurationValue"), JAVA_BYTE.withName("iConfiguration"), diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java index eaaa83c3..8c3cc34e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java @@ -13,8 +13,7 @@ import static java.lang.foreign.MemoryLayout.PathElement.groupElement; import static java.lang.foreign.MemoryLayout.structLayout; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; +import static java.lang.foreign.ValueLayout.*; /** * USB device descriptor @@ -86,14 +85,14 @@ public int iSerialNumber() { public static final GroupLayout LAYOUT = structLayout( JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName("bDescriptorType"), - JAVA_SHORT.withBitAlignment(8).withName("bcdUSB"), + JAVA_SHORT_UNALIGNED.withName("bcdUSB"), JAVA_BYTE.withName("bDeviceClass"), JAVA_BYTE.withName("bDeviceSubClass"), JAVA_BYTE.withName("bDeviceProtocol"), JAVA_BYTE.withName("bMaxPacketSize0"), - JAVA_SHORT.withBitAlignment(8).withName("idVendor"), - JAVA_SHORT.withBitAlignment(8).withName("idProduct"), - JAVA_SHORT.withBitAlignment(8).withName("bcdDevice"), + JAVA_SHORT_UNALIGNED.withName("idVendor"), + JAVA_SHORT_UNALIGNED.withName("idProduct"), + JAVA_SHORT_UNALIGNED.withName("bcdDevice"), JAVA_BYTE.withName("iManufacturer"), JAVA_BYTE.withName("iProduct"), JAVA_BYTE.withName("iSerialNumber"), diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java index ae6b82a1..2c3364c3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java @@ -13,8 +13,7 @@ import static java.lang.foreign.MemoryLayout.PathElement.groupElement; import static java.lang.foreign.MemoryLayout.structLayout; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; +import static java.lang.foreign.ValueLayout.*; /** * USB endpoint descriptor @@ -60,7 +59,7 @@ public int interval() { JAVA_BYTE.withName("bDescriptorType"), JAVA_BYTE.withName("bEndpointAddress"), JAVA_BYTE.withName("bmAttributes"), - JAVA_SHORT.withBitAlignment(8).withName("wMaxPacketSize"), + JAVA_SHORT_UNALIGNED.withName("wMaxPacketSize"), JAVA_BYTE.withName("bInterval") ); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java index cd77f42d..d8072aaa 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java @@ -50,7 +50,7 @@ public class USBHelper { JAVA_BYTE.withName("CurrentConfigurationValue"), JAVA_BYTE.withName("Speed"), JAVA_BYTE.withName("DeviceIsHub"), - JAVA_SHORT.withBitAlignment(8).withName("DeviceAddress"), + JAVA_SHORT_UNALIGNED.withName("DeviceAddress"), JAVA_INT.withName("NumberOfOpenPipes"), JAVA_INT.withName("ConnectionStatus") // USB_PIPE_INFO PipeList[0] diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 8f50e7ca..97e5e564 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -12,6 +12,8 @@ import net.codecrete.usb.usbstandard.SetupPacket; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.winusb.WinUSB; +import net.codecrete.usb.windows.winsdk.Kernel32B; +import net.codecrete.usb.windows.winsdk.WinUSB2; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; @@ -103,16 +105,17 @@ public void claimInterface(int interfaceNumber) { try (var arena = Arena.openConfined()) { MemorySegment deviceHandle; + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); // open Windows device if needed if (firstIntfHandle.deviceHandle == null) { var pathSegment = Win.createSegmentFromString(firstIntfHandle.devicePath, arena); - deviceHandle = Kernel32.CreateFileW(pathSegment, Kernel32.GENERIC_WRITE() | Kernel32.GENERIC_READ(), + deviceHandle = Kernel32B.CreateFileW(pathSegment, Kernel32.GENERIC_WRITE() | Kernel32.GENERIC_READ(), Kernel32.FILE_SHARE_WRITE() | Kernel32.FILE_SHARE_READ(), NULL, Kernel32.OPEN_EXISTING(), - Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), NULL); + Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), NULL, lastErrorState); if (Win.IsInvalidHandle(deviceHandle)) - throwLastError("Cannot open USB device %s", firstIntfHandle.devicePath); + throwLastError(lastErrorState, "Cannot open USB device %s", firstIntfHandle.devicePath); } else { deviceHandle = firstIntfHandle.deviceHandle; } @@ -120,8 +123,8 @@ public void claimInterface(int interfaceNumber) { try { // open interface var interfaceHandleHolder = arena.allocate(ADDRESS); - if (WinUSB.WinUsb_Initialize(deviceHandle, interfaceHandleHolder) == 0) - throwLastError("Cannot open WinUSB device"); + if (WinUSB2.WinUsb_Initialize(deviceHandle, interfaceHandleHolder, lastErrorState) == 0) + throwLastError(lastErrorState, "Cannot open WinUSB device"); var interfaceHandle = interfaceHandleHolder.get(ADDRESS, 0); firstIntfHandle.deviceHandle = deviceHandle; @@ -152,9 +155,12 @@ public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { if (altSetting == null) throwException("Interface %d does not have an alternate interface setting %d", interfaceNumber, alternateNumber); - if (WinUSB.WinUsb_SetCurrentAlternateSetting(intfHandle.interfaceHandle, (byte) alternateNumber) == 0) - throwLastError("Failed to set alternate interface"); - + try (var arena = Arena.openConfined()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + if (WinUSB2.WinUsb_SetCurrentAlternateSetting(intfHandle.interfaceHandle, + (byte) alternateNumber, lastErrorState) == 0) + throwLastError(lastErrorState, "Failed to set alternate interface"); + } intf.setAlternate(altSetting); } @@ -183,8 +189,7 @@ public void releaseInterface(int interfaceNumber) { setClaimed(interfaceNumber, false); } - private MemorySegment createSetupPacket(Arena arena, USBDirection direction, USBControlTransfer setup, - MemorySegment data) { + private MemorySegment createSetupPacket(USBDirection direction, USBControlTransfer setup, MemorySegment data, Arena arena) { var setupPacket = new SetupPacket(arena); var bmRequest = (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); @@ -203,12 +208,13 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { try (var arena = Arena.openConfined()) { var buffer = arena.allocate(length); - var setupPacket = createSetupPacket(arena, USBDirection.IN, setup, buffer); + var setupPacket = createSetupPacket(USBDirection.IN, setup, buffer, arena); var lengthHolder = arena.allocate(JAVA_INT); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - if (WinUSB.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer, (int) buffer.byteSize(), - lengthHolder, NULL) == 0) - throwLastError("Control transfer IN failed"); + if (WinUSB2.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer, (int) buffer.byteSize(), + lengthHolder, NULL, lastErrorState) == 0) + throwLastError(lastErrorState, "Control transfer IN failed"); int rxLength = lengthHolder.get(JAVA_INT, 0); return buffer.asSlice(0, rxLength).toArray(JAVA_BYTE); @@ -229,12 +235,13 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { buffer.copyFrom(MemorySegment.ofArray(data)); // create setup packet - var setupPacket = createSetupPacket(arena, USBDirection.OUT, setup, buffer); + var setupPacket = createSetupPacket(USBDirection.OUT, setup, buffer, arena); var lengthHolder = arena.allocate(JAVA_INT); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - if (WinUSB.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer, (int) buffer.byteSize(), - lengthHolder, NULL) == 0) - throwLastError("Control transfer OUT failed"); + if (WinUSB2.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer, (int) buffer.byteSize(), + lengthHolder, NULL, lastErrorState) == 0) + throwLastError(lastErrorState, "Control transfer OUT failed"); } } @@ -248,9 +255,11 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { try (var arena = Arena.openConfined()) { // set timeout var timeoutHolder = arena.allocate(JAVA_INT, timeout); - if (WinUSB.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), - WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder) == 0) - throwLastError("Setting timeout failed"); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + + if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), + WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder, lastErrorState) == 0) + throwLastError(lastErrorState, "Setting timeout failed"); // copy data to native heap var buffer = arena.allocate(data.length); @@ -258,9 +267,9 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { var lengthHolder = arena.allocate(JAVA_INT); // send data - if (WinUSB.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, (int) buffer.byteSize(), - lengthHolder, NULL) == 0) { - int err = Kernel32.GetLastError(); + if (WinUSB2.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, (int) buffer.byteSize(), + lengthHolder, NULL, lastErrorState) == 0) { + int err = Win.getLastError(lastErrorState); if (err == Kernel32.ERROR_SEM_TIMEOUT()) throw new USBTimeoutException("Transfer out aborted due to timeout"); throwException(err, "Bulk/interrupt transfer OUT failed"); @@ -276,18 +285,19 @@ public byte[] transferIn(int endpointNumber, int timeout) { try (var arena = Arena.openConfined()) { // set timeout var timeoutHolder = arena.allocate(JAVA_INT, timeout); - if (WinUSB.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), - WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder) == 0) - throwLastError("Setting timeout failed"); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), + WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder, lastErrorState) == 0) + throwLastError(lastErrorState, "Setting timeout failed"); // create native heap buffer for data var buffer = arena.allocate(endpoint.packetSize()); var lengthHolder = arena.allocate(JAVA_INT); // receive data - if (WinUSB.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, (int) buffer.byteSize(), - lengthHolder, NULL) == 0) { - int err = Kernel32.GetLastError(); + if (WinUSB2.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, (int) buffer.byteSize(), + lengthHolder, NULL, lastErrorState) == 0) { + int err = Win.getLastError(lastErrorState); if (err == Kernel32.ERROR_SEM_TIMEOUT()) throw new USBTimeoutException("Transfer in aborted due to timeout"); throwException(err, "Bulk/interrupt transfer IN failed"); @@ -303,8 +313,12 @@ public byte[] transferIn(int endpointNumber, int timeout) { public void clearHalt(USBDirection direction, int endpointNumber) { var endpoint = getEndpoint(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); - if (WinUSB.WinUsb_ResetPipe(intfHandle.interfaceHandle, endpoint.endpointAddress()) == 0) - throwLastError("Clearing halt failed"); + + try (var arena = Arena.openConfined()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + if (WinUSB2.WinUsb_ResetPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), lastErrorState) == 0) + throwLastError(lastErrorState, "Clearing halt failed"); + } } private InterfaceHandle getInterfaceHandle(int interfaceNumber) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 5de5b731..0de36140 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -23,6 +23,7 @@ import net.codecrete.usb.windows.gen.setupapi.SetupAPI; import net.codecrete.usb.windows.gen.usbioctl.USBIoctl; import net.codecrete.usb.windows.gen.user32.*; +import net.codecrete.usb.windows.winsdk.Kernel32B; import net.codecrete.usb.windows.winsdk.SetupAPI2; import net.codecrete.usb.windows.winsdk.User32B; @@ -129,13 +130,7 @@ private void enumeratePresentDevices() { var lastErrorState = outerArena.allocate(Win.LAST_ERROR_STATE.layout()); // get device information set of all USB devices present - final var devInfoSetHandle = SetupAPI2.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, - NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), lastErrorState); - if (Win.IsInvalidHandle(devInfoSetHandle)) - throwLastError(lastErrorState, "internal error (SetupDiGetClassDevsW)"); - - // ensure the result is destroyed when the scope is left - outerCleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); + final var devInfoSetHandle = createDevInfoSet(outerCleanup, lastErrorState); var devInfo = outerArena.allocate(SP_DEVINFO_DATA.$LAYOUT()); SP_DEVINFO_DATA.cbSize$set(devInfo, (int) SP_DEVINFO_DATA.$LAYOUT().byteSize()); @@ -185,22 +180,28 @@ private Map enumerateChildren(List childrenIds) { // iterate all children for (var instanceId : childrenIds) { try (var arena = Arena.openConfined(); var cleanup = new ScopeCleanup()) { + + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + // create device info set - var devInfoSetHandle = SetupAPI.SetupDiCreateDeviceInfoList(NULL, NULL); + var devInfoSetHandle = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, lastErrorState); if (Win.IsInvalidHandle(devInfoSetHandle)) - throwLastError("Cannot create device info list"); + throwLastError(lastErrorState, "Cannot create device info list"); cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); // get device info for child var devInfo = arena.allocate(SP_DEVINFO_DATA.$LAYOUT()); SP_DEVINFO_DATA.cbSize$set(devInfo, (int) devInfo.byteSize()); var instanceIdSegment = Win.createSegmentFromString(instanceId, arena); - if (SetupAPI.SetupDiOpenDeviceInfoW(devInfoSetHandle, instanceIdSegment, NULL, 0, devInfo) == 0) - throwLastError("Internal error (SetupDiOpenDeviceInfoW)"); + if (SetupAPI2.SetupDiOpenDeviceInfoW(devInfoSetHandle, instanceIdSegment, NULL, 0, + devInfo, lastErrorState) == 0) + throwLastError(lastErrorState, "Internal error (SetupDiOpenDeviceInfoW)"); // get hardware IDs (to extract interface number) var hardwareIds = DeviceProperty.getDeviceStringListProperty(devInfoSetHandle, devInfo, DeviceProperty.DEVPKEY_Device_HardwareIds); + if (hardwareIds == null) + throwException("DEVPKEY_Device_HardwareIds not found"); int interfaceNumber = extractInterfaceNumber(hardwareIds); if (interfaceNumber == -1) continue; @@ -242,10 +243,11 @@ private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSetHandle, Mem var hubHandle = hubHandles.get(hubPath); if (hubHandle == null) { var hubPathSeg = Win.createSegmentFromString(hubPath, arena); - hubHandle = Kernel32.CreateFileW(hubPathSeg, Kernel32.GENERIC_WRITE(), Kernel32.FILE_SHARE_WRITE(), - NULL, Kernel32.OPEN_EXISTING(), 0, NULL); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + hubHandle = Kernel32B.CreateFileW(hubPathSeg, Kernel32.GENERIC_WRITE(), Kernel32.FILE_SHARE_WRITE(), + NULL, Kernel32.OPEN_EXISTING(), 0, NULL, lastErrorState); if (Win.IsInvalidHandle(hubHandle)) - throwLastError("Cannot open USB hub"); + throwLastError(lastErrorState, "Cannot open USB hub"); hubHandles.put(hubPath, hubHandle); } @@ -269,6 +271,7 @@ private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSetHandle, Mem // sleep and retry try { + //noinspection BusyWait Thread.sleep(200); } catch (InterruptedException e) { // ignore @@ -303,9 +306,10 @@ private USBDevice createDevice(String devicePath, Map children, var connInfo = arena.allocate(USBHelper.USB_NODE_CONNECTION_INFORMATION_EX$Struct); USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex.set(connInfo, usbPortNum); var sizeHolder = arena.allocate(JAVA_INT); - if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), connInfo - , (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL) == 0) - throwLastError("Internal error (cannot get device descriptor)"); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + if (Kernel32B.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), connInfo, + (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL, lastErrorState) == 0) + throwLastError(lastErrorState, "Internal error (cannot get device descriptor)"); var descriptorSegment = USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(connInfo); var deviceDescriptor = new DeviceDescriptor(descriptorSegment); @@ -347,9 +351,10 @@ private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, // execute request var effectiveSizeHolder = arena.allocate(JAVA_INT); - if (Kernel32.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION(), - descriptorRequest, size, descriptorRequest, size, effectiveSizeHolder, NULL) == 0) - throwLastError("Cannot retrieve descriptor %d", index); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + if (Kernel32B.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION(), + descriptorRequest, size, descriptorRequest, size, effectiveSizeHolder, NULL, lastErrorState) == 0) + throwLastError(lastErrorState, "Cannot retrieve descriptor %d", index); // determine size of descriptor int expectedSize; @@ -414,19 +419,14 @@ private void onDeviceConnected(String devicePath) { var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); // get device information set of all USB devices present - final var devInfoSetHandle = SetupAPI2.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, - NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), lastErrorState); - if (Win.IsInvalidHandle(devInfoSetHandle)) - throwLastError(lastErrorState, "internal error (SetupDiGetClassDevsW)"); - - // ensure the result is destroyed when the scope is left - cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); + final var devInfoSetHandle = createDevInfoSet(cleanup, lastErrorState); var devIntfData = arena.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); var devicePathSegment = Win.createSegmentFromString(devicePath, arena); - if (SetupAPI.SetupDiOpenDeviceInterfaceW(devInfoSetHandle, devicePathSegment, 0, devIntfData) == 0) - throwLastError("internal error (SetupDiOpenDeviceInterfaceW)"); + if (SetupAPI2.SetupDiOpenDeviceInterfaceW(devInfoSetHandle, devicePathSegment, 0, + devIntfData, lastErrorState) == 0) + throwLastError(lastErrorState, "internal error (SetupDiOpenDeviceInterfaceW)"); cleanup.add(() -> SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSetHandle, devIntfData)); @@ -489,6 +489,29 @@ private static boolean isCompositeDevice(String deviceService) { return "usbccgp".equalsIgnoreCase(deviceService); } + /** + * Creates a new device information set for USB devices. + *

+ * The info set is added to the cleanup object for later releasing. + * A native memory segment is passed to be used for the last error call state. + *

+ * @param cleanup cleanup handler + * @param lastErrorState memory segment for last error call state + * @return handle to device information set + */ + private static MemorySegment createDevInfoSet(ScopeCleanup cleanup, MemorySegment lastErrorState) { + // get device information set of all USB devices present + var devInfoSetHandle = SetupAPI2.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, + NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), lastErrorState); + if (Win.IsInvalidHandle(devInfoSetHandle)) + throwLastError(lastErrorState, "internal error (SetupDiGetClassDevsW)"); + + // ensure the result is destroyed when the scope is left + cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); + + return devInfoSetHandle; + } + private static final Pattern MULTIPLE_INTERFACE_ID = Pattern.compile("USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); private static int extractInterfaceNumber(List hardwareIds) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java index 6e0cb690..fcdbfb41 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java @@ -61,18 +61,6 @@ static void throwException(String message, Object... args) { throw new USBException(String.format(message, args)); } - /** - * Throws an exception for the last error. - *

- * The message of the last Windows error code is looked up and appended to the message. - *

- * @param message exception message format ({@link String#format(String, Object...)} style) - * @param args arguments for exception message - */ - static void throwLastError(String message, Object... args) { - throwException(Kernel32.GetLastError(), message, args); - } - /** * Throws an exception for the last error. *

diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java index 03c1a902..d90e6ad3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java @@ -56,14 +56,6 @@ public static int RegQueryValueExW(MemorySegment hKey, MemorySegment lpValueName public static int KEY_READ() { return (int)131097L; } - /** - * {@snippet : - * #define REG_MULTI_SZ 7 - * } - */ - public static int REG_MULTI_SZ() { - return (int)7L; - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java index 9cc743a7..5121c07f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -80,22 +80,6 @@ public static int FORMAT_MESSAGE_IGNORE_INSERTS() { public static int FORMAT_MESSAGE_FROM_SYSTEM() { return (int)4096L; } - public static MethodHandle CreateFileW$MH() { - return RuntimeHelper.requireNonNull(constants$0.CreateFileW$MH,"CreateFileW"); - } - /** - * {@snippet : - * HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); - * } - */ - public static MemorySegment CreateFileW(MemorySegment lpFileName, int dwDesiredAccess, int dwShareMode, MemorySegment lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, MemorySegment hTemplateFile) { - var mh$ = CreateFileW$MH(); - try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } public static MethodHandle CloseHandle$MH() { return RuntimeHelper.requireNonNull(constants$0.CloseHandle$MH,"CloseHandle"); } @@ -112,38 +96,6 @@ public static int CloseHandle(MemorySegment hObject) { throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle GetLastError$MH() { - return RuntimeHelper.requireNonNull(constants$0.GetLastError$MH,"GetLastError"); - } - /** - * {@snippet : - * DWORD GetLastError(); - * } - */ - public static int GetLastError() { - var mh$ = GetLastError$MH(); - try { - return (int)mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle DeviceIoControl$MH() { - return RuntimeHelper.requireNonNull(constants$0.DeviceIoControl$MH,"DeviceIoControl"); - } - /** - * {@snippet : - * BOOL DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped); - * } - */ - public static int DeviceIoControl(MemorySegment hDevice, int dwIoControlCode, MemorySegment lpInBuffer, int nInBufferSize, MemorySegment lpOutBuffer, int nOutBufferSize, MemorySegment lpBytesReturned, MemorySegment lpOverlapped) { - var mh$ = DeviceIoControl$MH(); - try { - return (int)mh$.invokeExact(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } public static MethodHandle GetModuleHandleW$MH() { return RuntimeHelper.requireNonNull(constants$0.GetModuleHandleW$MH,"GetModuleHandleW"); } @@ -177,7 +129,7 @@ public static MemorySegment LocalFree(MemorySegment hMem) { } } public static MethodHandle FormatMessageW$MH() { - return RuntimeHelper.requireNonNull(constants$1.FormatMessageW$MH,"FormatMessageW"); + return RuntimeHelper.requireNonNull(constants$0.FormatMessageW$MH,"FormatMessageW"); } /** * {@snippet : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java index b6ca6311..027db927 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java @@ -8,19 +8,6 @@ final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} - static final FunctionDescriptor CreateFileW$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle CreateFileW$MH = RuntimeHelper.downcallHandle( - "CreateFileW", - constants$0.CreateFileW$FUNC - ); static final FunctionDescriptor CloseHandle$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT ); @@ -28,25 +15,6 @@ final class constants$0 { "CloseHandle", constants$0.CloseHandle$FUNC ); - static final FunctionDescriptor GetLastError$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT); - static final MethodHandle GetLastError$MH = RuntimeHelper.downcallHandle( - "GetLastError", - constants$0.GetLastError$FUNC - ); - static final FunctionDescriptor DeviceIoControl$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle DeviceIoControl$MH = RuntimeHelper.downcallHandle( - "DeviceIoControl", - constants$0.DeviceIoControl$FUNC - ); static final FunctionDescriptor GetModuleHandleW$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT ); @@ -61,6 +29,19 @@ final class constants$0 { "LocalFree", constants$0.LocalFree$FUNC ); + static final FunctionDescriptor FormatMessageW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle FormatMessageW$MH = RuntimeHelper.downcallHandle( + "FormatMessageW", + constants$0.FormatMessageW$FUNC + ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java index 6cc609d7..bbf36562 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java @@ -72,38 +72,6 @@ public static int DIGCF_DEVICEINTERFACE() { public static int DIREG_DEV() { return (int)1L; } - public static MethodHandle SetupDiCreateDeviceInfoList$MH() { - return RuntimeHelper.requireNonNull(constants$0.SetupDiCreateDeviceInfoList$MH,"SetupDiCreateDeviceInfoList"); - } - /** - * {@snippet : - * HDEVINFO SetupDiCreateDeviceInfoList(const GUID* ClassGuid, HWND hwndParent); - * } - */ - public static MemorySegment SetupDiCreateDeviceInfoList(MemorySegment ClassGuid, MemorySegment hwndParent) { - var mh$ = SetupDiCreateDeviceInfoList$MH(); - try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(ClassGuid, hwndParent); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle SetupDiOpenDeviceInfoW$MH() { - return RuntimeHelper.requireNonNull(constants$0.SetupDiOpenDeviceInfoW$MH,"SetupDiOpenDeviceInfoW"); - } - /** - * {@snippet : - * BOOL SetupDiOpenDeviceInfoW(HDEVINFO DeviceInfoSet, PCWSTR DeviceInstanceId, HWND hwndParent, DWORD OpenFlags, PSP_DEVINFO_DATA DeviceInfoData); - * } - */ - public static int SetupDiOpenDeviceInfoW(MemorySegment DeviceInfoSet, MemorySegment DeviceInstanceId, MemorySegment hwndParent, int OpenFlags, MemorySegment DeviceInfoData) { - var mh$ = SetupDiOpenDeviceInfoW$MH(); - try { - return (int)mh$.invokeExact(DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } public static MethodHandle SetupDiDestroyDeviceInfoList$MH() { return RuntimeHelper.requireNonNull(constants$0.SetupDiDestroyDeviceInfoList$MH,"SetupDiDestroyDeviceInfoList"); } @@ -120,22 +88,6 @@ public static int SetupDiDestroyDeviceInfoList(MemorySegment DeviceInfoSet) { throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle SetupDiOpenDeviceInterfaceW$MH() { - return RuntimeHelper.requireNonNull(constants$0.SetupDiOpenDeviceInterfaceW$MH,"SetupDiOpenDeviceInterfaceW"); - } - /** - * {@snippet : - * BOOL SetupDiOpenDeviceInterfaceW(HDEVINFO DeviceInfoSet, PCWSTR DevicePath, DWORD OpenFlags, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData); - * } - */ - public static int SetupDiOpenDeviceInterfaceW(MemorySegment DeviceInfoSet, MemorySegment DevicePath, int OpenFlags, MemorySegment DeviceInterfaceData) { - var mh$ = SetupDiOpenDeviceInterfaceW$MH(); - try { - return (int)mh$.invokeExact(DeviceInfoSet, DevicePath, OpenFlags, DeviceInterfaceData); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } public static MethodHandle SetupDiDeleteDeviceInterfaceData$MH() { return RuntimeHelper.requireNonNull(constants$0.SetupDiDeleteDeviceInterfaceData$MH,"SetupDiDeleteDeviceInterfaceData"); } @@ -152,30 +104,6 @@ public static int SetupDiDeleteDeviceInterfaceData(MemorySegment DeviceInfoSet, throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle SetupDiGetDeviceRegistryPropertyW$MH() { - return RuntimeHelper.requireNonNull(constants$0.SetupDiGetDeviceRegistryPropertyW$MH,"SetupDiGetDeviceRegistryPropertyW"); - } - /** - * {@snippet : - * BOOL SetupDiGetDeviceRegistryPropertyW(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, PDWORD PropertyRegDataType, PBYTE PropertyBuffer, DWORD PropertyBufferSize, PDWORD RequiredSize); - * } - */ - public static int SetupDiGetDeviceRegistryPropertyW(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, int Property, MemorySegment PropertyRegDataType, MemorySegment PropertyBuffer, int PropertyBufferSize, MemorySegment RequiredSize) { - var mh$ = SetupDiGetDeviceRegistryPropertyW$MH(); - try { - return (int)mh$.invokeExact(DeviceInfoSet, DeviceInfoData, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - /** - * {@snippet : - * #define SPDRP_ADDRESS 28 - * } - */ - public static int SPDRP_ADDRESS() { - return (int)28L; - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java index c0abf521..749bd392 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java @@ -8,25 +8,6 @@ final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} - static final FunctionDescriptor SetupDiCreateDeviceInfoList$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle SetupDiCreateDeviceInfoList$MH = RuntimeHelper.downcallHandle( - "SetupDiCreateDeviceInfoList", - constants$0.SetupDiCreateDeviceInfoList$FUNC - ); - static final FunctionDescriptor SetupDiOpenDeviceInfoW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle SetupDiOpenDeviceInfoW$MH = RuntimeHelper.downcallHandle( - "SetupDiOpenDeviceInfoW", - constants$0.SetupDiOpenDeviceInfoW$FUNC - ); static final FunctionDescriptor SetupDiDestroyDeviceInfoList$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT ); @@ -34,16 +15,6 @@ final class constants$0 { "SetupDiDestroyDeviceInfoList", constants$0.SetupDiDestroyDeviceInfoList$FUNC ); - static final FunctionDescriptor SetupDiOpenDeviceInterfaceW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle SetupDiOpenDeviceInterfaceW$MH = RuntimeHelper.downcallHandle( - "SetupDiOpenDeviceInterfaceW", - constants$0.SetupDiOpenDeviceInterfaceW$FUNC - ); static final FunctionDescriptor SetupDiDeleteDeviceInterfaceData$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT @@ -52,19 +23,6 @@ final class constants$0 { "SetupDiDeleteDeviceInterfaceData", constants$0.SetupDiDeleteDeviceInterfaceData$FUNC ); - static final FunctionDescriptor SetupDiGetDeviceRegistryPropertyW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle SetupDiGetDeviceRegistryPropertyW$MH = RuntimeHelper.downcallHandle( - "SetupDiGetDeviceRegistryPropertyW", - constants$0.SetupDiGetDeviceRegistryPropertyW$FUNC - ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java index 444f9385..3af32d2b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java @@ -24,22 +24,6 @@ public class WinUSB { public static int PIPE_TRANSFER_TIMEOUT() { return (int)3L; } - public static MethodHandle WinUsb_Initialize$MH() { - return RuntimeHelper.requireNonNull(constants$0.WinUsb_Initialize$MH,"WinUsb_Initialize"); - } - /** - * {@snippet : - * BOOL WinUsb_Initialize(HANDLE DeviceHandle, PWINUSB_INTERFACE_HANDLE InterfaceHandle); - * } - */ - public static int WinUsb_Initialize(MemorySegment DeviceHandle, MemorySegment InterfaceHandle) { - var mh$ = WinUsb_Initialize$MH(); - try { - return (int)mh$.invokeExact(DeviceHandle, InterfaceHandle); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } public static MethodHandle WinUsb_Free$MH() { return RuntimeHelper.requireNonNull(constants$0.WinUsb_Free$MH,"WinUsb_Free"); } @@ -56,134 +40,6 @@ public static int WinUsb_Free(MemorySegment InterfaceHandle) { throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle WinUsb_GetAssociatedInterface$MH() { - return RuntimeHelper.requireNonNull(constants$0.WinUsb_GetAssociatedInterface$MH,"WinUsb_GetAssociatedInterface"); - } - /** - * {@snippet : - * BOOL WinUsb_GetAssociatedInterface(WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR AssociatedInterfaceIndex, PWINUSB_INTERFACE_HANDLE AssociatedInterfaceHandle); - * } - */ - public static int WinUsb_GetAssociatedInterface(MemorySegment InterfaceHandle, byte AssociatedInterfaceIndex, MemorySegment AssociatedInterfaceHandle) { - var mh$ = WinUsb_GetAssociatedInterface$MH(); - try { - return (int)mh$.invokeExact(InterfaceHandle, AssociatedInterfaceIndex, AssociatedInterfaceHandle); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle WinUsb_GetDescriptor$MH() { - return RuntimeHelper.requireNonNull(constants$0.WinUsb_GetDescriptor$MH,"WinUsb_GetDescriptor"); - } - /** - * {@snippet : - * BOOL WinUsb_GetDescriptor(WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR DescriptorType, UCHAR Index, USHORT LanguageID, PUCHAR Buffer, ULONG BufferLength, PULONG LengthTransferred); - * } - */ - public static int WinUsb_GetDescriptor(MemorySegment InterfaceHandle, byte DescriptorType, byte Index, short LanguageID, MemorySegment Buffer, int BufferLength, MemorySegment LengthTransferred) { - var mh$ = WinUsb_GetDescriptor$MH(); - try { - return (int)mh$.invokeExact(InterfaceHandle, DescriptorType, Index, LanguageID, Buffer, BufferLength, LengthTransferred); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle WinUsb_SetCurrentAlternateSetting$MH() { - return RuntimeHelper.requireNonNull(constants$0.WinUsb_SetCurrentAlternateSetting$MH,"WinUsb_SetCurrentAlternateSetting"); - } - /** - * {@snippet : - * BOOL WinUsb_SetCurrentAlternateSetting(WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR SettingNumber); - * } - */ - public static int WinUsb_SetCurrentAlternateSetting(MemorySegment InterfaceHandle, byte SettingNumber) { - var mh$ = WinUsb_SetCurrentAlternateSetting$MH(); - try { - return (int)mh$.invokeExact(InterfaceHandle, SettingNumber); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle WinUsb_SetPipePolicy$MH() { - return RuntimeHelper.requireNonNull(constants$0.WinUsb_SetPipePolicy$MH,"WinUsb_SetPipePolicy"); - } - /** - * {@snippet : - * BOOL WinUsb_SetPipePolicy(WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR PipeID, ULONG PolicyType, ULONG ValueLength, PVOID Value); - * } - */ - public static int WinUsb_SetPipePolicy(MemorySegment InterfaceHandle, byte PipeID, int PolicyType, int ValueLength, MemorySegment Value) { - var mh$ = WinUsb_SetPipePolicy$MH(); - try { - return (int)mh$.invokeExact(InterfaceHandle, PipeID, PolicyType, ValueLength, Value); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle WinUsb_ReadPipe$MH() { - return RuntimeHelper.requireNonNull(constants$1.WinUsb_ReadPipe$MH,"WinUsb_ReadPipe"); - } - /** - * {@snippet : - * BOOL WinUsb_ReadPipe(WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR PipeID, PUCHAR Buffer, ULONG BufferLength, PULONG LengthTransferred, LPOVERLAPPED Overlapped); - * } - */ - public static int WinUsb_ReadPipe(MemorySegment InterfaceHandle, byte PipeID, MemorySegment Buffer, int BufferLength, MemorySegment LengthTransferred, MemorySegment Overlapped) { - var mh$ = WinUsb_ReadPipe$MH(); - try { - return (int)mh$.invokeExact(InterfaceHandle, PipeID, Buffer, BufferLength, LengthTransferred, Overlapped); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle WinUsb_WritePipe$MH() { - return RuntimeHelper.requireNonNull(constants$1.WinUsb_WritePipe$MH,"WinUsb_WritePipe"); - } - /** - * {@snippet : - * BOOL WinUsb_WritePipe(WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR PipeID, PUCHAR Buffer, ULONG BufferLength, PULONG LengthTransferred, LPOVERLAPPED Overlapped); - * } - */ - public static int WinUsb_WritePipe(MemorySegment InterfaceHandle, byte PipeID, MemorySegment Buffer, int BufferLength, MemorySegment LengthTransferred, MemorySegment Overlapped) { - var mh$ = WinUsb_WritePipe$MH(); - try { - return (int)mh$.invokeExact(InterfaceHandle, PipeID, Buffer, BufferLength, LengthTransferred, Overlapped); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle WinUsb_ControlTransfer$MH() { - return RuntimeHelper.requireNonNull(constants$1.WinUsb_ControlTransfer$MH,"WinUsb_ControlTransfer"); - } - /** - * {@snippet : - * BOOL WinUsb_ControlTransfer(WINUSB_INTERFACE_HANDLE InterfaceHandle, WINUSB_SETUP_PACKET SetupPacket, PUCHAR Buffer, ULONG BufferLength, PULONG LengthTransferred, LPOVERLAPPED Overlapped); - * } - */ - public static int WinUsb_ControlTransfer(MemorySegment InterfaceHandle, MemorySegment SetupPacket, MemorySegment Buffer, int BufferLength, MemorySegment LengthTransferred, MemorySegment Overlapped) { - var mh$ = WinUsb_ControlTransfer$MH(); - try { - return (int)mh$.invokeExact(InterfaceHandle, SetupPacket, Buffer, BufferLength, LengthTransferred, Overlapped); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - public static MethodHandle WinUsb_ResetPipe$MH() { - return RuntimeHelper.requireNonNull(constants$1.WinUsb_ResetPipe$MH,"WinUsb_ResetPipe"); - } - /** - * {@snippet : - * BOOL WinUsb_ResetPipe(WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR PipeID); - * } - */ - public static int WinUsb_ResetPipe(MemorySegment InterfaceHandle, byte PipeID) { - var mh$ = WinUsb_ResetPipe$MH(); - try { - return (int)mh$.invokeExact(InterfaceHandle, PipeID); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java index 95c57ad9..2b90b7fb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java @@ -8,14 +8,6 @@ final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} - static final FunctionDescriptor WinUsb_Initialize$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle WinUsb_Initialize$MH = RuntimeHelper.downcallHandle( - "WinUsb_Initialize", - constants$0.WinUsb_Initialize$FUNC - ); static final FunctionDescriptor WinUsb_Free$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT ); @@ -23,47 +15,6 @@ final class constants$0 { "WinUsb_Free", constants$0.WinUsb_Free$FUNC ); - static final FunctionDescriptor WinUsb_GetAssociatedInterface$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle WinUsb_GetAssociatedInterface$MH = RuntimeHelper.downcallHandle( - "WinUsb_GetAssociatedInterface", - constants$0.WinUsb_GetAssociatedInterface$FUNC - ); - static final FunctionDescriptor WinUsb_GetDescriptor$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_SHORT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle WinUsb_GetDescriptor$MH = RuntimeHelper.downcallHandle( - "WinUsb_GetDescriptor", - constants$0.WinUsb_GetDescriptor$FUNC - ); - static final FunctionDescriptor WinUsb_SetCurrentAlternateSetting$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT - ); - static final MethodHandle WinUsb_SetCurrentAlternateSetting$MH = RuntimeHelper.downcallHandle( - "WinUsb_SetCurrentAlternateSetting", - constants$0.WinUsb_SetCurrentAlternateSetting$FUNC - ); - static final FunctionDescriptor WinUsb_SetPipePolicy$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle WinUsb_SetPipePolicy$MH = RuntimeHelper.downcallHandle( - "WinUsb_SetPipePolicy", - constants$0.WinUsb_SetPipePolicy$FUNC - ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java new file mode 100644 index 00000000..ac40c327 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java @@ -0,0 +1,75 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +package net.codecrete.usb.windows.winsdk; + +import net.codecrete.usb.windows.Win; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; + +/** + * Native function calls for Kernel32. + *

+ * This code is manually created to include the additional parameters for capturing + * {@code GetLastError()} until jextract catches up and can generate the corresponding code. + *

+ */ +public class Kernel32B { + static { + System.loadLibrary("Kernel32"); + } + + private static final Linker LINKER = Linker.nativeLinker(); + private static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup(); + + + private static final FunctionDescriptor CreateFileW$FUNC = + FunctionDescriptor.of(ADDRESS, ADDRESS, JAVA_INT, JAVA_INT, ADDRESS, JAVA_INT, JAVA_INT, ADDRESS); + + private static final MethodHandle CreateFileW$MH = LINKER.downcallHandle( + LOOKUP.find("CreateFileW").get(), + CreateFileW$FUNC, + Win.LAST_ERROR_STATE + ); + + public static MemorySegment CreateFileW(MemorySegment lpFileName, int dwDesiredAccess, int dwShareMode, + MemorySegment lpSecurityAttributes, int dwCreationDisposition, + int dwFlagsAndAttributes, MemorySegment hTemplateFile, + MemorySegment lastErrorState) { + try { + return (MemorySegment)CreateFileW$MH.invokeExact(lastErrorState, lpFileName, dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + private static final FunctionDescriptor DeviceIoControl$FUNC = + FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT, ADDRESS, JAVA_INT, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); + + private static final MethodHandle DeviceIoControl$MH = LINKER.downcallHandle( + LOOKUP.find("DeviceIoControl").get(), + DeviceIoControl$FUNC, + Win.LAST_ERROR_STATE + ); + + public static int DeviceIoControl(MemorySegment hDevice, int dwIoControlCode, MemorySegment lpInBuffer, + int nInBufferSize, MemorySegment lpOutBuffer, int nOutBufferSize, + MemorySegment lpBytesReturned, MemorySegment lpOverlapped, MemorySegment lastErrorState) { + try { + return (int)DeviceIoControl$MH.invokeExact(lastErrorState, hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java index 860483a8..b4ba3b84 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java @@ -42,6 +42,19 @@ public class SetupAPI2 { Win.LAST_ERROR_STATE ); + public static int SetupDiGetDevicePropertyW(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, + MemorySegment PropertyKey, MemorySegment PropertyType, + MemorySegment PropertyBuffer, int PropertyBufferSize, + MemorySegment RequiredSize, int Flags, + MemorySegment lastErrorState) { + try { + return (int)SetupDiGetDevicePropertyW$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, + PropertyKey, PropertyType, PropertyBuffer, PropertyBufferSize, RequiredSize, Flags); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + private static final FunctionDescriptor SetupDiEnumDeviceInfo$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT, ADDRESS); @@ -51,6 +64,15 @@ public class SetupAPI2 { Win.LAST_ERROR_STATE ); + public static int SetupDiEnumDeviceInfo(MemorySegment DeviceInfoSet, int MemberIndex, MemorySegment DeviceInfoData, + MemorySegment lastErrorState) { + try { + return (int)SetupDiEnumDeviceInfo$MH.invokeExact(lastErrorState, DeviceInfoSet, MemberIndex, DeviceInfoData); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + private static final FunctionDescriptor SetupDiOpenDevRegKey$FUNC = FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, JAVA_INT, JAVA_INT, JAVA_INT, JAVA_INT); @@ -60,6 +82,16 @@ public class SetupAPI2 { Win.LAST_ERROR_STATE ); + public static MemorySegment SetupDiOpenDevRegKey(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, + int Scope, int HwProfile, int KeyType, int samDesired, + MemorySegment lastErrorState) { + try { + return (MemorySegment)SetupDiOpenDevRegKey$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, Scope, HwProfile, KeyType, samDesired); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + private static final FunctionDescriptor SetupDiGetClassDevsW$FUNC = FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, ADDRESS, JAVA_INT); @@ -69,6 +101,15 @@ public class SetupAPI2 { Win.LAST_ERROR_STATE ); + public static MemorySegment SetupDiGetClassDevsW(MemorySegment ClassGuid, MemorySegment Enumerator, + MemorySegment hwndParent, int Flags, MemorySegment lastErrorState) { + try { + return (MemorySegment)SetupDiGetClassDevsW$MH.invokeExact(lastErrorState, ClassGuid, Enumerator, hwndParent, Flags); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + private static final FunctionDescriptor SetupDiEnumDeviceInterfaces$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS); @@ -78,6 +119,17 @@ public class SetupAPI2 { Win.LAST_ERROR_STATE ); + public static int SetupDiEnumDeviceInterfaces(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, + MemorySegment InterfaceClassGuid, int MemberIndex, + MemorySegment DeviceInterfaceData, MemorySegment lastErrorState) { + try { + return (int)SetupDiEnumDeviceInterfaces$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, + InterfaceClassGuid, MemberIndex, DeviceInterfaceData); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + private static final FunctionDescriptor SetupDiGetDeviceInterfaceDetailW$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); @@ -87,93 +139,71 @@ public class SetupAPI2 { Win.LAST_ERROR_STATE ); - - /** - * {@snippet lang=c : - * BOOL SetupDiGetDevicePropertyW(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, const DEVPROPKEY* PropertyKey, DEVPROPTYPE* PropertyType, PBYTE PropertyBuffer, DWORD PropertyBufferSize, PDWORD RequiredSize, DWORD Flags); - * } - */ - public static int SetupDiGetDevicePropertyW(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, - MemorySegment PropertyKey, MemorySegment PropertyType, - MemorySegment PropertyBuffer, int PropertyBufferSize, - MemorySegment RequiredSize, int Flags, - MemorySegment lastErrorState) { + public static int SetupDiGetDeviceInterfaceDetailW(MemorySegment DeviceInfoSet, MemorySegment DeviceInterfaceData, + MemorySegment DeviceInterfaceDetailData, int DeviceInterfaceDetailDataSize, + MemorySegment RequiredSize, MemorySegment DeviceInfoData, + MemorySegment lastErrorState) { try { - return (int)SetupDiGetDevicePropertyW$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, - PropertyKey, PropertyType, PropertyBuffer, PropertyBufferSize, RequiredSize, Flags); + return (int)SetupDiGetDeviceInterfaceDetailW$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInterfaceData, + DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData); } catch (Throwable ex) { throw new RuntimeException(ex); } } - /** - * {@snippet lang=c : - * BOOL SetupDiEnumDeviceInfo(HDEVINFO DeviceInfoSet, DWORD MemberIndex, PSP_DEVINFO_DATA DeviceInfoData); - * } - */ - public static int SetupDiEnumDeviceInfo(MemorySegment DeviceInfoSet, int MemberIndex, MemorySegment DeviceInfoData, - MemorySegment lastErrorState) { - try { - return (int)SetupDiEnumDeviceInfo$MH.invokeExact(lastErrorState, DeviceInfoSet, MemberIndex, DeviceInfoData); - } catch (Throwable ex) { - throw new RuntimeException(ex); - } - } + private static final FunctionDescriptor SetupDiCreateDeviceInfoList$FUNC = + FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS); - /** - * {@snippet lang=c : - * HDEVINFO SetupDiGetClassDevsW(const GUID* ClassGuid, PCWSTR Enumerator, HWND hwndParent, DWORD Flags); - * } - */ - public static MemorySegment SetupDiOpenDevRegKey(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, - int Scope, int HwProfile, int KeyType, int samDesired, - MemorySegment lastErrorState) { + private static final MethodHandle SetupDiCreateDeviceInfoList$MH = LINKER.downcallHandle( + LOOKUP.find("SetupDiCreateDeviceInfoList").get(), + SetupDiCreateDeviceInfoList$FUNC, + Win.LAST_ERROR_STATE + ); + + public static MemorySegment SetupDiCreateDeviceInfoList(MemorySegment ClassGuid, MemorySegment hwndParent, + MemorySegment lastErrorState) { try { - return (MemorySegment)SetupDiOpenDevRegKey$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, Scope, HwProfile, KeyType, samDesired); + return (MemorySegment)SetupDiCreateDeviceInfoList$MH.invokeExact(lastErrorState, ClassGuid, hwndParent); } catch (Throwable ex) { throw new RuntimeException(ex); } } - public static MemorySegment SetupDiGetClassDevsW(MemorySegment ClassGuid, MemorySegment Enumerator, - MemorySegment hwndParent, int Flags, MemorySegment lastErrorState) { + private static final FunctionDescriptor SetupDiOpenDeviceInfoW$FUNC = + FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS ); + + private static final MethodHandle SetupDiOpenDeviceInfoW$MH = LINKER.downcallHandle( + LOOKUP.find("SetupDiOpenDeviceInfoW").get(), + SetupDiOpenDeviceInfoW$FUNC, + Win.LAST_ERROR_STATE + ); + + public static int SetupDiOpenDeviceInfoW(MemorySegment DeviceInfoSet, MemorySegment DeviceInstanceId, + MemorySegment hwndParent, int OpenFlags, MemorySegment DeviceInfoData, + MemorySegment lastErrorState) { try { - return (MemorySegment)SetupDiGetClassDevsW$MH.invokeExact(lastErrorState, ClassGuid, Enumerator, hwndParent, Flags); + return (int)SetupDiOpenDeviceInfoW$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData); } catch (Throwable ex) { throw new RuntimeException(ex); } } - /** - * {@snippet : - * BOOL SetupDiEnumDeviceInterfaces(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, const GUID* InterfaceClassGuid, DWORD MemberIndex, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData); - * } - */ - public static int SetupDiEnumDeviceInterfaces(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, - MemorySegment InterfaceClassGuid, int MemberIndex, + private static final FunctionDescriptor SetupDiOpenDeviceInterfaceW$FUNC = + FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, JAVA_INT, ADDRESS); + + private static final MethodHandle SetupDiOpenDeviceInterfaceW$MH = LINKER.downcallHandle( + LOOKUP.find("SetupDiOpenDeviceInterfaceW").get(), + SetupDiOpenDeviceInterfaceW$FUNC, + Win.LAST_ERROR_STATE + ); + + public static int SetupDiOpenDeviceInterfaceW(MemorySegment DeviceInfoSet, MemorySegment DevicePath, int OpenFlags, MemorySegment DeviceInterfaceData, MemorySegment lastErrorState) { try { - return (int)SetupDiEnumDeviceInterfaces$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, - InterfaceClassGuid, MemberIndex, DeviceInterfaceData); + return (int)SetupDiOpenDeviceInterfaceW$MH.invokeExact(lastErrorState, DeviceInfoSet, DevicePath, OpenFlags, DeviceInterfaceData); } catch (Throwable ex) { throw new RuntimeException(ex); } } - /** - * {@snippet : - * BOOL SetupDiGetDeviceInterfaceDetailW(HDEVINFO DeviceInfoSet, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData, DWORD DeviceInterfaceDetailDataSize, PDWORD RequiredSize, PSP_DEVINFO_DATA DeviceInfoData); - * } - */ - public static int SetupDiGetDeviceInterfaceDetailW(MemorySegment DeviceInfoSet, MemorySegment DeviceInterfaceData, - MemorySegment DeviceInterfaceDetailData, int DeviceInterfaceDetailDataSize, - MemorySegment RequiredSize, MemorySegment DeviceInfoData, - MemorySegment lastErrorState) { - try { - return (int)SetupDiGetDeviceInterfaceDetailW$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInterfaceData, - DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData); - } catch (Throwable ex) { - throw new RuntimeException(ex); - } - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java index f5b488b0..89ecf892 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java @@ -40,6 +40,14 @@ public class User32B { Win.LAST_ERROR_STATE ); + public static short RegisterClassExW(MemorySegment unnamedParam1, MemorySegment lastErrorState) { + try { + return (short)RegisterClassExW$MH.invokeExact(lastErrorState, unnamedParam1); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + private static final FunctionDescriptor CreateWindowExW$FUNC = FunctionDescriptor.of(ADDRESS, JAVA_INT, ADDRESS, ADDRESS, JAVA_INT, JAVA_INT, JAVA_INT, JAVA_INT, JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS); @@ -50,42 +58,6 @@ public class User32B { Win.LAST_ERROR_STATE ); - private static final FunctionDescriptor RegisterDeviceNotificationW$FUNC = - FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, JAVA_INT); - - private static final MethodHandle RegisterDeviceNotificationW$MH = LINKER.downcallHandle( - LOOKUP.find("RegisterDeviceNotificationW").get(), - RegisterDeviceNotificationW$FUNC, - Win.LAST_ERROR_STATE - ); - - private static final FunctionDescriptor GetMessageW$FUNC = - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, JAVA_INT, JAVA_INT); - - private static final MethodHandle GetMessageW$MH = LINKER.downcallHandle( - LOOKUP.find("GetMessageW").get(), - GetMessageW$FUNC, - Win.LAST_ERROR_STATE - ); - - /** - * {@snippet : - * ATOM RegisterClassExW(const WNDCLASSEXW* unnamedParam1); - * } - */ - public static short RegisterClassExW(MemorySegment unnamedParam1, MemorySegment lastErrorState) { - try { - return (short)RegisterClassExW$MH.invokeExact(lastErrorState, unnamedParam1); - } catch (Throwable ex) { - throw new RuntimeException(ex); - } - } - - /** - * {@snippet : - * HWND CreateWindowExW(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam); - * } - */ public static MemorySegment CreateWindowExW(int dwExStyle, MemorySegment lpClassName, MemorySegment lpWindowName, int dwStyle, int X, int Y, int nWidth, int nHeight, MemorySegment hWndParent, MemorySegment hMenu, MemorySegment hInstance, @@ -98,11 +70,15 @@ public static MemorySegment CreateWindowExW(int dwExStyle, MemorySegment lpClass } } - /** - * {@snippet : - * HDEVNOTIFY RegisterDeviceNotificationW(HANDLE hRecipient, LPVOID NotificationFilter, DWORD Flags); - * } - */ + private static final FunctionDescriptor RegisterDeviceNotificationW$FUNC = + FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, JAVA_INT); + + private static final MethodHandle RegisterDeviceNotificationW$MH = LINKER.downcallHandle( + LOOKUP.find("RegisterDeviceNotificationW").get(), + RegisterDeviceNotificationW$FUNC, + Win.LAST_ERROR_STATE + ); + public static MemorySegment RegisterDeviceNotificationW(MemorySegment hRecipient, MemorySegment NotificationFilter, int Flags, MemorySegment lastErrorState) { try { @@ -112,11 +88,15 @@ public static MemorySegment RegisterDeviceNotificationW(MemorySegment hRecipient } } - /** - * {@snippet : - * BOOL GetMessageW(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax); - * } - */ + private static final FunctionDescriptor GetMessageW$FUNC = + FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, JAVA_INT, JAVA_INT); + + private static final MethodHandle GetMessageW$MH = LINKER.downcallHandle( + LOOKUP.find("GetMessageW").get(), + GetMessageW$FUNC, + Win.LAST_ERROR_STATE + ); + public static int GetMessageW(MemorySegment lpMsg, MemorySegment hWnd, int wMsgFilterMin, int wMsgFilterMax, MemorySegment lastErrorState) { try { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java new file mode 100644 index 00000000..da78af10 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java @@ -0,0 +1,158 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +package net.codecrete.usb.windows.winsdk; + +import net.codecrete.usb.usbstandard.SetupPacket; +import net.codecrete.usb.windows.Win; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.*; + +/** + * Native function calls for WinUSB. + *

+ * This code is manually created to include the additional parameters for capturing + * {@code GetLastError()} until jextract catches up and can generate the corresponding code. + *

+ */ +public class WinUSB2 { + static { + System.loadLibrary("Winusb"); + } + + private static final Linker LINKER = Linker.nativeLinker(); + private static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup(); + + + private static final FunctionDescriptor WinUsb_Initialize$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS); + + private static final MethodHandle WinUsb_Initialize$MH = LINKER.downcallHandle( + LOOKUP.find("WinUsb_Initialize").get(), + WinUsb_Initialize$FUNC, + Win.LAST_ERROR_STATE + ); + + public static int WinUsb_Initialize(MemorySegment DeviceHandle, MemorySegment InterfaceHandle, MemorySegment lastErrorState) { + try { + return (int)WinUsb_Initialize$MH.invokeExact(lastErrorState, DeviceHandle, InterfaceHandle); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + private static final FunctionDescriptor WinUsb_SetCurrentAlternateSetting$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE); + + private static final MethodHandle WinUsb_SetCurrentAlternateSetting$MH = LINKER.downcallHandle( + LOOKUP.find("WinUsb_SetCurrentAlternateSetting").get(), + WinUsb_SetCurrentAlternateSetting$FUNC, + Win.LAST_ERROR_STATE + ); + + public static int WinUsb_SetCurrentAlternateSetting(MemorySegment InterfaceHandle, byte SettingNumber, MemorySegment lastErrorState) { + try { + return (int)WinUsb_SetCurrentAlternateSetting$MH.invokeExact(lastErrorState, InterfaceHandle, SettingNumber); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + private static final FunctionDescriptor WinUsb_ControlTransfer$FUNC = + FunctionDescriptor.of(JAVA_INT, ADDRESS, SetupPacket.LAYOUT, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); + + private static final MethodHandle WinUsb_ControlTransfer$MH = LINKER.downcallHandle( + LOOKUP.find("WinUsb_ControlTransfer").get(), + WinUsb_ControlTransfer$FUNC, + Win.LAST_ERROR_STATE + ); + + public static int WinUsb_ControlTransfer(MemorySegment InterfaceHandle, MemorySegment SetupPacket, + MemorySegment Buffer, int BufferLength, MemorySegment LengthTransferred, + MemorySegment Overlapped, MemorySegment lastErrorState) { + try { + return (int)WinUsb_ControlTransfer$MH.invokeExact(lastErrorState, InterfaceHandle, SetupPacket, Buffer, BufferLength, LengthTransferred, Overlapped); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + private static final FunctionDescriptor WinUsb_SetPipePolicy$FUNC = + FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, JAVA_INT, JAVA_INT, ADDRESS); + + private static final MethodHandle WinUsb_SetPipePolicy$MH = LINKER.downcallHandle( + LOOKUP.find("WinUsb_SetPipePolicy").get(), + WinUsb_SetPipePolicy$FUNC, + Win.LAST_ERROR_STATE + ); + + public static int WinUsb_SetPipePolicy(MemorySegment InterfaceHandle, byte PipeID, int PolicyType, int ValueLength, + MemorySegment Value, MemorySegment lastErrorState) { + try { + return (int)WinUsb_SetPipePolicy$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID, PolicyType, ValueLength, Value); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + private static final FunctionDescriptor WinUsb_WritePipe$FUNC = + FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); + + private static final MethodHandle WinUsb_WritePipe$MH = LINKER.downcallHandle( + LOOKUP.find("WinUsb_WritePipe").get(), + WinUsb_WritePipe$FUNC, + Win.LAST_ERROR_STATE + ); + + public static int WinUsb_WritePipe(MemorySegment InterfaceHandle, byte PipeID, MemorySegment Buffer, + int BufferLength, MemorySegment LengthTransferred, MemorySegment Overlapped, + MemorySegment lastErrorState) { + try { + return (int)WinUsb_WritePipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID, Buffer, BufferLength, LengthTransferred, Overlapped); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + private static final FunctionDescriptor WinUsb_ReadPipe$FUNC = + FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); + + private static final MethodHandle WinUsb_ReadPipe$MH = LINKER.downcallHandle( + LOOKUP.find("WinUsb_ReadPipe").get(), + WinUsb_ReadPipe$FUNC, + Win.LAST_ERROR_STATE + ); + + public static int WinUsb_ReadPipe(MemorySegment InterfaceHandle, byte PipeID, MemorySegment Buffer, + int BufferLength, MemorySegment LengthTransferred, MemorySegment Overlapped, + MemorySegment lastErrorState) { + try { + return (int)WinUsb_ReadPipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID, Buffer, BufferLength, LengthTransferred, Overlapped); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + private static final FunctionDescriptor WinUsb_ResetPipe$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE); + + private static final MethodHandle WinUsb_ResetPipe$MH = LINKER.downcallHandle( + LOOKUP.find("WinUsb_ResetPipe").get(), + WinUsb_ResetPipe$FUNC, + Win.LAST_ERROR_STATE + ); + + public static int WinUsb_ResetPipe(MemorySegment InterfaceHandle, byte PipeID, MemorySegment lastErrorState) { + try { + return (int)WinUsb_ResetPipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } +} From b39a808de13801eae1c840e2ff1cb95f4a7f24dd Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 28 Dec 2022 22:06:12 +0100 Subject: [PATCH 174/433] Minor cleanup --- .../src/main/java/net/codecrete/usb/linux/IO.java | 10 ---------- .../main/java/net/codecrete/usb/macos/IoKitHelper.java | 2 +- .../usb/usbstandard/ConfigurationDescriptor.java | 3 ++- .../codecrete/usb/usbstandard/DeviceDescriptor.java | 3 ++- .../codecrete/usb/usbstandard/EndpointDescriptor.java | 3 ++- .../usb/windows/WindowsUSBDeviceRegistry.java | 2 +- 6 files changed, 8 insertions(+), 15 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java index 880c9a9a..813f7b52 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java @@ -31,11 +31,6 @@ public class IO { private static final FunctionDescriptor open$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT); private static final MethodHandle open$MH = linker.downcallHandle(linker.defaultLookup().find("open").get(), open$FUNC, ERRNO_STATE); - /** - * {@snippet lang=c : - * int ioctl(int fd, unsigned long request, ...); - * } - */ public static int ioctl(int fd, long request, MemorySegment segment, MemorySegment errno) { try { return (int)ioctl$MH.invokeExact(errno, fd, request, segment); @@ -44,11 +39,6 @@ public static int ioctl(int fd, long request, MemorySegment segment, MemorySegme } } - /** - * {@snippet lang=c : - * int open(char* file, int oflag, ...); - * } - */ public static int open(MemorySegment file, int oflag, MemorySegment errno) { try { return (int)open$MH.invokeExact(errno, file, oflag); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index c3ebd907..5c21b3be 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -53,7 +53,7 @@ public class IoKitHelper { * @param service the service * @param pluginType the plugin interface type * @param interfaceId the interface ID - * @return the interface, or null if the plugin type or interface is not available + * @return the interface, or {@code null} if the plugin type or interface is not available */ public static MemorySegment getInterface(int service, MemorySegment pluginType, MemorySegment interfaceId) { try (var arena = Arena.openConfined()) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java index 924f019d..3d4dcf5c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java @@ -13,7 +13,8 @@ import static java.lang.foreign.MemoryLayout.PathElement.groupElement; import static java.lang.foreign.MemoryLayout.structLayout; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_SHORT_UNALIGNED; /** * USB configuration descriptor diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java index 8c3cc34e..708cc3a1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java @@ -13,7 +13,8 @@ import static java.lang.foreign.MemoryLayout.PathElement.groupElement; import static java.lang.foreign.MemoryLayout.structLayout; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_SHORT_UNALIGNED; /** * USB device descriptor diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java index 2c3364c3..059a9335 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java @@ -13,7 +13,8 @@ import static java.lang.foreign.MemoryLayout.PathElement.groupElement; import static java.lang.foreign.MemoryLayout.structLayout; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_SHORT_UNALIGNED; /** * USB endpoint descriptor diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 0de36140..46b9febe 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -260,7 +260,7 @@ private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSetHandle, Mem // For certain devices, it seems to take some time until DEVPKEY_Device_Children // entry is present. So we retry a few times if needed and pause in between. - List childrenInstanceIDs = null; + List childrenInstanceIDs; int numTries = 5; while (true) { numTries -= 1; From 5550c528e555d1e9e4f9ec642551cd6c7bc38442 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Wed, 28 Dec 2022 22:24:08 +0100 Subject: [PATCH 175/433] Remove notice re GetLastError --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 166ae481..98fc7b2f 100644 --- a/README.md +++ b/README.md @@ -119,8 +119,6 @@ USB devices can implement certain control requests to instruct Windows to automa The test devices implement the required control requests. So the driver is installed automatically. -This library does not yet run reliably on Windows as the Java VM sometimes overwrites the last error code, which is needed for proper function, not just in error cases. It works incorrectly when run in the debugger and sometimes even without the debugger. A future version of the Foreign Function & Memory API will hopefully provide a way to save the last error code. The developers are aware of the issue. - The library has not been tested on Windows for ARM64. It might or might not work. From 5b82b2e984ce1cd40eed77ec481a65b2e7e0fa29 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 30 Dec 2022 16:55:19 +0100 Subject: [PATCH 176/433] Small improvement to Windows reference code --- reference/windows/USB/usb_registry.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/reference/windows/USB/usb_registry.cpp b/reference/windows/USB/usb_registry.cpp index 1076cc8f..88ea62f7 100644 --- a/reference/windows/USB/usb_registry.cpp +++ b/reference/windows/USB/usb_registry.cpp @@ -198,7 +198,7 @@ std::map usb_registry::enumerate_child_devices(const std::vec for (const std::wstring& child_instance_id : child_ids) { HDEVINFO dev_info_set_hdl = SetupDiCreateDeviceInfoList(NULL, NULL); if (dev_info_set_hdl == INVALID_HANDLE_VALUE) - throw usb_error("internal error (SetupDiGetClassDevsA)", GetLastError()); + throw usb_error("internal error (SetupDiCreateDeviceInfoList)", GetLastError()); // ensure the result id destroyed when the scope is left auto dev_info_set_guard = make_scope_exit([dev_info_set_hdl]() { @@ -287,16 +287,17 @@ void usb_registry::on_device_connected(const WCHAR* path) { usb_device_ptr device; try { - // get as set of all USB devices present - HDEVINFO dev_info_set_hdl = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + // create empty device information set + HDEVINFO dev_info_set_hdl = SetupDiCreateDeviceInfoList(NULL, NULL); if (dev_info_set_hdl == INVALID_HANDLE_VALUE) - usb_error::throw_error("internal error (SetupDiGetClassDevsW)"); + throw usb_error("internal error (SetupDiCreateDeviceInfoList)", GetLastError()); // ensure the result is destroyed when the scope is left auto dev_info_set_guard = make_scope_exit([dev_info_set_hdl]() { SetupDiDestroyDeviceInfoList(dev_info_set_hdl); }); + // load device information into dev info set SP_DEVICE_INTERFACE_DATA dev_intf_data = { sizeof(dev_intf_data) }; if (!SetupDiOpenDeviceInterfaceW(dev_info_set_hdl, path, 0, &dev_intf_data)) usb_error::throw_error("internal error (SetupDiOpenDeviceInterfaceW)"); @@ -305,6 +306,7 @@ void usb_registry::on_device_connected(const WCHAR* path) { SetupDiDeleteDeviceInterfaceData(dev_info_set_hdl, &dev_intf_data); }); + // load device info data SP_DEVINFO_DATA dev_info = { sizeof(dev_info) }; if (!SetupDiGetDeviceInterfaceDetailW(dev_info_set_hdl, &dev_intf_data, nullptr, 0, nullptr, &dev_info)) { DWORD err = GetLastError(); From b6f0aa3b838faec1bad8372e582ccf3c0ac3dfa4 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 30 Dec 2022 17:13:32 +0100 Subject: [PATCH 177/433] Windows: improve code when device is connected --- .../usb/windows/WindowsUSBDeviceRegistry.java | 53 ++++++++----------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 46b9febe..84c9ee70 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -88,7 +88,7 @@ protected void monitorDevices() { hwnd = User32B.CreateWindowExW(0, className, windowName, 0, 0, 0, 0, 0, User32.HWND_MESSAGE(), NULL, instance, NULL, lastErrorState); if (hwnd.address() == 0) - throwLastError(lastErrorState, "internal error (CreateWindowExW)"); + throwLastError(lastErrorState, "Internal error (CreateWindowExW)"); // configure notifications var notificationFilter = arena.allocate(DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); @@ -100,7 +100,7 @@ protected void monitorDevices() { var notifyHandle = User32B.RegisterDeviceNotificationW(hwnd, notificationFilter, User32.DEVICE_NOTIFY_WINDOW_HANDLE(), lastErrorState); if (notifyHandle.address() == 0) - throwLastError(lastErrorState, "internal error (RegisterDeviceNotificationW)"); + throwLastError(lastErrorState, "Internal error (RegisterDeviceNotificationW)"); // initial device enumeration enumeratePresentDevices(); @@ -130,8 +130,15 @@ private void enumeratePresentDevices() { var lastErrorState = outerArena.allocate(Win.LAST_ERROR_STATE.layout()); // get device information set of all USB devices present - final var devInfoSetHandle = createDevInfoSet(outerCleanup, lastErrorState); + var devInfoSetHandle = SetupAPI2.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, + NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), lastErrorState); + if (Win.IsInvalidHandle(devInfoSetHandle)) + throwLastError(lastErrorState, "Internal error (SetupDiGetClassDevsW)"); + // ensure the result is destroyed when the scope is left + outerCleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); + + // allocate SP_DEVINFO_DATA (will receive details for each device) var devInfo = outerArena.allocate(SP_DEVINFO_DATA.$LAYOUT()); SP_DEVINFO_DATA.cbSize$set(devInfo, (int) SP_DEVINFO_DATA.$LAYOUT().byteSize()); @@ -183,10 +190,10 @@ private Map enumerateChildren(List childrenIds) { var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - // create device info set + // create empty device info set var devInfoSetHandle = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, lastErrorState); if (Win.IsInvalidHandle(devInfoSetHandle)) - throwLastError(lastErrorState, "Cannot create device info list"); + throwLastError(lastErrorState, "Internal error (SetupDiCreateDeviceInfoList)"); cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); // get device info for child @@ -418,15 +425,20 @@ private void onDeviceConnected(String devicePath) { var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - // get device information set of all USB devices present - final var devInfoSetHandle = createDevInfoSet(cleanup, lastErrorState); + // create empty device info set + var devInfoSetHandle = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, lastErrorState); + if (Win.IsInvalidHandle(devInfoSetHandle)) + throwLastError(lastErrorState, "Internal error (SetupDiCreateDeviceInfoList)"); + + cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); + // load device information into dev info set var devIntfData = arena.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); var devicePathSegment = Win.createSegmentFromString(devicePath, arena); if (SetupAPI2.SetupDiOpenDeviceInterfaceW(devInfoSetHandle, devicePathSegment, 0, devIntfData, lastErrorState) == 0) - throwLastError(lastErrorState, "internal error (SetupDiOpenDeviceInterfaceW)"); + throwLastError(lastErrorState, "Internal error (SetupDiOpenDeviceInterfaceW)"); cleanup.add(() -> SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSetHandle, devIntfData)); @@ -436,7 +448,7 @@ private void onDeviceConnected(String devicePath) { NULL, devInfo, lastErrorState) == 0) { int err = Win.getLastError(lastErrorState); if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) - throwException(err, "internal error (SetupDiGetDeviceInterfaceDetailW)"); + throwException(err, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); } // ensure all hubs are closed later @@ -489,29 +501,6 @@ private static boolean isCompositeDevice(String deviceService) { return "usbccgp".equalsIgnoreCase(deviceService); } - /** - * Creates a new device information set for USB devices. - *

- * The info set is added to the cleanup object for later releasing. - * A native memory segment is passed to be used for the last error call state. - *

- * @param cleanup cleanup handler - * @param lastErrorState memory segment for last error call state - * @return handle to device information set - */ - private static MemorySegment createDevInfoSet(ScopeCleanup cleanup, MemorySegment lastErrorState) { - // get device information set of all USB devices present - var devInfoSetHandle = SetupAPI2.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, - NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), lastErrorState); - if (Win.IsInvalidHandle(devInfoSetHandle)) - throwLastError(lastErrorState, "internal error (SetupDiGetClassDevsW)"); - - // ensure the result is destroyed when the scope is left - cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); - - return devInfoSetHandle; - } - private static final Pattern MULTIPLE_INTERFACE_ID = Pattern.compile("USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); private static int extractInterfaceNumber(List hardwareIds) { From f0a484b02a0c914b7d7fab22c32fbf22581dc741 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 3 Jan 2023 09:29:30 +0100 Subject: [PATCH 178/433] Consistent naming of device information set and device information data --- .../codecrete/usb/windows/DeviceProperty.java | 62 +++++++++------ .../usb/windows/WindowsUSBDeviceRegistry.java | 78 +++++++++---------- 2 files changed, 73 insertions(+), 67 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index 3a244cff..468d3e92 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -57,17 +57,17 @@ public class DeviceProperty { /** * Gets the device property with integer type. - * @param devInfo device information set containing the device - * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the device in the information set + * @param devInfoSet device information set containing the device ({@code HDEVINFO}) + * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set * @param propertyKey property key (of type {@code DEVPKEY}) * @return property value */ - public static int getDeviceIntProperty(MemorySegment devInfo, MemorySegment devInfoData, MemorySegment propertyKey) { + public static int getDeviceIntProperty(MemorySegment devInfoSet, MemorySegment devInfoData, MemorySegment propertyKey) { try (var arena = Arena.openConfined()) { var propertyTypeHolder = arena.allocate(JAVA_INT); var propertyValueHolder = arena.allocate(JAVA_INT); var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - if (SetupAPI2.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, + if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, lastErrorState) == 0) throwLastError(lastErrorState, "Internal error (SetupDiGetDevicePropertyW)"); @@ -80,15 +80,15 @@ public static int getDeviceIntProperty(MemorySegment devInfo, MemorySegment devI /** * Gets the device property with string type. - * @param devInfo device information set containing the device - * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the device in the information set + * @param devInfoSet device information set containing the device ({@code HDEVINFO}) + * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set * @param propertyKey property key (of type {@code DEVPKEY}) * @return property value */ - public static String getDeviceStringProperty(MemorySegment devInfo, MemorySegment devInfoData, + public static String getDeviceStringProperty(MemorySegment devInfoSet, MemorySegment devInfoData, MemorySegment propertyKey) { try (var arena = Arena.openConfined()) { - var propertyValue = getVariableLengthProperty(devInfo, devInfoData, propertyKey, SetupAPI.DEVPROP_TYPE_STRING(), arena); + var propertyValue = getVariableLengthProperty(devInfoSet, devInfoData, propertyKey, SetupAPI.DEVPROP_TYPE_STRING(), arena); if (propertyValue == null) return null; return Win.createStringFromSegment(propertyValue); @@ -97,15 +97,15 @@ public static String getDeviceStringProperty(MemorySegment devInfo, MemorySegmen /** * Gets the device property with string list type. - * @param devInfo device information set containing the device - * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the device in the information set + * @param devInfoSet device information set containing the device ({@code HDEVINFO}) + * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set * @param propertyKey property key (of type {@code DEVPKEY}) * @return property value */ - public static List getDeviceStringListProperty(MemorySegment devInfo, MemorySegment devInfoData, + public static List getDeviceStringListProperty(MemorySegment devInfoSet, MemorySegment devInfoData, MemorySegment propertyKey) { try (var arena = Arena.openConfined()) { - var propertyValue = getVariableLengthProperty(devInfo, devInfoData, propertyKey, + var propertyValue = getVariableLengthProperty(devInfoSet, devInfoData, propertyKey, SetupAPI.DEVPROP_TYPE_STRING() | SetupAPI.DEVPROP_TYPEMOD_LIST(), arena); if (propertyValue == null) return null; @@ -114,14 +114,14 @@ public static List getDeviceStringListProperty(MemorySegment devInfo, Me } } - private static MemorySegment getVariableLengthProperty(MemorySegment devInfo, MemorySegment devInfoData, MemorySegment propertyKey, + private static MemorySegment getVariableLengthProperty(MemorySegment devInfoSet, MemorySegment devInfoData, MemorySegment propertyKey, int propertyType, Arena arena) { // query length (thus no buffer) var propertyTypeHolder = arena.allocate(JAVA_INT); var requiredSizeHolder = arena.allocate(JAVA_INT); var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - if (SetupAPI2.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, NULL, 0, + if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, NULL, 0, requiredSizeHolder, 0, lastErrorState) == 0) { int err = Win.getLastError(lastErrorState); if (err == Kernel32.ERROR_NOT_FOUND()) @@ -139,7 +139,7 @@ private static MemorySegment getVariableLengthProperty(MemorySegment devInfo, Me var propertyValueHolder = arena.allocateArray(JAVA_CHAR, stringLen + 1); // get property value - if (SetupAPI2.SetupDiGetDevicePropertyW(devInfo, devInfoData, propertyKey, propertyTypeHolder, + if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, lastErrorState) == 0) throwLastError(lastErrorState, "Internal error (SetupDiGetDevicePropertyW)"); @@ -148,18 +148,18 @@ private static MemorySegment getVariableLengthProperty(MemorySegment devInfo, Me /** * Gets a list of {@code DeviceInterfaceGUIDs} from device-specific configuration information in the registry. - * @param devInfoSetHandle device information set containing the device - * @param devInfo {@code SP_DEVINFO_DATA} structure specifying the device in the information set + * @param devInfoSet device information set containing the device ({@code HDEVINFO}) + * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set * @param arena arena for allocating memory * @return list of GUIDs */ - public static List findDeviceInterfaceGUIDs(MemorySegment devInfoSetHandle, MemorySegment devInfo, Arena arena) { + public static List findDeviceInterfaceGUIDs(MemorySegment devInfoSet, MemorySegment devInfoData, Arena arena) { try (var cleanup = new ScopeCleanup()) { var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); // open device registry key - var regKey = SetupAPI2.SetupDiOpenDevRegKey(devInfoSetHandle, devInfo, SetupAPI.DICS_FLAG_GLOBAL(), + var regKey = SetupAPI2.SetupDiOpenDevRegKey(devInfoSet, devInfoData, SetupAPI.DICS_FLAG_GLOBAL(), 0, SetupAPI.DIREG_DEV(), Advapi32.KEY_READ(), lastErrorState); if (Win.IsInvalidHandle(regKey)) throwLastError(lastErrorState, "Cannot open device registry key"); @@ -198,18 +198,18 @@ public static String getDevicePath(String instanceID, MemorySegment interfaceGui // get device info set for instance var instanceIDSegment = Win.createSegmentFromString(instanceID, arena); - final var devInfoSetHandle = SetupAPI2.SetupDiGetClassDevsW(interfaceGuid, instanceIDSegment, NULL, + final var devInfoSet = SetupAPI2.SetupDiGetClassDevsW(interfaceGuid, instanceIDSegment, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), lastErrorState); - if (Win.IsInvalidHandle(devInfoSetHandle)) + if (Win.IsInvalidHandle(devInfoSet)) throwLastError(lastErrorState, "internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left - cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); + cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); // retrieve first element of enumeration var devIntfData = arena.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); - if (SetupAPI2.SetupDiEnumDeviceInterfaces(devInfoSetHandle, NULL, interfaceGuid, 0, + if (SetupAPI2.SetupDiEnumDeviceInterfaces(devInfoSet, NULL, interfaceGuid, 0, devIntfData, lastErrorState) == 0) throwLastError(lastErrorState, "internal error (SetupDiEnumDeviceInterfaces)"); @@ -221,7 +221,7 @@ public static String getDevicePath(String instanceID, MemorySegment interfaceGui SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$set(intfDetailData, (int) SP_DEVICE_INTERFACE_DETAIL_DATA_W.sizeof()); int intfDetailDataSize = (int) intfDetailData.byteSize(); - if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, intfDetailData, + if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSet, devIntfData, intfDetailData, intfDetailDataSize, NULL, NULL, lastErrorState) == 0) throwLastError(lastErrorState, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); @@ -229,6 +229,20 @@ public static String getDevicePath(String instanceID, MemorySegment interfaceGui } } + /** + * Checks if the device is a composite USB device + * @param devInfoSet device information set containing the device ({@code HDEVINFO}) + * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set + * @return {@code true} if it is a composite device + */ + public static boolean isCompositeDevice(MemorySegment devInfoSet, MemorySegment devInfoData) { + var deviceService = getDeviceStringProperty(devInfoSet, devInfoData, + DEVPKEY_Device_Service); + + // usbccgp is the USB Generic Parent Driver used for composite devices + return "usbccgp".equalsIgnoreCase(deviceService); + } + private static MemorySegment createDEVPROPKEY(int data1, short data2, short data3, byte data4_0, byte data4_1, byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7, int pid) { var propKey = Win.GLOBAL_ALLOCATOR.allocate(DEVPROPKEY.$LAYOUT()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 84c9ee70..b5583105 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -130,17 +130,17 @@ private void enumeratePresentDevices() { var lastErrorState = outerArena.allocate(Win.LAST_ERROR_STATE.layout()); // get device information set of all USB devices present - var devInfoSetHandle = SetupAPI2.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, + var devInfoSet = SetupAPI2.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), lastErrorState); - if (Win.IsInvalidHandle(devInfoSetHandle)) + if (Win.IsInvalidHandle(devInfoSet)) throwLastError(lastErrorState, "Internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left - outerCleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); + outerCleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); // allocate SP_DEVINFO_DATA (will receive details for each device) - var devInfo = outerArena.allocate(SP_DEVINFO_DATA.$LAYOUT()); - SP_DEVINFO_DATA.cbSize$set(devInfo, (int) SP_DEVINFO_DATA.$LAYOUT().byteSize()); + var devInfoData = outerArena.allocate(SP_DEVINFO_DATA.$LAYOUT()); + SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) SP_DEVINFO_DATA.$LAYOUT().byteSize()); // ensure all hubs are closed later final var hubHandles = new HashMap(); @@ -149,19 +149,19 @@ private void enumeratePresentDevices() { // iterate all devices for (int i = 0; true; i++) { - if (SetupAPI2.SetupDiEnumDeviceInfo(devInfoSetHandle, i, devInfo, lastErrorState) == 0) { + if (SetupAPI2.SetupDiEnumDeviceInfo(devInfoSet, i, devInfoData, lastErrorState) == 0) { int err = Win.getLastError(lastErrorState); if (err == Kernel32.ERROR_NO_MORE_ITEMS()) break; throwLastError(lastErrorState, "Internal error (SetupDiEnumDeviceInfo)"); } - var instanceID = DeviceProperty.getDeviceStringProperty(devInfoSetHandle, devInfo, + var instanceId = DeviceProperty.getDeviceStringProperty(devInfoSet, devInfoData, DeviceProperty.DEVPKEY_Device_InstanceId); - var devicePath = DeviceProperty.getDevicePath(instanceID, USBHelper.GUID_DEVINTERFACE_USB_DEVICE); + var devicePath = DeviceProperty.getDevicePath(instanceId, USBHelper.GUID_DEVINTERFACE_USB_DEVICE); try { - deviceList.add(createDeviceFromDeviceInfo(devInfoSetHandle, devInfo, devicePath, hubHandles)); + deviceList.add(createDeviceFromDeviceInfo(devInfoSet, devInfoData, devicePath, hubHandles)); } catch (Throwable e) { System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring " @@ -191,21 +191,21 @@ private Map enumerateChildren(List childrenIds) { var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); // create empty device info set - var devInfoSetHandle = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, lastErrorState); - if (Win.IsInvalidHandle(devInfoSetHandle)) + var devInfoSet = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, lastErrorState); + if (Win.IsInvalidHandle(devInfoSet)) throwLastError(lastErrorState, "Internal error (SetupDiCreateDeviceInfoList)"); - cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); + cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); // get device info for child - var devInfo = arena.allocate(SP_DEVINFO_DATA.$LAYOUT()); - SP_DEVINFO_DATA.cbSize$set(devInfo, (int) devInfo.byteSize()); + var devInfoData = arena.allocate(SP_DEVINFO_DATA.$LAYOUT()); + SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) devInfoData.byteSize()); var instanceIdSegment = Win.createSegmentFromString(instanceId, arena); - if (SetupAPI2.SetupDiOpenDeviceInfoW(devInfoSetHandle, instanceIdSegment, NULL, 0, - devInfo, lastErrorState) == 0) + if (SetupAPI2.SetupDiOpenDeviceInfoW(devInfoSet, instanceIdSegment, NULL, 0, + devInfoData, lastErrorState) == 0) throwLastError(lastErrorState, "Internal error (SetupDiOpenDeviceInfoW)"); // get hardware IDs (to extract interface number) - var hardwareIds = DeviceProperty.getDeviceStringListProperty(devInfoSetHandle, devInfo, + var hardwareIds = DeviceProperty.getDeviceStringListProperty(devInfoSet, devInfoData, DeviceProperty.DEVPKEY_Device_HardwareIds); if (hardwareIds == null) throwException("DEVPKEY_Device_HardwareIds not found"); @@ -213,7 +213,7 @@ private Map enumerateChildren(List childrenIds) { if (interfaceNumber == -1) continue; - var guids = DeviceProperty.findDeviceInterfaceGUIDs(devInfoSetHandle, devInfo, arena); + var guids = DeviceProperty.findDeviceInterfaceGUIDs(devInfoSet, devInfoData, arena); for (var guid : guids) { // check for Class GUID @@ -236,15 +236,15 @@ private Map enumerateChildren(List childrenIds) { return children; } - private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSetHandle, MemorySegment devInfo, + private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSet, MemorySegment devInfoData, String devicePath, HashMap hubHandles) { try (var arena = Arena.openConfined()) { - var usbPortNum = DeviceProperty.getDeviceIntProperty(devInfoSetHandle, devInfo, + var usbPortNum = DeviceProperty.getDeviceIntProperty(devInfoSet, devInfoData, DeviceProperty.DEVPKEY_Device_Address); - var parentInstanceID = DeviceProperty.getDeviceStringProperty(devInfoSetHandle, devInfo, + var parentInstanceId = DeviceProperty.getDeviceStringProperty(devInfoSet, devInfoData, DeviceProperty.DEVPKEY_Device_Parent); - var hubPath = DeviceProperty.getDevicePath(parentInstanceID, USBHelper.GUID_DEVINTERFACE_USB_HUB); + var hubPath = DeviceProperty.getDevicePath(parentInstanceId, USBHelper.GUID_DEVINTERFACE_USB_HUB); // open hub if not open yet var hubHandle = hubHandles.get(hubPath); @@ -259,19 +259,16 @@ private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSetHandle, Mem } // check for composite device - var deviceService = DeviceProperty.getDeviceStringProperty(devInfoSetHandle, devInfo, - DeviceProperty.DEVPKEY_Device_Service); - Map children = null; - if (isCompositeDevice(deviceService)) { + if (DeviceProperty.isCompositeDevice(devInfoSet, devInfoData)) { - // For certain devices, it seems to take some time until DEVPKEY_Device_Children + // For certain devices, it seems to take some time until the "Device_Children" // entry is present. So we retry a few times if needed and pause in between. List childrenInstanceIDs; int numTries = 5; while (true) { numTries -= 1; - childrenInstanceIDs = DeviceProperty.getDeviceStringListProperty(devInfoSetHandle, devInfo, + childrenInstanceIDs = DeviceProperty.getDeviceStringListProperty(devInfoSet, devInfoData, DeviceProperty.DEVPKEY_Device_Children); if (childrenInstanceIDs != null || numTries == 0) break; @@ -426,26 +423,26 @@ private void onDeviceConnected(String devicePath) { var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); // create empty device info set - var devInfoSetHandle = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, lastErrorState); - if (Win.IsInvalidHandle(devInfoSetHandle)) + var devInfoSet = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, lastErrorState); + if (Win.IsInvalidHandle(devInfoSet)) throwLastError(lastErrorState, "Internal error (SetupDiCreateDeviceInfoList)"); - cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSetHandle)); + cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); // load device information into dev info set var devIntfData = arena.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); var devicePathSegment = Win.createSegmentFromString(devicePath, arena); - if (SetupAPI2.SetupDiOpenDeviceInterfaceW(devInfoSetHandle, devicePathSegment, 0, + if (SetupAPI2.SetupDiOpenDeviceInterfaceW(devInfoSet, devicePathSegment, 0, devIntfData, lastErrorState) == 0) throwLastError(lastErrorState, "Internal error (SetupDiOpenDeviceInterfaceW)"); - cleanup.add(() -> SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSetHandle, devIntfData)); + cleanup.add(() -> SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSet, devIntfData)); - var devInfo = arena.allocate(SP_DEVINFO_DATA.$LAYOUT()); - SP_DEVINFO_DATA.cbSize$set(devInfo, (int) devInfo.byteSize()); - if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSetHandle, devIntfData, NULL, 0, - NULL, devInfo, lastErrorState) == 0) { + var devInfoData = arena.allocate(SP_DEVINFO_DATA.$LAYOUT()); + SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) devInfoData.byteSize()); + if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSet, devIntfData, NULL, 0, + NULL, devInfoData, lastErrorState) == 0) { int err = Win.getLastError(lastErrorState); if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) throwException(err, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); @@ -457,7 +454,7 @@ private void onDeviceConnected(String devicePath) { try { // create device instance - var device = createDeviceFromDeviceInfo(devInfoSetHandle, devInfo, devicePath, hubHandles); + var device = createDeviceFromDeviceInfo(devInfoSet, devInfoData, devicePath, hubHandles); // add it to device list addDevice(device); @@ -496,11 +493,6 @@ protected int findDeviceIndex(List deviceList, Object deviceId) { return -1; } - private static boolean isCompositeDevice(String deviceService) { - // usbccgp is the USB Generic Parent Driver used for composite devices - return "usbccgp".equalsIgnoreCase(deviceService); - } - private static final Pattern MULTIPLE_INTERFACE_ID = Pattern.compile("USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); private static int extractInterfaceNumber(List hardwareIds) { From 76cea7d993a996fff2e99372afa5b3f304c3001e Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 3 Jan 2023 09:42:00 +0100 Subject: [PATCH 179/433] Consistent naming of device information set and device information data --- reference/windows/USB/usb_device_info.cpp | 42 +++++++-------- reference/windows/USB/usb_device_info.hpp | 28 +++++----- reference/windows/USB/usb_registry.cpp | 62 +++++++++++------------ reference/windows/USB/usb_registry.hpp | 2 +- 4 files changed, 67 insertions(+), 67 deletions(-) diff --git a/reference/windows/USB/usb_device_info.cpp b/reference/windows/USB/usb_device_info.cpp index a2fe48d8..1a4f9909 100644 --- a/reference/windows/USB/usb_device_info.cpp +++ b/reference/windows/USB/usb_device_info.cpp @@ -19,18 +19,18 @@ std::wstring usb_device_info::get_device_path(const std::wstring& instance_id, const GUID* interface_guid) { // get device info set for instance - HDEVINFO dev_info_set_hdl = SetupDiGetClassDevsW(interface_guid, instance_id.c_str(), nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); - if (dev_info_set_hdl == INVALID_HANDLE_VALUE) + HDEVINFO dev_info_set = SetupDiGetClassDevsW(interface_guid, instance_id.c_str(), nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (dev_info_set == INVALID_HANDLE_VALUE) usb_error::throw_error("internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left - auto dev_info_set_guard = make_scope_exit([dev_info_set_hdl]() { - SetupDiDestroyDeviceInfoList(dev_info_set_hdl); + auto dev_info_set_guard = make_scope_exit([dev_info_set]() { + SetupDiDestroyDeviceInfoList(dev_info_set); }); // retrieve first element of enumeration SP_DEVICE_INTERFACE_DATA dev_intf_data = { sizeof(dev_intf_data) }; - if (!SetupDiEnumDeviceInterfaces(dev_info_set_hdl, nullptr, interface_guid, 0, &dev_intf_data)) + if (!SetupDiEnumDeviceInterfaces(dev_info_set, nullptr, interface_guid, 0, &dev_intf_data)) usb_error::throw_error("internal error (SetupDiEnumDeviceInterfaces)"); // retrieve path @@ -38,17 +38,17 @@ std::wstring usb_device_info::get_device_path(const std::wstring& instance_id, c memset(dev_path_buf, 0, sizeof(dev_path_buf)); PSP_DEVICE_INTERFACE_DETAIL_DATA_W intf_detail_data = reinterpret_cast(dev_path_buf); intf_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); - if (!SetupDiGetDeviceInterfaceDetailW(dev_info_set_hdl, &dev_intf_data, intf_detail_data, sizeof(dev_path_buf), nullptr, nullptr)) + if (!SetupDiGetDeviceInterfaceDetailW(dev_info_set, &dev_intf_data, intf_detail_data, sizeof(dev_path_buf), nullptr, nullptr)) throw usb_error("Internal error (SetupDiGetDeviceInterfaceDetailA)", GetLastError()); return intf_detail_data->DevicePath; } -uint32_t usb_device_info::get_device_property_int(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { +uint32_t usb_device_info::get_device_property_int(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { // query property value DEVPROPTYPE property_type; uint32_t property_value = -1; - if (!SetupDiGetDevicePropertyW(dev_info, dev_info_data, prop_key, &property_type, reinterpret_cast(&property_value), sizeof(property_value), nullptr, 0)) + if (!SetupDiGetDevicePropertyW(dev_info_set, dev_info_data, prop_key, &property_type, reinterpret_cast(&property_value), sizeof(property_value), nullptr, 0)) usb_error::throw_error("internal error (SetupDiGetDevicePropertyW)"); // check property type @@ -58,12 +58,12 @@ uint32_t usb_device_info::get_device_property_int(HDEVINFO dev_info, SP_DEVINFO_ return property_value; } -std::vector usb_device_info::get_device_property_variable_length(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key, DEVPROPTYPE expected_type) { +std::vector usb_device_info::get_device_property_variable_length(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key, DEVPROPTYPE expected_type) { // query length DWORD required_size = 0; DEVPROPTYPE property_type; - if (!SetupDiGetDevicePropertyW(dev_info, dev_info_data, prop_key, &property_type, nullptr, 0, &required_size, 0)) { + if (!SetupDiGetDevicePropertyW(dev_info_set, dev_info_data, prop_key, &property_type, nullptr, 0, &required_size, 0)) { DWORD err = GetLastError(); if (err == ERROR_NOT_FOUND) return {}; @@ -78,22 +78,22 @@ std::vector usb_device_info::get_device_property_variable_length(HDEVIN // query property value std::vector property_value; property_value.resize(required_size); - if (!SetupDiGetDevicePropertyW(dev_info, dev_info_data, prop_key, &property_type, &property_value[0], required_size, nullptr, 0)) + if (!SetupDiGetDevicePropertyW(dev_info_set, dev_info_data, prop_key, &property_type, &property_value[0], required_size, nullptr, 0)) usb_error::throw_error("internal error (SetupDiGetDevicePropertyW)"); return property_value; } -std::wstring usb_device_info::get_device_property_string(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { +std::wstring usb_device_info::get_device_property_string(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { - auto property_value = get_device_property_variable_length(dev_info, dev_info_data, prop_key, DEVPROP_TYPE_STRING); + auto property_value = get_device_property_variable_length(dev_info_set, dev_info_data, prop_key, DEVPROP_TYPE_STRING); if (property_value.size() == 0) return L""; return std::wstring(reinterpret_cast(&property_value[0])); } -std::vector usb_device_info::get_device_property_string_list(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { - auto property_value = get_device_property_variable_length(dev_info, dev_info_data, prop_key, DEVPROP_TYPE_STRING | DEVPROP_TYPEMOD_LIST); +std::vector usb_device_info::get_device_property_string_list(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { + auto property_value = get_device_property_variable_length(dev_info_set, dev_info_data, prop_key, DEVPROP_TYPE_STRING | DEVPROP_TYPEMOD_LIST); if (property_value.size() == 0) return {}; return split_string_list(reinterpret_cast(&property_value[0])); @@ -174,17 +174,17 @@ std::string usb_device_info::get_string(HANDLE hub_handle, ULONG usb_port_num, i return result; } -bool usb_device_info::is_composite_device(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data) { - std::wstring device_service = usb_device_info::get_device_property_string(dev_info, dev_info_data, &DEVPKEY_Device_Service); +bool usb_device_info::is_composite_device(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data) { + std::wstring device_service = usb_device_info::get_device_property_string(dev_info_set, dev_info_data, &DEVPKEY_Device_Service); return lstrcmpiW(device_service.c_str(), L"usbccgp") == 0; } static const std::wregex multiple_interface_pattern(L"USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); -int usb_device_info::get_first_interface(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data) { +int usb_device_info::get_first_interface(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data) { // Also see https://docs.microsoft.com/en-us/windows-hardware/drivers/install/standard-usb-identifiers#multiple-interface-usb-devices - auto hardware_ids = usb_device_info::get_device_property_string_list(dev_info, dev_info_data, &DEVPKEY_Device_HardwareIds); + auto hardware_ids = usb_device_info::get_device_property_string_list(dev_info_set, dev_info_data, &DEVPKEY_Device_HardwareIds); for (const std::wstring& id : hardware_ids) { auto matches = std::wsmatch{}; @@ -195,8 +195,8 @@ int usb_device_info::get_first_interface(HDEVINFO dev_info, SP_DEVINFO_DATA* dev return -1; } -std::vector usb_device_info::find_device_interface_guids(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data) { - HKEY reg_key = SetupDiOpenDevRegKey(dev_info, dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); +std::vector usb_device_info::find_device_interface_guids(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data) { + HKEY reg_key = SetupDiOpenDevRegKey(dev_info_set, dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); if (reg_key == INVALID_HANDLE_VALUE) throw usb_error("Cannot open device registry key", GetLastError()); diff --git a/reference/windows/USB/usb_device_info.hpp b/reference/windows/USB/usb_device_info.hpp index 042e004c..5f5ab067 100644 --- a/reference/windows/USB/usb_device_info.hpp +++ b/reference/windows/USB/usb_device_info.hpp @@ -26,39 +26,39 @@ class usb_device_info /// /// Get a device property of integer type. /// - /// handle of device information set containing the device + /// handle of device information set containing the device /// pointer to device information structure representing the device /// property key /// property integer value - static uint32_t get_device_property_int(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key); + static uint32_t get_device_property_int(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key); /// /// Get a device property of string type. /// - /// handle of device information set containing the device + /// handle of device information set containing the device /// pointer to device information structure representing the device /// property key /// property string value - static std::wstring get_device_property_string(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key); + static std::wstring get_device_property_string(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key); /// /// Get a device property of variable length. /// - /// handle of device information set containing the device + /// handle of device information set containing the device /// pointer to device information structure representing the device /// property key /// expected property type (use DEVPROP_TYPE_xxx constants) /// property value as byte array - static std::vector get_device_property_variable_length(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key, DEVPROPTYPE expected_type); + static std::vector get_device_property_variable_length(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key, DEVPROPTYPE expected_type); /// /// Get a device property of string list type. /// - /// handle of device information set containing the device + /// handle of device information set containing the device /// pointer to device information structure representing the device /// property key /// property value as vector of strings - static std::vector get_device_property_string_list(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key); + static std::vector get_device_property_string_list(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key); /// /// Split the string list into a vector of strings @@ -117,10 +117,10 @@ class usb_device_info /// in Windows. In the Setup API, they are represented as child devices. /// /// - /// handle of device information set containing the device + /// handle of device information set containing the device /// pointer to device information structure representing the device /// true if device is a composite device, false otherwise - static bool is_composite_device(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data); + static bool is_composite_device(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data); /// /// Get the number of the first USB interface. @@ -128,18 +128,18 @@ class usb_device_info /// The first interface number is relevant for child devices of composite devices. /// /// - /// handle of device information set containing the device + /// handle of device information set containing the device /// pointer to device information structure representing the device /// - static int get_first_interface(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data); + static int get_first_interface(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data); /// /// Get the device's interface GUIDs. /// - /// handle of device information set containing the device + /// handle of device information set containing the device /// pointer to device information structure representing the device /// vector of GUIDs - static std::vector find_device_interface_guids(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data); + static std::vector find_device_interface_guids(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data); friend class usb_registry; }; diff --git a/reference/windows/USB/usb_registry.cpp b/reference/windows/USB/usb_registry.cpp index 88ea62f7..f499fed7 100644 --- a/reference/windows/USB/usb_registry.cpp +++ b/reference/windows/USB/usb_registry.cpp @@ -121,20 +121,20 @@ void usb_registry::monitor() { void usb_registry::detect_present_devices() { // get device information set of all USB devices present - HDEVINFO dev_info_set_hdl = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); - if (dev_info_set_hdl == INVALID_HANDLE_VALUE) + HDEVINFO dev_info_set = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (dev_info_set == INVALID_HANDLE_VALUE) throw usb_error("internal error (SetupDiGetClassDevsA)", GetLastError()); // ensure the result id destroyed when the scope is left - auto dev_info_set_guard = make_scope_exit([dev_info_set_hdl]() { - SetupDiDestroyDeviceInfoList(dev_info_set_hdl); + auto dev_info_set_guard = make_scope_exit([dev_info_set]() { + SetupDiDestroyDeviceInfoList(dev_info_set); }); - SP_DEVINFO_DATA dev_info = { sizeof(dev_info) }; + SP_DEVINFO_DATA dev_info_data = { sizeof(dev_info_data) }; // iterate over the set for (int i = 0; ; i++) { - if (!SetupDiEnumDeviceInfo(dev_info_set_hdl, i, &dev_info)) { + if (!SetupDiEnumDeviceInfo(dev_info_set, i, &dev_info_data)) { DWORD err = GetLastError(); if (err == ERROR_NO_MORE_ITEMS) break; @@ -142,16 +142,16 @@ void usb_registry::detect_present_devices() { } // create new device - auto device = create_device(dev_info_set_hdl, &dev_info); + auto device = create_device(dev_info_set, &dev_info_data); devices.push_back(device); } } -std::shared_ptr usb_registry::create_device(HDEVINFO dev_info_set_hdl, SP_DEVINFO_DATA* dev_info) { +std::shared_ptr usb_registry::create_device(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data) { - DWORD usb_port_num = usb_device_info::get_device_property_int(dev_info_set_hdl, dev_info, &DEVPKEY_Device_Address); - std::wstring instance_id = usb_device_info::get_device_property_string(dev_info_set_hdl, dev_info, &DEVPKEY_Device_InstanceId); - std::wstring parent_instance_id = usb_device_info::get_device_property_string(dev_info_set_hdl, dev_info, &DEVPKEY_Device_Parent); + DWORD usb_port_num = usb_device_info::get_device_property_int(dev_info_set, dev_info_data, &DEVPKEY_Device_Address); + std::wstring instance_id = usb_device_info::get_device_property_string(dev_info_set, dev_info_data, &DEVPKEY_Device_InstanceId); + std::wstring parent_instance_id = usb_device_info::get_device_property_string(dev_info_set, dev_info_data, &DEVPKEY_Device_Parent); std::wstring hub_path = usb_device_info::get_device_path(parent_instance_id, &GUID_DEVINTERFACE_USB_HUB); @@ -166,8 +166,8 @@ std::shared_ptr usb_registry::create_device(HDEVINFO dev_info_set_hd // check for composite device std::map children{}; - if (usb_device_info::is_composite_device(dev_info_set_hdl, dev_info)) - children = enumerate_child_devices(usb_device_info::get_device_property_string_list(dev_info_set_hdl, dev_info, &DEVPKEY_Device_Children)); + if (usb_device_info::is_composite_device(dev_info_set, dev_info_data)) + children = enumerate_child_devices(usb_device_info::get_device_property_string_list(dev_info_set, dev_info_data, &DEVPKEY_Device_Children)); auto path = usb_device_info::get_device_path(instance_id, &GUID_DEVINTERFACE_USB_DEVICE); @@ -196,27 +196,27 @@ std::map usb_registry::enumerate_child_devices(const std::vec std::map children{}; for (const std::wstring& child_instance_id : child_ids) { - HDEVINFO dev_info_set_hdl = SetupDiCreateDeviceInfoList(NULL, NULL); - if (dev_info_set_hdl == INVALID_HANDLE_VALUE) + HDEVINFO dev_info_set = SetupDiCreateDeviceInfoList(NULL, NULL); + if (dev_info_set == INVALID_HANDLE_VALUE) throw usb_error("internal error (SetupDiCreateDeviceInfoList)", GetLastError()); // ensure the result id destroyed when the scope is left - auto dev_info_set_guard = make_scope_exit([dev_info_set_hdl]() { - SetupDiDestroyDeviceInfoList(dev_info_set_hdl); + auto dev_info_set_guard = make_scope_exit([dev_info_set]() { + SetupDiDestroyDeviceInfoList(dev_info_set); }); // get device info for child - SP_DEVINFO_DATA dev_info = { sizeof(dev_info) }; - if (!SetupDiOpenDeviceInfoW(dev_info_set_hdl, child_instance_id.c_str(), nullptr, 0, &dev_info)) + SP_DEVINFO_DATA dev_info_data = { sizeof(dev_info_data) }; + if (!SetupDiOpenDeviceInfoW(dev_info_set, child_instance_id.c_str(), nullptr, 0, &dev_info_data)) throw usb_error("internal error (SetupDiOpenDeviceInfoW)", GetLastError()); // get first interface number - int interface_number = usb_device_info::get_first_interface(dev_info_set_hdl, &dev_info); + int interface_number = usb_device_info::get_first_interface(dev_info_set, &dev_info_data); if (interface_number == -1) continue; // get device interface GUIDs - auto device_guids = usb_device_info::find_device_interface_guids(dev_info_set_hdl, &dev_info); + auto device_guids = usb_device_info::find_device_interface_guids(dev_info_set, &dev_info_data); CLSID clsid{}; // use GUIDs to get device path @@ -288,34 +288,34 @@ void usb_registry::on_device_connected(const WCHAR* path) { usb_device_ptr device; try { // create empty device information set - HDEVINFO dev_info_set_hdl = SetupDiCreateDeviceInfoList(NULL, NULL); - if (dev_info_set_hdl == INVALID_HANDLE_VALUE) + HDEVINFO dev_info_set = SetupDiCreateDeviceInfoList(NULL, NULL); + if (dev_info_set == INVALID_HANDLE_VALUE) throw usb_error("internal error (SetupDiCreateDeviceInfoList)", GetLastError()); // ensure the result is destroyed when the scope is left - auto dev_info_set_guard = make_scope_exit([dev_info_set_hdl]() { - SetupDiDestroyDeviceInfoList(dev_info_set_hdl); + auto dev_info_set_guard = make_scope_exit([dev_info_set]() { + SetupDiDestroyDeviceInfoList(dev_info_set); }); // load device information into dev info set SP_DEVICE_INTERFACE_DATA dev_intf_data = { sizeof(dev_intf_data) }; - if (!SetupDiOpenDeviceInterfaceW(dev_info_set_hdl, path, 0, &dev_intf_data)) + if (!SetupDiOpenDeviceInterfaceW(dev_info_set, path, 0, &dev_intf_data)) usb_error::throw_error("internal error (SetupDiOpenDeviceInterfaceW)"); - auto dev_intf_data_guard = make_scope_exit([dev_info_set_hdl, &dev_intf_data]() { - SetupDiDeleteDeviceInterfaceData(dev_info_set_hdl, &dev_intf_data); + auto dev_intf_data_guard = make_scope_exit([dev_info_set, &dev_intf_data]() { + SetupDiDeleteDeviceInterfaceData(dev_info_set, &dev_intf_data); }); // load device info data - SP_DEVINFO_DATA dev_info = { sizeof(dev_info) }; - if (!SetupDiGetDeviceInterfaceDetailW(dev_info_set_hdl, &dev_intf_data, nullptr, 0, nullptr, &dev_info)) { + SP_DEVINFO_DATA dev_info_data = { sizeof(dev_info_data) }; + if (!SetupDiGetDeviceInterfaceDetailW(dev_info_set, &dev_intf_data, nullptr, 0, nullptr, &dev_info_data)) { DWORD err = GetLastError(); if (err != ERROR_INSUFFICIENT_BUFFER) throw usb_error("internal error (SetupDiGetDeviceInterfaceDetailW)", err); } // create new device - device = create_device(dev_info_set_hdl, &dev_info); + device = create_device(dev_info_set, &dev_info_data); devices.push_back(device); } catch (const std::exception& e) { diff --git a/reference/windows/USB/usb_registry.hpp b/reference/windows/USB/usb_registry.hpp index a15dbe2f..42968c08 100644 --- a/reference/windows/USB/usb_registry.hpp +++ b/reference/windows/USB/usb_registry.hpp @@ -57,7 +57,7 @@ class usb_registry { bool handle_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static LRESULT handle_windows_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - std::shared_ptr create_device(HDEVINFO dev_info_set_hdl, SP_DEVINFO_DATA* dev_info); + std::shared_ptr create_device(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info); std::vector devices; From 8b36d9ee3221ec7dd0a99d976be7d2831802b35b Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 19 Jan 2023 21:30:49 +0100 Subject: [PATCH 180/433] Ignore exception if string desc unavailable --- .../net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java | 4 ++++ .../java/net/codecrete/usb/windows/WindowsUSBException.java | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index b1acd063..93ffdd82 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -8,6 +8,7 @@ package net.codecrete.usb.windows; import net.codecrete.usb.USBDevice; +import net.codecrete.usb.USBException; import net.codecrete.usb.common.ForeignMemory; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.common.USBDeviceRegistry; @@ -347,6 +348,9 @@ private String getStringDescriptor(Addressable hubHandle, int usbPortNumber, int var stringDesc = new StringDescriptor(getDescriptor(hubHandle, usbPortNumber, STRING_DESCRIPTOR_TYPE, index, DEFAULT_LANGUAGE, session)); return stringDesc.string(); + } catch (USBException e) { + System.err.printf("Info: [JavaDoesUSB] failed to retrieve string descriptor %d (%s) - ignoring%n", index, e.getMessage()); + return null; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java index c17bde26..4f3b0bcf 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java @@ -75,9 +75,11 @@ static void throwLastError(String message, Object... args) { private static String getErrorMessage(int errorCode) { try (var session = MemorySession.openConfined()) { var messagePointerHolder = session.allocate(ADDRESS); - Kernel32.FormatMessageW(Kernel32.FORMAT_MESSAGE_ALLOCATE_BUFFER() + int res = Kernel32.FormatMessageW(Kernel32.FORMAT_MESSAGE_ALLOCATE_BUFFER() | Kernel32.FORMAT_MESSAGE_FROM_SYSTEM() | Kernel32.FORMAT_MESSAGE_IGNORE_INSERTS(), NULL, errorCode, 0, messagePointerHolder, 0, NULL); + if (res == 0) + return "unspecified error"; var messagePointer = messagePointerHolder.get(ADDRESS, 0); String message = Win.createStringFromSegment(MemorySegment.ofAddress(messagePointer, 4000, session)); Kernel32.LocalFree(messagePointer); From 3fc0e601566d9f61fbe23c25db68788db2fab25b Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 21 Jan 2023 14:09:31 +0100 Subject: [PATCH 181/433] Windows: ignore missing string descriptors --- java-does-usb/pom.xml | 4 +++- .../net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java | 4 ++++ .../java/net/codecrete/usb/windows/WindowsUSBException.java | 4 +++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 7229e43f..6b3c7beb 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -57,7 +57,9 @@ 3.10.1 20 - --enable-preview + + --enable-preview + 20 20 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index b5583105..62f5fda4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -8,6 +8,7 @@ package net.codecrete.usb.windows; import net.codecrete.usb.USBDevice; +import net.codecrete.usb.USBException; import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.common.USBDeviceRegistry; @@ -391,6 +392,9 @@ private String getStringDescriptor(MemorySegment hubHandle, int usbPortNumber, i var stringDesc = new StringDescriptor(getDescriptor(hubHandle, usbPortNumber, STRING_DESCRIPTOR_TYPE, index, DEFAULT_LANGUAGE, arena)); return stringDesc.string(); + } catch (USBException e) { + System.err.printf("Info: [JavaDoesUSB] failed to retrieve string descriptor %d (%s) - ignoring%n", index, e.getMessage()); + return null; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java index fcdbfb41..7dd23888 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java @@ -79,9 +79,11 @@ static void throwLastError(MemorySegment lastErrorState, String message, Object. private static String getErrorMessage(int errorCode) { try (var arena = Arena.openConfined()) { var messagePointerHolder = arena.allocate(ADDRESS); - Kernel32.FormatMessageW(Kernel32.FORMAT_MESSAGE_ALLOCATE_BUFFER() + int res = Kernel32.FormatMessageW(Kernel32.FORMAT_MESSAGE_ALLOCATE_BUFFER() | Kernel32.FORMAT_MESSAGE_FROM_SYSTEM() | Kernel32.FORMAT_MESSAGE_IGNORE_INSERTS(), NULL, errorCode, 0, messagePointerHolder, 0, NULL); + if (res == 0) + return "unspecified error"; var messagePointer = messagePointerHolder.get(ForeignMemory.UNBOUNDED_ADDRESS, 0); String message = Win.createStringFromSegment(messagePointer); Kernel32.LocalFree(messagePointer); From 04a62d40657fb3a774e1c1c90442c1087e7677ba Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 30 Jan 2023 20:57:03 +0100 Subject: [PATCH 182/433] Fix compiler args in POM --- java-does-usb/pom.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index d706ef0d..139b70f9 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -57,7 +57,9 @@ 3.10.1 19 - --enable-preview + + --enable-preview + 19 19 From 7dfc41645167e96e1516f1ab9661d6b1434d0154 Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Mon, 30 Jan 2023 21:07:11 +0100 Subject: [PATCH 183/433] Increase version to 0.4.1 --- README.md | 5 +++-- examples/bulk_transfer/pom.xml | 4 ++-- examples/enumerate/README.md | 2 +- examples/enumerate/pom.xml | 4 ++-- examples/monitor/README.md | 2 +- examples/monitor/pom.xml | 4 ++-- examples/stm_dfu/README.md | 2 +- examples/stm_dfu/pom.xml | 4 ++-- java-does-usb/pom.xml | 2 +- 9 files changed, 15 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 69297fc1..41989542 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ The library uses the [Foreign Function & Memory API](https://github.com/openjdk/ ### Planned +- High-throughput input/output streams - Isochronous transfer ### Not planned @@ -38,14 +39,14 @@ If you are using Maven, add the below dependency to your pom.xml: net.codecrete.usb java-does-usb - 0.4.0 + 0.4.1 ``` If you are using Gradle, add the below dependency to your build.gradle file: ```groovy -compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '0.4.0' +compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '0.4.1' ``` ```java diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index bdca1f9d..ad0745b4 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples bulk-transfer - 0.4.0 + 0.4.1 bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.4.0 + 0.4.1 diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index acf5247d..9405cde4 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] ----------------< net.codecrete.usb.examples:enumerate >---------------- -[INFO] Building enumerate 0.4.0 +[INFO] Building enumerate 0.4.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ enumerate --- diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index efb357c2..67853aa7 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples enumerate - 0.4.0 + 0.4.1 enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.4.0 + 0.4.1 diff --git a/examples/monitor/README.md b/examples/monitor/README.md index 5f0c6d81..816498b1 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -----------------< net.codecrete.usb.examples:monitor >----------------- -[INFO] Building monitor 0.4.0 +[INFO] Building monitor 0.4.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ monitor --- diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index b54370a7..80bb68e6 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples monitor - 0.4.0 + 0.4.1 monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.4.0 + 0.4.1 diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index 25bd2c3e..b4c1742d 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -57,7 +57,7 @@ SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE="0666" Run the command below (adapting the file path depending on your specific board): ```shell -$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.4.0.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin +$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.4.1.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin DFU device found with serial 36C730037136. Target memory segment: Internal Flash Erasing page at 0x8000000 (size 0x4000) diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index f876b116..a7d18974 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples stm_dfu - 0.4.0 + 0.4.1 stm_dfu https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu @@ -13,7 +13,7 @@ net.codecrete.usb java-does-usb - 0.4.0 + 0.4.1 diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 139b70f9..dad1174a 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 0.4.0 + 0.4.1 19 From 4a82616291ea0aa3a88bc62aee6bd6ec52174dd2 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 1 Feb 2023 22:57:03 +0100 Subject: [PATCH 184/433] High throughput iostreams (C++/macOS) --- reference/macos/USB/iokit_helper.cpp | 5 + reference/macos/USB/iokit_helper.hpp | 2 + reference/macos/USB/speed_test.cpp | 26 +- reference/macos/USB/usb_device.cpp | 70 +++++- reference/macos/USB/usb_device.hpp | 48 +++- reference/macos/USB/usb_iostream.cpp | 223 ++++++++++++++++++ reference/macos/USB/usb_iostream.hpp | 151 ++++++++++++ reference/macos/USB/usb_registry.cpp | 61 ++++- reference/macos/USB/usb_registry.hpp | 26 +- reference/macos/usb.xcodeproj/project.pbxproj | 22 +- 10 files changed, 603 insertions(+), 31 deletions(-) create mode 100644 reference/macos/USB/usb_iostream.cpp create mode 100644 reference/macos/USB/usb_iostream.hpp diff --git a/reference/macos/USB/iokit_helper.cpp b/reference/macos/USB/iokit_helper.cpp index 49512179..8b089e68 100644 --- a/reference/macos/USB/iokit_helper.cpp +++ b/reference/macos/USB/iokit_helper.cpp @@ -55,3 +55,8 @@ int iokit_helper::ioreg_get_property_as_int(io_service_t service, CFStringRef pr CFNumberGetValue(static_cast(property), kCFNumberSInt32Type, &value); return value; } + +int iokit_helper::get_ref_count(void* obj) { + int* data = reinterpret_cast(obj)[1]; + return data[2]; +} diff --git a/reference/macos/USB/iokit_helper.hpp b/reference/macos/USB/iokit_helper.hpp index f69a4c56..56f3fa07 100644 --- a/reference/macos/USB/iokit_helper.hpp +++ b/reference/macos/USB/iokit_helper.hpp @@ -20,6 +20,8 @@ class iokit_helper { static std::string string_from_cfstring(CFStringRef str); static std::string ioreg_get_property_as_string(io_service_t service, CFStringRef property_name); static int ioreg_get_property_as_int(io_service_t service, CFStringRef property_name); + + static int get_ref_count(void* obj); }; template T** iokit_helper::get_interface(io_service_t service, CFUUIDRef plugin_type, CFUUIDRef interface_id) { diff --git a/reference/macos/USB/speed_test.cpp b/reference/macos/USB/speed_test.cpp index 40141d8f..ab60607b 100644 --- a/reference/macos/USB/speed_test.cpp +++ b/reference/macos/USB/speed_test.cpp @@ -40,14 +40,17 @@ bool speed_test::transmit(int num_bytes) { prng seq(PRNG_INIT); - std::vector buf(2048); + std::vector buf(2000); int pos = 0; + auto is_ptr = device_->open_output_stream(ep_out_); + std::ostream& os = *is_ptr; + while (num_bytes > 0) { int n = std::min(num_bytes, static_cast(buf.size())); try { seq.fill(buf, n); - device_->transfer_out(ep_out_, buf, n); + os.write(reinterpret_cast(buf.data()), n); } catch (usb_error& error) { std::cerr << std::endl << "ERROR: " << error.what() << " (writing at pos " << pos << ")" << std::endl; @@ -66,12 +69,21 @@ bool speed_test::receive(int num_bytes) { prng seq(PRNG_INIT); int pos = 0; + std::vector data; + + auto is_ptr = device_->open_input_stream(ep_in_); + std::istream& is = *is_ptr; while (num_bytes > 0) { int n; try { - std::vector data = device_->transfer_in(ep_in_); - n = std::min(num_bytes, static_cast(data.size())); + data.resize(2000); + is.read(reinterpret_cast(data.data()), data.capacity()); + n = static_cast(is.gcount()); + if (n <= 0) + break; + data.resize(n); + int p = seq.verify(data, n); if (p != -1) { std::cerr << std::endl << "Invalid data received at pos " << (pos + p) << std::endl; @@ -89,6 +101,10 @@ bool speed_test::receive(int num_bytes) { update_progress(n); } + if (num_bytes != 0) { + std::cerr << std::endl << "ERROR: EOF encountered after " << pos << " bytes" << std::endl; + } + return true; } @@ -111,7 +127,7 @@ void speed_test::start_measurement() { } void speed_test::update_progress(int n) { - std::lock_guard lockGuard(progress_mutex); + std::lock_guard lock(progress_mutex); processed_bytes += n; } diff --git a/reference/macos/USB/usb_device.cpp b/reference/macos/USB/usb_device.cpp index 78869df8..ce342b87 100644 --- a/reference/macos/USB/usb_device.cpp +++ b/reference/macos/USB/usb_device.cpp @@ -9,6 +9,8 @@ #include "usb_device.hpp" #include "usb_error.hpp" +#include "usb_iostream.hpp" +#include "usb_registry.hpp" #include "scope.hpp" #include "iokit_helper.hpp" #include "config_parser.hpp" @@ -17,10 +19,11 @@ #include #include +#include #include -usb_device::usb_device(io_service_t service, IOUSBDeviceInterface** device, uint64_t entry_id, int vendor_id, int product_id) -: entry_id_(entry_id), device_(device), vendor_id_(vendor_id), product_id_(product_id), is_open_(false) { +usb_device::usb_device(usb_registry* registry, io_service_t service, IOUSBDeviceInterface** device, uint64_t entry_id, int vendor_id, int product_id) +: registry_(registry), entry_id_(entry_id), device_(device), vendor_id_(vendor_id), product_id_(product_id), is_open_(false) { manufacturer_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBVendorString)); product_ = iokit_helper::ioreg_get_property_as_string(service, CFSTR(kUSBProductString)); @@ -188,9 +191,13 @@ void usb_device::release_interface(int interface_number) { auto iter = claimed_interfaces_.find(interface_number); if (iter == claimed_interfaces_.end()) - throw usb_error("interface has been claimed"); + throw usb_error("interface has not been claimed"); IOUSBInterfaceInterface** interface = (*iter).second; + auto source = (*interface)->GetInterfaceAsyncEventSource(interface); + if (source != nullptr) + registry_->remove_event_source(source); + claimed_interfaces_.erase(iter); uintf->set_claimed(false); @@ -351,6 +358,25 @@ std::vector usb_device::control_transfer_in(const usb_control_request& return data; } +std::unique_ptr usb_device::open_input_stream(int endpoint_number) { + return std::unique_ptr(new usb_istream(registry_->get_shared_ptr(this), endpoint_number)); +} + +std::unique_ptr usb_device::open_output_stream(int endpoint_number) { + return std::unique_ptr(new usb_ostream(registry_->get_shared_ptr(this), endpoint_number)); +} + +void usb_device::abort_transfer(usb_direction direction, int endpoint_number) { + auto pipe = get_pipe(direction == usb_direction::in ? endpoint_number + 128 : endpoint_number); + IOUSBInterfaceInterface** interface = claimed_interfaces_[pipe->interface_number]; + + IOReturn ret = (*interface)->AbortPipe(interface, pipe->pipe_index); + usb_error::check(ret, "failed to abort transfer"); + + ret = (*interface)->ClearPipeStallBothEnds(interface, pipe->pipe_index); + usb_error::check(ret, "failed to clear pipe stall"); +} + const usb_device::pipe_info* usb_device::get_pipe(int endpoint_address) { auto it = std::find_if(pipes_.begin(), pipes_.end(), [endpoint_address](const pipe_info& pipe){ return pipe.endpoint_address == endpoint_address; }); @@ -403,3 +429,41 @@ int usb_device::get_alternate_index(int interface_number, int alternate_setting) return -1; } + +void usb_device::submit_transfer_in(int endpoint_number, uint8_t* buffer, int buffer_size, const std::function& completion) { + auto pipe = ep_in_pipe(endpoint_number); + IOUSBInterfaceInterface** interface = claimed_interfaces_[pipe->interface_number]; + create_event_source(interface); + + // submit request + IOReturn ret = (*interface)->ReadPipeAsync(interface, pipe->pipe_index, buffer, buffer_size, async_io_completed, + const_cast*>(&completion)); + usb_error::check(ret, "failed to submit async transfer"); +} + +void usb_device::submit_transfer_out(int endpoint_number, const uint8_t* data, int data_size, const std::function& completion) { + auto pipe = ep_out_pipe(endpoint_number); + IOUSBInterfaceInterface** interface = claimed_interfaces_[pipe->interface_number]; + create_event_source(interface); + + // submit request + IOReturn ret = (*interface)->WritePipeAsync(interface, pipe->pipe_index, const_cast(data), data_size, async_io_completed, + const_cast*>(&completion)); + usb_error::check(ret, "failed to submit async transfer"); +} + +void usb_device::create_event_source(IOUSBInterfaceInterface** interface) { + auto source = (*interface)->GetInterfaceAsyncEventSource(interface); + if (source == nullptr) { + IOReturn ret = (*interface)->CreateInterfaceAsyncEventSource(interface, &source); + usb_error::check(ret, "failed to create event source for interface"); + registry_->add_event_source(source); + } +} + +void usb_device::async_io_completed(void* refcon, IOReturn result, void* arg0) { + // 'refcon' is lambda function for completion, 'arg0' is the number of read bytes + int size = static_cast(reinterpret_cast(arg0)); + auto completion = reinterpret_cast*>(refcon); + (*completion)(result, size); +} diff --git a/reference/macos/USB/usb_device.hpp b/reference/macos/USB/usb_device.hpp index e601ea29..adb0a73d 100644 --- a/reference/macos/USB/usb_device.hpp +++ b/reference/macos/USB/usb_device.hpp @@ -12,6 +12,8 @@ #include #include +#include +#include #include #include #include @@ -20,6 +22,8 @@ #include "configuration.hpp" +class usb_registry; + /** * USB control request type. @@ -215,6 +219,37 @@ class usb_device { * @return received data */ std::vector control_transfer_in(const usb_control_request& request, int timeout = 0); + + /** + * Open a new input stream for a bulk endpoint. + * + * The input stream is optimized for maximum throughput. + * + * Do not use the input stream concurrently with other transfer operations on the same endpoint. The input stream + * buffers data for high throughput. When the stream is closed, any data in the buffers will be lost. + * + * @param endpoint_number endpoint number (between 1 and 127) + */ + std::unique_ptr open_input_stream(int endpoint_number); + + /** + * Open a new output stream for a bulk endpoint. + * + * The output stream is optimized for maximum throughput. + * + * Do not use the output stream concurrently with other transfer operations on the same endpoint. + * + * @param endpoint_number endpoint number (between 1 and 127) + */ + std::unique_ptr open_output_stream(int endpoint_number); + + /** + * Aborts all transfer on the specified endpoint. + * + * @param direction endpoint direction + * @param endpoint_number endpoint number (between 1 and 127) + */ + void abort_transfer(usb_direction direction, int endpoint_number); private: struct pipe_info { @@ -225,7 +260,7 @@ class usb_device { int interface_number; }; - usb_device(io_service_t service, IOUSBDeviceInterface** device, uint64_t entry_id, int vendor_id, int product_id); + usb_device(usb_registry* registry, io_service_t service, IOUSBDeviceInterface** device, uint64_t entry_id, int vendor_id, int product_id); uint64_t entry_id() const { return entry_id_; } void build_pipe_info(); const pipe_info* get_pipe(int endpoint_address); @@ -236,6 +271,15 @@ class usb_device { usb_interface* get_intf_ptr(int interface_number); int get_alternate_index(int interface_number, int alternate_setting); + // Submits async request (completion handler is not copied; lifetime must be managed by caller) + void submit_transfer_in(int endpoint_number, uint8_t* buffer, int buffer_size, const std::function& completion); + // Submits async request (completion handler is not copied; lifetime must be managed by caller) + void submit_transfer_out(int endpoint_number, const uint8_t* data, int data_size, const std::function& completion); + // Create event source for asynchronous communication (if needed) + void create_event_source(IOUSBInterfaceInterface** interface); + static void async_io_completed(void* refcon, IOReturn result, void* arg0); + + usb_registry* registry_; uint64_t entry_id_; IOUSBDeviceInterface** device_; bool is_open_; @@ -250,6 +294,8 @@ class usb_device { std::string serial_number_; friend class usb_registry; + friend class usb_istreambuf; + friend class usb_ostreambuf; }; typedef std::shared_ptr usb_device_ptr; diff --git a/reference/macos/USB/usb_iostream.cpp b/reference/macos/USB/usb_iostream.cpp new file mode 100644 index 00000000..b067db68 --- /dev/null +++ b/reference/macos/USB/usb_iostream.cpp @@ -0,0 +1,223 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#include "usb_iostream.hpp" +#include "usb_error.hpp" + +// --- usb_istreambuf --- + +usb_istreambuf::usb_istreambuf(usb_device_ptr device, int endpoint_number) +: device_(device), ep_num_(endpoint_number), is_closed_(false), submitted_index_(0), completed_index_(0), processed_index_(-1) { + setg(nullptr, nullptr, nullptr); + + packet_size_ = device->get_endpoint(usb_direction::in, endpoint_number).packet_size(); + + // allocate the buffers + for (int i = 0; i < num_outstanding_requests; i++) + request_buffers[i] = new uint8_t[packet_size_]; + + // create completion handler lambda + io_completion = [this](IOReturn result, int size) { on_completed(result, size); }; + + // start requests except for one + const std::lock_guard lock(io_mutex); + for (int i = 0; i < num_outstanding_requests - 1; i++) + submit_request(); +} + +usb_istreambuf::~usb_istreambuf() { + // free buffers + for (int i = 0; i < num_outstanding_requests; i++) + delete [] request_buffers[i]; +} + +void usb_istreambuf::close() { + is_closed_ = true; + io_condition.notify_all(); + device_->abort_transfer(usb_direction::in, ep_num_); +} + +void usb_istreambuf::submit_request() { + int index = submitted_index_ % num_outstanding_requests; + submitted_index_ += 1; + + device_->submit_transfer_in(ep_num_, request_buffers[index], packet_size_, io_completion); +} + +void usb_istreambuf::on_completed(IOReturn result, int size) { + const std::lock_guard lock(io_mutex); + if (is_closed_) { + completed_index_ += 1; + if (completed_index_ == submitted_index_) + delete this; + return; + } + + int index = completed_index_ % num_outstanding_requests; + request_sizes[index] = size; + request_results[index] = result; + + completed_index_ += 1; + io_condition.notify_all(); +} + +usb_istreambuf::int_type usb_istreambuf::underflow() { + if (is_closed_) + return traits_type::eof(); + + if (gptr() < egptr()) + return traits_type::to_int_type(*gptr()); + + // loop until no ZLP has been received + while (true) { + std::unique_lock wait_lock(io_mutex); + processed_index_ += 1; + submit_request(); + + // wait until a completed request is available + io_condition.wait(wait_lock, [this] { return completed_index_ - processed_index_ > 0 || is_closed_; }); + + if (is_closed_) + return traits_type::eof(); + + int index = processed_index_ % num_outstanding_requests; + usb_error::check(request_results[index], "error reading from USB endpoint"); + + // set stream buffer to buffer from completed request + char* buf = reinterpret_cast(request_buffers[index]); + int size = request_sizes[index]; + + if (size != 0) { + setg(buf, buf, buf + size); + return traits_type::to_int_type(*gptr()); + } + } +} + + +// --- usb_ostreambuf --- + +usb_ostreambuf::usb_ostreambuf(usb_device_ptr device, int endpoint_number) +: device_(device), ep_num_(endpoint_number), is_closed_(false), processing_index_(0), + completed_index_(0), checked_index_(0), needs_zlp_(false) { + + packet_size_ = device->get_endpoint(usb_direction::out, endpoint_number).packet_size(); + + // allocate the buffers + for (int i = 0; i < num_outstanding_requests; i++) + request_buffers[i] = new uint8_t[packet_size_]; + + char* buf = reinterpret_cast(request_buffers[0]); + setp(buf, buf + packet_size_); + + // create completion handler lambda + io_completion = [this](IOReturn result, int size) { on_completed(result, size); }; +} + +usb_ostreambuf::~usb_ostreambuf() { + // free buffers + for (int i = 0; i < num_outstanding_requests; i++) + delete [] request_buffers[i]; +} + +int usb_ostreambuf::sync() { + std::unique_lock wait_lock(io_mutex); + + // submit request if there is any data in the current buffer + auto size = pptr() - pbase(); + if (size > 0) { + int index = processing_index_ % num_outstanding_requests; + device_->submit_transfer_out(ep_num_, request_buffers[index], (int)size, io_completion); + processing_index_ += 1; + needs_zlp_ = size == packet_size_; + } + + // send a zero-length packet if required + if (needs_zlp_) { + // wait until an unused buffer is available + io_condition.wait(wait_lock, [this] { return processing_index_ - completed_index_ < num_outstanding_requests; }); + check_for_errors(); + + device_->submit_transfer_out(ep_num_, nullptr, 0, io_completion); + processing_index_ += 1; + needs_zlp_ = false; + } + + // wait until all buffers have been transmitted + io_condition.wait(wait_lock, [this] { return processing_index_ == completed_index_; }); + check_for_errors(); + + return 0; +} + +int usb_ostreambuf::overflow (int c) { + std::unique_lock wait_lock(io_mutex); + + // submit request + auto size = pptr() - pbase(); + int index = processing_index_ % num_outstanding_requests; + device_->submit_transfer_out(ep_num_, request_buffers[index], (int)size, io_completion); + processing_index_ += 1; + needs_zlp_ = size == packet_size_; + + // wait until an unused buffer is available + io_condition.wait(wait_lock, [this] { return processing_index_ - completed_index_ < num_outstanding_requests; }); + check_for_errors(); + + // configure stream buffer + index = processing_index_ % num_outstanding_requests; + char* buf = reinterpret_cast(request_buffers[index]); + setp(buf, buf + packet_size_); + + // insert char + if (c != traits_type::eof()) { + *pptr() = (char)c; + pbump( 1 ); + } + + return c; +} + +void usb_ostreambuf::on_completed(IOReturn result, int size) { + const std::lock_guard lock(io_mutex); + int index = completed_index_ % num_outstanding_requests; + request_results[index] = result; + completed_index_ += 1; + io_condition.notify_all(); +} + +void usb_ostreambuf::check_for_errors() { + while (completed_index_ - checked_index_ > 0) { + int index = completed_index_ % num_outstanding_requests; + usb_error::check(request_results[index], "error writing to USB endpoint"); + checked_index_ += 1; + } +} + + +// --- usb_istream --- + +usb_istream::usb_istream(usb_device_ptr device, int ep_num) + : std::istream(new usb_istreambuf(device, ep_num)) {} + +usb_istream::~usb_istream() { + // close buffer (it will deallocate itself) + static_cast(rdbuf())->close(); +} + + +// --- usb_ostream --- + +usb_ostream::usb_ostream(usb_device_ptr device, int ep_num) + : std::ostream(new usb_ostreambuf(device, ep_num)) {} + +usb_ostream::~usb_ostream() { + // flush all data + static_cast(rdbuf())->pubsync(); +} diff --git a/reference/macos/USB/usb_iostream.hpp b/reference/macos/USB/usb_iostream.hpp new file mode 100644 index 00000000..7860a313 --- /dev/null +++ b/reference/macos/USB/usb_iostream.hpp @@ -0,0 +1,151 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#pragma once + +#include +#include +#include +#include +#include "usb_device.hpp" + +/** + * Input stream buffer for USB bulk or interrupt endpoint. + * + * The stream buffer is internally used by an input stream. It submits multiple asynchronous IO requests to + * achieve maximum throughput. + */ +class usb_istreambuf : public std::streambuf { +public: + /// Constructor + usb_istreambuf(usb_device_ptr device, int ep_num); + /// Destructor + virtual ~usb_istreambuf(); + + /// Closes this buffer. This stream buffer will automatically free itself. + void close(); + +protected: + /// Called when the internal buffer has no further data to read. + virtual int_type underflow(); + + void on_completed(IOReturn result, int size); + +private: + void submit_request(); + + /// Maximum number of concurrently outstanding requests + static constexpr int num_outstanding_requests = 4; + + /// USB device + usb_device_ptr device_; + /// endpoint number + int ep_num_; + /// Indicates that this stream buffer is closed + bool is_closed_; + /// packet size + int packet_size_; + /// Mutex for synchronization between input stream caller and background thread handling IO completion. + std::mutex io_mutex; + /// Condition for synchronization between input stream caller and background thread handling IO completion + std::condition_variable io_condition; + /// Index after last submitted IO request + unsigned int submitted_index_; + /// Index after last completed IO request + unsigned int completed_index_; + /// Index after last processed IO request + unsigned int processed_index_; + /// Data buffers for receiving data + uint8_t* request_buffers[num_outstanding_requests]; + /// Size of received data + int request_sizes[num_outstanding_requests]; + /// Result code of IO request + IOReturn request_results[num_outstanding_requests]; + /// IO completion lambda + std::function io_completion; +}; + +/** + * Output stream buffer for USB bulk or interrupt endpoint. + * + * The stream buffer is internally used by an output stream. It submits multiple asynchronous IO requests to + * achieve maximum throughput. + */ +class usb_ostreambuf : public std::streambuf { +public: + /// Constructor + usb_ostreambuf(usb_device_ptr device, int ep_num); + /// Destructor + virtual ~usb_ostreambuf(); + + virtual int sync(); + +protected: + /// Called when the internal buffer has no space left to add more data. + virtual int overflow (int c); + + void on_completed(IOReturn result, int size); + + void check_for_errors(); + +private: + void submit_request(); + + /// Maximum number of concurrently outstanding requests + static constexpr int num_outstanding_requests = 4; + + /// USB device + usb_device_ptr device_; + /// endpoint number + int ep_num_; + /// Indicates that this stream buffer is closed + bool is_closed_; + /// Indicates if a zero-length packet is required + bool needs_zlp_; + /// packet size + int packet_size_; + /// Mutex for synchronization between output stream caller and background thread handling IO completion. + std::mutex io_mutex; + /// Condition for synchronization between output stream caller and background thread handling IO completion + std::condition_variable io_condition; + /// Index of buffer being currently used by base class + unsigned int processing_index_; + /// Index after last completed IO request + unsigned int completed_index_; + /// Index after last completed IO request that has been checked for errors + unsigned int checked_index_; + /// Data buffers for transmitting data + uint8_t* request_buffers[num_outstanding_requests]; + /// Result code of IO request + IOReturn request_results[num_outstanding_requests]; + /// IO completion lambda + std::function io_completion; +}; + +/** + * Input stream for reading from a USB bulk endpoint + */ +class usb_istream : public std::istream { +public: + /// Constructor + usb_istream(usb_device_ptr device, int ep_num); + /// Destructor + ~usb_istream(); +}; + +/** + * Output stream for writing to a USB bulk endpoint + */ +class usb_ostream : public std::ostream { +public: + /// Constructor + usb_ostream(usb_device_ptr device, int ep_num); + /// Destructor + ~usb_ostream(); +}; diff --git a/reference/macos/USB/usb_registry.cpp b/reference/macos/USB/usb_registry.cpp index fda37b13..2e673ef4 100644 --- a/reference/macos/USB/usb_registry.cpp +++ b/reference/macos/USB/usb_registry.cpp @@ -19,10 +19,10 @@ #include usb_registry::usb_registry() -: notify_port(nullptr), run_loop_source(nullptr), +: notify_port(nullptr), monitor_run_loop_source(nullptr), device_connected_iter(0), device_disconnected_iter(0), on_connected_callback(nullptr), on_disconnected_callback(nullptr), - is_device_list_ready(false) { + async_io_run_loop(nullptr), is_device_list_ready(false) { } usb_registry::~usb_registry() { @@ -34,9 +34,12 @@ usb_registry::~usb_registry() { IOObjectRelease(device_disconnected_iter); device_disconnected_iter = 0; } - + if (async_io_run_loop != nullptr) { + CFRunLoopStop(async_io_run_loop); + async_io_thread.join(); + } if (notify_port != nullptr) { - CFRunLoopStop(run_loop); + CFRunLoopStop(monitor_run_loop); monitor_thread.join(); IONotificationPortDestroy(notify_port); @@ -59,17 +62,17 @@ void usb_registry::set_on_device_disconnected(std::function wait_lock(monitor_mutex); + std::unique_lock wait_lock(monitor_mutex); monitor_condition.wait(wait_lock, [this] { return is_device_list_ready; }); } void usb_registry::monitor() { notify_port = IONotificationPortCreate(kIOMainPortDefault); - run_loop_source = IONotificationPortGetRunLoopSource(notify_port); + monitor_run_loop_source = IONotificationPortGetRunLoopSource(notify_port); - run_loop = CFRunLoopGetCurrent(); - CFRunLoopAddSource(run_loop, run_loop_source, kCFRunLoopDefaultMode); + monitor_run_loop = CFRunLoopGetCurrent(); + CFRunLoopAddSource(monitor_run_loop, monitor_run_loop_source, kCFRunLoopDefaultMode); auto matching_dict = IOServiceMatching(kIOUSBDeviceClassName); // Interested in instances of USB device @@ -103,7 +106,11 @@ void usb_registry::monitor() { // iterate to activate notifications device_disconnected(device_disconnected_iter); - is_device_list_ready = true; + { + std::lock_guard lock(monitor_mutex); + is_device_list_ready = true; + } + monitor_condition.notify_all(); // start run loop @@ -142,7 +149,7 @@ void usb_registry::device_connected(io_iterator_t iterator) { continue; // ignore // Create new device - std::shared_ptr device(new usb_device(service, dev, entry_id, vendor_id, product_id)); + std::shared_ptr device(new usb_device(this, service, dev, entry_id, vendor_id, product_id)); devices.push_back(device); // Call callback function @@ -183,3 +190,37 @@ void usb_registry::device_disconnected(io_iterator_t iterator) { on_disconnected_callback(device); } } + +std::shared_ptr usb_registry::get_shared_ptr(usb_device* device) { + auto it = std::find_if(devices.cbegin(), devices.cend(), [device](auto dev) { return dev.get() == device; }); + if (it == devices.cend()) + return nullptr; + + return *it; +} + +void usb_registry::add_event_source(CFRunLoopSourceRef source) { + std::unique_lock wait_lock(async_io_mutex); + if (async_io_run_loop == nullptr) { + async_io_thread = std::thread(&usb_registry::async_io_run, this, source); + async_io_condition.wait(wait_lock, [this] { return async_io_run_loop != nullptr; }); + return; + } + + CFRunLoopAddSource(async_io_run_loop, source, kCFRunLoopDefaultMode); +} + +void usb_registry::remove_event_source(CFRunLoopSourceRef source) { + CFRunLoopRemoveSource(async_io_run_loop, source, kCFRunLoopDefaultMode); +} + +void usb_registry::async_io_run(CFRunLoopSourceRef first_source) { + { + std::lock_guard lock(async_io_mutex); + async_io_run_loop = CFRunLoopGetCurrent(); + CFRunLoopAddSource(async_io_run_loop, first_source, kCFRunLoopDefaultMode); + } + + async_io_condition.notify_all(); + CFRunLoopRun(); +} diff --git a/reference/macos/USB/usb_registry.hpp b/reference/macos/USB/usb_registry.hpp index 0f66c724..86e90e5f 100644 --- a/reference/macos/USB/usb_registry.hpp +++ b/reference/macos/USB/usb_registry.hpp @@ -52,20 +52,38 @@ class usb_registry { static void device_connected_f(void *refcon, io_iterator_t iterator); static void device_disconnected_f(void *refcon, io_iterator_t iterator); + + std::shared_ptr get_shared_ptr(usb_device* device); + // Add event source to background thread for handling asynchronous IO completion + void add_event_source(CFRunLoopSourceRef source); + // Remove event source to background thread for handling asynchronous IO completion + void remove_event_source(CFRunLoopSourceRef source); + // Main function for background thread + void async_io_run(CFRunLoopSourceRef first_source); std::vector devices; std::function on_connected_callback; std::function on_disconnected_callback; + // monitoring thread, port, run loop, mutex, condition etc. std::thread monitor_thread; - CFRunLoopRef run_loop; + CFRunLoopRef monitor_run_loop; IONotificationPortRef notify_port; - CFRunLoopSourceRef run_loop_source; + CFRunLoopSourceRef monitor_run_loop_source; + std::mutex monitor_mutex; + std::condition_variable monitor_condition; + + // async_io thread and run loop + std::thread async_io_thread; + volatile CFRunLoopRef async_io_run_loop; + std::mutex async_io_mutex; + std::condition_variable async_io_condition; + io_iterator_t device_connected_iter; io_iterator_t device_disconnected_iter; bool is_device_list_ready; - std::mutex monitor_mutex; - std::condition_variable monitor_condition; + + friend class usb_device; }; diff --git a/reference/macos/usb.xcodeproj/project.pbxproj b/reference/macos/usb.xcodeproj/project.pbxproj index 0a38e428..bd3bf925 100644 --- a/reference/macos/usb.xcodeproj/project.pbxproj +++ b/reference/macos/usb.xcodeproj/project.pbxproj @@ -20,6 +20,7 @@ 64937C7E28D60C82009BD0C2 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 64937C7D28D60C82009BD0C2 /* CoreFoundation.framework */; }; 64937C8128D6F9DE009BD0C2 /* tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64937C7F28D6F9DE009BD0C2 /* tests.cpp */; }; 64937C8428D71D31009BD0C2 /* assertion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 64937C8228D71D31009BD0C2 /* assertion.cpp */; }; + 649E7E1A298AEB580043B589 /* usb_iostream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 649E7E18298AEB580043B589 /* usb_iostream.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -60,6 +61,8 @@ 64937C8028D6F9DE009BD0C2 /* tests.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = tests.hpp; sourceTree = ""; }; 64937C8228D71D31009BD0C2 /* assertion.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = assertion.cpp; sourceTree = ""; }; 64937C8328D71D31009BD0C2 /* assertion.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = assertion.hpp; sourceTree = ""; }; + 649E7E18298AEB580043B589 /* usb_iostream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = usb_iostream.cpp; sourceTree = ""; }; + 649E7E19298AEB580043B589 /* usb_iostream.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = usb_iostream.hpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -95,16 +98,20 @@ 64937C6228D5EBF1009BD0C2 /* USB */ = { isa = PBXGroup; children = ( - 64835E5D290BCA9F00113E4E /* config_parser.cpp */, - 64835E5E290BCA9F00113E4E /* config_parser.hpp */, - 64835E5F290BCA9F00113E4E /* configuration.cpp */, - 64835E5C290BCA9F00113E4E /* configuration.hpp */, 64937C8328D71D31009BD0C2 /* assertion.hpp */, 64937C8228D71D31009BD0C2 /* assertion.cpp */, + 64835E5E290BCA9F00113E4E /* config_parser.hpp */, + 64835E5D290BCA9F00113E4E /* config_parser.cpp */, + 64835E5C290BCA9F00113E4E /* configuration.hpp */, + 64835E5F290BCA9F00113E4E /* configuration.cpp */, 64937C6D28D5ED1F009BD0C2 /* iokit_helper.hpp */, 64937C6C28D5ED1F009BD0C2 /* iokit_helper.cpp */, 64937C6328D5EBF1009BD0C2 /* main.cpp */, + 64292E7229144D6C004F6169 /* prng.hpp */, + 64292E7129144D6C004F6169 /* prng.cpp */, 64937C6F28D5ED1F009BD0C2 /* scope.hpp */, + 64292E7529144DE1004F6169 /* speed_test.hpp */, + 64292E7429144DE1004F6169 /* speed_test.cpp */, 64937C8028D6F9DE009BD0C2 /* tests.hpp */, 64937C7F28D6F9DE009BD0C2 /* tests.cpp */, 64937C7528D5ED8D009BD0C2 /* usb_error.hpp */, @@ -113,10 +120,8 @@ 64937C7728D5FE6D009BD0C2 /* usb_device.cpp */, 64937C6E28D5ED1F009BD0C2 /* usb_registry.hpp */, 64937C6B28D5ED1F009BD0C2 /* usb_registry.cpp */, - 64292E7129144D6C004F6169 /* prng.cpp */, - 64292E7229144D6C004F6169 /* prng.hpp */, - 64292E7429144DE1004F6169 /* speed_test.cpp */, - 64292E7529144DE1004F6169 /* speed_test.hpp */, + 649E7E19298AEB580043B589 /* usb_iostream.hpp */, + 649E7E18298AEB580043B589 /* usb_iostream.cpp */, ); path = USB; sourceTree = ""; @@ -193,6 +198,7 @@ 64937C7928D5FE6D009BD0C2 /* usb_device.cpp in Sources */, 64937C7228D5ED1F009BD0C2 /* usb_registry.cpp in Sources */, 64835E60290BCA9F00113E4E /* config_parser.cpp in Sources */, + 649E7E1A298AEB580043B589 /* usb_iostream.cpp in Sources */, 64937C6428D5EBF1009BD0C2 /* main.cpp in Sources */, 64937C7628D5ED8D009BD0C2 /* usb_error.cpp in Sources */, 64292E7329144D6C004F6169 /* prng.cpp in Sources */, From 67e20fe3ffb31290bd65fc4522e3db970175add5 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 4 Feb 2023 15:03:44 +0100 Subject: [PATCH 185/433] High throughput iostreams (C++/Linux) --- reference/linux/CMakeLists.txt | 1 + reference/linux/speed_test.cpp | 26 +++- reference/linux/usb_device.cpp | 42 ++++- reference/linux/usb_device.hpp | 33 +++- reference/linux/usb_error.cpp | 5 + reference/linux/usb_error.hpp | 8 + reference/linux/usb_iostream.cpp | 254 +++++++++++++++++++++++++++++++ reference/linux/usb_iostream.hpp | 144 ++++++++++++++++++ reference/linux/usb_registry.cpp | 154 +++++++++++++++++-- reference/linux/usb_registry.hpp | 19 ++- 10 files changed, 663 insertions(+), 23 deletions(-) create mode 100644 reference/linux/usb_iostream.cpp create mode 100644 reference/linux/usb_iostream.hpp diff --git a/reference/linux/CMakeLists.txt b/reference/linux/CMakeLists.txt index d6596572..af64e603 100644 --- a/reference/linux/CMakeLists.txt +++ b/reference/linux/CMakeLists.txt @@ -18,6 +18,7 @@ set(SOURCES tests.cpp tests.hpp usb_device.cpp usb_device.hpp usb_error.cpp usb_error.hpp + usb_iostream.cpp usb_iostream.hpp usb_registry.cpp usb_registry.hpp ) diff --git a/reference/linux/speed_test.cpp b/reference/linux/speed_test.cpp index 40141d8f..ab60607b 100644 --- a/reference/linux/speed_test.cpp +++ b/reference/linux/speed_test.cpp @@ -40,14 +40,17 @@ bool speed_test::transmit(int num_bytes) { prng seq(PRNG_INIT); - std::vector buf(2048); + std::vector buf(2000); int pos = 0; + auto is_ptr = device_->open_output_stream(ep_out_); + std::ostream& os = *is_ptr; + while (num_bytes > 0) { int n = std::min(num_bytes, static_cast(buf.size())); try { seq.fill(buf, n); - device_->transfer_out(ep_out_, buf, n); + os.write(reinterpret_cast(buf.data()), n); } catch (usb_error& error) { std::cerr << std::endl << "ERROR: " << error.what() << " (writing at pos " << pos << ")" << std::endl; @@ -66,12 +69,21 @@ bool speed_test::receive(int num_bytes) { prng seq(PRNG_INIT); int pos = 0; + std::vector data; + + auto is_ptr = device_->open_input_stream(ep_in_); + std::istream& is = *is_ptr; while (num_bytes > 0) { int n; try { - std::vector data = device_->transfer_in(ep_in_); - n = std::min(num_bytes, static_cast(data.size())); + data.resize(2000); + is.read(reinterpret_cast(data.data()), data.capacity()); + n = static_cast(is.gcount()); + if (n <= 0) + break; + data.resize(n); + int p = seq.verify(data, n); if (p != -1) { std::cerr << std::endl << "Invalid data received at pos " << (pos + p) << std::endl; @@ -89,6 +101,10 @@ bool speed_test::receive(int num_bytes) { update_progress(n); } + if (num_bytes != 0) { + std::cerr << std::endl << "ERROR: EOF encountered after " << pos << " bytes" << std::endl; + } + return true; } @@ -111,7 +127,7 @@ void speed_test::start_measurement() { } void speed_test::update_progress(int n) { - std::lock_guard lockGuard(progress_mutex); + std::lock_guard lock(progress_mutex); processed_bytes += n; } diff --git a/reference/linux/usb_device.cpp b/reference/linux/usb_device.cpp index 5ee5c765..02427bc6 100644 --- a/reference/linux/usb_device.cpp +++ b/reference/linux/usb_device.cpp @@ -8,6 +8,8 @@ // #include "usb_device.hpp" +#include "usb_iostream.hpp" +#include "usb_registry.hpp" #include "usb_error.hpp" #include "scope.hpp" #include "config_parser.hpp" @@ -21,8 +23,8 @@ #include -usb_device::usb_device(const char* path, int vendor_id, int product_id) -: path_(path), fd_(-1), vendor_id_(vendor_id), product_id_(product_id) { +usb_device::usb_device(usb_registry* registry, const char* path, int vendor_id, int product_id) +: registry_(registry), path_(path), fd_(-1), uses_urbs_(false), vendor_id_(vendor_id), product_id_(product_id) { read_descriptor(); } @@ -112,6 +114,11 @@ void usb_device::open() { void usb_device::close() { if (!is_open()) return; + + if (uses_urbs_) { + registry_->remove_async_fd(fd_); + uses_urbs_ = false; + } for (auto& intf : interfaces_) intf.set_claimed(false); @@ -170,7 +177,7 @@ std::vector usb_device::transfer_in(int endpoint_number, int timeout) { std::vector data(ep->packet_size()); - struct usbdevfs_bulktransfer transfer = {0}; + usbdevfs_bulktransfer transfer = {0}; transfer.ep = endpoint_number + 128; transfer.len = ep->packet_size(); transfer.timeout = timeout; @@ -190,7 +197,7 @@ void usb_device::transfer_out(int endpoint_number, const std::vector& d check_endpoint(usb_direction::out, endpoint_number); - struct usbdevfs_bulktransfer transfer = {0}; + usbdevfs_bulktransfer transfer = {0}; transfer.ep = endpoint_number; transfer.len = data.size(); transfer.timeout = timeout; @@ -206,7 +213,7 @@ int usb_device::control_transfer_core(const usb_control_request &request, uint8_ if (!is_open()) throw usb_error("USB device is not open"); - struct usbdevfs_ctrltransfer ctrl_request = {0}; + usbdevfs_ctrltransfer ctrl_request = {0}; ctrl_request.bRequestType = request.bmRequestType; ctrl_request.bRequest = request.bRequest; ctrl_request.wValue = request.wValue; @@ -272,3 +279,28 @@ const usb_endpoint* usb_device::check_endpoint(usb_direction direction, int endp throw usb_error("no such endpoint"); } + +std::unique_ptr usb_device::open_input_stream(int endpoint_number) { + return std::unique_ptr(new usb_istream(registry_->get_shared_ptr(this), endpoint_number)); +} + +std::unique_ptr usb_device::open_output_stream(int endpoint_number) { + return std::unique_ptr(new usb_ostream(registry_->get_shared_ptr(this), endpoint_number)); +} + +void usb_device::submit_urb(usbdevfs_urb* urb) { + if (!uses_urbs_) { + uses_urbs_ = true; + registry_->add_async_fd(fd_); + } + + int result = ioctl(fd_, USBDEVFS_SUBMITURB, urb); + if (result < 0) + usb_error::throw_error("Failed to submit URB"); +} + +void usb_device::cancel_urb(usbdevfs_urb* urb) { + int result = ioctl(fd_, USBDEVFS_DISCARDURB, urb); + if (result < 0) + usb_error::throw_error("Failed to submit URB"); +} diff --git a/reference/linux/usb_device.hpp b/reference/linux/usb_device.hpp index d9aca1a9..065f23bf 100644 --- a/reference/linux/usb_device.hpp +++ b/reference/linux/usb_device.hpp @@ -68,6 +68,8 @@ struct usb_control_request { } }; +class usb_registry; +struct usbdevfs_urb; /** * USB device. @@ -203,17 +205,44 @@ class usb_device { */ std::vector control_transfer_in(const usb_control_request& request, int timeout = 0); + /** + * Open a new input stream for a bulk endpoint. + * + * The input stream is optimized for maximum throughput. + * + * Do not use the input stream concurrently with other transfer operations on the same endpoint. The input stream + * buffers data for high throughput. When the stream is closed, any data in the buffers will be lost. + * + * @param endpoint_number endpoint number (between 1 and 127) + */ + std::unique_ptr open_input_stream(int endpoint_number); + + /** + * Open a new output stream for a bulk endpoint. + * + * The output stream is optimized for maximum throughput. + * + * Do not use the output stream concurrently with other transfer operations on the same endpoint. + * + * @param endpoint_number endpoint number (between 1 and 127) + */ + std::unique_ptr open_output_stream(int endpoint_number); + private: - usb_device(const char* path, int vendor_id, int product_id); + usb_device(usb_registry* registry, const char* path, int vendor_id, int product_id); void set_product_strings(const char* manufacturer, const char* product, const char* serial_number); const char* path() const { return path_.c_str(); } int control_transfer_core(const usb_control_request& request, uint8_t* data, int timeout); void read_descriptor(); usb_interface* get_intf_ptr(int number); const usb_endpoint* check_endpoint(usb_direction direction, int endpoint_number); + void submit_urb(usbdevfs_urb* urb); + void cancel_urb(usbdevfs_urb* urb); + usb_registry* registry_; std::string path_; int fd_; + bool uses_urbs_; std::set claimed_interfaces_; std::vector interfaces_; @@ -224,6 +253,8 @@ class usb_device { std::string serial_number_; friend class usb_registry; + friend class usb_istreambuf; + friend class usb_ostreambuf; }; typedef std::shared_ptr usb_device_ptr; diff --git a/reference/linux/usb_error.cpp b/reference/linux/usb_error.cpp index 6bcc5003..1844bd54 100644 --- a/reference/linux/usb_error.cpp +++ b/reference/linux/usb_error.cpp @@ -30,6 +30,11 @@ void usb_error::throw_error(const char* message) { throw usb_error(message, errno); } +void usb_error::check(int code, const char* message) { + if (code != 0) + throw usb_error(message, code); +} + std::string usb_error::full_message(const char* message, int code) { if (code == 0) return message; diff --git a/reference/linux/usb_error.hpp b/reference/linux/usb_error.hpp index e3a6553c..f5218417 100644 --- a/reference/linux/usb_error.hpp +++ b/reference/linux/usb_error.hpp @@ -36,6 +36,14 @@ class usb_error : public std::exception { */ static void throw_error(const char* message); + /** + * Throws a USB error exception if the code indicates an error. + * + * @param code error code + * @param message additional information for the error message + */ + static void check(int code, const char* message); + private: static std::string full_message(const char* message, int code); diff --git a/reference/linux/usb_iostream.cpp b/reference/linux/usb_iostream.cpp new file mode 100644 index 00000000..ab79bfde --- /dev/null +++ b/reference/linux/usb_iostream.cpp @@ -0,0 +1,254 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for Linux +// + +#include "usb_iostream.hpp" +#include "usb_error.hpp" +#include + +// --- usb_istreambuf --- + +usb_istreambuf::usb_istreambuf(usb_device_ptr device, int endpoint_number) +: device_(device), ep_num_(endpoint_number), is_closed_(false), submitted_index_(0), completed_index_(0), processed_index_(-1) { + setg(nullptr, nullptr, nullptr); + + buffer_size_ = 8 * device->get_endpoint(usb_direction::in, endpoint_number).packet_size(); + + // create completion handler lambda + io_completion = [this]() { on_completed(); }; + + // initialize the URBs + for (int i = 0; i < num_outstanding_requests; i++) { + usbdevfs_urb* urb = urbs_ + i; + memset(urb, 0, sizeof(*urb)); + urb->type = USBDEVFS_URB_TYPE_BULK; + urb->endpoint = 128 + ep_num_; + urb->buffer = new uint8_t[buffer_size_]; + urb->buffer_length = buffer_size_; + urb->usercontext = &io_completion; + } + + // start requests except for one + const std::lock_guard lock(io_mutex); + for (int i = 0; i < num_outstanding_requests - 1; i++) + submit_request(); +} + +usb_istreambuf::~usb_istreambuf() { + close(); + + // free buffers + for (int i = 0; i < num_outstanding_requests; i++) + delete [] reinterpret_cast(urbs_[i].buffer); +} + +void usb_istreambuf::close() { + const std::lock_guard lock(io_mutex); + + is_closed_ = true; + io_condition.notify_all(); + + while (submitted_index_ > completed_index_) { + submitted_index_ -= 1; + int index = submitted_index_ % num_outstanding_requests; + device_->cancel_urb(&urbs_[index]); + } +} + +void usb_istreambuf::submit_request() { + int index = submitted_index_ % num_outstanding_requests; + submitted_index_ += 1; + + device_->submit_urb(&urbs_[index]); +} + +void usb_istreambuf::on_completed() { + const std::lock_guard lock(io_mutex); + if (is_closed_) { + completed_index_ += 1; + if (completed_index_ == submitted_index_) + delete this; + return; + } + + completed_index_ += 1; + io_condition.notify_all(); +} + +usb_istreambuf::int_type usb_istreambuf::underflow() { + if (is_closed_) + return traits_type::eof(); + + if (gptr() < egptr()) + return traits_type::to_int_type(*gptr()); + + // loop until no ZLP has been received + while (true) { + std::unique_lock wait_lock(io_mutex); + processed_index_ += 1; + submit_request(); + + // wait until a completed request is available + io_condition.wait(wait_lock, [this] { return completed_index_ - processed_index_ > 0 || is_closed_; }); + + if (is_closed_) + return traits_type::eof(); + + int index = processed_index_ % num_outstanding_requests; + usbdevfs_urb* urb = urbs_ + index; + usb_error::check(urb->status, "error reading from USB endpoint"); + + // set stream buffer to buffer from completed request + char* buf = reinterpret_cast(urb->buffer); + int size = urb->actual_length; + + if (size != 0) { + setg(buf, buf, buf + size); + return traits_type::to_int_type(*gptr()); + } + } +} + + +// --- usb_ostreambuf --- + +usb_ostreambuf::usb_ostreambuf(usb_device_ptr device, int endpoint_number) +: device_(device), ep_num_(endpoint_number), is_closed_(false), processing_index_(0), + completed_index_(0), checked_index_(0), needs_zlp_(false) { + + buffer_size_ = 8 * device->get_endpoint(usb_direction::out, endpoint_number).packet_size(); + + // create completion handler lambda + io_completion = [this]() { on_completed(); }; + + // initialize the URBs + for (int i = 0; i < num_outstanding_requests; i++) { + usbdevfs_urb* urb = urbs_ + i; + memset(urb, 0, sizeof(urb)); + urb->type = USBDEVFS_URB_TYPE_BULK; + urb->endpoint = ep_num_; + urb->buffer = new uint8_t[buffer_size_]; + urb->buffer_length = buffer_size_; + urb->usercontext = &io_completion; + } + + char* buf = reinterpret_cast(urbs_[0].buffer); + setp(buf, buf + buffer_size_); +} + +usb_ostreambuf::~usb_ostreambuf() { + // flush all data + sync(); + + // free buffers + for (int i = 0; i < num_outstanding_requests; i++) + delete [] reinterpret_cast(urbs_[i].buffer); +} + +int usb_ostreambuf::sync() { + std::unique_lock wait_lock(io_mutex); + + // submit request if there is any data in the current buffer + auto size = pptr() - pbase(); + if (size > 0) { + int index = processing_index_ % num_outstanding_requests; + usbdevfs_urb* urb = urbs_ + index; + urb->buffer_length = size; + device_->submit_urb(urb); + processing_index_ += 1; + needs_zlp_ = size == buffer_size_; + } + + // send a zero-length packet if required + if (needs_zlp_) { + // wait until an unused buffer is available + io_condition.wait(wait_lock, [this] { return processing_index_ - completed_index_ < num_outstanding_requests; }); + check_for_errors(); + + int index = processing_index_ % num_outstanding_requests; + usbdevfs_urb* urb = urbs_ + index; + urb->buffer_length = 0; + device_->submit_urb(urb); + processing_index_ += 1; + needs_zlp_ = false; + } + + // wait until all buffers have been transmitted + io_condition.wait(wait_lock, [this] { return processing_index_ == completed_index_; }); + check_for_errors(); + + return 0; +} + +int usb_ostreambuf::overflow (int c) { + std::unique_lock wait_lock(io_mutex); + + // submit request + auto size = pptr() - pbase(); + int index = processing_index_ % num_outstanding_requests; + usbdevfs_urb* urb = urbs_ + index; + urb->buffer_length = size; + device_->submit_urb(urb); + processing_index_ += 1; + needs_zlp_ = size == buffer_size_; + + // wait until an unused buffer is available + io_condition.wait(wait_lock, [this] { return processing_index_ - completed_index_ < num_outstanding_requests; }); + check_for_errors(); + + // configure stream buffer + index = processing_index_ % num_outstanding_requests; + urb = urbs_ + index; + char* buf = reinterpret_cast(urb->buffer); + setp(buf, buf + buffer_size_); + + // insert char + if (c != traits_type::eof()) { + *pptr() = (char)c; + pbump( 1 ); + } + + return c; +} + +void usb_ostreambuf::on_completed() { + const std::lock_guard lock(io_mutex); + completed_index_ += 1; + io_condition.notify_all(); +} + +void usb_ostreambuf::check_for_errors() { + while (completed_index_ - checked_index_ > 0) { + int index = completed_index_ % num_outstanding_requests; + usbdevfs_urb* urb = urbs_ + index; + usb_error::check(urb->status, "error writing to USB endpoint"); + checked_index_ += 1; + } +} + + +// --- usb_istream --- + +usb_istream::usb_istream(usb_device_ptr device, int ep_num) + : std::istream(new usb_istreambuf(device, ep_num)) {} + +usb_istream::~usb_istream() { + // delete buffer + delete rdbuf(); +} + + +// --- usb_ostream --- + +usb_ostream::usb_ostream(usb_device_ptr device, int ep_num) + : std::ostream(new usb_ostreambuf(device, ep_num)) {} + +usb_ostream::~usb_ostream() { + // delete buffer + delete rdbuf(); +} diff --git a/reference/linux/usb_iostream.hpp b/reference/linux/usb_iostream.hpp new file mode 100644 index 00000000..23a6194a --- /dev/null +++ b/reference/linux/usb_iostream.hpp @@ -0,0 +1,144 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for Linux +// + +#pragma once + +#include +#include +#include +#include +#include +#include "usb_device.hpp" + +/** + * Input stream buffer for USB bulk or interrupt endpoint. + * + * The stream buffer is internally used by an input stream. It submits multiple asynchronous IO requests to + * achieve maximum throughput. + */ +class usb_istreambuf : public std::streambuf { +public: + /// Constructor + usb_istreambuf(usb_device_ptr device, int ep_num); + /// Destructor + virtual ~usb_istreambuf(); + + /// Closes this buffer. This stream buffer will automatically free itself. + void close(); + +protected: + /// Called when the internal buffer has no further data to read. + virtual int_type underflow(); + + void on_completed(); + +private: + void submit_request(); + + /// Maximum number of concurrently outstanding requests + static constexpr int num_outstanding_requests = 4; + + /// USB device + usb_device_ptr device_; + /// endpoint number + int ep_num_; + /// Indicates that this stream buffer is closed + bool is_closed_; + /// buffer size + int buffer_size_; + /// Mutex for synchronization between input stream caller and background thread handling IO completion. + std::mutex io_mutex; + /// Condition for synchronization between input stream caller and background thread handling IO completion + std::condition_variable io_condition; + /// Index after last submitted IO request + unsigned int submitted_index_; + /// Index after last completed IO request + unsigned int completed_index_; + /// Index after last processed IO request + unsigned int processed_index_; + /// USB request buffers + usbdevfs_urb urbs_[num_outstanding_requests]; + /// IO completion lambda + std::function io_completion; +}; + +/** + * Output stream buffer for USB bulk or interrupt endpoint. + * + * The stream buffer is internally used by an output stream. It submits multiple asynchronous IO requests to + * achieve maximum throughput. + */ +class usb_ostreambuf : public std::streambuf { +public: + /// Constructor + usb_ostreambuf(usb_device_ptr device, int ep_num); + /// Destructor + virtual ~usb_ostreambuf(); + + virtual int sync(); + +protected: + /// Called when the internal buffer has no space left to add more data. + virtual int overflow (int c); + + void on_completed(); + + void check_for_errors(); + +private: + /// Maximum number of concurrently outstanding requests + static constexpr int num_outstanding_requests = 4; + + /// USB device + usb_device_ptr device_; + /// endpoint number + int ep_num_; + /// Indicates that this stream buffer is closed + bool is_closed_; + /// Indicates if a zero-length packet is required + bool needs_zlp_; + /// buffer size + int buffer_size_; + /// Mutex for synchronization between output stream caller and background thread handling IO completion. + std::mutex io_mutex; + /// Condition for synchronization between output stream caller and background thread handling IO completion + std::condition_variable io_condition; + /// Index of buffer being currently used by base class + unsigned int processing_index_; + /// Index after last completed IO request + unsigned int completed_index_; + /// Index after last completed IO request that has been checked for errors + unsigned int checked_index_; + /// USB request buffers + usbdevfs_urb urbs_[num_outstanding_requests]; + /// IO completion lambda + std::function io_completion; +}; + +/** + * Input stream for reading from a USB bulk endpoint + */ +class usb_istream : public std::istream { +public: + /// Constructor + usb_istream(usb_device_ptr device, int ep_num); + /// Destructor + ~usb_istream(); +}; + +/** + * Output stream for writing to a USB bulk endpoint + */ +class usb_ostream : public std::ostream { +public: + /// Constructor + usb_ostream(usb_device_ptr device, int ep_num); + /// Destructor + ~usb_ostream(); +}; diff --git a/reference/linux/usb_registry.cpp b/reference/linux/usb_registry.cpp index d1e04a54..0ff1d6db 100644 --- a/reference/linux/usb_registry.cpp +++ b/reference/linux/usb_registry.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -26,15 +28,21 @@ #include usb_registry::usb_registry() -: wake_event_fd(-1), - on_connected_callback(nullptr), on_disconnected_callback(nullptr), - is_device_list_ready(false) { +: monitor_wake_event_fd(-1), + on_connected_callback(nullptr), on_disconnected_callback(nullptr), is_device_list_ready(false), + async_io_update_event_fd(-1), async_io_update_request(0), async_io_update_response(0) { } usb_registry::~usb_registry() { - eventfd_write(wake_event_fd, 1); + eventfd_write(monitor_wake_event_fd, 1); monitor_thread.join(); - ::close(wake_event_fd); + ::close(monitor_wake_event_fd); + + if (async_io_update_event_fd != -1) { + eventfd_write(async_io_update_event_fd, 999999); + async_io_thread.join(); + ::close(async_io_update_event_fd); + } } std::vector usb_registry::get_devices() { @@ -50,8 +58,8 @@ void usb_registry::set_on_device_disconnected(std::function usb_registry::create_device(udev_device* udev_dev) { if (vendor_id == 0 || product_id == 0) return nullptr; - std::shared_ptr device(new usb_device(path, vendor_id, product_id)); + std::shared_ptr device(new usb_device(this, path, vendor_id, product_id)); device->set_product_strings( udev_device_get_sysattr_value(udev_dev, "manufacturer"), udev_device_get_sysattr_value(udev_dev, "product"), @@ -232,3 +240,131 @@ std::shared_ptr usb_registry::create_device(udev_device* udev_dev) { ); return device; } + +std::shared_ptr usb_registry::get_shared_ptr(usb_device* device) { + auto it = std::find_if(devices.cbegin(), devices.cend(), [device](auto dev) { return dev.get() == device; }); + if (it == devices.cend()) + return nullptr; + + return *it; +} + +void usb_registry::async_io_run() { + + { + std::lock_guard lock(async_io_mutex); + async_io_update_response = async_io_update_request; + async_io_condition.notify_all(); + } + + std::vector fds; + fds.resize(2); + fds[0].fd = async_io_update_event_fd; + fds[0].events = POLLIN; + + while (true) { + + int num_fds = 1; + fds.resize(async_io_fds.size() + 1); + + { + std::lock_guard lock(async_io_mutex); + for (auto fd : async_io_fds) { + fds[num_fds].fd = fd; + fds[num_fds].events = POLLIN | POLLOUT; + num_fds += 1; + } + } + + int ret = poll(fds.data(), num_fds, -1); + if (ret < 0) + usb_error::throw_error("internal error (poll)"); + + for (auto it = fds.begin(); it != fds.end(); ++it) { + if (it->revents == 0) + continue; + + if (it->fd == async_io_update_event_fd) { + eventfd_t value = 0; + eventfd_read(async_io_update_event_fd, &value); + if (value >= 999999) + return; + + std::lock_guard lock(async_io_mutex); + async_io_update_response = async_io_update_request; + async_io_condition.notify_all(); + continue; + } + + if ((it->revents & POLLERR) != 0) { + // TODO + continue; + } + + if (it->revents != 0) { + usbdevfs_urb* urb = nullptr; + ret = ioctl(it->fd, USBDEVFS_REAPURB, &urb); + if (ret < 0) + usb_error::throw_error("internal error (reap URB)"); + + auto completion = reinterpret_cast*>(urb->usercontext); + (*completion)(); + } + } + } +} + +void usb_registry::add_async_fd(int fd) { + int expected_request; + + { + std::lock_guard lock(async_io_mutex); + + // start background thread if needed + if (async_io_update_event_fd == -1) { + async_io_update_event_fd = eventfd(0, 0); + if (async_io_update_event_fd < 0) + usb_error::throw_error("internal error(eventfd)"); + + async_io_thread = std::thread(&usb_registry::async_io_run, this); + } + + if (std::find(async_io_fds.begin(), async_io_fds.end(), fd) != async_io_fds.end()) + return; // already registered + + async_io_fds.emplace_back(fd); + eventfd_write(async_io_update_event_fd, 1); + + async_io_update_request += 1; + expected_request = async_io_update_request; + } + + // wait for background process to add file descriptor for polling + { + std::unique_lock wait_lock(async_io_mutex); + async_io_condition.wait(wait_lock, [this, expected_request] { return expected_request - async_io_update_response <= 0; }); + } +} + + +void usb_registry::remove_async_fd(int fd) { + int expected_request; + + { + std::lock_guard lock(async_io_mutex); + + async_io_fds.erase( + std::remove(async_io_fds.begin(), async_io_fds.end(), fd), + async_io_fds.end() + ); + async_io_update_request += 1; + expected_request = async_io_update_request; + eventfd_write(async_io_update_event_fd, 1); + } + + // wait for background process to remove file descriptor from polling + { + std::unique_lock wait_lock(async_io_mutex); + async_io_condition.wait(wait_lock, [this, expected_request] { return expected_request - async_io_update_response <= 0; }); + } +} diff --git a/reference/linux/usb_registry.hpp b/reference/linux/usb_registry.hpp index e4dda808..2274289e 100644 --- a/reference/linux/usb_registry.hpp +++ b/reference/linux/usb_registry.hpp @@ -50,7 +50,12 @@ class usb_registry { void on_device_connected(udev_device* udev_dev); void on_device_disconnected(udev_device* udev_dev); + void async_io_run(); + void add_async_fd(int fd); + void remove_async_fd(int fd); + std::shared_ptr create_device(udev_device* udev_dev); + std::shared_ptr get_shared_ptr(usb_device* device); std::vector devices; @@ -58,10 +63,18 @@ class usb_registry { std::function on_disconnected_callback; std::thread monitor_thread; - - int wake_event_fd; - + int monitor_wake_event_fd; bool is_device_list_ready; std::mutex monitor_mutex; std::condition_variable monitor_condition; + + std::thread async_io_thread; + std::mutex async_io_mutex; + std::condition_variable async_io_condition; + std::vector async_io_fds; + int async_io_update_event_fd; + int async_io_update_request; + int async_io_update_response; + + friend usb_device; }; From 0528f5f0076f5c83d49ad95546e79a0a849e1d17 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 5 Feb 2023 22:56:53 +0100 Subject: [PATCH 186/433] High throughput iostreams (C++/Windows) --- reference/windows/USB/USB.vcxproj | 4 + reference/windows/USB/USB.vcxproj.filters | 6 + reference/windows/USB/speed_test.cpp | 28 ++- reference/windows/USB/usb_device.cpp | 72 ++++++- reference/windows/USB/usb_device.hpp | 40 +++- reference/windows/USB/usb_iostream.cpp | 249 ++++++++++++++++++++++ reference/windows/USB/usb_iostream.hpp | 153 +++++++++++++ reference/windows/USB/usb_registry.cpp | 77 ++++++- reference/windows/USB/usb_registry.hpp | 19 +- 9 files changed, 633 insertions(+), 15 deletions(-) create mode 100644 reference/windows/USB/usb_iostream.cpp create mode 100644 reference/windows/USB/usb_iostream.hpp diff --git a/reference/windows/USB/USB.vcxproj b/reference/windows/USB/USB.vcxproj index b0ed58d6..ed5d926c 100644 --- a/reference/windows/USB/USB.vcxproj +++ b/reference/windows/USB/USB.vcxproj @@ -29,6 +29,7 @@ + @@ -42,6 +43,7 @@ + @@ -132,6 +134,7 @@ _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true EnableFastChecks + stdcpp17 Console @@ -146,6 +149,7 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true + stdcpp17 Console diff --git a/reference/windows/USB/USB.vcxproj.filters b/reference/windows/USB/USB.vcxproj.filters index 865a9487..4bf8b8df 100644 --- a/reference/windows/USB/USB.vcxproj.filters +++ b/reference/windows/USB/USB.vcxproj.filters @@ -48,6 +48,9 @@ Source Files + + Source Files + @@ -83,5 +86,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/reference/windows/USB/speed_test.cpp b/reference/windows/USB/speed_test.cpp index 40141d8f..234aece6 100644 --- a/reference/windows/USB/speed_test.cpp +++ b/reference/windows/USB/speed_test.cpp @@ -22,7 +22,7 @@ static constexpr uint32_t PRNG_INIT = 0x7b; speed_test::speed_test(usb_device_ptr device, int ep_out, int ep_in) -: device_(device), ep_out_(ep_out), ep_in_(ep_in) { } +: device_(device), ep_out_(ep_out), ep_in_(ep_in), processed_bytes(0) { } void speed_test::run(int num_bytes) { reset_buffers(); @@ -40,14 +40,17 @@ bool speed_test::transmit(int num_bytes) { prng seq(PRNG_INIT); - std::vector buf(2048); + std::vector buf(2000); int pos = 0; + auto is_ptr = device_->open_output_stream(ep_out_); + std::ostream& os = *is_ptr; + while (num_bytes > 0) { int n = std::min(num_bytes, static_cast(buf.size())); try { seq.fill(buf, n); - device_->transfer_out(ep_out_, buf, n); + os.write(reinterpret_cast(buf.data()), n); } catch (usb_error& error) { std::cerr << std::endl << "ERROR: " << error.what() << " (writing at pos " << pos << ")" << std::endl; @@ -66,12 +69,21 @@ bool speed_test::receive(int num_bytes) { prng seq(PRNG_INIT); int pos = 0; + std::vector data; + + auto is_ptr = device_->open_input_stream(ep_in_); + std::istream& is = *is_ptr; while (num_bytes > 0) { int n; try { - std::vector data = device_->transfer_in(ep_in_); - n = std::min(num_bytes, static_cast(data.size())); + data.resize(2000); + is.read(reinterpret_cast(data.data()), data.capacity()); + n = static_cast(is.gcount()); + if (n <= 0) + break; + data.resize(n); + int p = seq.verify(data, n); if (p != -1) { std::cerr << std::endl << "Invalid data received at pos " << (pos + p) << std::endl; @@ -89,6 +101,10 @@ bool speed_test::receive(int num_bytes) { update_progress(n); } + if (num_bytes != 0) { + std::cerr << std::endl << "ERROR: EOF encountered after " << pos << " bytes" << std::endl; + } + return true; } @@ -111,7 +127,7 @@ void speed_test::start_measurement() { } void speed_test::update_progress(int n) { - std::lock_guard lockGuard(progress_mutex); + std::lock_guard lock(progress_mutex); processed_bytes += n; } diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp index 25ab8787..867244f8 100644 --- a/reference/windows/USB/usb_device.cpp +++ b/reference/windows/USB/usb_device.cpp @@ -9,13 +9,15 @@ #include "usb_device.hpp" #include "usb_error.hpp" +#include "usb_iostream.hpp" #include "scope.hpp" #include "config_parser.hpp" +#include "usb_registry.hpp" #include -usb_device::usb_device(std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, std::map&& children) -: vendor_id_(vendor_id), product_id_(product_id), is_open_(false), device_path_(std::move(device_path)) { +usb_device::usb_device(usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, std::map&& children) +: registry_(registry), vendor_id_(vendor_id), product_id_(product_id), is_open_(false), device_path_(std::move(device_path)) { config_parser parser{}; parser.parse(config_desc.data(), static_cast(config_desc.size())); @@ -139,6 +141,8 @@ void usb_device::claim_interface(int interface_number) { nullptr); if (first_intf_handle->device_handle == INVALID_HANDLE_VALUE) usb_error::throw_error("Cannot open USB device"); + + registry_->add_to_completion_port(first_intf_handle->device_handle); } // open interface @@ -374,6 +378,70 @@ usb_device::interface_handle* usb_device::check_valid_endpoint(usb_direction dir return get_interface_handle(intf->number()); } +std::unique_ptr usb_device::open_input_stream(int endpoint_number) { + return std::unique_ptr(new usb_istream(registry_->get_shared_ptr(this), endpoint_number)); +} + +std::unique_ptr usb_device::open_output_stream(int endpoint_number) { + return std::unique_ptr(new usb_ostream(registry_->get_shared_ptr(this), endpoint_number)); +} + +void usb_device::add_completion_handler(OVERLAPPED* overlapped, std::function* completion_handler) { + registry_->add_completion_handler(overlapped, completion_handler); +} + +void usb_device::remove_completion_handler(OVERLAPPED* overlapped) { + registry_->remove_completion_handler(overlapped); +} + +void usb_device::configure_for_async_io(usb_direction direction, int endpoint_number) { + auto intf_handle = check_valid_endpoint(usb_direction::in, endpoint_number)->intf_handle; + UCHAR endpoint_address = ep_address(usb_direction::in, endpoint_number); + + ULONG value = 0; + if (!WinUsb_SetPipePolicy(intf_handle, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) + usb_error::throw_error("Failed to set endpoint timeout"); + + if (direction == usb_direction::in) { + value = TRUE; + if (!WinUsb_SetPipePolicy(intf_handle, endpoint_address, RAW_IO, sizeof(value), &value)) + usb_error::throw_error("Failed to set endpoint for raw IO"); + } +} + +void usb_device::submit_transfer_in(int endpoint_number, uint8_t* buffer, int buffer_len, OVERLAPPED* overlapped) { + + auto intf_handle = check_valid_endpoint(usb_direction::in, endpoint_number)->intf_handle; + UCHAR endpoint_address = ep_address(usb_direction::in, endpoint_number); + + if (!WinUsb_ReadPipe(intf_handle, endpoint_address, buffer, buffer_len, nullptr, overlapped)) { + DWORD err = GetLastError(); + if (err == ERROR_IO_PENDING) + return; + throw new usb_error("Failed to submit transfer IN", err); + } +} + +void usb_device::submit_transfer_out(int endpoint_number, uint8_t* data, int data_len, OVERLAPPED* overlapped) { + + auto intf_handle = check_valid_endpoint(usb_direction::out, endpoint_number)->intf_handle; + UCHAR endpoint_address = ep_address(usb_direction::out, endpoint_number); + + if (!WinUsb_WritePipe(intf_handle, endpoint_address, data, data_len, nullptr, overlapped)) { + DWORD err = GetLastError(); + if (err == ERROR_IO_PENDING) + return; + throw new usb_error("Failed to submit transfer OUT", err); + } +} + +void usb_device::cancel_transfer(usb_direction direction, int endpoint_number, OVERLAPPED* overlapped) { + auto handle_info = check_valid_endpoint(direction, endpoint_number); + + if (!CancelIoEx(handle_info->device_handle, overlapped)) + usb_error::throw_error("Error on cancelling transfer"); +} + // --- interface_handle diff --git a/reference/windows/USB/usb_device.hpp b/reference/windows/USB/usb_device.hpp index 08d23a06..4c4da685 100644 --- a/reference/windows/USB/usb_device.hpp +++ b/reference/windows/USB/usb_device.hpp @@ -9,6 +9,8 @@ #pragma once +#include +#include #include #include #include @@ -75,6 +77,8 @@ struct usb_control_request { }; +class usb_registry; + /** * USB device. * @@ -209,6 +213,29 @@ class usb_device { */ std::vector control_transfer_in(const usb_control_request& request, int timeout = 0); + /** + * Open a new input stream for a bulk endpoint. + * + * The input stream is optimized for maximum throughput. + * + * Do not use the input stream concurrently with other transfer operations on the same endpoint. The input stream + * buffers data for high throughput. When the stream is closed, any data in the buffers will be lost. + * + * @param endpoint_number endpoint number (between 1 and 127) + */ + std::unique_ptr open_input_stream(int endpoint_number); + + /** + * Open a new output stream for a bulk endpoint. + * + * The output stream is optimized for maximum throughput. + * + * Do not use the output stream concurrently with other transfer operations on the same endpoint. + * + * @param endpoint_number endpoint number (between 1 and 127) + */ + std::unique_ptr open_output_stream(int endpoint_number); + private: struct interface_handle { int interface_num; @@ -221,7 +248,7 @@ class usb_device { interface_handle(int intf_num, int first_num, std::wstring&& path); }; - usb_device(std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, std::map&& children); + usb_device(usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, std::map&& children); void set_product_names(const std::string& manufacturer, const std::string& product, const std::string& serial_number); void build_handles(const std::wstring& device_path, std::map&& children); @@ -238,6 +265,14 @@ class usb_device { return static_cast(direction) | static_cast(endpoint_number); } + void configure_for_async_io(usb_direction direction, int endpoint_number); + void add_completion_handler(OVERLAPPED* overlapped, std::function* completion_handler); + void remove_completion_handler(OVERLAPPED* overlapped); + void submit_transfer_in(int endpoint_number, uint8_t* buffer, int buffer_len, OVERLAPPED* overlapped); + void submit_transfer_out(int endpoint_number, uint8_t* data, int data_len, OVERLAPPED* overlapped); + void cancel_transfer(usb_direction direction, int endpoint_number, OVERLAPPED* overlapped); + + usb_registry* registry_; bool is_open_; int product_id_; @@ -250,7 +285,10 @@ class usb_device { std::vector interfaces_; std::vector functions_; std::vector interface_handles_; + friend class usb_registry; + friend class usb_istreambuf; + friend class usb_ostreambuf; }; typedef std::shared_ptr usb_device_ptr; diff --git a/reference/windows/USB/usb_iostream.cpp b/reference/windows/USB/usb_iostream.cpp new file mode 100644 index 00000000..db6afba6 --- /dev/null +++ b/reference/windows/USB/usb_iostream.cpp @@ -0,0 +1,249 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for Windows +// + +#include "usb_iostream.hpp" +#include "usb_error.hpp" +#include + +// --- usb_istreambuf --- + +usb_istreambuf::usb_istreambuf(usb_device_ptr device, int endpoint_number) +: device(device), endpoint_number(endpoint_number), is_closed(false), submitted_index(0), completed_index(0), processed_index(-1) { + + setg(nullptr, nullptr, nullptr); + + buffer_size = 4 * device->get_endpoint(usb_direction::in, endpoint_number).packet_size(); + + // create buffers + for (int i = 0; i < num_outstanding_requests; i++) + buffers[i] = new uint8_t[buffer_size]; + + // initialize OUTLAPPED structure and submit request + memset(overlapped_requests, 0, sizeof(overlapped_requests)); + + // create and register IO completion handler + io_completion_handler = [this](DWORD result, DWORD size) { on_io_completion(result, size); }; + for (int i = 0; i < num_outstanding_requests; i++) + device->add_completion_handler(&overlapped_requests[i], &io_completion_handler); + + // start requests except for one + const std::lock_guard lock(io_mutex); + for (int i = 0; i < num_outstanding_requests - 1; i++) + submit_request(); +} + +usb_istreambuf::~usb_istreambuf() { + close(); + + for (int i = 0; i < num_outstanding_requests; i++) + delete[] buffers[i]; +} + +void usb_istreambuf::close() { + { + const std::lock_guard lock(io_mutex); + + is_closed = true; + + for (int i = completed_index; submitted_index - i > 0; i += 1) { + int index = i % num_outstanding_requests; + device->cancel_transfer(usb_direction::in, endpoint_number, &overlapped_requests[index]); + } + } + + io_condition.notify_all(); + + // wait until all completion handlers have been called + std::unique_lock wait_lock(io_mutex); + io_condition.wait(wait_lock, [this] { return completed_index == submitted_index; }); +} + +void usb_istreambuf::submit_request() { + int index = submitted_index % num_outstanding_requests; + submitted_index += 1; + + device->submit_transfer_in(endpoint_number, buffers[index], buffer_size, &overlapped_requests[index]); +} + +void usb_istreambuf::on_io_completion(DWORD result, DWORD size) { + const std::lock_guard lock(io_mutex); + + int index = completed_index % num_outstanding_requests; + request_sizes[index] = size; + request_results[index] = result; + + completed_index += 1; + io_condition.notify_all(); +} + +usb_istreambuf::int_type usb_istreambuf::underflow() { + if (is_closed) + return traits_type::eof(); + + if (gptr() < egptr()) + return traits_type::to_int_type(*gptr()); + + // loop until no ZLP has been received + while (true) { + std::unique_lock wait_lock(io_mutex); + processed_index += 1; + submit_request(); + + // wait until a completed request is available + io_condition.wait(wait_lock, [this] { return completed_index - processed_index > 0 || is_closed; }); + + if (is_closed) + return traits_type::eof(); + + int index = processed_index % num_outstanding_requests; + if (request_results[index] != S_OK) + throw new usb_error("transfer IN failed", request_results[index]); + + // set stream buffer to buffer from completed request + char* buf = reinterpret_cast(buffers[index]); + int size = request_sizes[index]; + + if (size != 0) { + setg(buf, buf, buf + size); + return traits_type::to_int_type(*gptr()); + } + } +} + + +// --- usb_ostreambuf --- + +usb_ostreambuf::usb_ostreambuf(usb_device_ptr device, int endpoint_number) +: device(device), endpoint_number(endpoint_number), processing_index(0), completed_index(0), checked_index(0), needs_zlp(false) { + + packet_size = device->get_endpoint(usb_direction::out, endpoint_number).packet_size(); + buffer_size = 1 * packet_size; + + // create buffers + for (int i = 0; i < num_outstanding_requests; i++) + buffers[i] = new uint8_t[buffer_size]; + + char* buf = reinterpret_cast(buffers[0]); + setp(buf, buf + buffer_size); + + // initialize OUTLAPPED structure and submit request + memset(overlapped_requests, 0, sizeof(overlapped_requests)); + + // create and register IO completion handler + io_completion_handler = [this](DWORD result, DWORD size) { on_io_completion(result, size); }; + for (int i = 0; i < num_outstanding_requests; i++) + device->add_completion_handler(&overlapped_requests[i], &io_completion_handler); +} + +usb_ostreambuf::~usb_ostreambuf() { + sync(); + + for (int i = 0; i < num_outstanding_requests; i++) + delete[] buffers[i]; +} + +int usb_ostreambuf::sync() { + std::unique_lock wait_lock(io_mutex); + + // submit request if there is any data in the current buffer + auto size = static_cast(pptr() - pbase()); + if (size > 0) + submit_transfer(size); + + // send a zero-length packet if required + if (needs_zlp) { + // wait until an unused buffer is available + io_condition.wait(wait_lock, [this] { return processing_index - completed_index < num_outstanding_requests; }); + check_for_errors(); + + submit_transfer(0); + } + + // wait until all buffers have been transmitted + io_condition.wait(wait_lock, [this] { return processing_index == completed_index; }); + check_for_errors(); + + int index = processing_index % num_outstanding_requests; + char* buf = reinterpret_cast(buffers[index]); + setp(buf, buf + buffer_size); + + return 0; +} + +int usb_ostreambuf::overflow (int c) { + std::unique_lock wait_lock(io_mutex); + + // submit request + auto size = static_cast(pptr() - pbase()); + submit_transfer(size); + + // wait until an unused buffer is available + io_condition.wait(wait_lock, [this] { return processing_index - completed_index < num_outstanding_requests; }); + check_for_errors(); + + // configure stream buffer + int index = processing_index % num_outstanding_requests; + char* buf = reinterpret_cast(buffers[index]); + setp(buf, buf + buffer_size); + + // insert char + if (c != traits_type::eof()) { + *pptr() = (char)c; + pbump(1); + } + + return c; +} + +void usb_ostreambuf::on_io_completion(DWORD result, DWORD size) { + const std::lock_guard lock(io_mutex); + int index = completed_index % num_outstanding_requests; + request_results[index] = result; + completed_index += 1; + io_condition.notify_all(); +} + +void usb_ostreambuf::check_for_errors() { + + while (completed_index - checked_index > 0) { + int index = completed_index % num_outstanding_requests; + if (request_results[index] != S_OK) + throw new usb_error("transfer OUT failed", request_results[index]); + checked_index += 1; + } +} + +void usb_ostreambuf::submit_transfer(int size) { + int index = processing_index % num_outstanding_requests; + device->submit_transfer_out(endpoint_number, buffers[index], size, &overlapped_requests[index]); + processing_index += 1; + needs_zlp = size == packet_size; +} + + +// --- usb_istream --- + +usb_istream::usb_istream(usb_device_ptr device, int ep_num) + : std::istream(new usb_istreambuf(device, ep_num)) {} + +usb_istream::~usb_istream() { + // deallocate stream buffer + delete rdbuf(); +} + + +// --- usb_ostream --- + +usb_ostream::usb_ostream(usb_device_ptr device, int ep_num) + : std::ostream(new usb_ostreambuf(device, ep_num)) {} + +usb_ostream::~usb_ostream() { + // deallocate stream buffer + delete rdbuf(); +} diff --git a/reference/windows/USB/usb_iostream.hpp b/reference/windows/USB/usb_iostream.hpp new file mode 100644 index 00000000..c1274677 --- /dev/null +++ b/reference/windows/USB/usb_iostream.hpp @@ -0,0 +1,153 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for Windows +// + +#pragma once + +#include +#include +#include +#include "usb_device.hpp" + +/** + * Input stream buffer for USB bulk or interrupt endpoint. + * + * The stream buffer is internally used by an input stream. It submits multiple asynchronous IO requests to + * achieve maximum throughput. + */ +class usb_istreambuf : public std::streambuf { +public: + /// Constructor + usb_istreambuf(usb_device_ptr device, int ep_num); + /// Destructor + virtual ~usb_istreambuf(); + +protected: + /// Called when the internal buffer has no further data to read. + virtual int_type underflow(); + +private: + void submit_request(); + + void close(); + void on_io_completion(DWORD result, DWORD size); + + /// Maximum number of concurrently outstanding requests + static constexpr int num_outstanding_requests = 4; + + /// USB device + usb_device_ptr device; + /// endpoint number + int endpoint_number; + /// Indicates that this stream buffer is closed + bool is_closed; + /// buffer size + int buffer_size; + /// Mutex for synchronization between input stream caller and background thread handling IO completion. + std::mutex io_mutex; + /// Condition for synchronization between input stream caller and background thread handling IO completion + std::condition_variable io_condition; + /// Index after last submitted IO request + int submitted_index; + /// Index after last completed IO request + int completed_index; + /// Index after last processed IO request + int processed_index; + /// Async IO request information + OVERLAPPED overlapped_requests[num_outstanding_requests]; + /// Data buffers + uint8_t* buffers[num_outstanding_requests]; + /// Size of received data + DWORD request_sizes[num_outstanding_requests]; + /// Result code of IO request + DWORD request_results[num_outstanding_requests]; + /// Async IO completion handler + std::function io_completion_handler; + + friend class usb_istream; +}; + +/** + * Output stream buffer for USB bulk or interrupt endpoint. + * + * The stream buffer is internally used by an output stream. It submits multiple asynchronous IO requests to + * achieve maximum throughput. + */ +class usb_ostreambuf : public std::streambuf { +public: + /// Constructor + usb_ostreambuf(usb_device_ptr device, int ep_num); + /// Destructor + virtual ~usb_ostreambuf(); + + virtual int sync(); + +protected: + /// Called when the internal buffer has no space left to add more data. + virtual int overflow (int c); + +private: + void submit_transfer(int size); + void check_for_errors(); + + void on_io_completion(DWORD result, DWORD size); + + /// Maximum number of concurrently outstanding requests + static constexpr int num_outstanding_requests = 4; + + /// USB device + usb_device_ptr device; + /// endpoint number + int endpoint_number; + /// Indicates if a zero-length packet is required + bool needs_zlp; + /// packet size + int packet_size; + /// buffer size + int buffer_size; + /// Mutex for synchronization between output stream caller and background thread handling IO completion. + std::mutex io_mutex; + /// Condition for synchronization between output stream caller and background thread handling IO completion + std::condition_variable io_condition; + /// Index of buffer being currently used by base class + int processing_index; + /// Index after last completed IO request + int completed_index; + /// Index after last completed IO request that has been checked for errors + int checked_index; + /// Async IO request information + OVERLAPPED overlapped_requests[num_outstanding_requests]; + /// Data buffers for transmitting data + uint8_t* buffers[num_outstanding_requests]; + /// Result code of IO request + DWORD request_results[num_outstanding_requests]; + /// Async IO completion handler + std::function io_completion_handler; +}; + +/** + * Input stream for reading from a USB bulk endpoint + */ +class usb_istream : public std::istream { +public: + /// Constructor + usb_istream(usb_device_ptr device, int ep_num); + /// Destructor + ~usb_istream(); +}; + +/** + * Output stream for writing to a USB bulk endpoint + */ +class usb_ostream : public std::ostream { +public: + /// Constructor + usb_ostream(usb_device_ptr device, int ep_num); + /// Destructor + ~usb_ostream(); +}; diff --git a/reference/windows/USB/usb_registry.cpp b/reference/windows/USB/usb_registry.cpp index f499fed7..9433cf68 100644 --- a/reference/windows/USB/usb_registry.cpp +++ b/reference/windows/USB/usb_registry.cpp @@ -29,14 +29,19 @@ usb_registry::usb_registry() : on_connected_callback(nullptr), on_disconnected_callback(nullptr), - is_device_list_ready(false), background_thread_id_(0), message_window(nullptr) { + is_device_list_ready(false), monitor_thread_id_(0), message_window(nullptr), + async_io_completion_port(nullptr) { } usb_registry::~usb_registry() { - SendMessage(message_window, WM_CLOSE, 0, 0); monitor_thread.join(); + if (async_io_completion_port != nullptr) { + PostQueuedCompletionStatus(async_io_completion_port, 0, -1, nullptr); + async_io_thread.join(); + CloseHandle(async_io_completion_port); + } } std::vector usb_registry::get_devices() { @@ -54,7 +59,7 @@ void usb_registry::set_on_device_disconnected(std::function wait_lock(monitor_mutex); + std::unique_lock wait_lock(monitor_mutex); monitor_condition.wait(wait_lock, [this] { return is_device_list_ready; }); } @@ -63,7 +68,7 @@ static const LPCWSTR WINDOW_NAME = L"USB device monitor"; void usb_registry::monitor() { - background_thread_id_ = GetCurrentThreadId(); + monitor_thread_id_ = GetCurrentThreadId(); HMODULE instance = GetModuleHandleW(nullptr); WNDCLASSEXW wx = { 0 }; @@ -182,7 +187,7 @@ std::shared_ptr usb_registry::create_device(HDEVINFO dev_info_set, S auto config_desc = usb_device_info::get_descriptor(hub_handle, usb_port_num, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0); // Create new device - std::shared_ptr device(new usb_device(std::move(path), conn_info.DeviceDescriptor.idVendor, conn_info.DeviceDescriptor.idProduct, config_desc, std::move(children))); + std::shared_ptr device(new usb_device(this, std::move(path), conn_info.DeviceDescriptor.idVendor, conn_info.DeviceDescriptor.idProduct, config_desc, std::move(children))); device->set_product_names( usb_device_info::get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iManufacturer), usb_device_info::get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iProduct), @@ -370,3 +375,65 @@ void usb_registry::on_device_disconnected(const WCHAR* path) { } } } + +std::shared_ptr usb_registry::get_shared_ptr(usb_device* device) { + auto it = std::find_if(devices.cbegin(), devices.cend(), [device](auto dev) { return dev.get() == device; }); + if (it == devices.cend()) + return nullptr; + + return *it; +} + +void usb_registry::async_io_run() { + + while (true) { + OVERLAPPED* overlapped = nullptr; + DWORD num_bytes = 0; + ULONG_PTR completion_key = 0; + if (!GetQueuedCompletionStatus(async_io_completion_port, &num_bytes, &completion_key, &overlapped, INFINITE) && overlapped == nullptr) + usb_error::throw_error("internal error (GetQueuedCompletionStatus)"); + + if (overlapped == nullptr) + return; // registry is closing + + std::function* completion_handler = get_completion_handler(overlapped); + if (overlapped == nullptr) + continue; // might be completion from synchronous operation + + DWORD result = static_cast(overlapped->Internal); + (*completion_handler)(result, num_bytes); + } +} + +void usb_registry::add_to_completion_port(HANDLE handle) { + HANDLE port_handle = CreateIoCompletionPort(handle, async_io_completion_port, 0xd03fbc01, 0); + if (port_handle == nullptr) + usb_error::throw_error("internal error (CreateIoCompletionPort)"); + + if (async_io_completion_port == nullptr) { + async_io_completion_port = port_handle; + async_io_thread = std::thread(&usb_registry::async_io_run, this); + } +} + +void usb_registry::add_completion_handler(OVERLAPPED* overlapped, std::function* completion_handler) { + std::lock_guard lock(async_io_mutex); + + async_io_completion_handlers.insert(std::pair(overlapped, completion_handler)); +} + +void usb_registry::remove_completion_handler(OVERLAPPED* overlapped) { + std::lock_guard lock(async_io_mutex); + + async_io_completion_handlers.erase(overlapped); +} + +std::function* usb_registry::get_completion_handler(OVERLAPPED* overlapped) { + std::lock_guard lock(async_io_mutex); + + auto it = async_io_completion_handlers.find(overlapped); + if (it == async_io_completion_handlers.end()) + return nullptr; + + return it->second; +} diff --git a/reference/windows/USB/usb_registry.hpp b/reference/windows/USB/usb_registry.hpp index 42968c08..a95abe28 100644 --- a/reference/windows/USB/usb_registry.hpp +++ b/reference/windows/USB/usb_registry.hpp @@ -64,11 +64,28 @@ class usb_registry { std::function on_connected_callback; std::function on_disconnected_callback; + std::shared_ptr get_shared_ptr(usb_device* device); + + void async_io_run(); + void add_to_completion_port(HANDLE); + void add_completion_handler(OVERLAPPED* overlapped, std::function* completion_handler); + void remove_completion_handler(OVERLAPPED* overlapped); + std::function* get_completion_handler(OVERLAPPED* overlapped); + std::thread monitor_thread; bool is_device_list_ready; std::mutex monitor_mutex; std::condition_variable monitor_condition; - DWORD background_thread_id_; + DWORD monitor_thread_id_; HWND message_window; + + std::thread async_io_thread; + std::mutex async_io_mutex; + HANDLE async_io_completion_port; + std::map*> async_io_completion_handlers; + + friend class usb_device; + friend class usb_istreambuf; + friend class usb_ostreambuf; }; From 514ed57ed9af9ba5421fe052caf2719f165bb735 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 6 Feb 2023 23:20:47 +0100 Subject: [PATCH 187/433] Use raw IO (C++/Windows) --- reference/windows/USB/usb_device.cpp | 16 +++++++--------- reference/windows/USB/usb_iostream.cpp | 4 ++++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp index 867244f8..c182f2d7 100644 --- a/reference/windows/USB/usb_device.cpp +++ b/reference/windows/USB/usb_device.cpp @@ -395,18 +395,16 @@ void usb_device::remove_completion_handler(OVERLAPPED* overlapped) { } void usb_device::configure_for_async_io(usb_direction direction, int endpoint_number) { - auto intf_handle = check_valid_endpoint(usb_direction::in, endpoint_number)->intf_handle; - UCHAR endpoint_address = ep_address(usb_direction::in, endpoint_number); + auto intf_handle = check_valid_endpoint(direction, endpoint_number)->intf_handle; + UCHAR endpoint_address = ep_address(direction, endpoint_number); - ULONG value = 0; - if (!WinUsb_SetPipePolicy(intf_handle, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) + ULONG timeout = 0; + if (!WinUsb_SetPipePolicy(intf_handle, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(timeout), &timeout)) usb_error::throw_error("Failed to set endpoint timeout"); - if (direction == usb_direction::in) { - value = TRUE; - if (!WinUsb_SetPipePolicy(intf_handle, endpoint_address, RAW_IO, sizeof(value), &value)) - usb_error::throw_error("Failed to set endpoint for raw IO"); - } + UCHAR raw_io = 1; + if (!WinUsb_SetPipePolicy(intf_handle, endpoint_address, RAW_IO, sizeof(raw_io), &raw_io)) + usb_error::throw_error("Failed to set endpoint for raw IO"); } void usb_device::submit_transfer_in(int endpoint_number, uint8_t* buffer, int buffer_len, OVERLAPPED* overlapped) { diff --git a/reference/windows/USB/usb_iostream.cpp b/reference/windows/USB/usb_iostream.cpp index db6afba6..caf9d8e2 100644 --- a/reference/windows/USB/usb_iostream.cpp +++ b/reference/windows/USB/usb_iostream.cpp @@ -17,6 +17,8 @@ usb_istreambuf::usb_istreambuf(usb_device_ptr device, int endpoint_number) : device(device), endpoint_number(endpoint_number), is_closed(false), submitted_index(0), completed_index(0), processed_index(-1) { setg(nullptr, nullptr, nullptr); + + device->configure_for_async_io(usb_direction::in, endpoint_number); buffer_size = 4 * device->get_endpoint(usb_direction::in, endpoint_number).packet_size(); @@ -122,6 +124,8 @@ usb_istreambuf::int_type usb_istreambuf::underflow() { usb_ostreambuf::usb_ostreambuf(usb_device_ptr device, int endpoint_number) : device(device), endpoint_number(endpoint_number), processing_index(0), completed_index(0), checked_index(0), needs_zlp(false) { + device->configure_for_async_io(usb_direction::out, endpoint_number); + packet_size = device->get_endpoint(usb_direction::out, endpoint_number).packet_size(); buffer_size = 1 * packet_size; From a0f2568c8648783843f33a945a1b74f2cbf5f962 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 11 Feb 2023 15:22:06 +0100 Subject: [PATCH 188/433] iostreams using blocking queue (C++/macOS) --- reference/macos/USB/blocking_queue.hpp | 69 +++++ reference/macos/USB/usb_device.cpp | 3 - reference/macos/USB/usb_iostream.cpp | 246 +++++++++--------- reference/macos/USB/usb_iostream.hpp | 118 +++++---- reference/macos/USB/usb_registry.cpp | 10 +- reference/macos/usb.xcodeproj/project.pbxproj | 2 + 6 files changed, 258 insertions(+), 190 deletions(-) create mode 100644 reference/macos/USB/blocking_queue.hpp diff --git a/reference/macos/USB/blocking_queue.hpp b/reference/macos/USB/blocking_queue.hpp new file mode 100644 index 00000000..154b0230 --- /dev/null +++ b/reference/macos/USB/blocking_queue.hpp @@ -0,0 +1,69 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#pragma once + +#include +#include + + +/** + * Blocking FIFO queue for passing work from one thread to another. + * + * The queue is unbounded. + */ +template +class blocking_queue { +public: + /** + * Indicates if the queue is empty. + * + * @return 'true' if the queue is empty, 'false' if the queue contains elements + */ + bool empty() const { + std::lock_guard lock(guard); + return queue.empty(); + } + + /** + * Adds the item to the end of the queue. + * + * @param item item to add + */ + void put(const T& item) { + { + std::lock_guard lock(guard); + queue.push(item); + } + + signal.notify_one(); + } + + /** + * Takes the oldest item from the queue and removes it. + * + * Waits until an item is available. + * + * @return item removed from queue + */ + T take() { + std::unique_lock lock(guard); + while (queue.empty()) + signal.wait(lock); + + T item = queue.front(); + queue.pop(); + return item; + } + +private: + std::queue queue; + mutable std::mutex guard; + std::condition_variable signal; +}; diff --git a/reference/macos/USB/usb_device.cpp b/reference/macos/USB/usb_device.cpp index ce342b87..6b6a699e 100644 --- a/reference/macos/USB/usb_device.cpp +++ b/reference/macos/USB/usb_device.cpp @@ -372,9 +372,6 @@ void usb_device::abort_transfer(usb_direction direction, int endpoint_number) { IOReturn ret = (*interface)->AbortPipe(interface, pipe->pipe_index); usb_error::check(ret, "failed to abort transfer"); - - ret = (*interface)->ClearPipeStallBothEnds(interface, pipe->pipe_index); - usb_error::check(ret, "failed to clear pipe stall"); } const usb_device::pipe_info* usb_device::get_pipe(int endpoint_address) { diff --git a/reference/macos/USB/usb_iostream.cpp b/reference/macos/USB/usb_iostream.cpp index b067db68..032387b4 100644 --- a/reference/macos/USB/usb_iostream.cpp +++ b/reference/macos/USB/usb_iostream.cpp @@ -13,191 +13,183 @@ // --- usb_istreambuf --- usb_istreambuf::usb_istreambuf(usb_device_ptr device, int endpoint_number) -: device_(device), ep_num_(endpoint_number), is_closed_(false), submitted_index_(0), completed_index_(0), processed_index_(-1) { +: device(device), endpoint_number(endpoint_number), is_closed(false) { setg(nullptr, nullptr, nullptr); - packet_size_ = device->get_endpoint(usb_direction::in, endpoint_number).packet_size(); + buffer_size = device->get_endpoint(usb_direction::in, endpoint_number).packet_size(); - // allocate the buffers - for (int i = 0; i < num_outstanding_requests; i++) - request_buffers[i] = new uint8_t[packet_size_]; - - // create completion handler lambda - io_completion = [this](IOReturn result, int size) { on_completed(result, size); }; - - // start requests except for one - const std::lock_guard lock(io_mutex); - for (int i = 0; i < num_outstanding_requests - 1; i++) - submit_request(); + // allocate the buffers and submit requests + for (int i = 0; i < max_outstanding_requests; i++) { + transfer_request* request = &requests[i]; + request->buffer = new uint8_t[buffer_size]; + request->io_completion = [this, request](IOReturn result, int size) { on_completed(request, result, size); }; + + if (i == 0) + current_request = request; + else + submit_transfer(request); + } } usb_istreambuf::~usb_istreambuf() { + close(); + // free buffers - for (int i = 0; i < num_outstanding_requests; i++) - delete [] request_buffers[i]; + for (int i = 0; i < max_outstanding_requests; i++) + delete [] requests[i].buffer; } void usb_istreambuf::close() { - is_closed_ = true; - io_condition.notify_all(); - device_->abort_transfer(usb_direction::in, ep_num_); + is_closed = true; + setg(nullptr, nullptr, nullptr); + + device->abort_transfer(usb_direction::in, endpoint_number); + + // wait until completion handlers have been called + while (num_outstanding_requests > 0) + wait_for_request_completion(); } -void usb_istreambuf::submit_request() { - int index = submitted_index_ % num_outstanding_requests; - submitted_index_ += 1; - - device_->submit_transfer_in(ep_num_, request_buffers[index], packet_size_, io_completion); +void usb_istreambuf::submit_transfer(transfer_request* request) { + device->submit_transfer_in(endpoint_number, request->buffer, buffer_size, request->io_completion); + num_outstanding_requests += 1; } -void usb_istreambuf::on_completed(IOReturn result, int size) { - const std::lock_guard lock(io_mutex); - if (is_closed_) { - completed_index_ += 1; - if (completed_index_ == submitted_index_) - delete this; - return; - } - - int index = completed_index_ % num_outstanding_requests; - request_sizes[index] = size; - request_results[index] = result; - - completed_index_ += 1; - io_condition.notify_all(); +void usb_istreambuf::on_completed(transfer_request* request, IOReturn result, int size) { + request->result_code = result; + request->result_size = size; + completed_request_queue.put(request); +} + +usb_istreambuf::transfer_request* usb_istreambuf::wait_for_request_completion() { + transfer_request* request = completed_request_queue.take(); + num_outstanding_requests -= 1; + return request; + } usb_istreambuf::int_type usb_istreambuf::underflow() { - if (is_closed_) + if (is_closed) return traits_type::eof(); if (gptr() < egptr()) return traits_type::to_int_type(*gptr()); - // loop until no ZLP has been received - while (true) { - std::unique_lock wait_lock(io_mutex); - processed_index_ += 1; - submit_request(); - - // wait until a completed request is available - io_condition.wait(wait_lock, [this] { return completed_index_ - processed_index_ > 0 || is_closed_; }); - - if (is_closed_) - return traits_type::eof(); - - int index = processed_index_ % num_outstanding_requests; - usb_error::check(request_results[index], "error reading from USB endpoint"); + // loop until non-ZLP has been received + do { + submit_transfer(current_request); - // set stream buffer to buffer from completed request - char* buf = reinterpret_cast(request_buffers[index]); - int size = request_sizes[index]; + current_request = wait_for_request_completion(); + usb_error::check(current_request->result_code, "error reading from USB endpoint"); + + char* buf = reinterpret_cast(current_request->buffer); + int size = current_request->result_size; + setg(buf, buf, buf + size); - if (size != 0) { - setg(buf, buf, buf + size); - return traits_type::to_int_type(*gptr()); - } - } + } while (current_request->result_size == 0); + + return traits_type::to_int_type(*gptr()); } // --- usb_ostreambuf --- usb_ostreambuf::usb_ostreambuf(usb_device_ptr device, int endpoint_number) -: device_(device), ep_num_(endpoint_number), is_closed_(false), processing_index_(0), - completed_index_(0), checked_index_(0), needs_zlp_(false) { +: device(device), endpoint_number(endpoint_number), is_closed(false), needs_zlp(false) { - packet_size_ = device->get_endpoint(usb_direction::out, endpoint_number).packet_size(); + packet_size = device->get_endpoint(usb_direction::out, endpoint_number).packet_size(); + buffer_size = packet_size; - // allocate the buffers - for (int i = 0; i < num_outstanding_requests; i++) - request_buffers[i] = new uint8_t[packet_size_]; - - char* buf = reinterpret_cast(request_buffers[0]); - setp(buf, buf + packet_size_); - - // create completion handler lambda - io_completion = [this](IOReturn result, int size) { on_completed(result, size); }; + // create requests + for (int i = 0; i < max_outstanding_requests; i++) { + transfer_request* request = &requests[i]; + request->buffer = new uint8_t[buffer_size]; + request->io_completion = [this, request](IOReturn result, int size) { on_completed(request, result); }; + } + + fill_queue(); +} + +void usb_ostreambuf::fill_queue() { + for (int i = 1; i < max_outstanding_requests; i++) + available_request_queue.put(&requests[i]); + + // configure stream buffer for first request + current_request = &requests[0]; + char* buf = reinterpret_cast(current_request->buffer); + setp(buf, buf + buffer_size); } usb_ostreambuf::~usb_ostreambuf() { + sync(); + // free buffers - for (int i = 0; i < num_outstanding_requests; i++) - delete [] request_buffers[i]; + for (int i = 0; i < max_outstanding_requests; i++) + delete [] requests[i].buffer; } int usb_ostreambuf::sync() { - std::unique_lock wait_lock(io_mutex); - // submit request if there is any data in the current buffer auto size = pptr() - pbase(); - if (size > 0) { - int index = processing_index_ % num_outstanding_requests; - device_->submit_transfer_out(ep_num_, request_buffers[index], (int)size, io_completion); - processing_index_ += 1; - needs_zlp_ = size == packet_size_; - } + if (size > 0) + submit_transfer((int)size); // send a zero-length packet if required - if (needs_zlp_) { - // wait until an unused buffer is available - io_condition.wait(wait_lock, [this] { return processing_index_ - completed_index_ < num_outstanding_requests; }); - check_for_errors(); - - device_->submit_transfer_out(ep_num_, nullptr, 0, io_completion); - processing_index_ += 1; - needs_zlp_ = false; - } - - // wait until all buffers have been transmitted - io_condition.wait(wait_lock, [this] { return processing_index_ == completed_index_; }); - check_for_errors(); + if (needs_zlp) + submit_transfer(0); + + // Wait until all buffers have been transmitted by removing them from the + // queue and reinserting them. One request is the current request. + // So the queue only contains max_outstanding_requests - 1 requests. + for (int i = 0; i < max_outstanding_requests - 1; i++) + wait_for_available_transfer(); + fill_queue(); + return 0; } int usb_ostreambuf::overflow (int c) { - std::unique_lock wait_lock(io_mutex); - // submit request auto size = pptr() - pbase(); - int index = processing_index_ % num_outstanding_requests; - device_->submit_transfer_out(ep_num_, request_buffers[index], (int)size, io_completion); - processing_index_ += 1; - needs_zlp_ = size == packet_size_; - - // wait until an unused buffer is available - io_condition.wait(wait_lock, [this] { return processing_index_ - completed_index_ < num_outstanding_requests; }); - check_for_errors(); + submit_transfer((int)size); - // configure stream buffer - index = processing_index_ % num_outstanding_requests; - char* buf = reinterpret_cast(request_buffers[index]); - setp(buf, buf + packet_size_); - // insert char if (c != traits_type::eof()) { *pptr() = (char)c; - pbump( 1 ); + pbump(1); } return c; } -void usb_ostreambuf::on_completed(IOReturn result, int size) { - const std::lock_guard lock(io_mutex); - int index = completed_index_ % num_outstanding_requests; - request_results[index] = result; - completed_index_ += 1; - io_condition.notify_all(); +void usb_ostreambuf::submit_transfer(int size) { + device->submit_transfer_out(endpoint_number, current_request->buffer, size, current_request->io_completion); + needs_zlp = size == packet_size; + + current_request = wait_for_available_transfer(); + + // configure stream buffer + char* buf = reinterpret_cast(current_request->buffer); + setp(buf, buf + buffer_size); +} + +void usb_ostreambuf::on_completed(transfer_request* request, IOReturn result) { + request->result_code = result; + available_request_queue.put(request); } -void usb_ostreambuf::check_for_errors() { - while (completed_index_ - checked_index_ > 0) { - int index = completed_index_ % num_outstanding_requests; - usb_error::check(request_results[index], "error writing to USB endpoint"); - checked_index_ += 1; +usb_ostreambuf::transfer_request* usb_ostreambuf::wait_for_available_transfer() { + auto request = available_request_queue.take(); + + // check for error + int result = request->result_code; + if (result != 0) { + request->result_code = 0; + throw usb_error("error writing to USB endpoint", result); } + + return request; } @@ -207,8 +199,8 @@ usb_istream::usb_istream(usb_device_ptr device, int ep_num) : std::istream(new usb_istreambuf(device, ep_num)) {} usb_istream::~usb_istream() { - // close buffer (it will deallocate itself) - static_cast(rdbuf())->close(); + // free stream buffer + delete rdbuf(); } @@ -218,6 +210,6 @@ usb_ostream::usb_ostream(usb_device_ptr device, int ep_num) : std::ostream(new usb_ostreambuf(device, ep_num)) {} usb_ostream::~usb_ostream() { - // flush all data - static_cast(rdbuf())->pubsync(); + // free stream buffer + delete rdbuf(); } diff --git a/reference/macos/USB/usb_iostream.hpp b/reference/macos/USB/usb_iostream.hpp index 7860a313..ca2b97a3 100644 --- a/reference/macos/USB/usb_iostream.hpp +++ b/reference/macos/USB/usb_iostream.hpp @@ -10,10 +10,9 @@ #pragma once #include -#include -#include #include #include "usb_device.hpp" +#include "blocking_queue.hpp" /** * Input stream buffer for USB bulk or interrupt endpoint. @@ -34,41 +33,43 @@ class usb_istreambuf : public std::streambuf { protected: /// Called when the internal buffer has no further data to read. virtual int_type underflow(); - - void on_completed(IOReturn result, int size); - + private: - void submit_request(); + /// Transfer request + struct transfer_request { + /// buffer for recevied data + uint8_t* buffer; + /// result coce + int result_code; + /// result size (in bytes) + int result_size; + /// IO completion handler + std::function io_completion; + }; + + void on_completed(transfer_request* request, IOReturn result, int size); + void submit_transfer(transfer_request* request); + transfer_request* wait_for_request_completion(); /// Maximum number of concurrently outstanding requests - static constexpr int num_outstanding_requests = 4; - + static constexpr int max_outstanding_requests = 4; + /// USB device - usb_device_ptr device_; + usb_device_ptr device; /// endpoint number - int ep_num_; + int endpoint_number; /// Indicates that this stream buffer is closed - bool is_closed_; - /// packet size - int packet_size_; - /// Mutex for synchronization between input stream caller and background thread handling IO completion. - std::mutex io_mutex; - /// Condition for synchronization between input stream caller and background thread handling IO completion - std::condition_variable io_condition; - /// Index after last submitted IO request - unsigned int submitted_index_; - /// Index after last completed IO request - unsigned int completed_index_; - /// Index after last processed IO request - unsigned int processed_index_; - /// Data buffers for receiving data - uint8_t* request_buffers[num_outstanding_requests]; - /// Size of received data - int request_sizes[num_outstanding_requests]; - /// Result code of IO request - IOReturn request_results[num_outstanding_requests]; - /// IO completion lambda - std::function io_completion; + bool is_closed; + /// buffer size + int buffer_size; + /// transfer requests + transfer_request requests[max_outstanding_requests]; + /// queue with completed requests + blocking_queue completed_request_queue; + /// number of outstanding requests (requests pending with OS and requests in queue) + int num_outstanding_requests; + /// current request being read from + transfer_request* current_request; }; /** @@ -90,42 +91,45 @@ class usb_ostreambuf : public std::streambuf { /// Called when the internal buffer has no space left to add more data. virtual int overflow (int c); - void on_completed(IOReturn result, int size); - - void check_for_errors(); private: - void submit_request(); + /// Transfer request + struct transfer_request { + /// buffer for recevied data + uint8_t* buffer; + /// result coce + int result_code; + /// IO completion handler + std::function io_completion; + }; + + void fill_queue(); + void submit_transfer(int size); + void on_completed(transfer_request* request, IOReturn result); + transfer_request* wait_for_available_transfer(); /// Maximum number of concurrently outstanding requests - static constexpr int num_outstanding_requests = 4; + static constexpr int max_outstanding_requests = 4; /// USB device - usb_device_ptr device_; + usb_device_ptr device; /// endpoint number - int ep_num_; + int endpoint_number; /// Indicates that this stream buffer is closed - bool is_closed_; + bool is_closed; /// Indicates if a zero-length packet is required - bool needs_zlp_; + bool needs_zlp; /// packet size - int packet_size_; - /// Mutex for synchronization between output stream caller and background thread handling IO completion. - std::mutex io_mutex; - /// Condition for synchronization between output stream caller and background thread handling IO completion - std::condition_variable io_condition; - /// Index of buffer being currently used by base class - unsigned int processing_index_; - /// Index after last completed IO request - unsigned int completed_index_; - /// Index after last completed IO request that has been checked for errors - unsigned int checked_index_; - /// Data buffers for transmitting data - uint8_t* request_buffers[num_outstanding_requests]; - /// Result code of IO request - IOReturn request_results[num_outstanding_requests]; - /// IO completion lambda - std::function io_completion; + int packet_size; + /// packet size + int buffer_size; + /// transfer requests + transfer_request requests[max_outstanding_requests]; + /// queue with available requests + blocking_queue available_request_queue; + /// current request being written to + transfer_request* current_request; + }; /** diff --git a/reference/macos/USB/usb_registry.cpp b/reference/macos/USB/usb_registry.cpp index 2e673ef4..adf3b909 100644 --- a/reference/macos/USB/usb_registry.cpp +++ b/reference/macos/USB/usb_registry.cpp @@ -202,9 +202,13 @@ std::shared_ptr usb_registry::get_shared_ptr(usb_device* device) { void usb_registry::add_event_source(CFRunLoopSourceRef source) { std::unique_lock wait_lock(async_io_mutex); if (async_io_run_loop == nullptr) { - async_io_thread = std::thread(&usb_registry::async_io_run, this, source); - async_io_condition.wait(wait_lock, [this] { return async_io_run_loop != nullptr; }); - return; + if (async_io_thread.joinable()) { + async_io_condition.wait(wait_lock, [this] { return async_io_run_loop != nullptr; }); + } else { + async_io_thread = std::thread(&usb_registry::async_io_run, this, source); + async_io_condition.wait(wait_lock, [this] { return async_io_run_loop != nullptr; }); + return; + } } CFRunLoopAddSource(async_io_run_loop, source, kCFRunLoopDefaultMode); diff --git a/reference/macos/usb.xcodeproj/project.pbxproj b/reference/macos/usb.xcodeproj/project.pbxproj index bd3bf925..b17cf56e 100644 --- a/reference/macos/usb.xcodeproj/project.pbxproj +++ b/reference/macos/usb.xcodeproj/project.pbxproj @@ -40,6 +40,7 @@ 64292E7229144D6C004F6169 /* prng.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = prng.hpp; sourceTree = ""; }; 64292E7429144DE1004F6169 /* speed_test.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = speed_test.cpp; sourceTree = ""; }; 64292E7529144DE1004F6169 /* speed_test.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = speed_test.hpp; sourceTree = ""; }; + 64443AF22997C56E009283A9 /* blocking_queue.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = blocking_queue.hpp; sourceTree = ""; }; 64835E5C290BCA9F00113E4E /* configuration.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = configuration.hpp; sourceTree = ""; }; 64835E5D290BCA9F00113E4E /* config_parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = config_parser.cpp; sourceTree = ""; }; 64835E5E290BCA9F00113E4E /* config_parser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = config_parser.hpp; sourceTree = ""; }; @@ -100,6 +101,7 @@ children = ( 64937C8328D71D31009BD0C2 /* assertion.hpp */, 64937C8228D71D31009BD0C2 /* assertion.cpp */, + 64443AF22997C56E009283A9 /* blocking_queue.hpp */, 64835E5E290BCA9F00113E4E /* config_parser.hpp */, 64835E5D290BCA9F00113E4E /* config_parser.cpp */, 64835E5C290BCA9F00113E4E /* configuration.hpp */, From a48925182f143499612c185edcc8b8981ae9b04d Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 11 Feb 2023 15:45:42 +0100 Subject: [PATCH 189/433] High throughput input/output streams (macOS) --- java-does-usb/jextract/macos/gen_macos.sh | 1 + .../net/codecrete/usb/macos/IoKitUSB.java | 21 ++ .../usb/macos/MacosEndpointInputStream.java | 194 ++++++++++++++++++ .../usb/macos/MacosEndpointOutputStream.java | 186 +++++++++++++++++ .../codecrete/usb/macos/MacosUSBDevice.java | 109 +++++++++- .../usb/macos/MacosUSBDeviceRegistry.java | 49 ++++- .../gen/corefoundation/CoreFoundation.java | 18 +- .../macos/gen/corefoundation/constants$1.java | 28 +-- .../macos/gen/corefoundation/constants$2.java | 24 +++ .../java/net/codecrete/usb/SpeedTest.java | 71 +++++++ 10 files changed, 675 insertions(+), 26 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index dfc6b75f..88f04821 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -23,6 +23,7 @@ $JEXTRACT --source --output ../../src/main/java \ --include-function CFNumberGetValue \ --include-function CFRunLoopGetCurrent \ --include-function CFRunLoopAddSource \ + --include-function CFRunLoopRemoveSource \ --include-function CFRunLoopRun \ --include-function CFUUIDGetUUIDBytes \ --include-constant kCFNumberSInt32Type \ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index 8af9151e..c8557ec1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -113,6 +113,12 @@ public static int ReadPipeTO(MemorySegment self, byte pipeRef, MemorySegment buf .apply(self, pipeRef, buf, sizeHolder, noDataTimeout, completionTimeout); } + // IOReturn (*ReadPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, void *refcon); + public static int ReadPipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, MemorySegment callback, MemorySegment refcon) { + return IOUSBInterfaceInterface190.ReadPipeAsync(getVtable(self), SegmentScope.global()) + .apply(self, pipeRef, buf, size, callback, refcon); + } + // IOReturn (*WritePipe)(void *self, UInt8 pipeRef, void *buf, UInt32 size); public static int WritePipe(MemorySegment self, byte pipeRef, MemorySegment buf, int size) { return IOUSBInterfaceInterface190.WritePipe(getVtable(self), SegmentScope.global()).apply(self, pipeRef, buf, size); @@ -123,6 +129,11 @@ public static int WritePipeTO(MemorySegment self, byte pipeRef, MemorySegment bu return IOUSBInterfaceInterface190.WritePipeTO(getVtable(self), SegmentScope.global()).apply(self, pipeRef, buf, size, noDataTimeout, completionTimeout); } + // IOReturn (*WritePipeAsync)(vovoid *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, void *refcon); + public static int WritePipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, MemorySegment callback, MemorySegment refcon) { + return IOUSBInterfaceInterface190.WritePipeAsync(getVtable(self), SegmentScope.global()).apply(self, pipeRef, buf, size, callback, refcon); + } + // IOReturn (* AbortPipe)(void* self, UInt8 pipeRef); public static int AbortPipe(MemorySegment self, byte pipeRef) { return IOUSBInterfaceInterface190.AbortPipe(getVtable(self), SegmentScope.global()).apply(self, pipeRef); @@ -137,4 +148,14 @@ public static int SetAlternateInterface(MemorySegment self, byte alternateSettin public static int ClearPipeStallBothEnds(MemorySegment self, byte pipeRef) { return IOUSBInterfaceInterface190.ClearPipeStallBothEnds(getVtable(self), SegmentScope.global()).apply(self, pipeRef); } + + // CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void* self); + public static MemorySegment GetInterfaceAsyncEventSource(MemorySegment self) { + return IOUSBInterfaceInterface190.GetInterfaceAsyncEventSource(getVtable(self), SegmentScope.global()).apply(self); + } + + // IOReturn (*CreateInterfaceAsyncEventSource)(void *self, CFRunLoopSourceRef *source); + public static int CreateInterfaceAsyncEventSource(MemorySegment self, MemorySegment source) { + return IOUSBInterfaceInterface190.CreateInterfaceAsyncEventSource(getVtable(self), SegmentScope.global()).apply(self, source); + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java new file mode 100644 index 00000000..35349d43 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java @@ -0,0 +1,194 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.macos; + +import net.codecrete.usb.USBDirection; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.util.concurrent.ArrayBlockingQueue; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static net.codecrete.usb.macos.MacosUSBException.throwException; + +/** + * Input stream for bulk endpoints – optimized for high throughput. + * + *

+ * Multiple asynchronous transfer IN requests are submitted to achieve a good + * degree of concurrency between the USB communication handled by the operating + * system and the consuming application code. + *

+ *

+ * For thread synchronization (between the background thread handling IO completion + * and the consuming application thread) a blocking queue is used. When an transfer IN + * requests completes, the background thread adds it to the queue. The consuming code + * waits for the next item in the queue. + *

+ */ +public class MacosEndpointInputStream extends InputStream { + + private static final int MAX_OUTSTANDING_REQUESTS = 4; + + private MacosUSBDevice device; + private final int endpointNumber; + // Arena to allocate buffers and completion handlers + private final Arena arena; + // Size of buffers (multiple of packet size) + private final int bufferSize; + // Queue of completed requests + private final ArrayBlockingQueue completedRequestQueue; + // Number of outstanding requests (includes requests pending with the + // operation system and requests in the completed queue) + private int numOutstandingRequests; + // Request and buffer being currently read from + private TransferRequest currentRequest; + // Read offset within current request + private int readOffset; + + /** + * Creates a new instance + * + * @param device USB device + * @param endpointNumber endpoint number + */ + MacosEndpointInputStream(MacosUSBDevice device, int endpointNumber) { + this.device = device; + this.endpointNumber = endpointNumber; + + bufferSize = device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); + completedRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); + arena = Arena.openShared(); + + // create all requests and submit all except one + for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { + final var request = new TransferRequest(); + request.buffer = arena.allocate(bufferSize, 8); + request.completionHandler = device.createCompletionHandler(USBDirection.IN, endpointNumber, arena, + (result, size) -> onCompletion(request, result, size)); + + if (i == 0) { + currentRequest = request; + } else { + submitRequest(request); + } + } + } + + @Override + public int read() throws IOException { + if (isClosed()) + return -1; + + if (available() == 0) + receiveMoreData(); + + if (isClosed()) + return -1; + + int b = currentRequest.buffer.get(JAVA_BYTE, readOffset) & 0xff; + readOffset += 1; + return b; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (isClosed()) + return -1; + + if (available() == 0) + receiveMoreData(); + + if (isClosed()) + return -1; + + // copy data to receiving buffer + int n = Math.min(len, currentRequest.resultSize - readOffset); + MemorySegment.copy(currentRequest.buffer, readOffset, MemorySegment.ofArray(b), off, n); + readOffset += n; + + // TODO: poll for further completed requests if 'n' is les than 'len' + + return n; + } + + @SuppressWarnings("RedundantThrows") + @Override + public int available() throws IOException { + return currentRequest.resultSize - readOffset; + } + + private boolean isClosed() { + return device == null; + } + + @SuppressWarnings("RedundantThrows") + @Override + public void close() throws IOException { + // abort all transfers on endpoint + device.abortTransfer(USBDirection.IN, endpointNumber); + device = null; + + // wait until completion handlers have been called + while (numOutstandingRequests > 0) + waitForRequestCompletion(); + + completedRequestQueue.clear(); + currentRequest = null; + arena.close(); + } + + private void receiveMoreData() throws IOException { + // loop until non-ZLP has been received + do { + submitRequest(currentRequest); + + currentRequest = waitForRequestCompletion(); + readOffset = 0; + + // check for error + if (currentRequest.result != 0) { + close(); + throwException(currentRequest.result, "error reading from USB endpoint"); + } + } while (currentRequest.resultSize == 0); + } + + void submitRequest(TransferRequest request) { + device.submitTransferIn(endpointNumber, request.buffer, bufferSize, request.completionHandler); + numOutstandingRequests += 1; + } + + void onCompletion(TransferRequest request, int result, int size) { + request.result = result; + request.resultSize = size; + completedRequestQueue.add(request); + } + + TransferRequest waitForRequestCompletion() { + while (true) { + try { + TransferRequest request = completedRequestQueue.take(); + numOutstandingRequests -= 1; + return request; + + } catch (InterruptedException e) { + // ignore and retry + } + } + } + + private static class TransferRequest { + MemorySegment buffer; + int result; + int resultSize; + MemorySegment completionHandler; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java new file mode 100644 index 00000000..c7ef7093 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java @@ -0,0 +1,186 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.macos; + +import net.codecrete.usb.USBDirection; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.util.Arrays; +import java.util.concurrent.ArrayBlockingQueue; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static net.codecrete.usb.macos.MacosUSBException.throwException; + +/** + * Output stream for bulk endpoints – optimized for high throughput. + * + *

+ * Multiple asynchronous transfer OUT requests are submitted to achieve a good + * degree of concurrency between the USB communication handled by the operating + * system and the producing application code. The number of requests is limited + * in order to retain the flow control and keep memory usage at a reasonable size. + *

+ *

+ * For thread synchronization (between the background thread handling IO completion + * and the producing application thread) a blocking queue is used. It is prefilled with + * requests ready to be used for a transfer. The background thread adds the completed + * requests back to this queue. The producing application thread waits until a request + * is available for use. + *

+ */ +public class MacosEndpointOutputStream extends OutputStream { + + private static final int MAX_OUTSTANDING_REQUESTS = 4; + + private MacosUSBDevice device; + private final int endpointNumber; + private final Arena arena; + // Endpoint's packet size + private final int packetSize; + // Size of buffers (multiple of packet size) + private final int bufferSize; + // Blocking queue of available requests (to limit the number of submitted requests) + private final ArrayBlockingQueue availableRequestQueue; + private boolean needsZlp; + private TransferRequest currentRequest; + private int writeOffset; + + + /** + * Creates a new instance + * @param device USB device + * @param endpointNumber endpoint number + */ + MacosEndpointOutputStream(MacosUSBDevice device, int endpointNumber) { + this.device = device; + this.endpointNumber = endpointNumber; + + packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize(); + bufferSize = packetSize; + availableRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); + arena = Arena.openShared(); + + // prefill request queue + for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { + final var request = new TransferRequest(); + request.buffer = arena.allocate(bufferSize, 8); + request.completionHandler = device.createCompletionHandler(USBDirection.OUT, endpointNumber, arena, + (result, size) -> onCompletion(request, result)); + + if (i == 0) { + currentRequest = request; + } else { + availableRequestQueue.add(request); + } + } + } + + @Override + public void write(int b) throws IOException { + if (isClosed()) + throw new IOException("Bulk endpoint output stream has been closed"); + + currentRequest.buffer.set(JAVA_BYTE, writeOffset, (byte)b); + writeOffset += 1; + if (writeOffset == bufferSize) + submitTransfer(writeOffset); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (isClosed()) + throw new IOException("Bulk endpoint output stream has been closed"); + + while (len > 0) { + int chunkSize = Math.min(len, bufferSize - writeOffset); + MemorySegment.copy(b, off, currentRequest.buffer, JAVA_BYTE, writeOffset, chunkSize); + writeOffset += chunkSize; + off += chunkSize; + len -= chunkSize; + + if (writeOffset == bufferSize) + submitTransfer(writeOffset); + } + } + + @Override + public void flush() throws IOException { + if (isClosed()) + throw new IOException("Bulk endpoint output stream has been closed"); + + if (writeOffset > 0) + submitTransfer(writeOffset); + + if (needsZlp) + submitTransfer(0); + + // Wait until all buffers have been transmitted by removing them from the + // queue and reinserting them. One request is the current request. + // So the queue only contains MAX_OUTSTANDING_REQUESTS - 1 requests. + var requests = new TransferRequest[MAX_OUTSTANDING_REQUESTS - 1]; + for (int i = 0; i < MAX_OUTSTANDING_REQUESTS - 1; i++) + requests[i] = waitForAvailableRequest(); + availableRequestQueue.addAll(Arrays.asList(requests).subList(1, MAX_OUTSTANDING_REQUESTS - 1)); + } + + @Override + public void close() throws IOException { + flush(); + + device = null; + availableRequestQueue.clear(); + currentRequest = null; + arena.close(); + } + + private boolean isClosed() { + return device == null; + } + + private void submitTransfer(int size) { + device.submitTransferOut(endpointNumber, currentRequest.buffer, size, currentRequest.completionHandler); + needsZlp = size == packetSize; + + writeOffset = 0; + currentRequest = waitForAvailableRequest(); + } + + private void onCompletion(TransferRequest request, int result) { + request.result = result; + availableRequestQueue.add(request); + } + + TransferRequest waitForAvailableRequest() { + while (true) { + try { + TransferRequest request = availableRequestQueue.take(); + + // check for error + int result = request.result; + if (result != 0) { + request.result = 0; + throwException(result, "error writing to USB endpoint"); + } + + return request; + + } catch (InterruptedException e) { + // ignore and retry + } + } + } + + private static class TransferRequest { + MemorySegment buffer; + int result; + MemorySegment completionHandler; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 7c1875df..82be030b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -19,8 +19,15 @@ import net.codecrete.usb.macos.gen.iokit.IOUSBFindInterfaceRequest; import net.codecrete.usb.usbstandard.ConfigurationDescriptor; +import java.io.InputStream; +import java.io.OutputStream; import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -31,13 +38,15 @@ public class MacosUSBDevice extends USBDeviceImpl { + private final MacosUSBDeviceRegistry registry; private MemorySegment device; private int configurationValue; private List claimedInterfaces; private Map endpoints; - MacosUSBDevice(MemorySegment device, Object id, int vendorId, int productId) { + MacosUSBDevice(MacosUSBDeviceRegistry registry, MemorySegment device, Object id, int vendorId, int productId) { super(id, vendorId, productId); + this.registry = registry; loadDescription(device); @@ -213,6 +222,10 @@ public void releaseInterface(int interfaceNumber) { var interfaceInfo = interfaceInfoOptional.get(); + var source = IoKitUSB.GetInterfaceAsyncEventSource(interfaceInfo.iokitInterface()); + if (source.address() != 0) + registry.removeEventSource(source); + int ret = IoKitUSB.USBInterfaceClose(interfaceInfo.iokitInterface()); if (ret != 0) throwException(ret, "Failed to release interface"); @@ -419,7 +432,73 @@ public byte[] transferIn(int endpointNumber, int timeout) { } } - @Override + static final MethodHandle asyncIOCompletedMH; + + static { + try { + asyncIOCompletedMH = MethodHandles.lookup().findStatic(MacosUSBDevice.class, "asyncIOCompleted", + MethodType.methodType(void.class, AsyncIOCallback.class, MemorySegment.class, int.class, MemorySegment.class)); + } catch (IllegalAccessException|NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + static void asyncIOCompleted(AsyncIOCallback callback, MemorySegment ignoredRefcon, int result, MemorySegment arg0) { + callback.completed(result, (int)arg0.address()); + } + + synchronized MemorySegment createCompletionHandler(USBDirection direction, int endpointNumber, Arena arena, AsyncIOCallback callback) { + var endpoint = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, null); + + var source = IoKitUSB.GetInterfaceAsyncEventSource(endpoint.iokitInterface()); + if (source.address() == 0) { + try (Arena innerArena = Arena.openConfined()) { + var sourceHolder = innerArena.allocate(ADDRESS); + int ret = IoKitUSB.CreateInterfaceAsyncEventSource(endpoint.iokitInterface(), sourceHolder); + if (ret != 0) + throwException(ret, "failed to create event source"); + source = sourceHolder.get(ADDRESS, 0); + registry.addEventSource(source); + } + } + + var methodHandle = asyncIOCompletedMH.bindTo(callback); + return Linker.nativeLinker().upcallStub(methodHandle, + FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT, ADDRESS), arena.scope()); + } + + void submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, MemorySegment completionHandler) { + + var endpoint = getEndpointInfo(endpointNumber, USBDirection.IN, + USBTransferType.BULK, null); + + // submit request + int ret = IoKitUSB.ReadPipeAsync(endpoint.iokitInterface(), endpoint.pipeIndex, buffer, bufferSize, completionHandler, MemorySegment.NULL); + if (ret != 0) + throwException(ret, "failed to submit async transfer"); + } + + void submitTransferOut(int endpointNumber, MemorySegment data, int dataSize, MemorySegment completionHandler) { + + var endpoint = getEndpointInfo(endpointNumber, USBDirection.OUT, + USBTransferType.BULK, null); + + // submit request + int ret = IoKitUSB.WritePipeAsync(endpoint.iokitInterface(), endpoint.pipeIndex, data, dataSize, completionHandler, MemorySegment.NULL); + if (ret != 0) + throwException(ret, "failed to submit async transfer"); + } + + public void abortTransfer(USBDirection direction, int endpointNumber) { + var endpointInfo = getEndpointInfo(endpointNumber, direction, + USBTransferType.BULK, USBTransferType.INTERRUPT); + + int ret = IoKitUSB.AbortPipe(endpointInfo.iokitInterface(), endpointInfo.pipeIndex()); + if (ret != 0) + throwException(ret, "Aborting transfer failed"); + } + + @Override public void clearHalt(USBDirection direction, int endpointNumber) { var endpointInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); @@ -429,6 +508,20 @@ public void clearHalt(USBDirection direction, int endpointNumber) { throwException(ret, "Clearing halt condition failed"); } + @Override + public InputStream openInputStream(int endpointNumber) { + // check that endpoint number is valid + getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, null); + return new MacosEndpointInputStream(this, endpointNumber); + } + + @Override + public OutputStream openOutputStream(int endpointNumber) { + // check that endpoint number is valid + getEndpoint(endpointNumber, USBDirection.OUT, USBTransferType.BULK, null); + return new MacosEndpointOutputStream(this, endpointNumber); + } + private static USBTransferType getTransferType(byte macosTransferType) { return switch (macosTransferType) { case 1 -> USBTransferType.ISOCHRONOUS; @@ -443,4 +536,16 @@ record InterfaceInfo(MemorySegment iokitInterface, int interfaceNumber) { record EndpointInfo(MemorySegment iokitInterface, byte pipeIndex, USBTransferType transferType, int packetSize) { } + + @FunctionalInterface + public interface AsyncIOCallback { + + /** + * Called when the asynchronous IO has completed. + * + * @param result the result code of the operation + * @param size the size of the transferred data (in bytes) + */ + void completed(int result, int size); + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index ae157a21..fafb1d92 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -18,6 +18,8 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.ArrayList; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import static java.lang.foreign.MemorySegment.NULL; @@ -169,7 +171,7 @@ private USBDevice createDevice(Long entryID, int service, MemorySegment deviceIn info.vid = vendorId; info.pid = productId; - var device = new MacosUSBDevice(deviceIntf, entryID, vendorId, productId); + var device = new MacosUSBDevice(this, deviceIntf, entryID, vendorId, productId); String manufacturer = IoKitHelper.getPropertyString(service, KEY_VENDOR, arena); String product = IoKitHelper.getPropertyString(service, KEY_PRODUCT, arena); @@ -256,6 +258,51 @@ private void onDevicesDisconnected(@SuppressWarnings("SameParameterValue") Memor }); } + private final ReentrantLock asyncIoLock = new ReentrantLock(); + private final Condition asyncIoReady = asyncIoLock.newCondition(); + private MemorySegment asyncIoRunLoop; + + void addEventSource(MemorySegment source) { + try { + asyncIoLock.lock(); + + if (asyncIoRunLoop == null) { + // start background thread + Thread t = new Thread(() -> asyncIOCompletionTask(source), "USB async IO"); + t.setDaemon(true); + t.start(); + + while (asyncIoRunLoop == null) + asyncIoReady.awaitUninterruptibly(); + + return; + } + + CoreFoundation.CFRunLoopAddSource(asyncIoRunLoop, source, IOKit.kCFRunLoopDefaultMode$get()); + + } finally { + asyncIoLock.unlock(); + } + } + + void removeEventSource(MemorySegment source) { + CoreFoundation.CFRunLoopRemoveSource(asyncIoRunLoop, source, IOKit.kCFRunLoopDefaultMode$get()); + } + + private void asyncIOCompletionTask(MemorySegment firstSource) { + try { + asyncIoLock.lock(); + asyncIoRunLoop = CoreFoundation.CFRunLoopGetCurrent(); + CoreFoundation.CFRunLoopAddSource(asyncIoRunLoop, firstSource, IOKit.kCFRunLoopDefaultMode$get()); + asyncIoReady.signalAll(); + } finally { + asyncIoLock.unlock(); + } + + // loop forever + CoreFoundation.CFRunLoopRun(); + } + @FunctionalInterface interface IOKitDeviceConsumer { void accept(long entryId, int service, MemorySegment deviceIntf); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java index 32901212..4b0efbe2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java @@ -201,8 +201,24 @@ public static void CFRunLoopAddSource(MemorySegment rl, MemorySegment source, Me throw new AssertionError("should not reach here", ex$); } } + public static MethodHandle CFRunLoopRemoveSource$MH() { + return RuntimeHelper.requireNonNull(constants$1.CFRunLoopRemoveSource$MH,"CFRunLoopRemoveSource"); + } + /** + * {@snippet : + * void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode); + * } + */ + public static void CFRunLoopRemoveSource(MemorySegment rl, MemorySegment source, MemorySegment mode) { + var mh$ = CFRunLoopRemoveSource$MH(); + try { + mh$.invokeExact(rl, source, mode); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static MethodHandle CFUUIDGetUUIDBytes$MH() { - return RuntimeHelper.requireNonNull(constants$1.CFUUIDGetUUIDBytes$MH,"CFUUIDGetUUIDBytes"); + return RuntimeHelper.requireNonNull(constants$2.CFUUIDGetUUIDBytes$MH,"CFUUIDGetUUIDBytes"); } /** * {@snippet : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java index 90825ba1..c4ac9715 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java @@ -3,7 +3,6 @@ package net.codecrete.usb.macos.gen.corefoundation; import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; import java.lang.invoke.MethodHandle; final class constants$1 { @@ -42,29 +41,14 @@ final class constants$1 { "CFRunLoopAddSource", constants$1.CFRunLoopAddSource$FUNC ); - static final FunctionDescriptor CFUUIDGetUUIDBytes$FUNC = FunctionDescriptor.of(MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("byte0"), - Constants$root.C_CHAR$LAYOUT.withName("byte1"), - Constants$root.C_CHAR$LAYOUT.withName("byte2"), - Constants$root.C_CHAR$LAYOUT.withName("byte3"), - Constants$root.C_CHAR$LAYOUT.withName("byte4"), - Constants$root.C_CHAR$LAYOUT.withName("byte5"), - Constants$root.C_CHAR$LAYOUT.withName("byte6"), - Constants$root.C_CHAR$LAYOUT.withName("byte7"), - Constants$root.C_CHAR$LAYOUT.withName("byte8"), - Constants$root.C_CHAR$LAYOUT.withName("byte9"), - Constants$root.C_CHAR$LAYOUT.withName("byte10"), - Constants$root.C_CHAR$LAYOUT.withName("byte11"), - Constants$root.C_CHAR$LAYOUT.withName("byte12"), - Constants$root.C_CHAR$LAYOUT.withName("byte13"), - Constants$root.C_CHAR$LAYOUT.withName("byte14"), - Constants$root.C_CHAR$LAYOUT.withName("byte15") - ), + static final FunctionDescriptor CFRunLoopRemoveSource$FUNC = FunctionDescriptor.ofVoid( + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle CFUUIDGetUUIDBytes$MH = RuntimeHelper.downcallHandle( - "CFUUIDGetUUIDBytes", - constants$1.CFUUIDGetUUIDBytes$FUNC + static final MethodHandle CFRunLoopRemoveSource$MH = RuntimeHelper.downcallHandle( + "CFRunLoopRemoveSource", + constants$1.CFRunLoopRemoveSource$FUNC ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java index 2bfd6b76..5e1183c1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java @@ -9,6 +9,30 @@ final class constants$2 { // Suppresses default constructor, ensuring non-instantiability. private constants$2() {} + static final FunctionDescriptor CFUUIDGetUUIDBytes$FUNC = FunctionDescriptor.of(MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("byte0"), + Constants$root.C_CHAR$LAYOUT.withName("byte1"), + Constants$root.C_CHAR$LAYOUT.withName("byte2"), + Constants$root.C_CHAR$LAYOUT.withName("byte3"), + Constants$root.C_CHAR$LAYOUT.withName("byte4"), + Constants$root.C_CHAR$LAYOUT.withName("byte5"), + Constants$root.C_CHAR$LAYOUT.withName("byte6"), + Constants$root.C_CHAR$LAYOUT.withName("byte7"), + Constants$root.C_CHAR$LAYOUT.withName("byte8"), + Constants$root.C_CHAR$LAYOUT.withName("byte9"), + Constants$root.C_CHAR$LAYOUT.withName("byte10"), + Constants$root.C_CHAR$LAYOUT.withName("byte11"), + Constants$root.C_CHAR$LAYOUT.withName("byte12"), + Constants$root.C_CHAR$LAYOUT.withName("byte13"), + Constants$root.C_CHAR$LAYOUT.withName("byte14"), + Constants$root.C_CHAR$LAYOUT.withName("byte15") + ), + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle CFUUIDGetUUIDBytes$MH = RuntimeHelper.downcallHandle( + "CFUUIDGetUUIDBytes", + constants$2.CFUUIDGetUUIDBytes$FUNC + ); static final FunctionDescriptor CFUUIDCreateFromUUIDBytes$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT, MemoryLayout.structLayout( diff --git a/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java new file mode 100644 index 00000000..f5d91a01 --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java @@ -0,0 +1,71 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Unit test to measure loopback speed +// + +package net.codecrete.usb; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.concurrent.CompletableFuture; + +import static org.junit.jupiter.api.Assertions.*; + +public class SpeedTest extends TestDeviceBase { + + @Test + void loopback_isFast() throws Throwable { + final boolean isHighSpeed = testDevice.getEndpoint(USBDirection.IN, LOOPBACK_EP_IN).packetSize() == 512; + final int numBytes = isHighSpeed ? 5000000 : 500000; + + byte[] sampleData = generateRandomBytes(numBytes, 7219937602343L); + + long start = System.currentTimeMillis(); + var writer = CompletableFuture.runAsync(() -> writeBytes(sampleData)); + var reader = CompletableFuture.supplyAsync(() -> readBytes(numBytes)); + CompletableFuture.allOf(writer, reader).join(); + long end = System.currentTimeMillis(); + if (reader.isCompletedExceptionally()) + throw reader.exceptionNow(); + + assertArrayEquals(sampleData, reader.resultNow()); + + double throughput = 2.0 * numBytes / (end - start); + double expectedThroughput = isHighSpeed ? 19000 : 500; + System.out.printf("Throughput: expected %,.0f KB/s, actual %,.0f KB/s%n", expectedThroughput, throughput); + + assertTrue(throughput >= expectedThroughput, "Expected throughput not achieved"); + } + + static void writeBytes(byte[] data) { + try (var os = testDevice.openOutputStream(LOOPBACK_EP_OUT)) { + os.write(data); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + static byte[] readBytes(int numBytes) { + try (var is = testDevice.openInputStream(LOOPBACK_EP_IN)) { + byte[] buffer = new byte[numBytes]; + int bytesRead = 0; + while (bytesRead < numBytes) { + int n = is.read(buffer, bytesRead, numBytes - bytesRead); + if (n <= 0) + throw new RuntimeException("unexpected end of input stream"); + bytesRead += n; + } + return buffer; + + } catch (IOException e) { + throw new RuntimeException(e); + } catch (Throwable e) { + e.printStackTrace(System.err); + throw e; + } + } +} From 0cbfbd2b450cad423c5b4de1baf4219f0961d296 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 11 Feb 2023 15:49:55 +0100 Subject: [PATCH 190/433] Fix background thread startup glitch --- .../usb/macos/MacosUSBDeviceRegistry.java | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index fafb1d92..8915ad59 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -259,7 +259,7 @@ private void onDevicesDisconnected(@SuppressWarnings("SameParameterValue") Memor } private final ReentrantLock asyncIoLock = new ReentrantLock(); - private final Condition asyncIoReady = asyncIoLock.newCondition(); + private Condition asyncIoReady; private MemorySegment asyncIoRunLoop; void addEventSource(MemorySegment source) { @@ -267,15 +267,24 @@ void addEventSource(MemorySegment source) { asyncIoLock.lock(); if (asyncIoRunLoop == null) { - // start background thread - Thread t = new Thread(() -> asyncIOCompletionTask(source), "USB async IO"); - t.setDaemon(true); - t.start(); - while (asyncIoRunLoop == null) - asyncIoReady.awaitUninterruptibly(); + if (asyncIoReady == null) { + // start background thread + asyncIoReady = asyncIoLock.newCondition(); + Thread t = new Thread(() -> asyncIOCompletionTask(source), "USB async IO"); + t.setDaemon(true); + t.start(); - return; + while (asyncIoRunLoop == null) + asyncIoReady.awaitUninterruptibly(); + + return; + + } else { + // special case: run loop is not ready yet but background process is already starting + while (asyncIoRunLoop == null) + asyncIoReady.awaitUninterruptibly(); + } } CoreFoundation.CFRunLoopAddSource(asyncIoRunLoop, source, IOKit.kCFRunLoopDefaultMode$get()); From 1c7440ab4792101b64a4808b007a5dfdbf915892 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 11 Feb 2023 16:12:34 +0100 Subject: [PATCH 191/433] Reuse function descriptor (macOS) --- .../src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 82be030b..49599b6d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -433,6 +433,7 @@ public byte[] transferIn(int endpointNumber, int timeout) { } static final MethodHandle asyncIOCompletedMH; + static final FunctionDescriptor completionHandlerFuncDesc = FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT, ADDRESS); static { try { @@ -463,8 +464,7 @@ synchronized MemorySegment createCompletionHandler(USBDirection direction, int e } var methodHandle = asyncIOCompletedMH.bindTo(callback); - return Linker.nativeLinker().upcallStub(methodHandle, - FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT, ADDRESS), arena.scope()); + return Linker.nativeLinker().upcallStub(methodHandle, completionHandlerFuncDesc, arena.scope()); } void submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, MemorySegment completionHandler) { From b0e9f3604ea72c6768ffb8c2679c4e2dec38c64b Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 14 Feb 2023 20:25:57 +0100 Subject: [PATCH 192/433] Improved error handling for input stream (macOS) --- .../usb/macos/MacosEndpointInputStream.java | 111 ++++++++++-------- .../codecrete/usb/macos/MacosUSBDevice.java | 90 +++++++------- .../codecrete/usb/macos/TransferTimeout.java | 8 +- 3 files changed, 116 insertions(+), 93 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java index 35349d43..f35e4c03 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java @@ -8,6 +8,7 @@ package net.codecrete.usb.macos; import net.codecrete.usb.USBDirection; +import net.codecrete.usb.USBException; import java.io.IOException; import java.io.InputStream; @@ -35,7 +36,7 @@ */ public class MacosEndpointInputStream extends InputStream { - private static final int MAX_OUTSTANDING_REQUESTS = 4; + private static final int MAX_OUTSTANDING_REQUESTS = 8; private MacosUSBDevice device; private final int endpointNumber; @@ -46,7 +47,7 @@ public class MacosEndpointInputStream extends InputStream { // Queue of completed requests private final ArrayBlockingQueue completedRequestQueue; // Number of outstanding requests (includes requests pending with the - // operation system and requests in the completed queue) + // operating system and requests in the completed queue) private int numOutstandingRequests; // Request and buffer being currently read from private TransferRequest currentRequest; @@ -63,25 +64,58 @@ public class MacosEndpointInputStream extends InputStream { this.device = device; this.endpointNumber = endpointNumber; - bufferSize = device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); + bufferSize = 4 * device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); completedRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); - arena = Arena.openShared(); // create all requests and submit all except one - for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { - final var request = new TransferRequest(); - request.buffer = arena.allocate(bufferSize, 8); - request.completionHandler = device.createCompletionHandler(USBDirection.IN, endpointNumber, arena, - (result, size) -> onCompletion(request, result, size)); - - if (i == 0) { - currentRequest = request; - } else { - submitRequest(request); + arena = Arena.openShared(); + try { + for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { + final var request = new TransferRequest(); + request.buffer = arena.allocate(bufferSize, 8); + request.completionHandler = device.createCompletionHandler(USBDirection.IN, endpointNumber, arena, (result, size) -> onCompletion(request, result, size)); + + if (i == 0) { + currentRequest = request; + } else { + submitRequest(request); + } } + } catch (Throwable t) { + collectOutstandingRequests(); + throw t; } } + @SuppressWarnings("RedundantThrows") + @Override + public void close() throws IOException { + if (device == null) + return; // already closed + + // abort all transfers on endpoint + try { + device.abortTransfer(USBDirection.IN, endpointNumber); + } catch (USBException e) { + // If aborting the transfer is not possible, the device has + // likely been closed or unplugged. So all outstanding + // requests will terminate anyway. + } + device = null; + + collectOutstandingRequests(); + } + + private void collectOutstandingRequests() { + // wait until completion handlers have been called + while (numOutstandingRequests > 0) + waitForRequestCompletion(); + + completedRequestQueue.clear(); + currentRequest = null; + arena.close(); + } + @Override public int read() throws IOException { if (isClosed()) @@ -90,9 +124,6 @@ public int read() throws IOException { if (available() == 0) receiveMoreData(); - if (isClosed()) - return -1; - int b = currentRequest.buffer.get(JAVA_BYTE, readOffset) & 0xff; readOffset += 1; return b; @@ -106,15 +137,12 @@ public int read(byte[] b, int off, int len) throws IOException { if (available() == 0) receiveMoreData(); - if (isClosed()) - return -1; - // copy data to receiving buffer int n = Math.min(len, currentRequest.resultSize - readOffset); MemorySegment.copy(currentRequest.buffer, readOffset, MemorySegment.ofArray(b), off, n); readOffset += n; - // TODO: poll for further completed requests if 'n' is les than 'len' + // TODO: poll for further completed requests if 'n' is less than 'len' return n; } @@ -129,36 +157,25 @@ private boolean isClosed() { return device == null; } - @SuppressWarnings("RedundantThrows") - @Override - public void close() throws IOException { - // abort all transfers on endpoint - device.abortTransfer(USBDirection.IN, endpointNumber); - device = null; - - // wait until completion handlers have been called - while (numOutstandingRequests > 0) - waitForRequestCompletion(); + private void receiveMoreData() throws IOException { + try { + // loop until non-ZLP has been received + do { + submitRequest(currentRequest); - completedRequestQueue.clear(); - currentRequest = null; - arena.close(); - } + currentRequest = waitForRequestCompletion(); + readOffset = 0; - private void receiveMoreData() throws IOException { - // loop until non-ZLP has been received - do { - submitRequest(currentRequest); + // check for error + if (currentRequest.result != 0) + throwException(currentRequest.result, "error reading from USB endpoint"); - currentRequest = waitForRequestCompletion(); - readOffset = 0; + } while (currentRequest.resultSize == 0); - // check for error - if (currentRequest.result != 0) { - close(); - throwException(currentRequest.result, "error reading from USB endpoint"); - } - } while (currentRequest.resultSize == 0); + } catch (Throwable t) { + close(); + throw t; + } } void submitRequest(TransferRequest request) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 49599b6d..e4f225ae 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -60,7 +60,7 @@ public boolean isOpen() { } @Override - public void open() { + public synchronized void open() { if (isOpen()) throwException("the device is already open"); @@ -80,7 +80,7 @@ public void open() { } @Override - public void close() { + public synchronized void close() { if (!isOpen()) return; @@ -95,7 +95,7 @@ public void close() { IoKitUSB.USBDeviceClose(device); } - void closeFully() { + synchronized void closeFully() { close(); IoKitUSB.Release(device); device = null; @@ -168,7 +168,7 @@ private InterfaceInfo findInterface(int interfaceNumber) { throw new AssertionError("not reached"); } - public void claimInterface(int interfaceNumber) { + public synchronized void claimInterface(int interfaceNumber) { checkIsOpen(); try (var cleanup = new ScopeCleanup()) { @@ -188,7 +188,7 @@ public void claimInterface(int interfaceNumber) { updateEndpointList(); } - public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { + public synchronized void selectAlternateSetting(int interfaceNumber, int alternateNumber) { // check interface var intf = getInterface(interfaceNumber); if (intf == null) @@ -212,7 +212,7 @@ public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { updateEndpointList(); } - public void releaseInterface(int interfaceNumber) { + public synchronized void releaseInterface(int interfaceNumber) { checkIsOpen(); var interfaceInfoOptional = @@ -284,7 +284,7 @@ private void updateEndpointList() { } } - private EndpointInfo getEndpointInfo(int endpointNumber, USBDirection direction, + private synchronized EndpointInfo getEndpointInfo(int endpointNumber, USBDirection direction, USBTransferType transferType1, USBTransferType transferType2) { if (endpoints != null) { byte endpointAddress = (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)); @@ -301,7 +301,7 @@ private EndpointInfo getEndpointInfo(int endpointNumber, USBDirection direction, transferTypeDesc = String.format("%s or %s", transferType1.name(), transferType2.name()); throwException( - "Endpoint number %d does not exist, is not part of a claimed interface or is not valid for %s transfer in %s direction", + "Endpoint number %d does not exist, is not part of a claimed interface or is not valid for %s transfer in %s direction", endpointNumber, transferTypeDesc, direction.name()); throw new AssertionError("not reached"); } @@ -322,13 +322,17 @@ private static MemorySegment createDeviceRequest(Arena arena, USBDirection direc @Override public byte[] controlTransferIn(USBControlTransfer setup, int length) { - checkIsOpen(); + MemorySegment dev; + synchronized (this) { + checkIsOpen(); + dev = device; + } try (var arena = Arena.openConfined()) { var data = arena.allocate(length); var deviceRequest = createDeviceRequest(arena, USBDirection.IN, setup, data); - int ret = IoKitUSB.DeviceRequest(device, deviceRequest); + int ret = IoKitUSB.DeviceRequest(dev, deviceRequest); if (ret != 0) throwException(ret, "Control IN transfer failed"); @@ -339,7 +343,11 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { @Override public void controlTransferOut(USBControlTransfer setup, byte[] data) { - checkIsOpen(); + MemorySegment dev; + synchronized (this) { + checkIsOpen(); + dev = device; + } try (var arena = Arena.openConfined()) { int dataLength = data != null ? data.length : 0; @@ -348,7 +356,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { dataSegment.copyFrom(MemorySegment.ofArray(data)); var deviceRequest = createDeviceRequest(arena, USBDirection.OUT, setup, dataSegment); - int ret = IoKitUSB.DeviceRequest(device, deviceRequest); + int ret = IoKitUSB.DeviceRequest(dev, deviceRequest); if (ret != 0) throwException(ret, "Control OUT transfer failed"); } @@ -357,8 +365,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { @Override public void transferOut(int endpointNumber, byte[] data, int timeout) { - var endpointInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, - USBTransferType.BULK, USBTransferType.INTERRUPT); + EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); try (var arena = Arena.openConfined()) { var nativeData = arena.allocateArray(JAVA_BYTE, data.length); @@ -367,12 +374,12 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { int ret; if (timeout <= 0) { // transfer without timeout - ret = IoKitUSB.WritePipe(endpointInfo.iokitInterface(), endpointInfo.pipeIndex, nativeData, data.length); + ret = IoKitUSB.WritePipe(epInfo.iokitInterface(), epInfo.pipeIndex(), nativeData, data.length); - } else if (endpointInfo.transferType == USBTransferType.BULK) { + } else if (epInfo.transferType() == USBTransferType.BULK) { // bulk transfer with timeout - ret = IoKitUSB.WritePipeTO(endpointInfo.iokitInterface(), endpointInfo.pipeIndex, nativeData, + ret = IoKitUSB.WritePipeTO(epInfo.iokitInterface(), epInfo.pipeIndex(), nativeData, data.length, timeout, timeout); if (ret == IOKit.kIOUSBTransactionTimeout()) throw new USBTimeoutException("Transfer out aborted due to timeout"); @@ -380,8 +387,8 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { } else { // interrupt transfer with timeout - var transferTimeout = new TransferTimeout(endpointInfo, timeout); - ret = IoKitUSB.WritePipe(endpointInfo.iokitInterface(), endpointInfo.pipeIndex, nativeData, data.length); + var transferTimeout = new TransferTimeout(epInfo, timeout); + ret = IoKitUSB.WritePipe(epInfo.iokitInterface(), epInfo.pipeIndex(), nativeData, data.length); if (ret == IOKit.kIOReturnAborted()) throw new USBTimeoutException("Transfer out aborted due to timeout"); transferTimeout.markCompleted(); @@ -395,22 +402,21 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { @Override public byte[] transferIn(int endpointNumber, int timeout) { - var endpoint = getEndpointInfo(endpointNumber, USBDirection.IN, - USBTransferType.BULK, USBTransferType.INTERRUPT); + EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); try (var arena = Arena.openConfined()) { - var nativeData = arena.allocateArray(JAVA_BYTE, endpoint.packetSize()); - var sizeHolder = arena.allocate(JAVA_INT, endpoint.packetSize()); + var nativeData = arena.allocateArray(JAVA_BYTE, epInfo.packetSize()); + var sizeHolder = arena.allocate(JAVA_INT, epInfo.packetSize()); int ret; if (timeout <= 0) { // transfer without timeout - ret = IoKitUSB.ReadPipe(endpoint.iokitInterface(), endpoint.pipeIndex, nativeData, sizeHolder); + ret = IoKitUSB.ReadPipe(epInfo.iokitInterface(), epInfo.pipeIndex(), nativeData, sizeHolder); - } else if (endpoint.transferType == USBTransferType.BULK) { + } else if (epInfo.transferType() == USBTransferType.BULK) { // bulk transfer with timeout - ret = IoKitUSB.ReadPipeTO(endpoint.iokitInterface(), endpoint.pipeIndex, nativeData, + ret = IoKitUSB.ReadPipeTO(epInfo.iokitInterface(), epInfo.pipeIndex(), nativeData, sizeHolder, timeout, timeout); if (ret == IOKit.kIOUSBTransactionTimeout()) throw new USBTimeoutException("Transfer in aborted due to timeout"); @@ -418,8 +424,8 @@ public byte[] transferIn(int endpointNumber, int timeout) { } else { // interrupt transfer with timeout - var transferTimeout = new TransferTimeout(endpoint, timeout); - ret = IoKitUSB.ReadPipe(endpoint.iokitInterface(), endpoint.pipeIndex, nativeData, sizeHolder); + var transferTimeout = new TransferTimeout(epInfo, timeout); + ret = IoKitUSB.ReadPipe(epInfo.iokitInterface(), epInfo.pipeIndex(), nativeData, sizeHolder); if (ret == IOKit.kIOReturnAborted()) throw new USBTimeoutException("Transfer in aborted due to timeout"); transferTimeout.markCompleted(); @@ -469,41 +475,37 @@ synchronized MemorySegment createCompletionHandler(USBDirection direction, int e void submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, MemorySegment completionHandler) { - var endpoint = getEndpointInfo(endpointNumber, USBDirection.IN, - USBTransferType.BULK, null); + EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, null); // submit request - int ret = IoKitUSB.ReadPipeAsync(endpoint.iokitInterface(), endpoint.pipeIndex, buffer, bufferSize, completionHandler, MemorySegment.NULL); + int ret = IoKitUSB.ReadPipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), buffer, bufferSize, completionHandler, MemorySegment.NULL); if (ret != 0) throwException(ret, "failed to submit async transfer"); } void submitTransferOut(int endpointNumber, MemorySegment data, int dataSize, MemorySegment completionHandler) { - var endpoint = getEndpointInfo(endpointNumber, USBDirection.OUT, - USBTransferType.BULK, null); + EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, null); // submit request - int ret = IoKitUSB.WritePipeAsync(endpoint.iokitInterface(), endpoint.pipeIndex, data, dataSize, completionHandler, MemorySegment.NULL); + int ret = IoKitUSB.WritePipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), data, dataSize, completionHandler, MemorySegment.NULL); if (ret != 0) throwException(ret, "failed to submit async transfer"); } public void abortTransfer(USBDirection direction, int endpointNumber) { - var endpointInfo = getEndpointInfo(endpointNumber, direction, - USBTransferType.BULK, USBTransferType.INTERRUPT); + EndpointInfo epInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); - int ret = IoKitUSB.AbortPipe(endpointInfo.iokitInterface(), endpointInfo.pipeIndex()); + int ret = IoKitUSB.AbortPipe(epInfo.iokitInterface(), epInfo.pipeIndex()); if (ret != 0) throwException(ret, "Aborting transfer failed"); } - @Override + @Override public void clearHalt(USBDirection direction, int endpointNumber) { - var endpointInfo = getEndpointInfo(endpointNumber, direction, - USBTransferType.BULK, USBTransferType.INTERRUPT); + EndpointInfo epInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); - int ret = IoKitUSB.ClearPipeStallBothEnds(endpointInfo.iokitInterface(), endpointInfo.pipeIndex); + int ret = IoKitUSB.ClearPipeStallBothEnds(epInfo.iokitInterface(), epInfo.pipeIndex()); if (ret != 0) throwException(ret, "Clearing halt condition failed"); } @@ -511,14 +513,16 @@ public void clearHalt(USBDirection direction, int endpointNumber) { @Override public InputStream openInputStream(int endpointNumber) { // check that endpoint number is valid - getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, null); + getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, null); + return new MacosEndpointInputStream(this, endpointNumber); } @Override public OutputStream openOutputStream(int endpointNumber) { // check that endpoint number is valid - getEndpoint(endpointNumber, USBDirection.OUT, USBTransferType.BULK, null); + getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, null); + return new MacosEndpointOutputStream(this, endpointNumber); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java index 9abe7cc2..51bb0213 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java @@ -38,9 +38,11 @@ class TransferTimeout { private synchronized void abort() { if (completed) return; - int ret = IoKitUSB.AbortPipe(endpointInfo.iokitInterface(), endpointInfo.pipeIndex()); - if (ret != 0) - throwException(ret, "Failed to abort USB transfer after timeout"); + if (endpointInfo.iokitInterface() != null) { + int ret = IoKitUSB.AbortPipe(endpointInfo.iokitInterface(), endpointInfo.pipeIndex()); + if (ret != 0) + throwException(ret, "Failed to abort USB transfer after timeout"); + } } /** From bfcd903b618da08976cad47621728c6007e0ab4a Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 14 Feb 2023 20:26:25 +0100 Subject: [PATCH 193/433] Transfer rate test with logic analyzer --- .../codecrete/usb/sample/LogicAnalyzer.java | 359 ++++++++++++++++++ .../test/resources/fx2lafw-saleae-logic.fw | Bin 0 -> 8120 bytes 2 files changed, 359 insertions(+) create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java create mode 100644 java-does-usb/src/test/resources/fx2lafw-saleae-logic.fw diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java b/java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java new file mode 100644 index 00000000..5c3dae18 --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java @@ -0,0 +1,359 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Firmware for logic analyzer is from Sigrok project +// and licensed under GNU GPL (version 2, or later). +// + +package net.codecrete.usb.sample; + +import net.codecrete.usb.*; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Sample program for sampling data with a logic analyzer. + *

+ * This sample assumes that a Saleae 8 clone with the VID 0x0925 and PID + * 0x3881 is connected. + *

+ *

+ * The USB communication of Saleae 8 clones (and any other logic analyzer + * based on a similar Cypress chip) is very sensitive as the chip only has + * a tiny internal buffer and – for the maximum 24 MHz sample rate – operates + * rather close to the practical limit of USB 2.0 high-speed. If the USB bus + * has other traffic from other devices or if the JVM takes a GC time-out, + * the internal buffer overruns and the logic analyzer stops data acquisition. + *

+ *

+ * The firmware for the Cypress chips needs to be uploaded once after the + * device has been connected. After the firmware upload, the device disconnect + * and reconnect after about 2 to 3 seconds. Vendor and product ID do not + * change but the manufacturer name and serial number do. + *

+ */ +public class LogicAnalyzer implements Closeable { + + /// USB vendor ID + final static int VID = 0x0925; + /// USB product ID + final static int PID = 0x3881; + + // bulk endpoint number + final static int EP = 2; + + /// Effective sample rate (in Hz) + private int effSampleRate; + /// Sample period (in clock ticks) + private int period; + /// Sample duration (in ms) + private int duration; + /// Flag to use 48 MHz clock (instead of 30 MHz) + private boolean use48Mhz; + /// Flag that buffer overrun has been detected + private volatile boolean bufferOverrunDetected; + /// Flag that acquisition should/has stopped + private volatile boolean stopped; + /// Filename for saving sample data + private String filename; + /// Variable is updated while new data is received + private volatile long activityValue; + /// Indicates a dry run (to suppress output) + private boolean isDryRun; + + public static void main(String[] args) { + try (var logicAnalyzer = new LogicAnalyzer()) { + logicAnalyzer.sampleData(24000000, 5000, "sample.bin"); + } + } + + private USBDevice device; + + LogicAnalyzer() { + device = USB.getDevice(new USBDeviceFilter(VID, PID)); + if (device == null) + throw new IllegalStateException("no logic analyzer connected"); + + checkFirmware(); + + device.open(); + device.claimInterface(0); + + dryRun(12000000, 100); + dryRun(10000000, 200); + } + + @Override + public void close() { + device.close(); + } + + /** + * Sample data and save it to the file + * @param sampleRate sample rate (in Hz) + * @param duration duration (in ms) + * @param filename filename to save to, or {@code null} to not save it + */ + void sampleData(int sampleRate, int duration, String filename) { + if (sampleRate < 20000 || sampleRate > 24000000) { + System.err.println("Sample rate outside the supported range of 10kHz to 24Mhz"); + return; + } + + stopped = false; + bufferOverrunDetected = false; + this.filename = filename; + prepareSampling(sampleRate, duration); + var acquirer = CompletableFuture.runAsync(this::saveSamples); + sleep(20); // give thread time to start + startAcquisition(); + var watchdog = CompletableFuture.runAsync(this::detectBufferOverrun); + CompletableFuture.allOf(acquirer, watchdog).join(); + } + + void dryRun(int sampleRate, int duration) { + isDryRun = true; + sampleData(sampleRate, duration, null); + isDryRun = false; + } + + void prepareSampling(int sampleRate, int duration) { + this.duration = duration; + + // calculate the optimal sample rate and if to use the 48 or 30 MHz clock + int ticks48Mhz = (48000000 + sampleRate / 2) / sampleRate; + int ticks30Mhz = (30000000 + sampleRate / 2) / sampleRate; + double err48Mhz = Math.abs(48000000.0 / ticks48Mhz - sampleRate); + double err30Mhz = Math.abs(30000000.0 / ticks30Mhz - sampleRate); + + if (ticks48Mhz <= 0x0600 && err48Mhz <= err30Mhz) { + use48Mhz = true; + period = ticks48Mhz; + effSampleRate = 48000000 / period; + } else { + use48Mhz = false; + period = ticks30Mhz; + effSampleRate = 30000000 / period; + } + } + + /** + * Start acquisition with the specified sample rate + */ + void startAcquisition() { + // Command structure (3 bytes) + // Bit 5: 0 - 8 bit samples, 1 - 16 bit samples + // Bit 6: 0 - 30 MHz clock, 1 - 48 MHz clock + // Byte 0: flags (not needed here) + // Byte 1-2: clock ticks (-1) between two samples (16 bit, big endian) + + int ticks = period - 1; + byte flags = use48Mhz ? (byte)(1 << 6) : 0; + + var cmd = new byte[3]; + cmd[0] = flags; + cmd[1] = (byte)(ticks >> 8); + cmd[2] = (byte)(ticks & 0xff); + + // send the start command + final int commandCodeStart = 0xb1; + device.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.DEVICE, commandCodeStart, 0, 0), cmd); + } + + void saveSamples() { + + // retrieve the sample data from the bulk endpoint + int expectedSize = (int)(((long)duration * effSampleRate + 500) / 1000); + + byte[] sampleData = new byte[expectedSize]; + + int size = 0; + try (var is = device.openInputStream(EP)) { + + while (size < expectedSize) { + int n = is.read(sampleData, size, sampleData.length - size); + if (n <= 0) + break; + size += n; + activityValue = size; + } + + } catch (USBException e) { + if (!stopped && !bufferOverrunDetected) + throw e; + + } catch (IOException e) { + System.err.println("Retrieving samples failed"); + e.printStackTrace(System.err); + return; + } + + if (bufferOverrunDetected) { + System.err.println("Buffer overflow, acquisition has stopped"); + } else if (!stopped) { + stopAcquisition(); + } else { + stopped = true; + } + + if (!isDryRun) + System.out.printf("%,d samples retrieved with %,d sample/s%n", size, effSampleRate); + + if (filename != null) { + try { + Files.write(Path.of(filename), sampleData); + } catch (IOException e) { + System.err.printf("Saving samples to %s failed%n", filename); + e.printStackTrace(System.err); + } + } + } + + void stopAcquisition() { + // stop the acquisition by halting the bulk endpoint and clearing the halt + stopped = true; + device.clearHalt(USBDirection.IN, EP); + } + + void detectBufferOverrun() { + // if the 'activityValue' hasn't changed within 20ms, the logic analyzer + // has stopped sending data (likely due to a buffer overrun) + long lastValue = 0; + while (true) { + sleep(20); + + if (stopped) + break; + + if (lastValue == activityValue) { + bufferOverrunDetected = true; + stopAcquisition(); + return; + } + + lastValue = activityValue; + } + } + + void checkFirmware() { + if (device.manufacturer() != null) { + System.out.println("Device ready"); + return; + } + + System.out.println("Uploading firmware..."); + + byte[] firmware; + // load open-source firmware from Sigrok project (see http://sigrok.org/wiki/Fx2lafw) + try (var is = getClass().getClassLoader().getResourceAsStream("fx2lafw-saleae-logic.fw")) { + firmware = is.readAllBytes(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + device.open(); + + byte[] cmd = new byte[] { 1 }; + device.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.DEVICE, 0xa0, 0xe600, 0x0000), cmd); + + final int len = firmware.length; + int offset = 0; + while (offset < len) { + int n = Math.min(len - offset, 0x1000); + byte[] chunk = Arrays.copyOfRange(firmware, offset, offset + n); + device.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.DEVICE, 0xa0, offset, 0x0000), chunk); + offset += n; + } + + cmd = new byte[] { 0 }; + device.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.DEVICE, 0xa0, 0xe600, 0x0000), cmd); + + device.close(); + DeviceMonitor.instance().awaitDevice(false); + + System.out.println("Waiting for device to reconnect..."); + + DeviceMonitor.instance().awaitDevice(true); + sleep(200); + + device = USB.getDevice(new USBDeviceFilter(VID, PID)); + if (device == null) + throw new IllegalStateException("no logic analyzer connected"); + if (device.manufacturer() == null) + throw new IllegalStateException("firmware upload failed"); + + System.out.println("Device is ready"); + } + + void sleep(long milliseconds) { + while (true) { + try { + Thread.sleep(milliseconds); + return; + } catch (InterruptedException e) { + // ignore and try again + } + } + } + + + static class DeviceMonitor { + + private static DeviceMonitor singleInstance; + + private final Lock deviceLock = new ReentrantLock(); + private final Condition deviceConnected = deviceLock.newCondition(); + private boolean isDeviceConnected; + + static synchronized DeviceMonitor instance() { + if (singleInstance == null) { + singleInstance = new DeviceMonitor(); + singleInstance.start(); + } + return singleInstance; + } + + private DeviceMonitor() { } + + private void start() { + USB.setOnDeviceConnected((device) -> onDeviceConnected(device, true)); + USB.setOnDeviceDisconnected((device) -> onDeviceConnected(device, false)); + isDeviceConnected = USB.getDevice(new USBDeviceFilter(VID, PID)) != null; + } + + private void onDeviceConnected(USBDevice device, boolean connected) { + if (device.vendorId() == VID && device.productId() == device.productId()) { + try { + deviceLock.lock(); + isDeviceConnected = connected; + deviceConnected.signalAll(); + + } finally { + deviceLock.unlock(); + } + } + } + + void awaitDevice(boolean connected) { + try { + deviceLock.lock(); + while (isDeviceConnected != connected) + deviceConnected.awaitUninterruptibly(); + + } finally { + deviceLock.unlock(); + } + } + } +} diff --git a/java-does-usb/src/test/resources/fx2lafw-saleae-logic.fw b/java-does-usb/src/test/resources/fx2lafw-saleae-logic.fw new file mode 100644 index 0000000000000000000000000000000000000000..96167c13ac56c7ea87e61f9e4e9d40febb07c43b GIT binary patch literal 8120 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 V#}fuP1OR$H#J)EGY60#?{|41rVGjTR literal 0 HcmV?d00001 From 09508a4d48c15dabfc18d548beba4ba034a8f587 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 17 Feb 2023 19:37:03 +0100 Subject: [PATCH 194/433] Use asynchronous requests under the hood (macOS) --- .../net/codecrete/usb/macos/IoKitUSB.java | 45 +- .../usb/macos/MacosEndpointInputStream.java | 10 +- .../usb/macos/MacosEndpointOutputStream.java | 125 ++++-- .../codecrete/usb/macos/MacosUSBDevice.java | 397 +++++++++++++----- .../codecrete/usb/macos/TransferTimeout.java | 69 --- .../java/net/codecrete/usb/SpeedTest.java | 2 +- 6 files changed, 409 insertions(+), 239 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index c8557ec1..f95c246b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -42,6 +42,16 @@ public static int Release(MemorySegment self) { return IOUSBDeviceInterface100.Release(getVtable(self), SegmentScope.global()).apply(self); } + // IOReturn (* CreateDeviceAsyncEventSource)(void* self, CFRunLoopSourceRef* source); + public static int CreateDeviceAsyncEventSource(MemorySegment self, MemorySegment source) { + return IOUSBDeviceInterface100.CreateDeviceAsyncEventSource(getVtable(self), SegmentScope.global()).apply(self, source); + } + + // CFRunLoopSourceRef (* GetDeviceAsyncEventSource)(void* self); + public static MemorySegment GetDeviceAsyncEventSource(MemorySegment self) { + return IOUSBDeviceInterface100.GetDeviceAsyncEventSource(getVtable(self), SegmentScope.global()).apply(self); + } + // IOReturn (*USBDeviceOpen)(void *self); public static int USBDeviceOpen(MemorySegment self) { return IOUSBDeviceInterface100.USBDeviceOpen(getVtable(self), SegmentScope.global()).apply(self); @@ -67,9 +77,9 @@ public static int CreateInterfaceIterator(MemorySegment self, MemorySegment req, return IOUSBDeviceInterface100.CreateInterfaceIterator(getVtable(self), SegmentScope.global()).apply(self, req, iter); } - // IOReturn (*DeviceRequest)(void *self, IOUSBDevRequest *req); - public static int DeviceRequest(MemorySegment self, MemorySegment deviceRequest) { - return IOUSBDeviceInterface100.DeviceRequest(getVtable(self), SegmentScope.global()).apply(self, deviceRequest); + // IOReturn (* DeviceRequestAsync)(void* self, IOUSBDevRequest* req, IOAsyncCallback1 callback, void* refCon); + public static int DeviceRequestAsync(MemorySegment self, MemorySegment deviceRequest, MemorySegment callback, MemorySegment refCon) { + return IOUSBDeviceInterface100.DeviceRequestAsync(getVtable(self), SegmentScope.global()).apply(self, deviceRequest, callback, refCon); } // IOReturn (*USBInterfaceOpen)(void *self);; @@ -101,32 +111,16 @@ public static int GetPipeProperties(MemorySegment self, byte pipeRef, MemorySegm directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); } - // IOReturn (*ReadPipe)(void *self, UInt8 pipeRef, void *buf, UInt32 *size); - public static int ReadPipe(MemorySegment self, byte pipeRef, MemorySegment buf, MemorySegment sizeHolder) { - return IOUSBInterfaceInterface190.ReadPipe(getVtable(self), SegmentScope.global()) - .apply(self, pipeRef, buf, sizeHolder); - } - - // IOReturn (* ReadPipeTO)(void* self, UInt8 pipeRef, void* buf, UInt32* size, UInt32 noDataTimeout, UInt32 completionTimeout); - public static int ReadPipeTO(MemorySegment self, byte pipeRef, MemorySegment buf, MemorySegment sizeHolder, int noDataTimeout, int completionTimeout) { - return IOUSBInterfaceInterface190.ReadPipeTO(getVtable(self), SegmentScope.global()) - .apply(self, pipeRef, buf, sizeHolder, noDataTimeout, completionTimeout); - } - // IOReturn (*ReadPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, void *refcon); public static int ReadPipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, MemorySegment callback, MemorySegment refcon) { return IOUSBInterfaceInterface190.ReadPipeAsync(getVtable(self), SegmentScope.global()) .apply(self, pipeRef, buf, size, callback, refcon); } - // IOReturn (*WritePipe)(void *self, UInt8 pipeRef, void *buf, UInt32 size); - public static int WritePipe(MemorySegment self, byte pipeRef, MemorySegment buf, int size) { - return IOUSBInterfaceInterface190.WritePipe(getVtable(self), SegmentScope.global()).apply(self, pipeRef, buf, size); - } - - // IOReturn (* WritePipeTO)(void* self, UInt8 pipeRef, void* buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout); - public static int WritePipeTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, int noDataTimeout, int completionTimeout) { - return IOUSBInterfaceInterface190.WritePipeTO(getVtable(self), SegmentScope.global()).apply(self, pipeRef, buf, size, noDataTimeout, completionTimeout); + // IOReturn (*ReadPipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void *refcon); + public static int ReadPipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, int noDataTimeout, int completionTimeout, MemorySegment callback, MemorySegment refcon) { + return IOUSBInterfaceInterface190.ReadPipeAsyncTO(getVtable(self), SegmentScope.global()) + .apply(self, pipeRef, buf, size, noDataTimeout, completionTimeout, callback, refcon); } // IOReturn (*WritePipeAsync)(vovoid *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, void *refcon); @@ -134,6 +128,11 @@ public static int WritePipeAsync(MemorySegment self, byte pipeRef, MemorySegment return IOUSBInterfaceInterface190.WritePipeAsync(getVtable(self), SegmentScope.global()).apply(self, pipeRef, buf, size, callback, refcon); } + // IOReturn (*WritePipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void *refcon); + public static int WritePipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, int noDataTimeout, int completionTimeout, MemorySegment callback, MemorySegment refcon) { + return IOUSBInterfaceInterface190.WritePipeAsyncTO(getVtable(self), SegmentScope.global()).apply(self, pipeRef, buf, size, noDataTimeout, completionTimeout, callback, refcon); + } + // IOReturn (* AbortPipe)(void* self, UInt8 pipeRef); public static int AbortPipe(MemorySegment self, byte pipeRef) { return IOUSBInterfaceInterface190.AbortPipe(getVtable(self), SegmentScope.global()).apply(self, pipeRef); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java index f35e4c03..b9395b60 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java @@ -73,7 +73,7 @@ public class MacosEndpointInputStream extends InputStream { for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { final var request = new TransferRequest(); request.buffer = arena.allocate(bufferSize, 8); - request.completionHandler = device.createCompletionHandler(USBDirection.IN, endpointNumber, arena, (result, size) -> onCompletion(request, result, size)); + request.completionHandler = (result, size) -> onCompletion(request, result, size); if (i == 0) { currentRequest = request; @@ -90,8 +90,8 @@ public class MacosEndpointInputStream extends InputStream { @SuppressWarnings("RedundantThrows") @Override public void close() throws IOException { - if (device == null) - return; // already closed + if (isClosed()) + return; // abort all transfers on endpoint try { @@ -179,7 +179,7 @@ private void receiveMoreData() throws IOException { } void submitRequest(TransferRequest request) { - device.submitTransferIn(endpointNumber, request.buffer, bufferSize, request.completionHandler); + device.submitTransferIn(endpointNumber, request.buffer, bufferSize, 0, request.completionHandler); numOutstandingRequests += 1; } @@ -206,6 +206,6 @@ private static class TransferRequest { MemorySegment buffer; int result; int resultSize; - MemorySegment completionHandler; + MacosUSBDevice.AsyncIOCompletion completionHandler; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java index c7ef7093..fe9f62c8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java @@ -52,6 +52,8 @@ public class MacosEndpointOutputStream extends OutputStream { private boolean needsZlp; private TransferRequest currentRequest; private int writeOffset; + private int numOutstandingRequests; + private boolean hasError; /** @@ -72,8 +74,7 @@ public class MacosEndpointOutputStream extends OutputStream { for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { final var request = new TransferRequest(); request.buffer = arena.allocate(bufferSize, 8); - request.completionHandler = device.createCompletionHandler(USBDirection.OUT, endpointNumber, arena, - (result, size) -> onCompletion(request, result)); + request.completionHandler = (result, size) -> onCompletion(request, result); if (i == 0) { currentRequest = request; @@ -83,6 +84,22 @@ public class MacosEndpointOutputStream extends OutputStream { } } + @Override + public void close() throws IOException { + if (isClosed()) + return; + + if (!hasError) + flush(); + else + waitForOutstandingRequests(); + + device = null; + availableRequestQueue.clear(); + currentRequest = null; + arena.close(); + } + @Override public void write(int b) throws IOException { if (isClosed()) @@ -122,50 +139,86 @@ public void flush() throws IOException { if (needsZlp) submitTransfer(0); - // Wait until all buffers have been transmitted by removing them from the - // queue and reinserting them. One request is the current request. - // So the queue only contains MAX_OUTSTANDING_REQUESTS - 1 requests. - var requests = new TransferRequest[MAX_OUTSTANDING_REQUESTS - 1]; - for (int i = 0; i < MAX_OUTSTANDING_REQUESTS - 1; i++) - requests[i] = waitForAvailableRequest(); - availableRequestQueue.addAll(Arrays.asList(requests).subList(1, MAX_OUTSTANDING_REQUESTS - 1)); - } - - @Override - public void close() throws IOException { - flush(); - - device = null; - availableRequestQueue.clear(); - currentRequest = null; - arena.close(); + waitForOutstandingRequests(); } private boolean isClosed() { return device == null; } - private void submitTransfer(int size) { - device.submitTransferOut(endpointNumber, currentRequest.buffer, size, currentRequest.completionHandler); - needsZlp = size == packetSize; + /** + * Submits a request for transfer and set a new request + * as the current one, possibly waiting until it is ready. + *

+ * Throws an exception if the request to be reused has completed with an error on the + * previous operation. The exception is suppressed if {@code hasError} flag is set. + *

+ * + * @param size size of data to be transmitted + */ + private void submitTransfer(int size) throws IOException { + try { + device.submitTransferOut(endpointNumber, currentRequest.buffer, size, 0, currentRequest.completionHandler); - writeOffset = 0; - currentRequest = waitForAvailableRequest(); + synchronized (this) { + numOutstandingRequests += 1; + } + + needsZlp = size == packetSize; + writeOffset = 0; + currentRequest = waitForAvailableRequest(); + + } catch (Throwable t) { + hasError = true; + close(); + throw t; + } } - private void onCompletion(TransferRequest request, int result) { - request.result = result; - availableRequestQueue.add(request); + /** + * Wait until all outstanding requests have been completed. + *

+ * Throws an exception if any of the requests has completed with an error. + * The exception is suppressed if {@code hasError} flag is set. + *

+ */ + private void waitForOutstandingRequests() { + // Wait until all buffers have been transmitted by removing them from the + // queue and reinserting them. + + int numRequests; + synchronized (this) { + numRequests = numOutstandingRequests + availableRequestQueue.size(); + } + + if (numRequests == 0) + return; + + var requests = new TransferRequest[numRequests]; + for (int i = 0; i < numRequests; i++) + requests[i] = waitForAvailableRequest(); + + // reinsert the requests + if (!hasError) + availableRequestQueue.addAll(Arrays.asList(requests)); } - TransferRequest waitForAvailableRequest() { + /** + * Wait until one of the allocated requests is available for use. + *

+ * Throws an exception if the request to be reused has completed with an error on the + * previous operation. The exception is suppressed if {@code hasError} flag is set. + *

+ * @return request ready for use + */ + private TransferRequest waitForAvailableRequest() { while (true) { try { TransferRequest request = availableRequestQueue.take(); // check for error int result = request.result; - if (result != 0) { + if (result != 0 && !hasError) { request.result = 0; throwException(result, "error writing to USB endpoint"); } @@ -178,9 +231,21 @@ TransferRequest waitForAvailableRequest() { } } + /** + * Called by the asynchronous IO completion handler. + * + * @param request the completed request + * @param result the request result code + */ + private synchronized void onCompletion(TransferRequest request, int result) { + request.result = result; + availableRequestQueue.add(request); + numOutstandingRequests -= 1; + } + private static class TransferRequest { MemorySegment buffer; int result; - MemorySegment completionHandler; + MacosUSBDevice.AsyncIOCompletion completionHandler; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index e4f225ae..5d549c02 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -21,10 +21,7 @@ import java.io.InputStream; import java.io.OutputStream; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.Linker; -import java.lang.foreign.MemorySegment; +import java.lang.foreign.*; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -36,13 +33,59 @@ import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.macos.MacosUSBException.throwException; +/** + * MacOS implementation of {@link net.codecrete.usb.USBDevice}. + *

+ * All read and write operations on endpoints are submitted through synchronized methods in order to control + * concurrency. If it wasn't controlled, the danger is that device and interface pointers are used, which have + * just been closed and thus deallocated by another thread, likely leading to crashes. + *

+ *

+ * As a consequence of the synchronized submission, blocking operations consists of submitting an + * asynchronous request and waiting for the completion. + *

+ *

+ * For the completion callback, an upcall stub is created for each device instance. The device instance is bound + * to this stub. The stub is used as the {@code callback} parameter in the native functions. For each USB + * interface, an event source is registered in the registry's asynchronous IO completion background thread. + * To map the callback to a specific request, the request provides a completion handler. It is assigned a unique + * number. The number is passed as {@code refcon} to the native call while the mapping between the number and the + * completion handler is maintained in a hash map. + *

+ */ public class MacosUSBDevice extends USBDeviceImpl { + static final MethodHandle asyncIOCompletedMH; + // Function descriptor for callback functions of type 'IOAsyncCallback1' + static final FunctionDescriptor completionHandlerFuncDesc = FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT, ADDRESS); + + static { + try { + asyncIOCompletedMH = MethodHandles.lookup().findStatic(MacosUSBDevice.class, "asyncIOCompleted", + MethodType.methodType(void.class, MacosUSBDevice.class, MemorySegment.class, int.class, MemorySegment.class)); + } catch (IllegalAccessException|NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + private final MacosUSBDeviceRegistry registry; + // Native USB device interface (IOUSBDeviceInterface**) private MemorySegment device; + // Currently selected configuration private int configurationValue; + // Details about interfaces that have been claimed private List claimedInterfaces; + // Details about endpoints of current alternate settings (for claimed interfaces) private Map endpoints; + // Last used handler ID + private int lastHandlerId; + // Completion handlers of currently outstanding asynchronous IO requests, + // indexed by assigned ID, which is passed in and out as 'refcon' + private Map completionHandlers; + /// Arena used to allocate upcall stub for event source + private Arena arena; + /// Upcall stub for IO completion callback + private MemorySegment completionUpcallStub; MacosUSBDevice(MacosUSBDeviceRegistry registry, MemorySegment device, Object id, int vendorId, int productId) { super(id, vendorId, productId); @@ -71,6 +114,8 @@ public synchronized void open() { claimedInterfaces = new ArrayList<>(); + addDeviceEventSource(); + // set configuration ret = IoKitUSB.SetConfiguration(device, (byte) configurationValue); if (ret != 0) @@ -92,6 +137,11 @@ public synchronized void close() { claimedInterfaces = null; endpoints = null; + + var source = IoKitUSB.GetDeviceAsyncEventSource(device); + if (source.address() != 0) + registry.removeEventSource(source); + IoKitUSB.USBDeviceClose(device); } @@ -183,6 +233,7 @@ public synchronized void claimInterface(int interfaceNumber) { IoKitUSB.AddRef(interfaceInfo.iokitInterface()); claimedInterfaces.add(interfaceInfo); setClaimed(interfaceNumber, true); + addInterfaceEventSource(interfaceInfo); } updateEndpointList(); @@ -322,43 +373,34 @@ private static MemorySegment createDeviceRequest(Arena arena, USBDirection direc @Override public byte[] controlTransferIn(USBControlTransfer setup, int length) { - MemorySegment dev; - synchronized (this) { - checkIsOpen(); - dev = device; - } - try (var arena = Arena.openConfined()) { var data = arena.allocate(length); var deviceRequest = createDeviceRequest(arena, USBDirection.IN, setup, data); + var request = createRequest(); - int ret = IoKitUSB.DeviceRequest(dev, deviceRequest); - if (ret != 0) - throwException(ret, "Control IN transfer failed"); + synchronized (request) { + submitControlTransfer(deviceRequest, (result, size) -> onRequestCompleted(request, result, size)); + waitForRequest(request, USBDirection.IN, 0, false); + } - int lenDone = IOUSBDevRequest.wLenDone$get(deviceRequest); - return data.asSlice(0, lenDone).toArray(JAVA_BYTE); + return data.asSlice(0, request.size).toArray(JAVA_BYTE); } } @Override public void controlTransferOut(USBControlTransfer setup, byte[] data) { - MemorySegment dev; - synchronized (this) { - checkIsOpen(); - dev = device; - } - try (var arena = Arena.openConfined()) { int dataLength = data != null ? data.length : 0; var dataSegment = arena.allocate(dataLength); if (dataLength > 0) dataSegment.copyFrom(MemorySegment.ofArray(data)); var deviceRequest = createDeviceRequest(arena, USBDirection.OUT, setup, dataSegment); + var request = createRequest(); - int ret = IoKitUSB.DeviceRequest(dev, deviceRequest); - if (ret != 0) - throwException(ret, "Control OUT transfer failed"); + synchronized (request) { + submitControlTransfer(deviceRequest, (result, size) -> onRequestCompleted(request, result, size)); + waitForRequest(request, USBDirection.OUT, 0, false); + } } } @@ -371,31 +413,19 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { var nativeData = arena.allocateArray(JAVA_BYTE, data.length); nativeData.copyFrom(MemorySegment.ofArray(data)); - int ret; - if (timeout <= 0) { - // transfer without timeout - ret = IoKitUSB.WritePipe(epInfo.iokitInterface(), epInfo.pipeIndex(), nativeData, data.length); - - } else if (epInfo.transferType() == USBTransferType.BULK) { - - // bulk transfer with timeout - ret = IoKitUSB.WritePipeTO(epInfo.iokitInterface(), epInfo.pipeIndex(), nativeData, - data.length, timeout, timeout); - if (ret == IOKit.kIOUSBTransactionTimeout()) - throw new USBTimeoutException("Transfer out aborted due to timeout"); - - } else { - - // interrupt transfer with timeout - var transferTimeout = new TransferTimeout(epInfo, timeout); - ret = IoKitUSB.WritePipe(epInfo.iokitInterface(), epInfo.pipeIndex(), nativeData, data.length); - if (ret == IOKit.kIOReturnAborted()) - throw new USBTimeoutException("Transfer out aborted due to timeout"); - transferTimeout.markCompleted(); + var request = createRequest(); + synchronized (request) { + if (timeout <= 0 || epInfo.transferType() == USBTransferType.BULK) { + // no timeout or timeout handled by operating system + submitTransferOut(endpointNumber, nativeData, data.length, timeout, (result, size) -> onRequestCompleted(request, result, size)); + waitForRequest(request, USBDirection.OUT, endpointNumber, false); + + } else { + // interrupt transfer with timeout + submitTransferOut(endpointNumber, nativeData, data.length, 0, (result, size) -> onRequestCompleted(request, result, size)); + waitForRequestOrAbort(request, timeout, USBDirection.OUT, endpointNumber); + } } - - if (ret != 0) - throwException(ret, "Sending data to endpoint %d failed", endpointNumber); } } @@ -406,91 +436,166 @@ public byte[] transferIn(int endpointNumber, int timeout) { try (var arena = Arena.openConfined()) { var nativeData = arena.allocateArray(JAVA_BYTE, epInfo.packetSize()); - var sizeHolder = arena.allocate(JAVA_INT, epInfo.packetSize()); - int ret; - if (timeout <= 0) { - // transfer without timeout - ret = IoKitUSB.ReadPipe(epInfo.iokitInterface(), epInfo.pipeIndex(), nativeData, sizeHolder); + var request = createRequest(); + synchronized (request) { + if (timeout <= 0 || epInfo.transferType() == USBTransferType.BULK) { + // no timeout or timeout handled by operating system + submitTransferIn(endpointNumber, nativeData, epInfo.packetSize(), timeout, (result, size) -> onRequestCompleted(request, result, size)); + waitForRequest(request, USBDirection.IN, endpointNumber, false); + + } else { + // interrupt transfer with timeout + submitTransferIn(endpointNumber, nativeData, epInfo.packetSize(), 0, (result, size) -> onRequestCompleted(request, result, size)); + waitForRequestOrAbort(request, timeout, USBDirection.IN, endpointNumber); + } + } - } else if (epInfo.transferType() == USBTransferType.BULK) { + return nativeData.asSlice(0, request.size).toArray(JAVA_BYTE); + } + } - // bulk transfer with timeout - ret = IoKitUSB.ReadPipeTO(epInfo.iokitInterface(), epInfo.pipeIndex(), nativeData, - sizeHolder, timeout, timeout); - if (ret == IOKit.kIOUSBTransactionTimeout()) - throw new USBTimeoutException("Transfer in aborted due to timeout"); + /** + * Submits a transfer IN request to the specified BULK or INTERRUPT endpoint. + *

+ * A timeout may only be specified for BULK endpoints. + *

+ * @param endpointNumber endpoint number + * @param buffer buffer that will receive data + * @param bufferSize buffer length (should be packet size or multiple thereof) + * @param timeout the timeout, in milliseconds, or 0 for no timeout + * @param completionHandler handler that will be called when the request completes + */ + synchronized void submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, int timeout, AsyncIOCompletion completionHandler) { - } else { + EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); - // interrupt transfer with timeout - var transferTimeout = new TransferTimeout(epInfo, timeout); - ret = IoKitUSB.ReadPipe(epInfo.iokitInterface(), epInfo.pipeIndex(), nativeData, sizeHolder); - if (ret == IOKit.kIOReturnAborted()) - throw new USBTimeoutException("Transfer in aborted due to timeout"); - transferTimeout.markCompleted(); - } - if (ret != 0) - throwException(ret, "Receiving data from endpoint %d failed", endpointNumber); + // submit request + int ret; + if (timeout <= 0) + ret = IoKitUSB.ReadPipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), buffer, bufferSize, + getCompletionUpcallStub(), saveCompletionHandler(completionHandler)); + else + ret = IoKitUSB.ReadPipeAsyncTO(epInfo.iokitInterface(), epInfo.pipeIndex(), buffer, bufferSize, timeout, + timeout, getCompletionUpcallStub(), saveCompletionHandler(completionHandler)); - int size = sizeHolder.get(JAVA_INT, 0); - return nativeData.asSlice(0, size).toArray(JAVA_BYTE); - } + if (ret != 0) + throwException(ret, "failed to submit transfer IN request"); } - static final MethodHandle asyncIOCompletedMH; - static final FunctionDescriptor completionHandlerFuncDesc = FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT, ADDRESS); + /** + * Submits a transfer OUT request to the specified BULK or INTERRUPT endpoint. + *

+ * A timeout may only be specified for BULK endpoints. + *

+ * @param endpointNumber endpoint number + * @param data buffer with data to be transmitted + * @param dataSize number of bytes to be transmitted + * @param timeout the timeout, in milliseconds, or 0 for no timeout + * @param completionHandler handler that will be called when the request completes + */ + synchronized void submitTransferOut(int endpointNumber, MemorySegment data, int dataSize, int timeout, + AsyncIOCompletion completionHandler) { - static { - try { - asyncIOCompletedMH = MethodHandles.lookup().findStatic(MacosUSBDevice.class, "asyncIOCompleted", - MethodType.methodType(void.class, AsyncIOCallback.class, MemorySegment.class, int.class, MemorySegment.class)); - } catch (IllegalAccessException|NoSuchMethodException e) { - throw new RuntimeException(e); - } + EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); + + // submit request + int ret; + if (timeout <= 0) + ret = IoKitUSB.WritePipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), data, dataSize, + getCompletionUpcallStub(), saveCompletionHandler(completionHandler)); + else + ret = IoKitUSB.WritePipeAsyncTO(epInfo.iokitInterface(), epInfo.pipeIndex(), data, dataSize, timeout, + timeout, getCompletionUpcallStub(), saveCompletionHandler(completionHandler)); + + if (ret != 0) + throwException(ret, "failed to submit transfer OUT request"); } - static void asyncIOCompleted(AsyncIOCallback callback, MemorySegment ignoredRefcon, int result, MemorySegment arg0) { - callback.completed(result, (int)arg0.address()); + /** + * Submits a control transfer request. + * @param deviceRequest control transfer request + * @param completionHandler handler that will be called when the request completes + */ + synchronized void submitControlTransfer(MemorySegment deviceRequest, AsyncIOCompletion completionHandler) { + + checkIsOpen(); + + // submit request + int ret = IoKitUSB.DeviceRequestAsync(device, deviceRequest, getCompletionUpcallStub(), saveCompletionHandler(completionHandler)); + + if (ret != 0) + throwException(ret, "failed to submit control transfer request"); } - synchronized MemorySegment createCompletionHandler(USBDirection direction, int endpointNumber, Arena arena, AsyncIOCallback callback) { - var endpoint = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, null); + private TransferRequest createRequest() { + var request = new TransferRequest(); + request.size = -1; + return request; + } - var source = IoKitUSB.GetInterfaceAsyncEventSource(endpoint.iokitInterface()); - if (source.address() == 0) { - try (Arena innerArena = Arena.openConfined()) { - var sourceHolder = innerArena.allocate(ADDRESS); - int ret = IoKitUSB.CreateInterfaceAsyncEventSource(endpoint.iokitInterface(), sourceHolder); - if (ret != 0) - throwException(ret, "failed to create event source"); - source = sourceHolder.get(ADDRESS, 0); - registry.addEventSource(source); + private void waitForRequest(TransferRequest request, USBDirection direction, int endpointNumber, boolean ignoreAbort) { + // wait for request + while (request.size == -1) { + try { + request.wait(); + } catch (InterruptedException e) { + // ignore and retry } } - var methodHandle = asyncIOCompletedMH.bindTo(callback); - return Linker.nativeLinker().upcallStub(methodHandle, completionHandlerFuncDesc, arena.scope()); + // test for error + if (request.result != 0) { + var operation = getOperationDescription(direction, endpointNumber); + if (request.result == IOKit.kIOUSBTransactionTimeout()) + throw new USBTimeoutException(operation + "aborted due to timeout"); + if (request.result != IOKit.kIOReturnAborted() || !ignoreAbort) + throwException(request.result, operation + " failed"); + } } - void submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, MemorySegment completionHandler) { + private void waitForRequestOrAbort(TransferRequest request, int timeout, USBDirection direction, int endpointNumber) { + // wait for request or abort when timeout occurs + long expiration = System.currentTimeMillis() + timeout; + long remainingTimeout = timeout; + while (remainingTimeout > 0 && request.size == -1) { + try { + request.wait(remainingTimeout); + remainingTimeout = expiration - System.currentTimeMillis(); + + } catch (InterruptedException e) { + // ignore and retry + } + } - EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, null); + // test for timeout + if (request.result == 0 && remainingTimeout <= 0) { + abortTransfer(direction, endpointNumber); + waitForRequest(request, direction, endpointNumber, true); + throw new USBTimeoutException(getOperationDescription(direction, endpointNumber) + "aborted due to timeout"); + } - // submit request - int ret = IoKitUSB.ReadPipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), buffer, bufferSize, completionHandler, MemorySegment.NULL); - if (ret != 0) - throwException(ret, "failed to submit async transfer"); + if (request.result != 0) { + var operation = direction == USBDirection.IN ? "Transfer in" : "Transfer out"; + throwException(request.result, getOperationDescription(direction, endpointNumber) + " failed", operation); + } } - void submitTransferOut(int endpointNumber, MemorySegment data, int dataSize, MemorySegment completionHandler) { + private static String getOperationDescription(USBDirection direction, int endpointNumber) { + if (endpointNumber == 0) { + return "Control transfer"; + } else { + return String.format("Transfer %s on endpoint %d", direction.name(), endpointNumber); + } - EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, null); + } - // submit request - int ret = IoKitUSB.WritePipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), data, dataSize, completionHandler, MemorySegment.NULL); - if (ret != 0) - throwException(ret, "failed to submit async transfer"); + private static void onRequestCompleted(TransferRequest request, int result, int size) { + synchronized (request) { + request.result = result; + request.size = size; + request.notify(); + } } public void abortTransfer(USBDirection direction, int endpointNumber) { @@ -535,14 +640,73 @@ private static USBTransferType getTransferType(byte macosTransferType) { }; } - record InterfaceInfo(MemorySegment iokitInterface, int interfaceNumber) { + private synchronized MemorySegment getCompletionUpcallStub() { + if (completionUpcallStub == null) { + arena = Arena.openShared(); + var methodHandle = asyncIOCompletedMH.bindTo(this); + completionUpcallStub = Linker.nativeLinker().upcallStub(methodHandle, completionHandlerFuncDesc, arena.scope()); + } + + return completionUpcallStub; } - record EndpointInfo(MemorySegment iokitInterface, byte pipeIndex, USBTransferType transferType, int packetSize) { + private synchronized MemorySegment saveCompletionHandler(AsyncIOCompletion handler) { + if (completionHandlers == null) + completionHandlers = new HashMap<>(); + + while (true) { + lastHandlerId += 1; + var key = Integer.valueOf(lastHandlerId); + if (completionHandlers.containsKey(key)) + continue; + + completionHandlers.put(key, handler); + return MemorySegment.ofAddress(lastHandlerId, 0, SegmentScope.global()); + } + } + + private synchronized void addDeviceEventSource() { + try (Arena innerArena = Arena.openConfined()) { + var sourceHolder = innerArena.allocate(ADDRESS); + int ret = IoKitUSB.CreateDeviceAsyncEventSource(device, sourceHolder); + if (ret != 0) + throwException(ret, "failed to create event source"); + var source = sourceHolder.get(ADDRESS, 0); + registry.addEventSource(source); + } + } + + private synchronized void addInterfaceEventSource(InterfaceInfo interfaceInfo) { + try (Arena innerArena = Arena.openConfined()) { + var sourceHolder = innerArena.allocate(ADDRESS); + int ret = IoKitUSB.CreateInterfaceAsyncEventSource(interfaceInfo.iokitInterface(), sourceHolder); + if (ret != 0) + throwException(ret, "failed to create event source"); + var source = sourceHolder.get(ADDRESS, 0); + registry.addEventSource(source); + } + } + + private synchronized AsyncIOCompletion getCompletionHandler(MemorySegment refcon) { + var key = Integer.valueOf((int)refcon.address()); + var handler = completionHandlers.remove(key); + + if (!isOpen() && completionHandlers.size() == 0) { + completionHandlers = null; + completionUpcallStub = null; + arena.close(); + arena = null; + } + + return handler; + } + + private static void asyncIOCompleted(MacosUSBDevice device, MemorySegment refcon, int result, MemorySegment arg0) { + device.getCompletionHandler(refcon).completed(result, (int)arg0.address()); } @FunctionalInterface - public interface AsyncIOCallback { + public interface AsyncIOCompletion { /** * Called when the asynchronous IO has completed. @@ -552,4 +716,15 @@ public interface AsyncIOCallback { */ void completed(int result, int size); } + + record InterfaceInfo(MemorySegment iokitInterface, int interfaceNumber) { + } + + record EndpointInfo(MemorySegment iokitInterface, byte pipeIndex, USBTransferType transferType, int packetSize) { + } + + static class TransferRequest { + int result; + int size; + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java deleted file mode 100644 index 51bb0213..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/TransferTimeout.java +++ /dev/null @@ -1,69 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.macos; - -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -import static net.codecrete.usb.macos.MacosUSBException.throwException; - -/** - * Manages the timeout for a USB transfer. - *

- * Not used for bulk transfers as IOKit offers suitable functions ({@code WritePipeTO()}, {@code ReadPipeTO()}). - *

- */ -class TransferTimeout { - /** - * Schedules a timeout for the specified endpoint. - *

- * If the timeout expires, the transfer is aborted. - *

- * - * @param endpointInfo endpoint information - * @param timeout timeout, in milliseconds - */ - TransferTimeout(MacosUSBDevice.EndpointInfo endpointInfo, int timeout) { - this.endpointInfo = endpointInfo; - future = getScheduledExecutorService().schedule(this::abort, timeout, TimeUnit.MILLISECONDS); - } - - private synchronized void abort() { - if (completed) - return; - if (endpointInfo.iokitInterface() != null) { - int ret = IoKitUSB.AbortPipe(endpointInfo.iokitInterface(), endpointInfo.pipeIndex()); - if (ret != 0) - throwException(ret, "Failed to abort USB transfer after timeout"); - } - } - - /** - * Marks the transfer as completed and cancels the timeout. - */ - synchronized void markCompleted() { - if (completed) - return; - completed = true; - future.cancel(false); - } - - static synchronized ScheduledExecutorService getScheduledExecutorService() { - if (scheduledExecutorService == null) - scheduledExecutorService = Executors.newScheduledThreadPool(1); - return scheduledExecutorService; - } - - private final ScheduledFuture future; - private final MacosUSBDevice.EndpointInfo endpointInfo; - private boolean completed; - - private static ScheduledExecutorService scheduledExecutorService; -} diff --git a/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java index f5d91a01..38336c71 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java @@ -37,7 +37,7 @@ void loopback_isFast() throws Throwable { double throughput = 2.0 * numBytes / (end - start); double expectedThroughput = isHighSpeed ? 19000 : 500; - System.out.printf("Throughput: expected %,.0f KB/s, actual %,.0f KB/s%n", expectedThroughput, throughput); + System.out.printf("Throughput: expected ≥%,.0f KB/s, actual %,.0f KB/s%n", expectedThroughput, throughput); assertTrue(throughput >= expectedThroughput, "Expected throughput not achieved"); } From 026a88ad7425fba9dcb33b8fecb5181c2dcfd5fe Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 18 Feb 2023 13:06:23 +0100 Subject: [PATCH 195/433] iostreams using blocking queues (C++/Windows) --- reference/windows/USB/USB.vcxproj | 1 + reference/windows/USB/USB.vcxproj.filters | 3 + reference/windows/USB/blocking_queue.hpp | 69 +++++++ reference/windows/USB/usb_device.cpp | 2 +- reference/windows/USB/usb_device.hpp | 2 +- reference/windows/USB/usb_iostream.cpp | 238 ++++++++++------------ reference/windows/USB/usb_iostream.hpp | 105 ++++++---- reference/windows/USB/usb_registry.cpp | 9 +- reference/windows/USB/usb_registry.hpp | 6 +- 9 files changed, 251 insertions(+), 184 deletions(-) create mode 100644 reference/windows/USB/blocking_queue.hpp diff --git a/reference/windows/USB/USB.vcxproj b/reference/windows/USB/USB.vcxproj index ed5d926c..62063b27 100644 --- a/reference/windows/USB/USB.vcxproj +++ b/reference/windows/USB/USB.vcxproj @@ -34,6 +34,7 @@ + diff --git a/reference/windows/USB/USB.vcxproj.filters b/reference/windows/USB/USB.vcxproj.filters index 4bf8b8df..7de3d949 100644 --- a/reference/windows/USB/USB.vcxproj.filters +++ b/reference/windows/USB/USB.vcxproj.filters @@ -89,5 +89,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/reference/windows/USB/blocking_queue.hpp b/reference/windows/USB/blocking_queue.hpp new file mode 100644 index 00000000..154b0230 --- /dev/null +++ b/reference/windows/USB/blocking_queue.hpp @@ -0,0 +1,69 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#pragma once + +#include +#include + + +/** + * Blocking FIFO queue for passing work from one thread to another. + * + * The queue is unbounded. + */ +template +class blocking_queue { +public: + /** + * Indicates if the queue is empty. + * + * @return 'true' if the queue is empty, 'false' if the queue contains elements + */ + bool empty() const { + std::lock_guard lock(guard); + return queue.empty(); + } + + /** + * Adds the item to the end of the queue. + * + * @param item item to add + */ + void put(const T& item) { + { + std::lock_guard lock(guard); + queue.push(item); + } + + signal.notify_one(); + } + + /** + * Takes the oldest item from the queue and removes it. + * + * Waits until an item is available. + * + * @return item removed from queue + */ + T take() { + std::unique_lock lock(guard); + while (queue.empty()) + signal.wait(lock); + + T item = queue.front(); + queue.pop(); + return item; + } + +private: + std::queue queue; + mutable std::mutex guard; + std::condition_variable signal; +}; diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp index c182f2d7..aa08049c 100644 --- a/reference/windows/USB/usb_device.cpp +++ b/reference/windows/USB/usb_device.cpp @@ -386,7 +386,7 @@ std::unique_ptr usb_device::open_output_stream(int endpoint_number return std::unique_ptr(new usb_ostream(registry_->get_shared_ptr(this), endpoint_number)); } -void usb_device::add_completion_handler(OVERLAPPED* overlapped, std::function* completion_handler) { +void usb_device::add_completion_handler(OVERLAPPED* overlapped, std::function* completion_handler) { registry_->add_completion_handler(overlapped, completion_handler); } diff --git a/reference/windows/USB/usb_device.hpp b/reference/windows/USB/usb_device.hpp index 4c4da685..2e965315 100644 --- a/reference/windows/USB/usb_device.hpp +++ b/reference/windows/USB/usb_device.hpp @@ -266,7 +266,7 @@ class usb_device { } void configure_for_async_io(usb_direction direction, int endpoint_number); - void add_completion_handler(OVERLAPPED* overlapped, std::function* completion_handler); + void add_completion_handler(OVERLAPPED* overlapped, std::function* completion_handler); void remove_completion_handler(OVERLAPPED* overlapped); void submit_transfer_in(int endpoint_number, uint8_t* buffer, int buffer_len, OVERLAPPED* overlapped); void submit_transfer_out(int endpoint_number, uint8_t* data, int data_len, OVERLAPPED* overlapped); diff --git a/reference/windows/USB/usb_iostream.cpp b/reference/windows/USB/usb_iostream.cpp index caf9d8e2..20cb36d1 100644 --- a/reference/windows/USB/usb_iostream.cpp +++ b/reference/windows/USB/usb_iostream.cpp @@ -14,7 +14,7 @@ // --- usb_istreambuf --- usb_istreambuf::usb_istreambuf(usb_device_ptr device, int endpoint_number) -: device(device), endpoint_number(endpoint_number), is_closed(false), submitted_index(0), completed_index(0), processed_index(-1) { +: device(device), endpoint_number(endpoint_number), is_closed(false) { setg(nullptr, nullptr, nullptr); @@ -22,66 +22,62 @@ usb_istreambuf::usb_istreambuf(usb_device_ptr device, int endpoint_number) buffer_size = 4 * device->get_endpoint(usb_direction::in, endpoint_number).packet_size(); - // create buffers - for (int i = 0; i < num_outstanding_requests; i++) - buffers[i] = new uint8_t[buffer_size]; - - // initialize OUTLAPPED structure and submit request - memset(overlapped_requests, 0, sizeof(overlapped_requests)); - - // create and register IO completion handler - io_completion_handler = [this](DWORD result, DWORD size) { on_io_completion(result, size); }; - for (int i = 0; i < num_outstanding_requests; i++) - device->add_completion_handler(&overlapped_requests[i], &io_completion_handler); - - // start requests except for one - const std::lock_guard lock(io_mutex); - for (int i = 0; i < num_outstanding_requests - 1; i++) - submit_request(); + // allocate the buffers and submit requests + memset(requests, 0, sizeof(requests)); + for (int i = 0; i < max_outstanding_requests; i++) { + transfer_request* request = &requests[i]; + request->buffer = new uint8_t[buffer_size]; + request->io_completion = [this, request]() { on_completed(request); }; + device->add_completion_handler(&request->overlapped, &request->io_completion); + + if (i == 0) + current_request = request; + else + submit_transfer(request); + } } usb_istreambuf::~usb_istreambuf() { close(); - for (int i = 0; i < num_outstanding_requests; i++) - delete[] buffers[i]; + for (int i = 0; i < max_outstanding_requests; i++) + delete[] requests[i].buffer; } void usb_istreambuf::close() { - { - const std::lock_guard lock(io_mutex); - - is_closed = true; + is_closed = true; + setg(nullptr, nullptr, nullptr); - for (int i = completed_index; submitted_index - i > 0; i += 1) { - int index = i % num_outstanding_requests; - device->cancel_transfer(usb_direction::in, endpoint_number, &overlapped_requests[index]); - } + // cancel outstanding requests + for (int i = 0; i < max_outstanding_requests; i++) { + if (!requests[i].is_completed) + device->cancel_transfer(usb_direction::in, endpoint_number, &requests[i].overlapped); } - io_condition.notify_all(); + // wait until completion handlers have been called + while (num_outstanding_requests > 0) + wait_for_request_completion(); - // wait until all completion handlers have been called - std::unique_lock wait_lock(io_mutex); - io_condition.wait(wait_lock, [this] { return completed_index == submitted_index; }); + // remove completion handlers + for (int i = 0; i < max_outstanding_requests; i++) + device->remove_completion_handler(&requests->overlapped); } -void usb_istreambuf::submit_request() { - int index = submitted_index % num_outstanding_requests; - submitted_index += 1; - - device->submit_transfer_in(endpoint_number, buffers[index], buffer_size, &overlapped_requests[index]); +void usb_istreambuf::submit_transfer(transfer_request* request) { + request->is_completed = false; + device->submit_transfer_in(endpoint_number, request->buffer, buffer_size, &request->overlapped); + num_outstanding_requests += 1; } -void usb_istreambuf::on_io_completion(DWORD result, DWORD size) { - const std::lock_guard lock(io_mutex); - - int index = completed_index % num_outstanding_requests; - request_sizes[index] = size; - request_results[index] = result; +void usb_istreambuf::on_completed(transfer_request* request) { + request->is_completed = true; + completed_request_queue.put(request); +} - completed_index += 1; - io_condition.notify_all(); +usb_istreambuf::transfer_request* usb_istreambuf::wait_for_request_completion() { + transfer_request* request = completed_request_queue.take(); + num_outstanding_requests -= 1; + return request; } usb_istreambuf::int_type usb_istreambuf::underflow() { @@ -91,110 +87,91 @@ usb_istreambuf::int_type usb_istreambuf::underflow() { if (gptr() < egptr()) return traits_type::to_int_type(*gptr()); - // loop until no ZLP has been received - while (true) { - std::unique_lock wait_lock(io_mutex); - processed_index += 1; - submit_request(); + // loop until non-ZLP has been received + do { + submit_transfer(current_request); - // wait until a completed request is available - io_condition.wait(wait_lock, [this] { return completed_index - processed_index > 0 || is_closed; }); + current_request = wait_for_request_completion(); + if (current_request->result_code() != S_OK) + throw new usb_error("transfer IN failed", current_request->result_code()); - if (is_closed) - return traits_type::eof(); + char* buf = reinterpret_cast(current_request->buffer); + int size = current_request->result_size(); + setg(buf, buf, buf + size); - int index = processed_index % num_outstanding_requests; - if (request_results[index] != S_OK) - throw new usb_error("transfer IN failed", request_results[index]); + } while (current_request->result_size() == 0); - // set stream buffer to buffer from completed request - char* buf = reinterpret_cast(buffers[index]); - int size = request_sizes[index]; - - if (size != 0) { - setg(buf, buf, buf + size); - return traits_type::to_int_type(*gptr()); - } - } + return traits_type::to_int_type(*gptr()); } // --- usb_ostreambuf --- usb_ostreambuf::usb_ostreambuf(usb_device_ptr device, int endpoint_number) -: device(device), endpoint_number(endpoint_number), processing_index(0), completed_index(0), checked_index(0), needs_zlp(false) { +: device(device), endpoint_number(endpoint_number), needs_zlp(false) { device->configure_for_async_io(usb_direction::out, endpoint_number); packet_size = device->get_endpoint(usb_direction::out, endpoint_number).packet_size(); buffer_size = 1 * packet_size; - // create buffers - for (int i = 0; i < num_outstanding_requests; i++) - buffers[i] = new uint8_t[buffer_size]; - - char* buf = reinterpret_cast(buffers[0]); - setp(buf, buf + buffer_size); - - // initialize OUTLAPPED structure and submit request - memset(overlapped_requests, 0, sizeof(overlapped_requests)); + // create requests + memset(requests, 0, sizeof(requests)); + for (int i = 0; i < max_outstanding_requests; i++) { + transfer_request* request = &requests[i]; + request->buffer = new uint8_t[buffer_size]; + request->io_completion = [this, request](void) { on_completed(request); }; + device->add_completion_handler(&request->overlapped, &request->io_completion); + } - // create and register IO completion handler - io_completion_handler = [this](DWORD result, DWORD size) { on_io_completion(result, size); }; - for (int i = 0; i < num_outstanding_requests; i++) - device->add_completion_handler(&overlapped_requests[i], &io_completion_handler); + fill_queue(); } +void usb_ostreambuf::fill_queue() { + for (int i = 1; i < max_outstanding_requests; i++) + available_request_queue.put(&requests[i]); + + // configure stream buffer for first request + current_request = &requests[0]; + char* buf = reinterpret_cast(current_request->buffer); + setp(buf, buf + buffer_size); +} + usb_ostreambuf::~usb_ostreambuf() { sync(); - for (int i = 0; i < num_outstanding_requests; i++) - delete[] buffers[i]; + // free buffers + for (int i = 0; i < max_outstanding_requests; i++) { + device->remove_completion_handler(&requests[i].overlapped); + delete[] requests[i].buffer; + } } int usb_ostreambuf::sync() { - std::unique_lock wait_lock(io_mutex); - // submit request if there is any data in the current buffer - auto size = static_cast(pptr() - pbase()); + auto size = pptr() - pbase(); if (size > 0) - submit_transfer(size); - - // send a zero-length packet if required - if (needs_zlp) { - // wait until an unused buffer is available - io_condition.wait(wait_lock, [this] { return processing_index - completed_index < num_outstanding_requests; }); - check_for_errors(); + submit_transfer((int)size); + // send a zero-length packet if required + if (needs_zlp) submit_transfer(0); - } - // wait until all buffers have been transmitted - io_condition.wait(wait_lock, [this] { return processing_index == completed_index; }); - check_for_errors(); + // Wait until all buffers have been transmitted by removing them from the + // queue and reinserting them. One request is the current request. + // So the queue only contains max_outstanding_requests - 1 requests. + for (int i = 0; i < max_outstanding_requests - 1; i++) + wait_for_available_transfer(); - int index = processing_index % num_outstanding_requests; - char* buf = reinterpret_cast(buffers[index]); - setp(buf, buf + buffer_size); + fill_queue(); return 0; } int usb_ostreambuf::overflow (int c) { - std::unique_lock wait_lock(io_mutex); - // submit request - auto size = static_cast(pptr() - pbase()); - submit_transfer(size); - - // wait until an unused buffer is available - io_condition.wait(wait_lock, [this] { return processing_index - completed_index < num_outstanding_requests; }); - check_for_errors(); - - // configure stream buffer - int index = processing_index % num_outstanding_requests; - char* buf = reinterpret_cast(buffers[index]); - setp(buf, buf + buffer_size); + auto size = pptr() - pbase(); + submit_transfer((int)size); // insert char if (c != traits_type::eof()) { @@ -205,29 +182,30 @@ int usb_ostreambuf::overflow (int c) { return c; } -void usb_ostreambuf::on_io_completion(DWORD result, DWORD size) { - const std::lock_guard lock(io_mutex); - int index = completed_index % num_outstanding_requests; - request_results[index] = result; - completed_index += 1; - io_condition.notify_all(); -} +void usb_ostreambuf::submit_transfer(int size) { + device->submit_transfer_out(endpoint_number, current_request->buffer, size, ¤t_request->overlapped); + needs_zlp = size == packet_size; -void usb_ostreambuf::check_for_errors() { + current_request = wait_for_available_transfer(); - while (completed_index - checked_index > 0) { - int index = completed_index % num_outstanding_requests; - if (request_results[index] != S_OK) - throw new usb_error("transfer OUT failed", request_results[index]); - checked_index += 1; - } + // configure stream buffer + char* buf = reinterpret_cast(current_request->buffer); + setp(buf, buf + buffer_size); } -void usb_ostreambuf::submit_transfer(int size) { - int index = processing_index % num_outstanding_requests; - device->submit_transfer_out(endpoint_number, buffers[index], size, &overlapped_requests[index]); - processing_index += 1; - needs_zlp = size == packet_size; +void usb_ostreambuf::on_completed(transfer_request* request) { + available_request_queue.put(request); +} + +usb_ostreambuf::transfer_request* usb_ostreambuf::wait_for_available_transfer() { + auto request = available_request_queue.take(); + + // check for error + DWORD result = request->result_code(); + if (result != S_OK) + throw new usb_error("transfer OUT failed", result); + + return request; } diff --git a/reference/windows/USB/usb_iostream.hpp b/reference/windows/USB/usb_iostream.hpp index c1274677..5e60516d 100644 --- a/reference/windows/USB/usb_iostream.hpp +++ b/reference/windows/USB/usb_iostream.hpp @@ -13,6 +13,7 @@ #include #include #include "usb_device.hpp" +#include "blocking_queue.hpp" /** * Input stream buffer for USB bulk or interrupt endpoint. @@ -32,13 +33,34 @@ class usb_istreambuf : public std::streambuf { virtual int_type underflow(); private: - void submit_request(); + /// Transfer request + struct transfer_request { + /// buffer for recevied data + uint8_t* buffer; + /// IO completion handler + std::function io_completion; + /// data structure for overlapped requests + OVERLAPPED overlapped; + /// indicates if the request has completed + bool is_completed; + + DWORD result_code() { + return static_cast(overlapped.Internal); + } + + DWORD result_size() { + return static_cast(overlapped.InternalHigh); + } + }; + + void submit_transfer(transfer_request* request); void close(); - void on_io_completion(DWORD result, DWORD size); + void on_completed(transfer_request* request); + transfer_request* wait_for_request_completion(); /// Maximum number of concurrently outstanding requests - static constexpr int num_outstanding_requests = 4; + static constexpr int max_outstanding_requests = 4; /// USB device usb_device_ptr device; @@ -48,26 +70,14 @@ class usb_istreambuf : public std::streambuf { bool is_closed; /// buffer size int buffer_size; - /// Mutex for synchronization between input stream caller and background thread handling IO completion. - std::mutex io_mutex; - /// Condition for synchronization between input stream caller and background thread handling IO completion - std::condition_variable io_condition; - /// Index after last submitted IO request - int submitted_index; - /// Index after last completed IO request - int completed_index; - /// Index after last processed IO request - int processed_index; - /// Async IO request information - OVERLAPPED overlapped_requests[num_outstanding_requests]; - /// Data buffers - uint8_t* buffers[num_outstanding_requests]; - /// Size of received data - DWORD request_sizes[num_outstanding_requests]; - /// Result code of IO request - DWORD request_results[num_outstanding_requests]; - /// Async IO completion handler - std::function io_completion_handler; + /// transfer requests + transfer_request requests[max_outstanding_requests]; + /// queue with completed requests + blocking_queue completed_request_queue; + /// number of outstanding requests (requests pending with OS and requests in queue) + int num_outstanding_requests; + /// current request being read from + transfer_request* current_request; friend class usb_istream; }; @@ -92,13 +102,32 @@ class usb_ostreambuf : public std::streambuf { virtual int overflow (int c); private: + /// Transfer request + struct transfer_request { + /// buffer for recevied data + uint8_t* buffer; + /// overlapped data structure + OVERLAPPED overlapped; + /// IO completion handler + std::function io_completion; + + DWORD result_code() { + return static_cast(overlapped.Internal); + } + + DWORD result_size() { + return static_cast(overlapped.InternalHigh); + } + }; + + void fill_queue(); void submit_transfer(int size); - void check_for_errors(); + transfer_request* wait_for_available_transfer(); - void on_io_completion(DWORD result, DWORD size); + void on_completed(transfer_request* request); /// Maximum number of concurrently outstanding requests - static constexpr int num_outstanding_requests = 4; + static constexpr int max_outstanding_requests = 4; /// USB device usb_device_ptr device; @@ -110,24 +139,12 @@ class usb_ostreambuf : public std::streambuf { int packet_size; /// buffer size int buffer_size; - /// Mutex for synchronization between output stream caller and background thread handling IO completion. - std::mutex io_mutex; - /// Condition for synchronization between output stream caller and background thread handling IO completion - std::condition_variable io_condition; - /// Index of buffer being currently used by base class - int processing_index; - /// Index after last completed IO request - int completed_index; - /// Index after last completed IO request that has been checked for errors - int checked_index; - /// Async IO request information - OVERLAPPED overlapped_requests[num_outstanding_requests]; - /// Data buffers for transmitting data - uint8_t* buffers[num_outstanding_requests]; - /// Result code of IO request - DWORD request_results[num_outstanding_requests]; - /// Async IO completion handler - std::function io_completion_handler; + /// transfer requests + transfer_request requests[max_outstanding_requests]; + /// queue with available requests + blocking_queue available_request_queue; + /// current request being written to + transfer_request* current_request; }; /** diff --git a/reference/windows/USB/usb_registry.cpp b/reference/windows/USB/usb_registry.cpp index 9433cf68..57cd3d84 100644 --- a/reference/windows/USB/usb_registry.cpp +++ b/reference/windows/USB/usb_registry.cpp @@ -396,12 +396,11 @@ void usb_registry::async_io_run() { if (overlapped == nullptr) return; // registry is closing - std::function* completion_handler = get_completion_handler(overlapped); + std::function* completion_handler = get_completion_handler(overlapped); if (overlapped == nullptr) continue; // might be completion from synchronous operation - DWORD result = static_cast(overlapped->Internal); - (*completion_handler)(result, num_bytes); + (*completion_handler)(); } } @@ -416,7 +415,7 @@ void usb_registry::add_to_completion_port(HANDLE handle) { } } -void usb_registry::add_completion_handler(OVERLAPPED* overlapped, std::function* completion_handler) { +void usb_registry::add_completion_handler(OVERLAPPED* overlapped, std::function* completion_handler) { std::lock_guard lock(async_io_mutex); async_io_completion_handlers.insert(std::pair(overlapped, completion_handler)); @@ -428,7 +427,7 @@ void usb_registry::remove_completion_handler(OVERLAPPED* overlapped) { async_io_completion_handlers.erase(overlapped); } -std::function* usb_registry::get_completion_handler(OVERLAPPED* overlapped) { +std::function* usb_registry::get_completion_handler(OVERLAPPED* overlapped) { std::lock_guard lock(async_io_mutex); auto it = async_io_completion_handlers.find(overlapped); diff --git a/reference/windows/USB/usb_registry.hpp b/reference/windows/USB/usb_registry.hpp index a95abe28..4f3f9129 100644 --- a/reference/windows/USB/usb_registry.hpp +++ b/reference/windows/USB/usb_registry.hpp @@ -68,9 +68,9 @@ class usb_registry { void async_io_run(); void add_to_completion_port(HANDLE); - void add_completion_handler(OVERLAPPED* overlapped, std::function* completion_handler); + void add_completion_handler(OVERLAPPED* overlapped, std::function* completion_handler); void remove_completion_handler(OVERLAPPED* overlapped); - std::function* get_completion_handler(OVERLAPPED* overlapped); + std::function* get_completion_handler(OVERLAPPED* overlapped); std::thread monitor_thread; @@ -83,7 +83,7 @@ class usb_registry { std::thread async_io_thread; std::mutex async_io_mutex; HANDLE async_io_completion_port; - std::map*> async_io_completion_handlers; + std::map*> async_io_completion_handlers; friend class usb_device; friend class usb_istreambuf; From dc19d9c34386d1dbcb4bc5f66baccb7487133883 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 19 Feb 2023 11:37:04 +0100 Subject: [PATCH 196/433] High througput input stream (Windows) --- java-does-usb/jextract/windows/gen_win.cmd | 5 + .../windows/WindowsEndpointInputStream.java | 220 ++++++++++++++++++ .../usb/windows/WindowsUSBDevice.java | 143 +++++++++++- .../usb/windows/WindowsUSBDeviceRegistry.java | 104 ++++++++- .../usb/windows/WindowsUSBException.java | 2 +- .../usb/windows/gen/kernel32/Kernel32.java | 16 ++ .../usb/windows/gen/kernel32/OVERLAPPED.java | 16 ++ .../usb/windows/gen/kernel32/_OVERLAPPED.java | 216 +++++++++++++++++ .../usb/windows/gen/winusb/WinUSB.java | 8 + .../usb/windows/winsdk/Kernel32B.java | 60 ++++- 10 files changed, 775 insertions(+), 15 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/OVERLAPPED.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index f916dfc0..175202fd 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -20,6 +20,7 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-constant ERROR_SEM_TIMEOUT ^ --include-constant ERROR_GEN_FAILURE ^ --include-constant ERROR_NOT_FOUND ^ + --include-constant ERROR_IO_PENDING ^ --include-constant GENERIC_READ ^ --include-constant GENERIC_WRITE ^ --include-constant FILE_SHARE_READ ^ @@ -30,8 +31,11 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-constant FORMAT_MESSAGE_ALLOCATE_BUFFER ^ --include-constant FORMAT_MESSAGE_FROM_SYSTEM ^ --include-constant FORMAT_MESSAGE_IGNORE_INSERTS ^ + --include-constant INFINITE ^ --include-struct _GUID ^ --include-typedef GUID ^ + --include-struct _OVERLAPPED ^ + --include-typedef OVERLAPPED ^ windows_headers.h call %JEXTRACT% --source --output ../../src/main/java ^ @@ -110,6 +114,7 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --target-package net.codecrete.usb.windows.gen.winusb ^ --include-function WinUsb_Free ^ --include-constant PIPE_TRANSFER_TIMEOUT ^ + --include-constant RAW_IO ^ windows_headers.h call %JEXTRACT% --source --output ../../src/main/java ^ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java new file mode 100644 index 00000000..6404c653 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java @@ -0,0 +1,220 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.windows; + +import net.codecrete.usb.USBDirection; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.util.concurrent.ArrayBlockingQueue; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static net.codecrete.usb.windows.WindowsUSBException.throwException; + +/** + * Input stream for bulk endpoints – optimized for high throughput. + * + *

+ * Multiple asynchronous transfer IN requests are submitted to achieve a good + * degree of concurrency between the USB communication handled by the operating + * system and the consuming application code. + *

+ *

+ * For thread synchronization (between the background thread handling IO completion + * and the consuming application thread) a blocking queue is used. When an transfer IN + * requests completes, the background thread adds it to the queue. The consuming code + * waits for the next item in the queue. + *

+ */ +public class WindowsEndpointInputStream extends InputStream { + + private static final int MAX_OUTSTANDING_REQUESTS = 8; + + private WindowsUSBDevice device; + private final int endpointNumber; + // Arena to allocate buffers and completion handlers + private final Arena arena; + // Size of buffers (multiple of packet size) + private final int bufferSize; + // Queue of completed requests + private final ArrayBlockingQueue completedRequestQueue; + // Number of outstanding requests (includes requests pending with the + // operating system and requests in the completed queue) + private int numOutstandingRequests; + // Request and buffer being currently read from + private TransferRequest[] allRequests; + private TransferRequest currentRequest; + // Read offset within current request + private int readOffset; + + /** + * Creates a new instance + * + * @param device USB device + * @param endpointNumber endpoint number + */ + WindowsEndpointInputStream(WindowsUSBDevice device, int endpointNumber) { + this.device = device; + this.endpointNumber = endpointNumber; + + bufferSize = 4 * device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); + completedRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); + + device.configureForAsyncIo(endpointNumber, USBDirection.IN); + + // create all requests and submit all except one + allRequests = new TransferRequest[MAX_OUTSTANDING_REQUESTS]; + arena = Arena.openShared(); + try { + for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { + final var request = new TransferRequest(); + allRequests[i] = request; + request.buffer = arena.allocate(bufferSize, 8); + request.completionHandler = (result, size) -> onCompletion(request, result, size); + + if (i == 0) { + currentRequest = request; + } else { + submitRequest(request); + } + } + } catch (Throwable t) { + collectOutstandingRequests(); + throw t; + } + } + + @SuppressWarnings("RedundantThrows") + @Override + public void close() throws IOException { + if (isClosed()) + return; + + // abort all transfers on endpoint + abortAllRequests(); + device = null; + + collectOutstandingRequests(); + } + + private void abortAllRequests() { + for (var request : allRequests) { + if (request != null && request.cancelHandle != 0) + device.cancelTransfer(endpointNumber, USBDirection.IN, request.cancelHandle); + } + } + + private void collectOutstandingRequests() { + // wait until completion handlers have been called + while (numOutstandingRequests > 0) + waitForRequestCompletion(); + + allRequests = null; + completedRequestQueue.clear(); + currentRequest = null; + arena.close(); + } + + @Override + public int read() throws IOException { + if (isClosed()) + return -1; + + if (available() == 0) + receiveMoreData(); + + int b = currentRequest.buffer.get(JAVA_BYTE, readOffset) & 0xff; + readOffset += 1; + return b; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (isClosed()) + return -1; + + if (available() == 0) + receiveMoreData(); + + // copy data to receiving buffer + int n = Math.min(len, currentRequest.resultSize - readOffset); + MemorySegment.copy(currentRequest.buffer, readOffset, MemorySegment.ofArray(b), off, n); + readOffset += n; + + // TODO: poll for further completed requests if 'n' is less than 'len' + + return n; + } + + @SuppressWarnings("RedundantThrows") + @Override + public int available() throws IOException { + return currentRequest.resultSize - readOffset; + } + + private boolean isClosed() { + return device == null; + } + + private void receiveMoreData() throws IOException { + try { + // loop until non-ZLP has been received + do { + submitRequest(currentRequest); + + currentRequest = waitForRequestCompletion(); + readOffset = 0; + + // check for error + if (currentRequest.result != 0) + throwException(currentRequest.result, "error reading from USB endpoint"); + + } while (currentRequest.resultSize == 0); + + } catch (Throwable t) { + close(); + throw t; + } + } + + void submitRequest(TransferRequest request) { + request.cancelHandle = + device.submitTransferIn(endpointNumber, request.buffer, bufferSize, request.completionHandler); + numOutstandingRequests += 1; + } + + void onCompletion(TransferRequest request, int result, int size) { + request.result = result; + request.resultSize = size; + request.cancelHandle = 0; + completedRequestQueue.add(request); + } + + TransferRequest waitForRequestCompletion() { + while (true) { + try { + TransferRequest request = completedRequestQueue.take(); + numOutstandingRequests -= 1; + return request; + + } catch (InterruptedException e) { + // ignore and retry + } + } + } + + private static class TransferRequest { + MemorySegment buffer; + int result; + int resultSize; + long cancelHandle; + WindowsUSBDevice.AsyncIOCompletion completionHandler; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 97e5e564..3b780c78 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -11,13 +11,17 @@ import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.usbstandard.SetupPacket; import net.codecrete.usb.windows.gen.kernel32.Kernel32; +import net.codecrete.usb.windows.gen.kernel32.OVERLAPPED; import net.codecrete.usb.windows.gen.winusb.WinUSB; import net.codecrete.usb.windows.winsdk.Kernel32B; import net.codecrete.usb.windows.winsdk.WinUSB2; +import java.io.InputStream; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentScope; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -31,11 +35,20 @@ */ public class WindowsUSBDevice extends USBDeviceImpl { + private final WindowsUSBDeviceRegistry registry; private List interfaceHandles_; private boolean isOpen_; - - WindowsUSBDevice(String devicePath, Map children, int vendorId, int productId, MemorySegment configDesc) { + // Completion handlers of currently outstanding asynchronous IO requests, + // indexed by OVERLAPPED pointer. + private Map completionHandlers; + // available OVERLAPPED data structures + private List availableOverlappedStructs; + // Arena used to allocate OVERLAPPED data structures + private Arena arena; + + WindowsUSBDevice(WindowsUSBDeviceRegistry registry, String devicePath, Map children, int vendorId, int productId, MemorySegment configDesc) { super(devicePath, vendorId, productId); + this.registry = registry; readDescription(configDesc, devicePath, children); } @@ -68,18 +81,26 @@ public boolean isOpen() { } @Override - public void open() { + public synchronized void open() { if (isOpen()) throwException("the device is already open"); isOpen_ = true; + + availableOverlappedStructs = new ArrayList<>(); + arena = Arena.openShared(); + completionHandlers = new HashMap<>(); } @Override - public void close() { + public synchronized void close() { if (!isOpen()) return; + availableOverlappedStructs = null; + arena.close(); + completionHandlers = null; + for (var intf : interfaces_) { if (intf.isClaimed()) releaseInterface(intf.number()); @@ -88,7 +109,7 @@ public void close() { isOpen_ = false; } - public void claimInterface(int interfaceNumber) { + public synchronized void claimInterface(int interfaceNumber) { checkIsOpen(); var intfHandle = getInterfaceHandle(interfaceNumber); @@ -116,6 +137,9 @@ public void claimInterface(int interfaceNumber) { if (Win.IsInvalidHandle(deviceHandle)) throwLastError(lastErrorState, "Cannot open USB device %s", firstIntfHandle.devicePath); + + registry.addToCompletionPort(deviceHandle, this); + } else { deviceHandle = firstIntfHandle.deviceHandle; } @@ -141,7 +165,7 @@ public void claimInterface(int interfaceNumber) { } @Override - public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { + public synchronized void selectAlternateSetting(int interfaceNumber, int alternateNumber) { checkIsOpen(); var intfHandle = getInterfaceHandle(interfaceNumber); @@ -164,7 +188,7 @@ public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { intf.setAlternate(altSetting); } - public void releaseInterface(int interfaceNumber) { + public synchronized void releaseInterface(int interfaceNumber) { checkIsOpen(); var intfHandle = getInterfaceHandle(interfaceNumber); @@ -182,6 +206,7 @@ public void releaseInterface(int interfaceNumber) { // close device firstIntfHandle.deviceOpenCount -= 1; if (firstIntfHandle.deviceOpenCount == 0) { + registry.removeFromCompletionPort(firstIntfHandle.deviceHandle); Kernel32.CloseHandle(firstIntfHandle.deviceHandle); firstIntfHandle.deviceHandle = null; } @@ -309,6 +334,71 @@ public byte[] transferIn(int endpointNumber, int timeout) { } } + synchronized long submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, AsyncIOCompletion completion) { + var endpoint = getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); + var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); + + try (var arena = Arena.openConfined()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + var overlapped = getOverlapped(completion); + + // submit transfer + if (WinUSB2.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, bufferSize, + NULL, overlapped, lastErrorState) == 0) { + int err = Win.getLastError(lastErrorState); + if (err != Kernel32.ERROR_IO_PENDING()) + throwException(err, "Submitting transfer IN failed"); + } + + return overlapped.address(); + } + } + + /** + * Cancels an asynchronous IO request. + *

+ * If the specific request is not found, the error is silently ignored. Such errors + * are likely to happen due to concurrency issues. + *

+ * @param endpointNumber endpoint number + * @param direction endpoint direction + * @param cancelHandle request's cancel handle returned when the request was submitted + */ + synchronized void cancelTransfer(int endpointNumber, USBDirection direction, long cancelHandle) { + var endpoint = getEndpoint(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); + var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); + + try (var arena = Arena.openConfined()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + var overlapped = MemorySegment.ofAddress(cancelHandle, 0, SegmentScope.global()); + + if (Kernel32B.CancelIoEx(intfHandle.deviceHandle, overlapped, lastErrorState) == 0) { + int err = Win.getLastError(lastErrorState); + if (err != Kernel32.ERROR_NOT_FOUND()) + throwException(err, "Cancelling transfer failed"); + } + } + } + + synchronized void configureForAsyncIo(int endpointNumber, USBDirection direction) { + var endpoint = getEndpoint(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); + var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); + + try (var arena = Arena.openConfined()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + + var timeoutHolder = arena.allocate(JAVA_INT, 0); + if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), + WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder, lastErrorState) == 0) + throwLastError(lastErrorState, "Setting timeout failed"); + + var rawIoHolder = arena.allocate(JAVA_BYTE, (byte)0); + if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), + WinUSB.RAW_IO(), (int) rawIoHolder.byteSize(), rawIoHolder, lastErrorState) == 0) + throwLastError(lastErrorState, "Setting raw IO failed"); + } + } + @Override public void clearHalt(USBDirection direction, int endpointNumber) { var endpoint = getEndpoint(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); @@ -321,6 +411,14 @@ public void clearHalt(USBDirection direction, int endpointNumber) { } } + @Override + public InputStream openInputStream(int endpointNumber) { + // check that endpoint number is valid + getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, null); + + return new WindowsEndpointInputStream(this, endpointNumber); + } + private InterfaceHandle getInterfaceHandle(int interfaceNumber) { for (var intfHandle : interfaceHandles_) { if (intfHandle.interfaceNumber == interfaceNumber) @@ -367,4 +465,35 @@ private InterfaceHandle findControlTransferInterface(USBControlTransfer setup) { throwException("Control transfer failed as no interface has been claimed"); throw new AssertionError("not reached"); } + + synchronized void onAsyncIoCompleted(MemorySegment overlapped) { + var handler = completionHandlers.get(overlapped); + handler.completed((int)OVERLAPPED.Internal$get(overlapped), (int)OVERLAPPED.InternalHigh$get(overlapped)); + completionHandlers.remove(overlapped); + availableOverlappedStructs.add(overlapped); + } + + private MemorySegment getOverlapped(AsyncIOCompletion completionHandler) { + MemorySegment overlapped; + int size = availableOverlappedStructs.size(); + if (size == 0) { + overlapped = arena.allocate(OVERLAPPED.$LAYOUT()); + } else { + overlapped = availableOverlappedStructs.remove(size - 1); + } + completionHandlers.put(overlapped, completionHandler); + return overlapped; + } + + @FunctionalInterface + public interface AsyncIOCompletion { + + /** + * Called when the asynchronous IO has completed. + * + * @param result the result code of the operation + * @param size the size of the transferred data (in bytes) + */ + void completed(int result, int size); + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 62f5fda4..1c293480 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -18,6 +18,7 @@ import net.codecrete.usb.usbstandard.StringDescriptor; import net.codecrete.usb.windows.gen.kernel32.GUID; import net.codecrete.usb.windows.gen.kernel32.Kernel32; +import net.codecrete.usb.windows.gen.kernel32.OVERLAPPED; import net.codecrete.usb.windows.gen.ole32.Ole32; import net.codecrete.usb.windows.gen.setupapi.SP_DEVICE_INTERFACE_DATA; import net.codecrete.usb.windows.gen.setupapi.SP_DEVINFO_DATA; @@ -28,10 +29,7 @@ import net.codecrete.usb.windows.winsdk.SetupAPI2; import net.codecrete.usb.windows.winsdk.User32B; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.Linker; -import java.lang.foreign.MemorySegment; +import java.lang.foreign.*; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.ArrayList; @@ -56,6 +54,15 @@ */ public class WindowsUSBDeviceRegistry extends USBDeviceRegistry { + /// Windows completion port for asynchronous/overlapped IO + private MemorySegment asyncIoCompletionPort = NULL; + /// last used completion key + private long lastUsedCompletionKey; + /// USB devices indexed by completion key + private Map devicesByCompletionKey; + /// completion keys indexed by Windows device handle + private Map completionKeysByHandle; + @Override protected void monitorDevices() { try (var arena = Arena.openConfined()) { @@ -324,7 +331,7 @@ private USBDevice createDevice(String devicePath, Map children, var configDesc = getDescriptor(hubHandle, usbPortNum, CONFIGURATION_DESCRIPTOR_TYPE, 0, (short) 0, arena); - var device = new WindowsUSBDevice(devicePath, children, vendorId, productId, configDesc); + var device = new WindowsUSBDevice(this, devicePath, children, vendorId, productId, configDesc); device.setFromDeviceDescriptor(descriptorSegment); device.setProductString(descriptorSegment, (index) -> getStringDescriptor(hubHandle, usbPortNum, index)); @@ -516,4 +523,91 @@ private static int extractInterfaceNumber(List hardwareIds) { return -1; } + + /** + * Background task for handling asynchronous IO completions. + */ + private void asyncCompletionTask() { + + try (var arena = Arena.openConfined()) { + + var overlappedHolder = arena.allocate(ADDRESS, NULL); + var numBytesHolder = arena.allocate(JAVA_INT, 0); + var completionKeyHolder = arena.allocate(JAVA_LONG, 0); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + + while (true) { + overlappedHolder.set(ADDRESS, 0, MemorySegment.NULL); + completionKeyHolder.set(JAVA_LONG, 0, 0); + + int res = Kernel32B.GetQueuedCompletionStatus(asyncIoCompletionPort, numBytesHolder, completionKeyHolder, + overlappedHolder, Kernel32.INFINITE(), lastErrorState); + var overlapped = overlappedHolder.get(ADDRESS, 0); + + if (res == 0 && overlapped == MemorySegment.NULL) + throwLastError(lastErrorState, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); + + if (overlapped == MemorySegment.NULL) + return; // registry is closing + + long completionKey = completionKeyHolder.get(JAVA_LONG, 0); + var device = devicesByCompletionKey.get(completionKey); + + if (device != null) { + overlapped = OVERLAPPED.ofAddress(overlapped, SegmentScope.global()); + device.onAsyncIoCompleted(overlapped); + } + } + } + } + + /** + * Add a Windows handle (of a USB device) to the completion port + * @param handle Windows handle + * @param device USB device + */ + synchronized void addToCompletionPort(MemorySegment handle, WindowsUSBDevice device) { + + lastUsedCompletionKey += 1; + var completionKey = Long.valueOf(lastUsedCompletionKey); + if (devicesByCompletionKey == null) { + devicesByCompletionKey = new HashMap<>(); + completionKeysByHandle = new HashMap<>(); + } + devicesByCompletionKey.put(completionKey, device); + completionKeysByHandle.put(handle, completionKey); + + try (var arena = Arena.openConfined()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + + // Creates a new port if it doesn't exist; adds handle to existing port if it exists + MemorySegment portHandle = Kernel32B.CreateIoCompletionPort(handle, asyncIoCompletionPort, + lastUsedCompletionKey, 0, lastErrorState); + if (portHandle == MemorySegment.NULL) + throwLastError(lastErrorState, "internal error (CreateIoCompletionPort)"); + + if (asyncIoCompletionPort == MemorySegment.NULL) { + asyncIoCompletionPort = portHandle; + + // start background thread for handling IO completion + Thread t = new Thread(this::asyncCompletionTask, "USB async IO"); + t.setDaemon(true); + t.start(); + } + } + } + + /** + * Removes a handle from the dispatching. + *

+ * The handle is removed from the completion port by closing the device. + *

+ * @param handle Windows device handle + */ + synchronized void removeFromCompletionPort(MemorySegment handle) { + Long completionKey = completionKeysByHandle.get(handle); + completionKeysByHandle.remove(handle); + devicesByCompletionKey.remove(completionKey); + } + } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java index 7dd23888..32018aa9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java @@ -76,7 +76,7 @@ static void throwLastError(MemorySegment lastErrorState, String message, Object. throwException(Win.getLastError(lastErrorState), message, args); } - private static String getErrorMessage(int errorCode) { + static String getErrorMessage(int errorCode) { try (var arena = Arena.openConfined()) { var messagePointerHolder = arena.allocate(ADDRESS); int res = Kernel32.FormatMessageW(Kernel32.FORMAT_MESSAGE_ALLOCATE_BUFFER() diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java index 5121c07f..95e61fa0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -160,6 +160,14 @@ public static int GENERIC_READ() { public static int GENERIC_WRITE() { return (int)1073741824L; } + /** + * {@snippet : + * #define INFINITE 4294967295 + * } + */ + public static int INFINITE() { + return (int)4294967295L; + } /** * {@snippet : * #define ERROR_SUCCESS 0 @@ -216,6 +224,14 @@ public static int ERROR_MORE_DATA() { public static int ERROR_NO_MORE_ITEMS() { return (int)259L; } + /** + * {@snippet : + * #define ERROR_IO_PENDING 997 + * } + */ + public static int ERROR_IO_PENDING() { + return (int)997L; + } /** * {@snippet : * #define ERROR_NOT_FOUND 1168 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/OVERLAPPED.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/OVERLAPPED.java new file mode 100644 index 00000000..129b9892 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/OVERLAPPED.java @@ -0,0 +1,16 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.kernel32; + +/** + * {@snippet : + * typedef struct _OVERLAPPED OVERLAPPED; + * } + */ +public final class OVERLAPPED extends _OVERLAPPED { + + // Suppresses default constructor, ensuring non-instantiability. + private OVERLAPPED() {} +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java new file mode 100644 index 00000000..fd578468 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java @@ -0,0 +1,216 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.kernel32; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct _OVERLAPPED { + * ULONG_PTR Internal; + * ULONG_PTR InternalHigh; + * union { + * struct { + * DWORD Offset; + * DWORD OffsetHigh; + * }; + * PVOID Pointer; + * }; + * HANDLE hEvent; + * }; + * } + */ +public class _OVERLAPPED { + + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_LONG_LONG$LAYOUT.withName("Internal"), + Constants$root.C_LONG_LONG$LAYOUT.withName("InternalHigh"), + MemoryLayout.unionLayout( + MemoryLayout.structLayout( + Constants$root.C_LONG$LAYOUT.withName("Offset"), + Constants$root.C_LONG$LAYOUT.withName("OffsetHigh") + ).withName("$anon$0"), + Constants$root.C_POINTER$LAYOUT.withName("Pointer") + ).withName("$anon$0"), + Constants$root.C_POINTER$LAYOUT.withName("hEvent") + ).withName("_OVERLAPPED"); + public static MemoryLayout $LAYOUT() { + return _OVERLAPPED.$struct$LAYOUT; + } + static final VarHandle Internal$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Internal")); + public static VarHandle Internal$VH() { + return _OVERLAPPED.Internal$VH; + } + /** + * Getter for field: + * {@snippet : + * ULONG_PTR Internal; + * } + */ + public static long Internal$get(MemorySegment seg) { + return (long)_OVERLAPPED.Internal$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * ULONG_PTR Internal; + * } + */ + public static void Internal$set(MemorySegment seg, long x) { + _OVERLAPPED.Internal$VH.set(seg, x); + } + public static long Internal$get(MemorySegment seg, long index) { + return (long)_OVERLAPPED.Internal$VH.get(seg.asSlice(index*sizeof())); + } + public static void Internal$set(MemorySegment seg, long index, long x) { + _OVERLAPPED.Internal$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle InternalHigh$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("InternalHigh")); + public static VarHandle InternalHigh$VH() { + return _OVERLAPPED.InternalHigh$VH; + } + /** + * Getter for field: + * {@snippet : + * ULONG_PTR InternalHigh; + * } + */ + public static long InternalHigh$get(MemorySegment seg) { + return (long)_OVERLAPPED.InternalHigh$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * ULONG_PTR InternalHigh; + * } + */ + public static void InternalHigh$set(MemorySegment seg, long x) { + _OVERLAPPED.InternalHigh$VH.set(seg, x); + } + public static long InternalHigh$get(MemorySegment seg, long index) { + return (long)_OVERLAPPED.InternalHigh$VH.get(seg.asSlice(index*sizeof())); + } + public static void InternalHigh$set(MemorySegment seg, long index, long x) { + _OVERLAPPED.InternalHigh$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle Offset$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("Offset")); + public static VarHandle Offset$VH() { + return _OVERLAPPED.Offset$VH; + } + /** + * Getter for field: + * {@snippet : + * DWORD Offset; + * } + */ + public static int Offset$get(MemorySegment seg) { + return (int)_OVERLAPPED.Offset$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * DWORD Offset; + * } + */ + public static void Offset$set(MemorySegment seg, int x) { + _OVERLAPPED.Offset$VH.set(seg, x); + } + public static int Offset$get(MemorySegment seg, long index) { + return (int)_OVERLAPPED.Offset$VH.get(seg.asSlice(index*sizeof())); + } + public static void Offset$set(MemorySegment seg, long index, int x) { + _OVERLAPPED.Offset$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle OffsetHigh$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("OffsetHigh")); + public static VarHandle OffsetHigh$VH() { + return _OVERLAPPED.OffsetHigh$VH; + } + /** + * Getter for field: + * {@snippet : + * DWORD OffsetHigh; + * } + */ + public static int OffsetHigh$get(MemorySegment seg) { + return (int)_OVERLAPPED.OffsetHigh$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * DWORD OffsetHigh; + * } + */ + public static void OffsetHigh$set(MemorySegment seg, int x) { + _OVERLAPPED.OffsetHigh$VH.set(seg, x); + } + public static int OffsetHigh$get(MemorySegment seg, long index) { + return (int)_OVERLAPPED.OffsetHigh$VH.get(seg.asSlice(index*sizeof())); + } + public static void OffsetHigh$set(MemorySegment seg, long index, int x) { + _OVERLAPPED.OffsetHigh$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle Pointer$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("Pointer")); + public static VarHandle Pointer$VH() { + return _OVERLAPPED.Pointer$VH; + } + /** + * Getter for field: + * {@snippet : + * PVOID Pointer; + * } + */ + public static MemorySegment Pointer$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)_OVERLAPPED.Pointer$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * PVOID Pointer; + * } + */ + public static void Pointer$set(MemorySegment seg, MemorySegment x) { + _OVERLAPPED.Pointer$VH.set(seg, x); + } + public static MemorySegment Pointer$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)_OVERLAPPED.Pointer$VH.get(seg.asSlice(index*sizeof())); + } + public static void Pointer$set(MemorySegment seg, long index, MemorySegment x) { + _OVERLAPPED.Pointer$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle hEvent$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hEvent")); + public static VarHandle hEvent$VH() { + return _OVERLAPPED.hEvent$VH; + } + /** + * Getter for field: + * {@snippet : + * HANDLE hEvent; + * } + */ + public static MemorySegment hEvent$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)_OVERLAPPED.hEvent$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * HANDLE hEvent; + * } + */ + public static void hEvent$set(MemorySegment seg, MemorySegment x) { + _OVERLAPPED.hEvent$VH.set(seg, x); + } + public static MemorySegment hEvent$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)_OVERLAPPED.hEvent$VH.get(seg.asSlice(index*sizeof())); + } + public static void hEvent$set(MemorySegment seg, long index, MemorySegment x) { + _OVERLAPPED.hEvent$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java index 3af32d2b..0dafcd77 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java @@ -24,6 +24,14 @@ public class WinUSB { public static int PIPE_TRANSFER_TIMEOUT() { return (int)3L; } + /** + * {@snippet : + * #define RAW_IO 7 + * } + */ + public static int RAW_IO() { + return (int)7L; + } public static MethodHandle WinUsb_Free$MH() { return RuntimeHelper.requireNonNull(constants$0.WinUsb_Free$MH,"WinUsb_Free"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java index ac40c327..24b02a99 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java @@ -14,8 +14,7 @@ import java.lang.foreign.SymbolLookup; import java.lang.invoke.MethodHandle; -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.*; /** * Native function calls for Kernel32. @@ -72,4 +71,61 @@ public static int DeviceIoControl(MemorySegment hDevice, int dwIoControlCode, Me throw new RuntimeException(ex); } } + + private static final FunctionDescriptor GetQueuedCompletionStatus$FUNC = + FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS, JAVA_INT); + + private static final MethodHandle GetQueuedCompletionStatus$MH = LINKER.downcallHandle( + LOOKUP.find("GetQueuedCompletionStatus").get(), + GetQueuedCompletionStatus$FUNC, + Win.LAST_ERROR_STATE + ); + + public static int GetQueuedCompletionStatus(MemorySegment CompletionPort, + MemorySegment lpNumberOfBytesTransferred, + MemorySegment lpCompletionKey, MemorySegment lpOverlapped, + int dwMilliseconds, MemorySegment lastErrorState) { + try { + return (int)GetQueuedCompletionStatus$MH.invokeExact(lastErrorState, CompletionPort, + lpNumberOfBytesTransferred, lpCompletionKey, lpOverlapped, dwMilliseconds); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + private static final FunctionDescriptor CreateIoCompletionPort$FUNC = + FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, JAVA_LONG, JAVA_INT); + + private static final MethodHandle CreateIoCompletionPort$MH = LINKER.downcallHandle( + LOOKUP.find("CreateIoCompletionPort").get(), + CreateIoCompletionPort$FUNC, + Win.LAST_ERROR_STATE + ); + + public static MemorySegment CreateIoCompletionPort(MemorySegment FileHandle, MemorySegment ExistingCompletionPort, + long CompletionKey, int NumberOfConcurrentThreads, MemorySegment lastErrorState) { + try { + return (MemorySegment) CreateIoCompletionPort$MH.invokeExact(lastErrorState, FileHandle, + ExistingCompletionPort, CompletionKey, NumberOfConcurrentThreads); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + private static final FunctionDescriptor CancelIoEx$FUNC = + FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS); + + private static final MethodHandle CancelIoEx$MH = LINKER.downcallHandle( + LOOKUP.find("CancelIoEx").get(), + CancelIoEx$FUNC, + Win.LAST_ERROR_STATE + ); + + public static int CancelIoEx(MemorySegment hFile, MemorySegment lpOverlapped, MemorySegment lastErrorState) { + try { + return (int) CancelIoEx$MH.invokeExact(lastErrorState, hFile, lpOverlapped); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } } From 85289b0bfced87d81e75bf1375584fb7be716336 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 19 Feb 2023 11:37:18 +0100 Subject: [PATCH 197/433] Minor cleanup (C++/Windows) --- reference/windows/USB/usb_device.cpp | 2 +- reference/windows/USB/usb_device.hpp | 3 ++- reference/windows/USB/usb_iostream.hpp | 4 ++-- reference/windows/USB/usb_registry.cpp | 6 +++--- reference/windows/USB/usb_registry.hpp | 6 +++--- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp index aa08049c..436c23d2 100644 --- a/reference/windows/USB/usb_device.cpp +++ b/reference/windows/USB/usb_device.cpp @@ -386,7 +386,7 @@ std::unique_ptr usb_device::open_output_stream(int endpoint_number return std::unique_ptr(new usb_ostream(registry_->get_shared_ptr(this), endpoint_number)); } -void usb_device::add_completion_handler(OVERLAPPED* overlapped, std::function* completion_handler) { +void usb_device::add_completion_handler(OVERLAPPED* overlapped, usb_io_callback* completion_handler) { registry_->add_completion_handler(overlapped, completion_handler); } diff --git a/reference/windows/USB/usb_device.hpp b/reference/windows/USB/usb_device.hpp index 2e965315..e4168021 100644 --- a/reference/windows/USB/usb_device.hpp +++ b/reference/windows/USB/usb_device.hpp @@ -25,6 +25,7 @@ #include "configuration.hpp" +typedef std::function usb_io_callback; /** * USB control request type. @@ -266,7 +267,7 @@ class usb_device { } void configure_for_async_io(usb_direction direction, int endpoint_number); - void add_completion_handler(OVERLAPPED* overlapped, std::function* completion_handler); + void add_completion_handler(OVERLAPPED* overlapped, usb_io_callback* completion_handler); void remove_completion_handler(OVERLAPPED* overlapped); void submit_transfer_in(int endpoint_number, uint8_t* buffer, int buffer_len, OVERLAPPED* overlapped); void submit_transfer_out(int endpoint_number, uint8_t* data, int data_len, OVERLAPPED* overlapped); diff --git a/reference/windows/USB/usb_iostream.hpp b/reference/windows/USB/usb_iostream.hpp index 5e60516d..db3dcac2 100644 --- a/reference/windows/USB/usb_iostream.hpp +++ b/reference/windows/USB/usb_iostream.hpp @@ -38,7 +38,7 @@ class usb_istreambuf : public std::streambuf { /// buffer for recevied data uint8_t* buffer; /// IO completion handler - std::function io_completion; + usb_io_callback io_completion; /// data structure for overlapped requests OVERLAPPED overlapped; /// indicates if the request has completed @@ -109,7 +109,7 @@ class usb_ostreambuf : public std::streambuf { /// overlapped data structure OVERLAPPED overlapped; /// IO completion handler - std::function io_completion; + usb_io_callback io_completion; DWORD result_code() { return static_cast(overlapped.Internal); diff --git a/reference/windows/USB/usb_registry.cpp b/reference/windows/USB/usb_registry.cpp index 57cd3d84..bd64dd19 100644 --- a/reference/windows/USB/usb_registry.cpp +++ b/reference/windows/USB/usb_registry.cpp @@ -396,7 +396,7 @@ void usb_registry::async_io_run() { if (overlapped == nullptr) return; // registry is closing - std::function* completion_handler = get_completion_handler(overlapped); + usb_io_callback* completion_handler = get_completion_handler(overlapped); if (overlapped == nullptr) continue; // might be completion from synchronous operation @@ -415,7 +415,7 @@ void usb_registry::add_to_completion_port(HANDLE handle) { } } -void usb_registry::add_completion_handler(OVERLAPPED* overlapped, std::function* completion_handler) { +void usb_registry::add_completion_handler(OVERLAPPED* overlapped, usb_io_callback* completion_handler) { std::lock_guard lock(async_io_mutex); async_io_completion_handlers.insert(std::pair(overlapped, completion_handler)); @@ -427,7 +427,7 @@ void usb_registry::remove_completion_handler(OVERLAPPED* overlapped) { async_io_completion_handlers.erase(overlapped); } -std::function* usb_registry::get_completion_handler(OVERLAPPED* overlapped) { +usb_io_callback* usb_registry::get_completion_handler(OVERLAPPED* overlapped) { std::lock_guard lock(async_io_mutex); auto it = async_io_completion_handlers.find(overlapped); diff --git a/reference/windows/USB/usb_registry.hpp b/reference/windows/USB/usb_registry.hpp index 4f3f9129..fe66b060 100644 --- a/reference/windows/USB/usb_registry.hpp +++ b/reference/windows/USB/usb_registry.hpp @@ -68,9 +68,9 @@ class usb_registry { void async_io_run(); void add_to_completion_port(HANDLE); - void add_completion_handler(OVERLAPPED* overlapped, std::function* completion_handler); + void add_completion_handler(OVERLAPPED* overlapped, usb_io_callback* completion_handler); void remove_completion_handler(OVERLAPPED* overlapped); - std::function* get_completion_handler(OVERLAPPED* overlapped); + usb_io_callback* get_completion_handler(OVERLAPPED* overlapped); std::thread monitor_thread; @@ -83,7 +83,7 @@ class usb_registry { std::thread async_io_thread; std::mutex async_io_mutex; HANDLE async_io_completion_port; - std::map*> async_io_completion_handlers; + std::map async_io_completion_handlers; friend class usb_device; friend class usb_istreambuf; From 6eb1eb49c3e78c8f5d6819a224fb52502630580b Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 19 Feb 2023 12:49:43 +0100 Subject: [PATCH 198/433] High throughput output stream (Windows) --- .../windows/WindowsEndpointOutputStream.java | 254 ++++++++++++++++++ .../usb/windows/WindowsUSBDevice.java | 29 ++ 2 files changed, 283 insertions(+) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java new file mode 100644 index 00000000..62de1e8c --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java @@ -0,0 +1,254 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.windows; + +import net.codecrete.usb.USBDirection; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.util.Arrays; +import java.util.concurrent.ArrayBlockingQueue; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static net.codecrete.usb.windows.WindowsUSBException.throwException; + +/** + * Output stream for bulk endpoints – optimized for high throughput. + * + *

+ * Multiple asynchronous transfer OUT requests are submitted to achieve a good + * degree of concurrency between the USB communication handled by the operating + * system and the producing application code. The number of requests is limited + * in order to retain the flow control and keep memory usage at a reasonable size. + *

+ *

+ * For thread synchronization (between the background thread handling IO completion + * and the producing application thread) a blocking queue is used. It is prefilled with + * requests ready to be used for a transfer. The background thread adds the completed + * requests back to this queue. The producing application thread waits until a request + * is available for use. + *

+ */ +public class WindowsEndpointOutputStream extends OutputStream { + + private static final int MAX_OUTSTANDING_REQUESTS = 4; + + private WindowsUSBDevice device; + private final int endpointNumber; + private final Arena arena; + // Endpoint's packet size + private final int packetSize; + // Size of buffers (multiple of packet size) + private final int bufferSize; + // Blocking queue of available requests (to limit the number of submitted requests) + private final ArrayBlockingQueue availableRequestQueue; + private boolean needsZlp; + private TransferRequest currentRequest; + private int writeOffset; + private int numOutstandingRequests; + private boolean hasError; + + + /** + * Creates a new instance + * @param device USB device + * @param endpointNumber endpoint number + */ + WindowsEndpointOutputStream(WindowsUSBDevice device, int endpointNumber) { + this.device = device; + this.endpointNumber = endpointNumber; + + packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize(); + bufferSize = packetSize; + + device.configureForAsyncIo(endpointNumber, USBDirection.OUT); + + availableRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); + arena = Arena.openShared(); + + // prefill request queue + for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { + final var request = new TransferRequest(); + request.buffer = arena.allocate(bufferSize, 8); + request.completionHandler = (result, size) -> onCompletion(request, result); + + if (i == 0) { + currentRequest = request; + } else { + availableRequestQueue.add(request); + } + } + } + + @Override + public void close() throws IOException { + if (isClosed()) + return; + + if (!hasError) + flush(); + else + waitForOutstandingRequests(); + + device = null; + availableRequestQueue.clear(); + currentRequest = null; + arena.close(); + } + + @Override + public void write(int b) throws IOException { + if (isClosed()) + throw new IOException("Bulk endpoint output stream has been closed"); + + currentRequest.buffer.set(JAVA_BYTE, writeOffset, (byte)b); + writeOffset += 1; + if (writeOffset == bufferSize) + submitTransfer(writeOffset); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (isClosed()) + throw new IOException("Bulk endpoint output stream has been closed"); + + while (len > 0) { + int chunkSize = Math.min(len, bufferSize - writeOffset); + MemorySegment.copy(b, off, currentRequest.buffer, JAVA_BYTE, writeOffset, chunkSize); + writeOffset += chunkSize; + off += chunkSize; + len -= chunkSize; + + if (writeOffset == bufferSize) + submitTransfer(writeOffset); + } + } + + @Override + public void flush() throws IOException { + if (isClosed()) + throw new IOException("Bulk endpoint output stream has been closed"); + + if (writeOffset > 0) + submitTransfer(writeOffset); + + if (needsZlp) + submitTransfer(0); + + waitForOutstandingRequests(); + } + + private boolean isClosed() { + return device == null; + } + + /** + * Submits a request for transfer and set a new request + * as the current one, possibly waiting until it is ready. + *

+ * Throws an exception if the request to be reused has completed with an error on the + * previous operation. The exception is suppressed if {@code hasError} flag is set. + *

+ * + * @param size size of data to be transmitted + */ + private void submitTransfer(int size) throws IOException { + try { + device.submitTransferOut(endpointNumber, currentRequest.buffer, size, currentRequest.completionHandler); + + synchronized (this) { + numOutstandingRequests += 1; + } + + needsZlp = size == packetSize; + writeOffset = 0; + currentRequest = waitForAvailableRequest(); + + } catch (Throwable t) { + hasError = true; + close(); + throw t; + } + } + + /** + * Wait until all outstanding requests have been completed. + *

+ * Throws an exception if any of the requests has completed with an error. + * The exception is suppressed if {@code hasError} flag is set. + *

+ */ + private void waitForOutstandingRequests() { + // Wait until all buffers have been transmitted by removing them from the + // queue and reinserting them. + + int numRequests; + synchronized (this) { + numRequests = numOutstandingRequests + availableRequestQueue.size(); + } + + if (numRequests == 0) + return; + + var requests = new TransferRequest[numRequests]; + for (int i = 0; i < numRequests; i++) + requests[i] = waitForAvailableRequest(); + + // reinsert the requests + if (!hasError) + availableRequestQueue.addAll(Arrays.asList(requests)); + } + + /** + * Wait until one of the allocated requests is available for use. + *

+ * Throws an exception if the request to be reused has completed with an error on the + * previous operation. The exception is suppressed if {@code hasError} flag is set. + *

+ * @return request ready for use + */ + private TransferRequest waitForAvailableRequest() { + while (true) { + try { + TransferRequest request = availableRequestQueue.take(); + + // check for error + int result = request.result; + if (result != 0 && !hasError) { + request.result = 0; + throwException(result, "error reading from USB endpoint"); + } + + return request; + + } catch (InterruptedException e) { + // ignore and retry + } + } + } + + /** + * Called by the asynchronous IO completion handler. + * + * @param request the completed request + * @param result the request result code + */ + private synchronized void onCompletion(TransferRequest request, int result) { + request.result = result; + availableRequestQueue.add(request); + numOutstandingRequests -= 1; + } + + private static class TransferRequest { + MemorySegment buffer; + int result; + WindowsUSBDevice.AsyncIOCompletion completionHandler; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 3b780c78..649b0123 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -17,6 +17,7 @@ import net.codecrete.usb.windows.winsdk.WinUSB2; import java.io.InputStream; +import java.io.OutputStream; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentScope; @@ -334,6 +335,26 @@ public byte[] transferIn(int endpointNumber, int timeout) { } } + synchronized long submitTransferOut(int endpointNumber, MemorySegment data, int dataSize, AsyncIOCompletion completion) { + var endpoint = getEndpoint(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); + var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); + + try (var arena = Arena.openConfined()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + var overlapped = getOverlapped(completion); + + // submit transfer + if (WinUSB2.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), data, dataSize, + NULL, overlapped, lastErrorState) == 0) { + int err = Win.getLastError(lastErrorState); + if (err != Kernel32.ERROR_IO_PENDING()) + throwException(err, "Submitting transfer OUT failed"); + } + + return overlapped.address(); + } + } + synchronized long submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, AsyncIOCompletion completion) { var endpoint = getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); @@ -419,6 +440,14 @@ public InputStream openInputStream(int endpointNumber) { return new WindowsEndpointInputStream(this, endpointNumber); } + @Override + public OutputStream openOutputStream(int endpointNumber) { + // check that endpoint number is valid + getEndpoint(endpointNumber, USBDirection.OUT, USBTransferType.BULK, null); + + return new WindowsEndpointOutputStream(this, endpointNumber); + } + private InterfaceHandle getInterfaceHandle(int interfaceNumber) { for (var intfHandle : interfaceHandles_) { if (intfHandle.interfaceNumber == interfaceNumber) From 9a1d3f3efd3ab7dd934fe9dc6473ed4ec97b924e Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 19 Feb 2023 17:23:04 +0100 Subject: [PATCH 199/433] Consistent parameter order / abortTransfer() function --- .../java/net/codecrete/usb/USBDevice.java | 10 +++++ .../codecrete/usb/common/USBDeviceImpl.java | 42 +++---------------- .../codecrete/usb/linux/LinuxUSBDevice.java | 14 ++++--- .../codecrete/usb/macos/MacosUSBDevice.java | 6 +++ .../windows/WindowsEndpointInputStream.java | 29 ++++--------- .../windows/WindowsEndpointOutputStream.java | 2 +- .../usb/windows/WindowsUSBDevice.java | 36 ++++++++++------ .../codecrete/usb/windows/winsdk/WinUSB2.java | 15 +++++++ .../java/net/codecrete/usb/SpeedTest.java | 2 +- .../codecrete/usb/sample/LogicAnalyzer.java | 3 +- 10 files changed, 83 insertions(+), 76 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index a0f28721..85918f5c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -302,6 +302,16 @@ public interface USBDevice { */ InputStream openInputStream(int endpointNumber); + /** + * Aborts all transfers on an endpoint. + *

+ * This operation is not valid on the control endpoint 0. + *

+ * @param direction endpoint direction + * @param endpointNumber endpoint number (in the range between 1 and 127) + */ + void abortTransfers(USBDirection direction, int endpointNumber); + /** * Clears an endpoint's halt condition. *

diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 9921cdff..09b6e651 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -221,46 +221,16 @@ public USBEndpoint getEndpoint(USBDirection direction, int endpointNumber) { return null; } - /** - * Checks if the specified endpoint is valid for communication and returns the endpoint address. - * - * @param endpointNumber endpoint number (1 to 127) - * @param direction transfer direction - * @param transferType1 transfer type 1 - * @param transferType2 transfer type 2 (or {@code null}) - * @return endpoint address - */ - protected byte getEndpointAddress(int endpointNumber, USBDirection direction, - USBTransferType transferType1, USBTransferType transferType2) { - - checkIsOpen(); - - if (endpointNumber >= 1 && endpointNumber <= 127) { - for (var intf : interfaces_) { - if (intf.isClaimed()) { - for (var ep : intf.alternate().endpoints()) { - if (ep.number() == endpointNumber && ep.direction() == direction - && (ep.transferType() == transferType1 || ep.transferType() == transferType2)) - return (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)); - } - } - } - } - - throwInvalidEndpointException(endpointNumber, direction, transferType1, transferType2); - throw new AssertionError("not reached"); - } - /** * Checks if the specified endpoint is valid for communication and returns the endpoint. * - * @param endpointNumber endpoint number (1 to 127) * @param direction transfer direction + * @param endpointNumber endpoint number (1 to 127) * @param transferType1 transfer type 1 * @param transferType2 transfer type 2 (or {@code null}) * @return endpoint */ - protected EndpointInfo getEndpoint(int endpointNumber, USBDirection direction, + protected EndpointInfo getEndpoint(USBDirection direction, int endpointNumber, USBTransferType transferType1, USBTransferType transferType2) { checkIsOpen(); @@ -279,11 +249,11 @@ protected EndpointInfo getEndpoint(int endpointNumber, USBDirection direction, } } - throwInvalidEndpointException(endpointNumber, direction, transferType1, transferType2); + throwInvalidEndpointException(direction, endpointNumber, transferType1, transferType2); return null; // will never be reached } - protected void throwInvalidEndpointException(int endpointNumber, USBDirection direction, + protected void throwInvalidEndpointException(USBDirection direction, int endpointNumber, USBTransferType transferType1, USBTransferType transferType2) { String transferTypeDesc; if (transferType2 == null) @@ -336,7 +306,7 @@ public byte[] transferIn(int endpointNumber) { @Override public OutputStream openOutputStream(int endpointNumber) { // check that endpoint number is valid - var endpointInfo = getEndpoint(endpointNumber, USBDirection.OUT, USBTransferType.BULK, null); + var endpointInfo = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, null); var endpoint = getInterface(endpointInfo.interfaceNumber).alternate().getEndpoint(endpointNumber, USBDirection.OUT); return new EndpointOutputStream(this, endpointNumber, endpoint.packetSize()); } @@ -344,7 +314,7 @@ public OutputStream openOutputStream(int endpointNumber) { @Override public InputStream openInputStream(int endpointNumber) { // check that endpoint number is valid - getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, null); + getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, null); return new EndpointInputStream(this, endpointNumber); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 43cf8cca..071929f6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -206,13 +206,13 @@ private MemorySegment createBulkTransfer(Arena arena, byte endpointAddress, Memo @Override public void transferOut(int endpointNumber, byte[] data, int timeout) { - var endpointAddress = getEndpointAddress(endpointNumber, USBDirection.OUT, + var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); try (var arena = Arena.openConfined()) { var buffer = arena.allocate(data.length); buffer.copyFrom(MemorySegment.ofArray(data)); - var transfer = createBulkTransfer(arena, endpointAddress, buffer, timeout); + var transfer = createBulkTransfer(arena, endpoint.endpointAddress(), buffer, timeout); var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); int res = IO.ioctl(fd, USBDevFS.BULK, transfer, errnoState); @@ -227,7 +227,7 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { @Override public byte[] transferIn(int endpointNumber, int timeout) { - var endpoint = getEndpoint(endpointNumber, USBDirection.IN, + var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); try (var arena = Arena.openConfined()) { @@ -250,11 +250,11 @@ public byte[] transferIn(int endpointNumber, int timeout) { @Override public void clearHalt(USBDirection direction, int endpointNumber) { - var endpointAddress = getEndpointAddress(endpointNumber, direction, + var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); try (var arena = Arena.openConfined()) { - var endpointAddrSegment = arena.allocate(JAVA_INT, endpointAddress & 0xff); + var endpointAddrSegment = arena.allocate(JAVA_INT, endpoint.endpointAddress() & 0xff); var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); int res = IO.ioctl(fd, USBDevFS.CLEAR_HALT, endpointAddrSegment, errnoState); if (res < 0) @@ -262,4 +262,8 @@ public void clearHalt(USBDirection direction, int endpointNumber) { } } + @Override + public synchronized void abortTransfers(USBDirection direction, int endpointNumber) { + throw new UnsupportedOperationException("not implemented yet"); + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 5d549c02..23e1f4e3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -615,6 +615,12 @@ public void clearHalt(USBDirection direction, int endpointNumber) { throwException(ret, "Clearing halt condition failed"); } + + @Override + public synchronized void abortTransfers(USBDirection direction, int endpointNumber) { + throw new UnsupportedOperationException("not implemented yet"); + } + @Override public InputStream openInputStream(int endpointNumber) { // check that endpoint number is valid diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java index 6404c653..de6a9fed 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java @@ -39,19 +39,18 @@ public class WindowsEndpointInputStream extends InputStream { private WindowsUSBDevice device; private final int endpointNumber; - // Arena to allocate buffers and completion handlers + /// Arena to allocate buffers and completion handlers private final Arena arena; - // Size of buffers (multiple of packet size) + /// Size of buffers (multiple of packet size) private final int bufferSize; - // Queue of completed requests + /// Queue of completed requests private final ArrayBlockingQueue completedRequestQueue; - // Number of outstanding requests (includes requests pending with the - // operating system and requests in the completed queue) + /// Number of outstanding requests (includes requests pending with the + /// operating system and requests in the completed queue) private int numOutstandingRequests; - // Request and buffer being currently read from - private TransferRequest[] allRequests; + /// Request and buffer being currently read from private TransferRequest currentRequest; - // Read offset within current request + /// Read offset within current request private int readOffset; /** @@ -67,15 +66,13 @@ public class WindowsEndpointInputStream extends InputStream { bufferSize = 4 * device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); completedRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); - device.configureForAsyncIo(endpointNumber, USBDirection.IN); + device.configureForAsyncIo(USBDirection.IN, endpointNumber); // create all requests and submit all except one - allRequests = new TransferRequest[MAX_OUTSTANDING_REQUESTS]; arena = Arena.openShared(); try { for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { final var request = new TransferRequest(); - allRequests[i] = request; request.buffer = arena.allocate(bufferSize, 8); request.completionHandler = (result, size) -> onCompletion(request, result, size); @@ -98,25 +95,17 @@ public void close() throws IOException { return; // abort all transfers on endpoint - abortAllRequests(); + device.abortTransfers(USBDirection.IN, endpointNumber); device = null; collectOutstandingRequests(); } - private void abortAllRequests() { - for (var request : allRequests) { - if (request != null && request.cancelHandle != 0) - device.cancelTransfer(endpointNumber, USBDirection.IN, request.cancelHandle); - } - } - private void collectOutstandingRequests() { // wait until completion handlers have been called while (numOutstandingRequests > 0) waitForRequestCompletion(); - allRequests = null; completedRequestQueue.clear(); currentRequest = null; arena.close(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java index 62de1e8c..06942c15 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java @@ -68,7 +68,7 @@ public class WindowsEndpointOutputStream extends OutputStream { packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize(); bufferSize = packetSize; - device.configureForAsyncIo(endpointNumber, USBDirection.OUT); + device.configureForAsyncIo(USBDirection.OUT, endpointNumber); availableRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); arena = Arena.openShared(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 649b0123..13935284 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -275,7 +275,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { public void transferOut(int endpointNumber, byte[] data, int timeout) { checkIsOpen(); - var endpoint = getEndpoint(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); + var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.openConfined()) { @@ -305,7 +305,7 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { @Override public byte[] transferIn(int endpointNumber, int timeout) { - var endpoint = getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); + var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.openConfined()) { @@ -336,7 +336,7 @@ public byte[] transferIn(int endpointNumber, int timeout) { } synchronized long submitTransferOut(int endpointNumber, MemorySegment data, int dataSize, AsyncIOCompletion completion) { - var endpoint = getEndpoint(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); + var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.openConfined()) { @@ -356,7 +356,7 @@ synchronized long submitTransferOut(int endpointNumber, MemorySegment data, int } synchronized long submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, AsyncIOCompletion completion) { - var endpoint = getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); + var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.openConfined()) { @@ -381,12 +381,12 @@ synchronized long submitTransferIn(int endpointNumber, MemorySegment buffer, int * If the specific request is not found, the error is silently ignored. Such errors * are likely to happen due to concurrency issues. *

- * @param endpointNumber endpoint number * @param direction endpoint direction + * @param endpointNumber endpoint number * @param cancelHandle request's cancel handle returned when the request was submitted */ - synchronized void cancelTransfer(int endpointNumber, USBDirection direction, long cancelHandle) { - var endpoint = getEndpoint(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); + synchronized void cancelTransfer(USBDirection direction, int endpointNumber, long cancelHandle) { + var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.openConfined()) { @@ -401,8 +401,8 @@ synchronized void cancelTransfer(int endpointNumber, USBDirection direction, lon } } - synchronized void configureForAsyncIo(int endpointNumber, USBDirection direction) { - var endpoint = getEndpoint(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); + synchronized void configureForAsyncIo(USBDirection direction, int endpointNumber) { + var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.openConfined()) { @@ -422,7 +422,7 @@ synchronized void configureForAsyncIo(int endpointNumber, USBDirection direction @Override public void clearHalt(USBDirection direction, int endpointNumber) { - var endpoint = getEndpoint(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); + var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.openConfined()) { @@ -432,10 +432,22 @@ public void clearHalt(USBDirection direction, int endpointNumber) { } } + @Override + public void abortTransfers(USBDirection direction, int endpointNumber) { + var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); + var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); + + try (var arena = Arena.openConfined()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + if (WinUSB2.WinUsb_AbortPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), lastErrorState) == 0) + throwLastError(lastErrorState, "Aborting transfers on endpoint failed"); + } + } + @Override public InputStream openInputStream(int endpointNumber) { // check that endpoint number is valid - getEndpoint(endpointNumber, USBDirection.IN, USBTransferType.BULK, null); + getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, null); return new WindowsEndpointInputStream(this, endpointNumber); } @@ -443,7 +455,7 @@ public InputStream openInputStream(int endpointNumber) { @Override public OutputStream openOutputStream(int endpointNumber) { // check that endpoint number is valid - getEndpoint(endpointNumber, USBDirection.OUT, USBTransferType.BULK, null); + getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, null); return new WindowsEndpointOutputStream(this, endpointNumber); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java index da78af10..834dd016 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java @@ -155,4 +155,19 @@ public static int WinUsb_ResetPipe(MemorySegment InterfaceHandle, byte PipeID, M throw new RuntimeException(ex); } } + private static final FunctionDescriptor WinUsb_AbortPipe$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE); + + private static final MethodHandle WinUsb_AbortPipe$MH = LINKER.downcallHandle( + LOOKUP.find("WinUsb_AbortPipe").get(), + WinUsb_ResetPipe$FUNC, + Win.LAST_ERROR_STATE + ); + + public static int WinUsb_AbortPipe(MemorySegment InterfaceHandle, byte PipeID, MemorySegment lastErrorState) { + try { + return (int)WinUsb_AbortPipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java index 38336c71..cb869346 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java @@ -36,7 +36,7 @@ void loopback_isFast() throws Throwable { assertArrayEquals(sampleData, reader.resultNow()); double throughput = 2.0 * numBytes / (end - start); - double expectedThroughput = isHighSpeed ? 19000 : 500; + double expectedThroughput = isHighSpeed ? 15000 : 500; System.out.printf("Throughput: expected ≥%,.0f KB/s, actual %,.0f KB/s%n", expectedThroughput, throughput); assertTrue(throughput >= expectedThroughput, "Expected throughput not achieved"); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java b/java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java index 5c3dae18..30ca96dc 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java @@ -223,7 +223,7 @@ void saveSamples() { void stopAcquisition() { // stop the acquisition by halting the bulk endpoint and clearing the halt stopped = true; - device.clearHalt(USBDirection.IN, EP); + device.abortTransfers(USBDirection.IN, EP); } void detectBufferOverrun() { @@ -263,6 +263,7 @@ void checkFirmware() { } device.open(); + device.claimInterface(0); byte[] cmd = new byte[] { 1 }; device.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.DEVICE, 0xa0, 0xe600, 0x0000), cmd); From 4ae800c451cbbd69aa8422d48a5ee1f032fff559 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 19 Feb 2023 17:55:15 +0100 Subject: [PATCH 200/433] Prepare for refactoring of common code --- .../usb/common/AsyncEndpointInputStream.java | 214 +++++++++++++++ .../usb/common/AsyncEndpointOutputStream.java | 255 ++++++++++++++++++ .../usb/common/AsyncIOCompletion.java | 27 ++ .../usb/macos/MacosEndpointInputStream.java | 3 +- .../usb/macos/MacosEndpointOutputStream.java | 3 +- .../codecrete/usb/macos/MacosUSBDevice.java | 13 +- .../windows/WindowsEndpointInputStream.java | 193 +------------ .../windows/WindowsEndpointOutputStream.java | 238 +--------------- .../usb/windows/WindowsUSBDevice.java | 13 +- 9 files changed, 518 insertions(+), 441 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/AsyncEndpointInputStream.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/AsyncEndpointOutputStream.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/AsyncIOCompletion.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncEndpointInputStream.java new file mode 100644 index 00000000..20d7a21f --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncEndpointInputStream.java @@ -0,0 +1,214 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +import net.codecrete.usb.USBDirection; +import net.codecrete.usb.USBException; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.util.concurrent.ArrayBlockingQueue; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; + +/** + * Input stream for bulk endpoints – optimized for high throughput. + * + *

+ * Multiple asynchronous transfer IN requests are submitted to achieve a good + * degree of concurrency between the USB communication handled by the operating + * system and the consuming application code. + *

+ *

+ * For thread synchronization (between the background thread handling IO completion + * and the consuming application thread) a blocking queue is used. When an transfer IN + * requests completes, the background thread adds it to the queue. The consuming code + * waits for the next item in the queue. + *

+ */ +public abstract class AsyncEndpointInputStream extends InputStream { + + private static final int MAX_OUTSTANDING_REQUESTS = 8; + + protected USBDeviceImpl device; + protected final int endpointNumber; + // Arena to allocate buffers and completion handlers + protected final Arena arena; + // Size of buffers (multiple of packet size) + protected final int bufferSize; + // Queue of completed requests + private final ArrayBlockingQueue completedRequestQueue; + // Number of outstanding requests (includes requests pending with the + // operating system and requests in the completed queue) + private int numOutstandingRequests; + // Request and buffer being currently read from + private TransferRequest currentRequest; + // Read offset within current request + private int readOffset; + + /** + * Creates a new instance + * + * @param device USB device + * @param endpointNumber endpoint number + */ + protected AsyncEndpointInputStream(USBDeviceImpl device, int endpointNumber) { + this.device = device; + this.endpointNumber = endpointNumber; + + bufferSize = 4 * device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); + completedRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); + + // create all requests and submit all except one + arena = Arena.openShared(); + try { + for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { + final var request = new TransferRequest(); + request.buffer = arena.allocate(bufferSize, 8); + request.completionHandler = (result, size) -> onCompletion(request, result, size); + + if (i == 0) { + currentRequest = request; + } else { + submitRequest(request); + } + } + } catch (Throwable t) { + collectOutstandingRequests(); + throw t; + } + } + + @SuppressWarnings("RedundantThrows") + @Override + public void close() throws IOException { + if (isClosed()) + return; + + // abort all transfers on endpoint + try { + device.abortTransfers(USBDirection.IN, endpointNumber); + } catch (USBException e) { + // If aborting the transfer is not possible, the device has + // likely been closed or unplugged. So all outstanding + // requests will terminate anyway. + } + device = null; + + collectOutstandingRequests(); + } + + private void collectOutstandingRequests() { + // wait until completion handlers have been called + while (numOutstandingRequests > 0) + waitForRequestCompletion(); + + completedRequestQueue.clear(); + currentRequest = null; + arena.close(); + } + + @Override + public int read() throws IOException { + if (isClosed()) + return -1; + + if (available() == 0) + receiveMoreData(); + + int b = currentRequest.buffer.get(JAVA_BYTE, readOffset) & 0xff; + readOffset += 1; + return b; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (isClosed()) + return -1; + + if (available() == 0) + receiveMoreData(); + + // copy data to receiving buffer + int n = Math.min(len, currentRequest.resultSize - readOffset); + MemorySegment.copy(currentRequest.buffer, readOffset, MemorySegment.ofArray(b), off, n); + readOffset += n; + + // TODO: poll for further completed requests if 'n' is less than 'len' + + return n; + } + + @SuppressWarnings("RedundantThrows") + @Override + public int available() throws IOException { + return currentRequest.resultSize - readOffset; + } + + private boolean isClosed() { + return device == null; + } + + private void receiveMoreData() throws IOException { + try { + // loop until non-ZLP has been received + do { + submitRequest(currentRequest); + + currentRequest = waitForRequestCompletion(); + readOffset = 0; + + // check for error + if (currentRequest.result != 0) + throwException(currentRequest.result, "error reading from USB endpoint"); + + } while (currentRequest.resultSize == 0); + + } catch (Throwable t) { + close(); + throw t; + } + } + + void submitRequest(TransferRequest request) { + submitTransferIn(request.buffer, bufferSize, request.completionHandler); + numOutstandingRequests += 1; + } + + protected abstract void submitTransferIn(MemorySegment buffer, int bufferSize, AsyncIOCompletion completion); + + protected abstract void throwException(int errorCode, String message); + + void onCompletion(TransferRequest request, int result, int size) { + request.result = result; + request.resultSize = size; + completedRequestQueue.add(request); + } + + TransferRequest waitForRequestCompletion() { + while (true) { + try { + TransferRequest request = completedRequestQueue.take(); + numOutstandingRequests -= 1; + return request; + + } catch (InterruptedException e) { + // ignore and retry + } + } + } + + private static class TransferRequest { + MemorySegment buffer; + int result; + int resultSize; + AsyncIOCompletion completionHandler; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncEndpointOutputStream.java new file mode 100644 index 00000000..21cdbee4 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncEndpointOutputStream.java @@ -0,0 +1,255 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +import net.codecrete.usb.USBDirection; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.util.Arrays; +import java.util.concurrent.ArrayBlockingQueue; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; + +/** + * Output stream for bulk endpoints – optimized for high throughput. + * + *

+ * Multiple asynchronous transfer OUT requests are submitted to achieve a good + * degree of concurrency between the USB communication handled by the operating + * system and the producing application code. The number of requests is limited + * in order to retain the flow control and keep memory usage at a reasonable size. + *

+ *

+ * For thread synchronization (between the background thread handling IO completion + * and the producing application thread) a blocking queue is used. It is prefilled with + * requests ready to be used for a transfer. The background thread adds the completed + * requests back to this queue. The producing application thread waits until a request + * is available for use. + *

+ */ +public abstract class AsyncEndpointOutputStream extends OutputStream { + + private static final int MAX_OUTSTANDING_REQUESTS = 4; + + protected USBDeviceImpl device; + protected final int endpointNumber; + protected final Arena arena; + // Endpoint's packet size + private final int packetSize; + // Size of buffers (multiple of packet size) + private final int bufferSize; + // Blocking queue of available requests (to limit the number of submitted requests) + private final ArrayBlockingQueue availableRequestQueue; + private boolean needsZlp; + private TransferRequest currentRequest; + private int writeOffset; + private int numOutstandingRequests; + private boolean hasError; + + + /** + * Creates a new instance + * @param device USB device + * @param endpointNumber endpoint number + */ + protected AsyncEndpointOutputStream(USBDeviceImpl device, int endpointNumber) { + this.device = device; + this.endpointNumber = endpointNumber; + + packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize(); + bufferSize = packetSize; + + availableRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); + arena = Arena.openShared(); + + // prefill request queue + for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { + final var request = new TransferRequest(); + request.buffer = arena.allocate(bufferSize, 8); + request.completionHandler = (result, size) -> onCompletion(request, result); + + if (i == 0) { + currentRequest = request; + } else { + availableRequestQueue.add(request); + } + } + } + + @Override + public void close() throws IOException { + if (isClosed()) + return; + + if (!hasError) + flush(); + else + waitForOutstandingRequests(); + + device = null; + availableRequestQueue.clear(); + currentRequest = null; + arena.close(); + } + + @Override + public void write(int b) throws IOException { + if (isClosed()) + throw new IOException("Bulk endpoint output stream has been closed"); + + currentRequest.buffer.set(JAVA_BYTE, writeOffset, (byte)b); + writeOffset += 1; + if (writeOffset == bufferSize) + submitTransfer(writeOffset); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (isClosed()) + throw new IOException("Bulk endpoint output stream has been closed"); + + while (len > 0) { + int chunkSize = Math.min(len, bufferSize - writeOffset); + MemorySegment.copy(b, off, currentRequest.buffer, JAVA_BYTE, writeOffset, chunkSize); + writeOffset += chunkSize; + off += chunkSize; + len -= chunkSize; + + if (writeOffset == bufferSize) + submitTransfer(writeOffset); + } + } + + @Override + public void flush() throws IOException { + if (isClosed()) + throw new IOException("Bulk endpoint output stream has been closed"); + + if (writeOffset > 0) + submitTransfer(writeOffset); + + if (needsZlp) + submitTransfer(0); + + waitForOutstandingRequests(); + } + + private boolean isClosed() { + return device == null; + } + + /** + * Submits a request for transfer and set a new request + * as the current one, possibly waiting until it is ready. + *

+ * Throws an exception if the request to be reused has completed with an error on the + * previous operation. The exception is suppressed if {@code hasError} flag is set. + *

+ * + * @param size size of data to be transmitted + */ + private void submitTransfer(int size) throws IOException { + try { + submitTransferOut(currentRequest.buffer, size, currentRequest.completionHandler); + + synchronized (this) { + numOutstandingRequests += 1; + } + + needsZlp = size == packetSize; + writeOffset = 0; + currentRequest = waitForAvailableRequest(); + + } catch (Throwable t) { + hasError = true; + close(); + throw t; + } + } + + /** + * Wait until all outstanding requests have been completed. + *

+ * Throws an exception if any of the requests has completed with an error. + * The exception is suppressed if {@code hasError} flag is set. + *

+ */ + private void waitForOutstandingRequests() { + // Wait until all buffers have been transmitted by removing them from the + // queue and reinserting them. + + int numRequests; + synchronized (this) { + numRequests = numOutstandingRequests + availableRequestQueue.size(); + } + + if (numRequests == 0) + return; + + var requests = new TransferRequest[numRequests]; + for (int i = 0; i < numRequests; i++) + requests[i] = waitForAvailableRequest(); + + // reinsert the requests + if (!hasError) + availableRequestQueue.addAll(Arrays.asList(requests)); + } + + /** + * Wait until one of the allocated requests is available for use. + *

+ * Throws an exception if the request to be reused has completed with an error on the + * previous operation. The exception is suppressed if {@code hasError} flag is set. + *

+ * @return request ready for use + */ + private TransferRequest waitForAvailableRequest() { + while (true) { + try { + TransferRequest request = availableRequestQueue.take(); + + // check for error + int result = request.result; + if (result != 0 && !hasError) { + request.result = 0; + throwException(result, "error reading from USB endpoint"); + } + + return request; + + } catch (InterruptedException e) { + // ignore and retry + } + } + } + + /** + * Called by the asynchronous IO completion handler. + * + * @param request the completed request + * @param result the request result code + */ + private synchronized void onCompletion(TransferRequest request, int result) { + request.result = result; + availableRequestQueue.add(request); + numOutstandingRequests -= 1; + } + + protected abstract void submitTransferOut(MemorySegment data, int dataSize, AsyncIOCompletion completion); + + protected abstract void throwException(int errorCode, String message); + + private static class TransferRequest { + MemorySegment buffer; + int result; + AsyncIOCompletion completionHandler; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncIOCompletion.java b/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncIOCompletion.java new file mode 100644 index 00000000..63581eed --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncIOCompletion.java @@ -0,0 +1,27 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +/** + * Lambda function called when an asynchronous IO operation has completed. + */ +@FunctionalInterface +public interface AsyncIOCompletion { + + /** + * Called when the asynchronous IO has completed. + *

+ * A result code of 0 indicates a successful operation. Other codes + * indicate a failure. The code is operating system specific. + *

+ * + * @param result the native result code of the operation. + * @param size the size of the transferred data (in bytes) + */ + void completed(int result, int size); +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java index b9395b60..c76ebe52 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java @@ -9,6 +9,7 @@ import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBException; +import net.codecrete.usb.common.AsyncIOCompletion; import java.io.IOException; import java.io.InputStream; @@ -206,6 +207,6 @@ private static class TransferRequest { MemorySegment buffer; int result; int resultSize; - MacosUSBDevice.AsyncIOCompletion completionHandler; + AsyncIOCompletion completionHandler; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java index fe9f62c8..4f3442fa 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java @@ -8,6 +8,7 @@ package net.codecrete.usb.macos; import net.codecrete.usb.USBDirection; +import net.codecrete.usb.common.AsyncIOCompletion; import java.io.IOException; import java.io.OutputStream; @@ -246,6 +247,6 @@ private synchronized void onCompletion(TransferRequest request, int result) { private static class TransferRequest { MemorySegment buffer; int result; - MacosUSBDevice.AsyncIOCompletion completionHandler; + AsyncIOCompletion completionHandler; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 23e1f4e3..d1a1d0bb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -11,6 +11,7 @@ import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBTimeoutException; import net.codecrete.usb.USBTransferType; +import net.codecrete.usb.common.AsyncIOCompletion; import net.codecrete.usb.common.ForeignMemory; import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.common.USBDeviceImpl; @@ -711,18 +712,6 @@ private static void asyncIOCompleted(MacosUSBDevice device, MemorySegment refcon device.getCompletionHandler(refcon).completed(result, (int)arg0.address()); } - @FunctionalInterface - public interface AsyncIOCompletion { - - /** - * Called when the asynchronous IO has completed. - * - * @param result the result code of the operation - * @param size the size of the transferred data (in bytes) - */ - void completed(int result, int size); - } - record InterfaceInfo(MemorySegment iokitInterface, int interfaceNumber) { } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java index de6a9fed..424f64e8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java @@ -8,202 +8,25 @@ package net.codecrete.usb.windows; import net.codecrete.usb.USBDirection; +import net.codecrete.usb.common.AsyncEndpointInputStream; +import net.codecrete.usb.common.AsyncIOCompletion; -import java.io.IOException; -import java.io.InputStream; -import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.util.concurrent.ArrayBlockingQueue; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static net.codecrete.usb.windows.WindowsUSBException.throwException; +public class WindowsEndpointInputStream extends AsyncEndpointInputStream { -/** - * Input stream for bulk endpoints – optimized for high throughput. - * - *

- * Multiple asynchronous transfer IN requests are submitted to achieve a good - * degree of concurrency between the USB communication handled by the operating - * system and the consuming application code. - *

- *

- * For thread synchronization (between the background thread handling IO completion - * and the consuming application thread) a blocking queue is used. When an transfer IN - * requests completes, the background thread adds it to the queue. The consuming code - * waits for the next item in the queue. - *

- */ -public class WindowsEndpointInputStream extends InputStream { - - private static final int MAX_OUTSTANDING_REQUESTS = 8; - - private WindowsUSBDevice device; - private final int endpointNumber; - /// Arena to allocate buffers and completion handlers - private final Arena arena; - /// Size of buffers (multiple of packet size) - private final int bufferSize; - /// Queue of completed requests - private final ArrayBlockingQueue completedRequestQueue; - /// Number of outstanding requests (includes requests pending with the - /// operating system and requests in the completed queue) - private int numOutstandingRequests; - /// Request and buffer being currently read from - private TransferRequest currentRequest; - /// Read offset within current request - private int readOffset; - - /** - * Creates a new instance - * - * @param device USB device - * @param endpointNumber endpoint number - */ WindowsEndpointInputStream(WindowsUSBDevice device, int endpointNumber) { - this.device = device; - this.endpointNumber = endpointNumber; - - bufferSize = 4 * device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); - completedRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); - + super(device, endpointNumber); device.configureForAsyncIo(USBDirection.IN, endpointNumber); - - // create all requests and submit all except one - arena = Arena.openShared(); - try { - for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { - final var request = new TransferRequest(); - request.buffer = arena.allocate(bufferSize, 8); - request.completionHandler = (result, size) -> onCompletion(request, result, size); - - if (i == 0) { - currentRequest = request; - } else { - submitRequest(request); - } - } - } catch (Throwable t) { - collectOutstandingRequests(); - throw t; - } } - @SuppressWarnings("RedundantThrows") @Override - public void close() throws IOException { - if (isClosed()) - return; - - // abort all transfers on endpoint - device.abortTransfers(USBDirection.IN, endpointNumber); - device = null; - - collectOutstandingRequests(); - } - - private void collectOutstandingRequests() { - // wait until completion handlers have been called - while (numOutstandingRequests > 0) - waitForRequestCompletion(); - - completedRequestQueue.clear(); - currentRequest = null; - arena.close(); - } - - @Override - public int read() throws IOException { - if (isClosed()) - return -1; - - if (available() == 0) - receiveMoreData(); - - int b = currentRequest.buffer.get(JAVA_BYTE, readOffset) & 0xff; - readOffset += 1; - return b; + protected void submitTransferIn(MemorySegment buffer, int bufferSize, AsyncIOCompletion completion) { + ((WindowsUSBDevice)device).submitTransferIn(endpointNumber, buffer, bufferSize, completion); } @Override - public int read(byte[] b, int off, int len) throws IOException { - if (isClosed()) - return -1; - - if (available() == 0) - receiveMoreData(); - - // copy data to receiving buffer - int n = Math.min(len, currentRequest.resultSize - readOffset); - MemorySegment.copy(currentRequest.buffer, readOffset, MemorySegment.ofArray(b), off, n); - readOffset += n; - - // TODO: poll for further completed requests if 'n' is less than 'len' - - return n; - } - - @SuppressWarnings("RedundantThrows") - @Override - public int available() throws IOException { - return currentRequest.resultSize - readOffset; - } - - private boolean isClosed() { - return device == null; - } - - private void receiveMoreData() throws IOException { - try { - // loop until non-ZLP has been received - do { - submitRequest(currentRequest); - - currentRequest = waitForRequestCompletion(); - readOffset = 0; - - // check for error - if (currentRequest.result != 0) - throwException(currentRequest.result, "error reading from USB endpoint"); - - } while (currentRequest.resultSize == 0); - - } catch (Throwable t) { - close(); - throw t; - } - } - - void submitRequest(TransferRequest request) { - request.cancelHandle = - device.submitTransferIn(endpointNumber, request.buffer, bufferSize, request.completionHandler); - numOutstandingRequests += 1; - } - - void onCompletion(TransferRequest request, int result, int size) { - request.result = result; - request.resultSize = size; - request.cancelHandle = 0; - completedRequestQueue.add(request); - } - - TransferRequest waitForRequestCompletion() { - while (true) { - try { - TransferRequest request = completedRequestQueue.take(); - numOutstandingRequests -= 1; - return request; - - } catch (InterruptedException e) { - // ignore and retry - } - } - } - - private static class TransferRequest { - MemorySegment buffer; - int result; - int resultSize; - long cancelHandle; - WindowsUSBDevice.AsyncIOCompletion completionHandler; + protected void throwException(int errorCode, String message) { + WindowsUSBException.throwException(errorCode, message); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java index 06942c15..b453f936 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java @@ -8,247 +8,25 @@ package net.codecrete.usb.windows; import net.codecrete.usb.USBDirection; +import net.codecrete.usb.common.AsyncEndpointOutputStream; +import net.codecrete.usb.common.AsyncIOCompletion; -import java.io.IOException; -import java.io.OutputStream; -import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.util.Arrays; -import java.util.concurrent.ArrayBlockingQueue; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static net.codecrete.usb.windows.WindowsUSBException.throwException; +public class WindowsEndpointOutputStream extends AsyncEndpointOutputStream { -/** - * Output stream for bulk endpoints – optimized for high throughput. - * - *

- * Multiple asynchronous transfer OUT requests are submitted to achieve a good - * degree of concurrency between the USB communication handled by the operating - * system and the producing application code. The number of requests is limited - * in order to retain the flow control and keep memory usage at a reasonable size. - *

- *

- * For thread synchronization (between the background thread handling IO completion - * and the producing application thread) a blocking queue is used. It is prefilled with - * requests ready to be used for a transfer. The background thread adds the completed - * requests back to this queue. The producing application thread waits until a request - * is available for use. - *

- */ -public class WindowsEndpointOutputStream extends OutputStream { - - private static final int MAX_OUTSTANDING_REQUESTS = 4; - - private WindowsUSBDevice device; - private final int endpointNumber; - private final Arena arena; - // Endpoint's packet size - private final int packetSize; - // Size of buffers (multiple of packet size) - private final int bufferSize; - // Blocking queue of available requests (to limit the number of submitted requests) - private final ArrayBlockingQueue availableRequestQueue; - private boolean needsZlp; - private TransferRequest currentRequest; - private int writeOffset; - private int numOutstandingRequests; - private boolean hasError; - - - /** - * Creates a new instance - * @param device USB device - * @param endpointNumber endpoint number - */ WindowsEndpointOutputStream(WindowsUSBDevice device, int endpointNumber) { - this.device = device; - this.endpointNumber = endpointNumber; - - packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize(); - bufferSize = packetSize; - + super(device, endpointNumber); device.configureForAsyncIo(USBDirection.OUT, endpointNumber); - - availableRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); - arena = Arena.openShared(); - - // prefill request queue - for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { - final var request = new TransferRequest(); - request.buffer = arena.allocate(bufferSize, 8); - request.completionHandler = (result, size) -> onCompletion(request, result); - - if (i == 0) { - currentRequest = request; - } else { - availableRequestQueue.add(request); - } - } } @Override - public void close() throws IOException { - if (isClosed()) - return; - - if (!hasError) - flush(); - else - waitForOutstandingRequests(); - - device = null; - availableRequestQueue.clear(); - currentRequest = null; - arena.close(); + protected void submitTransferOut(MemorySegment data, int dataSize, AsyncIOCompletion completion) { + ((WindowsUSBDevice)device).submitTransferOut(endpointNumber, data, dataSize, completion); } @Override - public void write(int b) throws IOException { - if (isClosed()) - throw new IOException("Bulk endpoint output stream has been closed"); - - currentRequest.buffer.set(JAVA_BYTE, writeOffset, (byte)b); - writeOffset += 1; - if (writeOffset == bufferSize) - submitTransfer(writeOffset); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - if (isClosed()) - throw new IOException("Bulk endpoint output stream has been closed"); - - while (len > 0) { - int chunkSize = Math.min(len, bufferSize - writeOffset); - MemorySegment.copy(b, off, currentRequest.buffer, JAVA_BYTE, writeOffset, chunkSize); - writeOffset += chunkSize; - off += chunkSize; - len -= chunkSize; - - if (writeOffset == bufferSize) - submitTransfer(writeOffset); - } - } - - @Override - public void flush() throws IOException { - if (isClosed()) - throw new IOException("Bulk endpoint output stream has been closed"); - - if (writeOffset > 0) - submitTransfer(writeOffset); - - if (needsZlp) - submitTransfer(0); - - waitForOutstandingRequests(); - } - - private boolean isClosed() { - return device == null; - } - - /** - * Submits a request for transfer and set a new request - * as the current one, possibly waiting until it is ready. - *

- * Throws an exception if the request to be reused has completed with an error on the - * previous operation. The exception is suppressed if {@code hasError} flag is set. - *

- * - * @param size size of data to be transmitted - */ - private void submitTransfer(int size) throws IOException { - try { - device.submitTransferOut(endpointNumber, currentRequest.buffer, size, currentRequest.completionHandler); - - synchronized (this) { - numOutstandingRequests += 1; - } - - needsZlp = size == packetSize; - writeOffset = 0; - currentRequest = waitForAvailableRequest(); - - } catch (Throwable t) { - hasError = true; - close(); - throw t; - } - } - - /** - * Wait until all outstanding requests have been completed. - *

- * Throws an exception if any of the requests has completed with an error. - * The exception is suppressed if {@code hasError} flag is set. - *

- */ - private void waitForOutstandingRequests() { - // Wait until all buffers have been transmitted by removing them from the - // queue and reinserting them. - - int numRequests; - synchronized (this) { - numRequests = numOutstandingRequests + availableRequestQueue.size(); - } - - if (numRequests == 0) - return; - - var requests = new TransferRequest[numRequests]; - for (int i = 0; i < numRequests; i++) - requests[i] = waitForAvailableRequest(); - - // reinsert the requests - if (!hasError) - availableRequestQueue.addAll(Arrays.asList(requests)); - } - - /** - * Wait until one of the allocated requests is available for use. - *

- * Throws an exception if the request to be reused has completed with an error on the - * previous operation. The exception is suppressed if {@code hasError} flag is set. - *

- * @return request ready for use - */ - private TransferRequest waitForAvailableRequest() { - while (true) { - try { - TransferRequest request = availableRequestQueue.take(); - - // check for error - int result = request.result; - if (result != 0 && !hasError) { - request.result = 0; - throwException(result, "error reading from USB endpoint"); - } - - return request; - - } catch (InterruptedException e) { - // ignore and retry - } - } - } - - /** - * Called by the asynchronous IO completion handler. - * - * @param request the completed request - * @param result the request result code - */ - private synchronized void onCompletion(TransferRequest request, int result) { - request.result = result; - availableRequestQueue.add(request); - numOutstandingRequests -= 1; - } - - private static class TransferRequest { - MemorySegment buffer; - int result; - WindowsUSBDevice.AsyncIOCompletion completionHandler; + protected void throwException(int errorCode, String message) { + WindowsUSBException.throwException(errorCode, message); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 13935284..43060aac 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -8,6 +8,7 @@ package net.codecrete.usb.windows; import net.codecrete.usb.*; +import net.codecrete.usb.common.AsyncIOCompletion; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.usbstandard.SetupPacket; import net.codecrete.usb.windows.gen.kernel32.Kernel32; @@ -525,16 +526,4 @@ private MemorySegment getOverlapped(AsyncIOCompletion completionHandler) { completionHandlers.put(overlapped, completionHandler); return overlapped; } - - @FunctionalInterface - public interface AsyncIOCompletion { - - /** - * Called when the asynchronous IO has completed. - * - * @param result the result code of the operation - * @param size the size of the transferred data (in bytes) - */ - void completed(int result, int size); - } } From 875a44a91768efe41817a15ab8baab135fdb048f Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 19 Feb 2023 18:06:31 +0100 Subject: [PATCH 201/433] Use common input/output stream code --- .../usb/macos/CoreFoundationHelper.java | 4 +- .../net/codecrete/usb/macos/IoKitHelper.java | 39 ++- .../net/codecrete/usb/macos/IoKitUSB.java | 68 +++-- .../usb/macos/MacosEndpointInputStream.java | 196 +-------------- .../usb/macos/MacosEndpointOutputStream.java | 236 +----------------- .../codecrete/usb/macos/MacosUSBDevice.java | 144 ++++++----- .../usb/macos/MacosUSBDeviceRegistry.java | 27 +- .../usb/macos/MacosUSBException.java | 11 +- .../java/net/codecrete/usb/macos/UUID.java | 1 + 9 files changed, 182 insertions(+), 544 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java index c403ede2..c73542ee 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java @@ -26,7 +26,7 @@ public class CoreFoundationHelper { * Gets Java string as a copy of the {@code CFStringRef}. * * @param string the string to copy ({@code CFStringRef}) - * @param arena the arena to allocate memory + * @param arena the arena to allocate memory * @return copied string */ public static String stringFromCFStringRef(MemorySegment string, Arena arena) { @@ -47,7 +47,7 @@ public static String stringFromCFStringRef(MemorySegment string, Arena arena) { * ownership without incrementing the reference count. *

* - * @param string the string + * @param string the string * @param allocator the allocator for allocating memory * @return {@code CFStringRef} */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index 5c21b3be..0f80c9ff 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -22,26 +22,21 @@ * Constants and helper functions for the IOKit framework. */ public class IoKitHelper { - public static final MemorySegment kIOUSBDeviceUserClientTypeID = UUID.CreateCFUUID( - new byte[]{(byte) 0x9d, (byte) 0xc7, (byte) 0xb7, (byte) 0x80, (byte) 0x9e, (byte) 0xc0, (byte) 0x11, - (byte) 0xD4, (byte) 0xa5, (byte) 0x4f, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, - (byte) 0x28, (byte) 0x61}); - public static final MemorySegment kIOUSBInterfaceUserClientTypeID = UUID.CreateCFUUID( - new byte[]{(byte) 0x2d, (byte) 0x97, (byte) 0x86, (byte) 0xc6, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, - (byte) 0xD4, (byte) 0xad, (byte) 0x51, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, - (byte) 0x28, (byte) 0x61}); - public static final MemorySegment kIOUSBDeviceInterfaceID100 = UUID.CreateCFUUID( - new byte[]{(byte) 0x5c, (byte) 0x81, (byte) 0x87, (byte) 0xd0, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, - (byte) 0xD4, (byte) 0x8b, (byte) 0x45, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, - (byte) 0x28, (byte) 0x61}); - public static final MemorySegment kIOUSBInterfaceInterfaceID100 = UUID.CreateCFUUID( - new byte[]{(byte) 0x73, (byte) 0xc9, (byte) 0x7a, (byte) 0xe8, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, - (byte) 0xD4, (byte) 0xb1, (byte) 0xd0, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, - (byte) 0x28, (byte) 0x61}); - public static final MemorySegment kIOCFPlugInInterfaceID = UUID.CreateCFUUID( - new byte[]{(byte) 0xC2, (byte) 0x44, (byte) 0xE8, (byte) 0x58, (byte) 0x10, (byte) 0x9C, (byte) 0x11, - (byte) 0xD4, (byte) 0x91, (byte) 0xD4, (byte) 0x00, (byte) 0x50, (byte) 0xE4, (byte) 0xC6, - (byte) 0x42, (byte) 0x6F}); + public static final MemorySegment kIOUSBDeviceUserClientTypeID = UUID.CreateCFUUID(new byte[]{(byte) 0x9d, + (byte) 0xc7, (byte) 0xb7, (byte) 0x80, (byte) 0x9e, (byte) 0xc0, (byte) 0x11, (byte) 0xD4, (byte) 0xa5, + (byte) 0x4f, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61}); + public static final MemorySegment kIOUSBInterfaceUserClientTypeID = UUID.CreateCFUUID(new byte[]{(byte) 0x2d, + (byte) 0x97, (byte) 0x86, (byte) 0xc6, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, (byte) 0xad, + (byte) 0x51, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61}); + public static final MemorySegment kIOUSBDeviceInterfaceID100 = UUID.CreateCFUUID(new byte[]{(byte) 0x5c, + (byte) 0x81, (byte) 0x87, (byte) 0xd0, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, (byte) 0x8b, + (byte) 0x45, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61}); + public static final MemorySegment kIOUSBInterfaceInterfaceID100 = UUID.CreateCFUUID(new byte[]{(byte) 0x73, + (byte) 0xc9, (byte) 0x7a, (byte) 0xe8, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, (byte) 0xb1, + (byte) 0xd0, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61}); + public static final MemorySegment kIOCFPlugInInterfaceID = UUID.CreateCFUUID(new byte[]{(byte) 0xC2, (byte) 0x44, + (byte) 0xE8, (byte) 0x58, (byte) 0x10, (byte) 0x9C, (byte) 0x11, (byte) 0xD4, (byte) 0x91, (byte) 0xD4, + (byte) 0x00, (byte) 0x50, (byte) 0xE4, (byte) 0xC6, (byte) 0x42, (byte) 0x6F}); /** * Get an interface of the specified service. @@ -61,8 +56,8 @@ public static MemorySegment getInterface(int service, MemorySegment pluginType, var plugHolder = arena.allocate(ADDRESS, NULL); // MemorySegment for holding score var score = arena.allocate(JAVA_INT, 0); - int ret = IOKit.IOCreatePlugInInterfaceForService(service, pluginType, kIOCFPlugInInterfaceID, - plugHolder, score); + int ret = IOKit.IOCreatePlugInInterfaceForService(service, pluginType, kIOCFPlugInInterfaceID, plugHolder + , score); if (ret != 0) return null; var plug = plugHolder.get(ADDRESS, 0); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index f95c246b..f9ade06d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -69,17 +69,21 @@ public static int GetConfigurationDescriptorPtr(MemorySegment self, byte configI // IOReturn (*SetConfiguration)(void *self, UInt8 configNum); public static int SetConfiguration(MemorySegment self, byte configValue) { - return IOUSBDeviceInterface100.SetConfiguration(getVtable(self), SegmentScope.global()).apply(self, configValue); + return IOUSBDeviceInterface100.SetConfiguration(getVtable(self), SegmentScope.global()).apply(self, + configValue); } // IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter); public static int CreateInterfaceIterator(MemorySegment self, MemorySegment req, MemorySegment iter) { - return IOUSBDeviceInterface100.CreateInterfaceIterator(getVtable(self), SegmentScope.global()).apply(self, req, iter); + return IOUSBDeviceInterface100.CreateInterfaceIterator(getVtable(self), SegmentScope.global()).apply(self, + req, iter); } // IOReturn (* DeviceRequestAsync)(void* self, IOUSBDevRequest* req, IOAsyncCallback1 callback, void* refCon); - public static int DeviceRequestAsync(MemorySegment self, MemorySegment deviceRequest, MemorySegment callback, MemorySegment refCon) { - return IOUSBDeviceInterface100.DeviceRequestAsync(getVtable(self), SegmentScope.global()).apply(self, deviceRequest, callback, refCon); + public static int DeviceRequestAsync(MemorySegment self, MemorySegment deviceRequest, MemorySegment callback, + MemorySegment refCon) { + return IOUSBDeviceInterface100.DeviceRequestAsync(getVtable(self), SegmentScope.global()).apply(self, + deviceRequest, callback, refCon); } // IOReturn (*USBInterfaceOpen)(void *self);; @@ -94,12 +98,14 @@ public static int USBInterfaceClose(MemorySegment self) { // IOReturn (*GetInterfaceNumber)(void *self, UInt8 *intfNumber); public static int GetInterfaceNumber(MemorySegment self, MemorySegment intfNumberHolder) { - return IOUSBInterfaceInterface190.GetInterfaceNumber(getVtable(self), SegmentScope.global()).apply(self, intfNumberHolder); + return IOUSBInterfaceInterface190.GetInterfaceNumber(getVtable(self), SegmentScope.global()).apply(self, + intfNumberHolder); } // IOReturn (*GetNumEndpoints)(void *self, UInt8 *intfNumEndpoints); public static int GetNumEndpoints(MemorySegment self, MemorySegment intfNumEndpointsHolder) { - return IOUSBInterfaceInterface190.GetNumEndpoints(getVtable(self), SegmentScope.global()).apply(self, intfNumEndpointsHolder); + return IOUSBInterfaceInterface190.GetNumEndpoints(getVtable(self), SegmentScope.global()).apply(self, + intfNumEndpointsHolder); } // IOReturn (*GetPipeProperties)(void *self, UInt8 pipeRef, UInt8 *direction, UInt8 *number, UInt8 *transferType, @@ -107,30 +113,42 @@ public static int GetNumEndpoints(MemorySegment self, MemorySegment intfNumEndpo public static int GetPipeProperties(MemorySegment self, byte pipeRef, MemorySegment directionHolder, MemorySegment numberHolder, MemorySegment transferTypeHolder, MemorySegment maxPacketSizeHolder, MemorySegment intervalHolder) { - return IOUSBInterfaceInterface190.GetPipeProperties(getVtable(self), SegmentScope.global()).apply(self, pipeRef, - directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); + return IOUSBInterfaceInterface190.GetPipeProperties(getVtable(self), SegmentScope.global()).apply(self, + pipeRef, directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); } - // IOReturn (*ReadPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, void *refcon); - public static int ReadPipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceInterface190.ReadPipeAsync(getVtable(self), SegmentScope.global()) - .apply(self, pipeRef, buf, size, callback, refcon); + // IOReturn (*ReadPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, void + // *refcon); + public static int ReadPipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, + MemorySegment callback, MemorySegment refcon) { + return IOUSBInterfaceInterface190.ReadPipeAsync(getVtable(self), SegmentScope.global()).apply(self, pipeRef, + buf, size, callback, refcon); } - // IOReturn (*ReadPipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void *refcon); - public static int ReadPipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, int noDataTimeout, int completionTimeout, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceInterface190.ReadPipeAsyncTO(getVtable(self), SegmentScope.global()) - .apply(self, pipeRef, buf, size, noDataTimeout, completionTimeout, callback, refcon); + // IOReturn (*ReadPipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 + // completionTimeout, IOAsyncCallback1 callback, void *refcon); + public static int ReadPipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, + int noDataTimeout, int completionTimeout, MemorySegment callback, + MemorySegment refcon) { + return IOUSBInterfaceInterface190.ReadPipeAsyncTO(getVtable(self), SegmentScope.global()).apply(self, pipeRef + , buf, size, noDataTimeout, completionTimeout, callback, refcon); } - // IOReturn (*WritePipeAsync)(vovoid *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, void *refcon); - public static int WritePipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceInterface190.WritePipeAsync(getVtable(self), SegmentScope.global()).apply(self, pipeRef, buf, size, callback, refcon); + // IOReturn (*WritePipeAsync)(vovoid *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, + // void *refcon); + public static int WritePipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, + MemorySegment callback, MemorySegment refcon) { + return IOUSBInterfaceInterface190.WritePipeAsync(getVtable(self), SegmentScope.global()).apply(self, pipeRef, + buf, size, callback, refcon); } - // IOReturn (*WritePipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 completionTimeout, IOAsyncCallback1 callback, void *refcon); - public static int WritePipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, int noDataTimeout, int completionTimeout, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceInterface190.WritePipeAsyncTO(getVtable(self), SegmentScope.global()).apply(self, pipeRef, buf, size, noDataTimeout, completionTimeout, callback, refcon); + // IOReturn (*WritePipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 + // completionTimeout, IOAsyncCallback1 callback, void *refcon); + public static int WritePipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, + int noDataTimeout, int completionTimeout, MemorySegment callback, + MemorySegment refcon) { + return IOUSBInterfaceInterface190.WritePipeAsyncTO(getVtable(self), SegmentScope.global()).apply(self, + pipeRef, buf, size, noDataTimeout, completionTimeout, callback, refcon); } // IOReturn (* AbortPipe)(void* self, UInt8 pipeRef); @@ -140,12 +158,14 @@ public static int AbortPipe(MemorySegment self, byte pipeRef) { // IOReturn (*SetAlternateInterface)(void *self, UInt8 alternateSetting); public static int SetAlternateInterface(MemorySegment self, byte alternateSetting) { - return IOUSBInterfaceInterface190.SetAlternateInterface(getVtable(self), SegmentScope.global()).apply(self, alternateSetting); + return IOUSBInterfaceInterface190.SetAlternateInterface(getVtable(self), SegmentScope.global()).apply(self, + alternateSetting); } // IOReturn (* ClearPipeStallBothEnds)(void* self, UInt8 pipeRef); public static int ClearPipeStallBothEnds(MemorySegment self, byte pipeRef) { - return IOUSBInterfaceInterface190.ClearPipeStallBothEnds(getVtable(self), SegmentScope.global()).apply(self, pipeRef); + return IOUSBInterfaceInterface190.ClearPipeStallBothEnds(getVtable(self), SegmentScope.global()).apply(self, + pipeRef); } // CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void* self); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java index c76ebe52..69d45eea 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java @@ -7,206 +7,24 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.USBDirection; -import net.codecrete.usb.USBException; +import net.codecrete.usb.common.AsyncEndpointInputStream; import net.codecrete.usb.common.AsyncIOCompletion; -import java.io.IOException; -import java.io.InputStream; -import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.util.concurrent.ArrayBlockingQueue; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static net.codecrete.usb.macos.MacosUSBException.throwException; +public class MacosEndpointInputStream extends AsyncEndpointInputStream { -/** - * Input stream for bulk endpoints – optimized for high throughput. - * - *

- * Multiple asynchronous transfer IN requests are submitted to achieve a good - * degree of concurrency between the USB communication handled by the operating - * system and the consuming application code. - *

- *

- * For thread synchronization (between the background thread handling IO completion - * and the consuming application thread) a blocking queue is used. When an transfer IN - * requests completes, the background thread adds it to the queue. The consuming code - * waits for the next item in the queue. - *

- */ -public class MacosEndpointInputStream extends InputStream { - - private static final int MAX_OUTSTANDING_REQUESTS = 8; - - private MacosUSBDevice device; - private final int endpointNumber; - // Arena to allocate buffers and completion handlers - private final Arena arena; - // Size of buffers (multiple of packet size) - private final int bufferSize; - // Queue of completed requests - private final ArrayBlockingQueue completedRequestQueue; - // Number of outstanding requests (includes requests pending with the - // operating system and requests in the completed queue) - private int numOutstandingRequests; - // Request and buffer being currently read from - private TransferRequest currentRequest; - // Read offset within current request - private int readOffset; - - /** - * Creates a new instance - * - * @param device USB device - * @param endpointNumber endpoint number - */ MacosEndpointInputStream(MacosUSBDevice device, int endpointNumber) { - this.device = device; - this.endpointNumber = endpointNumber; - - bufferSize = 4 * device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); - completedRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); - - // create all requests and submit all except one - arena = Arena.openShared(); - try { - for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { - final var request = new TransferRequest(); - request.buffer = arena.allocate(bufferSize, 8); - request.completionHandler = (result, size) -> onCompletion(request, result, size); - - if (i == 0) { - currentRequest = request; - } else { - submitRequest(request); - } - } - } catch (Throwable t) { - collectOutstandingRequests(); - throw t; - } - } - - @SuppressWarnings("RedundantThrows") - @Override - public void close() throws IOException { - if (isClosed()) - return; - - // abort all transfers on endpoint - try { - device.abortTransfer(USBDirection.IN, endpointNumber); - } catch (USBException e) { - // If aborting the transfer is not possible, the device has - // likely been closed or unplugged. So all outstanding - // requests will terminate anyway. - } - device = null; - - collectOutstandingRequests(); - } - - private void collectOutstandingRequests() { - // wait until completion handlers have been called - while (numOutstandingRequests > 0) - waitForRequestCompletion(); - - completedRequestQueue.clear(); - currentRequest = null; - arena.close(); - } - - @Override - public int read() throws IOException { - if (isClosed()) - return -1; - - if (available() == 0) - receiveMoreData(); - - int b = currentRequest.buffer.get(JAVA_BYTE, readOffset) & 0xff; - readOffset += 1; - return b; + super(device, endpointNumber); } @Override - public int read(byte[] b, int off, int len) throws IOException { - if (isClosed()) - return -1; - - if (available() == 0) - receiveMoreData(); - - // copy data to receiving buffer - int n = Math.min(len, currentRequest.resultSize - readOffset); - MemorySegment.copy(currentRequest.buffer, readOffset, MemorySegment.ofArray(b), off, n); - readOffset += n; - - // TODO: poll for further completed requests if 'n' is less than 'len' - - return n; + protected void submitTransferIn(MemorySegment buffer, int bufferSize, AsyncIOCompletion completion) { + ((MacosUSBDevice) device).submitTransferIn(endpointNumber, buffer, bufferSize, 0, completion); } - @SuppressWarnings("RedundantThrows") @Override - public int available() throws IOException { - return currentRequest.resultSize - readOffset; - } - - private boolean isClosed() { - return device == null; - } - - private void receiveMoreData() throws IOException { - try { - // loop until non-ZLP has been received - do { - submitRequest(currentRequest); - - currentRequest = waitForRequestCompletion(); - readOffset = 0; - - // check for error - if (currentRequest.result != 0) - throwException(currentRequest.result, "error reading from USB endpoint"); - - } while (currentRequest.resultSize == 0); - - } catch (Throwable t) { - close(); - throw t; - } - } - - void submitRequest(TransferRequest request) { - device.submitTransferIn(endpointNumber, request.buffer, bufferSize, 0, request.completionHandler); - numOutstandingRequests += 1; - } - - void onCompletion(TransferRequest request, int result, int size) { - request.result = result; - request.resultSize = size; - completedRequestQueue.add(request); - } - - TransferRequest waitForRequestCompletion() { - while (true) { - try { - TransferRequest request = completedRequestQueue.take(); - numOutstandingRequests -= 1; - return request; - - } catch (InterruptedException e) { - // ignore and retry - } - } - } - - private static class TransferRequest { - MemorySegment buffer; - int result; - int resultSize; - AsyncIOCompletion completionHandler; + protected void throwException(int errorCode, String message) { + MacosUSBException.throwException(errorCode, message); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java index 4f3442fa..c68719a1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java @@ -7,246 +7,24 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.USBDirection; +import net.codecrete.usb.common.AsyncEndpointOutputStream; import net.codecrete.usb.common.AsyncIOCompletion; -import java.io.IOException; -import java.io.OutputStream; -import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.util.Arrays; -import java.util.concurrent.ArrayBlockingQueue; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static net.codecrete.usb.macos.MacosUSBException.throwException; +public class MacosEndpointOutputStream extends AsyncEndpointOutputStream { -/** - * Output stream for bulk endpoints – optimized for high throughput. - * - *

- * Multiple asynchronous transfer OUT requests are submitted to achieve a good - * degree of concurrency between the USB communication handled by the operating - * system and the producing application code. The number of requests is limited - * in order to retain the flow control and keep memory usage at a reasonable size. - *

- *

- * For thread synchronization (between the background thread handling IO completion - * and the producing application thread) a blocking queue is used. It is prefilled with - * requests ready to be used for a transfer. The background thread adds the completed - * requests back to this queue. The producing application thread waits until a request - * is available for use. - *

- */ -public class MacosEndpointOutputStream extends OutputStream { - - private static final int MAX_OUTSTANDING_REQUESTS = 4; - - private MacosUSBDevice device; - private final int endpointNumber; - private final Arena arena; - // Endpoint's packet size - private final int packetSize; - // Size of buffers (multiple of packet size) - private final int bufferSize; - // Blocking queue of available requests (to limit the number of submitted requests) - private final ArrayBlockingQueue availableRequestQueue; - private boolean needsZlp; - private TransferRequest currentRequest; - private int writeOffset; - private int numOutstandingRequests; - private boolean hasError; - - - /** - * Creates a new instance - * @param device USB device - * @param endpointNumber endpoint number - */ MacosEndpointOutputStream(MacosUSBDevice device, int endpointNumber) { - this.device = device; - this.endpointNumber = endpointNumber; - - packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize(); - bufferSize = packetSize; - availableRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); - arena = Arena.openShared(); - - // prefill request queue - for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { - final var request = new TransferRequest(); - request.buffer = arena.allocate(bufferSize, 8); - request.completionHandler = (result, size) -> onCompletion(request, result); - - if (i == 0) { - currentRequest = request; - } else { - availableRequestQueue.add(request); - } - } - } - - @Override - public void close() throws IOException { - if (isClosed()) - return; - - if (!hasError) - flush(); - else - waitForOutstandingRequests(); - - device = null; - availableRequestQueue.clear(); - currentRequest = null; - arena.close(); + super(device, endpointNumber); } @Override - public void write(int b) throws IOException { - if (isClosed()) - throw new IOException("Bulk endpoint output stream has been closed"); - - currentRequest.buffer.set(JAVA_BYTE, writeOffset, (byte)b); - writeOffset += 1; - if (writeOffset == bufferSize) - submitTransfer(writeOffset); + protected void submitTransferOut(MemorySegment data, int dataSize, AsyncIOCompletion completion) { + ((MacosUSBDevice) device).submitTransferOut(endpointNumber, data, dataSize, 0, completion); } @Override - public void write(byte[] b, int off, int len) throws IOException { - if (isClosed()) - throw new IOException("Bulk endpoint output stream has been closed"); - - while (len > 0) { - int chunkSize = Math.min(len, bufferSize - writeOffset); - MemorySegment.copy(b, off, currentRequest.buffer, JAVA_BYTE, writeOffset, chunkSize); - writeOffset += chunkSize; - off += chunkSize; - len -= chunkSize; - - if (writeOffset == bufferSize) - submitTransfer(writeOffset); - } - } - - @Override - public void flush() throws IOException { - if (isClosed()) - throw new IOException("Bulk endpoint output stream has been closed"); - - if (writeOffset > 0) - submitTransfer(writeOffset); - - if (needsZlp) - submitTransfer(0); - - waitForOutstandingRequests(); - } - - private boolean isClosed() { - return device == null; - } - - /** - * Submits a request for transfer and set a new request - * as the current one, possibly waiting until it is ready. - *

- * Throws an exception if the request to be reused has completed with an error on the - * previous operation. The exception is suppressed if {@code hasError} flag is set. - *

- * - * @param size size of data to be transmitted - */ - private void submitTransfer(int size) throws IOException { - try { - device.submitTransferOut(endpointNumber, currentRequest.buffer, size, 0, currentRequest.completionHandler); - - synchronized (this) { - numOutstandingRequests += 1; - } - - needsZlp = size == packetSize; - writeOffset = 0; - currentRequest = waitForAvailableRequest(); - - } catch (Throwable t) { - hasError = true; - close(); - throw t; - } - } - - /** - * Wait until all outstanding requests have been completed. - *

- * Throws an exception if any of the requests has completed with an error. - * The exception is suppressed if {@code hasError} flag is set. - *

- */ - private void waitForOutstandingRequests() { - // Wait until all buffers have been transmitted by removing them from the - // queue and reinserting them. - - int numRequests; - synchronized (this) { - numRequests = numOutstandingRequests + availableRequestQueue.size(); - } - - if (numRequests == 0) - return; - - var requests = new TransferRequest[numRequests]; - for (int i = 0; i < numRequests; i++) - requests[i] = waitForAvailableRequest(); - - // reinsert the requests - if (!hasError) - availableRequestQueue.addAll(Arrays.asList(requests)); - } - - /** - * Wait until one of the allocated requests is available for use. - *

- * Throws an exception if the request to be reused has completed with an error on the - * previous operation. The exception is suppressed if {@code hasError} flag is set. - *

- * @return request ready for use - */ - private TransferRequest waitForAvailableRequest() { - while (true) { - try { - TransferRequest request = availableRequestQueue.take(); - - // check for error - int result = request.result; - if (result != 0 && !hasError) { - request.result = 0; - throwException(result, "error writing to USB endpoint"); - } - - return request; - - } catch (InterruptedException e) { - // ignore and retry - } - } - } - - /** - * Called by the asynchronous IO completion handler. - * - * @param request the completed request - * @param result the request result code - */ - private synchronized void onCompletion(TransferRequest request, int result) { - request.result = result; - availableRequestQueue.add(request); - numOutstandingRequests -= 1; - } - - private static class TransferRequest { - MemorySegment buffer; - int result; - AsyncIOCompletion completionHandler; + protected void throwException(int errorCode, String message) { + MacosUSBException.throwException(errorCode, message); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index d1a1d0bb..2710d8eb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -37,21 +37,21 @@ /** * MacOS implementation of {@link net.codecrete.usb.USBDevice}. *

- * All read and write operations on endpoints are submitted through synchronized methods in order to control - * concurrency. If it wasn't controlled, the danger is that device and interface pointers are used, which have - * just been closed and thus deallocated by another thread, likely leading to crashes. + * All read and write operations on endpoints are submitted through synchronized methods in order to control + * concurrency. If it wasn't controlled, the danger is that device and interface pointers are used, which have + * just been closed and thus deallocated by another thread, likely leading to crashes. *

*

- * As a consequence of the synchronized submission, blocking operations consists of submitting an - * asynchronous request and waiting for the completion. + * As a consequence of the synchronized submission, blocking operations consists of submitting an + * asynchronous request and waiting for the completion. *

*

- * For the completion callback, an upcall stub is created for each device instance. The device instance is bound - * to this stub. The stub is used as the {@code callback} parameter in the native functions. For each USB - * interface, an event source is registered in the registry's asynchronous IO completion background thread. - * To map the callback to a specific request, the request provides a completion handler. It is assigned a unique - * number. The number is passed as {@code refcon} to the native call while the mapping between the number and the - * completion handler is maintained in a hash map. + * For the completion callback, an upcall stub is created for each device instance. The device instance is bound + * to this stub. The stub is used as the {@code callback} parameter in the native functions. For each USB + * interface, an event source is registered in the registry's asynchronous IO completion background thread. + * To map the callback to a specific request, the request provides a completion handler. It is assigned a unique + * number. The number is passed as {@code refcon} to the native call while the mapping between the number and the + * completion handler is maintained in a hash map. *

*/ public class MacosUSBDevice extends USBDeviceImpl { @@ -63,8 +63,9 @@ public class MacosUSBDevice extends USBDeviceImpl { static { try { asyncIOCompletedMH = MethodHandles.lookup().findStatic(MacosUSBDevice.class, "asyncIOCompleted", - MethodType.methodType(void.class, MacosUSBDevice.class, MemorySegment.class, int.class, MemorySegment.class)); - } catch (IllegalAccessException|NoSuchMethodException e) { + MethodType.methodType(void.class, MacosUSBDevice.class, MemorySegment.class, int.class, + MemorySegment.class)); + } catch (IllegalAccessException | NoSuchMethodException e) { throw new RuntimeException(e); } } @@ -198,8 +199,8 @@ private InterfaceInfo findInterface(int interfaceNumber) { final int service_final = service; cleanup.add(() -> IOKit.IOObjectRelease(service_final)); - final var intf = IoKitHelper.getInterface(service, - IoKitHelper.kIOUSBInterfaceUserClientTypeID, IoKitHelper.kIOUSBInterfaceInterfaceID100); + final var intf = IoKitHelper.getInterface(service, IoKitHelper.kIOUSBInterfaceUserClientTypeID, + IoKitHelper.kIOUSBInterfaceInterfaceID100); if (intf == null) continue; @@ -251,10 +252,11 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna // check alternate setting var altSetting = intf.getAlternate(alternateNumber); if (altSetting == null) - throwException("Interface %d does not have an alternate interface setting %d", interfaceNumber, alternateNumber); + throwException("Interface %d does not have an alternate interface setting %d", interfaceNumber, + alternateNumber); - var intfInfo = claimedInterfaces.stream() - .filter((interf) -> interf.interfaceNumber() == interfaceNumber).findFirst().get(); + var intfInfo = + claimedInterfaces.stream().filter((interf) -> interf.interfaceNumber() == interfaceNumber).findFirst().get(); int ret = IoKitUSB.SetAlternateInterface(intfInfo.iokitInterface(), (byte) alternateNumber); if (ret != 0) @@ -337,12 +339,11 @@ private void updateEndpointList() { } private synchronized EndpointInfo getEndpointInfo(int endpointNumber, USBDirection direction, - USBTransferType transferType1, USBTransferType transferType2) { + USBTransferType transferType1, USBTransferType transferType2) { if (endpoints != null) { byte endpointAddress = (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)); var endpointInfo = endpoints.get(endpointAddress); - if (endpointInfo != null - && (endpointInfo.transferType == transferType1 || endpointInfo.transferType == transferType2)) + if (endpointInfo != null && (endpointInfo.transferType == transferType1 || endpointInfo.transferType == transferType2)) return endpointInfo; } @@ -352,14 +353,13 @@ private synchronized EndpointInfo getEndpointInfo(int endpointNumber, USBDirecti else transferTypeDesc = String.format("%s or %s", transferType1.name(), transferType2.name()); - throwException( - "Endpoint number %d does not exist, is not part of a claimed interface or is not valid for %s transfer in %s direction", - endpointNumber, transferTypeDesc, direction.name()); + throwException("Endpoint number %d does not exist, is not part of a claimed interface or is not valid for %s " + + "transfer in %s direction", endpointNumber, transferTypeDesc, direction.name()); throw new AssertionError("not reached"); } - private static MemorySegment createDeviceRequest(Arena arena, USBDirection direction, - USBControlTransfer setup, MemorySegment data) { + private static MemorySegment createDeviceRequest(Arena arena, USBDirection direction, USBControlTransfer setup, + MemorySegment data) { var deviceRequest = arena.allocate(IOUSBDevRequest.$LAYOUT()); var bmRequestType = (direction == USBDirection.IN ? 0x80 : 0x00) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); @@ -408,7 +408,8 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { @Override public void transferOut(int endpointNumber, byte[] data, int timeout) { - EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); + EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, + USBTransferType.INTERRUPT); try (var arena = Arena.openConfined()) { var nativeData = arena.allocateArray(JAVA_BYTE, data.length); @@ -418,12 +419,14 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { synchronized (request) { if (timeout <= 0 || epInfo.transferType() == USBTransferType.BULK) { // no timeout or timeout handled by operating system - submitTransferOut(endpointNumber, nativeData, data.length, timeout, (result, size) -> onRequestCompleted(request, result, size)); + submitTransferOut(endpointNumber, nativeData, data.length, timeout, + (result, size) -> onRequestCompleted(request, result, size)); waitForRequest(request, USBDirection.OUT, endpointNumber, false); } else { // interrupt transfer with timeout - submitTransferOut(endpointNumber, nativeData, data.length, 0, (result, size) -> onRequestCompleted(request, result, size)); + submitTransferOut(endpointNumber, nativeData, data.length, 0, + (result, size) -> onRequestCompleted(request, result, size)); waitForRequestOrAbort(request, timeout, USBDirection.OUT, endpointNumber); } } @@ -433,7 +436,8 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { @Override public byte[] transferIn(int endpointNumber, int timeout) { - EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); + EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, + USBTransferType.INTERRUPT); try (var arena = Arena.openConfined()) { var nativeData = arena.allocateArray(JAVA_BYTE, epInfo.packetSize()); @@ -442,12 +446,14 @@ public byte[] transferIn(int endpointNumber, int timeout) { synchronized (request) { if (timeout <= 0 || epInfo.transferType() == USBTransferType.BULK) { // no timeout or timeout handled by operating system - submitTransferIn(endpointNumber, nativeData, epInfo.packetSize(), timeout, (result, size) -> onRequestCompleted(request, result, size)); + submitTransferIn(endpointNumber, nativeData, epInfo.packetSize(), timeout, + (result, size) -> onRequestCompleted(request, result, size)); waitForRequest(request, USBDirection.IN, endpointNumber, false); } else { // interrupt transfer with timeout - submitTransferIn(endpointNumber, nativeData, epInfo.packetSize(), 0, (result, size) -> onRequestCompleted(request, result, size)); + submitTransferIn(endpointNumber, nativeData, epInfo.packetSize(), 0, + (result, size) -> onRequestCompleted(request, result, size)); waitForRequestOrAbort(request, timeout, USBDirection.IN, endpointNumber); } } @@ -459,26 +465,29 @@ public byte[] transferIn(int endpointNumber, int timeout) { /** * Submits a transfer IN request to the specified BULK or INTERRUPT endpoint. *

- * A timeout may only be specified for BULK endpoints. + * A timeout may only be specified for BULK endpoints. *

- * @param endpointNumber endpoint number - * @param buffer buffer that will receive data - * @param bufferSize buffer length (should be packet size or multiple thereof) - * @param timeout the timeout, in milliseconds, or 0 for no timeout + * + * @param endpointNumber endpoint number + * @param buffer buffer that will receive data + * @param bufferSize buffer length (should be packet size or multiple thereof) + * @param timeout the timeout, in milliseconds, or 0 for no timeout * @param completionHandler handler that will be called when the request completes */ - synchronized void submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, int timeout, AsyncIOCompletion completionHandler) { + synchronized void submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, int timeout, + AsyncIOCompletion completionHandler) { - EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); + EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, + USBTransferType.INTERRUPT); // submit request int ret; if (timeout <= 0) ret = IoKitUSB.ReadPipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), buffer, bufferSize, - getCompletionUpcallStub(), saveCompletionHandler(completionHandler)); + getCompletionUpcallStub(), saveCompletionHandler(completionHandler)); else ret = IoKitUSB.ReadPipeAsyncTO(epInfo.iokitInterface(), epInfo.pipeIndex(), buffer, bufferSize, timeout, - timeout, getCompletionUpcallStub(), saveCompletionHandler(completionHandler)); + timeout, getCompletionUpcallStub(), saveCompletionHandler(completionHandler)); if (ret != 0) throwException(ret, "failed to submit transfer IN request"); @@ -487,18 +496,20 @@ synchronized void submitTransferIn(int endpointNumber, MemorySegment buffer, int /** * Submits a transfer OUT request to the specified BULK or INTERRUPT endpoint. *

- * A timeout may only be specified for BULK endpoints. + * A timeout may only be specified for BULK endpoints. *

- * @param endpointNumber endpoint number - * @param data buffer with data to be transmitted - * @param dataSize number of bytes to be transmitted - * @param timeout the timeout, in milliseconds, or 0 for no timeout + * + * @param endpointNumber endpoint number + * @param data buffer with data to be transmitted + * @param dataSize number of bytes to be transmitted + * @param timeout the timeout, in milliseconds, or 0 for no timeout * @param completionHandler handler that will be called when the request completes */ synchronized void submitTransferOut(int endpointNumber, MemorySegment data, int dataSize, int timeout, AsyncIOCompletion completionHandler) { - EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); + EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, + USBTransferType.INTERRUPT); // submit request int ret; @@ -515,7 +526,8 @@ synchronized void submitTransferOut(int endpointNumber, MemorySegment data, int /** * Submits a control transfer request. - * @param deviceRequest control transfer request + * + * @param deviceRequest control transfer request * @param completionHandler handler that will be called when the request completes */ synchronized void submitControlTransfer(MemorySegment deviceRequest, AsyncIOCompletion completionHandler) { @@ -523,7 +535,8 @@ synchronized void submitControlTransfer(MemorySegment deviceRequest, AsyncIOComp checkIsOpen(); // submit request - int ret = IoKitUSB.DeviceRequestAsync(device, deviceRequest, getCompletionUpcallStub(), saveCompletionHandler(completionHandler)); + int ret = IoKitUSB.DeviceRequestAsync(device, deviceRequest, getCompletionUpcallStub(), + saveCompletionHandler(completionHandler)); if (ret != 0) throwException(ret, "failed to submit control transfer request"); @@ -535,7 +548,8 @@ private TransferRequest createRequest() { return request; } - private void waitForRequest(TransferRequest request, USBDirection direction, int endpointNumber, boolean ignoreAbort) { + private void waitForRequest(TransferRequest request, USBDirection direction, int endpointNumber, + boolean ignoreAbort) { // wait for request while (request.size == -1) { try { @@ -555,7 +569,8 @@ private void waitForRequest(TransferRequest request, USBDirection direction, int } } - private void waitForRequestOrAbort(TransferRequest request, int timeout, USBDirection direction, int endpointNumber) { + private void waitForRequestOrAbort(TransferRequest request, int timeout, USBDirection direction, + int endpointNumber) { // wait for request or abort when timeout occurs long expiration = System.currentTimeMillis() + timeout; long remainingTimeout = timeout; @@ -571,9 +586,10 @@ private void waitForRequestOrAbort(TransferRequest request, int timeout, USBDire // test for timeout if (request.result == 0 && remainingTimeout <= 0) { - abortTransfer(direction, endpointNumber); + abortTransfers(direction, endpointNumber); waitForRequest(request, direction, endpointNumber, true); - throw new USBTimeoutException(getOperationDescription(direction, endpointNumber) + "aborted due to timeout"); + throw new USBTimeoutException(getOperationDescription(direction, endpointNumber) + "aborted due to " + + "timeout"); } if (request.result != 0) { @@ -599,8 +615,10 @@ private static void onRequestCompleted(TransferRequest request, int result, int } } - public void abortTransfer(USBDirection direction, int endpointNumber) { - EndpointInfo epInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); + @Override + public void abortTransfers(USBDirection direction, int endpointNumber) { + EndpointInfo epInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, + USBTransferType.INTERRUPT); int ret = IoKitUSB.AbortPipe(epInfo.iokitInterface(), epInfo.pipeIndex()); if (ret != 0) @@ -609,19 +627,14 @@ public void abortTransfer(USBDirection direction, int endpointNumber) { @Override public void clearHalt(USBDirection direction, int endpointNumber) { - EndpointInfo epInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); + EndpointInfo epInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, + USBTransferType.INTERRUPT); int ret = IoKitUSB.ClearPipeStallBothEnds(epInfo.iokitInterface(), epInfo.pipeIndex()); if (ret != 0) throwException(ret, "Clearing halt condition failed"); } - - @Override - public synchronized void abortTransfers(USBDirection direction, int endpointNumber) { - throw new UnsupportedOperationException("not implemented yet"); - } - @Override public InputStream openInputStream(int endpointNumber) { // check that endpoint number is valid @@ -651,7 +664,8 @@ private synchronized MemorySegment getCompletionUpcallStub() { if (completionUpcallStub == null) { arena = Arena.openShared(); var methodHandle = asyncIOCompletedMH.bindTo(this); - completionUpcallStub = Linker.nativeLinker().upcallStub(methodHandle, completionHandlerFuncDesc, arena.scope()); + completionUpcallStub = Linker.nativeLinker().upcallStub(methodHandle, completionHandlerFuncDesc, + arena.scope()); } return completionUpcallStub; @@ -695,7 +709,7 @@ private synchronized void addInterfaceEventSource(InterfaceInfo interfaceInfo) { } private synchronized AsyncIOCompletion getCompletionHandler(MemorySegment refcon) { - var key = Integer.valueOf((int)refcon.address()); + var key = Integer.valueOf((int) refcon.address()); var handler = completionHandlers.remove(key); if (!isOpen() && completionHandlers.size() == 0) { @@ -709,7 +723,7 @@ private synchronized AsyncIOCompletion getCompletionHandler(MemorySegment refcon } private static void asyncIOCompleted(MacosUSBDevice device, MemorySegment refcon, int result, MemorySegment arg0) { - device.getCompletionHandler(refcon).completed(result, (int)arg0.address()); + device.getCompletionHandler(refcon).completed(result, (int) arg0.address()); } record InterfaceInfo(MemorySegment iokitInterface, int interfaceNumber) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 8915ad59..58bc19d9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -35,12 +35,18 @@ public class MacosUSBDeviceRegistry extends USBDeviceRegistry { private final MemorySegment KEY_ID_VENDOR = CoreFoundationHelper.createCFStringRef("idVendor", GLOBAL_ALLOCATOR); private final MemorySegment KEY_ID_PRODUCT = CoreFoundationHelper.createCFStringRef("idProduct", GLOBAL_ALLOCATOR); - private final MemorySegment KEY_VENDOR = CoreFoundationHelper.createCFStringRef("kUSBVendorString", GLOBAL_ALLOCATOR); - private final MemorySegment KEY_PRODUCT = CoreFoundationHelper.createCFStringRef("kUSBProductString", GLOBAL_ALLOCATOR); - private final MemorySegment KEY_SERIAL_NUM = CoreFoundationHelper.createCFStringRef("kUSBSerialNumberString", GLOBAL_ALLOCATOR); - private final MemorySegment KEY_DEVICE_CLASS = CoreFoundationHelper.createCFStringRef("bDeviceClass", GLOBAL_ALLOCATOR); - private final MemorySegment KEY_DEVICE_SUBCLASS = CoreFoundationHelper.createCFStringRef("bDeviceSubClass", GLOBAL_ALLOCATOR); - private final MemorySegment KEY_DEVICE_PROTOCOL = CoreFoundationHelper.createCFStringRef("bDeviceProtocol", GLOBAL_ALLOCATOR); + private final MemorySegment KEY_VENDOR = CoreFoundationHelper.createCFStringRef("kUSBVendorString", + GLOBAL_ALLOCATOR); + private final MemorySegment KEY_PRODUCT = CoreFoundationHelper.createCFStringRef("kUSBProductString", + GLOBAL_ALLOCATOR); + private final MemorySegment KEY_SERIAL_NUM = CoreFoundationHelper.createCFStringRef("kUSBSerialNumberString", + GLOBAL_ALLOCATOR); + private final MemorySegment KEY_DEVICE_CLASS = CoreFoundationHelper.createCFStringRef("bDeviceClass", + GLOBAL_ALLOCATOR); + private final MemorySegment KEY_DEVICE_SUBCLASS = CoreFoundationHelper.createCFStringRef("bDeviceSubClass", + GLOBAL_ALLOCATOR); + private final MemorySegment KEY_DEVICE_PROTOCOL = CoreFoundationHelper.createCFStringRef("bDeviceProtocol", + GLOBAL_ALLOCATOR); private final MemorySegment KEY_USB_BCD = CoreFoundationHelper.createCFStringRef("bcdUSB", GLOBAL_ALLOCATOR); private final MemorySegment KEY_DEVICE_BCD = CoreFoundationHelper.createCFStringRef("bcdDevice", GLOBAL_ALLOCATOR); @@ -113,7 +119,8 @@ private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { final int service = svc; cleanup.add(() -> IOKit.IOObjectRelease(service)); - var device = IoKitHelper.getInterface(service, IoKitHelper.kIOUSBDeviceUserClientTypeID, IoKitHelper.kIOUSBDeviceInterfaceID100); + var device = IoKitHelper.getInterface(service, IoKitHelper.kIOUSBDeviceUserClientTypeID, + IoKitHelper.kIOUSBDeviceInterfaceID100); if (device != null) cleanup.add(() -> IoKitUSB.Release(device)); @@ -183,7 +190,8 @@ private USBDevice createDevice(Long entryID, int service, MemorySegment deviceIn Integer subclassCode = IoKitHelper.getPropertyInt(service, KEY_DEVICE_SUBCLASS, arena); Integer protocolCode = IoKitHelper.getPropertyInt(service, KEY_DEVICE_PROTOCOL, arena); - device.setClassCodes(classCode != null ? classCode : 0, subclassCode != null ? subclassCode : 0, protocolCode != null ? protocolCode : 0); + device.setClassCodes(classCode != null ? classCode : 0, subclassCode != null ? subclassCode : 0, + protocolCode != null ? protocolCode : 0); Integer usbVersion = IoKitHelper.getPropertyInt(service, KEY_USB_BCD, arena); Integer deviceVersion = IoKitHelper.getPropertyInt(service, KEY_DEVICE_BCD, arena); @@ -239,7 +247,8 @@ private void onDevicesConnected(MemorySegment ignoredRefCon, int iterator) { * @param ignoredRefCon ignored parameter * @param iterator device iterator */ - private void onDevicesDisconnected(@SuppressWarnings("SameParameterValue") MemorySegment ignoredRefCon, int iterator) { + private void onDevicesDisconnected(@SuppressWarnings("SameParameterValue") MemorySegment ignoredRefCon, + int iterator) { // process device iterator for disconnected devices iterateDevices(iterator, (entryId, service, deviceIntf) -> { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java index eec54c27..98ec23b7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java @@ -21,7 +21,8 @@ public class MacosUSBException extends USBException { *

* The message for the macOS error code is looked up and appended to the message. *

- * @param message exception message + * + * @param message exception message * @param errorCode macOS error code (usually returned by macOS functions) */ public MacosUSBException(String message, int errorCode) { @@ -38,9 +39,10 @@ private static String machErrorMessage(int errorCode) { *

* The message for the macOS error code is looked up and appended to the message. *

+ * * @param errorCode macOS error code (usually returned by macOS functions) - * @param message exception message format ({@link String#format(String, Object...)} style) - * @param args arguments for exception message + * @param message exception message format ({@link String#format(String, Object...)} style) + * @param args arguments for exception message */ static void throwException(int errorCode, String message, Object... args) { var formattedMessage = String.format(message, args); @@ -53,8 +55,9 @@ static void throwException(int errorCode, String message, Object... args) { /** * Throws a USB exception. + * * @param message exception message format ({@link String#format(String, Object...)} style) - * @param args arguments for exception message + * @param args arguments for exception message */ static void throwException(String message, Object... args) { throw new USBException(String.format(message, args)); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java index bf40c7c1..66b3102d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java @@ -21,6 +21,7 @@ public class UUID { /** * Creates a CFUUID struct from a byte array. + * * @param bytes UUID as 16 bytes * @return the CFUUID */ From bebd5cf159976133aa65cf82ff1c281a83711b2b Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 21 Feb 2023 18:37:24 +0100 Subject: [PATCH 202/433] iostreams using blocking queues (C++/Linux) --- reference/linux/.vscode/settings.json | 6 +- reference/linux/CMakeLists.txt | 1 + reference/linux/blocking_queue.hpp | 70 +++++++ reference/linux/usb_device.hpp | 4 + reference/linux/usb_iostream.cpp | 278 ++++++++++++-------------- reference/linux/usb_iostream.hpp | 126 +++++++----- reference/linux/usb_registry.cpp | 2 +- reference/linux/usb_registry.hpp | 1 - 8 files changed, 280 insertions(+), 208 deletions(-) create mode 100644 reference/linux/blocking_queue.hpp diff --git a/reference/linux/.vscode/settings.json b/reference/linux/.vscode/settings.json index 9eac4d83..753dfa42 100644 --- a/reference/linux/.vscode/settings.json +++ b/reference/linux/.vscode/settings.json @@ -53,6 +53,10 @@ "stop_token": "cpp", "streambuf": "cpp", "thread": "cpp", - "typeinfo": "cpp" + "typeinfo": "cpp", + "set": "cpp", + "fstream": "cpp", + "iomanip": "cpp", + "sstream": "cpp" } } \ No newline at end of file diff --git a/reference/linux/CMakeLists.txt b/reference/linux/CMakeLists.txt index af64e603..8cad5236 100644 --- a/reference/linux/CMakeLists.txt +++ b/reference/linux/CMakeLists.txt @@ -9,6 +9,7 @@ find_package(Threads REQUIRED) set(SOURCES assertion.cpp assertion.hpp + blocking_queue.hpp config_parser.cpp config_parser.hpp configuration.cpp configuration.hpp main.cpp diff --git a/reference/linux/blocking_queue.hpp b/reference/linux/blocking_queue.hpp new file mode 100644 index 00000000..4b2a8b49 --- /dev/null +++ b/reference/linux/blocking_queue.hpp @@ -0,0 +1,70 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code common for Linux / macOS / Windows +// + +#pragma once + +#include +#include +#include + + +/** + * Blocking FIFO queue for passing work from one thread to another. + * + * The queue is unbounded. + */ +template +class blocking_queue { +public: + /** + * Indicates if the queue is empty. + * + * @return 'true' if the queue is empty, 'false' if the queue contains elements + */ + bool empty() const { + std::lock_guard lock(guard); + return queue.empty(); + } + + /** + * Adds the item to the end of the queue. + * + * @param item item to add + */ + void put(const T& item) { + { + std::lock_guard lock(guard); + queue.push(item); + } + + signal.notify_one(); + } + + /** + * Takes the oldest item from the queue and removes it. + * + * Waits until an item is available. + * + * @return item removed from queue + */ + T take() { + std::unique_lock lock(guard); + while (queue.empty()) + signal.wait(lock); + + T item = queue.front(); + queue.pop(); + return item; + } + +private: + std::queue queue; + mutable std::mutex guard; + std::condition_variable signal; +}; diff --git a/reference/linux/usb_device.hpp b/reference/linux/usb_device.hpp index 065f23bf..625186ba 100644 --- a/reference/linux/usb_device.hpp +++ b/reference/linux/usb_device.hpp @@ -9,6 +9,7 @@ #pragma once +#include #include #include #include @@ -18,6 +19,9 @@ #include "configuration.hpp" +typedef std::function usb_io_callback; + + /** * USB control request type. * diff --git a/reference/linux/usb_iostream.cpp b/reference/linux/usb_iostream.cpp index ab79bfde..727e82be 100644 --- a/reference/linux/usb_iostream.cpp +++ b/reference/linux/usb_iostream.cpp @@ -14,221 +14,193 @@ // --- usb_istreambuf --- usb_istreambuf::usb_istreambuf(usb_device_ptr device, int endpoint_number) -: device_(device), ep_num_(endpoint_number), is_closed_(false), submitted_index_(0), completed_index_(0), processed_index_(-1) { +: device(device), endpoint_number(endpoint_number), is_closed(false), num_outstanding_requests(0) { + setg(nullptr, nullptr, nullptr); - buffer_size_ = 8 * device->get_endpoint(usb_direction::in, endpoint_number).packet_size(); - - // create completion handler lambda - io_completion = [this]() { on_completed(); }; - - // initialize the URBs - for (int i = 0; i < num_outstanding_requests; i++) { - usbdevfs_urb* urb = urbs_ + i; - memset(urb, 0, sizeof(*urb)); - urb->type = USBDEVFS_URB_TYPE_BULK; - urb->endpoint = 128 + ep_num_; - urb->buffer = new uint8_t[buffer_size_]; - urb->buffer_length = buffer_size_; - urb->usercontext = &io_completion; + buffer_size = 8 * device->get_endpoint(usb_direction::in, endpoint_number).packet_size(); + + // allocate the buffers and submit requests + memset(requests, 0, sizeof(requests)); + for (int i = 0; i < max_outstanding_requests; i++) { + transfer_request* request = &requests[i]; + request->io_completion = [this, request]() { on_completed(request); }; + request->urb.type = USBDEVFS_URB_TYPE_BULK; + request->urb.endpoint = 128 + endpoint_number; + request->urb.buffer = new uint8_t[buffer_size]; + request->urb.buffer_length = buffer_size; + request->urb.usercontext = &request->io_completion; + + if (i == 0) + current_request = request; + else + submit_transfer(request); } - - // start requests except for one - const std::lock_guard lock(io_mutex); - for (int i = 0; i < num_outstanding_requests - 1; i++) - submit_request(); } usb_istreambuf::~usb_istreambuf() { close(); // free buffers - for (int i = 0; i < num_outstanding_requests; i++) - delete [] reinterpret_cast(urbs_[i].buffer); + for (int i = 0; i < max_outstanding_requests; i++) + delete[] reinterpret_cast(requests[i].urb.buffer); } void usb_istreambuf::close() { - const std::lock_guard lock(io_mutex); - - is_closed_ = true; - io_condition.notify_all(); + is_closed = true; + setg(nullptr, nullptr, nullptr); - while (submitted_index_ > completed_index_) { - submitted_index_ -= 1; - int index = submitted_index_ % num_outstanding_requests; - device_->cancel_urb(&urbs_[index]); + // cancel outstanding requests + for (int i = 0; i < max_outstanding_requests; i++) { + if (!requests[i].is_completed) + device->cancel_urb(&requests[i].urb); } + + // wait until completion handlers have been called + while (num_outstanding_requests > 0) + wait_for_request_completion(); } -void usb_istreambuf::submit_request() { - int index = submitted_index_ % num_outstanding_requests; - submitted_index_ += 1; +void usb_istreambuf::submit_transfer(transfer_request* request) { + request->is_completed = false; + device->submit_urb(&request->urb); + num_outstanding_requests += 1; +} - device_->submit_urb(&urbs_[index]); +void usb_istreambuf::on_completed(transfer_request* request) { + request->is_completed = true; + completed_request_queue.put(request); } -void usb_istreambuf::on_completed() { - const std::lock_guard lock(io_mutex); - if (is_closed_) { - completed_index_ += 1; - if (completed_index_ == submitted_index_) - delete this; - return; - } - - completed_index_ += 1; - io_condition.notify_all(); +usb_istreambuf::transfer_request* usb_istreambuf::wait_for_request_completion() { + transfer_request* request = completed_request_queue.take(); + num_outstanding_requests -= 1; + return request; } usb_istreambuf::int_type usb_istreambuf::underflow() { - if (is_closed_) + if (is_closed) return traits_type::eof(); - + if (gptr() < egptr()) return traits_type::to_int_type(*gptr()); - - // loop until no ZLP has been received - while (true) { - std::unique_lock wait_lock(io_mutex); - processed_index_ += 1; - submit_request(); - - // wait until a completed request is available - io_condition.wait(wait_lock, [this] { return completed_index_ - processed_index_ > 0 || is_closed_; }); - - if (is_closed_) - return traits_type::eof(); - - int index = processed_index_ % num_outstanding_requests; - usbdevfs_urb* urb = urbs_ + index; - usb_error::check(urb->status, "error reading from USB endpoint"); - - // set stream buffer to buffer from completed request - char* buf = reinterpret_cast(urb->buffer); - int size = urb->actual_length; - - if (size != 0) { - setg(buf, buf, buf + size); - return traits_type::to_int_type(*gptr()); - } - } + + // loop until non-ZLP has been received + do { + submit_transfer(current_request); + + current_request = wait_for_request_completion(); + usb_error::check(current_request->result_code(), "error reading from USB endpoint"); + + char* buf = reinterpret_cast(current_request->urb.buffer); + int size = current_request->result_size(); + setg(buf, buf, buf + size); + + } while (current_request->result_size() == 0); + + return traits_type::to_int_type(*gptr()); } // --- usb_ostreambuf --- usb_ostreambuf::usb_ostreambuf(usb_device_ptr device, int endpoint_number) -: device_(device), ep_num_(endpoint_number), is_closed_(false), processing_index_(0), - completed_index_(0), checked_index_(0), needs_zlp_(false) { - - buffer_size_ = 8 * device->get_endpoint(usb_direction::out, endpoint_number).packet_size(); +: device(device), endpoint_number(endpoint_number), is_closed(false), needs_zlp(false) { - // create completion handler lambda - io_completion = [this]() { on_completed(); }; - - // initialize the URBs - for (int i = 0; i < num_outstanding_requests; i++) { - usbdevfs_urb* urb = urbs_ + i; - memset(urb, 0, sizeof(urb)); - urb->type = USBDEVFS_URB_TYPE_BULK; - urb->endpoint = ep_num_; - urb->buffer = new uint8_t[buffer_size_]; - urb->buffer_length = buffer_size_; - urb->usercontext = &io_completion; + packet_size = device->get_endpoint(usb_direction::out, endpoint_number).packet_size(); + buffer_size = 1 * packet_size; + + // create requests + memset(requests, 0, sizeof(requests)); + for (int i = 0; i < max_outstanding_requests; i++) { + transfer_request* request = &requests[i]; + request->io_completion = [this, request](void) { on_completed(request); }; + request->urb.type = USBDEVFS_URB_TYPE_BULK; + request->urb.endpoint = endpoint_number; + request->urb.buffer = new uint8_t[buffer_size]; + request->urb.usercontext = &request->io_completion; } - - char* buf = reinterpret_cast(urbs_[0].buffer); - setp(buf, buf + buffer_size_); + + fill_queue(); } - + usb_ostreambuf::~usb_ostreambuf() { // flush all data sync(); // free buffers - for (int i = 0; i < num_outstanding_requests; i++) - delete [] reinterpret_cast(urbs_[i].buffer); + for (int i = 0; i < max_outstanding_requests; i++) + delete[] reinterpret_cast(requests[i].urb.buffer); } -int usb_ostreambuf::sync() { - std::unique_lock wait_lock(io_mutex); +void usb_ostreambuf::fill_queue() { + for (int i = 1; i < max_outstanding_requests; i++) + available_request_queue.put(&requests[i]); + // configure stream buffer for first request + current_request = &requests[0]; + char* buf = reinterpret_cast(current_request->urb.buffer); + setp(buf, buf + buffer_size); +} + +int usb_ostreambuf::sync() { // submit request if there is any data in the current buffer auto size = pptr() - pbase(); - if (size > 0) { - int index = processing_index_ % num_outstanding_requests; - usbdevfs_urb* urb = urbs_ + index; - urb->buffer_length = size; - device_->submit_urb(urb); - processing_index_ += 1; - needs_zlp_ = size == buffer_size_; - } - + if (size > 0) + submit_transfer((int)size); + // send a zero-length packet if required - if (needs_zlp_) { - // wait until an unused buffer is available - io_condition.wait(wait_lock, [this] { return processing_index_ - completed_index_ < num_outstanding_requests; }); - check_for_errors(); - - int index = processing_index_ % num_outstanding_requests; - usbdevfs_urb* urb = urbs_ + index; - urb->buffer_length = 0; - device_->submit_urb(urb); - processing_index_ += 1; - needs_zlp_ = false; - } + if (needs_zlp) + submit_transfer(0); + + // Wait until all buffers have been transmitted by removing them from the + // queue and reinserting them. One request is the current request. + // So the queue only contains max_outstanding_requests - 1 requests. + for (int i = 0; i < max_outstanding_requests - 1; i++) + wait_for_available_transfer(); + + fill_queue(); - // wait until all buffers have been transmitted - io_condition.wait(wait_lock, [this] { return processing_index_ == completed_index_; }); - check_for_errors(); - return 0; } int usb_ostreambuf::overflow (int c) { - std::unique_lock wait_lock(io_mutex); - // submit request auto size = pptr() - pbase(); - int index = processing_index_ % num_outstanding_requests; - usbdevfs_urb* urb = urbs_ + index; - urb->buffer_length = size; - device_->submit_urb(urb); - processing_index_ += 1; - needs_zlp_ = size == buffer_size_; - - // wait until an unused buffer is available - io_condition.wait(wait_lock, [this] { return processing_index_ - completed_index_ < num_outstanding_requests; }); - check_for_errors(); - - // configure stream buffer - index = processing_index_ % num_outstanding_requests; - urb = urbs_ + index; - char* buf = reinterpret_cast(urb->buffer); - setp(buf, buf + buffer_size_); + submit_transfer((int)size); // insert char if (c != traits_type::eof()) { *pptr() = (char)c; - pbump( 1 ); + pbump(1); } - + return c; } -void usb_ostreambuf::on_completed() { - const std::lock_guard lock(io_mutex); - completed_index_ += 1; - io_condition.notify_all(); +void usb_ostreambuf::submit_transfer(int size) { + current_request->urb.buffer_length = size; + device->submit_urb(¤t_request->urb); + needs_zlp = size == packet_size; + + current_request = wait_for_available_transfer(); + + // configure stream buffer + char* buf = reinterpret_cast(current_request->urb.buffer); + setp(buf, buf + buffer_size); } -void usb_ostreambuf::check_for_errors() { - while (completed_index_ - checked_index_ > 0) { - int index = completed_index_ % num_outstanding_requests; - usbdevfs_urb* urb = urbs_ + index; - usb_error::check(urb->status, "error writing to USB endpoint"); - checked_index_ += 1; - } +void usb_ostreambuf::on_completed(transfer_request* request) { + available_request_queue.put(request); +} + +usb_ostreambuf::transfer_request* usb_ostreambuf::wait_for_available_transfer() { + auto request = available_request_queue.take(); + + // check for error + usb_error::check(request->result_code(), "error writing to USB endpoint"); + + return request; } diff --git a/reference/linux/usb_iostream.hpp b/reference/linux/usb_iostream.hpp index 23a6194a..e64c6efc 100644 --- a/reference/linux/usb_iostream.hpp +++ b/reference/linux/usb_iostream.hpp @@ -9,12 +9,12 @@ #pragma once -#include #include #include #include #include #include "usb_device.hpp" +#include "blocking_queue.hpp" /** * Input stream buffer for USB bulk or interrupt endpoint. @@ -29,44 +29,53 @@ class usb_istreambuf : public std::streambuf { /// Destructor virtual ~usb_istreambuf(); - /// Closes this buffer. This stream buffer will automatically free itself. - void close(); - protected: /// Called when the internal buffer has no further data to read. virtual int_type underflow(); - void on_completed(); - private: - void submit_request(); + /// Transfer request + struct transfer_request { + /// USB request buffer + usbdevfs_urb urb; + /// IO completion handler + usb_io_callback io_completion; + /// indicates if the request has completed + bool is_completed; + + int result_code() { + return urb.status; + } + + int result_size() { + return urb.actual_length; + } + }; + + void submit_transfer(transfer_request* request); + void close(); + void on_completed(transfer_request* request); + transfer_request* wait_for_request_completion(); /// Maximum number of concurrently outstanding requests - static constexpr int num_outstanding_requests = 4; + static constexpr int max_outstanding_requests = 4; /// USB device - usb_device_ptr device_; + usb_device_ptr device; /// endpoint number - int ep_num_; + int endpoint_number; /// Indicates that this stream buffer is closed - bool is_closed_; + bool is_closed; /// buffer size - int buffer_size_; - /// Mutex for synchronization between input stream caller and background thread handling IO completion. - std::mutex io_mutex; - /// Condition for synchronization between input stream caller and background thread handling IO completion - std::condition_variable io_condition; - /// Index after last submitted IO request - unsigned int submitted_index_; - /// Index after last completed IO request - unsigned int completed_index_; - /// Index after last processed IO request - unsigned int processed_index_; - /// USB request buffers - usbdevfs_urb urbs_[num_outstanding_requests]; - /// IO completion lambda - std::function io_completion; -}; + int buffer_size; + /// transfer requests + transfer_request requests[max_outstanding_requests]; + /// queue with completed requests + blocking_queue completed_request_queue; + /// number of outstanding requests (requests pending with OS and requests in queue) + int num_outstanding_requests; + /// current request being read from + transfer_request* current_request;}; /** * Output stream buffer for USB bulk or interrupt endpoint. @@ -87,38 +96,51 @@ class usb_ostreambuf : public std::streambuf { /// Called when the internal buffer has no space left to add more data. virtual int overflow (int c); - void on_completed(); - - void check_for_errors(); - private: + /// Transfer request + struct transfer_request { + /// USB request buffer + usbdevfs_urb urb; + /// IO completion handler + usb_io_callback io_completion; + /// indicates if the request has completed + bool is_completed; + + int result_code() { + return urb.status; + } + + int result_size() { + return urb.actual_length; + } + }; + + void fill_queue(); + void submit_transfer(int size); + transfer_request* wait_for_available_transfer(); + void on_completed(transfer_request* request); + /// Maximum number of concurrently outstanding requests - static constexpr int num_outstanding_requests = 4; - + static constexpr int max_outstanding_requests = 4; + /// USB device - usb_device_ptr device_; + usb_device_ptr device; /// endpoint number - int ep_num_; + int endpoint_number; /// Indicates that this stream buffer is closed - bool is_closed_; + bool is_closed; /// Indicates if a zero-length packet is required - bool needs_zlp_; + bool needs_zlp; + /// packet size + int packet_size; /// buffer size - int buffer_size_; - /// Mutex for synchronization between output stream caller and background thread handling IO completion. - std::mutex io_mutex; - /// Condition for synchronization between output stream caller and background thread handling IO completion - std::condition_variable io_condition; - /// Index of buffer being currently used by base class - unsigned int processing_index_; - /// Index after last completed IO request - unsigned int completed_index_; - /// Index after last completed IO request that has been checked for errors - unsigned int checked_index_; - /// USB request buffers - usbdevfs_urb urbs_[num_outstanding_requests]; - /// IO completion lambda - std::function io_completion; + int buffer_size; + /// transfer requests + transfer_request requests[max_outstanding_requests]; + /// queue with available requests + blocking_queue available_request_queue; + /// current request being written to + transfer_request* current_request; }; /** diff --git a/reference/linux/usb_registry.cpp b/reference/linux/usb_registry.cpp index 0ff1d6db..865b2632 100644 --- a/reference/linux/usb_registry.cpp +++ b/reference/linux/usb_registry.cpp @@ -307,7 +307,7 @@ void usb_registry::async_io_run() { if (ret < 0) usb_error::throw_error("internal error (reap URB)"); - auto completion = reinterpret_cast*>(urb->usercontext); + auto completion = reinterpret_cast(urb->usercontext); (*completion)(); } } diff --git a/reference/linux/usb_registry.hpp b/reference/linux/usb_registry.hpp index 2274289e..6a95dcb2 100644 --- a/reference/linux/usb_registry.hpp +++ b/reference/linux/usb_registry.hpp @@ -21,7 +21,6 @@ struct udev; struct udev_device; - /** * Registry of connected USB devices. */ From edb6c4fea4d8cb6ace05b0c458106be0f45d15dd Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 22 Feb 2023 20:00:47 +0100 Subject: [PATCH 203/433] High throughput input/output streams (Linux) --- java-does-usb/jextract/linux/gen_linux.sh | 8 + .../usb/common/AsyncEndpointInputStream.java | 214 --------- .../usb/common/AsyncEndpointOutputStream.java | 255 ----------- .../usb/common/EndpointInputStream.java | 200 ++++++-- .../usb/common/EndpointOutputStream.java | 246 ++++++++-- .../codecrete/usb/common/USBDeviceImpl.java | 15 - .../main/java/net/codecrete/usb/linux/IO.java | 35 +- .../usb/linux/LinuxEndpointInputStream.java | 30 ++ .../usb/linux/LinuxEndpointOutputStream.java | 30 ++ .../codecrete/usb/linux/LinuxUSBDevice.java | 46 +- .../usb/linux/LinuxUSBDeviceRegistry.java | 242 +++++++++- .../usb/linux/LinuxUSBException.java | 16 +- .../net/codecrete/usb/linux/USBDevFS.java | 5 + .../codecrete/usb/linux/gen/errno/errno.java | 8 + .../codecrete/usb/linux/gen/poll/poll.java | 16 + .../linux/gen/usbdevice_fs/usbdevfs_urb.java | 430 ++++++++++++++++++ .../linux/gen/usbdevice_fs/usbdevice_fs.java | 8 + .../usb/macos/MacosEndpointInputStream.java | 4 +- .../usb/macos/MacosEndpointOutputStream.java | 4 +- .../windows/WindowsEndpointInputStream.java | 4 +- .../windows/WindowsEndpointOutputStream.java | 4 +- .../usb/windows/WindowsUSBDeviceRegistry.java | 1 - 22 files changed, 1243 insertions(+), 578 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/AsyncEndpointInputStream.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/AsyncEndpointOutputStream.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index efa5dc6e..a277c3fd 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -16,6 +16,7 @@ $JEXTRACT --source --output ../../src/main/java \ --target-package net.codecrete.usb.linux.gen.errno \ --include-constant ETIMEDOUT \ --include-constant EPIPE \ + --include-constant EBADF \ /usr/include/errno.h # string.h @@ -48,12 +49,17 @@ $JEXTRACT --source --output ../../src/main/java \ --include-struct usbdevfs_bulktransfer \ --include-struct usbdevfs_ctrltransfer \ --include-struct usbdevfs_setinterface \ + --include-struct usbdevfs_urb \ --include-constant USBDEVFS_CONTROL \ --include-constant USBDEVFS_BULK \ --include-constant USBDEVFS_CLAIMINTERFACE \ --include-constant USBDEVFS_RELEASEINTERFACE \ --include-constant USBDEVFS_SETINTERFACE \ --include-constant USBDEVFS_CLEAR_HALT \ + --include-constant USBDEVFS_SUBMITURB \ + --include-constant USBDEVFS_DISCARDURB \ + --include-constant USBDEVFS_REAPURB \ + --include-constant USBDEVFS_URB_TYPE_BULK \ /usr/include/linux/usbdevice_fs.h # libudev.h @@ -90,5 +96,7 @@ $JEXTRACT --source --output ../../src/main/java \ --include-function poll \ --include-struct pollfd \ --include-constant POLLIN \ + --include-constant POLLOUT \ + --include-constant POLLERR \ /usr/include/poll.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncEndpointInputStream.java deleted file mode 100644 index 20d7a21f..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncEndpointInputStream.java +++ /dev/null @@ -1,214 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2023 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.common; - -import net.codecrete.usb.USBDirection; -import net.codecrete.usb.USBException; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.foreign.Arena; -import java.lang.foreign.MemorySegment; -import java.util.concurrent.ArrayBlockingQueue; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; - -/** - * Input stream for bulk endpoints – optimized for high throughput. - * - *

- * Multiple asynchronous transfer IN requests are submitted to achieve a good - * degree of concurrency between the USB communication handled by the operating - * system and the consuming application code. - *

- *

- * For thread synchronization (between the background thread handling IO completion - * and the consuming application thread) a blocking queue is used. When an transfer IN - * requests completes, the background thread adds it to the queue. The consuming code - * waits for the next item in the queue. - *

- */ -public abstract class AsyncEndpointInputStream extends InputStream { - - private static final int MAX_OUTSTANDING_REQUESTS = 8; - - protected USBDeviceImpl device; - protected final int endpointNumber; - // Arena to allocate buffers and completion handlers - protected final Arena arena; - // Size of buffers (multiple of packet size) - protected final int bufferSize; - // Queue of completed requests - private final ArrayBlockingQueue completedRequestQueue; - // Number of outstanding requests (includes requests pending with the - // operating system and requests in the completed queue) - private int numOutstandingRequests; - // Request and buffer being currently read from - private TransferRequest currentRequest; - // Read offset within current request - private int readOffset; - - /** - * Creates a new instance - * - * @param device USB device - * @param endpointNumber endpoint number - */ - protected AsyncEndpointInputStream(USBDeviceImpl device, int endpointNumber) { - this.device = device; - this.endpointNumber = endpointNumber; - - bufferSize = 4 * device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); - completedRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); - - // create all requests and submit all except one - arena = Arena.openShared(); - try { - for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { - final var request = new TransferRequest(); - request.buffer = arena.allocate(bufferSize, 8); - request.completionHandler = (result, size) -> onCompletion(request, result, size); - - if (i == 0) { - currentRequest = request; - } else { - submitRequest(request); - } - } - } catch (Throwable t) { - collectOutstandingRequests(); - throw t; - } - } - - @SuppressWarnings("RedundantThrows") - @Override - public void close() throws IOException { - if (isClosed()) - return; - - // abort all transfers on endpoint - try { - device.abortTransfers(USBDirection.IN, endpointNumber); - } catch (USBException e) { - // If aborting the transfer is not possible, the device has - // likely been closed or unplugged. So all outstanding - // requests will terminate anyway. - } - device = null; - - collectOutstandingRequests(); - } - - private void collectOutstandingRequests() { - // wait until completion handlers have been called - while (numOutstandingRequests > 0) - waitForRequestCompletion(); - - completedRequestQueue.clear(); - currentRequest = null; - arena.close(); - } - - @Override - public int read() throws IOException { - if (isClosed()) - return -1; - - if (available() == 0) - receiveMoreData(); - - int b = currentRequest.buffer.get(JAVA_BYTE, readOffset) & 0xff; - readOffset += 1; - return b; - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - if (isClosed()) - return -1; - - if (available() == 0) - receiveMoreData(); - - // copy data to receiving buffer - int n = Math.min(len, currentRequest.resultSize - readOffset); - MemorySegment.copy(currentRequest.buffer, readOffset, MemorySegment.ofArray(b), off, n); - readOffset += n; - - // TODO: poll for further completed requests if 'n' is less than 'len' - - return n; - } - - @SuppressWarnings("RedundantThrows") - @Override - public int available() throws IOException { - return currentRequest.resultSize - readOffset; - } - - private boolean isClosed() { - return device == null; - } - - private void receiveMoreData() throws IOException { - try { - // loop until non-ZLP has been received - do { - submitRequest(currentRequest); - - currentRequest = waitForRequestCompletion(); - readOffset = 0; - - // check for error - if (currentRequest.result != 0) - throwException(currentRequest.result, "error reading from USB endpoint"); - - } while (currentRequest.resultSize == 0); - - } catch (Throwable t) { - close(); - throw t; - } - } - - void submitRequest(TransferRequest request) { - submitTransferIn(request.buffer, bufferSize, request.completionHandler); - numOutstandingRequests += 1; - } - - protected abstract void submitTransferIn(MemorySegment buffer, int bufferSize, AsyncIOCompletion completion); - - protected abstract void throwException(int errorCode, String message); - - void onCompletion(TransferRequest request, int result, int size) { - request.result = result; - request.resultSize = size; - completedRequestQueue.add(request); - } - - TransferRequest waitForRequestCompletion() { - while (true) { - try { - TransferRequest request = completedRequestQueue.take(); - numOutstandingRequests -= 1; - return request; - - } catch (InterruptedException e) { - // ignore and retry - } - } - } - - private static class TransferRequest { - MemorySegment buffer; - int result; - int resultSize; - AsyncIOCompletion completionHandler; - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncEndpointOutputStream.java deleted file mode 100644 index 21cdbee4..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncEndpointOutputStream.java +++ /dev/null @@ -1,255 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2023 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.common; - -import net.codecrete.usb.USBDirection; - -import java.io.IOException; -import java.io.OutputStream; -import java.lang.foreign.Arena; -import java.lang.foreign.MemorySegment; -import java.util.Arrays; -import java.util.concurrent.ArrayBlockingQueue; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; - -/** - * Output stream for bulk endpoints – optimized for high throughput. - * - *

- * Multiple asynchronous transfer OUT requests are submitted to achieve a good - * degree of concurrency between the USB communication handled by the operating - * system and the producing application code. The number of requests is limited - * in order to retain the flow control and keep memory usage at a reasonable size. - *

- *

- * For thread synchronization (between the background thread handling IO completion - * and the producing application thread) a blocking queue is used. It is prefilled with - * requests ready to be used for a transfer. The background thread adds the completed - * requests back to this queue. The producing application thread waits until a request - * is available for use. - *

- */ -public abstract class AsyncEndpointOutputStream extends OutputStream { - - private static final int MAX_OUTSTANDING_REQUESTS = 4; - - protected USBDeviceImpl device; - protected final int endpointNumber; - protected final Arena arena; - // Endpoint's packet size - private final int packetSize; - // Size of buffers (multiple of packet size) - private final int bufferSize; - // Blocking queue of available requests (to limit the number of submitted requests) - private final ArrayBlockingQueue availableRequestQueue; - private boolean needsZlp; - private TransferRequest currentRequest; - private int writeOffset; - private int numOutstandingRequests; - private boolean hasError; - - - /** - * Creates a new instance - * @param device USB device - * @param endpointNumber endpoint number - */ - protected AsyncEndpointOutputStream(USBDeviceImpl device, int endpointNumber) { - this.device = device; - this.endpointNumber = endpointNumber; - - packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize(); - bufferSize = packetSize; - - availableRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); - arena = Arena.openShared(); - - // prefill request queue - for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { - final var request = new TransferRequest(); - request.buffer = arena.allocate(bufferSize, 8); - request.completionHandler = (result, size) -> onCompletion(request, result); - - if (i == 0) { - currentRequest = request; - } else { - availableRequestQueue.add(request); - } - } - } - - @Override - public void close() throws IOException { - if (isClosed()) - return; - - if (!hasError) - flush(); - else - waitForOutstandingRequests(); - - device = null; - availableRequestQueue.clear(); - currentRequest = null; - arena.close(); - } - - @Override - public void write(int b) throws IOException { - if (isClosed()) - throw new IOException("Bulk endpoint output stream has been closed"); - - currentRequest.buffer.set(JAVA_BYTE, writeOffset, (byte)b); - writeOffset += 1; - if (writeOffset == bufferSize) - submitTransfer(writeOffset); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - if (isClosed()) - throw new IOException("Bulk endpoint output stream has been closed"); - - while (len > 0) { - int chunkSize = Math.min(len, bufferSize - writeOffset); - MemorySegment.copy(b, off, currentRequest.buffer, JAVA_BYTE, writeOffset, chunkSize); - writeOffset += chunkSize; - off += chunkSize; - len -= chunkSize; - - if (writeOffset == bufferSize) - submitTransfer(writeOffset); - } - } - - @Override - public void flush() throws IOException { - if (isClosed()) - throw new IOException("Bulk endpoint output stream has been closed"); - - if (writeOffset > 0) - submitTransfer(writeOffset); - - if (needsZlp) - submitTransfer(0); - - waitForOutstandingRequests(); - } - - private boolean isClosed() { - return device == null; - } - - /** - * Submits a request for transfer and set a new request - * as the current one, possibly waiting until it is ready. - *

- * Throws an exception if the request to be reused has completed with an error on the - * previous operation. The exception is suppressed if {@code hasError} flag is set. - *

- * - * @param size size of data to be transmitted - */ - private void submitTransfer(int size) throws IOException { - try { - submitTransferOut(currentRequest.buffer, size, currentRequest.completionHandler); - - synchronized (this) { - numOutstandingRequests += 1; - } - - needsZlp = size == packetSize; - writeOffset = 0; - currentRequest = waitForAvailableRequest(); - - } catch (Throwable t) { - hasError = true; - close(); - throw t; - } - } - - /** - * Wait until all outstanding requests have been completed. - *

- * Throws an exception if any of the requests has completed with an error. - * The exception is suppressed if {@code hasError} flag is set. - *

- */ - private void waitForOutstandingRequests() { - // Wait until all buffers have been transmitted by removing them from the - // queue and reinserting them. - - int numRequests; - synchronized (this) { - numRequests = numOutstandingRequests + availableRequestQueue.size(); - } - - if (numRequests == 0) - return; - - var requests = new TransferRequest[numRequests]; - for (int i = 0; i < numRequests; i++) - requests[i] = waitForAvailableRequest(); - - // reinsert the requests - if (!hasError) - availableRequestQueue.addAll(Arrays.asList(requests)); - } - - /** - * Wait until one of the allocated requests is available for use. - *

- * Throws an exception if the request to be reused has completed with an error on the - * previous operation. The exception is suppressed if {@code hasError} flag is set. - *

- * @return request ready for use - */ - private TransferRequest waitForAvailableRequest() { - while (true) { - try { - TransferRequest request = availableRequestQueue.take(); - - // check for error - int result = request.result; - if (result != 0 && !hasError) { - request.result = 0; - throwException(result, "error reading from USB endpoint"); - } - - return request; - - } catch (InterruptedException e) { - // ignore and retry - } - } - } - - /** - * Called by the asynchronous IO completion handler. - * - * @param request the completed request - * @param result the request result code - */ - private synchronized void onCompletion(TransferRequest request, int result) { - request.result = result; - availableRequestQueue.add(request); - numOutstandingRequests -= 1; - } - - protected abstract void submitTransferOut(MemorySegment data, int dataSize, AsyncIOCompletion completion); - - protected abstract void throwException(int errorCode, String message); - - private static class TransferRequest { - MemorySegment buffer; - int result; - AsyncIOCompletion completionHandler; - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index 0d829206..407db1b2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -1,59 +1,147 @@ // // Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher +// Copyright (c) 2023 Manuel Bleichenbacher // Licensed under MIT License // https://opensource.org/licenses/MIT // package net.codecrete.usb.common; -import net.codecrete.usb.USBDevice; +import net.codecrete.usb.USBDirection; +import net.codecrete.usb.USBException; import java.io.IOException; import java.io.InputStream; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.util.concurrent.ArrayBlockingQueue; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; /** - * Input stream receiving data from a USB bulk endpoint. + * Input stream for bulk endpoints – optimized for high throughput. + * + *

+ * Multiple asynchronous transfer IN requests are submitted to achieve a good + * degree of concurrency between the USB communication handled by the operating + * system and the consuming application code. + *

*

- * The input stream tries to receive a packet at a time. + * For thread synchronization (between the background thread handling IO completion + * and the consuming application thread) a blocking queue is used. When an transfer IN + * requests completes, the background thread adds it to the queue. The consuming code + * waits for the next item in the queue. *

*/ -public class EndpointInputStream extends InputStream { +public abstract class EndpointInputStream extends InputStream { + + private static final int MAX_OUTSTANDING_REQUESTS = 8; + + protected USBDeviceImpl device; + protected final int endpointNumber; + // Arena to allocate buffers and completion handlers + protected final Arena arena; + // Size of buffers (multiple of packet size) + protected final int bufferSize; + // Queue of completed requests + private final ArrayBlockingQueue completedRequestQueue; + // Number of outstanding requests (includes requests pending with the + // operating system and requests in the completed queue) + private int numOutstandingRequests; + // Request and buffer being currently read from + private TransferRequest currentRequest; + // Read offset within current request + private int readOffset; + + /** + * Creates a new instance + * + * @param device USB device + * @param endpointNumber endpoint number + */ + protected EndpointInputStream(USBDeviceImpl device, int endpointNumber) { + this.device = device; + this.endpointNumber = endpointNumber; + + bufferSize = 4 * device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); + completedRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); + + // create all requests and submit all except one + arena = Arena.openShared(); + try { + for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { + final var request = new TransferRequest(); + request.buffer = arena.allocate(bufferSize, 8); + request.completionHandler = (result, size) -> onCompletion(request, result, size); + + if (i == 0) { + currentRequest = request; + } else { + submitRequest(request); + } + } + } catch (Throwable t) { + collectOutstandingRequests(); + throw t; + } + } + + @SuppressWarnings("RedundantThrows") + @Override + public void close() throws IOException { + if (isClosed()) + return; + + // abort all transfers on endpoint + try { + device.abortTransfers(USBDirection.IN, endpointNumber); + } catch (USBException e) { + // If aborting the transfer is not possible, the device has + // likely been closed or unplugged. So all outstanding + // requests will terminate anyway. + } + device = null; + + collectOutstandingRequests(); + } - private USBDevice device_; - private final int endpointNumber_; - private byte[] packet_; - private int readOffset_; + private void collectOutstandingRequests() { + // wait until completion handlers have been called + while (numOutstandingRequests > 0) + waitForRequestCompletion(); - EndpointInputStream(USBDevice device, int endpointNumber) { - device_ = device; - endpointNumber_ = endpointNumber; + completedRequestQueue.clear(); + currentRequest = null; + arena.close(); } @Override public int read() throws IOException { - if (device_ == null) - throw new IOException("Bulk endpoint input stream has been closed"); + if (isClosed()) + return -1; if (available() == 0) receiveMoreData(); - int b = packet_[readOffset_] & 0xff; - readOffset_ += 1; + int b = currentRequest.buffer.get(JAVA_BYTE, readOffset) & 0xff; + readOffset += 1; return b; } @Override public int read(byte[] b, int off, int len) throws IOException { - if (device_ == null) - throw new IOException("Bulk endpoint input stream has been closed"); + if (isClosed()) + return -1; if (available() == 0) receiveMoreData(); - int n = Math.min(len, packet_.length - readOffset_); - System.arraycopy(packet_, readOffset_, b, off, n); - readOffset_ += n; + // copy data to receiving buffer + int n = Math.min(len, currentRequest.resultSize - readOffset); + MemorySegment.copy(currentRequest.buffer, readOffset, MemorySegment.ofArray(b), off, n); + readOffset += n; + + // TODO: poll for further completed requests if 'n' is less than 'len' return n; } @@ -61,24 +149,66 @@ public int read(byte[] b, int off, int len) throws IOException { @SuppressWarnings("RedundantThrows") @Override public int available() throws IOException { - return (packet_ != null ? packet_.length : 0) - readOffset_; + return currentRequest.resultSize - readOffset; + } + + private boolean isClosed() { + return device == null; } private void receiveMoreData() throws IOException { - if (device_ == null) - throw new IOException("Bulk endpoint input stream has been closed"); - - readOffset_ = 0; - // skip zero-length packets - do { - packet_ = device_.transferIn(endpointNumber_); - } while (packet_.length == 0); + try { + // loop until non-ZLP has been received + do { + submitRequest(currentRequest); + + currentRequest = waitForRequestCompletion(); + readOffset = 0; + + // check for error + if (currentRequest.result != 0) + throwException(currentRequest.result, "error reading from USB endpoint"); + + } while (currentRequest.resultSize == 0); + + } catch (Throwable t) { + close(); + throw t; + } } - @SuppressWarnings("RedundantThrows") - @Override - public void close() throws IOException { - device_ = null; - packet_ = null; + void submitRequest(TransferRequest request) { + submitTransferIn(request.buffer, bufferSize, request.completionHandler); + numOutstandingRequests += 1; + } + + protected abstract void submitTransferIn(MemorySegment buffer, int bufferSize, AsyncIOCompletion completion); + + protected abstract void throwException(int errorCode, String message); + + void onCompletion(TransferRequest request, int result, int size) { + request.result = result; + request.resultSize = size; + completedRequestQueue.add(request); + } + + TransferRequest waitForRequestCompletion() { + while (true) { + try { + TransferRequest request = completedRequestQueue.take(); + numOutstandingRequests -= 1; + return request; + + } catch (InterruptedException e) { + // ignore and retry + } + } + } + + private static class TransferRequest { + MemorySegment buffer; + int result; + int resultSize; + AsyncIOCompletion completionHandler; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java index d5771015..b9005ad2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -1,87 +1,257 @@ // // Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher +// Copyright (c) 2023 Manuel Bleichenbacher // Licensed under MIT License // https://opensource.org/licenses/MIT // package net.codecrete.usb.common; -import net.codecrete.usb.USBDevice; +import net.codecrete.usb.USBDirection; import java.io.IOException; import java.io.OutputStream; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; import java.util.Arrays; +import java.util.concurrent.ArrayBlockingQueue; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; /** - * Output stream transmitting data to a USB bulk endpoint. + * Output stream for bulk endpoints – optimized for high throughput. + * + *

+ * Multiple asynchronous transfer OUT requests are submitted to achieve a good + * degree of concurrency between the USB communication handled by the operating + * system and the producing application code. The number of requests is limited + * in order to retain the flow control and keep memory usage at a reasonable size. + *

*

- * The output stream uses a buffer that fits a single data packet. + * For thread synchronization (between the background thread handling IO completion + * and the producing application thread) a blocking queue is used. It is prefilled with + * requests ready to be used for a transfer. The background thread adds the completed + * requests back to this queue. The producing application thread waits until a request + * is available for use. *

*/ -public class EndpointOutputStream extends OutputStream { +public abstract class EndpointOutputStream extends OutputStream { + + private static final int MAX_OUTSTANDING_REQUESTS = 4; + + protected USBDeviceImpl device; + protected final int endpointNumber; + protected final Arena arena; + // Endpoint's packet size + private final int packetSize; + // Size of buffers (multiple of packet size) + private final int bufferSize; + // Blocking queue of available requests (to limit the number of submitted requests) + private final ArrayBlockingQueue availableRequestQueue; + private boolean needsZlp; + private TransferRequest currentRequest; + private int writeOffset; + private int numOutstandingRequests; + private boolean hasError; + - private USBDevice device_; - private final int endpointNumber_; - private byte[] buffer_; - private int bufferedBytes_; + /** + * Creates a new instance + * + * @param device USB device + * @param endpointNumber endpoint number + */ + protected EndpointOutputStream(USBDeviceImpl device, int endpointNumber) { + this.device = device; + this.endpointNumber = endpointNumber; - EndpointOutputStream(USBDevice device, int endpointNumber, int packetSize) { - device_ = device; - endpointNumber_ = endpointNumber; - buffer_ = new byte[packetSize]; + packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize(); + bufferSize = packetSize; + + availableRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); + arena = Arena.openShared(); + + // prefill request queue + for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { + final var request = new TransferRequest(); + request.buffer = arena.allocate(bufferSize, 8); + request.completionHandler = (result, size) -> onCompletion(request, result); + + if (i == 0) { + currentRequest = request; + } else { + availableRequestQueue.add(request); + } + } + } + + @Override + public void close() throws IOException { + if (isClosed()) + return; + + if (!hasError) + flush(); + else + waitForOutstandingRequests(); + + device = null; + availableRequestQueue.clear(); + currentRequest = null; + arena.close(); } @Override public void write(int b) throws IOException { - if (device_ == null) + if (isClosed()) throw new IOException("Bulk endpoint output stream has been closed"); - buffer_[bufferedBytes_] = (byte)b; - bufferedBytes_ += 1; - if (bufferedBytes_ == buffer_.length) - flush(); + currentRequest.buffer.set(JAVA_BYTE, writeOffset, (byte) b); + writeOffset += 1; + if (writeOffset == bufferSize) + submitTransfer(writeOffset); } @Override public void write(byte[] b, int off, int len) throws IOException { - if (device_ == null) + if (isClosed()) throw new IOException("Bulk endpoint output stream has been closed"); while (len > 0) { - int chunkSize = Math.min(len, buffer_.length - bufferedBytes_); - System.arraycopy(b, off, buffer_, bufferedBytes_, chunkSize); - bufferedBytes_ += chunkSize; + int chunkSize = Math.min(len, bufferSize - writeOffset); + MemorySegment.copy(b, off, currentRequest.buffer, JAVA_BYTE, writeOffset, chunkSize); + writeOffset += chunkSize; off += chunkSize; len -= chunkSize; - if (bufferedBytes_ == buffer_.length) - flush(); + if (writeOffset == bufferSize) + submitTransfer(writeOffset); } } @Override public void flush() throws IOException { - if (device_ == null) + if (isClosed()) throw new IOException("Bulk endpoint output stream has been closed"); - if (bufferedBytes_ == 0) + if (writeOffset > 0) + submitTransfer(writeOffset); + + if (needsZlp) + submitTransfer(0); + + waitForOutstandingRequests(); + } + + private boolean isClosed() { + return device == null; + } + + /** + * Submits a request for transfer and set a new request + * as the current one, possibly waiting until it is ready. + *

+ * Throws an exception if the request to be reused has completed with an error on the + * previous operation. The exception is suppressed if {@code hasError} flag is set. + *

+ * + * @param size size of data to be transmitted + */ + private void submitTransfer(int size) throws IOException { + try { + submitTransferOut(currentRequest.buffer, size, currentRequest.completionHandler); + + synchronized (this) { + numOutstandingRequests += 1; + } + + needsZlp = size == packetSize; + writeOffset = 0; + currentRequest = waitForAvailableRequest(); + + } catch (Throwable t) { + hasError = true; + close(); + throw t; + } + } + + /** + * Wait until all outstanding requests have been completed. + *

+ * Throws an exception if any of the requests has completed with an error. + * The exception is suppressed if {@code hasError} flag is set. + *

+ */ + private void waitForOutstandingRequests() { + // Wait until all buffers have been transmitted by removing them from the + // queue and reinserting them. + + int numRequests; + synchronized (this) { + numRequests = numOutstandingRequests + availableRequestQueue.size(); + } + + if (numRequests == 0) return; - byte[] data; - if (bufferedBytes_ < buffer_.length) { - data = Arrays.copyOfRange(buffer_, 0, bufferedBytes_); - } else { - data = buffer_; + var requests = new TransferRequest[numRequests]; + for (int i = 0; i < numRequests; i++) + requests[i] = waitForAvailableRequest(); + + // reinsert the requests + if (!hasError) + availableRequestQueue.addAll(Arrays.asList(requests)); + } + + /** + * Wait until one of the allocated requests is available for use. + *

+ * Throws an exception if the request to be reused has completed with an error on the + * previous operation. The exception is suppressed if {@code hasError} flag is set. + *

+ * + * @return request ready for use + */ + private TransferRequest waitForAvailableRequest() { + while (true) { + try { + TransferRequest request = availableRequestQueue.take(); + + // check for error + int result = request.result; + if (result != 0 && !hasError) { + request.result = 0; + throwException(result, "error reading from USB endpoint"); + } + + return request; + + } catch (InterruptedException e) { + // ignore and retry + } } - device_.transferOut(endpointNumber_, data); - bufferedBytes_ = 0; } - @Override - public void close() throws IOException { - flush(); - buffer_ = null; - device_ = null; + /** + * Called by the asynchronous IO completion handler. + * + * @param request the completed request + * @param result the request result code + */ + private synchronized void onCompletion(TransferRequest request, int result) { + request.result = result; + availableRequestQueue.add(request); + numOutstandingRequests -= 1; + } + + protected abstract void submitTransferOut(MemorySegment data, int dataSize, AsyncIOCompletion completion); + + protected abstract void throwException(int errorCode, String message); + + private static class TransferRequest { + MemorySegment buffer; + int result; + AsyncIOCompletion completionHandler; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 09b6e651..327154dc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -303,21 +303,6 @@ public byte[] transferIn(int endpointNumber) { @Override public abstract byte[] transferIn(int endpointNumber, int timeout); - @Override - public OutputStream openOutputStream(int endpointNumber) { - // check that endpoint number is valid - var endpointInfo = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, null); - var endpoint = getInterface(endpointInfo.interfaceNumber).alternate().getEndpoint(endpointNumber, USBDirection.OUT); - return new EndpointOutputStream(this, endpointNumber, endpoint.packetSize()); - } - - @Override - public InputStream openInputStream(int endpointNumber) { - // check that endpoint number is valid - getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, null); - return new EndpointInputStream(this, endpointNumber); - } - @Override public boolean equals(Object o) { if (this == o) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java index 813f7b52..2d6c88ee 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java @@ -30,10 +30,16 @@ public class IO { private static final MethodHandle ioctl$MH = linker.downcallHandle(linker.defaultLookup().find("ioctl").get(), ioctl$FUNC, ERRNO_STATE); private static final FunctionDescriptor open$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT); private static final MethodHandle open$MH = linker.downcallHandle(linker.defaultLookup().find("open").get(), open$FUNC, ERRNO_STATE); + private static final FunctionDescriptor eventfd$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_INT); + private static final MethodHandle eventfd$MH = linker.downcallHandle(linker.defaultLookup().find("eventfd").get(), eventfd$FUNC, ERRNO_STATE); + private static final FunctionDescriptor eventfd_read$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS); + private static final MethodHandle eventfd_read$MH = linker.downcallHandle(linker.defaultLookup().find("eventfd_read").get(), eventfd_read$FUNC, ERRNO_STATE); + private static final FunctionDescriptor eventfd_write$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_LONG); + private static final MethodHandle eventfd_write$MH = linker.downcallHandle(linker.defaultLookup().find("eventfd_write").get(), eventfd_write$FUNC, ERRNO_STATE); public static int ioctl(int fd, long request, MemorySegment segment, MemorySegment errno) { try { - return (int)ioctl$MH.invokeExact(errno, fd, request, segment); + return (int) ioctl$MH.invokeExact(errno, fd, request, segment); } catch (Throwable ex) { throw new RuntimeException(ex); } @@ -41,7 +47,31 @@ public static int ioctl(int fd, long request, MemorySegment segment, MemorySegme public static int open(MemorySegment file, int oflag, MemorySegment errno) { try { - return (int)open$MH.invokeExact(errno, file, oflag); + return (int) open$MH.invokeExact(errno, file, oflag); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + public static int eventfd(int count, int flags, MemorySegment errno) { + try { + return (int) eventfd$MH.invokeExact(errno, count, flags); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + public static int eventfd_read(int fd, MemorySegment value, MemorySegment errno) { + try { + return (int) eventfd_read$MH.invokeExact(errno, fd, value); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + public static int eventfd_write(int fd, long value, MemorySegment errno) { + try { + return (int) eventfd_write$MH.invokeExact(errno, fd, value); } catch (Throwable ex) { throw new RuntimeException(ex); } @@ -52,6 +82,7 @@ public static int open(MemorySegment file, int oflag, MemorySegment errno) { *

* The memory segment is assumed to have the layout {@link #ERRNO_STATE}. *

+ * * @param errno memory segment with error code * @return error code */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java new file mode 100644 index 00000000..bba60a41 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java @@ -0,0 +1,30 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.linux; + +import net.codecrete.usb.common.AsyncIOCompletion; +import net.codecrete.usb.common.EndpointInputStream; + +import java.lang.foreign.MemorySegment; + +public class LinuxEndpointInputStream extends EndpointInputStream { + + LinuxEndpointInputStream(LinuxUSBDevice device, int endpointNumber) { + super(device, endpointNumber); + } + + @Override + protected void submitTransferIn(MemorySegment buffer, int bufferSize, AsyncIOCompletion completion) { + ((LinuxUSBDevice) device).submitTransferIn(endpointNumber, buffer, bufferSize, completion); + } + + @Override + protected void throwException(int errorCode, String message) { + LinuxUSBException.throwException(errorCode, message); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java new file mode 100644 index 00000000..90b16992 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java @@ -0,0 +1,30 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.linux; + +import net.codecrete.usb.common.AsyncIOCompletion; +import net.codecrete.usb.common.EndpointOutputStream; + +import java.lang.foreign.MemorySegment; + +public class LinuxEndpointOutputStream extends EndpointOutputStream { + + LinuxEndpointOutputStream(LinuxUSBDevice device, int endpointNumber) { + super(device, endpointNumber); + } + + @Override + protected void submitTransferOut(MemorySegment data, int dataSize, AsyncIOCompletion completion) { + ((LinuxUSBDevice) device).submitTransferOut(endpointNumber, data, dataSize, completion); + } + + @Override + protected void throwException(int errorCode, String message) { + LinuxUSBException.throwException(errorCode, message); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 071929f6..a669610d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -8,6 +8,7 @@ package net.codecrete.usb.linux; import net.codecrete.usb.*; +import net.codecrete.usb.common.AsyncIOCompletion; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.common.USBInterfaceImpl; import net.codecrete.usb.linux.gen.errno.errno; @@ -19,6 +20,8 @@ import net.codecrete.usb.usbstandard.DeviceDescriptor; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.nio.file.Files; @@ -33,8 +36,11 @@ public class LinuxUSBDevice extends USBDeviceImpl { private int fd = -1; - LinuxUSBDevice(Object id, int vendorId, int productId) { + private final LinuxUSBDeviceRegistry registry; + + LinuxUSBDevice(LinuxUSBDeviceRegistry registry, Object id, int vendorId, int productId) { super(id, vendorId, productId); + this.registry = registry; loadDescription((String) id); } @@ -69,6 +75,7 @@ public void open() { fd = IO.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC(), errnoState); if (fd == -1) throwLastError(errnoState, "Cannot open USB device"); + registry.registerCompletionHandling(this); } } @@ -77,6 +84,8 @@ public void close() { if (!isOpen()) return; + registry.unregisterCompletionHandling(this); + for (var intf : interfaces_) ((USBInterfaceImpl) intf).setClaimed(false); @@ -84,6 +93,10 @@ public void close() { fd = -1; } + int fileDescriptor() { + return fd; + } + public void claimInterface(int interfaceNumber) { checkIsOpen(); @@ -264,6 +277,35 @@ public void clearHalt(USBDirection direction, int endpointNumber) { @Override public synchronized void abortTransfers(USBDirection direction, int endpointNumber) { - throw new UnsupportedOperationException("not implemented yet"); + var endpoint = getEndpoint(direction, endpointNumber, + USBTransferType.BULK, USBTransferType.INTERRUPT); + + registry.abortTransfers(this, endpoint.endpointAddress()); + } + + @Override + public InputStream openInputStream(int endpointNumber) { + // check that endpoint number is valid + getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, null); + + return new LinuxEndpointInputStream(this, endpointNumber); + } + + @Override + public OutputStream openOutputStream(int endpointNumber) { + // check that endpoint number is valid + getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, null); + + return new LinuxEndpointOutputStream(this, endpointNumber); + } + + synchronized void submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, AsyncIOCompletion completion) { + var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); + registry.submitBulkTransfer(this, endpoint.endpointAddress(), buffer, bufferSize, completion); + } + + synchronized void submitTransferOut(int endpointNumber, MemorySegment data, int dataSize, AsyncIOCompletion completion) { + var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); + registry.submitBulkTransfer(this, endpoint.endpointAddress(), data, dataSize, completion); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 3063e054..73382006 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -8,20 +8,30 @@ package net.codecrete.usb.linux; import net.codecrete.usb.USBDevice; +import net.codecrete.usb.common.AsyncIOCompletion; import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.common.USBDeviceRegistry; +import net.codecrete.usb.linux.gen.errno.errno; import net.codecrete.usb.linux.gen.poll.poll; import net.codecrete.usb.linux.gen.poll.pollfd; import net.codecrete.usb.linux.gen.udev.udev; +import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_urb; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; import java.lang.foreign.SegmentScope; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_LONG; import static net.codecrete.usb.linux.LinuxUSBException.throwException; +import static net.codecrete.usb.linux.LinuxUSBException.throwLastError; +import static net.codecrete.usb.linux.USBDevFS.*; +import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.USBDEVFS_URB_TYPE_BULK; /** * Linux implementation of USB device registry. @@ -39,6 +49,15 @@ public class LinuxUSBDeviceRegistry extends USBDeviceRegistry { private final MemorySegment ATTR_PRODUCT = GLOBAL_ALLOCATOR.allocateUtf8String("product"); private final MemorySegment ATTR_SERIAL = GLOBAL_ALLOCATOR.allocateUtf8String("serial"); + /// available URBs + private final List availableURBs = new ArrayList<>(); + /// map of URB address to completion handler (for outstanding requests) + private final Map completionHandlerByURB = new HashMap<>(); + /// array of file descriptors using asynchronous completion + private int[] asyncFds; + /// file descriptor to notify async IO background thread about an update + private int asyncIOUpdateEventFd; + @Override protected void monitorDevices() { @@ -197,7 +216,7 @@ private USBDevice getDeviceDetails(MemorySegment udevDevice) { productId = Integer.parseInt(idProduct, 16); // create device instance - var device = new LinuxUSBDevice(devPath, vendorId, productId); + var device = new LinuxUSBDevice(this, devPath, vendorId, productId); device.setProductStrings(getDeviceAttribute(udevDevice, ATTR_MANUFACTURER), getDeviceAttribute(udevDevice, ATTR_PRODUCT), getDeviceAttribute(udevDevice, ATTR_SERIAL)); @@ -231,7 +250,7 @@ private static String getDeviceAction(MemorySegment udevDevice) { /** * Waits until the specified file descriptor becomes ready for reading. * - * @param fd the file descriptor + * @param fd the file descriptor * @param arena an arena for allocating memory */ private static void waitForFileDescriptor(int fd, Arena arena) { @@ -242,4 +261,223 @@ private static void waitForFileDescriptor(int fd, Arena arena) { if (res < 0) throwException("internal error (poll)"); } + + /** + * Background task for handling asynchronous IO completions. + */ + private void asyncCompletionTask() { + + try (var arena = Arena.openConfined()) { + var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + var asyncPolls = pollfd.allocateArray(100, arena); + var urbPointerHolder = arena.allocate(ADDRESS); + var eventfdValueHolder = arena.allocate(JAVA_LONG); + + while (true) { + + // get current file descriptor array + int[] fds; + synchronized (this) { + fds = asyncFds; + } + + // prepare pollfd struct array + var n = fds.length; + for (int i = 0; i < n; i++) { + pollfd.fd$set(asyncPolls, i, fds[i]); + pollfd.events$set(asyncPolls, i, (short) (poll.POLLIN() | poll.POLLOUT())); + pollfd.revents$set(asyncPolls, i, (short) 0); + } + + pollfd.fd$set(asyncPolls, n, asyncIOUpdateEventFd); + pollfd.events$set(asyncPolls, n, (short) poll.POLLIN()); + pollfd.revents$set(asyncPolls, n, (short) 0); + + // poll for event + int res = poll.poll(asyncPolls, n + 1, -1); + if (res < 0) + throwException("internal error (poll)"); + + // check for events + for (int i = 0; i < n + 1; i++) { + var revent = pollfd.revents$get(asyncPolls, i); + if (revent == 0) + continue; + + if ((revent & poll.POLLERR()) != 0) { + // TODO + System.err.println("Error in asynchronous request"); + continue; + } + + if (i != n) { + // reap URB + int fd = pollfd.fd$get(asyncPolls, i); + reapURB(fd, urbPointerHolder, errnoState); + + } else { + res = IO.eventfd_read(asyncIOUpdateEventFd, eventfdValueHolder, errnoState); + if (res < 0) + throwLastError(errnoState, "internal error (eventfd_read)"); + } + } + + } + } + } + + private void reapURB(int fd, MemorySegment urbPointerHolder, MemorySegment errnoState) { + int res; + res = IO.ioctl(fd, REAPURB, urbPointerHolder, errnoState); + if (res < 0) { + var err = IO.getErrno(errnoState); + if (err == errno.EBADF()) + return; // ignore, device might have been closed + throwException(err, "internal error (reap URB)"); + } + + var addr = urbPointerHolder.get(ADDRESS, 0); + var urb = usbdevfs_urb.ofAddress(addr, SegmentScope.global()); + int status = usbdevfs_urb.status$get(urb); + int length = usbdevfs_urb.actual_length$get(urb); + + // call completion handler + synchronized (this) { + var completionHandler = completionHandlerByURB.get(urb.address()); + completionHandler.completed(status, length); + recycleURB(urb); + } + } + + /** + * Notifies background process about changed FD list + */ + private void notifyAsyncIOTask() { + // start background process if needed + if (asyncIOUpdateEventFd == 0) { + startAsyncIOHandler(); + return; + } + + try (var arena = Arena.openConfined()) { + var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + if (IO.eventfd_write(asyncIOUpdateEventFd, 1, errnoState) < 0) + throwLastError(errnoState, "internal error (eventfd_write)"); + } + } + + /** + * Register a device for asynchronous IO completion handling + * + * @param device USB device + */ + synchronized void registerCompletionHandling(LinuxUSBDevice device) { + int n = asyncFds != null ? asyncFds.length : 0; + int[] fds = new int[n + 1]; + if (n > 0) + System.arraycopy(asyncFds, 0, fds, 0, n); + fds[n] = device.fileDescriptor(); + + // activate new array + asyncFds = fds; + notifyAsyncIOTask(); + } + + /** + * Unregisters a device from asynchronous IO completion handling. + * + * @param device USB device + */ + synchronized void unregisterCompletionHandling(LinuxUSBDevice device) { + // copy file descriptor (except the device's) into new array + int n = asyncFds.length; + if (n == 0) + return; + + int fd = device.fileDescriptor(); + int[] fds = new int[n - 1]; + int tgt = 0; + for (int asyncFd : asyncFds) { + if (asyncFd != fd) { + if (tgt == n) + return; + fds[tgt] = asyncFd; + tgt += 1; + } + } + + + // activate new array + asyncFds = fds; + notifyAsyncIOTask(); + } + + synchronized void submitBulkTransfer(LinuxUSBDevice device, int endpointAddress, MemorySegment buffer, int bufferLength, AsyncIOCompletion completion) { + var urb = getURB(completion); + + usbdevfs_urb.type$set(urb, (byte) USBDEVFS_URB_TYPE_BULK()); + usbdevfs_urb.endpoint$set(urb, (byte) endpointAddress); + usbdevfs_urb.buffer$set(urb, buffer); + usbdevfs_urb.buffer_length$set(urb, bufferLength); + usbdevfs_urb.usercontext$set(urb, MemorySegment.ofAddress(device.fileDescriptor())); + + try (var arena = Arena.openConfined()) { + var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + if (IO.ioctl(device.fileDescriptor(), SUBMITURB, urb, errnoState) < 0) + throwLastError(errnoState, "failed to submit bulk transfer request"); + } + } + + private MemorySegment getURB(AsyncIOCompletion completionHandler) { + MemorySegment urb; + int size = availableURBs.size(); + if (size > 0) { + urb = availableURBs.remove(size - 1); + } else { + urb = usbdevfs_urb.allocate(GLOBAL_ALLOCATOR); + } + + completionHandlerByURB.put(urb.address(), completionHandler); + + return urb; + } + + synchronized void recycleURB(MemorySegment urb) { + completionHandlerByURB.remove(urb.address()); + availableURBs.add(urb); + } + + synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { + int fd = device.fileDescriptor(); + try (var arena = Arena.openConfined()) { + var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + + for (var urbAddress : completionHandlerByURB.keySet()) { + var urb = usbdevfs_urb.ofAddress(MemorySegment.ofAddress(urbAddress), SegmentScope.global()); + if (fd != (int) usbdevfs_urb.usercontext$get(urb).address()) + continue; + if (endpointAddress != usbdevfs_urb.endpoint$get(urb)) + continue; + + if (IO.ioctl(fd, DISCARDURB, urb, errnoState) < 0) + throwLastError(errnoState, "failed to cancel transfer request"); + } + } + } + + private void startAsyncIOHandler() { + try (var arena = Arena.openConfined()) { + var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + asyncIOUpdateEventFd = IO.eventfd(0, 0, errnoState); + if (asyncIOUpdateEventFd == -1) { + asyncIOUpdateEventFd = 0; + throwLastError(errnoState, "internal error (eventfd)"); + } + } + + // start background thread for handling IO completion + Thread t = new Thread(this::asyncCompletionTask, "USB async IO"); + t.setDaemon(true); + t.start(); + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java index 88eff822..653fc204 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java @@ -22,7 +22,8 @@ public class LinuxUSBException extends USBException { *

* The message for the Linux error code is looked up and appended to the message. *

- * @param message exception message + * + * @param message exception message * @param errorCode Linux error code (returned by {@code errno}) */ public LinuxUSBException(String message, int errorCode) { @@ -34,9 +35,10 @@ public LinuxUSBException(String message, int errorCode) { *

* The message for the Linux error code is looked up and appended to the message. *

+ * * @param errorCode Linux error code (returned by {@code errno}) - * @param message exception message format ({@link String#format(String, Object...)} style) - * @param args arguments for exception message + * @param message exception message format ({@link String#format(String, Object...)} style) + * @param args arguments for exception message */ static void throwException(int errorCode, String message, Object... args) { var formattedMessage = String.format(message, args); @@ -49,8 +51,9 @@ static void throwException(int errorCode, String message, Object... args) { /** * Throws a USB exception. + * * @param message exception message format ({@link String#format(String, Object...)} style) - * @param args arguments for exception message + * @param args arguments for exception message */ static void throwException(String message, Object... args) { throw new USBException(String.format(message, args)); @@ -62,9 +65,10 @@ static void throwException(String message, Object... args) { * The message of the last Linux error code is provided in a memory segment with the layout * {@link IO#ERRNO_STATE}. *

- * @param errno segment with lat error code + * + * @param errno segment with lat error code * @param message exception message format ({@link String#format(String, Object...)} style) - * @param args arguments for exception message + * @param args arguments for exception message */ static void throwLastError(MemorySegment errno, String message, Object... args) { throwException(IO.getErrno(errno), message, args); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java index 2e579017..27b68e1c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java @@ -18,4 +18,9 @@ public class USBDevFS { public static final long RELEASEINTERFACE = 0x80045510L; public static final long SETINTERFACE = 0x80085504L; public static final long CLEAR_HALT = 0x80045515L; + public static final long SUBMITURB = 0x8038550AL; + public static final long DISCARDURB = 0x550BL; + public static final long REAPURB = 0x4008550CL; + public static final long RESETEP = 0x80045503L; + } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java index a8cd6a61..40fbb4cf 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -13,6 +13,14 @@ public class errno { public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + /** + * {@snippet : + * #define EBADF 9 + * } + */ + public static int EBADF() { + return (int)9L; + } /** * {@snippet : * #define EPIPE 32 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java index 8fd51513..3b99e1a0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java @@ -24,6 +24,22 @@ public class poll { public static int POLLIN() { return (int)1L; } + /** + * {@snippet : + * #define POLLOUT 4 + * } + */ + public static int POLLOUT() { + return (int)4L; + } + /** + * {@snippet : + * #define POLLERR 8 + * } + */ + public static int POLLERR() { + return (int)8L; + } public static MethodHandle poll$MH() { return RuntimeHelper.requireNonNull(constants$0.poll$MH,"poll"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java new file mode 100644 index 00000000..9fd69b70 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java @@ -0,0 +1,430 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct usbdevfs_urb { + * unsigned char type; + * unsigned char endpoint; + * int status; + * unsigned int flags; + * void* buffer; + * int buffer_length; + * int actual_length; + * int start_frame; + * union { + * int number_of_packets; + * unsigned int stream_id; + * }; + * int error_count; + * unsigned int signr; + * void* usercontext; + * struct usbdevfs_iso_packet_desc iso_frame_desc[0]; + * }; + * } + */ +public class usbdevfs_urb { + + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_CHAR$LAYOUT.withName("type"), + Constants$root.C_CHAR$LAYOUT.withName("endpoint"), + MemoryLayout.paddingLayout(16), + Constants$root.C_INT$LAYOUT.withName("status"), + Constants$root.C_INT$LAYOUT.withName("flags"), + MemoryLayout.paddingLayout(32), + Constants$root.C_POINTER$LAYOUT.withName("buffer"), + Constants$root.C_INT$LAYOUT.withName("buffer_length"), + Constants$root.C_INT$LAYOUT.withName("actual_length"), + Constants$root.C_INT$LAYOUT.withName("start_frame"), + MemoryLayout.unionLayout( + Constants$root.C_INT$LAYOUT.withName("number_of_packets"), + Constants$root.C_INT$LAYOUT.withName("stream_id") + ).withName("$anon$0"), + Constants$root.C_INT$LAYOUT.withName("error_count"), + Constants$root.C_INT$LAYOUT.withName("signr"), + Constants$root.C_POINTER$LAYOUT.withName("usercontext"), + MemoryLayout.sequenceLayout(0, MemoryLayout.structLayout( + Constants$root.C_INT$LAYOUT.withName("length"), + Constants$root.C_INT$LAYOUT.withName("actual_length"), + Constants$root.C_INT$LAYOUT.withName("status") + ).withName("usbdevfs_iso_packet_desc")).withName("iso_frame_desc") + ).withName("usbdevfs_urb"); + public static MemoryLayout $LAYOUT() { + return usbdevfs_urb.$struct$LAYOUT; + } + static final VarHandle type$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("type")); + public static VarHandle type$VH() { + return usbdevfs_urb.type$VH; + } + /** + * Getter for field: + * {@snippet : + * unsigned char type; + * } + */ + public static byte type$get(MemorySegment seg) { + return (byte)usbdevfs_urb.type$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * unsigned char type; + * } + */ + public static void type$set(MemorySegment seg, byte x) { + usbdevfs_urb.type$VH.set(seg, x); + } + public static byte type$get(MemorySegment seg, long index) { + return (byte)usbdevfs_urb.type$VH.get(seg.asSlice(index*sizeof())); + } + public static void type$set(MemorySegment seg, long index, byte x) { + usbdevfs_urb.type$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle endpoint$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("endpoint")); + public static VarHandle endpoint$VH() { + return usbdevfs_urb.endpoint$VH; + } + /** + * Getter for field: + * {@snippet : + * unsigned char endpoint; + * } + */ + public static byte endpoint$get(MemorySegment seg) { + return (byte)usbdevfs_urb.endpoint$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * unsigned char endpoint; + * } + */ + public static void endpoint$set(MemorySegment seg, byte x) { + usbdevfs_urb.endpoint$VH.set(seg, x); + } + public static byte endpoint$get(MemorySegment seg, long index) { + return (byte)usbdevfs_urb.endpoint$VH.get(seg.asSlice(index*sizeof())); + } + public static void endpoint$set(MemorySegment seg, long index, byte x) { + usbdevfs_urb.endpoint$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle status$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("status")); + public static VarHandle status$VH() { + return usbdevfs_urb.status$VH; + } + /** + * Getter for field: + * {@snippet : + * int status; + * } + */ + public static int status$get(MemorySegment seg) { + return (int)usbdevfs_urb.status$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * int status; + * } + */ + public static void status$set(MemorySegment seg, int x) { + usbdevfs_urb.status$VH.set(seg, x); + } + public static int status$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.status$VH.get(seg.asSlice(index*sizeof())); + } + public static void status$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.status$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle flags$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("flags")); + public static VarHandle flags$VH() { + return usbdevfs_urb.flags$VH; + } + /** + * Getter for field: + * {@snippet : + * unsigned int flags; + * } + */ + public static int flags$get(MemorySegment seg) { + return (int)usbdevfs_urb.flags$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * unsigned int flags; + * } + */ + public static void flags$set(MemorySegment seg, int x) { + usbdevfs_urb.flags$VH.set(seg, x); + } + public static int flags$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.flags$VH.get(seg.asSlice(index*sizeof())); + } + public static void flags$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.flags$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle buffer$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("buffer")); + public static VarHandle buffer$VH() { + return usbdevfs_urb.buffer$VH; + } + /** + * Getter for field: + * {@snippet : + * void* buffer; + * } + */ + public static MemorySegment buffer$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)usbdevfs_urb.buffer$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * void* buffer; + * } + */ + public static void buffer$set(MemorySegment seg, MemorySegment x) { + usbdevfs_urb.buffer$VH.set(seg, x); + } + public static MemorySegment buffer$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)usbdevfs_urb.buffer$VH.get(seg.asSlice(index*sizeof())); + } + public static void buffer$set(MemorySegment seg, long index, MemorySegment x) { + usbdevfs_urb.buffer$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle buffer_length$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("buffer_length")); + public static VarHandle buffer_length$VH() { + return usbdevfs_urb.buffer_length$VH; + } + /** + * Getter for field: + * {@snippet : + * int buffer_length; + * } + */ + public static int buffer_length$get(MemorySegment seg) { + return (int)usbdevfs_urb.buffer_length$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * int buffer_length; + * } + */ + public static void buffer_length$set(MemorySegment seg, int x) { + usbdevfs_urb.buffer_length$VH.set(seg, x); + } + public static int buffer_length$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.buffer_length$VH.get(seg.asSlice(index*sizeof())); + } + public static void buffer_length$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.buffer_length$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle actual_length$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("actual_length")); + public static VarHandle actual_length$VH() { + return usbdevfs_urb.actual_length$VH; + } + /** + * Getter for field: + * {@snippet : + * int actual_length; + * } + */ + public static int actual_length$get(MemorySegment seg) { + return (int)usbdevfs_urb.actual_length$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * int actual_length; + * } + */ + public static void actual_length$set(MemorySegment seg, int x) { + usbdevfs_urb.actual_length$VH.set(seg, x); + } + public static int actual_length$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.actual_length$VH.get(seg.asSlice(index*sizeof())); + } + public static void actual_length$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.actual_length$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle start_frame$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("start_frame")); + public static VarHandle start_frame$VH() { + return usbdevfs_urb.start_frame$VH; + } + /** + * Getter for field: + * {@snippet : + * int start_frame; + * } + */ + public static int start_frame$get(MemorySegment seg) { + return (int)usbdevfs_urb.start_frame$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * int start_frame; + * } + */ + public static void start_frame$set(MemorySegment seg, int x) { + usbdevfs_urb.start_frame$VH.set(seg, x); + } + public static int start_frame$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.start_frame$VH.get(seg.asSlice(index*sizeof())); + } + public static void start_frame$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.start_frame$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle number_of_packets$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("number_of_packets")); + public static VarHandle number_of_packets$VH() { + return usbdevfs_urb.number_of_packets$VH; + } + /** + * Getter for field: + * {@snippet : + * int number_of_packets; + * } + */ + public static int number_of_packets$get(MemorySegment seg) { + return (int)usbdevfs_urb.number_of_packets$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * int number_of_packets; + * } + */ + public static void number_of_packets$set(MemorySegment seg, int x) { + usbdevfs_urb.number_of_packets$VH.set(seg, x); + } + public static int number_of_packets$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.number_of_packets$VH.get(seg.asSlice(index*sizeof())); + } + public static void number_of_packets$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.number_of_packets$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle stream_id$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("stream_id")); + public static VarHandle stream_id$VH() { + return usbdevfs_urb.stream_id$VH; + } + /** + * Getter for field: + * {@snippet : + * unsigned int stream_id; + * } + */ + public static int stream_id$get(MemorySegment seg) { + return (int)usbdevfs_urb.stream_id$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * unsigned int stream_id; + * } + */ + public static void stream_id$set(MemorySegment seg, int x) { + usbdevfs_urb.stream_id$VH.set(seg, x); + } + public static int stream_id$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.stream_id$VH.get(seg.asSlice(index*sizeof())); + } + public static void stream_id$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.stream_id$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle error_count$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("error_count")); + public static VarHandle error_count$VH() { + return usbdevfs_urb.error_count$VH; + } + /** + * Getter for field: + * {@snippet : + * int error_count; + * } + */ + public static int error_count$get(MemorySegment seg) { + return (int)usbdevfs_urb.error_count$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * int error_count; + * } + */ + public static void error_count$set(MemorySegment seg, int x) { + usbdevfs_urb.error_count$VH.set(seg, x); + } + public static int error_count$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.error_count$VH.get(seg.asSlice(index*sizeof())); + } + public static void error_count$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.error_count$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle signr$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("signr")); + public static VarHandle signr$VH() { + return usbdevfs_urb.signr$VH; + } + /** + * Getter for field: + * {@snippet : + * unsigned int signr; + * } + */ + public static int signr$get(MemorySegment seg) { + return (int)usbdevfs_urb.signr$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * unsigned int signr; + * } + */ + public static void signr$set(MemorySegment seg, int x) { + usbdevfs_urb.signr$VH.set(seg, x); + } + public static int signr$get(MemorySegment seg, long index) { + return (int)usbdevfs_urb.signr$VH.get(seg.asSlice(index*sizeof())); + } + public static void signr$set(MemorySegment seg, long index, int x) { + usbdevfs_urb.signr$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle usercontext$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("usercontext")); + public static VarHandle usercontext$VH() { + return usbdevfs_urb.usercontext$VH; + } + /** + * Getter for field: + * {@snippet : + * void* usercontext; + * } + */ + public static MemorySegment usercontext$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)usbdevfs_urb.usercontext$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * void* usercontext; + * } + */ + public static void usercontext$set(MemorySegment seg, MemorySegment x) { + usbdevfs_urb.usercontext$VH.set(seg, x); + } + public static MemorySegment usercontext$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)usbdevfs_urb.usercontext$VH.get(seg.asSlice(index*sizeof())); + } + public static void usercontext$set(MemorySegment seg, long index, MemorySegment x) { + usbdevfs_urb.usercontext$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java index 38e0d938..dcc268ad 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java @@ -13,6 +13,14 @@ public class usbdevice_fs { public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + /** + * {@snippet : + * #define USBDEVFS_URB_TYPE_BULK 3 + * } + */ + public static int USBDEVFS_URB_TYPE_BULK() { + return (int)3L; + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java index 69d45eea..979636ee 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java @@ -7,12 +7,12 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.common.AsyncEndpointInputStream; import net.codecrete.usb.common.AsyncIOCompletion; +import net.codecrete.usb.common.EndpointInputStream; import java.lang.foreign.MemorySegment; -public class MacosEndpointInputStream extends AsyncEndpointInputStream { +public class MacosEndpointInputStream extends EndpointInputStream { MacosEndpointInputStream(MacosUSBDevice device, int endpointNumber) { super(device, endpointNumber); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java index c68719a1..d3c512f0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java @@ -7,12 +7,12 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.common.AsyncEndpointOutputStream; import net.codecrete.usb.common.AsyncIOCompletion; +import net.codecrete.usb.common.EndpointOutputStream; import java.lang.foreign.MemorySegment; -public class MacosEndpointOutputStream extends AsyncEndpointOutputStream { +public class MacosEndpointOutputStream extends EndpointOutputStream { MacosEndpointOutputStream(MacosUSBDevice device, int endpointNumber) { super(device, endpointNumber); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java index 424f64e8..e96d5c95 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java @@ -8,12 +8,12 @@ package net.codecrete.usb.windows; import net.codecrete.usb.USBDirection; -import net.codecrete.usb.common.AsyncEndpointInputStream; import net.codecrete.usb.common.AsyncIOCompletion; +import net.codecrete.usb.common.EndpointInputStream; import java.lang.foreign.MemorySegment; -public class WindowsEndpointInputStream extends AsyncEndpointInputStream { +public class WindowsEndpointInputStream extends EndpointInputStream { WindowsEndpointInputStream(WindowsUSBDevice device, int endpointNumber) { super(device, endpointNumber); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java index b453f936..c2264159 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java @@ -8,12 +8,12 @@ package net.codecrete.usb.windows; import net.codecrete.usb.USBDirection; -import net.codecrete.usb.common.AsyncEndpointOutputStream; import net.codecrete.usb.common.AsyncIOCompletion; +import net.codecrete.usb.common.EndpointOutputStream; import java.lang.foreign.MemorySegment; -public class WindowsEndpointOutputStream extends AsyncEndpointOutputStream { +public class WindowsEndpointOutputStream extends EndpointOutputStream { WindowsEndpointOutputStream(WindowsUSBDevice device, int endpointNumber) { super(device, endpointNumber); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 1c293480..19614441 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -609,5 +609,4 @@ synchronized void removeFromCompletionPort(MemorySegment handle) { completionKeysByHandle.remove(handle); devicesByCompletionKey.remove(completionKey); } - } From ed9d7b88ca6b70611c6fcd5206583f57a56f3764 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 22 Feb 2023 22:49:52 +0100 Subject: [PATCH 204/433] Clean up / reformat --- .../codecrete/usb/USBAlternateInterface.java | 3 +- .../java/net/codecrete/usb/USBDevice.java | 10 +- .../java/net/codecrete/usb/USBInterface.java | 2 +- .../main/java/net/codecrete/usb/Version.java | 4 + .../usb/common/AsyncIOCompletion.java | 2 +- .../usb/common/CompositeFunction.java | 3 +- .../codecrete/usb/common/Configuration.java | 9 +- .../codecrete/usb/common/ForeignMemory.java | 2 +- .../codecrete/usb/common/ScopeCleanup.java | 3 +- .../usb/common/USBAlternateInterfaceImpl.java | 5 +- .../codecrete/usb/common/USBDeviceImpl.java | 40 ++--- .../usb/common/USBDeviceRegistry.java | 3 +- .../main/java/net/codecrete/usb/linux/IO.java | 36 ++--- .../java/net/codecrete/usb/linux/Linux.java | 25 +++ .../codecrete/usb/linux/LinuxUSBDevice.java | 43 +++-- .../usb/linux/LinuxUSBDeviceRegistry.java | 19 +-- .../usb/linux/LinuxUSBException.java | 4 +- .../codecrete/usb/macos/MacosUSBDevice.java | 4 +- .../usbstandard/ConfigurationDescriptor.java | 15 +- .../usb/usbstandard/DeviceDescriptor.java | 23 +-- .../usb/usbstandard/EndpointDescriptor.java | 11 +- .../InterfaceAssociationDescriptor.java | 14 +- .../usb/usbstandard/InterfaceDescriptor.java | 15 +- .../usb/usbstandard/SetupPacket.java | 9 +- .../usb/usbstandard/StringDescriptor.java | 7 +- .../codecrete/usb/windows/DeviceProperty.java | 75 +++++---- .../net/codecrete/usb/windows/USBHelper.java | 18 +-- .../java/net/codecrete/usb/windows/Win.java | 10 +- .../windows/WindowsEndpointInputStream.java | 2 +- .../windows/WindowsEndpointOutputStream.java | 2 +- .../usb/windows/WindowsUSBDevice.java | 56 ++++--- .../usb/windows/WindowsUSBDeviceRegistry.java | 62 ++++---- .../usb/windows/WindowsUSBException.java | 20 +-- .../usb/windows/winsdk/Kernel32B.java | 76 ++++----- .../usb/windows/winsdk/SetupAPI2.java | 147 ++++++++---------- .../codecrete/usb/windows/winsdk/User32B.java | 62 ++++---- .../codecrete/usb/windows/winsdk/WinUSB2.java | 107 ++++++------- 37 files changed, 445 insertions(+), 503 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java index 1d665230..b0445f9c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java @@ -69,8 +69,9 @@ public interface USBAlternateInterface { /** * Gets the endpoint with the specified number and direction. + * * @param endpointNumber endpoint number (in the range between 1 and 127, without the direction bit) - * @param direction endpoint direction + * @param direction endpoint direction * @return the endpoint, or {@code null} if no endpoint with the given number and direction exists */ USBEndpoint getEndpoint(int endpointNumber, USBDirection direction); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index 85918f5c..ea1e13af 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -134,7 +134,7 @@ public interface USBDevice { /** * Gets the endpoint with the specified number. * - * @param direction the endpoint direction + * @param direction the endpoint direction * @param endpointNumber the endpoint number (between 1 and 127) * @return the endpoint, or {@code null} if no endpoint with the given direction and number exists */ @@ -152,6 +152,7 @@ public interface USBDevice { *

* The device must be open and the interface must be claimed for exclusive access. *

+ * * @param interfaceNumber interface number * @param alternateNumber alternate setting number */ @@ -297,6 +298,7 @@ public interface USBDevice { * If {@link #transferIn(int)} and an input stream or multiple input streams * are used concurrently for the same endpoint, the behavior is unpredictable. *

+ * * @param endpointNumber bulk endpoint number (in the range between 1 and 127, i.e. without the direction bit) * @return the new input stream */ @@ -307,7 +309,8 @@ public interface USBDevice { *

* This operation is not valid on the control endpoint 0. *

- * @param direction endpoint direction + * + * @param direction endpoint direction * @param endpointNumber endpoint number (in the range between 1 and 127) */ void abortTransfers(USBDirection direction, int endpointNumber); @@ -322,7 +325,8 @@ public interface USBDevice { *

* Control endpoint 0 will never be halted. *

- * @param direction endpoint direction + * + * @param direction endpoint direction * @param endpointNumber endpoint number (in the range between 1 and 127) */ void clearHalt(USBDirection direction, int endpointNumber); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java index 2d6e7f54..8f63c649 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java @@ -21,7 +21,7 @@ public interface USBInterface { * Gets the interface number. *

* It is equal to the {@code bInterfaceNumber} field of the interface descriptor. - *

+ *

* * @return the interface number */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/Version.java b/java-does-usb/src/main/java/net/codecrete/usb/Version.java index 88267a4e..d2b4fd95 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/Version.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/Version.java @@ -22,6 +22,7 @@ public final class Version { * is minor version, the low one is the subminor version. As an example, * 0x0321 represents the version 3.2.1. *

+ * * @param bcdVersion version, encoded as described above */ public Version(int bcdVersion) { @@ -30,6 +31,7 @@ public Version(int bcdVersion) { /** * Major version + * * @return major version */ public int major() { @@ -38,6 +40,7 @@ public int major() { /** * Minor version + * * @return minor version */ public int minor() { @@ -46,6 +49,7 @@ public int minor() { /** * Subminor version + * * @return subminor version */ public int subminor() { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncIOCompletion.java b/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncIOCompletion.java index 63581eed..2e90f3f0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncIOCompletion.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncIOCompletion.java @@ -21,7 +21,7 @@ public interface AsyncIOCompletion { *

* * @param result the native result code of the operation. - * @param size the size of the transferred data (in bytes) + * @param size the size of the transferred data (in bytes) */ void completed(int result, int size); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java b/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java index 497b5aba..e2a0f03b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java @@ -36,7 +36,8 @@ public class CompositeFunction { * @param subclassCode the function subclass * @param protocolCode the function protocol */ - public CompositeFunction(int firstInterfaceNumber, int numInterfaces, int classCode, int subclassCode, int protocolCode) { + public CompositeFunction(int firstInterfaceNumber, int numInterfaces, int classCode, int subclassCode, + int protocolCode) { firstInterfaceNumber_ = firstInterfaceNumber; numInterfaces_ = numInterfaces; classCode_ = classCode; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java b/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java index 0df069e5..692ea52c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java @@ -46,7 +46,9 @@ public List interfaces() { return interfaces_; } - public List functions() { return functions_; } + public List functions() { + return functions_; + } public void addInterface(USBInterface intf) { interfaces_.add(intf); @@ -61,9 +63,6 @@ public void addFunction(CompositeFunction function) { } public CompositeFunction findFunction(int interfaceNumber) { - return functions_.stream() - .filter((f) -> interfaceNumber >= f.firstInterfaceNumber() - && interfaceNumber < f.firstInterfaceNumber() + f.numInterfaces()) - .findFirst().orElse(null); + return functions_.stream().filter((f) -> interfaceNumber >= f.firstInterfaceNumber() && interfaceNumber < f.firstInterfaceNumber() + f.numInterfaces()).findFirst().orElse(null); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java index c10a4fa2..cf4fbda5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java @@ -24,7 +24,7 @@ public class ForeignMemory { * Dereferences the address at the start of the memory segment and returns the result as * a memory segment of the specified length. * - * @param segment the memory segment with the pointer at offset 0 + * @param segment the memory segment with the pointer at offset 0 * @param byteSize the length * @return the dereferenced memory segment */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java index d0ec9a60..d9b3045b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java @@ -31,10 +31,11 @@ */ public class ScopeCleanup implements AutoCloseable { - private final ArrayList cleanupActions= new ArrayList<>(); + private final ArrayList cleanupActions = new ArrayList<>(); /** * Registers a cleanup action to be run later. + * * @param cleanupAction cleanup action */ public void add(Runnable cleanupAction) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java index d3c2456f..1522e97f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java @@ -62,9 +62,6 @@ void addEndpoint(USBEndpoint endpoint) { @Override public USBEndpoint getEndpoint(int endpointNumber, USBDirection direction) { - return endpoints_ - .stream().filter((ep) -> ep.number() == endpointNumber && ep.direction() == direction) - .findFirst() - .orElse(null); + return endpoints_.stream().filter((ep) -> ep.number() == endpointNumber && ep.direction() == direction).findFirst().orElse(null); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 327154dc..38e4717b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -10,8 +10,6 @@ import net.codecrete.usb.*; import net.codecrete.usb.usbstandard.DeviceDescriptor; -import java.io.InputStream; -import java.io.OutputStream; import java.lang.foreign.MemorySegment; import java.util.Collections; import java.util.List; @@ -39,9 +37,9 @@ public abstract class USBDeviceImpl implements USBDevice { /** * Creates a new instance. * - * @param id unique device ID - * @param vendorId USB vendor ID - * @param productId USB product ID + * @param id unique device ID + * @param vendorId USB vendor ID + * @param productId USB product ID */ protected USBDeviceImpl(Object id, int vendorId, int productId) { @@ -107,13 +105,19 @@ public int protocolCode() { } @Override - public Version usbVersion() { return usbVersion_; } + public Version usbVersion() { + return usbVersion_; + } @Override - public Version deviceVersion() { return deviceVersion_; } + public Version deviceVersion() { + return deviceVersion_; + } @Override - public byte[] configurationDescriptor() { return configurationDescriptor_; } + public byte[] configurationDescriptor() { + return configurationDescriptor_; + } public Object getUniqueId() { return id_; @@ -121,6 +125,7 @@ public Object getUniqueId() { /** * Sets the class codes and version for the device descriptor. + * * @param descriptor the device descriptor */ public void setFromDeviceDescriptor(MemorySegment descriptor) { @@ -134,6 +139,7 @@ public void setFromDeviceDescriptor(MemorySegment descriptor) { /** * Sets the configuration descriptor and derives the interface and endpoint descriptions. + * * @param descriptor configuration descriptor * @return parsed configuration */ @@ -160,10 +166,11 @@ public void setProductStrings(String manufacturer, String product, String serial /** * Sets the product strings from the device descriptor. *

- * To lookup the string, a lookup function is provided. It takes the - * string ID and returns the string from the string descriptor. + * To lookup the string, a lookup function is provided. It takes the + * string ID and returns the string from the string descriptor. *

- * @param descriptor device descriptor + * + * @param descriptor device descriptor * @param stringLookup string lookup function */ public void setProductString(MemorySegment descriptor, Function stringLookup) { @@ -230,8 +237,8 @@ public USBEndpoint getEndpoint(USBDirection direction, int endpointNumber) { * @param transferType2 transfer type 2 (or {@code null}) * @return endpoint */ - protected EndpointInfo getEndpoint(USBDirection direction, int endpointNumber, - USBTransferType transferType1, USBTransferType transferType2) { + protected EndpointInfo getEndpoint(USBDirection direction, int endpointNumber, USBTransferType transferType1, + USBTransferType transferType2) { checkIsOpen(); @@ -239,8 +246,7 @@ protected EndpointInfo getEndpoint(USBDirection direction, int endpointNumber, for (var intf : interfaces_) { if (intf.isClaimed()) { for (var ep : intf.alternate().endpoints()) { - if (ep.number() == endpointNumber && ep.direction() == direction - && (ep.transferType() == transferType1 || ep.transferType() == transferType2)) + if (ep.number() == endpointNumber && ep.direction() == direction && (ep.transferType() == transferType1 || ep.transferType() == transferType2)) return new EndpointInfo(intf.number(), ep.number(), (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)), ep.packetSize()); @@ -260,9 +266,7 @@ protected void throwInvalidEndpointException(USBDirection direction, int endpoin transferTypeDesc = transferType1.name(); else transferTypeDesc = String.format("%s or %s", transferType1.name(), transferType2.name()); - throw new USBException(String.format("Endpoint number %d does not exist, is not part of a claimed interface " + - "or is not valid for %s transfer in %s direction", endpointNumber, transferTypeDesc, - direction.name())); + throw new USBException(String.format("Endpoint number %d does not exist, is not part of a claimed interface " + "or is not valid for %s transfer in %s direction", endpointNumber, transferTypeDesc, direction.name())); } protected int getInterfaceNumber(USBDirection direction, int endpointNumber) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index 92b9e466..8c036638 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -102,7 +102,8 @@ protected void emitOnDeviceDisconnected(USBDevice device) { onDeviceDisconnectedHandler.accept(device); } catch (Throwable e) { - System.err.println("Warning: [JavaDoesUSB] unhandled exception in 'onDeviceDisconnected' handler - ignoring"); + System.err.println("Warning: [JavaDoesUSB] unhandled exception in 'onDeviceDisconnected' handler - " + + "ignoring"); e.printStackTrace(System.err); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java index 2d6c88ee..0145e517 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java @@ -9,33 +9,29 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; import static java.lang.foreign.ValueLayout.*; public class IO { - /** - * Call state for capturing the {@code errno} value. - */ - public static final Linker.Option.CaptureCallState ERRNO_STATE = Linker.Option.captureCallState("errno"); - - private static final VarHandle callState_errno$VH = ERRNO_STATE.layout().varHandle(MemoryLayout.PathElement.groupElement("errno")); - private static final Linker linker = Linker.nativeLinker(); private static final FunctionDescriptor ioctl$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_LONG, ADDRESS); - private static final MethodHandle ioctl$MH = linker.downcallHandle(linker.defaultLookup().find("ioctl").get(), ioctl$FUNC, ERRNO_STATE); + private static final MethodHandle ioctl$MH = linker.downcallHandle(linker.defaultLookup().find("ioctl").get(), + ioctl$FUNC, Linux.ERRNO_STATE); private static final FunctionDescriptor open$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT); - private static final MethodHandle open$MH = linker.downcallHandle(linker.defaultLookup().find("open").get(), open$FUNC, ERRNO_STATE); + private static final MethodHandle open$MH = linker.downcallHandle(linker.defaultLookup().find("open").get(), + open$FUNC, Linux.ERRNO_STATE); private static final FunctionDescriptor eventfd$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_INT); - private static final MethodHandle eventfd$MH = linker.downcallHandle(linker.defaultLookup().find("eventfd").get(), eventfd$FUNC, ERRNO_STATE); + private static final MethodHandle eventfd$MH = linker.downcallHandle(linker.defaultLookup().find("eventfd").get() + , eventfd$FUNC, Linux.ERRNO_STATE); private static final FunctionDescriptor eventfd_read$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS); - private static final MethodHandle eventfd_read$MH = linker.downcallHandle(linker.defaultLookup().find("eventfd_read").get(), eventfd_read$FUNC, ERRNO_STATE); + private static final MethodHandle eventfd_read$MH = linker.downcallHandle(linker.defaultLookup().find( + "eventfd_read").get(), eventfd_read$FUNC, Linux.ERRNO_STATE); private static final FunctionDescriptor eventfd_write$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_LONG); - private static final MethodHandle eventfd_write$MH = linker.downcallHandle(linker.defaultLookup().find("eventfd_write").get(), eventfd_write$FUNC, ERRNO_STATE); + private static final MethodHandle eventfd_write$MH = linker.downcallHandle(linker.defaultLookup().find( + "eventfd_write").get(), eventfd_write$FUNC, Linux.ERRNO_STATE); public static int ioctl(int fd, long request, MemorySegment segment, MemorySegment errno) { try { @@ -77,16 +73,4 @@ public static int eventfd_write(int fd, long value, MemorySegment errno) { } } - /** - * Gets the error code from the memory segment. - *

- * The memory segment is assumed to have the layout {@link #ERRNO_STATE}. - *

- * - * @param errno memory segment with error code - * @return error code - */ - public static int getErrno(MemorySegment errno) { - return (int) callState_errno$VH.get(errno); - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java index de361a0d..0c714427 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java @@ -9,11 +9,23 @@ import net.codecrete.usb.linux.gen.string.string; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.VarHandle; + /** * Helper functions for Linux */ public class Linux { + /** + * Call state for capturing the {@code errno} value. + */ + public static final Linker.Option.CaptureCallState ERRNO_STATE = Linker.Option.captureCallState("errno"); + private static final VarHandle callState_errno$VH = + ERRNO_STATE.layout().varHandle(MemoryLayout.PathElement.groupElement("errno")); + /** * Gets the error message for the specified error code (returned by {@code errno}). * @@ -23,4 +35,17 @@ public class Linux { public static String getErrorMessage(int err) { return string.strerror(err).getUtf8String(0); } + + /** + * Gets the error code from the memory segment. + *

+ * The memory segment is assumed to have the layout {@link #ERRNO_STATE}. + *

+ * + * @param errno memory segment with error code + * @return error code + */ + public static int getErrno(MemorySegment errno) { + return (int) callState_errno$VH.get(errno); + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index a669610d..295a5f6e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -71,7 +71,7 @@ public void open() { try (var arena = Arena.openConfined()) { var pathUtf8 = arena.allocateUtf8String(id_.toString()); - var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); fd = IO.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC(), errnoState); if (fd == -1) throwLastError(errnoState, "Cannot open USB device"); @@ -108,7 +108,7 @@ public void claimInterface(int interfaceNumber) { try (var arena = Arena.openConfined()) { var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); - var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); int ret = IO.ioctl(fd, USBDevFS.CLAIMINTERFACE, intfNumSegment, errnoState); if (ret != 0) throwLastError(errnoState, "Cannot claim USB interface"); @@ -129,13 +129,14 @@ public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { // check alternate setting var altSetting = intf.getAlternate(alternateNumber); if (altSetting == null) - throwException("Interface %d does not have an alternate interface setting %d", interfaceNumber, alternateNumber); + throwException("Interface %d does not have an alternate interface setting %d", interfaceNumber, + alternateNumber); try (var arena = Arena.openConfined()) { var setIntfSegment = arena.allocate(usbdevfs_setinterface.$LAYOUT()); usbdevfs_setinterface.interface_$set(setIntfSegment, interfaceNumber); usbdevfs_setinterface.altsetting$set(setIntfSegment, alternateNumber); - var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); int ret = IO.ioctl(fd, USBDevFS.SETINTERFACE, setIntfSegment, errnoState); if (ret != 0) throwLastError(errnoState, "Failed to set alternate interface"); @@ -155,7 +156,7 @@ public void releaseInterface(int interfaceNumber) { try (var arena = Arena.openConfined()) { var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); - var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); int ret = IO.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment, errnoState); if (ret != 0) throwLastError(errnoState, "Cannot release USB interface"); @@ -183,7 +184,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { var data = arena.allocate(length); var ctrlTransfer = createCtrlTransfer(arena, USBDirection.IN, setup, data); - var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); int res = IO.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer, errnoState); if (res < 0) throwLastError(errnoState, "Control IN transfer failed"); @@ -201,7 +202,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { buffer.copyFrom(MemorySegment.ofArray(data)); var ctrlTransfer = createCtrlTransfer(arena, USBDirection.OUT, setup, buffer); - var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); int res = IO.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer, errnoState); if (res < 0) throwLastError(errnoState, "Control OUT transfer failed"); @@ -219,18 +220,17 @@ private MemorySegment createBulkTransfer(Arena arena, byte endpointAddress, Memo @Override public void transferOut(int endpointNumber, byte[] data, int timeout) { - var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, - USBTransferType.BULK, USBTransferType.INTERRUPT); + var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); try (var arena = Arena.openConfined()) { var buffer = arena.allocate(data.length); buffer.copyFrom(MemorySegment.ofArray(data)); var transfer = createBulkTransfer(arena, endpoint.endpointAddress(), buffer, timeout); - var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); int res = IO.ioctl(fd, USBDevFS.BULK, transfer, errnoState); if (res < 0) { - int err = IO.getErrno(errnoState); + int err = Linux.getErrno(errnoState); if (err == errno.ETIMEDOUT()) throw new USBTimeoutException("Transfer out aborted due to timeout"); throwLastError(errnoState, "USB OUT transfer on endpoint %d failed", endpointNumber); @@ -240,18 +240,17 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { @Override public byte[] transferIn(int endpointNumber, int timeout) { - var endpoint = getEndpoint(USBDirection.IN, endpointNumber, - USBTransferType.BULK, USBTransferType.INTERRUPT); + var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); try (var arena = Arena.openConfined()) { var buffer = arena.allocate(endpoint.packetSize()); var transfer = createBulkTransfer(arena, endpoint.endpointAddress(), buffer, timeout); - var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); int res = IO.ioctl(fd, USBDevFS.BULK, transfer, errnoState); if (res < 0) { - int err = IO.getErrno(errnoState); + int err = Linux.getErrno(errnoState); if (err == errno.ETIMEDOUT()) throw new USBTimeoutException("Transfer in aborted due to timeout"); throwLastError(errnoState, "USB IN transfer on endpoint %d failed", endpointNumber); @@ -263,12 +262,11 @@ public byte[] transferIn(int endpointNumber, int timeout) { @Override public void clearHalt(USBDirection direction, int endpointNumber) { - var endpoint = getEndpoint(direction, endpointNumber, - USBTransferType.BULK, USBTransferType.INTERRUPT); + var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); try (var arena = Arena.openConfined()) { var endpointAddrSegment = arena.allocate(JAVA_INT, endpoint.endpointAddress() & 0xff); - var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); int res = IO.ioctl(fd, USBDevFS.CLEAR_HALT, endpointAddrSegment, errnoState); if (res < 0) throwLastError(errnoState, "Clearing halt failed"); @@ -277,8 +275,7 @@ public void clearHalt(USBDirection direction, int endpointNumber) { @Override public synchronized void abortTransfers(USBDirection direction, int endpointNumber) { - var endpoint = getEndpoint(direction, endpointNumber, - USBTransferType.BULK, USBTransferType.INTERRUPT); + var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); registry.abortTransfers(this, endpoint.endpointAddress()); } @@ -299,12 +296,14 @@ public OutputStream openOutputStream(int endpointNumber) { return new LinuxEndpointOutputStream(this, endpointNumber); } - synchronized void submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, AsyncIOCompletion completion) { + synchronized void submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, + AsyncIOCompletion completion) { var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); registry.submitBulkTransfer(this, endpoint.endpointAddress(), buffer, bufferSize, completion); } - synchronized void submitTransferOut(int endpointNumber, MemorySegment data, int dataSize, AsyncIOCompletion completion) { + synchronized void submitTransferOut(int endpointNumber, MemorySegment data, int dataSize, + AsyncIOCompletion completion) { var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); registry.submitBulkTransfer(this, endpoint.endpointAddress(), data, dataSize, completion); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 73382006..403569bb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -218,8 +218,8 @@ private USBDevice getDeviceDetails(MemorySegment udevDevice) { // create device instance var device = new LinuxUSBDevice(this, devPath, vendorId, productId); - device.setProductStrings(getDeviceAttribute(udevDevice, ATTR_MANUFACTURER), - getDeviceAttribute(udevDevice, ATTR_PRODUCT), getDeviceAttribute(udevDevice, ATTR_SERIAL)); + device.setProductStrings(getDeviceAttribute(udevDevice, ATTR_MANUFACTURER), getDeviceAttribute(udevDevice + , ATTR_PRODUCT), getDeviceAttribute(udevDevice, ATTR_SERIAL)); return device; @@ -268,7 +268,7 @@ private static void waitForFileDescriptor(int fd, Arena arena) { private void asyncCompletionTask() { try (var arena = Arena.openConfined()) { - var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); var asyncPolls = pollfd.allocateArray(100, arena); var urbPointerHolder = arena.allocate(ADDRESS); var eventfdValueHolder = arena.allocate(JAVA_LONG); @@ -330,7 +330,7 @@ private void reapURB(int fd, MemorySegment urbPointerHolder, MemorySegment errno int res; res = IO.ioctl(fd, REAPURB, urbPointerHolder, errnoState); if (res < 0) { - var err = IO.getErrno(errnoState); + var err = Linux.getErrno(errnoState); if (err == errno.EBADF()) return; // ignore, device might have been closed throwException(err, "internal error (reap URB)"); @@ -360,7 +360,7 @@ private void notifyAsyncIOTask() { } try (var arena = Arena.openConfined()) { - var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); if (IO.eventfd_write(asyncIOUpdateEventFd, 1, errnoState) < 0) throwLastError(errnoState, "internal error (eventfd_write)"); } @@ -412,7 +412,8 @@ synchronized void unregisterCompletionHandling(LinuxUSBDevice device) { notifyAsyncIOTask(); } - synchronized void submitBulkTransfer(LinuxUSBDevice device, int endpointAddress, MemorySegment buffer, int bufferLength, AsyncIOCompletion completion) { + synchronized void submitBulkTransfer(LinuxUSBDevice device, int endpointAddress, MemorySegment buffer, + int bufferLength, AsyncIOCompletion completion) { var urb = getURB(completion); usbdevfs_urb.type$set(urb, (byte) USBDEVFS_URB_TYPE_BULK()); @@ -422,7 +423,7 @@ synchronized void submitBulkTransfer(LinuxUSBDevice device, int endpointAddress, usbdevfs_urb.usercontext$set(urb, MemorySegment.ofAddress(device.fileDescriptor())); try (var arena = Arena.openConfined()) { - var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); if (IO.ioctl(device.fileDescriptor(), SUBMITURB, urb, errnoState) < 0) throwLastError(errnoState, "failed to submit bulk transfer request"); } @@ -450,7 +451,7 @@ synchronized void recycleURB(MemorySegment urb) { synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { int fd = device.fileDescriptor(); try (var arena = Arena.openConfined()) { - var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); for (var urbAddress : completionHandlerByURB.keySet()) { var urb = usbdevfs_urb.ofAddress(MemorySegment.ofAddress(urbAddress), SegmentScope.global()); @@ -467,7 +468,7 @@ synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { private void startAsyncIOHandler() { try (var arena = Arena.openConfined()) { - var errnoState = arena.allocate(IO.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); asyncIOUpdateEventFd = IO.eventfd(0, 0, errnoState); if (asyncIOUpdateEventFd == -1) { asyncIOUpdateEventFd = 0; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java index 653fc204..9ff7ffdd 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java @@ -63,7 +63,7 @@ static void throwException(String message, Object... args) { * Throws an exception for the last error. *

* The message of the last Linux error code is provided in a memory segment with the layout - * {@link IO#ERRNO_STATE}. + * {@link Linux#ERRNO_STATE}. *

* * @param errno segment with lat error code @@ -71,7 +71,7 @@ static void throwException(String message, Object... args) { * @param args arguments for exception message */ static void throwLastError(MemorySegment errno, String message, Object... args) { - throwException(IO.getErrno(errno), message, args); + throwException(Linux.getErrno(errno), message, args); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 2710d8eb..f4fb9a7f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -353,8 +353,8 @@ private synchronized EndpointInfo getEndpointInfo(int endpointNumber, USBDirecti else transferTypeDesc = String.format("%s or %s", transferType1.name(), transferType2.name()); - throwException("Endpoint number %d does not exist, is not part of a claimed interface or is not valid for %s " + - "transfer in %s direction", endpointNumber, transferTypeDesc, direction.name()); + throwException("Endpoint number %d does not exist, is not part of a claimed interface or is not valid for %s " + + "transfer in %s direction", endpointNumber, transferTypeDesc, direction.name()); throw new AssertionError("not reached"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java index 3d4dcf5c..8f728551 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java @@ -30,6 +30,7 @@ public ConfigurationDescriptor(MemorySegment descriptor) { public int descriptorType() { return 0xff & (byte) bDescriptorType$VH.get(descriptor); } + public int totalLength() { return 0xffff & (short) wTotalLength$VH.get(descriptor); } @@ -65,16 +66,10 @@ public int maxPower() { // uint8_t bmAttributes; // uint8_t bMaxPower; // } __attribute__((packed)); - public static final GroupLayout LAYOUT = structLayout( - JAVA_BYTE.withName("bLength"), - JAVA_BYTE.withName("bDescriptorType"), - JAVA_SHORT_UNALIGNED.withName("wTotalLength"), - JAVA_BYTE.withName("bNumInterfaces"), - JAVA_BYTE.withName("bConfigurationValue"), - JAVA_BYTE.withName("iConfiguration"), - JAVA_BYTE.withName("bmAttributes"), - JAVA_BYTE.withName("bMaxPower") - ); + public static final GroupLayout LAYOUT = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( + "bDescriptorType"), JAVA_SHORT_UNALIGNED.withName("wTotalLength"), JAVA_BYTE.withName("bNumInterfaces"), + JAVA_BYTE.withName("bConfigurationValue"), JAVA_BYTE.withName("iConfiguration"), JAVA_BYTE.withName( + "bmAttributes"), JAVA_BYTE.withName("bMaxPower")); private static final VarHandle bDescriptorType$VH = LAYOUT.varHandle(groupElement("bDescriptorType")); private static final VarHandle wTotalLength$VH = LAYOUT.varHandle(groupElement("wTotalLength")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java index 708cc3a1..dda87cc9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java @@ -83,22 +83,13 @@ public int iSerialNumber() { // uint8_t iSerialNumber; // uint8_t bNumConfigurations; // } __attribute__((packed)); - public static final GroupLayout LAYOUT = structLayout( - JAVA_BYTE.withName("bLength"), - JAVA_BYTE.withName("bDescriptorType"), - JAVA_SHORT_UNALIGNED.withName("bcdUSB"), - JAVA_BYTE.withName("bDeviceClass"), - JAVA_BYTE.withName("bDeviceSubClass"), - JAVA_BYTE.withName("bDeviceProtocol"), - JAVA_BYTE.withName("bMaxPacketSize0"), - JAVA_SHORT_UNALIGNED.withName("idVendor"), - JAVA_SHORT_UNALIGNED.withName("idProduct"), - JAVA_SHORT_UNALIGNED.withName("bcdDevice"), - JAVA_BYTE.withName("iManufacturer"), - JAVA_BYTE.withName("iProduct"), - JAVA_BYTE.withName("iSerialNumber"), - JAVA_BYTE.withName("bNumConfigurations") - ); + public static final GroupLayout LAYOUT = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( + "bDescriptorType"), JAVA_SHORT_UNALIGNED.withName("bcdUSB"), JAVA_BYTE.withName("bDeviceClass"), + JAVA_BYTE.withName("bDeviceSubClass"), JAVA_BYTE.withName("bDeviceProtocol"), JAVA_BYTE.withName( + "bMaxPacketSize0"), JAVA_SHORT_UNALIGNED.withName("idVendor"), JAVA_SHORT_UNALIGNED.withName( + "idProduct"), JAVA_SHORT_UNALIGNED.withName("bcdDevice"), JAVA_BYTE.withName( + "iManufacturer"), JAVA_BYTE.withName("iProduct"), JAVA_BYTE.withName( + "iSerialNumber"), JAVA_BYTE.withName("bNumConfigurations")); private static final VarHandle bcdUSB$VH = LAYOUT.varHandle(groupElement("bcdUSB")); private static final VarHandle bDeviceClass$VH = LAYOUT.varHandle(groupElement("bDeviceClass")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java index 059a9335..dfaa3571 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java @@ -55,14 +55,9 @@ public int interval() { // uint16_t wMaxPacketSize; // uint8_t bInterval; // } __attribute__((packed)); - public static final GroupLayout LAYOUT = structLayout( - JAVA_BYTE.withName("bLength"), - JAVA_BYTE.withName("bDescriptorType"), - JAVA_BYTE.withName("bEndpointAddress"), - JAVA_BYTE.withName("bmAttributes"), - JAVA_SHORT_UNALIGNED.withName("wMaxPacketSize"), - JAVA_BYTE.withName("bInterval") - ); + public static final GroupLayout LAYOUT = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( + "bDescriptorType"), JAVA_BYTE.withName("bEndpointAddress"), JAVA_BYTE.withName("bmAttributes"), + JAVA_SHORT_UNALIGNED.withName("wMaxPacketSize"), JAVA_BYTE.withName("bInterval")); private static final VarHandle bEndpointAddress$VH = LAYOUT.varHandle(groupElement("bEndpointAddress")); private static final VarHandle bmAttributes$VH = LAYOUT.varHandle(groupElement("bmAttributes")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java index d5fc5b73..ca1c9c45 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java @@ -65,16 +65,10 @@ public int function() { // uint8_t bFunctionProtocol, // uint8_t iFunction // } __attribute__((packed)); - public static final GroupLayout LAYOUT = structLayout( - JAVA_BYTE.withName("bLength"), - JAVA_BYTE.withName("bDescriptorType"), - JAVA_BYTE.withName("bFirstInterface"), - JAVA_BYTE.withName("bInterfaceCount"), - JAVA_BYTE.withName("bFunctionClass"), - JAVA_BYTE.withName("bFunctionSubClass"), - JAVA_BYTE.withName("bFunctionProtocol"), - JAVA_BYTE.withName("iFunction") - ); + public static final GroupLayout LAYOUT = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( + "bDescriptorType"), JAVA_BYTE.withName("bFirstInterface"), JAVA_BYTE.withName("bInterfaceCount"), + JAVA_BYTE.withName("bFunctionClass"), JAVA_BYTE.withName("bFunctionSubClass"), JAVA_BYTE.withName( + "bFunctionProtocol"), JAVA_BYTE.withName("iFunction")); private static final VarHandle bFirstInterface$VH = LAYOUT.varHandle(groupElement("bFirstInterface")); private static final VarHandle bInterfaceCount$VH = LAYOUT.varHandle(groupElement("bInterfaceCount")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java index 04668e37..e537b4e4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java @@ -69,17 +69,10 @@ public int iInterface() { // uint8_t bInterfaceProtocol; // uint8_t iInterface; // } __attribute__((packed)); - public static final GroupLayout LAYOUT = structLayout( - JAVA_BYTE.withName("bLength"), - JAVA_BYTE.withName("bDescriptorType"), - JAVA_BYTE.withName("bInterfaceNumber"), - JAVA_BYTE.withName("bAlternateSetting"), - JAVA_BYTE.withName("bNumEndpoints"), - JAVA_BYTE.withName("bInterfaceClass"), - JAVA_BYTE.withName("bInterfaceSubClass"), - JAVA_BYTE.withName("bInterfaceProtocol"), - JAVA_BYTE.withName("iInterface") - ); + public static final GroupLayout LAYOUT = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( + "bDescriptorType"), JAVA_BYTE.withName("bInterfaceNumber"), JAVA_BYTE.withName("bAlternateSetting"), + JAVA_BYTE.withName("bNumEndpoints"), JAVA_BYTE.withName("bInterfaceClass"), JAVA_BYTE.withName( + "bInterfaceSubClass"), JAVA_BYTE.withName("bInterfaceProtocol"), JAVA_BYTE.withName("iInterface")); private static final VarHandle bInterfaceNumber$VH = LAYOUT.varHandle(groupElement("bInterfaceNumber")); private static final VarHandle bAlternateSetting$VH = LAYOUT.varHandle(groupElement("bAlternateSetting")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java index b1109a3e..f5b98a75 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java @@ -91,13 +91,8 @@ public void setLength(int length) { // uint16_t wIndex; // uint16_t wLength; // } __attribute__((packed)); - public static final GroupLayout LAYOUT = structLayout( - JAVA_BYTE.withName("bmRequestType"), - JAVA_BYTE.withName("bRequest"), - JAVA_SHORT.withName("wValue"), - JAVA_SHORT.withName("wIndex"), - JAVA_SHORT.withName("wLength") - ); + public static final GroupLayout LAYOUT = structLayout(JAVA_BYTE.withName("bmRequestType"), JAVA_BYTE.withName( + "bRequest"), JAVA_SHORT.withName("wValue"), JAVA_SHORT.withName("wIndex"), JAVA_SHORT.withName("wLength")); private static final VarHandle bmRequestType$VH = LAYOUT.varHandle(groupElement("bmRequestType")); private static final VarHandle bRequest$VH = LAYOUT.varHandle(groupElement("bRequest")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java index 96dea670..04954815 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java @@ -40,11 +40,8 @@ public String string() { // uint8_t bDescriptorType; // uint16_t string[1]; // } __attribute__((packed)); - public static final GroupLayout LAYOUT = structLayout( - JAVA_BYTE.withName("bLength"), - JAVA_BYTE.withName("bDescriptorType"), - JAVA_SHORT.withName("string") - ); + public static final GroupLayout LAYOUT = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( + "bDescriptorType"), JAVA_SHORT.withName("string")); private static final VarHandle bLength$VH = LAYOUT.varHandle(groupElement("bLength")); private static final long string$offset = LAYOUT.byteOffset(groupElement("string")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index 468d3e92..a2d0d7f8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -32,37 +32,39 @@ public class DeviceProperty { public static final MemorySegment DEVPKEY_Device_Address = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, - (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, - (byte) 0x46, (byte) 0xa8, (byte) 0x50, (byte) 0xe0, 30); + (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50 + , (byte) 0xe0, 30); public static final MemorySegment DEVPKEY_Device_InstanceId = createDEVPROPKEY(0x78c34fc8, (short) 0x104a, - (short) 0x4aca, (byte) 0x9e, (byte) 0xa4, (byte) 0x52, (byte) 0x4d, - (byte) 0x52, (byte) 0x99, (byte) 0x6e, (byte) 0x57, 256); + (short) 0x4aca, (byte) 0x9e, (byte) 0xa4, (byte) 0x52, (byte) 0x4d, (byte) 0x52, (byte) 0x99, (byte) 0x6e + , (byte) 0x57, 256); public static final MemorySegment DEVPKEY_Device_Parent = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, - (short) 0x4706, (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, - (byte) 0x80, (byte) 0x08, (byte) 0xa5, (byte) 0xa7, 8); + (short) 0x4706, (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, (byte) 0x80, (byte) 0x08, (byte) 0xa5 + , (byte) 0xa7, 8); public static final MemorySegment DEVPKEY_Device_Service = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, - (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, - (byte) 0x46, (byte) 0xa8, (byte) 0x50, (byte) 0xe0, 6); + (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50 + , (byte) 0xe0, 6); public static final MemorySegment DEVPKEY_Device_Children = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, - (short) 0x4706, (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, - (byte) 0x80, (byte) 0x08, (byte) 0xa5, (byte) 0xa7, 9); + (short) 0x4706, (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, (byte) 0x80, (byte) 0x08, (byte) 0xa5 + , (byte) 0xa7, 9); public static final MemorySegment DEVPKEY_Device_HardwareIds = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, - (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, - (byte) 0x46, (byte) 0xa8, (byte) 0x50, (byte) 0xe0, 3); + (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50 + , (byte) 0xe0, 3); /** * Gets the device property with integer type. - * @param devInfoSet device information set containing the device ({@code HDEVINFO}) + * + * @param devInfoSet device information set containing the device ({@code HDEVINFO}) * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set * @param propertyKey property key (of type {@code DEVPKEY}) * @return property value */ - public static int getDeviceIntProperty(MemorySegment devInfoSet, MemorySegment devInfoData, MemorySegment propertyKey) { + public static int getDeviceIntProperty(MemorySegment devInfoSet, MemorySegment devInfoData, + MemorySegment propertyKey) { try (var arena = Arena.openConfined()) { var propertyTypeHolder = arena.allocate(JAVA_INT); var propertyValueHolder = arena.allocate(JAVA_INT); @@ -80,7 +82,8 @@ public static int getDeviceIntProperty(MemorySegment devInfoSet, MemorySegment d /** * Gets the device property with string type. - * @param devInfoSet device information set containing the device ({@code HDEVINFO}) + * + * @param devInfoSet device information set containing the device ({@code HDEVINFO}) * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set * @param propertyKey property key (of type {@code DEVPKEY}) * @return property value @@ -88,7 +91,8 @@ public static int getDeviceIntProperty(MemorySegment devInfoSet, MemorySegment d public static String getDeviceStringProperty(MemorySegment devInfoSet, MemorySegment devInfoData, MemorySegment propertyKey) { try (var arena = Arena.openConfined()) { - var propertyValue = getVariableLengthProperty(devInfoSet, devInfoData, propertyKey, SetupAPI.DEVPROP_TYPE_STRING(), arena); + var propertyValue = getVariableLengthProperty(devInfoSet, devInfoData, propertyKey, + SetupAPI.DEVPROP_TYPE_STRING(), arena); if (propertyValue == null) return null; return Win.createStringFromSegment(propertyValue); @@ -97,7 +101,8 @@ public static String getDeviceStringProperty(MemorySegment devInfoSet, MemorySeg /** * Gets the device property with string list type. - * @param devInfoSet device information set containing the device ({@code HDEVINFO}) + * + * @param devInfoSet device information set containing the device ({@code HDEVINFO}) * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set * @param propertyKey property key (of type {@code DEVPKEY}) * @return property value @@ -114,8 +119,8 @@ public static List getDeviceStringListProperty(MemorySegment devInfoSet, } } - private static MemorySegment getVariableLengthProperty(MemorySegment devInfoSet, MemorySegment devInfoData, MemorySegment propertyKey, - int propertyType, Arena arena) { + private static MemorySegment getVariableLengthProperty(MemorySegment devInfoSet, MemorySegment devInfoData, + MemorySegment propertyKey, int propertyType, Arena arena) { // query length (thus no buffer) var propertyTypeHolder = arena.allocate(JAVA_INT); @@ -148,19 +153,21 @@ private static MemorySegment getVariableLengthProperty(MemorySegment devInfoSet, /** * Gets a list of {@code DeviceInterfaceGUIDs} from device-specific configuration information in the registry. - * @param devInfoSet device information set containing the device ({@code HDEVINFO}) + * + * @param devInfoSet device information set containing the device ({@code HDEVINFO}) * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set - * @param arena arena for allocating memory + * @param arena arena for allocating memory * @return list of GUIDs */ - public static List findDeviceInterfaceGUIDs(MemorySegment devInfoSet, MemorySegment devInfoData, Arena arena) { + public static List findDeviceInterfaceGUIDs(MemorySegment devInfoSet, MemorySegment devInfoData, + Arena arena) { try (var cleanup = new ScopeCleanup()) { var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); // open device registry key - var regKey = SetupAPI2.SetupDiOpenDevRegKey(devInfoSet, devInfoData, SetupAPI.DICS_FLAG_GLOBAL(), - 0, SetupAPI.DIREG_DEV(), Advapi32.KEY_READ(), lastErrorState); + var regKey = SetupAPI2.SetupDiOpenDevRegKey(devInfoSet, devInfoData, SetupAPI.DICS_FLAG_GLOBAL(), 0, + SetupAPI.DIREG_DEV(), Advapi32.KEY_READ(), lastErrorState); if (Win.IsInvalidHandle(regKey)) throwLastError(lastErrorState, "Cannot open device registry key"); cleanup.add(() -> Advapi32.RegCloseKey(regKey)); @@ -188,7 +195,8 @@ public static List findDeviceInterfaceGUIDs(MemorySegment devInfoSet, Me /** * Gets the device path for the device with the given device instance ID and device interface class. - * @param instanceID device instance ID + * + * @param instanceID device instance ID * @param interfaceGuid device interface class * @return the device path */ @@ -209,8 +217,8 @@ public static String getDevicePath(String instanceID, MemorySegment interfaceGui // retrieve first element of enumeration var devIntfData = arena.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); - if (SetupAPI2.SetupDiEnumDeviceInterfaces(devInfoSet, NULL, interfaceGuid, 0, - devIntfData, lastErrorState) == 0) + if (SetupAPI2.SetupDiEnumDeviceInterfaces(devInfoSet, NULL, interfaceGuid, 0, devIntfData, + lastErrorState) == 0) throwLastError(lastErrorState, "internal error (SetupDiEnumDeviceInterfaces)"); // get device path @@ -231,23 +239,24 @@ public static String getDevicePath(String instanceID, MemorySegment interfaceGui /** * Checks if the device is a composite USB device - * @param devInfoSet device information set containing the device ({@code HDEVINFO}) + * + * @param devInfoSet device information set containing the device ({@code HDEVINFO}) * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set * @return {@code true} if it is a composite device */ public static boolean isCompositeDevice(MemorySegment devInfoSet, MemorySegment devInfoData) { - var deviceService = getDeviceStringProperty(devInfoSet, devInfoData, - DEVPKEY_Device_Service); + var deviceService = getDeviceStringProperty(devInfoSet, devInfoData, DEVPKEY_Device_Service); // usbccgp is the USB Generic Parent Driver used for composite devices return "usbccgp".equalsIgnoreCase(deviceService); } private static MemorySegment createDEVPROPKEY(int data1, short data2, short data3, byte data4_0, byte data4_1, - byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7, int pid) { + byte data4_2, byte data4_3, byte data4_4, byte data4_5, + byte data4_6, byte data4_7, int pid) { var propKey = Win.GLOBAL_ALLOCATOR.allocate(DEVPROPKEY.$LAYOUT()); - Win.setGUID(DEVPROPKEY.fmtid$slice(propKey), - data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4, data4_5, data4_6, data4_7); + Win.setGUID(DEVPROPKEY.fmtid$slice(propKey), data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4 + , data4_5, data4_6, data4_7); DEVPROPKEY.pid$set(propKey, pid); return propKey; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java index d8072aaa..11c46090 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java @@ -44,14 +44,10 @@ public class USBHelper { // USB_CONNECTION_STATUS ConnectionStatus;/* OUTPUT */ // USB_PIPE_INFO PipeList[0];/* OUTPUT */ //} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; - public static final GroupLayout USB_NODE_CONNECTION_INFORMATION_EX$Struct = structLayout( - JAVA_INT.withName("ConnectionIndex"), - DeviceDescriptor.LAYOUT.withName("DeviceDescriptor"), - JAVA_BYTE.withName("CurrentConfigurationValue"), - JAVA_BYTE.withName("Speed"), - JAVA_BYTE.withName("DeviceIsHub"), - JAVA_SHORT_UNALIGNED.withName("DeviceAddress"), - JAVA_INT.withName("NumberOfOpenPipes"), + public static final GroupLayout USB_NODE_CONNECTION_INFORMATION_EX$Struct = structLayout(JAVA_INT.withName( + "ConnectionIndex"), DeviceDescriptor.LAYOUT.withName("DeviceDescriptor"), JAVA_BYTE.withName( + "CurrentConfigurationValue"), JAVA_BYTE.withName("Speed"), JAVA_BYTE.withName("DeviceIsHub"), + JAVA_SHORT_UNALIGNED.withName("DeviceAddress"), JAVA_INT.withName("NumberOfOpenPipes"), JAVA_INT.withName("ConnectionStatus") // USB_PIPE_INFO PipeList[0] ); @@ -76,10 +72,8 @@ public class USBHelper { // } SetupPacket; // UCHAR Data[0]; //} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST; - public static final GroupLayout USB_DESCRIPTOR_REQUEST$Struct = structLayout( - JAVA_INT.withName("ConnectionIndex"), - SetupPacket.LAYOUT.withName("SetupPacket") - ); + public static final GroupLayout USB_DESCRIPTOR_REQUEST$Struct = structLayout(JAVA_INT.withName("ConnectionIndex") + , SetupPacket.LAYOUT.withName("SetupPacket")); public static final VarHandle USB_DESCRIPTOR_REQUEST_ConnectionIndex = USB_DESCRIPTOR_REQUEST$Struct.varHandle(groupElement("ConnectionIndex")); public static final long USB_DESCRIPTOR_REQUEST_SetupPacket$Offset = diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index b44b9e8d..cb424e77 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -31,18 +31,22 @@ public class Win { /** * Call state for capturing the {@code GetLastError()} value. */ - public static final Linker.Option.CaptureCallState LAST_ERROR_STATE = Linker.Option.captureCallState("GetLastError"); + public static final Linker.Option.CaptureCallState LAST_ERROR_STATE = Linker.Option.captureCallState( + "GetLastError"); - private static final VarHandle callState_GetLastError$VH = LAST_ERROR_STATE.layout().varHandle(MemoryLayout.PathElement.groupElement("GetLastError")); + private static final VarHandle callState_GetLastError$VH = + LAST_ERROR_STATE.layout().varHandle(MemoryLayout.PathElement.groupElement("GetLastError")); /** * Returns the error code captured using the call state {@link #LAST_ERROR_STATE}. + * * @param callState the call state * @return the error code */ public static int getLastError(MemorySegment callState) { return (int) callState_GetLastError$VH.get(callState); } + /** * Checks if a Windows handle is invalid. * @@ -59,7 +63,7 @@ public static boolean IsInvalidHandle(MemorySegment handle) { * The memory segment contains a copy of the string (null-terminated, UTF-16/wide characters). *

* - * @param str the string to copy + * @param str the string to copy * @param arena the arena for the memory segment * @return the resulting memory segment */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java index e96d5c95..b18bef72 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java @@ -22,7 +22,7 @@ public class WindowsEndpointInputStream extends EndpointInputStream { @Override protected void submitTransferIn(MemorySegment buffer, int bufferSize, AsyncIOCompletion completion) { - ((WindowsUSBDevice)device).submitTransferIn(endpointNumber, buffer, bufferSize, completion); + ((WindowsUSBDevice) device).submitTransferIn(endpointNumber, buffer, bufferSize, completion); } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java index c2264159..ffaf513e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java @@ -22,7 +22,7 @@ public class WindowsEndpointOutputStream extends EndpointOutputStream { @Override protected void submitTransferOut(MemorySegment data, int dataSize, AsyncIOCompletion completion) { - ((WindowsUSBDevice)device).submitTransferOut(endpointNumber, data, dataSize, completion); + ((WindowsUSBDevice) device).submitTransferOut(endpointNumber, data, dataSize, completion); } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 43060aac..fb744ef6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -48,7 +48,8 @@ public class WindowsUSBDevice extends USBDeviceImpl { // Arena used to allocate OVERLAPPED data structures private Arena arena; - WindowsUSBDevice(WindowsUSBDeviceRegistry registry, String devicePath, Map children, int vendorId, int productId, MemorySegment configDesc) { + WindowsUSBDevice(WindowsUSBDeviceRegistry registry, String devicePath, Map children, + int vendorId, int productId, MemorySegment configDesc) { super(devicePath, vendorId, productId); this.registry = registry; readDescription(configDesc, devicePath, children); @@ -179,12 +180,13 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna // check alternate setting var altSetting = intf.getAlternate(alternateNumber); if (altSetting == null) - throwException("Interface %d does not have an alternate interface setting %d", interfaceNumber, alternateNumber); + throwException("Interface %d does not have an alternate interface setting %d", interfaceNumber, + alternateNumber); try (var arena = Arena.openConfined()) { var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - if (WinUSB2.WinUsb_SetCurrentAlternateSetting(intfHandle.interfaceHandle, - (byte) alternateNumber, lastErrorState) == 0) + if (WinUSB2.WinUsb_SetCurrentAlternateSetting(intfHandle.interfaceHandle, (byte) alternateNumber, + lastErrorState) == 0) throwLastError(lastErrorState, "Failed to set alternate interface"); } intf.setAlternate(altSetting); @@ -216,7 +218,8 @@ public synchronized void releaseInterface(int interfaceNumber) { setClaimed(interfaceNumber, false); } - private MemorySegment createSetupPacket(USBDirection direction, USBControlTransfer setup, MemorySegment data, Arena arena) { + private MemorySegment createSetupPacket(USBDirection direction, USBControlTransfer setup, MemorySegment data, + Arena arena) { var setupPacket = new SetupPacket(arena); var bmRequest = (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); @@ -239,8 +242,8 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { var lengthHolder = arena.allocate(JAVA_INT); var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - if (WinUSB2.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer, (int) buffer.byteSize(), - lengthHolder, NULL, lastErrorState) == 0) + if (WinUSB2.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer, + (int) buffer.byteSize(), lengthHolder, NULL, lastErrorState) == 0) throwLastError(lastErrorState, "Control transfer IN failed"); int rxLength = lengthHolder.get(JAVA_INT, 0); @@ -266,8 +269,8 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { var lengthHolder = arena.allocate(JAVA_INT); var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - if (WinUSB2.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer, (int) buffer.byteSize(), - lengthHolder, NULL, lastErrorState) == 0) + if (WinUSB2.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer, + (int) buffer.byteSize(), lengthHolder, NULL, lastErrorState) == 0) throwLastError(lastErrorState, "Control transfer OUT failed"); } } @@ -294,8 +297,8 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { var lengthHolder = arena.allocate(JAVA_INT); // send data - if (WinUSB2.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, (int) buffer.byteSize(), - lengthHolder, NULL, lastErrorState) == 0) { + if (WinUSB2.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, + (int) buffer.byteSize(), lengthHolder, NULL, lastErrorState) == 0) { int err = Win.getLastError(lastErrorState); if (err == Kernel32.ERROR_SEM_TIMEOUT()) throw new USBTimeoutException("Transfer out aborted due to timeout"); @@ -322,8 +325,8 @@ public byte[] transferIn(int endpointNumber, int timeout) { var lengthHolder = arena.allocate(JAVA_INT); // receive data - if (WinUSB2.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, (int) buffer.byteSize(), - lengthHolder, NULL, lastErrorState) == 0) { + if (WinUSB2.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, + (int) buffer.byteSize(), lengthHolder, NULL, lastErrorState) == 0) { int err = Win.getLastError(lastErrorState); if (err == Kernel32.ERROR_SEM_TIMEOUT()) throw new USBTimeoutException("Transfer in aborted due to timeout"); @@ -336,7 +339,8 @@ public byte[] transferIn(int endpointNumber, int timeout) { } } - synchronized long submitTransferOut(int endpointNumber, MemorySegment data, int dataSize, AsyncIOCompletion completion) { + synchronized long submitTransferOut(int endpointNumber, MemorySegment data, int dataSize, + AsyncIOCompletion completion) { var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); @@ -345,8 +349,8 @@ synchronized long submitTransferOut(int endpointNumber, MemorySegment data, int var overlapped = getOverlapped(completion); // submit transfer - if (WinUSB2.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), data, dataSize, - NULL, overlapped, lastErrorState) == 0) { + if (WinUSB2.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), data, dataSize, NULL + , overlapped, lastErrorState) == 0) { int err = Win.getLastError(lastErrorState); if (err != Kernel32.ERROR_IO_PENDING()) throwException(err, "Submitting transfer OUT failed"); @@ -356,7 +360,8 @@ synchronized long submitTransferOut(int endpointNumber, MemorySegment data, int } } - synchronized long submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, AsyncIOCompletion completion) { + synchronized long submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, + AsyncIOCompletion completion) { var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); @@ -379,12 +384,13 @@ synchronized long submitTransferIn(int endpointNumber, MemorySegment buffer, int /** * Cancels an asynchronous IO request. *

- * If the specific request is not found, the error is silently ignored. Such errors - * are likely to happen due to concurrency issues. + * If the specific request is not found, the error is silently ignored. Such errors + * are likely to happen due to concurrency issues. *

- * @param direction endpoint direction + * + * @param direction endpoint direction * @param endpointNumber endpoint number - * @param cancelHandle request's cancel handle returned when the request was submitted + * @param cancelHandle request's cancel handle returned when the request was submitted */ synchronized void cancelTransfer(USBDirection direction, int endpointNumber, long cancelHandle) { var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); @@ -414,9 +420,9 @@ synchronized void configureForAsyncIo(USBDirection direction, int endpointNumber WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder, lastErrorState) == 0) throwLastError(lastErrorState, "Setting timeout failed"); - var rawIoHolder = arena.allocate(JAVA_BYTE, (byte)0); - if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), - WinUSB.RAW_IO(), (int) rawIoHolder.byteSize(), rawIoHolder, lastErrorState) == 0) + var rawIoHolder = arena.allocate(JAVA_BYTE, (byte) 0); + if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), WinUSB.RAW_IO(), + (int) rawIoHolder.byteSize(), rawIoHolder, lastErrorState) == 0) throwLastError(lastErrorState, "Setting raw IO failed"); } } @@ -510,7 +516,7 @@ private InterfaceHandle findControlTransferInterface(USBControlTransfer setup) { synchronized void onAsyncIoCompleted(MemorySegment overlapped) { var handler = completionHandlers.get(overlapped); - handler.completed((int)OVERLAPPED.Internal$get(overlapped), (int)OVERLAPPED.InternalHigh$get(overlapped)); + handler.completed((int) OVERLAPPED.Internal$get(overlapped), (int) OVERLAPPED.InternalHigh$get(overlapped)); completionHandlers.remove(overlapped); availableOverlappedStructs.add(overlapped); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 19614441..0c1e35fc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -93,8 +93,8 @@ protected void monitorDevices() { throwLastError(lastErrorState, "Internal error (RegisterClassExW)"); // create message-only window - hwnd = User32B.CreateWindowExW(0, className, windowName, 0, 0, 0, 0, 0, - User32.HWND_MESSAGE(), NULL, instance, NULL, lastErrorState); + hwnd = User32B.CreateWindowExW(0, className, windowName, 0, 0, 0, 0, 0, User32.HWND_MESSAGE(), NULL, + instance, NULL, lastErrorState); if (hwnd.address() == 0) throwLastError(lastErrorState, "Internal error (CreateWindowExW)"); @@ -138,8 +138,8 @@ private void enumeratePresentDevices() { var lastErrorState = outerArena.allocate(Win.LAST_ERROR_STATE.layout()); // get device information set of all USB devices present - var devInfoSet = SetupAPI2.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, - NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), lastErrorState); + var devInfoSet = SetupAPI2.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, + SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), lastErrorState); if (Win.IsInvalidHandle(devInfoSet)) throwLastError(lastErrorState, "Internal error (SetupDiGetClassDevsW)"); @@ -208,8 +208,8 @@ private Map enumerateChildren(List childrenIds) { var devInfoData = arena.allocate(SP_DEVINFO_DATA.$LAYOUT()); SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) devInfoData.byteSize()); var instanceIdSegment = Win.createSegmentFromString(instanceId, arena); - if (SetupAPI2.SetupDiOpenDeviceInfoW(devInfoSet, instanceIdSegment, NULL, 0, - devInfoData, lastErrorState) == 0) + if (SetupAPI2.SetupDiOpenDeviceInfoW(devInfoSet, instanceIdSegment, NULL, 0, devInfoData, + lastErrorState) == 0) throwLastError(lastErrorState, "Internal error (SetupDiOpenDeviceInfoW)"); // get hardware IDs (to extract interface number) @@ -305,12 +305,13 @@ private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSet, MemorySeg * Retrieve device descriptor and create {@code USBDevice} instance * * @param devicePath the device path - * @param children map of child device paths, indexed by the first interface number + * @param children map of child device paths, indexed by the first interface number * @param hubHandle the hub handle (parent) * @param usbPortNum the USB port number * @return the {@code USBDevice} instance */ - private USBDevice createDevice(String devicePath, Map children, MemorySegment hubHandle, int usbPortNum) { + private USBDevice createDevice(String devicePath, Map children, MemorySegment hubHandle, + int usbPortNum) { try (var arena = Arena.openConfined()) { @@ -319,8 +320,9 @@ private USBDevice createDevice(String devicePath, Map children, USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex.set(connInfo, usbPortNum); var sizeHolder = arena.allocate(JAVA_INT); var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - if (Kernel32B.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), connInfo, - (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL, lastErrorState) == 0) + if (Kernel32B.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), + connInfo, (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL, + lastErrorState) == 0) throwLastError(lastErrorState, "Internal error (cannot get device descriptor)"); var descriptorSegment = USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(connInfo); @@ -353,13 +355,14 @@ private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, // create descriptor requests var descriptorRequest = arena.allocate(size); USBHelper.USB_DESCRIPTOR_REQUEST_ConnectionIndex.set(descriptorRequest, usbPortNumber); - var setupPacket = new SetupPacket(descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_SetupPacket$Offset, - SetupPacket.LAYOUT.byteSize())); + var setupPacket = + new SetupPacket(descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_SetupPacket$Offset, + SetupPacket.LAYOUT.byteSize())); setupPacket.setRequestType(0x80); // device-to-host / type standard / recipient device setupPacket.setRequest(USBHelper.USB_REQUEST_GET_DESCRIPTOR); setupPacket.setValue((descriptorType << 8) | index); setupPacket.setIndex(languageID); - setupPacket.setLength(size - (int)USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset); + setupPacket.setLength(size - (int) USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset); // execute request var effectiveSizeHolder = arena.allocate(JAVA_INT); @@ -373,8 +376,8 @@ private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, if (descriptorType != CONFIGURATION_DESCRIPTOR_TYPE) { expectedSize = 255 & descriptorRequest.get(JAVA_BYTE, USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset); } else { - var configDesc = new ConfigurationDescriptor(descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, - ConfigurationDescriptor.LAYOUT.byteSize())); + var configDesc = + new ConfigurationDescriptor(descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, ConfigurationDescriptor.LAYOUT.byteSize())); expectedSize = configDesc.totalLength(); } @@ -396,11 +399,12 @@ private String getStringDescriptor(MemorySegment hubHandle, int usbPortNumber, i return null; try (var arena = Arena.openConfined()) { - var stringDesc = new StringDescriptor(getDescriptor(hubHandle, usbPortNumber, STRING_DESCRIPTOR_TYPE, index, - DEFAULT_LANGUAGE, arena)); + var stringDesc = new StringDescriptor(getDescriptor(hubHandle, usbPortNumber, STRING_DESCRIPTOR_TYPE, + index, DEFAULT_LANGUAGE, arena)); return stringDesc.string(); } catch (USBException e) { - System.err.printf("Info: [JavaDoesUSB] failed to retrieve string descriptor %d (%s) - ignoring%n", index, e.getMessage()); + System.err.printf("Info: [JavaDoesUSB] failed to retrieve string descriptor %d (%s) - ignoring%n", index, + e.getMessage()); return null; } } @@ -413,8 +417,8 @@ private long handleWindowMessage(MemorySegment hWnd, int uMsg, long wParam, long if (DEV_BROADCAST_HDR.dbch_devicetype$get(data) == User32.DBT_DEVTYP_DEVICEINTERFACE()) { // get device path - var nameSlice = MemorySegment.ofAddress( - DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address(), 500); + var nameSlice = + MemorySegment.ofAddress(DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address(), 500); var devicePath = Win.createStringFromSegment(nameSlice); if (wParam == User32.DBT_DEVICEARRIVAL()) onDeviceConnected(devicePath); @@ -444,16 +448,15 @@ private void onDeviceConnected(String devicePath) { var devIntfData = arena.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); var devicePathSegment = Win.createSegmentFromString(devicePath, arena); - if (SetupAPI2.SetupDiOpenDeviceInterfaceW(devInfoSet, devicePathSegment, 0, - devIntfData, lastErrorState) == 0) + if (SetupAPI2.SetupDiOpenDeviceInterfaceW(devInfoSet, devicePathSegment, 0, devIntfData, lastErrorState) == 0) throwLastError(lastErrorState, "Internal error (SetupDiOpenDeviceInterfaceW)"); cleanup.add(() -> SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSet, devIntfData)); var devInfoData = arena.allocate(SP_DEVINFO_DATA.$LAYOUT()); SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) devInfoData.byteSize()); - if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSet, devIntfData, NULL, 0, - NULL, devInfoData, lastErrorState) == 0) { + if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSet, devIntfData, NULL, 0, NULL, devInfoData, + lastErrorState) == 0) { int err = Win.getLastError(lastErrorState); if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) throwException(err, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); @@ -504,7 +507,8 @@ protected int findDeviceIndex(List deviceList, Object deviceId) { return -1; } - private static final Pattern MULTIPLE_INTERFACE_ID = Pattern.compile("USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); + private static final Pattern MULTIPLE_INTERFACE_ID = Pattern.compile("USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4" + + "}&MI_([0-9A-Fa-f]{2})"); private static int extractInterfaceNumber(List hardwareIds) { // Also see https://docs.microsoft.com/en-us/windows-hardware/drivers/install/standard-usb-identifiers#multiple-interface-usb-devices @@ -540,8 +544,8 @@ private void asyncCompletionTask() { overlappedHolder.set(ADDRESS, 0, MemorySegment.NULL); completionKeyHolder.set(JAVA_LONG, 0, 0); - int res = Kernel32B.GetQueuedCompletionStatus(asyncIoCompletionPort, numBytesHolder, completionKeyHolder, - overlappedHolder, Kernel32.INFINITE(), lastErrorState); + int res = Kernel32B.GetQueuedCompletionStatus(asyncIoCompletionPort, numBytesHolder, + completionKeyHolder, overlappedHolder, Kernel32.INFINITE(), lastErrorState); var overlapped = overlappedHolder.get(ADDRESS, 0); if (res == 0 && overlapped == MemorySegment.NULL) @@ -563,6 +567,7 @@ private void asyncCompletionTask() { /** * Add a Windows handle (of a USB device) to the completion port + * * @param handle Windows handle * @param device USB device */ @@ -600,8 +605,9 @@ synchronized void addToCompletionPort(MemorySegment handle, WindowsUSBDevice dev /** * Removes a handle from the dispatching. *

- * The handle is removed from the completion port by closing the device. + * The handle is removed from the completion port by closing the device. *

+ * * @param handle Windows device handle */ synchronized void removeFromCompletionPort(MemorySegment handle) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java index 32018aa9..ab1026d3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java @@ -27,7 +27,8 @@ public class WindowsUSBException extends USBException { *

* The message for the Windows error code is looked up and appended to the message. *

- * @param message exception message + * + * @param message exception message * @param errorCode Windows error code (usually returned from {@code GetLastError()}) */ public WindowsUSBException(String message, int errorCode) { @@ -39,9 +40,10 @@ public WindowsUSBException(String message, int errorCode) { *

* The message for the Windows error code is looked up and appended to the message. *

+ * * @param errorCode Windows error code (usually returned from {@code GetLastError()}) - * @param message exception message format ({@link String#format(String, Object...)} style) - * @param args arguments for exception message + * @param message exception message format ({@link String#format(String, Object...)} style) + * @param args arguments for exception message */ static void throwException(int errorCode, String message, Object... args) { var formattedMessage = String.format(message, args); @@ -54,8 +56,9 @@ static void throwException(int errorCode, String message, Object... args) { /** * Throws a USB exception. + * * @param message exception message format ({@link String#format(String, Object...)} style) - * @param args arguments for exception message + * @param args arguments for exception message */ static void throwException(String message, Object... args) { throw new USBException(String.format(message, args)); @@ -69,8 +72,8 @@ static void throwException(String message, Object... args) { *

* * @param lastErrorState call capture state containing last error code - * @param message exception message format ({@link String#format(String, Object...)} style) - * @param args arguments for exception message + * @param message exception message format ({@link String#format(String, Object...)} style) + * @param args arguments for exception message */ static void throwLastError(MemorySegment lastErrorState, String message, Object... args) { throwException(Win.getLastError(lastErrorState), message, args); @@ -79,9 +82,8 @@ static void throwLastError(MemorySegment lastErrorState, String message, Object. static String getErrorMessage(int errorCode) { try (var arena = Arena.openConfined()) { var messagePointerHolder = arena.allocate(ADDRESS); - int res = Kernel32.FormatMessageW(Kernel32.FORMAT_MESSAGE_ALLOCATE_BUFFER() - | Kernel32.FORMAT_MESSAGE_FROM_SYSTEM() | Kernel32.FORMAT_MESSAGE_IGNORE_INSERTS(), - NULL, errorCode, 0, messagePointerHolder, 0, NULL); + int res = + Kernel32.FormatMessageW(Kernel32.FORMAT_MESSAGE_ALLOCATE_BUFFER() | Kernel32.FORMAT_MESSAGE_FROM_SYSTEM() | Kernel32.FORMAT_MESSAGE_IGNORE_INSERTS(), NULL, errorCode, 0, messagePointerHolder, 0, NULL); if (res == 0) return "unspecified error"; var messagePointer = messagePointerHolder.get(ForeignMemory.UNBOUNDED_ADDRESS, 0); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java index 24b02a99..ed18a405 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java @@ -32,78 +32,68 @@ public class Kernel32B { private static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup(); - private static final FunctionDescriptor CreateFileW$FUNC = - FunctionDescriptor.of(ADDRESS, ADDRESS, JAVA_INT, JAVA_INT, ADDRESS, JAVA_INT, JAVA_INT, ADDRESS); + private static final FunctionDescriptor CreateFileW$FUNC = FunctionDescriptor.of(ADDRESS, ADDRESS, JAVA_INT, + JAVA_INT, ADDRESS, JAVA_INT, JAVA_INT, ADDRESS); - private static final MethodHandle CreateFileW$MH = LINKER.downcallHandle( - LOOKUP.find("CreateFileW").get(), - CreateFileW$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle CreateFileW$MH = LINKER.downcallHandle(LOOKUP.find("CreateFileW").get(), + CreateFileW$FUNC, Win.LAST_ERROR_STATE); public static MemorySegment CreateFileW(MemorySegment lpFileName, int dwDesiredAccess, int dwShareMode, MemorySegment lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, MemorySegment hTemplateFile, MemorySegment lastErrorState) { try { - return (MemorySegment)CreateFileW$MH.invokeExact(lastErrorState, lpFileName, dwDesiredAccess, dwShareMode, - lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); + return (MemorySegment) CreateFileW$MH.invokeExact(lastErrorState, lpFileName, dwDesiredAccess, + dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor DeviceIoControl$FUNC = - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT, ADDRESS, JAVA_INT, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); + private static final FunctionDescriptor DeviceIoControl$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT, + ADDRESS, JAVA_INT, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); - private static final MethodHandle DeviceIoControl$MH = LINKER.downcallHandle( - LOOKUP.find("DeviceIoControl").get(), - DeviceIoControl$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle DeviceIoControl$MH = LINKER.downcallHandle(LOOKUP.find("DeviceIoControl").get() + , DeviceIoControl$FUNC, Win.LAST_ERROR_STATE); public static int DeviceIoControl(MemorySegment hDevice, int dwIoControlCode, MemorySegment lpInBuffer, int nInBufferSize, MemorySegment lpOutBuffer, int nOutBufferSize, - MemorySegment lpBytesReturned, MemorySegment lpOverlapped, MemorySegment lastErrorState) { + MemorySegment lpBytesReturned, MemorySegment lpOverlapped, + MemorySegment lastErrorState) { try { - return (int)DeviceIoControl$MH.invokeExact(lastErrorState, hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); + return (int) DeviceIoControl$MH.invokeExact(lastErrorState, hDevice, dwIoControlCode, lpInBuffer, + nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor GetQueuedCompletionStatus$FUNC = - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS, JAVA_INT); + private static final FunctionDescriptor GetQueuedCompletionStatus$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, + ADDRESS, ADDRESS, ADDRESS, JAVA_INT); - private static final MethodHandle GetQueuedCompletionStatus$MH = LINKER.downcallHandle( - LOOKUP.find("GetQueuedCompletionStatus").get(), - GetQueuedCompletionStatus$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle GetQueuedCompletionStatus$MH = LINKER.downcallHandle(LOOKUP.find( + "GetQueuedCompletionStatus").get(), GetQueuedCompletionStatus$FUNC, Win.LAST_ERROR_STATE); public static int GetQueuedCompletionStatus(MemorySegment CompletionPort, - MemorySegment lpNumberOfBytesTransferred, - MemorySegment lpCompletionKey, MemorySegment lpOverlapped, - int dwMilliseconds, MemorySegment lastErrorState) { + MemorySegment lpNumberOfBytesTransferred, + MemorySegment lpCompletionKey, MemorySegment lpOverlapped, + int dwMilliseconds, MemorySegment lastErrorState) { try { - return (int)GetQueuedCompletionStatus$MH.invokeExact(lastErrorState, CompletionPort, + return (int) GetQueuedCompletionStatus$MH.invokeExact(lastErrorState, CompletionPort, lpNumberOfBytesTransferred, lpCompletionKey, lpOverlapped, dwMilliseconds); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor CreateIoCompletionPort$FUNC = - FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, JAVA_LONG, JAVA_INT); + private static final FunctionDescriptor CreateIoCompletionPort$FUNC = FunctionDescriptor.of(ADDRESS, ADDRESS, + ADDRESS, JAVA_LONG, JAVA_INT); - private static final MethodHandle CreateIoCompletionPort$MH = LINKER.downcallHandle( - LOOKUP.find("CreateIoCompletionPort").get(), - CreateIoCompletionPort$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle CreateIoCompletionPort$MH = LINKER.downcallHandle(LOOKUP.find( + "CreateIoCompletionPort").get(), CreateIoCompletionPort$FUNC, Win.LAST_ERROR_STATE); - public static MemorySegment CreateIoCompletionPort(MemorySegment FileHandle, MemorySegment ExistingCompletionPort, - long CompletionKey, int NumberOfConcurrentThreads, MemorySegment lastErrorState) { + public static MemorySegment CreateIoCompletionPort(MemorySegment FileHandle, MemorySegment ExistingCompletionPort + , long CompletionKey, int NumberOfConcurrentThreads, MemorySegment lastErrorState) { try { return (MemorySegment) CreateIoCompletionPort$MH.invokeExact(lastErrorState, FileHandle, ExistingCompletionPort, CompletionKey, NumberOfConcurrentThreads); @@ -112,14 +102,10 @@ public static MemorySegment CreateIoCompletionPort(MemorySegment FileHandle, Mem } } - private static final FunctionDescriptor CancelIoEx$FUNC = - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS); + private static final FunctionDescriptor CancelIoEx$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS); - private static final MethodHandle CancelIoEx$MH = LINKER.downcallHandle( - LOOKUP.find("CancelIoEx").get(), - CancelIoEx$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle CancelIoEx$MH = LINKER.downcallHandle(LOOKUP.find("CancelIoEx").get(), + CancelIoEx$FUNC, Win.LAST_ERROR_STATE); public static int CancelIoEx(MemorySegment hFile, MemorySegment lpOverlapped, MemorySegment lastErrorState) { try { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java index b4ba3b84..ef36ad7f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java @@ -33,174 +33,153 @@ public class SetupAPI2 { private static final Linker LINKER = Linker.nativeLinker(); private static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup(); - private static final FunctionDescriptor SetupDiGetDevicePropertyW$FUNC = - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS, JAVA_INT); + private static final FunctionDescriptor SetupDiGetDevicePropertyW$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, + ADDRESS, ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS, JAVA_INT); - private static final MethodHandle SetupDiGetDevicePropertyW$MH = LINKER.downcallHandle( - LOOKUP.find("SetupDiGetDevicePropertyW").get(), - SetupDiGetDevicePropertyW$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle SetupDiGetDevicePropertyW$MH = LINKER.downcallHandle(LOOKUP.find( + "SetupDiGetDevicePropertyW").get(), SetupDiGetDevicePropertyW$FUNC, Win.LAST_ERROR_STATE); public static int SetupDiGetDevicePropertyW(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, MemorySegment PropertyKey, MemorySegment PropertyType, MemorySegment PropertyBuffer, int PropertyBufferSize, - MemorySegment RequiredSize, int Flags, - MemorySegment lastErrorState) { + MemorySegment RequiredSize, int Flags, MemorySegment lastErrorState) { try { - return (int)SetupDiGetDevicePropertyW$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, + return (int) SetupDiGetDevicePropertyW$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, PropertyKey, PropertyType, PropertyBuffer, PropertyBufferSize, RequiredSize, Flags); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor SetupDiEnumDeviceInfo$FUNC = - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT, ADDRESS); + private static final FunctionDescriptor SetupDiEnumDeviceInfo$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, + JAVA_INT, ADDRESS); - private static final MethodHandle SetupDiEnumDeviceInfo$MH = LINKER.downcallHandle( - LOOKUP.find("SetupDiEnumDeviceInfo").get(), - SetupDiEnumDeviceInfo$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle SetupDiEnumDeviceInfo$MH = LINKER.downcallHandle(LOOKUP.find( + "SetupDiEnumDeviceInfo").get(), SetupDiEnumDeviceInfo$FUNC, Win.LAST_ERROR_STATE); - public static int SetupDiEnumDeviceInfo(MemorySegment DeviceInfoSet, int MemberIndex, MemorySegment DeviceInfoData, - MemorySegment lastErrorState) { + public static int SetupDiEnumDeviceInfo(MemorySegment DeviceInfoSet, int MemberIndex, + MemorySegment DeviceInfoData, MemorySegment lastErrorState) { try { - return (int)SetupDiEnumDeviceInfo$MH.invokeExact(lastErrorState, DeviceInfoSet, MemberIndex, DeviceInfoData); + return (int) SetupDiEnumDeviceInfo$MH.invokeExact(lastErrorState, DeviceInfoSet, MemberIndex, + DeviceInfoData); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor SetupDiOpenDevRegKey$FUNC = - FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, JAVA_INT, JAVA_INT, JAVA_INT, JAVA_INT); + private static final FunctionDescriptor SetupDiOpenDevRegKey$FUNC = FunctionDescriptor.of(ADDRESS, ADDRESS, + ADDRESS, JAVA_INT, JAVA_INT, JAVA_INT, JAVA_INT); - private static final MethodHandle SetupDiOpenDevRegKey$MH = LINKER.downcallHandle( - LOOKUP.find("SetupDiOpenDevRegKey").get(), - SetupDiOpenDevRegKey$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle SetupDiOpenDevRegKey$MH = LINKER.downcallHandle(LOOKUP.find( + "SetupDiOpenDevRegKey").get(), SetupDiOpenDevRegKey$FUNC, Win.LAST_ERROR_STATE); public static MemorySegment SetupDiOpenDevRegKey(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, int Scope, int HwProfile, int KeyType, int samDesired, MemorySegment lastErrorState) { try { - return (MemorySegment)SetupDiOpenDevRegKey$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, Scope, HwProfile, KeyType, samDesired); + return (MemorySegment) SetupDiOpenDevRegKey$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, + Scope, HwProfile, KeyType, samDesired); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor SetupDiGetClassDevsW$FUNC = - FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, ADDRESS, JAVA_INT); + private static final FunctionDescriptor SetupDiGetClassDevsW$FUNC = FunctionDescriptor.of(ADDRESS, ADDRESS, + ADDRESS, ADDRESS, JAVA_INT); - private static final MethodHandle SetupDiGetClassDevsW$MH = LINKER.downcallHandle( - LOOKUP.find("SetupDiGetClassDevsW").get(), - SetupDiGetClassDevsW$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle SetupDiGetClassDevsW$MH = LINKER.downcallHandle(LOOKUP.find( + "SetupDiGetClassDevsW").get(), SetupDiGetClassDevsW$FUNC, Win.LAST_ERROR_STATE); public static MemorySegment SetupDiGetClassDevsW(MemorySegment ClassGuid, MemorySegment Enumerator, - MemorySegment hwndParent, int Flags, MemorySegment lastErrorState) { + MemorySegment hwndParent, int Flags, + MemorySegment lastErrorState) { try { - return (MemorySegment)SetupDiGetClassDevsW$MH.invokeExact(lastErrorState, ClassGuid, Enumerator, hwndParent, Flags); + return (MemorySegment) SetupDiGetClassDevsW$MH.invokeExact(lastErrorState, ClassGuid, Enumerator, + hwndParent, Flags); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor SetupDiEnumDeviceInterfaces$FUNC = - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS); + private static final FunctionDescriptor SetupDiEnumDeviceInterfaces$FUNC = FunctionDescriptor.of(JAVA_INT, + ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS); - private static final MethodHandle SetupDiEnumDeviceInterfaces$MH = LINKER.downcallHandle( - LOOKUP.find("SetupDiEnumDeviceInterfaces").get(), - SetupDiEnumDeviceInterfaces$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle SetupDiEnumDeviceInterfaces$MH = LINKER.downcallHandle(LOOKUP.find( + "SetupDiEnumDeviceInterfaces").get(), SetupDiEnumDeviceInterfaces$FUNC, Win.LAST_ERROR_STATE); public static int SetupDiEnumDeviceInterfaces(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, MemorySegment InterfaceClassGuid, int MemberIndex, MemorySegment DeviceInterfaceData, MemorySegment lastErrorState) { try { - return (int)SetupDiEnumDeviceInterfaces$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, + return (int) SetupDiEnumDeviceInterfaces$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, InterfaceClassGuid, MemberIndex, DeviceInterfaceData); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor SetupDiGetDeviceInterfaceDetailW$FUNC = - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); + private static final FunctionDescriptor SetupDiGetDeviceInterfaceDetailW$FUNC = FunctionDescriptor.of(JAVA_INT, + ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); - private static final MethodHandle SetupDiGetDeviceInterfaceDetailW$MH = LINKER.downcallHandle( - LOOKUP.find("SetupDiGetDeviceInterfaceDetailW").get(), - SetupDiGetDeviceInterfaceDetailW$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle SetupDiGetDeviceInterfaceDetailW$MH = LINKER.downcallHandle(LOOKUP.find( + "SetupDiGetDeviceInterfaceDetailW").get(), SetupDiGetDeviceInterfaceDetailW$FUNC, Win.LAST_ERROR_STATE); - public static int SetupDiGetDeviceInterfaceDetailW(MemorySegment DeviceInfoSet, MemorySegment DeviceInterfaceData, - MemorySegment DeviceInterfaceDetailData, int DeviceInterfaceDetailDataSize, - MemorySegment RequiredSize, MemorySegment DeviceInfoData, - MemorySegment lastErrorState) { + public static int SetupDiGetDeviceInterfaceDetailW(MemorySegment DeviceInfoSet, MemorySegment DeviceInterfaceData + , MemorySegment DeviceInterfaceDetailData, int DeviceInterfaceDetailDataSize, MemorySegment RequiredSize, + MemorySegment DeviceInfoData, MemorySegment lastErrorState) { try { - return (int)SetupDiGetDeviceInterfaceDetailW$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInterfaceData, - DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData); + return (int) SetupDiGetDeviceInterfaceDetailW$MH.invokeExact(lastErrorState, DeviceInfoSet, + DeviceInterfaceData, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize, RequiredSize, + DeviceInfoData); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor SetupDiCreateDeviceInfoList$FUNC = - FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS); + private static final FunctionDescriptor SetupDiCreateDeviceInfoList$FUNC = FunctionDescriptor.of(ADDRESS, ADDRESS + , ADDRESS); - private static final MethodHandle SetupDiCreateDeviceInfoList$MH = LINKER.downcallHandle( - LOOKUP.find("SetupDiCreateDeviceInfoList").get(), - SetupDiCreateDeviceInfoList$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle SetupDiCreateDeviceInfoList$MH = LINKER.downcallHandle(LOOKUP.find( + "SetupDiCreateDeviceInfoList").get(), SetupDiCreateDeviceInfoList$FUNC, Win.LAST_ERROR_STATE); public static MemorySegment SetupDiCreateDeviceInfoList(MemorySegment ClassGuid, MemorySegment hwndParent, MemorySegment lastErrorState) { try { - return (MemorySegment)SetupDiCreateDeviceInfoList$MH.invokeExact(lastErrorState, ClassGuid, hwndParent); + return (MemorySegment) SetupDiCreateDeviceInfoList$MH.invokeExact(lastErrorState, ClassGuid, hwndParent); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor SetupDiOpenDeviceInfoW$FUNC = - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS ); + private static final FunctionDescriptor SetupDiOpenDeviceInfoW$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, + ADDRESS, ADDRESS, JAVA_INT, ADDRESS); - private static final MethodHandle SetupDiOpenDeviceInfoW$MH = LINKER.downcallHandle( - LOOKUP.find("SetupDiOpenDeviceInfoW").get(), - SetupDiOpenDeviceInfoW$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle SetupDiOpenDeviceInfoW$MH = LINKER.downcallHandle(LOOKUP.find( + "SetupDiOpenDeviceInfoW").get(), SetupDiOpenDeviceInfoW$FUNC, Win.LAST_ERROR_STATE); public static int SetupDiOpenDeviceInfoW(MemorySegment DeviceInfoSet, MemorySegment DeviceInstanceId, MemorySegment hwndParent, int OpenFlags, MemorySegment DeviceInfoData, MemorySegment lastErrorState) { try { - return (int)SetupDiOpenDeviceInfoW$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData); + return (int) SetupDiOpenDeviceInfoW$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInstanceId, + hwndParent, OpenFlags, DeviceInfoData); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor SetupDiOpenDeviceInterfaceW$FUNC = - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, JAVA_INT, ADDRESS); + private static final FunctionDescriptor SetupDiOpenDeviceInterfaceW$FUNC = FunctionDescriptor.of(JAVA_INT, + ADDRESS, ADDRESS, JAVA_INT, ADDRESS); - private static final MethodHandle SetupDiOpenDeviceInterfaceW$MH = LINKER.downcallHandle( - LOOKUP.find("SetupDiOpenDeviceInterfaceW").get(), - SetupDiOpenDeviceInterfaceW$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle SetupDiOpenDeviceInterfaceW$MH = LINKER.downcallHandle(LOOKUP.find( + "SetupDiOpenDeviceInterfaceW").get(), SetupDiOpenDeviceInterfaceW$FUNC, Win.LAST_ERROR_STATE); - public static int SetupDiOpenDeviceInterfaceW(MemorySegment DeviceInfoSet, MemorySegment DevicePath, int OpenFlags, - MemorySegment DeviceInterfaceData, MemorySegment lastErrorState) { + public static int SetupDiOpenDeviceInterfaceW(MemorySegment DeviceInfoSet, MemorySegment DevicePath, + int OpenFlags, MemorySegment DeviceInterfaceData, + MemorySegment lastErrorState) { try { - return (int)SetupDiOpenDeviceInterfaceW$MH.invokeExact(lastErrorState, DeviceInfoSet, DevicePath, OpenFlags, DeviceInterfaceData); + return (int) SetupDiOpenDeviceInterfaceW$MH.invokeExact(lastErrorState, DeviceInfoSet, DevicePath, + OpenFlags, DeviceInterfaceData); } catch (Throwable ex) { throw new RuntimeException(ex); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java index 89ecf892..12cace91 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java @@ -34,73 +34,63 @@ public class User32B { private static final FunctionDescriptor RegisterClassExW$FUNC = FunctionDescriptor.of(JAVA_SHORT, ADDRESS); - private static final MethodHandle RegisterClassExW$MH = LINKER.downcallHandle( - LOOKUP.find("RegisterClassExW").get(), - RegisterClassExW$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle RegisterClassExW$MH = + LINKER.downcallHandle(LOOKUP.find("RegisterClassExW").get(), RegisterClassExW$FUNC, Win.LAST_ERROR_STATE); public static short RegisterClassExW(MemorySegment unnamedParam1, MemorySegment lastErrorState) { try { - return (short)RegisterClassExW$MH.invokeExact(lastErrorState, unnamedParam1); + return (short) RegisterClassExW$MH.invokeExact(lastErrorState, unnamedParam1); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor CreateWindowExW$FUNC = - FunctionDescriptor.of(ADDRESS, JAVA_INT, ADDRESS, ADDRESS, JAVA_INT, JAVA_INT, JAVA_INT, JAVA_INT, - JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS); + private static final FunctionDescriptor CreateWindowExW$FUNC = FunctionDescriptor.of(ADDRESS, JAVA_INT, ADDRESS, + ADDRESS, JAVA_INT, JAVA_INT, JAVA_INT, JAVA_INT, JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS); - private static final MethodHandle CreateWindowExW$MH = LINKER.downcallHandle( - LOOKUP.find("CreateWindowExW").get(), - CreateWindowExW$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle CreateWindowExW$MH = LINKER.downcallHandle(LOOKUP.find("CreateWindowExW").get() + , CreateWindowExW$FUNC, Win.LAST_ERROR_STATE); public static MemorySegment CreateWindowExW(int dwExStyle, MemorySegment lpClassName, MemorySegment lpWindowName, int dwStyle, int X, int Y, int nWidth, int nHeight, - MemorySegment hWndParent, MemorySegment hMenu, MemorySegment hInstance, - MemorySegment lpParam, MemorySegment lastErrorState) { + MemorySegment hWndParent, MemorySegment hMenu, + MemorySegment hInstance, MemorySegment lpParam, + MemorySegment lastErrorState) { try { - return (MemorySegment)CreateWindowExW$MH.invokeExact(lastErrorState, dwExStyle, lpClassName, lpWindowName, - dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + return (MemorySegment) CreateWindowExW$MH.invokeExact(lastErrorState, dwExStyle, lpClassName, + lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor RegisterDeviceNotificationW$FUNC = - FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, JAVA_INT); + private static final FunctionDescriptor RegisterDeviceNotificationW$FUNC = FunctionDescriptor.of(ADDRESS, ADDRESS + , ADDRESS, JAVA_INT); - private static final MethodHandle RegisterDeviceNotificationW$MH = LINKER.downcallHandle( - LOOKUP.find("RegisterDeviceNotificationW").get(), - RegisterDeviceNotificationW$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle RegisterDeviceNotificationW$MH = LINKER.downcallHandle(LOOKUP.find( + "RegisterDeviceNotificationW").get(), RegisterDeviceNotificationW$FUNC, Win.LAST_ERROR_STATE); - public static MemorySegment RegisterDeviceNotificationW(MemorySegment hRecipient, MemorySegment NotificationFilter, - int Flags, MemorySegment lastErrorState) { + public static MemorySegment RegisterDeviceNotificationW(MemorySegment hRecipient, + MemorySegment NotificationFilter, int Flags, + MemorySegment lastErrorState) { try { - return (MemorySegment)RegisterDeviceNotificationW$MH.invokeExact(lastErrorState, hRecipient, NotificationFilter, Flags); + return (MemorySegment) RegisterDeviceNotificationW$MH.invokeExact(lastErrorState, hRecipient, + NotificationFilter, Flags); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor GetMessageW$FUNC = - FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, JAVA_INT, JAVA_INT); + private static final FunctionDescriptor GetMessageW$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, + JAVA_INT, JAVA_INT); - private static final MethodHandle GetMessageW$MH = LINKER.downcallHandle( - LOOKUP.find("GetMessageW").get(), - GetMessageW$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle GetMessageW$MH = LINKER.downcallHandle(LOOKUP.find("GetMessageW").get(), + GetMessageW$FUNC, Win.LAST_ERROR_STATE); public static int GetMessageW(MemorySegment lpMsg, MemorySegment hWnd, int wMsgFilterMin, int wMsgFilterMax, MemorySegment lastErrorState) { try { - return (int)GetMessageW$MH.invokeExact(lastErrorState, lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); + return (int) GetMessageW$MH.invokeExact(lastErrorState, lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); } catch (Throwable ex) { throw new RuntimeException(ex); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java index 834dd016..805b94cc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java @@ -35,106 +35,96 @@ public class WinUSB2 { private static final FunctionDescriptor WinUsb_Initialize$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS); - private static final MethodHandle WinUsb_Initialize$MH = LINKER.downcallHandle( - LOOKUP.find("WinUsb_Initialize").get(), - WinUsb_Initialize$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle WinUsb_Initialize$MH = + LINKER.downcallHandle(LOOKUP.find("WinUsb_Initialize").get(), WinUsb_Initialize$FUNC, Win.LAST_ERROR_STATE); - public static int WinUsb_Initialize(MemorySegment DeviceHandle, MemorySegment InterfaceHandle, MemorySegment lastErrorState) { + public static int WinUsb_Initialize(MemorySegment DeviceHandle, MemorySegment InterfaceHandle, + MemorySegment lastErrorState) { try { - return (int)WinUsb_Initialize$MH.invokeExact(lastErrorState, DeviceHandle, InterfaceHandle); + return (int) WinUsb_Initialize$MH.invokeExact(lastErrorState, DeviceHandle, InterfaceHandle); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor WinUsb_SetCurrentAlternateSetting$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE); + private static final FunctionDescriptor WinUsb_SetCurrentAlternateSetting$FUNC = FunctionDescriptor.of(JAVA_INT, + ADDRESS, JAVA_BYTE); - private static final MethodHandle WinUsb_SetCurrentAlternateSetting$MH = LINKER.downcallHandle( - LOOKUP.find("WinUsb_SetCurrentAlternateSetting").get(), - WinUsb_SetCurrentAlternateSetting$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle WinUsb_SetCurrentAlternateSetting$MH = LINKER.downcallHandle(LOOKUP.find( + "WinUsb_SetCurrentAlternateSetting").get(), WinUsb_SetCurrentAlternateSetting$FUNC, Win.LAST_ERROR_STATE); - public static int WinUsb_SetCurrentAlternateSetting(MemorySegment InterfaceHandle, byte SettingNumber, MemorySegment lastErrorState) { + public static int WinUsb_SetCurrentAlternateSetting(MemorySegment InterfaceHandle, byte SettingNumber, + MemorySegment lastErrorState) { try { - return (int)WinUsb_SetCurrentAlternateSetting$MH.invokeExact(lastErrorState, InterfaceHandle, SettingNumber); + return (int) WinUsb_SetCurrentAlternateSetting$MH.invokeExact(lastErrorState, InterfaceHandle, + SettingNumber); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor WinUsb_ControlTransfer$FUNC = - FunctionDescriptor.of(JAVA_INT, ADDRESS, SetupPacket.LAYOUT, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); + private static final FunctionDescriptor WinUsb_ControlTransfer$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, + SetupPacket.LAYOUT, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); - private static final MethodHandle WinUsb_ControlTransfer$MH = LINKER.downcallHandle( - LOOKUP.find("WinUsb_ControlTransfer").get(), - WinUsb_ControlTransfer$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle WinUsb_ControlTransfer$MH = LINKER.downcallHandle(LOOKUP.find( + "WinUsb_ControlTransfer").get(), WinUsb_ControlTransfer$FUNC, Win.LAST_ERROR_STATE); public static int WinUsb_ControlTransfer(MemorySegment InterfaceHandle, MemorySegment SetupPacket, MemorySegment Buffer, int BufferLength, MemorySegment LengthTransferred, MemorySegment Overlapped, MemorySegment lastErrorState) { try { - return (int)WinUsb_ControlTransfer$MH.invokeExact(lastErrorState, InterfaceHandle, SetupPacket, Buffer, BufferLength, LengthTransferred, Overlapped); + return (int) WinUsb_ControlTransfer$MH.invokeExact(lastErrorState, InterfaceHandle, SetupPacket, Buffer, + BufferLength, LengthTransferred, Overlapped); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor WinUsb_SetPipePolicy$FUNC = - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, JAVA_INT, JAVA_INT, ADDRESS); + private static final FunctionDescriptor WinUsb_SetPipePolicy$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, + JAVA_BYTE, JAVA_INT, JAVA_INT, ADDRESS); - private static final MethodHandle WinUsb_SetPipePolicy$MH = LINKER.downcallHandle( - LOOKUP.find("WinUsb_SetPipePolicy").get(), - WinUsb_SetPipePolicy$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle WinUsb_SetPipePolicy$MH = LINKER.downcallHandle(LOOKUP.find( + "WinUsb_SetPipePolicy").get(), WinUsb_SetPipePolicy$FUNC, Win.LAST_ERROR_STATE); - public static int WinUsb_SetPipePolicy(MemorySegment InterfaceHandle, byte PipeID, int PolicyType, int ValueLength, - MemorySegment Value, MemorySegment lastErrorState) { + public static int WinUsb_SetPipePolicy(MemorySegment InterfaceHandle, byte PipeID, int PolicyType, + int ValueLength, MemorySegment Value, MemorySegment lastErrorState) { try { - return (int)WinUsb_SetPipePolicy$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID, PolicyType, ValueLength, Value); + return (int) WinUsb_SetPipePolicy$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID, PolicyType, + ValueLength, Value); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor WinUsb_WritePipe$FUNC = - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); + private static final FunctionDescriptor WinUsb_WritePipe$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, + JAVA_BYTE, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); - private static final MethodHandle WinUsb_WritePipe$MH = LINKER.downcallHandle( - LOOKUP.find("WinUsb_WritePipe").get(), - WinUsb_WritePipe$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle WinUsb_WritePipe$MH = + LINKER.downcallHandle(LOOKUP.find("WinUsb_WritePipe").get(), WinUsb_WritePipe$FUNC, Win.LAST_ERROR_STATE); public static int WinUsb_WritePipe(MemorySegment InterfaceHandle, byte PipeID, MemorySegment Buffer, int BufferLength, MemorySegment LengthTransferred, MemorySegment Overlapped, MemorySegment lastErrorState) { try { - return (int)WinUsb_WritePipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID, Buffer, BufferLength, LengthTransferred, Overlapped); + return (int) WinUsb_WritePipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID, Buffer, + BufferLength, LengthTransferred, Overlapped); } catch (Throwable ex) { throw new RuntimeException(ex); } } - private static final FunctionDescriptor WinUsb_ReadPipe$FUNC = - FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); + private static final FunctionDescriptor WinUsb_ReadPipe$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE + , ADDRESS, JAVA_INT, ADDRESS, ADDRESS); - private static final MethodHandle WinUsb_ReadPipe$MH = LINKER.downcallHandle( - LOOKUP.find("WinUsb_ReadPipe").get(), - WinUsb_ReadPipe$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle WinUsb_ReadPipe$MH = LINKER.downcallHandle(LOOKUP.find("WinUsb_ReadPipe").get() + , WinUsb_ReadPipe$FUNC, Win.LAST_ERROR_STATE); public static int WinUsb_ReadPipe(MemorySegment InterfaceHandle, byte PipeID, MemorySegment Buffer, int BufferLength, MemorySegment LengthTransferred, MemorySegment Overlapped, MemorySegment lastErrorState) { try { - return (int)WinUsb_ReadPipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID, Buffer, BufferLength, LengthTransferred, Overlapped); + return (int) WinUsb_ReadPipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID, Buffer, BufferLength + , LengthTransferred, Overlapped); } catch (Throwable ex) { throw new RuntimeException(ex); } @@ -142,30 +132,25 @@ public static int WinUsb_ReadPipe(MemorySegment InterfaceHandle, byte PipeID, Me private static final FunctionDescriptor WinUsb_ResetPipe$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE); - private static final MethodHandle WinUsb_ResetPipe$MH = LINKER.downcallHandle( - LOOKUP.find("WinUsb_ResetPipe").get(), - WinUsb_ResetPipe$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle WinUsb_ResetPipe$MH = + LINKER.downcallHandle(LOOKUP.find("WinUsb_ResetPipe").get(), WinUsb_ResetPipe$FUNC, Win.LAST_ERROR_STATE); public static int WinUsb_ResetPipe(MemorySegment InterfaceHandle, byte PipeID, MemorySegment lastErrorState) { try { - return (int)WinUsb_ResetPipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID); + return (int) WinUsb_ResetPipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID); } catch (Throwable ex) { throw new RuntimeException(ex); } } + private static final FunctionDescriptor WinUsb_AbortPipe$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE); - private static final MethodHandle WinUsb_AbortPipe$MH = LINKER.downcallHandle( - LOOKUP.find("WinUsb_AbortPipe").get(), - WinUsb_ResetPipe$FUNC, - Win.LAST_ERROR_STATE - ); + private static final MethodHandle WinUsb_AbortPipe$MH = + LINKER.downcallHandle(LOOKUP.find("WinUsb_AbortPipe").get(), WinUsb_ResetPipe$FUNC, Win.LAST_ERROR_STATE); public static int WinUsb_AbortPipe(MemorySegment InterfaceHandle, byte PipeID, MemorySegment lastErrorState) { try { - return (int)WinUsb_AbortPipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID); + return (int) WinUsb_AbortPipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID); } catch (Throwable ex) { throw new RuntimeException(ex); } From 3ba8488256163239acaea934ed7e2753aa5e1ee0 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 24 Feb 2023 13:28:28 +0100 Subject: [PATCH 205/433] Refactoring of asynchronous IO processing --- .../usb/common/AsyncIOCompletion.java | 27 -- .../usb/common/EndpointInputStream.java | 137 ++++---- .../usb/common/EndpointOutputStream.java | 129 ++++---- .../net/codecrete/usb/common/Transfer.java | 39 +++ .../usb/common/TransferCompletion.java | 30 ++ .../codecrete/usb/common/USBDeviceImpl.java | 16 + .../usb/linux/LinuxEndpointInputStream.java | 13 +- .../usb/linux/LinuxEndpointOutputStream.java | 13 +- .../codecrete/usb/linux/LinuxTransfer.java | 22 ++ .../codecrete/usb/linux/LinuxUSBDevice.java | 26 +- .../usb/linux/LinuxUSBDeviceRegistry.java | 52 +-- .../codecrete/usb/macos/MacosAsyncTask.java | 194 ++++++++++++ .../usb/macos/MacosEndpointInputStream.java | 13 +- .../usb/macos/MacosEndpointOutputStream.java | 13 +- .../codecrete/usb/macos/MacosTransfer.java | 14 + .../codecrete/usb/macos/MacosUSBDevice.java | 299 +++++++----------- .../usb/macos/MacosUSBDeviceRegistry.java | 58 +--- .../usbstandard/ConfigurationDescriptor.java | 14 +- .../usb/usbstandard/DeviceDescriptor.java | 23 +- .../usb/usbstandard/EndpointDescriptor.java | 11 +- .../InterfaceAssociationDescriptor.java | 14 +- .../usb/usbstandard/InterfaceDescriptor.java | 15 +- .../usb/usbstandard/SetupPacket.java | 9 +- .../usb/usbstandard/StringDescriptor.java | 7 +- .../windows/WindowsEndpointInputStream.java | 13 +- .../windows/WindowsEndpointOutputStream.java | 13 +- .../usb/windows/WindowsTransfer.java | 16 + .../usb/windows/WindowsUSBDevice.java | 71 ++--- .../usb/windows/WindowsUSBDeviceRegistry.java | 112 ++++--- 29 files changed, 785 insertions(+), 628 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/AsyncIOCompletion.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/Transfer.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/TransferCompletion.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxTransfer.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/MacosTransfer.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsTransfer.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncIOCompletion.java b/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncIOCompletion.java deleted file mode 100644 index 2e90f3f0..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/AsyncIOCompletion.java +++ /dev/null @@ -1,27 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2023 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.common; - -/** - * Lambda function called when an asynchronous IO operation has completed. - */ -@FunctionalInterface -public interface AsyncIOCompletion { - - /** - * Called when the asynchronous IO has completed. - *

- * A result code of 0 indicates a successful operation. Other codes - * indicate a failure. The code is operating system specific. - *

- * - * @param result the native result code of the operation. - * @param size the size of the transferred data (in bytes) - */ - void completed(int result, int size); -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index 407db1b2..dfb3fa59 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -22,20 +22,20 @@ * Input stream for bulk endpoints – optimized for high throughput. * *

- * Multiple asynchronous transfer IN requests are submitted to achieve a good + * Multiple asynchronous transfer are submitted to achieve a good * degree of concurrency between the USB communication handled by the operating * system and the consuming application code. *

*

* For thread synchronization (between the background thread handling IO completion - * and the consuming application thread) a blocking queue is used. When an transfer IN - * requests completes, the background thread adds it to the queue. The consuming code + * and the consuming application thread) a blocking queue is used. When an transfer + * completes, the background thread adds it to the queue. The consuming code * waits for the next item in the queue. *

*/ public abstract class EndpointInputStream extends InputStream { - private static final int MAX_OUTSTANDING_REQUESTS = 8; + private static final int MAX_OUTSTANDING_TRANSFERS = 8; protected USBDeviceImpl device; protected final int endpointNumber; @@ -43,14 +43,14 @@ public abstract class EndpointInputStream extends InputStream { protected final Arena arena; // Size of buffers (multiple of packet size) protected final int bufferSize; - // Queue of completed requests - private final ArrayBlockingQueue completedRequestQueue; - // Number of outstanding requests (includes requests pending with the - // operating system and requests in the completed queue) - private int numOutstandingRequests; - // Request and buffer being currently read from - private TransferRequest currentRequest; - // Read offset within current request + // Queue of completed transfers + private final ArrayBlockingQueue completedTransferQueue; + // Number of outstanding transfers (includes transfers pending with the + // operating system and transfers in the completed queue) + private int numOutstandingTransfers; + // Transfer and associated buffer being currently read from + private Transfer currentTransfer; + // Read offset within current transfer buffer private int readOffset; /** @@ -64,28 +64,33 @@ protected EndpointInputStream(USBDeviceImpl device, int endpointNumber) { this.endpointNumber = endpointNumber; bufferSize = 4 * device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); - completedRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); + completedTransferQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_TRANSFERS); - // create all requests and submit all except one + // create all transfers, and submit them except one arena = Arena.openShared(); try { - for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { - final var request = new TransferRequest(); - request.buffer = arena.allocate(bufferSize, 8); - request.completionHandler = (result, size) -> onCompletion(request, result, size); + for (int i = 0; i < MAX_OUTSTANDING_TRANSFERS; i++) { + final var transfer = device.createTransfer(); + transfer.data = arena.allocate(bufferSize, 8); + transfer.dataSize = bufferSize; + transfer.completionHandler = this::onCompletion; if (i == 0) { - currentRequest = request; + currentTransfer = transfer; } else { - submitRequest(request); + submitTransfer(transfer); } } } catch (Throwable t) { - collectOutstandingRequests(); + collectOutstandingTransfers(); throw t; } } + private boolean isClosed() { + return device == null; + } + @SuppressWarnings("RedundantThrows") @Override public void close() throws IOException { @@ -95,24 +100,15 @@ public void close() throws IOException { // abort all transfers on endpoint try { device.abortTransfers(USBDirection.IN, endpointNumber); + } catch (USBException e) { // If aborting the transfer is not possible, the device has // likely been closed or unplugged. So all outstanding - // requests will terminate anyway. + // transfers will terminate anyway. } device = null; - collectOutstandingRequests(); - } - - private void collectOutstandingRequests() { - // wait until completion handlers have been called - while (numOutstandingRequests > 0) - waitForRequestCompletion(); - - completedRequestQueue.clear(); - currentRequest = null; - arena.close(); + collectOutstandingTransfers(); } @Override @@ -123,7 +119,7 @@ public int read() throws IOException { if (available() == 0) receiveMoreData(); - int b = currentRequest.buffer.get(JAVA_BYTE, readOffset) & 0xff; + int b = currentTransfer.data.get(JAVA_BYTE, readOffset) & 0xff; readOffset += 1; return b; } @@ -137,11 +133,11 @@ public int read(byte[] b, int off, int len) throws IOException { receiveMoreData(); // copy data to receiving buffer - int n = Math.min(len, currentRequest.resultSize - readOffset); - MemorySegment.copy(currentRequest.buffer, readOffset, MemorySegment.ofArray(b), off, n); + int n = Math.min(len, currentTransfer.resultSize - readOffset); + MemorySegment.copy(currentTransfer.data, readOffset, MemorySegment.ofArray(b), off, n); readOffset += n; - // TODO: poll for further completed requests if 'n' is less than 'len' + // TODO: poll for further completed transfers if 'n' is less than 'len' return n; } @@ -149,27 +145,26 @@ public int read(byte[] b, int off, int len) throws IOException { @SuppressWarnings("RedundantThrows") @Override public int available() throws IOException { - return currentRequest.resultSize - readOffset; - } - - private boolean isClosed() { - return device == null; + return currentTransfer.resultSize - readOffset; } private void receiveMoreData() throws IOException { try { // loop until non-ZLP has been received do { - submitRequest(currentRequest); + // the current transfer has no more data to process and + // can be submitted to read more data + submitTransfer(currentTransfer); - currentRequest = waitForRequestCompletion(); + currentTransfer = waitForCompletedTransfer(); readOffset = 0; // check for error - if (currentRequest.result != 0) - throwException(currentRequest.result, "error reading from USB endpoint"); + if (currentTransfer.resultCode != 0) + device.throwOSException(currentTransfer.resultCode, "error reading from endpoint %d", + endpointNumber); - } while (currentRequest.resultSize == 0); + } while (currentTransfer.resultSize <= 0); } catch (Throwable t) { close(); @@ -177,38 +172,36 @@ private void receiveMoreData() throws IOException { } } - void submitRequest(TransferRequest request) { - submitTransferIn(request.buffer, bufferSize, request.completionHandler); - numOutstandingRequests += 1; - } - - protected abstract void submitTransferIn(MemorySegment buffer, int bufferSize, AsyncIOCompletion completion); - - protected abstract void throwException(int errorCode, String message); - - void onCompletion(TransferRequest request, int result, int size) { - request.result = result; - request.resultSize = size; - completedRequestQueue.add(request); - } - - TransferRequest waitForRequestCompletion() { + private Transfer waitForCompletedTransfer() { while (true) { try { - TransferRequest request = completedRequestQueue.take(); - numOutstandingRequests -= 1; - return request; - + Transfer transfer = completedTransferQueue.take(); + numOutstandingTransfers -= 1; + return transfer; } catch (InterruptedException e) { // ignore and retry } } } - private static class TransferRequest { - MemorySegment buffer; - int result; - int resultSize; - AsyncIOCompletion completionHandler; + private void submitTransfer(Transfer transfer) { + submitTransferIn(transfer); + numOutstandingTransfers += 1; + } + + private void onCompletion(Transfer transfer) { + completedTransferQueue.add(transfer); } + + private void collectOutstandingTransfers() { + // wait until completion handlers have been called + while (numOutstandingTransfers > 0) + waitForCompletedTransfer(); + + completedTransferQueue.clear(); + currentTransfer = null; + arena.close(); + } + + protected abstract void submitTransferIn(Transfer transfer); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java index b9005ad2..cf234c91 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -22,22 +22,22 @@ * Output stream for bulk endpoints – optimized for high throughput. * *

- * Multiple asynchronous transfer OUT requests are submitted to achieve a good + * Multiple asynchronous transfers are submitted to achieve a good * degree of concurrency between the USB communication handled by the operating - * system and the producing application code. The number of requests is limited - * in order to retain the flow control and keep memory usage at a reasonable size. + * system and the producing application code. The number of concurrent transfers is limited + * in order to retain flow control and keep memory usage at a reasonable size. *

*

* For thread synchronization (between the background thread handling IO completion * and the producing application thread) a blocking queue is used. It is prefilled with - * requests ready to be used for a transfer. The background thread adds the completed - * requests back to this queue. The producing application thread waits until a request + * transfer instances ready to be used. The background thread adds the completed + * instances back to this queue. The producing application thread waits until a transfer instance * is available for use. *

*/ public abstract class EndpointOutputStream extends OutputStream { - private static final int MAX_OUTSTANDING_REQUESTS = 4; + private static final int MAX_OUTSTANDING_TRANSFERS = 4; protected USBDeviceImpl device; protected final int endpointNumber; @@ -46,12 +46,12 @@ public abstract class EndpointOutputStream extends OutputStream { private final int packetSize; // Size of buffers (multiple of packet size) private final int bufferSize; - // Blocking queue of available requests (to limit the number of submitted requests) - private final ArrayBlockingQueue availableRequestQueue; + // Blocking queue of available transfers (to limit the number of submitted transfers) + private final ArrayBlockingQueue availableTransferQueue; private boolean needsZlp; - private TransferRequest currentRequest; + private Transfer currentTransfer; private int writeOffset; - private int numOutstandingRequests; + private int numOutstandingTransfers; private boolean hasError; @@ -68,23 +68,27 @@ protected EndpointOutputStream(USBDeviceImpl device, int endpointNumber) { packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize(); bufferSize = packetSize; - availableRequestQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_REQUESTS); + availableTransferQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_TRANSFERS); arena = Arena.openShared(); - // prefill request queue - for (int i = 0; i < MAX_OUTSTANDING_REQUESTS; i++) { - final var request = new TransferRequest(); - request.buffer = arena.allocate(bufferSize, 8); - request.completionHandler = (result, size) -> onCompletion(request, result); + // prefill transfer queue + for (int i = 0; i < MAX_OUTSTANDING_TRANSFERS; i++) { + final var transfer = device.createTransfer(); + transfer.data = arena.allocate(bufferSize, 8); + transfer.completionHandler = this::onCompletion; if (i == 0) { - currentRequest = request; + currentTransfer = transfer; } else { - availableRequestQueue.add(request); + availableTransferQueue.add(transfer); } } } + private boolean isClosed() { + return device == null; + } + @Override public void close() throws IOException { if (isClosed()) @@ -93,11 +97,11 @@ public void close() throws IOException { if (!hasError) flush(); else - waitForOutstandingRequests(); + waitForOutstandingTransfers(); device = null; - availableRequestQueue.clear(); - currentRequest = null; + availableTransferQueue.clear(); + currentTransfer = null; arena.close(); } @@ -106,7 +110,7 @@ public void write(int b) throws IOException { if (isClosed()) throw new IOException("Bulk endpoint output stream has been closed"); - currentRequest.buffer.set(JAVA_BYTE, writeOffset, (byte) b); + currentTransfer.data.set(JAVA_BYTE, writeOffset, (byte) b); writeOffset += 1; if (writeOffset == bufferSize) submitTransfer(writeOffset); @@ -119,7 +123,7 @@ public void write(byte[] b, int off, int len) throws IOException { while (len > 0) { int chunkSize = Math.min(len, bufferSize - writeOffset); - MemorySegment.copy(b, off, currentRequest.buffer, JAVA_BYTE, writeOffset, chunkSize); + MemorySegment.copy(b, off, currentTransfer.data, JAVA_BYTE, writeOffset, chunkSize); writeOffset += chunkSize; off += chunkSize; len -= chunkSize; @@ -140,18 +144,14 @@ public void flush() throws IOException { if (needsZlp) submitTransfer(0); - waitForOutstandingRequests(); - } - - private boolean isClosed() { - return device == null; + waitForOutstandingTransfers(); } /** - * Submits a request for transfer and set a new request - * as the current one, possibly waiting until it is ready. + * Submits a transfer and set a new transfer instance + * as the current one, possibly waiting until one is ready. *

- * Throws an exception if the request to be reused has completed with an error on the + * Throws an exception if the transfer to be reused has completed with an error on the * previous operation. The exception is suppressed if {@code hasError} flag is set. *

* @@ -159,15 +159,16 @@ private boolean isClosed() { */ private void submitTransfer(int size) throws IOException { try { - submitTransferOut(currentRequest.buffer, size, currentRequest.completionHandler); + currentTransfer.dataSize = size; + submitTransferOut(currentTransfer); synchronized (this) { - numOutstandingRequests += 1; + numOutstandingTransfers += 1; } needsZlp = size == packetSize; writeOffset = 0; - currentRequest = waitForAvailableRequest(); + currentTransfer = waitForAvailableTransfer(); } catch (Throwable t) { hasError = true; @@ -177,55 +178,55 @@ private void submitTransfer(int size) throws IOException { } /** - * Wait until all outstanding requests have been completed. + * Wait until all outstanding transfers have been completed. *

- * Throws an exception if any of the requests has completed with an error. + * Throws an exception if any of the transfers has completed with an error. * The exception is suppressed if {@code hasError} flag is set. *

*/ - private void waitForOutstandingRequests() { + private void waitForOutstandingTransfers() { // Wait until all buffers have been transmitted by removing them from the // queue and reinserting them. - int numRequests; + int numTransfers; synchronized (this) { - numRequests = numOutstandingRequests + availableRequestQueue.size(); + numTransfers = numOutstandingTransfers + availableTransferQueue.size(); } - if (numRequests == 0) + if (numTransfers == 0) return; - var requests = new TransferRequest[numRequests]; - for (int i = 0; i < numRequests; i++) - requests[i] = waitForAvailableRequest(); + var transfers = new Transfer[numTransfers]; + for (int i = 0; i < numTransfers; i++) + transfers[i] = waitForAvailableTransfer(); - // reinsert the requests + // reinsert the transfer instances if (!hasError) - availableRequestQueue.addAll(Arrays.asList(requests)); + availableTransferQueue.addAll(Arrays.asList(transfers)); } /** - * Wait until one of the allocated requests is available for use. + * Wait until one of the allocated transfer instances is available for use. *

- * Throws an exception if the request to be reused has completed with an error on the + * Throws an exception if the transfer to be reused has completed with an error on the * previous operation. The exception is suppressed if {@code hasError} flag is set. *

* - * @return request ready for use + * @return transfer instance ready for use */ - private TransferRequest waitForAvailableRequest() { + private Transfer waitForAvailableTransfer() { while (true) { try { - TransferRequest request = availableRequestQueue.take(); + Transfer transfer = availableTransferQueue.take(); // check for error - int result = request.result; + int result = transfer.resultCode; if (result != 0 && !hasError) { - request.result = 0; - throwException(result, "error reading from USB endpoint"); + transfer.resultCode = 0; + device.throwOSException(result, "error writing to endpoint %d", endpointNumber); } - return request; + return transfer; } catch (InterruptedException e) { // ignore and retry @@ -236,22 +237,12 @@ private TransferRequest waitForAvailableRequest() { /** * Called by the asynchronous IO completion handler. * - * @param request the completed request - * @param result the request result code + * @param transfer the completed request */ - private synchronized void onCompletion(TransferRequest request, int result) { - request.result = result; - availableRequestQueue.add(request); - numOutstandingRequests -= 1; + private synchronized void onCompletion(Transfer transfer) { + availableTransferQueue.add(transfer); + numOutstandingTransfers -= 1; } - protected abstract void submitTransferOut(MemorySegment data, int dataSize, AsyncIOCompletion completion); - - protected abstract void throwException(int errorCode, String message); - - private static class TransferRequest { - MemorySegment buffer; - int result; - AsyncIOCompletion completionHandler; - } + protected abstract void submitTransferOut(Transfer request); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/Transfer.java b/java-does-usb/src/main/java/net/codecrete/usb/common/Transfer.java new file mode 100644 index 00000000..a12e158e --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/Transfer.java @@ -0,0 +1,39 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +import java.lang.foreign.MemorySegment; + +/** + * Asynchronous USB endpoint transfer. + */ +public class Transfer { + /** + * Buffer with data to transfer (in or out) + */ + public MemorySegment data; + /** + * Length of data to transfer (in bytes) + */ + public int dataSize; + /** + * Result code (operating system specific). + *

+ * 0 represents success, all other values represent an error. + *

+ */ + public int resultCode; + /** + * Length of transferred data (in bytes) + */ + public int resultSize; + /** + * Completion handler to call when the transfer is complete. + */ + public TransferCompletion completionHandler; +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/TransferCompletion.java b/java-does-usb/src/main/java/net/codecrete/usb/common/TransferCompletion.java new file mode 100644 index 00000000..578b33cf --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/TransferCompletion.java @@ -0,0 +1,30 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +/** + * Functional interface used to notify when an asynchronous USB transfer operation has completed. + */ +@FunctionalInterface +public interface TransferCompletion { + + /** + * Called when the asynchronous transfer has completed. + *

+ * When this function has been called, {@link Transfer#resultCode} and + * {@link Transfer#resultSize} have been filled in. + *

+ *

+ * Since there is a single background task calling all completion functions, + * this function should only execute little work and return quickly. + *

+ * + * @param transfer completed transfer request + */ + void completed(Transfer transfer); +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 38e4717b..f0dcd5a1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -307,6 +307,22 @@ public byte[] transferIn(int endpointNumber) { @Override public abstract byte[] transferIn(int endpointNumber, int timeout); + /** + * Create a transfer object suitable for this device. + * + * @return transfer object + */ + protected abstract Transfer createTransfer(); + + /** + * Throws an exception for the specified operating-specific error code. + * + * @param errorCode error code, operating specific + * @param message exception message format ({@link String#format(String, Object...)} style) + * @param args arguments for exception message + */ + protected abstract void throwOSException(int errorCode, String message, Object... args); + @Override public boolean equals(Object o) { if (this == o) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java index bba60a41..3f16f495 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java @@ -7,10 +7,8 @@ package net.codecrete.usb.linux; -import net.codecrete.usb.common.AsyncIOCompletion; import net.codecrete.usb.common.EndpointInputStream; - -import java.lang.foreign.MemorySegment; +import net.codecrete.usb.common.Transfer; public class LinuxEndpointInputStream extends EndpointInputStream { @@ -19,12 +17,7 @@ public class LinuxEndpointInputStream extends EndpointInputStream { } @Override - protected void submitTransferIn(MemorySegment buffer, int bufferSize, AsyncIOCompletion completion) { - ((LinuxUSBDevice) device).submitTransferIn(endpointNumber, buffer, bufferSize, completion); - } - - @Override - protected void throwException(int errorCode, String message) { - LinuxUSBException.throwException(errorCode, message); + protected void submitTransferIn(Transfer transfer) { + ((LinuxUSBDevice) device).submitTransferIn(endpointNumber, (LinuxTransfer) transfer); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java index 90b16992..be083067 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java @@ -7,10 +7,8 @@ package net.codecrete.usb.linux; -import net.codecrete.usb.common.AsyncIOCompletion; import net.codecrete.usb.common.EndpointOutputStream; - -import java.lang.foreign.MemorySegment; +import net.codecrete.usb.common.Transfer; public class LinuxEndpointOutputStream extends EndpointOutputStream { @@ -19,12 +17,7 @@ public class LinuxEndpointOutputStream extends EndpointOutputStream { } @Override - protected void submitTransferOut(MemorySegment data, int dataSize, AsyncIOCompletion completion) { - ((LinuxUSBDevice) device).submitTransferOut(endpointNumber, data, dataSize, completion); - } - - @Override - protected void throwException(int errorCode, String message) { - LinuxUSBException.throwException(errorCode, message); + protected void submitTransferOut(Transfer transfer) { + ((LinuxUSBDevice) device).submitTransferOut(endpointNumber, (LinuxTransfer) transfer); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxTransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxTransfer.java new file mode 100644 index 00000000..0be287af --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxTransfer.java @@ -0,0 +1,22 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.linux; + +import net.codecrete.usb.common.Transfer; +import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_urb; + +import java.lang.foreign.MemorySegment; + +public class LinuxTransfer extends Transfer { + /** + * USB request buffer. + * + * @see usbdevfs_urb + */ + MemorySegment urb; +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 295a5f6e..b6def580 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -8,7 +8,7 @@ package net.codecrete.usb.linux; import net.codecrete.usb.*; -import net.codecrete.usb.common.AsyncIOCompletion; +import net.codecrete.usb.common.Transfer; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.common.USBInterfaceImpl; import net.codecrete.usb.linux.gen.errno.errno; @@ -75,7 +75,7 @@ public void open() { fd = IO.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC(), errnoState); if (fd == -1) throwLastError(errnoState, "Cannot open USB device"); - registry.registerCompletionHandling(this); + registry.addForAsyncIOCompletion(this); } } @@ -84,7 +84,7 @@ public void close() { if (!isOpen()) return; - registry.unregisterCompletionHandling(this); + registry.removeFromAsyncIOCompletion(this); for (var intf : interfaces_) ((USBInterfaceImpl) intf).setClaimed(false); @@ -260,6 +260,16 @@ public byte[] transferIn(int endpointNumber, int timeout) { } } + @Override + protected Transfer createTransfer() { + return new LinuxTransfer(); + } + + @Override + protected void throwOSException(int errorCode, String message, Object... args) { + throwException(errorCode, message, args); + } + @Override public void clearHalt(USBDirection direction, int endpointNumber) { var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); @@ -296,15 +306,13 @@ public OutputStream openOutputStream(int endpointNumber) { return new LinuxEndpointOutputStream(this, endpointNumber); } - synchronized void submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, - AsyncIOCompletion completion) { + synchronized void submitTransferIn(int endpointNumber, LinuxTransfer transfer) { var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); - registry.submitBulkTransfer(this, endpoint.endpointAddress(), buffer, bufferSize, completion); + registry.submitBulkTransfer(this, endpoint.endpointAddress(), transfer); } - synchronized void submitTransferOut(int endpointNumber, MemorySegment data, int dataSize, - AsyncIOCompletion completion) { + synchronized void submitTransferOut(int endpointNumber, LinuxTransfer transfer) { var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); - registry.submitBulkTransfer(this, endpoint.endpointAddress(), data, dataSize, completion); + registry.submitBulkTransfer(this, endpoint.endpointAddress(), transfer); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 403569bb..734e1001 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -8,7 +8,6 @@ package net.codecrete.usb.linux; import net.codecrete.usb.USBDevice; -import net.codecrete.usb.common.AsyncIOCompletion; import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.common.USBDeviceRegistry; import net.codecrete.usb.linux.gen.errno.errno; @@ -52,7 +51,7 @@ public class LinuxUSBDeviceRegistry extends USBDeviceRegistry { /// available URBs private final List availableURBs = new ArrayList<>(); /// map of URB address to completion handler (for outstanding requests) - private final Map completionHandlerByURB = new HashMap<>(); + private final Map completionHandlerByURB = new HashMap<>(); /// array of file descriptors using asynchronous completion private int[] asyncFds; /// file descriptor to notify async IO background thread about an update @@ -336,17 +335,11 @@ private void reapURB(int fd, MemorySegment urbPointerHolder, MemorySegment errno throwException(err, "internal error (reap URB)"); } - var addr = urbPointerHolder.get(ADDRESS, 0); - var urb = usbdevfs_urb.ofAddress(addr, SegmentScope.global()); - int status = usbdevfs_urb.status$get(urb); - int length = usbdevfs_urb.actual_length$get(urb); + var urbAddr = urbPointerHolder.get(JAVA_LONG, 0); + var transfer = getRequest(urbAddr); // call completion handler - synchronized (this) { - var completionHandler = completionHandlerByURB.get(urb.address()); - completionHandler.completed(status, length); - recycleURB(urb); - } + transfer.completionHandler.completed(transfer); } /** @@ -371,7 +364,7 @@ private void notifyAsyncIOTask() { * * @param device USB device */ - synchronized void registerCompletionHandling(LinuxUSBDevice device) { + synchronized void addForAsyncIOCompletion(LinuxUSBDevice device) { int n = asyncFds != null ? asyncFds.length : 0; int[] fds = new int[n + 1]; if (n > 0) @@ -388,7 +381,7 @@ synchronized void registerCompletionHandling(LinuxUSBDevice device) { * * @param device USB device */ - synchronized void unregisterCompletionHandling(LinuxUSBDevice device) { + synchronized void removeFromAsyncIOCompletion(LinuxUSBDevice device) { // copy file descriptor (except the device's) into new array int n = asyncFds.length; if (n == 0) @@ -406,20 +399,20 @@ synchronized void unregisterCompletionHandling(LinuxUSBDevice device) { } } - // activate new array asyncFds = fds; notifyAsyncIOTask(); } - synchronized void submitBulkTransfer(LinuxUSBDevice device, int endpointAddress, MemorySegment buffer, - int bufferLength, AsyncIOCompletion completion) { - var urb = getURB(completion); + synchronized void submitBulkTransfer(LinuxUSBDevice device, int endpointAddress, LinuxTransfer request) { + + addURB(request); + var urb = request.urb; usbdevfs_urb.type$set(urb, (byte) USBDEVFS_URB_TYPE_BULK()); usbdevfs_urb.endpoint$set(urb, (byte) endpointAddress); - usbdevfs_urb.buffer$set(urb, buffer); - usbdevfs_urb.buffer_length$set(urb, bufferLength); + usbdevfs_urb.buffer$set(urb, request.data); + usbdevfs_urb.buffer_length$set(urb, request.dataSize); usbdevfs_urb.usercontext$set(urb, MemorySegment.ofAddress(device.fileDescriptor())); try (var arena = Arena.openConfined()) { @@ -429,7 +422,7 @@ synchronized void submitBulkTransfer(LinuxUSBDevice device, int endpointAddress, } } - private MemorySegment getURB(AsyncIOCompletion completionHandler) { + void addURB(LinuxTransfer request) { MemorySegment urb; int size = availableURBs.size(); if (size > 0) { @@ -438,14 +431,21 @@ private MemorySegment getURB(AsyncIOCompletion completionHandler) { urb = usbdevfs_urb.allocate(GLOBAL_ALLOCATOR); } - completionHandlerByURB.put(urb.address(), completionHandler); - - return urb; + request.urb = urb; + completionHandlerByURB.put(urb.address(), request); } - synchronized void recycleURB(MemorySegment urb) { - completionHandlerByURB.remove(urb.address()); - availableURBs.add(urb); + private synchronized LinuxTransfer getRequest(long urbAddr) { + var request = completionHandlerByURB.remove(urbAddr); + if (request == null) + return null; + + request.resultCode = usbdevfs_urb.status$get(request.urb); + request.resultSize = usbdevfs_urb.actual_length$get(request.urb); + + availableURBs.add(request.urb); + request.urb = null; + return request; } synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java new file mode 100644 index 00000000..404bf927 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java @@ -0,0 +1,194 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.macos; + +import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; +import net.codecrete.usb.macos.gen.iokit.IOKit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentScope; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; + +/** + * Background task for handling asynchronous transfers. + *

+ * Each USB device and interface must register its event source with this task. + *

+ *

+ * The task assigns a consecutive number to transfers. It is used in the + * {@code refcon} argument to match callbacks with the submitted transfer. + *

+ */ +class MacosAsyncTask { + + private static MacosAsyncTask singletonInstance; + + /** + * Singleton instance of background task. + * + * @return background task + */ + static synchronized MacosAsyncTask instance() { + if (singletonInstance == null) + singletonInstance = new MacosAsyncTask(); + return singletonInstance; + } + + private final ReentrantLock asyncIoLock = new ReentrantLock(); + private Condition asyncIoReady; + private MemorySegment asyncIoRunLoop; + private MemorySegment completionUpcallStub; + private long lastTransferId; + private final Map transfersById = new HashMap<>(); + + /** + * Adds an event source to this background. + * + * @param source event source + */ + void addEventSource(MemorySegment source) { + try { + asyncIoLock.lock(); + + if (asyncIoRunLoop == null) { + + if (asyncIoReady == null) { + // start background thread + asyncIoReady = asyncIoLock.newCondition(); + startAsyncIOThread(source); + + while (asyncIoRunLoop == null) + asyncIoReady.awaitUninterruptibly(); + + return; + + } else { + // special case: run loop is not ready yet but background process is already starting + while (asyncIoRunLoop == null) + asyncIoReady.awaitUninterruptibly(); + } + } + + CoreFoundation.CFRunLoopAddSource(asyncIoRunLoop, source, IOKit.kCFRunLoopDefaultMode$get()); + + } finally { + asyncIoLock.unlock(); + } + } + + /** + * Removes an event source from this background task. + * + * @param source event source + */ + void removeEventSource(MemorySegment source) { + CoreFoundation.CFRunLoopRemoveSource(asyncIoRunLoop, source, IOKit.kCFRunLoopDefaultMode$get()); + } + + /** + * Starts the background thread. + * + * @param firstSource first event source + */ + private void startAsyncIOThread(MemorySegment firstSource) { + try { + var completionHandlerFuncDesc = FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT, ADDRESS); + var asyncIOCompletedMH = MethodHandles.lookup().findVirtual(MacosAsyncTask.class, "asyncIOCompleted", + MethodType.methodType(void.class, MemorySegment.class, int.class, MemorySegment.class)); + + var methodHandle = asyncIOCompletedMH.bindTo(this); + completionUpcallStub = Linker.nativeLinker().upcallStub(methodHandle, completionHandlerFuncDesc, + SegmentScope.global()); + + } catch (IllegalAccessException | NoSuchMethodException e) { + throw new RuntimeException(e); + } + + Thread t = new Thread(() -> asyncIOCompletionTask(firstSource), "USB async IO"); + t.setDaemon(true); + t.start(); + } + + /** + * Background task calling the completion handlers. + *

+ * Without an initial event source, the run loop will immediately exit. + * Later it has no problems if the number of event sources drops to 0. + *

+ * + * @param firstSource first event source + */ + private void asyncIOCompletionTask(MemorySegment firstSource) { + try { + asyncIoLock.lock(); + asyncIoRunLoop = CoreFoundation.CFRunLoopGetCurrent(); + CoreFoundation.CFRunLoopAddSource(asyncIoRunLoop, firstSource, IOKit.kCFRunLoopDefaultMode$get()); + asyncIoReady.signalAll(); + } finally { + asyncIoLock.unlock(); + } + + // loop forever + CoreFoundation.CFRunLoopRun(); + } + + /** + * Prepare a transfer for submission by assigning it an ID + * and remembering the association to the transfer. + *

+ * Each submission needs to be prepared separately. + *

+ * + * @param transfer transfer + */ + synchronized void prepareForSubmission(MacosTransfer transfer) { + lastTransferId += 1; + transfer.id = lastTransferId; + transfer.resultSize = -1; + transfersById.put(lastTransferId, transfer); + } + + /** + * Callback function called when an asynchronous transfer has completed. + * + * @param refcon contains transfer ID + * @param result contains result code + * @param arg0 contains actual length of transferred data + */ + private void asyncIOCompleted(MemorySegment refcon, int result, MemorySegment arg0) { + + MacosTransfer transfer; + synchronized (this) { + transfer = transfersById.remove(refcon.address()); + } + + transfer.resultCode = result; + transfer.resultSize = (int) arg0.address(); + transfer.completionHandler.completed(transfer); + } + + /** + * Gets the native IO completion callback function for asynchronous transfers + * to be handled by this background task. + * + * @return function pointer + */ + MemorySegment nativeCompletionCallback() { + return completionUpcallStub; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java index 979636ee..711e6aac 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java @@ -7,10 +7,8 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.common.AsyncIOCompletion; import net.codecrete.usb.common.EndpointInputStream; - -import java.lang.foreign.MemorySegment; +import net.codecrete.usb.common.Transfer; public class MacosEndpointInputStream extends EndpointInputStream { @@ -19,12 +17,7 @@ public class MacosEndpointInputStream extends EndpointInputStream { } @Override - protected void submitTransferIn(MemorySegment buffer, int bufferSize, AsyncIOCompletion completion) { - ((MacosUSBDevice) device).submitTransferIn(endpointNumber, buffer, bufferSize, 0, completion); - } - - @Override - protected void throwException(int errorCode, String message) { - MacosUSBException.throwException(errorCode, message); + protected void submitTransferIn(Transfer transfer) { + ((MacosUSBDevice) device).submitTransferIn(endpointNumber, (MacosTransfer) transfer, 0); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java index d3c512f0..56494142 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java @@ -7,10 +7,8 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.common.AsyncIOCompletion; import net.codecrete.usb.common.EndpointOutputStream; - -import java.lang.foreign.MemorySegment; +import net.codecrete.usb.common.Transfer; public class MacosEndpointOutputStream extends EndpointOutputStream { @@ -19,12 +17,7 @@ public class MacosEndpointOutputStream extends EndpointOutputStream { } @Override - protected void submitTransferOut(MemorySegment data, int dataSize, AsyncIOCompletion completion) { - ((MacosUSBDevice) device).submitTransferOut(endpointNumber, data, dataSize, 0, completion); - } - - @Override - protected void throwException(int errorCode, String message) { - MacosUSBException.throwException(errorCode, message); + protected void submitTransferOut(Transfer request) { + ((MacosUSBDevice) device).submitTransferOut(endpointNumber, (MacosTransfer) request, 0); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosTransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosTransfer.java new file mode 100644 index 00000000..55dee2d5 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosTransfer.java @@ -0,0 +1,14 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.macos; + +import net.codecrete.usb.common.Transfer; + +public class MacosTransfer extends Transfer { + long id; +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index f4fb9a7f..2d74fe9b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -11,9 +11,9 @@ import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBTimeoutException; import net.codecrete.usb.USBTransferType; -import net.codecrete.usb.common.AsyncIOCompletion; import net.codecrete.usb.common.ForeignMemory; import net.codecrete.usb.common.ScopeCleanup; +import net.codecrete.usb.common.Transfer; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.macos.gen.iokit.IOKit; import net.codecrete.usb.macos.gen.iokit.IOUSBDevRequest; @@ -22,10 +22,8 @@ import java.io.InputStream; import java.io.OutputStream; -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -43,34 +41,12 @@ *

*

* As a consequence of the synchronized submission, blocking operations consists of submitting an - * asynchronous request and waiting for the completion. - *

- *

- * For the completion callback, an upcall stub is created for each device instance. The device instance is bound - * to this stub. The stub is used as the {@code callback} parameter in the native functions. For each USB - * interface, an event source is registered in the registry's asynchronous IO completion background thread. - * To map the callback to a specific request, the request provides a completion handler. It is assigned a unique - * number. The number is passed as {@code refcon} to the native call while the mapping between the number and the - * completion handler is maintained in a hash map. + * asynchronous transfer and waiting for the completion. *

*/ public class MacosUSBDevice extends USBDeviceImpl { - static final MethodHandle asyncIOCompletedMH; - // Function descriptor for callback functions of type 'IOAsyncCallback1' - static final FunctionDescriptor completionHandlerFuncDesc = FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT, ADDRESS); - - static { - try { - asyncIOCompletedMH = MethodHandles.lookup().findStatic(MacosUSBDevice.class, "asyncIOCompleted", - MethodType.methodType(void.class, MacosUSBDevice.class, MemorySegment.class, int.class, - MemorySegment.class)); - } catch (IllegalAccessException | NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - private final MacosUSBDeviceRegistry registry; + private final MacosAsyncTask asyncTask; // Native USB device interface (IOUSBDeviceInterface**) private MemorySegment device; // Currently selected configuration @@ -79,19 +55,10 @@ public class MacosUSBDevice extends USBDeviceImpl { private List claimedInterfaces; // Details about endpoints of current alternate settings (for claimed interfaces) private Map endpoints; - // Last used handler ID - private int lastHandlerId; - // Completion handlers of currently outstanding asynchronous IO requests, - // indexed by assigned ID, which is passed in and out as 'refcon' - private Map completionHandlers; - /// Arena used to allocate upcall stub for event source - private Arena arena; - /// Upcall stub for IO completion callback - private MemorySegment completionUpcallStub; - - MacosUSBDevice(MacosUSBDeviceRegistry registry, MemorySegment device, Object id, int vendorId, int productId) { + + MacosUSBDevice(MemorySegment device, Object id, int vendorId, int productId) { super(id, vendorId, productId); - this.registry = registry; + asyncTask = MacosAsyncTask.instance(); loadDescription(device); @@ -142,7 +109,7 @@ public synchronized void close() { var source = IoKitUSB.GetDeviceAsyncEventSource(device); if (source.address() != 0) - registry.removeEventSource(source); + asyncTask.removeEventSource(source); IoKitUSB.USBDeviceClose(device); } @@ -278,7 +245,7 @@ public synchronized void releaseInterface(int interfaceNumber) { var source = IoKitUSB.GetInterfaceAsyncEventSource(interfaceInfo.iokitInterface()); if (source.address() != 0) - registry.removeEventSource(source); + asyncTask.removeEventSource(source); int ret = IoKitUSB.USBInterfaceClose(interfaceInfo.iokitInterface()); if (ret != 0) @@ -377,14 +344,16 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { try (var arena = Arena.openConfined()) { var data = arena.allocate(length); var deviceRequest = createDeviceRequest(arena, USBDirection.IN, setup, data); - var request = createRequest(); - synchronized (request) { - submitControlTransfer(deviceRequest, (result, size) -> onRequestCompleted(request, result, size)); - waitForRequest(request, USBDirection.IN, 0, false); + var transfer = (MacosTransfer) createTransfer(); + transfer.completionHandler = MacosUSBDevice::onTransferCompleted; + + synchronized (transfer) { + submitControlTransfer(deviceRequest, transfer); + waitForTransfer(transfer, USBDirection.IN, 0, false); } - return data.asSlice(0, request.size).toArray(JAVA_BYTE); + return data.asSlice(0, transfer.resultSize).toArray(JAVA_BYTE); } } @@ -396,11 +365,13 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { if (dataLength > 0) dataSegment.copyFrom(MemorySegment.ofArray(data)); var deviceRequest = createDeviceRequest(arena, USBDirection.OUT, setup, dataSegment); - var request = createRequest(); - synchronized (request) { - submitControlTransfer(deviceRequest, (result, size) -> onRequestCompleted(request, result, size)); - waitForRequest(request, USBDirection.OUT, 0, false); + var transfer = (MacosTransfer) createTransfer(); + transfer.completionHandler = MacosUSBDevice::onTransferCompleted; + + synchronized (transfer) { + submitControlTransfer(deviceRequest, transfer); + waitForTransfer(transfer, USBDirection.OUT, 0, false); } } } @@ -415,19 +386,21 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { var nativeData = arena.allocateArray(JAVA_BYTE, data.length); nativeData.copyFrom(MemorySegment.ofArray(data)); - var request = createRequest(); - synchronized (request) { + var transfer = (MacosTransfer) createTransfer(); + transfer.data = nativeData; + transfer.dataSize = data.length; + transfer.completionHandler = MacosUSBDevice::onTransferCompleted; + + synchronized (transfer) { if (timeout <= 0 || epInfo.transferType() == USBTransferType.BULK) { // no timeout or timeout handled by operating system - submitTransferOut(endpointNumber, nativeData, data.length, timeout, - (result, size) -> onRequestCompleted(request, result, size)); - waitForRequest(request, USBDirection.OUT, endpointNumber, false); + submitTransferOut(endpointNumber, transfer, timeout); + waitForTransfer(transfer, USBDirection.OUT, endpointNumber, false); } else { // interrupt transfer with timeout - submitTransferOut(endpointNumber, nativeData, data.length, 0, - (result, size) -> onRequestCompleted(request, result, size)); - waitForRequestOrAbort(request, timeout, USBDirection.OUT, endpointNumber); + submitTransferOut(endpointNumber, transfer, 0); + waitForTransferTO(transfer, timeout, USBDirection.OUT, endpointNumber); } } } @@ -442,141 +415,135 @@ public byte[] transferIn(int endpointNumber, int timeout) { try (var arena = Arena.openConfined()) { var nativeData = arena.allocateArray(JAVA_BYTE, epInfo.packetSize()); - var request = createRequest(); - synchronized (request) { + var transfer = (MacosTransfer) createTransfer(); + transfer.data = nativeData; + transfer.dataSize = epInfo.packetSize(); + transfer.completionHandler = MacosUSBDevice::onTransferCompleted; + + synchronized (transfer) { if (timeout <= 0 || epInfo.transferType() == USBTransferType.BULK) { - // no timeout or timeout handled by operating system - submitTransferIn(endpointNumber, nativeData, epInfo.packetSize(), timeout, - (result, size) -> onRequestCompleted(request, result, size)); - waitForRequest(request, USBDirection.IN, endpointNumber, false); + // no timeout, or timeout handled by operating system + submitTransferIn(endpointNumber, transfer, timeout); + waitForTransfer(transfer, USBDirection.IN, endpointNumber, false); } else { // interrupt transfer with timeout - submitTransferIn(endpointNumber, nativeData, epInfo.packetSize(), 0, - (result, size) -> onRequestCompleted(request, result, size)); - waitForRequestOrAbort(request, timeout, USBDirection.IN, endpointNumber); + submitTransferIn(endpointNumber, transfer, 0); + waitForTransferTO(transfer, timeout, USBDirection.IN, endpointNumber); } } - return nativeData.asSlice(0, request.size).toArray(JAVA_BYTE); + return nativeData.asSlice(0, transfer.resultSize).toArray(JAVA_BYTE); } } /** - * Submits a transfer IN request to the specified BULK or INTERRUPT endpoint. + * Submits a transfer IN to the specified BULK or INTERRUPT endpoint. *

* A timeout may only be specified for BULK endpoints. *

* - * @param endpointNumber endpoint number - * @param buffer buffer that will receive data - * @param bufferSize buffer length (should be packet size or multiple thereof) - * @param timeout the timeout, in milliseconds, or 0 for no timeout - * @param completionHandler handler that will be called when the request completes + * @param endpointNumber endpoint number + * @param transfer transfer to execute + * @param timeout the timeout, in milliseconds, or 0 for no timeout */ - synchronized void submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, int timeout, - AsyncIOCompletion completionHandler) { + synchronized void submitTransferIn(int endpointNumber, MacosTransfer transfer, int timeout) { EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); + asyncTask.prepareForSubmission(transfer); - // submit request + // submit transfer int ret; if (timeout <= 0) - ret = IoKitUSB.ReadPipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), buffer, bufferSize, - getCompletionUpcallStub(), saveCompletionHandler(completionHandler)); + ret = IoKitUSB.ReadPipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data, + transfer.dataSize, asyncTask.nativeCompletionCallback(), MemorySegment.ofAddress(transfer.id)); else - ret = IoKitUSB.ReadPipeAsyncTO(epInfo.iokitInterface(), epInfo.pipeIndex(), buffer, bufferSize, timeout, - timeout, getCompletionUpcallStub(), saveCompletionHandler(completionHandler)); + ret = IoKitUSB.ReadPipeAsyncTO(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data, + transfer.dataSize, timeout, timeout, asyncTask.nativeCompletionCallback(), + MemorySegment.ofAddress(transfer.id)); if (ret != 0) - throwException(ret, "failed to submit transfer IN request"); + throwException(ret, "failed to read from endpoint %d", endpointNumber); } /** - * Submits a transfer OUT request to the specified BULK or INTERRUPT endpoint. + * Submits a transfer OUT to the specified BULK or INTERRUPT endpoint. *

* A timeout may only be specified for BULK endpoints. *

* - * @param endpointNumber endpoint number - * @param data buffer with data to be transmitted - * @param dataSize number of bytes to be transmitted - * @param timeout the timeout, in milliseconds, or 0 for no timeout - * @param completionHandler handler that will be called when the request completes + * @param endpointNumber endpoint number + * @param transfer transfer request to execute + * @param timeout the timeout, in milliseconds, or 0 for no timeout */ - synchronized void submitTransferOut(int endpointNumber, MemorySegment data, int dataSize, int timeout, - AsyncIOCompletion completionHandler) { + synchronized void submitTransferOut(int endpointNumber, MacosTransfer transfer, int timeout) { EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); + asyncTask.prepareForSubmission(transfer); - // submit request + // submit transfer int ret; if (timeout <= 0) - ret = IoKitUSB.WritePipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), data, dataSize, - getCompletionUpcallStub(), saveCompletionHandler(completionHandler)); + ret = IoKitUSB.WritePipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data, + transfer.dataSize, asyncTask.nativeCompletionCallback(), MemorySegment.ofAddress(transfer.id)); else - ret = IoKitUSB.WritePipeAsyncTO(epInfo.iokitInterface(), epInfo.pipeIndex(), data, dataSize, timeout, - timeout, getCompletionUpcallStub(), saveCompletionHandler(completionHandler)); + ret = IoKitUSB.WritePipeAsyncTO(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data, + transfer.dataSize, timeout, timeout, asyncTask.nativeCompletionCallback(), + MemorySegment.ofAddress(transfer.id)); if (ret != 0) - throwException(ret, "failed to submit transfer OUT request"); + throwException(ret, "failed to write to endpoint %d", endpointNumber); } /** - * Submits a control transfer request. + * Submits a control transfer. * - * @param deviceRequest control transfer request - * @param completionHandler handler that will be called when the request completes + * @param deviceRequest control transfer request + * @param transfer transfer request (for completion handling) */ - synchronized void submitControlTransfer(MemorySegment deviceRequest, AsyncIOCompletion completionHandler) { + synchronized void submitControlTransfer(MemorySegment deviceRequest, MacosTransfer transfer) { checkIsOpen(); + asyncTask.prepareForSubmission(transfer); - // submit request - int ret = IoKitUSB.DeviceRequestAsync(device, deviceRequest, getCompletionUpcallStub(), - saveCompletionHandler(completionHandler)); + // submit transfer + int ret = IoKitUSB.DeviceRequestAsync(device, deviceRequest, asyncTask.nativeCompletionCallback(), + MemorySegment.ofAddress(transfer.id)); if (ret != 0) - throwException(ret, "failed to submit control transfer request"); - } - - private TransferRequest createRequest() { - var request = new TransferRequest(); - request.size = -1; - return request; + throwException(ret, "failed to execute control transfer"); } - private void waitForRequest(TransferRequest request, USBDirection direction, int endpointNumber, - boolean ignoreAbort) { - // wait for request - while (request.size == -1) { + private void waitForTransfer(MacosTransfer transfer, USBDirection direction, int endpointNumber, + boolean ignoreAbort) { + // wait for transfer + while (transfer.resultSize == -1) { try { - request.wait(); + transfer.wait(); } catch (InterruptedException e) { // ignore and retry } } // test for error - if (request.result != 0) { + if (transfer.resultCode != 0) { var operation = getOperationDescription(direction, endpointNumber); - if (request.result == IOKit.kIOUSBTransactionTimeout()) + if (transfer.resultCode == IOKit.kIOUSBTransactionTimeout()) throw new USBTimeoutException(operation + "aborted due to timeout"); - if (request.result != IOKit.kIOReturnAborted() || !ignoreAbort) - throwException(request.result, operation + " failed"); + if (transfer.resultCode != IOKit.kIOReturnAborted() || !ignoreAbort) + throwException(transfer.resultCode, operation + " failed"); } } - private void waitForRequestOrAbort(TransferRequest request, int timeout, USBDirection direction, - int endpointNumber) { - // wait for request or abort when timeout occurs + private void waitForTransferTO(MacosTransfer transfer, int timeout, USBDirection direction, int endpointNumber) { + // wait for transfer to complete, or abort when timeout occurs long expiration = System.currentTimeMillis() + timeout; long remainingTimeout = timeout; - while (remainingTimeout > 0 && request.size == -1) { + while (remainingTimeout > 0 && transfer.resultSize == -1) { try { - request.wait(remainingTimeout); + transfer.wait(remainingTimeout); remainingTimeout = expiration - System.currentTimeMillis(); } catch (InterruptedException e) { @@ -585,16 +552,17 @@ private void waitForRequestOrAbort(TransferRequest request, int timeout, USBDire } // test for timeout - if (request.result == 0 && remainingTimeout <= 0) { + if (transfer.resultCode == 0 && remainingTimeout <= 0) { abortTransfers(direction, endpointNumber); - waitForRequest(request, direction, endpointNumber, true); + waitForTransfer(transfer, direction, endpointNumber, true); throw new USBTimeoutException(getOperationDescription(direction, endpointNumber) + "aborted due to " + "timeout"); } - if (request.result != 0) { + if (transfer.resultCode != 0) { var operation = direction == USBDirection.IN ? "Transfer in" : "Transfer out"; - throwException(request.result, getOperationDescription(direction, endpointNumber) + " failed", operation); + throwException(transfer.resultCode, getOperationDescription(direction, endpointNumber) + " failed", + operation); } } @@ -607,11 +575,14 @@ private static String getOperationDescription(USBDirection direction, int endpoi } - private static void onRequestCompleted(TransferRequest request, int result, int size) { - synchronized (request) { - request.result = result; - request.size = size; - request.notify(); + @Override + protected Transfer createTransfer() { + return new MacosTransfer(); + } + + private static void onTransferCompleted(Transfer transfer) { + synchronized (transfer) { + transfer.notify(); } } @@ -651,6 +622,11 @@ public OutputStream openOutputStream(int endpointNumber) { return new MacosEndpointOutputStream(this, endpointNumber); } + @Override + protected void throwOSException(int errorCode, String message, Object... args) { + throwException(errorCode, message, args); + } + private static USBTransferType getTransferType(byte macosTransferType) { return switch (macosTransferType) { case 1 -> USBTransferType.ISOCHRONOUS; @@ -660,32 +636,6 @@ private static USBTransferType getTransferType(byte macosTransferType) { }; } - private synchronized MemorySegment getCompletionUpcallStub() { - if (completionUpcallStub == null) { - arena = Arena.openShared(); - var methodHandle = asyncIOCompletedMH.bindTo(this); - completionUpcallStub = Linker.nativeLinker().upcallStub(methodHandle, completionHandlerFuncDesc, - arena.scope()); - } - - return completionUpcallStub; - } - - private synchronized MemorySegment saveCompletionHandler(AsyncIOCompletion handler) { - if (completionHandlers == null) - completionHandlers = new HashMap<>(); - - while (true) { - lastHandlerId += 1; - var key = Integer.valueOf(lastHandlerId); - if (completionHandlers.containsKey(key)) - continue; - - completionHandlers.put(key, handler); - return MemorySegment.ofAddress(lastHandlerId, 0, SegmentScope.global()); - } - } - private synchronized void addDeviceEventSource() { try (Arena innerArena = Arena.openConfined()) { var sourceHolder = innerArena.allocate(ADDRESS); @@ -693,7 +643,7 @@ private synchronized void addDeviceEventSource() { if (ret != 0) throwException(ret, "failed to create event source"); var source = sourceHolder.get(ADDRESS, 0); - registry.addEventSource(source); + asyncTask.addEventSource(source); } } @@ -704,36 +654,13 @@ private synchronized void addInterfaceEventSource(InterfaceInfo interfaceInfo) { if (ret != 0) throwException(ret, "failed to create event source"); var source = sourceHolder.get(ADDRESS, 0); - registry.addEventSource(source); + asyncTask.addEventSource(source); } } - private synchronized AsyncIOCompletion getCompletionHandler(MemorySegment refcon) { - var key = Integer.valueOf((int) refcon.address()); - var handler = completionHandlers.remove(key); - - if (!isOpen() && completionHandlers.size() == 0) { - completionHandlers = null; - completionUpcallStub = null; - arena.close(); - arena = null; - } - - return handler; - } - - private static void asyncIOCompleted(MacosUSBDevice device, MemorySegment refcon, int result, MemorySegment arg0) { - device.getCompletionHandler(refcon).completed(result, (int) arg0.address()); - } - record InterfaceInfo(MemorySegment iokitInterface, int interfaceNumber) { } record EndpointInfo(MemorySegment iokitInterface, byte pipeIndex, USBTransferType transferType, int packetSize) { } - - static class TransferRequest { - int result; - int size; - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 58bc19d9..98293d0c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -18,8 +18,6 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.ArrayList; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import static java.lang.foreign.MemorySegment.NULL; @@ -178,7 +176,7 @@ private USBDevice createDevice(Long entryID, int service, MemorySegment deviceIn info.vid = vendorId; info.pid = productId; - var device = new MacosUSBDevice(this, deviceIntf, entryID, vendorId, productId); + var device = new MacosUSBDevice(deviceIntf, entryID, vendorId, productId); String manufacturer = IoKitHelper.getPropertyString(service, KEY_VENDOR, arena); String product = IoKitHelper.getPropertyString(service, KEY_PRODUCT, arena); @@ -267,60 +265,6 @@ private void onDevicesDisconnected(@SuppressWarnings("SameParameterValue") Memor }); } - private final ReentrantLock asyncIoLock = new ReentrantLock(); - private Condition asyncIoReady; - private MemorySegment asyncIoRunLoop; - - void addEventSource(MemorySegment source) { - try { - asyncIoLock.lock(); - - if (asyncIoRunLoop == null) { - - if (asyncIoReady == null) { - // start background thread - asyncIoReady = asyncIoLock.newCondition(); - Thread t = new Thread(() -> asyncIOCompletionTask(source), "USB async IO"); - t.setDaemon(true); - t.start(); - - while (asyncIoRunLoop == null) - asyncIoReady.awaitUninterruptibly(); - - return; - - } else { - // special case: run loop is not ready yet but background process is already starting - while (asyncIoRunLoop == null) - asyncIoReady.awaitUninterruptibly(); - } - } - - CoreFoundation.CFRunLoopAddSource(asyncIoRunLoop, source, IOKit.kCFRunLoopDefaultMode$get()); - - } finally { - asyncIoLock.unlock(); - } - } - - void removeEventSource(MemorySegment source) { - CoreFoundation.CFRunLoopRemoveSource(asyncIoRunLoop, source, IOKit.kCFRunLoopDefaultMode$get()); - } - - private void asyncIOCompletionTask(MemorySegment firstSource) { - try { - asyncIoLock.lock(); - asyncIoRunLoop = CoreFoundation.CFRunLoopGetCurrent(); - CoreFoundation.CFRunLoopAddSource(asyncIoRunLoop, firstSource, IOKit.kCFRunLoopDefaultMode$get()); - asyncIoReady.signalAll(); - } finally { - asyncIoLock.unlock(); - } - - // loop forever - CoreFoundation.CFRunLoopRun(); - } - @FunctionalInterface interface IOKitDeviceConsumer { void accept(long entryId, int service, MemorySegment deviceIntf); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java index 8f728551..fbfdc3d0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java @@ -66,10 +66,16 @@ public int maxPower() { // uint8_t bmAttributes; // uint8_t bMaxPower; // } __attribute__((packed)); - public static final GroupLayout LAYOUT = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( - "bDescriptorType"), JAVA_SHORT_UNALIGNED.withName("wTotalLength"), JAVA_BYTE.withName("bNumInterfaces"), - JAVA_BYTE.withName("bConfigurationValue"), JAVA_BYTE.withName("iConfiguration"), JAVA_BYTE.withName( - "bmAttributes"), JAVA_BYTE.withName("bMaxPower")); + public static final GroupLayout LAYOUT = structLayout( + JAVA_BYTE.withName("bLength"), + JAVA_BYTE.withName("bDescriptorType"), + JAVA_SHORT_UNALIGNED.withName("wTotalLength"), + JAVA_BYTE.withName("bNumInterfaces"), + JAVA_BYTE.withName("bConfigurationValue"), + JAVA_BYTE.withName("iConfiguration"), + JAVA_BYTE.withName("bmAttributes"), + JAVA_BYTE.withName("bMaxPower") + ); private static final VarHandle bDescriptorType$VH = LAYOUT.varHandle(groupElement("bDescriptorType")); private static final VarHandle wTotalLength$VH = LAYOUT.varHandle(groupElement("wTotalLength")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java index dda87cc9..708cc3a1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java @@ -83,13 +83,22 @@ public int iSerialNumber() { // uint8_t iSerialNumber; // uint8_t bNumConfigurations; // } __attribute__((packed)); - public static final GroupLayout LAYOUT = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( - "bDescriptorType"), JAVA_SHORT_UNALIGNED.withName("bcdUSB"), JAVA_BYTE.withName("bDeviceClass"), - JAVA_BYTE.withName("bDeviceSubClass"), JAVA_BYTE.withName("bDeviceProtocol"), JAVA_BYTE.withName( - "bMaxPacketSize0"), JAVA_SHORT_UNALIGNED.withName("idVendor"), JAVA_SHORT_UNALIGNED.withName( - "idProduct"), JAVA_SHORT_UNALIGNED.withName("bcdDevice"), JAVA_BYTE.withName( - "iManufacturer"), JAVA_BYTE.withName("iProduct"), JAVA_BYTE.withName( - "iSerialNumber"), JAVA_BYTE.withName("bNumConfigurations")); + public static final GroupLayout LAYOUT = structLayout( + JAVA_BYTE.withName("bLength"), + JAVA_BYTE.withName("bDescriptorType"), + JAVA_SHORT_UNALIGNED.withName("bcdUSB"), + JAVA_BYTE.withName("bDeviceClass"), + JAVA_BYTE.withName("bDeviceSubClass"), + JAVA_BYTE.withName("bDeviceProtocol"), + JAVA_BYTE.withName("bMaxPacketSize0"), + JAVA_SHORT_UNALIGNED.withName("idVendor"), + JAVA_SHORT_UNALIGNED.withName("idProduct"), + JAVA_SHORT_UNALIGNED.withName("bcdDevice"), + JAVA_BYTE.withName("iManufacturer"), + JAVA_BYTE.withName("iProduct"), + JAVA_BYTE.withName("iSerialNumber"), + JAVA_BYTE.withName("bNumConfigurations") + ); private static final VarHandle bcdUSB$VH = LAYOUT.varHandle(groupElement("bcdUSB")); private static final VarHandle bDeviceClass$VH = LAYOUT.varHandle(groupElement("bDeviceClass")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java index dfaa3571..059a9335 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java @@ -55,9 +55,14 @@ public int interval() { // uint16_t wMaxPacketSize; // uint8_t bInterval; // } __attribute__((packed)); - public static final GroupLayout LAYOUT = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( - "bDescriptorType"), JAVA_BYTE.withName("bEndpointAddress"), JAVA_BYTE.withName("bmAttributes"), - JAVA_SHORT_UNALIGNED.withName("wMaxPacketSize"), JAVA_BYTE.withName("bInterval")); + public static final GroupLayout LAYOUT = structLayout( + JAVA_BYTE.withName("bLength"), + JAVA_BYTE.withName("bDescriptorType"), + JAVA_BYTE.withName("bEndpointAddress"), + JAVA_BYTE.withName("bmAttributes"), + JAVA_SHORT_UNALIGNED.withName("wMaxPacketSize"), + JAVA_BYTE.withName("bInterval") + ); private static final VarHandle bEndpointAddress$VH = LAYOUT.varHandle(groupElement("bEndpointAddress")); private static final VarHandle bmAttributes$VH = LAYOUT.varHandle(groupElement("bmAttributes")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java index ca1c9c45..d5fc5b73 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java @@ -65,10 +65,16 @@ public int function() { // uint8_t bFunctionProtocol, // uint8_t iFunction // } __attribute__((packed)); - public static final GroupLayout LAYOUT = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( - "bDescriptorType"), JAVA_BYTE.withName("bFirstInterface"), JAVA_BYTE.withName("bInterfaceCount"), - JAVA_BYTE.withName("bFunctionClass"), JAVA_BYTE.withName("bFunctionSubClass"), JAVA_BYTE.withName( - "bFunctionProtocol"), JAVA_BYTE.withName("iFunction")); + public static final GroupLayout LAYOUT = structLayout( + JAVA_BYTE.withName("bLength"), + JAVA_BYTE.withName("bDescriptorType"), + JAVA_BYTE.withName("bFirstInterface"), + JAVA_BYTE.withName("bInterfaceCount"), + JAVA_BYTE.withName("bFunctionClass"), + JAVA_BYTE.withName("bFunctionSubClass"), + JAVA_BYTE.withName("bFunctionProtocol"), + JAVA_BYTE.withName("iFunction") + ); private static final VarHandle bFirstInterface$VH = LAYOUT.varHandle(groupElement("bFirstInterface")); private static final VarHandle bInterfaceCount$VH = LAYOUT.varHandle(groupElement("bInterfaceCount")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java index e537b4e4..04668e37 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java @@ -69,10 +69,17 @@ public int iInterface() { // uint8_t bInterfaceProtocol; // uint8_t iInterface; // } __attribute__((packed)); - public static final GroupLayout LAYOUT = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( - "bDescriptorType"), JAVA_BYTE.withName("bInterfaceNumber"), JAVA_BYTE.withName("bAlternateSetting"), - JAVA_BYTE.withName("bNumEndpoints"), JAVA_BYTE.withName("bInterfaceClass"), JAVA_BYTE.withName( - "bInterfaceSubClass"), JAVA_BYTE.withName("bInterfaceProtocol"), JAVA_BYTE.withName("iInterface")); + public static final GroupLayout LAYOUT = structLayout( + JAVA_BYTE.withName("bLength"), + JAVA_BYTE.withName("bDescriptorType"), + JAVA_BYTE.withName("bInterfaceNumber"), + JAVA_BYTE.withName("bAlternateSetting"), + JAVA_BYTE.withName("bNumEndpoints"), + JAVA_BYTE.withName("bInterfaceClass"), + JAVA_BYTE.withName("bInterfaceSubClass"), + JAVA_BYTE.withName("bInterfaceProtocol"), + JAVA_BYTE.withName("iInterface") + ); private static final VarHandle bInterfaceNumber$VH = LAYOUT.varHandle(groupElement("bInterfaceNumber")); private static final VarHandle bAlternateSetting$VH = LAYOUT.varHandle(groupElement("bAlternateSetting")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java index f5b98a75..b1109a3e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java @@ -91,8 +91,13 @@ public void setLength(int length) { // uint16_t wIndex; // uint16_t wLength; // } __attribute__((packed)); - public static final GroupLayout LAYOUT = structLayout(JAVA_BYTE.withName("bmRequestType"), JAVA_BYTE.withName( - "bRequest"), JAVA_SHORT.withName("wValue"), JAVA_SHORT.withName("wIndex"), JAVA_SHORT.withName("wLength")); + public static final GroupLayout LAYOUT = structLayout( + JAVA_BYTE.withName("bmRequestType"), + JAVA_BYTE.withName("bRequest"), + JAVA_SHORT.withName("wValue"), + JAVA_SHORT.withName("wIndex"), + JAVA_SHORT.withName("wLength") + ); private static final VarHandle bmRequestType$VH = LAYOUT.varHandle(groupElement("bmRequestType")); private static final VarHandle bRequest$VH = LAYOUT.varHandle(groupElement("bRequest")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java index 04954815..96dea670 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java @@ -40,8 +40,11 @@ public String string() { // uint8_t bDescriptorType; // uint16_t string[1]; // } __attribute__((packed)); - public static final GroupLayout LAYOUT = structLayout(JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName( - "bDescriptorType"), JAVA_SHORT.withName("string")); + public static final GroupLayout LAYOUT = structLayout( + JAVA_BYTE.withName("bLength"), + JAVA_BYTE.withName("bDescriptorType"), + JAVA_SHORT.withName("string") + ); private static final VarHandle bLength$VH = LAYOUT.varHandle(groupElement("bLength")); private static final long string$offset = LAYOUT.byteOffset(groupElement("string")); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java index b18bef72..c257e10d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java @@ -8,10 +8,8 @@ package net.codecrete.usb.windows; import net.codecrete.usb.USBDirection; -import net.codecrete.usb.common.AsyncIOCompletion; import net.codecrete.usb.common.EndpointInputStream; - -import java.lang.foreign.MemorySegment; +import net.codecrete.usb.common.Transfer; public class WindowsEndpointInputStream extends EndpointInputStream { @@ -21,12 +19,7 @@ public class WindowsEndpointInputStream extends EndpointInputStream { } @Override - protected void submitTransferIn(MemorySegment buffer, int bufferSize, AsyncIOCompletion completion) { - ((WindowsUSBDevice) device).submitTransferIn(endpointNumber, buffer, bufferSize, completion); - } - - @Override - protected void throwException(int errorCode, String message) { - WindowsUSBException.throwException(errorCode, message); + protected void submitTransferIn(Transfer transfer) { + ((WindowsUSBDevice) device).submitTransferIn(endpointNumber, (WindowsTransfer) transfer); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java index ffaf513e..21b504ae 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java @@ -8,10 +8,8 @@ package net.codecrete.usb.windows; import net.codecrete.usb.USBDirection; -import net.codecrete.usb.common.AsyncIOCompletion; import net.codecrete.usb.common.EndpointOutputStream; - -import java.lang.foreign.MemorySegment; +import net.codecrete.usb.common.Transfer; public class WindowsEndpointOutputStream extends EndpointOutputStream { @@ -21,12 +19,7 @@ public class WindowsEndpointOutputStream extends EndpointOutputStream { } @Override - protected void submitTransferOut(MemorySegment data, int dataSize, AsyncIOCompletion completion) { - ((WindowsUSBDevice) device).submitTransferOut(endpointNumber, data, dataSize, completion); - } - - @Override - protected void throwException(int errorCode, String message) { - WindowsUSBException.throwException(errorCode, message); + protected void submitTransferOut(Transfer request) { + ((WindowsUSBDevice) device).submitTransferOut(endpointNumber, (WindowsTransfer) request); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsTransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsTransfer.java new file mode 100644 index 00000000..5989f040 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsTransfer.java @@ -0,0 +1,16 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.windows; + +import net.codecrete.usb.common.Transfer; + +import java.lang.foreign.MemorySegment; + +public class WindowsTransfer extends Transfer { + MemorySegment overlapped; +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index fb744ef6..3d048db7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -8,11 +8,10 @@ package net.codecrete.usb.windows; import net.codecrete.usb.*; -import net.codecrete.usb.common.AsyncIOCompletion; +import net.codecrete.usb.common.Transfer; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.usbstandard.SetupPacket; import net.codecrete.usb.windows.gen.kernel32.Kernel32; -import net.codecrete.usb.windows.gen.kernel32.OVERLAPPED; import net.codecrete.usb.windows.gen.winusb.WinUSB; import net.codecrete.usb.windows.winsdk.Kernel32B; import net.codecrete.usb.windows.winsdk.WinUSB2; @@ -23,7 +22,6 @@ import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentScope; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -40,13 +38,6 @@ public class WindowsUSBDevice extends USBDeviceImpl { private final WindowsUSBDeviceRegistry registry; private List interfaceHandles_; private boolean isOpen_; - // Completion handlers of currently outstanding asynchronous IO requests, - // indexed by OVERLAPPED pointer. - private Map completionHandlers; - // available OVERLAPPED data structures - private List availableOverlappedStructs; - // Arena used to allocate OVERLAPPED data structures - private Arena arena; WindowsUSBDevice(WindowsUSBDeviceRegistry registry, String devicePath, Map children, int vendorId, int productId, MemorySegment configDesc) { @@ -89,10 +80,6 @@ public synchronized void open() { throwException("the device is already open"); isOpen_ = true; - - availableOverlappedStructs = new ArrayList<>(); - arena = Arena.openShared(); - completionHandlers = new HashMap<>(); } @Override @@ -100,10 +87,6 @@ public synchronized void close() { if (!isOpen()) return; - availableOverlappedStructs = null; - arena.close(); - completionHandlers = null; - for (var intf : interfaces_) { if (intf.isClaimed()) releaseInterface(intf.number()); @@ -210,7 +193,6 @@ public synchronized void releaseInterface(int interfaceNumber) { // close device firstIntfHandle.deviceOpenCount -= 1; if (firstIntfHandle.deviceOpenCount == 0) { - registry.removeFromCompletionPort(firstIntfHandle.deviceHandle); Kernel32.CloseHandle(firstIntfHandle.deviceHandle); firstIntfHandle.deviceHandle = null; } @@ -339,45 +321,49 @@ public byte[] transferIn(int endpointNumber, int timeout) { } } - synchronized long submitTransferOut(int endpointNumber, MemorySegment data, int dataSize, - AsyncIOCompletion completion) { + @Override + protected Transfer createTransfer() { + return registry.createRequest(); + } + + @Override + protected void throwOSException(int errorCode, String message, Object... args) { + throwException(errorCode, message, args); + } + + synchronized void submitTransferOut(int endpointNumber, WindowsTransfer request) { var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.openConfined()) { var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - var overlapped = getOverlapped(completion); + registry.addOverlapped(request); // submit transfer - if (WinUSB2.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), data, dataSize, NULL - , overlapped, lastErrorState) == 0) { + if (WinUSB2.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), request.data, request.dataSize, NULL + , request.overlapped, lastErrorState) == 0) { int err = Win.getLastError(lastErrorState); if (err != Kernel32.ERROR_IO_PENDING()) throwException(err, "Submitting transfer OUT failed"); } - - return overlapped.address(); } } - synchronized long submitTransferIn(int endpointNumber, MemorySegment buffer, int bufferSize, - AsyncIOCompletion completion) { + synchronized void submitTransferIn(int endpointNumber, WindowsTransfer request) { var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.openConfined()) { var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - var overlapped = getOverlapped(completion); + registry.addOverlapped(request); // submit transfer - if (WinUSB2.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, bufferSize, - NULL, overlapped, lastErrorState) == 0) { + if (WinUSB2.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), request.data, request.dataSize, + NULL, request.overlapped, lastErrorState) == 0) { int err = Win.getLastError(lastErrorState); if (err != Kernel32.ERROR_IO_PENDING()) throwException(err, "Submitting transfer IN failed"); } - - return overlapped.address(); } } @@ -513,23 +499,4 @@ private InterfaceHandle findControlTransferInterface(USBControlTransfer setup) { throwException("Control transfer failed as no interface has been claimed"); throw new AssertionError("not reached"); } - - synchronized void onAsyncIoCompleted(MemorySegment overlapped) { - var handler = completionHandlers.get(overlapped); - handler.completed((int) OVERLAPPED.Internal$get(overlapped), (int) OVERLAPPED.InternalHigh$get(overlapped)); - completionHandlers.remove(overlapped); - availableOverlappedStructs.add(overlapped); - } - - private MemorySegment getOverlapped(AsyncIOCompletion completionHandler) { - MemorySegment overlapped; - int size = availableOverlappedStructs.size(); - if (size == 0) { - overlapped = arena.allocate(OVERLAPPED.$LAYOUT()); - } else { - overlapped = availableOverlappedStructs.remove(size - 1); - } - completionHandlers.put(overlapped, completionHandler); - return overlapped; - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 0c1e35fc..a6636ca5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -54,14 +54,10 @@ */ public class WindowsUSBDeviceRegistry extends USBDeviceRegistry { - /// Windows completion port for asynchronous/overlapped IO + /** + * Windows completion port for asynchronous/overlapped IO + */ private MemorySegment asyncIoCompletionPort = NULL; - /// last used completion key - private long lastUsedCompletionKey; - /// USB devices indexed by completion key - private Map devicesByCompletionKey; - /// completion keys indexed by Windows device handle - private Map completionKeysByHandle; @Override protected void monitorDevices() { @@ -546,21 +542,25 @@ private void asyncCompletionTask() { int res = Kernel32B.GetQueuedCompletionStatus(asyncIoCompletionPort, numBytesHolder, completionKeyHolder, overlappedHolder, Kernel32.INFINITE(), lastErrorState); - var overlapped = overlappedHolder.get(ADDRESS, 0); + var overlappedAddr = overlappedHolder.get(JAVA_LONG, 0); - if (res == 0 && overlapped == MemorySegment.NULL) + if (res == 0 && overlappedAddr == 0) throwLastError(lastErrorState, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); - if (overlapped == MemorySegment.NULL) - return; // registry is closing + if (overlappedAddr == 0) + return; // registry is closing? - long completionKey = completionKeyHolder.get(JAVA_LONG, 0); - var device = devicesByCompletionKey.get(completionKey); + var request = getRequest(overlappedAddr); + if (request != null) + request.completionHandler.completed(request); - if (device != null) { - overlapped = OVERLAPPED.ofAddress(overlapped, SegmentScope.global()); - device.onAsyncIoCompleted(overlapped); - } +// long completionKey = completionKeyHolder.get(JAVA_LONG, 0); +// var device = devicesByCompletionKey.get(completionKey); +// +// if (device != null) { +// overlapped = OVERLAPPED.ofAddress(overlapped, SegmentScope.global()); +// device.onAsyncIoCompleted(overlapped); +// } } } } @@ -573,46 +573,70 @@ private void asyncCompletionTask() { */ synchronized void addToCompletionPort(MemorySegment handle, WindowsUSBDevice device) { - lastUsedCompletionKey += 1; - var completionKey = Long.valueOf(lastUsedCompletionKey); - if (devicesByCompletionKey == null) { - devicesByCompletionKey = new HashMap<>(); - completionKeysByHandle = new HashMap<>(); - } - devicesByCompletionKey.put(completionKey, device); - completionKeysByHandle.put(handle, completionKey); - try (var arena = Arena.openConfined()) { var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); // Creates a new port if it doesn't exist; adds handle to existing port if it exists MemorySegment portHandle = Kernel32B.CreateIoCompletionPort(handle, asyncIoCompletionPort, - lastUsedCompletionKey, 0, lastErrorState); + handle.address(), 0, lastErrorState); if (portHandle == MemorySegment.NULL) throwLastError(lastErrorState, "internal error (CreateIoCompletionPort)"); if (asyncIoCompletionPort == MemorySegment.NULL) { asyncIoCompletionPort = portHandle; - - // start background thread for handling IO completion - Thread t = new Thread(this::asyncCompletionTask, "USB async IO"); - t.setDaemon(true); - t.start(); + startAsyncIOTask(); } } } - /** - * Removes a handle from the dispatching. - *

- * The handle is removed from the completion port by closing the device. - *

- * - * @param handle Windows device handle - */ - synchronized void removeFromCompletionPort(MemorySegment handle) { - Long completionKey = completionKeysByHandle.get(handle); - completionKeysByHandle.remove(handle); - devicesByCompletionKey.remove(completionKey); + void startAsyncIOTask() { + availableOverlappedStructs = new ArrayList<>(); + arena = Arena.openShared(); + requestsByOverlapped = new HashMap<>(); + + // start background thread for handling IO completion + Thread t = new Thread(this::asyncCompletionTask, "USB async IO"); + t.setDaemon(true); + t.start(); + } + + // Currently outstanding transfer requests, + // indexed by OVERLAPPED address. + private Map requestsByOverlapped; + // available OVERLAPPED data structures + private List availableOverlappedStructs; + // Arena used to allocate OVERLAPPED data structures + private Arena arena; + + void addOverlapped(WindowsTransfer request) { + MemorySegment overlapped; + int size = availableOverlappedStructs.size(); + if (size == 0) { + overlapped = arena.allocate(OVERLAPPED.$LAYOUT()); + } else { + overlapped = availableOverlappedStructs.remove(size - 1); + } + + request.overlapped = overlapped; + requestsByOverlapped.put(overlapped.address(), request); + } + + private synchronized WindowsTransfer getRequest(long overlappedAddr) { + var request = requestsByOverlapped.remove(overlappedAddr); + if (request == null) + return null; + + request.resultCode = (int) OVERLAPPED.Internal$get(request.overlapped); + request.resultSize = (int) OVERLAPPED.InternalHigh$get(request.overlapped); + + availableOverlappedStructs.add(request.overlapped); + request.overlapped = null; + return request; + } + + synchronized WindowsTransfer createRequest() { + var request = new WindowsTransfer(); + request.resultSize = -1; + return request; } } From a44fd56d67c4b0c56630021e28e68a3e70bfc272 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 24 Feb 2023 14:33:03 +0100 Subject: [PATCH 206/433] Asynchronous code refactoring (Linux) --- .../usb/common/EndpointInputStream.java | 2 +- .../usb/common/EndpointOutputStream.java | 2 +- .../net/codecrete/usb/common/Transfer.java | 2 +- .../codecrete/usb/linux/LinuxAsyncTask.java | 296 ++++++++++++++++++ .../codecrete/usb/linux/LinuxUSBDevice.java | 26 +- .../usb/linux/LinuxUSBDeviceRegistry.java | 240 +------------- .../codecrete/usb/macos/MacosAsyncTask.java | 2 +- .../codecrete/usb/macos/MacosUSBDevice.java | 8 +- .../usb/windows/WindowsUSBDeviceRegistry.java | 2 +- 9 files changed, 319 insertions(+), 261 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index dfb3fa59..71c5a0c4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -73,7 +73,7 @@ protected EndpointInputStream(USBDeviceImpl device, int endpointNumber) { final var transfer = device.createTransfer(); transfer.data = arena.allocate(bufferSize, 8); transfer.dataSize = bufferSize; - transfer.completionHandler = this::onCompletion; + transfer.completion = this::onCompletion; if (i == 0) { currentTransfer = transfer; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java index cf234c91..46b32d79 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -75,7 +75,7 @@ protected EndpointOutputStream(USBDeviceImpl device, int endpointNumber) { for (int i = 0; i < MAX_OUTSTANDING_TRANSFERS; i++) { final var transfer = device.createTransfer(); transfer.data = arena.allocate(bufferSize, 8); - transfer.completionHandler = this::onCompletion; + transfer.completion = this::onCompletion; if (i == 0) { currentTransfer = transfer; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/Transfer.java b/java-does-usb/src/main/java/net/codecrete/usb/common/Transfer.java index a12e158e..efc294f3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/Transfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/Transfer.java @@ -35,5 +35,5 @@ public class Transfer { /** * Completion handler to call when the transfer is complete. */ - public TransferCompletion completionHandler; + public TransferCompletion completion; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java new file mode 100644 index 00000000..23c1050e --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -0,0 +1,296 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.linux; + +import net.codecrete.usb.linux.gen.errno.errno; +import net.codecrete.usb.linux.gen.poll.poll; +import net.codecrete.usb.linux.gen.poll.pollfd; +import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_urb; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SegmentScope; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static net.codecrete.usb.linux.LinuxUSBException.throwException; +import static net.codecrete.usb.linux.LinuxUSBException.throwLastError; +import static net.codecrete.usb.linux.USBDevFS.*; +import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.USBDEVFS_URB_TYPE_BULK; + +/** + * Background task for handling asynchronous transfers. + *

+ * Each USB device must register its file handler with this task. + *

+ *

+ * The task keeps track of the submitted transfers by remembering the + * URB address (USB request buffer) in order to match it to the + * completion. + *

+ *

+ * URBs are allocated but never freed. To limit the memory usage, + * URBs are reused. So the maximum number of outstanding transfers + * determines the number of allocated URBs. + *

+ */ +public class LinuxAsyncTask { + private static LinuxAsyncTask singletonInstance; + + /** + * Singleton instance of background task. + * + * @return background task + */ + static synchronized LinuxAsyncTask instance() { + if (singletonInstance == null) + singletonInstance = new LinuxAsyncTask(); + return singletonInstance; + } + + private final SegmentAllocator GLOBAL_ALLOCATOR = SegmentAllocator.nativeAllocator(SegmentScope.global()); + /// available URBs + private final List availableURBs = new ArrayList<>(); + /// map of URB addresses to transfer (for outstanding transfers) + private final Map transfersByURB = new HashMap<>(); + /// array of file descriptors using asynchronous completion + private int[] asyncFds; + /// file descriptor to notify async IO background thread about an update + private int asyncIOUpdateEventFd; + + /** + * Background task for handling asynchronous IO completions. + */ + private void asyncCompletionTask() { + + try (var arena = Arena.openConfined()) { + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); + var asyncPolls = pollfd.allocateArray(100, arena); + var urbPointerHolder = arena.allocate(ADDRESS); + var eventfdValueHolder = arena.allocate(JAVA_LONG); + + while (true) { + + // get current file descriptor array + int[] fds; + synchronized (this) { + fds = asyncFds; + } + + // prepare pollfd struct array + var n = fds.length; + for (int i = 0; i < n; i++) { + pollfd.fd$set(asyncPolls, i, fds[i]); + pollfd.events$set(asyncPolls, i, (short) (poll.POLLIN() | poll.POLLOUT())); + pollfd.revents$set(asyncPolls, i, (short) 0); + } + + pollfd.fd$set(asyncPolls, n, asyncIOUpdateEventFd); + pollfd.events$set(asyncPolls, n, (short) poll.POLLIN()); + pollfd.revents$set(asyncPolls, n, (short) 0); + + // poll for event + int res = poll.poll(asyncPolls, n + 1, -1); + if (res < 0) + throwException("internal error (poll)"); + + // check for events + for (int i = 0; i < n + 1; i++) { + var revent = pollfd.revents$get(asyncPolls, i); + if (revent == 0) + continue; + + if ((revent & poll.POLLERR()) != 0) { + // most likely the device has been disconnected; ignore + continue; + } + + if (i != n) { + // reap URB + int fd = pollfd.fd$get(asyncPolls, i); + reapURB(fd, urbPointerHolder, errnoState); + + } else { + // wakeup to refresh list of file descriptors + res = IO.eventfd_read(asyncIOUpdateEventFd, eventfdValueHolder, errnoState); + if (res < 0) + throwLastError(errnoState, "internal error (eventfd_read)"); + } + } + + } + } + } + + private void reapURB(int fd, MemorySegment urbPointerHolder, MemorySegment errnoState) { + int res; + res = IO.ioctl(fd, REAPURB, urbPointerHolder, errnoState); + if (res < 0) { + var err = Linux.getErrno(errnoState); + if (err == errno.EBADF()) + return; // ignore, device might have been closed + throwException(err, "internal error (reap URB)"); + } + + // call completion handler + var urbAddr = urbPointerHolder.get(JAVA_LONG, 0); + var transfer = getTransferResult(urbAddr); + transfer.completion.completed(transfer); + } + + /** + * Notifies background process about changed FD list + */ + private void notifyAsyncIOTask() { + // start background process if needed + if (asyncIOUpdateEventFd == 0) { + startAsyncIOHandler(); + return; + } + + try (var arena = Arena.openConfined()) { + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); + if (IO.eventfd_write(asyncIOUpdateEventFd, 1, errnoState) < 0) + throwLastError(errnoState, "internal error (eventfd_write)"); + } + } + + /** + * Register a device for asynchronous IO completion handling + * + * @param device USB device + */ + synchronized void addForAsyncIOCompletion(LinuxUSBDevice device) { + int n = asyncFds != null ? asyncFds.length : 0; + int[] fds = new int[n + 1]; + if (n > 0) + System.arraycopy(asyncFds, 0, fds, 0, n); + fds[n] = device.fileDescriptor(); + + // activate new array + asyncFds = fds; + notifyAsyncIOTask(); + } + + /** + * Unregisters a device from asynchronous IO completion handling. + * + * @param device USB device + */ + synchronized void removeFromAsyncIOCompletion(LinuxUSBDevice device) { + // copy file descriptor (except the device's) into new array + int n = asyncFds.length; + if (n == 0) { + System.err.println("internal error (file descriptor not found) - ignoring"); + return; + } + + int fd = device.fileDescriptor(); + int[] fds = new int[n - 1]; + int tgt = 0; + for (int asyncFd : asyncFds) { + if (asyncFd != fd) { + if (tgt == n) { + System.err.println("internal error (file descriptor not found) - ignoring"); + return; + } + fds[tgt] = asyncFd; + tgt += 1; + } + } + + // make new array to active one + asyncFds = fds; + notifyAsyncIOTask(); + } + + synchronized void submitBulkTransfer(LinuxUSBDevice device, int endpointAddress, LinuxTransfer transfer) { + + addURB(transfer); + var urb = transfer.urb; + + usbdevfs_urb.type$set(urb, (byte) USBDEVFS_URB_TYPE_BULK()); + usbdevfs_urb.endpoint$set(urb, (byte) endpointAddress); + usbdevfs_urb.buffer$set(urb, transfer.data); + usbdevfs_urb.buffer_length$set(urb, transfer.dataSize); + usbdevfs_urb.usercontext$set(urb, MemorySegment.ofAddress(device.fileDescriptor())); + + try (var arena = Arena.openConfined()) { + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); + if (IO.ioctl(device.fileDescriptor(), SUBMITURB, urb, errnoState) < 0) { + String action = endpointAddress >= 128 ? "reading from" : "writing to"; + throwLastError(errnoState, "failed %s endpoint %d", action, endpointAddress); + } + } + } + + private void addURB(LinuxTransfer transfer) { + MemorySegment urb; + int size = availableURBs.size(); + if (size > 0) { + urb = availableURBs.remove(size - 1); + } else { + urb = usbdevfs_urb.allocate(GLOBAL_ALLOCATOR); + } + + transfer.urb = urb; + transfersByURB.put(urb.address(), transfer); + } + + private synchronized LinuxTransfer getTransferResult(long urbAddr) { + var transfer = transfersByURB.remove(urbAddr); + if (transfer == null) + throwException("internal error (unknown URB)"); + + transfer.resultCode = usbdevfs_urb.status$get(transfer.urb); + transfer.resultSize = usbdevfs_urb.actual_length$get(transfer.urb); + + availableURBs.add(transfer.urb); + transfer.urb = null; + return transfer; + } + + synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { + int fd = device.fileDescriptor(); + try (var arena = Arena.openConfined()) { + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); + + for (var urbAddress : transfersByURB.keySet()) { + var urb = usbdevfs_urb.ofAddress(MemorySegment.ofAddress(urbAddress), SegmentScope.global()); + if (fd != (int) usbdevfs_urb.usercontext$get(urb).address()) + continue; + if (endpointAddress != usbdevfs_urb.endpoint$get(urb)) + continue; + + if (IO.ioctl(fd, DISCARDURB, urb, errnoState) < 0) + throwLastError(errnoState, "failed to cancel transfer"); + } + } + } + + private void startAsyncIOHandler() { + try (var arena = Arena.openConfined()) { + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); + asyncIOUpdateEventFd = IO.eventfd(0, 0, errnoState); + if (asyncIOUpdateEventFd == -1) { + asyncIOUpdateEventFd = 0; + throwLastError(errnoState, "internal error (eventfd)"); + } + } + + // start background thread for handling IO completion + Thread t = new Thread(this::asyncCompletionTask, "USB async IO"); + t.setDaemon(true); + t.start(); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index b6def580..91b8034d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -36,11 +36,11 @@ public class LinuxUSBDevice extends USBDeviceImpl { private int fd = -1; - private final LinuxUSBDeviceRegistry registry; + private final LinuxAsyncTask asyncTask; - LinuxUSBDevice(LinuxUSBDeviceRegistry registry, Object id, int vendorId, int productId) { + LinuxUSBDevice(Object id, int vendorId, int productId) { super(id, vendorId, productId); - this.registry = registry; + asyncTask = LinuxAsyncTask.instance(); loadDescription((String) id); } @@ -65,7 +65,7 @@ public boolean isOpen() { } @Override - public void open() { + public synchronized void open() { if (isOpen()) throwException("the device is already open"); @@ -75,16 +75,16 @@ public void open() { fd = IO.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC(), errnoState); if (fd == -1) throwLastError(errnoState, "Cannot open USB device"); - registry.addForAsyncIOCompletion(this); + asyncTask.addForAsyncIOCompletion(this); } } @Override - public void close() { + public synchronized void close() { if (!isOpen()) return; - registry.removeFromAsyncIOCompletion(this); + asyncTask.removeFromAsyncIOCompletion(this); for (var intf : interfaces_) ((USBInterfaceImpl) intf).setClaimed(false); @@ -97,7 +97,7 @@ int fileDescriptor() { return fd; } - public void claimInterface(int interfaceNumber) { + public synchronized void claimInterface(int interfaceNumber) { checkIsOpen(); var intf = getInterface(interfaceNumber); @@ -117,7 +117,7 @@ public void claimInterface(int interfaceNumber) { } @Override - public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { + public synchronized void selectAlternateSetting(int interfaceNumber, int alternateNumber) { checkIsOpen(); var intf = getInterface(interfaceNumber); @@ -145,7 +145,7 @@ public void selectAlternateSetting(int interfaceNumber, int alternateNumber) { intf.setAlternate(altSetting); } - public void releaseInterface(int interfaceNumber) { + public synchronized void releaseInterface(int interfaceNumber) { checkIsOpen(); var intf = getInterface(interfaceNumber); @@ -287,7 +287,7 @@ public void clearHalt(USBDirection direction, int endpointNumber) { public synchronized void abortTransfers(USBDirection direction, int endpointNumber) { var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); - registry.abortTransfers(this, endpoint.endpointAddress()); + asyncTask.abortTransfers(this, endpoint.endpointAddress()); } @Override @@ -308,11 +308,11 @@ public OutputStream openOutputStream(int endpointNumber) { synchronized void submitTransferIn(int endpointNumber, LinuxTransfer transfer) { var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); - registry.submitBulkTransfer(this, endpoint.endpointAddress(), transfer); + asyncTask.submitBulkTransfer(this, endpoint.endpointAddress(), transfer); } synchronized void submitTransferOut(int endpointNumber, LinuxTransfer transfer) { var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); - registry.submitBulkTransfer(this, endpoint.endpointAddress(), transfer); + asyncTask.submitBulkTransfer(this, endpoint.endpointAddress(), transfer); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 734e1001..20e2c537 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -10,27 +10,18 @@ import net.codecrete.usb.USBDevice; import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.common.USBDeviceRegistry; -import net.codecrete.usb.linux.gen.errno.errno; import net.codecrete.usb.linux.gen.poll.poll; import net.codecrete.usb.linux.gen.poll.pollfd; import net.codecrete.usb.linux.gen.udev.udev; -import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_urb; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; import java.lang.foreign.SegmentScope; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_LONG; import static net.codecrete.usb.linux.LinuxUSBException.throwException; -import static net.codecrete.usb.linux.LinuxUSBException.throwLastError; -import static net.codecrete.usb.linux.USBDevFS.*; -import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.USBDEVFS_URB_TYPE_BULK; /** * Linux implementation of USB device registry. @@ -48,15 +39,6 @@ public class LinuxUSBDeviceRegistry extends USBDeviceRegistry { private final MemorySegment ATTR_PRODUCT = GLOBAL_ALLOCATOR.allocateUtf8String("product"); private final MemorySegment ATTR_SERIAL = GLOBAL_ALLOCATOR.allocateUtf8String("serial"); - /// available URBs - private final List availableURBs = new ArrayList<>(); - /// map of URB address to completion handler (for outstanding requests) - private final Map completionHandlerByURB = new HashMap<>(); - /// array of file descriptors using asynchronous completion - private int[] asyncFds; - /// file descriptor to notify async IO background thread about an update - private int asyncIOUpdateEventFd; - @Override protected void monitorDevices() { @@ -215,7 +197,7 @@ private USBDevice getDeviceDetails(MemorySegment udevDevice) { productId = Integer.parseInt(idProduct, 16); // create device instance - var device = new LinuxUSBDevice(this, devPath, vendorId, productId); + var device = new LinuxUSBDevice(devPath, vendorId, productId); device.setProductStrings(getDeviceAttribute(udevDevice, ATTR_MANUFACTURER), getDeviceAttribute(udevDevice , ATTR_PRODUCT), getDeviceAttribute(udevDevice, ATTR_SERIAL)); @@ -261,224 +243,4 @@ private static void waitForFileDescriptor(int fd, Arena arena) { throwException("internal error (poll)"); } - /** - * Background task for handling asynchronous IO completions. - */ - private void asyncCompletionTask() { - - try (var arena = Arena.openConfined()) { - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); - var asyncPolls = pollfd.allocateArray(100, arena); - var urbPointerHolder = arena.allocate(ADDRESS); - var eventfdValueHolder = arena.allocate(JAVA_LONG); - - while (true) { - - // get current file descriptor array - int[] fds; - synchronized (this) { - fds = asyncFds; - } - - // prepare pollfd struct array - var n = fds.length; - for (int i = 0; i < n; i++) { - pollfd.fd$set(asyncPolls, i, fds[i]); - pollfd.events$set(asyncPolls, i, (short) (poll.POLLIN() | poll.POLLOUT())); - pollfd.revents$set(asyncPolls, i, (short) 0); - } - - pollfd.fd$set(asyncPolls, n, asyncIOUpdateEventFd); - pollfd.events$set(asyncPolls, n, (short) poll.POLLIN()); - pollfd.revents$set(asyncPolls, n, (short) 0); - - // poll for event - int res = poll.poll(asyncPolls, n + 1, -1); - if (res < 0) - throwException("internal error (poll)"); - - // check for events - for (int i = 0; i < n + 1; i++) { - var revent = pollfd.revents$get(asyncPolls, i); - if (revent == 0) - continue; - - if ((revent & poll.POLLERR()) != 0) { - // TODO - System.err.println("Error in asynchronous request"); - continue; - } - - if (i != n) { - // reap URB - int fd = pollfd.fd$get(asyncPolls, i); - reapURB(fd, urbPointerHolder, errnoState); - - } else { - res = IO.eventfd_read(asyncIOUpdateEventFd, eventfdValueHolder, errnoState); - if (res < 0) - throwLastError(errnoState, "internal error (eventfd_read)"); - } - } - - } - } - } - - private void reapURB(int fd, MemorySegment urbPointerHolder, MemorySegment errnoState) { - int res; - res = IO.ioctl(fd, REAPURB, urbPointerHolder, errnoState); - if (res < 0) { - var err = Linux.getErrno(errnoState); - if (err == errno.EBADF()) - return; // ignore, device might have been closed - throwException(err, "internal error (reap URB)"); - } - - var urbAddr = urbPointerHolder.get(JAVA_LONG, 0); - var transfer = getRequest(urbAddr); - - // call completion handler - transfer.completionHandler.completed(transfer); - } - - /** - * Notifies background process about changed FD list - */ - private void notifyAsyncIOTask() { - // start background process if needed - if (asyncIOUpdateEventFd == 0) { - startAsyncIOHandler(); - return; - } - - try (var arena = Arena.openConfined()) { - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); - if (IO.eventfd_write(asyncIOUpdateEventFd, 1, errnoState) < 0) - throwLastError(errnoState, "internal error (eventfd_write)"); - } - } - - /** - * Register a device for asynchronous IO completion handling - * - * @param device USB device - */ - synchronized void addForAsyncIOCompletion(LinuxUSBDevice device) { - int n = asyncFds != null ? asyncFds.length : 0; - int[] fds = new int[n + 1]; - if (n > 0) - System.arraycopy(asyncFds, 0, fds, 0, n); - fds[n] = device.fileDescriptor(); - - // activate new array - asyncFds = fds; - notifyAsyncIOTask(); - } - - /** - * Unregisters a device from asynchronous IO completion handling. - * - * @param device USB device - */ - synchronized void removeFromAsyncIOCompletion(LinuxUSBDevice device) { - // copy file descriptor (except the device's) into new array - int n = asyncFds.length; - if (n == 0) - return; - - int fd = device.fileDescriptor(); - int[] fds = new int[n - 1]; - int tgt = 0; - for (int asyncFd : asyncFds) { - if (asyncFd != fd) { - if (tgt == n) - return; - fds[tgt] = asyncFd; - tgt += 1; - } - } - - // activate new array - asyncFds = fds; - notifyAsyncIOTask(); - } - - synchronized void submitBulkTransfer(LinuxUSBDevice device, int endpointAddress, LinuxTransfer request) { - - addURB(request); - var urb = request.urb; - - usbdevfs_urb.type$set(urb, (byte) USBDEVFS_URB_TYPE_BULK()); - usbdevfs_urb.endpoint$set(urb, (byte) endpointAddress); - usbdevfs_urb.buffer$set(urb, request.data); - usbdevfs_urb.buffer_length$set(urb, request.dataSize); - usbdevfs_urb.usercontext$set(urb, MemorySegment.ofAddress(device.fileDescriptor())); - - try (var arena = Arena.openConfined()) { - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); - if (IO.ioctl(device.fileDescriptor(), SUBMITURB, urb, errnoState) < 0) - throwLastError(errnoState, "failed to submit bulk transfer request"); - } - } - - void addURB(LinuxTransfer request) { - MemorySegment urb; - int size = availableURBs.size(); - if (size > 0) { - urb = availableURBs.remove(size - 1); - } else { - urb = usbdevfs_urb.allocate(GLOBAL_ALLOCATOR); - } - - request.urb = urb; - completionHandlerByURB.put(urb.address(), request); - } - - private synchronized LinuxTransfer getRequest(long urbAddr) { - var request = completionHandlerByURB.remove(urbAddr); - if (request == null) - return null; - - request.resultCode = usbdevfs_urb.status$get(request.urb); - request.resultSize = usbdevfs_urb.actual_length$get(request.urb); - - availableURBs.add(request.urb); - request.urb = null; - return request; - } - - synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { - int fd = device.fileDescriptor(); - try (var arena = Arena.openConfined()) { - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); - - for (var urbAddress : completionHandlerByURB.keySet()) { - var urb = usbdevfs_urb.ofAddress(MemorySegment.ofAddress(urbAddress), SegmentScope.global()); - if (fd != (int) usbdevfs_urb.usercontext$get(urb).address()) - continue; - if (endpointAddress != usbdevfs_urb.endpoint$get(urb)) - continue; - - if (IO.ioctl(fd, DISCARDURB, urb, errnoState) < 0) - throwLastError(errnoState, "failed to cancel transfer request"); - } - } - } - - private void startAsyncIOHandler() { - try (var arena = Arena.openConfined()) { - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); - asyncIOUpdateEventFd = IO.eventfd(0, 0, errnoState); - if (asyncIOUpdateEventFd == -1) { - asyncIOUpdateEventFd = 0; - throwLastError(errnoState, "internal error (eventfd)"); - } - } - - // start background thread for handling IO completion - Thread t = new Thread(this::asyncCompletionTask, "USB async IO"); - t.setDaemon(true); - t.start(); - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java index 404bf927..6a8a0326 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java @@ -179,7 +179,7 @@ private void asyncIOCompleted(MemorySegment refcon, int result, MemorySegment ar transfer.resultCode = result; transfer.resultSize = (int) arg0.address(); - transfer.completionHandler.completed(transfer); + transfer.completion.completed(transfer); } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 2d74fe9b..c87f10f3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -346,7 +346,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { var deviceRequest = createDeviceRequest(arena, USBDirection.IN, setup, data); var transfer = (MacosTransfer) createTransfer(); - transfer.completionHandler = MacosUSBDevice::onTransferCompleted; + transfer.completion = MacosUSBDevice::onTransferCompleted; synchronized (transfer) { submitControlTransfer(deviceRequest, transfer); @@ -367,7 +367,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { var deviceRequest = createDeviceRequest(arena, USBDirection.OUT, setup, dataSegment); var transfer = (MacosTransfer) createTransfer(); - transfer.completionHandler = MacosUSBDevice::onTransferCompleted; + transfer.completion = MacosUSBDevice::onTransferCompleted; synchronized (transfer) { submitControlTransfer(deviceRequest, transfer); @@ -389,7 +389,7 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { var transfer = (MacosTransfer) createTransfer(); transfer.data = nativeData; transfer.dataSize = data.length; - transfer.completionHandler = MacosUSBDevice::onTransferCompleted; + transfer.completion = MacosUSBDevice::onTransferCompleted; synchronized (transfer) { if (timeout <= 0 || epInfo.transferType() == USBTransferType.BULK) { @@ -418,7 +418,7 @@ public byte[] transferIn(int endpointNumber, int timeout) { var transfer = (MacosTransfer) createTransfer(); transfer.data = nativeData; transfer.dataSize = epInfo.packetSize(); - transfer.completionHandler = MacosUSBDevice::onTransferCompleted; + transfer.completion = MacosUSBDevice::onTransferCompleted; synchronized (transfer) { if (timeout <= 0 || epInfo.transferType() == USBTransferType.BULK) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index a6636ca5..4898cc1c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -552,7 +552,7 @@ private void asyncCompletionTask() { var request = getRequest(overlappedAddr); if (request != null) - request.completionHandler.completed(request); + request.completion.completed(request); // long completionKey = completionKeyHolder.get(JAVA_LONG, 0); // var device = devicesByCompletionKey.get(completionKey); From 9c2dcfdbeb414c4737a6f0275b6450c0e37fe175 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 25 Feb 2023 12:52:14 +0100 Subject: [PATCH 207/433] Bulk/interrupt transfer use async IO internally (Linux) --- .gitignore | 2 + java-does-usb/jextract/linux/gen_linux.sh | 1 + .../codecrete/usb/common/USBDeviceImpl.java | 75 +++++++++++++++ .../codecrete/usb/linux/LinuxAsyncTask.java | 44 ++++++--- .../usb/linux/LinuxEndpointInputStream.java | 3 +- .../usb/linux/LinuxEndpointOutputStream.java | 3 +- .../codecrete/usb/linux/LinuxUSBDevice.java | 55 +++++------ .../net/codecrete/usb/linux/USBDevFS.java | 1 + .../codecrete/usb/linux/gen/errno/errno.java | 8 ++ .../codecrete/usb/macos/MacosUSBDevice.java | 94 +++---------------- .../usb/macos/MacosUSBException.java | 3 + reference/linux/usb_registry.cpp | 1 + 12 files changed, 161 insertions(+), 129 deletions(-) diff --git a/.gitignore b/.gitignore index 27dc8f0a..b29b5c47 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +java-does-usb/sample.bin + # Maven target/ *.ser diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index a277c3fd..f629b191 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -17,6 +17,7 @@ $JEXTRACT --source --output ../../src/main/java \ --include-constant ETIMEDOUT \ --include-constant EPIPE \ --include-constant EBADF \ + --include-constant EAGAIN \ /usr/include/errno.h # string.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index f0dcd5a1..75cc76dc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -307,6 +307,66 @@ public byte[] transferIn(int endpointNumber) { @Override public abstract byte[] transferIn(int endpointNumber, int timeout); + protected void waitForTransfer(Transfer transfer, int timeout, USBDirection direction, int endpointNumber) { + if (timeout <= 0) { + waitNoTimeout(transfer); + + } else { + boolean hasTimedOut = waitWithTimeout(transfer, timeout); + + // test for timeout + if (hasTimedOut && transfer.resultCode == 0) { + abortTransfers(direction, endpointNumber); + waitNoTimeout(transfer); + throw new USBTimeoutException(getOperationDescription(direction, endpointNumber) + "aborted due to " + + "timeout"); + } + } + + // test for error + if (transfer.resultCode != 0) { + var operation = getOperationDescription(direction, endpointNumber); + throwOSException(transfer.resultCode, operation + " failed"); + } + } + + private static void waitNoTimeout(Transfer transfer) { + // wait for transfer + while (transfer.resultSize == -1) { + try { + transfer.wait(); + } catch (InterruptedException e) { + // ignore and retry + } + } + } + + private static boolean waitWithTimeout(Transfer transfer, int timeout) { + // wait for transfer to complete, or abort when timeout occurs + long expiration = System.currentTimeMillis() + timeout; + long remainingTimeout = timeout; + while (remainingTimeout > 0 && transfer.resultSize == -1) { + try { + transfer.wait(remainingTimeout); + remainingTimeout = expiration - System.currentTimeMillis(); + + } catch (InterruptedException e) { + // ignore and retry + } + } + + return remainingTimeout <= 0; + } + + protected static String getOperationDescription(USBDirection direction, int endpointNumber) { + if (endpointNumber == 0) { + return "Control transfer"; + } else { + return String.format("Transfer %s on endpoint %d", direction.name(), endpointNumber); + } + + } + /** * Create a transfer object suitable for this device. * @@ -314,6 +374,21 @@ public byte[] transferIn(int endpointNumber) { */ protected abstract Transfer createTransfer(); + /** + * Completion handler used for synchronous, blocking transfers. + *

+ * Calls {@link Object#notify()} so the caller can use + * {@link Object#wait()} to wait for completion. + *

+ * + * @param transfer the transfer that has completed + */ + protected static void onSyncTransferCompleted(Transfer transfer) { + synchronized (transfer) { + transfer.notify(); + } + } + /** * Throws an exception for the specified operating-specific error code. * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index 23c1050e..f6b3f0db 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -70,6 +70,14 @@ static synchronized LinuxAsyncTask instance() { /** * Background task for handling asynchronous IO completions. + *

+ * It polls on all registered file descriptors. If a file descriptor is + * ready, the URB is "reaped". + *

+ *

+ * Using an additional {@code eventfd} file descriptor, this background task + * can be woken up to refresh the list of polled file descriptors. + *

*/ private void asyncCompletionTask() { @@ -91,7 +99,7 @@ private void asyncCompletionTask() { var n = fds.length; for (int i = 0; i < n; i++) { pollfd.fd$set(asyncPolls, i, fds[i]); - pollfd.events$set(asyncPolls, i, (short) (poll.POLLIN() | poll.POLLOUT())); + pollfd.events$set(asyncPolls, i, (short) poll.POLLOUT()); pollfd.revents$set(asyncPolls, i, (short) 0); } @@ -111,7 +119,10 @@ private void asyncCompletionTask() { continue; if ((revent & poll.POLLERR()) != 0) { - // most likely the device has been disconnected; ignore + // most likely the device has been disconnected; + // remove from polled FD list to prevent further problems + int fd = pollfd.fd$get(asyncPolls, i); + removeFdFromAsyncIOCompletion(fd); continue; } @@ -127,16 +138,24 @@ private void asyncCompletionTask() { throwLastError(errnoState, "internal error (eventfd_read)"); } } - } } } + /** + * Reap URB and handle the completed transfer. + * + * @param fd file descriptor + * @param urbPointerHolder native memory to receive the URB pointer + * @param errnoState native memory to receive the errno + */ private void reapURB(int fd, MemorySegment urbPointerHolder, MemorySegment errnoState) { int res; - res = IO.ioctl(fd, REAPURB, urbPointerHolder, errnoState); + res = IO.ioctl(fd, REAPURBNDELAY, urbPointerHolder, errnoState); if (res < 0) { var err = Linux.getErrno(errnoState); + if (err == errno.EAGAIN()) + return; // retry if (err == errno.EBADF()) return; // ignore, device might have been closed throwException(err, "internal error (reap URB)"); @@ -188,22 +207,22 @@ synchronized void addForAsyncIOCompletion(LinuxUSBDevice device) { * @param device USB device */ synchronized void removeFromAsyncIOCompletion(LinuxUSBDevice device) { + removeFdFromAsyncIOCompletion(device.fileDescriptor()); + notifyAsyncIOTask(); + } + + private synchronized void removeFdFromAsyncIOCompletion(int fd) { // copy file descriptor (except the device's) into new array int n = asyncFds.length; - if (n == 0) { - System.err.println("internal error (file descriptor not found) - ignoring"); + if (n == 0) return; - } - int fd = device.fileDescriptor(); int[] fds = new int[n - 1]; int tgt = 0; for (int asyncFd : asyncFds) { if (asyncFd != fd) { - if (tgt == n) { - System.err.println("internal error (file descriptor not found) - ignoring"); + if (tgt == n) return; - } fds[tgt] = asyncFd; tgt += 1; } @@ -211,7 +230,6 @@ synchronized void removeFromAsyncIOCompletion(LinuxUSBDevice device) { // make new array to active one asyncFds = fds; - notifyAsyncIOTask(); } synchronized void submitBulkTransfer(LinuxUSBDevice device, int endpointAddress, LinuxTransfer transfer) { @@ -252,7 +270,7 @@ private synchronized LinuxTransfer getTransferResult(long urbAddr) { if (transfer == null) throwException("internal error (unknown URB)"); - transfer.resultCode = usbdevfs_urb.status$get(transfer.urb); + transfer.resultCode = -usbdevfs_urb.status$get(transfer.urb); transfer.resultSize = usbdevfs_urb.actual_length$get(transfer.urb); availableURBs.add(transfer.urb); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java index 3f16f495..dddbdf66 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java @@ -7,6 +7,7 @@ package net.codecrete.usb.linux; +import net.codecrete.usb.USBDirection; import net.codecrete.usb.common.EndpointInputStream; import net.codecrete.usb.common.Transfer; @@ -18,6 +19,6 @@ public class LinuxEndpointInputStream extends EndpointInputStream { @Override protected void submitTransferIn(Transfer transfer) { - ((LinuxUSBDevice) device).submitTransferIn(endpointNumber, (LinuxTransfer) transfer); + ((LinuxUSBDevice) device).submitBulkTransfer(USBDirection.IN, endpointNumber, (LinuxTransfer) transfer); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java index be083067..ffaae2a6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java @@ -7,6 +7,7 @@ package net.codecrete.usb.linux; +import net.codecrete.usb.USBDirection; import net.codecrete.usb.common.EndpointOutputStream; import net.codecrete.usb.common.Transfer; @@ -18,6 +19,6 @@ public class LinuxEndpointOutputStream extends EndpointOutputStream { @Override protected void submitTransferOut(Transfer transfer) { - ((LinuxUSBDevice) device).submitTransferOut(endpointNumber, (LinuxTransfer) transfer); + ((LinuxUSBDevice) device).submitBulkTransfer(USBDirection.OUT, endpointNumber, (LinuxTransfer) transfer); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 91b8034d..9c80638f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -7,14 +7,15 @@ package net.codecrete.usb.linux; -import net.codecrete.usb.*; +import net.codecrete.usb.USBControlTransfer; +import net.codecrete.usb.USBDirection; +import net.codecrete.usb.USBException; +import net.codecrete.usb.USBTransferType; import net.codecrete.usb.common.Transfer; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.common.USBInterfaceImpl; -import net.codecrete.usb.linux.gen.errno.errno; import net.codecrete.usb.linux.gen.fcntl.fcntl; import net.codecrete.usb.linux.gen.unistd.unistd; -import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_bulktransfer; import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_ctrltransfer; import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_setinterface; import net.codecrete.usb.usbstandard.DeviceDescriptor; @@ -209,12 +210,12 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { } } - private MemorySegment createBulkTransfer(Arena arena, byte endpointAddress, MemorySegment data, int timeout) { - var transfer = arena.allocate(usbdevfs_bulktransfer.$LAYOUT()); - usbdevfs_bulktransfer.ep$set(transfer, 255 & endpointAddress); - usbdevfs_bulktransfer.len$set(transfer, (int) data.byteSize()); - usbdevfs_bulktransfer.data$set(transfer, data); - usbdevfs_bulktransfer.timeout$set(transfer, timeout); + private LinuxTransfer createSyncTransfer(MemorySegment data) { + var transfer = new LinuxTransfer(); + transfer.data = data; + transfer.dataSize = (int) data.byteSize(); + transfer.resultSize = -1; + transfer.completion = USBDeviceImpl::onSyncTransferCompleted; return transfer; } @@ -225,15 +226,11 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { try (var arena = Arena.openConfined()) { var buffer = arena.allocate(data.length); buffer.copyFrom(MemorySegment.ofArray(data)); - var transfer = createBulkTransfer(arena, endpoint.endpointAddress(), buffer, timeout); + var transfer = createSyncTransfer(buffer); - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); - int res = IO.ioctl(fd, USBDevFS.BULK, transfer, errnoState); - if (res < 0) { - int err = Linux.getErrno(errnoState); - if (err == errno.ETIMEDOUT()) - throw new USBTimeoutException("Transfer out aborted due to timeout"); - throwLastError(errnoState, "USB OUT transfer on endpoint %d failed", endpointNumber); + synchronized (transfer) { + asyncTask.submitBulkTransfer(this, endpoint.endpointAddress(), transfer); + waitForTransfer(transfer, timeout, USBDirection.OUT, endpointNumber); } } } @@ -244,19 +241,14 @@ public byte[] transferIn(int endpointNumber, int timeout) { try (var arena = Arena.openConfined()) { var buffer = arena.allocate(endpoint.packetSize()); + var transfer = createSyncTransfer(buffer); - var transfer = createBulkTransfer(arena, endpoint.endpointAddress(), buffer, timeout); - - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); - int res = IO.ioctl(fd, USBDevFS.BULK, transfer, errnoState); - if (res < 0) { - int err = Linux.getErrno(errnoState); - if (err == errno.ETIMEDOUT()) - throw new USBTimeoutException("Transfer in aborted due to timeout"); - throwLastError(errnoState, "USB IN transfer on endpoint %d failed", endpointNumber); + synchronized (transfer) { + asyncTask.submitBulkTransfer(this, endpoint.endpointAddress(), transfer); + waitForTransfer(transfer, timeout, USBDirection.IN, endpointNumber); } - return buffer.asSlice(0, res).toArray(JAVA_BYTE); + return buffer.asSlice(0, transfer.resultSize).toArray(JAVA_BYTE); } } @@ -306,13 +298,8 @@ public OutputStream openOutputStream(int endpointNumber) { return new LinuxEndpointOutputStream(this, endpointNumber); } - synchronized void submitTransferIn(int endpointNumber, LinuxTransfer transfer) { - var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); - asyncTask.submitBulkTransfer(this, endpoint.endpointAddress(), transfer); - } - - synchronized void submitTransferOut(int endpointNumber, LinuxTransfer transfer) { - var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); + synchronized void submitBulkTransfer(USBDirection direction, int endpointNumber, LinuxTransfer transfer) { + var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, null); asyncTask.submitBulkTransfer(this, endpoint.endpointAddress(), transfer); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java index 27b68e1c..8fe31c10 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java @@ -21,6 +21,7 @@ public class USBDevFS { public static final long SUBMITURB = 0x8038550AL; public static final long DISCARDURB = 0x550BL; public static final long REAPURB = 0x4008550CL; + public static final long REAPURBNDELAY = 0x4008550DL; public static final long RESETEP = 0x80045503L; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java index 40fbb4cf..84524ec7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -21,6 +21,14 @@ public class errno { public static int EBADF() { return (int)9L; } + /** + * {@snippet : + * #define EAGAIN 11 + * } + */ + public static int EAGAIN() { + return (int)11L; + } /** * {@snippet : * #define EPIPE 32 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index c87f10f3..2c69fe44 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -9,7 +9,6 @@ import net.codecrete.usb.USBControlTransfer; import net.codecrete.usb.USBDirection; -import net.codecrete.usb.USBTimeoutException; import net.codecrete.usb.USBTransferType; import net.codecrete.usb.common.ForeignMemory; import net.codecrete.usb.common.ScopeCleanup; @@ -345,12 +344,12 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { var data = arena.allocate(length); var deviceRequest = createDeviceRequest(arena, USBDirection.IN, setup, data); - var transfer = (MacosTransfer) createTransfer(); - transfer.completion = MacosUSBDevice::onTransferCompleted; + var transfer = new MacosTransfer(); + transfer.completion = USBDeviceImpl::onSyncTransferCompleted; synchronized (transfer) { submitControlTransfer(deviceRequest, transfer); - waitForTransfer(transfer, USBDirection.IN, 0, false); + waitForTransfer(transfer, 0, USBDirection.IN, 0); } return data.asSlice(0, transfer.resultSize).toArray(JAVA_BYTE); @@ -366,12 +365,12 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { dataSegment.copyFrom(MemorySegment.ofArray(data)); var deviceRequest = createDeviceRequest(arena, USBDirection.OUT, setup, dataSegment); - var transfer = (MacosTransfer) createTransfer(); - transfer.completion = MacosUSBDevice::onTransferCompleted; + var transfer = new MacosTransfer(); + transfer.completion = USBDeviceImpl::onSyncTransferCompleted; synchronized (transfer) { submitControlTransfer(deviceRequest, transfer); - waitForTransfer(transfer, USBDirection.OUT, 0, false); + waitForTransfer(transfer, 0, USBDirection.OUT, 0); } } } @@ -386,21 +385,21 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { var nativeData = arena.allocateArray(JAVA_BYTE, data.length); nativeData.copyFrom(MemorySegment.ofArray(data)); - var transfer = (MacosTransfer) createTransfer(); + var transfer = new MacosTransfer(); transfer.data = nativeData; transfer.dataSize = data.length; - transfer.completion = MacosUSBDevice::onTransferCompleted; + transfer.completion = USBDeviceImpl::onSyncTransferCompleted; synchronized (transfer) { if (timeout <= 0 || epInfo.transferType() == USBTransferType.BULK) { // no timeout or timeout handled by operating system submitTransferOut(endpointNumber, transfer, timeout); - waitForTransfer(transfer, USBDirection.OUT, endpointNumber, false); + waitForTransfer(transfer, 0, USBDirection.OUT, endpointNumber); } else { // interrupt transfer with timeout submitTransferOut(endpointNumber, transfer, 0); - waitForTransferTO(transfer, timeout, USBDirection.OUT, endpointNumber); + waitForTransfer(transfer, timeout, USBDirection.OUT, endpointNumber); } } } @@ -415,21 +414,21 @@ public byte[] transferIn(int endpointNumber, int timeout) { try (var arena = Arena.openConfined()) { var nativeData = arena.allocateArray(JAVA_BYTE, epInfo.packetSize()); - var transfer = (MacosTransfer) createTransfer(); + var transfer = new MacosTransfer(); transfer.data = nativeData; transfer.dataSize = epInfo.packetSize(); - transfer.completion = MacosUSBDevice::onTransferCompleted; + transfer.completion = USBDeviceImpl::onSyncTransferCompleted; synchronized (transfer) { if (timeout <= 0 || epInfo.transferType() == USBTransferType.BULK) { // no timeout, or timeout handled by operating system submitTransferIn(endpointNumber, transfer, timeout); - waitForTransfer(transfer, USBDirection.IN, endpointNumber, false); + waitForTransfer(transfer, 0, USBDirection.IN, endpointNumber); } else { // interrupt transfer with timeout submitTransferIn(endpointNumber, transfer, 0); - waitForTransferTO(transfer, timeout, USBDirection.IN, endpointNumber); + waitForTransfer(transfer, timeout, USBDirection.IN, endpointNumber); } } @@ -516,76 +515,11 @@ synchronized void submitControlTransfer(MemorySegment deviceRequest, MacosTransf throwException(ret, "failed to execute control transfer"); } - private void waitForTransfer(MacosTransfer transfer, USBDirection direction, int endpointNumber, - boolean ignoreAbort) { - // wait for transfer - while (transfer.resultSize == -1) { - try { - transfer.wait(); - } catch (InterruptedException e) { - // ignore and retry - } - } - - // test for error - if (transfer.resultCode != 0) { - var operation = getOperationDescription(direction, endpointNumber); - if (transfer.resultCode == IOKit.kIOUSBTransactionTimeout()) - throw new USBTimeoutException(operation + "aborted due to timeout"); - if (transfer.resultCode != IOKit.kIOReturnAborted() || !ignoreAbort) - throwException(transfer.resultCode, operation + " failed"); - } - } - - private void waitForTransferTO(MacosTransfer transfer, int timeout, USBDirection direction, int endpointNumber) { - // wait for transfer to complete, or abort when timeout occurs - long expiration = System.currentTimeMillis() + timeout; - long remainingTimeout = timeout; - while (remainingTimeout > 0 && transfer.resultSize == -1) { - try { - transfer.wait(remainingTimeout); - remainingTimeout = expiration - System.currentTimeMillis(); - - } catch (InterruptedException e) { - // ignore and retry - } - } - - // test for timeout - if (transfer.resultCode == 0 && remainingTimeout <= 0) { - abortTransfers(direction, endpointNumber); - waitForTransfer(transfer, direction, endpointNumber, true); - throw new USBTimeoutException(getOperationDescription(direction, endpointNumber) + "aborted due to " + - "timeout"); - } - - if (transfer.resultCode != 0) { - var operation = direction == USBDirection.IN ? "Transfer in" : "Transfer out"; - throwException(transfer.resultCode, getOperationDescription(direction, endpointNumber) + " failed", - operation); - } - } - - private static String getOperationDescription(USBDirection direction, int endpointNumber) { - if (endpointNumber == 0) { - return "Control transfer"; - } else { - return String.format("Transfer %s on endpoint %d", direction.name(), endpointNumber); - } - - } - @Override protected Transfer createTransfer() { return new MacosTransfer(); } - private static void onTransferCompleted(Transfer transfer) { - synchronized (transfer) { - transfer.notify(); - } - } - @Override public void abortTransfers(USBDirection direction, int endpointNumber) { EndpointInfo epInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java index 98ec23b7..43078fb5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java @@ -8,6 +8,7 @@ import net.codecrete.usb.USBException; import net.codecrete.usb.USBStallException; +import net.codecrete.usb.USBTimeoutException; import net.codecrete.usb.macos.gen.iokit.IOKit; import net.codecrete.usb.macos.gen.mach.mach; @@ -48,6 +49,8 @@ static void throwException(int errorCode, String message, Object... args) { var formattedMessage = String.format(message, args); if (errorCode == IOKit.kIOUSBPipeStalled()) { throw new USBStallException(formattedMessage); + } else if (errorCode == IOKit.kIOUSBTransactionTimeout()) { + throw new USBTimeoutException(formattedMessage); } else { throw new MacosUSBException(formattedMessage, errorCode); } diff --git a/reference/linux/usb_registry.cpp b/reference/linux/usb_registry.cpp index 865b2632..66d6f8b5 100644 --- a/reference/linux/usb_registry.cpp +++ b/reference/linux/usb_registry.cpp @@ -31,6 +31,7 @@ usb_registry::usb_registry() : monitor_wake_event_fd(-1), on_connected_callback(nullptr), on_disconnected_callback(nullptr), is_device_list_ready(false), async_io_update_event_fd(-1), async_io_update_request(0), async_io_update_response(0) { + std::cout << std::hex << USBDEVFS_REAPURBNDELAY << std::endl; } usb_registry::~usb_registry() { From 8e8a5d89ce114fec151652eeca573c7d9aecb26e Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 25 Feb 2023 15:10:29 +0100 Subject: [PATCH 208/433] Control transfer use async IO internally (Linux) --- java-does-usb/jextract/linux/gen_linux.sh | 3 + .../net/codecrete/usb/USBTransferType.java | 4 + .../codecrete/usb/common/USBDeviceImpl.java | 5 +- .../codecrete/usb/linux/LinuxAsyncTask.java | 21 +++- .../usb/linux/LinuxEndpointInputStream.java | 2 +- .../usb/linux/LinuxEndpointOutputStream.java | 2 +- .../codecrete/usb/linux/LinuxTransfer.java | 2 +- .../codecrete/usb/linux/LinuxUSBDevice.java | 108 ++++++++++-------- .../linux/gen/usbdevice_fs/usbdevice_fs.java | 24 ++++ reference/linux/usb_registry.cpp | 1 - 10 files changed, 115 insertions(+), 57 deletions(-) diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index f629b191..9e1a717f 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -60,7 +60,10 @@ $JEXTRACT --source --output ../../src/main/java \ --include-constant USBDEVFS_SUBMITURB \ --include-constant USBDEVFS_DISCARDURB \ --include-constant USBDEVFS_REAPURB \ + --include-constant USBDEVFS_URB_TYPE_INTERRUPT \ + --include-constant USBDEVFS_URB_TYPE_CONTROL \ --include-constant USBDEVFS_URB_TYPE_BULK \ + --include-constant USBDEVFS_URB_TYPE_ISO \ /usr/include/linux/usbdevice_fs.h # libudev.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBTransferType.java b/java-does-usb/src/main/java/net/codecrete/usb/USBTransferType.java index 3acdc2c1..bfeaa0c0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBTransferType.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBTransferType.java @@ -11,6 +11,10 @@ * USB endpoint transfer type enumeration. */ public enum USBTransferType { + /** + * Control transfer + */ + CONTROL, /** * Bulk transfer */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 75cc76dc..6e9ee7d3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -249,7 +249,7 @@ protected EndpointInfo getEndpoint(USBDirection direction, int endpointNumber, U if (ep.number() == endpointNumber && ep.direction() == direction && (ep.transferType() == transferType1 || ep.transferType() == transferType2)) return new EndpointInfo(intf.number(), ep.number(), (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)), - ep.packetSize()); + ep.packetSize(), ep.transferType()); } } } @@ -418,6 +418,7 @@ public String toString() { return "VID: 0x" + String.format("%04x", vendorId_) + ", PID: 0x" + String.format("%04x", productId_) + ", " + "manufacturer: " + manufacturer_ + ", product: " + product_ + ", serial: " + serialNumber_ + ", ID: " + id_; } - public record EndpointInfo(int interfaceNumber, int endpointNumber, byte endpointAddress, int packetSize) { + public record EndpointInfo(int interfaceNumber, int endpointNumber, byte endpointAddress, int packetSize, + USBTransferType transferType) { } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index f6b3f0db..f2842bff 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -7,6 +7,7 @@ package net.codecrete.usb.linux; +import net.codecrete.usb.USBTransferType; import net.codecrete.usb.linux.gen.errno.errno; import net.codecrete.usb.linux.gen.poll.poll; import net.codecrete.usb.linux.gen.poll.pollfd; @@ -26,7 +27,7 @@ import static net.codecrete.usb.linux.LinuxUSBException.throwException; import static net.codecrete.usb.linux.LinuxUSBException.throwLastError; import static net.codecrete.usb.linux.USBDevFS.*; -import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.USBDEVFS_URB_TYPE_BULK; +import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.*; /** * Background task for handling asynchronous transfers. @@ -35,7 +36,7 @@ *

*

* The task keeps track of the submitted transfers by remembering the - * URB address (USB request buffer) in order to match it to the + * URB address (USB request block) in order to match it to the * completion. *

*

@@ -232,12 +233,12 @@ private synchronized void removeFdFromAsyncIOCompletion(int fd) { asyncFds = fds; } - synchronized void submitBulkTransfer(LinuxUSBDevice device, int endpointAddress, LinuxTransfer transfer) { + synchronized void submitTransfer(LinuxUSBDevice device, int endpointAddress, USBTransferType transferType, LinuxTransfer transfer) { addURB(transfer); var urb = transfer.urb; - usbdevfs_urb.type$set(urb, (byte) USBDEVFS_URB_TYPE_BULK()); + usbdevfs_urb.type$set(urb, (byte) urbTransferType(transferType)); usbdevfs_urb.endpoint$set(urb, (byte) endpointAddress); usbdevfs_urb.buffer$set(urb, transfer.data); usbdevfs_urb.buffer_length$set(urb, transfer.dataSize); @@ -247,11 +248,21 @@ synchronized void submitBulkTransfer(LinuxUSBDevice device, int endpointAddress, var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); if (IO.ioctl(device.fileDescriptor(), SUBMITURB, urb, errnoState) < 0) { String action = endpointAddress >= 128 ? "reading from" : "writing to"; - throwLastError(errnoState, "failed %s endpoint %d", action, endpointAddress); + String endpoint = endpointAddress == 0 ? "control endpoint" : String.format("endpoint %d", endpointAddress); + throwLastError(errnoState, "failed %s %s", action, endpoint); } } } + private static int urbTransferType(USBTransferType transferType) { + return switch (transferType) { + case BULK -> USBDEVFS_URB_TYPE_BULK(); + case INTERRUPT -> USBDEVFS_URB_TYPE_INTERRUPT(); + case CONTROL -> USBDEVFS_URB_TYPE_CONTROL(); + case ISOCHRONOUS -> USBDEVFS_URB_TYPE_ISO(); + }; + } + private void addURB(LinuxTransfer transfer) { MemorySegment urb; int size = availableURBs.size(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java index dddbdf66..a8387029 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java @@ -19,6 +19,6 @@ public class LinuxEndpointInputStream extends EndpointInputStream { @Override protected void submitTransferIn(Transfer transfer) { - ((LinuxUSBDevice) device).submitBulkTransfer(USBDirection.IN, endpointNumber, (LinuxTransfer) transfer); + ((LinuxUSBDevice) device).submitTransfer(USBDirection.IN, endpointNumber, (LinuxTransfer) transfer); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java index ffaae2a6..dd7e71c7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java @@ -19,6 +19,6 @@ public class LinuxEndpointOutputStream extends EndpointOutputStream { @Override protected void submitTransferOut(Transfer transfer) { - ((LinuxUSBDevice) device).submitBulkTransfer(USBDirection.OUT, endpointNumber, (LinuxTransfer) transfer); + ((LinuxUSBDevice) device).submitTransfer(USBDirection.OUT, endpointNumber, (LinuxTransfer) transfer); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxTransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxTransfer.java index 0be287af..4e40a5e6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxTransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxTransfer.java @@ -14,7 +14,7 @@ public class LinuxTransfer extends Transfer { /** - * USB request buffer. + * USB request block. * * @see usbdevfs_urb */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 9c80638f..633fa620 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -16,9 +16,9 @@ import net.codecrete.usb.common.USBInterfaceImpl; import net.codecrete.usb.linux.gen.fcntl.fcntl; import net.codecrete.usb.linux.gen.unistd.unistd; -import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_ctrltransfer; import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_setinterface; import net.codecrete.usb.usbstandard.DeviceDescriptor; +import net.codecrete.usb.usbstandard.SetupPacket; import java.io.IOException; import java.io.InputStream; @@ -165,71 +165,74 @@ public synchronized void releaseInterface(int interfaceNumber) { } } - private MemorySegment createCtrlTransfer(Arena arena, USBDirection direction, USBControlTransfer setup, - MemorySegment data) { - var ctrlTransfer = arena.allocate(usbdevfs_ctrltransfer.$LAYOUT()); - var bmRequest = - (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); - usbdevfs_ctrltransfer.bRequestType$set(ctrlTransfer, (byte) bmRequest); - usbdevfs_ctrltransfer.bRequest$set(ctrlTransfer, (byte) setup.request()); - usbdevfs_ctrltransfer.wValue$set(ctrlTransfer, (short) setup.value()); - usbdevfs_ctrltransfer.wIndex$set(ctrlTransfer, (short) setup.index()); - usbdevfs_ctrltransfer.wLength$set(ctrlTransfer, (short) data.byteSize()); - usbdevfs_ctrltransfer.data$set(ctrlTransfer, data); - return ctrlTransfer; - } - @Override - public byte[] controlTransferIn(USBControlTransfer setup, int length) { + public void controlTransferOut(USBControlTransfer setup, byte[] data) { try (var arena = Arena.openConfined()) { - var data = arena.allocate(length); - var ctrlTransfer = createCtrlTransfer(arena, USBDirection.IN, setup, data); - - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); - int res = IO.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer, errnoState); - if (res < 0) - throwLastError(errnoState, "Control IN transfer failed"); + int dataLength = data != null ? data.length : 0; + var transfer = createSyncCtrlTransfer(arena, USBDirection.OUT, setup, dataLength); + if (dataLength != 0) + transfer.data.asSlice(8).copyFrom(MemorySegment.ofArray(data)); - return data.asSlice(0, res).toArray(JAVA_BYTE); + synchronized (transfer) { + submitTransfer(USBDirection.OUT, 0, transfer); + waitForTransfer(transfer, 0, USBDirection.OUT, 0); + } } } @Override - public void controlTransferOut(USBControlTransfer setup, byte[] data) { + public byte[] controlTransferIn(USBControlTransfer setup, int length) { try (var arena = Arena.openConfined()) { - int dataLength = data != null ? data.length : 0; - var buffer = arena.allocate(dataLength); - if (dataLength != 0) - buffer.copyFrom(MemorySegment.ofArray(data)); - var ctrlTransfer = createCtrlTransfer(arena, USBDirection.OUT, setup, buffer); + var transfer = createSyncCtrlTransfer(arena, USBDirection.IN, setup, length); - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); - int res = IO.ioctl(fd, USBDevFS.CONTROL, ctrlTransfer, errnoState); - if (res < 0) - throwLastError(errnoState, "Control OUT transfer failed"); + synchronized (transfer) { + submitTransfer(USBDirection.IN, 0, transfer); + waitForTransfer(transfer, 0, USBDirection.IN, 0); + } + + return transfer.data.asSlice(8, transfer.resultSize).toArray(JAVA_BYTE); } } - private LinuxTransfer createSyncTransfer(MemorySegment data) { + /** + * Create transfer object for synchronous control request. + * + * @param arena arena for allocating memory + * @param direction direction + * @param setup setup data + * @param dataLength data length (in addition to setup data) + * @return transfer object + */ + private LinuxTransfer createSyncCtrlTransfer(Arena arena, USBDirection direction, USBControlTransfer setup, + int dataLength) { + var bmRequest = + (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); + var buffer = arena.allocate(8 + dataLength, 8); + var setupPacket = new SetupPacket(buffer); + setupPacket.setRequestType(bmRequest); + setupPacket.setRequest(setup.request()); + setupPacket.setValue(setup.value()); + setupPacket.setIndex(setup.index()); + setupPacket.setLength(dataLength); + var transfer = new LinuxTransfer(); - transfer.data = data; - transfer.dataSize = (int) data.byteSize(); + transfer.data = buffer; + transfer.dataSize = (int) buffer.byteSize(); transfer.resultSize = -1; transfer.completion = USBDeviceImpl::onSyncTransferCompleted; + return transfer; } @Override public void transferOut(int endpointNumber, byte[] data, int timeout) { - var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); - try (var arena = Arena.openConfined()) { var buffer = arena.allocate(data.length); buffer.copyFrom(MemorySegment.ofArray(data)); var transfer = createSyncTransfer(buffer); synchronized (transfer) { - asyncTask.submitBulkTransfer(this, endpoint.endpointAddress(), transfer); + submitTransfer(USBDirection.OUT, endpointNumber, transfer); waitForTransfer(transfer, timeout, USBDirection.OUT, endpointNumber); } } @@ -244,7 +247,7 @@ public byte[] transferIn(int endpointNumber, int timeout) { var transfer = createSyncTransfer(buffer); synchronized (transfer) { - asyncTask.submitBulkTransfer(this, endpoint.endpointAddress(), transfer); + submitTransfer(USBDirection.IN, endpointNumber, transfer); waitForTransfer(transfer, timeout, USBDirection.IN, endpointNumber); } @@ -252,6 +255,24 @@ public byte[] transferIn(int endpointNumber, int timeout) { } } + private LinuxTransfer createSyncTransfer(MemorySegment data) { + var transfer = new LinuxTransfer(); + transfer.data = data; + transfer.dataSize = (int) data.byteSize(); + transfer.resultSize = -1; + transfer.completion = USBDeviceImpl::onSyncTransferCompleted; + return transfer; + } + + synchronized void submitTransfer(USBDirection direction, int endpointNumber, LinuxTransfer transfer) { + if (endpointNumber != 0) { + var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); + asyncTask.submitTransfer(this, endpoint.endpointAddress(), endpoint.transferType(), transfer); + } else { + asyncTask.submitTransfer(this, 0, USBTransferType.CONTROL, transfer); + } + } + @Override protected Transfer createTransfer() { return new LinuxTransfer(); @@ -297,9 +318,4 @@ public OutputStream openOutputStream(int endpointNumber) { return new LinuxEndpointOutputStream(this, endpointNumber); } - - synchronized void submitBulkTransfer(USBDirection direction, int endpointNumber, LinuxTransfer transfer) { - var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, null); - asyncTask.submitBulkTransfer(this, endpoint.endpointAddress(), transfer); - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java index dcc268ad..e6a5e495 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java @@ -13,6 +13,30 @@ public class usbdevice_fs { public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + /** + * {@snippet : + * #define USBDEVFS_URB_TYPE_ISO 0 + * } + */ + public static int USBDEVFS_URB_TYPE_ISO() { + return (int)0L; + } + /** + * {@snippet : + * #define USBDEVFS_URB_TYPE_INTERRUPT 1 + * } + */ + public static int USBDEVFS_URB_TYPE_INTERRUPT() { + return (int)1L; + } + /** + * {@snippet : + * #define USBDEVFS_URB_TYPE_CONTROL 2 + * } + */ + public static int USBDEVFS_URB_TYPE_CONTROL() { + return (int)2L; + } /** * {@snippet : * #define USBDEVFS_URB_TYPE_BULK 3 diff --git a/reference/linux/usb_registry.cpp b/reference/linux/usb_registry.cpp index 66d6f8b5..865b2632 100644 --- a/reference/linux/usb_registry.cpp +++ b/reference/linux/usb_registry.cpp @@ -31,7 +31,6 @@ usb_registry::usb_registry() : monitor_wake_event_fd(-1), on_connected_callback(nullptr), on_disconnected_callback(nullptr), is_device_list_ready(false), async_io_update_event_fd(-1), async_io_update_request(0), async_io_update_response(0) { - std::cout << std::hex << USBDEVFS_REAPURBNDELAY << std::endl; } usb_registry::~usb_registry() { From ddd9b88e1949ff5a586bbd9428f9725ed41034c0 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 25 Feb 2023 17:29:15 +0100 Subject: [PATCH 209/433] Improve input/output stream documentation --- .../src/main/java/net/codecrete/usb/USBDevice.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index ea1e13af..98e0a604 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -280,6 +280,13 @@ public interface USBDevice { * Opens a new output stream to send data to a bulk endpoint. *

* All data written to this output stream is sent to the specified bulk endpoint. + * Buffering and concurrent IO requests are used to achieve a high throughput. + *

+ *

+ * The stream will insert zero-length packets if {@link OutputStream#flush()} is called + * and the last packet size was equal to maximum packet size of the endpoint. + *

+ *

* If {@link #transferOut(int, byte[])} and a output stream or multiple output streams * are used concurrently for the same endpoint, the behavior is unpredictable. *

@@ -293,8 +300,10 @@ public interface USBDevice { * Opens a new input stream to receive data from a bulk endpoint. *

* All data received from the specified bulk endpoint can be read using this input stream. + * Buffering and concurrent IO requests are used to achieve a high throughput. *

*

+ * If the buffers contain data when the stream is closed, this data will be discarded. * If {@link #transferIn(int)} and an input stream or multiple input streams * are used concurrently for the same endpoint, the behavior is unpredictable. *

From 0773a32e5f055371a38f0608a0c71596ce1cfe79 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 26 Feb 2023 13:24:25 +0100 Subject: [PATCH 210/433] Separate async IO class (Windows) --- java-does-usb/jextract/windows/gen_win.cmd | 1 + .../usb/common/EndpointInputStream.java | 9 +- .../usb/common/EndpointOutputStream.java | 8 +- .../codecrete/usb/linux/LinuxAsyncTask.java | 11 +- .../net/codecrete/usb/windows/USBHelper.java | 2 +- .../usb/windows/WindowsAsyncTask.java | 172 ++++++++++++++++++ .../windows/WindowsEndpointInputStream.java | 6 +- .../windows/WindowsEndpointOutputStream.java | 6 +- .../usb/windows/WindowsUSBDevice.java | 54 ++---- .../usb/windows/WindowsUSBDeviceRegistry.java | 127 +------------ .../usb/windows/WindowsUSBException.java | 30 ++- .../usb/windows/gen/kernel32/Kernel32.java | 8 + 12 files changed, 255 insertions(+), 179 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index 175202fd..3223a8a7 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -31,6 +31,7 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-constant FORMAT_MESSAGE_ALLOCATE_BUFFER ^ --include-constant FORMAT_MESSAGE_FROM_SYSTEM ^ --include-constant FORMAT_MESSAGE_IGNORE_INSERTS ^ + --include-constant FORMAT_MESSAGE_FROM_HMODULE ^ --include-constant INFINITE ^ --include-struct _GUID ^ --include-typedef GUID ^ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index 71c5a0c4..3ceabd33 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -62,12 +62,14 @@ public abstract class EndpointInputStream extends InputStream { protected EndpointInputStream(USBDeviceImpl device, int endpointNumber) { this.device = device; this.endpointNumber = endpointNumber; - + arena = Arena.openShared(); bufferSize = 4 * device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); + + configureEndpoint(); + completedTransferQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_TRANSFERS); // create all transfers, and submit them except one - arena = Arena.openShared(); try { for (int i = 0; i < MAX_OUTSTANDING_TRANSFERS; i++) { final var transfer = device.createTransfer(); @@ -204,4 +206,7 @@ private void collectOutstandingTransfers() { } protected abstract void submitTransferIn(Transfer transfer); + + protected void configureEndpoint() { + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java index 46b32d79..972f5c63 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -64,12 +64,13 @@ public abstract class EndpointOutputStream extends OutputStream { protected EndpointOutputStream(USBDeviceImpl device, int endpointNumber) { this.device = device; this.endpointNumber = endpointNumber; - packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize(); bufferSize = packetSize; + arena = Arena.openShared(); + + configureEndpoint(); availableTransferQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_TRANSFERS); - arena = Arena.openShared(); // prefill transfer queue for (int i = 0; i < MAX_OUTSTANDING_TRANSFERS; i++) { @@ -245,4 +246,7 @@ private synchronized void onCompletion(Transfer transfer) { } protected abstract void submitTransferOut(Transfer request); + + protected void configureEndpoint() { + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index f2842bff..d656eac4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -32,12 +32,11 @@ /** * Background task for handling asynchronous transfers. *

- * Each USB device must register its file handler with this task. + * Each USB device must register its file handle with this task. *

*

- * The task keeps track of the submitted transfers by remembering the - * URB address (USB request block) in order to match it to the - * completion. + * The task keeps track of the submitted transfers by indexing them + * by URB address (USB request block). *

*

* URBs are allocated but never freed. To limit the memory usage, @@ -174,7 +173,7 @@ private void reapURB(int fd, MemorySegment urbPointerHolder, MemorySegment errno private void notifyAsyncIOTask() { // start background process if needed if (asyncIOUpdateEventFd == 0) { - startAsyncIOHandler(); + startAsyncIOTask(); return; } @@ -307,7 +306,7 @@ synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { } } - private void startAsyncIOHandler() { + private void startAsyncIOTask() { try (var arena = Arena.openConfined()) { var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); asyncIOUpdateEventFd = IO.eventfd(0, 0, errnoState); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java index 11c46090..bc0738ea 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java @@ -45,7 +45,7 @@ public class USBHelper { // USB_PIPE_INFO PipeList[0];/* OUTPUT */ //} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; public static final GroupLayout USB_NODE_CONNECTION_INFORMATION_EX$Struct = structLayout(JAVA_INT.withName( - "ConnectionIndex"), DeviceDescriptor.LAYOUT.withName("DeviceDescriptor"), JAVA_BYTE.withName( + "ConnectionIndex"), DeviceDescriptor.LAYOUT.withName("DeviceDescriptor"), JAVA_BYTE.withName( "CurrentConfigurationValue"), JAVA_BYTE.withName("Speed"), JAVA_BYTE.withName("DeviceIsHub"), JAVA_SHORT_UNALIGNED.withName("DeviceAddress"), JAVA_INT.withName("NumberOfOpenPipes"), JAVA_INT.withName("ConnectionStatus") diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java new file mode 100644 index 00000000..cd84821a --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java @@ -0,0 +1,172 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.windows; + +import net.codecrete.usb.windows.gen.kernel32.Kernel32; +import net.codecrete.usb.windows.gen.kernel32.OVERLAPPED; +import net.codecrete.usb.windows.winsdk.Kernel32B; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static java.lang.foreign.MemorySegment.NULL; +import static java.lang.foreign.ValueLayout.*; +import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; + +/** + * Background task for handling asynchronous transfers. + *

+ * Each USB device must register its handle with this task. + *

+ *

+ * The task keeps track of the submitted transfers by indexing them + * by OVERLAPPED struct address. + *

+ *

+ * OVERLAPPED structs are allocated but never freed. To limit the memory usage, + * OVERLAPPED structs are reused. So the maximum number of outstanding transfers + * determines the number of allocated OVERLAPPED structs. + *

+ */ +public class WindowsAsyncTask { + + private static WindowsAsyncTask singletonInstance; + + /** + * Singleton instance of background task. + * + * @return background task + */ + static synchronized WindowsAsyncTask instance() { + if (singletonInstance == null) + singletonInstance = new WindowsAsyncTask(); + return singletonInstance; + } + + // Currently outstanding transfer requests, + // indexed by OVERLAPPED address. + private Map requestsByOverlapped; + // available OVERLAPPED data structures + private List availableOverlappedStructs; + // Arena used to allocate OVERLAPPED data structures + private Arena arena; + + /** + * Windows completion port for asynchronous/overlapped IO + */ + private MemorySegment asyncIoCompletionPort = NULL; + + /** + * Background task for handling asynchronous IO completions. + */ + private void asyncCompletionTask() { + + try (var arena = Arena.openConfined()) { + + var overlappedHolder = arena.allocate(ADDRESS, NULL); + var numBytesHolder = arena.allocate(JAVA_INT, 0); + var completionKeyHolder = arena.allocate(JAVA_LONG, 0); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + + while (true) { + overlappedHolder.set(ADDRESS, 0, MemorySegment.NULL); + completionKeyHolder.set(JAVA_LONG, 0, 0); + + int res = Kernel32B.GetQueuedCompletionStatus(asyncIoCompletionPort, numBytesHolder, + completionKeyHolder, overlappedHolder, Kernel32.INFINITE(), lastErrorState); + var overlappedAddr = overlappedHolder.get(JAVA_LONG, 0); + + if (res == 0 && overlappedAddr == 0) + throwLastError(lastErrorState, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); + + if (overlappedAddr == 0) + return; // registry closing? + + completeTransfer(overlappedAddr); + } + } + } + + /** + * Add a Windows handle (of a USB device) to the completion port. + *

+ * The handle is removed by closing it. + *

+ * + * @param handle Windows handle + */ + synchronized void addDevice(MemorySegment handle) { + + try (var arena = Arena.openConfined()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + + // Creates a new port if it doesn't exist; adds handle to existing port if it exists + MemorySegment portHandle = Kernel32B.CreateIoCompletionPort(handle, asyncIoCompletionPort, + handle.address(), 0, lastErrorState); + if (portHandle == MemorySegment.NULL) + throwLastError(lastErrorState, "internal error (CreateIoCompletionPort)"); + + if (asyncIoCompletionPort == MemorySegment.NULL) { + asyncIoCompletionPort = portHandle; + startAsyncIOTask(); + } + } + } + + private void startAsyncIOTask() { + availableOverlappedStructs = new ArrayList<>(); + arena = Arena.openShared(); + requestsByOverlapped = new HashMap<>(); + + // start background thread for handling IO completion + Thread t = new Thread(this::asyncCompletionTask, "USB async IO"); + t.setDaemon(true); + t.start(); + } + + /** + * Prepare a transfer for submission by adding the OVERLAPPED struct. + * + * @param transfer transfer to prepare + */ + synchronized void prepareForSubmission(WindowsTransfer transfer) { + MemorySegment overlapped; + int size = availableOverlappedStructs.size(); + if (size == 0) { + overlapped = arena.allocate(OVERLAPPED.$LAYOUT()); + } else { + overlapped = availableOverlappedStructs.remove(size - 1); + } + + transfer.overlapped = overlapped; + transfer.resultSize = -1; + requestsByOverlapped.put(overlapped.address(), transfer); + } + + /** + * Completes the transfer by calling the completion handler. + * + * @param overlappedAddr address of OVERLAPPED struct + */ + private synchronized void completeTransfer(long overlappedAddr) { + var transfer = requestsByOverlapped.remove(overlappedAddr); + if (transfer == null) + return; + + transfer.resultCode = (int) OVERLAPPED.Internal$get(transfer.overlapped); + transfer.resultSize = (int) OVERLAPPED.InternalHigh$get(transfer.overlapped); + + availableOverlappedStructs.add(transfer.overlapped); + transfer.overlapped = null; + transfer.completion.completed(transfer); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java index c257e10d..ba20ef78 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java @@ -15,11 +15,15 @@ public class WindowsEndpointInputStream extends EndpointInputStream { WindowsEndpointInputStream(WindowsUSBDevice device, int endpointNumber) { super(device, endpointNumber); - device.configureForAsyncIo(USBDirection.IN, endpointNumber); } @Override protected void submitTransferIn(Transfer transfer) { ((WindowsUSBDevice) device).submitTransferIn(endpointNumber, (WindowsTransfer) transfer); } + + @Override + protected void configureEndpoint() { + ((WindowsUSBDevice) device).configureForAsyncIo(USBDirection.IN, endpointNumber); + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java index 21b504ae..8618bceb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java @@ -15,11 +15,15 @@ public class WindowsEndpointOutputStream extends EndpointOutputStream { WindowsEndpointOutputStream(WindowsUSBDevice device, int endpointNumber) { super(device, endpointNumber); - device.configureForAsyncIo(USBDirection.OUT, endpointNumber); } @Override protected void submitTransferOut(Transfer request) { ((WindowsUSBDevice) device).submitTransferOut(endpointNumber, (WindowsTransfer) request); } + + @Override + protected void configureEndpoint() { + ((WindowsUSBDevice) device).configureForAsyncIo(USBDirection.OUT, endpointNumber); + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 3d048db7..5256a648 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -20,7 +20,6 @@ import java.io.OutputStream; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentScope; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -35,14 +34,14 @@ */ public class WindowsUSBDevice extends USBDeviceImpl { - private final WindowsUSBDeviceRegistry registry; + private final WindowsAsyncTask asyncTask; private List interfaceHandles_; private boolean isOpen_; WindowsUSBDevice(WindowsUSBDeviceRegistry registry, String devicePath, Map children, int vendorId, int productId, MemorySegment configDesc) { super(devicePath, vendorId, productId); - this.registry = registry; + asyncTask = WindowsAsyncTask.instance(); readDescription(configDesc, devicePath, children); } @@ -124,7 +123,7 @@ public synchronized void claimInterface(int interfaceNumber) { if (Win.IsInvalidHandle(deviceHandle)) throwLastError(lastErrorState, "Cannot open USB device %s", firstIntfHandle.devicePath); - registry.addToCompletionPort(deviceHandle, this); + asyncTask.addDevice(deviceHandle); } else { deviceHandle = firstIntfHandle.deviceHandle; @@ -323,7 +322,7 @@ public byte[] transferIn(int endpointNumber, int timeout) { @Override protected Transfer createTransfer() { - return registry.createRequest(); + return new WindowsTransfer(); } @Override @@ -331,17 +330,17 @@ protected void throwOSException(int errorCode, String message, Object... args) { throwException(errorCode, message, args); } - synchronized void submitTransferOut(int endpointNumber, WindowsTransfer request) { + synchronized void submitTransferOut(int endpointNumber, WindowsTransfer transfer) { var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.openConfined()) { var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - registry.addOverlapped(request); + asyncTask.prepareForSubmission(transfer); // submit transfer - if (WinUSB2.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), request.data, request.dataSize, NULL - , request.overlapped, lastErrorState) == 0) { + if (WinUSB2.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), transfer.data, transfer.dataSize, NULL + , transfer.overlapped, lastErrorState) == 0) { int err = Win.getLastError(lastErrorState); if (err != Kernel32.ERROR_IO_PENDING()) throwException(err, "Submitting transfer OUT failed"); @@ -349,17 +348,17 @@ synchronized void submitTransferOut(int endpointNumber, WindowsTransfer request) } } - synchronized void submitTransferIn(int endpointNumber, WindowsTransfer request) { + synchronized void submitTransferIn(int endpointNumber, WindowsTransfer transfer) { var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.openConfined()) { var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - registry.addOverlapped(request); + asyncTask.prepareForSubmission(transfer); // submit transfer - if (WinUSB2.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), request.data, request.dataSize, - NULL, request.overlapped, lastErrorState) == 0) { + if (WinUSB2.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), transfer.data, transfer.dataSize, + NULL, transfer.overlapped, lastErrorState) == 0) { int err = Win.getLastError(lastErrorState); if (err != Kernel32.ERROR_IO_PENDING()) throwException(err, "Submitting transfer IN failed"); @@ -367,33 +366,6 @@ synchronized void submitTransferIn(int endpointNumber, WindowsTransfer request) } } - /** - * Cancels an asynchronous IO request. - *

- * If the specific request is not found, the error is silently ignored. Such errors - * are likely to happen due to concurrency issues. - *

- * - * @param direction endpoint direction - * @param endpointNumber endpoint number - * @param cancelHandle request's cancel handle returned when the request was submitted - */ - synchronized void cancelTransfer(USBDirection direction, int endpointNumber, long cancelHandle) { - var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); - var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); - - try (var arena = Arena.openConfined()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - var overlapped = MemorySegment.ofAddress(cancelHandle, 0, SegmentScope.global()); - - if (Kernel32B.CancelIoEx(intfHandle.deviceHandle, overlapped, lastErrorState) == 0) { - int err = Win.getLastError(lastErrorState); - if (err != Kernel32.ERROR_NOT_FOUND()) - throwException(err, "Cancelling transfer failed"); - } - } - } - synchronized void configureForAsyncIo(USBDirection direction, int endpointNumber) { var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); @@ -406,7 +378,7 @@ synchronized void configureForAsyncIo(USBDirection direction, int endpointNumber WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder, lastErrorState) == 0) throwLastError(lastErrorState, "Setting timeout failed"); - var rawIoHolder = arena.allocate(JAVA_BYTE, (byte) 0); + var rawIoHolder = arena.allocate(JAVA_BYTE, (byte) 1); if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), WinUSB.RAW_IO(), (int) rawIoHolder.byteSize(), rawIoHolder, lastErrorState) == 0) throwLastError(lastErrorState, "Setting raw IO failed"); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 4898cc1c..5421deab 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -18,7 +18,6 @@ import net.codecrete.usb.usbstandard.StringDescriptor; import net.codecrete.usb.windows.gen.kernel32.GUID; import net.codecrete.usb.windows.gen.kernel32.Kernel32; -import net.codecrete.usb.windows.gen.kernel32.OVERLAPPED; import net.codecrete.usb.windows.gen.ole32.Ole32; import net.codecrete.usb.windows.gen.setupapi.SP_DEVICE_INTERFACE_DATA; import net.codecrete.usb.windows.gen.setupapi.SP_DEVINFO_DATA; @@ -29,7 +28,10 @@ import net.codecrete.usb.windows.winsdk.SetupAPI2; import net.codecrete.usb.windows.winsdk.User32B; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.ArrayList; @@ -54,11 +56,6 @@ */ public class WindowsUSBDeviceRegistry extends USBDeviceRegistry { - /** - * Windows completion port for asynchronous/overlapped IO - */ - private MemorySegment asyncIoCompletionPort = NULL; - @Override protected void monitorDevices() { try (var arena = Arena.openConfined()) { @@ -523,120 +520,4 @@ private static int extractInterfaceNumber(List hardwareIds) { return -1; } - - /** - * Background task for handling asynchronous IO completions. - */ - private void asyncCompletionTask() { - - try (var arena = Arena.openConfined()) { - - var overlappedHolder = arena.allocate(ADDRESS, NULL); - var numBytesHolder = arena.allocate(JAVA_INT, 0); - var completionKeyHolder = arena.allocate(JAVA_LONG, 0); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - - while (true) { - overlappedHolder.set(ADDRESS, 0, MemorySegment.NULL); - completionKeyHolder.set(JAVA_LONG, 0, 0); - - int res = Kernel32B.GetQueuedCompletionStatus(asyncIoCompletionPort, numBytesHolder, - completionKeyHolder, overlappedHolder, Kernel32.INFINITE(), lastErrorState); - var overlappedAddr = overlappedHolder.get(JAVA_LONG, 0); - - if (res == 0 && overlappedAddr == 0) - throwLastError(lastErrorState, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); - - if (overlappedAddr == 0) - return; // registry is closing? - - var request = getRequest(overlappedAddr); - if (request != null) - request.completion.completed(request); - -// long completionKey = completionKeyHolder.get(JAVA_LONG, 0); -// var device = devicesByCompletionKey.get(completionKey); -// -// if (device != null) { -// overlapped = OVERLAPPED.ofAddress(overlapped, SegmentScope.global()); -// device.onAsyncIoCompleted(overlapped); -// } - } - } - } - - /** - * Add a Windows handle (of a USB device) to the completion port - * - * @param handle Windows handle - * @param device USB device - */ - synchronized void addToCompletionPort(MemorySegment handle, WindowsUSBDevice device) { - - try (var arena = Arena.openConfined()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - - // Creates a new port if it doesn't exist; adds handle to existing port if it exists - MemorySegment portHandle = Kernel32B.CreateIoCompletionPort(handle, asyncIoCompletionPort, - handle.address(), 0, lastErrorState); - if (portHandle == MemorySegment.NULL) - throwLastError(lastErrorState, "internal error (CreateIoCompletionPort)"); - - if (asyncIoCompletionPort == MemorySegment.NULL) { - asyncIoCompletionPort = portHandle; - startAsyncIOTask(); - } - } - } - - void startAsyncIOTask() { - availableOverlappedStructs = new ArrayList<>(); - arena = Arena.openShared(); - requestsByOverlapped = new HashMap<>(); - - // start background thread for handling IO completion - Thread t = new Thread(this::asyncCompletionTask, "USB async IO"); - t.setDaemon(true); - t.start(); - } - - // Currently outstanding transfer requests, - // indexed by OVERLAPPED address. - private Map requestsByOverlapped; - // available OVERLAPPED data structures - private List availableOverlappedStructs; - // Arena used to allocate OVERLAPPED data structures - private Arena arena; - - void addOverlapped(WindowsTransfer request) { - MemorySegment overlapped; - int size = availableOverlappedStructs.size(); - if (size == 0) { - overlapped = arena.allocate(OVERLAPPED.$LAYOUT()); - } else { - overlapped = availableOverlappedStructs.remove(size - 1); - } - - request.overlapped = overlapped; - requestsByOverlapped.put(overlapped.address(), request); - } - - private synchronized WindowsTransfer getRequest(long overlappedAddr) { - var request = requestsByOverlapped.remove(overlappedAddr); - if (request == null) - return null; - - request.resultCode = (int) OVERLAPPED.Internal$get(request.overlapped); - request.resultSize = (int) OVERLAPPED.InternalHigh$get(request.overlapped); - - availableOverlappedStructs.add(request.overlapped); - request.overlapped = null; - return request; - } - - synchronized WindowsTransfer createRequest() { - var request = new WindowsTransfer(); - request.resultSize = -1; - return request; - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java index ab1026d3..ca2b3a8b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java @@ -79,13 +79,39 @@ static void throwLastError(MemorySegment lastErrorState, String message, Object. throwException(Win.getLastError(lastErrorState), message, args); } + private static MemorySegment ntModule; + + private static MemorySegment getNtModule() { + if (ntModule == null) { + try (var arena = Arena.openConfined()) { + var moduleName = Win.createSegmentFromString("NTDLL.DLL", arena); + ntModule = Kernel32.GetModuleHandleW(moduleName); + } + } + + return ntModule; + } + static String getErrorMessage(int errorCode) { try (var arena = Arena.openConfined()) { var messagePointerHolder = arena.allocate(ADDRESS); - int res = - Kernel32.FormatMessageW(Kernel32.FORMAT_MESSAGE_ALLOCATE_BUFFER() | Kernel32.FORMAT_MESSAGE_FROM_SYSTEM() | Kernel32.FORMAT_MESSAGE_IGNORE_INSERTS(), NULL, errorCode, 0, messagePointerHolder, 0, NULL); + + // First try: Win32 error code + int res = Kernel32.FormatMessageW( + Kernel32.FORMAT_MESSAGE_ALLOCATE_BUFFER() | Kernel32.FORMAT_MESSAGE_FROM_SYSTEM() | Kernel32.FORMAT_MESSAGE_IGNORE_INSERTS(), + NULL, errorCode, 0, messagePointerHolder, 0, NULL); + + // Second try: NTSTATUS error code + if (res == 0) { + res = Kernel32.FormatMessageW( + Kernel32.FORMAT_MESSAGE_ALLOCATE_BUFFER() | Kernel32.FORMAT_MESSAGE_FROM_HMODULE() | Kernel32.FORMAT_MESSAGE_IGNORE_INSERTS(), + getNtModule(), errorCode, 0, messagePointerHolder, 0, NULL); + } + + // Fallback if (res == 0) return "unspecified error"; + var messagePointer = messagePointerHolder.get(ForeignMemory.UNBOUNDED_ADDRESS, 0); String message = Win.createStringFromSegment(messagePointer); Kernel32.LocalFree(messagePointer); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java index 95e61fa0..0aab7d0d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -72,6 +72,14 @@ public static int FORMAT_MESSAGE_ALLOCATE_BUFFER() { public static int FORMAT_MESSAGE_IGNORE_INSERTS() { return (int)512L; } + /** + * {@snippet : + * #define FORMAT_MESSAGE_FROM_HMODULE 2048 + * } + */ + public static int FORMAT_MESSAGE_FROM_HMODULE() { + return (int)2048L; + } /** * {@snippet : * #define FORMAT_MESSAGE_FROM_SYSTEM 4096 From 66b386172ef7aa9821bc3a4e18932969fa4ef9de Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 26 Feb 2023 17:21:54 +0100 Subject: [PATCH 211/433] Bulk/interrupt transfer use async IO internally (Windows) --- java-does-usb/jextract/windows/gen_win.cmd | 9 + .../jextract/windows/windows_headers.h | 1 + .../usb/windows/WindowsUSBDevice.java | 63 ++--- .../usb/windows/WindowsUSBException.java | 3 +- .../usb/windows/gen/ntdll/Constants$root.java | 21 ++ .../usb/windows/gen/ntdll/NtDll.java | 26 +++ .../usb/windows/gen/ntdll/RuntimeHelper.java | 217 ++++++++++++++++++ 7 files changed, 295 insertions(+), 45 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/RuntimeHelper.java diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index 3223a8a7..5a3a4d03 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -139,3 +139,12 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --target-package net.codecrete.usb.windows.gen.ole32 ^ --include-function CLSIDFromString ^ windows_headers.h + +call %JEXTRACT% --source --output ../../src/main/java ^ + -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ + -I "%SDK_DIR%\um" ^ + -I "%SDK_DIR%\shared" ^ + --header-class-name NtDll ^ + --target-package net.codecrete.usb.windows.gen.ntdll ^ + --include-constant STATUS_UNSUCCESSFUL ^ + windows_headers.h diff --git a/java-does-usb/jextract/windows/windows_headers.h b/java-does-usb/jextract/windows/windows_headers.h index fbc95ecb..e7b6a1c7 100644 --- a/java-does-usb/jextract/windows/windows_headers.h +++ b/java-does-usb/jextract/windows/windows_headers.h @@ -4,3 +4,4 @@ #include #include #include +#include diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 5256a648..63d79728 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -258,32 +258,14 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { @Override public void transferOut(int endpointNumber, byte[] data, int timeout) { - checkIsOpen(); - - var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); - var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); - try (var arena = Arena.openConfined()) { - // set timeout - var timeoutHolder = arena.allocate(JAVA_INT, timeout); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - - if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), - WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder, lastErrorState) == 0) - throwLastError(lastErrorState, "Setting timeout failed"); - - // copy data to native heap var buffer = arena.allocate(data.length); buffer.copyFrom(MemorySegment.ofArray(data)); - var lengthHolder = arena.allocate(JAVA_INT); + var transfer = createSyncTransfer(buffer); - // send data - if (WinUSB2.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, - (int) buffer.byteSize(), lengthHolder, NULL, lastErrorState) == 0) { - int err = Win.getLastError(lastErrorState); - if (err == Kernel32.ERROR_SEM_TIMEOUT()) - throw new USBTimeoutException("Transfer out aborted due to timeout"); - throwException(err, "Bulk/interrupt transfer OUT failed"); + synchronized (transfer) { + submitTransferOut(endpointNumber, transfer); + waitForTransfer(transfer, timeout, USBDirection.OUT, endpointNumber); } } } @@ -291,35 +273,28 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { @Override public byte[] transferIn(int endpointNumber, int timeout) { var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); - var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.openConfined()) { - // set timeout - var timeoutHolder = arena.allocate(JAVA_INT, timeout); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), - WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder, lastErrorState) == 0) - throwLastError(lastErrorState, "Setting timeout failed"); - - // create native heap buffer for data var buffer = arena.allocate(endpoint.packetSize()); - var lengthHolder = arena.allocate(JAVA_INT); + var transfer = createSyncTransfer(buffer); - // receive data - if (WinUSB2.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer, - (int) buffer.byteSize(), lengthHolder, NULL, lastErrorState) == 0) { - int err = Win.getLastError(lastErrorState); - if (err == Kernel32.ERROR_SEM_TIMEOUT()) - throw new USBTimeoutException("Transfer in aborted due to timeout"); - throwException(err, "Bulk/interrupt transfer IN failed"); + synchronized (transfer) { + submitTransferIn(endpointNumber, transfer); + waitForTransfer(transfer, timeout, USBDirection.IN, endpointNumber); } - // copy data - int len = lengthHolder.get(JAVA_INT, 0); - return buffer.asSlice(0, len).toArray(JAVA_BYTE); + return buffer.asSlice(0, transfer.resultSize).toArray(JAVA_BYTE); } } + private WindowsTransfer createSyncTransfer(MemorySegment data) { + var transfer = new WindowsTransfer(); + transfer.data = data; + transfer.dataSize = (int) data.byteSize(); + transfer.completion = USBDeviceImpl::onSyncTransferCompleted; + return transfer; + } + @Override protected Transfer createTransfer() { return new WindowsTransfer(); @@ -386,7 +361,7 @@ synchronized void configureForAsyncIo(USBDirection direction, int endpointNumber } @Override - public void clearHalt(USBDirection direction, int endpointNumber) { + public synchronized void clearHalt(USBDirection direction, int endpointNumber) { var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); @@ -398,7 +373,7 @@ public void clearHalt(USBDirection direction, int endpointNumber) { } @Override - public void abortTransfers(USBDirection direction, int endpointNumber) { + public synchronized void abortTransfers(USBDirection direction, int endpointNumber) { var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java index ca2b3a8b..d6dde4c7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java @@ -10,6 +10,7 @@ import net.codecrete.usb.USBStallException; import net.codecrete.usb.common.ForeignMemory; import net.codecrete.usb.windows.gen.kernel32.Kernel32; +import net.codecrete.usb.windows.gen.ntdll.NtDll; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; @@ -47,7 +48,7 @@ public WindowsUSBException(String message, int errorCode) { */ static void throwException(int errorCode, String message, Object... args) { var formattedMessage = String.format(message, args); - if (errorCode == Kernel32.ERROR_GEN_FAILURE()) { + if (errorCode == Kernel32.ERROR_GEN_FAILURE() || errorCode == NtDll.STATUS_UNSUCCESSFUL()) { throw new USBStallException(formattedMessage); } else { throw new WindowsUSBException(formattedMessage, errorCode); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/Constants$root.java new file mode 100644 index 00000000..d0e6f9f6 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/Constants$root.java @@ -0,0 +1,21 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.ntdll; + +import static java.lang.foreign.ValueLayout.*; +final class Constants$root { + + // Suppresses default constructor, ensuring non-instantiability. + private Constants$root() {} + static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; + static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; + static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + static final OfInt C_INT$LAYOUT = JAVA_INT; + static final OfInt C_LONG$LAYOUT = JAVA_INT; + static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; + static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; + static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; + static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java new file mode 100644 index 00000000..d43f1028 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java @@ -0,0 +1,26 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.ntdll; + +import static java.lang.foreign.ValueLayout.*; +public class NtDll { + + public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; + public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; + public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; + public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; + public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; + public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; + public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; + public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + /** + * {@snippet : + * #define STATUS_UNSUCCESSFUL -1073741823 + * } + */ + public static int STATUS_UNSUCCESSFUL() { + return (int)-1073741823L; + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/RuntimeHelper.java new file mode 100644 index 00000000..a7c0fcaa --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/RuntimeHelper.java @@ -0,0 +1,217 @@ +package net.codecrete.usb.windows.gen.ntdll; +// Generated by jextract + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static java.lang.foreign.ValueLayout.*; + +final class RuntimeHelper { + + private static final Linker LINKER = Linker.nativeLinker(); + private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); + private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); + private static final SymbolLookup SYMBOL_LOOKUP; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + + final static SegmentAllocator CONSTANT_ALLOCATOR = + (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + + static { + + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); + } + + // Suppresses default constructor, ensuring non-instantiability. + private RuntimeHelper() {} + + static T requireNonNull(T obj, String symbolName) { + if (obj == null) { + throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); + } + return obj; + } + + static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { + return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + } + + static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). + map(addr -> LINKER.downcallHandle(addr, fdesc)). + orElse(null); + } + + static MethodHandle downcallHandle(FunctionDescriptor fdesc) { + return LINKER.downcallHandle(fdesc); + } + + static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { + return SYMBOL_LOOKUP.find(name). + map(addr -> VarargsInvoker.make(addr, fdesc)). + orElse(null); + } + + static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + try { + MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); + handle = handle.bindTo(z); + return LINKER.upcallStub(handle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { + return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + } + + // Internals only below this point + + private static final class VarargsInvoker { + private static final MethodHandle INVOKE_MH; + private final MemorySegment symbol; + private final FunctionDescriptor function; + + private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { + this.symbol = symbol; + this.function = function; + } + + static { + try { + INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { + VarargsInvoker invoker = new VarargsInvoker(symbol, function); + MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); + MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); + for (MemoryLayout layout : function.argumentLayouts()) { + mtype = mtype.appendParameterTypes(carrier(layout, false)); + } + mtype = mtype.appendParameterTypes(Object[].class); + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { + mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); + } else { + handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); + } + return handle.asType(mtype); + } + + static Class carrier(MemoryLayout layout, boolean ret) { + if (layout instanceof ValueLayout valueLayout) { + return valueLayout.carrier(); + } else if (layout instanceof GroupLayout) { + return MemorySegment.class; + } else { + throw new AssertionError("Cannot get here!"); + } + } + + private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { + // one trailing Object[] + int nNamedArgs = function.argumentLayouts().size(); + assert(args.length == nNamedArgs + 1); + // The last argument is the array of vararg collector + Object[] unnamedArgs = (Object[]) args[args.length - 1]; + + int argsCount = nNamedArgs + unnamedArgs.length; + Class[] argTypes = new Class[argsCount]; + MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; + + int pos = 0; + for (pos = 0; pos < nNamedArgs; pos++) { + argLayouts[pos] = function.argumentLayouts().get(pos); + } + + assert pos == nNamedArgs; + for (Object o: unnamedArgs) { + argLayouts[pos] = variadicLayout(normalize(o.getClass())); + pos++; + } + assert pos == argsCount; + + FunctionDescriptor f = (function.returnLayout().isEmpty()) ? + FunctionDescriptor.ofVoid(argLayouts) : + FunctionDescriptor.of(function.returnLayout().get(), argLayouts); + MethodHandle mh = LINKER.downcallHandle(symbol, f); + boolean needsAllocator = function.returnLayout().isPresent() && + function.returnLayout().get() instanceof GroupLayout; + if (needsAllocator) { + mh = mh.bindTo(allocator); + } + // flatten argument list so that it can be passed to an asSpreader MH + Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; + System.arraycopy(args, 0, allArgs, 0, nNamedArgs); + System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); + + return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); + } + + private static Class unboxIfNeeded(Class clazz) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Void.class) { + return void.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return clazz; + } + } + + private Class promote(Class c) { + if (c == byte.class || c == char.class || c == short.class || c == int.class) { + return long.class; + } else if (c == float.class) { + return double.class; + } else { + return c; + } + } + + private Class normalize(Class c) { + c = unboxIfNeeded(c); + if (c.isPrimitive()) { + return promote(c); + } + if (c == MemorySegment.class) { + return MemorySegment.class; + } + throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); + } + + private MemoryLayout variadicLayout(Class c) { + if (c == long.class) { + return JAVA_LONG; + } else if (c == double.class) { + return JAVA_DOUBLE; + } else if (c == MemorySegment.class) { + return ADDRESS; + } else { + throw new IllegalArgumentException("Unhandled variadic argument class: " + c); + } + } + } +} From b74f240c4b60feb95972866b0a5f290baf2d7c7b Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 26 Feb 2023 17:46:47 +0100 Subject: [PATCH 212/433] Control requests use async IO internally (Windows) --- .../usb/windows/WindowsUSBDevice.java | 103 ++++++++++-------- .../usb/windows/WindowsUSBDeviceRegistry.java | 2 +- 2 files changed, 60 insertions(+), 45 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 63d79728..09f3a381 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -38,7 +38,7 @@ public class WindowsUSBDevice extends USBDeviceImpl { private List interfaceHandles_; private boolean isOpen_; - WindowsUSBDevice(WindowsUSBDeviceRegistry registry, String devicePath, Map children, + WindowsUSBDevice(String devicePath, Map children, int vendorId, int productId, MemorySegment configDesc) { super(devicePath, vendorId, productId); asyncTask = WindowsAsyncTask.instance(); @@ -199,60 +199,42 @@ public synchronized void releaseInterface(int interfaceNumber) { setClaimed(interfaceNumber, false); } - private MemorySegment createSetupPacket(USBDirection direction, USBControlTransfer setup, MemorySegment data, - Arena arena) { - var setupPacket = new SetupPacket(arena); - var bmRequest = - (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); - setupPacket.setRequestType(bmRequest); - setupPacket.setRequest(setup.request()); - setupPacket.setValue(setup.value()); - setupPacket.setIndex(setup.index()); - setupPacket.setLength(data != null ? (int) data.byteSize() : 0); - return setupPacket.segment(); - } - @Override - public byte[] controlTransferIn(USBControlTransfer setup, int length) { - checkIsOpen(); - var intfHandle = findControlTransferInterface(setup); - + public void controlTransferOut(USBControlTransfer setup, byte[] data) { try (var arena = Arena.openConfined()) { - var buffer = arena.allocate(length); - var setupPacket = createSetupPacket(USBDirection.IN, setup, buffer, arena); - var lengthHolder = arena.allocate(JAVA_INT); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); - if (WinUSB2.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer, - (int) buffer.byteSize(), lengthHolder, NULL, lastErrorState) == 0) - throwLastError(lastErrorState, "Control transfer IN failed"); + // copy data to native memory + var transfer = createSyncControlTransfer(); + int dataLength = data != null ? data.length : 0; + transfer.dataSize = dataLength; + if (dataLength != 0) { + var buffer = arena.allocate(data.length); + buffer.copyFrom(MemorySegment.ofArray(data)); + transfer.data = buffer; + } else { + transfer.data = NULL; + } - int rxLength = lengthHolder.get(JAVA_INT, 0); - return buffer.asSlice(0, rxLength).toArray(JAVA_BYTE); + synchronized (transfer) { + submitControlTransfer(USBDirection.OUT, setup, transfer); + waitForTransfer(transfer, 0, USBDirection.OUT, 0); + } } } @Override - public void controlTransferOut(USBControlTransfer setup, byte[] data) { - checkIsOpen(); - var intfHandle = findControlTransferInterface(setup); - + public byte[] controlTransferIn(USBControlTransfer setup, int length) { try (var arena = Arena.openConfined()) { + var transfer = createSyncControlTransfer(); + transfer.data = arena.allocate(length); + transfer.dataSize = length; - // copy data to native memory - int dataLength = data != null ? data.length : 0; - MemorySegment buffer = arena.allocate(dataLength); - if (dataLength != 0) - buffer.copyFrom(MemorySegment.ofArray(data)); - - // create setup packet - var setupPacket = createSetupPacket(USBDirection.OUT, setup, buffer, arena); - var lengthHolder = arena.allocate(JAVA_INT); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + synchronized (transfer) { + submitControlTransfer(USBDirection.IN, setup, transfer); + waitForTransfer(transfer, 0, USBDirection.IN, 0); + } - if (WinUSB2.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer, - (int) buffer.byteSize(), lengthHolder, NULL, lastErrorState) == 0) - throwLastError(lastErrorState, "Control transfer OUT failed"); + return transfer.data.asSlice(0, transfer.resultSize).toArray(JAVA_BYTE); } } @@ -287,6 +269,12 @@ public byte[] transferIn(int endpointNumber, int timeout) { } } + private WindowsTransfer createSyncControlTransfer() { + var transfer = new WindowsTransfer(); + transfer.completion = USBDeviceImpl::onSyncTransferCompleted; + return transfer; + } + private WindowsTransfer createSyncTransfer(MemorySegment data) { var transfer = new WindowsTransfer(); transfer.data = data; @@ -305,6 +293,33 @@ protected void throwOSException(int errorCode, String message, Object... args) { throwException(errorCode, message, args); } + synchronized void submitControlTransfer(USBDirection direction, USBControlTransfer setup, WindowsTransfer transfer) { + checkIsOpen(); + var intfHandle = findControlTransferInterface(setup); + + try (var arena = Arena.openConfined()) { + var setupPacket = new SetupPacket(arena); + var bmRequest = + (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); + setupPacket.setRequestType(bmRequest); + setupPacket.setRequest(setup.request()); + setupPacket.setValue(setup.value()); + setupPacket.setIndex(setup.index()); + setupPacket.setLength(transfer.dataSize); + + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + asyncTask.prepareForSubmission(transfer); + + // submit transfer + if (WinUSB2.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket.segment(), transfer.data, + transfer.dataSize, NULL, transfer.overlapped, lastErrorState) == 0) { + int err = Win.getLastError(lastErrorState); + if (err != Kernel32.ERROR_IO_PENDING()) + throwException(err, "Submitting control transfer failed"); + } + } + } + synchronized void submitTransferOut(int endpointNumber, WindowsTransfer transfer) { var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 5421deab..12a21fbb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -326,7 +326,7 @@ private USBDevice createDevice(String devicePath, Map children, var configDesc = getDescriptor(hubHandle, usbPortNum, CONFIGURATION_DESCRIPTOR_TYPE, 0, (short) 0, arena); - var device = new WindowsUSBDevice(this, devicePath, children, vendorId, productId, configDesc); + var device = new WindowsUSBDevice(devicePath, children, vendorId, productId, configDesc); device.setFromDeviceDescriptor(descriptorSegment); device.setProductString(descriptorSegment, (index) -> getStringDescriptor(hubHandle, usbPortNum, index)); From f0778e4097ea2e9db57b0640d88c9087904d882f Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 26 Feb 2023 17:59:19 +0100 Subject: [PATCH 213/433] Cleanup (Windows) --- java-does-usb/jextract/windows/gen_win.cmd | 9 - .../jextract/windows/windows_headers.h | 1 - .../net/codecrete/usb/linux/USBDevFS.java | 4 - .../java/net/codecrete/usb/windows/Win.java | 9 +- .../usb/windows/gen/kernel32/Kernel32.java | 16 -- .../usb/windows/gen/kernel32/constants$1.java | 26 --- .../windows/gen/stdlib/Constants$root.java | 21 -- .../usb/windows/gen/stdlib/RuntimeHelper.java | 217 ------------------ .../usb/windows/gen/stdlib/StdLib.java | 37 --- .../usb/windows/gen/stdlib/constants$0.java | 20 -- .../usb/windows/gen/winusb/constants$1.java | 64 ------ .../usb/windows/winsdk/Kernel32B.java | 13 -- .../codecrete/usb/windows/winsdk/WinUSB2.java | 2 +- 13 files changed, 7 insertions(+), 432 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/Constants$root.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/StdLib.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index 5a3a4d03..e1679449 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -12,12 +12,10 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-function GetModuleHandleW ^ --include-function FormatMessageW ^ --include-function LocalFree ^ - --include-constant ERROR_SUCCESS ^ --include-constant ERROR_NO_MORE_ITEMS ^ --include-constant ERROR_MORE_DATA ^ --include-constant ERROR_INSUFFICIENT_BUFFER ^ --include-constant ERROR_FILE_NOT_FOUND ^ - --include-constant ERROR_SEM_TIMEOUT ^ --include-constant ERROR_GEN_FAILURE ^ --include-constant ERROR_NOT_FOUND ^ --include-constant ERROR_IO_PENDING ^ @@ -65,13 +63,6 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-constant DIREG_DEV ^ windows_headers.h -call %JEXTRACT% --source --output ../../src/main/java ^ - -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ - --header-class-name StdLib ^ - --target-package net.codecrete.usb.windows.gen.stdlib ^ - --include-function wcslen ^ - windows_headers.h - call %JEXTRACT% --source --output ../../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -I "%SDK_DIR%\um" ^ diff --git a/java-does-usb/jextract/windows/windows_headers.h b/java-does-usb/jextract/windows/windows_headers.h index e7b6a1c7..171b98ee 100644 --- a/java-does-usb/jextract/windows/windows_headers.h +++ b/java-does-usb/jextract/windows/windows_headers.h @@ -1,6 +1,5 @@ #include #include -#include #include #include #include diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java index 8fe31c10..a11b9be9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java @@ -12,16 +12,12 @@ */ public class USBDevFS { - public static final long CONTROL = 0xc0185500L; - public static final long BULK = 0xc0185502L; public static final long CLAIMINTERFACE = 0x8004550FL; public static final long RELEASEINTERFACE = 0x80045510L; public static final long SETINTERFACE = 0x80085504L; public static final long CLEAR_HALT = 0x80045515L; public static final long SUBMITURB = 0x8038550AL; public static final long DISCARDURB = 0x550BL; - public static final long REAPURB = 0x4008550CL; public static final long REAPURBNDELAY = 0x4008550DL; - public static final long RESETEP = 0x80045503L; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index cb424e77..ff2a3bea 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -8,7 +8,6 @@ package net.codecrete.usb.windows; import net.codecrete.usb.windows.gen.kernel32.GUID; -import net.codecrete.usb.windows.gen.stdlib.StdLib; import java.lang.foreign.*; import java.lang.invoke.VarHandle; @@ -85,8 +84,12 @@ public static MemorySegment createSegmentFromString(String str, Arena arena) { * @return copied string */ public static String createStringFromSegment(MemorySegment segment) { - long strLen = StdLib.wcslen(segment); - return new String(segment.asSlice(0, 2L * strLen).toArray(JAVA_CHAR)); + int len = 0; + while (segment.get(JAVA_CHAR, len) != 0) { + len += 2; + } + + return new String(segment.asSlice(0, len).toArray(JAVA_CHAR)); } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java index 0aab7d0d..6951a326 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -176,14 +176,6 @@ public static int GENERIC_WRITE() { public static int INFINITE() { return (int)4294967295L; } - /** - * {@snippet : - * #define ERROR_SUCCESS 0 - * } - */ - public static int ERROR_SUCCESS() { - return (int)0L; - } /** * {@snippet : * #define ERROR_FILE_NOT_FOUND 2 @@ -200,14 +192,6 @@ public static int ERROR_FILE_NOT_FOUND() { public static int ERROR_GEN_FAILURE() { return (int)31L; } - /** - * {@snippet : - * #define ERROR_SEM_TIMEOUT 121 - * } - */ - public static int ERROR_SEM_TIMEOUT() { - return (int)121L; - } /** * {@snippet : * #define ERROR_INSUFFICIENT_BUFFER 122 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java deleted file mode 100644 index 306521b3..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java +++ /dev/null @@ -1,26 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.kernel32; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -final class constants$1 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$1() {} - static final FunctionDescriptor FormatMessageW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle FormatMessageW$MH = RuntimeHelper.downcallHandle( - "FormatMessageW", - constants$1.FormatMessageW$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/Constants$root.java deleted file mode 100644 index 01ae179c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.stdlib; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfInt C_LONG$LAYOUT = JAVA_INT; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/RuntimeHelper.java deleted file mode 100644 index 56e1248c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/RuntimeHelper.java +++ /dev/null @@ -1,217 +0,0 @@ -package net.codecrete.usb.windows.gen.stdlib; -// Generated by jextract - -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.*; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); - - static { - - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { - try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/StdLib.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/StdLib.java deleted file mode 100644 index 08c5b6a8..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/StdLib.java +++ /dev/null @@ -1,37 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.stdlib; - -import java.lang.foreign.MemorySegment; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.*; -public class StdLib { - - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; - public static MethodHandle wcslen$MH() { - return RuntimeHelper.requireNonNull(constants$0.wcslen$MH,"wcslen"); - } - /** - * {@snippet : - * unsigned long long wcslen(const wchar_t* _String); - * } - */ - public static long wcslen(MemorySegment _String) { - var mh$ = wcslen$MH(); - try { - return (long)mh$.invokeExact(_String); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/constants$0.java deleted file mode 100644 index 8c197603..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/stdlib/constants$0.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.stdlib; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final FunctionDescriptor wcslen$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle wcslen$MH = RuntimeHelper.downcallHandle( - "wcslen", - constants$0.wcslen$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java deleted file mode 100644 index 06bbbb9c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$1.java +++ /dev/null @@ -1,64 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.winusb; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -final class constants$1 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$1() {} - static final FunctionDescriptor WinUsb_ReadPipe$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle WinUsb_ReadPipe$MH = RuntimeHelper.downcallHandle( - "WinUsb_ReadPipe", - constants$1.WinUsb_ReadPipe$FUNC - ); - static final FunctionDescriptor WinUsb_WritePipe$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle WinUsb_WritePipe$MH = RuntimeHelper.downcallHandle( - "WinUsb_WritePipe", - constants$1.WinUsb_WritePipe$FUNC - ); - static final FunctionDescriptor WinUsb_ControlTransfer$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("RequestType"), - Constants$root.C_CHAR$LAYOUT.withName("Request"), - Constants$root.C_SHORT$LAYOUT.withName("Value"), - Constants$root.C_SHORT$LAYOUT.withName("Index"), - Constants$root.C_SHORT$LAYOUT.withName("Length") - ).withName("_WINUSB_SETUP_PACKET"), - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle WinUsb_ControlTransfer$MH = RuntimeHelper.downcallHandle( - "WinUsb_ControlTransfer", - constants$1.WinUsb_ControlTransfer$FUNC - ); - static final FunctionDescriptor WinUsb_ResetPipe$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT - ); - static final MethodHandle WinUsb_ResetPipe$MH = RuntimeHelper.downcallHandle( - "WinUsb_ResetPipe", - constants$1.WinUsb_ResetPipe$FUNC - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java index ed18a405..ae3ad68c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java @@ -101,17 +101,4 @@ public static MemorySegment CreateIoCompletionPort(MemorySegment FileHandle, Mem throw new RuntimeException(ex); } } - - private static final FunctionDescriptor CancelIoEx$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS); - - private static final MethodHandle CancelIoEx$MH = LINKER.downcallHandle(LOOKUP.find("CancelIoEx").get(), - CancelIoEx$FUNC, Win.LAST_ERROR_STATE); - - public static int CancelIoEx(MemorySegment hFile, MemorySegment lpOverlapped, MemorySegment lastErrorState) { - try { - return (int) CancelIoEx$MH.invokeExact(lastErrorState, hFile, lpOverlapped); - } catch (Throwable ex) { - throw new RuntimeException(ex); - } - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java index 805b94cc..ee4a1c97 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java @@ -146,7 +146,7 @@ public static int WinUsb_ResetPipe(MemorySegment InterfaceHandle, byte PipeID, M private static final FunctionDescriptor WinUsb_AbortPipe$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE); private static final MethodHandle WinUsb_AbortPipe$MH = - LINKER.downcallHandle(LOOKUP.find("WinUsb_AbortPipe").get(), WinUsb_ResetPipe$FUNC, Win.LAST_ERROR_STATE); + LINKER.downcallHandle(LOOKUP.find("WinUsb_AbortPipe").get(), WinUsb_AbortPipe$FUNC, Win.LAST_ERROR_STATE); public static int WinUsb_AbortPipe(MemorySegment InterfaceHandle, byte PipeID, MemorySegment lastErrorState) { try { From 9019cd7b50fa3efa119bcb9ca2d215d4ba6be253 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 27 Feb 2023 20:27:56 +0100 Subject: [PATCH 214/433] Configurable buffer size for input/output streams --- .../java/net/codecrete/usb/USBDevice.java | 33 +++++++++++++++++-- .../usb/common/EndpointInputStream.java | 24 ++++++++------ .../usb/common/EndpointOutputStream.java | 28 +++++++++------- .../usb/linux/LinuxEndpointInputStream.java | 4 +-- .../usb/linux/LinuxEndpointOutputStream.java | 4 +-- .../codecrete/usb/linux/LinuxUSBDevice.java | 8 ++--- .../usb/macos/MacosEndpointInputStream.java | 4 +-- .../usb/macos/MacosEndpointOutputStream.java | 4 +-- .../codecrete/usb/macos/MacosUSBDevice.java | 8 ++--- .../windows/WindowsEndpointInputStream.java | 4 +-- .../windows/WindowsEndpointOutputStream.java | 4 +-- .../usb/windows/WindowsUSBDevice.java | 8 ++--- .../codecrete/usb/sample/LogicAnalyzer.java | 7 +++- 13 files changed, 91 insertions(+), 49 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index 98e0a604..a60d07ff 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -292,9 +292,23 @@ public interface USBDevice { *

* * @param endpointNumber bulk endpoint number (in the range between 1 and 127) + * @param bufferSize approximate buffer size (in bytes) * @return the new output stream */ - OutputStream openOutputStream(int endpointNumber); + OutputStream openOutputStream(int endpointNumber, int bufferSize); + + /** + * Opens a new output stream to send data to a bulk endpoint. + *

+ * The buffer is configured with minimal size. In all other aspects, this method + * works like {@link #openOutputStream(int, int)}. + *

+ * @param endpointNumber bulk endpoint number (in the range between 1 and 127) + * @return the new output stream + */ + default OutputStream openOutputStream(int endpointNumber) { + return openOutputStream(endpointNumber, 1); + } /** * Opens a new input stream to receive data from a bulk endpoint. @@ -309,9 +323,24 @@ public interface USBDevice { *

* * @param endpointNumber bulk endpoint number (in the range between 1 and 127, i.e. without the direction bit) + * @param bufferSize approximate buffer size (in bytes) + * @return the new input stream + */ + InputStream openInputStream(int endpointNumber, int bufferSize); + + /** + * Opens a new input stream to receive data from a bulk endpoint. + *

+ * The buffer is configured with minimal size. In all other aspects, this method + * works like {@link #openInputStream(int, int)}. + *

+ * + * @param endpointNumber bulk endpoint number (in the range between 1 and 127, i.e. without the direction bit) * @return the new input stream */ - InputStream openInputStream(int endpointNumber); + default InputStream openInputStream(int endpointNumber) { + return openInputStream(endpointNumber, 1); + } /** * Aborts all transfers on an endpoint. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index 3ceabd33..6d43fd5d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -35,14 +35,12 @@ */ public abstract class EndpointInputStream extends InputStream { - private static final int MAX_OUTSTANDING_TRANSFERS = 8; - protected USBDeviceImpl device; protected final int endpointNumber; // Arena to allocate buffers and completion handlers protected final Arena arena; - // Size of buffers (multiple of packet size) - protected final int bufferSize; + // Transfer size (multiple of packet size) + protected final int transferSize; // Queue of completed transfers private final ArrayBlockingQueue completedTransferQueue; // Number of outstanding transfers (includes transfers pending with the @@ -58,23 +56,29 @@ public abstract class EndpointInputStream extends InputStream { * * @param device USB device * @param endpointNumber endpoint number + * @param bufferSize approximate buffer size (in bytes) */ - protected EndpointInputStream(USBDeviceImpl device, int endpointNumber) { + protected EndpointInputStream(USBDeviceImpl device, int endpointNumber, int bufferSize) { this.device = device; this.endpointNumber = endpointNumber; arena = Arena.openShared(); - bufferSize = 4 * device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); + + int packetSize = device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); + int n = (int) Math.round(Math.sqrt((double) bufferSize / packetSize)); + n = Math.min(Math.max(n, 4), 32); // 32 limits packet size to 16KB (for USB HS) + transferSize = n * packetSize; + int maxOutstandingTransfers = Math.max((bufferSize + transferSize / 2) / transferSize, 2); configureEndpoint(); - completedTransferQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_TRANSFERS); + completedTransferQueue = new ArrayBlockingQueue<>(maxOutstandingTransfers); // create all transfers, and submit them except one try { - for (int i = 0; i < MAX_OUTSTANDING_TRANSFERS; i++) { + for (int i = 0; i < maxOutstandingTransfers; i++) { final var transfer = device.createTransfer(); - transfer.data = arena.allocate(bufferSize, 8); - transfer.dataSize = bufferSize; + transfer.data = arena.allocate(transferSize, 8); + transfer.dataSize = transferSize; transfer.completion = this::onCompletion; if (i == 0) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java index 972f5c63..f6076879 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -37,15 +37,14 @@ */ public abstract class EndpointOutputStream extends OutputStream { - private static final int MAX_OUTSTANDING_TRANSFERS = 4; protected USBDeviceImpl device; protected final int endpointNumber; protected final Arena arena; // Endpoint's packet size private final int packetSize; - // Size of buffers (multiple of packet size) - private final int bufferSize; + // Transfer size (multiple of packet size) + private final int transferSize; // Blocking queue of available transfers (to limit the number of submitted transfers) private final ArrayBlockingQueue availableTransferQueue; private boolean needsZlp; @@ -60,22 +59,27 @@ public abstract class EndpointOutputStream extends OutputStream { * * @param device USB device * @param endpointNumber endpoint number + * @param bufferSize approximate buffer size (in bytes) */ - protected EndpointOutputStream(USBDeviceImpl device, int endpointNumber) { + protected EndpointOutputStream(USBDeviceImpl device, int endpointNumber, int bufferSize) { this.device = device; this.endpointNumber = endpointNumber; - packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize(); - bufferSize = packetSize; arena = Arena.openShared(); + packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize(); + int n = (int) Math.round(Math.sqrt((double) bufferSize / packetSize)); + n = Math.min(Math.max(n, 4), 32); // 32 limits packet size to 16KB (for USB HS) + transferSize = n * packetSize; + int maxOutstandingTransfers = Math.max((bufferSize + transferSize / 2) / transferSize, 2); + configureEndpoint(); - availableTransferQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_TRANSFERS); + availableTransferQueue = new ArrayBlockingQueue<>(maxOutstandingTransfers); // prefill transfer queue - for (int i = 0; i < MAX_OUTSTANDING_TRANSFERS; i++) { + for (int i = 0; i < maxOutstandingTransfers; i++) { final var transfer = device.createTransfer(); - transfer.data = arena.allocate(bufferSize, 8); + transfer.data = arena.allocate(transferSize, 8); transfer.completion = this::onCompletion; if (i == 0) { @@ -113,7 +117,7 @@ public void write(int b) throws IOException { currentTransfer.data.set(JAVA_BYTE, writeOffset, (byte) b); writeOffset += 1; - if (writeOffset == bufferSize) + if (writeOffset == transferSize) submitTransfer(writeOffset); } @@ -123,13 +127,13 @@ public void write(byte[] b, int off, int len) throws IOException { throw new IOException("Bulk endpoint output stream has been closed"); while (len > 0) { - int chunkSize = Math.min(len, bufferSize - writeOffset); + int chunkSize = Math.min(len, transferSize - writeOffset); MemorySegment.copy(b, off, currentTransfer.data, JAVA_BYTE, writeOffset, chunkSize); writeOffset += chunkSize; off += chunkSize; len -= chunkSize; - if (writeOffset == bufferSize) + if (writeOffset == transferSize) submitTransfer(writeOffset); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java index a8387029..9d1f7ce0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java @@ -13,8 +13,8 @@ public class LinuxEndpointInputStream extends EndpointInputStream { - LinuxEndpointInputStream(LinuxUSBDevice device, int endpointNumber) { - super(device, endpointNumber); + LinuxEndpointInputStream(LinuxUSBDevice device, int endpointNumber, int bufferSize) { + super(device, endpointNumber, bufferSize); } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java index dd7e71c7..ab5b997d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java @@ -13,8 +13,8 @@ public class LinuxEndpointOutputStream extends EndpointOutputStream { - LinuxEndpointOutputStream(LinuxUSBDevice device, int endpointNumber) { - super(device, endpointNumber); + LinuxEndpointOutputStream(LinuxUSBDevice device, int endpointNumber, int bufferSize) { + super(device, endpointNumber, bufferSize); } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 633fa620..023273e8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -304,18 +304,18 @@ public synchronized void abortTransfers(USBDirection direction, int endpointNumb } @Override - public InputStream openInputStream(int endpointNumber) { + public InputStream openInputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, null); - return new LinuxEndpointInputStream(this, endpointNumber); + return new LinuxEndpointInputStream(this, endpointNumber, bufferSize); } @Override - public OutputStream openOutputStream(int endpointNumber) { + public OutputStream openOutputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, null); - return new LinuxEndpointOutputStream(this, endpointNumber); + return new LinuxEndpointOutputStream(this, endpointNumber, bufferSize); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java index 711e6aac..e947caec 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java @@ -12,8 +12,8 @@ public class MacosEndpointInputStream extends EndpointInputStream { - MacosEndpointInputStream(MacosUSBDevice device, int endpointNumber) { - super(device, endpointNumber); + MacosEndpointInputStream(MacosUSBDevice device, int endpointNumber, int bufferSize) { + super(device, endpointNumber, bufferSize); } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java index 56494142..d8f16f2c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java @@ -12,8 +12,8 @@ public class MacosEndpointOutputStream extends EndpointOutputStream { - MacosEndpointOutputStream(MacosUSBDevice device, int endpointNumber) { - super(device, endpointNumber); + MacosEndpointOutputStream(MacosUSBDevice device, int endpointNumber, int bufferSize) { + super(device, endpointNumber, bufferSize); } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 2c69fe44..4061238b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -541,19 +541,19 @@ public void clearHalt(USBDirection direction, int endpointNumber) { } @Override - public InputStream openInputStream(int endpointNumber) { + public InputStream openInputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, null); - return new MacosEndpointInputStream(this, endpointNumber); + return new MacosEndpointInputStream(this, endpointNumber, bufferSize); } @Override - public OutputStream openOutputStream(int endpointNumber) { + public OutputStream openOutputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, null); - return new MacosEndpointOutputStream(this, endpointNumber); + return new MacosEndpointOutputStream(this, endpointNumber, bufferSize); } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java index ba20ef78..d331954e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java @@ -13,8 +13,8 @@ public class WindowsEndpointInputStream extends EndpointInputStream { - WindowsEndpointInputStream(WindowsUSBDevice device, int endpointNumber) { - super(device, endpointNumber); + WindowsEndpointInputStream(WindowsUSBDevice device, int endpointNumber, int bufferSize) { + super(device, endpointNumber, bufferSize); } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java index 8618bceb..46eb0f31 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java @@ -13,8 +13,8 @@ public class WindowsEndpointOutputStream extends EndpointOutputStream { - WindowsEndpointOutputStream(WindowsUSBDevice device, int endpointNumber) { - super(device, endpointNumber); + WindowsEndpointOutputStream(WindowsUSBDevice device, int endpointNumber, int bufferSize) { + super(device, endpointNumber, bufferSize); } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 09f3a381..a496fea9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -400,19 +400,19 @@ public synchronized void abortTransfers(USBDirection direction, int endpointNumb } @Override - public InputStream openInputStream(int endpointNumber) { + public InputStream openInputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, null); - return new WindowsEndpointInputStream(this, endpointNumber); + return new WindowsEndpointInputStream(this, endpointNumber, bufferSize); } @Override - public OutputStream openOutputStream(int endpointNumber) { + public OutputStream openOutputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, null); - return new WindowsEndpointOutputStream(this, endpointNumber); + return new WindowsEndpointOutputStream(this, endpointNumber, bufferSize); } private InterfaceHandle getInterfaceHandle(int interfaceNumber) { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java b/java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java index 30ca96dc..b280266c 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java @@ -71,6 +71,8 @@ public class LogicAnalyzer implements Closeable { private volatile long activityValue; /// Indicates a dry run (to suppress output) private boolean isDryRun; + /// Buffer size for input stream (good for approx. 0.2s of data) + private int bufferSize; public static void main(String[] args) { try (var logicAnalyzer = new LogicAnalyzer()) { @@ -146,6 +148,9 @@ void prepareSampling(int sampleRate, int duration) { period = ticks30Mhz; effSampleRate = 30000000 / period; } + + bufferSize = (int) Math.round(effSampleRate * 0.2); + bufferSize = Math.max(bufferSize, 16 * 4096); } /** @@ -179,7 +184,7 @@ void saveSamples() { byte[] sampleData = new byte[expectedSize]; int size = 0; - try (var is = device.openInputStream(EP)) { + try (var is = device.openInputStream(EP, bufferSize)) { while (size < expectedSize) { int n = is.read(sampleData, size, sampleData.length - size); From f7e8b786f43577600e1f0c88a971acb341e6748e Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 23 Mar 2023 10:19:25 +0100 Subject: [PATCH 215/433] Update README --- README.md | 16 ++++++++-------- java-does-usb/jextract/README.md | 10 ++++++++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 0087777f..0600b71f 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Java Does USB: USB Library for Java -> **Development branch for JDK 20** - [![javadoc](https://javadoc.io/badge2/net.codecrete.usb/java-does-usb/javadoc.svg)](https://javadoc.io/doc/net.codecrete.usb/java-does-usb) -*Java Does USB* is a library for working with USB devices. It allows to query information about all conntected USB devices and to communicate with USB devices using custom / vendor specific protocols. (It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc.) +*Java Does USB* is a Java library for working with USB devices. It allows to query information about all conntected USB devices and to communicate with USB devices using custom / vendor specific protocols. (It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc.) + +The library uses the [Foreign Function & Memory API](https://github.com/openjdk/panama-foreign) to access native APIs of the underlying operating system. It only uses Java code and does not need JNI or any native third-party library. The *Foreign Function & Memory API* (aka as project Panama) is in preview and will be introduced in a future Java version. Currently, it can be used with Java 19 or Java 20 (with preview features enabled). -The library uses the [Foreign Function & Memory API](https://github.com/openjdk/panama-foreign) to access native APIs of the underlying operating system. It only uses Java code and does not need JNI or any native third-party library. The *Foreign Function & Memory API* (aka as project Panama) is in preview and will be introduced in a future Java version. Currently, it can be used with Java 19 (with preview features enabled). +*Note: The main branch and published versions ≥ 0.5.0 work with JDK 20 only. For JDK 19, use version 0.4.x.* ## Features @@ -16,12 +16,12 @@ The library uses the [Foreign Function & Memory API](https://github.com/openjdk/ - Control, bulk and interrupt transfers (optionally with timeout) - Notifications about connected/disconnected devices - Descriptive information about interfaces, settings and endpoints +- High-throughput input/output streams - Support for alternate interface settings, composite devices and interface association - Published on Maven Central ### Planned -- High-throughput input/output streams - Isochronous transfer ### Not planned @@ -41,7 +41,7 @@ If you are using Maven, add the below dependency to your pom.xml: net.codecrete.usb java-does-usb - 0.4.1 + 0.5.0 ``` @@ -85,7 +85,7 @@ public class EnumerateDevices { - Java 20, preview features enabled (available at https://www.azul.com/downloads/?package=jdk) - Windows (x86 64-bit), macOS (x86 64-bit, ARM 64-bit) or Linux 64 bit (x86 64-bit, ARM 64-bit) -For a version compatible with JDK 20, see the branch `jdk20`. +For JDK 19, use the latest published version 0.4.x. ## Platform-specific Considerations @@ -126,7 +126,7 @@ The library has not been tested on Windows for ARM64. It might or might not work ### 32-bit versions -The Foreign Function & Memory API has not been implemented for 32-bit operating systems / JDKs. So it does not support them (and likely never will). +The Foreign Function & Memory API has not been implemented for 32-bit operating systems / JDKs (and likely never will be). diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index f89193ef..be543cf4 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -13,7 +13,11 @@ The resulting code is then committed to the source code repository. Before the c ## General limitations -- Binaries of *jextract* can be downloaded from https://jdk.java.net/jextract/. x64 binaries are available but no ARM64 binaries. According to the mailing list, cross-compiling is not possible, i.e. ARM64 binaries are needed on macOS with Apple Silicon. But so far, the x64 binaries (using the Rosetta2 emulation) have worked without problems. +- The binaries for *jextract* on https://jdk.java.net/jextract/ have not been updated for JDK 20. So it must be built from source. Instructions can be found at [Building & Testing](https://github.com/openjdk/jextract#building--testing). + +- According to the jextract mailing list, it would be required to create separate code form Intel x64 and ARM64 architecture. And jextract would need to be run on each architecture separately (no cross-compilation). Fortunately, this doesn't seem to be the case. Linux code generated on Intel x64 also runs on ARM64 without change. The same holds for macOS. However, jextract needs to be run on each operating system separately. + +- JDK 20 introduced a new feature for saving the thread-specific error values (`GetLastError()` on Windows, `errno` on Linux). To use it, an additional parameter must be added to function calls. Unfortuntely, this is not yet supported by jextract. So with the JDK 20 updates, more code is written manually and less is generated by jextract. - `typedef` and `struct`: @@ -64,7 +68,7 @@ SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so", MemorySessi ## MacOS -Most of the required native functions on macOS are part of a framework. Framework internally have a more complex file organization of header and binary files than appears on the outside. Thus they require a special logic to locate framework header files. *clang* supports it with the `-F`. *jextract* allows to specify the options via `compiler_flags.txt` file. Since the file must be in the local directory and since it does not apply to Linux and Windows, separate directories must be used for the operating systems. +Most of the required native functions on macOS are part of a framework. Frameworks internally have a more complex file organization of header and binary files than appears from the outside. Thus they require a special logic to locate framework header files. *clang* supports it with the `-F`. *jextract* allows to specify the options via `compiler_flags.txt` file. Since the file must be in the local directory and since it does not apply to Linux and Windows, separate directories must be used for the operating systems. The generated code has the same problem as the Linux code for *udev*. It must be manually changed to use `SymbolLookup.libraryLookup()` for the libraries `CoreFoundation.framework/CoreFoundation` and `IOKit.framework/IOKit` respectively. @@ -73,6 +77,8 @@ The generated code has the same problem as the Linux code for *udev*. It must be Most Windows SDK header files are not independent. They require that `Windows.h` is included first. So instead of specifying the target header files directly, a helper header file (`windows_headers.h` in this directory) is specified. +Compared to Linux and macOS, the code generation on Windows is very slow (about 1 min vs 3 seconds). And jextract crashes sometimes. + The known limitations are: - Variable size `struct`: Several Windows struct are of variable size. The last member is an array. The `struct` definition specifies array length 1. But you are expected to allocate more space depending on the actual array size you need. *jextract* generates code for array length 1 and when access array members, the length is checked. So the generated code is difficult to use. Variable size `struct`s are a pain - in any language. From 8502a30dfa9bfd5c94d09db27f7e60efcda1eb5b Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 23 Mar 2023 14:22:18 +0100 Subject: [PATCH 216/433] Upgrade examples to 0.5.0 --- README.md | 2 +- examples/bulk_transfer/README.md | 16 ++++++++-------- examples/bulk_transfer/pom.xml | 17 +++++++++++------ examples/enumerate/README.md | 11 ++++++----- examples/enumerate/pom.xml | 21 +++++++++++++-------- examples/monitor/README.md | 11 ++++++----- examples/monitor/pom.xml | 21 +++++++++++++-------- examples/stm_dfu/README.md | 12 ++++++------ examples/stm_dfu/pom.xml | 29 +++++++++++++++++------------ 9 files changed, 81 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 0600b71f..d6b0ce23 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ If you are using Maven, add the below dependency to your pom.xml: If you are using Gradle, add the below dependency to your build.gradle file: ```groovy -compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '0.4.1' +compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '0.5.0' ``` ```java diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index 64386371..246ad9cd 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -4,16 +4,16 @@ This sample shows how to find a device, open it and transfer data from and to bu ## Prerequisites -- Java 19 +- Java 20 - Apache Maven - 64-bit operating system (Windows, macOS, Linux) - A USB device with bulk IN and OUT endpoints (e.g. the test device, see https://github.com/manuelbl/JavaDoesUSB/tree/main/test-devices/loopback-stm32) ## How to run -### Install Java 19 +### Install Java 20 -Check that *Java 19* is installed: +Check that *Java 20* is installed: ```shell $ java -version @@ -39,16 +39,16 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] --------------< net.codecrete.usb.examples:bulk-transfer >-------------- -[INFO] Building bulk-transfer 0.4.0 +[INFO] Building bulk-transfer 0.5.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ bulk-transfer --- [INFO] Using 'UTF-8' encoding to copy filtered resources. -[INFO] skip non existing resourceDirectory /Users/manuel/Documents/Lab/JavaDoesUSB/examples/bulk_transfer/src/main/resources +[INFO] skip non existing resourceDirectory /Users/me/Documents/JavaDoesUSB/examples/bulk_transfer/src/main/resources [INFO] [INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ bulk-transfer --- [INFO] Changes detected - recompiling the module! -[INFO] Compiling 1 source file to /Users/manuel/Documents/Lab/JavaDoesUSB/examples/bulk_transfer/target/classes +[INFO] Compiling 1 source file to /Users/me/Documents/JavaDoesUSB/examples/bulk_transfer/target/classes [INFO] [INFO] --- exec-maven-plugin:3.1.0:exec (default-cli) @ bulk-transfer --- 6 bytes sent. @@ -56,7 +56,7 @@ $ mvn compile exec:exec [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ -[INFO] Total time: 3.830 s -[INFO] Finished at: 2022-09-09T14:43:10+02:00 +[INFO] Total time: 1.259 s +[INFO] Finished at: 2023-03-23T14:10:17+01:00 [INFO] ------------------------------------------------------------------------ ``` diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index ad0745b4..fac703df 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples bulk-transfer - 0.4.1 + 0.5.0 bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.4.1 + 0.5.0 @@ -42,15 +42,20 @@ maven-compiler-plugin 3.8.0 - 19 - --enable-preview - 19 - 19 + 20 + + --enable-preview + + 20 + 20
maven-surefire-plugin 2.22.1 + + --enable-preview --enable-native-access=ALL-UNNAMED + maven-jar-plugin diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index 9405cde4..ec4dcf7c 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -4,15 +4,15 @@ This sample enumerates the connected USB devices and provides information about ## Prerequisites -- Java 19 +- Java 20 - Apache Maven - 64-bit operating system (Windows, macOS, Linux) ## How to run -### Install Java 19 +### Install Java 20 -Check that *Java 19* is installed: +Check that *Java 20* is installed: ```shell $ java -version @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] ----------------< net.codecrete.usb.examples:enumerate >---------------- -[INFO] Building enumerate 0.4.1 +[INFO] Building enumerate 0.5.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ enumerate --- @@ -46,7 +46,8 @@ $ mvn compile exec:exec [INFO] skip non existing resourceDirectory /Users/me/Documents/JavaDoesUSB/examples/enumerate/src/main/resources [INFO] [INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ enumerate --- -[INFO] Nothing to compile - all classes are up to date +[INFO] Changes detected - recompiling the module! +[INFO] Compiling 2 source files to /Users/me/Documents/JavaDoesUSB/examples/enumerate/target/classes [INFO] [INFO] --- exec-maven-plugin:3.1.0:exec (default-cli) @ enumerate --- Device: diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index 67853aa7..c5a66cd9 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,22 +6,22 @@ net.codecrete.usb.examples enumerate - 0.4.1 + 0.5.0 enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate UTF-8 - 19 - 19 + 20 + 20 net.codecrete.usb java-does-usb - 0.4.1 + 0.5.0 @@ -42,15 +42,20 @@ maven-compiler-plugin 3.8.0 - 19 - --enable-preview - 19 - 19 + 20 + + --enable-preview + + 20 + 20 maven-surefire-plugin 2.22.1 + + --enable-preview --enable-native-access=ALL-UNNAMED + maven-jar-plugin diff --git a/examples/monitor/README.md b/examples/monitor/README.md index 816498b1..18979fcb 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -4,15 +4,15 @@ This sample program monitors USB devices as they are connected and disconnected. ## Prerequisites -- Java 19 +- Java 20 - Apache Maven - 64-bit operating system (Windows, macOS, Linux) ## How to run -### Install Java 19 +### Install Java 20 -Check that *Java 19* is installed: +Check that *Java 20* is installed: ```shell $ java -version @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -----------------< net.codecrete.usb.examples:monitor >----------------- -[INFO] Building monitor 0.4.1 +[INFO] Building monitor 0.5.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ monitor --- @@ -46,7 +46,8 @@ $ mvn compile exec:exec [INFO] skip non existing resourceDirectory /Users/me/Documents/JavaDoesUSB/examples/monitor/src/main/resources [INFO] [INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ monitor --- -[INFO] Nothing to compile - all classes are up to date +[INFO] Changes detected - recompiling the module! +[INFO] Compiling 1 source file to /Users/me/Documents/JavaDoesUSB/examples/monitor/target/classes [INFO] [INFO] --- exec-maven-plugin:3.1.0:exec (default-cli) @ monitor --- Present: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 8D8F515C5456, ID: 4295291950 diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index 80bb68e6..32fbfcbe 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,22 +6,22 @@ net.codecrete.usb.examples monitor - 0.4.1 + 0.5.0 monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor UTF-8 - 19 - 19 + 20 + 20 net.codecrete.usb java-does-usb - 0.4.1 + 0.5.0 @@ -42,15 +42,20 @@ maven-compiler-plugin 3.8.0 - 19 - --enable-preview - 19 - 19 + 20 + + --enable-preview + + 20 + 20 maven-surefire-plugin 2.22.1 + + --enable-preview --enable-native-access=ALL-UNNAMED + maven-jar-plugin diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index b4c1742d..0b22186d 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -6,15 +6,15 @@ Even though the DFU ## Prerequisites -- Java 19 +- Java 20 - Apache Maven - 64-bit operating system (Windows, macOS, Linux) ## How to run -### Install Java 19 +### Install Java 20 -Check that *Java 19* is installed: +Check that *Java 20* is installed: ```shell $ java -version @@ -57,8 +57,8 @@ SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE="0666" Run the command below (adapting the file path depending on your specific board): ```shell -$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.4.1.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin -DFU device found with serial 36C730037136. +$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.5.0.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin +DFU device found with serial 35A737883336. Target memory segment: Internal Flash Erasing page at 0x8000000 (size 0x4000) Writing data at 0x8000000 (size 0x800) @@ -66,7 +66,7 @@ Writing data at 0x8000800 (size 0x800) Writing data at 0x8001000 (size 0x800) Writing data at 0x8001800 (size 0x800) Writing data at 0x8002000 (size 0x800) -Writing data at 0x8002800 (size 0x4cc) +Writing data at 0x8002800 (size 0x1f4) Firmware successfully downloaded and verified DFU mode exited and firmware started ``` diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index a7d18974..8ad9f2be 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -4,16 +4,22 @@ net.codecrete.usb.examples stm_dfu - 0.4.1 + 0.5.0 stm_dfu https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu + + UTF-8 + 20 + 20 + + net.codecrete.usb java-does-usb - 0.4.1 + 0.5.0 @@ -31,10 +37,12 @@ maven-compiler-plugin 3.8.0 - 19 - --enable-preview - 19 - 19 + 20 + + --enable-preview + + 20 + 20 @@ -44,6 +52,9 @@ maven-surefire-plugin 2.22.2 + + --enable-preview --enable-native-access=ALL-UNNAMED + maven-shade-plugin @@ -76,10 +87,4 @@ - - - 19 - 19 - UTF-8 - From 7510a7217b01be3885e48e5cc7fc0c4216bcc3cc Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 26 Apr 2023 18:51:03 +0200 Subject: [PATCH 217/433] Unload and restore kernel driver on Linux --- java-does-usb/jextract/README.md | 2 +- java-does-usb/jextract/linux/gen_linux.sh | 12 +- .../codecrete/usb/linux/LinuxUSBDevice.java | 22 +++- .../net/codecrete/usb/linux/USBDevFS.java | 5 +- .../usbdevfs_disconnect_claim.java | 93 ++++++++++++++ .../gen/usbdevice_fs/usbdevfs_ioctl.java | 118 ++++++++++++++++++ .../linux/gen/usbdevice_fs/usbdevice_fs.java | 8 ++ .../codecrete/usb/sample/USBSerialTest.java | 93 ++++++++++++++ reference/linux/usb_device.cpp | 15 ++- 9 files changed, 355 insertions(+), 13 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/sample/USBSerialTest.java diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index be543cf4..f7562a0e 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -62,7 +62,7 @@ SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); with: ``` -SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so", MemorySession.openImplicit()); +SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so.1", MemorySession.openImplicit()); ``` diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index 9e1a717f..cb11fb2b 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -2,14 +2,6 @@ JEXTRACT=../../../../jextract/build/jextract/bin/jextract -# sd-device.h (install libsystemd-dev if file is missing) -# Error: /usr/include/inttypes.h:290:8: error: unknown type name 'intmax_t' -#$JEXTRACT --source --output ../src/main/java \ -#$JEXTRACT --source --output ../src/main/java \ -# --header-class-name sd_device \ -# --target-package net.codecrete.usb.linux.gen.sd-device -# /usr/include/systemd/sd-device.h - # errno.h $JEXTRACT --source --output ../../src/main/java \ --header-class-name errno \ @@ -51,6 +43,8 @@ $JEXTRACT --source --output ../../src/main/java \ --include-struct usbdevfs_ctrltransfer \ --include-struct usbdevfs_setinterface \ --include-struct usbdevfs_urb \ + --include-struct usbdevfs_disconnect_claim \ + --include-struct usbdevfs_ioctl \ --include-constant USBDEVFS_CONTROL \ --include-constant USBDEVFS_BULK \ --include-constant USBDEVFS_CLAIMINTERFACE \ @@ -60,10 +54,12 @@ $JEXTRACT --source --output ../../src/main/java \ --include-constant USBDEVFS_SUBMITURB \ --include-constant USBDEVFS_DISCARDURB \ --include-constant USBDEVFS_REAPURB \ + --include-constant USBDEVFS_DISCONNECT_CLAIM \ --include-constant USBDEVFS_URB_TYPE_INTERRUPT \ --include-constant USBDEVFS_URB_TYPE_CONTROL \ --include-constant USBDEVFS_URB_TYPE_BULK \ --include-constant USBDEVFS_URB_TYPE_ISO \ + --include-constant USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER \ /usr/include/linux/usbdevice_fs.h # libudev.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 023273e8..602a089e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -16,7 +16,10 @@ import net.codecrete.usb.common.USBInterfaceImpl; import net.codecrete.usb.linux.gen.fcntl.fcntl; import net.codecrete.usb.linux.gen.unistd.unistd; +import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_disconnect_claim; +import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_ioctl; import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_setinterface; +import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs; import net.codecrete.usb.usbstandard.DeviceDescriptor; import net.codecrete.usb.usbstandard.SetupPacket; @@ -110,9 +113,18 @@ public synchronized void claimInterface(int interfaceNumber) { try (var arena = Arena.openConfined()) { var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); - int ret = IO.ioctl(fd, USBDevFS.CLAIMINTERFACE, intfNumSegment, errnoState); + + // claim interface (possibly disconnecting kernel driver) + var disconnectClaim = usbdevfs_disconnect_claim.allocate(arena); + usbdevfs_disconnect_claim.interface_$set(disconnectClaim, interfaceNumber); + usbdevfs_disconnect_claim.flags$set(disconnectClaim, usbdevice_fs.USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER()); + byte[] driverName = { 'u', 's', 'b', 'f', 's', 0 }; + usbdevfs_disconnect_claim.driver$slice(disconnectClaim).copyFrom(MemorySegment.ofArray(driverName)); + int ret = IO.ioctl(fd, USBDevFS.DISCONNECT_CLAIM, disconnectClaim, errnoState); + if (ret != 0) throwLastError(errnoState, "Cannot claim USB interface"); + setClaimed(interfaceNumber, true); } } @@ -161,7 +173,15 @@ public synchronized void releaseInterface(int interfaceNumber) { int ret = IO.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment, errnoState); if (ret != 0) throwLastError(errnoState, "Cannot release USB interface"); + setClaimed(interfaceNumber, false); + + // reattach kernel driver + var request = usbdevfs_ioctl.allocate(arena); + usbdevfs_ioctl.ifno$set(request, interfaceNumber); + usbdevfs_ioctl.ioctl_code$set(request, USBDevFS.CONNECT); + usbdevfs_ioctl.data$set(request, MemorySegment.NULL); + IO.ioctl(fd, USBDevFS.IOCTL, request, errnoState); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java index a11b9be9..4f05637f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java @@ -12,12 +12,13 @@ */ public class USBDevFS { - public static final long CLAIMINTERFACE = 0x8004550FL; public static final long RELEASEINTERFACE = 0x80045510L; public static final long SETINTERFACE = 0x80085504L; public static final long CLEAR_HALT = 0x80045515L; public static final long SUBMITURB = 0x8038550AL; public static final long DISCARDURB = 0x550BL; public static final long REAPURBNDELAY = 0x4008550DL; - + public static final long DISCONNECT_CLAIM = 0x8108551BL; + public static final int CONNECT = 0x5517; + public static final long IOCTL = 0xC0105512L; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java new file mode 100644 index 00000000..fa658189 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java @@ -0,0 +1,93 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct usbdevfs_disconnect_claim { + * unsigned int interface; + * unsigned int flags; + * char driver[256]; + * }; + * } + */ +public class usbdevfs_disconnect_claim { + + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_INT$LAYOUT.withName("interface"), + Constants$root.C_INT$LAYOUT.withName("flags"), + MemoryLayout.sequenceLayout(256, Constants$root.C_CHAR$LAYOUT).withName("driver") + ).withName("usbdevfs_disconnect_claim"); + public static MemoryLayout $LAYOUT() { + return usbdevfs_disconnect_claim.$struct$LAYOUT; + } + static final VarHandle interface_$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("interface")); + public static VarHandle interface_$VH() { + return usbdevfs_disconnect_claim.interface_$VH; + } + /** + * Getter for field: + * {@snippet : + * unsigned int interface; + * } + */ + public static int interface_$get(MemorySegment seg) { + return (int)usbdevfs_disconnect_claim.interface_$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * unsigned int interface; + * } + */ + public static void interface_$set(MemorySegment seg, int x) { + usbdevfs_disconnect_claim.interface_$VH.set(seg, x); + } + public static int interface_$get(MemorySegment seg, long index) { + return (int)usbdevfs_disconnect_claim.interface_$VH.get(seg.asSlice(index*sizeof())); + } + public static void interface_$set(MemorySegment seg, long index, int x) { + usbdevfs_disconnect_claim.interface_$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle flags$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("flags")); + public static VarHandle flags$VH() { + return usbdevfs_disconnect_claim.flags$VH; + } + /** + * Getter for field: + * {@snippet : + * unsigned int flags; + * } + */ + public static int flags$get(MemorySegment seg) { + return (int)usbdevfs_disconnect_claim.flags$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * unsigned int flags; + * } + */ + public static void flags$set(MemorySegment seg, int x) { + usbdevfs_disconnect_claim.flags$VH.set(seg, x); + } + public static int flags$get(MemorySegment seg, long index) { + return (int)usbdevfs_disconnect_claim.flags$VH.get(seg.asSlice(index*sizeof())); + } + public static void flags$set(MemorySegment seg, long index, int x) { + usbdevfs_disconnect_claim.flags$VH.set(seg.asSlice(index*sizeof()), x); + } + public static MemorySegment driver$slice(MemorySegment seg) { + return seg.asSlice(8, 256); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java new file mode 100644 index 00000000..34dbb990 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java @@ -0,0 +1,118 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.*; +import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct usbdevfs_ioctl { + * int ifno; + * int ioctl_code; + * void* data; + * }; + * } + */ +public class usbdevfs_ioctl { + + static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( + Constants$root.C_INT$LAYOUT.withName("ifno"), + Constants$root.C_INT$LAYOUT.withName("ioctl_code"), + Constants$root.C_POINTER$LAYOUT.withName("data") + ).withName("usbdevfs_ioctl"); + public static MemoryLayout $LAYOUT() { + return usbdevfs_ioctl.$struct$LAYOUT; + } + static final VarHandle ifno$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ifno")); + public static VarHandle ifno$VH() { + return usbdevfs_ioctl.ifno$VH; + } + /** + * Getter for field: + * {@snippet : + * int ifno; + * } + */ + public static int ifno$get(MemorySegment seg) { + return (int)usbdevfs_ioctl.ifno$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * int ifno; + * } + */ + public static void ifno$set(MemorySegment seg, int x) { + usbdevfs_ioctl.ifno$VH.set(seg, x); + } + public static int ifno$get(MemorySegment seg, long index) { + return (int)usbdevfs_ioctl.ifno$VH.get(seg.asSlice(index*sizeof())); + } + public static void ifno$set(MemorySegment seg, long index, int x) { + usbdevfs_ioctl.ifno$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle ioctl_code$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ioctl_code")); + public static VarHandle ioctl_code$VH() { + return usbdevfs_ioctl.ioctl_code$VH; + } + /** + * Getter for field: + * {@snippet : + * int ioctl_code; + * } + */ + public static int ioctl_code$get(MemorySegment seg) { + return (int)usbdevfs_ioctl.ioctl_code$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * int ioctl_code; + * } + */ + public static void ioctl_code$set(MemorySegment seg, int x) { + usbdevfs_ioctl.ioctl_code$VH.set(seg, x); + } + public static int ioctl_code$get(MemorySegment seg, long index) { + return (int)usbdevfs_ioctl.ioctl_code$VH.get(seg.asSlice(index*sizeof())); + } + public static void ioctl_code$set(MemorySegment seg, long index, int x) { + usbdevfs_ioctl.ioctl_code$VH.set(seg.asSlice(index*sizeof()), x); + } + static final VarHandle data$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("data")); + public static VarHandle data$VH() { + return usbdevfs_ioctl.data$VH; + } + /** + * Getter for field: + * {@snippet : + * void* data; + * } + */ + public static MemorySegment data$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)usbdevfs_ioctl.data$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * void* data; + * } + */ + public static void data$set(MemorySegment seg, MemorySegment x) { + usbdevfs_ioctl.data$VH.set(seg, x); + } + public static MemorySegment data$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)usbdevfs_ioctl.data$VH.get(seg.asSlice(index*sizeof())); + } + public static void data$set(MemorySegment seg, long index, MemorySegment x) { + usbdevfs_ioctl.data$VH.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java index e6a5e495..0a36e81d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java @@ -45,6 +45,14 @@ public static int USBDEVFS_URB_TYPE_CONTROL() { public static int USBDEVFS_URB_TYPE_BULK() { return (int)3L; } + /** + * {@snippet : + * #define USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER 2 + * } + */ + public static int USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER() { + return (int)2L; + } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/USBSerialTest.java b/java-does-usb/src/test/java/net/codecrete/usb/sample/USBSerialTest.java new file mode 100644 index 00000000..da6d5546 --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/sample/USBSerialTest.java @@ -0,0 +1,93 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.sample; + +import net.codecrete.usb.*; + +/** + * Interacts with a USB CDC device (serial device) directly,without using the + * standard USB CDC driver. + * + *

+ * This test is aimed at Linux, which requires to unload and restore the + * kernel driver. It also works on macOS (without the needed to unload a + * driver). It will fail on Windows as the standard driver is in the way and + * cannot be quickly replaced. + *

+ *

+ * For the test to work on Linux, the user must have sufficient permission to + * access the device at the USB level. So check the permissions under + * /dev/bus/usb/... The permissions of the serial device (/dev/tty...) do not + * apply for this test. + *

+ */ +public class USBSerialTest { + public static void main(String[] args) { + + for (var device : USB.getAllDevices()) { + int commInterfaceNum = getCDCCommInterfaceNum(device); + if (commInterfaceNum >= 0) { + System.out.printf("USB CDC device: %s%n", device); + interact(device, commInterfaceNum); + } + } + } + + static void interact(USBDevice device, int commInterfaceNum) { + // communication and data interface must have consecutive numbers + int dataInterfaceNum = commInterfaceNum + 1; + + // open device and interfaces + device.open(); + device.claimInterface(commInterfaceNum); + device.claimInterface(dataInterfaceNum); + + // set line coding (9600bps, 8 bit) + byte[] coding = { (byte)0x80, 0x25, 0, 0, 0, 0, 8 }; + device.controlTransferOut( + new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, 0x20, 0, commInterfaceNum), + coding); + + // send some data + int dataOutEp = getDataOutEndpointNum(device, dataInterfaceNum); + byte[] data = { 'H', 'e', 'l', 'l', 'o', '\r', '\n' }; + device.transferOut(dataOutEp, data); + + // close device and interfaces + device.releaseInterface(dataInterfaceNum); + device.releaseInterface(commInterfaceNum); + device.close(); + } + + static int getCDCCommInterfaceNum(USBDevice device) { + // CDC ACM implementations consist of two consecutive interfaces + // with certain class, subclass and protocol codes + int numInterfaces = device.interfaces().size(); + if (numInterfaces < 2) + return -1; + + for (int i = 0; i < numInterfaces - 1; i += 1) { + var commIntf = device.getInterface(i).alternate(); + var dataIntf = device.getInterface(i + 1).alternate(); + + if (commIntf.classCode() == 2 && commIntf.subclassCode() == 2 && commIntf.protocolCode() == 1 && dataIntf.classCode() == 10) + return i; + } + + return -1; + } + + static int getDataOutEndpointNum(USBDevice device, int dataInterfaceNum) { + var altInterface = device.getInterface(dataInterfaceNum).alternate(); + for (var endpoint : altInterface.endpoints()) { + if (endpoint.direction() == USBDirection.OUT) + return endpoint.number(); + } + return -1; + } +} diff --git a/reference/linux/usb_device.cpp b/reference/linux/usb_device.cpp index 02427bc6..387d4040 100644 --- a/reference/linux/usb_device.cpp +++ b/reference/linux/usb_device.cpp @@ -142,8 +142,14 @@ void usb_device::claim_interface(int interface_number) { if (intf->is_claimed()) throw usb_error("interface has already been claimed"); + + usbdevfs_disconnect_claim dc = { + .interface = static_cast(interface_number), + .flags = USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER, + .driver = "usbfs" + }; - int result = ioctl(fd_, USBDEVFS_CLAIMINTERFACE, &interface_number); + int result = ioctl(fd_, USBDEVFS_DISCONNECT_CLAIM, &dc); if (result < 0) usb_error::throw_error("Failed to claim interface"); @@ -169,6 +175,13 @@ void usb_device::release_interface(int interface_number) { intf->set_claimed(false); claimed_interfaces_.erase(interface_number); + + usbdevfs_ioctl cmd = { + .ifno = interface_number, + .ioctl_code = USBDEVFS_CONNECT, + .data = nullptr + }; + ioctl(fd_, USBDEVFS_IOCTL, &cmd); } std::vector usb_device::transfer_in(int endpoint_number, int timeout) { From 085f68e64d50204674c63c97661984b06110822f Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 26 Apr 2023 18:51:24 +0200 Subject: [PATCH 218/433] Better filename for locating libudev --- .../java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java index 9529b895..09317884 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java @@ -22,7 +22,7 @@ final class RuntimeHelper { static { // System.loadLibrary("udev"); // SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so", SegmentScope.global()); + SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so.1", SegmentScope.global()); SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } From 85801e156ece6a286c4b99eba0b1e7a108447726 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 28 Apr 2023 20:34:02 +0200 Subject: [PATCH 219/433] macOS: use USBOpenDeviceSeize --- java-does-usb/jextract/macos/gen_macos.sh | 4 +- .../net/codecrete/usb/macos/IoKitHelper.java | 12 +- .../net/codecrete/usb/macos/IoKitUSB.java | 28 +- .../codecrete/usb/macos/MacosUSBDevice.java | 4 +- .../usb/macos/MacosUSBDeviceRegistry.java | 2 +- .../gen/iokit/IOUSBDeviceInterface100.java | 16 - .../gen/iokit/IOUSBDeviceInterface182.java | 16 + ...ruct100.java => IOUSBDeviceStruct182.java} | 972 +++++++++++++----- .../codecrete/usb/sample/USBSerialTest.java | 8 +- 9 files changed, 783 insertions(+), 279 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface100.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface182.java rename java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/{IOUSBDeviceStruct100.java => IOUSBDeviceStruct182.java} (65%) diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index 88f04821..78c29098 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -51,8 +51,8 @@ $JEXTRACT --source --output ../../src/main/java \ --include-function IORegistryEntryGetRegistryEntryID \ --include-function IOServiceAddMatchingNotification \ --include-function IOServiceMatching \ - --include-struct IOUSBDeviceStruct100 \ - --include-typedef IOUSBDeviceInterface100 \ + --include-struct IOUSBDeviceStruct182 \ + --include-typedef IOUSBDeviceInterface182 \ --include-constant kIOUSBFindInterfaceDontCare \ --include-typedef IOUSBFindInterfaceRequest \ --include-typedef IOUSBDevRequest \ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index 0f80c9ff..7c063c93 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -28,12 +28,12 @@ public class IoKitHelper { public static final MemorySegment kIOUSBInterfaceUserClientTypeID = UUID.CreateCFUUID(new byte[]{(byte) 0x2d, (byte) 0x97, (byte) 0x86, (byte) 0xc6, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, (byte) 0xad, (byte) 0x51, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61}); - public static final MemorySegment kIOUSBDeviceInterfaceID100 = UUID.CreateCFUUID(new byte[]{(byte) 0x5c, - (byte) 0x81, (byte) 0x87, (byte) 0xd0, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, (byte) 0x8b, - (byte) 0x45, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61}); - public static final MemorySegment kIOUSBInterfaceInterfaceID100 = UUID.CreateCFUUID(new byte[]{(byte) 0x73, - (byte) 0xc9, (byte) 0x7a, (byte) 0xe8, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, (byte) 0xb1, - (byte) 0xd0, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61}); + public static final MemorySegment kIOUSBDeviceInterfaceID182 = UUID.CreateCFUUID(new byte[]{(byte) 0x15, + (byte) 0x2f, (byte) 0xc4, (byte) 0x96, (byte) 0x48, (byte) 0x91, (byte) 0x11, (byte) 0xD5, (byte) 0x9d, + (byte) 0x52, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x80, (byte) 0x1e, (byte) 0x86}); + public static final MemorySegment kIOUSBInterfaceInterfaceID190 = UUID.CreateCFUUID(new byte[]{(byte) 0x8f, + (byte) 0xdb, (byte) 0x84, (byte) 0x55, (byte) 0x74, (byte) 0xa6, (byte) 0x11, (byte) 0xD6, (byte) 0x97, + (byte) 0xb1, (byte) 0x00, (byte) 0x30, (byte) 0x65, (byte) 0xd3, (byte) 0x60, (byte) 0x8e}); public static final MemorySegment kIOCFPlugInInterfaceID = UUID.CreateCFUUID(new byte[]{(byte) 0xC2, (byte) 0x44, (byte) 0xE8, (byte) 0x58, (byte) 0x10, (byte) 0x9C, (byte) 0x11, (byte) 0xD4, (byte) 0x91, (byte) 0xD4, (byte) 0x00, (byte) 0x50, (byte) 0xE4, (byte) 0xC6, (byte) 0x42, (byte) 0x6F}); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index f9ade06d..55d34700 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -8,7 +8,7 @@ package net.codecrete.usb.macos; import net.codecrete.usb.common.ForeignMemory; -import net.codecrete.usb.macos.gen.iokit.IOUSBDeviceInterface100; +import net.codecrete.usb.macos.gen.iokit.IOUSBDeviceInterface182; import net.codecrete.usb.macos.gen.iokit.IOUSBInterfaceInterface190; import java.lang.foreign.MemorySegment; @@ -29,60 +29,60 @@ private static MemorySegment getVtable(MemorySegment self) { // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); public static int QueryInterface(MemorySegment self, MemorySegment iid, MemorySegment ppv) { - return IOUSBDeviceInterface100.QueryInterface(getVtable(self), SegmentScope.global()).apply(self, iid, ppv); + return IOUSBDeviceInterface182.QueryInterface(getVtable(self), SegmentScope.global()).apply(self, iid, ppv); } // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); public static int AddRef(MemorySegment self) { - return IOUSBDeviceInterface100.AddRef(getVtable(self), SegmentScope.global()).apply(self); + return IOUSBDeviceInterface182.AddRef(getVtable(self), SegmentScope.global()).apply(self); } // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer) public static int Release(MemorySegment self) { - return IOUSBDeviceInterface100.Release(getVtable(self), SegmentScope.global()).apply(self); + return IOUSBDeviceInterface182.Release(getVtable(self), SegmentScope.global()).apply(self); } // IOReturn (* CreateDeviceAsyncEventSource)(void* self, CFRunLoopSourceRef* source); public static int CreateDeviceAsyncEventSource(MemorySegment self, MemorySegment source) { - return IOUSBDeviceInterface100.CreateDeviceAsyncEventSource(getVtable(self), SegmentScope.global()).apply(self, source); + return IOUSBDeviceInterface182.CreateDeviceAsyncEventSource(getVtable(self), SegmentScope.global()).apply(self, source); } // CFRunLoopSourceRef (* GetDeviceAsyncEventSource)(void* self); public static MemorySegment GetDeviceAsyncEventSource(MemorySegment self) { - return IOUSBDeviceInterface100.GetDeviceAsyncEventSource(getVtable(self), SegmentScope.global()).apply(self); + return IOUSBDeviceInterface182.GetDeviceAsyncEventSource(getVtable(self), SegmentScope.global()).apply(self); } - // IOReturn (*USBDeviceOpen)(void *self); - public static int USBDeviceOpen(MemorySegment self) { - return IOUSBDeviceInterface100.USBDeviceOpen(getVtable(self), SegmentScope.global()).apply(self); + // IOReturn (*USBDeviceOpenSeize)(void *self); + public static int USBDeviceOpenSeize(MemorySegment self) { + return IOUSBDeviceInterface182.USBDeviceOpenSeize(getVtable(self), SegmentScope.global()).apply(self); } // IOReturn (*USBDeviceClose)(void *self); public static int USBDeviceClose(MemorySegment self) { - return IOUSBDeviceInterface100.USBDeviceClose(getVtable(self), SegmentScope.global()).apply(self); + return IOUSBDeviceInterface182.USBDeviceClose(getVtable(self), SegmentScope.global()).apply(self); } // IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc); public static int GetConfigurationDescriptorPtr(MemorySegment self, byte configIndex, MemorySegment descHolder) { - return IOUSBDeviceInterface100.GetConfigurationDescriptorPtr(getVtable(self), SegmentScope.global()).apply(self, configIndex, descHolder); + return IOUSBDeviceInterface182.GetConfigurationDescriptorPtr(getVtable(self), SegmentScope.global()).apply(self, configIndex, descHolder); } // IOReturn (*SetConfiguration)(void *self, UInt8 configNum); public static int SetConfiguration(MemorySegment self, byte configValue) { - return IOUSBDeviceInterface100.SetConfiguration(getVtable(self), SegmentScope.global()).apply(self, + return IOUSBDeviceInterface182.SetConfiguration(getVtable(self), SegmentScope.global()).apply(self, configValue); } // IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter); public static int CreateInterfaceIterator(MemorySegment self, MemorySegment req, MemorySegment iter) { - return IOUSBDeviceInterface100.CreateInterfaceIterator(getVtable(self), SegmentScope.global()).apply(self, + return IOUSBDeviceInterface182.CreateInterfaceIterator(getVtable(self), SegmentScope.global()).apply(self, req, iter); } // IOReturn (* DeviceRequestAsync)(void* self, IOUSBDevRequest* req, IOAsyncCallback1 callback, void* refCon); public static int DeviceRequestAsync(MemorySegment self, MemorySegment deviceRequest, MemorySegment callback, MemorySegment refCon) { - return IOUSBDeviceInterface100.DeviceRequestAsync(getVtable(self), SegmentScope.global()).apply(self, + return IOUSBDeviceInterface182.DeviceRequestAsync(getVtable(self), SegmentScope.global()).apply(self, deviceRequest, callback, refCon); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 4061238b..152e0596 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -76,7 +76,7 @@ public synchronized void open() { throwException("the device is already open"); // open device - int ret = IoKitUSB.USBDeviceOpen(device); + int ret = IoKitUSB.USBDeviceOpenSeize(device); if (ret != 0) throwException(ret, "unable to open USB device"); @@ -166,7 +166,7 @@ private InterfaceInfo findInterface(int interfaceNumber) { cleanup.add(() -> IOKit.IOObjectRelease(service_final)); final var intf = IoKitHelper.getInterface(service, IoKitHelper.kIOUSBInterfaceUserClientTypeID, - IoKitHelper.kIOUSBInterfaceInterfaceID100); + IoKitHelper.kIOUSBInterfaceInterfaceID190); if (intf == null) continue; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 98293d0c..c31d8bba 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -118,7 +118,7 @@ private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { cleanup.add(() -> IOKit.IOObjectRelease(service)); var device = IoKitHelper.getInterface(service, IoKitHelper.kIOUSBDeviceUserClientTypeID, - IoKitHelper.kIOUSBDeviceInterfaceID100); + IoKitHelper.kIOUSBDeviceInterfaceID182); if (device != null) cleanup.add(() -> IoKitUSB.Release(device)); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface100.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface100.java deleted file mode 100644 index c1618c86..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface100.java +++ /dev/null @@ -1,16 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -/** - * {@snippet : - * typedef struct IOUSBDeviceStruct100 IOUSBDeviceInterface100; - * } - */ -public final class IOUSBDeviceInterface100 extends IOUSBDeviceStruct100 { - - // Suppresses default constructor, ensuring non-instantiability. - private IOUSBDeviceInterface100() {} -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface182.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface182.java new file mode 100644 index 00000000..7a978984 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface182.java @@ -0,0 +1,16 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +/** + * {@snippet : + * typedef struct IOUSBDeviceStruct182 IOUSBDeviceInterface182; + * } + */ +public final class IOUSBDeviceInterface182 extends IOUSBDeviceStruct182 { + + // Suppresses default constructor, ensuring non-instantiability. + private IOUSBDeviceInterface182() {} +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct100.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct182.java similarity index 65% rename from java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct100.java rename to java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct182.java index d3a40366..322d17c1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct100.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct182.java @@ -7,7 +7,7 @@ import java.lang.invoke.VarHandle; /** * {@snippet : - * struct IOUSBDeviceStruct100 { + * struct IOUSBDeviceStruct182 { * void* _reserved; * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); * ULONG (*AddRef)(void*); @@ -37,10 +37,18 @@ * IOReturn (*DeviceRequest)(void*,IOUSBDevRequest*); * IOReturn (*DeviceRequestAsync)(void*,IOUSBDevRequest*,IOAsyncCallback1,void*); * IOReturn (*CreateInterfaceIterator)(void*,IOUSBFindInterfaceRequest*,io_iterator_t*); + * IOReturn (*USBDeviceOpenSeize)(void*); + * IOReturn (*DeviceRequestTO)(void*,IOUSBDevRequestTO*); + * IOReturn (*DeviceRequestAsyncTO)(void*,IOUSBDevRequestTO*,IOAsyncCallback1,void*); + * IOReturn (*USBDeviceSuspend)(void*,Boolean); + * IOReturn (*USBDeviceAbortPipeZero)(void*); + * IOReturn (*USBGetManufacturerStringIndex)(void*,UInt8*); + * IOReturn (*USBGetProductStringIndex)(void*,UInt8*); + * IOReturn (*USBGetSerialNumberStringIndex)(void*,UInt8*); * }; * } */ -public class IOUSBDeviceStruct100 { +public class IOUSBDeviceStruct182 { static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_POINTER$LAYOUT.withName("_reserved"), @@ -71,14 +79,22 @@ public class IOUSBDeviceStruct100 { Constants$root.C_POINTER$LAYOUT.withName("ResetDevice"), Constants$root.C_POINTER$LAYOUT.withName("DeviceRequest"), Constants$root.C_POINTER$LAYOUT.withName("DeviceRequestAsync"), - Constants$root.C_POINTER$LAYOUT.withName("CreateInterfaceIterator") - ).withName("IOUSBDeviceStruct100"); + Constants$root.C_POINTER$LAYOUT.withName("CreateInterfaceIterator"), + Constants$root.C_POINTER$LAYOUT.withName("USBDeviceOpenSeize"), + Constants$root.C_POINTER$LAYOUT.withName("DeviceRequestTO"), + Constants$root.C_POINTER$LAYOUT.withName("DeviceRequestAsyncTO"), + Constants$root.C_POINTER$LAYOUT.withName("USBDeviceSuspend"), + Constants$root.C_POINTER$LAYOUT.withName("USBDeviceAbortPipeZero"), + Constants$root.C_POINTER$LAYOUT.withName("USBGetManufacturerStringIndex"), + Constants$root.C_POINTER$LAYOUT.withName("USBGetProductStringIndex"), + Constants$root.C_POINTER$LAYOUT.withName("USBGetSerialNumberStringIndex") + ).withName("IOUSBDeviceStruct182"); public static MemoryLayout $LAYOUT() { - return IOUSBDeviceStruct100.$struct$LAYOUT; + return IOUSBDeviceStruct182.$struct$LAYOUT; } static final VarHandle _reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("_reserved")); public static VarHandle _reserved$VH() { - return IOUSBDeviceStruct100._reserved$VH; + return IOUSBDeviceStruct182._reserved$VH; } /** * Getter for field: @@ -87,7 +103,7 @@ public class IOUSBDeviceStruct100 { * } */ public static MemorySegment _reserved$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100._reserved$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182._reserved$VH.get(seg); } /** * Setter for field: @@ -96,13 +112,13 @@ public class IOUSBDeviceStruct100 { * } */ public static void _reserved$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100._reserved$VH.set(seg, x); + IOUSBDeviceStruct182._reserved$VH.set(seg, x); } public static MemorySegment _reserved$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100._reserved$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182._reserved$VH.get(seg.asSlice(index*sizeof())); } public static void _reserved$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100._reserved$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182._reserved$VH.set(seg.asSlice(index*sizeof()), x); } static final FunctionDescriptor QueryInterface$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -127,7 +143,7 @@ public class IOUSBDeviceStruct100 { Constants$root.C_POINTER$LAYOUT ); static final MethodHandle QueryInterface$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.QueryInterface$FUNC + IOUSBDeviceStruct182.QueryInterface$FUNC ); /** * {@snippet : @@ -138,13 +154,13 @@ public interface QueryInterface { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); static MemorySegment allocate(QueryInterface fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOUSBDeviceStruct100.QueryInterface$FUNC, scope); + return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOUSBDeviceStruct182.QueryInterface$FUNC, scope); } static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBDeviceStruct100.QueryInterface$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)IOUSBDeviceStruct182.QueryInterface$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -154,7 +170,7 @@ static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle QueryInterface$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("QueryInterface")); public static VarHandle QueryInterface$VH() { - return IOUSBDeviceStruct100.QueryInterface$VH; + return IOUSBDeviceStruct182.QueryInterface$VH; } /** * Getter for field: @@ -163,7 +179,7 @@ static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment QueryInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.QueryInterface$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.QueryInterface$VH.get(seg); } /** * Setter for field: @@ -172,13 +188,13 @@ static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void QueryInterface$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.QueryInterface$VH.set(seg, x); + IOUSBDeviceStruct182.QueryInterface$VH.set(seg, x); } public static MemorySegment QueryInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.QueryInterface$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.QueryInterface$VH.get(seg.asSlice(index*sizeof())); } public static void QueryInterface$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.QueryInterface$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.QueryInterface$VH.set(seg.asSlice(index*sizeof()), x); } public static QueryInterface QueryInterface(MemorySegment segment, SegmentScope scope) { return QueryInterface.ofAddress(QueryInterface$get(segment), scope); @@ -187,7 +203,7 @@ public static QueryInterface QueryInterface(MemorySegment segment, SegmentScope Constants$root.C_POINTER$LAYOUT ); static final MethodHandle AddRef$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.AddRef$FUNC + IOUSBDeviceStruct182.AddRef$FUNC ); /** * {@snippet : @@ -198,13 +214,13 @@ public interface AddRef { int apply(java.lang.foreign.MemorySegment _x0); static MemorySegment allocate(AddRef fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(AddRef.class, fi, IOUSBDeviceStruct100.AddRef$FUNC, scope); + return RuntimeHelper.upcallStub(AddRef.class, fi, IOUSBDeviceStruct182.AddRef$FUNC, scope); } static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct100.AddRef$MH.invokeExact(symbol, __x0); + return (int)IOUSBDeviceStruct182.AddRef$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -214,7 +230,7 @@ static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle AddRef$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AddRef")); public static VarHandle AddRef$VH() { - return IOUSBDeviceStruct100.AddRef$VH; + return IOUSBDeviceStruct182.AddRef$VH; } /** * Getter for field: @@ -223,7 +239,7 @@ static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment AddRef$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.AddRef$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.AddRef$VH.get(seg); } /** * Setter for field: @@ -232,13 +248,13 @@ static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void AddRef$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.AddRef$VH.set(seg, x); + IOUSBDeviceStruct182.AddRef$VH.set(seg, x); } public static MemorySegment AddRef$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.AddRef$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.AddRef$VH.get(seg.asSlice(index*sizeof())); } public static void AddRef$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.AddRef$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.AddRef$VH.set(seg.asSlice(index*sizeof()), x); } public static AddRef AddRef(MemorySegment segment, SegmentScope scope) { return AddRef.ofAddress(AddRef$get(segment), scope); @@ -247,7 +263,7 @@ public static AddRef AddRef(MemorySegment segment, SegmentScope scope) { Constants$root.C_POINTER$LAYOUT ); static final MethodHandle Release$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.Release$FUNC + IOUSBDeviceStruct182.Release$FUNC ); /** * {@snippet : @@ -258,13 +274,13 @@ public interface Release { int apply(java.lang.foreign.MemorySegment _x0); static MemorySegment allocate(Release fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(Release.class, fi, IOUSBDeviceStruct100.Release$FUNC, scope); + return RuntimeHelper.upcallStub(Release.class, fi, IOUSBDeviceStruct182.Release$FUNC, scope); } static Release ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct100.Release$MH.invokeExact(symbol, __x0); + return (int)IOUSBDeviceStruct182.Release$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -274,7 +290,7 @@ static Release ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle Release$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Release")); public static VarHandle Release$VH() { - return IOUSBDeviceStruct100.Release$VH; + return IOUSBDeviceStruct182.Release$VH; } /** * Getter for field: @@ -283,7 +299,7 @@ static Release ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment Release$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.Release$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.Release$VH.get(seg); } /** * Setter for field: @@ -292,13 +308,13 @@ static Release ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void Release$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.Release$VH.set(seg, x); + IOUSBDeviceStruct182.Release$VH.set(seg, x); } public static MemorySegment Release$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.Release$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.Release$VH.get(seg.asSlice(index*sizeof())); } public static void Release$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.Release$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.Release$VH.set(seg.asSlice(index*sizeof()), x); } public static Release Release(MemorySegment segment, SegmentScope scope) { return Release.ofAddress(Release$get(segment), scope); @@ -308,7 +324,7 @@ public static Release Release(MemorySegment segment, SegmentScope scope) { Constants$root.C_POINTER$LAYOUT ); static final MethodHandle CreateDeviceAsyncEventSource$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$FUNC + IOUSBDeviceStruct182.CreateDeviceAsyncEventSource$FUNC ); /** * {@snippet : @@ -319,13 +335,13 @@ public interface CreateDeviceAsyncEventSource { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(CreateDeviceAsyncEventSource fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(CreateDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$FUNC, scope); + return RuntimeHelper.upcallStub(CreateDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct182.CreateDeviceAsyncEventSource$FUNC, scope); } static CreateDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct182.CreateDeviceAsyncEventSource$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -335,7 +351,7 @@ static CreateDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope s static final VarHandle CreateDeviceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateDeviceAsyncEventSource")); public static VarHandle CreateDeviceAsyncEventSource$VH() { - return IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$VH; + return IOUSBDeviceStruct182.CreateDeviceAsyncEventSource$VH; } /** * Getter for field: @@ -344,7 +360,7 @@ static CreateDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope s * } */ public static MemorySegment CreateDeviceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.CreateDeviceAsyncEventSource$VH.get(seg); } /** * Setter for field: @@ -353,13 +369,13 @@ static CreateDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope s * } */ public static void CreateDeviceAsyncEventSource$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$VH.set(seg, x); + IOUSBDeviceStruct182.CreateDeviceAsyncEventSource$VH.set(seg, x); } public static MemorySegment CreateDeviceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.CreateDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); } public static void CreateDeviceAsyncEventSource$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.CreateDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.CreateDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); } public static CreateDeviceAsyncEventSource CreateDeviceAsyncEventSource(MemorySegment segment, SegmentScope scope) { return CreateDeviceAsyncEventSource.ofAddress(CreateDeviceAsyncEventSource$get(segment), scope); @@ -368,7 +384,7 @@ public static CreateDeviceAsyncEventSource CreateDeviceAsyncEventSource(MemorySe Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceAsyncEventSource$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.GetDeviceAsyncEventSource$FUNC + IOUSBDeviceStruct182.GetDeviceAsyncEventSource$FUNC ); /** * {@snippet : @@ -379,13 +395,13 @@ public interface GetDeviceAsyncEventSource { java.lang.foreign.MemorySegment apply(java.lang.foreign.MemorySegment _x0); static MemorySegment allocate(GetDeviceAsyncEventSource fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct100.GetDeviceAsyncEventSource$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct182.GetDeviceAsyncEventSource$FUNC, scope); } static GetDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceAsyncEventSource$MH.invokeExact(symbol, __x0); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceAsyncEventSource$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -395,7 +411,7 @@ static GetDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scop static final VarHandle GetDeviceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncEventSource")); public static VarHandle GetDeviceAsyncEventSource$VH() { - return IOUSBDeviceStruct100.GetDeviceAsyncEventSource$VH; + return IOUSBDeviceStruct182.GetDeviceAsyncEventSource$VH; } /** * Getter for field: @@ -404,7 +420,7 @@ static GetDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scop * } */ public static MemorySegment GetDeviceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceAsyncEventSource$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceAsyncEventSource$VH.get(seg); } /** * Setter for field: @@ -413,13 +429,13 @@ static GetDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scop * } */ public static void GetDeviceAsyncEventSource$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceAsyncEventSource$VH.set(seg, x); + IOUSBDeviceStruct182.GetDeviceAsyncEventSource$VH.set(seg, x); } public static MemorySegment GetDeviceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceAsyncEventSource$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.GetDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceAsyncEventSource GetDeviceAsyncEventSource(MemorySegment segment, SegmentScope scope) { return GetDeviceAsyncEventSource.ofAddress(GetDeviceAsyncEventSource$get(segment), scope); @@ -429,7 +445,7 @@ public static GetDeviceAsyncEventSource GetDeviceAsyncEventSource(MemorySegment Constants$root.C_POINTER$LAYOUT ); static final MethodHandle CreateDeviceAsyncPort$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.CreateDeviceAsyncPort$FUNC + IOUSBDeviceStruct182.CreateDeviceAsyncPort$FUNC ); /** * {@snippet : @@ -440,13 +456,13 @@ public interface CreateDeviceAsyncPort { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(CreateDeviceAsyncPort fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(CreateDeviceAsyncPort.class, fi, IOUSBDeviceStruct100.CreateDeviceAsyncPort$FUNC, scope); + return RuntimeHelper.upcallStub(CreateDeviceAsyncPort.class, fi, IOUSBDeviceStruct182.CreateDeviceAsyncPort$FUNC, scope); } static CreateDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.CreateDeviceAsyncPort$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct182.CreateDeviceAsyncPort$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -456,7 +472,7 @@ static CreateDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle CreateDeviceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateDeviceAsyncPort")); public static VarHandle CreateDeviceAsyncPort$VH() { - return IOUSBDeviceStruct100.CreateDeviceAsyncPort$VH; + return IOUSBDeviceStruct182.CreateDeviceAsyncPort$VH; } /** * Getter for field: @@ -465,7 +481,7 @@ static CreateDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment CreateDeviceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.CreateDeviceAsyncPort$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.CreateDeviceAsyncPort$VH.get(seg); } /** * Setter for field: @@ -474,13 +490,13 @@ static CreateDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void CreateDeviceAsyncPort$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.CreateDeviceAsyncPort$VH.set(seg, x); + IOUSBDeviceStruct182.CreateDeviceAsyncPort$VH.set(seg, x); } public static MemorySegment CreateDeviceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.CreateDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.CreateDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); } public static void CreateDeviceAsyncPort$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.CreateDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.CreateDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); } public static CreateDeviceAsyncPort CreateDeviceAsyncPort(MemorySegment segment, SegmentScope scope) { return CreateDeviceAsyncPort.ofAddress(CreateDeviceAsyncPort$get(segment), scope); @@ -489,7 +505,7 @@ public static CreateDeviceAsyncPort CreateDeviceAsyncPort(MemorySegment segment, Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceAsyncPort$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.GetDeviceAsyncPort$FUNC + IOUSBDeviceStruct182.GetDeviceAsyncPort$FUNC ); /** * {@snippet : @@ -500,13 +516,13 @@ public interface GetDeviceAsyncPort { int apply(java.lang.foreign.MemorySegment _x0); static MemorySegment allocate(GetDeviceAsyncPort fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceAsyncPort.class, fi, IOUSBDeviceStruct100.GetDeviceAsyncPort$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceAsyncPort.class, fi, IOUSBDeviceStruct182.GetDeviceAsyncPort$FUNC, scope); } static GetDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceAsyncPort$MH.invokeExact(symbol, __x0); + return (int)IOUSBDeviceStruct182.GetDeviceAsyncPort$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -516,7 +532,7 @@ static GetDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetDeviceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncPort")); public static VarHandle GetDeviceAsyncPort$VH() { - return IOUSBDeviceStruct100.GetDeviceAsyncPort$VH; + return IOUSBDeviceStruct182.GetDeviceAsyncPort$VH; } /** * Getter for field: @@ -525,7 +541,7 @@ static GetDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceAsyncPort$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceAsyncPort$VH.get(seg); } /** * Setter for field: @@ -534,13 +550,13 @@ static GetDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceAsyncPort$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceAsyncPort$VH.set(seg, x); + IOUSBDeviceStruct182.GetDeviceAsyncPort$VH.set(seg, x); } public static MemorySegment GetDeviceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceAsyncPort$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.GetDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceAsyncPort GetDeviceAsyncPort(MemorySegment segment, SegmentScope scope) { return GetDeviceAsyncPort.ofAddress(GetDeviceAsyncPort$get(segment), scope); @@ -549,7 +565,7 @@ public static GetDeviceAsyncPort GetDeviceAsyncPort(MemorySegment segment, Segme Constants$root.C_POINTER$LAYOUT ); static final MethodHandle USBDeviceOpen$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.USBDeviceOpen$FUNC + IOUSBDeviceStruct182.USBDeviceOpen$FUNC ); /** * {@snippet : @@ -560,13 +576,13 @@ public interface USBDeviceOpen { int apply(java.lang.foreign.MemorySegment _x0); static MemorySegment allocate(USBDeviceOpen fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBDeviceOpen.class, fi, IOUSBDeviceStruct100.USBDeviceOpen$FUNC, scope); + return RuntimeHelper.upcallStub(USBDeviceOpen.class, fi, IOUSBDeviceStruct182.USBDeviceOpen$FUNC, scope); } static USBDeviceOpen ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct100.USBDeviceOpen$MH.invokeExact(symbol, __x0); + return (int)IOUSBDeviceStruct182.USBDeviceOpen$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -576,7 +592,7 @@ static USBDeviceOpen ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle USBDeviceOpen$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceOpen")); public static VarHandle USBDeviceOpen$VH() { - return IOUSBDeviceStruct100.USBDeviceOpen$VH; + return IOUSBDeviceStruct182.USBDeviceOpen$VH; } /** * Getter for field: @@ -585,7 +601,7 @@ static USBDeviceOpen ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment USBDeviceOpen$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.USBDeviceOpen$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceOpen$VH.get(seg); } /** * Setter for field: @@ -594,13 +610,13 @@ static USBDeviceOpen ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void USBDeviceOpen$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.USBDeviceOpen$VH.set(seg, x); + IOUSBDeviceStruct182.USBDeviceOpen$VH.set(seg, x); } public static MemorySegment USBDeviceOpen$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.USBDeviceOpen$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceOpen$VH.get(seg.asSlice(index*sizeof())); } public static void USBDeviceOpen$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.USBDeviceOpen$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.USBDeviceOpen$VH.set(seg.asSlice(index*sizeof()), x); } public static USBDeviceOpen USBDeviceOpen(MemorySegment segment, SegmentScope scope) { return USBDeviceOpen.ofAddress(USBDeviceOpen$get(segment), scope); @@ -609,7 +625,7 @@ public static USBDeviceOpen USBDeviceOpen(MemorySegment segment, SegmentScope sc Constants$root.C_POINTER$LAYOUT ); static final MethodHandle USBDeviceClose$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.USBDeviceClose$FUNC + IOUSBDeviceStruct182.USBDeviceClose$FUNC ); /** * {@snippet : @@ -620,13 +636,13 @@ public interface USBDeviceClose { int apply(java.lang.foreign.MemorySegment _x0); static MemorySegment allocate(USBDeviceClose fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBDeviceClose.class, fi, IOUSBDeviceStruct100.USBDeviceClose$FUNC, scope); + return RuntimeHelper.upcallStub(USBDeviceClose.class, fi, IOUSBDeviceStruct182.USBDeviceClose$FUNC, scope); } static USBDeviceClose ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct100.USBDeviceClose$MH.invokeExact(symbol, __x0); + return (int)IOUSBDeviceStruct182.USBDeviceClose$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -636,7 +652,7 @@ static USBDeviceClose ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle USBDeviceClose$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceClose")); public static VarHandle USBDeviceClose$VH() { - return IOUSBDeviceStruct100.USBDeviceClose$VH; + return IOUSBDeviceStruct182.USBDeviceClose$VH; } /** * Getter for field: @@ -645,7 +661,7 @@ static USBDeviceClose ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment USBDeviceClose$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.USBDeviceClose$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceClose$VH.get(seg); } /** * Setter for field: @@ -654,13 +670,13 @@ static USBDeviceClose ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void USBDeviceClose$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.USBDeviceClose$VH.set(seg, x); + IOUSBDeviceStruct182.USBDeviceClose$VH.set(seg, x); } public static MemorySegment USBDeviceClose$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.USBDeviceClose$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceClose$VH.get(seg.asSlice(index*sizeof())); } public static void USBDeviceClose$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.USBDeviceClose$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.USBDeviceClose$VH.set(seg.asSlice(index*sizeof()), x); } public static USBDeviceClose USBDeviceClose(MemorySegment segment, SegmentScope scope) { return USBDeviceClose.ofAddress(USBDeviceClose$get(segment), scope); @@ -670,7 +686,7 @@ public static USBDeviceClose USBDeviceClose(MemorySegment segment, SegmentScope Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceClass$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.GetDeviceClass$FUNC + IOUSBDeviceStruct182.GetDeviceClass$FUNC ); /** * {@snippet : @@ -681,13 +697,13 @@ public interface GetDeviceClass { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceClass fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceClass.class, fi, IOUSBDeviceStruct100.GetDeviceClass$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceClass.class, fi, IOUSBDeviceStruct182.GetDeviceClass$FUNC, scope); } static GetDeviceClass ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceClass$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct182.GetDeviceClass$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -697,7 +713,7 @@ static GetDeviceClass ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetDeviceClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceClass")); public static VarHandle GetDeviceClass$VH() { - return IOUSBDeviceStruct100.GetDeviceClass$VH; + return IOUSBDeviceStruct182.GetDeviceClass$VH; } /** * Getter for field: @@ -706,7 +722,7 @@ static GetDeviceClass ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceClass$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceClass$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceClass$VH.get(seg); } /** * Setter for field: @@ -715,13 +731,13 @@ static GetDeviceClass ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceClass$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceClass$VH.set(seg, x); + IOUSBDeviceStruct182.GetDeviceClass$VH.set(seg, x); } public static MemorySegment GetDeviceClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceClass$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceClass$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceClass$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceClass$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.GetDeviceClass$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceClass GetDeviceClass(MemorySegment segment, SegmentScope scope) { return GetDeviceClass.ofAddress(GetDeviceClass$get(segment), scope); @@ -731,7 +747,7 @@ public static GetDeviceClass GetDeviceClass(MemorySegment segment, SegmentScope Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceSubClass$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.GetDeviceSubClass$FUNC + IOUSBDeviceStruct182.GetDeviceSubClass$FUNC ); /** * {@snippet : @@ -742,13 +758,13 @@ public interface GetDeviceSubClass { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceSubClass fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceSubClass.class, fi, IOUSBDeviceStruct100.GetDeviceSubClass$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceSubClass.class, fi, IOUSBDeviceStruct182.GetDeviceSubClass$FUNC, scope); } static GetDeviceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceSubClass$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct182.GetDeviceSubClass$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -758,7 +774,7 @@ static GetDeviceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetDeviceSubClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceSubClass")); public static VarHandle GetDeviceSubClass$VH() { - return IOUSBDeviceStruct100.GetDeviceSubClass$VH; + return IOUSBDeviceStruct182.GetDeviceSubClass$VH; } /** * Getter for field: @@ -767,7 +783,7 @@ static GetDeviceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceSubClass$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceSubClass$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceSubClass$VH.get(seg); } /** * Setter for field: @@ -776,13 +792,13 @@ static GetDeviceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceSubClass$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceSubClass$VH.set(seg, x); + IOUSBDeviceStruct182.GetDeviceSubClass$VH.set(seg, x); } public static MemorySegment GetDeviceSubClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceSubClass$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceSubClass$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceSubClass$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceSubClass$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.GetDeviceSubClass$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceSubClass GetDeviceSubClass(MemorySegment segment, SegmentScope scope) { return GetDeviceSubClass.ofAddress(GetDeviceSubClass$get(segment), scope); @@ -792,7 +808,7 @@ public static GetDeviceSubClass GetDeviceSubClass(MemorySegment segment, Segment Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceProtocol$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.GetDeviceProtocol$FUNC + IOUSBDeviceStruct182.GetDeviceProtocol$FUNC ); /** * {@snippet : @@ -803,13 +819,13 @@ public interface GetDeviceProtocol { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceProtocol fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceProtocol.class, fi, IOUSBDeviceStruct100.GetDeviceProtocol$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceProtocol.class, fi, IOUSBDeviceStruct182.GetDeviceProtocol$FUNC, scope); } static GetDeviceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceProtocol$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct182.GetDeviceProtocol$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -819,7 +835,7 @@ static GetDeviceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetDeviceProtocol$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProtocol")); public static VarHandle GetDeviceProtocol$VH() { - return IOUSBDeviceStruct100.GetDeviceProtocol$VH; + return IOUSBDeviceStruct182.GetDeviceProtocol$VH; } /** * Getter for field: @@ -828,7 +844,7 @@ static GetDeviceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceProtocol$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceProtocol$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceProtocol$VH.get(seg); } /** * Setter for field: @@ -837,13 +853,13 @@ static GetDeviceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceProtocol$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceProtocol$VH.set(seg, x); + IOUSBDeviceStruct182.GetDeviceProtocol$VH.set(seg, x); } public static MemorySegment GetDeviceProtocol$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceProtocol$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceProtocol$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceProtocol$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceProtocol$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.GetDeviceProtocol$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceProtocol GetDeviceProtocol(MemorySegment segment, SegmentScope scope) { return GetDeviceProtocol.ofAddress(GetDeviceProtocol$get(segment), scope); @@ -853,7 +869,7 @@ public static GetDeviceProtocol GetDeviceProtocol(MemorySegment segment, Segment Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceVendor$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.GetDeviceVendor$FUNC + IOUSBDeviceStruct182.GetDeviceVendor$FUNC ); /** * {@snippet : @@ -864,13 +880,13 @@ public interface GetDeviceVendor { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceVendor fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceVendor.class, fi, IOUSBDeviceStruct100.GetDeviceVendor$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceVendor.class, fi, IOUSBDeviceStruct182.GetDeviceVendor$FUNC, scope); } static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceVendor$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct182.GetDeviceVendor$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -880,7 +896,7 @@ static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetDeviceVendor$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceVendor")); public static VarHandle GetDeviceVendor$VH() { - return IOUSBDeviceStruct100.GetDeviceVendor$VH; + return IOUSBDeviceStruct182.GetDeviceVendor$VH; } /** * Getter for field: @@ -889,7 +905,7 @@ static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceVendor$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceVendor$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceVendor$VH.get(seg); } /** * Setter for field: @@ -898,13 +914,13 @@ static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceVendor$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceVendor$VH.set(seg, x); + IOUSBDeviceStruct182.GetDeviceVendor$VH.set(seg, x); } public static MemorySegment GetDeviceVendor$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceVendor$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceVendor$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceVendor$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceVendor$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.GetDeviceVendor$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceVendor GetDeviceVendor(MemorySegment segment, SegmentScope scope) { return GetDeviceVendor.ofAddress(GetDeviceVendor$get(segment), scope); @@ -914,7 +930,7 @@ public static GetDeviceVendor GetDeviceVendor(MemorySegment segment, SegmentScop Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceProduct$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.GetDeviceProduct$FUNC + IOUSBDeviceStruct182.GetDeviceProduct$FUNC ); /** * {@snippet : @@ -925,13 +941,13 @@ public interface GetDeviceProduct { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceProduct fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceProduct.class, fi, IOUSBDeviceStruct100.GetDeviceProduct$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceProduct.class, fi, IOUSBDeviceStruct182.GetDeviceProduct$FUNC, scope); } static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceProduct$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct182.GetDeviceProduct$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -941,7 +957,7 @@ static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetDeviceProduct$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProduct")); public static VarHandle GetDeviceProduct$VH() { - return IOUSBDeviceStruct100.GetDeviceProduct$VH; + return IOUSBDeviceStruct182.GetDeviceProduct$VH; } /** * Getter for field: @@ -950,7 +966,7 @@ static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceProduct$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceProduct$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceProduct$VH.get(seg); } /** * Setter for field: @@ -959,13 +975,13 @@ static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceProduct$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceProduct$VH.set(seg, x); + IOUSBDeviceStruct182.GetDeviceProduct$VH.set(seg, x); } public static MemorySegment GetDeviceProduct$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceProduct$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceProduct$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceProduct$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceProduct$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.GetDeviceProduct$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceProduct GetDeviceProduct(MemorySegment segment, SegmentScope scope) { return GetDeviceProduct.ofAddress(GetDeviceProduct$get(segment), scope); @@ -975,7 +991,7 @@ public static GetDeviceProduct GetDeviceProduct(MemorySegment segment, SegmentSc Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceReleaseNumber$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.GetDeviceReleaseNumber$FUNC + IOUSBDeviceStruct182.GetDeviceReleaseNumber$FUNC ); /** * {@snippet : @@ -986,13 +1002,13 @@ public interface GetDeviceReleaseNumber { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceReleaseNumber fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceReleaseNumber.class, fi, IOUSBDeviceStruct100.GetDeviceReleaseNumber$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceReleaseNumber.class, fi, IOUSBDeviceStruct182.GetDeviceReleaseNumber$FUNC, scope); } static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceReleaseNumber$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct182.GetDeviceReleaseNumber$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1002,7 +1018,7 @@ static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) static final VarHandle GetDeviceReleaseNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceReleaseNumber")); public static VarHandle GetDeviceReleaseNumber$VH() { - return IOUSBDeviceStruct100.GetDeviceReleaseNumber$VH; + return IOUSBDeviceStruct182.GetDeviceReleaseNumber$VH; } /** * Getter for field: @@ -1011,7 +1027,7 @@ static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static MemorySegment GetDeviceReleaseNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceReleaseNumber$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceReleaseNumber$VH.get(seg); } /** * Setter for field: @@ -1020,13 +1036,13 @@ static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static void GetDeviceReleaseNumber$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceReleaseNumber$VH.set(seg, x); + IOUSBDeviceStruct182.GetDeviceReleaseNumber$VH.set(seg, x); } public static MemorySegment GetDeviceReleaseNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceReleaseNumber$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceReleaseNumber$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceReleaseNumber$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceReleaseNumber$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.GetDeviceReleaseNumber$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceReleaseNumber GetDeviceReleaseNumber(MemorySegment segment, SegmentScope scope) { return GetDeviceReleaseNumber.ofAddress(GetDeviceReleaseNumber$get(segment), scope); @@ -1036,7 +1052,7 @@ public static GetDeviceReleaseNumber GetDeviceReleaseNumber(MemorySegment segmen Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceAddress$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.GetDeviceAddress$FUNC + IOUSBDeviceStruct182.GetDeviceAddress$FUNC ); /** * {@snippet : @@ -1047,13 +1063,13 @@ public interface GetDeviceAddress { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceAddress fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceAddress.class, fi, IOUSBDeviceStruct100.GetDeviceAddress$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceAddress.class, fi, IOUSBDeviceStruct182.GetDeviceAddress$FUNC, scope); } static GetDeviceAddress ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceAddress$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct182.GetDeviceAddress$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1063,7 +1079,7 @@ static GetDeviceAddress ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetDeviceAddress$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAddress")); public static VarHandle GetDeviceAddress$VH() { - return IOUSBDeviceStruct100.GetDeviceAddress$VH; + return IOUSBDeviceStruct182.GetDeviceAddress$VH; } /** * Getter for field: @@ -1072,7 +1088,7 @@ static GetDeviceAddress ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceAddress$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceAddress$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceAddress$VH.get(seg); } /** * Setter for field: @@ -1081,13 +1097,13 @@ static GetDeviceAddress ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceAddress$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceAddress$VH.set(seg, x); + IOUSBDeviceStruct182.GetDeviceAddress$VH.set(seg, x); } public static MemorySegment GetDeviceAddress$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceAddress$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceAddress$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceAddress$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceAddress$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.GetDeviceAddress$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceAddress GetDeviceAddress(MemorySegment segment, SegmentScope scope) { return GetDeviceAddress.ofAddress(GetDeviceAddress$get(segment), scope); @@ -1097,7 +1113,7 @@ public static GetDeviceAddress GetDeviceAddress(MemorySegment segment, SegmentSc Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceBusPowerAvailable$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$FUNC + IOUSBDeviceStruct182.GetDeviceBusPowerAvailable$FUNC ); /** * {@snippet : @@ -1108,13 +1124,13 @@ public interface GetDeviceBusPowerAvailable { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceBusPowerAvailable fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceBusPowerAvailable.class, fi, IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceBusPowerAvailable.class, fi, IOUSBDeviceStruct182.GetDeviceBusPowerAvailable$FUNC, scope); } static GetDeviceBusPowerAvailable ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct182.GetDeviceBusPowerAvailable$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1124,7 +1140,7 @@ static GetDeviceBusPowerAvailable ofAddress(MemorySegment addr, SegmentScope sco static final VarHandle GetDeviceBusPowerAvailable$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceBusPowerAvailable")); public static VarHandle GetDeviceBusPowerAvailable$VH() { - return IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$VH; + return IOUSBDeviceStruct182.GetDeviceBusPowerAvailable$VH; } /** * Getter for field: @@ -1133,7 +1149,7 @@ static GetDeviceBusPowerAvailable ofAddress(MemorySegment addr, SegmentScope sco * } */ public static MemorySegment GetDeviceBusPowerAvailable$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceBusPowerAvailable$VH.get(seg); } /** * Setter for field: @@ -1142,13 +1158,13 @@ static GetDeviceBusPowerAvailable ofAddress(MemorySegment addr, SegmentScope sco * } */ public static void GetDeviceBusPowerAvailable$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$VH.set(seg, x); + IOUSBDeviceStruct182.GetDeviceBusPowerAvailable$VH.set(seg, x); } public static MemorySegment GetDeviceBusPowerAvailable$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceBusPowerAvailable$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceBusPowerAvailable$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceBusPowerAvailable$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.GetDeviceBusPowerAvailable$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceBusPowerAvailable GetDeviceBusPowerAvailable(MemorySegment segment, SegmentScope scope) { return GetDeviceBusPowerAvailable.ofAddress(GetDeviceBusPowerAvailable$get(segment), scope); @@ -1158,7 +1174,7 @@ public static GetDeviceBusPowerAvailable GetDeviceBusPowerAvailable(MemorySegmen Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceSpeed$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.GetDeviceSpeed$FUNC + IOUSBDeviceStruct182.GetDeviceSpeed$FUNC ); /** * {@snippet : @@ -1169,13 +1185,13 @@ public interface GetDeviceSpeed { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceSpeed fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceSpeed.class, fi, IOUSBDeviceStruct100.GetDeviceSpeed$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceSpeed.class, fi, IOUSBDeviceStruct182.GetDeviceSpeed$FUNC, scope); } static GetDeviceSpeed ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetDeviceSpeed$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct182.GetDeviceSpeed$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1185,7 +1201,7 @@ static GetDeviceSpeed ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetDeviceSpeed$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceSpeed")); public static VarHandle GetDeviceSpeed$VH() { - return IOUSBDeviceStruct100.GetDeviceSpeed$VH; + return IOUSBDeviceStruct182.GetDeviceSpeed$VH; } /** * Getter for field: @@ -1194,7 +1210,7 @@ static GetDeviceSpeed ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceSpeed$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceSpeed$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceSpeed$VH.get(seg); } /** * Setter for field: @@ -1203,13 +1219,13 @@ static GetDeviceSpeed ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceSpeed$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceSpeed$VH.set(seg, x); + IOUSBDeviceStruct182.GetDeviceSpeed$VH.set(seg, x); } public static MemorySegment GetDeviceSpeed$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetDeviceSpeed$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceSpeed$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceSpeed$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.GetDeviceSpeed$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.GetDeviceSpeed$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceSpeed GetDeviceSpeed(MemorySegment segment, SegmentScope scope) { return GetDeviceSpeed.ofAddress(GetDeviceSpeed$get(segment), scope); @@ -1219,7 +1235,7 @@ public static GetDeviceSpeed GetDeviceSpeed(MemorySegment segment, SegmentScope Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetNumberOfConfigurations$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.GetNumberOfConfigurations$FUNC + IOUSBDeviceStruct182.GetNumberOfConfigurations$FUNC ); /** * {@snippet : @@ -1230,13 +1246,13 @@ public interface GetNumberOfConfigurations { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetNumberOfConfigurations fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetNumberOfConfigurations.class, fi, IOUSBDeviceStruct100.GetNumberOfConfigurations$FUNC, scope); + return RuntimeHelper.upcallStub(GetNumberOfConfigurations.class, fi, IOUSBDeviceStruct182.GetNumberOfConfigurations$FUNC, scope); } static GetNumberOfConfigurations ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetNumberOfConfigurations$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct182.GetNumberOfConfigurations$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1246,7 +1262,7 @@ static GetNumberOfConfigurations ofAddress(MemorySegment addr, SegmentScope scop static final VarHandle GetNumberOfConfigurations$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetNumberOfConfigurations")); public static VarHandle GetNumberOfConfigurations$VH() { - return IOUSBDeviceStruct100.GetNumberOfConfigurations$VH; + return IOUSBDeviceStruct182.GetNumberOfConfigurations$VH; } /** * Getter for field: @@ -1255,7 +1271,7 @@ static GetNumberOfConfigurations ofAddress(MemorySegment addr, SegmentScope scop * } */ public static MemorySegment GetNumberOfConfigurations$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetNumberOfConfigurations$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetNumberOfConfigurations$VH.get(seg); } /** * Setter for field: @@ -1264,13 +1280,13 @@ static GetNumberOfConfigurations ofAddress(MemorySegment addr, SegmentScope scop * } */ public static void GetNumberOfConfigurations$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.GetNumberOfConfigurations$VH.set(seg, x); + IOUSBDeviceStruct182.GetNumberOfConfigurations$VH.set(seg, x); } public static MemorySegment GetNumberOfConfigurations$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetNumberOfConfigurations$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetNumberOfConfigurations$VH.get(seg.asSlice(index*sizeof())); } public static void GetNumberOfConfigurations$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.GetNumberOfConfigurations$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.GetNumberOfConfigurations$VH.set(seg.asSlice(index*sizeof()), x); } public static GetNumberOfConfigurations GetNumberOfConfigurations(MemorySegment segment, SegmentScope scope) { return GetNumberOfConfigurations.ofAddress(GetNumberOfConfigurations$get(segment), scope); @@ -1280,7 +1296,7 @@ public static GetNumberOfConfigurations GetNumberOfConfigurations(MemorySegment Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetLocationID$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.GetLocationID$FUNC + IOUSBDeviceStruct182.GetLocationID$FUNC ); /** * {@snippet : @@ -1291,13 +1307,13 @@ public interface GetLocationID { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetLocationID fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetLocationID.class, fi, IOUSBDeviceStruct100.GetLocationID$FUNC, scope); + return RuntimeHelper.upcallStub(GetLocationID.class, fi, IOUSBDeviceStruct182.GetLocationID$FUNC, scope); } static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetLocationID$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct182.GetLocationID$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1307,7 +1323,7 @@ static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetLocationID$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetLocationID")); public static VarHandle GetLocationID$VH() { - return IOUSBDeviceStruct100.GetLocationID$VH; + return IOUSBDeviceStruct182.GetLocationID$VH; } /** * Getter for field: @@ -1316,7 +1332,7 @@ static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetLocationID$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetLocationID$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetLocationID$VH.get(seg); } /** * Setter for field: @@ -1325,13 +1341,13 @@ static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetLocationID$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.GetLocationID$VH.set(seg, x); + IOUSBDeviceStruct182.GetLocationID$VH.set(seg, x); } public static MemorySegment GetLocationID$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetLocationID$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetLocationID$VH.get(seg.asSlice(index*sizeof())); } public static void GetLocationID$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.GetLocationID$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.GetLocationID$VH.set(seg.asSlice(index*sizeof()), x); } public static GetLocationID GetLocationID(MemorySegment segment, SegmentScope scope) { return GetLocationID.ofAddress(GetLocationID$get(segment), scope); @@ -1342,7 +1358,7 @@ public static GetLocationID GetLocationID(MemorySegment segment, SegmentScope sc Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetConfigurationDescriptorPtr$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$FUNC + IOUSBDeviceStruct182.GetConfigurationDescriptorPtr$FUNC ); /** * {@snippet : @@ -1353,13 +1369,13 @@ public interface GetConfigurationDescriptorPtr { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2); static MemorySegment allocate(GetConfigurationDescriptorPtr fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetConfigurationDescriptorPtr.class, fi, IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$FUNC, scope); + return RuntimeHelper.upcallStub(GetConfigurationDescriptorPtr.class, fi, IOUSBDeviceStruct182.GetConfigurationDescriptorPtr$FUNC, scope); } static GetConfigurationDescriptorPtr ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)IOUSBDeviceStruct182.GetConfigurationDescriptorPtr$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1369,7 +1385,7 @@ static GetConfigurationDescriptorPtr ofAddress(MemorySegment addr, SegmentScope static final VarHandle GetConfigurationDescriptorPtr$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetConfigurationDescriptorPtr")); public static VarHandle GetConfigurationDescriptorPtr$VH() { - return IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$VH; + return IOUSBDeviceStruct182.GetConfigurationDescriptorPtr$VH; } /** * Getter for field: @@ -1378,7 +1394,7 @@ static GetConfigurationDescriptorPtr ofAddress(MemorySegment addr, SegmentScope * } */ public static MemorySegment GetConfigurationDescriptorPtr$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetConfigurationDescriptorPtr$VH.get(seg); } /** * Setter for field: @@ -1387,13 +1403,13 @@ static GetConfigurationDescriptorPtr ofAddress(MemorySegment addr, SegmentScope * } */ public static void GetConfigurationDescriptorPtr$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$VH.set(seg, x); + IOUSBDeviceStruct182.GetConfigurationDescriptorPtr$VH.set(seg, x); } public static MemorySegment GetConfigurationDescriptorPtr$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetConfigurationDescriptorPtr$VH.get(seg.asSlice(index*sizeof())); } public static void GetConfigurationDescriptorPtr$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.GetConfigurationDescriptorPtr$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.GetConfigurationDescriptorPtr$VH.set(seg.asSlice(index*sizeof()), x); } public static GetConfigurationDescriptorPtr GetConfigurationDescriptorPtr(MemorySegment segment, SegmentScope scope) { return GetConfigurationDescriptorPtr.ofAddress(GetConfigurationDescriptorPtr$get(segment), scope); @@ -1403,7 +1419,7 @@ public static GetConfigurationDescriptorPtr GetConfigurationDescriptorPtr(Memory Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetConfiguration$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.GetConfiguration$FUNC + IOUSBDeviceStruct182.GetConfiguration$FUNC ); /** * {@snippet : @@ -1414,13 +1430,13 @@ public interface GetConfiguration { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetConfiguration fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetConfiguration.class, fi, IOUSBDeviceStruct100.GetConfiguration$FUNC, scope); + return RuntimeHelper.upcallStub(GetConfiguration.class, fi, IOUSBDeviceStruct182.GetConfiguration$FUNC, scope); } static GetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.GetConfiguration$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct182.GetConfiguration$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1430,7 +1446,7 @@ static GetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetConfiguration$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetConfiguration")); public static VarHandle GetConfiguration$VH() { - return IOUSBDeviceStruct100.GetConfiguration$VH; + return IOUSBDeviceStruct182.GetConfiguration$VH; } /** * Getter for field: @@ -1439,7 +1455,7 @@ static GetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetConfiguration$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetConfiguration$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetConfiguration$VH.get(seg); } /** * Setter for field: @@ -1448,13 +1464,13 @@ static GetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetConfiguration$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.GetConfiguration$VH.set(seg, x); + IOUSBDeviceStruct182.GetConfiguration$VH.set(seg, x); } public static MemorySegment GetConfiguration$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetConfiguration$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetConfiguration$VH.get(seg.asSlice(index*sizeof())); } public static void GetConfiguration$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.GetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.GetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); } public static GetConfiguration GetConfiguration(MemorySegment segment, SegmentScope scope) { return GetConfiguration.ofAddress(GetConfiguration$get(segment), scope); @@ -1464,7 +1480,7 @@ public static GetConfiguration GetConfiguration(MemorySegment segment, SegmentSc Constants$root.C_CHAR$LAYOUT ); static final MethodHandle SetConfiguration$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.SetConfiguration$FUNC + IOUSBDeviceStruct182.SetConfiguration$FUNC ); /** * {@snippet : @@ -1475,13 +1491,13 @@ public interface SetConfiguration { int apply(java.lang.foreign.MemorySegment _x0, byte _x1); static MemorySegment allocate(SetConfiguration fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(SetConfiguration.class, fi, IOUSBDeviceStruct100.SetConfiguration$FUNC, scope); + return RuntimeHelper.upcallStub(SetConfiguration.class, fi, IOUSBDeviceStruct182.SetConfiguration$FUNC, scope); } static SetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBDeviceStruct100.SetConfiguration$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct182.SetConfiguration$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1491,7 +1507,7 @@ static SetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle SetConfiguration$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetConfiguration")); public static VarHandle SetConfiguration$VH() { - return IOUSBDeviceStruct100.SetConfiguration$VH; + return IOUSBDeviceStruct182.SetConfiguration$VH; } /** * Getter for field: @@ -1500,7 +1516,7 @@ static SetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment SetConfiguration$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.SetConfiguration$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.SetConfiguration$VH.get(seg); } /** * Setter for field: @@ -1509,13 +1525,13 @@ static SetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void SetConfiguration$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.SetConfiguration$VH.set(seg, x); + IOUSBDeviceStruct182.SetConfiguration$VH.set(seg, x); } public static MemorySegment SetConfiguration$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.SetConfiguration$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.SetConfiguration$VH.get(seg.asSlice(index*sizeof())); } public static void SetConfiguration$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.SetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.SetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); } public static SetConfiguration SetConfiguration(MemorySegment segment, SegmentScope scope) { return SetConfiguration.ofAddress(SetConfiguration$get(segment), scope); @@ -1526,7 +1542,7 @@ public static SetConfiguration SetConfiguration(MemorySegment segment, SegmentSc Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetBusFrameNumber$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.GetBusFrameNumber$FUNC + IOUSBDeviceStruct182.GetBusFrameNumber$FUNC ); /** * {@snippet : @@ -1537,13 +1553,13 @@ public interface GetBusFrameNumber { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); static MemorySegment allocate(GetBusFrameNumber fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetBusFrameNumber.class, fi, IOUSBDeviceStruct100.GetBusFrameNumber$FUNC, scope); + return RuntimeHelper.upcallStub(GetBusFrameNumber.class, fi, IOUSBDeviceStruct182.GetBusFrameNumber$FUNC, scope); } static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBDeviceStruct100.GetBusFrameNumber$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)IOUSBDeviceStruct182.GetBusFrameNumber$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1553,7 +1569,7 @@ static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetBusFrameNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBusFrameNumber")); public static VarHandle GetBusFrameNumber$VH() { - return IOUSBDeviceStruct100.GetBusFrameNumber$VH; + return IOUSBDeviceStruct182.GetBusFrameNumber$VH; } /** * Getter for field: @@ -1562,7 +1578,7 @@ static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetBusFrameNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetBusFrameNumber$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetBusFrameNumber$VH.get(seg); } /** * Setter for field: @@ -1571,13 +1587,13 @@ static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetBusFrameNumber$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.GetBusFrameNumber$VH.set(seg, x); + IOUSBDeviceStruct182.GetBusFrameNumber$VH.set(seg, x); } public static MemorySegment GetBusFrameNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.GetBusFrameNumber$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetBusFrameNumber$VH.get(seg.asSlice(index*sizeof())); } public static void GetBusFrameNumber$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.GetBusFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.GetBusFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); } public static GetBusFrameNumber GetBusFrameNumber(MemorySegment segment, SegmentScope scope) { return GetBusFrameNumber.ofAddress(GetBusFrameNumber$get(segment), scope); @@ -1586,7 +1602,7 @@ public static GetBusFrameNumber GetBusFrameNumber(MemorySegment segment, Segment Constants$root.C_POINTER$LAYOUT ); static final MethodHandle ResetDevice$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.ResetDevice$FUNC + IOUSBDeviceStruct182.ResetDevice$FUNC ); /** * {@snippet : @@ -1597,13 +1613,13 @@ public interface ResetDevice { int apply(java.lang.foreign.MemorySegment _x0); static MemorySegment allocate(ResetDevice fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(ResetDevice.class, fi, IOUSBDeviceStruct100.ResetDevice$FUNC, scope); + return RuntimeHelper.upcallStub(ResetDevice.class, fi, IOUSBDeviceStruct182.ResetDevice$FUNC, scope); } static ResetDevice ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct100.ResetDevice$MH.invokeExact(symbol, __x0); + return (int)IOUSBDeviceStruct182.ResetDevice$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1613,7 +1629,7 @@ static ResetDevice ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle ResetDevice$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ResetDevice")); public static VarHandle ResetDevice$VH() { - return IOUSBDeviceStruct100.ResetDevice$VH; + return IOUSBDeviceStruct182.ResetDevice$VH; } /** * Getter for field: @@ -1622,7 +1638,7 @@ static ResetDevice ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment ResetDevice$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.ResetDevice$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.ResetDevice$VH.get(seg); } /** * Setter for field: @@ -1631,13 +1647,13 @@ static ResetDevice ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void ResetDevice$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.ResetDevice$VH.set(seg, x); + IOUSBDeviceStruct182.ResetDevice$VH.set(seg, x); } public static MemorySegment ResetDevice$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.ResetDevice$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.ResetDevice$VH.get(seg.asSlice(index*sizeof())); } public static void ResetDevice$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.ResetDevice$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.ResetDevice$VH.set(seg.asSlice(index*sizeof()), x); } public static ResetDevice ResetDevice(MemorySegment segment, SegmentScope scope) { return ResetDevice.ofAddress(ResetDevice$get(segment), scope); @@ -1647,7 +1663,7 @@ public static ResetDevice ResetDevice(MemorySegment segment, SegmentScope scope) Constants$root.C_POINTER$LAYOUT ); static final MethodHandle DeviceRequest$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.DeviceRequest$FUNC + IOUSBDeviceStruct182.DeviceRequest$FUNC ); /** * {@snippet : @@ -1658,13 +1674,13 @@ public interface DeviceRequest { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(DeviceRequest fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(DeviceRequest.class, fi, IOUSBDeviceStruct100.DeviceRequest$FUNC, scope); + return RuntimeHelper.upcallStub(DeviceRequest.class, fi, IOUSBDeviceStruct182.DeviceRequest$FUNC, scope); } static DeviceRequest ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct100.DeviceRequest$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct182.DeviceRequest$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1674,7 +1690,7 @@ static DeviceRequest ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle DeviceRequest$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequest")); public static VarHandle DeviceRequest$VH() { - return IOUSBDeviceStruct100.DeviceRequest$VH; + return IOUSBDeviceStruct182.DeviceRequest$VH; } /** * Getter for field: @@ -1683,7 +1699,7 @@ static DeviceRequest ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment DeviceRequest$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.DeviceRequest$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.DeviceRequest$VH.get(seg); } /** * Setter for field: @@ -1692,13 +1708,13 @@ static DeviceRequest ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void DeviceRequest$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.DeviceRequest$VH.set(seg, x); + IOUSBDeviceStruct182.DeviceRequest$VH.set(seg, x); } public static MemorySegment DeviceRequest$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.DeviceRequest$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.DeviceRequest$VH.get(seg.asSlice(index*sizeof())); } public static void DeviceRequest$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.DeviceRequest$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.DeviceRequest$VH.set(seg.asSlice(index*sizeof()), x); } public static DeviceRequest DeviceRequest(MemorySegment segment, SegmentScope scope) { return DeviceRequest.ofAddress(DeviceRequest$get(segment), scope); @@ -1710,7 +1726,7 @@ public static DeviceRequest DeviceRequest(MemorySegment segment, SegmentScope sc Constants$root.C_POINTER$LAYOUT ); static final MethodHandle DeviceRequestAsync$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.DeviceRequestAsync$FUNC + IOUSBDeviceStruct182.DeviceRequestAsync$FUNC ); /** * {@snippet : @@ -1721,13 +1737,13 @@ public interface DeviceRequestAsync { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3); static MemorySegment allocate(DeviceRequestAsync fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(DeviceRequestAsync.class, fi, IOUSBDeviceStruct100.DeviceRequestAsync$FUNC, scope); + return RuntimeHelper.upcallStub(DeviceRequestAsync.class, fi, IOUSBDeviceStruct182.DeviceRequestAsync$FUNC, scope); } static DeviceRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3) -> { try { - return (int)IOUSBDeviceStruct100.DeviceRequestAsync$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); + return (int)IOUSBDeviceStruct182.DeviceRequestAsync$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1737,7 +1753,7 @@ static DeviceRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle DeviceRequestAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestAsync")); public static VarHandle DeviceRequestAsync$VH() { - return IOUSBDeviceStruct100.DeviceRequestAsync$VH; + return IOUSBDeviceStruct182.DeviceRequestAsync$VH; } /** * Getter for field: @@ -1746,7 +1762,7 @@ static DeviceRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment DeviceRequestAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.DeviceRequestAsync$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.DeviceRequestAsync$VH.get(seg); } /** * Setter for field: @@ -1755,13 +1771,13 @@ static DeviceRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void DeviceRequestAsync$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.DeviceRequestAsync$VH.set(seg, x); + IOUSBDeviceStruct182.DeviceRequestAsync$VH.set(seg, x); } public static MemorySegment DeviceRequestAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.DeviceRequestAsync$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.DeviceRequestAsync$VH.get(seg.asSlice(index*sizeof())); } public static void DeviceRequestAsync$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.DeviceRequestAsync$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.DeviceRequestAsync$VH.set(seg.asSlice(index*sizeof()), x); } public static DeviceRequestAsync DeviceRequestAsync(MemorySegment segment, SegmentScope scope) { return DeviceRequestAsync.ofAddress(DeviceRequestAsync$get(segment), scope); @@ -1772,7 +1788,7 @@ public static DeviceRequestAsync DeviceRequestAsync(MemorySegment segment, Segme Constants$root.C_POINTER$LAYOUT ); static final MethodHandle CreateInterfaceIterator$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct100.CreateInterfaceIterator$FUNC + IOUSBDeviceStruct182.CreateInterfaceIterator$FUNC ); /** * {@snippet : @@ -1783,13 +1799,13 @@ public interface CreateInterfaceIterator { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); static MemorySegment allocate(CreateInterfaceIterator fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(CreateInterfaceIterator.class, fi, IOUSBDeviceStruct100.CreateInterfaceIterator$FUNC, scope); + return RuntimeHelper.upcallStub(CreateInterfaceIterator.class, fi, IOUSBDeviceStruct182.CreateInterfaceIterator$FUNC, scope); } static CreateInterfaceIterator ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBDeviceStruct100.CreateInterfaceIterator$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)IOUSBDeviceStruct182.CreateInterfaceIterator$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1799,7 +1815,7 @@ static CreateInterfaceIterator ofAddress(MemorySegment addr, SegmentScope scope) static final VarHandle CreateInterfaceIterator$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceIterator")); public static VarHandle CreateInterfaceIterator$VH() { - return IOUSBDeviceStruct100.CreateInterfaceIterator$VH; + return IOUSBDeviceStruct182.CreateInterfaceIterator$VH; } /** * Getter for field: @@ -1808,7 +1824,7 @@ static CreateInterfaceIterator ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static MemorySegment CreateInterfaceIterator$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.CreateInterfaceIterator$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.CreateInterfaceIterator$VH.get(seg); } /** * Setter for field: @@ -1817,17 +1833,505 @@ static CreateInterfaceIterator ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static void CreateInterfaceIterator$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct100.CreateInterfaceIterator$VH.set(seg, x); + IOUSBDeviceStruct182.CreateInterfaceIterator$VH.set(seg, x); } public static MemorySegment CreateInterfaceIterator$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct100.CreateInterfaceIterator$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.CreateInterfaceIterator$VH.get(seg.asSlice(index*sizeof())); } public static void CreateInterfaceIterator$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct100.CreateInterfaceIterator$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct182.CreateInterfaceIterator$VH.set(seg.asSlice(index*sizeof()), x); } public static CreateInterfaceIterator CreateInterfaceIterator(MemorySegment segment, SegmentScope scope) { return CreateInterfaceIterator.ofAddress(CreateInterfaceIterator$get(segment), scope); } + static final FunctionDescriptor USBDeviceOpenSeize$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBDeviceOpenSeize$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct182.USBDeviceOpenSeize$FUNC + ); + /** + * {@snippet : + * IOReturn (*USBDeviceOpenSeize)(void*); + * } + */ + public interface USBDeviceOpenSeize { + + int apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(USBDeviceOpenSeize fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(USBDeviceOpenSeize.class, fi, IOUSBDeviceStruct182.USBDeviceOpenSeize$FUNC, scope); + } + static USBDeviceOpenSeize ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { + try { + return (int)IOUSBDeviceStruct182.USBDeviceOpenSeize$MH.invokeExact(symbol, __x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBDeviceOpenSeize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceOpenSeize")); + public static VarHandle USBDeviceOpenSeize$VH() { + return IOUSBDeviceStruct182.USBDeviceOpenSeize$VH; + } + /** + * Getter for field: + * {@snippet : + * IOReturn (*USBDeviceOpenSeize)(void*); + * } + */ + public static MemorySegment USBDeviceOpenSeize$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceOpenSeize$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*USBDeviceOpenSeize)(void*); + * } + */ + public static void USBDeviceOpenSeize$set(MemorySegment seg, MemorySegment x) { + IOUSBDeviceStruct182.USBDeviceOpenSeize$VH.set(seg, x); + } + public static MemorySegment USBDeviceOpenSeize$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceOpenSeize$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBDeviceOpenSeize$set(MemorySegment seg, long index, MemorySegment x) { + IOUSBDeviceStruct182.USBDeviceOpenSeize$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBDeviceOpenSeize USBDeviceOpenSeize(MemorySegment segment, SegmentScope scope) { + return USBDeviceOpenSeize.ofAddress(USBDeviceOpenSeize$get(segment), scope); + } + static final FunctionDescriptor DeviceRequestTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle DeviceRequestTO$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct182.DeviceRequestTO$FUNC + ); + /** + * {@snippet : + * IOReturn (*DeviceRequestTO)(void*,IOUSBDevRequestTO*); + * } + */ + public interface DeviceRequestTO { + + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(DeviceRequestTO fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(DeviceRequestTO.class, fi, IOUSBDeviceStruct182.DeviceRequestTO$FUNC, scope); + } + static DeviceRequestTO ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { + try { + return (int)IOUSBDeviceStruct182.DeviceRequestTO$MH.invokeExact(symbol, __x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle DeviceRequestTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestTO")); + public static VarHandle DeviceRequestTO$VH() { + return IOUSBDeviceStruct182.DeviceRequestTO$VH; + } + /** + * Getter for field: + * {@snippet : + * IOReturn (*DeviceRequestTO)(void*,IOUSBDevRequestTO*); + * } + */ + public static MemorySegment DeviceRequestTO$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.DeviceRequestTO$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*DeviceRequestTO)(void*,IOUSBDevRequestTO*); + * } + */ + public static void DeviceRequestTO$set(MemorySegment seg, MemorySegment x) { + IOUSBDeviceStruct182.DeviceRequestTO$VH.set(seg, x); + } + public static MemorySegment DeviceRequestTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.DeviceRequestTO$VH.get(seg.asSlice(index*sizeof())); + } + public static void DeviceRequestTO$set(MemorySegment seg, long index, MemorySegment x) { + IOUSBDeviceStruct182.DeviceRequestTO$VH.set(seg.asSlice(index*sizeof()), x); + } + public static DeviceRequestTO DeviceRequestTO(MemorySegment segment, SegmentScope scope) { + return DeviceRequestTO.ofAddress(DeviceRequestTO$get(segment), scope); + } + static final FunctionDescriptor DeviceRequestAsyncTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle DeviceRequestAsyncTO$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct182.DeviceRequestAsyncTO$FUNC + ); + /** + * {@snippet : + * IOReturn (*DeviceRequestAsyncTO)(void*,IOUSBDevRequestTO*,IOAsyncCallback1,void*); + * } + */ + public interface DeviceRequestAsyncTO { + + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3); + static MemorySegment allocate(DeviceRequestAsyncTO fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(DeviceRequestAsyncTO.class, fi, IOUSBDeviceStruct182.DeviceRequestAsyncTO$FUNC, scope); + } + static DeviceRequestAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3) -> { + try { + return (int)IOUSBDeviceStruct182.DeviceRequestAsyncTO$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle DeviceRequestAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestAsyncTO")); + public static VarHandle DeviceRequestAsyncTO$VH() { + return IOUSBDeviceStruct182.DeviceRequestAsyncTO$VH; + } + /** + * Getter for field: + * {@snippet : + * IOReturn (*DeviceRequestAsyncTO)(void*,IOUSBDevRequestTO*,IOAsyncCallback1,void*); + * } + */ + public static MemorySegment DeviceRequestAsyncTO$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.DeviceRequestAsyncTO$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*DeviceRequestAsyncTO)(void*,IOUSBDevRequestTO*,IOAsyncCallback1,void*); + * } + */ + public static void DeviceRequestAsyncTO$set(MemorySegment seg, MemorySegment x) { + IOUSBDeviceStruct182.DeviceRequestAsyncTO$VH.set(seg, x); + } + public static MemorySegment DeviceRequestAsyncTO$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.DeviceRequestAsyncTO$VH.get(seg.asSlice(index*sizeof())); + } + public static void DeviceRequestAsyncTO$set(MemorySegment seg, long index, MemorySegment x) { + IOUSBDeviceStruct182.DeviceRequestAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); + } + public static DeviceRequestAsyncTO DeviceRequestAsyncTO(MemorySegment segment, SegmentScope scope) { + return DeviceRequestAsyncTO.ofAddress(DeviceRequestAsyncTO$get(segment), scope); + } + static final FunctionDescriptor USBDeviceSuspend$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_CHAR$LAYOUT + ); + static final MethodHandle USBDeviceSuspend$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct182.USBDeviceSuspend$FUNC + ); + /** + * {@snippet : + * IOReturn (*USBDeviceSuspend)(void*,Boolean); + * } + */ + public interface USBDeviceSuspend { + + int apply(java.lang.foreign.MemorySegment _x0, byte _x1); + static MemorySegment allocate(USBDeviceSuspend fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(USBDeviceSuspend.class, fi, IOUSBDeviceStruct182.USBDeviceSuspend$FUNC, scope); + } + static USBDeviceSuspend ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { + try { + return (int)IOUSBDeviceStruct182.USBDeviceSuspend$MH.invokeExact(symbol, __x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBDeviceSuspend$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceSuspend")); + public static VarHandle USBDeviceSuspend$VH() { + return IOUSBDeviceStruct182.USBDeviceSuspend$VH; + } + /** + * Getter for field: + * {@snippet : + * IOReturn (*USBDeviceSuspend)(void*,Boolean); + * } + */ + public static MemorySegment USBDeviceSuspend$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceSuspend$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*USBDeviceSuspend)(void*,Boolean); + * } + */ + public static void USBDeviceSuspend$set(MemorySegment seg, MemorySegment x) { + IOUSBDeviceStruct182.USBDeviceSuspend$VH.set(seg, x); + } + public static MemorySegment USBDeviceSuspend$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceSuspend$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBDeviceSuspend$set(MemorySegment seg, long index, MemorySegment x) { + IOUSBDeviceStruct182.USBDeviceSuspend$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBDeviceSuspend USBDeviceSuspend(MemorySegment segment, SegmentScope scope) { + return USBDeviceSuspend.ofAddress(USBDeviceSuspend$get(segment), scope); + } + static final FunctionDescriptor USBDeviceAbortPipeZero$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBDeviceAbortPipeZero$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct182.USBDeviceAbortPipeZero$FUNC + ); + /** + * {@snippet : + * IOReturn (*USBDeviceAbortPipeZero)(void*); + * } + */ + public interface USBDeviceAbortPipeZero { + + int apply(java.lang.foreign.MemorySegment _x0); + static MemorySegment allocate(USBDeviceAbortPipeZero fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(USBDeviceAbortPipeZero.class, fi, IOUSBDeviceStruct182.USBDeviceAbortPipeZero$FUNC, scope); + } + static USBDeviceAbortPipeZero ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0) -> { + try { + return (int)IOUSBDeviceStruct182.USBDeviceAbortPipeZero$MH.invokeExact(symbol, __x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBDeviceAbortPipeZero$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceAbortPipeZero")); + public static VarHandle USBDeviceAbortPipeZero$VH() { + return IOUSBDeviceStruct182.USBDeviceAbortPipeZero$VH; + } + /** + * Getter for field: + * {@snippet : + * IOReturn (*USBDeviceAbortPipeZero)(void*); + * } + */ + public static MemorySegment USBDeviceAbortPipeZero$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceAbortPipeZero$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*USBDeviceAbortPipeZero)(void*); + * } + */ + public static void USBDeviceAbortPipeZero$set(MemorySegment seg, MemorySegment x) { + IOUSBDeviceStruct182.USBDeviceAbortPipeZero$VH.set(seg, x); + } + public static MemorySegment USBDeviceAbortPipeZero$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceAbortPipeZero$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBDeviceAbortPipeZero$set(MemorySegment seg, long index, MemorySegment x) { + IOUSBDeviceStruct182.USBDeviceAbortPipeZero$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBDeviceAbortPipeZero USBDeviceAbortPipeZero(MemorySegment segment, SegmentScope scope) { + return USBDeviceAbortPipeZero.ofAddress(USBDeviceAbortPipeZero$get(segment), scope); + } + static final FunctionDescriptor USBGetManufacturerStringIndex$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBGetManufacturerStringIndex$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct182.USBGetManufacturerStringIndex$FUNC + ); + /** + * {@snippet : + * IOReturn (*USBGetManufacturerStringIndex)(void*,UInt8*); + * } + */ + public interface USBGetManufacturerStringIndex { + + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(USBGetManufacturerStringIndex fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(USBGetManufacturerStringIndex.class, fi, IOUSBDeviceStruct182.USBGetManufacturerStringIndex$FUNC, scope); + } + static USBGetManufacturerStringIndex ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { + try { + return (int)IOUSBDeviceStruct182.USBGetManufacturerStringIndex$MH.invokeExact(symbol, __x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBGetManufacturerStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBGetManufacturerStringIndex")); + public static VarHandle USBGetManufacturerStringIndex$VH() { + return IOUSBDeviceStruct182.USBGetManufacturerStringIndex$VH; + } + /** + * Getter for field: + * {@snippet : + * IOReturn (*USBGetManufacturerStringIndex)(void*,UInt8*); + * } + */ + public static MemorySegment USBGetManufacturerStringIndex$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBGetManufacturerStringIndex$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*USBGetManufacturerStringIndex)(void*,UInt8*); + * } + */ + public static void USBGetManufacturerStringIndex$set(MemorySegment seg, MemorySegment x) { + IOUSBDeviceStruct182.USBGetManufacturerStringIndex$VH.set(seg, x); + } + public static MemorySegment USBGetManufacturerStringIndex$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBGetManufacturerStringIndex$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBGetManufacturerStringIndex$set(MemorySegment seg, long index, MemorySegment x) { + IOUSBDeviceStruct182.USBGetManufacturerStringIndex$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBGetManufacturerStringIndex USBGetManufacturerStringIndex(MemorySegment segment, SegmentScope scope) { + return USBGetManufacturerStringIndex.ofAddress(USBGetManufacturerStringIndex$get(segment), scope); + } + static final FunctionDescriptor USBGetProductStringIndex$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBGetProductStringIndex$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct182.USBGetProductStringIndex$FUNC + ); + /** + * {@snippet : + * IOReturn (*USBGetProductStringIndex)(void*,UInt8*); + * } + */ + public interface USBGetProductStringIndex { + + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(USBGetProductStringIndex fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(USBGetProductStringIndex.class, fi, IOUSBDeviceStruct182.USBGetProductStringIndex$FUNC, scope); + } + static USBGetProductStringIndex ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { + try { + return (int)IOUSBDeviceStruct182.USBGetProductStringIndex$MH.invokeExact(symbol, __x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBGetProductStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBGetProductStringIndex")); + public static VarHandle USBGetProductStringIndex$VH() { + return IOUSBDeviceStruct182.USBGetProductStringIndex$VH; + } + /** + * Getter for field: + * {@snippet : + * IOReturn (*USBGetProductStringIndex)(void*,UInt8*); + * } + */ + public static MemorySegment USBGetProductStringIndex$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBGetProductStringIndex$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*USBGetProductStringIndex)(void*,UInt8*); + * } + */ + public static void USBGetProductStringIndex$set(MemorySegment seg, MemorySegment x) { + IOUSBDeviceStruct182.USBGetProductStringIndex$VH.set(seg, x); + } + public static MemorySegment USBGetProductStringIndex$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBGetProductStringIndex$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBGetProductStringIndex$set(MemorySegment seg, long index, MemorySegment x) { + IOUSBDeviceStruct182.USBGetProductStringIndex$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBGetProductStringIndex USBGetProductStringIndex(MemorySegment segment, SegmentScope scope) { + return USBGetProductStringIndex.ofAddress(USBGetProductStringIndex$get(segment), scope); + } + static final FunctionDescriptor USBGetSerialNumberStringIndex$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle USBGetSerialNumberStringIndex$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct182.USBGetSerialNumberStringIndex$FUNC + ); + /** + * {@snippet : + * IOReturn (*USBGetSerialNumberStringIndex)(void*,UInt8*); + * } + */ + public interface USBGetSerialNumberStringIndex { + + int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); + static MemorySegment allocate(USBGetSerialNumberStringIndex fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(USBGetSerialNumberStringIndex.class, fi, IOUSBDeviceStruct182.USBGetSerialNumberStringIndex$FUNC, scope); + } + static USBGetSerialNumberStringIndex ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { + try { + return (int)IOUSBDeviceStruct182.USBGetSerialNumberStringIndex$MH.invokeExact(symbol, __x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBGetSerialNumberStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBGetSerialNumberStringIndex")); + public static VarHandle USBGetSerialNumberStringIndex$VH() { + return IOUSBDeviceStruct182.USBGetSerialNumberStringIndex$VH; + } + /** + * Getter for field: + * {@snippet : + * IOReturn (*USBGetSerialNumberStringIndex)(void*,UInt8*); + * } + */ + public static MemorySegment USBGetSerialNumberStringIndex$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBGetSerialNumberStringIndex$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*USBGetSerialNumberStringIndex)(void*,UInt8*); + * } + */ + public static void USBGetSerialNumberStringIndex$set(MemorySegment seg, MemorySegment x) { + IOUSBDeviceStruct182.USBGetSerialNumberStringIndex$VH.set(seg, x); + } + public static MemorySegment USBGetSerialNumberStringIndex$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBGetSerialNumberStringIndex$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBGetSerialNumberStringIndex$set(MemorySegment seg, long index, MemorySegment x) { + IOUSBDeviceStruct182.USBGetSerialNumberStringIndex$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBGetSerialNumberStringIndex USBGetSerialNumberStringIndex(MemorySegment segment, SegmentScope scope) { + return USBGetSerialNumberStringIndex.ofAddress(USBGetSerialNumberStringIndex$get(segment), scope); + } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/USBSerialTest.java b/java-does-usb/src/test/java/net/codecrete/usb/sample/USBSerialTest.java index da6d5546..edab3b2a 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/sample/USBSerialTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/sample/USBSerialTest.java @@ -10,14 +10,14 @@ import net.codecrete.usb.*; /** - * Interacts with a USB CDC device (serial device) directly,without using the + * Interacts with a USB CDC device (serial device) directly, without using the * standard USB CDC driver. * *

* This test is aimed at Linux, which requires to unload and restore the - * kernel driver. It also works on macOS (without the needed to unload a - * driver). It will fail on Windows as the standard driver is in the way and - * cannot be quickly replaced. + * kernel driver. It will neither work on macOS (the USB CDC driver claims the + * interface with exclusive access) nor on Windows (only devices with the + * WinUSB driver can be opened). *

*

* For the test to work on Linux, the user must have sufficient permission to From 3739fc9d41af0663a08a97c31d1262055c0051f9 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 28 Apr 2023 20:36:16 +0200 Subject: [PATCH 220/433] macOS reference code: use USBDevcieOpenSeize --- reference/macos/USB/usb_device.cpp | 4 ++-- reference/macos/USB/usb_registry.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/reference/macos/USB/usb_device.cpp b/reference/macos/USB/usb_device.cpp index 6b6a699e..47f8aab3 100644 --- a/reference/macos/USB/usb_device.cpp +++ b/reference/macos/USB/usb_device.cpp @@ -98,7 +98,7 @@ void usb_device::open() { int tries = 0; IOReturn ret = 0; while (tries < 3) { - ret = (*device_)->USBDeviceOpen(device_); + ret = (*device_)->USBDeviceOpenSeize(device_); if (ret != kIOReturnExclusiveAccess) break; @@ -152,7 +152,7 @@ void usb_device::claim_interface(int interface_number) { auto service_guard = make_scope_exit([service]() { IOObjectRelease(service); }); - IOUSBInterfaceInterface** intf = iokit_helper::get_interface(service, kIOUSBInterfaceUserClientTypeID, kIOUSBInterfaceInterfaceID); + IOUSBInterfaceInterface** intf = iokit_helper::get_interface(service, kIOUSBInterfaceUserClientTypeID, kIOUSBInterfaceInterfaceID190); if (intf == nullptr) throw usb_error("internal error (failed to create interface interface)"); diff --git a/reference/macos/USB/usb_registry.cpp b/reference/macos/USB/usb_registry.cpp index adf3b909..478f46f0 100644 --- a/reference/macos/USB/usb_registry.cpp +++ b/reference/macos/USB/usb_registry.cpp @@ -130,7 +130,7 @@ void usb_registry::device_connected(io_iterator_t iterator) { auto service_guard = make_scope_exit([service]() { IOObjectRelease(service); }); // Test if the device has a client interface (otherwise it's likely a controller) - IOUSBDeviceInterface** dev = iokit_helper::get_interface(service, kIOUSBDeviceUserClientTypeID, kIOUSBDeviceInterfaceID); + IOUSBDeviceInterface** dev = iokit_helper::get_interface(service, kIOUSBDeviceUserClientTypeID, kIOUSBDeviceInterfaceID182); if (dev == nullptr) continue; From 2da89b1d17226dcec39082fc33870adf884d51e4 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 30 Apr 2023 17:24:01 +0200 Subject: [PATCH 221/433] Upgrade to latest TinyUSB --- .../composite-stm32/.vscode/settings.json | 9 + .../composite-stm32/bin/blackpill-f401cc.bin | Bin 11620 -> 11664 bytes .../composite-stm32/bin/blackpill-f411ce.bin | Bin 11624 -> 11668 bytes .../composite-stm32/bin/bluepill-f103c8.bin | Bin 10180 -> 12152 bytes .../lib/tinyusb/class/audio/audio.h | 8 +- .../lib/tinyusb/class/audio/audio_device.c | 426 +++--- .../lib/tinyusb/class/audio/audio_device.h | 4 +- .../lib/tinyusb/class/bth/bth_device.h | 2 +- .../lib/tinyusb/class/cdc/cdc.h | 45 +- .../lib/tinyusb/class/cdc/cdc_device.c | 29 +- .../lib/tinyusb/class/cdc/cdc_device.h | 7 +- .../lib/tinyusb/class/cdc/cdc_host.c | 1137 +++++++++++++++-- .../lib/tinyusb/class/cdc/cdc_host.h | 208 ++- .../lib/tinyusb/class/cdc/cdc_rndis.h | 2 +- .../lib/tinyusb/class/cdc/cdc_rndis_host.c | 8 +- .../lib/tinyusb/class/cdc/cdc_rndis_host.h | 2 +- .../lib/tinyusb/class/cdc/serial/cp210x.h | 64 + .../lib/tinyusb/class/cdc/serial/ftdi_sio.h | 249 ++++ .../lib/tinyusb/class/dfu/dfu_device.c | 14 +- .../lib/tinyusb/class/dfu/dfu_rt_device.c | 2 +- .../lib/tinyusb/class/hid/hid.h | 11 +- .../lib/tinyusb/class/hid/hid_device.c | 22 +- .../lib/tinyusb/class/hid/hid_device.h | 29 +- .../lib/tinyusb/class/hid/hid_host.c | 430 ++++--- .../lib/tinyusb/class/hid/hid_host.h | 56 +- .../lib/tinyusb/class/midi/midi.h | 6 +- .../lib/tinyusb/class/midi/midi_device.c | 13 +- .../lib/tinyusb/class/midi/midi_device.h | 2 +- .../lib/tinyusb/class/msc/msc.h | 2 +- .../lib/tinyusb/class/msc/msc_device.c | 18 +- .../lib/tinyusb/class/msc/msc_device.h | 2 +- .../lib/tinyusb/class/msc/msc_host.c | 102 +- .../lib/tinyusb/class/msc/msc_host.h | 25 +- .../lib/tinyusb/class/net/ecm_rndis_device.c | 21 +- .../lib/tinyusb/class/net/ncm_device.c | 16 +- .../lib/tinyusb/class/net/net_device.h | 4 +- .../lib/tinyusb/class/usbtmc/usbtmc.h | 25 +- .../lib/tinyusb/class/usbtmc/usbtmc_device.c | 106 +- .../lib/tinyusb/class/usbtmc/usbtmc_device.h | 2 +- .../lib/tinyusb/class/vendor/vendor_device.c | 65 +- .../lib/tinyusb/class/vendor/vendor_device.h | 25 +- .../lib/tinyusb/class/vendor/vendor_host.c | 2 +- .../lib/tinyusb/class/vendor/vendor_host.h | 2 +- .../lib/tinyusb/class/video/video.h | 81 +- .../lib/tinyusb/class/video/video_device.c | 246 +++- .../lib/tinyusb/common/tusb_common.h | 38 + .../lib/tinyusb/common/tusb_compiler.h | 40 +- .../lib/tinyusb/common/tusb_debug.h | 20 +- .../lib/tinyusb/common/tusb_fifo.c | 484 ++++--- .../lib/tinyusb/common/tusb_fifo.h | 103 +- .../lib/tinyusb/common/tusb_mcu.h | 135 +- .../lib/tinyusb/common/tusb_private.h | 110 +- .../lib/tinyusb/common/tusb_timeout.h | 2 +- .../lib/tinyusb/common/tusb_types.h | 44 +- .../lib/tinyusb/common/tusb_verify.h | 2 +- .../composite-stm32/lib/tinyusb/device/dcd.h | 10 +- .../composite-stm32/lib/tinyusb/device/usbd.c | 75 +- .../composite-stm32/lib/tinyusb/device/usbd.h | 28 +- .../lib/tinyusb/device/usbd_control.c | 8 +- .../lib/tinyusb/device/usbd_pvt.h | 8 +- .../lib/tinyusb/dwc2/dcd_dwc2.c | 11 +- .../lib/tinyusb/dwc2/dwc2_stm32.h | 12 +- .../lib/tinyusb/dwc2/hwcfg_list.md | 777 +++++++++++ .../composite-stm32/lib/tinyusb/osal/osal.h | 23 +- .../lib/tinyusb/osal/osal_freertos.h | 86 +- .../lib/tinyusb/osal/osal_none.h | 18 +- .../lib/tinyusb/osal/osal_pico.h | 2 +- .../lib/tinyusb/osal/osal_rtthread.h | 2 +- .../lib/tinyusb/osal/osal_rtx4.h | 4 +- .../lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c | 673 ++++++---- .../stm32_fsdev/dcd_stm32_fsdev_pvt_st.h | 241 ++-- .../composite-stm32/lib/tinyusb/tusb.c | 245 +++- .../composite-stm32/lib/tinyusb/tusb_option.h | 84 +- .../loopback-stm32/bin/blackpill-f401cc.bin | Bin 10740 -> 10840 bytes .../loopback-stm32/bin/blackpill-f411ce.bin | Bin 10744 -> 10844 bytes .../loopback-stm32/bin/bluepill-f103c8.bin | Bin 9236 -> 11068 bytes .../loopback-stm32/bin/disco_f723ie.bin | Bin 11504 -> 11616 bytes .../lib/tinyusb/class/audio/audio.h | 8 +- .../lib/tinyusb/class/audio/audio_device.c | 426 +++--- .../lib/tinyusb/class/audio/audio_device.h | 4 +- .../lib/tinyusb/class/bth/bth_device.h | 2 +- .../lib/tinyusb/class/cdc/cdc.h | 45 +- .../lib/tinyusb/class/cdc/cdc_device.c | 29 +- .../lib/tinyusb/class/cdc/cdc_device.h | 7 +- .../lib/tinyusb/class/cdc/cdc_host.c | 1137 +++++++++++++++-- .../lib/tinyusb/class/cdc/cdc_host.h | 208 ++- .../lib/tinyusb/class/cdc/cdc_rndis.h | 2 +- .../lib/tinyusb/class/cdc/cdc_rndis_host.c | 8 +- .../lib/tinyusb/class/cdc/cdc_rndis_host.h | 2 +- .../lib/tinyusb/class/cdc/serial/cp210x.h | 64 + .../lib/tinyusb/class/cdc/serial/ftdi_sio.h | 249 ++++ .../lib/tinyusb/class/dfu/dfu_device.c | 14 +- .../lib/tinyusb/class/dfu/dfu_rt_device.c | 2 +- .../lib/tinyusb/class/hid/hid.h | 11 +- .../lib/tinyusb/class/hid/hid_device.c | 22 +- .../lib/tinyusb/class/hid/hid_device.h | 29 +- .../lib/tinyusb/class/hid/hid_host.c | 430 ++++--- .../lib/tinyusb/class/hid/hid_host.h | 56 +- .../lib/tinyusb/class/midi/midi.h | 6 +- .../lib/tinyusb/class/midi/midi_device.c | 13 +- .../lib/tinyusb/class/midi/midi_device.h | 2 +- .../lib/tinyusb/class/msc/msc.h | 2 +- .../lib/tinyusb/class/msc/msc_device.c | 18 +- .../lib/tinyusb/class/msc/msc_device.h | 2 +- .../lib/tinyusb/class/msc/msc_host.c | 102 +- .../lib/tinyusb/class/msc/msc_host.h | 25 +- .../lib/tinyusb/class/net/ecm_rndis_device.c | 21 +- .../lib/tinyusb/class/net/ncm_device.c | 16 +- .../lib/tinyusb/class/net/net_device.h | 4 +- .../lib/tinyusb/class/usbtmc/usbtmc.h | 25 +- .../lib/tinyusb/class/usbtmc/usbtmc_device.c | 106 +- .../lib/tinyusb/class/usbtmc/usbtmc_device.h | 2 +- .../lib/tinyusb/class/vendor/vendor_device.c | 65 +- .../lib/tinyusb/class/vendor/vendor_device.h | 25 +- .../lib/tinyusb/class/vendor/vendor_host.c | 2 +- .../lib/tinyusb/class/vendor/vendor_host.h | 2 +- .../lib/tinyusb/class/video/video.h | 81 +- .../lib/tinyusb/class/video/video_device.c | 246 +++- .../lib/tinyusb/common/tusb_common.h | 38 + .../lib/tinyusb/common/tusb_compiler.h | 40 +- .../lib/tinyusb/common/tusb_debug.h | 20 +- .../lib/tinyusb/common/tusb_fifo.c | 492 +++---- .../lib/tinyusb/common/tusb_fifo.h | 103 +- .../lib/tinyusb/common/tusb_mcu.h | 135 +- .../lib/tinyusb/common/tusb_private.h | 110 +- .../lib/tinyusb/common/tusb_timeout.h | 2 +- .../lib/tinyusb/common/tusb_types.h | 44 +- .../lib/tinyusb/common/tusb_verify.h | 2 +- .../loopback-stm32/lib/tinyusb/device/dcd.h | 10 +- .../loopback-stm32/lib/tinyusb/device/usbd.c | 75 +- .../loopback-stm32/lib/tinyusb/device/usbd.h | 28 +- .../lib/tinyusb/device/usbd_control.c | 8 +- .../lib/tinyusb/device/usbd_pvt.h | 8 +- .../lib/tinyusb/dwc2/dcd_dwc2.c | 19 +- .../lib/tinyusb/dwc2/dwc2_stm32.h | 12 +- .../lib/tinyusb/dwc2/hwcfg_list.md | 777 +++++++++++ .../loopback-stm32/lib/tinyusb/osal/osal.h | 23 +- .../lib/tinyusb/osal/osal_freertos.h | 86 +- .../lib/tinyusb/osal/osal_none.h | 18 +- .../lib/tinyusb/osal/osal_pico.h | 2 +- .../lib/tinyusb/osal/osal_rtthread.h | 2 +- .../lib/tinyusb/osal/osal_rtx4.h | 4 +- .../lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c | 648 +++++++--- .../stm32_fsdev/dcd_stm32_fsdev_pvt_st.h | 241 ++-- .../loopback-stm32/lib/tinyusb/tusb.c | 245 +++- .../loopback-stm32/lib/tinyusb/tusb_option.h | 84 +- 146 files changed, 10401 insertions(+), 3209 deletions(-) create mode 100644 test-devices/composite-stm32/.vscode/settings.json create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/cdc/serial/cp210x.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/cdc/serial/ftdi_sio.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/dwc2/hwcfg_list.md create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/serial/cp210x.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/serial/ftdi_sio.h create mode 100644 test-devices/loopback-stm32/lib/tinyusb/dwc2/hwcfg_list.md diff --git a/test-devices/composite-stm32/.vscode/settings.json b/test-devices/composite-stm32/.vscode/settings.json new file mode 100644 index 00000000..87eaf860 --- /dev/null +++ b/test-devices/composite-stm32/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "files.associations": { + "tusb_option.h": "c", + "tusb_config.h": "c", + "cdc_device.h": "c", + "usbd_pvt.h": "c", + "usbd.h": "c" + } +} \ No newline at end of file diff --git a/test-devices/composite-stm32/bin/blackpill-f401cc.bin b/test-devices/composite-stm32/bin/blackpill-f401cc.bin index 3e2f142ad4dd479b717041324ebac075fbf9c0d3..c2fc3f0fa080f30193757440eefc8cab83324edf 100755 GIT binary patch delta 4511 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 delta 4460 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 diff --git a/test-devices/composite-stm32/bin/blackpill-f411ce.bin b/test-devices/composite-stm32/bin/blackpill-f411ce.bin index 58ed2e6fab02117d79b3cf873a5637b00dfaad35..9b9b6a087c2617d099436148542a3d3dcb5705b1 100755 GIT binary patch delta 4400 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 PHOk=5jM6C5NCf&j1tQf6 delta 4457 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 RilRga@PKNfafY7??O&nR><0h< diff --git a/test-devices/composite-stm32/bin/bluepill-f103c8.bin b/test-devices/composite-stm32/bin/bluepill-f103c8.bin index 916356c4b93dc531aa0a9f657cbb986151a01c37..fa6465296e208f1e3f507a1c041c00a116f1f635 100755 GIT binary patch delta 7946 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

mQCc*4u*vNDw#Vw) z{skiS$ShIzNFuge6+}4Uufe0-$ugS{PTLJoJq4dd-!tsz-v}xb z{(7h`Mtkcm;WG9$CF+1_L?%phIoowcLrJ4L}m$CvCzjVcGrRFpOh4P zl)EcjYHy*4=dN-&u3^)wyy}Qi%&&w~j7duUo21+g758=OPP_y!=!8Pj&qD{5?J*J1cihu#=b%jo1=o4Q8>n`gLhsjY0d_ABMQsG zvYC^^PP1UAw+S}dnM6*f;HQtmy4Bf}M8z!y@04IY4668J1lER#B6Tk1Za;rKhMVB1 zNG1TZ;;0eDGw9S=vsLw z;C&|l@Y%NJ(iQ^Vt+#OTAMo@-<5tYr345Gs$Y8{%$O;&(xM*Pdkbbb3$ux{lsZn!@ZG!8Bgu`<1N^a3|K|AF5ic#!G;O_n_QNZ* z@CfzDj~kNyrn>8Xs^QuWC19vlKH6Jr4LmPWFPeSHPr$$)y2$CgrlPHWYoOuUIX#%Y zrrT>2JeU@IFqY%A`hVdr4H%Oj)sS9|Q|~vjpfV?=rb{@aXUQ>UNwgOfxGVCL2MX7PK>ynA%3aVH_=&by(3I94AY%XB)jOrq85FPqIKbINwn@_%wnu@7BlD7 zC`}g?x%P|sJG%iRWVXULq`Hmm9JgZltEAh+!cNTmfuao_W6U1 z-$c2I7!mF!iE`8dDNI9S;C<4?h>~tN@VKCnu#90`+w+zg?x@1J>SmPYe$A}I|IS@y z%s$@zY-hLVV&E=Hj$2F4fUB?F58uetE!NrI73VSUiVK-`@lK{8X@BhX5eu!}D1%Bv0wIL z(nna#UOvI$?R(+=E&coz8bQd}1d7`7Uv3xYb<$U9L|~9fy*1vDlsU*8m?77>+tIzg zbyeWIo(bQD%vI$dy-bDZ|DCzoq0tk@k-S-x^V?oV6u`3RvfdP{+OB zfli*gJb`dKAp2*4V&aYj*~ArzOOgymR<4YERi3ZP-wWLvBScio7h+!A0%gJWF`An> z78p@*P%~J63gto05vZ+i_KS0ODnh&AI%_vvi_Wthj;pDO5<$lGi&|T$fD7c@stB^K zh|Gb*tDarM=C&yz6O4~3LzHPx_S$O=t3E9GQpvI0P`_BtxLq`q4)A8n+hfoadGgwT z6{AT|8oUHlNno3l`d~~RqTAe1GGtPh(_4ayJ$lz;&57WaV4#*dy)d}PF*k}##18>8 z;Df^tPWm6K-GjK-Ne^6IWv*Hpu6-y&3Za7d1J6 zNavDL`^Mgk4eFnB*w0qanMg!A*(@cDI3Y`AlarA#F114XV5nP33T(=dL{$>0gsu7@ z8-U5?4nSq&-~1Zc3g2yz+1E{^4uXO9*gq!-IV6bb*#xm}?fWrqLLg+rqJLJx#F)NN z;`;T~PEbO-%@O4LZ)eLv$d=A)EoOOq4V>usAX3)97ef`kq`m_}(}VJC9BGG=p8$sd ziGYZNPbk#U;vP6@%axT4*P_KxH4V9ztDD}=t_;m;-byvrHqy|k{TSgxEYFDfPZJvp+;8S+i6WK!#Ls=PaW{rWeYo#JY=-{I${M@TX} zpA|4s_V(7~Kr)?l%`dE$<0tp|7UN21u@R?bYgDdRZ(DJ4#W=ni8K6G!qit*dCsu9k z6n(3iiQS}KM5iz9CKxws$gE0&;BxMVo$S4B#DT04{bmdsL-Mww?hG8p+HahQ5x2|M z_V6TD%UaLuH|n9pd;oqP1^Yo-1^Z1YcI$jY#gnz<$91g)x>HVH%7Sn2Hu?c=Lpo&}{$4p5-Pkh(7RzNajl-^?@}|9 zWZN*m`^i~U=5*ma^aj7CUB*B7Nw!Ag1%ZeS{2h{F|fbwr!XxJzf+Eme9R%A`u<$FckrHVK}R3;M0v}rQ$+!Xxu zdoSO2X6D}eyXT(!yXT&JZsdP|x9M;h&L~63fZ%tyTv&kf)n+KdXFa~R@Z1EF9-MI3 z?wpHQ02m08$Xel5yqh{%E^t&SHC8S>PA$NTk8G!CjBP>>J$JSZK*)flo*^X`4=AyT z0751H%sRXuNrl2E^xQ`_)5yU3**YX`PE?yS&SC?SUZ1cI3|?Ywwo-ZpDL+5J4icOb z1eGDba9D}muArB&sVRy!>Q?BW_nip?hol|J{FMc(3L2Xv#fpqrS|$9HscG5<{Yd{t zu!aF~g0TKhA5*7Vfu!Fil-M5?GM*CS1GmPh@~gNRbsEr_oZ4(R2Nu|Fl{6@(QZ`du3bA<_*!Mpc>X)d=gkVi8_540*9XR5v;EWs@9Z3%ixd)ZlmjTQHX_5yPU^3wLqli|;z_>{IAYN^r zb@r1M(psA2`$^q9Q1?ko+F2%Yl(LypdZ2aT5W&nzBCwS8H$`80ny#ng$e^_%>4i8u zxD{-1dq~4CoDTI$CZa`MKC=@^$Kz_wT&Tp}RjizQ5CsVE_RG?86%5ror5!+q!Anvr zk`7I!amXAC5e-i`@*4Lh9cLww9{wM&<7%thQU2fio^ivOEm6I8Jp42$Y)w&yOjrY#;U9zN z;3cgM8ntu~kW)`d>782{oZ|5yb;Y}7c!`bEQ zv{R$)9fF-2v2{>T)^hIJHt+NLPJ6eH8f)v=0WJ29Zhg0pZgbZPpJtjpSQ?$e-KJ*x zur&Cf%sex<`I311Wtd3W23&K4C-db@phxxUgJ(au{Z`RQG<#d{WQ3u+eMi8YN(cZq^jQ&B^MLaWU!%-q zl|GDQjlo{LwI(xkm#f)Xp6T3fXG6IAZ!*NP1;>JmxDQ1w7Z$T+Y(X+!cvZa1^|i1h zYo2Gp6ya#5s|HxQBDx_+?y&C))2NuM3T)`$fuCXhL12gXwcBTK%!rxG2192n`@Hw{ zAMoz7vuCe(=eevLaFLCrv?&t(_P}%_z;~=k#r?Ho28TN5ZOY>UKHle-nc*wm{l}iO z?+qhd6>xbvI(+v8()As_KZP;w@cj=HR0>#bbAHHtxs3_{n%FcNYXhCH8jmQmcWZ3HvWRT4M}=4hBs8 zNgDSkP_ZwpVacMM5YFONd`fJc@(-~>qBBb-pN~J3 zLMyTR6+JAIIrx5rLA$wdlK!nzUnW{0V+F>VYNf^3faD z%xP~$rq%Wnt+?6VO1A;gwGgIj-|nC~JA7Tf7wxZxDY_~EI{_B0ThGIyb^EpfpE}qt z?{v_e-M()9TKn4N-|pkl`boFV0JcHLdjdtUjmGu7PdixUC!H7|^G4Fxsp8sv2KdfT z8rsZU)!@^9blZsz6||qejJ~hLmZvZj#9JlCq%hQBH|Tf|%ykK6N z7oNTy9y`P3h0vz0166}$2MhN2$fsU|3pNX$fU$Z zhDaPhrW3$LyLTPx_B}LboxQEq0XTOp-bkKwr`Dgr6>?+}ZzT+E+CjJfT`*`581#}o zi`x@^j8L{bMcF!iYl^b%b~Qu+BXsFaP@V1GE??2WdzVq=!DjbhzxP#p=GjiWX2j~+ zWk+F3{qyGZ5ett@8~CrpN5SvE5?AZHd|!&4@a)!C@EiDj&7TUhvlrg`0Y-+CAa2OH z+d^lt{8Q-OhZwNwqFOa_t_!x+%kj$28gUw!`c>P)ddJg zL?6|lYZ<=ABj7V|tE^N_w-dbVFIuVQDujZZnM)HBhS?+l6f_h!7c`jq3*h9?P3AY~ zno(I^)6&$0*bytYz>TDb;kZT8(j+#dk1Mes2tUdxDJ1$J=SfX9s@;K*D*5MIl*%zjfw=Bq)HYz0^Ir}7F^^{KBdc}o~b85H4Uo*|tmOu>anUJ*VmWX&=blg0}z4vC^KxXByC zTRTXQ1|-awRpdF71{5Kw4^U5DTb@Eac@2FFl}dz~Iu0YruOKr}-S%b!GR$_(=N^!m zrQ2!^oNB)k%S6^f=q(+Lq;SS72cTomWq`v;?an0W>%=R4w=6SBI%<^^#N=&bII7t zFcDAm*+Un^G^r#FFGSLF!ruIn%(6r)cNBsblKv=!@{OJukioqXR3AVQ4JNVofy7@y zCj_@pk6dU?x9lFnyH?942?dG@5t|Njb{1l<>!#mt=OcE>&F^#YeHBE#4@s>s3%!;k zu?Lc-)Y6#T#p3!F_5dZ%ScXmN{iMx2nNtOH=(nzK*frZ;{RIni=Qm{bCu5DuW*KjtRv8q+1@nG3r=dq? z+(j+N?B%0Xpy`)W?U1|-2HRcqjyu5hw$-xcHg4%zy1U(8HF`9HXR1TzWY&<~u*1#< znk0%vrK3Ja&79FYxTV}`PE&`Z?&SBKkk*0DzL9N^#u2wZEwt)#QycsCbi|H>$Mv`1 zMVZb&t~lq*be?Td=6RyOK6Kt45^*=KJSYyzdPHYDG-ud1qoVr8-}~^Z_sgYH2M~A! zWEA8AkV{0oS$C`a|GfpkBx56Qhj4hU$Jw%MTzZ!OG9I`T$wi%TVKq ze%uR=Zq1dN8BcUsA91#fr5O4x>4O{4M5+u!UF}P`%*unHw-5%WgR@6zs4wXQV+^GO z*ka}iLrUz01o4#W1=0Rq^?~%8zU+r<5t63lm*g_*ztXC&@9zEU=YNn*))Uuk^y?yt zX^-ibr9E?T?AJ={PGP^^_=BHb%xloMgwj0M*Y_6Gql)V2BfTWL4x?mjEV1@t7C691 z(E32HHpR?+y~)@=5{(zt-GuuUy=mLF)z(~0OJ)C_>&tu5(7hK)G&2@0x4@-6!5i6n zX8c8alZ5a@2$h;{#(O2!ahx~a0Jmbmt#rbcqJ`=W$4N!_B73Wj%`bqHuyi$0%xEzA${wZOocrgwN*NRQI zeHiBnvj5&9Ec!VOn4P8HKqrL0Y>1SxKNs{OyRZ*5B ziX0AUn5KDm?RQYjcTqM#@&5<)K4XgV4wK}j>jLdjeoZGs-e}FV)^G5hZw7x~ZHkUV z2OH@iY3WWic^l|&cR)zha74b(io$EqEt7_AgcS5Jvhj%Z(^j~OEBDUJINOl^H#Hle zBT8jAMRdR|gl7jE*!R=w0vPIUh_e5Lw|TSo_vkbIZr|oj6!(hV%9#VjTozDvN};{k zuAp}vi=Ex5xtNad4jW5fA9mod4Yk@ep;529*yJ4Lm6%_#8X2A(doujB@p9k}nR>F+c+)J6t0-bv7r?WI+s?$2nP{d`N`ef3x}A8Nt+)T0~AeJsNh3m z$Z`d4>gd;XU-RnMkSfC4sq07Wx!wVh0%fP^2<9x}jab8i= z)AiQ+T)=+nNrC4$@_Ak9v6lI(Xvved$)TBhEKk}lz?5ru}iR4IX zx}j`*uohz}Ak~)Lap)sI1Yg0Slgye3U*c2Up z;x$pb%U^eWU?7^>UYVF)?8lTb6bVh+%};tw_Rw@s?X-L>Z!;u9^E+l zOK54+EqW2|#_0=JAcGRSS7B4{yA{5aYS=9|8dykBh;pKs4DbSEfL;)xxU3oX2)`*a zdG;xb4D9ChLo?$&L=U98?d}~vbe_FlIAZwOkqY`^U zPD|Zz?qt|A=VezHNE>LecKZsMAO0iC7|(RoV`HwD-e-~+x`-*#kTo|>t ziOveccZb;`Ypg2M7C8${xLaPNGMw==VB-L=nUE3W=HxJ zjExeHmq*d^Y@Q7xD!X%aXQy2i)L4z2&8c`|ClkLB2`|0COH*`wJ%0~2())VBm@Tr_ zrs{$dOnE{)S?rV1P9^qyg4`KZUVRib_4=x#&4=E*macl`7?hu^3bMBwiT|g(p(Ziy za6e2?u#`_GvLZ|d_EvEBfu}^Lc3h$nxZQdW8AyGwSDs;`FT+IzhEB$|D>frp|MiKb z-t;RpZA!&8o?gnE#oX`IB>Q#cnzK|m+yd@Ip5&*1{4YhjyB7ce diff --git a/test-devices/composite-stm32/lib/tinyusb/class/audio/audio.h b/test-devices/composite-stm32/lib/tinyusb/class/audio/audio.h index 6f9c1a6b..70d43128 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/audio/audio.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/audio/audio.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -721,11 +721,13 @@ typedef struct TU_ATTR_PACKED uint8_t bLength ; ///< Size of this descriptor, in bytes: 17. uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL. + uint8_t bTerminalID ; ///< Constant uniquely identifying the Terminal within the audio function. This value is used in all requests to address this terminal. uint16_t wTerminalType ; ///< Constant characterizing the type of Terminal. See: audio_terminal_type_t for USB streaming and audio_terminal_input_type_t for other input types. uint8_t bAssocTerminal ; ///< ID of the Output Terminal to which this Input Terminal is associated. uint8_t bCSourceID ; ///< ID of the Clock Entity to which this Input Terminal is connected. uint8_t bNrChannels ; ///< Number of logical output channels in the Terminal’s output audio channel cluster. uint32_t bmChannelConfig ; ///< Describes the spatial location of the logical channels. See:audio_channel_config_t. + uint8_t iChannelNames ; ///< Index of a string descriptor, describing the name of the first logical channel. uint16_t bmControls ; ///< See: audio_terminal_input_control_pos_t. uint8_t iTerminal ; ///< Index of a string descriptor, describing the Input Terminal. } audio_desc_input_terminal_t; @@ -822,10 +824,10 @@ typedef struct TU_ATTR_PACKED uint8_t type : 2; ///< Request type tusb_request_type_t. uint8_t direction : 1; ///< Direction type. tusb_dir_t } bmRequestType_bit; - + uint8_t bmRequestType; }; - + uint8_t bRequest; ///< Request type audio_cs_req_t uint8_t bChannelNumber; uint8_t bControlSelector; diff --git a/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.c b/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.c index a021755b..f487fe60 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2020 Reinhard Panhuber, Jerzy Kasenberg @@ -66,51 +66,41 @@ // Use ring buffer if it's available, some MCUs need extra RAM requirements #ifndef TUD_AUDIO_PREFER_RING_BUFFER -#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT -#define TUD_AUDIO_PREFER_RING_BUFFER 0 -#else -#define TUD_AUDIO_PREFER_RING_BUFFER 1 -#endif + #if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT + #define TUD_AUDIO_PREFER_RING_BUFFER 0 + #else + #define TUD_AUDIO_PREFER_RING_BUFFER 1 + #endif #endif // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer // is available or driver is would need to be changed dramatically -// Only STM32 synopsys and dcd_transdimension use non-linear buffer for now -// Synopsys detection copied from dcd_synopsys.c (refactor later on) -#if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \ - defined (STM32F107xB) || defined (STM32F107xC) -#define STM32F1_SYNOPSYS -#endif - -#if defined (STM32L475xx) || defined (STM32L476xx) || \ - defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \ - defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || \ - defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx) -#define STM32L4_SYNOPSYS -#endif - -#if (CFG_TUSB_MCU == OPT_MCU_STM32F1 && defined(STM32F1_SYNOPSYS)) || \ - CFG_TUSB_MCU == OPT_MCU_STM32F2 || \ - CFG_TUSB_MCU == OPT_MCU_STM32F4 || \ - CFG_TUSB_MCU == OPT_MCU_STM32F7 || \ - CFG_TUSB_MCU == OPT_MCU_STM32H7 || \ - (CFG_TUSB_MCU == OPT_MCU_STM32L4 && defined(STM32L4_SYNOPSYS)) || \ - CFG_TUSB_MCU == OPT_MCU_RX63X || \ - CFG_TUSB_MCU == OPT_MCU_RX65X || \ - CFG_TUSB_MCU == OPT_MCU_RX72N || \ - CFG_TUSB_MCU == OPT_MCU_GD32VF103 || \ - CFG_TUSB_MCU == OPT_MCU_LPC18XX || \ - CFG_TUSB_MCU == OPT_MCU_LPC43XX || \ - CFG_TUSB_MCU == OPT_MCU_MIMXRT || \ +// Only STM32 and dcd_transdimension use non-linear buffer for now +// dwc2 except esp32sx (since it may use dcd_esp32sx) +#if (defined(TUP_USBIP_DWC2) && !TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)) || \ + defined(TUP_USBIP_FSDEV) || \ + CFG_TUSB_MCU == OPT_MCU_RX63X || \ + CFG_TUSB_MCU == OPT_MCU_RX65X || \ + CFG_TUSB_MCU == OPT_MCU_RX72N || \ + CFG_TUSB_MCU == OPT_MCU_LPC18XX || \ + CFG_TUSB_MCU == OPT_MCU_LPC43XX || \ + CFG_TUSB_MCU == OPT_MCU_MIMXRT || \ CFG_TUSB_MCU == OPT_MCU_MSP432E4 -#if TUD_AUDIO_PREFER_RING_BUFFER -#define USE_LINEAR_BUFFER 0 + #if TUD_AUDIO_PREFER_RING_BUFFER + #define USE_LINEAR_BUFFER 0 + #else + #define USE_LINEAR_BUFFER 1 + #endif #else -#define USE_LINEAR_BUFFER 1 + #define USE_LINEAR_BUFFER 1 #endif + +// Temporarily put the check here for stm32_fsdev +#ifdef TUP_USBIP_FSDEV + #define USE_ISO_EP_ALLOCATION 1 #else -#define USE_LINEAR_BUFFER 1 + #define USE_ISO_EP_ALLOCATION 0 #endif // Declaration of buffers @@ -122,143 +112,159 @@ // EP IN software buffers and mutexes #if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING -#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO -#endif -#endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO -#endif -#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO -#endif -#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 + #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO + #endif + #endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 + + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO + #endif + #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 + + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO + #endif + #endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 #endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING // Linear buffer TX in case: // - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR // - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into #if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) -#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX]; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX]; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX]; -#endif + #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX]; + #endif + + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX]; + #endif + + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX]; + #endif #endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) // EP OUT software buffers and mutexes #if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING -#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO -#endif -#endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO -#endif -#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO -#endif -#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 + #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO + #endif + #endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 + + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO + #endif + #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 + + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO + #endif + #endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING // Linear buffer RX in case: // - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR // - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into #if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) -#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX]; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX]; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX]; -#endif + #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX]; + #endif + + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX]; + #endif + + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX]; + #endif #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) // Control buffers CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ]; + #if CFG_TUD_AUDIO > 1 CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ]; #endif + #if CFG_TUD_AUDIO > 2 CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ]; #endif // Active alternate setting of interfaces uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT]; + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT]; #endif + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; #endif // Software encoding/decoding support FIFOs #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING -#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ]; -tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO -#endif -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ]; -tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO -#endif -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ]; -tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO -#endif -#endif + #if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ]; + tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO + #endif + #endif + + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ]; + tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO + #endif + #endif + + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ]; + tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO + #endif + #endif #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING -#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ]; -tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO -#endif -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ]; -tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO -#endif -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ]; -tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO -#endif -#endif + #if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ]; + tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO + #endif + #endif + + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ]; + tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO + #endif + #endif + + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ]; + tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO + #endif + #endif #endif typedef struct @@ -306,7 +312,7 @@ typedef struct #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP struct { - uint32_t value; // Feedback value for asynchronous mode (in 16.16 format). + CFG_TUSB_MEM_ALIGN uint32_t value; // Feedback value for asynchronous mode (in 16.16 format). uint32_t min_value; // min value according to UAC2 FMT-2.0 section 2.3.1.1. uint32_t max_value; // max value according to UAC2 FMT-2.0 section 2.3.1.1. @@ -341,7 +347,7 @@ typedef struct // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74) #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE]; + CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE]; #endif // Decoding parameters - parameters are set when alternate AS interface is set by host @@ -447,6 +453,10 @@ static inline uint8_t tu_desc_subtype(void const* desc) } #endif +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq); +#endif + bool tud_audio_n_mounted(uint8_t func_id) { TU_VERIFY(func_id < CFG_TUD_AUDIO); @@ -819,10 +829,7 @@ uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint1 // We write directly into the EP's buffer - abort if previous transfer not complete TU_VERIFY(!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr)); - // Check length - TU_VERIFY(len <= CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE); - - memcpy(_audiod_fct[func_id].ep_int_ctr_buf, buffer, len); + TU_VERIFY(tu_memcpy_s(_audiod_fct[func_id].ep_int_ctr_buf, CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE, buffer, len)==0); // Schedule transmit TU_VERIFY(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr, _audiod_fct[func_id].ep_int_ctr_buf, len)); @@ -1470,6 +1477,83 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin #endif } +#if USE_ISO_EP_ALLOCATION + #if CFG_TUD_AUDIO_ENABLE_EP_IN + uint8_t ep_in = 0; + uint16_t ep_in_size = 0; + #endif + + #if CFG_TUD_AUDIO_ENABLE_EP_OUT + uint8_t ep_out = 0; + uint16_t ep_out_size = 0; + #endif + + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + uint8_t ep_fb = 0; + #endif + + uint8_t const *p_desc = _audiod_fct[i].p_desc; + uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; + while (p_desc < p_desc_end) + { + if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) + { + tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; + if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) + { + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + // Explicit feedback EP + if (desc_ep->bmAttributes.usage == 1) + { + ep_fb = desc_ep->bEndpointAddress; + } + #endif + // Data EP + if (desc_ep->bmAttributes.usage == 0) + { + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) + { + #if CFG_TUD_AUDIO_ENABLE_EP_IN + ep_in = desc_ep->bEndpointAddress; + ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size); + #endif + } else + { + #if CFG_TUD_AUDIO_ENABLE_EP_OUT + ep_out = desc_ep->bEndpointAddress; + ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size); + #endif + } + } + + } + } + p_desc = tu_desc_next(p_desc); + } + + #if CFG_TUD_AUDIO_ENABLE_EP_IN + if (ep_in) + { + usbd_edpt_iso_alloc(rhport, ep_in, ep_in_size); + } + #endif + + #if CFG_TUD_AUDIO_ENABLE_EP_OUT + if (ep_out) + { + usbd_edpt_iso_alloc(rhport, ep_out, ep_out_size); + } + #endif + + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + if (ep_fb) + { + usbd_edpt_iso_alloc(rhport, ep_fb, 4); + } + #endif + +#endif // USE_ISO_EP_ALLOCATION + break; } } @@ -1531,17 +1615,19 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * if (audio->ep_in_as_intf_num == itf) { audio->ep_in_as_intf_num = 0; + #if !USE_ISO_EP_ALLOCATION usbd_edpt_close(rhport, audio->ep_in); + #endif // Clear FIFOs, since data is no longer valid -#if !CFG_TUD_AUDIO_ENABLE_ENCODING + #if !CFG_TUD_AUDIO_ENABLE_ENCODING tu_fifo_clear(&audio->ep_in_ff); -#else + #else for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) { tu_fifo_clear(&audio->tx_supp_ff[cnt]); } -#endif + #endif // Invoke callback - can be used to stop data sampling if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); @@ -1549,23 +1635,25 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * audio->ep_in = 0; // Necessary? } -#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN #if CFG_TUD_AUDIO_ENABLE_EP_OUT if (audio->ep_out_as_intf_num == itf) { audio->ep_out_as_intf_num = 0; + #if !USE_ISO_EP_ALLOCATION usbd_edpt_close(rhport, audio->ep_out); + #endif // Clear FIFOs, since data is no longer valid -#if !CFG_TUD_AUDIO_ENABLE_DECODING + #if !CFG_TUD_AUDIO_ENABLE_DECODING tu_fifo_clear(&audio->ep_out_ff); -#else + #else for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) { tu_fifo_clear(&audio->rx_supp_ff[cnt]); } -#endif + #endif // Invoke callback - can be used to stop data sampling if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); @@ -1573,13 +1661,15 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * audio->ep_out = 0; // Necessary? // Close corresponding feedback EP -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + #if !USE_ISO_EP_ALLOCATION usbd_edpt_close(rhport, audio->ep_fb); + #endif audio->ep_fb = 0; tu_memclr(&audio->feedback, sizeof(audio->feedback)); -#endif + #endif } -#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT // Save current alternative interface setting audio->alt_setting[idxItf] = alt; @@ -1604,8 +1694,11 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) { tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc; +#if USE_ISO_EP_ALLOCATION + TU_ASSERT(usbd_edpt_iso_activate(rhport, desc_ep)); +#else TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); - +#endif uint8_t const ep_addr = desc_ep->bEndpointAddress; //TODO: We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND! @@ -1620,11 +1713,11 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * audio->ep_in_sz = tu_edpt_packet_size(desc_ep); // If software encoding is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters -#if CFG_TUD_AUDIO_ENABLE_ENCODING + #if CFG_TUD_AUDIO_ENABLE_ENCODING audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf); // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / audio->n_bytes_per_sampe_tx) * audio->n_bytes_per_sampe_tx); for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) { @@ -1632,9 +1725,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * } audio->n_ff_used_tx = audio->n_channels_tx / audio->n_channels_per_ff_tx; TU_ASSERT( audio->n_ff_used_tx <= audio->n_tx_supp_ff ); -#endif - -#endif + #endif + #endif // Schedule first transmit if alternate interface is not zero i.e. streaming is disabled - in case no sample data is available a ZLP is loaded // It is necessary to trigger this here since the refill is done with an RX FIFO empty interrupt which can only trigger if something was in there @@ -1651,11 +1743,11 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * audio->ep_out_as_intf_num = itf; audio->ep_out_sz = tu_edpt_packet_size(desc_ep); -#if CFG_TUD_AUDIO_ENABLE_DECODING + #if CFG_TUD_AUDIO_ENABLE_DECODING audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf); // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sampe_rx) * audio->n_bytes_per_sampe_rx; for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) { @@ -1663,18 +1755,18 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * } audio->n_ff_used_rx = audio->n_channels_rx / audio->n_channels_per_ff_rx; TU_ASSERT( audio->n_ff_used_rx <= audio->n_rx_supp_ff ); -#endif -#endif + #endif + #endif // Prepare for incoming data -#if USE_LINEAR_BUFFER_RX + #if USE_LINEAR_BUFFER_RX TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); -#else + #else TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false); -#endif + #endif } -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 1) // Check if usage is explicit data feedback { audio->ep_fb = ep_addr; @@ -1683,7 +1775,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // Enable SOF interrupt if callback is implemented if (tud_audio_feedback_interval_isr) usbd_sof_enable(rhport, true); } -#endif + #endif #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT foundEPs += 1; @@ -1734,7 +1826,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * default: break; } } -#endif +#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP // We are done - abort loop break; @@ -2032,7 +2124,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 { if (tud_audio_fb_done_cb) tud_audio_fb_done_cb(func_id); - // Schedule a transmit with the new value if EP is not busy + // Schedule a transmit with the new value if EP is not busy if (!usbd_edpt_busy(rhport, audio->ep_fb)) { // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent @@ -2198,7 +2290,7 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req if (len > _audiod_fct[func_id].ctrl_buf_sz) len = _audiod_fct[func_id].ctrl_buf_sz; // Copy into buffer - memcpy((void *)_audiod_fct[func_id].ctrl_buf, data, (size_t)len); + TU_VERIFY(0 == tu_memcpy_s(_audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz, data, (size_t)len)); // Schedule transmit return tud_control_xfer(rhport, p_request, (void*)_audiod_fct[func_id].ctrl_buf, len); diff --git a/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.h b/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.h index 0ef100fa..7c88b99f 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2020 Ha Thach (tinyusb.org) @@ -473,7 +473,7 @@ TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id); // the choice of format is left to the caller and feedback argument is sent as-is. If CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION is set, then tinyusb // expects 16.16 format and handles the conversion to 10.14 on FS. // -// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 devices. On Linux and macOS it seems the +// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 devices. On Linux and macOS it seems the // driver can work with either format. So a good compromise is to keep format correction disabled and stick to 16.16 format. // Feedback value can be determined from within the SOF ISR of the audio driver. This should reduce jitter. If the feature is used, the user can not set the feedback value. diff --git a/test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.h b/test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.h index 1b90d091..921bd7a1 100755 --- a/test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2020 Jerzy Kasenberg diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc.h b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc.h index e345139e..4658e43a 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc.h @@ -41,16 +41,6 @@ /** \defgroup ClassDriver_CDC_Common Common Definitions * @{ */ -// TODO remove -/// CDC Pipe ID, used to indicate which pipe the API is addressing to (Notification, Out, In) -typedef enum -{ - CDC_PIPE_NOTIFICATION , ///< Notification pipe - CDC_PIPE_DATA_IN , ///< Data in pipe - CDC_PIPE_DATA_OUT , ///< Data out pipe - CDC_PIPE_ERROR , ///< Invalid Pipe ID -}cdc_pipeid_t; - //--------------------------------------------------------------------+ // CDC Communication Interface Class //--------------------------------------------------------------------+ @@ -192,8 +182,30 @@ typedef enum CDC_REQUEST_MDLM_SEMANTIC_MODEL = 0x60, }cdc_management_request_t; +enum +{ + CDC_CONTROL_LINE_STATE_DTR = 0x01, + CDC_CONTROL_LINE_STATE_RTS = 0x02, +}; + +enum +{ + CDC_LINE_CONDING_STOP_BITS_1 = 0, // 1 bit + CDC_LINE_CONDING_STOP_BITS_1_5 = 1, // 1.5 bits + CDC_LINE_CONDING_STOP_BITS_2 = 2, // 2 bits +}; + +enum +{ + CDC_LINE_CODING_PARITY_NONE = 0, + CDC_LINE_CODING_PARITY_ODD = 1, + CDC_LINE_CODING_PARITY_EVEN = 2, + CDC_LINE_CODING_PARITY_MARK = 3, + CDC_LINE_CODING_PARITY_SPACE = 4, +}; + //--------------------------------------------------------------------+ -// Management Elemenent Notification (Notification Endpoint) +// Management Element Notification (Notification Endpoint) //--------------------------------------------------------------------+ /// 6.3 Notification Codes @@ -365,7 +377,9 @@ typedef struct TU_ATTR_PACKED uint32_t incoming_distinctive : 1; ///< 0 : Reports only incoming ringing. 1 : Reports incoming distinctive ringing patterns. uint32_t dual_tone_multi_freq : 1; ///< 0 : Cannot report dual tone multi-frequency (DTMF) digits input remotely over the telephone line. 1 : Can report DTMF digits input remotely over the telephone line. uint32_t line_state_change : 1; ///< 0 : Does not support line state change notification. 1 : Does support line state change notification - uint32_t TU_RESERVED : 26; + uint32_t TU_RESERVED0 : 2; + uint32_t TU_RESERVED1 : 16; + uint32_t TU_RESERVED2 : 8; } bmCapabilities; }cdc_desc_func_telephone_call_state_reporting_capabilities_t; @@ -390,9 +404,10 @@ TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct"); typedef struct TU_ATTR_PACKED { - uint16_t dte_is_present : 1; ///< Indicates to DCE if DTE is presentor not. This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR. - uint16_t half_duplex_carrier_control : 1; - uint16_t : 14; + uint16_t dtr : 1; + uint16_t rts : 1; + uint16_t : 6; + uint16_t : 8; } cdc_line_control_state_t; TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct"); diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.c b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.c index fab6f003..5adce521 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -53,7 +53,7 @@ typedef struct /*------------- From this point, data is not cleared by bus reset -------------*/ char wanted_char; - cdc_line_coding_t line_coding; + TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // FIFO tu_fifo_t rx_ff; @@ -62,10 +62,8 @@ typedef struct uint8_t rx_ff_buf[CFG_TUD_CDC_RX_BUFSIZE]; uint8_t tx_ff_buf[CFG_TUD_CDC_TX_BUFSIZE]; -#if CFG_FIFO_MUTEX - osal_mutex_def_t rx_ff_mutex; - osal_mutex_def_t tx_ff_mutex; -#endif + OSAL_MUTEX_DEF(rx_ff_mutex); + OSAL_MUTEX_DEF(tx_ff_mutex); // Endpoint Transfer buffer CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EP_BUFSIZE]; @@ -78,7 +76,7 @@ typedef struct //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; +CFG_TUSB_MEM_SECTION tu_static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; static bool _prep_out_transaction (cdcd_interface_t* p_cdc) { @@ -171,7 +169,8 @@ uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) bufsize); // flush if queue more than packet size - if ( tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE ) + // may need to suppress -Wunreachable-code since most of the time CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE + if ( (tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE) || ((CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE) && tu_fifo_full(&p_cdc->tx_ff)) ) { tud_cdc_n_write_flush(itf); } @@ -247,10 +246,8 @@ void cdcd_init(void) // In this way, the most current data is prioritized. tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, true); -#if CFG_FIFO_MUTEX tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, osal_mutex_create(&p_cdc->rx_ff_mutex)); tu_fifo_config_mutex(&p_cdc->tx_ff, osal_mutex_create(&p_cdc->tx_ff_mutex), NULL); -#endif } } @@ -389,7 +386,7 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t bool const rts = tu_bit_test(request->wValue, 1); p_cdc->line_state = (uint8_t) request->wValue; - + // Disable fifo overwriting if DTR bit is set tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr); @@ -435,8 +432,8 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // Received new data if ( ep_addr == p_cdc->ep_out ) { - tu_fifo_write_n(&p_cdc->rx_ff, &p_cdc->epout_buf, (uint16_t) xferred_bytes); - + tu_fifo_write_n(&p_cdc->rx_ff, p_cdc->epout_buf, (uint16_t) xferred_bytes); + // Check for wanted char and invoke callback if needed if ( tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1) ) { @@ -448,14 +445,14 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ } } } - + // invoke receive callback (if there is still data) if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf); - + // prepare for OUT transaction _prep_out_transaction(p_cdc); } - + // Data sent to host, we continue to fetch from tx fifo to send. // Note: This will cause incorrect baudrate set in line coding. // Though maybe the baudrate is not really important !!! diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.h b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.h index fbc7162a..a6e07aa5 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -27,7 +27,6 @@ #ifndef _TUSB_CDC_DEVICE_H_ #define _TUSB_CDC_DEVICE_H_ -#include "common/tusb_common.h" #include "cdc.h" //--------------------------------------------------------------------+ @@ -81,7 +80,7 @@ int32_t tud_cdc_n_read_char (uint8_t itf); // Clear the received FIFO void tud_cdc_n_read_flush (uint8_t itf); -// Get a byte from FIFO at the specified position without removing it +// Get a byte from FIFO without removing it bool tud_cdc_n_peek (uint8_t itf, uint8_t* ui8); // Write bytes to TX FIFO, data may remain in the FIFO for a while @@ -135,7 +134,7 @@ TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf); // Invoked when received `wanted_char` TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char); -// Invoked when space becomes available in TX buffer +// Invoked when a TX is complete and therefore space becomes available in TX buffer TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf); // Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.c b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.c index ee824cb4..fe3691bf 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -33,154 +33,698 @@ #include "cdc_host.h" +// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message +#define CDCH_DEBUG 2 + +#define TU_LOG_CDCH(...) TU_LOG(CDCH_DEBUG, __VA_ARGS__) + //--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF +// Host CDC Interface //--------------------------------------------------------------------+ + typedef struct { - uint8_t itf_num; - uint8_t itf_protocol; + uint8_t daddr; + uint8_t bInterfaceNumber; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t serial_drid; // Serial Driver ID + cdc_acm_capability_t acm_capability; uint8_t ep_notif; - uint8_t ep_in; - uint8_t ep_out; - cdc_acm_capability_t acm_capability; + uint8_t line_state; // DTR (bit0), RTS (bit1) + TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width + + tuh_xfer_cb_t user_control_cb; + + struct { + tu_edpt_stream_t tx; + tu_edpt_stream_t rx; + + uint8_t tx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; + CFG_TUH_MEM_ALIGN uint8_t tx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; + + uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; + CFG_TUH_MEM_ALIGN uint8_t rx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; + } stream; + +} cdch_interface_t; + +CFG_TUH_MEM_SECTION +static cdch_interface_t cdch_data[CFG_TUH_CDC]; + +//--------------------------------------------------------------------+ +// Serial Driver +//--------------------------------------------------------------------+ + +//------------- ACM prototypes -------------// +static void acm_process_config(tuh_xfer_t* xfer); + +static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + +//------------- FTDI prototypes -------------// +#if CFG_TUH_CDC_FTDI +#include "serial/ftdi_sio.h" + +static uint16_t const ftdi_pids[] = { TU_FTDI_PID_LIST }; +enum { + FTDI_PID_COUNT = sizeof(ftdi_pids) / sizeof(ftdi_pids[0]) +}; + +// Store last request baudrate since divisor to baudrate is not easy +static uint32_t _ftdi_requested_baud; + +static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); +static void ftdi_process_config(tuh_xfer_t* xfer); + +static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +#endif + +//------------- CP210X prototypes -------------// +#if CFG_TUH_CDC_CP210X +#include "serial/cp210x.h" + +static uint16_t const cp210x_pids[] = { TU_CP210X_PID_LIST }; +enum { + CP210X_PID_COUNT = sizeof(cp210x_pids) / sizeof(cp210x_pids[0]) +}; -} cdch_data_t; +static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); +static void cp210x_process_config(tuh_xfer_t* xfer); + +static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +#endif + +enum { + SERIAL_DRIVER_ACM = 0, + +#if CFG_TUH_CDC_FTDI + SERIAL_DRIVER_FTDI, +#endif + +#if CFG_TUH_CDC_CP210X + SERIAL_DRIVER_CP210X, +#endif +}; + +typedef struct { + void (*const process_set_config)(tuh_xfer_t* xfer); + bool (*const set_control_line_state)(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_baudrate)(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +} cdch_serial_driver_t; + +// Note driver list must be in the same order as SERIAL_DRIVER enum +static const cdch_serial_driver_t serial_drivers[] = { + { .process_set_config = acm_process_config, + .set_control_line_state = acm_set_control_line_state, + .set_baudrate = acm_set_baudrate + }, + + #if CFG_TUH_CDC_FTDI + { .process_set_config = ftdi_process_config, + .set_control_line_state = ftdi_sio_set_modem_ctrl, + .set_baudrate = ftdi_sio_set_baudrate + }, + #endif + + #if CFG_TUH_CDC_CP210X + { .process_set_config = cp210x_process_config, + .set_control_line_state = cp210x_set_modem_ctrl, + .set_baudrate = cp210x_set_baudrate + }, + #endif +}; + +enum { + SERIAL_DRIVER_COUNT = sizeof(serial_drivers) / sizeof(serial_drivers[0]) +}; //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -static cdch_data_t cdch_data[CFG_TUH_DEVICE_MAX]; -static inline cdch_data_t* get_itf(uint8_t dev_addr) +static inline cdch_interface_t* get_itf(uint8_t idx) { - return &cdch_data[dev_addr-1]; + TU_ASSERT(idx < CFG_TUH_CDC, NULL); + cdch_interface_t* p_cdc = &cdch_data[idx]; + + return (p_cdc->daddr != 0) ? p_cdc : NULL; } -bool tuh_cdc_mounted(uint8_t dev_addr) +static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) { - cdch_data_t* cdc = get_itf(dev_addr); - return cdc->ep_in && cdc->ep_out; + for(uint8_t i=0; idaddr == daddr) && + (ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr)) + { + return i; + } + } + + return TUSB_INDEX_INVALID_8; } -bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid) + +static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const *itf_desc) { - if ( !tuh_cdc_mounted(dev_addr) ) return false; + for(uint8_t i=0; idaddr = daddr; + p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber; + p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; + p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol; + p_cdc->line_state = 0; + return p_cdc; + } + } - switch (pipeid) - { - case CDC_PIPE_NOTIFICATION: - return usbh_edpt_busy(dev_addr, p_cdc->ep_notif ); + return NULL; +} - case CDC_PIPE_DATA_IN: - return usbh_edpt_busy(dev_addr, p_cdc->ep_in ); +static bool open_ep_stream_pair(cdch_interface_t* p_cdc , tusb_desc_endpoint_t const *desc_ep); +static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num); +static void cdch_internal_control_complete(tuh_xfer_t* xfer); - case CDC_PIPE_DATA_OUT: - return usbh_edpt_busy(dev_addr, p_cdc->ep_out ); +//--------------------------------------------------------------------+ +// APPLICATION API +//--------------------------------------------------------------------+ - default: - return false; +uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num) +{ + for(uint8_t i=0; idaddr == daddr && p_cdc->bInterfaceNumber == itf_num) return i; } + + return TUSB_INDEX_INVALID_8; +} + +bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc && info); + + info->daddr = p_cdc->daddr; + + // re-construct descriptor + tusb_desc_interface_t* desc = &info->desc; + desc->bLength = sizeof(tusb_desc_interface_t); + desc->bDescriptorType = TUSB_DESC_INTERFACE; + + desc->bInterfaceNumber = p_cdc->bInterfaceNumber; + desc->bAlternateSetting = 0; + desc->bNumEndpoints = 2u + (p_cdc->ep_notif ? 1u : 0u); + desc->bInterfaceClass = TUSB_CLASS_CDC; + desc->bInterfaceSubClass = p_cdc->bInterfaceSubClass; + desc->bInterfaceProtocol = p_cdc->bInterfaceProtocol; + desc->iInterface = 0; // not used yet + + return true; +} + +bool tuh_cdc_mounted(uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + return p_cdc != NULL; +} + +bool tuh_cdc_get_dtr(uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR) ? true : false; +} + +bool tuh_cdc_get_rts(uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS) ? true : false; +} + +bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + *line_coding = p_cdc->line_coding; + + return true; } //--------------------------------------------------------------------+ -// APPLICATION API (parameter validation needed) +// Write //--------------------------------------------------------------------+ -bool tuh_cdc_serial_is_mounted(uint8_t dev_addr) + +uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) { - // TODO consider all AT Command as serial candidate - return tuh_cdc_mounted(dev_addr) && - (cdch_data[dev_addr-1].itf_protocol <= CDC_COMM_PROTOCOL_ATCOMMAND_CDMA); + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return tu_edpt_stream_write(&p_cdc->stream.tx, buffer, bufsize); } -bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify) +uint32_t tuh_cdc_write_flush(uint8_t idx) { - (void) is_notify; - TU_VERIFY( tuh_cdc_mounted(dev_addr) ); - TU_VERIFY( p_data != NULL && length); + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return tu_edpt_stream_write_xfer(&p_cdc->stream.tx); +} - uint8_t const ep_out = cdch_data[dev_addr-1].ep_out; - if ( usbh_edpt_busy(dev_addr, ep_out) ) return false; +bool tuh_cdc_write_clear(uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); - return usbh_edpt_xfer(dev_addr, ep_out, (void*)(uintptr_t) p_data, (uint16_t) length); + return tu_edpt_stream_clear(&p_cdc->stream.tx); } -bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify) +uint32_t tuh_cdc_write_available(uint8_t idx) { - (void) is_notify; - TU_VERIFY( tuh_cdc_mounted(dev_addr) ); - TU_VERIFY( p_buffer != NULL && length ); + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return tu_edpt_stream_write_available(&p_cdc->stream.tx); +} + +//--------------------------------------------------------------------+ +// Read +//--------------------------------------------------------------------+ - uint8_t const ep_in = cdch_data[dev_addr-1].ep_in; - if ( usbh_edpt_busy(dev_addr, ep_in) ) return false; +uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); - return usbh_edpt_xfer(dev_addr, ep_in, p_buffer, (uint16_t) length); + return tu_edpt_stream_read(&p_cdc->stream.rx, buffer, bufsize); } -bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb) +uint32_t tuh_cdc_read_available(uint8_t idx) { - cdch_data_t const * p_cdc = get_itf(dev_addr); + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); - tusb_control_request_t const request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, - .wValue = tu_htole16((uint16_t) ((dtr ? 1u : 0u) | (rts ? 2u : 0u))), - .wIndex = tu_htole16(p_cdc->itf_num), - .wLength = 0 - }; + return tu_edpt_stream_read_available(&p_cdc->stream.rx); +} + +bool tuh_cdc_peek(uint8_t idx, uint8_t* ch) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return tu_edpt_stream_peek(&p_cdc->stream.rx, ch); +} + +bool tuh_cdc_read_clear (uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); - tuh_xfer_t xfer = + bool ret = tu_edpt_stream_clear(&p_cdc->stream.rx); + tu_edpt_stream_read_xfer(&p_cdc->stream.rx); + return ret; +} + +//--------------------------------------------------------------------+ +// Control Endpoint API +//--------------------------------------------------------------------+ + +// internal control complete to update state such as line state, encoding +static void cdch_internal_control_complete(tuh_xfer_t* xfer) +{ + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t* p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); + + if (xfer->result == XFER_RESULT_SUCCESS) { - .daddr = dev_addr, - .ep_addr = 0, - .setup = &request, - .buffer = NULL, - .complete_cb = complete_cb, - .user_data = 0 - }; + switch (p_cdc->serial_drid) { + case SERIAL_DRIVER_ACM: + switch (xfer->setup->bRequest) { + case CDC_REQUEST_SET_CONTROL_LINE_STATE: + p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + break; - return tuh_control_xfer(&xfer); + case CDC_REQUEST_SET_LINE_CODING: { + uint16_t const len = tu_min16(sizeof(cdc_line_coding_t), tu_le16toh(xfer->setup->wLength)); + memcpy(&p_cdc->line_coding, xfer->buffer, len); + } + break; + + default: break; + } + break; + + #if CFG_TUH_CDC_FTDI + case SERIAL_DRIVER_FTDI: + switch (xfer->setup->bRequest) { + case FTDI_SIO_MODEM_CTRL: + p_cdc->line_state = (uint8_t) (tu_le16toh(xfer->setup->wValue) & 0x00ff); + break; + + case FTDI_SIO_SET_BAUD_RATE: + // convert from divisor to baudrate is not supported + p_cdc->line_coding.bit_rate = _ftdi_requested_baud; + break; + + default: break; + } + break; + #endif + + #if CFG_TUH_CDC_CP210X + case SERIAL_DRIVER_CP210X: + switch(xfer->setup->bRequest) { + case CP210X_SET_MHS: + p_cdc->line_state = (uint8_t) (tu_le16toh(xfer->setup->wValue) & 0x00ff); + break; + + case CP210X_SET_BAUDRATE: { + uint32_t baudrate; + memcpy(&baudrate, xfer->buffer, sizeof(uint32_t)); + p_cdc->line_coding.bit_rate = tu_le32toh(baudrate); + } + break; + } + break; + #endif + + default: break; + } + } + + xfer->complete_cb = p_cdc->user_control_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } +} + +bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + + if ( complete_cb ) { + return driver->set_control_line_state(p_cdc, line_state, complete_cb, user_data); + }else { + // blocking + xfer_result_t result = XFER_RESULT_INVALID; + bool ret = driver->set_control_line_state(p_cdc, line_state, complete_cb, (uintptr_t) &result); + + if (user_data) { + // user_data is not NULL, return result via user_data + *((xfer_result_t*) user_data) = result; + } + + TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); + + p_cdc->line_state = (uint8_t) line_state; + return true; + } +} + +bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + + if ( complete_cb ) { + return driver->set_baudrate(p_cdc, baudrate, complete_cb, user_data); + }else { + // blocking + xfer_result_t result = XFER_RESULT_INVALID; + bool ret = driver->set_baudrate(p_cdc, baudrate, complete_cb, (uintptr_t) &result); + + if (user_data) { + // user_data is not NULL, return result via user_data + *((xfer_result_t*) user_data) = result; + } + + TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); + + p_cdc->line_coding.bit_rate = baudrate; + return true; + } +} + +bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + cdch_interface_t* p_cdc = get_itf(idx); + // only ACM support this set line coding request + TU_VERIFY(p_cdc && p_cdc->serial_drid == SERIAL_DRIVER_ACM); + TU_VERIFY(p_cdc->acm_capability.support_line_request); + + if ( complete_cb ) { + return acm_set_line_coding(p_cdc, line_coding, complete_cb, user_data); + }else { + // blocking + xfer_result_t result = XFER_RESULT_INVALID; + bool ret = acm_set_line_coding(p_cdc, line_coding, complete_cb, (uintptr_t) &result); + + if (user_data) { + // user_data is not NULL, return result via user_data + *((xfer_result_t*) user_data) = result; + } + + TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); + + p_cdc->line_coding = *line_coding; + return true; + } } //--------------------------------------------------------------------+ -// USBH-CLASS DRIVER API +// CLASS-USBH API //--------------------------------------------------------------------+ + void cdch_init(void) { tu_memclr(cdch_data, sizeof(cdch_data)); + + for(size_t i=0; istream.tx, true, true, false, + p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, + p_cdc->stream.tx_ep_buf, CFG_TUH_CDC_TX_EPSIZE); + + tu_edpt_stream_init(&p_cdc->stream.rx, true, false, false, + p_cdc->stream.rx_ff_buf, CFG_TUH_CDC_RX_BUFSIZE, + p_cdc->stream.rx_ep_buf, CFG_TUH_CDC_RX_EPSIZE); + } } -bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) +void cdch_close(uint8_t daddr) +{ + for(uint8_t idx=0; idxdaddr == daddr) + { + // Invoke application callback + if (tuh_cdc_umount_cb) tuh_cdc_umount_cb(idx); + + //tu_memclr(p_cdc, sizeof(cdch_interface_t)); + p_cdc->daddr = 0; + p_cdc->bInterfaceNumber = 0; + tu_edpt_stream_close(&p_cdc->stream.tx); + tu_edpt_stream_close(&p_cdc->stream.rx); + } + } +} + +bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +{ + // TODO handle stall response, retry failed transfer ... + TU_ASSERT(event == XFER_RESULT_SUCCESS); + + uint8_t const idx = get_idx_by_ep_addr(daddr, ep_addr); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc); + + if ( ep_addr == p_cdc->stream.tx.ep_addr ) + { + // invoke tx complete callback to possibly refill tx fifo + if (tuh_cdc_tx_complete_cb) tuh_cdc_tx_complete_cb(idx); + + if ( 0 == tu_edpt_stream_write_xfer(&p_cdc->stream.tx) ) + { + // If there is no data left, a ZLP should be sent if: + // - xferred_bytes is multiple of EP Packet size and not zero + tu_edpt_stream_write_zlp_if_needed(&p_cdc->stream.tx, xferred_bytes); + } + } + else if ( ep_addr == p_cdc->stream.rx.ep_addr ) + { + tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); + + #if CFG_TUH_CDC_FTDI + // FTDI reserve 2 bytes for status + if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI) { + uint8_t status[2]; + tu_edpt_stream_read(&p_cdc->stream.rx, status, 2); + (void) status; // TODO handle status + } + #endif + + // invoke receive callback + if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(idx); + + // prepare for next transfer if needed + tu_edpt_stream_read_xfer(&p_cdc->stream.rx); + }else if ( ep_addr == p_cdc->ep_notif ) + { + // TODO handle notification endpoint + }else + { + TU_ASSERT(false); + } + + return true; +} + +//--------------------------------------------------------------------+ +// Enumeration +//--------------------------------------------------------------------+ + +static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); + +static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t const *desc_ep) +{ + for(size_t i=0; i<2; i++) + { + TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && + TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); + + TU_ASSERT(tuh_edpt_open(p_cdc->daddr, desc_ep)); + + if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) + { + tu_edpt_stream_open(&p_cdc->stream.rx, p_cdc->daddr, desc_ep); + }else + { + tu_edpt_stream_open(&p_cdc->stream.tx, p_cdc->daddr, desc_ep); + } + + desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(desc_ep); + } + + return true; +} + +bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { (void) rhport; - (void) max_len; // Only support ACM subclass - // Protocol 0xFF can be RNDIS device for windows XP - TU_VERIFY( TUSB_CLASS_CDC == itf_desc->bInterfaceClass && - CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass && - 0xFF != itf_desc->bInterfaceProtocol); + // Note: Protocol 0xFF can be RNDIS device + if ( TUSB_CLASS_CDC == itf_desc->bInterfaceClass && + CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) + { + return acm_open(daddr, itf_desc, max_len); + } + #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X + else if ( 0xff == itf_desc->bInterfaceClass ) + { + uint16_t vid, pid; + TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); + + #if CFG_TUH_CDC_FTDI + if (TU_FTDI_VID == vid) { + for (size_t i = 0; i < FTDI_PID_COUNT; i++) { + if (ftdi_pids[i] == pid) { + return ftdi_open(daddr, itf_desc, max_len); + } + } + } + #endif + + #if CFG_TUH_CDC_CP210X + if (TU_CP210X_VID == vid) { + for (size_t i = 0; i < CP210X_PID_COUNT; i++) { + if (cp210x_pids[i] == pid) { + return cp210x_open(daddr, itf_desc, max_len); + } + } + } + #endif + } + #endif + + return false; +} + +static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num) { + if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); + + // Prepare for incoming data + tu_edpt_stream_read_xfer(&p_cdc->stream.rx); + + // notify usbh that driver enumeration is complete + usbh_driver_set_config_complete(p_cdc->daddr, itf_num); +} + + +bool cdch_set_config(uint8_t daddr, uint8_t itf_num) +{ + tusb_control_request_t request; + request.wIndex = tu_htole16((uint16_t) itf_num); - cdch_data_t * p_cdc = get_itf(dev_addr); + // fake transfer to kick-off process + tuh_xfer_t xfer; + xfer.daddr = daddr; + xfer.result = XFER_RESULT_SUCCESS; + xfer.setup = &request; + xfer.user_data = 0; // initial state - p_cdc->itf_num = itf_desc->bInterfaceNumber; - p_cdc->itf_protocol = itf_desc->bInterfaceProtocol; + uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - //------------- Communication Interface -------------// - uint16_t drv_len = tu_desc_len(itf_desc); + serial_drivers[p_cdc->serial_drid].process_set_config(&xfer); + return true; +} + +//--------------------------------------------------------------------+ +// ACM +//--------------------------------------------------------------------+ + +enum { + CONFIG_ACM_SET_CONTROL_LINE_STATE = 0, + CONFIG_ACM_SET_LINE_CODING, + CONFIG_ACM_COMPLETE, +}; + +static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) +{ + uint8_t const * p_desc_end = ((uint8_t const*) itf_desc) + max_len; + + cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + TU_VERIFY(p_cdc); + + p_cdc->serial_drid = SERIAL_DRIVER_ACM; + + //------------- Control Interface -------------// uint8_t const * p_desc = tu_desc_next(itf_desc); // Communication Functional Descriptors - while( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) + while( (p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc)) ) { if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) ) { @@ -188,19 +732,18 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities; } - drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); } - if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + // Open notification endpoint of control interface if any + if (itf_desc->bNumEndpoints == 1) { - // notification endpoint + TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)); tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; - TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) ); + TU_ASSERT( tuh_edpt_open(daddr, desc_ep) ); p_cdc->ep_notif = desc_ep->bEndpointAddress; - drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); } @@ -209,52 +752,426 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) { // next to endpoint descriptor - drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); // data endpoints expected to be in pairs - for(uint32_t i=0; i<2; i++) - { - tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; - TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); + TU_ASSERT(open_ep_stream_pair(p_cdc, (tusb_desc_endpoint_t const *) p_desc)); + } + + return true; +} - TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); +static void acm_process_config(tuh_xfer_t* xfer) +{ + uintptr_t const state = xfer->user_data; + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); - if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) + switch(state) + { + case CONFIG_ACM_SET_CONTROL_LINE_STATE: + #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + if (p_cdc->acm_capability.support_line_request) { - p_cdc->ep_in = desc_ep->bEndpointAddress; - }else + TU_ASSERT(acm_set_control_line_state(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, acm_process_config, + CONFIG_ACM_SET_LINE_CODING), ); + break; + } + #endif + TU_ATTR_FALLTHROUGH; + + case CONFIG_ACM_SET_LINE_CODING: + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + if (p_cdc->acm_capability.support_line_request) { - p_cdc->ep_out = desc_ep->bEndpointAddress; + cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT(acm_set_line_coding(p_cdc, &line_coding, acm_process_config, CONFIG_ACM_COMPLETE), ); + break; } + #endif + TU_ATTR_FALLTHROUGH; - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next( p_desc ); - } + case CONFIG_ACM_COMPLETE: + // itf_num+1 to account for data interface as well + set_config_complete(p_cdc, idx, itf_num+1); + break; + + default: break; } +} + +static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_VERIFY(p_cdc->acm_capability.support_line_request); + TU_LOG_CDCH("CDC ACM Set Control Line State\r\n"); + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, + .wValue = tu_htole16(line_state), + .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), + .wLength = 0 + }; + + p_cdc->user_control_cb = complete_cb; + + tuh_xfer_t xfer = { + .daddr = p_cdc->daddr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call + .user_data = user_data + }; + + TU_ASSERT(tuh_control_xfer(&xfer)); return true; } -bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num) +static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_LOG_CDCH("CDC ACM Set Line Conding\r\n"); + + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = CDC_REQUEST_SET_LINE_CODING, + .wValue = 0, + .wIndex = tu_htole16(p_cdc->bInterfaceNumber), + .wLength = tu_htole16(sizeof(cdc_line_coding_t)) + }; + + // use usbh enum buf to hold line coding since user line_coding variable does not live long enough + uint8_t* enum_buf = usbh_get_enum_buf(); + memcpy(enum_buf, line_coding, sizeof(cdc_line_coding_t)); + + p_cdc->user_control_cb = complete_cb; + tuh_xfer_t xfer = { + .daddr = p_cdc->daddr, + .ep_addr = 0, + .setup = &request, + .buffer = enum_buf, + .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call + .user_data = user_data + }; + + TU_ASSERT(tuh_control_xfer(&xfer)); + return true; +} + +static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_VERIFY(p_cdc->acm_capability.support_line_request); + cdc_line_coding_t line_coding = p_cdc->line_coding; + line_coding.bit_rate = baudrate; + return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data); +} + +//--------------------------------------------------------------------+ +// FTDI +//--------------------------------------------------------------------+ +#if CFG_TUH_CDC_FTDI + +enum { + CONFIG_FTDI_RESET = 0, + CONFIG_FTDI_MODEM_CTRL, + CONFIG_FTDI_SET_BAUDRATE, + CONFIG_FTDI_SET_DATA, + CONFIG_FTDI_COMPLETE +}; + +static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) { + // FTDI Interface includes 1 vendor interface + 2 bulk endpoints + TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff && itf_desc->bNumEndpoints == 2); + TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); + + cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + TU_VERIFY(p_cdc); + + TU_LOG_CDCH("FTDI opened\r\n"); + + p_cdc->serial_drid = SERIAL_DRIVER_FTDI; + + // endpoint pair + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); + + // data endpoints expected to be in pairs + return open_ep_stream_pair(p_cdc, desc_ep); +} + +// set request without data +static bool ftdi_sio_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_VENDOR, + .direction = TUSB_DIR_OUT + }, + .bRequest = command, + .wValue = tu_htole16(value), + .wIndex = 0, + .wLength = 0 + }; + + tuh_xfer_t xfer = { + .daddr = p_cdc->daddr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb, + .user_data = user_data + }; + + return tuh_control_xfer(&xfer); +} + +static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data); +} + +static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - (void) dev_addr; (void) itf_num; + TU_LOG_CDCH("CDC FTDI Set Control Line State\r\n"); + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | line_state, + complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } -bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) { - (void) ep_addr; - tuh_cdc_xfer_isr( dev_addr, event, 0, xferred_bytes ); + const uint8_t divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; + uint32_t divisor; + + /* divisor shifted 3 bits to the left */ + uint32_t divisor3 = base / (2 * baud); + divisor = (divisor3 >> 3); + divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14; + + /* Deal with special cases for highest baud rates. */ + if (divisor == 1) { /* 1.0 */ + divisor = 0; + } + else if (divisor == 0x4001) { /* 1.5 */ + divisor = 1; + } + + return divisor; +} + +static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) +{ + return ftdi_232bm_baud_base_to_divisor(baud, 48000000u); +} + +static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate); + TU_LOG_CDCH("CDC FTDI Set BaudRate = %lu, divisor = 0x%04x\n", baudrate, divisor); + + p_cdc->user_control_cb = complete_cb; + _ftdi_requested_baud = baudrate; + TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor, + complete_cb ? cdch_internal_control_complete : NULL, user_data)); + return true; } -void cdch_close(uint8_t dev_addr) +static void ftdi_process_config(tuh_xfer_t* xfer) { + uintptr_t const state = xfer->user_data; + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); + + switch(state) { + // Note may need to read FTDI eeprom + case CONFIG_FTDI_RESET: + TU_ASSERT(ftdi_sio_reset(p_cdc, ftdi_process_config, CONFIG_FTDI_MODEM_CTRL),); + break; + + case CONFIG_FTDI_MODEM_CTRL: + #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + TU_ASSERT( + ftdi_sio_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + + case CONFIG_FTDI_SET_BAUDRATE: { + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT(ftdi_sio_set_baudrate(p_cdc, line_coding.bit_rate, ftdi_process_config, CONFIG_FTDI_SET_DATA),); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + } + + case CONFIG_FTDI_SET_DATA: { + #if 0 // TODO set data format + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT(ftdi_sio_set_data(p_cdc, process_ftdi_config, CONFIG_FTDI_COMPLETE),); + break; + #endif + #endif + + TU_ATTR_FALLTHROUGH; + } + + case CONFIG_FTDI_COMPLETE: + set_config_complete(p_cdc, idx, itf_num); + break; + + default: + break; + } +} + +#endif + +//--------------------------------------------------------------------+ +// CP210x +//--------------------------------------------------------------------+ + +#if CFG_TUH_CDC_CP210X + +enum { + CONFIG_CP210X_IFC_ENABLE = 0, + CONFIG_CP210X_SET_BAUDRATE, + CONFIG_CP210X_SET_LINE_CTL, + CONFIG_CP210X_SET_DTR_RTS, + CONFIG_CP210X_COMPLETE +}; + +static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { + // CP210x Interface includes 1 vendor interface + 2 bulk endpoints + TU_VERIFY(itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0 && itf_desc->bNumEndpoints == 2); + TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); + + cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + TU_VERIFY(p_cdc); + + TU_LOG_CDCH("CP210x opened\r\n"); + p_cdc->serial_drid = SERIAL_DRIVER_CP210X; + + // endpoint pair + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); + + // data endpoints expected to be in pairs + return open_ep_stream_pair(p_cdc, desc_ep); +} + +static bool cp210x_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_VENDOR, + .direction = TUSB_DIR_OUT + }, + .bRequest = command, + .wValue = tu_htole16(value), + .wIndex = p_cdc->bInterfaceNumber, + .wLength = tu_htole16(length) + }; + + // use usbh enum buf since application variable does not live long enough + uint8_t* enum_buf = NULL; + + if (buffer && length > 0) { + enum_buf = usbh_get_enum_buf(); + tu_memcpy_s(enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length); + } + + tuh_xfer_t xfer = { + .daddr = p_cdc->daddr, + .ep_addr = 0, + .setup = &request, + .buffer = enum_buf, + .complete_cb = complete_cb, + .user_data = user_data + }; + + return tuh_control_xfer(&xfer); +} + +static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + return cp210x_set_request(p_cdc, CP210X_IFC_ENABLE, enabled, NULL, 0, complete_cb, user_data); +} + +static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_LOG_CDCH("CDC CP210x Set BaudRate = %lu\n", baudrate); + uint32_t baud_le = tu_htole32(baudrate); + p_cdc->user_control_cb = complete_cb; + return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, + complete_cb ? cdch_internal_control_complete : NULL, user_data); +} + +static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); + TU_LOG_CDCH("CDC CP210x Set Control Line State\r\n"); + p_cdc->user_control_cb = complete_cb; + return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | line_state, NULL, 0, + complete_cb ? cdch_internal_control_complete : NULL, user_data); +} - cdch_data_t * p_cdc = get_itf(dev_addr); - tu_memclr(p_cdc, sizeof(cdch_data_t)); +static void cp210x_process_config(tuh_xfer_t* xfer) { + uintptr_t const state = xfer->user_data; + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); + + switch (state) { + case CONFIG_CP210X_IFC_ENABLE: + TU_ASSERT(cp210x_ifc_enable(p_cdc, 1, cp210x_process_config, CONFIG_CP210X_SET_BAUDRATE),); + break; + + case CONFIG_CP210X_SET_BAUDRATE: { + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT(cp210x_set_baudrate(p_cdc, line_coding.bit_rate, cp210x_process_config, CONFIG_CP210X_SET_LINE_CTL),); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + } + + case CONFIG_CP210X_SET_LINE_CTL: { + #if defined(CFG_TUH_CDC_LINE_CODING_ON_ENUM) && 0 // skip for now + cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + } + + case CONFIG_CP210X_SET_DTR_RTS: + #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + TU_ASSERT( + cp210x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, cp210x_process_config, CONFIG_CP210X_COMPLETE),); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + + case CONFIG_CP210X_COMPLETE: + set_config_complete(p_cdc, idx, itf_num); + break; + + default: break; + } } #endif + +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.h b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.h index 33dbd2ef..19552f1e 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -34,89 +34,159 @@ #endif //--------------------------------------------------------------------+ -// CDC APPLICATION PUBLIC API +// Class Driver Configuration //--------------------------------------------------------------------+ -/** \ingroup ClassDriver_CDC Communication Device Class (CDC) - * \addtogroup CDC_Serial Serial - * @{ - * \defgroup CDC_Serial_Host Host - * @{ */ -bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb); +// Set Line Control state on enumeration/mounted: DTR ( bit 0), RTS (bit 1) +#ifndef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM +#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0 +#endif + +// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t +//#ifndef CFG_TUH_CDC_LINE_CODING_ON_ENUM +//#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } +//#endif + +// RX FIFO size +#ifndef CFG_TUH_CDC_RX_BUFSIZE +#define CFG_TUH_CDC_RX_BUFSIZE USBH_EPSIZE_BULK_MAX +#endif + +// RX Endpoint size +#ifndef CFG_TUH_CDC_RX_EPSIZE +#define CFG_TUH_CDC_RX_EPSIZE USBH_EPSIZE_BULK_MAX +#endif + +// TX FIFO size +#ifndef CFG_TUH_CDC_TX_BUFSIZE +#define CFG_TUH_CDC_TX_BUFSIZE USBH_EPSIZE_BULK_MAX +#endif + +// TX Endpoint size +#ifndef CFG_TUH_CDC_TX_EPSIZE +#define CFG_TUH_CDC_TX_EPSIZE USBH_EPSIZE_BULK_MAX +#endif + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ -static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb) +// Get Interface index from device address + interface number +// return TUSB_INDEX_INVALID_8 (0xFF) if not found +uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num); + +// Get Interface information +// return true if index is correct and interface is currently mounted +bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info); + +// Check if a interface is mounted +bool tuh_cdc_mounted(uint8_t idx); + +// Get current DTR status +bool tuh_cdc_get_dtr(uint8_t idx); + +// Get current RTS status +bool tuh_cdc_get_rts(uint8_t idx); + +// Check if interface is connected (DTR active) +TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) { - return tuh_cdc_set_control_line_state(dev_addr, true, true, complete_cb); + return tuh_cdc_get_dtr(idx); } -static inline bool tuh_cdc_disconnect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb) +// Get local (saved/cached) version of line coding. +// This function should return correct values if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding() +// are invoked previously or CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined. +// NOTE: This function does not make any USB transfer request to device. +bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding); + +//--------------------------------------------------------------------+ +// Write API +//--------------------------------------------------------------------+ + +// Get the number of bytes available for writing +uint32_t tuh_cdc_write_available(uint8_t idx); + +// Write to cdc interface +uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize); + +// Force sending data if possible, return number of forced bytes +uint32_t tuh_cdc_write_flush(uint8_t idx); + +// Clear the transmit FIFO +bool tuh_cdc_write_clear(uint8_t idx); + +//--------------------------------------------------------------------+ +// Read API +//--------------------------------------------------------------------+ + +// Get the number of bytes available for reading +uint32_t tuh_cdc_read_available(uint8_t idx); + +// Read from cdc interface +uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize); + +// Get a byte from RX FIFO without removing it +bool tuh_cdc_peek(uint8_t idx, uint8_t* ch); + +// Clear the received FIFO +bool tuh_cdc_read_clear (uint8_t idx); + +//--------------------------------------------------------------------+ +// Control Endpoint (Request) API +// Each Function will make a USB control transfer request to/from device +// - If complete_cb is provided, the function will return immediately and invoke +// the callback when request is complete. +// - If complete_cb is NULL, the function will block until request is complete. +// - In this case, user_data should be pointed to xfer_result_t to hold the transfer result. +// - The function will return true if transfer is successful, false otherwise. +//--------------------------------------------------------------------+ + +// Request to Set Control Line State: DTR (bit 0), RTS (bit 1) +bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + +// Request to set baudrate +bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + +// Request to Set Line Coding (ACM only) +// Should only use if you don't work with serial devices such as FTDI/CP210x +bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + +// Request to Get Line Coding (ACM only) +// Should only use if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding() never got invoked and +// CFG_TUH_CDC_LINE_CODING_ON_ENUM is not defined +// bool tuh_cdc_get_line_coding(uint8_t idx, cdc_line_coding_t* coding); + +// Connect by set both DTR, RTS +TU_ATTR_ALWAYS_INLINE static inline +bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return tuh_cdc_set_control_line_state(dev_addr, false, false, complete_cb); + return tuh_cdc_set_control_line_state(idx, CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS, complete_cb, user_data); } -/** \brief Check if device support CDC Serial interface or not - * \param[in] dev_addr device address - * \retval true if device supports - * \retval false if device does not support or is not mounted - */ -bool tuh_cdc_serial_is_mounted(uint8_t dev_addr); - -/** \brief Check if the interface is currently busy or not - * \param[in] dev_addr device address - * \param[in] pipeid value from \ref cdc_pipeid_t to indicate target pipe. - * \retval true if the interface is busy, meaning the stack is still transferring/waiting data from/to device - * \retval false if the interface is not busy, meaning the stack successfully transferred data from/to device - * \note This function is used to check if previous transfer is complete (success or error), so that the next transfer - * can be scheduled. User needs to make sure the corresponding interface is mounted - * (by \ref tuh_cdc_serial_is_mounted) before calling this function. - */ -bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid); - -/** \brief Perform USB OUT transfer to device - * \param[in] dev_addr device address - * \param[in] p_data Buffer containing data. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION) - * \param[in] length Number of bytes to be transferred via USB bus - * \retval TUSB_ERROR_NONE on success - * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device - * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request) - * \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct - * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the - * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION. - */ -bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify); - -/** \brief Perform USB IN transfer to get data from device - * \param[in] dev_addr device address - * \param[in] p_buffer Buffer containing received data. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION) - * \param[in] length Number of bytes to be transferred via USB bus - * \retval TUSB_ERROR_NONE on success - * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device - * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request) - * \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct - * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the - * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION. - */ -bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify); +// Disconnect by clear both DTR, RTS +TU_ATTR_ALWAYS_INLINE static inline +bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + return tuh_cdc_set_control_line_state(idx, 0x00, complete_cb, user_data); +} //--------------------------------------------------------------------+ // CDC APPLICATION CALLBACKS //--------------------------------------------------------------------+ -/** \brief Callback function that is invoked when an transferring event occurred - * \param[in] dev_addr Address of device - * \param[in] event an value from \ref xfer_result_t - * \param[in] pipe_id value from \ref cdc_pipeid_t indicate the pipe - * \param[in] xferred_bytes Number of bytes transferred via USB bus - * \note event can be one of following - * - XFER_RESULT_SUCCESS : previously scheduled transfer completes successfully. - * - XFER_RESULT_FAILED : previously scheduled transfer encountered a transaction error. - * - XFER_RESULT_STALLED : previously scheduled transfer is stalled by device. - * \note - */ -void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes); +// Invoked when a device with CDC interface is mounted +// idx is index of cdc interface in the internal pool. +TU_ATTR_WEAK extern void tuh_cdc_mount_cb(uint8_t idx); + +// Invoked when a device with CDC interface is unmounted +TU_ATTR_WEAK extern void tuh_cdc_umount_cb(uint8_t idx); + +// Invoked when received new data +TU_ATTR_WEAK extern void tuh_cdc_rx_cb(uint8_t idx); -/// @} // group CDC_Serial_Host -/// @} +// Invoked when a TX is complete and therefore space becomes available in TX buffer +TU_ATTR_WEAK extern void tuh_cdc_tx_complete_cb(uint8_t idx); //--------------------------------------------------------------------+ // Internal Class Driver API diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis.h b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis.h index e0f129fe..ad153e0a 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c index 8f28f51a..11a5355a 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -50,8 +50,8 @@ //--------------------------------------------------------------------+ #define RNDIS_MSG_PAYLOAD_MAX (1024*4) -CFG_TUSB_MEM_SECTION static uint8_t msg_notification[CFG_TUH_DEVICE_MAX][8]; -CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t msg_payload[RNDIS_MSG_PAYLOAD_MAX]; +CFG_TUH_MEM_SECTION static uint8_t msg_notification[CFG_TUH_DEVICE_MAX][8]; +CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN static uint8_t msg_payload[RNDIS_MSG_PAYLOAD_MAX]; static rndish_data_t rndish_data[CFG_TUH_DEVICE_MAX]; @@ -117,7 +117,7 @@ void rndish_init(void) //------------- Task creation -------------// - //------------- semaphore creation for notificaiton pipe -------------// + //------------- semaphore creation for notification pipe -------------// for(uint8_t i=0; i= 2 -static tu_lookup_entry_t const _dfu_request_lookup[] = +tu_static tu_lookup_entry_t const _dfu_request_lookup[] = { { .key = DFU_REQUEST_DETACH , .data = "DETACH" }, { .key = DFU_REQUEST_DNLOAD , .data = "DNLOAD" }, @@ -85,13 +85,13 @@ static tu_lookup_entry_t const _dfu_request_lookup[] = { .key = DFU_REQUEST_ABORT , .data = "ABORT" }, }; -static tu_lookup_table_t const _dfu_request_table = +tu_static tu_lookup_table_t const _dfu_request_table = { .count = TU_ARRAY_SIZE(_dfu_request_lookup), .items = _dfu_request_lookup }; -static tu_lookup_entry_t const _dfu_state_lookup[] = +tu_static tu_lookup_entry_t const _dfu_state_lookup[] = { { .key = APP_IDLE , .data = "APP_IDLE" }, { .key = APP_DETACH , .data = "APP_DETACH" }, @@ -106,13 +106,13 @@ static tu_lookup_entry_t const _dfu_state_lookup[] = { .key = DFU_ERROR , .data = "ERROR" }, }; -static tu_lookup_table_t const _dfu_state_table = +tu_static tu_lookup_table_t const _dfu_state_table = { .count = TU_ARRAY_SIZE(_dfu_state_lookup), .items = _dfu_state_lookup }; -static tu_lookup_entry_t const _dfu_status_lookup[] = +tu_static tu_lookup_entry_t const _dfu_status_lookup[] = { { .key = DFU_STATUS_OK , .data = "OK" }, { .key = DFU_STATUS_ERR_TARGET , .data = "errTARGET" }, @@ -132,7 +132,7 @@ static tu_lookup_entry_t const _dfu_status_lookup[] = { .key = DFU_STATUS_ERR_STALLEDPKT , .data = "errSTALLEDPKT" }, }; -static tu_lookup_table_t const _dfu_status_table = +tu_static tu_lookup_table_t const _dfu_status_table = { .count = TU_ARRAY_SIZE(_dfu_status_lookup), .items = _dfu_status_lookup diff --git a/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c b/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c index b9cd6096..7b77b3f8 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c @@ -110,7 +110,7 @@ bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request TU_LOG2(" DFU RT Request: GETSTATUS\r\n"); dfu_status_response_t resp; // Status = OK, Poll timeout is ignored during RT, State = APP_IDLE, IString = 0 - memset(&resp, 0x00, sizeof(dfu_status_response_t)); + TU_VERIFY(tu_memset_s(&resp, sizeof(resp), 0x00, sizeof(resp))==0); tud_control_xfer(rhport, request, &resp, sizeof(dfu_status_response_t)); } break; diff --git a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid.h b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid.h index 44a464be..fbd3eef3 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -708,6 +708,7 @@ enum { HID_USAGE_PAGE_MSR = 0x8e, HID_USAGE_PAGE_CAMERA = 0x90, HID_USAGE_PAGE_ARCADE = 0x91, + HID_USAGE_PAGE_FIDO = 0xF1D0, // FIDO alliance HID usage page HID_USAGE_PAGE_VENDOR = 0xFF00 // 0xFF00 - 0xFFFF }; @@ -844,6 +845,14 @@ enum HID_USAGE_CONSUMER_AC_PAN = 0x0238, }; +/// HID Usage Table: FIDO Alliance Page (0xF1D0) +enum +{ + HID_USAGE_FIDO_U2FHID = 0x01, // U2FHID usage for top-level collection + HID_USAGE_FIDO_DATA_IN = 0x20, // Raw IN data report + HID_USAGE_FIDO_DATA_OUT = 0x21 // Raw OUT data report +}; + /*-------------------------------------------------------------------- * ASCII to KEYCODE Conversion * Expand to array of [128][2] (shift, keycode) diff --git a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.c b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.c index 8077e4de..9240fe2c 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.c @@ -58,7 +58,7 @@ typedef struct tusb_hid_descriptor_hid_t const * hid_descriptor; } hidd_interface_t; -CFG_TUSB_MEM_SECTION static hidd_interface_t _hidd_itf[CFG_TUD_HID]; +CFG_TUSB_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID]; /*------------- Helpers -------------*/ static inline uint8_t get_index_by_itfnum(uint8_t itf_num) @@ -92,16 +92,12 @@ bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, u // prepare data if (report_id) { - len = tu_min16(len, CFG_TUD_HID_EP_BUFSIZE-1); - p_hid->epin_buf[0] = report_id; - memcpy(p_hid->epin_buf+1, report, len); + TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf+1, CFG_TUD_HID_EP_BUFSIZE-1, report, len)); len++; }else { - // If report id = 0, skip ID field - len = tu_min16(len, CFG_TUD_HID_EP_BUFSIZE); - memcpy(p_hid->epin_buf, report, len); + TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf, CFG_TUD_HID_EP_BUFSIZE, report, len)); } return usbd_edpt_xfer(rhport, p_hid->ep_in, p_hid->epin_buf, len); @@ -126,7 +122,7 @@ bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modi if ( keycode ) { - memcpy(report.keycode, keycode, 6); + memcpy(report.keycode, keycode, sizeof(report.keycode)); }else { tu_memclr(report.keycode, 6); @@ -151,8 +147,7 @@ bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, } bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, - int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) -{ + int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) { hid_gamepad_report_t report = { .x = x, @@ -183,11 +178,12 @@ void hidd_reset(uint8_t rhport) } uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) -{ + { TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0); // len = interface + hid + n*endpoints - uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + + uint16_t const drv_len = + (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); TU_ASSERT(max_len >= drv_len, 0); @@ -403,7 +399,7 @@ bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ { if (tud_hid_report_complete_cb) { - tud_hid_report_complete_cb(instance, p_hid->epin_buf, (/*uint16_t*/ uint8_t) xferred_bytes); + tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t) xferred_bytes); } } // Received report diff --git a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.h b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.h index 3143b102..17b24def 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.h @@ -116,7 +116,7 @@ TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate); // Invoked when sent REPORT successfully to host // Application can use this to send the next report // Note: For composite reports, report[0] is report ID -TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, /*uint16_t*/ uint8_t len ); +TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len); //--------------------------------------------------------------------+ @@ -182,7 +182,7 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ /* Report ID if any */\ __VA_ARGS__ \ - /* 8 bits Modifier Keys (Shfit, Control, Alt) */ \ + /* 8 bits Modifier Keys (Shift, Control, Alt) */ \ HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\ HID_USAGE_MIN ( 224 ) ,\ HID_USAGE_MAX ( 231 ) ,\ @@ -352,6 +352,31 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ HID_COLLECTION_END \ +// FIDO U2F Authenticator Descriptor Template +// - 1st parameter is report size, which is 64 bytes maximum in U2F +// - 2nd parameter is HID_REPORT_ID(n) (optional) +#define TUD_HID_REPORT_DESC_FIDO_U2F(report_size, ...) \ + HID_USAGE_PAGE_N ( HID_USAGE_PAGE_FIDO, 2 ) ,\ + HID_USAGE ( HID_USAGE_FIDO_U2FHID ) ,\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */ \ + __VA_ARGS__ \ + /* Usage Data In */ \ + HID_USAGE ( HID_USAGE_FIDO_DATA_IN ) ,\ + HID_LOGICAL_MIN ( 0 ) ,\ + HID_LOGICAL_MAX_N ( 0xff, 2 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_REPORT_COUNT ( report_size ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + /* Usage Data Out */ \ + HID_USAGE ( HID_USAGE_FIDO_DATA_OUT ) ,\ + HID_LOGICAL_MIN ( 0 ) ,\ + HID_LOGICAL_MAX_N ( 0xff, 2 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_REPORT_COUNT ( report_size ) ,\ + HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + HID_COLLECTION_END \ + // HID Generic Input & Output // - 1st parameter is report size (mandatory) // - 2nd parameter is report id HID_REPORT_ID(n) (optional) diff --git a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.c b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.c index ca745464..d95d3ef3 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -39,6 +39,8 @@ typedef struct { + uint8_t daddr; + uint8_t itf_num; uint8_t ep_in; uint8_t ep_out; @@ -52,77 +54,158 @@ typedef struct uint16_t epin_size; uint16_t epout_size; - uint8_t epin_buf[CFG_TUH_HID_EPIN_BUFSIZE]; - uint8_t epout_buf[CFG_TUH_HID_EPOUT_BUFSIZE]; + CFG_TUH_MEM_ALIGN uint8_t epin_buf[CFG_TUH_HID_EPIN_BUFSIZE]; + CFG_TUH_MEM_ALIGN uint8_t epout_buf[CFG_TUH_HID_EPOUT_BUFSIZE]; } hidh_interface_t; -typedef struct +CFG_TUH_MEM_SECTION +tu_static hidh_interface_t _hidh_itf[CFG_TUH_HID]; + +//--------------------------------------------------------------------+ +// Helper +//--------------------------------------------------------------------+ + +TU_ATTR_ALWAYS_INLINE static inline +hidh_interface_t* get_hid_itf(uint8_t daddr, uint8_t idx) { - uint8_t inst_count; - hidh_interface_t instances[CFG_TUH_HID]; -} hidh_device_t; + TU_ASSERT(daddr && idx < CFG_TUH_HID, NULL); + hidh_interface_t* p_hid = &_hidh_itf[idx]; + return (p_hid->daddr == daddr) ? p_hid : NULL; +} -static hidh_device_t _hidh_dev[CFG_TUH_DEVICE_MAX]; +// Get instance ID by endpoint address +static uint8_t get_idx_by_epaddr(uint8_t daddr, uint8_t ep_addr) +{ + for ( uint8_t idx = 0; idx < CFG_TUH_HID; idx++ ) + { + hidh_interface_t const * p_hid = &_hidh_itf[idx]; -//------------- Internal prototypes -------------// + if ( p_hid->daddr == daddr && + (p_hid->ep_in == ep_addr || p_hid->ep_out == ep_addr) ) + { + return idx; + } + } -// Get HID device & interface -TU_ATTR_ALWAYS_INLINE static inline hidh_device_t* get_dev(uint8_t dev_addr); -TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_instance(uint8_t dev_addr, uint8_t instance); -static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf); -static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr); + return TUSB_INDEX_INVALID_8; +} + +static hidh_interface_t* find_new_itf(void) +{ + for(uint8_t i=0; iinst_count; + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + return p_hid != NULL; +} + +bool tuh_hid_itf_get_info(uint8_t daddr, uint8_t idx, tuh_itf_info_t* info) +{ + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid && info); + + info->daddr = daddr; + + // re-construct descriptor + tusb_desc_interface_t* desc = &info->desc; + desc->bLength = sizeof(tusb_desc_interface_t); + desc->bDescriptorType = TUSB_DESC_INTERFACE; + + desc->bInterfaceNumber = p_hid->itf_num; + desc->bAlternateSetting = 0; + desc->bNumEndpoints = (uint8_t) ((p_hid->ep_in ? 1u : 0u) + (p_hid->ep_out ? 1u : 0u)); + desc->bInterfaceClass = TUSB_CLASS_HID; + desc->bInterfaceSubClass = (p_hid->itf_protocol ? HID_SUBCLASS_BOOT : HID_SUBCLASS_NONE); + desc->bInterfaceProtocol = p_hid->itf_protocol; + desc->iInterface = 0; // not used yet + + return true; } -bool tuh_hid_mounted(uint8_t dev_addr, uint8_t instance) +uint8_t tuh_hid_itf_get_index(uint8_t daddr, uint8_t itf_num) { - hidh_interface_t* hid_itf = get_instance(dev_addr, instance); - return (hid_itf->ep_in != 0) || (hid_itf->ep_out != 0); + for ( uint8_t idx = 0; idx < CFG_TUH_HID; idx++ ) + { + hidh_interface_t const * p_hid = &_hidh_itf[idx]; + + if ( p_hid->daddr == daddr && p_hid->itf_num == itf_num) return idx; + } + + return TUSB_INDEX_INVALID_8; } -uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance) +uint8_t tuh_hid_interface_protocol(uint8_t daddr, uint8_t idx) { - hidh_interface_t* hid_itf = get_instance(dev_addr, instance); - return hid_itf->itf_protocol; + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + return p_hid ? p_hid->itf_protocol : 0; } //--------------------------------------------------------------------+ // Control Endpoint API //--------------------------------------------------------------------+ -uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance) +uint8_t tuh_hid_get_protocol(uint8_t daddr, uint8_t idx) { - hidh_interface_t* hid_itf = get_instance(dev_addr, instance); - return hid_itf->protocol_mode; + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + return p_hid ? p_hid->protocol_mode : 0; } static void set_protocol_complete(tuh_xfer_t* xfer) { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const daddr = xfer->daddr; - uint8_t const instance = get_instance_id_by_itfnum(daddr, itf_num); - hidh_interface_t* hid_itf = get_instance(daddr, instance); + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const daddr = xfer->daddr; + uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num); + + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid, ); if (XFER_RESULT_SUCCESS == xfer->result) { - hid_itf->protocol_mode = (uint8_t) tu_le16toh(xfer->setup->wValue); + p_hid->protocol_mode = (uint8_t) tu_le16toh(xfer->setup->wValue); } if (tuh_hid_set_protocol_complete_cb) { - tuh_hid_set_protocol_complete_cb(daddr, instance, hid_itf->protocol_mode); + tuh_hid_set_protocol_complete_cb(daddr, idx, p_hid->protocol_mode); } } - -static bool _hidh_set_protocol(uint8_t dev_addr, uint8_t itf_num, uint8_t protocol, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +static bool _hidh_set_protocol(uint8_t daddr, uint8_t itf_num, uint8_t protocol, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG2("HID Set Protocol = %d\r\n", protocol); @@ -142,7 +225,7 @@ static bool _hidh_set_protocol(uint8_t dev_addr, uint8_t itf_num, uint8_t protoc tuh_xfer_t xfer = { - .daddr = dev_addr, + .daddr = daddr, .ep_addr = 0, .setup = &request, .buffer = NULL, @@ -150,16 +233,15 @@ static bool _hidh_set_protocol(uint8_t dev_addr, uint8_t itf_num, uint8_t protoc .user_data = user_data }; - TU_ASSERT( tuh_control_xfer(&xfer) ); - return true; + return tuh_control_xfer(&xfer); } -bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol) +bool tuh_hid_set_protocol(uint8_t daddr, uint8_t idx, uint8_t protocol) { - hidh_interface_t* hid_itf = get_instance(dev_addr, instance); - TU_VERIFY(hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE); + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid && p_hid->itf_protocol != HID_ITF_PROTOCOL_NONE); - return _hidh_set_protocol(dev_addr, hid_itf->itf_num, protocol, set_protocol_complete, 0); + return _hidh_set_protocol(daddr, p_hid->itf_num, protocol, set_protocol_complete, 0); } static void set_report_complete(tuh_xfer_t* xfer) @@ -168,20 +250,22 @@ static void set_report_complete(tuh_xfer_t* xfer) if (tuh_hid_set_report_complete_cb) { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const instance = get_instance_id_by_itfnum(xfer->daddr, itf_num); + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num); uint8_t const report_type = tu_u16_high(xfer->setup->wValue); uint8_t const report_id = tu_u16_low(xfer->setup->wValue); - tuh_hid_set_report_complete_cb(xfer->daddr, instance, report_id, report_type, + tuh_hid_set_report_complete_cb(xfer->daddr, idx, report_id, report_type, (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0); } } -bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) +bool tuh_hid_set_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) { - hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid); + TU_LOG2("HID Set Report: id = %u, type = %u, len = %u\r\n", report_id, report_type, len); tusb_control_request_t const request = @@ -193,14 +277,14 @@ bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, u .direction = TUSB_DIR_OUT }, .bRequest = HID_REQ_CONTROL_SET_REPORT, - .wValue = tu_u16(report_type, report_id), - .wIndex = hid_itf->itf_num, + .wValue = tu_htole16(tu_u16(report_type, report_id)), + .wIndex = tu_htole16((uint16_t)p_hid->itf_num), .wLength = len }; tuh_xfer_t xfer = { - .daddr = dev_addr, + .daddr = daddr, .ep_addr = 0, .setup = &request, .buffer = report, @@ -208,14 +292,14 @@ bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, u .user_data = 0 }; - TU_ASSERT( tuh_control_xfer(&xfer) ); - return true; + return tuh_control_xfer(&xfer); } -static bool _hidh_set_idle(uint8_t dev_addr, uint8_t itf_num, uint16_t idle_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +static bool _hidh_set_idle(uint8_t daddr, uint8_t itf_num, uint16_t idle_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // SET IDLE request, device can stall if not support this request TU_LOG2("HID Set Idle \r\n"); + tusb_control_request_t const request = { .bmRequestType_bit = @@ -225,14 +309,14 @@ static bool _hidh_set_idle(uint8_t dev_addr, uint8_t itf_num, uint16_t idle_rate .direction = TUSB_DIR_OUT }, .bRequest = HID_REQ_CONTROL_SET_IDLE, - .wValue = idle_rate, - .wIndex = itf_num, + .wValue = tu_htole16(idle_rate), + .wIndex = tu_htole16((uint16_t)itf_num), .wLength = 0 }; tuh_xfer_t xfer = { - .daddr = dev_addr, + .daddr = daddr, .ep_addr = 0, .setup = &request, .buffer = NULL, @@ -240,96 +324,148 @@ static bool _hidh_set_idle(uint8_t dev_addr, uint8_t itf_num, uint16_t idle_rate .user_data = user_data }; - TU_ASSERT( tuh_control_xfer(&xfer) ); - - return true; + return tuh_control_xfer(&xfer); } //--------------------------------------------------------------------+ // Interrupt Endpoint API //--------------------------------------------------------------------+ -bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance) +// Check if HID interface is ready to receive report +bool tuh_hid_receive_ready(uint8_t dev_addr, uint8_t idx) +{ + hidh_interface_t* p_hid = get_hid_itf(dev_addr, idx); + TU_VERIFY(p_hid); + + return !usbh_edpt_busy(dev_addr, p_hid->ep_in); +} + +bool tuh_hid_receive_report(uint8_t daddr, uint8_t idx) { - hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid); // claim endpoint - TU_VERIFY( usbh_edpt_claim(dev_addr, hid_itf->ep_in) ); + TU_VERIFY( usbh_edpt_claim(daddr, p_hid->ep_in) ); - if ( !usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size) ) + if ( !usbh_edpt_xfer(daddr, p_hid->ep_in, p_hid->epin_buf, p_hid->epin_size) ) { - usbh_edpt_claim(dev_addr, hid_itf->ep_in); + usbh_edpt_release(daddr, p_hid->ep_in); return false; } return true; } -//bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance) -//{ -// TU_VERIFY(tuh_n_hid_n_mounted(dev_addr, instance)); -// -// hidh_interface_t* hid_itf = get_instance(dev_addr, instance); -// return !usbh_edpt_busy(dev_addr, hid_itf->ep_in); -//} +bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx) +{ + hidh_interface_t* p_hid = get_hid_itf(dev_addr, idx); + TU_VERIFY(p_hid); + + return !usbh_edpt_busy(dev_addr, p_hid->ep_out); +} + +bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const void* report, uint16_t len) +{ + TU_LOG2("HID Send Report %d\r\n", report_id); + + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid); + + if (p_hid->ep_out == 0) + { + // This HID does not have an out endpoint (other than control) + return false; + } + else if (len > CFG_TUH_HID_EPOUT_BUFSIZE || + (report_id != 0 && len > (CFG_TUH_HID_EPOUT_BUFSIZE - 1))) + { + // ep_out buffer is not large enough to hold contents + return false; + } -//void tuh_hid_send_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t const* report, uint16_t len); + // claim endpoint + TU_VERIFY( usbh_edpt_claim(daddr, p_hid->ep_out) ); + + if (report_id == 0) + { + // No report ID in transmission + memcpy(&p_hid->epout_buf[0], report, len); + } + else + { + p_hid->epout_buf[0] = report_id; + memcpy(&p_hid->epout_buf[1], report, len); + ++len; // 1 more byte for report_id + } + + TU_LOG3_MEM(p_hid->epout_buf, len, 2); + + if ( !usbh_edpt_xfer(daddr, p_hid->ep_out, p_hid->epout_buf, len) ) + { + usbh_edpt_release(daddr, p_hid->ep_out); + return false; + } + + return true; +} //--------------------------------------------------------------------+ // USBH API //--------------------------------------------------------------------+ void hidh_init(void) { - tu_memclr(_hidh_dev, sizeof(_hidh_dev)); + tu_memclr(_hidh_itf, sizeof(_hidh_itf)); } -bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { (void) result; uint8_t const dir = tu_edpt_dir(ep_addr); - uint8_t const instance = get_instance_id_by_epaddr(dev_addr, ep_addr); - hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + uint8_t const idx = get_idx_by_epaddr(daddr, ep_addr); + + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid); if ( dir == TUSB_DIR_IN ) { - TU_LOG2(" Get Report callback (%u, %u)\r\n", dev_addr, instance); - TU_LOG3_MEM(hid_itf->epin_buf, xferred_bytes, 2); - tuh_hid_report_received_cb(dev_addr, instance, hid_itf->epin_buf, (uint16_t) xferred_bytes); + TU_LOG2(" Get Report callback (%u, %u)\r\n", daddr, idx); + TU_LOG3_MEM(p_hid->epin_buf, xferred_bytes, 2); + tuh_hid_report_received_cb(daddr, idx, p_hid->epin_buf, (uint16_t) xferred_bytes); }else { - if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(dev_addr, instance, hid_itf->epout_buf, (uint16_t) xferred_bytes); + if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(daddr, idx, p_hid->epout_buf, (uint16_t) xferred_bytes); } return true; } -void hidh_close(uint8_t dev_addr) +void hidh_close(uint8_t daddr) { - TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); - - hidh_device_t* hid_dev = get_dev(dev_addr); - - if (tuh_hid_umount_cb) + for(uint8_t i=0; iinst_count; inst++ ) tuh_hid_umount_cb(dev_addr, inst); + hidh_interface_t* p_hid = &_hidh_itf[i]; + if (p_hid->daddr == daddr) + { + if(tuh_hid_umount_cb) tuh_hid_umount_cb(daddr, i); + p_hid->daddr = 0; + } } - - tu_memclr(hid_dev, sizeof(hidh_device_t)); } //--------------------------------------------------------------------+ // Enumeration //--------------------------------------------------------------------+ -bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) +bool hidh_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) { (void) rhport; (void) max_len; TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass); - TU_LOG2("[%u] HID opening Interface %u\r\n", dev_addr, desc_itf->bInterfaceNumber); + TU_LOG2("[%u] HID opening Interface %u\r\n", daddr, desc_itf->bInterfaceNumber); // len = interface + hid + n*endpoints uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + @@ -343,12 +479,9 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc; TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType); - // not enough interface, try to increase CFG_TUH_HID - // TODO multiple devices - hidh_device_t* hid_dev = get_dev(dev_addr); - TU_ASSERT(hid_dev->inst_count < CFG_TUH_HID, 0); - - hidh_interface_t* hid_itf = get_instance(dev_addr, hid_dev->inst_count); + hidh_interface_t* p_hid = find_new_itf(); + TU_ASSERT(p_hid); // not enough interface, try to increase CFG_TUH_HID + p_hid->daddr = daddr; //------------- Endpoint Descriptors -------------// p_desc = tu_desc_next(p_desc); @@ -357,34 +490,35 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de for(int i = 0; i < desc_itf->bNumEndpoints; i++) { TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType); - TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) ); + TU_ASSERT( tuh_edpt_open(daddr, desc_ep) ); if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { - hid_itf->ep_in = desc_ep->bEndpointAddress; - hid_itf->epin_size = tu_edpt_packet_size(desc_ep); + p_hid->ep_in = desc_ep->bEndpointAddress; + p_hid->epin_size = tu_edpt_packet_size(desc_ep); } else { - hid_itf->ep_out = desc_ep->bEndpointAddress; - hid_itf->epout_size = tu_edpt_packet_size(desc_ep); + p_hid->ep_out = desc_ep->bEndpointAddress; + p_hid->epout_size = tu_edpt_packet_size(desc_ep); } p_desc = tu_desc_next(p_desc); desc_ep = (tusb_desc_endpoint_t const *) p_desc; } - hid_dev->inst_count++; - - hid_itf->itf_num = desc_itf->bInterfaceNumber; + p_hid->itf_num = desc_itf->bInterfaceNumber; // Assume bNumDescriptors = 1 - hid_itf->report_desc_type = desc_hid->bReportType; - hid_itf->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength); + p_hid->report_desc_type = desc_hid->bReportType; + p_hid->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength); // Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config - hid_itf->protocol_mode = HID_PROTOCOL_BOOT; - if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass ) hid_itf->itf_protocol = desc_itf->bInterfaceProtocol; + p_hid->protocol_mode = HID_PROTOCOL_BOOT; + if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass ) + { + p_hid->itf_protocol = desc_itf->bInterfaceProtocol; + } return true; } @@ -400,16 +534,16 @@ enum { CONFIG_COMPLETE }; -static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len); +static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t const* desc_report, uint16_t desc_len); static void process_set_config(tuh_xfer_t* xfer); -bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num) +bool hidh_set_config(uint8_t daddr, uint8_t itf_num) { tusb_control_request_t request; request.wIndex = tu_htole16((uint16_t) itf_num); tuh_xfer_t xfer; - xfer.daddr = dev_addr; + xfer.daddr = daddr; xfer.result = XFER_RESULT_SUCCESS; xfer.setup = &request; xfer.user_data = CONFG_SET_IDLE; @@ -422,8 +556,10 @@ bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num) static void process_set_config(tuh_xfer_t* xfer) { - // Stall is a valid response for SET_IDLE, therefore we could ignore its result - if ( xfer->setup->bRequest != HID_REQ_CONTROL_SET_IDLE ) + // Stall is a valid response for SET_IDLE, sometime SET_PROTOCOL as well + // therefore we could ignore its result + if ( !(xfer->setup->bRequest == HID_REQ_CONTROL_SET_IDLE || + xfer->setup->bRequest == HID_REQ_CONTROL_SET_PROTOCOL) ) { TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, ); } @@ -432,8 +568,9 @@ static void process_set_config(tuh_xfer_t* xfer) uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t const daddr = xfer->daddr; - uint8_t const instance = get_instance_id_by_itfnum(daddr, itf_num); - hidh_interface_t* hid_itf = get_instance(daddr, instance); + uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num); + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid, ); switch(state) { @@ -441,27 +578,27 @@ static void process_set_config(tuh_xfer_t* xfer) { // Idle rate = 0 mean only report when there is changes const uint16_t idle_rate = 0; - const uintptr_t next_state = (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? CONFIG_SET_PROTOCOL : CONFIG_GET_REPORT_DESC; + const uintptr_t next_state = (p_hid->itf_protocol != HID_ITF_PROTOCOL_NONE) ? CONFIG_SET_PROTOCOL : CONFIG_GET_REPORT_DESC; _hidh_set_idle(daddr, itf_num, idle_rate, process_set_config, next_state); } break; case CONFIG_SET_PROTOCOL: - _hidh_set_protocol(daddr, hid_itf->itf_num, HID_PROTOCOL_BOOT, process_set_config, CONFIG_GET_REPORT_DESC); + _hidh_set_protocol(daddr, p_hid->itf_num, HID_PROTOCOL_BOOT, process_set_config, CONFIG_GET_REPORT_DESC); break; case CONFIG_GET_REPORT_DESC: // Get Report Descriptor if possible // using usbh enumeration buffer since report descriptor can be very long - if( hid_itf->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE ) + if( p_hid->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE ) { - TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", hid_itf->report_desc_len); + TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", p_hid->report_desc_len); // Driver is mounted without report descriptor - config_driver_mount_complete(daddr, instance, NULL, 0); + config_driver_mount_complete(daddr, idx, NULL, 0); }else { - tuh_descriptor_get_hid_report(daddr, itf_num, hid_itf->report_desc_type, 0, usbh_get_enum_buf(), hid_itf->report_desc_len, process_set_config, CONFIG_COMPLETE); + tuh_descriptor_get_hid_report(daddr, itf_num, p_hid->report_desc_type, 0, usbh_get_enum_buf(), p_hid->report_desc_len, process_set_config, CONFIG_COMPLETE); } break; @@ -470,7 +607,7 @@ static void process_set_config(tuh_xfer_t* xfer) uint8_t const* desc_report = usbh_get_enum_buf(); uint16_t const desc_len = tu_le16toh(xfer->setup->wLength); - config_driver_mount_complete(daddr, instance, desc_report, desc_len); + config_driver_mount_complete(daddr, idx, desc_report, desc_len); } break; @@ -478,15 +615,16 @@ static void process_set_config(tuh_xfer_t* xfer) } } -static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) +static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t const* desc_report, uint16_t desc_len) { - hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid, ); // enumeration is complete - tuh_hid_mount_cb(dev_addr, instance, desc_report, desc_len); + if (tuh_hid_mount_cb) tuh_hid_mount_cb(daddr, idx, desc_report, desc_len); // notify usbh that driver enumeration is complete - usbh_driver_set_config_complete(dev_addr, hid_itf->itf_num); + usbh_driver_set_config_complete(daddr, p_hid->itf_num); } //--------------------------------------------------------------------+ @@ -631,46 +769,4 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, return report_num; } -//--------------------------------------------------------------------+ -// Helper -//--------------------------------------------------------------------+ - -// Get Device by address -TU_ATTR_ALWAYS_INLINE static inline hidh_device_t* get_dev(uint8_t dev_addr) -{ - return &_hidh_dev[dev_addr-1]; -} - -// Get Interface by instance number -TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_instance(uint8_t dev_addr, uint8_t instance) -{ - return &_hidh_dev[dev_addr-1].instances[instance]; -} - -// Get instance ID by interface number -static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf) -{ - for ( uint8_t inst = 0; inst < CFG_TUH_HID; inst++ ) - { - hidh_interface_t *hid = get_instance(dev_addr, inst); - - if ( (hid->itf_num == itf) && (hid->ep_in || hid->ep_out) ) return inst; - } - - return 0xff; -} - -// Get instance ID by endpoint address -static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr) -{ - for ( uint8_t inst = 0; inst < CFG_TUH_HID; inst++ ) - { - hidh_interface_t *hid = get_instance(dev_addr, inst); - - if ( (ep_addr == hid->ep_in) || ( ep_addr == hid->ep_out) ) return inst; - } - - return 0xff; -} - #endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.h b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.h index fe09b03b..08ad421d 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -62,14 +62,27 @@ typedef struct // Interface API //--------------------------------------------------------------------+ -// Get the number of HID instances -uint8_t tuh_hid_instance_count(uint8_t dev_addr); +// Get the total number of mounted HID interfaces of a device +uint8_t tuh_hid_itf_get_count(uint8_t dev_addr); -// Check if HID instance is mounted -bool tuh_hid_mounted(uint8_t dev_addr, uint8_t instance); +// Get all mounted interfaces across devices +uint8_t tuh_hid_itf_get_total_count(void); + +// backward compatible rename +#define tuh_hid_instance_count tuh_hid_itf_get_count + +// Get Interface information +bool tuh_hid_itf_get_info(uint8_t daddr, uint8_t idx, tuh_itf_info_t* itf_info); + +// Get Interface index from device address + interface number +// return TUSB_INDEX_INVALID_8 (0xFF) if not found +uint8_t tuh_hid_itf_get_index(uint8_t daddr, uint8_t itf_num); // Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values -uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance); +uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t idx); + +// Check if HID interface is mounted +bool tuh_hid_mounted(uint8_t dev_addr, uint8_t idx); // Parse report descriptor into array of report_info struct and return number of reports. // For complicated report, application should write its own parser. @@ -82,31 +95,34 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, // Get current protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) // Note: Device will be initialized in Boot protocol for simplicity. // Application can use set_protocol() to switch back to Report protocol. -uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance); +uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t idx); // Set protocol to HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) // This function is only supported by Boot interface (tuh_n_hid_interface_protocol() != NONE) -bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol); +bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t idx, uint8_t protocol); // Set Report using control endpoint -// report_type is either Intput, Output or Feature, (value from hid_report_type_t) -bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, void* report, uint16_t len); +// report_type is either Input, Output or Feature, (value from hid_report_type_t) +bool tuh_hid_set_report(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len); //--------------------------------------------------------------------+ // Interrupt Endpoint API //--------------------------------------------------------------------+ -// Check if the interface is ready to use -//bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance); +// Check if HID interface is ready to receive report +bool tuh_hid_receive_ready(uint8_t dev_addr, uint8_t idx); // Try to receive next report on Interrupt Endpoint. Immediately return // - true If succeeded, tuh_hid_report_received_cb() callback will be invoked when report is available // - false if failed to queue the transfer e.g endpoint is busy -bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance); +bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t idx); + +// Check if HID interface is ready to send report +bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx); // Send report using interrupt endpoint // If report_id > 0 (composite), it will be sent as 1st byte, then report contents. Otherwise only report content is sent. -//void tuh_hid_send_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t const* report, uint16_t len); +bool tuh_hid_send_report(uint8_t dev_addr, uint8_t idx, uint8_t report_id, const void* report, uint16_t len); //--------------------------------------------------------------------+ // Callbacks (Weak is optional) @@ -117,24 +133,24 @@ bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance); // can be used to parse common/simple enough descriptor. // Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped // therefore report_desc = NULL, desc_len = 0 -void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report_desc, uint16_t desc_len); +TU_ATTR_WEAK void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report_desc, uint16_t desc_len); // Invoked when device with hid interface is un-mounted -TU_ATTR_WEAK void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance); +TU_ATTR_WEAK void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t idx); // Invoked when received report from device via interrupt endpoint // Note: if there is report ID (composite), it is 1st byte of report -void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len); // Invoked when sent report to device successfully via interrupt endpoint -TU_ATTR_WEAK void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); +TU_ATTR_WEAK void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len); // Invoked when Sent Report to device via either control endpoint // len = 0 indicate there is error in the transfer e.g stalled response -TU_ATTR_WEAK void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len); +TU_ATTR_WEAK void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len); // Invoked when Set Protocol request is complete -TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t protocol); +TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t protocol); //--------------------------------------------------------------------+ // Internal Class Driver API diff --git a/test-devices/composite-stm32/lib/tinyusb/class/midi/midi.h b/test-devices/composite-stm32/lib/tinyusb/class/midi/midi.h index 74dc4174..8ddcdfda 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/midi/midi.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/midi/midi.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -71,8 +71,8 @@ typedef enum MIDI_CIN_SYSEX_END_1BYTE = 5, // SysEx ends with 1 data, or 1 byte system common message MIDI_CIN_SYSEX_END_2BYTE = 6, // SysEx ends with 2 data MIDI_CIN_SYSEX_END_3BYTE = 7, // SysEx ends with 3 data - MIDI_CIN_NOTE_ON = 8, - MIDI_CIN_NOTE_OFF = 9, + MIDI_CIN_NOTE_OFF = 8, + MIDI_CIN_NOTE_ON = 9, MIDI_CIN_POLY_KEYPRESS = 10, MIDI_CIN_CONTROL_CHANGE = 11, MIDI_CIN_PROGRAM_CHANGE = 12, diff --git a/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.c b/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.c index de41706e..e3e7826d 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -182,7 +182,7 @@ uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, ui uint8_t const count = (uint8_t) tu_min32(stream->total - stream->index, bufsize); // Skip the header (1st byte) in the buffer - memcpy(buf8, stream->buffer + 1 + stream->index, count); + TU_VERIFY(0 == tu_memcpy_s(buf8, bufsize, stream->buffer + 1 + stream->index, count)); total_read += count; stream->index += count; @@ -261,11 +261,11 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* stream->buffer[1] = data; // Check to see if we're still in a SysEx transmit. - if ( stream->buffer[0] == MIDI_CIN_SYSEX_START ) + if ( ((stream->buffer[0]) & 0xF) == MIDI_CIN_SYSEX_START ) { if ( data == MIDI_STATUS_SYSEX_END ) { - stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; + stream->buffer[0] = (uint8_t) ((cable_num << 4) | MIDI_CIN_SYSEX_END_1BYTE); stream->total = 2; } else @@ -308,6 +308,7 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; stream->total = 2; } + stream->buffer[0] |= (uint8_t)(cable_num << 4); } else { @@ -328,9 +329,9 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* stream->index++; // See if this byte ends a SysEx. - if ( stream->buffer[0] == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END ) + if ( (stream->buffer[0] & 0xF) == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END ) { - stream->buffer[0] = MIDI_CIN_SYSEX_START + (stream->index - 1); + stream->buffer[0] = (uint8_t) ((cable_num << 4) | (MIDI_CIN_SYSEX_START + (stream->index - 1))); stream->total = stream->index; } } diff --git a/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.h b/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.h index 211edc8d..1c6f996b 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) diff --git a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc.h b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc.h index 84b6e4d7..7f25a29b 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) diff --git a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.c b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.c index 00b0a1d0..159a1125 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.c @@ -71,8 +71,8 @@ typedef struct uint8_t add_sense_qualifier; }mscd_interface_t; -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static mscd_interface_t _mscd_itf; -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _mscd_buf[CFG_TUD_MSC_EP_BUFSIZE]; +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static mscd_interface_t _mscd_itf; +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t _mscd_buf[CFG_TUD_MSC_EP_BUFSIZE]; //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION @@ -202,7 +202,7 @@ uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw) //--------------------------------------------------------------------+ #if CFG_TUSB_DEBUG >= 2 -TU_ATTR_UNUSED static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] = +TU_ATTR_UNUSED tu_static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] = { { .key = SCSI_CMD_TEST_UNIT_READY , .data = "Test Unit Ready" }, { .key = SCSI_CMD_INQUIRY , .data = "Inquiry" }, @@ -217,7 +217,7 @@ TU_ATTR_UNUSED static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] = { .key = SCSI_CMD_WRITE_10 , .data = "Write10" } }; -TU_ATTR_UNUSED static tu_lookup_table_t const _msc_scsi_cmd_table = +TU_ATTR_UNUSED tu_static tu_lookup_table_t const _msc_scsi_cmd_table = { .count = TU_ARRAY_SIZE(_msc_scsi_cmd_lookup), .items = _msc_scsi_cmd_lookup @@ -707,7 +707,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ read_capa10.block_size = tu_htonl(block_size); resplen = sizeof(read_capa10); - memcpy(buffer, &read_capa10, (size_t) resplen); + TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &read_capa10, (size_t) resplen)); } } break; @@ -741,7 +741,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ read_fmt_capa.block_size_u16 = tu_htons(block_size); resplen = sizeof(read_fmt_capa); - memcpy(buffer, &read_fmt_capa, (size_t) resplen); + TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &read_fmt_capa, (size_t) resplen)); } } break; @@ -764,7 +764,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ tud_msc_inquiry_cb(lun, inquiry_rsp.vendor_id, inquiry_rsp.product_id, inquiry_rsp.product_rev); resplen = sizeof(inquiry_rsp); - memcpy(buffer, &inquiry_rsp, (size_t) resplen); + TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &inquiry_rsp, (size_t) resplen)); } break; @@ -788,7 +788,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ mode_resp.write_protected = !writable; resplen = sizeof(mode_resp); - memcpy(buffer, &mode_resp, (size_t) resplen); + TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &mode_resp, (size_t) resplen)); } break; @@ -806,7 +806,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ sense_rsp.add_sense_qualifier = p_msc->add_sense_qualifier; resplen = sizeof(sense_rsp); - memcpy(buffer, &sense_rsp, (size_t) resplen); + TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &sense_rsp, (size_t) resplen)); // request sense callback could overwrite the sense data if (tud_msc_request_sense_cb) diff --git a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.h b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.h index 5839b168..72f95be0 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) diff --git a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.c b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.c index 934f79ff..1b48813e 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -33,6 +33,11 @@ #include "msc_host.h" +// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message +#define MSCH_DEBUG 2 + +#define TU_LOG_MSCH(...) TU_LOG(MSCH_DEBUG, __VA_ARGS__) + //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ @@ -64,16 +69,17 @@ typedef struct uint8_t stage; void* buffer; tuh_msc_complete_cb_t complete_cb; + uintptr_t complete_arg; - msc_cbw_t cbw; - msc_csw_t csw; + CFG_TUH_MEM_ALIGN msc_cbw_t cbw; + CFG_TUH_MEM_ALIGN msc_csw_t csw; }msch_interface_t; -CFG_TUSB_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUH_DEVICE_MAX]; +CFG_TUH_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUH_DEVICE_MAX]; // buffer used to read scsi information when mounted // largest response data currently is inquiry TODO Inquiry is not part of enum anymore -CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) +CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN static uint8_t _msch_buffer[sizeof(scsi_inquiry_resp_t)]; TU_ATTR_ALWAYS_INLINE @@ -126,7 +132,7 @@ static inline void cbw_init(msc_cbw_t *cbw, uint8_t lun) cbw->lun = lun; } -bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->configured); @@ -137,13 +143,14 @@ bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tu p_msc->stage = MSC_STAGE_CMD; p_msc->buffer = data; p_msc->complete_cb = complete_cb; + p_msc->complete_arg = arg; TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t))); return true; } -bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->configured); @@ -156,10 +163,10 @@ bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_r cbw.cmd_len = sizeof(scsi_read_capacity10_t); cbw.command[0] = SCSI_CMD_READ_CAPACITY_10; - return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb); + return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg); } -bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->mounted); @@ -178,10 +185,10 @@ bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* respons }; memcpy(cbw.command, &cmd_inquiry, cbw.cmd_len); - return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb); + return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg); } -bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->configured); @@ -195,10 +202,10 @@ bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_ cbw.command[0] = SCSI_CMD_TEST_UNIT_READY; cbw.command[1] = lun; // according to wiki TODO need verification - return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb); + return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb, arg); } -bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msc_cbw_t cbw; cbw_init(&cbw, lun); @@ -215,34 +222,34 @@ bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_ms memcpy(cbw.command, &cmd_request_sense, cbw.cmd_len); - return tuh_msc_scsi_command(dev_addr, &cbw, resposne, complete_cb); + return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg); } -bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->mounted); msc_cbw_t cbw; cbw_init(&cbw, lun); - + cbw.total_bytes = block_count*p_msc->capacity[lun].block_size; cbw.dir = TUSB_DIR_IN_MASK; cbw.cmd_len = sizeof(scsi_read10_t); - + scsi_read10_t const cmd_read10 = { .cmd_code = SCSI_CMD_READ_10, .lba = tu_htonl(lba), .block_count = tu_htons(block_count) }; - + memcpy(cbw.command, &cmd_read10, cbw.cmd_len); - - return tuh_msc_scsi_command(dev_addr, &cbw, buffer, complete_cb); + + return tuh_msc_scsi_command(dev_addr, &cbw, buffer, complete_cb, arg); } - -bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb) + +bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->mounted); @@ -263,7 +270,7 @@ bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_ memcpy(cbw.command, &cmd_write10, cbw.cmd_len); - return tuh_msc_scsi_command(dev_addr, &cbw, (void*)(uintptr_t) buffer, complete_cb); + return tuh_msc_scsi_command(dev_addr, &cbw, (void*)(uintptr_t) buffer, complete_cb, arg); } #if 0 @@ -344,7 +351,17 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32 // SCSI op is complete p_msc->stage = MSC_STAGE_IDLE; - if (p_msc->complete_cb) p_msc->complete_cb(dev_addr, cbw, csw); + if (p_msc->complete_cb) + { + tuh_msc_complete_data_t const cb_data = + { + .cbw = cbw, + .csw = csw, + .scsi_data = p_msc->buffer, + .user_arg = p_msc->complete_arg + }; + p_msc->complete_cb(dev_addr, &cb_data); + } break; // unknown state @@ -359,9 +376,9 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32 //--------------------------------------------------------------------+ static void config_get_maxlun_complete (tuh_xfer_t* xfer); -static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); -static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); -static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); +static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data); +static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); +static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) { @@ -405,7 +422,7 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) p_msc->configured = true; //------------- Get Max Lun -------------// - TU_LOG2("MSC Get Max Lun\r\n"); + TU_LOG_MSCH("MSC Get Max Lun\r\n"); tusb_control_request_t const request = { .bmRequestType_bit = @@ -444,39 +461,48 @@ static void config_get_maxlun_complete (tuh_xfer_t* xfer) p_msc->max_lun++; // MAX LUN is minus 1 by specs // TODO multiple LUN support - TU_LOG2("SCSI Test Unit Ready\r\n"); + TU_LOG_MSCH("SCSI Test Unit Ready\r\n"); uint8_t const lun = 0; - tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete); + tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete, 0); } -static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) { + msc_cbw_t const* cbw = cb_data->cbw; + msc_csw_t const* csw = cb_data->csw; + if (csw->status == 0) { // Unit is ready, read its capacity - TU_LOG2("SCSI Read Capacity\r\n"); - tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete); + TU_LOG_MSCH("SCSI Read Capacity\r\n"); + tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete, 0); }else { // Note: During enumeration, some device fails Test Unit Ready and require a few retries // with Request Sense to start working !! // TODO limit number of retries - TU_LOG2("SCSI Request Sense\r\n"); - TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, _msch_buffer, config_request_sense_complete)); + TU_LOG_MSCH("SCSI Request Sense\r\n"); + TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, _msch_buffer, config_request_sense_complete, 0)); } return true; } -static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) { + msc_cbw_t const* cbw = cb_data->cbw; + msc_csw_t const* csw = cb_data->csw; + TU_ASSERT(csw->status == 0); - TU_ASSERT(tuh_msc_test_unit_ready(dev_addr, cbw->lun, config_test_unit_ready_complete)); + TU_ASSERT(tuh_msc_test_unit_ready(dev_addr, cbw->lun, config_test_unit_ready_complete, 0)); return true; } -static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) { + msc_cbw_t const* cbw = cb_data->cbw; + msc_csw_t const* csw = cb_data->csw; + TU_ASSERT(csw->status == 0); msch_interface_t* p_msc = get_itf(dev_addr); diff --git a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.h b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.h index 7718ad4f..6c0e5c9d 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -41,7 +41,14 @@ #define CFG_TUH_MSC_MAXLUN 4 #endif -typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); +typedef struct { + msc_cbw_t const* cbw; // SCSI command + msc_csw_t const* csw; // SCSI status + void* scsi_data; // SCSI Data + uintptr_t user_arg; // user argument +}tuh_msc_complete_data_t; + +typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); //--------------------------------------------------------------------+ // Application API @@ -66,33 +73,33 @@ uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun); // Perform a full SCSI command (cbw, data, csw) in non-blocking manner. // Complete callback is invoked when SCSI op is complete. // return true if success, false if there is already pending operation. -bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Inquiry command // Complete callback is invoked when SCSI op is complete. -bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Test Unit Ready command // Complete callback is invoked when SCSI op is complete. -bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Request Sense 10 command // Complete callback is invoked when SCSI op is complete. -bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Read 10 command. Read n blocks starting from LBA to buffer // Complete callback is invoked when SCSI op is complete. -bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Write 10 command. Write n blocks starting from LBA to device // Complete callback is invoked when SCSI op is complete. -bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Read Capacity 10 command // Complete callback is invoked when SCSI op is complete. // Note: during enumeration, host stack already carried out this request. Application can retrieve capacity by // simply call tuh_msc_get_block_count() and tuh_msc_get_block_size() -bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); //------------- Application Callback -------------// diff --git a/test-devices/composite-stm32/lib/tinyusb/class/net/ecm_rndis_device.c b/test-devices/composite-stm32/lib/tinyusb/class/net/ecm_rndis_device.c index 5f316762..8ac7cbd0 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/net/ecm_rndis_device.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/net/ecm_rndis_device.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2020 Peter Lawrence @@ -51,7 +51,7 @@ typedef struct bool ecm_mode; - // Endpoint descriptor use to open/close when receving SetInterface + // Endpoint descriptor use to open/close when receiving SetInterface // TODO since configuration descriptor may not be long-lived memory, we should // keep a copy of endpoint attribute instead uint8_t const * ecm_desc_epdata; @@ -61,8 +61,11 @@ typedef struct #define CFG_TUD_NET_PACKET_PREFIX_LEN sizeof(rndis_data_packet_t) #define CFG_TUD_NET_PACKET_SUFFIX_LEN 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t received[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t transmitted[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static +uint8_t received[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static +uint8_t transmitted[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; struct ecm_notify_struct { @@ -70,7 +73,7 @@ struct ecm_notify_struct uint32_t downlink, uplink; }; -static const struct ecm_notify_struct ecm_notify_nc = +tu_static const struct ecm_notify_struct ecm_notify_nc = { .header = { .bmRequestType = 0xA1, @@ -80,7 +83,7 @@ static const struct ecm_notify_struct ecm_notify_nc = }, }; -static const struct ecm_notify_struct ecm_notify_csc = +tu_static const struct ecm_notify_struct ecm_notify_csc = { .header = { .bmRequestType = 0xA1, @@ -92,7 +95,7 @@ static const struct ecm_notify_struct ecm_notify_csc = }; // TODO remove CFG_TUSB_MEM_SECTION, control internal buffer is already in this special section -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static union +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static union { uint8_t rndis_buf[120]; struct ecm_notify_struct ecm_buf; @@ -102,9 +105,9 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static union // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ // TODO remove CFG_TUSB_MEM_SECTION -CFG_TUSB_MEM_SECTION static netd_interface_t _netd_itf; +CFG_TUSB_MEM_SECTION tu_static netd_interface_t _netd_itf; -static bool can_xmit; +tu_static bool can_xmit; void tud_network_recv_renew(void) { diff --git a/test-devices/composite-stm32/lib/tinyusb/class/net/ncm_device.c b/test-devices/composite-stm32/lib/tinyusb/class/net/ncm_device.c index 00892b49..9e958024 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/net/ncm_device.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/net/ncm_device.c @@ -130,7 +130,7 @@ typedef struct // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static const ntb_parameters_t ntb_parameters = { +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static const ntb_parameters_t ntb_parameters = { .wLength = sizeof(ntb_parameters_t), .bmNtbFormatsSupported = 0x01, .dwNtbInMaxSize = CFG_TUD_NCM_IN_NTB_MAX_SIZE, @@ -145,11 +145,11 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static const ntb_parameters_t ntb_parame .wNtbOutMaxDatagrams = 0 }; -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static transmit_ntb_t transmit_ntb[2]; +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static transmit_ntb_t transmit_ntb[2]; -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t receive_ntb[CFG_TUD_NCM_OUT_NTB_MAX_SIZE]; +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t receive_ntb[CFG_TUD_NCM_OUT_NTB_MAX_SIZE]; -static ncm_interface_t ncm_interface; +tu_static ncm_interface_t ncm_interface; /* * Set up the NTB state in ncm_interface to be ready to add datagrams. @@ -196,7 +196,7 @@ static void ncm_start_tx(void) { ncm_prepare_for_tx(); } -static struct ecm_notify_struct ncm_notify_connected = +tu_static struct ecm_notify_struct ncm_notify_connected = { .header = { .bmRequestType_bit = { @@ -210,7 +210,7 @@ static struct ecm_notify_struct ncm_notify_connected = }, }; -static struct ecm_notify_struct ncm_notify_speed_change = +tu_static struct ecm_notify_struct ncm_notify_speed_change = { .header = { .bmRequestType_bit = { @@ -392,7 +392,7 @@ bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t if (NCM_GET_NTB_PARAMETERS == request->bRequest) { - tud_control_xfer(rhport, request, (void*)&ntb_parameters, sizeof(ntb_parameters)); + tud_control_xfer(rhport, request, (void*)(uintptr_t) &ntb_parameters, sizeof(ntb_parameters)); } break; @@ -430,7 +430,7 @@ static void handle_incoming_datagram(uint32_t len) { ncm_interface.num_datagrams++; } - + tud_network_recv_renew(); } diff --git a/test-devices/composite-stm32/lib/tinyusb/class/net/net_device.h b/test-devices/composite-stm32/lib/tinyusb/class/net/net_device.h index 6e294465..39991635 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/net/net_device.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/net/net_device.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2020 Peter Lawrence @@ -94,7 +94,7 @@ void tud_network_init_cb(void); // client must provide this: 48-bit MAC address // TODO removed later since it is not part of tinyusb stack -extern const uint8_t tud_network_mac_address[6]; +extern uint8_t tud_network_mac_address[6]; //------------- NCM -------------// diff --git a/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc.h b/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc.h index e7016ae2..090ab3c4 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc.h @@ -158,7 +158,7 @@ enum { USBTMC_BULK_IN_ERR_DATA_TOO_SHORT = 4u, USBTMC_BULK_IN_ERR_DATA_TOO_LONG = 5u, }; -// bult-in halt errors +// built-in halt errors enum { USBTMC_BULK_IN_ERR = 1u, ///< receives a USBTMC command message that expects a response while a /// Bulk-IN transfer is in progress @@ -262,14 +262,14 @@ typedef struct TU_ATTR_PACKED struct TU_ATTR_PACKED { - unsigned int listenOnly :1; - unsigned int talkOnly :1; - unsigned int supportsIndicatorPulse :1; + uint8_t listenOnly :1; + uint8_t talkOnly :1; + uint8_t supportsIndicatorPulse :1; } bmIntfcCapabilities; struct TU_ATTR_PACKED { - unsigned int canEndBulkInOnTermChar :1; + uint8_t canEndBulkInOnTermChar :1; } bmDevCapabilities; uint8_t _reserved2[6]; @@ -277,17 +277,17 @@ typedef struct TU_ATTR_PACKED struct TU_ATTR_PACKED { - unsigned int is488_2 :1; - unsigned int supportsREN_GTL_LLO :1; - unsigned int supportsTrigger :1; + uint8_t supportsTrigger :1; + uint8_t supportsREN_GTL_LLO :1; + uint8_t is488_2 :1; } bmIntfcCapabilities488; struct TU_ATTR_PACKED { - unsigned int SCPI :1; - unsigned int SR1 :1; - unsigned int RL1 :1; - unsigned int DT1 :1; + uint8_t DT1 :1; + uint8_t RL1 :1; + uint8_t SR1 :1; + uint8_t SCPI :1; } bmDevCapabilities488; uint8_t _reserved3[8]; } usbtmc_response_capabilities_488_t; @@ -316,4 +316,3 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_interrupt_488_t) == 2u, "struct wrong length"); #endif - diff --git a/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c b/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c index af4a9273..4e320a77 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c @@ -78,12 +78,12 @@ #ifdef xDEBUG #include "uart_util.h" -static char logMsg[150]; +tu_static char logMsg[150]; #endif // Buffer size must be an exact multiple of the max packet size for both // bulk (up to 64 bytes for FS, 512 bytes for HS). In addation, this driver -// imposes a minimum buffer size of 32 bytes. +// imposes a minimum buffer size of 32 bytes. #define USBTMCD_BUFFER_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) /* @@ -143,7 +143,7 @@ typedef struct usbtmc_capabilities_specific_t const * capabilities; } usbtmc_interface_state_t; -CFG_TUSB_MEM_SECTION static usbtmc_interface_state_t usbtmc_state = +CFG_TUSB_MEM_SECTION tu_static usbtmc_interface_state_t usbtmc_state = { .itf_id = 0xFF, }; @@ -154,15 +154,20 @@ TU_VERIFY_STATIC(USBTMCD_BUFFER_SIZE >= 32u,"USBTMC dev buffer size too small"); static bool handle_devMsgOutStart(uint8_t rhport, void *data, size_t len); static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t packetLen); -static uint8_t termChar; -static uint8_t termCharRequested = false; +#ifndef NDEBUG +tu_static uint8_t termChar; +#endif -osal_mutex_def_t usbtmcLockBuffer; -static osal_mutex_t usbtmcLock; +tu_static uint8_t termCharRequested = false; + +#if OSAL_MUTEX_REQUIRED +static OSAL_MUTEX_DEF(usbtmcLockBuffer); +#endif +osal_mutex_t usbtmcLock; // Our own private lock, mostly for the state variable. -#define criticalEnter() do {osal_mutex_lock(usbtmcLock,OSAL_TIMEOUT_WAIT_FOREVER); } while (0) -#define criticalLeave() do {osal_mutex_unlock(usbtmcLock); } while (0) +#define criticalEnter() do { (void) osal_mutex_lock(usbtmcLock,OSAL_TIMEOUT_WAIT_FOREVER); } while (0) +#define criticalLeave() do { (void) osal_mutex_unlock(usbtmcLock); } while (0) bool atomicChangeState(usbtmcd_state_enum expectedState, usbtmcd_state_enum newState) { @@ -362,9 +367,9 @@ bool tud_usbtmc_start_bus_read() case STATE_RCV: break; default: - TU_VERIFY(false); + return false; } - TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, 64)); + TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, (uint16_t)usbtmc_state.ep_bulk_out_wMaxPacketSize)); return true; } @@ -440,7 +445,10 @@ static bool handle_devMsgIn(void *data, size_t len) usbtmc_state.transfer_size_sent = 0u; termCharRequested = msg->bmTransferAttributes.TermCharEnabled; + +#ifndef NDEBUG termChar = msg->TermChar; +#endif if(termCharRequested) TU_VERIFY(usbtmc_state.capabilities->bmDevCapabilities.canEndBulkInOnTermChar); @@ -464,53 +472,53 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint switch(usbtmc_state.state) { case STATE_IDLE: - TU_VERIFY(xferred_bytes >= sizeof(usbtmc_msg_generic_t)); - msg = (usbtmc_msg_generic_t*)(usbtmc_state.ep_bulk_out_buf); - uint8_t invInvTag = (uint8_t)~(msg->header.bTagInverse); - TU_VERIFY(msg->header.bTag == invInvTag); - TU_VERIFY(msg->header.bTag != 0x00); - - switch(msg->header.MsgID) { - case USBTMC_MSGID_DEV_DEP_MSG_OUT: - if(!handle_devMsgOutStart(rhport, msg, xferred_bytes)) - { - usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); - TU_VERIFY(false); - } - break; + { + TU_VERIFY(xferred_bytes >= sizeof(usbtmc_msg_generic_t)); + msg = (usbtmc_msg_generic_t*)(usbtmc_state.ep_bulk_out_buf); + uint8_t invInvTag = (uint8_t)~(msg->header.bTagInverse); + TU_VERIFY(msg->header.bTag == invInvTag); + TU_VERIFY(msg->header.bTag != 0x00); + + switch(msg->header.MsgID) { + case USBTMC_MSGID_DEV_DEP_MSG_OUT: + if(!handle_devMsgOutStart(rhport, msg, xferred_bytes)) + { + usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); + return false; + } + break; - case USBTMC_MSGID_DEV_DEP_MSG_IN: - TU_VERIFY(handle_devMsgIn(msg, xferred_bytes)); - break; + case USBTMC_MSGID_DEV_DEP_MSG_IN: + TU_VERIFY(handle_devMsgIn(msg, xferred_bytes)); + break; #if (CFG_TUD_USBTMC_ENABLE_488) - case USBTMC_MSGID_USB488_TRIGGER: - // Spec says we halt the EP if we didn't declare we support it. - TU_VERIFY(usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger); - TU_VERIFY(tud_usbtmc_msg_trigger_cb(msg)); + case USBTMC_MSGID_USB488_TRIGGER: + // Spec says we halt the EP if we didn't declare we support it. + TU_VERIFY(usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger); + TU_VERIFY(tud_usbtmc_msg_trigger_cb(msg)); - break; + break; #endif - case USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT: - case USBTMC_MSGID_VENDOR_SPECIFIC_IN: - default: - usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); - TU_VERIFY(false); - return false; + case USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT: + case USBTMC_MSGID_VENDOR_SPECIFIC_IN: + default: + usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); + return false; + } + return true; } - return true; - case STATE_RCV: if(!handle_devMsgOut(rhport, usbtmc_state.ep_bulk_out_buf, xferred_bytes, xferred_bytes)) { usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); - TU_VERIFY(false); + return false; } return true; case STATE_ABORTING_BULK_OUT: - TU_VERIFY(false); - return false; // Should be stalled by now, shouldn't have received a packet. + // Should be stalled by now, shouldn't have received a packet. + return false; case STATE_TX_REQUESTED: case STATE_TX_INITIATED: @@ -518,7 +526,7 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint case STATE_ABORTING_BULK_IN_SHORTED: case STATE_ABORTING_BULK_IN_ABORTED: default: - TU_VERIFY(false); + return false; } } else if(ep_addr == usbtmc_state.ep_bulk_in) @@ -567,7 +575,6 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint default: TU_ASSERT(false); - return false; } } else if (ep_addr == usbtmc_state.ep_int_in) { @@ -598,8 +605,8 @@ bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request uint32_t ep_addr = (request->wIndex); // At this point, a transfer MAY be in progress. Based on USB spec, when clearing bulk EP HALT, - // the EP transfer buffer needs to be cleared and DTOG needs to be reset, even if - // the EP is not halted. The only USBD API interface to do this is to stall and then unstall the EP. + // the EP transfer buffer needs to be cleared and DTOG needs to be reset, even if + // the EP is not halted. The only USBD API interface to do this is to stall and then un-stall the EP. if(ep_addr == usbtmc_state.ep_bulk_out) { criticalEnter(); @@ -871,16 +878,13 @@ bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request case USB488_bREQUEST_LOCAL_LOCKOUT: { TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface - TU_VERIFY(false); return false; } #endif default: - TU_VERIFY(false); return false; } - TU_VERIFY(false); } #endif /* CFG_TUD_TSMC */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h b/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h index 144b3315..c1298ddb 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h @@ -36,7 +36,7 @@ #endif /*********************************************** - * Functions to be implemeted by the class implementation + * Functions to be implemented by the class implementation */ // In order to proceed, app must call call tud_usbtmc_start_bus_read(rhport) during or soon after: diff --git a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.c b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.c index 3b81a108..93596ee3 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.c @@ -59,7 +59,7 @@ typedef struct CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_VENDOR_EPSIZE]; } vendord_interface_t; -CFG_TUSB_MEM_SECTION static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR]; +CFG_TUSB_MEM_SECTION tu_static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR]; #define ITF_MEM_RESET_SIZE offsetof(vendord_interface_t, rx_ff) @@ -86,8 +86,8 @@ static void _prep_out_transaction (vendord_interface_t* p_itf) { uint8_t const rhport = 0; - // skip if previous transfer not complete - if ( usbd_edpt_busy(rhport, p_itf->ep_out) ) return; + // claim endpoint + TU_VERIFY(usbd_edpt_claim(rhport, p_itf->ep_out), ); // Prepare for incoming data but only allow what we can store in the ring buffer. uint16_t max_read = tu_fifo_remaining(&p_itf->rx_ff); @@ -95,6 +95,11 @@ static void _prep_out_transaction (vendord_interface_t* p_itf) { usbd_edpt_xfer(rhport, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE); } + else + { + // Release endpoint since we don't make any transfer + usbd_edpt_release(rhport, p_itf->ep_out); + } } uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize) @@ -115,37 +120,47 @@ void tud_vendor_n_read_flush (uint8_t itf) //--------------------------------------------------------------------+ // Write API //--------------------------------------------------------------------+ -static uint16_t maybe_transmit(vendord_interface_t* p_itf) -{ - uint8_t const rhport = 0; - - // skip if previous transfer not complete - TU_VERIFY( !usbd_edpt_busy(rhport, p_itf->ep_in) ); - - uint16_t count = tu_fifo_read_n(&p_itf->tx_ff, p_itf->epin_buf, CFG_TUD_VENDOR_EPSIZE); - if (count > 0) - { - TU_ASSERT( usbd_edpt_xfer(rhport, p_itf->ep_in, p_itf->epin_buf, count) ); - } - return count; -} - uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize) { vendord_interface_t* p_itf = &_vendord_itf[itf]; uint16_t ret = tu_fifo_write_n(&p_itf->tx_ff, buffer, (uint16_t) bufsize); + + // flush if queue more than packet size if (tu_fifo_count(&p_itf->tx_ff) >= CFG_TUD_VENDOR_EPSIZE) { - maybe_transmit(p_itf); + tud_vendor_n_write_flush(itf); } return ret; } -uint32_t tud_vendor_n_flush (uint8_t itf) +uint32_t tud_vendor_n_write_flush (uint8_t itf) { vendord_interface_t* p_itf = &_vendord_itf[itf]; - uint32_t ret = maybe_transmit(p_itf); - return ret; + // Skip if usb is not ready yet + TU_VERIFY( tud_ready(), 0 ); + + // No data to send + if ( !tu_fifo_count(&p_itf->tx_ff) ) return 0; + + uint8_t const rhport = 0; + + // Claim the endpoint + TU_VERIFY( usbd_edpt_claim(rhport, p_itf->ep_in), 0 ); + + // Pull data from FIFO + uint16_t const count = tu_fifo_read_n(&p_itf->tx_ff, p_itf->epin_buf, sizeof(p_itf->epin_buf)); + + if ( count ) + { + TU_ASSERT( usbd_edpt_xfer(rhport, p_itf->ep_in, p_itf->epin_buf, count), 0 ); + return count; + }else + { + // Release endpoint since we don't make any transfer + // Note: data is dropped if terminal is not connected + usbd_edpt_release(rhport, p_itf->ep_in); + return 0; + } } uint32_t tud_vendor_n_write_available (uint8_t itf) @@ -225,10 +240,10 @@ uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, ui // Prepare for incoming data if ( p_vendor->ep_out ) { - TU_ASSERT(usbd_edpt_xfer(rhport, p_vendor->ep_out, p_vendor->epout_buf, sizeof(p_vendor->epout_buf)), 0); + _prep_out_transaction(p_vendor); } - if ( p_vendor->ep_in ) maybe_transmit(p_vendor); + if ( p_vendor->ep_in ) tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); } return (uint16_t) ((uintptr_t) p_desc - (uintptr_t) desc_itf); @@ -263,7 +278,7 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint { if (tud_vendor_tx_cb) tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes); // Send complete, try to send more if possible - maybe_transmit(p_itf); + tud_vendor_n_write_flush(itf); } return true; diff --git a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.h b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.h index 4a873e5f..d239406b 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -48,11 +48,13 @@ bool tud_vendor_n_peek (uint8_t itf, uint8_t* ui8); void tud_vendor_n_read_flush (uint8_t itf); uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize); +uint32_t tud_vendor_n_write_flush (uint8_t itf); uint32_t tud_vendor_n_write_available (uint8_t itf); -static inline -uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str); -uint32_t tud_vendor_n_flush (uint8_t itf); +static inline uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str); + +// backward compatible +#define tud_vendor_n_flush(itf) tud_vendor_n_write_flush(itf) //--------------------------------------------------------------------+ // Application API (Single Port) @@ -65,7 +67,10 @@ static inline void tud_vendor_read_flush (void); static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize); static inline uint32_t tud_vendor_write_str (char const* str); static inline uint32_t tud_vendor_write_available (void); -static inline uint32_t tud_vendor_flush (void); +static inline uint32_t tud_vendor_write_flush (void); + +// backward compatible +#define tud_vendor_flush() tud_vendor_write_flush() //--------------------------------------------------------------------+ // Application Callback API (weak is optional) @@ -115,6 +120,11 @@ static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize) return tud_vendor_n_write(0, buffer, bufsize); } +static inline uint32_t tud_vendor_write_flush (void) +{ + return tud_vendor_n_write_flush(0); +} + static inline uint32_t tud_vendor_write_str (char const* str) { return tud_vendor_n_write_str(0, str); @@ -125,11 +135,6 @@ static inline uint32_t tud_vendor_write_available (void) return tud_vendor_n_write_available(0); } -static inline uint32_t tud_vendor_flush (void) -{ - return tud_vendor_n_flush(0); -} - //--------------------------------------------------------------------+ // Internal Class Driver API //--------------------------------------------------------------------+ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.c b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.c index dbea1228..e66c5007 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) diff --git a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.h b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.h index 65223fbc..acfebe7a 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) diff --git a/test-devices/composite-stm32/lib/tinyusb/class/video/video.h b/test-devices/composite-stm32/lib/tinyusb/class/video/video.h index 84474654..c0088c4f 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/video/video.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/video/video.h @@ -302,6 +302,45 @@ typedef struct TU_ATTR_PACKED { uint8_t bCopyProtect; } tusb_desc_cs_video_fmt_uncompressed_t; +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFormatIndex; + uint8_t bNumFrameDescriptors; + uint8_t bmFlags; + uint8_t bDefaultFrameIndex; + uint8_t bAspectRatioX; + uint8_t bAspectRatioY; + uint8_t bmInterlaceFlags; + uint8_t bCopyProtect; +} tusb_desc_cs_video_fmt_mjpeg_t; + +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFormatIndex; + uint32_t dwMaxVideoFrameBufferSize; /* deprecated */ + uint8_t bFormatType; +} tusb_desc_cs_video_fmt_dv_t; + +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFormatIndex; + uint8_t bNumFrameDescriptors; + uint8_t guidFormat[16]; + uint8_t bBitsPerPixel; + uint8_t bDefaultFrameIndex; + uint8_t bAspectRatioX; + uint8_t bAspectRatioY; + uint8_t bmInterlaceFlags; + uint8_t bCopyProtect; + uint8_t bVaribaleSize; +} tusb_desc_cs_video_fmt_frame_based_t; + typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType; @@ -318,6 +357,24 @@ typedef struct TU_ATTR_PACKED { uint32_t dwFrameInterval[]; } tusb_desc_cs_video_frm_uncompressed_t; +typedef tusb_desc_cs_video_frm_uncompressed_t tusb_desc_cs_video_frm_mjpeg_t; + +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFrameIndex; + uint8_t bmCapabilities; + uint16_t wWidth; + uint16_t wHeight; + uint32_t dwMinBitRate; + uint32_t dwMaxBitRate; + uint32_t dwDefaultFrameInterval; + uint8_t bFrameIntervalType; + uint32_t dwBytesPerLine; + uint32_t dwFrameInterval[]; +} tusb_desc_cs_video_frm_frame_based_t; + //--------------------------------------------------------------------+ // Requests //--------------------------------------------------------------------+ @@ -378,8 +435,11 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c #define TUD_VIDEO_DESC_CS_VS_IN_LEN 13 #define TUD_VIDEO_DESC_CS_VS_OUT_LEN 9 #define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN 27 +#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN 11 #define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN 38 #define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN 26 +#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN 38 +#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN 26 #define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN 6 /* 2.2 compression formats */ @@ -462,6 +522,25 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ +/* Motion-JPEG 3.1.1 Table 3-1 */ +#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG(_fmtidx, _numfrmdesc, _fixed_sz, _frmidx, _asrx, _asry, _interlace, _cp) \ + TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_MJPEG, \ + _fmtidx, _numfrmdesc, _fixed_sz, _frmidx, _asrx, _asry, _interlace, _cp + +/* Motion-JPEG 3.1.1 Table 3-2 and 3-3 */ +#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, _minfrminterval, _maxfrminterval, _frmintervalstep) \ + TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_MJPEG, \ + _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ + U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), 0, \ + U32_TO_U8S_LE(_minfrminterval), U32_TO_U8S_LE(_maxfrminterval), U32_TO_U8S_LE(_frmintervalstep) + +/* Motion-JPEG 3.1.1 Table 3-2 and 3-4 */ +#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, ...) \ + TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN + (TU_ARGS_NUM(__VA_ARGS__)) * 4, \ + TUSB_DESC_CS_INTERFACE, VIDEO_CS_VS_INTERFACE_FRAME_MJPEG, \ + _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ + U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ + /* 3.9.2.6 */ #define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(_color, _trns, _mat) \ TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN, \ @@ -470,7 +549,7 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c /* 3.10.1.1 */ #define TUD_VIDEO_DESC_EP_ISO(_ep, _epsize, _ep_interval) \ - 7, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS,\ + 7, TUSB_DESC_ENDPOINT, _ep, (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS),\ U16_TO_U8S_LE(_epsize), _ep_interval /* 3.10.1.2 */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/video/video_device.c b/test-devices/composite-stm32/lib/tinyusb/class/video/video_device.c index 7636db5f..d6e98602 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/video/video_device.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/video/video_device.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2021 Koji KITAYAMA @@ -59,6 +59,34 @@ typedef struct TU_ATTR_PACKED { uint8_t bEntityId; } tusb_desc_cs_video_entity_itf_t; +typedef union { + struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFormatIndex; + uint8_t bNumFrameDescriptors; + }; + tusb_desc_cs_video_fmt_uncompressed_t uncompressed; + tusb_desc_cs_video_fmt_mjpeg_t mjpeg; + tusb_desc_cs_video_fmt_frame_based_t frame_based; +} tusb_desc_cs_video_fmt_t; + +typedef union { + struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFrameIndex; + uint8_t bmCapabilities; + uint16_t wWidth; + uint16_t wHeight; + }; + tusb_desc_cs_video_frm_uncompressed_t uncompressed; + tusb_desc_cs_video_frm_mjpeg_t mjpeg; + tusb_desc_cs_video_frm_frame_based_t frame_based; +} tusb_desc_cs_video_frm_t; + /* video streaming interface */ typedef struct TU_ATTR_PACKED { uint8_t index_vc; /* index of bound video control interface */ @@ -80,7 +108,7 @@ typedef struct TU_ATTR_PACKED { /* video control interface */ typedef struct TU_ATTR_PACKED { - void const *beg; /* The head of the first video control interface descriptor */ + uint8_t const *beg; /* The head of the first video control interface descriptor */ uint16_t len; /* Byte length of the descriptors */ uint16_t cur; /* offset for current video control interface */ uint8_t stm[CFG_TUD_VIDEO_STREAMING]; /* Indices of streaming interface */ @@ -97,11 +125,11 @@ typedef struct TU_ATTR_PACKED { //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION static videod_interface_t _videod_itf[CFG_TUD_VIDEO]; -CFG_TUSB_MEM_SECTION static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING]; +CFG_TUSB_MEM_SECTION tu_static videod_interface_t _videod_itf[CFG_TUD_VIDEO]; +CFG_TUSB_MEM_SECTION tu_static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING]; -static uint8_t const _cap_get = 0x1u; /* support for GET */ -static uint8_t const _cap_get_set = 0x3u; /* support for GET and SET */ +tu_static uint8_t const _cap_get = 0x1u; /* support for GET */ +tu_static uint8_t const _cap_get_set = 0x3u; /* support for GET and SET */ /** Get interface number from the interface descriptor * @@ -146,7 +174,7 @@ static tusb_desc_vc_itf_t const* _get_desc_vc(videod_interface_t const *self) static tusb_desc_vs_itf_t const* _get_desc_vs(videod_streaming_interface_t const *self) { if (!self->desc.cur) return NULL; - void const *desc = _videod_itf[self->index_vc].beg; + uint8_t const *desc = _videod_itf[self->index_vc].beg; return (tusb_desc_vs_itf_t const*)(desc + self->desc.cur); } @@ -219,9 +247,9 @@ static void const* _next_desc_itf(void const *beg, void const *end) * * @return The pointer for interface descriptor. * @retval end did not found interface descriptor */ -static inline void const* _find_desc_itf(void const *beg, void const *end, uint_fast8_t itfnum, uint_fast8_t altnum) +static inline uint8_t const* _find_desc_itf(void const *beg, void const *end, uint_fast8_t itfnum, uint_fast8_t altnum) { - return _find_desc_3(beg, end, TUSB_DESC_INTERFACE, itfnum, altnum); + return (uint8_t const*) _find_desc_3(beg, end, TUSB_DESC_INTERFACE, itfnum, altnum); } /** Find the first endpoint descriptor belonging to the current interface descriptor. @@ -243,6 +271,13 @@ static void const* _find_desc_ep(void const *beg, void const *end) return end; } +/** Return the end of the video control descriptor. */ +static inline void const* _end_of_control_descriptor(void const *desc) +{ + tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const *)desc; + return ((uint8_t const*) desc) + vc->std.bLength + tu_le16toh(vc->ctl.wTotalLength); +} + /** Find the first entity descriptor with the entity ID * specified by the argument belonging to the current video control descriptor. * @@ -253,10 +288,8 @@ static void const* _find_desc_ep(void const *beg, void const *end) * @retval end did not found interface descriptor */ static void const* _find_desc_entity(void const *desc, uint_fast8_t entityid) { - tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const*)desc; - void const *beg = vc; - void const *end = beg + vc->std.bLength + vc->ctl.wTotalLength; - for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) { + void const *end = _end_of_control_descriptor(desc); + for (void const *cur = desc; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) { tusb_desc_cs_video_entity_itf_t const *itf = (tusb_desc_cs_video_entity_itf_t const *)cur; if ((VIDEO_CS_ITF_VC_INPUT_TERMINAL <= itf->bDescriptorSubtype && itf->bDescriptorSubtype < VIDEO_CS_ITF_VC_MAX) @@ -272,21 +305,42 @@ static void const* _find_desc_entity(void const *desc, uint_fast8_t entityid) static inline void const* _end_of_streaming_descriptor(void const *desc) { tusb_desc_vs_itf_t const *vs = (tusb_desc_vs_itf_t const *)desc; - return desc + vs->std.bLength + vs->stm.wTotalLength; + return ((uint8_t const*) desc) + vs->std.bLength + tu_le16toh(vs->stm.wTotalLength); } /** Find the first format descriptor with the specified format number. */ -static inline tusb_desc_cs_video_fmt_uncompressed_t const *_find_desc_format(void const *beg, void const *end, uint_fast8_t fmtnum) +static inline void const *_find_desc_format(void const *beg, void const *end, uint_fast8_t fmtnum) { - return (tusb_desc_cs_video_fmt_uncompressed_t const*) - _find_desc_3(beg, end, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED, fmtnum); + for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) { + uint8_t const *p = (uint8_t const *)cur; + uint_fast8_t fmt = p[2]; + if ((fmt == VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED || + fmt == VIDEO_CS_ITF_VS_FORMAT_MJPEG || + fmt == VIDEO_CS_ITF_VS_FORMAT_DV || + fmt == VIDEO_CS_ITF_VS_FRAME_FRAME_BASED) && + fmtnum == p[3]) { + return cur; + } + cur = tu_desc_next(cur); + } + return end; } /** Find the first frame descriptor with the specified format number. */ -static inline tusb_desc_cs_video_frm_uncompressed_t const *_find_desc_frame(void const *beg, void const *end, uint_fast8_t frmnum) +static inline void const *_find_desc_frame(void const *beg, void const *end, uint_fast8_t frmnum) { - return (tusb_desc_cs_video_frm_uncompressed_t const*) - _find_desc_3(beg, end, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, frmnum); + for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) { + uint8_t const *p = (uint8_t const *)cur; + uint_fast8_t frm = p[2]; + if ((frm == VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED || + frm == VIDEO_CS_ITF_VS_FRAME_MJPEG || + frm == VIDEO_CS_ITF_VS_FRAME_FRAME_BASED) && + frmnum == p[3]) { + return cur; + } + cur = tu_desc_next(cur); + } + return end; } /** Set uniquely determined values to variables that have not been set @@ -307,7 +361,6 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm /* Set the parameters determined by the format */ param->wKeyFrameRate = 1; param->wPFrameRate = 0; - param->wCompQuality = 1; /* 1 to 10000 */ param->wCompWindowSize = 1; /* GOP size? */ param->wDelay = 0; /* milliseconds */ param->dwClockFrequency = 27000000; /* same as MPEG-2 system time clock */ @@ -319,8 +372,18 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm param->bBitDepthLuma = 8; void const *end = _end_of_streaming_descriptor(vs); - tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); + tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); TU_ASSERT(fmt != end); + + switch (fmt->bDescriptorSubType) { + case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED: + param->wCompQuality = 1; /* 1 to 10000 */ + break; + case VIDEO_CS_ITF_VS_FORMAT_MJPEG: + break; + default: return false; + } + uint_fast8_t frmnum = param->bFrameIndex; TU_ASSERT(frmnum <= fmt->bNumFrameDescriptors); if (!frmnum) { @@ -328,28 +391,39 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm frmnum = 1; param->bFrameIndex = 1; } - tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); + tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); TU_ASSERT(frm != end); /* Set the parameters determined by the frame */ uint_fast32_t frame_size = param->dwMaxVideoFrameSize; if (!frame_size) { - frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->bBitsPerPixel / 8; + switch (fmt->bDescriptorSubType) { + case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED: + frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->uncompressed.bBitsPerPixel / 8; + break; + case VIDEO_CS_ITF_VS_FORMAT_MJPEG: + frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */ + break; + default: break; + } param->dwMaxVideoFrameSize = frame_size; } uint_fast32_t interval = param->dwFrameInterval; if (!interval) { - if ((1 < frm->bFrameIntervalType) || - ((0 == frm->bFrameIntervalType) && (frm->dwFrameInterval[1] != frm->dwFrameInterval[0]))) { + if ((1 < frm->uncompressed.bFrameIntervalType) || + ((0 == frm->uncompressed.bFrameIntervalType) && + (frm->uncompressed.dwFrameInterval[1] != frm->uncompressed.dwFrameInterval[0]))) { return true; } - interval = frm->dwFrameInterval[0]; + interval = frm->uncompressed.dwFrameInterval[0]; param->dwFrameInterval = interval; } uint_fast32_t interval_ms = interval / 10000; TU_ASSERT(interval_ms); uint_fast32_t payload_size = (frame_size + interval_ms - 1) / interval_ms + 2; + if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) + payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE; param->dwMaxPayloadTransferSize = payload_size; return true; } @@ -366,7 +440,8 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * if (!fmtnum) { switch (request) { case VIDEO_REQUEST_GET_MAX: - param->bFormatIndex = _get_desc_vs(stm)->stm.bNumFormats; + if (_get_desc_vs(stm)) + param->bFormatIndex = _get_desc_vs(stm)->stm.bNumFormats; break; case VIDEO_REQUEST_GET_MIN: case VIDEO_REQUEST_GET_DEF: @@ -395,7 +470,7 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); TU_ASSERT(vs); void const *end = _end_of_streaming_descriptor(vs); - tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); + tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); switch (request) { case VIDEO_REQUEST_GET_MAX: frmnum = fmt->bNumFrameDescriptors; @@ -404,14 +479,32 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * frmnum = 1; break; case VIDEO_REQUEST_GET_DEF: - frmnum = fmt->bDefaultFrameIndex; + switch (fmt->bDescriptorSubType) { + case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED: + frmnum = fmt->uncompressed.bDefaultFrameIndex; + break; + case VIDEO_CS_ITF_VS_FORMAT_MJPEG: + frmnum = fmt->mjpeg.bDefaultFrameIndex; + break; + default: return false; + } break; default: return false; } - param->bFrameIndex = (uint8_t) frmnum; + param->bFrameIndex = (uint8_t)frmnum; /* Set the parameters determined by the frame */ - tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); - param->dwMaxVideoFrameSize = (uint32_t) (frm->wWidth * frm->wHeight * fmt->bBitsPerPixel / 8); + tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); + uint_fast32_t frame_size; + switch (fmt->bDescriptorSubType) { + case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED: + frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->uncompressed.bBitsPerPixel / 8; + break; + case VIDEO_CS_ITF_VS_FORMAT_MJPEG: + frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */ + break; + default: return false; + } + param->dwMaxVideoFrameSize = frame_size; return true; } @@ -419,17 +512,17 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); TU_ASSERT(vs); void const *end = _end_of_streaming_descriptor(vs); - tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); - tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); + tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); + tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); uint_fast32_t interval, interval_ms; switch (request) { case VIDEO_REQUEST_GET_MAX: { uint_fast32_t min_interval, max_interval; - uint_fast8_t num_intervals = frm->bFrameIntervalType; - max_interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1]; - min_interval = frm->dwFrameInterval[0]; + uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType; + max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1]; + min_interval = frm->uncompressed.dwFrameInterval[0]; interval = max_interval; interval_ms = min_interval / 10000; } @@ -437,24 +530,24 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * case VIDEO_REQUEST_GET_MIN: { uint_fast32_t min_interval, max_interval; - uint_fast8_t num_intervals = frm->bFrameIntervalType; - max_interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1]; - min_interval = frm->dwFrameInterval[0]; + uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType; + max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1]; + min_interval = frm->uncompressed.dwFrameInterval[0]; interval = min_interval; interval_ms = max_interval / 10000; } break; case VIDEO_REQUEST_GET_DEF: - interval = frm->dwDefaultFrameInterval; + interval = frm->uncompressed.dwDefaultFrameInterval; interval_ms = interval / 10000; break; case VIDEO_REQUEST_GET_RES: { - uint_fast8_t num_intervals = frm->bFrameIntervalType; + uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType; if (num_intervals) { interval = 0; } else { - interval = frm->dwFrameInterval[2]; + interval = frm->uncompressed.dwFrameInterval[2]; interval_ms = interval / 10000; } } @@ -466,11 +559,15 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * param->dwMaxPayloadTransferSize = 0; } else { uint_fast32_t frame_size = param->dwMaxVideoFrameSize; + uint_fast32_t payload_size; if (!interval_ms) { - param->dwMaxPayloadTransferSize = frame_size + 2; + payload_size = frame_size + 2; } else { - param->dwMaxPayloadTransferSize = (frame_size + interval_ms - 1) / interval_ms + 2; + payload_size = (frame_size + interval_ms - 1) / interval_ms + 2; } + if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) + payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE; + param->dwMaxPayloadTransferSize = payload_size; } return true; } @@ -484,10 +581,12 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self) { tusb_desc_vc_itf_t const *vc = _get_desc_vc(self); + /* The next descriptor after the class-specific VC interface header descriptor. */ - void const *cur = (void const*)vc + vc->std.bLength + vc->ctl.bLength; + void const *cur = (uint8_t const*)vc + vc->std.bLength + vc->ctl.bLength; + /* The end of the video control interface descriptor. */ - void const *end = (void const*)vc + vc->std.bLength + vc->ctl.wTotalLength; + void const *end = _end_of_control_descriptor(vc); if (vc->std.bNumEndpoints) { /* Find the notification endpoint descriptor. */ cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT); @@ -506,10 +605,11 @@ static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self) static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t altnum) { TU_LOG2(" open VC %d\n", altnum); - void const *beg = self->beg; - void const *end = beg + self->len; + uint8_t const *beg = self->beg; + uint8_t const *end = beg + self->len; + /* The first descriptor is a video control interface descriptor. */ - void const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); + uint8_t const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); TU_LOG2(" cur %d\n", cur - beg); TU_VERIFY(cur < end); @@ -519,7 +619,8 @@ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t TU_ASSERT(vc->ctl.bInCollection <= CFG_TUD_VIDEO_STREAMING); /* Update to point the end of the video control interface descriptor. */ - end = cur + vc->std.bLength + vc->ctl.wTotalLength; + end = _end_of_control_descriptor(cur); + /* Advance to the next descriptor after the class-specific VC interface header descriptor. */ cur += vc->std.bLength + vc->ctl.bLength; TU_LOG2(" bNumEndpoints %d\n", vc->std.bNumEndpoints); @@ -534,7 +635,7 @@ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t /* Open the notification endpoint */ TU_ASSERT(usbd_edpt_open(rhport, notif)); } - self->cur = (uint16_t) ((void const*)vc - beg); + self->cur = (uint16_t) ((uint8_t const*)vc - beg); return true; } @@ -546,7 +647,7 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint { uint_fast8_t i; TU_LOG2(" reopen VS %d\n", altnum); - void const *desc = _videod_itf[stm->index_vc].beg; + uint8_t const *desc = _videod_itf[stm->index_vc].beg; /* Close endpoints of previous settings. */ for (i = 0; i < TU_ARRAY_SIZE(stm->desc.ep); ++i) { @@ -557,16 +658,18 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint stm->desc.ep[i] = 0; TU_LOG2(" close EP%02x\n", ep_adr); } + /* clear transfer management information */ stm->buffer = NULL; stm->bufsize = 0; stm->offset = 0; /* Find a alternate interface */ - void const *beg = desc + stm->desc.beg; - void const *end = desc + stm->desc.end; - void const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); + uint8_t const *beg = desc + stm->desc.beg; + uint8_t const *end = desc + stm->desc.end; + uint8_t const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); TU_VERIFY(cur < end); + uint_fast8_t numeps = ((tusb_desc_interface_t const *)cur)->bNumEndpoints; TU_ASSERT(numeps <= TU_ARRAY_SIZE(stm->desc.ep)); stm->desc.cur = (uint16_t) (cur - desc); /* Save the offset of the new settings */ @@ -576,6 +679,7 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint video_probe_and_commit_control_t *param = (video_probe_and_commit_control_t *)&stm->ep_buf; tu_memclr(param, sizeof(*param)); + TU_LOG2(" done 0\n"); return _update_streaming_parameters(stm, param); } /* Open endpoints of the new settings. */ @@ -604,6 +708,7 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint hdr->bHeaderLength = sizeof(*hdr); hdr->bmHeaderInfo = 0; + TU_LOG2(" done\n"); return true; } @@ -676,7 +781,7 @@ static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage, if (stage == CONTROL_STAGE_SETUP) { TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); TU_VERIFY(tud_control_xfer(rhport, request, &self->power_mode, sizeof(self->power_mode)), VIDEO_ERROR_UNKNOWN); - } else if (stage == CONTROL_STAGE_ACK) { + } else if (stage == CONTROL_STAGE_DATA) { if (tud_video_power_mode_cb) return tud_video_power_mode_cb(ctl_idx, self->power_mode); } return VIDEO_ERROR_NONE; @@ -818,10 +923,10 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, switch (request->bRequest) { case VIDEO_REQUEST_SET_CUR: if (stage == CONTROL_STAGE_SETUP) { - TU_VERIFY(sizeof(video_probe_and_commit_control_t) == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(sizeof(video_probe_and_commit_control_t) >= request->wLength, VIDEO_ERROR_UNKNOWN); TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); - } else if (stage == CONTROL_STAGE_ACK) { + } else if (stage == CONTROL_STAGE_DATA) { TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); } @@ -845,7 +950,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, video_probe_and_commit_control_t tmp; tmp = *(video_probe_and_commit_control_t*)&self->ep_buf; TU_VERIFY(_negotiate_streaming_parameters(self, request->bRequest, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); - TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, &tmp, sizeof(tmp)), VIDEO_ERROR_UNKNOWN); } return VIDEO_ERROR_NONE; @@ -862,7 +967,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, if (stage == CONTROL_STAGE_SETUP) { TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t)&_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN); } return VIDEO_ERROR_NONE; @@ -874,9 +979,9 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, switch (request->bRequest) { case VIDEO_REQUEST_SET_CUR: if (stage == CONTROL_STAGE_SETUP) { - TU_VERIFY(sizeof(video_probe_and_commit_control_t) == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(sizeof(video_probe_and_commit_control_t) >= request->wLength, VIDEO_ERROR_UNKNOWN); TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); - } else if (stage == CONTROL_STAGE_ACK) { + } else if (stage == CONTROL_STAGE_DATA) { TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); if (tud_video_commit_cb) { return tud_video_commit_cb(self->index_vc, self->index_vs, (video_probe_and_commit_control_t*)self->ep_buf); @@ -944,7 +1049,6 @@ static int handle_video_stm_req(uint8_t rhport, uint8_t stage, default: return VIDEO_ERROR_INVALID_REQUEST; } - return VIDEO_ERROR_UNKNOWN; } //--------------------------------------------------------------------+ @@ -977,7 +1081,7 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu if (!stm || !stm->desc.ep[0] || stm->buffer) return false; /* Find EP address */ - void const *desc = _videod_itf[stm->index_vc].beg; + uint8_t const *desc = _videod_itf[stm->index_vc].beg; uint8_t ep_addr = 0; for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { uint_fast16_t ofs_ep = stm->desc.ep[i]; @@ -1044,13 +1148,15 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin } TU_ASSERT(ctl_idx < CFG_TUD_VIDEO, 0); - void const *end = (void const*)itf_desc + max_len; - self->beg = itf_desc; + uint8_t const *end = (uint8_t const*)itf_desc + max_len; + self->beg = (uint8_t const*) itf_desc; self->len = max_len; + /*------------- Video Control Interface -------------*/ TU_VERIFY(_open_vc_itf(rhport, self, 0), 0); tusb_desc_vc_itf_t const *vc = _get_desc_vc(self); uint_fast8_t bInCollection = vc->ctl.bInCollection; + /* Find the end of the video interface descriptor */ void const *cur = _next_desc_itf(itf_desc, end); for (uint8_t stm_idx = 0; stm_idx < bInCollection; ++stm_idx) { @@ -1101,7 +1207,7 @@ bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_ for (itf = 0; itf < CFG_TUD_VIDEO_STREAMING; ++itf) { videod_streaming_interface_t *stm = &_videod_streaming_itf[itf]; if (!stm->desc.beg) continue; - void const *desc = _videod_itf[stm->index_vc].beg; + uint8_t const *desc = _videod_itf[stm->index_vc].beg; if (itfnum == _desc_itfnum(desc + stm->desc.beg)) break; } @@ -1127,7 +1233,7 @@ bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 uint_fast16_t const ep_ofs = stm->desc.ep[0]; if (!ep_ofs) continue; ctl = &_videod_itf[stm->index_vc]; - void const *desc = ctl->beg; + uint8_t const *desc = ctl->beg; if (ep_addr == _desc_ep_addr(desc + ep_ofs)) break; } diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_common.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_common.h index b1ee40a1..957491aa 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_common.h +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_common.h @@ -75,6 +75,21 @@ #include "tusb_timeout.h" // TODO remove +//--------------------------------------------------------------------+ +// Optional API implemented by application if needed +// TODO move to a more ovious place/file +//--------------------------------------------------------------------+ + +// flush data cache +TU_ATTR_WEAK extern void tusb_app_dcache_flush(uintptr_t addr, uint32_t data_size); + +// invalidate data cache +TU_ATTR_WEAK extern void tusb_app_dcache_invalidate(uintptr_t addr, uint32_t data_size); + +// Optional physical <-> virtual address translation +TU_ATTR_WEAK extern void* tusb_app_virt_to_phys(void *virt_addr); +TU_ATTR_WEAK extern void* tusb_app_phys_to_virt(void *phys_addr); + //--------------------------------------------------------------------+ // Internal Inline Functions //--------------------------------------------------------------------+ @@ -83,6 +98,29 @@ #define tu_memclr(buffer, size) memset((buffer), 0, (size)) #define tu_varclr(_var) tu_memclr(_var, sizeof(*(_var))) +// This is a backport of memset_s from c11 +TU_ATTR_ALWAYS_INLINE static inline int tu_memset_s(void *dest, size_t destsz, int ch, size_t count) +{ + // TODO may check if desst and src is not NULL + if (count > destsz) { + return -1; + } + memset(dest, ch, count); + return 0; +} + +// This is a backport of memcpy_s from c11 +TU_ATTR_ALWAYS_INLINE static inline int tu_memcpy_s(void *dest, size_t destsz, const void * src, size_t count ) +{ + // TODO may check if desst and src is not NULL + if (count > destsz) { + return -1; + } + memcpy(dest, src, count); + return 0; +} + + //------------- Bytes -------------// TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_u32(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0) { diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_compiler.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_compiler.h index 2c30daf6..5ab56e14 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_compiler.h +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_compiler.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -61,6 +61,13 @@ #define TU_VERIFY_STATIC(const_expr, _mess) enum { TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1/(!!(const_expr)) } #endif +/* --------------------- Fuzzing types -------------------------------------- */ +#ifdef _FUZZ + #define tu_static static __thread +#else + #define tu_static static +#endif + // for declaration of reserved field, make use of _TU_COUNTER_ #define TU_RESERVED TU_XSTRCAT(reserved, _TU_COUNTER_) @@ -76,9 +83,9 @@ * - ##__VA_ARGS__ is used to deal with 0 paramerter (swallows comma) *------------------------------------------------------------------*/ #if !defined(__CCRX__) -#define TU_ARGS_NUM(...) _TU_NARG(_0, ##__VA_ARGS__,_RSEQ_N()) +#define TU_ARGS_NUM(...) _TU_NARG(_0, ##__VA_ARGS__, _RSEQ_N()) #else -#define TU_ARGS_NUM(...) _TU_NARG(_0, __VA_ARGS__,_RSEQ_N()) +#define TU_ARGS_NUM(...) _TU_NARG(_0, __VA_ARGS__, _RSEQ_N()) #endif #define _TU_NARG(...) _GET_NTH_ARG(__VA_ARGS__) @@ -131,10 +138,14 @@ #define TU_ATTR_BIT_FIELD_ORDER_BEGIN #define TU_ATTR_BIT_FIELD_ORDER_END - #if __has_attribute(__fallthrough__) - #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough)) - #else + #if __GNUC__ < 5 #define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */ + #else + #if __has_attribute(__fallthrough__) + #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough)) + #else + #define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */ + #endif #endif // Endian conversion use well-known host to network (big endian) naming @@ -144,8 +155,17 @@ #define TU_BYTE_ORDER TU_BIG_ENDIAN #endif - #define TU_BSWAP16(u16) (__builtin_bswap16(u16)) - #define TU_BSWAP32(u32) (__builtin_bswap32(u32)) + // Unfortunately XC16 doesn't provide builtins for 32bit endian conversion + #if defined(__XC16) + #define TU_BSWAP16(u16) (__builtin_swap(u16)) + #define TU_BSWAP32(u32) ((((u32) & 0xff000000) >> 24) | \ + (((u32) & 0x00ff0000) >> 8) | \ + (((u32) & 0x0000ff00) << 8) | \ + (((u32) & 0x000000ff) << 24)) + #else + #define TU_BSWAP16(u16) (__builtin_bswap16(u16)) + #define TU_BSWAP32(u32) (__builtin_bswap32(u32)) + #endif #ifndef __ARMCC_VERSION // List of obsolete callback function that is renamed and should not be defined. @@ -189,7 +209,7 @@ #define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used #define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused #define TU_ATTR_USED __attribute__ ((used)) // Function/Variable is meant to be used - #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough)) + #define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */ #define TU_ATTR_PACKED_BEGIN #define TU_ATTR_PACKED_END @@ -232,7 +252,7 @@ #define TU_BSWAP16(u16) ((unsigned short)_builtin_revw((unsigned long)u16)) #define TU_BSWAP32(u32) (_builtin_revl(u32)) -#else +#else #error "Compiler attribute porting is required" #endif diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_debug.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_debug.h index ac5bee6e..82f68204 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_debug.h +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_debug.h @@ -66,7 +66,7 @@ static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) #define TU_LOG(n, ...) TU_XSTRCAT(TU_LOG, n)(__VA_ARGS__) #define TU_LOG_MEM(n, ...) TU_XSTRCAT3(TU_LOG, n, _MEM)(__VA_ARGS__) #define TU_LOG_ARR(n, ...) TU_XSTRCAT3(TU_LOG, n, _ARR)(__VA_ARGS__) -#define TU_LOG_VAR(n, ...) TU_XSTRCAT3(TU_LOG, n, _VAR)(__VA_ARGS__) +#define TU_LOG_PTR(n, ...) TU_XSTRCAT3(TU_LOG, n, _PTR)(__VA_ARGS__) #define TU_LOG_INT(n, ...) TU_XSTRCAT3(TU_LOG, n, _INT)(__VA_ARGS__) #define TU_LOG_HEX(n, ...) TU_XSTRCAT3(TU_LOG, n, _HEX)(__VA_ARGS__) #define TU_LOG_LOCATION() tu_printf("%s: %d:\r\n", __PRETTY_FUNCTION__, __LINE__) @@ -76,7 +76,7 @@ static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) #define TU_LOG1 tu_printf #define TU_LOG1_MEM tu_print_mem #define TU_LOG1_ARR(_x, _n) tu_print_arr((uint8_t const*)(_x), _n) -#define TU_LOG1_VAR(_x) tu_print_arr((uint8_t const*)(_x), sizeof(*(_x))) +#define TU_LOG1_PTR(_x) tu_print_arr((uint8_t const*)(_x), sizeof(*(_x))) #define TU_LOG1_INT(_x) tu_printf(#_x " = %ld\r\n", (unsigned long) (_x) ) #define TU_LOG1_HEX(_x) tu_printf(#_x " = %lX\r\n", (unsigned long) (_x) ) @@ -85,7 +85,7 @@ static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) #define TU_LOG2 TU_LOG1 #define TU_LOG2_MEM TU_LOG1_MEM #define TU_LOG2_ARR TU_LOG1_ARR - #define TU_LOG2_VAR TU_LOG1_VAR + #define TU_LOG2_PTR TU_LOG1_PTR #define TU_LOG2_INT TU_LOG1_INT #define TU_LOG2_HEX TU_LOG1_HEX #endif @@ -95,7 +95,7 @@ static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) #define TU_LOG3 TU_LOG1 #define TU_LOG3_MEM TU_LOG1_MEM #define TU_LOG3_ARR TU_LOG1_ARR - #define TU_LOG3_VAR TU_LOG1_VAR + #define TU_LOG3_PTR TU_LOG1_PTR #define TU_LOG3_INT TU_LOG1_INT #define TU_LOG3_HEX TU_LOG1_HEX #endif @@ -114,7 +114,7 @@ typedef struct static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) { - static char not_found[11]; + tu_static char not_found[11]; for(uint16_t i=0; icount; i++) { @@ -132,7 +132,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG #define TU_LOG(n, ...) #define TU_LOG_MEM(n, ...) - #define TU_LOG_VAR(n, ...) + #define TU_LOG_PTR(n, ...) #define TU_LOG_INT(n, ...) #define TU_LOG_HEX(n, ...) #define TU_LOG_LOCATION() @@ -143,14 +143,14 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #define TU_LOG0(...) #define TU_LOG0_MEM(...) -#define TU_LOG0_VAR(...) +#define TU_LOG0_PTR(...) #define TU_LOG0_INT(...) #define TU_LOG0_HEX(...) #ifndef TU_LOG1 #define TU_LOG1(...) #define TU_LOG1_MEM(...) - #define TU_LOG1_VAR(...) + #define TU_LOG1_PTR(...) #define TU_LOG1_INT(...) #define TU_LOG1_HEX(...) #endif @@ -158,7 +158,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG2 #define TU_LOG2(...) #define TU_LOG2_MEM(...) - #define TU_LOG2_VAR(...) + #define TU_LOG2_PTR(...) #define TU_LOG2_INT(...) #define TU_LOG2_HEX(...) #endif @@ -166,7 +166,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG3 #define TU_LOG3(...) #define TU_LOG3_MEM(...) - #define TU_LOG3_VAR(...) + #define TU_LOG3_PTR(...) #define TU_LOG3_INT(...) #define TU_LOG3_HEX(...) #endif diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.c b/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.c index 895b9208..a52c9226 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.c +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.c @@ -28,21 +28,22 @@ #include "osal/osal.h" #include "tusb_fifo.h" -// Supress IAR warning +#define TU_FIFO_DBG 0 + +// Suppress IAR warning // Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement #if defined(__ICCARM__) #pragma diag_suppress = Pa082 #endif -// implement mutex lock and unlock -#if CFG_FIFO_MUTEX +#if OSAL_MUTEX_REQUIRED -static inline void _ff_lock(tu_fifo_mutex_t mutex) +TU_ATTR_ALWAYS_INLINE static inline void _ff_lock(osal_mutex_t mutex) { if (mutex) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); } -static inline void _ff_unlock(tu_fifo_mutex_t mutex) +TU_ATTR_ALWAYS_INLINE static inline void _ff_unlock(osal_mutex_t mutex) { if (mutex) osal_mutex_unlock(mutex); } @@ -66,23 +67,20 @@ typedef enum bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable) { - if (depth > 0x8000) return false; // Maximum depth is 2^15 items + // Limit index space to 2*depth - this allows for a fast "modulo" calculation + // but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable + // only if overflow happens once (important for unsupervised DMA applications) + if (depth > 0x8000) return false; _ff_lock(f->mutex_wr); _ff_lock(f->mutex_rd); - f->buffer = (uint8_t*) buffer; - f->depth = depth; - f->item_size = item_size; + f->buffer = (uint8_t*) buffer; + f->depth = depth; + f->item_size = (uint16_t) (item_size & 0x7FFF); f->overwritable = overwritable; - - // Limit index space to 2*depth - this allows for a fast "modulo" calculation - // but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable - // only if overflow happens once (important for unsupervised DMA applications) - f->max_pointer_idx = (uint16_t) (2*depth - 1); - f->non_used_index_space = UINT16_MAX - f->max_pointer_idx; - - f->rd_idx = f->wr_idx = 0; + f->rd_idx = 0; + f->wr_idx = 0; _ff_unlock(f->mutex_wr); _ff_unlock(f->mutex_rd); @@ -90,25 +88,22 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si return true; } -// Static functions are intended to work on local variables -static inline uint16_t _ff_mod(uint16_t idx, uint16_t depth) -{ - while ( idx >= depth) idx -= depth; - return idx; -} +//--------------------------------------------------------------------+ +// Pull & Push +//--------------------------------------------------------------------+ // Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address -// Code adapted from dcd_synopsis.c +// Code adapted from dcd_synopsys.c // TODO generalize with configurable 1 byte or 4 byte each read static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t len) { - volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf; + volatile const uint32_t * reg_rx = (volatile const uint32_t *) app_buf; // Reading full available 32 bit words from const app address uint16_t full_words = len >> 2; while(full_words--) { - tu_unaligned_write32(ff_buf, *rx_fifo); + tu_unaligned_write32(ff_buf, *reg_rx); ff_buf += 4; } @@ -116,7 +111,7 @@ static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t uint8_t const bytes_rem = len & 0x03; if ( bytes_rem ) { - uint32_t tmp32 = *rx_fifo; + uint32_t tmp32 = *reg_rx; memcpy(ff_buf, &tmp32, bytes_rem); } } @@ -125,49 +120,49 @@ static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t // where all data is written to a constant address in full word copies static void _ff_pull_const_addr(void * app_buf, const uint8_t * ff_buf, uint16_t len) { - volatile uint32_t * tx_fifo = (volatile uint32_t *) app_buf; + volatile uint32_t * reg_tx = (volatile uint32_t *) app_buf; - // Pushing full available 32 bit words to const app address + // Write full available 32 bit words to const address uint16_t full_words = len >> 2; while(full_words--) { - *tx_fifo = tu_unaligned_read32(ff_buf); + *reg_tx = tu_unaligned_read32(ff_buf); ff_buf += 4; } - // Write the remaining 1-3 bytes into const app address + // Write the remaining 1-3 bytes into const address uint8_t const bytes_rem = len & 0x03; if ( bytes_rem ) { uint32_t tmp32 = 0; memcpy(&tmp32, ff_buf, bytes_rem); - *tx_fifo = tmp32; + *reg_tx = tmp32; } } -// send one item to FIFO WITHOUT updating write pointer +// send one item to fifo WITHOUT updating write pointer static inline void _ff_push(tu_fifo_t* f, void const * app_buf, uint16_t rel) { memcpy(f->buffer + (rel * f->item_size), app_buf, f->item_size); } -// send n items to FIFO WITHOUT updating write pointer -static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode) +// send n items to fifo WITHOUT updating write pointer +static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t wr_ptr, tu_fifo_copy_mode_t copy_mode) { - uint16_t const nLin = f->depth - rel; - uint16_t const nWrap = n - nLin; + uint16_t const lin_count = f->depth - wr_ptr; + uint16_t const wrap_count = n - lin_count; - uint16_t nLin_bytes = nLin * f->item_size; - uint16_t nWrap_bytes = nWrap * f->item_size; + uint16_t lin_bytes = lin_count * f->item_size; + uint16_t wrap_bytes = wrap_count * f->item_size; // current buffer of fifo - uint8_t* ff_buf = f->buffer + (rel * f->item_size); + uint8_t* ff_buf = f->buffer + (wr_ptr * f->item_size); switch (copy_mode) { case TU_FIFO_COPY_INC: - if(n <= nLin) + if(n <= lin_count) { // Linear only memcpy(ff_buf, app_buf, n*f->item_size); @@ -177,16 +172,17 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t // Wrap around // Write data to linear part of buffer - memcpy(ff_buf, app_buf, nLin_bytes); + memcpy(ff_buf, app_buf, lin_bytes); // Write data wrapped around - memcpy(f->buffer, ((uint8_t const*) app_buf) + nLin_bytes, nWrap_bytes); + // TU_ASSERT(nWrap_bytes <= f->depth, ); + memcpy(f->buffer, ((uint8_t const*) app_buf) + lin_bytes, wrap_bytes); } break; case TU_FIFO_COPY_CST_FULL_WORDS: // Intended for hardware buffers from which it can be read word by word only - if(n <= nLin) + if(n <= lin_count) { // Linear only _ff_push_const_addr(ff_buf, app_buf, n*f->item_size); @@ -196,17 +192,18 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t // Wrap around case // Write full words to linear part of buffer - uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC; + uint16_t nLin_4n_bytes = lin_bytes & 0xFFFC; _ff_push_const_addr(ff_buf, app_buf, nLin_4n_bytes); ff_buf += nLin_4n_bytes; // There could be odd 1-3 bytes before the wrap-around boundary - volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf; - uint8_t rem = nLin_bytes & 0x03; + uint8_t rem = lin_bytes & 0x03; if (rem > 0) { - uint8_t remrem = (uint8_t) tu_min16(nWrap_bytes, 4-rem); - nWrap_bytes -= remrem; + volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf; + + uint8_t remrem = (uint8_t) tu_min16(wrap_bytes, 4-rem); + wrap_bytes -= remrem; uint32_t tmp32 = *rx_fifo; uint8_t * src_u8 = ((uint8_t *) &tmp32); @@ -224,34 +221,34 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t } // Write data wrapped part - if (nWrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, nWrap_bytes); + if (wrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, wrap_bytes); } break; } } -// get one item from FIFO WITHOUT updating read pointer +// get one item from fifo WITHOUT updating read pointer static inline void _ff_pull(tu_fifo_t* f, void * app_buf, uint16_t rel) { memcpy(app_buf, f->buffer + (rel * f->item_size), f->item_size); } -// get n items from FIFO WITHOUT updating read pointer -static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode) +// get n items from fifo WITHOUT updating read pointer +static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rd_ptr, tu_fifo_copy_mode_t copy_mode) { - uint16_t const nLin = f->depth - rel; - uint16_t const nWrap = n - nLin; // only used if wrapped + uint16_t const lin_count = f->depth - rd_ptr; + uint16_t const wrap_count = n - lin_count; // only used if wrapped - uint16_t nLin_bytes = nLin * f->item_size; - uint16_t nWrap_bytes = nWrap * f->item_size; + uint16_t lin_bytes = lin_count * f->item_size; + uint16_t wrap_bytes = wrap_count * f->item_size; // current buffer of fifo - uint8_t* ff_buf = f->buffer + (rel * f->item_size); + uint8_t* ff_buf = f->buffer + (rd_ptr * f->item_size); switch (copy_mode) { case TU_FIFO_COPY_INC: - if ( n <= nLin ) + if ( n <= lin_count ) { // Linear only memcpy(app_buf, ff_buf, n*f->item_size); @@ -261,15 +258,15 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu // Wrap around // Read data from linear part of buffer - memcpy(app_buf, ff_buf, nLin_bytes); + memcpy(app_buf, ff_buf, lin_bytes); // Read data wrapped part - memcpy((uint8_t*) app_buf + nLin_bytes, f->buffer, nWrap_bytes); + memcpy((uint8_t*) app_buf + lin_bytes, f->buffer, wrap_bytes); } break; case TU_FIFO_COPY_CST_FULL_WORDS: - if ( n <= nLin ) + if ( n <= lin_count ) { // Linear only _ff_pull_const_addr(app_buf, ff_buf, n*f->item_size); @@ -279,17 +276,18 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu // Wrap around case // Read full words from linear part of buffer - uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC; - _ff_pull_const_addr(app_buf, ff_buf, nLin_4n_bytes); - ff_buf += nLin_4n_bytes; + uint16_t lin_4n_bytes = lin_bytes & 0xFFFC; + _ff_pull_const_addr(app_buf, ff_buf, lin_4n_bytes); + ff_buf += lin_4n_bytes; // There could be odd 1-3 bytes before the wrap-around boundary - volatile uint32_t * tx_fifo = (volatile uint32_t *) app_buf; - uint8_t rem = nLin_bytes & 0x03; + uint8_t rem = lin_bytes & 0x03; if (rem > 0) { - uint8_t remrem = (uint8_t) tu_min16(nWrap_bytes, 4-rem); - nWrap_bytes -= remrem; + volatile uint32_t * reg_tx = (volatile uint32_t *) app_buf; + + uint8_t remrem = (uint8_t) tu_min16(wrap_bytes, 4-rem); + wrap_bytes -= remrem; uint32_t tmp32=0; uint8_t * dst_u8 = (uint8_t *)&tmp32; @@ -301,7 +299,7 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu ff_buf = f->buffer; while(remrem--) *dst_u8++ = *ff_buf++; - *tx_fifo = tmp32; + *reg_tx = tmp32; } else { @@ -309,7 +307,7 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu } // Read data wrapped part - if (nWrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, nWrap_bytes); + if (wrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, wrap_bytes); } break; @@ -317,178 +315,232 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu } } -// Advance an absolute pointer -static uint16_t advance_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) +//--------------------------------------------------------------------+ +// Helper +//--------------------------------------------------------------------+ + +// return only the index difference and as such can be used to determine an overflow i.e overflowable count +TU_ATTR_ALWAYS_INLINE static inline +uint16_t _ff_count(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) { - // We limit the index space of p such that a correct wrap around happens - // Check for a wrap around or if we are in unused index space - This has to be checked first!! - // We are exploiting the wrap around to the correct index - if ((p > (uint16_t)(p + offset)) || ((uint16_t)(p + offset) > f->max_pointer_idx)) + // In case we have non-power of two depth we need a further modification + if (wr_idx >= rd_idx) { - p = (uint16_t) ((p + offset) + f->non_used_index_space); - } - else + return (uint16_t) (wr_idx - rd_idx); + } else { - p += offset; + return (uint16_t) (2*depth - (rd_idx - wr_idx)); } - return p; } -// Backward an absolute pointer -static uint16_t backward_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) +// return remaining slot in fifo +TU_ATTR_ALWAYS_INLINE static inline +uint16_t _ff_remaining(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) +{ + uint16_t const count = _ff_count(depth, wr_idx, rd_idx); + return (depth > count) ? (depth - count) : 0; +} + +//--------------------------------------------------------------------+ +// Index Helper +//--------------------------------------------------------------------+ + +// Advance an absolute index +// "absolute" index is only in the range of [0..2*depth) +static uint16_t advance_index(uint16_t depth, uint16_t idx, uint16_t offset) { // We limit the index space of p such that a correct wrap around happens // Check for a wrap around or if we are in unused index space - This has to be checked first!! // We are exploiting the wrap around to the correct index - if ((p < (uint16_t)(p - offset)) || ((uint16_t)(p - offset) > f->max_pointer_idx)) + uint16_t new_idx = (uint16_t) (idx + offset); + if ( (idx > new_idx) || (new_idx >= 2*depth) ) { - p = (uint16_t) ((p - offset) - f->non_used_index_space); + uint16_t const non_used_index_space = (uint16_t) (UINT16_MAX - (2*depth-1)); + new_idx = (uint16_t) (new_idx + non_used_index_space); } - else - { - p -= offset; - } - return p; -} -// get relative from absolute pointer -static uint16_t get_relative_pointer(tu_fifo_t* f, uint16_t p) -{ - return _ff_mod(p, f->depth); + return new_idx; } -// Works on local copies of w and r - return only the difference and as such can be used to determine an overflow -static inline uint16_t _tu_fifo_count(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) +#if 0 // not used but +// Backward an absolute index +static uint16_t backward_index(uint16_t depth, uint16_t idx, uint16_t offset) { - uint16_t cnt = wAbs-rAbs; - - // In case we have non-power of two depth we need a further modification - if (rAbs > wAbs) cnt -= f->non_used_index_space; + // We limit the index space of p such that a correct wrap around happens + // Check for a wrap around or if we are in unused index space - This has to be checked first!! + // We are exploiting the wrap around to the correct index + uint16_t new_idx = (uint16_t) (idx - offset); + if ( (idx < new_idx) || (new_idx >= 2*depth) ) + { + uint16_t const non_used_index_space = (uint16_t) (UINT16_MAX - (2*depth-1)); + new_idx = (uint16_t) (new_idx - non_used_index_space); + } - return cnt; + return new_idx; } +#endif -// Works on local copies of w and r -static inline bool _tu_fifo_empty(uint16_t wAbs, uint16_t rAbs) +// index to pointer, simply an modulo with minus. +TU_ATTR_ALWAYS_INLINE static inline +uint16_t idx2ptr(uint16_t depth, uint16_t idx) { - return wAbs == rAbs; + // Only run at most 3 times since index is limit in the range of [0..2*depth) + while ( idx >= depth ) idx -= depth; + return idx; } -// Works on local copies of w and r -static inline bool _tu_fifo_full(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) +// Works on local copies of w +// When an overwritable fifo is overflowed, rd_idx will be re-index so that it forms +// an full fifo i.e _ff_count() = depth +TU_ATTR_ALWAYS_INLINE static inline +uint16_t _ff_correct_read_index(tu_fifo_t* f, uint16_t wr_idx) { - return (_tu_fifo_count(f, wAbs, rAbs) == f->depth); -} + uint16_t rd_idx; + if ( wr_idx >= f->depth ) + { + rd_idx = wr_idx - f->depth; + }else + { + rd_idx = wr_idx + f->depth; + } -// Works on local copies of w and r -// BE AWARE - THIS FUNCTION MIGHT NOT GIVE A CORRECT ANSWERE IN CASE WRITE POINTER "OVERFLOWS" -// Only one overflow is allowed for this function to work e.g. if depth = 100, you must not -// write more than 2*depth-1 items in one rush without updating write pointer. Otherwise -// write pointer wraps and you pointer states are messed up. This can only happen if you -// use DMAs, write functions do not allow such an error. -static inline bool _tu_fifo_overflowed(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) -{ - return (_tu_fifo_count(f, wAbs, rAbs) > f->depth); -} + f->rd_idx = rd_idx; -// Works on local copies of w -// For more details see _tu_fifo_overflow()! -static inline void _tu_fifo_correct_read_pointer(tu_fifo_t* f, uint16_t wAbs) -{ - f->rd_idx = backward_pointer(f, wAbs, f->depth); + return rd_idx; } // Works on local copies of w and r // Must be protected by mutexes since in case of an overflow read pointer gets modified -static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wAbs, uint16_t rAbs) +static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wr_idx, uint16_t rd_idx) { - uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs); + uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); + + // nothing to peek + if ( cnt == 0 ) return false; // Check overflow and correct if required - if (cnt > f->depth) + if ( cnt > f->depth ) { - _tu_fifo_correct_read_pointer(f, wAbs); + rd_idx = _ff_correct_read_index(f, wr_idx); cnt = f->depth; } - // Skip beginning of buffer - if (cnt == 0) return false; - - uint16_t rRel = get_relative_pointer(f, rAbs); + uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); // Peek data - _ff_pull(f, p_buffer, rRel); + _ff_pull(f, p_buffer, rd_ptr); return true; } // Works on local copies of w and r // Must be protected by mutexes since in case of an overflow read pointer gets modified -static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t wAbs, uint16_t rAbs, tu_fifo_copy_mode_t copy_mode) +static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx, tu_fifo_copy_mode_t copy_mode) { - uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs); + uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); + + // nothing to peek + if ( cnt == 0 ) return 0; // Check overflow and correct if required - if (cnt > f->depth) + if ( cnt > f->depth ) { - _tu_fifo_correct_read_pointer(f, wAbs); - rAbs = f->rd_idx; + rd_idx = _ff_correct_read_index(f, wr_idx); cnt = f->depth; } - // Skip beginning of buffer - if (cnt == 0) return 0; - // Check if we can read something at and after offset - if too less is available we read what remains - if (cnt < n) n = cnt; + if ( cnt < n ) n = cnt; - uint16_t rRel = get_relative_pointer(f, rAbs); + uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); // Peek data - _ff_pull_n(f, p_buffer, n, rRel, copy_mode); + _ff_pull_n(f, p_buffer, n, rd_ptr, copy_mode); return n; } -// Works on local copies of w and r -static inline uint16_t _tu_fifo_remaining(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) -{ - return f->depth - _tu_fifo_count(f, wAbs, rAbs); -} - static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu_fifo_copy_mode_t copy_mode) { if ( n == 0 ) return 0; _ff_lock(f->mutex_wr); - uint16_t w = f->wr_idx, r = f->rd_idx; + uint16_t wr_idx = f->wr_idx; + uint16_t rd_idx = f->rd_idx; + uint8_t const* buf8 = (uint8_t const*) data; - if (!f->overwritable) + TU_LOG(TU_FIFO_DBG, "rd = %3u, wr = %3u, count = %3u, remain = %3u, n = %3u: ", + rd_idx, wr_idx, _ff_count(f->depth, wr_idx, rd_idx), _ff_remaining(f->depth, wr_idx, rd_idx), n); + + if ( !f->overwritable ) { - // Not overwritable limit up to full - n = tu_min16(n, _tu_fifo_remaining(f, w, r)); + // limit up to full + uint16_t const remain = _ff_remaining(f->depth, wr_idx, rd_idx); + n = tu_min16(n, remain); } - else if (n >= f->depth) + else { - // Only copy last part - buf8 = buf8 + (n - f->depth) * f->item_size; - n = f->depth; - - // We start writing at the read pointer's position since we fill the complete - // buffer and we do not want to modify the read pointer within a write function! - // This would end up in a race condition with read functions! - w = r; + // In over-writable mode, fifo_write() is allowed even when fifo is full. In such case, + // oldest data in fifo i.e at read pointer data will be overwritten + // Note: we can modify read buffer contents but we must not modify the read index itself within a write function! + // Since it would end up in a race condition with read functions! + if ( n >= f->depth ) + { + // Only copy last part + if ( copy_mode == TU_FIFO_COPY_INC ) + { + buf8 += (n - f->depth) * f->item_size; + }else + { + // TODO should read from hw fifo to discard data, however reading an odd number could + // accidentally discard data. + } + + n = f->depth; + + // We start writing at the read pointer's position since we fill the whole buffer + wr_idx = rd_idx; + } + else + { + uint16_t const overflowable_count = _ff_count(f->depth, wr_idx, rd_idx); + if (overflowable_count + n >= 2*f->depth) + { + // Double overflowed + // Index is bigger than the allowed range [0,2*depth) + // re-position write index to have a full fifo after pushed + wr_idx = advance_index(f->depth, rd_idx, f->depth - n); + + // TODO we should also shift out n bytes from read index since we avoid changing rd index !! + // However memmove() is expensive due to actual copying + wrapping consideration. + // Also race condition could happen anyway if read() is invoke while moving result in corrupted memory + // currently deliberately not implemented --> result in incorrect data read back + }else + { + // normal + single overflowed: + // Index is in the range of [0,2*depth) and thus detect and recoverable. Recovering is handled in read() + // Therefore we just increase write index + // we will correct (re-position) read index later on in fifo_read() function + } + } } - uint16_t wRel = get_relative_pointer(f, w); + if (n) + { + uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); - // Write data - _ff_push_n(f, buf8, n, wRel, copy_mode); + TU_LOG(TU_FIFO_DBG, "actual_n = %u, wr_ptr = %u", n, wr_ptr); - // Advance pointer - f->wr_idx = advance_pointer(f, w, n); + // Write data + _ff_push_n(f, buf8, n, wr_ptr, copy_mode); + + // Advance index + f->wr_idx = advance_index(f->depth, wr_idx, n); + + TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\n", f->wr_idx); + } _ff_unlock(f->mutex_wr); @@ -504,12 +556,16 @@ static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo n = _tu_fifo_peek_n(f, buffer, n, f->wr_idx, f->rd_idx, copy_mode); // Advance read pointer - f->rd_idx = advance_pointer(f, f->rd_idx, n); + f->rd_idx = advance_index(f->depth, f->rd_idx, n); _ff_unlock(f->mutex_rd); return n; } +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + /******************************************************************************/ /*! @brief Get number of items in FIFO. @@ -527,7 +583,7 @@ static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo /******************************************************************************/ uint16_t tu_fifo_count(tu_fifo_t* f) { - return tu_min16(_tu_fifo_count(f, f->wr_idx, f->rd_idx), f->depth); + return tu_min16(_ff_count(f->depth, f->wr_idx, f->rd_idx), f->depth); } /******************************************************************************/ @@ -545,7 +601,7 @@ uint16_t tu_fifo_count(tu_fifo_t* f) /******************************************************************************/ bool tu_fifo_empty(tu_fifo_t* f) { - return _tu_fifo_empty(f->wr_idx, f->rd_idx); + return f->wr_idx == f->rd_idx; } /******************************************************************************/ @@ -563,7 +619,7 @@ bool tu_fifo_empty(tu_fifo_t* f) /******************************************************************************/ bool tu_fifo_full(tu_fifo_t* f) { - return _tu_fifo_full(f, f->wr_idx, f->rd_idx); + return _ff_count(f->depth, f->wr_idx, f->rd_idx) >= f->depth; } /******************************************************************************/ @@ -581,7 +637,7 @@ bool tu_fifo_full(tu_fifo_t* f) /******************************************************************************/ uint16_t tu_fifo_remaining(tu_fifo_t* f) { - return _tu_fifo_remaining(f, f->wr_idx, f->rd_idx); + return _ff_remaining(f->depth, f->wr_idx, f->rd_idx); } /******************************************************************************/ @@ -607,14 +663,14 @@ uint16_t tu_fifo_remaining(tu_fifo_t* f) /******************************************************************************/ bool tu_fifo_overflowed(tu_fifo_t* f) { - return _tu_fifo_overflowed(f, f->wr_idx, f->rd_idx); + return _ff_count(f->depth, f->wr_idx, f->rd_idx) > f->depth; } // Only use in case tu_fifo_overflow() returned true! void tu_fifo_correct_read_pointer(tu_fifo_t* f) { _ff_lock(f->mutex_rd); - _tu_fifo_correct_read_pointer(f, f->wr_idx); + _ff_correct_read_index(f, f->wr_idx); _ff_unlock(f->mutex_rd); } @@ -643,7 +699,7 @@ bool tu_fifo_read(tu_fifo_t* f, void * buffer) bool ret = _tu_fifo_peek(f, buffer, f->wr_idx, f->rd_idx); // Advance pointer - f->rd_idx = advance_pointer(f, f->rd_idx, ret); + f->rd_idx = advance_index(f->depth, f->rd_idx, ret); _ff_unlock(f->mutex_rd); return ret; @@ -682,8 +738,6 @@ uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t* f, void * buffer, uint1 @param[in] f Pointer to the FIFO buffer to manipulate - @param[in] offset - Position to read from in the FIFO buffer with respect to read pointer @param[in] p_buffer Pointer to the place holder for data read from the buffer @@ -742,20 +796,20 @@ bool tu_fifo_write(tu_fifo_t* f, const void * data) _ff_lock(f->mutex_wr); bool ret; - uint16_t const w = f->wr_idx; + uint16_t const wr_idx = f->wr_idx; - if ( _tu_fifo_full(f, w, f->rd_idx) && !f->overwritable ) + if ( tu_fifo_full(f) && !f->overwritable ) { ret = false; }else { - uint16_t wRel = get_relative_pointer(f, w); + uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); // Write data - _ff_push(f, data, wRel); + _ff_push(f, data, wr_ptr); // Advance pointer - f->wr_idx = advance_pointer(f, w, 1); + f->wr_idx = advance_index(f->depth, wr_idx, 1); ret = true; } @@ -817,9 +871,8 @@ bool tu_fifo_clear(tu_fifo_t *f) _ff_lock(f->mutex_wr); _ff_lock(f->mutex_rd); - f->rd_idx = f->wr_idx = 0; - f->max_pointer_idx = (uint16_t) (2*f->depth-1); - f->non_used_index_space = UINT16_MAX - f->max_pointer_idx; + f->rd_idx = 0; + f->wr_idx = 0; _ff_unlock(f->mutex_wr); _ff_unlock(f->mutex_rd); @@ -857,7 +910,7 @@ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) As long as the DMA is the only process writing into the FIFO this is safe to use. - USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE! + USE WITH CARE - WE DO NOT CONDUCT SAFETY CHECKS HERE! @param[in] f Pointer to the FIFO buffer to manipulate @@ -867,7 +920,7 @@ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) /******************************************************************************/ void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n) { - f->wr_idx = advance_pointer(f, f->wr_idx, n); + f->wr_idx = advance_index(f->depth, f->wr_idx, n); } /******************************************************************************/ @@ -878,7 +931,7 @@ void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n) FIFO. As long as the DMA is the only process reading from the FIFO this is safe to use. - USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE! + USE WITH CARE - WE DO NOT CONDUCT SAFETY CHECKS HERE! @param[in] f Pointer to the FIFO buffer to manipulate @@ -888,7 +941,7 @@ void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n) /******************************************************************************/ void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n) { - f->rd_idx = advance_pointer(f, f->rd_idx, n); + f->rd_idx = advance_index(f->depth, f->rd_idx, n); } /******************************************************************************/ @@ -909,17 +962,18 @@ void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n) void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { // Operate on temporary values in case they change in between - uint16_t w = f->wr_idx, r = f->rd_idx; + uint16_t wr_idx = f->wr_idx; + uint16_t rd_idx = f->rd_idx; - uint16_t cnt = _tu_fifo_count(f, w, r); + uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); // Check overflow and correct if required - may happen in case a DMA wrote too fast if (cnt > f->depth) { _ff_lock(f->mutex_rd); - _tu_fifo_correct_read_pointer(f, w); + rd_idx = _ff_correct_read_index(f, wr_idx); _ff_unlock(f->mutex_rd); - r = f->rd_idx; + cnt = f->depth; } @@ -934,22 +988,25 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) } // Get relative pointers - w = get_relative_pointer(f, w); - r = get_relative_pointer(f, r); + uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); + uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); // Copy pointer to buffer to start reading from - info->ptr_lin = &f->buffer[r]; + info->ptr_lin = &f->buffer[rd_ptr]; // Check if there is a wrap around necessary - if (w > r) { + if (wr_ptr > rd_ptr) + { // Non wrapping case info->len_lin = cnt; + info->len_wrap = 0; info->ptr_wrap = NULL; } else { - info->len_lin = f->depth - r; // Also the case if FIFO was full + info->len_lin = f->depth - rd_ptr; // Also the case if FIFO was full + info->len_wrap = cnt - info->len_lin; info->ptr_wrap = f->buffer; } @@ -972,36 +1029,37 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) /******************************************************************************/ void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { - uint16_t w = f->wr_idx, r = f->rd_idx; - uint16_t free = _tu_fifo_remaining(f, w, r); + uint16_t wr_idx = f->wr_idx; + uint16_t rd_idx = f->rd_idx; + uint16_t remain = _ff_remaining(f->depth, wr_idx, rd_idx); - if (free == 0) + if (remain == 0) { - info->len_lin = 0; + info->len_lin = 0; info->len_wrap = 0; - info->ptr_lin = NULL; + info->ptr_lin = NULL; info->ptr_wrap = NULL; return; } // Get relative pointers - w = get_relative_pointer(f, w); - r = get_relative_pointer(f, r); + uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); + uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); // Copy pointer to buffer to start writing to - info->ptr_lin = &f->buffer[w]; + info->ptr_lin = &f->buffer[wr_ptr]; - if (w < r) + if (wr_ptr < rd_ptr) { // Non wrapping case - info->len_lin = r-w; + info->len_lin = rd_ptr-wr_ptr; info->len_wrap = 0; info->ptr_wrap = NULL; } else { - info->len_lin = f->depth - w; - info->len_wrap = free - info->len_lin; // Remaining length - n already was limited to free or FIFO depth - info->ptr_wrap = f->buffer; // Always start of buffer + info->len_lin = f->depth - wr_ptr; + info->len_wrap = remain - info->len_lin; // Remaining length - n already was limited to remain or FIFO depth + info->ptr_wrap = f->buffer; // Always start of buffer } } diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.h index 18db289a..2f60ec2f 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.h +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.h @@ -32,7 +32,7 @@ extern "C" { #endif -// Due to the use of unmasked pointers, this FIFO does not suffer from loosing +// Due to the use of unmasked pointers, this FIFO does not suffer from losing // one item slice. Furthermore, write and read operations are completely // decoupled as write and read functions do not modify a common state. Henceforth, // writing or reading from the FIFO within an ISR is safe as long as no other @@ -42,32 +42,84 @@ extern "C" { // within a certain number (see tu_fifo_overflow()). #include "common/tusb_common.h" +#include "osal/osal.h" // mutex is only needed for RTOS // for OS None, we don't get preempted -#define CFG_FIFO_MUTEX (CFG_TUSB_OS != OPT_OS_NONE) +#define CFG_FIFO_MUTEX OSAL_MUTEX_REQUIRED -#if CFG_FIFO_MUTEX -#include "osal/osal.h" -#define tu_fifo_mutex_t osal_mutex_t -#endif +/* Write/Read index is always in the range of: + * 0 .. 2*depth-1 + * The extra window allow us to determine the fifo state of empty or full with only 2 indices + * Following are examples with depth = 3 + * + * - empty: W = R + * | + * ------------------------- + * | 0 | RW| 2 | 3 | 4 | 5 | + * + * - full 1: W > R + * | + * ------------------------- + * | 0 | R | 2 | 3 | W | 5 | + * + * - full 2: W < R + * | + * ------------------------- + * | 0 | 1 | W | 3 | 4 | R | + * + * - Number of items in the fifo can be determined in either cases: + * - case W >= R: Count = W - R + * - case W < R: Count = 2*depth - (R - W) + * + * In non-overwritable mode, computed Count (in above 2 cases) is at most equal to depth. + * However, in over-writable mode, write index can be repeatedly increased and count can be + * temporarily larger than depth (overflowed condition) e.g + * + * - Overflowed 1: write(3), write(1) + * In this case we will adjust Read index when read()/peek() is called so that count = depth. + * | + * ------------------------- + * | R | 1 | 2 | 3 | W | 5 | + * + * - Double Overflowed i.e index is out of allowed range [0,2*depth) + * This occurs when we continue to write after 1st overflowed to 2nd overflowed. e.g: + * write(3), write(1), write(2) + * This must be prevented since it will cause unrecoverable state, in above example + * if not handled the fifo will be empty instead of continue-to-be full. Since we must not modify + * read index in write() function, which cause race condition. We will re-position write index so that + * after data is written it is a full fifo i.e W = depth - R + * + * re-position W = 1 before write(2) + * Note: we should also move data from mem[3] to read index as well, but deliberately skipped here + * since it is an expensive operation !!! + * | + * ------------------------- + * | R | W | 2 | 3 | 4 | 5 | + * + * perform write(2), result is still a full fifo. + * + * | + * ------------------------- + * | R | 1 | 2 | W | 4 | 5 | + */ typedef struct { - uint8_t* buffer ; ///< buffer pointer - uint16_t depth ; ///< max items - uint16_t item_size ; ///< size of each item - bool overwritable ; + uint8_t* buffer ; // buffer pointer + uint16_t depth ; // max items - uint16_t non_used_index_space ; ///< required for non-power-of-two buffer length - uint16_t max_pointer_idx ; ///< maximum absolute pointer index + struct TU_ATTR_PACKED { + uint16_t item_size : 15; // size of each item + bool overwritable : 1 ; // ovwerwritable when full + }; - volatile uint16_t wr_idx ; ///< write pointer - volatile uint16_t rd_idx ; ///< read pointer + volatile uint16_t wr_idx ; // write index + volatile uint16_t rd_idx ; // read index -#if CFG_FIFO_MUTEX - tu_fifo_mutex_t mutex_wr; - tu_fifo_mutex_t mutex_rd; +#if OSAL_MUTEX_REQUIRED + osal_mutex_t mutex_wr; + osal_mutex_t mutex_rd; #endif } tu_fifo_t; @@ -86,8 +138,6 @@ typedef struct .depth = _depth, \ .item_size = sizeof(_type), \ .overwritable = _overwritable, \ - .non_used_index_space = UINT16_MAX - (2*(_depth)-1), \ - .max_pointer_idx = 2*(_depth)-1, \ } #define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \ @@ -99,13 +149,18 @@ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable); bool tu_fifo_clear(tu_fifo_t *f); bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable); -#if CFG_FIFO_MUTEX +#if OSAL_MUTEX_REQUIRED TU_ATTR_ALWAYS_INLINE static inline -void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t write_mutex_hdl, tu_fifo_mutex_t read_mutex_hdl) +void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_mutex) { - f->mutex_wr = write_mutex_hdl; - f->mutex_rd = read_mutex_hdl; + f->mutex_wr = wr_mutex; + f->mutex_rd = rd_mutex; } + +#else + +#define tu_fifo_config_mutex(_f, _wr_mutex, _rd_mutex) + #endif bool tu_fifo_write (tu_fifo_t* f, void const * p_data); @@ -133,7 +188,7 @@ uint16_t tu_fifo_depth(tu_fifo_t* f) } // Pointer modifications intended to be used in combinations with DMAs. -// USE WITH CARE - NO SAFTY CHECKS CONDUCTED HERE! NOT MUTEX PROTECTED! +// USE WITH CARE - NO SAFETY CHECKS CONDUCTED HERE! NOT MUTEX PROTECTED! void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n); void tu_fifo_advance_read_pointer (tu_fifo_t *f, uint16_t n); diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_mcu.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_mcu.h index baa82fc1..ba8976a8 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_mcu.h +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_mcu.h @@ -28,8 +28,8 @@ #define TUSB_MCU_H_ //--------------------------------------------------------------------+ -// Port Specific -// TUP stand for TinyUSB Port (can be renamed) +// Port/Platform Specific +// TUP stand for TinyUSB Port/Platform (can be renamed) //--------------------------------------------------------------------+ //------------- Unaligned Memory Access -------------// @@ -48,13 +48,16 @@ * - RHPORT_HIGHSPEED: support highspeed with on-chip PHY */ -//------------- NXP -------------// +//--------------------------------------------------------------------+ +// NXP +//--------------------------------------------------------------------+ #if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX) #define TUP_DCD_ENDPOINT_MAX 5 #elif TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX) #define TUP_DCD_ENDPOINT_MAX 16 #define TUP_USBIP_OHCI + #define TUP_OHCI_RHPORTS 2 #elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX) // TODO USB0 has 6, USB1 has 4 @@ -82,18 +85,24 @@ #define TUP_DCD_ENDPOINT_MAX 8 #define TUP_RHPORT_HIGHSPEED 1 // Port0 HS, Port1 HS -#elif TU_CHECK_MCU(OPT_MCU_MKL25ZXX, OPT_MCU_K32L2BXX) +#elif TU_CHECK_MCU(OPT_MCU_KINETIS_KL, OPT_MCU_KINETIS_K32) + #define TUP_USBIP_CHIPIDEA_FS + #define TUP_USBIP_CHIPIDEA_FS_KINETIS #define TUP_DCD_ENDPOINT_MAX 16 #elif TU_CHECK_MCU(OPT_MCU_MM32F327X) #define TUP_DCD_ENDPOINT_MAX 16 -//------------- Nordic -------------// +//--------------------------------------------------------------------+ +// Nordic +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_NRF5X) // 8 CBI + 1 ISO #define TUP_DCD_ENDPOINT_MAX 9 -//------------- Microchip -------------// +//--------------------------------------------------------------------+ +// Microchip +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_SAMD21, OPT_MCU_SAMD51, OPT_MCU_SAME5X) || \ TU_CHECK_MCU(OPT_MCU_SAMD11, OPT_MCU_SAML21, OPT_MCU_SAML22) #define TUP_DCD_ENDPOINT_MAX 8 @@ -111,19 +120,35 @@ #define TUP_DCD_ENDPOINT_MAX 8 #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER -//------------- ST -------------// +#elif TU_CHECK_MCU(OPT_MCU_PIC32MX, OPT_MCU_PIC32MM, OPT_MCU_PIC32MK) || \ + TU_CHECK_MCU(OPT_MCU_PIC24, OPT_MCU_DSPIC33) + #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + +//--------------------------------------------------------------------+ +// ST +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_STM32F0) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32F1) + // - F102, F103 use fsdev + // - F105, F107 use dwc2 #if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \ defined (STM32F107xB) || defined (STM32F107xC) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 #define TUP_DCD_ENDPOINT_MAX 4 - #else + #elif defined(STM32F102x6) || defined(STM32F102xB) || \ + defined(STM32F103x6) || defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 + #else + #error "Unsupported STM32F1 mcu" #endif #elif TU_CHECK_MCU(OPT_MCU_STM32F2) @@ -134,6 +159,8 @@ #define TUP_DCD_ENDPOINT_MAX 6 #elif TU_CHECK_MCU(OPT_MCU_STM32F3) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32F4) @@ -162,12 +189,18 @@ #define TUP_DCD_ENDPOINT_MAX 9 #elif TU_CHECK_MCU(OPT_MCU_STM32G4) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32L0, OPT_MCU_STM32L1) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32L4) + // - L4x2, L4x3 use fsdev + // - L4x4, L4x6, L4x7, L4x9 use dwc2 #if defined (STM32L475xx) || defined (STM32L476xx) || \ defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \ defined (STM32L4A6xx) || defined (STM32L4P5xx) || defined (STM32L4Q5xx) || \ @@ -177,31 +210,57 @@ #define TUP_USBIP_DWC2_STM32 #define TUP_DCD_ENDPOINT_MAX 6 - #else + #elif defined(STM32L412xx) || defined(STM32L422xx) || defined(STM32L432xx) || defined(STM32L433xx) || \ + defined(STM32L442xx) || defined(STM32L443xx) || defined(STM32L452xx) || defined(STM32L462xx) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 + #else + #error "Unsupported STM32L4 mcu" #endif #elif TU_CHECK_MCU(OPT_MCU_STM32WB) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 + #define TUP_DCD_ENDPOINT_MAX 8 + +#elif TU_CHECK_MCU(OPT_MCU_STM32U5) + #define TUP_USBIP_DWC2 + #define TUP_USBIP_DWC2_STM32 + #define TUP_DCD_ENDPOINT_MAX 6 + +#elif TU_CHECK_MCU(OPT_MCU_STM32L5) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 -//------------- Sony -------------// + +//--------------------------------------------------------------------+ +// Sony +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_CXD56) #define TUP_DCD_ENDPOINT_MAX 7 #define TUP_RHPORT_HIGHSPEED 1 #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER -//------------- TI -------------// +//--------------------------------------------------------------------+ +// TI +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_MSP430x5xx) #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129) #define TUP_DCD_ENDPOINT_MAX 8 -//------------- ValentyUSB -------------// +//--------------------------------------------------------------------+ +// ValentyUSB (Litex) +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_VALENTYUSB_EPTRI) #define TUP_DCD_ENDPOINT_MAX 16 -//------------- Nuvoton -------------// +//--------------------------------------------------------------------+ +// Nuvoton +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_NUC121, OPT_MCU_NUC126) #define TUP_DCD_ENDPOINT_MAX 8 @@ -212,47 +271,65 @@ #define TUP_DCD_ENDPOINT_MAX 12 #define TUP_RHPORT_HIGHSPEED 1 -//------------- Espressif -------------// +//--------------------------------------------------------------------+ +// Espressif +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) #define TUP_USBIP_DWC2 #define TUP_DCD_ENDPOINT_MAX 6 -//------------- Dialog -------------// +//--------------------------------------------------------------------+ +// Dialog +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_DA1469X) #define TUP_DCD_ENDPOINT_MAX 4 -//------------- Raspberry Pi -------------// +//--------------------------------------------------------------------+ +// Raspberry Pi +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_RP2040) #define TUP_DCD_ENDPOINT_MAX 16 #define TU_ATTR_FAST_FUNC __attribute__((section(".time_critical.tinyusb"))) -//------------- Silabs -------------// +//--------------------------------------------------------------------+ +// Silabs +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_EFM32GG) #define TUP_USBIP_DWC2 #define TUP_DCD_ENDPOINT_MAX 7 -//------------- Renesas -------------// -#elif TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N) +//--------------------------------------------------------------------+ +// Renesas +//--------------------------------------------------------------------+ +#elif TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N, OPT_MCU_RAXXX) #define TUP_DCD_ENDPOINT_MAX 10 -//------------- GigaDevice -------------// +//--------------------------------------------------------------------+ +// GigaDevice +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_GD32VF103) #define TUP_USBIP_DWC2 #define TUP_DCD_ENDPOINT_MAX 4 -//------------- Broadcom -------------// +//--------------------------------------------------------------------+ +// Broadcom +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837) #define TUP_USBIP_DWC2 #define TUP_DCD_ENDPOINT_MAX 8 #define TUP_RHPORT_HIGHSPEED 1 -//------------- Broadcom -------------// +//--------------------------------------------------------------------+ +// Infineon +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_XMC4000) #define TUP_USBIP_DWC2 #define TUP_DCD_ENDPOINT_MAX 8 -//------------- BridgeTek -------------// +//--------------------------------------------------------------------+ +// BridgeTek +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_FT90X) #define TUP_DCD_ENDPOINT_MAX 8 #define TUP_RHPORT_HIGHSPEED 1 @@ -261,16 +338,26 @@ #define TUP_DCD_ENDPOINT_MAX 16 #define TUP_RHPORT_HIGHSPEED 1 -//------------ Allwinner -------------// +//--------------------------------------------------------------------+ +// Allwinner +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_F1C100S) #define TUP_DCD_ENDPOINT_MAX 4 +//------------- WCH -------------// +#elif TU_CHECK_MCU(OPT_MCU_CH32V307) + #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_RHPORT_HIGHSPEED 1 #endif //--------------------------------------------------------------------+ // Default Values //--------------------------------------------------------------------+ +#ifndef TUP_MCU_MULTIPLE_CORE +#define TUP_MCU_MULTIPLE_CORE 0 +#endif + #ifndef TUP_DCD_ENDPOINT_MAX #warning "TUP_DCD_ENDPOINT_MAX is not defined for this MCU, default to 8" #define TUP_DCD_ENDPOINT_MAX 8 diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_private.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_private.h index b34506f6..d5541856 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_private.h +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_private.h @@ -28,6 +28,8 @@ #ifndef _TUSB_PRIVATE_H_ #define _TUSB_PRIVATE_H_ +// Internal Helper used by Host and Device Stack + #ifdef __cplusplus extern "C" { #endif @@ -39,8 +41,31 @@ typedef struct TU_ATTR_PACKED volatile uint8_t claimed : 1; }tu_edpt_state_t; +typedef struct { + bool is_host; // host or device most + union { + uint8_t daddr; + uint8_t rhport; + uint8_t hwid; + }; + uint8_t ep_addr; + uint8_t ep_speed; + + uint16_t ep_packetsize; + uint16_t ep_bufsize; + + // TODO xfer_fifo can skip this buffer + uint8_t* ep_buf; + + tu_fifo_t ff; + + // mutex: read if ep rx, write if e tx + OSAL_MUTEX_DEF(ff_mutex); + +}tu_edpt_stream_t; + //--------------------------------------------------------------------+ -// Internal Helper used by Host and Device Stack +// Endpoint //--------------------------------------------------------------------+ // Check if endpoint descriptor is valid per USB specs @@ -58,6 +83,89 @@ bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex); // Release an endpoint with provided mutex bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex); +//--------------------------------------------------------------------+ +// Endpoint Stream +//--------------------------------------------------------------------+ + +// Init an stream, should only be called once +bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool overwritable, + void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize); + +// Open an stream for an endpoint +// hwid is either device address (host mode) or rhport (device mode) +TU_ATTR_ALWAYS_INLINE static inline +void tu_edpt_stream_open(tu_edpt_stream_t* s, uint8_t hwid, tusb_desc_endpoint_t const *desc_ep) +{ + tu_fifo_clear(&s->ff); + s->hwid = hwid; + s->ep_addr = desc_ep->bEndpointAddress; + s->ep_packetsize = tu_edpt_packet_size(desc_ep); +} + +TU_ATTR_ALWAYS_INLINE static inline +void tu_edpt_stream_close(tu_edpt_stream_t* s) +{ + s->hwid = 0; + s->ep_addr = 0; +} + +// Clear fifo +TU_ATTR_ALWAYS_INLINE static inline +bool tu_edpt_stream_clear(tu_edpt_stream_t* s) +{ + return tu_fifo_clear(&s->ff); +} + +//--------------------------------------------------------------------+ +// Stream Write +//--------------------------------------------------------------------+ + +// Write to stream +uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize); + +// Start an usb transfer if endpoint is not busy +uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s); + +// Start an zero-length packet if needed +bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes); + +// Get the number of bytes available for writing +TU_ATTR_ALWAYS_INLINE static inline +uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) +{ + return (uint32_t) tu_fifo_remaining(&s->ff); +} + +//--------------------------------------------------------------------+ +// Stream Read +//--------------------------------------------------------------------+ + +// Read from stream +uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize); + +// Start an usb transfer if endpoint is not busy +uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s); + +// Must be called in the transfer complete callback +TU_ATTR_ALWAYS_INLINE static inline +void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) +{ + tu_fifo_write_n(&s->ff, s->ep_buf, (uint16_t) xferred_bytes); +} + +// Get the number of bytes available for reading +TU_ATTR_ALWAYS_INLINE static inline +uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t* s) +{ + return (uint32_t) tu_fifo_count(&s->ff); +} + +TU_ATTR_ALWAYS_INLINE static inline +bool tu_edpt_stream_peek(tu_edpt_stream_t* s, uint8_t* ch) +{ + return tu_fifo_peek(&s->ff, ch); +} + #ifdef __cplusplus } #endif diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_timeout.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_timeout.h index ce53955f..533e67ab 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_timeout.h +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_timeout.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_types.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_types.h index 1f2a38d4..39a2d456 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_types.h +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_types.h @@ -69,6 +69,15 @@ typedef enum TUSB_DIR_IN_MASK = 0x80 }tusb_dir_t; +enum +{ + TUSB_EPSIZE_BULK_FS = 64, + TUSB_EPSIZE_BULK_HS= 512, + + TUSB_EPSIZE_ISO_FS_MAX = 1023, + TUSB_EPSIZE_ISO_HS_MAX = 1024, +}; + /// Isochronous End Point Attributes typedef enum { @@ -225,7 +234,7 @@ enum { typedef enum { - XFER_RESULT_SUCCESS, + XFER_RESULT_SUCCESS = 0, XFER_RESULT_FAILED, XFER_RESULT_STALLED, XFER_RESULT_TIMEOUT, @@ -243,7 +252,6 @@ enum INTERFACE_INVALID_NUMBER = 0xff }; - typedef enum { MS_OS_20_SET_HEADER_DESCRIPTOR = 0x00, @@ -265,6 +273,11 @@ enum CONTROL_STAGE_ACK }; +enum +{ + TUSB_INDEX_INVALID_8 = 0xFFu +}; + //--------------------------------------------------------------------+ // USB Descriptors //--------------------------------------------------------------------+ @@ -513,25 +526,52 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpo return tu_le16toh(desc_ep->wMaxPacketSize) & TU_GENMASK(10, 0); } +#if CFG_TUSB_DEBUG +TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_dir_str(tusb_dir_t dir) +{ + tu_static const char *str[] = {"out", "in"}; + return str[dir]; +} + +TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_t t) +{ + tu_static const char *str[] = {"control", "isochronous", "bulk", "interrupt"}; + return str[t]; +} +#endif + //--------------------------------------------------------------------+ // Descriptor helper //--------------------------------------------------------------------+ + +// return next descriptor TU_ATTR_ALWAYS_INLINE static inline uint8_t const * tu_desc_next(void const* desc) { uint8_t const* desc8 = (uint8_t const*) desc; return desc8 + desc8[DESC_OFFSET_LEN]; } +// get descriptor type TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_type(void const* desc) { return ((uint8_t const*) desc)[DESC_OFFSET_TYPE]; } +// get descriptor length TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc) { return ((uint8_t const*) desc)[DESC_OFFSET_LEN]; } +// find descriptor that match byte1 (type) +uint8_t const * tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byte1); + +// find descriptor that match byte1 (type) and byte2 +uint8_t const * tu_desc_find2(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2); + +// find descriptor that match byte1 (type) and byte2 +uint8_t const * tu_desc_find3(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2, uint8_t byte3); + #ifdef __cplusplus } #endif diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_verify.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_verify.h index a52a6d26..12355e8b 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_verify.h +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_verify.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) diff --git a/test-devices/composite-stm32/lib/tinyusb/device/dcd.h b/test-devices/composite-stm32/lib/tinyusb/device/dcd.h index c1780f65..00419ff0 100644 --- a/test-devices/composite-stm32/lib/tinyusb/device/dcd.h +++ b/test-devices/composite-stm32/lib/tinyusb/device/dcd.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -167,6 +167,12 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); // This API never calls with control endpoints, since it is auto cleared when receiving setup packet void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr); +// Allocate packet buffer used by ISO endpoints +// Some MCU need manual packet buffer allocation, we allocation largest size to avoid clustering +TU_ATTR_WEAK bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size); + +// Configure and enable an ISO endpoint according to descriptor +TU_ATTR_WEAK bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); //--------------------------------------------------------------------+ // Event API (implemented by stack) //--------------------------------------------------------------------+ @@ -193,7 +199,7 @@ TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_reset (uint8_t rhport, t TU_ATTR_ALWAYS_INLINE static inline void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr) { dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SETUP_RECEIVED }; - memcpy(&event.setup_received, setup, 8); + memcpy(&event.setup_received, setup, sizeof(tusb_control_request_t)); dcd_event_handler(&event, in_isr); } diff --git a/test-devices/composite-stm32/lib/tinyusb/device/usbd.c b/test-devices/composite-stm32/lib/tinyusb/device/usbd.c index c199e647..cee56af6 100644 --- a/test-devices/composite-stm32/lib/tinyusb/device/usbd.c +++ b/test-devices/composite-stm32/lib/tinyusb/device/usbd.c @@ -39,13 +39,13 @@ // USBD Configuration //--------------------------------------------------------------------+ -// Debug level of USBD -#define USBD_DBG 2 - #ifndef CFG_TUD_TASK_QUEUE_SZ #define CFG_TUD_TASK_QUEUE_SZ 16 #endif +// Debug level of USBD +#define USBD_DBG 2 + //--------------------------------------------------------------------+ // Device Data //--------------------------------------------------------------------+ @@ -76,7 +76,7 @@ typedef struct }usbd_device_t; -static usbd_device_t _usbd_dev; +tu_static usbd_device_t _usbd_dev; //--------------------------------------------------------------------+ // Class Driver @@ -88,7 +88,7 @@ static usbd_device_t _usbd_dev; #endif // Built-in class drivers -static usbd_class_driver_t const _usbd_driver[] = +tu_static usbd_class_driver_t const _usbd_driver[] = { #if CFG_TUD_CDC { @@ -238,8 +238,8 @@ static usbd_class_driver_t const _usbd_driver[] = enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(_usbd_driver) }; // Additional class drivers implemented by application -static usbd_class_driver_t const * _app_driver = NULL; -static uint8_t _app_driver_count = 0; +tu_static usbd_class_driver_t const * _app_driver = NULL; +tu_static uint8_t _app_driver_count = 0; // virtually joins built-in and application drivers together. // Application is positioned first to allow overwriting built-in ones. @@ -265,17 +265,19 @@ static inline usbd_class_driver_t const * get_driver(uint8_t drvid) //--------------------------------------------------------------------+ enum { RHPORT_INVALID = 0xFFu }; -static uint8_t _usbd_rhport = RHPORT_INVALID; +tu_static uint8_t _usbd_rhport = RHPORT_INVALID; // Event queue // usbd_int_set() is used as mutex in OS NONE config OSAL_QUEUE_DEF(usbd_int_set, _usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t); -static osal_queue_t _usbd_q; +tu_static osal_queue_t _usbd_q; -// Mutex for claiming endpoint, only needed when using with preempted RTOS -#if CFG_TUSB_OS != OPT_OS_NONE -static osal_mutex_def_t _ubsd_mutexdef; -static osal_mutex_t _usbd_mutex; +// Mutex for claiming endpoint +#if OSAL_MUTEX_REQUIRED + tu_static osal_mutex_def_t _ubsd_mutexdef; + tu_static osal_mutex_t _usbd_mutex; +#else + #define _usbd_mutex NULL #endif @@ -297,7 +299,7 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, // Debug //--------------------------------------------------------------------+ #if CFG_TUSB_DEBUG >= 2 -static char const* const _usbd_event_str[DCD_EVENT_COUNT] = +tu_static char const* const _usbd_event_str[DCD_EVENT_COUNT] = { "Invalid" , "Bus Reset" , @@ -386,10 +388,12 @@ bool tud_init (uint8_t rhport) TU_LOG(USBD_DBG, "USBD init on controller %u\r\n", rhport); TU_LOG_INT(USBD_DBG, sizeof(usbd_device_t)); + TU_LOG_INT(USBD_DBG, sizeof(tu_fifo_t)); + TU_LOG_INT(USBD_DBG, sizeof(tu_edpt_stream_t)); tu_varclr(&_usbd_dev); -#if CFG_TUSB_OS != OPT_OS_NONE +#if OSAL_MUTEX_REQUIRED // Init device mutex _usbd_mutex = osal_mutex_create(&_ubsd_mutexdef); TU_ASSERT(_usbd_mutex); @@ -446,7 +450,7 @@ static void usbd_reset(uint8_t rhport) bool tud_task_event_ready(void) { // Skip if stack is not initialized - if ( !tusb_inited() ) return false; + if ( !tud_inited() ) return false; return !osal_queue_empty(_usbd_q); } @@ -474,7 +478,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) (void) in_isr; // not implemented yet // Skip if stack is not initialized - if ( !tusb_inited() ) return; + if ( !tud_inited() ) return; // Loop until there is no more events in the queue while (1) @@ -504,7 +508,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) break; case DCD_EVENT_SETUP_RECEIVED: - TU_LOG_VAR(USBD_DBG, &event.setup_received); + TU_LOG_PTR(USBD_DBG, &event.setup_received); TU_LOG(USBD_DBG, "\r\n"); // Mark as connected after receiving 1st setup packet. @@ -1209,11 +1213,7 @@ bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr) uint8_t const dir = tu_edpt_dir(ep_addr); tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir]; -#if TUSB_OPT_MUTEX return tu_edpt_claim(ep_state, _usbd_mutex); -#else - return tu_edpt_claim(ep_state, NULL); -#endif } bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr) @@ -1224,11 +1224,7 @@ bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr) uint8_t const dir = tu_edpt_dir(ep_addr); tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir]; -#if TUSB_OPT_MUTEX return tu_edpt_release(ep_state, _usbd_mutex); -#else - return tu_edpt_release(ep_state, NULL); -#endif } bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) @@ -1386,4 +1382,31 @@ void usbd_sof_enable(uint8_t rhport, bool en) dcd_sof_enable(rhport, en); } +bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) +{ + rhport = _usbd_rhport; + + TU_ASSERT(dcd_edpt_iso_alloc); + TU_ASSERT(tu_edpt_number(ep_addr) < CFG_TUD_ENDPPOINT_MAX); + + return dcd_edpt_iso_alloc(rhport, ep_addr, largest_packet_size); +} + +bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) +{ + rhport = _usbd_rhport; + + uint8_t const epnum = tu_edpt_number(desc_ep->bEndpointAddress); + uint8_t const dir = tu_edpt_dir(desc_ep->bEndpointAddress); + + TU_ASSERT(dcd_edpt_iso_activate); + TU_ASSERT(epnum < CFG_TUD_ENDPPOINT_MAX); + TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed)); + + _usbd_dev.ep_status[epnum][dir].stalled = false; + _usbd_dev.ep_status[epnum][dir].busy = false; + _usbd_dev.ep_status[epnum][dir].claimed = false; + return dcd_edpt_iso_activate(rhport, desc_ep); +} + #endif diff --git a/test-devices/composite-stm32/lib/tinyusb/device/usbd.h b/test-devices/composite-stm32/lib/tinyusb/device/usbd.h index 17b4d927..255e5a84 100644 --- a/test-devices/composite-stm32/lib/tinyusb/device/usbd.h +++ b/test-devices/composite-stm32/lib/tinyusb/device/usbd.h @@ -293,7 +293,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* MIDI Streaming (MS) Interface */\ 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum) + 1), 0, 2, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_MIDI_STREAMING, AUDIO_FUNC_PROTOCOL_CODE_UNDEF, 0,\ /* MS Header */\ - 7, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(7 + (_numcables) * TUD_MIDI_DESC_JACK_LEN) + 7, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(7 + (_numcables) * TUD_MIDI_DESC_JACK_LEN + 2 * TUD_MIDI_DESC_EP_LEN(_numcables)) #define TUD_MIDI_JACKID_IN_EMB(_cablenum) \ (uint8_t)(((_cablenum) - 1) * 4 + 1) @@ -308,15 +308,17 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb (uint8_t)(((_cablenum) - 1) * 4 + 4) #define TUD_MIDI_DESC_JACK_LEN (6 + 6 + 9 + 9) -#define TUD_MIDI_DESC_JACK(_cablenum) \ +#define TUD_MIDI_DESC_JACK_DESC(_cablenum, _stridx) \ /* MS In Jack (Embedded) */\ - 6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_IN_EMB(_cablenum), 0,\ + 6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_IN_EMB(_cablenum), _stridx,\ /* MS In Jack (External) */\ - 6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_IN_EXT(_cablenum), 0,\ + 6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_IN_EXT(_cablenum), _stridx,\ /* MS Out Jack (Embedded), connected to In Jack External */\ - 9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_OUT_EMB(_cablenum), 1, TUD_MIDI_JACKID_IN_EXT(_cablenum), 1, 0,\ + 9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_OUT_EMB(_cablenum), 1, TUD_MIDI_JACKID_IN_EXT(_cablenum), 1, _stridx,\ /* MS Out Jack (External), connected to In Jack Embedded */\ - 9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_OUT_EXT(_cablenum), 1, TUD_MIDI_JACKID_IN_EMB(_cablenum), 1, 0 + 9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_OUT_EXT(_cablenum), 1, TUD_MIDI_JACKID_IN_EMB(_cablenum), 1, _stridx + +#define TUD_MIDI_DESC_JACK(_cablenum) TUD_MIDI_DESC_JACK_DESC(_cablenum, 0) #define TUD_MIDI_DESC_EP_LEN(_numcables) (9 + 4 + (_numcables)) #define TUD_MIDI_DESC_EP(_epout, _epsize, _numcables) \ @@ -333,7 +335,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb // - 1 Embedded Jack out connected to 1 External Jack In #define TUD_MIDI_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \ TUD_MIDI_DESC_HEAD(_itfnum, _stridx, 1),\ - TUD_MIDI_DESC_JACK(1),\ + TUD_MIDI_DESC_JACK_DESC(1, 0),\ TUD_MIDI_DESC_EP(_epout, _epsize, 1),\ TUD_MIDI_JACKID_IN_EMB(1),\ TUD_MIDI_DESC_EP(_epin, _epsize, 1),\ @@ -418,7 +420,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */ #define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN 7 #define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_ep, _interval) \ - TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_NO_SYNC | TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_NO_SYNC | TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval // AUDIO simple descriptor (UAC2) for 1 microphone input // - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source @@ -465,7 +467,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) @@ -514,7 +516,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) @@ -562,7 +564,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\ /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\ @@ -602,7 +604,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* optional interrupt endpoint */ \ // _int_pollingInterval : for LS/FS, expressed in frames (1ms each). 16 may be a good number? #define TUD_USBTMC_INT_DESCRIPTOR(_ep_interrupt, _ep_interrupt_size, _int_pollingInterval ) \ - 7, TUSB_DESC_ENDPOINT, _ep_interrupt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_interrupt_size), 0x16 + 7, TUSB_DESC_ENDPOINT, _ep_interrupt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_interrupt_size), _int_pollingInterval #define TUD_USBTMC_INT_DESCRIPTOR_LEN (7u) @@ -647,7 +649,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb #define TUD_DFU_DESC_LEN(_alt_count) (9 + (_alt_count) * 9) // Interface number, Alternate count, starting string index, attributes, detach timeout, transfer size -// Note: Alternate count must be numberic or macro, string index is increased by one for each Alt interface +// Note: Alternate count must be numeric or macro, string index is increased by one for each Alt interface #define TUD_DFU_DESCRIPTOR(_itfnum, _alt_count, _stridx, _attr, _timeout, _xfer_size) \ TU_XSTRCAT(_TUD_DFU_ALT_,_alt_count)(_itfnum, 0, _stridx), \ /* Function */ \ diff --git a/test-devices/composite-stm32/lib/tinyusb/device/usbd_control.c b/test-devices/composite-stm32/lib/tinyusb/device/usbd_control.c index 0995ef66..ea8eef28 100644 --- a/test-devices/composite-stm32/lib/tinyusb/device/usbd_control.c +++ b/test-devices/composite-stm32/lib/tinyusb/device/usbd_control.c @@ -53,10 +53,10 @@ typedef struct usbd_control_xfer_cb_t complete_cb; } usbd_control_xfer_t; -static usbd_control_xfer_t _ctrl_xfer; +tu_static usbd_control_xfer_t _ctrl_xfer; CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN -static uint8_t _usbd_ctrl_buf[CFG_TUD_ENDPOINT0_SIZE]; +tu_static uint8_t _usbd_ctrl_buf[CFG_TUD_ENDPOINT0_SIZE]; //--------------------------------------------------------------------+ // Application API @@ -93,7 +93,9 @@ static bool _data_stage_xact(uint8_t rhport) if ( _ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN ) { ep_addr = EDPT_CTRL_IN; - if ( xact_len ) memcpy(_usbd_ctrl_buf, _ctrl_xfer.buffer, xact_len); + if ( xact_len ) { + TU_VERIFY(0 == tu_memcpy_s(_usbd_ctrl_buf, CFG_TUD_ENDPOINT0_SIZE, _ctrl_xfer.buffer, xact_len)); + } } return usbd_edpt_xfer(rhport, ep_addr, xact_len ? _usbd_ctrl_buf : NULL, xact_len); diff --git a/test-devices/composite-stm32/lib/tinyusb/device/usbd_pvt.h b/test-devices/composite-stm32/lib/tinyusb/device/usbd_pvt.h index 6fad46db..8393d346 100644 --- a/test-devices/composite-stm32/lib/tinyusb/device/usbd_pvt.h +++ b/test-devices/composite-stm32/lib/tinyusb/device/usbd_pvt.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -96,6 +96,12 @@ void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr); // Check if endpoint is stalled bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr); +// Allocate packet buffer used by ISO endpoints +bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size); + +// Configure and enable an ISO endpoint according to descriptor +bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); + // Check if endpoint is ready (not busy and not stalled) TU_ATTR_ALWAYS_INLINE static inline bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr) diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dcd_dwc2.c b/test-devices/composite-stm32/lib/tinyusb/dwc2/dcd_dwc2.c index 7765afd8..22c82201 100644 --- a/test-devices/composite-stm32/lib/tinyusb/dwc2/dcd_dwc2.c +++ b/test-devices/composite-stm32/lib/tinyusb/dwc2/dcd_dwc2.c @@ -529,8 +529,10 @@ void dcd_init (uint8_t rhport) dwc2->dcfg |= DCFG_NZLSOHSK; // Clear all interrupts - dwc2->gintsts |= dwc2->gintsts; - dwc2->gotgint |= dwc2->gotgint; + uint32_t int_mask = dwc2->gintsts; + dwc2->gintsts |= int_mask; + int_mask = dwc2->gotgint; + dwc2->gotgint |= int_mask; // Required as part of core initialization. // TODO: How should mode mismatch be handled? It will cause @@ -1003,7 +1005,7 @@ static void handle_rxflvl_irq(uint8_t rhport) switch ( pktsts ) { - // Global OUT NAK: do nothign + // Global OUT NAK: do nothing case GRXSTS_PKTSTS_GLOBALOUTNAK: break; case GRXSTS_PKTSTS_SETUPRX: @@ -1219,7 +1221,8 @@ void dcd_int_handler(uint8_t rhport) { dwc2_regs_t *dwc2 = DWC2_REG(rhport); - uint32_t const int_status = dwc2->gintsts & dwc2->gintmsk; + uint32_t const int_mask = dwc2->gintmsk; + uint32_t const int_status = dwc2->gintsts & int_mask; if(int_status & GINTSTS_USBRST) { diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_stm32.h b/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_stm32.h index 337f611d..cb455bd9 100644 --- a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_stm32.h +++ b/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_stm32.h @@ -82,6 +82,12 @@ #define EP_MAX_FS 6 #define EP_FIFO_SIZE_FS 1280 +#elif CFG_TUSB_MCU == OPT_MCU_STM32U5 + #include "stm32u5xx.h" + #define USB_OTG_FS_PERIPH_BASE USB_OTG_FS_BASE + #define EP_MAX_FS 6 + #define EP_FIFO_SIZE_FS 1280 + #else #error "Unsupported MCUs" #endif @@ -110,19 +116,19 @@ static const dwc2_controller_t _dwc2_controller[] = // //--------------------------------------------------------------------+ -// SystemCoreClock is alrady included by family header +// SystemCoreClock is already included by family header // extern uint32_t SystemCoreClock; TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_enable(uint8_t rhport) { - NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum); + NVIC_EnableIRQ((IRQn_Type)_dwc2_controller[rhport].irqnum); } TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_disable (uint8_t rhport) { - NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum); + NVIC_DisableIRQ((IRQn_Type)_dwc2_controller[rhport].irqnum); } TU_ATTR_ALWAYS_INLINE diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/hwcfg_list.md b/test-devices/composite-stm32/lib/tinyusb/dwc2/hwcfg_list.md new file mode 100644 index 00000000..b5590da0 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/dwc2/hwcfg_list.md @@ -0,0 +1,777 @@ +# DWC2 Hardware Configuration Registers + +## Broadcom BCM2711 (Pi4) + +dwc2->guid = 2708A000 +dwc2->gsnpsid = 4F54280A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 228DDD50 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 2 +hw_cfg2->point2point = 0 +hw_cfg2->hs_phy_type = 1 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 7 +hw_cfg2->num_host_ch = 7 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 0 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = FF000E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 0 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 0 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 0 +hw_cfg3->lpm_mode = 0 +hw_cfg3->total_fifo_size = 4080 + +dwc2->ghwcfg4 = 1FF00020 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 0 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 0 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 15 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## EFM32GG FS + +dwc2->guid = 0 +dwc2->gsnpsid = 4F54330A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 228F5910 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 2 +hw_cfg2->point2point = 0 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 6 +hw_cfg2->num_host_ch = 13 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 0 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 1F204E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 0 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 1 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 0 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 0 +hw_cfg3->lpm_mode = 0 +hw_cfg3->total_fifo_size = 498 + +dwc2->ghwcfg4 = 1BF08030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 2 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 13 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## ESP32-S2 Fullspeed + +dwc2->guid = 0 +dwc2->gsnpsid = 4F54400A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 224DD930 +hw_cfg2->op_mode = 2 +hw_cfg2->arch = 3 +hw_cfg2->point2point = 0 +hw_cfg2->hs_phy_type = 1 +hw_cfg2->fs_phy_type = 2 +hw_cfg2->num_dev_ep = 6 +hw_cfg2->num_host_ch = 9 +hw_cfg2->period_channel_support = 0 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 1 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 22 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = C804B5 +hw_cfg3->xfer_size_width = 10 +hw_cfg3->packet_size_width = 5 +hw_cfg3->otg_enable = 0 +hw_cfg3->i2c_enable = 0 +hw_cfg3->vendor_ctrl_itf = 1 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 1 +hw_cfg3->otg_adp_support = 1 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 1 +hw_cfg3->lpm_mode = 0 +hw_cfg3->total_fifo_size = 23130 + +dwc2->ghwcfg4 = D3F0A030 +hw_cfg4->num_dev_period_in_ep = 10 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 0 +hw_cfg4->hibernation = 1 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 1 +hw_cfg4->acg_enable = 1 +hw_cfg4->utmi_phy_data_width = 1 +hw_cfg4->dev_ctrl_ep_num = 10 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 0 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 0 +hw_cfg4->dedicated_fifos = 0 +hw_cfg4->num_dev_in_eps = 13 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 1 + +## STM32F407 and STM32F207 + +STM32F407 and STM32F207 are exactly the same + +### STM32F407 Fullspeed + +dwc2->guid = 1200 +dwc2->gsnpsid = 4F54281A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229DCD20 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 0 +hw_cfg2->point2point = 1 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 3 +hw_cfg2->num_host_ch = 7 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 20001E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 1 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 0 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 0 +hw_cfg3->lpm_mode = 0 +hw_cfg3->total_fifo_size = 512 + +dwc2->ghwcfg4 = FF08030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 2 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 7 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +### STM32F407 Highspeed + +dwc2->guid = 1100 +dwc2->gsnpsid = 4F54281A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229ED590 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 2 +hw_cfg2->point2point = 0 +hw_cfg2->hs_phy_type = 2 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 5 +hw_cfg2->num_host_ch = 11 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 3F403E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 1 +hw_cfg3->vendor_ctrl_itf = 1 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 0 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 0 +hw_cfg3->lpm_mode = 0 +hw_cfg3->total_fifo_size = 1012 + +dwc2->ghwcfg4 = 17F00030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 0 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 11 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## STM32F411 Fullspeed + +dwc2->guid = 1200 +dwc2->gsnpsid = 4F54281A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229DCD20 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 0 +hw_cfg2->point2point = 1 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 3 +hw_cfg2->num_host_ch = 7 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 20001E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 1 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 0 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 0 +hw_cfg3->lpm_mode = 0 +hw_cfg3->total_fifo_size = 512 + +dwc2->ghwcfg4 = FF08030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 2 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 7 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## STM32F412 FS + +dwc2->guid = 2000 +dwc2->gsnpsid = 4F54320A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229ED520 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 0 +hw_cfg2->point2point = 1 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 5 +hw_cfg2->num_host_ch = 11 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 200D1E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 1 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 1 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 1 +hw_cfg3->lpm_mode = 1 +hw_cfg3->total_fifo_size = 512 + +dwc2->ghwcfg4 = 17F08030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 2 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 11 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## STM32F723 + +### STM32F723 HighSpeed + +dwc2->guid = 3100 +dwc2->gsnpsid = 4F54330A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229FE1D0 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 2 +hw_cfg2->point2point = 0 +hw_cfg2->hs_phy_type = 3 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 8 +hw_cfg2->num_host_ch = 15 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 3EED2E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 0 +hw_cfg3->vendor_ctrl_itf = 1 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 1 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 1 +hw_cfg3->lpm_mode = 1 +hw_cfg3->total_fifo_size = 1006 + +dwc2->ghwcfg4 = 23F00030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 0 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 1 +hw_cfg4->dma_desc_enable = 1 +hw_cfg4->dma_dynamic = 0 + +### STM32F723 Fullspeed + +dwc2->guid = 3000 +dwc2->gsnpsid = 4F54330A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229ED520 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 0 +hw_cfg2->point2point = 1 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 5 +hw_cfg2->num_host_ch = 11 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 200D1E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 1 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 1 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 1 +hw_cfg3->lpm_mode = 1 +hw_cfg3->total_fifo_size = 512 + +dwc2->ghwcfg4 = 17F08030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 2 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 11 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## STM32F767 FS + +dwc2->guid = 2000 +dwc2->gsnpsid = 4F54320A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229ED520 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 0 +hw_cfg2->point2point = 1 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 5 +hw_cfg2->num_host_ch = 11 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 200D1E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 1 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 1 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 1 +hw_cfg3->lpm_mode = 1 +hw_cfg3->total_fifo_size = 512 + +dwc2->ghwcfg4 = 17F08030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 2 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 11 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## STM32H743 (both cores HS) + +dwc2->guid = 2300 +dwc2->gsnpsid = 4F54330A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229FE190 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 2 +hw_cfg2->point2point = 0 +hw_cfg2->hs_phy_type = 2 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 8 +hw_cfg2->num_host_ch = 15 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 3B8D2E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 0 +hw_cfg3->vendor_ctrl_itf = 1 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 1 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 1 +hw_cfg3->lpm_mode = 1 +hw_cfg3->total_fifo_size = 952 + +dwc2->ghwcfg4 = E3F00030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 0 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 1 +hw_cfg4->dma_desc_enable = 1 +hw_cfg4->dma_dynamic = 1 + +## STM32L476 FS + +dwc2->guid = 2000 +dwc2->gsnpsid = 4F54310A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229ED520 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 0 +hw_cfg2->point2point = 1 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 5 +hw_cfg2->num_host_ch = 11 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 200D1E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 1 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 1 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 1 +hw_cfg3->lpm_mode = 1 +hw_cfg3->total_fifo_size = 512 + +dwc2->ghwcfg4 = 17F08030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 2 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 11 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## GD32VF103 Fullspeed + +dwc2->guid = 1000 +dwc2->gsnpsid = 0 +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 0 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 0 +hw_cfg2->point2point = 0 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 0 +hw_cfg2->num_dev_ep = 0 +hw_cfg2->num_host_ch = 0 +hw_cfg2->period_channel_support = 0 +hw_cfg2->enable_dynamic_fifo = 0 +hw_cfg2->mul_cpu_int = 0 +hw_cfg2->nperiod_tx_q_depth = 0 +hw_cfg2->host_period_tx_q_depth = 0 +hw_cfg2->dev_token_q_depth = 0 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 0 +hw_cfg3->xfer_size_width = 0 +hw_cfg3->packet_size_width = 0 +hw_cfg3->otg_enable = 0 +hw_cfg3->i2c_enable = 0 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 0 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 0 +hw_cfg3->lpm_mode = 0 +hw_cfg3->total_fifo_size = 0 + +dwc2->ghwcfg4 = 0 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 0 +hw_cfg4->ahb_freq_min = 0 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 0 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 0 +hw_cfg4->vbus_valid_filter_enabled = 0 +hw_cfg4->a_valid_filter_enabled = 0 +hw_cfg4->b_valid_filter_enabled = 0 +hw_cfg4->dedicated_fifos = 0 +hw_cfg4->num_dev_in_eps = 0 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## XMC4500 + +dwc2->guid = AEC000 +dwc2->gsnpsid = 4F54292A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 228F5930 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 2 +hw_cfg2->point2point = 1 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 6 +hw_cfg2->num_host_ch = 13 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 0 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 27A01E5 +hw_cfg3->xfer_size_width = 5 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 1 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 0 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 0 +hw_cfg3->lpm_mode = 0 +hw_cfg3->total_fifo_size = 634 + +dwc2->ghwcfg4 = DBF08030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 2 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 13 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 1 diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal.h index 9d11866d..f092e8ff 100644 --- a/test-devices/composite-stm32/lib/tinyusb/osal/osal.h +++ b/test-devices/composite-stm32/lib/tinyusb/osal/osal.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -33,17 +33,24 @@ #include "common/tusb_common.h" -// Return immediately -#define OSAL_TIMEOUT_NOTIMEOUT (0) -// Default timeout -#define OSAL_TIMEOUT_NORMAL (10) -// Wait forever -#define OSAL_TIMEOUT_WAIT_FOREVER (UINT32_MAX) +typedef void (*osal_task_func_t)( void * ); +// Timeout +#define OSAL_TIMEOUT_NOTIMEOUT (0) // Return immediately +#define OSAL_TIMEOUT_NORMAL (10) // Default timeout +#define OSAL_TIMEOUT_WAIT_FOREVER (UINT32_MAX) // Wait forever #define OSAL_TIMEOUT_CONTROL_XFER OSAL_TIMEOUT_WAIT_FOREVER -typedef void (*osal_task_func_t)( void * ); +// Mutex is required when using a preempted RTOS or MCU has multiple cores +#if (CFG_TUSB_OS == OPT_OS_NONE) && !TUP_MCU_MULTIPLE_CORE + #define OSAL_MUTEX_REQUIRED 0 + #define OSAL_MUTEX_DEF(_name) uint8_t :0 +#else + #define OSAL_MUTEX_REQUIRED 1 + #define OSAL_MUTEX_DEF(_name) osal_mutex_def_t _name +#endif +// OS thin implementation #if CFG_TUSB_OS == OPT_OS_NONE #include "osal_none.h" #elif CFG_TUSB_OS == OPT_OS_FREERTOS diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal_freertos.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal_freertos.h index 52db336f..477f6489 100644 --- a/test-devices/composite-stm32/lib/tinyusb/osal/osal_freertos.h +++ b/test-devices/composite-stm32/lib/tinyusb/osal/osal_freertos.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -37,6 +37,43 @@ extern "C" { #endif +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF PROTYPES +//--------------------------------------------------------------------+ + +#if configSUPPORT_STATIC_ALLOCATION + typedef StaticSemaphore_t osal_semaphore_def_t; + typedef StaticSemaphore_t osal_mutex_def_t; +#else + // not used therefore defined to smallest possible type to save space + typedef uint8_t osal_semaphore_def_t; + typedef uint8_t osal_mutex_def_t; +#endif + +typedef SemaphoreHandle_t osal_semaphore_t; +typedef SemaphoreHandle_t osal_mutex_t; + +// _int_set is not used with an RTOS +#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ + static _type _name##_##buf[_depth];\ + osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf }; + +typedef struct +{ + uint16_t depth; + uint16_t item_sz; + void* buf; +#if configSUPPORT_STATIC_ALLOCATION + StaticQueue_t sq; +#endif +}osal_queue_def_t; + +typedef QueueHandle_t osal_queue_t; + +//--------------------------------------------------------------------+ +// TASK API +//--------------------------------------------------------------------+ + TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec) { if (msec == OSAL_TIMEOUT_WAIT_FOREVER) return portMAX_DELAY; @@ -51,9 +88,6 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec) return ticks; } -//--------------------------------------------------------------------+ -// TASK API -//--------------------------------------------------------------------+ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) { vTaskDelay( pdMS_TO_TICKS(msec) ); @@ -62,12 +96,15 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) //--------------------------------------------------------------------+ // Semaphore API //--------------------------------------------------------------------+ -typedef StaticSemaphore_t osal_semaphore_def_t; -typedef SemaphoreHandle_t osal_semaphore_t; TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) { +#if configSUPPORT_STATIC_ALLOCATION return xSemaphoreCreateBinaryStatic(semdef); +#else + (void) semdef; + return xSemaphoreCreateBinary(); +#endif } TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) @@ -78,7 +115,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t se } else { - BaseType_t xHigherPriorityTaskWoken; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t res = xSemaphoreGiveFromISR(sem_hdl, &xHigherPriorityTaskWoken); #if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3 @@ -92,7 +129,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t se } } -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) { return xSemaphoreTake(sem_hdl, _osal_ms2tick(msec)); } @@ -105,15 +142,18 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t c //--------------------------------------------------------------------+ // MUTEX API (priority inheritance) //--------------------------------------------------------------------+ -typedef StaticSemaphore_t osal_mutex_def_t; -typedef SemaphoreHandle_t osal_mutex_t; TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) { +#if configSUPPORT_STATIC_ALLOCATION return xSemaphoreCreateMutexStatic(mdef); +#else + (void) mdef; + return xSemaphoreCreateMutex(); +#endif } -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) { return osal_semaphore_wait(mutex_hdl, msec); } @@ -127,25 +167,13 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd // QUEUE API //--------------------------------------------------------------------+ -// _int_set is not used with an RTOS -#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ - static _type _name##_##buf[_depth];\ - osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf }; - -typedef struct -{ - uint16_t depth; - uint16_t item_sz; - void* buf; - - StaticQueue_t sq; -}osal_queue_def_t; - -typedef QueueHandle_t osal_queue_t; - TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) { - return xQueueCreateStatic(qdef->depth, qdef->item_sz, (uint8_t*) qdef->buf, &qdef->sq); +#if configSUPPORT_STATIC_ALLOCATION + return xQueueCreateStatic(qdef->depth, qdef->item_sz, (uint8_t*) qdef->buf, &qdef->sq); +#else + return xQueueCreate(qdef->depth, qdef->item_sz); +#endif } TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) @@ -161,7 +189,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void } else { - BaseType_t xHigherPriorityTaskWoken; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t res = xQueueSendToBackFromISR(qhdl, data, &xHigherPriorityTaskWoken); #if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3 diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal_none.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal_none.h index 9c80e454..5f407378 100644 --- a/test-devices/composite-stm32/lib/tinyusb/osal/osal_none.h +++ b/test-devices/composite-stm32/lib/tinyusb/osal/osal_none.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -35,6 +35,10 @@ // TASK API //--------------------------------------------------------------------+ +#if CFG_TUH_ENABLED +// currently only needed/available in host mode +void osal_task_delay(uint32_t msec); +#endif //--------------------------------------------------------------------+ // Binary Semaphore API @@ -82,6 +86,10 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t s typedef osal_semaphore_def_t osal_mutex_def_t; typedef osal_semaphore_t osal_mutex_t; +#if OSAL_MUTEX_REQUIRED +// Note: multiple cores MCUs usually do provide IPC API for mutex +// or we can use std atomic function + TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) { mdef->count = 1; @@ -98,6 +106,14 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd return osal_semaphore_post(mutex_hdl, false); } +#else + +#define osal_mutex_create(_mdef) (NULL) +#define osal_mutex_lock(_mutex_hdl, _ms) (true) +#define osal_mutex_unlock(_mutex_hdl) (true) + +#endif + //--------------------------------------------------------------------+ // QUEUE API //--------------------------------------------------------------------+ diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal_pico.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal_pico.h index 8b428d64..e6efa096 100644 --- a/test-devices/composite-stm32/lib/tinyusb/osal/osal_pico.h +++ b/test-devices/composite-stm32/lib/tinyusb/osal/osal_pico.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtthread.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtthread.h index f8452bfb..18eb9c69 100644 --- a/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtthread.h +++ b/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtthread.h @@ -63,7 +63,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t se } TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) { - // TODO: implement + rt_sem_control(sem_hdl, RT_IPC_CMD_RESET, 0); } //--------------------------------------------------------------------+ diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtx4.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtx4.h index dea1c12c..e443135e 100644 --- a/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtx4.h +++ b/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtx4.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2021 Tian Yunhao (t123yh) @@ -115,7 +115,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd os_mbx_declare(_name##__mbox, _depth); \ _declare_box(_name##__pool, sizeof(_type), _depth); \ osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .pool = _name##__pool, .mbox = _name##__mbox }; - + typedef struct { diff --git a/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c b/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c index f17176ae..30a2e9c8 100644 --- a/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c +++ b/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Nathan Conrad @@ -6,6 +6,8 @@ * Portions: * Copyright (c) 2016 STMicroelectronics * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2022 Simon Küppers (skuep) + * Copyright (c) 2022 HiFiPhile * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -64,10 +66,6 @@ * - STALL handled, but not tested. * - Does it work? No clue. * - All EP BTABLE buffers are created based on max packet size of first EP opened with that address. - * - No isochronous endpoints - * - Endpoint index is the ID of the endpoint - * - This means that priority is given to endpoints with lower ID numbers - * - Code is mixing up EP IX with EP ID. Everywhere. * - Packet buffer memory is copied in the interrupt. * - This is better for performance, but means interrupts are disabled for longer * - DMA may be the best choice, but it could also be pushed to the USBD task. @@ -103,24 +101,15 @@ #include "tusb_option.h" -#if defined(STM32F102x6) || defined(STM32F102xB) || \ - defined(STM32F103x6) || defined(STM32F103xB) || \ - defined(STM32F103xE) || defined(STM32F103xG) -#define STM32F1_FSDEV -#endif - -#if CFG_TUD_ENABLED && \ - ( TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32F3, OPT_MCU_STM32L0, OPT_MCU_STM32L1, OPT_MCU_STM32G4, OPT_MCU_STM32WB) || \ - (TU_CHECK_MCU(OPT_MCU_STM32F1) && defined(STM32F1_FSDEV)) \ - ) - -// In order to reduce the dependance on HAL, we undefine this. -// Some definitions are copied to our private include file. -#undef USE_HAL_DRIVER +#if CFG_TUD_ENABLED && defined(TUP_USBIP_FSDEV) #include "device/dcd.h" -#include "dcd_stm32_fsdev_pvt_st.h" +#ifdef TUP_USBIP_FSDEV_STM32 + // Undefine to reduce the dependence on HAL + #undef USE_HAL_DRIVER + #include "dcd_stm32_fsdev_pvt_st.h" +#endif /***************************************************** * Configuration @@ -142,74 +131,99 @@ # define DCD_STM32_BTABLE_LENGTH (PMA_LENGTH - DCD_STM32_BTABLE_BASE) #endif -// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval) -// We disable SOF for now until needed later on -#ifndef USE_SOF -# define USE_SOF 0 -#endif - /*************************************************** * Checks, structs, defines, function definitions, etc. */ TU_VERIFY_STATIC((MAX_EP_COUNT) <= STFSDEV_EP_COUNT, "Only 8 endpoints supported on the hardware"); - -TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_LENGTH))<=(PMA_LENGTH), - "BTABLE does not fit in PMA RAM"); - +TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_LENGTH))<=(PMA_LENGTH), "BTABLE does not fit in PMA RAM"); TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligned to 8 bytes"); +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + // One of these for every EP IN & OUT, uses a bit of RAM.... typedef struct { uint8_t * buffer; - // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API + tu_fifo_t * ff; uint16_t total_len; uint16_t queued_len; uint16_t pma_ptr; - uint8_t max_packet_size; - uint8_t pma_alloc_size; + uint16_t max_packet_size; + uint16_t pma_alloc_size; + uint8_t ep_idx; // index for USB_EPnR register } xfer_ctl_t; +// EP allocator +typedef struct +{ + uint8_t ep_num; + uint8_t ep_type; + bool allocated[2]; +} ep_alloc_t; + static xfer_ctl_t xfer_status[MAX_EP_COUNT][2]; -static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t epnum, uint32_t dir) -{ - return &xfer_status[epnum][dir]; -} +static ep_alloc_t ep_alloc_status[STFSDEV_EP_COUNT]; static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6]; static uint8_t remoteWakeCountdown; // When wake is requested +//--------------------------------------------------------------------+ +// Prototypes +//--------------------------------------------------------------------+ + // into the stack. static void dcd_handle_bus_reset(void); static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix); static void dcd_ep_ctr_handler(void); -// PMA allocation/access +// PMA allocation/access static uint8_t open_ep_count; static uint16_t ep_buf_ptr; ///< Points to first free memory location static void dcd_pma_alloc_reset(void); static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length); static void dcd_pma_free(uint8_t ep_addr); +static void dcd_ep_free(uint8_t ep_addr); +static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type); static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes); static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes); -//static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes); -//static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes); +static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes); +static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes); + +//--------------------------------------------------------------------+ +// Inline helper +//--------------------------------------------------------------------+ + +TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t ep_addr) +{ + uint8_t epnum = tu_edpt_number(ep_addr); + uint8_t dir = tu_edpt_dir(ep_addr); + // Fix -Werror=null-dereference + TU_ASSERT(epnum < MAX_EP_COUNT, &xfer_status[0][0]); + + return &xfer_status[epnum][dir]; +} // Using a function due to better type checks // This seems better than having to do type casts everywhere else -static inline void reg16_clear_bits(__IO uint16_t *reg, uint16_t mask) { +TU_ATTR_ALWAYS_INLINE static inline void reg16_clear_bits(__IO uint16_t *reg, uint16_t mask) { *reg = (uint16_t)(*reg & ~mask); } // Bits in ISTR are cleared upon writing 0 -static inline void clear_istr_bits(uint16_t mask) { +TU_ATTR_ALWAYS_INLINE static inline void clear_istr_bits(uint16_t mask) { USB->ISTR = ~mask; } +//--------------------------------------------------------------------+ +// Controller API +//--------------------------------------------------------------------+ + void dcd_init (uint8_t rhport) { /* Clocks should already be enabled */ @@ -222,7 +236,7 @@ void dcd_init (uint8_t rhport) { asm("NOP"); } - // Perform USB peripheral reset + // Perform USB peripheral reset USB->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; for(uint32_t i = 0; i<200; i++) // should be a few us { @@ -235,7 +249,7 @@ void dcd_init (uint8_t rhport) asm("NOP"); } USB->CNTR = 0; // Enable USB - + USB->BTABLE = DCD_STM32_BTABLE_BASE; USB->ISTR = 0; // Clear pending interrupts @@ -247,9 +261,9 @@ void dcd_init (uint8_t rhport) pcd_set_endpoint(USB,i,0u); } - USB->CNTR |= USB_CNTR_RESETM | (USE_SOF ? USB_CNTR_SOFM : 0) | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; + USB->CNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; dcd_handle_bus_reset(); - + // Enable pull-up if supported if ( dcd_connect ) dcd_connect(rhport); } @@ -292,7 +306,14 @@ void dcd_sof_enable(uint8_t rhport, bool en) (void) rhport; (void) en; - // TODO implement later + if (en) + { + USB->CNTR |= USB_CNTR_SOFM; + } + else + { + USB->CNTR &= (uint16_t) ~USB_CNTR_SOFM; + } } // Enable device interrupt @@ -302,7 +323,8 @@ void dcd_int_enable (uint8_t rhport) // Member here forces write to RAM before allowing ISR to execute __DSB(); __ISB(); -#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 +#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || \ + CFG_TUSB_MCU == OPT_MCU_STM32L4 NVIC_EnableIRQ(USB_IRQn); #elif CFG_TUSB_MCU == OPT_MCU_STM32L1 @@ -340,6 +362,9 @@ void dcd_int_enable (uint8_t rhport) NVIC_EnableIRQ(USB_HP_IRQn); NVIC_EnableIRQ(USB_LP_IRQn); +#elif CFG_TUSB_MCU == OPT_MCU_STM32L5 + NVIC_EnableIRQ(USB_FS_IRQn); + #else #error Unknown arch in USB driver #endif @@ -350,7 +375,8 @@ void dcd_int_disable(uint8_t rhport) { (void)rhport; -#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 +#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || \ + CFG_TUSB_MCU == OPT_MCU_STM32L4 NVIC_DisableIRQ(USB_IRQn); #elif CFG_TUSB_MCU == OPT_MCU_STM32L1 NVIC_DisableIRQ(USB_LP_IRQn); @@ -386,6 +412,9 @@ void dcd_int_disable(uint8_t rhport) NVIC_DisableIRQ(USB_HP_IRQn); NVIC_DisableIRQ(USB_LP_IRQn); +#elif CFG_TUSB_MCU == OPT_MCU_STM32L5 + NVIC_DisableIRQ(USB_FS_IRQn); + #else #error Unknown arch in USB driver #endif @@ -400,7 +429,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) (void) dev_addr; // Respond with status - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); + dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK | 0x00, NULL, 0); // DCD can only set address after status for this request is complete. // do it at dcd_edpt0_status_complete() @@ -441,10 +470,17 @@ static void dcd_handle_bus_reset(void) //__IO uint16_t * const epreg = &(EPREG(0)); USB->DADDR = 0u; // disable USB peripheral by clearing the EF flag - // Clear all EPREG (or maybe this is automatic? I'm not sure) + for(uint32_t i=0; itotal_len != xfer->queued_len)) /* TX not complete */ { dcd_transmit_packet(xfer, EPindex); } else /* TX Complete */ { - dcd_event_xfer_complete(0, (uint8_t)(0x80 + EPindex), xfer->total_len, XFER_RESULT_SUCCESS, true); + dcd_event_xfer_complete(0, ep_addr, xfer->total_len, XFER_RESULT_SUCCESS, true); } } @@ -490,9 +527,9 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr) { uint32_t EPindex = wIstr & USB_ISTR_EP_ID; uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex); - uint32_t count = pcd_get_ep_rx_cnt(USB,EPindex); + uint8_t ep_addr = wEPRegVal & USB_EPADDR_FIELD; - xfer_ctl_t *xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_OUT); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); // Verify the CTR_RX bit is set. This was in the ST Micro code, // but I'm not sure it's actually necessary? @@ -500,12 +537,13 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr) { return; } - - if((EPindex == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) /* Setup packet */ + + if((ep_addr == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) /* Setup packet */ { // The setup_received function uses memcpy, so this must first copy the setup data into // user memory, to allow for the 32-bit access that memcpy performs. uint8_t userMemBuf[8]; + uint32_t count = pcd_get_ep_rx_cnt(USB, EPindex); /* Get SETUP Packet*/ if(count == 8) // Setup packet should always be 8 bytes. If not, ignore it, and try again. { @@ -518,23 +556,33 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr) } else { + uint32_t count; + /* Read from correct register when ISOCHRONOUS (double buffered) */ + if ( (wEPRegVal & USB_EP_DTOG_RX) && ( (wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) ) { + count = pcd_get_ep_tx_cnt(USB, EPindex); + } else { + count = pcd_get_ep_rx_cnt(USB, EPindex); + } + + TU_ASSERT(count <= xfer->max_packet_size, /**/); + // Clear RX CTR interrupt flag - if(EPindex != 0u) + if(ep_addr != 0u) { pcd_clear_rx_ep_ctr(USB, EPindex); } if (count != 0U) { -#if 0 // TODO support dcd_edpt_xfer_fifo API + uint16_t addr = *pcd_ep_rx_address_ptr(USB, EPindex); + if (xfer->ff) { - dcd_read_packet_memory_ff(xfer->ff, *pcd_ep_rx_address_ptr(USB,EPindex), count); + dcd_read_packet_memory_ff(xfer->ff, addr, count); } else -#endif { - dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), *pcd_ep_rx_address_ptr(USB,EPindex), count); + dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), addr, count); } xfer->queued_len = (uint16_t)(xfer->queued_len + count); @@ -543,7 +591,7 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr) if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len)) { /* RX COMPLETE */ - dcd_event_xfer_complete(0, EPindex, xfer->queued_len, XFER_RESULT_SUCCESS, true); + dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true); // Though the host could still send, we don't know. // Does the bulk pipe need to be reset to valid to allow for a ZLP? } @@ -551,21 +599,26 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr) { uint32_t remaining = (uint32_t)xfer->total_len - (uint32_t)xfer->queued_len; if(remaining >= xfer->max_packet_size) { - pcd_set_ep_rx_cnt(USB, EPindex,xfer->max_packet_size); + pcd_set_ep_rx_bufsize(USB, EPindex,xfer->max_packet_size); } else { - pcd_set_ep_rx_cnt(USB, EPindex,remaining); + pcd_set_ep_rx_bufsize(USB, EPindex,remaining); + } + + if (!((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS)) { + /* Set endpoint active again for receiving more data. + * Note that isochronous endpoints stay active always */ + pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID); } - pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID); } } // For EP0, prepare to receive another SETUP packet. // Clear CTR last so that a new packet does not overwrite the packing being read. // (Based on the docs, it seems SETUP will always be accepted after CTR is cleared) - if(EPindex == 0u) + if(ep_addr == 0u) { // Always be prepared for a status packet... - pcd_set_ep_rx_cnt(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE); + pcd_set_ep_rx_bufsize(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE); pcd_clear_rx_ep_ctr(USB, EPindex); } } @@ -602,6 +655,12 @@ void dcd_int_handler(uint8_t rhport) { // dcd_ep_ctr_handler(), so less need to loop here. The other interrupts shouldn't // be triggered repeatedly. + /* Put SOF flag at the beginning of ISR in case to get least amount of jitter if it is used for timing purposes */ + if(int_status & USB_ISTR_SOF) { + clear_istr_bits(USB_ISTR_SOF); + dcd_event_sof(0, USB->FNR & USB_FNR_FN, true); + } + if(int_status & USB_ISTR_RESET) { // USBRST is start of reset. clear_istr_bits(USB_ISTR_RESET); @@ -639,13 +698,6 @@ void dcd_int_handler(uint8_t rhport) { dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); } -#if USE_SOF - if(int_status & USB_ISTR_SOF) { - clear_istr_bits(USB_ISTR_SOF); - dcd_event_bus_signal(0, DCD_EVENT_SOF, true); - } -#endif - if(int_status & USB_ISTR_ESOF) { if(remoteWakeCountdown == 1u) { @@ -683,31 +735,30 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * re static void dcd_pma_alloc_reset(void) { + open_ep_count = 0; ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT; // 8 bytes per endpoint (two TX and two RX words, each) //TU_LOG2("dcd_pma_alloc_reset()\r\n"); for(uint32_t i=0; ipma_alloc_size = 0U; - xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_alloc_size = 0U; - xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_ptr = 0U; - xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_ptr = 0U; + xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_OUT))->pma_alloc_size = 0U; + xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_alloc_size = 0U; + xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_OUT))->pma_ptr = 0U; + xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_ptr = 0U; } } /*** * Allocate a section of PMA - * + * * If the EP number has already been allocated, and the new allocation * is larger than the old allocation, then this will fail with a TU_ASSERT. * (This is done to simplify the code. More complicated algorithms could be used) - * + * * During failure, TU_ASSERT is used. If this happens, rework/reallocate memory manually. */ static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length) { - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - xfer_ctl_t* epXferCtl = xfer_ctl_ptr(epnum,dir); + xfer_ctl_t* epXferCtl = xfer_ctl_ptr(ep_addr); if(epXferCtl->pma_alloc_size != 0U) { @@ -716,13 +767,15 @@ static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length) TU_ASSERT(length <= epXferCtl->pma_alloc_size, 0xFFFF); // Verify no larger than previous alloc return epXferCtl->pma_ptr; } - - uint16_t addr = ep_buf_ptr; + + open_ep_count++; + + uint16_t addr = ep_buf_ptr; ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer - + // Verify no overflow TU_ASSERT(ep_buf_ptr <= PMA_LENGTH, 0xFFFF); - + epXferCtl->pma_ptr = addr; epXferCtl->pma_alloc_size = length; //TU_LOG2("dcd_pma_alloc(%x,%x)=%x\r\n",ep_addr,length,addr); @@ -735,12 +788,9 @@ static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length) */ static void dcd_pma_free(uint8_t ep_addr) { - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - // Presently, this should never be called for EP0 IN/OUT TU_ASSERT(open_ep_count > 2, /**/); - TU_ASSERT(xfer_ctl_ptr(epnum,dir)->max_packet_size != 0, /**/); + TU_ASSERT(xfer_ctl_ptr(ep_addr)->max_packet_size != 0, /**/); open_ep_count--; // If count is 2, only EP0 should be open, so allocations can be mostly reset. @@ -752,10 +802,83 @@ static void dcd_pma_free(uint8_t ep_addr) // Skip EP0 for(uint32_t i=1; ipma_alloc_size = 0U; - xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_alloc_size = 0U; - xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_ptr = 0U; - xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_ptr = 0U; + xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_OUT))->pma_alloc_size = 0U; + xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_alloc_size = 0U; + xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_OUT))->pma_ptr = 0U; + xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_ptr = 0U; + } + } +} + +/*** + * Allocate hardware endpoint + */ +static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + for(uint8_t i = 0; i < STFSDEV_EP_COUNT; i++) + { + // Check if already allocated + if(ep_alloc_status[i].allocated[dir] && + ep_alloc_status[i].ep_type == ep_type && + ep_alloc_status[i].ep_num == epnum) + { + return i; + } + + // If EP of current direction is not allocated + // Except for ISO endpoint, both direction should be free + if(!ep_alloc_status[i].allocated[dir] && + (ep_type != TUSB_XFER_ISOCHRONOUS || !ep_alloc_status[i].allocated[dir ^ 1])) + { + // Check if EP number is the same + if(ep_alloc_status[i].ep_num == 0xFF || + ep_alloc_status[i].ep_num == epnum) + { + // One EP pair has to be the same type + if(ep_alloc_status[i].ep_type == 0xFF || + ep_alloc_status[i].ep_type == ep_type) + { + ep_alloc_status[i].ep_num = epnum; + ep_alloc_status[i].ep_type = ep_type; + ep_alloc_status[i].allocated[dir] = true; + + return i; + } + } + } + } + + // Allocation failed + TU_ASSERT(0); +} + +/*** + * Free hardware endpoint + */ +static void dcd_ep_free(uint8_t ep_addr) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + for(uint8_t i = 0; i < STFSDEV_EP_COUNT; i++) + { + // Check if EP number & dir are the same + if(ep_alloc_status[i].ep_num == epnum && + ep_alloc_status[i].allocated[dir] == dir) + { + ep_alloc_status[i].allocated[dir] = false; + // Reset entry if ISO endpoint or both direction are free + if(ep_alloc_status[i].ep_type == TUSB_XFER_ISOCHRONOUS || + !ep_alloc_status[i].allocated[dir ^ 1]) + { + ep_alloc_status[i].ep_num = 0xFF; + ep_alloc_status[i].ep_type = 0xFF; + + return; + } } } } @@ -766,27 +889,24 @@ static void dcd_pma_free(uint8_t ep_addr) bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) { (void)rhport; - uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); + uint8_t const ep_idx = dcd_ep_alloc(p_endpoint_desc->bEndpointAddress, p_endpoint_desc->bmAttributes.xfer); uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); - const uint16_t epMaxPktSize = tu_edpt_packet_size(p_endpoint_desc); + const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc); + const uint16_t buffer_size = pcd_aligned_buffer_size(packet_size); uint16_t pma_addr; uint32_t wType; - - // Isochronous not supported (yet), and some other driver assumptions. - TU_ASSERT(p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS); - TU_ASSERT(epnum < MAX_EP_COUNT); + + TU_ASSERT(ep_idx < STFSDEV_EP_COUNT); + TU_ASSERT(buffer_size <= 1024); // Set type switch(p_endpoint_desc->bmAttributes.xfer) { case TUSB_XFER_CONTROL: wType = USB_EP_CONTROL; break; -#if (0) - case TUSB_XFER_ISOCHRONOUS: // FIXME: Not yet supported + case TUSB_XFER_ISOCHRONOUS: wType = USB_EP_ISOCHRONOUS; break; -#endif - case TUSB_XFER_BULK: wType = USB_EP_CONTROL; break; @@ -799,30 +919,49 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc TU_ASSERT(false); } - pcd_set_eptype(USB, epnum, wType); - pcd_set_ep_address(USB, epnum, epnum); + pcd_set_eptype(USB, ep_idx, wType); + pcd_set_ep_address(USB, ep_idx, tu_edpt_number(p_endpoint_desc->bEndpointAddress)); // Be normal, for now, instead of only accepting zero-byte packets (on control endpoint) // or being double-buffered (bulk endpoints) pcd_clear_ep_kind(USB,0); - pma_addr = dcd_pma_alloc(p_endpoint_desc->bEndpointAddress, epMaxPktSize); + /* Create a packet memory buffer area. For isochronous endpoints, + * use the same buffer as the double buffer, essentially disabling double buffering */ + pma_addr = dcd_pma_alloc(p_endpoint_desc->bEndpointAddress, buffer_size); - if(dir == TUSB_DIR_IN) + if( (dir == TUSB_DIR_IN) || (wType == USB_EP_ISOCHRONOUS) ) { - *pcd_ep_tx_address_ptr(USB, epnum) = pma_addr; - pcd_set_ep_tx_cnt(USB, epnum, epMaxPktSize); - pcd_clear_tx_dtog(USB, epnum); - pcd_set_ep_tx_status(USB,epnum,USB_EP_TX_NAK); + *pcd_ep_tx_address_ptr(USB, ep_idx) = pma_addr; + pcd_set_ep_tx_bufsize(USB, ep_idx, buffer_size); + pcd_clear_tx_dtog(USB, ep_idx); } - else + + if( (dir == TUSB_DIR_OUT) || (wType == USB_EP_ISOCHRONOUS) ) { - *pcd_ep_rx_address_ptr(USB, epnum) = pma_addr; - pcd_set_ep_rx_cnt(USB, epnum, epMaxPktSize); - pcd_clear_rx_dtog(USB, epnum); - pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_NAK); + *pcd_ep_rx_address_ptr(USB, ep_idx) = pma_addr; + pcd_set_ep_rx_bufsize(USB, ep_idx, buffer_size); + pcd_clear_rx_dtog(USB, ep_idx); } - xfer_ctl_ptr(epnum, dir)->max_packet_size = epMaxPktSize; + /* Enable endpoint */ + if (dir == TUSB_DIR_IN) + { + if(wType == USB_EP_ISOCHRONOUS) { + pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); + } else { + pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK); + } + } else + { + if(wType == USB_EP_ISOCHRONOUS) { + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); + } else { + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK); + } + } + + xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->max_packet_size = packet_size; + xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->ep_idx = ep_idx; return true; } @@ -835,29 +974,89 @@ void dcd_edpt_close_all (uint8_t rhport) /** * Close an endpoint. - * + * * This function may be called with interrupts enabled or disabled. - * + * * This also clears transfers in progress, should there be any. */ void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) { (void)rhport; - uint32_t const epnum = tu_edpt_number(ep_addr); - uint32_t const dir = tu_edpt_dir(ep_addr); - + + xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + uint8_t const ep_idx = xfer->ep_idx; + uint8_t const dir = tu_edpt_dir(ep_addr); + if(dir == TUSB_DIR_IN) { - pcd_set_ep_tx_status(USB,epnum,USB_EP_TX_DIS); + pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); } else { - pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_DIS); + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); } + dcd_ep_free(ep_addr); + dcd_pma_free(ep_addr); } +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) +{ + (void)rhport; + + TU_ASSERT(largest_packet_size <= 1024); + + uint8_t const ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS); + const uint16_t buffer_size = pcd_aligned_buffer_size(largest_packet_size); + + /* Create a packet memory buffer area. For isochronous endpoints, + * use the same buffer as the double buffer, essentially disabling double buffering */ + uint16_t pma_addr = dcd_pma_alloc(ep_addr, buffer_size); + + xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx; + + pcd_set_eptype(USB, ep_idx, USB_EP_ISOCHRONOUS); + + *pcd_ep_tx_address_ptr(USB, ep_idx) = pma_addr; + *pcd_ep_rx_address_ptr(USB, ep_idx) = pma_addr; + + return true; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) +{ + (void)rhport; + uint8_t const ep_idx = xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->ep_idx; + uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); + const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc); + const uint16_t buffer_size = pcd_aligned_buffer_size(packet_size); + + /* Disable endpoint */ + if(dir == TUSB_DIR_IN) + { + pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); + } + else + { + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); + } + + pcd_set_ep_address(USB, ep_idx, tu_edpt_number(p_endpoint_desc->bEndpointAddress)); + // Be normal, for now, instead of only accepting zero-byte packets (on control endpoint) + // or being double-buffered (bulk endpoints) + pcd_clear_ep_kind(USB,0); + + pcd_set_ep_tx_bufsize(USB, ep_idx, buffer_size); + pcd_set_ep_rx_bufsize(USB, ep_idx, buffer_size); + pcd_clear_tx_dtog(USB, ep_idx); + pcd_clear_rx_dtog(USB, ep_idx); + + xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->max_packet_size = packet_size; + + return true; +} + // Currently, single-buffered, and only 64 bytes at a time (max) static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix) @@ -868,21 +1067,27 @@ static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix) { len = xfer->max_packet_size; } - uint16_t oldAddr = *pcd_ep_tx_address_ptr(USB,ep_ix); -#if 0 // TODO support dcd_edpt_xfer_fifo API + uint16_t ep_reg = pcd_get_endpoint(USB, ep_ix); + uint16_t addr_ptr = *pcd_ep_tx_address_ptr(USB,ep_ix); + if (xfer->ff) { - dcd_write_packet_memory_ff(xfer->ff, oldAddr, len); + dcd_write_packet_memory_ff(xfer->ff, addr_ptr, len); } else -#endif { - dcd_write_packet_memory(oldAddr, &(xfer->buffer[xfer->queued_len]), len); + dcd_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len); } xfer->queued_len = (uint16_t)(xfer->queued_len + len); - pcd_set_ep_tx_cnt(USB,ep_ix,len); + /* Write into correct register when ISOCHRONOUS (double buffered) */ + if ( (ep_reg & USB_EP_DTOG_TX) && ( (ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) ) { + pcd_set_ep_rx_cnt(USB, ep_ix, len); + } else { + pcd_set_ep_tx_cnt(USB, ep_ix, len); + } + pcd_set_ep_tx_status(USB, ep_ix, USB_EP_TX_VALID); } @@ -890,13 +1095,12 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t { (void) rhport; - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - - xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir); + xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + uint8_t const ep_idx = xfer->ep_idx; + uint8_t const dir = tu_edpt_dir(ep_addr); xfer->buffer = buffer; - // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API + xfer->ff = NULL; xfer->total_len = total_bytes; xfer->queued_len = 0; @@ -904,37 +1108,36 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t { // A setup token can occur immediately after an OUT STATUS packet so make sure we have a valid // buffer for the control endpoint. - if (epnum == 0 && buffer == NULL) + if (ep_idx == 0 && buffer == NULL) { xfer->buffer = (uint8_t*)_setup_packet; } + if(total_bytes > xfer->max_packet_size) { - pcd_set_ep_rx_cnt(USB,epnum,xfer->max_packet_size); + pcd_set_ep_rx_bufsize(USB,ep_idx,xfer->max_packet_size); } else { - pcd_set_ep_rx_cnt(USB,epnum,total_bytes); + pcd_set_ep_rx_bufsize(USB,ep_idx,total_bytes); } - pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_VALID); + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_VALID); } else // IN { - dcd_transmit_packet(xfer,epnum); + dcd_transmit_packet(xfer,ep_idx); } return true; } -#if 0 // TODO support dcd_edpt_xfer_fifo API bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void) rhport; - uint8_t const epnum = tu_edpt_number(ep_addr); + xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + uint8_t const epnum = xfer->ep_idx; uint8_t const dir = tu_edpt_dir(ep_addr); - xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir); - xfer->buffer = NULL; - // xfer->ff = ff; // TODO support dcd_edpt_xfer_fifo API + xfer->ff = ff; xfer->total_len = total_bytes; xfer->queued_len = 0; @@ -942,9 +1145,9 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 { if(total_bytes > xfer->max_packet_size) { - pcd_set_ep_rx_cnt(USB,epnum,xfer->max_packet_size); + pcd_set_ep_rx_bufsize(USB,epnum,xfer->max_packet_size); } else { - pcd_set_ep_rx_cnt(USB,epnum,total_bytes); + pcd_set_ep_rx_bufsize(USB,epnum,total_bytes); } pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_VALID); } @@ -954,19 +1157,22 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 } return true; } -#endif void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) { (void)rhport; - if (ep_addr & 0x80) + xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + uint8_t const ep_idx = xfer->ep_idx; + uint8_t const dir = tu_edpt_dir(ep_addr); + + if (dir == TUSB_DIR_IN) { // IN - pcd_set_ep_tx_status(USB, ep_addr & 0x7F, USB_EP_TX_STALL); + pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_STALL); } else { // OUT - pcd_set_ep_rx_status(USB, ep_addr, USB_EP_RX_STALL); + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_STALL); } } @@ -974,21 +1180,26 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) { (void)rhport; - if (ep_addr & 0x80) - { // IN - ep_addr &= 0x7F; + xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + uint8_t const ep_idx = xfer->ep_idx; + uint8_t const dir = tu_edpt_dir(ep_addr); - pcd_set_ep_tx_status(USB,ep_addr, USB_EP_TX_NAK); + if (dir == TUSB_DIR_IN) + { // IN + if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) { + pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK); + } /* Reset to DATA0 if clearing stall condition. */ - pcd_clear_tx_dtog(USB,ep_addr); + pcd_clear_tx_dtog(USB, ep_idx); } else { // OUT + if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) { + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK); + } /* Reset to DATA0 if clearing stall condition. */ - pcd_clear_rx_dtog(USB,ep_addr); - - pcd_set_ep_rx_status(USB,ep_addr, USB_EP_RX_NAK); + pcd_clear_rx_dtog(USB, ep_idx); } } @@ -1005,8 +1216,7 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) */ static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes) { - uint32_t n = ((uint32_t)wNBytes + 1U) >> 1U; - uint32_t i; + uint32_t n = (uint32_t)wNBytes >> 1U; uint16_t temp1, temp2; const uint8_t * srcVal; @@ -1017,64 +1227,74 @@ static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, si srcVal = src; pdwVal = &pma[PMA_STRIDE*(dst>>1)]; - for (i = n; i != 0; i--) + while (n--) { - temp1 = (uint16_t) *srcVal; + temp1 = (uint16_t)*srcVal; srcVal++; - temp2 = temp1 | ((uint16_t)((uint16_t) ((*srcVal) << 8U))) ; + temp2 = temp1 | ((uint16_t)(((uint16_t)(*srcVal)) << 8U)) ; *pdwVal = temp2; pdwVal += PMA_STRIDE; srcVal++; } + + if (wNBytes & 0x01) + { + temp1 = *srcVal; + *pdwVal = temp1; + } + return true; } -#if 0 // TODO support dcd_edpt_xfer_fifo API /** * @brief Copy from FIFO to packet memory area (PMA). * Uses byte-access of system memory and 16-bit access of packet memory * @param wNBytes no. of bytes to be copied. * @retval None */ - -// THIS FUNCTION IS UNTESTED - static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes) { // Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies - // Check for first linear part - void * src; - uint16_t len = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes); // We want to read from the FIFO - THIS FUNCTION CHANGED!!! - TU_VERIFY(len && dcd_write_packet_memory(dst, src, len)); // and write it into the PMA - tu_fifo_advance_read_pointer(ff, len); + tu_fifo_buffer_info_t info; + tu_fifo_get_read_info(ff, &info); - // Check for wrapped part - if (len < wNBytes) + uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin); + uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap); + + // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part, + // last lin byte will be combined with wrapped part + // To ensure PMA is always access 16bit aligned (dst aligned to 16 bit) + if((cnt_lin & 0x01) && cnt_wrap) { - // Get remaining wrapped length - uint16_t len2 = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes - len); - TU_VERIFY(len2); + // Copy first linear part + dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin &~0x01); + dst += cnt_lin &~0x01; - // Update destination pointer - dst += len; + // Copy last linear byte & first wrapped byte + uint16_t tmp = ((uint8_t*)info.ptr_lin)[cnt_lin - 1] | ((uint16_t)(((uint8_t*)info.ptr_wrap)[0]) << 8U); + dcd_write_packet_memory(dst, &tmp, 2); + dst += 2; - // Since PMA is accessed 16-bit wise we need to handle the case when a 16 bit value was split - if (len % 2) // If len is uneven there is a byte left to copy + // Copy rest of wrapped byte + dcd_write_packet_memory(dst, ((uint8_t*)info.ptr_wrap) + 1, cnt_wrap - 1); + } + else + { + // Copy linear part + dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin); + dst += info.len_lin; + + if(info.len_wrap) { - // Since PMA can accessed only 16 bit-wise we copy the last byte again - tu_fifo_backward_read_pointer(ff, 1); // Move one byte back and copy two bytes for the PMA - tu_fifo_read_n(ff, (void *) &pma[PMA_STRIDE*(dst>>1)], 2); // Since EP FIFOs must be of item size 1 this is safe to do - dst++; - len2--; + // Copy wrapped byte + dcd_write_packet_memory(dst, info.ptr_wrap, cnt_wrap); } - - TU_VERIFY(dcd_write_packet_memory(dst, src, len2)); - tu_fifo_advance_write_pointer(ff, len2); } + tu_fifo_advance_read_pointer(ff, cnt_lin + cnt_wrap); + return true; } -#endif /** * @brief Copy a buffer from packet memory area (PMA) to user memory area. @@ -1085,7 +1305,6 @@ static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wN static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes) { uint32_t n = (uint32_t)wNBytes >> 1U; - uint32_t i; // The GCC optimizer will combine access to 32-bit sizes if we let it. Force // it volatile so that it won't do that. __IO const uint16_t *pdwVal; @@ -1094,7 +1313,7 @@ static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wN pdwVal = &pma[PMA_STRIDE*(src>>1)]; uint8_t *dstVal = (uint8_t*)dst; - for (i = n; i != 0U; i--) + while (n--) { temp = *pdwVal; pdwVal += PMA_STRIDE; @@ -1102,7 +1321,7 @@ static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wN *dstVal++ = ((temp >> 8) & 0xFF); } - if (wNBytes % 2) + if (wNBytes & 0x01) { temp = *pdwVal; pdwVal += PMA_STRIDE; @@ -1111,52 +1330,58 @@ static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wN return true; } -#if 0 // TODO support dcd_edpt_xfer_fifo API /** * @brief Copy a buffer from user packet memory area (PMA) to FIFO. * Uses byte-access of system memory and 16-bit access of packet memory * @param wNBytes no. of bytes to be copied. * @retval None */ - -// THIS FUNCTION IS UNTESTED - static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes) { // Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies // Check for first linear part - void * dst; - uint16_t len = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes); // THIS FUNCTION CHANGED!!!! - TU_VERIFY(len && dcd_read_packet_memory(dst, src, len)); - tu_fifo_advance_write_pointer(ff, len); + tu_fifo_buffer_info_t info; + tu_fifo_get_write_info(ff, &info); // We want to read from the FIFO + + uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin); + uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap); - // Check for wrapped part - if (len < wNBytes) + // We want to read from PMA and write it into the FIFO, if LIN part is ODD and has WRAPPED part, + // last lin byte will be combined with wrapped part + // To ensure PMA is always access 16bit aligned (src aligned to 16 bit) + if((cnt_lin & 0x01) && cnt_wrap) { - // Get remaining wrapped length - uint16_t len2 = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes - len); - TU_VERIFY(len2); + // Copy first linear part + dcd_read_packet_memory(info.ptr_lin, src, cnt_lin &~0x01); + src += cnt_lin &~0x01; + + // Copy last linear byte & first wrapped byte + uint16_t tmp; + dcd_read_packet_memory(&tmp, src, 2); - // Update source pointer - src += len; + ((uint8_t*)info.ptr_lin)[cnt_lin - 1] = (uint8_t)tmp; + ((uint8_t*)info.ptr_wrap)[0] = (uint8_t)(tmp >> 8U); + src += 2; + + // Copy rest of wrapped byte + dcd_read_packet_memory(((uint8_t*)info.ptr_wrap) + 1, src, cnt_wrap - 1); + } + else + { + // Copy linear part + dcd_read_packet_memory(info.ptr_lin, src, cnt_lin); + src += cnt_lin; - // Since PMA is accessed 16-bit wise we need to handle the case when a 16 bit value was split - if (len % 2) // If len is uneven there is a byte left to copy + if(info.len_wrap) { - uint32_t temp = pma[PMA_STRIDE*(src>>1)]; - *((uint8_t *)dst++) = ((temp >> 8) & 0xFF); - src++; - len2--; + // Copy wrapped byte + dcd_read_packet_memory(info.ptr_wrap, src, cnt_wrap); } - - TU_VERIFY(dcd_read_packet_memory(dst, src, len2)); - tu_fifo_advance_write_pointer(ff, len2); } + tu_fifo_advance_write_pointer(ff, cnt_lin + cnt_wrap); + return true; } #endif - -#endif - diff --git a/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h b/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h index bffae450..e3fc8aeb 100644 --- a/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h +++ b/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h @@ -1,12 +1,6 @@ /** - ****************************************************************************** - * @file dcd_stm32f0_pvt_st.h - * @brief DCD utilities from ST code - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2016 STMicroelectronics

- *

© parts COPYRIGHT(c) N Conrad

+ * Copyright(c) 2016 STMicroelectronics + * Copyright(c) N Conrad * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -30,7 +24,7 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - **********/ + */ // This file contains source copied from ST's HAL, and thus should have their copyright statement. @@ -41,10 +35,7 @@ #ifndef PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ #define PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ -#if defined(STM32F042x6) || \ - defined(STM32F070x6) || defined(STM32F070xB) || \ - defined(STM32F072xB) || \ - defined(STM32F078xx) +#if CFG_TUSB_MCU == OPT_MCU_STM32F0 #include "stm32f0xx.h" #define PMA_LENGTH (1024u) // F0x2 models are crystal-less @@ -52,7 +43,7 @@ // 070RB: 2 x 16 bits/word memory LPM Support, BCD Support // PMA dedicated to USB (no sharing with CAN) -#elif defined(STM32F1_FSDEV) +#elif CFG_TUSB_MCU == OPT_MCU_STM32F1 #include "stm32f1xx.h" #define PMA_LENGTH (512u) // NO internal Pull-ups @@ -98,6 +89,18 @@ #undef USB_PMAADDR #define USB_PMAADDR USB1_PMAADDR +#elif CFG_TUSB_MCU == OPT_MCU_STM32L4 + #include "stm32l4xx.h" + #define PMA_LENGTH (1024u) + +#elif CFG_TUSB_MCU == OPT_MCU_STM32L5 + #include "stm32l5xx.h" + #define PMA_LENGTH (1024u) + + #ifndef USB_PMAADDR + #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS)) + #endif + #else #error You are using an untested or unimplemented STM32 variant. Please update the driver. // This includes L1x0, L1x1, L1x2, L4x2 and L4x3, G1x1, G1x3, and G1x4 @@ -116,76 +119,89 @@ static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR; // prototypes -static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum); -static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum); -static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wRegValue); +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx); +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx); +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue); +/* Aligned buffer size according to hardware */ +TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t size) +{ + /* The STM32 full speed USB peripheral supports only a limited set of + * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */ + uint16_t blocksize = (size > 62) ? 32 : 2; + + // Round up while dividing requested size by blocksize + uint16_t numblocks = (size + blocksize - 1) / blocksize ; + + return numblocks * blocksize; +} /* SetENDPOINT */ -static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wRegValue) +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue) { - __O uint16_t *reg = (__O uint16_t *)((&USBx->EP0R) + bEpNum*2u); + __O uint16_t *reg = (__O uint16_t *)((&USBx->EP0R) + bEpIdx*2u); *reg = (uint16_t)wRegValue; } /* GetENDPOINT */ -static inline uint16_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpNum) { - __I uint16_t *reg = (__I uint16_t *)((&USBx->EP0R) + bEpNum*2u); +TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx) { + __I uint16_t *reg = (__I uint16_t *)((&USBx->EP0R) + bEpIdx*2u); return *reg; } -static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wType) +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wType) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= (uint32_t)USB_EP_T_MASK; regVal |= wType; regVal |= USB_EP_CTR_RX | USB_EP_CTR_TX; // These clear on write0, so must set high - pcd_set_endpoint(USBx, bEpNum, regVal); + pcd_set_endpoint(USBx, bEpIdx, regVal); } -static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EP_T_FIELD; return regVal; } /** * @brief Clears bit CTR_RX / CTR_TX in the endpoint register. * @param USBx USB peripheral instance register address. - * @param bEpNum Endpoint Number. + * @param bEpIdx Endpoint Number. * @retval None */ -static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal &= ~USB_EP_CTR_RX; regVal |= USB_EP_CTR_TX; // preserve CTR_TX (clears on writing 0) - pcd_set_endpoint(USBx, bEpNum, regVal); + pcd_set_endpoint(USBx, bEpIdx, regVal); } -static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpNum) + +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal &= ~USB_EP_CTR_TX; regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0) - pcd_set_endpoint(USBx, bEpNum,regVal); + pcd_set_endpoint(USBx, bEpIdx,regVal); } /** * @brief gets counter of the tx buffer. * @param USBx USB peripheral instance register address. - * @param bEpNum Endpoint Number. + * @param bEpIdx Endpoint Number. * @retval Counter value */ -static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) { - __I uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpNum); + __I uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpIdx); return *regPtr & 0x3ffU; } -static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) { - __I uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpNum); + __I uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpIdx); return *regPtr & 0x3ffU; } @@ -196,49 +212,36 @@ static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpNum) * @param wNBlocks no. of Blocks. * @retval None */ +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_cnt_reg(__O uint16_t * pdwReg, size_t wCount) +{ + /* We assume that the buffer size is already aligned to hardware requirements. */ + uint16_t blocksize = (wCount > 62) ? 1 : 0; + uint16_t numblocks = wCount / (blocksize ? 32 : 2); -static inline void pcd_set_ep_cnt_rx_reg(__O uint16_t * pdwReg, size_t wCount) { - uint32_t wNBlocks; - if(wCount > 62u) - { - wNBlocks = wCount >> 5u; - if((wCount & 0x1fU) == 0u) - { - wNBlocks--; - } - wNBlocks = wNBlocks << 10u; - wNBlocks |= 0x8000u; // Mark block size as 32byte - *pdwReg = (uint16_t)wNBlocks; - } - else - { - wNBlocks = wCount >> 1u; - if((wCount & 0x1U) != 0u) - { - wNBlocks++; - } - *pdwReg = (uint16_t)((wNBlocks) << 10u); - } -} + /* There should be no remainder in the above calculation */ + TU_ASSERT((wCount - (numblocks * (blocksize ? 32 : 2))) == 0, /**/); + /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ + *pdwReg = (blocksize << 15) | ((numblocks - blocksize) << 10); +} /** * @brief Sets address in an endpoint register. * @param USBx USB peripheral instance register address. - * @param bEpNum Endpoint Number. + * @param bEpIdx Endpoint Number. * @param bAddr Address. * @retval None */ -static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t bAddr) +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t bAddr) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal |= bAddr; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpNum,regVal); + pcd_set_endpoint(USBx, bEpIdx,regVal); } -static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) { size_t total_word_offset = (((USBx)->BTABLE)>>1) + x; total_word_offset *= PMA_STRIDE; @@ -246,46 +249,61 @@ static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) } // Pointers to the PMA table entries (using the ARM address space) -static inline __IO uint16_t* pcd_ep_tx_address_ptr(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_address_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { - return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 0u); + return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 0u); } -static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { - return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 1u); + return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 1u); } -static inline __IO uint16_t* pcd_ep_rx_address_ptr(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_address_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { - return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 2u); + return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 2u); } -static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { - return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 3u); + return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 3u); } -static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wCount) +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { - *pcd_ep_tx_cnt_ptr(USBx, bEpNum) = (uint16_t)wCount; + __IO uint16_t * reg = pcd_ep_tx_cnt_ptr(USBx, bEpIdx); + *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU); } -static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wCount) +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { - __IO uint16_t *pdwReg = pcd_ep_rx_cnt_ptr((USBx),(bEpNum)); - pcd_set_ep_cnt_rx_reg(pdwReg, wCount); + __IO uint16_t * reg = pcd_ep_rx_cnt_ptr(USBx, bEpIdx); + *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU); +} + +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) +{ + __IO uint16_t *pdwReg = pcd_ep_tx_cnt_ptr((USBx),(bEpIdx)); + wCount = pcd_aligned_buffer_size(wCount); + pcd_set_ep_cnt_reg(pdwReg, wCount); +} + +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) +{ + __IO uint16_t *pdwReg = pcd_ep_rx_cnt_ptr((USBx),(bEpIdx)); + wCount = pcd_aligned_buffer_size(wCount); + pcd_set_ep_cnt_reg(pdwReg, wCount); } /** * @brief sets the status for tx transfer (bits STAT_TX[1:0]). * @param USBx USB peripheral instance register address. - * @param bEpNum Endpoint Number. + * @param bEpIdx Endpoint Number. * @param wState new state * @retval None */ -static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wState) +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPTX_DTOGMASK; /* toggle first bit ? */ @@ -298,21 +316,22 @@ static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpNum, ui { regVal ^= USB_EPTX_DTOG2; } + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpNum, regVal); + pcd_set_endpoint(USBx, bEpIdx, regVal); } /* pcd_set_ep_tx_status */ /** * @brief sets the status for rx transfer (bits STAT_TX[1:0]) * @param USBx USB peripheral instance register address. - * @param bEpNum Endpoint Number. + * @param bEpIdx Endpoint Number. * @param wState new state * @retval None */ -static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wState) +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPRX_DTOGMASK; /* toggle first bit ? */ @@ -325,13 +344,14 @@ static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpNum, ui { regVal ^= USB_EPRX_DTOG2; } + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpNum, regVal); + pcd_set_endpoint(USBx, bEpIdx, regVal); } /* pcd_set_ep_rx_status */ -static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); return (regVal & USB_EPRX_STAT) >> (12u); } /* pcd_get_ep_rx_status */ @@ -339,71 +359,71 @@ static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpNum /** * @brief Toggles DTOG_RX / DTOG_TX bit in the endpoint register. * @param USBx USB peripheral instance register address. - * @param bEpNum Endpoint Number. + * @param bEpIdx Endpoint Number. * @retval None */ -static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_RX; - pcd_set_endpoint(USBx, bEpNum, regVal); + pcd_set_endpoint(USBx, bEpIdx, regVal); } -static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_TX; - pcd_set_endpoint(USBx, bEpNum, regVal); + pcd_set_endpoint(USBx, bEpIdx, regVal); } /** * @brief Clears DTOG_RX / DTOG_TX bit in the endpoint register. * @param USBx USB peripheral instance register address. - * @param bEpNum Endpoint Number. + * @param bEpIdx Endpoint Number. * @retval None */ -static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); if((regVal & USB_EP_DTOG_RX) != 0) { - pcd_rx_dtog(USBx,bEpNum); + pcd_rx_dtog(USBx,bEpIdx); } } -static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); if((regVal & USB_EP_DTOG_TX) != 0) { - pcd_tx_dtog(USBx,bEpNum); + pcd_tx_dtog(USBx,bEpIdx); } } /** * @brief set & clear EP_KIND bit. * @param USBx USB peripheral instance register address. - * @param bEpNum Endpoint Number. + * @param bEpIdx Endpoint Number. * @retval None */ -static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal |= USB_EP_KIND; regVal &= USB_EPREG_MASK; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpNum, regVal); + pcd_set_endpoint(USBx, bEpIdx, regVal); } -static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPKIND_MASK; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpNum, regVal); + pcd_set_endpoint(USBx, bEpIdx, regVal); } // This checks if the device has "LPM" @@ -417,6 +437,7 @@ static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpNum) USB_ISTR_RESET | USB_ISTR_SOF | USB_ISTR_ESOF | USB_ISTR_L1REQ_FORCED ) // Number of endpoints in hardware +// TODO should use TUP_DCD_ENDPOINT_MAX #define STFSDEV_EP_COUNT (8u) #endif /* PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/tusb.c b/test-devices/composite-stm32/lib/tinyusb/tusb.c index c3787ff8..85fe5a3c 100644 --- a/test-devices/composite-stm32/lib/tinyusb/tusb.c +++ b/test-devices/composite-stm32/lib/tinyusb/tusb.c @@ -31,11 +31,18 @@ #include "tusb.h" #include "common/tusb_private.h" -// TODO clean up #if CFG_TUD_ENABLED #include "device/usbd_pvt.h" #endif +#if CFG_TUH_ENABLED +#include "host/usbh_classdriver.h" +#endif + +//--------------------------------------------------------------------+ +// Public API +//--------------------------------------------------------------------+ + bool tusb_init(void) { #if CFG_TUD_ENABLED && defined(TUD_OPT_RHPORT) @@ -67,18 +74,51 @@ bool tusb_inited(void) } //--------------------------------------------------------------------+ -// Internal Helper for both Host and Device stack +// Descriptor helper +//--------------------------------------------------------------------+ + +uint8_t const * tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byte1) +{ + while(desc+1 < end) + { + if ( desc[1] == byte1 ) return desc; + desc += desc[DESC_OFFSET_LEN]; + } + return NULL; +} + +uint8_t const * tu_desc_find2(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2) +{ + while(desc+2 < end) + { + if ( desc[1] == byte1 && desc[2] == byte2) return desc; + desc += desc[DESC_OFFSET_LEN]; + } + return NULL; +} + +uint8_t const * tu_desc_find3(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2, uint8_t byte3) +{ + while(desc+3 < end) + { + if (desc[1] == byte1 && desc[2] == byte2 && desc[3] == byte3) return desc; + desc += desc[DESC_OFFSET_LEN]; + } + return NULL; +} + + +//--------------------------------------------------------------------+ +// Endpoint Helper for both Host and Device stack //--------------------------------------------------------------------+ bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex) { (void) mutex; -#if TUSB_OPT_MUTEX // pre-check to help reducing mutex lock TU_VERIFY((ep_state->busy == 0) && (ep_state->claimed == 0)); - osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); -#endif + (void) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); // can only claim the endpoint if it is not busy and not claimed yet. bool const available = (ep_state->busy == 0) && (ep_state->claimed == 0); @@ -87,9 +127,7 @@ bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex) ep_state->claimed = 1; } -#if TUSB_OPT_MUTEX - osal_mutex_unlock(mutex); -#endif + (void) osal_mutex_unlock(mutex); return available; } @@ -98,9 +136,7 @@ bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex) { (void) mutex; -#if TUSB_OPT_MUTEX - osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); -#endif + (void) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); // can only release the endpoint if it is claimed and not busy bool const ret = (ep_state->claimed == 1) && (ep_state->busy == 0); @@ -109,9 +145,7 @@ bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex) ep_state->claimed = 0; } -#if TUSB_OPT_MUTEX - osal_mutex_unlock(mutex); -#endif + (void) osal_mutex_unlock(mutex); return ret; } @@ -204,9 +238,184 @@ uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, return len; } -/*------------------------------------------------------------------*/ -/* Debug - *------------------------------------------------------------------*/ +//--------------------------------------------------------------------+ +// Endpoint Stream Helper for both Host and Device stack +//--------------------------------------------------------------------+ + +bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool overwritable, + void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize) +{ + osal_mutex_t new_mutex = osal_mutex_create(&s->ff_mutex); + (void) new_mutex; + (void) is_tx; + + s->is_host = is_host; + tu_fifo_config(&s->ff, ff_buf, ff_bufsize, 1, overwritable); + tu_fifo_config_mutex(&s->ff, is_tx ? new_mutex : NULL, is_tx ? NULL : new_mutex); + + s->ep_buf = ep_buf; + s->ep_bufsize = ep_bufsize; + + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline +bool stream_claim(tu_edpt_stream_t* s) +{ + if (s->is_host) + { + #if CFG_TUH_ENABLED + return usbh_edpt_claim(s->daddr, s->ep_addr); + #endif + }else + { + #if CFG_TUD_ENABLED + return usbd_edpt_claim(s->rhport, s->ep_addr); + #endif + } + + return false; +} + +TU_ATTR_ALWAYS_INLINE static inline +bool stream_xfer(tu_edpt_stream_t* s, uint16_t count) +{ + if (s->is_host) + { + #if CFG_TUH_ENABLED + return usbh_edpt_xfer(s->daddr, s->ep_addr, count ? s->ep_buf : NULL, count); + #endif + }else + { + #if CFG_TUD_ENABLED + return usbd_edpt_xfer(s->rhport, s->ep_addr, count ? s->ep_buf : NULL, count); + #endif + } + + return false; +} + +TU_ATTR_ALWAYS_INLINE static inline +bool stream_release(tu_edpt_stream_t* s) +{ + if (s->is_host) + { + #if CFG_TUH_ENABLED + return usbh_edpt_release(s->daddr, s->ep_addr); + #endif + }else + { + #if CFG_TUD_ENABLED + return usbd_edpt_release(s->rhport, s->ep_addr); + #endif + } + + return false; +} + +//--------------------------------------------------------------------+ +// Stream Write +//--------------------------------------------------------------------+ + +bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes) +{ + // ZLP condition: no pending data, last transferred bytes is multiple of packet size + TU_VERIFY( !tu_fifo_count(&s->ff) && last_xferred_bytes && (0 == (last_xferred_bytes & (s->ep_packetsize-1))) ); + + TU_VERIFY( stream_claim(s) ); + TU_ASSERT( stream_xfer(s, 0) ); + + return true; +} + +uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) +{ + // skip if no data + TU_VERIFY( tu_fifo_count(&s->ff), 0 ); + + // Claim the endpoint + TU_VERIFY( stream_claim(s), 0 ); + + // Pull data from FIFO -> EP buf + uint16_t const count = tu_fifo_read_n(&s->ff, s->ep_buf, s->ep_bufsize); + + if ( count ) + { + TU_ASSERT( stream_xfer(s, count), 0 ); + return count; + }else + { + // Release endpoint since we don't make any transfer + // Note: data is dropped if terminal is not connected + stream_release(s); + return 0; + } +} + +uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize) +{ + TU_VERIFY(bufsize); // TODO support ZLP + + uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); + + // flush if fifo has more than packet size or + // in rare case: fifo depth is configured too small (which never reach packet size) + if ( (tu_fifo_count(&s->ff) >= s->ep_packetsize) || (tu_fifo_depth(&s->ff) < s->ep_packetsize) ) + { + tu_edpt_stream_write_xfer(s); + } + + return ret; +} + +//--------------------------------------------------------------------+ +// Stream Read +//--------------------------------------------------------------------+ + +uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) +{ + uint16_t available = tu_fifo_remaining(&s->ff); + + // Prepare for incoming data but only allow what we can store in the ring buffer. + // TODO Actually we can still carry out the transfer, keeping count of received bytes + // and slowly move it to the FIFO when read(). + // This pre-check reduces endpoint claiming + TU_VERIFY(available >= s->ep_packetsize); + + // claim endpoint + TU_VERIFY(stream_claim(s), 0); + + // get available again since fifo can be changed before endpoint is claimed + available = tu_fifo_remaining(&s->ff); + + if ( available >= s->ep_packetsize ) + { + // multiple of packet size limit by ep bufsize + uint16_t count = (uint16_t) (available & ~(s->ep_packetsize -1)); + count = tu_min16(count, s->ep_bufsize); + + TU_ASSERT( stream_xfer(s, count), 0 ); + + return count; + }else + { + // Release endpoint since we don't make any transfer + stream_release(s); + return 0; + } +} + +uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize) +{ + uint32_t num_read = tu_fifo_read_n(&s->ff, buffer, (uint16_t) bufsize); + tu_edpt_stream_read_xfer(s); + return num_read; +} + +//--------------------------------------------------------------------+ +// Debug +//--------------------------------------------------------------------+ + #if CFG_TUSB_DEBUG #include @@ -286,7 +495,7 @@ void tu_print_mem(void const *buf, uint32_t count, uint8_t indent) tu_printf("%04X: ", 16*i/item_per_line); } - memcpy(&value, buf8, size); + tu_memcpy_s(&value, sizeof(value), buf8, size); buf8 += size; tu_printf(" "); diff --git a/test-devices/composite-stm32/lib/tinyusb/tusb_option.h b/test-devices/composite-stm32/lib/tinyusb/tusb_option.h index e7fc6885..4f3f3a98 100644 --- a/test-devices/composite-stm32/lib/tinyusb/tusb_option.h +++ b/test-devices/composite-stm32/lib/tinyusb/tusb_option.h @@ -27,13 +27,10 @@ #ifndef _TUSB_OPTION_H_ #define _TUSB_OPTION_H_ -// To avoid GCC compiler warnings when -pedantic option is used (strict ISO C) -typedef int make_iso_compilers_happy; - #include "common/tusb_compiler.h" #define TUSB_VERSION_MAJOR 0 -#define TUSB_VERSION_MINOR 14 +#define TUSB_VERSION_MINOR 15 #define TUSB_VERSION_REVISION 0 #define TUSB_VERSION_STRING TU_STRING(TUSB_VERSION_MAJOR) "." TU_STRING(TUSB_VERSION_MINOR) "." TU_STRING(TUSB_VERSION_REVISION) @@ -84,6 +81,8 @@ typedef int make_iso_compilers_happy; #define OPT_MCU_STM32G0 310 ///< ST G0 #define OPT_MCU_STM32G4 311 ///< ST G4 #define OPT_MCU_STM32WB 312 ///< ST WB +#define OPT_MCU_STM32U5 313 ///< ST U5 +#define OPT_MCU_STM32L5 314 ///< ST L5 // Sony #define OPT_MCU_CXD56 400 ///< SONY CXD56 @@ -119,8 +118,11 @@ typedef int make_iso_compilers_happy; #define OPT_MCU_RP2040 1100 ///< Raspberry Pi RP2040 // NXP Kinetis -#define OPT_MCU_MKL25ZXX 1200 ///< NXP MKL25Zxx -#define OPT_MCU_K32L2BXX 1201 ///< NXP K32L2Bxx +#define OPT_MCU_KINETIS_KL 1200 ///< NXP KL series +#define OPT_MCU_KINETIS_K32 1201 ///< NXP K32 series + +#define OPT_MCU_MKL25ZXX 1200 ///< Alias to KL (obsolete) +#define OPT_MCU_K32L2BXX 1201 ///< Alias to K32 (obsolete) // Silabs #define OPT_MCU_EFM32GG 1300 ///< Silabs EFM32GG @@ -129,6 +131,8 @@ typedef int make_iso_compilers_happy; #define OPT_MCU_RX63X 1400 ///< Renesas RX63N/631 #define OPT_MCU_RX65X 1401 ///< Renesas RX65N/RX651 #define OPT_MCU_RX72N 1402 ///< Renesas RX72N +#define OPT_MCU_RAXXX 1403 ///< Renesas RAxxx families + // Mind Motion #define OPT_MCU_MM32F327X 1500 ///< Mind Motion MM32F327 @@ -146,6 +150,11 @@ typedef int make_iso_compilers_happy; // PIC #define OPT_MCU_PIC32MZ 1900 ///< MicroChip PIC32MZ family +#define OPT_MCU_PIC32MM 1901 ///< MicroChip PIC32MM family +#define OPT_MCU_PIC32MX 1902 ///< MicroChip PIC32MX family +#define OPT_MCU_PIC32MK 1903 ///< MicroChip PIC32MK family +#define OPT_MCU_PIC24 1910 ///< MicroChip PIC24 family +#define OPT_MCU_DSPIC33 1911 ///< MicroChip DSPIC33 family // BridgeTek #define OPT_MCU_FT90X 2000 ///< BridgeTek FT90x @@ -154,6 +163,9 @@ typedef int make_iso_compilers_happy; // Allwinner #define OPT_MCU_F1C100S 2100 ///< Allwinner F1C100s family +// WCH +#define OPT_MCU_CH32V307 2200 ///< WCH CH32V307 + // Helper to check if configured MCU is one of listed // Apply _TU_CHECK_MCU with || as separator to list of input #define _TU_CHECK_MCU(_m) (CFG_TUSB_MCU == _m) @@ -250,6 +262,10 @@ typedef int make_iso_compilers_happy; // For backward compatible #define TUSB_OPT_HOST_ENABLED CFG_TUH_ENABLED +// highspeed support indicator +#define TUH_OPT_HIGH_SPEED (CFG_TUH_MAX_SPEED ? (CFG_TUH_MAX_SPEED & OPT_MODE_HIGH_SPEED) : TUP_RHPORT_HIGHSPEED) + + //--------------------------------------------------------------------+ // TODO move later //--------------------------------------------------------------------+ @@ -274,12 +290,15 @@ typedef int make_iso_compilers_happy; #define CFG_TUSB_DEBUG 0 #endif -// place data in accessible RAM for usb controller +// TODO MEM_SECTION can be different for host and device controller +// should use CFG_TUD_MEM_SECTION, CFG_TUH_MEM_SECTION #ifndef CFG_TUSB_MEM_SECTION #define CFG_TUSB_MEM_SECTION #endif // alignment requirement of buffer used for endpoint transferring +// TODO MEM_ALIGN can be different for host and device controller +// should use CFG_TUD_MEM_ALIGN, CFG_TUH_MEM_ALIGN #ifndef CFG_TUSB_MEM_ALIGN #define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4) #endif @@ -293,13 +312,30 @@ typedef int make_iso_compilers_happy; #define CFG_TUSB_OS_INC_PATH #endif -// mutex is only needed for RTOS TODO also required with multiple core MCUs -#define TUSB_OPT_MUTEX (CFG_TUSB_OS != OPT_OS_NONE) - //-------------------------------------------------------------------- // Device Options (Default) //-------------------------------------------------------------------- +// Attribute to place data in accessible RAM for device controller +// default to CFG_TUSB_MEM_SECTION for backward-compatible +#ifndef CFG_TUD_MEM_SECTION + #ifdef CFG_TUSB_MEM_SECTION + #define CFG_TUD_MEM_SECTION CFG_TUSB_MEM_SECTION + #else + #define CFG_TUD_MEM_SECTION + #endif +#endif + +// Attribute to align memory for device controller +// default to CFG_TUSB_MEM_ALIGN for backward-compatible +#ifndef CFG_TUD_MEM_ALIGN + #ifdef CFG_TUSB_MEM_ALIGN + #define CFG_TUD_MEM_ALIGN CFG_TUSB_MEM_ALIGN + #else + #define CFG_TUD_MEM_ALIGN TU_ATTR_ALIGNED(4) + #endif +#endif + #ifndef CFG_TUD_ENDPOINT0_SIZE #define CFG_TUD_ENDPOINT0_SIZE 64 #endif @@ -378,6 +414,21 @@ typedef int make_iso_compilers_happy; #endif #endif // CFG_TUH_ENABLED +// Attribute to place data in accessible RAM for host controller +// default to CFG_TUSB_MEM_SECTION for backward-compatible +#ifndef CFG_TUH_MEM_SECTION + #ifdef CFG_TUSB_MEM_SECTION + #define CFG_TUH_MEM_SECTION CFG_TUSB_MEM_SECTION + #else + #define CFG_TUH_MEM_SECTION + #endif +#endif + +// Attribute to align memory for host controller +#ifndef CFG_TUH_MEM_ALIGN + #define CFG_TUH_MEM_ALIGN TU_ATTR_ALIGNED(4) +#endif + //------------- CLASS -------------// #ifndef CFG_TUH_HUB @@ -388,6 +439,16 @@ typedef int make_iso_compilers_happy; #define CFG_TUH_CDC 0 #endif +#ifndef CFG_TUH_CDC_FTDI + // FTDI is not part of CDC class, only to re-use CDC driver API + #define CFG_TUH_CDC_FTDI 0 +#endif + +#ifndef CFG_TUH_CDC_CP210X + // CP210X is not part of CDC class, only to re-use CDC driver API + #define CFG_TUH_CDC_CP210X 0 +#endif + #ifndef CFG_TUH_HID #define CFG_TUH_HID 0 #endif @@ -425,6 +486,9 @@ typedef int make_iso_compilers_happy; #error Control Endpoint Max Packet Size cannot be larger than 64 #endif +// To avoid GCC compiler warnings when -pedantic option is used (strict ISO C) +typedef int make_iso_compilers_happy; + #endif /* _TUSB_OPTION_H_ */ /** @} */ diff --git a/test-devices/loopback-stm32/bin/blackpill-f401cc.bin b/test-devices/loopback-stm32/bin/blackpill-f401cc.bin index 872fca7e598a7376bf37fec25385ce4e8f4648da..bcc55d390551f4d8c8fddef7c6270e880aa20a9d 100755 GIT binary patch delta 5200 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 QPy+l&hv3Z^{$fD?3+-|la{vGU delta 5075 zcmZu#4SW+-w!e2KACsgXX;WyMwlrz@NC`**S5xaQb(&6Fq82L419YW)yhp0fw^?v*;mArpen>sG`towPHjovxxQ_m3ej(@nc75`WDvP|i<76f%KflfF|^sksx0F8(29K7}a$ zkILDa^I-NOkjQr{^9-7+CJu?}snk1>xmuKqkoW@stKL{0R1#Z&U-4vOaZw&6A|yv6Az}rI)L}U~8Paz$PNvG}LYCbu{sNnn!}sy~ zv}qpV^Rqz2SFK}5u#u(uw*+{WI#C*+;J2Q0SNQx}jg4$mkQ(#_c7ucsG#Q(Mw9j2p zAkwsb5t9%>D?uxd_uBAb(=@5+kC-}_$)UT*JX5BaU3pKvd; zxkHowVpmQMI1^K3?2+c_FBuInN}3*{uHeG_Nx$@FFf+V|)eSySX67n6EItyqa@2wD z^WsxyjIRVw2`mJYjBkoB;)-1!O@u)gg*~i#a9WHS-4P^0Ir@xzMzD&sHh;2lvL>M* zM;qlVk!EIx-yc!XO~DQ}d4x%_h89DNuNd!?6v-lz#;xF#?+rt@bFnzXniar=;jf;R-iraG{_#c)`E-&{OPd z5rpj_S0E6)J)|)Pg0Dv~4g~+eT0=?PL2kHw-ig;EOj7>jAFjR&q5$r4aPCsRFJT>Qjz>7(d@&;%E=qnLlkTH;2H80(|^8 zHMbFh)Er4-$Zmcp)Nt2Sw@)qQR1qz}q1hAKI#WwDEesP2s*&7gz0=s}iU_c0Q!$BTEDPxRSbHICIY zs0d10U#{xQa&(QL)K|kx!Q^ovUBVG8;qOKSD{NWtGOE@O`n)x$*SjOQ2lkhK_?{VC z8fsW%>21KZYy<6sP*)(JqXDWh5Zn>m&b}C-XnTkac>PTfRj49Qa3=&b3ySQYAblr+ zJqdeS8X&M7D7ImvH>mHncfJ##8x^qPskpgO$@zjNve$8w&&t`mAL;B3C>!zYkG?@G z3FgiOhT;fjS^`5IaD$Eaz@1ibr-l7X&u!DiCWvnmwMoO*qG7WBpcI6}S~j-b#?(4(AL^|C!HMB+V@pRdm@sk&;)lcT?t zGo87$nNCZ4W~CfG6PxbLs?DfIGfV1+p;(x~BJL(P68|$^1hz`z*rXYjqrc=E^!eGu zYSMMDE&@NRM$9$;yY$u6r8uumy9KB6cck5eoB3zcEXl-u0whc5;onQM<BPqCXSlMrJ?_u|cAPuQp8cB!)pW{~NLTsRLMC zGKs86e9ZTzGtV^-`q&CdQL?iFs&cO!^-tMc3J#lgR={OK-00gQB^TimwGEAK^_@O% z5E*1Z0csQV7?qETDIc{*NiyH5z$Mn8qo!q^K*PGtKaEJx=~ z9uu1Q?+nGOlVbpMtHoO8;7Dz1YG0!>$MuC84WJ`L5t)(rPTXrwJd54&?ZUy4($u6r zUnR0$3M28-q@o3zNi%7fKvrMh89^=PtMLLPZsr>@@^x#c8n}Z{z)0NA@5?Z!RZSu5 zTVX{D8cD)L>nZ+JM&_;gnTSaSnlJ!Ozs65xAg1{Ga}=I+(-5O*M&fgmd!%%|71HGs z-Zm|#?OMA`QB+ZkI8AQUpu)q`Zhaj$PShcTt(LI@D>+o zL{@HR1!MJbc|#55IsK?WGu&RUbEH%)pWHHr7Y)_Rh0T4Z-FR1ja4S2~zmO~8YPjS| zENUlKI5 zm_Yawh*3bK7h#)c+}mcUFB2Ks;=c9!vB&u3nfabG=k`b$MX9zWSJt)VI)>}z=tZdA zCF5(_NTw)S$X*u04tT~dwL-oY8N^zJXWZGgM@lQwmSE5;Z-Ww>Nc@JGVr{AxN=muw zEwGygbJO9xej3K-w}CIFf-Y>ca#^sd7pKVavgGFR-d076=6X_Ijv=_S&6s#bG8KKP zUUIp!wg23hr+2KBeoc_04@{kfgwyNi^Oh`IvUXy}*}>n+QD4m7W#aG6%Jcm0Y$l{m zpW1VIbL;e_Xzr5n$6B-Md&YWDJUS%*@@y(3z-J(RuvMQ3(x%pUbU@y4R?$TEp|(}I zb7#eUXVp-Kp95-DD?0M?v+%<3{fDFqNt0wqmpmZ76J7&2TNl^`4aCb?Iy{fpWfvx! z&DRp@TD!X=+lE{Dhq7~0$`5$vV;lMSi(46N`ME@n0~_A2lwLadqsl zKz1(~u5)BUVvDQ=CcZ7_OU)Z_i(duz{Tkk!`yurP-1c+l5@yU>MA+SVMk9eJoCq6N zosblE(rMoT?yh*Fu)~*kKL%LGS2J$G$plBN6LSuJmZ>6P+?V+EYtvd~4Lq&lhfEeN zK}I|CxPCvcH7_%dUd5&_g&V3gp1#!GIj{;9K+{(p*T6M~f5KdqeZx}+m?2mWI4+Q* zv-neHr-w*MPw#dr@wNl^uYRmj!7BzW0Kz9;?x&-kkPx~ z)@JA9>pRwiRW= z2gtYL>pW`1z~ipX>ePWB8>M~#eJTEUtwlX|fU!JMTL%?^Y}MgUB*sprMFs!c?cT9u z3!PXDIB(MO@#vHBAKRwCx9yn)9zPlvR4WEL>h6`4Zi}d=JJyvvK#QqV?^tSD?^szG zwF8$N9n(_u4ka9>UwO%4Isq3J1vbW}E&NNrLE4y}0?Zb8HqMkb5cT1HnxBlgJT|`O4)F@~3Y3beJOm6L@@9Ktf zG}_5OG&9e$-@BepAGnUG&Dl)xs>}KfG@tLJBU%HRsphGszr(?SMrChu;%ZJcsUu}s zgOa|aOzbIpANbn>)pS}~=B>U^md!*o^eUITgWe5JEssa%OeH(%T~5cEKqLF=P?y6P z7?SikHO3u5V*}NMJhtcibk1yljj>r`;Amk?MlTO_ej~j}S}y}4X$!5*{!b;Qq;k|m8Q3M`+-O3etF zE!gr`82_p8duULD&>M^Qqa(KnDG@doFFGt~dp4EZLz}qUh3m0(^Ah7lvqytZmwT>o zU^C0E8qxFS*?FFaoRy;t-pTF^F=ll{gOc|3NK6hgw@S11Dl;jPO;scl=?~~{;KmJw zMD2)27fn&S2|5he57oK>Yyqv3HC?}`V*I7;=;<_W88o_kC-E%@1;%_rSmh)(oDNNM zc0jlNTF$mYkztQnZGlOOpb|~-sCw$0@Ci8gb?Kn`wgI|n6F!x_&-IyF3lr?C-F2vZ zX^r34fp#q8j9`A={g5IWtYB9?Q3PR$G3>J%fG=^gu^toj0DSMaI` zL#y~(olv=&e1~E;ylai|Y(c-RuBvw|owjum6P61)`WSG0bJw|f34co*>qHMWZq@Dh zr^n!^UTq<9Aa2K_ZC4KqbL)Py)yy}{$@Hjp#iP&1G$UBkE2x`_>-r_s125C4EKA8V zk)#wI2WJ|aJ_!F!q$GupjNsI)dKGXwHOsFEHPx41pi3*^vZ;04w(fJ`9{8W)ZxTY} z@X-{ls3yJkMiP?NepRO7B+WRy#oq(BY8w9Gns4n$c^CTc4SF9=5$ie4-7vHUXplcu cxGDF8RK#Rx;r}rNw^}qT=aWMSJ~Gfh05W3W*#H0l diff --git a/test-devices/loopback-stm32/bin/blackpill-f411ce.bin b/test-devices/loopback-stm32/bin/blackpill-f411ce.bin index 6d848f7a377c768736f4c0e1d2e50e99efeea1a9..2ff6e6b3b388adc6d14662bec6cc52fbdf37856c 100755 GIT binary patch delta 5042 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 delta 5040 zcmZu#4SW+-w!e2KACsnS(x%WhZE4Z~rUa#cAL&-5PSa^i+*hnV7SNUQ@gAu@*Qoon zvimb>&^0N`Tj{tzq1iq^p8{^b(ybPuq*z6H;+j&+7Evh*3=qWW2V~mNySlHx z-|3mT=YP&U_uO;Ny^}BRlkV;4!1K)r84&z+m=VKt)ApQBx{9uBA4hJcmy9n2d54)l zhS@w_6p4eA&I*JmL#PljATv&0X(N1ytTJMg}WFD-c7K4ufIs=6F7~ zXE{JOXyYekH|T7jgA7<)djKJAcXA~X|C3)TzcCF_$N+{7+HO^)>TV=D_{Ze=6r%Vh z`FzzmFnbY5G8O31Vgin2`Zh^79mnpkZz#bUT8 zTQUCmfS^}=_W4;ay6MP(5?p>Ys<0cmIkjf)q<{_1UKFf{u-pxEChUTz*hD)~rL*Fd zLViriCY^^^kk_c0zmr+1x(|>J&?x0wm~FU-x2R0GgRfT2%kBY52hd-DUIhAYAn`ji z@<)D~Dj)aot$;ki52%*n-Ml=>;vyJ=B|3){h`~z4IJ;$B3Wqslm<@57d$nk9S6~5W zOsoirJ^P%!KSt<&f;bL{c;w4qJQ5BPD@dgF$0JigZ8u|Qs`L(IYG(15*dQNyfNxJq za}l5a2t<5MvNZ)7S!!^Lk7uc)r9KMYwVboUkZ*yC#k3G4Ig{Q=tJtSAs^ zTGy?%$+(?t@?g41Q_2vv3z;<-XqD>hT4n5jpxTJdL?t|>#UD^ zJuH)3UBSD2tpRKB5&dk=}L0Q&B0r^*V)|T zQ{G}nP7XK|m1VR@3$>T@x+o>hj#5`}Vg8g?dMA(>YGKvG50x3YN)C%p#LOJk(R)sO z{4qw z<5?oj%nyA$Dx>{@E;eP9Nj3+ULX5BI@0MgK_u1YF6g+^WWCNS~Lb-aN*ima!+jg?d z0QMi2P!YQ6z0eZwGeOIRg)|9Ukc1a~?-Gg~V}h=m1d_JxV3QI-l!w#~YWH1J(? z=J*9~p`(a{c%@fj6vc6QVaB~J147dXqyu0^3&%PB# z*cx>Be1Y48D!ni8=P<^;!0%aeFq!M&M#>i+{d1T}&Y$}I)i=V)szOI@l$y$pQj^$1 zqLx49o1~&lmN~SsJa>3~*5_CxngV%HfQ}b`e=TQX3x>7KpSue`;%VO#&Z} ztc>en1I?lT9hD(>pt9T?tmLRYOC2mkb$1x4hHb<}7c%X9fRSh|UfNtfIbd z!YFxtxndy8ws#b1-V7}VlShPf35T(SzaJIMuw{YEs9HPhao3=JcT=DR_LqMA-Z@(u zYFK3IZ@{%|1MPuOS0JE+KC00dXbNm+Uky{VHOTthUOz+?s>l`C0Rhc|BKtc?+f884 z!k(7;2rLJRZA9-5XnU>Q@B8RR8LW6ZW^9ymo`8YubTYOH;VRxKmLFhyzzM9f1sI_aTx<>^9y^ey`;{0 zHhT0Mufah@X@tekuHu5igvpE3BMsPaQLu2|3F)2K6ptJ~K)MB4KkeD#y&w4lYv$a~ zdK$|3M>H0BA9R@ge2XSez4NNJAZ{GV#o~+nhnhv%L~;;_^h#%UGAHL|bBqIt^Y|2P zcFwO3WI-ovIDmq40Ylld>f_d|Ac^fl$buqr==I;*?fDtQFVPua}#6cpNt(( z&%p=z#X3E&(J6BtjDP!dnMl#!K1MhOu7!h%Sb#<9jEig_e{}q=g#6KQ^pA4D+<0EB ze!c^X%chVSiBEdo;Tv?iwccrqL&jmljtaOBh#NgEQc4jnQCiU0R?o?EI*~y-^v&WjQ$Nq3!^XFk>zkG9$7GTNbvLHy5iL- zQNTHsVlC4%TC33vG}?0$@ZYpWK6W4 z=TBv1-e$@~Od8O%4rulaKb3))JFY!P;aM{aF|u7qd}*phO4phpEspVvX62OJIh6$~ zOm}an-%-9ew4uJFlgKtqzgbW0>!#mylKJO`n9+DqUmzZNW>VW(R!>VBG z9d9Vl8AJuDkNsV(Dp$?^Jl;jV#`PP}t4u$3JhT+EelHC#$17Lz7d+LG)! z_50Y?;gx>+E<)uln^@CE@<+CZ>~JCMi)-RiD`atzPOO!=ChTo3Qd&_`2?o9LHYD06 z6Yns8v`w*xl2U*EF4#>2kLXa|APwU;wt8GQ`;)vv7_RFGfF7V6M$OPiVpni8Tb(R;g2K`e=ci2UdU^*3sdG9XL4z# zqm^e{a4Y{AL^IlKk$=!Q^7Bz zZfFunTpisnkWEX0+ZoX&*2xmUl{<63R`tN8d=*^ZYxsG&pHMw;dCy%y*qpp2bBGL` zLL)Le!unN5C7IO(dGbDRX9Ylhl{XuZUBAnF5EFiO&aF6wsE`?mNgH2is7OrUNxVI6 zSSzoAr&at{22&D2M!NI3K`)R83FUyfh=j>Xpa~^|wE0~C_KLq@Xz)LI|8*o>PSa(RuwW>^qqzvmJ zNo(C>*A}>t-o5CyUG}HecdZAlViVj%56R%+6~4V-v1^a}n4YMugJM9I>d-NX zv65*~!9Tj)Kb~Tu6N>@o4M}_~@@(viyXJw%zm5rt`-Zye?w90Flc=S;)|EU& ziyEqbT$9#6URFjm;gW;nNfg~Ahr{(7H#uDApbh8)v>FmL6Dh)FX?W>?geq5sHB4>JW{Ou_)^4Erd^;UZ(xJIZp7Ni9lLU>$ z-6@INHsx1_%d&|eXbs~*YLu6`fRyop~Oo%pDUr1ZX1Xal% z3HLFrw+W}tNJ zvI(wTCmJ*vL8A$qK7#Q(gy*1b4MSTjZbt`h6;i`&E?%-{TzE)u*MY5@i zWFmc-J`a~@C?u*W7FjY)H4}6Qu%9T^L)ZjbC2RKnvWoGRcA^*3xE0Xs?w`W9_6Use zsIbaTY}jq8UD-bM_L-b*g(AZ)qtXPE6hS2#ViD!^S>YHs_igF0@@GS|e-r*H`)$V; z$|RWJ?b@CD%9q!8Jzc121*Zq|3#Z<8K#0AUU$al7m23k`HL8yc>!Gj}R> z#v*@;sz$M@Ur_ps>jov%2VcynEKANa;pAVWsyR5}*z{re1tK*$bYK)~vg#GUX-$?_ z7WCJbUZ6`W;X;~Z``Nk^!oBco#9t+Z$SI{Ny04nF-|Klvy8YES4d-gce%@@}pZYO$ t;_Gw-&J^=mRSgV12sF%}D%_O&sRl6_N$}$rf(tJiiRY6e3I5_h{|8N!+Y0~y diff --git a/test-devices/loopback-stm32/bin/bluepill-f103c8.bin b/test-devices/loopback-stm32/bin/bluepill-f103c8.bin index ea177727ff2765c9a5e005631641ca5c4edf69ac..456927607a8d7fe1cc0d196bb445325dcb63e781 100755 GIT binary patch delta 6673 zcmbVRe_T`Nxqsht@(TzM2ues)P7=J0L~X>iwZ&>k!V!szg|%B-cSrT!joTl$>3X+i z_uA#4U7J*0Eys31YS+$owRTuINH171)OG9Jy3Z0SccN{jYc&e(?LoqFAeM8VHxYmI z?vK06hlk|6@AE#-^FHtQ`SBk1)Ev31vkYf52*EExmlp9$@my6IJi^ynys89WLgFJ+ zzBTjgNCONEu%+n`{}SFu6_xWWWueN-`TMD*c%ZwDqA^~{@1<`rtt28DEWXh%CsPqQ zITb-j*Q2dLViA9aUXp*FLJUY`bUj%xR?M3eW_+H%U2#KJ6lP8Uo#Y=Q5)m1<}&? zVrsDP#%Yz;%r0oOv1j6#@%5v~JLO2@0j+7tARSw2AFA=K`K+9OLFLN638u;8nsRp612 z!tp+E$jJ}jpvEFZ3KB0JmXp&FjaS!WY(iG`+IAQI05i&wP5ixC1p#97E+ArSwx>mS z##J}!MEK-37d~BRY!P&a>!CvKkb;$y zJLLO9G`mfBF(@a0BsVr2SRMFV33GXDhae~4m33VsKN`r=NA2t{g6%Hd@Lz(=?2geg z7K=M&Y+1yT^>@n**+@T_EL?~q>+HrfJv56#*>J|KK{=3QWka*3pA0%@2a_x1Z^9T+ z><)Fn?j8^B1?zu3=AlN7^(8IB9+zs+!u|@JZ#QizAiJk{vyUt;PIe&tFH zKM%)&nqGIIF3qJ|| z0+hWoR!!?oVK~{nE^2rTn3wk z)(DEsE-Xvv(LZ#OJw^Z zO43RH`4x~%9y*F5WR^(o<6p|Vm3lD6JM)<=vNS!B9z6Bc!GFm&;XeND{CUg?wb$Us z;;olH@w-Ke{=`QN#W z*ZBgS92%?`(^Y0ZHD>qCR!bS?YE&kT(WzjAE$}TclJ@rdJ zQK0|wm%iR{lwTIrjLVJzh|V8R>$=>2%C3r*^X9@E^^7;COHQtweq6$w;x!wf_uJDul1Bew*GNF8zT`(R`-|C^%axy4hVvnRL8$>!9GJ`1m$QyM7p8vQYK zVDgcUl3G;0I`L44!9OrD03iG?={sk0!5^n!c5_Ez+N6K%kduSbJ!chRvZZfyC|g_C zG@Q)>7@h{Mx(;-7-B}bN=kOj7iCpMeuKbX5>4!7Khewpu_^R?V> zm1T}D6RP8L7Adg!#T36_t}%Dn5zhSAI7Bi?RPfbvZ&d1!z!U$Yxp#X%O^Il@TYy+|^XMd9gk*@xU zi1YR!<(NWy$n(5J4Mc?_0Q{_|3Pzrn@W9UMg|U~vb;Mjd9MemR zfg|H`J`O~WRO@2& zA%w@dD&AtK2#`Eh9a4mzM*n2mC%h92wLhX~ zN7Z3AEKq#I5VGG9T_|EzMSxYc)qvxlkX7yKwsKFFzfi)9H+Wp5*z%^JdCe^4Epb3M zEGNG&tJ_MacU+`y#<$^RoseN3l&LUowR_s&`vIv}%63>i`{6GgerF;}K_`BW1gm7B&r%9RKa3#;4l5o^s_67N*fo(th1vWhg^7%Vu{` z*+7;8;+^)4#aly(cy>+pI?5jsa0TUKg4u=^0eZNAg&R59+FY`YK$p9WiXX%0Rv>xXd0Kpcdf;E{5?oWwMUJW)-Ju2yRVycZ ztL?$(B)P6}0y0!PWM!MJR@0x>MuhHSX=M7UBNbD*K)YvSRCT<7rwwR|3h^7i1ps;nV<&?<_wNomT>KyU#3ME1KQO7shx;g`JrB!#R@6NVsSqRAxhlp!w;DEF+85BbSwW&q&XY01eEqTd-ll`hC(mCU1izPWC!qcPV^W(mH>C=TmozvAJH`LZdI>w9N4uIb@wvYha65unH?vxC$@V z*mc{2k5l6|$|B9vY91et<*r4HoVOdM2!SDQ(_$TvK*m-82COLV#LTC zxX3GjNK(cyuj~1pRl%YNuDleZ`CaoG@DKTq=ar_jt>AsSvs>~oaJ^IFmf|4@_xgSC zj4a(!jpL8fQs$3R1=Atj%+w{E-~07MHjT|W`#Yq?jFz8Co|?hodz1#Us^Uek%>(wX zl#vzI!P*K3taCstKAN|mk+ipC^Gx#Xnf!Dd!g+QJ9CG zuEl13Fo%C=zG>MLX_429+a)b_D6PAsC61ZoZcuMjGDBOv*xW5SnH;`vzBzDJHQ`lU z=6w)&Pb*&?dT?#FAD27D&ziqm(}x?<|CDQ zvUklbCvFS22y;}shbn`Vm`_;~AEz@2Sw-SQU0%tlhQ9%*I!QnoIC^J|V#LOL-HTF` zqsT#SYOlK}=(6cc566)ie531-Ds**;k^44_0SbJn%h`|3yCesb3qCc>Y>HRH%@)ka zd23vqPw}c@=M}`S+CY!k{^547DwT6HTzM6NN%oDmAT-y-Ov>7!Ly!*wx6~@rWpVJH zV-s1FrhG{ZQX#emvkqDlT-tIHBsp#?XAL^oYa^MA5fL}6%}6+YkDT0@dhR@pAnj}c zLmhdqcSuV+=?gR>Fqlam`?4;faFI2zLTT`JpnC!hl@PzaO#DLis^limQDHi<(+vf% zj<9MYy4t+UMpj5PHxc^XM3%-~T|B6QeV&0f@56)W=&5rVlsf_40YEYdNrG+?jwCEe z6(c)WN3YixsN_iRzbQ&oZM&-G#YdqvcxsyFOQ(YqDjxa<`wyT+$a!rh`NXAuY4L7V zxUJe2X=D2Vy!*$ps7#xn;QJ+=qeR5{N`6BW+1EuE!PU&j-oa{H)ldz-oK}Y^OS^~2 zzJtx$5BK)Ov^Lx?l`&oq4ebMbbL6(0vh}{)RuIKxk5k$BHeese4mtVJv@%S$dZBHY zNlv964XN6Vp6@k}haL?DtEu-ZLhY`_F=Qce2$+Ew9N9b@e}I=xf*0yb;)OuMbMUr! zEtnP1w#v!wX|fAsk4Ce{vM^B_5^`JLjr&5&n_R$T@W{!Rrr(VZ8lQ1FPp)2+DMmTz zN+nLXp;Dy_l$kNFvO@`BsLO>4e9DkwRUBOcNA*!U36sMefbNES_%Jz&z!i`=8#3jC zV4x%Z)gqyUA~8Q*BpT{JjPn_V48!QZYJ`QcTs7k2#f@$-Lbu%&68f)H%t5G_?$K>l z<=7oK5Eep6U3(&q$^!}GK}b!TmFYav0rv(190DW)B9cO(SBHyifL7a~^{lEJjTKa_ zQw>)^LljN#&B8*3u)sSju?YTR%Hr9*b+*IpbyC5Xx-H@WRj4e?btRC?C2|xM;E<(a z{T}v4wi$Z!Ig+JuH+sRfFqUUn>VXb~3s#rLo`6n$so^=eeD;pxd@A|_&zt^V_Q?xZ zc+`?*W3|s(tMgN~{F9~NzlO{YC8;h&$s^Pg;azmk4Ia0&~ zs@yh)6h5oxbO_l$jOzWk^0YwN^}Y{c1D0GbVvL+^A-1YXLA_dhp3D@V-OZZEFUH=D z&-QMlh|Ct36+Pf9rFseYsR(+^Vb9vErsHYz(8A`eRAY4`-CP}LMvH$KE9lGaTUARn z9t(vKyc(=w2UnK^$jX>9eFf*((yE~nM z$>5&$5R z2*A=nvvOu5bmaHJ`|)dC=&ErIyRLKLzy(wfE(8xg8q0XD^6&Os;Q#NsjOPyjP0tzs zubvD1U9MB6UH6!jc3s+Yvt9$JLBB>qvdC)~E}Ffg91U-sz47(BjlpNSEQt}9MRZcz zL>)zfFhHWv$obaTEF0aKsMUKujaw2Nu=%KM39f$Z3c5iFr7qX?5H&Wheb{y-@~>Az zB?dN^bPJH(#(xfyIK7$@2EZ6ye-UFVt8pt*6s7mX;AQu$ zpjo3(J+XaOP`%>p5U9B#$C;ivbUV#5U8~_^NpRs2M%9@#s zIOep~F)5=0TSnT-EP2i4RfeXw+FDA=b)0(@yptBXETU2r3^szNlA1%)_S}D`AnM$% z_2-Fq&W0hpR^WScf2kn(nX8^9-`J5J z06axfdW`JAyO{I&L}c=rSU&j`GZ)viH8L#5F0!4SmFEHw;<4O#M2#mxYW!*lA#=N_ z9LY9vmYtKni9tL_-a?#R)8e(FmlfnVq*Y(+ zqZo>%Jipc;eG8DMofA_*@X}V&=~fQ9!8iPhq2? zAu0vQnO$mpG^BT%+pRUou3Oq9;7>8H8C*lE3>iLZ^Hv~gtI@S3*dQ<`>jOk!`kVm< z#%9s8q|U$5+8{IsnSr`M6RZeS zp0pBeSCC^%kbQR5^!i$4Un#s-i>rlNwhqus5YVvz(+~)532qj4L>aau1SWy%W~&6M zn}gegf=~_^egkE0r??kk)d|SELwVr9pj8U`%-tpJ{}o^xIIyx&wKZtOx*!klP} zfmi~o?}MrqP_k#r8-!P`EMe{;-v_(zXz_=`>Rm1FSvSol~7k(28*60?*+{5Mln~U#@q!A=5Ds( z#>{*$$qd{7H!x^781%Z3D(+5tzc}fAm9;kMeWRciHGMXaakI)a)cdyt^E%)E8ZA6f z?dfjy?+{W>HwdOaN6k(FMIT|bPgfiIiX~)!Qo0;@3^w9&WTkaW@KU4!ew(dD(v#BO z>MtT5h!WSZCAd4d6ZV^fkc*Qc&wDAUGzz{KcOC;Z8$r#=JQ}Y=-$B9HNA{;wXnG*M zj*zPiGC53f&AC#+~C;OL9Uqgg2ATrrfFDj`BCD@rj9S_q6J4x4kvHT#fgU zkZEcLl8>kk;N3cbdBdO@Uq>#OX5>;SCLpRg2DDX+^phsvlv;^@L!L^#1E-TcsjIMq zTurs7UdK`EdPref@lE@#qJnS3wEc8nEP+bR1>5K1aKGmUqbd>TT8Nf*jdv<3aefG8YkKsKE#O+1$uF>tv6mtP==0TObnPDxh7@Y!+OpzY-Zo6-O z_)%|ZD_xwa{>4ibq>TT?(=m+FZw~8+RYy-yjXyqWZY}dN#oF-gWH@74p;s&Yjt0JI+;mb?IMQG~2cTbSkJ#6R`c)cg6#cu&^j z2U81+kz6(*+4L3M;AWvxM)+zk%C{%$*W*;So__(?3d)JyIcwp-0>00(vav!&vgYAkWM=kE4#{tf zljYgB;^#?yw(Wi-e>x^XjUahotSdqTYE*wLc&ioZO&IY`y@c=rG%PvuWz3+F9;eZ@ zS-`!t_03n9QeNRozbB13r9KH!6dLJpvi>Tqp`Z2JWtq*>&j)F1G^AC!NnwZ{g5!ATipGuxo0PoDiT zgT~#atZ<;{DsF9Ea1}wDu-$fm#hbZFKy6@+l6w`FBXJug2;ZL{oRM-i-B%E5 z62H_*LAEigpJ^)7=ewpTcy@+@k2fRsiD9XX9qB0(hD`a`fp0Yqt9Mx?3C>T-yb?qs zRq9+HFbrc<>{?%|#$Qk!HjU(jm9;8&xcj2~GGwKZiyCntNDX{eiA2^1=GPR7xh`tj z;KbPoLgcV@lkd0}di`QnW*J7rrETdRdkC&|lXC zc>Dl;TRCwO3YQiwO|r+KwrYSL1Jbu6yVGW=*r_aYSR^7@YDul7j?`J|Nqt&{#gkT% zA*EF?BhoV`*Pr|?sU@ZL{DRGb(ra9bczSU&B%imdQaUX2?`>Wmq_zq{#)-KMytz~LFAekCU+t;-HWkQVGxTp;*&Dzbm1WH~-ktd16C zx}!2Ct=I4671KS~2K_=Y(4=`SCx$8w;b!ryGO!b9OPAtuGzYERno}U}VO#i61-4oI zn!R?JWAnH?6Wv|AtY`D?N)DF8p6mvzUHng#y`p3~H1=1Nsg8+wzY0p$@!=*nwzVlv zUPCOr&3D5visi0hTLCNic7+?38ojv4DQDOIq5QDobl9O2Q1x%YJHE^4Nj=BP>D*4l z3`>hGu!cuE78mpy{ZqA@`i=f-Y#d^kd|6_I7!r(hkX@U4u#s(ji?#4FF-WD+C6(z^1+cFV>=zg5*?5``^WxtkwuV*k5cLS11(CH z)5m@dH-1n!5ie1lHkt`J<6ZC>V;o{xd$Q$9>;V`TMpFDgo=cIQz-Z2WVMA2MK2)=5 z8rqBs*TVHHI;PpD^`mVQ@wpRl5X*kqj#LF6QgqeRU26QLu_6)sY4B3Vjz^lUje8cMqUhDYcc=m9=+>+dDHm zjh(3#3#xTdS9a$HUTlPI$p!z@fAIH20`p2YhWyn=5!|$_WAw&B6)dA(+a;S7@W>P4>KY=hGQsqr_vpr<^b#-*+lE&Pv1H1<;;d69?y@@j&IPaCsSjk~+_ zAhYV)m{yA#f1*n}5ntC0=aIhfNZNU5Y}e_co%9ucWq2BtxH|v< diff --git a/test-devices/loopback-stm32/bin/disco_f723ie.bin b/test-devices/loopback-stm32/bin/disco_f723ie.bin index 76dd788b5b0994b41910ced54300bfd6f9f8624b..8b399eba27fa8e1a4f0ab86c184c4c97d2fc5b86 100755 GIT binary patch delta 5267 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 delta 5078 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 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO -#endif -#endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO -#endif -#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO -#endif -#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 + #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO + #endif + #endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 + + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO + #endif + #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 + + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO + #endif + #endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 #endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING // Linear buffer TX in case: // - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR // - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into #if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) -#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX]; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX]; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX]; -#endif + #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX]; + #endif + + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX]; + #endif + + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX]; + #endif #endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) // EP OUT software buffers and mutexes #if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING -#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO -#endif -#endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO -#endif -#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO -#endif -#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 + #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO + #endif + #endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 + + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO + #endif + #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 + + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO + #endif + #endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING // Linear buffer RX in case: // - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR // - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into #if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) -#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX]; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX]; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX]; -#endif + #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX]; + #endif + + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX]; + #endif + + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX]; + #endif #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) // Control buffers CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ]; + #if CFG_TUD_AUDIO > 1 CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ]; #endif + #if CFG_TUD_AUDIO > 2 CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ]; #endif // Active alternate setting of interfaces uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT]; + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT]; #endif + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; #endif // Software encoding/decoding support FIFOs #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING -#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ]; -tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO -#endif -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ]; -tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO -#endif -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ]; -tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO -#endif -#endif + #if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ]; + tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO + #endif + #endif + + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ]; + tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO + #endif + #endif + + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ]; + tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO + #endif + #endif #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING -#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ]; -tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO -#endif -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ]; -tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO -#endif -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ]; -tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; -#if CFG_FIFO_MUTEX -osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO -#endif -#endif + #if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ]; + tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO + #endif + #endif + + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ]; + tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO + #endif + #endif + + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 + CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ]; + tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; + #if CFG_FIFO_MUTEX + osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO + #endif + #endif #endif typedef struct @@ -306,7 +312,7 @@ typedef struct #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP struct { - uint32_t value; // Feedback value for asynchronous mode (in 16.16 format). + CFG_TUSB_MEM_ALIGN uint32_t value; // Feedback value for asynchronous mode (in 16.16 format). uint32_t min_value; // min value according to UAC2 FMT-2.0 section 2.3.1.1. uint32_t max_value; // max value according to UAC2 FMT-2.0 section 2.3.1.1. @@ -341,7 +347,7 @@ typedef struct // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74) #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE]; + CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE]; #endif // Decoding parameters - parameters are set when alternate AS interface is set by host @@ -447,6 +453,10 @@ static inline uint8_t tu_desc_subtype(void const* desc) } #endif +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq); +#endif + bool tud_audio_n_mounted(uint8_t func_id) { TU_VERIFY(func_id < CFG_TUD_AUDIO); @@ -819,10 +829,7 @@ uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint1 // We write directly into the EP's buffer - abort if previous transfer not complete TU_VERIFY(!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr)); - // Check length - TU_VERIFY(len <= CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE); - - memcpy(_audiod_fct[func_id].ep_int_ctr_buf, buffer, len); + TU_VERIFY(tu_memcpy_s(_audiod_fct[func_id].ep_int_ctr_buf, CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE, buffer, len)==0); // Schedule transmit TU_VERIFY(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr, _audiod_fct[func_id].ep_int_ctr_buf, len)); @@ -1470,6 +1477,83 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin #endif } +#if USE_ISO_EP_ALLOCATION + #if CFG_TUD_AUDIO_ENABLE_EP_IN + uint8_t ep_in = 0; + uint16_t ep_in_size = 0; + #endif + + #if CFG_TUD_AUDIO_ENABLE_EP_OUT + uint8_t ep_out = 0; + uint16_t ep_out_size = 0; + #endif + + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + uint8_t ep_fb = 0; + #endif + + uint8_t const *p_desc = _audiod_fct[i].p_desc; + uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; + while (p_desc < p_desc_end) + { + if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) + { + tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; + if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) + { + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + // Explicit feedback EP + if (desc_ep->bmAttributes.usage == 1) + { + ep_fb = desc_ep->bEndpointAddress; + } + #endif + // Data EP + if (desc_ep->bmAttributes.usage == 0) + { + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) + { + #if CFG_TUD_AUDIO_ENABLE_EP_IN + ep_in = desc_ep->bEndpointAddress; + ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size); + #endif + } else + { + #if CFG_TUD_AUDIO_ENABLE_EP_OUT + ep_out = desc_ep->bEndpointAddress; + ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size); + #endif + } + } + + } + } + p_desc = tu_desc_next(p_desc); + } + + #if CFG_TUD_AUDIO_ENABLE_EP_IN + if (ep_in) + { + usbd_edpt_iso_alloc(rhport, ep_in, ep_in_size); + } + #endif + + #if CFG_TUD_AUDIO_ENABLE_EP_OUT + if (ep_out) + { + usbd_edpt_iso_alloc(rhport, ep_out, ep_out_size); + } + #endif + + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + if (ep_fb) + { + usbd_edpt_iso_alloc(rhport, ep_fb, 4); + } + #endif + +#endif // USE_ISO_EP_ALLOCATION + break; } } @@ -1531,17 +1615,19 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * if (audio->ep_in_as_intf_num == itf) { audio->ep_in_as_intf_num = 0; + #if !USE_ISO_EP_ALLOCATION usbd_edpt_close(rhport, audio->ep_in); + #endif // Clear FIFOs, since data is no longer valid -#if !CFG_TUD_AUDIO_ENABLE_ENCODING + #if !CFG_TUD_AUDIO_ENABLE_ENCODING tu_fifo_clear(&audio->ep_in_ff); -#else + #else for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) { tu_fifo_clear(&audio->tx_supp_ff[cnt]); } -#endif + #endif // Invoke callback - can be used to stop data sampling if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); @@ -1549,23 +1635,25 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * audio->ep_in = 0; // Necessary? } -#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_IN #if CFG_TUD_AUDIO_ENABLE_EP_OUT if (audio->ep_out_as_intf_num == itf) { audio->ep_out_as_intf_num = 0; + #if !USE_ISO_EP_ALLOCATION usbd_edpt_close(rhport, audio->ep_out); + #endif // Clear FIFOs, since data is no longer valid -#if !CFG_TUD_AUDIO_ENABLE_DECODING + #if !CFG_TUD_AUDIO_ENABLE_DECODING tu_fifo_clear(&audio->ep_out_ff); -#else + #else for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) { tu_fifo_clear(&audio->rx_supp_ff[cnt]); } -#endif + #endif // Invoke callback - can be used to stop data sampling if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); @@ -1573,13 +1661,15 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * audio->ep_out = 0; // Necessary? // Close corresponding feedback EP -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + #if !USE_ISO_EP_ALLOCATION usbd_edpt_close(rhport, audio->ep_fb); + #endif audio->ep_fb = 0; tu_memclr(&audio->feedback, sizeof(audio->feedback)); -#endif + #endif } -#endif +#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT // Save current alternative interface setting audio->alt_setting[idxItf] = alt; @@ -1604,8 +1694,11 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) { tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc; +#if USE_ISO_EP_ALLOCATION + TU_ASSERT(usbd_edpt_iso_activate(rhport, desc_ep)); +#else TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); - +#endif uint8_t const ep_addr = desc_ep->bEndpointAddress; //TODO: We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND! @@ -1620,11 +1713,11 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * audio->ep_in_sz = tu_edpt_packet_size(desc_ep); // If software encoding is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters -#if CFG_TUD_AUDIO_ENABLE_ENCODING + #if CFG_TUD_AUDIO_ENABLE_ENCODING audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf); // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / audio->n_bytes_per_sampe_tx) * audio->n_bytes_per_sampe_tx); for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) { @@ -1632,9 +1725,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * } audio->n_ff_used_tx = audio->n_channels_tx / audio->n_channels_per_ff_tx; TU_ASSERT( audio->n_ff_used_tx <= audio->n_tx_supp_ff ); -#endif - -#endif + #endif + #endif // Schedule first transmit if alternate interface is not zero i.e. streaming is disabled - in case no sample data is available a ZLP is loaded // It is necessary to trigger this here since the refill is done with an RX FIFO empty interrupt which can only trigger if something was in there @@ -1651,11 +1743,11 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * audio->ep_out_as_intf_num = itf; audio->ep_out_sz = tu_edpt_packet_size(desc_ep); -#if CFG_TUD_AUDIO_ENABLE_DECODING + #if CFG_TUD_AUDIO_ENABLE_DECODING audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf); // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sampe_rx) * audio->n_bytes_per_sampe_rx; for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) { @@ -1663,18 +1755,18 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * } audio->n_ff_used_rx = audio->n_channels_rx / audio->n_channels_per_ff_rx; TU_ASSERT( audio->n_ff_used_rx <= audio->n_rx_supp_ff ); -#endif -#endif + #endif + #endif // Prepare for incoming data -#if USE_LINEAR_BUFFER_RX + #if USE_LINEAR_BUFFER_RX TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); -#else + #else TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false); -#endif + #endif } -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 1) // Check if usage is explicit data feedback { audio->ep_fb = ep_addr; @@ -1683,7 +1775,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // Enable SOF interrupt if callback is implemented if (tud_audio_feedback_interval_isr) usbd_sof_enable(rhport, true); } -#endif + #endif #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT foundEPs += 1; @@ -1734,7 +1826,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * default: break; } } -#endif +#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP // We are done - abort loop break; @@ -2032,7 +2124,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 { if (tud_audio_fb_done_cb) tud_audio_fb_done_cb(func_id); - // Schedule a transmit with the new value if EP is not busy + // Schedule a transmit with the new value if EP is not busy if (!usbd_edpt_busy(rhport, audio->ep_fb)) { // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent @@ -2198,7 +2290,7 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req if (len > _audiod_fct[func_id].ctrl_buf_sz) len = _audiod_fct[func_id].ctrl_buf_sz; // Copy into buffer - memcpy((void *)_audiod_fct[func_id].ctrl_buf, data, (size_t)len); + TU_VERIFY(0 == tu_memcpy_s(_audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz, data, (size_t)len)); // Schedule transmit return tud_control_xfer(rhport, p_request, (void*)_audiod_fct[func_id].ctrl_buf, len); diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/audio/audio_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/audio/audio_device.h index 0ef100fa..7c88b99f 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/audio/audio_device.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/audio/audio_device.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2020 Ha Thach (tinyusb.org) @@ -473,7 +473,7 @@ TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id); // the choice of format is left to the caller and feedback argument is sent as-is. If CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION is set, then tinyusb // expects 16.16 format and handles the conversion to 10.14 on FS. // -// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 devices. On Linux and macOS it seems the +// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 devices. On Linux and macOS it seems the // driver can work with either format. So a good compromise is to keep format correction disabled and stick to 16.16 format. // Feedback value can be determined from within the SOF ISR of the audio driver. This should reduce jitter. If the feature is used, the user can not set the feedback value. diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.h index 1b90d091..921bd7a1 100755 --- a/test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2020 Jerzy Kasenberg diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc.h b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc.h index e345139e..4658e43a 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc.h @@ -41,16 +41,6 @@ /** \defgroup ClassDriver_CDC_Common Common Definitions * @{ */ -// TODO remove -/// CDC Pipe ID, used to indicate which pipe the API is addressing to (Notification, Out, In) -typedef enum -{ - CDC_PIPE_NOTIFICATION , ///< Notification pipe - CDC_PIPE_DATA_IN , ///< Data in pipe - CDC_PIPE_DATA_OUT , ///< Data out pipe - CDC_PIPE_ERROR , ///< Invalid Pipe ID -}cdc_pipeid_t; - //--------------------------------------------------------------------+ // CDC Communication Interface Class //--------------------------------------------------------------------+ @@ -192,8 +182,30 @@ typedef enum CDC_REQUEST_MDLM_SEMANTIC_MODEL = 0x60, }cdc_management_request_t; +enum +{ + CDC_CONTROL_LINE_STATE_DTR = 0x01, + CDC_CONTROL_LINE_STATE_RTS = 0x02, +}; + +enum +{ + CDC_LINE_CONDING_STOP_BITS_1 = 0, // 1 bit + CDC_LINE_CONDING_STOP_BITS_1_5 = 1, // 1.5 bits + CDC_LINE_CONDING_STOP_BITS_2 = 2, // 2 bits +}; + +enum +{ + CDC_LINE_CODING_PARITY_NONE = 0, + CDC_LINE_CODING_PARITY_ODD = 1, + CDC_LINE_CODING_PARITY_EVEN = 2, + CDC_LINE_CODING_PARITY_MARK = 3, + CDC_LINE_CODING_PARITY_SPACE = 4, +}; + //--------------------------------------------------------------------+ -// Management Elemenent Notification (Notification Endpoint) +// Management Element Notification (Notification Endpoint) //--------------------------------------------------------------------+ /// 6.3 Notification Codes @@ -365,7 +377,9 @@ typedef struct TU_ATTR_PACKED uint32_t incoming_distinctive : 1; ///< 0 : Reports only incoming ringing. 1 : Reports incoming distinctive ringing patterns. uint32_t dual_tone_multi_freq : 1; ///< 0 : Cannot report dual tone multi-frequency (DTMF) digits input remotely over the telephone line. 1 : Can report DTMF digits input remotely over the telephone line. uint32_t line_state_change : 1; ///< 0 : Does not support line state change notification. 1 : Does support line state change notification - uint32_t TU_RESERVED : 26; + uint32_t TU_RESERVED0 : 2; + uint32_t TU_RESERVED1 : 16; + uint32_t TU_RESERVED2 : 8; } bmCapabilities; }cdc_desc_func_telephone_call_state_reporting_capabilities_t; @@ -390,9 +404,10 @@ TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct"); typedef struct TU_ATTR_PACKED { - uint16_t dte_is_present : 1; ///< Indicates to DCE if DTE is presentor not. This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR. - uint16_t half_duplex_carrier_control : 1; - uint16_t : 14; + uint16_t dtr : 1; + uint16_t rts : 1; + uint16_t : 6; + uint16_t : 8; } cdc_line_control_state_t; TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct"); diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.c index fab6f003..5adce521 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.c +++ b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -53,7 +53,7 @@ typedef struct /*------------- From this point, data is not cleared by bus reset -------------*/ char wanted_char; - cdc_line_coding_t line_coding; + TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // FIFO tu_fifo_t rx_ff; @@ -62,10 +62,8 @@ typedef struct uint8_t rx_ff_buf[CFG_TUD_CDC_RX_BUFSIZE]; uint8_t tx_ff_buf[CFG_TUD_CDC_TX_BUFSIZE]; -#if CFG_FIFO_MUTEX - osal_mutex_def_t rx_ff_mutex; - osal_mutex_def_t tx_ff_mutex; -#endif + OSAL_MUTEX_DEF(rx_ff_mutex); + OSAL_MUTEX_DEF(tx_ff_mutex); // Endpoint Transfer buffer CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EP_BUFSIZE]; @@ -78,7 +76,7 @@ typedef struct //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; +CFG_TUSB_MEM_SECTION tu_static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; static bool _prep_out_transaction (cdcd_interface_t* p_cdc) { @@ -171,7 +169,8 @@ uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) bufsize); // flush if queue more than packet size - if ( tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE ) + // may need to suppress -Wunreachable-code since most of the time CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE + if ( (tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE) || ((CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE) && tu_fifo_full(&p_cdc->tx_ff)) ) { tud_cdc_n_write_flush(itf); } @@ -247,10 +246,8 @@ void cdcd_init(void) // In this way, the most current data is prioritized. tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, true); -#if CFG_FIFO_MUTEX tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, osal_mutex_create(&p_cdc->rx_ff_mutex)); tu_fifo_config_mutex(&p_cdc->tx_ff, osal_mutex_create(&p_cdc->tx_ff_mutex), NULL); -#endif } } @@ -389,7 +386,7 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t bool const rts = tu_bit_test(request->wValue, 1); p_cdc->line_state = (uint8_t) request->wValue; - + // Disable fifo overwriting if DTR bit is set tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr); @@ -435,8 +432,8 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // Received new data if ( ep_addr == p_cdc->ep_out ) { - tu_fifo_write_n(&p_cdc->rx_ff, &p_cdc->epout_buf, (uint16_t) xferred_bytes); - + tu_fifo_write_n(&p_cdc->rx_ff, p_cdc->epout_buf, (uint16_t) xferred_bytes); + // Check for wanted char and invoke callback if needed if ( tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1) ) { @@ -448,14 +445,14 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ } } } - + // invoke receive callback (if there is still data) if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf); - + // prepare for OUT transaction _prep_out_transaction(p_cdc); } - + // Data sent to host, we continue to fetch from tx fifo to send. // Note: This will cause incorrect baudrate set in line coding. // Though maybe the baudrate is not really important !!! diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.h index fbc7162a..a6e07aa5 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -27,7 +27,6 @@ #ifndef _TUSB_CDC_DEVICE_H_ #define _TUSB_CDC_DEVICE_H_ -#include "common/tusb_common.h" #include "cdc.h" //--------------------------------------------------------------------+ @@ -81,7 +80,7 @@ int32_t tud_cdc_n_read_char (uint8_t itf); // Clear the received FIFO void tud_cdc_n_read_flush (uint8_t itf); -// Get a byte from FIFO at the specified position without removing it +// Get a byte from FIFO without removing it bool tud_cdc_n_peek (uint8_t itf, uint8_t* ui8); // Write bytes to TX FIFO, data may remain in the FIFO for a while @@ -135,7 +134,7 @@ TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf); // Invoked when received `wanted_char` TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char); -// Invoked when space becomes available in TX buffer +// Invoked when a TX is complete and therefore space becomes available in TX buffer TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf); // Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.c b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.c index ee824cb4..fe3691bf 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.c +++ b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -33,154 +33,698 @@ #include "cdc_host.h" +// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message +#define CDCH_DEBUG 2 + +#define TU_LOG_CDCH(...) TU_LOG(CDCH_DEBUG, __VA_ARGS__) + //--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF +// Host CDC Interface //--------------------------------------------------------------------+ + typedef struct { - uint8_t itf_num; - uint8_t itf_protocol; + uint8_t daddr; + uint8_t bInterfaceNumber; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t serial_drid; // Serial Driver ID + cdc_acm_capability_t acm_capability; uint8_t ep_notif; - uint8_t ep_in; - uint8_t ep_out; - cdc_acm_capability_t acm_capability; + uint8_t line_state; // DTR (bit0), RTS (bit1) + TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width + + tuh_xfer_cb_t user_control_cb; + + struct { + tu_edpt_stream_t tx; + tu_edpt_stream_t rx; + + uint8_t tx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; + CFG_TUH_MEM_ALIGN uint8_t tx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; + + uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; + CFG_TUH_MEM_ALIGN uint8_t rx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; + } stream; + +} cdch_interface_t; + +CFG_TUH_MEM_SECTION +static cdch_interface_t cdch_data[CFG_TUH_CDC]; + +//--------------------------------------------------------------------+ +// Serial Driver +//--------------------------------------------------------------------+ + +//------------- ACM prototypes -------------// +static void acm_process_config(tuh_xfer_t* xfer); + +static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + +//------------- FTDI prototypes -------------// +#if CFG_TUH_CDC_FTDI +#include "serial/ftdi_sio.h" + +static uint16_t const ftdi_pids[] = { TU_FTDI_PID_LIST }; +enum { + FTDI_PID_COUNT = sizeof(ftdi_pids) / sizeof(ftdi_pids[0]) +}; + +// Store last request baudrate since divisor to baudrate is not easy +static uint32_t _ftdi_requested_baud; + +static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); +static void ftdi_process_config(tuh_xfer_t* xfer); + +static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +#endif + +//------------- CP210X prototypes -------------// +#if CFG_TUH_CDC_CP210X +#include "serial/cp210x.h" + +static uint16_t const cp210x_pids[] = { TU_CP210X_PID_LIST }; +enum { + CP210X_PID_COUNT = sizeof(cp210x_pids) / sizeof(cp210x_pids[0]) +}; -} cdch_data_t; +static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); +static void cp210x_process_config(tuh_xfer_t* xfer); + +static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +#endif + +enum { + SERIAL_DRIVER_ACM = 0, + +#if CFG_TUH_CDC_FTDI + SERIAL_DRIVER_FTDI, +#endif + +#if CFG_TUH_CDC_CP210X + SERIAL_DRIVER_CP210X, +#endif +}; + +typedef struct { + void (*const process_set_config)(tuh_xfer_t* xfer); + bool (*const set_control_line_state)(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_baudrate)(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +} cdch_serial_driver_t; + +// Note driver list must be in the same order as SERIAL_DRIVER enum +static const cdch_serial_driver_t serial_drivers[] = { + { .process_set_config = acm_process_config, + .set_control_line_state = acm_set_control_line_state, + .set_baudrate = acm_set_baudrate + }, + + #if CFG_TUH_CDC_FTDI + { .process_set_config = ftdi_process_config, + .set_control_line_state = ftdi_sio_set_modem_ctrl, + .set_baudrate = ftdi_sio_set_baudrate + }, + #endif + + #if CFG_TUH_CDC_CP210X + { .process_set_config = cp210x_process_config, + .set_control_line_state = cp210x_set_modem_ctrl, + .set_baudrate = cp210x_set_baudrate + }, + #endif +}; + +enum { + SERIAL_DRIVER_COUNT = sizeof(serial_drivers) / sizeof(serial_drivers[0]) +}; //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -static cdch_data_t cdch_data[CFG_TUH_DEVICE_MAX]; -static inline cdch_data_t* get_itf(uint8_t dev_addr) +static inline cdch_interface_t* get_itf(uint8_t idx) { - return &cdch_data[dev_addr-1]; + TU_ASSERT(idx < CFG_TUH_CDC, NULL); + cdch_interface_t* p_cdc = &cdch_data[idx]; + + return (p_cdc->daddr != 0) ? p_cdc : NULL; } -bool tuh_cdc_mounted(uint8_t dev_addr) +static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) { - cdch_data_t* cdc = get_itf(dev_addr); - return cdc->ep_in && cdc->ep_out; + for(uint8_t i=0; idaddr == daddr) && + (ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr)) + { + return i; + } + } + + return TUSB_INDEX_INVALID_8; } -bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid) + +static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const *itf_desc) { - if ( !tuh_cdc_mounted(dev_addr) ) return false; + for(uint8_t i=0; idaddr = daddr; + p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber; + p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; + p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol; + p_cdc->line_state = 0; + return p_cdc; + } + } - switch (pipeid) - { - case CDC_PIPE_NOTIFICATION: - return usbh_edpt_busy(dev_addr, p_cdc->ep_notif ); + return NULL; +} - case CDC_PIPE_DATA_IN: - return usbh_edpt_busy(dev_addr, p_cdc->ep_in ); +static bool open_ep_stream_pair(cdch_interface_t* p_cdc , tusb_desc_endpoint_t const *desc_ep); +static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num); +static void cdch_internal_control_complete(tuh_xfer_t* xfer); - case CDC_PIPE_DATA_OUT: - return usbh_edpt_busy(dev_addr, p_cdc->ep_out ); +//--------------------------------------------------------------------+ +// APPLICATION API +//--------------------------------------------------------------------+ - default: - return false; +uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num) +{ + for(uint8_t i=0; idaddr == daddr && p_cdc->bInterfaceNumber == itf_num) return i; } + + return TUSB_INDEX_INVALID_8; +} + +bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc && info); + + info->daddr = p_cdc->daddr; + + // re-construct descriptor + tusb_desc_interface_t* desc = &info->desc; + desc->bLength = sizeof(tusb_desc_interface_t); + desc->bDescriptorType = TUSB_DESC_INTERFACE; + + desc->bInterfaceNumber = p_cdc->bInterfaceNumber; + desc->bAlternateSetting = 0; + desc->bNumEndpoints = 2u + (p_cdc->ep_notif ? 1u : 0u); + desc->bInterfaceClass = TUSB_CLASS_CDC; + desc->bInterfaceSubClass = p_cdc->bInterfaceSubClass; + desc->bInterfaceProtocol = p_cdc->bInterfaceProtocol; + desc->iInterface = 0; // not used yet + + return true; +} + +bool tuh_cdc_mounted(uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + return p_cdc != NULL; +} + +bool tuh_cdc_get_dtr(uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR) ? true : false; +} + +bool tuh_cdc_get_rts(uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS) ? true : false; +} + +bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + *line_coding = p_cdc->line_coding; + + return true; } //--------------------------------------------------------------------+ -// APPLICATION API (parameter validation needed) +// Write //--------------------------------------------------------------------+ -bool tuh_cdc_serial_is_mounted(uint8_t dev_addr) + +uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) { - // TODO consider all AT Command as serial candidate - return tuh_cdc_mounted(dev_addr) && - (cdch_data[dev_addr-1].itf_protocol <= CDC_COMM_PROTOCOL_ATCOMMAND_CDMA); + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return tu_edpt_stream_write(&p_cdc->stream.tx, buffer, bufsize); } -bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify) +uint32_t tuh_cdc_write_flush(uint8_t idx) { - (void) is_notify; - TU_VERIFY( tuh_cdc_mounted(dev_addr) ); - TU_VERIFY( p_data != NULL && length); + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return tu_edpt_stream_write_xfer(&p_cdc->stream.tx); +} - uint8_t const ep_out = cdch_data[dev_addr-1].ep_out; - if ( usbh_edpt_busy(dev_addr, ep_out) ) return false; +bool tuh_cdc_write_clear(uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); - return usbh_edpt_xfer(dev_addr, ep_out, (void*)(uintptr_t) p_data, (uint16_t) length); + return tu_edpt_stream_clear(&p_cdc->stream.tx); } -bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify) +uint32_t tuh_cdc_write_available(uint8_t idx) { - (void) is_notify; - TU_VERIFY( tuh_cdc_mounted(dev_addr) ); - TU_VERIFY( p_buffer != NULL && length ); + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return tu_edpt_stream_write_available(&p_cdc->stream.tx); +} + +//--------------------------------------------------------------------+ +// Read +//--------------------------------------------------------------------+ - uint8_t const ep_in = cdch_data[dev_addr-1].ep_in; - if ( usbh_edpt_busy(dev_addr, ep_in) ) return false; +uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); - return usbh_edpt_xfer(dev_addr, ep_in, p_buffer, (uint16_t) length); + return tu_edpt_stream_read(&p_cdc->stream.rx, buffer, bufsize); } -bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb) +uint32_t tuh_cdc_read_available(uint8_t idx) { - cdch_data_t const * p_cdc = get_itf(dev_addr); + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); - tusb_control_request_t const request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, - .wValue = tu_htole16((uint16_t) ((dtr ? 1u : 0u) | (rts ? 2u : 0u))), - .wIndex = tu_htole16(p_cdc->itf_num), - .wLength = 0 - }; + return tu_edpt_stream_read_available(&p_cdc->stream.rx); +} + +bool tuh_cdc_peek(uint8_t idx, uint8_t* ch) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return tu_edpt_stream_peek(&p_cdc->stream.rx, ch); +} + +bool tuh_cdc_read_clear (uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); - tuh_xfer_t xfer = + bool ret = tu_edpt_stream_clear(&p_cdc->stream.rx); + tu_edpt_stream_read_xfer(&p_cdc->stream.rx); + return ret; +} + +//--------------------------------------------------------------------+ +// Control Endpoint API +//--------------------------------------------------------------------+ + +// internal control complete to update state such as line state, encoding +static void cdch_internal_control_complete(tuh_xfer_t* xfer) +{ + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t* p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); + + if (xfer->result == XFER_RESULT_SUCCESS) { - .daddr = dev_addr, - .ep_addr = 0, - .setup = &request, - .buffer = NULL, - .complete_cb = complete_cb, - .user_data = 0 - }; + switch (p_cdc->serial_drid) { + case SERIAL_DRIVER_ACM: + switch (xfer->setup->bRequest) { + case CDC_REQUEST_SET_CONTROL_LINE_STATE: + p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + break; - return tuh_control_xfer(&xfer); + case CDC_REQUEST_SET_LINE_CODING: { + uint16_t const len = tu_min16(sizeof(cdc_line_coding_t), tu_le16toh(xfer->setup->wLength)); + memcpy(&p_cdc->line_coding, xfer->buffer, len); + } + break; + + default: break; + } + break; + + #if CFG_TUH_CDC_FTDI + case SERIAL_DRIVER_FTDI: + switch (xfer->setup->bRequest) { + case FTDI_SIO_MODEM_CTRL: + p_cdc->line_state = (uint8_t) (tu_le16toh(xfer->setup->wValue) & 0x00ff); + break; + + case FTDI_SIO_SET_BAUD_RATE: + // convert from divisor to baudrate is not supported + p_cdc->line_coding.bit_rate = _ftdi_requested_baud; + break; + + default: break; + } + break; + #endif + + #if CFG_TUH_CDC_CP210X + case SERIAL_DRIVER_CP210X: + switch(xfer->setup->bRequest) { + case CP210X_SET_MHS: + p_cdc->line_state = (uint8_t) (tu_le16toh(xfer->setup->wValue) & 0x00ff); + break; + + case CP210X_SET_BAUDRATE: { + uint32_t baudrate; + memcpy(&baudrate, xfer->buffer, sizeof(uint32_t)); + p_cdc->line_coding.bit_rate = tu_le32toh(baudrate); + } + break; + } + break; + #endif + + default: break; + } + } + + xfer->complete_cb = p_cdc->user_control_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } +} + +bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + + if ( complete_cb ) { + return driver->set_control_line_state(p_cdc, line_state, complete_cb, user_data); + }else { + // blocking + xfer_result_t result = XFER_RESULT_INVALID; + bool ret = driver->set_control_line_state(p_cdc, line_state, complete_cb, (uintptr_t) &result); + + if (user_data) { + // user_data is not NULL, return result via user_data + *((xfer_result_t*) user_data) = result; + } + + TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); + + p_cdc->line_state = (uint8_t) line_state; + return true; + } +} + +bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + + if ( complete_cb ) { + return driver->set_baudrate(p_cdc, baudrate, complete_cb, user_data); + }else { + // blocking + xfer_result_t result = XFER_RESULT_INVALID; + bool ret = driver->set_baudrate(p_cdc, baudrate, complete_cb, (uintptr_t) &result); + + if (user_data) { + // user_data is not NULL, return result via user_data + *((xfer_result_t*) user_data) = result; + } + + TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); + + p_cdc->line_coding.bit_rate = baudrate; + return true; + } +} + +bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + cdch_interface_t* p_cdc = get_itf(idx); + // only ACM support this set line coding request + TU_VERIFY(p_cdc && p_cdc->serial_drid == SERIAL_DRIVER_ACM); + TU_VERIFY(p_cdc->acm_capability.support_line_request); + + if ( complete_cb ) { + return acm_set_line_coding(p_cdc, line_coding, complete_cb, user_data); + }else { + // blocking + xfer_result_t result = XFER_RESULT_INVALID; + bool ret = acm_set_line_coding(p_cdc, line_coding, complete_cb, (uintptr_t) &result); + + if (user_data) { + // user_data is not NULL, return result via user_data + *((xfer_result_t*) user_data) = result; + } + + TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); + + p_cdc->line_coding = *line_coding; + return true; + } } //--------------------------------------------------------------------+ -// USBH-CLASS DRIVER API +// CLASS-USBH API //--------------------------------------------------------------------+ + void cdch_init(void) { tu_memclr(cdch_data, sizeof(cdch_data)); + + for(size_t i=0; istream.tx, true, true, false, + p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, + p_cdc->stream.tx_ep_buf, CFG_TUH_CDC_TX_EPSIZE); + + tu_edpt_stream_init(&p_cdc->stream.rx, true, false, false, + p_cdc->stream.rx_ff_buf, CFG_TUH_CDC_RX_BUFSIZE, + p_cdc->stream.rx_ep_buf, CFG_TUH_CDC_RX_EPSIZE); + } } -bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) +void cdch_close(uint8_t daddr) +{ + for(uint8_t idx=0; idxdaddr == daddr) + { + // Invoke application callback + if (tuh_cdc_umount_cb) tuh_cdc_umount_cb(idx); + + //tu_memclr(p_cdc, sizeof(cdch_interface_t)); + p_cdc->daddr = 0; + p_cdc->bInterfaceNumber = 0; + tu_edpt_stream_close(&p_cdc->stream.tx); + tu_edpt_stream_close(&p_cdc->stream.rx); + } + } +} + +bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +{ + // TODO handle stall response, retry failed transfer ... + TU_ASSERT(event == XFER_RESULT_SUCCESS); + + uint8_t const idx = get_idx_by_ep_addr(daddr, ep_addr); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc); + + if ( ep_addr == p_cdc->stream.tx.ep_addr ) + { + // invoke tx complete callback to possibly refill tx fifo + if (tuh_cdc_tx_complete_cb) tuh_cdc_tx_complete_cb(idx); + + if ( 0 == tu_edpt_stream_write_xfer(&p_cdc->stream.tx) ) + { + // If there is no data left, a ZLP should be sent if: + // - xferred_bytes is multiple of EP Packet size and not zero + tu_edpt_stream_write_zlp_if_needed(&p_cdc->stream.tx, xferred_bytes); + } + } + else if ( ep_addr == p_cdc->stream.rx.ep_addr ) + { + tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); + + #if CFG_TUH_CDC_FTDI + // FTDI reserve 2 bytes for status + if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI) { + uint8_t status[2]; + tu_edpt_stream_read(&p_cdc->stream.rx, status, 2); + (void) status; // TODO handle status + } + #endif + + // invoke receive callback + if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(idx); + + // prepare for next transfer if needed + tu_edpt_stream_read_xfer(&p_cdc->stream.rx); + }else if ( ep_addr == p_cdc->ep_notif ) + { + // TODO handle notification endpoint + }else + { + TU_ASSERT(false); + } + + return true; +} + +//--------------------------------------------------------------------+ +// Enumeration +//--------------------------------------------------------------------+ + +static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); + +static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t const *desc_ep) +{ + for(size_t i=0; i<2; i++) + { + TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && + TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); + + TU_ASSERT(tuh_edpt_open(p_cdc->daddr, desc_ep)); + + if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) + { + tu_edpt_stream_open(&p_cdc->stream.rx, p_cdc->daddr, desc_ep); + }else + { + tu_edpt_stream_open(&p_cdc->stream.tx, p_cdc->daddr, desc_ep); + } + + desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(desc_ep); + } + + return true; +} + +bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { (void) rhport; - (void) max_len; // Only support ACM subclass - // Protocol 0xFF can be RNDIS device for windows XP - TU_VERIFY( TUSB_CLASS_CDC == itf_desc->bInterfaceClass && - CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass && - 0xFF != itf_desc->bInterfaceProtocol); + // Note: Protocol 0xFF can be RNDIS device + if ( TUSB_CLASS_CDC == itf_desc->bInterfaceClass && + CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) + { + return acm_open(daddr, itf_desc, max_len); + } + #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X + else if ( 0xff == itf_desc->bInterfaceClass ) + { + uint16_t vid, pid; + TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); + + #if CFG_TUH_CDC_FTDI + if (TU_FTDI_VID == vid) { + for (size_t i = 0; i < FTDI_PID_COUNT; i++) { + if (ftdi_pids[i] == pid) { + return ftdi_open(daddr, itf_desc, max_len); + } + } + } + #endif + + #if CFG_TUH_CDC_CP210X + if (TU_CP210X_VID == vid) { + for (size_t i = 0; i < CP210X_PID_COUNT; i++) { + if (cp210x_pids[i] == pid) { + return cp210x_open(daddr, itf_desc, max_len); + } + } + } + #endif + } + #endif + + return false; +} + +static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num) { + if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); + + // Prepare for incoming data + tu_edpt_stream_read_xfer(&p_cdc->stream.rx); + + // notify usbh that driver enumeration is complete + usbh_driver_set_config_complete(p_cdc->daddr, itf_num); +} + + +bool cdch_set_config(uint8_t daddr, uint8_t itf_num) +{ + tusb_control_request_t request; + request.wIndex = tu_htole16((uint16_t) itf_num); - cdch_data_t * p_cdc = get_itf(dev_addr); + // fake transfer to kick-off process + tuh_xfer_t xfer; + xfer.daddr = daddr; + xfer.result = XFER_RESULT_SUCCESS; + xfer.setup = &request; + xfer.user_data = 0; // initial state - p_cdc->itf_num = itf_desc->bInterfaceNumber; - p_cdc->itf_protocol = itf_desc->bInterfaceProtocol; + uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - //------------- Communication Interface -------------// - uint16_t drv_len = tu_desc_len(itf_desc); + serial_drivers[p_cdc->serial_drid].process_set_config(&xfer); + return true; +} + +//--------------------------------------------------------------------+ +// ACM +//--------------------------------------------------------------------+ + +enum { + CONFIG_ACM_SET_CONTROL_LINE_STATE = 0, + CONFIG_ACM_SET_LINE_CODING, + CONFIG_ACM_COMPLETE, +}; + +static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) +{ + uint8_t const * p_desc_end = ((uint8_t const*) itf_desc) + max_len; + + cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + TU_VERIFY(p_cdc); + + p_cdc->serial_drid = SERIAL_DRIVER_ACM; + + //------------- Control Interface -------------// uint8_t const * p_desc = tu_desc_next(itf_desc); // Communication Functional Descriptors - while( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) + while( (p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc)) ) { if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) ) { @@ -188,19 +732,18 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities; } - drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); } - if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + // Open notification endpoint of control interface if any + if (itf_desc->bNumEndpoints == 1) { - // notification endpoint + TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)); tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; - TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) ); + TU_ASSERT( tuh_edpt_open(daddr, desc_ep) ); p_cdc->ep_notif = desc_ep->bEndpointAddress; - drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); } @@ -209,52 +752,426 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) { // next to endpoint descriptor - drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); // data endpoints expected to be in pairs - for(uint32_t i=0; i<2; i++) - { - tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; - TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); + TU_ASSERT(open_ep_stream_pair(p_cdc, (tusb_desc_endpoint_t const *) p_desc)); + } + + return true; +} - TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); +static void acm_process_config(tuh_xfer_t* xfer) +{ + uintptr_t const state = xfer->user_data; + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); - if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) + switch(state) + { + case CONFIG_ACM_SET_CONTROL_LINE_STATE: + #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + if (p_cdc->acm_capability.support_line_request) { - p_cdc->ep_in = desc_ep->bEndpointAddress; - }else + TU_ASSERT(acm_set_control_line_state(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, acm_process_config, + CONFIG_ACM_SET_LINE_CODING), ); + break; + } + #endif + TU_ATTR_FALLTHROUGH; + + case CONFIG_ACM_SET_LINE_CODING: + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + if (p_cdc->acm_capability.support_line_request) { - p_cdc->ep_out = desc_ep->bEndpointAddress; + cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT(acm_set_line_coding(p_cdc, &line_coding, acm_process_config, CONFIG_ACM_COMPLETE), ); + break; } + #endif + TU_ATTR_FALLTHROUGH; - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next( p_desc ); - } + case CONFIG_ACM_COMPLETE: + // itf_num+1 to account for data interface as well + set_config_complete(p_cdc, idx, itf_num+1); + break; + + default: break; } +} + +static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_VERIFY(p_cdc->acm_capability.support_line_request); + TU_LOG_CDCH("CDC ACM Set Control Line State\r\n"); + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, + .wValue = tu_htole16(line_state), + .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), + .wLength = 0 + }; + + p_cdc->user_control_cb = complete_cb; + + tuh_xfer_t xfer = { + .daddr = p_cdc->daddr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call + .user_data = user_data + }; + + TU_ASSERT(tuh_control_xfer(&xfer)); return true; } -bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num) +static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_LOG_CDCH("CDC ACM Set Line Conding\r\n"); + + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = CDC_REQUEST_SET_LINE_CODING, + .wValue = 0, + .wIndex = tu_htole16(p_cdc->bInterfaceNumber), + .wLength = tu_htole16(sizeof(cdc_line_coding_t)) + }; + + // use usbh enum buf to hold line coding since user line_coding variable does not live long enough + uint8_t* enum_buf = usbh_get_enum_buf(); + memcpy(enum_buf, line_coding, sizeof(cdc_line_coding_t)); + + p_cdc->user_control_cb = complete_cb; + tuh_xfer_t xfer = { + .daddr = p_cdc->daddr, + .ep_addr = 0, + .setup = &request, + .buffer = enum_buf, + .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call + .user_data = user_data + }; + + TU_ASSERT(tuh_control_xfer(&xfer)); + return true; +} + +static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_VERIFY(p_cdc->acm_capability.support_line_request); + cdc_line_coding_t line_coding = p_cdc->line_coding; + line_coding.bit_rate = baudrate; + return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data); +} + +//--------------------------------------------------------------------+ +// FTDI +//--------------------------------------------------------------------+ +#if CFG_TUH_CDC_FTDI + +enum { + CONFIG_FTDI_RESET = 0, + CONFIG_FTDI_MODEM_CTRL, + CONFIG_FTDI_SET_BAUDRATE, + CONFIG_FTDI_SET_DATA, + CONFIG_FTDI_COMPLETE +}; + +static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) { + // FTDI Interface includes 1 vendor interface + 2 bulk endpoints + TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff && itf_desc->bNumEndpoints == 2); + TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); + + cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + TU_VERIFY(p_cdc); + + TU_LOG_CDCH("FTDI opened\r\n"); + + p_cdc->serial_drid = SERIAL_DRIVER_FTDI; + + // endpoint pair + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); + + // data endpoints expected to be in pairs + return open_ep_stream_pair(p_cdc, desc_ep); +} + +// set request without data +static bool ftdi_sio_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_VENDOR, + .direction = TUSB_DIR_OUT + }, + .bRequest = command, + .wValue = tu_htole16(value), + .wIndex = 0, + .wLength = 0 + }; + + tuh_xfer_t xfer = { + .daddr = p_cdc->daddr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb, + .user_data = user_data + }; + + return tuh_control_xfer(&xfer); +} + +static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data); +} + +static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - (void) dev_addr; (void) itf_num; + TU_LOG_CDCH("CDC FTDI Set Control Line State\r\n"); + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | line_state, + complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } -bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) { - (void) ep_addr; - tuh_cdc_xfer_isr( dev_addr, event, 0, xferred_bytes ); + const uint8_t divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; + uint32_t divisor; + + /* divisor shifted 3 bits to the left */ + uint32_t divisor3 = base / (2 * baud); + divisor = (divisor3 >> 3); + divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14; + + /* Deal with special cases for highest baud rates. */ + if (divisor == 1) { /* 1.0 */ + divisor = 0; + } + else if (divisor == 0x4001) { /* 1.5 */ + divisor = 1; + } + + return divisor; +} + +static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) +{ + return ftdi_232bm_baud_base_to_divisor(baud, 48000000u); +} + +static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate); + TU_LOG_CDCH("CDC FTDI Set BaudRate = %lu, divisor = 0x%04x\n", baudrate, divisor); + + p_cdc->user_control_cb = complete_cb; + _ftdi_requested_baud = baudrate; + TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor, + complete_cb ? cdch_internal_control_complete : NULL, user_data)); + return true; } -void cdch_close(uint8_t dev_addr) +static void ftdi_process_config(tuh_xfer_t* xfer) { + uintptr_t const state = xfer->user_data; + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); + + switch(state) { + // Note may need to read FTDI eeprom + case CONFIG_FTDI_RESET: + TU_ASSERT(ftdi_sio_reset(p_cdc, ftdi_process_config, CONFIG_FTDI_MODEM_CTRL),); + break; + + case CONFIG_FTDI_MODEM_CTRL: + #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + TU_ASSERT( + ftdi_sio_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + + case CONFIG_FTDI_SET_BAUDRATE: { + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT(ftdi_sio_set_baudrate(p_cdc, line_coding.bit_rate, ftdi_process_config, CONFIG_FTDI_SET_DATA),); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + } + + case CONFIG_FTDI_SET_DATA: { + #if 0 // TODO set data format + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT(ftdi_sio_set_data(p_cdc, process_ftdi_config, CONFIG_FTDI_COMPLETE),); + break; + #endif + #endif + + TU_ATTR_FALLTHROUGH; + } + + case CONFIG_FTDI_COMPLETE: + set_config_complete(p_cdc, idx, itf_num); + break; + + default: + break; + } +} + +#endif + +//--------------------------------------------------------------------+ +// CP210x +//--------------------------------------------------------------------+ + +#if CFG_TUH_CDC_CP210X + +enum { + CONFIG_CP210X_IFC_ENABLE = 0, + CONFIG_CP210X_SET_BAUDRATE, + CONFIG_CP210X_SET_LINE_CTL, + CONFIG_CP210X_SET_DTR_RTS, + CONFIG_CP210X_COMPLETE +}; + +static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { + // CP210x Interface includes 1 vendor interface + 2 bulk endpoints + TU_VERIFY(itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0 && itf_desc->bNumEndpoints == 2); + TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); + + cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + TU_VERIFY(p_cdc); + + TU_LOG_CDCH("CP210x opened\r\n"); + p_cdc->serial_drid = SERIAL_DRIVER_CP210X; + + // endpoint pair + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); + + // data endpoints expected to be in pairs + return open_ep_stream_pair(p_cdc, desc_ep); +} + +static bool cp210x_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_VENDOR, + .direction = TUSB_DIR_OUT + }, + .bRequest = command, + .wValue = tu_htole16(value), + .wIndex = p_cdc->bInterfaceNumber, + .wLength = tu_htole16(length) + }; + + // use usbh enum buf since application variable does not live long enough + uint8_t* enum_buf = NULL; + + if (buffer && length > 0) { + enum_buf = usbh_get_enum_buf(); + tu_memcpy_s(enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length); + } + + tuh_xfer_t xfer = { + .daddr = p_cdc->daddr, + .ep_addr = 0, + .setup = &request, + .buffer = enum_buf, + .complete_cb = complete_cb, + .user_data = user_data + }; + + return tuh_control_xfer(&xfer); +} + +static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + return cp210x_set_request(p_cdc, CP210X_IFC_ENABLE, enabled, NULL, 0, complete_cb, user_data); +} + +static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_LOG_CDCH("CDC CP210x Set BaudRate = %lu\n", baudrate); + uint32_t baud_le = tu_htole32(baudrate); + p_cdc->user_control_cb = complete_cb; + return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, + complete_cb ? cdch_internal_control_complete : NULL, user_data); +} + +static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); + TU_LOG_CDCH("CDC CP210x Set Control Line State\r\n"); + p_cdc->user_control_cb = complete_cb; + return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | line_state, NULL, 0, + complete_cb ? cdch_internal_control_complete : NULL, user_data); +} - cdch_data_t * p_cdc = get_itf(dev_addr); - tu_memclr(p_cdc, sizeof(cdch_data_t)); +static void cp210x_process_config(tuh_xfer_t* xfer) { + uintptr_t const state = xfer->user_data; + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); + + switch (state) { + case CONFIG_CP210X_IFC_ENABLE: + TU_ASSERT(cp210x_ifc_enable(p_cdc, 1, cp210x_process_config, CONFIG_CP210X_SET_BAUDRATE),); + break; + + case CONFIG_CP210X_SET_BAUDRATE: { + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT(cp210x_set_baudrate(p_cdc, line_coding.bit_rate, cp210x_process_config, CONFIG_CP210X_SET_LINE_CTL),); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + } + + case CONFIG_CP210X_SET_LINE_CTL: { + #if defined(CFG_TUH_CDC_LINE_CODING_ON_ENUM) && 0 // skip for now + cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + } + + case CONFIG_CP210X_SET_DTR_RTS: + #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + TU_ASSERT( + cp210x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, cp210x_process_config, CONFIG_CP210X_COMPLETE),); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + + case CONFIG_CP210X_COMPLETE: + set_config_complete(p_cdc, idx, itf_num); + break; + + default: break; + } } #endif + +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.h b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.h index 33dbd2ef..19552f1e 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -34,89 +34,159 @@ #endif //--------------------------------------------------------------------+ -// CDC APPLICATION PUBLIC API +// Class Driver Configuration //--------------------------------------------------------------------+ -/** \ingroup ClassDriver_CDC Communication Device Class (CDC) - * \addtogroup CDC_Serial Serial - * @{ - * \defgroup CDC_Serial_Host Host - * @{ */ -bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb); +// Set Line Control state on enumeration/mounted: DTR ( bit 0), RTS (bit 1) +#ifndef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM +#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0 +#endif + +// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t +//#ifndef CFG_TUH_CDC_LINE_CODING_ON_ENUM +//#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } +//#endif + +// RX FIFO size +#ifndef CFG_TUH_CDC_RX_BUFSIZE +#define CFG_TUH_CDC_RX_BUFSIZE USBH_EPSIZE_BULK_MAX +#endif + +// RX Endpoint size +#ifndef CFG_TUH_CDC_RX_EPSIZE +#define CFG_TUH_CDC_RX_EPSIZE USBH_EPSIZE_BULK_MAX +#endif + +// TX FIFO size +#ifndef CFG_TUH_CDC_TX_BUFSIZE +#define CFG_TUH_CDC_TX_BUFSIZE USBH_EPSIZE_BULK_MAX +#endif + +// TX Endpoint size +#ifndef CFG_TUH_CDC_TX_EPSIZE +#define CFG_TUH_CDC_TX_EPSIZE USBH_EPSIZE_BULK_MAX +#endif + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ -static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb) +// Get Interface index from device address + interface number +// return TUSB_INDEX_INVALID_8 (0xFF) if not found +uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num); + +// Get Interface information +// return true if index is correct and interface is currently mounted +bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info); + +// Check if a interface is mounted +bool tuh_cdc_mounted(uint8_t idx); + +// Get current DTR status +bool tuh_cdc_get_dtr(uint8_t idx); + +// Get current RTS status +bool tuh_cdc_get_rts(uint8_t idx); + +// Check if interface is connected (DTR active) +TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) { - return tuh_cdc_set_control_line_state(dev_addr, true, true, complete_cb); + return tuh_cdc_get_dtr(idx); } -static inline bool tuh_cdc_disconnect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb) +// Get local (saved/cached) version of line coding. +// This function should return correct values if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding() +// are invoked previously or CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined. +// NOTE: This function does not make any USB transfer request to device. +bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding); + +//--------------------------------------------------------------------+ +// Write API +//--------------------------------------------------------------------+ + +// Get the number of bytes available for writing +uint32_t tuh_cdc_write_available(uint8_t idx); + +// Write to cdc interface +uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize); + +// Force sending data if possible, return number of forced bytes +uint32_t tuh_cdc_write_flush(uint8_t idx); + +// Clear the transmit FIFO +bool tuh_cdc_write_clear(uint8_t idx); + +//--------------------------------------------------------------------+ +// Read API +//--------------------------------------------------------------------+ + +// Get the number of bytes available for reading +uint32_t tuh_cdc_read_available(uint8_t idx); + +// Read from cdc interface +uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize); + +// Get a byte from RX FIFO without removing it +bool tuh_cdc_peek(uint8_t idx, uint8_t* ch); + +// Clear the received FIFO +bool tuh_cdc_read_clear (uint8_t idx); + +//--------------------------------------------------------------------+ +// Control Endpoint (Request) API +// Each Function will make a USB control transfer request to/from device +// - If complete_cb is provided, the function will return immediately and invoke +// the callback when request is complete. +// - If complete_cb is NULL, the function will block until request is complete. +// - In this case, user_data should be pointed to xfer_result_t to hold the transfer result. +// - The function will return true if transfer is successful, false otherwise. +//--------------------------------------------------------------------+ + +// Request to Set Control Line State: DTR (bit 0), RTS (bit 1) +bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + +// Request to set baudrate +bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + +// Request to Set Line Coding (ACM only) +// Should only use if you don't work with serial devices such as FTDI/CP210x +bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + +// Request to Get Line Coding (ACM only) +// Should only use if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding() never got invoked and +// CFG_TUH_CDC_LINE_CODING_ON_ENUM is not defined +// bool tuh_cdc_get_line_coding(uint8_t idx, cdc_line_coding_t* coding); + +// Connect by set both DTR, RTS +TU_ATTR_ALWAYS_INLINE static inline +bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return tuh_cdc_set_control_line_state(dev_addr, false, false, complete_cb); + return tuh_cdc_set_control_line_state(idx, CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS, complete_cb, user_data); } -/** \brief Check if device support CDC Serial interface or not - * \param[in] dev_addr device address - * \retval true if device supports - * \retval false if device does not support or is not mounted - */ -bool tuh_cdc_serial_is_mounted(uint8_t dev_addr); - -/** \brief Check if the interface is currently busy or not - * \param[in] dev_addr device address - * \param[in] pipeid value from \ref cdc_pipeid_t to indicate target pipe. - * \retval true if the interface is busy, meaning the stack is still transferring/waiting data from/to device - * \retval false if the interface is not busy, meaning the stack successfully transferred data from/to device - * \note This function is used to check if previous transfer is complete (success or error), so that the next transfer - * can be scheduled. User needs to make sure the corresponding interface is mounted - * (by \ref tuh_cdc_serial_is_mounted) before calling this function. - */ -bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid); - -/** \brief Perform USB OUT transfer to device - * \param[in] dev_addr device address - * \param[in] p_data Buffer containing data. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION) - * \param[in] length Number of bytes to be transferred via USB bus - * \retval TUSB_ERROR_NONE on success - * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device - * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request) - * \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct - * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the - * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION. - */ -bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify); - -/** \brief Perform USB IN transfer to get data from device - * \param[in] dev_addr device address - * \param[in] p_buffer Buffer containing received data. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION) - * \param[in] length Number of bytes to be transferred via USB bus - * \retval TUSB_ERROR_NONE on success - * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device - * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request) - * \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct - * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the - * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION. - */ -bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify); +// Disconnect by clear both DTR, RTS +TU_ATTR_ALWAYS_INLINE static inline +bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + return tuh_cdc_set_control_line_state(idx, 0x00, complete_cb, user_data); +} //--------------------------------------------------------------------+ // CDC APPLICATION CALLBACKS //--------------------------------------------------------------------+ -/** \brief Callback function that is invoked when an transferring event occurred - * \param[in] dev_addr Address of device - * \param[in] event an value from \ref xfer_result_t - * \param[in] pipe_id value from \ref cdc_pipeid_t indicate the pipe - * \param[in] xferred_bytes Number of bytes transferred via USB bus - * \note event can be one of following - * - XFER_RESULT_SUCCESS : previously scheduled transfer completes successfully. - * - XFER_RESULT_FAILED : previously scheduled transfer encountered a transaction error. - * - XFER_RESULT_STALLED : previously scheduled transfer is stalled by device. - * \note - */ -void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes); +// Invoked when a device with CDC interface is mounted +// idx is index of cdc interface in the internal pool. +TU_ATTR_WEAK extern void tuh_cdc_mount_cb(uint8_t idx); + +// Invoked when a device with CDC interface is unmounted +TU_ATTR_WEAK extern void tuh_cdc_umount_cb(uint8_t idx); + +// Invoked when received new data +TU_ATTR_WEAK extern void tuh_cdc_rx_cb(uint8_t idx); -/// @} // group CDC_Serial_Host -/// @} +// Invoked when a TX is complete and therefore space becomes available in TX buffer +TU_ATTR_WEAK extern void tuh_cdc_tx_complete_cb(uint8_t idx); //--------------------------------------------------------------------+ // Internal Class Driver API diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis.h b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis.h index e0f129fe..ad153e0a 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c index 8f28f51a..11a5355a 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c +++ b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -50,8 +50,8 @@ //--------------------------------------------------------------------+ #define RNDIS_MSG_PAYLOAD_MAX (1024*4) -CFG_TUSB_MEM_SECTION static uint8_t msg_notification[CFG_TUH_DEVICE_MAX][8]; -CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t msg_payload[RNDIS_MSG_PAYLOAD_MAX]; +CFG_TUH_MEM_SECTION static uint8_t msg_notification[CFG_TUH_DEVICE_MAX][8]; +CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN static uint8_t msg_payload[RNDIS_MSG_PAYLOAD_MAX]; static rndish_data_t rndish_data[CFG_TUH_DEVICE_MAX]; @@ -117,7 +117,7 @@ void rndish_init(void) //------------- Task creation -------------// - //------------- semaphore creation for notificaiton pipe -------------// + //------------- semaphore creation for notification pipe -------------// for(uint8_t i=0; i= 2 -static tu_lookup_entry_t const _dfu_request_lookup[] = +tu_static tu_lookup_entry_t const _dfu_request_lookup[] = { { .key = DFU_REQUEST_DETACH , .data = "DETACH" }, { .key = DFU_REQUEST_DNLOAD , .data = "DNLOAD" }, @@ -85,13 +85,13 @@ static tu_lookup_entry_t const _dfu_request_lookup[] = { .key = DFU_REQUEST_ABORT , .data = "ABORT" }, }; -static tu_lookup_table_t const _dfu_request_table = +tu_static tu_lookup_table_t const _dfu_request_table = { .count = TU_ARRAY_SIZE(_dfu_request_lookup), .items = _dfu_request_lookup }; -static tu_lookup_entry_t const _dfu_state_lookup[] = +tu_static tu_lookup_entry_t const _dfu_state_lookup[] = { { .key = APP_IDLE , .data = "APP_IDLE" }, { .key = APP_DETACH , .data = "APP_DETACH" }, @@ -106,13 +106,13 @@ static tu_lookup_entry_t const _dfu_state_lookup[] = { .key = DFU_ERROR , .data = "ERROR" }, }; -static tu_lookup_table_t const _dfu_state_table = +tu_static tu_lookup_table_t const _dfu_state_table = { .count = TU_ARRAY_SIZE(_dfu_state_lookup), .items = _dfu_state_lookup }; -static tu_lookup_entry_t const _dfu_status_lookup[] = +tu_static tu_lookup_entry_t const _dfu_status_lookup[] = { { .key = DFU_STATUS_OK , .data = "OK" }, { .key = DFU_STATUS_ERR_TARGET , .data = "errTARGET" }, @@ -132,7 +132,7 @@ static tu_lookup_entry_t const _dfu_status_lookup[] = { .key = DFU_STATUS_ERR_STALLEDPKT , .data = "errSTALLEDPKT" }, }; -static tu_lookup_table_t const _dfu_status_table = +tu_static tu_lookup_table_t const _dfu_status_table = { .count = TU_ARRAY_SIZE(_dfu_status_lookup), .items = _dfu_status_lookup diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c index b9cd6096..7b77b3f8 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c +++ b/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c @@ -110,7 +110,7 @@ bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request TU_LOG2(" DFU RT Request: GETSTATUS\r\n"); dfu_status_response_t resp; // Status = OK, Poll timeout is ignored during RT, State = APP_IDLE, IString = 0 - memset(&resp, 0x00, sizeof(dfu_status_response_t)); + TU_VERIFY(tu_memset_s(&resp, sizeof(resp), 0x00, sizeof(resp))==0); tud_control_xfer(rhport, request, &resp, sizeof(dfu_status_response_t)); } break; diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid.h b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid.h index 44a464be..fbd3eef3 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -708,6 +708,7 @@ enum { HID_USAGE_PAGE_MSR = 0x8e, HID_USAGE_PAGE_CAMERA = 0x90, HID_USAGE_PAGE_ARCADE = 0x91, + HID_USAGE_PAGE_FIDO = 0xF1D0, // FIDO alliance HID usage page HID_USAGE_PAGE_VENDOR = 0xFF00 // 0xFF00 - 0xFFFF }; @@ -844,6 +845,14 @@ enum HID_USAGE_CONSUMER_AC_PAN = 0x0238, }; +/// HID Usage Table: FIDO Alliance Page (0xF1D0) +enum +{ + HID_USAGE_FIDO_U2FHID = 0x01, // U2FHID usage for top-level collection + HID_USAGE_FIDO_DATA_IN = 0x20, // Raw IN data report + HID_USAGE_FIDO_DATA_OUT = 0x21 // Raw OUT data report +}; + /*-------------------------------------------------------------------- * ASCII to KEYCODE Conversion * Expand to array of [128][2] (shift, keycode) diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.c index 8077e4de..9240fe2c 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.c +++ b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.c @@ -58,7 +58,7 @@ typedef struct tusb_hid_descriptor_hid_t const * hid_descriptor; } hidd_interface_t; -CFG_TUSB_MEM_SECTION static hidd_interface_t _hidd_itf[CFG_TUD_HID]; +CFG_TUSB_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID]; /*------------- Helpers -------------*/ static inline uint8_t get_index_by_itfnum(uint8_t itf_num) @@ -92,16 +92,12 @@ bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, u // prepare data if (report_id) { - len = tu_min16(len, CFG_TUD_HID_EP_BUFSIZE-1); - p_hid->epin_buf[0] = report_id; - memcpy(p_hid->epin_buf+1, report, len); + TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf+1, CFG_TUD_HID_EP_BUFSIZE-1, report, len)); len++; }else { - // If report id = 0, skip ID field - len = tu_min16(len, CFG_TUD_HID_EP_BUFSIZE); - memcpy(p_hid->epin_buf, report, len); + TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf, CFG_TUD_HID_EP_BUFSIZE, report, len)); } return usbd_edpt_xfer(rhport, p_hid->ep_in, p_hid->epin_buf, len); @@ -126,7 +122,7 @@ bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modi if ( keycode ) { - memcpy(report.keycode, keycode, 6); + memcpy(report.keycode, keycode, sizeof(report.keycode)); }else { tu_memclr(report.keycode, 6); @@ -151,8 +147,7 @@ bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, } bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, - int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) -{ + int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) { hid_gamepad_report_t report = { .x = x, @@ -183,11 +178,12 @@ void hidd_reset(uint8_t rhport) } uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) -{ + { TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0); // len = interface + hid + n*endpoints - uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + + uint16_t const drv_len = + (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); TU_ASSERT(max_len >= drv_len, 0); @@ -403,7 +399,7 @@ bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ { if (tud_hid_report_complete_cb) { - tud_hid_report_complete_cb(instance, p_hid->epin_buf, (/*uint16_t*/ uint8_t) xferred_bytes); + tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t) xferred_bytes); } } // Received report diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.h index 3143b102..17b24def 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.h @@ -116,7 +116,7 @@ TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate); // Invoked when sent REPORT successfully to host // Application can use this to send the next report // Note: For composite reports, report[0] is report ID -TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, /*uint16_t*/ uint8_t len ); +TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len); //--------------------------------------------------------------------+ @@ -182,7 +182,7 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ /* Report ID if any */\ __VA_ARGS__ \ - /* 8 bits Modifier Keys (Shfit, Control, Alt) */ \ + /* 8 bits Modifier Keys (Shift, Control, Alt) */ \ HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\ HID_USAGE_MIN ( 224 ) ,\ HID_USAGE_MAX ( 231 ) ,\ @@ -352,6 +352,31 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ HID_COLLECTION_END \ +// FIDO U2F Authenticator Descriptor Template +// - 1st parameter is report size, which is 64 bytes maximum in U2F +// - 2nd parameter is HID_REPORT_ID(n) (optional) +#define TUD_HID_REPORT_DESC_FIDO_U2F(report_size, ...) \ + HID_USAGE_PAGE_N ( HID_USAGE_PAGE_FIDO, 2 ) ,\ + HID_USAGE ( HID_USAGE_FIDO_U2FHID ) ,\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */ \ + __VA_ARGS__ \ + /* Usage Data In */ \ + HID_USAGE ( HID_USAGE_FIDO_DATA_IN ) ,\ + HID_LOGICAL_MIN ( 0 ) ,\ + HID_LOGICAL_MAX_N ( 0xff, 2 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_REPORT_COUNT ( report_size ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + /* Usage Data Out */ \ + HID_USAGE ( HID_USAGE_FIDO_DATA_OUT ) ,\ + HID_LOGICAL_MIN ( 0 ) ,\ + HID_LOGICAL_MAX_N ( 0xff, 2 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_REPORT_COUNT ( report_size ) ,\ + HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + HID_COLLECTION_END \ + // HID Generic Input & Output // - 1st parameter is report size (mandatory) // - 2nd parameter is report id HID_REPORT_ID(n) (optional) diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.c b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.c index ca745464..d95d3ef3 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.c +++ b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -39,6 +39,8 @@ typedef struct { + uint8_t daddr; + uint8_t itf_num; uint8_t ep_in; uint8_t ep_out; @@ -52,77 +54,158 @@ typedef struct uint16_t epin_size; uint16_t epout_size; - uint8_t epin_buf[CFG_TUH_HID_EPIN_BUFSIZE]; - uint8_t epout_buf[CFG_TUH_HID_EPOUT_BUFSIZE]; + CFG_TUH_MEM_ALIGN uint8_t epin_buf[CFG_TUH_HID_EPIN_BUFSIZE]; + CFG_TUH_MEM_ALIGN uint8_t epout_buf[CFG_TUH_HID_EPOUT_BUFSIZE]; } hidh_interface_t; -typedef struct +CFG_TUH_MEM_SECTION +tu_static hidh_interface_t _hidh_itf[CFG_TUH_HID]; + +//--------------------------------------------------------------------+ +// Helper +//--------------------------------------------------------------------+ + +TU_ATTR_ALWAYS_INLINE static inline +hidh_interface_t* get_hid_itf(uint8_t daddr, uint8_t idx) { - uint8_t inst_count; - hidh_interface_t instances[CFG_TUH_HID]; -} hidh_device_t; + TU_ASSERT(daddr && idx < CFG_TUH_HID, NULL); + hidh_interface_t* p_hid = &_hidh_itf[idx]; + return (p_hid->daddr == daddr) ? p_hid : NULL; +} -static hidh_device_t _hidh_dev[CFG_TUH_DEVICE_MAX]; +// Get instance ID by endpoint address +static uint8_t get_idx_by_epaddr(uint8_t daddr, uint8_t ep_addr) +{ + for ( uint8_t idx = 0; idx < CFG_TUH_HID; idx++ ) + { + hidh_interface_t const * p_hid = &_hidh_itf[idx]; -//------------- Internal prototypes -------------// + if ( p_hid->daddr == daddr && + (p_hid->ep_in == ep_addr || p_hid->ep_out == ep_addr) ) + { + return idx; + } + } -// Get HID device & interface -TU_ATTR_ALWAYS_INLINE static inline hidh_device_t* get_dev(uint8_t dev_addr); -TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_instance(uint8_t dev_addr, uint8_t instance); -static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf); -static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr); + return TUSB_INDEX_INVALID_8; +} + +static hidh_interface_t* find_new_itf(void) +{ + for(uint8_t i=0; iinst_count; + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + return p_hid != NULL; +} + +bool tuh_hid_itf_get_info(uint8_t daddr, uint8_t idx, tuh_itf_info_t* info) +{ + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid && info); + + info->daddr = daddr; + + // re-construct descriptor + tusb_desc_interface_t* desc = &info->desc; + desc->bLength = sizeof(tusb_desc_interface_t); + desc->bDescriptorType = TUSB_DESC_INTERFACE; + + desc->bInterfaceNumber = p_hid->itf_num; + desc->bAlternateSetting = 0; + desc->bNumEndpoints = (uint8_t) ((p_hid->ep_in ? 1u : 0u) + (p_hid->ep_out ? 1u : 0u)); + desc->bInterfaceClass = TUSB_CLASS_HID; + desc->bInterfaceSubClass = (p_hid->itf_protocol ? HID_SUBCLASS_BOOT : HID_SUBCLASS_NONE); + desc->bInterfaceProtocol = p_hid->itf_protocol; + desc->iInterface = 0; // not used yet + + return true; } -bool tuh_hid_mounted(uint8_t dev_addr, uint8_t instance) +uint8_t tuh_hid_itf_get_index(uint8_t daddr, uint8_t itf_num) { - hidh_interface_t* hid_itf = get_instance(dev_addr, instance); - return (hid_itf->ep_in != 0) || (hid_itf->ep_out != 0); + for ( uint8_t idx = 0; idx < CFG_TUH_HID; idx++ ) + { + hidh_interface_t const * p_hid = &_hidh_itf[idx]; + + if ( p_hid->daddr == daddr && p_hid->itf_num == itf_num) return idx; + } + + return TUSB_INDEX_INVALID_8; } -uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance) +uint8_t tuh_hid_interface_protocol(uint8_t daddr, uint8_t idx) { - hidh_interface_t* hid_itf = get_instance(dev_addr, instance); - return hid_itf->itf_protocol; + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + return p_hid ? p_hid->itf_protocol : 0; } //--------------------------------------------------------------------+ // Control Endpoint API //--------------------------------------------------------------------+ -uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance) +uint8_t tuh_hid_get_protocol(uint8_t daddr, uint8_t idx) { - hidh_interface_t* hid_itf = get_instance(dev_addr, instance); - return hid_itf->protocol_mode; + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + return p_hid ? p_hid->protocol_mode : 0; } static void set_protocol_complete(tuh_xfer_t* xfer) { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const daddr = xfer->daddr; - uint8_t const instance = get_instance_id_by_itfnum(daddr, itf_num); - hidh_interface_t* hid_itf = get_instance(daddr, instance); + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const daddr = xfer->daddr; + uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num); + + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid, ); if (XFER_RESULT_SUCCESS == xfer->result) { - hid_itf->protocol_mode = (uint8_t) tu_le16toh(xfer->setup->wValue); + p_hid->protocol_mode = (uint8_t) tu_le16toh(xfer->setup->wValue); } if (tuh_hid_set_protocol_complete_cb) { - tuh_hid_set_protocol_complete_cb(daddr, instance, hid_itf->protocol_mode); + tuh_hid_set_protocol_complete_cb(daddr, idx, p_hid->protocol_mode); } } - -static bool _hidh_set_protocol(uint8_t dev_addr, uint8_t itf_num, uint8_t protocol, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +static bool _hidh_set_protocol(uint8_t daddr, uint8_t itf_num, uint8_t protocol, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG2("HID Set Protocol = %d\r\n", protocol); @@ -142,7 +225,7 @@ static bool _hidh_set_protocol(uint8_t dev_addr, uint8_t itf_num, uint8_t protoc tuh_xfer_t xfer = { - .daddr = dev_addr, + .daddr = daddr, .ep_addr = 0, .setup = &request, .buffer = NULL, @@ -150,16 +233,15 @@ static bool _hidh_set_protocol(uint8_t dev_addr, uint8_t itf_num, uint8_t protoc .user_data = user_data }; - TU_ASSERT( tuh_control_xfer(&xfer) ); - return true; + return tuh_control_xfer(&xfer); } -bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol) +bool tuh_hid_set_protocol(uint8_t daddr, uint8_t idx, uint8_t protocol) { - hidh_interface_t* hid_itf = get_instance(dev_addr, instance); - TU_VERIFY(hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE); + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid && p_hid->itf_protocol != HID_ITF_PROTOCOL_NONE); - return _hidh_set_protocol(dev_addr, hid_itf->itf_num, protocol, set_protocol_complete, 0); + return _hidh_set_protocol(daddr, p_hid->itf_num, protocol, set_protocol_complete, 0); } static void set_report_complete(tuh_xfer_t* xfer) @@ -168,20 +250,22 @@ static void set_report_complete(tuh_xfer_t* xfer) if (tuh_hid_set_report_complete_cb) { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const instance = get_instance_id_by_itfnum(xfer->daddr, itf_num); + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num); uint8_t const report_type = tu_u16_high(xfer->setup->wValue); uint8_t const report_id = tu_u16_low(xfer->setup->wValue); - tuh_hid_set_report_complete_cb(xfer->daddr, instance, report_id, report_type, + tuh_hid_set_report_complete_cb(xfer->daddr, idx, report_id, report_type, (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0); } } -bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) +bool tuh_hid_set_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) { - hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid); + TU_LOG2("HID Set Report: id = %u, type = %u, len = %u\r\n", report_id, report_type, len); tusb_control_request_t const request = @@ -193,14 +277,14 @@ bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, u .direction = TUSB_DIR_OUT }, .bRequest = HID_REQ_CONTROL_SET_REPORT, - .wValue = tu_u16(report_type, report_id), - .wIndex = hid_itf->itf_num, + .wValue = tu_htole16(tu_u16(report_type, report_id)), + .wIndex = tu_htole16((uint16_t)p_hid->itf_num), .wLength = len }; tuh_xfer_t xfer = { - .daddr = dev_addr, + .daddr = daddr, .ep_addr = 0, .setup = &request, .buffer = report, @@ -208,14 +292,14 @@ bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, u .user_data = 0 }; - TU_ASSERT( tuh_control_xfer(&xfer) ); - return true; + return tuh_control_xfer(&xfer); } -static bool _hidh_set_idle(uint8_t dev_addr, uint8_t itf_num, uint16_t idle_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +static bool _hidh_set_idle(uint8_t daddr, uint8_t itf_num, uint16_t idle_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // SET IDLE request, device can stall if not support this request TU_LOG2("HID Set Idle \r\n"); + tusb_control_request_t const request = { .bmRequestType_bit = @@ -225,14 +309,14 @@ static bool _hidh_set_idle(uint8_t dev_addr, uint8_t itf_num, uint16_t idle_rate .direction = TUSB_DIR_OUT }, .bRequest = HID_REQ_CONTROL_SET_IDLE, - .wValue = idle_rate, - .wIndex = itf_num, + .wValue = tu_htole16(idle_rate), + .wIndex = tu_htole16((uint16_t)itf_num), .wLength = 0 }; tuh_xfer_t xfer = { - .daddr = dev_addr, + .daddr = daddr, .ep_addr = 0, .setup = &request, .buffer = NULL, @@ -240,96 +324,148 @@ static bool _hidh_set_idle(uint8_t dev_addr, uint8_t itf_num, uint16_t idle_rate .user_data = user_data }; - TU_ASSERT( tuh_control_xfer(&xfer) ); - - return true; + return tuh_control_xfer(&xfer); } //--------------------------------------------------------------------+ // Interrupt Endpoint API //--------------------------------------------------------------------+ -bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance) +// Check if HID interface is ready to receive report +bool tuh_hid_receive_ready(uint8_t dev_addr, uint8_t idx) +{ + hidh_interface_t* p_hid = get_hid_itf(dev_addr, idx); + TU_VERIFY(p_hid); + + return !usbh_edpt_busy(dev_addr, p_hid->ep_in); +} + +bool tuh_hid_receive_report(uint8_t daddr, uint8_t idx) { - hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid); // claim endpoint - TU_VERIFY( usbh_edpt_claim(dev_addr, hid_itf->ep_in) ); + TU_VERIFY( usbh_edpt_claim(daddr, p_hid->ep_in) ); - if ( !usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size) ) + if ( !usbh_edpt_xfer(daddr, p_hid->ep_in, p_hid->epin_buf, p_hid->epin_size) ) { - usbh_edpt_claim(dev_addr, hid_itf->ep_in); + usbh_edpt_release(daddr, p_hid->ep_in); return false; } return true; } -//bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance) -//{ -// TU_VERIFY(tuh_n_hid_n_mounted(dev_addr, instance)); -// -// hidh_interface_t* hid_itf = get_instance(dev_addr, instance); -// return !usbh_edpt_busy(dev_addr, hid_itf->ep_in); -//} +bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx) +{ + hidh_interface_t* p_hid = get_hid_itf(dev_addr, idx); + TU_VERIFY(p_hid); + + return !usbh_edpt_busy(dev_addr, p_hid->ep_out); +} + +bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const void* report, uint16_t len) +{ + TU_LOG2("HID Send Report %d\r\n", report_id); + + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid); + + if (p_hid->ep_out == 0) + { + // This HID does not have an out endpoint (other than control) + return false; + } + else if (len > CFG_TUH_HID_EPOUT_BUFSIZE || + (report_id != 0 && len > (CFG_TUH_HID_EPOUT_BUFSIZE - 1))) + { + // ep_out buffer is not large enough to hold contents + return false; + } -//void tuh_hid_send_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t const* report, uint16_t len); + // claim endpoint + TU_VERIFY( usbh_edpt_claim(daddr, p_hid->ep_out) ); + + if (report_id == 0) + { + // No report ID in transmission + memcpy(&p_hid->epout_buf[0], report, len); + } + else + { + p_hid->epout_buf[0] = report_id; + memcpy(&p_hid->epout_buf[1], report, len); + ++len; // 1 more byte for report_id + } + + TU_LOG3_MEM(p_hid->epout_buf, len, 2); + + if ( !usbh_edpt_xfer(daddr, p_hid->ep_out, p_hid->epout_buf, len) ) + { + usbh_edpt_release(daddr, p_hid->ep_out); + return false; + } + + return true; +} //--------------------------------------------------------------------+ // USBH API //--------------------------------------------------------------------+ void hidh_init(void) { - tu_memclr(_hidh_dev, sizeof(_hidh_dev)); + tu_memclr(_hidh_itf, sizeof(_hidh_itf)); } -bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { (void) result; uint8_t const dir = tu_edpt_dir(ep_addr); - uint8_t const instance = get_instance_id_by_epaddr(dev_addr, ep_addr); - hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + uint8_t const idx = get_idx_by_epaddr(daddr, ep_addr); + + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid); if ( dir == TUSB_DIR_IN ) { - TU_LOG2(" Get Report callback (%u, %u)\r\n", dev_addr, instance); - TU_LOG3_MEM(hid_itf->epin_buf, xferred_bytes, 2); - tuh_hid_report_received_cb(dev_addr, instance, hid_itf->epin_buf, (uint16_t) xferred_bytes); + TU_LOG2(" Get Report callback (%u, %u)\r\n", daddr, idx); + TU_LOG3_MEM(p_hid->epin_buf, xferred_bytes, 2); + tuh_hid_report_received_cb(daddr, idx, p_hid->epin_buf, (uint16_t) xferred_bytes); }else { - if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(dev_addr, instance, hid_itf->epout_buf, (uint16_t) xferred_bytes); + if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(daddr, idx, p_hid->epout_buf, (uint16_t) xferred_bytes); } return true; } -void hidh_close(uint8_t dev_addr) +void hidh_close(uint8_t daddr) { - TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); - - hidh_device_t* hid_dev = get_dev(dev_addr); - - if (tuh_hid_umount_cb) + for(uint8_t i=0; iinst_count; inst++ ) tuh_hid_umount_cb(dev_addr, inst); + hidh_interface_t* p_hid = &_hidh_itf[i]; + if (p_hid->daddr == daddr) + { + if(tuh_hid_umount_cb) tuh_hid_umount_cb(daddr, i); + p_hid->daddr = 0; + } } - - tu_memclr(hid_dev, sizeof(hidh_device_t)); } //--------------------------------------------------------------------+ // Enumeration //--------------------------------------------------------------------+ -bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) +bool hidh_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) { (void) rhport; (void) max_len; TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass); - TU_LOG2("[%u] HID opening Interface %u\r\n", dev_addr, desc_itf->bInterfaceNumber); + TU_LOG2("[%u] HID opening Interface %u\r\n", daddr, desc_itf->bInterfaceNumber); // len = interface + hid + n*endpoints uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + @@ -343,12 +479,9 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc; TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType); - // not enough interface, try to increase CFG_TUH_HID - // TODO multiple devices - hidh_device_t* hid_dev = get_dev(dev_addr); - TU_ASSERT(hid_dev->inst_count < CFG_TUH_HID, 0); - - hidh_interface_t* hid_itf = get_instance(dev_addr, hid_dev->inst_count); + hidh_interface_t* p_hid = find_new_itf(); + TU_ASSERT(p_hid); // not enough interface, try to increase CFG_TUH_HID + p_hid->daddr = daddr; //------------- Endpoint Descriptors -------------// p_desc = tu_desc_next(p_desc); @@ -357,34 +490,35 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de for(int i = 0; i < desc_itf->bNumEndpoints; i++) { TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType); - TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) ); + TU_ASSERT( tuh_edpt_open(daddr, desc_ep) ); if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { - hid_itf->ep_in = desc_ep->bEndpointAddress; - hid_itf->epin_size = tu_edpt_packet_size(desc_ep); + p_hid->ep_in = desc_ep->bEndpointAddress; + p_hid->epin_size = tu_edpt_packet_size(desc_ep); } else { - hid_itf->ep_out = desc_ep->bEndpointAddress; - hid_itf->epout_size = tu_edpt_packet_size(desc_ep); + p_hid->ep_out = desc_ep->bEndpointAddress; + p_hid->epout_size = tu_edpt_packet_size(desc_ep); } p_desc = tu_desc_next(p_desc); desc_ep = (tusb_desc_endpoint_t const *) p_desc; } - hid_dev->inst_count++; - - hid_itf->itf_num = desc_itf->bInterfaceNumber; + p_hid->itf_num = desc_itf->bInterfaceNumber; // Assume bNumDescriptors = 1 - hid_itf->report_desc_type = desc_hid->bReportType; - hid_itf->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength); + p_hid->report_desc_type = desc_hid->bReportType; + p_hid->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength); // Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config - hid_itf->protocol_mode = HID_PROTOCOL_BOOT; - if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass ) hid_itf->itf_protocol = desc_itf->bInterfaceProtocol; + p_hid->protocol_mode = HID_PROTOCOL_BOOT; + if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass ) + { + p_hid->itf_protocol = desc_itf->bInterfaceProtocol; + } return true; } @@ -400,16 +534,16 @@ enum { CONFIG_COMPLETE }; -static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len); +static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t const* desc_report, uint16_t desc_len); static void process_set_config(tuh_xfer_t* xfer); -bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num) +bool hidh_set_config(uint8_t daddr, uint8_t itf_num) { tusb_control_request_t request; request.wIndex = tu_htole16((uint16_t) itf_num); tuh_xfer_t xfer; - xfer.daddr = dev_addr; + xfer.daddr = daddr; xfer.result = XFER_RESULT_SUCCESS; xfer.setup = &request; xfer.user_data = CONFG_SET_IDLE; @@ -422,8 +556,10 @@ bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num) static void process_set_config(tuh_xfer_t* xfer) { - // Stall is a valid response for SET_IDLE, therefore we could ignore its result - if ( xfer->setup->bRequest != HID_REQ_CONTROL_SET_IDLE ) + // Stall is a valid response for SET_IDLE, sometime SET_PROTOCOL as well + // therefore we could ignore its result + if ( !(xfer->setup->bRequest == HID_REQ_CONTROL_SET_IDLE || + xfer->setup->bRequest == HID_REQ_CONTROL_SET_PROTOCOL) ) { TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, ); } @@ -432,8 +568,9 @@ static void process_set_config(tuh_xfer_t* xfer) uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t const daddr = xfer->daddr; - uint8_t const instance = get_instance_id_by_itfnum(daddr, itf_num); - hidh_interface_t* hid_itf = get_instance(daddr, instance); + uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num); + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid, ); switch(state) { @@ -441,27 +578,27 @@ static void process_set_config(tuh_xfer_t* xfer) { // Idle rate = 0 mean only report when there is changes const uint16_t idle_rate = 0; - const uintptr_t next_state = (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? CONFIG_SET_PROTOCOL : CONFIG_GET_REPORT_DESC; + const uintptr_t next_state = (p_hid->itf_protocol != HID_ITF_PROTOCOL_NONE) ? CONFIG_SET_PROTOCOL : CONFIG_GET_REPORT_DESC; _hidh_set_idle(daddr, itf_num, idle_rate, process_set_config, next_state); } break; case CONFIG_SET_PROTOCOL: - _hidh_set_protocol(daddr, hid_itf->itf_num, HID_PROTOCOL_BOOT, process_set_config, CONFIG_GET_REPORT_DESC); + _hidh_set_protocol(daddr, p_hid->itf_num, HID_PROTOCOL_BOOT, process_set_config, CONFIG_GET_REPORT_DESC); break; case CONFIG_GET_REPORT_DESC: // Get Report Descriptor if possible // using usbh enumeration buffer since report descriptor can be very long - if( hid_itf->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE ) + if( p_hid->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE ) { - TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", hid_itf->report_desc_len); + TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", p_hid->report_desc_len); // Driver is mounted without report descriptor - config_driver_mount_complete(daddr, instance, NULL, 0); + config_driver_mount_complete(daddr, idx, NULL, 0); }else { - tuh_descriptor_get_hid_report(daddr, itf_num, hid_itf->report_desc_type, 0, usbh_get_enum_buf(), hid_itf->report_desc_len, process_set_config, CONFIG_COMPLETE); + tuh_descriptor_get_hid_report(daddr, itf_num, p_hid->report_desc_type, 0, usbh_get_enum_buf(), p_hid->report_desc_len, process_set_config, CONFIG_COMPLETE); } break; @@ -470,7 +607,7 @@ static void process_set_config(tuh_xfer_t* xfer) uint8_t const* desc_report = usbh_get_enum_buf(); uint16_t const desc_len = tu_le16toh(xfer->setup->wLength); - config_driver_mount_complete(daddr, instance, desc_report, desc_len); + config_driver_mount_complete(daddr, idx, desc_report, desc_len); } break; @@ -478,15 +615,16 @@ static void process_set_config(tuh_xfer_t* xfer) } } -static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) +static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t const* desc_report, uint16_t desc_len) { - hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid, ); // enumeration is complete - tuh_hid_mount_cb(dev_addr, instance, desc_report, desc_len); + if (tuh_hid_mount_cb) tuh_hid_mount_cb(daddr, idx, desc_report, desc_len); // notify usbh that driver enumeration is complete - usbh_driver_set_config_complete(dev_addr, hid_itf->itf_num); + usbh_driver_set_config_complete(daddr, p_hid->itf_num); } //--------------------------------------------------------------------+ @@ -631,46 +769,4 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, return report_num; } -//--------------------------------------------------------------------+ -// Helper -//--------------------------------------------------------------------+ - -// Get Device by address -TU_ATTR_ALWAYS_INLINE static inline hidh_device_t* get_dev(uint8_t dev_addr) -{ - return &_hidh_dev[dev_addr-1]; -} - -// Get Interface by instance number -TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_instance(uint8_t dev_addr, uint8_t instance) -{ - return &_hidh_dev[dev_addr-1].instances[instance]; -} - -// Get instance ID by interface number -static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf) -{ - for ( uint8_t inst = 0; inst < CFG_TUH_HID; inst++ ) - { - hidh_interface_t *hid = get_instance(dev_addr, inst); - - if ( (hid->itf_num == itf) && (hid->ep_in || hid->ep_out) ) return inst; - } - - return 0xff; -} - -// Get instance ID by endpoint address -static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr) -{ - for ( uint8_t inst = 0; inst < CFG_TUH_HID; inst++ ) - { - hidh_interface_t *hid = get_instance(dev_addr, inst); - - if ( (ep_addr == hid->ep_in) || ( ep_addr == hid->ep_out) ) return inst; - } - - return 0xff; -} - #endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.h b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.h index fe09b03b..08ad421d 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -62,14 +62,27 @@ typedef struct // Interface API //--------------------------------------------------------------------+ -// Get the number of HID instances -uint8_t tuh_hid_instance_count(uint8_t dev_addr); +// Get the total number of mounted HID interfaces of a device +uint8_t tuh_hid_itf_get_count(uint8_t dev_addr); -// Check if HID instance is mounted -bool tuh_hid_mounted(uint8_t dev_addr, uint8_t instance); +// Get all mounted interfaces across devices +uint8_t tuh_hid_itf_get_total_count(void); + +// backward compatible rename +#define tuh_hid_instance_count tuh_hid_itf_get_count + +// Get Interface information +bool tuh_hid_itf_get_info(uint8_t daddr, uint8_t idx, tuh_itf_info_t* itf_info); + +// Get Interface index from device address + interface number +// return TUSB_INDEX_INVALID_8 (0xFF) if not found +uint8_t tuh_hid_itf_get_index(uint8_t daddr, uint8_t itf_num); // Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values -uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance); +uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t idx); + +// Check if HID interface is mounted +bool tuh_hid_mounted(uint8_t dev_addr, uint8_t idx); // Parse report descriptor into array of report_info struct and return number of reports. // For complicated report, application should write its own parser. @@ -82,31 +95,34 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, // Get current protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) // Note: Device will be initialized in Boot protocol for simplicity. // Application can use set_protocol() to switch back to Report protocol. -uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance); +uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t idx); // Set protocol to HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) // This function is only supported by Boot interface (tuh_n_hid_interface_protocol() != NONE) -bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol); +bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t idx, uint8_t protocol); // Set Report using control endpoint -// report_type is either Intput, Output or Feature, (value from hid_report_type_t) -bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, void* report, uint16_t len); +// report_type is either Input, Output or Feature, (value from hid_report_type_t) +bool tuh_hid_set_report(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len); //--------------------------------------------------------------------+ // Interrupt Endpoint API //--------------------------------------------------------------------+ -// Check if the interface is ready to use -//bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance); +// Check if HID interface is ready to receive report +bool tuh_hid_receive_ready(uint8_t dev_addr, uint8_t idx); // Try to receive next report on Interrupt Endpoint. Immediately return // - true If succeeded, tuh_hid_report_received_cb() callback will be invoked when report is available // - false if failed to queue the transfer e.g endpoint is busy -bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance); +bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t idx); + +// Check if HID interface is ready to send report +bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx); // Send report using interrupt endpoint // If report_id > 0 (composite), it will be sent as 1st byte, then report contents. Otherwise only report content is sent. -//void tuh_hid_send_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t const* report, uint16_t len); +bool tuh_hid_send_report(uint8_t dev_addr, uint8_t idx, uint8_t report_id, const void* report, uint16_t len); //--------------------------------------------------------------------+ // Callbacks (Weak is optional) @@ -117,24 +133,24 @@ bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance); // can be used to parse common/simple enough descriptor. // Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped // therefore report_desc = NULL, desc_len = 0 -void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report_desc, uint16_t desc_len); +TU_ATTR_WEAK void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report_desc, uint16_t desc_len); // Invoked when device with hid interface is un-mounted -TU_ATTR_WEAK void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance); +TU_ATTR_WEAK void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t idx); // Invoked when received report from device via interrupt endpoint // Note: if there is report ID (composite), it is 1st byte of report -void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len); // Invoked when sent report to device successfully via interrupt endpoint -TU_ATTR_WEAK void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); +TU_ATTR_WEAK void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len); // Invoked when Sent Report to device via either control endpoint // len = 0 indicate there is error in the transfer e.g stalled response -TU_ATTR_WEAK void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len); +TU_ATTR_WEAK void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len); // Invoked when Set Protocol request is complete -TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t protocol); +TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t protocol); //--------------------------------------------------------------------+ // Internal Class Driver API diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi.h b/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi.h index 74dc4174..8ddcdfda 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -71,8 +71,8 @@ typedef enum MIDI_CIN_SYSEX_END_1BYTE = 5, // SysEx ends with 1 data, or 1 byte system common message MIDI_CIN_SYSEX_END_2BYTE = 6, // SysEx ends with 2 data MIDI_CIN_SYSEX_END_3BYTE = 7, // SysEx ends with 3 data - MIDI_CIN_NOTE_ON = 8, - MIDI_CIN_NOTE_OFF = 9, + MIDI_CIN_NOTE_OFF = 8, + MIDI_CIN_NOTE_ON = 9, MIDI_CIN_POLY_KEYPRESS = 10, MIDI_CIN_CONTROL_CHANGE = 11, MIDI_CIN_PROGRAM_CHANGE = 12, diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.c index de41706e..e3e7826d 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.c +++ b/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -182,7 +182,7 @@ uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, ui uint8_t const count = (uint8_t) tu_min32(stream->total - stream->index, bufsize); // Skip the header (1st byte) in the buffer - memcpy(buf8, stream->buffer + 1 + stream->index, count); + TU_VERIFY(0 == tu_memcpy_s(buf8, bufsize, stream->buffer + 1 + stream->index, count)); total_read += count; stream->index += count; @@ -261,11 +261,11 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* stream->buffer[1] = data; // Check to see if we're still in a SysEx transmit. - if ( stream->buffer[0] == MIDI_CIN_SYSEX_START ) + if ( ((stream->buffer[0]) & 0xF) == MIDI_CIN_SYSEX_START ) { if ( data == MIDI_STATUS_SYSEX_END ) { - stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; + stream->buffer[0] = (uint8_t) ((cable_num << 4) | MIDI_CIN_SYSEX_END_1BYTE); stream->total = 2; } else @@ -308,6 +308,7 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; stream->total = 2; } + stream->buffer[0] |= (uint8_t)(cable_num << 4); } else { @@ -328,9 +329,9 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* stream->index++; // See if this byte ends a SysEx. - if ( stream->buffer[0] == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END ) + if ( (stream->buffer[0] & 0xF) == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END ) { - stream->buffer[0] = MIDI_CIN_SYSEX_START + (stream->index - 1); + stream->buffer[0] = (uint8_t) ((cable_num << 4) | (MIDI_CIN_SYSEX_START + (stream->index - 1))); stream->total = stream->index; } } diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.h index 211edc8d..1c6f996b 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc.h b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc.h index 84b6e4d7..7f25a29b 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.c index 00b0a1d0..159a1125 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.c +++ b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.c @@ -71,8 +71,8 @@ typedef struct uint8_t add_sense_qualifier; }mscd_interface_t; -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static mscd_interface_t _mscd_itf; -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _mscd_buf[CFG_TUD_MSC_EP_BUFSIZE]; +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static mscd_interface_t _mscd_itf; +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t _mscd_buf[CFG_TUD_MSC_EP_BUFSIZE]; //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION @@ -202,7 +202,7 @@ uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw) //--------------------------------------------------------------------+ #if CFG_TUSB_DEBUG >= 2 -TU_ATTR_UNUSED static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] = +TU_ATTR_UNUSED tu_static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] = { { .key = SCSI_CMD_TEST_UNIT_READY , .data = "Test Unit Ready" }, { .key = SCSI_CMD_INQUIRY , .data = "Inquiry" }, @@ -217,7 +217,7 @@ TU_ATTR_UNUSED static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] = { .key = SCSI_CMD_WRITE_10 , .data = "Write10" } }; -TU_ATTR_UNUSED static tu_lookup_table_t const _msc_scsi_cmd_table = +TU_ATTR_UNUSED tu_static tu_lookup_table_t const _msc_scsi_cmd_table = { .count = TU_ARRAY_SIZE(_msc_scsi_cmd_lookup), .items = _msc_scsi_cmd_lookup @@ -707,7 +707,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ read_capa10.block_size = tu_htonl(block_size); resplen = sizeof(read_capa10); - memcpy(buffer, &read_capa10, (size_t) resplen); + TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &read_capa10, (size_t) resplen)); } } break; @@ -741,7 +741,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ read_fmt_capa.block_size_u16 = tu_htons(block_size); resplen = sizeof(read_fmt_capa); - memcpy(buffer, &read_fmt_capa, (size_t) resplen); + TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &read_fmt_capa, (size_t) resplen)); } } break; @@ -764,7 +764,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ tud_msc_inquiry_cb(lun, inquiry_rsp.vendor_id, inquiry_rsp.product_id, inquiry_rsp.product_rev); resplen = sizeof(inquiry_rsp); - memcpy(buffer, &inquiry_rsp, (size_t) resplen); + TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &inquiry_rsp, (size_t) resplen)); } break; @@ -788,7 +788,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ mode_resp.write_protected = !writable; resplen = sizeof(mode_resp); - memcpy(buffer, &mode_resp, (size_t) resplen); + TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &mode_resp, (size_t) resplen)); } break; @@ -806,7 +806,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ sense_rsp.add_sense_qualifier = p_msc->add_sense_qualifier; resplen = sizeof(sense_rsp); - memcpy(buffer, &sense_rsp, (size_t) resplen); + TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &sense_rsp, (size_t) resplen)); // request sense callback could overwrite the sense data if (tud_msc_request_sense_cb) diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.h index 5839b168..72f95be0 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.c b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.c index 934f79ff..1b48813e 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.c +++ b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -33,6 +33,11 @@ #include "msc_host.h" +// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message +#define MSCH_DEBUG 2 + +#define TU_LOG_MSCH(...) TU_LOG(MSCH_DEBUG, __VA_ARGS__) + //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ @@ -64,16 +69,17 @@ typedef struct uint8_t stage; void* buffer; tuh_msc_complete_cb_t complete_cb; + uintptr_t complete_arg; - msc_cbw_t cbw; - msc_csw_t csw; + CFG_TUH_MEM_ALIGN msc_cbw_t cbw; + CFG_TUH_MEM_ALIGN msc_csw_t csw; }msch_interface_t; -CFG_TUSB_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUH_DEVICE_MAX]; +CFG_TUH_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUH_DEVICE_MAX]; // buffer used to read scsi information when mounted // largest response data currently is inquiry TODO Inquiry is not part of enum anymore -CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) +CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN static uint8_t _msch_buffer[sizeof(scsi_inquiry_resp_t)]; TU_ATTR_ALWAYS_INLINE @@ -126,7 +132,7 @@ static inline void cbw_init(msc_cbw_t *cbw, uint8_t lun) cbw->lun = lun; } -bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->configured); @@ -137,13 +143,14 @@ bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tu p_msc->stage = MSC_STAGE_CMD; p_msc->buffer = data; p_msc->complete_cb = complete_cb; + p_msc->complete_arg = arg; TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t))); return true; } -bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->configured); @@ -156,10 +163,10 @@ bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_r cbw.cmd_len = sizeof(scsi_read_capacity10_t); cbw.command[0] = SCSI_CMD_READ_CAPACITY_10; - return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb); + return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg); } -bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->mounted); @@ -178,10 +185,10 @@ bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* respons }; memcpy(cbw.command, &cmd_inquiry, cbw.cmd_len); - return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb); + return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg); } -bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->configured); @@ -195,10 +202,10 @@ bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_ cbw.command[0] = SCSI_CMD_TEST_UNIT_READY; cbw.command[1] = lun; // according to wiki TODO need verification - return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb); + return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb, arg); } -bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msc_cbw_t cbw; cbw_init(&cbw, lun); @@ -215,34 +222,34 @@ bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_ms memcpy(cbw.command, &cmd_request_sense, cbw.cmd_len); - return tuh_msc_scsi_command(dev_addr, &cbw, resposne, complete_cb); + return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg); } -bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->mounted); msc_cbw_t cbw; cbw_init(&cbw, lun); - + cbw.total_bytes = block_count*p_msc->capacity[lun].block_size; cbw.dir = TUSB_DIR_IN_MASK; cbw.cmd_len = sizeof(scsi_read10_t); - + scsi_read10_t const cmd_read10 = { .cmd_code = SCSI_CMD_READ_10, .lba = tu_htonl(lba), .block_count = tu_htons(block_count) }; - + memcpy(cbw.command, &cmd_read10, cbw.cmd_len); - - return tuh_msc_scsi_command(dev_addr, &cbw, buffer, complete_cb); + + return tuh_msc_scsi_command(dev_addr, &cbw, buffer, complete_cb, arg); } - -bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb) + +bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->mounted); @@ -263,7 +270,7 @@ bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_ memcpy(cbw.command, &cmd_write10, cbw.cmd_len); - return tuh_msc_scsi_command(dev_addr, &cbw, (void*)(uintptr_t) buffer, complete_cb); + return tuh_msc_scsi_command(dev_addr, &cbw, (void*)(uintptr_t) buffer, complete_cb, arg); } #if 0 @@ -344,7 +351,17 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32 // SCSI op is complete p_msc->stage = MSC_STAGE_IDLE; - if (p_msc->complete_cb) p_msc->complete_cb(dev_addr, cbw, csw); + if (p_msc->complete_cb) + { + tuh_msc_complete_data_t const cb_data = + { + .cbw = cbw, + .csw = csw, + .scsi_data = p_msc->buffer, + .user_arg = p_msc->complete_arg + }; + p_msc->complete_cb(dev_addr, &cb_data); + } break; // unknown state @@ -359,9 +376,9 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32 //--------------------------------------------------------------------+ static void config_get_maxlun_complete (tuh_xfer_t* xfer); -static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); -static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); -static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); +static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data); +static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); +static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) { @@ -405,7 +422,7 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) p_msc->configured = true; //------------- Get Max Lun -------------// - TU_LOG2("MSC Get Max Lun\r\n"); + TU_LOG_MSCH("MSC Get Max Lun\r\n"); tusb_control_request_t const request = { .bmRequestType_bit = @@ -444,39 +461,48 @@ static void config_get_maxlun_complete (tuh_xfer_t* xfer) p_msc->max_lun++; // MAX LUN is minus 1 by specs // TODO multiple LUN support - TU_LOG2("SCSI Test Unit Ready\r\n"); + TU_LOG_MSCH("SCSI Test Unit Ready\r\n"); uint8_t const lun = 0; - tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete); + tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete, 0); } -static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) { + msc_cbw_t const* cbw = cb_data->cbw; + msc_csw_t const* csw = cb_data->csw; + if (csw->status == 0) { // Unit is ready, read its capacity - TU_LOG2("SCSI Read Capacity\r\n"); - tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete); + TU_LOG_MSCH("SCSI Read Capacity\r\n"); + tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete, 0); }else { // Note: During enumeration, some device fails Test Unit Ready and require a few retries // with Request Sense to start working !! // TODO limit number of retries - TU_LOG2("SCSI Request Sense\r\n"); - TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, _msch_buffer, config_request_sense_complete)); + TU_LOG_MSCH("SCSI Request Sense\r\n"); + TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, _msch_buffer, config_request_sense_complete, 0)); } return true; } -static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) { + msc_cbw_t const* cbw = cb_data->cbw; + msc_csw_t const* csw = cb_data->csw; + TU_ASSERT(csw->status == 0); - TU_ASSERT(tuh_msc_test_unit_ready(dev_addr, cbw->lun, config_test_unit_ready_complete)); + TU_ASSERT(tuh_msc_test_unit_ready(dev_addr, cbw->lun, config_test_unit_ready_complete, 0)); return true; } -static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) { + msc_cbw_t const* cbw = cb_data->cbw; + msc_csw_t const* csw = cb_data->csw; + TU_ASSERT(csw->status == 0); msch_interface_t* p_msc = get_itf(dev_addr); diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.h b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.h index 7718ad4f..6c0e5c9d 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -41,7 +41,14 @@ #define CFG_TUH_MSC_MAXLUN 4 #endif -typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); +typedef struct { + msc_cbw_t const* cbw; // SCSI command + msc_csw_t const* csw; // SCSI status + void* scsi_data; // SCSI Data + uintptr_t user_arg; // user argument +}tuh_msc_complete_data_t; + +typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); //--------------------------------------------------------------------+ // Application API @@ -66,33 +73,33 @@ uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun); // Perform a full SCSI command (cbw, data, csw) in non-blocking manner. // Complete callback is invoked when SCSI op is complete. // return true if success, false if there is already pending operation. -bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Inquiry command // Complete callback is invoked when SCSI op is complete. -bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Test Unit Ready command // Complete callback is invoked when SCSI op is complete. -bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Request Sense 10 command // Complete callback is invoked when SCSI op is complete. -bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Read 10 command. Read n blocks starting from LBA to buffer // Complete callback is invoked when SCSI op is complete. -bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Write 10 command. Write n blocks starting from LBA to device // Complete callback is invoked when SCSI op is complete. -bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Read Capacity 10 command // Complete callback is invoked when SCSI op is complete. // Note: during enumeration, host stack already carried out this request. Application can retrieve capacity by // simply call tuh_msc_get_block_count() and tuh_msc_get_block_size() -bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); //------------- Application Callback -------------// diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/net/ecm_rndis_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/net/ecm_rndis_device.c index 5f316762..8ac7cbd0 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/net/ecm_rndis_device.c +++ b/test-devices/loopback-stm32/lib/tinyusb/class/net/ecm_rndis_device.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2020 Peter Lawrence @@ -51,7 +51,7 @@ typedef struct bool ecm_mode; - // Endpoint descriptor use to open/close when receving SetInterface + // Endpoint descriptor use to open/close when receiving SetInterface // TODO since configuration descriptor may not be long-lived memory, we should // keep a copy of endpoint attribute instead uint8_t const * ecm_desc_epdata; @@ -61,8 +61,11 @@ typedef struct #define CFG_TUD_NET_PACKET_PREFIX_LEN sizeof(rndis_data_packet_t) #define CFG_TUD_NET_PACKET_SUFFIX_LEN 0 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t received[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t transmitted[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static +uint8_t received[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static +uint8_t transmitted[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; struct ecm_notify_struct { @@ -70,7 +73,7 @@ struct ecm_notify_struct uint32_t downlink, uplink; }; -static const struct ecm_notify_struct ecm_notify_nc = +tu_static const struct ecm_notify_struct ecm_notify_nc = { .header = { .bmRequestType = 0xA1, @@ -80,7 +83,7 @@ static const struct ecm_notify_struct ecm_notify_nc = }, }; -static const struct ecm_notify_struct ecm_notify_csc = +tu_static const struct ecm_notify_struct ecm_notify_csc = { .header = { .bmRequestType = 0xA1, @@ -92,7 +95,7 @@ static const struct ecm_notify_struct ecm_notify_csc = }; // TODO remove CFG_TUSB_MEM_SECTION, control internal buffer is already in this special section -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static union +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static union { uint8_t rndis_buf[120]; struct ecm_notify_struct ecm_buf; @@ -102,9 +105,9 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static union // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ // TODO remove CFG_TUSB_MEM_SECTION -CFG_TUSB_MEM_SECTION static netd_interface_t _netd_itf; +CFG_TUSB_MEM_SECTION tu_static netd_interface_t _netd_itf; -static bool can_xmit; +tu_static bool can_xmit; void tud_network_recv_renew(void) { diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/net/ncm_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/net/ncm_device.c index 00892b49..9e958024 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/net/ncm_device.c +++ b/test-devices/loopback-stm32/lib/tinyusb/class/net/ncm_device.c @@ -130,7 +130,7 @@ typedef struct // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static const ntb_parameters_t ntb_parameters = { +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static const ntb_parameters_t ntb_parameters = { .wLength = sizeof(ntb_parameters_t), .bmNtbFormatsSupported = 0x01, .dwNtbInMaxSize = CFG_TUD_NCM_IN_NTB_MAX_SIZE, @@ -145,11 +145,11 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static const ntb_parameters_t ntb_parame .wNtbOutMaxDatagrams = 0 }; -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static transmit_ntb_t transmit_ntb[2]; +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static transmit_ntb_t transmit_ntb[2]; -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t receive_ntb[CFG_TUD_NCM_OUT_NTB_MAX_SIZE]; +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t receive_ntb[CFG_TUD_NCM_OUT_NTB_MAX_SIZE]; -static ncm_interface_t ncm_interface; +tu_static ncm_interface_t ncm_interface; /* * Set up the NTB state in ncm_interface to be ready to add datagrams. @@ -196,7 +196,7 @@ static void ncm_start_tx(void) { ncm_prepare_for_tx(); } -static struct ecm_notify_struct ncm_notify_connected = +tu_static struct ecm_notify_struct ncm_notify_connected = { .header = { .bmRequestType_bit = { @@ -210,7 +210,7 @@ static struct ecm_notify_struct ncm_notify_connected = }, }; -static struct ecm_notify_struct ncm_notify_speed_change = +tu_static struct ecm_notify_struct ncm_notify_speed_change = { .header = { .bmRequestType_bit = { @@ -392,7 +392,7 @@ bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t if (NCM_GET_NTB_PARAMETERS == request->bRequest) { - tud_control_xfer(rhport, request, (void*)&ntb_parameters, sizeof(ntb_parameters)); + tud_control_xfer(rhport, request, (void*)(uintptr_t) &ntb_parameters, sizeof(ntb_parameters)); } break; @@ -430,7 +430,7 @@ static void handle_incoming_datagram(uint32_t len) { ncm_interface.num_datagrams++; } - + tud_network_recv_renew(); } diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/net/net_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/net/net_device.h index 6e294465..39991635 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/net/net_device.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/net/net_device.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2020 Peter Lawrence @@ -94,7 +94,7 @@ void tud_network_init_cb(void); // client must provide this: 48-bit MAC address // TODO removed later since it is not part of tinyusb stack -extern const uint8_t tud_network_mac_address[6]; +extern uint8_t tud_network_mac_address[6]; //------------- NCM -------------// diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc.h b/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc.h index e7016ae2..090ab3c4 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc.h @@ -158,7 +158,7 @@ enum { USBTMC_BULK_IN_ERR_DATA_TOO_SHORT = 4u, USBTMC_BULK_IN_ERR_DATA_TOO_LONG = 5u, }; -// bult-in halt errors +// built-in halt errors enum { USBTMC_BULK_IN_ERR = 1u, ///< receives a USBTMC command message that expects a response while a /// Bulk-IN transfer is in progress @@ -262,14 +262,14 @@ typedef struct TU_ATTR_PACKED struct TU_ATTR_PACKED { - unsigned int listenOnly :1; - unsigned int talkOnly :1; - unsigned int supportsIndicatorPulse :1; + uint8_t listenOnly :1; + uint8_t talkOnly :1; + uint8_t supportsIndicatorPulse :1; } bmIntfcCapabilities; struct TU_ATTR_PACKED { - unsigned int canEndBulkInOnTermChar :1; + uint8_t canEndBulkInOnTermChar :1; } bmDevCapabilities; uint8_t _reserved2[6]; @@ -277,17 +277,17 @@ typedef struct TU_ATTR_PACKED struct TU_ATTR_PACKED { - unsigned int is488_2 :1; - unsigned int supportsREN_GTL_LLO :1; - unsigned int supportsTrigger :1; + uint8_t supportsTrigger :1; + uint8_t supportsREN_GTL_LLO :1; + uint8_t is488_2 :1; } bmIntfcCapabilities488; struct TU_ATTR_PACKED { - unsigned int SCPI :1; - unsigned int SR1 :1; - unsigned int RL1 :1; - unsigned int DT1 :1; + uint8_t DT1 :1; + uint8_t RL1 :1; + uint8_t SR1 :1; + uint8_t SCPI :1; } bmDevCapabilities488; uint8_t _reserved3[8]; } usbtmc_response_capabilities_488_t; @@ -316,4 +316,3 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_interrupt_488_t) == 2u, "struct wrong length"); #endif - diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c index af4a9273..4e320a77 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c +++ b/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c @@ -78,12 +78,12 @@ #ifdef xDEBUG #include "uart_util.h" -static char logMsg[150]; +tu_static char logMsg[150]; #endif // Buffer size must be an exact multiple of the max packet size for both // bulk (up to 64 bytes for FS, 512 bytes for HS). In addation, this driver -// imposes a minimum buffer size of 32 bytes. +// imposes a minimum buffer size of 32 bytes. #define USBTMCD_BUFFER_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) /* @@ -143,7 +143,7 @@ typedef struct usbtmc_capabilities_specific_t const * capabilities; } usbtmc_interface_state_t; -CFG_TUSB_MEM_SECTION static usbtmc_interface_state_t usbtmc_state = +CFG_TUSB_MEM_SECTION tu_static usbtmc_interface_state_t usbtmc_state = { .itf_id = 0xFF, }; @@ -154,15 +154,20 @@ TU_VERIFY_STATIC(USBTMCD_BUFFER_SIZE >= 32u,"USBTMC dev buffer size too small"); static bool handle_devMsgOutStart(uint8_t rhport, void *data, size_t len); static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t packetLen); -static uint8_t termChar; -static uint8_t termCharRequested = false; +#ifndef NDEBUG +tu_static uint8_t termChar; +#endif -osal_mutex_def_t usbtmcLockBuffer; -static osal_mutex_t usbtmcLock; +tu_static uint8_t termCharRequested = false; + +#if OSAL_MUTEX_REQUIRED +static OSAL_MUTEX_DEF(usbtmcLockBuffer); +#endif +osal_mutex_t usbtmcLock; // Our own private lock, mostly for the state variable. -#define criticalEnter() do {osal_mutex_lock(usbtmcLock,OSAL_TIMEOUT_WAIT_FOREVER); } while (0) -#define criticalLeave() do {osal_mutex_unlock(usbtmcLock); } while (0) +#define criticalEnter() do { (void) osal_mutex_lock(usbtmcLock,OSAL_TIMEOUT_WAIT_FOREVER); } while (0) +#define criticalLeave() do { (void) osal_mutex_unlock(usbtmcLock); } while (0) bool atomicChangeState(usbtmcd_state_enum expectedState, usbtmcd_state_enum newState) { @@ -362,9 +367,9 @@ bool tud_usbtmc_start_bus_read() case STATE_RCV: break; default: - TU_VERIFY(false); + return false; } - TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, 64)); + TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, (uint16_t)usbtmc_state.ep_bulk_out_wMaxPacketSize)); return true; } @@ -440,7 +445,10 @@ static bool handle_devMsgIn(void *data, size_t len) usbtmc_state.transfer_size_sent = 0u; termCharRequested = msg->bmTransferAttributes.TermCharEnabled; + +#ifndef NDEBUG termChar = msg->TermChar; +#endif if(termCharRequested) TU_VERIFY(usbtmc_state.capabilities->bmDevCapabilities.canEndBulkInOnTermChar); @@ -464,53 +472,53 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint switch(usbtmc_state.state) { case STATE_IDLE: - TU_VERIFY(xferred_bytes >= sizeof(usbtmc_msg_generic_t)); - msg = (usbtmc_msg_generic_t*)(usbtmc_state.ep_bulk_out_buf); - uint8_t invInvTag = (uint8_t)~(msg->header.bTagInverse); - TU_VERIFY(msg->header.bTag == invInvTag); - TU_VERIFY(msg->header.bTag != 0x00); - - switch(msg->header.MsgID) { - case USBTMC_MSGID_DEV_DEP_MSG_OUT: - if(!handle_devMsgOutStart(rhport, msg, xferred_bytes)) - { - usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); - TU_VERIFY(false); - } - break; + { + TU_VERIFY(xferred_bytes >= sizeof(usbtmc_msg_generic_t)); + msg = (usbtmc_msg_generic_t*)(usbtmc_state.ep_bulk_out_buf); + uint8_t invInvTag = (uint8_t)~(msg->header.bTagInverse); + TU_VERIFY(msg->header.bTag == invInvTag); + TU_VERIFY(msg->header.bTag != 0x00); + + switch(msg->header.MsgID) { + case USBTMC_MSGID_DEV_DEP_MSG_OUT: + if(!handle_devMsgOutStart(rhport, msg, xferred_bytes)) + { + usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); + return false; + } + break; - case USBTMC_MSGID_DEV_DEP_MSG_IN: - TU_VERIFY(handle_devMsgIn(msg, xferred_bytes)); - break; + case USBTMC_MSGID_DEV_DEP_MSG_IN: + TU_VERIFY(handle_devMsgIn(msg, xferred_bytes)); + break; #if (CFG_TUD_USBTMC_ENABLE_488) - case USBTMC_MSGID_USB488_TRIGGER: - // Spec says we halt the EP if we didn't declare we support it. - TU_VERIFY(usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger); - TU_VERIFY(tud_usbtmc_msg_trigger_cb(msg)); + case USBTMC_MSGID_USB488_TRIGGER: + // Spec says we halt the EP if we didn't declare we support it. + TU_VERIFY(usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger); + TU_VERIFY(tud_usbtmc_msg_trigger_cb(msg)); - break; + break; #endif - case USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT: - case USBTMC_MSGID_VENDOR_SPECIFIC_IN: - default: - usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); - TU_VERIFY(false); - return false; + case USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT: + case USBTMC_MSGID_VENDOR_SPECIFIC_IN: + default: + usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); + return false; + } + return true; } - return true; - case STATE_RCV: if(!handle_devMsgOut(rhport, usbtmc_state.ep_bulk_out_buf, xferred_bytes, xferred_bytes)) { usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); - TU_VERIFY(false); + return false; } return true; case STATE_ABORTING_BULK_OUT: - TU_VERIFY(false); - return false; // Should be stalled by now, shouldn't have received a packet. + // Should be stalled by now, shouldn't have received a packet. + return false; case STATE_TX_REQUESTED: case STATE_TX_INITIATED: @@ -518,7 +526,7 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint case STATE_ABORTING_BULK_IN_SHORTED: case STATE_ABORTING_BULK_IN_ABORTED: default: - TU_VERIFY(false); + return false; } } else if(ep_addr == usbtmc_state.ep_bulk_in) @@ -567,7 +575,6 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint default: TU_ASSERT(false); - return false; } } else if (ep_addr == usbtmc_state.ep_int_in) { @@ -598,8 +605,8 @@ bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request uint32_t ep_addr = (request->wIndex); // At this point, a transfer MAY be in progress. Based on USB spec, when clearing bulk EP HALT, - // the EP transfer buffer needs to be cleared and DTOG needs to be reset, even if - // the EP is not halted. The only USBD API interface to do this is to stall and then unstall the EP. + // the EP transfer buffer needs to be cleared and DTOG needs to be reset, even if + // the EP is not halted. The only USBD API interface to do this is to stall and then un-stall the EP. if(ep_addr == usbtmc_state.ep_bulk_out) { criticalEnter(); @@ -871,16 +878,13 @@ bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request case USB488_bREQUEST_LOCAL_LOCKOUT: { TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface - TU_VERIFY(false); return false; } #endif default: - TU_VERIFY(false); return false; } - TU_VERIFY(false); } #endif /* CFG_TUD_TSMC */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h index 144b3315..c1298ddb 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h @@ -36,7 +36,7 @@ #endif /*********************************************** - * Functions to be implemeted by the class implementation + * Functions to be implemented by the class implementation */ // In order to proceed, app must call call tud_usbtmc_start_bus_read(rhport) during or soon after: diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.c index 3b81a108..93596ee3 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.c +++ b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.c @@ -59,7 +59,7 @@ typedef struct CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_VENDOR_EPSIZE]; } vendord_interface_t; -CFG_TUSB_MEM_SECTION static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR]; +CFG_TUSB_MEM_SECTION tu_static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR]; #define ITF_MEM_RESET_SIZE offsetof(vendord_interface_t, rx_ff) @@ -86,8 +86,8 @@ static void _prep_out_transaction (vendord_interface_t* p_itf) { uint8_t const rhport = 0; - // skip if previous transfer not complete - if ( usbd_edpt_busy(rhport, p_itf->ep_out) ) return; + // claim endpoint + TU_VERIFY(usbd_edpt_claim(rhport, p_itf->ep_out), ); // Prepare for incoming data but only allow what we can store in the ring buffer. uint16_t max_read = tu_fifo_remaining(&p_itf->rx_ff); @@ -95,6 +95,11 @@ static void _prep_out_transaction (vendord_interface_t* p_itf) { usbd_edpt_xfer(rhport, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE); } + else + { + // Release endpoint since we don't make any transfer + usbd_edpt_release(rhport, p_itf->ep_out); + } } uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize) @@ -115,37 +120,47 @@ void tud_vendor_n_read_flush (uint8_t itf) //--------------------------------------------------------------------+ // Write API //--------------------------------------------------------------------+ -static uint16_t maybe_transmit(vendord_interface_t* p_itf) -{ - uint8_t const rhport = 0; - - // skip if previous transfer not complete - TU_VERIFY( !usbd_edpt_busy(rhport, p_itf->ep_in) ); - - uint16_t count = tu_fifo_read_n(&p_itf->tx_ff, p_itf->epin_buf, CFG_TUD_VENDOR_EPSIZE); - if (count > 0) - { - TU_ASSERT( usbd_edpt_xfer(rhport, p_itf->ep_in, p_itf->epin_buf, count) ); - } - return count; -} - uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize) { vendord_interface_t* p_itf = &_vendord_itf[itf]; uint16_t ret = tu_fifo_write_n(&p_itf->tx_ff, buffer, (uint16_t) bufsize); + + // flush if queue more than packet size if (tu_fifo_count(&p_itf->tx_ff) >= CFG_TUD_VENDOR_EPSIZE) { - maybe_transmit(p_itf); + tud_vendor_n_write_flush(itf); } return ret; } -uint32_t tud_vendor_n_flush (uint8_t itf) +uint32_t tud_vendor_n_write_flush (uint8_t itf) { vendord_interface_t* p_itf = &_vendord_itf[itf]; - uint32_t ret = maybe_transmit(p_itf); - return ret; + // Skip if usb is not ready yet + TU_VERIFY( tud_ready(), 0 ); + + // No data to send + if ( !tu_fifo_count(&p_itf->tx_ff) ) return 0; + + uint8_t const rhport = 0; + + // Claim the endpoint + TU_VERIFY( usbd_edpt_claim(rhport, p_itf->ep_in), 0 ); + + // Pull data from FIFO + uint16_t const count = tu_fifo_read_n(&p_itf->tx_ff, p_itf->epin_buf, sizeof(p_itf->epin_buf)); + + if ( count ) + { + TU_ASSERT( usbd_edpt_xfer(rhport, p_itf->ep_in, p_itf->epin_buf, count), 0 ); + return count; + }else + { + // Release endpoint since we don't make any transfer + // Note: data is dropped if terminal is not connected + usbd_edpt_release(rhport, p_itf->ep_in); + return 0; + } } uint32_t tud_vendor_n_write_available (uint8_t itf) @@ -225,10 +240,10 @@ uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, ui // Prepare for incoming data if ( p_vendor->ep_out ) { - TU_ASSERT(usbd_edpt_xfer(rhport, p_vendor->ep_out, p_vendor->epout_buf, sizeof(p_vendor->epout_buf)), 0); + _prep_out_transaction(p_vendor); } - if ( p_vendor->ep_in ) maybe_transmit(p_vendor); + if ( p_vendor->ep_in ) tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); } return (uint16_t) ((uintptr_t) p_desc - (uintptr_t) desc_itf); @@ -263,7 +278,7 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint { if (tud_vendor_tx_cb) tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes); // Send complete, try to send more if possible - maybe_transmit(p_itf); + tud_vendor_n_write_flush(itf); } return true; diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.h index 4a873e5f..d239406b 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -48,11 +48,13 @@ bool tud_vendor_n_peek (uint8_t itf, uint8_t* ui8); void tud_vendor_n_read_flush (uint8_t itf); uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize); +uint32_t tud_vendor_n_write_flush (uint8_t itf); uint32_t tud_vendor_n_write_available (uint8_t itf); -static inline -uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str); -uint32_t tud_vendor_n_flush (uint8_t itf); +static inline uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str); + +// backward compatible +#define tud_vendor_n_flush(itf) tud_vendor_n_write_flush(itf) //--------------------------------------------------------------------+ // Application API (Single Port) @@ -65,7 +67,10 @@ static inline void tud_vendor_read_flush (void); static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize); static inline uint32_t tud_vendor_write_str (char const* str); static inline uint32_t tud_vendor_write_available (void); -static inline uint32_t tud_vendor_flush (void); +static inline uint32_t tud_vendor_write_flush (void); + +// backward compatible +#define tud_vendor_flush() tud_vendor_write_flush() //--------------------------------------------------------------------+ // Application Callback API (weak is optional) @@ -115,6 +120,11 @@ static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize) return tud_vendor_n_write(0, buffer, bufsize); } +static inline uint32_t tud_vendor_write_flush (void) +{ + return tud_vendor_n_write_flush(0); +} + static inline uint32_t tud_vendor_write_str (char const* str) { return tud_vendor_n_write_str(0, str); @@ -125,11 +135,6 @@ static inline uint32_t tud_vendor_write_available (void) return tud_vendor_n_write_available(0); } -static inline uint32_t tud_vendor_flush (void) -{ - return tud_vendor_n_flush(0); -} - //--------------------------------------------------------------------+ // Internal Class Driver API //--------------------------------------------------------------------+ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.c b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.c index dbea1228..e66c5007 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.c +++ b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.h b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.h index 65223fbc..acfebe7a 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/video/video.h b/test-devices/loopback-stm32/lib/tinyusb/class/video/video.h index 84474654..c0088c4f 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/video/video.h +++ b/test-devices/loopback-stm32/lib/tinyusb/class/video/video.h @@ -302,6 +302,45 @@ typedef struct TU_ATTR_PACKED { uint8_t bCopyProtect; } tusb_desc_cs_video_fmt_uncompressed_t; +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFormatIndex; + uint8_t bNumFrameDescriptors; + uint8_t bmFlags; + uint8_t bDefaultFrameIndex; + uint8_t bAspectRatioX; + uint8_t bAspectRatioY; + uint8_t bmInterlaceFlags; + uint8_t bCopyProtect; +} tusb_desc_cs_video_fmt_mjpeg_t; + +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFormatIndex; + uint32_t dwMaxVideoFrameBufferSize; /* deprecated */ + uint8_t bFormatType; +} tusb_desc_cs_video_fmt_dv_t; + +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFormatIndex; + uint8_t bNumFrameDescriptors; + uint8_t guidFormat[16]; + uint8_t bBitsPerPixel; + uint8_t bDefaultFrameIndex; + uint8_t bAspectRatioX; + uint8_t bAspectRatioY; + uint8_t bmInterlaceFlags; + uint8_t bCopyProtect; + uint8_t bVaribaleSize; +} tusb_desc_cs_video_fmt_frame_based_t; + typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType; @@ -318,6 +357,24 @@ typedef struct TU_ATTR_PACKED { uint32_t dwFrameInterval[]; } tusb_desc_cs_video_frm_uncompressed_t; +typedef tusb_desc_cs_video_frm_uncompressed_t tusb_desc_cs_video_frm_mjpeg_t; + +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFrameIndex; + uint8_t bmCapabilities; + uint16_t wWidth; + uint16_t wHeight; + uint32_t dwMinBitRate; + uint32_t dwMaxBitRate; + uint32_t dwDefaultFrameInterval; + uint8_t bFrameIntervalType; + uint32_t dwBytesPerLine; + uint32_t dwFrameInterval[]; +} tusb_desc_cs_video_frm_frame_based_t; + //--------------------------------------------------------------------+ // Requests //--------------------------------------------------------------------+ @@ -378,8 +435,11 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c #define TUD_VIDEO_DESC_CS_VS_IN_LEN 13 #define TUD_VIDEO_DESC_CS_VS_OUT_LEN 9 #define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN 27 +#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN 11 #define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN 38 #define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN 26 +#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN 38 +#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN 26 #define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN 6 /* 2.2 compression formats */ @@ -462,6 +522,25 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ +/* Motion-JPEG 3.1.1 Table 3-1 */ +#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG(_fmtidx, _numfrmdesc, _fixed_sz, _frmidx, _asrx, _asry, _interlace, _cp) \ + TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_MJPEG, \ + _fmtidx, _numfrmdesc, _fixed_sz, _frmidx, _asrx, _asry, _interlace, _cp + +/* Motion-JPEG 3.1.1 Table 3-2 and 3-3 */ +#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, _minfrminterval, _maxfrminterval, _frmintervalstep) \ + TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_MJPEG, \ + _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ + U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), 0, \ + U32_TO_U8S_LE(_minfrminterval), U32_TO_U8S_LE(_maxfrminterval), U32_TO_U8S_LE(_frmintervalstep) + +/* Motion-JPEG 3.1.1 Table 3-2 and 3-4 */ +#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, ...) \ + TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN + (TU_ARGS_NUM(__VA_ARGS__)) * 4, \ + TUSB_DESC_CS_INTERFACE, VIDEO_CS_VS_INTERFACE_FRAME_MJPEG, \ + _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ + U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ + /* 3.9.2.6 */ #define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(_color, _trns, _mat) \ TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN, \ @@ -470,7 +549,7 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c /* 3.10.1.1 */ #define TUD_VIDEO_DESC_EP_ISO(_ep, _epsize, _ep_interval) \ - 7, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS,\ + 7, TUSB_DESC_ENDPOINT, _ep, (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS),\ U16_TO_U8S_LE(_epsize), _ep_interval /* 3.10.1.2 */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.c index 7636db5f..d6e98602 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.c +++ b/test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2021 Koji KITAYAMA @@ -59,6 +59,34 @@ typedef struct TU_ATTR_PACKED { uint8_t bEntityId; } tusb_desc_cs_video_entity_itf_t; +typedef union { + struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFormatIndex; + uint8_t bNumFrameDescriptors; + }; + tusb_desc_cs_video_fmt_uncompressed_t uncompressed; + tusb_desc_cs_video_fmt_mjpeg_t mjpeg; + tusb_desc_cs_video_fmt_frame_based_t frame_based; +} tusb_desc_cs_video_fmt_t; + +typedef union { + struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFrameIndex; + uint8_t bmCapabilities; + uint16_t wWidth; + uint16_t wHeight; + }; + tusb_desc_cs_video_frm_uncompressed_t uncompressed; + tusb_desc_cs_video_frm_mjpeg_t mjpeg; + tusb_desc_cs_video_frm_frame_based_t frame_based; +} tusb_desc_cs_video_frm_t; + /* video streaming interface */ typedef struct TU_ATTR_PACKED { uint8_t index_vc; /* index of bound video control interface */ @@ -80,7 +108,7 @@ typedef struct TU_ATTR_PACKED { /* video control interface */ typedef struct TU_ATTR_PACKED { - void const *beg; /* The head of the first video control interface descriptor */ + uint8_t const *beg; /* The head of the first video control interface descriptor */ uint16_t len; /* Byte length of the descriptors */ uint16_t cur; /* offset for current video control interface */ uint8_t stm[CFG_TUD_VIDEO_STREAMING]; /* Indices of streaming interface */ @@ -97,11 +125,11 @@ typedef struct TU_ATTR_PACKED { //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION static videod_interface_t _videod_itf[CFG_TUD_VIDEO]; -CFG_TUSB_MEM_SECTION static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING]; +CFG_TUSB_MEM_SECTION tu_static videod_interface_t _videod_itf[CFG_TUD_VIDEO]; +CFG_TUSB_MEM_SECTION tu_static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING]; -static uint8_t const _cap_get = 0x1u; /* support for GET */ -static uint8_t const _cap_get_set = 0x3u; /* support for GET and SET */ +tu_static uint8_t const _cap_get = 0x1u; /* support for GET */ +tu_static uint8_t const _cap_get_set = 0x3u; /* support for GET and SET */ /** Get interface number from the interface descriptor * @@ -146,7 +174,7 @@ static tusb_desc_vc_itf_t const* _get_desc_vc(videod_interface_t const *self) static tusb_desc_vs_itf_t const* _get_desc_vs(videod_streaming_interface_t const *self) { if (!self->desc.cur) return NULL; - void const *desc = _videod_itf[self->index_vc].beg; + uint8_t const *desc = _videod_itf[self->index_vc].beg; return (tusb_desc_vs_itf_t const*)(desc + self->desc.cur); } @@ -219,9 +247,9 @@ static void const* _next_desc_itf(void const *beg, void const *end) * * @return The pointer for interface descriptor. * @retval end did not found interface descriptor */ -static inline void const* _find_desc_itf(void const *beg, void const *end, uint_fast8_t itfnum, uint_fast8_t altnum) +static inline uint8_t const* _find_desc_itf(void const *beg, void const *end, uint_fast8_t itfnum, uint_fast8_t altnum) { - return _find_desc_3(beg, end, TUSB_DESC_INTERFACE, itfnum, altnum); + return (uint8_t const*) _find_desc_3(beg, end, TUSB_DESC_INTERFACE, itfnum, altnum); } /** Find the first endpoint descriptor belonging to the current interface descriptor. @@ -243,6 +271,13 @@ static void const* _find_desc_ep(void const *beg, void const *end) return end; } +/** Return the end of the video control descriptor. */ +static inline void const* _end_of_control_descriptor(void const *desc) +{ + tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const *)desc; + return ((uint8_t const*) desc) + vc->std.bLength + tu_le16toh(vc->ctl.wTotalLength); +} + /** Find the first entity descriptor with the entity ID * specified by the argument belonging to the current video control descriptor. * @@ -253,10 +288,8 @@ static void const* _find_desc_ep(void const *beg, void const *end) * @retval end did not found interface descriptor */ static void const* _find_desc_entity(void const *desc, uint_fast8_t entityid) { - tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const*)desc; - void const *beg = vc; - void const *end = beg + vc->std.bLength + vc->ctl.wTotalLength; - for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) { + void const *end = _end_of_control_descriptor(desc); + for (void const *cur = desc; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) { tusb_desc_cs_video_entity_itf_t const *itf = (tusb_desc_cs_video_entity_itf_t const *)cur; if ((VIDEO_CS_ITF_VC_INPUT_TERMINAL <= itf->bDescriptorSubtype && itf->bDescriptorSubtype < VIDEO_CS_ITF_VC_MAX) @@ -272,21 +305,42 @@ static void const* _find_desc_entity(void const *desc, uint_fast8_t entityid) static inline void const* _end_of_streaming_descriptor(void const *desc) { tusb_desc_vs_itf_t const *vs = (tusb_desc_vs_itf_t const *)desc; - return desc + vs->std.bLength + vs->stm.wTotalLength; + return ((uint8_t const*) desc) + vs->std.bLength + tu_le16toh(vs->stm.wTotalLength); } /** Find the first format descriptor with the specified format number. */ -static inline tusb_desc_cs_video_fmt_uncompressed_t const *_find_desc_format(void const *beg, void const *end, uint_fast8_t fmtnum) +static inline void const *_find_desc_format(void const *beg, void const *end, uint_fast8_t fmtnum) { - return (tusb_desc_cs_video_fmt_uncompressed_t const*) - _find_desc_3(beg, end, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED, fmtnum); + for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) { + uint8_t const *p = (uint8_t const *)cur; + uint_fast8_t fmt = p[2]; + if ((fmt == VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED || + fmt == VIDEO_CS_ITF_VS_FORMAT_MJPEG || + fmt == VIDEO_CS_ITF_VS_FORMAT_DV || + fmt == VIDEO_CS_ITF_VS_FRAME_FRAME_BASED) && + fmtnum == p[3]) { + return cur; + } + cur = tu_desc_next(cur); + } + return end; } /** Find the first frame descriptor with the specified format number. */ -static inline tusb_desc_cs_video_frm_uncompressed_t const *_find_desc_frame(void const *beg, void const *end, uint_fast8_t frmnum) +static inline void const *_find_desc_frame(void const *beg, void const *end, uint_fast8_t frmnum) { - return (tusb_desc_cs_video_frm_uncompressed_t const*) - _find_desc_3(beg, end, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, frmnum); + for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) { + uint8_t const *p = (uint8_t const *)cur; + uint_fast8_t frm = p[2]; + if ((frm == VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED || + frm == VIDEO_CS_ITF_VS_FRAME_MJPEG || + frm == VIDEO_CS_ITF_VS_FRAME_FRAME_BASED) && + frmnum == p[3]) { + return cur; + } + cur = tu_desc_next(cur); + } + return end; } /** Set uniquely determined values to variables that have not been set @@ -307,7 +361,6 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm /* Set the parameters determined by the format */ param->wKeyFrameRate = 1; param->wPFrameRate = 0; - param->wCompQuality = 1; /* 1 to 10000 */ param->wCompWindowSize = 1; /* GOP size? */ param->wDelay = 0; /* milliseconds */ param->dwClockFrequency = 27000000; /* same as MPEG-2 system time clock */ @@ -319,8 +372,18 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm param->bBitDepthLuma = 8; void const *end = _end_of_streaming_descriptor(vs); - tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); + tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); TU_ASSERT(fmt != end); + + switch (fmt->bDescriptorSubType) { + case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED: + param->wCompQuality = 1; /* 1 to 10000 */ + break; + case VIDEO_CS_ITF_VS_FORMAT_MJPEG: + break; + default: return false; + } + uint_fast8_t frmnum = param->bFrameIndex; TU_ASSERT(frmnum <= fmt->bNumFrameDescriptors); if (!frmnum) { @@ -328,28 +391,39 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm frmnum = 1; param->bFrameIndex = 1; } - tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); + tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); TU_ASSERT(frm != end); /* Set the parameters determined by the frame */ uint_fast32_t frame_size = param->dwMaxVideoFrameSize; if (!frame_size) { - frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->bBitsPerPixel / 8; + switch (fmt->bDescriptorSubType) { + case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED: + frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->uncompressed.bBitsPerPixel / 8; + break; + case VIDEO_CS_ITF_VS_FORMAT_MJPEG: + frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */ + break; + default: break; + } param->dwMaxVideoFrameSize = frame_size; } uint_fast32_t interval = param->dwFrameInterval; if (!interval) { - if ((1 < frm->bFrameIntervalType) || - ((0 == frm->bFrameIntervalType) && (frm->dwFrameInterval[1] != frm->dwFrameInterval[0]))) { + if ((1 < frm->uncompressed.bFrameIntervalType) || + ((0 == frm->uncompressed.bFrameIntervalType) && + (frm->uncompressed.dwFrameInterval[1] != frm->uncompressed.dwFrameInterval[0]))) { return true; } - interval = frm->dwFrameInterval[0]; + interval = frm->uncompressed.dwFrameInterval[0]; param->dwFrameInterval = interval; } uint_fast32_t interval_ms = interval / 10000; TU_ASSERT(interval_ms); uint_fast32_t payload_size = (frame_size + interval_ms - 1) / interval_ms + 2; + if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) + payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE; param->dwMaxPayloadTransferSize = payload_size; return true; } @@ -366,7 +440,8 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * if (!fmtnum) { switch (request) { case VIDEO_REQUEST_GET_MAX: - param->bFormatIndex = _get_desc_vs(stm)->stm.bNumFormats; + if (_get_desc_vs(stm)) + param->bFormatIndex = _get_desc_vs(stm)->stm.bNumFormats; break; case VIDEO_REQUEST_GET_MIN: case VIDEO_REQUEST_GET_DEF: @@ -395,7 +470,7 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); TU_ASSERT(vs); void const *end = _end_of_streaming_descriptor(vs); - tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); + tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); switch (request) { case VIDEO_REQUEST_GET_MAX: frmnum = fmt->bNumFrameDescriptors; @@ -404,14 +479,32 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * frmnum = 1; break; case VIDEO_REQUEST_GET_DEF: - frmnum = fmt->bDefaultFrameIndex; + switch (fmt->bDescriptorSubType) { + case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED: + frmnum = fmt->uncompressed.bDefaultFrameIndex; + break; + case VIDEO_CS_ITF_VS_FORMAT_MJPEG: + frmnum = fmt->mjpeg.bDefaultFrameIndex; + break; + default: return false; + } break; default: return false; } - param->bFrameIndex = (uint8_t) frmnum; + param->bFrameIndex = (uint8_t)frmnum; /* Set the parameters determined by the frame */ - tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); - param->dwMaxVideoFrameSize = (uint32_t) (frm->wWidth * frm->wHeight * fmt->bBitsPerPixel / 8); + tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); + uint_fast32_t frame_size; + switch (fmt->bDescriptorSubType) { + case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED: + frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->uncompressed.bBitsPerPixel / 8; + break; + case VIDEO_CS_ITF_VS_FORMAT_MJPEG: + frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */ + break; + default: return false; + } + param->dwMaxVideoFrameSize = frame_size; return true; } @@ -419,17 +512,17 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); TU_ASSERT(vs); void const *end = _end_of_streaming_descriptor(vs); - tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); - tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); + tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); + tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); uint_fast32_t interval, interval_ms; switch (request) { case VIDEO_REQUEST_GET_MAX: { uint_fast32_t min_interval, max_interval; - uint_fast8_t num_intervals = frm->bFrameIntervalType; - max_interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1]; - min_interval = frm->dwFrameInterval[0]; + uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType; + max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1]; + min_interval = frm->uncompressed.dwFrameInterval[0]; interval = max_interval; interval_ms = min_interval / 10000; } @@ -437,24 +530,24 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * case VIDEO_REQUEST_GET_MIN: { uint_fast32_t min_interval, max_interval; - uint_fast8_t num_intervals = frm->bFrameIntervalType; - max_interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1]; - min_interval = frm->dwFrameInterval[0]; + uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType; + max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1]; + min_interval = frm->uncompressed.dwFrameInterval[0]; interval = min_interval; interval_ms = max_interval / 10000; } break; case VIDEO_REQUEST_GET_DEF: - interval = frm->dwDefaultFrameInterval; + interval = frm->uncompressed.dwDefaultFrameInterval; interval_ms = interval / 10000; break; case VIDEO_REQUEST_GET_RES: { - uint_fast8_t num_intervals = frm->bFrameIntervalType; + uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType; if (num_intervals) { interval = 0; } else { - interval = frm->dwFrameInterval[2]; + interval = frm->uncompressed.dwFrameInterval[2]; interval_ms = interval / 10000; } } @@ -466,11 +559,15 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * param->dwMaxPayloadTransferSize = 0; } else { uint_fast32_t frame_size = param->dwMaxVideoFrameSize; + uint_fast32_t payload_size; if (!interval_ms) { - param->dwMaxPayloadTransferSize = frame_size + 2; + payload_size = frame_size + 2; } else { - param->dwMaxPayloadTransferSize = (frame_size + interval_ms - 1) / interval_ms + 2; + payload_size = (frame_size + interval_ms - 1) / interval_ms + 2; } + if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) + payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE; + param->dwMaxPayloadTransferSize = payload_size; } return true; } @@ -484,10 +581,12 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self) { tusb_desc_vc_itf_t const *vc = _get_desc_vc(self); + /* The next descriptor after the class-specific VC interface header descriptor. */ - void const *cur = (void const*)vc + vc->std.bLength + vc->ctl.bLength; + void const *cur = (uint8_t const*)vc + vc->std.bLength + vc->ctl.bLength; + /* The end of the video control interface descriptor. */ - void const *end = (void const*)vc + vc->std.bLength + vc->ctl.wTotalLength; + void const *end = _end_of_control_descriptor(vc); if (vc->std.bNumEndpoints) { /* Find the notification endpoint descriptor. */ cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT); @@ -506,10 +605,11 @@ static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self) static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t altnum) { TU_LOG2(" open VC %d\n", altnum); - void const *beg = self->beg; - void const *end = beg + self->len; + uint8_t const *beg = self->beg; + uint8_t const *end = beg + self->len; + /* The first descriptor is a video control interface descriptor. */ - void const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); + uint8_t const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); TU_LOG2(" cur %d\n", cur - beg); TU_VERIFY(cur < end); @@ -519,7 +619,8 @@ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t TU_ASSERT(vc->ctl.bInCollection <= CFG_TUD_VIDEO_STREAMING); /* Update to point the end of the video control interface descriptor. */ - end = cur + vc->std.bLength + vc->ctl.wTotalLength; + end = _end_of_control_descriptor(cur); + /* Advance to the next descriptor after the class-specific VC interface header descriptor. */ cur += vc->std.bLength + vc->ctl.bLength; TU_LOG2(" bNumEndpoints %d\n", vc->std.bNumEndpoints); @@ -534,7 +635,7 @@ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t /* Open the notification endpoint */ TU_ASSERT(usbd_edpt_open(rhport, notif)); } - self->cur = (uint16_t) ((void const*)vc - beg); + self->cur = (uint16_t) ((uint8_t const*)vc - beg); return true; } @@ -546,7 +647,7 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint { uint_fast8_t i; TU_LOG2(" reopen VS %d\n", altnum); - void const *desc = _videod_itf[stm->index_vc].beg; + uint8_t const *desc = _videod_itf[stm->index_vc].beg; /* Close endpoints of previous settings. */ for (i = 0; i < TU_ARRAY_SIZE(stm->desc.ep); ++i) { @@ -557,16 +658,18 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint stm->desc.ep[i] = 0; TU_LOG2(" close EP%02x\n", ep_adr); } + /* clear transfer management information */ stm->buffer = NULL; stm->bufsize = 0; stm->offset = 0; /* Find a alternate interface */ - void const *beg = desc + stm->desc.beg; - void const *end = desc + stm->desc.end; - void const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); + uint8_t const *beg = desc + stm->desc.beg; + uint8_t const *end = desc + stm->desc.end; + uint8_t const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); TU_VERIFY(cur < end); + uint_fast8_t numeps = ((tusb_desc_interface_t const *)cur)->bNumEndpoints; TU_ASSERT(numeps <= TU_ARRAY_SIZE(stm->desc.ep)); stm->desc.cur = (uint16_t) (cur - desc); /* Save the offset of the new settings */ @@ -576,6 +679,7 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint video_probe_and_commit_control_t *param = (video_probe_and_commit_control_t *)&stm->ep_buf; tu_memclr(param, sizeof(*param)); + TU_LOG2(" done 0\n"); return _update_streaming_parameters(stm, param); } /* Open endpoints of the new settings. */ @@ -604,6 +708,7 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint hdr->bHeaderLength = sizeof(*hdr); hdr->bmHeaderInfo = 0; + TU_LOG2(" done\n"); return true; } @@ -676,7 +781,7 @@ static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage, if (stage == CONTROL_STAGE_SETUP) { TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); TU_VERIFY(tud_control_xfer(rhport, request, &self->power_mode, sizeof(self->power_mode)), VIDEO_ERROR_UNKNOWN); - } else if (stage == CONTROL_STAGE_ACK) { + } else if (stage == CONTROL_STAGE_DATA) { if (tud_video_power_mode_cb) return tud_video_power_mode_cb(ctl_idx, self->power_mode); } return VIDEO_ERROR_NONE; @@ -818,10 +923,10 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, switch (request->bRequest) { case VIDEO_REQUEST_SET_CUR: if (stage == CONTROL_STAGE_SETUP) { - TU_VERIFY(sizeof(video_probe_and_commit_control_t) == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(sizeof(video_probe_and_commit_control_t) >= request->wLength, VIDEO_ERROR_UNKNOWN); TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); - } else if (stage == CONTROL_STAGE_ACK) { + } else if (stage == CONTROL_STAGE_DATA) { TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); } @@ -845,7 +950,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, video_probe_and_commit_control_t tmp; tmp = *(video_probe_and_commit_control_t*)&self->ep_buf; TU_VERIFY(_negotiate_streaming_parameters(self, request->bRequest, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); - TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, &tmp, sizeof(tmp)), VIDEO_ERROR_UNKNOWN); } return VIDEO_ERROR_NONE; @@ -862,7 +967,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, if (stage == CONTROL_STAGE_SETUP) { TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN); + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t)&_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN); } return VIDEO_ERROR_NONE; @@ -874,9 +979,9 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, switch (request->bRequest) { case VIDEO_REQUEST_SET_CUR: if (stage == CONTROL_STAGE_SETUP) { - TU_VERIFY(sizeof(video_probe_and_commit_control_t) == request->wLength, VIDEO_ERROR_UNKNOWN); + TU_VERIFY(sizeof(video_probe_and_commit_control_t) >= request->wLength, VIDEO_ERROR_UNKNOWN); TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); - } else if (stage == CONTROL_STAGE_ACK) { + } else if (stage == CONTROL_STAGE_DATA) { TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); if (tud_video_commit_cb) { return tud_video_commit_cb(self->index_vc, self->index_vs, (video_probe_and_commit_control_t*)self->ep_buf); @@ -944,7 +1049,6 @@ static int handle_video_stm_req(uint8_t rhport, uint8_t stage, default: return VIDEO_ERROR_INVALID_REQUEST; } - return VIDEO_ERROR_UNKNOWN; } //--------------------------------------------------------------------+ @@ -977,7 +1081,7 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu if (!stm || !stm->desc.ep[0] || stm->buffer) return false; /* Find EP address */ - void const *desc = _videod_itf[stm->index_vc].beg; + uint8_t const *desc = _videod_itf[stm->index_vc].beg; uint8_t ep_addr = 0; for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { uint_fast16_t ofs_ep = stm->desc.ep[i]; @@ -1044,13 +1148,15 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin } TU_ASSERT(ctl_idx < CFG_TUD_VIDEO, 0); - void const *end = (void const*)itf_desc + max_len; - self->beg = itf_desc; + uint8_t const *end = (uint8_t const*)itf_desc + max_len; + self->beg = (uint8_t const*) itf_desc; self->len = max_len; + /*------------- Video Control Interface -------------*/ TU_VERIFY(_open_vc_itf(rhport, self, 0), 0); tusb_desc_vc_itf_t const *vc = _get_desc_vc(self); uint_fast8_t bInCollection = vc->ctl.bInCollection; + /* Find the end of the video interface descriptor */ void const *cur = _next_desc_itf(itf_desc, end); for (uint8_t stm_idx = 0; stm_idx < bInCollection; ++stm_idx) { @@ -1101,7 +1207,7 @@ bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_ for (itf = 0; itf < CFG_TUD_VIDEO_STREAMING; ++itf) { videod_streaming_interface_t *stm = &_videod_streaming_itf[itf]; if (!stm->desc.beg) continue; - void const *desc = _videod_itf[stm->index_vc].beg; + uint8_t const *desc = _videod_itf[stm->index_vc].beg; if (itfnum == _desc_itfnum(desc + stm->desc.beg)) break; } @@ -1127,7 +1233,7 @@ bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 uint_fast16_t const ep_ofs = stm->desc.ep[0]; if (!ep_ofs) continue; ctl = &_videod_itf[stm->index_vc]; - void const *desc = ctl->beg; + uint8_t const *desc = ctl->beg; if (ep_addr == _desc_ep_addr(desc + ep_ofs)) break; } diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_common.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_common.h index b1ee40a1..957491aa 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_common.h +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_common.h @@ -75,6 +75,21 @@ #include "tusb_timeout.h" // TODO remove +//--------------------------------------------------------------------+ +// Optional API implemented by application if needed +// TODO move to a more ovious place/file +//--------------------------------------------------------------------+ + +// flush data cache +TU_ATTR_WEAK extern void tusb_app_dcache_flush(uintptr_t addr, uint32_t data_size); + +// invalidate data cache +TU_ATTR_WEAK extern void tusb_app_dcache_invalidate(uintptr_t addr, uint32_t data_size); + +// Optional physical <-> virtual address translation +TU_ATTR_WEAK extern void* tusb_app_virt_to_phys(void *virt_addr); +TU_ATTR_WEAK extern void* tusb_app_phys_to_virt(void *phys_addr); + //--------------------------------------------------------------------+ // Internal Inline Functions //--------------------------------------------------------------------+ @@ -83,6 +98,29 @@ #define tu_memclr(buffer, size) memset((buffer), 0, (size)) #define tu_varclr(_var) tu_memclr(_var, sizeof(*(_var))) +// This is a backport of memset_s from c11 +TU_ATTR_ALWAYS_INLINE static inline int tu_memset_s(void *dest, size_t destsz, int ch, size_t count) +{ + // TODO may check if desst and src is not NULL + if (count > destsz) { + return -1; + } + memset(dest, ch, count); + return 0; +} + +// This is a backport of memcpy_s from c11 +TU_ATTR_ALWAYS_INLINE static inline int tu_memcpy_s(void *dest, size_t destsz, const void * src, size_t count ) +{ + // TODO may check if desst and src is not NULL + if (count > destsz) { + return -1; + } + memcpy(dest, src, count); + return 0; +} + + //------------- Bytes -------------// TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_u32(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0) { diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_compiler.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_compiler.h index 2c30daf6..5ab56e14 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_compiler.h +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_compiler.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -61,6 +61,13 @@ #define TU_VERIFY_STATIC(const_expr, _mess) enum { TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1/(!!(const_expr)) } #endif +/* --------------------- Fuzzing types -------------------------------------- */ +#ifdef _FUZZ + #define tu_static static __thread +#else + #define tu_static static +#endif + // for declaration of reserved field, make use of _TU_COUNTER_ #define TU_RESERVED TU_XSTRCAT(reserved, _TU_COUNTER_) @@ -76,9 +83,9 @@ * - ##__VA_ARGS__ is used to deal with 0 paramerter (swallows comma) *------------------------------------------------------------------*/ #if !defined(__CCRX__) -#define TU_ARGS_NUM(...) _TU_NARG(_0, ##__VA_ARGS__,_RSEQ_N()) +#define TU_ARGS_NUM(...) _TU_NARG(_0, ##__VA_ARGS__, _RSEQ_N()) #else -#define TU_ARGS_NUM(...) _TU_NARG(_0, __VA_ARGS__,_RSEQ_N()) +#define TU_ARGS_NUM(...) _TU_NARG(_0, __VA_ARGS__, _RSEQ_N()) #endif #define _TU_NARG(...) _GET_NTH_ARG(__VA_ARGS__) @@ -131,10 +138,14 @@ #define TU_ATTR_BIT_FIELD_ORDER_BEGIN #define TU_ATTR_BIT_FIELD_ORDER_END - #if __has_attribute(__fallthrough__) - #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough)) - #else + #if __GNUC__ < 5 #define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */ + #else + #if __has_attribute(__fallthrough__) + #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough)) + #else + #define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */ + #endif #endif // Endian conversion use well-known host to network (big endian) naming @@ -144,8 +155,17 @@ #define TU_BYTE_ORDER TU_BIG_ENDIAN #endif - #define TU_BSWAP16(u16) (__builtin_bswap16(u16)) - #define TU_BSWAP32(u32) (__builtin_bswap32(u32)) + // Unfortunately XC16 doesn't provide builtins for 32bit endian conversion + #if defined(__XC16) + #define TU_BSWAP16(u16) (__builtin_swap(u16)) + #define TU_BSWAP32(u32) ((((u32) & 0xff000000) >> 24) | \ + (((u32) & 0x00ff0000) >> 8) | \ + (((u32) & 0x0000ff00) << 8) | \ + (((u32) & 0x000000ff) << 24)) + #else + #define TU_BSWAP16(u16) (__builtin_bswap16(u16)) + #define TU_BSWAP32(u32) (__builtin_bswap32(u32)) + #endif #ifndef __ARMCC_VERSION // List of obsolete callback function that is renamed and should not be defined. @@ -189,7 +209,7 @@ #define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used #define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused #define TU_ATTR_USED __attribute__ ((used)) // Function/Variable is meant to be used - #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough)) + #define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */ #define TU_ATTR_PACKED_BEGIN #define TU_ATTR_PACKED_END @@ -232,7 +252,7 @@ #define TU_BSWAP16(u16) ((unsigned short)_builtin_revw((unsigned long)u16)) #define TU_BSWAP32(u32) (_builtin_revl(u32)) -#else +#else #error "Compiler attribute porting is required" #endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_debug.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_debug.h index ac5bee6e..82f68204 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_debug.h +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_debug.h @@ -66,7 +66,7 @@ static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) #define TU_LOG(n, ...) TU_XSTRCAT(TU_LOG, n)(__VA_ARGS__) #define TU_LOG_MEM(n, ...) TU_XSTRCAT3(TU_LOG, n, _MEM)(__VA_ARGS__) #define TU_LOG_ARR(n, ...) TU_XSTRCAT3(TU_LOG, n, _ARR)(__VA_ARGS__) -#define TU_LOG_VAR(n, ...) TU_XSTRCAT3(TU_LOG, n, _VAR)(__VA_ARGS__) +#define TU_LOG_PTR(n, ...) TU_XSTRCAT3(TU_LOG, n, _PTR)(__VA_ARGS__) #define TU_LOG_INT(n, ...) TU_XSTRCAT3(TU_LOG, n, _INT)(__VA_ARGS__) #define TU_LOG_HEX(n, ...) TU_XSTRCAT3(TU_LOG, n, _HEX)(__VA_ARGS__) #define TU_LOG_LOCATION() tu_printf("%s: %d:\r\n", __PRETTY_FUNCTION__, __LINE__) @@ -76,7 +76,7 @@ static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) #define TU_LOG1 tu_printf #define TU_LOG1_MEM tu_print_mem #define TU_LOG1_ARR(_x, _n) tu_print_arr((uint8_t const*)(_x), _n) -#define TU_LOG1_VAR(_x) tu_print_arr((uint8_t const*)(_x), sizeof(*(_x))) +#define TU_LOG1_PTR(_x) tu_print_arr((uint8_t const*)(_x), sizeof(*(_x))) #define TU_LOG1_INT(_x) tu_printf(#_x " = %ld\r\n", (unsigned long) (_x) ) #define TU_LOG1_HEX(_x) tu_printf(#_x " = %lX\r\n", (unsigned long) (_x) ) @@ -85,7 +85,7 @@ static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) #define TU_LOG2 TU_LOG1 #define TU_LOG2_MEM TU_LOG1_MEM #define TU_LOG2_ARR TU_LOG1_ARR - #define TU_LOG2_VAR TU_LOG1_VAR + #define TU_LOG2_PTR TU_LOG1_PTR #define TU_LOG2_INT TU_LOG1_INT #define TU_LOG2_HEX TU_LOG1_HEX #endif @@ -95,7 +95,7 @@ static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) #define TU_LOG3 TU_LOG1 #define TU_LOG3_MEM TU_LOG1_MEM #define TU_LOG3_ARR TU_LOG1_ARR - #define TU_LOG3_VAR TU_LOG1_VAR + #define TU_LOG3_PTR TU_LOG1_PTR #define TU_LOG3_INT TU_LOG1_INT #define TU_LOG3_HEX TU_LOG1_HEX #endif @@ -114,7 +114,7 @@ typedef struct static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) { - static char not_found[11]; + tu_static char not_found[11]; for(uint16_t i=0; icount; i++) { @@ -132,7 +132,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG #define TU_LOG(n, ...) #define TU_LOG_MEM(n, ...) - #define TU_LOG_VAR(n, ...) + #define TU_LOG_PTR(n, ...) #define TU_LOG_INT(n, ...) #define TU_LOG_HEX(n, ...) #define TU_LOG_LOCATION() @@ -143,14 +143,14 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #define TU_LOG0(...) #define TU_LOG0_MEM(...) -#define TU_LOG0_VAR(...) +#define TU_LOG0_PTR(...) #define TU_LOG0_INT(...) #define TU_LOG0_HEX(...) #ifndef TU_LOG1 #define TU_LOG1(...) #define TU_LOG1_MEM(...) - #define TU_LOG1_VAR(...) + #define TU_LOG1_PTR(...) #define TU_LOG1_INT(...) #define TU_LOG1_HEX(...) #endif @@ -158,7 +158,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG2 #define TU_LOG2(...) #define TU_LOG2_MEM(...) - #define TU_LOG2_VAR(...) + #define TU_LOG2_PTR(...) #define TU_LOG2_INT(...) #define TU_LOG2_HEX(...) #endif @@ -166,7 +166,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG3 #define TU_LOG3(...) #define TU_LOG3_MEM(...) - #define TU_LOG3_VAR(...) + #define TU_LOG3_PTR(...) #define TU_LOG3_INT(...) #define TU_LOG3_HEX(...) #endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.c b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.c index b9bcdc7a..a52c9226 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.c +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.c @@ -28,21 +28,22 @@ #include "osal/osal.h" #include "tusb_fifo.h" -// Supress IAR warning +#define TU_FIFO_DBG 0 + +// Suppress IAR warning // Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement #if defined(__ICCARM__) #pragma diag_suppress = Pa082 #endif -// implement mutex lock and unlock -#if CFG_FIFO_MUTEX +#if OSAL_MUTEX_REQUIRED -static inline void _ff_lock(tu_fifo_mutex_t mutex) +TU_ATTR_ALWAYS_INLINE static inline void _ff_lock(osal_mutex_t mutex) { if (mutex) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); } -static inline void _ff_unlock(tu_fifo_mutex_t mutex) +TU_ATTR_ALWAYS_INLINE static inline void _ff_unlock(osal_mutex_t mutex) { if (mutex) osal_mutex_unlock(mutex); } @@ -66,23 +67,20 @@ typedef enum bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable) { - if (depth > 0x8000) return false; // Maximum depth is 2^15 items + // Limit index space to 2*depth - this allows for a fast "modulo" calculation + // but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable + // only if overflow happens once (important for unsupervised DMA applications) + if (depth > 0x8000) return false; _ff_lock(f->mutex_wr); _ff_lock(f->mutex_rd); - f->buffer = (uint8_t*) buffer; - f->depth = depth; - f->item_size = item_size; + f->buffer = (uint8_t*) buffer; + f->depth = depth; + f->item_size = (uint16_t) (item_size & 0x7FFF); f->overwritable = overwritable; - - // Limit index space to 2*depth - this allows for a fast "modulo" calculation - // but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable - // only if overflow happens once (important for unsupervised DMA applications) - f->max_pointer_idx = (uint16_t) (2*depth - 1); - f->non_used_index_space = UINT16_MAX - f->max_pointer_idx; - - f->rd_idx = f->wr_idx = 0; + f->rd_idx = 0; + f->wr_idx = 0; _ff_unlock(f->mutex_wr); _ff_unlock(f->mutex_rd); @@ -90,25 +88,22 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si return true; } -// Static functions are intended to work on local variables -static inline uint16_t _ff_mod(uint16_t idx, uint16_t depth) -{ - while ( idx >= depth) idx -= depth; - return idx; -} +//--------------------------------------------------------------------+ +// Pull & Push +//--------------------------------------------------------------------+ // Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address -// Code adapted from dcd_synopsis.c +// Code adapted from dcd_synopsys.c // TODO generalize with configurable 1 byte or 4 byte each read static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t len) { - volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf; + volatile const uint32_t * reg_rx = (volatile const uint32_t *) app_buf; // Reading full available 32 bit words from const app address - uint8_t * ff_buf_end = ff_buf + (len & 0xfffc); - while(ff_buf < ff_buf_end) + uint16_t full_words = len >> 2; + while(full_words--) { - tu_unaligned_write32(ff_buf, *rx_fifo); + tu_unaligned_write32(ff_buf, *reg_rx); ff_buf += 4; } @@ -116,7 +111,7 @@ static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t uint8_t const bytes_rem = len & 0x03; if ( bytes_rem ) { - uint32_t tmp32 = *rx_fifo; + uint32_t tmp32 = *reg_rx; memcpy(ff_buf, &tmp32, bytes_rem); } } @@ -125,49 +120,49 @@ static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t // where all data is written to a constant address in full word copies static void _ff_pull_const_addr(void * app_buf, const uint8_t * ff_buf, uint16_t len) { - volatile uint32_t * tx_fifo = (volatile uint32_t *) app_buf; + volatile uint32_t * reg_tx = (volatile uint32_t *) app_buf; - // Pushing full available 32 bit words to const app address - const uint8_t * ff_buf_end = ff_buf + (len & 0xfffc); - while(ff_buf < ff_buf_end) + // Write full available 32 bit words to const address + uint16_t full_words = len >> 2; + while(full_words--) { - *tx_fifo = tu_unaligned_read32(ff_buf); + *reg_tx = tu_unaligned_read32(ff_buf); ff_buf += 4; } - // Write the remaining 1-3 bytes into const app address + // Write the remaining 1-3 bytes into const address uint8_t const bytes_rem = len & 0x03; if ( bytes_rem ) { uint32_t tmp32 = 0; memcpy(&tmp32, ff_buf, bytes_rem); - *tx_fifo = tmp32; + *reg_tx = tmp32; } } -// send one item to FIFO WITHOUT updating write pointer +// send one item to fifo WITHOUT updating write pointer static inline void _ff_push(tu_fifo_t* f, void const * app_buf, uint16_t rel) { memcpy(f->buffer + (rel * f->item_size), app_buf, f->item_size); } -// send n items to FIFO WITHOUT updating write pointer -static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode) +// send n items to fifo WITHOUT updating write pointer +static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t wr_ptr, tu_fifo_copy_mode_t copy_mode) { - uint16_t const nLin = f->depth - rel; - uint16_t const nWrap = n - nLin; + uint16_t const lin_count = f->depth - wr_ptr; + uint16_t const wrap_count = n - lin_count; - uint16_t nLin_bytes = nLin * f->item_size; - uint16_t nWrap_bytes = nWrap * f->item_size; + uint16_t lin_bytes = lin_count * f->item_size; + uint16_t wrap_bytes = wrap_count * f->item_size; // current buffer of fifo - uint8_t* ff_buf = f->buffer + (rel * f->item_size); + uint8_t* ff_buf = f->buffer + (wr_ptr * f->item_size); switch (copy_mode) { case TU_FIFO_COPY_INC: - if(n <= nLin) + if(n <= lin_count) { // Linear only memcpy(ff_buf, app_buf, n*f->item_size); @@ -177,16 +172,17 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t // Wrap around // Write data to linear part of buffer - memcpy(ff_buf, app_buf, nLin_bytes); + memcpy(ff_buf, app_buf, lin_bytes); // Write data wrapped around - memcpy(f->buffer, ((uint8_t const*) app_buf) + nLin_bytes, nWrap_bytes); + // TU_ASSERT(nWrap_bytes <= f->depth, ); + memcpy(f->buffer, ((uint8_t const*) app_buf) + lin_bytes, wrap_bytes); } break; case TU_FIFO_COPY_CST_FULL_WORDS: // Intended for hardware buffers from which it can be read word by word only - if(n <= nLin) + if(n <= lin_count) { // Linear only _ff_push_const_addr(ff_buf, app_buf, n*f->item_size); @@ -196,17 +192,18 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t // Wrap around case // Write full words to linear part of buffer - uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC; + uint16_t nLin_4n_bytes = lin_bytes & 0xFFFC; _ff_push_const_addr(ff_buf, app_buf, nLin_4n_bytes); ff_buf += nLin_4n_bytes; // There could be odd 1-3 bytes before the wrap-around boundary - volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf; - uint8_t rem = nLin_bytes & 0x03; + uint8_t rem = lin_bytes & 0x03; if (rem > 0) { - uint8_t remrem = (uint8_t) tu_min16(nWrap_bytes, 4-rem); - nWrap_bytes -= remrem; + volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf; + + uint8_t remrem = (uint8_t) tu_min16(wrap_bytes, 4-rem); + wrap_bytes -= remrem; uint32_t tmp32 = *rx_fifo; uint8_t * src_u8 = ((uint8_t *) &tmp32); @@ -224,34 +221,34 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t } // Write data wrapped part - if (nWrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, nWrap_bytes); + if (wrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, wrap_bytes); } break; } } -// get one item from FIFO WITHOUT updating read pointer +// get one item from fifo WITHOUT updating read pointer static inline void _ff_pull(tu_fifo_t* f, void * app_buf, uint16_t rel) { memcpy(app_buf, f->buffer + (rel * f->item_size), f->item_size); } -// get n items from FIFO WITHOUT updating read pointer -static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode) +// get n items from fifo WITHOUT updating read pointer +static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rd_ptr, tu_fifo_copy_mode_t copy_mode) { - uint16_t const nLin = f->depth - rel; - uint16_t const nWrap = n - nLin; // only used if wrapped + uint16_t const lin_count = f->depth - rd_ptr; + uint16_t const wrap_count = n - lin_count; // only used if wrapped - uint16_t nLin_bytes = nLin * f->item_size; - uint16_t nWrap_bytes = nWrap * f->item_size; + uint16_t lin_bytes = lin_count * f->item_size; + uint16_t wrap_bytes = wrap_count * f->item_size; // current buffer of fifo - uint8_t* ff_buf = f->buffer + (rel * f->item_size); + uint8_t* ff_buf = f->buffer + (rd_ptr * f->item_size); switch (copy_mode) { case TU_FIFO_COPY_INC: - if ( n <= nLin ) + if ( n <= lin_count ) { // Linear only memcpy(app_buf, ff_buf, n*f->item_size); @@ -261,15 +258,15 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu // Wrap around // Read data from linear part of buffer - memcpy(app_buf, ff_buf, nLin_bytes); + memcpy(app_buf, ff_buf, lin_bytes); // Read data wrapped part - memcpy((uint8_t*) app_buf + nLin_bytes, f->buffer, nWrap_bytes); + memcpy((uint8_t*) app_buf + lin_bytes, f->buffer, wrap_bytes); } break; case TU_FIFO_COPY_CST_FULL_WORDS: - if ( n <= nLin ) + if ( n <= lin_count ) { // Linear only _ff_pull_const_addr(app_buf, ff_buf, n*f->item_size); @@ -279,17 +276,18 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu // Wrap around case // Read full words from linear part of buffer - uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC; - _ff_pull_const_addr(app_buf, ff_buf, nLin_4n_bytes); - ff_buf += nLin_4n_bytes; + uint16_t lin_4n_bytes = lin_bytes & 0xFFFC; + _ff_pull_const_addr(app_buf, ff_buf, lin_4n_bytes); + ff_buf += lin_4n_bytes; // There could be odd 1-3 bytes before the wrap-around boundary - volatile uint32_t * tx_fifo = (volatile uint32_t *) app_buf; - uint8_t rem = nLin_bytes & 0x03; + uint8_t rem = lin_bytes & 0x03; if (rem > 0) { - uint8_t remrem = (uint8_t) tu_min16(nWrap_bytes, 4-rem); - nWrap_bytes -= remrem; + volatile uint32_t * reg_tx = (volatile uint32_t *) app_buf; + + uint8_t remrem = (uint8_t) tu_min16(wrap_bytes, 4-rem); + wrap_bytes -= remrem; uint32_t tmp32=0; uint8_t * dst_u8 = (uint8_t *)&tmp32; @@ -301,7 +299,7 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu ff_buf = f->buffer; while(remrem--) *dst_u8++ = *ff_buf++; - *tx_fifo = tmp32; + *reg_tx = tmp32; } else { @@ -309,7 +307,7 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu } // Read data wrapped part - if (nWrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, nWrap_bytes); + if (wrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, wrap_bytes); } break; @@ -317,178 +315,232 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu } } -// Advance an absolute pointer -static uint16_t advance_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) +//--------------------------------------------------------------------+ +// Helper +//--------------------------------------------------------------------+ + +// return only the index difference and as such can be used to determine an overflow i.e overflowable count +TU_ATTR_ALWAYS_INLINE static inline +uint16_t _ff_count(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) { - // We limit the index space of p such that a correct wrap around happens - // Check for a wrap around or if we are in unused index space - This has to be checked first!! - // We are exploiting the wrap around to the correct index - if ((p > (uint16_t)(p + offset)) || ((uint16_t)(p + offset) > f->max_pointer_idx)) + // In case we have non-power of two depth we need a further modification + if (wr_idx >= rd_idx) { - p = (uint16_t) ((p + offset) + f->non_used_index_space); - } - else + return (uint16_t) (wr_idx - rd_idx); + } else { - p += offset; + return (uint16_t) (2*depth - (rd_idx - wr_idx)); } - return p; } -// Backward an absolute pointer -static uint16_t backward_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) +// return remaining slot in fifo +TU_ATTR_ALWAYS_INLINE static inline +uint16_t _ff_remaining(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) +{ + uint16_t const count = _ff_count(depth, wr_idx, rd_idx); + return (depth > count) ? (depth - count) : 0; +} + +//--------------------------------------------------------------------+ +// Index Helper +//--------------------------------------------------------------------+ + +// Advance an absolute index +// "absolute" index is only in the range of [0..2*depth) +static uint16_t advance_index(uint16_t depth, uint16_t idx, uint16_t offset) { // We limit the index space of p such that a correct wrap around happens // Check for a wrap around or if we are in unused index space - This has to be checked first!! // We are exploiting the wrap around to the correct index - if ((p < (uint16_t)(p - offset)) || ((uint16_t)(p - offset) > f->max_pointer_idx)) + uint16_t new_idx = (uint16_t) (idx + offset); + if ( (idx > new_idx) || (new_idx >= 2*depth) ) { - p = (uint16_t) ((p - offset) - f->non_used_index_space); + uint16_t const non_used_index_space = (uint16_t) (UINT16_MAX - (2*depth-1)); + new_idx = (uint16_t) (new_idx + non_used_index_space); } - else - { - p -= offset; - } - return p; -} -// get relative from absolute pointer -static uint16_t get_relative_pointer(tu_fifo_t* f, uint16_t p) -{ - return _ff_mod(p, f->depth); + return new_idx; } -// Works on local copies of w and r - return only the difference and as such can be used to determine an overflow -static inline uint16_t _tu_fifo_count(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) +#if 0 // not used but +// Backward an absolute index +static uint16_t backward_index(uint16_t depth, uint16_t idx, uint16_t offset) { - uint16_t cnt = wAbs-rAbs; - - // In case we have non-power of two depth we need a further modification - if (rAbs > wAbs) cnt -= f->non_used_index_space; + // We limit the index space of p such that a correct wrap around happens + // Check for a wrap around or if we are in unused index space - This has to be checked first!! + // We are exploiting the wrap around to the correct index + uint16_t new_idx = (uint16_t) (idx - offset); + if ( (idx < new_idx) || (new_idx >= 2*depth) ) + { + uint16_t const non_used_index_space = (uint16_t) (UINT16_MAX - (2*depth-1)); + new_idx = (uint16_t) (new_idx - non_used_index_space); + } - return cnt; + return new_idx; } +#endif -// Works on local copies of w and r -static inline bool _tu_fifo_empty(uint16_t wAbs, uint16_t rAbs) +// index to pointer, simply an modulo with minus. +TU_ATTR_ALWAYS_INLINE static inline +uint16_t idx2ptr(uint16_t depth, uint16_t idx) { - return wAbs == rAbs; + // Only run at most 3 times since index is limit in the range of [0..2*depth) + while ( idx >= depth ) idx -= depth; + return idx; } -// Works on local copies of w and r -static inline bool _tu_fifo_full(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) +// Works on local copies of w +// When an overwritable fifo is overflowed, rd_idx will be re-index so that it forms +// an full fifo i.e _ff_count() = depth +TU_ATTR_ALWAYS_INLINE static inline +uint16_t _ff_correct_read_index(tu_fifo_t* f, uint16_t wr_idx) { - return (_tu_fifo_count(f, wAbs, rAbs) == f->depth); -} + uint16_t rd_idx; + if ( wr_idx >= f->depth ) + { + rd_idx = wr_idx - f->depth; + }else + { + rd_idx = wr_idx + f->depth; + } -// Works on local copies of w and r -// BE AWARE - THIS FUNCTION MIGHT NOT GIVE A CORRECT ANSWERE IN CASE WRITE POINTER "OVERFLOWS" -// Only one overflow is allowed for this function to work e.g. if depth = 100, you must not -// write more than 2*depth-1 items in one rush without updating write pointer. Otherwise -// write pointer wraps and you pointer states are messed up. This can only happen if you -// use DMAs, write functions do not allow such an error. -static inline bool _tu_fifo_overflowed(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) -{ - return (_tu_fifo_count(f, wAbs, rAbs) > f->depth); -} + f->rd_idx = rd_idx; -// Works on local copies of w -// For more details see _tu_fifo_overflow()! -static inline void _tu_fifo_correct_read_pointer(tu_fifo_t* f, uint16_t wAbs) -{ - f->rd_idx = backward_pointer(f, wAbs, f->depth); + return rd_idx; } // Works on local copies of w and r // Must be protected by mutexes since in case of an overflow read pointer gets modified -static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wAbs, uint16_t rAbs) +static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wr_idx, uint16_t rd_idx) { - uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs); + uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); + + // nothing to peek + if ( cnt == 0 ) return false; // Check overflow and correct if required - if (cnt > f->depth) + if ( cnt > f->depth ) { - _tu_fifo_correct_read_pointer(f, wAbs); + rd_idx = _ff_correct_read_index(f, wr_idx); cnt = f->depth; } - // Skip beginning of buffer - if (cnt == 0) return false; - - uint16_t rRel = get_relative_pointer(f, rAbs); + uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); // Peek data - _ff_pull(f, p_buffer, rRel); + _ff_pull(f, p_buffer, rd_ptr); return true; } // Works on local copies of w and r // Must be protected by mutexes since in case of an overflow read pointer gets modified -static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t wAbs, uint16_t rAbs, tu_fifo_copy_mode_t copy_mode) +static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx, tu_fifo_copy_mode_t copy_mode) { - uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs); + uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); + + // nothing to peek + if ( cnt == 0 ) return 0; // Check overflow and correct if required - if (cnt > f->depth) + if ( cnt > f->depth ) { - _tu_fifo_correct_read_pointer(f, wAbs); - rAbs = f->rd_idx; + rd_idx = _ff_correct_read_index(f, wr_idx); cnt = f->depth; } - // Skip beginning of buffer - if (cnt == 0) return 0; - // Check if we can read something at and after offset - if too less is available we read what remains - if (cnt < n) n = cnt; + if ( cnt < n ) n = cnt; - uint16_t rRel = get_relative_pointer(f, rAbs); + uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); // Peek data - _ff_pull_n(f, p_buffer, n, rRel, copy_mode); + _ff_pull_n(f, p_buffer, n, rd_ptr, copy_mode); return n; } -// Works on local copies of w and r -static inline uint16_t _tu_fifo_remaining(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) -{ - return f->depth - _tu_fifo_count(f, wAbs, rAbs); -} - static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu_fifo_copy_mode_t copy_mode) { if ( n == 0 ) return 0; _ff_lock(f->mutex_wr); - uint16_t w = f->wr_idx, r = f->rd_idx; + uint16_t wr_idx = f->wr_idx; + uint16_t rd_idx = f->rd_idx; + uint8_t const* buf8 = (uint8_t const*) data; - if (!f->overwritable) + TU_LOG(TU_FIFO_DBG, "rd = %3u, wr = %3u, count = %3u, remain = %3u, n = %3u: ", + rd_idx, wr_idx, _ff_count(f->depth, wr_idx, rd_idx), _ff_remaining(f->depth, wr_idx, rd_idx), n); + + if ( !f->overwritable ) { - // Not overwritable limit up to full - n = tu_min16(n, _tu_fifo_remaining(f, w, r)); + // limit up to full + uint16_t const remain = _ff_remaining(f->depth, wr_idx, rd_idx); + n = tu_min16(n, remain); } - else if (n >= f->depth) + else { - // Only copy last part - buf8 = buf8 + (n - f->depth) * f->item_size; - n = f->depth; - - // We start writing at the read pointer's position since we fill the complete - // buffer and we do not want to modify the read pointer within a write function! - // This would end up in a race condition with read functions! - w = r; + // In over-writable mode, fifo_write() is allowed even when fifo is full. In such case, + // oldest data in fifo i.e at read pointer data will be overwritten + // Note: we can modify read buffer contents but we must not modify the read index itself within a write function! + // Since it would end up in a race condition with read functions! + if ( n >= f->depth ) + { + // Only copy last part + if ( copy_mode == TU_FIFO_COPY_INC ) + { + buf8 += (n - f->depth) * f->item_size; + }else + { + // TODO should read from hw fifo to discard data, however reading an odd number could + // accidentally discard data. + } + + n = f->depth; + + // We start writing at the read pointer's position since we fill the whole buffer + wr_idx = rd_idx; + } + else + { + uint16_t const overflowable_count = _ff_count(f->depth, wr_idx, rd_idx); + if (overflowable_count + n >= 2*f->depth) + { + // Double overflowed + // Index is bigger than the allowed range [0,2*depth) + // re-position write index to have a full fifo after pushed + wr_idx = advance_index(f->depth, rd_idx, f->depth - n); + + // TODO we should also shift out n bytes from read index since we avoid changing rd index !! + // However memmove() is expensive due to actual copying + wrapping consideration. + // Also race condition could happen anyway if read() is invoke while moving result in corrupted memory + // currently deliberately not implemented --> result in incorrect data read back + }else + { + // normal + single overflowed: + // Index is in the range of [0,2*depth) and thus detect and recoverable. Recovering is handled in read() + // Therefore we just increase write index + // we will correct (re-position) read index later on in fifo_read() function + } + } } - uint16_t wRel = get_relative_pointer(f, w); + if (n) + { + uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); - // Write data - _ff_push_n(f, buf8, n, wRel, copy_mode); + TU_LOG(TU_FIFO_DBG, "actual_n = %u, wr_ptr = %u", n, wr_ptr); - // Advance pointer - f->wr_idx = advance_pointer(f, w, n); + // Write data + _ff_push_n(f, buf8, n, wr_ptr, copy_mode); + + // Advance index + f->wr_idx = advance_index(f->depth, wr_idx, n); + + TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\n", f->wr_idx); + } _ff_unlock(f->mutex_wr); @@ -504,12 +556,16 @@ static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo n = _tu_fifo_peek_n(f, buffer, n, f->wr_idx, f->rd_idx, copy_mode); // Advance read pointer - f->rd_idx = advance_pointer(f, f->rd_idx, n); + f->rd_idx = advance_index(f->depth, f->rd_idx, n); _ff_unlock(f->mutex_rd); return n; } +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + /******************************************************************************/ /*! @brief Get number of items in FIFO. @@ -527,7 +583,7 @@ static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo /******************************************************************************/ uint16_t tu_fifo_count(tu_fifo_t* f) { - return tu_min16(_tu_fifo_count(f, f->wr_idx, f->rd_idx), f->depth); + return tu_min16(_ff_count(f->depth, f->wr_idx, f->rd_idx), f->depth); } /******************************************************************************/ @@ -545,7 +601,7 @@ uint16_t tu_fifo_count(tu_fifo_t* f) /******************************************************************************/ bool tu_fifo_empty(tu_fifo_t* f) { - return _tu_fifo_empty(f->wr_idx, f->rd_idx); + return f->wr_idx == f->rd_idx; } /******************************************************************************/ @@ -563,7 +619,7 @@ bool tu_fifo_empty(tu_fifo_t* f) /******************************************************************************/ bool tu_fifo_full(tu_fifo_t* f) { - return _tu_fifo_full(f, f->wr_idx, f->rd_idx); + return _ff_count(f->depth, f->wr_idx, f->rd_idx) >= f->depth; } /******************************************************************************/ @@ -581,7 +637,7 @@ bool tu_fifo_full(tu_fifo_t* f) /******************************************************************************/ uint16_t tu_fifo_remaining(tu_fifo_t* f) { - return _tu_fifo_remaining(f, f->wr_idx, f->rd_idx); + return _ff_remaining(f->depth, f->wr_idx, f->rd_idx); } /******************************************************************************/ @@ -607,14 +663,14 @@ uint16_t tu_fifo_remaining(tu_fifo_t* f) /******************************************************************************/ bool tu_fifo_overflowed(tu_fifo_t* f) { - return _tu_fifo_overflowed(f, f->wr_idx, f->rd_idx); + return _ff_count(f->depth, f->wr_idx, f->rd_idx) > f->depth; } // Only use in case tu_fifo_overflow() returned true! void tu_fifo_correct_read_pointer(tu_fifo_t* f) { _ff_lock(f->mutex_rd); - _tu_fifo_correct_read_pointer(f, f->wr_idx); + _ff_correct_read_index(f, f->wr_idx); _ff_unlock(f->mutex_rd); } @@ -643,7 +699,7 @@ bool tu_fifo_read(tu_fifo_t* f, void * buffer) bool ret = _tu_fifo_peek(f, buffer, f->wr_idx, f->rd_idx); // Advance pointer - f->rd_idx = advance_pointer(f, f->rd_idx, ret); + f->rd_idx = advance_index(f->depth, f->rd_idx, ret); _ff_unlock(f->mutex_rd); return ret; @@ -682,8 +738,6 @@ uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t* f, void * buffer, uint1 @param[in] f Pointer to the FIFO buffer to manipulate - @param[in] offset - Position to read from in the FIFO buffer with respect to read pointer @param[in] p_buffer Pointer to the place holder for data read from the buffer @@ -742,20 +796,20 @@ bool tu_fifo_write(tu_fifo_t* f, const void * data) _ff_lock(f->mutex_wr); bool ret; - uint16_t const w = f->wr_idx; + uint16_t const wr_idx = f->wr_idx; - if ( _tu_fifo_full(f, w, f->rd_idx) && !f->overwritable ) + if ( tu_fifo_full(f) && !f->overwritable ) { ret = false; }else { - uint16_t wRel = get_relative_pointer(f, w); + uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); // Write data - _ff_push(f, data, wRel); + _ff_push(f, data, wr_ptr); // Advance pointer - f->wr_idx = advance_pointer(f, w, 1); + f->wr_idx = advance_index(f->depth, wr_idx, 1); ret = true; } @@ -817,9 +871,8 @@ bool tu_fifo_clear(tu_fifo_t *f) _ff_lock(f->mutex_wr); _ff_lock(f->mutex_rd); - f->rd_idx = f->wr_idx = 0; - f->max_pointer_idx = (uint16_t) (2*f->depth-1); - f->non_used_index_space = UINT16_MAX - f->max_pointer_idx; + f->rd_idx = 0; + f->wr_idx = 0; _ff_unlock(f->mutex_wr); _ff_unlock(f->mutex_rd); @@ -857,7 +910,7 @@ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) As long as the DMA is the only process writing into the FIFO this is safe to use. - USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE! + USE WITH CARE - WE DO NOT CONDUCT SAFETY CHECKS HERE! @param[in] f Pointer to the FIFO buffer to manipulate @@ -867,7 +920,7 @@ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) /******************************************************************************/ void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n) { - f->wr_idx = advance_pointer(f, f->wr_idx, n); + f->wr_idx = advance_index(f->depth, f->wr_idx, n); } /******************************************************************************/ @@ -878,7 +931,7 @@ void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n) FIFO. As long as the DMA is the only process reading from the FIFO this is safe to use. - USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE! + USE WITH CARE - WE DO NOT CONDUCT SAFETY CHECKS HERE! @param[in] f Pointer to the FIFO buffer to manipulate @@ -888,7 +941,7 @@ void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n) /******************************************************************************/ void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n) { - f->rd_idx = advance_pointer(f, f->rd_idx, n); + f->rd_idx = advance_index(f->depth, f->rd_idx, n); } /******************************************************************************/ @@ -909,17 +962,18 @@ void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n) void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { // Operate on temporary values in case they change in between - uint16_t w = f->wr_idx, r = f->rd_idx; + uint16_t wr_idx = f->wr_idx; + uint16_t rd_idx = f->rd_idx; - uint16_t cnt = _tu_fifo_count(f, w, r); + uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); // Check overflow and correct if required - may happen in case a DMA wrote too fast if (cnt > f->depth) { _ff_lock(f->mutex_rd); - _tu_fifo_correct_read_pointer(f, w); + rd_idx = _ff_correct_read_index(f, wr_idx); _ff_unlock(f->mutex_rd); - r = f->rd_idx; + cnt = f->depth; } @@ -934,22 +988,25 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) } // Get relative pointers - w = get_relative_pointer(f, w); - r = get_relative_pointer(f, r); + uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); + uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); // Copy pointer to buffer to start reading from - info->ptr_lin = &f->buffer[r]; + info->ptr_lin = &f->buffer[rd_ptr]; // Check if there is a wrap around necessary - if (w > r) { + if (wr_ptr > rd_ptr) + { // Non wrapping case info->len_lin = cnt; + info->len_wrap = 0; info->ptr_wrap = NULL; } else { - info->len_lin = f->depth - r; // Also the case if FIFO was full + info->len_lin = f->depth - rd_ptr; // Also the case if FIFO was full + info->len_wrap = cnt - info->len_lin; info->ptr_wrap = f->buffer; } @@ -972,36 +1029,37 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) /******************************************************************************/ void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { - uint16_t w = f->wr_idx, r = f->rd_idx; - uint16_t free = _tu_fifo_remaining(f, w, r); + uint16_t wr_idx = f->wr_idx; + uint16_t rd_idx = f->rd_idx; + uint16_t remain = _ff_remaining(f->depth, wr_idx, rd_idx); - if (free == 0) + if (remain == 0) { - info->len_lin = 0; + info->len_lin = 0; info->len_wrap = 0; - info->ptr_lin = NULL; + info->ptr_lin = NULL; info->ptr_wrap = NULL; return; } // Get relative pointers - w = get_relative_pointer(f, w); - r = get_relative_pointer(f, r); + uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); + uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); // Copy pointer to buffer to start writing to - info->ptr_lin = &f->buffer[w]; + info->ptr_lin = &f->buffer[wr_ptr]; - if (w < r) + if (wr_ptr < rd_ptr) { // Non wrapping case - info->len_lin = r-w; + info->len_lin = rd_ptr-wr_ptr; info->len_wrap = 0; info->ptr_wrap = NULL; } else { - info->len_lin = f->depth - w; - info->len_wrap = free - info->len_lin; // Remaining length - n already was limited to free or FIFO depth - info->ptr_wrap = f->buffer; // Always start of buffer + info->len_lin = f->depth - wr_ptr; + info->len_wrap = remain - info->len_lin; // Remaining length - n already was limited to remain or FIFO depth + info->ptr_wrap = f->buffer; // Always start of buffer } } diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.h index 18db289a..2f60ec2f 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.h +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.h @@ -32,7 +32,7 @@ extern "C" { #endif -// Due to the use of unmasked pointers, this FIFO does not suffer from loosing +// Due to the use of unmasked pointers, this FIFO does not suffer from losing // one item slice. Furthermore, write and read operations are completely // decoupled as write and read functions do not modify a common state. Henceforth, // writing or reading from the FIFO within an ISR is safe as long as no other @@ -42,32 +42,84 @@ extern "C" { // within a certain number (see tu_fifo_overflow()). #include "common/tusb_common.h" +#include "osal/osal.h" // mutex is only needed for RTOS // for OS None, we don't get preempted -#define CFG_FIFO_MUTEX (CFG_TUSB_OS != OPT_OS_NONE) +#define CFG_FIFO_MUTEX OSAL_MUTEX_REQUIRED -#if CFG_FIFO_MUTEX -#include "osal/osal.h" -#define tu_fifo_mutex_t osal_mutex_t -#endif +/* Write/Read index is always in the range of: + * 0 .. 2*depth-1 + * The extra window allow us to determine the fifo state of empty or full with only 2 indices + * Following are examples with depth = 3 + * + * - empty: W = R + * | + * ------------------------- + * | 0 | RW| 2 | 3 | 4 | 5 | + * + * - full 1: W > R + * | + * ------------------------- + * | 0 | R | 2 | 3 | W | 5 | + * + * - full 2: W < R + * | + * ------------------------- + * | 0 | 1 | W | 3 | 4 | R | + * + * - Number of items in the fifo can be determined in either cases: + * - case W >= R: Count = W - R + * - case W < R: Count = 2*depth - (R - W) + * + * In non-overwritable mode, computed Count (in above 2 cases) is at most equal to depth. + * However, in over-writable mode, write index can be repeatedly increased and count can be + * temporarily larger than depth (overflowed condition) e.g + * + * - Overflowed 1: write(3), write(1) + * In this case we will adjust Read index when read()/peek() is called so that count = depth. + * | + * ------------------------- + * | R | 1 | 2 | 3 | W | 5 | + * + * - Double Overflowed i.e index is out of allowed range [0,2*depth) + * This occurs when we continue to write after 1st overflowed to 2nd overflowed. e.g: + * write(3), write(1), write(2) + * This must be prevented since it will cause unrecoverable state, in above example + * if not handled the fifo will be empty instead of continue-to-be full. Since we must not modify + * read index in write() function, which cause race condition. We will re-position write index so that + * after data is written it is a full fifo i.e W = depth - R + * + * re-position W = 1 before write(2) + * Note: we should also move data from mem[3] to read index as well, but deliberately skipped here + * since it is an expensive operation !!! + * | + * ------------------------- + * | R | W | 2 | 3 | 4 | 5 | + * + * perform write(2), result is still a full fifo. + * + * | + * ------------------------- + * | R | 1 | 2 | W | 4 | 5 | + */ typedef struct { - uint8_t* buffer ; ///< buffer pointer - uint16_t depth ; ///< max items - uint16_t item_size ; ///< size of each item - bool overwritable ; + uint8_t* buffer ; // buffer pointer + uint16_t depth ; // max items - uint16_t non_used_index_space ; ///< required for non-power-of-two buffer length - uint16_t max_pointer_idx ; ///< maximum absolute pointer index + struct TU_ATTR_PACKED { + uint16_t item_size : 15; // size of each item + bool overwritable : 1 ; // ovwerwritable when full + }; - volatile uint16_t wr_idx ; ///< write pointer - volatile uint16_t rd_idx ; ///< read pointer + volatile uint16_t wr_idx ; // write index + volatile uint16_t rd_idx ; // read index -#if CFG_FIFO_MUTEX - tu_fifo_mutex_t mutex_wr; - tu_fifo_mutex_t mutex_rd; +#if OSAL_MUTEX_REQUIRED + osal_mutex_t mutex_wr; + osal_mutex_t mutex_rd; #endif } tu_fifo_t; @@ -86,8 +138,6 @@ typedef struct .depth = _depth, \ .item_size = sizeof(_type), \ .overwritable = _overwritable, \ - .non_used_index_space = UINT16_MAX - (2*(_depth)-1), \ - .max_pointer_idx = 2*(_depth)-1, \ } #define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \ @@ -99,13 +149,18 @@ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable); bool tu_fifo_clear(tu_fifo_t *f); bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable); -#if CFG_FIFO_MUTEX +#if OSAL_MUTEX_REQUIRED TU_ATTR_ALWAYS_INLINE static inline -void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t write_mutex_hdl, tu_fifo_mutex_t read_mutex_hdl) +void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_mutex) { - f->mutex_wr = write_mutex_hdl; - f->mutex_rd = read_mutex_hdl; + f->mutex_wr = wr_mutex; + f->mutex_rd = rd_mutex; } + +#else + +#define tu_fifo_config_mutex(_f, _wr_mutex, _rd_mutex) + #endif bool tu_fifo_write (tu_fifo_t* f, void const * p_data); @@ -133,7 +188,7 @@ uint16_t tu_fifo_depth(tu_fifo_t* f) } // Pointer modifications intended to be used in combinations with DMAs. -// USE WITH CARE - NO SAFTY CHECKS CONDUCTED HERE! NOT MUTEX PROTECTED! +// USE WITH CARE - NO SAFETY CHECKS CONDUCTED HERE! NOT MUTEX PROTECTED! void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n); void tu_fifo_advance_read_pointer (tu_fifo_t *f, uint16_t n); diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_mcu.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_mcu.h index baa82fc1..ba8976a8 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_mcu.h +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_mcu.h @@ -28,8 +28,8 @@ #define TUSB_MCU_H_ //--------------------------------------------------------------------+ -// Port Specific -// TUP stand for TinyUSB Port (can be renamed) +// Port/Platform Specific +// TUP stand for TinyUSB Port/Platform (can be renamed) //--------------------------------------------------------------------+ //------------- Unaligned Memory Access -------------// @@ -48,13 +48,16 @@ * - RHPORT_HIGHSPEED: support highspeed with on-chip PHY */ -//------------- NXP -------------// +//--------------------------------------------------------------------+ +// NXP +//--------------------------------------------------------------------+ #if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX) #define TUP_DCD_ENDPOINT_MAX 5 #elif TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX) #define TUP_DCD_ENDPOINT_MAX 16 #define TUP_USBIP_OHCI + #define TUP_OHCI_RHPORTS 2 #elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX) // TODO USB0 has 6, USB1 has 4 @@ -82,18 +85,24 @@ #define TUP_DCD_ENDPOINT_MAX 8 #define TUP_RHPORT_HIGHSPEED 1 // Port0 HS, Port1 HS -#elif TU_CHECK_MCU(OPT_MCU_MKL25ZXX, OPT_MCU_K32L2BXX) +#elif TU_CHECK_MCU(OPT_MCU_KINETIS_KL, OPT_MCU_KINETIS_K32) + #define TUP_USBIP_CHIPIDEA_FS + #define TUP_USBIP_CHIPIDEA_FS_KINETIS #define TUP_DCD_ENDPOINT_MAX 16 #elif TU_CHECK_MCU(OPT_MCU_MM32F327X) #define TUP_DCD_ENDPOINT_MAX 16 -//------------- Nordic -------------// +//--------------------------------------------------------------------+ +// Nordic +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_NRF5X) // 8 CBI + 1 ISO #define TUP_DCD_ENDPOINT_MAX 9 -//------------- Microchip -------------// +//--------------------------------------------------------------------+ +// Microchip +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_SAMD21, OPT_MCU_SAMD51, OPT_MCU_SAME5X) || \ TU_CHECK_MCU(OPT_MCU_SAMD11, OPT_MCU_SAML21, OPT_MCU_SAML22) #define TUP_DCD_ENDPOINT_MAX 8 @@ -111,19 +120,35 @@ #define TUP_DCD_ENDPOINT_MAX 8 #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER -//------------- ST -------------// +#elif TU_CHECK_MCU(OPT_MCU_PIC32MX, OPT_MCU_PIC32MM, OPT_MCU_PIC32MK) || \ + TU_CHECK_MCU(OPT_MCU_PIC24, OPT_MCU_DSPIC33) + #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + +//--------------------------------------------------------------------+ +// ST +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_STM32F0) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32F1) + // - F102, F103 use fsdev + // - F105, F107 use dwc2 #if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \ defined (STM32F107xB) || defined (STM32F107xC) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 #define TUP_DCD_ENDPOINT_MAX 4 - #else + #elif defined(STM32F102x6) || defined(STM32F102xB) || \ + defined(STM32F103x6) || defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 + #else + #error "Unsupported STM32F1 mcu" #endif #elif TU_CHECK_MCU(OPT_MCU_STM32F2) @@ -134,6 +159,8 @@ #define TUP_DCD_ENDPOINT_MAX 6 #elif TU_CHECK_MCU(OPT_MCU_STM32F3) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32F4) @@ -162,12 +189,18 @@ #define TUP_DCD_ENDPOINT_MAX 9 #elif TU_CHECK_MCU(OPT_MCU_STM32G4) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32L0, OPT_MCU_STM32L1) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32L4) + // - L4x2, L4x3 use fsdev + // - L4x4, L4x6, L4x7, L4x9 use dwc2 #if defined (STM32L475xx) || defined (STM32L476xx) || \ defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \ defined (STM32L4A6xx) || defined (STM32L4P5xx) || defined (STM32L4Q5xx) || \ @@ -177,31 +210,57 @@ #define TUP_USBIP_DWC2_STM32 #define TUP_DCD_ENDPOINT_MAX 6 - #else + #elif defined(STM32L412xx) || defined(STM32L422xx) || defined(STM32L432xx) || defined(STM32L433xx) || \ + defined(STM32L442xx) || defined(STM32L443xx) || defined(STM32L452xx) || defined(STM32L462xx) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 + #else + #error "Unsupported STM32L4 mcu" #endif #elif TU_CHECK_MCU(OPT_MCU_STM32WB) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 + #define TUP_DCD_ENDPOINT_MAX 8 + +#elif TU_CHECK_MCU(OPT_MCU_STM32U5) + #define TUP_USBIP_DWC2 + #define TUP_USBIP_DWC2_STM32 + #define TUP_DCD_ENDPOINT_MAX 6 + +#elif TU_CHECK_MCU(OPT_MCU_STM32L5) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 -//------------- Sony -------------// + +//--------------------------------------------------------------------+ +// Sony +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_CXD56) #define TUP_DCD_ENDPOINT_MAX 7 #define TUP_RHPORT_HIGHSPEED 1 #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER -//------------- TI -------------// +//--------------------------------------------------------------------+ +// TI +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_MSP430x5xx) #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129) #define TUP_DCD_ENDPOINT_MAX 8 -//------------- ValentyUSB -------------// +//--------------------------------------------------------------------+ +// ValentyUSB (Litex) +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_VALENTYUSB_EPTRI) #define TUP_DCD_ENDPOINT_MAX 16 -//------------- Nuvoton -------------// +//--------------------------------------------------------------------+ +// Nuvoton +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_NUC121, OPT_MCU_NUC126) #define TUP_DCD_ENDPOINT_MAX 8 @@ -212,47 +271,65 @@ #define TUP_DCD_ENDPOINT_MAX 12 #define TUP_RHPORT_HIGHSPEED 1 -//------------- Espressif -------------// +//--------------------------------------------------------------------+ +// Espressif +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) #define TUP_USBIP_DWC2 #define TUP_DCD_ENDPOINT_MAX 6 -//------------- Dialog -------------// +//--------------------------------------------------------------------+ +// Dialog +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_DA1469X) #define TUP_DCD_ENDPOINT_MAX 4 -//------------- Raspberry Pi -------------// +//--------------------------------------------------------------------+ +// Raspberry Pi +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_RP2040) #define TUP_DCD_ENDPOINT_MAX 16 #define TU_ATTR_FAST_FUNC __attribute__((section(".time_critical.tinyusb"))) -//------------- Silabs -------------// +//--------------------------------------------------------------------+ +// Silabs +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_EFM32GG) #define TUP_USBIP_DWC2 #define TUP_DCD_ENDPOINT_MAX 7 -//------------- Renesas -------------// -#elif TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N) +//--------------------------------------------------------------------+ +// Renesas +//--------------------------------------------------------------------+ +#elif TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N, OPT_MCU_RAXXX) #define TUP_DCD_ENDPOINT_MAX 10 -//------------- GigaDevice -------------// +//--------------------------------------------------------------------+ +// GigaDevice +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_GD32VF103) #define TUP_USBIP_DWC2 #define TUP_DCD_ENDPOINT_MAX 4 -//------------- Broadcom -------------// +//--------------------------------------------------------------------+ +// Broadcom +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837) #define TUP_USBIP_DWC2 #define TUP_DCD_ENDPOINT_MAX 8 #define TUP_RHPORT_HIGHSPEED 1 -//------------- Broadcom -------------// +//--------------------------------------------------------------------+ +// Infineon +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_XMC4000) #define TUP_USBIP_DWC2 #define TUP_DCD_ENDPOINT_MAX 8 -//------------- BridgeTek -------------// +//--------------------------------------------------------------------+ +// BridgeTek +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_FT90X) #define TUP_DCD_ENDPOINT_MAX 8 #define TUP_RHPORT_HIGHSPEED 1 @@ -261,16 +338,26 @@ #define TUP_DCD_ENDPOINT_MAX 16 #define TUP_RHPORT_HIGHSPEED 1 -//------------ Allwinner -------------// +//--------------------------------------------------------------------+ +// Allwinner +//--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_F1C100S) #define TUP_DCD_ENDPOINT_MAX 4 +//------------- WCH -------------// +#elif TU_CHECK_MCU(OPT_MCU_CH32V307) + #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_RHPORT_HIGHSPEED 1 #endif //--------------------------------------------------------------------+ // Default Values //--------------------------------------------------------------------+ +#ifndef TUP_MCU_MULTIPLE_CORE +#define TUP_MCU_MULTIPLE_CORE 0 +#endif + #ifndef TUP_DCD_ENDPOINT_MAX #warning "TUP_DCD_ENDPOINT_MAX is not defined for this MCU, default to 8" #define TUP_DCD_ENDPOINT_MAX 8 diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_private.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_private.h index b34506f6..d5541856 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_private.h +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_private.h @@ -28,6 +28,8 @@ #ifndef _TUSB_PRIVATE_H_ #define _TUSB_PRIVATE_H_ +// Internal Helper used by Host and Device Stack + #ifdef __cplusplus extern "C" { #endif @@ -39,8 +41,31 @@ typedef struct TU_ATTR_PACKED volatile uint8_t claimed : 1; }tu_edpt_state_t; +typedef struct { + bool is_host; // host or device most + union { + uint8_t daddr; + uint8_t rhport; + uint8_t hwid; + }; + uint8_t ep_addr; + uint8_t ep_speed; + + uint16_t ep_packetsize; + uint16_t ep_bufsize; + + // TODO xfer_fifo can skip this buffer + uint8_t* ep_buf; + + tu_fifo_t ff; + + // mutex: read if ep rx, write if e tx + OSAL_MUTEX_DEF(ff_mutex); + +}tu_edpt_stream_t; + //--------------------------------------------------------------------+ -// Internal Helper used by Host and Device Stack +// Endpoint //--------------------------------------------------------------------+ // Check if endpoint descriptor is valid per USB specs @@ -58,6 +83,89 @@ bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex); // Release an endpoint with provided mutex bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex); +//--------------------------------------------------------------------+ +// Endpoint Stream +//--------------------------------------------------------------------+ + +// Init an stream, should only be called once +bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool overwritable, + void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize); + +// Open an stream for an endpoint +// hwid is either device address (host mode) or rhport (device mode) +TU_ATTR_ALWAYS_INLINE static inline +void tu_edpt_stream_open(tu_edpt_stream_t* s, uint8_t hwid, tusb_desc_endpoint_t const *desc_ep) +{ + tu_fifo_clear(&s->ff); + s->hwid = hwid; + s->ep_addr = desc_ep->bEndpointAddress; + s->ep_packetsize = tu_edpt_packet_size(desc_ep); +} + +TU_ATTR_ALWAYS_INLINE static inline +void tu_edpt_stream_close(tu_edpt_stream_t* s) +{ + s->hwid = 0; + s->ep_addr = 0; +} + +// Clear fifo +TU_ATTR_ALWAYS_INLINE static inline +bool tu_edpt_stream_clear(tu_edpt_stream_t* s) +{ + return tu_fifo_clear(&s->ff); +} + +//--------------------------------------------------------------------+ +// Stream Write +//--------------------------------------------------------------------+ + +// Write to stream +uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize); + +// Start an usb transfer if endpoint is not busy +uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s); + +// Start an zero-length packet if needed +bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes); + +// Get the number of bytes available for writing +TU_ATTR_ALWAYS_INLINE static inline +uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) +{ + return (uint32_t) tu_fifo_remaining(&s->ff); +} + +//--------------------------------------------------------------------+ +// Stream Read +//--------------------------------------------------------------------+ + +// Read from stream +uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize); + +// Start an usb transfer if endpoint is not busy +uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s); + +// Must be called in the transfer complete callback +TU_ATTR_ALWAYS_INLINE static inline +void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) +{ + tu_fifo_write_n(&s->ff, s->ep_buf, (uint16_t) xferred_bytes); +} + +// Get the number of bytes available for reading +TU_ATTR_ALWAYS_INLINE static inline +uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t* s) +{ + return (uint32_t) tu_fifo_count(&s->ff); +} + +TU_ATTR_ALWAYS_INLINE static inline +bool tu_edpt_stream_peek(tu_edpt_stream_t* s, uint8_t* ch) +{ + return tu_fifo_peek(&s->ff, ch); +} + #ifdef __cplusplus } #endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_timeout.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_timeout.h index ce53955f..533e67ab 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_timeout.h +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_timeout.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_types.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_types.h index 1f2a38d4..39a2d456 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_types.h +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_types.h @@ -69,6 +69,15 @@ typedef enum TUSB_DIR_IN_MASK = 0x80 }tusb_dir_t; +enum +{ + TUSB_EPSIZE_BULK_FS = 64, + TUSB_EPSIZE_BULK_HS= 512, + + TUSB_EPSIZE_ISO_FS_MAX = 1023, + TUSB_EPSIZE_ISO_HS_MAX = 1024, +}; + /// Isochronous End Point Attributes typedef enum { @@ -225,7 +234,7 @@ enum { typedef enum { - XFER_RESULT_SUCCESS, + XFER_RESULT_SUCCESS = 0, XFER_RESULT_FAILED, XFER_RESULT_STALLED, XFER_RESULT_TIMEOUT, @@ -243,7 +252,6 @@ enum INTERFACE_INVALID_NUMBER = 0xff }; - typedef enum { MS_OS_20_SET_HEADER_DESCRIPTOR = 0x00, @@ -265,6 +273,11 @@ enum CONTROL_STAGE_ACK }; +enum +{ + TUSB_INDEX_INVALID_8 = 0xFFu +}; + //--------------------------------------------------------------------+ // USB Descriptors //--------------------------------------------------------------------+ @@ -513,25 +526,52 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpo return tu_le16toh(desc_ep->wMaxPacketSize) & TU_GENMASK(10, 0); } +#if CFG_TUSB_DEBUG +TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_dir_str(tusb_dir_t dir) +{ + tu_static const char *str[] = {"out", "in"}; + return str[dir]; +} + +TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_t t) +{ + tu_static const char *str[] = {"control", "isochronous", "bulk", "interrupt"}; + return str[t]; +} +#endif + //--------------------------------------------------------------------+ // Descriptor helper //--------------------------------------------------------------------+ + +// return next descriptor TU_ATTR_ALWAYS_INLINE static inline uint8_t const * tu_desc_next(void const* desc) { uint8_t const* desc8 = (uint8_t const*) desc; return desc8 + desc8[DESC_OFFSET_LEN]; } +// get descriptor type TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_type(void const* desc) { return ((uint8_t const*) desc)[DESC_OFFSET_TYPE]; } +// get descriptor length TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc) { return ((uint8_t const*) desc)[DESC_OFFSET_LEN]; } +// find descriptor that match byte1 (type) +uint8_t const * tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byte1); + +// find descriptor that match byte1 (type) and byte2 +uint8_t const * tu_desc_find2(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2); + +// find descriptor that match byte1 (type) and byte2 +uint8_t const * tu_desc_find3(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2, uint8_t byte3); + #ifdef __cplusplus } #endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_verify.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_verify.h index a52a6d26..12355e8b 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_verify.h +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_verify.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) diff --git a/test-devices/loopback-stm32/lib/tinyusb/device/dcd.h b/test-devices/loopback-stm32/lib/tinyusb/device/dcd.h index c1780f65..00419ff0 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/device/dcd.h +++ b/test-devices/loopback-stm32/lib/tinyusb/device/dcd.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -167,6 +167,12 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); // This API never calls with control endpoints, since it is auto cleared when receiving setup packet void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr); +// Allocate packet buffer used by ISO endpoints +// Some MCU need manual packet buffer allocation, we allocation largest size to avoid clustering +TU_ATTR_WEAK bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size); + +// Configure and enable an ISO endpoint according to descriptor +TU_ATTR_WEAK bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); //--------------------------------------------------------------------+ // Event API (implemented by stack) //--------------------------------------------------------------------+ @@ -193,7 +199,7 @@ TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_reset (uint8_t rhport, t TU_ATTR_ALWAYS_INLINE static inline void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr) { dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SETUP_RECEIVED }; - memcpy(&event.setup_received, setup, 8); + memcpy(&event.setup_received, setup, sizeof(tusb_control_request_t)); dcd_event_handler(&event, in_isr); } diff --git a/test-devices/loopback-stm32/lib/tinyusb/device/usbd.c b/test-devices/loopback-stm32/lib/tinyusb/device/usbd.c index c199e647..cee56af6 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/device/usbd.c +++ b/test-devices/loopback-stm32/lib/tinyusb/device/usbd.c @@ -39,13 +39,13 @@ // USBD Configuration //--------------------------------------------------------------------+ -// Debug level of USBD -#define USBD_DBG 2 - #ifndef CFG_TUD_TASK_QUEUE_SZ #define CFG_TUD_TASK_QUEUE_SZ 16 #endif +// Debug level of USBD +#define USBD_DBG 2 + //--------------------------------------------------------------------+ // Device Data //--------------------------------------------------------------------+ @@ -76,7 +76,7 @@ typedef struct }usbd_device_t; -static usbd_device_t _usbd_dev; +tu_static usbd_device_t _usbd_dev; //--------------------------------------------------------------------+ // Class Driver @@ -88,7 +88,7 @@ static usbd_device_t _usbd_dev; #endif // Built-in class drivers -static usbd_class_driver_t const _usbd_driver[] = +tu_static usbd_class_driver_t const _usbd_driver[] = { #if CFG_TUD_CDC { @@ -238,8 +238,8 @@ static usbd_class_driver_t const _usbd_driver[] = enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(_usbd_driver) }; // Additional class drivers implemented by application -static usbd_class_driver_t const * _app_driver = NULL; -static uint8_t _app_driver_count = 0; +tu_static usbd_class_driver_t const * _app_driver = NULL; +tu_static uint8_t _app_driver_count = 0; // virtually joins built-in and application drivers together. // Application is positioned first to allow overwriting built-in ones. @@ -265,17 +265,19 @@ static inline usbd_class_driver_t const * get_driver(uint8_t drvid) //--------------------------------------------------------------------+ enum { RHPORT_INVALID = 0xFFu }; -static uint8_t _usbd_rhport = RHPORT_INVALID; +tu_static uint8_t _usbd_rhport = RHPORT_INVALID; // Event queue // usbd_int_set() is used as mutex in OS NONE config OSAL_QUEUE_DEF(usbd_int_set, _usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t); -static osal_queue_t _usbd_q; +tu_static osal_queue_t _usbd_q; -// Mutex for claiming endpoint, only needed when using with preempted RTOS -#if CFG_TUSB_OS != OPT_OS_NONE -static osal_mutex_def_t _ubsd_mutexdef; -static osal_mutex_t _usbd_mutex; +// Mutex for claiming endpoint +#if OSAL_MUTEX_REQUIRED + tu_static osal_mutex_def_t _ubsd_mutexdef; + tu_static osal_mutex_t _usbd_mutex; +#else + #define _usbd_mutex NULL #endif @@ -297,7 +299,7 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, // Debug //--------------------------------------------------------------------+ #if CFG_TUSB_DEBUG >= 2 -static char const* const _usbd_event_str[DCD_EVENT_COUNT] = +tu_static char const* const _usbd_event_str[DCD_EVENT_COUNT] = { "Invalid" , "Bus Reset" , @@ -386,10 +388,12 @@ bool tud_init (uint8_t rhport) TU_LOG(USBD_DBG, "USBD init on controller %u\r\n", rhport); TU_LOG_INT(USBD_DBG, sizeof(usbd_device_t)); + TU_LOG_INT(USBD_DBG, sizeof(tu_fifo_t)); + TU_LOG_INT(USBD_DBG, sizeof(tu_edpt_stream_t)); tu_varclr(&_usbd_dev); -#if CFG_TUSB_OS != OPT_OS_NONE +#if OSAL_MUTEX_REQUIRED // Init device mutex _usbd_mutex = osal_mutex_create(&_ubsd_mutexdef); TU_ASSERT(_usbd_mutex); @@ -446,7 +450,7 @@ static void usbd_reset(uint8_t rhport) bool tud_task_event_ready(void) { // Skip if stack is not initialized - if ( !tusb_inited() ) return false; + if ( !tud_inited() ) return false; return !osal_queue_empty(_usbd_q); } @@ -474,7 +478,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) (void) in_isr; // not implemented yet // Skip if stack is not initialized - if ( !tusb_inited() ) return; + if ( !tud_inited() ) return; // Loop until there is no more events in the queue while (1) @@ -504,7 +508,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) break; case DCD_EVENT_SETUP_RECEIVED: - TU_LOG_VAR(USBD_DBG, &event.setup_received); + TU_LOG_PTR(USBD_DBG, &event.setup_received); TU_LOG(USBD_DBG, "\r\n"); // Mark as connected after receiving 1st setup packet. @@ -1209,11 +1213,7 @@ bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr) uint8_t const dir = tu_edpt_dir(ep_addr); tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir]; -#if TUSB_OPT_MUTEX return tu_edpt_claim(ep_state, _usbd_mutex); -#else - return tu_edpt_claim(ep_state, NULL); -#endif } bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr) @@ -1224,11 +1224,7 @@ bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr) uint8_t const dir = tu_edpt_dir(ep_addr); tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir]; -#if TUSB_OPT_MUTEX return tu_edpt_release(ep_state, _usbd_mutex); -#else - return tu_edpt_release(ep_state, NULL); -#endif } bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) @@ -1386,4 +1382,31 @@ void usbd_sof_enable(uint8_t rhport, bool en) dcd_sof_enable(rhport, en); } +bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) +{ + rhport = _usbd_rhport; + + TU_ASSERT(dcd_edpt_iso_alloc); + TU_ASSERT(tu_edpt_number(ep_addr) < CFG_TUD_ENDPPOINT_MAX); + + return dcd_edpt_iso_alloc(rhport, ep_addr, largest_packet_size); +} + +bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) +{ + rhport = _usbd_rhport; + + uint8_t const epnum = tu_edpt_number(desc_ep->bEndpointAddress); + uint8_t const dir = tu_edpt_dir(desc_ep->bEndpointAddress); + + TU_ASSERT(dcd_edpt_iso_activate); + TU_ASSERT(epnum < CFG_TUD_ENDPPOINT_MAX); + TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed)); + + _usbd_dev.ep_status[epnum][dir].stalled = false; + _usbd_dev.ep_status[epnum][dir].busy = false; + _usbd_dev.ep_status[epnum][dir].claimed = false; + return dcd_edpt_iso_activate(rhport, desc_ep); +} + #endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/device/usbd.h b/test-devices/loopback-stm32/lib/tinyusb/device/usbd.h index 17b4d927..255e5a84 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/device/usbd.h +++ b/test-devices/loopback-stm32/lib/tinyusb/device/usbd.h @@ -293,7 +293,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* MIDI Streaming (MS) Interface */\ 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum) + 1), 0, 2, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_MIDI_STREAMING, AUDIO_FUNC_PROTOCOL_CODE_UNDEF, 0,\ /* MS Header */\ - 7, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(7 + (_numcables) * TUD_MIDI_DESC_JACK_LEN) + 7, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(7 + (_numcables) * TUD_MIDI_DESC_JACK_LEN + 2 * TUD_MIDI_DESC_EP_LEN(_numcables)) #define TUD_MIDI_JACKID_IN_EMB(_cablenum) \ (uint8_t)(((_cablenum) - 1) * 4 + 1) @@ -308,15 +308,17 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb (uint8_t)(((_cablenum) - 1) * 4 + 4) #define TUD_MIDI_DESC_JACK_LEN (6 + 6 + 9 + 9) -#define TUD_MIDI_DESC_JACK(_cablenum) \ +#define TUD_MIDI_DESC_JACK_DESC(_cablenum, _stridx) \ /* MS In Jack (Embedded) */\ - 6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_IN_EMB(_cablenum), 0,\ + 6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_IN_EMB(_cablenum), _stridx,\ /* MS In Jack (External) */\ - 6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_IN_EXT(_cablenum), 0,\ + 6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_IN_EXT(_cablenum), _stridx,\ /* MS Out Jack (Embedded), connected to In Jack External */\ - 9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_OUT_EMB(_cablenum), 1, TUD_MIDI_JACKID_IN_EXT(_cablenum), 1, 0,\ + 9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_OUT_EMB(_cablenum), 1, TUD_MIDI_JACKID_IN_EXT(_cablenum), 1, _stridx,\ /* MS Out Jack (External), connected to In Jack Embedded */\ - 9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_OUT_EXT(_cablenum), 1, TUD_MIDI_JACKID_IN_EMB(_cablenum), 1, 0 + 9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_OUT_EXT(_cablenum), 1, TUD_MIDI_JACKID_IN_EMB(_cablenum), 1, _stridx + +#define TUD_MIDI_DESC_JACK(_cablenum) TUD_MIDI_DESC_JACK_DESC(_cablenum, 0) #define TUD_MIDI_DESC_EP_LEN(_numcables) (9 + 4 + (_numcables)) #define TUD_MIDI_DESC_EP(_epout, _epsize, _numcables) \ @@ -333,7 +335,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb // - 1 Embedded Jack out connected to 1 External Jack In #define TUD_MIDI_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \ TUD_MIDI_DESC_HEAD(_itfnum, _stridx, 1),\ - TUD_MIDI_DESC_JACK(1),\ + TUD_MIDI_DESC_JACK_DESC(1, 0),\ TUD_MIDI_DESC_EP(_epout, _epsize, 1),\ TUD_MIDI_JACKID_IN_EMB(1),\ TUD_MIDI_DESC_EP(_epin, _epsize, 1),\ @@ -418,7 +420,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */ #define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN 7 #define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_ep, _interval) \ - TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_NO_SYNC | TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_NO_SYNC | TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval // AUDIO simple descriptor (UAC2) for 1 microphone input // - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source @@ -465,7 +467,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) @@ -514,7 +516,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) @@ -562,7 +564,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\ /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\ @@ -602,7 +604,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* optional interrupt endpoint */ \ // _int_pollingInterval : for LS/FS, expressed in frames (1ms each). 16 may be a good number? #define TUD_USBTMC_INT_DESCRIPTOR(_ep_interrupt, _ep_interrupt_size, _int_pollingInterval ) \ - 7, TUSB_DESC_ENDPOINT, _ep_interrupt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_interrupt_size), 0x16 + 7, TUSB_DESC_ENDPOINT, _ep_interrupt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_interrupt_size), _int_pollingInterval #define TUD_USBTMC_INT_DESCRIPTOR_LEN (7u) @@ -647,7 +649,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb #define TUD_DFU_DESC_LEN(_alt_count) (9 + (_alt_count) * 9) // Interface number, Alternate count, starting string index, attributes, detach timeout, transfer size -// Note: Alternate count must be numberic or macro, string index is increased by one for each Alt interface +// Note: Alternate count must be numeric or macro, string index is increased by one for each Alt interface #define TUD_DFU_DESCRIPTOR(_itfnum, _alt_count, _stridx, _attr, _timeout, _xfer_size) \ TU_XSTRCAT(_TUD_DFU_ALT_,_alt_count)(_itfnum, 0, _stridx), \ /* Function */ \ diff --git a/test-devices/loopback-stm32/lib/tinyusb/device/usbd_control.c b/test-devices/loopback-stm32/lib/tinyusb/device/usbd_control.c index 0995ef66..ea8eef28 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/device/usbd_control.c +++ b/test-devices/loopback-stm32/lib/tinyusb/device/usbd_control.c @@ -53,10 +53,10 @@ typedef struct usbd_control_xfer_cb_t complete_cb; } usbd_control_xfer_t; -static usbd_control_xfer_t _ctrl_xfer; +tu_static usbd_control_xfer_t _ctrl_xfer; CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN -static uint8_t _usbd_ctrl_buf[CFG_TUD_ENDPOINT0_SIZE]; +tu_static uint8_t _usbd_ctrl_buf[CFG_TUD_ENDPOINT0_SIZE]; //--------------------------------------------------------------------+ // Application API @@ -93,7 +93,9 @@ static bool _data_stage_xact(uint8_t rhport) if ( _ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN ) { ep_addr = EDPT_CTRL_IN; - if ( xact_len ) memcpy(_usbd_ctrl_buf, _ctrl_xfer.buffer, xact_len); + if ( xact_len ) { + TU_VERIFY(0 == tu_memcpy_s(_usbd_ctrl_buf, CFG_TUD_ENDPOINT0_SIZE, _ctrl_xfer.buffer, xact_len)); + } } return usbd_edpt_xfer(rhport, ep_addr, xact_len ? _usbd_ctrl_buf : NULL, xact_len); diff --git a/test-devices/loopback-stm32/lib/tinyusb/device/usbd_pvt.h b/test-devices/loopback-stm32/lib/tinyusb/device/usbd_pvt.h index 6fad46db..8393d346 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/device/usbd_pvt.h +++ b/test-devices/loopback-stm32/lib/tinyusb/device/usbd_pvt.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -96,6 +96,12 @@ void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr); // Check if endpoint is stalled bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr); +// Allocate packet buffer used by ISO endpoints +bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size); + +// Configure and enable an ISO endpoint according to descriptor +bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); + // Check if endpoint is ready (not busy and not stalled) TU_ATTR_ALWAYS_INLINE static inline bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr) diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c index ef703d29..22c82201 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c +++ b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c @@ -529,8 +529,10 @@ void dcd_init (uint8_t rhport) dwc2->dcfg |= DCFG_NZLSOHSK; // Clear all interrupts - dwc2->gintsts |= dwc2->gintsts; - dwc2->gotgint |= dwc2->gotgint; + uint32_t int_mask = dwc2->gintsts; + dwc2->gintsts |= int_mask; + int_mask = dwc2->gotgint; + dwc2->gotgint |= int_mask; // Required as part of core initialization. // TODO: How should mode mismatch be handled? It will cause @@ -931,8 +933,8 @@ static void read_fifo_packet(uint8_t rhport, uint8_t * dst, uint16_t len) volatile const uint32_t * rx_fifo = dwc2->fifo[0]; // Reading full available 32 bit words from fifo - uint8_t * dst_end = dst + (len & 0xfffc); - while(dst < dst_end) + uint16_t full_words = len >> 2; + while(full_words--) { tu_unaligned_write32(dst, *rx_fifo); dst += 4; @@ -958,8 +960,8 @@ static void write_fifo_packet(uint8_t rhport, uint8_t fifo_num, uint8_t const * volatile uint32_t * tx_fifo = dwc2->fifo[fifo_num]; // Pushing full available 32 bit words to fifo - const uint8_t * src_end = src + (len & 0xfffc); - while(src < src_end) + uint16_t full_words = len >> 2; + while(full_words--) { *tx_fifo = tu_unaligned_read32(src); src += 4; @@ -1003,7 +1005,7 @@ static void handle_rxflvl_irq(uint8_t rhport) switch ( pktsts ) { - // Global OUT NAK: do nothign + // Global OUT NAK: do nothing case GRXSTS_PKTSTS_GLOBALOUTNAK: break; case GRXSTS_PKTSTS_SETUPRX: @@ -1219,7 +1221,8 @@ void dcd_int_handler(uint8_t rhport) { dwc2_regs_t *dwc2 = DWC2_REG(rhport); - uint32_t const int_status = dwc2->gintsts & dwc2->gintmsk; + uint32_t const int_mask = dwc2->gintmsk; + uint32_t const int_status = dwc2->gintsts & int_mask; if(int_status & GINTSTS_USBRST) { diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_stm32.h b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_stm32.h index 337f611d..cb455bd9 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_stm32.h +++ b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_stm32.h @@ -82,6 +82,12 @@ #define EP_MAX_FS 6 #define EP_FIFO_SIZE_FS 1280 +#elif CFG_TUSB_MCU == OPT_MCU_STM32U5 + #include "stm32u5xx.h" + #define USB_OTG_FS_PERIPH_BASE USB_OTG_FS_BASE + #define EP_MAX_FS 6 + #define EP_FIFO_SIZE_FS 1280 + #else #error "Unsupported MCUs" #endif @@ -110,19 +116,19 @@ static const dwc2_controller_t _dwc2_controller[] = // //--------------------------------------------------------------------+ -// SystemCoreClock is alrady included by family header +// SystemCoreClock is already included by family header // extern uint32_t SystemCoreClock; TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_enable(uint8_t rhport) { - NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum); + NVIC_EnableIRQ((IRQn_Type)_dwc2_controller[rhport].irqnum); } TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_disable (uint8_t rhport) { - NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum); + NVIC_DisableIRQ((IRQn_Type)_dwc2_controller[rhport].irqnum); } TU_ATTR_ALWAYS_INLINE diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/hwcfg_list.md b/test-devices/loopback-stm32/lib/tinyusb/dwc2/hwcfg_list.md new file mode 100644 index 00000000..b5590da0 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/dwc2/hwcfg_list.md @@ -0,0 +1,777 @@ +# DWC2 Hardware Configuration Registers + +## Broadcom BCM2711 (Pi4) + +dwc2->guid = 2708A000 +dwc2->gsnpsid = 4F54280A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 228DDD50 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 2 +hw_cfg2->point2point = 0 +hw_cfg2->hs_phy_type = 1 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 7 +hw_cfg2->num_host_ch = 7 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 0 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = FF000E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 0 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 0 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 0 +hw_cfg3->lpm_mode = 0 +hw_cfg3->total_fifo_size = 4080 + +dwc2->ghwcfg4 = 1FF00020 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 0 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 0 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 15 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## EFM32GG FS + +dwc2->guid = 0 +dwc2->gsnpsid = 4F54330A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 228F5910 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 2 +hw_cfg2->point2point = 0 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 6 +hw_cfg2->num_host_ch = 13 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 0 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 1F204E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 0 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 1 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 0 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 0 +hw_cfg3->lpm_mode = 0 +hw_cfg3->total_fifo_size = 498 + +dwc2->ghwcfg4 = 1BF08030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 2 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 13 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## ESP32-S2 Fullspeed + +dwc2->guid = 0 +dwc2->gsnpsid = 4F54400A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 224DD930 +hw_cfg2->op_mode = 2 +hw_cfg2->arch = 3 +hw_cfg2->point2point = 0 +hw_cfg2->hs_phy_type = 1 +hw_cfg2->fs_phy_type = 2 +hw_cfg2->num_dev_ep = 6 +hw_cfg2->num_host_ch = 9 +hw_cfg2->period_channel_support = 0 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 1 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 22 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = C804B5 +hw_cfg3->xfer_size_width = 10 +hw_cfg3->packet_size_width = 5 +hw_cfg3->otg_enable = 0 +hw_cfg3->i2c_enable = 0 +hw_cfg3->vendor_ctrl_itf = 1 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 1 +hw_cfg3->otg_adp_support = 1 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 1 +hw_cfg3->lpm_mode = 0 +hw_cfg3->total_fifo_size = 23130 + +dwc2->ghwcfg4 = D3F0A030 +hw_cfg4->num_dev_period_in_ep = 10 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 0 +hw_cfg4->hibernation = 1 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 1 +hw_cfg4->acg_enable = 1 +hw_cfg4->utmi_phy_data_width = 1 +hw_cfg4->dev_ctrl_ep_num = 10 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 0 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 0 +hw_cfg4->dedicated_fifos = 0 +hw_cfg4->num_dev_in_eps = 13 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 1 + +## STM32F407 and STM32F207 + +STM32F407 and STM32F207 are exactly the same + +### STM32F407 Fullspeed + +dwc2->guid = 1200 +dwc2->gsnpsid = 4F54281A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229DCD20 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 0 +hw_cfg2->point2point = 1 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 3 +hw_cfg2->num_host_ch = 7 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 20001E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 1 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 0 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 0 +hw_cfg3->lpm_mode = 0 +hw_cfg3->total_fifo_size = 512 + +dwc2->ghwcfg4 = FF08030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 2 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 7 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +### STM32F407 Highspeed + +dwc2->guid = 1100 +dwc2->gsnpsid = 4F54281A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229ED590 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 2 +hw_cfg2->point2point = 0 +hw_cfg2->hs_phy_type = 2 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 5 +hw_cfg2->num_host_ch = 11 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 3F403E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 1 +hw_cfg3->vendor_ctrl_itf = 1 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 0 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 0 +hw_cfg3->lpm_mode = 0 +hw_cfg3->total_fifo_size = 1012 + +dwc2->ghwcfg4 = 17F00030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 0 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 11 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## STM32F411 Fullspeed + +dwc2->guid = 1200 +dwc2->gsnpsid = 4F54281A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229DCD20 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 0 +hw_cfg2->point2point = 1 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 3 +hw_cfg2->num_host_ch = 7 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 20001E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 1 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 0 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 0 +hw_cfg3->lpm_mode = 0 +hw_cfg3->total_fifo_size = 512 + +dwc2->ghwcfg4 = FF08030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 2 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 7 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## STM32F412 FS + +dwc2->guid = 2000 +dwc2->gsnpsid = 4F54320A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229ED520 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 0 +hw_cfg2->point2point = 1 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 5 +hw_cfg2->num_host_ch = 11 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 200D1E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 1 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 1 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 1 +hw_cfg3->lpm_mode = 1 +hw_cfg3->total_fifo_size = 512 + +dwc2->ghwcfg4 = 17F08030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 2 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 11 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## STM32F723 + +### STM32F723 HighSpeed + +dwc2->guid = 3100 +dwc2->gsnpsid = 4F54330A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229FE1D0 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 2 +hw_cfg2->point2point = 0 +hw_cfg2->hs_phy_type = 3 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 8 +hw_cfg2->num_host_ch = 15 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 3EED2E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 0 +hw_cfg3->vendor_ctrl_itf = 1 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 1 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 1 +hw_cfg3->lpm_mode = 1 +hw_cfg3->total_fifo_size = 1006 + +dwc2->ghwcfg4 = 23F00030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 0 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 1 +hw_cfg4->dma_desc_enable = 1 +hw_cfg4->dma_dynamic = 0 + +### STM32F723 Fullspeed + +dwc2->guid = 3000 +dwc2->gsnpsid = 4F54330A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229ED520 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 0 +hw_cfg2->point2point = 1 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 5 +hw_cfg2->num_host_ch = 11 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 200D1E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 1 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 1 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 1 +hw_cfg3->lpm_mode = 1 +hw_cfg3->total_fifo_size = 512 + +dwc2->ghwcfg4 = 17F08030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 2 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 11 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## STM32F767 FS + +dwc2->guid = 2000 +dwc2->gsnpsid = 4F54320A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229ED520 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 0 +hw_cfg2->point2point = 1 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 5 +hw_cfg2->num_host_ch = 11 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 200D1E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 1 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 1 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 1 +hw_cfg3->lpm_mode = 1 +hw_cfg3->total_fifo_size = 512 + +dwc2->ghwcfg4 = 17F08030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 2 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 11 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## STM32H743 (both cores HS) + +dwc2->guid = 2300 +dwc2->gsnpsid = 4F54330A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229FE190 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 2 +hw_cfg2->point2point = 0 +hw_cfg2->hs_phy_type = 2 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 8 +hw_cfg2->num_host_ch = 15 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 3B8D2E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 0 +hw_cfg3->vendor_ctrl_itf = 1 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 1 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 1 +hw_cfg3->lpm_mode = 1 +hw_cfg3->total_fifo_size = 952 + +dwc2->ghwcfg4 = E3F00030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 0 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 1 +hw_cfg4->dma_desc_enable = 1 +hw_cfg4->dma_dynamic = 1 + +## STM32L476 FS + +dwc2->guid = 2000 +dwc2->gsnpsid = 4F54310A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 229ED520 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 0 +hw_cfg2->point2point = 1 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 5 +hw_cfg2->num_host_ch = 11 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 1 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 200D1E8 +hw_cfg3->xfer_size_width = 8 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 1 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 1 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 1 +hw_cfg3->lpm_mode = 1 +hw_cfg3->total_fifo_size = 512 + +dwc2->ghwcfg4 = 17F08030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 2 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 11 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## GD32VF103 Fullspeed + +dwc2->guid = 1000 +dwc2->gsnpsid = 0 +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 0 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 0 +hw_cfg2->point2point = 0 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 0 +hw_cfg2->num_dev_ep = 0 +hw_cfg2->num_host_ch = 0 +hw_cfg2->period_channel_support = 0 +hw_cfg2->enable_dynamic_fifo = 0 +hw_cfg2->mul_cpu_int = 0 +hw_cfg2->nperiod_tx_q_depth = 0 +hw_cfg2->host_period_tx_q_depth = 0 +hw_cfg2->dev_token_q_depth = 0 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 0 +hw_cfg3->xfer_size_width = 0 +hw_cfg3->packet_size_width = 0 +hw_cfg3->otg_enable = 0 +hw_cfg3->i2c_enable = 0 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 0 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 0 +hw_cfg3->lpm_mode = 0 +hw_cfg3->total_fifo_size = 0 + +dwc2->ghwcfg4 = 0 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 0 +hw_cfg4->ahb_freq_min = 0 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 0 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 0 +hw_cfg4->vbus_valid_filter_enabled = 0 +hw_cfg4->a_valid_filter_enabled = 0 +hw_cfg4->b_valid_filter_enabled = 0 +hw_cfg4->dedicated_fifos = 0 +hw_cfg4->num_dev_in_eps = 0 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 0 + +## XMC4500 + +dwc2->guid = AEC000 +dwc2->gsnpsid = 4F54292A +dwc2->ghwcfg1 = 0 + +dwc2->ghwcfg2 = 228F5930 +hw_cfg2->op_mode = 0 +hw_cfg2->arch = 2 +hw_cfg2->point2point = 1 +hw_cfg2->hs_phy_type = 0 +hw_cfg2->fs_phy_type = 1 +hw_cfg2->num_dev_ep = 6 +hw_cfg2->num_host_ch = 13 +hw_cfg2->period_channel_support = 1 +hw_cfg2->enable_dynamic_fifo = 1 +hw_cfg2->mul_cpu_int = 0 +hw_cfg2->nperiod_tx_q_depth = 2 +hw_cfg2->host_period_tx_q_depth = 2 +hw_cfg2->dev_token_q_depth = 8 +hw_cfg2->otg_enable_ic_usb = 0 + +dwc2->ghwcfg3 = 27A01E5 +hw_cfg3->xfer_size_width = 5 +hw_cfg3->packet_size_width = 6 +hw_cfg3->otg_enable = 1 +hw_cfg3->i2c_enable = 1 +hw_cfg3->vendor_ctrl_itf = 0 +hw_cfg3->optional_feature_removed = 0 +hw_cfg3->synch_reset = 0 +hw_cfg3->otg_adp_support = 0 +hw_cfg3->otg_enable_hsic = 0 +hw_cfg3->battery_charger_support = 0 +hw_cfg3->lpm_mode = 0 +hw_cfg3->total_fifo_size = 634 + +dwc2->ghwcfg4 = DBF08030 +hw_cfg4->num_dev_period_in_ep = 0 +hw_cfg4->power_optimized = 1 +hw_cfg4->ahb_freq_min = 1 +hw_cfg4->hibernation = 0 +hw_cfg4->service_interval_mode = 0 +hw_cfg4->ipg_isoc_en = 0 +hw_cfg4->acg_enable = 0 +hw_cfg4->utmi_phy_data_width = 2 +hw_cfg4->dev_ctrl_ep_num = 0 +hw_cfg4->iddg_filter_enabled = 1 +hw_cfg4->vbus_valid_filter_enabled = 1 +hw_cfg4->a_valid_filter_enabled = 1 +hw_cfg4->b_valid_filter_enabled = 1 +hw_cfg4->dedicated_fifos = 1 +hw_cfg4->num_dev_in_eps = 13 +hw_cfg4->dma_desc_enable = 0 +hw_cfg4->dma_dynamic = 1 diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal.h index 9d11866d..f092e8ff 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/osal/osal.h +++ b/test-devices/loopback-stm32/lib/tinyusb/osal/osal.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -33,17 +33,24 @@ #include "common/tusb_common.h" -// Return immediately -#define OSAL_TIMEOUT_NOTIMEOUT (0) -// Default timeout -#define OSAL_TIMEOUT_NORMAL (10) -// Wait forever -#define OSAL_TIMEOUT_WAIT_FOREVER (UINT32_MAX) +typedef void (*osal_task_func_t)( void * ); +// Timeout +#define OSAL_TIMEOUT_NOTIMEOUT (0) // Return immediately +#define OSAL_TIMEOUT_NORMAL (10) // Default timeout +#define OSAL_TIMEOUT_WAIT_FOREVER (UINT32_MAX) // Wait forever #define OSAL_TIMEOUT_CONTROL_XFER OSAL_TIMEOUT_WAIT_FOREVER -typedef void (*osal_task_func_t)( void * ); +// Mutex is required when using a preempted RTOS or MCU has multiple cores +#if (CFG_TUSB_OS == OPT_OS_NONE) && !TUP_MCU_MULTIPLE_CORE + #define OSAL_MUTEX_REQUIRED 0 + #define OSAL_MUTEX_DEF(_name) uint8_t :0 +#else + #define OSAL_MUTEX_REQUIRED 1 + #define OSAL_MUTEX_DEF(_name) osal_mutex_def_t _name +#endif +// OS thin implementation #if CFG_TUSB_OS == OPT_OS_NONE #include "osal_none.h" #elif CFG_TUSB_OS == OPT_OS_FREERTOS diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_freertos.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_freertos.h index 52db336f..477f6489 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_freertos.h +++ b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_freertos.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -37,6 +37,43 @@ extern "C" { #endif +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF PROTYPES +//--------------------------------------------------------------------+ + +#if configSUPPORT_STATIC_ALLOCATION + typedef StaticSemaphore_t osal_semaphore_def_t; + typedef StaticSemaphore_t osal_mutex_def_t; +#else + // not used therefore defined to smallest possible type to save space + typedef uint8_t osal_semaphore_def_t; + typedef uint8_t osal_mutex_def_t; +#endif + +typedef SemaphoreHandle_t osal_semaphore_t; +typedef SemaphoreHandle_t osal_mutex_t; + +// _int_set is not used with an RTOS +#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ + static _type _name##_##buf[_depth];\ + osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf }; + +typedef struct +{ + uint16_t depth; + uint16_t item_sz; + void* buf; +#if configSUPPORT_STATIC_ALLOCATION + StaticQueue_t sq; +#endif +}osal_queue_def_t; + +typedef QueueHandle_t osal_queue_t; + +//--------------------------------------------------------------------+ +// TASK API +//--------------------------------------------------------------------+ + TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec) { if (msec == OSAL_TIMEOUT_WAIT_FOREVER) return portMAX_DELAY; @@ -51,9 +88,6 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec) return ticks; } -//--------------------------------------------------------------------+ -// TASK API -//--------------------------------------------------------------------+ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) { vTaskDelay( pdMS_TO_TICKS(msec) ); @@ -62,12 +96,15 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) //--------------------------------------------------------------------+ // Semaphore API //--------------------------------------------------------------------+ -typedef StaticSemaphore_t osal_semaphore_def_t; -typedef SemaphoreHandle_t osal_semaphore_t; TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) { +#if configSUPPORT_STATIC_ALLOCATION return xSemaphoreCreateBinaryStatic(semdef); +#else + (void) semdef; + return xSemaphoreCreateBinary(); +#endif } TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) @@ -78,7 +115,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t se } else { - BaseType_t xHigherPriorityTaskWoken; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t res = xSemaphoreGiveFromISR(sem_hdl, &xHigherPriorityTaskWoken); #if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3 @@ -92,7 +129,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t se } } -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) { return xSemaphoreTake(sem_hdl, _osal_ms2tick(msec)); } @@ -105,15 +142,18 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t c //--------------------------------------------------------------------+ // MUTEX API (priority inheritance) //--------------------------------------------------------------------+ -typedef StaticSemaphore_t osal_mutex_def_t; -typedef SemaphoreHandle_t osal_mutex_t; TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) { +#if configSUPPORT_STATIC_ALLOCATION return xSemaphoreCreateMutexStatic(mdef); +#else + (void) mdef; + return xSemaphoreCreateMutex(); +#endif } -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) { return osal_semaphore_wait(mutex_hdl, msec); } @@ -127,25 +167,13 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd // QUEUE API //--------------------------------------------------------------------+ -// _int_set is not used with an RTOS -#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ - static _type _name##_##buf[_depth];\ - osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf }; - -typedef struct -{ - uint16_t depth; - uint16_t item_sz; - void* buf; - - StaticQueue_t sq; -}osal_queue_def_t; - -typedef QueueHandle_t osal_queue_t; - TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) { - return xQueueCreateStatic(qdef->depth, qdef->item_sz, (uint8_t*) qdef->buf, &qdef->sq); +#if configSUPPORT_STATIC_ALLOCATION + return xQueueCreateStatic(qdef->depth, qdef->item_sz, (uint8_t*) qdef->buf, &qdef->sq); +#else + return xQueueCreate(qdef->depth, qdef->item_sz); +#endif } TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) @@ -161,7 +189,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void } else { - BaseType_t xHigherPriorityTaskWoken; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t res = xQueueSendToBackFromISR(qhdl, data, &xHigherPriorityTaskWoken); #if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3 diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_none.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_none.h index 9c80e454..5f407378 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_none.h +++ b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_none.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -35,6 +35,10 @@ // TASK API //--------------------------------------------------------------------+ +#if CFG_TUH_ENABLED +// currently only needed/available in host mode +void osal_task_delay(uint32_t msec); +#endif //--------------------------------------------------------------------+ // Binary Semaphore API @@ -82,6 +86,10 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t s typedef osal_semaphore_def_t osal_mutex_def_t; typedef osal_semaphore_t osal_mutex_t; +#if OSAL_MUTEX_REQUIRED +// Note: multiple cores MCUs usually do provide IPC API for mutex +// or we can use std atomic function + TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) { mdef->count = 1; @@ -98,6 +106,14 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd return osal_semaphore_post(mutex_hdl, false); } +#else + +#define osal_mutex_create(_mdef) (NULL) +#define osal_mutex_lock(_mutex_hdl, _ms) (true) +#define osal_mutex_unlock(_mutex_hdl) (true) + +#endif + //--------------------------------------------------------------------+ // QUEUE API //--------------------------------------------------------------------+ diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_pico.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_pico.h index 8b428d64..e6efa096 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_pico.h +++ b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_pico.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtthread.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtthread.h index f8452bfb..18eb9c69 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtthread.h +++ b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtthread.h @@ -63,7 +63,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t se } TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) { - // TODO: implement + rt_sem_control(sem_hdl, RT_IPC_CMD_RESET, 0); } //--------------------------------------------------------------------+ diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtx4.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtx4.h index dea1c12c..e443135e 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtx4.h +++ b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtx4.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2021 Tian Yunhao (t123yh) @@ -115,7 +115,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd os_mbx_declare(_name##__mbox, _depth); \ _declare_box(_name##__pool, sizeof(_type), _depth); \ osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .pool = _name##__pool, .mbox = _name##__mbox }; - + typedef struct { diff --git a/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c b/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c index 6550d568..30a2e9c8 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c +++ b/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Nathan Conrad @@ -6,6 +6,8 @@ * Portions: * Copyright (c) 2016 STMicroelectronics * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2022 Simon Küppers (skuep) + * Copyright (c) 2022 HiFiPhile * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -64,10 +66,6 @@ * - STALL handled, but not tested. * - Does it work? No clue. * - All EP BTABLE buffers are created based on max packet size of first EP opened with that address. - * - No isochronous endpoints - * - Endpoint index is the ID of the endpoint - * - This means that priority is given to endpoints with lower ID numbers - * - Code is mixing up EP IX with EP ID. Everywhere. * - Packet buffer memory is copied in the interrupt. * - This is better for performance, but means interrupts are disabled for longer * - DMA may be the best choice, but it could also be pushed to the USBD task. @@ -103,24 +101,15 @@ #include "tusb_option.h" -#if defined(STM32F102x6) || defined(STM32F102xB) || \ - defined(STM32F103x6) || defined(STM32F103xB) || \ - defined(STM32F103xE) || defined(STM32F103xG) -#define STM32F1_FSDEV -#endif - -#if CFG_TUD_ENABLED && \ - ( TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32F3, OPT_MCU_STM32L0, OPT_MCU_STM32L1, OPT_MCU_STM32G4, OPT_MCU_STM32WB) || \ - (TU_CHECK_MCU(OPT_MCU_STM32F1) && defined(STM32F1_FSDEV)) \ - ) - -// In order to reduce the dependance on HAL, we undefine this. -// Some definitions are copied to our private include file. -#undef USE_HAL_DRIVER +#if CFG_TUD_ENABLED && defined(TUP_USBIP_FSDEV) #include "device/dcd.h" -#include "dcd_stm32_fsdev_pvt_st.h" +#ifdef TUP_USBIP_FSDEV_STM32 + // Undefine to reduce the dependence on HAL + #undef USE_HAL_DRIVER + #include "dcd_stm32_fsdev_pvt_st.h" +#endif /***************************************************** * Configuration @@ -142,23 +131,18 @@ # define DCD_STM32_BTABLE_LENGTH (PMA_LENGTH - DCD_STM32_BTABLE_BASE) #endif -// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval) -// We disable SOF for now until needed later on -#ifndef USE_SOF -# define USE_SOF 0 -#endif - /*************************************************** * Checks, structs, defines, function definitions, etc. */ TU_VERIFY_STATIC((MAX_EP_COUNT) <= STFSDEV_EP_COUNT, "Only 8 endpoints supported on the hardware"); - -TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_LENGTH))<=(PMA_LENGTH), - "BTABLE does not fit in PMA RAM"); - +TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_LENGTH))<=(PMA_LENGTH), "BTABLE does not fit in PMA RAM"); TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligned to 8 bytes"); +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + // One of these for every EP IN & OUT, uses a bit of RAM.... typedef struct { @@ -167,49 +151,79 @@ typedef struct uint16_t total_len; uint16_t queued_len; uint16_t pma_ptr; - uint8_t max_packet_size; - uint8_t pma_alloc_size; + uint16_t max_packet_size; + uint16_t pma_alloc_size; + uint8_t ep_idx; // index for USB_EPnR register } xfer_ctl_t; +// EP allocator +typedef struct +{ + uint8_t ep_num; + uint8_t ep_type; + bool allocated[2]; +} ep_alloc_t; + static xfer_ctl_t xfer_status[MAX_EP_COUNT][2]; -static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t epnum, uint32_t dir) -{ - return &xfer_status[epnum][dir]; -} +static ep_alloc_t ep_alloc_status[STFSDEV_EP_COUNT]; static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6]; static uint8_t remoteWakeCountdown; // When wake is requested +//--------------------------------------------------------------------+ +// Prototypes +//--------------------------------------------------------------------+ + // into the stack. static void dcd_handle_bus_reset(void); static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix); static void dcd_ep_ctr_handler(void); -// PMA allocation/access +// PMA allocation/access static uint8_t open_ep_count; static uint16_t ep_buf_ptr; ///< Points to first free memory location static void dcd_pma_alloc_reset(void); static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length); static void dcd_pma_free(uint8_t ep_addr); +static void dcd_ep_free(uint8_t ep_addr); +static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type); static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes); static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes); static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes); static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes); +//--------------------------------------------------------------------+ +// Inline helper +//--------------------------------------------------------------------+ + +TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t ep_addr) +{ + uint8_t epnum = tu_edpt_number(ep_addr); + uint8_t dir = tu_edpt_dir(ep_addr); + // Fix -Werror=null-dereference + TU_ASSERT(epnum < MAX_EP_COUNT, &xfer_status[0][0]); + + return &xfer_status[epnum][dir]; +} + // Using a function due to better type checks // This seems better than having to do type casts everywhere else -static inline void reg16_clear_bits(__IO uint16_t *reg, uint16_t mask) { +TU_ATTR_ALWAYS_INLINE static inline void reg16_clear_bits(__IO uint16_t *reg, uint16_t mask) { *reg = (uint16_t)(*reg & ~mask); } // Bits in ISTR are cleared upon writing 0 -static inline void clear_istr_bits(uint16_t mask) { +TU_ATTR_ALWAYS_INLINE static inline void clear_istr_bits(uint16_t mask) { USB->ISTR = ~mask; } +//--------------------------------------------------------------------+ +// Controller API +//--------------------------------------------------------------------+ + void dcd_init (uint8_t rhport) { /* Clocks should already be enabled */ @@ -222,7 +236,7 @@ void dcd_init (uint8_t rhport) { asm("NOP"); } - // Perform USB peripheral reset + // Perform USB peripheral reset USB->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; for(uint32_t i = 0; i<200; i++) // should be a few us { @@ -235,7 +249,7 @@ void dcd_init (uint8_t rhport) asm("NOP"); } USB->CNTR = 0; // Enable USB - + USB->BTABLE = DCD_STM32_BTABLE_BASE; USB->ISTR = 0; // Clear pending interrupts @@ -247,9 +261,9 @@ void dcd_init (uint8_t rhport) pcd_set_endpoint(USB,i,0u); } - USB->CNTR |= USB_CNTR_RESETM | (USE_SOF ? USB_CNTR_SOFM : 0) | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; + USB->CNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; dcd_handle_bus_reset(); - + // Enable pull-up if supported if ( dcd_connect ) dcd_connect(rhport); } @@ -292,7 +306,14 @@ void dcd_sof_enable(uint8_t rhport, bool en) (void) rhport; (void) en; - // TODO implement later + if (en) + { + USB->CNTR |= USB_CNTR_SOFM; + } + else + { + USB->CNTR &= (uint16_t) ~USB_CNTR_SOFM; + } } // Enable device interrupt @@ -302,7 +323,8 @@ void dcd_int_enable (uint8_t rhport) // Member here forces write to RAM before allowing ISR to execute __DSB(); __ISB(); -#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 +#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || \ + CFG_TUSB_MCU == OPT_MCU_STM32L4 NVIC_EnableIRQ(USB_IRQn); #elif CFG_TUSB_MCU == OPT_MCU_STM32L1 @@ -340,6 +362,9 @@ void dcd_int_enable (uint8_t rhport) NVIC_EnableIRQ(USB_HP_IRQn); NVIC_EnableIRQ(USB_LP_IRQn); +#elif CFG_TUSB_MCU == OPT_MCU_STM32L5 + NVIC_EnableIRQ(USB_FS_IRQn); + #else #error Unknown arch in USB driver #endif @@ -350,7 +375,8 @@ void dcd_int_disable(uint8_t rhport) { (void)rhport; -#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 +#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || \ + CFG_TUSB_MCU == OPT_MCU_STM32L4 NVIC_DisableIRQ(USB_IRQn); #elif CFG_TUSB_MCU == OPT_MCU_STM32L1 NVIC_DisableIRQ(USB_LP_IRQn); @@ -386,6 +412,9 @@ void dcd_int_disable(uint8_t rhport) NVIC_DisableIRQ(USB_HP_IRQn); NVIC_DisableIRQ(USB_LP_IRQn); +#elif CFG_TUSB_MCU == OPT_MCU_STM32L5 + NVIC_DisableIRQ(USB_FS_IRQn); + #else #error Unknown arch in USB driver #endif @@ -400,7 +429,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) (void) dev_addr; // Respond with status - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); + dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK | 0x00, NULL, 0); // DCD can only set address after status for this request is complete. // do it at dcd_edpt0_status_complete() @@ -441,10 +470,17 @@ static void dcd_handle_bus_reset(void) //__IO uint16_t * const epreg = &(EPREG(0)); USB->DADDR = 0u; // disable USB peripheral by clearing the EF flag - // Clear all EPREG (or maybe this is automatic? I'm not sure) + for(uint32_t i=0; itotal_len != xfer->queued_len)) /* TX not complete */ { dcd_transmit_packet(xfer, EPindex); } else /* TX Complete */ { - dcd_event_xfer_complete(0, (uint8_t)(0x80 + EPindex), xfer->total_len, XFER_RESULT_SUCCESS, true); + dcd_event_xfer_complete(0, ep_addr, xfer->total_len, XFER_RESULT_SUCCESS, true); } } @@ -490,9 +527,9 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr) { uint32_t EPindex = wIstr & USB_ISTR_EP_ID; uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex); - uint32_t count = pcd_get_ep_rx_cnt(USB,EPindex); + uint8_t ep_addr = wEPRegVal & USB_EPADDR_FIELD; - xfer_ctl_t *xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_OUT); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); // Verify the CTR_RX bit is set. This was in the ST Micro code, // but I'm not sure it's actually necessary? @@ -500,12 +537,13 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr) { return; } - - if((EPindex == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) /* Setup packet */ + + if((ep_addr == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) /* Setup packet */ { // The setup_received function uses memcpy, so this must first copy the setup data into // user memory, to allow for the 32-bit access that memcpy performs. uint8_t userMemBuf[8]; + uint32_t count = pcd_get_ep_rx_cnt(USB, EPindex); /* Get SETUP Packet*/ if(count == 8) // Setup packet should always be 8 bytes. If not, ignore it, and try again. { @@ -518,21 +556,33 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr) } else { + uint32_t count; + /* Read from correct register when ISOCHRONOUS (double buffered) */ + if ( (wEPRegVal & USB_EP_DTOG_RX) && ( (wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) ) { + count = pcd_get_ep_tx_cnt(USB, EPindex); + } else { + count = pcd_get_ep_rx_cnt(USB, EPindex); + } + + TU_ASSERT(count <= xfer->max_packet_size, /**/); + // Clear RX CTR interrupt flag - if(EPindex != 0u) + if(ep_addr != 0u) { pcd_clear_rx_ep_ctr(USB, EPindex); } if (count != 0U) { + uint16_t addr = *pcd_ep_rx_address_ptr(USB, EPindex); + if (xfer->ff) { - dcd_read_packet_memory_ff(xfer->ff, *pcd_ep_rx_address_ptr(USB,EPindex), count); + dcd_read_packet_memory_ff(xfer->ff, addr, count); } else { - dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), *pcd_ep_rx_address_ptr(USB,EPindex), count); + dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), addr, count); } xfer->queued_len = (uint16_t)(xfer->queued_len + count); @@ -541,7 +591,7 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr) if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len)) { /* RX COMPLETE */ - dcd_event_xfer_complete(0, EPindex, xfer->queued_len, XFER_RESULT_SUCCESS, true); + dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true); // Though the host could still send, we don't know. // Does the bulk pipe need to be reset to valid to allow for a ZLP? } @@ -549,21 +599,26 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr) { uint32_t remaining = (uint32_t)xfer->total_len - (uint32_t)xfer->queued_len; if(remaining >= xfer->max_packet_size) { - pcd_set_ep_rx_cnt(USB, EPindex,xfer->max_packet_size); + pcd_set_ep_rx_bufsize(USB, EPindex,xfer->max_packet_size); } else { - pcd_set_ep_rx_cnt(USB, EPindex,remaining); + pcd_set_ep_rx_bufsize(USB, EPindex,remaining); + } + + if (!((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS)) { + /* Set endpoint active again for receiving more data. + * Note that isochronous endpoints stay active always */ + pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID); } - pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID); } } // For EP0, prepare to receive another SETUP packet. // Clear CTR last so that a new packet does not overwrite the packing being read. // (Based on the docs, it seems SETUP will always be accepted after CTR is cleared) - if(EPindex == 0u) + if(ep_addr == 0u) { // Always be prepared for a status packet... - pcd_set_ep_rx_cnt(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE); + pcd_set_ep_rx_bufsize(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE); pcd_clear_rx_ep_ctr(USB, EPindex); } } @@ -600,6 +655,12 @@ void dcd_int_handler(uint8_t rhport) { // dcd_ep_ctr_handler(), so less need to loop here. The other interrupts shouldn't // be triggered repeatedly. + /* Put SOF flag at the beginning of ISR in case to get least amount of jitter if it is used for timing purposes */ + if(int_status & USB_ISTR_SOF) { + clear_istr_bits(USB_ISTR_SOF); + dcd_event_sof(0, USB->FNR & USB_FNR_FN, true); + } + if(int_status & USB_ISTR_RESET) { // USBRST is start of reset. clear_istr_bits(USB_ISTR_RESET); @@ -637,13 +698,6 @@ void dcd_int_handler(uint8_t rhport) { dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); } -#if USE_SOF - if(int_status & USB_ISTR_SOF) { - clear_istr_bits(USB_ISTR_SOF); - dcd_event_bus_signal(0, DCD_EVENT_SOF, true); - } -#endif - if(int_status & USB_ISTR_ESOF) { if(remoteWakeCountdown == 1u) { @@ -686,29 +740,25 @@ static void dcd_pma_alloc_reset(void) //TU_LOG2("dcd_pma_alloc_reset()\r\n"); for(uint32_t i=0; ipma_alloc_size = 0U; - xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_alloc_size = 0U; - xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_ptr = 0U; - xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_ptr = 0U; + xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_OUT))->pma_alloc_size = 0U; + xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_alloc_size = 0U; + xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_OUT))->pma_ptr = 0U; + xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_ptr = 0U; } } /*** * Allocate a section of PMA - * + * * If the EP number has already been allocated, and the new allocation * is larger than the old allocation, then this will fail with a TU_ASSERT. * (This is done to simplify the code. More complicated algorithms could be used) - * + * * During failure, TU_ASSERT is used. If this happens, rework/reallocate memory manually. */ static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length) { - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - xfer_ctl_t* epXferCtl = xfer_ctl_ptr(epnum,dir); - - open_ep_count++; + xfer_ctl_t* epXferCtl = xfer_ctl_ptr(ep_addr); if(epXferCtl->pma_alloc_size != 0U) { @@ -717,13 +767,15 @@ static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length) TU_ASSERT(length <= epXferCtl->pma_alloc_size, 0xFFFF); // Verify no larger than previous alloc return epXferCtl->pma_ptr; } - - uint16_t addr = ep_buf_ptr; + + open_ep_count++; + + uint16_t addr = ep_buf_ptr; ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer - + // Verify no overflow TU_ASSERT(ep_buf_ptr <= PMA_LENGTH, 0xFFFF); - + epXferCtl->pma_ptr = addr; epXferCtl->pma_alloc_size = length; //TU_LOG2("dcd_pma_alloc(%x,%x)=%x\r\n",ep_addr,length,addr); @@ -736,12 +788,9 @@ static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length) */ static void dcd_pma_free(uint8_t ep_addr) { - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - // Presently, this should never be called for EP0 IN/OUT TU_ASSERT(open_ep_count > 2, /**/); - TU_ASSERT(xfer_ctl_ptr(epnum,dir)->max_packet_size != 0, /**/); + TU_ASSERT(xfer_ctl_ptr(ep_addr)->max_packet_size != 0, /**/); open_ep_count--; // If count is 2, only EP0 should be open, so allocations can be mostly reset. @@ -753,10 +802,83 @@ static void dcd_pma_free(uint8_t ep_addr) // Skip EP0 for(uint32_t i=1; ipma_alloc_size = 0U; - xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_alloc_size = 0U; - xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_ptr = 0U; - xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_ptr = 0U; + xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_OUT))->pma_alloc_size = 0U; + xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_alloc_size = 0U; + xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_OUT))->pma_ptr = 0U; + xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_ptr = 0U; + } + } +} + +/*** + * Allocate hardware endpoint + */ +static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + for(uint8_t i = 0; i < STFSDEV_EP_COUNT; i++) + { + // Check if already allocated + if(ep_alloc_status[i].allocated[dir] && + ep_alloc_status[i].ep_type == ep_type && + ep_alloc_status[i].ep_num == epnum) + { + return i; + } + + // If EP of current direction is not allocated + // Except for ISO endpoint, both direction should be free + if(!ep_alloc_status[i].allocated[dir] && + (ep_type != TUSB_XFER_ISOCHRONOUS || !ep_alloc_status[i].allocated[dir ^ 1])) + { + // Check if EP number is the same + if(ep_alloc_status[i].ep_num == 0xFF || + ep_alloc_status[i].ep_num == epnum) + { + // One EP pair has to be the same type + if(ep_alloc_status[i].ep_type == 0xFF || + ep_alloc_status[i].ep_type == ep_type) + { + ep_alloc_status[i].ep_num = epnum; + ep_alloc_status[i].ep_type = ep_type; + ep_alloc_status[i].allocated[dir] = true; + + return i; + } + } + } + } + + // Allocation failed + TU_ASSERT(0); +} + +/*** + * Free hardware endpoint + */ +static void dcd_ep_free(uint8_t ep_addr) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + for(uint8_t i = 0; i < STFSDEV_EP_COUNT; i++) + { + // Check if EP number & dir are the same + if(ep_alloc_status[i].ep_num == epnum && + ep_alloc_status[i].allocated[dir] == dir) + { + ep_alloc_status[i].allocated[dir] = false; + // Reset entry if ISO endpoint or both direction are free + if(ep_alloc_status[i].ep_type == TUSB_XFER_ISOCHRONOUS || + !ep_alloc_status[i].allocated[dir ^ 1]) + { + ep_alloc_status[i].ep_num = 0xFF; + ep_alloc_status[i].ep_type = 0xFF; + + return; + } } } } @@ -767,27 +889,24 @@ static void dcd_pma_free(uint8_t ep_addr) bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) { (void)rhport; - uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); + uint8_t const ep_idx = dcd_ep_alloc(p_endpoint_desc->bEndpointAddress, p_endpoint_desc->bmAttributes.xfer); uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); - const uint16_t epMaxPktSize = tu_edpt_packet_size(p_endpoint_desc); + const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc); + const uint16_t buffer_size = pcd_aligned_buffer_size(packet_size); uint16_t pma_addr; uint32_t wType; - - // Isochronous not supported (yet), and some other driver assumptions. - TU_ASSERT(p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS); - TU_ASSERT(epnum < MAX_EP_COUNT); + + TU_ASSERT(ep_idx < STFSDEV_EP_COUNT); + TU_ASSERT(buffer_size <= 1024); // Set type switch(p_endpoint_desc->bmAttributes.xfer) { case TUSB_XFER_CONTROL: wType = USB_EP_CONTROL; break; -#if (0) - case TUSB_XFER_ISOCHRONOUS: // FIXME: Not yet supported + case TUSB_XFER_ISOCHRONOUS: wType = USB_EP_ISOCHRONOUS; break; -#endif - case TUSB_XFER_BULK: wType = USB_EP_CONTROL; break; @@ -800,30 +919,49 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc TU_ASSERT(false); } - pcd_set_eptype(USB, epnum, wType); - pcd_set_ep_address(USB, epnum, epnum); + pcd_set_eptype(USB, ep_idx, wType); + pcd_set_ep_address(USB, ep_idx, tu_edpt_number(p_endpoint_desc->bEndpointAddress)); // Be normal, for now, instead of only accepting zero-byte packets (on control endpoint) // or being double-buffered (bulk endpoints) pcd_clear_ep_kind(USB,0); - pma_addr = dcd_pma_alloc(p_endpoint_desc->bEndpointAddress, epMaxPktSize); + /* Create a packet memory buffer area. For isochronous endpoints, + * use the same buffer as the double buffer, essentially disabling double buffering */ + pma_addr = dcd_pma_alloc(p_endpoint_desc->bEndpointAddress, buffer_size); - if(dir == TUSB_DIR_IN) + if( (dir == TUSB_DIR_IN) || (wType == USB_EP_ISOCHRONOUS) ) { - *pcd_ep_tx_address_ptr(USB, epnum) = pma_addr; - pcd_set_ep_tx_cnt(USB, epnum, epMaxPktSize); - pcd_clear_tx_dtog(USB, epnum); - pcd_set_ep_tx_status(USB,epnum,USB_EP_TX_NAK); + *pcd_ep_tx_address_ptr(USB, ep_idx) = pma_addr; + pcd_set_ep_tx_bufsize(USB, ep_idx, buffer_size); + pcd_clear_tx_dtog(USB, ep_idx); } - else + + if( (dir == TUSB_DIR_OUT) || (wType == USB_EP_ISOCHRONOUS) ) + { + *pcd_ep_rx_address_ptr(USB, ep_idx) = pma_addr; + pcd_set_ep_rx_bufsize(USB, ep_idx, buffer_size); + pcd_clear_rx_dtog(USB, ep_idx); + } + + /* Enable endpoint */ + if (dir == TUSB_DIR_IN) { - *pcd_ep_rx_address_ptr(USB, epnum) = pma_addr; - pcd_set_ep_rx_cnt(USB, epnum, epMaxPktSize); - pcd_clear_rx_dtog(USB, epnum); - pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_NAK); + if(wType == USB_EP_ISOCHRONOUS) { + pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); + } else { + pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK); + } + } else + { + if(wType == USB_EP_ISOCHRONOUS) { + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); + } else { + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK); + } } - xfer_ctl_ptr(epnum, dir)->max_packet_size = epMaxPktSize; + xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->max_packet_size = packet_size; + xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->ep_idx = ep_idx; return true; } @@ -836,29 +974,89 @@ void dcd_edpt_close_all (uint8_t rhport) /** * Close an endpoint. - * + * * This function may be called with interrupts enabled or disabled. - * + * * This also clears transfers in progress, should there be any. */ void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) { (void)rhport; - uint32_t const epnum = tu_edpt_number(ep_addr); - uint32_t const dir = tu_edpt_dir(ep_addr); - + + xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + uint8_t const ep_idx = xfer->ep_idx; + uint8_t const dir = tu_edpt_dir(ep_addr); + if(dir == TUSB_DIR_IN) { - pcd_set_ep_tx_status(USB,epnum,USB_EP_TX_DIS); + pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); } else { - pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_DIS); + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); } + dcd_ep_free(ep_addr); + dcd_pma_free(ep_addr); } +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) +{ + (void)rhport; + + TU_ASSERT(largest_packet_size <= 1024); + + uint8_t const ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS); + const uint16_t buffer_size = pcd_aligned_buffer_size(largest_packet_size); + + /* Create a packet memory buffer area. For isochronous endpoints, + * use the same buffer as the double buffer, essentially disabling double buffering */ + uint16_t pma_addr = dcd_pma_alloc(ep_addr, buffer_size); + + xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx; + + pcd_set_eptype(USB, ep_idx, USB_EP_ISOCHRONOUS); + + *pcd_ep_tx_address_ptr(USB, ep_idx) = pma_addr; + *pcd_ep_rx_address_ptr(USB, ep_idx) = pma_addr; + + return true; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) +{ + (void)rhport; + uint8_t const ep_idx = xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->ep_idx; + uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); + const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc); + const uint16_t buffer_size = pcd_aligned_buffer_size(packet_size); + + /* Disable endpoint */ + if(dir == TUSB_DIR_IN) + { + pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); + } + else + { + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); + } + + pcd_set_ep_address(USB, ep_idx, tu_edpt_number(p_endpoint_desc->bEndpointAddress)); + // Be normal, for now, instead of only accepting zero-byte packets (on control endpoint) + // or being double-buffered (bulk endpoints) + pcd_clear_ep_kind(USB,0); + + pcd_set_ep_tx_bufsize(USB, ep_idx, buffer_size); + pcd_set_ep_rx_bufsize(USB, ep_idx, buffer_size); + pcd_clear_tx_dtog(USB, ep_idx); + pcd_clear_rx_dtog(USB, ep_idx); + + xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->max_packet_size = packet_size; + + return true; +} + // Currently, single-buffered, and only 64 bytes at a time (max) static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix) @@ -869,19 +1067,27 @@ static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix) { len = xfer->max_packet_size; } - uint16_t oldAddr = *pcd_ep_tx_address_ptr(USB,ep_ix); + + uint16_t ep_reg = pcd_get_endpoint(USB, ep_ix); + uint16_t addr_ptr = *pcd_ep_tx_address_ptr(USB,ep_ix); if (xfer->ff) { - dcd_write_packet_memory_ff(xfer->ff, oldAddr, len); + dcd_write_packet_memory_ff(xfer->ff, addr_ptr, len); } else { - dcd_write_packet_memory(oldAddr, &(xfer->buffer[xfer->queued_len]), len); + dcd_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len); } xfer->queued_len = (uint16_t)(xfer->queued_len + len); - pcd_set_ep_tx_cnt(USB,ep_ix,len); + /* Write into correct register when ISOCHRONOUS (double buffered) */ + if ( (ep_reg & USB_EP_DTOG_TX) && ( (ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) ) { + pcd_set_ep_rx_cnt(USB, ep_ix, len); + } else { + pcd_set_ep_tx_cnt(USB, ep_ix, len); + } + pcd_set_ep_tx_status(USB, ep_ix, USB_EP_TX_VALID); } @@ -889,10 +1095,9 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t { (void) rhport; - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - - xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir); + xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + uint8_t const ep_idx = xfer->ep_idx; + uint8_t const dir = tu_edpt_dir(ep_addr); xfer->buffer = buffer; xfer->ff = NULL; @@ -903,21 +1108,22 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t { // A setup token can occur immediately after an OUT STATUS packet so make sure we have a valid // buffer for the control endpoint. - if (epnum == 0 && buffer == NULL) + if (ep_idx == 0 && buffer == NULL) { xfer->buffer = (uint8_t*)_setup_packet; } + if(total_bytes > xfer->max_packet_size) { - pcd_set_ep_rx_cnt(USB,epnum,xfer->max_packet_size); + pcd_set_ep_rx_bufsize(USB,ep_idx,xfer->max_packet_size); } else { - pcd_set_ep_rx_cnt(USB,epnum,total_bytes); + pcd_set_ep_rx_bufsize(USB,ep_idx,total_bytes); } - pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_VALID); + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_VALID); } else // IN { - dcd_transmit_packet(xfer,epnum); + dcd_transmit_packet(xfer,ep_idx); } return true; } @@ -926,11 +1132,10 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 { (void) rhport; - uint8_t const epnum = tu_edpt_number(ep_addr); + xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + uint8_t const epnum = xfer->ep_idx; uint8_t const dir = tu_edpt_dir(ep_addr); - xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir); - xfer->buffer = NULL; xfer->ff = ff; xfer->total_len = total_bytes; @@ -940,9 +1145,9 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 { if(total_bytes > xfer->max_packet_size) { - pcd_set_ep_rx_cnt(USB,epnum,xfer->max_packet_size); + pcd_set_ep_rx_bufsize(USB,epnum,xfer->max_packet_size); } else { - pcd_set_ep_rx_cnt(USB,epnum,total_bytes); + pcd_set_ep_rx_bufsize(USB,epnum,total_bytes); } pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_VALID); } @@ -957,13 +1162,17 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) { (void)rhport; - if (ep_addr & 0x80) + xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + uint8_t const ep_idx = xfer->ep_idx; + uint8_t const dir = tu_edpt_dir(ep_addr); + + if (dir == TUSB_DIR_IN) { // IN - pcd_set_ep_tx_status(USB, ep_addr & 0x7F, USB_EP_TX_STALL); + pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_STALL); } else { // OUT - pcd_set_ep_rx_status(USB, ep_addr, USB_EP_RX_STALL); + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_STALL); } } @@ -971,21 +1180,26 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) { (void)rhport; - if (ep_addr & 0x80) - { // IN - ep_addr &= 0x7F; + xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + uint8_t const ep_idx = xfer->ep_idx; + uint8_t const dir = tu_edpt_dir(ep_addr); - pcd_set_ep_tx_status(USB,ep_addr, USB_EP_TX_NAK); + if (dir == TUSB_DIR_IN) + { // IN + if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) { + pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK); + } /* Reset to DATA0 if clearing stall condition. */ - pcd_clear_tx_dtog(USB,ep_addr); + pcd_clear_tx_dtog(USB, ep_idx); } else { // OUT + if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) { + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK); + } /* Reset to DATA0 if clearing stall condition. */ - pcd_clear_rx_dtog(USB,ep_addr); - - pcd_set_ep_rx_status(USB,ep_addr, USB_EP_RX_NAK); + pcd_clear_rx_dtog(USB, ep_idx); } } @@ -1002,8 +1216,7 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) */ static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes) { - uint32_t n = ((uint32_t)wNBytes + 1U) >> 1U; - uint32_t i; + uint32_t n = (uint32_t)wNBytes >> 1U; uint16_t temp1, temp2; const uint8_t * srcVal; @@ -1014,15 +1227,22 @@ static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, si srcVal = src; pdwVal = &pma[PMA_STRIDE*(dst>>1)]; - for (i = n; i != 0; i--) + while (n--) { - temp1 = (uint16_t) *srcVal; + temp1 = (uint16_t)*srcVal; srcVal++; - temp2 = temp1 | ((uint16_t)((uint16_t) ((*srcVal) << 8U))) ; + temp2 = temp1 | ((uint16_t)(((uint16_t)(*srcVal)) << 8U)) ; *pdwVal = temp2; pdwVal += PMA_STRIDE; srcVal++; } + + if (wNBytes & 0x01) + { + temp1 = *srcVal; + *pdwVal = temp1; + } + return true; } @@ -1035,46 +1255,43 @@ static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, si static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes) { // Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies - - // Check for first linear part tu_fifo_buffer_info_t info; tu_fifo_get_read_info(ff, &info); - uint16_t lenLin = tu_min16(info.len_lin, wNBytes); - TU_VERIFY(lenLin && dcd_write_packet_memory(dst, info.ptr_lin, lenLin)); // and write it into the PMA + uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin); + uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap); - // Check for wrapped part - uint16_t lenWrap = 0; - if (lenLin < wNBytes) + // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part, + // last lin byte will be combined with wrapped part + // To ensure PMA is always access 16bit aligned (dst aligned to 16 bit) + if((cnt_lin & 0x01) && cnt_wrap) { - TU_VERIFY(info.len_wrap); - - // Update destination pointer - dst += lenLin; + // Copy first linear part + dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin &~0x01); + dst += cnt_lin &~0x01; - // Get destination pointer - uint8_t * src = info.ptr_wrap; + // Copy last linear byte & first wrapped byte + uint16_t tmp = ((uint8_t*)info.ptr_lin)[cnt_lin - 1] | ((uint16_t)(((uint8_t*)info.ptr_wrap)[0]) << 8U); + dcd_write_packet_memory(dst, &tmp, 2); + dst += 2; - // Length of second, wrapped part - lenWrap = tu_min16(info.len_wrap, wNBytes - lenLin); + // Copy rest of wrapped byte + dcd_write_packet_memory(dst, ((uint8_t*)info.ptr_wrap) + 1, cnt_wrap - 1); + } + else + { + // Copy linear part + dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin); + dst += info.len_lin; - // Since PMA is accessed 16-bit wise we need to handle the case when a 16 bit value was split - if (lenLin % 2) // If len is uneven there is a byte left to copy + if(info.len_wrap) { - // Since PMA can accessed only 16 bit-wise we copy the last byte again - uint32_t temp = ((uint8_t*)info.ptr_lin)[lenLin - 1] | ((*src) << 8); - pma[PMA_STRIDE*(dst>>1)] = temp; - dst++; - src++; - lenLin++; - lenWrap--; + // Copy wrapped byte + dcd_write_packet_memory(dst, info.ptr_wrap, cnt_wrap); } - - TU_VERIFY(dcd_write_packet_memory(dst, src, lenWrap)); // write it into the PMA } - // update the PMA write pointer - tu_fifo_advance_read_pointer(ff, lenLin + lenWrap); + tu_fifo_advance_read_pointer(ff, cnt_lin + cnt_wrap); return true; } @@ -1088,7 +1305,6 @@ static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wN static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes) { uint32_t n = (uint32_t)wNBytes >> 1U; - uint32_t i; // The GCC optimizer will combine access to 32-bit sizes if we let it. Force // it volatile so that it won't do that. __IO const uint16_t *pdwVal; @@ -1097,7 +1313,7 @@ static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wN pdwVal = &pma[PMA_STRIDE*(src>>1)]; uint8_t *dstVal = (uint8_t*)dst; - for (i = n; i != 0U; i--) + while (n--) { temp = *pdwVal; pdwVal += PMA_STRIDE; @@ -1105,7 +1321,7 @@ static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wN *dstVal++ = ((temp >> 8) & 0xFF); } - if (wNBytes % 2) + if (wNBytes & 0x01) { temp = *pdwVal; pdwVal += PMA_STRIDE; @@ -1125,41 +1341,47 @@ static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNB // Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies // Check for first linear part tu_fifo_buffer_info_t info; - tu_fifo_get_write_info(ff, &info); - uint16_t lenLin = tu_min16(info.len_lin, wNBytes); - TU_VERIFY(lenLin && dcd_read_packet_memory(info.ptr_lin, src, lenLin)); + tu_fifo_get_write_info(ff, &info); // We want to read from the FIFO + + uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin); + uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap); - // Check for wrapped part - uint16_t lenWrap = 0; - if (lenLin < wNBytes) + // We want to read from PMA and write it into the FIFO, if LIN part is ODD and has WRAPPED part, + // last lin byte will be combined with wrapped part + // To ensure PMA is always access 16bit aligned (src aligned to 16 bit) + if((cnt_lin & 0x01) && cnt_wrap) { - // Update source pointer - src += lenLin; + // Copy first linear part + dcd_read_packet_memory(info.ptr_lin, src, cnt_lin &~0x01); + src += cnt_lin &~0x01; - // Get destination pointer - uint8_t * dst = info.ptr_wrap; + // Copy last linear byte & first wrapped byte + uint16_t tmp; + dcd_read_packet_memory(&tmp, src, 2); - // Length of second, wrapped part - lenWrap = tu_min16(info.len_wrap, wNBytes - lenLin); + ((uint8_t*)info.ptr_lin)[cnt_lin - 1] = (uint8_t)tmp; + ((uint8_t*)info.ptr_wrap)[0] = (uint8_t)(tmp >> 8U); + src += 2; - // Since PMA is accessed 16-bit wise we need to handle the case when a 16 bit value was split - if (lenLin % 2) // If len is uneven there is a byte left to copy + // Copy rest of wrapped byte + dcd_read_packet_memory(((uint8_t*)info.ptr_wrap) + 1, src, cnt_wrap - 1); + } + else + { + // Copy linear part + dcd_read_packet_memory(info.ptr_lin, src, cnt_lin); + src += cnt_lin; + + if(info.len_wrap) { - uint32_t temp = pma[PMA_STRIDE*(src>>1)]; - *dst = temp >> 8; - src++; - dst++; - lenLin++; - lenWrap--; + // Copy wrapped byte + dcd_read_packet_memory(info.ptr_wrap, src, cnt_wrap); } - - TU_VERIFY(dcd_read_packet_memory(dst, src, lenWrap)); } - tu_fifo_advance_write_pointer(ff, lenLin + lenWrap); + tu_fifo_advance_write_pointer(ff, cnt_lin + cnt_wrap); return true; } #endif - diff --git a/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h b/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h index bffae450..e3fc8aeb 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h +++ b/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h @@ -1,12 +1,6 @@ /** - ****************************************************************************** - * @file dcd_stm32f0_pvt_st.h - * @brief DCD utilities from ST code - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2016 STMicroelectronics

- *

© parts COPYRIGHT(c) N Conrad

+ * Copyright(c) 2016 STMicroelectronics + * Copyright(c) N Conrad * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -30,7 +24,7 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - **********/ + */ // This file contains source copied from ST's HAL, and thus should have their copyright statement. @@ -41,10 +35,7 @@ #ifndef PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ #define PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ -#if defined(STM32F042x6) || \ - defined(STM32F070x6) || defined(STM32F070xB) || \ - defined(STM32F072xB) || \ - defined(STM32F078xx) +#if CFG_TUSB_MCU == OPT_MCU_STM32F0 #include "stm32f0xx.h" #define PMA_LENGTH (1024u) // F0x2 models are crystal-less @@ -52,7 +43,7 @@ // 070RB: 2 x 16 bits/word memory LPM Support, BCD Support // PMA dedicated to USB (no sharing with CAN) -#elif defined(STM32F1_FSDEV) +#elif CFG_TUSB_MCU == OPT_MCU_STM32F1 #include "stm32f1xx.h" #define PMA_LENGTH (512u) // NO internal Pull-ups @@ -98,6 +89,18 @@ #undef USB_PMAADDR #define USB_PMAADDR USB1_PMAADDR +#elif CFG_TUSB_MCU == OPT_MCU_STM32L4 + #include "stm32l4xx.h" + #define PMA_LENGTH (1024u) + +#elif CFG_TUSB_MCU == OPT_MCU_STM32L5 + #include "stm32l5xx.h" + #define PMA_LENGTH (1024u) + + #ifndef USB_PMAADDR + #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS)) + #endif + #else #error You are using an untested or unimplemented STM32 variant. Please update the driver. // This includes L1x0, L1x1, L1x2, L4x2 and L4x3, G1x1, G1x3, and G1x4 @@ -116,76 +119,89 @@ static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR; // prototypes -static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum); -static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum); -static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wRegValue); +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx); +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx); +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue); +/* Aligned buffer size according to hardware */ +TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t size) +{ + /* The STM32 full speed USB peripheral supports only a limited set of + * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */ + uint16_t blocksize = (size > 62) ? 32 : 2; + + // Round up while dividing requested size by blocksize + uint16_t numblocks = (size + blocksize - 1) / blocksize ; + + return numblocks * blocksize; +} /* SetENDPOINT */ -static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wRegValue) +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue) { - __O uint16_t *reg = (__O uint16_t *)((&USBx->EP0R) + bEpNum*2u); + __O uint16_t *reg = (__O uint16_t *)((&USBx->EP0R) + bEpIdx*2u); *reg = (uint16_t)wRegValue; } /* GetENDPOINT */ -static inline uint16_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpNum) { - __I uint16_t *reg = (__I uint16_t *)((&USBx->EP0R) + bEpNum*2u); +TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx) { + __I uint16_t *reg = (__I uint16_t *)((&USBx->EP0R) + bEpIdx*2u); return *reg; } -static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wType) +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wType) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= (uint32_t)USB_EP_T_MASK; regVal |= wType; regVal |= USB_EP_CTR_RX | USB_EP_CTR_TX; // These clear on write0, so must set high - pcd_set_endpoint(USBx, bEpNum, regVal); + pcd_set_endpoint(USBx, bEpIdx, regVal); } -static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EP_T_FIELD; return regVal; } /** * @brief Clears bit CTR_RX / CTR_TX in the endpoint register. * @param USBx USB peripheral instance register address. - * @param bEpNum Endpoint Number. + * @param bEpIdx Endpoint Number. * @retval None */ -static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal &= ~USB_EP_CTR_RX; regVal |= USB_EP_CTR_TX; // preserve CTR_TX (clears on writing 0) - pcd_set_endpoint(USBx, bEpNum, regVal); + pcd_set_endpoint(USBx, bEpIdx, regVal); } -static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpNum) + +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal &= ~USB_EP_CTR_TX; regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0) - pcd_set_endpoint(USBx, bEpNum,regVal); + pcd_set_endpoint(USBx, bEpIdx,regVal); } /** * @brief gets counter of the tx buffer. * @param USBx USB peripheral instance register address. - * @param bEpNum Endpoint Number. + * @param bEpIdx Endpoint Number. * @retval Counter value */ -static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) { - __I uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpNum); + __I uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpIdx); return *regPtr & 0x3ffU; } -static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) { - __I uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpNum); + __I uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpIdx); return *regPtr & 0x3ffU; } @@ -196,49 +212,36 @@ static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpNum) * @param wNBlocks no. of Blocks. * @retval None */ +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_cnt_reg(__O uint16_t * pdwReg, size_t wCount) +{ + /* We assume that the buffer size is already aligned to hardware requirements. */ + uint16_t blocksize = (wCount > 62) ? 1 : 0; + uint16_t numblocks = wCount / (blocksize ? 32 : 2); -static inline void pcd_set_ep_cnt_rx_reg(__O uint16_t * pdwReg, size_t wCount) { - uint32_t wNBlocks; - if(wCount > 62u) - { - wNBlocks = wCount >> 5u; - if((wCount & 0x1fU) == 0u) - { - wNBlocks--; - } - wNBlocks = wNBlocks << 10u; - wNBlocks |= 0x8000u; // Mark block size as 32byte - *pdwReg = (uint16_t)wNBlocks; - } - else - { - wNBlocks = wCount >> 1u; - if((wCount & 0x1U) != 0u) - { - wNBlocks++; - } - *pdwReg = (uint16_t)((wNBlocks) << 10u); - } -} + /* There should be no remainder in the above calculation */ + TU_ASSERT((wCount - (numblocks * (blocksize ? 32 : 2))) == 0, /**/); + /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ + *pdwReg = (blocksize << 15) | ((numblocks - blocksize) << 10); +} /** * @brief Sets address in an endpoint register. * @param USBx USB peripheral instance register address. - * @param bEpNum Endpoint Number. + * @param bEpIdx Endpoint Number. * @param bAddr Address. * @retval None */ -static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t bAddr) +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t bAddr) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal |= bAddr; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpNum,regVal); + pcd_set_endpoint(USBx, bEpIdx,regVal); } -static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) { size_t total_word_offset = (((USBx)->BTABLE)>>1) + x; total_word_offset *= PMA_STRIDE; @@ -246,46 +249,61 @@ static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) } // Pointers to the PMA table entries (using the ARM address space) -static inline __IO uint16_t* pcd_ep_tx_address_ptr(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_address_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { - return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 0u); + return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 0u); } -static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { - return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 1u); + return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 1u); } -static inline __IO uint16_t* pcd_ep_rx_address_ptr(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_address_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { - return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 2u); + return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 2u); } -static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { - return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 3u); + return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 3u); } -static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wCount) +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { - *pcd_ep_tx_cnt_ptr(USBx, bEpNum) = (uint16_t)wCount; + __IO uint16_t * reg = pcd_ep_tx_cnt_ptr(USBx, bEpIdx); + *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU); } -static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wCount) +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { - __IO uint16_t *pdwReg = pcd_ep_rx_cnt_ptr((USBx),(bEpNum)); - pcd_set_ep_cnt_rx_reg(pdwReg, wCount); + __IO uint16_t * reg = pcd_ep_rx_cnt_ptr(USBx, bEpIdx); + *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU); +} + +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) +{ + __IO uint16_t *pdwReg = pcd_ep_tx_cnt_ptr((USBx),(bEpIdx)); + wCount = pcd_aligned_buffer_size(wCount); + pcd_set_ep_cnt_reg(pdwReg, wCount); +} + +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) +{ + __IO uint16_t *pdwReg = pcd_ep_rx_cnt_ptr((USBx),(bEpIdx)); + wCount = pcd_aligned_buffer_size(wCount); + pcd_set_ep_cnt_reg(pdwReg, wCount); } /** * @brief sets the status for tx transfer (bits STAT_TX[1:0]). * @param USBx USB peripheral instance register address. - * @param bEpNum Endpoint Number. + * @param bEpIdx Endpoint Number. * @param wState new state * @retval None */ -static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wState) +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPTX_DTOGMASK; /* toggle first bit ? */ @@ -298,21 +316,22 @@ static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpNum, ui { regVal ^= USB_EPTX_DTOG2; } + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpNum, regVal); + pcd_set_endpoint(USBx, bEpIdx, regVal); } /* pcd_set_ep_tx_status */ /** * @brief sets the status for rx transfer (bits STAT_TX[1:0]) * @param USBx USB peripheral instance register address. - * @param bEpNum Endpoint Number. + * @param bEpIdx Endpoint Number. * @param wState new state * @retval None */ -static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wState) +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPRX_DTOGMASK; /* toggle first bit ? */ @@ -325,13 +344,14 @@ static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpNum, ui { regVal ^= USB_EPRX_DTOG2; } + regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpNum, regVal); + pcd_set_endpoint(USBx, bEpIdx, regVal); } /* pcd_set_ep_rx_status */ -static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); return (regVal & USB_EPRX_STAT) >> (12u); } /* pcd_get_ep_rx_status */ @@ -339,71 +359,71 @@ static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpNum /** * @brief Toggles DTOG_RX / DTOG_TX bit in the endpoint register. * @param USBx USB peripheral instance register address. - * @param bEpNum Endpoint Number. + * @param bEpIdx Endpoint Number. * @retval None */ -static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_RX; - pcd_set_endpoint(USBx, bEpNum, regVal); + pcd_set_endpoint(USBx, bEpIdx, regVal); } -static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_TX; - pcd_set_endpoint(USBx, bEpNum, regVal); + pcd_set_endpoint(USBx, bEpIdx, regVal); } /** * @brief Clears DTOG_RX / DTOG_TX bit in the endpoint register. * @param USBx USB peripheral instance register address. - * @param bEpNum Endpoint Number. + * @param bEpIdx Endpoint Number. * @retval None */ -static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); if((regVal & USB_EP_DTOG_RX) != 0) { - pcd_rx_dtog(USBx,bEpNum); + pcd_rx_dtog(USBx,bEpIdx); } } -static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); if((regVal & USB_EP_DTOG_TX) != 0) { - pcd_tx_dtog(USBx,bEpNum); + pcd_tx_dtog(USBx,bEpIdx); } } /** * @brief set & clear EP_KIND bit. * @param USBx USB peripheral instance register address. - * @param bEpNum Endpoint Number. + * @param bEpIdx Endpoint Number. * @retval None */ -static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal |= USB_EP_KIND; regVal &= USB_EPREG_MASK; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpNum, regVal); + pcd_set_endpoint(USBx, bEpIdx, regVal); } -static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpNum) +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); + uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPKIND_MASK; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpNum, regVal); + pcd_set_endpoint(USBx, bEpIdx, regVal); } // This checks if the device has "LPM" @@ -417,6 +437,7 @@ static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpNum) USB_ISTR_RESET | USB_ISTR_SOF | USB_ISTR_ESOF | USB_ISTR_L1REQ_FORCED ) // Number of endpoints in hardware +// TODO should use TUP_DCD_ENDPOINT_MAX #define STFSDEV_EP_COUNT (8u) #endif /* PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/tusb.c b/test-devices/loopback-stm32/lib/tinyusb/tusb.c index c3787ff8..85fe5a3c 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/tusb.c +++ b/test-devices/loopback-stm32/lib/tinyusb/tusb.c @@ -31,11 +31,18 @@ #include "tusb.h" #include "common/tusb_private.h" -// TODO clean up #if CFG_TUD_ENABLED #include "device/usbd_pvt.h" #endif +#if CFG_TUH_ENABLED +#include "host/usbh_classdriver.h" +#endif + +//--------------------------------------------------------------------+ +// Public API +//--------------------------------------------------------------------+ + bool tusb_init(void) { #if CFG_TUD_ENABLED && defined(TUD_OPT_RHPORT) @@ -67,18 +74,51 @@ bool tusb_inited(void) } //--------------------------------------------------------------------+ -// Internal Helper for both Host and Device stack +// Descriptor helper +//--------------------------------------------------------------------+ + +uint8_t const * tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byte1) +{ + while(desc+1 < end) + { + if ( desc[1] == byte1 ) return desc; + desc += desc[DESC_OFFSET_LEN]; + } + return NULL; +} + +uint8_t const * tu_desc_find2(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2) +{ + while(desc+2 < end) + { + if ( desc[1] == byte1 && desc[2] == byte2) return desc; + desc += desc[DESC_OFFSET_LEN]; + } + return NULL; +} + +uint8_t const * tu_desc_find3(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2, uint8_t byte3) +{ + while(desc+3 < end) + { + if (desc[1] == byte1 && desc[2] == byte2 && desc[3] == byte3) return desc; + desc += desc[DESC_OFFSET_LEN]; + } + return NULL; +} + + +//--------------------------------------------------------------------+ +// Endpoint Helper for both Host and Device stack //--------------------------------------------------------------------+ bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex) { (void) mutex; -#if TUSB_OPT_MUTEX // pre-check to help reducing mutex lock TU_VERIFY((ep_state->busy == 0) && (ep_state->claimed == 0)); - osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); -#endif + (void) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); // can only claim the endpoint if it is not busy and not claimed yet. bool const available = (ep_state->busy == 0) && (ep_state->claimed == 0); @@ -87,9 +127,7 @@ bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex) ep_state->claimed = 1; } -#if TUSB_OPT_MUTEX - osal_mutex_unlock(mutex); -#endif + (void) osal_mutex_unlock(mutex); return available; } @@ -98,9 +136,7 @@ bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex) { (void) mutex; -#if TUSB_OPT_MUTEX - osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); -#endif + (void) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); // can only release the endpoint if it is claimed and not busy bool const ret = (ep_state->claimed == 1) && (ep_state->busy == 0); @@ -109,9 +145,7 @@ bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex) ep_state->claimed = 0; } -#if TUSB_OPT_MUTEX - osal_mutex_unlock(mutex); -#endif + (void) osal_mutex_unlock(mutex); return ret; } @@ -204,9 +238,184 @@ uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, return len; } -/*------------------------------------------------------------------*/ -/* Debug - *------------------------------------------------------------------*/ +//--------------------------------------------------------------------+ +// Endpoint Stream Helper for both Host and Device stack +//--------------------------------------------------------------------+ + +bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool overwritable, + void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize) +{ + osal_mutex_t new_mutex = osal_mutex_create(&s->ff_mutex); + (void) new_mutex; + (void) is_tx; + + s->is_host = is_host; + tu_fifo_config(&s->ff, ff_buf, ff_bufsize, 1, overwritable); + tu_fifo_config_mutex(&s->ff, is_tx ? new_mutex : NULL, is_tx ? NULL : new_mutex); + + s->ep_buf = ep_buf; + s->ep_bufsize = ep_bufsize; + + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline +bool stream_claim(tu_edpt_stream_t* s) +{ + if (s->is_host) + { + #if CFG_TUH_ENABLED + return usbh_edpt_claim(s->daddr, s->ep_addr); + #endif + }else + { + #if CFG_TUD_ENABLED + return usbd_edpt_claim(s->rhport, s->ep_addr); + #endif + } + + return false; +} + +TU_ATTR_ALWAYS_INLINE static inline +bool stream_xfer(tu_edpt_stream_t* s, uint16_t count) +{ + if (s->is_host) + { + #if CFG_TUH_ENABLED + return usbh_edpt_xfer(s->daddr, s->ep_addr, count ? s->ep_buf : NULL, count); + #endif + }else + { + #if CFG_TUD_ENABLED + return usbd_edpt_xfer(s->rhport, s->ep_addr, count ? s->ep_buf : NULL, count); + #endif + } + + return false; +} + +TU_ATTR_ALWAYS_INLINE static inline +bool stream_release(tu_edpt_stream_t* s) +{ + if (s->is_host) + { + #if CFG_TUH_ENABLED + return usbh_edpt_release(s->daddr, s->ep_addr); + #endif + }else + { + #if CFG_TUD_ENABLED + return usbd_edpt_release(s->rhport, s->ep_addr); + #endif + } + + return false; +} + +//--------------------------------------------------------------------+ +// Stream Write +//--------------------------------------------------------------------+ + +bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes) +{ + // ZLP condition: no pending data, last transferred bytes is multiple of packet size + TU_VERIFY( !tu_fifo_count(&s->ff) && last_xferred_bytes && (0 == (last_xferred_bytes & (s->ep_packetsize-1))) ); + + TU_VERIFY( stream_claim(s) ); + TU_ASSERT( stream_xfer(s, 0) ); + + return true; +} + +uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) +{ + // skip if no data + TU_VERIFY( tu_fifo_count(&s->ff), 0 ); + + // Claim the endpoint + TU_VERIFY( stream_claim(s), 0 ); + + // Pull data from FIFO -> EP buf + uint16_t const count = tu_fifo_read_n(&s->ff, s->ep_buf, s->ep_bufsize); + + if ( count ) + { + TU_ASSERT( stream_xfer(s, count), 0 ); + return count; + }else + { + // Release endpoint since we don't make any transfer + // Note: data is dropped if terminal is not connected + stream_release(s); + return 0; + } +} + +uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize) +{ + TU_VERIFY(bufsize); // TODO support ZLP + + uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); + + // flush if fifo has more than packet size or + // in rare case: fifo depth is configured too small (which never reach packet size) + if ( (tu_fifo_count(&s->ff) >= s->ep_packetsize) || (tu_fifo_depth(&s->ff) < s->ep_packetsize) ) + { + tu_edpt_stream_write_xfer(s); + } + + return ret; +} + +//--------------------------------------------------------------------+ +// Stream Read +//--------------------------------------------------------------------+ + +uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) +{ + uint16_t available = tu_fifo_remaining(&s->ff); + + // Prepare for incoming data but only allow what we can store in the ring buffer. + // TODO Actually we can still carry out the transfer, keeping count of received bytes + // and slowly move it to the FIFO when read(). + // This pre-check reduces endpoint claiming + TU_VERIFY(available >= s->ep_packetsize); + + // claim endpoint + TU_VERIFY(stream_claim(s), 0); + + // get available again since fifo can be changed before endpoint is claimed + available = tu_fifo_remaining(&s->ff); + + if ( available >= s->ep_packetsize ) + { + // multiple of packet size limit by ep bufsize + uint16_t count = (uint16_t) (available & ~(s->ep_packetsize -1)); + count = tu_min16(count, s->ep_bufsize); + + TU_ASSERT( stream_xfer(s, count), 0 ); + + return count; + }else + { + // Release endpoint since we don't make any transfer + stream_release(s); + return 0; + } +} + +uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize) +{ + uint32_t num_read = tu_fifo_read_n(&s->ff, buffer, (uint16_t) bufsize); + tu_edpt_stream_read_xfer(s); + return num_read; +} + +//--------------------------------------------------------------------+ +// Debug +//--------------------------------------------------------------------+ + #if CFG_TUSB_DEBUG #include @@ -286,7 +495,7 @@ void tu_print_mem(void const *buf, uint32_t count, uint8_t indent) tu_printf("%04X: ", 16*i/item_per_line); } - memcpy(&value, buf8, size); + tu_memcpy_s(&value, sizeof(value), buf8, size); buf8 += size; tu_printf(" "); diff --git a/test-devices/loopback-stm32/lib/tinyusb/tusb_option.h b/test-devices/loopback-stm32/lib/tinyusb/tusb_option.h index e7fc6885..4f3f3a98 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/tusb_option.h +++ b/test-devices/loopback-stm32/lib/tinyusb/tusb_option.h @@ -27,13 +27,10 @@ #ifndef _TUSB_OPTION_H_ #define _TUSB_OPTION_H_ -// To avoid GCC compiler warnings when -pedantic option is used (strict ISO C) -typedef int make_iso_compilers_happy; - #include "common/tusb_compiler.h" #define TUSB_VERSION_MAJOR 0 -#define TUSB_VERSION_MINOR 14 +#define TUSB_VERSION_MINOR 15 #define TUSB_VERSION_REVISION 0 #define TUSB_VERSION_STRING TU_STRING(TUSB_VERSION_MAJOR) "." TU_STRING(TUSB_VERSION_MINOR) "." TU_STRING(TUSB_VERSION_REVISION) @@ -84,6 +81,8 @@ typedef int make_iso_compilers_happy; #define OPT_MCU_STM32G0 310 ///< ST G0 #define OPT_MCU_STM32G4 311 ///< ST G4 #define OPT_MCU_STM32WB 312 ///< ST WB +#define OPT_MCU_STM32U5 313 ///< ST U5 +#define OPT_MCU_STM32L5 314 ///< ST L5 // Sony #define OPT_MCU_CXD56 400 ///< SONY CXD56 @@ -119,8 +118,11 @@ typedef int make_iso_compilers_happy; #define OPT_MCU_RP2040 1100 ///< Raspberry Pi RP2040 // NXP Kinetis -#define OPT_MCU_MKL25ZXX 1200 ///< NXP MKL25Zxx -#define OPT_MCU_K32L2BXX 1201 ///< NXP K32L2Bxx +#define OPT_MCU_KINETIS_KL 1200 ///< NXP KL series +#define OPT_MCU_KINETIS_K32 1201 ///< NXP K32 series + +#define OPT_MCU_MKL25ZXX 1200 ///< Alias to KL (obsolete) +#define OPT_MCU_K32L2BXX 1201 ///< Alias to K32 (obsolete) // Silabs #define OPT_MCU_EFM32GG 1300 ///< Silabs EFM32GG @@ -129,6 +131,8 @@ typedef int make_iso_compilers_happy; #define OPT_MCU_RX63X 1400 ///< Renesas RX63N/631 #define OPT_MCU_RX65X 1401 ///< Renesas RX65N/RX651 #define OPT_MCU_RX72N 1402 ///< Renesas RX72N +#define OPT_MCU_RAXXX 1403 ///< Renesas RAxxx families + // Mind Motion #define OPT_MCU_MM32F327X 1500 ///< Mind Motion MM32F327 @@ -146,6 +150,11 @@ typedef int make_iso_compilers_happy; // PIC #define OPT_MCU_PIC32MZ 1900 ///< MicroChip PIC32MZ family +#define OPT_MCU_PIC32MM 1901 ///< MicroChip PIC32MM family +#define OPT_MCU_PIC32MX 1902 ///< MicroChip PIC32MX family +#define OPT_MCU_PIC32MK 1903 ///< MicroChip PIC32MK family +#define OPT_MCU_PIC24 1910 ///< MicroChip PIC24 family +#define OPT_MCU_DSPIC33 1911 ///< MicroChip DSPIC33 family // BridgeTek #define OPT_MCU_FT90X 2000 ///< BridgeTek FT90x @@ -154,6 +163,9 @@ typedef int make_iso_compilers_happy; // Allwinner #define OPT_MCU_F1C100S 2100 ///< Allwinner F1C100s family +// WCH +#define OPT_MCU_CH32V307 2200 ///< WCH CH32V307 + // Helper to check if configured MCU is one of listed // Apply _TU_CHECK_MCU with || as separator to list of input #define _TU_CHECK_MCU(_m) (CFG_TUSB_MCU == _m) @@ -250,6 +262,10 @@ typedef int make_iso_compilers_happy; // For backward compatible #define TUSB_OPT_HOST_ENABLED CFG_TUH_ENABLED +// highspeed support indicator +#define TUH_OPT_HIGH_SPEED (CFG_TUH_MAX_SPEED ? (CFG_TUH_MAX_SPEED & OPT_MODE_HIGH_SPEED) : TUP_RHPORT_HIGHSPEED) + + //--------------------------------------------------------------------+ // TODO move later //--------------------------------------------------------------------+ @@ -274,12 +290,15 @@ typedef int make_iso_compilers_happy; #define CFG_TUSB_DEBUG 0 #endif -// place data in accessible RAM for usb controller +// TODO MEM_SECTION can be different for host and device controller +// should use CFG_TUD_MEM_SECTION, CFG_TUH_MEM_SECTION #ifndef CFG_TUSB_MEM_SECTION #define CFG_TUSB_MEM_SECTION #endif // alignment requirement of buffer used for endpoint transferring +// TODO MEM_ALIGN can be different for host and device controller +// should use CFG_TUD_MEM_ALIGN, CFG_TUH_MEM_ALIGN #ifndef CFG_TUSB_MEM_ALIGN #define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4) #endif @@ -293,13 +312,30 @@ typedef int make_iso_compilers_happy; #define CFG_TUSB_OS_INC_PATH #endif -// mutex is only needed for RTOS TODO also required with multiple core MCUs -#define TUSB_OPT_MUTEX (CFG_TUSB_OS != OPT_OS_NONE) - //-------------------------------------------------------------------- // Device Options (Default) //-------------------------------------------------------------------- +// Attribute to place data in accessible RAM for device controller +// default to CFG_TUSB_MEM_SECTION for backward-compatible +#ifndef CFG_TUD_MEM_SECTION + #ifdef CFG_TUSB_MEM_SECTION + #define CFG_TUD_MEM_SECTION CFG_TUSB_MEM_SECTION + #else + #define CFG_TUD_MEM_SECTION + #endif +#endif + +// Attribute to align memory for device controller +// default to CFG_TUSB_MEM_ALIGN for backward-compatible +#ifndef CFG_TUD_MEM_ALIGN + #ifdef CFG_TUSB_MEM_ALIGN + #define CFG_TUD_MEM_ALIGN CFG_TUSB_MEM_ALIGN + #else + #define CFG_TUD_MEM_ALIGN TU_ATTR_ALIGNED(4) + #endif +#endif + #ifndef CFG_TUD_ENDPOINT0_SIZE #define CFG_TUD_ENDPOINT0_SIZE 64 #endif @@ -378,6 +414,21 @@ typedef int make_iso_compilers_happy; #endif #endif // CFG_TUH_ENABLED +// Attribute to place data in accessible RAM for host controller +// default to CFG_TUSB_MEM_SECTION for backward-compatible +#ifndef CFG_TUH_MEM_SECTION + #ifdef CFG_TUSB_MEM_SECTION + #define CFG_TUH_MEM_SECTION CFG_TUSB_MEM_SECTION + #else + #define CFG_TUH_MEM_SECTION + #endif +#endif + +// Attribute to align memory for host controller +#ifndef CFG_TUH_MEM_ALIGN + #define CFG_TUH_MEM_ALIGN TU_ATTR_ALIGNED(4) +#endif + //------------- CLASS -------------// #ifndef CFG_TUH_HUB @@ -388,6 +439,16 @@ typedef int make_iso_compilers_happy; #define CFG_TUH_CDC 0 #endif +#ifndef CFG_TUH_CDC_FTDI + // FTDI is not part of CDC class, only to re-use CDC driver API + #define CFG_TUH_CDC_FTDI 0 +#endif + +#ifndef CFG_TUH_CDC_CP210X + // CP210X is not part of CDC class, only to re-use CDC driver API + #define CFG_TUH_CDC_CP210X 0 +#endif + #ifndef CFG_TUH_HID #define CFG_TUH_HID 0 #endif @@ -425,6 +486,9 @@ typedef int make_iso_compilers_happy; #error Control Endpoint Max Packet Size cannot be larger than 64 #endif +// To avoid GCC compiler warnings when -pedantic option is used (strict ISO C) +typedef int make_iso_compilers_happy; + #endif /* _TUSB_OPTION_H_ */ /** @} */ From 547950d652b5025b7f5aa193f3f62caf30fa56b3 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 6 May 2023 17:29:35 +0200 Subject: [PATCH 222/433] Fix #11 (race condition in Linux) --- java-does-usb/jextract/README.md | 16 +-- java-does-usb/jextract/linux/gen_linux.sh | 2 +- .../codecrete/usb/linux/LinuxAsyncTask.java | 116 ++++++++++-------- .../codecrete/usb/linux/LinuxUSBDevice.java | 5 +- .../codecrete/usb/linux/gen/errno/errno.java | 12 +- .../codecrete/usb/macos/MacosUSBDevice.java | 8 +- .../codecrete/usb/sample/LogicAnalyzer.java | 5 +- 7 files changed, 86 insertions(+), 78 deletions(-) diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index f7562a0e..c79a41bc 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -68,7 +68,7 @@ SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so.1", MemorySes ## MacOS -Most of the required native functions on macOS are part of a framework. Frameworks internally have a more complex file organization of header and binary files than appears from the outside. Thus they require a special logic to locate framework header files. *clang* supports it with the `-F`. *jextract* allows to specify the options via `compiler_flags.txt` file. Since the file must be in the local directory and since it does not apply to Linux and Windows, separate directories must be used for the operating systems. +Most of the required native functions on macOS are part of a framework. Frameworks internally have a more complex file organization of header and binary files than appears from the outside. Thus, they require a special logic to locate framework header files. *clang* supports it with the `-F`. *jextract* allows to specify the options via `compiler_flags.txt` file. Since the file must be in the local directory and since it does not apply to Linux and Windows, separate directories must be used for the operating systems. The generated code has the same problem as the Linux code for *udev*. It must be manually changed to use `SymbolLookup.libraryLookup()` for the libraries `CoreFoundation.framework/CoreFoundation` and `IOKit.framework/IOKit` respectively. @@ -102,12 +102,12 @@ The worst example is [`IOUSBInterfaceStruct100`](https://github.com/manuelbl/Jav The table below shows statictics for version 0.2.0 of the library: -| Operating Systems | Manually Created | % | Generated | % | Total | % | -| - | -:| -:| -:| -:| -:| -:| -| Linux | 24,140 | 1.96% | 182,774 | 14.84% | 206,914 | 16.80% | -| macOS | 57,788 | 4.69% | 666,037 | 54.08% | 723,825 | 58.77% | -| Windows | 46,085 | 3.74% | 201,000 | 16.32% | 247,085 | 20.06% | -| Common | 53,774 | 4.37% | 53,774 | 0.00% | | 4.37% | -| Grand Total | 181,787 | 14.76% | 1,049,811 | 85.24% | 1,231,598 | 100.00% | +| Operating Systems | Manually Created | % | Generated | % | Total | % | +|-------------------|-----------------:|-------:|----------:|-------:|----------:|--------:| +| Linux | 24,140 | 1.96% | 182,774 | 14.84% | 206,914 | 16.80% | +| macOS | 57,788 | 4.69% | 666,037 | 54.08% | 723,825 | 58.77% | +| Windows | 46,085 | 3.74% | 201,000 | 16.32% | 247,085 | 20.06% | +| Common | 53,774 | 4.37% | 53,774 | 0.00% | | 4.37% | +| Grand Total | 181,787 | 14.76% | 1,049,811 | 85.24% | 1,231,598 | 100.00% | *Code Size (compiled), in bytes and percentage of total size* diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index cb11fb2b..e5df0d26 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -6,10 +6,10 @@ JEXTRACT=../../../../jextract/build/jextract/bin/jextract $JEXTRACT --source --output ../../src/main/java \ --header-class-name errno \ --target-package net.codecrete.usb.linux.gen.errno \ - --include-constant ETIMEDOUT \ --include-constant EPIPE \ --include-constant EBADF \ --include-constant EAGAIN \ + --include-constant EINVAL \ /usr/include/errno.h # string.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index d656eac4..470dfbf4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -15,10 +15,8 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SegmentScope; import java.util.ArrayList; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -58,15 +56,15 @@ static synchronized LinuxAsyncTask instance() { return singletonInstance; } - private final SegmentAllocator GLOBAL_ALLOCATOR = SegmentAllocator.nativeAllocator(SegmentScope.global()); + private final Arena urbArena = Arena.openShared(); /// available URBs private final List availableURBs = new ArrayList<>(); /// map of URB addresses to transfer (for outstanding transfers) - private final Map transfersByURB = new HashMap<>(); + private final Map transfersByURB = new LinkedHashMap<>(); /// array of file descriptors using asynchronous completion private int[] asyncFds; /// file descriptor to notify async IO background thread about an update - private int asyncIOUpdateEventFd; + private int asyncIOWakeUpEventFd; /** * Background task for handling asynchronous IO completions. @@ -103,7 +101,8 @@ private void asyncCompletionTask() { pollfd.revents$set(asyncPolls, i, (short) 0); } - pollfd.fd$set(asyncPolls, n, asyncIOUpdateEventFd); + // entry n is the wake-up event file descriptor + pollfd.fd$set(asyncPolls, n, asyncIOWakeUpEventFd); pollfd.events$set(asyncPolls, n, (short) poll.POLLIN()); pollfd.revents$set(asyncPolls, n, (short) 0); @@ -112,30 +111,34 @@ private void asyncCompletionTask() { if (res < 0) throwException("internal error (poll)"); - // check for events - for (int i = 0; i < n + 1; i++) { - var revent = pollfd.revents$get(asyncPolls, i); - if (revent == 0) - continue; + // acquire lock + synchronized (this) { - if ((revent & poll.POLLERR()) != 0) { - // most likely the device has been disconnected; - // remove from polled FD list to prevent further problems - int fd = pollfd.fd$get(asyncPolls, i); - removeFdFromAsyncIOCompletion(fd); + if ((pollfd.revents$get(asyncPolls, n) & poll.POLLIN()) != 0) { + // wakeup to refresh list of file descriptors + res = IO.eventfd_read(asyncIOWakeUpEventFd, eventfdValueHolder, errnoState); + if (res < 0) + throwLastError(errnoState, "internal error (eventfd_read)"); continue; } - if (i != n) { + // check for events + for (int i = 0; i < n + 1; i++) { + var revent = pollfd.revents$get(asyncPolls, i); + if (revent == 0) + continue; + + if ((revent & poll.POLLERR()) != 0) { + // most likely the device has been disconnected; + // remove from polled FD list to prevent further problems + int fd = pollfd.fd$get(asyncPolls, i); + removeFdFromAsyncIOCompletion(fd); + continue; + } + // reap URB int fd = pollfd.fd$get(asyncPolls, i); - reapURB(fd, urbPointerHolder, errnoState); - - } else { - // wakeup to refresh list of file descriptors - res = IO.eventfd_read(asyncIOUpdateEventFd, eventfdValueHolder, errnoState); - if (res < 0) - throwLastError(errnoState, "internal error (eventfd_read)"); + reapURBs(fd, urbPointerHolder, errnoState); } } } @@ -143,28 +146,29 @@ private void asyncCompletionTask() { } /** - * Reap URB and handle the completed transfer. + * Reap all pending URBs and handle the completed transfers. * * @param fd file descriptor * @param urbPointerHolder native memory to receive the URB pointer * @param errnoState native memory to receive the errno */ - private void reapURB(int fd, MemorySegment urbPointerHolder, MemorySegment errnoState) { - int res; - res = IO.ioctl(fd, REAPURBNDELAY, urbPointerHolder, errnoState); - if (res < 0) { - var err = Linux.getErrno(errnoState); - if (err == errno.EAGAIN()) - return; // retry - if (err == errno.EBADF()) - return; // ignore, device might have been closed - throwException(err, "internal error (reap URB)"); - } + private void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment errnoState) { + while (true) { + int res = IO.ioctl(fd, REAPURBNDELAY, urbPointerHolder, errnoState); + if (res < 0) { + var err = Linux.getErrno(errnoState); + if (err == errno.EAGAIN()) + return; // no more pending URBs + if (err == errno.EBADF()) + return; // ignore, device might have been closed + throwException(err, "internal error (reap URB)"); + } - // call completion handler - var urbAddr = urbPointerHolder.get(JAVA_LONG, 0); - var transfer = getTransferResult(urbAddr); - transfer.completion.completed(transfer); + // call completion handler + var urb = urbPointerHolder.get(ADDRESS, 0); + var transfer = getTransferResult(urb); + transfer.completion.completed(transfer); + } } /** @@ -172,14 +176,14 @@ private void reapURB(int fd, MemorySegment urbPointerHolder, MemorySegment errno */ private void notifyAsyncIOTask() { // start background process if needed - if (asyncIOUpdateEventFd == 0) { + if (asyncIOWakeUpEventFd == 0) { startAsyncIOTask(); return; } try (var arena = Arena.openConfined()) { var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); - if (IO.eventfd_write(asyncIOUpdateEventFd, 1, errnoState) < 0) + if (IO.eventfd_write(asyncIOWakeUpEventFd, 1, errnoState) < 0) throwLastError(errnoState, "internal error (eventfd_write)"); } } @@ -268,15 +272,15 @@ private void addURB(LinuxTransfer transfer) { if (size > 0) { urb = availableURBs.remove(size - 1); } else { - urb = usbdevfs_urb.allocate(GLOBAL_ALLOCATOR); + urb = usbdevfs_urb.allocate(urbArena); } transfer.urb = urb; - transfersByURB.put(urb.address(), transfer); + transfersByURB.put(urb, transfer); } - private synchronized LinuxTransfer getTransferResult(long urbAddr) { - var transfer = transfersByURB.remove(urbAddr); + private synchronized LinuxTransfer getTransferResult(MemorySegment urb) { + var transfer = transfersByURB.remove(urb); if (transfer == null) throwException("internal error (unknown URB)"); @@ -291,17 +295,21 @@ private synchronized LinuxTransfer getTransferResult(long urbAddr) { synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { int fd = device.fileDescriptor(); try (var arena = Arena.openConfined()) { + var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); - for (var urbAddress : transfersByURB.keySet()) { - var urb = usbdevfs_urb.ofAddress(MemorySegment.ofAddress(urbAddress), SegmentScope.global()); + // iterate all URBs and discard the ones for the specified endpoint + for (var urb : transfersByURB.keySet()) { if (fd != (int) usbdevfs_urb.usercontext$get(urb).address()) continue; if (endpointAddress != usbdevfs_urb.endpoint$get(urb)) continue; - if (IO.ioctl(fd, DISCARDURB, urb, errnoState) < 0) - throwLastError(errnoState, "failed to cancel transfer"); + if (IO.ioctl(fd, DISCARDURB, urb, errnoState) < 0) { + // ignore EINVAL; it occurs if the URB has completed at the same time + if (Linux.getErrno(errnoState) != errno.EINVAL()) + throwLastError(errnoState, "failed to abort transfer"); + } } } } @@ -309,9 +317,9 @@ synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { private void startAsyncIOTask() { try (var arena = Arena.openConfined()) { var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); - asyncIOUpdateEventFd = IO.eventfd(0, 0, errnoState); - if (asyncIOUpdateEventFd == -1) { - asyncIOUpdateEventFd = 0; + asyncIOWakeUpEventFd = IO.eventfd(0, 0, errnoState); + if (asyncIOWakeUpEventFd == -1) { + asyncIOWakeUpEventFd = 0; throwLastError(errnoState, "internal error (eventfd)"); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 602a089e..fe1c0857 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -111,7 +111,6 @@ public synchronized void claimInterface(int interfaceNumber) { throwException("Interface %d has already been claimed", interfaceNumber); try (var arena = Arena.openConfined()) { - var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); // claim interface (possibly disconnecting kernel driver) @@ -324,7 +323,7 @@ public synchronized void abortTransfers(USBDirection direction, int endpointNumb } @Override - public InputStream openInputStream(int endpointNumber, int bufferSize) { + public synchronized InputStream openInputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, null); @@ -332,7 +331,7 @@ public InputStream openInputStream(int endpointNumber, int bufferSize) { } @Override - public OutputStream openOutputStream(int endpointNumber, int bufferSize) { + public synchronized OutputStream openOutputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, null); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java index 84524ec7..c34a6458 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -31,19 +31,19 @@ public static int EAGAIN() { } /** * {@snippet : - * #define EPIPE 32 + * #define EINVAL 22 * } */ - public static int EPIPE() { - return (int)32L; + public static int EINVAL() { + return (int)22L; } /** * {@snippet : - * #define ETIMEDOUT 110 + * #define EPIPE 32 * } */ - public static int ETIMEDOUT() { - return (int)110L; + public static int EPIPE() { + return (int)32L; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 152e0596..70f52905 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -97,10 +97,10 @@ public synchronized void close() { if (!isOpen()) return; - for (InterfaceInfo interfaceInfo : claimedInterfaces) { - IoKitUSB.USBInterfaceClose(interfaceInfo.iokitInterface()); - IoKitUSB.Release(interfaceInfo.iokitInterface()); - setClaimed(interfaceInfo.interfaceNumber, false); + for (InterfaceInfo(MemorySegment iokitInterface, int interfaceNumber) : claimedInterfaces) { + IoKitUSB.USBInterfaceClose(iokitInterface); + IoKitUSB.Release(iokitInterface); + setClaimed(interfaceNumber, false); } claimedInterfaces = null; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java b/java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java index b280266c..5794e844 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java @@ -118,7 +118,7 @@ void sampleData(int sampleRate, int duration, String filename) { this.filename = filename; prepareSampling(sampleRate, duration); var acquirer = CompletableFuture.runAsync(this::saveSamples); - sleep(20); // give thread time to start + sleep(50); // give thread time to start startAcquisition(); var watchdog = CompletableFuture.runAsync(this::detectBufferOverrun); CompletableFuture.allOf(acquirer, watchdog).join(); @@ -232,11 +232,12 @@ void stopAcquisition() { } void detectBufferOverrun() { + sleep(10); // if the 'activityValue' hasn't changed within 20ms, the logic analyzer // has stopped sending data (likely due to a buffer overrun) long lastValue = 0; while (true) { - sleep(20); + sleep(5); if (stopped) break; From ae2002c7c50cae4b7a56d6715ecf41b56e8ee6ec Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 13 May 2023 15:40:32 +0200 Subject: [PATCH 223/433] Unplug test --- java-does-usb/jextract/macos/gen_macos.sh | 1 + .../codecrete/usb/macos/MacosUSBDevice.java | 27 +- .../codecrete/usb/macos/gen/iokit/IOKit.java | 8 + .../{sample => special}/EnumerateDevices.java | 2 +- .../{sample => special}/LogicAnalyzer.java | 2 +- .../{sample => special}/MonitorDevices.java | 2 +- .../{sample => special}/USBSerialTest.java | 2 +- .../net/codecrete/usb/special/Unplug.java | 327 ++++++++++++++++++ 8 files changed, 362 insertions(+), 9 deletions(-) rename java-does-usb/src/test/java/net/codecrete/usb/{sample => special}/EnumerateDevices.java (92%) rename java-does-usb/src/test/java/net/codecrete/usb/{sample => special}/LogicAnalyzer.java (99%) rename java-does-usb/src/test/java/net/codecrete/usb/{sample => special}/MonitorDevices.java (96%) rename java-does-usb/src/test/java/net/codecrete/usb/{sample => special}/USBSerialTest.java (98%) create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index 78c29098..13d8dd4e 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -39,6 +39,7 @@ $JEXTRACT --source --output ../../src/main/java \ --include-constant kIOUSBDeviceClassName \ --include-constant kIOFirstMatchNotification \ --include-constant kIOTerminatedNotification \ + --include-constant kIOReturnExclusiveAccess \ --include-var kCFRunLoopDefaultMode \ --include-struct IOCFPlugInInterfaceStruct \ --include-typedef IOCFPlugInInterface \ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 70f52905..b6d1fa8e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -55,8 +55,11 @@ public class MacosUSBDevice extends USBDeviceImpl { // Details about endpoints of current alternate settings (for claimed interfaces) private Map endpoints; + private final long discoveryTime; + MacosUSBDevice(MemorySegment device, Object id, int vendorId, int productId) { super(id, vendorId, productId); + discoveryTime = System.currentTimeMillis(); asyncTask = MacosAsyncTask.instance(); loadDescription(device); @@ -75,13 +78,27 @@ public synchronized void open() { if (isOpen()) throwException("the device is already open"); - // open device - int ret = IoKitUSB.USBDeviceOpenSeize(device); + // open device (several retries if device has just been connected/discovered) + long duration = System.currentTimeMillis() - discoveryTime; + int numTries = duration < 1000 ? 4 : 1; + int ret = 0; + while (numTries > 0) { + numTries -= 1; + ret = IoKitUSB.USBDeviceOpenSeize(device); + if (ret != IOKit.kIOReturnExclusiveAccess()) + break; + + // sleep and retry + try { + Thread.sleep(90); + } catch (InterruptedException e) { + // ignore + } + } if (ret != 0) throwException(ret, "unable to open USB device"); claimedInterfaces = new ArrayList<>(); - addDeviceEventSource(); // set configuration @@ -541,7 +558,7 @@ public void clearHalt(USBDirection direction, int endpointNumber) { } @Override - public InputStream openInputStream(int endpointNumber, int bufferSize) { + public synchronized InputStream openInputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, null); @@ -549,7 +566,7 @@ public InputStream openInputStream(int endpointNumber, int bufferSize) { } @Override - public OutputStream openOutputStream(int endpointNumber, int bufferSize) { + public synchronized OutputStream openOutputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, null); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java index bec09c37..f80e21ad 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java @@ -224,6 +224,14 @@ public static int IOCreatePlugInInterfaceForService(int service, MemorySegment p throw new AssertionError("should not reach here", ex$); } } + /** + * {@snippet : + * #define kIOReturnExclusiveAccess -536870203 + * } + */ + public static int kIOReturnExclusiveAccess() { + return (int)-536870203L; + } /** * {@snippet : * #define kIOReturnAborted -536870165 diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/EnumerateDevices.java b/java-does-usb/src/test/java/net/codecrete/usb/special/EnumerateDevices.java similarity index 92% rename from java-does-usb/src/test/java/net/codecrete/usb/sample/EnumerateDevices.java rename to java-does-usb/src/test/java/net/codecrete/usb/special/EnumerateDevices.java index c18a3b45..2951df4b 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/sample/EnumerateDevices.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/EnumerateDevices.java @@ -5,7 +5,7 @@ // https://opensource.org/licenses/MIT // -package net.codecrete.usb.sample; +package net.codecrete.usb.special; import net.codecrete.usb.USB; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java b/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java similarity index 99% rename from java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java rename to java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java index 5794e844..11b04ccf 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/sample/LogicAnalyzer.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java @@ -8,7 +8,7 @@ // and licensed under GNU GPL (version 2, or later). // -package net.codecrete.usb.sample; +package net.codecrete.usb.special; import net.codecrete.usb.*; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java b/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java similarity index 96% rename from java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java rename to java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java index 9f0c0df3..2aacff50 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/sample/MonitorDevices.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java @@ -5,7 +5,7 @@ // https://opensource.org/licenses/MIT // -package net.codecrete.usb.sample; +package net.codecrete.usb.special; import net.codecrete.usb.USB; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/sample/USBSerialTest.java b/java-does-usb/src/test/java/net/codecrete/usb/special/USBSerialTest.java similarity index 98% rename from java-does-usb/src/test/java/net/codecrete/usb/sample/USBSerialTest.java rename to java-does-usb/src/test/java/net/codecrete/usb/special/USBSerialTest.java index edab3b2a..053aa4f3 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/sample/USBSerialTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/USBSerialTest.java @@ -5,7 +5,7 @@ // https://opensource.org/licenses/MIT // -package net.codecrete.usb.sample; +package net.codecrete.usb.special; import net.codecrete.usb.*; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java new file mode 100644 index 00000000..9f3f5caa --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java @@ -0,0 +1,327 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.special; + +import net.codecrete.usb.USB; +import net.codecrete.usb.USBDevice; +import net.codecrete.usb.USBException; + +import java.io.IOException; +import java.util.HashMap; + +import static java.time.Duration.*; + +/** + * Test for robustness when USB devices is unplugged during operation. + * + *

+ * Requires use of test device. + *

+ */ +public class Unplug { + /** + * Loopback test device vendor ID + */ + static final int VID_LOOPBACK = 0xcafe; + /** + * Loopback test device product ID + */ + static final int PID_LOOPBACK = 0xceaf; + /** + * Loopback test device loopback interface number + */ + static final int LOOPBACK_INTF = 0; + + private static final int LOOPBACK_EP_OUT = 1; + private static final int LOOPBACK_EP_IN = 2; + private static final int ECHO_EP_OUT = 3; + private static final int ECHO_EP_IN = 3; + + private static final HashMap activeDevices = new HashMap<>(); + + public static void main(String[] args) throws IOException { + System.out.println("Plug and unplug test device multiple times."); + System.out.println("Hit ENTER to exit."); + + USB.setOnDeviceConnected(Unplug::onPluggedDevice); + USB.setOnDeviceDisconnected(Unplug::onUnpluggedDevice); + USB.getAllDevices().forEach(Unplug::onPluggedDevice); + + //noinspection ResultOfMethodCallIgnored + System.in.read(); + } + + private static void onPluggedDevice(USBDevice device) { + if (!isTestDevice(device)) + return; + + var worker = new DeviceWorker(device); + activeDevices.put(device, worker); + worker.start(); + } + + private static void onUnpluggedDevice(USBDevice device) { + if (!isTestDevice(device)) + return; + + var worker = activeDevices.remove(device); + worker.setDisconnectTime(System.currentTimeMillis()); + worker.join(); + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + private static boolean isTestDevice(USBDevice device) { + return device.vendorId() == VID_LOOPBACK && device.productId() == PID_LOOPBACK; + } + + static class DeviceWorker { + + private final USBDevice device; + + private final int seed; + + private long disconnectTime; + + private final HashMap workTracking = new HashMap<>(); + + DeviceWorker(USBDevice device) { + this.device = device; + this.seed = (int) System.currentTimeMillis(); + } + + void start() { + System.out.println("Device connected"); + + device.open(); + device.claimInterface(LOOPBACK_INTF); + + // start loopback sender and receiver + startThread((seed & 1) != 0 ? this::sendLoopbackDataStream : this::sendLoopbackData); + startThread((seed & 2) != 0 ? this::receiveLoopbackDataStream : this::receiveLoopbackData); + + // start echo sender and receiver + startThread(this::sendEcho); + startThread(this::receiveEcho); + } + + private void startThread(Runnable action) { + var thread = new Thread(() -> runAction(action)); + var work = new Work(); + workTracking.put(thread, work); + thread.start(); + } + + void join() { + // wait for threads to finish + for (var thread : workTracking.keySet()) { + try { + boolean terminated = thread.join(ofSeconds(5)); + if (!terminated) + System.err.printf("Thread \"%s\" failed to join within 5s%n", thread.getName()); + + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + device.close(); + + // check achieved work + for (var e : workTracking.entrySet()) { + var work = e.getValue(); + var expectedWork = work.expectedWorkPerSec * 0.001 * (work.finishTime - work.startTime); + if (work.actualWork < expectedWork) + System.err.printf("Thread \"%s\" achieved insufficient work executed. Expected: %.0f, achieved: %d%n", + e.getKey().getName(), expectedWork, work.actualWork); + } + + // check that the threads haven't terminated early + for (var e : workTracking.entrySet()) { + long duration = Math.abs(e.getValue().finishTime - disconnectTime); + if (duration > 500) + System.err.printf("Thread \"%s\" has likely crashed early%n", e.getKey().getName()); + } + + System.out.println("Device disconnected"); + } + + void setDisconnectTime(long time) { + disconnectTime = time; + } + + private synchronized void logFinish() { + var work = workTracking.get(Thread.currentThread()); + work.finishTime = System.currentTimeMillis(); + } + + private void logStart(String operation, long expectedWorkPerSec) { + Thread.currentThread().setName(operation); + var work = workTracking.get(Thread.currentThread()); + work.startTime = System.currentTimeMillis(); + work.expectedWorkPerSec = expectedWorkPerSec; + } + + private void logWork(long amount) { + var work = workTracking.get(Thread.currentThread()); + work.actualWork += amount; + } + + private void runAction(Runnable action) { + try { + action.run(); + } catch (USBException e) { + logFinish(); + } + } + + private void sendLoopbackData() { + logStart("sending loopback data", 300_000); + var prng = new PRNG(); + var data = new byte[5000]; + //noinspection InfiniteLoopStatement + while (true) { + prng.fill(data); + device.transferOut(LOOPBACK_EP_OUT, data, 1000); + logWork(data.length); + } + } + + private void receiveLoopbackData() { + logStart("receiving loopback data", 300_000); + var prng = new PRNG(); + //noinspection InfiniteLoopStatement + while (true) { + byte[] data = device.transferIn(LOOPBACK_EP_IN); + int index = prng.verify(data); + if (index >= 0) + throw new RuntimeException("invalid data received"); + logWork(data.length); + } + } + + private void sendLoopbackDataStream() { + logStart("sending loopback data with output stream", 300_000); + var prng = new PRNG(); + var data = new byte[5000]; + try (var os = device.openOutputStream(LOOPBACK_EP_OUT)) { + //noinspection InfiniteLoopStatement + while (true) { + prng.fill(data); + os.write(data); + logWork(data.length); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void receiveLoopbackDataStream() { + logStart("receiving loopback data with input stream", 300_000); + var prng = new PRNG(); + try (var is = device.openInputStream(LOOPBACK_EP_IN)) { + //noinspection InfiniteLoopStatement + while (true) { + var data = new byte[2000]; + int n = is.read(data); + int index = prng.verify(data, n); + if (index >= 0) + throw new RuntimeException("invalid data received"); + logWork(n); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void sendEcho() { + logStart("sending echo", 7); + var data = new byte[] { 0x03, 0x45, 0x73, (byte)0xb3, (byte)0x9f, 0x3f, 0x00, 0x6a }; + //noinspection InfiniteLoopStatement + while (true) { + device.transferOut(ECHO_EP_OUT, data); + logWork(1); + sleep(100); + } + } + + private void receiveEcho() { + logStart("receiving echo", 14); + //noinspection InfiniteLoopStatement + while (true) { + device.transferIn(ECHO_EP_IN); + logWork(1); + } + } + + @SuppressWarnings("SameParameterValue") + private static void sleep(long millis) { + try { + Thread.sleep(millis); + + } catch (InterruptedException e) { + // ignore + } + } + } + + static class Work { + long startTime; + long expectedWorkPerSec; + long actualWork; + long finishTime; + } + + /** + * Pseudo random number generator + */ + static class PRNG { + private int state; + private int nBytes; + private int bits; + + int next() { + int x = state; + x ^= x << 13; + x ^= x >>> 17; + x ^= x << 5; + state = x; + return x; + } + + void fill(byte[] data) { + int len = data.length; + for (int i = 0; i < len; i++) { + if (nBytes == 0) { + bits = next(); + nBytes = 4; + } + data[i] = (byte) bits; + bits >>>= 8; + nBytes--; + } + } + + int verify(byte[] data) { + return verify(data, data.length); + } + + int verify(byte[] data, int len) { + for (int i = 0; i < len; i++) { + if (nBytes == 0) { + bits = next(); + nBytes = 4; + } + if (data[i] != (byte) bits) + return i; + bits >>>= 8; + nBytes--; + } + return -1; + } + } +} From 76fdf87c5a0aba7f01e47dc2dcb19aea15468cdc Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 13 May 2023 14:15:40 +0200 Subject: [PATCH 224/433] Improve robustness --- .../main/java/net/codecrete/usb/windows/WindowsUSBDevice.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index a496fea9..8ba3b93f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -400,7 +400,7 @@ public synchronized void abortTransfers(USBDirection direction, int endpointNumb } @Override - public InputStream openInputStream(int endpointNumber, int bufferSize) { + public synchronized InputStream openInputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, null); @@ -408,7 +408,7 @@ public InputStream openInputStream(int endpointNumber, int bufferSize) { } @Override - public OutputStream openOutputStream(int endpointNumber, int bufferSize) { + public synchronized OutputStream openOutputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, null); From 9a6bc21f86b1574b80630ca1f8c6f7cd83e7c2f8 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 13 May 2023 17:17:30 +0200 Subject: [PATCH 225/433] Improve robustness when unplugging device --- java-does-usb/jextract/linux/gen_linux.sh | 2 +- .../java/net/codecrete/usb/linux/LinuxAsyncTask.java | 2 +- .../net/codecrete/usb/linux/gen/errno/errno.java | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index e5df0d26..31b8654f 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -7,9 +7,9 @@ $JEXTRACT --source --output ../../src/main/java \ --header-class-name errno \ --target-package net.codecrete.usb.linux.gen.errno \ --include-constant EPIPE \ - --include-constant EBADF \ --include-constant EAGAIN \ --include-constant EINVAL \ + --include-constant ENODEV \ /usr/include/errno.h # string.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index 470dfbf4..b157039f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -159,7 +159,7 @@ private void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment errn var err = Linux.getErrno(errnoState); if (err == errno.EAGAIN()) return; // no more pending URBs - if (err == errno.EBADF()) + if (err == errno.ENODEV()) return; // ignore, device might have been closed throwException(err, "internal error (reap URB)"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java index c34a6458..7f9506df 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -15,19 +15,19 @@ public class errno { public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; /** * {@snippet : - * #define EBADF 9 + * #define EAGAIN 11 * } */ - public static int EBADF() { - return (int)9L; + public static int EAGAIN() { + return (int)11L; } /** * {@snippet : - * #define EAGAIN 11 + * #define ENODEV 19 * } */ - public static int EAGAIN() { - return (int)11L; + public static int ENODEV() { + return (int)19L; } /** * {@snippet : From 08a47ef6854937169cd7e3867ef104114248ccc8 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 14 May 2023 16:55:34 +0200 Subject: [PATCH 226/433] Fine-tune tests --- .../main/java/net/codecrete/usb/USBDevice.java | 10 ++++++++++ .../usb/common/EndpointInputStream.java | 12 ++++++++---- .../usb/common/EndpointOutputStream.java | 12 ++++++++---- .../java/net/codecrete/usb/BulkTransferTest.java | 1 + .../test/java/net/codecrete/usb/TimeoutTest.java | 8 +++++--- .../loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c | 13 ++++++++++++- test-devices/loopback-stm32/src/main.c | 16 ++++++++++++---- test-devices/loopback-stm32/src/vendor_custom.c | 14 +++++--------- 8 files changed, 61 insertions(+), 25 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index a60d07ff..aa77f024 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -216,6 +216,11 @@ public interface USBDevice { *

* This method can send data to bulk and interrupt endpoints. *

+ *

+ * If the sent data length is a multiple of the packet size, it is often + * required to send an additional zero-length packet (ZLP) for the device + * to actually process the data. This method will not do it automatically. + *

* * @param endpointNumber endpoint number (in the range between 1 and 127) * @param data data to send @@ -231,6 +236,11 @@ public interface USBDevice { *

* This method can send data to bulk and interrupt endpoints. *

+ *

+ * If the sent data length is a multiple of the packet size, it is often + * required to send an additional zero-length packet (ZLP) for the device + * to actually process the data. This method will not do it automatically. + *

* * @param endpointNumber the endpoint number (in the range between 1 and 127) * @param timeout the timeout period, in milliseconds (0 for no timeout) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index 6d43fd5d..b9b68f13 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -64,10 +64,14 @@ protected EndpointInputStream(USBDeviceImpl device, int endpointNumber, int buff arena = Arena.openShared(); int packetSize = device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); - int n = (int) Math.round(Math.sqrt((double) bufferSize / packetSize)); - n = Math.min(Math.max(n, 4), 32); // 32 limits packet size to 16KB (for USB HS) - transferSize = n * packetSize; - int maxOutstandingTransfers = Math.max((bufferSize + transferSize / 2) / transferSize, 2); + + // use between 4 and 32 packets per transfer (256B to 2KB for FS, 2KB to 16KB for HS) + int numPacketsPerTransfer = (int) Math.round(Math.sqrt((double) bufferSize / packetSize)); + numPacketsPerTransfer = Math.min(Math.max(numPacketsPerTransfer, 4), 32); + transferSize = numPacketsPerTransfer * packetSize; + + // use at least 2 outstanding transfers (3 in total) + int maxOutstandingTransfers = Math.max((bufferSize + transferSize / 2) / transferSize, 3); configureEndpoint(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java index f6076879..9b2d3c59 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -67,10 +67,14 @@ protected EndpointOutputStream(USBDeviceImpl device, int endpointNumber, int buf arena = Arena.openShared(); packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize(); - int n = (int) Math.round(Math.sqrt((double) bufferSize / packetSize)); - n = Math.min(Math.max(n, 4), 32); // 32 limits packet size to 16KB (for USB HS) - transferSize = n * packetSize; - int maxOutstandingTransfers = Math.max((bufferSize + transferSize / 2) / transferSize, 2); + + // use between 4 and 32 packets per transfer (256B to 2KB for FS, 2KB to 16KB for HS) + int numPacketsPerTransfer = (int) Math.round(Math.sqrt((double) bufferSize / packetSize)); + numPacketsPerTransfer = Math.min(Math.max(numPacketsPerTransfer, 4), 32); + transferSize = numPacketsPerTransfer * packetSize; + + // use at least 2 outstanding transfers (3 in total) + int maxOutstandingTransfers = Math.max((bufferSize + transferSize / 2) / transferSize, 3); configureEndpoint(); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java index 7e53460b..cf68679c 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java @@ -42,6 +42,7 @@ void transferWithZLP_succeeds() { var inEndpoint = testDevice.getEndpoint(USBDirection.IN, LOOPBACK_EP_IN); byte[] sampleData = generateRandomBytes(inEndpoint.packetSize(), 97333894); testDevice.transferOut(LOOPBACK_EP_OUT, sampleData); + testDevice.transferOut(LOOPBACK_EP_OUT, new byte[0]); byte[] data = testDevice.transferIn(LOOPBACK_EP_IN); assertArrayEquals(sampleData, data); data = testDevice.transferIn(LOOPBACK_EP_IN); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java index 79645270..436d0f47 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java @@ -40,14 +40,16 @@ void bulkTransfer_doesNotTimeOut() { @Test @Timeout(value = 1, unit = TimeUnit.SECONDS) void bulkTransferOut_timesOut() { - // The test device has an internal buffer of about 500 bytes. - // So the first transfer should not time out. + // The test device has an internal buffer of about 2KB for full-speed + // and 16KB for high-speed. The first transfer should not time-out. + final int bufferSize = 32 * testDevice + .getEndpoint(USBDirection.OUT, LOOPBACK_EP_OUT).packetSize(); byte[] data = generateRandomBytes(100, 9383073929L); testDevice.transferOut(LOOPBACK_EP_OUT, data, 200); assertThrows(USBTimeoutException.class, () -> { - for (int i = 0; i < 50; i++) { + for (int i = 0; i < bufferSize / data.length; i++) { testDevice.transferOut(LOOPBACK_EP_OUT, data, 200); } }); diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c index 22c82201..aa6757ee 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c +++ b/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c @@ -222,6 +222,8 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c { (void) rhport; + TU_ASSERT(epnum < DWC2_EP_MAX, ); + dwc2_regs_t * dwc2 = DWC2_REG(rhport); // EP0 is limited to one packet each xfer @@ -743,6 +745,9 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + TU_ASSERT(epnum < ep_count); + xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); xfer->buffer = buffer; xfer->ff = NULL; @@ -783,6 +788,9 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + TU_ASSERT(epnum < ep_count); + xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); xfer->buffer = NULL; xfer->ff = ff; @@ -1024,6 +1032,9 @@ static void handle_rxflvl_irq(uint8_t rhport) case GRXSTS_PKTSTS_OUTRX: { + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + TU_ASSERT(epnum < ep_count, ); + // Out packet received xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); @@ -1288,7 +1299,7 @@ void dcd_int_handler(uint8_t rhport) if(int_status & GINTSTS_SOF) { - dwc2->gotgint = GINTSTS_SOF; + dwc2->gintsts = GINTSTS_SOF; if (_sof_en) { diff --git a/test-devices/loopback-stm32/src/main.c b/test-devices/loopback-stm32/src/main.c index 4107ef29..b58c45f1 100644 --- a/test-devices/loopback-stm32/src/main.c +++ b/test-devices/loopback-stm32/src/main.c @@ -18,11 +18,19 @@ #include "usb_descriptors.h" #include "vendor_custom.h" +#if BOARD_TUD_MAX_SPEED == OPT_MODE_HIGH_SPEED + #define BUFFER_SIZE 16384 +#else + #define BUFFER_SIZE 2048 +#endif + // FIFO buffer for loopback data tu_fifo_t loopback_fifo; -uint8_t loopback_buffer[2048] __attribute__ ((aligned(4))); +uint8_t loopback_buffer[BUFFER_SIZE] __attribute__ ((aligned(4))); uint16_t bulk_packet_size = 64; +const int num_rx_packets = 2; +const int num_tx_packets = 4; // buffer for echoed packet uint8_t echo_buffer[16]; @@ -81,7 +89,7 @@ void loopback_check_tx(void) { uint16_t n = tu_fifo_count(&loopback_fifo); if (n > 0 && !cust_vendor_is_transmitting(EP_LOOPBACK_TX)) { - uint16_t max_size = 2 * bulk_packet_size; + uint16_t max_size = num_tx_packets * bulk_packet_size; if (n > max_size) n = max_size; @@ -93,8 +101,8 @@ void loopback_check_tx(void) { void loopback_check_rx(void) { uint16_t n = tu_fifo_remaining(&loopback_fifo); - if (n >= bulk_packet_size && !cust_vendor_is_receiving(EP_LOOPBACK_RX)) - cust_vendor_prepare_recv_fifo(EP_LOOPBACK_RX, &loopback_fifo, bulk_packet_size); + if (n >= num_rx_packets * bulk_packet_size && !cust_vendor_is_receiving(EP_LOOPBACK_RX)) + cust_vendor_prepare_recv_fifo(EP_LOOPBACK_RX, &loopback_fifo, num_rx_packets * bulk_packet_size); } diff --git a/test-devices/loopback-stm32/src/vendor_custom.c b/test-devices/loopback-stm32/src/vendor_custom.c index 0a29ce18..a408fc5a 100644 --- a/test-devices/loopback-stm32/src/vendor_custom.c +++ b/test-devices/loopback-stm32/src/vendor_custom.c @@ -58,7 +58,7 @@ void cv_reset(uint8_t rhport) { // nothing to do } -// Open interface is the descriptor matches this class +// Open interface if the descriptor matches this class uint16_t cv_open(uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t max_len) { cv_num_eps_open = 0; @@ -185,8 +185,7 @@ void cust_vendor_prepare_recv(uint8_t ep_addr, void* buf, uint32_t buf_len) { uint8_t const rhport = BOARD_TUD_RHPORT; - if (usbd_edpt_busy(rhport, ep_addr)) - return; + TU_ASSERT(!usbd_edpt_busy(rhport, ep_addr), ); usbd_edpt_xfer(rhport, ep_addr, buf, buf_len); } @@ -194,8 +193,7 @@ void cust_vendor_prepare_recv(uint8_t ep_addr, void* buf, uint32_t buf_len) { void cust_vendor_prepare_recv_fifo(uint8_t ep_addr, tu_fifo_t * fifo, uint32_t buf_len) { uint8_t const rhport = BOARD_TUD_RHPORT; - if (usbd_edpt_busy(rhport, ep_addr)) - return; + TU_ASSERT(!usbd_edpt_busy(rhport, ep_addr), ); usbd_edpt_xfer_fifo(rhport, ep_addr, fifo, buf_len); } @@ -205,8 +203,7 @@ void cust_vendor_start_transmit(uint8_t ep_addr, void const * data, uint32_t dat uint8_t const rhport = BOARD_TUD_RHPORT; - if (usbd_edpt_busy(rhport, ep_addr)) - return; + TU_ASSERT(!usbd_edpt_busy(rhport, ep_addr), ); usbd_edpt_xfer(rhport, ep_addr, (void*) data, data_len); } @@ -215,8 +212,7 @@ void cust_vendor_start_transmit_fifo(uint8_t ep_addr, tu_fifo_t * fifo, uint32_t uint8_t const rhport = BOARD_TUD_RHPORT; - if (usbd_edpt_busy(rhport, ep_addr)) - return; + TU_ASSERT(!usbd_edpt_busy(rhport, ep_addr), ); usbd_edpt_xfer_fifo(rhport, ep_addr, (void*) fifo, data_len); } From d5525035ffb08a1c88d2455d9be3e2f4e9c91f6a Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 18 May 2023 14:34:18 +0200 Subject: [PATCH 227/433] More consistent instance variable names --- .../src/main/java/net/codecrete/usb/USB.java | 45 +++---- .../net/codecrete/usb/USBDeviceFilter.java | 73 +++++------ .../net/codecrete/usb/USBDevicePredicate.java | 38 ++++++ .../java/net/codecrete/usb/USBException.java | 6 +- .../usb/common/CompositeFunction.java | 30 ++--- .../codecrete/usb/common/Configuration.java | 38 +++--- .../usb/common/EndpointOutputStream.java | 1 - .../usb/common/USBAlternateInterfaceImpl.java | 37 +++--- .../codecrete/usb/common/USBDeviceImpl.java | 122 ++++++++++-------- .../codecrete/usb/common/USBEndpointImpl.java | 24 ++-- .../usb/common/USBInterfaceImpl.java | 30 ++--- .../codecrete/usb/linux/LinuxUSBDevice.java | 4 +- .../usb/windows/WindowsUSBDevice.java | 25 ++-- .../codecrete/usb/DeviceEnumerationTest.java | 7 + .../loopback-stm32/.vscode/settings.json | 4 +- 15 files changed, 268 insertions(+), 216 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/USBDevicePredicate.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USB.java b/java-does-usb/src/main/java/net/codecrete/usb/USB.java index ab37236e..27ee8cef 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USB.java @@ -14,7 +14,8 @@ import java.util.List; import java.util.function.Consumer; -import java.util.stream.Collectors; + +import static java.util.stream.Collectors.toList; /** * Provides access to USB devices. @@ -38,14 +39,14 @@ private static USBDeviceRegistry createInstance() { return impl; } - private static USBDeviceRegistry _instance = null; + private static USBDeviceRegistry singletonInstance = null; private static synchronized USBDeviceRegistry instance() { - if (_instance == null) { - _instance = createInstance(); - _instance.start(); + if (singletonInstance == null) { + singletonInstance = createInstance(); + singletonInstance.start(); } - return _instance; + return singletonInstance; } // Private, so no instance can be created @@ -67,43 +68,43 @@ public static List getAllDevices() { } /** - * Gets a list of connected USB devices matching the specified filter. + * Gets a list of connected USB devices matching the specified predicate. * - * @param filter device filter + * @param predicate device predicate/filter * @return list of USB devices */ - public static List getDevices(USBDeviceFilter filter) { - return instance().getAllDevices().stream().filter(filter::matches).collect(Collectors.toList()); + public static List getDevices(USBDevicePredicate predicate) { + return instance().getAllDevices().stream().filter(predicate::matches).collect(toList()); } /** - * Gets a list of connected USB devices matching any of the specified filters. + * Gets a list of connected USB devices matching any of the specified predicates/filters. * - * @param filters list of device filters + * @param predicates list of device predicates/filters * @return list of USB devices */ - public static List getDevices(List filters) { - return instance().getAllDevices().stream().filter(dev -> USBDeviceFilter.matchesAny(dev, filters)).collect(Collectors.toList()); + public static List getDevices(List predicates) { + return instance().getAllDevices().stream().filter(dev -> USBDevicePredicate.matchesAny(dev, predicates)).collect(toList()); } /** - * Gets the first connected USB device matching the specified filter. + * Gets the first connected USB device matching the specified predicate. * - * @param filter device filter + * @param predicate device predicate/filter * @return USB device, or {@code null} if no device matches */ - public static USBDevice getDevice(USBDeviceFilter filter) { - return instance().getAllDevices().stream().filter(filter::matches).findFirst().orElse(null); + public static USBDevice getDevice(USBDevicePredicate predicate) { + return instance().getAllDevices().stream().filter(predicate::matches).findFirst().orElse(null); } /** - * Gets the first connected USB device matching any of the specified filters. + * Gets the first connected USB device matching any of the specified predicates. * - * @param filters list of device filters + * @param predicates list of device predicates/filters * @return USB device, or {@code null} if no device matches */ - public static USBDevice getDevice(List filters) { - return instance().getAllDevices().stream().filter(dev -> USBDeviceFilter.matchesAny(dev, filters)).findFirst().orElse(null); + public static USBDevice getDevice(List predicates) { + return instance().getAllDevices().stream().filter(dev -> USBDevicePredicate.matchesAny(dev, predicates)).findFirst().orElse(null); } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java index b7f784d0..cf7b1852 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java @@ -20,13 +20,13 @@ * product ID and serial number is globally unique. *

*/ -public class USBDeviceFilter { - private Integer vendorId_; - private Integer productId_; - private Integer classCode_; - private Integer subclassCode_; - private Integer protocolCode_; - private String serialNumber_; +public class USBDeviceFilter implements USBDevicePredicate { + private Integer vid; + private Integer pid; + private Integer deviceClass; + private Integer deviceSubclass; + private Integer deviceProtocol; + private String serialString; /** * Creates a new instance. @@ -41,8 +41,8 @@ public USBDeviceFilter() { * @param productId product ID */ public USBDeviceFilter(int vendorId, int productId) { - vendorId_ = vendorId; - productId_ = productId; + vid = vendorId; + pid = productId; } /** @@ -53,9 +53,9 @@ public USBDeviceFilter(int vendorId, int productId) { * @param serialNumber serial number */ public USBDeviceFilter(int vendorId, int productId, String serialNumber) { - vendorId_ = vendorId; - productId_ = productId; - serialNumber_ = serialNumber; + vid = vendorId; + pid = productId; + serialString = serialNumber; } /** @@ -64,7 +64,7 @@ public USBDeviceFilter(int vendorId, int productId, String serialNumber) { * @return vendor ID, or {@code null} if the vendor ID is not relevant for matching */ public Integer vendorId() { - return vendorId_; + return vid; } /** @@ -73,7 +73,7 @@ public Integer vendorId() { * @param vendorId vendor ID, or {@code null} if the vendor ID is not relevant for matching */ public void setVendorId(Integer vendorId) { - vendorId_ = vendorId; + vid = vendorId; } /** @@ -82,7 +82,7 @@ public void setVendorId(Integer vendorId) { * @return product ID, or {@code null} if the product ID is not relevant for matching */ public Integer productId() { - return productId_; + return pid; } /** @@ -91,7 +91,7 @@ public Integer productId() { * @param productId product ID, or {@code null} if the product ID is not relevant for matching */ public void setProductId(Integer productId) { - productId_ = productId; + pid = productId; } /** @@ -100,7 +100,7 @@ public void setProductId(Integer productId) { * @return class code, or {@code null} if the class code is not relevant for matching */ public Integer classCode() { - return classCode_; + return deviceClass; } /** @@ -109,7 +109,7 @@ public Integer classCode() { * @param classCode class code, or {@code null} if the class code is not relevant for matching */ public void setClassCode(Integer classCode) { - classCode_ = classCode; + deviceClass = classCode; } /** @@ -118,7 +118,7 @@ public void setClassCode(Integer classCode) { * @return subclass code, or {@code null} if the subclass code is not relevant for matching */ public Integer subclassCode() { - return subclassCode_; + return deviceSubclass; } /** @@ -127,7 +127,7 @@ public Integer subclassCode() { * @param subclassCode subclass code, or {@code null} if the subclass code is not relevant for matching */ public void setSubclassCode(Integer subclassCode) { - subclassCode_ = subclassCode; + deviceSubclass = subclassCode; } /** @@ -136,7 +136,7 @@ public void setSubclassCode(Integer subclassCode) { * @return protocol code, or {@code null} if the protocol code is not relevant for matching */ public Integer protocolCode() { - return protocolCode_; + return deviceProtocol; } /** @@ -144,8 +144,8 @@ public Integer protocolCode() { * * @param protocolCode protocol code, or {@code null} if the protocol code is not relevant for matching */ - public void setProtocolCode_(Integer protocolCode) { - protocolCode_ = protocolCode; + public void setProtocolCode(Integer protocolCode) { + deviceProtocol = protocolCode; } /** @@ -154,7 +154,7 @@ public void setProtocolCode_(Integer protocolCode) { * @return serial number, or {@code null} if the serial number is not relevant for matching */ public String serialNumber() { - return serialNumber_; + return serialString; } /** @@ -163,7 +163,7 @@ public String serialNumber() { * @param serialNumber serial number, or {@code null} if the serial number is not relevant for matching */ public void setSerialNumber(String serialNumber) { - serialNumber_ = serialNumber; + serialString = serialNumber; } /** @@ -173,27 +173,16 @@ public void setSerialNumber(String serialNumber) { * @return {@code true} if it matches, {@code false} otherwise */ public boolean matches(USBDevice device) { - if (vendorId_ != null && device.vendorId() != vendorId_) + if (vid != null && device.vendorId() != vid) return false; - if (productId_ != null && device.productId() != productId_) + if (pid != null && device.productId() != pid) return false; - if (serialNumber_ != null && !serialNumber_.equals(device.serialNumber())) + if (serialString != null && !serialString.equals(device.serialNumber())) return false; - if (classCode_ != null && device.classCode() != classCode_) + if (deviceClass != null && device.classCode() != deviceClass) return false; - if (subclassCode_ != null && device.subclassCode() != subclassCode_) + if (deviceSubclass != null && device.subclassCode() != deviceSubclass) return false; - return protocolCode_ == null || device.protocolCode() == protocolCode_; - } - - /** - * Test if the USB devices matches any of the filter conditions. - * - * @param device the USB device - * @param filters a list of filter conditions - * @return {@code true} if it matches, {@code false} otherwise - */ - public static boolean matchesAny(USBDevice device, List filters) { - return filters.stream().anyMatch(filter -> filter.matches(device)); + return deviceProtocol == null || device.protocolCode() == deviceProtocol; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevicePredicate.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevicePredicate.java new file mode 100644 index 00000000..6472e793 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevicePredicate.java @@ -0,0 +1,38 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb; + +import java.util.List; + +/** + * Represents a predicate (boolean-valued function) of one argument, evaluated for a given USB device. + *

+ * This is a functional interface whose functional method is {@link #matches(USBDevice)}. + *

+ */ +@FunctionalInterface +public interface USBDevicePredicate { + /** + * Evaluates this predicate on the given USB device. + * + * @param device the USB device + * @return {@code true} of the devices matches the predicate, otherwise {@code false} + */ + boolean matches(USBDevice device); + + /** + * Test if the USB devices matches any of the filter conditions. + * + * @param device the USB device + * @param predicates a list of filter predicates + * @return {@code true} if it matches, {@code false} otherwise + */ + public static boolean matchesAny(USBDevice device, List predicates) { + return predicates.stream().anyMatch(predicate -> predicate.matches(device)); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBException.java b/java-does-usb/src/main/java/net/codecrete/usb/USBException.java index 31827e62..f78487ee 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBException.java @@ -15,7 +15,7 @@ public class USBException extends RuntimeException { /** * Error code. */ - private int errorCode_ = -1; + private int code = -1; /** * Creates a new instance with a message. @@ -34,7 +34,7 @@ public USBException(String message) { */ public USBException(String message, int errorCode) { super(message + " (error code: " + errorCode + ")"); - errorCode_ = errorCode; + code = errorCode; } /** @@ -53,6 +53,6 @@ public USBException(String message, Throwable cause) { * @return the error code */ public int errorCode() { - return errorCode_; + return code; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java b/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java index e2a0f03b..91bfe1e2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java @@ -21,11 +21,11 @@ *

*/ public class CompositeFunction { - private final int firstInterfaceNumber_; - private final int numInterfaces_; - private final int classCode_; - private final int subclassCode_; - private final int protocolCode_; + private final int firstIntfNumber; + private final int interfaceCount; + private final int functionCode; + private final int functionSubclass; + private final int functionProtocol; /** * Creates a new instance. @@ -38,30 +38,30 @@ public class CompositeFunction { */ public CompositeFunction(int firstInterfaceNumber, int numInterfaces, int classCode, int subclassCode, int protocolCode) { - firstInterfaceNumber_ = firstInterfaceNumber; - numInterfaces_ = numInterfaces; - classCode_ = classCode; - subclassCode_ = subclassCode; - protocolCode_ = protocolCode; + firstIntfNumber = firstInterfaceNumber; + interfaceCount = numInterfaces; + functionCode = classCode; + functionSubclass = subclassCode; + functionProtocol = protocolCode; } public int firstInterfaceNumber() { - return firstInterfaceNumber_; + return firstIntfNumber; } public int numInterfaces() { - return numInterfaces_; + return interfaceCount; } public int classCode() { - return classCode_; + return functionCode; } public int subclassCode() { - return subclassCode_; + return functionSubclass; } public int protocolCode() { - return protocolCode_; + return functionProtocol; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java b/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java index 692ea52c..7dc70fa0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java @@ -16,53 +16,53 @@ * Describes a device configuration. */ public class Configuration { - private final List functions_; - private final List interfaces_; - private final int configValue_; - private final int attributes_; - private final int maxPower_; + private final List functionList; + private final List interfaceList; + private final int configuration; + private final int configurationAttributes; + private final int configurationMaxPower; public Configuration(int configValue, int attributes, int maxPower) { - configValue_ = configValue; - attributes_ = attributes; - maxPower_ = maxPower; - functions_ = new ArrayList<>(); - interfaces_ = new ArrayList<>(); + configuration = configValue; + configurationAttributes = attributes; + configurationMaxPower = maxPower; + functionList = new ArrayList<>(); + interfaceList = new ArrayList<>(); } public int configValue() { - return configValue_; + return configuration; } public int attributes() { - return attributes_; + return configurationAttributes; } public int maxPower() { - return maxPower_; + return configurationMaxPower; } public List interfaces() { - return interfaces_; + return interfaceList; } public List functions() { - return functions_; + return functionList; } public void addInterface(USBInterface intf) { - interfaces_.add(intf); + interfaceList.add(intf); } public USBInterfaceImpl findInterfaceByNumber(int number) { - return (USBInterfaceImpl) interfaces_.stream().filter((intf) -> intf.number() == number).findFirst().orElse(null); + return (USBInterfaceImpl) interfaceList.stream().filter((intf) -> intf.number() == number).findFirst().orElse(null); } public void addFunction(CompositeFunction function) { - functions_.add(function); + functionList.add(function); } public CompositeFunction findFunction(int interfaceNumber) { - return functions_.stream().filter((f) -> interfaceNumber >= f.firstInterfaceNumber() && interfaceNumber < f.firstInterfaceNumber() + f.numInterfaces()).findFirst().orElse(null); + return functionList.stream().filter((f) -> interfaceNumber >= f.firstInterfaceNumber() && interfaceNumber < f.firstInterfaceNumber() + f.numInterfaces()).findFirst().orElse(null); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java index 9b2d3c59..294a3acb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -37,7 +37,6 @@ */ public abstract class EndpointOutputStream extends OutputStream { - protected USBDeviceImpl device; protected final int endpointNumber; protected final Arena arena; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java index 1522e97f..c6eced74 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java @@ -11,57 +11,58 @@ import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBEndpoint; -import java.util.Collections; import java.util.List; +import static java.util.Collections.unmodifiableList; + public class USBAlternateInterfaceImpl implements USBAlternateInterface { - private final int number_; - private final int classCode_; - private final int subclassCode_; - private final int protocolCode_; - private final List endpoints_; + private final int alternateInterfaceNumber; + private final int alternateInterfaceClass; + private final int alternateInterfaceSubclass; + private final int alternateInterfaceProtocol; + private final List endpointList; public USBAlternateInterfaceImpl(int number, int classCode, int subclassCode, int protocolCode, List endpoints) { - number_ = number; - classCode_ = classCode; - subclassCode_ = subclassCode; - protocolCode_ = protocolCode; - endpoints_ = endpoints; + alternateInterfaceNumber = number; + alternateInterfaceClass = classCode; + alternateInterfaceSubclass = subclassCode; + alternateInterfaceProtocol = protocolCode; + endpointList = endpoints; } @Override public int number() { - return number_; + return alternateInterfaceNumber; } @Override public int classCode() { - return classCode_; + return alternateInterfaceClass; } @Override public int subclassCode() { - return subclassCode_; + return alternateInterfaceSubclass; } @Override public int protocolCode() { - return protocolCode_; + return alternateInterfaceProtocol; } @Override public List endpoints() { - return Collections.unmodifiableList(endpoints_); + return unmodifiableList(endpointList); } void addEndpoint(USBEndpoint endpoint) { - endpoints_.add(endpoint); + endpointList.add(endpoint); } @Override public USBEndpoint getEndpoint(int endpointNumber, USBDirection direction) { - return endpoints_.stream().filter((ep) -> ep.number() == endpointNumber && ep.direction() == direction).findFirst().orElse(null); + return endpointList.stream().filter((ep) -> ep.number() == endpointNumber && ep.direction() == direction).findFirst().orElse(null); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 6e9ee7d3..65236f3b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -19,20 +19,30 @@ public abstract class USBDeviceImpl implements USBDevice { - protected final Object id_; - protected final int vendorId_; - protected final int productId_; - protected String manufacturer_; - protected String product_; - protected String serialNumber_; - protected int classCode_; - protected int subclassCode_; - protected int protocolCode_; - protected Version usbVersion_; - protected Version deviceVersion_; - - protected List interfaces_; - protected byte[] configurationDescriptor_; + /** + * Operation-specific device ID used for {@link #equals(Object)} and {@link #hashCode()}. + *

+ * Can be a String instance (such as a file path) or a Long instance (such as an internal ID). + * It only needs to be valid for the duration the device is connected. + *

+ */ + protected final Object uniqueDeviceId; + + protected List interfaceList; + + protected byte[] rawConfigurationDescriptor; + + // Information from the device descriptor + protected final int vid; + protected final int pid; + protected String manufacturerString; + protected String productString; + protected String serialString; + protected int deviceClass; + protected int deviceSubclass; + protected int deviceProtocol; + protected Version versionUSB; + protected Version versionDevice; /** * Creates a new instance. @@ -45,9 +55,9 @@ protected USBDeviceImpl(Object id, int vendorId, int productId) { assert id != null; - id_ = id; - vendorId_ = vendorId; - productId_ = productId; + uniqueDeviceId = id; + vid = vendorId; + pid = productId; } @Override @@ -66,61 +76,61 @@ protected void checkIsOpen() { @Override public int productId() { - return productId_; + return pid; } @Override public int vendorId() { - return vendorId_; + return vid; } @Override public String product() { - return product_; + return productString; } @Override public String manufacturer() { - return manufacturer_; + return manufacturerString; } @Override public String serialNumber() { - return serialNumber_; + return serialString; } @Override public int classCode() { - return classCode_; + return deviceClass; } @Override public int subclassCode() { - return subclassCode_; + return deviceSubclass; } @Override public int protocolCode() { - return protocolCode_; + return deviceProtocol; } @Override public Version usbVersion() { - return usbVersion_; + return versionUSB; } @Override public Version deviceVersion() { - return deviceVersion_; + return versionDevice; } @Override public byte[] configurationDescriptor() { - return configurationDescriptor_; + return rawConfigurationDescriptor; } public Object getUniqueId() { - return id_; + return uniqueDeviceId; } /** @@ -130,11 +140,11 @@ public Object getUniqueId() { */ public void setFromDeviceDescriptor(MemorySegment descriptor) { var deviceDescriptor = new DeviceDescriptor(descriptor); - classCode_ = deviceDescriptor.deviceClass() & 255; - subclassCode_ = deviceDescriptor.deviceSubClass() & 255; - protocolCode_ = deviceDescriptor.deviceProtocol() & 255; - usbVersion_ = new Version(deviceDescriptor.usbVersion()); - deviceVersion_ = new Version(deviceDescriptor.deviceVersion()); + deviceClass = deviceDescriptor.deviceClass() & 255; + deviceSubclass = deviceDescriptor.deviceSubClass() & 255; + deviceProtocol = deviceDescriptor.deviceProtocol() & 255; + versionUSB = new Version(deviceDescriptor.usbVersion()); + versionDevice = new Version(deviceDescriptor.deviceVersion()); } /** @@ -144,9 +154,9 @@ public void setFromDeviceDescriptor(MemorySegment descriptor) { * @return parsed configuration */ protected Configuration setConfigurationDescriptor(MemorySegment descriptor) { - configurationDescriptor_ = descriptor.toArray(JAVA_BYTE); + rawConfigurationDescriptor = descriptor.toArray(JAVA_BYTE); var configuration = ConfigurationParser.parseConfigurationDescriptor(descriptor); - interfaces_ = configuration.interfaces(); + interfaceList = configuration.interfaces(); return configuration; } @@ -158,9 +168,9 @@ protected Configuration setConfigurationDescriptor(MemorySegment descriptor) { * @param serialNumber serial number */ public void setProductStrings(String manufacturer, String product, String serialNumber) { - manufacturer_ = manufacturer; - product_ = product; - serialNumber_ = serialNumber; + manufacturerString = manufacturer; + productString = product; + serialString = serialNumber; } /** @@ -175,25 +185,25 @@ public void setProductStrings(String manufacturer, String product, String serial */ public void setProductString(MemorySegment descriptor, Function stringLookup) { var deviceDescriptor = new DeviceDescriptor(descriptor); - manufacturer_ = stringLookup.apply(deviceDescriptor.iManufacturer()); - product_ = stringLookup.apply(deviceDescriptor.iProduct()); - serialNumber_ = stringLookup.apply(deviceDescriptor.iSerialNumber()); + manufacturerString = stringLookup.apply(deviceDescriptor.iManufacturer()); + productString = stringLookup.apply(deviceDescriptor.iProduct()); + serialString = stringLookup.apply(deviceDescriptor.iSerialNumber()); } public void setClassCodes(int classCode, int subclassCode, int protocolCode) { - classCode_ = classCode; - subclassCode_ = subclassCode; - protocolCode_ = protocolCode; + deviceClass = classCode; + deviceSubclass = subclassCode; + deviceProtocol = protocolCode; } public void setVersions(int usbVersion, int deviceVersion) { - usbVersion_ = new Version(usbVersion); - deviceVersion_ = new Version(deviceVersion); + versionUSB = new Version(usbVersion); + versionDevice = new Version(deviceVersion); } @Override public List interfaces() { - return Collections.unmodifiableList(interfaces_); + return Collections.unmodifiableList(interfaceList); } @Override @@ -203,7 +213,7 @@ public List interfaces() { public abstract void releaseInterface(int interfaceNumber); public void setClaimed(int interfaceNumber, boolean claimed) { - for (var intf : interfaces_) { + for (var intf : interfaceList) { if (intf.number() == interfaceNumber) { ((USBInterfaceImpl) intf).setClaimed(claimed); return; @@ -214,12 +224,12 @@ public void setClaimed(int interfaceNumber, boolean claimed) { @Override public USBInterfaceImpl getInterface(int interfaceNumber) { - return (USBInterfaceImpl) interfaces_.stream().filter((intf) -> intf.number() == interfaceNumber).findFirst().orElse(null); + return (USBInterfaceImpl) interfaceList.stream().filter((intf) -> intf.number() == interfaceNumber).findFirst().orElse(null); } @Override public USBEndpoint getEndpoint(USBDirection direction, int endpointNumber) { - for (var intf : interfaces_) { + for (var intf : interfaceList) { for (var endpoint : intf.alternate().endpoints()) { if (endpoint.direction() == direction && endpoint.number() == endpointNumber) return endpoint; @@ -243,7 +253,7 @@ protected EndpointInfo getEndpoint(USBDirection direction, int endpointNumber, U checkIsOpen(); if (endpointNumber >= 1 && endpointNumber <= 127) { - for (var intf : interfaces_) { + for (var intf : interfaceList) { if (intf.isClaimed()) { for (var ep : intf.alternate().endpoints()) { if (ep.number() == endpointNumber && ep.direction() == direction && (ep.transferType() == transferType1 || ep.transferType() == transferType2)) @@ -273,7 +283,7 @@ protected int getInterfaceNumber(USBDirection direction, int endpointNumber) { if (endpointNumber < 1 || endpointNumber > 127) return -1; - for (var intf : interfaces_) { + for (var intf : interfaceList) { if (intf.isClaimed()) { for (var ep : intf.alternate().endpoints()) { if (ep.number() == endpointNumber && ep.direction() == direction) @@ -405,17 +415,17 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; USBDeviceImpl that = (USBDeviceImpl) o; - return id_.equals(that.id_); + return uniqueDeviceId.equals(that.uniqueDeviceId); } @Override public int hashCode() { - return id_.hashCode(); + return uniqueDeviceId.hashCode(); } @Override public String toString() { - return "VID: 0x" + String.format("%04x", vendorId_) + ", PID: 0x" + String.format("%04x", productId_) + ", " + "manufacturer: " + manufacturer_ + ", product: " + product_ + ", serial: " + serialNumber_ + ", ID: " + id_; + return "VID: 0x" + String.format("%04x", vid) + ", PID: 0x" + String.format("%04x", pid) + ", " + "manufacturer: " + manufacturerString + ", product: " + productString + ", serial: " + serialString + ", ID: " + uniqueDeviceId; } public record EndpointInfo(int interfaceNumber, int endpointNumber, byte endpointAddress, int packetSize, diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBEndpointImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBEndpointImpl.java index c245a4f3..f896b0f2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBEndpointImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBEndpointImpl.java @@ -16,35 +16,35 @@ */ public class USBEndpointImpl implements USBEndpoint { - private final int number_; - private final USBDirection direction_; - private final USBTransferType type_; - private final int packetSize_; + private final int endpointNumber; + private final USBDirection transferDirection; + private final USBTransferType type; + private final int maxPacketSize; public USBEndpointImpl(int number, USBDirection direction, USBTransferType type, int packetSize) { - number_ = number; - direction_ = direction; - type_ = type; - packetSize_ = packetSize; + endpointNumber = number; + transferDirection = direction; + this.type = type; + maxPacketSize = packetSize; } @Override public int number() { - return number_; + return endpointNumber; } @Override public USBDirection direction() { - return direction_; + return transferDirection; } @Override public USBTransferType transferType() { - return type_; + return type; } @Override public int packetSize() { - return packetSize_; + return maxPacketSize; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java index 2cf7b634..5990208f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java @@ -15,52 +15,52 @@ public class USBInterfaceImpl implements USBInterface { - private final int number_; - private USBAlternateInterface alternate_; - private final List alternates_; + private final int interfaceNumber; + private USBAlternateInterface currentAlternate; + private final List alternateInterfaces; - private boolean isClaimed_; + private boolean claimed; public USBInterfaceImpl(int number, List alternates) { - number_ = number; - alternates_ = alternates; - alternate_ = alternates.get(0); + interfaceNumber = number; + alternateInterfaces = alternates; + currentAlternate = alternates.get(0); } @Override public int number() { - return number_; + return interfaceNumber; } @Override public boolean isClaimed() { - return isClaimed_; + return claimed; } public void setClaimed(boolean claimed) { - isClaimed_ = claimed; + this.claimed = claimed; } @Override public USBAlternateInterface alternate() { - return alternate_; + return currentAlternate; } @Override public USBAlternateInterface getAlternate(int alternateNumber) { - return alternates_.stream().filter((alt) -> alt.number() == alternateNumber).findFirst().orElse(null); + return alternateInterfaces.stream().filter((alt) -> alt.number() == alternateNumber).findFirst().orElse(null); } @Override public List alternates() { - return Collections.unmodifiableList(alternates_); + return Collections.unmodifiableList(alternateInterfaces); } void addAlternate(USBAlternateInterface alt) { - alternates_.add(alt); + alternateInterfaces.add(alt); } public void setAlternate(USBAlternateInterface alternate) { - alternate_ = alternate; + currentAlternate = alternate; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index fe1c0857..741fdf2b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -74,7 +74,7 @@ public synchronized void open() { throwException("the device is already open"); try (var arena = Arena.openConfined()) { - var pathUtf8 = arena.allocateUtf8String(id_.toString()); + var pathUtf8 = arena.allocateUtf8String(uniqueDeviceId.toString()); var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); fd = IO.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC(), errnoState); if (fd == -1) @@ -90,7 +90,7 @@ public synchronized void close() { asyncTask.removeFromAsyncIOCompletion(this); - for (var intf : interfaces_) + for (var intf : interfaceList) ((USBInterfaceImpl) intf).setClaimed(false); unistd.close(fd); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 8ba3b93f..21598ba3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -32,11 +32,16 @@ /** * Windows implementation for USB device. */ +@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") public class WindowsUSBDevice extends USBDeviceImpl { private final WindowsAsyncTask asyncTask; - private List interfaceHandles_; - private boolean isOpen_; + private List interfaceHandles; + /** + * Indicates if {@link #open()} has been called. Since separate interfaces can have separate underlying + * Windows device, {@link #claimInterface(int)} instead of {@link #open()} will open the Windows device. + */ + private boolean showAsOpen; WindowsUSBDevice(String devicePath, Map children, int vendorId, int productId, MemorySegment configDesc) { @@ -49,7 +54,7 @@ private void readDescription(MemorySegment configDesc, String devicePath, Map(); + interfaceHandles = new ArrayList<>(); for (var intf : configuration.interfaces()) { var interfaceNumber = intf.number(); var function = configuration.findFunction(interfaceNumber); @@ -64,13 +69,13 @@ private void readDescription(MemorySegment configDesc, String devicePath, Map dev.vendorId() == vid && dev.productId() == pid); + assertEquals(vid, device.vendorId()); + assertEquals(pid, device.productId()); + } } diff --git a/test-devices/loopback-stm32/.vscode/settings.json b/test-devices/loopback-stm32/.vscode/settings.json index 0b167675..a92d1337 100644 --- a/test-devices/loopback-stm32/.vscode/settings.json +++ b/test-devices/loopback-stm32/.vscode/settings.json @@ -1,6 +1,8 @@ { "files.associations": { "usbd.h": "c", - "usbd_pvt.h": "c" + "usbd_pvt.h": "c", + "dwc2_stm32.h": "c", + "stm32f7xx.h": "c" } } \ No newline at end of file From f14cf4ebb10058ab6e9a1f60365aa4e7d7034a4a Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 18 May 2023 14:35:59 +0200 Subject: [PATCH 228/433] Minor cleanup --- .../src/main/java/net/codecrete/usb/USBDeviceFilter.java | 2 -- .../src/main/java/net/codecrete/usb/USBDevicePredicate.java | 2 +- .../src/main/java/net/codecrete/usb/common/USBDeviceImpl.java | 1 + .../src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java | 1 + 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java index cf7b1852..121e1cca 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java @@ -7,8 +7,6 @@ package net.codecrete.usb; -import java.util.List; - /** * Filter condition for matching USB devices. *

diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevicePredicate.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevicePredicate.java index 6472e793..6b1b773b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevicePredicate.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevicePredicate.java @@ -32,7 +32,7 @@ public interface USBDevicePredicate { * @param predicates a list of filter predicates * @return {@code true} if it matches, {@code false} otherwise */ - public static boolean matchesAny(USBDevice device, List predicates) { + static boolean matchesAny(USBDevice device, List predicates) { return predicates.stream().anyMatch(predicate -> predicate.matches(device)); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 65236f3b..ceecaaca 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -17,6 +17,7 @@ import static java.lang.foreign.ValueLayout.JAVA_BYTE; +@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") public abstract class USBDeviceImpl implements USBDevice { /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 741fdf2b..97fab7f6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -36,6 +36,7 @@ import static net.codecrete.usb.linux.LinuxUSBException.throwException; import static net.codecrete.usb.linux.LinuxUSBException.throwLastError; +@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") public class LinuxUSBDevice extends USBDeviceImpl { private int fd = -1; From 4500bb42783d6a8081afeb0e34cc709bc3564630 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 18 May 2023 19:54:58 +0200 Subject: [PATCH 229/433] Fix typos --- java-does-usb/jextract/README.md | 4 ++-- .../src/main/java/net/codecrete/usb/USBEndpoint.java | 2 +- .../src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index c79a41bc..a9b37b08 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -17,7 +17,7 @@ The resulting code is then committed to the source code repository. Before the c - According to the jextract mailing list, it would be required to create separate code form Intel x64 and ARM64 architecture. And jextract would need to be run on each architecture separately (no cross-compilation). Fortunately, this doesn't seem to be the case. Linux code generated on Intel x64 also runs on ARM64 without change. The same holds for macOS. However, jextract needs to be run on each operating system separately. -- JDK 20 introduced a new feature for saving the thread-specific error values (`GetLastError()` on Windows, `errno` on Linux). To use it, an additional parameter must be added to function calls. Unfortuntely, this is not yet supported by jextract. So with the JDK 20 updates, more code is written manually and less is generated by jextract. +- JDK 20 introduced a new feature for saving the thread-specific error values (`GetLastError()` on Windows, `errno` on Linux). To use it, an additional parameter must be added to function calls. Unfortunately, this is not yet supported by jextract. So with the JDK 20 updates, more code is written manually and less is generated by jextract. - `typedef` and `struct`: @@ -98,7 +98,7 @@ The known limitations are: *jextract* generates a comprehensive set of methods for each function, struct, struct member etc. Most of it will not be used as a typical application just uses a subset of struct members, might only read or write them etc. So a considerable amount of code is generated. For some types, it's a bit excessive. -The worst example is [`IOUSBInterfaceStruct100`](https://github.com/manuelbl/JavaDoesUSB/blob/main/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct100.java) (macOS). This is a `struct` consisting of about 75 member functions. It's bascially a vtable of a C++ class. *jextract* generates the same number of classes plus a huge class for the struct itself. The total code size (compiled) for this single `struct` is over 300 kByte. +The worst example is [`IOUSBInterfaceStruct100`](https://github.com/manuelbl/JavaDoesUSB/blob/main/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct100.java) (macOS). This is a `struct` consisting of about 75 member functions. It's basically a vtable of a C++ class. *jextract* generates the same number of classes plus a huge class for the struct itself. The total code size (compiled) for this single `struct` is over 300 kByte. The table below shows statictics for version 0.2.0 of the library: diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBEndpoint.java b/java-does-usb/src/main/java/net/codecrete/usb/USBEndpoint.java index 8ccd271d..434e0d34 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBEndpoint.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBEndpoint.java @@ -24,7 +24,7 @@ public interface USBEndpoint { *

*

* Use this number when calling any of the transfer methods of a - * {@link USBDevice} instace. + * {@link USBDevice} instance. *

* * @return the endpoint number diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index b6d1fa8e..a18dcdb1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -43,6 +43,7 @@ * asynchronous transfer and waiting for the completion. *

*/ +@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") public class MacosUSBDevice extends USBDeviceImpl { private final MacosAsyncTask asyncTask; From 4abd0e05c07372c3f3e0a5693d39335a6c102d3f Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 2 Jul 2023 10:33:51 +0200 Subject: [PATCH 230/433] macOS: detach/attach drivers --- java-does-usb/jextract/macos/gen_macos.sh | 6 +- java-does-usb/pom.xml | 14 +- .../java/net/codecrete/usb/USBDevice.java | 50 ++ .../codecrete/usb/common/USBDeviceImpl.java | 10 + .../codecrete/usb/linux/LinuxUSBDevice.java | 50 +- .../net/codecrete/usb/linux/USBDevFS.java | 1 + .../net/codecrete/usb/macos/IoKitHelper.java | 6 +- .../net/codecrete/usb/macos/IoKitUSB.java | 29 +- .../codecrete/usb/macos/MacosUSBDevice.java | 14 + .../usb/macos/MacosUSBDeviceRegistry.java | 2 +- .../codecrete/usb/macos/gen/iokit/IOKit.java | 16 + .../gen/iokit/IOUSBDeviceInterface182.java | 16 - .../gen/iokit/IOUSBDeviceInterface187.java | 16 + ...ruct182.java => IOUSBDeviceStruct187.java} | 659 ++++++++++-------- 14 files changed, 536 insertions(+), 353 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface182.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface187.java rename java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/{IOUSBDeviceStruct182.java => IOUSBDeviceStruct187.java} (82%) diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index 13d8dd4e..c74b5864 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -52,8 +52,8 @@ $JEXTRACT --source --output ../../src/main/java \ --include-function IORegistryEntryGetRegistryEntryID \ --include-function IOServiceAddMatchingNotification \ --include-function IOServiceMatching \ - --include-struct IOUSBDeviceStruct182 \ - --include-typedef IOUSBDeviceInterface182 \ + --include-struct IOUSBDeviceStruct187 \ + --include-typedef IOUSBDeviceInterface187 \ --include-constant kIOUSBFindInterfaceDontCare \ --include-typedef IOUSBFindInterfaceRequest \ --include-typedef IOUSBDevRequest \ @@ -62,6 +62,8 @@ $JEXTRACT --source --output ../../src/main/java \ --include-constant kIOUSBTransactionTimeout \ --include-constant kIOReturnAborted \ --include-constant kIOUSBPipeStalled \ + --include-constant kUSBReEnumerateCaptureDeviceMask \ + --include-constant kUSBReEnumerateReleaseDeviceMask \ iokit_helper.h # mach.h diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 6b3c7beb..af40c9a3 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 0.5.0 + 0.5.1 20 @@ -54,7 +54,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.10.1 + 3.11.0 20 @@ -67,7 +67,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.0.0-M7 + 3.1.2 --enable-preview --enable-native-access=ALL-UNNAMED @@ -75,7 +75,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.4.1 + 3.5.0 attach-javadocs @@ -93,7 +93,7 @@ org.apache.maven.plugins maven-gpg-plugin - 3.0.1 + 3.1.0 sign-artifacts @@ -107,7 +107,7 @@ org.apache.maven.plugins maven-source-plugin - 3.2.1 + 3.3.0 attach-sources @@ -140,7 +140,7 @@ org.junit.jupiter junit-jupiter - 5.9.0 + 5.9.3 test diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index aa77f024..1dfc2103 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -99,6 +99,56 @@ public interface USBDevice { */ Version deviceVersion(); + /** + * Detaches the standard operating-system drivers of this device. + *

+ * By detaching the standard drivers, the operating system releases the exclusive access to the device + * and/or some or all of the device's interfaces. This allows the application to open the device and claim + * interfaces. It is relevant for device and interfaces implementing standard USB classes, such as HID, CDC + * and mass storage. + *

+ *

+ * This method should be called before the device is opened. After the device has been closed, + * {@link #attachStandardDrivers()} should be called to restore the previous state. + *

+ *

+ * On macOS, all device drivers are immediately detached from the device. To execute it, the application must + * be run as root. Without root privileges, the method does nothing. + *

+ *

+ * On Linux, this method changes the behavior of {@link #claimInterface(int)} for this device. The standard drivers + * will be detached interface by interface when the interface is claimed. + *

+ *

+ * On Windows, this method does nothing. It is not possible to temporarily change the drivers. + *

+ */ + void detachStandardDrivers(); + + /** + * Reattaches the standard operating-system drivers to this device. + *

+ * By attaching the standard drivers, the operating system claims the device and/or its interfaces if they + * implement standard USB classes, such as HID, CDC and mass storage. It is used to restore the state before + * calling {@link #detachStandardDrivers()}. + *

+ *

+ * This method should be called after the device has been closed. + *

+ *

+ * On macOS, the application must be run as root. Without root privileges, the method does nothing. + *

+ *

+ * On Linux, this method changes the behavior of {@link #claimInterface(int)}. Standard drivers will no longer be + * detached when the interface is claimed. Standard drivers are automatically reattached when the interfaces + * are released, at the lasted when the device is closed. + *

+ *

+ * On Windows, this method does nothing. + *

+ */ + void attachStandardDrivers(); + /** * Opens the device for communication. */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index ceecaaca..d57c11d7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -61,6 +61,16 @@ protected USBDeviceImpl(Object id, int vendorId, int productId) { pid = productId; } + @Override + public void detachStandardDrivers() { + // Default implementation: do nothing + } + + @Override + public void attachStandardDrivers() { + // Default implementation: do nothing + } + @Override public abstract void open(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 97fab7f6..36566119 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -43,6 +43,8 @@ public class LinuxUSBDevice extends USBDeviceImpl { private final LinuxAsyncTask asyncTask; + private boolean detachDrivers = false; + LinuxUSBDevice(Object id, int vendorId, int productId) { super(id, vendorId, productId); asyncTask = LinuxAsyncTask.instance(); @@ -64,6 +66,16 @@ private void loadDescription(String path) { setConfigurationDescriptor(descriptorsSegment.asSlice(DeviceDescriptor.LAYOUT.byteSize())); } + @Override + public void detachStandardDrivers() { + detachDrivers = true; + } + + @Override + public void attachStandardDrivers() { + detachDrivers = false; + } + @Override public boolean isOpen() { return fd != -1; @@ -113,14 +125,22 @@ public synchronized void claimInterface(int interfaceNumber) { try (var arena = Arena.openConfined()) { var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); - - // claim interface (possibly disconnecting kernel driver) - var disconnectClaim = usbdevfs_disconnect_claim.allocate(arena); - usbdevfs_disconnect_claim.interface_$set(disconnectClaim, interfaceNumber); - usbdevfs_disconnect_claim.flags$set(disconnectClaim, usbdevice_fs.USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER()); - byte[] driverName = { 'u', 's', 'b', 'f', 's', 0 }; - usbdevfs_disconnect_claim.driver$slice(disconnectClaim).copyFrom(MemorySegment.ofArray(driverName)); - int ret = IO.ioctl(fd, USBDevFS.DISCONNECT_CLAIM, disconnectClaim, errnoState); + int ret; + + if (detachDrivers) { + // claim interface (detaching kernel driver) + var disconnectClaim = usbdevfs_disconnect_claim.allocate(arena); + usbdevfs_disconnect_claim.interface_$set(disconnectClaim, interfaceNumber); + usbdevfs_disconnect_claim.flags$set(disconnectClaim, usbdevice_fs.USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER()); + byte[] driverName = {'u', 's', 'b', 'f', 's', 0}; + usbdevfs_disconnect_claim.driver$slice(disconnectClaim).copyFrom(MemorySegment.ofArray(driverName)); + ret = IO.ioctl(fd, USBDevFS.DISCONNECT_CLAIM, disconnectClaim, errnoState); + + } else { + // claim interface (without detaching kernel driver) + var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); + ret = IO.ioctl(fd, USBDevFS.CLAIMINTERFACE, intfNumSegment, errnoState); + } if (ret != 0) throwLastError(errnoState, "Cannot claim USB interface"); @@ -176,12 +196,14 @@ public synchronized void releaseInterface(int interfaceNumber) { setClaimed(interfaceNumber, false); - // reattach kernel driver - var request = usbdevfs_ioctl.allocate(arena); - usbdevfs_ioctl.ifno$set(request, interfaceNumber); - usbdevfs_ioctl.ioctl_code$set(request, USBDevFS.CONNECT); - usbdevfs_ioctl.data$set(request, MemorySegment.NULL); - IO.ioctl(fd, USBDevFS.IOCTL, request, errnoState); + if (detachDrivers) { + // reattach kernel driver + var request = usbdevfs_ioctl.allocate(arena); + usbdevfs_ioctl.ifno$set(request, interfaceNumber); + usbdevfs_ioctl.ioctl_code$set(request, USBDevFS.CONNECT); + usbdevfs_ioctl.data$set(request, MemorySegment.NULL); + IO.ioctl(fd, USBDevFS.IOCTL, request, errnoState); + } } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java index 4f05637f..56aabad7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java @@ -12,6 +12,7 @@ */ public class USBDevFS { + public static final long CLAIMINTERFACE = 0x8004550FL; public static final long RELEASEINTERFACE = 0x80045510L; public static final long SETINTERFACE = 0x80085504L; public static final long CLEAR_HALT = 0x80045515L; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index 7c063c93..896ab60c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -28,9 +28,9 @@ public class IoKitHelper { public static final MemorySegment kIOUSBInterfaceUserClientTypeID = UUID.CreateCFUUID(new byte[]{(byte) 0x2d, (byte) 0x97, (byte) 0x86, (byte) 0xc6, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, (byte) 0xad, (byte) 0x51, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61}); - public static final MemorySegment kIOUSBDeviceInterfaceID182 = UUID.CreateCFUUID(new byte[]{(byte) 0x15, - (byte) 0x2f, (byte) 0xc4, (byte) 0x96, (byte) 0x48, (byte) 0x91, (byte) 0x11, (byte) 0xD5, (byte) 0x9d, - (byte) 0x52, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x80, (byte) 0x1e, (byte) 0x86}); + public static final MemorySegment kIOUSBDeviceInterfaceID187 = UUID.CreateCFUUID(new byte[]{(byte) 0x3c, + (byte) 0x9e, (byte) 0xe1, (byte) 0xeb, (byte) 0x24, (byte) 0x02, (byte) 0x11, (byte) 0xb2, (byte) 0x8e, + (byte) 0x7e, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x80, (byte) 0x1e, (byte) 0x86}); public static final MemorySegment kIOUSBInterfaceInterfaceID190 = UUID.CreateCFUUID(new byte[]{(byte) 0x8f, (byte) 0xdb, (byte) 0x84, (byte) 0x55, (byte) 0x74, (byte) 0xa6, (byte) 0x11, (byte) 0xD6, (byte) 0x97, (byte) 0xb1, (byte) 0x00, (byte) 0x30, (byte) 0x65, (byte) 0xd3, (byte) 0x60, (byte) 0x8e}); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index 55d34700..03b4d41d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -8,7 +8,7 @@ package net.codecrete.usb.macos; import net.codecrete.usb.common.ForeignMemory; -import net.codecrete.usb.macos.gen.iokit.IOUSBDeviceInterface182; +import net.codecrete.usb.macos.gen.iokit.IOUSBDeviceInterface187; import net.codecrete.usb.macos.gen.iokit.IOUSBInterfaceInterface190; import java.lang.foreign.MemorySegment; @@ -29,60 +29,65 @@ private static MemorySegment getVtable(MemorySegment self) { // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); public static int QueryInterface(MemorySegment self, MemorySegment iid, MemorySegment ppv) { - return IOUSBDeviceInterface182.QueryInterface(getVtable(self), SegmentScope.global()).apply(self, iid, ppv); + return IOUSBDeviceInterface187.QueryInterface(getVtable(self), SegmentScope.global()).apply(self, iid, ppv); } // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); public static int AddRef(MemorySegment self) { - return IOUSBDeviceInterface182.AddRef(getVtable(self), SegmentScope.global()).apply(self); + return IOUSBDeviceInterface187.AddRef(getVtable(self), SegmentScope.global()).apply(self); } // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer) public static int Release(MemorySegment self) { - return IOUSBDeviceInterface182.Release(getVtable(self), SegmentScope.global()).apply(self); + return IOUSBDeviceInterface187.Release(getVtable(self), SegmentScope.global()).apply(self); } // IOReturn (* CreateDeviceAsyncEventSource)(void* self, CFRunLoopSourceRef* source); public static int CreateDeviceAsyncEventSource(MemorySegment self, MemorySegment source) { - return IOUSBDeviceInterface182.CreateDeviceAsyncEventSource(getVtable(self), SegmentScope.global()).apply(self, source); + return IOUSBDeviceInterface187.CreateDeviceAsyncEventSource(getVtable(self), SegmentScope.global()).apply(self, source); } // CFRunLoopSourceRef (* GetDeviceAsyncEventSource)(void* self); public static MemorySegment GetDeviceAsyncEventSource(MemorySegment self) { - return IOUSBDeviceInterface182.GetDeviceAsyncEventSource(getVtable(self), SegmentScope.global()).apply(self); + return IOUSBDeviceInterface187.GetDeviceAsyncEventSource(getVtable(self), SegmentScope.global()).apply(self); } // IOReturn (*USBDeviceOpenSeize)(void *self); public static int USBDeviceOpenSeize(MemorySegment self) { - return IOUSBDeviceInterface182.USBDeviceOpenSeize(getVtable(self), SegmentScope.global()).apply(self); + return IOUSBDeviceInterface187.USBDeviceOpenSeize(getVtable(self), SegmentScope.global()).apply(self); } // IOReturn (*USBDeviceClose)(void *self); public static int USBDeviceClose(MemorySegment self) { - return IOUSBDeviceInterface182.USBDeviceClose(getVtable(self), SegmentScope.global()).apply(self); + return IOUSBDeviceInterface187.USBDeviceClose(getVtable(self), SegmentScope.global()).apply(self); + } + + // IOReturn (* USBDeviceReEnumerate)(void* self, UInt32 options); + public static int USBDeviceReEnumerate(MemorySegment self, int options) { + return IOUSBDeviceInterface187.USBDeviceReEnumerate(getVtable(self), SegmentScope.global()).apply(self, options); } // IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc); public static int GetConfigurationDescriptorPtr(MemorySegment self, byte configIndex, MemorySegment descHolder) { - return IOUSBDeviceInterface182.GetConfigurationDescriptorPtr(getVtable(self), SegmentScope.global()).apply(self, configIndex, descHolder); + return IOUSBDeviceInterface187.GetConfigurationDescriptorPtr(getVtable(self), SegmentScope.global()).apply(self, configIndex, descHolder); } // IOReturn (*SetConfiguration)(void *self, UInt8 configNum); public static int SetConfiguration(MemorySegment self, byte configValue) { - return IOUSBDeviceInterface182.SetConfiguration(getVtable(self), SegmentScope.global()).apply(self, + return IOUSBDeviceInterface187.SetConfiguration(getVtable(self), SegmentScope.global()).apply(self, configValue); } // IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter); public static int CreateInterfaceIterator(MemorySegment self, MemorySegment req, MemorySegment iter) { - return IOUSBDeviceInterface182.CreateInterfaceIterator(getVtable(self), SegmentScope.global()).apply(self, + return IOUSBDeviceInterface187.CreateInterfaceIterator(getVtable(self), SegmentScope.global()).apply(self, req, iter); } // IOReturn (* DeviceRequestAsync)(void* self, IOUSBDevRequest* req, IOAsyncCallback1 callback, void* refCon); public static int DeviceRequestAsync(MemorySegment self, MemorySegment deviceRequest, MemorySegment callback, MemorySegment refCon) { - return IOUSBDeviceInterface182.DeviceRequestAsync(getVtable(self), SegmentScope.global()).apply(self, + return IOUSBDeviceInterface187.DeviceRequestAsync(getVtable(self), SegmentScope.global()).apply(self, deviceRequest, callback, refCon); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index a18dcdb1..b5f1d0ba 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -69,6 +69,20 @@ public class MacosUSBDevice extends USBDeviceImpl { IoKitUSB.AddRef(device); } + @Override + public void detachStandardDrivers() { + int ret = IoKitUSB.USBDeviceReEnumerate(device, IOKit.kUSBReEnumerateCaptureDeviceMask()); + if (ret != 0) + throwException(ret, "failed to detach kernel drivers"); + } + + @Override + public void attachStandardDrivers() { + int ret = IoKitUSB.USBDeviceReEnumerate(device, IOKit.kUSBReEnumerateReleaseDeviceMask()); + if (ret != 0) + throwException(ret, "failed to attach kernel drivers"); + } + @Override public boolean isOpen() { return claimedInterfaces != null; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index c31d8bba..27719837 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -118,7 +118,7 @@ private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { cleanup.add(() -> IOKit.IOObjectRelease(service)); var device = IoKitHelper.getInterface(service, IoKitHelper.kIOUSBDeviceUserClientTypeID, - IoKitHelper.kIOUSBDeviceInterfaceID182); + IoKitHelper.kIOUSBDeviceInterfaceID187); if (device != null) cleanup.add(() -> IoKitUSB.Release(device)); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java index f80e21ad..5044aeac 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java @@ -26,6 +26,22 @@ public class IOKit { public static int kIOUSBFindInterfaceDontCare() { return (int)65535L; } + /** + * {@snippet : + * enum .kUSBReEnumerateCaptureDeviceMask = 1073741824; + * } + */ + public static int kUSBReEnumerateCaptureDeviceMask() { + return (int)1073741824L; + } + /** + * {@snippet : + * enum .kUSBReEnumerateReleaseDeviceMask = 536870912; + * } + */ + public static int kUSBReEnumerateReleaseDeviceMask() { + return (int)536870912L; + } public static MemoryLayout kCFRunLoopDefaultMode$LAYOUT() { return constants$0.kCFRunLoopDefaultMode$LAYOUT; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface182.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface182.java deleted file mode 100644 index 7a978984..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface182.java +++ /dev/null @@ -1,16 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -/** - * {@snippet : - * typedef struct IOUSBDeviceStruct182 IOUSBDeviceInterface182; - * } - */ -public final class IOUSBDeviceInterface182 extends IOUSBDeviceStruct182 { - - // Suppresses default constructor, ensuring non-instantiability. - private IOUSBDeviceInterface182() {} -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface187.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface187.java new file mode 100644 index 00000000..be0be089 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface187.java @@ -0,0 +1,16 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +/** + * {@snippet : + * typedef struct IOUSBDeviceStruct187 IOUSBDeviceInterface187; + * } + */ +public final class IOUSBDeviceInterface187 extends IOUSBDeviceStruct187 { + + // Suppresses default constructor, ensuring non-instantiability. + private IOUSBDeviceInterface187() {} +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct182.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java similarity index 82% rename from java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct182.java rename to java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java index 322d17c1..fef575c0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct182.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java @@ -7,7 +7,7 @@ import java.lang.invoke.VarHandle; /** * {@snippet : - * struct IOUSBDeviceStruct182 { + * struct IOUSBDeviceStruct187 { * void* _reserved; * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); * ULONG (*AddRef)(void*); @@ -45,10 +45,11 @@ * IOReturn (*USBGetManufacturerStringIndex)(void*,UInt8*); * IOReturn (*USBGetProductStringIndex)(void*,UInt8*); * IOReturn (*USBGetSerialNumberStringIndex)(void*,UInt8*); + * IOReturn (*USBDeviceReEnumerate)(void*,UInt32); * }; * } */ -public class IOUSBDeviceStruct182 { +public class IOUSBDeviceStruct187 { static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_POINTER$LAYOUT.withName("_reserved"), @@ -87,14 +88,15 @@ public class IOUSBDeviceStruct182 { Constants$root.C_POINTER$LAYOUT.withName("USBDeviceAbortPipeZero"), Constants$root.C_POINTER$LAYOUT.withName("USBGetManufacturerStringIndex"), Constants$root.C_POINTER$LAYOUT.withName("USBGetProductStringIndex"), - Constants$root.C_POINTER$LAYOUT.withName("USBGetSerialNumberStringIndex") - ).withName("IOUSBDeviceStruct182"); + Constants$root.C_POINTER$LAYOUT.withName("USBGetSerialNumberStringIndex"), + Constants$root.C_POINTER$LAYOUT.withName("USBDeviceReEnumerate") + ).withName("IOUSBDeviceStruct187"); public static MemoryLayout $LAYOUT() { - return IOUSBDeviceStruct182.$struct$LAYOUT; + return IOUSBDeviceStruct187.$struct$LAYOUT; } static final VarHandle _reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("_reserved")); public static VarHandle _reserved$VH() { - return IOUSBDeviceStruct182._reserved$VH; + return IOUSBDeviceStruct187._reserved$VH; } /** * Getter for field: @@ -103,7 +105,7 @@ public class IOUSBDeviceStruct182 { * } */ public static MemorySegment _reserved$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182._reserved$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187._reserved$VH.get(seg); } /** * Setter for field: @@ -112,13 +114,13 @@ public class IOUSBDeviceStruct182 { * } */ public static void _reserved$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182._reserved$VH.set(seg, x); + IOUSBDeviceStruct187._reserved$VH.set(seg, x); } public static MemorySegment _reserved$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182._reserved$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187._reserved$VH.get(seg.asSlice(index*sizeof())); } public static void _reserved$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182._reserved$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187._reserved$VH.set(seg.asSlice(index*sizeof()), x); } static final FunctionDescriptor QueryInterface$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, @@ -143,7 +145,7 @@ public class IOUSBDeviceStruct182 { Constants$root.C_POINTER$LAYOUT ); static final MethodHandle QueryInterface$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.QueryInterface$FUNC + IOUSBDeviceStruct187.QueryInterface$FUNC ); /** * {@snippet : @@ -154,13 +156,13 @@ public interface QueryInterface { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); static MemorySegment allocate(QueryInterface fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOUSBDeviceStruct182.QueryInterface$FUNC, scope); + return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOUSBDeviceStruct187.QueryInterface$FUNC, scope); } static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBDeviceStruct182.QueryInterface$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)IOUSBDeviceStruct187.QueryInterface$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -170,7 +172,7 @@ static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle QueryInterface$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("QueryInterface")); public static VarHandle QueryInterface$VH() { - return IOUSBDeviceStruct182.QueryInterface$VH; + return IOUSBDeviceStruct187.QueryInterface$VH; } /** * Getter for field: @@ -179,7 +181,7 @@ static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment QueryInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.QueryInterface$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.QueryInterface$VH.get(seg); } /** * Setter for field: @@ -188,13 +190,13 @@ static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void QueryInterface$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.QueryInterface$VH.set(seg, x); + IOUSBDeviceStruct187.QueryInterface$VH.set(seg, x); } public static MemorySegment QueryInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.QueryInterface$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.QueryInterface$VH.get(seg.asSlice(index*sizeof())); } public static void QueryInterface$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.QueryInterface$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.QueryInterface$VH.set(seg.asSlice(index*sizeof()), x); } public static QueryInterface QueryInterface(MemorySegment segment, SegmentScope scope) { return QueryInterface.ofAddress(QueryInterface$get(segment), scope); @@ -203,7 +205,7 @@ public static QueryInterface QueryInterface(MemorySegment segment, SegmentScope Constants$root.C_POINTER$LAYOUT ); static final MethodHandle AddRef$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.AddRef$FUNC + IOUSBDeviceStruct187.AddRef$FUNC ); /** * {@snippet : @@ -214,13 +216,13 @@ public interface AddRef { int apply(java.lang.foreign.MemorySegment _x0); static MemorySegment allocate(AddRef fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(AddRef.class, fi, IOUSBDeviceStruct182.AddRef$FUNC, scope); + return RuntimeHelper.upcallStub(AddRef.class, fi, IOUSBDeviceStruct187.AddRef$FUNC, scope); } static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct182.AddRef$MH.invokeExact(symbol, __x0); + return (int)IOUSBDeviceStruct187.AddRef$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -230,7 +232,7 @@ static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle AddRef$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AddRef")); public static VarHandle AddRef$VH() { - return IOUSBDeviceStruct182.AddRef$VH; + return IOUSBDeviceStruct187.AddRef$VH; } /** * Getter for field: @@ -239,7 +241,7 @@ static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment AddRef$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.AddRef$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.AddRef$VH.get(seg); } /** * Setter for field: @@ -248,13 +250,13 @@ static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void AddRef$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.AddRef$VH.set(seg, x); + IOUSBDeviceStruct187.AddRef$VH.set(seg, x); } public static MemorySegment AddRef$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.AddRef$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.AddRef$VH.get(seg.asSlice(index*sizeof())); } public static void AddRef$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.AddRef$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.AddRef$VH.set(seg.asSlice(index*sizeof()), x); } public static AddRef AddRef(MemorySegment segment, SegmentScope scope) { return AddRef.ofAddress(AddRef$get(segment), scope); @@ -263,7 +265,7 @@ public static AddRef AddRef(MemorySegment segment, SegmentScope scope) { Constants$root.C_POINTER$LAYOUT ); static final MethodHandle Release$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.Release$FUNC + IOUSBDeviceStruct187.Release$FUNC ); /** * {@snippet : @@ -274,13 +276,13 @@ public interface Release { int apply(java.lang.foreign.MemorySegment _x0); static MemorySegment allocate(Release fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(Release.class, fi, IOUSBDeviceStruct182.Release$FUNC, scope); + return RuntimeHelper.upcallStub(Release.class, fi, IOUSBDeviceStruct187.Release$FUNC, scope); } static Release ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct182.Release$MH.invokeExact(symbol, __x0); + return (int)IOUSBDeviceStruct187.Release$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -290,7 +292,7 @@ static Release ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle Release$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Release")); public static VarHandle Release$VH() { - return IOUSBDeviceStruct182.Release$VH; + return IOUSBDeviceStruct187.Release$VH; } /** * Getter for field: @@ -299,7 +301,7 @@ static Release ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment Release$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.Release$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.Release$VH.get(seg); } /** * Setter for field: @@ -308,13 +310,13 @@ static Release ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void Release$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.Release$VH.set(seg, x); + IOUSBDeviceStruct187.Release$VH.set(seg, x); } public static MemorySegment Release$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.Release$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.Release$VH.get(seg.asSlice(index*sizeof())); } public static void Release$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.Release$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.Release$VH.set(seg.asSlice(index*sizeof()), x); } public static Release Release(MemorySegment segment, SegmentScope scope) { return Release.ofAddress(Release$get(segment), scope); @@ -324,7 +326,7 @@ public static Release Release(MemorySegment segment, SegmentScope scope) { Constants$root.C_POINTER$LAYOUT ); static final MethodHandle CreateDeviceAsyncEventSource$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.CreateDeviceAsyncEventSource$FUNC + IOUSBDeviceStruct187.CreateDeviceAsyncEventSource$FUNC ); /** * {@snippet : @@ -335,13 +337,13 @@ public interface CreateDeviceAsyncEventSource { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(CreateDeviceAsyncEventSource fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(CreateDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct182.CreateDeviceAsyncEventSource$FUNC, scope); + return RuntimeHelper.upcallStub(CreateDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct187.CreateDeviceAsyncEventSource$FUNC, scope); } static CreateDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.CreateDeviceAsyncEventSource$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.CreateDeviceAsyncEventSource$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -351,7 +353,7 @@ static CreateDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope s static final VarHandle CreateDeviceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateDeviceAsyncEventSource")); public static VarHandle CreateDeviceAsyncEventSource$VH() { - return IOUSBDeviceStruct182.CreateDeviceAsyncEventSource$VH; + return IOUSBDeviceStruct187.CreateDeviceAsyncEventSource$VH; } /** * Getter for field: @@ -360,7 +362,7 @@ static CreateDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope s * } */ public static MemorySegment CreateDeviceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.CreateDeviceAsyncEventSource$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.CreateDeviceAsyncEventSource$VH.get(seg); } /** * Setter for field: @@ -369,13 +371,13 @@ static CreateDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope s * } */ public static void CreateDeviceAsyncEventSource$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.CreateDeviceAsyncEventSource$VH.set(seg, x); + IOUSBDeviceStruct187.CreateDeviceAsyncEventSource$VH.set(seg, x); } public static MemorySegment CreateDeviceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.CreateDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.CreateDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); } public static void CreateDeviceAsyncEventSource$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.CreateDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.CreateDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); } public static CreateDeviceAsyncEventSource CreateDeviceAsyncEventSource(MemorySegment segment, SegmentScope scope) { return CreateDeviceAsyncEventSource.ofAddress(CreateDeviceAsyncEventSource$get(segment), scope); @@ -384,7 +386,7 @@ public static CreateDeviceAsyncEventSource CreateDeviceAsyncEventSource(MemorySe Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceAsyncEventSource$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.GetDeviceAsyncEventSource$FUNC + IOUSBDeviceStruct187.GetDeviceAsyncEventSource$FUNC ); /** * {@snippet : @@ -395,13 +397,13 @@ public interface GetDeviceAsyncEventSource { java.lang.foreign.MemorySegment apply(java.lang.foreign.MemorySegment _x0); static MemorySegment allocate(GetDeviceAsyncEventSource fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct182.GetDeviceAsyncEventSource$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct187.GetDeviceAsyncEventSource$FUNC, scope); } static GetDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceAsyncEventSource$MH.invokeExact(symbol, __x0); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceAsyncEventSource$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -411,7 +413,7 @@ static GetDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scop static final VarHandle GetDeviceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncEventSource")); public static VarHandle GetDeviceAsyncEventSource$VH() { - return IOUSBDeviceStruct182.GetDeviceAsyncEventSource$VH; + return IOUSBDeviceStruct187.GetDeviceAsyncEventSource$VH; } /** * Getter for field: @@ -420,7 +422,7 @@ static GetDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scop * } */ public static MemorySegment GetDeviceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceAsyncEventSource$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceAsyncEventSource$VH.get(seg); } /** * Setter for field: @@ -429,13 +431,13 @@ static GetDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scop * } */ public static void GetDeviceAsyncEventSource$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceAsyncEventSource$VH.set(seg, x); + IOUSBDeviceStruct187.GetDeviceAsyncEventSource$VH.set(seg, x); } public static MemorySegment GetDeviceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceAsyncEventSource$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.GetDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceAsyncEventSource GetDeviceAsyncEventSource(MemorySegment segment, SegmentScope scope) { return GetDeviceAsyncEventSource.ofAddress(GetDeviceAsyncEventSource$get(segment), scope); @@ -445,7 +447,7 @@ public static GetDeviceAsyncEventSource GetDeviceAsyncEventSource(MemorySegment Constants$root.C_POINTER$LAYOUT ); static final MethodHandle CreateDeviceAsyncPort$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.CreateDeviceAsyncPort$FUNC + IOUSBDeviceStruct187.CreateDeviceAsyncPort$FUNC ); /** * {@snippet : @@ -456,13 +458,13 @@ public interface CreateDeviceAsyncPort { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(CreateDeviceAsyncPort fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(CreateDeviceAsyncPort.class, fi, IOUSBDeviceStruct182.CreateDeviceAsyncPort$FUNC, scope); + return RuntimeHelper.upcallStub(CreateDeviceAsyncPort.class, fi, IOUSBDeviceStruct187.CreateDeviceAsyncPort$FUNC, scope); } static CreateDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.CreateDeviceAsyncPort$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.CreateDeviceAsyncPort$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -472,7 +474,7 @@ static CreateDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle CreateDeviceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateDeviceAsyncPort")); public static VarHandle CreateDeviceAsyncPort$VH() { - return IOUSBDeviceStruct182.CreateDeviceAsyncPort$VH; + return IOUSBDeviceStruct187.CreateDeviceAsyncPort$VH; } /** * Getter for field: @@ -481,7 +483,7 @@ static CreateDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment CreateDeviceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.CreateDeviceAsyncPort$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.CreateDeviceAsyncPort$VH.get(seg); } /** * Setter for field: @@ -490,13 +492,13 @@ static CreateDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void CreateDeviceAsyncPort$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.CreateDeviceAsyncPort$VH.set(seg, x); + IOUSBDeviceStruct187.CreateDeviceAsyncPort$VH.set(seg, x); } public static MemorySegment CreateDeviceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.CreateDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.CreateDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); } public static void CreateDeviceAsyncPort$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.CreateDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.CreateDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); } public static CreateDeviceAsyncPort CreateDeviceAsyncPort(MemorySegment segment, SegmentScope scope) { return CreateDeviceAsyncPort.ofAddress(CreateDeviceAsyncPort$get(segment), scope); @@ -505,7 +507,7 @@ public static CreateDeviceAsyncPort CreateDeviceAsyncPort(MemorySegment segment, Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceAsyncPort$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.GetDeviceAsyncPort$FUNC + IOUSBDeviceStruct187.GetDeviceAsyncPort$FUNC ); /** * {@snippet : @@ -516,13 +518,13 @@ public interface GetDeviceAsyncPort { int apply(java.lang.foreign.MemorySegment _x0); static MemorySegment allocate(GetDeviceAsyncPort fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceAsyncPort.class, fi, IOUSBDeviceStruct182.GetDeviceAsyncPort$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceAsyncPort.class, fi, IOUSBDeviceStruct187.GetDeviceAsyncPort$FUNC, scope); } static GetDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct182.GetDeviceAsyncPort$MH.invokeExact(symbol, __x0); + return (int)IOUSBDeviceStruct187.GetDeviceAsyncPort$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -532,7 +534,7 @@ static GetDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetDeviceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncPort")); public static VarHandle GetDeviceAsyncPort$VH() { - return IOUSBDeviceStruct182.GetDeviceAsyncPort$VH; + return IOUSBDeviceStruct187.GetDeviceAsyncPort$VH; } /** * Getter for field: @@ -541,7 +543,7 @@ static GetDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceAsyncPort$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceAsyncPort$VH.get(seg); } /** * Setter for field: @@ -550,13 +552,13 @@ static GetDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceAsyncPort$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceAsyncPort$VH.set(seg, x); + IOUSBDeviceStruct187.GetDeviceAsyncPort$VH.set(seg, x); } public static MemorySegment GetDeviceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceAsyncPort$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.GetDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceAsyncPort GetDeviceAsyncPort(MemorySegment segment, SegmentScope scope) { return GetDeviceAsyncPort.ofAddress(GetDeviceAsyncPort$get(segment), scope); @@ -565,7 +567,7 @@ public static GetDeviceAsyncPort GetDeviceAsyncPort(MemorySegment segment, Segme Constants$root.C_POINTER$LAYOUT ); static final MethodHandle USBDeviceOpen$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.USBDeviceOpen$FUNC + IOUSBDeviceStruct187.USBDeviceOpen$FUNC ); /** * {@snippet : @@ -576,13 +578,13 @@ public interface USBDeviceOpen { int apply(java.lang.foreign.MemorySegment _x0); static MemorySegment allocate(USBDeviceOpen fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBDeviceOpen.class, fi, IOUSBDeviceStruct182.USBDeviceOpen$FUNC, scope); + return RuntimeHelper.upcallStub(USBDeviceOpen.class, fi, IOUSBDeviceStruct187.USBDeviceOpen$FUNC, scope); } static USBDeviceOpen ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct182.USBDeviceOpen$MH.invokeExact(symbol, __x0); + return (int)IOUSBDeviceStruct187.USBDeviceOpen$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -592,7 +594,7 @@ static USBDeviceOpen ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle USBDeviceOpen$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceOpen")); public static VarHandle USBDeviceOpen$VH() { - return IOUSBDeviceStruct182.USBDeviceOpen$VH; + return IOUSBDeviceStruct187.USBDeviceOpen$VH; } /** * Getter for field: @@ -601,7 +603,7 @@ static USBDeviceOpen ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment USBDeviceOpen$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceOpen$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceOpen$VH.get(seg); } /** * Setter for field: @@ -610,13 +612,13 @@ static USBDeviceOpen ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void USBDeviceOpen$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.USBDeviceOpen$VH.set(seg, x); + IOUSBDeviceStruct187.USBDeviceOpen$VH.set(seg, x); } public static MemorySegment USBDeviceOpen$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceOpen$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceOpen$VH.get(seg.asSlice(index*sizeof())); } public static void USBDeviceOpen$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.USBDeviceOpen$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.USBDeviceOpen$VH.set(seg.asSlice(index*sizeof()), x); } public static USBDeviceOpen USBDeviceOpen(MemorySegment segment, SegmentScope scope) { return USBDeviceOpen.ofAddress(USBDeviceOpen$get(segment), scope); @@ -625,7 +627,7 @@ public static USBDeviceOpen USBDeviceOpen(MemorySegment segment, SegmentScope sc Constants$root.C_POINTER$LAYOUT ); static final MethodHandle USBDeviceClose$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.USBDeviceClose$FUNC + IOUSBDeviceStruct187.USBDeviceClose$FUNC ); /** * {@snippet : @@ -636,13 +638,13 @@ public interface USBDeviceClose { int apply(java.lang.foreign.MemorySegment _x0); static MemorySegment allocate(USBDeviceClose fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBDeviceClose.class, fi, IOUSBDeviceStruct182.USBDeviceClose$FUNC, scope); + return RuntimeHelper.upcallStub(USBDeviceClose.class, fi, IOUSBDeviceStruct187.USBDeviceClose$FUNC, scope); } static USBDeviceClose ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct182.USBDeviceClose$MH.invokeExact(symbol, __x0); + return (int)IOUSBDeviceStruct187.USBDeviceClose$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -652,7 +654,7 @@ static USBDeviceClose ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle USBDeviceClose$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceClose")); public static VarHandle USBDeviceClose$VH() { - return IOUSBDeviceStruct182.USBDeviceClose$VH; + return IOUSBDeviceStruct187.USBDeviceClose$VH; } /** * Getter for field: @@ -661,7 +663,7 @@ static USBDeviceClose ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment USBDeviceClose$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceClose$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceClose$VH.get(seg); } /** * Setter for field: @@ -670,13 +672,13 @@ static USBDeviceClose ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void USBDeviceClose$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.USBDeviceClose$VH.set(seg, x); + IOUSBDeviceStruct187.USBDeviceClose$VH.set(seg, x); } public static MemorySegment USBDeviceClose$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceClose$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceClose$VH.get(seg.asSlice(index*sizeof())); } public static void USBDeviceClose$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.USBDeviceClose$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.USBDeviceClose$VH.set(seg.asSlice(index*sizeof()), x); } public static USBDeviceClose USBDeviceClose(MemorySegment segment, SegmentScope scope) { return USBDeviceClose.ofAddress(USBDeviceClose$get(segment), scope); @@ -686,7 +688,7 @@ public static USBDeviceClose USBDeviceClose(MemorySegment segment, SegmentScope Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceClass$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.GetDeviceClass$FUNC + IOUSBDeviceStruct187.GetDeviceClass$FUNC ); /** * {@snippet : @@ -697,13 +699,13 @@ public interface GetDeviceClass { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceClass fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceClass.class, fi, IOUSBDeviceStruct182.GetDeviceClass$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceClass.class, fi, IOUSBDeviceStruct187.GetDeviceClass$FUNC, scope); } static GetDeviceClass ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.GetDeviceClass$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.GetDeviceClass$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -713,7 +715,7 @@ static GetDeviceClass ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetDeviceClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceClass")); public static VarHandle GetDeviceClass$VH() { - return IOUSBDeviceStruct182.GetDeviceClass$VH; + return IOUSBDeviceStruct187.GetDeviceClass$VH; } /** * Getter for field: @@ -722,7 +724,7 @@ static GetDeviceClass ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceClass$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceClass$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceClass$VH.get(seg); } /** * Setter for field: @@ -731,13 +733,13 @@ static GetDeviceClass ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceClass$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceClass$VH.set(seg, x); + IOUSBDeviceStruct187.GetDeviceClass$VH.set(seg, x); } public static MemorySegment GetDeviceClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceClass$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceClass$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceClass$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceClass$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.GetDeviceClass$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceClass GetDeviceClass(MemorySegment segment, SegmentScope scope) { return GetDeviceClass.ofAddress(GetDeviceClass$get(segment), scope); @@ -747,7 +749,7 @@ public static GetDeviceClass GetDeviceClass(MemorySegment segment, SegmentScope Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceSubClass$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.GetDeviceSubClass$FUNC + IOUSBDeviceStruct187.GetDeviceSubClass$FUNC ); /** * {@snippet : @@ -758,13 +760,13 @@ public interface GetDeviceSubClass { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceSubClass fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceSubClass.class, fi, IOUSBDeviceStruct182.GetDeviceSubClass$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceSubClass.class, fi, IOUSBDeviceStruct187.GetDeviceSubClass$FUNC, scope); } static GetDeviceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.GetDeviceSubClass$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.GetDeviceSubClass$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -774,7 +776,7 @@ static GetDeviceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetDeviceSubClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceSubClass")); public static VarHandle GetDeviceSubClass$VH() { - return IOUSBDeviceStruct182.GetDeviceSubClass$VH; + return IOUSBDeviceStruct187.GetDeviceSubClass$VH; } /** * Getter for field: @@ -783,7 +785,7 @@ static GetDeviceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceSubClass$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceSubClass$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceSubClass$VH.get(seg); } /** * Setter for field: @@ -792,13 +794,13 @@ static GetDeviceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceSubClass$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceSubClass$VH.set(seg, x); + IOUSBDeviceStruct187.GetDeviceSubClass$VH.set(seg, x); } public static MemorySegment GetDeviceSubClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceSubClass$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceSubClass$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceSubClass$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceSubClass$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.GetDeviceSubClass$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceSubClass GetDeviceSubClass(MemorySegment segment, SegmentScope scope) { return GetDeviceSubClass.ofAddress(GetDeviceSubClass$get(segment), scope); @@ -808,7 +810,7 @@ public static GetDeviceSubClass GetDeviceSubClass(MemorySegment segment, Segment Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceProtocol$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.GetDeviceProtocol$FUNC + IOUSBDeviceStruct187.GetDeviceProtocol$FUNC ); /** * {@snippet : @@ -819,13 +821,13 @@ public interface GetDeviceProtocol { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceProtocol fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceProtocol.class, fi, IOUSBDeviceStruct182.GetDeviceProtocol$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceProtocol.class, fi, IOUSBDeviceStruct187.GetDeviceProtocol$FUNC, scope); } static GetDeviceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.GetDeviceProtocol$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.GetDeviceProtocol$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -835,7 +837,7 @@ static GetDeviceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetDeviceProtocol$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProtocol")); public static VarHandle GetDeviceProtocol$VH() { - return IOUSBDeviceStruct182.GetDeviceProtocol$VH; + return IOUSBDeviceStruct187.GetDeviceProtocol$VH; } /** * Getter for field: @@ -844,7 +846,7 @@ static GetDeviceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceProtocol$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceProtocol$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceProtocol$VH.get(seg); } /** * Setter for field: @@ -853,13 +855,13 @@ static GetDeviceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceProtocol$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceProtocol$VH.set(seg, x); + IOUSBDeviceStruct187.GetDeviceProtocol$VH.set(seg, x); } public static MemorySegment GetDeviceProtocol$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceProtocol$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceProtocol$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceProtocol$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceProtocol$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.GetDeviceProtocol$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceProtocol GetDeviceProtocol(MemorySegment segment, SegmentScope scope) { return GetDeviceProtocol.ofAddress(GetDeviceProtocol$get(segment), scope); @@ -869,7 +871,7 @@ public static GetDeviceProtocol GetDeviceProtocol(MemorySegment segment, Segment Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceVendor$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.GetDeviceVendor$FUNC + IOUSBDeviceStruct187.GetDeviceVendor$FUNC ); /** * {@snippet : @@ -880,13 +882,13 @@ public interface GetDeviceVendor { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceVendor fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceVendor.class, fi, IOUSBDeviceStruct182.GetDeviceVendor$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceVendor.class, fi, IOUSBDeviceStruct187.GetDeviceVendor$FUNC, scope); } static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.GetDeviceVendor$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.GetDeviceVendor$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -896,7 +898,7 @@ static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetDeviceVendor$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceVendor")); public static VarHandle GetDeviceVendor$VH() { - return IOUSBDeviceStruct182.GetDeviceVendor$VH; + return IOUSBDeviceStruct187.GetDeviceVendor$VH; } /** * Getter for field: @@ -905,7 +907,7 @@ static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceVendor$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceVendor$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceVendor$VH.get(seg); } /** * Setter for field: @@ -914,13 +916,13 @@ static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceVendor$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceVendor$VH.set(seg, x); + IOUSBDeviceStruct187.GetDeviceVendor$VH.set(seg, x); } public static MemorySegment GetDeviceVendor$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceVendor$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceVendor$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceVendor$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceVendor$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.GetDeviceVendor$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceVendor GetDeviceVendor(MemorySegment segment, SegmentScope scope) { return GetDeviceVendor.ofAddress(GetDeviceVendor$get(segment), scope); @@ -930,7 +932,7 @@ public static GetDeviceVendor GetDeviceVendor(MemorySegment segment, SegmentScop Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceProduct$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.GetDeviceProduct$FUNC + IOUSBDeviceStruct187.GetDeviceProduct$FUNC ); /** * {@snippet : @@ -941,13 +943,13 @@ public interface GetDeviceProduct { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceProduct fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceProduct.class, fi, IOUSBDeviceStruct182.GetDeviceProduct$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceProduct.class, fi, IOUSBDeviceStruct187.GetDeviceProduct$FUNC, scope); } static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.GetDeviceProduct$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.GetDeviceProduct$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -957,7 +959,7 @@ static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetDeviceProduct$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProduct")); public static VarHandle GetDeviceProduct$VH() { - return IOUSBDeviceStruct182.GetDeviceProduct$VH; + return IOUSBDeviceStruct187.GetDeviceProduct$VH; } /** * Getter for field: @@ -966,7 +968,7 @@ static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceProduct$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceProduct$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceProduct$VH.get(seg); } /** * Setter for field: @@ -975,13 +977,13 @@ static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceProduct$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceProduct$VH.set(seg, x); + IOUSBDeviceStruct187.GetDeviceProduct$VH.set(seg, x); } public static MemorySegment GetDeviceProduct$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceProduct$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceProduct$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceProduct$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceProduct$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.GetDeviceProduct$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceProduct GetDeviceProduct(MemorySegment segment, SegmentScope scope) { return GetDeviceProduct.ofAddress(GetDeviceProduct$get(segment), scope); @@ -991,7 +993,7 @@ public static GetDeviceProduct GetDeviceProduct(MemorySegment segment, SegmentSc Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceReleaseNumber$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.GetDeviceReleaseNumber$FUNC + IOUSBDeviceStruct187.GetDeviceReleaseNumber$FUNC ); /** * {@snippet : @@ -1002,13 +1004,13 @@ public interface GetDeviceReleaseNumber { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceReleaseNumber fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceReleaseNumber.class, fi, IOUSBDeviceStruct182.GetDeviceReleaseNumber$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceReleaseNumber.class, fi, IOUSBDeviceStruct187.GetDeviceReleaseNumber$FUNC, scope); } static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.GetDeviceReleaseNumber$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.GetDeviceReleaseNumber$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1018,7 +1020,7 @@ static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) static final VarHandle GetDeviceReleaseNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceReleaseNumber")); public static VarHandle GetDeviceReleaseNumber$VH() { - return IOUSBDeviceStruct182.GetDeviceReleaseNumber$VH; + return IOUSBDeviceStruct187.GetDeviceReleaseNumber$VH; } /** * Getter for field: @@ -1027,7 +1029,7 @@ static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static MemorySegment GetDeviceReleaseNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceReleaseNumber$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceReleaseNumber$VH.get(seg); } /** * Setter for field: @@ -1036,13 +1038,13 @@ static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static void GetDeviceReleaseNumber$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceReleaseNumber$VH.set(seg, x); + IOUSBDeviceStruct187.GetDeviceReleaseNumber$VH.set(seg, x); } public static MemorySegment GetDeviceReleaseNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceReleaseNumber$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceReleaseNumber$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceReleaseNumber$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceReleaseNumber$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.GetDeviceReleaseNumber$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceReleaseNumber GetDeviceReleaseNumber(MemorySegment segment, SegmentScope scope) { return GetDeviceReleaseNumber.ofAddress(GetDeviceReleaseNumber$get(segment), scope); @@ -1052,7 +1054,7 @@ public static GetDeviceReleaseNumber GetDeviceReleaseNumber(MemorySegment segmen Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceAddress$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.GetDeviceAddress$FUNC + IOUSBDeviceStruct187.GetDeviceAddress$FUNC ); /** * {@snippet : @@ -1063,13 +1065,13 @@ public interface GetDeviceAddress { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceAddress fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceAddress.class, fi, IOUSBDeviceStruct182.GetDeviceAddress$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceAddress.class, fi, IOUSBDeviceStruct187.GetDeviceAddress$FUNC, scope); } static GetDeviceAddress ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.GetDeviceAddress$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.GetDeviceAddress$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1079,7 +1081,7 @@ static GetDeviceAddress ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetDeviceAddress$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAddress")); public static VarHandle GetDeviceAddress$VH() { - return IOUSBDeviceStruct182.GetDeviceAddress$VH; + return IOUSBDeviceStruct187.GetDeviceAddress$VH; } /** * Getter for field: @@ -1088,7 +1090,7 @@ static GetDeviceAddress ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceAddress$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceAddress$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceAddress$VH.get(seg); } /** * Setter for field: @@ -1097,13 +1099,13 @@ static GetDeviceAddress ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceAddress$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceAddress$VH.set(seg, x); + IOUSBDeviceStruct187.GetDeviceAddress$VH.set(seg, x); } public static MemorySegment GetDeviceAddress$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceAddress$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceAddress$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceAddress$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceAddress$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.GetDeviceAddress$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceAddress GetDeviceAddress(MemorySegment segment, SegmentScope scope) { return GetDeviceAddress.ofAddress(GetDeviceAddress$get(segment), scope); @@ -1113,7 +1115,7 @@ public static GetDeviceAddress GetDeviceAddress(MemorySegment segment, SegmentSc Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceBusPowerAvailable$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.GetDeviceBusPowerAvailable$FUNC + IOUSBDeviceStruct187.GetDeviceBusPowerAvailable$FUNC ); /** * {@snippet : @@ -1124,13 +1126,13 @@ public interface GetDeviceBusPowerAvailable { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceBusPowerAvailable fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceBusPowerAvailable.class, fi, IOUSBDeviceStruct182.GetDeviceBusPowerAvailable$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceBusPowerAvailable.class, fi, IOUSBDeviceStruct187.GetDeviceBusPowerAvailable$FUNC, scope); } static GetDeviceBusPowerAvailable ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.GetDeviceBusPowerAvailable$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.GetDeviceBusPowerAvailable$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1140,7 +1142,7 @@ static GetDeviceBusPowerAvailable ofAddress(MemorySegment addr, SegmentScope sco static final VarHandle GetDeviceBusPowerAvailable$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceBusPowerAvailable")); public static VarHandle GetDeviceBusPowerAvailable$VH() { - return IOUSBDeviceStruct182.GetDeviceBusPowerAvailable$VH; + return IOUSBDeviceStruct187.GetDeviceBusPowerAvailable$VH; } /** * Getter for field: @@ -1149,7 +1151,7 @@ static GetDeviceBusPowerAvailable ofAddress(MemorySegment addr, SegmentScope sco * } */ public static MemorySegment GetDeviceBusPowerAvailable$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceBusPowerAvailable$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceBusPowerAvailable$VH.get(seg); } /** * Setter for field: @@ -1158,13 +1160,13 @@ static GetDeviceBusPowerAvailable ofAddress(MemorySegment addr, SegmentScope sco * } */ public static void GetDeviceBusPowerAvailable$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceBusPowerAvailable$VH.set(seg, x); + IOUSBDeviceStruct187.GetDeviceBusPowerAvailable$VH.set(seg, x); } public static MemorySegment GetDeviceBusPowerAvailable$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceBusPowerAvailable$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceBusPowerAvailable$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceBusPowerAvailable$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceBusPowerAvailable$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.GetDeviceBusPowerAvailable$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceBusPowerAvailable GetDeviceBusPowerAvailable(MemorySegment segment, SegmentScope scope) { return GetDeviceBusPowerAvailable.ofAddress(GetDeviceBusPowerAvailable$get(segment), scope); @@ -1174,7 +1176,7 @@ public static GetDeviceBusPowerAvailable GetDeviceBusPowerAvailable(MemorySegmen Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetDeviceSpeed$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.GetDeviceSpeed$FUNC + IOUSBDeviceStruct187.GetDeviceSpeed$FUNC ); /** * {@snippet : @@ -1185,13 +1187,13 @@ public interface GetDeviceSpeed { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetDeviceSpeed fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceSpeed.class, fi, IOUSBDeviceStruct182.GetDeviceSpeed$FUNC, scope); + return RuntimeHelper.upcallStub(GetDeviceSpeed.class, fi, IOUSBDeviceStruct187.GetDeviceSpeed$FUNC, scope); } static GetDeviceSpeed ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.GetDeviceSpeed$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.GetDeviceSpeed$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1201,7 +1203,7 @@ static GetDeviceSpeed ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetDeviceSpeed$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceSpeed")); public static VarHandle GetDeviceSpeed$VH() { - return IOUSBDeviceStruct182.GetDeviceSpeed$VH; + return IOUSBDeviceStruct187.GetDeviceSpeed$VH; } /** * Getter for field: @@ -1210,7 +1212,7 @@ static GetDeviceSpeed ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceSpeed$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceSpeed$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceSpeed$VH.get(seg); } /** * Setter for field: @@ -1219,13 +1221,13 @@ static GetDeviceSpeed ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceSpeed$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceSpeed$VH.set(seg, x); + IOUSBDeviceStruct187.GetDeviceSpeed$VH.set(seg, x); } public static MemorySegment GetDeviceSpeed$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetDeviceSpeed$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceSpeed$VH.get(seg.asSlice(index*sizeof())); } public static void GetDeviceSpeed$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.GetDeviceSpeed$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.GetDeviceSpeed$VH.set(seg.asSlice(index*sizeof()), x); } public static GetDeviceSpeed GetDeviceSpeed(MemorySegment segment, SegmentScope scope) { return GetDeviceSpeed.ofAddress(GetDeviceSpeed$get(segment), scope); @@ -1235,7 +1237,7 @@ public static GetDeviceSpeed GetDeviceSpeed(MemorySegment segment, SegmentScope Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetNumberOfConfigurations$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.GetNumberOfConfigurations$FUNC + IOUSBDeviceStruct187.GetNumberOfConfigurations$FUNC ); /** * {@snippet : @@ -1246,13 +1248,13 @@ public interface GetNumberOfConfigurations { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetNumberOfConfigurations fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetNumberOfConfigurations.class, fi, IOUSBDeviceStruct182.GetNumberOfConfigurations$FUNC, scope); + return RuntimeHelper.upcallStub(GetNumberOfConfigurations.class, fi, IOUSBDeviceStruct187.GetNumberOfConfigurations$FUNC, scope); } static GetNumberOfConfigurations ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.GetNumberOfConfigurations$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.GetNumberOfConfigurations$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1262,7 +1264,7 @@ static GetNumberOfConfigurations ofAddress(MemorySegment addr, SegmentScope scop static final VarHandle GetNumberOfConfigurations$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetNumberOfConfigurations")); public static VarHandle GetNumberOfConfigurations$VH() { - return IOUSBDeviceStruct182.GetNumberOfConfigurations$VH; + return IOUSBDeviceStruct187.GetNumberOfConfigurations$VH; } /** * Getter for field: @@ -1271,7 +1273,7 @@ static GetNumberOfConfigurations ofAddress(MemorySegment addr, SegmentScope scop * } */ public static MemorySegment GetNumberOfConfigurations$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetNumberOfConfigurations$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetNumberOfConfigurations$VH.get(seg); } /** * Setter for field: @@ -1280,13 +1282,13 @@ static GetNumberOfConfigurations ofAddress(MemorySegment addr, SegmentScope scop * } */ public static void GetNumberOfConfigurations$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.GetNumberOfConfigurations$VH.set(seg, x); + IOUSBDeviceStruct187.GetNumberOfConfigurations$VH.set(seg, x); } public static MemorySegment GetNumberOfConfigurations$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetNumberOfConfigurations$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetNumberOfConfigurations$VH.get(seg.asSlice(index*sizeof())); } public static void GetNumberOfConfigurations$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.GetNumberOfConfigurations$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.GetNumberOfConfigurations$VH.set(seg.asSlice(index*sizeof()), x); } public static GetNumberOfConfigurations GetNumberOfConfigurations(MemorySegment segment, SegmentScope scope) { return GetNumberOfConfigurations.ofAddress(GetNumberOfConfigurations$get(segment), scope); @@ -1296,7 +1298,7 @@ public static GetNumberOfConfigurations GetNumberOfConfigurations(MemorySegment Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetLocationID$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.GetLocationID$FUNC + IOUSBDeviceStruct187.GetLocationID$FUNC ); /** * {@snippet : @@ -1307,13 +1309,13 @@ public interface GetLocationID { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetLocationID fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetLocationID.class, fi, IOUSBDeviceStruct182.GetLocationID$FUNC, scope); + return RuntimeHelper.upcallStub(GetLocationID.class, fi, IOUSBDeviceStruct187.GetLocationID$FUNC, scope); } static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.GetLocationID$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.GetLocationID$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1323,7 +1325,7 @@ static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetLocationID$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetLocationID")); public static VarHandle GetLocationID$VH() { - return IOUSBDeviceStruct182.GetLocationID$VH; + return IOUSBDeviceStruct187.GetLocationID$VH; } /** * Getter for field: @@ -1332,7 +1334,7 @@ static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetLocationID$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetLocationID$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetLocationID$VH.get(seg); } /** * Setter for field: @@ -1341,13 +1343,13 @@ static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetLocationID$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.GetLocationID$VH.set(seg, x); + IOUSBDeviceStruct187.GetLocationID$VH.set(seg, x); } public static MemorySegment GetLocationID$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetLocationID$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetLocationID$VH.get(seg.asSlice(index*sizeof())); } public static void GetLocationID$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.GetLocationID$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.GetLocationID$VH.set(seg.asSlice(index*sizeof()), x); } public static GetLocationID GetLocationID(MemorySegment segment, SegmentScope scope) { return GetLocationID.ofAddress(GetLocationID$get(segment), scope); @@ -1358,7 +1360,7 @@ public static GetLocationID GetLocationID(MemorySegment segment, SegmentScope sc Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetConfigurationDescriptorPtr$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.GetConfigurationDescriptorPtr$FUNC + IOUSBDeviceStruct187.GetConfigurationDescriptorPtr$FUNC ); /** * {@snippet : @@ -1369,13 +1371,13 @@ public interface GetConfigurationDescriptorPtr { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2); static MemorySegment allocate(GetConfigurationDescriptorPtr fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetConfigurationDescriptorPtr.class, fi, IOUSBDeviceStruct182.GetConfigurationDescriptorPtr$FUNC, scope); + return RuntimeHelper.upcallStub(GetConfigurationDescriptorPtr.class, fi, IOUSBDeviceStruct187.GetConfigurationDescriptorPtr$FUNC, scope); } static GetConfigurationDescriptorPtr ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBDeviceStruct182.GetConfigurationDescriptorPtr$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)IOUSBDeviceStruct187.GetConfigurationDescriptorPtr$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1385,7 +1387,7 @@ static GetConfigurationDescriptorPtr ofAddress(MemorySegment addr, SegmentScope static final VarHandle GetConfigurationDescriptorPtr$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetConfigurationDescriptorPtr")); public static VarHandle GetConfigurationDescriptorPtr$VH() { - return IOUSBDeviceStruct182.GetConfigurationDescriptorPtr$VH; + return IOUSBDeviceStruct187.GetConfigurationDescriptorPtr$VH; } /** * Getter for field: @@ -1394,7 +1396,7 @@ static GetConfigurationDescriptorPtr ofAddress(MemorySegment addr, SegmentScope * } */ public static MemorySegment GetConfigurationDescriptorPtr$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetConfigurationDescriptorPtr$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetConfigurationDescriptorPtr$VH.get(seg); } /** * Setter for field: @@ -1403,13 +1405,13 @@ static GetConfigurationDescriptorPtr ofAddress(MemorySegment addr, SegmentScope * } */ public static void GetConfigurationDescriptorPtr$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.GetConfigurationDescriptorPtr$VH.set(seg, x); + IOUSBDeviceStruct187.GetConfigurationDescriptorPtr$VH.set(seg, x); } public static MemorySegment GetConfigurationDescriptorPtr$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetConfigurationDescriptorPtr$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetConfigurationDescriptorPtr$VH.get(seg.asSlice(index*sizeof())); } public static void GetConfigurationDescriptorPtr$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.GetConfigurationDescriptorPtr$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.GetConfigurationDescriptorPtr$VH.set(seg.asSlice(index*sizeof()), x); } public static GetConfigurationDescriptorPtr GetConfigurationDescriptorPtr(MemorySegment segment, SegmentScope scope) { return GetConfigurationDescriptorPtr.ofAddress(GetConfigurationDescriptorPtr$get(segment), scope); @@ -1419,7 +1421,7 @@ public static GetConfigurationDescriptorPtr GetConfigurationDescriptorPtr(Memory Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetConfiguration$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.GetConfiguration$FUNC + IOUSBDeviceStruct187.GetConfiguration$FUNC ); /** * {@snippet : @@ -1430,13 +1432,13 @@ public interface GetConfiguration { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(GetConfiguration fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetConfiguration.class, fi, IOUSBDeviceStruct182.GetConfiguration$FUNC, scope); + return RuntimeHelper.upcallStub(GetConfiguration.class, fi, IOUSBDeviceStruct187.GetConfiguration$FUNC, scope); } static GetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.GetConfiguration$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.GetConfiguration$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1446,7 +1448,7 @@ static GetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetConfiguration$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetConfiguration")); public static VarHandle GetConfiguration$VH() { - return IOUSBDeviceStruct182.GetConfiguration$VH; + return IOUSBDeviceStruct187.GetConfiguration$VH; } /** * Getter for field: @@ -1455,7 +1457,7 @@ static GetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetConfiguration$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetConfiguration$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetConfiguration$VH.get(seg); } /** * Setter for field: @@ -1464,13 +1466,13 @@ static GetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetConfiguration$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.GetConfiguration$VH.set(seg, x); + IOUSBDeviceStruct187.GetConfiguration$VH.set(seg, x); } public static MemorySegment GetConfiguration$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetConfiguration$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetConfiguration$VH.get(seg.asSlice(index*sizeof())); } public static void GetConfiguration$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.GetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.GetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); } public static GetConfiguration GetConfiguration(MemorySegment segment, SegmentScope scope) { return GetConfiguration.ofAddress(GetConfiguration$get(segment), scope); @@ -1480,7 +1482,7 @@ public static GetConfiguration GetConfiguration(MemorySegment segment, SegmentSc Constants$root.C_CHAR$LAYOUT ); static final MethodHandle SetConfiguration$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.SetConfiguration$FUNC + IOUSBDeviceStruct187.SetConfiguration$FUNC ); /** * {@snippet : @@ -1491,13 +1493,13 @@ public interface SetConfiguration { int apply(java.lang.foreign.MemorySegment _x0, byte _x1); static MemorySegment allocate(SetConfiguration fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(SetConfiguration.class, fi, IOUSBDeviceStruct182.SetConfiguration$FUNC, scope); + return RuntimeHelper.upcallStub(SetConfiguration.class, fi, IOUSBDeviceStruct187.SetConfiguration$FUNC, scope); } static SetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBDeviceStruct182.SetConfiguration$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.SetConfiguration$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1507,7 +1509,7 @@ static SetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle SetConfiguration$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetConfiguration")); public static VarHandle SetConfiguration$VH() { - return IOUSBDeviceStruct182.SetConfiguration$VH; + return IOUSBDeviceStruct187.SetConfiguration$VH; } /** * Getter for field: @@ -1516,7 +1518,7 @@ static SetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment SetConfiguration$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.SetConfiguration$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.SetConfiguration$VH.get(seg); } /** * Setter for field: @@ -1525,13 +1527,13 @@ static SetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void SetConfiguration$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.SetConfiguration$VH.set(seg, x); + IOUSBDeviceStruct187.SetConfiguration$VH.set(seg, x); } public static MemorySegment SetConfiguration$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.SetConfiguration$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.SetConfiguration$VH.get(seg.asSlice(index*sizeof())); } public static void SetConfiguration$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.SetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.SetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); } public static SetConfiguration SetConfiguration(MemorySegment segment, SegmentScope scope) { return SetConfiguration.ofAddress(SetConfiguration$get(segment), scope); @@ -1542,7 +1544,7 @@ public static SetConfiguration SetConfiguration(MemorySegment segment, SegmentSc Constants$root.C_POINTER$LAYOUT ); static final MethodHandle GetBusFrameNumber$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.GetBusFrameNumber$FUNC + IOUSBDeviceStruct187.GetBusFrameNumber$FUNC ); /** * {@snippet : @@ -1553,13 +1555,13 @@ public interface GetBusFrameNumber { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); static MemorySegment allocate(GetBusFrameNumber fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetBusFrameNumber.class, fi, IOUSBDeviceStruct182.GetBusFrameNumber$FUNC, scope); + return RuntimeHelper.upcallStub(GetBusFrameNumber.class, fi, IOUSBDeviceStruct187.GetBusFrameNumber$FUNC, scope); } static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBDeviceStruct182.GetBusFrameNumber$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)IOUSBDeviceStruct187.GetBusFrameNumber$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1569,7 +1571,7 @@ static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle GetBusFrameNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBusFrameNumber")); public static VarHandle GetBusFrameNumber$VH() { - return IOUSBDeviceStruct182.GetBusFrameNumber$VH; + return IOUSBDeviceStruct187.GetBusFrameNumber$VH; } /** * Getter for field: @@ -1578,7 +1580,7 @@ static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetBusFrameNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetBusFrameNumber$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetBusFrameNumber$VH.get(seg); } /** * Setter for field: @@ -1587,13 +1589,13 @@ static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetBusFrameNumber$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.GetBusFrameNumber$VH.set(seg, x); + IOUSBDeviceStruct187.GetBusFrameNumber$VH.set(seg, x); } public static MemorySegment GetBusFrameNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.GetBusFrameNumber$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetBusFrameNumber$VH.get(seg.asSlice(index*sizeof())); } public static void GetBusFrameNumber$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.GetBusFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.GetBusFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); } public static GetBusFrameNumber GetBusFrameNumber(MemorySegment segment, SegmentScope scope) { return GetBusFrameNumber.ofAddress(GetBusFrameNumber$get(segment), scope); @@ -1602,7 +1604,7 @@ public static GetBusFrameNumber GetBusFrameNumber(MemorySegment segment, Segment Constants$root.C_POINTER$LAYOUT ); static final MethodHandle ResetDevice$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.ResetDevice$FUNC + IOUSBDeviceStruct187.ResetDevice$FUNC ); /** * {@snippet : @@ -1613,13 +1615,13 @@ public interface ResetDevice { int apply(java.lang.foreign.MemorySegment _x0); static MemorySegment allocate(ResetDevice fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(ResetDevice.class, fi, IOUSBDeviceStruct182.ResetDevice$FUNC, scope); + return RuntimeHelper.upcallStub(ResetDevice.class, fi, IOUSBDeviceStruct187.ResetDevice$FUNC, scope); } static ResetDevice ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct182.ResetDevice$MH.invokeExact(symbol, __x0); + return (int)IOUSBDeviceStruct187.ResetDevice$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1629,7 +1631,7 @@ static ResetDevice ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle ResetDevice$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ResetDevice")); public static VarHandle ResetDevice$VH() { - return IOUSBDeviceStruct182.ResetDevice$VH; + return IOUSBDeviceStruct187.ResetDevice$VH; } /** * Getter for field: @@ -1638,7 +1640,7 @@ static ResetDevice ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment ResetDevice$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.ResetDevice$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.ResetDevice$VH.get(seg); } /** * Setter for field: @@ -1647,13 +1649,13 @@ static ResetDevice ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void ResetDevice$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.ResetDevice$VH.set(seg, x); + IOUSBDeviceStruct187.ResetDevice$VH.set(seg, x); } public static MemorySegment ResetDevice$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.ResetDevice$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.ResetDevice$VH.get(seg.asSlice(index*sizeof())); } public static void ResetDevice$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.ResetDevice$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.ResetDevice$VH.set(seg.asSlice(index*sizeof()), x); } public static ResetDevice ResetDevice(MemorySegment segment, SegmentScope scope) { return ResetDevice.ofAddress(ResetDevice$get(segment), scope); @@ -1663,7 +1665,7 @@ public static ResetDevice ResetDevice(MemorySegment segment, SegmentScope scope) Constants$root.C_POINTER$LAYOUT ); static final MethodHandle DeviceRequest$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.DeviceRequest$FUNC + IOUSBDeviceStruct187.DeviceRequest$FUNC ); /** * {@snippet : @@ -1674,13 +1676,13 @@ public interface DeviceRequest { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(DeviceRequest fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(DeviceRequest.class, fi, IOUSBDeviceStruct182.DeviceRequest$FUNC, scope); + return RuntimeHelper.upcallStub(DeviceRequest.class, fi, IOUSBDeviceStruct187.DeviceRequest$FUNC, scope); } static DeviceRequest ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.DeviceRequest$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.DeviceRequest$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1690,7 +1692,7 @@ static DeviceRequest ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle DeviceRequest$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequest")); public static VarHandle DeviceRequest$VH() { - return IOUSBDeviceStruct182.DeviceRequest$VH; + return IOUSBDeviceStruct187.DeviceRequest$VH; } /** * Getter for field: @@ -1699,7 +1701,7 @@ static DeviceRequest ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment DeviceRequest$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.DeviceRequest$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.DeviceRequest$VH.get(seg); } /** * Setter for field: @@ -1708,13 +1710,13 @@ static DeviceRequest ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void DeviceRequest$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.DeviceRequest$VH.set(seg, x); + IOUSBDeviceStruct187.DeviceRequest$VH.set(seg, x); } public static MemorySegment DeviceRequest$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.DeviceRequest$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.DeviceRequest$VH.get(seg.asSlice(index*sizeof())); } public static void DeviceRequest$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.DeviceRequest$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.DeviceRequest$VH.set(seg.asSlice(index*sizeof()), x); } public static DeviceRequest DeviceRequest(MemorySegment segment, SegmentScope scope) { return DeviceRequest.ofAddress(DeviceRequest$get(segment), scope); @@ -1726,7 +1728,7 @@ public static DeviceRequest DeviceRequest(MemorySegment segment, SegmentScope sc Constants$root.C_POINTER$LAYOUT ); static final MethodHandle DeviceRequestAsync$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.DeviceRequestAsync$FUNC + IOUSBDeviceStruct187.DeviceRequestAsync$FUNC ); /** * {@snippet : @@ -1737,13 +1739,13 @@ public interface DeviceRequestAsync { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3); static MemorySegment allocate(DeviceRequestAsync fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(DeviceRequestAsync.class, fi, IOUSBDeviceStruct182.DeviceRequestAsync$FUNC, scope); + return RuntimeHelper.upcallStub(DeviceRequestAsync.class, fi, IOUSBDeviceStruct187.DeviceRequestAsync$FUNC, scope); } static DeviceRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3) -> { try { - return (int)IOUSBDeviceStruct182.DeviceRequestAsync$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); + return (int)IOUSBDeviceStruct187.DeviceRequestAsync$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1753,7 +1755,7 @@ static DeviceRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle DeviceRequestAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestAsync")); public static VarHandle DeviceRequestAsync$VH() { - return IOUSBDeviceStruct182.DeviceRequestAsync$VH; + return IOUSBDeviceStruct187.DeviceRequestAsync$VH; } /** * Getter for field: @@ -1762,7 +1764,7 @@ static DeviceRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment DeviceRequestAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.DeviceRequestAsync$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.DeviceRequestAsync$VH.get(seg); } /** * Setter for field: @@ -1771,13 +1773,13 @@ static DeviceRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void DeviceRequestAsync$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.DeviceRequestAsync$VH.set(seg, x); + IOUSBDeviceStruct187.DeviceRequestAsync$VH.set(seg, x); } public static MemorySegment DeviceRequestAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.DeviceRequestAsync$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.DeviceRequestAsync$VH.get(seg.asSlice(index*sizeof())); } public static void DeviceRequestAsync$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.DeviceRequestAsync$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.DeviceRequestAsync$VH.set(seg.asSlice(index*sizeof()), x); } public static DeviceRequestAsync DeviceRequestAsync(MemorySegment segment, SegmentScope scope) { return DeviceRequestAsync.ofAddress(DeviceRequestAsync$get(segment), scope); @@ -1788,7 +1790,7 @@ public static DeviceRequestAsync DeviceRequestAsync(MemorySegment segment, Segme Constants$root.C_POINTER$LAYOUT ); static final MethodHandle CreateInterfaceIterator$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.CreateInterfaceIterator$FUNC + IOUSBDeviceStruct187.CreateInterfaceIterator$FUNC ); /** * {@snippet : @@ -1799,13 +1801,13 @@ public interface CreateInterfaceIterator { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); static MemorySegment allocate(CreateInterfaceIterator fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(CreateInterfaceIterator.class, fi, IOUSBDeviceStruct182.CreateInterfaceIterator$FUNC, scope); + return RuntimeHelper.upcallStub(CreateInterfaceIterator.class, fi, IOUSBDeviceStruct187.CreateInterfaceIterator$FUNC, scope); } static CreateInterfaceIterator ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBDeviceStruct182.CreateInterfaceIterator$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)IOUSBDeviceStruct187.CreateInterfaceIterator$MH.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1815,7 +1817,7 @@ static CreateInterfaceIterator ofAddress(MemorySegment addr, SegmentScope scope) static final VarHandle CreateInterfaceIterator$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceIterator")); public static VarHandle CreateInterfaceIterator$VH() { - return IOUSBDeviceStruct182.CreateInterfaceIterator$VH; + return IOUSBDeviceStruct187.CreateInterfaceIterator$VH; } /** * Getter for field: @@ -1824,7 +1826,7 @@ static CreateInterfaceIterator ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static MemorySegment CreateInterfaceIterator$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.CreateInterfaceIterator$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.CreateInterfaceIterator$VH.get(seg); } /** * Setter for field: @@ -1833,13 +1835,13 @@ static CreateInterfaceIterator ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static void CreateInterfaceIterator$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.CreateInterfaceIterator$VH.set(seg, x); + IOUSBDeviceStruct187.CreateInterfaceIterator$VH.set(seg, x); } public static MemorySegment CreateInterfaceIterator$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.CreateInterfaceIterator$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.CreateInterfaceIterator$VH.get(seg.asSlice(index*sizeof())); } public static void CreateInterfaceIterator$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.CreateInterfaceIterator$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.CreateInterfaceIterator$VH.set(seg.asSlice(index*sizeof()), x); } public static CreateInterfaceIterator CreateInterfaceIterator(MemorySegment segment, SegmentScope scope) { return CreateInterfaceIterator.ofAddress(CreateInterfaceIterator$get(segment), scope); @@ -1848,7 +1850,7 @@ public static CreateInterfaceIterator CreateInterfaceIterator(MemorySegment segm Constants$root.C_POINTER$LAYOUT ); static final MethodHandle USBDeviceOpenSeize$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.USBDeviceOpenSeize$FUNC + IOUSBDeviceStruct187.USBDeviceOpenSeize$FUNC ); /** * {@snippet : @@ -1859,13 +1861,13 @@ public interface USBDeviceOpenSeize { int apply(java.lang.foreign.MemorySegment _x0); static MemorySegment allocate(USBDeviceOpenSeize fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBDeviceOpenSeize.class, fi, IOUSBDeviceStruct182.USBDeviceOpenSeize$FUNC, scope); + return RuntimeHelper.upcallStub(USBDeviceOpenSeize.class, fi, IOUSBDeviceStruct187.USBDeviceOpenSeize$FUNC, scope); } static USBDeviceOpenSeize ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct182.USBDeviceOpenSeize$MH.invokeExact(symbol, __x0); + return (int)IOUSBDeviceStruct187.USBDeviceOpenSeize$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1875,7 +1877,7 @@ static USBDeviceOpenSeize ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle USBDeviceOpenSeize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceOpenSeize")); public static VarHandle USBDeviceOpenSeize$VH() { - return IOUSBDeviceStruct182.USBDeviceOpenSeize$VH; + return IOUSBDeviceStruct187.USBDeviceOpenSeize$VH; } /** * Getter for field: @@ -1884,7 +1886,7 @@ static USBDeviceOpenSeize ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment USBDeviceOpenSeize$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceOpenSeize$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceOpenSeize$VH.get(seg); } /** * Setter for field: @@ -1893,13 +1895,13 @@ static USBDeviceOpenSeize ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void USBDeviceOpenSeize$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.USBDeviceOpenSeize$VH.set(seg, x); + IOUSBDeviceStruct187.USBDeviceOpenSeize$VH.set(seg, x); } public static MemorySegment USBDeviceOpenSeize$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceOpenSeize$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceOpenSeize$VH.get(seg.asSlice(index*sizeof())); } public static void USBDeviceOpenSeize$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.USBDeviceOpenSeize$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.USBDeviceOpenSeize$VH.set(seg.asSlice(index*sizeof()), x); } public static USBDeviceOpenSeize USBDeviceOpenSeize(MemorySegment segment, SegmentScope scope) { return USBDeviceOpenSeize.ofAddress(USBDeviceOpenSeize$get(segment), scope); @@ -1909,7 +1911,7 @@ public static USBDeviceOpenSeize USBDeviceOpenSeize(MemorySegment segment, Segme Constants$root.C_POINTER$LAYOUT ); static final MethodHandle DeviceRequestTO$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.DeviceRequestTO$FUNC + IOUSBDeviceStruct187.DeviceRequestTO$FUNC ); /** * {@snippet : @@ -1920,13 +1922,13 @@ public interface DeviceRequestTO { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(DeviceRequestTO fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(DeviceRequestTO.class, fi, IOUSBDeviceStruct182.DeviceRequestTO$FUNC, scope); + return RuntimeHelper.upcallStub(DeviceRequestTO.class, fi, IOUSBDeviceStruct187.DeviceRequestTO$FUNC, scope); } static DeviceRequestTO ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.DeviceRequestTO$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.DeviceRequestTO$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1936,7 +1938,7 @@ static DeviceRequestTO ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle DeviceRequestTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestTO")); public static VarHandle DeviceRequestTO$VH() { - return IOUSBDeviceStruct182.DeviceRequestTO$VH; + return IOUSBDeviceStruct187.DeviceRequestTO$VH; } /** * Getter for field: @@ -1945,7 +1947,7 @@ static DeviceRequestTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment DeviceRequestTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.DeviceRequestTO$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.DeviceRequestTO$VH.get(seg); } /** * Setter for field: @@ -1954,13 +1956,13 @@ static DeviceRequestTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void DeviceRequestTO$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.DeviceRequestTO$VH.set(seg, x); + IOUSBDeviceStruct187.DeviceRequestTO$VH.set(seg, x); } public static MemorySegment DeviceRequestTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.DeviceRequestTO$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.DeviceRequestTO$VH.get(seg.asSlice(index*sizeof())); } public static void DeviceRequestTO$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.DeviceRequestTO$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.DeviceRequestTO$VH.set(seg.asSlice(index*sizeof()), x); } public static DeviceRequestTO DeviceRequestTO(MemorySegment segment, SegmentScope scope) { return DeviceRequestTO.ofAddress(DeviceRequestTO$get(segment), scope); @@ -1972,7 +1974,7 @@ public static DeviceRequestTO DeviceRequestTO(MemorySegment segment, SegmentScop Constants$root.C_POINTER$LAYOUT ); static final MethodHandle DeviceRequestAsyncTO$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.DeviceRequestAsyncTO$FUNC + IOUSBDeviceStruct187.DeviceRequestAsyncTO$FUNC ); /** * {@snippet : @@ -1983,13 +1985,13 @@ public interface DeviceRequestAsyncTO { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3); static MemorySegment allocate(DeviceRequestAsyncTO fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(DeviceRequestAsyncTO.class, fi, IOUSBDeviceStruct182.DeviceRequestAsyncTO$FUNC, scope); + return RuntimeHelper.upcallStub(DeviceRequestAsyncTO.class, fi, IOUSBDeviceStruct187.DeviceRequestAsyncTO$FUNC, scope); } static DeviceRequestAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3) -> { try { - return (int)IOUSBDeviceStruct182.DeviceRequestAsyncTO$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); + return (int)IOUSBDeviceStruct187.DeviceRequestAsyncTO$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1999,7 +2001,7 @@ static DeviceRequestAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle DeviceRequestAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestAsyncTO")); public static VarHandle DeviceRequestAsyncTO$VH() { - return IOUSBDeviceStruct182.DeviceRequestAsyncTO$VH; + return IOUSBDeviceStruct187.DeviceRequestAsyncTO$VH; } /** * Getter for field: @@ -2008,7 +2010,7 @@ static DeviceRequestAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment DeviceRequestAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.DeviceRequestAsyncTO$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.DeviceRequestAsyncTO$VH.get(seg); } /** * Setter for field: @@ -2017,13 +2019,13 @@ static DeviceRequestAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void DeviceRequestAsyncTO$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.DeviceRequestAsyncTO$VH.set(seg, x); + IOUSBDeviceStruct187.DeviceRequestAsyncTO$VH.set(seg, x); } public static MemorySegment DeviceRequestAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.DeviceRequestAsyncTO$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.DeviceRequestAsyncTO$VH.get(seg.asSlice(index*sizeof())); } public static void DeviceRequestAsyncTO$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.DeviceRequestAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.DeviceRequestAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); } public static DeviceRequestAsyncTO DeviceRequestAsyncTO(MemorySegment segment, SegmentScope scope) { return DeviceRequestAsyncTO.ofAddress(DeviceRequestAsyncTO$get(segment), scope); @@ -2033,7 +2035,7 @@ public static DeviceRequestAsyncTO DeviceRequestAsyncTO(MemorySegment segment, S Constants$root.C_CHAR$LAYOUT ); static final MethodHandle USBDeviceSuspend$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.USBDeviceSuspend$FUNC + IOUSBDeviceStruct187.USBDeviceSuspend$FUNC ); /** * {@snippet : @@ -2044,13 +2046,13 @@ public interface USBDeviceSuspend { int apply(java.lang.foreign.MemorySegment _x0, byte _x1); static MemorySegment allocate(USBDeviceSuspend fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBDeviceSuspend.class, fi, IOUSBDeviceStruct182.USBDeviceSuspend$FUNC, scope); + return RuntimeHelper.upcallStub(USBDeviceSuspend.class, fi, IOUSBDeviceStruct187.USBDeviceSuspend$FUNC, scope); } static USBDeviceSuspend ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBDeviceStruct182.USBDeviceSuspend$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.USBDeviceSuspend$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2060,7 +2062,7 @@ static USBDeviceSuspend ofAddress(MemorySegment addr, SegmentScope scope) { static final VarHandle USBDeviceSuspend$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceSuspend")); public static VarHandle USBDeviceSuspend$VH() { - return IOUSBDeviceStruct182.USBDeviceSuspend$VH; + return IOUSBDeviceStruct187.USBDeviceSuspend$VH; } /** * Getter for field: @@ -2069,7 +2071,7 @@ static USBDeviceSuspend ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment USBDeviceSuspend$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceSuspend$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceSuspend$VH.get(seg); } /** * Setter for field: @@ -2078,13 +2080,13 @@ static USBDeviceSuspend ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void USBDeviceSuspend$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.USBDeviceSuspend$VH.set(seg, x); + IOUSBDeviceStruct187.USBDeviceSuspend$VH.set(seg, x); } public static MemorySegment USBDeviceSuspend$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceSuspend$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceSuspend$VH.get(seg.asSlice(index*sizeof())); } public static void USBDeviceSuspend$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.USBDeviceSuspend$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.USBDeviceSuspend$VH.set(seg.asSlice(index*sizeof()), x); } public static USBDeviceSuspend USBDeviceSuspend(MemorySegment segment, SegmentScope scope) { return USBDeviceSuspend.ofAddress(USBDeviceSuspend$get(segment), scope); @@ -2093,7 +2095,7 @@ public static USBDeviceSuspend USBDeviceSuspend(MemorySegment segment, SegmentSc Constants$root.C_POINTER$LAYOUT ); static final MethodHandle USBDeviceAbortPipeZero$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.USBDeviceAbortPipeZero$FUNC + IOUSBDeviceStruct187.USBDeviceAbortPipeZero$FUNC ); /** * {@snippet : @@ -2104,13 +2106,13 @@ public interface USBDeviceAbortPipeZero { int apply(java.lang.foreign.MemorySegment _x0); static MemorySegment allocate(USBDeviceAbortPipeZero fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBDeviceAbortPipeZero.class, fi, IOUSBDeviceStruct182.USBDeviceAbortPipeZero$FUNC, scope); + return RuntimeHelper.upcallStub(USBDeviceAbortPipeZero.class, fi, IOUSBDeviceStruct187.USBDeviceAbortPipeZero$FUNC, scope); } static USBDeviceAbortPipeZero ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct182.USBDeviceAbortPipeZero$MH.invokeExact(symbol, __x0); + return (int)IOUSBDeviceStruct187.USBDeviceAbortPipeZero$MH.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2120,7 +2122,7 @@ static USBDeviceAbortPipeZero ofAddress(MemorySegment addr, SegmentScope scope) static final VarHandle USBDeviceAbortPipeZero$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceAbortPipeZero")); public static VarHandle USBDeviceAbortPipeZero$VH() { - return IOUSBDeviceStruct182.USBDeviceAbortPipeZero$VH; + return IOUSBDeviceStruct187.USBDeviceAbortPipeZero$VH; } /** * Getter for field: @@ -2129,7 +2131,7 @@ static USBDeviceAbortPipeZero ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static MemorySegment USBDeviceAbortPipeZero$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceAbortPipeZero$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceAbortPipeZero$VH.get(seg); } /** * Setter for field: @@ -2138,13 +2140,13 @@ static USBDeviceAbortPipeZero ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static void USBDeviceAbortPipeZero$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.USBDeviceAbortPipeZero$VH.set(seg, x); + IOUSBDeviceStruct187.USBDeviceAbortPipeZero$VH.set(seg, x); } public static MemorySegment USBDeviceAbortPipeZero$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBDeviceAbortPipeZero$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceAbortPipeZero$VH.get(seg.asSlice(index*sizeof())); } public static void USBDeviceAbortPipeZero$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.USBDeviceAbortPipeZero$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.USBDeviceAbortPipeZero$VH.set(seg.asSlice(index*sizeof()), x); } public static USBDeviceAbortPipeZero USBDeviceAbortPipeZero(MemorySegment segment, SegmentScope scope) { return USBDeviceAbortPipeZero.ofAddress(USBDeviceAbortPipeZero$get(segment), scope); @@ -2154,7 +2156,7 @@ public static USBDeviceAbortPipeZero USBDeviceAbortPipeZero(MemorySegment segmen Constants$root.C_POINTER$LAYOUT ); static final MethodHandle USBGetManufacturerStringIndex$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.USBGetManufacturerStringIndex$FUNC + IOUSBDeviceStruct187.USBGetManufacturerStringIndex$FUNC ); /** * {@snippet : @@ -2165,13 +2167,13 @@ public interface USBGetManufacturerStringIndex { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(USBGetManufacturerStringIndex fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBGetManufacturerStringIndex.class, fi, IOUSBDeviceStruct182.USBGetManufacturerStringIndex$FUNC, scope); + return RuntimeHelper.upcallStub(USBGetManufacturerStringIndex.class, fi, IOUSBDeviceStruct187.USBGetManufacturerStringIndex$FUNC, scope); } static USBGetManufacturerStringIndex ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.USBGetManufacturerStringIndex$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.USBGetManufacturerStringIndex$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2181,7 +2183,7 @@ static USBGetManufacturerStringIndex ofAddress(MemorySegment addr, SegmentScope static final VarHandle USBGetManufacturerStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBGetManufacturerStringIndex")); public static VarHandle USBGetManufacturerStringIndex$VH() { - return IOUSBDeviceStruct182.USBGetManufacturerStringIndex$VH; + return IOUSBDeviceStruct187.USBGetManufacturerStringIndex$VH; } /** * Getter for field: @@ -2190,7 +2192,7 @@ static USBGetManufacturerStringIndex ofAddress(MemorySegment addr, SegmentScope * } */ public static MemorySegment USBGetManufacturerStringIndex$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBGetManufacturerStringIndex$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBGetManufacturerStringIndex$VH.get(seg); } /** * Setter for field: @@ -2199,13 +2201,13 @@ static USBGetManufacturerStringIndex ofAddress(MemorySegment addr, SegmentScope * } */ public static void USBGetManufacturerStringIndex$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.USBGetManufacturerStringIndex$VH.set(seg, x); + IOUSBDeviceStruct187.USBGetManufacturerStringIndex$VH.set(seg, x); } public static MemorySegment USBGetManufacturerStringIndex$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBGetManufacturerStringIndex$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBGetManufacturerStringIndex$VH.get(seg.asSlice(index*sizeof())); } public static void USBGetManufacturerStringIndex$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.USBGetManufacturerStringIndex$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.USBGetManufacturerStringIndex$VH.set(seg.asSlice(index*sizeof()), x); } public static USBGetManufacturerStringIndex USBGetManufacturerStringIndex(MemorySegment segment, SegmentScope scope) { return USBGetManufacturerStringIndex.ofAddress(USBGetManufacturerStringIndex$get(segment), scope); @@ -2215,7 +2217,7 @@ public static USBGetManufacturerStringIndex USBGetManufacturerStringIndex(Memory Constants$root.C_POINTER$LAYOUT ); static final MethodHandle USBGetProductStringIndex$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.USBGetProductStringIndex$FUNC + IOUSBDeviceStruct187.USBGetProductStringIndex$FUNC ); /** * {@snippet : @@ -2226,13 +2228,13 @@ public interface USBGetProductStringIndex { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(USBGetProductStringIndex fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBGetProductStringIndex.class, fi, IOUSBDeviceStruct182.USBGetProductStringIndex$FUNC, scope); + return RuntimeHelper.upcallStub(USBGetProductStringIndex.class, fi, IOUSBDeviceStruct187.USBGetProductStringIndex$FUNC, scope); } static USBGetProductStringIndex ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.USBGetProductStringIndex$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.USBGetProductStringIndex$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2242,7 +2244,7 @@ static USBGetProductStringIndex ofAddress(MemorySegment addr, SegmentScope scope static final VarHandle USBGetProductStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBGetProductStringIndex")); public static VarHandle USBGetProductStringIndex$VH() { - return IOUSBDeviceStruct182.USBGetProductStringIndex$VH; + return IOUSBDeviceStruct187.USBGetProductStringIndex$VH; } /** * Getter for field: @@ -2251,7 +2253,7 @@ static USBGetProductStringIndex ofAddress(MemorySegment addr, SegmentScope scope * } */ public static MemorySegment USBGetProductStringIndex$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBGetProductStringIndex$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBGetProductStringIndex$VH.get(seg); } /** * Setter for field: @@ -2260,13 +2262,13 @@ static USBGetProductStringIndex ofAddress(MemorySegment addr, SegmentScope scope * } */ public static void USBGetProductStringIndex$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.USBGetProductStringIndex$VH.set(seg, x); + IOUSBDeviceStruct187.USBGetProductStringIndex$VH.set(seg, x); } public static MemorySegment USBGetProductStringIndex$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBGetProductStringIndex$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBGetProductStringIndex$VH.get(seg.asSlice(index*sizeof())); } public static void USBGetProductStringIndex$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.USBGetProductStringIndex$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.USBGetProductStringIndex$VH.set(seg.asSlice(index*sizeof()), x); } public static USBGetProductStringIndex USBGetProductStringIndex(MemorySegment segment, SegmentScope scope) { return USBGetProductStringIndex.ofAddress(USBGetProductStringIndex$get(segment), scope); @@ -2276,7 +2278,7 @@ public static USBGetProductStringIndex USBGetProductStringIndex(MemorySegment se Constants$root.C_POINTER$LAYOUT ); static final MethodHandle USBGetSerialNumberStringIndex$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct182.USBGetSerialNumberStringIndex$FUNC + IOUSBDeviceStruct187.USBGetSerialNumberStringIndex$FUNC ); /** * {@snippet : @@ -2287,13 +2289,13 @@ public interface USBGetSerialNumberStringIndex { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); static MemorySegment allocate(USBGetSerialNumberStringIndex fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBGetSerialNumberStringIndex.class, fi, IOUSBDeviceStruct182.USBGetSerialNumberStringIndex$FUNC, scope); + return RuntimeHelper.upcallStub(USBGetSerialNumberStringIndex.class, fi, IOUSBDeviceStruct187.USBGetSerialNumberStringIndex$FUNC, scope); } static USBGetSerialNumberStringIndex ofAddress(MemorySegment addr, SegmentScope scope) { MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct182.USBGetSerialNumberStringIndex$MH.invokeExact(symbol, __x0, __x1); + return (int)IOUSBDeviceStruct187.USBGetSerialNumberStringIndex$MH.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2303,7 +2305,7 @@ static USBGetSerialNumberStringIndex ofAddress(MemorySegment addr, SegmentScope static final VarHandle USBGetSerialNumberStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBGetSerialNumberStringIndex")); public static VarHandle USBGetSerialNumberStringIndex$VH() { - return IOUSBDeviceStruct182.USBGetSerialNumberStringIndex$VH; + return IOUSBDeviceStruct187.USBGetSerialNumberStringIndex$VH; } /** * Getter for field: @@ -2312,7 +2314,7 @@ static USBGetSerialNumberStringIndex ofAddress(MemorySegment addr, SegmentScope * } */ public static MemorySegment USBGetSerialNumberStringIndex$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBGetSerialNumberStringIndex$VH.get(seg); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBGetSerialNumberStringIndex$VH.get(seg); } /** * Setter for field: @@ -2321,17 +2323,78 @@ static USBGetSerialNumberStringIndex ofAddress(MemorySegment addr, SegmentScope * } */ public static void USBGetSerialNumberStringIndex$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct182.USBGetSerialNumberStringIndex$VH.set(seg, x); + IOUSBDeviceStruct187.USBGetSerialNumberStringIndex$VH.set(seg, x); } public static MemorySegment USBGetSerialNumberStringIndex$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct182.USBGetSerialNumberStringIndex$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBGetSerialNumberStringIndex$VH.get(seg.asSlice(index*sizeof())); } public static void USBGetSerialNumberStringIndex$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct182.USBGetSerialNumberStringIndex$VH.set(seg.asSlice(index*sizeof()), x); + IOUSBDeviceStruct187.USBGetSerialNumberStringIndex$VH.set(seg.asSlice(index*sizeof()), x); } public static USBGetSerialNumberStringIndex USBGetSerialNumberStringIndex(MemorySegment segment, SegmentScope scope) { return USBGetSerialNumberStringIndex.ofAddress(USBGetSerialNumberStringIndex$get(segment), scope); } + static final FunctionDescriptor USBDeviceReEnumerate$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_INT$LAYOUT + ); + static final MethodHandle USBDeviceReEnumerate$MH = RuntimeHelper.downcallHandle( + IOUSBDeviceStruct187.USBDeviceReEnumerate$FUNC + ); + /** + * {@snippet : + * IOReturn (*USBDeviceReEnumerate)(void*,UInt32); + * } + */ + public interface USBDeviceReEnumerate { + + int apply(java.lang.foreign.MemorySegment _x0, int _x1); + static MemorySegment allocate(USBDeviceReEnumerate fi, SegmentScope scope) { + return RuntimeHelper.upcallStub(USBDeviceReEnumerate.class, fi, IOUSBDeviceStruct187.USBDeviceReEnumerate$FUNC, scope); + } + static USBDeviceReEnumerate ofAddress(MemorySegment addr, SegmentScope scope) { + MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + return (java.lang.foreign.MemorySegment __x0, int __x1) -> { + try { + return (int)IOUSBDeviceStruct187.USBDeviceReEnumerate$MH.invokeExact(symbol, __x0, __x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + }; + } + } + + static final VarHandle USBDeviceReEnumerate$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceReEnumerate")); + public static VarHandle USBDeviceReEnumerate$VH() { + return IOUSBDeviceStruct187.USBDeviceReEnumerate$VH; + } + /** + * Getter for field: + * {@snippet : + * IOReturn (*USBDeviceReEnumerate)(void*,UInt32); + * } + */ + public static MemorySegment USBDeviceReEnumerate$get(MemorySegment seg) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceReEnumerate$VH.get(seg); + } + /** + * Setter for field: + * {@snippet : + * IOReturn (*USBDeviceReEnumerate)(void*,UInt32); + * } + */ + public static void USBDeviceReEnumerate$set(MemorySegment seg, MemorySegment x) { + IOUSBDeviceStruct187.USBDeviceReEnumerate$VH.set(seg, x); + } + public static MemorySegment USBDeviceReEnumerate$get(MemorySegment seg, long index) { + return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceReEnumerate$VH.get(seg.asSlice(index*sizeof())); + } + public static void USBDeviceReEnumerate$set(MemorySegment seg, long index, MemorySegment x) { + IOUSBDeviceStruct187.USBDeviceReEnumerate$VH.set(seg.asSlice(index*sizeof()), x); + } + public static USBDeviceReEnumerate USBDeviceReEnumerate(MemorySegment segment, SegmentScope scope) { + return USBDeviceReEnumerate.ofAddress(USBDeviceReEnumerate$get(segment), scope); + } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { From ee875c1e86643c96976e8fc3f05632639935992e Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 2 Jul 2023 14:17:49 +0200 Subject: [PATCH 231/433] Sample for e-paper display with IT8951 controller --- examples/epaper_display/README.md | 86 ++++++ examples/epaper_display/pom.xml | 99 ++++++ .../codecrete/usb/examples/EPaperDisplay.java | 92 ++++++ .../codecrete/usb/examples/IT8951Driver.java | 289 ++++++++++++++++++ examples/epaper_display/tiger.jpg | Bin 0 -> 333612 bytes 5 files changed, 566 insertions(+) create mode 100644 examples/epaper_display/README.md create mode 100644 examples/epaper_display/pom.xml create mode 100644 examples/epaper_display/src/main/java/net/codecrete/usb/examples/EPaperDisplay.java create mode 100644 examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java create mode 100644 examples/epaper_display/tiger.jpg diff --git a/examples/epaper_display/README.md b/examples/epaper_display/README.md new file mode 100644 index 00000000..95b62de2 --- /dev/null +++ b/examples/epaper_display/README.md @@ -0,0 +1,86 @@ +# E-Paper Display + +This sample shows how to communicate with an IT8951 controller for e-paper displays, e.g. [Waveshare E-Ink display HAT for Raspberry Pi](https://www.waveshare.com/9.7inch-e-paper-hat.htm) + +## Prerequisites + +- Java 20 +- Apache Maven +- 64-bit operating system (macOS, Linux, Windows) +- IT8951 controller + +On Windows, the display controller's driver must be replaced with the *WinUSB* driver +using [Zadig](https://zadig.akeo.ie/). + +On macOS, root privileges are required to successfully run the sample. (The standard driver will +be temporarily detached.) + +## How to run + +### Install Java 20 + +Check that *Java 20* is installed: + +```shell +$ java -version +``` + +If not, download and install it, e.g. from [Azul](https://www.azul.com/downloads/?package=jdk). + +### Install Maven + +Check that *Maven* is installed: + +```shell +$ mvn -version +``` + +If it is not present, install it, typically using package manager like *Homebrew* on macOS, *Chocolately* on Windows and *apt* on Linux. + +### Run the sample + +```shell +$ cd JavaDoesUSB/examples/epaper_display +$ mvn compile exec:exec +[INFO] Scanning for projects... +[INFO] +[INFO] -------------< net.codecrete.usb.examples:epaper-display >-------------- +[INFO] Building epaper-display 0.5.1 +[INFO] from pom.xml +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] +[INFO] --- resources:3.3.1:resources (default-resources) @ epaper-display --- +[INFO] skip non existing resourceDirectory /Users/me/Documents/JavaDoesUSB/examples/epaper_display/src/main/resources +[INFO] +[INFO] --- compiler:3.11.0:compile (default-compile) @ epaper-display --- +[INFO] Changes detected - recompiling the module! :source +[INFO] Compiling 2 source files with javac [debug release 20] to target/classes +[INFO] +[INFO] --- exec:3.1.0:exec (default-cli) @ epaper-display --- +Display size: 1200 x 825 +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 1.502 s +[INFO] Finished at: 2023-07-02T14:08:50+02:00 +[INFO] ------------------------------------------------------------------------ +``` + +### Run the sample on macOS + +In order to run the sample with root privileges, the best approach is to build it first without +root privileges and then run it as root without Maven: + +```shell +$ cd JavaDoesUSB/examples/epaper_display +$ mvn compile +[INFO] Scanning for projects... +... +[INFO] ------------------------------------------------------------------------ +$ sudo -i +Password: +$ cd /Users/me/Documents/JavaDoesUSB/examples/epaper_display +$ export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-20.jdk/Contents/Home +$ JAVA_HOME/bin/java --enable-preview --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/0.5.1/java-does-usb-0.5.1.jar net.codecrete.usb.examples.EPaperDisplay +Display size: 1200 x 825 +``` diff --git a/examples/epaper_display/pom.xml b/examples/epaper_display/pom.xml new file mode 100644 index 00000000..f1d28baf --- /dev/null +++ b/examples/epaper_display/pom.xml @@ -0,0 +1,99 @@ + + + + 4.0.0 + + net.codecrete.usb.examples + epaper-display + 0.5.1 + + epaper-display + https://github.com/manuelbl/JavaDoesUSB/examples/epaper_display + + + UTF-8 + 20 + 20 + + + + + net.codecrete.usb + java-does-usb + 0.5.1 + + + + + + + + + maven-clean-plugin + 3.3.1 + + + + maven-resources-plugin + 3.3.1 + + + maven-compiler-plugin + 3.11.0 + + 20 + + --enable-preview + + 20 + 20 + + + + maven-surefire-plugin + 2.22.1 + + --enable-preview --enable-native-access=ALL-UNNAMED + + + + maven-jar-plugin + 3.1.2 + + + maven-install-plugin + 3.1.1 + + + maven-deploy-plugin + 3.1.1 + + + + maven-site-plugin + 3.12.1 + + + maven-project-info-reports-plugin + 3.4.5 + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + java + + --enable-preview + --enable-native-access=ALL-UNNAMED + -classpath + + net.codecrete.usb.examples.EPaperDisplay + + + + + + + diff --git a/examples/epaper_display/src/main/java/net/codecrete/usb/examples/EPaperDisplay.java b/examples/epaper_display/src/main/java/net/codecrete/usb/examples/EPaperDisplay.java new file mode 100644 index 00000000..7cc3a536 --- /dev/null +++ b/examples/epaper_display/src/main/java/net/codecrete/usb/examples/EPaperDisplay.java @@ -0,0 +1,92 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.examples; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +/** + * Example program for displaying an image and text on an e-paper display + * controlled by an IT8951 controller. + */ +public class EPaperDisplay { + + public static void main(String[] args) throws IOException { + // load image of tiger + var tigerImage = ImageIO.read(new File("tiger.jpg")); + + // connect to display controller + var display = new IT8951Driver(); + display.open(); + + var width = display.info().width(); + var height = display.info().height(); + System.out.printf("Display size: %d x %d%n", width, height); + + // resize image to fit display (converting it to grayscale) + var image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); + image = resizedImage(tigerImage, width, height); + + // add text to image + Graphics2D g = (Graphics2D) image.getGraphics(); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g.setFont(new Font("Arial", Font.BOLD, 40)); + g.drawString("Java Does USB", 20, height - 40); + g.dispose(); + + // display image + display.displayImage(image, 0, 0); + + display.close(); + } + + /** + * Returns a copy of the image, resized to the specified width and height. + *

+ * To prevent distortion, the image is cropped to fit the target width and height. + *

+ *

+ * The new image will be in 8-bit grayscale. + *

+ * @param image image to resize + * @param width width, in pixels + * @param height height, in pixels + * @return resized image + */ + static BufferedImage resizedImage(BufferedImage image, int width, int height) { + + var resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); + var g = (Graphics2D) resizedImage.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + int srcWidth = image.getWidth(); + int srcHeight = image.getHeight(); + var targetAspectRatio = (double) width / height; + var srcAspectRatio = (double) srcWidth / srcHeight; + + if (targetAspectRatio > srcAspectRatio) { + // target image is wider than source image - fit width and cut top and bottom + var modifiedHeight = width / srcAspectRatio; + var cutY = (int) Math.round((modifiedHeight - height) / 2); + g.drawImage(image, 0, -cutY, width, height + cutY, 0, 0, srcWidth, srcHeight, null); + } else { + // target image is narrower than source image - fit height and cut left and right + var modifiedWidth = height * srcAspectRatio; + var cutX = (int) Math.round((modifiedWidth - width) / 2); + g.drawImage(image, -cutX, 0, width + cutX, height, 0, 0, srcWidth, srcHeight, null); + } + + g.dispose(); + return resizedImage; + } +} diff --git a/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java b/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java new file mode 100644 index 00000000..d28be20a --- /dev/null +++ b/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java @@ -0,0 +1,289 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.examples; + +import net.codecrete.usb.USB; +import net.codecrete.usb.USBDevice; + +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * Driver for the IT8951 e-paper display controller. + */ +public class IT8951Driver { + + private static final int ENDPOINT_IN = 1; + private static final int ENDPOINT_OUT = 2; + + private static final byte[] GET_SYS_CMD = { + (byte)0xfe, 0, 0x38, 0x39, 0x35, 0x31, (byte)0x80, 0, 0x01, 0, 0x02, 0, 0, 0, 0, 0 + }; + private static final byte[] LD_IMG_AREA_CMD = { + (byte)0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, (byte)0xa2, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + private static final byte[] DPY_AREA_CMD = { + (byte)0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, (byte)0x94, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + + private USBDevice device; + private int sequenceNo = 1; + + private DisplayInfo displayInfo; + + /** + * Opens the controller for communication. + * + * @throws IllegalStateException if no IT8951 device is found + */ + public void open() { + device = USB.getDevice(dev -> dev.vendorId() == 0x048d && dev.productId() == 0x8951); + if (device == null) + throw new IllegalStateException("No IT8951 device found"); + + device.detachStandardDrivers(); + device.open(); + try { + device.claimInterface(0); + var sysInfoBytes = readCommand(GET_SYS_CMD, DisplayInfo.LENGTH); + displayInfo = DisplayInfo.from(sysInfoBytes); + + } catch (Throwable t) { + device.close(); + throw t; + } + } + + /** + * Displays the provided image at the specified position. + * + *

+ * The provided image must be an 8-bit grayscale image, + * and it must fully fit within the bounds of the display. + *

+ * + * @param image image + * @param x x-position + * @param y y-position + */ + public void displayImage(BufferedImage image, int x, int y) { + int width = image.getWidth(); + int height = image.getHeight(); + int address = info().imageBufBase; + + // split into bands to no exceed 60KB transfer size + int bandHeight = (60000 - 20) / width; + + for (int yOffset = 0; yOffset < height; yOffset += bandHeight) { + bandHeight = Math.min(bandHeight, height - yOffset); + var pixelData = pixelsFromImage(image, 0, yOffset, width, bandHeight); + loadImageArea(new Area(address, x, y + yOffset, width, bandHeight), pixelData); + } + + displayArea(new DisplayArea(address, 2, x, y, width, height, 1)); + } + + /** + * Close the communication with the controller. + */ + public void close() { + device.close(); + device.attachStandardDrivers(); + } + + /** + * Gets information about the display and controller. + * + * @return information + */ + public DisplayInfo info() { + return displayInfo; + } + + /** + * Execute a read command. + * @param command command + * @param expectedLength expected length of received data (in bytes) + * @return received data + */ + private byte[] readCommand(byte[] command, int expectedLength) { + var cmd = createCommandBlock(command, expectedLength, true); + device.transferOut(ENDPOINT_OUT, cmd); + byte[] result = device.transferIn(ENDPOINT_IN, 1000); + readStatus(); + return result; + } + + /** + * Execute a write command. + * @param command command + * @param data1 part 1 of data to be written + * @param data2 part 2 of data to be written (or {@code null} if there is no second part) + */ + private void writeCommand(byte[] command, byte[] data1, byte[] data2) { + var cmd = createCommandBlock(command, data1.length + ((data2 != null) ? data2.length : 0), false); + device.transferOut(ENDPOINT_OUT, cmd); + device.transferOut(ENDPOINT_OUT, data1); + if (data2 != null) + device.transferOut(ENDPOINT_OUT, data2); + readStatus(); + } + + /** + * Execute a write command. + * @param command command + * @param data data to be written + */ + private void writeCommand(byte[] command, byte[] data) { + writeCommand(command, data, null); + } + + /** + * Wraps the given command in a command block. + * @param command command + * @param dataLength length of data to be read or written (in bytes) + * @param isDirectionIn indicates if data direction is in (from device to host) + * @return the command block + */ + private byte[] createCommandBlock(byte[] command, int dataLength, boolean isDirectionIn) { + var cmd = ByteBuffer.allocate(15 + command.length).order(ByteOrder.LITTLE_ENDIAN); + cmd.putInt(0x43425355); // signature + cmd.putInt(sequenceNo); + sequenceNo += 1; + cmd.putInt(dataLength); // data transfer length + cmd.put((byte)(isDirectionIn ? 0x80 : 0x00)); // flags + cmd.put((byte)0); // logical unit number + cmd.put((byte)command.length); + cmd.put(command); + return cmd.array(); + } + + private void loadImageArea(Area area, byte[] pixelData) { + writeCommand(LD_IMG_AREA_CMD, area.toByteArray(), pixelData); + } + + private void displayArea(DisplayArea area) { + writeCommand(DPY_AREA_CMD, area.toByteArray()); + } + + private byte[] pixelsFromImage(BufferedImage image, int x, int y, int w, int h) { + var buffer = (DataBufferByte) image.getRaster().getDataBuffer(); + var data = buffer.getData(); + var stride = buffer.getSize() / image.getHeight(); + + byte[] pixels = new byte[w * h]; + for (int iy = 0; iy < h; iy += 1) + System.arraycopy(data, (iy + y) * stride + x, pixels, iy * w, w); + + return pixels; + } + + /** + * Read the status block. + * @return status block + */ + private Status readStatus() { + var result = device.transferIn(ENDPOINT_IN, 1000); + if (result.length == 13) + return Status.from(result); + + throw new RuntimeException(String.format("Unexpected length of status block (%d)", result.length)); + } + + /** + * Display and controller information + * + * @param standardCmdNo standard command number 2T-con Communication Protocol + * @param extendedCmdNo extended command number + * @param signature signature (0x31 0x35 0x39 0x38 (8951)) + * @param version command table version + * @param width display width (in pixels) + * @param height display height (in pixels) + * @param updateBufBase update buffer base address + * @param imageBufBase image buffer base address (index 0) + * @param temperatureNo temperature segment number + * @param modeNo display mode number + * @param frameCount frame count for each mode (8 elements) + * @param numImgBuf number of image buffers + */ + public record DisplayInfo( + int standardCmdNo, + int extendedCmdNo, + int signature, + int version, + int width, + int height, + int updateBufBase, + int imageBufBase, + int temperatureNo, + /// Display mode + int modeNo, + int[] frameCount, // 8 elements + int numImgBuf + ) { + static DisplayInfo from(byte[] bytes) { + var buf = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN); + int standardCmdNo = buf.getInt(); + int extendedCmdNo = buf.getInt(); + int signature = buf.getInt(); + int version = buf.getInt(); + int width = buf.getInt(); + int height = buf.getInt(); + int updateBufBase = buf.getInt(); + int imageBufBase = buf.getInt(); + int temperatureNo = buf.getInt(); + int modeNo = buf.getInt(); + int[] frameCount = new int[8]; + for (int i = 0; i < 8; i += 1) + frameCount[i] = buf.getInt(); + int numImgBuf = buf.getInt(); + return new DisplayInfo(standardCmdNo, extendedCmdNo, signature, version, width, height, + updateBufBase, imageBufBase, temperatureNo, modeNo, frameCount, numImgBuf); + } + + static final int LENGTH = 112; + } + + record Status(int sequence, int dataRemaining, byte status) { + static Status from(byte[] bytes) { + var buf = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); + int sequence = buf.getInt(); + int dataLeft = buf.getInt(); + byte status = buf.get(); + return new Status(sequence, dataLeft, status); + } + } + + record Area(int address, int x, int y, int w, int h) { + byte[] toByteArray() { + var buf = ByteBuffer.allocate(20).order(ByteOrder.BIG_ENDIAN); + buf.putInt(address); + buf.putInt(x); + buf.putInt(y); + buf.putInt(w); + buf.putInt(h); + return buf.array(); + } + } + + record DisplayArea(int address, int mode, int x, int y, int w, int h, int wait_ready) { + byte[] toByteArray() { + var buf = ByteBuffer.allocate(28).order(ByteOrder.BIG_ENDIAN); + buf.putInt(address); + buf.putInt(mode); + buf.putInt(x); + buf.putInt(y); + buf.putInt(w); + buf.putInt(h); + buf.putInt(wait_ready); + return buf.array(); + } + } +} diff --git a/examples/epaper_display/tiger.jpg b/examples/epaper_display/tiger.jpg new file mode 100644 index 0000000000000000000000000000000000000000..82060f991a68e3c916517c2ab606e52f2898a8a5 GIT binary patch literal 333612 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%0D{Z`l-l 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
2kFc(SsAUop)4c2yFnXPJ4`J; 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 Date: Sun, 2 Jul 2023 15:13:25 +0200 Subject: [PATCH 232/433] Fix source version for bulk_transfer example --- examples/bulk_transfer/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index fac703df..272b483f 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -13,8 +13,8 @@ UTF-8 - 19 - 19 + 20 + 20 From af4b4b1111828536f0a5379c3cbeee39bdb631bd Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 2 Jul 2023 15:24:15 +0200 Subject: [PATCH 233/433] Use JAVA_HOME when running example --- examples/epaper_display/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/epaper_display/pom.xml b/examples/epaper_display/pom.xml index f1d28baf..4fefedc6 100644 --- a/examples/epaper_display/pom.xml +++ b/examples/epaper_display/pom.xml @@ -83,7 +83,7 @@ exec-maven-plugin 3.1.0 - java + ${JAVA_HOME}/bin/java --enable-preview --enable-native-access=ALL-UNNAMED From 81e833a79b9f45eb4061c3dcdb60afd07be79172 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 2 Jul 2023 16:25:59 +0200 Subject: [PATCH 234/433] Add Floyd-Steinberg dithering --- .../codecrete/usb/examples/EPaperDisplay.java | 2 +- .../codecrete/usb/examples/IT8951Driver.java | 75 ++++++++++++++++++- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/examples/epaper_display/src/main/java/net/codecrete/usb/examples/EPaperDisplay.java b/examples/epaper_display/src/main/java/net/codecrete/usb/examples/EPaperDisplay.java index 7cc3a536..373f7270 100644 --- a/examples/epaper_display/src/main/java/net/codecrete/usb/examples/EPaperDisplay.java +++ b/examples/epaper_display/src/main/java/net/codecrete/usb/examples/EPaperDisplay.java @@ -39,7 +39,7 @@ public static void main(String[] args) throws IOException { Graphics2D g = (Graphics2D) image.getGraphics(); g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); g.setFont(new Font("Arial", Font.BOLD, 40)); - g.drawString("Java Does USB", 20, height - 40); + g.drawString("Java Does USB", 30, height - 40); g.dispose(); // display image diff --git a/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java b/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java index d28be20a..12814e7b 100644 --- a/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java +++ b/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java @@ -14,6 +14,8 @@ import java.awt.image.DataBufferByte; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.Arrays; +import java.util.Random; /** * Driver for the IT8951 e-paper display controller. @@ -63,11 +65,14 @@ public void open() { /** * Displays the provided image at the specified position. - * *

* The provided image must be an 8-bit grayscale image, * and it must fully fit within the bounds of the display. *

+ *

+ * The image is rendered in 4-bit grayscale mode. For the + * reduction to 4-bit, Floyd-Steinberg dithering is used. + *

* * @param image image * @param x x-position @@ -76,14 +81,18 @@ public void open() { public void displayImage(BufferedImage image, int x, int y) { int width = image.getWidth(); int height = image.getHeight(); + var stride = image.getRaster().getDataBuffer().getSize() / image.getHeight(); int address = info().imageBufBase; // split into bands to no exceed 60KB transfer size int bandHeight = (60000 - 20) / width; + var errors = createInitialDitheringErrors(width); + for (int yOffset = 0; yOffset < height; yOffset += bandHeight) { bandHeight = Math.min(bandHeight, height - yOffset); var pixelData = pixelsFromImage(image, 0, yOffset, width, bandHeight); + errors = dither(pixelData, stride, errors); loadImageArea(new Area(address, x, y + yOffset, width, bandHeight), pixelData); } @@ -185,6 +194,70 @@ private byte[] pixelsFromImage(BufferedImage image, int x, int y, int w, int h) return pixels; } + /** + * Initializes the errors for dithering. + * @param width image width (in pixels) + * @return initial errors + */ + private int[] createInitialDitheringErrors(int width) { + // initialize errors with random values in the range [-127, 128]. + int[] errors = new int[width + 2]; + var random = new Random(); + + for (int i = 0; i < errors.length; i++) + errors[i] = random.nextInt(256) - 127; + + return errors; + } + + /** + * Quantizes the provided grayscale pixel data to 16 levels of gray + * using Floyd-Steinberg dithering. + *

+ * The pixel data is quantized in place. The resulting grayscale values + * are 0, 16, 32, ... 240. + *

+ *

+ * The pixel data consists of a single byte per pixel. A new pixel line + * starts every stride bytes. The actual image width can be + * slightly shorter. + *

+ * @param pixels array with pixel data to be modified + * @param stride the + * @param errors errors carried forward from the previous band + * @return errors to be carried forward to the next band + */ + private int[] dither(byte[] pixels, int stride, int[] errors) { + int[] currentErrors = errors; + int[] nextErrors = new int[errors.length]; + + for (int offset = 0; offset < pixels.length; offset += stride) { + Arrays.fill(nextErrors, 0); + ditherRow(pixels, offset, currentErrors, nextErrors); + + // swap error arrays + int[] errs = currentErrors; + currentErrors = nextErrors; + nextErrors = errs; + } + + return currentErrors; + } + + private void ditherRow(byte[] pixels, int offset, int[] currentErrors, int[] nextErrors) { + int w = currentErrors.length - 2; + for (int i = 0; i < w; i += 1) { + int targetValue = (pixels[offset + i] & 0xff) + (currentErrors[i + 1] + 7) / 16; + int quantizedValue = targetValue < 0 ? 0 : (targetValue > 0xf0 ? 0xf0 : (targetValue + 7) & 0xf0); + pixels[offset + i] = (byte) quantizedValue; + int quantizationError = targetValue - quantizedValue; + currentErrors[i + 2] += quantizationError * 7; + nextErrors[i] += quantizationError * 3; + nextErrors[i + 1] += quantizationError * 5 ; + nextErrors[i + 2] += quantizationError; + } + } + /** * Read the status block. * @return status block From 1b8b41d274a76d689099197f718f99afd209d238 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 2 Jul 2023 21:32:30 +0200 Subject: [PATCH 235/433] Improve dithering (e-paper display example) --- .../codecrete/usb/examples/EPaperDisplay.java | 3 +-- .../codecrete/usb/examples/IT8951Driver.java | 20 +++++++++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/examples/epaper_display/src/main/java/net/codecrete/usb/examples/EPaperDisplay.java b/examples/epaper_display/src/main/java/net/codecrete/usb/examples/EPaperDisplay.java index 373f7270..75dbd0f2 100644 --- a/examples/epaper_display/src/main/java/net/codecrete/usb/examples/EPaperDisplay.java +++ b/examples/epaper_display/src/main/java/net/codecrete/usb/examples/EPaperDisplay.java @@ -32,8 +32,7 @@ public static void main(String[] args) throws IOException { System.out.printf("Display size: %d x %d%n", width, height); // resize image to fit display (converting it to grayscale) - var image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); - image = resizedImage(tigerImage, width, height); + var image = resizedImage(tigerImage, width, height); // add text to image Graphics2D g = (Graphics2D) image.getGraphics(); diff --git a/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java b/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java index 12814e7b..e3b4f7e2 100644 --- a/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java +++ b/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java @@ -182,7 +182,7 @@ private void displayArea(DisplayArea area) { writeCommand(DPY_AREA_CMD, area.toByteArray()); } - private byte[] pixelsFromImage(BufferedImage image, int x, int y, int w, int h) { + private static byte[] pixelsFromImage(BufferedImage image, int x, int y, int w, int h) { var buffer = (DataBufferByte) image.getRaster().getDataBuffer(); var data = buffer.getData(); var stride = buffer.getSize() / image.getHeight(); @@ -199,7 +199,7 @@ private byte[] pixelsFromImage(BufferedImage image, int x, int y, int w, int h) * @param width image width (in pixels) * @return initial errors */ - private int[] createInitialDitheringErrors(int width) { + private static int[] createInitialDitheringErrors(int width) { // initialize errors with random values in the range [-127, 128]. int[] errors = new int[width + 2]; var random = new Random(); @@ -227,7 +227,7 @@ private int[] createInitialDitheringErrors(int width) { * @param errors errors carried forward from the previous band * @return errors to be carried forward to the next band */ - private int[] dither(byte[] pixels, int stride, int[] errors) { + private static int[] dither(byte[] pixels, int stride, int[] errors) { int[] currentErrors = errors; int[] nextErrors = new int[errors.length]; @@ -244,12 +244,20 @@ private int[] dither(byte[] pixels, int stride, int[] errors) { return currentErrors; } - private void ditherRow(byte[] pixels, int offset, int[] currentErrors, int[] nextErrors) { + private static void ditherRow(byte[] pixels, int offset, int[] currentErrors, int[] nextErrors) { int w = currentErrors.length - 2; for (int i = 0; i < w; i += 1) { - int targetValue = (pixels[offset + i] & 0xff) + (currentErrors[i + 1] + 7) / 16; - int quantizedValue = targetValue < 0 ? 0 : (targetValue > 0xf0 ? 0xf0 : (targetValue + 7) & 0xf0); + // scale range from [0, 255] to [0, 240] + int targetValue = (((pixels[offset + i] & 0xff) * 16 + currentErrors[i + 1]) * 15 + 127) / 255; + int quantizedValue; + if (targetValue <= 0) + quantizedValue = 0; + else if (targetValue >= 240) + quantizedValue = 240; + else + quantizedValue = (targetValue + 8) & 0xf0; pixels[offset + i] = (byte) quantizedValue; + int quantizationError = targetValue - quantizedValue; currentErrors[i + 2] += quantizationError * 7; nextErrors[i] += quantizationError * 3; From 7c7752878eb664a5c64ce1e1baa8bc81b671b7b1 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 3 Jul 2023 22:07:52 +0200 Subject: [PATCH 236/433] detach/attach drivers: check device is closed --- java-does-usb/pom.xml | 2 +- .../java/net/codecrete/usb/common/USBDeviceImpl.java | 10 ++++++++-- .../java/net/codecrete/usb/linux/LinuxUSBDevice.java | 4 ++++ .../java/net/codecrete/usb/macos/MacosUSBDevice.java | 4 ++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index af40c9a3..492f905e 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -69,7 +69,7 @@ maven-surefire-plugin 3.1.2 - --enable-preview --enable-native-access=ALL-UNNAMED + --enable-preview --enable-native-access=net.codecrete.usb diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index d57c11d7..1a4ef79f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -63,12 +63,18 @@ protected USBDeviceImpl(Object id, int vendorId, int productId) { @Override public void detachStandardDrivers() { - // Default implementation: do nothing + if (isOpen()) + throw new USBException("detachStandardDrivers() must not be called while the device is open"); + + // default implementation: do nothing } @Override public void attachStandardDrivers() { - // Default implementation: do nothing + if (isOpen()) + throw new USBException("attachStandardDrivers() must not be called while the device is open"); + + // default implementation: do nothing } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 36566119..1c145668 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -68,11 +68,15 @@ private void loadDescription(String path) { @Override public void detachStandardDrivers() { + if (isOpen()) + throwException("detachStandardDrivers() must not be called while the device is open"); detachDrivers = true; } @Override public void attachStandardDrivers() { + if (isOpen()) + throwException("attachStandardDrivers() must not be called while the device is open"); detachDrivers = false; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index b5f1d0ba..94477223 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -71,6 +71,8 @@ public class MacosUSBDevice extends USBDeviceImpl { @Override public void detachStandardDrivers() { + if (isOpen()) + throwException("detachStandardDrivers() must not be called while the device is open"); int ret = IoKitUSB.USBDeviceReEnumerate(device, IOKit.kUSBReEnumerateCaptureDeviceMask()); if (ret != 0) throwException(ret, "failed to detach kernel drivers"); @@ -78,6 +80,8 @@ public void detachStandardDrivers() { @Override public void attachStandardDrivers() { + if (isOpen()) + throwException("attachStandardDrivers() must not be called while the device is open"); int ret = IoKitUSB.USBDeviceReEnumerate(device, IOKit.kUSBReEnumerateReleaseDeviceMask()); if (ret != 0) throwException(ret, "failed to attach kernel drivers"); From 065e00fdc5b9d0373814118857bd0b8f7d28de24 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 3 Jul 2023 22:12:04 +0200 Subject: [PATCH 237/433] e-paper display: Typo in README --- examples/epaper_display/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/epaper_display/README.md b/examples/epaper_display/README.md index 95b62de2..79ccc00c 100644 --- a/examples/epaper_display/README.md +++ b/examples/epaper_display/README.md @@ -66,7 +66,7 @@ Display size: 1200 x 825 [INFO] ------------------------------------------------------------------------ ``` -### Run the sample on macOS +### Run on macOS In order to run the sample with root privileges, the best approach is to build it first without root privileges and then run it as root without Maven: @@ -81,6 +81,6 @@ $ sudo -i Password: $ cd /Users/me/Documents/JavaDoesUSB/examples/epaper_display $ export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-20.jdk/Contents/Home -$ JAVA_HOME/bin/java --enable-preview --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/0.5.1/java-does-usb-0.5.1.jar net.codecrete.usb.examples.EPaperDisplay +$ $JAVA_HOME/bin/java --enable-preview --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/0.5.1/java-does-usb-0.5.1.jar net.codecrete.usb.examples.EPaperDisplay Display size: 1200 x 825 ``` From 93abac5028aba958659f4737088e2c60116d59ba Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 3 Jul 2023 22:38:04 +0200 Subject: [PATCH 238/433] Increase version number to 0.5.1 --- README.md | 4 ++-- examples/bulk_transfer/README.md | 2 +- examples/bulk_transfer/pom.xml | 4 ++-- examples/enumerate/README.md | 2 +- examples/enumerate/pom.xml | 4 ++-- examples/monitor/README.md | 2 +- examples/monitor/pom.xml | 4 ++-- examples/stm_dfu/README.md | 2 +- examples/stm_dfu/pom.xml | 4 ++-- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index d6b0ce23..dd1efd41 100644 --- a/README.md +++ b/README.md @@ -41,14 +41,14 @@ If you are using Maven, add the below dependency to your pom.xml: net.codecrete.usb java-does-usb - 0.5.0 + 0.5.1 ``` If you are using Gradle, add the below dependency to your build.gradle file: ```groovy -compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '0.5.0' +compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '0.5.1' ``` ```java diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index 246ad9cd..b7f63b11 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] --------------< net.codecrete.usb.examples:bulk-transfer >-------------- -[INFO] Building bulk-transfer 0.5.0 +[INFO] Building bulk-transfer 0.5.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ bulk-transfer --- diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index 272b483f..721b0b3a 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples bulk-transfer - 0.5.0 + 0.5.1 bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.5.0 + 0.5.1 diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index ec4dcf7c..78867753 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] ----------------< net.codecrete.usb.examples:enumerate >---------------- -[INFO] Building enumerate 0.5.0 +[INFO] Building enumerate 0.5.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ enumerate --- diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index c5a66cd9..ceac2fee 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples enumerate - 0.5.0 + 0.5.1 enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.5.0 + 0.5.1 diff --git a/examples/monitor/README.md b/examples/monitor/README.md index 18979fcb..6c1c892b 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -----------------< net.codecrete.usb.examples:monitor >----------------- -[INFO] Building monitor 0.5.0 +[INFO] Building monitor 0.5.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ monitor --- diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index 32fbfcbe..b4075b7b 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples monitor - 0.5.0 + 0.5.1 monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.5.0 + 0.5.1 diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index 0b22186d..2b4d3982 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -57,7 +57,7 @@ SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE="0666" Run the command below (adapting the file path depending on your specific board): ```shell -$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.5.0.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin +$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.5.1.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin DFU device found with serial 35A737883336. Target memory segment: Internal Flash Erasing page at 0x8000000 (size 0x4000) diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index 8ad9f2be..19df9cfd 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples stm_dfu - 0.5.0 + 0.5.1 stm_dfu https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu @@ -19,7 +19,7 @@ net.codecrete.usb java-does-usb - 0.5.0 + 0.5.1 From 3b83cf5cc3946dd5e91b52b011a329c1127e9807 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 3 Jul 2023 22:45:34 +0200 Subject: [PATCH 239/433] Update loopback firmware --- .../loopback-stm32/bin/blackpill-f401cc.bin | Bin 10840 -> 10956 bytes .../loopback-stm32/bin/blackpill-f411ce.bin | Bin 10844 -> 10960 bytes .../loopback-stm32/bin/bluepill-f103c8.bin | Bin 11068 -> 11100 bytes .../loopback-stm32/bin/disco_f723ie.bin | Bin 11616 -> 11744 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/test-devices/loopback-stm32/bin/blackpill-f401cc.bin b/test-devices/loopback-stm32/bin/blackpill-f401cc.bin index bcc55d390551f4d8c8fddef7c6270e880aa20a9d..852fc6dd8e7a0b2ef44b5af8e73ebd19a406a426 100755 GIT binary patch delta 2705 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 VSkva}@C%!S|0w}}pYbPR`X?{CGo%0j delta 2555 zcmZuz4Ny~87QQzxKQEA!K!A{h)R#PvpHzwH)=*?Yz$fI{20^!?9r@{4V8`xY-JSZg zyNNnGg>jvVw{F$cuGO(RYb}rrQ=vr@2pzG3<0sfPSoN4LYP67VpRAZ22RpluyMZoJnRGisMG28v!_jN^*bl+)R zH|P~0phy5HU6;B{y$tZ5M(CCu#W6P^)@Yq_1Z^!uIi#dDfM1W=6c+d^)UKFSxH}3y zg0y=Q)W?% z@Mfe{W~hB)_kFTR8WkvWX4i?5u9h{ozw@?)y$`!AubCQKqRU zpAc+{R}B9G^(vE+*oc}1Hb|Lj0YCag^;EJLjVb3VGJ3_Z3RzWKAw&mNhHP!nsGPVq z$eEN^uH9<^b1x67aKHwpm8_L{xi*s-LWjve!U~k5rr}jorS{0Nfg&1F=fZE0I%Z+jMI|7i3XsiRaz@KQ z22jb^r_zWc81QE^R_s$V_UXo%=I;O2nEyW-Pq2mxk*orgpH2vsM~fjaa-a#mqK#tCCGVCBj0zR!)8k0U>rPN>}Dmj$&!IN#?7du@z^32`orFIh@JmFw!N zs{(M+lhLFJfM2zObSp_aahmk4M#Fyw%qO=;Be5WoS@gV*65uw}|iYFUUO zwB=@aImOKb&0>K#SJ&E5o4ySlvL!k7XS=!SuKWF z%pl%cW_l4l$#+Tl=a@sA7^b^XrOov;G;_vy_i0uEKkQgrEkm76zi!eLB~E&4b}&Rp zAzL)yp7d62tTSx!mw9c#3iuV%oi0G@n>$?k<`Ds8+9sp*7cjr+|F{^8_j}zu)L#%% zoof1mkm$T1=$yw`oy`MG-kgO;+4t)M^>|et%@f20Iqn=pv*>y7bF`dJ)pYC<=IC|_ z4o5WnJ=#p$NNEBO{)UeHXAnUBw9WHe@@e$_T3VGoOwt=`-@!=DLjV^SIv4SS=2#u^T+;lLUWXeDS#`pR?c<|wDE7!EYi zyp9Oe$$T}{`M)IiII?dd#^~vrC@F#Y3OgA8$vb*q&%X@n!4*&qLcjo&p^|twe^3DS zVjk3=$2^Ub(W^NLio{TToa&LcvVe_mOlUOLuC9HrDS_9?1_pmt9=qvCr_3kYH!6I6 zyQtb;YGBM;YNobF-d+O6&v}W^$HW>Chf}U3p&rn&&4H$pr?y!M@bEN(=?4AFED?&; zgETc#_7#0R25_H?5g=lUV{gEBpVs!CTiHV0e`Heq=*?3~fE#DN1TRjurj<9{c7 z`K3dG&a7`;WAgd++fF?MaR&!uUGXi41>jv{`inq1_Hv*%4OOR`Go*Yce5>)jaX;7( z`^V%7?#JTqG45M(AI$gpH!hJQ%b*c)={cU&g3Q5|x^VkBr|{hp04NdUu?lpJllJgT zvhBgAd}(|B`j1?w*z>r!{klNrmyJ_0eR1Jre!HHh;u3qUG^GEE=X1H8thw<9EdUhZ#EK0@3?>W63^p244mRrKGeZ) zioR3j4Z9yOMpZ}+2L;khs%8zV<@1J}>o>Ax<0RZyjCy99lGm3@SwUPR#t0x~5V0p3 zPM<;loSp1Bja@0~1iRyzRrpp`Ou<)AaisMs_ZBNHVM}9=8(Xz)&l2qZX!I$&?=o48n_LPt{E4~W;4p%{Whi_o7lGRQCQEEvs%3A;c diff --git a/test-devices/loopback-stm32/bin/bluepill-f103c8.bin b/test-devices/loopback-stm32/bin/bluepill-f103c8.bin index 456927607a8d7fe1cc0d196bb445325dcb63e781..c39ace153c40dff9461930563882c6635ae41917 100755 GIT binary patch delta 947 zcmaJ=U1$_n6h3FOGjrGMy0dOp)1=i&Ho9?FV=F#To~9P8^UXSZFBF>s_u!=2^)8)23zyTHKoVD5eSy7r#Ie0n z#qmm$4uF~quLZZM64bLpM>TNm^1cyaDBZQ$e&`?mp|jc1bbCVWI6CZ~{*+g3a3%tv z2>?ya&EnitCA2=7J^Of7w0aDg^KH3pq%m97y%|vRGr0}Un#oa&dg=;B@pIZ1T#!*c z_y&_b&*8&px5~B7l{FpQ*wpL|vo}W9Lqm`2y$SA*FTBzxbTSyngOm%VLIa*XAv*ln zgW$47yF9OS$cq^DSzM9ntSR^v>dOKB(-GAD-rKl?>O8$8HMIuHRYq;USNdSOzL7%_7S^sAoHIt>gp9Zm-rSs*u!N6pd32V)+ zaE88@J43yE>~BA!M{+AB=nW+$6*=}Zbt}iQjczJQyi6743!J3Gq7_GJNW69AGYP~H z!^{Qsh>kjFb9tO4mF6MYsNXlHz+Z5|w5{Q^-oSd8tVcfYK7qUc=GXiWzxaypm9DW6 z_Z|NRaHsNKsq6?twT#eU00-!4^;Nu0PPi8btVHDPDr}@4^*DY^chs*JK8}O9#TZo? z)An=>gfi{_#{L)`i|s^{#$)Z+La8|iA~_j^-{~WsZjc7&Y-``n{4W`&7}vR$k8{(p znf-s+z0C1S7imR&DW0Le_yRm-9gBa3_&Y@t^Y9X-5-X)&`MLu2CAQ#U%T6c(TxyNZ zyD3YV42UM{83BnO`Eh;CeoG7AIsVoH98q(4l06e|8Zrk=^q74 z=~^pe5hk>p$u~f$ z(ne-A4d6~VTS52bY-)V`oC5l#Y=2Tj<+hS|3!I(!CR~$N)YOu@<=ljM`o(p33erm! zPy~SDPB^%>I43#+@u6_uKgf#VY+bT4Zf!%wtOET5uGrGc(XxIBNz`S_#}BE;R?+M+ z;4=(#t-#@JZEo&0mQ_^Ht!o9H1#fTb0DqTm)Perxx{*0)g!*6Y|E2VN_{p?)pE3~Y zGcqSAX{&a8Wu%rw3oGb>t@f2ehLJgKxT0lod_5HQO_}{%S&KT5MAe++HGb22lA5Hd z`ju5{wB)Rj>E3K`G`%rYUaOOfE@q)pL{Ta21ASptex`hrMx}bGnyr&*QaW{TIbCAE zJ##m13(ZdX)f&~=o?43W1-bMK_9rt_i>3BIX70yf_wQ3O4_BMDNBwGfUyZu3h)Rr& zycqF16cYpHoZ(a~d=6g4@8Al31EP6I_ zKk)h|8Y}F@k4W}3;~Nz59CwY|LFmhH=N`ZKTl&@WUh`hAJ;Dqzm${e8=bO2${r|vQIB^QrfAq(f#cek_hZDrsJ5sW|D;G!qm<(7CTY0n0QPG0MY085+P&hx?NWXS zgiX6q9>{n3c)3Lh{kvmP`kFnzNb|wk!cG}P7t<&}^fK?zOQDeOv=hWi9{&&E1oJbP Er|*J29{>OV diff --git a/test-devices/loopback-stm32/bin/disco_f723ie.bin b/test-devices/loopback-stm32/bin/disco_f723ie.bin index 8b399eba27fa8e1a4f0ab86c184c4c97d2fc5b86..1567e9e69d1836b83efbef599a18923f8a7ab3fd 100755 GIT binary patch delta 3037 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 ADgXcg delta 2927 zcmZ`*e^3)w9)E8)KQ`f4NWg@IU|^wA0~+P5XmkVu+rZMJitPdRu0h8E+Fp;ge@N@p zfSsP9)>?hzRLFUC&UR|gt3W6>Od`+nZ{``Pb)-*@-Yrb`WnsjOiqVweG%xAoDLw6|v(wKIbVez^!ahMgpfD$Cjy zLt^c0>%9o693_Q_0jt9?kJbdTgW5@rJNqemIZa)4l6y3(w-yc|WEe>FBJs~L6&L8+ z=|JMC+2%0AYbz~*64V|#T$VrN;0CW6N_K`6>)Y=d2GP)K6mo!jhhacht%Kd~#Mr=d zW%_XpjMryf;hX?=(3Q$AB<>>TGC%%IJNN<=Vg@EYzzVpYuWbL=ow zBhh;cW!H$Z3yGKGa@0>swI;lsJfK~q3(A96nG!krGRenr@#`FiY|fXaDcG^r|^%Lo6hC0HyCXK1F!Mg^MjL2G@r}QQ~ROKoGSj+$t zO)XOn89>dZ&P)Zi?5I~ z`VKIzPbk9Qk>?Xu{vwq@OeLUoK*c3-n8S_*kcR45akxLUn9GK1<>ruh@x9i;|KzOx zAC3$hIeH!vH9?9J_uyyA2Z^h&kIW@@X4qsGNA(U~6?f@uouRYB2JUXIn8RWUIg~Vj z-zK%mm+hW-4y^VDS0?*OCe zfcY`J05PWd`4=!30IH)(-5-*ShI~k99hqFfV=q~0UWaGMHuDon_vsKL{u5p5faI?w zH_S`%0g`7~v~DZ-*$e0aT!0t~PR_60x&Eo~H^7mj0kYdtxN4V#^4HCDANK^l720^@ zTsPBoT#i02O$&oknn8{}FHxMrc-qt4We=C8VXoHVPU1YKT}fci?@bE3;lVHrJl5-1i8X%e0d~ z)>k?Ubf1SXay&@V?Vn%^xom%fv@Xnr*@1;c@PBHdEkog`c!aHWpG&G@k4VuU!q|GR zh1^;gq--+jcFd$4j*m$Qj5NJlKtq=PL)mT&`_JXn`j!2^g&1BybRZGR#*gjXMQP*k zw>k}{nk=PlIB}BJR!g)4v1>cF`__jO`5caw((cDBIv_{KV$h{}#lg1DfjM!CgwULE z!~PHzP733qU5o}8$^uo2s#1#AOdL9e5^~ZtPxQnHOYapPc5YqJ>1yYr;y0ex@9a81U(aU5{F8@O^6^fD! zgc^EddtaakB8ci-D)SA`bYc4t0plEZ9$)* zdNhH|NHgh4#YLkMa+Zl`^9L~61&XZ~`de7h&48m11?`RY4Qu(-W@B@Pufg|Zi%~RC zXGT|4CbS*t(@m;r2#U;5!o!zr&pbT4Gq$AyO%0KKi|qbz`)1l0ndkUWuI(8$(cCa> z(U2^jo=h<5$mNhaxEr3At|LY1ynCsjcG6=Rmke%?IPCcd#&-oOcu}f8yb05!w!E&{ z*I&kgqV@6U;aCz+cXwNAJ3SR|oTG#8@-HNV&D6Qc8Vs2_sBW}r@$W|URjGkZ);~&& zYY<>+CxTK|O3^9Bwh^EdUo}8EF?6tI;vla1UfuyA9%_Iyc>0>ks0w0tF!WS~ir7aj zA`NGu1Cih7=lZE&18$Hgm#4f6{*Mak;8zkt9!Zs;CS#x*IsG%$J?~scDgGI6kNYuF zMaul&dwRZ<7`J!IL7B?d&8+D$iH?-Cp==hje}(lT;RW8-Jg)WMSlWY56bQ+aWtn*S z`;vaRsiJtOiCZqr=d%_0?;;Y@J{5Yo!vFmmaB3;mTsPoPN-k(uMQSEEt9DY4MvFfisTo!gJ^9yS&+;mG3tP)qH;xFZgZE1+o9bnT z`wWWVte|sktWlcVof=bWFDBE7R6E~KDu!abgEjr>1uL5jVip3D c5}*?TvdO+eciN#;#PsUnGZw*%AAU06-_&eTl>h($ From 3755159ec4345788056b10f0aade97f8dff5f0ea Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 25 Jul 2023 17:36:49 +0200 Subject: [PATCH 240/433] transferOut() with offset and length --- .../java/net/codecrete/usb/USBDevice.java | 25 ++++++++++++++++++- .../codecrete/usb/common/USBDeviceImpl.java | 9 +++++-- .../codecrete/usb/linux/LinuxUSBDevice.java | 6 ++--- .../codecrete/usb/macos/MacosUSBDevice.java | 8 +++--- .../usb/windows/WindowsUSBDevice.java | 4 +-- 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index 1dfc2103..a9ba17d2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -293,11 +293,34 @@ public interface USBDevice { *

* * @param endpointNumber the endpoint number (in the range between 1 and 127) - * @param timeout the timeout period, in milliseconds (0 for no timeout) * @param data data to send + * @param timeout the timeout period, in milliseconds (0 for no timeout) */ void transferOut(int endpointNumber, byte[] data, int timeout); + /** + * Sends data to this device. + *

+ * This method blocks until the data has been sent, the timeout period has expired + * or an error has occurred. If the timeout expires, a {@link USBTimeoutException} is thrown. + *

+ *

+ * This method can send data to bulk and interrupt endpoints. + *

+ *

+ * If the sent data length is a multiple of the packet size, it is often + * required to send an additional zero-length packet (ZLP) for the device + * to actually process the data. This method will not do it automatically. + *

+ * + * @param endpointNumber the endpoint number (in the range between 1 and 127) + * @param data buffer containing data to send + * @param offset offset of the first byte to send + * @param length number of bytes to send + * @param timeout the timeout period, in milliseconds (0 for no timeout) + */ + void transferOut(int endpointNumber, byte[] data, int offset, int length, int timeout); + /** * Receives data from this device. *

diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 1a4ef79f..05419a04 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -320,11 +320,16 @@ protected int getInterfaceNumber(USBDirection direction, int endpointNumber) { @Override public void transferOut(int endpointNumber, byte[] data) { - transferOut(endpointNumber, data, 0); + transferOut(endpointNumber, data, 0, data.length, 0); } @Override - public abstract void transferOut(int endpointNumber, byte[] data, int timeout); + public void transferOut(int endpointNumber, byte[] data, int timeout) { + transferOut(endpointNumber, data, 0, data.length, timeout); + } + + @Override + public abstract void transferOut(int endpointNumber, byte[] data, int offset, int length, int timeout); @Override public byte[] transferIn(int endpointNumber) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 1c145668..318a9950 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -271,10 +271,10 @@ private LinuxTransfer createSyncCtrlTransfer(Arena arena, USBDirection direction } @Override - public void transferOut(int endpointNumber, byte[] data, int timeout) { + public void transferOut(int endpointNumber, byte[] data, int offset, int length, int timeout) { try (var arena = Arena.openConfined()) { - var buffer = arena.allocate(data.length); - buffer.copyFrom(MemorySegment.ofArray(data)); + var buffer = arena.allocate(length); + buffer.copyFrom(MemorySegment.ofArray(data).asSlice(offset, length)); var transfer = createSyncTransfer(buffer); synchronized (transfer) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 94477223..a321fad4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -412,18 +412,18 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { } @Override - public void transferOut(int endpointNumber, byte[] data, int timeout) { + public void transferOut(int endpointNumber, byte[] data, int offset, int length, int timeout) { EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); try (var arena = Arena.openConfined()) { - var nativeData = arena.allocateArray(JAVA_BYTE, data.length); - nativeData.copyFrom(MemorySegment.ofArray(data)); + var nativeData = arena.allocateArray(JAVA_BYTE, length); + nativeData.copyFrom(MemorySegment.ofArray(data).asSlice(offset, length)); var transfer = new MacosTransfer(); transfer.data = nativeData; - transfer.dataSize = data.length; + transfer.dataSize = length; transfer.completion = USBDeviceImpl::onSyncTransferCompleted; synchronized (transfer) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 21598ba3..4d9efa38 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -244,10 +244,10 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { } @Override - public void transferOut(int endpointNumber, byte[] data, int timeout) { + public void transferOut(int endpointNumber, byte[] data, int offset, int length, int timeout) { try (var arena = Arena.openConfined()) { var buffer = arena.allocate(data.length); - buffer.copyFrom(MemorySegment.ofArray(data)); + buffer.copyFrom(MemorySegment.ofArray(data).asSlice(offset, length)); var transfer = createSyncTransfer(buffer); synchronized (transfer) { From e7281a1fb25261df24793e09a7a99bce45edde19 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 25 Jul 2023 17:37:39 +0200 Subject: [PATCH 241/433] Reference code: detach standard drivers for macOS --- reference/macos/USB/usb_device.cpp | 16 ++++++++++++++++ reference/macos/USB/usb_device.hpp | 26 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/reference/macos/USB/usb_device.cpp b/reference/macos/USB/usb_device.cpp index 47f8aab3..d2e80d33 100644 --- a/reference/macos/USB/usb_device.cpp +++ b/reference/macos/USB/usb_device.cpp @@ -85,6 +85,22 @@ const usb_endpoint& usb_device::get_endpoint(usb_direction direction, int endpoi return usb_endpoint::invalid; } +void usb_device::detach_standard_drivers() { + if (is_open()) + throw usb_error("detach_standard_drivers() must not be called when the device is open", 0); + + IOReturn ret = (*device_)->USBDeviceReEnumerate(device_, kUSBReEnumerateCaptureDeviceMask); + usb_error::check(ret, "failed to detach standard drivers"); +} + +void usb_device::attach_standard_drivers() { + if (is_open()) + throw usb_error("attach_standard_drivers() must not be called when the device is open", 0); + + IOReturn ret = (*device_)->USBDeviceReEnumerate(device_, kUSBReEnumerateReleaseDeviceMask); + usb_error::check(ret, "failed to attach standard drivers"); +} + bool usb_device::is_open() const { return is_open_; diff --git a/reference/macos/USB/usb_device.hpp b/reference/macos/USB/usb_device.hpp index adb0a73d..788ac588 100644 --- a/reference/macos/USB/usb_device.hpp +++ b/reference/macos/USB/usb_device.hpp @@ -108,6 +108,32 @@ class usb_device { */ const usb_interface& get_interface(int interface_number) const; + /** + * Detaches the standard drivers of the operating system. + * + * By detaching the standard drivers, the operating system releases the exclusive access + * to the device and/or its interfaces. It is relevant for USB devices implementing standard + * USB classes such as HID, CDC or mass storage. + * + * Executing this function requires either root privileges or the _com.apple.vm.device-access_ entitlement. + * + * This method should be called before the device is opened. After the device has been closed, + * `attach_standard_drivers()` should be called to restore the initial state. + */ + void detach_standard_drivers(); + + /** + * Attaches the standard drivers of the operating system. + * + * By attaching the standard drivers, the original state before `detach_standard_drivers()` was called + * is restored. + * + * Executing this function requires either root privileges or the _com.apple.vm.device-access_ entitlement. + * + * This method should be called after the device has been closed. + */ + void attach_standard_drivers(); + /** * Get a USB endpoint. * From fd5d64850905cb3deb28c4a6dde8e334630208a5 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 25 Jul 2023 20:29:35 +0200 Subject: [PATCH 242/433] Linux: upgrade to JDK 21 --- java-does-usb/pom.xml | 12 +- .../usb/common/EndpointInputStream.java | 2 +- .../usb/common/EndpointOutputStream.java | 2 +- .../java/net/codecrete/usb/linux/Linux.java | 8 +- .../codecrete/usb/linux/LinuxAsyncTask.java | 22 +-- .../codecrete/usb/linux/LinuxUSBDevice.java | 28 +-- .../usb/linux/LinuxUSBDeviceRegistry.java | 5 +- .../usb/linux/gen/errno/Constants$root.java | 21 --- .../usb/linux/gen/errno/RuntimeHelper.java | 26 ++- .../usb/linux/gen/errno/constants$0.java | 11 ++ .../codecrete/usb/linux/gen/errno/errno.java | 18 +- .../usb/linux/gen/fcntl/Constants$root.java | 21 --- .../usb/linux/gen/fcntl/RuntimeHelper.java | 26 ++- .../usb/linux/gen/fcntl/constants$0.java | 11 ++ .../codecrete/usb/linux/gen/fcntl/fcntl.java | 18 +- .../usb/linux/gen/poll/Constants$root.java | 21 --- .../usb/linux/gen/poll/RuntimeHelper.java | 26 ++- .../usb/linux/gen/poll/constants$0.java | 25 ++- .../codecrete/usb/linux/gen/poll/poll.java | 19 +- .../codecrete/usb/linux/gen/poll/pollfd.java | 47 +++-- .../usb/linux/gen/string/Constants$root.java | 21 --- .../usb/linux/gen/string/RuntimeHelper.java | 26 ++- .../usb/linux/gen/string/constants$0.java | 10 +- .../usb/linux/gen/string/string.java | 19 +- .../usb/linux/gen/udev/Constants$root.java | 21 --- .../usb/linux/gen/udev/RuntimeHelper.java | 28 ++- .../usb/linux/gen/udev/constants$0.java | 43 ++--- .../usb/linux/gen/udev/constants$1.java | 54 ++---- .../usb/linux/gen/udev/constants$2.java | 61 +++--- .../usb/linux/gen/udev/constants$3.java | 27 ++- .../codecrete/usb/linux/gen/udev/udev.java | 55 +++--- .../usb/linux/gen/unistd/Constants$root.java | 21 --- .../usb/linux/gen/unistd/RuntimeHelper.java | 26 ++- .../usb/linux/gen/unistd/constants$0.java | 10 +- .../usb/linux/gen/unistd/unistd.java | 19 +- .../gen/usbdevice_fs/Constants$root.java | 21 --- .../linux/gen/usbdevice_fs/RuntimeHelper.java | 26 ++- .../linux/gen/usbdevice_fs/constants$0.java | 31 +++ .../linux/gen/usbdevice_fs/constants$1.java | 28 +++ .../linux/gen/usbdevice_fs/constants$2.java | 49 +++++ .../linux/gen/usbdevice_fs/constants$3.java | 19 ++ .../linux/gen/usbdevice_fs/constants$4.java | 19 ++ .../linux/gen/usbdevice_fs/constants$6.java | 14 ++ .../usbdevice_fs/usbdevfs_bulktransfer.java | 60 +++--- .../usbdevice_fs/usbdevfs_ctrltransfer.java | 96 ++++------ .../usbdevfs_disconnect_claim.java | 36 ++-- .../gen/usbdevice_fs/usbdevfs_ioctl.java | 47 +++-- .../usbdevice_fs/usbdevfs_setinterface.java | 35 ++-- .../linux/gen/usbdevice_fs/usbdevfs_urb.java | 176 +++++++----------- .../linux/gen/usbdevice_fs/usbdevice_fs.java | 18 +- 50 files changed, 754 insertions(+), 731 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/Constants$root.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/Constants$root.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/Constants$root.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/Constants$root.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$1.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$2.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$3.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$4.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$6.java diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 492f905e..2f0a2926 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -9,8 +9,8 @@ 0.5.1 - 20 - 20 + 21 + 21 UTF-8 @@ -56,12 +56,12 @@ maven-compiler-plugin 3.11.0 - 20 + 21 --enable-preview - 20 - 20 + 21 + 21 @@ -85,7 +85,7 @@ - 20 + 21 --enable-preview ${java.home}/bin/javadoc diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index b9b68f13..188093e8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -61,7 +61,7 @@ public abstract class EndpointInputStream extends InputStream { protected EndpointInputStream(USBDeviceImpl device, int endpointNumber, int bufferSize) { this.device = device; this.endpointNumber = endpointNumber; - arena = Arena.openShared(); + arena = Arena.ofShared(); int packetSize = device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java index 294a3acb..e70b2d29 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -63,7 +63,7 @@ public abstract class EndpointOutputStream extends OutputStream { protected EndpointOutputStream(USBDeviceImpl device, int endpointNumber, int bufferSize) { this.device = device; this.endpointNumber = endpointNumber; - arena = Arena.openShared(); + arena = Arena.ofShared(); packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java index 0c714427..c01344a1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java @@ -10,8 +10,9 @@ import net.codecrete.usb.linux.gen.string.string; import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemoryLayout.PathElement; import java.lang.foreign.MemorySegment; +import java.lang.foreign.StructLayout; import java.lang.invoke.VarHandle; /** @@ -22,9 +23,10 @@ public class Linux { /** * Call state for capturing the {@code errno} value. */ - public static final Linker.Option.CaptureCallState ERRNO_STATE = Linker.Option.captureCallState("errno"); + public static final Linker.Option ERRNO_STATE = Linker.Option.captureCallState("errno"); + public static final StructLayout ERRNO_STATE_LAYOUT = Linker.Option.captureStateLayout(); private static final VarHandle callState_errno$VH = - ERRNO_STATE.layout().varHandle(MemoryLayout.PathElement.groupElement("errno")); + ERRNO_STATE_LAYOUT.varHandle(PathElement.groupElement("errno")); /** * Gets the error message for the specified error code (returned by {@code errno}). diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index b157039f..04d39924 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -56,7 +56,7 @@ static synchronized LinuxAsyncTask instance() { return singletonInstance; } - private final Arena urbArena = Arena.openShared(); + private final Arena urbArena = Arena.ofShared(); /// available URBs private final List availableURBs = new ArrayList<>(); /// map of URB addresses to transfer (for outstanding transfers) @@ -79,8 +79,8 @@ static synchronized LinuxAsyncTask instance() { */ private void asyncCompletionTask() { - try (var arena = Arena.openConfined()) { - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); + try (var arena = Arena.ofConfined()) { + var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); var asyncPolls = pollfd.allocateArray(100, arena); var urbPointerHolder = arena.allocate(ADDRESS); var eventfdValueHolder = arena.allocate(JAVA_LONG); @@ -181,8 +181,8 @@ private void notifyAsyncIOTask() { return; } - try (var arena = Arena.openConfined()) { - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); + try (var arena = Arena.ofConfined()) { + var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); if (IO.eventfd_write(asyncIOWakeUpEventFd, 1, errnoState) < 0) throwLastError(errnoState, "internal error (eventfd_write)"); } @@ -247,8 +247,8 @@ synchronized void submitTransfer(LinuxUSBDevice device, int endpointAddress, USB usbdevfs_urb.buffer_length$set(urb, transfer.dataSize); usbdevfs_urb.usercontext$set(urb, MemorySegment.ofAddress(device.fileDescriptor())); - try (var arena = Arena.openConfined()) { - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); + try (var arena = Arena.ofConfined()) { + var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); if (IO.ioctl(device.fileDescriptor(), SUBMITURB, urb, errnoState) < 0) { String action = endpointAddress >= 128 ? "reading from" : "writing to"; String endpoint = endpointAddress == 0 ? "control endpoint" : String.format("endpoint %d", endpointAddress); @@ -294,9 +294,9 @@ private synchronized LinuxTransfer getTransferResult(MemorySegment urb) { synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { int fd = device.fileDescriptor(); - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); // iterate all URBs and discard the ones for the specified endpoint for (var urb : transfersByURB.keySet()) { @@ -315,8 +315,8 @@ synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { } private void startAsyncIOTask() { - try (var arena = Arena.openConfined()) { - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); + try (var arena = Arena.ofConfined()) { + var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); asyncIOWakeUpEventFd = IO.eventfd(0, 0, errnoState); if (asyncIOWakeUpEventFd == -1) { asyncIOWakeUpEventFd = 0; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 318a9950..e8fe1153 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -90,9 +90,9 @@ public synchronized void open() { if (isOpen()) throwException("the device is already open"); - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var pathUtf8 = arena.allocateUtf8String(uniqueDeviceId.toString()); - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); fd = IO.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC(), errnoState); if (fd == -1) throwLastError(errnoState, "Cannot open USB device"); @@ -127,8 +127,8 @@ public synchronized void claimInterface(int interfaceNumber) { if (intf.isClaimed()) throwException("Interface %d has already been claimed", interfaceNumber); - try (var arena = Arena.openConfined()) { - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); + try (var arena = Arena.ofConfined()) { + var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); int ret; if (detachDrivers) { @@ -169,11 +169,11 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna throwException("Interface %d does not have an alternate interface setting %d", interfaceNumber, alternateNumber); - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var setIntfSegment = arena.allocate(usbdevfs_setinterface.$LAYOUT()); usbdevfs_setinterface.interface_$set(setIntfSegment, interfaceNumber); usbdevfs_setinterface.altsetting$set(setIntfSegment, alternateNumber); - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); int ret = IO.ioctl(fd, USBDevFS.SETINTERFACE, setIntfSegment, errnoState); if (ret != 0) throwLastError(errnoState, "Failed to set alternate interface"); @@ -191,9 +191,9 @@ public synchronized void releaseInterface(int interfaceNumber) { if (!intf.isClaimed()) throwException("Interface %d has not been claimed", interfaceNumber); - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); int ret = IO.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment, errnoState); if (ret != 0) throwLastError(errnoState, "Cannot release USB interface"); @@ -213,7 +213,7 @@ public synchronized void releaseInterface(int interfaceNumber) { @Override public void controlTransferOut(USBControlTransfer setup, byte[] data) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { int dataLength = data != null ? data.length : 0; var transfer = createSyncCtrlTransfer(arena, USBDirection.OUT, setup, dataLength); if (dataLength != 0) @@ -228,7 +228,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { @Override public byte[] controlTransferIn(USBControlTransfer setup, int length) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var transfer = createSyncCtrlTransfer(arena, USBDirection.IN, setup, length); synchronized (transfer) { @@ -272,7 +272,7 @@ private LinuxTransfer createSyncCtrlTransfer(Arena arena, USBDirection direction @Override public void transferOut(int endpointNumber, byte[] data, int offset, int length, int timeout) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var buffer = arena.allocate(length); buffer.copyFrom(MemorySegment.ofArray(data).asSlice(offset, length)); var transfer = createSyncTransfer(buffer); @@ -288,7 +288,7 @@ public void transferOut(int endpointNumber, byte[] data, int offset, int length, public byte[] transferIn(int endpointNumber, int timeout) { var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var buffer = arena.allocate(endpoint.packetSize()); var transfer = createSyncTransfer(buffer); @@ -333,9 +333,9 @@ protected void throwOSException(int errorCode, String message, Object... args) { public void clearHalt(USBDirection direction, int endpointNumber) { var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var endpointAddrSegment = arena.allocate(JAVA_INT, endpoint.endpointAddress() & 0xff); - var errnoState = arena.allocate(Linux.ERRNO_STATE.layout()); + var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); int res = IO.ioctl(fd, USBDevFS.CLEAR_HALT, endpointAddrSegment, errnoState); if (res < 0) throwLastError(errnoState, "Clearing halt failed"); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 20e2c537..ac9be5d9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -17,7 +17,6 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SegmentScope; import java.util.ArrayList; import java.util.List; @@ -28,7 +27,7 @@ */ public class LinuxUSBDeviceRegistry extends USBDeviceRegistry { - private final SegmentAllocator GLOBAL_ALLOCATOR = SegmentAllocator.nativeAllocator(SegmentScope.global()); + private final SegmentAllocator GLOBAL_ALLOCATOR = Arena.global(); private final MemorySegment SUBSYSTEM_USB = GLOBAL_ALLOCATOR.allocateUtf8String("usb"); private final MemorySegment MONITOR_NAME = GLOBAL_ALLOCATOR.allocateUtf8String("udev"); private final MemorySegment DEVTYPE_USB_DEVICE = GLOBAL_ALLOCATOR.allocateUtf8String("usb_device"); @@ -77,7 +76,7 @@ protected void monitorDevices() { // monitor device changes //noinspection InfiniteLoopStatement while (true) { - try (var arena = Arena.openConfined(); var cleanup = new ScopeCleanup()) { + try (var arena = Arena.ofConfined(); var cleanup = new ScopeCleanup()) { // wait for next change waitForFileDescriptor(fd, arena); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/Constants$root.java deleted file mode 100644 index 495f0826..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.errno; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfLong C_LONG$LAYOUT = JAVA_LONG; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/RuntimeHelper.java index df62e601..f46e44cf 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/RuntimeHelper.java @@ -15,9 +15,10 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { @@ -36,7 +37,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -55,18 +58,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java new file mode 100644 index 00000000..d06cfe72 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java @@ -0,0 +1,11 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.errno; + +final class constants$0 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java index 7f9506df..5db1b041 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -2,17 +2,19 @@ package net.codecrete.usb.linux.gen.errno; +import java.lang.foreign.AddressLayout; + import static java.lang.foreign.ValueLayout.*; public class errno { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfLong C_LONG = JAVA_LONG; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; /** * {@snippet : * #define EAGAIN 11 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/Constants$root.java deleted file mode 100644 index 0d01265b..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.fcntl; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfLong C_LONG$LAYOUT = JAVA_LONG; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/RuntimeHelper.java index a8fb98e4..6b36ff84 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/RuntimeHelper.java @@ -15,9 +15,10 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { @@ -36,7 +37,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -55,18 +58,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java new file mode 100644 index 00000000..384b1450 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java @@ -0,0 +1,11 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.fcntl; + +final class constants$0 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java index 4dcd2d69..a6dd2f36 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java @@ -2,17 +2,19 @@ package net.codecrete.usb.linux.gen.fcntl; +import java.lang.foreign.AddressLayout; + import static java.lang.foreign.ValueLayout.*; public class fcntl { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfLong C_LONG = JAVA_LONG; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; /** * {@snippet : * #define O_RDWR 2 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/Constants$root.java deleted file mode 100644 index 3445f223..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.poll; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfLong C_LONG$LAYOUT = JAVA_LONG; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/RuntimeHelper.java index 7903bdec..5fdcd815 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/RuntimeHelper.java @@ -15,9 +15,10 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { @@ -36,7 +37,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -55,18 +58,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java index 910ee5dc..112fe8b5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java @@ -3,19 +3,32 @@ package net.codecrete.usb.linux.gen.poll; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.*; final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} - static final FunctionDescriptor poll$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT + static final StructLayout const$0 = MemoryLayout.structLayout( + JAVA_INT.withName("fd"), + JAVA_SHORT.withName("events"), + JAVA_SHORT.withName("revents") + ).withName("pollfd"); + static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("fd")); + static final VarHandle const$2 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("events")); + static final VarHandle const$3 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("revents")); + static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + JAVA_LONG, + JAVA_INT ); - static final MethodHandle poll$MH = RuntimeHelper.downcallHandle( + static final MethodHandle const$5 = RuntimeHelper.downcallHandle( "poll", - constants$0.poll$FUNC + constants$0.const$4 ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java index 3b99e1a0..c3002abe 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java @@ -2,20 +2,21 @@ package net.codecrete.usb.linux.gen.poll; +import java.lang.foreign.AddressLayout; import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class poll { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfLong C_LONG = JAVA_LONG; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; /** * {@snippet : * #define POLLIN 1 @@ -41,7 +42,7 @@ public static int POLLERR() { return (int)8L; } public static MethodHandle poll$MH() { - return RuntimeHelper.requireNonNull(constants$0.poll$MH,"poll"); + return RuntimeHelper.requireNonNull(constants$0.const$5,"poll"); } /** * {@snippet : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java index fe79fb38..6d632aa7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java @@ -2,7 +2,10 @@ package net.codecrete.usb.linux.gen.poll; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -15,17 +18,11 @@ */ public class pollfd { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_INT$LAYOUT.withName("fd"), - Constants$root.C_SHORT$LAYOUT.withName("events"), - Constants$root.C_SHORT$LAYOUT.withName("revents") - ).withName("pollfd"); public static MemoryLayout $LAYOUT() { - return pollfd.$struct$LAYOUT; + return constants$0.const$0; } - static final VarHandle fd$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("fd")); public static VarHandle fd$VH() { - return pollfd.fd$VH; + return constants$0.const$1; } /** * Getter for field: @@ -34,7 +31,7 @@ public class pollfd { * } */ public static int fd$get(MemorySegment seg) { - return (int)pollfd.fd$VH.get(seg); + return (int)constants$0.const$1.get(seg); } /** * Setter for field: @@ -43,17 +40,16 @@ public class pollfd { * } */ public static void fd$set(MemorySegment seg, int x) { - pollfd.fd$VH.set(seg, x); + constants$0.const$1.set(seg, x); } public static int fd$get(MemorySegment seg, long index) { - return (int)pollfd.fd$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$0.const$1.get(seg.asSlice(index*sizeof())); } public static void fd$set(MemorySegment seg, long index, int x) { - pollfd.fd$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$1.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle events$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("events")); public static VarHandle events$VH() { - return pollfd.events$VH; + return constants$0.const$2; } /** * Getter for field: @@ -62,7 +58,7 @@ public class pollfd { * } */ public static short events$get(MemorySegment seg) { - return (short)pollfd.events$VH.get(seg); + return (short)constants$0.const$2.get(seg); } /** * Setter for field: @@ -71,17 +67,16 @@ public class pollfd { * } */ public static void events$set(MemorySegment seg, short x) { - pollfd.events$VH.set(seg, x); + constants$0.const$2.set(seg, x); } public static short events$get(MemorySegment seg, long index) { - return (short)pollfd.events$VH.get(seg.asSlice(index*sizeof())); + return (short)constants$0.const$2.get(seg.asSlice(index*sizeof())); } public static void events$set(MemorySegment seg, long index, short x) { - pollfd.events$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$2.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle revents$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("revents")); public static VarHandle revents$VH() { - return pollfd.revents$VH; + return constants$0.const$3; } /** * Getter for field: @@ -90,7 +85,7 @@ public class pollfd { * } */ public static short revents$get(MemorySegment seg) { - return (short)pollfd.revents$VH.get(seg); + return (short)constants$0.const$3.get(seg); } /** * Setter for field: @@ -99,20 +94,20 @@ public class pollfd { * } */ public static void revents$set(MemorySegment seg, short x) { - pollfd.revents$VH.set(seg, x); + constants$0.const$3.set(seg, x); } public static short revents$get(MemorySegment seg, long index) { - return (short)pollfd.revents$VH.get(seg.asSlice(index*sizeof())); + return (short)constants$0.const$3.get(seg.asSlice(index*sizeof())); } public static void revents$set(MemorySegment seg, long index, short x) { - pollfd.revents$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$3.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/Constants$root.java deleted file mode 100644 index 1f613abd..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.string; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfLong C_LONG$LAYOUT = JAVA_LONG; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/RuntimeHelper.java index c0f67e19..e0a365d5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/RuntimeHelper.java @@ -15,9 +15,10 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { @@ -36,7 +37,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -55,18 +58,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/constants$0.java index dd5b8842..bfe9c830 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/constants$0.java @@ -4,16 +4,18 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} - static final FunctionDescriptor strerror$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT + static final FunctionDescriptor const$0 = FunctionDescriptor.of(RuntimeHelper.POINTER, + JAVA_INT ); - static final MethodHandle strerror$MH = RuntimeHelper.downcallHandle( + static final MethodHandle const$1 = RuntimeHelper.downcallHandle( "strerror", - constants$0.strerror$FUNC + constants$0.const$0 ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java index f123addd..895d225f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java @@ -2,22 +2,23 @@ package net.codecrete.usb.linux.gen.string; +import java.lang.foreign.AddressLayout; import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class string { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfLong C_LONG = JAVA_LONG; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; public static MethodHandle strerror$MH() { - return RuntimeHelper.requireNonNull(constants$0.strerror$MH,"strerror"); + return RuntimeHelper.requireNonNull(constants$0.const$1,"strerror"); } /** * {@snippet : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/Constants$root.java deleted file mode 100644 index c5a7e16a..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.udev; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfLong C_LONG$LAYOUT = JAVA_LONG; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java index 09317884..c2ccf243 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java @@ -15,14 +15,15 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { // System.loadLibrary("udev"); // SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so.1", SegmentScope.global()); + SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so.1", Arena.global()); SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } @@ -37,7 +38,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -56,18 +59,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java index 4e98a486..1017f6fe 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java @@ -8,46 +8,25 @@ final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} - static final FunctionDescriptor udev_new$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT); - static final MethodHandle udev_new$MH = RuntimeHelper.downcallHandle( + static final FunctionDescriptor const$0 = FunctionDescriptor.of(RuntimeHelper.POINTER); + static final MethodHandle const$1 = RuntimeHelper.downcallHandle( "udev_new", - constants$0.udev_new$FUNC + constants$0.const$0 ); - static final FunctionDescriptor udev_list_entry_get_next$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT + static final FunctionDescriptor const$2 = FunctionDescriptor.of(RuntimeHelper.POINTER, + RuntimeHelper.POINTER ); - static final MethodHandle udev_list_entry_get_next$MH = RuntimeHelper.downcallHandle( + static final MethodHandle const$3 = RuntimeHelper.downcallHandle( "udev_list_entry_get_next", - constants$0.udev_list_entry_get_next$FUNC + constants$0.const$2 ); - static final FunctionDescriptor udev_list_entry_get_name$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle udev_list_entry_get_name$MH = RuntimeHelper.downcallHandle( + static final MethodHandle const$4 = RuntimeHelper.downcallHandle( "udev_list_entry_get_name", - constants$0.udev_list_entry_get_name$FUNC - ); - static final FunctionDescriptor udev_device_unref$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT + constants$0.const$2 ); - static final MethodHandle udev_device_unref$MH = RuntimeHelper.downcallHandle( + static final MethodHandle const$5 = RuntimeHelper.downcallHandle( "udev_device_unref", - constants$0.udev_device_unref$FUNC - ); - static final FunctionDescriptor udev_device_new_from_syspath$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle udev_device_new_from_syspath$MH = RuntimeHelper.downcallHandle( - "udev_device_new_from_syspath", - constants$0.udev_device_new_from_syspath$FUNC - ); - static final FunctionDescriptor udev_device_get_devtype$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle udev_device_get_devtype$MH = RuntimeHelper.downcallHandle( - "udev_device_get_devtype", - constants$0.udev_device_get_devtype$FUNC + constants$0.const$2 ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java index cb5309af..9d318029 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java @@ -8,49 +8,29 @@ final class constants$1 { // Suppresses default constructor, ensuring non-instantiability. private constants$1() {} - static final FunctionDescriptor udev_device_get_devnode$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT + static final FunctionDescriptor const$0 = FunctionDescriptor.of(RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER ); - static final MethodHandle udev_device_get_devnode$MH = RuntimeHelper.downcallHandle( - "udev_device_get_devnode", - constants$1.udev_device_get_devnode$FUNC + static final MethodHandle const$1 = RuntimeHelper.downcallHandle( + "udev_device_new_from_syspath", + constants$1.const$0 ); - static final FunctionDescriptor udev_device_get_action$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT + static final MethodHandle const$2 = RuntimeHelper.downcallHandle( + "udev_device_get_devtype", + constants$0.const$2 ); - static final MethodHandle udev_device_get_action$MH = RuntimeHelper.downcallHandle( - "udev_device_get_action", - constants$1.udev_device_get_action$FUNC + static final MethodHandle const$3 = RuntimeHelper.downcallHandle( + "udev_device_get_devnode", + constants$0.const$2 ); - static final FunctionDescriptor udev_device_get_sysattr_value$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT + static final MethodHandle const$4 = RuntimeHelper.downcallHandle( + "udev_device_get_action", + constants$0.const$2 ); - static final MethodHandle udev_device_get_sysattr_value$MH = RuntimeHelper.downcallHandle( + static final MethodHandle const$5 = RuntimeHelper.downcallHandle( "udev_device_get_sysattr_value", - constants$1.udev_device_get_sysattr_value$FUNC - ); - static final FunctionDescriptor udev_monitor_new_from_netlink$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle udev_monitor_new_from_netlink$MH = RuntimeHelper.downcallHandle( - "udev_monitor_new_from_netlink", - constants$1.udev_monitor_new_from_netlink$FUNC - ); - static final FunctionDescriptor udev_monitor_enable_receiving$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle udev_monitor_enable_receiving$MH = RuntimeHelper.downcallHandle( - "udev_monitor_enable_receiving", - constants$1.udev_monitor_enable_receiving$FUNC - ); - static final FunctionDescriptor udev_monitor_get_fd$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle udev_monitor_get_fd$MH = RuntimeHelper.downcallHandle( - "udev_monitor_get_fd", - constants$1.udev_monitor_get_fd$FUNC + constants$1.const$0 ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$2.java index a8a06524..88ac3987 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$2.java @@ -4,54 +4,39 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; final class constants$2 { // Suppresses default constructor, ensuring non-instantiability. private constants$2() {} - static final FunctionDescriptor udev_monitor_receive_device$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle udev_monitor_receive_device$MH = RuntimeHelper.downcallHandle( - "udev_monitor_receive_device", - constants$2.udev_monitor_receive_device$FUNC - ); - static final FunctionDescriptor udev_monitor_filter_add_match_subsystem_devtype$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle udev_monitor_filter_add_match_subsystem_devtype$MH = RuntimeHelper.downcallHandle( - "udev_monitor_filter_add_match_subsystem_devtype", - constants$2.udev_monitor_filter_add_match_subsystem_devtype$FUNC - ); - static final FunctionDescriptor udev_enumerate_unref$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle udev_enumerate_unref$MH = RuntimeHelper.downcallHandle( - "udev_enumerate_unref", - constants$2.udev_enumerate_unref$FUNC + static final MethodHandle const$0 = RuntimeHelper.downcallHandle( + "udev_monitor_new_from_netlink", + constants$1.const$0 ); - static final FunctionDescriptor udev_enumerate_new$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT + static final FunctionDescriptor const$1 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER ); - static final MethodHandle udev_enumerate_new$MH = RuntimeHelper.downcallHandle( - "udev_enumerate_new", - constants$2.udev_enumerate_new$FUNC + static final MethodHandle const$2 = RuntimeHelper.downcallHandle( + "udev_monitor_enable_receiving", + constants$2.const$1 ); - static final FunctionDescriptor udev_enumerate_add_match_subsystem$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT + static final MethodHandle const$3 = RuntimeHelper.downcallHandle( + "udev_monitor_get_fd", + constants$2.const$1 ); - static final MethodHandle udev_enumerate_add_match_subsystem$MH = RuntimeHelper.downcallHandle( - "udev_enumerate_add_match_subsystem", - constants$2.udev_enumerate_add_match_subsystem$FUNC + static final MethodHandle const$4 = RuntimeHelper.downcallHandle( + "udev_monitor_receive_device", + constants$0.const$2 ); - static final FunctionDescriptor udev_enumerate_scan_devices$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT + static final FunctionDescriptor const$5 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER ); - static final MethodHandle udev_enumerate_scan_devices$MH = RuntimeHelper.downcallHandle( - "udev_enumerate_scan_devices", - constants$2.udev_enumerate_scan_devices$FUNC + static final MethodHandle const$6 = RuntimeHelper.downcallHandle( + "udev_monitor_filter_add_match_subsystem_devtype", + constants$2.const$5 ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$3.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$3.java index 4478b0f9..b469b77f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$3.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$3.java @@ -4,16 +4,35 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; final class constants$3 { // Suppresses default constructor, ensuring non-instantiability. private constants$3() {} - static final FunctionDescriptor udev_enumerate_get_list_entry$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT + static final MethodHandle const$0 = RuntimeHelper.downcallHandle( + "udev_enumerate_unref", + constants$0.const$2 + ); + static final MethodHandle const$1 = RuntimeHelper.downcallHandle( + "udev_enumerate_new", + constants$0.const$2 + ); + static final FunctionDescriptor const$2 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER + ); + static final MethodHandle const$3 = RuntimeHelper.downcallHandle( + "udev_enumerate_add_match_subsystem", + constants$3.const$2 + ); + static final MethodHandle const$4 = RuntimeHelper.downcallHandle( + "udev_enumerate_scan_devices", + constants$2.const$1 ); - static final MethodHandle udev_enumerate_get_list_entry$MH = RuntimeHelper.downcallHandle( + static final MethodHandle const$5 = RuntimeHelper.downcallHandle( "udev_enumerate_get_list_entry", - constants$3.udev_enumerate_get_list_entry$FUNC + constants$0.const$2 ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java index 2e40e26f..bcc40cb5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java @@ -2,22 +2,23 @@ package net.codecrete.usb.linux.gen.udev; +import java.lang.foreign.AddressLayout; import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class udev { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfLong C_LONG = JAVA_LONG; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; public static MethodHandle udev_new$MH() { - return RuntimeHelper.requireNonNull(constants$0.udev_new$MH,"udev_new"); + return RuntimeHelper.requireNonNull(constants$0.const$1,"udev_new"); } /** * {@snippet : @@ -33,7 +34,7 @@ public static MemorySegment udev_new() { } } public static MethodHandle udev_list_entry_get_next$MH() { - return RuntimeHelper.requireNonNull(constants$0.udev_list_entry_get_next$MH,"udev_list_entry_get_next"); + return RuntimeHelper.requireNonNull(constants$0.const$3,"udev_list_entry_get_next"); } /** * {@snippet : @@ -49,7 +50,7 @@ public static MemorySegment udev_list_entry_get_next(MemorySegment list_entry) { } } public static MethodHandle udev_list_entry_get_name$MH() { - return RuntimeHelper.requireNonNull(constants$0.udev_list_entry_get_name$MH,"udev_list_entry_get_name"); + return RuntimeHelper.requireNonNull(constants$0.const$4,"udev_list_entry_get_name"); } /** * {@snippet : @@ -65,7 +66,7 @@ public static MemorySegment udev_list_entry_get_name(MemorySegment list_entry) { } } public static MethodHandle udev_device_unref$MH() { - return RuntimeHelper.requireNonNull(constants$0.udev_device_unref$MH,"udev_device_unref"); + return RuntimeHelper.requireNonNull(constants$0.const$5,"udev_device_unref"); } /** * {@snippet : @@ -81,7 +82,7 @@ public static MemorySegment udev_device_unref(MemorySegment udev_device) { } } public static MethodHandle udev_device_new_from_syspath$MH() { - return RuntimeHelper.requireNonNull(constants$0.udev_device_new_from_syspath$MH,"udev_device_new_from_syspath"); + return RuntimeHelper.requireNonNull(constants$1.const$1,"udev_device_new_from_syspath"); } /** * {@snippet : @@ -97,7 +98,7 @@ public static MemorySegment udev_device_new_from_syspath(MemorySegment udev, Mem } } public static MethodHandle udev_device_get_devtype$MH() { - return RuntimeHelper.requireNonNull(constants$0.udev_device_get_devtype$MH,"udev_device_get_devtype"); + return RuntimeHelper.requireNonNull(constants$1.const$2,"udev_device_get_devtype"); } /** * {@snippet : @@ -113,7 +114,7 @@ public static MemorySegment udev_device_get_devtype(MemorySegment udev_device) { } } public static MethodHandle udev_device_get_devnode$MH() { - return RuntimeHelper.requireNonNull(constants$1.udev_device_get_devnode$MH,"udev_device_get_devnode"); + return RuntimeHelper.requireNonNull(constants$1.const$3,"udev_device_get_devnode"); } /** * {@snippet : @@ -129,7 +130,7 @@ public static MemorySegment udev_device_get_devnode(MemorySegment udev_device) { } } public static MethodHandle udev_device_get_action$MH() { - return RuntimeHelper.requireNonNull(constants$1.udev_device_get_action$MH,"udev_device_get_action"); + return RuntimeHelper.requireNonNull(constants$1.const$4,"udev_device_get_action"); } /** * {@snippet : @@ -145,7 +146,7 @@ public static MemorySegment udev_device_get_action(MemorySegment udev_device) { } } public static MethodHandle udev_device_get_sysattr_value$MH() { - return RuntimeHelper.requireNonNull(constants$1.udev_device_get_sysattr_value$MH,"udev_device_get_sysattr_value"); + return RuntimeHelper.requireNonNull(constants$1.const$5,"udev_device_get_sysattr_value"); } /** * {@snippet : @@ -161,7 +162,7 @@ public static MemorySegment udev_device_get_sysattr_value(MemorySegment udev_dev } } public static MethodHandle udev_monitor_new_from_netlink$MH() { - return RuntimeHelper.requireNonNull(constants$1.udev_monitor_new_from_netlink$MH,"udev_monitor_new_from_netlink"); + return RuntimeHelper.requireNonNull(constants$2.const$0,"udev_monitor_new_from_netlink"); } /** * {@snippet : @@ -177,7 +178,7 @@ public static MemorySegment udev_monitor_new_from_netlink(MemorySegment udev, Me } } public static MethodHandle udev_monitor_enable_receiving$MH() { - return RuntimeHelper.requireNonNull(constants$1.udev_monitor_enable_receiving$MH,"udev_monitor_enable_receiving"); + return RuntimeHelper.requireNonNull(constants$2.const$2,"udev_monitor_enable_receiving"); } /** * {@snippet : @@ -193,7 +194,7 @@ public static int udev_monitor_enable_receiving(MemorySegment udev_monitor) { } } public static MethodHandle udev_monitor_get_fd$MH() { - return RuntimeHelper.requireNonNull(constants$1.udev_monitor_get_fd$MH,"udev_monitor_get_fd"); + return RuntimeHelper.requireNonNull(constants$2.const$3,"udev_monitor_get_fd"); } /** * {@snippet : @@ -209,7 +210,7 @@ public static int udev_monitor_get_fd(MemorySegment udev_monitor) { } } public static MethodHandle udev_monitor_receive_device$MH() { - return RuntimeHelper.requireNonNull(constants$2.udev_monitor_receive_device$MH,"udev_monitor_receive_device"); + return RuntimeHelper.requireNonNull(constants$2.const$4,"udev_monitor_receive_device"); } /** * {@snippet : @@ -225,7 +226,7 @@ public static MemorySegment udev_monitor_receive_device(MemorySegment udev_monit } } public static MethodHandle udev_monitor_filter_add_match_subsystem_devtype$MH() { - return RuntimeHelper.requireNonNull(constants$2.udev_monitor_filter_add_match_subsystem_devtype$MH,"udev_monitor_filter_add_match_subsystem_devtype"); + return RuntimeHelper.requireNonNull(constants$2.const$6,"udev_monitor_filter_add_match_subsystem_devtype"); } /** * {@snippet : @@ -241,7 +242,7 @@ public static int udev_monitor_filter_add_match_subsystem_devtype(MemorySegment } } public static MethodHandle udev_enumerate_unref$MH() { - return RuntimeHelper.requireNonNull(constants$2.udev_enumerate_unref$MH,"udev_enumerate_unref"); + return RuntimeHelper.requireNonNull(constants$3.const$0,"udev_enumerate_unref"); } /** * {@snippet : @@ -257,7 +258,7 @@ public static MemorySegment udev_enumerate_unref(MemorySegment udev_enumerate) { } } public static MethodHandle udev_enumerate_new$MH() { - return RuntimeHelper.requireNonNull(constants$2.udev_enumerate_new$MH,"udev_enumerate_new"); + return RuntimeHelper.requireNonNull(constants$3.const$1,"udev_enumerate_new"); } /** * {@snippet : @@ -273,7 +274,7 @@ public static MemorySegment udev_enumerate_new(MemorySegment udev) { } } public static MethodHandle udev_enumerate_add_match_subsystem$MH() { - return RuntimeHelper.requireNonNull(constants$2.udev_enumerate_add_match_subsystem$MH,"udev_enumerate_add_match_subsystem"); + return RuntimeHelper.requireNonNull(constants$3.const$3,"udev_enumerate_add_match_subsystem"); } /** * {@snippet : @@ -289,7 +290,7 @@ public static int udev_enumerate_add_match_subsystem(MemorySegment udev_enumerat } } public static MethodHandle udev_enumerate_scan_devices$MH() { - return RuntimeHelper.requireNonNull(constants$2.udev_enumerate_scan_devices$MH,"udev_enumerate_scan_devices"); + return RuntimeHelper.requireNonNull(constants$3.const$4,"udev_enumerate_scan_devices"); } /** * {@snippet : @@ -305,7 +306,7 @@ public static int udev_enumerate_scan_devices(MemorySegment udev_enumerate) { } } public static MethodHandle udev_enumerate_get_list_entry$MH() { - return RuntimeHelper.requireNonNull(constants$3.udev_enumerate_get_list_entry$MH,"udev_enumerate_get_list_entry"); + return RuntimeHelper.requireNonNull(constants$3.const$5,"udev_enumerate_get_list_entry"); } /** * {@snippet : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/Constants$root.java deleted file mode 100644 index 3113cb6a..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfLong C_LONG$LAYOUT = JAVA_LONG; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/RuntimeHelper.java index 46a7b0b5..f3cff469 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/RuntimeHelper.java @@ -15,9 +15,10 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { @@ -36,7 +37,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -55,18 +58,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java index 119099ac..90d07fa3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java @@ -4,16 +4,18 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} - static final FunctionDescriptor close$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT + static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, + JAVA_INT ); - static final MethodHandle close$MH = RuntimeHelper.downcallHandle( + static final MethodHandle const$1 = RuntimeHelper.downcallHandle( "close", - constants$0.close$FUNC + constants$0.const$0 ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java index 18b6db19..581e508e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java @@ -2,21 +2,22 @@ package net.codecrete.usb.linux.gen.unistd; +import java.lang.foreign.AddressLayout; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class unistd { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfLong C_LONG = JAVA_LONG; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; public static MethodHandle close$MH() { - return RuntimeHelper.requireNonNull(constants$0.close$MH,"close"); + return RuntimeHelper.requireNonNull(constants$0.const$1,"close"); } /** * {@snippet : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/Constants$root.java deleted file mode 100644 index 8ef9a790..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfLong C_LONG$LAYOUT = JAVA_LONG; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/RuntimeHelper.java index dea9a0d2..5e6d3cd8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/RuntimeHelper.java @@ -15,9 +15,10 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { @@ -36,7 +37,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -55,18 +58,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$0.java new file mode 100644 index 00000000..24688f13 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$0.java @@ -0,0 +1,31 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.*; +final class constants$0 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} + static final StructLayout const$0 = MemoryLayout.structLayout( + JAVA_BYTE.withName("bRequestType"), + JAVA_BYTE.withName("bRequest"), + JAVA_SHORT.withName("wValue"), + JAVA_SHORT.withName("wIndex"), + JAVA_SHORT.withName("wLength"), + JAVA_INT.withName("timeout"), + MemoryLayout.paddingLayout(4), + RuntimeHelper.POINTER.withName("data") + ).withName("usbdevfs_ctrltransfer"); + static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("bRequestType")); + static final VarHandle const$2 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("bRequest")); + static final VarHandle const$3 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("wValue")); + static final VarHandle const$4 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("wIndex")); + static final VarHandle const$5 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("wLength")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$1.java new file mode 100644 index 00000000..9666d212 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$1.java @@ -0,0 +1,28 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$1 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$1() {} + static final VarHandle const$0 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("timeout")); + static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("data")); + static final StructLayout const$2 = MemoryLayout.structLayout( + JAVA_INT.withName("ep"), + JAVA_INT.withName("len"), + JAVA_INT.withName("timeout"), + MemoryLayout.paddingLayout(4), + RuntimeHelper.POINTER.withName("data") + ).withName("usbdevfs_bulktransfer"); + static final VarHandle const$3 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("ep")); + static final VarHandle const$4 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("len")); + static final VarHandle const$5 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("timeout")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$2.java new file mode 100644 index 00000000..384a0622 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$2.java @@ -0,0 +1,49 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$2 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$2() {} + static final VarHandle const$0 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("data")); + static final StructLayout const$1 = MemoryLayout.structLayout( + JAVA_INT.withName("interface"), + JAVA_INT.withName("altsetting") + ).withName("usbdevfs_setinterface"); + static final VarHandle const$2 = constants$2.const$1.varHandle(MemoryLayout.PathElement.groupElement("interface")); + static final VarHandle const$3 = constants$2.const$1.varHandle(MemoryLayout.PathElement.groupElement("altsetting")); + static final StructLayout const$4 = MemoryLayout.structLayout( + JAVA_BYTE.withName("type"), + JAVA_BYTE.withName("endpoint"), + MemoryLayout.paddingLayout(2), + JAVA_INT.withName("status"), + JAVA_INT.withName("flags"), + MemoryLayout.paddingLayout(4), + RuntimeHelper.POINTER.withName("buffer"), + JAVA_INT.withName("buffer_length"), + JAVA_INT.withName("actual_length"), + JAVA_INT.withName("start_frame"), + MemoryLayout.unionLayout( + JAVA_INT.withName("number_of_packets"), + JAVA_INT.withName("stream_id") + ).withName("$anon$0"), + JAVA_INT.withName("error_count"), + JAVA_INT.withName("signr"), + RuntimeHelper.POINTER.withName("usercontext"), + MemoryLayout.sequenceLayout(0, MemoryLayout.structLayout( + JAVA_INT.withName("length"), + JAVA_INT.withName("actual_length"), + JAVA_INT.withName("status") + ).withName("usbdevfs_iso_packet_desc")).withName("iso_frame_desc") + ).withName("usbdevfs_urb"); + static final VarHandle const$5 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("type")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$3.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$3.java new file mode 100644 index 00000000..2f58300d --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$3.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.VarHandle; +final class constants$3 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$3() {} + static final VarHandle const$0 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("endpoint")); + static final VarHandle const$1 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("status")); + static final VarHandle const$2 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("flags")); + static final VarHandle const$3 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("buffer")); + static final VarHandle const$4 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("buffer_length")); + static final VarHandle const$5 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("actual_length")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$4.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$4.java new file mode 100644 index 00000000..dd410c61 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$4.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.VarHandle; +final class constants$4 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$4() {} + static final VarHandle const$0 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("start_frame")); + static final VarHandle const$1 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("number_of_packets")); + static final VarHandle const$2 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("stream_id")); + static final VarHandle const$3 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("error_count")); + static final VarHandle const$4 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("signr")); + static final VarHandle const$5 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("usercontext")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$6.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$6.java new file mode 100644 index 00000000..787c95d8 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$6.java @@ -0,0 +1,14 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.VarHandle; +final class constants$6 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$6() {} + static final VarHandle const$0 = constants$5.const$4.varHandle(MemoryLayout.PathElement.groupElement("flags")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java index f8688893..07aa5f5e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java @@ -2,7 +2,10 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -16,19 +19,11 @@ */ public class usbdevfs_bulktransfer { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_INT$LAYOUT.withName("ep"), - Constants$root.C_INT$LAYOUT.withName("len"), - Constants$root.C_INT$LAYOUT.withName("timeout"), - MemoryLayout.paddingLayout(32), - Constants$root.C_POINTER$LAYOUT.withName("data") - ).withName("usbdevfs_bulktransfer"); public static MemoryLayout $LAYOUT() { - return usbdevfs_bulktransfer.$struct$LAYOUT; + return constants$1.const$2; } - static final VarHandle ep$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ep")); public static VarHandle ep$VH() { - return usbdevfs_bulktransfer.ep$VH; + return constants$1.const$3; } /** * Getter for field: @@ -37,7 +32,7 @@ public class usbdevfs_bulktransfer { * } */ public static int ep$get(MemorySegment seg) { - return (int)usbdevfs_bulktransfer.ep$VH.get(seg); + return (int)constants$1.const$3.get(seg); } /** * Setter for field: @@ -46,17 +41,16 @@ public class usbdevfs_bulktransfer { * } */ public static void ep$set(MemorySegment seg, int x) { - usbdevfs_bulktransfer.ep$VH.set(seg, x); + constants$1.const$3.set(seg, x); } public static int ep$get(MemorySegment seg, long index) { - return (int)usbdevfs_bulktransfer.ep$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$1.const$3.get(seg.asSlice(index*sizeof())); } public static void ep$set(MemorySegment seg, long index, int x) { - usbdevfs_bulktransfer.ep$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$3.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle len$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("len")); public static VarHandle len$VH() { - return usbdevfs_bulktransfer.len$VH; + return constants$1.const$4; } /** * Getter for field: @@ -65,7 +59,7 @@ public class usbdevfs_bulktransfer { * } */ public static int len$get(MemorySegment seg) { - return (int)usbdevfs_bulktransfer.len$VH.get(seg); + return (int)constants$1.const$4.get(seg); } /** * Setter for field: @@ -74,17 +68,16 @@ public class usbdevfs_bulktransfer { * } */ public static void len$set(MemorySegment seg, int x) { - usbdevfs_bulktransfer.len$VH.set(seg, x); + constants$1.const$4.set(seg, x); } public static int len$get(MemorySegment seg, long index) { - return (int)usbdevfs_bulktransfer.len$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$1.const$4.get(seg.asSlice(index*sizeof())); } public static void len$set(MemorySegment seg, long index, int x) { - usbdevfs_bulktransfer.len$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$4.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle timeout$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("timeout")); public static VarHandle timeout$VH() { - return usbdevfs_bulktransfer.timeout$VH; + return constants$1.const$5; } /** * Getter for field: @@ -93,7 +86,7 @@ public class usbdevfs_bulktransfer { * } */ public static int timeout$get(MemorySegment seg) { - return (int)usbdevfs_bulktransfer.timeout$VH.get(seg); + return (int)constants$1.const$5.get(seg); } /** * Setter for field: @@ -102,17 +95,16 @@ public class usbdevfs_bulktransfer { * } */ public static void timeout$set(MemorySegment seg, int x) { - usbdevfs_bulktransfer.timeout$VH.set(seg, x); + constants$1.const$5.set(seg, x); } public static int timeout$get(MemorySegment seg, long index) { - return (int)usbdevfs_bulktransfer.timeout$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$1.const$5.get(seg.asSlice(index*sizeof())); } public static void timeout$set(MemorySegment seg, long index, int x) { - usbdevfs_bulktransfer.timeout$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$5.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle data$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("data")); public static VarHandle data$VH() { - return usbdevfs_bulktransfer.data$VH; + return constants$2.const$0; } /** * Getter for field: @@ -121,7 +113,7 @@ public class usbdevfs_bulktransfer { * } */ public static MemorySegment data$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)usbdevfs_bulktransfer.data$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$2.const$0.get(seg); } /** * Setter for field: @@ -130,20 +122,20 @@ public class usbdevfs_bulktransfer { * } */ public static void data$set(MemorySegment seg, MemorySegment x) { - usbdevfs_bulktransfer.data$VH.set(seg, x); + constants$2.const$0.set(seg, x); } public static MemorySegment data$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)usbdevfs_bulktransfer.data$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$2.const$0.get(seg.asSlice(index*sizeof())); } public static void data$set(MemorySegment seg, long index, MemorySegment x) { - usbdevfs_bulktransfer.data$VH.set(seg.asSlice(index*sizeof()), x); + constants$2.const$0.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java index 78e0ae34..c32eba2f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java @@ -2,7 +2,10 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -19,22 +22,11 @@ */ public class usbdevfs_ctrltransfer { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("bRequestType"), - Constants$root.C_CHAR$LAYOUT.withName("bRequest"), - Constants$root.C_SHORT$LAYOUT.withName("wValue"), - Constants$root.C_SHORT$LAYOUT.withName("wIndex"), - Constants$root.C_SHORT$LAYOUT.withName("wLength"), - Constants$root.C_INT$LAYOUT.withName("timeout"), - MemoryLayout.paddingLayout(32), - Constants$root.C_POINTER$LAYOUT.withName("data") - ).withName("usbdevfs_ctrltransfer"); public static MemoryLayout $LAYOUT() { - return usbdevfs_ctrltransfer.$struct$LAYOUT; + return constants$0.const$0; } - static final VarHandle bRequestType$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("bRequestType")); public static VarHandle bRequestType$VH() { - return usbdevfs_ctrltransfer.bRequestType$VH; + return constants$0.const$1; } /** * Getter for field: @@ -43,7 +35,7 @@ public class usbdevfs_ctrltransfer { * } */ public static byte bRequestType$get(MemorySegment seg) { - return (byte)usbdevfs_ctrltransfer.bRequestType$VH.get(seg); + return (byte)constants$0.const$1.get(seg); } /** * Setter for field: @@ -52,17 +44,16 @@ public class usbdevfs_ctrltransfer { * } */ public static void bRequestType$set(MemorySegment seg, byte x) { - usbdevfs_ctrltransfer.bRequestType$VH.set(seg, x); + constants$0.const$1.set(seg, x); } public static byte bRequestType$get(MemorySegment seg, long index) { - return (byte)usbdevfs_ctrltransfer.bRequestType$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$0.const$1.get(seg.asSlice(index*sizeof())); } public static void bRequestType$set(MemorySegment seg, long index, byte x) { - usbdevfs_ctrltransfer.bRequestType$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$1.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle bRequest$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("bRequest")); public static VarHandle bRequest$VH() { - return usbdevfs_ctrltransfer.bRequest$VH; + return constants$0.const$2; } /** * Getter for field: @@ -71,7 +62,7 @@ public class usbdevfs_ctrltransfer { * } */ public static byte bRequest$get(MemorySegment seg) { - return (byte)usbdevfs_ctrltransfer.bRequest$VH.get(seg); + return (byte)constants$0.const$2.get(seg); } /** * Setter for field: @@ -80,17 +71,16 @@ public class usbdevfs_ctrltransfer { * } */ public static void bRequest$set(MemorySegment seg, byte x) { - usbdevfs_ctrltransfer.bRequest$VH.set(seg, x); + constants$0.const$2.set(seg, x); } public static byte bRequest$get(MemorySegment seg, long index) { - return (byte)usbdevfs_ctrltransfer.bRequest$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$0.const$2.get(seg.asSlice(index*sizeof())); } public static void bRequest$set(MemorySegment seg, long index, byte x) { - usbdevfs_ctrltransfer.bRequest$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$2.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle wValue$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("wValue")); public static VarHandle wValue$VH() { - return usbdevfs_ctrltransfer.wValue$VH; + return constants$0.const$3; } /** * Getter for field: @@ -99,7 +89,7 @@ public class usbdevfs_ctrltransfer { * } */ public static short wValue$get(MemorySegment seg) { - return (short)usbdevfs_ctrltransfer.wValue$VH.get(seg); + return (short)constants$0.const$3.get(seg); } /** * Setter for field: @@ -108,17 +98,16 @@ public class usbdevfs_ctrltransfer { * } */ public static void wValue$set(MemorySegment seg, short x) { - usbdevfs_ctrltransfer.wValue$VH.set(seg, x); + constants$0.const$3.set(seg, x); } public static short wValue$get(MemorySegment seg, long index) { - return (short)usbdevfs_ctrltransfer.wValue$VH.get(seg.asSlice(index*sizeof())); + return (short)constants$0.const$3.get(seg.asSlice(index*sizeof())); } public static void wValue$set(MemorySegment seg, long index, short x) { - usbdevfs_ctrltransfer.wValue$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$3.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle wIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("wIndex")); public static VarHandle wIndex$VH() { - return usbdevfs_ctrltransfer.wIndex$VH; + return constants$0.const$4; } /** * Getter for field: @@ -127,7 +116,7 @@ public class usbdevfs_ctrltransfer { * } */ public static short wIndex$get(MemorySegment seg) { - return (short)usbdevfs_ctrltransfer.wIndex$VH.get(seg); + return (short)constants$0.const$4.get(seg); } /** * Setter for field: @@ -136,17 +125,16 @@ public class usbdevfs_ctrltransfer { * } */ public static void wIndex$set(MemorySegment seg, short x) { - usbdevfs_ctrltransfer.wIndex$VH.set(seg, x); + constants$0.const$4.set(seg, x); } public static short wIndex$get(MemorySegment seg, long index) { - return (short)usbdevfs_ctrltransfer.wIndex$VH.get(seg.asSlice(index*sizeof())); + return (short)constants$0.const$4.get(seg.asSlice(index*sizeof())); } public static void wIndex$set(MemorySegment seg, long index, short x) { - usbdevfs_ctrltransfer.wIndex$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$4.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle wLength$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("wLength")); public static VarHandle wLength$VH() { - return usbdevfs_ctrltransfer.wLength$VH; + return constants$0.const$5; } /** * Getter for field: @@ -155,7 +143,7 @@ public class usbdevfs_ctrltransfer { * } */ public static short wLength$get(MemorySegment seg) { - return (short)usbdevfs_ctrltransfer.wLength$VH.get(seg); + return (short)constants$0.const$5.get(seg); } /** * Setter for field: @@ -164,17 +152,16 @@ public class usbdevfs_ctrltransfer { * } */ public static void wLength$set(MemorySegment seg, short x) { - usbdevfs_ctrltransfer.wLength$VH.set(seg, x); + constants$0.const$5.set(seg, x); } public static short wLength$get(MemorySegment seg, long index) { - return (short)usbdevfs_ctrltransfer.wLength$VH.get(seg.asSlice(index*sizeof())); + return (short)constants$0.const$5.get(seg.asSlice(index*sizeof())); } public static void wLength$set(MemorySegment seg, long index, short x) { - usbdevfs_ctrltransfer.wLength$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$5.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle timeout$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("timeout")); public static VarHandle timeout$VH() { - return usbdevfs_ctrltransfer.timeout$VH; + return constants$1.const$0; } /** * Getter for field: @@ -183,7 +170,7 @@ public class usbdevfs_ctrltransfer { * } */ public static int timeout$get(MemorySegment seg) { - return (int)usbdevfs_ctrltransfer.timeout$VH.get(seg); + return (int)constants$1.const$0.get(seg); } /** * Setter for field: @@ -192,17 +179,16 @@ public class usbdevfs_ctrltransfer { * } */ public static void timeout$set(MemorySegment seg, int x) { - usbdevfs_ctrltransfer.timeout$VH.set(seg, x); + constants$1.const$0.set(seg, x); } public static int timeout$get(MemorySegment seg, long index) { - return (int)usbdevfs_ctrltransfer.timeout$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$1.const$0.get(seg.asSlice(index*sizeof())); } public static void timeout$set(MemorySegment seg, long index, int x) { - usbdevfs_ctrltransfer.timeout$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$0.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle data$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("data")); public static VarHandle data$VH() { - return usbdevfs_ctrltransfer.data$VH; + return constants$1.const$1; } /** * Getter for field: @@ -211,7 +197,7 @@ public class usbdevfs_ctrltransfer { * } */ public static MemorySegment data$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)usbdevfs_ctrltransfer.data$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$1.const$1.get(seg); } /** * Setter for field: @@ -220,20 +206,20 @@ public class usbdevfs_ctrltransfer { * } */ public static void data$set(MemorySegment seg, MemorySegment x) { - usbdevfs_ctrltransfer.data$VH.set(seg, x); + constants$1.const$1.set(seg, x); } public static MemorySegment data$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)usbdevfs_ctrltransfer.data$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$1.const$1.get(seg.asSlice(index*sizeof())); } public static void data$set(MemorySegment seg, long index, MemorySegment x) { - usbdevfs_ctrltransfer.data$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$1.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java index fa658189..e238d86e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java @@ -2,7 +2,10 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -15,17 +18,11 @@ */ public class usbdevfs_disconnect_claim { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_INT$LAYOUT.withName("interface"), - Constants$root.C_INT$LAYOUT.withName("flags"), - MemoryLayout.sequenceLayout(256, Constants$root.C_CHAR$LAYOUT).withName("driver") - ).withName("usbdevfs_disconnect_claim"); public static MemoryLayout $LAYOUT() { - return usbdevfs_disconnect_claim.$struct$LAYOUT; + return constants$5.const$4; } - static final VarHandle interface_$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("interface")); public static VarHandle interface_$VH() { - return usbdevfs_disconnect_claim.interface_$VH; + return constants$5.const$5; } /** * Getter for field: @@ -34,7 +31,7 @@ public class usbdevfs_disconnect_claim { * } */ public static int interface_$get(MemorySegment seg) { - return (int)usbdevfs_disconnect_claim.interface_$VH.get(seg); + return (int)constants$5.const$5.get(seg); } /** * Setter for field: @@ -43,17 +40,16 @@ public class usbdevfs_disconnect_claim { * } */ public static void interface_$set(MemorySegment seg, int x) { - usbdevfs_disconnect_claim.interface_$VH.set(seg, x); + constants$5.const$5.set(seg, x); } public static int interface_$get(MemorySegment seg, long index) { - return (int)usbdevfs_disconnect_claim.interface_$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$5.const$5.get(seg.asSlice(index*sizeof())); } public static void interface_$set(MemorySegment seg, long index, int x) { - usbdevfs_disconnect_claim.interface_$VH.set(seg.asSlice(index*sizeof()), x); + constants$5.const$5.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle flags$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("flags")); public static VarHandle flags$VH() { - return usbdevfs_disconnect_claim.flags$VH; + return constants$6.const$0; } /** * Getter for field: @@ -62,7 +58,7 @@ public class usbdevfs_disconnect_claim { * } */ public static int flags$get(MemorySegment seg) { - return (int)usbdevfs_disconnect_claim.flags$VH.get(seg); + return (int)constants$6.const$0.get(seg); } /** * Setter for field: @@ -71,13 +67,13 @@ public class usbdevfs_disconnect_claim { * } */ public static void flags$set(MemorySegment seg, int x) { - usbdevfs_disconnect_claim.flags$VH.set(seg, x); + constants$6.const$0.set(seg, x); } public static int flags$get(MemorySegment seg, long index) { - return (int)usbdevfs_disconnect_claim.flags$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$6.const$0.get(seg.asSlice(index*sizeof())); } public static void flags$set(MemorySegment seg, long index, int x) { - usbdevfs_disconnect_claim.flags$VH.set(seg.asSlice(index*sizeof()), x); + constants$6.const$0.set(seg.asSlice(index*sizeof()), x); } public static MemorySegment driver$slice(MemorySegment seg) { return seg.asSlice(8, 256); @@ -87,7 +83,7 @@ public class usbdevfs_disconnect_claim { public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java index 34dbb990..8135f579 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java @@ -2,7 +2,10 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -15,17 +18,11 @@ */ public class usbdevfs_ioctl { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_INT$LAYOUT.withName("ifno"), - Constants$root.C_INT$LAYOUT.withName("ioctl_code"), - Constants$root.C_POINTER$LAYOUT.withName("data") - ).withName("usbdevfs_ioctl"); public static MemoryLayout $LAYOUT() { - return usbdevfs_ioctl.$struct$LAYOUT; + return constants$5.const$0; } - static final VarHandle ifno$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ifno")); public static VarHandle ifno$VH() { - return usbdevfs_ioctl.ifno$VH; + return constants$5.const$1; } /** * Getter for field: @@ -34,7 +31,7 @@ public class usbdevfs_ioctl { * } */ public static int ifno$get(MemorySegment seg) { - return (int)usbdevfs_ioctl.ifno$VH.get(seg); + return (int)constants$5.const$1.get(seg); } /** * Setter for field: @@ -43,17 +40,16 @@ public class usbdevfs_ioctl { * } */ public static void ifno$set(MemorySegment seg, int x) { - usbdevfs_ioctl.ifno$VH.set(seg, x); + constants$5.const$1.set(seg, x); } public static int ifno$get(MemorySegment seg, long index) { - return (int)usbdevfs_ioctl.ifno$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$5.const$1.get(seg.asSlice(index*sizeof())); } public static void ifno$set(MemorySegment seg, long index, int x) { - usbdevfs_ioctl.ifno$VH.set(seg.asSlice(index*sizeof()), x); + constants$5.const$1.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle ioctl_code$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ioctl_code")); public static VarHandle ioctl_code$VH() { - return usbdevfs_ioctl.ioctl_code$VH; + return constants$5.const$2; } /** * Getter for field: @@ -62,7 +58,7 @@ public class usbdevfs_ioctl { * } */ public static int ioctl_code$get(MemorySegment seg) { - return (int)usbdevfs_ioctl.ioctl_code$VH.get(seg); + return (int)constants$5.const$2.get(seg); } /** * Setter for field: @@ -71,17 +67,16 @@ public class usbdevfs_ioctl { * } */ public static void ioctl_code$set(MemorySegment seg, int x) { - usbdevfs_ioctl.ioctl_code$VH.set(seg, x); + constants$5.const$2.set(seg, x); } public static int ioctl_code$get(MemorySegment seg, long index) { - return (int)usbdevfs_ioctl.ioctl_code$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$5.const$2.get(seg.asSlice(index*sizeof())); } public static void ioctl_code$set(MemorySegment seg, long index, int x) { - usbdevfs_ioctl.ioctl_code$VH.set(seg.asSlice(index*sizeof()), x); + constants$5.const$2.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle data$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("data")); public static VarHandle data$VH() { - return usbdevfs_ioctl.data$VH; + return constants$5.const$3; } /** * Getter for field: @@ -90,7 +85,7 @@ public class usbdevfs_ioctl { * } */ public static MemorySegment data$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)usbdevfs_ioctl.data$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$5.const$3.get(seg); } /** * Setter for field: @@ -99,20 +94,20 @@ public class usbdevfs_ioctl { * } */ public static void data$set(MemorySegment seg, MemorySegment x) { - usbdevfs_ioctl.data$VH.set(seg, x); + constants$5.const$3.set(seg, x); } public static MemorySegment data$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)usbdevfs_ioctl.data$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$5.const$3.get(seg.asSlice(index*sizeof())); } public static void data$set(MemorySegment seg, long index, MemorySegment x) { - usbdevfs_ioctl.data$VH.set(seg.asSlice(index*sizeof()), x); + constants$5.const$3.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java index ea8ac910..b9989942 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java @@ -2,7 +2,10 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -14,16 +17,11 @@ */ public class usbdevfs_setinterface { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_INT$LAYOUT.withName("interface"), - Constants$root.C_INT$LAYOUT.withName("altsetting") - ).withName("usbdevfs_setinterface"); public static MemoryLayout $LAYOUT() { - return usbdevfs_setinterface.$struct$LAYOUT; + return constants$2.const$1; } - static final VarHandle interface_$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("interface")); public static VarHandle interface_$VH() { - return usbdevfs_setinterface.interface_$VH; + return constants$2.const$2; } /** * Getter for field: @@ -32,7 +30,7 @@ public class usbdevfs_setinterface { * } */ public static int interface_$get(MemorySegment seg) { - return (int)usbdevfs_setinterface.interface_$VH.get(seg); + return (int)constants$2.const$2.get(seg); } /** * Setter for field: @@ -41,17 +39,16 @@ public class usbdevfs_setinterface { * } */ public static void interface_$set(MemorySegment seg, int x) { - usbdevfs_setinterface.interface_$VH.set(seg, x); + constants$2.const$2.set(seg, x); } public static int interface_$get(MemorySegment seg, long index) { - return (int)usbdevfs_setinterface.interface_$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$2.const$2.get(seg.asSlice(index*sizeof())); } public static void interface_$set(MemorySegment seg, long index, int x) { - usbdevfs_setinterface.interface_$VH.set(seg.asSlice(index*sizeof()), x); + constants$2.const$2.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle altsetting$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("altsetting")); public static VarHandle altsetting$VH() { - return usbdevfs_setinterface.altsetting$VH; + return constants$2.const$3; } /** * Getter for field: @@ -60,7 +57,7 @@ public class usbdevfs_setinterface { * } */ public static int altsetting$get(MemorySegment seg) { - return (int)usbdevfs_setinterface.altsetting$VH.get(seg); + return (int)constants$2.const$3.get(seg); } /** * Setter for field: @@ -69,20 +66,20 @@ public class usbdevfs_setinterface { * } */ public static void altsetting$set(MemorySegment seg, int x) { - usbdevfs_setinterface.altsetting$VH.set(seg, x); + constants$2.const$3.set(seg, x); } public static int altsetting$get(MemorySegment seg, long index) { - return (int)usbdevfs_setinterface.altsetting$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$2.const$3.get(seg.asSlice(index*sizeof())); } public static void altsetting$set(MemorySegment seg, long index, int x) { - usbdevfs_setinterface.altsetting$VH.set(seg.asSlice(index*sizeof()), x); + constants$2.const$3.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java index 9fd69b70..ab7fd8e6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java @@ -2,7 +2,10 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -28,36 +31,11 @@ */ public class usbdevfs_urb { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("type"), - Constants$root.C_CHAR$LAYOUT.withName("endpoint"), - MemoryLayout.paddingLayout(16), - Constants$root.C_INT$LAYOUT.withName("status"), - Constants$root.C_INT$LAYOUT.withName("flags"), - MemoryLayout.paddingLayout(32), - Constants$root.C_POINTER$LAYOUT.withName("buffer"), - Constants$root.C_INT$LAYOUT.withName("buffer_length"), - Constants$root.C_INT$LAYOUT.withName("actual_length"), - Constants$root.C_INT$LAYOUT.withName("start_frame"), - MemoryLayout.unionLayout( - Constants$root.C_INT$LAYOUT.withName("number_of_packets"), - Constants$root.C_INT$LAYOUT.withName("stream_id") - ).withName("$anon$0"), - Constants$root.C_INT$LAYOUT.withName("error_count"), - Constants$root.C_INT$LAYOUT.withName("signr"), - Constants$root.C_POINTER$LAYOUT.withName("usercontext"), - MemoryLayout.sequenceLayout(0, MemoryLayout.structLayout( - Constants$root.C_INT$LAYOUT.withName("length"), - Constants$root.C_INT$LAYOUT.withName("actual_length"), - Constants$root.C_INT$LAYOUT.withName("status") - ).withName("usbdevfs_iso_packet_desc")).withName("iso_frame_desc") - ).withName("usbdevfs_urb"); public static MemoryLayout $LAYOUT() { - return usbdevfs_urb.$struct$LAYOUT; + return constants$2.const$4; } - static final VarHandle type$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("type")); public static VarHandle type$VH() { - return usbdevfs_urb.type$VH; + return constants$2.const$5; } /** * Getter for field: @@ -66,7 +44,7 @@ public class usbdevfs_urb { * } */ public static byte type$get(MemorySegment seg) { - return (byte)usbdevfs_urb.type$VH.get(seg); + return (byte)constants$2.const$5.get(seg); } /** * Setter for field: @@ -75,17 +53,16 @@ public class usbdevfs_urb { * } */ public static void type$set(MemorySegment seg, byte x) { - usbdevfs_urb.type$VH.set(seg, x); + constants$2.const$5.set(seg, x); } public static byte type$get(MemorySegment seg, long index) { - return (byte)usbdevfs_urb.type$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$2.const$5.get(seg.asSlice(index*sizeof())); } public static void type$set(MemorySegment seg, long index, byte x) { - usbdevfs_urb.type$VH.set(seg.asSlice(index*sizeof()), x); + constants$2.const$5.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle endpoint$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("endpoint")); public static VarHandle endpoint$VH() { - return usbdevfs_urb.endpoint$VH; + return constants$3.const$0; } /** * Getter for field: @@ -94,7 +71,7 @@ public class usbdevfs_urb { * } */ public static byte endpoint$get(MemorySegment seg) { - return (byte)usbdevfs_urb.endpoint$VH.get(seg); + return (byte)constants$3.const$0.get(seg); } /** * Setter for field: @@ -103,17 +80,16 @@ public class usbdevfs_urb { * } */ public static void endpoint$set(MemorySegment seg, byte x) { - usbdevfs_urb.endpoint$VH.set(seg, x); + constants$3.const$0.set(seg, x); } public static byte endpoint$get(MemorySegment seg, long index) { - return (byte)usbdevfs_urb.endpoint$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$3.const$0.get(seg.asSlice(index*sizeof())); } public static void endpoint$set(MemorySegment seg, long index, byte x) { - usbdevfs_urb.endpoint$VH.set(seg.asSlice(index*sizeof()), x); + constants$3.const$0.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle status$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("status")); public static VarHandle status$VH() { - return usbdevfs_urb.status$VH; + return constants$3.const$1; } /** * Getter for field: @@ -122,7 +98,7 @@ public class usbdevfs_urb { * } */ public static int status$get(MemorySegment seg) { - return (int)usbdevfs_urb.status$VH.get(seg); + return (int)constants$3.const$1.get(seg); } /** * Setter for field: @@ -131,17 +107,16 @@ public class usbdevfs_urb { * } */ public static void status$set(MemorySegment seg, int x) { - usbdevfs_urb.status$VH.set(seg, x); + constants$3.const$1.set(seg, x); } public static int status$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.status$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$3.const$1.get(seg.asSlice(index*sizeof())); } public static void status$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.status$VH.set(seg.asSlice(index*sizeof()), x); + constants$3.const$1.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle flags$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("flags")); public static VarHandle flags$VH() { - return usbdevfs_urb.flags$VH; + return constants$3.const$2; } /** * Getter for field: @@ -150,7 +125,7 @@ public class usbdevfs_urb { * } */ public static int flags$get(MemorySegment seg) { - return (int)usbdevfs_urb.flags$VH.get(seg); + return (int)constants$3.const$2.get(seg); } /** * Setter for field: @@ -159,17 +134,16 @@ public class usbdevfs_urb { * } */ public static void flags$set(MemorySegment seg, int x) { - usbdevfs_urb.flags$VH.set(seg, x); + constants$3.const$2.set(seg, x); } public static int flags$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.flags$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$3.const$2.get(seg.asSlice(index*sizeof())); } public static void flags$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.flags$VH.set(seg.asSlice(index*sizeof()), x); + constants$3.const$2.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle buffer$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("buffer")); public static VarHandle buffer$VH() { - return usbdevfs_urb.buffer$VH; + return constants$3.const$3; } /** * Getter for field: @@ -178,7 +152,7 @@ public class usbdevfs_urb { * } */ public static MemorySegment buffer$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)usbdevfs_urb.buffer$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$3.const$3.get(seg); } /** * Setter for field: @@ -187,17 +161,16 @@ public class usbdevfs_urb { * } */ public static void buffer$set(MemorySegment seg, MemorySegment x) { - usbdevfs_urb.buffer$VH.set(seg, x); + constants$3.const$3.set(seg, x); } public static MemorySegment buffer$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)usbdevfs_urb.buffer$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$3.const$3.get(seg.asSlice(index*sizeof())); } public static void buffer$set(MemorySegment seg, long index, MemorySegment x) { - usbdevfs_urb.buffer$VH.set(seg.asSlice(index*sizeof()), x); + constants$3.const$3.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle buffer_length$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("buffer_length")); public static VarHandle buffer_length$VH() { - return usbdevfs_urb.buffer_length$VH; + return constants$3.const$4; } /** * Getter for field: @@ -206,7 +179,7 @@ public class usbdevfs_urb { * } */ public static int buffer_length$get(MemorySegment seg) { - return (int)usbdevfs_urb.buffer_length$VH.get(seg); + return (int)constants$3.const$4.get(seg); } /** * Setter for field: @@ -215,17 +188,16 @@ public class usbdevfs_urb { * } */ public static void buffer_length$set(MemorySegment seg, int x) { - usbdevfs_urb.buffer_length$VH.set(seg, x); + constants$3.const$4.set(seg, x); } public static int buffer_length$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.buffer_length$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$3.const$4.get(seg.asSlice(index*sizeof())); } public static void buffer_length$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.buffer_length$VH.set(seg.asSlice(index*sizeof()), x); + constants$3.const$4.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle actual_length$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("actual_length")); public static VarHandle actual_length$VH() { - return usbdevfs_urb.actual_length$VH; + return constants$3.const$5; } /** * Getter for field: @@ -234,7 +206,7 @@ public class usbdevfs_urb { * } */ public static int actual_length$get(MemorySegment seg) { - return (int)usbdevfs_urb.actual_length$VH.get(seg); + return (int)constants$3.const$5.get(seg); } /** * Setter for field: @@ -243,17 +215,16 @@ public class usbdevfs_urb { * } */ public static void actual_length$set(MemorySegment seg, int x) { - usbdevfs_urb.actual_length$VH.set(seg, x); + constants$3.const$5.set(seg, x); } public static int actual_length$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.actual_length$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$3.const$5.get(seg.asSlice(index*sizeof())); } public static void actual_length$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.actual_length$VH.set(seg.asSlice(index*sizeof()), x); + constants$3.const$5.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle start_frame$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("start_frame")); public static VarHandle start_frame$VH() { - return usbdevfs_urb.start_frame$VH; + return constants$4.const$0; } /** * Getter for field: @@ -262,7 +233,7 @@ public class usbdevfs_urb { * } */ public static int start_frame$get(MemorySegment seg) { - return (int)usbdevfs_urb.start_frame$VH.get(seg); + return (int)constants$4.const$0.get(seg); } /** * Setter for field: @@ -271,17 +242,16 @@ public class usbdevfs_urb { * } */ public static void start_frame$set(MemorySegment seg, int x) { - usbdevfs_urb.start_frame$VH.set(seg, x); + constants$4.const$0.set(seg, x); } public static int start_frame$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.start_frame$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$4.const$0.get(seg.asSlice(index*sizeof())); } public static void start_frame$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.start_frame$VH.set(seg.asSlice(index*sizeof()), x); + constants$4.const$0.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle number_of_packets$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("number_of_packets")); public static VarHandle number_of_packets$VH() { - return usbdevfs_urb.number_of_packets$VH; + return constants$4.const$1; } /** * Getter for field: @@ -290,7 +260,7 @@ public class usbdevfs_urb { * } */ public static int number_of_packets$get(MemorySegment seg) { - return (int)usbdevfs_urb.number_of_packets$VH.get(seg); + return (int)constants$4.const$1.get(seg); } /** * Setter for field: @@ -299,17 +269,16 @@ public class usbdevfs_urb { * } */ public static void number_of_packets$set(MemorySegment seg, int x) { - usbdevfs_urb.number_of_packets$VH.set(seg, x); + constants$4.const$1.set(seg, x); } public static int number_of_packets$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.number_of_packets$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$4.const$1.get(seg.asSlice(index*sizeof())); } public static void number_of_packets$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.number_of_packets$VH.set(seg.asSlice(index*sizeof()), x); + constants$4.const$1.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle stream_id$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("stream_id")); public static VarHandle stream_id$VH() { - return usbdevfs_urb.stream_id$VH; + return constants$4.const$2; } /** * Getter for field: @@ -318,7 +287,7 @@ public class usbdevfs_urb { * } */ public static int stream_id$get(MemorySegment seg) { - return (int)usbdevfs_urb.stream_id$VH.get(seg); + return (int)constants$4.const$2.get(seg); } /** * Setter for field: @@ -327,17 +296,16 @@ public class usbdevfs_urb { * } */ public static void stream_id$set(MemorySegment seg, int x) { - usbdevfs_urb.stream_id$VH.set(seg, x); + constants$4.const$2.set(seg, x); } public static int stream_id$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.stream_id$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$4.const$2.get(seg.asSlice(index*sizeof())); } public static void stream_id$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.stream_id$VH.set(seg.asSlice(index*sizeof()), x); + constants$4.const$2.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle error_count$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("error_count")); public static VarHandle error_count$VH() { - return usbdevfs_urb.error_count$VH; + return constants$4.const$3; } /** * Getter for field: @@ -346,7 +314,7 @@ public class usbdevfs_urb { * } */ public static int error_count$get(MemorySegment seg) { - return (int)usbdevfs_urb.error_count$VH.get(seg); + return (int)constants$4.const$3.get(seg); } /** * Setter for field: @@ -355,17 +323,16 @@ public class usbdevfs_urb { * } */ public static void error_count$set(MemorySegment seg, int x) { - usbdevfs_urb.error_count$VH.set(seg, x); + constants$4.const$3.set(seg, x); } public static int error_count$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.error_count$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$4.const$3.get(seg.asSlice(index*sizeof())); } public static void error_count$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.error_count$VH.set(seg.asSlice(index*sizeof()), x); + constants$4.const$3.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle signr$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("signr")); public static VarHandle signr$VH() { - return usbdevfs_urb.signr$VH; + return constants$4.const$4; } /** * Getter for field: @@ -374,7 +341,7 @@ public class usbdevfs_urb { * } */ public static int signr$get(MemorySegment seg) { - return (int)usbdevfs_urb.signr$VH.get(seg); + return (int)constants$4.const$4.get(seg); } /** * Setter for field: @@ -383,17 +350,16 @@ public class usbdevfs_urb { * } */ public static void signr$set(MemorySegment seg, int x) { - usbdevfs_urb.signr$VH.set(seg, x); + constants$4.const$4.set(seg, x); } public static int signr$get(MemorySegment seg, long index) { - return (int)usbdevfs_urb.signr$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$4.const$4.get(seg.asSlice(index*sizeof())); } public static void signr$set(MemorySegment seg, long index, int x) { - usbdevfs_urb.signr$VH.set(seg.asSlice(index*sizeof()), x); + constants$4.const$4.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle usercontext$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("usercontext")); public static VarHandle usercontext$VH() { - return usbdevfs_urb.usercontext$VH; + return constants$4.const$5; } /** * Getter for field: @@ -402,7 +368,7 @@ public class usbdevfs_urb { * } */ public static MemorySegment usercontext$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)usbdevfs_urb.usercontext$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$4.const$5.get(seg); } /** * Setter for field: @@ -411,20 +377,20 @@ public class usbdevfs_urb { * } */ public static void usercontext$set(MemorySegment seg, MemorySegment x) { - usbdevfs_urb.usercontext$VH.set(seg, x); + constants$4.const$5.set(seg, x); } public static MemorySegment usercontext$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)usbdevfs_urb.usercontext$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$4.const$5.get(seg.asSlice(index*sizeof())); } public static void usercontext$set(MemorySegment seg, long index, MemorySegment x) { - usbdevfs_urb.usercontext$VH.set(seg.asSlice(index*sizeof()), x); + constants$4.const$5.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java index 0a36e81d..68d05fef 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java @@ -2,17 +2,19 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; +import java.lang.foreign.AddressLayout; + import static java.lang.foreign.ValueLayout.*; public class usbdevice_fs { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfLong C_LONG = JAVA_LONG; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; /** * {@snippet : * #define USBDEVFS_URB_TYPE_ISO 0 From 54dda6af04de98ed25102123da6a5529ff74330a Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 25 Jul 2023 20:31:41 +0200 Subject: [PATCH 243/433] Linux: upgrade to JDK 21 --- .../linux/gen/usbdevice_fs/constants$5.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$5.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$5.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$5.java new file mode 100644 index 00000000..fedeaec6 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$5.java @@ -0,0 +1,31 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$5 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$5() {} + static final StructLayout const$0 = MemoryLayout.structLayout( + JAVA_INT.withName("ifno"), + JAVA_INT.withName("ioctl_code"), + RuntimeHelper.POINTER.withName("data") + ).withName("usbdevfs_ioctl"); + static final VarHandle const$1 = constants$5.const$0.varHandle(MemoryLayout.PathElement.groupElement("ifno")); + static final VarHandle const$2 = constants$5.const$0.varHandle(MemoryLayout.PathElement.groupElement("ioctl_code")); + static final VarHandle const$3 = constants$5.const$0.varHandle(MemoryLayout.PathElement.groupElement("data")); + static final StructLayout const$4 = MemoryLayout.structLayout( + JAVA_INT.withName("interface"), + JAVA_INT.withName("flags"), + MemoryLayout.sequenceLayout(256, JAVA_BYTE).withName("driver") + ).withName("usbdevfs_disconnect_claim"); + static final VarHandle const$5 = constants$5.const$4.varHandle(MemoryLayout.PathElement.groupElement("interface")); +} + + From 178f15fe5d31f9ee8c0895dcc549ec65497d2c55 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 25 Jul 2023 21:10:00 +0200 Subject: [PATCH 244/433] Windows: upgrade to JDK 21 --- .../codecrete/usb/windows/DeviceProperty.java | 18 +- .../net/codecrete/usb/windows/USBHelper.java | 14 +- .../java/net/codecrete/usb/windows/Win.java | 14 +- .../usb/windows/WindowsAsyncTask.java | 10 +- .../usb/windows/WindowsUSBDevice.java | 40 ++--- .../usb/windows/WindowsUSBDeviceRegistry.java | 34 ++-- .../usb/windows/WindowsUSBException.java | 7 +- .../usb/windows/gen/advapi32/Advapi32.java | 21 +-- .../windows/gen/advapi32/Constants$root.java | 21 --- .../windows/gen/advapi32/RuntimeHelper.java | 26 ++- .../usb/windows/gen/advapi32/constants$0.java | 28 ++-- .../windows/gen/kernel32/Constants$root.java | 21 --- .../usb/windows/gen/kernel32/Kernel32.java | 25 +-- .../windows/gen/kernel32/RuntimeHelper.java | 26 ++- .../usb/windows/gen/kernel32/_GUID.java | 48 +++--- .../usb/windows/gen/kernel32/_OVERLAPPED.java | 87 ++++------ .../usb/windows/gen/kernel32/constants$0.java | 63 +++---- .../usb/windows/gen/kernel32/constants$1.java | 29 ++++ .../usb/windows/gen/kernel32/constants$2.java | 39 +++++ .../usb/windows/gen/ntdll/Constants$root.java | 21 --- .../usb/windows/gen/ntdll/NtDll.java | 18 +- .../usb/windows/gen/ntdll/RuntimeHelper.java | 26 ++- .../usb/windows/gen/ntdll/constants$0.java | 11 ++ .../usb/windows/gen/ole32/Constants$root.java | 21 --- .../usb/windows/gen/ole32/Ole32.java | 19 ++- .../usb/windows/gen/ole32/RuntimeHelper.java | 26 ++- .../usb/windows/gen/ole32/constants$0.java | 12 +- .../windows/gen/setupapi/Constants$root.java | 21 --- .../windows/gen/setupapi/RuntimeHelper.java | 26 ++- .../usb/windows/gen/setupapi/SetupAPI.java | 21 +-- .../usb/windows/gen/setupapi/_DEVPROPKEY.java | 29 ++-- .../setupapi/_SP_DEVICE_INTERFACE_DATA.java | 53 +++--- .../_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java | 25 ++- .../gen/setupapi/_SP_DEVINFO_DATA.java | 53 +++--- .../usb/windows/gen/setupapi/constants$0.java | 46 ++++-- .../usb/windows/gen/setupapi/constants$1.java | 36 ++++ .../usb/windows/gen/setupapi/constants$2.java | 30 ++++ .../windows/gen/usbioctl/Constants$root.java | 21 --- .../windows/gen/usbioctl/RuntimeHelper.java | 26 ++- .../usb/windows/gen/usbioctl/USBIoctl.java | 18 +- .../usb/windows/gen/usbioctl/constants$0.java | 11 ++ .../windows/gen/user32/Constants$root.java | 21 --- .../usb/windows/gen/user32/RuntimeHelper.java | 26 ++- .../usb/windows/gen/user32/User32.java | 21 +-- .../_DEV_BROADCAST_DEVICEINTERFACE_W.java | 55 +++---- .../gen/user32/_DEV_BROADCAST_HDR.java | 47 +++--- .../usb/windows/gen/user32/constants$0.java | 38 +++-- .../usb/windows/gen/user32/constants$1.java | 19 +++ .../usb/windows/gen/user32/constants$2.java | 35 ++++ .../usb/windows/gen/user32/constants$3.java | 37 +++++ .../usb/windows/gen/user32/constants$4.java | 35 ++++ .../usb/windows/gen/user32/tagMSG.java | 77 ++++----- .../windows/gen/user32/tagWNDCLASSEXW.java | 155 ++++++++---------- .../windows/gen/winusb/Constants$root.java | 21 --- .../usb/windows/gen/winusb/RuntimeHelper.java | 26 ++- .../usb/windows/gen/winusb/WinUSB.java | 19 ++- .../usb/windows/gen/winusb/constants$0.java | 10 +- 57 files changed, 948 insertions(+), 835 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Constants$root.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$2.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Constants$root.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$2.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$1.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$2.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$3.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$4.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/Constants$root.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index a2d0d7f8..5d0905d0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -65,10 +65,10 @@ public class DeviceProperty { */ public static int getDeviceIntProperty(MemorySegment devInfoSet, MemorySegment devInfoData, MemorySegment propertyKey) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var propertyTypeHolder = arena.allocate(JAVA_INT); var propertyValueHolder = arena.allocate(JAVA_INT); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, lastErrorState) == 0) throwLastError(lastErrorState, "Internal error (SetupDiGetDevicePropertyW)"); @@ -90,7 +90,7 @@ public static int getDeviceIntProperty(MemorySegment devInfoSet, MemorySegment d */ public static String getDeviceStringProperty(MemorySegment devInfoSet, MemorySegment devInfoData, MemorySegment propertyKey) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var propertyValue = getVariableLengthProperty(devInfoSet, devInfoData, propertyKey, SetupAPI.DEVPROP_TYPE_STRING(), arena); if (propertyValue == null) @@ -109,7 +109,7 @@ public static String getDeviceStringProperty(MemorySegment devInfoSet, MemorySeg */ public static List getDeviceStringListProperty(MemorySegment devInfoSet, MemorySegment devInfoData, MemorySegment propertyKey) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var propertyValue = getVariableLengthProperty(devInfoSet, devInfoData, propertyKey, SetupAPI.DEVPROP_TYPE_STRING() | SetupAPI.DEVPROP_TYPEMOD_LIST(), arena); if (propertyValue == null) @@ -125,7 +125,7 @@ private static MemorySegment getVariableLengthProperty(MemorySegment devInfoSet, // query length (thus no buffer) var propertyTypeHolder = arena.allocate(JAVA_INT); var requiredSizeHolder = arena.allocate(JAVA_INT); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, NULL, 0, requiredSizeHolder, 0, lastErrorState) == 0) { int err = Win.getLastError(lastErrorState); @@ -163,7 +163,7 @@ public static List findDeviceInterfaceGUIDs(MemorySegment devInfoSet, Me Arena arena) { try (var cleanup = new ScopeCleanup()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); // open device registry key var regKey = SetupAPI2.SetupDiOpenDevRegKey(devInfoSet, devInfoData, SetupAPI.DICS_FLAG_GLOBAL(), 0, @@ -201,8 +201,8 @@ public static List findDeviceInterfaceGUIDs(MemorySegment devInfoSet, Me * @return the device path */ public static String getDevicePath(String instanceID, MemorySegment interfaceGuid) { - try (var arena = Arena.openConfined(); var cleanup = new ScopeCleanup()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + try (var arena = Arena.ofConfined(); var cleanup = new ScopeCleanup()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); // get device info set for instance var instanceIDSegment = Win.createSegmentFromString(instanceID, arena); @@ -254,7 +254,7 @@ public static boolean isCompositeDevice(MemorySegment devInfoSet, MemorySegment private static MemorySegment createDEVPROPKEY(int data1, short data2, short data3, byte data4_0, byte data4_1, byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7, int pid) { - var propKey = Win.GLOBAL_ALLOCATOR.allocate(DEVPROPKEY.$LAYOUT()); + var propKey = Arena.global().allocate(DEVPROPKEY.$LAYOUT()); Win.setGUID(DEVPROPKEY.fmtid$slice(propKey), data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4 , data4_5, data4_6, data4_7); DEVPROPKEY.pid$set(propKey, pid); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java index bc0738ea..81dccff3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java @@ -44,11 +44,15 @@ public class USBHelper { // USB_CONNECTION_STATUS ConnectionStatus;/* OUTPUT */ // USB_PIPE_INFO PipeList[0];/* OUTPUT */ //} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; - public static final GroupLayout USB_NODE_CONNECTION_INFORMATION_EX$Struct = structLayout(JAVA_INT.withName( - "ConnectionIndex"), DeviceDescriptor.LAYOUT.withName("DeviceDescriptor"), JAVA_BYTE.withName( - "CurrentConfigurationValue"), JAVA_BYTE.withName("Speed"), JAVA_BYTE.withName("DeviceIsHub"), - JAVA_SHORT_UNALIGNED.withName("DeviceAddress"), JAVA_INT.withName("NumberOfOpenPipes"), - JAVA_INT.withName("ConnectionStatus") + public static final GroupLayout USB_NODE_CONNECTION_INFORMATION_EX$Struct = structLayout( + JAVA_INT.withName("ConnectionIndex"), + DeviceDescriptor.LAYOUT.withName("DeviceDescriptor"), + JAVA_BYTE.withName("CurrentConfigurationValue"), + JAVA_BYTE.withName("Speed"), + JAVA_BYTE.withName("DeviceIsHub"), + JAVA_SHORT_UNALIGNED.withName("DeviceAddress"), + JAVA_INT_UNALIGNED.withName("NumberOfOpenPipes"), + JAVA_INT_UNALIGNED.withName("ConnectionStatus") // USB_PIPE_INFO PipeList[0] ); public static final VarHandle USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex = diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index ff2a3bea..394faadb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -10,6 +10,7 @@ import net.codecrete.usb.windows.gen.kernel32.GUID; import java.lang.foreign.*; +import java.lang.foreign.MemoryLayout.PathElement; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.List; @@ -22,19 +23,14 @@ */ public class Win { - /** - * Global native memory segment allocator. - */ - public static final SegmentAllocator GLOBAL_ALLOCATOR = SegmentAllocator.nativeAllocator(SegmentScope.global()); - /** * Call state for capturing the {@code GetLastError()} value. */ - public static final Linker.Option.CaptureCallState LAST_ERROR_STATE = Linker.Option.captureCallState( - "GetLastError"); + public static final Linker.Option LAST_ERROR_STATE = Linker.Option.captureCallState("GetLastError"); + public static final StructLayout LAST_ERROR_STATE_LAYOUT = Linker.Option.captureStateLayout(); private static final VarHandle callState_GetLastError$VH = - LAST_ERROR_STATE.layout().varHandle(MemoryLayout.PathElement.groupElement("GetLastError")); + LAST_ERROR_STATE_LAYOUT.varHandle(PathElement.groupElement("GetLastError")); /** * Returns the error code captured using the call state {@link #LAST_ERROR_STATE}. @@ -132,7 +128,7 @@ public static List createStringListFromSegment(MemorySegment segment) { public static MemorySegment CreateGUID(int data1, short data2, short data3, byte data4_0, byte data4_1, byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7) { - var guid = GLOBAL_ALLOCATOR.allocate(GUID.$LAYOUT()); + var guid = Arena.global().allocate(GUID.$LAYOUT()); setGUID(guid, data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4, data4_5, data4_6, data4_7); return guid; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java index cd84821a..53c95ae9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java @@ -70,12 +70,12 @@ static synchronized WindowsAsyncTask instance() { */ private void asyncCompletionTask() { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var overlappedHolder = arena.allocate(ADDRESS, NULL); var numBytesHolder = arena.allocate(JAVA_INT, 0); var completionKeyHolder = arena.allocate(JAVA_LONG, 0); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); while (true) { overlappedHolder.set(ADDRESS, 0, MemorySegment.NULL); @@ -106,8 +106,8 @@ private void asyncCompletionTask() { */ synchronized void addDevice(MemorySegment handle) { - try (var arena = Arena.openConfined()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + try (var arena = Arena.ofConfined()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); // Creates a new port if it doesn't exist; adds handle to existing port if it exists MemorySegment portHandle = Kernel32B.CreateIoCompletionPort(handle, asyncIoCompletionPort, @@ -124,7 +124,7 @@ synchronized void addDevice(MemorySegment handle) { private void startAsyncIOTask() { availableOverlappedStructs = new ArrayList<>(); - arena = Arena.openShared(); + arena = Arena.ofShared(); requestsByOverlapped = new HashMap<>(); // start background thread for handling IO completion diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 4d9efa38..553cdee6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -113,10 +113,10 @@ public synchronized void claimInterface(int interfaceNumber) { if (firstIntfHandle.devicePath == null) throwException("Interface number %d cannot be claimed (non WinUSB device?)", interfaceNumber); - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { MemorySegment deviceHandle; - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); // open Windows device if needed if (firstIntfHandle.deviceHandle == null) { @@ -170,8 +170,8 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna throwException("Interface %d does not have an alternate interface setting %d", interfaceNumber, alternateNumber); - try (var arena = Arena.openConfined()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + try (var arena = Arena.ofConfined()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); if (WinUSB2.WinUsb_SetCurrentAlternateSetting(intfHandle.interfaceHandle, (byte) alternateNumber, lastErrorState) == 0) throwLastError(lastErrorState, "Failed to set alternate interface"); @@ -206,7 +206,7 @@ public synchronized void releaseInterface(int interfaceNumber) { @Override public void controlTransferOut(USBControlTransfer setup, byte[] data) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { // copy data to native memory var transfer = createSyncControlTransfer(); @@ -229,7 +229,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { @Override public byte[] controlTransferIn(USBControlTransfer setup, int length) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var transfer = createSyncControlTransfer(); transfer.data = arena.allocate(length); transfer.dataSize = length; @@ -245,7 +245,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { @Override public void transferOut(int endpointNumber, byte[] data, int offset, int length, int timeout) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var buffer = arena.allocate(data.length); buffer.copyFrom(MemorySegment.ofArray(data).asSlice(offset, length)); var transfer = createSyncTransfer(buffer); @@ -261,7 +261,7 @@ public void transferOut(int endpointNumber, byte[] data, int offset, int length, public byte[] transferIn(int endpointNumber, int timeout) { var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var buffer = arena.allocate(endpoint.packetSize()); var transfer = createSyncTransfer(buffer); @@ -302,7 +302,7 @@ synchronized void submitControlTransfer(USBDirection direction, USBControlTransf checkIsOpen(); var intfHandle = findControlTransferInterface(setup); - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var setupPacket = new SetupPacket(arena); var bmRequest = (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); @@ -312,7 +312,7 @@ synchronized void submitControlTransfer(USBDirection direction, USBControlTransf setupPacket.setIndex(setup.index()); setupPacket.setLength(transfer.dataSize); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); asyncTask.prepareForSubmission(transfer); // submit transfer @@ -329,8 +329,8 @@ synchronized void submitTransferOut(int endpointNumber, WindowsTransfer transfer var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); - try (var arena = Arena.openConfined()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + try (var arena = Arena.ofConfined()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); asyncTask.prepareForSubmission(transfer); // submit transfer @@ -347,8 +347,8 @@ synchronized void submitTransferIn(int endpointNumber, WindowsTransfer transfer) var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); - try (var arena = Arena.openConfined()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + try (var arena = Arena.ofConfined()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); asyncTask.prepareForSubmission(transfer); // submit transfer @@ -365,8 +365,8 @@ synchronized void configureForAsyncIo(USBDirection direction, int endpointNumber var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); - try (var arena = Arena.openConfined()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + try (var arena = Arena.ofConfined()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); var timeoutHolder = arena.allocate(JAVA_INT, 0); if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), @@ -385,8 +385,8 @@ public synchronized void clearHalt(USBDirection direction, int endpointNumber) { var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); - try (var arena = Arena.openConfined()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + try (var arena = Arena.ofConfined()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); if (WinUSB2.WinUsb_ResetPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), lastErrorState) == 0) throwLastError(lastErrorState, "Clearing halt failed"); } @@ -397,8 +397,8 @@ public synchronized void abortTransfers(USBDirection direction, int endpointNumb var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); - try (var arena = Arena.openConfined()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + try (var arena = Arena.ofConfined()) { + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); if (WinUSB2.WinUsb_AbortPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), lastErrorState) == 0) throwLastError(lastErrorState, "Aborting transfers on endpoint failed"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 12a21fbb..ac6fcc6a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -58,10 +58,10 @@ public class WindowsUSBDeviceRegistry extends USBDeviceRegistry { @Override protected void monitorDevices() { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { MemorySegment hwnd; - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); try { final var className = Win.createSegmentFromString("USB_MONITOR", arena); @@ -73,7 +73,7 @@ protected void monitorDevices() { "handleWindowMessage", MethodType.methodType(long.class, MemorySegment.class, int.class, long.class, long.class)).bindTo(this); var handleWindowMessageStub = Linker.nativeLinker().upcallStub(handleWindowMessageMH, - FunctionDescriptor.of(JAVA_LONG, ADDRESS, JAVA_INT, JAVA_LONG, JAVA_LONG), arena.scope()); + FunctionDescriptor.of(JAVA_LONG, ADDRESS, JAVA_INT, JAVA_LONG, JAVA_LONG), arena); // register window class var wx = arena.allocate(WNDCLASSEXW.$LAYOUT()); @@ -126,9 +126,9 @@ protected void monitorDevices() { private void enumeratePresentDevices() { List deviceList = new ArrayList<>(); - try (var outerArena = Arena.openConfined(); var outerCleanup = new ScopeCleanup()) { + try (var outerArena = Arena.ofConfined(); var outerCleanup = new ScopeCleanup()) { - var lastErrorState = outerArena.allocate(Win.LAST_ERROR_STATE.layout()); + var lastErrorState = outerArena.allocate(Win.LAST_ERROR_STATE_LAYOUT); // get device information set of all USB devices present var devInfoSet = SetupAPI2.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, @@ -187,9 +187,9 @@ private Map enumerateChildren(List childrenIds) { // iterate all children for (var instanceId : childrenIds) { - try (var arena = Arena.openConfined(); var cleanup = new ScopeCleanup()) { + try (var arena = Arena.ofConfined(); var cleanup = new ScopeCleanup()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); // create empty device info set var devInfoSet = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, lastErrorState); @@ -239,7 +239,7 @@ private Map enumerateChildren(List childrenIds) { private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSet, MemorySegment devInfoData, String devicePath, HashMap hubHandles) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var usbPortNum = DeviceProperty.getDeviceIntProperty(devInfoSet, devInfoData, DeviceProperty.DEVPKEY_Device_Address); @@ -251,7 +251,7 @@ private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSet, MemorySeg var hubHandle = hubHandles.get(hubPath); if (hubHandle == null) { var hubPathSeg = Win.createSegmentFromString(hubPath, arena); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); hubHandle = Kernel32B.CreateFileW(hubPathSeg, Kernel32.GENERIC_WRITE(), Kernel32.FILE_SHARE_WRITE(), NULL, Kernel32.OPEN_EXISTING(), 0, NULL, lastErrorState); if (Win.IsInvalidHandle(hubHandle)) @@ -306,13 +306,13 @@ private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSet, MemorySeg private USBDevice createDevice(String devicePath, Map children, MemorySegment hubHandle, int usbPortNum) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { // get device descriptor var connInfo = arena.allocate(USBHelper.USB_NODE_CONNECTION_INFORMATION_EX$Struct); USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex.set(connInfo, usbPortNum); var sizeHolder = arena.allocate(JAVA_INT); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); if (Kernel32B.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), connInfo, (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL, lastErrorState) == 0) @@ -359,7 +359,7 @@ private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, // execute request var effectiveSizeHolder = arena.allocate(JAVA_INT); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); if (Kernel32B.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION(), descriptorRequest, size, descriptorRequest, size, effectiveSizeHolder, NULL, lastErrorState) == 0) throwLastError(lastErrorState, "Cannot retrieve descriptor %d", index); @@ -391,7 +391,7 @@ private String getStringDescriptor(MemorySegment hubHandle, int usbPortNumber, i if (index == 0) return null; - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var stringDesc = new StringDescriptor(getDescriptor(hubHandle, usbPortNumber, STRING_DESCRIPTOR_TYPE, index, DEFAULT_LANGUAGE, arena)); return stringDesc.string(); @@ -406,12 +406,12 @@ private long handleWindowMessage(MemorySegment hWnd, int uMsg, long wParam, long // check for message related to connecting/disconnecting devices if (uMsg == User32.WM_DEVICECHANGE() && (wParam == User32.DBT_DEVICEARRIVAL() || wParam == User32.DBT_DEVICEREMOVECOMPLETE())) { - var data = MemorySegment.ofAddress(lParam, DEV_BROADCAST_DEVICEINTERFACE_W.sizeof()); + var data = MemorySegment.ofAddress(lParam).reinterpret(DEV_BROADCAST_DEVICEINTERFACE_W.sizeof()); if (DEV_BROADCAST_HDR.dbch_devicetype$get(data) == User32.DBT_DEVTYP_DEVICEINTERFACE()) { // get device path var nameSlice = - MemorySegment.ofAddress(DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address(), 500); + MemorySegment.ofAddress(DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address()).reinterpret(500); var devicePath = Win.createStringFromSegment(nameSlice); if (wParam == User32.DBT_DEVICEARRIVAL()) onDeviceConnected(devicePath); @@ -426,9 +426,9 @@ private long handleWindowMessage(MemorySegment hWnd, int uMsg, long wParam, long } private void onDeviceConnected(String devicePath) { - try (var arena = Arena.openConfined(); var cleanup = new ScopeCleanup()) { + try (var arena = Arena.ofConfined(); var cleanup = new ScopeCleanup()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout()); + var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); // create empty device info set var devInfoSet = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, lastErrorState); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java index d6dde4c7..b0c83457 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java @@ -8,7 +8,6 @@ import net.codecrete.usb.USBException; import net.codecrete.usb.USBStallException; -import net.codecrete.usb.common.ForeignMemory; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.ntdll.NtDll; @@ -84,7 +83,7 @@ static void throwLastError(MemorySegment lastErrorState, String message, Object. private static MemorySegment getNtModule() { if (ntModule == null) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var moduleName = Win.createSegmentFromString("NTDLL.DLL", arena); ntModule = Kernel32.GetModuleHandleW(moduleName); } @@ -94,7 +93,7 @@ private static MemorySegment getNtModule() { } static String getErrorMessage(int errorCode) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var messagePointerHolder = arena.allocate(ADDRESS); // First try: Win32 error code @@ -113,7 +112,7 @@ static String getErrorMessage(int errorCode) { if (res == 0) return "unspecified error"; - var messagePointer = messagePointerHolder.get(ForeignMemory.UNBOUNDED_ADDRESS, 0); + var messagePointer = messagePointerHolder.get(ADDRESS, 0).reinterpret(128 * 1024); String message = Win.createStringFromSegment(messagePointer); Kernel32.LocalFree(messagePointer); return message.trim(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java index d90e6ad3..6152d8c1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java @@ -2,22 +2,23 @@ package net.codecrete.usb.windows.gen.advapi32; +import java.lang.foreign.AddressLayout; import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class Advapi32 { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfInt C_LONG = JAVA_INT; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; public static MethodHandle RegCloseKey$MH() { - return RuntimeHelper.requireNonNull(constants$0.RegCloseKey$MH,"RegCloseKey"); + return RuntimeHelper.requireNonNull(constants$0.const$1,"RegCloseKey"); } /** * {@snippet : @@ -33,7 +34,7 @@ public static int RegCloseKey(MemorySegment hKey) { } } public static MethodHandle RegQueryValueExW$MH() { - return RuntimeHelper.requireNonNull(constants$0.RegQueryValueExW$MH,"RegQueryValueExW"); + return RuntimeHelper.requireNonNull(constants$0.const$3,"RegQueryValueExW"); } /** * {@snippet : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Constants$root.java deleted file mode 100644 index 0f7077fb..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.advapi32; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfInt C_LONG$LAYOUT = JAVA_INT; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java index 1a4c2ea6..868da383 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java @@ -15,9 +15,10 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { System.loadLibrary("Advapi32"); @@ -36,7 +37,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -55,18 +58,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/constants$0.java index 0d959825..ee2a9f73 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/constants$0.java @@ -4,28 +4,30 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} - static final FunctionDescriptor RegCloseKey$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT + static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER ); - static final MethodHandle RegCloseKey$MH = RuntimeHelper.downcallHandle( + static final MethodHandle const$1 = RuntimeHelper.downcallHandle( "RegCloseKey", - constants$0.RegCloseKey$FUNC + constants$0.const$0 ); - static final FunctionDescriptor RegQueryValueExW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT + static final FunctionDescriptor const$2 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER ); - static final MethodHandle RegQueryValueExW$MH = RuntimeHelper.downcallHandle( + static final MethodHandle const$3 = RuntimeHelper.downcallHandle( "RegQueryValueExW", - constants$0.RegQueryValueExW$FUNC + constants$0.const$2 ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Constants$root.java deleted file mode 100644 index a523ae8e..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.kernel32; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfInt C_LONG$LAYOUT = JAVA_INT; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java index 6951a326..4561b07f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -2,20 +2,21 @@ package net.codecrete.usb.windows.gen.kernel32; +import java.lang.foreign.AddressLayout; import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class Kernel32 { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfInt C_LONG = JAVA_INT; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; /** * {@snippet : * #define FILE_SHARE_READ 1 @@ -89,7 +90,7 @@ public static int FORMAT_MESSAGE_FROM_SYSTEM() { return (int)4096L; } public static MethodHandle CloseHandle$MH() { - return RuntimeHelper.requireNonNull(constants$0.CloseHandle$MH,"CloseHandle"); + return RuntimeHelper.requireNonNull(constants$1.const$6,"CloseHandle"); } /** * {@snippet : @@ -105,7 +106,7 @@ public static int CloseHandle(MemorySegment hObject) { } } public static MethodHandle GetModuleHandleW$MH() { - return RuntimeHelper.requireNonNull(constants$0.GetModuleHandleW$MH,"GetModuleHandleW"); + return RuntimeHelper.requireNonNull(constants$2.const$1,"GetModuleHandleW"); } /** * {@snippet : @@ -121,7 +122,7 @@ public static MemorySegment GetModuleHandleW(MemorySegment lpModuleName) { } } public static MethodHandle LocalFree$MH() { - return RuntimeHelper.requireNonNull(constants$0.LocalFree$MH,"LocalFree"); + return RuntimeHelper.requireNonNull(constants$2.const$2,"LocalFree"); } /** * {@snippet : @@ -137,7 +138,7 @@ public static MemorySegment LocalFree(MemorySegment hMem) { } } public static MethodHandle FormatMessageW$MH() { - return RuntimeHelper.requireNonNull(constants$0.FormatMessageW$MH,"FormatMessageW"); + return RuntimeHelper.requireNonNull(constants$2.const$4,"FormatMessageW"); } /** * {@snippet : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java index 75671ff6..2f61c112 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java @@ -15,9 +15,10 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { System.loadLibrary("Kernel32"); @@ -36,7 +37,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -55,18 +58,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java index 8378c2cb..ead65d4b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java @@ -2,7 +2,10 @@ package net.codecrete.usb.windows.gen.kernel32; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -16,18 +19,11 @@ */ public class _GUID { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_LONG$LAYOUT.withName("Data1"), - Constants$root.C_SHORT$LAYOUT.withName("Data2"), - Constants$root.C_SHORT$LAYOUT.withName("Data3"), - MemoryLayout.sequenceLayout(8, Constants$root.C_CHAR$LAYOUT).withName("Data4") - ).withName("_GUID"); public static MemoryLayout $LAYOUT() { - return _GUID.$struct$LAYOUT; + return constants$0.const$0; } - static final VarHandle Data1$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Data1")); public static VarHandle Data1$VH() { - return _GUID.Data1$VH; + return constants$0.const$1; } /** * Getter for field: @@ -36,7 +32,7 @@ public class _GUID { * } */ public static int Data1$get(MemorySegment seg) { - return (int)_GUID.Data1$VH.get(seg); + return (int)constants$0.const$1.get(seg); } /** * Setter for field: @@ -45,17 +41,16 @@ public class _GUID { * } */ public static void Data1$set(MemorySegment seg, int x) { - _GUID.Data1$VH.set(seg, x); + constants$0.const$1.set(seg, x); } public static int Data1$get(MemorySegment seg, long index) { - return (int)_GUID.Data1$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$0.const$1.get(seg.asSlice(index*sizeof())); } public static void Data1$set(MemorySegment seg, long index, int x) { - _GUID.Data1$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$1.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle Data2$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Data2")); public static VarHandle Data2$VH() { - return _GUID.Data2$VH; + return constants$0.const$2; } /** * Getter for field: @@ -64,7 +59,7 @@ public class _GUID { * } */ public static short Data2$get(MemorySegment seg) { - return (short)_GUID.Data2$VH.get(seg); + return (short)constants$0.const$2.get(seg); } /** * Setter for field: @@ -73,17 +68,16 @@ public class _GUID { * } */ public static void Data2$set(MemorySegment seg, short x) { - _GUID.Data2$VH.set(seg, x); + constants$0.const$2.set(seg, x); } public static short Data2$get(MemorySegment seg, long index) { - return (short)_GUID.Data2$VH.get(seg.asSlice(index*sizeof())); + return (short)constants$0.const$2.get(seg.asSlice(index*sizeof())); } public static void Data2$set(MemorySegment seg, long index, short x) { - _GUID.Data2$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$2.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle Data3$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Data3")); public static VarHandle Data3$VH() { - return _GUID.Data3$VH; + return constants$0.const$3; } /** * Getter for field: @@ -92,7 +86,7 @@ public class _GUID { * } */ public static short Data3$get(MemorySegment seg) { - return (short)_GUID.Data3$VH.get(seg); + return (short)constants$0.const$3.get(seg); } /** * Setter for field: @@ -101,13 +95,13 @@ public class _GUID { * } */ public static void Data3$set(MemorySegment seg, short x) { - _GUID.Data3$VH.set(seg, x); + constants$0.const$3.set(seg, x); } public static short Data3$get(MemorySegment seg, long index) { - return (short)_GUID.Data3$VH.get(seg.asSlice(index*sizeof())); + return (short)constants$0.const$3.get(seg.asSlice(index*sizeof())); } public static void Data3$set(MemorySegment seg, long index, short x) { - _GUID.Data3$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$3.set(seg.asSlice(index*sizeof()), x); } public static MemorySegment Data4$slice(MemorySegment seg) { return seg.asSlice(8, 8); @@ -117,7 +111,7 @@ public class _GUID { public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java index fd578468..770014d6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java @@ -2,7 +2,10 @@ package net.codecrete.usb.windows.gen.kernel32; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -22,24 +25,11 @@ */ public class _OVERLAPPED { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_LONG_LONG$LAYOUT.withName("Internal"), - Constants$root.C_LONG_LONG$LAYOUT.withName("InternalHigh"), - MemoryLayout.unionLayout( - MemoryLayout.structLayout( - Constants$root.C_LONG$LAYOUT.withName("Offset"), - Constants$root.C_LONG$LAYOUT.withName("OffsetHigh") - ).withName("$anon$0"), - Constants$root.C_POINTER$LAYOUT.withName("Pointer") - ).withName("$anon$0"), - Constants$root.C_POINTER$LAYOUT.withName("hEvent") - ).withName("_OVERLAPPED"); public static MemoryLayout $LAYOUT() { - return _OVERLAPPED.$struct$LAYOUT; + return constants$0.const$4; } - static final VarHandle Internal$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Internal")); public static VarHandle Internal$VH() { - return _OVERLAPPED.Internal$VH; + return constants$0.const$5; } /** * Getter for field: @@ -48,7 +38,7 @@ public class _OVERLAPPED { * } */ public static long Internal$get(MemorySegment seg) { - return (long)_OVERLAPPED.Internal$VH.get(seg); + return (long)constants$0.const$5.get(seg); } /** * Setter for field: @@ -57,17 +47,16 @@ public class _OVERLAPPED { * } */ public static void Internal$set(MemorySegment seg, long x) { - _OVERLAPPED.Internal$VH.set(seg, x); + constants$0.const$5.set(seg, x); } public static long Internal$get(MemorySegment seg, long index) { - return (long)_OVERLAPPED.Internal$VH.get(seg.asSlice(index*sizeof())); + return (long)constants$0.const$5.get(seg.asSlice(index*sizeof())); } public static void Internal$set(MemorySegment seg, long index, long x) { - _OVERLAPPED.Internal$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$5.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle InternalHigh$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("InternalHigh")); public static VarHandle InternalHigh$VH() { - return _OVERLAPPED.InternalHigh$VH; + return constants$1.const$0; } /** * Getter for field: @@ -76,7 +65,7 @@ public class _OVERLAPPED { * } */ public static long InternalHigh$get(MemorySegment seg) { - return (long)_OVERLAPPED.InternalHigh$VH.get(seg); + return (long)constants$1.const$0.get(seg); } /** * Setter for field: @@ -85,17 +74,16 @@ public class _OVERLAPPED { * } */ public static void InternalHigh$set(MemorySegment seg, long x) { - _OVERLAPPED.InternalHigh$VH.set(seg, x); + constants$1.const$0.set(seg, x); } public static long InternalHigh$get(MemorySegment seg, long index) { - return (long)_OVERLAPPED.InternalHigh$VH.get(seg.asSlice(index*sizeof())); + return (long)constants$1.const$0.get(seg.asSlice(index*sizeof())); } public static void InternalHigh$set(MemorySegment seg, long index, long x) { - _OVERLAPPED.InternalHigh$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$0.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle Offset$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("Offset")); public static VarHandle Offset$VH() { - return _OVERLAPPED.Offset$VH; + return constants$1.const$1; } /** * Getter for field: @@ -104,7 +92,7 @@ public class _OVERLAPPED { * } */ public static int Offset$get(MemorySegment seg) { - return (int)_OVERLAPPED.Offset$VH.get(seg); + return (int)constants$1.const$1.get(seg); } /** * Setter for field: @@ -113,17 +101,16 @@ public class _OVERLAPPED { * } */ public static void Offset$set(MemorySegment seg, int x) { - _OVERLAPPED.Offset$VH.set(seg, x); + constants$1.const$1.set(seg, x); } public static int Offset$get(MemorySegment seg, long index) { - return (int)_OVERLAPPED.Offset$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$1.const$1.get(seg.asSlice(index*sizeof())); } public static void Offset$set(MemorySegment seg, long index, int x) { - _OVERLAPPED.Offset$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$1.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle OffsetHigh$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("OffsetHigh")); public static VarHandle OffsetHigh$VH() { - return _OVERLAPPED.OffsetHigh$VH; + return constants$1.const$2; } /** * Getter for field: @@ -132,7 +119,7 @@ public class _OVERLAPPED { * } */ public static int OffsetHigh$get(MemorySegment seg) { - return (int)_OVERLAPPED.OffsetHigh$VH.get(seg); + return (int)constants$1.const$2.get(seg); } /** * Setter for field: @@ -141,17 +128,16 @@ public class _OVERLAPPED { * } */ public static void OffsetHigh$set(MemorySegment seg, int x) { - _OVERLAPPED.OffsetHigh$VH.set(seg, x); + constants$1.const$2.set(seg, x); } public static int OffsetHigh$get(MemorySegment seg, long index) { - return (int)_OVERLAPPED.OffsetHigh$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$1.const$2.get(seg.asSlice(index*sizeof())); } public static void OffsetHigh$set(MemorySegment seg, long index, int x) { - _OVERLAPPED.OffsetHigh$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$2.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle Pointer$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("Pointer")); public static VarHandle Pointer$VH() { - return _OVERLAPPED.Pointer$VH; + return constants$1.const$3; } /** * Getter for field: @@ -160,7 +146,7 @@ public class _OVERLAPPED { * } */ public static MemorySegment Pointer$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)_OVERLAPPED.Pointer$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$1.const$3.get(seg); } /** * Setter for field: @@ -169,17 +155,16 @@ public class _OVERLAPPED { * } */ public static void Pointer$set(MemorySegment seg, MemorySegment x) { - _OVERLAPPED.Pointer$VH.set(seg, x); + constants$1.const$3.set(seg, x); } public static MemorySegment Pointer$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)_OVERLAPPED.Pointer$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$1.const$3.get(seg.asSlice(index*sizeof())); } public static void Pointer$set(MemorySegment seg, long index, MemorySegment x) { - _OVERLAPPED.Pointer$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$3.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle hEvent$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hEvent")); public static VarHandle hEvent$VH() { - return _OVERLAPPED.hEvent$VH; + return constants$1.const$4; } /** * Getter for field: @@ -188,7 +173,7 @@ public class _OVERLAPPED { * } */ public static MemorySegment hEvent$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)_OVERLAPPED.hEvent$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$1.const$4.get(seg); } /** * Setter for field: @@ -197,20 +182,20 @@ public class _OVERLAPPED { * } */ public static void hEvent$set(MemorySegment seg, MemorySegment x) { - _OVERLAPPED.hEvent$VH.set(seg, x); + constants$1.const$4.set(seg, x); } public static MemorySegment hEvent$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)_OVERLAPPED.hEvent$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$1.const$4.get(seg.asSlice(index*sizeof())); } public static void hEvent$set(MemorySegment seg, long index, MemorySegment x) { - _OVERLAPPED.hEvent$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$4.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java index 027db927..18b60b9b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java @@ -2,46 +2,37 @@ package net.codecrete.usb.windows.gen.kernel32; -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.*; final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} - static final FunctionDescriptor CloseHandle$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle CloseHandle$MH = RuntimeHelper.downcallHandle( - "CloseHandle", - constants$0.CloseHandle$FUNC - ); - static final FunctionDescriptor GetModuleHandleW$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetModuleHandleW$MH = RuntimeHelper.downcallHandle( - "GetModuleHandleW", - constants$0.GetModuleHandleW$FUNC - ); - static final FunctionDescriptor LocalFree$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle LocalFree$MH = RuntimeHelper.downcallHandle( - "LocalFree", - constants$0.LocalFree$FUNC - ); - static final FunctionDescriptor FormatMessageW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle FormatMessageW$MH = RuntimeHelper.downcallHandle( - "FormatMessageW", - constants$0.FormatMessageW$FUNC - ); + static final StructLayout const$0 = MemoryLayout.structLayout( + JAVA_INT.withName("Data1"), + JAVA_SHORT.withName("Data2"), + JAVA_SHORT.withName("Data3"), + MemoryLayout.sequenceLayout(8, JAVA_BYTE).withName("Data4") + ).withName("_GUID"); + static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("Data1")); + static final VarHandle const$2 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("Data2")); + static final VarHandle const$3 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("Data3")); + static final StructLayout const$4 = MemoryLayout.structLayout( + JAVA_LONG.withName("Internal"), + JAVA_LONG.withName("InternalHigh"), + MemoryLayout.unionLayout( + MemoryLayout.structLayout( + JAVA_INT.withName("Offset"), + JAVA_INT.withName("OffsetHigh") + ).withName("$anon$0"), + RuntimeHelper.POINTER.withName("Pointer") + ).withName("$anon$0"), + RuntimeHelper.POINTER.withName("hEvent") + ).withName("_OVERLAPPED"); + static final VarHandle const$5 = constants$0.const$4.varHandle(MemoryLayout.PathElement.groupElement("Internal")); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java new file mode 100644 index 00000000..b86794ff --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java @@ -0,0 +1,29 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.kernel32; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$1 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$1() {} + static final VarHandle const$0 = constants$0.const$4.varHandle(MemoryLayout.PathElement.groupElement("InternalHigh")); + static final VarHandle const$1 = constants$0.const$4.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("Offset")); + static final VarHandle const$2 = constants$0.const$4.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("OffsetHigh")); + static final VarHandle const$3 = constants$0.const$4.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("Pointer")); + static final VarHandle const$4 = constants$0.const$4.varHandle(MemoryLayout.PathElement.groupElement("hEvent")); + static final FunctionDescriptor const$5 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER + ); + static final MethodHandle const$6 = RuntimeHelper.downcallHandle( + "CloseHandle", + constants$1.const$5 + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$2.java new file mode 100644 index 00000000..0f426d9c --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$2.java @@ -0,0 +1,39 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.kernel32; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$2 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$2() {} + static final FunctionDescriptor const$0 = FunctionDescriptor.of(RuntimeHelper.POINTER, + RuntimeHelper.POINTER + ); + static final MethodHandle const$1 = RuntimeHelper.downcallHandle( + "GetModuleHandleW", + constants$2.const$0 + ); + static final MethodHandle const$2 = RuntimeHelper.downcallHandle( + "LocalFree", + constants$2.const$0 + ); + static final FunctionDescriptor const$3 = FunctionDescriptor.of(JAVA_INT, + JAVA_INT, + RuntimeHelper.POINTER, + JAVA_INT, + JAVA_INT, + RuntimeHelper.POINTER, + JAVA_INT, + RuntimeHelper.POINTER + ); + static final MethodHandle const$4 = RuntimeHelper.downcallHandle( + "FormatMessageW", + constants$2.const$3 + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/Constants$root.java deleted file mode 100644 index d0e6f9f6..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.ntdll; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfInt C_LONG$LAYOUT = JAVA_INT; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java index d43f1028..c7dbf69a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java @@ -2,17 +2,19 @@ package net.codecrete.usb.windows.gen.ntdll; +import java.lang.foreign.AddressLayout; + import static java.lang.foreign.ValueLayout.*; public class NtDll { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfInt C_LONG = JAVA_INT; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; /** * {@snippet : * #define STATUS_UNSUCCESSFUL -1073741823 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/RuntimeHelper.java index a7c0fcaa..45bfd22b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/RuntimeHelper.java @@ -15,9 +15,10 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { @@ -36,7 +37,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -55,18 +58,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/constants$0.java new file mode 100644 index 00000000..7bb245f6 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/constants$0.java @@ -0,0 +1,11 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.ntdll; + +final class constants$0 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Constants$root.java deleted file mode 100644 index 73537493..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.ole32; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfInt C_LONG$LAYOUT = JAVA_INT; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java index 50284a0c..15bc34d0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java @@ -2,22 +2,23 @@ package net.codecrete.usb.windows.gen.ole32; +import java.lang.foreign.AddressLayout; import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class Ole32 { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfInt C_LONG = JAVA_INT; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; public static MethodHandle CLSIDFromString$MH() { - return RuntimeHelper.requireNonNull(constants$0.CLSIDFromString$MH,"CLSIDFromString"); + return RuntimeHelper.requireNonNull(constants$0.const$1,"CLSIDFromString"); } /** * {@snippet : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java index 311819e6..c58af8c4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java @@ -15,9 +15,10 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { System.loadLibrary("Ole32"); @@ -36,7 +37,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -55,18 +58,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/constants$0.java index 9f9b0a6d..bf4c2c05 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/constants$0.java @@ -4,17 +4,19 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} - static final FunctionDescriptor CLSIDFromString$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT + static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER ); - static final MethodHandle CLSIDFromString$MH = RuntimeHelper.downcallHandle( + static final MethodHandle const$1 = RuntimeHelper.downcallHandle( "CLSIDFromString", - constants$0.CLSIDFromString$FUNC + constants$0.const$0 ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/Constants$root.java deleted file mode 100644 index 6d0aae8c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.setupapi; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfInt C_LONG$LAYOUT = JAVA_INT; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java index 4380383f..6a51526d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java @@ -15,9 +15,10 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { System.loadLibrary("SetupAPI"); @@ -36,7 +37,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -55,18 +58,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java index bbf36562..bccea11d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java @@ -2,20 +2,21 @@ package net.codecrete.usb.windows.gen.setupapi; +import java.lang.foreign.AddressLayout; import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class SetupAPI { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfInt C_LONG = JAVA_INT; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; /** * {@snippet : * #define DEVPROP_TYPEMOD_LIST 8192 @@ -73,7 +74,7 @@ public static int DIREG_DEV() { return (int)1L; } public static MethodHandle SetupDiDestroyDeviceInfoList$MH() { - return RuntimeHelper.requireNonNull(constants$0.SetupDiDestroyDeviceInfoList$MH,"SetupDiDestroyDeviceInfoList"); + return RuntimeHelper.requireNonNull(constants$2.const$1,"SetupDiDestroyDeviceInfoList"); } /** * {@snippet : @@ -89,7 +90,7 @@ public static int SetupDiDestroyDeviceInfoList(MemorySegment DeviceInfoSet) { } } public static MethodHandle SetupDiDeleteDeviceInterfaceData$MH() { - return RuntimeHelper.requireNonNull(constants$0.SetupDiDeleteDeviceInterfaceData$MH,"SetupDiDeleteDeviceInterfaceData"); + return RuntimeHelper.requireNonNull(constants$2.const$3,"SetupDiDeleteDeviceInterfaceData"); } /** * {@snippet : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java index d1bdbfa4..8389d24a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java @@ -2,7 +2,10 @@ package net.codecrete.usb.windows.gen.setupapi; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -14,24 +17,14 @@ */ public class _DEVPROPKEY { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - MemoryLayout.structLayout( - Constants$root.C_LONG$LAYOUT.withName("Data1"), - Constants$root.C_SHORT$LAYOUT.withName("Data2"), - Constants$root.C_SHORT$LAYOUT.withName("Data3"), - MemoryLayout.sequenceLayout(8, Constants$root.C_CHAR$LAYOUT).withName("Data4") - ).withName("fmtid"), - Constants$root.C_LONG$LAYOUT.withName("pid") - ).withName("_DEVPROPKEY"); public static MemoryLayout $LAYOUT() { - return _DEVPROPKEY.$struct$LAYOUT; + return constants$0.const$0; } public static MemorySegment fmtid$slice(MemorySegment seg) { return seg.asSlice(0, 16); } - static final VarHandle pid$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("pid")); public static VarHandle pid$VH() { - return _DEVPROPKEY.pid$VH; + return constants$0.const$1; } /** * Getter for field: @@ -40,7 +33,7 @@ public class _DEVPROPKEY { * } */ public static int pid$get(MemorySegment seg) { - return (int)_DEVPROPKEY.pid$VH.get(seg); + return (int)constants$0.const$1.get(seg); } /** * Setter for field: @@ -49,20 +42,20 @@ public class _DEVPROPKEY { * } */ public static void pid$set(MemorySegment seg, int x) { - _DEVPROPKEY.pid$VH.set(seg, x); + constants$0.const$1.set(seg, x); } public static int pid$get(MemorySegment seg, long index) { - return (int)_DEVPROPKEY.pid$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$0.const$1.get(seg.asSlice(index*sizeof())); } public static void pid$set(MemorySegment seg, long index, int x) { - _DEVPROPKEY.pid$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$1.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java index 9bc40ea2..c1b5e09f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java @@ -2,7 +2,10 @@ package net.codecrete.usb.windows.gen.setupapi; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -16,23 +19,11 @@ */ public class _SP_DEVICE_INTERFACE_DATA { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_LONG$LAYOUT.withName("cbSize"), - MemoryLayout.structLayout( - Constants$root.C_LONG$LAYOUT.withName("Data1"), - Constants$root.C_SHORT$LAYOUT.withName("Data2"), - Constants$root.C_SHORT$LAYOUT.withName("Data3"), - MemoryLayout.sequenceLayout(8, Constants$root.C_CHAR$LAYOUT).withName("Data4") - ).withName("InterfaceClassGuid"), - Constants$root.C_LONG$LAYOUT.withName("Flags"), - Constants$root.C_LONG_LONG$LAYOUT.withName("Reserved") - ).withName("_SP_DEVICE_INTERFACE_DATA"); public static MemoryLayout $LAYOUT() { - return _SP_DEVICE_INTERFACE_DATA.$struct$LAYOUT; + return constants$1.const$0; } - static final VarHandle cbSize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("cbSize")); public static VarHandle cbSize$VH() { - return _SP_DEVICE_INTERFACE_DATA.cbSize$VH; + return constants$1.const$1; } /** * Getter for field: @@ -41,7 +32,7 @@ public class _SP_DEVICE_INTERFACE_DATA { * } */ public static int cbSize$get(MemorySegment seg) { - return (int)_SP_DEVICE_INTERFACE_DATA.cbSize$VH.get(seg); + return (int)constants$1.const$1.get(seg); } /** * Setter for field: @@ -50,20 +41,19 @@ public class _SP_DEVICE_INTERFACE_DATA { * } */ public static void cbSize$set(MemorySegment seg, int x) { - _SP_DEVICE_INTERFACE_DATA.cbSize$VH.set(seg, x); + constants$1.const$1.set(seg, x); } public static int cbSize$get(MemorySegment seg, long index) { - return (int)_SP_DEVICE_INTERFACE_DATA.cbSize$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$1.const$1.get(seg.asSlice(index*sizeof())); } public static void cbSize$set(MemorySegment seg, long index, int x) { - _SP_DEVICE_INTERFACE_DATA.cbSize$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$1.set(seg.asSlice(index*sizeof()), x); } public static MemorySegment InterfaceClassGuid$slice(MemorySegment seg) { return seg.asSlice(4, 16); } - static final VarHandle Flags$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Flags")); public static VarHandle Flags$VH() { - return _SP_DEVICE_INTERFACE_DATA.Flags$VH; + return constants$1.const$2; } /** * Getter for field: @@ -72,7 +62,7 @@ public class _SP_DEVICE_INTERFACE_DATA { * } */ public static int Flags$get(MemorySegment seg) { - return (int)_SP_DEVICE_INTERFACE_DATA.Flags$VH.get(seg); + return (int)constants$1.const$2.get(seg); } /** * Setter for field: @@ -81,17 +71,16 @@ public class _SP_DEVICE_INTERFACE_DATA { * } */ public static void Flags$set(MemorySegment seg, int x) { - _SP_DEVICE_INTERFACE_DATA.Flags$VH.set(seg, x); + constants$1.const$2.set(seg, x); } public static int Flags$get(MemorySegment seg, long index) { - return (int)_SP_DEVICE_INTERFACE_DATA.Flags$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$1.const$2.get(seg.asSlice(index*sizeof())); } public static void Flags$set(MemorySegment seg, long index, int x) { - _SP_DEVICE_INTERFACE_DATA.Flags$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$2.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle Reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Reserved")); public static VarHandle Reserved$VH() { - return _SP_DEVICE_INTERFACE_DATA.Reserved$VH; + return constants$1.const$3; } /** * Getter for field: @@ -100,7 +89,7 @@ public class _SP_DEVICE_INTERFACE_DATA { * } */ public static long Reserved$get(MemorySegment seg) { - return (long)_SP_DEVICE_INTERFACE_DATA.Reserved$VH.get(seg); + return (long)constants$1.const$3.get(seg); } /** * Setter for field: @@ -109,20 +98,20 @@ public class _SP_DEVICE_INTERFACE_DATA { * } */ public static void Reserved$set(MemorySegment seg, long x) { - _SP_DEVICE_INTERFACE_DATA.Reserved$VH.set(seg, x); + constants$1.const$3.set(seg, x); } public static long Reserved$get(MemorySegment seg, long index) { - return (long)_SP_DEVICE_INTERFACE_DATA.Reserved$VH.get(seg.asSlice(index*sizeof())); + return (long)constants$1.const$3.get(seg.asSlice(index*sizeof())); } public static void Reserved$set(MemorySegment seg, long index, long x) { - _SP_DEVICE_INTERFACE_DATA.Reserved$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$3.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java index 6f9b55e4..4a837e91 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java @@ -2,7 +2,10 @@ package net.codecrete.usb.windows.gen.setupapi; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -14,17 +17,11 @@ */ public class _SP_DEVICE_INTERFACE_DETAIL_DATA_W { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_LONG$LAYOUT.withName("cbSize"), - MemoryLayout.sequenceLayout(1, Constants$root.C_SHORT$LAYOUT).withName("DevicePath"), - MemoryLayout.paddingLayout(16) - ).withName("_SP_DEVICE_INTERFACE_DETAIL_DATA_W"); public static MemoryLayout $LAYOUT() { - return _SP_DEVICE_INTERFACE_DETAIL_DATA_W.$struct$LAYOUT; + return constants$1.const$4; } - static final VarHandle cbSize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("cbSize")); public static VarHandle cbSize$VH() { - return _SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$VH; + return constants$1.const$5; } /** * Getter for field: @@ -33,7 +30,7 @@ public class _SP_DEVICE_INTERFACE_DETAIL_DATA_W { * } */ public static int cbSize$get(MemorySegment seg) { - return (int)_SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$VH.get(seg); + return (int)constants$1.const$5.get(seg); } /** * Setter for field: @@ -42,13 +39,13 @@ public class _SP_DEVICE_INTERFACE_DETAIL_DATA_W { * } */ public static void cbSize$set(MemorySegment seg, int x) { - _SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$VH.set(seg, x); + constants$1.const$5.set(seg, x); } public static int cbSize$get(MemorySegment seg, long index) { - return (int)_SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$1.const$5.get(seg.asSlice(index*sizeof())); } public static void cbSize$set(MemorySegment seg, long index, int x) { - _SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$5.set(seg.asSlice(index*sizeof()), x); } public static MemorySegment DevicePath$slice(MemorySegment seg) { return seg.asSlice(4, 2); @@ -58,7 +55,7 @@ public class _SP_DEVICE_INTERFACE_DETAIL_DATA_W { public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java index 375bb2a9..8cf558b5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java @@ -2,7 +2,10 @@ package net.codecrete.usb.windows.gen.setupapi; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -16,23 +19,11 @@ */ public class _SP_DEVINFO_DATA { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_LONG$LAYOUT.withName("cbSize"), - MemoryLayout.structLayout( - Constants$root.C_LONG$LAYOUT.withName("Data1"), - Constants$root.C_SHORT$LAYOUT.withName("Data2"), - Constants$root.C_SHORT$LAYOUT.withName("Data3"), - MemoryLayout.sequenceLayout(8, Constants$root.C_CHAR$LAYOUT).withName("Data4") - ).withName("ClassGuid"), - Constants$root.C_LONG$LAYOUT.withName("DevInst"), - Constants$root.C_LONG_LONG$LAYOUT.withName("Reserved") - ).withName("_SP_DEVINFO_DATA"); public static MemoryLayout $LAYOUT() { - return _SP_DEVINFO_DATA.$struct$LAYOUT; + return constants$0.const$2; } - static final VarHandle cbSize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("cbSize")); public static VarHandle cbSize$VH() { - return _SP_DEVINFO_DATA.cbSize$VH; + return constants$0.const$3; } /** * Getter for field: @@ -41,7 +32,7 @@ public class _SP_DEVINFO_DATA { * } */ public static int cbSize$get(MemorySegment seg) { - return (int)_SP_DEVINFO_DATA.cbSize$VH.get(seg); + return (int)constants$0.const$3.get(seg); } /** * Setter for field: @@ -50,20 +41,19 @@ public class _SP_DEVINFO_DATA { * } */ public static void cbSize$set(MemorySegment seg, int x) { - _SP_DEVINFO_DATA.cbSize$VH.set(seg, x); + constants$0.const$3.set(seg, x); } public static int cbSize$get(MemorySegment seg, long index) { - return (int)_SP_DEVINFO_DATA.cbSize$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$0.const$3.get(seg.asSlice(index*sizeof())); } public static void cbSize$set(MemorySegment seg, long index, int x) { - _SP_DEVINFO_DATA.cbSize$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$3.set(seg.asSlice(index*sizeof()), x); } public static MemorySegment ClassGuid$slice(MemorySegment seg) { return seg.asSlice(4, 16); } - static final VarHandle DevInst$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DevInst")); public static VarHandle DevInst$VH() { - return _SP_DEVINFO_DATA.DevInst$VH; + return constants$0.const$4; } /** * Getter for field: @@ -72,7 +62,7 @@ public class _SP_DEVINFO_DATA { * } */ public static int DevInst$get(MemorySegment seg) { - return (int)_SP_DEVINFO_DATA.DevInst$VH.get(seg); + return (int)constants$0.const$4.get(seg); } /** * Setter for field: @@ -81,17 +71,16 @@ public class _SP_DEVINFO_DATA { * } */ public static void DevInst$set(MemorySegment seg, int x) { - _SP_DEVINFO_DATA.DevInst$VH.set(seg, x); + constants$0.const$4.set(seg, x); } public static int DevInst$get(MemorySegment seg, long index) { - return (int)_SP_DEVINFO_DATA.DevInst$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$0.const$4.get(seg.asSlice(index*sizeof())); } public static void DevInst$set(MemorySegment seg, long index, int x) { - _SP_DEVINFO_DATA.DevInst$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$4.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle Reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Reserved")); public static VarHandle Reserved$VH() { - return _SP_DEVINFO_DATA.Reserved$VH; + return constants$0.const$5; } /** * Getter for field: @@ -100,7 +89,7 @@ public class _SP_DEVINFO_DATA { * } */ public static long Reserved$get(MemorySegment seg) { - return (long)_SP_DEVINFO_DATA.Reserved$VH.get(seg); + return (long)constants$0.const$5.get(seg); } /** * Setter for field: @@ -109,20 +98,20 @@ public class _SP_DEVINFO_DATA { * } */ public static void Reserved$set(MemorySegment seg, long x) { - _SP_DEVINFO_DATA.Reserved$VH.set(seg, x); + constants$0.const$5.set(seg, x); } public static long Reserved$get(MemorySegment seg, long index) { - return (long)_SP_DEVINFO_DATA.Reserved$VH.get(seg.asSlice(index*sizeof())); + return (long)constants$0.const$5.get(seg.asSlice(index*sizeof())); } public static void Reserved$set(MemorySegment seg, long index, long x) { - _SP_DEVINFO_DATA.Reserved$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$5.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java index 749bd392..e5d398cb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java @@ -2,27 +2,39 @@ package net.codecrete.usb.windows.gen.setupapi; -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.*; final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} - static final FunctionDescriptor SetupDiDestroyDeviceInfoList$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle SetupDiDestroyDeviceInfoList$MH = RuntimeHelper.downcallHandle( - "SetupDiDestroyDeviceInfoList", - constants$0.SetupDiDestroyDeviceInfoList$FUNC - ); - static final FunctionDescriptor SetupDiDeleteDeviceInterfaceData$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle SetupDiDeleteDeviceInterfaceData$MH = RuntimeHelper.downcallHandle( - "SetupDiDeleteDeviceInterfaceData", - constants$0.SetupDiDeleteDeviceInterfaceData$FUNC - ); + static final StructLayout const$0 = MemoryLayout.structLayout( + MemoryLayout.structLayout( + JAVA_INT.withName("Data1"), + JAVA_SHORT.withName("Data2"), + JAVA_SHORT.withName("Data3"), + MemoryLayout.sequenceLayout(8, JAVA_BYTE).withName("Data4") + ).withName("fmtid"), + JAVA_INT.withName("pid") + ).withName("_DEVPROPKEY"); + static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("pid")); + static final StructLayout const$2 = MemoryLayout.structLayout( + JAVA_INT.withName("cbSize"), + MemoryLayout.structLayout( + JAVA_INT.withName("Data1"), + JAVA_SHORT.withName("Data2"), + JAVA_SHORT.withName("Data3"), + MemoryLayout.sequenceLayout(8, JAVA_BYTE).withName("Data4") + ).withName("ClassGuid"), + JAVA_INT.withName("DevInst"), + JAVA_LONG.withName("Reserved") + ).withName("_SP_DEVINFO_DATA"); + static final VarHandle const$3 = constants$0.const$2.varHandle(MemoryLayout.PathElement.groupElement("cbSize")); + static final VarHandle const$4 = constants$0.const$2.varHandle(MemoryLayout.PathElement.groupElement("DevInst")); + static final VarHandle const$5 = constants$0.const$2.varHandle(MemoryLayout.PathElement.groupElement("Reserved")); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java new file mode 100644 index 00000000..08aa9ba2 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java @@ -0,0 +1,36 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.setupapi; + +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.*; +final class constants$1 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$1() {} + static final StructLayout const$0 = MemoryLayout.structLayout( + JAVA_INT.withName("cbSize"), + MemoryLayout.structLayout( + JAVA_INT.withName("Data1"), + JAVA_SHORT.withName("Data2"), + JAVA_SHORT.withName("Data3"), + MemoryLayout.sequenceLayout(8, JAVA_BYTE).withName("Data4") + ).withName("InterfaceClassGuid"), + JAVA_INT.withName("Flags"), + JAVA_LONG.withName("Reserved") + ).withName("_SP_DEVICE_INTERFACE_DATA"); + static final VarHandle const$1 = constants$1.const$0.varHandle(MemoryLayout.PathElement.groupElement("cbSize")); + static final VarHandle const$2 = constants$1.const$0.varHandle(MemoryLayout.PathElement.groupElement("Flags")); + static final VarHandle const$3 = constants$1.const$0.varHandle(MemoryLayout.PathElement.groupElement("Reserved")); + static final StructLayout const$4 = MemoryLayout.structLayout( + JAVA_INT.withName("cbSize"), + MemoryLayout.sequenceLayout(1, JAVA_SHORT).withName("DevicePath"), + MemoryLayout.paddingLayout(2) + ).withName("_SP_DEVICE_INTERFACE_DETAIL_DATA_W"); + static final VarHandle const$5 = constants$1.const$4.varHandle(MemoryLayout.PathElement.groupElement("cbSize")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$2.java new file mode 100644 index 00000000..5c778a87 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$2.java @@ -0,0 +1,30 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.setupapi; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$2 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$2() {} + static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER + ); + static final MethodHandle const$1 = RuntimeHelper.downcallHandle( + "SetupDiDestroyDeviceInfoList", + constants$2.const$0 + ); + static final FunctionDescriptor const$2 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER + ); + static final MethodHandle const$3 = RuntimeHelper.downcallHandle( + "SetupDiDeleteDeviceInterfaceData", + constants$2.const$2 + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/Constants$root.java deleted file mode 100644 index e7c4dd8b..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.usbioctl; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfInt C_LONG$LAYOUT = JAVA_INT; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java index 12f2bba9..099b08e3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java @@ -15,9 +15,10 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { @@ -36,7 +37,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -55,18 +58,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java index 34449de5..60c3662a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java @@ -2,17 +2,19 @@ package net.codecrete.usb.windows.gen.usbioctl; +import java.lang.foreign.AddressLayout; + import static java.lang.foreign.ValueLayout.*; public class USBIoctl { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfInt C_LONG = JAVA_INT; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; /** * {@snippet : * #define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 2229264 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$0.java new file mode 100644 index 00000000..dcc68cbc --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$0.java @@ -0,0 +1,11 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.usbioctl; + +final class constants$0 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/Constants$root.java deleted file mode 100644 index 7aabbc3e..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.user32; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfInt C_LONG$LAYOUT = JAVA_INT; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java index 24cd8ed6..c2ce369c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java @@ -15,9 +15,10 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { System.loadLibrary("User32"); @@ -36,7 +37,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -55,18 +58,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java index 2b2267a2..31903e05 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java @@ -2,20 +2,21 @@ package net.codecrete.usb.windows.gen.user32; +import java.lang.foreign.AddressLayout; import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class User32 { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfInt C_LONG = JAVA_INT; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; /** * {@snippet : * #define WM_DEVICECHANGE 537 @@ -57,7 +58,7 @@ public static int DBT_DEVTYP_DEVICEINTERFACE() { return (int)5L; } public static MethodHandle DefWindowProcW$MH() { - return RuntimeHelper.requireNonNull(constants$0.DefWindowProcW$MH,"DefWindowProcW"); + return RuntimeHelper.requireNonNull(constants$3.const$2,"DefWindowProcW"); } /** * {@snippet : @@ -78,7 +79,7 @@ public static long DefWindowProcW(MemorySegment hWnd, int Msg, long wParam, long * } */ public static MemorySegment HWND_MESSAGE() { - return constants$0.HWND_MESSAGE$ADDR; + return constants$4.const$5; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java index b525ec13..ff9172ce 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java @@ -2,7 +2,10 @@ package net.codecrete.usb.windows.gen.user32; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -17,25 +20,11 @@ */ public class _DEV_BROADCAST_DEVICEINTERFACE_W { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_LONG$LAYOUT.withName("dbcc_size"), - Constants$root.C_LONG$LAYOUT.withName("dbcc_devicetype"), - Constants$root.C_LONG$LAYOUT.withName("dbcc_reserved"), - MemoryLayout.structLayout( - Constants$root.C_LONG$LAYOUT.withName("Data1"), - Constants$root.C_SHORT$LAYOUT.withName("Data2"), - Constants$root.C_SHORT$LAYOUT.withName("Data3"), - MemoryLayout.sequenceLayout(8, Constants$root.C_CHAR$LAYOUT).withName("Data4") - ).withName("dbcc_classguid"), - MemoryLayout.sequenceLayout(1, Constants$root.C_SHORT$LAYOUT).withName("dbcc_name"), - MemoryLayout.paddingLayout(16) - ).withName("_DEV_BROADCAST_DEVICEINTERFACE_W"); public static MemoryLayout $LAYOUT() { - return _DEV_BROADCAST_DEVICEINTERFACE_W.$struct$LAYOUT; + return constants$4.const$1; } - static final VarHandle dbcc_size$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("dbcc_size")); public static VarHandle dbcc_size$VH() { - return _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$VH; + return constants$4.const$2; } /** * Getter for field: @@ -44,7 +33,7 @@ public class _DEV_BROADCAST_DEVICEINTERFACE_W { * } */ public static int dbcc_size$get(MemorySegment seg) { - return (int)_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$VH.get(seg); + return (int)constants$4.const$2.get(seg); } /** * Setter for field: @@ -53,17 +42,16 @@ public class _DEV_BROADCAST_DEVICEINTERFACE_W { * } */ public static void dbcc_size$set(MemorySegment seg, int x) { - _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$VH.set(seg, x); + constants$4.const$2.set(seg, x); } public static int dbcc_size$get(MemorySegment seg, long index) { - return (int)_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$4.const$2.get(seg.asSlice(index*sizeof())); } public static void dbcc_size$set(MemorySegment seg, long index, int x) { - _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$VH.set(seg.asSlice(index*sizeof()), x); + constants$4.const$2.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle dbcc_devicetype$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("dbcc_devicetype")); public static VarHandle dbcc_devicetype$VH() { - return _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$VH; + return constants$4.const$3; } /** * Getter for field: @@ -72,7 +60,7 @@ public class _DEV_BROADCAST_DEVICEINTERFACE_W { * } */ public static int dbcc_devicetype$get(MemorySegment seg) { - return (int)_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$VH.get(seg); + return (int)constants$4.const$3.get(seg); } /** * Setter for field: @@ -81,17 +69,16 @@ public class _DEV_BROADCAST_DEVICEINTERFACE_W { * } */ public static void dbcc_devicetype$set(MemorySegment seg, int x) { - _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$VH.set(seg, x); + constants$4.const$3.set(seg, x); } public static int dbcc_devicetype$get(MemorySegment seg, long index) { - return (int)_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$4.const$3.get(seg.asSlice(index*sizeof())); } public static void dbcc_devicetype$set(MemorySegment seg, long index, int x) { - _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$VH.set(seg.asSlice(index*sizeof()), x); + constants$4.const$3.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle dbcc_reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("dbcc_reserved")); public static VarHandle dbcc_reserved$VH() { - return _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_reserved$VH; + return constants$4.const$4; } /** * Getter for field: @@ -100,7 +87,7 @@ public class _DEV_BROADCAST_DEVICEINTERFACE_W { * } */ public static int dbcc_reserved$get(MemorySegment seg) { - return (int)_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_reserved$VH.get(seg); + return (int)constants$4.const$4.get(seg); } /** * Setter for field: @@ -109,13 +96,13 @@ public class _DEV_BROADCAST_DEVICEINTERFACE_W { * } */ public static void dbcc_reserved$set(MemorySegment seg, int x) { - _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_reserved$VH.set(seg, x); + constants$4.const$4.set(seg, x); } public static int dbcc_reserved$get(MemorySegment seg, long index) { - return (int)_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_reserved$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$4.const$4.get(seg.asSlice(index*sizeof())); } public static void dbcc_reserved$set(MemorySegment seg, long index, int x) { - _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_reserved$VH.set(seg.asSlice(index*sizeof()), x); + constants$4.const$4.set(seg.asSlice(index*sizeof()), x); } public static MemorySegment dbcc_classguid$slice(MemorySegment seg) { return seg.asSlice(12, 16); @@ -128,7 +115,7 @@ public class _DEV_BROADCAST_DEVICEINTERFACE_W { public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java index d037452d..06d1ef76 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java @@ -2,7 +2,10 @@ package net.codecrete.usb.windows.gen.user32; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -15,17 +18,11 @@ */ public class _DEV_BROADCAST_HDR { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_LONG$LAYOUT.withName("dbch_size"), - Constants$root.C_LONG$LAYOUT.withName("dbch_devicetype"), - Constants$root.C_LONG$LAYOUT.withName("dbch_reserved") - ).withName("_DEV_BROADCAST_HDR"); public static MemoryLayout $LAYOUT() { - return _DEV_BROADCAST_HDR.$struct$LAYOUT; + return constants$3.const$3; } - static final VarHandle dbch_size$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("dbch_size")); public static VarHandle dbch_size$VH() { - return _DEV_BROADCAST_HDR.dbch_size$VH; + return constants$3.const$4; } /** * Getter for field: @@ -34,7 +31,7 @@ public class _DEV_BROADCAST_HDR { * } */ public static int dbch_size$get(MemorySegment seg) { - return (int)_DEV_BROADCAST_HDR.dbch_size$VH.get(seg); + return (int)constants$3.const$4.get(seg); } /** * Setter for field: @@ -43,17 +40,16 @@ public class _DEV_BROADCAST_HDR { * } */ public static void dbch_size$set(MemorySegment seg, int x) { - _DEV_BROADCAST_HDR.dbch_size$VH.set(seg, x); + constants$3.const$4.set(seg, x); } public static int dbch_size$get(MemorySegment seg, long index) { - return (int)_DEV_BROADCAST_HDR.dbch_size$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$3.const$4.get(seg.asSlice(index*sizeof())); } public static void dbch_size$set(MemorySegment seg, long index, int x) { - _DEV_BROADCAST_HDR.dbch_size$VH.set(seg.asSlice(index*sizeof()), x); + constants$3.const$4.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle dbch_devicetype$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("dbch_devicetype")); public static VarHandle dbch_devicetype$VH() { - return _DEV_BROADCAST_HDR.dbch_devicetype$VH; + return constants$3.const$5; } /** * Getter for field: @@ -62,7 +58,7 @@ public class _DEV_BROADCAST_HDR { * } */ public static int dbch_devicetype$get(MemorySegment seg) { - return (int)_DEV_BROADCAST_HDR.dbch_devicetype$VH.get(seg); + return (int)constants$3.const$5.get(seg); } /** * Setter for field: @@ -71,17 +67,16 @@ public class _DEV_BROADCAST_HDR { * } */ public static void dbch_devicetype$set(MemorySegment seg, int x) { - _DEV_BROADCAST_HDR.dbch_devicetype$VH.set(seg, x); + constants$3.const$5.set(seg, x); } public static int dbch_devicetype$get(MemorySegment seg, long index) { - return (int)_DEV_BROADCAST_HDR.dbch_devicetype$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$3.const$5.get(seg.asSlice(index*sizeof())); } public static void dbch_devicetype$set(MemorySegment seg, long index, int x) { - _DEV_BROADCAST_HDR.dbch_devicetype$VH.set(seg.asSlice(index*sizeof()), x); + constants$3.const$5.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle dbch_reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("dbch_reserved")); public static VarHandle dbch_reserved$VH() { - return _DEV_BROADCAST_HDR.dbch_reserved$VH; + return constants$4.const$0; } /** * Getter for field: @@ -90,7 +85,7 @@ public class _DEV_BROADCAST_HDR { * } */ public static int dbch_reserved$get(MemorySegment seg) { - return (int)_DEV_BROADCAST_HDR.dbch_reserved$VH.get(seg); + return (int)constants$4.const$0.get(seg); } /** * Setter for field: @@ -99,20 +94,20 @@ public class _DEV_BROADCAST_HDR { * } */ public static void dbch_reserved$set(MemorySegment seg, int x) { - _DEV_BROADCAST_HDR.dbch_reserved$VH.set(seg, x); + constants$4.const$0.set(seg, x); } public static int dbch_reserved$get(MemorySegment seg, long index) { - return (int)_DEV_BROADCAST_HDR.dbch_reserved$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$4.const$0.get(seg.asSlice(index*sizeof())); } public static void dbch_reserved$set(MemorySegment seg, long index, int x) { - _DEV_BROADCAST_HDR.dbch_reserved$VH.set(seg.asSlice(index*sizeof()), x); + constants$4.const$0.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java index 196a0ea1..c4377aae 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java @@ -2,24 +2,34 @@ package net.codecrete.usb.windows.gen.user32; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemorySegment; -import java.lang.invoke.MethodHandle; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} - static final FunctionDescriptor DefWindowProcW$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle DefWindowProcW$MH = RuntimeHelper.downcallHandle( - "DefWindowProcW", - constants$0.DefWindowProcW$FUNC - ); - static final MemorySegment HWND_MESSAGE$ADDR = MemorySegment.ofAddress(-3L); + static final StructLayout const$0 = MemoryLayout.structLayout( + JAVA_INT.withName("cbSize"), + JAVA_INT.withName("style"), + RuntimeHelper.POINTER.withName("lpfnWndProc"), + JAVA_INT.withName("cbClsExtra"), + JAVA_INT.withName("cbWndExtra"), + RuntimeHelper.POINTER.withName("hInstance"), + RuntimeHelper.POINTER.withName("hIcon"), + RuntimeHelper.POINTER.withName("hCursor"), + RuntimeHelper.POINTER.withName("hbrBackground"), + RuntimeHelper.POINTER.withName("lpszMenuName"), + RuntimeHelper.POINTER.withName("lpszClassName"), + RuntimeHelper.POINTER.withName("hIconSm") + ).withName("tagWNDCLASSEXW"); + static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("cbSize")); + static final VarHandle const$2 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("style")); + static final VarHandle const$3 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("lpfnWndProc")); + static final VarHandle const$4 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("cbClsExtra")); + static final VarHandle const$5 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("cbWndExtra")); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$1.java new file mode 100644 index 00000000..1836e3c4 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$1.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.user32; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.VarHandle; +final class constants$1 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$1() {} + static final VarHandle const$0 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("hInstance")); + static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("hIcon")); + static final VarHandle const$2 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("hCursor")); + static final VarHandle const$3 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("hbrBackground")); + static final VarHandle const$4 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("lpszMenuName")); + static final VarHandle const$5 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("lpszClassName")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$2.java new file mode 100644 index 00000000..7fba5be6 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$2.java @@ -0,0 +1,35 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.user32; + +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +final class constants$2 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$2() {} + static final VarHandle const$0 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("hIconSm")); + static final StructLayout const$1 = MemoryLayout.structLayout( + RuntimeHelper.POINTER.withName("hwnd"), + JAVA_INT.withName("message"), + MemoryLayout.paddingLayout(4), + JAVA_LONG.withName("wParam"), + JAVA_LONG.withName("lParam"), + JAVA_INT.withName("time"), + MemoryLayout.structLayout( + JAVA_INT.withName("x"), + JAVA_INT.withName("y") + ).withName("pt"), + MemoryLayout.paddingLayout(4) + ).withName("tagMSG"); + static final VarHandle const$2 = constants$2.const$1.varHandle(MemoryLayout.PathElement.groupElement("hwnd")); + static final VarHandle const$3 = constants$2.const$1.varHandle(MemoryLayout.PathElement.groupElement("message")); + static final VarHandle const$4 = constants$2.const$1.varHandle(MemoryLayout.PathElement.groupElement("wParam")); + static final VarHandle const$5 = constants$2.const$1.varHandle(MemoryLayout.PathElement.groupElement("lParam")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$3.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$3.java new file mode 100644 index 00000000..1ab09470 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$3.java @@ -0,0 +1,37 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.user32; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +final class constants$3 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$3() {} + static final VarHandle const$0 = constants$2.const$1.varHandle(MemoryLayout.PathElement.groupElement("time")); + static final FunctionDescriptor const$1 = FunctionDescriptor.of(JAVA_LONG, + RuntimeHelper.POINTER, + JAVA_INT, + JAVA_LONG, + JAVA_LONG + ); + static final MethodHandle const$2 = RuntimeHelper.downcallHandle( + "DefWindowProcW", + constants$3.const$1 + ); + static final StructLayout const$3 = MemoryLayout.structLayout( + JAVA_INT.withName("dbch_size"), + JAVA_INT.withName("dbch_devicetype"), + JAVA_INT.withName("dbch_reserved") + ).withName("_DEV_BROADCAST_HDR"); + static final VarHandle const$4 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("dbch_size")); + static final VarHandle const$5 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("dbch_devicetype")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$4.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$4.java new file mode 100644 index 00000000..441a40cc --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$4.java @@ -0,0 +1,35 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.user32; + +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.StructLayout; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.*; +final class constants$4 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$4() {} + static final VarHandle const$0 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("dbch_reserved")); + static final StructLayout const$1 = MemoryLayout.structLayout( + JAVA_INT.withName("dbcc_size"), + JAVA_INT.withName("dbcc_devicetype"), + JAVA_INT.withName("dbcc_reserved"), + MemoryLayout.structLayout( + JAVA_INT.withName("Data1"), + JAVA_SHORT.withName("Data2"), + JAVA_SHORT.withName("Data3"), + MemoryLayout.sequenceLayout(8, JAVA_BYTE).withName("Data4") + ).withName("dbcc_classguid"), + MemoryLayout.sequenceLayout(1, JAVA_SHORT).withName("dbcc_name"), + MemoryLayout.paddingLayout(2) + ).withName("_DEV_BROADCAST_DEVICEINTERFACE_W"); + static final VarHandle const$2 = constants$4.const$1.varHandle(MemoryLayout.PathElement.groupElement("dbcc_size")); + static final VarHandle const$3 = constants$4.const$1.varHandle(MemoryLayout.PathElement.groupElement("dbcc_devicetype")); + static final VarHandle const$4 = constants$4.const$1.varHandle(MemoryLayout.PathElement.groupElement("dbcc_reserved")); + static final MemorySegment const$5 = MemorySegment.ofAddress(-3L); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java index afb5ad7a..98724ca8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java @@ -2,7 +2,10 @@ package net.codecrete.usb.windows.gen.user32; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -18,25 +21,11 @@ */ public class tagMSG { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_POINTER$LAYOUT.withName("hwnd"), - Constants$root.C_LONG$LAYOUT.withName("message"), - MemoryLayout.paddingLayout(32), - Constants$root.C_LONG_LONG$LAYOUT.withName("wParam"), - Constants$root.C_LONG_LONG$LAYOUT.withName("lParam"), - Constants$root.C_LONG$LAYOUT.withName("time"), - MemoryLayout.structLayout( - Constants$root.C_LONG$LAYOUT.withName("x"), - Constants$root.C_LONG$LAYOUT.withName("y") - ).withName("pt"), - MemoryLayout.paddingLayout(32) - ).withName("tagMSG"); public static MemoryLayout $LAYOUT() { - return tagMSG.$struct$LAYOUT; + return constants$2.const$1; } - static final VarHandle hwnd$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hwnd")); public static VarHandle hwnd$VH() { - return tagMSG.hwnd$VH; + return constants$2.const$2; } /** * Getter for field: @@ -45,7 +34,7 @@ public class tagMSG { * } */ public static MemorySegment hwnd$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)tagMSG.hwnd$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$2.const$2.get(seg); } /** * Setter for field: @@ -54,17 +43,16 @@ public class tagMSG { * } */ public static void hwnd$set(MemorySegment seg, MemorySegment x) { - tagMSG.hwnd$VH.set(seg, x); + constants$2.const$2.set(seg, x); } public static MemorySegment hwnd$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)tagMSG.hwnd$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$2.const$2.get(seg.asSlice(index*sizeof())); } public static void hwnd$set(MemorySegment seg, long index, MemorySegment x) { - tagMSG.hwnd$VH.set(seg.asSlice(index*sizeof()), x); + constants$2.const$2.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle message$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("message")); public static VarHandle message$VH() { - return tagMSG.message$VH; + return constants$2.const$3; } /** * Getter for field: @@ -73,7 +61,7 @@ public class tagMSG { * } */ public static int message$get(MemorySegment seg) { - return (int)tagMSG.message$VH.get(seg); + return (int)constants$2.const$3.get(seg); } /** * Setter for field: @@ -82,17 +70,16 @@ public class tagMSG { * } */ public static void message$set(MemorySegment seg, int x) { - tagMSG.message$VH.set(seg, x); + constants$2.const$3.set(seg, x); } public static int message$get(MemorySegment seg, long index) { - return (int)tagMSG.message$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$2.const$3.get(seg.asSlice(index*sizeof())); } public static void message$set(MemorySegment seg, long index, int x) { - tagMSG.message$VH.set(seg.asSlice(index*sizeof()), x); + constants$2.const$3.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle wParam$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("wParam")); public static VarHandle wParam$VH() { - return tagMSG.wParam$VH; + return constants$2.const$4; } /** * Getter for field: @@ -101,7 +88,7 @@ public class tagMSG { * } */ public static long wParam$get(MemorySegment seg) { - return (long)tagMSG.wParam$VH.get(seg); + return (long)constants$2.const$4.get(seg); } /** * Setter for field: @@ -110,17 +97,16 @@ public class tagMSG { * } */ public static void wParam$set(MemorySegment seg, long x) { - tagMSG.wParam$VH.set(seg, x); + constants$2.const$4.set(seg, x); } public static long wParam$get(MemorySegment seg, long index) { - return (long)tagMSG.wParam$VH.get(seg.asSlice(index*sizeof())); + return (long)constants$2.const$4.get(seg.asSlice(index*sizeof())); } public static void wParam$set(MemorySegment seg, long index, long x) { - tagMSG.wParam$VH.set(seg.asSlice(index*sizeof()), x); + constants$2.const$4.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle lParam$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("lParam")); public static VarHandle lParam$VH() { - return tagMSG.lParam$VH; + return constants$2.const$5; } /** * Getter for field: @@ -129,7 +115,7 @@ public class tagMSG { * } */ public static long lParam$get(MemorySegment seg) { - return (long)tagMSG.lParam$VH.get(seg); + return (long)constants$2.const$5.get(seg); } /** * Setter for field: @@ -138,17 +124,16 @@ public class tagMSG { * } */ public static void lParam$set(MemorySegment seg, long x) { - tagMSG.lParam$VH.set(seg, x); + constants$2.const$5.set(seg, x); } public static long lParam$get(MemorySegment seg, long index) { - return (long)tagMSG.lParam$VH.get(seg.asSlice(index*sizeof())); + return (long)constants$2.const$5.get(seg.asSlice(index*sizeof())); } public static void lParam$set(MemorySegment seg, long index, long x) { - tagMSG.lParam$VH.set(seg.asSlice(index*sizeof()), x); + constants$2.const$5.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle time$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("time")); public static VarHandle time$VH() { - return tagMSG.time$VH; + return constants$3.const$0; } /** * Getter for field: @@ -157,7 +142,7 @@ public class tagMSG { * } */ public static int time$get(MemorySegment seg) { - return (int)tagMSG.time$VH.get(seg); + return (int)constants$3.const$0.get(seg); } /** * Setter for field: @@ -166,13 +151,13 @@ public class tagMSG { * } */ public static void time$set(MemorySegment seg, int x) { - tagMSG.time$VH.set(seg, x); + constants$3.const$0.set(seg, x); } public static int time$get(MemorySegment seg, long index) { - return (int)tagMSG.time$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$3.const$0.get(seg.asSlice(index*sizeof())); } public static void time$set(MemorySegment seg, long index, int x) { - tagMSG.time$VH.set(seg.asSlice(index*sizeof()), x); + constants$3.const$0.set(seg.asSlice(index*sizeof()), x); } public static MemorySegment pt$slice(MemorySegment seg) { return seg.asSlice(36, 8); @@ -182,7 +167,7 @@ public class tagMSG { public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java index 7a7b1859..6f6c3346 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java @@ -2,7 +2,10 @@ package net.codecrete.usb.windows.gen.user32; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -24,26 +27,11 @@ */ public class tagWNDCLASSEXW { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_LONG$LAYOUT.withName("cbSize"), - Constants$root.C_LONG$LAYOUT.withName("style"), - Constants$root.C_POINTER$LAYOUT.withName("lpfnWndProc"), - Constants$root.C_LONG$LAYOUT.withName("cbClsExtra"), - Constants$root.C_LONG$LAYOUT.withName("cbWndExtra"), - Constants$root.C_POINTER$LAYOUT.withName("hInstance"), - Constants$root.C_POINTER$LAYOUT.withName("hIcon"), - Constants$root.C_POINTER$LAYOUT.withName("hCursor"), - Constants$root.C_POINTER$LAYOUT.withName("hbrBackground"), - Constants$root.C_POINTER$LAYOUT.withName("lpszMenuName"), - Constants$root.C_POINTER$LAYOUT.withName("lpszClassName"), - Constants$root.C_POINTER$LAYOUT.withName("hIconSm") - ).withName("tagWNDCLASSEXW"); public static MemoryLayout $LAYOUT() { - return tagWNDCLASSEXW.$struct$LAYOUT; + return constants$0.const$0; } - static final VarHandle cbSize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("cbSize")); public static VarHandle cbSize$VH() { - return tagWNDCLASSEXW.cbSize$VH; + return constants$0.const$1; } /** * Getter for field: @@ -52,7 +40,7 @@ public class tagWNDCLASSEXW { * } */ public static int cbSize$get(MemorySegment seg) { - return (int)tagWNDCLASSEXW.cbSize$VH.get(seg); + return (int)constants$0.const$1.get(seg); } /** * Setter for field: @@ -61,17 +49,16 @@ public class tagWNDCLASSEXW { * } */ public static void cbSize$set(MemorySegment seg, int x) { - tagWNDCLASSEXW.cbSize$VH.set(seg, x); + constants$0.const$1.set(seg, x); } public static int cbSize$get(MemorySegment seg, long index) { - return (int)tagWNDCLASSEXW.cbSize$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$0.const$1.get(seg.asSlice(index*sizeof())); } public static void cbSize$set(MemorySegment seg, long index, int x) { - tagWNDCLASSEXW.cbSize$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$1.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle style$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("style")); public static VarHandle style$VH() { - return tagWNDCLASSEXW.style$VH; + return constants$0.const$2; } /** * Getter for field: @@ -80,7 +67,7 @@ public class tagWNDCLASSEXW { * } */ public static int style$get(MemorySegment seg) { - return (int)tagWNDCLASSEXW.style$VH.get(seg); + return (int)constants$0.const$2.get(seg); } /** * Setter for field: @@ -89,17 +76,16 @@ public class tagWNDCLASSEXW { * } */ public static void style$set(MemorySegment seg, int x) { - tagWNDCLASSEXW.style$VH.set(seg, x); + constants$0.const$2.set(seg, x); } public static int style$get(MemorySegment seg, long index) { - return (int)tagWNDCLASSEXW.style$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$0.const$2.get(seg.asSlice(index*sizeof())); } public static void style$set(MemorySegment seg, long index, int x) { - tagWNDCLASSEXW.style$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$2.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle lpfnWndProc$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("lpfnWndProc")); public static VarHandle lpfnWndProc$VH() { - return tagWNDCLASSEXW.lpfnWndProc$VH; + return constants$0.const$3; } /** * Getter for field: @@ -108,7 +94,7 @@ public class tagWNDCLASSEXW { * } */ public static MemorySegment lpfnWndProc$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.lpfnWndProc$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$0.const$3.get(seg); } /** * Setter for field: @@ -117,17 +103,16 @@ public class tagWNDCLASSEXW { * } */ public static void lpfnWndProc$set(MemorySegment seg, MemorySegment x) { - tagWNDCLASSEXW.lpfnWndProc$VH.set(seg, x); + constants$0.const$3.set(seg, x); } public static MemorySegment lpfnWndProc$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.lpfnWndProc$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$0.const$3.get(seg.asSlice(index*sizeof())); } public static void lpfnWndProc$set(MemorySegment seg, long index, MemorySegment x) { - tagWNDCLASSEXW.lpfnWndProc$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$3.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle cbClsExtra$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("cbClsExtra")); public static VarHandle cbClsExtra$VH() { - return tagWNDCLASSEXW.cbClsExtra$VH; + return constants$0.const$4; } /** * Getter for field: @@ -136,7 +121,7 @@ public class tagWNDCLASSEXW { * } */ public static int cbClsExtra$get(MemorySegment seg) { - return (int)tagWNDCLASSEXW.cbClsExtra$VH.get(seg); + return (int)constants$0.const$4.get(seg); } /** * Setter for field: @@ -145,17 +130,16 @@ public class tagWNDCLASSEXW { * } */ public static void cbClsExtra$set(MemorySegment seg, int x) { - tagWNDCLASSEXW.cbClsExtra$VH.set(seg, x); + constants$0.const$4.set(seg, x); } public static int cbClsExtra$get(MemorySegment seg, long index) { - return (int)tagWNDCLASSEXW.cbClsExtra$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$0.const$4.get(seg.asSlice(index*sizeof())); } public static void cbClsExtra$set(MemorySegment seg, long index, int x) { - tagWNDCLASSEXW.cbClsExtra$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$4.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle cbWndExtra$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("cbWndExtra")); public static VarHandle cbWndExtra$VH() { - return tagWNDCLASSEXW.cbWndExtra$VH; + return constants$0.const$5; } /** * Getter for field: @@ -164,7 +148,7 @@ public class tagWNDCLASSEXW { * } */ public static int cbWndExtra$get(MemorySegment seg) { - return (int)tagWNDCLASSEXW.cbWndExtra$VH.get(seg); + return (int)constants$0.const$5.get(seg); } /** * Setter for field: @@ -173,17 +157,16 @@ public class tagWNDCLASSEXW { * } */ public static void cbWndExtra$set(MemorySegment seg, int x) { - tagWNDCLASSEXW.cbWndExtra$VH.set(seg, x); + constants$0.const$5.set(seg, x); } public static int cbWndExtra$get(MemorySegment seg, long index) { - return (int)tagWNDCLASSEXW.cbWndExtra$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$0.const$5.get(seg.asSlice(index*sizeof())); } public static void cbWndExtra$set(MemorySegment seg, long index, int x) { - tagWNDCLASSEXW.cbWndExtra$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$5.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle hInstance$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hInstance")); public static VarHandle hInstance$VH() { - return tagWNDCLASSEXW.hInstance$VH; + return constants$1.const$0; } /** * Getter for field: @@ -192,7 +175,7 @@ public class tagWNDCLASSEXW { * } */ public static MemorySegment hInstance$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hInstance$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$1.const$0.get(seg); } /** * Setter for field: @@ -201,17 +184,16 @@ public class tagWNDCLASSEXW { * } */ public static void hInstance$set(MemorySegment seg, MemorySegment x) { - tagWNDCLASSEXW.hInstance$VH.set(seg, x); + constants$1.const$0.set(seg, x); } public static MemorySegment hInstance$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hInstance$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$1.const$0.get(seg.asSlice(index*sizeof())); } public static void hInstance$set(MemorySegment seg, long index, MemorySegment x) { - tagWNDCLASSEXW.hInstance$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$0.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle hIcon$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hIcon")); public static VarHandle hIcon$VH() { - return tagWNDCLASSEXW.hIcon$VH; + return constants$1.const$1; } /** * Getter for field: @@ -220,7 +202,7 @@ public class tagWNDCLASSEXW { * } */ public static MemorySegment hIcon$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hIcon$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$1.const$1.get(seg); } /** * Setter for field: @@ -229,17 +211,16 @@ public class tagWNDCLASSEXW { * } */ public static void hIcon$set(MemorySegment seg, MemorySegment x) { - tagWNDCLASSEXW.hIcon$VH.set(seg, x); + constants$1.const$1.set(seg, x); } public static MemorySegment hIcon$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hIcon$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$1.const$1.get(seg.asSlice(index*sizeof())); } public static void hIcon$set(MemorySegment seg, long index, MemorySegment x) { - tagWNDCLASSEXW.hIcon$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$1.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle hCursor$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hCursor")); public static VarHandle hCursor$VH() { - return tagWNDCLASSEXW.hCursor$VH; + return constants$1.const$2; } /** * Getter for field: @@ -248,7 +229,7 @@ public class tagWNDCLASSEXW { * } */ public static MemorySegment hCursor$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hCursor$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$1.const$2.get(seg); } /** * Setter for field: @@ -257,17 +238,16 @@ public class tagWNDCLASSEXW { * } */ public static void hCursor$set(MemorySegment seg, MemorySegment x) { - tagWNDCLASSEXW.hCursor$VH.set(seg, x); + constants$1.const$2.set(seg, x); } public static MemorySegment hCursor$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hCursor$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$1.const$2.get(seg.asSlice(index*sizeof())); } public static void hCursor$set(MemorySegment seg, long index, MemorySegment x) { - tagWNDCLASSEXW.hCursor$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$2.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle hbrBackground$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hbrBackground")); public static VarHandle hbrBackground$VH() { - return tagWNDCLASSEXW.hbrBackground$VH; + return constants$1.const$3; } /** * Getter for field: @@ -276,7 +256,7 @@ public class tagWNDCLASSEXW { * } */ public static MemorySegment hbrBackground$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hbrBackground$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$1.const$3.get(seg); } /** * Setter for field: @@ -285,17 +265,16 @@ public class tagWNDCLASSEXW { * } */ public static void hbrBackground$set(MemorySegment seg, MemorySegment x) { - tagWNDCLASSEXW.hbrBackground$VH.set(seg, x); + constants$1.const$3.set(seg, x); } public static MemorySegment hbrBackground$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hbrBackground$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$1.const$3.get(seg.asSlice(index*sizeof())); } public static void hbrBackground$set(MemorySegment seg, long index, MemorySegment x) { - tagWNDCLASSEXW.hbrBackground$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$3.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle lpszMenuName$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("lpszMenuName")); public static VarHandle lpszMenuName$VH() { - return tagWNDCLASSEXW.lpszMenuName$VH; + return constants$1.const$4; } /** * Getter for field: @@ -304,7 +283,7 @@ public class tagWNDCLASSEXW { * } */ public static MemorySegment lpszMenuName$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.lpszMenuName$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$1.const$4.get(seg); } /** * Setter for field: @@ -313,17 +292,16 @@ public class tagWNDCLASSEXW { * } */ public static void lpszMenuName$set(MemorySegment seg, MemorySegment x) { - tagWNDCLASSEXW.lpszMenuName$VH.set(seg, x); + constants$1.const$4.set(seg, x); } public static MemorySegment lpszMenuName$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.lpszMenuName$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$1.const$4.get(seg.asSlice(index*sizeof())); } public static void lpszMenuName$set(MemorySegment seg, long index, MemorySegment x) { - tagWNDCLASSEXW.lpszMenuName$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$4.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle lpszClassName$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("lpszClassName")); public static VarHandle lpszClassName$VH() { - return tagWNDCLASSEXW.lpszClassName$VH; + return constants$1.const$5; } /** * Getter for field: @@ -332,7 +310,7 @@ public class tagWNDCLASSEXW { * } */ public static MemorySegment lpszClassName$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.lpszClassName$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$1.const$5.get(seg); } /** * Setter for field: @@ -341,17 +319,16 @@ public class tagWNDCLASSEXW { * } */ public static void lpszClassName$set(MemorySegment seg, MemorySegment x) { - tagWNDCLASSEXW.lpszClassName$VH.set(seg, x); + constants$1.const$5.set(seg, x); } public static MemorySegment lpszClassName$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.lpszClassName$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$1.const$5.get(seg.asSlice(index*sizeof())); } public static void lpszClassName$set(MemorySegment seg, long index, MemorySegment x) { - tagWNDCLASSEXW.lpszClassName$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$5.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle hIconSm$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("hIconSm")); public static VarHandle hIconSm$VH() { - return tagWNDCLASSEXW.hIconSm$VH; + return constants$2.const$0; } /** * Getter for field: @@ -360,7 +337,7 @@ public class tagWNDCLASSEXW { * } */ public static MemorySegment hIconSm$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hIconSm$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$2.const$0.get(seg); } /** * Setter for field: @@ -369,20 +346,20 @@ public class tagWNDCLASSEXW { * } */ public static void hIconSm$set(MemorySegment seg, MemorySegment x) { - tagWNDCLASSEXW.hIconSm$VH.set(seg, x); + constants$2.const$0.set(seg, x); } public static MemorySegment hIconSm$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)tagWNDCLASSEXW.hIconSm$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$2.const$0.get(seg.asSlice(index*sizeof())); } public static void hIconSm$set(MemorySegment seg, long index, MemorySegment x) { - tagWNDCLASSEXW.hIconSm$VH.set(seg.asSlice(index*sizeof()), x); + constants$2.const$0.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/Constants$root.java deleted file mode 100644 index 840db08a..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.winusb; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfInt C_LONG$LAYOUT = JAVA_INT; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java index 8b0bda65..c9ab3d52 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java @@ -15,9 +15,10 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { System.loadLibrary("Winusb"); @@ -36,7 +37,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -55,18 +58,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java index 0dafcd77..a35ff11d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java @@ -2,20 +2,21 @@ package net.codecrete.usb.windows.gen.winusb; +import java.lang.foreign.AddressLayout; import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class WinUSB { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT; - public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfInt C_LONG = JAVA_INT; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; /** * {@snippet : * #define PIPE_TRANSFER_TIMEOUT 3 @@ -33,7 +34,7 @@ public static int RAW_IO() { return (int)7L; } public static MethodHandle WinUsb_Free$MH() { - return RuntimeHelper.requireNonNull(constants$0.WinUsb_Free$MH,"WinUsb_Free"); + return RuntimeHelper.requireNonNull(constants$0.const$1,"WinUsb_Free"); } /** * {@snippet : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java index 2b90b7fb..90f3902c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java @@ -4,16 +4,18 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} - static final FunctionDescriptor WinUsb_Free$FUNC = FunctionDescriptor.of(Constants$root.C_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT + static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER ); - static final MethodHandle WinUsb_Free$MH = RuntimeHelper.downcallHandle( + static final MethodHandle const$1 = RuntimeHelper.downcallHandle( "WinUsb_Free", - constants$0.WinUsb_Free$FUNC + constants$0.const$0 ); } From c5ad449f51fb154fd5bc3119f4b670cc47152184 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 25 Jul 2023 23:00:21 +0200 Subject: [PATCH 245/433] macOS: upgrade to JDK 21 --- .../codecrete/usb/common/ForeignMemory.java | 14 +- .../net/codecrete/usb/macos/IoKitHelper.java | 7 +- .../net/codecrete/usb/macos/IoKitUSB.java | 56 +- .../codecrete/usb/macos/MacosAsyncTask.java | 4 +- .../codecrete/usb/macos/MacosUSBDevice.java | 26 +- .../usb/macos/MacosUSBDeviceRegistry.java | 10 +- .../java/net/codecrete/usb/macos/UUID.java | 2 +- .../usb/macos/gen/corefoundation/CFRange.java | 35 +- .../macos/gen/corefoundation/CFUUIDBytes.java | 203 +-- .../gen/corefoundation/Constants$root.java | 21 - .../gen/corefoundation/CoreFoundation.java | 45 +- .../gen/corefoundation/RuntimeHelper.java | 28 +- .../macos/gen/corefoundation/constants$0.java | 61 +- .../macos/gen/corefoundation/constants$1.java | 73 +- .../macos/gen/corefoundation/constants$2.java | 68 +- .../macos/gen/corefoundation/constants$3.java | 51 + .../macos/gen/corefoundation/constants$4.java | 19 + .../macos/gen/corefoundation/constants$5.java | 19 + .../macos/gen/corefoundation/constants$6.java | 68 + .../usb/macos/gen/iokit/Constants$root.java | 21 - .../gen/iokit/IOCFPlugInInterfaceStruct.java | 257 +-- .../codecrete/usb/macos/gen/iokit/IOKit.java | 61 +- .../usb/macos/gen/iokit/IOUSBDevRequest.java | 96 +- .../macos/gen/iokit/IOUSBDeviceStruct187.java | 1189 +++++------- .../gen/iokit/IOUSBFindInterfaceRequest.java | 59 +- .../gen/iokit/IOUSBInterfaceStruct190.java | 1590 ++++++----------- .../usb/macos/gen/iokit/RuntimeHelper.java | 28 +- .../usb/macos/gen/iokit/constants$0.java | 57 +- .../usb/macos/gen/iokit/constants$1.java | 68 +- .../usb/macos/gen/iokit/constants$10.java | 20 + .../usb/macos/gen/iokit/constants$11.java | 20 + .../usb/macos/gen/iokit/constants$12.java | 20 + .../usb/macos/gen/iokit/constants$13.java | 30 + .../usb/macos/gen/iokit/constants$14.java | 33 + .../usb/macos/gen/iokit/constants$15.java | 22 + .../usb/macos/gen/iokit/constants$16.java | 30 + .../usb/macos/gen/iokit/constants$17.java | 20 + .../usb/macos/gen/iokit/constants$18.java | 20 + .../usb/macos/gen/iokit/constants$19.java | 26 + .../usb/macos/gen/iokit/constants$2.java | 20 +- .../usb/macos/gen/iokit/constants$20.java | 73 + .../usb/macos/gen/iokit/constants$21.java | 20 + .../usb/macos/gen/iokit/constants$22.java | 20 + .../usb/macos/gen/iokit/constants$23.java | 20 + .../usb/macos/gen/iokit/constants$24.java | 20 + .../usb/macos/gen/iokit/constants$25.java | 20 + .../usb/macos/gen/iokit/constants$26.java | 20 + .../usb/macos/gen/iokit/constants$27.java | 20 + .../usb/macos/gen/iokit/constants$28.java | 30 + .../usb/macos/gen/iokit/constants$29.java | 36 + .../usb/macos/gen/iokit/constants$3.java | 45 + .../usb/macos/gen/iokit/constants$30.java | 20 + .../usb/macos/gen/iokit/constants$31.java | 31 + .../usb/macos/gen/iokit/constants$32.java | 38 + .../usb/macos/gen/iokit/constants$33.java | 34 + .../usb/macos/gen/iokit/constants$34.java | 22 + .../usb/macos/gen/iokit/constants$35.java | 33 + .../usb/macos/gen/iokit/constants$36.java | 42 + .../usb/macos/gen/iokit/constants$37.java | 22 + .../usb/macos/gen/iokit/constants$38.java | 28 + .../usb/macos/gen/iokit/constants$39.java | 34 + .../usb/macos/gen/iokit/constants$4.java | 79 + .../usb/macos/gen/iokit/constants$40.java | 36 + .../usb/macos/gen/iokit/constants$41.java | 20 + .../usb/macos/gen/iokit/constants$42.java | 34 + .../usb/macos/gen/iokit/constants$43.java | 34 + .../usb/macos/gen/iokit/constants$44.java | 15 + .../usb/macos/gen/iokit/constants$5.java | 49 + .../usb/macos/gen/iokit/constants$6.java | 28 + .../usb/macos/gen/iokit/constants$7.java | 24 + .../usb/macos/gen/iokit/constants$8.java | 20 + .../usb/macos/gen/iokit/constants$9.java | 20 + .../usb/macos/gen/mach/Constants$root.java | 21 - .../usb/macos/gen/mach/RuntimeHelper.java | 26 +- .../usb/macos/gen/mach/constants$0.java | 10 +- .../codecrete/usb/macos/gen/mach/mach.java | 19 +- 76 files changed, 2908 insertions(+), 2652 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$3.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$4.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$5.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$6.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/Constants$root.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$10.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$11.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$12.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$13.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$14.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$15.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$16.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$17.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$18.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$19.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$20.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$21.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$22.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$23.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$24.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$25.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$26.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$27.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$28.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$29.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$3.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$30.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$31.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$32.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$33.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$34.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$35.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$36.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$37.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$38.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$39.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$4.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$40.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$41.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$42.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$43.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$44.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$5.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$6.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$7.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$8.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$9.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java index cf4fbda5..9d002c89 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java @@ -8,18 +8,10 @@ package net.codecrete.usb.common; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; -public class ForeignMemory { - /** - * A value layout constant whose size is the same as that of a machine address. - *

- * {@code MemorySegment} instances created by dereferencing an address of this type - * will have length {@code Long.MAX_VALUE}/ - *

- */ - public static final ValueLayout.OfAddress UNBOUNDED_ADDRESS = ValueLayout.ADDRESS.asUnbounded(); +import static java.lang.foreign.ValueLayout.ADDRESS; +public class ForeignMemory { /** * Dereferences the address at the start of the memory segment and returns the result as * a memory segment of the specified length. @@ -29,6 +21,6 @@ public class ForeignMemory { * @return the dereferenced memory segment */ public static MemorySegment deref(MemorySegment segment, long byteSize) { - return segment.get(UNBOUNDED_ADDRESS, 0).asSlice(0, byteSize); + return segment.get(ADDRESS, 0).reinterpret(byteSize); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index 896ab60c..bcee8fd8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -12,7 +12,6 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentScope; import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.ADDRESS; @@ -51,7 +50,7 @@ public class IoKitHelper { * @return the interface, or {@code null} if the plugin type or interface is not available */ public static MemorySegment getInterface(int service, MemorySegment pluginType, MemorySegment interfaceId) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { // MemorySegment for holding IOCFPlugInInterface** var plugHolder = arena.allocate(ADDRESS, NULL); // MemorySegment for holding score @@ -133,9 +132,9 @@ public static String getPropertyString(int service, MemorySegment key, Arena are // debugging aid public static int getRefCount(MemorySegment self) { - var object = MemorySegment.ofAddress(self.address(), 16, SegmentScope.global()); + var object = MemorySegment.ofAddress(self.address()).reinterpret(16); var dataAddr = object.get(ADDRESS, ADDRESS.byteSize()); - var data = MemorySegment.ofAddress(dataAddr.address(), 12, SegmentScope.global()); + var data = MemorySegment.ofAddress(dataAddr.address()).reinterpret(12); return data.get(JAVA_INT, 8); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index 03b4d41d..c75d5ae7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -11,8 +11,8 @@ import net.codecrete.usb.macos.gen.iokit.IOUSBDeviceInterface187; import net.codecrete.usb.macos.gen.iokit.IOUSBInterfaceInterface190; +import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentScope; import static java.lang.foreign.ValueLayout.ADDRESS; @@ -22,94 +22,94 @@ public class IoKitUSB { private static MemorySegment getVtable(MemorySegment self) { - var object = MemorySegment.ofAddress(self.address(), ADDRESS.byteSize(), SegmentScope.global()); + var object = MemorySegment.ofAddress(self.address()).reinterpret(ADDRESS.byteSize()); // 800: size of biggest vtable and then some return ForeignMemory.deref(object, 800); } // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); public static int QueryInterface(MemorySegment self, MemorySegment iid, MemorySegment ppv) { - return IOUSBDeviceInterface187.QueryInterface(getVtable(self), SegmentScope.global()).apply(self, iid, ppv); + return IOUSBDeviceInterface187.QueryInterface(getVtable(self), Arena.global()).apply(self, iid, ppv); } // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); public static int AddRef(MemorySegment self) { - return IOUSBDeviceInterface187.AddRef(getVtable(self), SegmentScope.global()).apply(self); + return IOUSBDeviceInterface187.AddRef(getVtable(self), Arena.global()).apply(self); } // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer) public static int Release(MemorySegment self) { - return IOUSBDeviceInterface187.Release(getVtable(self), SegmentScope.global()).apply(self); + return IOUSBDeviceInterface187.Release(getVtable(self), Arena.global()).apply(self); } // IOReturn (* CreateDeviceAsyncEventSource)(void* self, CFRunLoopSourceRef* source); public static int CreateDeviceAsyncEventSource(MemorySegment self, MemorySegment source) { - return IOUSBDeviceInterface187.CreateDeviceAsyncEventSource(getVtable(self), SegmentScope.global()).apply(self, source); + return IOUSBDeviceInterface187.CreateDeviceAsyncEventSource(getVtable(self), Arena.global()).apply(self, source); } // CFRunLoopSourceRef (* GetDeviceAsyncEventSource)(void* self); public static MemorySegment GetDeviceAsyncEventSource(MemorySegment self) { - return IOUSBDeviceInterface187.GetDeviceAsyncEventSource(getVtable(self), SegmentScope.global()).apply(self); + return IOUSBDeviceInterface187.GetDeviceAsyncEventSource(getVtable(self), Arena.global()).apply(self); } // IOReturn (*USBDeviceOpenSeize)(void *self); public static int USBDeviceOpenSeize(MemorySegment self) { - return IOUSBDeviceInterface187.USBDeviceOpenSeize(getVtable(self), SegmentScope.global()).apply(self); + return IOUSBDeviceInterface187.USBDeviceOpenSeize(getVtable(self), Arena.global()).apply(self); } // IOReturn (*USBDeviceClose)(void *self); public static int USBDeviceClose(MemorySegment self) { - return IOUSBDeviceInterface187.USBDeviceClose(getVtable(self), SegmentScope.global()).apply(self); + return IOUSBDeviceInterface187.USBDeviceClose(getVtable(self), Arena.global()).apply(self); } // IOReturn (* USBDeviceReEnumerate)(void* self, UInt32 options); public static int USBDeviceReEnumerate(MemorySegment self, int options) { - return IOUSBDeviceInterface187.USBDeviceReEnumerate(getVtable(self), SegmentScope.global()).apply(self, options); + return IOUSBDeviceInterface187.USBDeviceReEnumerate(getVtable(self), Arena.global()).apply(self, options); } // IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc); public static int GetConfigurationDescriptorPtr(MemorySegment self, byte configIndex, MemorySegment descHolder) { - return IOUSBDeviceInterface187.GetConfigurationDescriptorPtr(getVtable(self), SegmentScope.global()).apply(self, configIndex, descHolder); + return IOUSBDeviceInterface187.GetConfigurationDescriptorPtr(getVtable(self), Arena.global()).apply(self, configIndex, descHolder); } // IOReturn (*SetConfiguration)(void *self, UInt8 configNum); public static int SetConfiguration(MemorySegment self, byte configValue) { - return IOUSBDeviceInterface187.SetConfiguration(getVtable(self), SegmentScope.global()).apply(self, + return IOUSBDeviceInterface187.SetConfiguration(getVtable(self), Arena.global()).apply(self, configValue); } // IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter); public static int CreateInterfaceIterator(MemorySegment self, MemorySegment req, MemorySegment iter) { - return IOUSBDeviceInterface187.CreateInterfaceIterator(getVtable(self), SegmentScope.global()).apply(self, + return IOUSBDeviceInterface187.CreateInterfaceIterator(getVtable(self), Arena.global()).apply(self, req, iter); } // IOReturn (* DeviceRequestAsync)(void* self, IOUSBDevRequest* req, IOAsyncCallback1 callback, void* refCon); public static int DeviceRequestAsync(MemorySegment self, MemorySegment deviceRequest, MemorySegment callback, MemorySegment refCon) { - return IOUSBDeviceInterface187.DeviceRequestAsync(getVtable(self), SegmentScope.global()).apply(self, + return IOUSBDeviceInterface187.DeviceRequestAsync(getVtable(self), Arena.global()).apply(self, deviceRequest, callback, refCon); } // IOReturn (*USBInterfaceOpen)(void *self);; public static int USBInterfaceOpen(MemorySegment self) { - return IOUSBInterfaceInterface190.USBInterfaceOpen(getVtable(self), SegmentScope.global()).apply(self); + return IOUSBInterfaceInterface190.USBInterfaceOpen(getVtable(self), Arena.global()).apply(self); } // IOReturn (*USBInterfaceClose)(void *self);; public static int USBInterfaceClose(MemorySegment self) { - return IOUSBInterfaceInterface190.USBInterfaceClose(getVtable(self), SegmentScope.global()).apply(self); + return IOUSBInterfaceInterface190.USBInterfaceClose(getVtable(self), Arena.global()).apply(self); } // IOReturn (*GetInterfaceNumber)(void *self, UInt8 *intfNumber); public static int GetInterfaceNumber(MemorySegment self, MemorySegment intfNumberHolder) { - return IOUSBInterfaceInterface190.GetInterfaceNumber(getVtable(self), SegmentScope.global()).apply(self, + return IOUSBInterfaceInterface190.GetInterfaceNumber(getVtable(self), Arena.global()).apply(self, intfNumberHolder); } // IOReturn (*GetNumEndpoints)(void *self, UInt8 *intfNumEndpoints); public static int GetNumEndpoints(MemorySegment self, MemorySegment intfNumEndpointsHolder) { - return IOUSBInterfaceInterface190.GetNumEndpoints(getVtable(self), SegmentScope.global()).apply(self, + return IOUSBInterfaceInterface190.GetNumEndpoints(getVtable(self), Arena.global()).apply(self, intfNumEndpointsHolder); } @@ -118,7 +118,7 @@ public static int GetNumEndpoints(MemorySegment self, MemorySegment intfNumEndpo public static int GetPipeProperties(MemorySegment self, byte pipeRef, MemorySegment directionHolder, MemorySegment numberHolder, MemorySegment transferTypeHolder, MemorySegment maxPacketSizeHolder, MemorySegment intervalHolder) { - return IOUSBInterfaceInterface190.GetPipeProperties(getVtable(self), SegmentScope.global()).apply(self, + return IOUSBInterfaceInterface190.GetPipeProperties(getVtable(self), Arena.global()).apply(self, pipeRef, directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); } @@ -126,7 +126,7 @@ public static int GetPipeProperties(MemorySegment self, byte pipeRef, MemorySegm // *refcon); public static int ReadPipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceInterface190.ReadPipeAsync(getVtable(self), SegmentScope.global()).apply(self, pipeRef, + return IOUSBInterfaceInterface190.ReadPipeAsync(getVtable(self), Arena.global()).apply(self, pipeRef, buf, size, callback, refcon); } @@ -135,7 +135,7 @@ public static int ReadPipeAsync(MemorySegment self, byte pipeRef, MemorySegment public static int ReadPipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, int noDataTimeout, int completionTimeout, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceInterface190.ReadPipeAsyncTO(getVtable(self), SegmentScope.global()).apply(self, pipeRef + return IOUSBInterfaceInterface190.ReadPipeAsyncTO(getVtable(self), Arena.global()).apply(self, pipeRef , buf, size, noDataTimeout, completionTimeout, callback, refcon); } @@ -143,7 +143,7 @@ public static int ReadPipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegmen // void *refcon); public static int WritePipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceInterface190.WritePipeAsync(getVtable(self), SegmentScope.global()).apply(self, pipeRef, + return IOUSBInterfaceInterface190.WritePipeAsync(getVtable(self), Arena.global()).apply(self, pipeRef, buf, size, callback, refcon); } @@ -152,34 +152,34 @@ public static int WritePipeAsync(MemorySegment self, byte pipeRef, MemorySegment public static int WritePipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, int noDataTimeout, int completionTimeout, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceInterface190.WritePipeAsyncTO(getVtable(self), SegmentScope.global()).apply(self, + return IOUSBInterfaceInterface190.WritePipeAsyncTO(getVtable(self), Arena.global()).apply(self, pipeRef, buf, size, noDataTimeout, completionTimeout, callback, refcon); } // IOReturn (* AbortPipe)(void* self, UInt8 pipeRef); public static int AbortPipe(MemorySegment self, byte pipeRef) { - return IOUSBInterfaceInterface190.AbortPipe(getVtable(self), SegmentScope.global()).apply(self, pipeRef); + return IOUSBInterfaceInterface190.AbortPipe(getVtable(self), Arena.global()).apply(self, pipeRef); } // IOReturn (*SetAlternateInterface)(void *self, UInt8 alternateSetting); public static int SetAlternateInterface(MemorySegment self, byte alternateSetting) { - return IOUSBInterfaceInterface190.SetAlternateInterface(getVtable(self), SegmentScope.global()).apply(self, + return IOUSBInterfaceInterface190.SetAlternateInterface(getVtable(self), Arena.global()).apply(self, alternateSetting); } // IOReturn (* ClearPipeStallBothEnds)(void* self, UInt8 pipeRef); public static int ClearPipeStallBothEnds(MemorySegment self, byte pipeRef) { - return IOUSBInterfaceInterface190.ClearPipeStallBothEnds(getVtable(self), SegmentScope.global()).apply(self, + return IOUSBInterfaceInterface190.ClearPipeStallBothEnds(getVtable(self), Arena.global()).apply(self, pipeRef); } // CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void* self); public static MemorySegment GetInterfaceAsyncEventSource(MemorySegment self) { - return IOUSBInterfaceInterface190.GetInterfaceAsyncEventSource(getVtable(self), SegmentScope.global()).apply(self); + return IOUSBInterfaceInterface190.GetInterfaceAsyncEventSource(getVtable(self), Arena.global()).apply(self); } // IOReturn (*CreateInterfaceAsyncEventSource)(void *self, CFRunLoopSourceRef *source); public static int CreateInterfaceAsyncEventSource(MemorySegment self, MemorySegment source) { - return IOUSBInterfaceInterface190.CreateInterfaceAsyncEventSource(getVtable(self), SegmentScope.global()).apply(self, source); + return IOUSBInterfaceInterface190.CreateInterfaceAsyncEventSource(getVtable(self), Arena.global()).apply(self, source); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java index 6a8a0326..eeb780bf 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java @@ -10,10 +10,10 @@ import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; import net.codecrete.usb.macos.gen.iokit.IOKit; +import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.Linker; import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentScope; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.HashMap; @@ -113,7 +113,7 @@ private void startAsyncIOThread(MemorySegment firstSource) { var methodHandle = asyncIOCompletedMH.bindTo(this); completionUpcallStub = Linker.nativeLinker().upcallStub(methodHandle, completionHandlerFuncDesc, - SegmentScope.global()); + Arena.global()); } catch (IllegalAccessException | NoSuchMethodException e) { throw new RuntimeException(e); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index a321fad4..716898d2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -133,10 +133,10 @@ public synchronized void close() { if (!isOpen()) return; - for (InterfaceInfo(MemorySegment iokitInterface, int interfaceNumber) : claimedInterfaces) { - IoKitUSB.USBInterfaceClose(iokitInterface); - IoKitUSB.Release(iokitInterface); - setClaimed(interfaceNumber, false); + for (var interfaceInfo : claimedInterfaces) { + IoKitUSB.USBInterfaceClose(interfaceInfo.iokitInterface); + IoKitUSB.Release(interfaceInfo.iokitInterface); + setClaimed(interfaceInfo.interfaceNumber, false); } claimedInterfaces = null; @@ -156,7 +156,7 @@ synchronized void closeFully() { } private void loadDescription(MemorySegment device) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { configurationValue = 0; @@ -177,7 +177,7 @@ private void loadDescription(MemorySegment device) { private InterfaceInfo findInterface(int interfaceNumber) { - try (var arena = Arena.openConfined(); var outerCleanup = new ScopeCleanup()) { + try (var arena = Arena.ofConfined(); var outerCleanup = new ScopeCleanup()) { var request = arena.allocate(IOUSBFindInterfaceRequest.$LAYOUT()); IOUSBFindInterfaceRequest.bInterfaceClass$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); IOUSBFindInterfaceRequest.bInterfaceSubClass$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); @@ -303,7 +303,7 @@ public synchronized void releaseInterface(int interfaceNumber) { private void updateEndpointList() { endpoints = new HashMap<>(); - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var directionHolder = arena.allocate(JAVA_BYTE); var numberHolder = arena.allocate(JAVA_BYTE); @@ -376,7 +376,7 @@ private static MemorySegment createDeviceRequest(Arena arena, USBDirection direc @Override public byte[] controlTransferIn(USBControlTransfer setup, int length) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var data = arena.allocate(length); var deviceRequest = createDeviceRequest(arena, USBDirection.IN, setup, data); @@ -394,7 +394,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { @Override public void controlTransferOut(USBControlTransfer setup, byte[] data) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { int dataLength = data != null ? data.length : 0; var dataSegment = arena.allocate(dataLength); if (dataLength > 0) @@ -417,7 +417,7 @@ public void transferOut(int endpointNumber, byte[] data, int offset, int length, EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var nativeData = arena.allocateArray(JAVA_BYTE, length); nativeData.copyFrom(MemorySegment.ofArray(data).asSlice(offset, length)); @@ -447,7 +447,7 @@ public byte[] transferIn(int endpointNumber, int timeout) { EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var nativeData = arena.allocateArray(JAVA_BYTE, epInfo.packetSize()); var transfer = new MacosTransfer(); @@ -607,7 +607,7 @@ private static USBTransferType getTransferType(byte macosTransferType) { } private synchronized void addDeviceEventSource() { - try (Arena innerArena = Arena.openConfined()) { + try (Arena innerArena = Arena.ofConfined()) { var sourceHolder = innerArena.allocate(ADDRESS); int ret = IoKitUSB.CreateDeviceAsyncEventSource(device, sourceHolder); if (ret != 0) @@ -618,7 +618,7 @@ private synchronized void addDeviceEventSource() { } private synchronized void addInterfaceEventSource(InterfaceInfo interfaceInfo) { - try (Arena innerArena = Arena.openConfined()) { + try (Arena innerArena = Arena.ofConfined()) { var sourceHolder = innerArena.allocate(ADDRESS); int ret = IoKitUSB.CreateInterfaceAsyncEventSource(interfaceInfo.iokitInterface(), sourceHolder); if (ret != 0) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 27719837..decd4d4f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -29,7 +29,7 @@ */ public class MacosUSBDeviceRegistry extends USBDeviceRegistry { - private final SegmentAllocator GLOBAL_ALLOCATOR = SegmentAllocator.nativeAllocator(SegmentScope.global()); + private final SegmentAllocator GLOBAL_ALLOCATOR = Arena.global(); private final MemorySegment KEY_ID_VENDOR = CoreFoundationHelper.createCFStringRef("idVendor", GLOBAL_ALLOCATOR); private final MemorySegment KEY_ID_PRODUCT = CoreFoundationHelper.createCFStringRef("idProduct", GLOBAL_ALLOCATOR); @@ -59,7 +59,7 @@ public class MacosUSBDeviceRegistry extends USBDeviceRegistry { protected void monitorDevices() { // as the method runs forever, there is no need to clean up one-time allocations - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { try { @@ -107,7 +107,7 @@ protected void monitorDevices() { */ private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var entryIdHolder = arena.allocate(JAVA_LONG); int svc; @@ -166,7 +166,7 @@ private USBDevice createDevice(Long entryID, int service, MemorySegment deviceIn if (deviceIntf == null) return null; - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { Integer vendorId = IoKitHelper.getPropertyInt(service, KEY_ID_VENDOR, arena); Integer productId = IoKitHelper.getPropertyInt(service, KEY_ID_PRODUCT, arena); @@ -208,7 +208,7 @@ private int setupNotification(Arena arena, MemorySegment notifyPort, MemorySegme // create callback stub var onDeviceCallbackStub = Linker.nativeLinker().upcallStub(callback.bindTo(this), - FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT), SegmentScope.global()); + FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT), Arena.global()); // Set up a notification to be called when a device is first matched / terminated by I/O Kit. // This method consumes the matchingDict reference. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java index 66b3102d..302da03d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java @@ -26,7 +26,7 @@ public class UUID { * @return the CFUUID */ public static MemorySegment CreateCFUUID(byte[] bytes) { - try (var arena = Arena.openConfined()) { + try (var arena = Arena.ofConfined()) { var uuidBytes = arena.allocate(16); uuidBytes.copyFrom(MemorySegment.ofArray(bytes)); return CoreFoundation.CFUUIDCreateFromUUIDBytes(NULL, uuidBytes); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java index ef744683..f0f8887b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java @@ -2,7 +2,10 @@ package net.codecrete.usb.macos.gen.corefoundation; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -14,16 +17,11 @@ */ public class CFRange { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_LONG_LONG$LAYOUT.withName("location"), - Constants$root.C_LONG_LONG$LAYOUT.withName("length") - ); public static MemoryLayout $LAYOUT() { - return CFRange.$struct$LAYOUT; + return constants$0.const$0; } - static final VarHandle location$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("location")); public static VarHandle location$VH() { - return CFRange.location$VH; + return constants$0.const$1; } /** * Getter for field: @@ -32,7 +30,7 @@ public class CFRange { * } */ public static long location$get(MemorySegment seg) { - return (long)CFRange.location$VH.get(seg); + return (long)constants$0.const$1.get(seg); } /** * Setter for field: @@ -41,17 +39,16 @@ public class CFRange { * } */ public static void location$set(MemorySegment seg, long x) { - CFRange.location$VH.set(seg, x); + constants$0.const$1.set(seg, x); } public static long location$get(MemorySegment seg, long index) { - return (long)CFRange.location$VH.get(seg.asSlice(index*sizeof())); + return (long)constants$0.const$1.get(seg.asSlice(index*sizeof())); } public static void location$set(MemorySegment seg, long index, long x) { - CFRange.location$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$1.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle length$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("length")); public static VarHandle length$VH() { - return CFRange.length$VH; + return constants$0.const$2; } /** * Getter for field: @@ -60,7 +57,7 @@ public class CFRange { * } */ public static long length$get(MemorySegment seg) { - return (long)CFRange.length$VH.get(seg); + return (long)constants$0.const$2.get(seg); } /** * Setter for field: @@ -69,20 +66,20 @@ public class CFRange { * } */ public static void length$set(MemorySegment seg, long x) { - CFRange.length$VH.set(seg, x); + constants$0.const$2.set(seg, x); } public static long length$get(MemorySegment seg, long index) { - return (long)CFRange.length$VH.get(seg.asSlice(index*sizeof())); + return (long)constants$0.const$2.get(seg.asSlice(index*sizeof())); } public static void length$set(MemorySegment seg, long index, long x) { - CFRange.length$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$2.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java index f2f406e2..26940ac9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java @@ -2,7 +2,10 @@ package net.codecrete.usb.macos.gen.corefoundation; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -28,30 +31,11 @@ */ public class CFUUIDBytes { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("byte0"), - Constants$root.C_CHAR$LAYOUT.withName("byte1"), - Constants$root.C_CHAR$LAYOUT.withName("byte2"), - Constants$root.C_CHAR$LAYOUT.withName("byte3"), - Constants$root.C_CHAR$LAYOUT.withName("byte4"), - Constants$root.C_CHAR$LAYOUT.withName("byte5"), - Constants$root.C_CHAR$LAYOUT.withName("byte6"), - Constants$root.C_CHAR$LAYOUT.withName("byte7"), - Constants$root.C_CHAR$LAYOUT.withName("byte8"), - Constants$root.C_CHAR$LAYOUT.withName("byte9"), - Constants$root.C_CHAR$LAYOUT.withName("byte10"), - Constants$root.C_CHAR$LAYOUT.withName("byte11"), - Constants$root.C_CHAR$LAYOUT.withName("byte12"), - Constants$root.C_CHAR$LAYOUT.withName("byte13"), - Constants$root.C_CHAR$LAYOUT.withName("byte14"), - Constants$root.C_CHAR$LAYOUT.withName("byte15") - ); public static MemoryLayout $LAYOUT() { - return CFUUIDBytes.$struct$LAYOUT; + return constants$3.const$3; } - static final VarHandle byte0$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte0")); public static VarHandle byte0$VH() { - return CFUUIDBytes.byte0$VH; + return constants$3.const$4; } /** * Getter for field: @@ -60,7 +44,7 @@ public class CFUUIDBytes { * } */ public static byte byte0$get(MemorySegment seg) { - return (byte)CFUUIDBytes.byte0$VH.get(seg); + return (byte)constants$3.const$4.get(seg); } /** * Setter for field: @@ -69,17 +53,16 @@ public class CFUUIDBytes { * } */ public static void byte0$set(MemorySegment seg, byte x) { - CFUUIDBytes.byte0$VH.set(seg, x); + constants$3.const$4.set(seg, x); } public static byte byte0$get(MemorySegment seg, long index) { - return (byte)CFUUIDBytes.byte0$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$3.const$4.get(seg.asSlice(index*sizeof())); } public static void byte0$set(MemorySegment seg, long index, byte x) { - CFUUIDBytes.byte0$VH.set(seg.asSlice(index*sizeof()), x); + constants$3.const$4.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle byte1$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte1")); public static VarHandle byte1$VH() { - return CFUUIDBytes.byte1$VH; + return constants$3.const$5; } /** * Getter for field: @@ -88,7 +71,7 @@ public class CFUUIDBytes { * } */ public static byte byte1$get(MemorySegment seg) { - return (byte)CFUUIDBytes.byte1$VH.get(seg); + return (byte)constants$3.const$5.get(seg); } /** * Setter for field: @@ -97,17 +80,16 @@ public class CFUUIDBytes { * } */ public static void byte1$set(MemorySegment seg, byte x) { - CFUUIDBytes.byte1$VH.set(seg, x); + constants$3.const$5.set(seg, x); } public static byte byte1$get(MemorySegment seg, long index) { - return (byte)CFUUIDBytes.byte1$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$3.const$5.get(seg.asSlice(index*sizeof())); } public static void byte1$set(MemorySegment seg, long index, byte x) { - CFUUIDBytes.byte1$VH.set(seg.asSlice(index*sizeof()), x); + constants$3.const$5.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle byte2$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte2")); public static VarHandle byte2$VH() { - return CFUUIDBytes.byte2$VH; + return constants$4.const$0; } /** * Getter for field: @@ -116,7 +98,7 @@ public class CFUUIDBytes { * } */ public static byte byte2$get(MemorySegment seg) { - return (byte)CFUUIDBytes.byte2$VH.get(seg); + return (byte)constants$4.const$0.get(seg); } /** * Setter for field: @@ -125,17 +107,16 @@ public class CFUUIDBytes { * } */ public static void byte2$set(MemorySegment seg, byte x) { - CFUUIDBytes.byte2$VH.set(seg, x); + constants$4.const$0.set(seg, x); } public static byte byte2$get(MemorySegment seg, long index) { - return (byte)CFUUIDBytes.byte2$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$4.const$0.get(seg.asSlice(index*sizeof())); } public static void byte2$set(MemorySegment seg, long index, byte x) { - CFUUIDBytes.byte2$VH.set(seg.asSlice(index*sizeof()), x); + constants$4.const$0.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle byte3$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte3")); public static VarHandle byte3$VH() { - return CFUUIDBytes.byte3$VH; + return constants$4.const$1; } /** * Getter for field: @@ -144,7 +125,7 @@ public class CFUUIDBytes { * } */ public static byte byte3$get(MemorySegment seg) { - return (byte)CFUUIDBytes.byte3$VH.get(seg); + return (byte)constants$4.const$1.get(seg); } /** * Setter for field: @@ -153,17 +134,16 @@ public class CFUUIDBytes { * } */ public static void byte3$set(MemorySegment seg, byte x) { - CFUUIDBytes.byte3$VH.set(seg, x); + constants$4.const$1.set(seg, x); } public static byte byte3$get(MemorySegment seg, long index) { - return (byte)CFUUIDBytes.byte3$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$4.const$1.get(seg.asSlice(index*sizeof())); } public static void byte3$set(MemorySegment seg, long index, byte x) { - CFUUIDBytes.byte3$VH.set(seg.asSlice(index*sizeof()), x); + constants$4.const$1.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle byte4$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte4")); public static VarHandle byte4$VH() { - return CFUUIDBytes.byte4$VH; + return constants$4.const$2; } /** * Getter for field: @@ -172,7 +152,7 @@ public class CFUUIDBytes { * } */ public static byte byte4$get(MemorySegment seg) { - return (byte)CFUUIDBytes.byte4$VH.get(seg); + return (byte)constants$4.const$2.get(seg); } /** * Setter for field: @@ -181,17 +161,16 @@ public class CFUUIDBytes { * } */ public static void byte4$set(MemorySegment seg, byte x) { - CFUUIDBytes.byte4$VH.set(seg, x); + constants$4.const$2.set(seg, x); } public static byte byte4$get(MemorySegment seg, long index) { - return (byte)CFUUIDBytes.byte4$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$4.const$2.get(seg.asSlice(index*sizeof())); } public static void byte4$set(MemorySegment seg, long index, byte x) { - CFUUIDBytes.byte4$VH.set(seg.asSlice(index*sizeof()), x); + constants$4.const$2.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle byte5$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte5")); public static VarHandle byte5$VH() { - return CFUUIDBytes.byte5$VH; + return constants$4.const$3; } /** * Getter for field: @@ -200,7 +179,7 @@ public class CFUUIDBytes { * } */ public static byte byte5$get(MemorySegment seg) { - return (byte)CFUUIDBytes.byte5$VH.get(seg); + return (byte)constants$4.const$3.get(seg); } /** * Setter for field: @@ -209,17 +188,16 @@ public class CFUUIDBytes { * } */ public static void byte5$set(MemorySegment seg, byte x) { - CFUUIDBytes.byte5$VH.set(seg, x); + constants$4.const$3.set(seg, x); } public static byte byte5$get(MemorySegment seg, long index) { - return (byte)CFUUIDBytes.byte5$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$4.const$3.get(seg.asSlice(index*sizeof())); } public static void byte5$set(MemorySegment seg, long index, byte x) { - CFUUIDBytes.byte5$VH.set(seg.asSlice(index*sizeof()), x); + constants$4.const$3.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle byte6$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte6")); public static VarHandle byte6$VH() { - return CFUUIDBytes.byte6$VH; + return constants$4.const$4; } /** * Getter for field: @@ -228,7 +206,7 @@ public class CFUUIDBytes { * } */ public static byte byte6$get(MemorySegment seg) { - return (byte)CFUUIDBytes.byte6$VH.get(seg); + return (byte)constants$4.const$4.get(seg); } /** * Setter for field: @@ -237,17 +215,16 @@ public class CFUUIDBytes { * } */ public static void byte6$set(MemorySegment seg, byte x) { - CFUUIDBytes.byte6$VH.set(seg, x); + constants$4.const$4.set(seg, x); } public static byte byte6$get(MemorySegment seg, long index) { - return (byte)CFUUIDBytes.byte6$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$4.const$4.get(seg.asSlice(index*sizeof())); } public static void byte6$set(MemorySegment seg, long index, byte x) { - CFUUIDBytes.byte6$VH.set(seg.asSlice(index*sizeof()), x); + constants$4.const$4.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle byte7$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte7")); public static VarHandle byte7$VH() { - return CFUUIDBytes.byte7$VH; + return constants$4.const$5; } /** * Getter for field: @@ -256,7 +233,7 @@ public class CFUUIDBytes { * } */ public static byte byte7$get(MemorySegment seg) { - return (byte)CFUUIDBytes.byte7$VH.get(seg); + return (byte)constants$4.const$5.get(seg); } /** * Setter for field: @@ -265,17 +242,16 @@ public class CFUUIDBytes { * } */ public static void byte7$set(MemorySegment seg, byte x) { - CFUUIDBytes.byte7$VH.set(seg, x); + constants$4.const$5.set(seg, x); } public static byte byte7$get(MemorySegment seg, long index) { - return (byte)CFUUIDBytes.byte7$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$4.const$5.get(seg.asSlice(index*sizeof())); } public static void byte7$set(MemorySegment seg, long index, byte x) { - CFUUIDBytes.byte7$VH.set(seg.asSlice(index*sizeof()), x); + constants$4.const$5.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle byte8$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte8")); public static VarHandle byte8$VH() { - return CFUUIDBytes.byte8$VH; + return constants$5.const$0; } /** * Getter for field: @@ -284,7 +260,7 @@ public class CFUUIDBytes { * } */ public static byte byte8$get(MemorySegment seg) { - return (byte)CFUUIDBytes.byte8$VH.get(seg); + return (byte)constants$5.const$0.get(seg); } /** * Setter for field: @@ -293,17 +269,16 @@ public class CFUUIDBytes { * } */ public static void byte8$set(MemorySegment seg, byte x) { - CFUUIDBytes.byte8$VH.set(seg, x); + constants$5.const$0.set(seg, x); } public static byte byte8$get(MemorySegment seg, long index) { - return (byte)CFUUIDBytes.byte8$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$5.const$0.get(seg.asSlice(index*sizeof())); } public static void byte8$set(MemorySegment seg, long index, byte x) { - CFUUIDBytes.byte8$VH.set(seg.asSlice(index*sizeof()), x); + constants$5.const$0.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle byte9$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte9")); public static VarHandle byte9$VH() { - return CFUUIDBytes.byte9$VH; + return constants$5.const$1; } /** * Getter for field: @@ -312,7 +287,7 @@ public class CFUUIDBytes { * } */ public static byte byte9$get(MemorySegment seg) { - return (byte)CFUUIDBytes.byte9$VH.get(seg); + return (byte)constants$5.const$1.get(seg); } /** * Setter for field: @@ -321,17 +296,16 @@ public class CFUUIDBytes { * } */ public static void byte9$set(MemorySegment seg, byte x) { - CFUUIDBytes.byte9$VH.set(seg, x); + constants$5.const$1.set(seg, x); } public static byte byte9$get(MemorySegment seg, long index) { - return (byte)CFUUIDBytes.byte9$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$5.const$1.get(seg.asSlice(index*sizeof())); } public static void byte9$set(MemorySegment seg, long index, byte x) { - CFUUIDBytes.byte9$VH.set(seg.asSlice(index*sizeof()), x); + constants$5.const$1.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle byte10$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte10")); public static VarHandle byte10$VH() { - return CFUUIDBytes.byte10$VH; + return constants$5.const$2; } /** * Getter for field: @@ -340,7 +314,7 @@ public class CFUUIDBytes { * } */ public static byte byte10$get(MemorySegment seg) { - return (byte)CFUUIDBytes.byte10$VH.get(seg); + return (byte)constants$5.const$2.get(seg); } /** * Setter for field: @@ -349,17 +323,16 @@ public class CFUUIDBytes { * } */ public static void byte10$set(MemorySegment seg, byte x) { - CFUUIDBytes.byte10$VH.set(seg, x); + constants$5.const$2.set(seg, x); } public static byte byte10$get(MemorySegment seg, long index) { - return (byte)CFUUIDBytes.byte10$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$5.const$2.get(seg.asSlice(index*sizeof())); } public static void byte10$set(MemorySegment seg, long index, byte x) { - CFUUIDBytes.byte10$VH.set(seg.asSlice(index*sizeof()), x); + constants$5.const$2.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle byte11$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte11")); public static VarHandle byte11$VH() { - return CFUUIDBytes.byte11$VH; + return constants$5.const$3; } /** * Getter for field: @@ -368,7 +341,7 @@ public class CFUUIDBytes { * } */ public static byte byte11$get(MemorySegment seg) { - return (byte)CFUUIDBytes.byte11$VH.get(seg); + return (byte)constants$5.const$3.get(seg); } /** * Setter for field: @@ -377,17 +350,16 @@ public class CFUUIDBytes { * } */ public static void byte11$set(MemorySegment seg, byte x) { - CFUUIDBytes.byte11$VH.set(seg, x); + constants$5.const$3.set(seg, x); } public static byte byte11$get(MemorySegment seg, long index) { - return (byte)CFUUIDBytes.byte11$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$5.const$3.get(seg.asSlice(index*sizeof())); } public static void byte11$set(MemorySegment seg, long index, byte x) { - CFUUIDBytes.byte11$VH.set(seg.asSlice(index*sizeof()), x); + constants$5.const$3.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle byte12$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte12")); public static VarHandle byte12$VH() { - return CFUUIDBytes.byte12$VH; + return constants$5.const$4; } /** * Getter for field: @@ -396,7 +368,7 @@ public class CFUUIDBytes { * } */ public static byte byte12$get(MemorySegment seg) { - return (byte)CFUUIDBytes.byte12$VH.get(seg); + return (byte)constants$5.const$4.get(seg); } /** * Setter for field: @@ -405,17 +377,16 @@ public class CFUUIDBytes { * } */ public static void byte12$set(MemorySegment seg, byte x) { - CFUUIDBytes.byte12$VH.set(seg, x); + constants$5.const$4.set(seg, x); } public static byte byte12$get(MemorySegment seg, long index) { - return (byte)CFUUIDBytes.byte12$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$5.const$4.get(seg.asSlice(index*sizeof())); } public static void byte12$set(MemorySegment seg, long index, byte x) { - CFUUIDBytes.byte12$VH.set(seg.asSlice(index*sizeof()), x); + constants$5.const$4.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle byte13$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte13")); public static VarHandle byte13$VH() { - return CFUUIDBytes.byte13$VH; + return constants$5.const$5; } /** * Getter for field: @@ -424,7 +395,7 @@ public class CFUUIDBytes { * } */ public static byte byte13$get(MemorySegment seg) { - return (byte)CFUUIDBytes.byte13$VH.get(seg); + return (byte)constants$5.const$5.get(seg); } /** * Setter for field: @@ -433,17 +404,16 @@ public class CFUUIDBytes { * } */ public static void byte13$set(MemorySegment seg, byte x) { - CFUUIDBytes.byte13$VH.set(seg, x); + constants$5.const$5.set(seg, x); } public static byte byte13$get(MemorySegment seg, long index) { - return (byte)CFUUIDBytes.byte13$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$5.const$5.get(seg.asSlice(index*sizeof())); } public static void byte13$set(MemorySegment seg, long index, byte x) { - CFUUIDBytes.byte13$VH.set(seg.asSlice(index*sizeof()), x); + constants$5.const$5.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle byte14$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte14")); public static VarHandle byte14$VH() { - return CFUUIDBytes.byte14$VH; + return constants$6.const$0; } /** * Getter for field: @@ -452,7 +422,7 @@ public class CFUUIDBytes { * } */ public static byte byte14$get(MemorySegment seg) { - return (byte)CFUUIDBytes.byte14$VH.get(seg); + return (byte)constants$6.const$0.get(seg); } /** * Setter for field: @@ -461,17 +431,16 @@ public class CFUUIDBytes { * } */ public static void byte14$set(MemorySegment seg, byte x) { - CFUUIDBytes.byte14$VH.set(seg, x); + constants$6.const$0.set(seg, x); } public static byte byte14$get(MemorySegment seg, long index) { - return (byte)CFUUIDBytes.byte14$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$6.const$0.get(seg.asSlice(index*sizeof())); } public static void byte14$set(MemorySegment seg, long index, byte x) { - CFUUIDBytes.byte14$VH.set(seg.asSlice(index*sizeof()), x); + constants$6.const$0.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle byte15$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("byte15")); public static VarHandle byte15$VH() { - return CFUUIDBytes.byte15$VH; + return constants$6.const$1; } /** * Getter for field: @@ -480,7 +449,7 @@ public class CFUUIDBytes { * } */ public static byte byte15$get(MemorySegment seg) { - return (byte)CFUUIDBytes.byte15$VH.get(seg); + return (byte)constants$6.const$1.get(seg); } /** * Setter for field: @@ -489,20 +458,20 @@ public class CFUUIDBytes { * } */ public static void byte15$set(MemorySegment seg, byte x) { - CFUUIDBytes.byte15$VH.set(seg, x); + constants$6.const$1.set(seg, x); } public static byte byte15$get(MemorySegment seg, long index) { - return (byte)CFUUIDBytes.byte15$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$6.const$1.get(seg.asSlice(index*sizeof())); } public static void byte15$set(MemorySegment seg, long index, byte x) { - CFUUIDBytes.byte15$VH.set(seg.asSlice(index*sizeof()), x); + constants$6.const$1.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/Constants$root.java deleted file mode 100644 index 5de30387..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.corefoundation; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfLong C_LONG$LAYOUT = JAVA_LONG; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java index 4b0efbe2..3b1c3e58 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java @@ -2,6 +2,7 @@ package net.codecrete.usb.macos.gen.corefoundation; +import java.lang.foreign.AddressLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; import java.lang.invoke.MethodHandle; @@ -9,16 +10,16 @@ import static java.lang.foreign.ValueLayout.*; public class CoreFoundation { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfLong C_LONG = JAVA_LONG; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; public static MethodHandle CFGetTypeID$MH() { - return RuntimeHelper.requireNonNull(constants$0.CFGetTypeID$MH,"CFGetTypeID"); + return RuntimeHelper.requireNonNull(constants$0.const$4,"CFGetTypeID"); } /** * {@snippet : @@ -34,7 +35,7 @@ public static long CFGetTypeID(MemorySegment cf) { } } public static MethodHandle CFRelease$MH() { - return RuntimeHelper.requireNonNull(constants$0.CFRelease$MH,"CFRelease"); + return RuntimeHelper.requireNonNull(constants$0.const$6,"CFRelease"); } /** * {@snippet : @@ -50,7 +51,7 @@ public static void CFRelease(MemorySegment cf) { } } public static MethodHandle CFStringGetTypeID$MH() { - return RuntimeHelper.requireNonNull(constants$0.CFStringGetTypeID$MH,"CFStringGetTypeID"); + return RuntimeHelper.requireNonNull(constants$1.const$1,"CFStringGetTypeID"); } /** * {@snippet : @@ -66,7 +67,7 @@ public static long CFStringGetTypeID() { } } public static MethodHandle CFStringCreateWithCharacters$MH() { - return RuntimeHelper.requireNonNull(constants$0.CFStringCreateWithCharacters$MH,"CFStringCreateWithCharacters"); + return RuntimeHelper.requireNonNull(constants$1.const$3,"CFStringCreateWithCharacters"); } /** * {@snippet : @@ -82,7 +83,7 @@ public static MemorySegment CFStringCreateWithCharacters(MemorySegment alloc, Me } } public static MethodHandle CFStringGetLength$MH() { - return RuntimeHelper.requireNonNull(constants$0.CFStringGetLength$MH,"CFStringGetLength"); + return RuntimeHelper.requireNonNull(constants$1.const$4,"CFStringGetLength"); } /** * {@snippet : @@ -98,7 +99,7 @@ public static long CFStringGetLength(MemorySegment theString) { } } public static MethodHandle CFStringGetCharacters$MH() { - return RuntimeHelper.requireNonNull(constants$0.CFStringGetCharacters$MH,"CFStringGetCharacters"); + return RuntimeHelper.requireNonNull(constants$1.const$6,"CFStringGetCharacters"); } /** * {@snippet : @@ -122,7 +123,7 @@ public static int kCFNumberSInt32Type() { return (int)3L; } public static MethodHandle CFNumberGetTypeID$MH() { - return RuntimeHelper.requireNonNull(constants$1.CFNumberGetTypeID$MH,"CFNumberGetTypeID"); + return RuntimeHelper.requireNonNull(constants$2.const$0,"CFNumberGetTypeID"); } /** * {@snippet : @@ -138,7 +139,7 @@ public static long CFNumberGetTypeID() { } } public static MethodHandle CFNumberGetValue$MH() { - return RuntimeHelper.requireNonNull(constants$1.CFNumberGetValue$MH,"CFNumberGetValue"); + return RuntimeHelper.requireNonNull(constants$2.const$2,"CFNumberGetValue"); } /** * {@snippet : @@ -154,7 +155,7 @@ public static byte CFNumberGetValue(MemorySegment number, long theType, MemorySe } } public static MethodHandle CFRunLoopGetCurrent$MH() { - return RuntimeHelper.requireNonNull(constants$1.CFRunLoopGetCurrent$MH,"CFRunLoopGetCurrent"); + return RuntimeHelper.requireNonNull(constants$2.const$4,"CFRunLoopGetCurrent"); } /** * {@snippet : @@ -170,7 +171,7 @@ public static MemorySegment CFRunLoopGetCurrent() { } } public static MethodHandle CFRunLoopRun$MH() { - return RuntimeHelper.requireNonNull(constants$1.CFRunLoopRun$MH,"CFRunLoopRun"); + return RuntimeHelper.requireNonNull(constants$2.const$6,"CFRunLoopRun"); } /** * {@snippet : @@ -186,7 +187,7 @@ public static void CFRunLoopRun() { } } public static MethodHandle CFRunLoopAddSource$MH() { - return RuntimeHelper.requireNonNull(constants$1.CFRunLoopAddSource$MH,"CFRunLoopAddSource"); + return RuntimeHelper.requireNonNull(constants$3.const$1,"CFRunLoopAddSource"); } /** * {@snippet : @@ -202,7 +203,7 @@ public static void CFRunLoopAddSource(MemorySegment rl, MemorySegment source, Me } } public static MethodHandle CFRunLoopRemoveSource$MH() { - return RuntimeHelper.requireNonNull(constants$1.CFRunLoopRemoveSource$MH,"CFRunLoopRemoveSource"); + return RuntimeHelper.requireNonNull(constants$3.const$2,"CFRunLoopRemoveSource"); } /** * {@snippet : @@ -218,7 +219,7 @@ public static void CFRunLoopRemoveSource(MemorySegment rl, MemorySegment source, } } public static MethodHandle CFUUIDGetUUIDBytes$MH() { - return RuntimeHelper.requireNonNull(constants$2.CFUUIDGetUUIDBytes$MH,"CFUUIDGetUUIDBytes"); + return RuntimeHelper.requireNonNull(constants$6.const$3,"CFUUIDGetUUIDBytes"); } /** * {@snippet : @@ -234,7 +235,7 @@ public static MemorySegment CFUUIDGetUUIDBytes(SegmentAllocator allocator, Memor } } public static MethodHandle CFUUIDCreateFromUUIDBytes$MH() { - return RuntimeHelper.requireNonNull(constants$2.CFUUIDCreateFromUUIDBytes$MH,"CFUUIDCreateFromUUIDBytes"); + return RuntimeHelper.requireNonNull(constants$6.const$5,"CFUUIDCreateFromUUIDBytes"); } /** * {@snippet : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java index d4f89117..9fb56e43 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java @@ -15,14 +15,15 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { // System.loadLibrary("CoreFoundation.framework"); // SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SymbolLookup loaderLookup = SymbolLookup.libraryLookup("CoreFoundation.framework/CoreFoundation", SegmentScope.global()); + SymbolLookup loaderLookup = SymbolLookup.libraryLookup("CoreFoundation.framework/CoreFoundation", Arena.global()); SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } @@ -37,7 +38,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -56,18 +59,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$0.java index 6a64bbf2..ec347d54 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$0.java @@ -4,57 +4,34 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_LONG; final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} - static final FunctionDescriptor CFGetTypeID$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle CFGetTypeID$MH = RuntimeHelper.downcallHandle( + static final StructLayout const$0 = MemoryLayout.structLayout( + JAVA_LONG.withName("location"), + JAVA_LONG.withName("length") + ).withName(""); + static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("location")); + static final VarHandle const$2 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("length")); + static final FunctionDescriptor const$3 = FunctionDescriptor.of(JAVA_LONG, + RuntimeHelper.POINTER + ); + static final MethodHandle const$4 = RuntimeHelper.downcallHandle( "CFGetTypeID", - constants$0.CFGetTypeID$FUNC + constants$0.const$3 ); - static final FunctionDescriptor CFRelease$FUNC = FunctionDescriptor.ofVoid( - Constants$root.C_POINTER$LAYOUT + static final FunctionDescriptor const$5 = FunctionDescriptor.ofVoid( + RuntimeHelper.POINTER ); - static final MethodHandle CFRelease$MH = RuntimeHelper.downcallHandle( + static final MethodHandle const$6 = RuntimeHelper.downcallHandle( "CFRelease", - constants$0.CFRelease$FUNC - ); - static final FunctionDescriptor CFStringGetTypeID$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT); - static final MethodHandle CFStringGetTypeID$MH = RuntimeHelper.downcallHandle( - "CFStringGetTypeID", - constants$0.CFStringGetTypeID$FUNC - ); - static final FunctionDescriptor CFStringCreateWithCharacters$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT - ); - static final MethodHandle CFStringCreateWithCharacters$MH = RuntimeHelper.downcallHandle( - "CFStringCreateWithCharacters", - constants$0.CFStringCreateWithCharacters$FUNC - ); - static final FunctionDescriptor CFStringGetLength$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle CFStringGetLength$MH = RuntimeHelper.downcallHandle( - "CFStringGetLength", - constants$0.CFStringGetLength$FUNC - ); - static final FunctionDescriptor CFStringGetCharacters$FUNC = FunctionDescriptor.ofVoid( - Constants$root.C_POINTER$LAYOUT, - MemoryLayout.structLayout( - Constants$root.C_LONG_LONG$LAYOUT.withName("location"), - Constants$root.C_LONG_LONG$LAYOUT.withName("length") - ), - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle CFStringGetCharacters$MH = RuntimeHelper.downcallHandle( - "CFStringGetCharacters", - constants$0.CFStringGetCharacters$FUNC + constants$0.const$5 ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java index c4ac9715..d7550d1a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java @@ -3,52 +3,43 @@ package net.codecrete.usb.macos.gen.corefoundation; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.JAVA_LONG; final class constants$1 { // Suppresses default constructor, ensuring non-instantiability. private constants$1() {} - static final FunctionDescriptor CFNumberGetTypeID$FUNC = FunctionDescriptor.of(Constants$root.C_LONG_LONG$LAYOUT); - static final MethodHandle CFNumberGetTypeID$MH = RuntimeHelper.downcallHandle( - "CFNumberGetTypeID", - constants$1.CFNumberGetTypeID$FUNC - ); - static final FunctionDescriptor CFNumberGetValue$FUNC = FunctionDescriptor.of(Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle CFNumberGetValue$MH = RuntimeHelper.downcallHandle( - "CFNumberGetValue", - constants$1.CFNumberGetValue$FUNC - ); - static final FunctionDescriptor CFRunLoopGetCurrent$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT); - static final MethodHandle CFRunLoopGetCurrent$MH = RuntimeHelper.downcallHandle( - "CFRunLoopGetCurrent", - constants$1.CFRunLoopGetCurrent$FUNC - ); - static final FunctionDescriptor CFRunLoopRun$FUNC = FunctionDescriptor.ofVoid(); - static final MethodHandle CFRunLoopRun$MH = RuntimeHelper.downcallHandle( - "CFRunLoopRun", - constants$1.CFRunLoopRun$FUNC - ); - static final FunctionDescriptor CFRunLoopAddSource$FUNC = FunctionDescriptor.ofVoid( - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle CFRunLoopAddSource$MH = RuntimeHelper.downcallHandle( - "CFRunLoopAddSource", - constants$1.CFRunLoopAddSource$FUNC - ); - static final FunctionDescriptor CFRunLoopRemoveSource$FUNC = FunctionDescriptor.ofVoid( - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle CFRunLoopRemoveSource$MH = RuntimeHelper.downcallHandle( - "CFRunLoopRemoveSource", - constants$1.CFRunLoopRemoveSource$FUNC + static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_LONG); + static final MethodHandle const$1 = RuntimeHelper.downcallHandle( + "CFStringGetTypeID", + constants$1.const$0 + ); + static final FunctionDescriptor const$2 = FunctionDescriptor.of(RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + JAVA_LONG + ); + static final MethodHandle const$3 = RuntimeHelper.downcallHandle( + "CFStringCreateWithCharacters", + constants$1.const$2 + ); + static final MethodHandle const$4 = RuntimeHelper.downcallHandle( + "CFStringGetLength", + constants$0.const$3 + ); + static final FunctionDescriptor const$5 = FunctionDescriptor.ofVoid( + RuntimeHelper.POINTER, + MemoryLayout.structLayout( + JAVA_LONG.withName("location"), + JAVA_LONG.withName("length") + ).withName(""), + RuntimeHelper.POINTER + ); + static final MethodHandle const$6 = RuntimeHelper.downcallHandle( + "CFStringGetCharacters", + constants$1.const$5 ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java index 5e1183c1..7db1c6cc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java @@ -3,60 +3,36 @@ package net.codecrete.usb.macos.gen.corefoundation; import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_LONG; final class constants$2 { // Suppresses default constructor, ensuring non-instantiability. private constants$2() {} - static final FunctionDescriptor CFUUIDGetUUIDBytes$FUNC = FunctionDescriptor.of(MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("byte0"), - Constants$root.C_CHAR$LAYOUT.withName("byte1"), - Constants$root.C_CHAR$LAYOUT.withName("byte2"), - Constants$root.C_CHAR$LAYOUT.withName("byte3"), - Constants$root.C_CHAR$LAYOUT.withName("byte4"), - Constants$root.C_CHAR$LAYOUT.withName("byte5"), - Constants$root.C_CHAR$LAYOUT.withName("byte6"), - Constants$root.C_CHAR$LAYOUT.withName("byte7"), - Constants$root.C_CHAR$LAYOUT.withName("byte8"), - Constants$root.C_CHAR$LAYOUT.withName("byte9"), - Constants$root.C_CHAR$LAYOUT.withName("byte10"), - Constants$root.C_CHAR$LAYOUT.withName("byte11"), - Constants$root.C_CHAR$LAYOUT.withName("byte12"), - Constants$root.C_CHAR$LAYOUT.withName("byte13"), - Constants$root.C_CHAR$LAYOUT.withName("byte14"), - Constants$root.C_CHAR$LAYOUT.withName("byte15") - ), - Constants$root.C_POINTER$LAYOUT + static final MethodHandle const$0 = RuntimeHelper.downcallHandle( + "CFNumberGetTypeID", + constants$1.const$0 + ); + static final FunctionDescriptor const$1 = FunctionDescriptor.of(JAVA_BYTE, + RuntimeHelper.POINTER, + JAVA_LONG, + RuntimeHelper.POINTER ); - static final MethodHandle CFUUIDGetUUIDBytes$MH = RuntimeHelper.downcallHandle( - "CFUUIDGetUUIDBytes", - constants$2.CFUUIDGetUUIDBytes$FUNC + static final MethodHandle const$2 = RuntimeHelper.downcallHandle( + "CFNumberGetValue", + constants$2.const$1 ); - static final FunctionDescriptor CFUUIDCreateFromUUIDBytes$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("byte0"), - Constants$root.C_CHAR$LAYOUT.withName("byte1"), - Constants$root.C_CHAR$LAYOUT.withName("byte2"), - Constants$root.C_CHAR$LAYOUT.withName("byte3"), - Constants$root.C_CHAR$LAYOUT.withName("byte4"), - Constants$root.C_CHAR$LAYOUT.withName("byte5"), - Constants$root.C_CHAR$LAYOUT.withName("byte6"), - Constants$root.C_CHAR$LAYOUT.withName("byte7"), - Constants$root.C_CHAR$LAYOUT.withName("byte8"), - Constants$root.C_CHAR$LAYOUT.withName("byte9"), - Constants$root.C_CHAR$LAYOUT.withName("byte10"), - Constants$root.C_CHAR$LAYOUT.withName("byte11"), - Constants$root.C_CHAR$LAYOUT.withName("byte12"), - Constants$root.C_CHAR$LAYOUT.withName("byte13"), - Constants$root.C_CHAR$LAYOUT.withName("byte14"), - Constants$root.C_CHAR$LAYOUT.withName("byte15") - ) + static final FunctionDescriptor const$3 = FunctionDescriptor.of(RuntimeHelper.POINTER); + static final MethodHandle const$4 = RuntimeHelper.downcallHandle( + "CFRunLoopGetCurrent", + constants$2.const$3 ); - static final MethodHandle CFUUIDCreateFromUUIDBytes$MH = RuntimeHelper.downcallHandle( - "CFUUIDCreateFromUUIDBytes", - constants$2.CFUUIDCreateFromUUIDBytes$FUNC + static final FunctionDescriptor const$5 = FunctionDescriptor.ofVoid(); + static final MethodHandle const$6 = RuntimeHelper.downcallHandle( + "CFRunLoopRun", + constants$2.const$5 ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$3.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$3.java new file mode 100644 index 00000000..1a0a9ed3 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$3.java @@ -0,0 +1,51 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.corefoundation; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +final class constants$3 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$3() {} + static final FunctionDescriptor const$0 = FunctionDescriptor.ofVoid( + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER + ); + static final MethodHandle const$1 = RuntimeHelper.downcallHandle( + "CFRunLoopAddSource", + constants$3.const$0 + ); + static final MethodHandle const$2 = RuntimeHelper.downcallHandle( + "CFRunLoopRemoveSource", + constants$3.const$0 + ); + static final StructLayout const$3 = MemoryLayout.structLayout( + JAVA_BYTE.withName("byte0"), + JAVA_BYTE.withName("byte1"), + JAVA_BYTE.withName("byte2"), + JAVA_BYTE.withName("byte3"), + JAVA_BYTE.withName("byte4"), + JAVA_BYTE.withName("byte5"), + JAVA_BYTE.withName("byte6"), + JAVA_BYTE.withName("byte7"), + JAVA_BYTE.withName("byte8"), + JAVA_BYTE.withName("byte9"), + JAVA_BYTE.withName("byte10"), + JAVA_BYTE.withName("byte11"), + JAVA_BYTE.withName("byte12"), + JAVA_BYTE.withName("byte13"), + JAVA_BYTE.withName("byte14"), + JAVA_BYTE.withName("byte15") + ).withName(""); + static final VarHandle const$4 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte0")); + static final VarHandle const$5 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte1")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$4.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$4.java new file mode 100644 index 00000000..52637eb6 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$4.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.corefoundation; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.VarHandle; +final class constants$4 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$4() {} + static final VarHandle const$0 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte2")); + static final VarHandle const$1 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte3")); + static final VarHandle const$2 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte4")); + static final VarHandle const$3 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte5")); + static final VarHandle const$4 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte6")); + static final VarHandle const$5 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte7")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$5.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$5.java new file mode 100644 index 00000000..075afe34 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$5.java @@ -0,0 +1,19 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.corefoundation; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.VarHandle; +final class constants$5 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$5() {} + static final VarHandle const$0 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte8")); + static final VarHandle const$1 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte9")); + static final VarHandle const$2 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte10")); + static final VarHandle const$3 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte11")); + static final VarHandle const$4 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte12")); + static final VarHandle const$5 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte13")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$6.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$6.java new file mode 100644 index 00000000..748e65c4 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$6.java @@ -0,0 +1,68 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.corefoundation; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +final class constants$6 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$6() {} + static final VarHandle const$0 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte14")); + static final VarHandle const$1 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte15")); + static final FunctionDescriptor const$2 = FunctionDescriptor.of(MemoryLayout.structLayout( + JAVA_BYTE.withName("byte0"), + JAVA_BYTE.withName("byte1"), + JAVA_BYTE.withName("byte2"), + JAVA_BYTE.withName("byte3"), + JAVA_BYTE.withName("byte4"), + JAVA_BYTE.withName("byte5"), + JAVA_BYTE.withName("byte6"), + JAVA_BYTE.withName("byte7"), + JAVA_BYTE.withName("byte8"), + JAVA_BYTE.withName("byte9"), + JAVA_BYTE.withName("byte10"), + JAVA_BYTE.withName("byte11"), + JAVA_BYTE.withName("byte12"), + JAVA_BYTE.withName("byte13"), + JAVA_BYTE.withName("byte14"), + JAVA_BYTE.withName("byte15") + ).withName(""), + RuntimeHelper.POINTER + ); + static final MethodHandle const$3 = RuntimeHelper.downcallHandle( + "CFUUIDGetUUIDBytes", + constants$6.const$2 + ); + static final FunctionDescriptor const$4 = FunctionDescriptor.of(RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + MemoryLayout.structLayout( + JAVA_BYTE.withName("byte0"), + JAVA_BYTE.withName("byte1"), + JAVA_BYTE.withName("byte2"), + JAVA_BYTE.withName("byte3"), + JAVA_BYTE.withName("byte4"), + JAVA_BYTE.withName("byte5"), + JAVA_BYTE.withName("byte6"), + JAVA_BYTE.withName("byte7"), + JAVA_BYTE.withName("byte8"), + JAVA_BYTE.withName("byte9"), + JAVA_BYTE.withName("byte10"), + JAVA_BYTE.withName("byte11"), + JAVA_BYTE.withName("byte12"), + JAVA_BYTE.withName("byte13"), + JAVA_BYTE.withName("byte14"), + JAVA_BYTE.withName("byte15") + ).withName("") + ); + static final MethodHandle const$5 = RuntimeHelper.downcallHandle( + "CFUUIDCreateFromUUIDBytes", + constants$6.const$4 + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/Constants$root.java deleted file mode 100644 index 7c6305d6..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfLong C_LONG$LAYOUT = JAVA_LONG; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java index 5aadda09..92d54afc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java @@ -2,8 +2,10 @@ package net.codecrete.usb.macos.gen.iokit; -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -22,24 +24,11 @@ */ public class IOCFPlugInInterfaceStruct { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_POINTER$LAYOUT.withName("_reserved"), - Constants$root.C_POINTER$LAYOUT.withName("QueryInterface"), - Constants$root.C_POINTER$LAYOUT.withName("AddRef"), - Constants$root.C_POINTER$LAYOUT.withName("Release"), - Constants$root.C_SHORT$LAYOUT.withName("version"), - Constants$root.C_SHORT$LAYOUT.withName("revision"), - MemoryLayout.paddingLayout(32), - Constants$root.C_POINTER$LAYOUT.withName("Probe"), - Constants$root.C_POINTER$LAYOUT.withName("Start"), - Constants$root.C_POINTER$LAYOUT.withName("Stop") - ).withName("IOCFPlugInInterfaceStruct"); public static MemoryLayout $LAYOUT() { - return IOCFPlugInInterfaceStruct.$struct$LAYOUT; + return constants$40.const$2; } - static final VarHandle _reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("_reserved")); public static VarHandle _reserved$VH() { - return IOCFPlugInInterfaceStruct._reserved$VH; + return constants$40.const$3; } /** * Getter for field: @@ -48,7 +37,7 @@ public class IOCFPlugInInterfaceStruct { * } */ public static MemorySegment _reserved$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct._reserved$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$40.const$3.get(seg); } /** * Setter for field: @@ -57,39 +46,14 @@ public class IOCFPlugInInterfaceStruct { * } */ public static void _reserved$set(MemorySegment seg, MemorySegment x) { - IOCFPlugInInterfaceStruct._reserved$VH.set(seg, x); + constants$40.const$3.set(seg, x); } public static MemorySegment _reserved$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct._reserved$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$40.const$3.get(seg.asSlice(index*sizeof())); } public static void _reserved$set(MemorySegment seg, long index, MemorySegment x) { - IOCFPlugInInterfaceStruct._reserved$VH.set(seg.asSlice(index*sizeof()), x); - } - static final FunctionDescriptor QueryInterface$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("byte0"), - Constants$root.C_CHAR$LAYOUT.withName("byte1"), - Constants$root.C_CHAR$LAYOUT.withName("byte2"), - Constants$root.C_CHAR$LAYOUT.withName("byte3"), - Constants$root.C_CHAR$LAYOUT.withName("byte4"), - Constants$root.C_CHAR$LAYOUT.withName("byte5"), - Constants$root.C_CHAR$LAYOUT.withName("byte6"), - Constants$root.C_CHAR$LAYOUT.withName("byte7"), - Constants$root.C_CHAR$LAYOUT.withName("byte8"), - Constants$root.C_CHAR$LAYOUT.withName("byte9"), - Constants$root.C_CHAR$LAYOUT.withName("byte10"), - Constants$root.C_CHAR$LAYOUT.withName("byte11"), - Constants$root.C_CHAR$LAYOUT.withName("byte12"), - Constants$root.C_CHAR$LAYOUT.withName("byte13"), - Constants$root.C_CHAR$LAYOUT.withName("byte14"), - Constants$root.C_CHAR$LAYOUT.withName("byte15") - ), - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle QueryInterface$MH = RuntimeHelper.downcallHandle( - IOCFPlugInInterfaceStruct.QueryInterface$FUNC - ); + constants$40.const$3.set(seg.asSlice(index*sizeof()), x); + } /** * {@snippet : * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); @@ -98,14 +62,14 @@ public class IOCFPlugInInterfaceStruct { public interface QueryInterface { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(QueryInterface fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOCFPlugInInterfaceStruct.QueryInterface$FUNC, scope); + static MemorySegment allocate(QueryInterface fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$40.const$4, fi, constants$5.const$1, scope); } - static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static QueryInterface ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOCFPlugInInterfaceStruct.QueryInterface$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)constants$5.const$3.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -113,9 +77,8 @@ static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle QueryInterface$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("QueryInterface")); public static VarHandle QueryInterface$VH() { - return IOCFPlugInInterfaceStruct.QueryInterface$VH; + return constants$40.const$5; } /** * Getter for field: @@ -124,7 +87,7 @@ static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment QueryInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.QueryInterface$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$40.const$5.get(seg); } /** * Setter for field: @@ -133,23 +96,17 @@ static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void QueryInterface$set(MemorySegment seg, MemorySegment x) { - IOCFPlugInInterfaceStruct.QueryInterface$VH.set(seg, x); + constants$40.const$5.set(seg, x); } public static MemorySegment QueryInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.QueryInterface$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$40.const$5.get(seg.asSlice(index*sizeof())); } public static void QueryInterface$set(MemorySegment seg, long index, MemorySegment x) { - IOCFPlugInInterfaceStruct.QueryInterface$VH.set(seg.asSlice(index*sizeof()), x); + constants$40.const$5.set(seg.asSlice(index*sizeof()), x); } - public static QueryInterface QueryInterface(MemorySegment segment, SegmentScope scope) { + public static QueryInterface QueryInterface(MemorySegment segment, Arena scope) { return QueryInterface.ofAddress(QueryInterface$get(segment), scope); } - static final FunctionDescriptor AddRef$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle AddRef$MH = RuntimeHelper.downcallHandle( - IOCFPlugInInterfaceStruct.AddRef$FUNC - ); /** * {@snippet : * ULONG (*AddRef)(void*); @@ -158,14 +115,14 @@ public static QueryInterface QueryInterface(MemorySegment segment, SegmentScope public interface AddRef { int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(AddRef fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(AddRef.class, fi, IOCFPlugInInterfaceStruct.AddRef$FUNC, scope); + static MemorySegment allocate(AddRef fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$41.const$0, fi, constants$5.const$5, scope); } - static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static AddRef ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOCFPlugInInterfaceStruct.AddRef$MH.invokeExact(symbol, __x0); + return (int)constants$6.const$1.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -173,9 +130,8 @@ static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle AddRef$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AddRef")); public static VarHandle AddRef$VH() { - return IOCFPlugInInterfaceStruct.AddRef$VH; + return constants$41.const$1; } /** * Getter for field: @@ -184,7 +140,7 @@ static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment AddRef$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.AddRef$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$41.const$1.get(seg); } /** * Setter for field: @@ -193,23 +149,17 @@ static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void AddRef$set(MemorySegment seg, MemorySegment x) { - IOCFPlugInInterfaceStruct.AddRef$VH.set(seg, x); + constants$41.const$1.set(seg, x); } public static MemorySegment AddRef$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.AddRef$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$41.const$1.get(seg.asSlice(index*sizeof())); } public static void AddRef$set(MemorySegment seg, long index, MemorySegment x) { - IOCFPlugInInterfaceStruct.AddRef$VH.set(seg.asSlice(index*sizeof()), x); + constants$41.const$1.set(seg.asSlice(index*sizeof()), x); } - public static AddRef AddRef(MemorySegment segment, SegmentScope scope) { + public static AddRef AddRef(MemorySegment segment, Arena scope) { return AddRef.ofAddress(AddRef$get(segment), scope); } - static final FunctionDescriptor Release$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle Release$MH = RuntimeHelper.downcallHandle( - IOCFPlugInInterfaceStruct.Release$FUNC - ); /** * {@snippet : * ULONG (*Release)(void*); @@ -218,14 +168,14 @@ public static AddRef AddRef(MemorySegment segment, SegmentScope scope) { public interface Release { int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(Release fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(Release.class, fi, IOCFPlugInInterfaceStruct.Release$FUNC, scope); + static MemorySegment allocate(Release fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$41.const$2, fi, constants$5.const$5, scope); } - static Release ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static Release ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOCFPlugInInterfaceStruct.Release$MH.invokeExact(symbol, __x0); + return (int)constants$6.const$1.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -233,9 +183,8 @@ static Release ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle Release$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Release")); public static VarHandle Release$VH() { - return IOCFPlugInInterfaceStruct.Release$VH; + return constants$41.const$3; } /** * Getter for field: @@ -244,7 +193,7 @@ static Release ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment Release$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.Release$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$41.const$3.get(seg); } /** * Setter for field: @@ -253,20 +202,19 @@ static Release ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void Release$set(MemorySegment seg, MemorySegment x) { - IOCFPlugInInterfaceStruct.Release$VH.set(seg, x); + constants$41.const$3.set(seg, x); } public static MemorySegment Release$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.Release$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$41.const$3.get(seg.asSlice(index*sizeof())); } public static void Release$set(MemorySegment seg, long index, MemorySegment x) { - IOCFPlugInInterfaceStruct.Release$VH.set(seg.asSlice(index*sizeof()), x); + constants$41.const$3.set(seg.asSlice(index*sizeof()), x); } - public static Release Release(MemorySegment segment, SegmentScope scope) { + public static Release Release(MemorySegment segment, Arena scope) { return Release.ofAddress(Release$get(segment), scope); } - static final VarHandle version$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("version")); public static VarHandle version$VH() { - return IOCFPlugInInterfaceStruct.version$VH; + return constants$41.const$4; } /** * Getter for field: @@ -275,7 +223,7 @@ public static Release Release(MemorySegment segment, SegmentScope scope) { * } */ public static short version$get(MemorySegment seg) { - return (short)IOCFPlugInInterfaceStruct.version$VH.get(seg); + return (short)constants$41.const$4.get(seg); } /** * Setter for field: @@ -284,17 +232,16 @@ public static Release Release(MemorySegment segment, SegmentScope scope) { * } */ public static void version$set(MemorySegment seg, short x) { - IOCFPlugInInterfaceStruct.version$VH.set(seg, x); + constants$41.const$4.set(seg, x); } public static short version$get(MemorySegment seg, long index) { - return (short)IOCFPlugInInterfaceStruct.version$VH.get(seg.asSlice(index*sizeof())); + return (short)constants$41.const$4.get(seg.asSlice(index*sizeof())); } public static void version$set(MemorySegment seg, long index, short x) { - IOCFPlugInInterfaceStruct.version$VH.set(seg.asSlice(index*sizeof()), x); + constants$41.const$4.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle revision$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("revision")); public static VarHandle revision$VH() { - return IOCFPlugInInterfaceStruct.revision$VH; + return constants$41.const$5; } /** * Getter for field: @@ -303,7 +250,7 @@ public static Release Release(MemorySegment segment, SegmentScope scope) { * } */ public static short revision$get(MemorySegment seg) { - return (short)IOCFPlugInInterfaceStruct.revision$VH.get(seg); + return (short)constants$41.const$5.get(seg); } /** * Setter for field: @@ -312,23 +259,14 @@ public static Release Release(MemorySegment segment, SegmentScope scope) { * } */ public static void revision$set(MemorySegment seg, short x) { - IOCFPlugInInterfaceStruct.revision$VH.set(seg, x); + constants$41.const$5.set(seg, x); } public static short revision$get(MemorySegment seg, long index) { - return (short)IOCFPlugInInterfaceStruct.revision$VH.get(seg.asSlice(index*sizeof())); + return (short)constants$41.const$5.get(seg.asSlice(index*sizeof())); } public static void revision$set(MemorySegment seg, long index, short x) { - IOCFPlugInInterfaceStruct.revision$VH.set(seg.asSlice(index*sizeof()), x); - } - static final FunctionDescriptor Probe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle Probe$MH = RuntimeHelper.downcallHandle( - IOCFPlugInInterfaceStruct.Probe$FUNC - ); + constants$41.const$5.set(seg.asSlice(index*sizeof()), x); + } /** * {@snippet : * IOReturn (*Probe)(void*,CFDictionaryRef,io_service_t,SInt32*); @@ -337,14 +275,14 @@ public static Release Release(MemorySegment segment, SegmentScope scope) { public interface Probe { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, int _x2, java.lang.foreign.MemorySegment _x3); - static MemorySegment allocate(Probe fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(Probe.class, fi, IOCFPlugInInterfaceStruct.Probe$FUNC, scope); + static MemorySegment allocate(Probe fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$42.const$1, fi, constants$42.const$0, scope); } - static Probe ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static Probe ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, int __x2, java.lang.foreign.MemorySegment __x3) -> { try { - return (int)IOCFPlugInInterfaceStruct.Probe$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); + return (int)constants$42.const$2.invokeExact(symbol, __x0, __x1, __x2, __x3); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -352,9 +290,8 @@ static Probe ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle Probe$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Probe")); public static VarHandle Probe$VH() { - return IOCFPlugInInterfaceStruct.Probe$VH; + return constants$42.const$3; } /** * Getter for field: @@ -363,7 +300,7 @@ static Probe ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment Probe$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.Probe$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$42.const$3.get(seg); } /** * Setter for field: @@ -372,25 +309,17 @@ static Probe ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void Probe$set(MemorySegment seg, MemorySegment x) { - IOCFPlugInInterfaceStruct.Probe$VH.set(seg, x); + constants$42.const$3.set(seg, x); } public static MemorySegment Probe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.Probe$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$42.const$3.get(seg.asSlice(index*sizeof())); } public static void Probe$set(MemorySegment seg, long index, MemorySegment x) { - IOCFPlugInInterfaceStruct.Probe$VH.set(seg.asSlice(index*sizeof()), x); + constants$42.const$3.set(seg.asSlice(index*sizeof()), x); } - public static Probe Probe(MemorySegment segment, SegmentScope scope) { + public static Probe Probe(MemorySegment segment, Arena scope) { return Probe.ofAddress(Probe$get(segment), scope); } - static final FunctionDescriptor Start$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle Start$MH = RuntimeHelper.downcallHandle( - IOCFPlugInInterfaceStruct.Start$FUNC - ); /** * {@snippet : * IOReturn (*Start)(void*,CFDictionaryRef,io_service_t); @@ -399,14 +328,14 @@ public static Probe Probe(MemorySegment segment, SegmentScope scope) { public interface Start { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, int _x2); - static MemorySegment allocate(Start fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(Start.class, fi, IOCFPlugInInterfaceStruct.Start$FUNC, scope); + static MemorySegment allocate(Start fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$42.const$5, fi, constants$42.const$4, scope); } - static Start ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static Start ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, int __x2) -> { try { - return (int)IOCFPlugInInterfaceStruct.Start$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)constants$43.const$0.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -414,9 +343,8 @@ static Start ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle Start$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Start")); public static VarHandle Start$VH() { - return IOCFPlugInInterfaceStruct.Start$VH; + return constants$43.const$1; } /** * Getter for field: @@ -425,7 +353,7 @@ static Start ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment Start$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.Start$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$43.const$1.get(seg); } /** * Setter for field: @@ -434,23 +362,17 @@ static Start ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void Start$set(MemorySegment seg, MemorySegment x) { - IOCFPlugInInterfaceStruct.Start$VH.set(seg, x); + constants$43.const$1.set(seg, x); } public static MemorySegment Start$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.Start$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$43.const$1.get(seg.asSlice(index*sizeof())); } public static void Start$set(MemorySegment seg, long index, MemorySegment x) { - IOCFPlugInInterfaceStruct.Start$VH.set(seg.asSlice(index*sizeof()), x); + constants$43.const$1.set(seg.asSlice(index*sizeof()), x); } - public static Start Start(MemorySegment segment, SegmentScope scope) { + public static Start Start(MemorySegment segment, Arena scope) { return Start.ofAddress(Start$get(segment), scope); } - static final FunctionDescriptor Stop$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle Stop$MH = RuntimeHelper.downcallHandle( - IOCFPlugInInterfaceStruct.Stop$FUNC - ); /** * {@snippet : * IOReturn (*Stop)(void*); @@ -459,14 +381,14 @@ public static Start Start(MemorySegment segment, SegmentScope scope) { public interface Stop { int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(Stop fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(Stop.class, fi, IOCFPlugInInterfaceStruct.Stop$FUNC, scope); + static MemorySegment allocate(Stop fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$43.const$2, fi, constants$5.const$5, scope); } - static Stop ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static Stop ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOCFPlugInInterfaceStruct.Stop$MH.invokeExact(symbol, __x0); + return (int)constants$6.const$1.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -474,9 +396,8 @@ static Stop ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle Stop$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Stop")); public static VarHandle Stop$VH() { - return IOCFPlugInInterfaceStruct.Stop$VH; + return constants$43.const$3; } /** * Getter for field: @@ -485,7 +406,7 @@ static Stop ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment Stop$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.Stop$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$43.const$3.get(seg); } /** * Setter for field: @@ -494,15 +415,15 @@ static Stop ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void Stop$set(MemorySegment seg, MemorySegment x) { - IOCFPlugInInterfaceStruct.Stop$VH.set(seg, x); + constants$43.const$3.set(seg, x); } public static MemorySegment Stop$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOCFPlugInInterfaceStruct.Stop$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$43.const$3.get(seg.asSlice(index*sizeof())); } public static void Stop$set(MemorySegment seg, long index, MemorySegment x) { - IOCFPlugInInterfaceStruct.Stop$VH.set(seg.asSlice(index*sizeof()), x); + constants$43.const$3.set(seg.asSlice(index*sizeof()), x); } - public static Stop Stop(MemorySegment segment, SegmentScope scope) { + public static Stop Stop(MemorySegment segment, Arena scope) { return Stop.ofAddress(Stop$get(segment), scope); } public static long sizeof() { return $LAYOUT().byteSize(); } @@ -510,7 +431,7 @@ public static Stop Stop(MemorySegment segment, SegmentScope scope) { public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java index 5044aeac..f03e1d08 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java @@ -2,6 +2,7 @@ package net.codecrete.usb.macos.gen.iokit; +import java.lang.foreign.AddressLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; @@ -10,14 +11,14 @@ import static java.lang.foreign.ValueLayout.*; public class IOKit { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfLong C_LONG = JAVA_LONG; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; /** * {@snippet : * enum .kIOUSBFindInterfaceDontCare = 65535; @@ -43,13 +44,13 @@ public static int kUSBReEnumerateReleaseDeviceMask() { return (int)536870912L; } public static MemoryLayout kCFRunLoopDefaultMode$LAYOUT() { - return constants$0.kCFRunLoopDefaultMode$LAYOUT; + return RuntimeHelper.POINTER; } public static VarHandle kCFRunLoopDefaultMode$VH() { - return constants$0.kCFRunLoopDefaultMode$VH; + return constants$2.const$1; } public static MemorySegment kCFRunLoopDefaultMode$SEGMENT() { - return RuntimeHelper.requireNonNull(constants$0.kCFRunLoopDefaultMode$SEGMENT,"kCFRunLoopDefaultMode"); + return RuntimeHelper.requireNonNull(constants$2.const$2,"kCFRunLoopDefaultMode"); } /** * Getter for variable: @@ -58,7 +59,7 @@ public static int kUSBReEnumerateReleaseDeviceMask() { * } */ public static MemorySegment kCFRunLoopDefaultMode$get() { - return (java.lang.foreign.MemorySegment) constants$0.kCFRunLoopDefaultMode$VH.get(RuntimeHelper.requireNonNull(constants$0.kCFRunLoopDefaultMode$SEGMENT, "kCFRunLoopDefaultMode")); + return (java.lang.foreign.MemorySegment) constants$2.const$1.get(RuntimeHelper.requireNonNull(constants$2.const$2, "kCFRunLoopDefaultMode")); } /** * Setter for variable: @@ -67,16 +68,16 @@ public static int kUSBReEnumerateReleaseDeviceMask() { * } */ public static void kCFRunLoopDefaultMode$set(MemorySegment x) { - constants$0.kCFRunLoopDefaultMode$VH.set(RuntimeHelper.requireNonNull(constants$0.kCFRunLoopDefaultMode$SEGMENT, "kCFRunLoopDefaultMode"), x); + constants$2.const$1.set(RuntimeHelper.requireNonNull(constants$2.const$2, "kCFRunLoopDefaultMode"), x); } public static MemoryLayout kIOMasterPortDefault$LAYOUT() { - return constants$0.kIOMasterPortDefault$LAYOUT; + return JAVA_INT; } public static VarHandle kIOMasterPortDefault$VH() { - return constants$0.kIOMasterPortDefault$VH; + return constants$2.const$3; } public static MemorySegment kIOMasterPortDefault$SEGMENT() { - return RuntimeHelper.requireNonNull(constants$0.kIOMasterPortDefault$SEGMENT,"kIOMasterPortDefault"); + return RuntimeHelper.requireNonNull(constants$2.const$4,"kIOMasterPortDefault"); } /** * Getter for variable: @@ -85,7 +86,7 @@ public static int kUSBReEnumerateReleaseDeviceMask() { * } */ public static int kIOMasterPortDefault$get() { - return (int) constants$0.kIOMasterPortDefault$VH.get(RuntimeHelper.requireNonNull(constants$0.kIOMasterPortDefault$SEGMENT, "kIOMasterPortDefault")); + return (int) constants$2.const$3.get(RuntimeHelper.requireNonNull(constants$2.const$4, "kIOMasterPortDefault")); } /** * Setter for variable: @@ -94,10 +95,10 @@ public static int kUSBReEnumerateReleaseDeviceMask() { * } */ public static void kIOMasterPortDefault$set(int x) { - constants$0.kIOMasterPortDefault$VH.set(RuntimeHelper.requireNonNull(constants$0.kIOMasterPortDefault$SEGMENT, "kIOMasterPortDefault"), x); + constants$2.const$3.set(RuntimeHelper.requireNonNull(constants$2.const$4, "kIOMasterPortDefault"), x); } public static MethodHandle IONotificationPortCreate$MH() { - return RuntimeHelper.requireNonNull(constants$0.IONotificationPortCreate$MH,"IONotificationPortCreate"); + return RuntimeHelper.requireNonNull(constants$2.const$6,"IONotificationPortCreate"); } /** * {@snippet : @@ -113,7 +114,7 @@ public static MemorySegment IONotificationPortCreate(int mainPort) { } } public static MethodHandle IONotificationPortGetRunLoopSource$MH() { - return RuntimeHelper.requireNonNull(constants$0.IONotificationPortGetRunLoopSource$MH,"IONotificationPortGetRunLoopSource"); + return RuntimeHelper.requireNonNull(constants$3.const$1,"IONotificationPortGetRunLoopSource"); } /** * {@snippet : @@ -129,7 +130,7 @@ public static MemorySegment IONotificationPortGetRunLoopSource(MemorySegment not } } public static MethodHandle IOObjectRelease$MH() { - return RuntimeHelper.requireNonNull(constants$0.IOObjectRelease$MH,"IOObjectRelease"); + return RuntimeHelper.requireNonNull(constants$3.const$3,"IOObjectRelease"); } /** * {@snippet : @@ -145,7 +146,7 @@ public static int IOObjectRelease(int object) { } } public static MethodHandle IOIteratorNext$MH() { - return RuntimeHelper.requireNonNull(constants$0.IOIteratorNext$MH,"IOIteratorNext"); + return RuntimeHelper.requireNonNull(constants$3.const$4,"IOIteratorNext"); } /** * {@snippet : @@ -161,7 +162,7 @@ public static int IOIteratorNext(int iterator) { } } public static MethodHandle IOServiceAddMatchingNotification$MH() { - return RuntimeHelper.requireNonNull(constants$1.IOServiceAddMatchingNotification$MH,"IOServiceAddMatchingNotification"); + return RuntimeHelper.requireNonNull(constants$3.const$6,"IOServiceAddMatchingNotification"); } /** * {@snippet : @@ -177,7 +178,7 @@ public static int IOServiceAddMatchingNotification(MemorySegment notifyPort, Mem } } public static MethodHandle IORegistryEntryGetRegistryEntryID$MH() { - return RuntimeHelper.requireNonNull(constants$1.IORegistryEntryGetRegistryEntryID$MH,"IORegistryEntryGetRegistryEntryID"); + return RuntimeHelper.requireNonNull(constants$4.const$1,"IORegistryEntryGetRegistryEntryID"); } /** * {@snippet : @@ -193,7 +194,7 @@ public static int IORegistryEntryGetRegistryEntryID(int entry, MemorySegment ent } } public static MethodHandle IORegistryEntryCreateCFProperty$MH() { - return RuntimeHelper.requireNonNull(constants$1.IORegistryEntryCreateCFProperty$MH,"IORegistryEntryCreateCFProperty"); + return RuntimeHelper.requireNonNull(constants$4.const$3,"IORegistryEntryCreateCFProperty"); } /** * {@snippet : @@ -209,7 +210,7 @@ public static MemorySegment IORegistryEntryCreateCFProperty(int entry, MemorySeg } } public static MethodHandle IOServiceMatching$MH() { - return RuntimeHelper.requireNonNull(constants$1.IOServiceMatching$MH,"IOServiceMatching"); + return RuntimeHelper.requireNonNull(constants$4.const$4,"IOServiceMatching"); } /** * {@snippet : @@ -225,7 +226,7 @@ public static MemorySegment IOServiceMatching(MemorySegment name) { } } public static MethodHandle IOCreatePlugInInterfaceForService$MH() { - return RuntimeHelper.requireNonNull(constants$1.IOCreatePlugInInterfaceForService$MH,"IOCreatePlugInInterfaceForService"); + return RuntimeHelper.requireNonNull(constants$43.const$5,"IOCreatePlugInInterfaceForService"); } /** * {@snippet : @@ -278,7 +279,7 @@ public static int kIOUSBTransactionTimeout() { * } */ public static MemorySegment kIOFirstMatchNotification() { - return constants$1.kIOFirstMatchNotification$SEGMENT; + return constants$44.const$0; } /** * {@snippet : @@ -286,7 +287,7 @@ public static MemorySegment kIOFirstMatchNotification() { * } */ public static MemorySegment kIOTerminatedNotification() { - return constants$2.kIOTerminatedNotification$SEGMENT; + return constants$44.const$1; } /** * {@snippet : @@ -294,7 +295,7 @@ public static MemorySegment kIOTerminatedNotification() { * } */ public static MemorySegment kIOUSBDeviceClassName() { - return constants$2.kIOUSBDeviceClassName$SEGMENT; + return constants$44.const$2; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java index 17780c2f..ae3953ce 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java @@ -2,7 +2,10 @@ package net.codecrete.usb.macos.gen.iokit; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -19,22 +22,11 @@ */ public class IOUSBDevRequest { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("bmRequestType"), - Constants$root.C_CHAR$LAYOUT.withName("bRequest"), - Constants$root.C_SHORT$LAYOUT.withName("wValue"), - Constants$root.C_SHORT$LAYOUT.withName("wIndex"), - Constants$root.C_SHORT$LAYOUT.withName("wLength"), - Constants$root.C_POINTER$LAYOUT.withName("pData"), - Constants$root.C_INT$LAYOUT.withName("wLenDone"), - MemoryLayout.paddingLayout(32) - ); public static MemoryLayout $LAYOUT() { - return IOUSBDevRequest.$struct$LAYOUT; + return constants$0.const$0; } - static final VarHandle bmRequestType$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("bmRequestType")); public static VarHandle bmRequestType$VH() { - return IOUSBDevRequest.bmRequestType$VH; + return constants$0.const$1; } /** * Getter for field: @@ -43,7 +35,7 @@ public class IOUSBDevRequest { * } */ public static byte bmRequestType$get(MemorySegment seg) { - return (byte)IOUSBDevRequest.bmRequestType$VH.get(seg); + return (byte)constants$0.const$1.get(seg); } /** * Setter for field: @@ -52,17 +44,16 @@ public class IOUSBDevRequest { * } */ public static void bmRequestType$set(MemorySegment seg, byte x) { - IOUSBDevRequest.bmRequestType$VH.set(seg, x); + constants$0.const$1.set(seg, x); } public static byte bmRequestType$get(MemorySegment seg, long index) { - return (byte)IOUSBDevRequest.bmRequestType$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$0.const$1.get(seg.asSlice(index*sizeof())); } public static void bmRequestType$set(MemorySegment seg, long index, byte x) { - IOUSBDevRequest.bmRequestType$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$1.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle bRequest$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("bRequest")); public static VarHandle bRequest$VH() { - return IOUSBDevRequest.bRequest$VH; + return constants$0.const$2; } /** * Getter for field: @@ -71,7 +62,7 @@ public class IOUSBDevRequest { * } */ public static byte bRequest$get(MemorySegment seg) { - return (byte)IOUSBDevRequest.bRequest$VH.get(seg); + return (byte)constants$0.const$2.get(seg); } /** * Setter for field: @@ -80,17 +71,16 @@ public class IOUSBDevRequest { * } */ public static void bRequest$set(MemorySegment seg, byte x) { - IOUSBDevRequest.bRequest$VH.set(seg, x); + constants$0.const$2.set(seg, x); } public static byte bRequest$get(MemorySegment seg, long index) { - return (byte)IOUSBDevRequest.bRequest$VH.get(seg.asSlice(index*sizeof())); + return (byte)constants$0.const$2.get(seg.asSlice(index*sizeof())); } public static void bRequest$set(MemorySegment seg, long index, byte x) { - IOUSBDevRequest.bRequest$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$2.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle wValue$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("wValue")); public static VarHandle wValue$VH() { - return IOUSBDevRequest.wValue$VH; + return constants$0.const$3; } /** * Getter for field: @@ -99,7 +89,7 @@ public class IOUSBDevRequest { * } */ public static short wValue$get(MemorySegment seg) { - return (short)IOUSBDevRequest.wValue$VH.get(seg); + return (short)constants$0.const$3.get(seg); } /** * Setter for field: @@ -108,17 +98,16 @@ public class IOUSBDevRequest { * } */ public static void wValue$set(MemorySegment seg, short x) { - IOUSBDevRequest.wValue$VH.set(seg, x); + constants$0.const$3.set(seg, x); } public static short wValue$get(MemorySegment seg, long index) { - return (short)IOUSBDevRequest.wValue$VH.get(seg.asSlice(index*sizeof())); + return (short)constants$0.const$3.get(seg.asSlice(index*sizeof())); } public static void wValue$set(MemorySegment seg, long index, short x) { - IOUSBDevRequest.wValue$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$3.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle wIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("wIndex")); public static VarHandle wIndex$VH() { - return IOUSBDevRequest.wIndex$VH; + return constants$0.const$4; } /** * Getter for field: @@ -127,7 +116,7 @@ public class IOUSBDevRequest { * } */ public static short wIndex$get(MemorySegment seg) { - return (short)IOUSBDevRequest.wIndex$VH.get(seg); + return (short)constants$0.const$4.get(seg); } /** * Setter for field: @@ -136,17 +125,16 @@ public class IOUSBDevRequest { * } */ public static void wIndex$set(MemorySegment seg, short x) { - IOUSBDevRequest.wIndex$VH.set(seg, x); + constants$0.const$4.set(seg, x); } public static short wIndex$get(MemorySegment seg, long index) { - return (short)IOUSBDevRequest.wIndex$VH.get(seg.asSlice(index*sizeof())); + return (short)constants$0.const$4.get(seg.asSlice(index*sizeof())); } public static void wIndex$set(MemorySegment seg, long index, short x) { - IOUSBDevRequest.wIndex$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$4.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle wLength$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("wLength")); public static VarHandle wLength$VH() { - return IOUSBDevRequest.wLength$VH; + return constants$0.const$5; } /** * Getter for field: @@ -155,7 +143,7 @@ public class IOUSBDevRequest { * } */ public static short wLength$get(MemorySegment seg) { - return (short)IOUSBDevRequest.wLength$VH.get(seg); + return (short)constants$0.const$5.get(seg); } /** * Setter for field: @@ -164,17 +152,16 @@ public class IOUSBDevRequest { * } */ public static void wLength$set(MemorySegment seg, short x) { - IOUSBDevRequest.wLength$VH.set(seg, x); + constants$0.const$5.set(seg, x); } public static short wLength$get(MemorySegment seg, long index) { - return (short)IOUSBDevRequest.wLength$VH.get(seg.asSlice(index*sizeof())); + return (short)constants$0.const$5.get(seg.asSlice(index*sizeof())); } public static void wLength$set(MemorySegment seg, long index, short x) { - IOUSBDevRequest.wLength$VH.set(seg.asSlice(index*sizeof()), x); + constants$0.const$5.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle pData$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("pData")); public static VarHandle pData$VH() { - return IOUSBDevRequest.pData$VH; + return constants$1.const$0; } /** * Getter for field: @@ -183,7 +170,7 @@ public class IOUSBDevRequest { * } */ public static MemorySegment pData$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDevRequest.pData$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$1.const$0.get(seg); } /** * Setter for field: @@ -192,17 +179,16 @@ public class IOUSBDevRequest { * } */ public static void pData$set(MemorySegment seg, MemorySegment x) { - IOUSBDevRequest.pData$VH.set(seg, x); + constants$1.const$0.set(seg, x); } public static MemorySegment pData$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDevRequest.pData$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$1.const$0.get(seg.asSlice(index*sizeof())); } public static void pData$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDevRequest.pData$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$0.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle wLenDone$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("wLenDone")); public static VarHandle wLenDone$VH() { - return IOUSBDevRequest.wLenDone$VH; + return constants$1.const$1; } /** * Getter for field: @@ -211,7 +197,7 @@ public class IOUSBDevRequest { * } */ public static int wLenDone$get(MemorySegment seg) { - return (int)IOUSBDevRequest.wLenDone$VH.get(seg); + return (int)constants$1.const$1.get(seg); } /** * Setter for field: @@ -220,20 +206,20 @@ public class IOUSBDevRequest { * } */ public static void wLenDone$set(MemorySegment seg, int x) { - IOUSBDevRequest.wLenDone$VH.set(seg, x); + constants$1.const$1.set(seg, x); } public static int wLenDone$get(MemorySegment seg, long index) { - return (int)IOUSBDevRequest.wLenDone$VH.get(seg.asSlice(index*sizeof())); + return (int)constants$1.const$1.get(seg.asSlice(index*sizeof())); } public static void wLenDone$set(MemorySegment seg, long index, int x) { - IOUSBDevRequest.wLenDone$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$1.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java index fef575c0..ad8d79c2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java @@ -2,8 +2,10 @@ package net.codecrete.usb.macos.gen.iokit; -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -51,52 +53,11 @@ */ public class IOUSBDeviceStruct187 { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_POINTER$LAYOUT.withName("_reserved"), - Constants$root.C_POINTER$LAYOUT.withName("QueryInterface"), - Constants$root.C_POINTER$LAYOUT.withName("AddRef"), - Constants$root.C_POINTER$LAYOUT.withName("Release"), - Constants$root.C_POINTER$LAYOUT.withName("CreateDeviceAsyncEventSource"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceAsyncEventSource"), - Constants$root.C_POINTER$LAYOUT.withName("CreateDeviceAsyncPort"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceAsyncPort"), - Constants$root.C_POINTER$LAYOUT.withName("USBDeviceOpen"), - Constants$root.C_POINTER$LAYOUT.withName("USBDeviceClose"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceClass"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceSubClass"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceProtocol"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceVendor"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceProduct"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceReleaseNumber"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceAddress"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceBusPowerAvailable"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceSpeed"), - Constants$root.C_POINTER$LAYOUT.withName("GetNumberOfConfigurations"), - Constants$root.C_POINTER$LAYOUT.withName("GetLocationID"), - Constants$root.C_POINTER$LAYOUT.withName("GetConfigurationDescriptorPtr"), - Constants$root.C_POINTER$LAYOUT.withName("GetConfiguration"), - Constants$root.C_POINTER$LAYOUT.withName("SetConfiguration"), - Constants$root.C_POINTER$LAYOUT.withName("GetBusFrameNumber"), - Constants$root.C_POINTER$LAYOUT.withName("ResetDevice"), - Constants$root.C_POINTER$LAYOUT.withName("DeviceRequest"), - Constants$root.C_POINTER$LAYOUT.withName("DeviceRequestAsync"), - Constants$root.C_POINTER$LAYOUT.withName("CreateInterfaceIterator"), - Constants$root.C_POINTER$LAYOUT.withName("USBDeviceOpenSeize"), - Constants$root.C_POINTER$LAYOUT.withName("DeviceRequestTO"), - Constants$root.C_POINTER$LAYOUT.withName("DeviceRequestAsyncTO"), - Constants$root.C_POINTER$LAYOUT.withName("USBDeviceSuspend"), - Constants$root.C_POINTER$LAYOUT.withName("USBDeviceAbortPipeZero"), - Constants$root.C_POINTER$LAYOUT.withName("USBGetManufacturerStringIndex"), - Constants$root.C_POINTER$LAYOUT.withName("USBGetProductStringIndex"), - Constants$root.C_POINTER$LAYOUT.withName("USBGetSerialNumberStringIndex"), - Constants$root.C_POINTER$LAYOUT.withName("USBDeviceReEnumerate") - ).withName("IOUSBDeviceStruct187"); public static MemoryLayout $LAYOUT() { - return IOUSBDeviceStruct187.$struct$LAYOUT; + return constants$4.const$5; } - static final VarHandle _reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("_reserved")); public static VarHandle _reserved$VH() { - return IOUSBDeviceStruct187._reserved$VH; + return constants$5.const$0; } /** * Getter for field: @@ -105,7 +66,7 @@ public class IOUSBDeviceStruct187 { * } */ public static MemorySegment _reserved$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187._reserved$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$5.const$0.get(seg); } /** * Setter for field: @@ -114,39 +75,14 @@ public class IOUSBDeviceStruct187 { * } */ public static void _reserved$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187._reserved$VH.set(seg, x); + constants$5.const$0.set(seg, x); } public static MemorySegment _reserved$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187._reserved$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$5.const$0.get(seg.asSlice(index*sizeof())); } public static void _reserved$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187._reserved$VH.set(seg.asSlice(index*sizeof()), x); - } - static final FunctionDescriptor QueryInterface$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("byte0"), - Constants$root.C_CHAR$LAYOUT.withName("byte1"), - Constants$root.C_CHAR$LAYOUT.withName("byte2"), - Constants$root.C_CHAR$LAYOUT.withName("byte3"), - Constants$root.C_CHAR$LAYOUT.withName("byte4"), - Constants$root.C_CHAR$LAYOUT.withName("byte5"), - Constants$root.C_CHAR$LAYOUT.withName("byte6"), - Constants$root.C_CHAR$LAYOUT.withName("byte7"), - Constants$root.C_CHAR$LAYOUT.withName("byte8"), - Constants$root.C_CHAR$LAYOUT.withName("byte9"), - Constants$root.C_CHAR$LAYOUT.withName("byte10"), - Constants$root.C_CHAR$LAYOUT.withName("byte11"), - Constants$root.C_CHAR$LAYOUT.withName("byte12"), - Constants$root.C_CHAR$LAYOUT.withName("byte13"), - Constants$root.C_CHAR$LAYOUT.withName("byte14"), - Constants$root.C_CHAR$LAYOUT.withName("byte15") - ), - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle QueryInterface$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.QueryInterface$FUNC - ); + constants$5.const$0.set(seg.asSlice(index*sizeof()), x); + } /** * {@snippet : * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); @@ -155,14 +91,14 @@ public class IOUSBDeviceStruct187 { public interface QueryInterface { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(QueryInterface fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOUSBDeviceStruct187.QueryInterface$FUNC, scope); + static MemorySegment allocate(QueryInterface fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$5.const$2, fi, constants$5.const$1, scope); } - static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static QueryInterface ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBDeviceStruct187.QueryInterface$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)constants$5.const$3.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -170,9 +106,8 @@ static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle QueryInterface$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("QueryInterface")); public static VarHandle QueryInterface$VH() { - return IOUSBDeviceStruct187.QueryInterface$VH; + return constants$5.const$4; } /** * Getter for field: @@ -181,7 +116,7 @@ static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment QueryInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.QueryInterface$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$5.const$4.get(seg); } /** * Setter for field: @@ -190,23 +125,17 @@ static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void QueryInterface$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.QueryInterface$VH.set(seg, x); + constants$5.const$4.set(seg, x); } public static MemorySegment QueryInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.QueryInterface$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$5.const$4.get(seg.asSlice(index*sizeof())); } public static void QueryInterface$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.QueryInterface$VH.set(seg.asSlice(index*sizeof()), x); + constants$5.const$4.set(seg.asSlice(index*sizeof()), x); } - public static QueryInterface QueryInterface(MemorySegment segment, SegmentScope scope) { + public static QueryInterface QueryInterface(MemorySegment segment, Arena scope) { return QueryInterface.ofAddress(QueryInterface$get(segment), scope); } - static final FunctionDescriptor AddRef$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle AddRef$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.AddRef$FUNC - ); /** * {@snippet : * ULONG (*AddRef)(void*); @@ -215,14 +144,14 @@ public static QueryInterface QueryInterface(MemorySegment segment, SegmentScope public interface AddRef { int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(AddRef fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(AddRef.class, fi, IOUSBDeviceStruct187.AddRef$FUNC, scope); + static MemorySegment allocate(AddRef fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$6.const$0, fi, constants$5.const$5, scope); } - static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static AddRef ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct187.AddRef$MH.invokeExact(symbol, __x0); + return (int)constants$6.const$1.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -230,9 +159,8 @@ static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle AddRef$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AddRef")); public static VarHandle AddRef$VH() { - return IOUSBDeviceStruct187.AddRef$VH; + return constants$6.const$2; } /** * Getter for field: @@ -241,7 +169,7 @@ static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment AddRef$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.AddRef$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$6.const$2.get(seg); } /** * Setter for field: @@ -250,23 +178,17 @@ static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void AddRef$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.AddRef$VH.set(seg, x); + constants$6.const$2.set(seg, x); } public static MemorySegment AddRef$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.AddRef$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$6.const$2.get(seg.asSlice(index*sizeof())); } public static void AddRef$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.AddRef$VH.set(seg.asSlice(index*sizeof()), x); + constants$6.const$2.set(seg.asSlice(index*sizeof()), x); } - public static AddRef AddRef(MemorySegment segment, SegmentScope scope) { + public static AddRef AddRef(MemorySegment segment, Arena scope) { return AddRef.ofAddress(AddRef$get(segment), scope); } - static final FunctionDescriptor Release$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle Release$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.Release$FUNC - ); /** * {@snippet : * ULONG (*Release)(void*); @@ -275,14 +197,14 @@ public static AddRef AddRef(MemorySegment segment, SegmentScope scope) { public interface Release { int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(Release fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(Release.class, fi, IOUSBDeviceStruct187.Release$FUNC, scope); + static MemorySegment allocate(Release fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$6.const$3, fi, constants$5.const$5, scope); } - static Release ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static Release ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct187.Release$MH.invokeExact(symbol, __x0); + return (int)constants$6.const$1.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -290,9 +212,8 @@ static Release ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle Release$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Release")); public static VarHandle Release$VH() { - return IOUSBDeviceStruct187.Release$VH; + return constants$6.const$4; } /** * Getter for field: @@ -301,7 +222,7 @@ static Release ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment Release$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.Release$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$6.const$4.get(seg); } /** * Setter for field: @@ -310,24 +231,17 @@ static Release ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void Release$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.Release$VH.set(seg, x); + constants$6.const$4.set(seg, x); } public static MemorySegment Release$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.Release$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$6.const$4.get(seg.asSlice(index*sizeof())); } public static void Release$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.Release$VH.set(seg.asSlice(index*sizeof()), x); + constants$6.const$4.set(seg.asSlice(index*sizeof()), x); } - public static Release Release(MemorySegment segment, SegmentScope scope) { + public static Release Release(MemorySegment segment, Arena scope) { return Release.ofAddress(Release$get(segment), scope); } - static final FunctionDescriptor CreateDeviceAsyncEventSource$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle CreateDeviceAsyncEventSource$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.CreateDeviceAsyncEventSource$FUNC - ); /** * {@snippet : * IOReturn (*CreateDeviceAsyncEventSource)(void*,CFRunLoopSourceRef*); @@ -336,14 +250,14 @@ public static Release Release(MemorySegment segment, SegmentScope scope) { public interface CreateDeviceAsyncEventSource { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(CreateDeviceAsyncEventSource fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(CreateDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct187.CreateDeviceAsyncEventSource$FUNC, scope); + static MemorySegment allocate(CreateDeviceAsyncEventSource fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$7.const$0, fi, constants$6.const$5, scope); } - static CreateDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static CreateDeviceAsyncEventSource ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.CreateDeviceAsyncEventSource$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -351,9 +265,8 @@ static CreateDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope s } } - static final VarHandle CreateDeviceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateDeviceAsyncEventSource")); public static VarHandle CreateDeviceAsyncEventSource$VH() { - return IOUSBDeviceStruct187.CreateDeviceAsyncEventSource$VH; + return constants$7.const$2; } /** * Getter for field: @@ -362,7 +275,7 @@ static CreateDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope s * } */ public static MemorySegment CreateDeviceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.CreateDeviceAsyncEventSource$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$7.const$2.get(seg); } /** * Setter for field: @@ -371,23 +284,17 @@ static CreateDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope s * } */ public static void CreateDeviceAsyncEventSource$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.CreateDeviceAsyncEventSource$VH.set(seg, x); + constants$7.const$2.set(seg, x); } public static MemorySegment CreateDeviceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.CreateDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$7.const$2.get(seg.asSlice(index*sizeof())); } public static void CreateDeviceAsyncEventSource$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.CreateDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); + constants$7.const$2.set(seg.asSlice(index*sizeof()), x); } - public static CreateDeviceAsyncEventSource CreateDeviceAsyncEventSource(MemorySegment segment, SegmentScope scope) { + public static CreateDeviceAsyncEventSource CreateDeviceAsyncEventSource(MemorySegment segment, Arena scope) { return CreateDeviceAsyncEventSource.ofAddress(CreateDeviceAsyncEventSource$get(segment), scope); } - static final FunctionDescriptor GetDeviceAsyncEventSource$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceAsyncEventSource$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.GetDeviceAsyncEventSource$FUNC - ); /** * {@snippet : * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void*); @@ -396,14 +303,14 @@ public static CreateDeviceAsyncEventSource CreateDeviceAsyncEventSource(MemorySe public interface GetDeviceAsyncEventSource { java.lang.foreign.MemorySegment apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(GetDeviceAsyncEventSource fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceAsyncEventSource.class, fi, IOUSBDeviceStruct187.GetDeviceAsyncEventSource$FUNC, scope); + static MemorySegment allocate(GetDeviceAsyncEventSource fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$7.const$3, fi, constants$3.const$0, scope); } - static GetDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetDeviceAsyncEventSource ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceAsyncEventSource$MH.invokeExact(symbol, __x0); + return (java.lang.foreign.MemorySegment)constants$7.const$4.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -411,9 +318,8 @@ static GetDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scop } } - static final VarHandle GetDeviceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncEventSource")); public static VarHandle GetDeviceAsyncEventSource$VH() { - return IOUSBDeviceStruct187.GetDeviceAsyncEventSource$VH; + return constants$7.const$5; } /** * Getter for field: @@ -422,7 +328,7 @@ static GetDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scop * } */ public static MemorySegment GetDeviceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceAsyncEventSource$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$7.const$5.get(seg); } /** * Setter for field: @@ -431,24 +337,17 @@ static GetDeviceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scop * } */ public static void GetDeviceAsyncEventSource$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceAsyncEventSource$VH.set(seg, x); + constants$7.const$5.set(seg, x); } public static MemorySegment GetDeviceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$7.const$5.get(seg.asSlice(index*sizeof())); } public static void GetDeviceAsyncEventSource$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); + constants$7.const$5.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceAsyncEventSource GetDeviceAsyncEventSource(MemorySegment segment, SegmentScope scope) { + public static GetDeviceAsyncEventSource GetDeviceAsyncEventSource(MemorySegment segment, Arena scope) { return GetDeviceAsyncEventSource.ofAddress(GetDeviceAsyncEventSource$get(segment), scope); } - static final FunctionDescriptor CreateDeviceAsyncPort$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle CreateDeviceAsyncPort$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.CreateDeviceAsyncPort$FUNC - ); /** * {@snippet : * IOReturn (*CreateDeviceAsyncPort)(void*,mach_port_t*); @@ -457,14 +356,14 @@ public static GetDeviceAsyncEventSource GetDeviceAsyncEventSource(MemorySegment public interface CreateDeviceAsyncPort { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(CreateDeviceAsyncPort fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(CreateDeviceAsyncPort.class, fi, IOUSBDeviceStruct187.CreateDeviceAsyncPort$FUNC, scope); + static MemorySegment allocate(CreateDeviceAsyncPort fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$8.const$0, fi, constants$6.const$5, scope); } - static CreateDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static CreateDeviceAsyncPort ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.CreateDeviceAsyncPort$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -472,9 +371,8 @@ static CreateDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle CreateDeviceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateDeviceAsyncPort")); public static VarHandle CreateDeviceAsyncPort$VH() { - return IOUSBDeviceStruct187.CreateDeviceAsyncPort$VH; + return constants$8.const$1; } /** * Getter for field: @@ -483,7 +381,7 @@ static CreateDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment CreateDeviceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.CreateDeviceAsyncPort$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$8.const$1.get(seg); } /** * Setter for field: @@ -492,23 +390,17 @@ static CreateDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void CreateDeviceAsyncPort$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.CreateDeviceAsyncPort$VH.set(seg, x); + constants$8.const$1.set(seg, x); } public static MemorySegment CreateDeviceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.CreateDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$8.const$1.get(seg.asSlice(index*sizeof())); } public static void CreateDeviceAsyncPort$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.CreateDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); + constants$8.const$1.set(seg.asSlice(index*sizeof()), x); } - public static CreateDeviceAsyncPort CreateDeviceAsyncPort(MemorySegment segment, SegmentScope scope) { + public static CreateDeviceAsyncPort CreateDeviceAsyncPort(MemorySegment segment, Arena scope) { return CreateDeviceAsyncPort.ofAddress(CreateDeviceAsyncPort$get(segment), scope); } - static final FunctionDescriptor GetDeviceAsyncPort$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceAsyncPort$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.GetDeviceAsyncPort$FUNC - ); /** * {@snippet : * mach_port_t (*GetDeviceAsyncPort)(void*); @@ -517,14 +409,14 @@ public static CreateDeviceAsyncPort CreateDeviceAsyncPort(MemorySegment segment, public interface GetDeviceAsyncPort { int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(GetDeviceAsyncPort fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceAsyncPort.class, fi, IOUSBDeviceStruct187.GetDeviceAsyncPort$FUNC, scope); + static MemorySegment allocate(GetDeviceAsyncPort fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$8.const$2, fi, constants$5.const$5, scope); } - static GetDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetDeviceAsyncPort ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct187.GetDeviceAsyncPort$MH.invokeExact(symbol, __x0); + return (int)constants$6.const$1.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -532,9 +424,8 @@ static GetDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetDeviceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncPort")); public static VarHandle GetDeviceAsyncPort$VH() { - return IOUSBDeviceStruct187.GetDeviceAsyncPort$VH; + return constants$8.const$3; } /** * Getter for field: @@ -543,7 +434,7 @@ static GetDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceAsyncPort$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$8.const$3.get(seg); } /** * Setter for field: @@ -552,23 +443,17 @@ static GetDeviceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceAsyncPort$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceAsyncPort$VH.set(seg, x); + constants$8.const$3.set(seg, x); } public static MemorySegment GetDeviceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$8.const$3.get(seg.asSlice(index*sizeof())); } public static void GetDeviceAsyncPort$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); + constants$8.const$3.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceAsyncPort GetDeviceAsyncPort(MemorySegment segment, SegmentScope scope) { + public static GetDeviceAsyncPort GetDeviceAsyncPort(MemorySegment segment, Arena scope) { return GetDeviceAsyncPort.ofAddress(GetDeviceAsyncPort$get(segment), scope); } - static final FunctionDescriptor USBDeviceOpen$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBDeviceOpen$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.USBDeviceOpen$FUNC - ); /** * {@snippet : * IOReturn (*USBDeviceOpen)(void*); @@ -577,14 +462,14 @@ public static GetDeviceAsyncPort GetDeviceAsyncPort(MemorySegment segment, Segme public interface USBDeviceOpen { int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(USBDeviceOpen fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBDeviceOpen.class, fi, IOUSBDeviceStruct187.USBDeviceOpen$FUNC, scope); + static MemorySegment allocate(USBDeviceOpen fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$8.const$4, fi, constants$5.const$5, scope); } - static USBDeviceOpen ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static USBDeviceOpen ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct187.USBDeviceOpen$MH.invokeExact(symbol, __x0); + return (int)constants$6.const$1.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -592,9 +477,8 @@ static USBDeviceOpen ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle USBDeviceOpen$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceOpen")); public static VarHandle USBDeviceOpen$VH() { - return IOUSBDeviceStruct187.USBDeviceOpen$VH; + return constants$8.const$5; } /** * Getter for field: @@ -603,7 +487,7 @@ static USBDeviceOpen ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment USBDeviceOpen$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceOpen$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$8.const$5.get(seg); } /** * Setter for field: @@ -612,23 +496,17 @@ static USBDeviceOpen ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void USBDeviceOpen$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.USBDeviceOpen$VH.set(seg, x); + constants$8.const$5.set(seg, x); } public static MemorySegment USBDeviceOpen$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceOpen$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$8.const$5.get(seg.asSlice(index*sizeof())); } public static void USBDeviceOpen$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.USBDeviceOpen$VH.set(seg.asSlice(index*sizeof()), x); + constants$8.const$5.set(seg.asSlice(index*sizeof()), x); } - public static USBDeviceOpen USBDeviceOpen(MemorySegment segment, SegmentScope scope) { + public static USBDeviceOpen USBDeviceOpen(MemorySegment segment, Arena scope) { return USBDeviceOpen.ofAddress(USBDeviceOpen$get(segment), scope); } - static final FunctionDescriptor USBDeviceClose$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBDeviceClose$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.USBDeviceClose$FUNC - ); /** * {@snippet : * IOReturn (*USBDeviceClose)(void*); @@ -637,14 +515,14 @@ public static USBDeviceOpen USBDeviceOpen(MemorySegment segment, SegmentScope sc public interface USBDeviceClose { int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(USBDeviceClose fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBDeviceClose.class, fi, IOUSBDeviceStruct187.USBDeviceClose$FUNC, scope); + static MemorySegment allocate(USBDeviceClose fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$9.const$0, fi, constants$5.const$5, scope); } - static USBDeviceClose ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static USBDeviceClose ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct187.USBDeviceClose$MH.invokeExact(symbol, __x0); + return (int)constants$6.const$1.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -652,9 +530,8 @@ static USBDeviceClose ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle USBDeviceClose$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceClose")); public static VarHandle USBDeviceClose$VH() { - return IOUSBDeviceStruct187.USBDeviceClose$VH; + return constants$9.const$1; } /** * Getter for field: @@ -663,7 +540,7 @@ static USBDeviceClose ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment USBDeviceClose$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceClose$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$9.const$1.get(seg); } /** * Setter for field: @@ -672,24 +549,17 @@ static USBDeviceClose ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void USBDeviceClose$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.USBDeviceClose$VH.set(seg, x); + constants$9.const$1.set(seg, x); } public static MemorySegment USBDeviceClose$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceClose$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$9.const$1.get(seg.asSlice(index*sizeof())); } public static void USBDeviceClose$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.USBDeviceClose$VH.set(seg.asSlice(index*sizeof()), x); + constants$9.const$1.set(seg.asSlice(index*sizeof()), x); } - public static USBDeviceClose USBDeviceClose(MemorySegment segment, SegmentScope scope) { + public static USBDeviceClose USBDeviceClose(MemorySegment segment, Arena scope) { return USBDeviceClose.ofAddress(USBDeviceClose$get(segment), scope); } - static final FunctionDescriptor GetDeviceClass$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceClass$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.GetDeviceClass$FUNC - ); /** * {@snippet : * IOReturn (*GetDeviceClass)(void*,UInt8*); @@ -698,14 +568,14 @@ public static USBDeviceClose USBDeviceClose(MemorySegment segment, SegmentScope public interface GetDeviceClass { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceClass fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceClass.class, fi, IOUSBDeviceStruct187.GetDeviceClass$FUNC, scope); + static MemorySegment allocate(GetDeviceClass fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$9.const$2, fi, constants$6.const$5, scope); } - static GetDeviceClass ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetDeviceClass ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.GetDeviceClass$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -713,9 +583,8 @@ static GetDeviceClass ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetDeviceClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceClass")); public static VarHandle GetDeviceClass$VH() { - return IOUSBDeviceStruct187.GetDeviceClass$VH; + return constants$9.const$3; } /** * Getter for field: @@ -724,7 +593,7 @@ static GetDeviceClass ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceClass$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceClass$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$9.const$3.get(seg); } /** * Setter for field: @@ -733,24 +602,17 @@ static GetDeviceClass ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceClass$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceClass$VH.set(seg, x); + constants$9.const$3.set(seg, x); } public static MemorySegment GetDeviceClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceClass$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$9.const$3.get(seg.asSlice(index*sizeof())); } public static void GetDeviceClass$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceClass$VH.set(seg.asSlice(index*sizeof()), x); + constants$9.const$3.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceClass GetDeviceClass(MemorySegment segment, SegmentScope scope) { + public static GetDeviceClass GetDeviceClass(MemorySegment segment, Arena scope) { return GetDeviceClass.ofAddress(GetDeviceClass$get(segment), scope); } - static final FunctionDescriptor GetDeviceSubClass$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceSubClass$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.GetDeviceSubClass$FUNC - ); /** * {@snippet : * IOReturn (*GetDeviceSubClass)(void*,UInt8*); @@ -759,14 +621,14 @@ public static GetDeviceClass GetDeviceClass(MemorySegment segment, SegmentScope public interface GetDeviceSubClass { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceSubClass fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceSubClass.class, fi, IOUSBDeviceStruct187.GetDeviceSubClass$FUNC, scope); + static MemorySegment allocate(GetDeviceSubClass fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$9.const$4, fi, constants$6.const$5, scope); } - static GetDeviceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetDeviceSubClass ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.GetDeviceSubClass$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -774,9 +636,8 @@ static GetDeviceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetDeviceSubClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceSubClass")); public static VarHandle GetDeviceSubClass$VH() { - return IOUSBDeviceStruct187.GetDeviceSubClass$VH; + return constants$9.const$5; } /** * Getter for field: @@ -785,7 +646,7 @@ static GetDeviceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceSubClass$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceSubClass$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$9.const$5.get(seg); } /** * Setter for field: @@ -794,24 +655,17 @@ static GetDeviceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceSubClass$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceSubClass$VH.set(seg, x); + constants$9.const$5.set(seg, x); } public static MemorySegment GetDeviceSubClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceSubClass$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$9.const$5.get(seg.asSlice(index*sizeof())); } public static void GetDeviceSubClass$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceSubClass$VH.set(seg.asSlice(index*sizeof()), x); + constants$9.const$5.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceSubClass GetDeviceSubClass(MemorySegment segment, SegmentScope scope) { + public static GetDeviceSubClass GetDeviceSubClass(MemorySegment segment, Arena scope) { return GetDeviceSubClass.ofAddress(GetDeviceSubClass$get(segment), scope); } - static final FunctionDescriptor GetDeviceProtocol$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceProtocol$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.GetDeviceProtocol$FUNC - ); /** * {@snippet : * IOReturn (*GetDeviceProtocol)(void*,UInt8*); @@ -820,14 +674,14 @@ public static GetDeviceSubClass GetDeviceSubClass(MemorySegment segment, Segment public interface GetDeviceProtocol { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceProtocol fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceProtocol.class, fi, IOUSBDeviceStruct187.GetDeviceProtocol$FUNC, scope); + static MemorySegment allocate(GetDeviceProtocol fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$10.const$0, fi, constants$6.const$5, scope); } - static GetDeviceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetDeviceProtocol ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.GetDeviceProtocol$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -835,9 +689,8 @@ static GetDeviceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetDeviceProtocol$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProtocol")); public static VarHandle GetDeviceProtocol$VH() { - return IOUSBDeviceStruct187.GetDeviceProtocol$VH; + return constants$10.const$1; } /** * Getter for field: @@ -846,7 +699,7 @@ static GetDeviceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceProtocol$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceProtocol$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$10.const$1.get(seg); } /** * Setter for field: @@ -855,24 +708,17 @@ static GetDeviceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceProtocol$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceProtocol$VH.set(seg, x); + constants$10.const$1.set(seg, x); } public static MemorySegment GetDeviceProtocol$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceProtocol$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$10.const$1.get(seg.asSlice(index*sizeof())); } public static void GetDeviceProtocol$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceProtocol$VH.set(seg.asSlice(index*sizeof()), x); + constants$10.const$1.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceProtocol GetDeviceProtocol(MemorySegment segment, SegmentScope scope) { + public static GetDeviceProtocol GetDeviceProtocol(MemorySegment segment, Arena scope) { return GetDeviceProtocol.ofAddress(GetDeviceProtocol$get(segment), scope); } - static final FunctionDescriptor GetDeviceVendor$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceVendor$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.GetDeviceVendor$FUNC - ); /** * {@snippet : * IOReturn (*GetDeviceVendor)(void*,UInt16*); @@ -881,14 +727,14 @@ public static GetDeviceProtocol GetDeviceProtocol(MemorySegment segment, Segment public interface GetDeviceVendor { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceVendor fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceVendor.class, fi, IOUSBDeviceStruct187.GetDeviceVendor$FUNC, scope); + static MemorySegment allocate(GetDeviceVendor fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$10.const$2, fi, constants$6.const$5, scope); } - static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetDeviceVendor ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.GetDeviceVendor$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -896,9 +742,8 @@ static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetDeviceVendor$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceVendor")); public static VarHandle GetDeviceVendor$VH() { - return IOUSBDeviceStruct187.GetDeviceVendor$VH; + return constants$10.const$3; } /** * Getter for field: @@ -907,7 +752,7 @@ static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceVendor$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceVendor$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$10.const$3.get(seg); } /** * Setter for field: @@ -916,24 +761,17 @@ static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceVendor$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceVendor$VH.set(seg, x); + constants$10.const$3.set(seg, x); } public static MemorySegment GetDeviceVendor$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceVendor$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$10.const$3.get(seg.asSlice(index*sizeof())); } public static void GetDeviceVendor$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceVendor$VH.set(seg.asSlice(index*sizeof()), x); + constants$10.const$3.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceVendor GetDeviceVendor(MemorySegment segment, SegmentScope scope) { + public static GetDeviceVendor GetDeviceVendor(MemorySegment segment, Arena scope) { return GetDeviceVendor.ofAddress(GetDeviceVendor$get(segment), scope); } - static final FunctionDescriptor GetDeviceProduct$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceProduct$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.GetDeviceProduct$FUNC - ); /** * {@snippet : * IOReturn (*GetDeviceProduct)(void*,UInt16*); @@ -942,14 +780,14 @@ public static GetDeviceVendor GetDeviceVendor(MemorySegment segment, SegmentScop public interface GetDeviceProduct { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceProduct fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceProduct.class, fi, IOUSBDeviceStruct187.GetDeviceProduct$FUNC, scope); + static MemorySegment allocate(GetDeviceProduct fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$10.const$4, fi, constants$6.const$5, scope); } - static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetDeviceProduct ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.GetDeviceProduct$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -957,9 +795,8 @@ static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetDeviceProduct$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProduct")); public static VarHandle GetDeviceProduct$VH() { - return IOUSBDeviceStruct187.GetDeviceProduct$VH; + return constants$10.const$5; } /** * Getter for field: @@ -968,7 +805,7 @@ static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceProduct$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceProduct$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$10.const$5.get(seg); } /** * Setter for field: @@ -977,24 +814,17 @@ static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceProduct$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceProduct$VH.set(seg, x); + constants$10.const$5.set(seg, x); } public static MemorySegment GetDeviceProduct$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceProduct$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$10.const$5.get(seg.asSlice(index*sizeof())); } public static void GetDeviceProduct$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceProduct$VH.set(seg.asSlice(index*sizeof()), x); + constants$10.const$5.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceProduct GetDeviceProduct(MemorySegment segment, SegmentScope scope) { + public static GetDeviceProduct GetDeviceProduct(MemorySegment segment, Arena scope) { return GetDeviceProduct.ofAddress(GetDeviceProduct$get(segment), scope); } - static final FunctionDescriptor GetDeviceReleaseNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceReleaseNumber$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.GetDeviceReleaseNumber$FUNC - ); /** * {@snippet : * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); @@ -1003,14 +833,14 @@ public static GetDeviceProduct GetDeviceProduct(MemorySegment segment, SegmentSc public interface GetDeviceReleaseNumber { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceReleaseNumber fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceReleaseNumber.class, fi, IOUSBDeviceStruct187.GetDeviceReleaseNumber$FUNC, scope); + static MemorySegment allocate(GetDeviceReleaseNumber fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$11.const$0, fi, constants$6.const$5, scope); } - static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetDeviceReleaseNumber ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.GetDeviceReleaseNumber$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1018,9 +848,8 @@ static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) } } - static final VarHandle GetDeviceReleaseNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceReleaseNumber")); public static VarHandle GetDeviceReleaseNumber$VH() { - return IOUSBDeviceStruct187.GetDeviceReleaseNumber$VH; + return constants$11.const$1; } /** * Getter for field: @@ -1029,7 +858,7 @@ static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static MemorySegment GetDeviceReleaseNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceReleaseNumber$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$11.const$1.get(seg); } /** * Setter for field: @@ -1038,24 +867,17 @@ static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static void GetDeviceReleaseNumber$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceReleaseNumber$VH.set(seg, x); + constants$11.const$1.set(seg, x); } public static MemorySegment GetDeviceReleaseNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceReleaseNumber$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$11.const$1.get(seg.asSlice(index*sizeof())); } public static void GetDeviceReleaseNumber$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceReleaseNumber$VH.set(seg.asSlice(index*sizeof()), x); + constants$11.const$1.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceReleaseNumber GetDeviceReleaseNumber(MemorySegment segment, SegmentScope scope) { + public static GetDeviceReleaseNumber GetDeviceReleaseNumber(MemorySegment segment, Arena scope) { return GetDeviceReleaseNumber.ofAddress(GetDeviceReleaseNumber$get(segment), scope); } - static final FunctionDescriptor GetDeviceAddress$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceAddress$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.GetDeviceAddress$FUNC - ); /** * {@snippet : * IOReturn (*GetDeviceAddress)(void*,USBDeviceAddress*); @@ -1064,14 +886,14 @@ public static GetDeviceReleaseNumber GetDeviceReleaseNumber(MemorySegment segmen public interface GetDeviceAddress { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceAddress fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceAddress.class, fi, IOUSBDeviceStruct187.GetDeviceAddress$FUNC, scope); + static MemorySegment allocate(GetDeviceAddress fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$11.const$2, fi, constants$6.const$5, scope); } - static GetDeviceAddress ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetDeviceAddress ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.GetDeviceAddress$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1079,9 +901,8 @@ static GetDeviceAddress ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetDeviceAddress$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAddress")); public static VarHandle GetDeviceAddress$VH() { - return IOUSBDeviceStruct187.GetDeviceAddress$VH; + return constants$11.const$3; } /** * Getter for field: @@ -1090,7 +911,7 @@ static GetDeviceAddress ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceAddress$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceAddress$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$11.const$3.get(seg); } /** * Setter for field: @@ -1099,24 +920,17 @@ static GetDeviceAddress ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceAddress$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceAddress$VH.set(seg, x); + constants$11.const$3.set(seg, x); } public static MemorySegment GetDeviceAddress$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceAddress$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$11.const$3.get(seg.asSlice(index*sizeof())); } public static void GetDeviceAddress$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceAddress$VH.set(seg.asSlice(index*sizeof()), x); + constants$11.const$3.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceAddress GetDeviceAddress(MemorySegment segment, SegmentScope scope) { + public static GetDeviceAddress GetDeviceAddress(MemorySegment segment, Arena scope) { return GetDeviceAddress.ofAddress(GetDeviceAddress$get(segment), scope); } - static final FunctionDescriptor GetDeviceBusPowerAvailable$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceBusPowerAvailable$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.GetDeviceBusPowerAvailable$FUNC - ); /** * {@snippet : * IOReturn (*GetDeviceBusPowerAvailable)(void*,UInt32*); @@ -1125,14 +939,14 @@ public static GetDeviceAddress GetDeviceAddress(MemorySegment segment, SegmentSc public interface GetDeviceBusPowerAvailable { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceBusPowerAvailable fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceBusPowerAvailable.class, fi, IOUSBDeviceStruct187.GetDeviceBusPowerAvailable$FUNC, scope); + static MemorySegment allocate(GetDeviceBusPowerAvailable fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$11.const$4, fi, constants$6.const$5, scope); } - static GetDeviceBusPowerAvailable ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetDeviceBusPowerAvailable ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.GetDeviceBusPowerAvailable$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1140,9 +954,8 @@ static GetDeviceBusPowerAvailable ofAddress(MemorySegment addr, SegmentScope sco } } - static final VarHandle GetDeviceBusPowerAvailable$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceBusPowerAvailable")); public static VarHandle GetDeviceBusPowerAvailable$VH() { - return IOUSBDeviceStruct187.GetDeviceBusPowerAvailable$VH; + return constants$11.const$5; } /** * Getter for field: @@ -1151,7 +964,7 @@ static GetDeviceBusPowerAvailable ofAddress(MemorySegment addr, SegmentScope sco * } */ public static MemorySegment GetDeviceBusPowerAvailable$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceBusPowerAvailable$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$11.const$5.get(seg); } /** * Setter for field: @@ -1160,24 +973,17 @@ static GetDeviceBusPowerAvailable ofAddress(MemorySegment addr, SegmentScope sco * } */ public static void GetDeviceBusPowerAvailable$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceBusPowerAvailable$VH.set(seg, x); + constants$11.const$5.set(seg, x); } public static MemorySegment GetDeviceBusPowerAvailable$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceBusPowerAvailable$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$11.const$5.get(seg.asSlice(index*sizeof())); } public static void GetDeviceBusPowerAvailable$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceBusPowerAvailable$VH.set(seg.asSlice(index*sizeof()), x); + constants$11.const$5.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceBusPowerAvailable GetDeviceBusPowerAvailable(MemorySegment segment, SegmentScope scope) { + public static GetDeviceBusPowerAvailable GetDeviceBusPowerAvailable(MemorySegment segment, Arena scope) { return GetDeviceBusPowerAvailable.ofAddress(GetDeviceBusPowerAvailable$get(segment), scope); } - static final FunctionDescriptor GetDeviceSpeed$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceSpeed$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.GetDeviceSpeed$FUNC - ); /** * {@snippet : * IOReturn (*GetDeviceSpeed)(void*,UInt8*); @@ -1186,14 +992,14 @@ public static GetDeviceBusPowerAvailable GetDeviceBusPowerAvailable(MemorySegmen public interface GetDeviceSpeed { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceSpeed fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceSpeed.class, fi, IOUSBDeviceStruct187.GetDeviceSpeed$FUNC, scope); + static MemorySegment allocate(GetDeviceSpeed fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$12.const$0, fi, constants$6.const$5, scope); } - static GetDeviceSpeed ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetDeviceSpeed ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.GetDeviceSpeed$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1201,9 +1007,8 @@ static GetDeviceSpeed ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetDeviceSpeed$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceSpeed")); public static VarHandle GetDeviceSpeed$VH() { - return IOUSBDeviceStruct187.GetDeviceSpeed$VH; + return constants$12.const$1; } /** * Getter for field: @@ -1212,7 +1017,7 @@ static GetDeviceSpeed ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceSpeed$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceSpeed$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$12.const$1.get(seg); } /** * Setter for field: @@ -1221,24 +1026,17 @@ static GetDeviceSpeed ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceSpeed$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceSpeed$VH.set(seg, x); + constants$12.const$1.set(seg, x); } public static MemorySegment GetDeviceSpeed$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetDeviceSpeed$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$12.const$1.get(seg.asSlice(index*sizeof())); } public static void GetDeviceSpeed$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.GetDeviceSpeed$VH.set(seg.asSlice(index*sizeof()), x); + constants$12.const$1.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceSpeed GetDeviceSpeed(MemorySegment segment, SegmentScope scope) { + public static GetDeviceSpeed GetDeviceSpeed(MemorySegment segment, Arena scope) { return GetDeviceSpeed.ofAddress(GetDeviceSpeed$get(segment), scope); } - static final FunctionDescriptor GetNumberOfConfigurations$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetNumberOfConfigurations$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.GetNumberOfConfigurations$FUNC - ); /** * {@snippet : * IOReturn (*GetNumberOfConfigurations)(void*,UInt8*); @@ -1247,14 +1045,14 @@ public static GetDeviceSpeed GetDeviceSpeed(MemorySegment segment, SegmentScope public interface GetNumberOfConfigurations { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetNumberOfConfigurations fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetNumberOfConfigurations.class, fi, IOUSBDeviceStruct187.GetNumberOfConfigurations$FUNC, scope); + static MemorySegment allocate(GetNumberOfConfigurations fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$12.const$2, fi, constants$6.const$5, scope); } - static GetNumberOfConfigurations ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetNumberOfConfigurations ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.GetNumberOfConfigurations$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1262,9 +1060,8 @@ static GetNumberOfConfigurations ofAddress(MemorySegment addr, SegmentScope scop } } - static final VarHandle GetNumberOfConfigurations$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetNumberOfConfigurations")); public static VarHandle GetNumberOfConfigurations$VH() { - return IOUSBDeviceStruct187.GetNumberOfConfigurations$VH; + return constants$12.const$3; } /** * Getter for field: @@ -1273,7 +1070,7 @@ static GetNumberOfConfigurations ofAddress(MemorySegment addr, SegmentScope scop * } */ public static MemorySegment GetNumberOfConfigurations$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetNumberOfConfigurations$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$12.const$3.get(seg); } /** * Setter for field: @@ -1282,24 +1079,17 @@ static GetNumberOfConfigurations ofAddress(MemorySegment addr, SegmentScope scop * } */ public static void GetNumberOfConfigurations$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.GetNumberOfConfigurations$VH.set(seg, x); + constants$12.const$3.set(seg, x); } public static MemorySegment GetNumberOfConfigurations$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetNumberOfConfigurations$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$12.const$3.get(seg.asSlice(index*sizeof())); } public static void GetNumberOfConfigurations$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.GetNumberOfConfigurations$VH.set(seg.asSlice(index*sizeof()), x); + constants$12.const$3.set(seg.asSlice(index*sizeof()), x); } - public static GetNumberOfConfigurations GetNumberOfConfigurations(MemorySegment segment, SegmentScope scope) { + public static GetNumberOfConfigurations GetNumberOfConfigurations(MemorySegment segment, Arena scope) { return GetNumberOfConfigurations.ofAddress(GetNumberOfConfigurations$get(segment), scope); } - static final FunctionDescriptor GetLocationID$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetLocationID$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.GetLocationID$FUNC - ); /** * {@snippet : * IOReturn (*GetLocationID)(void*,UInt32*); @@ -1308,14 +1098,14 @@ public static GetNumberOfConfigurations GetNumberOfConfigurations(MemorySegment public interface GetLocationID { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetLocationID fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetLocationID.class, fi, IOUSBDeviceStruct187.GetLocationID$FUNC, scope); + static MemorySegment allocate(GetLocationID fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$12.const$4, fi, constants$6.const$5, scope); } - static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetLocationID ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.GetLocationID$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1323,9 +1113,8 @@ static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetLocationID$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetLocationID")); public static VarHandle GetLocationID$VH() { - return IOUSBDeviceStruct187.GetLocationID$VH; + return constants$12.const$5; } /** * Getter for field: @@ -1334,7 +1123,7 @@ static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetLocationID$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetLocationID$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$12.const$5.get(seg); } /** * Setter for field: @@ -1343,25 +1132,17 @@ static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetLocationID$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.GetLocationID$VH.set(seg, x); + constants$12.const$5.set(seg, x); } public static MemorySegment GetLocationID$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetLocationID$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$12.const$5.get(seg.asSlice(index*sizeof())); } public static void GetLocationID$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.GetLocationID$VH.set(seg.asSlice(index*sizeof()), x); + constants$12.const$5.set(seg.asSlice(index*sizeof()), x); } - public static GetLocationID GetLocationID(MemorySegment segment, SegmentScope scope) { + public static GetLocationID GetLocationID(MemorySegment segment, Arena scope) { return GetLocationID.ofAddress(GetLocationID$get(segment), scope); } - static final FunctionDescriptor GetConfigurationDescriptorPtr$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetConfigurationDescriptorPtr$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.GetConfigurationDescriptorPtr$FUNC - ); /** * {@snippet : * IOReturn (*GetConfigurationDescriptorPtr)(void*,UInt8,IOUSBConfigurationDescriptorPtr*); @@ -1370,14 +1151,14 @@ public static GetLocationID GetLocationID(MemorySegment segment, SegmentScope sc public interface GetConfigurationDescriptorPtr { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(GetConfigurationDescriptorPtr fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetConfigurationDescriptorPtr.class, fi, IOUSBDeviceStruct187.GetConfigurationDescriptorPtr$FUNC, scope); + static MemorySegment allocate(GetConfigurationDescriptorPtr fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$13.const$1, fi, constants$13.const$0, scope); } - static GetConfigurationDescriptorPtr ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetConfigurationDescriptorPtr ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBDeviceStruct187.GetConfigurationDescriptorPtr$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)constants$13.const$2.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1385,9 +1166,8 @@ static GetConfigurationDescriptorPtr ofAddress(MemorySegment addr, SegmentScope } } - static final VarHandle GetConfigurationDescriptorPtr$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetConfigurationDescriptorPtr")); public static VarHandle GetConfigurationDescriptorPtr$VH() { - return IOUSBDeviceStruct187.GetConfigurationDescriptorPtr$VH; + return constants$13.const$3; } /** * Getter for field: @@ -1396,7 +1176,7 @@ static GetConfigurationDescriptorPtr ofAddress(MemorySegment addr, SegmentScope * } */ public static MemorySegment GetConfigurationDescriptorPtr$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetConfigurationDescriptorPtr$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$13.const$3.get(seg); } /** * Setter for field: @@ -1405,24 +1185,17 @@ static GetConfigurationDescriptorPtr ofAddress(MemorySegment addr, SegmentScope * } */ public static void GetConfigurationDescriptorPtr$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.GetConfigurationDescriptorPtr$VH.set(seg, x); + constants$13.const$3.set(seg, x); } public static MemorySegment GetConfigurationDescriptorPtr$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetConfigurationDescriptorPtr$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$13.const$3.get(seg.asSlice(index*sizeof())); } public static void GetConfigurationDescriptorPtr$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.GetConfigurationDescriptorPtr$VH.set(seg.asSlice(index*sizeof()), x); + constants$13.const$3.set(seg.asSlice(index*sizeof()), x); } - public static GetConfigurationDescriptorPtr GetConfigurationDescriptorPtr(MemorySegment segment, SegmentScope scope) { + public static GetConfigurationDescriptorPtr GetConfigurationDescriptorPtr(MemorySegment segment, Arena scope) { return GetConfigurationDescriptorPtr.ofAddress(GetConfigurationDescriptorPtr$get(segment), scope); } - static final FunctionDescriptor GetConfiguration$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetConfiguration$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.GetConfiguration$FUNC - ); /** * {@snippet : * IOReturn (*GetConfiguration)(void*,UInt8*); @@ -1431,14 +1204,14 @@ public static GetConfigurationDescriptorPtr GetConfigurationDescriptorPtr(Memory public interface GetConfiguration { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetConfiguration fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetConfiguration.class, fi, IOUSBDeviceStruct187.GetConfiguration$FUNC, scope); + static MemorySegment allocate(GetConfiguration fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$13.const$4, fi, constants$6.const$5, scope); } - static GetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetConfiguration ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.GetConfiguration$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1446,9 +1219,8 @@ static GetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetConfiguration$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetConfiguration")); public static VarHandle GetConfiguration$VH() { - return IOUSBDeviceStruct187.GetConfiguration$VH; + return constants$13.const$5; } /** * Getter for field: @@ -1457,7 +1229,7 @@ static GetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetConfiguration$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetConfiguration$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$13.const$5.get(seg); } /** * Setter for field: @@ -1466,24 +1238,17 @@ static GetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetConfiguration$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.GetConfiguration$VH.set(seg, x); + constants$13.const$5.set(seg, x); } public static MemorySegment GetConfiguration$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetConfiguration$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$13.const$5.get(seg.asSlice(index*sizeof())); } public static void GetConfiguration$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.GetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); + constants$13.const$5.set(seg.asSlice(index*sizeof()), x); } - public static GetConfiguration GetConfiguration(MemorySegment segment, SegmentScope scope) { + public static GetConfiguration GetConfiguration(MemorySegment segment, Arena scope) { return GetConfiguration.ofAddress(GetConfiguration$get(segment), scope); } - static final FunctionDescriptor SetConfiguration$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT - ); - static final MethodHandle SetConfiguration$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.SetConfiguration$FUNC - ); /** * {@snippet : * IOReturn (*SetConfiguration)(void*,UInt8); @@ -1492,14 +1257,14 @@ public static GetConfiguration GetConfiguration(MemorySegment segment, SegmentSc public interface SetConfiguration { int apply(java.lang.foreign.MemorySegment _x0, byte _x1); - static MemorySegment allocate(SetConfiguration fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(SetConfiguration.class, fi, IOUSBDeviceStruct187.SetConfiguration$FUNC, scope); + static MemorySegment allocate(SetConfiguration fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$14.const$1, fi, constants$14.const$0, scope); } - static SetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static SetConfiguration ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBDeviceStruct187.SetConfiguration$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$14.const$2.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1507,9 +1272,8 @@ static SetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle SetConfiguration$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetConfiguration")); public static VarHandle SetConfiguration$VH() { - return IOUSBDeviceStruct187.SetConfiguration$VH; + return constants$14.const$3; } /** * Getter for field: @@ -1518,7 +1282,7 @@ static SetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment SetConfiguration$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.SetConfiguration$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$14.const$3.get(seg); } /** * Setter for field: @@ -1527,25 +1291,17 @@ static SetConfiguration ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void SetConfiguration$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.SetConfiguration$VH.set(seg, x); + constants$14.const$3.set(seg, x); } public static MemorySegment SetConfiguration$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.SetConfiguration$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$14.const$3.get(seg.asSlice(index*sizeof())); } public static void SetConfiguration$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.SetConfiguration$VH.set(seg.asSlice(index*sizeof()), x); + constants$14.const$3.set(seg.asSlice(index*sizeof()), x); } - public static SetConfiguration SetConfiguration(MemorySegment segment, SegmentScope scope) { + public static SetConfiguration SetConfiguration(MemorySegment segment, Arena scope) { return SetConfiguration.ofAddress(SetConfiguration$get(segment), scope); } - static final FunctionDescriptor GetBusFrameNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetBusFrameNumber$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.GetBusFrameNumber$FUNC - ); /** * {@snippet : * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); @@ -1554,14 +1310,14 @@ public static SetConfiguration SetConfiguration(MemorySegment segment, SegmentSc public interface GetBusFrameNumber { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(GetBusFrameNumber fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetBusFrameNumber.class, fi, IOUSBDeviceStruct187.GetBusFrameNumber$FUNC, scope); + static MemorySegment allocate(GetBusFrameNumber fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$14.const$5, fi, constants$14.const$4, scope); } - static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetBusFrameNumber ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBDeviceStruct187.GetBusFrameNumber$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)constants$15.const$0.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1569,9 +1325,8 @@ static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetBusFrameNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBusFrameNumber")); public static VarHandle GetBusFrameNumber$VH() { - return IOUSBDeviceStruct187.GetBusFrameNumber$VH; + return constants$15.const$1; } /** * Getter for field: @@ -1580,7 +1335,7 @@ static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetBusFrameNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetBusFrameNumber$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$15.const$1.get(seg); } /** * Setter for field: @@ -1589,23 +1344,17 @@ static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetBusFrameNumber$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.GetBusFrameNumber$VH.set(seg, x); + constants$15.const$1.set(seg, x); } public static MemorySegment GetBusFrameNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.GetBusFrameNumber$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$15.const$1.get(seg.asSlice(index*sizeof())); } public static void GetBusFrameNumber$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.GetBusFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); + constants$15.const$1.set(seg.asSlice(index*sizeof()), x); } - public static GetBusFrameNumber GetBusFrameNumber(MemorySegment segment, SegmentScope scope) { + public static GetBusFrameNumber GetBusFrameNumber(MemorySegment segment, Arena scope) { return GetBusFrameNumber.ofAddress(GetBusFrameNumber$get(segment), scope); } - static final FunctionDescriptor ResetDevice$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle ResetDevice$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.ResetDevice$FUNC - ); /** * {@snippet : * IOReturn (*ResetDevice)(void*); @@ -1614,14 +1363,14 @@ public static GetBusFrameNumber GetBusFrameNumber(MemorySegment segment, Segment public interface ResetDevice { int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(ResetDevice fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(ResetDevice.class, fi, IOUSBDeviceStruct187.ResetDevice$FUNC, scope); + static MemorySegment allocate(ResetDevice fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$15.const$2, fi, constants$5.const$5, scope); } - static ResetDevice ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static ResetDevice ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct187.ResetDevice$MH.invokeExact(symbol, __x0); + return (int)constants$6.const$1.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1629,9 +1378,8 @@ static ResetDevice ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle ResetDevice$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ResetDevice")); public static VarHandle ResetDevice$VH() { - return IOUSBDeviceStruct187.ResetDevice$VH; + return constants$15.const$3; } /** * Getter for field: @@ -1640,7 +1388,7 @@ static ResetDevice ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment ResetDevice$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.ResetDevice$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$15.const$3.get(seg); } /** * Setter for field: @@ -1649,24 +1397,17 @@ static ResetDevice ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void ResetDevice$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.ResetDevice$VH.set(seg, x); + constants$15.const$3.set(seg, x); } public static MemorySegment ResetDevice$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.ResetDevice$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$15.const$3.get(seg.asSlice(index*sizeof())); } public static void ResetDevice$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.ResetDevice$VH.set(seg.asSlice(index*sizeof()), x); + constants$15.const$3.set(seg.asSlice(index*sizeof()), x); } - public static ResetDevice ResetDevice(MemorySegment segment, SegmentScope scope) { + public static ResetDevice ResetDevice(MemorySegment segment, Arena scope) { return ResetDevice.ofAddress(ResetDevice$get(segment), scope); } - static final FunctionDescriptor DeviceRequest$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle DeviceRequest$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.DeviceRequest$FUNC - ); /** * {@snippet : * IOReturn (*DeviceRequest)(void*,IOUSBDevRequest*); @@ -1675,14 +1416,14 @@ public static ResetDevice ResetDevice(MemorySegment segment, SegmentScope scope) public interface DeviceRequest { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(DeviceRequest fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(DeviceRequest.class, fi, IOUSBDeviceStruct187.DeviceRequest$FUNC, scope); + static MemorySegment allocate(DeviceRequest fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$15.const$4, fi, constants$6.const$5, scope); } - static DeviceRequest ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static DeviceRequest ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.DeviceRequest$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1690,9 +1431,8 @@ static DeviceRequest ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle DeviceRequest$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequest")); public static VarHandle DeviceRequest$VH() { - return IOUSBDeviceStruct187.DeviceRequest$VH; + return constants$15.const$5; } /** * Getter for field: @@ -1701,7 +1441,7 @@ static DeviceRequest ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment DeviceRequest$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.DeviceRequest$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$15.const$5.get(seg); } /** * Setter for field: @@ -1710,26 +1450,17 @@ static DeviceRequest ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void DeviceRequest$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.DeviceRequest$VH.set(seg, x); + constants$15.const$5.set(seg, x); } public static MemorySegment DeviceRequest$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.DeviceRequest$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$15.const$5.get(seg.asSlice(index*sizeof())); } public static void DeviceRequest$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.DeviceRequest$VH.set(seg.asSlice(index*sizeof()), x); + constants$15.const$5.set(seg.asSlice(index*sizeof()), x); } - public static DeviceRequest DeviceRequest(MemorySegment segment, SegmentScope scope) { + public static DeviceRequest DeviceRequest(MemorySegment segment, Arena scope) { return DeviceRequest.ofAddress(DeviceRequest$get(segment), scope); } - static final FunctionDescriptor DeviceRequestAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle DeviceRequestAsync$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.DeviceRequestAsync$FUNC - ); /** * {@snippet : * IOReturn (*DeviceRequestAsync)(void*,IOUSBDevRequest*,IOAsyncCallback1,void*); @@ -1738,14 +1469,14 @@ public static DeviceRequest DeviceRequest(MemorySegment segment, SegmentScope sc public interface DeviceRequestAsync { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3); - static MemorySegment allocate(DeviceRequestAsync fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(DeviceRequestAsync.class, fi, IOUSBDeviceStruct187.DeviceRequestAsync$FUNC, scope); + static MemorySegment allocate(DeviceRequestAsync fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$16.const$1, fi, constants$16.const$0, scope); } - static DeviceRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static DeviceRequestAsync ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3) -> { try { - return (int)IOUSBDeviceStruct187.DeviceRequestAsync$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); + return (int)constants$16.const$2.invokeExact(symbol, __x0, __x1, __x2, __x3); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1753,9 +1484,8 @@ static DeviceRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle DeviceRequestAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestAsync")); public static VarHandle DeviceRequestAsync$VH() { - return IOUSBDeviceStruct187.DeviceRequestAsync$VH; + return constants$16.const$3; } /** * Getter for field: @@ -1764,7 +1494,7 @@ static DeviceRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment DeviceRequestAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.DeviceRequestAsync$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$16.const$3.get(seg); } /** * Setter for field: @@ -1773,25 +1503,17 @@ static DeviceRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void DeviceRequestAsync$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.DeviceRequestAsync$VH.set(seg, x); + constants$16.const$3.set(seg, x); } public static MemorySegment DeviceRequestAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.DeviceRequestAsync$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$16.const$3.get(seg.asSlice(index*sizeof())); } public static void DeviceRequestAsync$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.DeviceRequestAsync$VH.set(seg.asSlice(index*sizeof()), x); + constants$16.const$3.set(seg.asSlice(index*sizeof()), x); } - public static DeviceRequestAsync DeviceRequestAsync(MemorySegment segment, SegmentScope scope) { + public static DeviceRequestAsync DeviceRequestAsync(MemorySegment segment, Arena scope) { return DeviceRequestAsync.ofAddress(DeviceRequestAsync$get(segment), scope); } - static final FunctionDescriptor CreateInterfaceIterator$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle CreateInterfaceIterator$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.CreateInterfaceIterator$FUNC - ); /** * {@snippet : * IOReturn (*CreateInterfaceIterator)(void*,IOUSBFindInterfaceRequest*,io_iterator_t*); @@ -1800,14 +1522,14 @@ public static DeviceRequestAsync DeviceRequestAsync(MemorySegment segment, Segme public interface CreateInterfaceIterator { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(CreateInterfaceIterator fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(CreateInterfaceIterator.class, fi, IOUSBDeviceStruct187.CreateInterfaceIterator$FUNC, scope); + static MemorySegment allocate(CreateInterfaceIterator fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$16.const$4, fi, constants$14.const$4, scope); } - static CreateInterfaceIterator ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static CreateInterfaceIterator ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBDeviceStruct187.CreateInterfaceIterator$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)constants$15.const$0.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1815,9 +1537,8 @@ static CreateInterfaceIterator ofAddress(MemorySegment addr, SegmentScope scope) } } - static final VarHandle CreateInterfaceIterator$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceIterator")); public static VarHandle CreateInterfaceIterator$VH() { - return IOUSBDeviceStruct187.CreateInterfaceIterator$VH; + return constants$16.const$5; } /** * Getter for field: @@ -1826,7 +1547,7 @@ static CreateInterfaceIterator ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static MemorySegment CreateInterfaceIterator$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.CreateInterfaceIterator$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$16.const$5.get(seg); } /** * Setter for field: @@ -1835,23 +1556,17 @@ static CreateInterfaceIterator ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static void CreateInterfaceIterator$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.CreateInterfaceIterator$VH.set(seg, x); + constants$16.const$5.set(seg, x); } public static MemorySegment CreateInterfaceIterator$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.CreateInterfaceIterator$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$16.const$5.get(seg.asSlice(index*sizeof())); } public static void CreateInterfaceIterator$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.CreateInterfaceIterator$VH.set(seg.asSlice(index*sizeof()), x); + constants$16.const$5.set(seg.asSlice(index*sizeof()), x); } - public static CreateInterfaceIterator CreateInterfaceIterator(MemorySegment segment, SegmentScope scope) { + public static CreateInterfaceIterator CreateInterfaceIterator(MemorySegment segment, Arena scope) { return CreateInterfaceIterator.ofAddress(CreateInterfaceIterator$get(segment), scope); } - static final FunctionDescriptor USBDeviceOpenSeize$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBDeviceOpenSeize$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.USBDeviceOpenSeize$FUNC - ); /** * {@snippet : * IOReturn (*USBDeviceOpenSeize)(void*); @@ -1860,14 +1575,14 @@ public static CreateInterfaceIterator CreateInterfaceIterator(MemorySegment segm public interface USBDeviceOpenSeize { int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(USBDeviceOpenSeize fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBDeviceOpenSeize.class, fi, IOUSBDeviceStruct187.USBDeviceOpenSeize$FUNC, scope); + static MemorySegment allocate(USBDeviceOpenSeize fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$17.const$0, fi, constants$5.const$5, scope); } - static USBDeviceOpenSeize ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static USBDeviceOpenSeize ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct187.USBDeviceOpenSeize$MH.invokeExact(symbol, __x0); + return (int)constants$6.const$1.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1875,9 +1590,8 @@ static USBDeviceOpenSeize ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle USBDeviceOpenSeize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceOpenSeize")); public static VarHandle USBDeviceOpenSeize$VH() { - return IOUSBDeviceStruct187.USBDeviceOpenSeize$VH; + return constants$17.const$1; } /** * Getter for field: @@ -1886,7 +1600,7 @@ static USBDeviceOpenSeize ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment USBDeviceOpenSeize$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceOpenSeize$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$17.const$1.get(seg); } /** * Setter for field: @@ -1895,24 +1609,17 @@ static USBDeviceOpenSeize ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void USBDeviceOpenSeize$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.USBDeviceOpenSeize$VH.set(seg, x); + constants$17.const$1.set(seg, x); } public static MemorySegment USBDeviceOpenSeize$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceOpenSeize$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$17.const$1.get(seg.asSlice(index*sizeof())); } public static void USBDeviceOpenSeize$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.USBDeviceOpenSeize$VH.set(seg.asSlice(index*sizeof()), x); + constants$17.const$1.set(seg.asSlice(index*sizeof()), x); } - public static USBDeviceOpenSeize USBDeviceOpenSeize(MemorySegment segment, SegmentScope scope) { + public static USBDeviceOpenSeize USBDeviceOpenSeize(MemorySegment segment, Arena scope) { return USBDeviceOpenSeize.ofAddress(USBDeviceOpenSeize$get(segment), scope); } - static final FunctionDescriptor DeviceRequestTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle DeviceRequestTO$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.DeviceRequestTO$FUNC - ); /** * {@snippet : * IOReturn (*DeviceRequestTO)(void*,IOUSBDevRequestTO*); @@ -1921,14 +1628,14 @@ public static USBDeviceOpenSeize USBDeviceOpenSeize(MemorySegment segment, Segme public interface DeviceRequestTO { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(DeviceRequestTO fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(DeviceRequestTO.class, fi, IOUSBDeviceStruct187.DeviceRequestTO$FUNC, scope); + static MemorySegment allocate(DeviceRequestTO fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$17.const$2, fi, constants$6.const$5, scope); } - static DeviceRequestTO ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static DeviceRequestTO ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.DeviceRequestTO$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1936,9 +1643,8 @@ static DeviceRequestTO ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle DeviceRequestTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestTO")); public static VarHandle DeviceRequestTO$VH() { - return IOUSBDeviceStruct187.DeviceRequestTO$VH; + return constants$17.const$3; } /** * Getter for field: @@ -1947,7 +1653,7 @@ static DeviceRequestTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment DeviceRequestTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.DeviceRequestTO$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$17.const$3.get(seg); } /** * Setter for field: @@ -1956,26 +1662,17 @@ static DeviceRequestTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void DeviceRequestTO$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.DeviceRequestTO$VH.set(seg, x); + constants$17.const$3.set(seg, x); } public static MemorySegment DeviceRequestTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.DeviceRequestTO$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$17.const$3.get(seg.asSlice(index*sizeof())); } public static void DeviceRequestTO$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.DeviceRequestTO$VH.set(seg.asSlice(index*sizeof()), x); + constants$17.const$3.set(seg.asSlice(index*sizeof()), x); } - public static DeviceRequestTO DeviceRequestTO(MemorySegment segment, SegmentScope scope) { + public static DeviceRequestTO DeviceRequestTO(MemorySegment segment, Arena scope) { return DeviceRequestTO.ofAddress(DeviceRequestTO$get(segment), scope); } - static final FunctionDescriptor DeviceRequestAsyncTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle DeviceRequestAsyncTO$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.DeviceRequestAsyncTO$FUNC - ); /** * {@snippet : * IOReturn (*DeviceRequestAsyncTO)(void*,IOUSBDevRequestTO*,IOAsyncCallback1,void*); @@ -1984,14 +1681,14 @@ public static DeviceRequestTO DeviceRequestTO(MemorySegment segment, SegmentScop public interface DeviceRequestAsyncTO { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3); - static MemorySegment allocate(DeviceRequestAsyncTO fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(DeviceRequestAsyncTO.class, fi, IOUSBDeviceStruct187.DeviceRequestAsyncTO$FUNC, scope); + static MemorySegment allocate(DeviceRequestAsyncTO fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$17.const$4, fi, constants$16.const$0, scope); } - static DeviceRequestAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static DeviceRequestAsyncTO ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3) -> { try { - return (int)IOUSBDeviceStruct187.DeviceRequestAsyncTO$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); + return (int)constants$16.const$2.invokeExact(symbol, __x0, __x1, __x2, __x3); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1999,9 +1696,8 @@ static DeviceRequestAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle DeviceRequestAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestAsyncTO")); public static VarHandle DeviceRequestAsyncTO$VH() { - return IOUSBDeviceStruct187.DeviceRequestAsyncTO$VH; + return constants$17.const$5; } /** * Getter for field: @@ -2010,7 +1706,7 @@ static DeviceRequestAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment DeviceRequestAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.DeviceRequestAsyncTO$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$17.const$5.get(seg); } /** * Setter for field: @@ -2019,24 +1715,17 @@ static DeviceRequestAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void DeviceRequestAsyncTO$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.DeviceRequestAsyncTO$VH.set(seg, x); + constants$17.const$5.set(seg, x); } public static MemorySegment DeviceRequestAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.DeviceRequestAsyncTO$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$17.const$5.get(seg.asSlice(index*sizeof())); } public static void DeviceRequestAsyncTO$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.DeviceRequestAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); + constants$17.const$5.set(seg.asSlice(index*sizeof()), x); } - public static DeviceRequestAsyncTO DeviceRequestAsyncTO(MemorySegment segment, SegmentScope scope) { + public static DeviceRequestAsyncTO DeviceRequestAsyncTO(MemorySegment segment, Arena scope) { return DeviceRequestAsyncTO.ofAddress(DeviceRequestAsyncTO$get(segment), scope); } - static final FunctionDescriptor USBDeviceSuspend$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT - ); - static final MethodHandle USBDeviceSuspend$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.USBDeviceSuspend$FUNC - ); /** * {@snippet : * IOReturn (*USBDeviceSuspend)(void*,Boolean); @@ -2045,14 +1734,14 @@ public static DeviceRequestAsyncTO DeviceRequestAsyncTO(MemorySegment segment, S public interface USBDeviceSuspend { int apply(java.lang.foreign.MemorySegment _x0, byte _x1); - static MemorySegment allocate(USBDeviceSuspend fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBDeviceSuspend.class, fi, IOUSBDeviceStruct187.USBDeviceSuspend$FUNC, scope); + static MemorySegment allocate(USBDeviceSuspend fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$18.const$0, fi, constants$14.const$0, scope); } - static USBDeviceSuspend ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static USBDeviceSuspend ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBDeviceStruct187.USBDeviceSuspend$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$14.const$2.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2060,9 +1749,8 @@ static USBDeviceSuspend ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle USBDeviceSuspend$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceSuspend")); public static VarHandle USBDeviceSuspend$VH() { - return IOUSBDeviceStruct187.USBDeviceSuspend$VH; + return constants$18.const$1; } /** * Getter for field: @@ -2071,7 +1759,7 @@ static USBDeviceSuspend ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment USBDeviceSuspend$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceSuspend$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$18.const$1.get(seg); } /** * Setter for field: @@ -2080,23 +1768,17 @@ static USBDeviceSuspend ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void USBDeviceSuspend$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.USBDeviceSuspend$VH.set(seg, x); + constants$18.const$1.set(seg, x); } public static MemorySegment USBDeviceSuspend$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceSuspend$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$18.const$1.get(seg.asSlice(index*sizeof())); } public static void USBDeviceSuspend$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.USBDeviceSuspend$VH.set(seg.asSlice(index*sizeof()), x); + constants$18.const$1.set(seg.asSlice(index*sizeof()), x); } - public static USBDeviceSuspend USBDeviceSuspend(MemorySegment segment, SegmentScope scope) { + public static USBDeviceSuspend USBDeviceSuspend(MemorySegment segment, Arena scope) { return USBDeviceSuspend.ofAddress(USBDeviceSuspend$get(segment), scope); } - static final FunctionDescriptor USBDeviceAbortPipeZero$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBDeviceAbortPipeZero$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.USBDeviceAbortPipeZero$FUNC - ); /** * {@snippet : * IOReturn (*USBDeviceAbortPipeZero)(void*); @@ -2105,14 +1787,14 @@ public static USBDeviceSuspend USBDeviceSuspend(MemorySegment segment, SegmentSc public interface USBDeviceAbortPipeZero { int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(USBDeviceAbortPipeZero fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBDeviceAbortPipeZero.class, fi, IOUSBDeviceStruct187.USBDeviceAbortPipeZero$FUNC, scope); + static MemorySegment allocate(USBDeviceAbortPipeZero fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$18.const$2, fi, constants$5.const$5, scope); } - static USBDeviceAbortPipeZero ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static USBDeviceAbortPipeZero ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBDeviceStruct187.USBDeviceAbortPipeZero$MH.invokeExact(symbol, __x0); + return (int)constants$6.const$1.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2120,9 +1802,8 @@ static USBDeviceAbortPipeZero ofAddress(MemorySegment addr, SegmentScope scope) } } - static final VarHandle USBDeviceAbortPipeZero$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceAbortPipeZero")); public static VarHandle USBDeviceAbortPipeZero$VH() { - return IOUSBDeviceStruct187.USBDeviceAbortPipeZero$VH; + return constants$18.const$3; } /** * Getter for field: @@ -2131,7 +1812,7 @@ static USBDeviceAbortPipeZero ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static MemorySegment USBDeviceAbortPipeZero$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceAbortPipeZero$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$18.const$3.get(seg); } /** * Setter for field: @@ -2140,24 +1821,17 @@ static USBDeviceAbortPipeZero ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static void USBDeviceAbortPipeZero$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.USBDeviceAbortPipeZero$VH.set(seg, x); + constants$18.const$3.set(seg, x); } public static MemorySegment USBDeviceAbortPipeZero$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceAbortPipeZero$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$18.const$3.get(seg.asSlice(index*sizeof())); } public static void USBDeviceAbortPipeZero$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.USBDeviceAbortPipeZero$VH.set(seg.asSlice(index*sizeof()), x); + constants$18.const$3.set(seg.asSlice(index*sizeof()), x); } - public static USBDeviceAbortPipeZero USBDeviceAbortPipeZero(MemorySegment segment, SegmentScope scope) { + public static USBDeviceAbortPipeZero USBDeviceAbortPipeZero(MemorySegment segment, Arena scope) { return USBDeviceAbortPipeZero.ofAddress(USBDeviceAbortPipeZero$get(segment), scope); } - static final FunctionDescriptor USBGetManufacturerStringIndex$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBGetManufacturerStringIndex$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.USBGetManufacturerStringIndex$FUNC - ); /** * {@snippet : * IOReturn (*USBGetManufacturerStringIndex)(void*,UInt8*); @@ -2166,14 +1840,14 @@ public static USBDeviceAbortPipeZero USBDeviceAbortPipeZero(MemorySegment segmen public interface USBGetManufacturerStringIndex { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(USBGetManufacturerStringIndex fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBGetManufacturerStringIndex.class, fi, IOUSBDeviceStruct187.USBGetManufacturerStringIndex$FUNC, scope); + static MemorySegment allocate(USBGetManufacturerStringIndex fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$18.const$4, fi, constants$6.const$5, scope); } - static USBGetManufacturerStringIndex ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static USBGetManufacturerStringIndex ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.USBGetManufacturerStringIndex$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2181,9 +1855,8 @@ static USBGetManufacturerStringIndex ofAddress(MemorySegment addr, SegmentScope } } - static final VarHandle USBGetManufacturerStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBGetManufacturerStringIndex")); public static VarHandle USBGetManufacturerStringIndex$VH() { - return IOUSBDeviceStruct187.USBGetManufacturerStringIndex$VH; + return constants$18.const$5; } /** * Getter for field: @@ -2192,7 +1865,7 @@ static USBGetManufacturerStringIndex ofAddress(MemorySegment addr, SegmentScope * } */ public static MemorySegment USBGetManufacturerStringIndex$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBGetManufacturerStringIndex$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$18.const$5.get(seg); } /** * Setter for field: @@ -2201,24 +1874,17 @@ static USBGetManufacturerStringIndex ofAddress(MemorySegment addr, SegmentScope * } */ public static void USBGetManufacturerStringIndex$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.USBGetManufacturerStringIndex$VH.set(seg, x); + constants$18.const$5.set(seg, x); } public static MemorySegment USBGetManufacturerStringIndex$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBGetManufacturerStringIndex$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$18.const$5.get(seg.asSlice(index*sizeof())); } public static void USBGetManufacturerStringIndex$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.USBGetManufacturerStringIndex$VH.set(seg.asSlice(index*sizeof()), x); + constants$18.const$5.set(seg.asSlice(index*sizeof()), x); } - public static USBGetManufacturerStringIndex USBGetManufacturerStringIndex(MemorySegment segment, SegmentScope scope) { + public static USBGetManufacturerStringIndex USBGetManufacturerStringIndex(MemorySegment segment, Arena scope) { return USBGetManufacturerStringIndex.ofAddress(USBGetManufacturerStringIndex$get(segment), scope); } - static final FunctionDescriptor USBGetProductStringIndex$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBGetProductStringIndex$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.USBGetProductStringIndex$FUNC - ); /** * {@snippet : * IOReturn (*USBGetProductStringIndex)(void*,UInt8*); @@ -2227,14 +1893,14 @@ public static USBGetManufacturerStringIndex USBGetManufacturerStringIndex(Memory public interface USBGetProductStringIndex { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(USBGetProductStringIndex fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBGetProductStringIndex.class, fi, IOUSBDeviceStruct187.USBGetProductStringIndex$FUNC, scope); + static MemorySegment allocate(USBGetProductStringIndex fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$19.const$0, fi, constants$6.const$5, scope); } - static USBGetProductStringIndex ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static USBGetProductStringIndex ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.USBGetProductStringIndex$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2242,9 +1908,8 @@ static USBGetProductStringIndex ofAddress(MemorySegment addr, SegmentScope scope } } - static final VarHandle USBGetProductStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBGetProductStringIndex")); public static VarHandle USBGetProductStringIndex$VH() { - return IOUSBDeviceStruct187.USBGetProductStringIndex$VH; + return constants$19.const$1; } /** * Getter for field: @@ -2253,7 +1918,7 @@ static USBGetProductStringIndex ofAddress(MemorySegment addr, SegmentScope scope * } */ public static MemorySegment USBGetProductStringIndex$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBGetProductStringIndex$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$19.const$1.get(seg); } /** * Setter for field: @@ -2262,24 +1927,17 @@ static USBGetProductStringIndex ofAddress(MemorySegment addr, SegmentScope scope * } */ public static void USBGetProductStringIndex$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.USBGetProductStringIndex$VH.set(seg, x); + constants$19.const$1.set(seg, x); } public static MemorySegment USBGetProductStringIndex$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBGetProductStringIndex$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$19.const$1.get(seg.asSlice(index*sizeof())); } public static void USBGetProductStringIndex$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.USBGetProductStringIndex$VH.set(seg.asSlice(index*sizeof()), x); + constants$19.const$1.set(seg.asSlice(index*sizeof()), x); } - public static USBGetProductStringIndex USBGetProductStringIndex(MemorySegment segment, SegmentScope scope) { + public static USBGetProductStringIndex USBGetProductStringIndex(MemorySegment segment, Arena scope) { return USBGetProductStringIndex.ofAddress(USBGetProductStringIndex$get(segment), scope); } - static final FunctionDescriptor USBGetSerialNumberStringIndex$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBGetSerialNumberStringIndex$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.USBGetSerialNumberStringIndex$FUNC - ); /** * {@snippet : * IOReturn (*USBGetSerialNumberStringIndex)(void*,UInt8*); @@ -2288,14 +1946,14 @@ public static USBGetProductStringIndex USBGetProductStringIndex(MemorySegment se public interface USBGetSerialNumberStringIndex { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(USBGetSerialNumberStringIndex fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBGetSerialNumberStringIndex.class, fi, IOUSBDeviceStruct187.USBGetSerialNumberStringIndex$FUNC, scope); + static MemorySegment allocate(USBGetSerialNumberStringIndex fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$19.const$2, fi, constants$6.const$5, scope); } - static USBGetSerialNumberStringIndex ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static USBGetSerialNumberStringIndex ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBDeviceStruct187.USBGetSerialNumberStringIndex$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2303,9 +1961,8 @@ static USBGetSerialNumberStringIndex ofAddress(MemorySegment addr, SegmentScope } } - static final VarHandle USBGetSerialNumberStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBGetSerialNumberStringIndex")); public static VarHandle USBGetSerialNumberStringIndex$VH() { - return IOUSBDeviceStruct187.USBGetSerialNumberStringIndex$VH; + return constants$19.const$3; } /** * Getter for field: @@ -2314,7 +1971,7 @@ static USBGetSerialNumberStringIndex ofAddress(MemorySegment addr, SegmentScope * } */ public static MemorySegment USBGetSerialNumberStringIndex$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBGetSerialNumberStringIndex$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$19.const$3.get(seg); } /** * Setter for field: @@ -2323,24 +1980,17 @@ static USBGetSerialNumberStringIndex ofAddress(MemorySegment addr, SegmentScope * } */ public static void USBGetSerialNumberStringIndex$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.USBGetSerialNumberStringIndex$VH.set(seg, x); + constants$19.const$3.set(seg, x); } public static MemorySegment USBGetSerialNumberStringIndex$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBGetSerialNumberStringIndex$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$19.const$3.get(seg.asSlice(index*sizeof())); } public static void USBGetSerialNumberStringIndex$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.USBGetSerialNumberStringIndex$VH.set(seg.asSlice(index*sizeof()), x); + constants$19.const$3.set(seg.asSlice(index*sizeof()), x); } - public static USBGetSerialNumberStringIndex USBGetSerialNumberStringIndex(MemorySegment segment, SegmentScope scope) { + public static USBGetSerialNumberStringIndex USBGetSerialNumberStringIndex(MemorySegment segment, Arena scope) { return USBGetSerialNumberStringIndex.ofAddress(USBGetSerialNumberStringIndex$get(segment), scope); } - static final FunctionDescriptor USBDeviceReEnumerate$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle USBDeviceReEnumerate$MH = RuntimeHelper.downcallHandle( - IOUSBDeviceStruct187.USBDeviceReEnumerate$FUNC - ); /** * {@snippet : * IOReturn (*USBDeviceReEnumerate)(void*,UInt32); @@ -2349,14 +1999,14 @@ public static USBGetSerialNumberStringIndex USBGetSerialNumberStringIndex(Memory public interface USBDeviceReEnumerate { int apply(java.lang.foreign.MemorySegment _x0, int _x1); - static MemorySegment allocate(USBDeviceReEnumerate fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBDeviceReEnumerate.class, fi, IOUSBDeviceStruct187.USBDeviceReEnumerate$FUNC, scope); + static MemorySegment allocate(USBDeviceReEnumerate fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$19.const$5, fi, constants$19.const$4, scope); } - static USBDeviceReEnumerate ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static USBDeviceReEnumerate ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, int __x1) -> { try { - return (int)IOUSBDeviceStruct187.USBDeviceReEnumerate$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$20.const$0.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2364,9 +2014,8 @@ static USBDeviceReEnumerate ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle USBDeviceReEnumerate$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceReEnumerate")); public static VarHandle USBDeviceReEnumerate$VH() { - return IOUSBDeviceStruct187.USBDeviceReEnumerate$VH; + return constants$20.const$1; } /** * Getter for field: @@ -2375,7 +2024,7 @@ static USBDeviceReEnumerate ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment USBDeviceReEnumerate$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceReEnumerate$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$20.const$1.get(seg); } /** * Setter for field: @@ -2384,15 +2033,15 @@ static USBDeviceReEnumerate ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void USBDeviceReEnumerate$set(MemorySegment seg, MemorySegment x) { - IOUSBDeviceStruct187.USBDeviceReEnumerate$VH.set(seg, x); + constants$20.const$1.set(seg, x); } public static MemorySegment USBDeviceReEnumerate$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBDeviceStruct187.USBDeviceReEnumerate$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$20.const$1.get(seg.asSlice(index*sizeof())); } public static void USBDeviceReEnumerate$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBDeviceStruct187.USBDeviceReEnumerate$VH.set(seg.asSlice(index*sizeof()), x); + constants$20.const$1.set(seg.asSlice(index*sizeof()), x); } - public static USBDeviceReEnumerate USBDeviceReEnumerate(MemorySegment segment, SegmentScope scope) { + public static USBDeviceReEnumerate USBDeviceReEnumerate(MemorySegment segment, Arena scope) { return USBDeviceReEnumerate.ofAddress(USBDeviceReEnumerate$get(segment), scope); } public static long sizeof() { return $LAYOUT().byteSize(); } @@ -2400,7 +2049,7 @@ public static USBDeviceReEnumerate USBDeviceReEnumerate(MemorySegment segment, S public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java index 3a54b981..007fbbfb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java @@ -2,7 +2,10 @@ package net.codecrete.usb.macos.gen.iokit; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -16,18 +19,11 @@ */ public class IOUSBFindInterfaceRequest { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_SHORT$LAYOUT.withName("bInterfaceClass"), - Constants$root.C_SHORT$LAYOUT.withName("bInterfaceSubClass"), - Constants$root.C_SHORT$LAYOUT.withName("bInterfaceProtocol"), - Constants$root.C_SHORT$LAYOUT.withName("bAlternateSetting") - ); public static MemoryLayout $LAYOUT() { - return IOUSBFindInterfaceRequest.$struct$LAYOUT; + return constants$1.const$2; } - static final VarHandle bInterfaceClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("bInterfaceClass")); public static VarHandle bInterfaceClass$VH() { - return IOUSBFindInterfaceRequest.bInterfaceClass$VH; + return constants$1.const$3; } /** * Getter for field: @@ -36,7 +32,7 @@ public class IOUSBFindInterfaceRequest { * } */ public static short bInterfaceClass$get(MemorySegment seg) { - return (short)IOUSBFindInterfaceRequest.bInterfaceClass$VH.get(seg); + return (short)constants$1.const$3.get(seg); } /** * Setter for field: @@ -45,17 +41,16 @@ public class IOUSBFindInterfaceRequest { * } */ public static void bInterfaceClass$set(MemorySegment seg, short x) { - IOUSBFindInterfaceRequest.bInterfaceClass$VH.set(seg, x); + constants$1.const$3.set(seg, x); } public static short bInterfaceClass$get(MemorySegment seg, long index) { - return (short)IOUSBFindInterfaceRequest.bInterfaceClass$VH.get(seg.asSlice(index*sizeof())); + return (short)constants$1.const$3.get(seg.asSlice(index*sizeof())); } public static void bInterfaceClass$set(MemorySegment seg, long index, short x) { - IOUSBFindInterfaceRequest.bInterfaceClass$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$3.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle bInterfaceSubClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("bInterfaceSubClass")); public static VarHandle bInterfaceSubClass$VH() { - return IOUSBFindInterfaceRequest.bInterfaceSubClass$VH; + return constants$1.const$4; } /** * Getter for field: @@ -64,7 +59,7 @@ public class IOUSBFindInterfaceRequest { * } */ public static short bInterfaceSubClass$get(MemorySegment seg) { - return (short)IOUSBFindInterfaceRequest.bInterfaceSubClass$VH.get(seg); + return (short)constants$1.const$4.get(seg); } /** * Setter for field: @@ -73,17 +68,16 @@ public class IOUSBFindInterfaceRequest { * } */ public static void bInterfaceSubClass$set(MemorySegment seg, short x) { - IOUSBFindInterfaceRequest.bInterfaceSubClass$VH.set(seg, x); + constants$1.const$4.set(seg, x); } public static short bInterfaceSubClass$get(MemorySegment seg, long index) { - return (short)IOUSBFindInterfaceRequest.bInterfaceSubClass$VH.get(seg.asSlice(index*sizeof())); + return (short)constants$1.const$4.get(seg.asSlice(index*sizeof())); } public static void bInterfaceSubClass$set(MemorySegment seg, long index, short x) { - IOUSBFindInterfaceRequest.bInterfaceSubClass$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$4.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle bInterfaceProtocol$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("bInterfaceProtocol")); public static VarHandle bInterfaceProtocol$VH() { - return IOUSBFindInterfaceRequest.bInterfaceProtocol$VH; + return constants$1.const$5; } /** * Getter for field: @@ -92,7 +86,7 @@ public class IOUSBFindInterfaceRequest { * } */ public static short bInterfaceProtocol$get(MemorySegment seg) { - return (short)IOUSBFindInterfaceRequest.bInterfaceProtocol$VH.get(seg); + return (short)constants$1.const$5.get(seg); } /** * Setter for field: @@ -101,17 +95,16 @@ public class IOUSBFindInterfaceRequest { * } */ public static void bInterfaceProtocol$set(MemorySegment seg, short x) { - IOUSBFindInterfaceRequest.bInterfaceProtocol$VH.set(seg, x); + constants$1.const$5.set(seg, x); } public static short bInterfaceProtocol$get(MemorySegment seg, long index) { - return (short)IOUSBFindInterfaceRequest.bInterfaceProtocol$VH.get(seg.asSlice(index*sizeof())); + return (short)constants$1.const$5.get(seg.asSlice(index*sizeof())); } public static void bInterfaceProtocol$set(MemorySegment seg, long index, short x) { - IOUSBFindInterfaceRequest.bInterfaceProtocol$VH.set(seg.asSlice(index*sizeof()), x); + constants$1.const$5.set(seg.asSlice(index*sizeof()), x); } - static final VarHandle bAlternateSetting$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("bAlternateSetting")); public static VarHandle bAlternateSetting$VH() { - return IOUSBFindInterfaceRequest.bAlternateSetting$VH; + return constants$2.const$0; } /** * Getter for field: @@ -120,7 +113,7 @@ public class IOUSBFindInterfaceRequest { * } */ public static short bAlternateSetting$get(MemorySegment seg) { - return (short)IOUSBFindInterfaceRequest.bAlternateSetting$VH.get(seg); + return (short)constants$2.const$0.get(seg); } /** * Setter for field: @@ -129,20 +122,20 @@ public class IOUSBFindInterfaceRequest { * } */ public static void bAlternateSetting$set(MemorySegment seg, short x) { - IOUSBFindInterfaceRequest.bAlternateSetting$VH.set(seg, x); + constants$2.const$0.set(seg, x); } public static short bAlternateSetting$get(MemorySegment seg, long index) { - return (short)IOUSBFindInterfaceRequest.bAlternateSetting$VH.get(seg.asSlice(index*sizeof())); + return (short)constants$2.const$0.get(seg.asSlice(index*sizeof())); } public static void bAlternateSetting$set(MemorySegment seg, long index, short x) { - IOUSBFindInterfaceRequest.bAlternateSetting$VH.set(seg.asSlice(index*sizeof()), x); + constants$2.const$0.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java index e4a85020..0cdc7159 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java @@ -2,8 +2,10 @@ package net.codecrete.usb.macos.gen.iokit; -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.VarHandle; /** * {@snippet : @@ -62,63 +64,11 @@ */ public class IOUSBInterfaceStruct190 { - static final StructLayout $struct$LAYOUT = MemoryLayout.structLayout( - Constants$root.C_POINTER$LAYOUT.withName("_reserved"), - Constants$root.C_POINTER$LAYOUT.withName("QueryInterface"), - Constants$root.C_POINTER$LAYOUT.withName("AddRef"), - Constants$root.C_POINTER$LAYOUT.withName("Release"), - Constants$root.C_POINTER$LAYOUT.withName("CreateInterfaceAsyncEventSource"), - Constants$root.C_POINTER$LAYOUT.withName("GetInterfaceAsyncEventSource"), - Constants$root.C_POINTER$LAYOUT.withName("CreateInterfaceAsyncPort"), - Constants$root.C_POINTER$LAYOUT.withName("GetInterfaceAsyncPort"), - Constants$root.C_POINTER$LAYOUT.withName("USBInterfaceOpen"), - Constants$root.C_POINTER$LAYOUT.withName("USBInterfaceClose"), - Constants$root.C_POINTER$LAYOUT.withName("GetInterfaceClass"), - Constants$root.C_POINTER$LAYOUT.withName("GetInterfaceSubClass"), - Constants$root.C_POINTER$LAYOUT.withName("GetInterfaceProtocol"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceVendor"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceProduct"), - Constants$root.C_POINTER$LAYOUT.withName("GetDeviceReleaseNumber"), - Constants$root.C_POINTER$LAYOUT.withName("GetConfigurationValue"), - Constants$root.C_POINTER$LAYOUT.withName("GetInterfaceNumber"), - Constants$root.C_POINTER$LAYOUT.withName("GetAlternateSetting"), - Constants$root.C_POINTER$LAYOUT.withName("GetNumEndpoints"), - Constants$root.C_POINTER$LAYOUT.withName("GetLocationID"), - Constants$root.C_POINTER$LAYOUT.withName("GetDevice"), - Constants$root.C_POINTER$LAYOUT.withName("SetAlternateInterface"), - Constants$root.C_POINTER$LAYOUT.withName("GetBusFrameNumber"), - Constants$root.C_POINTER$LAYOUT.withName("ControlRequest"), - Constants$root.C_POINTER$LAYOUT.withName("ControlRequestAsync"), - Constants$root.C_POINTER$LAYOUT.withName("GetPipeProperties"), - Constants$root.C_POINTER$LAYOUT.withName("GetPipeStatus"), - Constants$root.C_POINTER$LAYOUT.withName("AbortPipe"), - Constants$root.C_POINTER$LAYOUT.withName("ResetPipe"), - Constants$root.C_POINTER$LAYOUT.withName("ClearPipeStall"), - Constants$root.C_POINTER$LAYOUT.withName("ReadPipe"), - Constants$root.C_POINTER$LAYOUT.withName("WritePipe"), - Constants$root.C_POINTER$LAYOUT.withName("ReadPipeAsync"), - Constants$root.C_POINTER$LAYOUT.withName("WritePipeAsync"), - Constants$root.C_POINTER$LAYOUT.withName("ReadIsochPipeAsync"), - Constants$root.C_POINTER$LAYOUT.withName("WriteIsochPipeAsync"), - Constants$root.C_POINTER$LAYOUT.withName("ControlRequestTO"), - Constants$root.C_POINTER$LAYOUT.withName("ControlRequestAsyncTO"), - Constants$root.C_POINTER$LAYOUT.withName("ReadPipeTO"), - Constants$root.C_POINTER$LAYOUT.withName("WritePipeTO"), - Constants$root.C_POINTER$LAYOUT.withName("ReadPipeAsyncTO"), - Constants$root.C_POINTER$LAYOUT.withName("WritePipeAsyncTO"), - Constants$root.C_POINTER$LAYOUT.withName("USBInterfaceGetStringIndex"), - Constants$root.C_POINTER$LAYOUT.withName("USBInterfaceOpenSeize"), - Constants$root.C_POINTER$LAYOUT.withName("ClearPipeStallBothEnds"), - Constants$root.C_POINTER$LAYOUT.withName("SetPipePolicy"), - Constants$root.C_POINTER$LAYOUT.withName("GetBandwidthAvailable"), - Constants$root.C_POINTER$LAYOUT.withName("GetEndpointProperties") - ).withName("IOUSBInterfaceStruct190"); public static MemoryLayout $LAYOUT() { - return IOUSBInterfaceStruct190.$struct$LAYOUT; + return constants$20.const$2; } - static final VarHandle _reserved$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("_reserved")); public static VarHandle _reserved$VH() { - return IOUSBInterfaceStruct190._reserved$VH; + return constants$20.const$3; } /** * Getter for field: @@ -127,7 +77,7 @@ public class IOUSBInterfaceStruct190 { * } */ public static MemorySegment _reserved$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190._reserved$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$20.const$3.get(seg); } /** * Setter for field: @@ -136,39 +86,14 @@ public class IOUSBInterfaceStruct190 { * } */ public static void _reserved$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190._reserved$VH.set(seg, x); + constants$20.const$3.set(seg, x); } public static MemorySegment _reserved$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190._reserved$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$20.const$3.get(seg.asSlice(index*sizeof())); } public static void _reserved$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190._reserved$VH.set(seg.asSlice(index*sizeof()), x); - } - static final FunctionDescriptor QueryInterface$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - MemoryLayout.structLayout( - Constants$root.C_CHAR$LAYOUT.withName("byte0"), - Constants$root.C_CHAR$LAYOUT.withName("byte1"), - Constants$root.C_CHAR$LAYOUT.withName("byte2"), - Constants$root.C_CHAR$LAYOUT.withName("byte3"), - Constants$root.C_CHAR$LAYOUT.withName("byte4"), - Constants$root.C_CHAR$LAYOUT.withName("byte5"), - Constants$root.C_CHAR$LAYOUT.withName("byte6"), - Constants$root.C_CHAR$LAYOUT.withName("byte7"), - Constants$root.C_CHAR$LAYOUT.withName("byte8"), - Constants$root.C_CHAR$LAYOUT.withName("byte9"), - Constants$root.C_CHAR$LAYOUT.withName("byte10"), - Constants$root.C_CHAR$LAYOUT.withName("byte11"), - Constants$root.C_CHAR$LAYOUT.withName("byte12"), - Constants$root.C_CHAR$LAYOUT.withName("byte13"), - Constants$root.C_CHAR$LAYOUT.withName("byte14"), - Constants$root.C_CHAR$LAYOUT.withName("byte15") - ), - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle QueryInterface$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.QueryInterface$FUNC - ); + constants$20.const$3.set(seg.asSlice(index*sizeof()), x); + } /** * {@snippet : * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); @@ -177,14 +102,14 @@ public class IOUSBInterfaceStruct190 { public interface QueryInterface { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(QueryInterface fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(QueryInterface.class, fi, IOUSBInterfaceStruct190.QueryInterface$FUNC, scope); + static MemorySegment allocate(QueryInterface fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$20.const$4, fi, constants$5.const$1, scope); } - static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static QueryInterface ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBInterfaceStruct190.QueryInterface$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)constants$5.const$3.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -192,9 +117,8 @@ static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle QueryInterface$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("QueryInterface")); public static VarHandle QueryInterface$VH() { - return IOUSBInterfaceStruct190.QueryInterface$VH; + return constants$20.const$5; } /** * Getter for field: @@ -203,7 +127,7 @@ static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment QueryInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.QueryInterface$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$20.const$5.get(seg); } /** * Setter for field: @@ -212,23 +136,17 @@ static QueryInterface ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void QueryInterface$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.QueryInterface$VH.set(seg, x); + constants$20.const$5.set(seg, x); } public static MemorySegment QueryInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.QueryInterface$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$20.const$5.get(seg.asSlice(index*sizeof())); } public static void QueryInterface$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.QueryInterface$VH.set(seg.asSlice(index*sizeof()), x); + constants$20.const$5.set(seg.asSlice(index*sizeof()), x); } - public static QueryInterface QueryInterface(MemorySegment segment, SegmentScope scope) { + public static QueryInterface QueryInterface(MemorySegment segment, Arena scope) { return QueryInterface.ofAddress(QueryInterface$get(segment), scope); } - static final FunctionDescriptor AddRef$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle AddRef$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.AddRef$FUNC - ); /** * {@snippet : * ULONG (*AddRef)(void*); @@ -237,14 +155,14 @@ public static QueryInterface QueryInterface(MemorySegment segment, SegmentScope public interface AddRef { int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(AddRef fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(AddRef.class, fi, IOUSBInterfaceStruct190.AddRef$FUNC, scope); + static MemorySegment allocate(AddRef fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$21.const$0, fi, constants$5.const$5, scope); } - static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static AddRef ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBInterfaceStruct190.AddRef$MH.invokeExact(symbol, __x0); + return (int)constants$6.const$1.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -252,9 +170,8 @@ static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle AddRef$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AddRef")); public static VarHandle AddRef$VH() { - return IOUSBInterfaceStruct190.AddRef$VH; + return constants$21.const$1; } /** * Getter for field: @@ -263,7 +180,7 @@ static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment AddRef$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.AddRef$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$21.const$1.get(seg); } /** * Setter for field: @@ -272,23 +189,17 @@ static AddRef ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void AddRef$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.AddRef$VH.set(seg, x); + constants$21.const$1.set(seg, x); } public static MemorySegment AddRef$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.AddRef$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$21.const$1.get(seg.asSlice(index*sizeof())); } public static void AddRef$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.AddRef$VH.set(seg.asSlice(index*sizeof()), x); + constants$21.const$1.set(seg.asSlice(index*sizeof()), x); } - public static AddRef AddRef(MemorySegment segment, SegmentScope scope) { + public static AddRef AddRef(MemorySegment segment, Arena scope) { return AddRef.ofAddress(AddRef$get(segment), scope); } - static final FunctionDescriptor Release$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle Release$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.Release$FUNC - ); /** * {@snippet : * ULONG (*Release)(void*); @@ -297,14 +208,14 @@ public static AddRef AddRef(MemorySegment segment, SegmentScope scope) { public interface Release { int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(Release fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(Release.class, fi, IOUSBInterfaceStruct190.Release$FUNC, scope); + static MemorySegment allocate(Release fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$21.const$2, fi, constants$5.const$5, scope); } - static Release ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static Release ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBInterfaceStruct190.Release$MH.invokeExact(symbol, __x0); + return (int)constants$6.const$1.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -312,9 +223,8 @@ static Release ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle Release$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("Release")); public static VarHandle Release$VH() { - return IOUSBInterfaceStruct190.Release$VH; + return constants$21.const$3; } /** * Getter for field: @@ -323,7 +233,7 @@ static Release ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment Release$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.Release$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$21.const$3.get(seg); } /** * Setter for field: @@ -332,24 +242,17 @@ static Release ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void Release$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.Release$VH.set(seg, x); + constants$21.const$3.set(seg, x); } public static MemorySegment Release$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.Release$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$21.const$3.get(seg.asSlice(index*sizeof())); } public static void Release$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.Release$VH.set(seg.asSlice(index*sizeof()), x); + constants$21.const$3.set(seg.asSlice(index*sizeof()), x); } - public static Release Release(MemorySegment segment, SegmentScope scope) { + public static Release Release(MemorySegment segment, Arena scope) { return Release.ofAddress(Release$get(segment), scope); } - static final FunctionDescriptor CreateInterfaceAsyncEventSource$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle CreateInterfaceAsyncEventSource$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$FUNC - ); /** * {@snippet : * IOReturn (*CreateInterfaceAsyncEventSource)(void*,CFRunLoopSourceRef*); @@ -358,14 +261,14 @@ public static Release Release(MemorySegment segment, SegmentScope scope) { public interface CreateInterfaceAsyncEventSource { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(CreateInterfaceAsyncEventSource fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(CreateInterfaceAsyncEventSource.class, fi, IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$FUNC, scope); + static MemorySegment allocate(CreateInterfaceAsyncEventSource fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$21.const$4, fi, constants$6.const$5, scope); } - static CreateInterfaceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static CreateInterfaceAsyncEventSource ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -373,9 +276,8 @@ static CreateInterfaceAsyncEventSource ofAddress(MemorySegment addr, SegmentScop } } - static final VarHandle CreateInterfaceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceAsyncEventSource")); public static VarHandle CreateInterfaceAsyncEventSource$VH() { - return IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$VH; + return constants$21.const$5; } /** * Getter for field: @@ -384,7 +286,7 @@ static CreateInterfaceAsyncEventSource ofAddress(MemorySegment addr, SegmentScop * } */ public static MemorySegment CreateInterfaceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$21.const$5.get(seg); } /** * Setter for field: @@ -393,23 +295,17 @@ static CreateInterfaceAsyncEventSource ofAddress(MemorySegment addr, SegmentScop * } */ public static void CreateInterfaceAsyncEventSource$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$VH.set(seg, x); + constants$21.const$5.set(seg, x); } public static MemorySegment CreateInterfaceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$21.const$5.get(seg.asSlice(index*sizeof())); } public static void CreateInterfaceAsyncEventSource$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); + constants$21.const$5.set(seg.asSlice(index*sizeof()), x); } - public static CreateInterfaceAsyncEventSource CreateInterfaceAsyncEventSource(MemorySegment segment, SegmentScope scope) { + public static CreateInterfaceAsyncEventSource CreateInterfaceAsyncEventSource(MemorySegment segment, Arena scope) { return CreateInterfaceAsyncEventSource.ofAddress(CreateInterfaceAsyncEventSource$get(segment), scope); } - static final FunctionDescriptor GetInterfaceAsyncEventSource$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetInterfaceAsyncEventSource$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$FUNC - ); /** * {@snippet : * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void*); @@ -418,14 +314,14 @@ public static CreateInterfaceAsyncEventSource CreateInterfaceAsyncEventSource(Me public interface GetInterfaceAsyncEventSource { java.lang.foreign.MemorySegment apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(GetInterfaceAsyncEventSource fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetInterfaceAsyncEventSource.class, fi, IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$FUNC, scope); + static MemorySegment allocate(GetInterfaceAsyncEventSource fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$22.const$0, fi, constants$3.const$0, scope); } - static GetInterfaceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetInterfaceAsyncEventSource ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$MH.invokeExact(symbol, __x0); + return (java.lang.foreign.MemorySegment)constants$7.const$4.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -433,9 +329,8 @@ static GetInterfaceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope s } } - static final VarHandle GetInterfaceAsyncEventSource$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceAsyncEventSource")); public static VarHandle GetInterfaceAsyncEventSource$VH() { - return IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$VH; + return constants$22.const$1; } /** * Getter for field: @@ -444,7 +339,7 @@ static GetInterfaceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope s * } */ public static MemorySegment GetInterfaceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$22.const$1.get(seg); } /** * Setter for field: @@ -453,24 +348,17 @@ static GetInterfaceAsyncEventSource ofAddress(MemorySegment addr, SegmentScope s * } */ public static void GetInterfaceAsyncEventSource$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$VH.set(seg, x); + constants$22.const$1.set(seg, x); } public static MemorySegment GetInterfaceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$22.const$1.get(seg.asSlice(index*sizeof())); } public static void GetInterfaceAsyncEventSource$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource$VH.set(seg.asSlice(index*sizeof()), x); + constants$22.const$1.set(seg.asSlice(index*sizeof()), x); } - public static GetInterfaceAsyncEventSource GetInterfaceAsyncEventSource(MemorySegment segment, SegmentScope scope) { + public static GetInterfaceAsyncEventSource GetInterfaceAsyncEventSource(MemorySegment segment, Arena scope) { return GetInterfaceAsyncEventSource.ofAddress(GetInterfaceAsyncEventSource$get(segment), scope); } - static final FunctionDescriptor CreateInterfaceAsyncPort$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle CreateInterfaceAsyncPort$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$FUNC - ); /** * {@snippet : * IOReturn (*CreateInterfaceAsyncPort)(void*,mach_port_t*); @@ -479,14 +367,14 @@ public static GetInterfaceAsyncEventSource GetInterfaceAsyncEventSource(MemorySe public interface CreateInterfaceAsyncPort { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(CreateInterfaceAsyncPort fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(CreateInterfaceAsyncPort.class, fi, IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$FUNC, scope); + static MemorySegment allocate(CreateInterfaceAsyncPort fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$22.const$2, fi, constants$6.const$5, scope); } - static CreateInterfaceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static CreateInterfaceAsyncPort ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -494,9 +382,8 @@ static CreateInterfaceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope } } - static final VarHandle CreateInterfaceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceAsyncPort")); public static VarHandle CreateInterfaceAsyncPort$VH() { - return IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$VH; + return constants$22.const$3; } /** * Getter for field: @@ -505,7 +392,7 @@ static CreateInterfaceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope * } */ public static MemorySegment CreateInterfaceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$22.const$3.get(seg); } /** * Setter for field: @@ -514,23 +401,17 @@ static CreateInterfaceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope * } */ public static void CreateInterfaceAsyncPort$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$VH.set(seg, x); + constants$22.const$3.set(seg, x); } public static MemorySegment CreateInterfaceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$22.const$3.get(seg.asSlice(index*sizeof())); } public static void CreateInterfaceAsyncPort$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.CreateInterfaceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); + constants$22.const$3.set(seg.asSlice(index*sizeof()), x); } - public static CreateInterfaceAsyncPort CreateInterfaceAsyncPort(MemorySegment segment, SegmentScope scope) { + public static CreateInterfaceAsyncPort CreateInterfaceAsyncPort(MemorySegment segment, Arena scope) { return CreateInterfaceAsyncPort.ofAddress(CreateInterfaceAsyncPort$get(segment), scope); } - static final FunctionDescriptor GetInterfaceAsyncPort$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetInterfaceAsyncPort$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetInterfaceAsyncPort$FUNC - ); /** * {@snippet : * mach_port_t (*GetInterfaceAsyncPort)(void*); @@ -539,14 +420,14 @@ public static CreateInterfaceAsyncPort CreateInterfaceAsyncPort(MemorySegment se public interface GetInterfaceAsyncPort { int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(GetInterfaceAsyncPort fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetInterfaceAsyncPort.class, fi, IOUSBInterfaceStruct190.GetInterfaceAsyncPort$FUNC, scope); + static MemorySegment allocate(GetInterfaceAsyncPort fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$22.const$4, fi, constants$5.const$5, scope); } - static GetInterfaceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetInterfaceAsyncPort ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBInterfaceStruct190.GetInterfaceAsyncPort$MH.invokeExact(symbol, __x0); + return (int)constants$6.const$1.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -554,9 +435,8 @@ static GetInterfaceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetInterfaceAsyncPort$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceAsyncPort")); public static VarHandle GetInterfaceAsyncPort$VH() { - return IOUSBInterfaceStruct190.GetInterfaceAsyncPort$VH; + return constants$22.const$5; } /** * Getter for field: @@ -565,7 +445,7 @@ static GetInterfaceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetInterfaceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceAsyncPort$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$22.const$5.get(seg); } /** * Setter for field: @@ -574,23 +454,17 @@ static GetInterfaceAsyncPort ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetInterfaceAsyncPort$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetInterfaceAsyncPort$VH.set(seg, x); + constants$22.const$5.set(seg, x); } public static MemorySegment GetInterfaceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceAsyncPort$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$22.const$5.get(seg.asSlice(index*sizeof())); } public static void GetInterfaceAsyncPort$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetInterfaceAsyncPort$VH.set(seg.asSlice(index*sizeof()), x); + constants$22.const$5.set(seg.asSlice(index*sizeof()), x); } - public static GetInterfaceAsyncPort GetInterfaceAsyncPort(MemorySegment segment, SegmentScope scope) { + public static GetInterfaceAsyncPort GetInterfaceAsyncPort(MemorySegment segment, Arena scope) { return GetInterfaceAsyncPort.ofAddress(GetInterfaceAsyncPort$get(segment), scope); } - static final FunctionDescriptor USBInterfaceOpen$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBInterfaceOpen$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.USBInterfaceOpen$FUNC - ); /** * {@snippet : * IOReturn (*USBInterfaceOpen)(void*); @@ -599,14 +473,14 @@ public static GetInterfaceAsyncPort GetInterfaceAsyncPort(MemorySegment segment, public interface USBInterfaceOpen { int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(USBInterfaceOpen fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBInterfaceOpen.class, fi, IOUSBInterfaceStruct190.USBInterfaceOpen$FUNC, scope); + static MemorySegment allocate(USBInterfaceOpen fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$23.const$0, fi, constants$5.const$5, scope); } - static USBInterfaceOpen ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static USBInterfaceOpen ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBInterfaceStruct190.USBInterfaceOpen$MH.invokeExact(symbol, __x0); + return (int)constants$6.const$1.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -614,9 +488,8 @@ static USBInterfaceOpen ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle USBInterfaceOpen$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceOpen")); public static VarHandle USBInterfaceOpen$VH() { - return IOUSBInterfaceStruct190.USBInterfaceOpen$VH; + return constants$23.const$1; } /** * Getter for field: @@ -625,7 +498,7 @@ static USBInterfaceOpen ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment USBInterfaceOpen$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.USBInterfaceOpen$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$23.const$1.get(seg); } /** * Setter for field: @@ -634,23 +507,17 @@ static USBInterfaceOpen ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void USBInterfaceOpen$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.USBInterfaceOpen$VH.set(seg, x); + constants$23.const$1.set(seg, x); } public static MemorySegment USBInterfaceOpen$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.USBInterfaceOpen$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$23.const$1.get(seg.asSlice(index*sizeof())); } public static void USBInterfaceOpen$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.USBInterfaceOpen$VH.set(seg.asSlice(index*sizeof()), x); + constants$23.const$1.set(seg.asSlice(index*sizeof()), x); } - public static USBInterfaceOpen USBInterfaceOpen(MemorySegment segment, SegmentScope scope) { + public static USBInterfaceOpen USBInterfaceOpen(MemorySegment segment, Arena scope) { return USBInterfaceOpen.ofAddress(USBInterfaceOpen$get(segment), scope); } - static final FunctionDescriptor USBInterfaceClose$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBInterfaceClose$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.USBInterfaceClose$FUNC - ); /** * {@snippet : * IOReturn (*USBInterfaceClose)(void*); @@ -659,14 +526,14 @@ public static USBInterfaceOpen USBInterfaceOpen(MemorySegment segment, SegmentSc public interface USBInterfaceClose { int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(USBInterfaceClose fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBInterfaceClose.class, fi, IOUSBInterfaceStruct190.USBInterfaceClose$FUNC, scope); + static MemorySegment allocate(USBInterfaceClose fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$23.const$2, fi, constants$5.const$5, scope); } - static USBInterfaceClose ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static USBInterfaceClose ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBInterfaceStruct190.USBInterfaceClose$MH.invokeExact(symbol, __x0); + return (int)constants$6.const$1.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -674,9 +541,8 @@ static USBInterfaceClose ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle USBInterfaceClose$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceClose")); public static VarHandle USBInterfaceClose$VH() { - return IOUSBInterfaceStruct190.USBInterfaceClose$VH; + return constants$23.const$3; } /** * Getter for field: @@ -685,7 +551,7 @@ static USBInterfaceClose ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment USBInterfaceClose$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.USBInterfaceClose$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$23.const$3.get(seg); } /** * Setter for field: @@ -694,24 +560,17 @@ static USBInterfaceClose ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void USBInterfaceClose$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.USBInterfaceClose$VH.set(seg, x); + constants$23.const$3.set(seg, x); } public static MemorySegment USBInterfaceClose$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.USBInterfaceClose$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$23.const$3.get(seg.asSlice(index*sizeof())); } public static void USBInterfaceClose$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.USBInterfaceClose$VH.set(seg.asSlice(index*sizeof()), x); + constants$23.const$3.set(seg.asSlice(index*sizeof()), x); } - public static USBInterfaceClose USBInterfaceClose(MemorySegment segment, SegmentScope scope) { + public static USBInterfaceClose USBInterfaceClose(MemorySegment segment, Arena scope) { return USBInterfaceClose.ofAddress(USBInterfaceClose$get(segment), scope); } - static final FunctionDescriptor GetInterfaceClass$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetInterfaceClass$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetInterfaceClass$FUNC - ); /** * {@snippet : * IOReturn (*GetInterfaceClass)(void*,UInt8*); @@ -720,14 +579,14 @@ public static USBInterfaceClose USBInterfaceClose(MemorySegment segment, Segment public interface GetInterfaceClass { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetInterfaceClass fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetInterfaceClass.class, fi, IOUSBInterfaceStruct190.GetInterfaceClass$FUNC, scope); + static MemorySegment allocate(GetInterfaceClass fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$23.const$4, fi, constants$6.const$5, scope); } - static GetInterfaceClass ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetInterfaceClass ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetInterfaceClass$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -735,9 +594,8 @@ static GetInterfaceClass ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetInterfaceClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceClass")); public static VarHandle GetInterfaceClass$VH() { - return IOUSBInterfaceStruct190.GetInterfaceClass$VH; + return constants$23.const$5; } /** * Getter for field: @@ -746,7 +604,7 @@ static GetInterfaceClass ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetInterfaceClass$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceClass$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$23.const$5.get(seg); } /** * Setter for field: @@ -755,24 +613,17 @@ static GetInterfaceClass ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetInterfaceClass$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetInterfaceClass$VH.set(seg, x); + constants$23.const$5.set(seg, x); } public static MemorySegment GetInterfaceClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceClass$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$23.const$5.get(seg.asSlice(index*sizeof())); } public static void GetInterfaceClass$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetInterfaceClass$VH.set(seg.asSlice(index*sizeof()), x); + constants$23.const$5.set(seg.asSlice(index*sizeof()), x); } - public static GetInterfaceClass GetInterfaceClass(MemorySegment segment, SegmentScope scope) { + public static GetInterfaceClass GetInterfaceClass(MemorySegment segment, Arena scope) { return GetInterfaceClass.ofAddress(GetInterfaceClass$get(segment), scope); } - static final FunctionDescriptor GetInterfaceSubClass$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetInterfaceSubClass$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetInterfaceSubClass$FUNC - ); /** * {@snippet : * IOReturn (*GetInterfaceSubClass)(void*,UInt8*); @@ -781,14 +632,14 @@ public static GetInterfaceClass GetInterfaceClass(MemorySegment segment, Segment public interface GetInterfaceSubClass { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetInterfaceSubClass fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetInterfaceSubClass.class, fi, IOUSBInterfaceStruct190.GetInterfaceSubClass$FUNC, scope); + static MemorySegment allocate(GetInterfaceSubClass fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$24.const$0, fi, constants$6.const$5, scope); } - static GetInterfaceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetInterfaceSubClass ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetInterfaceSubClass$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -796,9 +647,8 @@ static GetInterfaceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetInterfaceSubClass$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceSubClass")); public static VarHandle GetInterfaceSubClass$VH() { - return IOUSBInterfaceStruct190.GetInterfaceSubClass$VH; + return constants$24.const$1; } /** * Getter for field: @@ -807,7 +657,7 @@ static GetInterfaceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetInterfaceSubClass$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceSubClass$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$24.const$1.get(seg); } /** * Setter for field: @@ -816,24 +666,17 @@ static GetInterfaceSubClass ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetInterfaceSubClass$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetInterfaceSubClass$VH.set(seg, x); + constants$24.const$1.set(seg, x); } public static MemorySegment GetInterfaceSubClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceSubClass$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$24.const$1.get(seg.asSlice(index*sizeof())); } public static void GetInterfaceSubClass$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetInterfaceSubClass$VH.set(seg.asSlice(index*sizeof()), x); + constants$24.const$1.set(seg.asSlice(index*sizeof()), x); } - public static GetInterfaceSubClass GetInterfaceSubClass(MemorySegment segment, SegmentScope scope) { + public static GetInterfaceSubClass GetInterfaceSubClass(MemorySegment segment, Arena scope) { return GetInterfaceSubClass.ofAddress(GetInterfaceSubClass$get(segment), scope); } - static final FunctionDescriptor GetInterfaceProtocol$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetInterfaceProtocol$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetInterfaceProtocol$FUNC - ); /** * {@snippet : * IOReturn (*GetInterfaceProtocol)(void*,UInt8*); @@ -842,14 +685,14 @@ public static GetInterfaceSubClass GetInterfaceSubClass(MemorySegment segment, S public interface GetInterfaceProtocol { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetInterfaceProtocol fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetInterfaceProtocol.class, fi, IOUSBInterfaceStruct190.GetInterfaceProtocol$FUNC, scope); + static MemorySegment allocate(GetInterfaceProtocol fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$24.const$2, fi, constants$6.const$5, scope); } - static GetInterfaceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetInterfaceProtocol ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetInterfaceProtocol$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -857,9 +700,8 @@ static GetInterfaceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetInterfaceProtocol$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceProtocol")); public static VarHandle GetInterfaceProtocol$VH() { - return IOUSBInterfaceStruct190.GetInterfaceProtocol$VH; + return constants$24.const$3; } /** * Getter for field: @@ -868,7 +710,7 @@ static GetInterfaceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetInterfaceProtocol$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceProtocol$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$24.const$3.get(seg); } /** * Setter for field: @@ -877,24 +719,17 @@ static GetInterfaceProtocol ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetInterfaceProtocol$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetInterfaceProtocol$VH.set(seg, x); + constants$24.const$3.set(seg, x); } public static MemorySegment GetInterfaceProtocol$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceProtocol$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$24.const$3.get(seg.asSlice(index*sizeof())); } public static void GetInterfaceProtocol$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetInterfaceProtocol$VH.set(seg.asSlice(index*sizeof()), x); + constants$24.const$3.set(seg.asSlice(index*sizeof()), x); } - public static GetInterfaceProtocol GetInterfaceProtocol(MemorySegment segment, SegmentScope scope) { + public static GetInterfaceProtocol GetInterfaceProtocol(MemorySegment segment, Arena scope) { return GetInterfaceProtocol.ofAddress(GetInterfaceProtocol$get(segment), scope); } - static final FunctionDescriptor GetDeviceVendor$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceVendor$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetDeviceVendor$FUNC - ); /** * {@snippet : * IOReturn (*GetDeviceVendor)(void*,UInt16*); @@ -903,14 +738,14 @@ public static GetInterfaceProtocol GetInterfaceProtocol(MemorySegment segment, S public interface GetDeviceVendor { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceVendor fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceVendor.class, fi, IOUSBInterfaceStruct190.GetDeviceVendor$FUNC, scope); + static MemorySegment allocate(GetDeviceVendor fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$24.const$4, fi, constants$6.const$5, scope); } - static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetDeviceVendor ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetDeviceVendor$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -918,9 +753,8 @@ static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetDeviceVendor$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceVendor")); public static VarHandle GetDeviceVendor$VH() { - return IOUSBInterfaceStruct190.GetDeviceVendor$VH; + return constants$24.const$5; } /** * Getter for field: @@ -929,7 +763,7 @@ static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceVendor$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetDeviceVendor$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$24.const$5.get(seg); } /** * Setter for field: @@ -938,24 +772,17 @@ static GetDeviceVendor ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceVendor$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetDeviceVendor$VH.set(seg, x); + constants$24.const$5.set(seg, x); } public static MemorySegment GetDeviceVendor$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetDeviceVendor$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$24.const$5.get(seg.asSlice(index*sizeof())); } public static void GetDeviceVendor$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetDeviceVendor$VH.set(seg.asSlice(index*sizeof()), x); + constants$24.const$5.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceVendor GetDeviceVendor(MemorySegment segment, SegmentScope scope) { + public static GetDeviceVendor GetDeviceVendor(MemorySegment segment, Arena scope) { return GetDeviceVendor.ofAddress(GetDeviceVendor$get(segment), scope); } - static final FunctionDescriptor GetDeviceProduct$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceProduct$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetDeviceProduct$FUNC - ); /** * {@snippet : * IOReturn (*GetDeviceProduct)(void*,UInt16*); @@ -964,14 +791,14 @@ public static GetDeviceVendor GetDeviceVendor(MemorySegment segment, SegmentScop public interface GetDeviceProduct { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceProduct fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceProduct.class, fi, IOUSBInterfaceStruct190.GetDeviceProduct$FUNC, scope); + static MemorySegment allocate(GetDeviceProduct fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$25.const$0, fi, constants$6.const$5, scope); } - static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetDeviceProduct ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetDeviceProduct$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -979,9 +806,8 @@ static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetDeviceProduct$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProduct")); public static VarHandle GetDeviceProduct$VH() { - return IOUSBInterfaceStruct190.GetDeviceProduct$VH; + return constants$25.const$1; } /** * Getter for field: @@ -990,7 +816,7 @@ static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDeviceProduct$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetDeviceProduct$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$25.const$1.get(seg); } /** * Setter for field: @@ -999,24 +825,17 @@ static GetDeviceProduct ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDeviceProduct$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetDeviceProduct$VH.set(seg, x); + constants$25.const$1.set(seg, x); } public static MemorySegment GetDeviceProduct$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetDeviceProduct$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$25.const$1.get(seg.asSlice(index*sizeof())); } public static void GetDeviceProduct$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetDeviceProduct$VH.set(seg.asSlice(index*sizeof()), x); + constants$25.const$1.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceProduct GetDeviceProduct(MemorySegment segment, SegmentScope scope) { + public static GetDeviceProduct GetDeviceProduct(MemorySegment segment, Arena scope) { return GetDeviceProduct.ofAddress(GetDeviceProduct$get(segment), scope); } - static final FunctionDescriptor GetDeviceReleaseNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDeviceReleaseNumber$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetDeviceReleaseNumber$FUNC - ); /** * {@snippet : * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); @@ -1025,14 +844,14 @@ public static GetDeviceProduct GetDeviceProduct(MemorySegment segment, SegmentSc public interface GetDeviceReleaseNumber { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceReleaseNumber fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDeviceReleaseNumber.class, fi, IOUSBInterfaceStruct190.GetDeviceReleaseNumber$FUNC, scope); + static MemorySegment allocate(GetDeviceReleaseNumber fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$25.const$2, fi, constants$6.const$5, scope); } - static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetDeviceReleaseNumber ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetDeviceReleaseNumber$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1040,9 +859,8 @@ static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) } } - static final VarHandle GetDeviceReleaseNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceReleaseNumber")); public static VarHandle GetDeviceReleaseNumber$VH() { - return IOUSBInterfaceStruct190.GetDeviceReleaseNumber$VH; + return constants$25.const$3; } /** * Getter for field: @@ -1051,7 +869,7 @@ static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static MemorySegment GetDeviceReleaseNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetDeviceReleaseNumber$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$25.const$3.get(seg); } /** * Setter for field: @@ -1060,24 +878,17 @@ static GetDeviceReleaseNumber ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static void GetDeviceReleaseNumber$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetDeviceReleaseNumber$VH.set(seg, x); + constants$25.const$3.set(seg, x); } public static MemorySegment GetDeviceReleaseNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetDeviceReleaseNumber$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$25.const$3.get(seg.asSlice(index*sizeof())); } public static void GetDeviceReleaseNumber$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetDeviceReleaseNumber$VH.set(seg.asSlice(index*sizeof()), x); + constants$25.const$3.set(seg.asSlice(index*sizeof()), x); } - public static GetDeviceReleaseNumber GetDeviceReleaseNumber(MemorySegment segment, SegmentScope scope) { + public static GetDeviceReleaseNumber GetDeviceReleaseNumber(MemorySegment segment, Arena scope) { return GetDeviceReleaseNumber.ofAddress(GetDeviceReleaseNumber$get(segment), scope); } - static final FunctionDescriptor GetConfigurationValue$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetConfigurationValue$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetConfigurationValue$FUNC - ); /** * {@snippet : * IOReturn (*GetConfigurationValue)(void*,UInt8*); @@ -1086,14 +897,14 @@ public static GetDeviceReleaseNumber GetDeviceReleaseNumber(MemorySegment segmen public interface GetConfigurationValue { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetConfigurationValue fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetConfigurationValue.class, fi, IOUSBInterfaceStruct190.GetConfigurationValue$FUNC, scope); + static MemorySegment allocate(GetConfigurationValue fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$25.const$4, fi, constants$6.const$5, scope); } - static GetConfigurationValue ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetConfigurationValue ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetConfigurationValue$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1101,9 +912,8 @@ static GetConfigurationValue ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetConfigurationValue$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetConfigurationValue")); public static VarHandle GetConfigurationValue$VH() { - return IOUSBInterfaceStruct190.GetConfigurationValue$VH; + return constants$25.const$5; } /** * Getter for field: @@ -1112,7 +922,7 @@ static GetConfigurationValue ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetConfigurationValue$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetConfigurationValue$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$25.const$5.get(seg); } /** * Setter for field: @@ -1121,24 +931,17 @@ static GetConfigurationValue ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetConfigurationValue$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetConfigurationValue$VH.set(seg, x); + constants$25.const$5.set(seg, x); } public static MemorySegment GetConfigurationValue$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetConfigurationValue$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$25.const$5.get(seg.asSlice(index*sizeof())); } public static void GetConfigurationValue$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetConfigurationValue$VH.set(seg.asSlice(index*sizeof()), x); + constants$25.const$5.set(seg.asSlice(index*sizeof()), x); } - public static GetConfigurationValue GetConfigurationValue(MemorySegment segment, SegmentScope scope) { + public static GetConfigurationValue GetConfigurationValue(MemorySegment segment, Arena scope) { return GetConfigurationValue.ofAddress(GetConfigurationValue$get(segment), scope); } - static final FunctionDescriptor GetInterfaceNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetInterfaceNumber$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetInterfaceNumber$FUNC - ); /** * {@snippet : * IOReturn (*GetInterfaceNumber)(void*,UInt8*); @@ -1147,14 +950,14 @@ public static GetConfigurationValue GetConfigurationValue(MemorySegment segment, public interface GetInterfaceNumber { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetInterfaceNumber fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetInterfaceNumber.class, fi, IOUSBInterfaceStruct190.GetInterfaceNumber$FUNC, scope); + static MemorySegment allocate(GetInterfaceNumber fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$26.const$0, fi, constants$6.const$5, scope); } - static GetInterfaceNumber ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetInterfaceNumber ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetInterfaceNumber$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1162,9 +965,8 @@ static GetInterfaceNumber ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetInterfaceNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceNumber")); public static VarHandle GetInterfaceNumber$VH() { - return IOUSBInterfaceStruct190.GetInterfaceNumber$VH; + return constants$26.const$1; } /** * Getter for field: @@ -1173,7 +975,7 @@ static GetInterfaceNumber ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetInterfaceNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceNumber$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$26.const$1.get(seg); } /** * Setter for field: @@ -1182,24 +984,17 @@ static GetInterfaceNumber ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetInterfaceNumber$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetInterfaceNumber$VH.set(seg, x); + constants$26.const$1.set(seg, x); } public static MemorySegment GetInterfaceNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetInterfaceNumber$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$26.const$1.get(seg.asSlice(index*sizeof())); } public static void GetInterfaceNumber$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetInterfaceNumber$VH.set(seg.asSlice(index*sizeof()), x); + constants$26.const$1.set(seg.asSlice(index*sizeof()), x); } - public static GetInterfaceNumber GetInterfaceNumber(MemorySegment segment, SegmentScope scope) { + public static GetInterfaceNumber GetInterfaceNumber(MemorySegment segment, Arena scope) { return GetInterfaceNumber.ofAddress(GetInterfaceNumber$get(segment), scope); } - static final FunctionDescriptor GetAlternateSetting$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetAlternateSetting$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetAlternateSetting$FUNC - ); /** * {@snippet : * IOReturn (*GetAlternateSetting)(void*,UInt8*); @@ -1208,14 +1003,14 @@ public static GetInterfaceNumber GetInterfaceNumber(MemorySegment segment, Segme public interface GetAlternateSetting { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetAlternateSetting fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetAlternateSetting.class, fi, IOUSBInterfaceStruct190.GetAlternateSetting$FUNC, scope); + static MemorySegment allocate(GetAlternateSetting fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$26.const$2, fi, constants$6.const$5, scope); } - static GetAlternateSetting ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetAlternateSetting ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetAlternateSetting$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1223,9 +1018,8 @@ static GetAlternateSetting ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetAlternateSetting$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetAlternateSetting")); public static VarHandle GetAlternateSetting$VH() { - return IOUSBInterfaceStruct190.GetAlternateSetting$VH; + return constants$26.const$3; } /** * Getter for field: @@ -1234,7 +1028,7 @@ static GetAlternateSetting ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetAlternateSetting$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetAlternateSetting$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$26.const$3.get(seg); } /** * Setter for field: @@ -1243,24 +1037,17 @@ static GetAlternateSetting ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetAlternateSetting$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetAlternateSetting$VH.set(seg, x); + constants$26.const$3.set(seg, x); } public static MemorySegment GetAlternateSetting$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetAlternateSetting$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$26.const$3.get(seg.asSlice(index*sizeof())); } public static void GetAlternateSetting$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetAlternateSetting$VH.set(seg.asSlice(index*sizeof()), x); + constants$26.const$3.set(seg.asSlice(index*sizeof()), x); } - public static GetAlternateSetting GetAlternateSetting(MemorySegment segment, SegmentScope scope) { + public static GetAlternateSetting GetAlternateSetting(MemorySegment segment, Arena scope) { return GetAlternateSetting.ofAddress(GetAlternateSetting$get(segment), scope); } - static final FunctionDescriptor GetNumEndpoints$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetNumEndpoints$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetNumEndpoints$FUNC - ); /** * {@snippet : * IOReturn (*GetNumEndpoints)(void*,UInt8*); @@ -1269,14 +1056,14 @@ public static GetAlternateSetting GetAlternateSetting(MemorySegment segment, Seg public interface GetNumEndpoints { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetNumEndpoints fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetNumEndpoints.class, fi, IOUSBInterfaceStruct190.GetNumEndpoints$FUNC, scope); + static MemorySegment allocate(GetNumEndpoints fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$26.const$4, fi, constants$6.const$5, scope); } - static GetNumEndpoints ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetNumEndpoints ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetNumEndpoints$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1284,9 +1071,8 @@ static GetNumEndpoints ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetNumEndpoints$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetNumEndpoints")); public static VarHandle GetNumEndpoints$VH() { - return IOUSBInterfaceStruct190.GetNumEndpoints$VH; + return constants$26.const$5; } /** * Getter for field: @@ -1295,7 +1081,7 @@ static GetNumEndpoints ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetNumEndpoints$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetNumEndpoints$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$26.const$5.get(seg); } /** * Setter for field: @@ -1304,24 +1090,17 @@ static GetNumEndpoints ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetNumEndpoints$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetNumEndpoints$VH.set(seg, x); + constants$26.const$5.set(seg, x); } public static MemorySegment GetNumEndpoints$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetNumEndpoints$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$26.const$5.get(seg.asSlice(index*sizeof())); } public static void GetNumEndpoints$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetNumEndpoints$VH.set(seg.asSlice(index*sizeof()), x); + constants$26.const$5.set(seg.asSlice(index*sizeof()), x); } - public static GetNumEndpoints GetNumEndpoints(MemorySegment segment, SegmentScope scope) { + public static GetNumEndpoints GetNumEndpoints(MemorySegment segment, Arena scope) { return GetNumEndpoints.ofAddress(GetNumEndpoints$get(segment), scope); } - static final FunctionDescriptor GetLocationID$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetLocationID$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetLocationID$FUNC - ); /** * {@snippet : * IOReturn (*GetLocationID)(void*,UInt32*); @@ -1330,14 +1109,14 @@ public static GetNumEndpoints GetNumEndpoints(MemorySegment segment, SegmentScop public interface GetLocationID { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetLocationID fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetLocationID.class, fi, IOUSBInterfaceStruct190.GetLocationID$FUNC, scope); + static MemorySegment allocate(GetLocationID fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$27.const$0, fi, constants$6.const$5, scope); } - static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetLocationID ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetLocationID$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1345,9 +1124,8 @@ static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetLocationID$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetLocationID")); public static VarHandle GetLocationID$VH() { - return IOUSBInterfaceStruct190.GetLocationID$VH; + return constants$27.const$1; } /** * Getter for field: @@ -1356,7 +1134,7 @@ static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetLocationID$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetLocationID$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$27.const$1.get(seg); } /** * Setter for field: @@ -1365,24 +1143,17 @@ static GetLocationID ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetLocationID$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetLocationID$VH.set(seg, x); + constants$27.const$1.set(seg, x); } public static MemorySegment GetLocationID$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetLocationID$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$27.const$1.get(seg.asSlice(index*sizeof())); } public static void GetLocationID$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetLocationID$VH.set(seg.asSlice(index*sizeof()), x); + constants$27.const$1.set(seg.asSlice(index*sizeof()), x); } - public static GetLocationID GetLocationID(MemorySegment segment, SegmentScope scope) { + public static GetLocationID GetLocationID(MemorySegment segment, Arena scope) { return GetLocationID.ofAddress(GetLocationID$get(segment), scope); } - static final FunctionDescriptor GetDevice$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetDevice$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetDevice$FUNC - ); /** * {@snippet : * IOReturn (*GetDevice)(void*,io_service_t*); @@ -1391,14 +1162,14 @@ public static GetLocationID GetLocationID(MemorySegment segment, SegmentScope sc public interface GetDevice { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDevice fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetDevice.class, fi, IOUSBInterfaceStruct190.GetDevice$FUNC, scope); + static MemorySegment allocate(GetDevice fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$27.const$2, fi, constants$6.const$5, scope); } - static GetDevice ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetDevice ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetDevice$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1406,9 +1177,8 @@ static GetDevice ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetDevice$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetDevice")); public static VarHandle GetDevice$VH() { - return IOUSBInterfaceStruct190.GetDevice$VH; + return constants$27.const$3; } /** * Getter for field: @@ -1417,7 +1187,7 @@ static GetDevice ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetDevice$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetDevice$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$27.const$3.get(seg); } /** * Setter for field: @@ -1426,24 +1196,17 @@ static GetDevice ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetDevice$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetDevice$VH.set(seg, x); + constants$27.const$3.set(seg, x); } public static MemorySegment GetDevice$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetDevice$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$27.const$3.get(seg.asSlice(index*sizeof())); } public static void GetDevice$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetDevice$VH.set(seg.asSlice(index*sizeof()), x); + constants$27.const$3.set(seg.asSlice(index*sizeof()), x); } - public static GetDevice GetDevice(MemorySegment segment, SegmentScope scope) { + public static GetDevice GetDevice(MemorySegment segment, Arena scope) { return GetDevice.ofAddress(GetDevice$get(segment), scope); } - static final FunctionDescriptor SetAlternateInterface$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT - ); - static final MethodHandle SetAlternateInterface$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.SetAlternateInterface$FUNC - ); /** * {@snippet : * IOReturn (*SetAlternateInterface)(void*,UInt8); @@ -1452,14 +1215,14 @@ public static GetDevice GetDevice(MemorySegment segment, SegmentScope scope) { public interface SetAlternateInterface { int apply(java.lang.foreign.MemorySegment _x0, byte _x1); - static MemorySegment allocate(SetAlternateInterface fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(SetAlternateInterface.class, fi, IOUSBInterfaceStruct190.SetAlternateInterface$FUNC, scope); + static MemorySegment allocate(SetAlternateInterface fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$27.const$4, fi, constants$14.const$0, scope); } - static SetAlternateInterface ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static SetAlternateInterface ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct190.SetAlternateInterface$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$14.const$2.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1467,9 +1230,8 @@ static SetAlternateInterface ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle SetAlternateInterface$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetAlternateInterface")); public static VarHandle SetAlternateInterface$VH() { - return IOUSBInterfaceStruct190.SetAlternateInterface$VH; + return constants$27.const$5; } /** * Getter for field: @@ -1478,7 +1240,7 @@ static SetAlternateInterface ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment SetAlternateInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.SetAlternateInterface$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$27.const$5.get(seg); } /** * Setter for field: @@ -1487,25 +1249,17 @@ static SetAlternateInterface ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void SetAlternateInterface$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.SetAlternateInterface$VH.set(seg, x); + constants$27.const$5.set(seg, x); } public static MemorySegment SetAlternateInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.SetAlternateInterface$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$27.const$5.get(seg.asSlice(index*sizeof())); } public static void SetAlternateInterface$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.SetAlternateInterface$VH.set(seg.asSlice(index*sizeof()), x); + constants$27.const$5.set(seg.asSlice(index*sizeof()), x); } - public static SetAlternateInterface SetAlternateInterface(MemorySegment segment, SegmentScope scope) { + public static SetAlternateInterface SetAlternateInterface(MemorySegment segment, Arena scope) { return SetAlternateInterface.ofAddress(SetAlternateInterface$get(segment), scope); } - static final FunctionDescriptor GetBusFrameNumber$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetBusFrameNumber$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetBusFrameNumber$FUNC - ); /** * {@snippet : * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); @@ -1514,14 +1268,14 @@ public static SetAlternateInterface SetAlternateInterface(MemorySegment segment, public interface GetBusFrameNumber { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(GetBusFrameNumber fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetBusFrameNumber.class, fi, IOUSBInterfaceStruct190.GetBusFrameNumber$FUNC, scope); + static MemorySegment allocate(GetBusFrameNumber fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$28.const$0, fi, constants$14.const$4, scope); } - static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetBusFrameNumber ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBInterfaceStruct190.GetBusFrameNumber$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)constants$15.const$0.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1529,9 +1283,8 @@ static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetBusFrameNumber$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBusFrameNumber")); public static VarHandle GetBusFrameNumber$VH() { - return IOUSBInterfaceStruct190.GetBusFrameNumber$VH; + return constants$28.const$1; } /** * Getter for field: @@ -1540,7 +1293,7 @@ static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetBusFrameNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetBusFrameNumber$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$28.const$1.get(seg); } /** * Setter for field: @@ -1549,25 +1302,17 @@ static GetBusFrameNumber ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetBusFrameNumber$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetBusFrameNumber$VH.set(seg, x); + constants$28.const$1.set(seg, x); } public static MemorySegment GetBusFrameNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetBusFrameNumber$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$28.const$1.get(seg.asSlice(index*sizeof())); } public static void GetBusFrameNumber$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetBusFrameNumber$VH.set(seg.asSlice(index*sizeof()), x); + constants$28.const$1.set(seg.asSlice(index*sizeof()), x); } - public static GetBusFrameNumber GetBusFrameNumber(MemorySegment segment, SegmentScope scope) { + public static GetBusFrameNumber GetBusFrameNumber(MemorySegment segment, Arena scope) { return GetBusFrameNumber.ofAddress(GetBusFrameNumber$get(segment), scope); } - static final FunctionDescriptor ControlRequest$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle ControlRequest$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.ControlRequest$FUNC - ); /** * {@snippet : * IOReturn (*ControlRequest)(void*,UInt8,IOUSBDevRequest*); @@ -1576,14 +1321,14 @@ public static GetBusFrameNumber GetBusFrameNumber(MemorySegment segment, Segment public interface ControlRequest { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(ControlRequest fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(ControlRequest.class, fi, IOUSBInterfaceStruct190.ControlRequest$FUNC, scope); + static MemorySegment allocate(ControlRequest fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$28.const$2, fi, constants$13.const$0, scope); } - static ControlRequest ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static ControlRequest ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBInterfaceStruct190.ControlRequest$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)constants$13.const$2.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1591,9 +1336,8 @@ static ControlRequest ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle ControlRequest$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ControlRequest")); public static VarHandle ControlRequest$VH() { - return IOUSBInterfaceStruct190.ControlRequest$VH; + return constants$28.const$3; } /** * Getter for field: @@ -1602,7 +1346,7 @@ static ControlRequest ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment ControlRequest$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ControlRequest$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$28.const$3.get(seg); } /** * Setter for field: @@ -1611,27 +1355,17 @@ static ControlRequest ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void ControlRequest$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.ControlRequest$VH.set(seg, x); + constants$28.const$3.set(seg, x); } public static MemorySegment ControlRequest$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ControlRequest$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$28.const$3.get(seg.asSlice(index*sizeof())); } public static void ControlRequest$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.ControlRequest$VH.set(seg.asSlice(index*sizeof()), x); + constants$28.const$3.set(seg.asSlice(index*sizeof()), x); } - public static ControlRequest ControlRequest(MemorySegment segment, SegmentScope scope) { + public static ControlRequest ControlRequest(MemorySegment segment, Arena scope) { return ControlRequest.ofAddress(ControlRequest$get(segment), scope); } - static final FunctionDescriptor ControlRequestAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle ControlRequestAsync$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.ControlRequestAsync$FUNC - ); /** * {@snippet : * IOReturn (*ControlRequestAsync)(void*,UInt8,IOUSBDevRequest*,IOAsyncCallback1,void*); @@ -1640,14 +1374,14 @@ public static ControlRequest ControlRequest(MemorySegment segment, SegmentScope public interface ControlRequestAsync { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3, java.lang.foreign.MemorySegment _x4); - static MemorySegment allocate(ControlRequestAsync fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(ControlRequestAsync.class, fi, IOUSBInterfaceStruct190.ControlRequestAsync$FUNC, scope); + static MemorySegment allocate(ControlRequestAsync fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$28.const$5, fi, constants$28.const$4, scope); } - static ControlRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static ControlRequestAsync ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3, java.lang.foreign.MemorySegment __x4) -> { try { - return (int)IOUSBInterfaceStruct190.ControlRequestAsync$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4); + return (int)constants$29.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1655,9 +1389,8 @@ static ControlRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle ControlRequestAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ControlRequestAsync")); public static VarHandle ControlRequestAsync$VH() { - return IOUSBInterfaceStruct190.ControlRequestAsync$VH; + return constants$29.const$1; } /** * Getter for field: @@ -1666,7 +1399,7 @@ static ControlRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment ControlRequestAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ControlRequestAsync$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$29.const$1.get(seg); } /** * Setter for field: @@ -1675,29 +1408,17 @@ static ControlRequestAsync ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void ControlRequestAsync$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.ControlRequestAsync$VH.set(seg, x); + constants$29.const$1.set(seg, x); } public static MemorySegment ControlRequestAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ControlRequestAsync$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$29.const$1.get(seg.asSlice(index*sizeof())); } public static void ControlRequestAsync$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.ControlRequestAsync$VH.set(seg.asSlice(index*sizeof()), x); + constants$29.const$1.set(seg.asSlice(index*sizeof()), x); } - public static ControlRequestAsync ControlRequestAsync(MemorySegment segment, SegmentScope scope) { + public static ControlRequestAsync ControlRequestAsync(MemorySegment segment, Arena scope) { return ControlRequestAsync.ofAddress(ControlRequestAsync$get(segment), scope); } - static final FunctionDescriptor GetPipeProperties$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetPipeProperties$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetPipeProperties$FUNC - ); /** * {@snippet : * IOReturn (*GetPipeProperties)(void*,UInt8,UInt8*,UInt8*,UInt8*,UInt16*,UInt8*); @@ -1706,14 +1427,14 @@ public static ControlRequestAsync ControlRequestAsync(MemorySegment segment, Seg public interface GetPipeProperties { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3, java.lang.foreign.MemorySegment _x4, java.lang.foreign.MemorySegment _x5, java.lang.foreign.MemorySegment _x6); - static MemorySegment allocate(GetPipeProperties fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetPipeProperties.class, fi, IOUSBInterfaceStruct190.GetPipeProperties$FUNC, scope); + static MemorySegment allocate(GetPipeProperties fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$29.const$3, fi, constants$29.const$2, scope); } - static GetPipeProperties ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetPipeProperties ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3, java.lang.foreign.MemorySegment __x4, java.lang.foreign.MemorySegment __x5, java.lang.foreign.MemorySegment __x6) -> { try { - return (int)IOUSBInterfaceStruct190.GetPipeProperties$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6); + return (int)constants$29.const$4.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1721,9 +1442,8 @@ static GetPipeProperties ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetPipeProperties$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetPipeProperties")); public static VarHandle GetPipeProperties$VH() { - return IOUSBInterfaceStruct190.GetPipeProperties$VH; + return constants$29.const$5; } /** * Getter for field: @@ -1732,7 +1452,7 @@ static GetPipeProperties ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetPipeProperties$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetPipeProperties$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$29.const$5.get(seg); } /** * Setter for field: @@ -1741,24 +1461,17 @@ static GetPipeProperties ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetPipeProperties$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetPipeProperties$VH.set(seg, x); + constants$29.const$5.set(seg, x); } public static MemorySegment GetPipeProperties$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetPipeProperties$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$29.const$5.get(seg.asSlice(index*sizeof())); } public static void GetPipeProperties$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetPipeProperties$VH.set(seg.asSlice(index*sizeof()), x); + constants$29.const$5.set(seg.asSlice(index*sizeof()), x); } - public static GetPipeProperties GetPipeProperties(MemorySegment segment, SegmentScope scope) { + public static GetPipeProperties GetPipeProperties(MemorySegment segment, Arena scope) { return GetPipeProperties.ofAddress(GetPipeProperties$get(segment), scope); } - static final FunctionDescriptor GetPipeStatus$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT - ); - static final MethodHandle GetPipeStatus$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetPipeStatus$FUNC - ); /** * {@snippet : * IOReturn (*GetPipeStatus)(void*,UInt8); @@ -1767,14 +1480,14 @@ public static GetPipeProperties GetPipeProperties(MemorySegment segment, Segment public interface GetPipeStatus { int apply(java.lang.foreign.MemorySegment _x0, byte _x1); - static MemorySegment allocate(GetPipeStatus fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetPipeStatus.class, fi, IOUSBInterfaceStruct190.GetPipeStatus$FUNC, scope); + static MemorySegment allocate(GetPipeStatus fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$30.const$0, fi, constants$14.const$0, scope); } - static GetPipeStatus ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetPipeStatus ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetPipeStatus$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$14.const$2.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1782,9 +1495,8 @@ static GetPipeStatus ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetPipeStatus$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetPipeStatus")); public static VarHandle GetPipeStatus$VH() { - return IOUSBInterfaceStruct190.GetPipeStatus$VH; + return constants$30.const$1; } /** * Getter for field: @@ -1793,7 +1505,7 @@ static GetPipeStatus ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetPipeStatus$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetPipeStatus$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$30.const$1.get(seg); } /** * Setter for field: @@ -1802,24 +1514,17 @@ static GetPipeStatus ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetPipeStatus$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetPipeStatus$VH.set(seg, x); + constants$30.const$1.set(seg, x); } public static MemorySegment GetPipeStatus$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetPipeStatus$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$30.const$1.get(seg.asSlice(index*sizeof())); } public static void GetPipeStatus$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetPipeStatus$VH.set(seg.asSlice(index*sizeof()), x); + constants$30.const$1.set(seg.asSlice(index*sizeof()), x); } - public static GetPipeStatus GetPipeStatus(MemorySegment segment, SegmentScope scope) { + public static GetPipeStatus GetPipeStatus(MemorySegment segment, Arena scope) { return GetPipeStatus.ofAddress(GetPipeStatus$get(segment), scope); } - static final FunctionDescriptor AbortPipe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT - ); - static final MethodHandle AbortPipe$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.AbortPipe$FUNC - ); /** * {@snippet : * IOReturn (*AbortPipe)(void*,UInt8); @@ -1828,14 +1533,14 @@ public static GetPipeStatus GetPipeStatus(MemorySegment segment, SegmentScope sc public interface AbortPipe { int apply(java.lang.foreign.MemorySegment _x0, byte _x1); - static MemorySegment allocate(AbortPipe fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(AbortPipe.class, fi, IOUSBInterfaceStruct190.AbortPipe$FUNC, scope); + static MemorySegment allocate(AbortPipe fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$30.const$2, fi, constants$14.const$0, scope); } - static AbortPipe ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static AbortPipe ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct190.AbortPipe$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$14.const$2.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1843,9 +1548,8 @@ static AbortPipe ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle AbortPipe$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("AbortPipe")); public static VarHandle AbortPipe$VH() { - return IOUSBInterfaceStruct190.AbortPipe$VH; + return constants$30.const$3; } /** * Getter for field: @@ -1854,7 +1558,7 @@ static AbortPipe ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment AbortPipe$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.AbortPipe$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$30.const$3.get(seg); } /** * Setter for field: @@ -1863,24 +1567,17 @@ static AbortPipe ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void AbortPipe$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.AbortPipe$VH.set(seg, x); + constants$30.const$3.set(seg, x); } public static MemorySegment AbortPipe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.AbortPipe$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$30.const$3.get(seg.asSlice(index*sizeof())); } public static void AbortPipe$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.AbortPipe$VH.set(seg.asSlice(index*sizeof()), x); + constants$30.const$3.set(seg.asSlice(index*sizeof()), x); } - public static AbortPipe AbortPipe(MemorySegment segment, SegmentScope scope) { + public static AbortPipe AbortPipe(MemorySegment segment, Arena scope) { return AbortPipe.ofAddress(AbortPipe$get(segment), scope); } - static final FunctionDescriptor ResetPipe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT - ); - static final MethodHandle ResetPipe$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.ResetPipe$FUNC - ); /** * {@snippet : * IOReturn (*ResetPipe)(void*,UInt8); @@ -1889,14 +1586,14 @@ public static AbortPipe AbortPipe(MemorySegment segment, SegmentScope scope) { public interface ResetPipe { int apply(java.lang.foreign.MemorySegment _x0, byte _x1); - static MemorySegment allocate(ResetPipe fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(ResetPipe.class, fi, IOUSBInterfaceStruct190.ResetPipe$FUNC, scope); + static MemorySegment allocate(ResetPipe fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$30.const$4, fi, constants$14.const$0, scope); } - static ResetPipe ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static ResetPipe ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct190.ResetPipe$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$14.const$2.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1904,9 +1601,8 @@ static ResetPipe ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle ResetPipe$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ResetPipe")); public static VarHandle ResetPipe$VH() { - return IOUSBInterfaceStruct190.ResetPipe$VH; + return constants$30.const$5; } /** * Getter for field: @@ -1915,7 +1611,7 @@ static ResetPipe ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment ResetPipe$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ResetPipe$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$30.const$5.get(seg); } /** * Setter for field: @@ -1924,24 +1620,17 @@ static ResetPipe ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void ResetPipe$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.ResetPipe$VH.set(seg, x); + constants$30.const$5.set(seg, x); } public static MemorySegment ResetPipe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ResetPipe$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$30.const$5.get(seg.asSlice(index*sizeof())); } public static void ResetPipe$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.ResetPipe$VH.set(seg.asSlice(index*sizeof()), x); + constants$30.const$5.set(seg.asSlice(index*sizeof()), x); } - public static ResetPipe ResetPipe(MemorySegment segment, SegmentScope scope) { + public static ResetPipe ResetPipe(MemorySegment segment, Arena scope) { return ResetPipe.ofAddress(ResetPipe$get(segment), scope); } - static final FunctionDescriptor ClearPipeStall$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT - ); - static final MethodHandle ClearPipeStall$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.ClearPipeStall$FUNC - ); /** * {@snippet : * IOReturn (*ClearPipeStall)(void*,UInt8); @@ -1950,14 +1639,14 @@ public static ResetPipe ResetPipe(MemorySegment segment, SegmentScope scope) { public interface ClearPipeStall { int apply(java.lang.foreign.MemorySegment _x0, byte _x1); - static MemorySegment allocate(ClearPipeStall fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(ClearPipeStall.class, fi, IOUSBInterfaceStruct190.ClearPipeStall$FUNC, scope); + static MemorySegment allocate(ClearPipeStall fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$31.const$0, fi, constants$14.const$0, scope); } - static ClearPipeStall ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static ClearPipeStall ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct190.ClearPipeStall$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$14.const$2.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1965,9 +1654,8 @@ static ClearPipeStall ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle ClearPipeStall$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ClearPipeStall")); public static VarHandle ClearPipeStall$VH() { - return IOUSBInterfaceStruct190.ClearPipeStall$VH; + return constants$31.const$1; } /** * Getter for field: @@ -1976,7 +1664,7 @@ static ClearPipeStall ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment ClearPipeStall$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ClearPipeStall$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$31.const$1.get(seg); } /** * Setter for field: @@ -1985,26 +1673,17 @@ static ClearPipeStall ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void ClearPipeStall$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.ClearPipeStall$VH.set(seg, x); + constants$31.const$1.set(seg, x); } public static MemorySegment ClearPipeStall$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ClearPipeStall$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$31.const$1.get(seg.asSlice(index*sizeof())); } public static void ClearPipeStall$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.ClearPipeStall$VH.set(seg.asSlice(index*sizeof()), x); + constants$31.const$1.set(seg.asSlice(index*sizeof()), x); } - public static ClearPipeStall ClearPipeStall(MemorySegment segment, SegmentScope scope) { + public static ClearPipeStall ClearPipeStall(MemorySegment segment, Arena scope) { return ClearPipeStall.ofAddress(ClearPipeStall$get(segment), scope); } - static final FunctionDescriptor ReadPipe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle ReadPipe$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.ReadPipe$FUNC - ); /** * {@snippet : * IOReturn (*ReadPipe)(void*,UInt8,void*,UInt32*); @@ -2013,14 +1692,14 @@ public static ClearPipeStall ClearPipeStall(MemorySegment segment, SegmentScope public interface ReadPipe { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3); - static MemorySegment allocate(ReadPipe fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(ReadPipe.class, fi, IOUSBInterfaceStruct190.ReadPipe$FUNC, scope); + static MemorySegment allocate(ReadPipe fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$31.const$3, fi, constants$31.const$2, scope); } - static ReadPipe ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static ReadPipe ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3) -> { try { - return (int)IOUSBInterfaceStruct190.ReadPipe$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); + return (int)constants$31.const$4.invokeExact(symbol, __x0, __x1, __x2, __x3); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2028,9 +1707,8 @@ static ReadPipe ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle ReadPipe$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadPipe")); public static VarHandle ReadPipe$VH() { - return IOUSBInterfaceStruct190.ReadPipe$VH; + return constants$31.const$5; } /** * Getter for field: @@ -2039,7 +1717,7 @@ static ReadPipe ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment ReadPipe$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadPipe$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$31.const$5.get(seg); } /** * Setter for field: @@ -2048,26 +1726,17 @@ static ReadPipe ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void ReadPipe$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.ReadPipe$VH.set(seg, x); + constants$31.const$5.set(seg, x); } public static MemorySegment ReadPipe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadPipe$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$31.const$5.get(seg.asSlice(index*sizeof())); } public static void ReadPipe$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.ReadPipe$VH.set(seg.asSlice(index*sizeof()), x); + constants$31.const$5.set(seg.asSlice(index*sizeof()), x); } - public static ReadPipe ReadPipe(MemorySegment segment, SegmentScope scope) { + public static ReadPipe ReadPipe(MemorySegment segment, Arena scope) { return ReadPipe.ofAddress(ReadPipe$get(segment), scope); } - static final FunctionDescriptor WritePipe$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle WritePipe$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.WritePipe$FUNC - ); /** * {@snippet : * IOReturn (*WritePipe)(void*,UInt8,void*,UInt32); @@ -2076,14 +1745,14 @@ public static ReadPipe ReadPipe(MemorySegment segment, SegmentScope scope) { public interface WritePipe { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3); - static MemorySegment allocate(WritePipe fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(WritePipe.class, fi, IOUSBInterfaceStruct190.WritePipe$FUNC, scope); + static MemorySegment allocate(WritePipe fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$32.const$1, fi, constants$32.const$0, scope); } - static WritePipe ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static WritePipe ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3) -> { try { - return (int)IOUSBInterfaceStruct190.WritePipe$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); + return (int)constants$32.const$2.invokeExact(symbol, __x0, __x1, __x2, __x3); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2091,9 +1760,8 @@ static WritePipe ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle WritePipe$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WritePipe")); public static VarHandle WritePipe$VH() { - return IOUSBInterfaceStruct190.WritePipe$VH; + return constants$32.const$3; } /** * Getter for field: @@ -2102,7 +1770,7 @@ static WritePipe ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment WritePipe$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WritePipe$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$32.const$3.get(seg); } /** * Setter for field: @@ -2111,28 +1779,17 @@ static WritePipe ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void WritePipe$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.WritePipe$VH.set(seg, x); + constants$32.const$3.set(seg, x); } public static MemorySegment WritePipe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WritePipe$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$32.const$3.get(seg.asSlice(index*sizeof())); } public static void WritePipe$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.WritePipe$VH.set(seg.asSlice(index*sizeof()), x); + constants$32.const$3.set(seg.asSlice(index*sizeof()), x); } - public static WritePipe WritePipe(MemorySegment segment, SegmentScope scope) { + public static WritePipe WritePipe(MemorySegment segment, Arena scope) { return WritePipe.ofAddress(WritePipe$get(segment), scope); } - static final FunctionDescriptor ReadPipeAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle ReadPipeAsync$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.ReadPipeAsync$FUNC - ); /** * {@snippet : * IOReturn (*ReadPipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); @@ -2141,14 +1798,14 @@ public static WritePipe WritePipe(MemorySegment segment, SegmentScope scope) { public interface ReadPipeAsync { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3, java.lang.foreign.MemorySegment _x4, java.lang.foreign.MemorySegment _x5); - static MemorySegment allocate(ReadPipeAsync fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(ReadPipeAsync.class, fi, IOUSBInterfaceStruct190.ReadPipeAsync$FUNC, scope); + static MemorySegment allocate(ReadPipeAsync fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$32.const$5, fi, constants$32.const$4, scope); } - static ReadPipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static ReadPipeAsync ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3, java.lang.foreign.MemorySegment __x4, java.lang.foreign.MemorySegment __x5) -> { try { - return (int)IOUSBInterfaceStruct190.ReadPipeAsync$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5); + return (int)constants$33.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2156,9 +1813,8 @@ static ReadPipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle ReadPipeAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadPipeAsync")); public static VarHandle ReadPipeAsync$VH() { - return IOUSBInterfaceStruct190.ReadPipeAsync$VH; + return constants$33.const$1; } /** * Getter for field: @@ -2167,7 +1823,7 @@ static ReadPipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment ReadPipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadPipeAsync$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$33.const$1.get(seg); } /** * Setter for field: @@ -2176,28 +1832,17 @@ static ReadPipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void ReadPipeAsync$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.ReadPipeAsync$VH.set(seg, x); + constants$33.const$1.set(seg, x); } public static MemorySegment ReadPipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadPipeAsync$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$33.const$1.get(seg.asSlice(index*sizeof())); } public static void ReadPipeAsync$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.ReadPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); + constants$33.const$1.set(seg.asSlice(index*sizeof()), x); } - public static ReadPipeAsync ReadPipeAsync(MemorySegment segment, SegmentScope scope) { + public static ReadPipeAsync ReadPipeAsync(MemorySegment segment, Arena scope) { return ReadPipeAsync.ofAddress(ReadPipeAsync$get(segment), scope); } - static final FunctionDescriptor WritePipeAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle WritePipeAsync$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.WritePipeAsync$FUNC - ); /** * {@snippet : * IOReturn (*WritePipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); @@ -2206,14 +1851,14 @@ public static ReadPipeAsync ReadPipeAsync(MemorySegment segment, SegmentScope sc public interface WritePipeAsync { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3, java.lang.foreign.MemorySegment _x4, java.lang.foreign.MemorySegment _x5); - static MemorySegment allocate(WritePipeAsync fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(WritePipeAsync.class, fi, IOUSBInterfaceStruct190.WritePipeAsync$FUNC, scope); + static MemorySegment allocate(WritePipeAsync fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$33.const$2, fi, constants$32.const$4, scope); } - static WritePipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static WritePipeAsync ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3, java.lang.foreign.MemorySegment __x4, java.lang.foreign.MemorySegment __x5) -> { try { - return (int)IOUSBInterfaceStruct190.WritePipeAsync$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5); + return (int)constants$33.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2221,9 +1866,8 @@ static WritePipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle WritePipeAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WritePipeAsync")); public static VarHandle WritePipeAsync$VH() { - return IOUSBInterfaceStruct190.WritePipeAsync$VH; + return constants$33.const$3; } /** * Getter for field: @@ -2232,7 +1876,7 @@ static WritePipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment WritePipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WritePipeAsync$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$33.const$3.get(seg); } /** * Setter for field: @@ -2241,30 +1885,17 @@ static WritePipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void WritePipeAsync$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.WritePipeAsync$VH.set(seg, x); + constants$33.const$3.set(seg, x); } public static MemorySegment WritePipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WritePipeAsync$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$33.const$3.get(seg.asSlice(index*sizeof())); } public static void WritePipeAsync$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.WritePipeAsync$VH.set(seg.asSlice(index*sizeof()), x); + constants$33.const$3.set(seg.asSlice(index*sizeof()), x); } - public static WritePipeAsync WritePipeAsync(MemorySegment segment, SegmentScope scope) { + public static WritePipeAsync WritePipeAsync(MemorySegment segment, Arena scope) { return WritePipeAsync.ofAddress(WritePipeAsync$get(segment), scope); } - static final FunctionDescriptor ReadIsochPipeAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle ReadIsochPipeAsync$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.ReadIsochPipeAsync$FUNC - ); /** * {@snippet : * IOReturn (*ReadIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); @@ -2273,14 +1904,14 @@ public static WritePipeAsync WritePipeAsync(MemorySegment segment, SegmentScope public interface ReadIsochPipeAsync { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, long _x3, int _x4, java.lang.foreign.MemorySegment _x5, java.lang.foreign.MemorySegment _x6, java.lang.foreign.MemorySegment _x7); - static MemorySegment allocate(ReadIsochPipeAsync fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(ReadIsochPipeAsync.class, fi, IOUSBInterfaceStruct190.ReadIsochPipeAsync$FUNC, scope); + static MemorySegment allocate(ReadIsochPipeAsync fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$33.const$5, fi, constants$33.const$4, scope); } - static ReadIsochPipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static ReadIsochPipeAsync ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, long __x3, int __x4, java.lang.foreign.MemorySegment __x5, java.lang.foreign.MemorySegment __x6, java.lang.foreign.MemorySegment __x7) -> { try { - return (int)IOUSBInterfaceStruct190.ReadIsochPipeAsync$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7); + return (int)constants$34.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2288,9 +1919,8 @@ static ReadIsochPipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle ReadIsochPipeAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadIsochPipeAsync")); public static VarHandle ReadIsochPipeAsync$VH() { - return IOUSBInterfaceStruct190.ReadIsochPipeAsync$VH; + return constants$34.const$1; } /** * Getter for field: @@ -2299,7 +1929,7 @@ static ReadIsochPipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment ReadIsochPipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadIsochPipeAsync$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$34.const$1.get(seg); } /** * Setter for field: @@ -2308,30 +1938,17 @@ static ReadIsochPipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void ReadIsochPipeAsync$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.ReadIsochPipeAsync$VH.set(seg, x); + constants$34.const$1.set(seg, x); } public static MemorySegment ReadIsochPipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadIsochPipeAsync$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$34.const$1.get(seg.asSlice(index*sizeof())); } public static void ReadIsochPipeAsync$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.ReadIsochPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); + constants$34.const$1.set(seg.asSlice(index*sizeof()), x); } - public static ReadIsochPipeAsync ReadIsochPipeAsync(MemorySegment segment, SegmentScope scope) { + public static ReadIsochPipeAsync ReadIsochPipeAsync(MemorySegment segment, Arena scope) { return ReadIsochPipeAsync.ofAddress(ReadIsochPipeAsync$get(segment), scope); } - static final FunctionDescriptor WriteIsochPipeAsync$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle WriteIsochPipeAsync$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.WriteIsochPipeAsync$FUNC - ); /** * {@snippet : * IOReturn (*WriteIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); @@ -2340,14 +1957,14 @@ public static ReadIsochPipeAsync ReadIsochPipeAsync(MemorySegment segment, Segme public interface WriteIsochPipeAsync { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, long _x3, int _x4, java.lang.foreign.MemorySegment _x5, java.lang.foreign.MemorySegment _x6, java.lang.foreign.MemorySegment _x7); - static MemorySegment allocate(WriteIsochPipeAsync fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(WriteIsochPipeAsync.class, fi, IOUSBInterfaceStruct190.WriteIsochPipeAsync$FUNC, scope); + static MemorySegment allocate(WriteIsochPipeAsync fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$34.const$2, fi, constants$33.const$4, scope); } - static WriteIsochPipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static WriteIsochPipeAsync ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, long __x3, int __x4, java.lang.foreign.MemorySegment __x5, java.lang.foreign.MemorySegment __x6, java.lang.foreign.MemorySegment __x7) -> { try { - return (int)IOUSBInterfaceStruct190.WriteIsochPipeAsync$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7); + return (int)constants$34.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2355,9 +1972,8 @@ static WriteIsochPipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle WriteIsochPipeAsync$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WriteIsochPipeAsync")); public static VarHandle WriteIsochPipeAsync$VH() { - return IOUSBInterfaceStruct190.WriteIsochPipeAsync$VH; + return constants$34.const$3; } /** * Getter for field: @@ -2366,7 +1982,7 @@ static WriteIsochPipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment WriteIsochPipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WriteIsochPipeAsync$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$34.const$3.get(seg); } /** * Setter for field: @@ -2375,25 +1991,17 @@ static WriteIsochPipeAsync ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void WriteIsochPipeAsync$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.WriteIsochPipeAsync$VH.set(seg, x); + constants$34.const$3.set(seg, x); } public static MemorySegment WriteIsochPipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WriteIsochPipeAsync$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$34.const$3.get(seg.asSlice(index*sizeof())); } public static void WriteIsochPipeAsync$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.WriteIsochPipeAsync$VH.set(seg.asSlice(index*sizeof()), x); + constants$34.const$3.set(seg.asSlice(index*sizeof()), x); } - public static WriteIsochPipeAsync WriteIsochPipeAsync(MemorySegment segment, SegmentScope scope) { + public static WriteIsochPipeAsync WriteIsochPipeAsync(MemorySegment segment, Arena scope) { return WriteIsochPipeAsync.ofAddress(WriteIsochPipeAsync$get(segment), scope); } - static final FunctionDescriptor ControlRequestTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle ControlRequestTO$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.ControlRequestTO$FUNC - ); /** * {@snippet : * IOReturn (*ControlRequestTO)(void*,UInt8,IOUSBDevRequestTO*); @@ -2402,14 +2010,14 @@ public static WriteIsochPipeAsync WriteIsochPipeAsync(MemorySegment segment, Seg public interface ControlRequestTO { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(ControlRequestTO fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(ControlRequestTO.class, fi, IOUSBInterfaceStruct190.ControlRequestTO$FUNC, scope); + static MemorySegment allocate(ControlRequestTO fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$34.const$4, fi, constants$13.const$0, scope); } - static ControlRequestTO ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static ControlRequestTO ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2) -> { try { - return (int)IOUSBInterfaceStruct190.ControlRequestTO$MH.invokeExact(symbol, __x0, __x1, __x2); + return (int)constants$13.const$2.invokeExact(symbol, __x0, __x1, __x2); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2417,9 +2025,8 @@ static ControlRequestTO ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle ControlRequestTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ControlRequestTO")); public static VarHandle ControlRequestTO$VH() { - return IOUSBInterfaceStruct190.ControlRequestTO$VH; + return constants$34.const$5; } /** * Getter for field: @@ -2428,7 +2035,7 @@ static ControlRequestTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment ControlRequestTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ControlRequestTO$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$34.const$5.get(seg); } /** * Setter for field: @@ -2437,27 +2044,17 @@ static ControlRequestTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void ControlRequestTO$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.ControlRequestTO$VH.set(seg, x); + constants$34.const$5.set(seg, x); } public static MemorySegment ControlRequestTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ControlRequestTO$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$34.const$5.get(seg.asSlice(index*sizeof())); } public static void ControlRequestTO$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.ControlRequestTO$VH.set(seg.asSlice(index*sizeof()), x); + constants$34.const$5.set(seg.asSlice(index*sizeof()), x); } - public static ControlRequestTO ControlRequestTO(MemorySegment segment, SegmentScope scope) { + public static ControlRequestTO ControlRequestTO(MemorySegment segment, Arena scope) { return ControlRequestTO.ofAddress(ControlRequestTO$get(segment), scope); } - static final FunctionDescriptor ControlRequestAsyncTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle ControlRequestAsyncTO$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.ControlRequestAsyncTO$FUNC - ); /** * {@snippet : * IOReturn (*ControlRequestAsyncTO)(void*,UInt8,IOUSBDevRequestTO*,IOAsyncCallback1,void*); @@ -2466,14 +2063,14 @@ public static ControlRequestTO ControlRequestTO(MemorySegment segment, SegmentSc public interface ControlRequestAsyncTO { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3, java.lang.foreign.MemorySegment _x4); - static MemorySegment allocate(ControlRequestAsyncTO fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(ControlRequestAsyncTO.class, fi, IOUSBInterfaceStruct190.ControlRequestAsyncTO$FUNC, scope); + static MemorySegment allocate(ControlRequestAsyncTO fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$35.const$0, fi, constants$28.const$4, scope); } - static ControlRequestAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static ControlRequestAsyncTO ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3, java.lang.foreign.MemorySegment __x4) -> { try { - return (int)IOUSBInterfaceStruct190.ControlRequestAsyncTO$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4); + return (int)constants$29.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2481,9 +2078,8 @@ static ControlRequestAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle ControlRequestAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ControlRequestAsyncTO")); public static VarHandle ControlRequestAsyncTO$VH() { - return IOUSBInterfaceStruct190.ControlRequestAsyncTO$VH; + return constants$35.const$1; } /** * Getter for field: @@ -2492,7 +2088,7 @@ static ControlRequestAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment ControlRequestAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ControlRequestAsyncTO$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$35.const$1.get(seg); } /** * Setter for field: @@ -2501,28 +2097,17 @@ static ControlRequestAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void ControlRequestAsyncTO$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.ControlRequestAsyncTO$VH.set(seg, x); + constants$35.const$1.set(seg, x); } public static MemorySegment ControlRequestAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ControlRequestAsyncTO$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$35.const$1.get(seg.asSlice(index*sizeof())); } public static void ControlRequestAsyncTO$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.ControlRequestAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); + constants$35.const$1.set(seg.asSlice(index*sizeof()), x); } - public static ControlRequestAsyncTO ControlRequestAsyncTO(MemorySegment segment, SegmentScope scope) { + public static ControlRequestAsyncTO ControlRequestAsyncTO(MemorySegment segment, Arena scope) { return ControlRequestAsyncTO.ofAddress(ControlRequestAsyncTO$get(segment), scope); } - static final FunctionDescriptor ReadPipeTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle ReadPipeTO$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.ReadPipeTO$FUNC - ); /** * {@snippet : * IOReturn (*ReadPipeTO)(void*,UInt8,void*,UInt32*,UInt32,UInt32); @@ -2531,14 +2116,14 @@ public static ControlRequestAsyncTO ControlRequestAsyncTO(MemorySegment segment, public interface ReadPipeTO { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3, int _x4, int _x5); - static MemorySegment allocate(ReadPipeTO fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(ReadPipeTO.class, fi, IOUSBInterfaceStruct190.ReadPipeTO$FUNC, scope); + static MemorySegment allocate(ReadPipeTO fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$35.const$3, fi, constants$35.const$2, scope); } - static ReadPipeTO ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static ReadPipeTO ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3, int __x4, int __x5) -> { try { - return (int)IOUSBInterfaceStruct190.ReadPipeTO$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5); + return (int)constants$35.const$4.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2546,9 +2131,8 @@ static ReadPipeTO ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle ReadPipeTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadPipeTO")); public static VarHandle ReadPipeTO$VH() { - return IOUSBInterfaceStruct190.ReadPipeTO$VH; + return constants$35.const$5; } /** * Getter for field: @@ -2557,7 +2141,7 @@ static ReadPipeTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment ReadPipeTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadPipeTO$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$35.const$5.get(seg); } /** * Setter for field: @@ -2566,28 +2150,17 @@ static ReadPipeTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void ReadPipeTO$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.ReadPipeTO$VH.set(seg, x); + constants$35.const$5.set(seg, x); } public static MemorySegment ReadPipeTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadPipeTO$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$35.const$5.get(seg.asSlice(index*sizeof())); } public static void ReadPipeTO$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.ReadPipeTO$VH.set(seg.asSlice(index*sizeof()), x); + constants$35.const$5.set(seg.asSlice(index*sizeof()), x); } - public static ReadPipeTO ReadPipeTO(MemorySegment segment, SegmentScope scope) { + public static ReadPipeTO ReadPipeTO(MemorySegment segment, Arena scope) { return ReadPipeTO.ofAddress(ReadPipeTO$get(segment), scope); } - static final FunctionDescriptor WritePipeTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle WritePipeTO$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.WritePipeTO$FUNC - ); /** * {@snippet : * IOReturn (*WritePipeTO)(void*,UInt8,void*,UInt32,UInt32,UInt32); @@ -2596,14 +2169,14 @@ public static ReadPipeTO ReadPipeTO(MemorySegment segment, SegmentScope scope) { public interface WritePipeTO { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3, int _x4, int _x5); - static MemorySegment allocate(WritePipeTO fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(WritePipeTO.class, fi, IOUSBInterfaceStruct190.WritePipeTO$FUNC, scope); + static MemorySegment allocate(WritePipeTO fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$36.const$1, fi, constants$36.const$0, scope); } - static WritePipeTO ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static WritePipeTO ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3, int __x4, int __x5) -> { try { - return (int)IOUSBInterfaceStruct190.WritePipeTO$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5); + return (int)constants$36.const$2.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2611,9 +2184,8 @@ static WritePipeTO ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle WritePipeTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WritePipeTO")); public static VarHandle WritePipeTO$VH() { - return IOUSBInterfaceStruct190.WritePipeTO$VH; + return constants$36.const$3; } /** * Getter for field: @@ -2622,7 +2194,7 @@ static WritePipeTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment WritePipeTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WritePipeTO$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$36.const$3.get(seg); } /** * Setter for field: @@ -2631,30 +2203,17 @@ static WritePipeTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void WritePipeTO$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.WritePipeTO$VH.set(seg, x); + constants$36.const$3.set(seg, x); } public static MemorySegment WritePipeTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WritePipeTO$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$36.const$3.get(seg.asSlice(index*sizeof())); } public static void WritePipeTO$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.WritePipeTO$VH.set(seg.asSlice(index*sizeof()), x); + constants$36.const$3.set(seg.asSlice(index*sizeof()), x); } - public static WritePipeTO WritePipeTO(MemorySegment segment, SegmentScope scope) { + public static WritePipeTO WritePipeTO(MemorySegment segment, Arena scope) { return WritePipeTO.ofAddress(WritePipeTO$get(segment), scope); } - static final FunctionDescriptor ReadPipeAsyncTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle ReadPipeAsyncTO$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.ReadPipeAsyncTO$FUNC - ); /** * {@snippet : * IOReturn (*ReadPipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); @@ -2663,14 +2222,14 @@ public static WritePipeTO WritePipeTO(MemorySegment segment, SegmentScope scope) public interface ReadPipeAsyncTO { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3, int _x4, int _x5, java.lang.foreign.MemorySegment _x6, java.lang.foreign.MemorySegment _x7); - static MemorySegment allocate(ReadPipeAsyncTO fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(ReadPipeAsyncTO.class, fi, IOUSBInterfaceStruct190.ReadPipeAsyncTO$FUNC, scope); + static MemorySegment allocate(ReadPipeAsyncTO fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$36.const$5, fi, constants$36.const$4, scope); } - static ReadPipeAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static ReadPipeAsyncTO ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3, int __x4, int __x5, java.lang.foreign.MemorySegment __x6, java.lang.foreign.MemorySegment __x7) -> { try { - return (int)IOUSBInterfaceStruct190.ReadPipeAsyncTO$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7); + return (int)constants$37.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2678,9 +2237,8 @@ static ReadPipeAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle ReadPipeAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ReadPipeAsyncTO")); public static VarHandle ReadPipeAsyncTO$VH() { - return IOUSBInterfaceStruct190.ReadPipeAsyncTO$VH; + return constants$37.const$1; } /** * Getter for field: @@ -2689,7 +2247,7 @@ static ReadPipeAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment ReadPipeAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadPipeAsyncTO$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$37.const$1.get(seg); } /** * Setter for field: @@ -2698,30 +2256,17 @@ static ReadPipeAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void ReadPipeAsyncTO$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.ReadPipeAsyncTO$VH.set(seg, x); + constants$37.const$1.set(seg, x); } public static MemorySegment ReadPipeAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ReadPipeAsyncTO$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$37.const$1.get(seg.asSlice(index*sizeof())); } public static void ReadPipeAsyncTO$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.ReadPipeAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); + constants$37.const$1.set(seg.asSlice(index*sizeof()), x); } - public static ReadPipeAsyncTO ReadPipeAsyncTO(MemorySegment segment, SegmentScope scope) { + public static ReadPipeAsyncTO ReadPipeAsyncTO(MemorySegment segment, Arena scope) { return ReadPipeAsyncTO.ofAddress(ReadPipeAsyncTO$get(segment), scope); } - static final FunctionDescriptor WritePipeAsyncTO$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle WritePipeAsyncTO$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.WritePipeAsyncTO$FUNC - ); /** * {@snippet : * IOReturn (*WritePipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); @@ -2730,14 +2275,14 @@ public static ReadPipeAsyncTO ReadPipeAsyncTO(MemorySegment segment, SegmentScop public interface WritePipeAsyncTO { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3, int _x4, int _x5, java.lang.foreign.MemorySegment _x6, java.lang.foreign.MemorySegment _x7); - static MemorySegment allocate(WritePipeAsyncTO fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(WritePipeAsyncTO.class, fi, IOUSBInterfaceStruct190.WritePipeAsyncTO$FUNC, scope); + static MemorySegment allocate(WritePipeAsyncTO fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$37.const$2, fi, constants$36.const$4, scope); } - static WritePipeAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static WritePipeAsyncTO ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3, int __x4, int __x5, java.lang.foreign.MemorySegment __x6, java.lang.foreign.MemorySegment __x7) -> { try { - return (int)IOUSBInterfaceStruct190.WritePipeAsyncTO$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7); + return (int)constants$37.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2745,9 +2290,8 @@ static WritePipeAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle WritePipeAsyncTO$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("WritePipeAsyncTO")); public static VarHandle WritePipeAsyncTO$VH() { - return IOUSBInterfaceStruct190.WritePipeAsyncTO$VH; + return constants$37.const$3; } /** * Getter for field: @@ -2756,7 +2300,7 @@ static WritePipeAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment WritePipeAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WritePipeAsyncTO$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$37.const$3.get(seg); } /** * Setter for field: @@ -2765,24 +2309,17 @@ static WritePipeAsyncTO ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void WritePipeAsyncTO$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.WritePipeAsyncTO$VH.set(seg, x); + constants$37.const$3.set(seg, x); } public static MemorySegment WritePipeAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.WritePipeAsyncTO$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$37.const$3.get(seg.asSlice(index*sizeof())); } public static void WritePipeAsyncTO$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.WritePipeAsyncTO$VH.set(seg.asSlice(index*sizeof()), x); + constants$37.const$3.set(seg.asSlice(index*sizeof()), x); } - public static WritePipeAsyncTO WritePipeAsyncTO(MemorySegment segment, SegmentScope scope) { + public static WritePipeAsyncTO WritePipeAsyncTO(MemorySegment segment, Arena scope) { return WritePipeAsyncTO.ofAddress(WritePipeAsyncTO$get(segment), scope); } - static final FunctionDescriptor USBInterfaceGetStringIndex$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBInterfaceGetStringIndex$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$FUNC - ); /** * {@snippet : * IOReturn (*USBInterfaceGetStringIndex)(void*,UInt8*); @@ -2791,14 +2328,14 @@ public static WritePipeAsyncTO WritePipeAsyncTO(MemorySegment segment, SegmentSc public interface USBInterfaceGetStringIndex { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(USBInterfaceGetStringIndex fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBInterfaceGetStringIndex.class, fi, IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$FUNC, scope); + static MemorySegment allocate(USBInterfaceGetStringIndex fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$37.const$4, fi, constants$6.const$5, scope); } - static USBInterfaceGetStringIndex ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static USBInterfaceGetStringIndex ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2806,9 +2343,8 @@ static USBInterfaceGetStringIndex ofAddress(MemorySegment addr, SegmentScope sco } } - static final VarHandle USBInterfaceGetStringIndex$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceGetStringIndex")); public static VarHandle USBInterfaceGetStringIndex$VH() { - return IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$VH; + return constants$37.const$5; } /** * Getter for field: @@ -2817,7 +2353,7 @@ static USBInterfaceGetStringIndex ofAddress(MemorySegment addr, SegmentScope sco * } */ public static MemorySegment USBInterfaceGetStringIndex$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$37.const$5.get(seg); } /** * Setter for field: @@ -2826,23 +2362,17 @@ static USBInterfaceGetStringIndex ofAddress(MemorySegment addr, SegmentScope sco * } */ public static void USBInterfaceGetStringIndex$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$VH.set(seg, x); + constants$37.const$5.set(seg, x); } public static MemorySegment USBInterfaceGetStringIndex$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$37.const$5.get(seg.asSlice(index*sizeof())); } public static void USBInterfaceGetStringIndex$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.USBInterfaceGetStringIndex$VH.set(seg.asSlice(index*sizeof()), x); + constants$37.const$5.set(seg.asSlice(index*sizeof()), x); } - public static USBInterfaceGetStringIndex USBInterfaceGetStringIndex(MemorySegment segment, SegmentScope scope) { + public static USBInterfaceGetStringIndex USBInterfaceGetStringIndex(MemorySegment segment, Arena scope) { return USBInterfaceGetStringIndex.ofAddress(USBInterfaceGetStringIndex$get(segment), scope); } - static final FunctionDescriptor USBInterfaceOpenSeize$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle USBInterfaceOpenSeize$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.USBInterfaceOpenSeize$FUNC - ); /** * {@snippet : * IOReturn (*USBInterfaceOpenSeize)(void*); @@ -2851,14 +2381,14 @@ public static USBInterfaceGetStringIndex USBInterfaceGetStringIndex(MemorySegmen public interface USBInterfaceOpenSeize { int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(USBInterfaceOpenSeize fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(USBInterfaceOpenSeize.class, fi, IOUSBInterfaceStruct190.USBInterfaceOpenSeize$FUNC, scope); + static MemorySegment allocate(USBInterfaceOpenSeize fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$38.const$0, fi, constants$5.const$5, scope); } - static USBInterfaceOpenSeize ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static USBInterfaceOpenSeize ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0) -> { try { - return (int)IOUSBInterfaceStruct190.USBInterfaceOpenSeize$MH.invokeExact(symbol, __x0); + return (int)constants$6.const$1.invokeExact(symbol, __x0); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2866,9 +2396,8 @@ static USBInterfaceOpenSeize ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle USBInterfaceOpenSeize$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceOpenSeize")); public static VarHandle USBInterfaceOpenSeize$VH() { - return IOUSBInterfaceStruct190.USBInterfaceOpenSeize$VH; + return constants$38.const$1; } /** * Getter for field: @@ -2877,7 +2406,7 @@ static USBInterfaceOpenSeize ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment USBInterfaceOpenSeize$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.USBInterfaceOpenSeize$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$38.const$1.get(seg); } /** * Setter for field: @@ -2886,24 +2415,17 @@ static USBInterfaceOpenSeize ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void USBInterfaceOpenSeize$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.USBInterfaceOpenSeize$VH.set(seg, x); + constants$38.const$1.set(seg, x); } public static MemorySegment USBInterfaceOpenSeize$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.USBInterfaceOpenSeize$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$38.const$1.get(seg.asSlice(index*sizeof())); } public static void USBInterfaceOpenSeize$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.USBInterfaceOpenSeize$VH.set(seg.asSlice(index*sizeof()), x); + constants$38.const$1.set(seg.asSlice(index*sizeof()), x); } - public static USBInterfaceOpenSeize USBInterfaceOpenSeize(MemorySegment segment, SegmentScope scope) { + public static USBInterfaceOpenSeize USBInterfaceOpenSeize(MemorySegment segment, Arena scope) { return USBInterfaceOpenSeize.ofAddress(USBInterfaceOpenSeize$get(segment), scope); } - static final FunctionDescriptor ClearPipeStallBothEnds$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT - ); - static final MethodHandle ClearPipeStallBothEnds$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.ClearPipeStallBothEnds$FUNC - ); /** * {@snippet : * IOReturn (*ClearPipeStallBothEnds)(void*,UInt8); @@ -2912,14 +2434,14 @@ public static USBInterfaceOpenSeize USBInterfaceOpenSeize(MemorySegment segment, public interface ClearPipeStallBothEnds { int apply(java.lang.foreign.MemorySegment _x0, byte _x1); - static MemorySegment allocate(ClearPipeStallBothEnds fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(ClearPipeStallBothEnds.class, fi, IOUSBInterfaceStruct190.ClearPipeStallBothEnds$FUNC, scope); + static MemorySegment allocate(ClearPipeStallBothEnds fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$38.const$2, fi, constants$14.const$0, scope); } - static ClearPipeStallBothEnds ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static ClearPipeStallBothEnds ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { try { - return (int)IOUSBInterfaceStruct190.ClearPipeStallBothEnds$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$14.const$2.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2927,9 +2449,8 @@ static ClearPipeStallBothEnds ofAddress(MemorySegment addr, SegmentScope scope) } } - static final VarHandle ClearPipeStallBothEnds$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ClearPipeStallBothEnds")); public static VarHandle ClearPipeStallBothEnds$VH() { - return IOUSBInterfaceStruct190.ClearPipeStallBothEnds$VH; + return constants$38.const$3; } /** * Getter for field: @@ -2938,7 +2459,7 @@ static ClearPipeStallBothEnds ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static MemorySegment ClearPipeStallBothEnds$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ClearPipeStallBothEnds$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$38.const$3.get(seg); } /** * Setter for field: @@ -2947,26 +2468,17 @@ static ClearPipeStallBothEnds ofAddress(MemorySegment addr, SegmentScope scope) * } */ public static void ClearPipeStallBothEnds$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.ClearPipeStallBothEnds$VH.set(seg, x); + constants$38.const$3.set(seg, x); } public static MemorySegment ClearPipeStallBothEnds$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.ClearPipeStallBothEnds$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$38.const$3.get(seg.asSlice(index*sizeof())); } public static void ClearPipeStallBothEnds$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.ClearPipeStallBothEnds$VH.set(seg.asSlice(index*sizeof()), x); + constants$38.const$3.set(seg.asSlice(index*sizeof()), x); } - public static ClearPipeStallBothEnds ClearPipeStallBothEnds(MemorySegment segment, SegmentScope scope) { + public static ClearPipeStallBothEnds ClearPipeStallBothEnds(MemorySegment segment, Arena scope) { return ClearPipeStallBothEnds.ofAddress(ClearPipeStallBothEnds$get(segment), scope); } - static final FunctionDescriptor SetPipePolicy$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_SHORT$LAYOUT, - Constants$root.C_CHAR$LAYOUT - ); - static final MethodHandle SetPipePolicy$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.SetPipePolicy$FUNC - ); /** * {@snippet : * IOReturn (*SetPipePolicy)(void*,UInt8,UInt16,UInt8); @@ -2975,14 +2487,14 @@ public static ClearPipeStallBothEnds ClearPipeStallBothEnds(MemorySegment segmen public interface SetPipePolicy { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, short _x2, byte _x3); - static MemorySegment allocate(SetPipePolicy fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(SetPipePolicy.class, fi, IOUSBInterfaceStruct190.SetPipePolicy$FUNC, scope); + static MemorySegment allocate(SetPipePolicy fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$38.const$5, fi, constants$38.const$4, scope); } - static SetPipePolicy ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static SetPipePolicy ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, short __x2, byte __x3) -> { try { - return (int)IOUSBInterfaceStruct190.SetPipePolicy$MH.invokeExact(symbol, __x0, __x1, __x2, __x3); + return (int)constants$39.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2990,9 +2502,8 @@ static SetPipePolicy ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle SetPipePolicy$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("SetPipePolicy")); public static VarHandle SetPipePolicy$VH() { - return IOUSBInterfaceStruct190.SetPipePolicy$VH; + return constants$39.const$1; } /** * Getter for field: @@ -3001,7 +2512,7 @@ static SetPipePolicy ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment SetPipePolicy$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.SetPipePolicy$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$39.const$1.get(seg); } /** * Setter for field: @@ -3010,24 +2521,17 @@ static SetPipePolicy ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void SetPipePolicy$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.SetPipePolicy$VH.set(seg, x); + constants$39.const$1.set(seg, x); } public static MemorySegment SetPipePolicy$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.SetPipePolicy$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$39.const$1.get(seg.asSlice(index*sizeof())); } public static void SetPipePolicy$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.SetPipePolicy$VH.set(seg.asSlice(index*sizeof()), x); + constants$39.const$1.set(seg.asSlice(index*sizeof()), x); } - public static SetPipePolicy SetPipePolicy(MemorySegment segment, SegmentScope scope) { + public static SetPipePolicy SetPipePolicy(MemorySegment segment, Arena scope) { return SetPipePolicy.ofAddress(SetPipePolicy$get(segment), scope); } - static final FunctionDescriptor GetBandwidthAvailable$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetBandwidthAvailable$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetBandwidthAvailable$FUNC - ); /** * {@snippet : * IOReturn (*GetBandwidthAvailable)(void*,UInt32*); @@ -3036,14 +2540,14 @@ public static SetPipePolicy SetPipePolicy(MemorySegment segment, SegmentScope sc public interface GetBandwidthAvailable { int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetBandwidthAvailable fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetBandwidthAvailable.class, fi, IOUSBInterfaceStruct190.GetBandwidthAvailable$FUNC, scope); + static MemorySegment allocate(GetBandwidthAvailable fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$39.const$2, fi, constants$6.const$5, scope); } - static GetBandwidthAvailable ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetBandwidthAvailable ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { try { - return (int)IOUSBInterfaceStruct190.GetBandwidthAvailable$MH.invokeExact(symbol, __x0, __x1); + return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3051,9 +2555,8 @@ static GetBandwidthAvailable ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetBandwidthAvailable$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetBandwidthAvailable")); public static VarHandle GetBandwidthAvailable$VH() { - return IOUSBInterfaceStruct190.GetBandwidthAvailable$VH; + return constants$39.const$3; } /** * Getter for field: @@ -3062,7 +2565,7 @@ static GetBandwidthAvailable ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetBandwidthAvailable$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetBandwidthAvailable$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$39.const$3.get(seg); } /** * Setter for field: @@ -3071,29 +2574,17 @@ static GetBandwidthAvailable ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetBandwidthAvailable$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetBandwidthAvailable$VH.set(seg, x); + constants$39.const$3.set(seg, x); } public static MemorySegment GetBandwidthAvailable$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetBandwidthAvailable$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$39.const$3.get(seg.asSlice(index*sizeof())); } public static void GetBandwidthAvailable$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetBandwidthAvailable$VH.set(seg.asSlice(index*sizeof()), x); + constants$39.const$3.set(seg.asSlice(index*sizeof()), x); } - public static GetBandwidthAvailable GetBandwidthAvailable(MemorySegment segment, SegmentScope scope) { + public static GetBandwidthAvailable GetBandwidthAvailable(MemorySegment segment, Arena scope) { return GetBandwidthAvailable.ofAddress(GetBandwidthAvailable$get(segment), scope); } - static final FunctionDescriptor GetEndpointProperties$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_CHAR$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle GetEndpointProperties$MH = RuntimeHelper.downcallHandle( - IOUSBInterfaceStruct190.GetEndpointProperties$FUNC - ); /** * {@snippet : * IOReturn (*GetEndpointProperties)(void*,UInt8,UInt8,UInt8,UInt8*,UInt16*,UInt8*); @@ -3102,14 +2593,14 @@ public static GetBandwidthAvailable GetBandwidthAvailable(MemorySegment segment, public interface GetEndpointProperties { int apply(java.lang.foreign.MemorySegment _x0, byte _x1, byte _x2, byte _x3, java.lang.foreign.MemorySegment _x4, java.lang.foreign.MemorySegment _x5, java.lang.foreign.MemorySegment _x6); - static MemorySegment allocate(GetEndpointProperties fi, SegmentScope scope) { - return RuntimeHelper.upcallStub(GetEndpointProperties.class, fi, IOUSBInterfaceStruct190.GetEndpointProperties$FUNC, scope); + static MemorySegment allocate(GetEndpointProperties fi, Arena scope) { + return RuntimeHelper.upcallStub(constants$39.const$5, fi, constants$39.const$4, scope); } - static GetEndpointProperties ofAddress(MemorySegment addr, SegmentScope scope) { - MemorySegment symbol = MemorySegment.ofAddress(addr.address(), 0, scope); + static GetEndpointProperties ofAddress(MemorySegment addr, Arena arena) { + MemorySegment symbol = addr.reinterpret(arena, null); return (java.lang.foreign.MemorySegment __x0, byte __x1, byte __x2, byte __x3, java.lang.foreign.MemorySegment __x4, java.lang.foreign.MemorySegment __x5, java.lang.foreign.MemorySegment __x6) -> { try { - return (int)IOUSBInterfaceStruct190.GetEndpointProperties$MH.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6); + return (int)constants$40.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3117,9 +2608,8 @@ static GetEndpointProperties ofAddress(MemorySegment addr, SegmentScope scope) { } } - static final VarHandle GetEndpointProperties$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("GetEndpointProperties")); public static VarHandle GetEndpointProperties$VH() { - return IOUSBInterfaceStruct190.GetEndpointProperties$VH; + return constants$40.const$1; } /** * Getter for field: @@ -3128,7 +2618,7 @@ static GetEndpointProperties ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static MemorySegment GetEndpointProperties$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetEndpointProperties$VH.get(seg); + return (java.lang.foreign.MemorySegment)constants$40.const$1.get(seg); } /** * Setter for field: @@ -3137,15 +2627,15 @@ static GetEndpointProperties ofAddress(MemorySegment addr, SegmentScope scope) { * } */ public static void GetEndpointProperties$set(MemorySegment seg, MemorySegment x) { - IOUSBInterfaceStruct190.GetEndpointProperties$VH.set(seg, x); + constants$40.const$1.set(seg, x); } public static MemorySegment GetEndpointProperties$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)IOUSBInterfaceStruct190.GetEndpointProperties$VH.get(seg.asSlice(index*sizeof())); + return (java.lang.foreign.MemorySegment)constants$40.const$1.get(seg.asSlice(index*sizeof())); } public static void GetEndpointProperties$set(MemorySegment seg, long index, MemorySegment x) { - IOUSBInterfaceStruct190.GetEndpointProperties$VH.set(seg.asSlice(index*sizeof()), x); + constants$40.const$1.set(seg.asSlice(index*sizeof()), x); } - public static GetEndpointProperties GetEndpointProperties(MemorySegment segment, SegmentScope scope) { + public static GetEndpointProperties GetEndpointProperties(MemorySegment segment, Arena scope) { return GetEndpointProperties.ofAddress(GetEndpointProperties$get(segment), scope); } public static long sizeof() { return $LAYOUT().byteSize(); } @@ -3153,7 +2643,7 @@ public static GetEndpointProperties GetEndpointProperties(MemorySegment segment, public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); } - public static MemorySegment ofAddress(MemorySegment addr, SegmentScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java index c691bfb5..6b52deb2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java @@ -15,14 +15,15 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { // System.loadLibrary("IOKit.framework"); // SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SymbolLookup loaderLookup = SymbolLookup.libraryLookup("IOKit.framework/IOKit", SegmentScope.global()); + SymbolLookup loaderLookup = SymbolLookup.libraryLookup("IOKit.framework/IOKit", Arena.global()); SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } @@ -37,7 +38,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -56,18 +59,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java index 3343291a..0c05b256 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java @@ -2,51 +2,30 @@ package net.codecrete.usb.macos.gen.iokit; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemorySegment; -import java.lang.invoke.MethodHandle; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; import java.lang.invoke.VarHandle; -import static java.lang.foreign.ValueLayout.OfAddress; -import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.*; final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} - static final OfAddress kCFRunLoopDefaultMode$LAYOUT = Constants$root.C_POINTER$LAYOUT; - static final VarHandle kCFRunLoopDefaultMode$VH = constants$0.kCFRunLoopDefaultMode$LAYOUT.varHandle(); - static final MemorySegment kCFRunLoopDefaultMode$SEGMENT = RuntimeHelper.lookupGlobalVariable("kCFRunLoopDefaultMode", constants$0.kCFRunLoopDefaultMode$LAYOUT); - static final OfInt kIOMasterPortDefault$LAYOUT = Constants$root.C_INT$LAYOUT; - static final VarHandle kIOMasterPortDefault$VH = constants$0.kIOMasterPortDefault$LAYOUT.varHandle(); - static final MemorySegment kIOMasterPortDefault$SEGMENT = RuntimeHelper.lookupGlobalVariable("kIOMasterPortDefault", constants$0.kIOMasterPortDefault$LAYOUT); - static final FunctionDescriptor IONotificationPortCreate$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle IONotificationPortCreate$MH = RuntimeHelper.downcallHandle( - "IONotificationPortCreate", - constants$0.IONotificationPortCreate$FUNC - ); - static final FunctionDescriptor IONotificationPortGetRunLoopSource$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle IONotificationPortGetRunLoopSource$MH = RuntimeHelper.downcallHandle( - "IONotificationPortGetRunLoopSource", - constants$0.IONotificationPortGetRunLoopSource$FUNC - ); - static final FunctionDescriptor IOObjectRelease$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle IOObjectRelease$MH = RuntimeHelper.downcallHandle( - "IOObjectRelease", - constants$0.IOObjectRelease$FUNC - ); - static final FunctionDescriptor IOIteratorNext$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle IOIteratorNext$MH = RuntimeHelper.downcallHandle( - "IOIteratorNext", - constants$0.IOIteratorNext$FUNC - ); + static final StructLayout const$0 = MemoryLayout.structLayout( + JAVA_BYTE.withName("bmRequestType"), + JAVA_BYTE.withName("bRequest"), + JAVA_SHORT.withName("wValue"), + JAVA_SHORT.withName("wIndex"), + JAVA_SHORT.withName("wLength"), + RuntimeHelper.POINTER.withName("pData"), + JAVA_INT.withName("wLenDone"), + MemoryLayout.paddingLayout(4) + ).withName(""); + static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("bmRequestType")); + static final VarHandle const$2 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("bRequest")); + static final VarHandle const$3 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("wValue")); + static final VarHandle const$4 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("wIndex")); + static final VarHandle const$5 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("wLength")); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$1.java index f75879ac..7f197c64 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$1.java @@ -2,62 +2,26 @@ package net.codecrete.usb.macos.gen.iokit; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemorySegment; -import java.lang.invoke.MethodHandle; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_SHORT; final class constants$1 { // Suppresses default constructor, ensuring non-instantiability. private constants$1() {} - static final FunctionDescriptor IOServiceAddMatchingNotification$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle IOServiceAddMatchingNotification$MH = RuntimeHelper.downcallHandle( - "IOServiceAddMatchingNotification", - constants$1.IOServiceAddMatchingNotification$FUNC - ); - static final FunctionDescriptor IORegistryEntryGetRegistryEntryID$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle IORegistryEntryGetRegistryEntryID$MH = RuntimeHelper.downcallHandle( - "IORegistryEntryGetRegistryEntryID", - constants$1.IORegistryEntryGetRegistryEntryID$FUNC - ); - static final FunctionDescriptor IORegistryEntryCreateCFProperty$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT - ); - static final MethodHandle IORegistryEntryCreateCFProperty$MH = RuntimeHelper.downcallHandle( - "IORegistryEntryCreateCFProperty", - constants$1.IORegistryEntryCreateCFProperty$FUNC - ); - static final FunctionDescriptor IOServiceMatching$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle IOServiceMatching$MH = RuntimeHelper.downcallHandle( - "IOServiceMatching", - constants$1.IOServiceMatching$FUNC - ); - static final FunctionDescriptor IOCreatePlugInInterfaceForService$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle IOCreatePlugInInterfaceForService$MH = RuntimeHelper.downcallHandle( - "IOCreatePlugInInterfaceForService", - constants$1.IOCreatePlugInInterfaceForService$FUNC - ); - static final MemorySegment kIOFirstMatchNotification$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("IOServiceFirstMatch"); + static final VarHandle const$0 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("pData")); + static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("wLenDone")); + static final StructLayout const$2 = MemoryLayout.structLayout( + JAVA_SHORT.withName("bInterfaceClass"), + JAVA_SHORT.withName("bInterfaceSubClass"), + JAVA_SHORT.withName("bInterfaceProtocol"), + JAVA_SHORT.withName("bAlternateSetting") + ).withName(""); + static final VarHandle const$3 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("bInterfaceClass")); + static final VarHandle const$4 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("bInterfaceSubClass")); + static final VarHandle const$5 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("bInterfaceProtocol")); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$10.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$10.java new file mode 100644 index 00000000..45874636 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$10.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$10 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$10() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceProtocol.class, "apply", constants$6.const$5); + static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProtocol")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceVendor.class, "apply", constants$6.const$5); + static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceVendor")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceProduct.class, "apply", constants$6.const$5); + static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProduct")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$11.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$11.java new file mode 100644 index 00000000..9e28e1bf --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$11.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$11 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$11() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceReleaseNumber.class, "apply", constants$6.const$5); + static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceReleaseNumber")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceAddress.class, "apply", constants$6.const$5); + static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAddress")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceBusPowerAvailable.class, "apply", constants$6.const$5); + static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceBusPowerAvailable")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$12.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$12.java new file mode 100644 index 00000000..13c8d1fd --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$12.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$12 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$12() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceSpeed.class, "apply", constants$6.const$5); + static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceSpeed")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetNumberOfConfigurations.class, "apply", constants$6.const$5); + static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetNumberOfConfigurations")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetLocationID.class, "apply", constants$6.const$5); + static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetLocationID")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$13.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$13.java new file mode 100644 index 00000000..39624ca6 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$13.java @@ -0,0 +1,30 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$13 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$13() {} + static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + JAVA_BYTE, + RuntimeHelper.POINTER + ); + static final MethodHandle const$1 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetConfigurationDescriptorPtr.class, "apply", constants$13.const$0); + static final MethodHandle const$2 = RuntimeHelper.downcallHandle( + constants$13.const$0 + ); + static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetConfigurationDescriptorPtr")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetConfiguration.class, "apply", constants$6.const$5); + static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetConfiguration")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$14.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$14.java new file mode 100644 index 00000000..f392ab2d --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$14.java @@ -0,0 +1,33 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$14 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$14() {} + static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + JAVA_BYTE + ); + static final MethodHandle const$1 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.SetConfiguration.class, "apply", constants$14.const$0); + static final MethodHandle const$2 = RuntimeHelper.downcallHandle( + constants$14.const$0 + ); + static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("SetConfiguration")); + static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER + ); + static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetBusFrameNumber.class, "apply", constants$14.const$4); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$15.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$15.java new file mode 100644 index 00000000..79a39ca9 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$15.java @@ -0,0 +1,22 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$15 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$15() {} + static final MethodHandle const$0 = RuntimeHelper.downcallHandle( + constants$14.const$4 + ); + static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetBusFrameNumber")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.ResetDevice.class, "apply", constants$5.const$5); + static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("ResetDevice")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.DeviceRequest.class, "apply", constants$6.const$5); + static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequest")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$16.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$16.java new file mode 100644 index 00000000..4aaba200 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$16.java @@ -0,0 +1,30 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$16 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$16() {} + static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER + ); + static final MethodHandle const$1 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.DeviceRequestAsync.class, "apply", constants$16.const$0); + static final MethodHandle const$2 = RuntimeHelper.downcallHandle( + constants$16.const$0 + ); + static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestAsync")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.CreateInterfaceIterator.class, "apply", constants$14.const$4); + static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceIterator")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$17.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$17.java new file mode 100644 index 00000000..18fbc0e1 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$17.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$17 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$17() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBDeviceOpenSeize.class, "apply", constants$5.const$5); + static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceOpenSeize")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.DeviceRequestTO.class, "apply", constants$6.const$5); + static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestTO")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.DeviceRequestAsyncTO.class, "apply", constants$16.const$0); + static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestAsyncTO")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$18.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$18.java new file mode 100644 index 00000000..c5cc1d28 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$18.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$18 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$18() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBDeviceSuspend.class, "apply", constants$14.const$0); + static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceSuspend")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBDeviceAbortPipeZero.class, "apply", constants$5.const$5); + static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceAbortPipeZero")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBGetManufacturerStringIndex.class, "apply", constants$6.const$5); + static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBGetManufacturerStringIndex")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$19.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$19.java new file mode 100644 index 00000000..a1df6f77 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$19.java @@ -0,0 +1,26 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$19 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$19() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBGetProductStringIndex.class, "apply", constants$6.const$5); + static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBGetProductStringIndex")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBGetSerialNumberStringIndex.class, "apply", constants$6.const$5); + static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBGetSerialNumberStringIndex")); + static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + JAVA_INT + ); + static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBDeviceReEnumerate.class, "apply", constants$19.const$4); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$2.java index a61ef756..0e4c4512 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$2.java @@ -2,13 +2,29 @@ package net.codecrete.usb.macos.gen.iokit; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; final class constants$2 { // Suppresses default constructor, ensuring non-instantiability. private constants$2() {} - static final MemorySegment kIOTerminatedNotification$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("IOServiceTerminate"); - static final MemorySegment kIOUSBDeviceClassName$SEGMENT = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("IOUSBDevice"); + static final VarHandle const$0 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("bAlternateSetting")); + static final VarHandle const$1 = RuntimeHelper.POINTER.varHandle(); + static final MemorySegment const$2 = RuntimeHelper.lookupGlobalVariable("kCFRunLoopDefaultMode", RuntimeHelper.POINTER); + static final VarHandle const$3 = JAVA_INT.varHandle(); + static final MemorySegment const$4 = RuntimeHelper.lookupGlobalVariable("kIOMasterPortDefault", JAVA_INT); + static final FunctionDescriptor const$5 = FunctionDescriptor.of(RuntimeHelper.POINTER, + JAVA_INT + ); + static final MethodHandle const$6 = RuntimeHelper.downcallHandle( + "IONotificationPortCreate", + constants$2.const$5 + ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$20.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$20.java new file mode 100644 index 00000000..a7e481c4 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$20.java @@ -0,0 +1,73 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$20 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$20() {} + static final MethodHandle const$0 = RuntimeHelper.downcallHandle( + constants$19.const$4 + ); + static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceReEnumerate")); + static final StructLayout const$2 = MemoryLayout.structLayout( + RuntimeHelper.POINTER.withName("_reserved"), + RuntimeHelper.POINTER.withName("QueryInterface"), + RuntimeHelper.POINTER.withName("AddRef"), + RuntimeHelper.POINTER.withName("Release"), + RuntimeHelper.POINTER.withName("CreateInterfaceAsyncEventSource"), + RuntimeHelper.POINTER.withName("GetInterfaceAsyncEventSource"), + RuntimeHelper.POINTER.withName("CreateInterfaceAsyncPort"), + RuntimeHelper.POINTER.withName("GetInterfaceAsyncPort"), + RuntimeHelper.POINTER.withName("USBInterfaceOpen"), + RuntimeHelper.POINTER.withName("USBInterfaceClose"), + RuntimeHelper.POINTER.withName("GetInterfaceClass"), + RuntimeHelper.POINTER.withName("GetInterfaceSubClass"), + RuntimeHelper.POINTER.withName("GetInterfaceProtocol"), + RuntimeHelper.POINTER.withName("GetDeviceVendor"), + RuntimeHelper.POINTER.withName("GetDeviceProduct"), + RuntimeHelper.POINTER.withName("GetDeviceReleaseNumber"), + RuntimeHelper.POINTER.withName("GetConfigurationValue"), + RuntimeHelper.POINTER.withName("GetInterfaceNumber"), + RuntimeHelper.POINTER.withName("GetAlternateSetting"), + RuntimeHelper.POINTER.withName("GetNumEndpoints"), + RuntimeHelper.POINTER.withName("GetLocationID"), + RuntimeHelper.POINTER.withName("GetDevice"), + RuntimeHelper.POINTER.withName("SetAlternateInterface"), + RuntimeHelper.POINTER.withName("GetBusFrameNumber"), + RuntimeHelper.POINTER.withName("ControlRequest"), + RuntimeHelper.POINTER.withName("ControlRequestAsync"), + RuntimeHelper.POINTER.withName("GetPipeProperties"), + RuntimeHelper.POINTER.withName("GetPipeStatus"), + RuntimeHelper.POINTER.withName("AbortPipe"), + RuntimeHelper.POINTER.withName("ResetPipe"), + RuntimeHelper.POINTER.withName("ClearPipeStall"), + RuntimeHelper.POINTER.withName("ReadPipe"), + RuntimeHelper.POINTER.withName("WritePipe"), + RuntimeHelper.POINTER.withName("ReadPipeAsync"), + RuntimeHelper.POINTER.withName("WritePipeAsync"), + RuntimeHelper.POINTER.withName("ReadIsochPipeAsync"), + RuntimeHelper.POINTER.withName("WriteIsochPipeAsync"), + RuntimeHelper.POINTER.withName("ControlRequestTO"), + RuntimeHelper.POINTER.withName("ControlRequestAsyncTO"), + RuntimeHelper.POINTER.withName("ReadPipeTO"), + RuntimeHelper.POINTER.withName("WritePipeTO"), + RuntimeHelper.POINTER.withName("ReadPipeAsyncTO"), + RuntimeHelper.POINTER.withName("WritePipeAsyncTO"), + RuntimeHelper.POINTER.withName("USBInterfaceGetStringIndex"), + RuntimeHelper.POINTER.withName("USBInterfaceOpenSeize"), + RuntimeHelper.POINTER.withName("ClearPipeStallBothEnds"), + RuntimeHelper.POINTER.withName("SetPipePolicy"), + RuntimeHelper.POINTER.withName("GetBandwidthAvailable"), + RuntimeHelper.POINTER.withName("GetEndpointProperties") + ).withName("IOUSBInterfaceStruct190"); + static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("_reserved")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.QueryInterface.class, "apply", constants$5.const$1); + static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("QueryInterface")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$21.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$21.java new file mode 100644 index 00000000..11a65d3b --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$21.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$21 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$21() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.AddRef.class, "apply", constants$5.const$5); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("AddRef")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.Release.class, "apply", constants$5.const$5); + static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("Release")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource.class, "apply", constants$6.const$5); + static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceAsyncEventSource")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$22.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$22.java new file mode 100644 index 00000000..c7b34333 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$22.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$22 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$22() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource.class, "apply", constants$3.const$0); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceAsyncEventSource")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.CreateInterfaceAsyncPort.class, "apply", constants$6.const$5); + static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceAsyncPort")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetInterfaceAsyncPort.class, "apply", constants$5.const$5); + static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceAsyncPort")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$23.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$23.java new file mode 100644 index 00000000..51f5726d --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$23.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$23 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$23() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.USBInterfaceOpen.class, "apply", constants$5.const$5); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceOpen")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.USBInterfaceClose.class, "apply", constants$5.const$5); + static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceClose")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetInterfaceClass.class, "apply", constants$6.const$5); + static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceClass")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$24.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$24.java new file mode 100644 index 00000000..5f698e5c --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$24.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$24 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$24() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetInterfaceSubClass.class, "apply", constants$6.const$5); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceSubClass")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetInterfaceProtocol.class, "apply", constants$6.const$5); + static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceProtocol")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetDeviceVendor.class, "apply", constants$6.const$5); + static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceVendor")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$25.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$25.java new file mode 100644 index 00000000..ac0ee5fd --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$25.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$25 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$25() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetDeviceProduct.class, "apply", constants$6.const$5); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProduct")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetDeviceReleaseNumber.class, "apply", constants$6.const$5); + static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceReleaseNumber")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetConfigurationValue.class, "apply", constants$6.const$5); + static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetConfigurationValue")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$26.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$26.java new file mode 100644 index 00000000..63ae0b5c --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$26.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$26 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$26() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetInterfaceNumber.class, "apply", constants$6.const$5); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceNumber")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetAlternateSetting.class, "apply", constants$6.const$5); + static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetAlternateSetting")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetNumEndpoints.class, "apply", constants$6.const$5); + static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetNumEndpoints")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$27.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$27.java new file mode 100644 index 00000000..3623d41b --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$27.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$27 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$27() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetLocationID.class, "apply", constants$6.const$5); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetLocationID")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetDevice.class, "apply", constants$6.const$5); + static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetDevice")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.SetAlternateInterface.class, "apply", constants$14.const$0); + static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("SetAlternateInterface")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$28.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$28.java new file mode 100644 index 00000000..b34eb80a --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$28.java @@ -0,0 +1,30 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$28 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$28() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetBusFrameNumber.class, "apply", constants$14.const$4); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetBusFrameNumber")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ControlRequest.class, "apply", constants$13.const$0); + static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ControlRequest")); + static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + JAVA_BYTE, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER + ); + static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ControlRequestAsync.class, "apply", constants$28.const$4); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$29.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$29.java new file mode 100644 index 00000000..a5466229 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$29.java @@ -0,0 +1,36 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$29 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$29() {} + static final MethodHandle const$0 = RuntimeHelper.downcallHandle( + constants$28.const$4 + ); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ControlRequestAsync")); + static final FunctionDescriptor const$2 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + JAVA_BYTE, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER + ); + static final MethodHandle const$3 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetPipeProperties.class, "apply", constants$29.const$2); + static final MethodHandle const$4 = RuntimeHelper.downcallHandle( + constants$29.const$2 + ); + static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetPipeProperties")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$3.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$3.java new file mode 100644 index 00000000..320ddc7f --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$3.java @@ -0,0 +1,45 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$3 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$3() {} + static final FunctionDescriptor const$0 = FunctionDescriptor.of(RuntimeHelper.POINTER, + RuntimeHelper.POINTER + ); + static final MethodHandle const$1 = RuntimeHelper.downcallHandle( + "IONotificationPortGetRunLoopSource", + constants$3.const$0 + ); + static final FunctionDescriptor const$2 = FunctionDescriptor.of(JAVA_INT, + JAVA_INT + ); + static final MethodHandle const$3 = RuntimeHelper.downcallHandle( + "IOObjectRelease", + constants$3.const$2 + ); + static final MethodHandle const$4 = RuntimeHelper.downcallHandle( + "IOIteratorNext", + constants$3.const$2 + ); + static final FunctionDescriptor const$5 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER + ); + static final MethodHandle const$6 = RuntimeHelper.downcallHandle( + "IOServiceAddMatchingNotification", + constants$3.const$5 + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$30.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$30.java new file mode 100644 index 00000000..ab553ef3 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$30.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$30 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$30() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetPipeStatus.class, "apply", constants$14.const$0); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetPipeStatus")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.AbortPipe.class, "apply", constants$14.const$0); + static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("AbortPipe")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ResetPipe.class, "apply", constants$14.const$0); + static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ResetPipe")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$31.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$31.java new file mode 100644 index 00000000..ea1c0dbc --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$31.java @@ -0,0 +1,31 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$31 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$31() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ClearPipeStall.class, "apply", constants$14.const$0); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ClearPipeStall")); + static final FunctionDescriptor const$2 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + JAVA_BYTE, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER + ); + static final MethodHandle const$3 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ReadPipe.class, "apply", constants$31.const$2); + static final MethodHandle const$4 = RuntimeHelper.downcallHandle( + constants$31.const$2 + ); + static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ReadPipe")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$32.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$32.java new file mode 100644 index 00000000..ee057f97 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$32.java @@ -0,0 +1,38 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$32 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$32() {} + static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + JAVA_BYTE, + RuntimeHelper.POINTER, + JAVA_INT + ); + static final MethodHandle const$1 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.WritePipe.class, "apply", constants$32.const$0); + static final MethodHandle const$2 = RuntimeHelper.downcallHandle( + constants$32.const$0 + ); + static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("WritePipe")); + static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + JAVA_BYTE, + RuntimeHelper.POINTER, + JAVA_INT, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER + ); + static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ReadPipeAsync.class, "apply", constants$32.const$4); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$33.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$33.java new file mode 100644 index 00000000..ec150123 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$33.java @@ -0,0 +1,34 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.*; +final class constants$33 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$33() {} + static final MethodHandle const$0 = RuntimeHelper.downcallHandle( + constants$32.const$4 + ); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ReadPipeAsync")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.WritePipeAsync.class, "apply", constants$32.const$4); + static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("WritePipeAsync")); + static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + JAVA_BYTE, + RuntimeHelper.POINTER, + JAVA_LONG, + JAVA_INT, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER + ); + static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ReadIsochPipeAsync.class, "apply", constants$33.const$4); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$34.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$34.java new file mode 100644 index 00000000..0dd3c4c6 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$34.java @@ -0,0 +1,22 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$34 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$34() {} + static final MethodHandle const$0 = RuntimeHelper.downcallHandle( + constants$33.const$4 + ); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ReadIsochPipeAsync")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.WriteIsochPipeAsync.class, "apply", constants$33.const$4); + static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("WriteIsochPipeAsync")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ControlRequestTO.class, "apply", constants$13.const$0); + static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ControlRequestTO")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$35.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$35.java new file mode 100644 index 00000000..315b2f75 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$35.java @@ -0,0 +1,33 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$35 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$35() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ControlRequestAsyncTO.class, "apply", constants$28.const$4); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ControlRequestAsyncTO")); + static final FunctionDescriptor const$2 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + JAVA_BYTE, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + JAVA_INT, + JAVA_INT + ); + static final MethodHandle const$3 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ReadPipeTO.class, "apply", constants$35.const$2); + static final MethodHandle const$4 = RuntimeHelper.downcallHandle( + constants$35.const$2 + ); + static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ReadPipeTO")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$36.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$36.java new file mode 100644 index 00000000..bd7bf064 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$36.java @@ -0,0 +1,42 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$36 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$36() {} + static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + JAVA_BYTE, + RuntimeHelper.POINTER, + JAVA_INT, + JAVA_INT, + JAVA_INT + ); + static final MethodHandle const$1 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.WritePipeTO.class, "apply", constants$36.const$0); + static final MethodHandle const$2 = RuntimeHelper.downcallHandle( + constants$36.const$0 + ); + static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("WritePipeTO")); + static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + JAVA_BYTE, + RuntimeHelper.POINTER, + JAVA_INT, + JAVA_INT, + JAVA_INT, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER + ); + static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ReadPipeAsyncTO.class, "apply", constants$36.const$4); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$37.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$37.java new file mode 100644 index 00000000..0d52f7d0 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$37.java @@ -0,0 +1,22 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$37 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$37() {} + static final MethodHandle const$0 = RuntimeHelper.downcallHandle( + constants$36.const$4 + ); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ReadPipeAsyncTO")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.WritePipeAsyncTO.class, "apply", constants$36.const$4); + static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("WritePipeAsyncTO")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.USBInterfaceGetStringIndex.class, "apply", constants$6.const$5); + static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceGetStringIndex")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$38.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$38.java new file mode 100644 index 00000000..ce319313 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$38.java @@ -0,0 +1,28 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.*; +final class constants$38 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$38() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.USBInterfaceOpenSeize.class, "apply", constants$5.const$5); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceOpenSeize")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ClearPipeStallBothEnds.class, "apply", constants$14.const$0); + static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ClearPipeStallBothEnds")); + static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + JAVA_BYTE, + JAVA_SHORT, + JAVA_BYTE + ); + static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.SetPipePolicy.class, "apply", constants$38.const$4); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$39.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$39.java new file mode 100644 index 00000000..0aaa0f85 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$39.java @@ -0,0 +1,34 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$39 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$39() {} + static final MethodHandle const$0 = RuntimeHelper.downcallHandle( + constants$38.const$4 + ); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("SetPipePolicy")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetBandwidthAvailable.class, "apply", constants$6.const$5); + static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetBandwidthAvailable")); + static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + JAVA_BYTE, + JAVA_BYTE, + JAVA_BYTE, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER + ); + static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetEndpointProperties.class, "apply", constants$39.const$4); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$4.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$4.java new file mode 100644 index 00000000..2118e4f6 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$4.java @@ -0,0 +1,79 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$4 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$4() {} + static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, + JAVA_INT, + RuntimeHelper.POINTER + ); + static final MethodHandle const$1 = RuntimeHelper.downcallHandle( + "IORegistryEntryGetRegistryEntryID", + constants$4.const$0 + ); + static final FunctionDescriptor const$2 = FunctionDescriptor.of(RuntimeHelper.POINTER, + JAVA_INT, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + JAVA_INT + ); + static final MethodHandle const$3 = RuntimeHelper.downcallHandle( + "IORegistryEntryCreateCFProperty", + constants$4.const$2 + ); + static final MethodHandle const$4 = RuntimeHelper.downcallHandle( + "IOServiceMatching", + constants$3.const$0 + ); + static final StructLayout const$5 = MemoryLayout.structLayout( + RuntimeHelper.POINTER.withName("_reserved"), + RuntimeHelper.POINTER.withName("QueryInterface"), + RuntimeHelper.POINTER.withName("AddRef"), + RuntimeHelper.POINTER.withName("Release"), + RuntimeHelper.POINTER.withName("CreateDeviceAsyncEventSource"), + RuntimeHelper.POINTER.withName("GetDeviceAsyncEventSource"), + RuntimeHelper.POINTER.withName("CreateDeviceAsyncPort"), + RuntimeHelper.POINTER.withName("GetDeviceAsyncPort"), + RuntimeHelper.POINTER.withName("USBDeviceOpen"), + RuntimeHelper.POINTER.withName("USBDeviceClose"), + RuntimeHelper.POINTER.withName("GetDeviceClass"), + RuntimeHelper.POINTER.withName("GetDeviceSubClass"), + RuntimeHelper.POINTER.withName("GetDeviceProtocol"), + RuntimeHelper.POINTER.withName("GetDeviceVendor"), + RuntimeHelper.POINTER.withName("GetDeviceProduct"), + RuntimeHelper.POINTER.withName("GetDeviceReleaseNumber"), + RuntimeHelper.POINTER.withName("GetDeviceAddress"), + RuntimeHelper.POINTER.withName("GetDeviceBusPowerAvailable"), + RuntimeHelper.POINTER.withName("GetDeviceSpeed"), + RuntimeHelper.POINTER.withName("GetNumberOfConfigurations"), + RuntimeHelper.POINTER.withName("GetLocationID"), + RuntimeHelper.POINTER.withName("GetConfigurationDescriptorPtr"), + RuntimeHelper.POINTER.withName("GetConfiguration"), + RuntimeHelper.POINTER.withName("SetConfiguration"), + RuntimeHelper.POINTER.withName("GetBusFrameNumber"), + RuntimeHelper.POINTER.withName("ResetDevice"), + RuntimeHelper.POINTER.withName("DeviceRequest"), + RuntimeHelper.POINTER.withName("DeviceRequestAsync"), + RuntimeHelper.POINTER.withName("CreateInterfaceIterator"), + RuntimeHelper.POINTER.withName("USBDeviceOpenSeize"), + RuntimeHelper.POINTER.withName("DeviceRequestTO"), + RuntimeHelper.POINTER.withName("DeviceRequestAsyncTO"), + RuntimeHelper.POINTER.withName("USBDeviceSuspend"), + RuntimeHelper.POINTER.withName("USBDeviceAbortPipeZero"), + RuntimeHelper.POINTER.withName("USBGetManufacturerStringIndex"), + RuntimeHelper.POINTER.withName("USBGetProductStringIndex"), + RuntimeHelper.POINTER.withName("USBGetSerialNumberStringIndex"), + RuntimeHelper.POINTER.withName("USBDeviceReEnumerate") + ).withName("IOUSBDeviceStruct187"); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$40.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$40.java new file mode 100644 index 00000000..e5407f3a --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$40.java @@ -0,0 +1,36 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_SHORT; +final class constants$40 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$40() {} + static final MethodHandle const$0 = RuntimeHelper.downcallHandle( + constants$39.const$4 + ); + static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetEndpointProperties")); + static final StructLayout const$2 = MemoryLayout.structLayout( + RuntimeHelper.POINTER.withName("_reserved"), + RuntimeHelper.POINTER.withName("QueryInterface"), + RuntimeHelper.POINTER.withName("AddRef"), + RuntimeHelper.POINTER.withName("Release"), + JAVA_SHORT.withName("version"), + JAVA_SHORT.withName("revision"), + MemoryLayout.paddingLayout(4), + RuntimeHelper.POINTER.withName("Probe"), + RuntimeHelper.POINTER.withName("Start"), + RuntimeHelper.POINTER.withName("Stop") + ).withName("IOCFPlugInInterfaceStruct"); + static final VarHandle const$3 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("_reserved")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOCFPlugInInterfaceStruct.QueryInterface.class, "apply", constants$5.const$1); + static final VarHandle const$5 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("QueryInterface")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$41.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$41.java new file mode 100644 index 00000000..8b77227c --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$41.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$41 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$41() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOCFPlugInInterfaceStruct.AddRef.class, "apply", constants$5.const$5); + static final VarHandle const$1 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("AddRef")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOCFPlugInInterfaceStruct.Release.class, "apply", constants$5.const$5); + static final VarHandle const$3 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("Release")); + static final VarHandle const$4 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("version")); + static final VarHandle const$5 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("revision")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$42.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$42.java new file mode 100644 index 00000000..4ed42f8d --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$42.java @@ -0,0 +1,34 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$42 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$42() {} + static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + JAVA_INT, + RuntimeHelper.POINTER + ); + static final MethodHandle const$1 = RuntimeHelper.upcallHandle(IOCFPlugInInterfaceStruct.Probe.class, "apply", constants$42.const$0); + static final MethodHandle const$2 = RuntimeHelper.downcallHandle( + constants$42.const$0 + ); + static final VarHandle const$3 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("Probe")); + static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + JAVA_INT + ); + static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOCFPlugInInterfaceStruct.Start.class, "apply", constants$42.const$4); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$43.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$43.java new file mode 100644 index 00000000..8ad9ceff --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$43.java @@ -0,0 +1,34 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$43 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$43() {} + static final MethodHandle const$0 = RuntimeHelper.downcallHandle( + constants$42.const$4 + ); + static final VarHandle const$1 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("Start")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOCFPlugInInterfaceStruct.Stop.class, "apply", constants$5.const$5); + static final VarHandle const$3 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("Stop")); + static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, + JAVA_INT, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER + ); + static final MethodHandle const$5 = RuntimeHelper.downcallHandle( + "IOCreatePlugInInterfaceForService", + constants$43.const$4 + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$44.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$44.java new file mode 100644 index 00000000..c074540f --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$44.java @@ -0,0 +1,15 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemorySegment; +final class constants$44 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$44() {} + static final MemorySegment const$0 = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("IOServiceFirstMatch"); + static final MemorySegment const$1 = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("IOServiceTerminate"); + static final MemorySegment const$2 = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("IOUSBDevice"); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$5.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$5.java new file mode 100644 index 00000000..b604c1c6 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$5.java @@ -0,0 +1,49 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$5 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$5() {} + static final VarHandle const$0 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("_reserved")); + static final FunctionDescriptor const$1 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + MemoryLayout.structLayout( + JAVA_BYTE.withName("byte0"), + JAVA_BYTE.withName("byte1"), + JAVA_BYTE.withName("byte2"), + JAVA_BYTE.withName("byte3"), + JAVA_BYTE.withName("byte4"), + JAVA_BYTE.withName("byte5"), + JAVA_BYTE.withName("byte6"), + JAVA_BYTE.withName("byte7"), + JAVA_BYTE.withName("byte8"), + JAVA_BYTE.withName("byte9"), + JAVA_BYTE.withName("byte10"), + JAVA_BYTE.withName("byte11"), + JAVA_BYTE.withName("byte12"), + JAVA_BYTE.withName("byte13"), + JAVA_BYTE.withName("byte14"), + JAVA_BYTE.withName("byte15") + ).withName(""), + RuntimeHelper.POINTER + ); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.QueryInterface.class, "apply", constants$5.const$1); + static final MethodHandle const$3 = RuntimeHelper.downcallHandle( + constants$5.const$1 + ); + static final VarHandle const$4 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("QueryInterface")); + static final FunctionDescriptor const$5 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$6.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$6.java new file mode 100644 index 00000000..eef323d4 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$6.java @@ -0,0 +1,28 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; +final class constants$6 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$6() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.AddRef.class, "apply", constants$5.const$5); + static final MethodHandle const$1 = RuntimeHelper.downcallHandle( + constants$5.const$5 + ); + static final VarHandle const$2 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("AddRef")); + static final MethodHandle const$3 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.Release.class, "apply", constants$5.const$5); + static final VarHandle const$4 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("Release")); + static final FunctionDescriptor const$5 = FunctionDescriptor.of(JAVA_INT, + RuntimeHelper.POINTER, + RuntimeHelper.POINTER + ); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$7.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$7.java new file mode 100644 index 00000000..5ac5bfcb --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$7.java @@ -0,0 +1,24 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$7 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$7() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.CreateDeviceAsyncEventSource.class, "apply", constants$6.const$5); + static final MethodHandle const$1 = RuntimeHelper.downcallHandle( + constants$6.const$5 + ); + static final VarHandle const$2 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("CreateDeviceAsyncEventSource")); + static final MethodHandle const$3 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceAsyncEventSource.class, "apply", constants$3.const$0); + static final MethodHandle const$4 = RuntimeHelper.downcallHandle( + constants$3.const$0 + ); + static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncEventSource")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$8.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$8.java new file mode 100644 index 00000000..9793b458 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$8.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$8 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$8() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.CreateDeviceAsyncPort.class, "apply", constants$6.const$5); + static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("CreateDeviceAsyncPort")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceAsyncPort.class, "apply", constants$5.const$5); + static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncPort")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBDeviceOpen.class, "apply", constants$5.const$5); + static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceOpen")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$9.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$9.java new file mode 100644 index 00000000..fccbf566 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$9.java @@ -0,0 +1,20 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +final class constants$9 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$9() {} + static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBDeviceClose.class, "apply", constants$5.const$5); + static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceClose")); + static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceClass.class, "apply", constants$6.const$5); + static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceClass")); + static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceSubClass.class, "apply", constants$6.const$5); + static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceSubClass")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java deleted file mode 100644 index 59e45ac5..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/Constants$root.java +++ /dev/null @@ -1,21 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.mach; - -import static java.lang.foreign.ValueLayout.*; -final class Constants$root { - - // Suppresses default constructor, ensuring non-instantiability. - private Constants$root() {} - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT; - static final OfInt C_INT$LAYOUT = JAVA_INT; - static final OfLong C_LONG$LAYOUT = JAVA_LONG; - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG; - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT; - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE; - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded(); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java index 0b83f5a7..1f0d63c5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java @@ -15,9 +15,10 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, SegmentScope.auto()); + (size, align) -> Arena.ofAuto().allocate(size, align); static { @@ -36,7 +37,9 @@ static T requireNonNull(T obj, String symbolName) { } static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), symbol.scope())).orElse(null); + return SYMBOL_LOOKUP.find(name) + .map(s -> s.reinterpret(layout.byteSize())) + .orElse(null); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -55,18 +58,25 @@ static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc orElse(null); } - static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, SegmentScope scope) { + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", fdesc.toMethodType()); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, scope); + return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); } catch (Throwable ex) { throw new AssertionError(ex); } } - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, SegmentScope scope) { - return MemorySegment.ofAddress(addr.address(), numElements * layout.byteSize(), scope); + static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { + try { + fiHandle = fiHandle.bindTo(z); + return LINKER.upcallStub(fiHandle, fdesc, scope); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java index a75c9930..433609ea 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java @@ -4,16 +4,18 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} - static final FunctionDescriptor mach_error_string$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_INT$LAYOUT + static final FunctionDescriptor const$0 = FunctionDescriptor.of(RuntimeHelper.POINTER, + JAVA_INT ); - static final MethodHandle mach_error_string$MH = RuntimeHelper.downcallHandle( + static final MethodHandle const$1 = RuntimeHelper.downcallHandle( "mach_error_string", - constants$0.mach_error_string$FUNC + constants$0.const$0 ); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java index 3d065d4c..b53bd86f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java @@ -2,22 +2,23 @@ package net.codecrete.usb.macos.gen.mach; +import java.lang.foreign.AddressLayout; import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import static java.lang.foreign.ValueLayout.*; public class mach { - public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT; - public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT; - public static final OfInt C_INT = Constants$root.C_INT$LAYOUT; - public static final OfLong C_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT; - public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; - public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; - public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfLong C_LONG = JAVA_LONG; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; public static MethodHandle mach_error_string$MH() { - return RuntimeHelper.requireNonNull(constants$0.mach_error_string$MH,"mach_error_string"); + return RuntimeHelper.requireNonNull(constants$0.const$1,"mach_error_string"); } /** * {@snippet : From 85a0fe8093af13a8cc9ea9bbf466176bfd99f5f9 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 26 Jul 2023 22:35:42 +0200 Subject: [PATCH 246/433] macOS: use PathElements to access vtable --- java-does-usb/pom.xml | 2 +- .../codecrete/usb/common/ForeignMemory.java | 27 +++++-- .../main/java/net/codecrete/usb/linux/IO.java | 1 + .../codecrete/usb/linux/LinuxAsyncTask.java | 5 +- .../codecrete/usb/linux/LinuxUSBDevice.java | 1 - .../net/codecrete/usb/macos/IoKitHelper.java | 70 ++++++++++++++++--- .../net/codecrete/usb/macos/IoKitUSB.java | 51 ++++++-------- .../codecrete/usb/macos/MacosUSBDevice.java | 10 +-- .../usb/usbstandard/StringDescriptor.java | 4 +- .../codecrete/usb/windows/DeviceProperty.java | 1 + .../net/codecrete/usb/windows/USBHelper.java | 8 +-- .../java/net/codecrete/usb/windows/Win.java | 1 + .../usb/windows/WindowsAsyncTask.java | 4 +- .../usb/windows/WindowsUSBDevice.java | 4 +- .../usb/windows/WindowsUSBException.java | 5 +- .../usb/windows/winsdk/Kernel32B.java | 1 + .../usb/windows/winsdk/SetupAPI2.java | 1 + .../codecrete/usb/windows/winsdk/User32B.java | 1 + .../codecrete/usb/windows/winsdk/WinUSB2.java | 1 + 19 files changed, 134 insertions(+), 64 deletions(-) diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 2f0a2926..89832e8f 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 0.5.1 + 0.6.0-SNAPSHOT 21 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java index 9d002c89..310f3d0d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java @@ -7,20 +7,35 @@ package net.codecrete.usb.common; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import static java.lang.foreign.ValueLayout.ADDRESS; +/** + * Helper functions for accessing native memory. + */ public class ForeignMemory { /** - * Dereferences the address at the start of the memory segment and returns the result as - * a memory segment of the specified length. + * Dereferences the address at the start of given memory segment and returns the result as + * a memory segment with the length suitable for the specified layout. * - * @param segment the memory segment with the pointer at offset 0 - * @param byteSize the length + * @param segment the memory segment with the pointer at offset 0 + * @param layout layout for determining size of memory segment * @return the dereferenced memory segment */ - public static MemorySegment deref(MemorySegment segment, long byteSize) { - return segment.get(ADDRESS, 0).reinterpret(byteSize); + public static MemorySegment dereference(MemorySegment segment, MemoryLayout layout) { + return segment.get(ADDRESS, 0).reinterpret(layout.byteSize()); + } + + /** + * Dereferences the address at the start of given memory segment and returns the result as + * a memory segment of size 0. + * + * @param segment the memory segment with the pointer at offset 0 + * @return the dereferenced memory segment + */ + public static MemorySegment dereference(MemorySegment segment) { + return segment.get(ADDRESS, 0); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java index 0145e517..c546ade1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java @@ -14,6 +14,7 @@ import static java.lang.foreign.ValueLayout.*; +@SuppressWarnings("OptionalGetWithoutIsPresent") public class IO { private static final Linker linker = Linker.nativeLinker(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index 04d39924..3e281156 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -22,6 +22,7 @@ import static java.lang.foreign.ValueLayout.ADDRESS; import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static net.codecrete.usb.common.ForeignMemory.dereference; import static net.codecrete.usb.linux.LinuxUSBException.throwException; import static net.codecrete.usb.linux.LinuxUSBException.throwLastError; import static net.codecrete.usb.linux.USBDevFS.*; @@ -56,7 +57,7 @@ static synchronized LinuxAsyncTask instance() { return singletonInstance; } - private final Arena urbArena = Arena.ofShared(); + private final Arena urbArena = Arena.ofAuto(); /// available URBs private final List availableURBs = new ArrayList<>(); /// map of URB addresses to transfer (for outstanding transfers) @@ -165,7 +166,7 @@ private void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment errn } // call completion handler - var urb = urbPointerHolder.get(ADDRESS, 0); + var urb = dereference(urbPointerHolder); var transfer = getTransferResult(urb); transfer.completion.completed(transfer); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index e8fe1153..0c1468ca 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -36,7 +36,6 @@ import static net.codecrete.usb.linux.LinuxUSBException.throwException; import static net.codecrete.usb.linux.LinuxUSBException.throwLastError; -@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") public class LinuxUSBDevice extends USBDeviceImpl { private int fd = -1; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index bcee8fd8..769cc110 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -11,11 +11,16 @@ import net.codecrete.usb.macos.gen.iokit.IOKit; import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemoryLayout.PathElement; import java.lang.foreign.MemorySegment; +import java.lang.foreign.StructLayout; +import java.lang.invoke.VarHandle; import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.ADDRESS; import static java.lang.foreign.ValueLayout.JAVA_INT; +import static net.codecrete.usb.common.ForeignMemory.dereference; /** * Constants and helper functions for the IOKit framework. @@ -38,16 +43,66 @@ public class IoKitHelper { (byte) 0x00, (byte) 0x50, (byte) 0xE4, (byte) 0xC6, (byte) 0x42, (byte) 0x6F}); /** - * Get an interface of the specified service. + * Layout of COM object. *

- * This method first request the specified plugin interfaces and then + * Parts of I/O Kit use a plug-in architecture following the Component Object Model (COM). + * This layout is the basis for calling object methods (through the vtable) and + * accessing the reference count (for debugging purposes). + *

+ */ + static final StructLayout COM_OBJECT = + MemoryLayout.structLayout( + ADDRESS.withTargetLayout( + MemoryLayout.structLayout( + // up to 100 function pointers + MemoryLayout.sequenceLayout(100, ADDRESS) + ) + ).withName("vtable"), + ADDRESS.withTargetLayout( + MemoryLayout.structLayout( + ADDRESS.withName("unknown"), + JAVA_INT.withName("refCount") + ) + ).withName("data") + ); + + /** + * Var handle for accessing the vtable. + *

+ * The vtable is an array of function pointers. + *

+ */ + static final VarHandle vtable$VH = COM_OBJECT.varHandle(PathElement.groupElement("vtable")); + + /** + * Var handle for accessing the reference count. + */ + static final VarHandle refCount$VH = COM_OBJECT.varHandle( + PathElement.groupElement("data"), + PathElement.dereferenceElement(), + PathElement.groupElement("refCount") + ); + + /** + * Get the vtable of the specified object instance. + * @param self object instance + * @return vtable + */ + static MemorySegment getVtable(MemorySegment self) { + return (MemorySegment) vtable$VH.get(self); + } + + /** + * Gets an object instance implementing the specified service. + *

+ * This method first requests the specified plugin interface and then * queries for the specified interface. *

* * @param service the service * @param pluginType the plugin interface type * @param interfaceId the interface ID - * @return the interface, or {@code null} if the plugin type or interface is not available + * @return object instance implementing the interface, or {@code null} if the plugin type or interface is not available */ public static MemorySegment getInterface(int service, MemorySegment pluginType, MemorySegment interfaceId) { try (var arena = Arena.ofConfined()) { @@ -59,7 +114,7 @@ public static MemorySegment getInterface(int service, MemorySegment pluginType, , score); if (ret != 0) return null; - var plug = plugHolder.get(ADDRESS, 0); + var plug = dereference(plugHolder, COM_OBJECT); // UUID bytes var refiid = CoreFoundation.CFUUIDGetUUIDBytes(arena, interfaceId); @@ -69,7 +124,7 @@ public static MemorySegment getInterface(int service, MemorySegment pluginType, IoKitUSB.Release(plug); if (ret != 0) return null; - return intfHolder.get(ADDRESS, 0); + return dereference(intfHolder, COM_OBJECT); } } @@ -132,9 +187,6 @@ public static String getPropertyString(int service, MemorySegment key, Arena are // debugging aid public static int getRefCount(MemorySegment self) { - var object = MemorySegment.ofAddress(self.address()).reinterpret(16); - var dataAddr = object.get(ADDRESS, ADDRESS.byteSize()); - var data = MemorySegment.ofAddress(dataAddr.address()).reinterpret(12); - return data.get(JAVA_INT, 8); + return (int) refCount$VH.get(self); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index c75d5ae7..50a371f5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -7,26 +7,19 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.common.ForeignMemory; import net.codecrete.usb.macos.gen.iokit.IOUSBDeviceInterface187; import net.codecrete.usb.macos.gen.iokit.IOUSBInterfaceInterface190; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import static java.lang.foreign.ValueLayout.ADDRESS; +import static net.codecrete.usb.macos.IoKitHelper.getVtable; /** * Helper functions to call the virtual methods of IOKit USB interfaces. */ public class IoKitUSB { - private static MemorySegment getVtable(MemorySegment self) { - var object = MemorySegment.ofAddress(self.address()).reinterpret(ADDRESS.byteSize()); - // 800: size of biggest vtable and then some - return ForeignMemory.deref(object, 800); - } - // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); public static int QueryInterface(MemorySegment self, MemorySegment iid, MemorySegment ppv) { return IOUSBDeviceInterface187.QueryInterface(getVtable(self), Arena.global()).apply(self, iid, ppv); @@ -44,7 +37,8 @@ public static int Release(MemorySegment self) { // IOReturn (* CreateDeviceAsyncEventSource)(void* self, CFRunLoopSourceRef* source); public static int CreateDeviceAsyncEventSource(MemorySegment self, MemorySegment source) { - return IOUSBDeviceInterface187.CreateDeviceAsyncEventSource(getVtable(self), Arena.global()).apply(self, source); + return IOUSBDeviceInterface187.CreateDeviceAsyncEventSource(getVtable(self), Arena.global()).apply(self, + source); } // CFRunLoopSourceRef (* GetDeviceAsyncEventSource)(void* self); @@ -69,26 +63,25 @@ public static int USBDeviceReEnumerate(MemorySegment self, int options) { // IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc); public static int GetConfigurationDescriptorPtr(MemorySegment self, byte configIndex, MemorySegment descHolder) { - return IOUSBDeviceInterface187.GetConfigurationDescriptorPtr(getVtable(self), Arena.global()).apply(self, configIndex, descHolder); + return IOUSBDeviceInterface187.GetConfigurationDescriptorPtr(getVtable(self), Arena.global()).apply(self, + configIndex, descHolder); } // IOReturn (*SetConfiguration)(void *self, UInt8 configNum); public static int SetConfiguration(MemorySegment self, byte configValue) { - return IOUSBDeviceInterface187.SetConfiguration(getVtable(self), Arena.global()).apply(self, - configValue); + return IOUSBDeviceInterface187.SetConfiguration(getVtable(self), Arena.global()).apply(self, configValue); } // IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter); public static int CreateInterfaceIterator(MemorySegment self, MemorySegment req, MemorySegment iter) { - return IOUSBDeviceInterface187.CreateInterfaceIterator(getVtable(self), Arena.global()).apply(self, - req, iter); + return IOUSBDeviceInterface187.CreateInterfaceIterator(getVtable(self), Arena.global()).apply(self, req, iter); } // IOReturn (* DeviceRequestAsync)(void* self, IOUSBDevRequest* req, IOAsyncCallback1 callback, void* refCon); public static int DeviceRequestAsync(MemorySegment self, MemorySegment deviceRequest, MemorySegment callback, MemorySegment refCon) { - return IOUSBDeviceInterface187.DeviceRequestAsync(getVtable(self), Arena.global()).apply(self, - deviceRequest, callback, refCon); + return IOUSBDeviceInterface187.DeviceRequestAsync(getVtable(self), Arena.global()).apply(self, deviceRequest, + callback, refCon); } // IOReturn (*USBInterfaceOpen)(void *self);; @@ -118,16 +111,16 @@ public static int GetNumEndpoints(MemorySegment self, MemorySegment intfNumEndpo public static int GetPipeProperties(MemorySegment self, byte pipeRef, MemorySegment directionHolder, MemorySegment numberHolder, MemorySegment transferTypeHolder, MemorySegment maxPacketSizeHolder, MemorySegment intervalHolder) { - return IOUSBInterfaceInterface190.GetPipeProperties(getVtable(self), Arena.global()).apply(self, - pipeRef, directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); + return IOUSBInterfaceInterface190.GetPipeProperties(getVtable(self), Arena.global()).apply(self, pipeRef, + directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); } // IOReturn (*ReadPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, void // *refcon); public static int ReadPipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceInterface190.ReadPipeAsync(getVtable(self), Arena.global()).apply(self, pipeRef, - buf, size, callback, refcon); + return IOUSBInterfaceInterface190.ReadPipeAsync(getVtable(self), Arena.global()).apply(self, pipeRef, buf, + size, callback, refcon); } // IOReturn (*ReadPipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 @@ -135,16 +128,16 @@ public static int ReadPipeAsync(MemorySegment self, byte pipeRef, MemorySegment public static int ReadPipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, int noDataTimeout, int completionTimeout, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceInterface190.ReadPipeAsyncTO(getVtable(self), Arena.global()).apply(self, pipeRef - , buf, size, noDataTimeout, completionTimeout, callback, refcon); + return IOUSBInterfaceInterface190.ReadPipeAsyncTO(getVtable(self), Arena.global()).apply(self, pipeRef, buf, + size, noDataTimeout, completionTimeout, callback, refcon); } // IOReturn (*WritePipeAsync)(vovoid *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, // void *refcon); public static int WritePipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceInterface190.WritePipeAsync(getVtable(self), Arena.global()).apply(self, pipeRef, - buf, size, callback, refcon); + return IOUSBInterfaceInterface190.WritePipeAsync(getVtable(self), Arena.global()).apply(self, pipeRef, buf, + size, callback, refcon); } // IOReturn (*WritePipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 @@ -152,8 +145,8 @@ public static int WritePipeAsync(MemorySegment self, byte pipeRef, MemorySegment public static int WritePipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, int noDataTimeout, int completionTimeout, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceInterface190.WritePipeAsyncTO(getVtable(self), Arena.global()).apply(self, - pipeRef, buf, size, noDataTimeout, completionTimeout, callback, refcon); + return IOUSBInterfaceInterface190.WritePipeAsyncTO(getVtable(self), Arena.global()).apply(self, pipeRef, buf, + size, noDataTimeout, completionTimeout, callback, refcon); } // IOReturn (* AbortPipe)(void* self, UInt8 pipeRef); @@ -169,8 +162,7 @@ public static int SetAlternateInterface(MemorySegment self, byte alternateSettin // IOReturn (* ClearPipeStallBothEnds)(void* self, UInt8 pipeRef); public static int ClearPipeStallBothEnds(MemorySegment self, byte pipeRef) { - return IOUSBInterfaceInterface190.ClearPipeStallBothEnds(getVtable(self), Arena.global()).apply(self, - pipeRef); + return IOUSBInterfaceInterface190.ClearPipeStallBothEnds(getVtable(self), Arena.global()).apply(self, pipeRef); } // CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void* self); @@ -180,6 +172,7 @@ public static MemorySegment GetInterfaceAsyncEventSource(MemorySegment self) { // IOReturn (*CreateInterfaceAsyncEventSource)(void *self, CFRunLoopSourceRef *source); public static int CreateInterfaceAsyncEventSource(MemorySegment self, MemorySegment source) { - return IOUSBInterfaceInterface190.CreateInterfaceAsyncEventSource(getVtable(self), Arena.global()).apply(self, source); + return IOUSBInterfaceInterface190.CreateInterfaceAsyncEventSource(getVtable(self), Arena.global()).apply(self + , source); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 716898d2..b7e297c7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -10,7 +10,6 @@ import net.codecrete.usb.USBControlTransfer; import net.codecrete.usb.USBDirection; import net.codecrete.usb.USBTransferType; -import net.codecrete.usb.common.ForeignMemory; import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.common.Transfer; import net.codecrete.usb.common.USBDeviceImpl; @@ -29,6 +28,7 @@ import java.util.Map; import static java.lang.foreign.ValueLayout.*; +import static net.codecrete.usb.common.ForeignMemory.dereference; import static net.codecrete.usb.macos.MacosUSBException.throwException; /** @@ -166,7 +166,7 @@ private void loadDescription(MemorySegment device) { if (ret != 0) throwException(ret, "failed to query first configuration"); - var configDesc = ForeignMemory.deref(descPtrHolder, 999999); + var configDesc = dereference(descPtrHolder).reinterpret(999999); var configDescHeader = new ConfigurationDescriptor(configDesc); configDesc = configDesc.asSlice(0, configDescHeader.totalLength()); @@ -243,6 +243,7 @@ public synchronized void claimInterface(int interfaceNumber) { updateEndpointList(); } + @SuppressWarnings("OptionalGetWithoutIsPresent") public synchronized void selectAlternateSetting(int interfaceNumber, int alternateNumber) { // check interface var intf = getInterface(interfaceNumber); @@ -340,6 +341,7 @@ private void updateEndpointList() { } } + @SuppressWarnings("SameParameterValue") private synchronized EndpointInfo getEndpointInfo(int endpointNumber, USBDirection direction, USBTransferType transferType1, USBTransferType transferType2) { if (endpoints != null) { @@ -612,7 +614,7 @@ private synchronized void addDeviceEventSource() { int ret = IoKitUSB.CreateDeviceAsyncEventSource(device, sourceHolder); if (ret != 0) throwException(ret, "failed to create event source"); - var source = sourceHolder.get(ADDRESS, 0); + var source = dereference(sourceHolder); asyncTask.addEventSource(source); } } @@ -623,7 +625,7 @@ private synchronized void addInterfaceEventSource(InterfaceInfo interfaceInfo) { int ret = IoKitUSB.CreateInterfaceAsyncEventSource(interfaceInfo.iokitInterface(), sourceHolder); if (ret != 0) throwException(ret, "failed to create event source"); - var source = sourceHolder.get(ADDRESS, 0); + var source = dereference(sourceHolder); asyncTask.addEventSource(source); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java index 96dea670..b696c54c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java @@ -8,11 +8,11 @@ package net.codecrete.usb.usbstandard; import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.invoke.VarHandle; import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.MemoryLayout.structLayout; import static java.lang.foreign.ValueLayout.*; /** @@ -40,7 +40,7 @@ public String string() { // uint8_t bDescriptorType; // uint16_t string[1]; // } __attribute__((packed)); - public static final GroupLayout LAYOUT = structLayout( + public static final GroupLayout LAYOUT = MemoryLayout.structLayout( JAVA_BYTE.withName("bLength"), JAVA_BYTE.withName("bDescriptorType"), JAVA_SHORT.withName("string") diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index 5d0905d0..c4af7be2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -254,6 +254,7 @@ public static boolean isCompositeDevice(MemorySegment devInfoSet, MemorySegment private static MemorySegment createDEVPROPKEY(int data1, short data2, short data3, byte data4_0, byte data4_1, byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7, int pid) { + @SuppressWarnings("resource") var propKey = Arena.global().allocate(DEVPROPKEY.$LAYOUT()); Win.setGUID(DEVPROPKEY.fmtid$slice(propKey), data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4 , data4_5, data4_6, data4_7); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java index 81dccff3..ad62a895 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java @@ -11,11 +11,11 @@ import net.codecrete.usb.usbstandard.SetupPacket; import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.invoke.VarHandle; import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.MemoryLayout.structLayout; import static java.lang.foreign.ValueLayout.*; /** @@ -44,7 +44,7 @@ public class USBHelper { // USB_CONNECTION_STATUS ConnectionStatus;/* OUTPUT */ // USB_PIPE_INFO PipeList[0];/* OUTPUT */ //} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; - public static final GroupLayout USB_NODE_CONNECTION_INFORMATION_EX$Struct = structLayout( + public static final GroupLayout USB_NODE_CONNECTION_INFORMATION_EX$Struct = MemoryLayout.structLayout( JAVA_INT.withName("ConnectionIndex"), DeviceDescriptor.LAYOUT.withName("DeviceDescriptor"), JAVA_BYTE.withName("CurrentConfigurationValue"), @@ -76,8 +76,8 @@ public class USBHelper { // } SetupPacket; // UCHAR Data[0]; //} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST; - public static final GroupLayout USB_DESCRIPTOR_REQUEST$Struct = structLayout(JAVA_INT.withName("ConnectionIndex") - , SetupPacket.LAYOUT.withName("SetupPacket")); + public static final GroupLayout USB_DESCRIPTOR_REQUEST$Struct = MemoryLayout.structLayout(JAVA_INT.withName( + "ConnectionIndex"), SetupPacket.LAYOUT.withName("SetupPacket")); public static final VarHandle USB_DESCRIPTOR_REQUEST_ConnectionIndex = USB_DESCRIPTOR_REQUEST$Struct.varHandle(groupElement("ConnectionIndex")); public static final long USB_DESCRIPTOR_REQUEST_SetupPacket$Offset = diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index 394faadb..209e2cc9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -128,6 +128,7 @@ public static List createStringListFromSegment(MemorySegment segment) { public static MemorySegment CreateGUID(int data1, short data2, short data3, byte data4_0, byte data4_1, byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7) { + @SuppressWarnings("resource") var guid = Arena.global().allocate(GUID.$LAYOUT()); setGUID(guid, data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4, data4_5, data4_6, data4_7); return guid; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java index 53c95ae9..8d2d6d30 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java @@ -78,7 +78,7 @@ private void asyncCompletionTask() { var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); while (true) { - overlappedHolder.set(ADDRESS, 0, MemorySegment.NULL); + overlappedHolder.set(ADDRESS, 0, NULL); completionKeyHolder.set(JAVA_LONG, 0, 0); int res = Kernel32B.GetQueuedCompletionStatus(asyncIoCompletionPort, numBytesHolder, @@ -124,7 +124,7 @@ synchronized void addDevice(MemorySegment handle) { private void startAsyncIOTask() { availableOverlappedStructs = new ArrayList<>(); - arena = Arena.ofShared(); + arena = Arena.ofAuto(); requestsByOverlapped = new HashMap<>(); // start background thread for handling IO completion diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 553cdee6..ec0acb0a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -26,13 +26,13 @@ import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.*; +import static net.codecrete.usb.common.ForeignMemory.dereference; import static net.codecrete.usb.windows.WindowsUSBException.throwException; import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; /** * Windows implementation for USB device. */ -@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") public class WindowsUSBDevice extends USBDeviceImpl { private final WindowsAsyncTask asyncTask; @@ -139,7 +139,7 @@ public synchronized void claimInterface(int interfaceNumber) { var interfaceHandleHolder = arena.allocate(ADDRESS); if (WinUSB2.WinUsb_Initialize(deviceHandle, interfaceHandleHolder, lastErrorState) == 0) throwLastError(lastErrorState, "Cannot open WinUSB device"); - var interfaceHandle = interfaceHandleHolder.get(ADDRESS, 0); + var interfaceHandle = dereference(interfaceHandleHolder); firstIntfHandle.deviceHandle = deviceHandle; firstIntfHandle.deviceOpenCount += 1; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java index b0c83457..e7374066 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java @@ -16,6 +16,7 @@ import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.ADDRESS; +import static net.codecrete.usb.common.ForeignMemory.dereference; /** * Exception thrown if a Windows specific error occurs. @@ -68,7 +69,7 @@ static void throwException(String message, Object... args) { * Throws an exception for the last error. *

* The last Windows error code is taken from the call capture state - * {@link Win.LAST_ERROR_STATE} provided as the first parameter. + * {@link Win#LAST_ERROR_STATE} provided as the first parameter. *

* * @param lastErrorState call capture state containing last error code @@ -112,7 +113,7 @@ static String getErrorMessage(int errorCode) { if (res == 0) return "unspecified error"; - var messagePointer = messagePointerHolder.get(ADDRESS, 0).reinterpret(128 * 1024); + var messagePointer = dereference(messagePointerHolder).reinterpret(128 * 1024); String message = Win.createStringFromSegment(messagePointer); Kernel32.LocalFree(messagePointer); return message.trim(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java index ae3ad68c..e78b17a1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java @@ -23,6 +23,7 @@ * {@code GetLastError()} until jextract catches up and can generate the corresponding code. *

*/ +@SuppressWarnings("OptionalGetWithoutIsPresent") public class Kernel32B { static { System.loadLibrary("Kernel32"); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java index ef36ad7f..75b2d1b3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java @@ -24,6 +24,7 @@ * {@code GetLastError()} until jextract catches up and can generate the corresponding code. *

*/ +@SuppressWarnings("OptionalGetWithoutIsPresent") public class SetupAPI2 { static { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java index 12cace91..45381dc0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java @@ -23,6 +23,7 @@ * {@code GetLastError()} until jextract catches up and can generate the corresponding code. *

*/ +@SuppressWarnings("OptionalGetWithoutIsPresent") public class User32B { static { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java index ee4a1c97..47b7295f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java @@ -24,6 +24,7 @@ * {@code GetLastError()} until jextract catches up and can generate the corresponding code. *

*/ +@SuppressWarnings("OptionalGetWithoutIsPresent") public class WinUSB2 { static { System.loadLibrary("Winusb"); From c0481bc59743293cd95f09376bffae7c41112d63 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 28 Jul 2023 09:02:13 +0200 Subject: [PATCH 247/433] Prepare README --- README.md | 23 ++++++++++--------- .../src/main/java/net/codecrete/usb/USB.java | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index dd1efd41..efcd3b3d 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ *Java Does USB* is a Java library for working with USB devices. It allows to query information about all conntected USB devices and to communicate with USB devices using custom / vendor specific protocols. (It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc.) -The library uses the [Foreign Function & Memory API](https://github.com/openjdk/panama-foreign) to access native APIs of the underlying operating system. It only uses Java code and does not need JNI or any native third-party library. The *Foreign Function & Memory API* (aka as project Panama) is in preview and will be introduced in a future Java version. Currently, it can be used with Java 19 or Java 20 (with preview features enabled). +The library uses the [Foreign Function & Memory API](https://github.com/openjdk/panama-foreign) to access native APIs of the underlying operating system. It is written entirely in Java and does not need JNI or any native third-party library. The *Foreign Function & Memory API* (aka as project Panama) is currently in preview and will leave preview with Java 22. Currently, it can be used with Java 19, Java 20 or Java 21 (with preview features enabled). -*Note: The main branch and published versions ≥ 0.5.0 work with JDK 20 only. For JDK 19, use version 0.4.x.* +*Note: The main branch and published versions ≥ 0.6.0 work with JDK 21 only. For JDK 20, use version 0.5.*. For JDK 19, use version 0.4.x. ## Features @@ -41,14 +41,14 @@ If you are using Maven, add the below dependency to your pom.xml: net.codecrete.usb java-does-usb - 0.5.1 + 0.6.0 ``` If you are using Gradle, add the below dependency to your build.gradle file: ```groovy -compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '0.5.1' +compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '0.6.0' ``` ```java @@ -78,14 +78,15 @@ public class EnumerateDevices { - [Enumeration](examples/enumerate/) lists all connected USB devices and displays information about interfaces and endpoints. - [Monitor](examples/monitor/) lists the connected USB devices and then monitors for USB devices being connected and disconnnected. - [Device Firmware Upload (DFU) for STM32](examples/stm_dfu) uploads firmware to STM32 microcontrollers supporting the built-in DFU mode. +- [ePaper Display](examples/epaper_display) communicates with an IT8951 controller for e-Paper displays and shows an image on the display. ## Prerequisite -- Java 20, preview features enabled (available at https://www.azul.com/downloads/?package=jdk) +- Java 21, preview features enabled (available at https://www.azul.com/downloads/?package=jdk) - Windows (x86 64-bit), macOS (x86 64-bit, ARM 64-bit) or Linux 64 bit (x86 64-bit, ARM 64-bit) -For JDK 19, use the latest published version 0.4.x. +For JDK 20, use the latest published version 0.5.x. For JDK 19, use the latest published version 0.4.x. ## Platform-specific Considerations @@ -93,16 +94,16 @@ For JDK 19, use the latest published version 0.4.x. ### macOS -No special considerations apply. Using this library, a Java application can connect to any USB device and claim any interfaces that isn't claimed by an operating system driver or another application. +No special considerations apply. Using this library, a Java application can connect to any USB device and claim any interfaces that isn't claimed by an operating system driver or another application. Standard operation-system drivers can be unloaded if the application is run with root privileges. ### Linux *libudev* is used to discover and monitor USB devices. It is closely tied to *systemd*. So the library only runs on Linux distributions with *systemd* and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfill this requirement. -Similar to macOS, a Java application can connect to any USB device and claim any interfaces that isn't claimed by an operating system driver or another application. +Similar to macOS, a Java application can connect to any USB device and claim any interfaces that isn't claimed by an operating system driver or another application. Standard operation system drivers can be unloaded (without the need for root privileges). -Most Linux distributions by default set up user accounts without the permission to access USB devices directly. The *udev* system daemon is responsible for assigning permissions to USB devices. It can be configured to assign specific permissions or ownership: +Most Linux distributions by default set up user accounts without permissions to access USB devices directly. The *udev* system daemon is responsible for assigning permissions to USB devices. It can be configured to assign specific permissions or ownership: Create a file called `/etc/udev/rules.d/80-javadoesusb-udev.rules` with the below content: @@ -115,9 +116,9 @@ This adds the rule to assign permission mode 0666 to all USB devices with vendor ### Windows -The Windows driver model is more rigid than the ones of macOS or Linux. It's not possible to open any USB device by default. Instead, only devices using the *WinUSB* driver can be opened. This even applies to devices with no installed driver. +The Windows driver model is more rigid than the ones of macOS or Linux. It's not possible to open any USB device that is not claimed. Instead, only devices using the *WinUSB* driver can be opened. This even applies to devices with no installed driver. -USB devices can implement certain control requests to instruct Windows to automatically install the WinUSB driver (search for WCID or Microsoft OS Compatibility Descriptors). The driver can also be manually installed or replaced using a software called [Zadig](https://zadig.akeo.ie/). +USB devices can implement certain control requests to instruct Windows to automatically install the WinUSB driver (search for *WCID* or *Microsoft OS Compatibility Descriptors*). The WinUSB driver can also be manually installed or replaced using a software called [Zadig](https://zadig.akeo.ie/). The test devices implement the required control requests. So the driver is installed automatically. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USB.java b/java-does-usb/src/main/java/net/codecrete/usb/USB.java index 27ee8cef..f77b4dd3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USB.java @@ -34,7 +34,7 @@ private static USBDeviceRegistry createInstance() { } else if (osName.equals("Linux") && (osArch.equals("amd64") || osArch.equals("aarch64"))) { impl = new LinuxUSBDeviceRegistry(); } else { - throw new UnsupportedOperationException(String.format("JavaCanDoUsb is not implemented for architecture " + "%s/%s", osName, osArch)); + throw new UnsupportedOperationException(String.format("Java Does USB has no implementation for architecture " + "%s/%s", osName, osArch)); } return impl; } From f579a6a4ea41d287f5afedf928c98bccbceeff08 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 28 Jul 2023 15:27:17 +0200 Subject: [PATCH 248/433] Work on code smells --- .../java/net/codecrete/usb/USBException.java | 4 +- .../codecrete/usb/common/Configuration.java | 10 +-- .../usb/common/ConfigurationParser.java | 2 +- .../usb/common/EndpointInputStream.java | 6 +- .../usb/common/EndpointOutputStream.java | 4 +- .../codecrete/usb/common/ForeignMemory.java | 3 + .../usb/common/USBAlternateInterfaceImpl.java | 2 +- .../codecrete/usb/common/USBDeviceImpl.java | 56 +++++++-------- .../usb/common/USBDeviceRegistry.java | 62 ++++++++++------- .../usb/common/USBInterfaceImpl.java | 2 +- .../main/java/net/codecrete/usb/linux/IO.java | 27 ++++---- .../java/net/codecrete/usb/linux/Linux.java | 13 ++-- .../codecrete/usb/linux/LinuxAsyncTask.java | 68 +++++++++---------- .../codecrete/usb/linux/LinuxUSBDevice.java | 29 +++----- .../usb/linux/LinuxUSBDeviceRegistry.java | 40 +++++++---- .../net/codecrete/usb/linux/USBDevFS.java | 29 +++++--- 16 files changed, 191 insertions(+), 166 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBException.java b/java-does-usb/src/main/java/net/codecrete/usb/USBException.java index f78487ee..dacc902a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBException.java @@ -15,7 +15,7 @@ public class USBException extends RuntimeException { /** * Error code. */ - private int code = -1; + private final int code; /** * Creates a new instance with a message. @@ -24,6 +24,7 @@ public class USBException extends RuntimeException { */ public USBException(String message) { super(message); + code = -1; } /** @@ -45,6 +46,7 @@ public USBException(String message, int errorCode) { */ public USBException(String message, Throwable cause) { super(message, cause); + code = -1; } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java b/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java index 7dc70fa0..e1ad6992 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java @@ -18,12 +18,12 @@ public class Configuration { private final List functionList; private final List interfaceList; - private final int configuration; + private final int configurationValue; private final int configurationAttributes; private final int configurationMaxPower; public Configuration(int configValue, int attributes, int maxPower) { - configuration = configValue; + configurationValue = configValue; configurationAttributes = attributes; configurationMaxPower = maxPower; functionList = new ArrayList<>(); @@ -31,7 +31,7 @@ public Configuration(int configValue, int attributes, int maxPower) { } public int configValue() { - return configuration; + return configurationValue; } public int attributes() { @@ -55,7 +55,7 @@ public void addInterface(USBInterface intf) { } public USBInterfaceImpl findInterfaceByNumber(int number) { - return (USBInterfaceImpl) interfaceList.stream().filter((intf) -> intf.number() == number).findFirst().orElse(null); + return (USBInterfaceImpl) interfaceList.stream().filter(intf -> intf.number() == number).findFirst().orElse(null); } public void addFunction(CompositeFunction function) { @@ -63,6 +63,6 @@ public void addFunction(CompositeFunction function) { } public CompositeFunction findFunction(int interfaceNumber) { - return functionList.stream().filter((f) -> interfaceNumber >= f.firstInterfaceNumber() && interfaceNumber < f.firstInterfaceNumber() + f.numInterfaces()).findFirst().orElse(null); + return functionList.stream().filter(f -> interfaceNumber >= f.firstInterfaceNumber() && interfaceNumber < f.firstInterfaceNumber() + f.numInterfaces()).findFirst().orElse(null); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java index 7063962e..58ec7e68 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java @@ -163,7 +163,7 @@ private int peekDescLength(int offset) { * @return descriptor type */ private int peekDescType(int offset) { - return 0xff & descriptor.get(ValueLayout.JAVA_BYTE, offset + 1); + return 0xff & descriptor.get(ValueLayout.JAVA_BYTE, offset + 1L); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index 188093e8..d1959a7e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -91,7 +91,7 @@ protected EndpointInputStream(USBDeviceImpl device, int endpointNumber, int buff submitTransfer(transfer); } } - } catch (Throwable t) { + } catch (Exception t) { collectOutstandingTransfers(); throw t; } @@ -176,7 +176,7 @@ private void receiveMoreData() throws IOException { } while (currentTransfer.resultSize <= 0); - } catch (Throwable t) { + } catch (Exception t) { close(); throw t; } @@ -189,7 +189,7 @@ private Transfer waitForCompletedTransfer() { numOutstandingTransfers -= 1; return transfer; } catch (InterruptedException e) { - // ignore and retry + Thread.currentThread().interrupt(); } } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java index e70b2d29..92fded78 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -178,7 +178,7 @@ private void submitTransfer(int size) throws IOException { writeOffset = 0; currentTransfer = waitForAvailableTransfer(); - } catch (Throwable t) { + } catch (Exception t) { hasError = true; close(); throw t; @@ -237,7 +237,7 @@ private Transfer waitForAvailableTransfer() { return transfer; } catch (InterruptedException e) { - // ignore and retry + Thread.currentThread().interrupt(); } } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java index 310f3d0d..1102cba3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ForeignMemory.java @@ -16,6 +16,9 @@ * Helper functions for accessing native memory. */ public class ForeignMemory { + private ForeignMemory() { + } + /** * Dereferences the address at the start of given memory segment and returns the result as * a memory segment with the length suitable for the specified layout. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java index c6eced74..401ba45e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java @@ -63,6 +63,6 @@ void addEndpoint(USBEndpoint endpoint) { @Override public USBEndpoint getEndpoint(int endpointNumber, USBDirection direction) { - return endpointList.stream().filter((ep) -> ep.number() == endpointNumber && ep.direction() == direction).findFirst().orElse(null); + return endpointList.stream().filter(ep -> ep.number() == endpointNumber && ep.direction() == direction).findFirst().orElse(null); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 05419a04..c19c4659 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -13,7 +13,7 @@ import java.lang.foreign.MemorySegment; import java.util.Collections; import java.util.List; -import java.util.function.Function; +import java.util.function.IntFunction; import static java.lang.foreign.ValueLayout.JAVA_BYTE; @@ -77,15 +77,6 @@ public void attachStandardDrivers() { // default implementation: do nothing } - @Override - public abstract void open(); - - @Override - public abstract void close(); - - @Override - public abstract boolean isOpen(); - protected void checkIsOpen() { if (!isOpen()) throw new USBException("The device needs to be open to call this method"); @@ -200,7 +191,7 @@ public void setProductStrings(String manufacturer, String product, String serial * @param descriptor device descriptor * @param stringLookup string lookup function */ - public void setProductString(MemorySegment descriptor, Function stringLookup) { + public void setProductString(MemorySegment descriptor, IntFunction stringLookup) { var deviceDescriptor = new DeviceDescriptor(descriptor); manufacturerString = stringLookup.apply(deviceDescriptor.iManufacturer()); productString = stringLookup.apply(deviceDescriptor.iProduct()); @@ -223,12 +214,6 @@ public List interfaces() { return Collections.unmodifiableList(interfaceList); } - @Override - public abstract void claimInterface(int interfaceNumber); - - @Override - public abstract void releaseInterface(int interfaceNumber); - public void setClaimed(int interfaceNumber, boolean claimed) { for (var intf : interfaceList) { if (intf.number() == interfaceNumber) { @@ -241,7 +226,19 @@ public void setClaimed(int interfaceNumber, boolean claimed) { @Override public USBInterfaceImpl getInterface(int interfaceNumber) { - return (USBInterfaceImpl) interfaceList.stream().filter((intf) -> intf.number() == interfaceNumber).findFirst().orElse(null); + return (USBInterfaceImpl) interfaceList.stream().filter(intf -> intf.number() == interfaceNumber).findFirst().orElse(null); + } + + public USBInterfaceImpl getInterfaceWithCheck(int interfaceNumber, boolean isClaimed) { + var intf = getInterface(interfaceNumber); + if (intf == null) + throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); + if (isClaimed && !intf.isClaimed()) { + throw new USBException(String.format("Interface %d has not been claimed", interfaceNumber)); + } else if (!isClaimed && intf.isClaimed()) { + throw new USBException(String.format("Interface %d has already been claimed", interfaceNumber)); + } + return intf; } @Override @@ -264,6 +261,7 @@ public USBEndpoint getEndpoint(USBDirection direction, int endpointNumber) { * @param transferType2 transfer type 2 (or {@code null}) * @return endpoint */ + @SuppressWarnings("java:S3776") protected EndpointInfo getEndpoint(USBDirection direction, int endpointNumber, USBTransferType transferType1, USBTransferType transferType2) { @@ -273,7 +271,8 @@ protected EndpointInfo getEndpoint(USBDirection direction, int endpointNumber, U for (var intf : interfaceList) { if (intf.isClaimed()) { for (var ep : intf.alternate().endpoints()) { - if (ep.number() == endpointNumber && ep.direction() == direction && (ep.transferType() == transferType1 || ep.transferType() == transferType2)) + if (ep.number() == endpointNumber && ep.direction() == direction + && (ep.transferType() == transferType1 || ep.transferType() == transferType2)) return new EndpointInfo(intf.number(), ep.number(), (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)), ep.packetSize(), ep.transferType()); @@ -312,12 +311,6 @@ protected int getInterfaceNumber(USBDirection direction, int endpointNumber) { return -1; } - @Override - public abstract byte[] controlTransferIn(USBControlTransfer setup, int length); - - @Override - public abstract void controlTransferOut(USBControlTransfer setup, byte[] data); - @Override public void transferOut(int endpointNumber, byte[] data) { transferOut(endpointNumber, data, 0, data.length, 0); @@ -328,17 +321,11 @@ public void transferOut(int endpointNumber, byte[] data, int timeout) { transferOut(endpointNumber, data, 0, data.length, timeout); } - @Override - public abstract void transferOut(int endpointNumber, byte[] data, int offset, int length, int timeout); - @Override public byte[] transferIn(int endpointNumber) { return transferIn(endpointNumber, 0); } - @Override - public abstract byte[] transferIn(int endpointNumber, int timeout); - protected void waitForTransfer(Transfer transfer, int timeout, USBDirection direction, int endpointNumber) { if (timeout <= 0) { waitNoTimeout(transfer); @@ -362,17 +349,19 @@ protected void waitForTransfer(Transfer transfer, int timeout, USBDirection dire } } + @SuppressWarnings("java:S2273") private static void waitNoTimeout(Transfer transfer) { // wait for transfer while (transfer.resultSize == -1) { try { transfer.wait(); } catch (InterruptedException e) { - // ignore and retry + Thread.currentThread().interrupt(); } } } + @SuppressWarnings("java:S2273") private static boolean waitWithTimeout(Transfer transfer, int timeout) { // wait for transfer to complete, or abort when timeout occurs long expiration = System.currentTimeMillis() + timeout; @@ -383,7 +372,7 @@ private static boolean waitWithTimeout(Transfer transfer, int timeout) { remainingTimeout = expiration - System.currentTimeMillis(); } catch (InterruptedException e) { - // ignore and retry + Thread.currentThread().interrupt(); } } @@ -415,6 +404,7 @@ protected static String getOperationDescription(USBDirection direction, int endp * * @param transfer the transfer that has completed */ + @SuppressWarnings({"java:S2445", "java:S2446"}) protected static void onSyncTransferCompleted(Transfer transfer) { synchronized (transfer) { transfer.notify(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index 8c036638..671781d2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -32,8 +32,8 @@ */ public abstract class USBDeviceRegistry { - private volatile List devices; - private volatile Throwable failureCause; + private List devices; + private Throwable failureCause; protected Consumer onDeviceConnectedHandler; protected Consumer onDeviceDisconnectedHandler; @@ -69,7 +69,7 @@ public void start() { * * @return list of devices */ - public List getAllDevices() { + public synchronized List getAllDevices() { return Collections.unmodifiableList(devices); } @@ -81,6 +81,7 @@ public void setOnDeviceDisconnected(Consumer handler) { onDeviceDisconnectedHandler = handler; } + @SuppressWarnings("java:S106") protected void emitOnDeviceConnected(USBDevice device) { if (onDeviceConnectedHandler == null) return; @@ -88,12 +89,13 @@ protected void emitOnDeviceConnected(USBDevice device) { try { onDeviceConnectedHandler.accept(device); - } catch (Throwable e) { + } catch (Exception e) { System.err.println("Warning: [JavaDoesUSB] unhandled exception in 'onDeviceConnected' handler - ignoring"); e.printStackTrace(System.err); } } + @SuppressWarnings("java:S106") protected void emitOnDeviceDisconnected(USBDevice device) { if (onDeviceDisconnectedHandler == null) return; @@ -101,7 +103,7 @@ protected void emitOnDeviceDisconnected(USBDevice device) { try { onDeviceDisconnectedHandler.accept(device); - } catch (Throwable e) { + } catch (Exception e) { System.err.println("Warning: [JavaDoesUSB] unhandled exception in 'onDeviceDisconnected' handler - " + "ignoring"); e.printStackTrace(System.err); @@ -168,7 +170,9 @@ protected void enumerationFailed(Throwable e) { * @param deviceList the device list */ protected void setInitialDeviceList(List deviceList) { - devices = deviceList; + synchronized (this) { + devices = deviceList; + } signalEnumerationComplete(); } @@ -178,20 +182,23 @@ protected void setInitialDeviceList(List deviceList) { * @param device device to add */ protected void addDevice(USBDevice device) { - // check for duplicates - if (findDeviceIndex(devices, ((USBDeviceImpl) device).getUniqueId()) >= 0) - return; - - // copy list - var newDeviceList = new ArrayList(devices.size() + 1); - newDeviceList.addAll(devices); - newDeviceList.add(device); - devices = newDeviceList; + synchronized (this) { + // check for duplicates + if (findDeviceIndex(devices, ((USBDeviceImpl) device).getUniqueId()) >= 0) + return; + + // copy list + var newDeviceList = new ArrayList(devices.size() + 1); + newDeviceList.addAll(devices); + newDeviceList.add(device); + devices = newDeviceList; + } // send notification emitOnDeviceConnected(device); } + @SuppressWarnings("java:S106") protected void closeAndRemoveDevice(Object deviceId) { var device = findDevice(deviceId); if (device == null) @@ -199,7 +206,7 @@ protected void closeAndRemoveDevice(Object deviceId) { try { device.close(); - } catch (Throwable e) { + } catch (Exception e) { System.err.println("Info: [JavaDoesUSB] failed to close USB device - ignoring exception"); e.printStackTrace(System.err); } @@ -213,16 +220,19 @@ protected void closeAndRemoveDevice(Object deviceId) { * @param deviceId the unique ID of the device to remove */ protected void removeDevice(Object deviceId) { - // locate device to be removed - int index = findDeviceIndex(devices, deviceId); - if (index < 0) - return; // strange - - // copy list and remove device - var device = devices.get(index); - var newDeviceList = new ArrayList<>(devices); - newDeviceList.remove(index); - devices = newDeviceList; + USBDevice device; + synchronized (this) { + // locate device to be removed + int index = findDeviceIndex(devices, deviceId); + if (index < 0) + return; // strange + + // copy list and remove device + device = devices.get(index); + var newDeviceList = new ArrayList<>(devices); + newDeviceList.remove(index); + devices = newDeviceList; + } // send notification emitOnDeviceDisconnected(device); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java index 5990208f..07234665 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java @@ -48,7 +48,7 @@ public USBAlternateInterface alternate() { @Override public USBAlternateInterface getAlternate(int alternateNumber) { - return alternateInterfaces.stream().filter((alt) -> alt.number() == alternateNumber).findFirst().orElse(null); + return alternateInterfaces.stream().filter(alt -> alt.number() == alternateNumber).findFirst().orElse(null); } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java index c546ade1..84e9f499 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java @@ -14,8 +14,11 @@ import static java.lang.foreign.ValueLayout.*; -@SuppressWarnings("OptionalGetWithoutIsPresent") -public class IO { +@SuppressWarnings({"OptionalGetWithoutIsPresent", "SameParameterValue", "java:S100"}) +class IO { + + private IO() { + } private static final Linker linker = Linker.nativeLinker(); private static final FunctionDescriptor ioctl$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_LONG, ADDRESS); @@ -34,43 +37,43 @@ public class IO { private static final MethodHandle eventfd_write$MH = linker.downcallHandle(linker.defaultLookup().find( "eventfd_write").get(), eventfd_write$FUNC, Linux.ERRNO_STATE); - public static int ioctl(int fd, long request, MemorySegment segment, MemorySegment errno) { + static int ioctl(int fd, long request, MemorySegment segment, MemorySegment errno) { try { return (int) ioctl$MH.invokeExact(errno, fd, request, segment); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } - public static int open(MemorySegment file, int oflag, MemorySegment errno) { + static int open(MemorySegment file, int oflag, MemorySegment errno) { try { return (int) open$MH.invokeExact(errno, file, oflag); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } - public static int eventfd(int count, int flags, MemorySegment errno) { + static int eventfd(int count, int flags, MemorySegment errno) { try { return (int) eventfd$MH.invokeExact(errno, count, flags); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } - public static int eventfd_read(int fd, MemorySegment value, MemorySegment errno) { + static int eventfd_read(int fd, MemorySegment value, MemorySegment errno) { try { return (int) eventfd_read$MH.invokeExact(errno, fd, value); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } - public static int eventfd_write(int fd, long value, MemorySegment errno) { + static int eventfd_write(int fd, long value, MemorySegment errno) { try { return (int) eventfd_write$MH.invokeExact(errno, fd, value); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java index c01344a1..aa0b7d7c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java @@ -18,13 +18,16 @@ /** * Helper functions for Linux */ -public class Linux { +class Linux { + + private Linux() { + } /** * Call state for capturing the {@code errno} value. */ - public static final Linker.Option ERRNO_STATE = Linker.Option.captureCallState("errno"); - public static final StructLayout ERRNO_STATE_LAYOUT = Linker.Option.captureStateLayout(); + static final Linker.Option ERRNO_STATE = Linker.Option.captureCallState("errno"); + static final StructLayout ERRNO_STATE_LAYOUT = Linker.Option.captureStateLayout(); private static final VarHandle callState_errno$VH = ERRNO_STATE_LAYOUT.varHandle(PathElement.groupElement("errno")); @@ -34,7 +37,7 @@ public class Linux { * @param err error code * @return error message */ - public static String getErrorMessage(int err) { + static String getErrorMessage(int err) { return string.strerror(err).getUtf8String(0); } @@ -47,7 +50,7 @@ public static String getErrorMessage(int err) { * @param errno memory segment with error code * @return error code */ - public static int getErrno(MemorySegment errno) { + static int getErrno(MemorySegment errno) { return (int) callState_errno$VH.get(errno); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index 3e281156..e5fe0787 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -43,19 +43,12 @@ * determines the number of allocated URBs. *

*/ -public class LinuxAsyncTask { - private static LinuxAsyncTask singletonInstance; - +@SuppressWarnings("java:S6548") +class LinuxAsyncTask { /** * Singleton instance of background task. - * - * @return background task */ - static synchronized LinuxAsyncTask instance() { - if (singletonInstance == null) - singletonInstance = new LinuxAsyncTask(); - return singletonInstance; - } + static final LinuxAsyncTask INSTANCE = new LinuxAsyncTask(); private final Arena urbArena = Arena.ofAuto(); /// available URBs @@ -78,11 +71,12 @@ static synchronized LinuxAsyncTask instance() { * can be woken up to refresh the list of polled file descriptors. *

*/ + @SuppressWarnings({"java:S2189", "java:S135", "java:S3776"}) private void asyncCompletionTask() { try (var arena = Arena.ofConfined()) { var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); - var asyncPolls = pollfd.allocateArray(100, arena); + var pollfdArray = pollfd.allocateArray(100, arena); var urbPointerHolder = arena.allocate(ADDRESS); var eventfdValueHolder = arena.allocate(JAVA_LONG); @@ -94,28 +88,18 @@ private void asyncCompletionTask() { fds = asyncFds; } - // prepare pollfd struct array - var n = fds.length; - for (int i = 0; i < n; i++) { - pollfd.fd$set(asyncPolls, i, fds[i]); - pollfd.events$set(asyncPolls, i, (short) poll.POLLOUT()); - pollfd.revents$set(asyncPolls, i, (short) 0); - } - - // entry n is the wake-up event file descriptor - pollfd.fd$set(asyncPolls, n, asyncIOWakeUpEventFd); - pollfd.events$set(asyncPolls, n, (short) poll.POLLIN()); - pollfd.revents$set(asyncPolls, n, (short) 0); - // poll for event - int res = poll.poll(asyncPolls, n + 1, -1); + fillPollfdArray(pollfdArray, fds); + int n = fds.length; + int res = poll.poll(pollfdArray, n + 1L, -1); if (res < 0) throwException("internal error (poll)"); // acquire lock synchronized (this) { - if ((pollfd.revents$get(asyncPolls, n) & poll.POLLIN()) != 0) { + // check for wakeup event + if ((pollfd.revents$get(pollfdArray, n) & poll.POLLIN()) != 0) { // wakeup to refresh list of file descriptors res = IO.eventfd_read(asyncIOWakeUpEventFd, eventfdValueHolder, errnoState); if (res < 0) @@ -123,22 +107,22 @@ private void asyncCompletionTask() { continue; } - // check for events + // check for USB device events for (int i = 0; i < n + 1; i++) { - var revent = pollfd.revents$get(asyncPolls, i); + var revent = pollfd.revents$get(pollfdArray, i); if (revent == 0) continue; if ((revent & poll.POLLERR()) != 0) { - // most likely the device has been disconnected; + // most likely the device has been disconnected, // remove from polled FD list to prevent further problems - int fd = pollfd.fd$get(asyncPolls, i); + int fd = pollfd.fd$get(pollfdArray, i); removeFdFromAsyncIOCompletion(fd); continue; } // reap URB - int fd = pollfd.fd$get(asyncPolls, i); + int fd = pollfd.fd$get(pollfdArray, i); reapURBs(fd, urbPointerHolder, errnoState); } } @@ -146,6 +130,21 @@ private void asyncCompletionTask() { } } + void fillPollfdArray(MemorySegment asyncPolls, int[] fds) { + // device file descriptors + var n = fds.length; + for (int i = 0; i < n; i++) { + pollfd.fd$set(asyncPolls, i, fds[i]); + pollfd.events$set(asyncPolls, i, (short) poll.POLLOUT()); + pollfd.revents$set(asyncPolls, i, (short) 0); + } + + // entry n is the wake-up event file descriptor + pollfd.fd$set(asyncPolls, n, asyncIOWakeUpEventFd); + pollfd.events$set(asyncPolls, n, (short) poll.POLLIN()); + pollfd.revents$set(asyncPolls, n, (short) 0); + } + /** * Reap all pending URBs and handle the completed transfers. * @@ -280,6 +279,7 @@ private void addURB(LinuxTransfer transfer) { transfersByURB.put(urb, transfer); } + @SuppressWarnings("java:S2259") private synchronized LinuxTransfer getTransferResult(MemorySegment urb) { var transfer = transfersByURB.remove(urb); if (transfer == null) @@ -293,6 +293,7 @@ private synchronized LinuxTransfer getTransferResult(MemorySegment urb) { return transfer; } + @SuppressWarnings("java:S1066") synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { int fd = device.fileDescriptor(); try (var arena = Arena.ofConfined()) { @@ -301,9 +302,8 @@ synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { // iterate all URBs and discard the ones for the specified endpoint for (var urb : transfersByURB.keySet()) { - if (fd != (int) usbdevfs_urb.usercontext$get(urb).address()) - continue; - if (endpointAddress != usbdevfs_urb.endpoint$get(urb)) + if (fd != (int) usbdevfs_urb.usercontext$get(urb).address() + || endpointAddress != usbdevfs_urb.endpoint$get(urb)) continue; if (IO.ioctl(fd, DISCARDURB, urb, errnoState) < 0) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 0c1468ca..181c6b50 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -36,8 +36,12 @@ import static net.codecrete.usb.linux.LinuxUSBException.throwException; import static net.codecrete.usb.linux.LinuxUSBException.throwLastError; +@SuppressWarnings("java:S2160") public class LinuxUSBDevice extends USBDeviceImpl { + @SuppressWarnings("resource") + private static final MemorySegment DRIVER_NAME_USBFS = Arena.global().allocateUtf8String("usbfs"); + private int fd = -1; private final LinuxAsyncTask asyncTask; @@ -46,7 +50,7 @@ public class LinuxUSBDevice extends USBDeviceImpl { LinuxUSBDevice(Object id, int vendorId, int productId) { super(id, vendorId, productId); - asyncTask = LinuxAsyncTask.instance(); + asyncTask = LinuxAsyncTask.INSTANCE; loadDescription((String) id); } @@ -120,11 +124,7 @@ int fileDescriptor() { public synchronized void claimInterface(int interfaceNumber) { checkIsOpen(); - var intf = getInterface(interfaceNumber); - if (intf == null) - throwException("Invalid interface number: %d", interfaceNumber); - if (intf.isClaimed()) - throwException("Interface %d has already been claimed", interfaceNumber); + var intf = getInterfaceWithCheck(interfaceNumber, false); try (var arena = Arena.ofConfined()) { var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); @@ -135,8 +135,7 @@ public synchronized void claimInterface(int interfaceNumber) { var disconnectClaim = usbdevfs_disconnect_claim.allocate(arena); usbdevfs_disconnect_claim.interface_$set(disconnectClaim, interfaceNumber); usbdevfs_disconnect_claim.flags$set(disconnectClaim, usbdevice_fs.USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER()); - byte[] driverName = {'u', 's', 'b', 'f', 's', 0}; - usbdevfs_disconnect_claim.driver$slice(disconnectClaim).copyFrom(MemorySegment.ofArray(driverName)); + usbdevfs_disconnect_claim.driver$slice(disconnectClaim).copyFrom(DRIVER_NAME_USBFS); ret = IO.ioctl(fd, USBDevFS.DISCONNECT_CLAIM, disconnectClaim, errnoState); } else { @@ -156,11 +155,7 @@ public synchronized void claimInterface(int interfaceNumber) { public synchronized void selectAlternateSetting(int interfaceNumber, int alternateNumber) { checkIsOpen(); - var intf = getInterface(interfaceNumber); - if (intf == null) - throwException("Invalid interface number: %d", interfaceNumber); - if (!intf.isClaimed()) - throwException("Interface %d has not been claimed", interfaceNumber); + var intf = getInterfaceWithCheck(interfaceNumber, true); // check alternate setting var altSetting = intf.getAlternate(alternateNumber); @@ -184,11 +179,7 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna public synchronized void releaseInterface(int interfaceNumber) { checkIsOpen(); - var intf = getInterface(interfaceNumber); - if (intf == null) - throwException("Invalid interface number: %d", interfaceNumber); - if (!intf.isClaimed()) - throwException("Interface %d has not been claimed", interfaceNumber); + getInterfaceWithCheck(interfaceNumber, true); try (var arena = Arena.ofConfined()) { var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); @@ -252,7 +243,7 @@ private LinuxTransfer createSyncCtrlTransfer(Arena arena, USBDirection direction int dataLength) { var bmRequest = (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); - var buffer = arena.allocate(8 + dataLength, 8); + var buffer = arena.allocate(8L + dataLength, 8); var setupPacket = new SetupPacket(buffer); setupPacket.setRequestType(bmRequest); setupPacket.setRequest(setup.request()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index ac9be5d9..f3cfc9d7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -16,7 +16,6 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; import java.util.ArrayList; import java.util.List; @@ -27,17 +26,32 @@ */ public class LinuxUSBDeviceRegistry extends USBDeviceRegistry { - private final SegmentAllocator GLOBAL_ALLOCATOR = Arena.global(); - private final MemorySegment SUBSYSTEM_USB = GLOBAL_ALLOCATOR.allocateUtf8String("usb"); - private final MemorySegment MONITOR_NAME = GLOBAL_ALLOCATOR.allocateUtf8String("udev"); - private final MemorySegment DEVTYPE_USB_DEVICE = GLOBAL_ALLOCATOR.allocateUtf8String("usb_device"); - - private final MemorySegment ATTR_ID_VENDOR = GLOBAL_ALLOCATOR.allocateUtf8String("idVendor"); - private final MemorySegment ATTR_ID_PRODUCT = GLOBAL_ALLOCATOR.allocateUtf8String("idProduct"); - private final MemorySegment ATTR_MANUFACTURER = GLOBAL_ALLOCATOR.allocateUtf8String("manufacturer"); - private final MemorySegment ATTR_PRODUCT = GLOBAL_ALLOCATOR.allocateUtf8String("product"); - private final MemorySegment ATTR_SERIAL = GLOBAL_ALLOCATOR.allocateUtf8String("serial"); + private static final MemorySegment SUBSYSTEM_USB; + private static final MemorySegment MONITOR_NAME; + private static final MemorySegment DEVTYPE_USB_DEVICE; + + private static final MemorySegment ATTR_ID_VENDOR; + private static final MemorySegment ATTR_ID_PRODUCT; + private static final MemorySegment ATTR_MANUFACTURER; + private static final MemorySegment ATTR_PRODUCT; + private static final MemorySegment ATTR_SERIAL; + + static { + @SuppressWarnings("resource") + var global = Arena.global(); + + SUBSYSTEM_USB = global.allocateUtf8String("usb"); + MONITOR_NAME = global.allocateUtf8String("udev"); + DEVTYPE_USB_DEVICE = global.allocateUtf8String("usb_device"); + + ATTR_ID_VENDOR = global.allocateUtf8String("idVendor"); + ATTR_ID_PRODUCT = global.allocateUtf8String("idProduct"); + ATTR_MANUFACTURER = global.allocateUtf8String("manufacturer"); + ATTR_PRODUCT = global.allocateUtf8String("product"); + ATTR_SERIAL = global.allocateUtf8String("serial"); + } + @SuppressWarnings({"java:S1181", "java:S2189"}) @Override protected void monitorDevices() { @@ -100,6 +114,7 @@ protected void monitorDevices() { } } + @SuppressWarnings("java:S135") private List enumeratePresentDevices(MemorySegment udevInstance) { List result = new ArrayList<>(); try (var outerCleanup = new ScopeCleanup()) { @@ -172,6 +187,7 @@ private void onDeviceDisconnected(MemorySegment udevDevice) { * @param udevDevice the device (udev_device*) * @return the device instance */ + @SuppressWarnings("java:S106") private USBDevice getDeviceDetails(MemorySegment udevDevice) { int vendorId = 0; @@ -203,7 +219,7 @@ private USBDevice getDeviceDetails(MemorySegment udevDevice) { return device; - } catch (Throwable e) { + } catch (Exception e) { System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device 0x%04x/0x%04x - " + "ignoring device%n", vendorId, productId); e.printStackTrace(System.err); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java index 56aabad7..f3be0b38 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java @@ -9,17 +9,24 @@ /** * Data structures and constants related to the USB device file system. + *

+ * The usbdev_fs header files compute these constants using function like macros. + * Thus, they cannot be generated using jextract. + *

*/ -public class USBDevFS { +class USBDevFS { - public static final long CLAIMINTERFACE = 0x8004550FL; - public static final long RELEASEINTERFACE = 0x80045510L; - public static final long SETINTERFACE = 0x80085504L; - public static final long CLEAR_HALT = 0x80045515L; - public static final long SUBMITURB = 0x8038550AL; - public static final long DISCARDURB = 0x550BL; - public static final long REAPURBNDELAY = 0x4008550DL; - public static final long DISCONNECT_CLAIM = 0x8108551BL; - public static final int CONNECT = 0x5517; - public static final long IOCTL = 0xC0105512L; + private USBDevFS() { + } + + static final long CLAIMINTERFACE = 0x8004550FL; + static final long RELEASEINTERFACE = 0x80045510L; + static final long SETINTERFACE = 0x80085504L; + static final long CLEAR_HALT = 0x80045515L; + static final long SUBMITURB = 0x8038550AL; + static final long DISCARDURB = 0x550BL; + static final long REAPURBNDELAY = 0x4008550DL; + static final long DISCONNECT_CLAIM = 0x8108551BL; + static final int CONNECT = 0x5517; + static final long IOCTL = 0xC0105512L; } From a3f283baf54a8e65e72c58b62a0176c17a6be741 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 28 Jul 2023 19:52:05 +0200 Subject: [PATCH 249/433] More code smells removed --- .../src/main/java/net/codecrete/usb/USB.java | 10 +- .../main/java/net/codecrete/usb/Version.java | 2 +- .../usb/macos/CoreFoundationHelper.java | 13 +- .../net/codecrete/usb/macos/IoKitHelper.java | 26 +-- .../net/codecrete/usb/macos/IoKitUSB.java | 164 +++++++++--------- .../codecrete/usb/macos/MacosAsyncTask.java | 42 +++-- .../codecrete/usb/macos/MacosUSBDevice.java | 98 +++++------ .../usb/macos/MacosUSBDeviceRegistry.java | 91 +++++----- .../java/net/codecrete/usb/macos/UUID.java | 11 +- .../usbstandard/ConfigurationDescriptor.java | 1 + .../codecrete/usb/usbstandard/Constants.java | 3 + .../usb/usbstandard/DeviceDescriptor.java | 1 + .../usb/usbstandard/EndpointDescriptor.java | 1 + .../InterfaceAssociationDescriptor.java | 2 +- .../usb/usbstandard/InterfaceDescriptor.java | 1 + .../usb/usbstandard/SetupPacket.java | 1 + .../usb/usbstandard/StringDescriptor.java | 3 +- 17 files changed, 251 insertions(+), 219 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USB.java b/java-does-usb/src/main/java/net/codecrete/usb/USB.java index f77b4dd3..d3f46e2a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USB.java @@ -15,16 +15,14 @@ import java.util.List; import java.util.function.Consumer; -import static java.util.stream.Collectors.toList; - /** * Provides access to USB devices. */ public class USB { private static USBDeviceRegistry createInstance() { - String osName = System.getProperty("os.name"); - String osArch = System.getProperty("os.arch"); + var osName = System.getProperty("os.name"); + var osArch = System.getProperty("os.arch"); USBDeviceRegistry impl; if (osName.equals("Mac OS X") && (osArch.equals("x86_64") || osArch.equals("aarch64"))) { @@ -74,7 +72,7 @@ public static List getAllDevices() { * @return list of USB devices */ public static List getDevices(USBDevicePredicate predicate) { - return instance().getAllDevices().stream().filter(predicate::matches).collect(toList()); + return instance().getAllDevices().stream().filter(predicate::matches).toList(); } /** @@ -84,7 +82,7 @@ public static List getDevices(USBDevicePredicate predicate) { * @return list of USB devices */ public static List getDevices(List predicates) { - return instance().getAllDevices().stream().filter(dev -> USBDevicePredicate.matchesAny(dev, predicates)).collect(toList()); + return instance().getAllDevices().stream().filter(dev -> USBDevicePredicate.matchesAny(dev, predicates)).toList(); } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/Version.java b/java-does-usb/src/main/java/net/codecrete/usb/Version.java index d2b4fd95..106d7b74 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/Version.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/Version.java @@ -67,7 +67,7 @@ public boolean equals(Object o) { return true; if (o == null || getClass() != o.getClass()) return false; - Version version = (Version) o; + var version = (Version) o; return bcdVersion == version.bcdVersion; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java index c73542ee..c9b884cc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java @@ -20,7 +20,10 @@ /** * Core Foundation helper functions */ -public class CoreFoundationHelper { +class CoreFoundationHelper { + + private CoreFoundationHelper() { + } /** * Gets Java string as a copy of the {@code CFStringRef}. @@ -29,9 +32,9 @@ public class CoreFoundationHelper { * @param arena the arena to allocate memory * @return copied string */ - public static String stringFromCFStringRef(MemorySegment string, Arena arena) { + static String stringFromCFStringRef(MemorySegment string, Arena arena) { - long strLen = CoreFoundation.CFStringGetLength(string); + var strLen = CoreFoundation.CFStringGetLength(string); var buffer = arena.allocateArray(JAVA_CHAR, strLen); var range = arena.allocate(CFRange.$LAYOUT()); CFRange.location$set(range, 0); @@ -51,8 +54,8 @@ public static String stringFromCFStringRef(MemorySegment string, Arena arena) { * @param allocator the allocator for allocating memory * @return {@code CFStringRef} */ - public static MemorySegment createCFStringRef(String string, SegmentAllocator allocator) { - char[] charArray = string.toCharArray(); + static MemorySegment createCFStringRef(String string, SegmentAllocator allocator) { + var charArray = string.toCharArray(); var chars = allocator.allocateArray(JAVA_CHAR, charArray.length); chars.copyFrom(MemorySegment.ofArray(charArray)); return CoreFoundation.CFStringCreateWithCharacters(NULL, chars, string.length()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index 769cc110..b508a015 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -25,20 +25,24 @@ /** * Constants and helper functions for the IOKit framework. */ -public class IoKitHelper { - public static final MemorySegment kIOUSBDeviceUserClientTypeID = UUID.CreateCFUUID(new byte[]{(byte) 0x9d, +class IoKitHelper { + + private IoKitHelper() { + } + + static final MemorySegment kIOUSBDeviceUserClientTypeID = UUID.createCFUUID(new byte[]{(byte) 0x9d, (byte) 0xc7, (byte) 0xb7, (byte) 0x80, (byte) 0x9e, (byte) 0xc0, (byte) 0x11, (byte) 0xD4, (byte) 0xa5, (byte) 0x4f, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61}); - public static final MemorySegment kIOUSBInterfaceUserClientTypeID = UUID.CreateCFUUID(new byte[]{(byte) 0x2d, + static final MemorySegment kIOUSBInterfaceUserClientTypeID = UUID.createCFUUID(new byte[]{(byte) 0x2d, (byte) 0x97, (byte) 0x86, (byte) 0xc6, (byte) 0x9e, (byte) 0xf3, (byte) 0x11, (byte) 0xD4, (byte) 0xad, (byte) 0x51, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x05, (byte) 0x28, (byte) 0x61}); - public static final MemorySegment kIOUSBDeviceInterfaceID187 = UUID.CreateCFUUID(new byte[]{(byte) 0x3c, + static final MemorySegment kIOUSBDeviceInterfaceID187 = UUID.createCFUUID(new byte[]{(byte) 0x3c, (byte) 0x9e, (byte) 0xe1, (byte) 0xeb, (byte) 0x24, (byte) 0x02, (byte) 0x11, (byte) 0xb2, (byte) 0x8e, (byte) 0x7e, (byte) 0x00, (byte) 0x0a, (byte) 0x27, (byte) 0x80, (byte) 0x1e, (byte) 0x86}); - public static final MemorySegment kIOUSBInterfaceInterfaceID190 = UUID.CreateCFUUID(new byte[]{(byte) 0x8f, + static final MemorySegment kIOUSBInterfaceInterfaceID190 = UUID.createCFUUID(new byte[]{(byte) 0x8f, (byte) 0xdb, (byte) 0x84, (byte) 0x55, (byte) 0x74, (byte) 0xa6, (byte) 0x11, (byte) 0xD6, (byte) 0x97, (byte) 0xb1, (byte) 0x00, (byte) 0x30, (byte) 0x65, (byte) 0xd3, (byte) 0x60, (byte) 0x8e}); - public static final MemorySegment kIOCFPlugInInterfaceID = UUID.CreateCFUUID(new byte[]{(byte) 0xC2, (byte) 0x44, + static final MemorySegment kIOCFPlugInInterfaceID = UUID.createCFUUID(new byte[]{(byte) 0xC2, (byte) 0x44, (byte) 0xE8, (byte) 0x58, (byte) 0x10, (byte) 0x9C, (byte) 0x11, (byte) 0xD4, (byte) 0x91, (byte) 0xD4, (byte) 0x00, (byte) 0x50, (byte) 0xE4, (byte) 0xC6, (byte) 0x42, (byte) 0x6F}); @@ -104,13 +108,13 @@ static MemorySegment getVtable(MemorySegment self) { * @param interfaceId the interface ID * @return object instance implementing the interface, or {@code null} if the plugin type or interface is not available */ - public static MemorySegment getInterface(int service, MemorySegment pluginType, MemorySegment interfaceId) { + static MemorySegment getInterface(int service, MemorySegment pluginType, MemorySegment interfaceId) { try (var arena = Arena.ofConfined()) { // MemorySegment for holding IOCFPlugInInterface** var plugHolder = arena.allocate(ADDRESS, NULL); // MemorySegment for holding score var score = arena.allocate(JAVA_INT, 0); - int ret = IOKit.IOCreatePlugInInterfaceForService(service, pluginType, kIOCFPlugInInterfaceID, plugHolder + var ret = IOKit.IOCreatePlugInInterfaceForService(service, pluginType, kIOCFPlugInInterfaceID, plugHolder , score); if (ret != 0) return null; @@ -139,7 +143,7 @@ public static MemorySegment getInterface(int service, MemorySegment pluginType, * @param arena the arena for allocating memory * @return the property value, or {@code null} if the service doesn't have the property */ - public static Integer getPropertyInt(int service, MemorySegment key, Arena arena) { + static Integer getPropertyInt(int service, MemorySegment key, Arena arena) { var value = IOKit.IORegistryEntryCreateCFProperty(service, key, NULL, 0); if (value.address() == 0) @@ -169,7 +173,7 @@ public static Integer getPropertyInt(int service, MemorySegment key, Arena arena * @param arena the arena for allocating memory * @return the property value, or {@code null} if the service doesn't have the property */ - public static String getPropertyString(int service, MemorySegment key, Arena arena) { + static String getPropertyString(int service, MemorySegment key, Arena arena) { var value = IOKit.IORegistryEntryCreateCFProperty(service, key, NULL, 0); if (value.address() == 0) @@ -186,7 +190,7 @@ public static String getPropertyString(int service, MemorySegment key, Arena are } // debugging aid - public static int getRefCount(MemorySegment self) { + static int getRefCount(MemorySegment self) { return (int) refCount$VH.get(self); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index 50a371f5..d2d3523c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -7,8 +7,8 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.macos.gen.iokit.IOUSBDeviceInterface187; -import net.codecrete.usb.macos.gen.iokit.IOUSBInterfaceInterface190; +import net.codecrete.usb.macos.gen.iokit.IOUSBDeviceStruct187; +import net.codecrete.usb.macos.gen.iokit.IOUSBInterfaceStruct190; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; @@ -18,161 +18,165 @@ /** * Helper functions to call the virtual methods of IOKit USB interfaces. */ -public class IoKitUSB { +@SuppressWarnings({"java:S100", "java:S107", "UnusedReturnValue", "SameParameterValue"}) +class IoKitUSB { - // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv); - public static int QueryInterface(MemorySegment self, MemorySegment iid, MemorySegment ppv) { - return IOUSBDeviceInterface187.QueryInterface(getVtable(self), Arena.global()).apply(self, iid, ppv); + private IoKitUSB() { } - // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer); - public static int AddRef(MemorySegment self) { - return IOUSBDeviceInterface187.AddRef(getVtable(self), Arena.global()).apply(self); + // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv) + static int QueryInterface(MemorySegment self, MemorySegment iid, MemorySegment ppv) { + return IOUSBDeviceStruct187.QueryInterface(getVtable(self), Arena.global()).apply(self, iid, ppv); + } + + // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer) + static int AddRef(MemorySegment self) { + return IOUSBDeviceStruct187.AddRef(getVtable(self), Arena.global()).apply(self); } // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer) - public static int Release(MemorySegment self) { - return IOUSBDeviceInterface187.Release(getVtable(self), Arena.global()).apply(self); + static int Release(MemorySegment self) { + return IOUSBDeviceStruct187.Release(getVtable(self), Arena.global()).apply(self); } - // IOReturn (* CreateDeviceAsyncEventSource)(void* self, CFRunLoopSourceRef* source); - public static int CreateDeviceAsyncEventSource(MemorySegment self, MemorySegment source) { - return IOUSBDeviceInterface187.CreateDeviceAsyncEventSource(getVtable(self), Arena.global()).apply(self, + // IOReturn (* CreateDeviceAsyncEventSource)(void* self, CFRunLoopSourceRef* source) + static int CreateDeviceAsyncEventSource(MemorySegment self, MemorySegment source) { + return IOUSBDeviceStruct187.CreateDeviceAsyncEventSource(getVtable(self), Arena.global()).apply(self, source); } - // CFRunLoopSourceRef (* GetDeviceAsyncEventSource)(void* self); - public static MemorySegment GetDeviceAsyncEventSource(MemorySegment self) { - return IOUSBDeviceInterface187.GetDeviceAsyncEventSource(getVtable(self), Arena.global()).apply(self); + // CFRunLoopSourceRef (* GetDeviceAsyncEventSource)(void* self) + static MemorySegment GetDeviceAsyncEventSource(MemorySegment self) { + return IOUSBDeviceStruct187.GetDeviceAsyncEventSource(getVtable(self), Arena.global()).apply(self); } - // IOReturn (*USBDeviceOpenSeize)(void *self); - public static int USBDeviceOpenSeize(MemorySegment self) { - return IOUSBDeviceInterface187.USBDeviceOpenSeize(getVtable(self), Arena.global()).apply(self); + // IOReturn (*USBDeviceOpenSeize)(void *self) + static int USBDeviceOpenSeize(MemorySegment self) { + return IOUSBDeviceStruct187.USBDeviceOpenSeize(getVtable(self), Arena.global()).apply(self); } - // IOReturn (*USBDeviceClose)(void *self); - public static int USBDeviceClose(MemorySegment self) { - return IOUSBDeviceInterface187.USBDeviceClose(getVtable(self), Arena.global()).apply(self); + // IOReturn (*USBDeviceClose)(void *self) + static int USBDeviceClose(MemorySegment self) { + return IOUSBDeviceStruct187.USBDeviceClose(getVtable(self), Arena.global()).apply(self); } - // IOReturn (* USBDeviceReEnumerate)(void* self, UInt32 options); - public static int USBDeviceReEnumerate(MemorySegment self, int options) { - return IOUSBDeviceInterface187.USBDeviceReEnumerate(getVtable(self), Arena.global()).apply(self, options); + // IOReturn (* USBDeviceReEnumerate)(void* self, UInt32 options) + static int USBDeviceReEnumerate(MemorySegment self, int options) { + return IOUSBDeviceStruct187.USBDeviceReEnumerate(getVtable(self), Arena.global()).apply(self, options); } - // IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc); - public static int GetConfigurationDescriptorPtr(MemorySegment self, byte configIndex, MemorySegment descHolder) { - return IOUSBDeviceInterface187.GetConfigurationDescriptorPtr(getVtable(self), Arena.global()).apply(self, + // IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc) + static int GetConfigurationDescriptorPtr(MemorySegment self, byte configIndex, MemorySegment descHolder) { + return IOUSBDeviceStruct187.GetConfigurationDescriptorPtr(getVtable(self), Arena.global()).apply(self, configIndex, descHolder); } - // IOReturn (*SetConfiguration)(void *self, UInt8 configNum); - public static int SetConfiguration(MemorySegment self, byte configValue) { - return IOUSBDeviceInterface187.SetConfiguration(getVtable(self), Arena.global()).apply(self, configValue); + // IOReturn (*SetConfiguration)(void *self, UInt8 configNum) + static int SetConfiguration(MemorySegment self, byte configValue) { + return IOUSBDeviceStruct187.SetConfiguration(getVtable(self), Arena.global()).apply(self, configValue); } - // IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter); - public static int CreateInterfaceIterator(MemorySegment self, MemorySegment req, MemorySegment iter) { - return IOUSBDeviceInterface187.CreateInterfaceIterator(getVtable(self), Arena.global()).apply(self, req, iter); + // IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter) + static int CreateInterfaceIterator(MemorySegment self, MemorySegment req, MemorySegment iter) { + return IOUSBDeviceStruct187.CreateInterfaceIterator(getVtable(self), Arena.global()).apply(self, req, iter); } - // IOReturn (* DeviceRequestAsync)(void* self, IOUSBDevRequest* req, IOAsyncCallback1 callback, void* refCon); - public static int DeviceRequestAsync(MemorySegment self, MemorySegment deviceRequest, MemorySegment callback, + // IOReturn (* DeviceRequestAsync)(void* self, IOUSBDevRequest* req, IOAsyncCallback1 callback, void* refCon) + static int DeviceRequestAsync(MemorySegment self, MemorySegment deviceRequest, MemorySegment callback, MemorySegment refCon) { - return IOUSBDeviceInterface187.DeviceRequestAsync(getVtable(self), Arena.global()).apply(self, deviceRequest, + return IOUSBDeviceStruct187.DeviceRequestAsync(getVtable(self), Arena.global()).apply(self, deviceRequest, callback, refCon); } - // IOReturn (*USBInterfaceOpen)(void *self);; - public static int USBInterfaceOpen(MemorySegment self) { - return IOUSBInterfaceInterface190.USBInterfaceOpen(getVtable(self), Arena.global()).apply(self); + // IOReturn (*USBInterfaceOpen)(void *self) + static int USBInterfaceOpen(MemorySegment self) { + return IOUSBInterfaceStruct190.USBInterfaceOpen(getVtable(self), Arena.global()).apply(self); } - // IOReturn (*USBInterfaceClose)(void *self);; - public static int USBInterfaceClose(MemorySegment self) { - return IOUSBInterfaceInterface190.USBInterfaceClose(getVtable(self), Arena.global()).apply(self); + // IOReturn (*USBInterfaceClose)(void *self) + static int USBInterfaceClose(MemorySegment self) { + return IOUSBInterfaceStruct190.USBInterfaceClose(getVtable(self), Arena.global()).apply(self); } - // IOReturn (*GetInterfaceNumber)(void *self, UInt8 *intfNumber); - public static int GetInterfaceNumber(MemorySegment self, MemorySegment intfNumberHolder) { - return IOUSBInterfaceInterface190.GetInterfaceNumber(getVtable(self), Arena.global()).apply(self, + // IOReturn (*GetInterfaceNumber)(void *self, UInt8 *intfNumber) + static int GetInterfaceNumber(MemorySegment self, MemorySegment intfNumberHolder) { + return IOUSBInterfaceStruct190.GetInterfaceNumber(getVtable(self), Arena.global()).apply(self, intfNumberHolder); } - // IOReturn (*GetNumEndpoints)(void *self, UInt8 *intfNumEndpoints); - public static int GetNumEndpoints(MemorySegment self, MemorySegment intfNumEndpointsHolder) { - return IOUSBInterfaceInterface190.GetNumEndpoints(getVtable(self), Arena.global()).apply(self, + // IOReturn (*GetNumEndpoints)(void *self, UInt8 *intfNumEndpoints) + static int GetNumEndpoints(MemorySegment self, MemorySegment intfNumEndpointsHolder) { + return IOUSBInterfaceStruct190.GetNumEndpoints(getVtable(self), Arena.global()).apply(self, intfNumEndpointsHolder); } // IOReturn (*GetPipeProperties)(void *self, UInt8 pipeRef, UInt8 *direction, UInt8 *number, UInt8 *transferType, - // UInt16 *maxPacketSize, UInt8 *interval); - public static int GetPipeProperties(MemorySegment self, byte pipeRef, MemorySegment directionHolder, + // UInt16 *maxPacketSize, UInt8 *interval) + static int GetPipeProperties(MemorySegment self, byte pipeRef, MemorySegment directionHolder, MemorySegment numberHolder, MemorySegment transferTypeHolder, MemorySegment maxPacketSizeHolder, MemorySegment intervalHolder) { - return IOUSBInterfaceInterface190.GetPipeProperties(getVtable(self), Arena.global()).apply(self, pipeRef, + return IOUSBInterfaceStruct190.GetPipeProperties(getVtable(self), Arena.global()).apply(self, pipeRef, directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); } // IOReturn (*ReadPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, void - // *refcon); - public static int ReadPipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, + // *refcon) + static int ReadPipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceInterface190.ReadPipeAsync(getVtable(self), Arena.global()).apply(self, pipeRef, buf, + return IOUSBInterfaceStruct190.ReadPipeAsync(getVtable(self), Arena.global()).apply(self, pipeRef, buf, size, callback, refcon); } // IOReturn (*ReadPipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 - // completionTimeout, IOAsyncCallback1 callback, void *refcon); - public static int ReadPipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, + // completionTimeout, IOAsyncCallback1 callback, void *refcon) + static int ReadPipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, int noDataTimeout, int completionTimeout, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceInterface190.ReadPipeAsyncTO(getVtable(self), Arena.global()).apply(self, pipeRef, buf, + return IOUSBInterfaceStruct190.ReadPipeAsyncTO(getVtable(self), Arena.global()).apply(self, pipeRef, buf, size, noDataTimeout, completionTimeout, callback, refcon); } // IOReturn (*WritePipeAsync)(vovoid *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, - // void *refcon); - public static int WritePipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, + // void *refcon) + static int WritePipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceInterface190.WritePipeAsync(getVtable(self), Arena.global()).apply(self, pipeRef, buf, + return IOUSBInterfaceStruct190.WritePipeAsync(getVtable(self), Arena.global()).apply(self, pipeRef, buf, size, callback, refcon); } // IOReturn (*WritePipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 - // completionTimeout, IOAsyncCallback1 callback, void *refcon); - public static int WritePipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, + // completionTimeout, IOAsyncCallback1 callback, void *refcon) + static int WritePipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, int noDataTimeout, int completionTimeout, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceInterface190.WritePipeAsyncTO(getVtable(self), Arena.global()).apply(self, pipeRef, buf, + return IOUSBInterfaceStruct190.WritePipeAsyncTO(getVtable(self), Arena.global()).apply(self, pipeRef, buf, size, noDataTimeout, completionTimeout, callback, refcon); } - // IOReturn (* AbortPipe)(void* self, UInt8 pipeRef); - public static int AbortPipe(MemorySegment self, byte pipeRef) { - return IOUSBInterfaceInterface190.AbortPipe(getVtable(self), Arena.global()).apply(self, pipeRef); + // IOReturn (* AbortPipe)(void* self, UInt8 pipeRef) + static int AbortPipe(MemorySegment self, byte pipeRef) { + return IOUSBInterfaceStruct190.AbortPipe(getVtable(self), Arena.global()).apply(self, pipeRef); } - // IOReturn (*SetAlternateInterface)(void *self, UInt8 alternateSetting); - public static int SetAlternateInterface(MemorySegment self, byte alternateSetting) { - return IOUSBInterfaceInterface190.SetAlternateInterface(getVtable(self), Arena.global()).apply(self, + // IOReturn (*SetAlternateInterface)(void *self, UInt8 alternateSetting) + static int SetAlternateInterface(MemorySegment self, byte alternateSetting) { + return IOUSBInterfaceStruct190.SetAlternateInterface(getVtable(self), Arena.global()).apply(self, alternateSetting); } - // IOReturn (* ClearPipeStallBothEnds)(void* self, UInt8 pipeRef); - public static int ClearPipeStallBothEnds(MemorySegment self, byte pipeRef) { - return IOUSBInterfaceInterface190.ClearPipeStallBothEnds(getVtable(self), Arena.global()).apply(self, pipeRef); + // IOReturn (* ClearPipeStallBothEnds)(void* self, UInt8 pipeRef) + static int ClearPipeStallBothEnds(MemorySegment self, byte pipeRef) { + return IOUSBInterfaceStruct190.ClearPipeStallBothEnds(getVtable(self), Arena.global()).apply(self, pipeRef); } - // CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void* self); - public static MemorySegment GetInterfaceAsyncEventSource(MemorySegment self) { - return IOUSBInterfaceInterface190.GetInterfaceAsyncEventSource(getVtable(self), Arena.global()).apply(self); + // CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void* self) + static MemorySegment GetInterfaceAsyncEventSource(MemorySegment self) { + return IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource(getVtable(self), Arena.global()).apply(self); } - // IOReturn (*CreateInterfaceAsyncEventSource)(void *self, CFRunLoopSourceRef *source); - public static int CreateInterfaceAsyncEventSource(MemorySegment self, MemorySegment source) { - return IOUSBInterfaceInterface190.CreateInterfaceAsyncEventSource(getVtable(self), Arena.global()).apply(self + // IOReturn (*CreateInterfaceAsyncEventSource)(void *self, CFRunLoopSourceRef *source) + static int CreateInterfaceAsyncEventSource(MemorySegment self, MemorySegment source) { + return IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource(getVtable(self), Arena.global()).apply(self , source); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java index eeb780bf..a2200051 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java @@ -7,6 +7,7 @@ package net.codecrete.usb.macos; +import net.codecrete.usb.USBException; import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; import net.codecrete.usb.macos.gen.iokit.IOKit; @@ -34,20 +35,13 @@ * {@code refcon} argument to match callbacks with the submitted transfer. *

*/ +@SuppressWarnings("java:S6548") class MacosAsyncTask { - private static MacosAsyncTask singletonInstance; - /** * Singleton instance of background task. - * - * @return background task */ - static synchronized MacosAsyncTask instance() { - if (singletonInstance == null) - singletonInstance = new MacosAsyncTask(); - return singletonInstance; - } + static final MacosAsyncTask INSTANCE = new MacosAsyncTask(); private final ReentrantLock asyncIoLock = new ReentrantLock(); private Condition asyncIoReady; @@ -72,15 +66,12 @@ void addEventSource(MemorySegment source) { asyncIoReady = asyncIoLock.newCondition(); startAsyncIOThread(source); - while (asyncIoRunLoop == null) - asyncIoReady.awaitUninterruptibly(); - + waitForRunLoopReady(); return; } else { // special case: run loop is not ready yet but background process is already starting - while (asyncIoRunLoop == null) - asyncIoReady.awaitUninterruptibly(); + waitForRunLoopReady(); } } @@ -91,6 +82,16 @@ void addEventSource(MemorySegment source) { } } + private void waitForRunLoopReady() { + while (true) { + synchronized (this) { + if (asyncIoRunLoop != null) + return; + } + asyncIoReady.awaitUninterruptibly(); + } + } + /** * Removes an event source from this background task. * @@ -116,12 +117,12 @@ private void startAsyncIOThread(MemorySegment firstSource) { Arena.global()); } catch (IllegalAccessException | NoSuchMethodException e) { - throw new RuntimeException(e); + throw new USBException("Creating method handle failed", e); } - Thread t = new Thread(() -> asyncIOCompletionTask(firstSource), "USB async IO"); - t.setDaemon(true); - t.start(); + var thread = new Thread(() -> asyncIOCompletionTask(firstSource), "USB async IO"); + thread.setDaemon(true); + thread.start(); } /** @@ -136,7 +137,9 @@ private void startAsyncIOThread(MemorySegment firstSource) { private void asyncIOCompletionTask(MemorySegment firstSource) { try { asyncIoLock.lock(); - asyncIoRunLoop = CoreFoundation.CFRunLoopGetCurrent(); + synchronized (this) { + asyncIoRunLoop = CoreFoundation.CFRunLoopGetCurrent(); + } CoreFoundation.CFRunLoopAddSource(asyncIoRunLoop, firstSource, IOKit.kCFRunLoopDefaultMode$get()); asyncIoReady.signalAll(); } finally { @@ -170,6 +173,7 @@ synchronized void prepareForSubmission(MacosTransfer transfer) { * @param result contains result code * @param arg0 contains actual length of transferred data */ + @SuppressWarnings("java:S1144") private void asyncIOCompleted(MemorySegment refcon, int result, MemorySegment arg0) { MacosTransfer transfer; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index b7e297c7..3f2d2134 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -43,7 +43,7 @@ * asynchronous transfer and waiting for the completion. *

*/ -@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") +@SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter", "java:S2160"}) public class MacosUSBDevice extends USBDeviceImpl { private final MacosAsyncTask asyncTask; @@ -61,7 +61,7 @@ public class MacosUSBDevice extends USBDeviceImpl { MacosUSBDevice(MemorySegment device, Object id, int vendorId, int productId) { super(id, vendorId, productId); discoveryTime = System.currentTimeMillis(); - asyncTask = MacosAsyncTask.instance(); + asyncTask = MacosAsyncTask.INSTANCE; loadDescription(device); @@ -73,7 +73,7 @@ public class MacosUSBDevice extends USBDeviceImpl { public void detachStandardDrivers() { if (isOpen()) throwException("detachStandardDrivers() must not be called while the device is open"); - int ret = IoKitUSB.USBDeviceReEnumerate(device, IOKit.kUSBReEnumerateCaptureDeviceMask()); + var ret = IoKitUSB.USBDeviceReEnumerate(device, IOKit.kUSBReEnumerateCaptureDeviceMask()); if (ret != 0) throwException(ret, "failed to detach kernel drivers"); } @@ -82,7 +82,7 @@ public void detachStandardDrivers() { public void attachStandardDrivers() { if (isOpen()) throwException("attachStandardDrivers() must not be called while the device is open"); - int ret = IoKitUSB.USBDeviceReEnumerate(device, IOKit.kUSBReEnumerateReleaseDeviceMask()); + var ret = IoKitUSB.USBDeviceReEnumerate(device, IOKit.kUSBReEnumerateReleaseDeviceMask()); if (ret != 0) throwException(ret, "failed to attach kernel drivers"); } @@ -92,15 +92,16 @@ public boolean isOpen() { return claimedInterfaces != null; } + @SuppressWarnings("java:S2276") @Override public synchronized void open() { if (isOpen()) throwException("the device is already open"); // open device (several retries if device has just been connected/discovered) - long duration = System.currentTimeMillis() - discoveryTime; - int numTries = duration < 1000 ? 4 : 1; - int ret = 0; + var duration = System.currentTimeMillis() - discoveryTime; + var numTries = duration < 1000 ? 4 : 1; + var ret = 0; while (numTries > 0) { numTries -= 1; ret = IoKitUSB.USBDeviceOpenSeize(device); @@ -111,7 +112,7 @@ public synchronized void open() { try { Thread.sleep(90); } catch (InterruptedException e) { - // ignore + Thread.currentThread().interrupt(); } } if (ret != 0) @@ -162,7 +163,7 @@ private void loadDescription(MemorySegment device) { // retrieve information of first configuration var descPtrHolder = arena.allocate(ADDRESS); - int ret = IoKitUSB.GetConfigurationDescriptorPtr(device, (byte) 0, descPtrHolder); + var ret = IoKitUSB.GetConfigurationDescriptorPtr(device, (byte) 0, descPtrHolder); if (ret != 0) throwException(ret, "failed to query first configuration"); @@ -175,6 +176,7 @@ private void loadDescription(MemorySegment device) { } } + @SuppressWarnings("java:S135") private InterfaceInfo findInterface(int interfaceNumber) { try (var arena = Arena.ofConfined(); var outerCleanup = new ScopeCleanup()) { @@ -185,7 +187,7 @@ private InterfaceInfo findInterface(int interfaceNumber) { IOUSBFindInterfaceRequest.bAlternateSetting$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); var iterHolder = arena.allocate(JAVA_INT); - int ret = IoKitUSB.CreateInterfaceIterator(device, request, iterHolder); + var ret = IoKitUSB.CreateInterfaceIterator(device, request, iterHolder); if (ret != 0) throwException("CreateInterfaceIterator failed"); @@ -198,7 +200,7 @@ private InterfaceInfo findInterface(int interfaceNumber) { while ((service = IOKit.IOIteratorNext(iter)) != 0) { try (var cleanup = new ScopeCleanup()) { - final int service_final = service; + final var service_final = service; cleanup.add(() -> IOKit.IOObjectRelease(service_final)); final var intf = IoKitHelper.getInterface(service, IoKitHelper.kIOUSBInterfaceUserClientTypeID, @@ -224,6 +226,7 @@ private InterfaceInfo findInterface(int interfaceNumber) { public synchronized void claimInterface(int interfaceNumber) { checkIsOpen(); + getInterfaceWithCheck(interfaceNumber, false); try (var cleanup = new ScopeCleanup()) { @@ -243,14 +246,10 @@ public synchronized void claimInterface(int interfaceNumber) { updateEndpointList(); } - @SuppressWarnings("OptionalGetWithoutIsPresent") + @SuppressWarnings({"OptionalGetWithoutIsPresent", "java:S3655"}) public synchronized void selectAlternateSetting(int interfaceNumber, int alternateNumber) { // check interface - var intf = getInterface(interfaceNumber); - if (intf == null) - throwException("Interface %d does not exist", interfaceNumber); - if (!intf.isClaimed()) - throwException("Interface %d has not been claimed", interfaceNumber); + var intf = getInterfaceWithCheck(interfaceNumber, true); // check alternate setting var altSetting = intf.getAlternate(alternateNumber); @@ -259,9 +258,9 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna alternateNumber); var intfInfo = - claimedInterfaces.stream().filter((interf) -> interf.interfaceNumber() == interfaceNumber).findFirst().get(); + claimedInterfaces.stream().filter(interf -> interf.interfaceNumber() == interfaceNumber).findFirst().get(); - int ret = IoKitUSB.SetAlternateInterface(intfInfo.iokitInterface(), (byte) alternateNumber); + var ret = IoKitUSB.SetAlternateInterface(intfInfo.iokitInterface(), (byte) alternateNumber); if (ret != 0) throwException(ret, "Failed to set alternate interface"); @@ -269,21 +268,20 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna updateEndpointList(); } + @SuppressWarnings({"OptionalGetWithoutIsPresent", "java:S3655"}) public synchronized void releaseInterface(int interfaceNumber) { checkIsOpen(); + getInterfaceWithCheck(interfaceNumber, true); - var interfaceInfoOptional = - claimedInterfaces.stream().filter(info -> info.interfaceNumber == interfaceNumber).findFirst(); - if (interfaceInfoOptional.isEmpty()) - throwException("Invalid interface number: %d", interfaceNumber); - - var interfaceInfo = interfaceInfoOptional.get(); + @SuppressWarnings("OptionalGetWithoutIsPresent") + var interfaceInfo = + claimedInterfaces.stream().filter(info -> info.interfaceNumber == interfaceNumber).findFirst().get(); var source = IoKitUSB.GetInterfaceAsyncEventSource(interfaceInfo.iokitInterface()); if (source.address() != 0) asyncTask.removeEventSource(source); - int ret = IoKitUSB.USBInterfaceClose(interfaceInfo.iokitInterface()); + var ret = IoKitUSB.USBInterfaceClose(interfaceInfo.iokitInterface()); if (ret != 0) throwException(ret, "Failed to release interface"); @@ -312,27 +310,27 @@ private void updateEndpointList() { var maxPacketSizeHolder = arena.allocate(JAVA_SHORT); var intervalHolder = arena.allocate(JAVA_BYTE); - for (InterfaceInfo interfaceInfo : claimedInterfaces) { + for (var interfaceInfo : claimedInterfaces) { var intf = interfaceInfo.iokitInterface(); var numEndpointsHolder = arena.allocate(JAVA_BYTE); - int ret = IoKitUSB.GetNumEndpoints(intf, numEndpointsHolder); + var ret = IoKitUSB.GetNumEndpoints(intf, numEndpointsHolder); if (ret != 0) throwException(ret, "Failed to get number of endpoints"); - int numEndpoints = numEndpointsHolder.get(JAVA_BYTE, 0) & 255; + var numEndpoints = numEndpointsHolder.get(JAVA_BYTE, 0) & 255; - for (int pipeIndex = 1; pipeIndex <= numEndpoints; pipeIndex++) { + for (var pipeIndex = 1; pipeIndex <= numEndpoints; pipeIndex++) { ret = IoKitUSB.GetPipeProperties(intf, (byte) pipeIndex, directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); if (ret != 0) throwException(ret, "Failed to get pipe properties"); - int endpointNumber = numberHolder.get(JAVA_BYTE, 0) & 0xff; - int direction = directionHolder.get(JAVA_BYTE, 0) & 0xff; - byte endpointAddress = (byte) (endpointNumber | (direction << 7)); - byte transferType = transferTypeHolder.get(JAVA_BYTE, 0); - int maxPacketSize = maxPacketSizeHolder.get(JAVA_SHORT, 0) & 0xffff; + var endpointNumber = numberHolder.get(JAVA_BYTE, 0) & 0xff; + var direction = directionHolder.get(JAVA_BYTE, 0) & 0xff; + var endpointAddress = (byte) (endpointNumber | (direction << 7)); + var transferType = transferTypeHolder.get(JAVA_BYTE, 0); + var maxPacketSize = maxPacketSizeHolder.get(JAVA_SHORT, 0) & 0xffff; var endpointInfo = new EndpointInfo(interfaceInfo.iokitInterface(), (byte) pipeIndex, getTransferType(transferType), maxPacketSize); endpoints.put(endpointAddress, endpointInfo); @@ -345,7 +343,7 @@ private void updateEndpointList() { private synchronized EndpointInfo getEndpointInfo(int endpointNumber, USBDirection direction, USBTransferType transferType1, USBTransferType transferType2) { if (endpoints != null) { - byte endpointAddress = (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)); + var endpointAddress = (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)); var endpointInfo = endpoints.get(endpointAddress); if (endpointInfo != null && (endpointInfo.transferType == transferType1 || endpointInfo.transferType == transferType2)) return endpointInfo; @@ -397,7 +395,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { @Override public void controlTransferOut(USBControlTransfer setup, byte[] data) { try (var arena = Arena.ofConfined()) { - int dataLength = data != null ? data.length : 0; + var dataLength = data != null ? data.length : 0; var dataSegment = arena.allocate(dataLength); if (dataLength > 0) dataSegment.copyFrom(MemorySegment.ofArray(data)); @@ -416,7 +414,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { @Override public void transferOut(int endpointNumber, byte[] data, int offset, int length, int timeout) { - EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, + var epInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); try (var arena = Arena.ofConfined()) { @@ -446,7 +444,7 @@ public void transferOut(int endpointNumber, byte[] data, int offset, int length, @Override public byte[] transferIn(int endpointNumber, int timeout) { - EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, + var epInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); try (var arena = Arena.ofConfined()) { @@ -486,7 +484,7 @@ public byte[] transferIn(int endpointNumber, int timeout) { */ synchronized void submitTransferIn(int endpointNumber, MacosTransfer transfer, int timeout) { - EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, + var epInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, USBTransferType.INTERRUPT); asyncTask.prepareForSubmission(transfer); @@ -516,7 +514,7 @@ synchronized void submitTransferIn(int endpointNumber, MacosTransfer transfer, i */ synchronized void submitTransferOut(int endpointNumber, MacosTransfer transfer, int timeout) { - EndpointInfo epInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, + var epInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, USBTransferType.INTERRUPT); asyncTask.prepareForSubmission(transfer); @@ -546,7 +544,7 @@ synchronized void submitControlTransfer(MemorySegment deviceRequest, MacosTransf asyncTask.prepareForSubmission(transfer); // submit transfer - int ret = IoKitUSB.DeviceRequestAsync(device, deviceRequest, asyncTask.nativeCompletionCallback(), + var ret = IoKitUSB.DeviceRequestAsync(device, deviceRequest, asyncTask.nativeCompletionCallback(), MemorySegment.ofAddress(transfer.id)); if (ret != 0) @@ -560,20 +558,20 @@ protected Transfer createTransfer() { @Override public void abortTransfers(USBDirection direction, int endpointNumber) { - EndpointInfo epInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, + var epInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); - int ret = IoKitUSB.AbortPipe(epInfo.iokitInterface(), epInfo.pipeIndex()); + var ret = IoKitUSB.AbortPipe(epInfo.iokitInterface(), epInfo.pipeIndex()); if (ret != 0) throwException(ret, "Aborting transfer failed"); } @Override public void clearHalt(USBDirection direction, int endpointNumber) { - EndpointInfo epInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, + var epInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, USBTransferType.INTERRUPT); - int ret = IoKitUSB.ClearPipeStallBothEnds(epInfo.iokitInterface(), epInfo.pipeIndex()); + var ret = IoKitUSB.ClearPipeStallBothEnds(epInfo.iokitInterface(), epInfo.pipeIndex()); if (ret != 0) throwException(ret, "Clearing halt condition failed"); } @@ -609,9 +607,9 @@ private static USBTransferType getTransferType(byte macosTransferType) { } private synchronized void addDeviceEventSource() { - try (Arena innerArena = Arena.ofConfined()) { + try (var innerArena = Arena.ofConfined()) { var sourceHolder = innerArena.allocate(ADDRESS); - int ret = IoKitUSB.CreateDeviceAsyncEventSource(device, sourceHolder); + var ret = IoKitUSB.CreateDeviceAsyncEventSource(device, sourceHolder); if (ret != 0) throwException(ret, "failed to create event source"); var source = dereference(sourceHolder); @@ -620,9 +618,9 @@ private synchronized void addDeviceEventSource() { } private synchronized void addInterfaceEventSource(InterfaceInfo interfaceInfo) { - try (Arena innerArena = Arena.ofConfined()) { + try (var innerArena = Arena.ofConfined()) { var sourceHolder = innerArena.allocate(ADDRESS); - int ret = IoKitUSB.CreateInterfaceAsyncEventSource(interfaceInfo.iokitInterface(), sourceHolder); + var ret = IoKitUSB.CreateInterfaceAsyncEventSource(interfaceInfo.iokitInterface(), sourceHolder); if (ret != 0) throwException(ret, "failed to create event source"); var source = dereference(sourceHolder); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index decd4d4f..79d80dad 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -22,32 +22,39 @@ import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.*; +import static net.codecrete.usb.macos.CoreFoundationHelper.createCFStringRef; import static net.codecrete.usb.macos.MacosUSBException.throwException; /** * MacOS implementation of USB device registry. */ +@SuppressWarnings("java:S116") public class MacosUSBDeviceRegistry extends USBDeviceRegistry { - private final SegmentAllocator GLOBAL_ALLOCATOR = Arena.global(); - - private final MemorySegment KEY_ID_VENDOR = CoreFoundationHelper.createCFStringRef("idVendor", GLOBAL_ALLOCATOR); - private final MemorySegment KEY_ID_PRODUCT = CoreFoundationHelper.createCFStringRef("idProduct", GLOBAL_ALLOCATOR); - private final MemorySegment KEY_VENDOR = CoreFoundationHelper.createCFStringRef("kUSBVendorString", - GLOBAL_ALLOCATOR); - private final MemorySegment KEY_PRODUCT = CoreFoundationHelper.createCFStringRef("kUSBProductString", - GLOBAL_ALLOCATOR); - private final MemorySegment KEY_SERIAL_NUM = CoreFoundationHelper.createCFStringRef("kUSBSerialNumberString", - GLOBAL_ALLOCATOR); - private final MemorySegment KEY_DEVICE_CLASS = CoreFoundationHelper.createCFStringRef("bDeviceClass", - GLOBAL_ALLOCATOR); - private final MemorySegment KEY_DEVICE_SUBCLASS = CoreFoundationHelper.createCFStringRef("bDeviceSubClass", - GLOBAL_ALLOCATOR); - private final MemorySegment KEY_DEVICE_PROTOCOL = CoreFoundationHelper.createCFStringRef("bDeviceProtocol", - GLOBAL_ALLOCATOR); - private final MemorySegment KEY_USB_BCD = CoreFoundationHelper.createCFStringRef("bcdUSB", GLOBAL_ALLOCATOR); - private final MemorySegment KEY_DEVICE_BCD = CoreFoundationHelper.createCFStringRef("bcdDevice", GLOBAL_ALLOCATOR); - + private static final MemorySegment KEY_ID_VENDOR; + private static final MemorySegment KEY_ID_PRODUCT; + private static final MemorySegment KEY_VENDOR; + private static final MemorySegment KEY_PRODUCT; + private static final MemorySegment KEY_SERIAL_NUM; + private static final MemorySegment KEY_DEVICE_CLASS; + private static final MemorySegment KEY_DEVICE_SUBCLASS; + private static final MemorySegment KEY_DEVICE_PROTOCOL; + private static final MemorySegment KEY_USB_BCD; + private static final MemorySegment KEY_DEVICE_BCD; + + static { + SegmentAllocator global = Arena.global(); + KEY_ID_VENDOR = createCFStringRef("idVendor", global); + KEY_ID_PRODUCT = createCFStringRef("idProduct", global); + KEY_VENDOR = createCFStringRef("kUSBVendorString", global); + KEY_PRODUCT = createCFStringRef("kUSBProductString", global); + KEY_SERIAL_NUM = createCFStringRef("kUSBSerialNumberString", global); + KEY_DEVICE_CLASS = createCFStringRef("bDeviceClass", global); + KEY_DEVICE_SUBCLASS = createCFStringRef("bDeviceSubClass", global); + KEY_DEVICE_PROTOCOL = createCFStringRef("bDeviceProtocol", global); + KEY_USB_BCD = createCFStringRef("bcdUSB", global); + KEY_DEVICE_BCD = createCFStringRef("bcdDevice", global); + } /** * Monitors the USB devices. @@ -72,24 +79,24 @@ protected void monitorDevices() { // setup notification for connected devices var onDeviceConnectedMH = MethodHandles.lookup().findVirtual(MacosUSBDeviceRegistry.class, "onDevicesConnected", MethodType.methodType(void.class, MemorySegment.class, int.class)); - int deviceConnectedIter = setupNotification(arena, notifyPort, IOKit.kIOFirstMatchNotification(), + var deviceConnectedIter = setupNotification(arena, notifyPort, IOKit.kIOFirstMatchNotification(), onDeviceConnectedMH); // iterate current devices in order to arm the notifications (and build initial device list) var deviceList = new ArrayList(); - iterateDevices(deviceConnectedIter, (device) -> deviceList.add(device)); + iterateDevices(deviceConnectedIter, device -> deviceList.add(device)); // NOSONAR setInitialDeviceList(deviceList); // setup notification for disconnected devices var onDeviceDisconnectedMH = MethodHandles.lookup().findVirtual(MacosUSBDeviceRegistry.class, "onDevicesDisconnected", MethodType.methodType(void.class, MemorySegment.class, int.class)); - int deviceDisconnectedIter = setupNotification(arena, notifyPort, IOKit.kIOTerminatedNotification(), + var deviceDisconnectedIter = setupNotification(arena, notifyPort, IOKit.kIOTerminatedNotification(), onDeviceDisconnectedMH); // iterate current devices in order to arm the notifications onDevicesDisconnected(NULL, deviceDisconnectedIter); - } catch (Throwable e) { + } catch (Exception e) { enumerationFailed(e); return; } @@ -114,7 +121,7 @@ private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { while ((svc = IOKit.IOIteratorNext(iterator)) != 0) { try (var cleanup = new ScopeCleanup()) { - final int service = svc; + final var service = svc; cleanup.add(() -> IOKit.IOObjectRelease(service)); var device = IoKitHelper.getInterface(service, IoKitHelper.kIOUSBDeviceUserClientTypeID, @@ -123,7 +130,7 @@ private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { cleanup.add(() -> IoKitUSB.Release(device)); // get entry ID (as unique ID) - int ret = IOKit.IORegistryEntryGetRegistryEntryID(service, entryIdHolder); + var ret = IOKit.IORegistryEntryGetRegistryEntryID(service, entryIdHolder); if (ret != 0) throwException(ret, "IORegistryEntryGetRegistryEntryID failed"); var entryId = entryIdHolder.get(JAVA_LONG, 0); @@ -145,6 +152,7 @@ private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { * @param iterator the iterator * @param consumer the consumer */ + @SuppressWarnings("java:S106") private void iterateDevices(int iterator, Consumer consumer) { iterateDevices(iterator, (entryId, service, deviceIntf) -> { @@ -154,7 +162,7 @@ private void iterateDevices(int iterator, Consumer consumer) { if (device != null) consumer.accept(device); - } catch (Throwable e) { + } catch (Exception e) { System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device 0x%04x/0x%04x - " + "ignoring device%n", deviceInfo.vid, deviceInfo.pid); e.printStackTrace(System.err); } @@ -168,8 +176,8 @@ private USBDevice createDevice(Long entryID, int service, MemorySegment deviceIn try (var arena = Arena.ofConfined()) { - Integer vendorId = IoKitHelper.getPropertyInt(service, KEY_ID_VENDOR, arena); - Integer productId = IoKitHelper.getPropertyInt(service, KEY_ID_PRODUCT, arena); + var vendorId = IoKitHelper.getPropertyInt(service, KEY_ID_VENDOR, arena); + var productId = IoKitHelper.getPropertyInt(service, KEY_ID_PRODUCT, arena); if (vendorId == null || productId == null) return null; @@ -178,21 +186,21 @@ private USBDevice createDevice(Long entryID, int service, MemorySegment deviceIn var device = new MacosUSBDevice(deviceIntf, entryID, vendorId, productId); - String manufacturer = IoKitHelper.getPropertyString(service, KEY_VENDOR, arena); - String product = IoKitHelper.getPropertyString(service, KEY_PRODUCT, arena); - String serial = IoKitHelper.getPropertyString(service, KEY_SERIAL_NUM, arena); + var manufacturer = IoKitHelper.getPropertyString(service, KEY_VENDOR, arena); + var product = IoKitHelper.getPropertyString(service, KEY_PRODUCT, arena); + var serial = IoKitHelper.getPropertyString(service, KEY_SERIAL_NUM, arena); device.setProductStrings(manufacturer, product, serial); - Integer classCode = IoKitHelper.getPropertyInt(service, KEY_DEVICE_CLASS, arena); - Integer subclassCode = IoKitHelper.getPropertyInt(service, KEY_DEVICE_SUBCLASS, arena); - Integer protocolCode = IoKitHelper.getPropertyInt(service, KEY_DEVICE_PROTOCOL, arena); + var classCode = IoKitHelper.getPropertyInt(service, KEY_DEVICE_CLASS, arena); + var subclassCode = IoKitHelper.getPropertyInt(service, KEY_DEVICE_SUBCLASS, arena); + var protocolCode = IoKitHelper.getPropertyInt(service, KEY_DEVICE_PROTOCOL, arena); device.setClassCodes(classCode != null ? classCode : 0, subclassCode != null ? subclassCode : 0, protocolCode != null ? protocolCode : 0); - Integer usbVersion = IoKitHelper.getPropertyInt(service, KEY_USB_BCD, arena); - Integer deviceVersion = IoKitHelper.getPropertyInt(service, KEY_DEVICE_BCD, arena); + var usbVersion = IoKitHelper.getPropertyInt(service, KEY_USB_BCD, arena); + var deviceVersion = IoKitHelper.getPropertyInt(service, KEY_DEVICE_BCD, arena); //noinspection DataFlowIssue device.setVersions(usbVersion, deviceVersion != null ? deviceVersion : 0); @@ -203,7 +211,7 @@ private USBDevice createDevice(Long entryID, int service, MemorySegment deviceIn private int setupNotification(Arena arena, MemorySegment notifyPort, MemorySegment notificationType, MethodHandle callback) { - // new matching dictionary for (dis)connected device notifications + // new matching dictionary for (dis)connected device notifications (NOSONAR) var matchingDict = IOKit.IOServiceMatching(IOKit.kIOUSBDeviceClassName()); // create callback stub @@ -213,7 +221,7 @@ private int setupNotification(Arena arena, MemorySegment notifyPort, MemorySegme // Set up a notification to be called when a device is first matched / terminated by I/O Kit. // This method consumes the matchingDict reference. var deviceIterHolder = arena.allocate(JAVA_INT); - int ret = IOKit.IOServiceAddMatchingNotification(notifyPort, notificationType, matchingDict, + var ret = IOKit.IOServiceAddMatchingNotification(notifyPort, notificationType, matchingDict, onDeviceCallbackStub, NULL, deviceIterHolder); if (ret != 0) throwException(ret, "IOServiceAddMatchingNotification failed"); @@ -230,6 +238,7 @@ private int setupNotification(Arena arena, MemorySegment notifyPort, MemorySegme * @param ignoredRefCon ignored parameter * @param iterator device iterator */ + @SuppressWarnings("java:S1172") private void onDevicesConnected(MemorySegment ignoredRefCon, int iterator) { // process device iterator for connected devices @@ -245,8 +254,8 @@ private void onDevicesConnected(MemorySegment ignoredRefCon, int iterator) { * @param ignoredRefCon ignored parameter * @param iterator device iterator */ - private void onDevicesDisconnected(@SuppressWarnings("SameParameterValue") MemorySegment ignoredRefCon, - int iterator) { + @SuppressWarnings({"SameParameterValue", "java:S1172", "java:S106"}) + private void onDevicesDisconnected(MemorySegment ignoredRefCon, int iterator) { // process device iterator for disconnected devices iterateDevices(iterator, (entryId, service, deviceIntf) -> { @@ -256,7 +265,7 @@ private void onDevicesDisconnected(@SuppressWarnings("SameParameterValue") Memor try { ((MacosUSBDevice) device).closeFully(); - } catch (Throwable e) { + } catch (Exception e) { System.err.println("Info: [JavaDoesUSB] failed to close USB device - ignoring exception"); e.printStackTrace(System.err); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java index 302da03d..d5b7ca82 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java @@ -17,7 +17,10 @@ /** * Memory layouts and helpers for CFUUID. */ -public class UUID { +class UUID { + + private UUID() { + } /** * Creates a CFUUID struct from a byte array. @@ -25,13 +28,13 @@ public class UUID { * @param bytes UUID as 16 bytes * @return the CFUUID */ - public static MemorySegment CreateCFUUID(byte[] bytes) { + static MemorySegment createCFUUID(byte[] bytes) { try (var arena = Arena.ofConfined()) { var uuidBytes = arena.allocate(16); uuidBytes.copyFrom(MemorySegment.ofArray(bytes)); return CoreFoundation.CFUUIDCreateFromUUIDBytes(NULL, uuidBytes); - } catch (Throwable t) { - throw new RuntimeException(t); + } catch (Exception e) { + throw new AssertionError("internal error (createCFUUID)", e); } } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java index fbfdc3d0..611e76f0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java @@ -19,6 +19,7 @@ /** * USB configuration descriptor */ +@SuppressWarnings("java:S125") public class ConfigurationDescriptor { private final MemorySegment descriptor; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/Constants.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/Constants.java index 7189af42..8868ea18 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/Constants.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/Constants.java @@ -12,6 +12,9 @@ */ public class Constants { + private Constants() { + } + public static final byte DEVICE_DESCRIPTOR_TYPE = 0x01; public static final byte CONFIGURATION_DESCRIPTOR_TYPE = 0x02; public static final byte STRING_DESCRIPTOR_TYPE = 0x03; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java index 708cc3a1..686e2a14 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java @@ -19,6 +19,7 @@ /** * USB device descriptor */ +@SuppressWarnings("java:S125") public class DeviceDescriptor { private final MemorySegment descriptor; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java index 059a9335..a6d5516c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java @@ -19,6 +19,7 @@ /** * USB endpoint descriptor */ +@SuppressWarnings("java:S125") public class EndpointDescriptor { private final MemorySegment descriptor; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java index d5fc5b73..e5f343f8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java @@ -18,6 +18,7 @@ /** * USB interface association descriptor (IAD) */ +@SuppressWarnings("java:S125") public class InterfaceAssociationDescriptor { private final MemorySegment descriptor; @@ -54,7 +55,6 @@ public int function() { return 0xff & (byte) iFunction$VH.get(descriptor); } - // struct USBInterfaceAssociationDescriptor { // uint8_t bLength, // uint8_t bDescriptorType, diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java index 04668e37..faf0032b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java @@ -18,6 +18,7 @@ /** * USB interface descriptor */ +@SuppressWarnings("java:S125") public class InterfaceDescriptor { private final MemorySegment descriptor; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java index b1109a3e..c934631b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java @@ -13,6 +13,7 @@ /** * USB setup packet. */ +@SuppressWarnings("java:S125") public class SetupPacket { private final MemorySegment descriptor; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java index b696c54c..d98b9cfb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java @@ -18,6 +18,7 @@ /** * USB string descriptor */ +@SuppressWarnings("java:S125") public class StringDescriptor { private final MemorySegment descriptor; @@ -31,7 +32,7 @@ public int length() { } public String string() { - var chars = descriptor.asSlice(string$offset, length() - 2).toArray(JAVA_CHAR); + var chars = descriptor.asSlice(string$offset, length() - 2L).toArray(JAVA_CHAR); return new String(chars); } From 398c1e2b274a640a48a6ae44f05cb67fb93b2abc Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 29 Jul 2023 09:59:13 +0200 Subject: [PATCH 250/433] Code style alignment --- .../usb/common/ConfigurationParser.java | 8 +- .../usb/common/EndpointInputStream.java | 30 +++--- .../usb/common/EndpointOutputStream.java | 40 ++++---- .../codecrete/usb/common/ScopeCleanup.java | 2 +- .../net/codecrete/usb/common/Transfer.java | 98 +++++++++++++++++-- .../codecrete/usb/common/USBDeviceImpl.java | 16 +-- .../usb/common/USBDeviceRegistry.java | 2 +- .../codecrete/usb/linux/LinuxAsyncTask.java | 50 +++++----- .../codecrete/usb/linux/LinuxUSBDevice.java | 32 +++--- .../codecrete/usb/macos/MacosAsyncTask.java | 40 ++++---- .../codecrete/usb/macos/MacosTransfer.java | 12 ++- .../codecrete/usb/macos/MacosUSBDevice.java | 42 ++++---- .../usb/macos/MacosUSBDeviceRegistry.java | 4 +- .../usb/windows/WindowsAsyncTask.java | 14 +-- .../usb/windows/WindowsTransfer.java | 12 ++- .../usb/windows/WindowsUSBDevice.java | 38 +++---- 16 files changed, 268 insertions(+), 172 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java index 58ec7e68..dc9d7dc7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java @@ -54,12 +54,12 @@ public Configuration parse() { parseHeader(); USBAlternateInterfaceImpl lastAlternate = null; - int offset = peekDescLength(0); + var offset = peekDescLength(0); while (offset < descriptor.byteSize()) { - int descLength = peekDescLength(offset); - int descType = peekDescType(offset); + var descLength = peekDescLength(offset); + var descType = peekDescType(offset); if (descType == INTERFACE_DESCRIPTOR_TYPE) { var intf = parseInterface(offset); @@ -99,7 +99,7 @@ private void parseHeader() { if (CONFIGURATION_DESCRIPTOR_TYPE != desc.descriptorType()) throw new USBException("Invalid USB configuration descriptor"); - int totalLength = desc.totalLength(); + var totalLength = desc.totalLength(); if (descriptor.byteSize() != totalLength) throw new USBException("Invalid USB configuration descriptor length"); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index d1959a7e..85125170 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -63,15 +63,15 @@ protected EndpointInputStream(USBDeviceImpl device, int endpointNumber, int buff this.endpointNumber = endpointNumber; arena = Arena.ofShared(); - int packetSize = device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); + var packetSize = device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); // use between 4 and 32 packets per transfer (256B to 2KB for FS, 2KB to 16KB for HS) - int numPacketsPerTransfer = (int) Math.round(Math.sqrt((double) bufferSize / packetSize)); + var numPacketsPerTransfer = (int) Math.round(Math.sqrt((double) bufferSize / packetSize)); numPacketsPerTransfer = Math.min(Math.max(numPacketsPerTransfer, 4), 32); transferSize = numPacketsPerTransfer * packetSize; // use at least 2 outstanding transfers (3 in total) - int maxOutstandingTransfers = Math.max((bufferSize + transferSize / 2) / transferSize, 3); + var maxOutstandingTransfers = Math.max((bufferSize + transferSize / 2) / transferSize, 3); configureEndpoint(); @@ -79,11 +79,11 @@ protected EndpointInputStream(USBDeviceImpl device, int endpointNumber, int buff // create all transfers, and submit them except one try { - for (int i = 0; i < maxOutstandingTransfers; i++) { + for (var i = 0; i < maxOutstandingTransfers; i++) { final var transfer = device.createTransfer(); - transfer.data = arena.allocate(transferSize, 8); - transfer.dataSize = transferSize; - transfer.completion = this::onCompletion; + transfer.setData(arena.allocate(transferSize, 8)); + transfer.setDataSize(transferSize); + transfer.setCompletion(this::onCompletion); if (i == 0) { currentTransfer = transfer; @@ -129,7 +129,7 @@ public int read() throws IOException { if (available() == 0) receiveMoreData(); - int b = currentTransfer.data.get(JAVA_BYTE, readOffset) & 0xff; + var b = currentTransfer.data().get(JAVA_BYTE, readOffset) & 0xff; readOffset += 1; return b; } @@ -143,8 +143,8 @@ public int read(byte[] b, int off, int len) throws IOException { receiveMoreData(); // copy data to receiving buffer - int n = Math.min(len, currentTransfer.resultSize - readOffset); - MemorySegment.copy(currentTransfer.data, readOffset, MemorySegment.ofArray(b), off, n); + var n = Math.min(len, currentTransfer.resultSize() - readOffset); + MemorySegment.copy(currentTransfer.data(), readOffset, MemorySegment.ofArray(b), off, n); readOffset += n; // TODO: poll for further completed transfers if 'n' is less than 'len' @@ -155,7 +155,7 @@ public int read(byte[] b, int off, int len) throws IOException { @SuppressWarnings("RedundantThrows") @Override public int available() throws IOException { - return currentTransfer.resultSize - readOffset; + return currentTransfer.resultSize() - readOffset; } private void receiveMoreData() throws IOException { @@ -170,11 +170,11 @@ private void receiveMoreData() throws IOException { readOffset = 0; // check for error - if (currentTransfer.resultCode != 0) - device.throwOSException(currentTransfer.resultCode, "error reading from endpoint %d", + if (currentTransfer.resultCode() != 0) + device.throwOSException(currentTransfer.resultCode(), "error reading from endpoint %d", endpointNumber); - } while (currentTransfer.resultSize <= 0); + } while (currentTransfer.resultSize() <= 0); } catch (Exception t) { close(); @@ -185,7 +185,7 @@ private void receiveMoreData() throws IOException { private Transfer waitForCompletedTransfer() { while (true) { try { - Transfer transfer = completedTransferQueue.take(); + var transfer = completedTransferQueue.take(); numOutstandingTransfers -= 1; return transfer; } catch (InterruptedException e) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java index 92fded78..e95578bc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -68,22 +68,22 @@ protected EndpointOutputStream(USBDeviceImpl device, int endpointNumber, int buf packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize(); // use between 4 and 32 packets per transfer (256B to 2KB for FS, 2KB to 16KB for HS) - int numPacketsPerTransfer = (int) Math.round(Math.sqrt((double) bufferSize / packetSize)); + var numPacketsPerTransfer = (int) Math.round(Math.sqrt((double) bufferSize / packetSize)); numPacketsPerTransfer = Math.min(Math.max(numPacketsPerTransfer, 4), 32); transferSize = numPacketsPerTransfer * packetSize; // use at least 2 outstanding transfers (3 in total) - int maxOutstandingTransfers = Math.max((bufferSize + transferSize / 2) / transferSize, 3); + var maxOutstandingTransfers = Math.max((bufferSize + transferSize / 2) / transferSize, 3); configureEndpoint(); availableTransferQueue = new ArrayBlockingQueue<>(maxOutstandingTransfers); // prefill transfer queue - for (int i = 0; i < maxOutstandingTransfers; i++) { + for (var i = 0; i < maxOutstandingTransfers; i++) { final var transfer = device.createTransfer(); - transfer.data = arena.allocate(transferSize, 8); - transfer.completion = this::onCompletion; + transfer.setData(arena.allocate(transferSize, 8)); + transfer.setCompletion(this::onCompletion); if (i == 0) { currentTransfer = transfer; @@ -115,10 +115,9 @@ public void close() throws IOException { @Override public void write(int b) throws IOException { - if (isClosed()) - throw new IOException("Bulk endpoint output stream has been closed"); + checkIsOpen(); - currentTransfer.data.set(JAVA_BYTE, writeOffset, (byte) b); + currentTransfer.data().set(JAVA_BYTE, writeOffset, (byte) b); writeOffset += 1; if (writeOffset == transferSize) submitTransfer(writeOffset); @@ -126,12 +125,11 @@ public void write(int b) throws IOException { @Override public void write(byte[] b, int off, int len) throws IOException { - if (isClosed()) - throw new IOException("Bulk endpoint output stream has been closed"); + checkIsOpen(); while (len > 0) { - int chunkSize = Math.min(len, transferSize - writeOffset); - MemorySegment.copy(b, off, currentTransfer.data, JAVA_BYTE, writeOffset, chunkSize); + var chunkSize = Math.min(len, transferSize - writeOffset); + MemorySegment.copy(b, off, currentTransfer.data(), JAVA_BYTE, writeOffset, chunkSize); writeOffset += chunkSize; off += chunkSize; len -= chunkSize; @@ -143,8 +141,7 @@ public void write(byte[] b, int off, int len) throws IOException { @Override public void flush() throws IOException { - if (isClosed()) - throw new IOException("Bulk endpoint output stream has been closed"); + checkIsOpen(); if (writeOffset > 0) submitTransfer(writeOffset); @@ -167,7 +164,7 @@ public void flush() throws IOException { */ private void submitTransfer(int size) throws IOException { try { - currentTransfer.dataSize = size; + currentTransfer.setDataSize(size); submitTransferOut(currentTransfer); synchronized (this) { @@ -205,7 +202,7 @@ private void waitForOutstandingTransfers() { return; var transfers = new Transfer[numTransfers]; - for (int i = 0; i < numTransfers; i++) + for (var i = 0; i < numTransfers; i++) transfers[i] = waitForAvailableTransfer(); // reinsert the transfer instances @@ -225,12 +222,12 @@ private void waitForOutstandingTransfers() { private Transfer waitForAvailableTransfer() { while (true) { try { - Transfer transfer = availableTransferQueue.take(); + var transfer = availableTransferQueue.take(); // check for error - int result = transfer.resultCode; + var result = transfer.resultCode(); if (result != 0 && !hasError) { - transfer.resultCode = 0; + transfer.setResultCode(0); device.throwOSException(result, "error writing to endpoint %d", endpointNumber); } @@ -256,4 +253,9 @@ private synchronized void onCompletion(Transfer transfer) { protected void configureEndpoint() { } + + private void checkIsOpen() throws IOException { + if (isClosed()) + throw new IOException("Bulk endpoint output stream has been closed"); + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java index d9b3045b..4624a2d2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java @@ -45,7 +45,7 @@ public void add(Runnable cleanupAction) { @Override public void close() { var size = cleanupActions.size(); - for (int i = size - 1; i >= 0; i--) + for (var i = size - 1; i >= 0; i--) cleanupActions.get(i).run(); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/Transfer.java b/java-does-usb/src/main/java/net/codecrete/usb/common/Transfer.java index efc294f3..0be15f99 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/Transfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/Transfer.java @@ -13,27 +13,105 @@ * Asynchronous USB endpoint transfer. */ public class Transfer { + private MemorySegment data; + private int dataSize; + private int resultCode; + private int resultSize; + private TransferCompletion completion; + + /** + * Gets the with data to transfer (in or out). + * + * @return buffer + */ + public MemorySegment data() { + return data; + } + + /** + * Sets buffer with data to transfer (in or out) + * + * @param data buffer + */ + public void setData(MemorySegment data) { + this.data = data; + } + /** - * Buffer with data to transfer (in or out) + * Gets length of data to transfer. + * + * @return length (in bytes) */ - public MemorySegment data; + public int dataSize() { + return dataSize; + } + /** - * Length of data to transfer (in bytes) + * Sets length of data to transfer. + * + * @param dataSize length (in bytes) */ - public int dataSize; + public void setDataSize(int dataSize) { + this.dataSize = dataSize; + } + /** - * Result code (operating system specific). + * Gets result code (operating system specific). *

* 0 represents success, all other values represent an error. *

+ * + * @return result code */ - public int resultCode; + public int resultCode() { + return resultCode; + } + /** - * Length of transferred data (in bytes) + * Sets result code (operating system specific). + *

+ * 0 represents success, all other values represent an error. + *

+ * + * @param resultCode result code + */ + public void setResultCode(int resultCode) { + this.resultCode = resultCode; + } + + /** + * Gets length of transferred data. + * + * @return length (in bytes) */ - public int resultSize; + public int resultSize() { + return resultSize; + } + + /** + * Sets length of transferred data. + * + * @param resultSize length (in bytes) + */ + public void setResultSize(int resultSize) { + this.resultSize = resultSize; + } + + /** + * Gets completion handler to call when the transfer is complete. + * + * @return completion handler + */ + public TransferCompletion completion() { + return completion; + } + /** - * Completion handler to call when the transfer is complete. + * Sets completion handler to call when the transfer is complete. + * + * @param completion completion handler */ - public TransferCompletion completion; + public void setCompletion(TransferCompletion completion) { + this.completion = completion; + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index c19c4659..371b0330 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -331,10 +331,10 @@ protected void waitForTransfer(Transfer transfer, int timeout, USBDirection dire waitNoTimeout(transfer); } else { - boolean hasTimedOut = waitWithTimeout(transfer, timeout); + var hasTimedOut = waitWithTimeout(transfer, timeout); // test for timeout - if (hasTimedOut && transfer.resultCode == 0) { + if (hasTimedOut && transfer.resultCode() == 0) { abortTransfers(direction, endpointNumber); waitNoTimeout(transfer); throw new USBTimeoutException(getOperationDescription(direction, endpointNumber) + "aborted due to " + @@ -343,16 +343,16 @@ protected void waitForTransfer(Transfer transfer, int timeout, USBDirection dire } // test for error - if (transfer.resultCode != 0) { + if (transfer.resultCode() != 0) { var operation = getOperationDescription(direction, endpointNumber); - throwOSException(transfer.resultCode, operation + " failed"); + throwOSException(transfer.resultCode(), operation + " failed"); } } @SuppressWarnings("java:S2273") private static void waitNoTimeout(Transfer transfer) { // wait for transfer - while (transfer.resultSize == -1) { + while (transfer.resultSize() == -1) { try { transfer.wait(); } catch (InterruptedException e) { @@ -364,9 +364,9 @@ private static void waitNoTimeout(Transfer transfer) { @SuppressWarnings("java:S2273") private static boolean waitWithTimeout(Transfer transfer, int timeout) { // wait for transfer to complete, or abort when timeout occurs - long expiration = System.currentTimeMillis() + timeout; + var expiration = System.currentTimeMillis() + timeout; long remainingTimeout = timeout; - while (remainingTimeout > 0 && transfer.resultSize == -1) { + while (remainingTimeout > 0 && transfer.resultSize() == -1) { try { transfer.wait(remainingTimeout); remainingTimeout = expiration - System.currentTimeMillis(); @@ -426,7 +426,7 @@ public boolean equals(Object o) { return true; if (o == null || getClass() != o.getClass()) return false; - USBDeviceImpl that = (USBDeviceImpl) o; + var that = (USBDeviceImpl) o; return uniqueDeviceId.equals(that.uniqueDeviceId); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index 671781d2..ded911f2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -121,7 +121,7 @@ protected void emitOnDeviceDisconnected(USBDevice device) { */ protected void startDeviceMonitor(Runnable monitorTask) { // start new thread - Thread t = new Thread(monitorTask, "USB device monitor"); + var t = new Thread(monitorTask, "USB device monitor"); t.setDaemon(true); t.start(); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index e5fe0787..a933fa63 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -90,8 +90,8 @@ private void asyncCompletionTask() { // poll for event fillPollfdArray(pollfdArray, fds); - int n = fds.length; - int res = poll.poll(pollfdArray, n + 1L, -1); + var n = fds.length; + var res = poll.poll(pollfdArray, n + 1L, -1); if (res < 0) throwException("internal error (poll)"); @@ -108,7 +108,7 @@ private void asyncCompletionTask() { } // check for USB device events - for (int i = 0; i < n + 1; i++) { + for (var i = 0; i < n + 1; i++) { var revent = pollfd.revents$get(pollfdArray, i); if (revent == 0) continue; @@ -116,13 +116,13 @@ private void asyncCompletionTask() { if ((revent & poll.POLLERR()) != 0) { // most likely the device has been disconnected, // remove from polled FD list to prevent further problems - int fd = pollfd.fd$get(pollfdArray, i); + var fd = pollfd.fd$get(pollfdArray, i); removeFdFromAsyncIOCompletion(fd); continue; } // reap URB - int fd = pollfd.fd$get(pollfdArray, i); + var fd = pollfd.fd$get(pollfdArray, i); reapURBs(fd, urbPointerHolder, errnoState); } } @@ -133,7 +133,7 @@ private void asyncCompletionTask() { void fillPollfdArray(MemorySegment asyncPolls, int[] fds) { // device file descriptors var n = fds.length; - for (int i = 0; i < n; i++) { + for (var i = 0; i < n; i++) { pollfd.fd$set(asyncPolls, i, fds[i]); pollfd.events$set(asyncPolls, i, (short) poll.POLLOUT()); pollfd.revents$set(asyncPolls, i, (short) 0); @@ -154,7 +154,7 @@ void fillPollfdArray(MemorySegment asyncPolls, int[] fds) { */ private void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment errnoState) { while (true) { - int res = IO.ioctl(fd, REAPURBNDELAY, urbPointerHolder, errnoState); + var res = IO.ioctl(fd, REAPURBNDELAY, urbPointerHolder, errnoState); if (res < 0) { var err = Linux.getErrno(errnoState); if (err == errno.EAGAIN()) @@ -167,7 +167,7 @@ private void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment errn // call completion handler var urb = dereference(urbPointerHolder); var transfer = getTransferResult(urb); - transfer.completion.completed(transfer); + transfer.completion().completed(transfer); } } @@ -194,8 +194,8 @@ private void notifyAsyncIOTask() { * @param device USB device */ synchronized void addForAsyncIOCompletion(LinuxUSBDevice device) { - int n = asyncFds != null ? asyncFds.length : 0; - int[] fds = new int[n + 1]; + var n = asyncFds != null ? asyncFds.length : 0; + var fds = new int[n + 1]; if (n > 0) System.arraycopy(asyncFds, 0, fds, 0, n); fds[n] = device.fileDescriptor(); @@ -217,13 +217,13 @@ synchronized void removeFromAsyncIOCompletion(LinuxUSBDevice device) { private synchronized void removeFdFromAsyncIOCompletion(int fd) { // copy file descriptor (except the device's) into new array - int n = asyncFds.length; + var n = asyncFds.length; if (n == 0) return; - int[] fds = new int[n - 1]; - int tgt = 0; - for (int asyncFd : asyncFds) { + var fds = new int[n - 1]; + var tgt = 0; + for (var asyncFd : asyncFds) { if (asyncFd != fd) { if (tgt == n) return; @@ -243,15 +243,15 @@ synchronized void submitTransfer(LinuxUSBDevice device, int endpointAddress, USB usbdevfs_urb.type$set(urb, (byte) urbTransferType(transferType)); usbdevfs_urb.endpoint$set(urb, (byte) endpointAddress); - usbdevfs_urb.buffer$set(urb, transfer.data); - usbdevfs_urb.buffer_length$set(urb, transfer.dataSize); + usbdevfs_urb.buffer$set(urb, transfer.data()); + usbdevfs_urb.buffer_length$set(urb, transfer.dataSize()); usbdevfs_urb.usercontext$set(urb, MemorySegment.ofAddress(device.fileDescriptor())); try (var arena = Arena.ofConfined()) { var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); if (IO.ioctl(device.fileDescriptor(), SUBMITURB, urb, errnoState) < 0) { - String action = endpointAddress >= 128 ? "reading from" : "writing to"; - String endpoint = endpointAddress == 0 ? "control endpoint" : String.format("endpoint %d", endpointAddress); + var action = endpointAddress >= 128 ? "reading from" : "writing to"; + var endpoint = endpointAddress == 0 ? "control endpoint" : String.format("endpoint %d", endpointAddress); throwLastError(errnoState, "failed %s %s", action, endpoint); } } @@ -268,7 +268,7 @@ private static int urbTransferType(USBTransferType transferType) { private void addURB(LinuxTransfer transfer) { MemorySegment urb; - int size = availableURBs.size(); + var size = availableURBs.size(); if (size > 0) { urb = availableURBs.remove(size - 1); } else { @@ -285,8 +285,8 @@ private synchronized LinuxTransfer getTransferResult(MemorySegment urb) { if (transfer == null) throwException("internal error (unknown URB)"); - transfer.resultCode = -usbdevfs_urb.status$get(transfer.urb); - transfer.resultSize = usbdevfs_urb.actual_length$get(transfer.urb); + transfer.setResultCode(-usbdevfs_urb.status$get(transfer.urb)); + transfer.setResultSize(usbdevfs_urb.actual_length$get(transfer.urb)); availableURBs.add(transfer.urb); transfer.urb = null; @@ -295,7 +295,7 @@ private synchronized LinuxTransfer getTransferResult(MemorySegment urb) { @SuppressWarnings("java:S1066") synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { - int fd = device.fileDescriptor(); + var fd = device.fileDescriptor(); try (var arena = Arena.ofConfined()) { var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); @@ -326,8 +326,8 @@ private void startAsyncIOTask() { } // start background thread for handling IO completion - Thread t = new Thread(this::asyncCompletionTask, "USB async IO"); - t.setDaemon(true); - t.start(); + var thread = new Thread(this::asyncCompletionTask, "USB async IO"); + thread.setDaemon(true); + thread.start(); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 181c6b50..51e41303 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -124,7 +124,7 @@ int fileDescriptor() { public synchronized void claimInterface(int interfaceNumber) { checkIsOpen(); - var intf = getInterfaceWithCheck(interfaceNumber, false); + getInterfaceWithCheck(interfaceNumber, false); try (var arena = Arena.ofConfined()) { var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); @@ -168,7 +168,7 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna usbdevfs_setinterface.interface_$set(setIntfSegment, interfaceNumber); usbdevfs_setinterface.altsetting$set(setIntfSegment, alternateNumber); var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); - int ret = IO.ioctl(fd, USBDevFS.SETINTERFACE, setIntfSegment, errnoState); + var ret = IO.ioctl(fd, USBDevFS.SETINTERFACE, setIntfSegment, errnoState); if (ret != 0) throwLastError(errnoState, "Failed to set alternate interface"); } @@ -184,7 +184,7 @@ public synchronized void releaseInterface(int interfaceNumber) { try (var arena = Arena.ofConfined()) { var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); - int ret = IO.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment, errnoState); + var ret = IO.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment, errnoState); if (ret != 0) throwLastError(errnoState, "Cannot release USB interface"); @@ -204,10 +204,10 @@ public synchronized void releaseInterface(int interfaceNumber) { @Override public void controlTransferOut(USBControlTransfer setup, byte[] data) { try (var arena = Arena.ofConfined()) { - int dataLength = data != null ? data.length : 0; + var dataLength = data != null ? data.length : 0; var transfer = createSyncCtrlTransfer(arena, USBDirection.OUT, setup, dataLength); if (dataLength != 0) - transfer.data.asSlice(8).copyFrom(MemorySegment.ofArray(data)); + transfer.data().asSlice(8).copyFrom(MemorySegment.ofArray(data)); synchronized (transfer) { submitTransfer(USBDirection.OUT, 0, transfer); @@ -226,7 +226,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { waitForTransfer(transfer, 0, USBDirection.IN, 0); } - return transfer.data.asSlice(8, transfer.resultSize).toArray(JAVA_BYTE); + return transfer.data().asSlice(8, transfer.resultSize()).toArray(JAVA_BYTE); } } @@ -252,10 +252,10 @@ private LinuxTransfer createSyncCtrlTransfer(Arena arena, USBDirection direction setupPacket.setLength(dataLength); var transfer = new LinuxTransfer(); - transfer.data = buffer; - transfer.dataSize = (int) buffer.byteSize(); - transfer.resultSize = -1; - transfer.completion = USBDeviceImpl::onSyncTransferCompleted; + transfer.setData(buffer); + transfer.setDataSize((int) buffer.byteSize()); + transfer.setResultSize(-1); + transfer.setCompletion(USBDeviceImpl::onSyncTransferCompleted); return transfer; } @@ -287,16 +287,16 @@ public byte[] transferIn(int endpointNumber, int timeout) { waitForTransfer(transfer, timeout, USBDirection.IN, endpointNumber); } - return buffer.asSlice(0, transfer.resultSize).toArray(JAVA_BYTE); + return buffer.asSlice(0, transfer.resultSize()).toArray(JAVA_BYTE); } } private LinuxTransfer createSyncTransfer(MemorySegment data) { var transfer = new LinuxTransfer(); - transfer.data = data; - transfer.dataSize = (int) data.byteSize(); - transfer.resultSize = -1; - transfer.completion = USBDeviceImpl::onSyncTransferCompleted; + transfer.setData(data); + transfer.setDataSize((int) data.byteSize()); + transfer.setResultSize(-1); + transfer.setCompletion(USBDeviceImpl::onSyncTransferCompleted); return transfer; } @@ -326,7 +326,7 @@ public void clearHalt(USBDirection direction, int endpointNumber) { try (var arena = Arena.ofConfined()) { var endpointAddrSegment = arena.allocate(JAVA_INT, endpoint.endpointAddress() & 0xff); var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); - int res = IO.ioctl(fd, USBDevFS.CLEAR_HALT, endpointAddrSegment, errnoState); + var res = IO.ioctl(fd, USBDevFS.CLEAR_HALT, endpointAddrSegment, errnoState); if (res < 0) throwLastError(errnoState, "Clearing halt failed"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java index a2200051..a99dc33e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java @@ -38,13 +38,20 @@ @SuppressWarnings("java:S6548") class MacosAsyncTask { + enum TaskState { + NOT_STARTED, + STARTING, + RUNNING + } + /** * Singleton instance of background task. */ static final MacosAsyncTask INSTANCE = new MacosAsyncTask(); private final ReentrantLock asyncIoLock = new ReentrantLock(); - private Condition asyncIoReady; + private final Condition asyncIoReady = asyncIoLock.newCondition(); + private TaskState state = TaskState.NOT_STARTED; private MemorySegment asyncIoRunLoop; private MemorySegment completionUpcallStub; private long lastTransferId; @@ -59,13 +66,9 @@ void addEventSource(MemorySegment source) { try { asyncIoLock.lock(); - if (asyncIoRunLoop == null) { - - if (asyncIoReady == null) { - // start background thread - asyncIoReady = asyncIoLock.newCondition(); + if (state != TaskState.RUNNING) { + if (state == TaskState.NOT_STARTED) { startAsyncIOThread(source); - waitForRunLoopReady(); return; @@ -83,13 +86,8 @@ void addEventSource(MemorySegment source) { } private void waitForRunLoopReady() { - while (true) { - synchronized (this) { - if (asyncIoRunLoop != null) - return; - } + while (state != TaskState.RUNNING) asyncIoReady.awaitUninterruptibly(); - } } /** @@ -108,6 +106,7 @@ void removeEventSource(MemorySegment source) { */ private void startAsyncIOThread(MemorySegment firstSource) { try { + state = TaskState.STARTING; var completionHandlerFuncDesc = FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT, ADDRESS); var asyncIOCompletedMH = MethodHandles.lookup().findVirtual(MacosAsyncTask.class, "asyncIOCompleted", MethodType.methodType(void.class, MemorySegment.class, int.class, MemorySegment.class)); @@ -137,10 +136,9 @@ private void startAsyncIOThread(MemorySegment firstSource) { private void asyncIOCompletionTask(MemorySegment firstSource) { try { asyncIoLock.lock(); - synchronized (this) { - asyncIoRunLoop = CoreFoundation.CFRunLoopGetCurrent(); - } + asyncIoRunLoop = CoreFoundation.CFRunLoopGetCurrent(); CoreFoundation.CFRunLoopAddSource(asyncIoRunLoop, firstSource, IOKit.kCFRunLoopDefaultMode$get()); + state = TaskState.RUNNING; asyncIoReady.signalAll(); } finally { asyncIoLock.unlock(); @@ -161,8 +159,8 @@ private void asyncIOCompletionTask(MemorySegment firstSource) { */ synchronized void prepareForSubmission(MacosTransfer transfer) { lastTransferId += 1; - transfer.id = lastTransferId; - transfer.resultSize = -1; + transfer.setId(lastTransferId); + transfer.setResultSize(-1); transfersById.put(lastTransferId, transfer); } @@ -181,9 +179,9 @@ private void asyncIOCompleted(MemorySegment refcon, int result, MemorySegment ar transfer = transfersById.remove(refcon.address()); } - transfer.resultCode = result; - transfer.resultSize = (int) arg0.address(); - transfer.completion.completed(transfer); + transfer.setResultCode(result); + transfer.setResultSize((int) arg0.address()); + transfer.completion().completed(transfer); } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosTransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosTransfer.java index 55dee2d5..6610234d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosTransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosTransfer.java @@ -9,6 +9,14 @@ import net.codecrete.usb.common.Transfer; -public class MacosTransfer extends Transfer { - long id; +class MacosTransfer extends Transfer { + private long id; + + public long id() { + return id; + } + + public void setId(long id) { + this.id = id; + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 3f2d2134..44b44bfa 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -381,14 +381,14 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { var deviceRequest = createDeviceRequest(arena, USBDirection.IN, setup, data); var transfer = new MacosTransfer(); - transfer.completion = USBDeviceImpl::onSyncTransferCompleted; + transfer.setCompletion(USBDeviceImpl::onSyncTransferCompleted); synchronized (transfer) { submitControlTransfer(deviceRequest, transfer); waitForTransfer(transfer, 0, USBDirection.IN, 0); } - return data.asSlice(0, transfer.resultSize).toArray(JAVA_BYTE); + return data.asSlice(0, transfer.resultSize()).toArray(JAVA_BYTE); } } @@ -402,7 +402,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { var deviceRequest = createDeviceRequest(arena, USBDirection.OUT, setup, dataSegment); var transfer = new MacosTransfer(); - transfer.completion = USBDeviceImpl::onSyncTransferCompleted; + transfer.setCompletion(USBDeviceImpl::onSyncTransferCompleted); synchronized (transfer) { submitControlTransfer(deviceRequest, transfer); @@ -422,9 +422,9 @@ public void transferOut(int endpointNumber, byte[] data, int offset, int length, nativeData.copyFrom(MemorySegment.ofArray(data).asSlice(offset, length)); var transfer = new MacosTransfer(); - transfer.data = nativeData; - transfer.dataSize = length; - transfer.completion = USBDeviceImpl::onSyncTransferCompleted; + transfer.setData(nativeData); + transfer.setDataSize(length); + transfer.setCompletion(USBDeviceImpl::onSyncTransferCompleted); synchronized (transfer) { if (timeout <= 0 || epInfo.transferType() == USBTransferType.BULK) { @@ -451,9 +451,9 @@ public byte[] transferIn(int endpointNumber, int timeout) { var nativeData = arena.allocateArray(JAVA_BYTE, epInfo.packetSize()); var transfer = new MacosTransfer(); - transfer.data = nativeData; - transfer.dataSize = epInfo.packetSize(); - transfer.completion = USBDeviceImpl::onSyncTransferCompleted; + transfer.setData(nativeData); + transfer.setDataSize(epInfo.packetSize()); + transfer.setCompletion(USBDeviceImpl::onSyncTransferCompleted); synchronized (transfer) { if (timeout <= 0 || epInfo.transferType() == USBTransferType.BULK) { @@ -468,7 +468,7 @@ public byte[] transferIn(int endpointNumber, int timeout) { } } - return nativeData.asSlice(0, transfer.resultSize).toArray(JAVA_BYTE); + return nativeData.asSlice(0, transfer.resultSize()).toArray(JAVA_BYTE); } } @@ -491,12 +491,12 @@ synchronized void submitTransferIn(int endpointNumber, MacosTransfer transfer, i // submit transfer int ret; if (timeout <= 0) - ret = IoKitUSB.ReadPipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data, - transfer.dataSize, asyncTask.nativeCompletionCallback(), MemorySegment.ofAddress(transfer.id)); + ret = IoKitUSB.ReadPipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data(), + transfer.dataSize(), asyncTask.nativeCompletionCallback(), MemorySegment.ofAddress(transfer.id())); else - ret = IoKitUSB.ReadPipeAsyncTO(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data, - transfer.dataSize, timeout, timeout, asyncTask.nativeCompletionCallback(), - MemorySegment.ofAddress(transfer.id)); + ret = IoKitUSB.ReadPipeAsyncTO(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data(), + transfer.dataSize(), timeout, timeout, asyncTask.nativeCompletionCallback(), + MemorySegment.ofAddress(transfer.id())); if (ret != 0) throwException(ret, "failed to read from endpoint %d", endpointNumber); @@ -521,12 +521,12 @@ synchronized void submitTransferOut(int endpointNumber, MacosTransfer transfer, // submit transfer int ret; if (timeout <= 0) - ret = IoKitUSB.WritePipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data, - transfer.dataSize, asyncTask.nativeCompletionCallback(), MemorySegment.ofAddress(transfer.id)); + ret = IoKitUSB.WritePipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data(), + transfer.dataSize(), asyncTask.nativeCompletionCallback(), MemorySegment.ofAddress(transfer.id())); else - ret = IoKitUSB.WritePipeAsyncTO(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data, - transfer.dataSize, timeout, timeout, asyncTask.nativeCompletionCallback(), - MemorySegment.ofAddress(transfer.id)); + ret = IoKitUSB.WritePipeAsyncTO(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data(), + transfer.dataSize(), timeout, timeout, asyncTask.nativeCompletionCallback(), + MemorySegment.ofAddress(transfer.id())); if (ret != 0) throwException(ret, "failed to write to endpoint %d", endpointNumber); @@ -545,7 +545,7 @@ synchronized void submitControlTransfer(MemorySegment deviceRequest, MacosTransf // submit transfer var ret = IoKitUSB.DeviceRequestAsync(device, deviceRequest, asyncTask.nativeCompletionCallback(), - MemorySegment.ofAddress(transfer.id)); + MemorySegment.ofAddress(transfer.id())); if (ret != 0) throwException(ret, "failed to execute control transfer"); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 79d80dad..62577d7e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -163,7 +163,9 @@ private void iterateDevices(int iterator, Consumer consumer) { consumer.accept(device); } catch (Exception e) { - System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device 0x%04x/0x%04x - " + "ignoring device%n", deviceInfo.vid, deviceInfo.pid); + System.err.printf( + "Info: [JavaDoesUSB] failed to retrieve information about device 0x%04x/0x%04x - ignoring device%n", + deviceInfo.vid, deviceInfo.pid); e.printStackTrace(System.err); } }); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java index 8d2d6d30..b21d39d2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java @@ -147,8 +147,8 @@ synchronized void prepareForSubmission(WindowsTransfer transfer) { overlapped = availableOverlappedStructs.remove(size - 1); } - transfer.overlapped = overlapped; - transfer.resultSize = -1; + transfer.setOverlapped(overlapped); + transfer.setResultSize(-1); requestsByOverlapped.put(overlapped.address(), transfer); } @@ -162,11 +162,11 @@ private synchronized void completeTransfer(long overlappedAddr) { if (transfer == null) return; - transfer.resultCode = (int) OVERLAPPED.Internal$get(transfer.overlapped); - transfer.resultSize = (int) OVERLAPPED.InternalHigh$get(transfer.overlapped); + transfer.setResultCode((int) OVERLAPPED.Internal$get(transfer.overlapped())); + transfer.setResultSize((int) OVERLAPPED.InternalHigh$get(transfer.overlapped())); - availableOverlappedStructs.add(transfer.overlapped); - transfer.overlapped = null; - transfer.completion.completed(transfer); + availableOverlappedStructs.add(transfer.overlapped()); + transfer.setOverlapped(null); + transfer.completion().completed(transfer); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsTransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsTransfer.java index 5989f040..9b45f4bb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsTransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsTransfer.java @@ -11,6 +11,14 @@ import java.lang.foreign.MemorySegment; -public class WindowsTransfer extends Transfer { - MemorySegment overlapped; +class WindowsTransfer extends Transfer { + private MemorySegment overlapped; + + public MemorySegment overlapped() { + return overlapped; + } + + public void setOverlapped(MemorySegment overlapped) { + this.overlapped = overlapped; + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index ec0acb0a..a8f61938 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -145,7 +145,7 @@ public synchronized void claimInterface(int interfaceNumber) { firstIntfHandle.deviceOpenCount += 1; intfHandle.interfaceHandle = interfaceHandle; - } catch (Throwable e) { + } catch (Exception e) { Kernel32.CloseHandle(deviceHandle); throw e; } @@ -211,13 +211,13 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { // copy data to native memory var transfer = createSyncControlTransfer(); int dataLength = data != null ? data.length : 0; - transfer.dataSize = dataLength; + transfer.setDataSize(dataLength); if (dataLength != 0) { var buffer = arena.allocate(data.length); buffer.copyFrom(MemorySegment.ofArray(data)); - transfer.data = buffer; + transfer.setData(buffer); } else { - transfer.data = NULL; + transfer.setData(NULL); } synchronized (transfer) { @@ -231,15 +231,15 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { public byte[] controlTransferIn(USBControlTransfer setup, int length) { try (var arena = Arena.ofConfined()) { var transfer = createSyncControlTransfer(); - transfer.data = arena.allocate(length); - transfer.dataSize = length; + transfer.setData(arena.allocate(length)); + transfer.setDataSize(length); synchronized (transfer) { submitControlTransfer(USBDirection.IN, setup, transfer); waitForTransfer(transfer, 0, USBDirection.IN, 0); } - return transfer.data.asSlice(0, transfer.resultSize).toArray(JAVA_BYTE); + return transfer.data().asSlice(0, transfer.resultSize()).toArray(JAVA_BYTE); } } @@ -270,21 +270,21 @@ public byte[] transferIn(int endpointNumber, int timeout) { waitForTransfer(transfer, timeout, USBDirection.IN, endpointNumber); } - return buffer.asSlice(0, transfer.resultSize).toArray(JAVA_BYTE); + return buffer.asSlice(0, transfer.resultSize()).toArray(JAVA_BYTE); } } private WindowsTransfer createSyncControlTransfer() { var transfer = new WindowsTransfer(); - transfer.completion = USBDeviceImpl::onSyncTransferCompleted; + transfer.setCompletion(USBDeviceImpl::onSyncTransferCompleted); return transfer; } private WindowsTransfer createSyncTransfer(MemorySegment data) { var transfer = new WindowsTransfer(); - transfer.data = data; - transfer.dataSize = (int) data.byteSize(); - transfer.completion = USBDeviceImpl::onSyncTransferCompleted; + transfer.setData(data); + transfer.setDataSize((int) data.byteSize()); + transfer.setCompletion(USBDeviceImpl::onSyncTransferCompleted); return transfer; } @@ -310,14 +310,14 @@ synchronized void submitControlTransfer(USBDirection direction, USBControlTransf setupPacket.setRequest(setup.request()); setupPacket.setValue(setup.value()); setupPacket.setIndex(setup.index()); - setupPacket.setLength(transfer.dataSize); + setupPacket.setLength(transfer.dataSize()); var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); asyncTask.prepareForSubmission(transfer); // submit transfer - if (WinUSB2.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket.segment(), transfer.data, - transfer.dataSize, NULL, transfer.overlapped, lastErrorState) == 0) { + if (WinUSB2.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket.segment(), transfer.data(), + transfer.dataSize(), NULL, transfer.overlapped(), lastErrorState) == 0) { int err = Win.getLastError(lastErrorState); if (err != Kernel32.ERROR_IO_PENDING()) throwException(err, "Submitting control transfer failed"); @@ -334,8 +334,8 @@ synchronized void submitTransferOut(int endpointNumber, WindowsTransfer transfer asyncTask.prepareForSubmission(transfer); // submit transfer - if (WinUSB2.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), transfer.data, transfer.dataSize, NULL - , transfer.overlapped, lastErrorState) == 0) { + if (WinUSB2.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), transfer.data(), + transfer.dataSize(), NULL, transfer.overlapped(), lastErrorState) == 0) { int err = Win.getLastError(lastErrorState); if (err != Kernel32.ERROR_IO_PENDING()) throwException(err, "Submitting transfer OUT failed"); @@ -352,8 +352,8 @@ synchronized void submitTransferIn(int endpointNumber, WindowsTransfer transfer) asyncTask.prepareForSubmission(transfer); // submit transfer - if (WinUSB2.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), transfer.data, transfer.dataSize, - NULL, transfer.overlapped, lastErrorState) == 0) { + if (WinUSB2.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), transfer.data(), + transfer.dataSize(), NULL, transfer.overlapped(), lastErrorState) == 0) { int err = Win.getLastError(lastErrorState); if (err != Kernel32.ERROR_IO_PENDING()) throwException(err, "Submitting transfer IN failed"); From 34c13bc58d5ca49d964a3812e96fff783eca0b50 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 29 Jul 2023 10:38:46 +0200 Subject: [PATCH 251/433] Remove USBDeviceFilter --- java-does-usb/pom.xml | 6 + .../src/main/java/net/codecrete/usb/USB.java | 32 ++- .../net/codecrete/usb/USBDeviceFilter.java | 186 ------------------ .../codecrete/usb/DeviceEnumerationTest.java | 61 ++---- .../net/codecrete/usb/TestDeviceBase.java | 10 +- .../codecrete/usb/special/LogicAnalyzer.java | 13 +- 6 files changed, 51 insertions(+), 257 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 89832e8f..4a9face8 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -143,6 +143,12 @@ 5.9.3 test + + org.assertj + assertj-core + 3.24.2 + test + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USB.java b/java-does-usb/src/main/java/net/codecrete/usb/USB.java index d3f46e2a..d2b9ddb8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USB.java @@ -13,6 +13,7 @@ import net.codecrete.usb.windows.WindowsUSBDeviceRegistry; import java.util.List; +import java.util.Optional; import java.util.function.Consumer; /** @@ -68,41 +69,32 @@ public static List getAllDevices() { /** * Gets a list of connected USB devices matching the specified predicate. * - * @param predicate device predicate/filter + * @param predicate device predicate * @return list of USB devices */ public static List getDevices(USBDevicePredicate predicate) { return instance().getAllDevices().stream().filter(predicate::matches).toList(); } - /** - * Gets a list of connected USB devices matching any of the specified predicates/filters. - * - * @param predicates list of device predicates/filters - * @return list of USB devices - */ - public static List getDevices(List predicates) { - return instance().getAllDevices().stream().filter(dev -> USBDevicePredicate.matchesAny(dev, predicates)).toList(); - } - /** * Gets the first connected USB device matching the specified predicate. * - * @param predicate device predicate/filter - * @return USB device, or {@code null} if no device matches + * @param predicate device predicate + * @return optional USB device */ - public static USBDevice getDevice(USBDevicePredicate predicate) { - return instance().getAllDevices().stream().filter(predicate::matches).findFirst().orElse(null); + public static Optional getDevice(USBDevicePredicate predicate) { + return instance().getAllDevices().stream().filter(predicate::matches).findFirst(); } /** - * Gets the first connected USB device matching any of the specified predicates. + * Gets the first connected USB device with the specified vendor and product ID. * - * @param predicates list of device predicates/filters - * @return USB device, or {@code null} if no device matches + * @param vendorId vendor ID + * @param productId product ID + * @return optional USB device */ - public static USBDevice getDevice(List predicates) { - return instance().getAllDevices().stream().filter(dev -> USBDevicePredicate.matchesAny(dev, predicates)).findFirst().orElse(null); + public static Optional getDevice(int vendorId, int productId) { + return getDevice(device -> device.vendorId() == vendorId && device.productId() == productId); } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java deleted file mode 100644 index 121e1cca..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDeviceFilter.java +++ /dev/null @@ -1,186 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb; - -/** - * Filter condition for matching USB devices. - *

- * In order to match this condition, all non-null properties - * of this instance must be equal to the same properties of the USB device. - *

- *

- * For a well implemented USB device, the combination of vendor ID, - * product ID and serial number is globally unique. - *

- */ -public class USBDeviceFilter implements USBDevicePredicate { - private Integer vid; - private Integer pid; - private Integer deviceClass; - private Integer deviceSubclass; - private Integer deviceProtocol; - private String serialString; - - /** - * Creates a new instance. - */ - public USBDeviceFilter() { - } - - /** - * Creates a new instance that matches the specified vendor and product ID. - * - * @param vendorId vendor ID - * @param productId product ID - */ - public USBDeviceFilter(int vendorId, int productId) { - vid = vendorId; - pid = productId; - } - - /** - * Creates a new instance that matches the specified vendor ID, product ID and serial number. - * - * @param vendorId vendor ID - * @param productId product ID - * @param serialNumber serial number - */ - public USBDeviceFilter(int vendorId, int productId, String serialNumber) { - vid = vendorId; - pid = productId; - serialString = serialNumber; - } - - /** - * Gets the USB vendor ID. - * - * @return vendor ID, or {@code null} if the vendor ID is not relevant for matching - */ - public Integer vendorId() { - return vid; - } - - /** - * Sets the USB vendor ID. - * - * @param vendorId vendor ID, or {@code null} if the vendor ID is not relevant for matching - */ - public void setVendorId(Integer vendorId) { - vid = vendorId; - } - - /** - * Gets the USB product ID. - * - * @return product ID, or {@code null} if the product ID is not relevant for matching - */ - public Integer productId() { - return pid; - } - - /** - * Sets the USB product ID. - * - * @param productId product ID, or {@code null} if the product ID is not relevant for matching - */ - public void setProductId(Integer productId) { - pid = productId; - } - - /** - * Gets the USB device class code. - * - * @return class code, or {@code null} if the class code is not relevant for matching - */ - public Integer classCode() { - return deviceClass; - } - - /** - * Sets the USB device class code. - * - * @param classCode class code, or {@code null} if the class code is not relevant for matching - */ - public void setClassCode(Integer classCode) { - deviceClass = classCode; - } - - /** - * Gets the USB device subclass code. - * - * @return subclass code, or {@code null} if the subclass code is not relevant for matching - */ - public Integer subclassCode() { - return deviceSubclass; - } - - /** - * Sets the USB device subclass code. - * - * @param subclassCode subclass code, or {@code null} if the subclass code is not relevant for matching - */ - public void setSubclassCode(Integer subclassCode) { - deviceSubclass = subclassCode; - } - - /** - * Gets the USB device protocol code. - * - * @return protocol code, or {@code null} if the protocol code is not relevant for matching - */ - public Integer protocolCode() { - return deviceProtocol; - } - - /** - * Sets the USB device protocol code. - * - * @param protocolCode protocol code, or {@code null} if the protocol code is not relevant for matching - */ - public void setProtocolCode(Integer protocolCode) { - deviceProtocol = protocolCode; - } - - /** - * Gets the device serial number. - * - * @return serial number, or {@code null} if the serial number is not relevant for matching - */ - public String serialNumber() { - return serialString; - } - - /** - * Sets the device serial number. - * - * @param serialNumber serial number, or {@code null} if the serial number is not relevant for matching - */ - public void setSerialNumber(String serialNumber) { - serialString = serialNumber; - } - - /** - * Tests if the specified USB device matches this filter. - * - * @param device USB device - * @return {@code true} if it matches, {@code false} otherwise - */ - public boolean matches(USBDevice device) { - if (vid != null && device.vendorId() != vid) - return false; - if (pid != null && device.productId() != pid) - return false; - if (serialString != null && !serialString.equals(device.serialNumber())) - return false; - if (deviceClass != null && device.classCode() != deviceClass) - return false; - if (deviceSubclass != null && device.subclassCode() != deviceSubclass) - return false; - return deviceProtocol == null || device.protocolCode() == deviceProtocol; - } -} diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java index 9a29f65f..02a3f84e 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java @@ -11,60 +11,39 @@ import org.junit.jupiter.api.Test; -import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class DeviceEnumerationTest extends TestDeviceBase { +class DeviceEnumerationTest extends TestDeviceBase { @Test void getAllDevices_includesLoopback() { - var found = USB.getAllDevices().stream() + var deviceList = USB.getAllDevices(); + assertThat(deviceList) + .isNotEmpty() .anyMatch(device -> device.vendorId() == vid && device.productId() == pid); - assertTrue(found); - } - - @Test - void getDevicesWithFilter_returnsLoopback() { - var result = USB.getDevices(new USBDeviceFilter(vid, pid)); - assertEquals(1, result.size()); - assertEquals(vid, result.get(0).vendorId()); - assertEquals(pid, result.get(0).productId()); - } - - @Test - void getDevicesWithMultipleFilters_returnsLoopback() { - var result = USB.getDevices(List.of( - new USBDeviceFilter(vid, pid), - new USBDeviceFilter(0x0000, 0xffff) - )); - assertEquals(1, result.size()); - assertEquals(vid, result.get(0).vendorId()); - assertEquals(pid, result.get(0).productId()); } @Test - void getDeviceWithFilter_returnsLoopback() { - var device = USB.getDevice(new USBDeviceFilter(vid, pid)); - assertEquals(vid, device.vendorId()); - assertEquals(pid, device.productId()); + void getDevices_includesLoopback() { + var deviceList = USB.getDevices(device -> device.vendorId() == vid && device.productId() == pid); + assertThat(deviceList) + .isNotEmpty() + .anyMatch(device -> device.vendorId() == vid && device.productId() == pid); } @Test - void getDeviceWithMultipleFilters_returnsLoopback() { - var device = USB.getDevice(List.of( - new USBDeviceFilter(vid, pid), - new USBDeviceFilter(0x0000, 0xffff) - )); - assertEquals(vid, device.vendorId()); - assertEquals(pid, device.productId()); + void getDevicePredicate_returnsLoopback() { + var device = USB.getDevice(dev -> dev.vendorId() == vid && dev.productId() == pid); + assertThat(device).isPresent(); + assertThat(device.get().productId()).isEqualTo(pid); + assertThat(device.get().vendorId()).isEqualTo(vid); } @Test - void getDeviceWithPredicate_returnsLoopback() { - var device = USB.getDevice(dev -> dev.vendorId() == vid && dev.productId() == pid); - assertEquals(vid, device.vendorId()); - assertEquals(pid, device.productId()); + void getDeviceVidPid_returnsLoopback() { + var device = USB.getDevice(vid, pid); + assertThat(device).isPresent(); + assertThat(device.get().productId()).isEqualTo(pid); + assertThat(device.get().vendorId()).isEqualTo(vid); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index a52f0ec6..e13a4e40 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -57,12 +57,12 @@ public class TestDeviceBase { protected static USBDevice testDevice; static USBDevice getDevice() { - var device = USB.getDevice(new USBDeviceFilter(VID_COMPOSITE, PID_COMPOSITE)); - if (device == null) - device = USB.getDevice(new USBDeviceFilter(VID_LOOPBACK, PID_LOOPBACK)); - if (device == null) + var optionalDevice = USB.getDevice(VID_COMPOSITE, PID_COMPOSITE); + if (optionalDevice.isEmpty()) + optionalDevice = USB.getDevice(VID_LOOPBACK, PID_LOOPBACK); + if (optionalDevice.isEmpty()) throw new IllegalStateException("No test device connected"); - return device; + return optionalDevice.get(); } static int getInterfaceNumber(USBDevice device) { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java b/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java index 11b04ccf..e146192a 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java @@ -83,10 +83,12 @@ public static void main(String[] args) { private USBDevice device; LogicAnalyzer() { - device = USB.getDevice(new USBDeviceFilter(VID, PID)); - if (device == null) + var optionalDevice = USB.getDevice(VID, PID); + if (optionalDevice.isEmpty()) throw new IllegalStateException("no logic analyzer connected"); + device = optionalDevice.get(); + checkFirmware(); device.open(); @@ -294,9 +296,10 @@ void checkFirmware() { DeviceMonitor.instance().awaitDevice(true); sleep(200); - device = USB.getDevice(new USBDeviceFilter(VID, PID)); - if (device == null) + var optionalDevice = USB.getDevice(VID, PID); + if (optionalDevice.isEmpty()) throw new IllegalStateException("no logic analyzer connected"); + device = optionalDevice.get(); if (device.manufacturer() == null) throw new IllegalStateException("firmware upload failed"); @@ -336,7 +339,7 @@ private DeviceMonitor() { } private void start() { USB.setOnDeviceConnected((device) -> onDeviceConnected(device, true)); USB.setOnDeviceDisconnected((device) -> onDeviceConnected(device, false)); - isDeviceConnected = USB.getDevice(new USBDeviceFilter(VID, PID)) != null; + isDeviceConnected = USB.getDevice(VID, PID).isPresent(); } private void onDeviceConnected(USBDevice device, boolean connected) { From ea214e58d9ddccbb07ad5710f37a8a2970c710a5 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 29 Jul 2023 11:13:03 +0200 Subject: [PATCH 252/433] Upgrade example projects --- examples/bulk_transfer/pom.xml | 14 +++++++------- .../net/codecrete/usb/examples/BulkTransfer.java | 11 +++++++++-- examples/enumerate/pom.xml | 14 +++++++------- examples/epaper_display/pom.xml | 14 +++++++------- .../net/codecrete/usb/examples/IT8951Driver.java | 7 ++++--- examples/monitor/pom.xml | 14 +++++++------- examples/stm_dfu/README.md | 1 + examples/stm_dfu/pom.xml | 14 +++++++------- java-does-usb/pom.xml | 2 +- 9 files changed, 50 insertions(+), 41 deletions(-) diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index 721b0b3a..ca51c5b7 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,22 +6,22 @@ net.codecrete.usb.examples bulk-transfer - 0.5.1 + 0.6.0-SNAPSHOT bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer UTF-8 - 20 - 20 + 21 + 21 net.codecrete.usb java-does-usb - 0.5.1 + 0.6.0-SNAPSHOT @@ -42,12 +42,12 @@ maven-compiler-plugin 3.8.0 - 20 + 21 --enable-preview - 20 - 20 + 21 + 21
diff --git a/examples/bulk_transfer/src/main/java/net/codecrete/usb/examples/BulkTransfer.java b/examples/bulk_transfer/src/main/java/net/codecrete/usb/examples/BulkTransfer.java index 37e8f2e3..bfef6131 100644 --- a/examples/bulk_transfer/src/main/java/net/codecrete/usb/examples/BulkTransfer.java +++ b/examples/bulk_transfer/src/main/java/net/codecrete/usb/examples/BulkTransfer.java @@ -14,7 +14,8 @@ *
*/ public class BulkTransfer { @@ -26,7 +27,13 @@ public class BulkTransfer { private static final int ENDPOINT_IN = 2; public static void main(String[] args) { - var device = USB.getDevice(new USBDeviceFilter(VID, PID)); + var optionalDevice = USB.getDevice(VID, PID); + if (optionalDevice.isEmpty()) { + System.out.printf("No USB device with VID=0x%04x and PID=0x%04x found.%n", VID, PID); + return; + } + + var device = optionalDevice.get(); device.open(); device.claimInterface(INTERFACE_NO); diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index ceac2fee..45177aba 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,22 +6,22 @@ net.codecrete.usb.examples enumerate - 0.5.1 + 0.6.0-SNAPSHOT enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate UTF-8 - 20 - 20 + 21 + 21 net.codecrete.usb java-does-usb - 0.5.1 + 0.6.0-SNAPSHOT @@ -42,12 +42,12 @@ maven-compiler-plugin 3.8.0 - 20 + 21 --enable-preview - 20 - 20 + 21 + 21 diff --git a/examples/epaper_display/pom.xml b/examples/epaper_display/pom.xml index 4fefedc6..697fdc5f 100644 --- a/examples/epaper_display/pom.xml +++ b/examples/epaper_display/pom.xml @@ -6,22 +6,22 @@ net.codecrete.usb.examples epaper-display - 0.5.1 + 0.6.0-SNAPSHOT epaper-display https://github.com/manuelbl/JavaDoesUSB/examples/epaper_display UTF-8 - 20 - 20 + 21 + 21 net.codecrete.usb java-does-usb - 0.5.1 + 0.6.0-SNAPSHOT @@ -42,12 +42,12 @@ maven-compiler-plugin 3.11.0 - 20 + 21 --enable-preview - 20 - 20 + 21 + 21 diff --git a/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java b/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java index e3b4f7e2..7170fc71 100644 --- a/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java +++ b/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java @@ -46,10 +46,11 @@ public class IT8951Driver { * @throws IllegalStateException if no IT8951 device is found */ public void open() { - device = USB.getDevice(dev -> dev.vendorId() == 0x048d && dev.productId() == 0x8951); - if (device == null) + var optionalDevice = USB.getDevice(0x048d, 0x8951); + if (optionalDevice.isEmpty()) throw new IllegalStateException("No IT8951 device found"); + device = optionalDevice.get(); device.detachStandardDrivers(); device.open(); try { @@ -57,7 +58,7 @@ public void open() { var sysInfoBytes = readCommand(GET_SYS_CMD, DisplayInfo.LENGTH); displayInfo = DisplayInfo.from(sysInfoBytes); - } catch (Throwable t) { + } catch (Exception t) { device.close(); throw t; } diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index b4075b7b..d549d71f 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,22 +6,22 @@ net.codecrete.usb.examples monitor - 0.5.1 + 0.6.0-SNAPSHOT monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor UTF-8 - 20 - 20 + 21 + 21 net.codecrete.usb java-does-usb - 0.5.1 + 0.6.0-SNAPSHOT @@ -42,12 +42,12 @@ maven-compiler-plugin 3.8.0 - 20 + 21 --enable-preview - 20 - 20 + 21 + 21 diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index 2b4d3982..f2a6d308 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -57,6 +57,7 @@ SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE="0666" Run the command below (adapting the file path depending on your specific board): ```shell +$ mvn package $ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.5.1.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin DFU device found with serial 35A737883336. Target memory segment: Internal Flash diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index 19df9cfd..5dcbc1de 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -4,22 +4,22 @@ net.codecrete.usb.examples stm_dfu - 0.5.1 + 0.6.0-SNAPSHOT stm_dfu https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu UTF-8 - 20 - 20 + 21 + 21 net.codecrete.usb java-does-usb - 0.5.1 + 0.6.0-SNAPSHOT @@ -37,12 +37,12 @@ maven-compiler-plugin 3.8.0 - 20 + 21 --enable-preview - 20 - 20 + 21 + 21 diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 4a9face8..32b756cf 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -69,7 +69,7 @@ maven-surefire-plugin 3.1.2 - --enable-preview --enable-native-access=net.codecrete.usb + --enable-preview --enable-native-access=ALL-UNNAMED From 87bb4c4ddea5cc4135c909712490bc172eba9f88 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 29 Jul 2023 12:39:55 +0200 Subject: [PATCH 253/433] Update README for e-paper display sample --- examples/epaper_display/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/epaper_display/README.md b/examples/epaper_display/README.md index 79ccc00c..c9d3b628 100644 --- a/examples/epaper_display/README.md +++ b/examples/epaper_display/README.md @@ -4,7 +4,7 @@ This sample shows how to communicate with an IT8951 controller for e-paper displ ## Prerequisites -- Java 20 +- Java 21 - Apache Maven - 64-bit operating system (macOS, Linux, Windows) - IT8951 controller @@ -17,9 +17,9 @@ be temporarily detached.) ## How to run -### Install Java 20 +### Install Java 21 -Check that *Java 20* is installed: +Check that *Java 21* is installed: ```shell $ java -version From fa3b30c22ee1996afd7f2e54a1561a9d6b5749bc Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 29 Jul 2023 12:40:51 +0200 Subject: [PATCH 254/433] EndpointInputStream: read as much as possible --- .../usb/common/EndpointInputStream.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index 85125170..b514b9f9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -139,17 +139,20 @@ public int read(byte[] b, int off, int len) throws IOException { if (isClosed()) return -1; - if (available() == 0) - receiveMoreData(); + var numRead = 0; + do { + if (available() == 0) + receiveMoreData(); - // copy data to receiving buffer - var n = Math.min(len, currentTransfer.resultSize() - readOffset); - MemorySegment.copy(currentTransfer.data(), readOffset, MemorySegment.ofArray(b), off, n); - readOffset += n; + // copy data to receiving buffer + var n = Math.min(len - numRead, currentTransfer.resultSize() - readOffset); + MemorySegment.copy(currentTransfer.data(), readOffset, MemorySegment.ofArray(b), (long) off + numRead, n); + readOffset += n; + numRead += n; - // TODO: poll for further completed transfers if 'n' is less than 'len' + } while (numRead < len && hasMoreTransfers()); - return n; + return numRead; } @SuppressWarnings("RedundantThrows") @@ -158,6 +161,10 @@ public int available() throws IOException { return currentTransfer.resultSize() - readOffset; } + private boolean hasMoreTransfers() { + return !completedTransferQueue.isEmpty(); + } + private void receiveMoreData() throws IOException { try { // loop until non-ZLP has been received From 5db383024f49c37462ee8720f9a84cd13bb10a63 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 29 Jul 2023 12:53:02 +0200 Subject: [PATCH 255/433] Code style alignment --- .../usb/usbstandard/StringDescriptor.java | 2 +- .../codecrete/usb/windows/DeviceProperty.java | 115 ++++++++---- .../usb/windows/InterfaceHandle.java | 1 + .../net/codecrete/usb/windows/USBHelper.java | 27 +-- .../java/net/codecrete/usb/windows/Win.java | 26 +-- .../usb/windows/WindowsAsyncTask.java | 37 ++-- .../usb/windows/WindowsUSBDevice.java | 15 +- .../usb/windows/WindowsUSBDeviceRegistry.java | 168 +++++++++--------- .../usb/windows/WindowsUSBException.java | 8 +- .../usb/windows/winsdk/Kernel32B.java | 13 +- .../usb/windows/winsdk/SetupAPI2.java | 22 +-- .../codecrete/usb/windows/winsdk/User32B.java | 13 +- .../codecrete/usb/windows/winsdk/WinUSB2.java | 21 ++- .../codecrete/usb/AlternateInterfaceTest.java | 2 +- .../net/codecrete/usb/BulkTransferTest.java | 2 +- .../codecrete/usb/ControlTransferTest.java | 2 +- .../net/codecrete/usb/DescriptionTest.java | 2 +- .../codecrete/usb/DeviceLifecycleTest.java | 2 +- .../codecrete/usb/InterruptTransferTest.java | 2 +- .../codecrete/usb/InvalidOperationTest.java | 2 +- .../java/net/codecrete/usb/SpeedTest.java | 2 +- .../java/net/codecrete/usb/StallTest.java | 8 +- .../java/net/codecrete/usb/StreamTest.java | 4 +- .../java/net/codecrete/usb/TimeoutTest.java | 2 +- .../net/codecrete/usb/special/Unplug.java | 2 +- 25 files changed, 272 insertions(+), 228 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java index d98b9cfb..4863045f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java @@ -48,5 +48,5 @@ public String string() { ); private static final VarHandle bLength$VH = LAYOUT.varHandle(groupElement("bLength")); - private static final long string$offset = LAYOUT.byteOffset(groupElement("string")); + private static final long string$offset = LAYOUT.byteOffset(groupElement("string")); // NOSONAR } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index c4af7be2..c6603c3e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -10,10 +10,9 @@ import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.windows.gen.advapi32.Advapi32; import net.codecrete.usb.windows.gen.kernel32.Kernel32; -import net.codecrete.usb.windows.gen.setupapi.DEVPROPKEY; -import net.codecrete.usb.windows.gen.setupapi.SP_DEVICE_INTERFACE_DATA; -import net.codecrete.usb.windows.gen.setupapi.SP_DEVICE_INTERFACE_DETAIL_DATA_W; -import net.codecrete.usb.windows.gen.setupapi.SetupAPI; +import net.codecrete.usb.windows.gen.kernel32._GUID; +import net.codecrete.usb.windows.gen.ole32.Ole32; +import net.codecrete.usb.windows.gen.setupapi.*; import net.codecrete.usb.windows.winsdk.SetupAPI2; import java.lang.foreign.Arena; @@ -29,29 +28,32 @@ /** * Device property GUIDs and functions */ -public class DeviceProperty { +class DeviceProperty { - public static final MemorySegment DEVPKEY_Device_Address = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, + private DeviceProperty() { + } + + static final MemorySegment DEVPKEY_Device_Address = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50 , (byte) 0xe0, 30); - public static final MemorySegment DEVPKEY_Device_InstanceId = createDEVPROPKEY(0x78c34fc8, (short) 0x104a, + static final MemorySegment DEVPKEY_Device_InstanceId = createDEVPROPKEY(0x78c34fc8, (short) 0x104a, (short) 0x4aca, (byte) 0x9e, (byte) 0xa4, (byte) 0x52, (byte) 0x4d, (byte) 0x52, (byte) 0x99, (byte) 0x6e , (byte) 0x57, 256); - public static final MemorySegment DEVPKEY_Device_Parent = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, + static final MemorySegment DEVPKEY_Device_Parent = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, (short) 0x4706, (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, (byte) 0x80, (byte) 0x08, (byte) 0xa5 , (byte) 0xa7, 8); - public static final MemorySegment DEVPKEY_Device_Service = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, + static final MemorySegment DEVPKEY_Device_Service = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50 , (byte) 0xe0, 6); - public static final MemorySegment DEVPKEY_Device_Children = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, + static final MemorySegment DEVPKEY_Device_Children = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, (short) 0x4706, (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, (byte) 0x80, (byte) 0x08, (byte) 0xa5 , (byte) 0xa7, 9); - public static final MemorySegment DEVPKEY_Device_HardwareIds = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, + static final MemorySegment DEVPKEY_Device_HardwareIds = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50 , (byte) 0xe0, 3); @@ -63,15 +65,16 @@ public class DeviceProperty { * @param propertyKey property key (of type {@code DEVPKEY}) * @return property value */ - public static int getDeviceIntProperty(MemorySegment devInfoSet, MemorySegment devInfoData, - MemorySegment propertyKey) { + @SuppressWarnings("SameParameterValue") + static int getDeviceIntProperty(MemorySegment devInfoSet, MemorySegment devInfoData, + MemorySegment propertyKey) { try (var arena = Arena.ofConfined()) { var propertyTypeHolder = arena.allocate(JAVA_INT); var propertyValueHolder = arena.allocate(JAVA_INT); var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, lastErrorState) == 0) - throwLastError(lastErrorState, "Internal error (SetupDiGetDevicePropertyW)"); + throwLastError(lastErrorState, "Internal error (SetupDiGetDevicePropertyW - A)"); if (propertyTypeHolder.get(JAVA_INT, 0) != SetupAPI.DEVPROP_TYPE_UINT32()) throwException("Internal error (expected property type UINT32)"); @@ -88,7 +91,7 @@ public static int getDeviceIntProperty(MemorySegment devInfoSet, MemorySegment d * @param propertyKey property key (of type {@code DEVPKEY}) * @return property value */ - public static String getDeviceStringProperty(MemorySegment devInfoSet, MemorySegment devInfoData, + static String getDeviceStringProperty(MemorySegment devInfoSet, MemorySegment devInfoData, MemorySegment propertyKey) { try (var arena = Arena.ofConfined()) { var propertyValue = getVariableLengthProperty(devInfoSet, devInfoData, propertyKey, @@ -107,7 +110,8 @@ public static String getDeviceStringProperty(MemorySegment devInfoSet, MemorySeg * @param propertyKey property key (of type {@code DEVPKEY}) * @return property value */ - public static List getDeviceStringListProperty(MemorySegment devInfoSet, MemorySegment devInfoData, + @SuppressWarnings("java:S1168") + static List getDeviceStringListProperty(MemorySegment devInfoSet, MemorySegment devInfoData, MemorySegment propertyKey) { try (var arena = Arena.ofConfined()) { var propertyValue = getVariableLengthProperty(devInfoSet, devInfoData, propertyKey, @@ -128,25 +132,25 @@ private static MemorySegment getVariableLengthProperty(MemorySegment devInfoSet, var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, NULL, 0, requiredSizeHolder, 0, lastErrorState) == 0) { - int err = Win.getLastError(lastErrorState); + var err = Win.getLastError(lastErrorState); if (err == Kernel32.ERROR_NOT_FOUND()) return null; if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) - throwException(err, "Internal error (SetupDiGetDevicePropertyW)"); + throwException(err, "Internal error (SetupDiGetDevicePropertyW - B)"); } if (propertyTypeHolder.get(JAVA_INT, 0) != propertyType) throwException("Internal error (unexpected property type)"); - int stringLen = requiredSizeHolder.get(JAVA_INT, 0) / 2 - 1; + var stringLen = requiredSizeHolder.get(JAVA_INT, 0) / 2 - 1; // allocate buffer - var propertyValueHolder = arena.allocateArray(JAVA_CHAR, stringLen + 1); + var propertyValueHolder = arena.allocateArray(JAVA_CHAR, stringLen + 1L); // get property value if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, lastErrorState) == 0) - throwLastError(lastErrorState, "Internal error (SetupDiGetDevicePropertyW)"); + throwLastError(lastErrorState, "Internal error (SetupDiGetDevicePropertyW - C)"); return propertyValueHolder; } @@ -159,7 +163,7 @@ private static MemorySegment getVariableLengthProperty(MemorySegment devInfoSet, * @param arena arena for allocating memory * @return list of GUIDs */ - public static List findDeviceInterfaceGUIDs(MemorySegment devInfoSet, MemorySegment devInfoData, + static List findDeviceInterfaceGUIDs(MemorySegment devInfoSet, MemorySegment devInfoData, Arena arena) { try (var cleanup = new ScopeCleanup()) { @@ -168,7 +172,7 @@ public static List findDeviceInterfaceGUIDs(MemorySegment devInfoSet, Me // open device registry key var regKey = SetupAPI2.SetupDiOpenDevRegKey(devInfoSet, devInfoData, SetupAPI.DICS_FLAG_GLOBAL(), 0, SetupAPI.DIREG_DEV(), Advapi32.KEY_READ(), lastErrorState); - if (Win.IsInvalidHandle(regKey)) + if (Win.isInvalidHandle(regKey)) throwLastError(lastErrorState, "Cannot open device registry key"); cleanup.add(() -> Advapi32.RegCloseKey(regKey)); @@ -196,27 +200,27 @@ public static List findDeviceInterfaceGUIDs(MemorySegment devInfoSet, Me /** * Gets the device path for the device with the given device instance ID and device interface class. * - * @param instanceID device instance ID - * @param interfaceGuid device interface class + * @param instanceId device instance ID + * @param interfaceGuid device interface class GUID * @return the device path */ - public static String getDevicePath(String instanceID, MemorySegment interfaceGuid) { + static String getDevicePath(String instanceId, MemorySegment interfaceGuid) { try (var arena = Arena.ofConfined(); var cleanup = new ScopeCleanup()) { var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); // get device info set for instance - var instanceIDSegment = Win.createSegmentFromString(instanceID, arena); + var instanceIDSegment = Win.createSegmentFromString(instanceId, arena); final var devInfoSet = SetupAPI2.SetupDiGetClassDevsW(interfaceGuid, instanceIDSegment, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), lastErrorState); - if (Win.IsInvalidHandle(devInfoSet)) + if (Win.isInvalidHandle(devInfoSet)) throwLastError(lastErrorState, "internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); // retrieve first element of enumeration - var devIntfData = arena.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); - SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); + var devIntfData = arena.allocate(_SP_DEVICE_INTERFACE_DATA.$LAYOUT()); + _SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); if (SetupAPI2.SetupDiEnumDeviceInterfaces(devInfoSet, NULL, interfaceGuid, 0, devIntfData, lastErrorState) == 0) throwLastError(lastErrorState, "internal error (SetupDiEnumDeviceInterfaces)"); @@ -224,11 +228,11 @@ public static String getDevicePath(String instanceID, MemorySegment interfaceGui // get device path // (SP_DEVICE_INTERFACE_DETAIL_DATA_W is of variable length and requires a bigger allocation so // the device path fits) - final int devicePathOffset = 4; - var intfDetailData = arena.allocate(4 + 260 * 2); - SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$set(intfDetailData, - (int) SP_DEVICE_INTERFACE_DETAIL_DATA_W.sizeof()); - int intfDetailDataSize = (int) intfDetailData.byteSize(); + final var devicePathOffset = 4; + var intfDetailData = arena.allocate(4L + 260 * 2); + _SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$set(intfDetailData, + (int) _SP_DEVICE_INTERFACE_DETAIL_DATA_W.sizeof()); + var intfDetailDataSize = (int) intfDetailData.byteSize(); if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSet, devIntfData, intfDetailData, intfDetailDataSize, NULL, NULL, lastErrorState) == 0) throwLastError(lastErrorState, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); @@ -237,6 +241,38 @@ public static String getDevicePath(String instanceID, MemorySegment interfaceGui } } + /** + * Gets the device path for the device from the given device info set and the given instance ID. + *

+ * The device path is looked up by checking the associated GUIDs. + *

+ * + * @param devInfoSet device information set containing the device ({@code HDEVINFO}) + * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set + * @param instanceId device instance ID + * @param arena arena for allocating memory + * @return the device path, {code null} if not found + */ + static String getDevicePathByGUID(MemorySegment devInfoSet, MemorySegment devInfoData, String instanceId, Arena arena) { + var guids = DeviceProperty.findDeviceInterfaceGUIDs(devInfoSet, devInfoData, arena); + + for (var guid : guids) { + // check for class GUID + var guidSegment = Win.createSegmentFromString(guid, arena); + var clsid = arena.allocate(_GUID.$LAYOUT()); + if (Ole32.CLSIDFromString(guidSegment, clsid) != 0) + continue; + + try { + return DeviceProperty.getDevicePath(instanceId, clsid); + } catch (Exception e) { + // ignore and try next one + } + } + + return null; + } + /** * Checks if the device is a composite USB device * @@ -244,21 +280,22 @@ public static String getDevicePath(String instanceID, MemorySegment interfaceGui * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set * @return {@code true} if it is a composite device */ - public static boolean isCompositeDevice(MemorySegment devInfoSet, MemorySegment devInfoData) { + static boolean isCompositeDevice(MemorySegment devInfoSet, MemorySegment devInfoData) { var deviceService = getDeviceStringProperty(devInfoSet, devInfoData, DEVPKEY_Device_Service); // usbccgp is the USB Generic Parent Driver used for composite devices return "usbccgp".equalsIgnoreCase(deviceService); } + @SuppressWarnings({"java:S107", "java:S117"}) private static MemorySegment createDEVPROPKEY(int data1, short data2, short data3, byte data4_0, byte data4_1, byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7, int pid) { @SuppressWarnings("resource") - var propKey = Arena.global().allocate(DEVPROPKEY.$LAYOUT()); - Win.setGUID(DEVPROPKEY.fmtid$slice(propKey), data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4 + var propKey = Arena.global().allocate(_DEVPROPKEY.$LAYOUT()); + Win.setGUID(_DEVPROPKEY.fmtid$slice(propKey), data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4 , data4_5, data4_6, data4_7); - DEVPROPKEY.pid$set(propKey, pid); + _DEVPROPKEY.pid$set(propKey, pid); return propKey; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java index f359d92b..91cc9bd4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java @@ -38,6 +38,7 @@ class InterfaceHandle { /** * The WinUSB handle of the interface. */ + @SuppressWarnings("java:S1700") MemorySegment interfaceHandle; /** * Count indicating how many interface depend on the device being open. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java index ad62a895..f960ffb7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java @@ -25,10 +25,13 @@ * USB_NODE_CONNECTION_INFORMATION_EX struct. *

*/ -public class USBHelper { +@SuppressWarnings({"java:S125", "java:S1192", "java:S115", "java:S100"}) +class USBHelper { - public static final byte USB_REQUEST_GET_DESCRIPTOR = 0x06; + private USBHelper() { + } + static final byte USB_REQUEST_GET_DESCRIPTOR = 0x06; // typedef struct _USB_NODE_CONNECTION_INFORMATION_EX { // ULONG ConnectionIndex; /* INPUT */ @@ -44,7 +47,7 @@ public class USBHelper { // USB_CONNECTION_STATUS ConnectionStatus;/* OUTPUT */ // USB_PIPE_INFO PipeList[0];/* OUTPUT */ //} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; - public static final GroupLayout USB_NODE_CONNECTION_INFORMATION_EX$Struct = MemoryLayout.structLayout( + static final GroupLayout USB_NODE_CONNECTION_INFORMATION_EX$Struct = MemoryLayout.structLayout( JAVA_INT.withName("ConnectionIndex"), DeviceDescriptor.LAYOUT.withName("DeviceDescriptor"), JAVA_BYTE.withName("CurrentConfigurationValue"), @@ -55,12 +58,12 @@ public class USBHelper { JAVA_INT_UNALIGNED.withName("ConnectionStatus") // USB_PIPE_INFO PipeList[0] ); - public static final VarHandle USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex = + static final VarHandle USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex = USB_NODE_CONNECTION_INFORMATION_EX$Struct.varHandle(groupElement("ConnectionIndex")); - public static final long USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset = + static final long USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset = USB_NODE_CONNECTION_INFORMATION_EX$Struct.byteOffset(groupElement("DeviceDescriptor")); - public static MemorySegment USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(MemorySegment seg) { + static MemorySegment USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(MemorySegment seg) { return seg.asSlice(USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset, DeviceDescriptor.LAYOUT.byteSize()); } @@ -76,21 +79,21 @@ public class USBHelper { // } SetupPacket; // UCHAR Data[0]; //} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST; - public static final GroupLayout USB_DESCRIPTOR_REQUEST$Struct = MemoryLayout.structLayout(JAVA_INT.withName( + static final GroupLayout USB_DESCRIPTOR_REQUEST$Struct = MemoryLayout.structLayout(JAVA_INT.withName( "ConnectionIndex"), SetupPacket.LAYOUT.withName("SetupPacket")); - public static final VarHandle USB_DESCRIPTOR_REQUEST_ConnectionIndex = + static final VarHandle USB_DESCRIPTOR_REQUEST_ConnectionIndex = USB_DESCRIPTOR_REQUEST$Struct.varHandle(groupElement("ConnectionIndex")); - public static final long USB_DESCRIPTOR_REQUEST_SetupPacket$Offset = + static final long USB_DESCRIPTOR_REQUEST_SetupPacket$Offset = USB_DESCRIPTOR_REQUEST$Struct.byteOffset(groupElement("SetupPacket")); - public static final long USB_DESCRIPTOR_REQUEST_Data$Offset = USB_DESCRIPTOR_REQUEST$Struct.byteSize(); + static final long USB_DESCRIPTOR_REQUEST_Data$Offset = USB_DESCRIPTOR_REQUEST$Struct.byteSize(); // A5DCBF10-6530-11D2-901F-00C04FB951ED - public static final MemorySegment GUID_DEVINTERFACE_USB_DEVICE = Win.CreateGUID(0xA5DCBF10, (short) 0x6530, + static final MemorySegment GUID_DEVINTERFACE_USB_DEVICE = Win.createGUID(0xA5DCBF10, (short) 0x6530, (short) 0x11D2, (byte) 0x90, (byte) 0x1F, (byte) 0x00, (byte) 0xC0, (byte) 0x4F, (byte) 0xB9, (byte) 0x51 , (byte) 0xED); // f18a0e88-c30c-11d0-8815-00a0c906bed8 - public static final MemorySegment GUID_DEVINTERFACE_USB_HUB = Win.CreateGUID(0xf18a0e88, (short) 0xc30c, + static final MemorySegment GUID_DEVINTERFACE_USB_HUB = Win.createGUID(0xf18a0e88, (short) 0xc30c, (short) 0x11d0, (byte) 0x88, (byte) 0x15, (byte) 0x00, (byte) 0xa0, (byte) 0xc9, (byte) 0x06, (byte) 0xbe , (byte) 0xd8); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index 209e2cc9..cb139923 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -7,7 +7,7 @@ package net.codecrete.usb.windows; -import net.codecrete.usb.windows.gen.kernel32.GUID; +import net.codecrete.usb.windows.gen.kernel32._GUID; import java.lang.foreign.*; import java.lang.foreign.MemoryLayout.PathElement; @@ -22,6 +22,8 @@ * Windows helpers. */ public class Win { + private Win() { + } /** * Call state for capturing the {@code GetLastError()} value. @@ -48,7 +50,7 @@ public static int getLastError(MemorySegment callState) { * @param handle Windows handle * @return {@code true} if the handle is invalid, {@code false} otherwise */ - public static boolean IsInvalidHandle(MemorySegment handle) { + public static boolean isInvalidHandle(MemorySegment handle) { return handle.address() == -1L; } @@ -64,7 +66,7 @@ public static boolean IsInvalidHandle(MemorySegment handle) { */ public static MemorySegment createSegmentFromString(String str, Arena arena) { // allocate segment (including space for terminating null) - var segment = arena.allocateArray(ValueLayout.JAVA_CHAR, str.length() + 1); + var segment = arena.allocateArray(ValueLayout.JAVA_CHAR, str.length() + 1L); // copy characters segment.copyFrom(MemorySegment.ofArray(str.toCharArray())); return segment; @@ -80,7 +82,7 @@ public static MemorySegment createSegmentFromString(String str, Arena arena) { * @return copied string */ public static String createStringFromSegment(MemorySegment segment) { - int len = 0; + var len = 0; while (segment.get(JAVA_CHAR, len) != 0) { len += 2; } @@ -100,7 +102,7 @@ public static String createStringFromSegment(MemorySegment segment) { */ public static List createStringListFromSegment(MemorySegment segment) { var stringList = new ArrayList(); - int offset = 0; + var offset = 0; while (segment.get(JAVA_CHAR, offset) != '\0') { var str = Win.createStringFromSegment(segment.asSlice(offset)); offset += str.length() * 2 + 2; @@ -125,21 +127,23 @@ public static List createStringListFromSegment(MemorySegment segment) { * @param data4_7 Byte 7 of group 4 * @return GUID as memory segment */ - public static MemorySegment CreateGUID(int data1, short data2, short data3, byte data4_0, byte data4_1, + @SuppressWarnings({"java:S117", "java:S107"}) + public static MemorySegment createGUID(int data1, short data2, short data3, byte data4_0, byte data4_1, byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7) { @SuppressWarnings("resource") - var guid = Arena.global().allocate(GUID.$LAYOUT()); + var guid = Arena.global().allocate(_GUID.$LAYOUT()); setGUID(guid, data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4, data4_5, data4_6, data4_7); return guid; } + @SuppressWarnings({"java:S117", "java:S107"}) public static void setGUID(MemorySegment guid, int data1, short data2, short data3, byte data4_0, byte data4_1, byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7) { - GUID.Data1$set(guid, data1); - GUID.Data2$set(guid, data2); - GUID.Data3$set(guid, data3); - var data4 = GUID.Data4$slice(guid); + _GUID.Data1$set(guid, data1); + _GUID.Data2$set(guid, data2); + _GUID.Data3$set(guid, data3); + var data4 = _GUID.Data4$slice(guid); data4.set(JAVA_BYTE, 0, data4_0); data4.set(JAVA_BYTE, 1, data4_1); data4.set(JAVA_BYTE, 2, data4_2); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java index b21d39d2..d708c62d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java @@ -8,7 +8,7 @@ package net.codecrete.usb.windows; import net.codecrete.usb.windows.gen.kernel32.Kernel32; -import net.codecrete.usb.windows.gen.kernel32.OVERLAPPED; +import net.codecrete.usb.windows.gen.kernel32._OVERLAPPED; import net.codecrete.usb.windows.winsdk.Kernel32B; import java.lang.foreign.Arena; @@ -37,20 +37,13 @@ * determines the number of allocated OVERLAPPED structs. *

*/ -public class WindowsAsyncTask { - - private static WindowsAsyncTask singletonInstance; +@SuppressWarnings("java:S6548") +class WindowsAsyncTask { /** * Singleton instance of background task. - * - * @return background task */ - static synchronized WindowsAsyncTask instance() { - if (singletonInstance == null) - singletonInstance = new WindowsAsyncTask(); - return singletonInstance; - } + static final WindowsAsyncTask INSTANCE = new WindowsAsyncTask(); // Currently outstanding transfer requests, // indexed by OVERLAPPED address. @@ -58,7 +51,7 @@ static synchronized WindowsAsyncTask instance() { // available OVERLAPPED data structures private List availableOverlappedStructs; // Arena used to allocate OVERLAPPED data structures - private Arena arena; + private Arena overlappedArena; /** * Windows completion port for asynchronous/overlapped IO @@ -81,7 +74,7 @@ private void asyncCompletionTask() { overlappedHolder.set(ADDRESS, 0, NULL); completionKeyHolder.set(JAVA_LONG, 0, 0); - int res = Kernel32B.GetQueuedCompletionStatus(asyncIoCompletionPort, numBytesHolder, + var res = Kernel32B.GetQueuedCompletionStatus(asyncIoCompletionPort, numBytesHolder, completionKeyHolder, overlappedHolder, Kernel32.INFINITE(), lastErrorState); var overlappedAddr = overlappedHolder.get(JAVA_LONG, 0); @@ -110,7 +103,7 @@ synchronized void addDevice(MemorySegment handle) { var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); // Creates a new port if it doesn't exist; adds handle to existing port if it exists - MemorySegment portHandle = Kernel32B.CreateIoCompletionPort(handle, asyncIoCompletionPort, + var portHandle = Kernel32B.CreateIoCompletionPort(handle, asyncIoCompletionPort, handle.address(), 0, lastErrorState); if (portHandle == MemorySegment.NULL) throwLastError(lastErrorState, "internal error (CreateIoCompletionPort)"); @@ -124,13 +117,13 @@ synchronized void addDevice(MemorySegment handle) { private void startAsyncIOTask() { availableOverlappedStructs = new ArrayList<>(); - arena = Arena.ofAuto(); + overlappedArena = Arena.ofAuto(); requestsByOverlapped = new HashMap<>(); // start background thread for handling IO completion - Thread t = new Thread(this::asyncCompletionTask, "USB async IO"); - t.setDaemon(true); - t.start(); + var thread = new Thread(this::asyncCompletionTask, "USB async IO"); + thread.setDaemon(true); + thread.start(); } /** @@ -140,9 +133,9 @@ private void startAsyncIOTask() { */ synchronized void prepareForSubmission(WindowsTransfer transfer) { MemorySegment overlapped; - int size = availableOverlappedStructs.size(); + var size = availableOverlappedStructs.size(); if (size == 0) { - overlapped = arena.allocate(OVERLAPPED.$LAYOUT()); + overlapped = overlappedArena.allocate(_OVERLAPPED.$LAYOUT()); } else { overlapped = availableOverlappedStructs.remove(size - 1); } @@ -162,8 +155,8 @@ private synchronized void completeTransfer(long overlappedAddr) { if (transfer == null) return; - transfer.setResultCode((int) OVERLAPPED.Internal$get(transfer.overlapped())); - transfer.setResultSize((int) OVERLAPPED.InternalHigh$get(transfer.overlapped())); + transfer.setResultCode((int) _OVERLAPPED.Internal$get(transfer.overlapped())); + transfer.setResultSize((int) _OVERLAPPED.InternalHigh$get(transfer.overlapped())); availableOverlappedStructs.add(transfer.overlapped()); transfer.setOverlapped(null); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index a8f61938..97e4f5a6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -33,6 +33,7 @@ /** * Windows implementation for USB device. */ +@SuppressWarnings("java:S2160") public class WindowsUSBDevice extends USBDeviceImpl { private final WindowsAsyncTask asyncTask; @@ -46,7 +47,7 @@ public class WindowsUSBDevice extends USBDeviceImpl { WindowsUSBDevice(String devicePath, Map children, int vendorId, int productId, MemorySegment configDesc) { super(devicePath, vendorId, productId); - asyncTask = WindowsAsyncTask.instance(); + asyncTask = WindowsAsyncTask.INSTANCE; readDescription(configDesc, devicePath, children); } @@ -125,7 +126,7 @@ public synchronized void claimInterface(int interfaceNumber) { Kernel32.FILE_SHARE_WRITE() | Kernel32.FILE_SHARE_READ(), NULL, Kernel32.OPEN_EXISTING(), Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), NULL, lastErrorState); - if (Win.IsInvalidHandle(deviceHandle)) + if (Win.isInvalidHandle(deviceHandle)) throwLastError(lastErrorState, "Cannot open USB device %s", firstIntfHandle.devicePath); asyncTask.addDevice(deviceHandle); @@ -210,7 +211,7 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { // copy data to native memory var transfer = createSyncControlTransfer(); - int dataLength = data != null ? data.length : 0; + var dataLength = data != null ? data.length : 0; transfer.setDataSize(dataLength); if (dataLength != 0) { var buffer = arena.allocate(data.length); @@ -318,7 +319,7 @@ synchronized void submitControlTransfer(USBDirection direction, USBControlTransf // submit transfer if (WinUSB2.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket.segment(), transfer.data(), transfer.dataSize(), NULL, transfer.overlapped(), lastErrorState) == 0) { - int err = Win.getLastError(lastErrorState); + var err = Win.getLastError(lastErrorState); if (err != Kernel32.ERROR_IO_PENDING()) throwException(err, "Submitting control transfer failed"); } @@ -336,7 +337,7 @@ synchronized void submitTransferOut(int endpointNumber, WindowsTransfer transfer // submit transfer if (WinUSB2.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), transfer.data(), transfer.dataSize(), NULL, transfer.overlapped(), lastErrorState) == 0) { - int err = Win.getLastError(lastErrorState); + var err = Win.getLastError(lastErrorState); if (err != Kernel32.ERROR_IO_PENDING()) throwException(err, "Submitting transfer OUT failed"); } @@ -354,7 +355,7 @@ synchronized void submitTransferIn(int endpointNumber, WindowsTransfer transfer) // submit transfer if (WinUSB2.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), transfer.data(), transfer.dataSize(), NULL, transfer.overlapped(), lastErrorState) == 0) { - int err = Win.getLastError(lastErrorState); + var err = Win.getLastError(lastErrorState); if (err != Kernel32.ERROR_IO_PENDING()) throwException(err, "Submitting transfer IN failed"); } @@ -432,7 +433,7 @@ private InterfaceHandle getInterfaceHandle(int interfaceNumber) { private InterfaceHandle findControlTransferInterface(USBControlTransfer setup) { - int interfaceNumber = -1; + var interfaceNumber = -1; int endpointNumber; if (setup.recipient() == USBRecipient.INTERFACE) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index ac6fcc6a..c0e32672 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -16,12 +16,8 @@ import net.codecrete.usb.usbstandard.DeviceDescriptor; import net.codecrete.usb.usbstandard.SetupPacket; import net.codecrete.usb.usbstandard.StringDescriptor; -import net.codecrete.usb.windows.gen.kernel32.GUID; import net.codecrete.usb.windows.gen.kernel32.Kernel32; -import net.codecrete.usb.windows.gen.ole32.Ole32; -import net.codecrete.usb.windows.gen.setupapi.SP_DEVICE_INTERFACE_DATA; -import net.codecrete.usb.windows.gen.setupapi.SP_DEVINFO_DATA; -import net.codecrete.usb.windows.gen.setupapi.SetupAPI; +import net.codecrete.usb.windows.gen.setupapi.*; import net.codecrete.usb.windows.gen.usbioctl.USBIoctl; import net.codecrete.usb.windows.gen.user32.*; import net.codecrete.usb.windows.winsdk.Kernel32B; @@ -76,11 +72,11 @@ protected void monitorDevices() { FunctionDescriptor.of(JAVA_LONG, ADDRESS, JAVA_INT, JAVA_LONG, JAVA_LONG), arena); // register window class - var wx = arena.allocate(WNDCLASSEXW.$LAYOUT()); - WNDCLASSEXW.cbSize$set(wx, (int) wx.byteSize()); - WNDCLASSEXW.lpfnWndProc$set(wx, handleWindowMessageStub); - WNDCLASSEXW.hInstance$set(wx, instance); - WNDCLASSEXW.lpszClassName$set(wx, className); + var wx = arena.allocate(tagWNDCLASSEXW.$LAYOUT()); + tagWNDCLASSEXW.cbSize$set(wx, (int) wx.byteSize()); + tagWNDCLASSEXW.lpfnWndProc$set(wx, handleWindowMessageStub); + tagWNDCLASSEXW.hInstance$set(wx, instance); + tagWNDCLASSEXW.lpszClassName$set(wx, className); var atom = User32B.RegisterClassExW(wx, lastErrorState); if (atom == 0) throwLastError(lastErrorState, "Internal error (RegisterClassExW)"); @@ -92,11 +88,11 @@ protected void monitorDevices() { throwLastError(lastErrorState, "Internal error (CreateWindowExW)"); // configure notifications - var notificationFilter = arena.allocate(DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); - DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$set(notificationFilter, (int) notificationFilter.byteSize()); - DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$set(notificationFilter, + var notificationFilter = arena.allocate(_DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); + _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$set(notificationFilter, (int) notificationFilter.byteSize()); + _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$set(notificationFilter, User32.DBT_DEVTYP_DEVICEINTERFACE()); - DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid$slice(notificationFilter).copyFrom(USBHelper.GUID_DEVINTERFACE_USB_DEVICE); + _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid$slice(notificationFilter).copyFrom(USBHelper.GUID_DEVINTERFACE_USB_DEVICE); var notifyHandle = User32B.RegisterDeviceNotificationW(hwnd, notificationFilter, User32.DEVICE_NOTIFY_WINDOW_HANDLE(), lastErrorState); @@ -106,13 +102,13 @@ protected void monitorDevices() { // initial device enumeration enumeratePresentDevices(); - } catch (Throwable e) { + } catch (Exception e) { enumerationFailed(e); return; } // process messages - var msg = arena.allocate(MSG.$LAYOUT()); + var msg = arena.allocate(tagMSG.$LAYOUT()); int err; //noinspection StatementWithEmptyBody while ((err = User32B.GetMessageW(msg, hwnd, 0, 0, lastErrorState)) > 0) @@ -123,6 +119,7 @@ protected void monitorDevices() { } } + @SuppressWarnings("java:S106") private void enumeratePresentDevices() { List deviceList = new ArrayList<>(); @@ -133,25 +130,25 @@ private void enumeratePresentDevices() { // get device information set of all USB devices present var devInfoSet = SetupAPI2.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), lastErrorState); - if (Win.IsInvalidHandle(devInfoSet)) + if (Win.isInvalidHandle(devInfoSet)) throwLastError(lastErrorState, "Internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left outerCleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); // allocate SP_DEVINFO_DATA (will receive details for each device) - var devInfoData = outerArena.allocate(SP_DEVINFO_DATA.$LAYOUT()); - SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) SP_DEVINFO_DATA.$LAYOUT().byteSize()); + var devInfoData = outerArena.allocate(_SP_DEVINFO_DATA.$LAYOUT()); + _SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) _SP_DEVINFO_DATA.$LAYOUT().byteSize()); // ensure all hubs are closed later final var hubHandles = new HashMap(); outerCleanup.add(() -> hubHandles.forEach((path, handle) -> Kernel32.CloseHandle(handle))); // iterate all devices - for (int i = 0; true; i++) { + for (var i = 0; true; i++) { if (SetupAPI2.SetupDiEnumDeviceInfo(devInfoSet, i, devInfoData, lastErrorState) == 0) { - int err = Win.getLastError(lastErrorState); + var err = Win.getLastError(lastErrorState); if (err == Kernel32.ERROR_NO_MORE_ITEMS()) break; throwLastError(lastErrorState, "Internal error (SetupDiEnumDeviceInfo)"); @@ -164,7 +161,7 @@ private void enumeratePresentDevices() { try { deviceList.add(createDeviceFromDeviceInfo(devInfoSet, devInfoData, devicePath, hubHandles)); - } catch (Throwable e) { + } catch (Exception e) { System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring " + "device%n", devicePath); e.printStackTrace(System.err); @@ -189,17 +186,18 @@ private Map enumerateChildren(List childrenIds) { for (var instanceId : childrenIds) { try (var arena = Arena.ofConfined(); var cleanup = new ScopeCleanup()) { + //noinspection DuplicatedCode var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); // create empty device info set var devInfoSet = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, lastErrorState); - if (Win.IsInvalidHandle(devInfoSet)) + if (Win.isInvalidHandle(devInfoSet)) throwLastError(lastErrorState, "Internal error (SetupDiCreateDeviceInfoList)"); cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); // get device info for child - var devInfoData = arena.allocate(SP_DEVINFO_DATA.$LAYOUT()); - SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) devInfoData.byteSize()); + var devInfoData = arena.allocate(_SP_DEVINFO_DATA.$LAYOUT()); + _SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) devInfoData.byteSize()); var instanceIdSegment = Win.createSegmentFromString(instanceId, arena); if (SetupAPI2.SetupDiOpenDeviceInfoW(devInfoSet, instanceIdSegment, NULL, 0, devInfoData, lastErrorState) == 0) @@ -210,33 +208,21 @@ private Map enumerateChildren(List childrenIds) { DeviceProperty.DEVPKEY_Device_HardwareIds); if (hardwareIds == null) throwException("DEVPKEY_Device_HardwareIds not found"); - int interfaceNumber = extractInterfaceNumber(hardwareIds); + var interfaceNumber = extractInterfaceNumber(hardwareIds); if (interfaceNumber == -1) continue; - var guids = DeviceProperty.findDeviceInterfaceGUIDs(devInfoSet, devInfoData, arena); + var devicePath = DeviceProperty.getDevicePathByGUID(devInfoSet, devInfoData, instanceId, arena); + if (devicePath != null) + children.put(interfaceNumber, devicePath); - for (var guid : guids) { - // check for Class GUID - var guidSegment = Win.createSegmentFromString(guid, arena); - var clsid = arena.allocate(GUID.$LAYOUT()); - if (Ole32.CLSIDFromString(guidSegment, clsid) != 0) - continue; - - try { - var devicePath = DeviceProperty.getDevicePath(instanceId, clsid); - children.put(interfaceNumber, devicePath); - break; - } catch (Exception e) { - // ignore and try next one - } - } } } return children; } + private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSet, MemorySegment devInfoData, String devicePath, HashMap hubHandles) { try (var arena = Arena.ofConfined()) { @@ -254,44 +240,49 @@ private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSet, MemorySeg var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); hubHandle = Kernel32B.CreateFileW(hubPathSeg, Kernel32.GENERIC_WRITE(), Kernel32.FILE_SHARE_WRITE(), NULL, Kernel32.OPEN_EXISTING(), 0, NULL, lastErrorState); - if (Win.IsInvalidHandle(hubHandle)) + if (Win.isInvalidHandle(hubHandle)) throwLastError(lastErrorState, "Cannot open USB hub"); hubHandles.put(hubPath, hubHandle); } // check for composite device - Map children = null; - if (DeviceProperty.isCompositeDevice(devInfoSet, devInfoData)) { - - // For certain devices, it seems to take some time until the "Device_Children" - // entry is present. So we retry a few times if needed and pause in between. - List childrenInstanceIDs; - int numTries = 5; - while (true) { - numTries -= 1; - childrenInstanceIDs = DeviceProperty.getDeviceStringListProperty(devInfoSet, devInfoData, - DeviceProperty.DEVPKEY_Device_Children); - if (childrenInstanceIDs != null || numTries == 0) - break; + var children = getChildDevices(devInfoSet, devInfoData, devicePath); - // sleep and retry - try { - //noinspection BusyWait - Thread.sleep(200); - } catch (InterruptedException e) { - // ignore - } - } + return createDevice(devicePath, children, hubHandle, usbPortNum); + } + } - if (childrenInstanceIDs == null) { - System.err.printf("Info: [JavaDoesUSB] cannot get device children of device %s%n", devicePath); - } else { - children = enumerateChildren(childrenInstanceIDs); - } + @SuppressWarnings({"java:S106", "java:S1168"}) + private Map getChildDevices(MemorySegment devInfoSet, MemorySegment devInfoData, String devicePath) { + if (!DeviceProperty.isCompositeDevice(devInfoSet, devInfoData)) + return null; + + // For certain devices, it seems to take some time until the "Device_Children" + // entry is present. So we retry a few times if needed and pause in between. + List childrenInstanceIDs; + var numTries = 5; + while (true) { + numTries -= 1; + childrenInstanceIDs = DeviceProperty.getDeviceStringListProperty(devInfoSet, devInfoData, + DeviceProperty.DEVPKEY_Device_Children); + if (childrenInstanceIDs != null || numTries == 0) + break; + + // sleep and retry + try { + //noinspection BusyWait + Thread.sleep(200); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); } + } - return createDevice(devicePath, children, hubHandle, usbPortNum); + if (childrenInstanceIDs == null) { + System.err.printf("Info: [JavaDoesUSB] cannot get device children of device %s%n", devicePath); + return null; } + + return enumerateChildren(childrenInstanceIDs); } /** @@ -321,14 +312,14 @@ private USBDevice createDevice(String devicePath, Map children, var descriptorSegment = USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(connInfo); var deviceDescriptor = new DeviceDescriptor(descriptorSegment); - int vendorId = deviceDescriptor.vendorID(); - int productId = deviceDescriptor.productID(); + var vendorId = deviceDescriptor.vendorID(); + var productId = deviceDescriptor.productID(); var configDesc = getDescriptor(hubHandle, usbPortNum, CONFIGURATION_DESCRIPTOR_TYPE, 0, (short) 0, arena); var device = new WindowsUSBDevice(devicePath, children, vendorId, productId, configDesc); device.setFromDeviceDescriptor(descriptorSegment); - device.setProductString(descriptorSegment, (index) -> getStringDescriptor(hubHandle, usbPortNum, index)); + device.setProductString(descriptorSegment, index -> getStringDescriptor(hubHandle, usbPortNum, index)); return device; } @@ -343,7 +334,7 @@ private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, int descriptorType, int index, short languageID, int requestSize, Arena arena) { - int size = requestSize != 0 ? requestSize + (int) USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset : 256; + var size = requestSize != 0 ? requestSize + (int) USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset : 256; // create descriptor requests var descriptorRequest = arena.allocate(size); @@ -387,6 +378,7 @@ private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, return descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, effectiveSize); } + @SuppressWarnings("java:S106") private String getStringDescriptor(MemorySegment hubHandle, int usbPortNumber, int index) { if (index == 0) return null; @@ -402,16 +394,17 @@ private String getStringDescriptor(MemorySegment hubHandle, int usbPortNumber, i } } + @SuppressWarnings("java:S1144") private long handleWindowMessage(MemorySegment hWnd, int uMsg, long wParam, long lParam) { // check for message related to connecting/disconnecting devices if (uMsg == User32.WM_DEVICECHANGE() && (wParam == User32.DBT_DEVICEARRIVAL() || wParam == User32.DBT_DEVICEREMOVECOMPLETE())) { - var data = MemorySegment.ofAddress(lParam).reinterpret(DEV_BROADCAST_DEVICEINTERFACE_W.sizeof()); - if (DEV_BROADCAST_HDR.dbch_devicetype$get(data) == User32.DBT_DEVTYP_DEVICEINTERFACE()) { + var data = MemorySegment.ofAddress(lParam).reinterpret(_DEV_BROADCAST_DEVICEINTERFACE_W.sizeof()); + if (_DEV_BROADCAST_HDR.dbch_devicetype$get(data) == User32.DBT_DEVTYP_DEVICEINTERFACE()) { // get device path var nameSlice = - MemorySegment.ofAddress(DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address()).reinterpret(500); + MemorySegment.ofAddress(_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address()).reinterpret(500); var devicePath = Win.createStringFromSegment(nameSlice); if (wParam == User32.DBT_DEVICEARRIVAL()) onDeviceConnected(devicePath); @@ -425,6 +418,7 @@ private long handleWindowMessage(MemorySegment hWnd, int uMsg, long wParam, long return User32.DefWindowProcW(hWnd, uMsg, wParam, lParam); } + @SuppressWarnings("java:S106") private void onDeviceConnected(String devicePath) { try (var arena = Arena.ofConfined(); var cleanup = new ScopeCleanup()) { @@ -432,25 +426,25 @@ private void onDeviceConnected(String devicePath) { // create empty device info set var devInfoSet = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, lastErrorState); - if (Win.IsInvalidHandle(devInfoSet)) + if (Win.isInvalidHandle(devInfoSet)) throwLastError(lastErrorState, "Internal error (SetupDiCreateDeviceInfoList)"); cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); // load device information into dev info set - var devIntfData = arena.allocate(SP_DEVICE_INTERFACE_DATA.$LAYOUT()); - SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); + var devIntfData = arena.allocate(_SP_DEVICE_INTERFACE_DATA.$LAYOUT()); + _SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); var devicePathSegment = Win.createSegmentFromString(devicePath, arena); if (SetupAPI2.SetupDiOpenDeviceInterfaceW(devInfoSet, devicePathSegment, 0, devIntfData, lastErrorState) == 0) throwLastError(lastErrorState, "Internal error (SetupDiOpenDeviceInterfaceW)"); cleanup.add(() -> SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSet, devIntfData)); - var devInfoData = arena.allocate(SP_DEVINFO_DATA.$LAYOUT()); - SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) devInfoData.byteSize()); + var devInfoData = arena.allocate(_SP_DEVINFO_DATA.$LAYOUT()); + _SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) devInfoData.byteSize()); if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSet, devIntfData, NULL, 0, NULL, devInfoData, lastErrorState) == 0) { - int err = Win.getLastError(lastErrorState); + var err = Win.getLastError(lastErrorState); if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) throwException(err, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); } @@ -466,7 +460,7 @@ private void onDeviceConnected(String devicePath) { // add it to device list addDevice(device); - } catch (Throwable e) { + } catch (Exception e) { System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring " + "device%n", devicePath); e.printStackTrace(System.err); @@ -492,7 +486,7 @@ private void onDeviceDisconnected(String devicePath) { @Override protected int findDeviceIndex(List deviceList, Object deviceId) { var id = deviceId.toString(); - for (int i = 0; i < deviceList.size(); i++) { + for (var i = 0; i < deviceList.size(); i++) { var dev = (USBDeviceImpl) deviceList.get(i); if (id.equalsIgnoreCase(dev.getUniqueId().toString())) return i; @@ -500,8 +494,8 @@ protected int findDeviceIndex(List deviceList, Object deviceId) { return -1; } - private static final Pattern MULTIPLE_INTERFACE_ID = Pattern.compile("USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4" + - "}&MI_([0-9A-Fa-f]{2})"); + private static final Pattern MULTIPLE_INTERFACE_ID = Pattern.compile( + "USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); private static int extractInterfaceNumber(List hardwareIds) { // Also see https://docs.microsoft.com/en-us/windows-hardware/drivers/install/standard-usb-identifiers#multiple-interface-usb-devices diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java index e7374066..b0bb3db7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java @@ -80,7 +80,7 @@ static void throwLastError(MemorySegment lastErrorState, String message, Object. throwException(Win.getLastError(lastErrorState), message, args); } - private static MemorySegment ntModule; + private static MemorySegment ntModule; // NOSONAR private static MemorySegment getNtModule() { if (ntModule == null) { @@ -98,7 +98,7 @@ static String getErrorMessage(int errorCode) { var messagePointerHolder = arena.allocate(ADDRESS); // First try: Win32 error code - int res = Kernel32.FormatMessageW( + var res = Kernel32.FormatMessageW( Kernel32.FORMAT_MESSAGE_ALLOCATE_BUFFER() | Kernel32.FORMAT_MESSAGE_FROM_SYSTEM() | Kernel32.FORMAT_MESSAGE_IGNORE_INSERTS(), NULL, errorCode, 0, messagePointerHolder, 0, NULL); @@ -113,8 +113,8 @@ static String getErrorMessage(int errorCode) { if (res == 0) return "unspecified error"; - var messagePointer = dereference(messagePointerHolder).reinterpret(128 * 1024); - String message = Win.createStringFromSegment(messagePointer); + var messagePointer = dereference(messagePointerHolder).reinterpret(128 * 1024); // NOSONAR + var message = Win.createStringFromSegment(messagePointer); Kernel32.LocalFree(messagePointer); return message.trim(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java index e78b17a1..4de451fa 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java @@ -23,12 +23,15 @@ * {@code GetLastError()} until jextract catches up and can generate the corresponding code. *

*/ -@SuppressWarnings("OptionalGetWithoutIsPresent") +@SuppressWarnings({"OptionalGetWithoutIsPresent", "java:S100", "java:S107", "java:S117"}) public class Kernel32B { static { System.loadLibrary("Kernel32"); } + private Kernel32B() { + } + private static final Linker LINKER = Linker.nativeLinker(); private static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup(); @@ -47,7 +50,7 @@ public static MemorySegment CreateFileW(MemorySegment lpFileName, int dwDesiredA return (MemorySegment) CreateFileW$MH.invokeExact(lastErrorState, lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -65,7 +68,7 @@ public static int DeviceIoControl(MemorySegment hDevice, int dwIoControlCode, Me return (int) DeviceIoControl$MH.invokeExact(lastErrorState, hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -83,7 +86,7 @@ public static int GetQueuedCompletionStatus(MemorySegment CompletionPort, return (int) GetQueuedCompletionStatus$MH.invokeExact(lastErrorState, CompletionPort, lpNumberOfBytesTransferred, lpCompletionKey, lpOverlapped, dwMilliseconds); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -99,7 +102,7 @@ public static MemorySegment CreateIoCompletionPort(MemorySegment FileHandle, Mem return (MemorySegment) CreateIoCompletionPort$MH.invokeExact(lastErrorState, FileHandle, ExistingCompletionPort, CompletionKey, NumberOfConcurrentThreads); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java index 75b2d1b3..ff9d15f8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java @@ -24,8 +24,10 @@ * {@code GetLastError()} until jextract catches up and can generate the corresponding code. *

*/ -@SuppressWarnings("OptionalGetWithoutIsPresent") +@SuppressWarnings({"OptionalGetWithoutIsPresent", "java:S100", "java:S107", "java:S117"}) public class SetupAPI2 { + private SetupAPI2() { + } static { System.loadLibrary("SetupAPI"); @@ -48,7 +50,7 @@ public static int SetupDiGetDevicePropertyW(MemorySegment DeviceInfoSet, MemoryS return (int) SetupDiGetDevicePropertyW$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, PropertyKey, PropertyType, PropertyBuffer, PropertyBufferSize, RequiredSize, Flags); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -64,7 +66,7 @@ public static int SetupDiEnumDeviceInfo(MemorySegment DeviceInfoSet, int MemberI return (int) SetupDiEnumDeviceInfo$MH.invokeExact(lastErrorState, DeviceInfoSet, MemberIndex, DeviceInfoData); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -81,7 +83,7 @@ public static MemorySegment SetupDiOpenDevRegKey(MemorySegment DeviceInfoSet, Me return (MemorySegment) SetupDiOpenDevRegKey$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, Scope, HwProfile, KeyType, samDesired); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -98,7 +100,7 @@ public static MemorySegment SetupDiGetClassDevsW(MemorySegment ClassGuid, Memory return (MemorySegment) SetupDiGetClassDevsW$MH.invokeExact(lastErrorState, ClassGuid, Enumerator, hwndParent, Flags); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -115,7 +117,7 @@ public static int SetupDiEnumDeviceInterfaces(MemorySegment DeviceInfoSet, Memor return (int) SetupDiEnumDeviceInterfaces$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, InterfaceClassGuid, MemberIndex, DeviceInterfaceData); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -133,7 +135,7 @@ public static int SetupDiGetDeviceInterfaceDetailW(MemorySegment DeviceInfoSet, DeviceInterfaceData, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -148,7 +150,7 @@ public static MemorySegment SetupDiCreateDeviceInfoList(MemorySegment ClassGuid, try { return (MemorySegment) SetupDiCreateDeviceInfoList$MH.invokeExact(lastErrorState, ClassGuid, hwndParent); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -165,7 +167,7 @@ public static int SetupDiOpenDeviceInfoW(MemorySegment DeviceInfoSet, MemorySegm return (int) SetupDiOpenDeviceInfoW$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -182,7 +184,7 @@ public static int SetupDiOpenDeviceInterfaceW(MemorySegment DeviceInfoSet, Memor return (int) SetupDiOpenDeviceInterfaceW$MH.invokeExact(lastErrorState, DeviceInfoSet, DevicePath, OpenFlags, DeviceInterfaceData); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java index 45381dc0..05caa2f2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java @@ -23,9 +23,12 @@ * {@code GetLastError()} until jextract catches up and can generate the corresponding code. *

*/ -@SuppressWarnings("OptionalGetWithoutIsPresent") +@SuppressWarnings({"OptionalGetWithoutIsPresent", "java:S100", "java:S107", "java:S117"}) public class User32B { + private User32B() { + } + static { System.loadLibrary("User32"); } @@ -42,7 +45,7 @@ public static short RegisterClassExW(MemorySegment unnamedParam1, MemorySegment try { return (short) RegisterClassExW$MH.invokeExact(lastErrorState, unnamedParam1); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -61,7 +64,7 @@ public static MemorySegment CreateWindowExW(int dwExStyle, MemorySegment lpClass return (MemorySegment) CreateWindowExW$MH.invokeExact(lastErrorState, dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -78,7 +81,7 @@ public static MemorySegment RegisterDeviceNotificationW(MemorySegment hRecipient return (MemorySegment) RegisterDeviceNotificationW$MH.invokeExact(lastErrorState, hRecipient, NotificationFilter, Flags); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -93,7 +96,7 @@ public static int GetMessageW(MemorySegment lpMsg, MemorySegment hWnd, int wMsgF try { return (int) GetMessageW$MH.invokeExact(lastErrorState, lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java index 47b7295f..57aab265 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java @@ -24,8 +24,11 @@ * {@code GetLastError()} until jextract catches up and can generate the corresponding code. *

*/ -@SuppressWarnings("OptionalGetWithoutIsPresent") +@SuppressWarnings({"OptionalGetWithoutIsPresent", "java:S100", "java:S107", "java:S117"}) public class WinUSB2 { + private WinUSB2() { + } + static { System.loadLibrary("Winusb"); } @@ -44,7 +47,7 @@ public static int WinUsb_Initialize(MemorySegment DeviceHandle, MemorySegment In try { return (int) WinUsb_Initialize$MH.invokeExact(lastErrorState, DeviceHandle, InterfaceHandle); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -60,7 +63,7 @@ public static int WinUsb_SetCurrentAlternateSetting(MemorySegment InterfaceHandl return (int) WinUsb_SetCurrentAlternateSetting$MH.invokeExact(lastErrorState, InterfaceHandle, SettingNumber); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -77,7 +80,7 @@ public static int WinUsb_ControlTransfer(MemorySegment InterfaceHandle, MemorySe return (int) WinUsb_ControlTransfer$MH.invokeExact(lastErrorState, InterfaceHandle, SetupPacket, Buffer, BufferLength, LengthTransferred, Overlapped); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -93,7 +96,7 @@ public static int WinUsb_SetPipePolicy(MemorySegment InterfaceHandle, byte PipeI return (int) WinUsb_SetPipePolicy$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID, PolicyType, ValueLength, Value); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -110,7 +113,7 @@ public static int WinUsb_WritePipe(MemorySegment InterfaceHandle, byte PipeID, M return (int) WinUsb_WritePipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID, Buffer, BufferLength, LengthTransferred, Overlapped); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -127,7 +130,7 @@ public static int WinUsb_ReadPipe(MemorySegment InterfaceHandle, byte PipeID, Me return (int) WinUsb_ReadPipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID, Buffer, BufferLength , LengthTransferred, Overlapped); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -140,7 +143,7 @@ public static int WinUsb_ResetPipe(MemorySegment InterfaceHandle, byte PipeID, M try { return (int) WinUsb_ResetPipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } @@ -153,7 +156,7 @@ public static int WinUsb_AbortPipe(MemorySegment InterfaceHandle, byte PipeID, M try { return (int) WinUsb_AbortPipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID); } catch (Throwable ex) { - throw new RuntimeException(ex); + throw new AssertionError(ex); } } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java index d13d4a6a..5238954a 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java @@ -15,7 +15,7 @@ import static org.junit.jupiter.api.Assertions.*; -public class AlternateInterfaceTest extends TestDeviceBase { +class AlternateInterfaceTest extends TestDeviceBase { @BeforeAll static void precondition() { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java index cf68679c..39333b78 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java @@ -17,7 +17,7 @@ import static org.junit.jupiter.api.Assertions.*; -public class BulkTransferTest extends TestDeviceBase { +class BulkTransferTest extends TestDeviceBase { @Test void smallTransfer_succeeds() { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java index b0d2840f..f355a044 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java @@ -16,7 +16,7 @@ /** * Tests control transfers */ -public class ControlTransferTest extends TestDeviceBase { +class ControlTransferTest extends TestDeviceBase { @Test void storeValue_succeeds() { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index 2393d69a..07d06126 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -16,7 +16,7 @@ /** * Tests the interface, alternate settings and endpoint descriptions. */ -public class DescriptionTest extends TestDeviceBase { +class DescriptionTest extends TestDeviceBase { @Test void deviceInfo_isCorrect() { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java index d53a8c3c..7ce074cc 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java @@ -14,7 +14,7 @@ import static org.junit.jupiter.api.Assertions.*; -public class DeviceLifecycleTest { +class DeviceLifecycleTest { private USBDevice device; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java index d91d20e9..384a379e 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java @@ -14,7 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; -public class InterruptTransferTest extends TestDeviceBase { +class InterruptTransferTest extends TestDeviceBase { @Test void smallTransfer_succeeds() { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java index 41e3c1e5..4ee735cd 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java @@ -12,7 +12,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -public class InvalidOperationTest extends TestDeviceBase { +class InvalidOperationTest extends TestDeviceBase { @Test void claimInvalidInterface_throws() { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java index cb869346..612df1ff 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java @@ -16,7 +16,7 @@ import static org.junit.jupiter.api.Assertions.*; -public class SpeedTest extends TestDeviceBase { +class SpeedTest extends TestDeviceBase { @Test void loopback_isFast() throws Throwable { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java index 11620938..4f8411ae 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java @@ -14,7 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -public class StallTest extends TestDeviceBase { +class StallTest extends TestDeviceBase { @Test void stalledBulkTransferOut_recovers() { @@ -46,9 +46,9 @@ void stalledBulkTransferIn_recovers() { @Test void invalidControlTransfer_throws() { - assertThrows(USBStallException.class, () -> testDevice.controlTransferIn( - new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x08, - (short) 0, (short) interfaceNumber), 2)); + var request = new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x08, + (short) 0, (short) interfaceNumber); + assertThrows(USBStallException.class, () -> testDevice.controlTransferIn(request, 2)); } void haltEndpoint(USBDirection direction, int endpointNumber) { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java index 665d365f..197a81d5 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java @@ -18,7 +18,7 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -public class StreamTest extends TestDeviceBase { +class StreamTest extends TestDeviceBase { @Test void smallTransfer_succeeds() { @@ -108,7 +108,7 @@ private static void sleep(int millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { - throw new RuntimeException(e); + Thread.currentThread().interrupt(); } } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java index 436d0f47..5fe0cf8a 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java @@ -18,7 +18,7 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -public class TimeoutTest extends TestDeviceBase { +class TimeoutTest extends TestDeviceBase { @Test @Timeout(value = 1, unit = TimeUnit.SECONDS) diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java index 9f3f5caa..198ef74a 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java @@ -264,7 +264,7 @@ private static void sleep(long millis) { Thread.sleep(millis); } catch (InterruptedException e) { - // ignore + Thread.currentThread().interrupt(); } } } From 670cb8280aeae717616656476c330f908713c309 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 29 Jul 2023 15:15:58 +0200 Subject: [PATCH 256/433] Windows: use more generated code --- java-does-usb/jextract/windows/gen_win.cmd | 4 + .../codecrete/usb/windows/USBConstants.java | 32 +++ .../net/codecrete/usb/windows/USBHelper.java | 103 -------- .../usb/windows/WindowsUSBDeviceRegistry.java | 41 ++-- .../gen/usbioctl/USB_DESCRIPTOR_REQUEST.java | 16 ++ .../USB_NODE_CONNECTION_INFORMATION_EX.java | 16 ++ .../gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java | 223 +++++++++++++++++ .../_USB_NODE_CONNECTION_INFORMATION_EX.java | 230 ++++++++++++++++++ .../usb/windows/gen/usbioctl/constants$0.java | 27 ++ .../usb/windows/gen/usbioctl/constants$1.java | 57 +++++ .../usb/windows/gen/usbioctl/constants$2.java | 17 ++ 11 files changed, 644 insertions(+), 122 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/USBConstants.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USB_DESCRIPTOR_REQUEST.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USB_NODE_CONNECTION_INFORMATION_EX.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$1.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$2.java diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index e1679449..a4084d2c 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -69,6 +69,10 @@ call %JEXTRACT% --source --output ../../src/main/java ^ -I "%SDK_DIR%\shared" ^ --header-class-name USBIoctl ^ --target-package net.codecrete.usb.windows.gen.usbioctl ^ + --include-struct _USB_NODE_CONNECTION_INFORMATION_EX ^ + --include-typedef USB_NODE_CONNECTION_INFORMATION_EX ^ + --include-struct _USB_DESCRIPTOR_REQUEST ^ + --include-typedef USB_DESCRIPTOR_REQUEST ^ --include-constant IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX ^ --include-constant IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION ^ windows_headers.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBConstants.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBConstants.java new file mode 100644 index 00000000..c4e18577 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBConstants.java @@ -0,0 +1,32 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.windows; + +import java.lang.foreign.MemorySegment; + +/** + * USB constants (general ones and Windows specific ones) + */ +@SuppressWarnings({"java:S125", "java:S1192", "java:S115", "java:S100"}) +class USBConstants { + + private USBConstants() { + } + + static final byte USB_REQUEST_GET_DESCRIPTOR = 0x06; + + // A5DCBF10-6530-11D2-901F-00C04FB951ED + static final MemorySegment GUID_DEVINTERFACE_USB_DEVICE = Win.createGUID(0xA5DCBF10, (short) 0x6530, + (short) 0x11D2, (byte) 0x90, (byte) 0x1F, (byte) 0x00, (byte) 0xC0, (byte) 0x4F, (byte) 0xB9, (byte) 0x51 + , (byte) 0xED); + + // f18a0e88-c30c-11d0-8815-00a0c906bed8 + static final MemorySegment GUID_DEVINTERFACE_USB_HUB = Win.createGUID(0xf18a0e88, (short) 0xc30c, + (short) 0x11d0, (byte) 0x88, (byte) 0x15, (byte) 0x00, (byte) 0xa0, (byte) 0xc9, (byte) 0x06, (byte) 0xbe + , (byte) 0xd8); +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java deleted file mode 100644 index f960ffb7..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBHelper.java +++ /dev/null @@ -1,103 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.windows; - -import net.codecrete.usb.usbstandard.DeviceDescriptor; -import net.codecrete.usb.usbstandard.SetupPacket; - -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.*; - -/** - * USB constants and struct - *

- * Mainly used to work around an alignment problem with the generated - * USB_NODE_CONNECTION_INFORMATION_EX struct. - *

- */ -@SuppressWarnings({"java:S125", "java:S1192", "java:S115", "java:S100"}) -class USBHelper { - - private USBHelper() { - } - - static final byte USB_REQUEST_GET_DESCRIPTOR = 0x06; - - // typedef struct _USB_NODE_CONNECTION_INFORMATION_EX { - // ULONG ConnectionIndex; /* INPUT */ - // /* usb device descriptor returned by this device - // during enumeration */ - // USB_DEVICE_DESCRIPTOR DeviceDescriptor;/* OUTPUT */ - // UCHAR CurrentConfigurationValue;/* OUTPUT */ - // /* values for the speed field are defined in USB200.h */ - // UCHAR Speed;/* OUTPUT */ - // BOOLEAN DeviceIsHub;/* OUTPUT */ - // USHORT DeviceAddress;/* OUTPUT */ - // ULONG NumberOfOpenPipes;/* OUTPUT */ - // USB_CONNECTION_STATUS ConnectionStatus;/* OUTPUT */ - // USB_PIPE_INFO PipeList[0];/* OUTPUT */ - //} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; - static final GroupLayout USB_NODE_CONNECTION_INFORMATION_EX$Struct = MemoryLayout.structLayout( - JAVA_INT.withName("ConnectionIndex"), - DeviceDescriptor.LAYOUT.withName("DeviceDescriptor"), - JAVA_BYTE.withName("CurrentConfigurationValue"), - JAVA_BYTE.withName("Speed"), - JAVA_BYTE.withName("DeviceIsHub"), - JAVA_SHORT_UNALIGNED.withName("DeviceAddress"), - JAVA_INT_UNALIGNED.withName("NumberOfOpenPipes"), - JAVA_INT_UNALIGNED.withName("ConnectionStatus") - // USB_PIPE_INFO PipeList[0] - ); - static final VarHandle USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex = - USB_NODE_CONNECTION_INFORMATION_EX$Struct.varHandle(groupElement("ConnectionIndex")); - static final long USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset = - USB_NODE_CONNECTION_INFORMATION_EX$Struct.byteOffset(groupElement("DeviceDescriptor")); - - static MemorySegment USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(MemorySegment seg) { - return seg.asSlice(USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$Offset, - DeviceDescriptor.LAYOUT.byteSize()); - } - - // typedef struct _USB_DESCRIPTOR_REQUEST { - // ULONG ConnectionIndex; - // struct { - // UCHAR bmRequest; - // UCHAR bRequest; - // USHORT wValue; - // USHORT wIndex; - // USHORT wLength; - // } SetupPacket; - // UCHAR Data[0]; - //} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST; - static final GroupLayout USB_DESCRIPTOR_REQUEST$Struct = MemoryLayout.structLayout(JAVA_INT.withName( - "ConnectionIndex"), SetupPacket.LAYOUT.withName("SetupPacket")); - static final VarHandle USB_DESCRIPTOR_REQUEST_ConnectionIndex = - USB_DESCRIPTOR_REQUEST$Struct.varHandle(groupElement("ConnectionIndex")); - static final long USB_DESCRIPTOR_REQUEST_SetupPacket$Offset = - USB_DESCRIPTOR_REQUEST$Struct.byteOffset(groupElement("SetupPacket")); - static final long USB_DESCRIPTOR_REQUEST_Data$Offset = USB_DESCRIPTOR_REQUEST$Struct.byteSize(); - - // A5DCBF10-6530-11D2-901F-00C04FB951ED - static final MemorySegment GUID_DEVINTERFACE_USB_DEVICE = Win.createGUID(0xA5DCBF10, (short) 0x6530, - (short) 0x11D2, (byte) 0x90, (byte) 0x1F, (byte) 0x00, (byte) 0xC0, (byte) 0x4F, (byte) 0xB9, (byte) 0x51 - , (byte) 0xED); - - // f18a0e88-c30c-11d0-8815-00a0c906bed8 - static final MemorySegment GUID_DEVINTERFACE_USB_HUB = Win.createGUID(0xf18a0e88, (short) 0xc30c, - (short) 0x11d0, (byte) 0x88, (byte) 0x15, (byte) 0x00, (byte) 0xa0, (byte) 0xc9, (byte) 0x06, (byte) 0xbe - , (byte) 0xd8); - - static { - assert USB_NODE_CONNECTION_INFORMATION_EX$Struct.byteSize() == 35; - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index c0e32672..862629e9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -19,6 +19,8 @@ import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.setupapi.*; import net.codecrete.usb.windows.gen.usbioctl.USBIoctl; +import net.codecrete.usb.windows.gen.usbioctl._USB_DESCRIPTOR_REQUEST; +import net.codecrete.usb.windows.gen.usbioctl._USB_NODE_CONNECTION_INFORMATION_EX; import net.codecrete.usb.windows.gen.user32.*; import net.codecrete.usb.windows.winsdk.Kernel32B; import net.codecrete.usb.windows.winsdk.SetupAPI2; @@ -52,6 +54,9 @@ */ public class WindowsUSBDeviceRegistry extends USBDeviceRegistry { + private static final long REQUEST_DATA_OFFSET + = _USB_DESCRIPTOR_REQUEST.$LAYOUT().byteOffset(PathElement.groupElement("Data")); + @Override protected void monitorDevices() { try (var arena = Arena.ofConfined()) { @@ -92,7 +97,7 @@ protected void monitorDevices() { _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$set(notificationFilter, (int) notificationFilter.byteSize()); _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$set(notificationFilter, User32.DBT_DEVTYP_DEVICEINTERFACE()); - _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid$slice(notificationFilter).copyFrom(USBHelper.GUID_DEVINTERFACE_USB_DEVICE); + _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid$slice(notificationFilter).copyFrom(USBConstants.GUID_DEVINTERFACE_USB_DEVICE); var notifyHandle = User32B.RegisterDeviceNotificationW(hwnd, notificationFilter, User32.DEVICE_NOTIFY_WINDOW_HANDLE(), lastErrorState); @@ -128,7 +133,7 @@ private void enumeratePresentDevices() { var lastErrorState = outerArena.allocate(Win.LAST_ERROR_STATE_LAYOUT); // get device information set of all USB devices present - var devInfoSet = SetupAPI2.SetupDiGetClassDevsW(USBHelper.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, + var devInfoSet = SetupAPI2.SetupDiGetClassDevsW(USBConstants.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), lastErrorState); if (Win.isInvalidHandle(devInfoSet)) throwLastError(lastErrorState, "Internal error (SetupDiGetClassDevsW)"); @@ -156,7 +161,7 @@ private void enumeratePresentDevices() { var instanceId = DeviceProperty.getDeviceStringProperty(devInfoSet, devInfoData, DeviceProperty.DEVPKEY_Device_InstanceId); - var devicePath = DeviceProperty.getDevicePath(instanceId, USBHelper.GUID_DEVINTERFACE_USB_DEVICE); + var devicePath = DeviceProperty.getDevicePath(instanceId, USBConstants.GUID_DEVINTERFACE_USB_DEVICE); try { deviceList.add(createDeviceFromDeviceInfo(devInfoSet, devInfoData, devicePath, hubHandles)); @@ -231,7 +236,7 @@ private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSet, MemorySeg DeviceProperty.DEVPKEY_Device_Address); var parentInstanceId = DeviceProperty.getDeviceStringProperty(devInfoSet, devInfoData, DeviceProperty.DEVPKEY_Device_Parent); - var hubPath = DeviceProperty.getDevicePath(parentInstanceId, USBHelper.GUID_DEVINTERFACE_USB_HUB); + var hubPath = DeviceProperty.getDevicePath(parentInstanceId, USBConstants.GUID_DEVINTERFACE_USB_HUB); // open hub if not open yet var hubHandle = hubHandles.get(hubPath); @@ -300,8 +305,8 @@ private USBDevice createDevice(String devicePath, Map children, try (var arena = Arena.ofConfined()) { // get device descriptor - var connInfo = arena.allocate(USBHelper.USB_NODE_CONNECTION_INFORMATION_EX$Struct); - USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_ConnectionIndex.set(connInfo, usbPortNum); + var connInfo = _USB_NODE_CONNECTION_INFORMATION_EX.allocate(arena); + _USB_NODE_CONNECTION_INFORMATION_EX.ConnectionIndex$set(connInfo, usbPortNum); var sizeHolder = arena.allocate(JAVA_INT); var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); if (Kernel32B.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), @@ -309,7 +314,7 @@ private USBDevice createDevice(String devicePath, Map children, lastErrorState) == 0) throwLastError(lastErrorState, "Internal error (cannot get device descriptor)"); - var descriptorSegment = USBHelper.USB_NODE_CONNECTION_INFORMATION_EX_DeviceDescriptor$slice(connInfo); + var descriptorSegment = _USB_NODE_CONNECTION_INFORMATION_EX.DeviceDescriptor$slice(connInfo); var deviceDescriptor = new DeviceDescriptor(descriptorSegment); var vendorId = deviceDescriptor.vendorID(); @@ -333,20 +338,17 @@ private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, int descriptorType, int index, short languageID, int requestSize, Arena arena) { - - var size = requestSize != 0 ? requestSize + (int) USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset : 256; + var size = requestSize != 0 ? requestSize + (int) REQUEST_DATA_OFFSET : 256; // create descriptor requests var descriptorRequest = arena.allocate(size); - USBHelper.USB_DESCRIPTOR_REQUEST_ConnectionIndex.set(descriptorRequest, usbPortNumber); - var setupPacket = - new SetupPacket(descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_SetupPacket$Offset, - SetupPacket.LAYOUT.byteSize())); + _USB_DESCRIPTOR_REQUEST.ConnectionIndex$set(descriptorRequest, usbPortNumber); + var setupPacket = new SetupPacket(_USB_DESCRIPTOR_REQUEST.SetupPacket$slice(descriptorRequest)); setupPacket.setRequestType(0x80); // device-to-host / type standard / recipient device - setupPacket.setRequest(USBHelper.USB_REQUEST_GET_DESCRIPTOR); + setupPacket.setRequest(USBConstants.USB_REQUEST_GET_DESCRIPTOR); setupPacket.setValue((descriptorType << 8) | index); setupPacket.setIndex(languageID); - setupPacket.setLength(size - (int) USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset); + setupPacket.setLength(size - (int) REQUEST_DATA_OFFSET); // execute request var effectiveSizeHolder = arena.allocate(JAVA_INT); @@ -358,15 +360,15 @@ private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, // determine size of descriptor int expectedSize; if (descriptorType != CONFIGURATION_DESCRIPTOR_TYPE) { - expectedSize = 255 & descriptorRequest.get(JAVA_BYTE, USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset); + expectedSize = 255 & descriptorRequest.get(JAVA_BYTE, REQUEST_DATA_OFFSET); } else { var configDesc = - new ConfigurationDescriptor(descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, ConfigurationDescriptor.LAYOUT.byteSize())); + new ConfigurationDescriptor(descriptorRequest.asSlice(REQUEST_DATA_OFFSET, ConfigurationDescriptor.LAYOUT.byteSize())); expectedSize = configDesc.totalLength(); } // check against effective size - var effectiveSize = effectiveSizeHolder.get(JAVA_INT, 0) - USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset; + var effectiveSize = effectiveSizeHolder.get(JAVA_INT, 0) - REQUEST_DATA_OFFSET; if (effectiveSize != expectedSize) { if (requestSize != 0) throwException("Unexpected descriptor size"); @@ -375,7 +377,7 @@ private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, return getDescriptor(hubHandle, usbPortNumber, descriptorType, index, languageID, expectedSize, arena); } - return descriptorRequest.asSlice(USBHelper.USB_DESCRIPTOR_REQUEST_Data$Offset, effectiveSize); + return descriptorRequest.asSlice(REQUEST_DATA_OFFSET, effectiveSize); } @SuppressWarnings("java:S106") @@ -387,6 +389,7 @@ private String getStringDescriptor(MemorySegment hubHandle, int usbPortNumber, i var stringDesc = new StringDescriptor(getDescriptor(hubHandle, usbPortNumber, STRING_DESCRIPTOR_TYPE, index, DEFAULT_LANGUAGE, arena)); return stringDesc.string(); + } catch (USBException e) { System.err.printf("Info: [JavaDoesUSB] failed to retrieve string descriptor %d (%s) - ignoring%n", index, e.getMessage()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USB_DESCRIPTOR_REQUEST.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USB_DESCRIPTOR_REQUEST.java new file mode 100644 index 00000000..6a5de025 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USB_DESCRIPTOR_REQUEST.java @@ -0,0 +1,16 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.usbioctl; + +/** + * {@snippet : + * typedef struct _USB_DESCRIPTOR_REQUEST USB_DESCRIPTOR_REQUEST; + * } + */ +public final class USB_DESCRIPTOR_REQUEST extends _USB_DESCRIPTOR_REQUEST { + + // Suppresses default constructor, ensuring non-instantiability. + private USB_DESCRIPTOR_REQUEST() {} +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USB_NODE_CONNECTION_INFORMATION_EX.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USB_NODE_CONNECTION_INFORMATION_EX.java new file mode 100644 index 00000000..9750d300 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USB_NODE_CONNECTION_INFORMATION_EX.java @@ -0,0 +1,16 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.usbioctl; + +/** + * {@snippet : + * typedef struct _USB_NODE_CONNECTION_INFORMATION_EX USB_NODE_CONNECTION_INFORMATION_EX; + * } + */ +public final class USB_NODE_CONNECTION_INFORMATION_EX extends _USB_NODE_CONNECTION_INFORMATION_EX { + + // Suppresses default constructor, ensuring non-instantiability. + private USB_NODE_CONNECTION_INFORMATION_EX() {} +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java new file mode 100644 index 00000000..38d3f92f --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java @@ -0,0 +1,223 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.usbioctl; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct _USB_DESCRIPTOR_REQUEST { + * ULONG ConnectionIndex; + * struct SetupPacket; + * UCHAR Data[0]; + * }; + * } + */ +public class _USB_DESCRIPTOR_REQUEST { + + public static MemoryLayout $LAYOUT() { + return constants$0.const$0; + } + public static VarHandle ConnectionIndex$VH() { + return constants$0.const$1; + } + /** + * Getter for field: + * {@snippet : + * ULONG ConnectionIndex; + * } + */ + public static int ConnectionIndex$get(MemorySegment seg) { + return (int)constants$0.const$1.get(seg); + } + /** + * Setter for field: + * {@snippet : + * ULONG ConnectionIndex; + * } + */ + public static void ConnectionIndex$set(MemorySegment seg, int x) { + constants$0.const$1.set(seg, x); + } + public static int ConnectionIndex$get(MemorySegment seg, long index) { + return (int)constants$0.const$1.get(seg.asSlice(index*sizeof())); + } + public static void ConnectionIndex$set(MemorySegment seg, long index, int x) { + constants$0.const$1.set(seg.asSlice(index*sizeof()), x); + } + /** + * {@snippet : + * struct { + * UCHAR bmRequest; + * UCHAR bRequest; + * USHORT wValue; + * USHORT wIndex; + * USHORT wLength; + * }; + * } + */ + public static final class SetupPacket { + + // Suppresses default constructor, ensuring non-instantiability. + private SetupPacket() {} + public static MemoryLayout $LAYOUT() { + return constants$0.const$2; + } + public static VarHandle bmRequest$VH() { + return constants$0.const$3; + } + /** + * Getter for field: + * {@snippet : + * UCHAR bmRequest; + * } + */ + public static byte bmRequest$get(MemorySegment seg) { + return (byte)constants$0.const$3.get(seg); + } + /** + * Setter for field: + * {@snippet : + * UCHAR bmRequest; + * } + */ + public static void bmRequest$set(MemorySegment seg, byte x) { + constants$0.const$3.set(seg, x); + } + public static byte bmRequest$get(MemorySegment seg, long index) { + return (byte)constants$0.const$3.get(seg.asSlice(index*sizeof())); + } + public static void bmRequest$set(MemorySegment seg, long index, byte x) { + constants$0.const$3.set(seg.asSlice(index*sizeof()), x); + } + public static VarHandle bRequest$VH() { + return constants$0.const$4; + } + /** + * Getter for field: + * {@snippet : + * UCHAR bRequest; + * } + */ + public static byte bRequest$get(MemorySegment seg) { + return (byte)constants$0.const$4.get(seg); + } + /** + * Setter for field: + * {@snippet : + * UCHAR bRequest; + * } + */ + public static void bRequest$set(MemorySegment seg, byte x) { + constants$0.const$4.set(seg, x); + } + public static byte bRequest$get(MemorySegment seg, long index) { + return (byte)constants$0.const$4.get(seg.asSlice(index*sizeof())); + } + public static void bRequest$set(MemorySegment seg, long index, byte x) { + constants$0.const$4.set(seg.asSlice(index*sizeof()), x); + } + public static VarHandle wValue$VH() { + return constants$0.const$5; + } + /** + * Getter for field: + * {@snippet : + * USHORT wValue; + * } + */ + public static short wValue$get(MemorySegment seg) { + return (short)constants$0.const$5.get(seg); + } + /** + * Setter for field: + * {@snippet : + * USHORT wValue; + * } + */ + public static void wValue$set(MemorySegment seg, short x) { + constants$0.const$5.set(seg, x); + } + public static short wValue$get(MemorySegment seg, long index) { + return (short)constants$0.const$5.get(seg.asSlice(index*sizeof())); + } + public static void wValue$set(MemorySegment seg, long index, short x) { + constants$0.const$5.set(seg.asSlice(index*sizeof()), x); + } + public static VarHandle wIndex$VH() { + return constants$1.const$0; + } + /** + * Getter for field: + * {@snippet : + * USHORT wIndex; + * } + */ + public static short wIndex$get(MemorySegment seg) { + return (short)constants$1.const$0.get(seg); + } + /** + * Setter for field: + * {@snippet : + * USHORT wIndex; + * } + */ + public static void wIndex$set(MemorySegment seg, short x) { + constants$1.const$0.set(seg, x); + } + public static short wIndex$get(MemorySegment seg, long index) { + return (short)constants$1.const$0.get(seg.asSlice(index*sizeof())); + } + public static void wIndex$set(MemorySegment seg, long index, short x) { + constants$1.const$0.set(seg.asSlice(index*sizeof()), x); + } + public static VarHandle wLength$VH() { + return constants$1.const$1; + } + /** + * Getter for field: + * {@snippet : + * USHORT wLength; + * } + */ + public static short wLength$get(MemorySegment seg) { + return (short)constants$1.const$1.get(seg); + } + /** + * Setter for field: + * {@snippet : + * USHORT wLength; + * } + */ + public static void wLength$set(MemorySegment seg, short x) { + constants$1.const$1.set(seg, x); + } + public static short wLength$get(MemorySegment seg, long index) { + return (short)constants$1.const$1.get(seg.asSlice(index*sizeof())); + } + public static void wLength$set(MemorySegment seg, long index, short x) { + constants$1.const$1.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } + } + + public static MemorySegment SetupPacket$slice(MemorySegment seg) { + return seg.asSlice(4, 8); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java new file mode 100644 index 00000000..4527cdee --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java @@ -0,0 +1,230 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.usbioctl; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct _USB_NODE_CONNECTION_INFORMATION_EX { + * ULONG ConnectionIndex; + * USB_DEVICE_DESCRIPTOR DeviceDescriptor; + * UCHAR CurrentConfigurationValue; + * UCHAR Speed; + * BOOLEAN DeviceIsHub; + * USHORT DeviceAddress; + * ULONG NumberOfOpenPipes; + * USB_CONNECTION_STATUS ConnectionStatus; + * USB_PIPE_INFO PipeList[0]; + * }; + * } + */ +public class _USB_NODE_CONNECTION_INFORMATION_EX { + + public static MemoryLayout $LAYOUT() { + return constants$1.const$2; + } + public static VarHandle ConnectionIndex$VH() { + return constants$1.const$3; + } + /** + * Getter for field: + * {@snippet : + * ULONG ConnectionIndex; + * } + */ + public static int ConnectionIndex$get(MemorySegment seg) { + return (int)constants$1.const$3.get(seg); + } + /** + * Setter for field: + * {@snippet : + * ULONG ConnectionIndex; + * } + */ + public static void ConnectionIndex$set(MemorySegment seg, int x) { + constants$1.const$3.set(seg, x); + } + public static int ConnectionIndex$get(MemorySegment seg, long index) { + return (int)constants$1.const$3.get(seg.asSlice(index*sizeof())); + } + public static void ConnectionIndex$set(MemorySegment seg, long index, int x) { + constants$1.const$3.set(seg.asSlice(index*sizeof()), x); + } + public static MemorySegment DeviceDescriptor$slice(MemorySegment seg) { + return seg.asSlice(4, 18); + } + public static VarHandle CurrentConfigurationValue$VH() { + return constants$1.const$4; + } + /** + * Getter for field: + * {@snippet : + * UCHAR CurrentConfigurationValue; + * } + */ + public static byte CurrentConfigurationValue$get(MemorySegment seg) { + return (byte)constants$1.const$4.get(seg); + } + /** + * Setter for field: + * {@snippet : + * UCHAR CurrentConfigurationValue; + * } + */ + public static void CurrentConfigurationValue$set(MemorySegment seg, byte x) { + constants$1.const$4.set(seg, x); + } + public static byte CurrentConfigurationValue$get(MemorySegment seg, long index) { + return (byte)constants$1.const$4.get(seg.asSlice(index*sizeof())); + } + public static void CurrentConfigurationValue$set(MemorySegment seg, long index, byte x) { + constants$1.const$4.set(seg.asSlice(index*sizeof()), x); + } + public static VarHandle Speed$VH() { + return constants$1.const$5; + } + /** + * Getter for field: + * {@snippet : + * UCHAR Speed; + * } + */ + public static byte Speed$get(MemorySegment seg) { + return (byte)constants$1.const$5.get(seg); + } + /** + * Setter for field: + * {@snippet : + * UCHAR Speed; + * } + */ + public static void Speed$set(MemorySegment seg, byte x) { + constants$1.const$5.set(seg, x); + } + public static byte Speed$get(MemorySegment seg, long index) { + return (byte)constants$1.const$5.get(seg.asSlice(index*sizeof())); + } + public static void Speed$set(MemorySegment seg, long index, byte x) { + constants$1.const$5.set(seg.asSlice(index*sizeof()), x); + } + public static VarHandle DeviceIsHub$VH() { + return constants$2.const$0; + } + /** + * Getter for field: + * {@snippet : + * BOOLEAN DeviceIsHub; + * } + */ + public static byte DeviceIsHub$get(MemorySegment seg) { + return (byte)constants$2.const$0.get(seg); + } + /** + * Setter for field: + * {@snippet : + * BOOLEAN DeviceIsHub; + * } + */ + public static void DeviceIsHub$set(MemorySegment seg, byte x) { + constants$2.const$0.set(seg, x); + } + public static byte DeviceIsHub$get(MemorySegment seg, long index) { + return (byte)constants$2.const$0.get(seg.asSlice(index*sizeof())); + } + public static void DeviceIsHub$set(MemorySegment seg, long index, byte x) { + constants$2.const$0.set(seg.asSlice(index*sizeof()), x); + } + public static VarHandle DeviceAddress$VH() { + return constants$2.const$1; + } + /** + * Getter for field: + * {@snippet : + * USHORT DeviceAddress; + * } + */ + public static short DeviceAddress$get(MemorySegment seg) { + return (short)constants$2.const$1.get(seg); + } + /** + * Setter for field: + * {@snippet : + * USHORT DeviceAddress; + * } + */ + public static void DeviceAddress$set(MemorySegment seg, short x) { + constants$2.const$1.set(seg, x); + } + public static short DeviceAddress$get(MemorySegment seg, long index) { + return (short)constants$2.const$1.get(seg.asSlice(index*sizeof())); + } + public static void DeviceAddress$set(MemorySegment seg, long index, short x) { + constants$2.const$1.set(seg.asSlice(index*sizeof()), x); + } + public static VarHandle NumberOfOpenPipes$VH() { + return constants$2.const$2; + } + /** + * Getter for field: + * {@snippet : + * ULONG NumberOfOpenPipes; + * } + */ + public static int NumberOfOpenPipes$get(MemorySegment seg) { + return (int)constants$2.const$2.get(seg); + } + /** + * Setter for field: + * {@snippet : + * ULONG NumberOfOpenPipes; + * } + */ + public static void NumberOfOpenPipes$set(MemorySegment seg, int x) { + constants$2.const$2.set(seg, x); + } + public static int NumberOfOpenPipes$get(MemorySegment seg, long index) { + return (int)constants$2.const$2.get(seg.asSlice(index*sizeof())); + } + public static void NumberOfOpenPipes$set(MemorySegment seg, long index, int x) { + constants$2.const$2.set(seg.asSlice(index*sizeof()), x); + } + public static VarHandle ConnectionStatus$VH() { + return constants$2.const$3; + } + /** + * Getter for field: + * {@snippet : + * USB_CONNECTION_STATUS ConnectionStatus; + * } + */ + public static int ConnectionStatus$get(MemorySegment seg) { + return (int)constants$2.const$3.get(seg); + } + /** + * Setter for field: + * {@snippet : + * USB_CONNECTION_STATUS ConnectionStatus; + * } + */ + public static void ConnectionStatus$set(MemorySegment seg, int x) { + constants$2.const$3.set(seg, x); + } + public static int ConnectionStatus$get(MemorySegment seg, long index) { + return (int)constants$2.const$3.get(seg.asSlice(index*sizeof())); + } + public static void ConnectionStatus$set(MemorySegment seg, long index, int x) { + constants$2.const$3.set(seg.asSlice(index*sizeof()), x); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$0.java index dcc68cbc..45923e11 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$0.java @@ -2,10 +2,37 @@ package net.codecrete.usb.windows.gen.usbioctl; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.*; final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. private constants$0() {} + static final StructLayout const$0 = MemoryLayout.structLayout( + JAVA_INT.withByteAlignment(1).withName("ConnectionIndex"), + MemoryLayout.structLayout( + JAVA_BYTE.withName("bmRequest"), + JAVA_BYTE.withName("bRequest"), + JAVA_SHORT.withByteAlignment(1).withName("wValue"), + JAVA_SHORT.withByteAlignment(1).withName("wIndex"), + JAVA_SHORT.withByteAlignment(1).withName("wLength") + ).withName("SetupPacket"), + MemoryLayout.sequenceLayout(0, JAVA_BYTE).withName("Data") + ).withName("_USB_DESCRIPTOR_REQUEST"); + static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("ConnectionIndex")); + static final StructLayout const$2 = MemoryLayout.structLayout( + JAVA_BYTE.withName("bmRequest"), + JAVA_BYTE.withName("bRequest"), + JAVA_SHORT.withByteAlignment(1).withName("wValue"), + JAVA_SHORT.withByteAlignment(1).withName("wIndex"), + JAVA_SHORT.withByteAlignment(1).withName("wLength") + ).withName(""); + static final VarHandle const$3 = constants$0.const$2.varHandle(MemoryLayout.PathElement.groupElement("bmRequest")); + static final VarHandle const$4 = constants$0.const$2.varHandle(MemoryLayout.PathElement.groupElement("bRequest")); + static final VarHandle const$5 = constants$0.const$2.varHandle(MemoryLayout.PathElement.groupElement("wValue")); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$1.java new file mode 100644 index 00000000..c6508243 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$1.java @@ -0,0 +1,57 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.usbioctl; + +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.*; +final class constants$1 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$1() {} + static final VarHandle const$0 = constants$0.const$2.varHandle(MemoryLayout.PathElement.groupElement("wIndex")); + static final VarHandle const$1 = constants$0.const$2.varHandle(MemoryLayout.PathElement.groupElement("wLength")); + static final StructLayout const$2 = MemoryLayout.structLayout( + JAVA_INT.withByteAlignment(1).withName("ConnectionIndex"), + MemoryLayout.structLayout( + JAVA_BYTE.withName("bLength"), + JAVA_BYTE.withName("bDescriptorType"), + JAVA_SHORT.withByteAlignment(1).withName("bcdUSB"), + JAVA_BYTE.withName("bDeviceClass"), + JAVA_BYTE.withName("bDeviceSubClass"), + JAVA_BYTE.withName("bDeviceProtocol"), + JAVA_BYTE.withName("bMaxPacketSize0"), + JAVA_SHORT.withByteAlignment(1).withName("idVendor"), + JAVA_SHORT.withByteAlignment(1).withName("idProduct"), + JAVA_SHORT.withByteAlignment(1).withName("bcdDevice"), + JAVA_BYTE.withName("iManufacturer"), + JAVA_BYTE.withName("iProduct"), + JAVA_BYTE.withName("iSerialNumber"), + JAVA_BYTE.withName("bNumConfigurations") + ).withName("DeviceDescriptor"), + JAVA_BYTE.withName("CurrentConfigurationValue"), + JAVA_BYTE.withName("Speed"), + JAVA_BYTE.withName("DeviceIsHub"), + JAVA_SHORT.withByteAlignment(1).withName("DeviceAddress"), + JAVA_INT.withByteAlignment(1).withName("NumberOfOpenPipes"), + JAVA_INT.withByteAlignment(1).withName("ConnectionStatus"), + MemoryLayout.sequenceLayout(0, MemoryLayout.structLayout( + MemoryLayout.structLayout( + JAVA_BYTE.withName("bLength"), + JAVA_BYTE.withName("bDescriptorType"), + JAVA_BYTE.withName("bEndpointAddress"), + JAVA_BYTE.withName("bmAttributes"), + JAVA_SHORT.withByteAlignment(1).withName("wMaxPacketSize"), + JAVA_BYTE.withName("bInterval") + ).withName("EndpointDescriptor"), + JAVA_INT.withByteAlignment(1).withName("ScheduleOffset") + ).withName("_USB_PIPE_INFO")).withName("PipeList") + ).withName("_USB_NODE_CONNECTION_INFORMATION_EX"); + static final VarHandle const$3 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("ConnectionIndex")); + static final VarHandle const$4 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("CurrentConfigurationValue")); + static final VarHandle const$5 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("Speed")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$2.java new file mode 100644 index 00000000..5e83bb48 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$2.java @@ -0,0 +1,17 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.usbioctl; + +import java.lang.foreign.MemoryLayout; +import java.lang.invoke.VarHandle; +final class constants$2 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$2() {} + static final VarHandle const$0 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("DeviceIsHub")); + static final VarHandle const$1 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("DeviceAddress")); + static final VarHandle const$2 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("NumberOfOpenPipes")); + static final VarHandle const$3 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("ConnectionStatus")); +} + + From ed7c6dd368e3406ce19e8cb1d2a3eda52cd3f2cc Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 29 Jul 2023 15:33:30 +0200 Subject: [PATCH 257/433] Unify error state handling --- .../java/net/codecrete/usb/linux/Linux.java | 16 ++-- .../codecrete/usb/linux/LinuxAsyncTask.java | 43 +++++------ .../codecrete/usb/linux/LinuxUSBDevice.java | 35 ++++----- .../usb/linux/LinuxUSBException.java | 6 +- .../codecrete/usb/windows/DeviceProperty.java | 37 +++++----- .../java/net/codecrete/usb/windows/Win.java | 6 +- .../usb/windows/WindowsAsyncTask.java | 13 ++-- .../usb/windows/WindowsUSBDevice.java | 57 ++++++++------- .../usb/windows/WindowsUSBDeviceRegistry.java | 73 ++++++++++--------- .../usb/windows/WindowsUSBException.java | 10 +-- 10 files changed, 154 insertions(+), 142 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java index aa0b7d7c..241e6161 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java @@ -9,10 +9,8 @@ import net.codecrete.usb.linux.gen.string.string; -import java.lang.foreign.Linker; +import java.lang.foreign.*; import java.lang.foreign.MemoryLayout.PathElement; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.StructLayout; import java.lang.invoke.VarHandle; /** @@ -27,10 +25,14 @@ private Linux() { * Call state for capturing the {@code errno} value. */ static final Linker.Option ERRNO_STATE = Linker.Option.captureCallState("errno"); - static final StructLayout ERRNO_STATE_LAYOUT = Linker.Option.captureStateLayout(); + private static final StructLayout ERRNO_STATE_LAYOUT = Linker.Option.captureStateLayout(); private static final VarHandle callState_errno$VH = ERRNO_STATE_LAYOUT.varHandle(PathElement.groupElement("errno")); + static MemorySegment allocateErrorState(Arena arena) { + return arena.allocate(ERRNO_STATE_LAYOUT.byteSize()); + } + /** * Gets the error message for the specified error code (returned by {@code errno}). * @@ -47,10 +49,10 @@ static String getErrorMessage(int err) { * The memory segment is assumed to have the layout {@link #ERRNO_STATE}. *

* - * @param errno memory segment with error code + * @param errorState memory segment with error code * @return error code */ - static int getErrno(MemorySegment errno) { - return (int) callState_errno$VH.get(errno); + static int getErrno(MemorySegment errorState) { + return (int) callState_errno$VH.get(errorState); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index a933fa63..100360c5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -23,6 +23,7 @@ import static java.lang.foreign.ValueLayout.ADDRESS; import static java.lang.foreign.ValueLayout.JAVA_LONG; import static net.codecrete.usb.common.ForeignMemory.dereference; +import static net.codecrete.usb.linux.Linux.allocateErrorState; import static net.codecrete.usb.linux.LinuxUSBException.throwException; import static net.codecrete.usb.linux.LinuxUSBException.throwLastError; import static net.codecrete.usb.linux.USBDevFS.*; @@ -75,7 +76,7 @@ class LinuxAsyncTask { private void asyncCompletionTask() { try (var arena = Arena.ofConfined()) { - var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); + var errorState = allocateErrorState(arena); var pollfdArray = pollfd.allocateArray(100, arena); var urbPointerHolder = arena.allocate(ADDRESS); var eventfdValueHolder = arena.allocate(JAVA_LONG); @@ -101,9 +102,9 @@ private void asyncCompletionTask() { // check for wakeup event if ((pollfd.revents$get(pollfdArray, n) & poll.POLLIN()) != 0) { // wakeup to refresh list of file descriptors - res = IO.eventfd_read(asyncIOWakeUpEventFd, eventfdValueHolder, errnoState); + res = IO.eventfd_read(asyncIOWakeUpEventFd, eventfdValueHolder, errorState); if (res < 0) - throwLastError(errnoState, "internal error (eventfd_read)"); + throwLastError(errorState, "internal error (eventfd_read)"); continue; } @@ -123,7 +124,7 @@ private void asyncCompletionTask() { // reap URB var fd = pollfd.fd$get(pollfdArray, i); - reapURBs(fd, urbPointerHolder, errnoState); + reapURBs(fd, urbPointerHolder, errorState); } } } @@ -150,13 +151,13 @@ void fillPollfdArray(MemorySegment asyncPolls, int[] fds) { * * @param fd file descriptor * @param urbPointerHolder native memory to receive the URB pointer - * @param errnoState native memory to receive the errno + * @param errorState native memory to receive the errno */ - private void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment errnoState) { + private void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment errorState) { while (true) { - var res = IO.ioctl(fd, REAPURBNDELAY, urbPointerHolder, errnoState); + var res = IO.ioctl(fd, REAPURBNDELAY, urbPointerHolder, errorState); if (res < 0) { - var err = Linux.getErrno(errnoState); + var err = Linux.getErrno(errorState); if (err == errno.EAGAIN()) return; // no more pending URBs if (err == errno.ENODEV()) @@ -182,9 +183,9 @@ private void notifyAsyncIOTask() { } try (var arena = Arena.ofConfined()) { - var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); - if (IO.eventfd_write(asyncIOWakeUpEventFd, 1, errnoState) < 0) - throwLastError(errnoState, "internal error (eventfd_write)"); + var errorState = allocateErrorState(arena); + if (IO.eventfd_write(asyncIOWakeUpEventFd, 1, errorState) < 0) + throwLastError(errorState, "internal error (eventfd_write)"); } } @@ -248,11 +249,11 @@ synchronized void submitTransfer(LinuxUSBDevice device, int endpointAddress, USB usbdevfs_urb.usercontext$set(urb, MemorySegment.ofAddress(device.fileDescriptor())); try (var arena = Arena.ofConfined()) { - var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); - if (IO.ioctl(device.fileDescriptor(), SUBMITURB, urb, errnoState) < 0) { + var errorState = allocateErrorState(arena); + if (IO.ioctl(device.fileDescriptor(), SUBMITURB, urb, errorState) < 0) { var action = endpointAddress >= 128 ? "reading from" : "writing to"; var endpoint = endpointAddress == 0 ? "control endpoint" : String.format("endpoint %d", endpointAddress); - throwLastError(errnoState, "failed %s %s", action, endpoint); + throwLastError(errorState, "failed %s %s", action, endpoint); } } } @@ -298,7 +299,7 @@ synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { var fd = device.fileDescriptor(); try (var arena = Arena.ofConfined()) { - var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); + var errorState = allocateErrorState(arena); // iterate all URBs and discard the ones for the specified endpoint for (var urb : transfersByURB.keySet()) { @@ -306,10 +307,10 @@ synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { || endpointAddress != usbdevfs_urb.endpoint$get(urb)) continue; - if (IO.ioctl(fd, DISCARDURB, urb, errnoState) < 0) { + if (IO.ioctl(fd, DISCARDURB, urb, errorState) < 0) { // ignore EINVAL; it occurs if the URB has completed at the same time - if (Linux.getErrno(errnoState) != errno.EINVAL()) - throwLastError(errnoState, "failed to abort transfer"); + if (Linux.getErrno(errorState) != errno.EINVAL()) + throwLastError(errorState, "failed to abort transfer"); } } } @@ -317,11 +318,11 @@ synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { private void startAsyncIOTask() { try (var arena = Arena.ofConfined()) { - var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); - asyncIOWakeUpEventFd = IO.eventfd(0, 0, errnoState); + var errorState = allocateErrorState(arena); + asyncIOWakeUpEventFd = IO.eventfd(0, 0, errorState); if (asyncIOWakeUpEventFd == -1) { asyncIOWakeUpEventFd = 0; - throwLastError(errnoState, "internal error (eventfd)"); + throwLastError(errorState, "internal error (eventfd)"); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 51e41303..42177ba1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -33,6 +33,7 @@ import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_INT; +import static net.codecrete.usb.linux.Linux.allocateErrorState; import static net.codecrete.usb.linux.LinuxUSBException.throwException; import static net.codecrete.usb.linux.LinuxUSBException.throwLastError; @@ -95,10 +96,10 @@ public synchronized void open() { try (var arena = Arena.ofConfined()) { var pathUtf8 = arena.allocateUtf8String(uniqueDeviceId.toString()); - var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); - fd = IO.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC(), errnoState); + var errorState = allocateErrorState(arena); + fd = IO.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC(), errorState); if (fd == -1) - throwLastError(errnoState, "Cannot open USB device"); + throwLastError(errorState, "Cannot open USB device"); asyncTask.addForAsyncIOCompletion(this); } } @@ -127,7 +128,7 @@ public synchronized void claimInterface(int interfaceNumber) { getInterfaceWithCheck(interfaceNumber, false); try (var arena = Arena.ofConfined()) { - var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); + var errorState = allocateErrorState(arena); int ret; if (detachDrivers) { @@ -136,16 +137,16 @@ public synchronized void claimInterface(int interfaceNumber) { usbdevfs_disconnect_claim.interface_$set(disconnectClaim, interfaceNumber); usbdevfs_disconnect_claim.flags$set(disconnectClaim, usbdevice_fs.USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER()); usbdevfs_disconnect_claim.driver$slice(disconnectClaim).copyFrom(DRIVER_NAME_USBFS); - ret = IO.ioctl(fd, USBDevFS.DISCONNECT_CLAIM, disconnectClaim, errnoState); + ret = IO.ioctl(fd, USBDevFS.DISCONNECT_CLAIM, disconnectClaim, errorState); } else { // claim interface (without detaching kernel driver) var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); - ret = IO.ioctl(fd, USBDevFS.CLAIMINTERFACE, intfNumSegment, errnoState); + ret = IO.ioctl(fd, USBDevFS.CLAIMINTERFACE, intfNumSegment, errorState); } if (ret != 0) - throwLastError(errnoState, "Cannot claim USB interface"); + throwLastError(errorState, "Cannot claim USB interface"); setClaimed(interfaceNumber, true); } @@ -167,10 +168,10 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna var setIntfSegment = arena.allocate(usbdevfs_setinterface.$LAYOUT()); usbdevfs_setinterface.interface_$set(setIntfSegment, interfaceNumber); usbdevfs_setinterface.altsetting$set(setIntfSegment, alternateNumber); - var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); - var ret = IO.ioctl(fd, USBDevFS.SETINTERFACE, setIntfSegment, errnoState); + var errorState = allocateErrorState(arena); + var ret = IO.ioctl(fd, USBDevFS.SETINTERFACE, setIntfSegment, errorState); if (ret != 0) - throwLastError(errnoState, "Failed to set alternate interface"); + throwLastError(errorState, "Failed to set alternate interface"); } intf.setAlternate(altSetting); @@ -183,10 +184,10 @@ public synchronized void releaseInterface(int interfaceNumber) { try (var arena = Arena.ofConfined()) { var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); - var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); - var ret = IO.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment, errnoState); + var errorState = allocateErrorState(arena); + var ret = IO.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment, errorState); if (ret != 0) - throwLastError(errnoState, "Cannot release USB interface"); + throwLastError(errorState, "Cannot release USB interface"); setClaimed(interfaceNumber, false); @@ -196,7 +197,7 @@ public synchronized void releaseInterface(int interfaceNumber) { usbdevfs_ioctl.ifno$set(request, interfaceNumber); usbdevfs_ioctl.ioctl_code$set(request, USBDevFS.CONNECT); usbdevfs_ioctl.data$set(request, MemorySegment.NULL); - IO.ioctl(fd, USBDevFS.IOCTL, request, errnoState); + IO.ioctl(fd, USBDevFS.IOCTL, request, errorState); } } } @@ -325,10 +326,10 @@ public void clearHalt(USBDirection direction, int endpointNumber) { try (var arena = Arena.ofConfined()) { var endpointAddrSegment = arena.allocate(JAVA_INT, endpoint.endpointAddress() & 0xff); - var errnoState = arena.allocate(Linux.ERRNO_STATE_LAYOUT); - var res = IO.ioctl(fd, USBDevFS.CLEAR_HALT, endpointAddrSegment, errnoState); + var errorState = allocateErrorState(arena); + var res = IO.ioctl(fd, USBDevFS.CLEAR_HALT, endpointAddrSegment, errorState); if (res < 0) - throwLastError(errnoState, "Clearing halt failed"); + throwLastError(errorState, "Clearing halt failed"); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java index 9ff7ffdd..1d8786cf 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java @@ -66,12 +66,12 @@ static void throwException(String message, Object... args) { * {@link Linux#ERRNO_STATE}. *

* - * @param errno segment with lat error code + * @param errorState segment with error state * @param message exception message format ({@link String#format(String, Object...)} style) * @param args arguments for exception message */ - static void throwLastError(MemorySegment errno, String message, Object... args) { - throwException(Linux.getErrno(errno), message, args); + static void throwLastError(MemorySegment errorState, String message, Object... args) { + throwException(Linux.getErrno(errorState), message, args); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index c6603c3e..492018ee 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -22,6 +22,7 @@ import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.JAVA_CHAR; import static java.lang.foreign.ValueLayout.JAVA_INT; +import static net.codecrete.usb.windows.Win.allocateErrorState; import static net.codecrete.usb.windows.WindowsUSBException.throwException; import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; @@ -71,10 +72,10 @@ static int getDeviceIntProperty(MemorySegment devInfoSet, MemorySegment devInfoD try (var arena = Arena.ofConfined()) { var propertyTypeHolder = arena.allocate(JAVA_INT); var propertyValueHolder = arena.allocate(JAVA_INT); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, - propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, lastErrorState) == 0) - throwLastError(lastErrorState, "Internal error (SetupDiGetDevicePropertyW - A)"); + propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, errorState) == 0) + throwLastError(errorState, "Internal error (SetupDiGetDevicePropertyW - A)"); if (propertyTypeHolder.get(JAVA_INT, 0) != SetupAPI.DEVPROP_TYPE_UINT32()) throwException("Internal error (expected property type UINT32)"); @@ -129,10 +130,10 @@ private static MemorySegment getVariableLengthProperty(MemorySegment devInfoSet, // query length (thus no buffer) var propertyTypeHolder = arena.allocate(JAVA_INT); var requiredSizeHolder = arena.allocate(JAVA_INT); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, NULL, 0, - requiredSizeHolder, 0, lastErrorState) == 0) { - var err = Win.getLastError(lastErrorState); + requiredSizeHolder, 0, errorState) == 0) { + var err = Win.getLastError(errorState); if (err == Kernel32.ERROR_NOT_FOUND()) return null; if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) @@ -149,8 +150,8 @@ private static MemorySegment getVariableLengthProperty(MemorySegment devInfoSet, // get property value if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, - propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, lastErrorState) == 0) - throwLastError(lastErrorState, "Internal error (SetupDiGetDevicePropertyW - C)"); + propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, errorState) == 0) + throwLastError(errorState, "Internal error (SetupDiGetDevicePropertyW - C)"); return propertyValueHolder; } @@ -167,13 +168,13 @@ static List findDeviceInterfaceGUIDs(MemorySegment devInfoSet, MemorySeg Arena arena) { try (var cleanup = new ScopeCleanup()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); // open device registry key var regKey = SetupAPI2.SetupDiOpenDevRegKey(devInfoSet, devInfoData, SetupAPI.DICS_FLAG_GLOBAL(), 0, - SetupAPI.DIREG_DEV(), Advapi32.KEY_READ(), lastErrorState); + SetupAPI.DIREG_DEV(), Advapi32.KEY_READ(), errorState); if (Win.isInvalidHandle(regKey)) - throwLastError(lastErrorState, "Cannot open device registry key"); + throwLastError(errorState, "Cannot open device registry key"); cleanup.add(() -> Advapi32.RegCloseKey(regKey)); // read registry value (without buffer, to query length) @@ -206,14 +207,14 @@ static List findDeviceInterfaceGUIDs(MemorySegment devInfoSet, MemorySeg */ static String getDevicePath(String instanceId, MemorySegment interfaceGuid) { try (var arena = Arena.ofConfined(); var cleanup = new ScopeCleanup()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); // get device info set for instance var instanceIDSegment = Win.createSegmentFromString(instanceId, arena); final var devInfoSet = SetupAPI2.SetupDiGetClassDevsW(interfaceGuid, instanceIDSegment, NULL, - SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), lastErrorState); + SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), errorState); if (Win.isInvalidHandle(devInfoSet)) - throwLastError(lastErrorState, "internal error (SetupDiGetClassDevsW)"); + throwLastError(errorState, "internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); @@ -222,8 +223,8 @@ static String getDevicePath(String instanceId, MemorySegment interfaceGuid) { var devIntfData = arena.allocate(_SP_DEVICE_INTERFACE_DATA.$LAYOUT()); _SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); if (SetupAPI2.SetupDiEnumDeviceInterfaces(devInfoSet, NULL, interfaceGuid, 0, devIntfData, - lastErrorState) == 0) - throwLastError(lastErrorState, "internal error (SetupDiEnumDeviceInterfaces)"); + errorState) == 0) + throwLastError(errorState, "internal error (SetupDiEnumDeviceInterfaces)"); // get device path // (SP_DEVICE_INTERFACE_DETAIL_DATA_W is of variable length and requires a bigger allocation so @@ -234,8 +235,8 @@ static String getDevicePath(String instanceId, MemorySegment interfaceGuid) { (int) _SP_DEVICE_INTERFACE_DETAIL_DATA_W.sizeof()); var intfDetailDataSize = (int) intfDetailData.byteSize(); if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSet, devIntfData, intfDetailData, - intfDetailDataSize, NULL, NULL, lastErrorState) == 0) - throwLastError(lastErrorState, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); + intfDetailDataSize, NULL, NULL, errorState) == 0) + throwLastError(errorState, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); return Win.createStringFromSegment(intfDetailData.asSlice(devicePathOffset)); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index cb139923..1bea7e6d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -29,11 +29,15 @@ private Win() { * Call state for capturing the {@code GetLastError()} value. */ public static final Linker.Option LAST_ERROR_STATE = Linker.Option.captureCallState("GetLastError"); - public static final StructLayout LAST_ERROR_STATE_LAYOUT = Linker.Option.captureStateLayout(); + private static final StructLayout LAST_ERROR_STATE_LAYOUT = Linker.Option.captureStateLayout(); private static final VarHandle callState_GetLastError$VH = LAST_ERROR_STATE_LAYOUT.varHandle(PathElement.groupElement("GetLastError")); + static MemorySegment allocateErrorState(Arena arena) { + return arena.allocate(LAST_ERROR_STATE_LAYOUT); + } + /** * Returns the error code captured using the call state {@link #LAST_ERROR_STATE}. * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java index d708c62d..0f406c86 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java @@ -20,6 +20,7 @@ import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.*; +import static net.codecrete.usb.windows.Win.allocateErrorState; import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; /** @@ -68,18 +69,18 @@ private void asyncCompletionTask() { var overlappedHolder = arena.allocate(ADDRESS, NULL); var numBytesHolder = arena.allocate(JAVA_INT, 0); var completionKeyHolder = arena.allocate(JAVA_LONG, 0); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); while (true) { overlappedHolder.set(ADDRESS, 0, NULL); completionKeyHolder.set(JAVA_LONG, 0, 0); var res = Kernel32B.GetQueuedCompletionStatus(asyncIoCompletionPort, numBytesHolder, - completionKeyHolder, overlappedHolder, Kernel32.INFINITE(), lastErrorState); + completionKeyHolder, overlappedHolder, Kernel32.INFINITE(), errorState); var overlappedAddr = overlappedHolder.get(JAVA_LONG, 0); if (res == 0 && overlappedAddr == 0) - throwLastError(lastErrorState, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); + throwLastError(errorState, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); if (overlappedAddr == 0) return; // registry closing? @@ -100,13 +101,13 @@ private void asyncCompletionTask() { synchronized void addDevice(MemorySegment handle) { try (var arena = Arena.ofConfined()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); // Creates a new port if it doesn't exist; adds handle to existing port if it exists var portHandle = Kernel32B.CreateIoCompletionPort(handle, asyncIoCompletionPort, - handle.address(), 0, lastErrorState); + handle.address(), 0, errorState); if (portHandle == MemorySegment.NULL) - throwLastError(lastErrorState, "internal error (CreateIoCompletionPort)"); + throwLastError(errorState, "internal error (CreateIoCompletionPort)"); if (asyncIoCompletionPort == MemorySegment.NULL) { asyncIoCompletionPort = portHandle; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 97e4f5a6..9c6ffc1c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -27,6 +27,7 @@ import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.common.ForeignMemory.dereference; +import static net.codecrete.usb.windows.Win.allocateErrorState; import static net.codecrete.usb.windows.WindowsUSBException.throwException; import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; @@ -117,17 +118,17 @@ public synchronized void claimInterface(int interfaceNumber) { try (var arena = Arena.ofConfined()) { MemorySegment deviceHandle; - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); // open Windows device if needed if (firstIntfHandle.deviceHandle == null) { var pathSegment = Win.createSegmentFromString(firstIntfHandle.devicePath, arena); deviceHandle = Kernel32B.CreateFileW(pathSegment, Kernel32.GENERIC_WRITE() | Kernel32.GENERIC_READ(), Kernel32.FILE_SHARE_WRITE() | Kernel32.FILE_SHARE_READ(), NULL, Kernel32.OPEN_EXISTING(), - Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), NULL, lastErrorState); + Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), NULL, errorState); if (Win.isInvalidHandle(deviceHandle)) - throwLastError(lastErrorState, "Cannot open USB device %s", firstIntfHandle.devicePath); + throwLastError(errorState, "Cannot open USB device %s", firstIntfHandle.devicePath); asyncTask.addDevice(deviceHandle); @@ -138,8 +139,8 @@ public synchronized void claimInterface(int interfaceNumber) { try { // open interface var interfaceHandleHolder = arena.allocate(ADDRESS); - if (WinUSB2.WinUsb_Initialize(deviceHandle, interfaceHandleHolder, lastErrorState) == 0) - throwLastError(lastErrorState, "Cannot open WinUSB device"); + if (WinUSB2.WinUsb_Initialize(deviceHandle, interfaceHandleHolder, errorState) == 0) + throwLastError(errorState, "Cannot open WinUSB device"); var interfaceHandle = dereference(interfaceHandleHolder); firstIntfHandle.deviceHandle = deviceHandle; @@ -172,10 +173,10 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna alternateNumber); try (var arena = Arena.ofConfined()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); if (WinUSB2.WinUsb_SetCurrentAlternateSetting(intfHandle.interfaceHandle, (byte) alternateNumber, - lastErrorState) == 0) - throwLastError(lastErrorState, "Failed to set alternate interface"); + errorState) == 0) + throwLastError(errorState, "Failed to set alternate interface"); } intf.setAlternate(altSetting); } @@ -313,13 +314,13 @@ synchronized void submitControlTransfer(USBDirection direction, USBControlTransf setupPacket.setIndex(setup.index()); setupPacket.setLength(transfer.dataSize()); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); asyncTask.prepareForSubmission(transfer); // submit transfer if (WinUSB2.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket.segment(), transfer.data(), - transfer.dataSize(), NULL, transfer.overlapped(), lastErrorState) == 0) { - var err = Win.getLastError(lastErrorState); + transfer.dataSize(), NULL, transfer.overlapped(), errorState) == 0) { + var err = Win.getLastError(errorState); if (err != Kernel32.ERROR_IO_PENDING()) throwException(err, "Submitting control transfer failed"); } @@ -331,13 +332,13 @@ synchronized void submitTransferOut(int endpointNumber, WindowsTransfer transfer var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.ofConfined()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); asyncTask.prepareForSubmission(transfer); // submit transfer if (WinUSB2.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), transfer.data(), - transfer.dataSize(), NULL, transfer.overlapped(), lastErrorState) == 0) { - var err = Win.getLastError(lastErrorState); + transfer.dataSize(), NULL, transfer.overlapped(), errorState) == 0) { + var err = Win.getLastError(errorState); if (err != Kernel32.ERROR_IO_PENDING()) throwException(err, "Submitting transfer OUT failed"); } @@ -349,13 +350,13 @@ synchronized void submitTransferIn(int endpointNumber, WindowsTransfer transfer) var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.ofConfined()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); asyncTask.prepareForSubmission(transfer); // submit transfer if (WinUSB2.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), transfer.data(), - transfer.dataSize(), NULL, transfer.overlapped(), lastErrorState) == 0) { - var err = Win.getLastError(lastErrorState); + transfer.dataSize(), NULL, transfer.overlapped(), errorState) == 0) { + var err = Win.getLastError(errorState); if (err != Kernel32.ERROR_IO_PENDING()) throwException(err, "Submitting transfer IN failed"); } @@ -367,17 +368,17 @@ synchronized void configureForAsyncIo(USBDirection direction, int endpointNumber var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.ofConfined()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); var timeoutHolder = arena.allocate(JAVA_INT, 0); if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), - WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder, lastErrorState) == 0) - throwLastError(lastErrorState, "Setting timeout failed"); + WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder, errorState) == 0) + throwLastError(errorState, "Setting timeout failed"); var rawIoHolder = arena.allocate(JAVA_BYTE, (byte) 1); if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), WinUSB.RAW_IO(), - (int) rawIoHolder.byteSize(), rawIoHolder, lastErrorState) == 0) - throwLastError(lastErrorState, "Setting raw IO failed"); + (int) rawIoHolder.byteSize(), rawIoHolder, errorState) == 0) + throwLastError(errorState, "Setting raw IO failed"); } } @@ -387,9 +388,9 @@ public synchronized void clearHalt(USBDirection direction, int endpointNumber) { var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.ofConfined()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); - if (WinUSB2.WinUsb_ResetPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), lastErrorState) == 0) - throwLastError(lastErrorState, "Clearing halt failed"); + var errorState = allocateErrorState(arena); + if (WinUSB2.WinUsb_ResetPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), errorState) == 0) + throwLastError(errorState, "Clearing halt failed"); } } @@ -399,9 +400,9 @@ public synchronized void abortTransfers(USBDirection direction, int endpointNumb var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.ofConfined()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); - if (WinUSB2.WinUsb_AbortPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), lastErrorState) == 0) - throwLastError(lastErrorState, "Aborting transfers on endpoint failed"); + var errorState = allocateErrorState(arena); + if (WinUSB2.WinUsb_AbortPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), errorState) == 0) + throwLastError(errorState, "Aborting transfers on endpoint failed"); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 862629e9..41731e6e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -41,6 +41,7 @@ import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.usbstandard.Constants.*; +import static net.codecrete.usb.windows.Win.allocateErrorState; import static net.codecrete.usb.windows.WindowsUSBException.throwException; import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; @@ -62,7 +63,7 @@ protected void monitorDevices() { try (var arena = Arena.ofConfined()) { MemorySegment hwnd; - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); try { final var className = Win.createSegmentFromString("USB_MONITOR", arena); @@ -82,15 +83,15 @@ protected void monitorDevices() { tagWNDCLASSEXW.lpfnWndProc$set(wx, handleWindowMessageStub); tagWNDCLASSEXW.hInstance$set(wx, instance); tagWNDCLASSEXW.lpszClassName$set(wx, className); - var atom = User32B.RegisterClassExW(wx, lastErrorState); + var atom = User32B.RegisterClassExW(wx, errorState); if (atom == 0) - throwLastError(lastErrorState, "Internal error (RegisterClassExW)"); + throwLastError(errorState, "Internal error (RegisterClassExW)"); // create message-only window hwnd = User32B.CreateWindowExW(0, className, windowName, 0, 0, 0, 0, 0, User32.HWND_MESSAGE(), NULL, - instance, NULL, lastErrorState); + instance, NULL, errorState); if (hwnd.address() == 0) - throwLastError(lastErrorState, "Internal error (CreateWindowExW)"); + throwLastError(errorState, "Internal error (CreateWindowExW)"); // configure notifications var notificationFilter = arena.allocate(_DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); @@ -100,9 +101,9 @@ protected void monitorDevices() { _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid$slice(notificationFilter).copyFrom(USBConstants.GUID_DEVINTERFACE_USB_DEVICE); var notifyHandle = User32B.RegisterDeviceNotificationW(hwnd, notificationFilter, - User32.DEVICE_NOTIFY_WINDOW_HANDLE(), lastErrorState); + User32.DEVICE_NOTIFY_WINDOW_HANDLE(), errorState); if (notifyHandle.address() == 0) - throwLastError(lastErrorState, "Internal error (RegisterDeviceNotificationW)"); + throwLastError(errorState, "Internal error (RegisterDeviceNotificationW)"); // initial device enumeration enumeratePresentDevices(); @@ -116,11 +117,11 @@ protected void monitorDevices() { var msg = arena.allocate(tagMSG.$LAYOUT()); int err; //noinspection StatementWithEmptyBody - while ((err = User32B.GetMessageW(msg, hwnd, 0, 0, lastErrorState)) > 0) + while ((err = User32B.GetMessageW(msg, hwnd, 0, 0, errorState)) > 0) ; // do nothing if (err == -1) - throwLastError(lastErrorState, "Internal error (GetMessageW)"); + throwLastError(errorState, "Internal error (GetMessageW)"); } } @@ -130,13 +131,13 @@ private void enumeratePresentDevices() { List deviceList = new ArrayList<>(); try (var outerArena = Arena.ofConfined(); var outerCleanup = new ScopeCleanup()) { - var lastErrorState = outerArena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(outerArena); // get device information set of all USB devices present var devInfoSet = SetupAPI2.SetupDiGetClassDevsW(USBConstants.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, - SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), lastErrorState); + SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), errorState); if (Win.isInvalidHandle(devInfoSet)) - throwLastError(lastErrorState, "Internal error (SetupDiGetClassDevsW)"); + throwLastError(errorState, "Internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left outerCleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); @@ -152,11 +153,11 @@ private void enumeratePresentDevices() { // iterate all devices for (var i = 0; true; i++) { - if (SetupAPI2.SetupDiEnumDeviceInfo(devInfoSet, i, devInfoData, lastErrorState) == 0) { - var err = Win.getLastError(lastErrorState); + if (SetupAPI2.SetupDiEnumDeviceInfo(devInfoSet, i, devInfoData, errorState) == 0) { + var err = Win.getLastError(errorState); if (err == Kernel32.ERROR_NO_MORE_ITEMS()) break; - throwLastError(lastErrorState, "Internal error (SetupDiEnumDeviceInfo)"); + throwLastError(errorState, "Internal error (SetupDiEnumDeviceInfo)"); } var instanceId = DeviceProperty.getDeviceStringProperty(devInfoSet, devInfoData, @@ -192,12 +193,12 @@ private Map enumerateChildren(List childrenIds) { try (var arena = Arena.ofConfined(); var cleanup = new ScopeCleanup()) { //noinspection DuplicatedCode - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); // create empty device info set - var devInfoSet = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, lastErrorState); + var devInfoSet = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, errorState); if (Win.isInvalidHandle(devInfoSet)) - throwLastError(lastErrorState, "Internal error (SetupDiCreateDeviceInfoList)"); + throwLastError(errorState, "Internal error (SetupDiCreateDeviceInfoList)"); cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); // get device info for child @@ -205,8 +206,8 @@ private Map enumerateChildren(List childrenIds) { _SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) devInfoData.byteSize()); var instanceIdSegment = Win.createSegmentFromString(instanceId, arena); if (SetupAPI2.SetupDiOpenDeviceInfoW(devInfoSet, instanceIdSegment, NULL, 0, devInfoData, - lastErrorState) == 0) - throwLastError(lastErrorState, "Internal error (SetupDiOpenDeviceInfoW)"); + errorState) == 0) + throwLastError(errorState, "Internal error (SetupDiOpenDeviceInfoW)"); // get hardware IDs (to extract interface number) var hardwareIds = DeviceProperty.getDeviceStringListProperty(devInfoSet, devInfoData, @@ -242,11 +243,11 @@ private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSet, MemorySeg var hubHandle = hubHandles.get(hubPath); if (hubHandle == null) { var hubPathSeg = Win.createSegmentFromString(hubPath, arena); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); hubHandle = Kernel32B.CreateFileW(hubPathSeg, Kernel32.GENERIC_WRITE(), Kernel32.FILE_SHARE_WRITE(), - NULL, Kernel32.OPEN_EXISTING(), 0, NULL, lastErrorState); + NULL, Kernel32.OPEN_EXISTING(), 0, NULL, errorState); if (Win.isInvalidHandle(hubHandle)) - throwLastError(lastErrorState, "Cannot open USB hub"); + throwLastError(errorState, "Cannot open USB hub"); hubHandles.put(hubPath, hubHandle); } @@ -308,11 +309,11 @@ private USBDevice createDevice(String devicePath, Map children, var connInfo = _USB_NODE_CONNECTION_INFORMATION_EX.allocate(arena); _USB_NODE_CONNECTION_INFORMATION_EX.ConnectionIndex$set(connInfo, usbPortNum); var sizeHolder = arena.allocate(JAVA_INT); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); if (Kernel32B.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), connInfo, (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL, - lastErrorState) == 0) - throwLastError(lastErrorState, "Internal error (cannot get device descriptor)"); + errorState) == 0) + throwLastError(errorState, "Internal error (cannot get device descriptor)"); var descriptorSegment = _USB_NODE_CONNECTION_INFORMATION_EX.DeviceDescriptor$slice(connInfo); var deviceDescriptor = new DeviceDescriptor(descriptorSegment); @@ -352,10 +353,10 @@ private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, // execute request var effectiveSizeHolder = arena.allocate(JAVA_INT); - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); if (Kernel32B.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION(), - descriptorRequest, size, descriptorRequest, size, effectiveSizeHolder, NULL, lastErrorState) == 0) - throwLastError(lastErrorState, "Cannot retrieve descriptor %d", index); + descriptorRequest, size, descriptorRequest, size, effectiveSizeHolder, NULL, errorState) == 0) + throwLastError(errorState, "Cannot retrieve descriptor %d", index); // determine size of descriptor int expectedSize; @@ -425,12 +426,12 @@ private long handleWindowMessage(MemorySegment hWnd, int uMsg, long wParam, long private void onDeviceConnected(String devicePath) { try (var arena = Arena.ofConfined(); var cleanup = new ScopeCleanup()) { - var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE_LAYOUT); + var errorState = allocateErrorState(arena); // create empty device info set - var devInfoSet = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, lastErrorState); + var devInfoSet = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, errorState); if (Win.isInvalidHandle(devInfoSet)) - throwLastError(lastErrorState, "Internal error (SetupDiCreateDeviceInfoList)"); + throwLastError(errorState, "Internal error (SetupDiCreateDeviceInfoList)"); cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); @@ -438,16 +439,16 @@ private void onDeviceConnected(String devicePath) { var devIntfData = arena.allocate(_SP_DEVICE_INTERFACE_DATA.$LAYOUT()); _SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); var devicePathSegment = Win.createSegmentFromString(devicePath, arena); - if (SetupAPI2.SetupDiOpenDeviceInterfaceW(devInfoSet, devicePathSegment, 0, devIntfData, lastErrorState) == 0) - throwLastError(lastErrorState, "Internal error (SetupDiOpenDeviceInterfaceW)"); + if (SetupAPI2.SetupDiOpenDeviceInterfaceW(devInfoSet, devicePathSegment, 0, devIntfData, errorState) == 0) + throwLastError(errorState, "Internal error (SetupDiOpenDeviceInterfaceW)"); cleanup.add(() -> SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSet, devIntfData)); var devInfoData = arena.allocate(_SP_DEVINFO_DATA.$LAYOUT()); _SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) devInfoData.byteSize()); if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSet, devIntfData, NULL, 0, NULL, devInfoData, - lastErrorState) == 0) { - var err = Win.getLastError(lastErrorState); + errorState) == 0) { + var err = Win.getLastError(errorState); if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) throwException(err, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java index b0bb3db7..2011aac9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java @@ -72,12 +72,12 @@ static void throwException(String message, Object... args) { * {@link Win#LAST_ERROR_STATE} provided as the first parameter. *

* - * @param lastErrorState call capture state containing last error code - * @param message exception message format ({@link String#format(String, Object...)} style) - * @param args arguments for exception message + * @param errorState call capture state containing last error code + * @param message exception message format ({@link String#format(String, Object...)} style) + * @param args arguments for exception message */ - static void throwLastError(MemorySegment lastErrorState, String message, Object... args) { - throwException(Win.getLastError(lastErrorState), message, args); + static void throwLastError(MemorySegment errorState, String message, Object... args) { + throwException(Win.getLastError(errorState), message, args); } private static MemorySegment ntModule; // NOSONAR From c4f180a0606a69db8e6f851c51246b2dabbb9a42 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 29 Jul 2023 15:39:46 +0200 Subject: [PATCH 258/433] Use allocate() methods --- .../net/codecrete/usb/linux/LinuxUSBDevice.java | 2 +- .../usb/linux/LinuxUSBDeviceRegistry.java | 2 +- .../codecrete/usb/macos/CoreFoundationHelper.java | 2 +- .../net/codecrete/usb/macos/MacosUSBDevice.java | 4 ++-- .../net/codecrete/usb/windows/DeviceProperty.java | 4 ++-- .../codecrete/usb/windows/WindowsAsyncTask.java | 2 +- .../usb/windows/WindowsUSBDeviceRegistry.java | 14 +++++++------- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 42177ba1..49a4fe14 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -165,7 +165,7 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna alternateNumber); try (var arena = Arena.ofConfined()) { - var setIntfSegment = arena.allocate(usbdevfs_setinterface.$LAYOUT()); + var setIntfSegment = usbdevfs_setinterface.allocate(arena); usbdevfs_setinterface.interface_$set(setIntfSegment, interfaceNumber); usbdevfs_setinterface.altsetting$set(setIntfSegment, alternateNumber); var errorState = allocateErrorState(arena); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index f3cfc9d7..63fb45f2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -250,7 +250,7 @@ private static String getDeviceAction(MemorySegment udevDevice) { * @param arena an arena for allocating memory */ private static void waitForFileDescriptor(int fd, Arena arena) { - var fds = arena.allocate(pollfd.$LAYOUT()); + var fds = pollfd.allocate(arena); pollfd.fd$set(fds, fd); pollfd.events$set(fds, (short) poll.POLLIN()); int res = poll.poll(fds, 1, -1); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java index c9b884cc..74459d50 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java @@ -36,7 +36,7 @@ static String stringFromCFStringRef(MemorySegment string, Arena arena) { var strLen = CoreFoundation.CFStringGetLength(string); var buffer = arena.allocateArray(JAVA_CHAR, strLen); - var range = arena.allocate(CFRange.$LAYOUT()); + var range = CFRange.allocate(arena); CFRange.location$set(range, 0); CFRange.length$set(range, strLen); CoreFoundation.CFStringGetCharacters(string, range, buffer); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 44b44bfa..39a67e48 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -180,7 +180,7 @@ private void loadDescription(MemorySegment device) { private InterfaceInfo findInterface(int interfaceNumber) { try (var arena = Arena.ofConfined(); var outerCleanup = new ScopeCleanup()) { - var request = arena.allocate(IOUSBFindInterfaceRequest.$LAYOUT()); + var request = IOUSBFindInterfaceRequest.allocate(arena); IOUSBFindInterfaceRequest.bInterfaceClass$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); IOUSBFindInterfaceRequest.bInterfaceSubClass$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); IOUSBFindInterfaceRequest.bInterfaceProtocol$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); @@ -362,7 +362,7 @@ private synchronized EndpointInfo getEndpointInfo(int endpointNumber, USBDirecti private static MemorySegment createDeviceRequest(Arena arena, USBDirection direction, USBControlTransfer setup, MemorySegment data) { - var deviceRequest = arena.allocate(IOUSBDevRequest.$LAYOUT()); + var deviceRequest = IOUSBDevRequest.allocate(arena); var bmRequestType = (direction == USBDirection.IN ? 0x80 : 0x00) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); IOUSBDevRequest.bmRequestType$set(deviceRequest, (byte) bmRequestType); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index 492018ee..2c255781 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -220,7 +220,7 @@ static String getDevicePath(String instanceId, MemorySegment interfaceGuid) { cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); // retrieve first element of enumeration - var devIntfData = arena.allocate(_SP_DEVICE_INTERFACE_DATA.$LAYOUT()); + var devIntfData = _SP_DEVICE_INTERFACE_DATA.allocate(arena); _SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); if (SetupAPI2.SetupDiEnumDeviceInterfaces(devInfoSet, NULL, interfaceGuid, 0, devIntfData, errorState) == 0) @@ -260,7 +260,7 @@ static String getDevicePathByGUID(MemorySegment devInfoSet, MemorySegment devInf for (var guid : guids) { // check for class GUID var guidSegment = Win.createSegmentFromString(guid, arena); - var clsid = arena.allocate(_GUID.$LAYOUT()); + var clsid = _GUID.allocate(arena); if (Ole32.CLSIDFromString(guidSegment, clsid) != 0) continue; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java index 0f406c86..7cad8a23 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java @@ -136,7 +136,7 @@ synchronized void prepareForSubmission(WindowsTransfer transfer) { MemorySegment overlapped; var size = availableOverlappedStructs.size(); if (size == 0) { - overlapped = overlappedArena.allocate(_OVERLAPPED.$LAYOUT()); + overlapped = _OVERLAPPED.allocate(overlappedArena); } else { overlapped = availableOverlappedStructs.remove(size - 1); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 41731e6e..2be1ed02 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -78,7 +78,7 @@ protected void monitorDevices() { FunctionDescriptor.of(JAVA_LONG, ADDRESS, JAVA_INT, JAVA_LONG, JAVA_LONG), arena); // register window class - var wx = arena.allocate(tagWNDCLASSEXW.$LAYOUT()); + var wx = tagWNDCLASSEXW.allocate(arena); tagWNDCLASSEXW.cbSize$set(wx, (int) wx.byteSize()); tagWNDCLASSEXW.lpfnWndProc$set(wx, handleWindowMessageStub); tagWNDCLASSEXW.hInstance$set(wx, instance); @@ -94,7 +94,7 @@ protected void monitorDevices() { throwLastError(errorState, "Internal error (CreateWindowExW)"); // configure notifications - var notificationFilter = arena.allocate(_DEV_BROADCAST_DEVICEINTERFACE_W.$LAYOUT()); + var notificationFilter = _DEV_BROADCAST_DEVICEINTERFACE_W.allocate(arena); _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$set(notificationFilter, (int) notificationFilter.byteSize()); _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$set(notificationFilter, User32.DBT_DEVTYP_DEVICEINTERFACE()); @@ -114,7 +114,7 @@ protected void monitorDevices() { } // process messages - var msg = arena.allocate(tagMSG.$LAYOUT()); + var msg = tagMSG.allocate(arena); int err; //noinspection StatementWithEmptyBody while ((err = User32B.GetMessageW(msg, hwnd, 0, 0, errorState)) > 0) @@ -143,7 +143,7 @@ private void enumeratePresentDevices() { outerCleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); // allocate SP_DEVINFO_DATA (will receive details for each device) - var devInfoData = outerArena.allocate(_SP_DEVINFO_DATA.$LAYOUT()); + var devInfoData = _SP_DEVINFO_DATA.allocate(outerArena); _SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) _SP_DEVINFO_DATA.$LAYOUT().byteSize()); // ensure all hubs are closed later @@ -202,7 +202,7 @@ private Map enumerateChildren(List childrenIds) { cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); // get device info for child - var devInfoData = arena.allocate(_SP_DEVINFO_DATA.$LAYOUT()); + var devInfoData = _SP_DEVINFO_DATA.allocate(arena); _SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) devInfoData.byteSize()); var instanceIdSegment = Win.createSegmentFromString(instanceId, arena); if (SetupAPI2.SetupDiOpenDeviceInfoW(devInfoSet, instanceIdSegment, NULL, 0, devInfoData, @@ -436,7 +436,7 @@ private void onDeviceConnected(String devicePath) { cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); // load device information into dev info set - var devIntfData = arena.allocate(_SP_DEVICE_INTERFACE_DATA.$LAYOUT()); + var devIntfData = _SP_DEVICE_INTERFACE_DATA.allocate(arena); _SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); var devicePathSegment = Win.createSegmentFromString(devicePath, arena); if (SetupAPI2.SetupDiOpenDeviceInterfaceW(devInfoSet, devicePathSegment, 0, devIntfData, errorState) == 0) @@ -444,7 +444,7 @@ private void onDeviceConnected(String devicePath) { cleanup.add(() -> SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSet, devIntfData)); - var devInfoData = arena.allocate(_SP_DEVINFO_DATA.$LAYOUT()); + var devInfoData = _SP_DEVINFO_DATA.allocate(arena); _SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) devInfoData.byteSize()); if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSet, devIntfData, NULL, 0, NULL, devInfoData, errorState) == 0) { From 75ed3c482a8fa4cfc1a28bb80c501a21b1d85771 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 29 Jul 2023 16:06:47 +0200 Subject: [PATCH 259/433] Hide unnecessary info message --- .../net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 2be1ed02..8bc3f6f8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -392,8 +392,6 @@ private String getStringDescriptor(MemorySegment hubHandle, int usbPortNumber, i return stringDesc.string(); } catch (USBException e) { - System.err.printf("Info: [JavaDoesUSB] failed to retrieve string descriptor %d (%s) - ignoring%n", index, - e.getMessage()); return null; } } From 63e4e76efe33d47a1f1b4fdd686910845b393f8c Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 30 Jul 2023 10:14:20 +0200 Subject: [PATCH 260/433] Update jextract README --- java-does-usb/jextract/README.md | 38 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index a9b37b08..d700e3a8 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -2,7 +2,7 @@ Some of the binding code for accessing native functions and data structures is generated with [jextract](https://jdk.java.net/jextract/). The tool is still under construction and has its limitations. -In order to generate the code, the scripts in this directory have to be run (`gen_linux.sh`, `gen_macos.sh` and `gen_win_xxx.cmd`). Each script has to be run on that particular operating system. +In order to generate the code, the scripts in the subdirectories have to be run (`linux/gen_linux.sh`, `macos/gen_macos.sh` and `/windowsgen_win.cmd`). Each script has to be run on the particular operating system. The code is generated in directories below `gen`, i.e. `main/java/net/codecrete/usb/linux/gen` and similar for the other operating systems. For each library (`xxx.so` or `xxx.dll`) and each macOS framework, a separate package is created. @@ -13,11 +13,11 @@ The resulting code is then committed to the source code repository. Before the c ## General limitations -- The binaries for *jextract* on https://jdk.java.net/jextract/ have not been updated for JDK 20. So it must be built from source. Instructions can be found at [Building & Testing](https://github.com/openjdk/jextract#building--testing). +- The binaries for *jextract* on https://jdk.java.net/jextract/ have not been updated for JDK 21. So it must be built from source. Instructions can be found at [Building & Testing](https://github.com/openjdk/jextract#building--testing). -- According to the jextract mailing list, it would be required to create separate code form Intel x64 and ARM64 architecture. And jextract would need to be run on each architecture separately (no cross-compilation). Fortunately, this doesn't seem to be the case. Linux code generated on Intel x64 also runs on ARM64 without change. The same holds for macOS. However, jextract needs to be run on each operating system separately. +- According to the jextract mailing list, it would be required to create separate code for Intel x64 and ARM64 architecture. And jextract would need to be run on each architecture separately (no cross-compilation). Fortunately, this doesn't seem to be the case. Linux code generated on Intel x64 also runs on ARM64 without change. The same holds for macOS. However, jextract needs to be run on each operating system separately. -- JDK 20 introduced a new feature for saving the thread-specific error values (`GetLastError()` on Windows, `errno` on Linux). To use it, an additional parameter must be added to function calls. Unfortunately, this is not yet supported by jextract. So with the JDK 20 updates, more code is written manually and less is generated by jextract. +- JDK 20 introduced a new feature for saving the thread-specific error values (`GetLastError()` on Windows, `errno` on Linux). To use it, an additional parameter must be added to function calls. Unfortunately, this is not yet supported by jextract. So a good number of function bindings have to be written manually. - `typedef` and `struct`: @@ -30,8 +30,8 @@ The resulting code is then committed to the source code repository. Before the c - *jextract* is not really transparent about what it does. It often skips elements without providing any information. In particular, it will silently skip a requested element in these cases: - `--include-var myvar` if `myvar` is declared as `static`. - - `--include-var myvar` if `myvar` is an `enum` constant. `enum` constants must be requested with `--include-macro`. - - `--include-macro MYMACRO` if `MYMACRO` is function-like, even if it evaluates to a constant. + - `--include-var myvar` if `myvar` is an `enum` constant. `enum` constants must be requested with `--include-constant`. + - `--include-constant MYCONSTANT` if `MYCONSTANT` is function-like, even if it evaluates to a constant. - `--include-struct mystruct` if `mystruct` is actually a `typedef` to a `struct`. - `--include-typedef mystruct` if `mystruct` is actually a `struct`. - `--include-typedef mytypedef` if `mytypedef` is a `typedef` for a primitive type. @@ -40,7 +40,7 @@ The resulting code is then committed to the source code repository. Before the c ## Linux -To run the script, most likely the header files for *libudev* must be installed (the library itself is most likely already installed): +To run the script, the header files for *libudev* must be present. In most cases, they aren't install by default (in contrast to the library itself): ``` sudo apt-get install libudev-dev @@ -62,7 +62,7 @@ SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); with: ``` -SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so.1", MemorySession.openImplicit()); +SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so", MemorySession.openImplicit()); ``` @@ -81,11 +81,9 @@ Compared to Linux and macOS, the code generation on Windows is very slow (about The known limitations are: -- Variable size `struct`: Several Windows struct are of variable size. The last member is an array. The `struct` definition specifies array length 1. But you are expected to allocate more space depending on the actual array size you need. *jextract* generates code for array length 1 and when access array members, the length is checked. So the generated code is difficult to use. Variable size `struct`s are a pain - in any language. +- Variable size `struct`: Several Windows struct are of variable size. The last member is an array. The `struct` definition specifies array length 1. But you are expected to allocate more space depending on the actual array size you need. *jextract* generates code for array length 1 and checks the length when the members are accessed. So the generated code is difficult to use. Variable size `struct`s are a pain - in any language. -- `USB_NODE_CONNECTION_INFORMATION_EX`: This struct uses a packed layout without considering alignment. The last four members are on an odd offset even though they are multiple bytes long. *jextract* creates the correct offsets but defines strict alignment constraints for the members. So the memory layout cannot be instantiated as it throws an exception. - -- GUID constants like `GUID_DEVINTERFACE_USB_DEVICE` do not work. While code is generated, the code fails at run-time as it is unable to locate the symbol. This is due to the fact that `GUID_DEVINTERFACE_USB_DEVICE` actually resolve to a variable definition and not to a variable declaration. It is not part of any library. Such constants should be skipped by *jextract*. +- GUID constants like `GUID_DEVINTERFACE_USB_DEVICE` do not work. While code is generated, the code fails at run-time as it is unable to locate the symbol. This is due to the fact that `GUID_DEVINTERFACE_USB_DEVICE` actually resolve to a variable definition and not to a variable declaration. The GUID constant is not contained in any library; instead the header files use linkage options to generate the constant in the callers code, which does not work with FFM. Such constants should be skipped by *jextract*. - *jextract* is a batch script and turns off *echo mode*. If a single batch scripts has multiple calls of *jextract*, two things need to be considered: @@ -98,16 +96,18 @@ The known limitations are: *jextract* generates a comprehensive set of methods for each function, struct, struct member etc. Most of it will not be used as a typical application just uses a subset of struct members, might only read or write them etc. So a considerable amount of code is generated. For some types, it's a bit excessive. -The worst example is [`IOUSBInterfaceStruct100`](https://github.com/manuelbl/JavaDoesUSB/blob/main/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct100.java) (macOS). This is a `struct` consisting of about 75 member functions. It's basically a vtable of a C++ class. *jextract* generates the same number of classes plus a huge class for the struct itself. The total code size (compiled) for this single `struct` is over 300 kByte. +The worst example is [`IOUSBInterfaceStruct190`](https://github.com/manuelbl/JavaDoesUSB/blob/main/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java) (macOS). This is a `struct` consisting of about 50 member functions. It's basically a vtable of a C++ class. For this single `struct`, *jextract* generates codes resulting in 70 class files with a total size of 227kByte.. -The table below shows statictics for version 0.2.0 of the library: +The table below shows statistics for version 0.6.0 of the library: | Operating Systems | Manually Created | % | Generated | % | Total | % | |-------------------|-----------------:|-------:|----------:|-------:|----------:|--------:| -| Linux | 24,140 | 1.96% | 182,774 | 14.84% | 206,914 | 16.80% | -| macOS | 57,788 | 4.69% | 666,037 | 54.08% | 723,825 | 58.77% | -| Windows | 46,085 | 3.74% | 201,000 | 16.32% | 247,085 | 20.06% | -| Common | 53,774 | 4.37% | 53,774 | 0.00% | | 4.37% | -| Grand Total | 181,787 | 14.76% | 1,049,811 | 85.24% | 1,231,598 | 100.00% | +| Linux | 48,516 | 3.64% | 197,169 | 14.79% | 245,685 | 18.42% | +| macOS | 78,718 | 5.90% | 546,907 | 41.01% | 625,625 | 46.91% | +| Windows | 104,811 | 7.86% | 256,079 | 19.20% | 360,890 | 27.06% | +| Common | 101,364 | 7.60% | | | 101,364 | 7.60% | +| Grand Total | 333,409 | 25.00% | 1,000,155 | 75.00% | 1,333,564 | 100.00% | *Code Size (compiled), in bytes and percentage of total size* + +If *jextract* could generate code for error state capturing, there would be even more generated and less manually written code. From 93fc9c5da541e10b7831a08bc2a7216749b79dc9 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 1 Aug 2023 22:12:51 +0200 Subject: [PATCH 261/433] CI/CD --- .../workflows/continuous-integration.yaml | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 java-does-usb/.github/workflows/continuous-integration.yaml diff --git a/java-does-usb/.github/workflows/continuous-integration.yaml b/java-does-usb/.github/workflows/continuous-integration.yaml new file mode 100644 index 00000000..499496f8 --- /dev/null +++ b/java-does-usb/.github/workflows/continuous-integration.yaml @@ -0,0 +1,27 @@ +name: Continuous Integration + +on: [push, pull_request] + +env: + MAVEN_ARGS: -B -V -ntp -e -Djansi.passthrough=true -Dstyle.color=always + +jobs: + + test_os: + name: OS ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macOS-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: '20' + cache: 'maven' + - name: Test + run: ./mvnw $MAVEN_ARGS -DskipTests clean package javadoc:javadoc + working-directory: ./java-does-usb From 8ad043c0b1fe47d10f2eb61dc1b70057b22da711 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 1 Aug 2023 22:14:34 +0200 Subject: [PATCH 262/433] CI/CD --- .../.github => .github}/workflows/continuous-integration.yaml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {java-does-usb/.github => .github}/workflows/continuous-integration.yaml (100%) diff --git a/java-does-usb/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml similarity index 100% rename from java-does-usb/.github/workflows/continuous-integration.yaml rename to .github/workflows/continuous-integration.yaml From c9cbd439d7c8ab467e6477a59dd05f4d4a1c02f8 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 1 Aug 2023 22:17:47 +0200 Subject: [PATCH 263/433] Maven wrapper --- java-does-usb/.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 + java-does-usb/mvnw | 308 ++++++++++++++++++ java-does-usb/mvnw.cmd | 205 ++++++++++++ 4 files changed, 531 insertions(+) create mode 100644 java-does-usb/.mvn/wrapper/maven-wrapper.jar create mode 100644 java-does-usb/.mvn/wrapper/maven-wrapper.properties create mode 100755 java-does-usb/mvnw create mode 100644 java-does-usb/mvnw.cmd diff --git a/java-does-usb/.mvn/wrapper/maven-wrapper.jar b/java-does-usb/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 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 A?*IS* literal 0 HcmV?d00001 diff --git a/java-does-usb/.mvn/wrapper/maven-wrapper.properties b/java-does-usb/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..6d3a5665 --- /dev/null +++ b/java-does-usb/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/java-does-usb/mvnw b/java-does-usb/mvnw new file mode 100755 index 00000000..8d937f4c --- /dev/null +++ b/java-does-usb/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/java-does-usb/mvnw.cmd b/java-does-usb/mvnw.cmd new file mode 100644 index 00000000..c4586b56 --- /dev/null +++ b/java-does-usb/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% From 52851c401d5a39ae0c3a4cd47ff16f1d087b918b Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 1 Aug 2023 22:26:39 +0200 Subject: [PATCH 264/433] CI for examples --- .github/workflows/continuous-integration.yaml | 17 +- .../.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 + examples/bulk_transfer/mvnw | 308 ++++++++++++++++++ examples/bulk_transfer/mvnw.cmd | 205 ++++++++++++ .../enumerate/.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 + examples/enumerate/mvnw | 308 ++++++++++++++++++ examples/enumerate/mvnw.cmd | 205 ++++++++++++ .../.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 + examples/epaper_display/mvnw | 308 ++++++++++++++++++ examples/epaper_display/mvnw.cmd | 205 ++++++++++++ .../monitor/.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 + examples/monitor/mvnw | 308 ++++++++++++++++++ examples/monitor/mvnw.cmd | 205 ++++++++++++ .../stm_dfu/.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 + examples/stm_dfu/mvnw | 308 ++++++++++++++++++ examples/stm_dfu/mvnw.cmd | 205 ++++++++++++ 21 files changed, 2671 insertions(+), 1 deletion(-) create mode 100644 examples/bulk_transfer/.mvn/wrapper/maven-wrapper.jar create mode 100644 examples/bulk_transfer/.mvn/wrapper/maven-wrapper.properties create mode 100755 examples/bulk_transfer/mvnw create mode 100644 examples/bulk_transfer/mvnw.cmd create mode 100644 examples/enumerate/.mvn/wrapper/maven-wrapper.jar create mode 100644 examples/enumerate/.mvn/wrapper/maven-wrapper.properties create mode 100755 examples/enumerate/mvnw create mode 100644 examples/enumerate/mvnw.cmd create mode 100644 examples/epaper_display/.mvn/wrapper/maven-wrapper.jar create mode 100644 examples/epaper_display/.mvn/wrapper/maven-wrapper.properties create mode 100755 examples/epaper_display/mvnw create mode 100644 examples/epaper_display/mvnw.cmd create mode 100644 examples/monitor/.mvn/wrapper/maven-wrapper.jar create mode 100644 examples/monitor/.mvn/wrapper/maven-wrapper.properties create mode 100755 examples/monitor/mvnw create mode 100644 examples/monitor/mvnw.cmd create mode 100644 examples/stm_dfu/.mvn/wrapper/maven-wrapper.jar create mode 100644 examples/stm_dfu/.mvn/wrapper/maven-wrapper.properties create mode 100755 examples/stm_dfu/mvnw create mode 100644 examples/stm_dfu/mvnw.cmd diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index 499496f8..a8b37dc5 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -22,6 +22,21 @@ jobs: distribution: 'zulu' java-version: '20' cache: 'maven' - - name: Test + - name: Library run: ./mvnw $MAVEN_ARGS -DskipTests clean package javadoc:javadoc working-directory: ./java-does-usb + - name: Example bulk_transfer + run: ./mvnw $MAVEN_ARGS clean compile + working-directory: ./bulk_transfer + - name: Example enumerate + run: ./mvnw $MAVEN_ARGS clean compile + working-directory: ./enumerate + - name: Example monitor + run: ./mvnw $MAVEN_ARGS clean compile + working-directory: ./monitor + - name: Example stm_dfu + run: ./mvnw $MAVEN_ARGS clean compile + working-directory: ./stm_dfu + - name: Example epaper_display + run: ./mvnw $MAVEN_ARGS clean compile + working-directory: ./epaper_display diff --git a/examples/bulk_transfer/.mvn/wrapper/maven-wrapper.jar b/examples/bulk_transfer/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 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 A?*IS* literal 0 HcmV?d00001 diff --git a/examples/bulk_transfer/.mvn/wrapper/maven-wrapper.properties b/examples/bulk_transfer/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..6d3a5665 --- /dev/null +++ b/examples/bulk_transfer/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/bulk_transfer/mvnw b/examples/bulk_transfer/mvnw new file mode 100755 index 00000000..8d937f4c --- /dev/null +++ b/examples/bulk_transfer/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/examples/bulk_transfer/mvnw.cmd b/examples/bulk_transfer/mvnw.cmd new file mode 100644 index 00000000..c4586b56 --- /dev/null +++ b/examples/bulk_transfer/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/examples/enumerate/.mvn/wrapper/maven-wrapper.jar b/examples/enumerate/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 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 A?*IS* literal 0 HcmV?d00001 diff --git a/examples/enumerate/.mvn/wrapper/maven-wrapper.properties b/examples/enumerate/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..6d3a5665 --- /dev/null +++ b/examples/enumerate/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/enumerate/mvnw b/examples/enumerate/mvnw new file mode 100755 index 00000000..8d937f4c --- /dev/null +++ b/examples/enumerate/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/examples/enumerate/mvnw.cmd b/examples/enumerate/mvnw.cmd new file mode 100644 index 00000000..c4586b56 --- /dev/null +++ b/examples/enumerate/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/examples/epaper_display/.mvn/wrapper/maven-wrapper.jar b/examples/epaper_display/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 zcmb5V1CS=sk~Z9!wr$(CZEL#U=Co~N+O}=mwr$(Cds^S@-Tij=#=rmlVk@E|Dyp8$ z$UKz?`Q$l@GN3=8fq)=^fVx`E)Pern1@-q?PE1vZPD);!LGdpP^)C$aAFx&{CzjH` zpQV9;fd0PyFPNN=yp*_@iYmRFcvOrKbU!1a*o)t$0ex(~3z5?bw11HQYW_uDngyer za60w&wz^`W&Z!0XSH^cLNR&k>%)Vr|$}(wfBzmSbuK^)dy#xr@_NZVszJASn12dw; z-KbI5yz=2awY0>OUF)&crfPu&tVl|!>g*#ur@K=$@8N05<_Mldg}X`N6O<~3|Dpk3 zRWb!e7z<{Mr96 z^C{%ROigEIapRGbFA5g4XoQAe_Y1ii3Ci!KV`?$ zZ2Hy1VP#hVp>OOqe~m|lo@^276Ik<~*6eRSOe;$wn_0@St#cJy}qI#RP= zHVMXyFYYX%T_k3MNbtOX{<*_6Htq*o|7~MkS|A|A|8AqKl!%zTirAJGz;R<3&F7_N z)uC9$9K1M-)g0#}tnM(lO2k~W&4xT7gshgZ1-y2Yo-q9Li7%zguh7W#kGfnjo7Cl6 z!^wTtP392HU0aVB!$cPHjdK}yi7xNMp+KVZy3_u}+lBCloJ&C?#NE@y$_{Uv83*iV zhDOcv`=|CiyQ5)C4fghUmxmwBP0fvuR>aV`bZ3{Q4&6-(M@5sHt0M(}WetqItGB1C zCU-)_n-VD;(6T1%0(@6%U`UgUwgJCCdXvI#f%79Elbg4^yucgfW1^ zNF!|C39SaXsqU9kIimX0vZ`U29)>O|Kfs*hXBXC;Cs9_Zos3%8lu)JGm~c19+j8Va z)~kFfHouwMbfRHJ``%9mLj_bCx!<)O9XNq&uH(>(Q0V7-gom7$kxSpjpPiYGG{IT8 zKdjoDkkMTL9-|vXDuUL=B-K)nVaSFd5TsX0v1C$ETE1Ajnhe9ept?d;xVCWMc$MbR zL{-oP*vjp_3%f0b8h!Qija6rzq~E!#7X~8^ZUb#@rnF~sG0hx^Ok?G9dwmit494OT z_WQzm_sR_#%|I`jx5(6aJYTLv;3U#e@*^jms9#~U`eHOZZEB~yn=4UA(=_U#pYn5e zeeaDmq-$-)&)5Y}h1zDbftv>|?GjQ=)qUw*^CkcAG#o%I8i186AbS@;qrezPCQYWHe=q-5zF>xO*Kk|VTZD;t={XqrKfR|{itr~k71VS?cBc=9zgeFbpeQf*Wad-tAW7(o ze6RbNeu31Uebi}b0>|=7ZjH*J+zSj8fy|+T)+X{N8Vv^d+USG3arWZ?pz)WD)VW}P z0!D>}01W#e@VWTL8w1m|h`D(EnHc*C5#1WK4G|C5ViXO$YzKfJkda# z2c2*qXI-StLW*7_c-%Dws+D#Kkv^gL!_=GMn?Y^0J7*3le!!fTzSux%=1T$O8oy8j z%)PQ9!O+>+y+Dw*r`*}y4SpUa21pWJ$gEDXCZg8L+B!pYWd8X;jRBQkN_b=#tb6Nx zVodM4k?gF&R&P=s`B3d@M5Qvr;1;i_w1AI=*rH(G1kVRMC`_nohm~Ie5^YWYqZMV2<`J* z`i)p799U_mcUjKYn!^T&hu7`Lw$PkddV&W(ni)y|9f}rGr|i-7nnfH6nyB$Q{(*Nv zZz@~rzWM#V@sjT3ewv9c`pP@xM6D!StnV@qCdO${loe(4Gy00NDF5&@Ku;h2P+Vh7 z(X6De$cX5@V}DHXG?K^6mV>XiT768Ee^ye&Cs=2yefVcFn|G zBz$~J(ld&1j@%`sBK^^0Gs$I$q9{R}!HhVu|B@Bhb29PF(%U6#P|T|{ughrfjB@s- zZ)nWbT=6f6aVyk86h(0{NqFg#_d-&q^A@E2l0Iu0(C1@^s6Y-G0r32qll>aW3cHP# zyH`KWu&2?XrIGVB6LOgb+$1zrsW>c2!a(2Y!TnGSAg(|akb#ROpk$~$h}jiY&nWEz zmMxk4&H$8yk(6GKOLQCx$Ji-5H%$Oo4l7~@gbHzNj;iC%_g-+`hCf=YA>Z&F)I1sI z%?Mm27>#i5b5x*U%#QE0wgsN|L73Qf%Mq)QW@O+)a;#mQN?b8e#X%wHbZyA_F+`P%-1SZVnTPPMermk1Rpm#(;z^tMJqwt zDMHw=^c9%?#BcjyPGZFlGOC12RN(i`QAez>VM4#BK&Tm~MZ_!#U8PR->|l+38rIqk zap{3_ei_txm=KL<4p_ukI`9GAEZ+--)Z%)I+9LYO!c|rF=Da5DE@8%g-Zb*O-z8Tv zzbvTzeUcYFgy{b)8Q6+BPl*C}p~DiX%RHMlZf;NmCH;xy=D6Ii;tGU~ zM?k;9X_E?)-wP|VRChb4LrAL*?XD6R2L(MxRFolr6GJ$C>Ihr*nv#lBU>Yklt`-bQ zr;5c(o}R!m4PRz=CnYcQv}m?O=CA(PWBW0?)UY)5d4Kf;8-HU@=xMnA#uw{g`hK{U zB-EQG%T-7FMuUQ;r2xgBi1w69b-Jk8Kujr>`C#&kw-kx_R_GLRC}oum#c{je^h&x9 zoEe)8uUX|SahpME4SEog-5X^wQE0^I!YEHlwawJ|l^^0kD)z{o4^I$Eha$5tzD*A8 zR<*lss4U5N*JCYl;sxBaQkB3M8VT|gXibxFR-NH4Hsmw|{={*Xk)%!$IeqpW&($DQ zuf$~fL+;QIaK?EUfKSX;Gpbm8{<=v#$SrH~P-it--v1kL>3SbJS@>hAE2x_k1-iK# zRN~My-v@dGN3E#c!V1(nOH>vJ{rcOVCx$5s7B?7EKe%B`bbx(8}km#t2a z1A~COG(S4C7~h~k+3;NkxdA4gbB7bRVbm%$DXK0TSBI=Ph6f+PA@$t){_NrRLb`jp zn1u=O0C8%&`rdQgO3kEi#QqiBQcBcbG3wqPrJ8+0r<`L0Co-n8y-NbWbx;}DTq@FD z1b)B$b>Nwx^2;+oIcgW(4I`5DeLE$mWYYc7#tishbd;Y!oQLxI>?6_zq7Ej)92xAZ z!D0mfl|v4EC<3(06V8m+BS)Vx90b=xBSTwTznptIbt5u5KD54$vwl|kp#RpZuJ*k) z>jw52JS&x)9&g3RDXGV zElux37>A=`#5(UuRx&d4qxrV<38_w?#plbw03l9>Nz$Y zZS;fNq6>cGvoASa2y(D&qR9_{@tVrnvduek+riBR#VCG|4Ne^w@mf2Y;-k90%V zpA6dVw|naH;pM~VAwLcQZ|pyTEr;_S2GpkB?7)+?cW{0yE$G43`viTn+^}IPNlDo3 zmE`*)*tFe^=p+a{a5xR;H0r=&!u9y)kYUv@;NUKZ)`u-KFTv0S&FTEQc;D3d|KEKSxirI9TtAWe#hvOXV z>807~TWI~^rL?)WMmi!T!j-vjsw@f11?#jNTu^cmjp!+A1f__Dw!7oqF>&r$V7gc< z?6D92h~Y?faUD+I8V!w~8Z%ws5S{20(AkaTZc>=z`ZK=>ik1td7Op#vAnD;8S zh<>2tmEZiSm-nEjuaWVE)aUXp$BumSS;qw#Xy7-yeq)(<{2G#ap8z)+lTi( ziMb-iig6!==yk zb6{;1hs`#qO5OJQlcJ|62g!?fbI^6v-(`tAQ%Drjcm!`-$%Q#@yw3pf`mXjN>=BSH z(Nftnf50zUUTK;htPt0ONKJq1_d0!a^g>DeNCNpoyZhsnch+s|jXg1!NnEv%li2yw zL}Y=P3u`S%Fj)lhWv0vF4}R;rh4&}2YB8B!|7^}a{#Oac|%oFdMToRrWxEIEN<0CG@_j#R4%R4i0$*6xzzr}^`rI!#y9Xkr{+Rt9G$*@ zQ}XJ+_dl^9@(QYdlXLIMI_Q2uSl>N9g*YXMjddFvVouadTFwyNOT0uG$p!rGF5*`1 z&xsKPj&;t10m&pdPv+LpZd$pyI_v1IJnMD%kWn{vY=O3k1sJRYwPoDV1S4OfVz4FB z$^ygjgHCW=ySKSsoSA&wSlq83JB+O-)s>>e@a{_FjB{@=AlrX7wq>JE=n@}@fba(;n4EG| zge1i)?NE@M@DC5eEv4; z#R~0aNssmFHANL@-eDq2_jFn=MXE9y>1FZH4&v<}vEdB6Kz^l)X%%X@E#4)ahB(KY zx8RH+1*6b|o1$_lRqi^)qoLs;eV5zkKSN;HDwJIx#ceKS!A$ZJ-BpJSc*zl+D~EM2 zm@Kpq2M*kX`;gES_Dd1Y#UH`i!#1HdehqP^{DA-AW^dV(UPu|O@Hvr>?X3^~=1iaRa~AVXbj z-yGL<(5}*)su2Tj#oIt+c6Gh}$0|sUYGGDzNMX+$Oi$e&UJt3&kwu)HX+XP{es(S3 z%9C9y({_fu>^BKjI7k;mZ4DKrdqxw`IM#8{Sh?X(6WE4S6-9M}U0&e32fV$2w{`19 zd=9JfCaYm@J$;nSG3(|byYDqh>c%`JW)W*Y0&K~g6)W?AvVP&DsF_6!fG3i%j^Q>R zR_j5@NguaZB{&XjXF+~6m|utO*pxq$8?0GjW0J-e6Lnf0c@}hvom8KOnirhjOM7!n zP#Iv^0_BqJI?hR5+Dl}p!7X}^NvFOCGvh9y*hgik<&X)3UcEBCdUr$Dt8?0f&LSur ze*n!(V(7umZ%UCS>Hf(g=}39OcvGbf2+D;OZ089m_nUbdCE0PXJfnyrIlLXGh2D!m zK=C#{JmoHY1ws47L0zeWkxxV=A%V8a&E^w%;fBp`PN_ndicD@oN?p?Bu~20>;h;W` ztV=hI*Ts$6JXOwOY?sOk_1xjzNYA#40dD}|js#3V{SLhPEkn5>Ma+cGQi*#`g-*g56Q&@!dg)|1YpLai3Bu8a;l2fnD6&)MZ~hS%&J}k z2p-wG=S|5YGy*Rcnm<9VIVq%~`Q{g(Vq4V)CP257v06=M2W|8AgZO0CC_}HVQ>`VU zy;2LDlG1iwIeMj?l40_`21Qsm?d=1~6f4@_&`lp~pIeXnR)wF0z7FH&wu~L~mfmMr zY4_w6tc{ZP&sa&Ui@UxZ*!UovRT})(p!GtQh~+AMZ6wcqMXM*4r@EaUdt>;Qs2Nt8 zDCJi#^Rwx|T|j_kZi6K!X>Ir%%UxaH>m6I9Yp;Sr;DKJ@{)dz4hpG>jX?>iiXzVQ0 zR$IzL8q11KPvIWIT{hU`TrFyI0YQh`#>J4XE*3;v^07C004~FC7TlRVVC}<}LC4h_ zZjZ)2*#)JyXPHcwte!}{y%i_!{^KwF9qzIRst@oUu~4m;1J_qR;Pz1KSI{rXY5_I_ z%gWC*%bNsb;v?>+TbM$qT`_U8{-g@egY=7+SN#(?RE<2nfrWrOn2OXK!ek7v`aDrH zxCoFHyA&@^@m+#Y(*cohQ4B76me;)(t}{#7?E$_u#1fv)vUE5K;jmlgYI0$Mo!*EA zf?dx$4L(?nyFbv|AF1kB!$P_q)wk1*@L0>mSC(A8f4Rgmv1HG;QDWFj<(1oz)JHr+cP|EPET zSD~QW&W(W?1PF-iZ()b|UrnB(#wG^NR!*X}t~OS-21dpXq)h)YcdA(1A`2nzVFax9rx~WuN=SVt`OIR=eE@$^9&Gx_HCfN= zI(V`)Jn+tJPF~mS?ED7#InwS&6OfH;qDzI_8@t>In6nl zo}q{Ds*cTG*w3CH{Mw9*Zs|iDH^KqmhlLp_+wfwIS24G z{c@fdgqy^Y)RNpI7va^nYr9;18t|j=AYDMpj)j1oNE;8+QQ)ap8O??lv%jbrb*a;} z?OvnGXbtE9zt;TOyWc|$9BeSGQbfNZR`o_C!kMr|mzFvN+5;g2TgFo8DzgS2kkuw@ z=`Gq?xbAPzyf3MQ^ZXp>Gx4GwPD))qv<1EreWT!S@H-IpO{TPP1se8Yv8f@Xw>B}Y z@#;egDL_+0WDA)AuP5@5Dyefuu&0g;P>ro9Qr>@2-VDrb(-whYxmWgkRGE(KC2LwS z;ya>ASBlDMtcZCCD8h+Awq1%A|Hbx)rpn`REck#(J^SbjiHXe-jBp!?>~DC7Wb?mC z_AN+^nOt;3tPnaRZBEpB6s|hCcFouWlA{3QJHP!EPBq1``CIsgMCYD#80(bsKpvwO)0#)1{ zos6v&9c=%W0G-T@9sfSLxeGZvnHk$SnHw57+5X4!u1dvH0YwOvuZ7M^2YOKra0dqR zD`K@MTs(k@h>VeI5UYI%n7#3L_WXVnpu$Vr-g}gEE>Y8ZQQsj_wbl&t6nj{;ga4q8SN#Z6cBZepMoyv7MF-tnnZp*(8jq848yZ zsG_fP$Y-rtCAPPI7QC^nzQjlk;p3tk88!1dJuEFZ!BoB;c!T>L>xSD<#+4X%*;_IB z0bZ%-SLOi5DV7uo{z}YLKHsOHfFIYlu8h(?gRs9@bbzk&dkvw*CWnV;GTAKOZfbY9 z(nKOTQ?fRRs(pr@KsUDq@*P`YUk4j=m?FIoIr)pHUCSE84|Qcf6GucZBRt;6oq_8Z zP^R{LRMo?8>5oaye)Jgg9?H}q?%m@2bBI!XOOP1B0s$%htwA&XuR`=chDc2)ebgna zFWvevD|V882V)@vt|>eeB+@<-L0^6NN%B5BREi8K=GwHVh6X>kCN+R3l{%oJw5g>F zrj$rp$9 zhepggNYDlBLM;Q*CB&%w zW+aY{Mj{=;Rc0dkUw~k)SwgT$RVEn+1QV;%<*FZg!1OcfOcLiF@~k$`IG|E8J0?R2 zk?iDGLR*b|9#WhNLtavx0&=Nx2NII{!@1T78VEA*I#65C`b5)8cGclxKQoVFM$P({ zLwJKo9!9xN4Q8a2F`xL&_>KZfN zOK?5jP%CT{^m4_jZahnn4DrqgTr%(e_({|z2`C2NrR6=v9 z*|55wrjpExm3M&wQ^P?rQPmkI9Z9jlcB~4IfYuLaBV95OGm#E|YwBvj5Z}L~f`&wc zrFo!zLX*C{d2}OGE{YCxyPDNV(%RZ7;;6oM*5a>5LmLy~_NIuhXTy-*>*^oo1L;`o zlY#igc#sXmsfGHA{Vu$lCq$&Ok|9~pSl5Q3csNqZc-!a;O@R$G28a@Sg#&gnrYFsk z&OjZtfIdsr%RV)bh>{>f883aoWuYCPDP{_)%yQhVdYh;6(EOO=;ztX1>n-LcOvCIr zKPLkb`WG2;>r)LTp!~AlXjf-Oe3k`Chvw$l7SB2bA=x3s$;;VTFL0QcHliysKd^*n zg-SNbtPnMAIBX7uiwi&vS)`dunX$}x)f=iwHH;OS6jZ9dYJ^wQ=F#j9U{wJ9eGH^#vzm$HIm->xSO>WQ~nwLYQ8FS|?l!vWL<%j1~P<+07ZMKkTqE0F*Oy1FchM z2(Nx-db%$WC~|loN~e!U`A4)V4@A|gPZh`TA18`yO1{ z(?VA_M6SYp-A#%JEppNHsV~kgW+*Ez=?H?GV!<$F^nOd+SZX(f0IoC#@A=TDv4B2M z%G-laS}yqR0f+qnYW_e7E;5$Q!eO-%XWZML++hz$Xaq@c%2&ognqB2%k;Cs!WA6vl z{6s3fwj*0Q_odHNXd(8234^=Asmc0#8ChzaSyIeCkO(wxqC=R`cZY1|TSK)EYx{W9 z!YXa8GER#Hx<^$eY>{d;u8*+0ocvY0f#D-}KO!`zyDD$%z1*2KI>T+Xmp)%%7c$P< zvTF;ea#Zfzz51>&s<=tS74(t=Hm0dIncn~&zaxiohmQn>6x`R+%vT%~Dhc%RQ=Cj^ z&%gxxQo!zAsu6Z+Ud#P!%3is<%*dJXe!*wZ-yidw|zw|C`cR z`fiF^(yZt?p{ZX|8Ita)UC$=fg6wOve?w+8ww|^7OQ0d zN(3dmJ@mV8>74I$kQl8NM%aC+2l?ZQ2pqkMs{&q(|4hwNM z^xYnjj)q6uAK@m|H$g2ARS2($e9aqGYlEED9sT?~{isH3Sk}kjmZ05Atkgh^M6VNP zX7@!i@k$yRsDK8RA1iqi0}#Phs7y(bKYAQbO9y=~10?8cXtIC4@gF#xZS;y3mAI`h zZ^VmqwJ%W>kisQ!J6R?Zjcgar;Il%$jI*@y)B+fn^53jQd0`)=C~w%Lo?qw!q3fVi{~2arObUM{s=q)hgBn64~)W0tyi?(vlFb z>tCE=B1cbfyY=V38fUGN(#vmn1aY!@v_c70}pa(Lrle-(-SH8Nd!emQF zf3kz0cE~KzB%37B24|e=l4)L}g1AF@v%J*A;5F7li!>I0`lfO9TR+ak`xyqWnj5iwJ$>t_vp(bet2p(jRD;5Q9x2*`|FA4#5cfo8SF@cW zeO{H7C0_YJ*P@_BEvm2dB}pUDYXq@G1^Ee#NY9Q`l`$BUXb01#lmQk^{g3?aaP~(* zD;INgi#8TDZ&*@ZKhx$jA^H-H1Lp`%`O{Y{@_o!+7ST}{Ng^P;X>~Bci{|Qdf1{}p z_kK+zL;>D30r6~R?|h!5NKYOi6X&I5)|ME+NG>d9^`hxKpU^)KBOpZiU^ z;|SzGWtbaclC-%9(zR-|q}kB8H&($nsB1LPAkgcm+Qs@cAov{IXxo5PHrH(8DuEMb z3_R#>7^jjGeS7$!`}m8!8$z|)I~{dhd)SvoH9oR9#LjO{{8O&r7w{d9V1z^syn&E6 z{DG0vlQF_Yb3*|>RzVop^{$mWp|%NDYj@4{d*-@O^<(=L=DMFIQHEp-dtz@1Rumd; zadt^4B#(uUyM6aeUJkGl0GfaULpR!2Ql&q$nEV^+SiDptdPbuJ=VJ)`czZ@&HPUuj zc5dSRB&xk)dI~;6N?wkzI}}4K3i%I=EnlKGpPJ9hu?mNzH7|H0j(mN3(ubdaps3GM z1i+9gk=!$mH=L#LRDf4!mXw0;uxSUIXhl|#h*uK+fQPilJc8RCK9GNPt=X^8`*;3$ zBBo77gkGB5F8a8)*OR10nK&~8CEMPVQyhY>i`PS{L^-*WAz$ljtU%zlG1lm%%U4Zw zms0oZR8b|`>4U1X*9JLQQ>m9MF5%ppoafz^;`7DbmmIENrc$hucekkE4I83WhT%(9 zMaE;f7`g4B#vl(#tNP8$3q{$&oY*oa0HLX6D?xTW3M6f<^{%CK4OE1Pmfue`M6Dh= z&Z-zrq$^xhP%|hU&)(+2KSSpeHgX^0?gRZ5wA8@%%9~@|*Ylux1M{WQ4ekG(T+_b` zb6I)QRGp%fRF)^T?i^j&JDBhfNU9?>Sl6WVMM%S?7< ze|4gaDbPooB=F4Y=>~_+y~Q1{Ox@%q>v+_ZIOfnz5y+qy zhi+^!CE*Lv-}>g^%G=bGLqD(aTN;yHDBH#tOC=X02}QU~Xdme``Wn>N>6{VwgU~Z>g+0 zxv0`>>iSfu$baHMw8(^FL6QWe;}(U>@;8j)t)yHAOj?SdeH;evFx-kpU@nT>lsrUt zqhV}2pD^5bC4786guG1`5|fK@pE6xcT#ns)vR|^?A08G62teHaE&p`ZrCBj_Swt*~dVt=5*RK6Y{% zABqK$X59BnrK3r3u=wxklRnA1uh+q`?T0kE1YhvDWF4OY#<(+V|R@R%tdkq2huF(!Ip+EpZF3zr*|9pmKHPo)Cu z;H+^s&`Ql}u=Jt~ZWj`bAw|i-3#7(2WuRU3DU{BW8`?!O?YO1M$*MMTsaEM!5Jyp~ z!gp6yR4$O%wQ8%dyz43ZPeoJwy;o;yg=S0^Y}%|)to>=N^`!3VMf1~}OZ`Dl$q&|w z9$!i3!i1uAgPTuKSWdBrDr*N$g=E#mdqfj*h;Z}OG`{n245+g;IKfdn!&gF2OtHaD zyGDzj@@d2!P(_Ux)3v;1ABTj__{w*kaRF-1YVU`})Acgk?(T*1YqEve3=5)8bkZK* z!Tus*e$h@^u z>#zV0771Bix~r&h2FJ9)%N{>s>?2tk1$bId)1#G;OKgn-U8jUo^AK;Hu)hQEi}swD(264kAS-SBCD$R(Ro0rh8~Le zzRwxbz_JHDbD+hTX15AWmVw!#rC)-zeZahQQmo6FG1)ah3uuyIuTMof}RO!`Y3^Fxn_-G$23RDOh(@NU?r6`*S?#E50)w zpcsgDZ-iO{;EesgDQq9;p*C#QH(sp~2w^zAJWaUL%@yo)iIL6y8;e_}=dwQc%k%;H zFt5lenH*`}LWd+fPqi;exJeRZgl&nLR%|a!%1x0RQ54cgyWBYrL>sskcAtPxi&8c( zw_K?sI*3n%S;lKiYpveBN08{rgV&-B1NN5Jiu07~%n#%&f!(R(z1)xsxtRBkg#+Lv zh21zX?aYDd_f}qdA`Os*j!eC<5)iUJ&Twj7?*p%vEOGElGhpRZsccM!<k}DeC;TY;rULQs3e}lZyP#UVb=6 zB$Dkm2FaHWUXr7<{R&46sfZ)&(HXxB_=e`%LZci`s7L6c-L7iF&wdmTJz`*^=jD~* zpOZ@jcq8LezVkE^M6D9^QgZqnX&x*mr1_Cf#R9R3&{i3%v#}V$UZzGC;Or*=Dw5SXBC6NV|sGZp^#%RTimyaj@!ZuyJ z6C+r}O1TsAzV9PAa*Gd!9#FQMl)ZLHzTr99biAqA(dz-m9LeIeKny3YB=*+|#-Gq# zaErUR5Z*Wh^e<+wcm70eW;f-g=YTbMiDX)AznDM6B73)T4r%nq+*hKcKF?)#vbv?K zPMe=sFCuC*ZqsBPh-?g!m*O`}6<}Pfj}Y1n9|Y@cUdD5GX_)6Sx9pPfS7 zxkt?g6ZwJ+50C7qrh6dMFmr7qah`FskT_H=GC92vkVh$WfZa2%5L99_DxyM{$#6HQ zx$VR-Wwt!q9JL2{ybEGJr$^?!V4m_BqDqt!mbs=QjHf340+^a{)waVvP0+98(BA$M ztWr&sM=juyYgvf`(SC}+y@QtYgU>0ghJ6VbU}|kEraR&&W%#;!#KI?le%g`e>ZVPiDrneh#&1(Y?uiMo^f5qo@{JEr(p9>8GhDa+PC9yG;lX+D?hQ^fZB&Sdox219zUj_5;+n<0@Wi3@DK`MU8FM!OFJ z8*_mTA-u!Ab#95FRVWTIqAL#BVQGxE_s?>Ql|@0o9vos&r<_4d!+Q6(_270)6#lu$ zV!j$a?_V0I<(3Z=J7C-K0a^Kc1Go9p&T6yQeAD+)dG-$a&%Fo0AOte~_Z&_m2@ue~ z9cKFf-A41Dz31Ooj9FSR`l?H5UtdP?JS=UU$jF#znE1k@0g%K?KQuwZkfDI3Ai)(q z#x_Yo6WR_Y@#6I_02S&NpcP<%sw!!M_3#*8qa+*4rS@x=i{-2K#*Qr)*Q$-{<_(<| z0730e+rubnT38*m;|$-4!1r6u&Ua2kO_s-(7*NGgDTe##%I>_9uW;X__b_k)xlv$; zW%K2hsmr>5e^Z~`tS-eUgWmSF9}Yg8E}qydSVX0nYZMX_x94QK?tw2>^;raVTqstR zIrNAX2`X~|h->dTOb9IrA!i5INpLV}99ES|i0ldzC`;R$FBY5&7+TIy8%GO8SZ37_ zw=^Swk?z+j-&0-cTE|LU0q@IKRa&C6ZlXbSa2vN5r-)*f<3{wLV*uJUw980AFkWN7 zKh{?97GmVu-0rs9FB6ludy|n`gN5p~?y51aJzBg6#+-=0pWdZ2n4xTiQ=&3As-!-6 zFlb|ssAJEJL#s8(=odfz8^9b#@RrvNE4gjuEITzAd7R4+rq$yEJKXP?6D@yM7xZ&^ z@%jnE3}bteJo{p(l`hu`Yvzg9I#~>(T;>c;ufeLfc!m3D&RaQS=gAtEO-WbI+f_#| zaVpq-<%~=27U8*qlVCuI6z9@j)#R!z3{jc>&I(qT-8IBW57_$z5Qm3gVC1TcWJNc% zDk?H3%QHno@fu9nT%L^K)=#sRiRNg|=%M zR;8BE)QA4#Dsg^EakzttRg9pkfIrF3iVYVM#*_+#3X+~qeZc^WQJvEyVlO@9=0pl!ayNOh|{j0j^a z+zi_$_0QKhwArW)sJ$wji;A`?$ecbr?(4x5%2pLgh#wggbt)#T^2R3a9m+>GcrUxU z*u-WTgHAN*e!0;Wa%1k)J_P(Vdp>vwrROTVae@6Wn04q4JL-)g&bWO6PWGuN2Q*s9 zn47Q2bIn4=!P1k0jN_U#+`Ah59zRD??jY?s;U;k@%q87=dM*_yvLN0->qswJWb zImaj{Ah&`)C$u#E0mfZh;iyyWNyEg;w0v%QS5 zGXqad{`>!XZJ%+nT+DiVm;lahOGmZyeqJ-;D&!S3d%CQS4ZFM zkzq5U^O|vIsU_erz_^^$|D0E3(i*&fF-fN}8!k3ugsUmW1{&dgnk!|>z2At?h^^T@ zWN_|`?#UM!FwqmSAgD6Hw%VM|fEAlhIA~^S@d@o<`-sxtE(|<><#76_5^l)Xr|l}Q zd@7Fa8Bj1ICqcy2fKl1rD4TYd84)PG5Ee2W4Nt@NNmpJWvc3q@@*c;~%^Vasf2H`y z+~U-19wtFT?@yIFc4SE_ab?s@wEUfSkOED}+qVjjy>=eac2^S^+|_3%cjH%EUTJ&r znp9q?RbStJcT*Vi{3KDa^jr4>{5x+?!1)8c2SqiCEzE$TQ+`3KPQQnG8_Qk<^)y_o zt1Q^f{#yCUt!1e(3;E6y?>p+7sGAYLp`lA3c~Y`re9q&`c6>0?c0E2Ap5seFv92#X z1Vldj!7A8@8tWr&?%;EBQ_Fwd)8A3!wIx`V!~~h(!$pCy7=&*+*uIzG@*d%*{qG#4 zX0^}}sRN^N=p{w(+yjv%xwb!%lnVTE7l1l6gJwQmq_G83J&Y98$S!r*L8}IiIa2E= zE!0tbOuEDb*No0-KB{zjo1k#_4FHtr{!)>o+Y@bll}Sa6D^xktI0H&l{jKAK)A(iz zB-N00F?~Z}Y7tG+vp)-q*v71(C}65$-=uXx^|R$xx9zZip-V>Hqeyfd(wteM)+!!H z$s+>g4I@+`h2>C|J;PhvtOq)`xm4;CyF}R<)!ma3T{Vf_5|zo;D4YI4ZDBkE(vMeE zb#ZV;n}CgA0w8x!UC2&5Z(K)9bibj#?~>R(72lFx_Am~jS?;7mo~p+05~XGD+(wV4 zEVYnf0N5+-7O+Gc1L!sPGUHv<6=cV8}*m$m`kBs@z zy;goR(?J^JrB7uXXpD00+SD0luk!vK3wwp(N%|X!HmO{xC#OMYQ&a7Yqv-54iEUK4 zVH;)rY6)pUX~ESvQK^w|&}>J{I?YlvOhpMgt-JB}m5Br`Q9X+^8+Xa%S81hO<1t#h zbS+MljFP1J0GGNR1}KwE=cfey%;@n&@Kli+Z5d>daJjbvuO3dW{r$1FT0j zR$c9$t~P50P+NhG^krLH%k}wsQ%mm+@#c;-c9>rYy;8#(jZ|KA8RrmnN2~>w0ciU7 zGiLC?Q^{^Ox-9F()RE^>Xq(MAbGaT0^6jc>M5^*&uc@YGt5Iw4i{6_z5}H$oO`arY z4BT(POK%DnxbH>P$A;OWPb@gYS96F7`jTn6JO@hdM za>_p!1mf?ULJZb1w-+HamqN__2CtI%VK`k^(++Ga0%z*z@k0wYJDqT^)~%|4O299; zh1_iRtc7you(kOK8?Q$R7v-@Qk4+i=8GD2_zI0%{Ra`_prF{+UPW^m5MCA&4ZUpZb z2*!)KA8b--Upp~U%f+rsmCmV~!Y>Gzl#yVvZER2h;f&rkdx{r#9mc8DZMJaQXs?SL zCg3#>xR6ve8&YkP*`Z=lng|Ow+h@t*!Ial*XQg3P;VS8@E1C)VS`?L9N+rxlD7bxC z3@Ag)Vu?#ykY`ND+GvRYTUP&-KDMiqly$Z~uFXt^)4Jjk9RIs*&$?-UPM*d7&m${m zm12kaN3mV1J|c6f$>V+{lvHp~XVW3DU0;cBR>7|)4bo{xa1-ts-lYU-Q-b)_fVVl`EP5X}+J9EzT20x8XIv=m7witdu7!3Lh=KE#OyKpT1GWk{YAo^ny|fvZt<+jmsFs=l*%e& zmRkBt5ccv4O7!HAyv2~rsq*(FmMTm?@TX3&1`nu|7C^F{ad%GLuoX}Rl}6`)uHF_xlx^gVca+mGH4T8u8;q{S*x3=j;kelz^atO~)v!Q_BT z4H6%IA}bvfuk0_vweELeEl8N5w-Q1GF!@f{VKnbyYB2?}d&QvI-j}~RI_+9t9$tC2 z94m=3eLi=sQb^S5;fqP?3aaXc&`}`lq z&M8dOXvxx9Y1^u_ZQHhO+qP}nwkvJhwoz$Mp6Qcq^7M#eWm}!3U@s07hop` zW24|J{t$aB`W>uBTssEvYMyi$hkaOqWh+^(RV_1MYnE0XPgW?7sBDk=Cqs(;$qrPEflqa0ZE?A3cBfW%0RPA235Wb6@=R_d>Sez; z`spwa50bq?-zh+id~Q!T`AYn`$GHzs;jxIw(A1_Ql&f|qP}|bon#H;sjKmSDM!nyn z>bU8l%3DB3F+$}|J^da!!pN|DO!Ndc2J)wMk!+Rr1hes#V}5o(?(yQSphn|9_aU<- zn|nsDS{^x&tweP;Ft`2ur>Koo2IdXJDsr6IN)7vB41Yy-^Wbo9*2th2QA@C zE0-0Gk12YOO?d_Guu6b3&(PIL`d zh4{`k54hu9o%v1K3PGuccez-wdC<&2fp)>`qIIaf)R{5un7-vwm=>LD7ibnJ$|KyE zzw`X*tM0S|V(I3vf454PY{yA5lbE+36_<1kd=&0Xy4jfvUKZ0$Jq!AG4KS7DrE9rph;dK^6*#CIU9qu7 z?)6O`TN&MCWGmUVd1@E2ow2`vZ1A#nGo8_n!dmX77DCgAP1va*ILU+!a&$zdm6Pa6 z4#|*&3dM+r_RJb%!0}7X!An&T4a4@ejqNJ;=1YVQ{J6|oURuj8MBZ8i7l=zz%S4-; zL}=M^wU43lZVwNJgN|#xIfo$aZfY#odZ6~z?aNn=oR1@zDb=a(o3w`IGu&j>6lYxL z&MtqINe4Z>bdsHNkVIu$Dbq0wc#X-xev221e~L zbm8kJ(Xzij$gF4Ij0(yuR?H1hShSy@{WXsHyKtAedk4O!IdpR{E32Oqp{1TD{usJi zGG@{3A$x%R*pp8b$RQo4w&eDhN`&b~iZ2m3U>@9p1o5kXoEVmHX7I6Uw4dn((mFw` zilWrqFd=F5sH$&*(eJB52zaLwRe zz`sruIc=Ck75>v5P5kd>B2u=drvGPg6s&k5^W!%CDxtRO)V6_Y_QP{%7B>E~vyMLG zhrfn8kijyK&bX+rZsnSJ26!j$1x+V!Pyn|ph%sXWr9^f&lf|C;+I^Fi_4;`-LJI&F zr;5O@#4jZX=Yaw0`pUyfF4J8A9wE#7_9!X|_s8~YUzWu&#E^%4NxUA3*jK-F5R3LP2|msHBLmiMIzVpPAEX)2 zLKYjm3VI4r#7|nP^}-}rL+Q4?LqlmBnbL+R8P%8VmV{`wP0=~2)LptW_i682*sUR# z+EifOk_cWVKg-iWr^Qf4cs^3&@BFRC6n0vu{HqZzNqW1{m)3K@gi$i}O(hT`f#bT- z8PqCdSj~FncPNmMKl9i9QPH1OMhvd42zLL~qWVup#nIJRg_?7KQ-g3jGTt5ywN;Qx zwmz4dddJYIOsC8VqC2R%NQ>zm=PJH70kS|EsEB>2Otmtf-18`jUGA6kMZL3vEASDN zNX%?0+=vgsUz!dxZ@~)eU17m4pN3xGC0T;#a@b9Iu0g_v*a3|ck^s_DVA^%yH-wt= zm1)7&q6&Rq#)nc9PQ6DKD{NU=&ul10rTiIe!)x^PS~=K(wX9|?k&{Mv&S$iL9@H7= zG0w~UxKXLF003zJ-H%fGA4Db9{~#p&Bl7ki^SWwv2sfoAlrLMvza)uh;7Aa_@FL4b z4G>`j5Mn9e5JrrN#R$wiB(!6@lU@49(tawM&oma6lB$-^!Pmmo;&j57CDmKi)yesg~P;lJPy9D(!;n;^1ql)$5uYf~f z&GywSWx=ABov_%8pCx=g-gww_u26?5st=rdeExu?5dvj^C?ZZxDv@Si^nX~2qA&K= z2jr;{=L(x~9GLXrIGXs>dehU^D}_NMCMegdtNVWyx)8xHT6Qu!R>?%@RvADs9er;NMkweUBFNrBm1F5e0_>^%CwM6ui}K_MpRqLS0*@lAcj zB6TTCBv>w2qh)qU3*kN+6tPmMQx|5Z0A4n67U-nss90Ec_rDF}r)IR4PE{$8;BSt= zT%6|jyD^(w6a*A5>_|TkMqx~e$n@8{`q?|)Q&Y4UWcI!yP-8AwBQ#P`%M&ib;}pli z9KAPU_9txQ3zOM#(x}*lN8q$2(Tq1yT4RN0!t~|&RdQMXfm!81d0ZuyD}aG3r4+g` z8Aevs3E_ssRAMR+&*Q30M!J5&o%^(3$ZJ=PLZ9<@x^0nb>dm17;8EQJE>hLgR(Wc% zn_LXw|5=b$6%X zS~ClDAZ?wdQrtKcV9>_v1_IXqy)?<@cGGq#!H`DNOE1hb4*P_@tGbMy6r@iCN=NiA zL1jLwuMw&N-e9H(v7>HGwqegSgD{GSzZ@sZ?g5Y`fuZ^X2hL=qeFO(;u|QZl1|HmW zYv+kq#fq_Kzr_LaezT zqIkG6R+ve#k6!xy*}@Kz@jcRaG9g|~j5fAYegGOE0k8+qtF?EgI99h*W}Cw z7TP&T0tz4QxiW!r zF4?|!WiNo=$ZCyrom-ep7y}(MVWOWxL+9?AlhX<>p||=VzvX`lUX(EdR^e5m%Rp_q zim6JL6{>S%OKoX(0FS>c1zY|;&!%i-sSE>ybYX3&^>zb`NPj7?N^ydh=s=0fpyyz% zraFILQ17_9<ettJJt~I+sl=&CPHwz zC9dEb#QFQcY?bk11Y=tEl{t+2IG`QFmYS>ECl;kv=N6&_xJLQt>}ZQiFSf+!D*4Ar zGJ~LFB7e_2AQaxg*h{$!eJ6=smO(d2ZNmwzcy3OG@)kNymCWS44|>fP^7QkJHkE9JmLryhcxFASKb4GYkJ|u^Fj=VdF0%6kgKllkt zC|_ov2R4cJ2QjjYjT6jE#J1J<xaNC>Xm;0SX<`LuW*}*{yQ3c9{Zl=<9NP z^2g5rAdO!-b4XfeBrXa4f{M0&VDrq+ps&2C8FYl@S59?edhp~7ee>GR$zQI4r8ONi zP^OA+8zrTAxOMx5ZBS03RS@J_V`3{QsOxznx6Yt*$IuEd3%R|Ki&zZkjNvrxlPD$m z%K+rwM!`E&Z46ogXCu!3 z8use`FJJ?g_xi?~?MxZYXEu=F=XTC8P3{W*CbG3Wk)^31nD~W>*cJ@W4xg%Qqo7rq z`pUu8wL!6Cm~@niI*YmQ+NbldAlQRh?L!)upVZ)|1{2;0gh38FD&8h#V{7tR&&J}I zX1?;dBqK}5XVyv;l(%?@IVMYj3lL4r)Wx9$<99}{B92UthUfHW3DvGth^Q0-=kcJ1 z!*I9xYAc$5N$~rXV>_VzPVv`6CeX(A_j3*ZkeB~lor#8O-k+0OOYzTkri@PVRRpOP zmBV|NKlJT?y4Q82er)@lK&P%CeLbRw8f+ZC9R)twg5ayJ-Va!hbpPlhs?>297lC8 zvD*WtsmSS{t{}hMPS;JjNf)`_WzqoEt~Pd0T;+_0g*?p=dEQ0#Aemzg_czxPUspzI z^H5oelpi$Z{#zG$emQJ#$q#|K%a0_x5`|;7XGMuQ7lQB9zsnh6b75B9@>ZatHR_6c z0(k}`kfHic{V|@;ghTu>UOZ_jFClp>UT#piDniL(5ZNYXWeW0VRfBerxamg4su5<; z(}Ct2AhR@I-ro0}DdZLRtgI@dm+V`cRZjgV-H+aXm5|Mgz`aZX63i<|oHk-E)cABn z0$NR?(>fla7)Ong28FZSi9Yk0LtYl5lZw5wT!K5=fYT$avgkMKJWx~V#i@7~6_{dM zxDDPIW2l{O2Elv#i^cjYg~lGHRj(W*9gD`(FILKY$R`tL2qo&rtU*c;li!V`O$aV{ z!m|n!FAB2>MR_FVN*Ktv5+2dW4rr3YmfEheyD+48%USM#q6)w%#2}~=5yZE1LLcth zF%VtefH&#AcMx7)JNC$P>~OFuG6sK}F7V$D7m!{ixz&inpAVpFXiu^QruAw@Sc7Y2 z_A^V(2W_+KTGRp2aQSMAgyV#b3@{?5q@hPEP6oF3^}|@8GuD6iKbX;!LI!L=P#Za zL$Zuv#=x3fseRMZ()#SQcXv->xW`C|6quwqL1M&KByBj z2V`}(uL4JB-hUs6304@%QL~S6VF^6ZI=e-Nm9Tc^7gWLd*HM-^S&0d1NuObw-Y3e> zqSXR3>u^~aDQx>tHzn9x?XRk}+__h_LvS~3Fa`#+m*MB9qG(g(GY-^;wO|i#x^?CR zVsOitW{)5m7YV{kb&Z!eXmI}pxP_^kI{}#_ zgjaG)(y7RO*u`io)9E{kXo@kDHrbP;mO`v2Hei32u~HxyuS)acL!R(MUiOKsKCRtv z#H4&dEtrDz|MLy<&(dV!`Pr-J2RVuX1OUME@1%*GzLOchqoc94!9QF$QnrTrRzl`K zYz}h+XD4&p|5Pg33fh+ch;6#w*H5`@6xA;;S5)H>i$}ii2d*l_1qHxY`L3g=t? z!-H0J5>kDt$4DQ{@V3$htxCI;N+$d^K^ad8q~&)NCV6wa5(D${P!Y2w(XF!8d0GpJ zRa=xLRQ;=8`J2+A334};LOIhU`HQ*0v4Upn?w|sciL|{AJSrG_(%-(W9EZb%>EAGG zpDY?z1rQLps`nbCtzqJ#@wxU4}(j!ZQ{`g`g*SXlLah*W9 zyuh)UWoRCknQtd~Lk#BT_qjwj&Kw8U)w=owaJ;A5ae}3)y>{neYNS`|VHJdcSEBF# zBJ6a;T)u;^i#L~LVF-X7!E$SggILXMlsEy~v}K*DM2)f@U~g|Q6I-Pss@)`>fgFWx zsq&7pe!|VA-h;@=fBF{(mR1^{1>ukTYUdyF^#A+(|I_&nm{_xaKn3h4&yMyym2k-wMFg(s@ez=DPmuB%`| z6;e@HQKB(|!PU1sW)W6~x|=8m6rL~4dQ9LTk|RzL-_(_77B4I~ZG=q7K%qHiv!FD8 zmt;Vnhb{ymaydv2V;X-5p zTt2ln?kaB9&(dH_X70^@rrCfz)nwfa9LYTHXO(IPcTEf$QiEhTpl??L+`Eetyqof8 zzl=q)?KdYni!C_9b8Z3xm7r5<5ZG-0uA`u^7Dm7k4mAsQ(rkoWy*^DZJa~#y6+hNG zh?7{D9$a9LS`a@SvZ5?C{JUHovWU9KI}z8YV4pWftx21v*Q;MpU{+b@>Or(}pwO^fu0qA3_k_Bo2}lIxvmMhucG-o>O=+R6YxZ zjs!o%K1AA*q#&bs@~%YA@C;}?!7yIml1`%lT3Cvq4)%A)U0o1)7HM;mm4-ZZK2`Lj zLo?!Kq1G1y1lk>$U~_tOW=%XFoyIui^Cdk511&V}x#n4JeB7>bpQkYIkpGQRHxH$L z%tS=WHC~upIXSem>=TTv?BLsQ37AO88(X+L1bI<;Bt>eY!}wjYoBn#2RGEP49&ZH-Z_}R_JK_ z>o*_y!pOI6?Vf*{x-XT;^(_0}2twfk`*)_lLl0H-g|}BC?dm7CU|^-gNJ~rx z($>97WTKf71$?2|V$Ybpf~Aj@ZZOcb3#uRq51%4^ts-#RMrJhgm|K3QpCsPGW=2dZ zAr5-HYX!D*o#Q&2;jL%X?0{}yH}j*(JC4ck;u%=a_D6CrXyBIM&O#7QWgc?@7MCsY zfH6&xgQmG$U6Miu$iF(*6d8Mq3Z+en_Fi`6VFF=i6L8+;Hr6J zmT=k0A2T{9Ghh9@)|G5R-<3A|qe_a#ipsFs6Yd!}Lcdl8k)I22-)F^4O&GP&1ljl~ z!REpRoer@}YTSWM&mueNci|^H?GbJcfC_Y@?Y+e4Yw?Qoy@VLy_8u2d#0W~C6j(pe zyO6SqpGhB-;)%3lwMGseMkWH0EgErnd9a_pLaxbWJug8$meJoY@o-5kNv&A$MJZ=U z^fXPLqV6m3#x%4V*OYD zUPS&WHikdN<{#Yj|EFQ`UojD4`Zh*CZO4Cv`w^&*FfqBi`iXsWg%%a< zk@*c%j1+xib(4q^nHHO^y5d8iNkvczbqZ5;^ZVu%*PJ!O?X-CoNP*&tOU!5%bwUEw zQN?P*a=KKlu{`7GoA}DE=#nDibRgecw>-*da~7&wgow}|DyCJq!-Lp8a~(zR@tO1 zgu(4s4HptPGn(HmN2ayYs@g+yx1n`nU3KM{tQHhMHBw7f#gwru$=C()`aKZAl^dYc ze7fC)8EZEXOryk6AD&-4L+4cJ&M@3;;{R)mi4=`ti7IZByr^|_HNsjcNFu?mIE)jD za2j)FPwRY!R_YR-P?URm0Pti*e#5jmfK)6EvaKCT{h)kbJl{AGr1Ekt}pG?^e z*botRf-RsB8q10BTroj{ZP**)2zkXTF+{9<4@$aNDreO7%tttKkR3z`3ljd?heAJEe<0%4zYK?};Ur*!a>PbGYFFi(OF-%wyzbKeBdbkjv^i9mn@UocSS z4;J%-Q$l`zb&r*Pb`U;3@qkc=8QaPE9KwmlVwAf01sa*uI2*N`9U^3*1lLsM9dJ(4 zZBkU}os|5YT#Z;PD8xVv!yo$-n{-n4JM5ukjnTciniiT`(cZ6sD6~67e5_?8am%!w zeCLUxq~7x-!Xg#PgKV&caC@7mu<86am{WaXo(lAemt4~I$utSp(URWpYNo$RvU*$N z#%iiA+h`(E;BUg;=I!#EaxO89bUK3*v5Nc3GPmURC5TqzC|))DsFNtJICH6oBW6#q z+B(N{ey+^mk_{!@ z)VhAWXG=_0j|0f9iJ;c404PiIFqK)(AD05Xh`Fk`r$^b`v+>*g+_+h@r)e+ELJ45) z?20~u<}HQyQ5AsBz(teF9!!_GLXnm{5Z0e{Ki*@!=&3x4-RcjBn##DDzHJ|KSZ5(E z9=tFZ)p~-}x%9sCY27)2i>(E-^OiYT?_)a;yXAGR$y+E`myMd;xDA#_Q49t*E}&ql#H~|x z2J2R1_#2lt91NnF!uqW%_=HlbF?A{B{n>}9$g5QF!bh_a7LTU~Jyz}7>W5{_LAov{ zy2_dmGy)d)&7^bJyUjEw%3xj{cuG0Eo zwL*XQB*Oi=r&HIIecC1%lbE;Y-*5|cL955S+2@uR18JDL<0;;Uc2Q9JEyo1R!!sz_ z#BqnkGfbLP#oQJk3y}nwMd(3Tt^PVA#zXnYF7D0W1)#+`i?@cm}fBkKD z+Mpcuim53|v7;8Tv(KraEyOK`HvJq^;rlNzOjIbW&HJDFqW>doN&j7)`RDv#v|PQ+ z03WnB4Y4X@Fe-@%3;He*FjY1MFmkyv0>64Cp~FIDKQTwmFP~_CxZOf{8gPy}I<=JC zo%_bmue&$UU0|GG%%99eI!m#5Y1MD3AsJqG#gt3u{%sj5&tQ&xZpP%fcKdYPtr<3$ zAeqgZ=vdjA;Xi##r%!J+yhK)TDP3%C7Y#J|&N^))dRk&qJSU*b;1W%t1;j#2{l~#{ zo8QYEny2AY>N{z4S6|uBzYp>7nP_tqX#!DfgQfeY6CO7ZRJ10&$5Rc+BEPb{ns!Bi z`y;v{>LQheel`}&OniUiNtQv@;EQP5iR&MitbPCYvoZgL76Tqu#lruAI`#g9F#j!= z^FLRVg0?m$=BCaL`u{ZnNKV>N`O$SuDvY`AoyfIzL9~ zo|bs1ADoXMr{tRGL% zA#cLu%kuMrYQXJq8(&qS|UYUxdCla(;SJLYIdQp)1luCxniVg~duy zUTPo9%ev2~W}Vbm-*=!DKv$%TktO$2rF~7-W-{ODp{sL%yQY_tcupR@HlA0f#^1l8 zbi>MV~o zz)zl1a?sGv)E}kP$4v3CQgTjpSJo?s>_$e>s2i+M^D5EfrwjFAo(8E%(^ROV0vz0o z-cg0jIk24n!wxZainfH)+?MGu@kg$XgaMY-^H}z^vG~XC7z2;p2Kv`b^3S#b5ssMOJ7724v>S36dD zeypxJ<=E~sD4f5wX060RIF-AR0#{Z z=&y$r8A-e6q18lIF{@O9Mi%dYSYT6erw!@zrl=uj>o(3=M*Bg4E$#bLhNUPO+Mn}>+IVN-`>5gM7tT7jre|&*_t;Tpk%PJL z%$qScr*q7OJ6?p&;VjEZ&*A;wHv2GdJ+fE;d(Qj#pmf2WL5#s^ZrXYC8x7)>5vq_7 zMCL}T{jNMA5`}6P5#PaMJDB2~TVt;!yEP)WEDAoi9PUt89S2Cj?+E0V(=_sv4Vn6b z_kS6~X!G;PKK>vZF@gWpg8Zuh%YX^2UYPdCg7?EH#^gkdOWpy(%RnXyyrhmJT~UJw zAR;%Zgb6z(mS+o9MT|Sc6O({!i0pzk;s9?Dq)%tTW3*XdM3zhPn*`z45$Bg!P4xfy zD*{>30*JsSk?bQ-DgG62v>Vw-w`SA}{*Za7%N(d-mr@~xq5&OvPa*F2Q3Mqzzf%Oe z4N$`+<=;f5_$9nBd=PhPRU>9_2N8M`tT<-fcvc&!qkoAo4J{e3&;6(YoF8Wd&A+>; z|MSKXb~83~{=byCWHm57tRs{!AI<5papN(zKssb_p_WT@0kL0T0Z5#KLbz%zfk?f7 zR!vXBs36XaNcq5usS7<>skM_*P$e*^8y1ksiuokbsGFQ_{-8BAMfu!Z6G=88;>Fxt z|F-RU{=9i6obkTa0k~L#g;9ot8GCSxjAsyeN~1;^E=o5`m%u7dO1C*nn1gklHCBUw z;R(LgZ}sHld`c%&=S+Vx%;_I1*36P`WYx%&AboA1W@P;BvuFW+ng*wh?^aH4-b7So zG?9kFs_6ma85@wo!Z`L)B#zQAZz{Mc7S%d<*_4cKYaKRSY`#<{w?}4*Z>f2gvK`P1 zfT~v?LkvzaxnV|3^^P5UZa1I@u*4>TdXADYkent$d1q;jzE~%v?@rFYC~jB;IM5n_U0;r>5Xmdu{;2%zCwa&n>vnRC^&+dUZKy zt=@Lfsb$dsMP}Bn;3sb+u76jBKX(|0P-^P!&CUJ!;M?R?z7)$0DXkMG*ccBLj+xI) zYP=jIl88MY5Jyf@wKN--x@We~_^#kM2#Xg$0yD+2Tu^MZ1w%AIpCToT-qQbctHpc_ z>Z97ECB%ak;R<4hEt6bVqgYm(!~^Yx9?6_FUDqQQVk=HETyWpi!O^`EZ_5AoSv@VbUzsqusIZ;yX!4CsMiznO}S{4e>^0`c<)c~mC#*{90@+T@%EQ~>bovc8n_$bvqkOU7CrYe8uI5~{3O7EijeX`js z-$LNz4pJA7_V5~JA_Wl*uSrQYSh9Wm($%@jowv^fSPW<~kK&M*hAleywHd?7v{`;Y zBhL2+-O+7QK_)7XOJAbdTV-S`!I)t~GE8z+fV7y;wp#!wj75drv;R*UdSh(}u$%{VSd0gLeFp;h6FkiVz%g=EY3G#>RU;alRy;vQmk*| z@x-ba0XKE%IyL4OYw6IXzMiS(q^UDk=t(#XgkuF`{P?=k8k3r)rmhkv`vg@kiWd34 z-~t+1aV3SabTbG=nQYs>3~E<}{5@0g**LAWi*~SfRZhGcgP{e5T!0M7CU}`f@r8xI z0bx%sI!?5);-wG+Mx&S=NRfIi>V-wP(n&$X0Bhd)qI^ch%96s6&u7qpiK8ijA=X_R zk&|9f$GXf-;VgnrxV83Cp-Q!!sHH`5O^o~qZu!xny1t?(Au(EAn)D??v<1Uo;#m7-M@ovk|()C(`o>QMTp}F?> zakm3bHBKUjH-MHXDow7#Z|@wea1X9ePH;%YA)fCZ9-MD)p^(p!2E`aU9nmJlm;CXQ zkx~$WQ`Yq{1h5k>E>Ex{Z=P=)N*0b8_O({IeKg?vqQ)hk=JHe z5iqUKm!~mLP0fnRwkCO(xxTV@&p+o8wdSP$jZofYP}yEkvSc z5yD-^>04{zTP7X44q9Af&-wgt7k|XtncO&L@y-wFFR44RsPu57FRvIBaI^Pqy_*DV z@i13CsaR5@X@xH=NT3}T`_vsy!a02n80eQqya=-p7#YW`Jc0z!QglGg`1zeg6uXwI zsB~hlNMo)kFL(V3Q1<%8yoI6X7ncn-&&Uh3rL@S(6@wKAXt6Wr=a2ObI7}8$D-FoI z>AJA>WsBEMi5ba6JhJ%9EAi&ocd(ZsD|MsXwu@X;2h#|(bSWu@2{+c7soC`%uo{sMYq&Vyufb)?OI59ds)O+kyE8@G z@tlpNr0UO~}qd0HQve6njJ zda2+l$gdX7AvvGhxM6OToCuQ|Zw|9!g1)O+7>~{KNvASjp9#Cqce-or+y5xdzWL3gLWt2oa+T(I+{j(&bF1laUsJB{fOgE-B}qslaS>C z)TjzG8XecbS%a+?yT!0QmTex?E478;D|sL*oS4C-g0Tq(YoH|eyxJ#1j088C|U-w5id`%Sz7X_w#l+U9+)$|2no<}5J zRb_9@0esSr?n}HvVGbD5@$p$8k4?qOe-GNOk3-K^Mw>Xg+drCKi5@$GTeijpI;;IG ziD<&go`ptLC&^<0jw^l0aY?_pUUK+xp#0Bk66iQ29vpR)VBE{JOJ&OL^gKsN<&t<| zCMLTYMSDG5Ie9O>6Dl#T{@cscz%)}?tC#?rj>iwQ0!YUk~R z$rB-k=fa9x&631Z9Mfqj_GRoS1MzqSMEdaZ2!isP19Sr>qG8!yL(WWF)_&{F)r>KnJGSciSp!P0fqHr+G=fGO02Q#9gHK zpwz+yhpC4w*<9JO@#(MdkZcWbdCO5B!H`Z|nV?UtcBo96$BgX+7VYMwp@b-%;BrJu zMd*K!{1txv{kHKPDs9?WZrz_^o1Tq2P=+=|E=Oy4#WE{>9}*9(apqhmE`&AeBzQgQ zELFLCmb~q|6y0FCt|B}*uI*ayZ#6=$BpGtF{Jfye#Q>FZ?BPnk)*Qmd?rNG^tvFUU z_b&antYsZnUR6Q9tQUy81r$&ovT#fy;(Db4F&M*C=KxQgHDrRcVR#d+ z0(D|*9#u`w_%2o3faI{?dNd9$#5nj1PROHNq z7HJ(;7B1ThyM>a@Fo^lJb2ls2lD`}ocREH|5pKN;$>gFyM6k)kZG;lA;@kSJIqUhf zX%dhcN(Jtomz4(rNng&1br3Xx33EvCWz%o8s;SpRiKEUFd+KJ+u|gn|J85dZ)Exc&=V|Ns8Xs#P>qv6PX&VAJXJ(ILZO!WJd0 z`+|f5HrEj~isRN7?dBHotcPI7;6W48*%J(9 zftl1Tr`bKH*WNdFx+h;BZ+`p!qKl~|Zt5izh}#pU9FQKE97#$@*pf38Hr8A+`N+50U3$6h%^!4fBN zjh^cl#8qW5OZbvxCfYzKHuyeKLF4z^@~+oqlz9(Hx8vypIiUlt!(vs}_t#4@nh$s; z>FYERg*KD#Xs+W4q-V-IBQK!)M1)Aa+h+V+is)z!_=gEn&^ci7<DEEmYcoSh?WdXUsP7O4)&lQXA(BVM5jI8s6;mO}94AC0gG(`>|T)yuV1l~i-ejCCt zoejDhX0nrZDP|x9u4zp%S2UeDzV`o#pBGu1tZ-$<9TIbN=ALwhQ0=9S{8#}Uu8n-~ z5~xIvUhLSz@c@0|me$CdZCpZl(vQw@a0Y4^{T0w_>pOkwI^x4KkBf3qGmm)nG|Ps5 z_XTY~^b^mL&_*yjl~RRIi&eS(>y?y}O4-)nWyTEPpQAb#Xz8SnnfIL+nAcNL9nqV9 zRL|eyF)RKI5-kJO6}>Q89XmgY@b1&!JI>g3ryZ@jN2v3vm7O`AL!BTWNouJzV+$+Y zYY}u%i>K6=IYU2O$2TAyVjGt?wgF9xCj;?EK(8fWu!!~48`3u^W$eUlCh*91PLxu1 zRY(F7Q3s7h$Q-p&L$ucN}it*-9KR z_<wHu?!dav0$P+PI3{J8?{+l|n&2YMLV2 z+hRta$A5WpCXl1RNbYBsX8IGX{2v>U|8_I-JD56K|GexW>}F_e_g_1r?08v8Kz{V$ zT=6aGMk>ibvRO@Yrc@ezaD0%ydHkXGHrR{7>q~~tO7ChJflwa4-xL|@#YIJejC5VT zInU4CjQ9V0+lClQY=vh^s4MadwQmk7li{54Y;Ht}gkZOIh9(vfK?3kXLoD72!lHD# zwI-Jg|IhT=Y#s|tso1PWp;|aJ2}M?Y{ETyYG<86woO_b+WVRh<9eJu#i5jxKu(s~3 z4mz+@3=aNl^xt{E2_xewFIsHJfCzEkqQ0<7e|{vT>{;WlICA|DW4c@^A*osWudRAP zJut4A^wh@}XW4*&iFq|rOUqg*x%1F+hu3U6Am;CLXMF&({;q0uEWG2w2lZtg)prt` z=5@!oRH~lpncz1yO4+)?>NkO4NEgP4U~VPmfw~CEWo`!#AeTySp3qOE#{oUW>FwHkZ3rBaFeISHfiVSB7%}M) z=10EZ1Ec&l;4 zG98m5sU!pVqojGEFh8P{2|!ReQ&hfDEH2dmTVkrS;$dN~G2v-qnxn^A2VeHqY@;P} zudZD5vHtVvB*loIDF1M7AEEvS&h0;X`u}!1vj6S-NmdbeL=r{*T2J6^VA7F`S`CDd zY|=AA6|9Tu8>ND6fQhfK4;L3vAdJPBA}d6YOyKP&ZVi%z6{lbkE|VyB*p1_julR^k zqBwjkqmFK=u&e8MfArjW-(Ei8{rWso1vt5NhUdN|zpXqK{ylJ8@}wq-nV~L4bIjtt zt$&(1FTIs+aw}{&0SO4*sa0H2h&7g}VN5uYjfed5h7eGp$2Wu*@m9WIr0kxOc}fX9eOWh zFKfV>+SD$@kESKYm{F*J90XQjr$!<~v(J%&RMuQM+6CkmnYZDGlOUdq}%)VA& zl#acS%XE2KuX~7IamK`og@C`21~*cEEc#PZM6HT*Veb_l&Ej~j0zL7p0Eo`mMu(=X zJ$v;&Lya75I4C^saKROgfi(fdP0C$GM3WyZn%mm3yEI>|S&O(u{{S<}ihUp#`X&_z zmQBma;82#`C;dR5Sx09e07FvtJLhZ{9R~|$FCdU6TDNUwTc9kNct?8e@o2MpQDrkg zN?G+aYtTjiUPA=RX5o{4RYu}6;)ET>TcgL^VpfIpluJ|lQR(_)>6k%L^FZmoK-Wm- zR5qy0P)hm8yvqOL>>Z;k4U}!s?%1~7v7K~m+gh=0c9Ip_9UC3nwr$%^I>yU6`;2kV z-uJ%y-afzA7;BC7jc-=XnpHK+Kf*tcOS>f5ab2&J&5hIOfXzs=&cz|Qmrpu6Z);`R z0%3^dioK5x?o7t~SK7u5m{dyUZ#QUPqBHYn@jETeG>VU=ieZuJ;mm^j>dZM7))cw?a`w8R z%3M0R=kdOt^W^$Kq5Z%aJ(a$(*qFpy^W}Ij$h+Jnmc9eaP(vB@{@8t zz=RQ$x4XYC#enS$fxh@;cSZ|D%7ug;0z{C8I8h{KocN-cyv3UG_nk99UNS4ki^OFkYea`q`rs zG@qdMI;4ogcd5Tr`di1JBg4I*6CFvCID_2SN5&)DZG&wXW{|c+BdQ4)G9_{YGA@A* zaf}o^hQFJCFtzt&*ua~%3NylCjLtqWTfmA-@zw;@*?d&RE3O8G&d;AVC|rZrU}jx# zC-9SF`9;CbQ(?07o8Q9E12vi)EP@tOIYKEKnO@-o!ggkC)^#L-c40iZtb4Y-cS>$I zTn~+>rn*Ts>*y*z^b3-fAlne+M-*%ecrI^rmKAVv23cB`aWD?JDJ5NIafRvRr*~~C z)99Afs`BPK!5BFT)b_^8GyH*{22}yDq;be`GnPl=vW+ITnaqzl(uYOHhXi}S!P+QZ z4SwfEPuu&z4t#?6Zaw}bvN{;|80DfxCTuOdz-}iY%AO}SBj1nx1(*F%3A-zdxU0aj z`zzw9-l?C(2H7rtBA*_)*rea>G?SnBgv#L)17oe57KFyDgzE36&tlDunHKKW$?}ta ztJc>6h<^^#x1@iTYrc}__pe0yf1OnQmoTjWaCG`#Cbdb?g5kXaXd-7;tfx?>Y-gI| zt7_K}yT5WM-2?bD-}ym*?~sZ{FgkQ9tXFSF zls=QGy?fZ=+(@M>P3Y>@O{f44yU^fP>zNzIQ0(&O$JCd_!p?2;} zI6E1j@`DxzgJvqcE@zgapQ?tophO14`=14DUZ*#@%rRi``pi0lkNgidSsHGjXK8gO{drQoNqR&tRjM4>^DtW`)fiRFO4LE=Z+nCBS~|B3gZsh`Y?-$g z@8@Z$D7C!L9l=SWoE;(+*YirPLWvBd$5Ztn3J3EaGM+#pW#@{3%yksGqy(2Bt5PVE zf*fICtPp77%}5j#0G8<=v=)LR>-a3dxja8cy3m$=MZ2#$8mbLvxE%NptMd+L?mG`v zF1cANFv17DqP^P5)AYHDQWHk*s~HFq6OaJ3h#BUqUOMkh)~!(ptZ2WP!_$TBV}!@>Ta#eQS_{ffgpfiRbyw1f)X4S z_iU`lNuTy86;%!sF3yh?$5zjW4F?6E9Ts-TnA zDyx5p1h$Z3IsHv7b*Q{5(bkPc{f`2Wfxg*Z#IvQ;W_q9|GqXGj<@abo)FyPtzI~i25&o zC!cJR%0!}lLf^L2eAfZg7Z69wp{J?D6UhXr%vvAn?%)7Ngct4Hrs@LZqD9qFHYAWy z4l=2LI?ER&$He2n`RiG&nsfLv?8$Cl)&d8a-~-N`I|&EPa@Y=v@>0Gl?jlt>AUY;H z`**5bpS#VGhdp4pKbf3iEF*>-eXg_$bqt5Dc%q0+)R50>zd^l7sN5R5Z)Ut+oz-8_ zJ`Z9HE9(=wRTD)T=%GZTEi9K5naPzlfE$|3GYGLRCLsnqLi8Sc6y&iskqA&Z$#7Ng z7Q@C0)6k;J$TlQ+VKZ5)-Ff_BNoIMm+~!@Cv1yAUI-U!R)LHc@+nSUzo$GlRb+8W< zYPG%NFfr;!(RlnvBbN~~EpT6Xj5*^Z&73tdIQ$LZu`vkfzdTKa5|JJtQ_rm4g$9LO zKtgYVdW=b<2WGM3I_j|Rd8gZ3j;)S#AT(aP^d>9wrtQS_+K>pZDX^?mN!Z>f^jP@1 zlJ;i79_MgOAJa`%S9EdVn>ip{d!k6c5%zizdIoB9Nr!n`*X#%6xP1?vHKc6*6+vKx zmEt|f^02)S_u_wlW_<`7uLQU%{wdH0iojOf_=}2=(krE<*!~kn%==#0Zz`?8v@4gP zPB=-O-W=OO3tD19%eX>PZj3YfrCt0sEjgTd#b$buAgBri#)wW14x7QcHf2Cneuizz z368r7`zpf`YltXY9|2V{stf8VCHgKXVGjv$m!hdDf0gi`(Q!(Pyg~FO28Vr#!BYP| zI)qG2?Ho=1Us9dTml}-ZOR?g5Vk)f+r=dbCN*N1=qNfG>UCLeA8pd3Ub-pRx1b3FA zEn`CIMf`2Mt3>>#3RkE19o}aMzi^C`+Z>8iIPHSdTdmjCdJBtNmd9o0^LrJc9|U9c zD~=FUnSyghk7jScMWT|SHkP(&DK$Z=n&lGm+FDTpGxfoIyKV)H6^nY~INQ#=OtIT! zyB*J=(#oHf=S)MNOncW->!c0r0H#=2QzobO&f@x&Y8sYi-)Ld;83zO$9@nPPhD}yt z{P`*fT@Z(?YAmF{1)C;o?G@dfd2$c+=Av*|;P@Yz1KnclB-Z-fJQ-=+T*g>0B7!g# zQH{dHt_%wj=wlmT&m59)TQ~xK)gB6f^EY$=1zcbGf~Q>p_PzDCHR6lndGmqPY2)&w z$Th^K%1v@KeY-5DpLr4zeJcHqB`HqX0A$e)AIm(Y(hNQk5uqovcuch0v=`DU5YC3y z-5i&?5@i$icVgS3@YrU<+aBw+WUaTr5Ya9$)S>!<@Q?5PsQIz560=q4wGE3Ycs*vK z8@ys>cpbG8Ff74#oVzfy)S@LK27V5-0h|;_~=j1TTZ9_1LrbBUHb?)F4fc)&F7hX1v160!vJc!aRI>vp*bYK=CB(Qbtw7 zDr2O^J%%#zHa7M5hGBh#8(2IBAk}zdhAk$`=QYe^0P6Bb+j5X)Grmi$ z6YH?*kx9hX>KCI04iaM_wzSVD+%EWS)@DR&nWsSBc2VIZ>C(jX((ZiV0=cp}rtTO&|GMvbmE4FpBF5Rd z6ZG=>X&>N3?ZN2^11pXEP4L?XUo`qrwxgQm4X~RCttXmZAhnhu4KDK=VkKq?@@Q_Z za`*xyHrsAEsR zV(7)2+|h)%EHHLD3>Qg{>G|ns_%5g5aSzA#z91R zMDKNuIt@|t?PkPsjCxUy&fu^At*yUYdBV!R_KOyVb?DO&z$GLJh9~b|3ELsysL7U6 zp24`RH+;%C(!bWHtX&*bF!l-jEXsR_|K~XL+9c+$`<11IzZ4>se?JZh1Ds60y#7sW zoh+O!Tuqd}w)1VxzL>W?;A=$xf1Os={m;|NbvBxm+JC@H^Fj$J=?t2XqL|2KWl$3+ zz$K+#_-KW(t)MEg6zBSF8XqU$IUhHj+&VwsZqd7) ztjz$#CZrccfmFdi_1$#&wl~A*RisBaBy~)w|txu1QrvR1?)2mb&m2N$C(5MS%hSX)VJnb@ZGXB5^%(<#1L@ zL^>fBd+dEe`&hxXM<0A9tviIs^BDkByJdc~mtTYr!%F7Q1XnK2$%h$Ob30*hSP$Bt zDd#w{2Z%x^Wpv8!)hm>6u01mY!xmPgwZ#Q0148)SxJc3Udt!-&}eRO^LN ze26pQB!Jhg&Z>#FD>`C`sU44><=v>O>tJdLs!HPpV#AM32^J@Za-9J(CQjKxpzXao zQfRkWP%g9P8XV21MmoHfx{DICLSc*t4qVeQL9t}&Pz0rM}YTba@XsD=XMW@FxFM{QYQJHvM(JsUSa3mcTUl9^qcVA zBveO--fqw%{#QGR1vy;x88+qMcgzmcYc#8U`CPPt6bl?uj%w_`b~9JliftnOa|ziW z|6(q&STs_*0{KNa(Z79@{`X&JY1^+;Xa69b|Dd7D&H!hVf6&hh4NZ5v0pt&DEsMpo zMr0ak4U%PP5+e(ja@sKj)2IONU+B`cVR&53WbXAm5=K>~>@0Qh7kK*=iU^KaC~-ir zYFQA7@!SSrZyYEp95i%GCj*1WgtDId*icG=rKu~O#ZtEB2^+&4+s_Tv1;2OIjh~pG zcfHczxNp>;OeocnVoL-HyKU!i!v0vWF_jJs&O1zm%4%40S7_FVNX1;R4h^c1u9V@f z`YzP6l>w>%a#*jk(Y82xQ@`@L(*zD&H>NY`iH(iyEU5R$qwTKC5jm4>BikQGHp^)u z-RQ`UCa70hJaYQeA=HtU1;fyxkcB2oY&q&->r-G9pis)t$`508$?eDDueFdW=n5hJ z08lH$dKN$y#OEE@k{#|<%GYY=_c~fHfC@pD54KSP9{Ek@T47ez$;m$}iwR}3?)hbkwS$@p2iVH0IM$lB*XYA+#}-re|UNzCE)SOYwy z=Y!fkG4&I%3J(_H#UsV#SjHulRIVcpJ`utDTY{k&6?#fzt~@Om=L(vs6cxAJxkIWI z@H7)f2h%9!jl@C!lm+X4uu;TT6o0pd7 zteFQ(ND@djf#o2kTkjcgT=dHs7ukmP0&l8{f;o3JuHGd2Op*?p7?Ct=jA*tIg{MZk z$2Lsc0e8Tdcwrjx|_Ok?9uB3Il|^2FF%X#ck}WoIvrzQXN%kT$9NI{79Wm~gZ3`8I+O`)`n30feZ( zDO-fl6IG3c^8S;Y_M-)+^CmM0tT^g0?H#>H8!oC8W%oU!~3|DJ?)~LT9*&GAQG13zOGq6gs*={cu|(V7{R$y@{-iV*9q@AD(#Ktb}J&3&k|5Djs$)9WM7!6#EaJ_ilvbfUvyh8c?-{n zfuFrC0u6}UJZ7aj@(cNG_(CKgjQQTA-UK@-MVmick zot}6F%@jhq(*}!rVFp5d6?dg|G}M*moyLriI!PQDI;E1L1eOa6>F9E6&mdLD>^0jJ z09l?1PptuV65gm=)VYiv<5?*<+MH~*G|$~9Z3XEy@B1-M(}o&*Fr9Sv6NYAP#`h{p zbwbUE3xeJ;vD}QMqECN)!yvDHRwb7c1s6IRmW!094`?Fm!l~45w)0X`Hg+6Y0-xf# zSMemBdE)Q=e^58HR{kWrL5-H0X6pDu%o{0=#!KxGp0A;6{N5kI+EoY_eTE%2q|rwm zekNeLY-R?htk!YP2|@dbd8TWG4#G)=bXlE{^ZTb^Q$}Er zz)Fp)ul24tBtQFIegdI37`K$VR3tVdi<(fIsu{#QMx=$&CK9M8oN%3Mk;>ZPd-;Q- zn|sSKSnc-S0yrw#TlA$+p{J~u=u98s>IoL@cNLOxH=+1m?;t1bR$vR=M$US&Z8DO3 z_&zhQuId1$wVNsS=X?&s(ecIi#00o{kuPs6kpYkL$jMyGW8U7mlCVaZeEL=HsIxqm zFRLxWin8B>!Dc#9Z#t0RNQiR-@5J+=;tC7|1D*~rxcwHa5iIVD@99cCFE@BukUC-S z^iJdt?dwU)kH2VY9?|zVShMbZctzFRz5Q4tiXa^>@U%jDYq}$rSyc#p2wXr}mc0qq z^lT>$y)N(Qg0dwmEwTopneoU(y)>Mj+f{iHM0o|>ZtCg-itPj4addYz??aE)Rp&hk z_SI)%XeSf=SjZq18h!Cc>Xy&EynnxdHQ){(x@g|ZA%`3LU^KzX02c5N;F#tEk1)7v z(|V9tO3>?^X|kQ*rRBf4>mWW2$-Lx})|M7z125&VHcxsCqB!<$l1F$zCrJ+nm0f3Z z%Hq^=SKpHyV2@Y*Cu2x>fXC0SscnR*($zEB{KOniJcpn@e`PMH*_Q6*0Z^8RNCEvZ z+UU9!927p9YZ&g=bnUvQUZcdisyn;-4;ACXOe-Xor9K8Qbp{ldE17+G@VQT+9ZJQ*9dZoXfU2ue|mMhrrZk2R7&~YjFW4`BTq45UwVc6JORKU)wBCTanITh0GD}s$`C5pb(9{b9 znwee6j%?-UV)_7opOioCf5@C?@w^@g& z&68+oMmV;5JW@TT63&CSDrfYL2$L)pVseDtAwPwleEM3F^-Ufn3PpfxFmx6o zQ`Wq9x#d$e`VKn5LOXNsrqhGao7~|s(u~drPrZ+;aP!C%z4NskZstCbAibD}O%8Ij zb~C(taxco~WzJLxhL1T}3ctXMbV6}_z=IZN9L0|SxLSe`$X`<)BhM`$1&&)e_}fCh z=idVL<+u6Vn{&ksP*ZLlMo$fC`dtzF_?~L?4Rril2G4%v5^7sUa^&8aMtMX&mtapl zD(dW|cisM3fqMaB`8?QbkyiUl2g>hMB5EoS&IB8TdoC~)b$nT=`%GgU`k-)+8}`)F*~I~DXMaTP%kZftx11~?iALs5J+&Rom#p%Y z>dH}-euH4u=_V3hc6^*2WMtL!9%yRTJ93p}@aV0zdY*?xchFI>m+UivV=;aMFp0P~ zwB8P)wvV6D-GL?6hJ#g7Hy7=2i^&Od#S=j!;Rc_yjO!*4aN7{vqzg2t-R|Dav%_NDk z`H_FVlSi==(~f-#65VmQ{EE92x<03lwo5p)s=ZJ^L7PlS>132Whr zR6v~t(#I+(`usYLCoO;Rt8j&b^5g_xgs*98Gp|N}b>-`HtVm)MscD)71y?(K6DRCZV26RsHPHKk)EKKZA%C99t3$t^B0-k5@?E>A-YMbFe?>ms?J?_guHHNU(;id*>xH zTrtam+Aq?n@-y@uY@A?hy?1qX^eLu_RaH4Ave?A8NapgQF=C%XI7wlcCf4<6BRo_% zBXxxc*A6-3CruF?3i8HOdbc%>N=-iiOF+9HX|ht6SCkz;A^am&qi_I&qk1B(x<=(m z>QG)nswCOLl_1{SZ@_eE#m^qb6#6DoMsB*)`17ui+XvF%(}|J4G$z2G*;E!1ERnAH z@q%=#uV6kBddqy4=g>!VTV)9*1=i{wJ}Ep!I*?)uJdA(LwE?(!?;}_u=^M2NShWC_ z*7l4aBJ=!QVU2-iehgb`$vOI8zkm{W%QO~?xOD;NgI;Iqa3#^$^U5D&McReLe&qs# zR<^@QpR4#W~Laz+QBsPt@3L#KF`Yr8}jgHe;5(cfpQ=;Zjtbt;c%y^#-m=hqOT z;KAYakW+$w0&F}>K10&SiPcD9SrDOuczj@U#W})5jGU-_htU`U6Q%wdy((%?J}y+$ z=$4jw1N nJo)qTxG{D(`3*#8tY|67hJRF;)r6F|#I`Ar6I0aafRa=kr-Z0I^}9xf^u;G5iEQCbpv3b#S#%H|HYHsQaHK$! zU#3Fpz8*^pK%RRmX<_09eIVziB0jOgPgFnI-*QcwEBtBiO#v!>{W1cLNXyw3D9M|A z*oGy(u8BkDA1c;MsXmpK^-~pl=We^RYnhZ4bz*)Q)C2G+E3tgx9PzU0T>c|1ilS!T zyE=bz`=wskDiOi!@!l?Y))#%{FM`}7r~X)i1)1*c6_2Q!_1{)fp%cS|YF+Q-CB%d< z=zYus`Vt@Mx*a7V)=mpLS$-5viaKgNB=+zN657qy0qR94!cTtX-Z%KBCg4OKw7b=t zr=`7q5Ox=lJ%!G5WIyNQC1xpqYU0{!I$hyrk!6%De$gp<_*Gc?ES(OwY8U^)Kjgc{ zSlhpXDb|;{+y9`u{EuMz54rlky2~p6xX2>MV6BZ&k`$q%q7v(xYps2wr9e8^4<;CB zc)eAT~B^rjzO6<4BDDH;il6 zFsM8jL+agQ;zazW(uiQjM%fPf2N~_p{cy29XP11_lQFpt`t#9nlk}>fv((FZt-dBa zuMIc4HmPHW04n0TTG9ug9;&OV9euL$Ib|+M7}}L~z4e%%%b|r~6OQj(S2d7XfYn#xp8;KQ55UYu#gY*De5j6Cc z#R%?rqwpy7I1(kpU7B*Pq=etXeYUn04jg%ZPjYqQNa$==yTG=6KX+=;i2Xg+kjV2T*Gc!(ef z`Q4fR*TA=M5-}z+s%YO+!K{k}S**ic&>o4_Tmv$EQTOp7F6TXPCj-UTXy?OQ=%*y62Qajk{rXbR%jMCOFMiVE3KekQa4xR}B%=iPtd8BXo~q$OX_ zSp910{Ew;m|GATsq_XiJ3w@s(jrj^NDtr(Dp!`Ve!Oq?|EJ9=vY2>IfrV{rT%(jiY zi}W@jA2iqd=?q>s;3%?@oi7~Ndo3Ge-2!zX58j(w&zVlPuXm3rcHb7O0RsM|!Ys(b zh(=*&Aywo3vuJoWZnU!u2_4bNkDTc&&bCYc%T zM~~xYxS#3KXFzQ@OXdc%9QDOxqiTd_> zT;(DX9{5dIuC4pO_xy+3{Ov)1I7j!Z)6&nHUvTRP>VU5dm#849icG)cvl0QOPkCIzG^lOp4#UcNr`VhBp(Ha%8@KPlvT*5u!v_$b#b~%sn3K{mu zaxeD%Q~{;Lw03ZAq(Pc-IVj>n*h3l2{sqioCMGatQY0kx zi`1(WWDQ=;gmLSGptEQ%UFC)th@|71<8eiRtX&Mx@#1q#nMF_BMfQdS>!!Qkx2o}= zuqRi?`UOX5P3fP%M+71Q$ctH4Av}bXED#fQ`KR4!b~60nsAv^*M7c-x`|~B}XIuq% zlqIJOf>WvlhQ@Uw$du|14)tZ?; zPNZ|xZSwp1y+d4sut8E4*l2JWR|~o0A9vD-?zC-w zDc@=wE1YKb*OMSi_Kx}&w;#h3>sHp|8^hnA3w?-WK)X?@Z2dgV7`9Cupf-B2RE4x^ zwlw+~!V9C^tyb`J;m2}ksD`w}G9`yu(^--{SQ+wt^Fu4Li~Fft!3QO`upSkAU?o;# z(1Q%GUVWbbkTK-M=T+ULkk3s6Dc9`G4CO6|=&-S&D+rbJQ$`Y-xL~ol;kc(l)VbU>{&>bV+*?ua;$bnDc29RW+Ig16)Vf6=L|fMR_P2b7>6}0 zdlB#-gj|j*C~M=F^2=K*k~=tl6YM3SXXi&K-`EvEXnWz&4D-^hQRBJI3gKKDj^6|> z*WhHSim1qAffNt60Mve9lfw^+&0bx-AM0%j>QP3%W=S@(l=(nrJ678mRQ(#+sI@d{ zdb#5fo#T;hK7xJ=M58wZf|?DHwD%!OZ3JrTGV5#{cfQwuiMvz%!CQ}CubJ7`z?@rSF<+KHNV2goc)a6hP0oHB@3LLKSH2w{um&J*z1Ka2 zLIR>lvOvh>Oxe%?3A@v<_T|}${zf_&@C~^FCo#jB(W9VLO?DX{)n(BQ0(V0`mI|9Y z#U3WwxixJkU_NTvA>5q(A@r2dnEXJp#6B=pww$XGU}~1~c``UKqQb=^*2P|4Dq*_! zhY^i61Sy%T5$Td0O6^C>h(xVvT!}Y##WeT8+s+Uuz=7)~V$>!zU;%d>H)rm*6^IrsCma%|cifwDLk_ z!^W2voQ)D;I$=v2E>iSaBw!d7aD+|LWl2iD!cBw`Q5p1~fk_xGiPi8e^mY&#viTAk zmaKL8m;JQ4bY(n6uBZt02z#noMMxTfF-RzjKre-c+@B)#J3pN-Zv7F}JtAwNk3j?OkpVCL6W1)Q$FLAj zGI!tX;g`O{%pt=0|q54Jyj##w*4e*|_;Us2Tn?!#^R(>u}|FAw1G_ z#wQsagnj9$TAC`2B_XgB$wNq~Sxgl?#0+QWWcB{G`c6~&SosbtRt}Tukw`TQ!oG1= zYyL(y<;Wh+H24>=E}Gs=Hs2%fg;&Qdvr74{E!R?Bd zIRQ?{{xkLJ_44P@y3^#(Be%(pk%$liKbUUo76wSoVfJmt9iTKL3z{uW6L&?jYg>EY zsx{kRiW@q%<$VZvbS(TKKTO4{Ad6l^IeY(F^3}=mX9|FZmQ`~RErNxlBPl3ast}W$T4V?SW=6kIGn@-^`qJv| zZXwhK4Kl1a4E}nLI`rdOi?^pd6;LZ-|8G&INHgOeC5q{_#s+SXb0r(;5ryHFsoTJD zx$VtNDh=-Tx3t!NTlk=hgAaSM)#U}e>_-Ex(|JoX*hWmBPPdTIa-2(BIOUJ|Iddy| zwY*J%z%W$}*;uSoB!BIJB6N6UhQUIQE_yz_qzI>J^KBi}BY>=s6i!&Tc@qiz!=i?7 zxiX$U`wY+pL|g$eMs`>($`tgd_(wYg79#sL4Fo+aAXig?OQz2#X0Qak(8U8^&8==C z#-0^IygzQfJG4SWwS5vko2aaOJn*kM+f1-)aG{T43VJAgxdP(fJ4&U{XR90*#a)G8+clOwdF?hJ?D) zmxu>0>M|g_QRHe_7G|q6o`C>9x4xd$Gl7lAuR~+FtNid=%DRsnf}YI*yOToWO%xnP zY*1G5yDnTGv{{xg5FhWU65q3-|-(+-rJ2WCeSJn(7Az>ej4Jp9+l-GyZ_| zJ8}>iA4g|}q1AhEEv#uWR&$g&Uyht?fVU(qk(j?^D`))s>oG08pow!f>P1u71P%oL2)UC4GeS87&G?{)NE;D=my1Q9{~;y zJULE=bG6jXE28Y11YmoZoo945`MM*`v%5b=_02*0cwzDve#3(4M}NPt`)?SCa|7*q z-94ks(R6WH-l9fE4m4}10WSu&O`|;ZCIT%vL$_pbABY!}s33@~gIvZ0H4co|=_-T$ zF#lC7r`89_+RL9wYN=E3YwR?2{$^ki(KKd>smX(Wh*^VmQh|Ob5$n_%N{!{9xP~LJO0^=V?BK8AbCEFBhDd$^yih$>U z(o{RReCU{#zHSEavFNdc8Yt<%N9pd1flD{ZVSWQu*ea1t#$J5f6*6;tCx=&;EIN^S}*3s%=M#)`~=nz!&Q0&{EP|9nzWyS<#!QxP;!E8&3D}?QKh^ zqGum|+;xu9QE=F#fe2ws5+y1Igr&l`fLyLKry=1}(W+2W`waeOR`ZXlW1B{|;4sE3 zn^ZVlR11hiV~p<~TaSen8I~ay#7Ql=-_|U@$8yjZsZ=Vi+^`JV2+kn+oiSUi%omO_+7}saXnJ9 z5ETilbag(g#jZPopCgJu+n@(i7g}3EK2@N zd64$77H5a`i%b%a^iRjMaprwzWz(`=7E6QY)o)gek7H)yZ-BLw^6FAoHwTj9nJtWc ztKaytMlWGLg29W{?gr|rx&snb@XyvR_}x3fmC>d=-nQp5ab3*whTw}DfUcKlMDDx` z-%?ek^*|Kqooy#>2lfklZ|jN4X$&n6f)RNNPl(+0S>t(8xSeOGj~X0CGRrWmm(WXT z))DDW_t&y$D#2`9<-+JT0x1==26*gpWPV~IF=rePVF%e-I&y$@5eo~A+>yZ&z6&7> z*INESfBHGNegTWga&d@;n;FSCGyW?}e_Qw#GTLHo*fWxuuG@I~5VA!A1pOdRTiPA~ z^AGe(yo=9bwLJD}@oDf$d+34~=(vIuPtOKiP}obDc|?@hY}J*@V|UynBeAkYa?S{@ z_f$U=K+>deTAi&=a*xv>Ruyw$UsTWY=Yn=xjf;s)6NQu>_niQ_idmzIwuL`Scf)f= zyzK?D5a5)^D@H&qN%F6Zd0JeXX*Knbe~VLe^gi|?JK67&mB4jrapV-$`hCQT;C{%T z*pjxB+Y|~LD9bmMN%Iq}S$F$x1yWU7@GcR91V8h;!O2I5MN_rq*gRx(k8T!1WSDTp zr9eJO4$~H94aG^6k5p8k=kFJ>4lnY0q_Bsa$@vTRW6uY?slH|Qt)Yu6Yun&pfJ zBi!h;6x?FDs&79#PT*HSCEUsKws#s%TFy*=2PAfb`>gEPBn+D-WdfXA?MkB=<8kb_ z1+4D11mdHG0EcAyg4dneLtfJ8)RyHQl@6hWJNe(d_EjyCHf7%Xsd)S4A-4COz{G@% z5xQ!P>AS@H@;4Ws)N91)3A6PleMe2<& z!(zv#%Uc?N`(Xmm)OJPYt)BM`nRjoWA&P0Yxl@c9Y02zlPH1J5l$nhPrMwu=atkz4 z)a-1+OEL;d@ctx=s<<+3Sv1VYy0RYmiji|#hy$66#`5;u~BkH4^$EGZ-Y4xyZ=%3KuaeLYKAUr$xMtIh_5mga> zPz<#G0mQ7IxEw-yO}BueN}RaFlg$RwCDB)vLF$wDu%qZyLYsPKdcbHD23$qn9i#JFqIo#OK?u7db2-$GatzO!On87%}Br};~#}n zziVB;qf_4(K$u>Qyz$ln_kBGS!CD-t4Y}9oxL@7@Sx*?NOAzdeINUD>Hl#*V%pfA; zSA`==YatS*G*crJ3`3ll4)vKss&)UtY#7ZxiVoG%9(4<%`WWcjX2jV(^g7Yhj+h5J z$5=?S=tuCyEt74^6jo@6y|@~N>&cVfFNtaRl=)Gm!vR;Bc$3-;ySCI$%kdmjQ|si` z{$q_YCe6vjy6re9jGN|`43D``)1PODtz0)vhV4XV36nVpOnMx2uM%qZ<3TtcI%>BQ zf0(J`{JqPPJxw>k#&nIvoZ5e9Sno)B2r+E0G} z@&M|zf4E0Q$O*NBR2I;?i7N} z@2^Su#`%qeX}m3cbSojiLk#84kvW1fICNPS`OyT0SpUoA0(s^2m~J<^eKE!dhJx_N zG_T}0&(<*an>oF=@?6?55g&IxSgY3?7|@pmDRE6gJyJNPH6un~%0hZ@?h=hI6O$b^ z)29#<4$E)cE-5IFbRpk9JVrw$$966UDyw;Iym4OY4Fc!&s1ZH4BJ1-$9<)Zt1c)N- zU^&9hsk6z?3%<9kGKHW|6~k;&cghtWz`oz`_YjVuvy;B;T67=L2c6=8`7WyTBv*QH zNv*bo1#KOk{O&)@&pkd*?v+kcJ8tM>AGx$~WMhH{L40_N=bkrVg+^p!H)IqXCQf2_ z0fPig=8CEo>p4vE(nc^DKbZ|9_Xo}$i4zJ`jVh95; z5%aNP3@``=EJ=Vt9U`y+$YtX;%OPzgZ_3+;+mh{p#W&y4-%%Bf`LhOy-*kB0qnB^m z_nBTz_b?-`F$*ymByshU>D)za2g`0j^ioo;A#QeL@x3@|+_!=YXA5f6Xg(Ack&WOg zJ<2i|Fd6OmyH!@YSMVxb;=M)ZDhBt)4`5T*>cUXWPG#%@$&*>K&u3#|`fm2mj*FKVf?du{xZ}WKWETTFhq6_fO$PS5(ItF=3~pFp~*j z!ys1<4EL1)#{`mz@gW|t-FpPkd%pK)n_Rb)F;z7cQ6dym_>YI3&e!=!m006oS3Mjq{q ze%hNzW=G0jpfl2K(x`CDuZCsJV*hm9T~%5n7R_g}VFpk`G((D^MWVMAmRp--T{`P; zwMgD<;e`fm`g3|fPns|6qnd{|FCHY*YAguXH(?%sx%4+Gu|Y)_8mk4EljxmP+MP`* z`SUbI{TCIN2OV+$y#g->Jqv#$wL;}4xJmah#$0`v^ughM_XjTA$B}ux)JZuY5-GW4 zKy440I+w=ZtE-_i+0xImq}vyzD68?8;94-5L~_O6Ty>X3itdA-x?6P(c4jkr+f!H( zUDeqiG>3bn^Sf8(`_YwqPeJ9&-@OCQZm4X{FfRMeBtN4E9Ca@;GVpU*L>lVb;@=PH zTQvTr?^jKyCKh&ZVOI*<y%T*Aw(XCPrFC=39*y$A`FSzxBiQ#W+uW10d8&gYp4{teh;^p@anft+z$5!Hv&@h0X-@xJG>hbTCxjDwMiWK@1b%8wYL6BrV zT41m}tX8g-`P@vj4T!Mlk8F0S!MA`^J=SCy9-jdwDe^hVDa`WwyI^H@ryt=F5y6>b zT8&iI6&j8edAfX^ycgWbnMZQ26Q~`LmdEScKC8|~$Jgyw(>18NAQ$9AwCRmri!96L zp^)b0P2CR-9S%cG$#rU}MXnx21T#031o>2VrDs@sa-FpjfvgLPW>Q&LHUoNOtmkt# zoDZ=5OGp{^vO~=p29^`aXd8K?(+f-bW`N$U;-o;%f?RcR!k02Nod2h^^8ly%Z67#E zC3|IOuj~^YBO=Fklo@3mvd6I{Z*&FZ>iq* zxh|JuJoo2$p8MJ3zO@dQ;%1#~Mrm48 zB0053{1bDi_a@jo<4!@!`w4}B(&Qb`~IeSBh zu+_yIYl2Wgk+?x4pCmAM>x_SqBPUj#c`C`k>_fp@qPlAAwD$!zOxRkL7;=|nu(#ut zyF^;&hm-D_;ji{d6rOloACu5*NkF4IC3@rifMG(|^Skv$H&^YnYL*rpw=UCi;JOuz zN*NX(7wZXS4tF@6PIWAs%*j!$RoL*3sh)}iry%thDvN5AUM888q_(>|Tzt|Yea3AyMYBgm$H_`F^v2%)bux)3s znFIEBDK;-JS5SH|;1?afJb<*=c5puu=w%tv#ihn*R!^Hd$KWAp4$#`joJ*)$kNtZ z2Al6h>Z>(u?3tmzA4^d+jLKx{97!Pb4;CX&u;M||**7zXI7hO6nrdMx*Xa=|-`#1^ zBQ?Ha&7cd7hN=%y4yUp?zl8~Lo;%mQrDe8!ce-W_K94FFMN*g(w8q-_K5S+c0{o29X&PzpV;UJE^!xnFc%b@>kvW4m#xiOj-L*DadC&2N#0Us z;<-(m1WB7$=j6hjcPC6JB)D3T2#IC`ibu#yi!uK7W2!j|Z>~RaJ*&XXy#ytIk2DIp z5?Qd^s90_?ILjU#>ZWk5HXts}grg_!Gmgm!d?eLGR7xEP zvTCrslV~94ym5_i<5oqy(@@?wN}lIdtiY8=?|Ng!XeYnly`@9wCGx2S$3x|0x8T2h zz7A85Vb2>s44rKpI_4Y7_Pnd2^mYj2%^jM|Du>u4`^Psda^JIP%*DK6bo`Vf&f{!% zDTYCwF5Nhi=)QhU2$@eQv&ZzxsX+Hl+gP6kW|e!n9IU2>Vh~cioI{>4WvR}t*4Hpz z%5z?HjLGoka}Q3AbX9AkY|Yjf^M(>@tBAI9JO5pDCQu0R3Nns>)LC#vB2p96C*?K? zvX$un$sBDx$1=+NNj*@Oa@u*b@O*XBr_sg@8sCUq-|LK!MUmC)epklrv}5O_^<{NP zX16|c$9Wtbks3y7geI^tF5oRZJu;v zwkW8j+8Ccxo9stEDOT_Go&j%$KCgVO7pm+^%PKEPBZqbMw%s@732XS{cX+wCSjH1s z5)bc=g**<^NNsroY` z?}fHHlgu^B?2r{^^gQ&j zbF~T((>|Yg&C5WKL8DCnl1}Z3!YHFW2S1|;Xr0`Uz-;=FxEwYc4QpeAtnm7^f~uzX zl;xA!?>MLR?tL80Iudm;mi{!ewL91KhG7Hsa-XepKi<2mc6%zf0GwtbfJ1Zf-<@Xu z#|XWDzv|04t)&9Id!UxAAkN{t5qC%%8-WV3i;3duS19%m2||Y{!3pR1=g|zQYAMqc zff)_2nj-O4wfxy;UNM?|Uieo!^J$A*uDe>@V(NKH;KS;Y_dtE8${p>RdcrW;=2*fj4~d?OG0l-(g?ik}vz} z)5-wDppVts>K-=|@{=!53?=8)Jw#RGpS_FWpbwtn}{v!JEJ$q-sr7F6&OPBuI# zuVNFMPte79XgEu!P&qRq8u4J>r%$l-IQ00Lin90(_KtC)aR_de zxN=pY2<1b29_^AG2WJIGmmX4rv3$!`l15{e(H!1^+x9voZ6;882YAE12q7+lgy+>) zj|s0CyzI9=Mo!R}&LXB`&DYpZ7c?0r(&KNV+~TULd0y^e;G{KVR4nL0KvU9mr8&$^ zxrM-9P8zE`J?aZ(iB~Rz<{vvnk2HaZU#K$aVFfYnbAXVUOLU#As5JvS%+26 zi$sNuPY}dLGUS$0g&;oBqhzv2dY`l3@6Na403M!Sh${B|7(y|_cONa;6BrtUe@ZzV z7SThtHT8k?Rwc)(Z}@BP#H@JJHz&GR&M=E@P9KJ89yQKmRh&I~%vbL1L-K3E>7>CH z)Y!=jXVb1iPrAoAZZ3}3wU*5~nrV!ZjL5zqJ<@NwjHCZC>68Cc<{&E_#S;E*jOdjtg?uKN|l`P8sjz&Qf7a^z9 z;{3-8T+H4y99_zc;JYIvs!sk$G}` z??mt*Mm9Z@glCZb!X?!xXD-21sFDPEpZOK{sbQseQ$%6~b;n+*z0hRoR}0Pe>B|#t z$XrVcXv8M|q*Z8MY&r9J0A=d^1bHpjrUXu)qEj~$%%=gZp`^~%O*lzxUquG^p6;n; z^(3HL+hx4gRP?4N*b2p9!^|2~rcw3!9nQj$vmZusbXYz_x^AVc`3qBFm(jS9ueU5h z^AnNnbswfQ2Jq=W=T+p-V|nQco@bOAH$pLQZ+BKH8E$iM>IDz z3|wc?QP`yI=X5YTlp8h}%p6{Deq?S0QD$Ug>ih1SdPZg237Rl{S~=Ha4~-ckMoIWMn+X@@`V6 z#HHZj>MQbt$Qqp*9T(cjc^lxZ7UO(>PwzF-qEr(wo`vaulxdall|KP`7p4gd`23&Jy=#sAes*0diLB(U$Nx46VQvP)8idSs8^zaV91xw*O-JMH=)FoJshRob|_)O)ojtfP))WHCr(;*2;VMQ75^ zfN@a^f#o<|*9X;3IcGodLUz-3i~FAu+zI4c5h+nW^h_!^)b*B_xw-l4O$TB(ixaqW ziMoa%i=BeS<-F45kMO;Tw|FWa`G2c!SuOA3CbowPhF6csf1|&qqugUrj;UgGHm| z;j^yoH?MZhR;AYOW_XW2Lg2j%%ejL)B@*bUMD`g<#Z${1+fa57r7X82 zcqY-cfPnK%Y^3@szRner zt)bBToYCph6Jv*W+&t?&9FG4(Iu2w46 z4B#AcFy_^J@f*6<{>CN}Sj969*DYV*e7<61U>GoN{tz!Do90+jApFueVY_IW(MQF; zl?4yA_(MvMwN&pWKVyg{3uU_+y6RMdot2vu%mC?st=N0pf-~JZXE?3JFf)j<{1xsU z`2ephz)#HzsWEP!inHm2hI(V(~@W zY7gGU-lO52cHD&SY)>QHgy$=>^X%u0TQZfCizro!*weMyvZC=;MWOawdAx~`3C*W` z%^#^$uRP;gyqEE0<(i8xcQY$oc+6mY#z{-XFxsO1(cN8Y)>p;^q9|5bk`Z*p|c!?(rErw#y;yT(%@c7trQBv6cj)$3>pI z>tz+;IB?D=aQV=s(n)o63*yn8dX1m7#Z4G{%fF@K2o5n3jxR~mU?nzMi#;}8e#(>{ zy{Z4!AI)jZ8TY;nq1aq}tq;~=zzoTv)er06oeX3;9{uP{LWR*2%9cmE%S^`~!BW>X zn3PZFTf3g*dG68~^1*q@#^Ge(_8puPEFLD8OS|0b2a{5e=N4S%;~f3tC>F6UxK#v9 z)N-#Mv8=ePCh1KsUKD1A8jF_%$MPf|_yCN9oy%*@um6D{w*2|4GY zb}gafrSC+f=b*W{)!a!fqwZ9)K>fk=i4qf!4M?0v{CMNTo2A9}mQzV=%3UT&i{3{W z>ulG#M!K7%jPf6Mjff9BMslgQq3zIogY);Cv3v;&b#;^=sh#(Bn%W)H*bHNaLwdpq z85%fUTUJJNjYO_426T2TBj0D{6t zw&S_HZ|C?pI_2q(9Fas&@uJs6nVX;P*5K#6p|#)_(8PM-{L(;2wl`ma{ZAd5gA)?y z>0GSLoK<*FwW+G8@-M3vcffg7I(qm7lzF)n`Q9iCvp*mn7=|CjlpG{x z&r0n}XLWZ!>=lynUr7D`6n`7a_ZgT< zm!i;&?Fb0Q2QmqmCHfZ7ex=_tU~(7b)L?RIvPyEAU=gLIZ-VTAA~WR00yKyTXg^(G zqWLZJs!FnQYMOH3*fN&Tn(IKMLf{Ki?pRo8zZJ6YVyj)y0^)-sR}2-)%mI(Aw2AgT zbbp1T{qB(OSNJd0cVBH^tI>HR(q+#*lmi@LWe*rZz&M2h1L_=50uZ1e*n#E*`6?aw zj`ka&JpceRGe@}Ey1)Q~O}0qHRg4K_u>4e1arvJ7Q9!=t5AuzG`n=a-f0}{+lnCE#zu$`oVn44eS&T?N*wz~t~E&oQDBrB_MSg z_yVrQehWbD0xHX|v-hpselAu;O7s;P*!uAT`dr~}Lie=tknaGoiU?;*8Cwgala-65 zosOB4mATbdXJFujzgA4?UkCKE093A1KM?W&Pw>A?IACqg1z~IZYkdP70EeCfjii(n z3k%ax?4|rY(87N&_vhsyVK1zp@uils|B%`(V4e3%sj5f|i(eIhiSg-fHK1Pb0-mS^ zeh?WA7#{hhNci5e;?n*iVy|)iJiR>|8{TN3!=VBC2dN)~^ISSW_(g<^rHr$)nVrdA z39BMa5wl5q+5F@)4b%5-> zA^-P20l_e^S2PTa&HE2wf3jf)#)2ITVXzndeuMpPo8}kphQKhegB%QO+yBpDpgkcl z1nlPp14#+^bIA7__h16pMFECzKJ3p4`;Rf$gnr%{!5#oG42AH&X8hV8061%4W91ku z`OW_hyI+uBOqYXkVC&BqoKWmv;|{O|4d#Nay<)gkxBr^^N48(VDF7Sj#H1i3>9138 zkhxAU7;M)I18&d!Yw!V9zQA0tp(G4<8U5GX{YoYCQ?p56FxcD-2FwO5fqyx@__=$L zeK6Sg3>XQv)qz1?zW-k$_j`-)tf+yRU_%fXrenc>$^70d1Q-W?T#vy;6#Y-Q-<2)+ z5iTl6MA7j9m&oBhRXTKr*$3gec z3E;zX457RGZwUvD$l&8e42Qb^cbq>zYy@ive8`2N9vk=#6+AQlZZ7qk=?(ap1q0n0 z{B9Fte-{Gi-Tvax1)M+d1}Fyg@9X~sh1m|hsDcZuYOnxriBPN;z)q3<=-yBN2iM6V A?*IS* literal 0 HcmV?d00001 diff --git a/examples/epaper_display/.mvn/wrapper/maven-wrapper.properties b/examples/epaper_display/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..6d3a5665 --- /dev/null +++ b/examples/epaper_display/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/epaper_display/mvnw b/examples/epaper_display/mvnw new file mode 100755 index 00000000..8d937f4c --- /dev/null +++ b/examples/epaper_display/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/examples/epaper_display/mvnw.cmd b/examples/epaper_display/mvnw.cmd new file mode 100644 index 00000000..c4586b56 --- /dev/null +++ b/examples/epaper_display/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/examples/monitor/.mvn/wrapper/maven-wrapper.jar b/examples/monitor/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 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 A?*IS* literal 0 HcmV?d00001 diff --git a/examples/monitor/.mvn/wrapper/maven-wrapper.properties b/examples/monitor/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..6d3a5665 --- /dev/null +++ b/examples/monitor/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/monitor/mvnw b/examples/monitor/mvnw new file mode 100755 index 00000000..8d937f4c --- /dev/null +++ b/examples/monitor/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/examples/monitor/mvnw.cmd b/examples/monitor/mvnw.cmd new file mode 100644 index 00000000..c4586b56 --- /dev/null +++ b/examples/monitor/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/examples/stm_dfu/.mvn/wrapper/maven-wrapper.jar b/examples/stm_dfu/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 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 A?*IS* literal 0 HcmV?d00001 diff --git a/examples/stm_dfu/.mvn/wrapper/maven-wrapper.properties b/examples/stm_dfu/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..6d3a5665 --- /dev/null +++ b/examples/stm_dfu/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/stm_dfu/mvnw b/examples/stm_dfu/mvnw new file mode 100755 index 00000000..8d937f4c --- /dev/null +++ b/examples/stm_dfu/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/examples/stm_dfu/mvnw.cmd b/examples/stm_dfu/mvnw.cmd new file mode 100644 index 00000000..c4586b56 --- /dev/null +++ b/examples/stm_dfu/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% From d80b069e1c4f7582d094d09135ac1687d86b74c5 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 1 Aug 2023 22:28:27 +0200 Subject: [PATCH 265/433] CI for examples --- .github/workflows/continuous-integration.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index a8b37dc5..54d76463 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -27,16 +27,16 @@ jobs: working-directory: ./java-does-usb - name: Example bulk_transfer run: ./mvnw $MAVEN_ARGS clean compile - working-directory: ./bulk_transfer + working-directory: ./examples/bulk_transfer - name: Example enumerate run: ./mvnw $MAVEN_ARGS clean compile - working-directory: ./enumerate + working-directory: ./examples/enumerate - name: Example monitor run: ./mvnw $MAVEN_ARGS clean compile - working-directory: ./monitor + working-directory: ./examples/monitor - name: Example stm_dfu run: ./mvnw $MAVEN_ARGS clean compile - working-directory: ./stm_dfu + working-directory: ./examples/stm_dfu - name: Example epaper_display run: ./mvnw $MAVEN_ARGS clean compile - working-directory: ./epaper_display + working-directory: ./examples/epaper_display From 6da1d02202259fce8bbcd057a5707ccb98a4d5c5 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 1 Aug 2023 22:32:19 +0200 Subject: [PATCH 266/433] CI for JDK 21 --- .github/workflows/continuous-integration.yaml | 42 +++ .../.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 + examples/bulk_transfer/mvnw | 308 ++++++++++++++++++ examples/bulk_transfer/mvnw.cmd | 205 ++++++++++++ .../enumerate/.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 + examples/enumerate/mvnw | 308 ++++++++++++++++++ examples/enumerate/mvnw.cmd | 205 ++++++++++++ .../.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 + examples/epaper_display/mvnw | 308 ++++++++++++++++++ examples/epaper_display/mvnw.cmd | 205 ++++++++++++ .../monitor/.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 + examples/monitor/mvnw | 308 ++++++++++++++++++ examples/monitor/mvnw.cmd | 205 ++++++++++++ .../stm_dfu/.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 + examples/stm_dfu/mvnw | 308 ++++++++++++++++++ examples/stm_dfu/mvnw.cmd | 205 ++++++++++++ java-does-usb/.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 + java-does-usb/mvnw | 308 ++++++++++++++++++ java-does-usb/mvnw.cmd | 205 ++++++++++++ 25 files changed, 3228 insertions(+) create mode 100644 .github/workflows/continuous-integration.yaml create mode 100644 examples/bulk_transfer/.mvn/wrapper/maven-wrapper.jar create mode 100644 examples/bulk_transfer/.mvn/wrapper/maven-wrapper.properties create mode 100755 examples/bulk_transfer/mvnw create mode 100644 examples/bulk_transfer/mvnw.cmd create mode 100644 examples/enumerate/.mvn/wrapper/maven-wrapper.jar create mode 100644 examples/enumerate/.mvn/wrapper/maven-wrapper.properties create mode 100755 examples/enumerate/mvnw create mode 100644 examples/enumerate/mvnw.cmd create mode 100644 examples/epaper_display/.mvn/wrapper/maven-wrapper.jar create mode 100644 examples/epaper_display/.mvn/wrapper/maven-wrapper.properties create mode 100755 examples/epaper_display/mvnw create mode 100644 examples/epaper_display/mvnw.cmd create mode 100644 examples/monitor/.mvn/wrapper/maven-wrapper.jar create mode 100644 examples/monitor/.mvn/wrapper/maven-wrapper.properties create mode 100755 examples/monitor/mvnw create mode 100644 examples/monitor/mvnw.cmd create mode 100644 examples/stm_dfu/.mvn/wrapper/maven-wrapper.jar create mode 100644 examples/stm_dfu/.mvn/wrapper/maven-wrapper.properties create mode 100755 examples/stm_dfu/mvnw create mode 100644 examples/stm_dfu/mvnw.cmd create mode 100644 java-does-usb/.mvn/wrapper/maven-wrapper.jar create mode 100644 java-does-usb/.mvn/wrapper/maven-wrapper.properties create mode 100755 java-does-usb/mvnw create mode 100644 java-does-usb/mvnw.cmd diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml new file mode 100644 index 00000000..6e55bd23 --- /dev/null +++ b/.github/workflows/continuous-integration.yaml @@ -0,0 +1,42 @@ +name: Continuous Integration + +on: [push, pull_request] + +env: + MAVEN_ARGS: -B -V -ntp -e -Djansi.passthrough=true -Dstyle.color=always + +jobs: + + test_os: + name: OS ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macOS-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: '21' + cache: 'maven' + - name: Library + run: ./mvnw $MAVEN_ARGS -DskipTests clean package javadoc:javadoc + working-directory: ./java-does-usb + - name: Example bulk_transfer + run: ./mvnw $MAVEN_ARGS clean compile + working-directory: ./examples/bulk_transfer + - name: Example enumerate + run: ./mvnw $MAVEN_ARGS clean compile + working-directory: ./examples/enumerate + - name: Example monitor + run: ./mvnw $MAVEN_ARGS clean compile + working-directory: ./examples/monitor + - name: Example stm_dfu + run: ./mvnw $MAVEN_ARGS clean compile + working-directory: ./examples/stm_dfu + - name: Example epaper_display + run: ./mvnw $MAVEN_ARGS clean compile + working-directory: ./examples/epaper_display diff --git a/examples/bulk_transfer/.mvn/wrapper/maven-wrapper.jar b/examples/bulk_transfer/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 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 A?*IS* literal 0 HcmV?d00001 diff --git a/examples/bulk_transfer/.mvn/wrapper/maven-wrapper.properties b/examples/bulk_transfer/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..6d3a5665 --- /dev/null +++ b/examples/bulk_transfer/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/bulk_transfer/mvnw b/examples/bulk_transfer/mvnw new file mode 100755 index 00000000..8d937f4c --- /dev/null +++ b/examples/bulk_transfer/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/examples/bulk_transfer/mvnw.cmd b/examples/bulk_transfer/mvnw.cmd new file mode 100644 index 00000000..c4586b56 --- /dev/null +++ b/examples/bulk_transfer/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/examples/enumerate/.mvn/wrapper/maven-wrapper.jar b/examples/enumerate/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 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 A?*IS* literal 0 HcmV?d00001 diff --git a/examples/enumerate/.mvn/wrapper/maven-wrapper.properties b/examples/enumerate/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..6d3a5665 --- /dev/null +++ b/examples/enumerate/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/enumerate/mvnw b/examples/enumerate/mvnw new file mode 100755 index 00000000..8d937f4c --- /dev/null +++ b/examples/enumerate/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/examples/enumerate/mvnw.cmd b/examples/enumerate/mvnw.cmd new file mode 100644 index 00000000..c4586b56 --- /dev/null +++ b/examples/enumerate/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/examples/epaper_display/.mvn/wrapper/maven-wrapper.jar b/examples/epaper_display/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 zcmb5V1CS=sk~Z9!wr$(CZEL#U=Co~N+O}=mwr$(Cds^S@-Tij=#=rmlVk@E|Dyp8$ z$UKz?`Q$l@GN3=8fq)=^fVx`E)Pern1@-q?PE1vZPD);!LGdpP^)C$aAFx&{CzjH` zpQV9;fd0PyFPNN=yp*_@iYmRFcvOrKbU!1a*o)t$0ex(~3z5?bw11HQYW_uDngyer za60w&wz^`W&Z!0XSH^cLNR&k>%)Vr|$}(wfBzmSbuK^)dy#xr@_NZVszJASn12dw; z-KbI5yz=2awY0>OUF)&crfPu&tVl|!>g*#ur@K=$@8N05<_Mldg}X`N6O<~3|Dpk3 zRWb!e7z<{Mr96 z^C{%ROigEIapRGbFA5g4XoQAe_Y1ii3Ci!KV`?$ zZ2Hy1VP#hVp>OOqe~m|lo@^276Ik<~*6eRSOe;$wn_0@St#cJy}qI#RP= zHVMXyFYYX%T_k3MNbtOX{<*_6Htq*o|7~MkS|A|A|8AqKl!%zTirAJGz;R<3&F7_N z)uC9$9K1M-)g0#}tnM(lO2k~W&4xT7gshgZ1-y2Yo-q9Li7%zguh7W#kGfnjo7Cl6 z!^wTtP392HU0aVB!$cPHjdK}yi7xNMp+KVZy3_u}+lBCloJ&C?#NE@y$_{Uv83*iV zhDOcv`=|CiyQ5)C4fghUmxmwBP0fvuR>aV`bZ3{Q4&6-(M@5sHt0M(}WetqItGB1C zCU-)_n-VD;(6T1%0(@6%U`UgUwgJCCdXvI#f%79Elbg4^yucgfW1^ zNF!|C39SaXsqU9kIimX0vZ`U29)>O|Kfs*hXBXC;Cs9_Zos3%8lu)JGm~c19+j8Va z)~kFfHouwMbfRHJ``%9mLj_bCx!<)O9XNq&uH(>(Q0V7-gom7$kxSpjpPiYGG{IT8 zKdjoDkkMTL9-|vXDuUL=B-K)nVaSFd5TsX0v1C$ETE1Ajnhe9ept?d;xVCWMc$MbR zL{-oP*vjp_3%f0b8h!Qija6rzq~E!#7X~8^ZUb#@rnF~sG0hx^Ok?G9dwmit494OT z_WQzm_sR_#%|I`jx5(6aJYTLv;3U#e@*^jms9#~U`eHOZZEB~yn=4UA(=_U#pYn5e zeeaDmq-$-)&)5Y}h1zDbftv>|?GjQ=)qUw*^CkcAG#o%I8i186AbS@;qrezPCQYWHe=q-5zF>xO*Kk|VTZD;t={XqrKfR|{itr~k71VS?cBc=9zgeFbpeQf*Wad-tAW7(o ze6RbNeu31Uebi}b0>|=7ZjH*J+zSj8fy|+T)+X{N8Vv^d+USG3arWZ?pz)WD)VW}P z0!D>}01W#e@VWTL8w1m|h`D(EnHc*C5#1WK4G|C5ViXO$YzKfJkda# z2c2*qXI-StLW*7_c-%Dws+D#Kkv^gL!_=GMn?Y^0J7*3le!!fTzSux%=1T$O8oy8j z%)PQ9!O+>+y+Dw*r`*}y4SpUa21pWJ$gEDXCZg8L+B!pYWd8X;jRBQkN_b=#tb6Nx zVodM4k?gF&R&P=s`B3d@M5Qvr;1;i_w1AI=*rH(G1kVRMC`_nohm~Ie5^YWYqZMV2<`J* z`i)p799U_mcUjKYn!^T&hu7`Lw$PkddV&W(ni)y|9f}rGr|i-7nnfH6nyB$Q{(*Nv zZz@~rzWM#V@sjT3ewv9c`pP@xM6D!StnV@qCdO${loe(4Gy00NDF5&@Ku;h2P+Vh7 z(X6De$cX5@V}DHXG?K^6mV>XiT768Ee^ye&Cs=2yefVcFn|G zBz$~J(ld&1j@%`sBK^^0Gs$I$q9{R}!HhVu|B@Bhb29PF(%U6#P|T|{ughrfjB@s- zZ)nWbT=6f6aVyk86h(0{NqFg#_d-&q^A@E2l0Iu0(C1@^s6Y-G0r32qll>aW3cHP# zyH`KWu&2?XrIGVB6LOgb+$1zrsW>c2!a(2Y!TnGSAg(|akb#ROpk$~$h}jiY&nWEz zmMxk4&H$8yk(6GKOLQCx$Ji-5H%$Oo4l7~@gbHzNj;iC%_g-+`hCf=YA>Z&F)I1sI z%?Mm27>#i5b5x*U%#QE0wgsN|L73Qf%Mq)QW@O+)a;#mQN?b8e#X%wHbZyA_F+`P%-1SZVnTPPMermk1Rpm#(;z^tMJqwt zDMHw=^c9%?#BcjyPGZFlGOC12RN(i`QAez>VM4#BK&Tm~MZ_!#U8PR->|l+38rIqk zap{3_ei_txm=KL<4p_ukI`9GAEZ+--)Z%)I+9LYO!c|rF=Da5DE@8%g-Zb*O-z8Tv zzbvTzeUcYFgy{b)8Q6+BPl*C}p~DiX%RHMlZf;NmCH;xy=D6Ii;tGU~ zM?k;9X_E?)-wP|VRChb4LrAL*?XD6R2L(MxRFolr6GJ$C>Ihr*nv#lBU>Yklt`-bQ zr;5c(o}R!m4PRz=CnYcQv}m?O=CA(PWBW0?)UY)5d4Kf;8-HU@=xMnA#uw{g`hK{U zB-EQG%T-7FMuUQ;r2xgBi1w69b-Jk8Kujr>`C#&kw-kx_R_GLRC}oum#c{je^h&x9 zoEe)8uUX|SahpME4SEog-5X^wQE0^I!YEHlwawJ|l^^0kD)z{o4^I$Eha$5tzD*A8 zR<*lss4U5N*JCYl;sxBaQkB3M8VT|gXibxFR-NH4Hsmw|{={*Xk)%!$IeqpW&($DQ zuf$~fL+;QIaK?EUfKSX;Gpbm8{<=v#$SrH~P-it--v1kL>3SbJS@>hAE2x_k1-iK# zRN~My-v@dGN3E#c!V1(nOH>vJ{rcOVCx$5s7B?7EKe%B`bbx(8}km#t2a z1A~COG(S4C7~h~k+3;NkxdA4gbB7bRVbm%$DXK0TSBI=Ph6f+PA@$t){_NrRLb`jp zn1u=O0C8%&`rdQgO3kEi#QqiBQcBcbG3wqPrJ8+0r<`L0Co-n8y-NbWbx;}DTq@FD z1b)B$b>Nwx^2;+oIcgW(4I`5DeLE$mWYYc7#tishbd;Y!oQLxI>?6_zq7Ej)92xAZ z!D0mfl|v4EC<3(06V8m+BS)Vx90b=xBSTwTznptIbt5u5KD54$vwl|kp#RpZuJ*k) z>jw52JS&x)9&g3RDXGV zElux37>A=`#5(UuRx&d4qxrV<38_w?#plbw03l9>Nz$Y zZS;fNq6>cGvoASa2y(D&qR9_{@tVrnvduek+riBR#VCG|4Ne^w@mf2Y;-k90%V zpA6dVw|naH;pM~VAwLcQZ|pyTEr;_S2GpkB?7)+?cW{0yE$G43`viTn+^}IPNlDo3 zmE`*)*tFe^=p+a{a5xR;H0r=&!u9y)kYUv@;NUKZ)`u-KFTv0S&FTEQc;D3d|KEKSxirI9TtAWe#hvOXV z>807~TWI~^rL?)WMmi!T!j-vjsw@f11?#jNTu^cmjp!+A1f__Dw!7oqF>&r$V7gc< z?6D92h~Y?faUD+I8V!w~8Z%ws5S{20(AkaTZc>=z`ZK=>ik1td7Op#vAnD;8S zh<>2tmEZiSm-nEjuaWVE)aUXp$BumSS;qw#Xy7-yeq)(<{2G#ap8z)+lTi( ziMb-iig6!==yk zb6{;1hs`#qO5OJQlcJ|62g!?fbI^6v-(`tAQ%Drjcm!`-$%Q#@yw3pf`mXjN>=BSH z(Nftnf50zUUTK;htPt0ONKJq1_d0!a^g>DeNCNpoyZhsnch+s|jXg1!NnEv%li2yw zL}Y=P3u`S%Fj)lhWv0vF4}R;rh4&}2YB8B!|7^}a{#Oac|%oFdMToRrWxEIEN<0CG@_j#R4%R4i0$*6xzzr}^`rI!#y9Xkr{+Rt9G$*@ zQ}XJ+_dl^9@(QYdlXLIMI_Q2uSl>N9g*YXMjddFvVouadTFwyNOT0uG$p!rGF5*`1 z&xsKPj&;t10m&pdPv+LpZd$pyI_v1IJnMD%kWn{vY=O3k1sJRYwPoDV1S4OfVz4FB z$^ygjgHCW=ySKSsoSA&wSlq83JB+O-)s>>e@a{_FjB{@=AlrX7wq>JE=n@}@fba(;n4EG| zge1i)?NE@M@DC5eEv4; z#R~0aNssmFHANL@-eDq2_jFn=MXE9y>1FZH4&v<}vEdB6Kz^l)X%%X@E#4)ahB(KY zx8RH+1*6b|o1$_lRqi^)qoLs;eV5zkKSN;HDwJIx#ceKS!A$ZJ-BpJSc*zl+D~EM2 zm@Kpq2M*kX`;gES_Dd1Y#UH`i!#1HdehqP^{DA-AW^dV(UPu|O@Hvr>?X3^~=1iaRa~AVXbj z-yGL<(5}*)su2Tj#oIt+c6Gh}$0|sUYGGDzNMX+$Oi$e&UJt3&kwu)HX+XP{es(S3 z%9C9y({_fu>^BKjI7k;mZ4DKrdqxw`IM#8{Sh?X(6WE4S6-9M}U0&e32fV$2w{`19 zd=9JfCaYm@J$;nSG3(|byYDqh>c%`JW)W*Y0&K~g6)W?AvVP&DsF_6!fG3i%j^Q>R zR_j5@NguaZB{&XjXF+~6m|utO*pxq$8?0GjW0J-e6Lnf0c@}hvom8KOnirhjOM7!n zP#Iv^0_BqJI?hR5+Dl}p!7X}^NvFOCGvh9y*hgik<&X)3UcEBCdUr$Dt8?0f&LSur ze*n!(V(7umZ%UCS>Hf(g=}39OcvGbf2+D;OZ089m_nUbdCE0PXJfnyrIlLXGh2D!m zK=C#{JmoHY1ws47L0zeWkxxV=A%V8a&E^w%;fBp`PN_ndicD@oN?p?Bu~20>;h;W` ztV=hI*Ts$6JXOwOY?sOk_1xjzNYA#40dD}|js#3V{SLhPEkn5>Ma+cGQi*#`g-*g56Q&@!dg)|1YpLai3Bu8a;l2fnD6&)MZ~hS%&J}k z2p-wG=S|5YGy*Rcnm<9VIVq%~`Q{g(Vq4V)CP257v06=M2W|8AgZO0CC_}HVQ>`VU zy;2LDlG1iwIeMj?l40_`21Qsm?d=1~6f4@_&`lp~pIeXnR)wF0z7FH&wu~L~mfmMr zY4_w6tc{ZP&sa&Ui@UxZ*!UovRT})(p!GtQh~+AMZ6wcqMXM*4r@EaUdt>;Qs2Nt8 zDCJi#^Rwx|T|j_kZi6K!X>Ir%%UxaH>m6I9Yp;Sr;DKJ@{)dz4hpG>jX?>iiXzVQ0 zR$IzL8q11KPvIWIT{hU`TrFyI0YQh`#>J4XE*3;v^07C004~FC7TlRVVC}<}LC4h_ zZjZ)2*#)JyXPHcwte!}{y%i_!{^KwF9qzIRst@oUu~4m;1J_qR;Pz1KSI{rXY5_I_ z%gWC*%bNsb;v?>+TbM$qT`_U8{-g@egY=7+SN#(?RE<2nfrWrOn2OXK!ek7v`aDrH zxCoFHyA&@^@m+#Y(*cohQ4B76me;)(t}{#7?E$_u#1fv)vUE5K;jmlgYI0$Mo!*EA zf?dx$4L(?nyFbv|AF1kB!$P_q)wk1*@L0>mSC(A8f4Rgmv1HG;QDWFj<(1oz)JHr+cP|EPET zSD~QW&W(W?1PF-iZ()b|UrnB(#wG^NR!*X}t~OS-21dpXq)h)YcdA(1A`2nzVFax9rx~WuN=SVt`OIR=eE@$^9&Gx_HCfN= zI(V`)Jn+tJPF~mS?ED7#InwS&6OfH;qDzI_8@t>In6nl zo}q{Ds*cTG*w3CH{Mw9*Zs|iDH^KqmhlLp_+wfwIS24G z{c@fdgqy^Y)RNpI7va^nYr9;18t|j=AYDMpj)j1oNE;8+QQ)ap8O??lv%jbrb*a;} z?OvnGXbtE9zt;TOyWc|$9BeSGQbfNZR`o_C!kMr|mzFvN+5;g2TgFo8DzgS2kkuw@ z=`Gq?xbAPzyf3MQ^ZXp>Gx4GwPD))qv<1EreWT!S@H-IpO{TPP1se8Yv8f@Xw>B}Y z@#;egDL_+0WDA)AuP5@5Dyefuu&0g;P>ro9Qr>@2-VDrb(-whYxmWgkRGE(KC2LwS z;ya>ASBlDMtcZCCD8h+Awq1%A|Hbx)rpn`REck#(J^SbjiHXe-jBp!?>~DC7Wb?mC z_AN+^nOt;3tPnaRZBEpB6s|hCcFouWlA{3QJHP!EPBq1``CIsgMCYD#80(bsKpvwO)0#)1{ zos6v&9c=%W0G-T@9sfSLxeGZvnHk$SnHw57+5X4!u1dvH0YwOvuZ7M^2YOKra0dqR zD`K@MTs(k@h>VeI5UYI%n7#3L_WXVnpu$Vr-g}gEE>Y8ZQQsj_wbl&t6nj{;ga4q8SN#Z6cBZepMoyv7MF-tnnZp*(8jq848yZ zsG_fP$Y-rtCAPPI7QC^nzQjlk;p3tk88!1dJuEFZ!BoB;c!T>L>xSD<#+4X%*;_IB z0bZ%-SLOi5DV7uo{z}YLKHsOHfFIYlu8h(?gRs9@bbzk&dkvw*CWnV;GTAKOZfbY9 z(nKOTQ?fRRs(pr@KsUDq@*P`YUk4j=m?FIoIr)pHUCSE84|Qcf6GucZBRt;6oq_8Z zP^R{LRMo?8>5oaye)Jgg9?H}q?%m@2bBI!XOOP1B0s$%htwA&XuR`=chDc2)ebgna zFWvevD|V882V)@vt|>eeB+@<-L0^6NN%B5BREi8K=GwHVh6X>kCN+R3l{%oJw5g>F zrj$rp$9 zhepggNYDlBLM;Q*CB&%w zW+aY{Mj{=;Rc0dkUw~k)SwgT$RVEn+1QV;%<*FZg!1OcfOcLiF@~k$`IG|E8J0?R2 zk?iDGLR*b|9#WhNLtavx0&=Nx2NII{!@1T78VEA*I#65C`b5)8cGclxKQoVFM$P({ zLwJKo9!9xN4Q8a2F`xL&_>KZfN zOK?5jP%CT{^m4_jZahnn4DrqgTr%(e_({|z2`C2NrR6=v9 z*|55wrjpExm3M&wQ^P?rQPmkI9Z9jlcB~4IfYuLaBV95OGm#E|YwBvj5Z}L~f`&wc zrFo!zLX*C{d2}OGE{YCxyPDNV(%RZ7;;6oM*5a>5LmLy~_NIuhXTy-*>*^oo1L;`o zlY#igc#sXmsfGHA{Vu$lCq$&Ok|9~pSl5Q3csNqZc-!a;O@R$G28a@Sg#&gnrYFsk z&OjZtfIdsr%RV)bh>{>f883aoWuYCPDP{_)%yQhVdYh;6(EOO=;ztX1>n-LcOvCIr zKPLkb`WG2;>r)LTp!~AlXjf-Oe3k`Chvw$l7SB2bA=x3s$;;VTFL0QcHliysKd^*n zg-SNbtPnMAIBX7uiwi&vS)`dunX$}x)f=iwHH;OS6jZ9dYJ^wQ=F#j9U{wJ9eGH^#vzm$HIm->xSO>WQ~nwLYQ8FS|?l!vWL<%j1~P<+07ZMKkTqE0F*Oy1FchM z2(Nx-db%$WC~|loN~e!U`A4)V4@A|gPZh`TA18`yO1{ z(?VA_M6SYp-A#%JEppNHsV~kgW+*Ez=?H?GV!<$F^nOd+SZX(f0IoC#@A=TDv4B2M z%G-laS}yqR0f+qnYW_e7E;5$Q!eO-%XWZML++hz$Xaq@c%2&ognqB2%k;Cs!WA6vl z{6s3fwj*0Q_odHNXd(8234^=Asmc0#8ChzaSyIeCkO(wxqC=R`cZY1|TSK)EYx{W9 z!YXa8GER#Hx<^$eY>{d;u8*+0ocvY0f#D-}KO!`zyDD$%z1*2KI>T+Xmp)%%7c$P< zvTF;ea#Zfzz51>&s<=tS74(t=Hm0dIncn~&zaxiohmQn>6x`R+%vT%~Dhc%RQ=Cj^ z&%gxxQo!zAsu6Z+Ud#P!%3is<%*dJXe!*wZ-yidw|zw|C`cR z`fiF^(yZt?p{ZX|8Ita)UC$=fg6wOve?w+8ww|^7OQ0d zN(3dmJ@mV8>74I$kQl8NM%aC+2l?ZQ2pqkMs{&q(|4hwNM z^xYnjj)q6uAK@m|H$g2ARS2($e9aqGYlEED9sT?~{isH3Sk}kjmZ05Atkgh^M6VNP zX7@!i@k$yRsDK8RA1iqi0}#Phs7y(bKYAQbO9y=~10?8cXtIC4@gF#xZS;y3mAI`h zZ^VmqwJ%W>kisQ!J6R?Zjcgar;Il%$jI*@y)B+fn^53jQd0`)=C~w%Lo?qw!q3fVi{~2arObUM{s=q)hgBn64~)W0tyi?(vlFb z>tCE=B1cbfyY=V38fUGN(#vmn1aY!@v_c70}pa(Lrle-(-SH8Nd!emQF zf3kz0cE~KzB%37B24|e=l4)L}g1AF@v%J*A;5F7li!>I0`lfO9TR+ak`xyqWnj5iwJ$>t_vp(bet2p(jRD;5Q9x2*`|FA4#5cfo8SF@cW zeO{H7C0_YJ*P@_BEvm2dB}pUDYXq@G1^Ee#NY9Q`l`$BUXb01#lmQk^{g3?aaP~(* zD;INgi#8TDZ&*@ZKhx$jA^H-H1Lp`%`O{Y{@_o!+7ST}{Ng^P;X>~Bci{|Qdf1{}p z_kK+zL;>D30r6~R?|h!5NKYOi6X&I5)|ME+NG>d9^`hxKpU^)KBOpZiU^ z;|SzGWtbaclC-%9(zR-|q}kB8H&($nsB1LPAkgcm+Qs@cAov{IXxo5PHrH(8DuEMb z3_R#>7^jjGeS7$!`}m8!8$z|)I~{dhd)SvoH9oR9#LjO{{8O&r7w{d9V1z^syn&E6 z{DG0vlQF_Yb3*|>RzVop^{$mWp|%NDYj@4{d*-@O^<(=L=DMFIQHEp-dtz@1Rumd; zadt^4B#(uUyM6aeUJkGl0GfaULpR!2Ql&q$nEV^+SiDptdPbuJ=VJ)`czZ@&HPUuj zc5dSRB&xk)dI~;6N?wkzI}}4K3i%I=EnlKGpPJ9hu?mNzH7|H0j(mN3(ubdaps3GM z1i+9gk=!$mH=L#LRDf4!mXw0;uxSUIXhl|#h*uK+fQPilJc8RCK9GNPt=X^8`*;3$ zBBo77gkGB5F8a8)*OR10nK&~8CEMPVQyhY>i`PS{L^-*WAz$ljtU%zlG1lm%%U4Zw zms0oZR8b|`>4U1X*9JLQQ>m9MF5%ppoafz^;`7DbmmIENrc$hucekkE4I83WhT%(9 zMaE;f7`g4B#vl(#tNP8$3q{$&oY*oa0HLX6D?xTW3M6f<^{%CK4OE1Pmfue`M6Dh= z&Z-zrq$^xhP%|hU&)(+2KSSpeHgX^0?gRZ5wA8@%%9~@|*Ylux1M{WQ4ekG(T+_b` zb6I)QRGp%fRF)^T?i^j&JDBhfNU9?>Sl6WVMM%S?7< ze|4gaDbPooB=F4Y=>~_+y~Q1{Ox@%q>v+_ZIOfnz5y+qy zhi+^!CE*Lv-}>g^%G=bGLqD(aTN;yHDBH#tOC=X02}QU~Xdme``Wn>N>6{VwgU~Z>g+0 zxv0`>>iSfu$baHMw8(^FL6QWe;}(U>@;8j)t)yHAOj?SdeH;evFx-kpU@nT>lsrUt zqhV}2pD^5bC4786guG1`5|fK@pE6xcT#ns)vR|^?A08G62teHaE&p`ZrCBj_Swt*~dVt=5*RK6Y{% zABqK$X59BnrK3r3u=wxklRnA1uh+q`?T0kE1YhvDWF4OY#<(+V|R@R%tdkq2huF(!Ip+EpZF3zr*|9pmKHPo)Cu z;H+^s&`Ql}u=Jt~ZWj`bAw|i-3#7(2WuRU3DU{BW8`?!O?YO1M$*MMTsaEM!5Jyp~ z!gp6yR4$O%wQ8%dyz43ZPeoJwy;o;yg=S0^Y}%|)to>=N^`!3VMf1~}OZ`Dl$q&|w z9$!i3!i1uAgPTuKSWdBrDr*N$g=E#mdqfj*h;Z}OG`{n245+g;IKfdn!&gF2OtHaD zyGDzj@@d2!P(_Ux)3v;1ABTj__{w*kaRF-1YVU`})Acgk?(T*1YqEve3=5)8bkZK* z!Tus*e$h@^u z>#zV0771Bix~r&h2FJ9)%N{>s>?2tk1$bId)1#G;OKgn-U8jUo^AK;Hu)hQEi}swD(264kAS-SBCD$R(Ro0rh8~Le zzRwxbz_JHDbD+hTX15AWmVw!#rC)-zeZahQQmo6FG1)ah3uuyIuTMof}RO!`Y3^Fxn_-G$23RDOh(@NU?r6`*S?#E50)w zpcsgDZ-iO{;EesgDQq9;p*C#QH(sp~2w^zAJWaUL%@yo)iIL6y8;e_}=dwQc%k%;H zFt5lenH*`}LWd+fPqi;exJeRZgl&nLR%|a!%1x0RQ54cgyWBYrL>sskcAtPxi&8c( zw_K?sI*3n%S;lKiYpveBN08{rgV&-B1NN5Jiu07~%n#%&f!(R(z1)xsxtRBkg#+Lv zh21zX?aYDd_f}qdA`Os*j!eC<5)iUJ&Twj7?*p%vEOGElGhpRZsccM!<k}DeC;TY;rULQs3e}lZyP#UVb=6 zB$Dkm2FaHWUXr7<{R&46sfZ)&(HXxB_=e`%LZci`s7L6c-L7iF&wdmTJz`*^=jD~* zpOZ@jcq8LezVkE^M6D9^QgZqnX&x*mr1_Cf#R9R3&{i3%v#}V$UZzGC;Or*=Dw5SXBC6NV|sGZp^#%RTimyaj@!ZuyJ z6C+r}O1TsAzV9PAa*Gd!9#FQMl)ZLHzTr99biAqA(dz-m9LeIeKny3YB=*+|#-Gq# zaErUR5Z*Wh^e<+wcm70eW;f-g=YTbMiDX)AznDM6B73)T4r%nq+*hKcKF?)#vbv?K zPMe=sFCuC*ZqsBPh-?g!m*O`}6<}Pfj}Y1n9|Y@cUdD5GX_)6Sx9pPfS7 zxkt?g6ZwJ+50C7qrh6dMFmr7qah`FskT_H=GC92vkVh$WfZa2%5L99_DxyM{$#6HQ zx$VR-Wwt!q9JL2{ybEGJr$^?!V4m_BqDqt!mbs=QjHf340+^a{)waVvP0+98(BA$M ztWr&sM=juyYgvf`(SC}+y@QtYgU>0ghJ6VbU}|kEraR&&W%#;!#KI?le%g`e>ZVPiDrneh#&1(Y?uiMo^f5qo@{JEr(p9>8GhDa+PC9yG;lX+D?hQ^fZB&Sdox219zUj_5;+n<0@Wi3@DK`MU8FM!OFJ z8*_mTA-u!Ab#95FRVWTIqAL#BVQGxE_s?>Ql|@0o9vos&r<_4d!+Q6(_270)6#lu$ zV!j$a?_V0I<(3Z=J7C-K0a^Kc1Go9p&T6yQeAD+)dG-$a&%Fo0AOte~_Z&_m2@ue~ z9cKFf-A41Dz31Ooj9FSR`l?H5UtdP?JS=UU$jF#znE1k@0g%K?KQuwZkfDI3Ai)(q z#x_Yo6WR_Y@#6I_02S&NpcP<%sw!!M_3#*8qa+*4rS@x=i{-2K#*Qr)*Q$-{<_(<| z0730e+rubnT38*m;|$-4!1r6u&Ua2kO_s-(7*NGgDTe##%I>_9uW;X__b_k)xlv$; zW%K2hsmr>5e^Z~`tS-eUgWmSF9}Yg8E}qydSVX0nYZMX_x94QK?tw2>^;raVTqstR zIrNAX2`X~|h->dTOb9IrA!i5INpLV}99ES|i0ldzC`;R$FBY5&7+TIy8%GO8SZ37_ zw=^Swk?z+j-&0-cTE|LU0q@IKRa&C6ZlXbSa2vN5r-)*f<3{wLV*uJUw980AFkWN7 zKh{?97GmVu-0rs9FB6ludy|n`gN5p~?y51aJzBg6#+-=0pWdZ2n4xTiQ=&3As-!-6 zFlb|ssAJEJL#s8(=odfz8^9b#@RrvNE4gjuEITzAd7R4+rq$yEJKXP?6D@yM7xZ&^ z@%jnE3}bteJo{p(l`hu`Yvzg9I#~>(T;>c;ufeLfc!m3D&RaQS=gAtEO-WbI+f_#| zaVpq-<%~=27U8*qlVCuI6z9@j)#R!z3{jc>&I(qT-8IBW57_$z5Qm3gVC1TcWJNc% zDk?H3%QHno@fu9nT%L^K)=#sRiRNg|=%M zR;8BE)QA4#Dsg^EakzttRg9pkfIrF3iVYVM#*_+#3X+~qeZc^WQJvEyVlO@9=0pl!ayNOh|{j0j^a z+zi_$_0QKhwArW)sJ$wji;A`?$ecbr?(4x5%2pLgh#wggbt)#T^2R3a9m+>GcrUxU z*u-WTgHAN*e!0;Wa%1k)J_P(Vdp>vwrROTVae@6Wn04q4JL-)g&bWO6PWGuN2Q*s9 zn47Q2bIn4=!P1k0jN_U#+`Ah59zRD??jY?s;U;k@%q87=dM*_yvLN0->qswJWb zImaj{Ah&`)C$u#E0mfZh;iyyWNyEg;w0v%QS5 zGXqad{`>!XZJ%+nT+DiVm;lahOGmZyeqJ-;D&!S3d%CQS4ZFM zkzq5U^O|vIsU_erz_^^$|D0E3(i*&fF-fN}8!k3ugsUmW1{&dgnk!|>z2At?h^^T@ zWN_|`?#UM!FwqmSAgD6Hw%VM|fEAlhIA~^S@d@o<`-sxtE(|<><#76_5^l)Xr|l}Q zd@7Fa8Bj1ICqcy2fKl1rD4TYd84)PG5Ee2W4Nt@NNmpJWvc3q@@*c;~%^Vasf2H`y z+~U-19wtFT?@yIFc4SE_ab?s@wEUfSkOED}+qVjjy>=eac2^S^+|_3%cjH%EUTJ&r znp9q?RbStJcT*Vi{3KDa^jr4>{5x+?!1)8c2SqiCEzE$TQ+`3KPQQnG8_Qk<^)y_o zt1Q^f{#yCUt!1e(3;E6y?>p+7sGAYLp`lA3c~Y`re9q&`c6>0?c0E2Ap5seFv92#X z1Vldj!7A8@8tWr&?%;EBQ_Fwd)8A3!wIx`V!~~h(!$pCy7=&*+*uIzG@*d%*{qG#4 zX0^}}sRN^N=p{w(+yjv%xwb!%lnVTE7l1l6gJwQmq_G83J&Y98$S!r*L8}IiIa2E= zE!0tbOuEDb*No0-KB{zjo1k#_4FHtr{!)>o+Y@bll}Sa6D^xktI0H&l{jKAK)A(iz zB-N00F?~Z}Y7tG+vp)-q*v71(C}65$-=uXx^|R$xx9zZip-V>Hqeyfd(wteM)+!!H z$s+>g4I@+`h2>C|J;PhvtOq)`xm4;CyF}R<)!ma3T{Vf_5|zo;D4YI4ZDBkE(vMeE zb#ZV;n}CgA0w8x!UC2&5Z(K)9bibj#?~>R(72lFx_Am~jS?;7mo~p+05~XGD+(wV4 zEVYnf0N5+-7O+Gc1L!sPGUHv<6=cV8}*m$m`kBs@z zy;goR(?J^JrB7uXXpD00+SD0luk!vK3wwp(N%|X!HmO{xC#OMYQ&a7Yqv-54iEUK4 zVH;)rY6)pUX~ESvQK^w|&}>J{I?YlvOhpMgt-JB}m5Br`Q9X+^8+Xa%S81hO<1t#h zbS+MljFP1J0GGNR1}KwE=cfey%;@n&@Kli+Z5d>daJjbvuO3dW{r$1FT0j zR$c9$t~P50P+NhG^krLH%k}wsQ%mm+@#c;-c9>rYy;8#(jZ|KA8RrmnN2~>w0ciU7 zGiLC?Q^{^Ox-9F()RE^>Xq(MAbGaT0^6jc>M5^*&uc@YGt5Iw4i{6_z5}H$oO`arY z4BT(POK%DnxbH>P$A;OWPb@gYS96F7`jTn6JO@hdM za>_p!1mf?ULJZb1w-+HamqN__2CtI%VK`k^(++Ga0%z*z@k0wYJDqT^)~%|4O299; zh1_iRtc7you(kOK8?Q$R7v-@Qk4+i=8GD2_zI0%{Ra`_prF{+UPW^m5MCA&4ZUpZb z2*!)KA8b--Upp~U%f+rsmCmV~!Y>Gzl#yVvZER2h;f&rkdx{r#9mc8DZMJaQXs?SL zCg3#>xR6ve8&YkP*`Z=lng|Ow+h@t*!Ial*XQg3P;VS8@E1C)VS`?L9N+rxlD7bxC z3@Ag)Vu?#ykY`ND+GvRYTUP&-KDMiqly$Z~uFXt^)4Jjk9RIs*&$?-UPM*d7&m${m zm12kaN3mV1J|c6f$>V+{lvHp~XVW3DU0;cBR>7|)4bo{xa1-ts-lYU-Q-b)_fVVl`EP5X}+J9EzT20x8XIv=m7witdu7!3Lh=KE#OyKpT1GWk{YAo^ny|fvZt<+jmsFs=l*%e& zmRkBt5ccv4O7!HAyv2~rsq*(FmMTm?@TX3&1`nu|7C^F{ad%GLuoX}Rl}6`)uHF_xlx^gVca+mGH4T8u8;q{S*x3=j;kelz^atO~)v!Q_BT z4H6%IA}bvfuk0_vweELeEl8N5w-Q1GF!@f{VKnbyYB2?}d&QvI-j}~RI_+9t9$tC2 z94m=3eLi=sQb^S5;fqP?3aaXc&`}`lq z&M8dOXvxx9Y1^u_ZQHhO+qP}nwkvJhwoz$Mp6Qcq^7M#eWm}!3U@s07hop` zW24|J{t$aB`W>uBTssEvYMyi$hkaOqWh+^(RV_1MYnE0XPgW?7sBDk=Cqs(;$qrPEflqa0ZE?A3cBfW%0RPA235Wb6@=R_d>Sez; z`spwa50bq?-zh+id~Q!T`AYn`$GHzs;jxIw(A1_Ql&f|qP}|bon#H;sjKmSDM!nyn z>bU8l%3DB3F+$}|J^da!!pN|DO!Ndc2J)wMk!+Rr1hes#V}5o(?(yQSphn|9_aU<- zn|nsDS{^x&tweP;Ft`2ur>Koo2IdXJDsr6IN)7vB41Yy-^Wbo9*2th2QA@C zE0-0Gk12YOO?d_Guu6b3&(PIL`d zh4{`k54hu9o%v1K3PGuccez-wdC<&2fp)>`qIIaf)R{5un7-vwm=>LD7ibnJ$|KyE zzw`X*tM0S|V(I3vf454PY{yA5lbE+36_<1kd=&0Xy4jfvUKZ0$Jq!AG4KS7DrE9rph;dK^6*#CIU9qu7 z?)6O`TN&MCWGmUVd1@E2ow2`vZ1A#nGo8_n!dmX77DCgAP1va*ILU+!a&$zdm6Pa6 z4#|*&3dM+r_RJb%!0}7X!An&T4a4@ejqNJ;=1YVQ{J6|oURuj8MBZ8i7l=zz%S4-; zL}=M^wU43lZVwNJgN|#xIfo$aZfY#odZ6~z?aNn=oR1@zDb=a(o3w`IGu&j>6lYxL z&MtqINe4Z>bdsHNkVIu$Dbq0wc#X-xev221e~L zbm8kJ(Xzij$gF4Ij0(yuR?H1hShSy@{WXsHyKtAedk4O!IdpR{E32Oqp{1TD{usJi zGG@{3A$x%R*pp8b$RQo4w&eDhN`&b~iZ2m3U>@9p1o5kXoEVmHX7I6Uw4dn((mFw` zilWrqFd=F5sH$&*(eJB52zaLwRe zz`sruIc=Ck75>v5P5kd>B2u=drvGPg6s&k5^W!%CDxtRO)V6_Y_QP{%7B>E~vyMLG zhrfn8kijyK&bX+rZsnSJ26!j$1x+V!Pyn|ph%sXWr9^f&lf|C;+I^Fi_4;`-LJI&F zr;5O@#4jZX=Yaw0`pUyfF4J8A9wE#7_9!X|_s8~YUzWu&#E^%4NxUA3*jK-F5R3LP2|msHBLmiMIzVpPAEX)2 zLKYjm3VI4r#7|nP^}-}rL+Q4?LqlmBnbL+R8P%8VmV{`wP0=~2)LptW_i682*sUR# z+EifOk_cWVKg-iWr^Qf4cs^3&@BFRC6n0vu{HqZzNqW1{m)3K@gi$i}O(hT`f#bT- z8PqCdSj~FncPNmMKl9i9QPH1OMhvd42zLL~qWVup#nIJRg_?7KQ-g3jGTt5ywN;Qx zwmz4dddJYIOsC8VqC2R%NQ>zm=PJH70kS|EsEB>2Otmtf-18`jUGA6kMZL3vEASDN zNX%?0+=vgsUz!dxZ@~)eU17m4pN3xGC0T;#a@b9Iu0g_v*a3|ck^s_DVA^%yH-wt= zm1)7&q6&Rq#)nc9PQ6DKD{NU=&ul10rTiIe!)x^PS~=K(wX9|?k&{Mv&S$iL9@H7= zG0w~UxKXLF003zJ-H%fGA4Db9{~#p&Bl7ki^SWwv2sfoAlrLMvza)uh;7Aa_@FL4b z4G>`j5Mn9e5JrrN#R$wiB(!6@lU@49(tawM&oma6lB$-^!Pmmo;&j57CDmKi)yesg~P;lJPy9D(!;n;^1ql)$5uYf~f z&GywSWx=ABov_%8pCx=g-gww_u26?5st=rdeExu?5dvj^C?ZZxDv@Si^nX~2qA&K= z2jr;{=L(x~9GLXrIGXs>dehU^D}_NMCMegdtNVWyx)8xHT6Qu!R>?%@RvADs9er;NMkweUBFNrBm1F5e0_>^%CwM6ui}K_MpRqLS0*@lAcj zB6TTCBv>w2qh)qU3*kN+6tPmMQx|5Z0A4n67U-nss90Ec_rDF}r)IR4PE{$8;BSt= zT%6|jyD^(w6a*A5>_|TkMqx~e$n@8{`q?|)Q&Y4UWcI!yP-8AwBQ#P`%M&ib;}pli z9KAPU_9txQ3zOM#(x}*lN8q$2(Tq1yT4RN0!t~|&RdQMXfm!81d0ZuyD}aG3r4+g` z8Aevs3E_ssRAMR+&*Q30M!J5&o%^(3$ZJ=PLZ9<@x^0nb>dm17;8EQJE>hLgR(Wc% zn_LXw|5=b$6%X zS~ClDAZ?wdQrtKcV9>_v1_IXqy)?<@cGGq#!H`DNOE1hb4*P_@tGbMy6r@iCN=NiA zL1jLwuMw&N-e9H(v7>HGwqegSgD{GSzZ@sZ?g5Y`fuZ^X2hL=qeFO(;u|QZl1|HmW zYv+kq#fq_Kzr_LaezT zqIkG6R+ve#k6!xy*}@Kz@jcRaG9g|~j5fAYegGOE0k8+qtF?EgI99h*W}Cw z7TP&T0tz4QxiW!r zF4?|!WiNo=$ZCyrom-ep7y}(MVWOWxL+9?AlhX<>p||=VzvX`lUX(EdR^e5m%Rp_q zim6JL6{>S%OKoX(0FS>c1zY|;&!%i-sSE>ybYX3&^>zb`NPj7?N^ydh=s=0fpyyz% zraFILQ17_9<ettJJt~I+sl=&CPHwz zC9dEb#QFQcY?bk11Y=tEl{t+2IG`QFmYS>ECl;kv=N6&_xJLQt>}ZQiFSf+!D*4Ar zGJ~LFB7e_2AQaxg*h{$!eJ6=smO(d2ZNmwzcy3OG@)kNymCWS44|>fP^7QkJHkE9JmLryhcxFASKb4GYkJ|u^Fj=VdF0%6kgKllkt zC|_ov2R4cJ2QjjYjT6jE#J1J<xaNC>Xm;0SX<`LuW*}*{yQ3c9{Zl=<9NP z^2g5rAdO!-b4XfeBrXa4f{M0&VDrq+ps&2C8FYl@S59?edhp~7ee>GR$zQI4r8ONi zP^OA+8zrTAxOMx5ZBS03RS@J_V`3{QsOxznx6Yt*$IuEd3%R|Ki&zZkjNvrxlPD$m z%K+rwM!`E&Z46ogXCu!3 z8use`FJJ?g_xi?~?MxZYXEu=F=XTC8P3{W*CbG3Wk)^31nD~W>*cJ@W4xg%Qqo7rq z`pUu8wL!6Cm~@niI*YmQ+NbldAlQRh?L!)upVZ)|1{2;0gh38FD&8h#V{7tR&&J}I zX1?;dBqK}5XVyv;l(%?@IVMYj3lL4r)Wx9$<99}{B92UthUfHW3DvGth^Q0-=kcJ1 z!*I9xYAc$5N$~rXV>_VzPVv`6CeX(A_j3*ZkeB~lor#8O-k+0OOYzTkri@PVRRpOP zmBV|NKlJT?y4Q82er)@lK&P%CeLbRw8f+ZC9R)twg5ayJ-Va!hbpPlhs?>297lC8 zvD*WtsmSS{t{}hMPS;JjNf)`_WzqoEt~Pd0T;+_0g*?p=dEQ0#Aemzg_czxPUspzI z^H5oelpi$Z{#zG$emQJ#$q#|K%a0_x5`|;7XGMuQ7lQB9zsnh6b75B9@>ZatHR_6c z0(k}`kfHic{V|@;ghTu>UOZ_jFClp>UT#piDniL(5ZNYXWeW0VRfBerxamg4su5<; z(}Ct2AhR@I-ro0}DdZLRtgI@dm+V`cRZjgV-H+aXm5|Mgz`aZX63i<|oHk-E)cABn z0$NR?(>fla7)Ong28FZSi9Yk0LtYl5lZw5wT!K5=fYT$avgkMKJWx~V#i@7~6_{dM zxDDPIW2l{O2Elv#i^cjYg~lGHRj(W*9gD`(FILKY$R`tL2qo&rtU*c;li!V`O$aV{ z!m|n!FAB2>MR_FVN*Ktv5+2dW4rr3YmfEheyD+48%USM#q6)w%#2}~=5yZE1LLcth zF%VtefH&#AcMx7)JNC$P>~OFuG6sK}F7V$D7m!{ixz&inpAVpFXiu^QruAw@Sc7Y2 z_A^V(2W_+KTGRp2aQSMAgyV#b3@{?5q@hPEP6oF3^}|@8GuD6iKbX;!LI!L=P#Za zL$Zuv#=x3fseRMZ()#SQcXv->xW`C|6quwqL1M&KByBj z2V`}(uL4JB-hUs6304@%QL~S6VF^6ZI=e-Nm9Tc^7gWLd*HM-^S&0d1NuObw-Y3e> zqSXR3>u^~aDQx>tHzn9x?XRk}+__h_LvS~3Fa`#+m*MB9qG(g(GY-^;wO|i#x^?CR zVsOitW{)5m7YV{kb&Z!eXmI}pxP_^kI{}#_ zgjaG)(y7RO*u`io)9E{kXo@kDHrbP;mO`v2Hei32u~HxyuS)acL!R(MUiOKsKCRtv z#H4&dEtrDz|MLy<&(dV!`Pr-J2RVuX1OUME@1%*GzLOchqoc94!9QF$QnrTrRzl`K zYz}h+XD4&p|5Pg33fh+ch;6#w*H5`@6xA;;S5)H>i$}ii2d*l_1qHxY`L3g=t? z!-H0J5>kDt$4DQ{@V3$htxCI;N+$d^K^ad8q~&)NCV6wa5(D${P!Y2w(XF!8d0GpJ zRa=xLRQ;=8`J2+A334};LOIhU`HQ*0v4Upn?w|sciL|{AJSrG_(%-(W9EZb%>EAGG zpDY?z1rQLps`nbCtzqJ#@wxU4}(j!ZQ{`g`g*SXlLah*W9 zyuh)UWoRCknQtd~Lk#BT_qjwj&Kw8U)w=owaJ;A5ae}3)y>{neYNS`|VHJdcSEBF# zBJ6a;T)u;^i#L~LVF-X7!E$SggILXMlsEy~v}K*DM2)f@U~g|Q6I-Pss@)`>fgFWx zsq&7pe!|VA-h;@=fBF{(mR1^{1>ukTYUdyF^#A+(|I_&nm{_xaKn3h4&yMyym2k-wMFg(s@ez=DPmuB%`| z6;e@HQKB(|!PU1sW)W6~x|=8m6rL~4dQ9LTk|RzL-_(_77B4I~ZG=q7K%qHiv!FD8 zmt;Vnhb{ymaydv2V;X-5p zTt2ln?kaB9&(dH_X70^@rrCfz)nwfa9LYTHXO(IPcTEf$QiEhTpl??L+`Eetyqof8 zzl=q)?KdYni!C_9b8Z3xm7r5<5ZG-0uA`u^7Dm7k4mAsQ(rkoWy*^DZJa~#y6+hNG zh?7{D9$a9LS`a@SvZ5?C{JUHovWU9KI}z8YV4pWftx21v*Q;MpU{+b@>Or(}pwO^fu0qA3_k_Bo2}lIxvmMhucG-o>O=+R6YxZ zjs!o%K1AA*q#&bs@~%YA@C;}?!7yIml1`%lT3Cvq4)%A)U0o1)7HM;mm4-ZZK2`Lj zLo?!Kq1G1y1lk>$U~_tOW=%XFoyIui^Cdk511&V}x#n4JeB7>bpQkYIkpGQRHxH$L z%tS=WHC~upIXSem>=TTv?BLsQ37AO88(X+L1bI<;Bt>eY!}wjYoBn#2RGEP49&ZH-Z_}R_JK_ z>o*_y!pOI6?Vf*{x-XT;^(_0}2twfk`*)_lLl0H-g|}BC?dm7CU|^-gNJ~rx z($>97WTKf71$?2|V$Ybpf~Aj@ZZOcb3#uRq51%4^ts-#RMrJhgm|K3QpCsPGW=2dZ zAr5-HYX!D*o#Q&2;jL%X?0{}yH}j*(JC4ck;u%=a_D6CrXyBIM&O#7QWgc?@7MCsY zfH6&xgQmG$U6Miu$iF(*6d8Mq3Z+en_Fi`6VFF=i6L8+;Hr6J zmT=k0A2T{9Ghh9@)|G5R-<3A|qe_a#ipsFs6Yd!}Lcdl8k)I22-)F^4O&GP&1ljl~ z!REpRoer@}YTSWM&mueNci|^H?GbJcfC_Y@?Y+e4Yw?Qoy@VLy_8u2d#0W~C6j(pe zyO6SqpGhB-;)%3lwMGseMkWH0EgErnd9a_pLaxbWJug8$meJoY@o-5kNv&A$MJZ=U z^fXPLqV6m3#x%4V*OYD zUPS&WHikdN<{#Yj|EFQ`UojD4`Zh*CZO4Cv`w^&*FfqBi`iXsWg%%a< zk@*c%j1+xib(4q^nHHO^y5d8iNkvczbqZ5;^ZVu%*PJ!O?X-CoNP*&tOU!5%bwUEw zQN?P*a=KKlu{`7GoA}DE=#nDibRgecw>-*da~7&wgow}|DyCJq!-Lp8a~(zR@tO1 zgu(4s4HptPGn(HmN2ayYs@g+yx1n`nU3KM{tQHhMHBw7f#gwru$=C()`aKZAl^dYc ze7fC)8EZEXOryk6AD&-4L+4cJ&M@3;;{R)mi4=`ti7IZByr^|_HNsjcNFu?mIE)jD za2j)FPwRY!R_YR-P?URm0Pti*e#5jmfK)6EvaKCT{h)kbJl{AGr1Ekt}pG?^e z*botRf-RsB8q10BTroj{ZP**)2zkXTF+{9<4@$aNDreO7%tttKkR3z`3ljd?heAJEe<0%4zYK?};Ur*!a>PbGYFFi(OF-%wyzbKeBdbkjv^i9mn@UocSS z4;J%-Q$l`zb&r*Pb`U;3@qkc=8QaPE9KwmlVwAf01sa*uI2*N`9U^3*1lLsM9dJ(4 zZBkU}os|5YT#Z;PD8xVv!yo$-n{-n4JM5ukjnTciniiT`(cZ6sD6~67e5_?8am%!w zeCLUxq~7x-!Xg#PgKV&caC@7mu<86am{WaXo(lAemt4~I$utSp(URWpYNo$RvU*$N z#%iiA+h`(E;BUg;=I!#EaxO89bUK3*v5Nc3GPmURC5TqzC|))DsFNtJICH6oBW6#q z+B(N{ey+^mk_{!@ z)VhAWXG=_0j|0f9iJ;c404PiIFqK)(AD05Xh`Fk`r$^b`v+>*g+_+h@r)e+ELJ45) z?20~u<}HQyQ5AsBz(teF9!!_GLXnm{5Z0e{Ki*@!=&3x4-RcjBn##DDzHJ|KSZ5(E z9=tFZ)p~-}x%9sCY27)2i>(E-^OiYT?_)a;yXAGR$y+E`myMd;xDA#_Q49t*E}&ql#H~|x z2J2R1_#2lt91NnF!uqW%_=HlbF?A{B{n>}9$g5QF!bh_a7LTU~Jyz}7>W5{_LAov{ zy2_dmGy)d)&7^bJyUjEw%3xj{cuG0Eo zwL*XQB*Oi=r&HIIecC1%lbE;Y-*5|cL955S+2@uR18JDL<0;;Uc2Q9JEyo1R!!sz_ z#BqnkGfbLP#oQJk3y}nwMd(3Tt^PVA#zXnYF7D0W1)#+`i?@cm}fBkKD z+Mpcuim53|v7;8Tv(KraEyOK`HvJq^;rlNzOjIbW&HJDFqW>doN&j7)`RDv#v|PQ+ z03WnB4Y4X@Fe-@%3;He*FjY1MFmkyv0>64Cp~FIDKQTwmFP~_CxZOf{8gPy}I<=JC zo%_bmue&$UU0|GG%%99eI!m#5Y1MD3AsJqG#gt3u{%sj5&tQ&xZpP%fcKdYPtr<3$ zAeqgZ=vdjA;Xi##r%!J+yhK)TDP3%C7Y#J|&N^))dRk&qJSU*b;1W%t1;j#2{l~#{ zo8QYEny2AY>N{z4S6|uBzYp>7nP_tqX#!DfgQfeY6CO7ZRJ10&$5Rc+BEPb{ns!Bi z`y;v{>LQheel`}&OniUiNtQv@;EQP5iR&MitbPCYvoZgL76Tqu#lruAI`#g9F#j!= z^FLRVg0?m$=BCaL`u{ZnNKV>N`O$SuDvY`AoyfIzL9~ zo|bs1ADoXMr{tRGL% zA#cLu%kuMrYQXJq8(&qS|UYUxdCla(;SJLYIdQp)1luCxniVg~duy zUTPo9%ev2~W}Vbm-*=!DKv$%TktO$2rF~7-W-{ODp{sL%yQY_tcupR@HlA0f#^1l8 zbi>MV~o zz)zl1a?sGv)E}kP$4v3CQgTjpSJo?s>_$e>s2i+M^D5EfrwjFAo(8E%(^ROV0vz0o z-cg0jIk24n!wxZainfH)+?MGu@kg$XgaMY-^H}z^vG~XC7z2;p2Kv`b^3S#b5ssMOJ7724v>S36dD zeypxJ<=E~sD4f5wX060RIF-AR0#{Z z=&y$r8A-e6q18lIF{@O9Mi%dYSYT6erw!@zrl=uj>o(3=M*Bg4E$#bLhNUPO+Mn}>+IVN-`>5gM7tT7jre|&*_t;Tpk%PJL z%$qScr*q7OJ6?p&;VjEZ&*A;wHv2GdJ+fE;d(Qj#pmf2WL5#s^ZrXYC8x7)>5vq_7 zMCL}T{jNMA5`}6P5#PaMJDB2~TVt;!yEP)WEDAoi9PUt89S2Cj?+E0V(=_sv4Vn6b z_kS6~X!G;PKK>vZF@gWpg8Zuh%YX^2UYPdCg7?EH#^gkdOWpy(%RnXyyrhmJT~UJw zAR;%Zgb6z(mS+o9MT|Sc6O({!i0pzk;s9?Dq)%tTW3*XdM3zhPn*`z45$Bg!P4xfy zD*{>30*JsSk?bQ-DgG62v>Vw-w`SA}{*Za7%N(d-mr@~xq5&OvPa*F2Q3Mqzzf%Oe z4N$`+<=;f5_$9nBd=PhPRU>9_2N8M`tT<-fcvc&!qkoAo4J{e3&;6(YoF8Wd&A+>; z|MSKXb~83~{=byCWHm57tRs{!AI<5papN(zKssb_p_WT@0kL0T0Z5#KLbz%zfk?f7 zR!vXBs36XaNcq5usS7<>skM_*P$e*^8y1ksiuokbsGFQ_{-8BAMfu!Z6G=88;>Fxt z|F-RU{=9i6obkTa0k~L#g;9ot8GCSxjAsyeN~1;^E=o5`m%u7dO1C*nn1gklHCBUw z;R(LgZ}sHld`c%&=S+Vx%;_I1*36P`WYx%&AboA1W@P;BvuFW+ng*wh?^aH4-b7So zG?9kFs_6ma85@wo!Z`L)B#zQAZz{Mc7S%d<*_4cKYaKRSY`#<{w?}4*Z>f2gvK`P1 zfT~v?LkvzaxnV|3^^P5UZa1I@u*4>TdXADYkent$d1q;jzE~%v?@rFYC~jB;IM5n_U0;r>5Xmdu{;2%zCwa&n>vnRC^&+dUZKy zt=@Lfsb$dsMP}Bn;3sb+u76jBKX(|0P-^P!&CUJ!;M?R?z7)$0DXkMG*ccBLj+xI) zYP=jIl88MY5Jyf@wKN--x@We~_^#kM2#Xg$0yD+2Tu^MZ1w%AIpCToT-qQbctHpc_ z>Z97ECB%ak;R<4hEt6bVqgYm(!~^Yx9?6_FUDqQQVk=HETyWpi!O^`EZ_5AoSv@VbUzsqusIZ;yX!4CsMiznO}S{4e>^0`c<)c~mC#*{90@+T@%EQ~>bovc8n_$bvqkOU7CrYe8uI5~{3O7EijeX`js z-$LNz4pJA7_V5~JA_Wl*uSrQYSh9Wm($%@jowv^fSPW<~kK&M*hAleywHd?7v{`;Y zBhL2+-O+7QK_)7XOJAbdTV-S`!I)t~GE8z+fV7y;wp#!wj75drv;R*UdSh(}u$%{VSd0gLeFp;h6FkiVz%g=EY3G#>RU;alRy;vQmk*| z@x-ba0XKE%IyL4OYw6IXzMiS(q^UDk=t(#XgkuF`{P?=k8k3r)rmhkv`vg@kiWd34 z-~t+1aV3SabTbG=nQYs>3~E<}{5@0g**LAWi*~SfRZhGcgP{e5T!0M7CU}`f@r8xI z0bx%sI!?5);-wG+Mx&S=NRfIi>V-wP(n&$X0Bhd)qI^ch%96s6&u7qpiK8ijA=X_R zk&|9f$GXf-;VgnrxV83Cp-Q!!sHH`5O^o~qZu!xny1t?(Au(EAn)D??v<1Uo;#m7-M@ovk|()C(`o>QMTp}F?> zakm3bHBKUjH-MHXDow7#Z|@wea1X9ePH;%YA)fCZ9-MD)p^(p!2E`aU9nmJlm;CXQ zkx~$WQ`Yq{1h5k>E>Ex{Z=P=)N*0b8_O({IeKg?vqQ)hk=JHe z5iqUKm!~mLP0fnRwkCO(xxTV@&p+o8wdSP$jZofYP}yEkvSc z5yD-^>04{zTP7X44q9Af&-wgt7k|XtncO&L@y-wFFR44RsPu57FRvIBaI^Pqy_*DV z@i13CsaR5@X@xH=NT3}T`_vsy!a02n80eQqya=-p7#YW`Jc0z!QglGg`1zeg6uXwI zsB~hlNMo)kFL(V3Q1<%8yoI6X7ncn-&&Uh3rL@S(6@wKAXt6Wr=a2ObI7}8$D-FoI z>AJA>WsBEMi5ba6JhJ%9EAi&ocd(ZsD|MsXwu@X;2h#|(bSWu@2{+c7soC`%uo{sMYq&Vyufb)?OI59ds)O+kyE8@G z@tlpNr0UO~}qd0HQve6njJ zda2+l$gdX7AvvGhxM6OToCuQ|Zw|9!g1)O+7>~{KNvASjp9#Cqce-or+y5xdzWL3gLWt2oa+T(I+{j(&bF1laUsJB{fOgE-B}qslaS>C z)TjzG8XecbS%a+?yT!0QmTex?E478;D|sL*oS4C-g0Tq(YoH|eyxJ#1j088C|U-w5id`%Sz7X_w#l+U9+)$|2no<}5J zRb_9@0esSr?n}HvVGbD5@$p$8k4?qOe-GNOk3-K^Mw>Xg+drCKi5@$GTeijpI;;IG ziD<&go`ptLC&^<0jw^l0aY?_pUUK+xp#0Bk66iQ29vpR)VBE{JOJ&OL^gKsN<&t<| zCMLTYMSDG5Ie9O>6Dl#T{@cscz%)}?tC#?rj>iwQ0!YUk~R z$rB-k=fa9x&631Z9Mfqj_GRoS1MzqSMEdaZ2!isP19Sr>qG8!yL(WWF)_&{F)r>KnJGSciSp!P0fqHr+G=fGO02Q#9gHK zpwz+yhpC4w*<9JO@#(MdkZcWbdCO5B!H`Z|nV?UtcBo96$BgX+7VYMwp@b-%;BrJu zMd*K!{1txv{kHKPDs9?WZrz_^o1Tq2P=+=|E=Oy4#WE{>9}*9(apqhmE`&AeBzQgQ zELFLCmb~q|6y0FCt|B}*uI*ayZ#6=$BpGtF{Jfye#Q>FZ?BPnk)*Qmd?rNG^tvFUU z_b&antYsZnUR6Q9tQUy81r$&ovT#fy;(Db4F&M*C=KxQgHDrRcVR#d+ z0(D|*9#u`w_%2o3faI{?dNd9$#5nj1PROHNq z7HJ(;7B1ThyM>a@Fo^lJb2ls2lD`}ocREH|5pKN;$>gFyM6k)kZG;lA;@kSJIqUhf zX%dhcN(Jtomz4(rNng&1br3Xx33EvCWz%o8s;SpRiKEUFd+KJ+u|gn|J85dZ)Exc&=V|Ns8Xs#P>qv6PX&VAJXJ(ILZO!WJd0 z`+|f5HrEj~isRN7?dBHotcPI7;6W48*%J(9 zftl1Tr`bKH*WNdFx+h;BZ+`p!qKl~|Zt5izh}#pU9FQKE97#$@*pf38Hr8A+`N+50U3$6h%^!4fBN zjh^cl#8qW5OZbvxCfYzKHuyeKLF4z^@~+oqlz9(Hx8vypIiUlt!(vs}_t#4@nh$s; z>FYERg*KD#Xs+W4q-V-IBQK!)M1)Aa+h+V+is)z!_=gEn&^ci7<DEEmYcoSh?WdXUsP7O4)&lQXA(BVM5jI8s6;mO}94AC0gG(`>|T)yuV1l~i-ejCCt zoejDhX0nrZDP|x9u4zp%S2UeDzV`o#pBGu1tZ-$<9TIbN=ALwhQ0=9S{8#}Uu8n-~ z5~xIvUhLSz@c@0|me$CdZCpZl(vQw@a0Y4^{T0w_>pOkwI^x4KkBf3qGmm)nG|Ps5 z_XTY~^b^mL&_*yjl~RRIi&eS(>y?y}O4-)nWyTEPpQAb#Xz8SnnfIL+nAcNL9nqV9 zRL|eyF)RKI5-kJO6}>Q89XmgY@b1&!JI>g3ryZ@jN2v3vm7O`AL!BTWNouJzV+$+Y zYY}u%i>K6=IYU2O$2TAyVjGt?wgF9xCj;?EK(8fWu!!~48`3u^W$eUlCh*91PLxu1 zRY(F7Q3s7h$Q-p&L$ucN}it*-9KR z_<wHu?!dav0$P+PI3{J8?{+l|n&2YMLV2 z+hRta$A5WpCXl1RNbYBsX8IGX{2v>U|8_I-JD56K|GexW>}F_e_g_1r?08v8Kz{V$ zT=6aGMk>ibvRO@Yrc@ezaD0%ydHkXGHrR{7>q~~tO7ChJflwa4-xL|@#YIJejC5VT zInU4CjQ9V0+lClQY=vh^s4MadwQmk7li{54Y;Ht}gkZOIh9(vfK?3kXLoD72!lHD# zwI-Jg|IhT=Y#s|tso1PWp;|aJ2}M?Y{ETyYG<86woO_b+WVRh<9eJu#i5jxKu(s~3 z4mz+@3=aNl^xt{E2_xewFIsHJfCzEkqQ0<7e|{vT>{;WlICA|DW4c@^A*osWudRAP zJut4A^wh@}XW4*&iFq|rOUqg*x%1F+hu3U6Am;CLXMF&({;q0uEWG2w2lZtg)prt` z=5@!oRH~lpncz1yO4+)?>NkO4NEgP4U~VPmfw~CEWo`!#AeTySp3qOE#{oUW>FwHkZ3rBaFeISHfiVSB7%}M) z=10EZ1Ec&l;4 zG98m5sU!pVqojGEFh8P{2|!ReQ&hfDEH2dmTVkrS;$dN~G2v-qnxn^A2VeHqY@;P} zudZD5vHtVvB*loIDF1M7AEEvS&h0;X`u}!1vj6S-NmdbeL=r{*T2J6^VA7F`S`CDd zY|=AA6|9Tu8>ND6fQhfK4;L3vAdJPBA}d6YOyKP&ZVi%z6{lbkE|VyB*p1_julR^k zqBwjkqmFK=u&e8MfArjW-(Ei8{rWso1vt5NhUdN|zpXqK{ylJ8@}wq-nV~L4bIjtt zt$&(1FTIs+aw}{&0SO4*sa0H2h&7g}VN5uYjfed5h7eGp$2Wu*@m9WIr0kxOc}fX9eOWh zFKfV>+SD$@kESKYm{F*J90XQjr$!<~v(J%&RMuQM+6CkmnYZDGlOUdq}%)VA& zl#acS%XE2KuX~7IamK`og@C`21~*cEEc#PZM6HT*Veb_l&Ej~j0zL7p0Eo`mMu(=X zJ$v;&Lya75I4C^saKROgfi(fdP0C$GM3WyZn%mm3yEI>|S&O(u{{S<}ihUp#`X&_z zmQBma;82#`C;dR5Sx09e07FvtJLhZ{9R~|$FCdU6TDNUwTc9kNct?8e@o2MpQDrkg zN?G+aYtTjiUPA=RX5o{4RYu}6;)ET>TcgL^VpfIpluJ|lQR(_)>6k%L^FZmoK-Wm- zR5qy0P)hm8yvqOL>>Z;k4U}!s?%1~7v7K~m+gh=0c9Ip_9UC3nwr$%^I>yU6`;2kV z-uJ%y-afzA7;BC7jc-=XnpHK+Kf*tcOS>f5ab2&J&5hIOfXzs=&cz|Qmrpu6Z);`R z0%3^dioK5x?o7t~SK7u5m{dyUZ#QUPqBHYn@jETeG>VU=ieZuJ;mm^j>dZM7))cw?a`w8R z%3M0R=kdOt^W^$Kq5Z%aJ(a$(*qFpy^W}Ij$h+Jnmc9eaP(vB@{@8t zz=RQ$x4XYC#enS$fxh@;cSZ|D%7ug;0z{C8I8h{KocN-cyv3UG_nk99UNS4ki^OFkYea`q`rs zG@qdMI;4ogcd5Tr`di1JBg4I*6CFvCID_2SN5&)DZG&wXW{|c+BdQ4)G9_{YGA@A* zaf}o^hQFJCFtzt&*ua~%3NylCjLtqWTfmA-@zw;@*?d&RE3O8G&d;AVC|rZrU}jx# zC-9SF`9;CbQ(?07o8Q9E12vi)EP@tOIYKEKnO@-o!ggkC)^#L-c40iZtb4Y-cS>$I zTn~+>rn*Ts>*y*z^b3-fAlne+M-*%ecrI^rmKAVv23cB`aWD?JDJ5NIafRvRr*~~C z)99Afs`BPK!5BFT)b_^8GyH*{22}yDq;be`GnPl=vW+ITnaqzl(uYOHhXi}S!P+QZ z4SwfEPuu&z4t#?6Zaw}bvN{;|80DfxCTuOdz-}iY%AO}SBj1nx1(*F%3A-zdxU0aj z`zzw9-l?C(2H7rtBA*_)*rea>G?SnBgv#L)17oe57KFyDgzE36&tlDunHKKW$?}ta ztJc>6h<^^#x1@iTYrc}__pe0yf1OnQmoTjWaCG`#Cbdb?g5kXaXd-7;tfx?>Y-gI| zt7_K}yT5WM-2?bD-}ym*?~sZ{FgkQ9tXFSF zls=QGy?fZ=+(@M>P3Y>@O{f44yU^fP>zNzIQ0(&O$JCd_!p?2;} zI6E1j@`DxzgJvqcE@zgapQ?tophO14`=14DUZ*#@%rRi``pi0lkNgidSsHGjXK8gO{drQoNqR&tRjM4>^DtW`)fiRFO4LE=Z+nCBS~|B3gZsh`Y?-$g z@8@Z$D7C!L9l=SWoE;(+*YirPLWvBd$5Ztn3J3EaGM+#pW#@{3%yksGqy(2Bt5PVE zf*fICtPp77%}5j#0G8<=v=)LR>-a3dxja8cy3m$=MZ2#$8mbLvxE%NptMd+L?mG`v zF1cANFv17DqP^P5)AYHDQWHk*s~HFq6OaJ3h#BUqUOMkh)~!(ptZ2WP!_$TBV}!@>Ta#eQS_{ffgpfiRbyw1f)X4S z_iU`lNuTy86;%!sF3yh?$5zjW4F?6E9Ts-TnA zDyx5p1h$Z3IsHv7b*Q{5(bkPc{f`2Wfxg*Z#IvQ;W_q9|GqXGj<@abo)FyPtzI~i25&o zC!cJR%0!}lLf^L2eAfZg7Z69wp{J?D6UhXr%vvAn?%)7Ngct4Hrs@LZqD9qFHYAWy z4l=2LI?ER&$He2n`RiG&nsfLv?8$Cl)&d8a-~-N`I|&EPa@Y=v@>0Gl?jlt>AUY;H z`**5bpS#VGhdp4pKbf3iEF*>-eXg_$bqt5Dc%q0+)R50>zd^l7sN5R5Z)Ut+oz-8_ zJ`Z9HE9(=wRTD)T=%GZTEi9K5naPzlfE$|3GYGLRCLsnqLi8Sc6y&iskqA&Z$#7Ng z7Q@C0)6k;J$TlQ+VKZ5)-Ff_BNoIMm+~!@Cv1yAUI-U!R)LHc@+nSUzo$GlRb+8W< zYPG%NFfr;!(RlnvBbN~~EpT6Xj5*^Z&73tdIQ$LZu`vkfzdTKa5|JJtQ_rm4g$9LO zKtgYVdW=b<2WGM3I_j|Rd8gZ3j;)S#AT(aP^d>9wrtQS_+K>pZDX^?mN!Z>f^jP@1 zlJ;i79_MgOAJa`%S9EdVn>ip{d!k6c5%zizdIoB9Nr!n`*X#%6xP1?vHKc6*6+vKx zmEt|f^02)S_u_wlW_<`7uLQU%{wdH0iojOf_=}2=(krE<*!~kn%==#0Zz`?8v@4gP zPB=-O-W=OO3tD19%eX>PZj3YfrCt0sEjgTd#b$buAgBri#)wW14x7QcHf2Cneuizz z368r7`zpf`YltXY9|2V{stf8VCHgKXVGjv$m!hdDf0gi`(Q!(Pyg~FO28Vr#!BYP| zI)qG2?Ho=1Us9dTml}-ZOR?g5Vk)f+r=dbCN*N1=qNfG>UCLeA8pd3Ub-pRx1b3FA zEn`CIMf`2Mt3>>#3RkE19o}aMzi^C`+Z>8iIPHSdTdmjCdJBtNmd9o0^LrJc9|U9c zD~=FUnSyghk7jScMWT|SHkP(&DK$Z=n&lGm+FDTpGxfoIyKV)H6^nY~INQ#=OtIT! zyB*J=(#oHf=S)MNOncW->!c0r0H#=2QzobO&f@x&Y8sYi-)Ld;83zO$9@nPPhD}yt z{P`*fT@Z(?YAmF{1)C;o?G@dfd2$c+=Av*|;P@Yz1KnclB-Z-fJQ-=+T*g>0B7!g# zQH{dHt_%wj=wlmT&m59)TQ~xK)gB6f^EY$=1zcbGf~Q>p_PzDCHR6lndGmqPY2)&w z$Th^K%1v@KeY-5DpLr4zeJcHqB`HqX0A$e)AIm(Y(hNQk5uqovcuch0v=`DU5YC3y z-5i&?5@i$icVgS3@YrU<+aBw+WUaTr5Ya9$)S>!<@Q?5PsQIz560=q4wGE3Ycs*vK z8@ys>cpbG8Ff74#oVzfy)S@LK27V5-0h|;_~=j1TTZ9_1LrbBUHb?)F4fc)&F7hX1v160!vJc!aRI>vp*bYK=CB(Qbtw7 zDr2O^J%%#zHa7M5hGBh#8(2IBAk}zdhAk$`=QYe^0P6Bb+j5X)Grmi$ z6YH?*kx9hX>KCI04iaM_wzSVD+%EWS)@DR&nWsSBc2VIZ>C(jX((ZiV0=cp}rtTO&|GMvbmE4FpBF5Rd z6ZG=>X&>N3?ZN2^11pXEP4L?XUo`qrwxgQm4X~RCttXmZAhnhu4KDK=VkKq?@@Q_Z za`*xyHrsAEsR zV(7)2+|h)%EHHLD3>Qg{>G|ns_%5g5aSzA#z91R zMDKNuIt@|t?PkPsjCxUy&fu^At*yUYdBV!R_KOyVb?DO&z$GLJh9~b|3ELsysL7U6 zp24`RH+;%C(!bWHtX&*bF!l-jEXsR_|K~XL+9c+$`<11IzZ4>se?JZh1Ds60y#7sW zoh+O!Tuqd}w)1VxzL>W?;A=$xf1Os={m;|NbvBxm+JC@H^Fj$J=?t2XqL|2KWl$3+ zz$K+#_-KW(t)MEg6zBSF8XqU$IUhHj+&VwsZqd7) ztjz$#CZrccfmFdi_1$#&wl~A*RisBaBy~)w|txu1QrvR1?)2mb&m2N$C(5MS%hSX)VJnb@ZGXB5^%(<#1L@ zL^>fBd+dEe`&hxXM<0A9tviIs^BDkByJdc~mtTYr!%F7Q1XnK2$%h$Ob30*hSP$Bt zDd#w{2Z%x^Wpv8!)hm>6u01mY!xmPgwZ#Q0148)SxJc3Udt!-&}eRO^LN ze26pQB!Jhg&Z>#FD>`C`sU44><=v>O>tJdLs!HPpV#AM32^J@Za-9J(CQjKxpzXao zQfRkWP%g9P8XV21MmoHfx{DICLSc*t4qVeQL9t}&Pz0rM}YTba@XsD=XMW@FxFM{QYQJHvM(JsUSa3mcTUl9^qcVA zBveO--fqw%{#QGR1vy;x88+qMcgzmcYc#8U`CPPt6bl?uj%w_`b~9JliftnOa|ziW z|6(q&STs_*0{KNa(Z79@{`X&JY1^+;Xa69b|Dd7D&H!hVf6&hh4NZ5v0pt&DEsMpo zMr0ak4U%PP5+e(ja@sKj)2IONU+B`cVR&53WbXAm5=K>~>@0Qh7kK*=iU^KaC~-ir zYFQA7@!SSrZyYEp95i%GCj*1WgtDId*icG=rKu~O#ZtEB2^+&4+s_Tv1;2OIjh~pG zcfHczxNp>;OeocnVoL-HyKU!i!v0vWF_jJs&O1zm%4%40S7_FVNX1;R4h^c1u9V@f z`YzP6l>w>%a#*jk(Y82xQ@`@L(*zD&H>NY`iH(iyEU5R$qwTKC5jm4>BikQGHp^)u z-RQ`UCa70hJaYQeA=HtU1;fyxkcB2oY&q&->r-G9pis)t$`508$?eDDueFdW=n5hJ z08lH$dKN$y#OEE@k{#|<%GYY=_c~fHfC@pD54KSP9{Ek@T47ez$;m$}iwR}3?)hbkwS$@p2iVH0IM$lB*XYA+#}-re|UNzCE)SOYwy z=Y!fkG4&I%3J(_H#UsV#SjHulRIVcpJ`utDTY{k&6?#fzt~@Om=L(vs6cxAJxkIWI z@H7)f2h%9!jl@C!lm+X4uu;TT6o0pd7 zteFQ(ND@djf#o2kTkjcgT=dHs7ukmP0&l8{f;o3JuHGd2Op*?p7?Ct=jA*tIg{MZk z$2Lsc0e8Tdcwrjx|_Ok?9uB3Il|^2FF%X#ck}WoIvrzQXN%kT$9NI{79Wm~gZ3`8I+O`)`n30feZ( zDO-fl6IG3c^8S;Y_M-)+^CmM0tT^g0?H#>H8!oC8W%oU!~3|DJ?)~LT9*&GAQG13zOGq6gs*={cu|(V7{R$y@{-iV*9q@AD(#Ktb}J&3&k|5Djs$)9WM7!6#EaJ_ilvbfUvyh8c?-{n zfuFrC0u6}UJZ7aj@(cNG_(CKgjQQTA-UK@-MVmick zot}6F%@jhq(*}!rVFp5d6?dg|G}M*moyLriI!PQDI;E1L1eOa6>F9E6&mdLD>^0jJ z09l?1PptuV65gm=)VYiv<5?*<+MH~*G|$~9Z3XEy@B1-M(}o&*Fr9Sv6NYAP#`h{p zbwbUE3xeJ;vD}QMqECN)!yvDHRwb7c1s6IRmW!094`?Fm!l~45w)0X`Hg+6Y0-xf# zSMemBdE)Q=e^58HR{kWrL5-H0X6pDu%o{0=#!KxGp0A;6{N5kI+EoY_eTE%2q|rwm zekNeLY-R?htk!YP2|@dbd8TWG4#G)=bXlE{^ZTb^Q$}Er zz)Fp)ul24tBtQFIegdI37`K$VR3tVdi<(fIsu{#QMx=$&CK9M8oN%3Mk;>ZPd-;Q- zn|sSKSnc-S0yrw#TlA$+p{J~u=u98s>IoL@cNLOxH=+1m?;t1bR$vR=M$US&Z8DO3 z_&zhQuId1$wVNsS=X?&s(ecIi#00o{kuPs6kpYkL$jMyGW8U7mlCVaZeEL=HsIxqm zFRLxWin8B>!Dc#9Z#t0RNQiR-@5J+=;tC7|1D*~rxcwHa5iIVD@99cCFE@BukUC-S z^iJdt?dwU)kH2VY9?|zVShMbZctzFRz5Q4tiXa^>@U%jDYq}$rSyc#p2wXr}mc0qq z^lT>$y)N(Qg0dwmEwTopneoU(y)>Mj+f{iHM0o|>ZtCg-itPj4addYz??aE)Rp&hk z_SI)%XeSf=SjZq18h!Cc>Xy&EynnxdHQ){(x@g|ZA%`3LU^KzX02c5N;F#tEk1)7v z(|V9tO3>?^X|kQ*rRBf4>mWW2$-Lx})|M7z125&VHcxsCqB!<$l1F$zCrJ+nm0f3Z z%Hq^=SKpHyV2@Y*Cu2x>fXC0SscnR*($zEB{KOniJcpn@e`PMH*_Q6*0Z^8RNCEvZ z+UU9!927p9YZ&g=bnUvQUZcdisyn;-4;ACXOe-Xor9K8Qbp{ldE17+G@VQT+9ZJQ*9dZoXfU2ue|mMhrrZk2R7&~YjFW4`BTq45UwVc6JORKU)wBCTanITh0GD}s$`C5pb(9{b9 znwee6j%?-UV)_7opOioCf5@C?@w^@g& z&68+oMmV;5JW@TT63&CSDrfYL2$L)pVseDtAwPwleEM3F^-Ufn3PpfxFmx6o zQ`Wq9x#d$e`VKn5LOXNsrqhGao7~|s(u~drPrZ+;aP!C%z4NskZstCbAibD}O%8Ij zb~C(taxco~WzJLxhL1T}3ctXMbV6}_z=IZN9L0|SxLSe`$X`<)BhM`$1&&)e_}fCh z=idVL<+u6Vn{&ksP*ZLlMo$fC`dtzF_?~L?4Rril2G4%v5^7sUa^&8aMtMX&mtapl zD(dW|cisM3fqMaB`8?QbkyiUl2g>hMB5EoS&IB8TdoC~)b$nT=`%GgU`k-)+8}`)F*~I~DXMaTP%kZftx11~?iALs5J+&Rom#p%Y z>dH}-euH4u=_V3hc6^*2WMtL!9%yRTJ93p}@aV0zdY*?xchFI>m+UivV=;aMFp0P~ zwB8P)wvV6D-GL?6hJ#g7Hy7=2i^&Od#S=j!;Rc_yjO!*4aN7{vqzg2t-R|Dav%_NDk z`H_FVlSi==(~f-#65VmQ{EE92x<03lwo5p)s=ZJ^L7PlS>132Whr zR6v~t(#I+(`usYLCoO;Rt8j&b^5g_xgs*98Gp|N}b>-`HtVm)MscD)71y?(K6DRCZV26RsHPHKk)EKKZA%C99t3$t^B0-k5@?E>A-YMbFe?>ms?J?_guHHNU(;id*>xH zTrtam+Aq?n@-y@uY@A?hy?1qX^eLu_RaH4Ave?A8NapgQF=C%XI7wlcCf4<6BRo_% zBXxxc*A6-3CruF?3i8HOdbc%>N=-iiOF+9HX|ht6SCkz;A^am&qi_I&qk1B(x<=(m z>QG)nswCOLl_1{SZ@_eE#m^qb6#6DoMsB*)`17ui+XvF%(}|J4G$z2G*;E!1ERnAH z@q%=#uV6kBddqy4=g>!VTV)9*1=i{wJ}Ep!I*?)uJdA(LwE?(!?;}_u=^M2NShWC_ z*7l4aBJ=!QVU2-iehgb`$vOI8zkm{W%QO~?xOD;NgI;Iqa3#^$^U5D&McReLe&qs# zR<^@QpR4#W~Laz+QBsPt@3L#KF`Yr8}jgHe;5(cfpQ=;Zjtbt;c%y^#-m=hqOT z;KAYakW+$w0&F}>K10&SiPcD9SrDOuczj@U#W})5jGU-_htU`U6Q%wdy((%?J}y+$ z=$4jw1N nJo)qTxG{D(`3*#8tY|67hJRF;)r6F|#I`Ar6I0aafRa=kr-Z0I^}9xf^u;G5iEQCbpv3b#S#%H|HYHsQaHK$! zU#3Fpz8*^pK%RRmX<_09eIVziB0jOgPgFnI-*QcwEBtBiO#v!>{W1cLNXyw3D9M|A z*oGy(u8BkDA1c;MsXmpK^-~pl=We^RYnhZ4bz*)Q)C2G+E3tgx9PzU0T>c|1ilS!T zyE=bz`=wskDiOi!@!l?Y))#%{FM`}7r~X)i1)1*c6_2Q!_1{)fp%cS|YF+Q-CB%d< z=zYus`Vt@Mx*a7V)=mpLS$-5viaKgNB=+zN657qy0qR94!cTtX-Z%KBCg4OKw7b=t zr=`7q5Ox=lJ%!G5WIyNQC1xpqYU0{!I$hyrk!6%De$gp<_*Gc?ES(OwY8U^)Kjgc{ zSlhpXDb|;{+y9`u{EuMz54rlky2~p6xX2>MV6BZ&k`$q%q7v(xYps2wr9e8^4<;CB zc)eAT~B^rjzO6<4BDDH;il6 zFsM8jL+agQ;zazW(uiQjM%fPf2N~_p{cy29XP11_lQFpt`t#9nlk}>fv((FZt-dBa zuMIc4HmPHW04n0TTG9ug9;&OV9euL$Ib|+M7}}L~z4e%%%b|r~6OQj(S2d7XfYn#xp8;KQ55UYu#gY*De5j6Cc z#R%?rqwpy7I1(kpU7B*Pq=etXeYUn04jg%ZPjYqQNa$==yTG=6KX+=;i2Xg+kjV2T*Gc!(ef z`Q4fR*TA=M5-}z+s%YO+!K{k}S**ic&>o4_Tmv$EQTOp7F6TXPCj-UTXy?OQ=%*y62Qajk{rXbR%jMCOFMiVE3KekQa4xR}B%=iPtd8BXo~q$OX_ zSp910{Ew;m|GATsq_XiJ3w@s(jrj^NDtr(Dp!`Ve!Oq?|EJ9=vY2>IfrV{rT%(jiY zi}W@jA2iqd=?q>s;3%?@oi7~Ndo3Ge-2!zX58j(w&zVlPuXm3rcHb7O0RsM|!Ys(b zh(=*&Aywo3vuJoWZnU!u2_4bNkDTc&&bCYc%T zM~~xYxS#3KXFzQ@OXdc%9QDOxqiTd_> zT;(DX9{5dIuC4pO_xy+3{Ov)1I7j!Z)6&nHUvTRP>VU5dm#849icG)cvl0QOPkCIzG^lOp4#UcNr`VhBp(Ha%8@KPlvT*5u!v_$b#b~%sn3K{mu zaxeD%Q~{;Lw03ZAq(Pc-IVj>n*h3l2{sqioCMGatQY0kx zi`1(WWDQ=;gmLSGptEQ%UFC)th@|71<8eiRtX&Mx@#1q#nMF_BMfQdS>!!Qkx2o}= zuqRi?`UOX5P3fP%M+71Q$ctH4Av}bXED#fQ`KR4!b~60nsAv^*M7c-x`|~B}XIuq% zlqIJOf>WvlhQ@Uw$du|14)tZ?; zPNZ|xZSwp1y+d4sut8E4*l2JWR|~o0A9vD-?zC-w zDc@=wE1YKb*OMSi_Kx}&w;#h3>sHp|8^hnA3w?-WK)X?@Z2dgV7`9Cupf-B2RE4x^ zwlw+~!V9C^tyb`J;m2}ksD`w}G9`yu(^--{SQ+wt^Fu4Li~Fft!3QO`upSkAU?o;# z(1Q%GUVWbbkTK-M=T+ULkk3s6Dc9`G4CO6|=&-S&D+rbJQ$`Y-xL~ol;kc(l)VbU>{&>bV+*?ua;$bnDc29RW+Ig16)Vf6=L|fMR_P2b7>6}0 zdlB#-gj|j*C~M=F^2=K*k~=tl6YM3SXXi&K-`EvEXnWz&4D-^hQRBJI3gKKDj^6|> z*WhHSim1qAffNt60Mve9lfw^+&0bx-AM0%j>QP3%W=S@(l=(nrJ678mRQ(#+sI@d{ zdb#5fo#T;hK7xJ=M58wZf|?DHwD%!OZ3JrTGV5#{cfQwuiMvz%!CQ}CubJ7`z?@rSF<+KHNV2goc)a6hP0oHB@3LLKSH2w{um&J*z1Ka2 zLIR>lvOvh>Oxe%?3A@v<_T|}${zf_&@C~^FCo#jB(W9VLO?DX{)n(BQ0(V0`mI|9Y z#U3WwxixJkU_NTvA>5q(A@r2dnEXJp#6B=pww$XGU}~1~c``UKqQb=^*2P|4Dq*_! zhY^i61Sy%T5$Td0O6^C>h(xVvT!}Y##WeT8+s+Uuz=7)~V$>!zU;%d>H)rm*6^IrsCma%|cifwDLk_ z!^W2voQ)D;I$=v2E>iSaBw!d7aD+|LWl2iD!cBw`Q5p1~fk_xGiPi8e^mY&#viTAk zmaKL8m;JQ4bY(n6uBZt02z#noMMxTfF-RzjKre-c+@B)#J3pN-Zv7F}JtAwNk3j?OkpVCL6W1)Q$FLAj zGI!tX;g`O{%pt=0|q54Jyj##w*4e*|_;Us2Tn?!#^R(>u}|FAw1G_ z#wQsagnj9$TAC`2B_XgB$wNq~Sxgl?#0+QWWcB{G`c6~&SosbtRt}Tukw`TQ!oG1= zYyL(y<;Wh+H24>=E}Gs=Hs2%fg;&Qdvr74{E!R?Bd zIRQ?{{xkLJ_44P@y3^#(Be%(pk%$liKbUUo76wSoVfJmt9iTKL3z{uW6L&?jYg>EY zsx{kRiW@q%<$VZvbS(TKKTO4{Ad6l^IeY(F^3}=mX9|FZmQ`~RErNxlBPl3ast}W$T4V?SW=6kIGn@-^`qJv| zZXwhK4Kl1a4E}nLI`rdOi?^pd6;LZ-|8G&INHgOeC5q{_#s+SXb0r(;5ryHFsoTJD zx$VtNDh=-Tx3t!NTlk=hgAaSM)#U}e>_-Ex(|JoX*hWmBPPdTIa-2(BIOUJ|Iddy| zwY*J%z%W$}*;uSoB!BIJB6N6UhQUIQE_yz_qzI>J^KBi}BY>=s6i!&Tc@qiz!=i?7 zxiX$U`wY+pL|g$eMs`>($`tgd_(wYg79#sL4Fo+aAXig?OQz2#X0Qak(8U8^&8==C z#-0^IygzQfJG4SWwS5vko2aaOJn*kM+f1-)aG{T43VJAgxdP(fJ4&U{XR90*#a)G8+clOwdF?hJ?D) zmxu>0>M|g_QRHe_7G|q6o`C>9x4xd$Gl7lAuR~+FtNid=%DRsnf}YI*yOToWO%xnP zY*1G5yDnTGv{{xg5FhWU65q3-|-(+-rJ2WCeSJn(7Az>ej4Jp9+l-GyZ_| zJ8}>iA4g|}q1AhEEv#uWR&$g&Uyht?fVU(qk(j?^D`))s>oG08pow!f>P1u71P%oL2)UC4GeS87&G?{)NE;D=my1Q9{~;y zJULE=bG6jXE28Y11YmoZoo945`MM*`v%5b=_02*0cwzDve#3(4M}NPt`)?SCa|7*q z-94ks(R6WH-l9fE4m4}10WSu&O`|;ZCIT%vL$_pbABY!}s33@~gIvZ0H4co|=_-T$ zF#lC7r`89_+RL9wYN=E3YwR?2{$^ki(KKd>smX(Wh*^VmQh|Ob5$n_%N{!{9xP~LJO0^=V?BK8AbCEFBhDd$^yih$>U z(o{RReCU{#zHSEavFNdc8Yt<%N9pd1flD{ZVSWQu*ea1t#$J5f6*6;tCx=&;EIN^S}*3s%=M#)`~=nz!&Q0&{EP|9nzWyS<#!QxP;!E8&3D}?QKh^ zqGum|+;xu9QE=F#fe2ws5+y1Igr&l`fLyLKry=1}(W+2W`waeOR`ZXlW1B{|;4sE3 zn^ZVlR11hiV~p<~TaSen8I~ay#7Ql=-_|U@$8yjZsZ=Vi+^`JV2+kn+oiSUi%omO_+7}saXnJ9 z5ETilbag(g#jZPopCgJu+n@(i7g}3EK2@N zd64$77H5a`i%b%a^iRjMaprwzWz(`=7E6QY)o)gek7H)yZ-BLw^6FAoHwTj9nJtWc ztKaytMlWGLg29W{?gr|rx&snb@XyvR_}x3fmC>d=-nQp5ab3*whTw}DfUcKlMDDx` z-%?ek^*|Kqooy#>2lfklZ|jN4X$&n6f)RNNPl(+0S>t(8xSeOGj~X0CGRrWmm(WXT z))DDW_t&y$D#2`9<-+JT0x1==26*gpWPV~IF=rePVF%e-I&y$@5eo~A+>yZ&z6&7> z*INESfBHGNegTWga&d@;n;FSCGyW?}e_Qw#GTLHo*fWxuuG@I~5VA!A1pOdRTiPA~ z^AGe(yo=9bwLJD}@oDf$d+34~=(vIuPtOKiP}obDc|?@hY}J*@V|UynBeAkYa?S{@ z_f$U=K+>deTAi&=a*xv>Ruyw$UsTWY=Yn=xjf;s)6NQu>_niQ_idmzIwuL`Scf)f= zyzK?D5a5)^D@H&qN%F6Zd0JeXX*Knbe~VLe^gi|?JK67&mB4jrapV-$`hCQT;C{%T z*pjxB+Y|~LD9bmMN%Iq}S$F$x1yWU7@GcR91V8h;!O2I5MN_rq*gRx(k8T!1WSDTp zr9eJO4$~H94aG^6k5p8k=kFJ>4lnY0q_Bsa$@vTRW6uY?slH|Qt)Yu6Yun&pfJ zBi!h;6x?FDs&79#PT*HSCEUsKws#s%TFy*=2PAfb`>gEPBn+D-WdfXA?MkB=<8kb_ z1+4D11mdHG0EcAyg4dneLtfJ8)RyHQl@6hWJNe(d_EjyCHf7%Xsd)S4A-4COz{G@% z5xQ!P>AS@H@;4Ws)N91)3A6PleMe2<& z!(zv#%Uc?N`(Xmm)OJPYt)BM`nRjoWA&P0Yxl@c9Y02zlPH1J5l$nhPrMwu=atkz4 z)a-1+OEL;d@ctx=s<<+3Sv1VYy0RYmiji|#hy$66#`5;u~BkH4^$EGZ-Y4xyZ=%3KuaeLYKAUr$xMtIh_5mga> zPz<#G0mQ7IxEw-yO}BueN}RaFlg$RwCDB)vLF$wDu%qZyLYsPKdcbHD23$qn9i#JFqIo#OK?u7db2-$GatzO!On87%}Br};~#}n zziVB;qf_4(K$u>Qyz$ln_kBGS!CD-t4Y}9oxL@7@Sx*?NOAzdeINUD>Hl#*V%pfA; zSA`==YatS*G*crJ3`3ll4)vKss&)UtY#7ZxiVoG%9(4<%`WWcjX2jV(^g7Yhj+h5J z$5=?S=tuCyEt74^6jo@6y|@~N>&cVfFNtaRl=)Gm!vR;Bc$3-;ySCI$%kdmjQ|si` z{$q_YCe6vjy6re9jGN|`43D``)1PODtz0)vhV4XV36nVpOnMx2uM%qZ<3TtcI%>BQ zf0(J`{JqPPJxw>k#&nIvoZ5e9Sno)B2r+E0G} z@&M|zf4E0Q$O*NBR2I;?i7N} z@2^Su#`%qeX}m3cbSojiLk#84kvW1fICNPS`OyT0SpUoA0(s^2m~J<^eKE!dhJx_N zG_T}0&(<*an>oF=@?6?55g&IxSgY3?7|@pmDRE6gJyJNPH6un~%0hZ@?h=hI6O$b^ z)29#<4$E)cE-5IFbRpk9JVrw$$966UDyw;Iym4OY4Fc!&s1ZH4BJ1-$9<)Zt1c)N- zU^&9hsk6z?3%<9kGKHW|6~k;&cghtWz`oz`_YjVuvy;B;T67=L2c6=8`7WyTBv*QH zNv*bo1#KOk{O&)@&pkd*?v+kcJ8tM>AGx$~WMhH{L40_N=bkrVg+^p!H)IqXCQf2_ z0fPig=8CEo>p4vE(nc^DKbZ|9_Xo}$i4zJ`jVh95; z5%aNP3@``=EJ=Vt9U`y+$YtX;%OPzgZ_3+;+mh{p#W&y4-%%Bf`LhOy-*kB0qnB^m z_nBTz_b?-`F$*ymByshU>D)za2g`0j^ioo;A#QeL@x3@|+_!=YXA5f6Xg(Ack&WOg zJ<2i|Fd6OmyH!@YSMVxb;=M)ZDhBt)4`5T*>cUXWPG#%@$&*>K&u3#|`fm2mj*FKVf?du{xZ}WKWETTFhq6_fO$PS5(ItF=3~pFp~*j z!ys1<4EL1)#{`mz@gW|t-FpPkd%pK)n_Rb)F;z7cQ6dym_>YI3&e!=!m006oS3Mjq{q ze%hNzW=G0jpfl2K(x`CDuZCsJV*hm9T~%5n7R_g}VFpk`G((D^MWVMAmRp--T{`P; zwMgD<;e`fm`g3|fPns|6qnd{|FCHY*YAguXH(?%sx%4+Gu|Y)_8mk4EljxmP+MP`* z`SUbI{TCIN2OV+$y#g->Jqv#$wL;}4xJmah#$0`v^ughM_XjTA$B}ux)JZuY5-GW4 zKy440I+w=ZtE-_i+0xImq}vyzD68?8;94-5L~_O6Ty>X3itdA-x?6P(c4jkr+f!H( zUDeqiG>3bn^Sf8(`_YwqPeJ9&-@OCQZm4X{FfRMeBtN4E9Ca@;GVpU*L>lVb;@=PH zTQvTr?^jKyCKh&ZVOI*<y%T*Aw(XCPrFC=39*y$A`FSzxBiQ#W+uW10d8&gYp4{teh;^p@anft+z$5!Hv&@h0X-@xJG>hbTCxjDwMiWK@1b%8wYL6BrV zT41m}tX8g-`P@vj4T!Mlk8F0S!MA`^J=SCy9-jdwDe^hVDa`WwyI^H@ryt=F5y6>b zT8&iI6&j8edAfX^ycgWbnMZQ26Q~`LmdEScKC8|~$Jgyw(>18NAQ$9AwCRmri!96L zp^)b0P2CR-9S%cG$#rU}MXnx21T#031o>2VrDs@sa-FpjfvgLPW>Q&LHUoNOtmkt# zoDZ=5OGp{^vO~=p29^`aXd8K?(+f-bW`N$U;-o;%f?RcR!k02Nod2h^^8ly%Z67#E zC3|IOuj~^YBO=Fklo@3mvd6I{Z*&FZ>iq* zxh|JuJoo2$p8MJ3zO@dQ;%1#~Mrm48 zB0053{1bDi_a@jo<4!@!`w4}B(&Qb`~IeSBh zu+_yIYl2Wgk+?x4pCmAM>x_SqBPUj#c`C`k>_fp@qPlAAwD$!zOxRkL7;=|nu(#ut zyF^;&hm-D_;ji{d6rOloACu5*NkF4IC3@rifMG(|^Skv$H&^YnYL*rpw=UCi;JOuz zN*NX(7wZXS4tF@6PIWAs%*j!$RoL*3sh)}iry%thDvN5AUM888q_(>|Tzt|Yea3AyMYBgm$H_`F^v2%)bux)3s znFIEBDK;-JS5SH|;1?afJb<*=c5puu=w%tv#ihn*R!^Hd$KWAp4$#`joJ*)$kNtZ z2Al6h>Z>(u?3tmzA4^d+jLKx{97!Pb4;CX&u;M||**7zXI7hO6nrdMx*Xa=|-`#1^ zBQ?Ha&7cd7hN=%y4yUp?zl8~Lo;%mQrDe8!ce-W_K94FFMN*g(w8q-_K5S+c0{o29X&PzpV;UJE^!xnFc%b@>kvW4m#xiOj-L*DadC&2N#0Us z;<-(m1WB7$=j6hjcPC6JB)D3T2#IC`ibu#yi!uK7W2!j|Z>~RaJ*&XXy#ytIk2DIp z5?Qd^s90_?ILjU#>ZWk5HXts}grg_!Gmgm!d?eLGR7xEP zvTCrslV~94ym5_i<5oqy(@@?wN}lIdtiY8=?|Ng!XeYnly`@9wCGx2S$3x|0x8T2h zz7A85Vb2>s44rKpI_4Y7_Pnd2^mYj2%^jM|Du>u4`^Psda^JIP%*DK6bo`Vf&f{!% zDTYCwF5Nhi=)QhU2$@eQv&ZzxsX+Hl+gP6kW|e!n9IU2>Vh~cioI{>4WvR}t*4Hpz z%5z?HjLGoka}Q3AbX9AkY|Yjf^M(>@tBAI9JO5pDCQu0R3Nns>)LC#vB2p96C*?K? zvX$un$sBDx$1=+NNj*@Oa@u*b@O*XBr_sg@8sCUq-|LK!MUmC)epklrv}5O_^<{NP zX16|c$9Wtbks3y7geI^tF5oRZJu;v zwkW8j+8Ccxo9stEDOT_Go&j%$KCgVO7pm+^%PKEPBZqbMw%s@732XS{cX+wCSjH1s z5)bc=g**<^NNsroY` z?}fHHlgu^B?2r{^^gQ&j zbF~T((>|Yg&C5WKL8DCnl1}Z3!YHFW2S1|;Xr0`Uz-;=FxEwYc4QpeAtnm7^f~uzX zl;xA!?>MLR?tL80Iudm;mi{!ewL91KhG7Hsa-XepKi<2mc6%zf0GwtbfJ1Zf-<@Xu z#|XWDzv|04t)&9Id!UxAAkN{t5qC%%8-WV3i;3duS19%m2||Y{!3pR1=g|zQYAMqc zff)_2nj-O4wfxy;UNM?|Uieo!^J$A*uDe>@V(NKH;KS;Y_dtE8${p>RdcrW;=2*fj4~d?OG0l-(g?ik}vz} z)5-wDppVts>K-=|@{=!53?=8)Jw#RGpS_FWpbwtn}{v!JEJ$q-sr7F6&OPBuI# zuVNFMPte79XgEu!P&qRq8u4J>r%$l-IQ00Lin90(_KtC)aR_de zxN=pY2<1b29_^AG2WJIGmmX4rv3$!`l15{e(H!1^+x9voZ6;882YAE12q7+lgy+>) zj|s0CyzI9=Mo!R}&LXB`&DYpZ7c?0r(&KNV+~TULd0y^e;G{KVR4nL0KvU9mr8&$^ zxrM-9P8zE`J?aZ(iB~Rz<{vvnk2HaZU#K$aVFfYnbAXVUOLU#As5JvS%+26 zi$sNuPY}dLGUS$0g&;oBqhzv2dY`l3@6Na403M!Sh${B|7(y|_cONa;6BrtUe@ZzV z7SThtHT8k?Rwc)(Z}@BP#H@JJHz&GR&M=E@P9KJ89yQKmRh&I~%vbL1L-K3E>7>CH z)Y!=jXVb1iPrAoAZZ3}3wU*5~nrV!ZjL5zqJ<@NwjHCZC>68Cc<{&E_#S;E*jOdjtg?uKN|l`P8sjz&Qf7a^z9 z;{3-8T+H4y99_zc;JYIvs!sk$G}` z??mt*Mm9Z@glCZb!X?!xXD-21sFDPEpZOK{sbQseQ$%6~b;n+*z0hRoR}0Pe>B|#t z$XrVcXv8M|q*Z8MY&r9J0A=d^1bHpjrUXu)qEj~$%%=gZp`^~%O*lzxUquG^p6;n; z^(3HL+hx4gRP?4N*b2p9!^|2~rcw3!9nQj$vmZusbXYz_x^AVc`3qBFm(jS9ueU5h z^AnNnbswfQ2Jq=W=T+p-V|nQco@bOAH$pLQZ+BKH8E$iM>IDz z3|wc?QP`yI=X5YTlp8h}%p6{Deq?S0QD$Ug>ih1SdPZg237Rl{S~=Ha4~-ckMoIWMn+X@@`V6 z#HHZj>MQbt$Qqp*9T(cjc^lxZ7UO(>PwzF-qEr(wo`vaulxdall|KP`7p4gd`23&Jy=#sAes*0diLB(U$Nx46VQvP)8idSs8^zaV91xw*O-JMH=)FoJshRob|_)O)ojtfP))WHCr(;*2;VMQ75^ zfN@a^f#o<|*9X;3IcGodLUz-3i~FAu+zI4c5h+nW^h_!^)b*B_xw-l4O$TB(ixaqW ziMoa%i=BeS<-F45kMO;Tw|FWa`G2c!SuOA3CbowPhF6csf1|&qqugUrj;UgGHm| z;j^yoH?MZhR;AYOW_XW2Lg2j%%ejL)B@*bUMD`g<#Z${1+fa57r7X82 zcqY-cfPnK%Y^3@szRner zt)bBToYCph6Jv*W+&t?&9FG4(Iu2w46 z4B#AcFy_^J@f*6<{>CN}Sj969*DYV*e7<61U>GoN{tz!Do90+jApFueVY_IW(MQF; zl?4yA_(MvMwN&pWKVyg{3uU_+y6RMdot2vu%mC?st=N0pf-~JZXE?3JFf)j<{1xsU z`2ephz)#HzsWEP!inHm2hI(V(~@W zY7gGU-lO52cHD&SY)>QHgy$=>^X%u0TQZfCizro!*weMyvZC=;MWOawdAx~`3C*W` z%^#^$uRP;gyqEE0<(i8xcQY$oc+6mY#z{-XFxsO1(cN8Y)>p;^q9|5bk`Z*p|c!?(rErw#y;yT(%@c7trQBv6cj)$3>pI z>tz+;IB?D=aQV=s(n)o63*yn8dX1m7#Z4G{%fF@K2o5n3jxR~mU?nzMi#;}8e#(>{ zy{Z4!AI)jZ8TY;nq1aq}tq;~=zzoTv)er06oeX3;9{uP{LWR*2%9cmE%S^`~!BW>X zn3PZFTf3g*dG68~^1*q@#^Ge(_8puPEFLD8OS|0b2a{5e=N4S%;~f3tC>F6UxK#v9 z)N-#Mv8=ePCh1KsUKD1A8jF_%$MPf|_yCN9oy%*@um6D{w*2|4GY zb}gafrSC+f=b*W{)!a!fqwZ9)K>fk=i4qf!4M?0v{CMNTo2A9}mQzV=%3UT&i{3{W z>ulG#M!K7%jPf6Mjff9BMslgQq3zIogY);Cv3v;&b#;^=sh#(Bn%W)H*bHNaLwdpq z85%fUTUJJNjYO_426T2TBj0D{6t zw&S_HZ|C?pI_2q(9Fas&@uJs6nVX;P*5K#6p|#)_(8PM-{L(;2wl`ma{ZAd5gA)?y z>0GSLoK<*FwW+G8@-M3vcffg7I(qm7lzF)n`Q9iCvp*mn7=|CjlpG{x z&r0n}XLWZ!>=lynUr7D`6n`7a_ZgT< zm!i;&?Fb0Q2QmqmCHfZ7ex=_tU~(7b)L?RIvPyEAU=gLIZ-VTAA~WR00yKyTXg^(G zqWLZJs!FnQYMOH3*fN&Tn(IKMLf{Ki?pRo8zZJ6YVyj)y0^)-sR}2-)%mI(Aw2AgT zbbp1T{qB(OSNJd0cVBH^tI>HR(q+#*lmi@LWe*rZz&M2h1L_=50uZ1e*n#E*`6?aw zj`ka&JpceRGe@}Ey1)Q~O}0qHRg4K_u>4e1arvJ7Q9!=t5AuzG`n=a-f0}{+lnCE#zu$`oVn44eS&T?N*wz~t~E&oQDBrB_MSg z_yVrQehWbD0xHX|v-hpselAu;O7s;P*!uAT`dr~}Lie=tknaGoiU?;*8Cwgala-65 zosOB4mATbdXJFujzgA4?UkCKE093A1KM?W&Pw>A?IACqg1z~IZYkdP70EeCfjii(n z3k%ax?4|rY(87N&_vhsyVK1zp@uils|B%`(V4e3%sj5f|i(eIhiSg-fHK1Pb0-mS^ zeh?WA7#{hhNci5e;?n*iVy|)iJiR>|8{TN3!=VBC2dN)~^ISSW_(g<^rHr$)nVrdA z39BMa5wl5q+5F@)4b%5-> zA^-P20l_e^S2PTa&HE2wf3jf)#)2ITVXzndeuMpPo8}kphQKhegB%QO+yBpDpgkcl z1nlPp14#+^bIA7__h16pMFECzKJ3p4`;Rf$gnr%{!5#oG42AH&X8hV8061%4W91ku z`OW_hyI+uBOqYXkVC&BqoKWmv;|{O|4d#Nay<)gkxBr^^N48(VDF7Sj#H1i3>9138 zkhxAU7;M)I18&d!Yw!V9zQA0tp(G4<8U5GX{YoYCQ?p56FxcD-2FwO5fqyx@__=$L zeK6Sg3>XQv)qz1?zW-k$_j`-)tf+yRU_%fXrenc>$^70d1Q-W?T#vy;6#Y-Q-<2)+ z5iTl6MA7j9m&oBhRXTKr*$3gec z3E;zX457RGZwUvD$l&8e42Qb^cbq>zYy@ive8`2N9vk=#6+AQlZZ7qk=?(ap1q0n0 z{B9Fte-{Gi-Tvax1)M+d1}Fyg@9X~sh1m|hsDcZuYOnxriBPN;z)q3<=-yBN2iM6V A?*IS* literal 0 HcmV?d00001 diff --git a/examples/epaper_display/.mvn/wrapper/maven-wrapper.properties b/examples/epaper_display/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..6d3a5665 --- /dev/null +++ b/examples/epaper_display/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/epaper_display/mvnw b/examples/epaper_display/mvnw new file mode 100755 index 00000000..8d937f4c --- /dev/null +++ b/examples/epaper_display/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/examples/epaper_display/mvnw.cmd b/examples/epaper_display/mvnw.cmd new file mode 100644 index 00000000..c4586b56 --- /dev/null +++ b/examples/epaper_display/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/examples/monitor/.mvn/wrapper/maven-wrapper.jar b/examples/monitor/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 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 A?*IS* literal 0 HcmV?d00001 diff --git a/examples/monitor/.mvn/wrapper/maven-wrapper.properties b/examples/monitor/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..6d3a5665 --- /dev/null +++ b/examples/monitor/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/monitor/mvnw b/examples/monitor/mvnw new file mode 100755 index 00000000..8d937f4c --- /dev/null +++ b/examples/monitor/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/examples/monitor/mvnw.cmd b/examples/monitor/mvnw.cmd new file mode 100644 index 00000000..c4586b56 --- /dev/null +++ b/examples/monitor/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/examples/stm_dfu/.mvn/wrapper/maven-wrapper.jar b/examples/stm_dfu/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 zcmb5V1CS=sk~Z9!wr$(CZEL#U=Co~N+O}=mwr$(Cds^S@-Tij=#=rmlVk@E|Dyp8$ z$UKz?`Q$l@GN3=8fq)=^fVx`E)Pern1@-q?PE1vZPD);!LGdpP^)C$aAFx&{CzjH` zpQV9;fd0PyFPNN=yp*_@iYmRFcvOrKbU!1a*o)t$0ex(~3z5?bw11HQYW_uDngyer za60w&wz^`W&Z!0XSH^cLNR&k>%)Vr|$}(wfBzmSbuK^)dy#xr@_NZVszJASn12dw; z-KbI5yz=2awY0>OUF)&crfPu&tVl|!>g*#ur@K=$@8N05<_Mldg}X`N6O<~3|Dpk3 zRWb!e7z<{Mr96 z^C{%ROigEIapRGbFA5g4XoQAe_Y1ii3Ci!KV`?$ zZ2Hy1VP#hVp>OOqe~m|lo@^276Ik<~*6eRSOe;$wn_0@St#cJy}qI#RP= zHVMXyFYYX%T_k3MNbtOX{<*_6Htq*o|7~MkS|A|A|8AqKl!%zTirAJGz;R<3&F7_N z)uC9$9K1M-)g0#}tnM(lO2k~W&4xT7gshgZ1-y2Yo-q9Li7%zguh7W#kGfnjo7Cl6 z!^wTtP392HU0aVB!$cPHjdK}yi7xNMp+KVZy3_u}+lBCloJ&C?#NE@y$_{Uv83*iV zhDOcv`=|CiyQ5)C4fghUmxmwBP0fvuR>aV`bZ3{Q4&6-(M@5sHt0M(}WetqItGB1C zCU-)_n-VD;(6T1%0(@6%U`UgUwgJCCdXvI#f%79Elbg4^yucgfW1^ zNF!|C39SaXsqU9kIimX0vZ`U29)>O|Kfs*hXBXC;Cs9_Zos3%8lu)JGm~c19+j8Va z)~kFfHouwMbfRHJ``%9mLj_bCx!<)O9XNq&uH(>(Q0V7-gom7$kxSpjpPiYGG{IT8 zKdjoDkkMTL9-|vXDuUL=B-K)nVaSFd5TsX0v1C$ETE1Ajnhe9ept?d;xVCWMc$MbR zL{-oP*vjp_3%f0b8h!Qija6rzq~E!#7X~8^ZUb#@rnF~sG0hx^Ok?G9dwmit494OT z_WQzm_sR_#%|I`jx5(6aJYTLv;3U#e@*^jms9#~U`eHOZZEB~yn=4UA(=_U#pYn5e zeeaDmq-$-)&)5Y}h1zDbftv>|?GjQ=)qUw*^CkcAG#o%I8i186AbS@;qrezPCQYWHe=q-5zF>xO*Kk|VTZD;t={XqrKfR|{itr~k71VS?cBc=9zgeFbpeQf*Wad-tAW7(o ze6RbNeu31Uebi}b0>|=7ZjH*J+zSj8fy|+T)+X{N8Vv^d+USG3arWZ?pz)WD)VW}P z0!D>}01W#e@VWTL8w1m|h`D(EnHc*C5#1WK4G|C5ViXO$YzKfJkda# z2c2*qXI-StLW*7_c-%Dws+D#Kkv^gL!_=GMn?Y^0J7*3le!!fTzSux%=1T$O8oy8j z%)PQ9!O+>+y+Dw*r`*}y4SpUa21pWJ$gEDXCZg8L+B!pYWd8X;jRBQkN_b=#tb6Nx zVodM4k?gF&R&P=s`B3d@M5Qvr;1;i_w1AI=*rH(G1kVRMC`_nohm~Ie5^YWYqZMV2<`J* z`i)p799U_mcUjKYn!^T&hu7`Lw$PkddV&W(ni)y|9f}rGr|i-7nnfH6nyB$Q{(*Nv zZz@~rzWM#V@sjT3ewv9c`pP@xM6D!StnV@qCdO${loe(4Gy00NDF5&@Ku;h2P+Vh7 z(X6De$cX5@V}DHXG?K^6mV>XiT768Ee^ye&Cs=2yefVcFn|G zBz$~J(ld&1j@%`sBK^^0Gs$I$q9{R}!HhVu|B@Bhb29PF(%U6#P|T|{ughrfjB@s- zZ)nWbT=6f6aVyk86h(0{NqFg#_d-&q^A@E2l0Iu0(C1@^s6Y-G0r32qll>aW3cHP# zyH`KWu&2?XrIGVB6LOgb+$1zrsW>c2!a(2Y!TnGSAg(|akb#ROpk$~$h}jiY&nWEz zmMxk4&H$8yk(6GKOLQCx$Ji-5H%$Oo4l7~@gbHzNj;iC%_g-+`hCf=YA>Z&F)I1sI z%?Mm27>#i5b5x*U%#QE0wgsN|L73Qf%Mq)QW@O+)a;#mQN?b8e#X%wHbZyA_F+`P%-1SZVnTPPMermk1Rpm#(;z^tMJqwt zDMHw=^c9%?#BcjyPGZFlGOC12RN(i`QAez>VM4#BK&Tm~MZ_!#U8PR->|l+38rIqk zap{3_ei_txm=KL<4p_ukI`9GAEZ+--)Z%)I+9LYO!c|rF=Da5DE@8%g-Zb*O-z8Tv zzbvTzeUcYFgy{b)8Q6+BPl*C}p~DiX%RHMlZf;NmCH;xy=D6Ii;tGU~ zM?k;9X_E?)-wP|VRChb4LrAL*?XD6R2L(MxRFolr6GJ$C>Ihr*nv#lBU>Yklt`-bQ zr;5c(o}R!m4PRz=CnYcQv}m?O=CA(PWBW0?)UY)5d4Kf;8-HU@=xMnA#uw{g`hK{U zB-EQG%T-7FMuUQ;r2xgBi1w69b-Jk8Kujr>`C#&kw-kx_R_GLRC}oum#c{je^h&x9 zoEe)8uUX|SahpME4SEog-5X^wQE0^I!YEHlwawJ|l^^0kD)z{o4^I$Eha$5tzD*A8 zR<*lss4U5N*JCYl;sxBaQkB3M8VT|gXibxFR-NH4Hsmw|{={*Xk)%!$IeqpW&($DQ zuf$~fL+;QIaK?EUfKSX;Gpbm8{<=v#$SrH~P-it--v1kL>3SbJS@>hAE2x_k1-iK# zRN~My-v@dGN3E#c!V1(nOH>vJ{rcOVCx$5s7B?7EKe%B`bbx(8}km#t2a z1A~COG(S4C7~h~k+3;NkxdA4gbB7bRVbm%$DXK0TSBI=Ph6f+PA@$t){_NrRLb`jp zn1u=O0C8%&`rdQgO3kEi#QqiBQcBcbG3wqPrJ8+0r<`L0Co-n8y-NbWbx;}DTq@FD z1b)B$b>Nwx^2;+oIcgW(4I`5DeLE$mWYYc7#tishbd;Y!oQLxI>?6_zq7Ej)92xAZ z!D0mfl|v4EC<3(06V8m+BS)Vx90b=xBSTwTznptIbt5u5KD54$vwl|kp#RpZuJ*k) z>jw52JS&x)9&g3RDXGV zElux37>A=`#5(UuRx&d4qxrV<38_w?#plbw03l9>Nz$Y zZS;fNq6>cGvoASa2y(D&qR9_{@tVrnvduek+riBR#VCG|4Ne^w@mf2Y;-k90%V zpA6dVw|naH;pM~VAwLcQZ|pyTEr;_S2GpkB?7)+?cW{0yE$G43`viTn+^}IPNlDo3 zmE`*)*tFe^=p+a{a5xR;H0r=&!u9y)kYUv@;NUKZ)`u-KFTv0S&FTEQc;D3d|KEKSxirI9TtAWe#hvOXV z>807~TWI~^rL?)WMmi!T!j-vjsw@f11?#jNTu^cmjp!+A1f__Dw!7oqF>&r$V7gc< z?6D92h~Y?faUD+I8V!w~8Z%ws5S{20(AkaTZc>=z`ZK=>ik1td7Op#vAnD;8S zh<>2tmEZiSm-nEjuaWVE)aUXp$BumSS;qw#Xy7-yeq)(<{2G#ap8z)+lTi( ziMb-iig6!==yk zb6{;1hs`#qO5OJQlcJ|62g!?fbI^6v-(`tAQ%Drjcm!`-$%Q#@yw3pf`mXjN>=BSH z(Nftnf50zUUTK;htPt0ONKJq1_d0!a^g>DeNCNpoyZhsnch+s|jXg1!NnEv%li2yw zL}Y=P3u`S%Fj)lhWv0vF4}R;rh4&}2YB8B!|7^}a{#Oac|%oFdMToRrWxEIEN<0CG@_j#R4%R4i0$*6xzzr}^`rI!#y9Xkr{+Rt9G$*@ zQ}XJ+_dl^9@(QYdlXLIMI_Q2uSl>N9g*YXMjddFvVouadTFwyNOT0uG$p!rGF5*`1 z&xsKPj&;t10m&pdPv+LpZd$pyI_v1IJnMD%kWn{vY=O3k1sJRYwPoDV1S4OfVz4FB z$^ygjgHCW=ySKSsoSA&wSlq83JB+O-)s>>e@a{_FjB{@=AlrX7wq>JE=n@}@fba(;n4EG| zge1i)?NE@M@DC5eEv4; z#R~0aNssmFHANL@-eDq2_jFn=MXE9y>1FZH4&v<}vEdB6Kz^l)X%%X@E#4)ahB(KY zx8RH+1*6b|o1$_lRqi^)qoLs;eV5zkKSN;HDwJIx#ceKS!A$ZJ-BpJSc*zl+D~EM2 zm@Kpq2M*kX`;gES_Dd1Y#UH`i!#1HdehqP^{DA-AW^dV(UPu|O@Hvr>?X3^~=1iaRa~AVXbj z-yGL<(5}*)su2Tj#oIt+c6Gh}$0|sUYGGDzNMX+$Oi$e&UJt3&kwu)HX+XP{es(S3 z%9C9y({_fu>^BKjI7k;mZ4DKrdqxw`IM#8{Sh?X(6WE4S6-9M}U0&e32fV$2w{`19 zd=9JfCaYm@J$;nSG3(|byYDqh>c%`JW)W*Y0&K~g6)W?AvVP&DsF_6!fG3i%j^Q>R zR_j5@NguaZB{&XjXF+~6m|utO*pxq$8?0GjW0J-e6Lnf0c@}hvom8KOnirhjOM7!n zP#Iv^0_BqJI?hR5+Dl}p!7X}^NvFOCGvh9y*hgik<&X)3UcEBCdUr$Dt8?0f&LSur ze*n!(V(7umZ%UCS>Hf(g=}39OcvGbf2+D;OZ089m_nUbdCE0PXJfnyrIlLXGh2D!m zK=C#{JmoHY1ws47L0zeWkxxV=A%V8a&E^w%;fBp`PN_ndicD@oN?p?Bu~20>;h;W` ztV=hI*Ts$6JXOwOY?sOk_1xjzNYA#40dD}|js#3V{SLhPEkn5>Ma+cGQi*#`g-*g56Q&@!dg)|1YpLai3Bu8a;l2fnD6&)MZ~hS%&J}k z2p-wG=S|5YGy*Rcnm<9VIVq%~`Q{g(Vq4V)CP257v06=M2W|8AgZO0CC_}HVQ>`VU zy;2LDlG1iwIeMj?l40_`21Qsm?d=1~6f4@_&`lp~pIeXnR)wF0z7FH&wu~L~mfmMr zY4_w6tc{ZP&sa&Ui@UxZ*!UovRT})(p!GtQh~+AMZ6wcqMXM*4r@EaUdt>;Qs2Nt8 zDCJi#^Rwx|T|j_kZi6K!X>Ir%%UxaH>m6I9Yp;Sr;DKJ@{)dz4hpG>jX?>iiXzVQ0 zR$IzL8q11KPvIWIT{hU`TrFyI0YQh`#>J4XE*3;v^07C004~FC7TlRVVC}<}LC4h_ zZjZ)2*#)JyXPHcwte!}{y%i_!{^KwF9qzIRst@oUu~4m;1J_qR;Pz1KSI{rXY5_I_ z%gWC*%bNsb;v?>+TbM$qT`_U8{-g@egY=7+SN#(?RE<2nfrWrOn2OXK!ek7v`aDrH zxCoFHyA&@^@m+#Y(*cohQ4B76me;)(t}{#7?E$_u#1fv)vUE5K;jmlgYI0$Mo!*EA zf?dx$4L(?nyFbv|AF1kB!$P_q)wk1*@L0>mSC(A8f4Rgmv1HG;QDWFj<(1oz)JHr+cP|EPET zSD~QW&W(W?1PF-iZ()b|UrnB(#wG^NR!*X}t~OS-21dpXq)h)YcdA(1A`2nzVFax9rx~WuN=SVt`OIR=eE@$^9&Gx_HCfN= zI(V`)Jn+tJPF~mS?ED7#InwS&6OfH;qDzI_8@t>In6nl zo}q{Ds*cTG*w3CH{Mw9*Zs|iDH^KqmhlLp_+wfwIS24G z{c@fdgqy^Y)RNpI7va^nYr9;18t|j=AYDMpj)j1oNE;8+QQ)ap8O??lv%jbrb*a;} z?OvnGXbtE9zt;TOyWc|$9BeSGQbfNZR`o_C!kMr|mzFvN+5;g2TgFo8DzgS2kkuw@ z=`Gq?xbAPzyf3MQ^ZXp>Gx4GwPD))qv<1EreWT!S@H-IpO{TPP1se8Yv8f@Xw>B}Y z@#;egDL_+0WDA)AuP5@5Dyefuu&0g;P>ro9Qr>@2-VDrb(-whYxmWgkRGE(KC2LwS z;ya>ASBlDMtcZCCD8h+Awq1%A|Hbx)rpn`REck#(J^SbjiHXe-jBp!?>~DC7Wb?mC z_AN+^nOt;3tPnaRZBEpB6s|hCcFouWlA{3QJHP!EPBq1``CIsgMCYD#80(bsKpvwO)0#)1{ zos6v&9c=%W0G-T@9sfSLxeGZvnHk$SnHw57+5X4!u1dvH0YwOvuZ7M^2YOKra0dqR zD`K@MTs(k@h>VeI5UYI%n7#3L_WXVnpu$Vr-g}gEE>Y8ZQQsj_wbl&t6nj{;ga4q8SN#Z6cBZepMoyv7MF-tnnZp*(8jq848yZ zsG_fP$Y-rtCAPPI7QC^nzQjlk;p3tk88!1dJuEFZ!BoB;c!T>L>xSD<#+4X%*;_IB z0bZ%-SLOi5DV7uo{z}YLKHsOHfFIYlu8h(?gRs9@bbzk&dkvw*CWnV;GTAKOZfbY9 z(nKOTQ?fRRs(pr@KsUDq@*P`YUk4j=m?FIoIr)pHUCSE84|Qcf6GucZBRt;6oq_8Z zP^R{LRMo?8>5oaye)Jgg9?H}q?%m@2bBI!XOOP1B0s$%htwA&XuR`=chDc2)ebgna zFWvevD|V882V)@vt|>eeB+@<-L0^6NN%B5BREi8K=GwHVh6X>kCN+R3l{%oJw5g>F zrj$rp$9 zhepggNYDlBLM;Q*CB&%w zW+aY{Mj{=;Rc0dkUw~k)SwgT$RVEn+1QV;%<*FZg!1OcfOcLiF@~k$`IG|E8J0?R2 zk?iDGLR*b|9#WhNLtavx0&=Nx2NII{!@1T78VEA*I#65C`b5)8cGclxKQoVFM$P({ zLwJKo9!9xN4Q8a2F`xL&_>KZfN zOK?5jP%CT{^m4_jZahnn4DrqgTr%(e_({|z2`C2NrR6=v9 z*|55wrjpExm3M&wQ^P?rQPmkI9Z9jlcB~4IfYuLaBV95OGm#E|YwBvj5Z}L~f`&wc zrFo!zLX*C{d2}OGE{YCxyPDNV(%RZ7;;6oM*5a>5LmLy~_NIuhXTy-*>*^oo1L;`o zlY#igc#sXmsfGHA{Vu$lCq$&Ok|9~pSl5Q3csNqZc-!a;O@R$G28a@Sg#&gnrYFsk z&OjZtfIdsr%RV)bh>{>f883aoWuYCPDP{_)%yQhVdYh;6(EOO=;ztX1>n-LcOvCIr zKPLkb`WG2;>r)LTp!~AlXjf-Oe3k`Chvw$l7SB2bA=x3s$;;VTFL0QcHliysKd^*n zg-SNbtPnMAIBX7uiwi&vS)`dunX$}x)f=iwHH;OS6jZ9dYJ^wQ=F#j9U{wJ9eGH^#vzm$HIm->xSO>WQ~nwLYQ8FS|?l!vWL<%j1~P<+07ZMKkTqE0F*Oy1FchM z2(Nx-db%$WC~|loN~e!U`A4)V4@A|gPZh`TA18`yO1{ z(?VA_M6SYp-A#%JEppNHsV~kgW+*Ez=?H?GV!<$F^nOd+SZX(f0IoC#@A=TDv4B2M z%G-laS}yqR0f+qnYW_e7E;5$Q!eO-%XWZML++hz$Xaq@c%2&ognqB2%k;Cs!WA6vl z{6s3fwj*0Q_odHNXd(8234^=Asmc0#8ChzaSyIeCkO(wxqC=R`cZY1|TSK)EYx{W9 z!YXa8GER#Hx<^$eY>{d;u8*+0ocvY0f#D-}KO!`zyDD$%z1*2KI>T+Xmp)%%7c$P< zvTF;ea#Zfzz51>&s<=tS74(t=Hm0dIncn~&zaxiohmQn>6x`R+%vT%~Dhc%RQ=Cj^ z&%gxxQo!zAsu6Z+Ud#P!%3is<%*dJXe!*wZ-yidw|zw|C`cR z`fiF^(yZt?p{ZX|8Ita)UC$=fg6wOve?w+8ww|^7OQ0d zN(3dmJ@mV8>74I$kQl8NM%aC+2l?ZQ2pqkMs{&q(|4hwNM z^xYnjj)q6uAK@m|H$g2ARS2($e9aqGYlEED9sT?~{isH3Sk}kjmZ05Atkgh^M6VNP zX7@!i@k$yRsDK8RA1iqi0}#Phs7y(bKYAQbO9y=~10?8cXtIC4@gF#xZS;y3mAI`h zZ^VmqwJ%W>kisQ!J6R?Zjcgar;Il%$jI*@y)B+fn^53jQd0`)=C~w%Lo?qw!q3fVi{~2arObUM{s=q)hgBn64~)W0tyi?(vlFb z>tCE=B1cbfyY=V38fUGN(#vmn1aY!@v_c70}pa(Lrle-(-SH8Nd!emQF zf3kz0cE~KzB%37B24|e=l4)L}g1AF@v%J*A;5F7li!>I0`lfO9TR+ak`xyqWnj5iwJ$>t_vp(bet2p(jRD;5Q9x2*`|FA4#5cfo8SF@cW zeO{H7C0_YJ*P@_BEvm2dB}pUDYXq@G1^Ee#NY9Q`l`$BUXb01#lmQk^{g3?aaP~(* zD;INgi#8TDZ&*@ZKhx$jA^H-H1Lp`%`O{Y{@_o!+7ST}{Ng^P;X>~Bci{|Qdf1{}p z_kK+zL;>D30r6~R?|h!5NKYOi6X&I5)|ME+NG>d9^`hxKpU^)KBOpZiU^ z;|SzGWtbaclC-%9(zR-|q}kB8H&($nsB1LPAkgcm+Qs@cAov{IXxo5PHrH(8DuEMb z3_R#>7^jjGeS7$!`}m8!8$z|)I~{dhd)SvoH9oR9#LjO{{8O&r7w{d9V1z^syn&E6 z{DG0vlQF_Yb3*|>RzVop^{$mWp|%NDYj@4{d*-@O^<(=L=DMFIQHEp-dtz@1Rumd; zadt^4B#(uUyM6aeUJkGl0GfaULpR!2Ql&q$nEV^+SiDptdPbuJ=VJ)`czZ@&HPUuj zc5dSRB&xk)dI~;6N?wkzI}}4K3i%I=EnlKGpPJ9hu?mNzH7|H0j(mN3(ubdaps3GM z1i+9gk=!$mH=L#LRDf4!mXw0;uxSUIXhl|#h*uK+fQPilJc8RCK9GNPt=X^8`*;3$ zBBo77gkGB5F8a8)*OR10nK&~8CEMPVQyhY>i`PS{L^-*WAz$ljtU%zlG1lm%%U4Zw zms0oZR8b|`>4U1X*9JLQQ>m9MF5%ppoafz^;`7DbmmIENrc$hucekkE4I83WhT%(9 zMaE;f7`g4B#vl(#tNP8$3q{$&oY*oa0HLX6D?xTW3M6f<^{%CK4OE1Pmfue`M6Dh= z&Z-zrq$^xhP%|hU&)(+2KSSpeHgX^0?gRZ5wA8@%%9~@|*Ylux1M{WQ4ekG(T+_b` zb6I)QRGp%fRF)^T?i^j&JDBhfNU9?>Sl6WVMM%S?7< ze|4gaDbPooB=F4Y=>~_+y~Q1{Ox@%q>v+_ZIOfnz5y+qy zhi+^!CE*Lv-}>g^%G=bGLqD(aTN;yHDBH#tOC=X02}QU~Xdme``Wn>N>6{VwgU~Z>g+0 zxv0`>>iSfu$baHMw8(^FL6QWe;}(U>@;8j)t)yHAOj?SdeH;evFx-kpU@nT>lsrUt zqhV}2pD^5bC4786guG1`5|fK@pE6xcT#ns)vR|^?A08G62teHaE&p`ZrCBj_Swt*~dVt=5*RK6Y{% zABqK$X59BnrK3r3u=wxklRnA1uh+q`?T0kE1YhvDWF4OY#<(+V|R@R%tdkq2huF(!Ip+EpZF3zr*|9pmKHPo)Cu z;H+^s&`Ql}u=Jt~ZWj`bAw|i-3#7(2WuRU3DU{BW8`?!O?YO1M$*MMTsaEM!5Jyp~ z!gp6yR4$O%wQ8%dyz43ZPeoJwy;o;yg=S0^Y}%|)to>=N^`!3VMf1~}OZ`Dl$q&|w z9$!i3!i1uAgPTuKSWdBrDr*N$g=E#mdqfj*h;Z}OG`{n245+g;IKfdn!&gF2OtHaD zyGDzj@@d2!P(_Ux)3v;1ABTj__{w*kaRF-1YVU`})Acgk?(T*1YqEve3=5)8bkZK* z!Tus*e$h@^u z>#zV0771Bix~r&h2FJ9)%N{>s>?2tk1$bId)1#G;OKgn-U8jUo^AK;Hu)hQEi}swD(264kAS-SBCD$R(Ro0rh8~Le zzRwxbz_JHDbD+hTX15AWmVw!#rC)-zeZahQQmo6FG1)ah3uuyIuTMof}RO!`Y3^Fxn_-G$23RDOh(@NU?r6`*S?#E50)w zpcsgDZ-iO{;EesgDQq9;p*C#QH(sp~2w^zAJWaUL%@yo)iIL6y8;e_}=dwQc%k%;H zFt5lenH*`}LWd+fPqi;exJeRZgl&nLR%|a!%1x0RQ54cgyWBYrL>sskcAtPxi&8c( zw_K?sI*3n%S;lKiYpveBN08{rgV&-B1NN5Jiu07~%n#%&f!(R(z1)xsxtRBkg#+Lv zh21zX?aYDd_f}qdA`Os*j!eC<5)iUJ&Twj7?*p%vEOGElGhpRZsccM!<k}DeC;TY;rULQs3e}lZyP#UVb=6 zB$Dkm2FaHWUXr7<{R&46sfZ)&(HXxB_=e`%LZci`s7L6c-L7iF&wdmTJz`*^=jD~* zpOZ@jcq8LezVkE^M6D9^QgZqnX&x*mr1_Cf#R9R3&{i3%v#}V$UZzGC;Or*=Dw5SXBC6NV|sGZp^#%RTimyaj@!ZuyJ z6C+r}O1TsAzV9PAa*Gd!9#FQMl)ZLHzTr99biAqA(dz-m9LeIeKny3YB=*+|#-Gq# zaErUR5Z*Wh^e<+wcm70eW;f-g=YTbMiDX)AznDM6B73)T4r%nq+*hKcKF?)#vbv?K zPMe=sFCuC*ZqsBPh-?g!m*O`}6<}Pfj}Y1n9|Y@cUdD5GX_)6Sx9pPfS7 zxkt?g6ZwJ+50C7qrh6dMFmr7qah`FskT_H=GC92vkVh$WfZa2%5L99_DxyM{$#6HQ zx$VR-Wwt!q9JL2{ybEGJr$^?!V4m_BqDqt!mbs=QjHf340+^a{)waVvP0+98(BA$M ztWr&sM=juyYgvf`(SC}+y@QtYgU>0ghJ6VbU}|kEraR&&W%#;!#KI?le%g`e>ZVPiDrneh#&1(Y?uiMo^f5qo@{JEr(p9>8GhDa+PC9yG;lX+D?hQ^fZB&Sdox219zUj_5;+n<0@Wi3@DK`MU8FM!OFJ z8*_mTA-u!Ab#95FRVWTIqAL#BVQGxE_s?>Ql|@0o9vos&r<_4d!+Q6(_270)6#lu$ zV!j$a?_V0I<(3Z=J7C-K0a^Kc1Go9p&T6yQeAD+)dG-$a&%Fo0AOte~_Z&_m2@ue~ z9cKFf-A41Dz31Ooj9FSR`l?H5UtdP?JS=UU$jF#znE1k@0g%K?KQuwZkfDI3Ai)(q z#x_Yo6WR_Y@#6I_02S&NpcP<%sw!!M_3#*8qa+*4rS@x=i{-2K#*Qr)*Q$-{<_(<| z0730e+rubnT38*m;|$-4!1r6u&Ua2kO_s-(7*NGgDTe##%I>_9uW;X__b_k)xlv$; zW%K2hsmr>5e^Z~`tS-eUgWmSF9}Yg8E}qydSVX0nYZMX_x94QK?tw2>^;raVTqstR zIrNAX2`X~|h->dTOb9IrA!i5INpLV}99ES|i0ldzC`;R$FBY5&7+TIy8%GO8SZ37_ zw=^Swk?z+j-&0-cTE|LU0q@IKRa&C6ZlXbSa2vN5r-)*f<3{wLV*uJUw980AFkWN7 zKh{?97GmVu-0rs9FB6ludy|n`gN5p~?y51aJzBg6#+-=0pWdZ2n4xTiQ=&3As-!-6 zFlb|ssAJEJL#s8(=odfz8^9b#@RrvNE4gjuEITzAd7R4+rq$yEJKXP?6D@yM7xZ&^ z@%jnE3}bteJo{p(l`hu`Yvzg9I#~>(T;>c;ufeLfc!m3D&RaQS=gAtEO-WbI+f_#| zaVpq-<%~=27U8*qlVCuI6z9@j)#R!z3{jc>&I(qT-8IBW57_$z5Qm3gVC1TcWJNc% zDk?H3%QHno@fu9nT%L^K)=#sRiRNg|=%M zR;8BE)QA4#Dsg^EakzttRg9pkfIrF3iVYVM#*_+#3X+~qeZc^WQJvEyVlO@9=0pl!ayNOh|{j0j^a z+zi_$_0QKhwArW)sJ$wji;A`?$ecbr?(4x5%2pLgh#wggbt)#T^2R3a9m+>GcrUxU z*u-WTgHAN*e!0;Wa%1k)J_P(Vdp>vwrROTVae@6Wn04q4JL-)g&bWO6PWGuN2Q*s9 zn47Q2bIn4=!P1k0jN_U#+`Ah59zRD??jY?s;U;k@%q87=dM*_yvLN0->qswJWb zImaj{Ah&`)C$u#E0mfZh;iyyWNyEg;w0v%QS5 zGXqad{`>!XZJ%+nT+DiVm;lahOGmZyeqJ-;D&!S3d%CQS4ZFM zkzq5U^O|vIsU_erz_^^$|D0E3(i*&fF-fN}8!k3ugsUmW1{&dgnk!|>z2At?h^^T@ zWN_|`?#UM!FwqmSAgD6Hw%VM|fEAlhIA~^S@d@o<`-sxtE(|<><#76_5^l)Xr|l}Q zd@7Fa8Bj1ICqcy2fKl1rD4TYd84)PG5Ee2W4Nt@NNmpJWvc3q@@*c;~%^Vasf2H`y z+~U-19wtFT?@yIFc4SE_ab?s@wEUfSkOED}+qVjjy>=eac2^S^+|_3%cjH%EUTJ&r znp9q?RbStJcT*Vi{3KDa^jr4>{5x+?!1)8c2SqiCEzE$TQ+`3KPQQnG8_Qk<^)y_o zt1Q^f{#yCUt!1e(3;E6y?>p+7sGAYLp`lA3c~Y`re9q&`c6>0?c0E2Ap5seFv92#X z1Vldj!7A8@8tWr&?%;EBQ_Fwd)8A3!wIx`V!~~h(!$pCy7=&*+*uIzG@*d%*{qG#4 zX0^}}sRN^N=p{w(+yjv%xwb!%lnVTE7l1l6gJwQmq_G83J&Y98$S!r*L8}IiIa2E= zE!0tbOuEDb*No0-KB{zjo1k#_4FHtr{!)>o+Y@bll}Sa6D^xktI0H&l{jKAK)A(iz zB-N00F?~Z}Y7tG+vp)-q*v71(C}65$-=uXx^|R$xx9zZip-V>Hqeyfd(wteM)+!!H z$s+>g4I@+`h2>C|J;PhvtOq)`xm4;CyF}R<)!ma3T{Vf_5|zo;D4YI4ZDBkE(vMeE zb#ZV;n}CgA0w8x!UC2&5Z(K)9bibj#?~>R(72lFx_Am~jS?;7mo~p+05~XGD+(wV4 zEVYnf0N5+-7O+Gc1L!sPGUHv<6=cV8}*m$m`kBs@z zy;goR(?J^JrB7uXXpD00+SD0luk!vK3wwp(N%|X!HmO{xC#OMYQ&a7Yqv-54iEUK4 zVH;)rY6)pUX~ESvQK^w|&}>J{I?YlvOhpMgt-JB}m5Br`Q9X+^8+Xa%S81hO<1t#h zbS+MljFP1J0GGNR1}KwE=cfey%;@n&@Kli+Z5d>daJjbvuO3dW{r$1FT0j zR$c9$t~P50P+NhG^krLH%k}wsQ%mm+@#c;-c9>rYy;8#(jZ|KA8RrmnN2~>w0ciU7 zGiLC?Q^{^Ox-9F()RE^>Xq(MAbGaT0^6jc>M5^*&uc@YGt5Iw4i{6_z5}H$oO`arY z4BT(POK%DnxbH>P$A;OWPb@gYS96F7`jTn6JO@hdM za>_p!1mf?ULJZb1w-+HamqN__2CtI%VK`k^(++Ga0%z*z@k0wYJDqT^)~%|4O299; zh1_iRtc7you(kOK8?Q$R7v-@Qk4+i=8GD2_zI0%{Ra`_prF{+UPW^m5MCA&4ZUpZb z2*!)KA8b--Upp~U%f+rsmCmV~!Y>Gzl#yVvZER2h;f&rkdx{r#9mc8DZMJaQXs?SL zCg3#>xR6ve8&YkP*`Z=lng|Ow+h@t*!Ial*XQg3P;VS8@E1C)VS`?L9N+rxlD7bxC z3@Ag)Vu?#ykY`ND+GvRYTUP&-KDMiqly$Z~uFXt^)4Jjk9RIs*&$?-UPM*d7&m${m zm12kaN3mV1J|c6f$>V+{lvHp~XVW3DU0;cBR>7|)4bo{xa1-ts-lYU-Q-b)_fVVl`EP5X}+J9EzT20x8XIv=m7witdu7!3Lh=KE#OyKpT1GWk{YAo^ny|fvZt<+jmsFs=l*%e& zmRkBt5ccv4O7!HAyv2~rsq*(FmMTm?@TX3&1`nu|7C^F{ad%GLuoX}Rl}6`)uHF_xlx^gVca+mGH4T8u8;q{S*x3=j;kelz^atO~)v!Q_BT z4H6%IA}bvfuk0_vweELeEl8N5w-Q1GF!@f{VKnbyYB2?}d&QvI-j}~RI_+9t9$tC2 z94m=3eLi=sQb^S5;fqP?3aaXc&`}`lq z&M8dOXvxx9Y1^u_ZQHhO+qP}nwkvJhwoz$Mp6Qcq^7M#eWm}!3U@s07hop` zW24|J{t$aB`W>uBTssEvYMyi$hkaOqWh+^(RV_1MYnE0XPgW?7sBDk=Cqs(;$qrPEflqa0ZE?A3cBfW%0RPA235Wb6@=R_d>Sez; z`spwa50bq?-zh+id~Q!T`AYn`$GHzs;jxIw(A1_Ql&f|qP}|bon#H;sjKmSDM!nyn z>bU8l%3DB3F+$}|J^da!!pN|DO!Ndc2J)wMk!+Rr1hes#V}5o(?(yQSphn|9_aU<- zn|nsDS{^x&tweP;Ft`2ur>Koo2IdXJDsr6IN)7vB41Yy-^Wbo9*2th2QA@C zE0-0Gk12YOO?d_Guu6b3&(PIL`d zh4{`k54hu9o%v1K3PGuccez-wdC<&2fp)>`qIIaf)R{5un7-vwm=>LD7ibnJ$|KyE zzw`X*tM0S|V(I3vf454PY{yA5lbE+36_<1kd=&0Xy4jfvUKZ0$Jq!AG4KS7DrE9rph;dK^6*#CIU9qu7 z?)6O`TN&MCWGmUVd1@E2ow2`vZ1A#nGo8_n!dmX77DCgAP1va*ILU+!a&$zdm6Pa6 z4#|*&3dM+r_RJb%!0}7X!An&T4a4@ejqNJ;=1YVQ{J6|oURuj8MBZ8i7l=zz%S4-; zL}=M^wU43lZVwNJgN|#xIfo$aZfY#odZ6~z?aNn=oR1@zDb=a(o3w`IGu&j>6lYxL z&MtqINe4Z>bdsHNkVIu$Dbq0wc#X-xev221e~L zbm8kJ(Xzij$gF4Ij0(yuR?H1hShSy@{WXsHyKtAedk4O!IdpR{E32Oqp{1TD{usJi zGG@{3A$x%R*pp8b$RQo4w&eDhN`&b~iZ2m3U>@9p1o5kXoEVmHX7I6Uw4dn((mFw` zilWrqFd=F5sH$&*(eJB52zaLwRe zz`sruIc=Ck75>v5P5kd>B2u=drvGPg6s&k5^W!%CDxtRO)V6_Y_QP{%7B>E~vyMLG zhrfn8kijyK&bX+rZsnSJ26!j$1x+V!Pyn|ph%sXWr9^f&lf|C;+I^Fi_4;`-LJI&F zr;5O@#4jZX=Yaw0`pUyfF4J8A9wE#7_9!X|_s8~YUzWu&#E^%4NxUA3*jK-F5R3LP2|msHBLmiMIzVpPAEX)2 zLKYjm3VI4r#7|nP^}-}rL+Q4?LqlmBnbL+R8P%8VmV{`wP0=~2)LptW_i682*sUR# z+EifOk_cWVKg-iWr^Qf4cs^3&@BFRC6n0vu{HqZzNqW1{m)3K@gi$i}O(hT`f#bT- z8PqCdSj~FncPNmMKl9i9QPH1OMhvd42zLL~qWVup#nIJRg_?7KQ-g3jGTt5ywN;Qx zwmz4dddJYIOsC8VqC2R%NQ>zm=PJH70kS|EsEB>2Otmtf-18`jUGA6kMZL3vEASDN zNX%?0+=vgsUz!dxZ@~)eU17m4pN3xGC0T;#a@b9Iu0g_v*a3|ck^s_DVA^%yH-wt= zm1)7&q6&Rq#)nc9PQ6DKD{NU=&ul10rTiIe!)x^PS~=K(wX9|?k&{Mv&S$iL9@H7= zG0w~UxKXLF003zJ-H%fGA4Db9{~#p&Bl7ki^SWwv2sfoAlrLMvza)uh;7Aa_@FL4b z4G>`j5Mn9e5JrrN#R$wiB(!6@lU@49(tawM&oma6lB$-^!Pmmo;&j57CDmKi)yesg~P;lJPy9D(!;n;^1ql)$5uYf~f z&GywSWx=ABov_%8pCx=g-gww_u26?5st=rdeExu?5dvj^C?ZZxDv@Si^nX~2qA&K= z2jr;{=L(x~9GLXrIGXs>dehU^D}_NMCMegdtNVWyx)8xHT6Qu!R>?%@RvADs9er;NMkweUBFNrBm1F5e0_>^%CwM6ui}K_MpRqLS0*@lAcj zB6TTCBv>w2qh)qU3*kN+6tPmMQx|5Z0A4n67U-nss90Ec_rDF}r)IR4PE{$8;BSt= zT%6|jyD^(w6a*A5>_|TkMqx~e$n@8{`q?|)Q&Y4UWcI!yP-8AwBQ#P`%M&ib;}pli z9KAPU_9txQ3zOM#(x}*lN8q$2(Tq1yT4RN0!t~|&RdQMXfm!81d0ZuyD}aG3r4+g` z8Aevs3E_ssRAMR+&*Q30M!J5&o%^(3$ZJ=PLZ9<@x^0nb>dm17;8EQJE>hLgR(Wc% zn_LXw|5=b$6%X zS~ClDAZ?wdQrtKcV9>_v1_IXqy)?<@cGGq#!H`DNOE1hb4*P_@tGbMy6r@iCN=NiA zL1jLwuMw&N-e9H(v7>HGwqegSgD{GSzZ@sZ?g5Y`fuZ^X2hL=qeFO(;u|QZl1|HmW zYv+kq#fq_Kzr_LaezT zqIkG6R+ve#k6!xy*}@Kz@jcRaG9g|~j5fAYegGOE0k8+qtF?EgI99h*W}Cw z7TP&T0tz4QxiW!r zF4?|!WiNo=$ZCyrom-ep7y}(MVWOWxL+9?AlhX<>p||=VzvX`lUX(EdR^e5m%Rp_q zim6JL6{>S%OKoX(0FS>c1zY|;&!%i-sSE>ybYX3&^>zb`NPj7?N^ydh=s=0fpyyz% zraFILQ17_9<ettJJt~I+sl=&CPHwz zC9dEb#QFQcY?bk11Y=tEl{t+2IG`QFmYS>ECl;kv=N6&_xJLQt>}ZQiFSf+!D*4Ar zGJ~LFB7e_2AQaxg*h{$!eJ6=smO(d2ZNmwzcy3OG@)kNymCWS44|>fP^7QkJHkE9JmLryhcxFASKb4GYkJ|u^Fj=VdF0%6kgKllkt zC|_ov2R4cJ2QjjYjT6jE#J1J<xaNC>Xm;0SX<`LuW*}*{yQ3c9{Zl=<9NP z^2g5rAdO!-b4XfeBrXa4f{M0&VDrq+ps&2C8FYl@S59?edhp~7ee>GR$zQI4r8ONi zP^OA+8zrTAxOMx5ZBS03RS@J_V`3{QsOxznx6Yt*$IuEd3%R|Ki&zZkjNvrxlPD$m z%K+rwM!`E&Z46ogXCu!3 z8use`FJJ?g_xi?~?MxZYXEu=F=XTC8P3{W*CbG3Wk)^31nD~W>*cJ@W4xg%Qqo7rq z`pUu8wL!6Cm~@niI*YmQ+NbldAlQRh?L!)upVZ)|1{2;0gh38FD&8h#V{7tR&&J}I zX1?;dBqK}5XVyv;l(%?@IVMYj3lL4r)Wx9$<99}{B92UthUfHW3DvGth^Q0-=kcJ1 z!*I9xYAc$5N$~rXV>_VzPVv`6CeX(A_j3*ZkeB~lor#8O-k+0OOYzTkri@PVRRpOP zmBV|NKlJT?y4Q82er)@lK&P%CeLbRw8f+ZC9R)twg5ayJ-Va!hbpPlhs?>297lC8 zvD*WtsmSS{t{}hMPS;JjNf)`_WzqoEt~Pd0T;+_0g*?p=dEQ0#Aemzg_czxPUspzI z^H5oelpi$Z{#zG$emQJ#$q#|K%a0_x5`|;7XGMuQ7lQB9zsnh6b75B9@>ZatHR_6c z0(k}`kfHic{V|@;ghTu>UOZ_jFClp>UT#piDniL(5ZNYXWeW0VRfBerxamg4su5<; z(}Ct2AhR@I-ro0}DdZLRtgI@dm+V`cRZjgV-H+aXm5|Mgz`aZX63i<|oHk-E)cABn z0$NR?(>fla7)Ong28FZSi9Yk0LtYl5lZw5wT!K5=fYT$avgkMKJWx~V#i@7~6_{dM zxDDPIW2l{O2Elv#i^cjYg~lGHRj(W*9gD`(FILKY$R`tL2qo&rtU*c;li!V`O$aV{ z!m|n!FAB2>MR_FVN*Ktv5+2dW4rr3YmfEheyD+48%USM#q6)w%#2}~=5yZE1LLcth zF%VtefH&#AcMx7)JNC$P>~OFuG6sK}F7V$D7m!{ixz&inpAVpFXiu^QruAw@Sc7Y2 z_A^V(2W_+KTGRp2aQSMAgyV#b3@{?5q@hPEP6oF3^}|@8GuD6iKbX;!LI!L=P#Za zL$Zuv#=x3fseRMZ()#SQcXv->xW`C|6quwqL1M&KByBj z2V`}(uL4JB-hUs6304@%QL~S6VF^6ZI=e-Nm9Tc^7gWLd*HM-^S&0d1NuObw-Y3e> zqSXR3>u^~aDQx>tHzn9x?XRk}+__h_LvS~3Fa`#+m*MB9qG(g(GY-^;wO|i#x^?CR zVsOitW{)5m7YV{kb&Z!eXmI}pxP_^kI{}#_ zgjaG)(y7RO*u`io)9E{kXo@kDHrbP;mO`v2Hei32u~HxyuS)acL!R(MUiOKsKCRtv z#H4&dEtrDz|MLy<&(dV!`Pr-J2RVuX1OUME@1%*GzLOchqoc94!9QF$QnrTrRzl`K zYz}h+XD4&p|5Pg33fh+ch;6#w*H5`@6xA;;S5)H>i$}ii2d*l_1qHxY`L3g=t? z!-H0J5>kDt$4DQ{@V3$htxCI;N+$d^K^ad8q~&)NCV6wa5(D${P!Y2w(XF!8d0GpJ zRa=xLRQ;=8`J2+A334};LOIhU`HQ*0v4Upn?w|sciL|{AJSrG_(%-(W9EZb%>EAGG zpDY?z1rQLps`nbCtzqJ#@wxU4}(j!ZQ{`g`g*SXlLah*W9 zyuh)UWoRCknQtd~Lk#BT_qjwj&Kw8U)w=owaJ;A5ae}3)y>{neYNS`|VHJdcSEBF# zBJ6a;T)u;^i#L~LVF-X7!E$SggILXMlsEy~v}K*DM2)f@U~g|Q6I-Pss@)`>fgFWx zsq&7pe!|VA-h;@=fBF{(mR1^{1>ukTYUdyF^#A+(|I_&nm{_xaKn3h4&yMyym2k-wMFg(s@ez=DPmuB%`| z6;e@HQKB(|!PU1sW)W6~x|=8m6rL~4dQ9LTk|RzL-_(_77B4I~ZG=q7K%qHiv!FD8 zmt;Vnhb{ymaydv2V;X-5p zTt2ln?kaB9&(dH_X70^@rrCfz)nwfa9LYTHXO(IPcTEf$QiEhTpl??L+`Eetyqof8 zzl=q)?KdYni!C_9b8Z3xm7r5<5ZG-0uA`u^7Dm7k4mAsQ(rkoWy*^DZJa~#y6+hNG zh?7{D9$a9LS`a@SvZ5?C{JUHovWU9KI}z8YV4pWftx21v*Q;MpU{+b@>Or(}pwO^fu0qA3_k_Bo2}lIxvmMhucG-o>O=+R6YxZ zjs!o%K1AA*q#&bs@~%YA@C;}?!7yIml1`%lT3Cvq4)%A)U0o1)7HM;mm4-ZZK2`Lj zLo?!Kq1G1y1lk>$U~_tOW=%XFoyIui^Cdk511&V}x#n4JeB7>bpQkYIkpGQRHxH$L z%tS=WHC~upIXSem>=TTv?BLsQ37AO88(X+L1bI<;Bt>eY!}wjYoBn#2RGEP49&ZH-Z_}R_JK_ z>o*_y!pOI6?Vf*{x-XT;^(_0}2twfk`*)_lLl0H-g|}BC?dm7CU|^-gNJ~rx z($>97WTKf71$?2|V$Ybpf~Aj@ZZOcb3#uRq51%4^ts-#RMrJhgm|K3QpCsPGW=2dZ zAr5-HYX!D*o#Q&2;jL%X?0{}yH}j*(JC4ck;u%=a_D6CrXyBIM&O#7QWgc?@7MCsY zfH6&xgQmG$U6Miu$iF(*6d8Mq3Z+en_Fi`6VFF=i6L8+;Hr6J zmT=k0A2T{9Ghh9@)|G5R-<3A|qe_a#ipsFs6Yd!}Lcdl8k)I22-)F^4O&GP&1ljl~ z!REpRoer@}YTSWM&mueNci|^H?GbJcfC_Y@?Y+e4Yw?Qoy@VLy_8u2d#0W~C6j(pe zyO6SqpGhB-;)%3lwMGseMkWH0EgErnd9a_pLaxbWJug8$meJoY@o-5kNv&A$MJZ=U z^fXPLqV6m3#x%4V*OYD zUPS&WHikdN<{#Yj|EFQ`UojD4`Zh*CZO4Cv`w^&*FfqBi`iXsWg%%a< zk@*c%j1+xib(4q^nHHO^y5d8iNkvczbqZ5;^ZVu%*PJ!O?X-CoNP*&tOU!5%bwUEw zQN?P*a=KKlu{`7GoA}DE=#nDibRgecw>-*da~7&wgow}|DyCJq!-Lp8a~(zR@tO1 zgu(4s4HptPGn(HmN2ayYs@g+yx1n`nU3KM{tQHhMHBw7f#gwru$=C()`aKZAl^dYc ze7fC)8EZEXOryk6AD&-4L+4cJ&M@3;;{R)mi4=`ti7IZByr^|_HNsjcNFu?mIE)jD za2j)FPwRY!R_YR-P?URm0Pti*e#5jmfK)6EvaKCT{h)kbJl{AGr1Ekt}pG?^e z*botRf-RsB8q10BTroj{ZP**)2zkXTF+{9<4@$aNDreO7%tttKkR3z`3ljd?heAJEe<0%4zYK?};Ur*!a>PbGYFFi(OF-%wyzbKeBdbkjv^i9mn@UocSS z4;J%-Q$l`zb&r*Pb`U;3@qkc=8QaPE9KwmlVwAf01sa*uI2*N`9U^3*1lLsM9dJ(4 zZBkU}os|5YT#Z;PD8xVv!yo$-n{-n4JM5ukjnTciniiT`(cZ6sD6~67e5_?8am%!w zeCLUxq~7x-!Xg#PgKV&caC@7mu<86am{WaXo(lAemt4~I$utSp(URWpYNo$RvU*$N z#%iiA+h`(E;BUg;=I!#EaxO89bUK3*v5Nc3GPmURC5TqzC|))DsFNtJICH6oBW6#q z+B(N{ey+^mk_{!@ z)VhAWXG=_0j|0f9iJ;c404PiIFqK)(AD05Xh`Fk`r$^b`v+>*g+_+h@r)e+ELJ45) z?20~u<}HQyQ5AsBz(teF9!!_GLXnm{5Z0e{Ki*@!=&3x4-RcjBn##DDzHJ|KSZ5(E z9=tFZ)p~-}x%9sCY27)2i>(E-^OiYT?_)a;yXAGR$y+E`myMd;xDA#_Q49t*E}&ql#H~|x z2J2R1_#2lt91NnF!uqW%_=HlbF?A{B{n>}9$g5QF!bh_a7LTU~Jyz}7>W5{_LAov{ zy2_dmGy)d)&7^bJyUjEw%3xj{cuG0Eo zwL*XQB*Oi=r&HIIecC1%lbE;Y-*5|cL955S+2@uR18JDL<0;;Uc2Q9JEyo1R!!sz_ z#BqnkGfbLP#oQJk3y}nwMd(3Tt^PVA#zXnYF7D0W1)#+`i?@cm}fBkKD z+Mpcuim53|v7;8Tv(KraEyOK`HvJq^;rlNzOjIbW&HJDFqW>doN&j7)`RDv#v|PQ+ z03WnB4Y4X@Fe-@%3;He*FjY1MFmkyv0>64Cp~FIDKQTwmFP~_CxZOf{8gPy}I<=JC zo%_bmue&$UU0|GG%%99eI!m#5Y1MD3AsJqG#gt3u{%sj5&tQ&xZpP%fcKdYPtr<3$ zAeqgZ=vdjA;Xi##r%!J+yhK)TDP3%C7Y#J|&N^))dRk&qJSU*b;1W%t1;j#2{l~#{ zo8QYEny2AY>N{z4S6|uBzYp>7nP_tqX#!DfgQfeY6CO7ZRJ10&$5Rc+BEPb{ns!Bi z`y;v{>LQheel`}&OniUiNtQv@;EQP5iR&MitbPCYvoZgL76Tqu#lruAI`#g9F#j!= z^FLRVg0?m$=BCaL`u{ZnNKV>N`O$SuDvY`AoyfIzL9~ zo|bs1ADoXMr{tRGL% zA#cLu%kuMrYQXJq8(&qS|UYUxdCla(;SJLYIdQp)1luCxniVg~duy zUTPo9%ev2~W}Vbm-*=!DKv$%TktO$2rF~7-W-{ODp{sL%yQY_tcupR@HlA0f#^1l8 zbi>MV~o zz)zl1a?sGv)E}kP$4v3CQgTjpSJo?s>_$e>s2i+M^D5EfrwjFAo(8E%(^ROV0vz0o z-cg0jIk24n!wxZainfH)+?MGu@kg$XgaMY-^H}z^vG~XC7z2;p2Kv`b^3S#b5ssMOJ7724v>S36dD zeypxJ<=E~sD4f5wX060RIF-AR0#{Z z=&y$r8A-e6q18lIF{@O9Mi%dYSYT6erw!@zrl=uj>o(3=M*Bg4E$#bLhNUPO+Mn}>+IVN-`>5gM7tT7jre|&*_t;Tpk%PJL z%$qScr*q7OJ6?p&;VjEZ&*A;wHv2GdJ+fE;d(Qj#pmf2WL5#s^ZrXYC8x7)>5vq_7 zMCL}T{jNMA5`}6P5#PaMJDB2~TVt;!yEP)WEDAoi9PUt89S2Cj?+E0V(=_sv4Vn6b z_kS6~X!G;PKK>vZF@gWpg8Zuh%YX^2UYPdCg7?EH#^gkdOWpy(%RnXyyrhmJT~UJw zAR;%Zgb6z(mS+o9MT|Sc6O({!i0pzk;s9?Dq)%tTW3*XdM3zhPn*`z45$Bg!P4xfy zD*{>30*JsSk?bQ-DgG62v>Vw-w`SA}{*Za7%N(d-mr@~xq5&OvPa*F2Q3Mqzzf%Oe z4N$`+<=;f5_$9nBd=PhPRU>9_2N8M`tT<-fcvc&!qkoAo4J{e3&;6(YoF8Wd&A+>; z|MSKXb~83~{=byCWHm57tRs{!AI<5papN(zKssb_p_WT@0kL0T0Z5#KLbz%zfk?f7 zR!vXBs36XaNcq5usS7<>skM_*P$e*^8y1ksiuokbsGFQ_{-8BAMfu!Z6G=88;>Fxt z|F-RU{=9i6obkTa0k~L#g;9ot8GCSxjAsyeN~1;^E=o5`m%u7dO1C*nn1gklHCBUw z;R(LgZ}sHld`c%&=S+Vx%;_I1*36P`WYx%&AboA1W@P;BvuFW+ng*wh?^aH4-b7So zG?9kFs_6ma85@wo!Z`L)B#zQAZz{Mc7S%d<*_4cKYaKRSY`#<{w?}4*Z>f2gvK`P1 zfT~v?LkvzaxnV|3^^P5UZa1I@u*4>TdXADYkent$d1q;jzE~%v?@rFYC~jB;IM5n_U0;r>5Xmdu{;2%zCwa&n>vnRC^&+dUZKy zt=@Lfsb$dsMP}Bn;3sb+u76jBKX(|0P-^P!&CUJ!;M?R?z7)$0DXkMG*ccBLj+xI) zYP=jIl88MY5Jyf@wKN--x@We~_^#kM2#Xg$0yD+2Tu^MZ1w%AIpCToT-qQbctHpc_ z>Z97ECB%ak;R<4hEt6bVqgYm(!~^Yx9?6_FUDqQQVk=HETyWpi!O^`EZ_5AoSv@VbUzsqusIZ;yX!4CsMiznO}S{4e>^0`c<)c~mC#*{90@+T@%EQ~>bovc8n_$bvqkOU7CrYe8uI5~{3O7EijeX`js z-$LNz4pJA7_V5~JA_Wl*uSrQYSh9Wm($%@jowv^fSPW<~kK&M*hAleywHd?7v{`;Y zBhL2+-O+7QK_)7XOJAbdTV-S`!I)t~GE8z+fV7y;wp#!wj75drv;R*UdSh(}u$%{VSd0gLeFp;h6FkiVz%g=EY3G#>RU;alRy;vQmk*| z@x-ba0XKE%IyL4OYw6IXzMiS(q^UDk=t(#XgkuF`{P?=k8k3r)rmhkv`vg@kiWd34 z-~t+1aV3SabTbG=nQYs>3~E<}{5@0g**LAWi*~SfRZhGcgP{e5T!0M7CU}`f@r8xI z0bx%sI!?5);-wG+Mx&S=NRfIi>V-wP(n&$X0Bhd)qI^ch%96s6&u7qpiK8ijA=X_R zk&|9f$GXf-;VgnrxV83Cp-Q!!sHH`5O^o~qZu!xny1t?(Au(EAn)D??v<1Uo;#m7-M@ovk|()C(`o>QMTp}F?> zakm3bHBKUjH-MHXDow7#Z|@wea1X9ePH;%YA)fCZ9-MD)p^(p!2E`aU9nmJlm;CXQ zkx~$WQ`Yq{1h5k>E>Ex{Z=P=)N*0b8_O({IeKg?vqQ)hk=JHe z5iqUKm!~mLP0fnRwkCO(xxTV@&p+o8wdSP$jZofYP}yEkvSc z5yD-^>04{zTP7X44q9Af&-wgt7k|XtncO&L@y-wFFR44RsPu57FRvIBaI^Pqy_*DV z@i13CsaR5@X@xH=NT3}T`_vsy!a02n80eQqya=-p7#YW`Jc0z!QglGg`1zeg6uXwI zsB~hlNMo)kFL(V3Q1<%8yoI6X7ncn-&&Uh3rL@S(6@wKAXt6Wr=a2ObI7}8$D-FoI z>AJA>WsBEMi5ba6JhJ%9EAi&ocd(ZsD|MsXwu@X;2h#|(bSWu@2{+c7soC`%uo{sMYq&Vyufb)?OI59ds)O+kyE8@G z@tlpNr0UO~}qd0HQve6njJ zda2+l$gdX7AvvGhxM6OToCuQ|Zw|9!g1)O+7>~{KNvASjp9#Cqce-or+y5xdzWL3gLWt2oa+T(I+{j(&bF1laUsJB{fOgE-B}qslaS>C z)TjzG8XecbS%a+?yT!0QmTex?E478;D|sL*oS4C-g0Tq(YoH|eyxJ#1j088C|U-w5id`%Sz7X_w#l+U9+)$|2no<}5J zRb_9@0esSr?n}HvVGbD5@$p$8k4?qOe-GNOk3-K^Mw>Xg+drCKi5@$GTeijpI;;IG ziD<&go`ptLC&^<0jw^l0aY?_pUUK+xp#0Bk66iQ29vpR)VBE{JOJ&OL^gKsN<&t<| zCMLTYMSDG5Ie9O>6Dl#T{@cscz%)}?tC#?rj>iwQ0!YUk~R z$rB-k=fa9x&631Z9Mfqj_GRoS1MzqSMEdaZ2!isP19Sr>qG8!yL(WWF)_&{F)r>KnJGSciSp!P0fqHr+G=fGO02Q#9gHK zpwz+yhpC4w*<9JO@#(MdkZcWbdCO5B!H`Z|nV?UtcBo96$BgX+7VYMwp@b-%;BrJu zMd*K!{1txv{kHKPDs9?WZrz_^o1Tq2P=+=|E=Oy4#WE{>9}*9(apqhmE`&AeBzQgQ zELFLCmb~q|6y0FCt|B}*uI*ayZ#6=$BpGtF{Jfye#Q>FZ?BPnk)*Qmd?rNG^tvFUU z_b&antYsZnUR6Q9tQUy81r$&ovT#fy;(Db4F&M*C=KxQgHDrRcVR#d+ z0(D|*9#u`w_%2o3faI{?dNd9$#5nj1PROHNq z7HJ(;7B1ThyM>a@Fo^lJb2ls2lD`}ocREH|5pKN;$>gFyM6k)kZG;lA;@kSJIqUhf zX%dhcN(Jtomz4(rNng&1br3Xx33EvCWz%o8s;SpRiKEUFd+KJ+u|gn|J85dZ)Exc&=V|Ns8Xs#P>qv6PX&VAJXJ(ILZO!WJd0 z`+|f5HrEj~isRN7?dBHotcPI7;6W48*%J(9 zftl1Tr`bKH*WNdFx+h;BZ+`p!qKl~|Zt5izh}#pU9FQKE97#$@*pf38Hr8A+`N+50U3$6h%^!4fBN zjh^cl#8qW5OZbvxCfYzKHuyeKLF4z^@~+oqlz9(Hx8vypIiUlt!(vs}_t#4@nh$s; z>FYERg*KD#Xs+W4q-V-IBQK!)M1)Aa+h+V+is)z!_=gEn&^ci7<DEEmYcoSh?WdXUsP7O4)&lQXA(BVM5jI8s6;mO}94AC0gG(`>|T)yuV1l~i-ejCCt zoejDhX0nrZDP|x9u4zp%S2UeDzV`o#pBGu1tZ-$<9TIbN=ALwhQ0=9S{8#}Uu8n-~ z5~xIvUhLSz@c@0|me$CdZCpZl(vQw@a0Y4^{T0w_>pOkwI^x4KkBf3qGmm)nG|Ps5 z_XTY~^b^mL&_*yjl~RRIi&eS(>y?y}O4-)nWyTEPpQAb#Xz8SnnfIL+nAcNL9nqV9 zRL|eyF)RKI5-kJO6}>Q89XmgY@b1&!JI>g3ryZ@jN2v3vm7O`AL!BTWNouJzV+$+Y zYY}u%i>K6=IYU2O$2TAyVjGt?wgF9xCj;?EK(8fWu!!~48`3u^W$eUlCh*91PLxu1 zRY(F7Q3s7h$Q-p&L$ucN}it*-9KR z_<wHu?!dav0$P+PI3{J8?{+l|n&2YMLV2 z+hRta$A5WpCXl1RNbYBsX8IGX{2v>U|8_I-JD56K|GexW>}F_e_g_1r?08v8Kz{V$ zT=6aGMk>ibvRO@Yrc@ezaD0%ydHkXGHrR{7>q~~tO7ChJflwa4-xL|@#YIJejC5VT zInU4CjQ9V0+lClQY=vh^s4MadwQmk7li{54Y;Ht}gkZOIh9(vfK?3kXLoD72!lHD# zwI-Jg|IhT=Y#s|tso1PWp;|aJ2}M?Y{ETyYG<86woO_b+WVRh<9eJu#i5jxKu(s~3 z4mz+@3=aNl^xt{E2_xewFIsHJfCzEkqQ0<7e|{vT>{;WlICA|DW4c@^A*osWudRAP zJut4A^wh@}XW4*&iFq|rOUqg*x%1F+hu3U6Am;CLXMF&({;q0uEWG2w2lZtg)prt` z=5@!oRH~lpncz1yO4+)?>NkO4NEgP4U~VPmfw~CEWo`!#AeTySp3qOE#{oUW>FwHkZ3rBaFeISHfiVSB7%}M) z=10EZ1Ec&l;4 zG98m5sU!pVqojGEFh8P{2|!ReQ&hfDEH2dmTVkrS;$dN~G2v-qnxn^A2VeHqY@;P} zudZD5vHtVvB*loIDF1M7AEEvS&h0;X`u}!1vj6S-NmdbeL=r{*T2J6^VA7F`S`CDd zY|=AA6|9Tu8>ND6fQhfK4;L3vAdJPBA}d6YOyKP&ZVi%z6{lbkE|VyB*p1_julR^k zqBwjkqmFK=u&e8MfArjW-(Ei8{rWso1vt5NhUdN|zpXqK{ylJ8@}wq-nV~L4bIjtt zt$&(1FTIs+aw}{&0SO4*sa0H2h&7g}VN5uYjfed5h7eGp$2Wu*@m9WIr0kxOc}fX9eOWh zFKfV>+SD$@kESKYm{F*J90XQjr$!<~v(J%&RMuQM+6CkmnYZDGlOUdq}%)VA& zl#acS%XE2KuX~7IamK`og@C`21~*cEEc#PZM6HT*Veb_l&Ej~j0zL7p0Eo`mMu(=X zJ$v;&Lya75I4C^saKROgfi(fdP0C$GM3WyZn%mm3yEI>|S&O(u{{S<}ihUp#`X&_z zmQBma;82#`C;dR5Sx09e07FvtJLhZ{9R~|$FCdU6TDNUwTc9kNct?8e@o2MpQDrkg zN?G+aYtTjiUPA=RX5o{4RYu}6;)ET>TcgL^VpfIpluJ|lQR(_)>6k%L^FZmoK-Wm- zR5qy0P)hm8yvqOL>>Z;k4U}!s?%1~7v7K~m+gh=0c9Ip_9UC3nwr$%^I>yU6`;2kV z-uJ%y-afzA7;BC7jc-=XnpHK+Kf*tcOS>f5ab2&J&5hIOfXzs=&cz|Qmrpu6Z);`R z0%3^dioK5x?o7t~SK7u5m{dyUZ#QUPqBHYn@jETeG>VU=ieZuJ;mm^j>dZM7))cw?a`w8R z%3M0R=kdOt^W^$Kq5Z%aJ(a$(*qFpy^W}Ij$h+Jnmc9eaP(vB@{@8t zz=RQ$x4XYC#enS$fxh@;cSZ|D%7ug;0z{C8I8h{KocN-cyv3UG_nk99UNS4ki^OFkYea`q`rs zG@qdMI;4ogcd5Tr`di1JBg4I*6CFvCID_2SN5&)DZG&wXW{|c+BdQ4)G9_{YGA@A* zaf}o^hQFJCFtzt&*ua~%3NylCjLtqWTfmA-@zw;@*?d&RE3O8G&d;AVC|rZrU}jx# zC-9SF`9;CbQ(?07o8Q9E12vi)EP@tOIYKEKnO@-o!ggkC)^#L-c40iZtb4Y-cS>$I zTn~+>rn*Ts>*y*z^b3-fAlne+M-*%ecrI^rmKAVv23cB`aWD?JDJ5NIafRvRr*~~C z)99Afs`BPK!5BFT)b_^8GyH*{22}yDq;be`GnPl=vW+ITnaqzl(uYOHhXi}S!P+QZ z4SwfEPuu&z4t#?6Zaw}bvN{;|80DfxCTuOdz-}iY%AO}SBj1nx1(*F%3A-zdxU0aj z`zzw9-l?C(2H7rtBA*_)*rea>G?SnBgv#L)17oe57KFyDgzE36&tlDunHKKW$?}ta ztJc>6h<^^#x1@iTYrc}__pe0yf1OnQmoTjWaCG`#Cbdb?g5kXaXd-7;tfx?>Y-gI| zt7_K}yT5WM-2?bD-}ym*?~sZ{FgkQ9tXFSF zls=QGy?fZ=+(@M>P3Y>@O{f44yU^fP>zNzIQ0(&O$JCd_!p?2;} zI6E1j@`DxzgJvqcE@zgapQ?tophO14`=14DUZ*#@%rRi``pi0lkNgidSsHGjXK8gO{drQoNqR&tRjM4>^DtW`)fiRFO4LE=Z+nCBS~|B3gZsh`Y?-$g z@8@Z$D7C!L9l=SWoE;(+*YirPLWvBd$5Ztn3J3EaGM+#pW#@{3%yksGqy(2Bt5PVE zf*fICtPp77%}5j#0G8<=v=)LR>-a3dxja8cy3m$=MZ2#$8mbLvxE%NptMd+L?mG`v zF1cANFv17DqP^P5)AYHDQWHk*s~HFq6OaJ3h#BUqUOMkh)~!(ptZ2WP!_$TBV}!@>Ta#eQS_{ffgpfiRbyw1f)X4S z_iU`lNuTy86;%!sF3yh?$5zjW4F?6E9Ts-TnA zDyx5p1h$Z3IsHv7b*Q{5(bkPc{f`2Wfxg*Z#IvQ;W_q9|GqXGj<@abo)FyPtzI~i25&o zC!cJR%0!}lLf^L2eAfZg7Z69wp{J?D6UhXr%vvAn?%)7Ngct4Hrs@LZqD9qFHYAWy z4l=2LI?ER&$He2n`RiG&nsfLv?8$Cl)&d8a-~-N`I|&EPa@Y=v@>0Gl?jlt>AUY;H z`**5bpS#VGhdp4pKbf3iEF*>-eXg_$bqt5Dc%q0+)R50>zd^l7sN5R5Z)Ut+oz-8_ zJ`Z9HE9(=wRTD)T=%GZTEi9K5naPzlfE$|3GYGLRCLsnqLi8Sc6y&iskqA&Z$#7Ng z7Q@C0)6k;J$TlQ+VKZ5)-Ff_BNoIMm+~!@Cv1yAUI-U!R)LHc@+nSUzo$GlRb+8W< zYPG%NFfr;!(RlnvBbN~~EpT6Xj5*^Z&73tdIQ$LZu`vkfzdTKa5|JJtQ_rm4g$9LO zKtgYVdW=b<2WGM3I_j|Rd8gZ3j;)S#AT(aP^d>9wrtQS_+K>pZDX^?mN!Z>f^jP@1 zlJ;i79_MgOAJa`%S9EdVn>ip{d!k6c5%zizdIoB9Nr!n`*X#%6xP1?vHKc6*6+vKx zmEt|f^02)S_u_wlW_<`7uLQU%{wdH0iojOf_=}2=(krE<*!~kn%==#0Zz`?8v@4gP zPB=-O-W=OO3tD19%eX>PZj3YfrCt0sEjgTd#b$buAgBri#)wW14x7QcHf2Cneuizz z368r7`zpf`YltXY9|2V{stf8VCHgKXVGjv$m!hdDf0gi`(Q!(Pyg~FO28Vr#!BYP| zI)qG2?Ho=1Us9dTml}-ZOR?g5Vk)f+r=dbCN*N1=qNfG>UCLeA8pd3Ub-pRx1b3FA zEn`CIMf`2Mt3>>#3RkE19o}aMzi^C`+Z>8iIPHSdTdmjCdJBtNmd9o0^LrJc9|U9c zD~=FUnSyghk7jScMWT|SHkP(&DK$Z=n&lGm+FDTpGxfoIyKV)H6^nY~INQ#=OtIT! zyB*J=(#oHf=S)MNOncW->!c0r0H#=2QzobO&f@x&Y8sYi-)Ld;83zO$9@nPPhD}yt z{P`*fT@Z(?YAmF{1)C;o?G@dfd2$c+=Av*|;P@Yz1KnclB-Z-fJQ-=+T*g>0B7!g# zQH{dHt_%wj=wlmT&m59)TQ~xK)gB6f^EY$=1zcbGf~Q>p_PzDCHR6lndGmqPY2)&w z$Th^K%1v@KeY-5DpLr4zeJcHqB`HqX0A$e)AIm(Y(hNQk5uqovcuch0v=`DU5YC3y z-5i&?5@i$icVgS3@YrU<+aBw+WUaTr5Ya9$)S>!<@Q?5PsQIz560=q4wGE3Ycs*vK z8@ys>cpbG8Ff74#oVzfy)S@LK27V5-0h|;_~=j1TTZ9_1LrbBUHb?)F4fc)&F7hX1v160!vJc!aRI>vp*bYK=CB(Qbtw7 zDr2O^J%%#zHa7M5hGBh#8(2IBAk}zdhAk$`=QYe^0P6Bb+j5X)Grmi$ z6YH?*kx9hX>KCI04iaM_wzSVD+%EWS)@DR&nWsSBc2VIZ>C(jX((ZiV0=cp}rtTO&|GMvbmE4FpBF5Rd z6ZG=>X&>N3?ZN2^11pXEP4L?XUo`qrwxgQm4X~RCttXmZAhnhu4KDK=VkKq?@@Q_Z za`*xyHrsAEsR zV(7)2+|h)%EHHLD3>Qg{>G|ns_%5g5aSzA#z91R zMDKNuIt@|t?PkPsjCxUy&fu^At*yUYdBV!R_KOyVb?DO&z$GLJh9~b|3ELsysL7U6 zp24`RH+;%C(!bWHtX&*bF!l-jEXsR_|K~XL+9c+$`<11IzZ4>se?JZh1Ds60y#7sW zoh+O!Tuqd}w)1VxzL>W?;A=$xf1Os={m;|NbvBxm+JC@H^Fj$J=?t2XqL|2KWl$3+ zz$K+#_-KW(t)MEg6zBSF8XqU$IUhHj+&VwsZqd7) ztjz$#CZrccfmFdi_1$#&wl~A*RisBaBy~)w|txu1QrvR1?)2mb&m2N$C(5MS%hSX)VJnb@ZGXB5^%(<#1L@ zL^>fBd+dEe`&hxXM<0A9tviIs^BDkByJdc~mtTYr!%F7Q1XnK2$%h$Ob30*hSP$Bt zDd#w{2Z%x^Wpv8!)hm>6u01mY!xmPgwZ#Q0148)SxJc3Udt!-&}eRO^LN ze26pQB!Jhg&Z>#FD>`C`sU44><=v>O>tJdLs!HPpV#AM32^J@Za-9J(CQjKxpzXao zQfRkWP%g9P8XV21MmoHfx{DICLSc*t4qVeQL9t}&Pz0rM}YTba@XsD=XMW@FxFM{QYQJHvM(JsUSa3mcTUl9^qcVA zBveO--fqw%{#QGR1vy;x88+qMcgzmcYc#8U`CPPt6bl?uj%w_`b~9JliftnOa|ziW z|6(q&STs_*0{KNa(Z79@{`X&JY1^+;Xa69b|Dd7D&H!hVf6&hh4NZ5v0pt&DEsMpo zMr0ak4U%PP5+e(ja@sKj)2IONU+B`cVR&53WbXAm5=K>~>@0Qh7kK*=iU^KaC~-ir zYFQA7@!SSrZyYEp95i%GCj*1WgtDId*icG=rKu~O#ZtEB2^+&4+s_Tv1;2OIjh~pG zcfHczxNp>;OeocnVoL-HyKU!i!v0vWF_jJs&O1zm%4%40S7_FVNX1;R4h^c1u9V@f z`YzP6l>w>%a#*jk(Y82xQ@`@L(*zD&H>NY`iH(iyEU5R$qwTKC5jm4>BikQGHp^)u z-RQ`UCa70hJaYQeA=HtU1;fyxkcB2oY&q&->r-G9pis)t$`508$?eDDueFdW=n5hJ z08lH$dKN$y#OEE@k{#|<%GYY=_c~fHfC@pD54KSP9{Ek@T47ez$;m$}iwR}3?)hbkwS$@p2iVH0IM$lB*XYA+#}-re|UNzCE)SOYwy z=Y!fkG4&I%3J(_H#UsV#SjHulRIVcpJ`utDTY{k&6?#fzt~@Om=L(vs6cxAJxkIWI z@H7)f2h%9!jl@C!lm+X4uu;TT6o0pd7 zteFQ(ND@djf#o2kTkjcgT=dHs7ukmP0&l8{f;o3JuHGd2Op*?p7?Ct=jA*tIg{MZk z$2Lsc0e8Tdcwrjx|_Ok?9uB3Il|^2FF%X#ck}WoIvrzQXN%kT$9NI{79Wm~gZ3`8I+O`)`n30feZ( zDO-fl6IG3c^8S;Y_M-)+^CmM0tT^g0?H#>H8!oC8W%oU!~3|DJ?)~LT9*&GAQG13zOGq6gs*={cu|(V7{R$y@{-iV*9q@AD(#Ktb}J&3&k|5Djs$)9WM7!6#EaJ_ilvbfUvyh8c?-{n zfuFrC0u6}UJZ7aj@(cNG_(CKgjQQTA-UK@-MVmick zot}6F%@jhq(*}!rVFp5d6?dg|G}M*moyLriI!PQDI;E1L1eOa6>F9E6&mdLD>^0jJ z09l?1PptuV65gm=)VYiv<5?*<+MH~*G|$~9Z3XEy@B1-M(}o&*Fr9Sv6NYAP#`h{p zbwbUE3xeJ;vD}QMqECN)!yvDHRwb7c1s6IRmW!094`?Fm!l~45w)0X`Hg+6Y0-xf# zSMemBdE)Q=e^58HR{kWrL5-H0X6pDu%o{0=#!KxGp0A;6{N5kI+EoY_eTE%2q|rwm zekNeLY-R?htk!YP2|@dbd8TWG4#G)=bXlE{^ZTb^Q$}Er zz)Fp)ul24tBtQFIegdI37`K$VR3tVdi<(fIsu{#QMx=$&CK9M8oN%3Mk;>ZPd-;Q- zn|sSKSnc-S0yrw#TlA$+p{J~u=u98s>IoL@cNLOxH=+1m?;t1bR$vR=M$US&Z8DO3 z_&zhQuId1$wVNsS=X?&s(ecIi#00o{kuPs6kpYkL$jMyGW8U7mlCVaZeEL=HsIxqm zFRLxWin8B>!Dc#9Z#t0RNQiR-@5J+=;tC7|1D*~rxcwHa5iIVD@99cCFE@BukUC-S z^iJdt?dwU)kH2VY9?|zVShMbZctzFRz5Q4tiXa^>@U%jDYq}$rSyc#p2wXr}mc0qq z^lT>$y)N(Qg0dwmEwTopneoU(y)>Mj+f{iHM0o|>ZtCg-itPj4addYz??aE)Rp&hk z_SI)%XeSf=SjZq18h!Cc>Xy&EynnxdHQ){(x@g|ZA%`3LU^KzX02c5N;F#tEk1)7v z(|V9tO3>?^X|kQ*rRBf4>mWW2$-Lx})|M7z125&VHcxsCqB!<$l1F$zCrJ+nm0f3Z z%Hq^=SKpHyV2@Y*Cu2x>fXC0SscnR*($zEB{KOniJcpn@e`PMH*_Q6*0Z^8RNCEvZ z+UU9!927p9YZ&g=bnUvQUZcdisyn;-4;ACXOe-Xor9K8Qbp{ldE17+G@VQT+9ZJQ*9dZoXfU2ue|mMhrrZk2R7&~YjFW4`BTq45UwVc6JORKU)wBCTanITh0GD}s$`C5pb(9{b9 znwee6j%?-UV)_7opOioCf5@C?@w^@g& z&68+oMmV;5JW@TT63&CSDrfYL2$L)pVseDtAwPwleEM3F^-Ufn3PpfxFmx6o zQ`Wq9x#d$e`VKn5LOXNsrqhGao7~|s(u~drPrZ+;aP!C%z4NskZstCbAibD}O%8Ij zb~C(taxco~WzJLxhL1T}3ctXMbV6}_z=IZN9L0|SxLSe`$X`<)BhM`$1&&)e_}fCh z=idVL<+u6Vn{&ksP*ZLlMo$fC`dtzF_?~L?4Rril2G4%v5^7sUa^&8aMtMX&mtapl zD(dW|cisM3fqMaB`8?QbkyiUl2g>hMB5EoS&IB8TdoC~)b$nT=`%GgU`k-)+8}`)F*~I~DXMaTP%kZftx11~?iALs5J+&Rom#p%Y z>dH}-euH4u=_V3hc6^*2WMtL!9%yRTJ93p}@aV0zdY*?xchFI>m+UivV=;aMFp0P~ zwB8P)wvV6D-GL?6hJ#g7Hy7=2i^&Od#S=j!;Rc_yjO!*4aN7{vqzg2t-R|Dav%_NDk z`H_FVlSi==(~f-#65VmQ{EE92x<03lwo5p)s=ZJ^L7PlS>132Whr zR6v~t(#I+(`usYLCoO;Rt8j&b^5g_xgs*98Gp|N}b>-`HtVm)MscD)71y?(K6DRCZV26RsHPHKk)EKKZA%C99t3$t^B0-k5@?E>A-YMbFe?>ms?J?_guHHNU(;id*>xH zTrtam+Aq?n@-y@uY@A?hy?1qX^eLu_RaH4Ave?A8NapgQF=C%XI7wlcCf4<6BRo_% zBXxxc*A6-3CruF?3i8HOdbc%>N=-iiOF+9HX|ht6SCkz;A^am&qi_I&qk1B(x<=(m z>QG)nswCOLl_1{SZ@_eE#m^qb6#6DoMsB*)`17ui+XvF%(}|J4G$z2G*;E!1ERnAH z@q%=#uV6kBddqy4=g>!VTV)9*1=i{wJ}Ep!I*?)uJdA(LwE?(!?;}_u=^M2NShWC_ z*7l4aBJ=!QVU2-iehgb`$vOI8zkm{W%QO~?xOD;NgI;Iqa3#^$^U5D&McReLe&qs# zR<^@QpR4#W~Laz+QBsPt@3L#KF`Yr8}jgHe;5(cfpQ=;Zjtbt;c%y^#-m=hqOT z;KAYakW+$w0&F}>K10&SiPcD9SrDOuczj@U#W})5jGU-_htU`U6Q%wdy((%?J}y+$ z=$4jw1N nJo)qTxG{D(`3*#8tY|67hJRF;)r6F|#I`Ar6I0aafRa=kr-Z0I^}9xf^u;G5iEQCbpv3b#S#%H|HYHsQaHK$! zU#3Fpz8*^pK%RRmX<_09eIVziB0jOgPgFnI-*QcwEBtBiO#v!>{W1cLNXyw3D9M|A z*oGy(u8BkDA1c;MsXmpK^-~pl=We^RYnhZ4bz*)Q)C2G+E3tgx9PzU0T>c|1ilS!T zyE=bz`=wskDiOi!@!l?Y))#%{FM`}7r~X)i1)1*c6_2Q!_1{)fp%cS|YF+Q-CB%d< z=zYus`Vt@Mx*a7V)=mpLS$-5viaKgNB=+zN657qy0qR94!cTtX-Z%KBCg4OKw7b=t zr=`7q5Ox=lJ%!G5WIyNQC1xpqYU0{!I$hyrk!6%De$gp<_*Gc?ES(OwY8U^)Kjgc{ zSlhpXDb|;{+y9`u{EuMz54rlky2~p6xX2>MV6BZ&k`$q%q7v(xYps2wr9e8^4<;CB zc)eAT~B^rjzO6<4BDDH;il6 zFsM8jL+agQ;zazW(uiQjM%fPf2N~_p{cy29XP11_lQFpt`t#9nlk}>fv((FZt-dBa zuMIc4HmPHW04n0TTG9ug9;&OV9euL$Ib|+M7}}L~z4e%%%b|r~6OQj(S2d7XfYn#xp8;KQ55UYu#gY*De5j6Cc z#R%?rqwpy7I1(kpU7B*Pq=etXeYUn04jg%ZPjYqQNa$==yTG=6KX+=;i2Xg+kjV2T*Gc!(ef z`Q4fR*TA=M5-}z+s%YO+!K{k}S**ic&>o4_Tmv$EQTOp7F6TXPCj-UTXy?OQ=%*y62Qajk{rXbR%jMCOFMiVE3KekQa4xR}B%=iPtd8BXo~q$OX_ zSp910{Ew;m|GATsq_XiJ3w@s(jrj^NDtr(Dp!`Ve!Oq?|EJ9=vY2>IfrV{rT%(jiY zi}W@jA2iqd=?q>s;3%?@oi7~Ndo3Ge-2!zX58j(w&zVlPuXm3rcHb7O0RsM|!Ys(b zh(=*&Aywo3vuJoWZnU!u2_4bNkDTc&&bCYc%T zM~~xYxS#3KXFzQ@OXdc%9QDOxqiTd_> zT;(DX9{5dIuC4pO_xy+3{Ov)1I7j!Z)6&nHUvTRP>VU5dm#849icG)cvl0QOPkCIzG^lOp4#UcNr`VhBp(Ha%8@KPlvT*5u!v_$b#b~%sn3K{mu zaxeD%Q~{;Lw03ZAq(Pc-IVj>n*h3l2{sqioCMGatQY0kx zi`1(WWDQ=;gmLSGptEQ%UFC)th@|71<8eiRtX&Mx@#1q#nMF_BMfQdS>!!Qkx2o}= zuqRi?`UOX5P3fP%M+71Q$ctH4Av}bXED#fQ`KR4!b~60nsAv^*M7c-x`|~B}XIuq% zlqIJOf>WvlhQ@Uw$du|14)tZ?; zPNZ|xZSwp1y+d4sut8E4*l2JWR|~o0A9vD-?zC-w zDc@=wE1YKb*OMSi_Kx}&w;#h3>sHp|8^hnA3w?-WK)X?@Z2dgV7`9Cupf-B2RE4x^ zwlw+~!V9C^tyb`J;m2}ksD`w}G9`yu(^--{SQ+wt^Fu4Li~Fft!3QO`upSkAU?o;# z(1Q%GUVWbbkTK-M=T+ULkk3s6Dc9`G4CO6|=&-S&D+rbJQ$`Y-xL~ol;kc(l)VbU>{&>bV+*?ua;$bnDc29RW+Ig16)Vf6=L|fMR_P2b7>6}0 zdlB#-gj|j*C~M=F^2=K*k~=tl6YM3SXXi&K-`EvEXnWz&4D-^hQRBJI3gKKDj^6|> z*WhHSim1qAffNt60Mve9lfw^+&0bx-AM0%j>QP3%W=S@(l=(nrJ678mRQ(#+sI@d{ zdb#5fo#T;hK7xJ=M58wZf|?DHwD%!OZ3JrTGV5#{cfQwuiMvz%!CQ}CubJ7`z?@rSF<+KHNV2goc)a6hP0oHB@3LLKSH2w{um&J*z1Ka2 zLIR>lvOvh>Oxe%?3A@v<_T|}${zf_&@C~^FCo#jB(W9VLO?DX{)n(BQ0(V0`mI|9Y z#U3WwxixJkU_NTvA>5q(A@r2dnEXJp#6B=pww$XGU}~1~c``UKqQb=^*2P|4Dq*_! zhY^i61Sy%T5$Td0O6^C>h(xVvT!}Y##WeT8+s+Uuz=7)~V$>!zU;%d>H)rm*6^IrsCma%|cifwDLk_ z!^W2voQ)D;I$=v2E>iSaBw!d7aD+|LWl2iD!cBw`Q5p1~fk_xGiPi8e^mY&#viTAk zmaKL8m;JQ4bY(n6uBZt02z#noMMxTfF-RzjKre-c+@B)#J3pN-Zv7F}JtAwNk3j?OkpVCL6W1)Q$FLAj zGI!tX;g`O{%pt=0|q54Jyj##w*4e*|_;Us2Tn?!#^R(>u}|FAw1G_ z#wQsagnj9$TAC`2B_XgB$wNq~Sxgl?#0+QWWcB{G`c6~&SosbtRt}Tukw`TQ!oG1= zYyL(y<;Wh+H24>=E}Gs=Hs2%fg;&Qdvr74{E!R?Bd zIRQ?{{xkLJ_44P@y3^#(Be%(pk%$liKbUUo76wSoVfJmt9iTKL3z{uW6L&?jYg>EY zsx{kRiW@q%<$VZvbS(TKKTO4{Ad6l^IeY(F^3}=mX9|FZmQ`~RErNxlBPl3ast}W$T4V?SW=6kIGn@-^`qJv| zZXwhK4Kl1a4E}nLI`rdOi?^pd6;LZ-|8G&INHgOeC5q{_#s+SXb0r(;5ryHFsoTJD zx$VtNDh=-Tx3t!NTlk=hgAaSM)#U}e>_-Ex(|JoX*hWmBPPdTIa-2(BIOUJ|Iddy| zwY*J%z%W$}*;uSoB!BIJB6N6UhQUIQE_yz_qzI>J^KBi}BY>=s6i!&Tc@qiz!=i?7 zxiX$U`wY+pL|g$eMs`>($`tgd_(wYg79#sL4Fo+aAXig?OQz2#X0Qak(8U8^&8==C z#-0^IygzQfJG4SWwS5vko2aaOJn*kM+f1-)aG{T43VJAgxdP(fJ4&U{XR90*#a)G8+clOwdF?hJ?D) zmxu>0>M|g_QRHe_7G|q6o`C>9x4xd$Gl7lAuR~+FtNid=%DRsnf}YI*yOToWO%xnP zY*1G5yDnTGv{{xg5FhWU65q3-|-(+-rJ2WCeSJn(7Az>ej4Jp9+l-GyZ_| zJ8}>iA4g|}q1AhEEv#uWR&$g&Uyht?fVU(qk(j?^D`))s>oG08pow!f>P1u71P%oL2)UC4GeS87&G?{)NE;D=my1Q9{~;y zJULE=bG6jXE28Y11YmoZoo945`MM*`v%5b=_02*0cwzDve#3(4M}NPt`)?SCa|7*q z-94ks(R6WH-l9fE4m4}10WSu&O`|;ZCIT%vL$_pbABY!}s33@~gIvZ0H4co|=_-T$ zF#lC7r`89_+RL9wYN=E3YwR?2{$^ki(KKd>smX(Wh*^VmQh|Ob5$n_%N{!{9xP~LJO0^=V?BK8AbCEFBhDd$^yih$>U z(o{RReCU{#zHSEavFNdc8Yt<%N9pd1flD{ZVSWQu*ea1t#$J5f6*6;tCx=&;EIN^S}*3s%=M#)`~=nz!&Q0&{EP|9nzWyS<#!QxP;!E8&3D}?QKh^ zqGum|+;xu9QE=F#fe2ws5+y1Igr&l`fLyLKry=1}(W+2W`waeOR`ZXlW1B{|;4sE3 zn^ZVlR11hiV~p<~TaSen8I~ay#7Ql=-_|U@$8yjZsZ=Vi+^`JV2+kn+oiSUi%omO_+7}saXnJ9 z5ETilbag(g#jZPopCgJu+n@(i7g}3EK2@N zd64$77H5a`i%b%a^iRjMaprwzWz(`=7E6QY)o)gek7H)yZ-BLw^6FAoHwTj9nJtWc ztKaytMlWGLg29W{?gr|rx&snb@XyvR_}x3fmC>d=-nQp5ab3*whTw}DfUcKlMDDx` z-%?ek^*|Kqooy#>2lfklZ|jN4X$&n6f)RNNPl(+0S>t(8xSeOGj~X0CGRrWmm(WXT z))DDW_t&y$D#2`9<-+JT0x1==26*gpWPV~IF=rePVF%e-I&y$@5eo~A+>yZ&z6&7> z*INESfBHGNegTWga&d@;n;FSCGyW?}e_Qw#GTLHo*fWxuuG@I~5VA!A1pOdRTiPA~ z^AGe(yo=9bwLJD}@oDf$d+34~=(vIuPtOKiP}obDc|?@hY}J*@V|UynBeAkYa?S{@ z_f$U=K+>deTAi&=a*xv>Ruyw$UsTWY=Yn=xjf;s)6NQu>_niQ_idmzIwuL`Scf)f= zyzK?D5a5)^D@H&qN%F6Zd0JeXX*Knbe~VLe^gi|?JK67&mB4jrapV-$`hCQT;C{%T z*pjxB+Y|~LD9bmMN%Iq}S$F$x1yWU7@GcR91V8h;!O2I5MN_rq*gRx(k8T!1WSDTp zr9eJO4$~H94aG^6k5p8k=kFJ>4lnY0q_Bsa$@vTRW6uY?slH|Qt)Yu6Yun&pfJ zBi!h;6x?FDs&79#PT*HSCEUsKws#s%TFy*=2PAfb`>gEPBn+D-WdfXA?MkB=<8kb_ z1+4D11mdHG0EcAyg4dneLtfJ8)RyHQl@6hWJNe(d_EjyCHf7%Xsd)S4A-4COz{G@% z5xQ!P>AS@H@;4Ws)N91)3A6PleMe2<& z!(zv#%Uc?N`(Xmm)OJPYt)BM`nRjoWA&P0Yxl@c9Y02zlPH1J5l$nhPrMwu=atkz4 z)a-1+OEL;d@ctx=s<<+3Sv1VYy0RYmiji|#hy$66#`5;u~BkH4^$EGZ-Y4xyZ=%3KuaeLYKAUr$xMtIh_5mga> zPz<#G0mQ7IxEw-yO}BueN}RaFlg$RwCDB)vLF$wDu%qZyLYsPKdcbHD23$qn9i#JFqIo#OK?u7db2-$GatzO!On87%}Br};~#}n zziVB;qf_4(K$u>Qyz$ln_kBGS!CD-t4Y}9oxL@7@Sx*?NOAzdeINUD>Hl#*V%pfA; zSA`==YatS*G*crJ3`3ll4)vKss&)UtY#7ZxiVoG%9(4<%`WWcjX2jV(^g7Yhj+h5J z$5=?S=tuCyEt74^6jo@6y|@~N>&cVfFNtaRl=)Gm!vR;Bc$3-;ySCI$%kdmjQ|si` z{$q_YCe6vjy6re9jGN|`43D``)1PODtz0)vhV4XV36nVpOnMx2uM%qZ<3TtcI%>BQ zf0(J`{JqPPJxw>k#&nIvoZ5e9Sno)B2r+E0G} z@&M|zf4E0Q$O*NBR2I;?i7N} z@2^Su#`%qeX}m3cbSojiLk#84kvW1fICNPS`OyT0SpUoA0(s^2m~J<^eKE!dhJx_N zG_T}0&(<*an>oF=@?6?55g&IxSgY3?7|@pmDRE6gJyJNPH6un~%0hZ@?h=hI6O$b^ z)29#<4$E)cE-5IFbRpk9JVrw$$966UDyw;Iym4OY4Fc!&s1ZH4BJ1-$9<)Zt1c)N- zU^&9hsk6z?3%<9kGKHW|6~k;&cghtWz`oz`_YjVuvy;B;T67=L2c6=8`7WyTBv*QH zNv*bo1#KOk{O&)@&pkd*?v+kcJ8tM>AGx$~WMhH{L40_N=bkrVg+^p!H)IqXCQf2_ z0fPig=8CEo>p4vE(nc^DKbZ|9_Xo}$i4zJ`jVh95; z5%aNP3@``=EJ=Vt9U`y+$YtX;%OPzgZ_3+;+mh{p#W&y4-%%Bf`LhOy-*kB0qnB^m z_nBTz_b?-`F$*ymByshU>D)za2g`0j^ioo;A#QeL@x3@|+_!=YXA5f6Xg(Ack&WOg zJ<2i|Fd6OmyH!@YSMVxb;=M)ZDhBt)4`5T*>cUXWPG#%@$&*>K&u3#|`fm2mj*FKVf?du{xZ}WKWETTFhq6_fO$PS5(ItF=3~pFp~*j z!ys1<4EL1)#{`mz@gW|t-FpPkd%pK)n_Rb)F;z7cQ6dym_>YI3&e!=!m006oS3Mjq{q ze%hNzW=G0jpfl2K(x`CDuZCsJV*hm9T~%5n7R_g}VFpk`G((D^MWVMAmRp--T{`P; zwMgD<;e`fm`g3|fPns|6qnd{|FCHY*YAguXH(?%sx%4+Gu|Y)_8mk4EljxmP+MP`* z`SUbI{TCIN2OV+$y#g->Jqv#$wL;}4xJmah#$0`v^ughM_XjTA$B}ux)JZuY5-GW4 zKy440I+w=ZtE-_i+0xImq}vyzD68?8;94-5L~_O6Ty>X3itdA-x?6P(c4jkr+f!H( zUDeqiG>3bn^Sf8(`_YwqPeJ9&-@OCQZm4X{FfRMeBtN4E9Ca@;GVpU*L>lVb;@=PH zTQvTr?^jKyCKh&ZVOI*<y%T*Aw(XCPrFC=39*y$A`FSzxBiQ#W+uW10d8&gYp4{teh;^p@anft+z$5!Hv&@h0X-@xJG>hbTCxjDwMiWK@1b%8wYL6BrV zT41m}tX8g-`P@vj4T!Mlk8F0S!MA`^J=SCy9-jdwDe^hVDa`WwyI^H@ryt=F5y6>b zT8&iI6&j8edAfX^ycgWbnMZQ26Q~`LmdEScKC8|~$Jgyw(>18NAQ$9AwCRmri!96L zp^)b0P2CR-9S%cG$#rU}MXnx21T#031o>2VrDs@sa-FpjfvgLPW>Q&LHUoNOtmkt# zoDZ=5OGp{^vO~=p29^`aXd8K?(+f-bW`N$U;-o;%f?RcR!k02Nod2h^^8ly%Z67#E zC3|IOuj~^YBO=Fklo@3mvd6I{Z*&FZ>iq* zxh|JuJoo2$p8MJ3zO@dQ;%1#~Mrm48 zB0053{1bDi_a@jo<4!@!`w4}B(&Qb`~IeSBh zu+_yIYl2Wgk+?x4pCmAM>x_SqBPUj#c`C`k>_fp@qPlAAwD$!zOxRkL7;=|nu(#ut zyF^;&hm-D_;ji{d6rOloACu5*NkF4IC3@rifMG(|^Skv$H&^YnYL*rpw=UCi;JOuz zN*NX(7wZXS4tF@6PIWAs%*j!$RoL*3sh)}iry%thDvN5AUM888q_(>|Tzt|Yea3AyMYBgm$H_`F^v2%)bux)3s znFIEBDK;-JS5SH|;1?afJb<*=c5puu=w%tv#ihn*R!^Hd$KWAp4$#`joJ*)$kNtZ z2Al6h>Z>(u?3tmzA4^d+jLKx{97!Pb4;CX&u;M||**7zXI7hO6nrdMx*Xa=|-`#1^ zBQ?Ha&7cd7hN=%y4yUp?zl8~Lo;%mQrDe8!ce-W_K94FFMN*g(w8q-_K5S+c0{o29X&PzpV;UJE^!xnFc%b@>kvW4m#xiOj-L*DadC&2N#0Us z;<-(m1WB7$=j6hjcPC6JB)D3T2#IC`ibu#yi!uK7W2!j|Z>~RaJ*&XXy#ytIk2DIp z5?Qd^s90_?ILjU#>ZWk5HXts}grg_!Gmgm!d?eLGR7xEP zvTCrslV~94ym5_i<5oqy(@@?wN}lIdtiY8=?|Ng!XeYnly`@9wCGx2S$3x|0x8T2h zz7A85Vb2>s44rKpI_4Y7_Pnd2^mYj2%^jM|Du>u4`^Psda^JIP%*DK6bo`Vf&f{!% zDTYCwF5Nhi=)QhU2$@eQv&ZzxsX+Hl+gP6kW|e!n9IU2>Vh~cioI{>4WvR}t*4Hpz z%5z?HjLGoka}Q3AbX9AkY|Yjf^M(>@tBAI9JO5pDCQu0R3Nns>)LC#vB2p96C*?K? zvX$un$sBDx$1=+NNj*@Oa@u*b@O*XBr_sg@8sCUq-|LK!MUmC)epklrv}5O_^<{NP zX16|c$9Wtbks3y7geI^tF5oRZJu;v zwkW8j+8Ccxo9stEDOT_Go&j%$KCgVO7pm+^%PKEPBZqbMw%s@732XS{cX+wCSjH1s z5)bc=g**<^NNsroY` z?}fHHlgu^B?2r{^^gQ&j zbF~T((>|Yg&C5WKL8DCnl1}Z3!YHFW2S1|;Xr0`Uz-;=FxEwYc4QpeAtnm7^f~uzX zl;xA!?>MLR?tL80Iudm;mi{!ewL91KhG7Hsa-XepKi<2mc6%zf0GwtbfJ1Zf-<@Xu z#|XWDzv|04t)&9Id!UxAAkN{t5qC%%8-WV3i;3duS19%m2||Y{!3pR1=g|zQYAMqc zff)_2nj-O4wfxy;UNM?|Uieo!^J$A*uDe>@V(NKH;KS;Y_dtE8${p>RdcrW;=2*fj4~d?OG0l-(g?ik}vz} z)5-wDppVts>K-=|@{=!53?=8)Jw#RGpS_FWpbwtn}{v!JEJ$q-sr7F6&OPBuI# zuVNFMPte79XgEu!P&qRq8u4J>r%$l-IQ00Lin90(_KtC)aR_de zxN=pY2<1b29_^AG2WJIGmmX4rv3$!`l15{e(H!1^+x9voZ6;882YAE12q7+lgy+>) zj|s0CyzI9=Mo!R}&LXB`&DYpZ7c?0r(&KNV+~TULd0y^e;G{KVR4nL0KvU9mr8&$^ zxrM-9P8zE`J?aZ(iB~Rz<{vvnk2HaZU#K$aVFfYnbAXVUOLU#As5JvS%+26 zi$sNuPY}dLGUS$0g&;oBqhzv2dY`l3@6Na403M!Sh${B|7(y|_cONa;6BrtUe@ZzV z7SThtHT8k?Rwc)(Z}@BP#H@JJHz&GR&M=E@P9KJ89yQKmRh&I~%vbL1L-K3E>7>CH z)Y!=jXVb1iPrAoAZZ3}3wU*5~nrV!ZjL5zqJ<@NwjHCZC>68Cc<{&E_#S;E*jOdjtg?uKN|l`P8sjz&Qf7a^z9 z;{3-8T+H4y99_zc;JYIvs!sk$G}` z??mt*Mm9Z@glCZb!X?!xXD-21sFDPEpZOK{sbQseQ$%6~b;n+*z0hRoR}0Pe>B|#t z$XrVcXv8M|q*Z8MY&r9J0A=d^1bHpjrUXu)qEj~$%%=gZp`^~%O*lzxUquG^p6;n; z^(3HL+hx4gRP?4N*b2p9!^|2~rcw3!9nQj$vmZusbXYz_x^AVc`3qBFm(jS9ueU5h z^AnNnbswfQ2Jq=W=T+p-V|nQco@bOAH$pLQZ+BKH8E$iM>IDz z3|wc?QP`yI=X5YTlp8h}%p6{Deq?S0QD$Ug>ih1SdPZg237Rl{S~=Ha4~-ckMoIWMn+X@@`V6 z#HHZj>MQbt$Qqp*9T(cjc^lxZ7UO(>PwzF-qEr(wo`vaulxdall|KP`7p4gd`23&Jy=#sAes*0diLB(U$Nx46VQvP)8idSs8^zaV91xw*O-JMH=)FoJshRob|_)O)ojtfP))WHCr(;*2;VMQ75^ zfN@a^f#o<|*9X;3IcGodLUz-3i~FAu+zI4c5h+nW^h_!^)b*B_xw-l4O$TB(ixaqW ziMoa%i=BeS<-F45kMO;Tw|FWa`G2c!SuOA3CbowPhF6csf1|&qqugUrj;UgGHm| z;j^yoH?MZhR;AYOW_XW2Lg2j%%ejL)B@*bUMD`g<#Z${1+fa57r7X82 zcqY-cfPnK%Y^3@szRner zt)bBToYCph6Jv*W+&t?&9FG4(Iu2w46 z4B#AcFy_^J@f*6<{>CN}Sj969*DYV*e7<61U>GoN{tz!Do90+jApFueVY_IW(MQF; zl?4yA_(MvMwN&pWKVyg{3uU_+y6RMdot2vu%mC?st=N0pf-~JZXE?3JFf)j<{1xsU z`2ephz)#HzsWEP!inHm2hI(V(~@W zY7gGU-lO52cHD&SY)>QHgy$=>^X%u0TQZfCizro!*weMyvZC=;MWOawdAx~`3C*W` z%^#^$uRP;gyqEE0<(i8xcQY$oc+6mY#z{-XFxsO1(cN8Y)>p;^q9|5bk`Z*p|c!?(rErw#y;yT(%@c7trQBv6cj)$3>pI z>tz+;IB?D=aQV=s(n)o63*yn8dX1m7#Z4G{%fF@K2o5n3jxR~mU?nzMi#;}8e#(>{ zy{Z4!AI)jZ8TY;nq1aq}tq;~=zzoTv)er06oeX3;9{uP{LWR*2%9cmE%S^`~!BW>X zn3PZFTf3g*dG68~^1*q@#^Ge(_8puPEFLD8OS|0b2a{5e=N4S%;~f3tC>F6UxK#v9 z)N-#Mv8=ePCh1KsUKD1A8jF_%$MPf|_yCN9oy%*@um6D{w*2|4GY zb}gafrSC+f=b*W{)!a!fqwZ9)K>fk=i4qf!4M?0v{CMNTo2A9}mQzV=%3UT&i{3{W z>ulG#M!K7%jPf6Mjff9BMslgQq3zIogY);Cv3v;&b#;^=sh#(Bn%W)H*bHNaLwdpq z85%fUTUJJNjYO_426T2TBj0D{6t zw&S_HZ|C?pI_2q(9Fas&@uJs6nVX;P*5K#6p|#)_(8PM-{L(;2wl`ma{ZAd5gA)?y z>0GSLoK<*FwW+G8@-M3vcffg7I(qm7lzF)n`Q9iCvp*mn7=|CjlpG{x z&r0n}XLWZ!>=lynUr7D`6n`7a_ZgT< zm!i;&?Fb0Q2QmqmCHfZ7ex=_tU~(7b)L?RIvPyEAU=gLIZ-VTAA~WR00yKyTXg^(G zqWLZJs!FnQYMOH3*fN&Tn(IKMLf{Ki?pRo8zZJ6YVyj)y0^)-sR}2-)%mI(Aw2AgT zbbp1T{qB(OSNJd0cVBH^tI>HR(q+#*lmi@LWe*rZz&M2h1L_=50uZ1e*n#E*`6?aw zj`ka&JpceRGe@}Ey1)Q~O}0qHRg4K_u>4e1arvJ7Q9!=t5AuzG`n=a-f0}{+lnCE#zu$`oVn44eS&T?N*wz~t~E&oQDBrB_MSg z_yVrQehWbD0xHX|v-hpselAu;O7s;P*!uAT`dr~}Lie=tknaGoiU?;*8Cwgala-65 zosOB4mATbdXJFujzgA4?UkCKE093A1KM?W&Pw>A?IACqg1z~IZYkdP70EeCfjii(n z3k%ax?4|rY(87N&_vhsyVK1zp@uils|B%`(V4e3%sj5f|i(eIhiSg-fHK1Pb0-mS^ zeh?WA7#{hhNci5e;?n*iVy|)iJiR>|8{TN3!=VBC2dN)~^ISSW_(g<^rHr$)nVrdA z39BMa5wl5q+5F@)4b%5-> zA^-P20l_e^S2PTa&HE2wf3jf)#)2ITVXzndeuMpPo8}kphQKhegB%QO+yBpDpgkcl z1nlPp14#+^bIA7__h16pMFECzKJ3p4`;Rf$gnr%{!5#oG42AH&X8hV8061%4W91ku z`OW_hyI+uBOqYXkVC&BqoKWmv;|{O|4d#Nay<)gkxBr^^N48(VDF7Sj#H1i3>9138 zkhxAU7;M)I18&d!Yw!V9zQA0tp(G4<8U5GX{YoYCQ?p56FxcD-2FwO5fqyx@__=$L zeK6Sg3>XQv)qz1?zW-k$_j`-)tf+yRU_%fXrenc>$^70d1Q-W?T#vy;6#Y-Q-<2)+ z5iTl6MA7j9m&oBhRXTKr*$3gec z3E;zX457RGZwUvD$l&8e42Qb^cbq>zYy@ive8`2N9vk=#6+AQlZZ7qk=?(ap1q0n0 z{B9Fte-{Gi-Tvax1)M+d1}Fyg@9X~sh1m|hsDcZuYOnxriBPN;z)q3<=-yBN2iM6V A?*IS* literal 0 HcmV?d00001 diff --git a/examples/stm_dfu/.mvn/wrapper/maven-wrapper.properties b/examples/stm_dfu/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..6d3a5665 --- /dev/null +++ b/examples/stm_dfu/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/stm_dfu/mvnw b/examples/stm_dfu/mvnw new file mode 100755 index 00000000..8d937f4c --- /dev/null +++ b/examples/stm_dfu/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/examples/stm_dfu/mvnw.cmd b/examples/stm_dfu/mvnw.cmd new file mode 100644 index 00000000..c4586b56 --- /dev/null +++ b/examples/stm_dfu/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/java-does-usb/.mvn/wrapper/maven-wrapper.jar b/java-does-usb/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 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 A?*IS* literal 0 HcmV?d00001 diff --git a/java-does-usb/.mvn/wrapper/maven-wrapper.properties b/java-does-usb/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..6d3a5665 --- /dev/null +++ b/java-does-usb/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/java-does-usb/mvnw b/java-does-usb/mvnw new file mode 100755 index 00000000..8d937f4c --- /dev/null +++ b/java-does-usb/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/java-does-usb/mvnw.cmd b/java-does-usb/mvnw.cmd new file mode 100644 index 00000000..c4586b56 --- /dev/null +++ b/java-does-usb/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% From c7b20a3c114fe080148cea8d19a2c311f899b2ac Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 1 Aug 2023 22:35:53 +0200 Subject: [PATCH 267/433] JDK from jdk.java.net --- .github/workflows/continuous-integration.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index 6e55bd23..0eb00733 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -17,11 +17,11 @@ jobs: steps: - uses: actions/checkout@v3 - name: Setup Java - uses: actions/setup-java@v3 + uses: oracle-actions/setup-java@v1 with: - distribution: 'zulu' - java-version: '21' - cache: 'maven' + website: jdk.java.net + release: '21' + version: latest - name: Library run: ./mvnw $MAVEN_ARGS -DskipTests clean package javadoc:javadoc working-directory: ./java-does-usb From 3f147e8c57d97f3bf698d5c4ad8e2515c48004e5 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 1 Aug 2023 22:37:34 +0200 Subject: [PATCH 268/433] Install main jar --- .github/workflows/continuous-integration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index 0eb00733..eb886261 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -23,7 +23,7 @@ jobs: release: '21' version: latest - name: Library - run: ./mvnw $MAVEN_ARGS -DskipTests clean package javadoc:javadoc + run: ./mvnw $MAVEN_ARGS -DskipTests clean install javadoc:javadoc working-directory: ./java-does-usb - name: Example bulk_transfer run: ./mvnw $MAVEN_ARGS clean compile From ab99a3d4eb852ff14d5d30f2cc3bc78189e707e8 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 1 Aug 2023 22:46:10 +0200 Subject: [PATCH 269/433] Install library --- .github/workflows/continuous-integration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index 54d76463..3f431119 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -23,7 +23,7 @@ jobs: java-version: '20' cache: 'maven' - name: Library - run: ./mvnw $MAVEN_ARGS -DskipTests clean package javadoc:javadoc + run: ./mvnw $MAVEN_ARGS -DskipTests clean install javadoc:javadoc working-directory: ./java-does-usb - name: Example bulk_transfer run: ./mvnw $MAVEN_ARGS clean compile From 1f19e7d3b8eef3373ba30196dd5884692257cdad Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 1 Aug 2023 23:14:28 +0200 Subject: [PATCH 270/433] GPG signing key --- .github/workflows/continuous-integration.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index 3f431119..8aca4463 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -22,6 +22,11 @@ jobs: distribution: 'zulu' java-version: '20' cache: 'maven' + - name: Configure GPG Key + run: | + echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import + env: + GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} - name: Library run: ./mvnw $MAVEN_ARGS -DskipTests clean install javadoc:javadoc working-directory: ./java-does-usb From 2f8fcc01762b3b7d3addff048b321e962039ddb7 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 1 Aug 2023 23:43:28 +0200 Subject: [PATCH 271/433] Windows decode64 --- .github/workflows/continuous-integration.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index 8aca4463..dfd5086f 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -27,6 +27,7 @@ jobs: echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import env: GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} + shell: bash - name: Library run: ./mvnw $MAVEN_ARGS -DskipTests clean install javadoc:javadoc working-directory: ./java-does-usb From 5ab14f0efbbdff03dd3d30bf0530b3fdeb727f18 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 1 Aug 2023 23:48:42 +0200 Subject: [PATCH 272/433] Add GPG key --- .github/workflows/continuous-integration.yaml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index eb886261..94b0a984 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -22,21 +22,27 @@ jobs: website: jdk.java.net release: '21' version: latest - - name: Library + - name: Configure GPG key + run: | + echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import + env: + GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} + shell: bash + - name: Build java-does-usb run: ./mvnw $MAVEN_ARGS -DskipTests clean install javadoc:javadoc working-directory: ./java-does-usb - - name: Example bulk_transfer + - name: Example "bulk_transfer" run: ./mvnw $MAVEN_ARGS clean compile working-directory: ./examples/bulk_transfer - - name: Example enumerate + - name: Example "enumerate" run: ./mvnw $MAVEN_ARGS clean compile working-directory: ./examples/enumerate - - name: Example monitor + - name: Example "monitor" run: ./mvnw $MAVEN_ARGS clean compile working-directory: ./examples/monitor - - name: Example stm_dfu + - name: Example "stm_dfu" run: ./mvnw $MAVEN_ARGS clean compile working-directory: ./examples/stm_dfu - - name: Example epaper_display + - name: Example "epaper_display" run: ./mvnw $MAVEN_ARGS clean compile working-directory: ./examples/epaper_display From 8de01072b8a6d08eb5aa80f9b0fbaf1f0a49b7a8 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 2 Aug 2023 13:16:11 +0200 Subject: [PATCH 273/433] Test device firmware CI --- .github/workflows/test-devices.yaml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .github/workflows/test-devices.yaml diff --git a/.github/workflows/test-devices.yaml b/.github/workflows/test-devices.yaml new file mode 100644 index 00000000..42306af5 --- /dev/null +++ b/.github/workflows/test-devices.yaml @@ -0,0 +1,29 @@ +name: Test Devices CI + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: actions/cache@v3 + with: + path: | + ~/.cache/pip + ~/.platformio/.cache + key: ${{ runner.os }}-pio + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + - name: Install PlatformIO Core + run: pip install --upgrade platformio + + - name: Build loopback firmware + run: pio run + working-directory: ./test-devices/loopback + + - name: Build composite firmware-stm32 + run: pio run + working-directory: ./test-devices/composite-stm32 From 70cc7b6bb82d08666f916670e1edcd5fc108f4fe Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 2 Aug 2023 13:19:03 +0200 Subject: [PATCH 274/433] Test device firmware CI --- .github/workflows/test-devices.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-devices.yaml b/.github/workflows/test-devices.yaml index 42306af5..2aacdeca 100644 --- a/.github/workflows/test-devices.yaml +++ b/.github/workflows/test-devices.yaml @@ -22,8 +22,8 @@ jobs: - name: Build loopback firmware run: pio run - working-directory: ./test-devices/loopback + working-directory: ./test-devices/loopback-stm32 - - name: Build composite firmware-stm32 + - name: Build composite firmware run: pio run working-directory: ./test-devices/composite-stm32 From 171f7f880330a905dd9488819ed29afa85138039 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 2 Aug 2023 13:26:02 +0200 Subject: [PATCH 275/433] Paths for CI trigger --- .github/workflows/continuous-integration.yaml | 11 ++++++++++- .github/workflows/test-devices.yaml | 10 +++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index 94b0a984..d6b491b2 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -1,6 +1,15 @@ name: Continuous Integration -on: [push, pull_request] +on: + push: + paths-ignore: + - "test-devices/**" + - "reference/**" + pull_request: + paths-ignore: + - "test-devices/**" + - "reference/**" + env: MAVEN_ARGS: -B -V -ntp -e -Djansi.passthrough=true -Dstyle.color=always diff --git a/.github/workflows/test-devices.yaml b/.github/workflows/test-devices.yaml index 2aacdeca..4ad663f7 100644 --- a/.github/workflows/test-devices.yaml +++ b/.github/workflows/test-devices.yaml @@ -1,6 +1,14 @@ name: Test Devices CI -on: [push, pull_request] +on: + push: + paths: + - "test-devices/**" + - ".github/**" + pull_request: + paths: + - "test-devices/**" + - ".github/**" jobs: build: From c0eb077799204089a6c4ea297f9a446510eeb863 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 6 Aug 2023 11:48:44 +0200 Subject: [PATCH 276/433] Consistent error messages --- .../src/main/java/net/codecrete/usb/USB.java | 4 +- .../net/codecrete/usb/USBControlTransfer.java | 9 +++- .../usb/common/CompositeFunction.java | 2 +- .../usb/common/ConfigurationParser.java | 6 +-- .../usb/common/EndpointInputStream.java | 6 +-- .../usb/common/EndpointOutputStream.java | 6 +-- .../usb/common/TransferCompletion.java | 4 +- .../codecrete/usb/common/USBDeviceImpl.java | 24 +++++----- .../usb/common/USBDeviceRegistry.java | 6 +-- .../codecrete/usb/linux/LinuxAsyncTask.java | 4 +- .../codecrete/usb/linux/LinuxUSBDevice.java | 16 +++---- .../usb/linux/LinuxUSBDeviceRegistry.java | 5 +- .../usb/linux/LinuxUSBException.java | 2 +- .../codecrete/usb/macos/MacosAsyncTask.java | 2 +- .../codecrete/usb/macos/MacosUSBDevice.java | 47 ++++++++++--------- .../usb/macos/MacosUSBDeviceRegistry.java | 4 +- .../usb/macos/MacosUSBException.java | 2 +- .../java/net/codecrete/usb/macos/UUID.java | 2 +- .../codecrete/usb/windows/DeviceProperty.java | 16 +++---- .../usb/windows/WindowsAsyncTask.java | 2 +- .../usb/windows/WindowsUSBDevice.java | 40 ++++++++-------- .../usb/windows/WindowsUSBDeviceRegistry.java | 46 +++++++++--------- .../usb/windows/WindowsUSBException.java | 2 +- 23 files changed, 136 insertions(+), 121 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USB.java b/java-does-usb/src/main/java/net/codecrete/usb/USB.java index d2b9ddb8..59564730 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USB.java @@ -33,7 +33,9 @@ private static USBDeviceRegistry createInstance() { } else if (osName.equals("Linux") && (osArch.equals("amd64") || osArch.equals("aarch64"))) { impl = new LinuxUSBDeviceRegistry(); } else { - throw new UnsupportedOperationException(String.format("Java Does USB has no implementation for architecture " + "%s/%s", osName, osArch)); + throw new UnsupportedOperationException(String.format( + "Java Does USB has no implementation for architecture %s/%s", + osName, osArch)); } return impl; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java index f354fdcd..ef937118 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java @@ -24,6 +24,11 @@ * @param value value (value between 0 and 65535, called {@code wValue} in USB specification) * @param index index (value between 0 and 65535, called {@code wIndex} in USB specification). */ -public record USBControlTransfer(USBRequestType requestType, USBRecipient recipient, int request, int value, - int index) { +public record USBControlTransfer( + USBRequestType requestType, + USBRecipient recipient, + int request, + int value, + int index +) { } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java b/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java index 91bfe1e2..049bbdc6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java @@ -8,7 +8,7 @@ package net.codecrete.usb.common; /** - * Describes the function of an interface of a composite USB device. + * Describes a function of a composite USB device. *

* A composite USB device can have multiple functions, e.g. a mass * storage function and a virtual serial port function. Each function diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java index dc9d7dc7..16c989cd 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java @@ -28,7 +28,7 @@ public class ConfigurationParser { /** - * Parse a USB configuration descriptor (incl. interface and endpoint descriptors) + * Parses a USB configuration descriptor (incl. interface and endpoint descriptors) * * @param desc configuration descriptor * @return parsed configuration data @@ -97,11 +97,11 @@ public Configuration parse() { private void parseHeader() { var desc = new ConfigurationDescriptor(descriptor); if (CONFIGURATION_DESCRIPTOR_TYPE != desc.descriptorType()) - throw new USBException("Invalid USB configuration descriptor"); + throw new USBException("invalid USB configuration descriptor"); var totalLength = desc.totalLength(); if (descriptor.byteSize() != totalLength) - throw new USBException("Invalid USB configuration descriptor length"); + throw new USBException("invalid USB configuration descriptor (invalid length)"); configuration = new Configuration(desc.configurationValue(), desc.attributes(), desc.maxPower()); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index b514b9f9..7e00f1fb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -22,12 +22,12 @@ * Input stream for bulk endpoints – optimized for high throughput. * *

- * Multiple asynchronous transfer are submitted to achieve a good + * Multiple asynchronous transfers are submitted to achieve a good * degree of concurrency between the USB communication handled by the operating * system and the consuming application code. *

*

- * For thread synchronization (between the background thread handling IO completion + * For thread synchronization (between the background thread handling IO completions * and the consuming application thread) a blocking queue is used. When an transfer * completes, the background thread adds it to the queue. The consuming code * waits for the next item in the queue. @@ -178,7 +178,7 @@ private void receiveMoreData() throws IOException { // check for error if (currentTransfer.resultCode() != 0) - device.throwOSException(currentTransfer.resultCode(), "error reading from endpoint %d", + device.throwOSException(currentTransfer.resultCode(), "error occurred while reading from endpoint %d", endpointNumber); } while (currentTransfer.resultSize() <= 0); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java index e95578bc..0a8c7f82 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -40,7 +40,7 @@ public abstract class EndpointOutputStream extends OutputStream { protected USBDeviceImpl device; protected final int endpointNumber; protected final Arena arena; - // Endpoint's packet size + // Endpoint packet size private final int packetSize; // Transfer size (multiple of packet size) private final int transferSize; @@ -228,7 +228,7 @@ private Transfer waitForAvailableTransfer() { var result = transfer.resultCode(); if (result != 0 && !hasError) { transfer.setResultCode(0); - device.throwOSException(result, "error writing to endpoint %d", endpointNumber); + device.throwOSException(result, "error occurred while transmitting to endpoint %d", endpointNumber); } return transfer; @@ -256,6 +256,6 @@ protected void configureEndpoint() { private void checkIsOpen() throws IOException { if (isClosed()) - throw new IOException("Bulk endpoint output stream has been closed"); + throw new IOException("endpoint output stream has been closed"); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/TransferCompletion.java b/java-does-usb/src/main/java/net/codecrete/usb/common/TransferCompletion.java index 578b33cf..98a555e6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/TransferCompletion.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/TransferCompletion.java @@ -16,8 +16,8 @@ public interface TransferCompletion { /** * Called when the asynchronous transfer has completed. *

- * When this function has been called, {@link Transfer#resultCode} and - * {@link Transfer#resultSize} have been filled in. + * When this function has been called, {@link Transfer#resultSize()} and + * {@link Transfer#resultSize()} have been filled in. *

*

* Since there is a single background task calling all completion functions, diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 371b0330..946102fc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -21,7 +21,7 @@ public abstract class USBDeviceImpl implements USBDevice { /** - * Operation-specific device ID used for {@link #equals(Object)} and {@link #hashCode()}. + * Operating system-specific device ID used for {@link #equals(Object)} and {@link #hashCode()}. *

* Can be a String instance (such as a file path) or a Long instance (such as an internal ID). * It only needs to be valid for the duration the device is connected. @@ -79,7 +79,7 @@ public void attachStandardDrivers() { protected void checkIsOpen() { if (!isOpen()) - throw new USBException("The device needs to be open to call this method"); + throw new USBException("device needs to be opened first for this operation"); } @Override @@ -221,7 +221,7 @@ public void setClaimed(int interfaceNumber, boolean claimed) { return; } } - throw new USBException("Internal error (interface not found)"); + throw new USBException("internal error (interface not found)"); } @Override @@ -232,11 +232,11 @@ public USBInterfaceImpl getInterface(int interfaceNumber) { public USBInterfaceImpl getInterfaceWithCheck(int interfaceNumber, boolean isClaimed) { var intf = getInterface(interfaceNumber); if (intf == null) - throw new USBException(String.format("Invalid interface number: %d", interfaceNumber)); + throw new USBException(String.format("invalid interface number: %d", interfaceNumber)); if (isClaimed && !intf.isClaimed()) { - throw new USBException(String.format("Interface %d has not been claimed", interfaceNumber)); + throw new USBException(String.format("interface %d must be claimed first", interfaceNumber)); } else if (!isClaimed && intf.isClaimed()) { - throw new USBException(String.format("Interface %d has already been claimed", interfaceNumber)); + throw new USBException(String.format("interface %d has already been claimed", interfaceNumber)); } return intf; } @@ -292,7 +292,9 @@ protected void throwInvalidEndpointException(USBDirection direction, int endpoin transferTypeDesc = transferType1.name(); else transferTypeDesc = String.format("%s or %s", transferType1.name(), transferType2.name()); - throw new USBException(String.format("Endpoint number %d does not exist, is not part of a claimed interface " + "or is not valid for %s transfer in %s direction", endpointNumber, transferTypeDesc, direction.name())); + throw new USBException(String.format( + "endpoint number %d does not exist, is not part of a claimed interface or is not valid for %s transfer in %s direction", + endpointNumber, transferTypeDesc, direction.name())); } protected int getInterfaceNumber(USBDirection direction, int endpointNumber) { @@ -337,8 +339,8 @@ protected void waitForTransfer(Transfer transfer, int timeout, USBDirection dire if (hasTimedOut && transfer.resultCode() == 0) { abortTransfers(direction, endpointNumber); waitNoTimeout(transfer); - throw new USBTimeoutException(getOperationDescription(direction, endpointNumber) + "aborted due to " + - "timeout"); + throw new USBTimeoutException(getOperationDescription(direction, endpointNumber) + + "aborted due to timeout"); } } @@ -381,9 +383,9 @@ private static boolean waitWithTimeout(Transfer transfer, int timeout) { protected static String getOperationDescription(USBDirection direction, int endpointNumber) { if (endpointNumber == 0) { - return "Control transfer"; + return "control transfer"; } else { - return String.format("Transfer %s on endpoint %d", direction.name(), endpointNumber); + return String.format("transfer %s on endpoint %d", direction.name(), endpointNumber); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index ded911f2..877ae310 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -104,8 +104,8 @@ protected void emitOnDeviceDisconnected(USBDevice device) { onDeviceDisconnectedHandler.accept(device); } catch (Exception e) { - System.err.println("Warning: [JavaDoesUSB] unhandled exception in 'onDeviceDisconnected' handler - " + - "ignoring"); + System.err.println( + "Warning: [JavaDoesUSB] unhandled exception in 'onDeviceDisconnected' handler - ignoring"); e.printStackTrace(System.err); } } @@ -136,7 +136,7 @@ protected void startDeviceMonitor(Runnable monitorTask) { } if (failureCause != null) - throw new USBException("Initial device enumeration has failed", failureCause); + throw new USBException("initial device enumeration has failed", failureCause); } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index 100360c5..19d01492 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -253,7 +253,7 @@ synchronized void submitTransfer(LinuxUSBDevice device, int endpointAddress, USB if (IO.ioctl(device.fileDescriptor(), SUBMITURB, urb, errorState) < 0) { var action = endpointAddress >= 128 ? "reading from" : "writing to"; var endpoint = endpointAddress == 0 ? "control endpoint" : String.format("endpoint %d", endpointAddress); - throwLastError(errorState, "failed %s %s", action, endpoint); + throwLastError(errorState, "error occurred while %s %s", action, endpoint); } } } @@ -310,7 +310,7 @@ synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { if (IO.ioctl(fd, DISCARDURB, urb, errorState) < 0) { // ignore EINVAL; it occurs if the URB has completed at the same time if (Linux.getErrno(errorState) != errno.EINVAL()) - throwLastError(errorState, "failed to abort transfer"); + throwLastError(errorState, "error occurred while aborting transfer"); } } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 49a4fe14..44aeb890 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -60,7 +60,7 @@ private void loadDescription(String path) { try { descriptors = Files.readAllBytes(Path.of(path)); } catch (IOException e) { - throw new USBException("Cannot read configuration descriptor", e); + throw new USBException("reading configuration descriptor failed", e); } // `descriptors` contains the device descriptor followed by the configuration descriptor @@ -92,14 +92,14 @@ public boolean isOpen() { @Override public synchronized void open() { if (isOpen()) - throwException("the device is already open"); + throwException("device is already open"); try (var arena = Arena.ofConfined()) { var pathUtf8 = arena.allocateUtf8String(uniqueDeviceId.toString()); var errorState = allocateErrorState(arena); fd = IO.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC(), errorState); if (fd == -1) - throwLastError(errorState, "Cannot open USB device"); + throwLastError(errorState, "opening USB device failed"); asyncTask.addForAsyncIOCompletion(this); } } @@ -146,7 +146,7 @@ public synchronized void claimInterface(int interfaceNumber) { } if (ret != 0) - throwLastError(errorState, "Cannot claim USB interface"); + throwLastError(errorState, "claiming USB interface failed"); setClaimed(interfaceNumber, true); } @@ -161,7 +161,7 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna // check alternate setting var altSetting = intf.getAlternate(alternateNumber); if (altSetting == null) - throwException("Interface %d does not have an alternate interface setting %d", interfaceNumber, + throwException("interface %d does not have an alternate interface setting %d", interfaceNumber, alternateNumber); try (var arena = Arena.ofConfined()) { @@ -171,7 +171,7 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna var errorState = allocateErrorState(arena); var ret = IO.ioctl(fd, USBDevFS.SETINTERFACE, setIntfSegment, errorState); if (ret != 0) - throwLastError(errorState, "Failed to set alternate interface"); + throwLastError(errorState, "setting alternate interface failed"); } intf.setAlternate(altSetting); @@ -187,7 +187,7 @@ public synchronized void releaseInterface(int interfaceNumber) { var errorState = allocateErrorState(arena); var ret = IO.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment, errorState); if (ret != 0) - throwLastError(errorState, "Cannot release USB interface"); + throwLastError(errorState, "releasing USB interface failed"); setClaimed(interfaceNumber, false); @@ -329,7 +329,7 @@ public void clearHalt(USBDirection direction, int endpointNumber) { var errorState = allocateErrorState(arena); var res = IO.ioctl(fd, USBDevFS.CLEAR_HALT, endpointAddrSegment, errorState); if (res < 0) - throwLastError(errorState, "Clearing halt failed"); + throwLastError(errorState, "clearing halt failed"); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 63fb45f2..7bf62baf 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -220,8 +220,9 @@ private USBDevice getDeviceDetails(MemorySegment udevDevice) { return device; } catch (Exception e) { - System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device 0x%04x/0x%04x - " + - "ignoring device%n", vendorId, productId); + System.err.printf( + "Info: [JavaDoesUSB] failed to retrieve information about device 0x%04x/0x%04x - ignoring device%n", + vendorId, productId); e.printStackTrace(System.err); return null; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java index 1d8786cf..43924a9a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java @@ -27,7 +27,7 @@ public class LinuxUSBException extends USBException { * @param errorCode Linux error code (returned by {@code errno}) */ public LinuxUSBException(String message, int errorCode) { - super(String.format("%s. %s", message, Linux.getErrorMessage(errorCode)), errorCode); + super(String.format("%s: %s", message, Linux.getErrorMessage(errorCode)), errorCode); } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java index a99dc33e..0ca192b5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java @@ -116,7 +116,7 @@ private void startAsyncIOThread(MemorySegment firstSource) { Arena.global()); } catch (IllegalAccessException | NoSuchMethodException e) { - throw new USBException("Creating method handle failed", e); + throw new USBException("internal error (creating method handle)", e); } var thread = new Thread(() -> asyncIOCompletionTask(firstSource), "USB async IO"); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 39a67e48..82d28dea 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -75,7 +75,7 @@ public void detachStandardDrivers() { throwException("detachStandardDrivers() must not be called while the device is open"); var ret = IoKitUSB.USBDeviceReEnumerate(device, IOKit.kUSBReEnumerateCaptureDeviceMask()); if (ret != 0) - throwException(ret, "failed to detach kernel drivers"); + throwException(ret, "detaching standard drivers failed"); } @Override @@ -84,7 +84,7 @@ public void attachStandardDrivers() { throwException("attachStandardDrivers() must not be called while the device is open"); var ret = IoKitUSB.USBDeviceReEnumerate(device, IOKit.kUSBReEnumerateReleaseDeviceMask()); if (ret != 0) - throwException(ret, "failed to attach kernel drivers"); + throwException(ret, "attaching standard drivers failed"); } @Override @@ -96,7 +96,7 @@ public boolean isOpen() { @Override public synchronized void open() { if (isOpen()) - throwException("the device is already open"); + throwException("device is already open"); // open device (several retries if device has just been connected/discovered) var duration = System.currentTimeMillis() - discoveryTime; @@ -116,7 +116,7 @@ public synchronized void open() { } } if (ret != 0) - throwException(ret, "unable to open USB device"); + throwException(ret, "opening USB device failed"); claimedInterfaces = new ArrayList<>(); addDeviceEventSource(); @@ -124,7 +124,7 @@ public synchronized void open() { // set configuration ret = IoKitUSB.SetConfiguration(device, (byte) configurationValue); if (ret != 0) - throwException(ret, "failed to set configuration"); + throwException(ret, "setting configuration failed"); updateEndpointList(); } @@ -165,7 +165,7 @@ private void loadDescription(MemorySegment device) { var descPtrHolder = arena.allocate(ADDRESS); var ret = IoKitUSB.GetConfigurationDescriptorPtr(device, (byte) 0, descPtrHolder); if (ret != 0) - throwException(ret, "failed to query first configuration"); + throwException(ret, "querying first configuration failed"); var configDesc = dereference(descPtrHolder).reinterpret(999999); var configDescHeader = new ConfigurationDescriptor(configDesc); @@ -189,7 +189,7 @@ private InterfaceInfo findInterface(int interfaceNumber) { var iterHolder = arena.allocate(JAVA_INT); var ret = IoKitUSB.CreateInterfaceIterator(device, request, iterHolder); if (ret != 0) - throwException("CreateInterfaceIterator failed"); + throwException("internal error (CreateInterfaceIterator)"); final var iter = iterHolder.get(JAVA_INT, 0); outerCleanup.add(() -> IOKit.IOObjectRelease(iter)); @@ -220,7 +220,7 @@ private InterfaceInfo findInterface(int interfaceNumber) { } } - throwException("Invalid interface number: %d", interfaceNumber); + throwException("invalid interface number: %d", interfaceNumber); throw new AssertionError("not reached"); } @@ -235,7 +235,7 @@ public synchronized void claimInterface(int interfaceNumber) { var ret = IoKitUSB.USBInterfaceOpen(interfaceInfo.iokitInterface()); if (ret != 0) - throwException(ret, "Failed to claim interface"); + throwException(ret, "claiming interface failed"); IoKitUSB.AddRef(interfaceInfo.iokitInterface()); claimedInterfaces.add(interfaceInfo); @@ -254,7 +254,7 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna // check alternate setting var altSetting = intf.getAlternate(alternateNumber); if (altSetting == null) - throwException("Interface %d does not have an alternate interface setting %d", interfaceNumber, + throwException("interface %d does not have an alternate interface setting %d", interfaceNumber, alternateNumber); var intfInfo = @@ -262,7 +262,7 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna var ret = IoKitUSB.SetAlternateInterface(intfInfo.iokitInterface(), (byte) alternateNumber); if (ret != 0) - throwException(ret, "Failed to set alternate interface"); + throwException(ret, "setting alternate interface failed"); intf.setAlternate(altSetting); updateEndpointList(); @@ -283,7 +283,7 @@ public synchronized void releaseInterface(int interfaceNumber) { var ret = IoKitUSB.USBInterfaceClose(interfaceInfo.iokitInterface()); if (ret != 0) - throwException(ret, "Failed to release interface"); + throwException(ret, "releasing interface failed"); claimedInterfaces.remove(interfaceInfo); IoKitUSB.Release(interfaceInfo.iokitInterface()); @@ -316,7 +316,7 @@ private void updateEndpointList() { var numEndpointsHolder = arena.allocate(JAVA_BYTE); var ret = IoKitUSB.GetNumEndpoints(intf, numEndpointsHolder); if (ret != 0) - throwException(ret, "Failed to get number of endpoints"); + throwException(ret, "internal error (GetNumEndpoints)"); var numEndpoints = numEndpointsHolder.get(JAVA_BYTE, 0) & 255; for (var pipeIndex = 1; pipeIndex <= numEndpoints; pipeIndex++) { @@ -324,7 +324,7 @@ private void updateEndpointList() { ret = IoKitUSB.GetPipeProperties(intf, (byte) pipeIndex, directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); if (ret != 0) - throwException(ret, "Failed to get pipe properties"); + throwException(ret, "internal error (GetPipeProperties)"); var endpointNumber = numberHolder.get(JAVA_BYTE, 0) & 0xff; var direction = directionHolder.get(JAVA_BYTE, 0) & 0xff; @@ -355,8 +355,9 @@ private synchronized EndpointInfo getEndpointInfo(int endpointNumber, USBDirecti else transferTypeDesc = String.format("%s or %s", transferType1.name(), transferType2.name()); - throwException("Endpoint number %d does not exist, is not part of a claimed interface or is not valid for %s " - + "transfer in %s direction", endpointNumber, transferTypeDesc, direction.name()); + throwException( + "endpoint number %d does not exist, is not part of a claimed interface or is not valid for %s transfer in %s direction", + endpointNumber, transferTypeDesc, direction.name()); throw new AssertionError("not reached"); } @@ -499,7 +500,7 @@ synchronized void submitTransferIn(int endpointNumber, MacosTransfer transfer, i MemorySegment.ofAddress(transfer.id())); if (ret != 0) - throwException(ret, "failed to read from endpoint %d", endpointNumber); + throwException(ret, "error occurred while reading from endpoint %d", endpointNumber); } /** @@ -529,7 +530,7 @@ synchronized void submitTransferOut(int endpointNumber, MacosTransfer transfer, MemorySegment.ofAddress(transfer.id())); if (ret != 0) - throwException(ret, "failed to write to endpoint %d", endpointNumber); + throwException(ret, "error occurred while transmitting to endpoint %d", endpointNumber); } /** @@ -548,7 +549,7 @@ synchronized void submitControlTransfer(MemorySegment deviceRequest, MacosTransf MemorySegment.ofAddress(transfer.id())); if (ret != 0) - throwException(ret, "failed to execute control transfer"); + throwException(ret, "control transfer failed"); } @Override @@ -563,7 +564,7 @@ public void abortTransfers(USBDirection direction, int endpointNumber) { var ret = IoKitUSB.AbortPipe(epInfo.iokitInterface(), epInfo.pipeIndex()); if (ret != 0) - throwException(ret, "Aborting transfer failed"); + throwException(ret, "aborting transfers failed"); } @Override @@ -573,7 +574,7 @@ public void clearHalt(USBDirection direction, int endpointNumber) { var ret = IoKitUSB.ClearPipeStallBothEnds(epInfo.iokitInterface(), epInfo.pipeIndex()); if (ret != 0) - throwException(ret, "Clearing halt condition failed"); + throwException(ret, "clearing halt condition failed"); } @Override @@ -611,7 +612,7 @@ private synchronized void addDeviceEventSource() { var sourceHolder = innerArena.allocate(ADDRESS); var ret = IoKitUSB.CreateDeviceAsyncEventSource(device, sourceHolder); if (ret != 0) - throwException(ret, "failed to create event source"); + throwException(ret, "internal error (CreateDeviceAsyncEventSource)"); var source = dereference(sourceHolder); asyncTask.addEventSource(source); } @@ -622,7 +623,7 @@ private synchronized void addInterfaceEventSource(InterfaceInfo interfaceInfo) { var sourceHolder = innerArena.allocate(ADDRESS); var ret = IoKitUSB.CreateInterfaceAsyncEventSource(interfaceInfo.iokitInterface(), sourceHolder); if (ret != 0) - throwException(ret, "failed to create event source"); + throwException(ret, "internal error (CreateInterfaceAsyncEventSource)"); var source = dereference(sourceHolder); asyncTask.addEventSource(source); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 62577d7e..049429ed 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -132,7 +132,7 @@ private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { // get entry ID (as unique ID) var ret = IOKit.IORegistryEntryGetRegistryEntryID(service, entryIdHolder); if (ret != 0) - throwException(ret, "IORegistryEntryGetRegistryEntryID failed"); + throwException(ret, "internal error (IORegistryEntryGetRegistryEntryID)"); var entryId = entryIdHolder.get(JAVA_LONG, 0); // call consumer to process device @@ -226,7 +226,7 @@ private int setupNotification(Arena arena, MemorySegment notifyPort, MemorySegme var ret = IOKit.IOServiceAddMatchingNotification(notifyPort, notificationType, matchingDict, onDeviceCallbackStub, NULL, deviceIterHolder); if (ret != 0) - throwException(ret, "IOServiceAddMatchingNotification failed"); + throwException(ret, "internal error (IOServiceAddMatchingNotification)"); return deviceIterHolder.get(JAVA_INT, 0); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java index 43078fb5..90653942 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java @@ -27,7 +27,7 @@ public class MacosUSBException extends USBException { * @param errorCode macOS error code (usually returned by macOS functions) */ public MacosUSBException(String message, int errorCode) { - super(String.format("%s. %s", message, machErrorMessage(errorCode)), errorCode); + super(String.format("%s: %s", message, machErrorMessage(errorCode)), errorCode); } private static String machErrorMessage(int errorCode) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java index d5b7ca82..5aef8e98 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/UUID.java @@ -34,7 +34,7 @@ static MemorySegment createCFUUID(byte[] bytes) { uuidBytes.copyFrom(MemorySegment.ofArray(bytes)); return CoreFoundation.CFUUIDCreateFromUUIDBytes(NULL, uuidBytes); } catch (Exception e) { - throw new AssertionError("internal error (createCFUUID)", e); + throw new AssertionError("internal error (CFUUIDCreateFromUUIDBytes)", e); } } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index 2c255781..0acecf5b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -75,10 +75,10 @@ static int getDeviceIntProperty(MemorySegment devInfoSet, MemorySegment devInfoD var errorState = allocateErrorState(arena); if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, errorState) == 0) - throwLastError(errorState, "Internal error (SetupDiGetDevicePropertyW - A)"); + throwLastError(errorState, "internal error (SetupDiGetDevicePropertyW - A)"); if (propertyTypeHolder.get(JAVA_INT, 0) != SetupAPI.DEVPROP_TYPE_UINT32()) - throwException("Internal error (expected property type UINT32)"); + throwException("internal error (expected property type UINT32)"); return propertyValueHolder.get(JAVA_INT, 0); } @@ -137,11 +137,11 @@ private static MemorySegment getVariableLengthProperty(MemorySegment devInfoSet, if (err == Kernel32.ERROR_NOT_FOUND()) return null; if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) - throwException(err, "Internal error (SetupDiGetDevicePropertyW - B)"); + throwException(err, "internal error (SetupDiGetDevicePropertyW - B)"); } if (propertyTypeHolder.get(JAVA_INT, 0) != propertyType) - throwException("Internal error (unexpected property type)"); + throwException("internal error (unexpected property type)"); var stringLen = requiredSizeHolder.get(JAVA_INT, 0) / 2 - 1; @@ -151,7 +151,7 @@ private static MemorySegment getVariableLengthProperty(MemorySegment devInfoSet, // get property value if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, errorState) == 0) - throwLastError(errorState, "Internal error (SetupDiGetDevicePropertyW - C)"); + throwLastError(errorState, "internal error (SetupDiGetDevicePropertyW - C)"); return propertyValueHolder; } @@ -174,7 +174,7 @@ static List findDeviceInterfaceGUIDs(MemorySegment devInfoSet, MemorySeg var regKey = SetupAPI2.SetupDiOpenDevRegKey(devInfoSet, devInfoData, SetupAPI.DICS_FLAG_GLOBAL(), 0, SetupAPI.DIREG_DEV(), Advapi32.KEY_READ(), errorState); if (Win.isInvalidHandle(regKey)) - throwLastError(errorState, "Cannot open device registry key"); + throwLastError(errorState, "internal error (SetupDiOpenDevRegKey)"); cleanup.add(() -> Advapi32.RegCloseKey(regKey)); // read registry value (without buffer, to query length) @@ -185,14 +185,14 @@ static List findDeviceInterfaceGUIDs(MemorySegment devInfoSet, MemorySeg if (res == Kernel32.ERROR_FILE_NOT_FOUND()) return List.of(); // no device interface GUIDs if (res != 0 && res != Kernel32.ERROR_MORE_DATA()) - throwException(res, "Internal error (RegQueryValueExW)"); + throwException(res, "internal error (RegQueryValueExW)"); // read registry value (with buffer) var valueSize = valueSizeHolder.get(JAVA_INT, 0); var value = arena.allocate(valueSize); res = Advapi32.RegQueryValueExW(regKey, keyNameSegment, NULL, valueTypeHolder, value, valueSizeHolder); if (res != 0) - throwException(res, "Internal error (RegQueryValueExW)"); + throwException(res, "internal error (RegQueryValueExW)"); return Win.createStringListFromSegment(value); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java index 7cad8a23..3a509650 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java @@ -80,7 +80,7 @@ private void asyncCompletionTask() { var overlappedAddr = overlappedHolder.get(JAVA_LONG, 0); if (res == 0 && overlappedAddr == 0) - throwLastError(errorState, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); + throwLastError(errorState, "internal error (SetupDiGetDeviceInterfaceDetailW)"); if (overlappedAddr == 0) return; // registry closing? diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 9c6ffc1c..5d5918c7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -83,7 +83,7 @@ public boolean isOpen() { @Override public synchronized void open() { if (isOpen()) - throwException("the device is already open"); + throwException("device is already open"); showAsOpen = true; } @@ -106,14 +106,14 @@ public synchronized void claimInterface(int interfaceNumber) { var intfHandle = getInterfaceHandle(interfaceNumber); if (intfHandle.interfaceHandle != null) - throwException("Interface %d has already been claimed", interfaceNumber); + throwException("interface %d has already been claimed", interfaceNumber); var firstIntfHandle = intfHandle; if (intfHandle.firstInterfaceNumber != interfaceNumber) firstIntfHandle = getInterfaceHandle(intfHandle.firstInterfaceNumber); if (firstIntfHandle.devicePath == null) - throwException("Interface number %d cannot be claimed (non WinUSB device?)", interfaceNumber); + throwException("interface number %d cannot be claimed (non WinUSB device?)", interfaceNumber); try (var arena = Arena.ofConfined()) { @@ -128,7 +128,7 @@ public synchronized void claimInterface(int interfaceNumber) { Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), NULL, errorState); if (Win.isInvalidHandle(deviceHandle)) - throwLastError(errorState, "Cannot open USB device %s", firstIntfHandle.devicePath); + throwLastError(errorState, "opening USB device %s failed", firstIntfHandle.devicePath); asyncTask.addDevice(deviceHandle); @@ -140,7 +140,7 @@ public synchronized void claimInterface(int interfaceNumber) { // open interface var interfaceHandleHolder = arena.allocate(ADDRESS); if (WinUSB2.WinUsb_Initialize(deviceHandle, interfaceHandleHolder, errorState) == 0) - throwLastError(errorState, "Cannot open WinUSB device"); + throwLastError(errorState, "opening WinUSB device failed"); var interfaceHandle = dereference(interfaceHandleHolder); firstIntfHandle.deviceHandle = deviceHandle; @@ -162,21 +162,21 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna var intfHandle = getInterfaceHandle(interfaceNumber); if (intfHandle.interfaceHandle == null) - throwException("Interface %d has not been claimed", interfaceNumber); + throwException("interface %d has not been claimed", interfaceNumber); var intf = getInterface(interfaceNumber); // check alternate setting var altSetting = intf.getAlternate(alternateNumber); if (altSetting == null) - throwException("Interface %d does not have an alternate interface setting %d", interfaceNumber, + throwException("interface %d does not have an alternate interface setting %d", interfaceNumber, alternateNumber); try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); if (WinUSB2.WinUsb_SetCurrentAlternateSetting(intfHandle.interfaceHandle, (byte) alternateNumber, errorState) == 0) - throwLastError(errorState, "Failed to set alternate interface"); + throwLastError(errorState, "setting alternate interface failed"); } intf.setAlternate(altSetting); } @@ -186,7 +186,7 @@ public synchronized void releaseInterface(int interfaceNumber) { var intfHandle = getInterfaceHandle(interfaceNumber); if (intfHandle.interfaceHandle == null) - throwException("Interface %d has not been claimed", interfaceNumber); + throwException("interface %d has not been claimed", interfaceNumber); var firstIntfHandle = intfHandle; if (intfHandle.firstInterfaceNumber != interfaceNumber) @@ -322,7 +322,7 @@ synchronized void submitControlTransfer(USBDirection direction, USBControlTransf transfer.dataSize(), NULL, transfer.overlapped(), errorState) == 0) { var err = Win.getLastError(errorState); if (err != Kernel32.ERROR_IO_PENDING()) - throwException(err, "Submitting control transfer failed"); + throwException(err, "submitting control transfer failed"); } } } @@ -340,7 +340,7 @@ synchronized void submitTransferOut(int endpointNumber, WindowsTransfer transfer transfer.dataSize(), NULL, transfer.overlapped(), errorState) == 0) { var err = Win.getLastError(errorState); if (err != Kernel32.ERROR_IO_PENDING()) - throwException(err, "Submitting transfer OUT failed"); + throwException(err, "submitting transfer OUT failed"); } } } @@ -358,7 +358,7 @@ synchronized void submitTransferIn(int endpointNumber, WindowsTransfer transfer) transfer.dataSize(), NULL, transfer.overlapped(), errorState) == 0) { var err = Win.getLastError(errorState); if (err != Kernel32.ERROR_IO_PENDING()) - throwException(err, "Submitting transfer IN failed"); + throwException(err, "submitting transfer IN failed"); } } } @@ -373,12 +373,12 @@ synchronized void configureForAsyncIo(USBDirection direction, int endpointNumber var timeoutHolder = arena.allocate(JAVA_INT, 0); if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder, errorState) == 0) - throwLastError(errorState, "Setting timeout failed"); + throwLastError(errorState, "setting timeout failed"); var rawIoHolder = arena.allocate(JAVA_BYTE, (byte) 1); if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), WinUSB.RAW_IO(), (int) rawIoHolder.byteSize(), rawIoHolder, errorState) == 0) - throwLastError(errorState, "Setting raw IO failed"); + throwLastError(errorState, "setting raw IO failed"); } } @@ -390,7 +390,7 @@ public synchronized void clearHalt(USBDirection direction, int endpointNumber) { try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); if (WinUSB2.WinUsb_ResetPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), errorState) == 0) - throwLastError(errorState, "Clearing halt failed"); + throwLastError(errorState, "clearing halt failed"); } } @@ -402,7 +402,7 @@ public synchronized void abortTransfers(USBDirection direction, int endpointNumb try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); if (WinUSB2.WinUsb_AbortPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), errorState) == 0) - throwLastError(errorState, "Aborting transfers on endpoint failed"); + throwLastError(errorState, "aborting transfers on endpoint failed"); } } @@ -428,7 +428,7 @@ private InterfaceHandle getInterfaceHandle(int interfaceNumber) { return intfHandle; } - throwException("Invalid interface number: %s", interfaceNumber); + throwException("invalid interface number %s", interfaceNumber); throw new AssertionError("not reached"); } @@ -448,14 +448,14 @@ private InterfaceHandle findControlTransferInterface(USBControlTransfer setup) { if (endpointNumber != 0) { interfaceNumber = getInterfaceNumber(direction, endpointNumber); if (interfaceNumber == -1) - throwException("Invalid endpoint number %d or interface not claimed", endpointNumber); + throwException("invalid endpoint number %d or interface not claimed", endpointNumber); } } if (interfaceNumber >= 0) { var intfHandle = getInterfaceHandle(interfaceNumber); if (intfHandle.interfaceHandle == null) - throwException("Interface number %d has not been claimed", interfaceNumber); + throwException("interface number %d has not been claimed", interfaceNumber); return intfHandle; } @@ -465,7 +465,7 @@ private InterfaceHandle findControlTransferInterface(USBControlTransfer setup) { return intfHandle; } - throwException("Control transfer failed as no interface has been claimed"); + throwException("control transfer cannot be executed as no interface has been claimed"); throw new AssertionError("not reached"); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 8bc3f6f8..54563069 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -85,13 +85,13 @@ protected void monitorDevices() { tagWNDCLASSEXW.lpszClassName$set(wx, className); var atom = User32B.RegisterClassExW(wx, errorState); if (atom == 0) - throwLastError(errorState, "Internal error (RegisterClassExW)"); + throwLastError(errorState, "internal error (RegisterClassExW)"); // create message-only window hwnd = User32B.CreateWindowExW(0, className, windowName, 0, 0, 0, 0, 0, User32.HWND_MESSAGE(), NULL, instance, NULL, errorState); if (hwnd.address() == 0) - throwLastError(errorState, "Internal error (CreateWindowExW)"); + throwLastError(errorState, "internal error (CreateWindowExW)"); // configure notifications var notificationFilter = _DEV_BROADCAST_DEVICEINTERFACE_W.allocate(arena); @@ -103,7 +103,7 @@ protected void monitorDevices() { var notifyHandle = User32B.RegisterDeviceNotificationW(hwnd, notificationFilter, User32.DEVICE_NOTIFY_WINDOW_HANDLE(), errorState); if (notifyHandle.address() == 0) - throwLastError(errorState, "Internal error (RegisterDeviceNotificationW)"); + throwLastError(errorState, "internal error (RegisterDeviceNotificationW)"); // initial device enumeration enumeratePresentDevices(); @@ -121,7 +121,7 @@ protected void monitorDevices() { ; // do nothing if (err == -1) - throwLastError(errorState, "Internal error (GetMessageW)"); + throwLastError(errorState, "internal error (GetMessageW)"); } } @@ -137,7 +137,7 @@ private void enumeratePresentDevices() { var devInfoSet = SetupAPI2.SetupDiGetClassDevsW(USBConstants.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), errorState); if (Win.isInvalidHandle(devInfoSet)) - throwLastError(errorState, "Internal error (SetupDiGetClassDevsW)"); + throwLastError(errorState, "internal error (SetupDiGetClassDevsW)"); // ensure the result is destroyed when the scope is left outerCleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); @@ -157,7 +157,7 @@ private void enumeratePresentDevices() { var err = Win.getLastError(errorState); if (err == Kernel32.ERROR_NO_MORE_ITEMS()) break; - throwLastError(errorState, "Internal error (SetupDiEnumDeviceInfo)"); + throwLastError(errorState, "internal error (SetupDiEnumDeviceInfo)"); } var instanceId = DeviceProperty.getDeviceStringProperty(devInfoSet, devInfoData, @@ -168,8 +168,9 @@ private void enumeratePresentDevices() { deviceList.add(createDeviceFromDeviceInfo(devInfoSet, devInfoData, devicePath, hubHandles)); } catch (Exception e) { - System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring " - + "device%n", devicePath); + System.err.printf( + "Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring device%n", + devicePath); e.printStackTrace(System.err); } } @@ -198,7 +199,7 @@ private Map enumerateChildren(List childrenIds) { // create empty device info set var devInfoSet = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, errorState); if (Win.isInvalidHandle(devInfoSet)) - throwLastError(errorState, "Internal error (SetupDiCreateDeviceInfoList)"); + throwLastError(errorState, "internal error (SetupDiCreateDeviceInfoList)"); cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); // get device info for child @@ -207,13 +208,13 @@ private Map enumerateChildren(List childrenIds) { var instanceIdSegment = Win.createSegmentFromString(instanceId, arena); if (SetupAPI2.SetupDiOpenDeviceInfoW(devInfoSet, instanceIdSegment, NULL, 0, devInfoData, errorState) == 0) - throwLastError(errorState, "Internal error (SetupDiOpenDeviceInfoW)"); + throwLastError(errorState, "internal error (SetupDiOpenDeviceInfoW)"); // get hardware IDs (to extract interface number) var hardwareIds = DeviceProperty.getDeviceStringListProperty(devInfoSet, devInfoData, DeviceProperty.DEVPKEY_Device_HardwareIds); if (hardwareIds == null) - throwException("DEVPKEY_Device_HardwareIds not found"); + throwException("internal error (device property 'HardwareIds' is missing)"); var interfaceNumber = extractInterfaceNumber(hardwareIds); if (interfaceNumber == -1) continue; @@ -247,7 +248,7 @@ private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSet, MemorySeg hubHandle = Kernel32B.CreateFileW(hubPathSeg, Kernel32.GENERIC_WRITE(), Kernel32.FILE_SHARE_WRITE(), NULL, Kernel32.OPEN_EXISTING(), 0, NULL, errorState); if (Win.isInvalidHandle(hubHandle)) - throwLastError(errorState, "Cannot open USB hub"); + throwLastError(errorState, "internal error (opening hub device)"); hubHandles.put(hubPath, hubHandle); } @@ -284,7 +285,9 @@ private Map getChildDevices(MemorySegment devInfoSet, MemorySeg } if (childrenInstanceIDs == null) { - System.err.printf("Info: [JavaDoesUSB] cannot get device children of device %s%n", devicePath); + System.err.printf( + "Info: [JavaDoesUSB] unable to retrieve information about children of device %s - ignoring%n", + devicePath); return null; } @@ -313,7 +316,7 @@ private USBDevice createDevice(String devicePath, Map children, if (Kernel32B.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), connInfo, (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL, errorState) == 0) - throwLastError(errorState, "Internal error (cannot get device descriptor)"); + throwLastError(errorState, "internal error (getting device descriptor failed)"); var descriptorSegment = _USB_NODE_CONNECTION_INFORMATION_EX.DeviceDescriptor$slice(connInfo); var deviceDescriptor = new DeviceDescriptor(descriptorSegment); @@ -356,7 +359,7 @@ private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, var errorState = allocateErrorState(arena); if (Kernel32B.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION(), descriptorRequest, size, descriptorRequest, size, effectiveSizeHolder, NULL, errorState) == 0) - throwLastError(errorState, "Cannot retrieve descriptor %d", index); + throwLastError(errorState, "internal error (retrieving descriptor %d failed)", index); // determine size of descriptor int expectedSize; @@ -372,7 +375,7 @@ private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, var effectiveSize = effectiveSizeHolder.get(JAVA_INT, 0) - REQUEST_DATA_OFFSET; if (effectiveSize != expectedSize) { if (requestSize != 0) - throwException("Unexpected descriptor size"); + throwException("internal error (unexpected descriptor size)"); // repeat with correct size return getDescriptor(hubHandle, usbPortNumber, descriptorType, index, languageID, expectedSize, arena); @@ -429,7 +432,7 @@ private void onDeviceConnected(String devicePath) { // create empty device info set var devInfoSet = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, errorState); if (Win.isInvalidHandle(devInfoSet)) - throwLastError(errorState, "Internal error (SetupDiCreateDeviceInfoList)"); + throwLastError(errorState, "internal error (SetupDiCreateDeviceInfoList)"); cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); @@ -438,7 +441,7 @@ private void onDeviceConnected(String devicePath) { _SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); var devicePathSegment = Win.createSegmentFromString(devicePath, arena); if (SetupAPI2.SetupDiOpenDeviceInterfaceW(devInfoSet, devicePathSegment, 0, devIntfData, errorState) == 0) - throwLastError(errorState, "Internal error (SetupDiOpenDeviceInterfaceW)"); + throwLastError(errorState, "internal error (SetupDiOpenDeviceInterfaceW)"); cleanup.add(() -> SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSet, devIntfData)); @@ -448,7 +451,7 @@ private void onDeviceConnected(String devicePath) { errorState) == 0) { var err = Win.getLastError(errorState); if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) - throwException(err, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); + throwException(err, "internal error (SetupDiGetDeviceInterfaceDetailW)"); } // ensure all hubs are closed later @@ -463,8 +466,9 @@ private void onDeviceConnected(String devicePath) { addDevice(device); } catch (Exception e) { - System.err.printf("Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring " + - "device%n", devicePath); + System.err.printf( + "Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring device%n", + devicePath); e.printStackTrace(System.err); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java index 2011aac9..7b93a575 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java @@ -33,7 +33,7 @@ public class WindowsUSBException extends USBException { * @param errorCode Windows error code (usually returned from {@code GetLastError()}) */ public WindowsUSBException(String message, int errorCode) { - super(String.format("%s. %s", message, getErrorMessage(errorCode)), errorCode); + super(String.format("%s: %s", message, getErrorMessage(errorCode)), errorCode); } /** From 7279d985fd0a216f6b5f2539f050384b5721decd Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 6 Aug 2023 15:25:07 +0200 Subject: [PATCH 277/433] Windows: introduce device info set --- .../codecrete/usb/windows/DeviceInfoSet.java | 358 ++++++++++++++++++ .../codecrete/usb/windows/DeviceProperty.java | 245 +----------- .../usb/windows/WindowsUSBDeviceRegistry.java | 120 ++---- 3 files changed, 388 insertions(+), 335 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java new file mode 100644 index 00000000..343e33b0 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java @@ -0,0 +1,358 @@ +package net.codecrete.usb.windows; + +import net.codecrete.usb.common.ScopeCleanup; +import net.codecrete.usb.windows.gen.advapi32.Advapi32; +import net.codecrete.usb.windows.gen.kernel32.Kernel32; +import net.codecrete.usb.windows.gen.kernel32._GUID; +import net.codecrete.usb.windows.gen.ole32.Ole32; +import net.codecrete.usb.windows.gen.setupapi.SetupAPI; +import net.codecrete.usb.windows.gen.setupapi._SP_DEVICE_INTERFACE_DATA; +import net.codecrete.usb.windows.gen.setupapi._SP_DEVICE_INTERFACE_DETAIL_DATA_W; +import net.codecrete.usb.windows.gen.setupapi._SP_DEVINFO_DATA; +import net.codecrete.usb.windows.winsdk.SetupAPI2; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.util.List; + +import static java.lang.foreign.MemorySegment.NULL; +import static java.lang.foreign.ValueLayout.JAVA_CHAR; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static net.codecrete.usb.windows.DeviceProperty.DEVPKEY_Device_Service; +import static net.codecrete.usb.windows.Win.allocateErrorState; +import static net.codecrete.usb.windows.WindowsUSBException.throwException; +import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; + +/** + * Device information set (of Windows Setup API). + * + *

+ * An instance of this class represents a device information set ({@code HDEVINFO}) + * and a current element within the set. + *

+ */ +public class DeviceInfoSet implements AutoCloseable { + + @FunctionalInterface + interface InfoSetCreator { + MemorySegment create(Arena arena, MemorySegment errorState); + } + + private final Arena arena; + private final MemorySegment errorState; + private final MemorySegment devInfoSet; + private final MemorySegment devInfoData; + private MemorySegment devIntfData; + private int iterationIndex = -1; + + /** + * Creates a new empty device info set. + * + * @return device info set + */ + static DeviceInfoSet ofEmpty() { + return new DeviceInfoSet((arena, errorState) -> SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, errorState)); + } + + /** + * Creates a new device info set containing the present devices of the specified device class and + * optionally device instance ID. + * + *

+ * After creation, there is no current element. {@link #next()} must be called first. + *

+ * + * @param interfaceGuid device interface class GUID + * @param instanceId device instance ID + * @return device info set + */ + static DeviceInfoSet ofPresentDevices(MemorySegment interfaceGuid, String instanceId) { + return new DeviceInfoSet((arena, errorState) -> { + var instanceIdSegment = instanceId != null ? Win.createSegmentFromString(instanceId, arena) : NULL; + return SetupAPI2.SetupDiGetClassDevsW(interfaceGuid, instanceIdSegment, NULL, + SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), errorState); + }); + } + + private DeviceInfoSet(InfoSetCreator creator) { + arena = Arena.ofConfined(); + try { + errorState = allocateErrorState(arena); + + devInfoSet = creator.create(arena, errorState); + if (Win.isInvalidHandle(devInfoSet)) + throwLastError(errorState, "internal error (creating device info set)"); + + // allocate SP_DEVINFO_DATA (will receive device details) + devInfoData = _SP_DEVINFO_DATA.allocate(arena); + _SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) _SP_DEVINFO_DATA.$LAYOUT().byteSize()); + + } catch (Exception e) { + arena.close(); + throw e; + } + } + + @Override + public void close() { + if (devIntfData != null) + SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSet, devIntfData); + SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet); + arena.close(); + } + + /** + * Iterates to the next element in this set. + * + * @return {@code true} if there is a current element, {@code false} if the iteration moved beyond the last element + */ + boolean next() { + iterationIndex += 1; + if (SetupAPI2.SetupDiEnumDeviceInfo(devInfoSet, iterationIndex, devInfoData, errorState) == 0) { + var err = Win.getLastError(errorState); + if (err == Kernel32.ERROR_NO_MORE_ITEMS()) + return false; + throwLastError(errorState, "internal error (SetupDiEnumDeviceInfo)"); + } + + return true; + } + + /** + * Adds the device with the specified instance ID to this device info set. + * + *

+ * The added device becomes the current element. + *

+ * + * @param instanceId instance ID + */ + void addInstance(String instanceId) { + var instanceIdSegment = Win.createSegmentFromString(instanceId, arena); + if (SetupAPI2.SetupDiOpenDeviceInfoW(devInfoSet, instanceIdSegment, NULL, 0, devInfoData, errorState) == 0) + throwLastError(errorState, "internal error (SetupDiOpenDeviceInfoW)"); + } + + /** + * Adds the device with the specified path to this device info set. + * + *

+ * The added device becomes the current element. + *

+ * + * @param devicePath device path + */ + void addDevice(String devicePath) { + if (devIntfData != null) + throw new AssertionError("calling addDevice() multiple times is not implemented"); + + // load device information into dev info set + var intfData = _SP_DEVICE_INTERFACE_DATA.allocate(arena); + _SP_DEVICE_INTERFACE_DATA.cbSize$set(intfData, (int) intfData.byteSize()); + var devicePathSegment = Win.createSegmentFromString(devicePath, arena); + if (SetupAPI2.SetupDiOpenDeviceInterfaceW(devInfoSet, devicePathSegment, 0, intfData, errorState) == 0) + throwLastError(errorState, "internal error (SetupDiOpenDeviceInterfaceW)"); + + devIntfData = intfData; // for later cleanup + + if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSet, intfData, NULL, 0, NULL, + devInfoData, errorState) == 0) { + var err = Win.getLastError(errorState); + if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) + throwException(err, "internal error (SetupDiGetDeviceInterfaceDetailW)"); + } + } + + + /** + * Checks if the current element is a composite USB device + * + * @return {@code true} if it is a composite device + */ + boolean isCompositeDevice() { + var deviceService = getStringProperty(DEVPKEY_Device_Service); + + // usbccgp is the USB Generic Parent Driver used for composite devices + return "usbccgp".equalsIgnoreCase(deviceService); + } + + /** + * Gets the device path for the device with the given instance ID. + *

+ * The device path is looked up by checking the GUIDs associated with the current element. + *

+ * + * @param instanceId device instance ID + * @return the device path, {@code null} if not found + */ + String getDevicePathByGUID(String instanceId) { + var guids = findDeviceInterfaceGUIDs(arena); + + for (var guid : guids) { + // check for class GUID + var guidSegment = Win.createSegmentFromString(guid, arena); + var clsid = _GUID.allocate(arena); + if (Ole32.CLSIDFromString(guidSegment, clsid) != 0) + continue; + + try { + return getDevicePath(instanceId, clsid); + } catch (Exception e) { + // ignore and try next one + } + } + + return null; + } + + /** + * Gets a list of {@code DeviceInterfaceGUIDs} from the current element's device configuration information + * in the registry. + * + * @param arena arena for allocating memory + * @return list of GUIDs + */ + private List findDeviceInterfaceGUIDs(Arena arena) { + + try (var cleanup = new ScopeCleanup()) { + // open device registry key + var regKey = SetupAPI2.SetupDiOpenDevRegKey(devInfoSet, devInfoData, SetupAPI.DICS_FLAG_GLOBAL(), 0, + SetupAPI.DIREG_DEV(), Advapi32.KEY_READ(), errorState); + if (Win.isInvalidHandle(regKey)) + throwLastError(errorState, "internal error (SetupDiOpenDevRegKey)"); + cleanup.add(() -> Advapi32.RegCloseKey(regKey)); + + // read registry value (without buffer, to query length) + var keyNameSegment = Win.createSegmentFromString("DeviceInterfaceGUIDs", arena); + var valueTypeHolder = arena.allocate(JAVA_INT); + var valueSizeHolder = arena.allocate(JAVA_INT); + var res = Advapi32.RegQueryValueExW(regKey, keyNameSegment, NULL, valueTypeHolder, NULL, valueSizeHolder); + if (res == Kernel32.ERROR_FILE_NOT_FOUND()) + return List.of(); // no device interface GUIDs + if (res != 0 && res != Kernel32.ERROR_MORE_DATA()) + throwException(res, "internal error (RegQueryValueExW)"); + + // read registry value (with buffer) + var valueSize = valueSizeHolder.get(JAVA_INT, 0); + var value = arena.allocate(valueSize); + res = Advapi32.RegQueryValueExW(regKey, keyNameSegment, NULL, valueTypeHolder, value, valueSizeHolder); + if (res != 0) + throwException(res, "internal error (RegQueryValueExW)"); + + return Win.createStringListFromSegment(value); + } + } + + /** + * Gets the integer device property of the current element. + * + * @param propertyKey property key (of type {@code DEVPKEY}) + * @return property value + */ + @SuppressWarnings("SameParameterValue") + int getIntProperty(MemorySegment propertyKey) { + var propertyTypeHolder = arena.allocate(JAVA_INT); + var propertyValueHolder = arena.allocate(JAVA_INT); + if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, + propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, errorState) == 0) + throwLastError(errorState, "internal error (SetupDiGetDevicePropertyW - A)"); + + if (propertyTypeHolder.get(JAVA_INT, 0) != SetupAPI.DEVPROP_TYPE_UINT32()) + throwException("internal error (expected property type UINT32)"); + + return propertyValueHolder.get(JAVA_INT, 0); + } + + /** + * Gets the string device property of the current element. + * + * @param propertyKey property key (of type {@code DEVPKEY}) + * @return property value + */ + String getStringProperty(MemorySegment propertyKey) { + var propertyValue = getVariableLengthProperty(propertyKey, SetupAPI.DEVPROP_TYPE_STRING(), arena); + if (propertyValue == null) + return null; + return Win.createStringFromSegment(propertyValue); + } + + /** + * Gets the string list device property of the current element. + * + * @param propertyKey property key (of type {@code DEVPKEY}) + * @return property value + */ + @SuppressWarnings("java:S1168") + List getStringListProperty(MemorySegment propertyKey) { + var propertyValue = getVariableLengthProperty(propertyKey, + SetupAPI.DEVPROP_TYPE_STRING() | SetupAPI.DEVPROP_TYPEMOD_LIST(), arena); + if (propertyValue == null) + return null; + + return Win.createStringListFromSegment(propertyValue); + } + + private MemorySegment getVariableLengthProperty(MemorySegment propertyKey, int propertyType, Arena arena) { + + // query length (thus no buffer) + var propertyTypeHolder = arena.allocate(JAVA_INT); + var requiredSizeHolder = arena.allocate(JAVA_INT); + if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, NULL, 0, + requiredSizeHolder, 0, errorState) == 0) { + var err = Win.getLastError(errorState); + if (err == Kernel32.ERROR_NOT_FOUND()) + return null; + if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) + throwException(err, "internal error (SetupDiGetDevicePropertyW - B)"); + } + + if (propertyTypeHolder.get(JAVA_INT, 0) != propertyType) + throwException("internal error (unexpected property type)"); + + var stringLen = requiredSizeHolder.get(JAVA_INT, 0) / 2 - 1; + + // allocate buffer + var propertyValueHolder = arena.allocateArray(JAVA_CHAR, stringLen + 1L); + + // get property value + if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, + propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, errorState) == 0) + throwLastError(errorState, "internal error (SetupDiGetDevicePropertyW - C)"); + + return propertyValueHolder; + } + + /** + * Gets the device path for the device with the given device instance ID and device interface class. + * + * @param instanceId device instance ID + * @param interfaceGuid device interface class GUID + * @return the device path + */ + static String getDevicePath(String instanceId, MemorySegment interfaceGuid) { + try (var arena = Arena.ofConfined(); + var deviceInfoSet = DeviceInfoSet.ofPresentDevices(interfaceGuid, instanceId)) { + + // retrieve first element of enumeration + var errorState = allocateErrorState(arena); + var devIntfData = _SP_DEVICE_INTERFACE_DATA.allocate(arena); + _SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); + if (SetupAPI2.SetupDiEnumDeviceInterfaces(deviceInfoSet.devInfoSet, NULL, interfaceGuid, 0, devIntfData, + errorState) == 0) + throwLastError(errorState, "internal error (SetupDiEnumDeviceInterfaces)"); + + // get device path + // (SP_DEVICE_INTERFACE_DETAIL_DATA_W is of variable length and requires a bigger allocation so + // the device path fits) + final var devicePathOffset = 4; + var intfDetailData = arena.allocate(4L + 260 * 2); + _SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$set(intfDetailData, + (int) _SP_DEVICE_INTERFACE_DETAIL_DATA_W.sizeof()); + if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(deviceInfoSet.devInfoSet, devIntfData, intfDetailData, + (int) intfDetailData.byteSize(), NULL, NULL, errorState) == 0) + throwLastError(errorState, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); + + return Win.createStringFromSegment(intfDetailData.asSlice(devicePathOffset)); + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java index 0acecf5b..c382465e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java @@ -7,27 +7,13 @@ package net.codecrete.usb.windows; -import net.codecrete.usb.common.ScopeCleanup; -import net.codecrete.usb.windows.gen.advapi32.Advapi32; -import net.codecrete.usb.windows.gen.kernel32.Kernel32; -import net.codecrete.usb.windows.gen.kernel32._GUID; -import net.codecrete.usb.windows.gen.ole32.Ole32; import net.codecrete.usb.windows.gen.setupapi.*; -import net.codecrete.usb.windows.winsdk.SetupAPI2; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.util.List; - -import static java.lang.foreign.MemorySegment.NULL; -import static java.lang.foreign.ValueLayout.JAVA_CHAR; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static net.codecrete.usb.windows.Win.allocateErrorState; -import static net.codecrete.usb.windows.WindowsUSBException.throwException; -import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; /** - * Device property GUIDs and functions + * Device property GUIDs */ class DeviceProperty { @@ -58,235 +44,6 @@ private DeviceProperty() { (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50 , (byte) 0xe0, 3); - /** - * Gets the device property with integer type. - * - * @param devInfoSet device information set containing the device ({@code HDEVINFO}) - * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set - * @param propertyKey property key (of type {@code DEVPKEY}) - * @return property value - */ - @SuppressWarnings("SameParameterValue") - static int getDeviceIntProperty(MemorySegment devInfoSet, MemorySegment devInfoData, - MemorySegment propertyKey) { - try (var arena = Arena.ofConfined()) { - var propertyTypeHolder = arena.allocate(JAVA_INT); - var propertyValueHolder = arena.allocate(JAVA_INT); - var errorState = allocateErrorState(arena); - if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, - propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, errorState) == 0) - throwLastError(errorState, "internal error (SetupDiGetDevicePropertyW - A)"); - - if (propertyTypeHolder.get(JAVA_INT, 0) != SetupAPI.DEVPROP_TYPE_UINT32()) - throwException("internal error (expected property type UINT32)"); - - return propertyValueHolder.get(JAVA_INT, 0); - } - } - - /** - * Gets the device property with string type. - * - * @param devInfoSet device information set containing the device ({@code HDEVINFO}) - * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set - * @param propertyKey property key (of type {@code DEVPKEY}) - * @return property value - */ - static String getDeviceStringProperty(MemorySegment devInfoSet, MemorySegment devInfoData, - MemorySegment propertyKey) { - try (var arena = Arena.ofConfined()) { - var propertyValue = getVariableLengthProperty(devInfoSet, devInfoData, propertyKey, - SetupAPI.DEVPROP_TYPE_STRING(), arena); - if (propertyValue == null) - return null; - return Win.createStringFromSegment(propertyValue); - } - } - - /** - * Gets the device property with string list type. - * - * @param devInfoSet device information set containing the device ({@code HDEVINFO}) - * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set - * @param propertyKey property key (of type {@code DEVPKEY}) - * @return property value - */ - @SuppressWarnings("java:S1168") - static List getDeviceStringListProperty(MemorySegment devInfoSet, MemorySegment devInfoData, - MemorySegment propertyKey) { - try (var arena = Arena.ofConfined()) { - var propertyValue = getVariableLengthProperty(devInfoSet, devInfoData, propertyKey, - SetupAPI.DEVPROP_TYPE_STRING() | SetupAPI.DEVPROP_TYPEMOD_LIST(), arena); - if (propertyValue == null) - return null; - - return Win.createStringListFromSegment(propertyValue); - } - } - - private static MemorySegment getVariableLengthProperty(MemorySegment devInfoSet, MemorySegment devInfoData, - MemorySegment propertyKey, int propertyType, Arena arena) { - - // query length (thus no buffer) - var propertyTypeHolder = arena.allocate(JAVA_INT); - var requiredSizeHolder = arena.allocate(JAVA_INT); - var errorState = allocateErrorState(arena); - if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, NULL, 0, - requiredSizeHolder, 0, errorState) == 0) { - var err = Win.getLastError(errorState); - if (err == Kernel32.ERROR_NOT_FOUND()) - return null; - if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) - throwException(err, "internal error (SetupDiGetDevicePropertyW - B)"); - } - - if (propertyTypeHolder.get(JAVA_INT, 0) != propertyType) - throwException("internal error (unexpected property type)"); - - var stringLen = requiredSizeHolder.get(JAVA_INT, 0) / 2 - 1; - - // allocate buffer - var propertyValueHolder = arena.allocateArray(JAVA_CHAR, stringLen + 1L); - - // get property value - if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, - propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, errorState) == 0) - throwLastError(errorState, "internal error (SetupDiGetDevicePropertyW - C)"); - - return propertyValueHolder; - } - - /** - * Gets a list of {@code DeviceInterfaceGUIDs} from device-specific configuration information in the registry. - * - * @param devInfoSet device information set containing the device ({@code HDEVINFO}) - * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set - * @param arena arena for allocating memory - * @return list of GUIDs - */ - static List findDeviceInterfaceGUIDs(MemorySegment devInfoSet, MemorySegment devInfoData, - Arena arena) { - - try (var cleanup = new ScopeCleanup()) { - var errorState = allocateErrorState(arena); - - // open device registry key - var regKey = SetupAPI2.SetupDiOpenDevRegKey(devInfoSet, devInfoData, SetupAPI.DICS_FLAG_GLOBAL(), 0, - SetupAPI.DIREG_DEV(), Advapi32.KEY_READ(), errorState); - if (Win.isInvalidHandle(regKey)) - throwLastError(errorState, "internal error (SetupDiOpenDevRegKey)"); - cleanup.add(() -> Advapi32.RegCloseKey(regKey)); - - // read registry value (without buffer, to query length) - var keyNameSegment = Win.createSegmentFromString("DeviceInterfaceGUIDs", arena); - var valueTypeHolder = arena.allocate(JAVA_INT); - var valueSizeHolder = arena.allocate(JAVA_INT); - var res = Advapi32.RegQueryValueExW(regKey, keyNameSegment, NULL, valueTypeHolder, NULL, valueSizeHolder); - if (res == Kernel32.ERROR_FILE_NOT_FOUND()) - return List.of(); // no device interface GUIDs - if (res != 0 && res != Kernel32.ERROR_MORE_DATA()) - throwException(res, "internal error (RegQueryValueExW)"); - - // read registry value (with buffer) - var valueSize = valueSizeHolder.get(JAVA_INT, 0); - var value = arena.allocate(valueSize); - res = Advapi32.RegQueryValueExW(regKey, keyNameSegment, NULL, valueTypeHolder, value, valueSizeHolder); - if (res != 0) - throwException(res, "internal error (RegQueryValueExW)"); - - return Win.createStringListFromSegment(value); - } - } - - /** - * Gets the device path for the device with the given device instance ID and device interface class. - * - * @param instanceId device instance ID - * @param interfaceGuid device interface class GUID - * @return the device path - */ - static String getDevicePath(String instanceId, MemorySegment interfaceGuid) { - try (var arena = Arena.ofConfined(); var cleanup = new ScopeCleanup()) { - var errorState = allocateErrorState(arena); - - // get device info set for instance - var instanceIDSegment = Win.createSegmentFromString(instanceId, arena); - final var devInfoSet = SetupAPI2.SetupDiGetClassDevsW(interfaceGuid, instanceIDSegment, NULL, - SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), errorState); - if (Win.isInvalidHandle(devInfoSet)) - throwLastError(errorState, "internal error (SetupDiGetClassDevsW)"); - - // ensure the result is destroyed when the scope is left - cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); - - // retrieve first element of enumeration - var devIntfData = _SP_DEVICE_INTERFACE_DATA.allocate(arena); - _SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); - if (SetupAPI2.SetupDiEnumDeviceInterfaces(devInfoSet, NULL, interfaceGuid, 0, devIntfData, - errorState) == 0) - throwLastError(errorState, "internal error (SetupDiEnumDeviceInterfaces)"); - - // get device path - // (SP_DEVICE_INTERFACE_DETAIL_DATA_W is of variable length and requires a bigger allocation so - // the device path fits) - final var devicePathOffset = 4; - var intfDetailData = arena.allocate(4L + 260 * 2); - _SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$set(intfDetailData, - (int) _SP_DEVICE_INTERFACE_DETAIL_DATA_W.sizeof()); - var intfDetailDataSize = (int) intfDetailData.byteSize(); - if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSet, devIntfData, intfDetailData, - intfDetailDataSize, NULL, NULL, errorState) == 0) - throwLastError(errorState, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); - - return Win.createStringFromSegment(intfDetailData.asSlice(devicePathOffset)); - } - } - - /** - * Gets the device path for the device from the given device info set and the given instance ID. - *

- * The device path is looked up by checking the associated GUIDs. - *

- * - * @param devInfoSet device information set containing the device ({@code HDEVINFO}) - * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set - * @param instanceId device instance ID - * @param arena arena for allocating memory - * @return the device path, {code null} if not found - */ - static String getDevicePathByGUID(MemorySegment devInfoSet, MemorySegment devInfoData, String instanceId, Arena arena) { - var guids = DeviceProperty.findDeviceInterfaceGUIDs(devInfoSet, devInfoData, arena); - - for (var guid : guids) { - // check for class GUID - var guidSegment = Win.createSegmentFromString(guid, arena); - var clsid = _GUID.allocate(arena); - if (Ole32.CLSIDFromString(guidSegment, clsid) != 0) - continue; - - try { - return DeviceProperty.getDevicePath(instanceId, clsid); - } catch (Exception e) { - // ignore and try next one - } - } - - return null; - } - - /** - * Checks if the device is a composite USB device - * - * @param devInfoSet device information set containing the device ({@code HDEVINFO}) - * @param devInfoData {@code SP_DEVINFO_DATA} structure specifying the element (device) in the information set - * @return {@code true} if it is a composite device - */ - static boolean isCompositeDevice(MemorySegment devInfoSet, MemorySegment devInfoData) { - var deviceService = getDeviceStringProperty(devInfoSet, devInfoData, DEVPKEY_Device_Service); - - // usbccgp is the USB Generic Parent Driver used for composite devices - return "usbccgp".equalsIgnoreCase(deviceService); - } @SuppressWarnings({"java:S107", "java:S117"}) private static MemorySegment createDEVPROPKEY(int data1, short data2, short data3, byte data4_0, byte data4_1, diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 54563069..9baf5722 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -17,13 +17,11 @@ import net.codecrete.usb.usbstandard.SetupPacket; import net.codecrete.usb.usbstandard.StringDescriptor; import net.codecrete.usb.windows.gen.kernel32.Kernel32; -import net.codecrete.usb.windows.gen.setupapi.*; import net.codecrete.usb.windows.gen.usbioctl.USBIoctl; import net.codecrete.usb.windows.gen.usbioctl._USB_DESCRIPTOR_REQUEST; import net.codecrete.usb.windows.gen.usbioctl._USB_NODE_CONNECTION_INFORMATION_EX; import net.codecrete.usb.windows.gen.user32.*; import net.codecrete.usb.windows.winsdk.Kernel32B; -import net.codecrete.usb.windows.winsdk.SetupAPI2; import net.codecrete.usb.windows.winsdk.User32B; import java.lang.foreign.Arena; @@ -41,6 +39,11 @@ import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.usbstandard.Constants.*; +import static net.codecrete.usb.windows.DeviceProperty.DEVPKEY_Device_Address; +import static net.codecrete.usb.windows.DeviceProperty.DEVPKEY_Device_Children; +import static net.codecrete.usb.windows.DeviceProperty.DEVPKEY_Device_HardwareIds; +import static net.codecrete.usb.windows.DeviceProperty.DEVPKEY_Device_InstanceId; +import static net.codecrete.usb.windows.DeviceProperty.DEVPKEY_Device_Parent; import static net.codecrete.usb.windows.Win.allocateErrorState; import static net.codecrete.usb.windows.WindowsUSBException.throwException; import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; @@ -129,43 +132,21 @@ protected void monitorDevices() { private void enumeratePresentDevices() { List deviceList = new ArrayList<>(); - try (var outerArena = Arena.ofConfined(); var outerCleanup = new ScopeCleanup()) { - - var errorState = allocateErrorState(outerArena); - - // get device information set of all USB devices present - var devInfoSet = SetupAPI2.SetupDiGetClassDevsW(USBConstants.GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, - SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), errorState); - if (Win.isInvalidHandle(devInfoSet)) - throwLastError(errorState, "internal error (SetupDiGetClassDevsW)"); - - // ensure the result is destroyed when the scope is left - outerCleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); - - // allocate SP_DEVINFO_DATA (will receive details for each device) - var devInfoData = _SP_DEVINFO_DATA.allocate(outerArena); - _SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) _SP_DEVINFO_DATA.$LAYOUT().byteSize()); + try (var cleanup = new ScopeCleanup(); + var deviceInfoSet = DeviceInfoSet.ofPresentDevices(USBConstants.GUID_DEVINTERFACE_USB_DEVICE, null)) { // ensure all hubs are closed later final var hubHandles = new HashMap(); - outerCleanup.add(() -> hubHandles.forEach((path, handle) -> Kernel32.CloseHandle(handle))); + cleanup.add(() -> hubHandles.forEach((path, handle) -> Kernel32.CloseHandle(handle))); // iterate all devices - for (var i = 0; true; i++) { - - if (SetupAPI2.SetupDiEnumDeviceInfo(devInfoSet, i, devInfoData, errorState) == 0) { - var err = Win.getLastError(errorState); - if (err == Kernel32.ERROR_NO_MORE_ITEMS()) - break; - throwLastError(errorState, "internal error (SetupDiEnumDeviceInfo)"); - } + while (deviceInfoSet.next()) { - var instanceId = DeviceProperty.getDeviceStringProperty(devInfoSet, devInfoData, - DeviceProperty.DEVPKEY_Device_InstanceId); - var devicePath = DeviceProperty.getDevicePath(instanceId, USBConstants.GUID_DEVINTERFACE_USB_DEVICE); + var instanceId = deviceInfoSet.getStringProperty(DEVPKEY_Device_InstanceId); + var devicePath = DeviceInfoSet.getDevicePath(instanceId, USBConstants.GUID_DEVINTERFACE_USB_DEVICE); try { - deviceList.add(createDeviceFromDeviceInfo(devInfoSet, devInfoData, devicePath, hubHandles)); + deviceList.add(createDeviceFromDeviceInfo(deviceInfoSet, devicePath, hubHandles)); } catch (Exception e) { System.err.printf( @@ -191,38 +172,22 @@ private Map enumerateChildren(List childrenIds) { // iterate all children for (var instanceId : childrenIds) { - try (var arena = Arena.ofConfined(); var cleanup = new ScopeCleanup()) { - - //noinspection DuplicatedCode - var errorState = allocateErrorState(arena); - - // create empty device info set - var devInfoSet = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, errorState); - if (Win.isInvalidHandle(devInfoSet)) - throwLastError(errorState, "internal error (SetupDiCreateDeviceInfoList)"); - cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); + try (var deviceInfoSet = DeviceInfoSet.ofEmpty()) { // get device info for child - var devInfoData = _SP_DEVINFO_DATA.allocate(arena); - _SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) devInfoData.byteSize()); - var instanceIdSegment = Win.createSegmentFromString(instanceId, arena); - if (SetupAPI2.SetupDiOpenDeviceInfoW(devInfoSet, instanceIdSegment, NULL, 0, devInfoData, - errorState) == 0) - throwLastError(errorState, "internal error (SetupDiOpenDeviceInfoW)"); + deviceInfoSet.addInstance(instanceId); // get hardware IDs (to extract interface number) - var hardwareIds = DeviceProperty.getDeviceStringListProperty(devInfoSet, devInfoData, - DeviceProperty.DEVPKEY_Device_HardwareIds); + var hardwareIds = deviceInfoSet.getStringListProperty(DEVPKEY_Device_HardwareIds); if (hardwareIds == null) throwException("internal error (device property 'HardwareIds' is missing)"); var interfaceNumber = extractInterfaceNumber(hardwareIds); if (interfaceNumber == -1) continue; - var devicePath = DeviceProperty.getDevicePathByGUID(devInfoSet, devInfoData, instanceId, arena); + var devicePath = deviceInfoSet.getDevicePathByGUID(instanceId); if (devicePath != null) children.put(interfaceNumber, devicePath); - } } @@ -230,15 +195,13 @@ private Map enumerateChildren(List childrenIds) { } - private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSet, MemorySegment devInfoData, - String devicePath, HashMap hubHandles) { + private USBDevice createDeviceFromDeviceInfo(DeviceInfoSet deviceInfoSet, String devicePath, + HashMap hubHandles) { try (var arena = Arena.ofConfined()) { - var usbPortNum = DeviceProperty.getDeviceIntProperty(devInfoSet, devInfoData, - DeviceProperty.DEVPKEY_Device_Address); - var parentInstanceId = DeviceProperty.getDeviceStringProperty(devInfoSet, devInfoData, - DeviceProperty.DEVPKEY_Device_Parent); - var hubPath = DeviceProperty.getDevicePath(parentInstanceId, USBConstants.GUID_DEVINTERFACE_USB_HUB); + var usbPortNum = deviceInfoSet.getIntProperty(DEVPKEY_Device_Address); + var parentInstanceId = deviceInfoSet.getStringProperty(DEVPKEY_Device_Parent); + var hubPath = DeviceInfoSet.getDevicePath(parentInstanceId, USBConstants.GUID_DEVINTERFACE_USB_HUB); // open hub if not open yet var hubHandle = hubHandles.get(hubPath); @@ -253,15 +216,15 @@ private USBDevice createDeviceFromDeviceInfo(MemorySegment devInfoSet, MemorySeg } // check for composite device - var children = getChildDevices(devInfoSet, devInfoData, devicePath); + var children = getChildDevices(deviceInfoSet, devicePath); return createDevice(devicePath, children, hubHandle, usbPortNum); } } @SuppressWarnings({"java:S106", "java:S1168"}) - private Map getChildDevices(MemorySegment devInfoSet, MemorySegment devInfoData, String devicePath) { - if (!DeviceProperty.isCompositeDevice(devInfoSet, devInfoData)) + private Map getChildDevices(DeviceInfoSet deviceInfoSet, String devicePath) { + if (!deviceInfoSet.isCompositeDevice()) return null; // For certain devices, it seems to take some time until the "Device_Children" @@ -270,8 +233,7 @@ private Map getChildDevices(MemorySegment devInfoSet, MemorySeg var numTries = 5; while (true) { numTries -= 1; - childrenInstanceIDs = DeviceProperty.getDeviceStringListProperty(devInfoSet, devInfoData, - DeviceProperty.DEVPKEY_Device_Children); + childrenInstanceIDs = deviceInfoSet.getStringListProperty(DEVPKEY_Device_Children); if (childrenInstanceIDs != null || numTries == 0) break; @@ -425,34 +387,10 @@ private long handleWindowMessage(MemorySegment hWnd, int uMsg, long wParam, long @SuppressWarnings("java:S106") private void onDeviceConnected(String devicePath) { - try (var arena = Arena.ofConfined(); var cleanup = new ScopeCleanup()) { + try (var cleanup = new ScopeCleanup(); + var deviceInfoSet = DeviceInfoSet.ofEmpty()) { - var errorState = allocateErrorState(arena); - - // create empty device info set - var devInfoSet = SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, errorState); - if (Win.isInvalidHandle(devInfoSet)) - throwLastError(errorState, "internal error (SetupDiCreateDeviceInfoList)"); - - cleanup.add(() -> SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet)); - - // load device information into dev info set - var devIntfData = _SP_DEVICE_INTERFACE_DATA.allocate(arena); - _SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); - var devicePathSegment = Win.createSegmentFromString(devicePath, arena); - if (SetupAPI2.SetupDiOpenDeviceInterfaceW(devInfoSet, devicePathSegment, 0, devIntfData, errorState) == 0) - throwLastError(errorState, "internal error (SetupDiOpenDeviceInterfaceW)"); - - cleanup.add(() -> SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSet, devIntfData)); - - var devInfoData = _SP_DEVINFO_DATA.allocate(arena); - _SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) devInfoData.byteSize()); - if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSet, devIntfData, NULL, 0, NULL, devInfoData, - errorState) == 0) { - var err = Win.getLastError(errorState); - if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) - throwException(err, "internal error (SetupDiGetDeviceInterfaceDetailW)"); - } + deviceInfoSet.addDevice(devicePath); // ensure all hubs are closed later final var hubHandles = new HashMap(); @@ -460,7 +398,7 @@ private void onDeviceConnected(String devicePath) { try { // create device instance - var device = createDeviceFromDeviceInfo(devInfoSet, devInfoData, devicePath, hubHandles); + var device = createDeviceFromDeviceInfo(deviceInfoSet, devicePath, hubHandles); // add it to device list addDevice(device); From b852efe6a1092d6c3c133010987c0a45eb5bfa2b Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 7 Aug 2023 19:21:37 +0200 Subject: [PATCH 278/433] Windows: more refactoring --- .../java/net/codecrete/usb/linux/Linux.java | 5 +- .../codecrete/usb/windows/DeviceInfoSet.java | 110 ++++++++++-------- ...ceProperty.java => DevicePropertyKey.java} | 38 ++++-- .../usb/windows/WindowsUSBDevice.java | 5 +- .../usb/windows/WindowsUSBDeviceRegistry.java | 100 +++++++--------- 5 files changed, 141 insertions(+), 117 deletions(-) rename java-does-usb/src/main/java/net/codecrete/usb/windows/{DeviceProperty.java => DevicePropertyKey.java} (66%) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java index 241e6161..c8c7ac70 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java @@ -9,8 +9,11 @@ import net.codecrete.usb.linux.gen.string.string; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout.PathElement; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.StructLayout; import java.lang.invoke.VarHandle; /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java index 343e33b0..623168f5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java @@ -18,7 +18,7 @@ import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.JAVA_CHAR; import static java.lang.foreign.ValueLayout.JAVA_INT; -import static net.codecrete.usb.windows.DeviceProperty.DEVPKEY_Device_Service; +import static net.codecrete.usb.windows.DevicePropertyKey.Service; import static net.codecrete.usb.windows.Win.allocateErrorState; import static net.codecrete.usb.windows.WindowsUSBException.throwException; import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; @@ -45,21 +45,13 @@ interface InfoSetCreator { private MemorySegment devIntfData; private int iterationIndex = -1; - /** - * Creates a new empty device info set. - * - * @return device info set - */ - static DeviceInfoSet ofEmpty() { - return new DeviceInfoSet((arena, errorState) -> SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, errorState)); - } - /** * Creates a new device info set containing the present devices of the specified device class and * optionally device instance ID. * *

- * After creation, there is no current element. {@link #next()} must be called first. + * After creation, there is no current element. {@link #next()} should be called to iterate the first + * and all subsequent elements. *

* * @param interfaceGuid device interface class GUID @@ -74,6 +66,45 @@ static DeviceInfoSet ofPresentDevices(MemorySegment interfaceGuid, String instan }); } + /** + * Creates a new device info set containing a single device with the specified instance ID. + * + *

+ * The device becomes the current element. The set cannot be iterated. + *

+ * + * @param instanceId instance ID + */ + static DeviceInfoSet ofInstance(String instanceId) { + var devInfoSet = ofEmpty(); + devInfoSet.addInstanceId(instanceId); + return devInfoSet; + } + + /** + * Creates a new device info set containing a single device with the specified path. + * + *

+ * The device becomes the current element. The set cannot be iterated. + *

+ * + * @param devicePath device path + */ + static DeviceInfoSet ofPath(String devicePath) { + var devInfoSet = ofEmpty(); + devInfoSet.addDevicePath(devicePath); + return devInfoSet; + } + + /** + * Creates a new empty device info set. + * + * @return device info set + */ + private static DeviceInfoSet ofEmpty() { + return new DeviceInfoSet((arena, errorState) -> SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, errorState)); + } + private DeviceInfoSet(InfoSetCreator creator) { arena = Arena.ofConfined(); try { @@ -101,48 +132,13 @@ public void close() { arena.close(); } - /** - * Iterates to the next element in this set. - * - * @return {@code true} if there is a current element, {@code false} if the iteration moved beyond the last element - */ - boolean next() { - iterationIndex += 1; - if (SetupAPI2.SetupDiEnumDeviceInfo(devInfoSet, iterationIndex, devInfoData, errorState) == 0) { - var err = Win.getLastError(errorState); - if (err == Kernel32.ERROR_NO_MORE_ITEMS()) - return false; - throwLastError(errorState, "internal error (SetupDiEnumDeviceInfo)"); - } - - return true; - } - - /** - * Adds the device with the specified instance ID to this device info set. - * - *

- * The added device becomes the current element. - *

- * - * @param instanceId instance ID - */ - void addInstance(String instanceId) { + private void addInstanceId(String instanceId) { var instanceIdSegment = Win.createSegmentFromString(instanceId, arena); if (SetupAPI2.SetupDiOpenDeviceInfoW(devInfoSet, instanceIdSegment, NULL, 0, devInfoData, errorState) == 0) throwLastError(errorState, "internal error (SetupDiOpenDeviceInfoW)"); } - /** - * Adds the device with the specified path to this device info set. - * - *

- * The added device becomes the current element. - *

- * - * @param devicePath device path - */ - void addDevice(String devicePath) { + private void addDevicePath(String devicePath) { if (devIntfData != null) throw new AssertionError("calling addDevice() multiple times is not implemented"); @@ -163,6 +159,22 @@ void addDevice(String devicePath) { } } + /** + * Iterates to the next element in this set. + * + * @return {@code true} if there is a current element, {@code false} if the iteration moved beyond the last element + */ + boolean next() { + iterationIndex += 1; + if (SetupAPI2.SetupDiEnumDeviceInfo(devInfoSet, iterationIndex, devInfoData, errorState) == 0) { + var err = Win.getLastError(errorState); + if (err == Kernel32.ERROR_NO_MORE_ITEMS()) + return false; + throwLastError(errorState, "internal error (SetupDiEnumDeviceInfo)"); + } + + return true; + } /** * Checks if the current element is a composite USB device @@ -170,7 +182,7 @@ void addDevice(String devicePath) { * @return {@code true} if it is a composite device */ boolean isCompositeDevice() { - var deviceService = getStringProperty(DEVPKEY_Device_Service); + var deviceService = getStringProperty(Service); // usbccgp is the USB Generic Parent Driver used for composite devices return "usbccgp".equalsIgnoreCase(deviceService); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DevicePropertyKey.java similarity index 66% rename from java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java rename to java-does-usb/src/main/java/net/codecrete/usb/windows/DevicePropertyKey.java index c382465e..72b97501 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceProperty.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DevicePropertyKey.java @@ -7,40 +7,58 @@ package net.codecrete.usb.windows; -import net.codecrete.usb.windows.gen.setupapi.*; +import net.codecrete.usb.windows.gen.setupapi._DEVPROPKEY; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; /** - * Device property GUIDs + * Device property keys (GUIDs) */ -class DeviceProperty { +class DevicePropertyKey { - private DeviceProperty() { + private DevicePropertyKey() { } - static final MemorySegment DEVPKEY_Device_Address = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, + /** + * DEVPKEY_Device_Address + */ + static final MemorySegment Address = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50 , (byte) 0xe0, 30); - static final MemorySegment DEVPKEY_Device_InstanceId = createDEVPROPKEY(0x78c34fc8, (short) 0x104a, + /** + * DEVPKEY_Device_InstanceId + */ + static final MemorySegment InstanceId = createDEVPROPKEY(0x78c34fc8, (short) 0x104a, (short) 0x4aca, (byte) 0x9e, (byte) 0xa4, (byte) 0x52, (byte) 0x4d, (byte) 0x52, (byte) 0x99, (byte) 0x6e , (byte) 0x57, 256); - static final MemorySegment DEVPKEY_Device_Parent = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, + /** + * DEVPKEY_Device_Parent + */ + static final MemorySegment Parent = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, (short) 0x4706, (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, (byte) 0x80, (byte) 0x08, (byte) 0xa5 , (byte) 0xa7, 8); - static final MemorySegment DEVPKEY_Device_Service = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, + /** + * DEVPKEY_Device_Service + */ + static final MemorySegment Service = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50 , (byte) 0xe0, 6); - static final MemorySegment DEVPKEY_Device_Children = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, + /** + * DEVPKEY_Device_Children + */ + static final MemorySegment Children = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, (short) 0x4706, (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, (byte) 0x80, (byte) 0x08, (byte) 0xa5 , (byte) 0xa7, 9); - static final MemorySegment DEVPKEY_Device_HardwareIds = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, + /** + * DEVPKEY_Device_HardwareIds + */ + static final MemorySegment HardwareIds = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50 , (byte) 0xe0, 3); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 5d5918c7..ed7601fe 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -7,7 +7,10 @@ package net.codecrete.usb.windows; -import net.codecrete.usb.*; +import net.codecrete.usb.USBControlTransfer; +import net.codecrete.usb.USBDirection; +import net.codecrete.usb.USBRecipient; +import net.codecrete.usb.USBTransferType; import net.codecrete.usb.common.Transfer; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.usbstandard.SetupPacket; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 9baf5722..39c271ab 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -30,20 +30,16 @@ import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.regex.Pattern; +import java.util.stream.Collectors; import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.usbstandard.Constants.*; -import static net.codecrete.usb.windows.DeviceProperty.DEVPKEY_Device_Address; -import static net.codecrete.usb.windows.DeviceProperty.DEVPKEY_Device_Children; -import static net.codecrete.usb.windows.DeviceProperty.DEVPKEY_Device_HardwareIds; -import static net.codecrete.usb.windows.DeviceProperty.DEVPKEY_Device_InstanceId; -import static net.codecrete.usb.windows.DeviceProperty.DEVPKEY_Device_Parent; +import static net.codecrete.usb.windows.DevicePropertyKey.*; +import static net.codecrete.usb.windows.USBConstants.GUID_DEVINTERFACE_USB_DEVICE; +import static net.codecrete.usb.windows.USBConstants.GUID_DEVINTERFACE_USB_HUB; import static net.codecrete.usb.windows.Win.allocateErrorState; import static net.codecrete.usb.windows.WindowsUSBException.throwException; import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; @@ -101,7 +97,7 @@ protected void monitorDevices() { _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$set(notificationFilter, (int) notificationFilter.byteSize()); _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$set(notificationFilter, User32.DBT_DEVTYP_DEVICEINTERFACE()); - _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid$slice(notificationFilter).copyFrom(USBConstants.GUID_DEVINTERFACE_USB_DEVICE); + _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid$slice(notificationFilter).copyFrom(GUID_DEVINTERFACE_USB_DEVICE); var notifyHandle = User32B.RegisterDeviceNotificationW(hwnd, notificationFilter, User32.DEVICE_NOTIFY_WINDOW_HANDLE(), errorState); @@ -133,7 +129,7 @@ private void enumeratePresentDevices() { List deviceList = new ArrayList<>(); try (var cleanup = new ScopeCleanup(); - var deviceInfoSet = DeviceInfoSet.ofPresentDevices(USBConstants.GUID_DEVINTERFACE_USB_DEVICE, null)) { + var deviceInfoSet = DeviceInfoSet.ofPresentDevices(GUID_DEVINTERFACE_USB_DEVICE, null)) { // ensure all hubs are closed later final var hubHandles = new HashMap(); @@ -142,8 +138,8 @@ private void enumeratePresentDevices() { // iterate all devices while (deviceInfoSet.next()) { - var instanceId = deviceInfoSet.getStringProperty(DEVPKEY_Device_InstanceId); - var devicePath = DeviceInfoSet.getDevicePath(instanceId, USBConstants.GUID_DEVINTERFACE_USB_DEVICE); + var instanceId = deviceInfoSet.getStringProperty(InstanceId); + var devicePath = DeviceInfoSet.getDevicePath(instanceId, GUID_DEVINTERFACE_USB_DEVICE); try { deviceList.add(createDeviceFromDeviceInfo(deviceInfoSet, devicePath, hubHandles)); @@ -160,48 +156,13 @@ private void enumeratePresentDevices() { } } - /** - * Enumerate the children of a composite device. - * - * @param childrenIds the children IDs - * @return map of containing children device paths, index by the first interface number - */ - private Map enumerateChildren(List childrenIds) { - - var children = new HashMap(); - - // iterate all children - for (var instanceId : childrenIds) { - try (var deviceInfoSet = DeviceInfoSet.ofEmpty()) { - - // get device info for child - deviceInfoSet.addInstance(instanceId); - - // get hardware IDs (to extract interface number) - var hardwareIds = deviceInfoSet.getStringListProperty(DEVPKEY_Device_HardwareIds); - if (hardwareIds == null) - throwException("internal error (device property 'HardwareIds' is missing)"); - var interfaceNumber = extractInterfaceNumber(hardwareIds); - if (interfaceNumber == -1) - continue; - - var devicePath = deviceInfoSet.getDevicePathByGUID(instanceId); - if (devicePath != null) - children.put(interfaceNumber, devicePath); - } - } - - return children; - } - - private USBDevice createDeviceFromDeviceInfo(DeviceInfoSet deviceInfoSet, String devicePath, HashMap hubHandles) { try (var arena = Arena.ofConfined()) { - var usbPortNum = deviceInfoSet.getIntProperty(DEVPKEY_Device_Address); - var parentInstanceId = deviceInfoSet.getStringProperty(DEVPKEY_Device_Parent); - var hubPath = DeviceInfoSet.getDevicePath(parentInstanceId, USBConstants.GUID_DEVINTERFACE_USB_HUB); + var usbPortNum = deviceInfoSet.getIntProperty(Address); + var parentInstanceId = deviceInfoSet.getStringProperty(Parent); + var hubPath = DeviceInfoSet.getDevicePath(parentInstanceId, GUID_DEVINTERFACE_USB_HUB); // open hub if not open yet var hubHandle = hubHandles.get(hubPath); @@ -233,7 +194,7 @@ private Map getChildDevices(DeviceInfoSet deviceInfoSet, String var numTries = 5; while (true) { numTries -= 1; - childrenInstanceIDs = deviceInfoSet.getStringListProperty(DEVPKEY_Device_Children); + childrenInstanceIDs = deviceInfoSet.getStringListProperty(Children); if (childrenInstanceIDs != null || numTries == 0) break; @@ -253,7 +214,11 @@ private Map getChildDevices(DeviceInfoSet deviceInfoSet, String return null; } - return enumerateChildren(childrenInstanceIDs); + // create children map (interface number -> device path) + return childrenInstanceIDs.stream() + .map(WindowsUSBDeviceRegistry::getNumberPathTuple) + .filter(Objects::nonNull) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } /** @@ -388,9 +353,7 @@ private long handleWindowMessage(MemorySegment hWnd, int uMsg, long wParam, long @SuppressWarnings("java:S106") private void onDeviceConnected(String devicePath) { try (var cleanup = new ScopeCleanup(); - var deviceInfoSet = DeviceInfoSet.ofEmpty()) { - - deviceInfoSet.addDevice(devicePath); + var deviceInfoSet = DeviceInfoSet.ofPath(devicePath)) { // ensure all hubs are closed later final var hubHandles = new HashMap(); @@ -438,6 +401,31 @@ protected int findDeviceIndex(List deviceList, Object deviceId) { return -1; } + /** + * Looks up the interface number and device path for the child device with the given instance ID. + * + * @param instanceId child instance ID + * @return tuple consisting of interface number and device path, or {@code null} if unsuccessful + */ + private static Map.Entry getNumberPathTuple(String instanceId) { + try (var deviceInfoSet = DeviceInfoSet.ofInstance(instanceId)) { + + // get hardware IDs (to extract interface number) + var hardwareIds = deviceInfoSet.getStringListProperty(HardwareIds); + if (hardwareIds == null) + throwException("internal error (device property 'HardwareIds' is missing)"); + var interfaceNumber = extractInterfaceNumber(hardwareIds); + if (interfaceNumber == -1) + return null; + + var devicePath = deviceInfoSet.getDevicePathByGUID(instanceId); + if (devicePath == null) + return null; + + return new AbstractMap.SimpleImmutableEntry<>(interfaceNumber, devicePath); + } + } + private static final Pattern MULTIPLE_INTERFACE_ID = Pattern.compile( "USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); From d47c2bd48ebb323860e03c35c1637da0ee231bd0 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 18 Sep 2023 23:54:23 +0200 Subject: [PATCH 279/433] device descriptor as byte array --- .../.mvn/wrapper/maven-wrapper.properties | 2 +- .../java/net/codecrete/usb/USBDevice.java | 7 +++++ .../codecrete/usb/common/USBDeviceImpl.java | 8 ++++++ .../main/java/net/codecrete/usb/linux/IO.java | 2 +- .../net/codecrete/usb/macos/IoKitUSB.java | 7 ++++- .../codecrete/usb/macos/MacosUSBDevice.java | 20 +++++++++++--- .../codecrete/usb/AlternateInterfaceTest.java | 2 +- .../net/codecrete/usb/BulkTransferTest.java | 26 +++++++++--------- .../net/codecrete/usb/DescriptionTest.java | 6 ++--- .../net/codecrete/usb/DescriptorTest.java | 23 ++++++++++++++++ .../codecrete/usb/DeviceLifecycleTest.java | 2 +- .../codecrete/usb/InterruptTransferTest.java | 4 +-- .../java/net/codecrete/usb/SpeedTest.java | 20 +++++++------- .../java/net/codecrete/usb/StallTest.java | 10 +++---- .../java/net/codecrete/usb/StreamTest.java | 27 ++++++++++--------- .../java/net/codecrete/usb/TimeoutTest.java | 16 +++++------ 16 files changed, 119 insertions(+), 63 deletions(-) create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/DescriptorTest.java diff --git a/java-does-usb/.mvn/wrapper/maven-wrapper.properties b/java-does-usb/.mvn/wrapper/maven-wrapper.properties index 6d3a5665..ac184013 100644 --- a/java-does-usb/.mvn/wrapper/maven-wrapper.properties +++ b/java-does-usb/.mvn/wrapper/maven-wrapper.properties @@ -14,5 +14,5 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.4/apache-maven-3.9.4-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java index a9ba17d2..67837476 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java @@ -452,6 +452,13 @@ default InputStream openInputStream(int endpointNumber) { */ void clearHalt(USBDirection direction, int endpointNumber); + /** + * Gets the device descriptor. + * + * @return the device descriptor (as a byte array) + */ + byte[] deviceDescriptor(); + /** * Gets the configuration descriptor. * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java index 946102fc..6db36ed5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java @@ -31,6 +31,8 @@ public abstract class USBDeviceImpl implements USBDevice { protected List interfaceList; + protected byte[] rawDeviceDescriptor; + protected byte[] rawConfigurationDescriptor; // Information from the device descriptor @@ -137,6 +139,11 @@ public byte[] configurationDescriptor() { return rawConfigurationDescriptor; } + @Override + public byte[] deviceDescriptor() { + return rawDeviceDescriptor; + } + public Object getUniqueId() { return uniqueDeviceId; } @@ -147,6 +154,7 @@ public Object getUniqueId() { * @param descriptor the device descriptor */ public void setFromDeviceDescriptor(MemorySegment descriptor) { + rawDeviceDescriptor = descriptor.toArray(JAVA_BYTE); var deviceDescriptor = new DeviceDescriptor(descriptor); deviceClass = deviceDescriptor.deviceClass() & 255; deviceSubclass = deviceDescriptor.deviceSubClass() & 255; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java index 84e9f499..88b6d364 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java @@ -23,7 +23,7 @@ private IO() { private static final Linker linker = Linker.nativeLinker(); private static final FunctionDescriptor ioctl$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_LONG, ADDRESS); private static final MethodHandle ioctl$MH = linker.downcallHandle(linker.defaultLookup().find("ioctl").get(), - ioctl$FUNC, Linux.ERRNO_STATE); + ioctl$FUNC, Linux.ERRNO_STATE, Linker.Option.firstVariadicArg(2)); private static final FunctionDescriptor open$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT); private static final MethodHandle open$MH = linker.downcallHandle(linker.defaultLookup().find("open").get(), open$FUNC, Linux.ERRNO_STATE); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java index d2d3523c..2ba04f12 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java @@ -81,9 +81,14 @@ static int CreateInterfaceIterator(MemorySegment self, MemorySegment req, Memory return IOUSBDeviceStruct187.CreateInterfaceIterator(getVtable(self), Arena.global()).apply(self, req, iter); } + // IOReturn (* DeviceRequest)(void* self, IOUSBDevRequest* req) + static int DeviceRequest(MemorySegment self, MemorySegment deviceRequest) { + return IOUSBDeviceStruct187.DeviceRequest(getVtable(self), Arena.global()).apply(self, deviceRequest); + } + // IOReturn (* DeviceRequestAsync)(void* self, IOUSBDevRequest* req, IOAsyncCallback1 callback, void* refCon) static int DeviceRequestAsync(MemorySegment self, MemorySegment deviceRequest, MemorySegment callback, - MemorySegment refCon) { + MemorySegment refCon) { return IOUSBDeviceStruct187.DeviceRequestAsync(getVtable(self), Arena.global()).apply(self, deviceRequest, callback, refCon); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index 82d28dea..a2a22818 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -7,9 +7,7 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.USBControlTransfer; -import net.codecrete.usb.USBDirection; -import net.codecrete.usb.USBTransferType; +import net.codecrete.usb.*; import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.common.Transfer; import net.codecrete.usb.common.USBDeviceImpl; @@ -17,6 +15,8 @@ import net.codecrete.usb.macos.gen.iokit.IOUSBDevRequest; import net.codecrete.usb.macos.gen.iokit.IOUSBFindInterfaceRequest; import net.codecrete.usb.usbstandard.ConfigurationDescriptor; +import net.codecrete.usb.usbstandard.Constants; +import net.codecrete.usb.usbstandard.DeviceDescriptor; import java.io.InputStream; import java.io.OutputStream; @@ -159,11 +159,23 @@ synchronized void closeFully() { private void loadDescription(MemorySegment device) { try (var arena = Arena.ofConfined()) { + var data = arena.allocate(DeviceDescriptor.LAYOUT.byteSize()); + var ret = IoKitUSB.DeviceRequest(device, createDeviceRequest(arena, USBDirection.IN, new USBControlTransfer( + USBRequestType.STANDARD, + USBRecipient.DEVICE, + 6, // get descriptor + Constants.DEVICE_DESCRIPTOR_TYPE << 8, + 0 + ), data)); + if (ret != 0) + throwException(ret, "querying device descriptor failed"); + rawDeviceDescriptor = data.toArray(JAVA_BYTE); + configurationValue = 0; // retrieve information of first configuration var descPtrHolder = arena.allocate(ADDRESS); - var ret = IoKitUSB.GetConfigurationDescriptorPtr(device, (byte) 0, descPtrHolder); + ret = IoKitUSB.GetConfigurationDescriptorPtr(device, (byte) 0, descPtrHolder); if (ret != 0) throwException(ret, "querying first configuration failed"); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java index 5238954a..857b9b61 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java @@ -47,7 +47,7 @@ void selectInvalidAlternateIntf_fails() { void transferOnValidEndpoint_succeeds() { testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 1); - byte[] sampleData = generateRandomBytes(12, 293872394); + var sampleData = generateRandomBytes(12, 293872394); testDevice.transferOut(LOOPBACK_EP_OUT, sampleData); var received = testDevice.transferIn(LOOPBACK_EP_IN); assertArrayEquals(sampleData, received); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java index 39333b78..2418fd93 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java @@ -21,9 +21,9 @@ class BulkTransferTest extends TestDeviceBase { @Test void smallTransfer_succeeds() { - byte[] sampleData = generateRandomBytes(12, 293872394); + var sampleData = generateRandomBytes(12, 293872394); writeBytes(sampleData); - byte[] data = readBytes(sampleData.length); + var data = readBytes(sampleData.length); assertArrayEquals(sampleData, data); } @@ -31,19 +31,19 @@ void smallTransfer_succeeds() { void mediumTransfer_succeeds() { // This synchronous approach should work as the test device // has an internal buffer of about 500 bytes. - byte[] sampleData = generateRandomBytes(140, 97333894); + var sampleData = generateRandomBytes(140, 97333894); writeBytes(sampleData); - byte[] data = readBytes(sampleData.length); + var data = readBytes(sampleData.length); assertArrayEquals(sampleData, data); } @Test void transferWithZLP_succeeds() { var inEndpoint = testDevice.getEndpoint(USBDirection.IN, LOOPBACK_EP_IN); - byte[] sampleData = generateRandomBytes(inEndpoint.packetSize(), 97333894); + var sampleData = generateRandomBytes(inEndpoint.packetSize(), 97333894); testDevice.transferOut(LOOPBACK_EP_OUT, sampleData); testDevice.transferOut(LOOPBACK_EP_OUT, new byte[0]); - byte[] data = testDevice.transferIn(LOOPBACK_EP_IN); + var data = testDevice.transferIn(LOOPBACK_EP_IN); assertArrayEquals(sampleData, data); data = testDevice.transferIn(LOOPBACK_EP_IN); assertNotNull(data); @@ -52,8 +52,8 @@ void transferWithZLP_succeeds() { @Test void largeTransfer_succeeds() throws Throwable { - final int numBytes = 230763; - byte[] sampleData = generateRandomBytes(numBytes, 3829007493L); + final var numBytes = 230763; + var sampleData = generateRandomBytes(numBytes, 3829007493L); var writer = CompletableFuture.runAsync(() -> writeBytes(sampleData)); var reader = CompletableFuture.supplyAsync(() -> readBytes(numBytes)); CompletableFuture.allOf(writer, reader).join(); @@ -63,19 +63,19 @@ void largeTransfer_succeeds() throws Throwable { } static void writeBytes(byte[] data) { - final int chunkSize = 100; - int numBytes = 0; + final var chunkSize = 100; + var numBytes = 0; while (numBytes < data.length) { - int size = Math.min(chunkSize, data.length - numBytes); + var size = Math.min(chunkSize, data.length - numBytes); testDevice.transferOut(LOOPBACK_EP_OUT, Arrays.copyOfRange(data, numBytes, numBytes + size)); numBytes += size; } } static byte[] readBytes(int numBytes) { var buffer = new ByteArrayOutputStream(); - int bytesRead = 0; + var bytesRead = 0; while (bytesRead < numBytes) { - byte[] data = testDevice.transferIn(LOOPBACK_EP_IN); + var data = testDevice.transferIn(LOOPBACK_EP_IN); buffer.writeBytes(data); bytesRead += data.length; } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index 07d06126..122d9832 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -36,7 +36,7 @@ void deviceInfo_isCorrect() { assertEquals(0x00, testDevice.protocolCode()); } - boolean isComposite = isCompositeDevce(); + var isComposite = isCompositeDevce(); assertEquals(2, testDevice.usbVersion().major()); assertEquals(isComposite ? 1 : 0, testDevice.usbVersion().minor()); @@ -132,9 +132,9 @@ void endpointDescriptors_areCorrect() { @Test void configurationDescription_isAvailable() { - int expectedLength = isLoopbackDevice() ? 69 : 98; + var expectedLength = isLoopbackDevice() ? 69 : 98; - byte[] configDesc = testDevice.configurationDescriptor(); + var configDesc = testDevice.configurationDescriptor(); assertNotNull(configDesc); assertEquals(expectedLength, configDesc.length); assertEquals(2, configDesc[1]); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptorTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptorTest.java new file mode 100644 index 00000000..85dc9057 --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptorTest.java @@ -0,0 +1,23 @@ +package net.codecrete.usb; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class DescriptorTest extends TestDeviceBase { + + @Test + void deviceDescriptor_isAvailable() { + var desc = testDevice.deviceDescriptor(); + assertEquals(18, desc.length); + assertEquals(0x01, desc[1]); + } + + @Test + void configurationDescriptor_isAvailable() { + var desc = testDevice.configurationDescriptor(); + assertTrue(desc.length > 60); + assertEquals(0x02, desc[1]); + } +} diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java index 7ce074cc..af45e92c 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java @@ -21,7 +21,7 @@ class DeviceLifecycleTest { @Test void lifecycle_showsValidState() { device = TestDeviceBase.getDevice(); - int interfaceNumber = TestDeviceBase.getInterfaceNumber(device); + var interfaceNumber = TestDeviceBase.getInterfaceNumber(device); var intf = device.interfaces().get(interfaceNumber); assertEquals(interfaceNumber, intf.number()); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java index 384a379e..5a2379a8 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java @@ -21,11 +21,11 @@ void smallTransfer_succeeds() { Assumptions.assumeTrue(isLoopbackDevice(), "Interrupt transfer only supported by loopback test device"); - byte[] sampleData = generateRandomBytes(12, 293872394); + var sampleData = generateRandomBytes(12, 293872394); testDevice.transferOut(ECHO_EP_OUT, sampleData); // receive first echo - byte[] echo = testDevice.transferIn(ECHO_EP_IN); + var echo = testDevice.transferIn(ECHO_EP_IN); assertArrayEquals(sampleData, echo); // receive second echo diff --git a/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java index 612df1ff..732bd3bb 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java @@ -20,23 +20,23 @@ class SpeedTest extends TestDeviceBase { @Test void loopback_isFast() throws Throwable { - final boolean isHighSpeed = testDevice.getEndpoint(USBDirection.IN, LOOPBACK_EP_IN).packetSize() == 512; - final int numBytes = isHighSpeed ? 5000000 : 500000; + final var isHighSpeed = testDevice.getEndpoint(USBDirection.IN, LOOPBACK_EP_IN).packetSize() == 512; + final var numBytes = isHighSpeed ? 5000000 : 500000; - byte[] sampleData = generateRandomBytes(numBytes, 7219937602343L); + var sampleData = generateRandomBytes(numBytes, 7219937602343L); - long start = System.currentTimeMillis(); + var start = System.currentTimeMillis(); var writer = CompletableFuture.runAsync(() -> writeBytes(sampleData)); var reader = CompletableFuture.supplyAsync(() -> readBytes(numBytes)); CompletableFuture.allOf(writer, reader).join(); - long end = System.currentTimeMillis(); + var end = System.currentTimeMillis(); if (reader.isCompletedExceptionally()) throw reader.exceptionNow(); assertArrayEquals(sampleData, reader.resultNow()); - double throughput = 2.0 * numBytes / (end - start); - double expectedThroughput = isHighSpeed ? 15000 : 500; + var throughput = 2.0 * numBytes / (end - start); + var expectedThroughput = isHighSpeed ? 15000.0 : 500.0; System.out.printf("Throughput: expected ≥%,.0f KB/s, actual %,.0f KB/s%n", expectedThroughput, throughput); assertTrue(throughput >= expectedThroughput, "Expected throughput not achieved"); @@ -51,10 +51,10 @@ static void writeBytes(byte[] data) { } static byte[] readBytes(int numBytes) { try (var is = testDevice.openInputStream(LOOPBACK_EP_IN)) { - byte[] buffer = new byte[numBytes]; - int bytesRead = 0; + var buffer = new byte[numBytes]; + var bytesRead = 0; while (bytesRead < numBytes) { - int n = is.read(buffer, bytesRead, numBytes - bytesRead); + var n = is.read(buffer, bytesRead, numBytes - bytesRead); if (n <= 0) throw new RuntimeException("unexpected end of input stream"); bytesRead += n; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java index 4f8411ae..6f97fe72 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java @@ -20,7 +20,7 @@ class StallTest extends TestDeviceBase { void stalledBulkTransferOut_recovers() { haltEndpoint(USBDirection.OUT, LOOPBACK_EP_OUT); - byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + var data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; assertThrows(USBStallException.class, () -> testDevice.transferOut(LOOPBACK_EP_OUT, data)); testDevice.clearHalt(USBDirection.OUT, LOOPBACK_EP_OUT); @@ -38,7 +38,7 @@ void stalledBulkTransferIn_recovers() { testDevice.clearHalt(USBDirection.IN, LOOPBACK_EP_IN); - byte[] data = new byte[] { 9, 8, 7, 6, 5, 4, 3, 2 }; + var data = new byte[] { 9, 8, 7, 6, 5, 4, 3, 2 }; testDevice.transferOut(LOOPBACK_EP_OUT, data); var receivedData = testDevice.transferIn(LOOPBACK_EP_IN); assertArrayEquals(data, receivedData); @@ -52,9 +52,9 @@ void invalidControlTransfer_throws() { } void haltEndpoint(USBDirection direction, int endpointNumber) { - final int SET_FEATURE = 0x03; - final int ENDPOINT_HALT = 0x00; - int endpointAddress = (direction == USBDirection.IN ? 0x80 : 0x00) | endpointNumber; + final var SET_FEATURE = 0x03; + final var ENDPOINT_HALT = 0x00; + var endpointAddress = (direction == USBDirection.IN ? 0x80 : 0x00) | endpointNumber; testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.STANDARD, USBRecipient.ENDPOINT, SET_FEATURE, ENDPOINT_HALT, endpointAddress), null); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java index 197a81d5..fb090bca 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java @@ -22,9 +22,9 @@ class StreamTest extends TestDeviceBase { @Test void smallTransfer_succeeds() { - byte[] sampleData = generateRandomBytes(12, 293872394); + var sampleData = generateRandomBytes(12, 293872394); writeBytes(sampleData, 100); - byte[] data = readBytes(sampleData.length); + var data = readBytes(sampleData.length); assertArrayEquals(sampleData, data); } @@ -32,15 +32,15 @@ void smallTransfer_succeeds() { void mediumTransfer_succeeds() { // This synchronous approach should work as the test device // has an internal buffer of about 500 bytes. - byte[] sampleData = generateRandomBytes(140, 97333894); + var sampleData = generateRandomBytes(140, 97333894); writeBytes(sampleData, 30); - byte[] data = readBytes(sampleData.length); + var data = readBytes(sampleData.length); assertArrayEquals(sampleData, data); } @Test void transferWithZLP_succeeds() { - final byte[] sampleData = generateRandomBytes(2 * LOOPBACK_MAX_PACKET_SIZE, 197007894); + final var sampleData = generateRandomBytes(2 * LOOPBACK_MAX_PACKET_SIZE, 197007894); var writer = CompletableFuture.runAsync(() -> { testDevice.transferOut(LOOPBACK_EP_OUT, Arrays.copyOfRange(sampleData, 0, LOOPBACK_MAX_PACKET_SIZE)); sleep(200); @@ -56,8 +56,8 @@ void transferWithZLP_succeeds() { @Test void largeTransferSmallChunks_succeeds() { - final int numBytes = 23076; - byte[] sampleData = generateRandomBytes(numBytes, 3829007493L); + final var numBytes = 23076; + var sampleData = generateRandomBytes(numBytes, 3829007493L); var writer = CompletableFuture.runAsync(() -> writeBytes(sampleData, 20)); var reader = CompletableFuture.supplyAsync(() -> readBytes(numBytes)); var allFutures = CompletableFuture.allOf(writer, reader); @@ -67,8 +67,8 @@ void largeTransferSmallChunks_succeeds() { @Test void largeTransferBigChunks_succeeds() { - final int numBytes = 230763; - byte[] sampleData = generateRandomBytes(numBytes, 3829007493L); + final var numBytes = 230763; + var sampleData = generateRandomBytes(numBytes, 3829007493L); var writer = CompletableFuture.runAsync(() -> writeBytes(sampleData, 150)); var reader = CompletableFuture.supplyAsync(() -> readBytes(numBytes)); CompletableFuture.allOf(writer, reader).join(); @@ -77,9 +77,9 @@ void largeTransferBigChunks_succeeds() { static void writeBytes(byte[] data, int chunkSize) { try (var os = testDevice.openOutputStream(LOOPBACK_EP_OUT)) { - int numBytes = 0; + var numBytes = 0; while (numBytes < data.length) { - int size = Math.min(chunkSize, data.length - numBytes); + var size = Math.min(chunkSize, data.length - numBytes); os.write(data, numBytes, size); numBytes += size; } @@ -91,9 +91,9 @@ static void writeBytes(byte[] data, int chunkSize) { static byte[] readBytes(int numBytes) { var buffer = new byte[numBytes]; try (var is = testDevice.openInputStream(LOOPBACK_EP_IN)) { - int bytesRead = 0; + var bytesRead = 0; while (bytesRead < numBytes) { - int n = is.read(buffer, bytesRead, numBytes - bytesRead); + var n = is.read(buffer, bytesRead, numBytes - bytesRead); assertTrue(n > 0); bytesRead += n; } @@ -104,6 +104,7 @@ static byte[] readBytes(int numBytes) { return buffer; } + @SuppressWarnings({"java:S2925", "SameParameterValue"}) private static void sleep(int millis) { try { Thread.sleep(millis); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java index 5fe0cf8a..a692aa13 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java @@ -29,10 +29,10 @@ void bulkTransferIn_timesOut() { @Test @Timeout(value = 1, unit = TimeUnit.SECONDS) void bulkTransfer_doesNotTimeOut() { - byte[] data = generateRandomBytes(20, 7280277392L); + var data = generateRandomBytes(20, 7280277392L); testDevice.transferOut(LOOPBACK_EP_OUT, data); - byte[] received = testDevice.transferIn(LOOPBACK_EP_IN, 200); + var received = testDevice.transferIn(LOOPBACK_EP_IN, 200); assertArrayEquals(data, received); } @@ -41,15 +41,15 @@ void bulkTransfer_doesNotTimeOut() { @Timeout(value = 1, unit = TimeUnit.SECONDS) void bulkTransferOut_timesOut() { // The test device has an internal buffer of about 2KB for full-speed - // and 16KB for high-speed. The first transfer should not time-out. - final int bufferSize = 32 * testDevice + // and 16KB for high-speed. The first transfer should not time out. + final var bufferSize = 32 * testDevice .getEndpoint(USBDirection.OUT, LOOPBACK_EP_OUT).packetSize(); - byte[] data = generateRandomBytes(100, 9383073929L); + var data = generateRandomBytes(100, 9383073929L); testDevice.transferOut(LOOPBACK_EP_OUT, data, 200); assertThrows(USBTimeoutException.class, () -> { - for (int i = 0; i < bufferSize / data.length; i++) { + for (var i = 0; i < bufferSize / data.length; i++) { testDevice.transferOut(LOOPBACK_EP_OUT, data, 200); } }); @@ -78,11 +78,11 @@ void interruptTransfer_doesNotTimeOut() { Assumptions.assumeTrue(isLoopbackDevice(), "Interrupt transfer only supported by loopback test device"); - byte[] sampleData = generateRandomBytes(12, 293872394); + var sampleData = generateRandomBytes(12, 293872394); testDevice.transferOut(ECHO_EP_OUT, sampleData, 200); // receive first echo - byte[] echo = testDevice.transferIn(ECHO_EP_IN, 200); + var echo = testDevice.transferIn(ECHO_EP_IN, 200); assertArrayEquals(sampleData, echo); // receive second echo From 39bac6bb13cbdbd0ccc9786595dfcb49e02fd4c2 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 19 Sep 2023 19:22:42 +0200 Subject: [PATCH 280/433] macOS: Deal with larger device descriptors --- .github/workflows/continuous-integration.yaml | 8 ++++---- .../net/codecrete/usb/macos/MacosUSBDevice.java | 13 ++++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index d6b491b2..ba1f23d0 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -26,11 +26,11 @@ jobs: steps: - uses: actions/checkout@v3 - name: Setup Java - uses: oracle-actions/setup-java@v1 + uses: actions/setup-java@v3 with: - website: jdk.java.net - release: '21' - version: latest + distribution: 'zulu' + java-version: '21' + cache: 'maven' - name: Configure GPG key run: | echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java index a2a22818..18673d2c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java @@ -16,7 +16,6 @@ import net.codecrete.usb.macos.gen.iokit.IOUSBFindInterfaceRequest; import net.codecrete.usb.usbstandard.ConfigurationDescriptor; import net.codecrete.usb.usbstandard.Constants; -import net.codecrete.usb.usbstandard.DeviceDescriptor; import java.io.InputStream; import java.io.OutputStream; @@ -159,17 +158,21 @@ synchronized void closeFully() { private void loadDescription(MemorySegment device) { try (var arena = Arena.ofConfined()) { - var data = arena.allocate(DeviceDescriptor.LAYOUT.byteSize()); - var ret = IoKitUSB.DeviceRequest(device, createDeviceRequest(arena, USBDirection.IN, new USBControlTransfer( + // retrieve device descriptor using synchronous control transfer + var data = arena.allocate(255); + var deviceRequest = createDeviceRequest(arena, USBDirection.IN, new USBControlTransfer( USBRequestType.STANDARD, USBRecipient.DEVICE, 6, // get descriptor Constants.DEVICE_DESCRIPTOR_TYPE << 8, 0 - ), data)); + ), data); + var ret = IoKitUSB.DeviceRequest(device, deviceRequest); if (ret != 0) throwException(ret, "querying device descriptor failed"); - rawDeviceDescriptor = data.toArray(JAVA_BYTE); + + var len = IOUSBDevRequest.wLenDone$get(deviceRequest); + rawDeviceDescriptor = data.asSlice(0, len).toArray(JAVA_BYTE); configurationValue = 0; From 6732cdbf451d6d6da7eabbb30bc80fb97275e3fd Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 19 Sep 2023 19:44:15 +0200 Subject: [PATCH 281/433] Linux: fix device descriptor --- .../src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java index 44aeb890..897d3c16 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java @@ -66,7 +66,7 @@ private void loadDescription(String path) { // `descriptors` contains the device descriptor followed by the configuration descriptor // (including the interface descriptors, endpoint descriptors etc.) var descriptorsSegment = MemorySegment.ofArray(descriptors); - setFromDeviceDescriptor(descriptorsSegment); + setFromDeviceDescriptor(descriptorsSegment.asSlice(0, DeviceDescriptor.LAYOUT)); setConfigurationDescriptor(descriptorsSegment.asSlice(DeviceDescriptor.LAYOUT.byteSize())); } From 70722c40f9358b7fdc0015a07aa9fd268edbdc15 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 19 Sep 2023 21:39:59 +0200 Subject: [PATCH 282/433] Print device/configuration descriptor --- examples/enumerate/pom.xml | 17 ++++++++++++++++- .../net/codecrete/usb/examples/Enumerate.java | 18 ++++++++++++++++++ .../src/main/resources/tinylog.properties | 3 +++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 examples/enumerate/src/main/resources/tinylog.properties diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index 45177aba..34048b3f 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -23,10 +23,25 @@ java-does-usb 0.6.0-SNAPSHOT + + org.tinylog + tinylog-api + 2.6.2 + + + org.tinylog + tinylog-impl + 2.6.2 + + + org.tinylog + jsl-tinylog + 2.6.2 + - + diff --git a/examples/enumerate/src/main/java/net/codecrete/usb/examples/Enumerate.java b/examples/enumerate/src/main/java/net/codecrete/usb/examples/Enumerate.java index ee89765a..b575db86 100644 --- a/examples/enumerate/src/main/java/net/codecrete/usb/examples/Enumerate.java +++ b/examples/enumerate/src/main/java/net/codecrete/usb/examples/Enumerate.java @@ -14,6 +14,7 @@ /** * Sample application enumerating connected USB devices. */ +@SuppressWarnings("java:S106") public class Enumerate { public static void main(String[] args) { @@ -42,10 +43,14 @@ private static void printDevice(USBDevice device) { for (var intf: device.interfaces()) printInterface(intf); + printRawDescriptor("Device descriptor", device.deviceDescriptor()); + printRawDescriptor("Configuration descriptor", device.configurationDescriptor()); + System.out.println(); System.out.println(); } + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") private static void printInParens(Optional text) { if (text.isPresent()) { System.out.printf(" (%s)%n", text.get()); @@ -85,4 +90,17 @@ private static void printEndpoint(USBEndpoint endpoint) { System.out.printf(" Transfer type: %s%n", endpoint.transferType().name()); System.out.printf(" Packet size: %d bytes%n", endpoint.packetSize()); } + + private static void printRawDescriptor(String title, byte[] descriptor) { + System.out.println(); + System.out.println(title); + + int len = descriptor.length; + for (int i = 0; i < len; i += 16) { + System.out.printf("%04x ", i); + for (int j = i; j < Math.min(i + 16, len); j += 1) + System.out.printf(" %02x", descriptor[j] & 255); + System.out.println(); + } + } } diff --git a/examples/enumerate/src/main/resources/tinylog.properties b/examples/enumerate/src/main/resources/tinylog.properties new file mode 100644 index 00000000..9cf0c142 --- /dev/null +++ b/examples/enumerate/src/main/resources/tinylog.properties @@ -0,0 +1,3 @@ +writer = console +writer.format = {date: HH:mm:ss.SSS} {level|size=5} [{class|size=40}] {message} +writer.level = info From 2c82664a1cc09189b15fee8d8721e6a04c1bc6e0 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 19 Sep 2023 21:45:45 +0200 Subject: [PATCH 283/433] Monitor example: logging --- examples/monitor/pom.xml | 15 +++++++++++++++ .../monitor/src/main/resources/tinylog.properties | 3 +++ 2 files changed, 18 insertions(+) create mode 100644 examples/monitor/src/main/resources/tinylog.properties diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index d549d71f..d94ef9a3 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -23,6 +23,21 @@ java-does-usb 0.6.0-SNAPSHOT + + org.tinylog + tinylog-api + 2.6.2 + + + org.tinylog + tinylog-impl + 2.6.2 + + + org.tinylog + jsl-tinylog + 2.6.2 + diff --git a/examples/monitor/src/main/resources/tinylog.properties b/examples/monitor/src/main/resources/tinylog.properties new file mode 100644 index 00000000..08b5f1d0 --- /dev/null +++ b/examples/monitor/src/main/resources/tinylog.properties @@ -0,0 +1,3 @@ +writer = console +writer.format = {date: HH:mm:ss.SSS} {level|size=5} [{class|size=40}] {message} +writer.level = debug From 8db72c7adeb6f87a7a966eff47bccfcacef92534 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 19 Sep 2023 21:48:27 +0200 Subject: [PATCH 284/433] Use logging --- .../usb/common/USBDeviceRegistry.java | 17 ++++++------ .../usb/linux/LinuxUSBDeviceRegistry.java | 8 +++--- .../usb/macos/MacosUSBDeviceRegistry.java | 12 ++++----- .../usb/windows/WindowsUSBDeviceRegistry.java | 27 ++++++++++--------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java index 877ae310..b3224dfc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java @@ -18,6 +18,9 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; +import static java.lang.System.Logger.Level.INFO; +import static java.lang.System.Logger.Level.WARNING; + /** * Base class for USB device registry. *

@@ -32,6 +35,8 @@ */ public abstract class USBDeviceRegistry { + private static final System.Logger LOG = System.getLogger(USBDeviceRegistry.class.getName()); + private List devices; private Throwable failureCause; protected Consumer onDeviceConnectedHandler; @@ -81,7 +86,6 @@ public void setOnDeviceDisconnected(Consumer handler) { onDeviceDisconnectedHandler = handler; } - @SuppressWarnings("java:S106") protected void emitOnDeviceConnected(USBDevice device) { if (onDeviceConnectedHandler == null) return; @@ -90,12 +94,10 @@ protected void emitOnDeviceConnected(USBDevice device) { onDeviceConnectedHandler.accept(device); } catch (Exception e) { - System.err.println("Warning: [JavaDoesUSB] unhandled exception in 'onDeviceConnected' handler - ignoring"); - e.printStackTrace(System.err); + LOG.log(WARNING, "unhandled exception in 'onDeviceConnected' handler - ignoring", e); } } - @SuppressWarnings("java:S106") protected void emitOnDeviceDisconnected(USBDevice device) { if (onDeviceDisconnectedHandler == null) return; @@ -104,9 +106,7 @@ protected void emitOnDeviceDisconnected(USBDevice device) { onDeviceDisconnectedHandler.accept(device); } catch (Exception e) { - System.err.println( - "Warning: [JavaDoesUSB] unhandled exception in 'onDeviceDisconnected' handler - ignoring"); - e.printStackTrace(System.err); + LOG.log(WARNING, "unhandled exception in 'onDeviceDisconnected' handler - ignoring", e); } } @@ -207,8 +207,7 @@ protected void closeAndRemoveDevice(Object deviceId) { try { device.close(); } catch (Exception e) { - System.err.println("Info: [JavaDoesUSB] failed to close USB device - ignoring exception"); - e.printStackTrace(System.err); + LOG.log(INFO, "failed to close USB device - ignoring exception", e); } removeDevice(deviceId); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java index 7bf62baf..ec12e75d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.List; +import static java.lang.System.Logger.Level.INFO; import static net.codecrete.usb.linux.LinuxUSBException.throwException; /** @@ -26,6 +27,8 @@ */ public class LinuxUSBDeviceRegistry extends USBDeviceRegistry { + private static final System.Logger LOG = System.getLogger(LinuxUSBDeviceRegistry.class.getName()); + private static final MemorySegment SUBSYSTEM_USB; private static final MemorySegment MONITOR_NAME; private static final MemorySegment DEVTYPE_USB_DEVICE; @@ -220,10 +223,7 @@ private USBDevice getDeviceDetails(MemorySegment udevDevice) { return device; } catch (Exception e) { - System.err.printf( - "Info: [JavaDoesUSB] failed to retrieve information about device 0x%04x/0x%04x - ignoring device%n", - vendorId, productId); - e.printStackTrace(System.err); + LOG.log(INFO, String.format("failed to retrieve information about device 0x%04x/0x%04x - ignoring device", vendorId, productId), e); return null; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java index 049429ed..d2bb8c0a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.function.Consumer; +import static java.lang.System.Logger.Level.INFO; import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.macos.CoreFoundationHelper.createCFStringRef; @@ -31,6 +32,8 @@ @SuppressWarnings("java:S116") public class MacosUSBDeviceRegistry extends USBDeviceRegistry { + private static final System.Logger LOG = System.getLogger(MacosUSBDeviceRegistry.class.getName()); + private static final MemorySegment KEY_ID_VENDOR; private static final MemorySegment KEY_ID_PRODUCT; private static final MemorySegment KEY_VENDOR; @@ -163,10 +166,8 @@ private void iterateDevices(int iterator, Consumer consumer) { consumer.accept(device); } catch (Exception e) { - System.err.printf( - "Info: [JavaDoesUSB] failed to retrieve information about device 0x%04x/0x%04x - ignoring device%n", - deviceInfo.vid, deviceInfo.pid); - e.printStackTrace(System.err); + LOG.log(INFO, String.format("failed to retrieve information about device 0x%04x/0x%04x - ignoring device", + deviceInfo.vid, deviceInfo.pid), e); } }); } @@ -268,8 +269,7 @@ private void onDevicesDisconnected(MemorySegment ignoredRefCon, int iterator) { try { ((MacosUSBDevice) device).closeFully(); } catch (Exception e) { - System.err.println("Info: [JavaDoesUSB] failed to close USB device - ignoring exception"); - e.printStackTrace(System.err); + LOG.log(INFO, "failed to close USB device - ignoring exception", e); } removeDevice(entryId); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 39c271ab..e9f05e69 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -34,6 +34,8 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import static java.lang.System.Logger.Level.DEBUG; +import static java.lang.System.Logger.Level.INFO; import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.usbstandard.Constants.*; @@ -54,6 +56,8 @@ */ public class WindowsUSBDeviceRegistry extends USBDeviceRegistry { + private static final System.Logger LOG = System.getLogger(WindowsUSBDeviceRegistry.class.getName()); + private static final long REQUEST_DATA_OFFSET = _USB_DESCRIPTOR_REQUEST.$LAYOUT().byteOffset(PathElement.groupElement("Data")); @@ -145,10 +149,7 @@ private void enumeratePresentDevices() { deviceList.add(createDeviceFromDeviceInfo(deviceInfoSet, devicePath, hubHandles)); } catch (Exception e) { - System.err.printf( - "Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring device%n", - devicePath); - e.printStackTrace(System.err); + LOG.log(INFO, String.format("failed to retrieve information about device %s - ignoring device", devicePath), e); } } @@ -200,6 +201,7 @@ private Map getChildDevices(DeviceInfoSet deviceInfoSet, String // sleep and retry try { + LOG.log(DEBUG, "Sleeping for 200ms (after unsuccessfully retrieving DEVPKEY_Device_Children)"); //noinspection BusyWait Thread.sleep(200); } catch (InterruptedException e) { @@ -208,9 +210,7 @@ private Map getChildDevices(DeviceInfoSet deviceInfoSet, String } if (childrenInstanceIDs == null) { - System.err.printf( - "Info: [JavaDoesUSB] unable to retrieve information about children of device %s - ignoring%n", - devicePath); + LOG.log(DEBUG, "unable to retrieve information about children of device {0} - ignoring", devicePath); return null; } @@ -367,10 +367,7 @@ private void onDeviceConnected(String devicePath) { addDevice(device); } catch (Exception e) { - System.err.printf( - "Info: [JavaDoesUSB] failed to retrieve information about device %s - ignoring device%n", - devicePath); - e.printStackTrace(System.err); + LOG.log(INFO, String.format("failed to retrieve information about device %s - ignoring device", devicePath), e); } } } @@ -415,12 +412,16 @@ private static Map.Entry getNumberPathTuple(String instanceId) if (hardwareIds == null) throwException("internal error (device property 'HardwareIds' is missing)"); var interfaceNumber = extractInterfaceNumber(hardwareIds); - if (interfaceNumber == -1) + if (interfaceNumber == -1) { + LOG.log(DEBUG, "Child device {0} has no interface number", instanceId); return null; + } var devicePath = deviceInfoSet.getDevicePathByGUID(instanceId); - if (devicePath == null) + if (devicePath == null) { + LOG.log(DEBUG, "Child device {0} has no device path", instanceId); return null; + } return new AbstractMap.SimpleImmutableEntry<>(interfaceNumber, devicePath); } From 2285e661b2fcf45ecdf615e01206d427d831d3a2 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 19 Sep 2023 22:00:19 +0200 Subject: [PATCH 285/433] Increase version to 0.6.0 --- examples/bulk_transfer/README.md | 2 +- examples/bulk_transfer/pom.xml | 4 ++-- examples/enumerate/README.md | 2 +- examples/enumerate/pom.xml | 4 ++-- examples/epaper_display/README.md | 4 ++-- examples/epaper_display/pom.xml | 4 ++-- examples/monitor/README.md | 2 +- examples/monitor/pom.xml | 4 ++-- examples/stm_dfu/README.md | 2 +- examples/stm_dfu/pom.xml | 4 ++-- java-does-usb/pom.xml | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index b7f63b11..f5a32e88 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] --------------< net.codecrete.usb.examples:bulk-transfer >-------------- -[INFO] Building bulk-transfer 0.5.1 +[INFO] Building bulk-transfer 0.6.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ bulk-transfer --- diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index ca51c5b7..fd9bbc9a 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples bulk-transfer - 0.6.0-SNAPSHOT + 0.6.0 bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.6.0-SNAPSHOT + 0.6.0 diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index 78867753..bb939075 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] ----------------< net.codecrete.usb.examples:enumerate >---------------- -[INFO] Building enumerate 0.5.1 +[INFO] Building enumerate 0.6.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ enumerate --- diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index 34048b3f..3fb8a871 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples enumerate - 0.6.0-SNAPSHOT + 0.6.0 enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.6.0-SNAPSHOT + 0.6.0 org.tinylog diff --git a/examples/epaper_display/README.md b/examples/epaper_display/README.md index c9d3b628..f484c05b 100644 --- a/examples/epaper_display/README.md +++ b/examples/epaper_display/README.md @@ -45,7 +45,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -------------< net.codecrete.usb.examples:epaper-display >-------------- -[INFO] Building epaper-display 0.5.1 +[INFO] Building epaper-display 0.6.0 [INFO] from pom.xml [INFO] --------------------------------[ jar ]--------------------------------- [INFO] @@ -81,6 +81,6 @@ $ sudo -i Password: $ cd /Users/me/Documents/JavaDoesUSB/examples/epaper_display $ export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-20.jdk/Contents/Home -$ $JAVA_HOME/bin/java --enable-preview --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/0.5.1/java-does-usb-0.5.1.jar net.codecrete.usb.examples.EPaperDisplay +$ $JAVA_HOME/bin/java --enable-preview --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/0.6.0/java-does-usb-0.6.0.jar net.codecrete.usb.examples.EPaperDisplay Display size: 1200 x 825 ``` diff --git a/examples/epaper_display/pom.xml b/examples/epaper_display/pom.xml index 697fdc5f..b5a33eb1 100644 --- a/examples/epaper_display/pom.xml +++ b/examples/epaper_display/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples epaper-display - 0.6.0-SNAPSHOT + 0.6.0 epaper-display https://github.com/manuelbl/JavaDoesUSB/examples/epaper_display @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.6.0-SNAPSHOT + 0.6.0 diff --git a/examples/monitor/README.md b/examples/monitor/README.md index 6c1c892b..44ff4348 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -----------------< net.codecrete.usb.examples:monitor >----------------- -[INFO] Building monitor 0.5.1 +[INFO] Building monitor 0.6.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ monitor --- diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index d94ef9a3..75d59896 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples monitor - 0.6.0-SNAPSHOT + 0.6.0 monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.6.0-SNAPSHOT + 0.6.0 org.tinylog diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index f2a6d308..8a430c5b 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -58,7 +58,7 @@ Run the command below (adapting the file path depending on your specific board): ```shell $ mvn package -$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.5.1.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin +$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.6.0.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin DFU device found with serial 35A737883336. Target memory segment: Internal Flash Erasing page at 0x8000000 (size 0x4000) diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index 5dcbc1de..a523f136 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples stm_dfu - 0.6.0-SNAPSHOT + 0.6.0 stm_dfu https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu @@ -19,7 +19,7 @@ net.codecrete.usb java-does-usb - 0.6.0-SNAPSHOT + 0.6.0 diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 32b756cf..30c4f9e1 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 0.6.0-SNAPSHOT + 0.6.0 21 From 923311f4507cfc3f7e0f5179d398702a621fe87f Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 24 Sep 2023 17:05:57 +0200 Subject: [PATCH 286/433] Windows: reference code closer to Java --- reference/windows/USB/USB.vcxproj | 4 +- reference/windows/USB/USB.vcxproj.filters | 12 +- reference/windows/USB/device_info_set.cpp | 245 +++++++++++++++++++ reference/windows/USB/device_info_set.h | 150 ++++++++++++ reference/windows/USB/usb_device.cpp | 12 +- reference/windows/USB/usb_device_info.cpp | 225 ------------------ reference/windows/USB/usb_device_info.hpp | 146 ------------ reference/windows/USB/usb_iostream.cpp | 4 +- reference/windows/USB/usb_registry.cpp | 275 ++++++++++++++-------- reference/windows/USB/usb_registry.hpp | 14 +- 10 files changed, 595 insertions(+), 492 deletions(-) create mode 100644 reference/windows/USB/device_info_set.cpp create mode 100644 reference/windows/USB/device_info_set.h delete mode 100644 reference/windows/USB/usb_device_info.cpp delete mode 100644 reference/windows/USB/usb_device_info.hpp diff --git a/reference/windows/USB/USB.vcxproj b/reference/windows/USB/USB.vcxproj index 62063b27..46f41a29 100644 --- a/reference/windows/USB/USB.vcxproj +++ b/reference/windows/USB/USB.vcxproj @@ -22,12 +22,12 @@ + - @@ -37,12 +37,12 @@ + - diff --git a/reference/windows/USB/USB.vcxproj.filters b/reference/windows/USB/USB.vcxproj.filters index 7de3d949..473ed8c6 100644 --- a/reference/windows/USB/USB.vcxproj.filters +++ b/reference/windows/USB/USB.vcxproj.filters @@ -33,9 +33,6 @@ Source Files - - Source Files - Source Files @@ -51,6 +48,9 @@ Source Files + + Source Files + @@ -71,9 +71,6 @@ Header Files - - Header Files - Header Files @@ -92,5 +89,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/reference/windows/USB/device_info_set.cpp b/reference/windows/USB/device_info_set.cpp new file mode 100644 index 00000000..6450ec20 --- /dev/null +++ b/reference/windows/USB/device_info_set.cpp @@ -0,0 +1,245 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for Windows +// + +#include "device_info_set.h" +#include "usb_error.hpp" +#include "scope.hpp" +#include + +device_info_set::device_info_set(HDEVINFO dev_info_set) + : dev_info_set_(dev_info_set), dev_info_data_({ sizeof(dev_intf_data_) }), + has_dev_intf_data_(false), dev_intf_data_({ sizeof(dev_intf_data_) }), iteration_index(-1) +{ +} + +device_info_set device_info_set::of_present_devices(const GUID& interface_guid, const std::wstring& instance_id) { + auto dev_info_set = SetupDiGetClassDevsW(&interface_guid, !instance_id.empty() ? instance_id.c_str() : nullptr, nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (dev_info_set == INVALID_HANDLE_VALUE) + usb_error::throw_error("internal error (SetupDiGetClassDevsW)"); + return device_info_set(dev_info_set); +} + +device_info_set device_info_set::of_instance(const std::wstring& instance_id) { + auto instance = of_empty(); + instance.add_instance(instance_id); + return instance; +} + +device_info_set device_info_set::of_path(const std::wstring& device_path) { + auto instance = of_empty(); + instance.add_device_path(device_path); + return instance; +} + +device_info_set device_info_set::of_empty() { + auto dev_info_set = SetupDiCreateDeviceInfoList(nullptr, nullptr); + if (dev_info_set == INVALID_HANDLE_VALUE) + usb_error::throw_error("internal error (SetupDiCreateDeviceInfoList)"); + return device_info_set(dev_info_set); +} + +device_info_set::device_info_set(device_info_set&& info_set) noexcept + : dev_info_set_(info_set.dev_info_set_), dev_info_data_(info_set.dev_info_data_), + has_dev_intf_data_(info_set.has_dev_intf_data_), dev_intf_data_(info_set.dev_intf_data_), + iteration_index(info_set.iteration_index) { + info_set.dev_info_set_ = INVALID_HANDLE_VALUE; + info_set.has_dev_intf_data_ = false; +} + +device_info_set::~device_info_set() { + if (dev_info_set_ == INVALID_HANDLE_VALUE) + return; + + if (has_dev_intf_data_) + SetupDiDeleteDeviceInterfaceData(dev_info_set_, &dev_intf_data_); + SetupDiDestroyDeviceInfoList(dev_info_set_); +} + +void device_info_set::add_instance(const std::wstring& instance_id) { + if (SetupDiOpenDeviceInfoW(dev_info_set_, instance_id.c_str(), nullptr, 0, &dev_info_data_) == 0) + throw usb_error("internal error (SetupDiOpenDeviceInfoW)", GetLastError()); +} + +void device_info_set::add_device_path(const std::wstring& device_path) { + if (has_dev_intf_data_) + throw usb_error("calling add_device_path() multiple times is not implemented"); + + // load device information into dev info set + if (SetupDiOpenDeviceInterfaceW(dev_info_set_, device_path.c_str(), 0, &dev_intf_data_) == 0) + usb_error::throw_error("internal error (SetupDiOpenDeviceInterfaceW)"); + has_dev_intf_data_ = true; + + if (SetupDiGetDeviceInterfaceDetailW(dev_info_set_, &dev_intf_data_, nullptr, 0, nullptr, &dev_info_data_) == 0) { + auto err = GetLastError(); + if (err != ERROR_INSUFFICIENT_BUFFER) + throw usb_error("internal error (SetupDiGetDeviceInterfaceDetailW)", err); + } +} + +bool device_info_set::next() { + iteration_index += 1; + + if (SetupDiEnumDeviceInfo(dev_info_set_, iteration_index, &dev_info_data_) == 0) { + auto err = GetLastError(); + if (err == ERROR_NO_MORE_ITEMS) + return false; + throw usb_error("internal error (SetupDiEnumDeviceInfo)", err); + } + + return true; +} + + +uint32_t device_info_set::get_device_property_int(const DEVPROPKEY& prop_key) { + // query property value + DEVPROPTYPE property_type; + uint32_t property_value = -1; + if (!SetupDiGetDevicePropertyW(dev_info_set_, &dev_info_data_, &prop_key, &property_type, reinterpret_cast(&property_value), sizeof(property_value), nullptr, 0)) + usb_error::throw_error("internal error (SetupDiGetDevicePropertyW)"); + + // check property type + if (property_type != DEVPROP_TYPE_UINT32) + throw usb_error("internal error (SetupDiGetDevicePropertyW)"); + + return property_value; +} + +std::vector device_info_set::get_device_property_variable_length(const DEVPROPKEY& prop_key, DEVPROPTYPE expected_type) { + + // query length + DWORD required_size = 0; + DEVPROPTYPE property_type; + if (!SetupDiGetDevicePropertyW(dev_info_set_, &dev_info_data_, &prop_key, &property_type, nullptr, 0, &required_size, 0)) { + DWORD err = GetLastError(); + if (err == ERROR_NOT_FOUND) + return {}; + if (err != ERROR_INSUFFICIENT_BUFFER) + throw usb_error("internal error (SetupDiGetDevicePropertyW)", err); + } + + // check property type + if (property_type != expected_type) + throw usb_error("internal error (SetupDiGetDevicePropertyW)"); + + // query property value + std::vector property_value; + property_value.resize(required_size); + if (!SetupDiGetDevicePropertyW(dev_info_set_, &dev_info_data_, &prop_key, &property_type, &property_value[0], required_size, nullptr, 0)) + usb_error::throw_error("internal error (SetupDiGetDevicePropertyW)"); + + return property_value; +} + +std::wstring device_info_set::get_device_property_string(const DEVPROPKEY& prop_key) { + + auto property_value = get_device_property_variable_length(prop_key, DEVPROP_TYPE_STRING); + if (property_value.size() == 0) + return L""; + return std::wstring(reinterpret_cast(&property_value[0])); +} + +std::vector device_info_set::get_device_property_string_list(const DEVPROPKEY& prop_key) { + auto property_value = get_device_property_variable_length(prop_key, DEVPROP_TYPE_STRING | DEVPROP_TYPEMOD_LIST); + if (property_value.size() == 0) + return {}; + return split_string_list(reinterpret_cast(&property_value[0])); +} + +std::vector device_info_set::split_string_list(const wchar_t* str_list_raw) { + std::vector str_list; + int offset = 0; + while (str_list_raw[offset] != L'\0') { + str_list.push_back(str_list_raw + offset); + offset += static_cast(str_list.back().length()) + 1; + } + + return str_list; +} + +bool device_info_set::is_composite_device() { + std::wstring device_service = get_device_property_string(DEVPKEY_Device_Service); + return lstrcmpiW(device_service.c_str(), L"usbccgp") == 0; +} + +std::wstring device_info_set::get_device_path(const std::wstring& instance_id, const GUID& interface_guid) { + + // get device info set for instance + HDEVINFO dev_info_set = SetupDiGetClassDevsW(&interface_guid, instance_id.c_str(), nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (dev_info_set == INVALID_HANDLE_VALUE) + usb_error::throw_error("internal error (SetupDiGetClassDevsW)"); + + // ensure the result is destroyed when the scope is left + auto dev_info_set_guard = make_scope_exit([dev_info_set]() { + SetupDiDestroyDeviceInfoList(dev_info_set); + }); + + // retrieve first element of enumeration + SP_DEVICE_INTERFACE_DATA dev_intf_data = { sizeof(dev_intf_data) }; + if (!SetupDiEnumDeviceInterfaces(dev_info_set, nullptr, &interface_guid, 0, &dev_intf_data)) + usb_error::throw_error("internal error (SetupDiEnumDeviceInterfaces)"); + + // retrieve path + uint8_t dev_path_buf[MAX_PATH * sizeof(WCHAR) + sizeof(DWORD)]; + memset(dev_path_buf, 0, sizeof(dev_path_buf)); + PSP_DEVICE_INTERFACE_DETAIL_DATA_W intf_detail_data = reinterpret_cast(dev_path_buf); + intf_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); + if (!SetupDiGetDeviceInterfaceDetailW(dev_info_set, &dev_intf_data, intf_detail_data, sizeof(dev_path_buf), nullptr, nullptr)) + throw usb_error("Internal error (SetupDiGetDeviceInterfaceDetailA)", GetLastError()); + + return intf_detail_data->DevicePath; +} + +std::wstring device_info_set::get_device_path_by_guid(const std::wstring& instance_id) { + auto device_guids = find_device_interface_guids(); + + CLSID clsid{}; + // use GUIDs to get device path + for (const std::wstring& guid : device_guids) { + if (CLSIDFromString(guid.c_str(), &clsid) != NOERROR) + continue; + + try { + return get_device_path(instance_id.c_str(), clsid); + } + catch (usb_error&) { + // ignore and try next one + } + } + + return {}; +} + +std::vector device_info_set::find_device_interface_guids() { + HKEY reg_key = SetupDiOpenDevRegKey(dev_info_set_, &dev_info_data_, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); + if (reg_key == INVALID_HANDLE_VALUE) + throw usb_error("Cannot open device registry key", GetLastError()); + + auto reg_key_guard = make_scope_exit([reg_key]() { + RegCloseKey(reg_key); + }); + + // read registry value (without buffer, to query length) + DWORD value_type = 0; + DWORD value_size = 0; + LSTATUS res = RegQueryValueExW(reg_key, L"DeviceInterfaceGUIDs", nullptr, &value_type, nullptr, &value_size); + if (res == ERROR_FILE_NOT_FOUND) + return std::vector(); + if (res != 0 && res != ERROR_MORE_DATA) + throw usb_error("Internal error (RegQueryValueExW)", res); + + std::vector str_list_raw; + str_list_raw.resize(value_size); + + // read registry value (with buffer) + res = RegQueryValueExW(reg_key, L"DeviceInterfaceGUIDs", nullptr, &value_type, &str_list_raw[0], &value_size); + if (res != 0) + throw usb_error("Internal error (RegQueryValueExW)", res); + + return split_string_list(reinterpret_cast(&str_list_raw[0])); +} diff --git a/reference/windows/USB/device_info_set.h b/reference/windows/USB/device_info_set.h new file mode 100644 index 00000000..60929951 --- /dev/null +++ b/reference/windows/USB/device_info_set.h @@ -0,0 +1,150 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Reference C++ code for Windows +// + +#pragma once + +#include +#include +#include +#undef min +#undef max +#undef LowSpeed +#include + +/** + * Device information set (of Windows Setup API). + * + * An instance of this class represents a device information set (DEVINFO) + * and a current element within the set. + */ +class device_info_set +{ +public: + /** + * Creates a new device info set containing the present devices of the specified device class and + * optionally device instance ID. + * + * After creation, there is no current element. `next()` should be called to iterate the first + * and all subsequent elements. + * + * @param interface_guid device interface class GUID + * @param instance_id device instance ID + * @return device info set + */ + static device_info_set of_present_devices(const GUID& interface_guid, const std::wstring& instance_id = L""); + + /** + * Creates a new device info set containing a single device with the specified instance ID. + * + * The device becomes the current element. The set cannot be iterated. + * + * @param instance_id instance ID + * @return device info set + */ + static device_info_set of_instance(const std::wstring& instance_id); + + /** + * Creates a new device info set containing a single device with the specified path. + * + * The device becomes the current element. The set cannot be iterated. + * + * @param device_path device path + * @return device info set + */ + static device_info_set of_path(const std::wstring& device_path); + + /** + * Creates a new empty device info set. + * + * @return device info set + */ + static device_info_set of_empty(); + + /** + * Iterates to the next element in this set. + * + * @return `true` if there is a current element, `false` if the iteration moved beyond the last element + */ + bool next(); + + /** + * Gets the integer device property of the current element. + * + * @param prop_key property key (`DEVPKEY_xxx`) + * @return property value + */ + uint32_t get_device_property_int(const DEVPROPKEY& prop_key); + + /** + * Gets the string device property of the current element. + * + * @param prop_key property key (`DEVPKEY_xxx`) + * @return property value + */ + std::wstring get_device_property_string(const DEVPROPKEY& prop_key); + + /** + * Gets the string list device property of the current element. + * + * @param prop_key property key (`DEVPKEY_xxx`) + * @return property value + */ + std::vector get_device_property_string_list(const DEVPROPKEY& prop_key); + + /** + * Checks if the current element is a composite device. + * + * @return `true` if it is a composite device + */ + bool is_composite_device(); + + device_info_set(device_info_set&& info_set) noexcept; + ~device_info_set(); + + /** + * Gets the device path for the device with the given device instance ID and device interface class. + * + * @param instance_id device instance ID + * @param interface_guid device interface class GUID + * @return the device path + */ + static std::wstring get_device_path(const std::wstring& instance_id, const GUID& interface_guid); + + /** + * Gets the device path for the device with the given instance ID. + * + * The device path is looked up by checking the GUIDs associated with the current element. + * + * @param instance_id device instance ID + * @return the device path, `nullptr` if not found + */ + std::wstring get_device_path_by_guid(const std::wstring& instance_id); + +private: + device_info_set(HDEVINFO dev_info_set); + device_info_set() = delete; + device_info_set(const device_info_set& info_set) = delete; + device_info_set& operator=(const device_info_set&) = delete; + device_info_set& operator=(device_info_set&& info_set) = delete; + + void add_instance(const std::wstring& instance_id); + void add_device_path(const std::wstring& device_path); + std::vector find_device_interface_guids(); + + std::vector get_device_property_variable_length(const DEVPROPKEY& prop_key, DEVPROPTYPE expected_type); + static std::vector split_string_list(const wchar_t* str_list_raw); + + + HDEVINFO dev_info_set_; + SP_DEVINFO_DATA dev_info_data_; + bool has_dev_intf_data_; + SP_DEVICE_INTERFACE_DATA dev_intf_data_; + int iteration_index; +}; + diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp index 436c23d2..3371d770 100644 --- a/reference/windows/USB/usb_device.cpp +++ b/reference/windows/USB/usb_device.cpp @@ -132,6 +132,7 @@ void usb_device::claim_interface(int interface_number) { // open device if needed if (first_intf_handle->device_handle == nullptr) { + std::wcerr << "opening device " << first_intf_handle->device_path << std::endl; first_intf_handle->device_handle = CreateFileW(first_intf_handle->device_path.c_str(), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, @@ -140,19 +141,20 @@ void usb_device::claim_interface(int interface_number) { FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr); if (first_intf_handle->device_handle == INVALID_HANDLE_VALUE) - usb_error::throw_error("Cannot open USB device"); + usb_error::throw_error("cannot open USB device"); registry_->add_to_completion_port(first_intf_handle->device_handle); } // open interface + std::wcerr << "opening interface for device " << first_intf_handle->device_path << std::endl; if (!WinUsb_Initialize(first_intf_handle->device_handle, &intf_handle->intf_handle)) { + auto err = GetLastError(); if (first_intf_handle->device_open_count == 0) { CloseHandle(first_intf_handle->device_handle); first_intf_handle->device_handle = nullptr; } - usb_error::throw_error("Cannot open USB device"); - return; + throw usb_error("cannot open USB device", err); } first_intf_handle->device_open_count += 1; @@ -416,7 +418,7 @@ void usb_device::submit_transfer_in(int endpoint_number, uint8_t* buffer, int bu DWORD err = GetLastError(); if (err == ERROR_IO_PENDING) return; - throw new usb_error("Failed to submit transfer IN", err); + throw usb_error("Failed to submit transfer IN", err); } } @@ -429,7 +431,7 @@ void usb_device::submit_transfer_out(int endpoint_number, uint8_t* data, int dat DWORD err = GetLastError(); if (err == ERROR_IO_PENDING) return; - throw new usb_error("Failed to submit transfer OUT", err); + throw usb_error("Failed to submit transfer OUT", err); } } diff --git a/reference/windows/USB/usb_device_info.cpp b/reference/windows/USB/usb_device_info.cpp deleted file mode 100644 index 1a4f9909..00000000 --- a/reference/windows/USB/usb_device_info.cpp +++ /dev/null @@ -1,225 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Reference C++ code for Windows -// - -#include "usb_device_info.hpp" -#include "scope.hpp" -#include "usb_error.hpp" -#include -#include -#include -#include - - -std::wstring usb_device_info::get_device_path(const std::wstring& instance_id, const GUID* interface_guid) { - - // get device info set for instance - HDEVINFO dev_info_set = SetupDiGetClassDevsW(interface_guid, instance_id.c_str(), nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); - if (dev_info_set == INVALID_HANDLE_VALUE) - usb_error::throw_error("internal error (SetupDiGetClassDevsW)"); - - // ensure the result is destroyed when the scope is left - auto dev_info_set_guard = make_scope_exit([dev_info_set]() { - SetupDiDestroyDeviceInfoList(dev_info_set); - }); - - // retrieve first element of enumeration - SP_DEVICE_INTERFACE_DATA dev_intf_data = { sizeof(dev_intf_data) }; - if (!SetupDiEnumDeviceInterfaces(dev_info_set, nullptr, interface_guid, 0, &dev_intf_data)) - usb_error::throw_error("internal error (SetupDiEnumDeviceInterfaces)"); - - // retrieve path - uint8_t dev_path_buf[MAX_PATH * sizeof(WCHAR) + sizeof(DWORD)]; - memset(dev_path_buf, 0, sizeof(dev_path_buf)); - PSP_DEVICE_INTERFACE_DETAIL_DATA_W intf_detail_data = reinterpret_cast(dev_path_buf); - intf_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); - if (!SetupDiGetDeviceInterfaceDetailW(dev_info_set, &dev_intf_data, intf_detail_data, sizeof(dev_path_buf), nullptr, nullptr)) - throw usb_error("Internal error (SetupDiGetDeviceInterfaceDetailA)", GetLastError()); - - return intf_detail_data->DevicePath; -} - -uint32_t usb_device_info::get_device_property_int(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { - // query property value - DEVPROPTYPE property_type; - uint32_t property_value = -1; - if (!SetupDiGetDevicePropertyW(dev_info_set, dev_info_data, prop_key, &property_type, reinterpret_cast(&property_value), sizeof(property_value), nullptr, 0)) - usb_error::throw_error("internal error (SetupDiGetDevicePropertyW)"); - - // check property type - if (property_type != DEVPROP_TYPE_UINT32) - throw usb_error("internal error (SetupDiGetDevicePropertyW)"); - - return property_value; -} - -std::vector usb_device_info::get_device_property_variable_length(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key, DEVPROPTYPE expected_type) { - - // query length - DWORD required_size = 0; - DEVPROPTYPE property_type; - if (!SetupDiGetDevicePropertyW(dev_info_set, dev_info_data, prop_key, &property_type, nullptr, 0, &required_size, 0)) { - DWORD err = GetLastError(); - if (err == ERROR_NOT_FOUND) - return {}; - if (err != ERROR_INSUFFICIENT_BUFFER) - throw usb_error("internal error (SetupDiGetDevicePropertyW)", err); - } - - // check property type - if (property_type != expected_type) - throw usb_error("internal error (SetupDiGetDevicePropertyW)"); - - // query property value - std::vector property_value; - property_value.resize(required_size); - if (!SetupDiGetDevicePropertyW(dev_info_set, dev_info_data, prop_key, &property_type, &property_value[0], required_size, nullptr, 0)) - usb_error::throw_error("internal error (SetupDiGetDevicePropertyW)"); - - return property_value; -} - -std::wstring usb_device_info::get_device_property_string(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { - - auto property_value = get_device_property_variable_length(dev_info_set, dev_info_data, prop_key, DEVPROP_TYPE_STRING); - if (property_value.size() == 0) - return L""; - return std::wstring(reinterpret_cast(&property_value[0])); -} - -std::vector usb_device_info::get_device_property_string_list(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key) { - auto property_value = get_device_property_variable_length(dev_info_set, dev_info_data, prop_key, DEVPROP_TYPE_STRING | DEVPROP_TYPEMOD_LIST); - if (property_value.size() == 0) - return {}; - return split_string_list(reinterpret_cast(&property_value[0])); -} - -std::vector usb_device_info::split_string_list(const wchar_t* str_list_raw) { - std::vector str_list; - int offset = 0; - while (str_list_raw[offset] != L'\0') { - str_list.push_back(str_list_raw + offset); - offset += static_cast(str_list.back().length()) + 1; - } - - return str_list; -} - -std::vector usb_device_info::get_descriptor(HANDLE hub_handle, ULONG usb_port_num, uint16_t descriptor_type, int index, int language_id, int request_size) { - int size = sizeof(USB_DESCRIPTOR_REQUEST) + (request_size != 0 ? request_size : 255); - uint8_t* descriptor_request_buffer = new uint8_t[size]; - auto dev_info_set_guard = make_scope_exit([descriptor_request_buffer]() { - delete[] descriptor_request_buffer; - }); - - // setup request data structure - USB_DESCRIPTOR_REQUEST* descriptor_request = reinterpret_cast(descriptor_request_buffer); - descriptor_request->ConnectionIndex = usb_port_num; - descriptor_request->SetupPacket.bmRequest = 0x80; // device-to-host / type standard / recipient device - descriptor_request->SetupPacket.bRequest = 0x06; // GET_DESCRIPTOR - descriptor_request->SetupPacket.wValue = (descriptor_type << 8) | index; - descriptor_request->SetupPacket.wIndex = language_id; - descriptor_request->SetupPacket.wLength = static_cast(size - sizeof(USB_DESCRIPTOR_REQUEST)); - - // get descriptor - DWORD bytesReturned = 0; - if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, descriptor_request, size, descriptor_request, size, &bytesReturned, nullptr)) - throw usb_error("Cannot retrieve descriptor (DeviceIoControl)", GetLastError()); - int data_size = bytesReturned - sizeof(USB_DESCRIPTOR_REQUEST); - - if (data_size <= 2) - throw usb_error("invalid descriptor"); - - // determine expected size of descriptor - int expected_size; - if (descriptor_type != USB_CONFIGURATION_DESCRIPTOR_TYPE) { - expected_size = descriptor_request->Data[0]; - } - else { - auto config_desc = reinterpret_cast(descriptor_request->Data); - expected_size = config_desc->wTotalLength; - } - - // check against effective size - if (data_size < expected_size) { - if (request_size != 0) - throw usb_error("Unexpected descriptor size"); - - // repeat with larger size - return get_descriptor(hub_handle, usb_port_num, descriptor_type, index, language_id, expected_size); - } - - return std::vector(descriptor_request->Data, descriptor_request->Data + data_size); -} - -std::string usb_device_info::get_string(HANDLE hub_handle, ULONG usb_port_num, int index) { - if (index == 0) - return ""; - - std::vector str_desc_raw = get_descriptor(hub_handle, usb_port_num, USB_STRING_DESCRIPTOR_TYPE, index, 0x0409); - USB_STRING_DESCRIPTOR* str_desc = reinterpret_cast(str_desc_raw.data()); - - // required length of UTF-8 string - int len = WideCharToMultiByte(CP_UTF8, 0, str_desc->bString, str_desc->bLength / 2 - 1, nullptr, 0, nullptr, nullptr); - - // convert to UTF-8 - std::string result; - result.resize(len, 'x'); - WideCharToMultiByte(CP_UTF8, 0, str_desc->bString, str_desc->bLength / 2 - 1, &result[0], len, nullptr, nullptr); - return result; -} - -bool usb_device_info::is_composite_device(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data) { - std::wstring device_service = usb_device_info::get_device_property_string(dev_info_set, dev_info_data, &DEVPKEY_Device_Service); - return lstrcmpiW(device_service.c_str(), L"usbccgp") == 0; -} - -static const std::wregex multiple_interface_pattern(L"USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); - -int usb_device_info::get_first_interface(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data) { - // Also see https://docs.microsoft.com/en-us/windows-hardware/drivers/install/standard-usb-identifiers#multiple-interface-usb-devices - - auto hardware_ids = usb_device_info::get_device_property_string_list(dev_info_set, dev_info_data, &DEVPKEY_Device_HardwareIds); - - for (const std::wstring& id : hardware_ids) { - auto matches = std::wsmatch{}; - if (std::regex_search(id, matches, multiple_interface_pattern)) - return std::stoul(matches[1].str(), nullptr, 16); - } - - return -1; -} - -std::vector usb_device_info::find_device_interface_guids(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data) { - HKEY reg_key = SetupDiOpenDevRegKey(dev_info_set, dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); - if (reg_key == INVALID_HANDLE_VALUE) - throw usb_error("Cannot open device registry key", GetLastError()); - - auto reg_key_guard = make_scope_exit([reg_key]() { - RegCloseKey(reg_key); - }); - - // read registry value (without buffer, to query length) - DWORD value_type = 0; - DWORD value_size = 0; - LSTATUS res = RegQueryValueExW(reg_key, L"DeviceInterfaceGUIDs", nullptr, &value_type, nullptr, &value_size); - if (res == ERROR_FILE_NOT_FOUND) - return std::vector(); - if (res != 0 && res != ERROR_MORE_DATA) - throw usb_error("Internal error (RegQueryValueExW)", res); - - std::vector str_list_raw; - str_list_raw.resize(value_size); - - // read registry value (with buffer) - res = RegQueryValueExW(reg_key, L"DeviceInterfaceGUIDs", nullptr, &value_type, &str_list_raw[0], &value_size); - if (res != 0) - throw usb_error("Internal error (RegQueryValueExW)", res); - - return split_string_list(reinterpret_cast(&str_list_raw[0])); -} diff --git a/reference/windows/USB/usb_device_info.hpp b/reference/windows/USB/usb_device_info.hpp deleted file mode 100644 index 5f5ab067..00000000 --- a/reference/windows/USB/usb_device_info.hpp +++ /dev/null @@ -1,146 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -// Reference C++ code for Windows -// - -#pragma once - -#include -#include -#include -#undef min -#undef max -#undef LowSpeed -#include - -///

-/// Helper class for querying device information. -/// -class usb_device_info -{ -private: - /// - /// Get a device property of integer type. - /// - /// handle of device information set containing the device - /// pointer to device information structure representing the device - /// property key - /// property integer value - static uint32_t get_device_property_int(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key); - - /// - /// Get a device property of string type. - /// - /// handle of device information set containing the device - /// pointer to device information structure representing the device - /// property key - /// property string value - static std::wstring get_device_property_string(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key); - - /// - /// Get a device property of variable length. - /// - /// handle of device information set containing the device - /// pointer to device information structure representing the device - /// property key - /// expected property type (use DEVPROP_TYPE_xxx constants) - /// property value as byte array - static std::vector get_device_property_variable_length(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key, DEVPROPTYPE expected_type); - - /// - /// Get a device property of string list type. - /// - /// handle of device information set containing the device - /// pointer to device information structure representing the device - /// property key - /// property value as vector of strings - static std::vector get_device_property_string_list(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY* prop_key); - - /// - /// Split the string list into a vector of strings - /// - /// The provides string list is a concatenation of null-terminated string, terminated with an additional zero-length string. - /// - /// - /// string list - /// vector of strings - static std::vector split_string_list(const wchar_t* string_list); - - /// - /// Get device path for the specified device instance and device interface class. - /// - /// device instance ID - /// device interface class GUID - /// device path - static std::wstring get_device_path(const std::wstring& instance_id, const GUID* interface_guid); - - /// - /// Get a USB descriptor. - /// - /// The descriptor is retrieved via the USB hub (the USB device's parent) so it can be - /// access for USB devices that are already opened by another application. - /// - /// - /// handle of USB hub - /// device's port number (at hub) - /// descriptor type (use USB_xxx_DESCRIPTOR_TYPE constants) - /// descriptor index - /// language ID - /// intial size to request - /// descriptor as byte array - static std::vector get_descriptor(HANDLE hub_handle, ULONG usb_port_num, uint16_t descriptor_type, int index, int language_id, int request_size = 0); - - /// - /// Get USB string with the specified index. - /// - /// The string descriptor is retrieved via the USB hub (the USB device's parent) so it can be - /// access for USB devices that are already opened by another application. - /// - /// - /// For string index 0, an empty string is returned. - /// - /// - /// handle of USB hub - /// device's port number (at hub) - /// string index - /// string - static std::string get_string(HANDLE hub_handle, ULONG usb_port_num, int index); - - /// - /// Query if device is a composite USB device. - /// - /// A composite device consists of multiple interfaces appearing as separate devices - /// in Windows. In the Setup API, they are represented as child devices. - /// - /// - /// handle of device information set containing the device - /// pointer to device information structure representing the device - /// true if device is a composite device, false otherwise - static bool is_composite_device(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data); - - /// - /// Get the number of the first USB interface. - /// - /// The first interface number is relevant for child devices of composite devices. - /// - /// - /// handle of device information set containing the device - /// pointer to device information structure representing the device - /// - static int get_first_interface(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data); - - /// - /// Get the device's interface GUIDs. - /// - /// handle of device information set containing the device - /// pointer to device information structure representing the device - /// vector of GUIDs - static std::vector find_device_interface_guids(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data); - - friend class usb_registry; -}; - diff --git a/reference/windows/USB/usb_iostream.cpp b/reference/windows/USB/usb_iostream.cpp index 20cb36d1..5d98701a 100644 --- a/reference/windows/USB/usb_iostream.cpp +++ b/reference/windows/USB/usb_iostream.cpp @@ -93,7 +93,7 @@ usb_istreambuf::int_type usb_istreambuf::underflow() { current_request = wait_for_request_completion(); if (current_request->result_code() != S_OK) - throw new usb_error("transfer IN failed", current_request->result_code()); + throw usb_error("transfer IN failed", current_request->result_code()); char* buf = reinterpret_cast(current_request->buffer); int size = current_request->result_size(); @@ -203,7 +203,7 @@ usb_ostreambuf::transfer_request* usb_ostreambuf::wait_for_available_transfer() // check for error DWORD result = request->result_code(); if (result != S_OK) - throw new usb_error("transfer OUT failed", result); + throw usb_error("transfer OUT failed", result); return request; } diff --git a/reference/windows/USB/usb_registry.cpp b/reference/windows/USB/usb_registry.cpp index bd64dd19..92ec3211 100644 --- a/reference/windows/USB/usb_registry.cpp +++ b/reference/windows/USB/usb_registry.cpp @@ -9,12 +9,13 @@ #include "usb_registry.hpp" #include "usb_device.hpp" -#include "usb_device_info.hpp" +#include "device_info_set.h" #include "usb_error.hpp" #include "scope.hpp" #include #include +#include #include #include @@ -125,56 +126,56 @@ void usb_registry::monitor() { void usb_registry::detect_present_devices() { - // get device information set of all USB devices present - HDEVINFO dev_info_set = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); - if (dev_info_set == INVALID_HANDLE_VALUE) - throw usb_error("internal error (SetupDiGetClassDevsA)", GetLastError()); + // get device information set of all present USB devices + auto dev_info_set = device_info_set::of_present_devices(GUID_DEVINTERFACE_USB_DEVICE); - // ensure the result id destroyed when the scope is left - auto dev_info_set_guard = make_scope_exit([dev_info_set]() { - SetupDiDestroyDeviceInfoList(dev_info_set); - }); + std::map hub_handles{}; - SP_DEVINFO_DATA dev_info_data = { sizeof(dev_info_data) }; + auto hub_handle_guard = make_scope_exit([&hub_handles]() { + for (auto& hub : hub_handles) + CloseHandle(hub.second); + }); // iterate over the set - for (int i = 0; ; i++) { - if (!SetupDiEnumDeviceInfo(dev_info_set, i, &dev_info_data)) { - DWORD err = GetLastError(); - if (err == ERROR_NO_MORE_ITEMS) - break; - throw usb_error("Internal error (SetupDiEnumDeviceInfo)", err); - } + while (dev_info_set.next()) { + + auto instance_id = dev_info_set.get_device_property_string(DEVPKEY_Device_InstanceId); + auto device_path = device_info_set::get_device_path(instance_id, GUID_DEVINTERFACE_USB_DEVICE); + + std::wcerr << "Device detected: InstanceId=" << instance_id << ", DevicePath=" << device_path << std::endl; // create new device - auto device = create_device(dev_info_set, &dev_info_data); + auto device = create_device_from_device_info(dev_info_set, std::move(device_path), hub_handles); devices.push_back(device); } } -std::shared_ptr usb_registry::create_device(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info_data) { - - DWORD usb_port_num = usb_device_info::get_device_property_int(dev_info_set, dev_info_data, &DEVPKEY_Device_Address); - std::wstring instance_id = usb_device_info::get_device_property_string(dev_info_set, dev_info_data, &DEVPKEY_Device_InstanceId); - std::wstring parent_instance_id = usb_device_info::get_device_property_string(dev_info_set, dev_info_data, &DEVPKEY_Device_Parent); - - std::wstring hub_path = usb_device_info::get_device_path(parent_instance_id, &GUID_DEVINTERFACE_USB_HUB); +std::shared_ptr usb_registry::create_device_from_device_info(device_info_set& dev_info_set, std::wstring&& device_path, std::map& hub_handles) { - // open parent (hub) - HANDLE hub_handle = CreateFileW(hub_path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); - if (hub_handle == INVALID_HANDLE_VALUE) - usb_error::throw_error("Cannot open USB hub"); + DWORD usb_port_num = dev_info_set.get_device_property_int(DEVPKEY_Device_Address); + std::wstring parent_instance_id = dev_info_set.get_device_property_string(DEVPKEY_Device_Parent); + std::wstring hub_path = device_info_set::get_device_path(parent_instance_id, GUID_DEVINTERFACE_USB_HUB); - auto hub_handle_guard = make_scope_exit([hub_handle]() { - CloseHandle(hub_handle); - }); + // open parent (hub) if not open + HANDLE hub_handle; + auto it = hub_handles.find(hub_path); + if (it != hub_handles.end()) { + hub_handle = it->second; + } + else { + hub_handle = CreateFileW(hub_path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); + if (hub_handle == INVALID_HANDLE_VALUE) + usb_error::throw_error("Cannot open USB hub"); + hub_handles[hub_path] = hub_handle; + } // check for composite device - std::map children{}; - if (usb_device_info::is_composite_device(dev_info_set, dev_info_data)) - children = enumerate_child_devices(usb_device_info::get_device_property_string_list(dev_info_set, dev_info_data, &DEVPKEY_Device_Children)); + auto children = get_child_devices(dev_info_set, device_path); - auto path = usb_device_info::get_device_path(instance_id, &GUID_DEVINTERFACE_USB_DEVICE); + return create_device(std::move(device_path), std::move(children), hub_handle, usb_port_num); +} + +std::shared_ptr usb_registry::create_device(std::wstring&& device_path, std::map&& children, HANDLE hub_handle, DWORD usb_port_num) { // get device descriptor USB_NODE_CONNECTION_INFORMATION_EX conn_info = { 0 }; @@ -183,66 +184,74 @@ std::shared_ptr usb_registry::create_device(HDEVINFO dev_info_set, S if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, sizeof(conn_info), &conn_info, sizeof(conn_info), &size, nullptr)) usb_error::throw_error("Internal error (cannot get device descriptor)"); + int vendorId = conn_info.DeviceDescriptor.idVendor; + int productId = conn_info.DeviceDescriptor.idProduct; + // get configuration descriptor - auto config_desc = usb_device_info::get_descriptor(hub_handle, usb_port_num, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0); + auto config_desc = get_descriptor(hub_handle, usb_port_num, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0); // Create new device - std::shared_ptr device(new usb_device(this, std::move(path), conn_info.DeviceDescriptor.idVendor, conn_info.DeviceDescriptor.idProduct, config_desc, std::move(children))); + // usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, std::map&& children + std::shared_ptr device(new usb_device(this, std::move(device_path), vendorId, productId, config_desc, std::move(children))); device->set_product_names( - usb_device_info::get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iManufacturer), - usb_device_info::get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iProduct), - usb_device_info::get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iSerialNumber) + get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iManufacturer), + get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iProduct), + get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iSerialNumber) ); return device; } -std::map usb_registry::enumerate_child_devices(const std::vector child_ids) { +std::map usb_registry::get_child_devices(device_info_set& dev_info_set, const std::wstring& device_path) { std::map children{}; - for (const std::wstring& child_instance_id : child_ids) { - HDEVINFO dev_info_set = SetupDiCreateDeviceInfoList(NULL, NULL); - if (dev_info_set == INVALID_HANDLE_VALUE) - throw usb_error("internal error (SetupDiCreateDeviceInfoList)", GetLastError()); + if (!dev_info_set.is_composite_device()) + return children; - // ensure the result id destroyed when the scope is left - auto dev_info_set_guard = make_scope_exit([dev_info_set]() { - SetupDiDestroyDeviceInfoList(dev_info_set); - }); + auto children_instance_ids = dev_info_set.get_device_property_string_list(DEVPKEY_Device_Children); + if (children_instance_ids.empty()) { + std::wcerr << "unable to retrieve information about children of device " << device_path << " - ignoring" << std::endl; + return children; + } - // get device info for child - SP_DEVINFO_DATA dev_info_data = { sizeof(dev_info_data) }; - if (!SetupDiOpenDeviceInfoW(dev_info_set, child_instance_id.c_str(), nullptr, 0, &dev_info_data)) - throw usb_error("internal error (SetupDiOpenDeviceInfoW)", GetLastError()); - - // get first interface number - int interface_number = usb_device_info::get_first_interface(dev_info_set, &dev_info_data); - if (interface_number == -1) - continue; - - // get device interface GUIDs - auto device_guids = usb_device_info::find_device_interface_guids(dev_info_set, &dev_info_data); - - CLSID clsid{}; - // use GUIDs to get device path - for (const std::wstring& guid : device_guids) { - if (CLSIDFromString(guid.c_str(), &clsid) != NOERROR) - continue; - - try { - auto device_path = usb_device_info::get_device_path(child_instance_id.c_str(), &clsid); - children[interface_number] = device_path; - break; - - } catch (usb_error&) { - // ignore and try next one - } - } + std::wcerr << "Children IDs: "; + for (auto it = children_instance_ids.begin(); it < children_instance_ids.end(); it++) { + if (it != children_instance_ids.begin()) + std::wcerr << ", "; + std::wcerr << *it; } + std::wcerr << std::endl; + + for (auto& child_id : children_instance_ids) + add_child_info(children, child_id); return children; } +void usb_registry::add_child_info(std::map& children, const std::wstring& child_id) { + + auto dev_info_set = device_info_set::of_instance(child_id); + + auto hardware_ids = dev_info_set.get_device_property_string_list(DEVPKEY_Device_HardwareIds); + if (hardware_ids.empty()) + return; + + auto intf_num = extract_interface_number(hardware_ids); + if (intf_num == -1) { + std::wcerr << "child device " << child_id << " has no interface number" << std::endl; + return; + } + + auto device_path = dev_info_set.get_device_path_by_guid(child_id); + if (device_path.empty()) { + std::wcerr << "child device " << child_id << " has no device path" << std::endl; + return; + } + + std::wcerr << "Child device: InteraceNumber=" << intf_num << ", DevicePath=" << device_path << std::endl; + + children[intf_num] = device_path; +} LRESULT usb_registry::handle_windows_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { @@ -292,35 +301,17 @@ void usb_registry::on_device_connected(const WCHAR* path) { usb_device_ptr device; try { - // create empty device information set - HDEVINFO dev_info_set = SetupDiCreateDeviceInfoList(NULL, NULL); - if (dev_info_set == INVALID_HANDLE_VALUE) - throw usb_error("internal error (SetupDiCreateDeviceInfoList)", GetLastError()); - - // ensure the result is destroyed when the scope is left - auto dev_info_set_guard = make_scope_exit([dev_info_set]() { - SetupDiDestroyDeviceInfoList(dev_info_set); - }); + // create device information set + auto dev_info_set = device_info_set::of_path(path); - // load device information into dev info set - SP_DEVICE_INTERFACE_DATA dev_intf_data = { sizeof(dev_intf_data) }; - if (!SetupDiOpenDeviceInterfaceW(dev_info_set, path, 0, &dev_intf_data)) - usb_error::throw_error("internal error (SetupDiOpenDeviceInterfaceW)"); - - auto dev_intf_data_guard = make_scope_exit([dev_info_set, &dev_intf_data]() { - SetupDiDeleteDeviceInterfaceData(dev_info_set, &dev_intf_data); + std::map hub_handles{}; + auto hub_handle_guard = make_scope_exit([&hub_handles]() { + for (auto& hub : hub_handles) + CloseHandle(hub.second); }); - // load device info data - SP_DEVINFO_DATA dev_info_data = { sizeof(dev_info_data) }; - if (!SetupDiGetDeviceInterfaceDetailW(dev_info_set, &dev_intf_data, nullptr, 0, nullptr, &dev_info_data)) { - DWORD err = GetLastError(); - if (err != ERROR_INSUFFICIENT_BUFFER) - throw usb_error("internal error (SetupDiGetDeviceInterfaceDetailW)", err); - } - // create new device - device = create_device(dev_info_set, &dev_info_data); + device = create_device_from_device_info(dev_info_set, path, hub_handles); devices.push_back(device); } catch (const std::exception& e) { @@ -436,3 +427,81 @@ usb_io_callback* usb_registry::get_completion_handler(OVERLAPPED* overlapped) { return it->second; } + +static const std::wregex multiple_interface_id_pattern(L"USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); + +int usb_registry::extract_interface_number(const std::vector& hardware_ids) { + // Also see https://docs.microsoft.com/en-us/windows-hardware/drivers/install/standard-usb-identifiers#multiple-interface-usb-devices + + for (auto& id : hardware_ids) { + auto matches = std::wsmatch{}; + if (std::regex_search(id, matches, multiple_interface_id_pattern)) + return std::stoul(matches[1].str(), nullptr, 16); + } + + return -1; +} + +std::vector usb_registry::get_descriptor(HANDLE hub_handle, ULONG usb_port_num, uint16_t descriptor_type, int index, int language_id, int request_size) { + int size = sizeof(USB_DESCRIPTOR_REQUEST) + (request_size != 0 ? request_size : 255); + uint8_t* descriptor_request_buffer = new uint8_t[size]; + auto dev_info_set_guard = make_scope_exit([descriptor_request_buffer]() { + delete[] descriptor_request_buffer; + }); + + // setup request data structure + USB_DESCRIPTOR_REQUEST* descriptor_request = reinterpret_cast(descriptor_request_buffer); + descriptor_request->ConnectionIndex = usb_port_num; + descriptor_request->SetupPacket.bmRequest = 0x80; // device-to-host / type standard / recipient device + descriptor_request->SetupPacket.bRequest = 0x06; // GET_DESCRIPTOR + descriptor_request->SetupPacket.wValue = (descriptor_type << 8) | index; + descriptor_request->SetupPacket.wIndex = language_id; + descriptor_request->SetupPacket.wLength = static_cast(size - sizeof(USB_DESCRIPTOR_REQUEST)); + + // get descriptor + DWORD bytesReturned = 0; + if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, descriptor_request, size, descriptor_request, size, &bytesReturned, nullptr)) + throw usb_error("Cannot retrieve descriptor (DeviceIoControl)", GetLastError()); + int data_size = bytesReturned - sizeof(USB_DESCRIPTOR_REQUEST); + + if (data_size <= 2) + throw usb_error("invalid descriptor"); + + // determine expected size of descriptor + int expected_size; + if (descriptor_type != USB_CONFIGURATION_DESCRIPTOR_TYPE) { + expected_size = descriptor_request->Data[0]; + } + else { + auto config_desc = reinterpret_cast(descriptor_request->Data); + expected_size = config_desc->wTotalLength; + } + + // check against effective size + if (data_size < expected_size) { + if (request_size != 0) + throw usb_error("Unexpected descriptor size"); + + // repeat with larger size + return get_descriptor(hub_handle, usb_port_num, descriptor_type, index, language_id, expected_size); + } + + return std::vector(descriptor_request->Data, descriptor_request->Data + data_size); +} + +std::string usb_registry::get_string(HANDLE hub_handle, ULONG usb_port_num, int index) { + if (index == 0) + return ""; + + std::vector str_desc_raw = get_descriptor(hub_handle, usb_port_num, USB_STRING_DESCRIPTOR_TYPE, index, 0x0409); + USB_STRING_DESCRIPTOR* str_desc = reinterpret_cast(str_desc_raw.data()); + + // required length of UTF-8 string + int len = WideCharToMultiByte(CP_UTF8, 0, str_desc->bString, str_desc->bLength / 2 - 1, nullptr, 0, nullptr, nullptr); + + // convert to UTF-8 + std::string result; + result.resize(len, 'x'); + WideCharToMultiByte(CP_UTF8, 0, str_desc->bString, str_desc->bLength / 2 - 1, &result[0], len, nullptr, nullptr); + return result; +} diff --git a/reference/windows/USB/usb_registry.hpp b/reference/windows/USB/usb_registry.hpp index fe66b060..9f10eff6 100644 --- a/reference/windows/USB/usb_registry.hpp +++ b/reference/windows/USB/usb_registry.hpp @@ -25,6 +25,8 @@ #undef LowSpeed #include +class device_info_set; + /** * Registry of connected USB devices. */ @@ -50,14 +52,20 @@ class usb_registry { void monitor(); void detect_present_devices(); - std::map enumerate_child_devices(const std::vector child_ids); - + std::map get_child_devices(device_info_set& dev_info_set, const std::wstring& device_path); + void add_child_info(std::map& children, const std::wstring& child_id); + std::shared_ptr create_device_from_device_info(device_info_set& dev_info_set, std::wstring&& device_path, std::map& hub_handles); + std::shared_ptr create_device(std::wstring&& device_path, std::map&& children, HANDLE hub_handle, DWORD usb_port_num); + + static std::string get_string(HANDLE hub_handle, ULONG usb_port_num, int index); + static std::vector get_descriptor(HANDLE hub_handle, ULONG usb_port_num, uint16_t descriptor_type, int index, int language_id, int request_size = 0); + static int extract_interface_number(const std::vector& hardware_ids); + void on_device_connected(const WCHAR* path); void on_device_disconnected(const WCHAR* path); bool handle_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static LRESULT handle_windows_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - std::shared_ptr create_device(HDEVINFO dev_info_set, SP_DEVINFO_DATA* dev_info); std::vector devices; From a02b612d45fcfade7091a567b204f4ca6e515a77 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 24 Sep 2023 20:00:24 +0200 Subject: [PATCH 287/433] Windows reference code: new approach for composite devices --- reference/windows/USB/usb_device.cpp | 146 ++++++++++++++++++++----- reference/windows/USB/usb_device.hpp | 10 +- reference/windows/USB/usb_error.cpp | 2 +- reference/windows/USB/usb_registry.cpp | 89 ++------------- reference/windows/USB/usb_registry.hpp | 4 +- 5 files changed, 140 insertions(+), 111 deletions(-) diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp index 3371d770..cf700124 100644 --- a/reference/windows/USB/usb_device.cpp +++ b/reference/windows/USB/usb_device.cpp @@ -10,21 +10,27 @@ #include "usb_device.hpp" #include "usb_error.hpp" #include "usb_iostream.hpp" +#include "device_info_set.h" #include "scope.hpp" #include "config_parser.hpp" #include "usb_registry.hpp" +#include + +#include #include +#include +#include -usb_device::usb_device(usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, std::map&& children) -: registry_(registry), vendor_id_(vendor_id), product_id_(product_id), is_open_(false), device_path_(std::move(device_path)) { +usb_device::usb_device(usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, bool is_composite) +: registry_(registry), vendor_id_(vendor_id), product_id_(product_id), is_open_(false), device_path_(std::move(device_path)), is_composite_(is_composite) { config_parser parser{}; parser.parse(config_desc.data(), static_cast(config_desc.size())); interfaces_ = std::move(parser.interfaces); functions_ = std::move(parser.functions); - build_handles(device_path_, std::move(children)); + build_handles(device_path_); } void usb_device::set_product_names(const std::string& manufacturer, const std::string& product, const std::string& serial_number) { @@ -33,19 +39,14 @@ void usb_device::set_product_names(const std::string& manufacturer, const std::s serial_number_ = serial_number; } -void usb_device::build_handles(const std::wstring& device_path, std::map&& children) { +void usb_device::build_handles(const std::wstring& device_path) { for (const usb_interface& intf : interfaces_) { int intf_number = intf.number(); auto function = get_function(intf_number); std::wstring path; - if (function->first_interface() == intf_number) { - if (children.size() > 0) { - path = std::move(children[intf_number]); - } else { - path = device_path; - } - } + if (intf_number == 0) + path = device_path; interface_handles_.push_back(interface_handle(intf_number, function->first_interface(), std::move(path))); } @@ -132,8 +133,13 @@ void usb_device::claim_interface(int interface_number) { // open device if needed if (first_intf_handle->device_handle == nullptr) { - std::wcerr << "opening device " << first_intf_handle->device_path << std::endl; - first_intf_handle->device_handle = CreateFileW(first_intf_handle->device_path.c_str(), + auto device_path = get_interface_device_path(first_intf_handle->interface_num); + if (device_path.empty()) + throw usb_error("failed to claim interface (function has no device path, might be missing WinUSB driver)"); + + std::wcerr << "opening device " << device_path << std::endl; + + first_intf_handle->device_handle = CreateFileW(device_path.c_str(), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, nullptr, @@ -143,21 +149,19 @@ void usb_device::claim_interface(int interface_number) { if (first_intf_handle->device_handle == INVALID_HANDLE_VALUE) usb_error::throw_error("cannot open USB device"); - registry_->add_to_completion_port(first_intf_handle->device_handle); - } - - // open interface - std::wcerr << "opening interface for device " << first_intf_handle->device_path << std::endl; - if (!WinUsb_Initialize(first_intf_handle->device_handle, &intf_handle->intf_handle)) { - auto err = GetLastError(); - if (first_intf_handle->device_open_count == 0) { + // open interface + if (!WinUsb_Initialize(first_intf_handle->device_handle, &first_intf_handle->intf_handle)) { + auto err = GetLastError(); CloseHandle(first_intf_handle->device_handle); first_intf_handle->device_handle = nullptr; + throw usb_error("cannot open USB device (2)", err); } - throw usb_error("cannot open USB device", err); + + registry_->add_to_completion_port(first_intf_handle->device_handle); } first_intf_handle->device_open_count += 1; + intf_handle->intf_handle = first_intf_handle->intf_handle; intf->set_claimed(true); } @@ -175,14 +179,13 @@ void usb_device::release_interface(int interface_number) { interface_handle* intf_handle = get_interface_handle(interface_number); interface_handle* first_intf_handle = get_interface_handle(intf_handle->first_interface_num); - // close interface - WinUsb_Free(intf_handle->intf_handle); intf_handle->intf_handle = nullptr; intf->set_claimed(false); // close device if needed first_intf_handle->device_open_count -= 1; if (first_intf_handle->device_open_count == 0) { + WinUsb_Free(first_intf_handle->intf_handle); CloseHandle(first_intf_handle->device_handle); first_intf_handle->device_handle = nullptr; } @@ -442,9 +445,102 @@ void usb_device::cancel_transfer(usb_direction direction, int endpoint_number, O usb_error::throw_error("Error on cancelling transfer"); } +std::wstring usb_device::get_interface_device_path(int interface_num) { + if (interface_num == 0) + return device_path_; + + auto it = interface_device_paths_.find(interface_num); + if (it != interface_device_paths_.end()) + return it->second; + + int num_retries = 30; // 30 x 100ms + + while (num_retries > 0) { + + auto dev_info_set = device_info_set::of_path(device_path_); + + if (!dev_info_set.is_composite_device()) + throw usb_error("internal error: interface belongs to a separate function but device is not composite"); + + auto children_instance_ids = dev_info_set.get_device_property_string_list(DEVPKEY_Device_Children); + if (children_instance_ids.empty()) { + std::wcerr << "missing children IDs for device " << device_path_ << std::endl; + + } else { + + std::wcerr << "children IDs: "; + for (auto it = children_instance_ids.begin(); it < children_instance_ids.end(); it++) { + if (it != children_instance_ids.begin()) + std::wcerr << ", "; + std::wcerr << *it; + } + std::wcerr << std::endl; + + std::wstring child_path; + for (auto& child_id : children_instance_ids) { + auto res = get_child_device_path(child_id, interface_num, child_path); + if (res == 1) + return child_path; + if (res == -1) + break; + } + } + + std::cerr << "Sleeping for 100ms..." << std::endl; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + num_retries -= 1; + } + + return {}; +} + +int usb_device::get_child_device_path(const std::wstring& child_id, int interface_num, std::wstring& device_path) { + + auto dev_info_set = device_info_set::of_instance(child_id); + + auto hardware_ids = dev_info_set.get_device_property_string_list(DEVPKEY_Device_HardwareIds); + if (hardware_ids.empty()) { + std::wcerr << "child device " << child_id << " has no hardware IDs" << std::endl; + return 0; + } + + auto intf_num = extract_interface_number(hardware_ids); + if (intf_num == -1) { + std::wcerr << "child device " << child_id << " has no interface number" << std::endl; + return 0; + } + + if (intf_num != interface_num) + return 0; + + device_path = dev_info_set.get_device_path_by_guid(child_id); + if (device_path.empty()) { + std::wcerr << "child device " << child_id << " has no device path" << std::endl; + return -1; + } + + std::wcerr << "child device: interface=" << intf_num << ", device path=" << device_path << std::endl; + interface_device_paths_[interface_num] = device_path; + return 1; +} + +static const std::wregex multiple_interface_id_pattern(L"USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); + +int usb_device::extract_interface_number(const std::vector& hardware_ids) { + // Also see https://docs.microsoft.com/en-us/windows-hardware/drivers/install/standard-usb-identifiers#multiple-interface-usb-devices + + for (auto& id : hardware_ids) { + auto matches = std::wsmatch{}; + if (std::regex_search(id, matches, multiple_interface_id_pattern)) + return std::stoul(matches[1].str(), nullptr, 16); + } + + return -1; +} + // --- interface_handle usb_device::interface_handle::interface_handle(int intf_num, int first_num, std::wstring&& path) - : interface_num(intf_num), first_interface_num(first_num), device_path(std::move(path)), + : interface_num(intf_num), first_interface_num(first_num), device_handle(nullptr), intf_handle(nullptr), device_open_count(0) { } diff --git a/reference/windows/USB/usb_device.hpp b/reference/windows/USB/usb_device.hpp index e4168021..18a69dec 100644 --- a/reference/windows/USB/usb_device.hpp +++ b/reference/windows/USB/usb_device.hpp @@ -241,7 +241,6 @@ class usb_device { struct interface_handle { int interface_num; int first_interface_num; - std::wstring device_path; HANDLE device_handle; WINUSB_INTERFACE_HANDLE intf_handle; int device_open_count; @@ -249,9 +248,12 @@ class usb_device { interface_handle(int intf_num, int first_num, std::wstring&& path); }; - usb_device(usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, std::map&& children); + usb_device(usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, bool is_composite); void set_product_names(const std::string& manufacturer, const std::string& product, const std::string& serial_number); - void build_handles(const std::wstring& device_path, std::map&& children); + void build_handles(const std::wstring& device_path); + std::wstring get_interface_device_path(int interface_num); + int get_child_device_path(const std::wstring& child_id, int interface_num, std::wstring& device_path); + static int extract_interface_number(const std::vector& hardware_ids); int control_transfer_core(const usb_control_request& request, uint8_t* data, int timeout); usb_composite_function* get_function(int intf_number); @@ -286,6 +288,8 @@ class usb_device { std::vector interfaces_; std::vector functions_; std::vector interface_handles_; + std::map interface_device_paths_; + bool is_composite_; friend class usb_registry; friend class usb_istreambuf; diff --git a/reference/windows/USB/usb_error.cpp b/reference/windows/USB/usb_error.cpp index c57e0a8b..2c5da8e4 100644 --- a/reference/windows/USB/usb_error.cpp +++ b/reference/windows/USB/usb_error.cpp @@ -36,7 +36,7 @@ std::string usb_error::full_message(const char* message, int code) { LPSTR messageBuffer = nullptr; size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, code, 0, (LPSTR)&messageBuffer, 0, NULL); + nullptr, code, 0, (LPSTR)&messageBuffer, 0, nullptr); while (size > 0 && (messageBuffer[size - 1] == L'\r' || messageBuffer[size - 1] == '\n')) size--; diff --git a/reference/windows/USB/usb_registry.cpp b/reference/windows/USB/usb_registry.cpp index 92ec3211..a92a1fbf 100644 --- a/reference/windows/USB/usb_registry.cpp +++ b/reference/windows/USB/usb_registry.cpp @@ -15,7 +15,6 @@ #include #include -#include #include #include @@ -27,7 +26,6 @@ #pragma comment (lib, "SetupAPI.lib") #pragma comment (lib, "Winusb.lib") - usb_registry::usb_registry() : on_connected_callback(nullptr), on_disconnected_callback(nullptr), is_device_list_ready(false), monitor_thread_id_(0), message_window(nullptr), @@ -108,7 +106,7 @@ void usb_registry::monitor() { notification_filter.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE; HDEVNOTIFY notify_handle = RegisterDeviceNotificationW(message_window, ¬ification_filter, DEVICE_NOTIFY_WINDOW_HANDLE /* | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES */); - if (notify_handle == NULL) + if (notify_handle == nullptr) usb_error::throw_error("internal error (RegisterDeviceNotificationW)"); auto notify_handle_guard = make_scope_exit([notify_handle]() { UnregisterDeviceNotification(notify_handle); }); @@ -142,7 +140,7 @@ void usb_registry::detect_present_devices() { auto instance_id = dev_info_set.get_device_property_string(DEVPKEY_Device_InstanceId); auto device_path = device_info_set::get_device_path(instance_id, GUID_DEVINTERFACE_USB_DEVICE); - std::wcerr << "Device detected: InstanceId=" << instance_id << ", DevicePath=" << device_path << std::endl; + std::wcerr << "Device present: InstanceId=" << instance_id << ", DevicePath=" << device_path << std::endl; // create new device auto device = create_device_from_device_info(dev_info_set, std::move(device_path), hub_handles); @@ -169,13 +167,10 @@ std::shared_ptr usb_registry::create_device_from_device_info(device_ hub_handles[hub_path] = hub_handle; } - // check for composite device - auto children = get_child_devices(dev_info_set, device_path); - - return create_device(std::move(device_path), std::move(children), hub_handle, usb_port_num); + return create_device(std::move(device_path), dev_info_set.is_composite_device(), hub_handle, usb_port_num); } -std::shared_ptr usb_registry::create_device(std::wstring&& device_path, std::map&& children, HANDLE hub_handle, DWORD usb_port_num) { +std::shared_ptr usb_registry::create_device(std::wstring&& device_path, bool is_composite, HANDLE hub_handle, DWORD usb_port_num) { // get device descriptor USB_NODE_CONNECTION_INFORMATION_EX conn_info = { 0 }; @@ -192,7 +187,7 @@ std::shared_ptr usb_registry::create_device(std::wstring&& device_pa // Create new device // usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, std::map&& children - std::shared_ptr device(new usb_device(this, std::move(device_path), vendorId, productId, config_desc, std::move(children))); + std::shared_ptr device(new usb_device(this, std::move(device_path), vendorId, productId, config_desc, is_composite)); device->set_product_names( get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iManufacturer), get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iProduct), @@ -201,58 +196,6 @@ std::shared_ptr usb_registry::create_device(std::wstring&& device_pa return device; } -std::map usb_registry::get_child_devices(device_info_set& dev_info_set, const std::wstring& device_path) { - - std::map children{}; - - if (!dev_info_set.is_composite_device()) - return children; - - auto children_instance_ids = dev_info_set.get_device_property_string_list(DEVPKEY_Device_Children); - if (children_instance_ids.empty()) { - std::wcerr << "unable to retrieve information about children of device " << device_path << " - ignoring" << std::endl; - return children; - } - - std::wcerr << "Children IDs: "; - for (auto it = children_instance_ids.begin(); it < children_instance_ids.end(); it++) { - if (it != children_instance_ids.begin()) - std::wcerr << ", "; - std::wcerr << *it; - } - std::wcerr << std::endl; - - for (auto& child_id : children_instance_ids) - add_child_info(children, child_id); - - return children; -} - -void usb_registry::add_child_info(std::map& children, const std::wstring& child_id) { - - auto dev_info_set = device_info_set::of_instance(child_id); - - auto hardware_ids = dev_info_set.get_device_property_string_list(DEVPKEY_Device_HardwareIds); - if (hardware_ids.empty()) - return; - - auto intf_num = extract_interface_number(hardware_ids); - if (intf_num == -1) { - std::wcerr << "child device " << child_id << " has no interface number" << std::endl; - return; - } - - auto device_path = dev_info_set.get_device_path_by_guid(child_id); - if (device_path.empty()) { - std::wcerr << "child device " << child_id << " has no device path" << std::endl; - return; - } - - std::wcerr << "Child device: InteraceNumber=" << intf_num << ", DevicePath=" << device_path << std::endl; - - children[intf_num] = device_path; -} - LRESULT usb_registry::handle_windows_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { usb_registry* self = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); @@ -262,19 +205,19 @@ LRESULT usb_registry::handle_windows_message(HWND hWnd, UINT uMsg, WPARAM wParam CREATESTRUCT* cs = reinterpret_cast(lParam); self = reinterpret_cast(cs->lpCreateParams); SetLastError(ERROR_SUCCESS); - LONG_PTR result = SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast(self)); + LONG_PTR result = SetWindowLongPtrW(hWnd, GWLP_USERDATA, reinterpret_cast(self)); break; } case WM_DESTROY: { - LONG_PTR result = SetWindowLongPtr(hWnd, GWLP_USERDATA, NULL); + LONG_PTR result = SetWindowLongPtrW(hWnd, GWLP_USERDATA, NULL); PostQuitMessage(0); break; } } if (self != nullptr && self->handle_message(hWnd, uMsg, wParam, lParam)) - return NULL; + return 0; return DefWindowProcW(hWnd, uMsg, wParam, lParam); } @@ -290,8 +233,10 @@ bool usb_registry::handle_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lP DEV_BROADCAST_DEVICEINTERFACE_W* broadcast = reinterpret_cast(lParam); if (wParam == DBT_DEVICEARRIVAL) { + std::wcerr << "Device added: DevicePath=" << broadcast->dbcc_name << std::endl; on_device_connected(broadcast->dbcc_name); } else { + std::wcerr << "Device removed: DevicePath=" << broadcast->dbcc_name << std::endl; on_device_disconnected(broadcast->dbcc_name); } return true; @@ -428,20 +373,6 @@ usb_io_callback* usb_registry::get_completion_handler(OVERLAPPED* overlapped) { return it->second; } -static const std::wregex multiple_interface_id_pattern(L"USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); - -int usb_registry::extract_interface_number(const std::vector& hardware_ids) { - // Also see https://docs.microsoft.com/en-us/windows-hardware/drivers/install/standard-usb-identifiers#multiple-interface-usb-devices - - for (auto& id : hardware_ids) { - auto matches = std::wsmatch{}; - if (std::regex_search(id, matches, multiple_interface_id_pattern)) - return std::stoul(matches[1].str(), nullptr, 16); - } - - return -1; -} - std::vector usb_registry::get_descriptor(HANDLE hub_handle, ULONG usb_port_num, uint16_t descriptor_type, int index, int language_id, int request_size) { int size = sizeof(USB_DESCRIPTOR_REQUEST) + (request_size != 0 ? request_size : 255); uint8_t* descriptor_request_buffer = new uint8_t[size]; diff --git a/reference/windows/USB/usb_registry.hpp b/reference/windows/USB/usb_registry.hpp index 9f10eff6..6ba0f946 100644 --- a/reference/windows/USB/usb_registry.hpp +++ b/reference/windows/USB/usb_registry.hpp @@ -52,10 +52,8 @@ class usb_registry { void monitor(); void detect_present_devices(); - std::map get_child_devices(device_info_set& dev_info_set, const std::wstring& device_path); - void add_child_info(std::map& children, const std::wstring& child_id); std::shared_ptr create_device_from_device_info(device_info_set& dev_info_set, std::wstring&& device_path, std::map& hub_handles); - std::shared_ptr create_device(std::wstring&& device_path, std::map&& children, HANDLE hub_handle, DWORD usb_port_num); + std::shared_ptr create_device(std::wstring&& device_path, bool is_composite, HANDLE hub_handle, DWORD usb_port_num); static std::string get_string(HANDLE hub_handle, ULONG usb_port_num, int index); static std::vector get_descriptor(HANDLE hub_handle, ULONG usb_port_num, uint16_t descriptor_type, int index, int language_id, int request_size = 0); From c0bbe3bff827e4fc5bc9bd0688006686334ff3c2 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 25 Sep 2023 22:49:21 +0200 Subject: [PATCH 288/433] Enhanced test devices --- .../codecrete/usb/ControlTransferTest.java | 14 +++++++++ .../net/codecrete/usb/DescriptionTest.java | 14 ++++----- .../net/codecrete/usb/TestDeviceBase.java | 2 +- .../composite-stm32/bin/blackpill-f401cc.bin | Bin 11664 -> 11756 bytes .../composite-stm32/bin/blackpill-f411ce.bin | Bin 11668 -> 11760 bytes .../composite-stm32/bin/bluepill-f103c8.bin | Bin 12152 -> 12244 bytes test-devices/composite-stm32/platformio.ini | 2 ++ test-devices/composite-stm32/src/main.c | 26 +++++++++++++--- .../composite-stm32/src/usb_descriptors.c | 21 +++++++------ .../composite-stm32/src/usb_descriptors.h | 23 +++++++++++++- .../composite-stm32/src/vendor_custom.c | 29 ++++++++++-------- .../composite-stm32/src/vendor_custom.h | 4 +++ .../loopback-stm32/bin/blackpill-f401cc.bin | Bin 10956 -> 10984 bytes .../loopback-stm32/bin/blackpill-f411ce.bin | Bin 10960 -> 10988 bytes .../loopback-stm32/bin/bluepill-f103c8.bin | Bin 11100 -> 11128 bytes .../loopback-stm32/bin/disco_f723ie.bin | Bin 11744 -> 11772 bytes test-devices/loopback-stm32/src/main.c | 26 +++++++++++++--- 17 files changed, 120 insertions(+), 41 deletions(-) diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java index f355a044..98131c4e 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java @@ -12,6 +12,7 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests control transfers @@ -38,4 +39,17 @@ void storeValueInDataStage_canBeRetrieved() { var retrievedValue = testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) interfaceNumber), 4); assertArrayEquals(sentValue, retrievedValue); } + + @Test + void interfaceNumber_canBeRetrieved() { + var response = testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x05, (short) 0, (short) interfaceNumber), 1); + assertEquals(interfaceNumber, response[0] & 0xff); + + if (isCompositeDevce()) { + testDevice.claimInterface(2); + response = testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x05, (short) 0, (short) 2), 1); + assertEquals(2, response[0] & 0xff); + testDevice.releaseInterface(2); + } + } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index 122d9832..fc443c50 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -24,16 +24,16 @@ void deviceInfo_isCorrect() { assertEquals(isLoopbackDevice() ? "Loopback" : "Composite", testDevice.product()); assertEquals(12, testDevice.serialNumber().length()); - if (interfaceNumber == 2) { - // composite device - assertEquals(0xef, testDevice.classCode()); - assertEquals(0x02, testDevice.subclassCode()); - assertEquals(0x01, testDevice.protocolCode()); - } else { + if (isLoopbackDevice()) { // simple device assertEquals(0xff, testDevice.classCode()); assertEquals(0x00, testDevice.subclassCode()); assertEquals(0x00, testDevice.protocolCode()); + } else { + // composite device + assertEquals(0xef, testDevice.classCode()); + assertEquals(0x02, testDevice.subclassCode()); + assertEquals(0x01, testDevice.protocolCode()); } var isComposite = isCompositeDevce(); @@ -132,7 +132,7 @@ void endpointDescriptors_areCorrect() { @Test void configurationDescription_isAvailable() { - var expectedLength = isLoopbackDevice() ? 69 : 98; + var expectedLength = isLoopbackDevice() ? 69 : 115; var configDesc = testDevice.configurationDescriptor(); assertNotNull(configDesc); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index e13a4e40..34c5f338 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -41,7 +41,7 @@ public class TestDeviceBase { /** * Composite test device loopback interface number */ - static final int LOOPBACK_INTF_COMPOSITE = 2; + static final int LOOPBACK_INTF_COMPOSITE = 3; /** * Interface number of connected test device */ diff --git a/test-devices/composite-stm32/bin/blackpill-f401cc.bin b/test-devices/composite-stm32/bin/blackpill-f401cc.bin index c2fc3f0fa080f30193757440eefc8cab83324edf..1df99e219a50ca704741324be6f6161601b5ec96 100755 GIT binary patch delta 1223 zcmZuvZ%kWN6hHU9S9)70V-zg3Y`uj!x;=;_3vNaY1-1vQTX5oxgb+Y9(>SvxN&+#a zOqWPuFZjD;S9J4<>yh!~#p~T(+{{mWN2%BJJ}&)_wEl{m%KF zd(Qiv^X|JJxBb;NehuxJ5dq^M@3u|wO?>0n2K3_)utnH2LuFKN`g|Ld>q$=o03u=P z;3$d&g4|OaTBUb|n%1#t0DCaI5&1#!q(cdzs(a!C0!lRLnqm>*KI=dD)pUQUwiiz7 z#@iFZza=~n9K?;F%%^Ic#wEmZbIGbHSE-D(Q$%7~Y0HUbMXdq{ zQa(+v*_7F2=Y*@2^K1O)BFgR6Q2${7mkVvnfmnNrtCOw9(XP~oP;V6AFeF;KwOjexL@>HI~@{I z{@&upt3r>mf2`c`3F0mJiQ^8*$#UCUO6*bQ=JI-M_@y0*-*zN^k#pJLucfrYTbZJn zcBc^pd=a80Si2NG6Q~~S^foKPf%6JbndK!GRR$sq+kY%*U zn(;~ciQb+sIP)XfZsW<81aT2bjmNj?kNVQR?^Xi#Gtbq@!af6Bo4yp0Y zG|j?JZ-GjrybzG>7?!qTeOZ7j?tRTa^*a6AKe$)Q6z8akO zWp-2FSkW&m!uN6vrj@`DUNM+j^?Q(7ycJC`#MRr%`KQ!ra3nOv^3jQ4953 zyidlgfEO9YEP#K=_`xE;e1?C?__y?AQ9J6SSBh%TUb9C=Vby$iDCOOtT;z zDSr0UY4)C%;S$3X)6@{i>^+YE&v&qzbbK_OU&cwssMif*%|HHc((%i*(rQCPw8?5m z1A#ZK@1f$c)S0_EZd>oN-n-d-HE*Z1<7zs7g{Ev}g%fNX$SiHd^DG_;RG0kDp&Qg> zUtspOUDP-^#B43GG22co=tiK2bRgyy9fz5trm_}hyUH#yyRPxTv3(m%B=AhRSup*? zuEJx?(^l~#{v8nL9Z@R4*&L?=2nK-zU<3>TPb(@Ox=)-t=XtfO`z_K`dvs^OQ%s|s zVV(nWhItbPyo;fW;Q+&K2CeXUBj5psAVX_5;KCgGa^?PlYBOM`4oDv4?8s@o{sTfd Bt=|9u delta 1130 zcmZuuZ)jUp6hHU9m*zHYXV=4m;kugxl(2bSJY?_AAX)J6XMCgaS4so@0Mr3B9t#4$QJZXGzn943s9tuq!V1iM?OuV2q{!7sGFYtE8)DbRD$IdZY({us69^ z;N+7;Qg~D#U+`N}@P(7}0G?!3FPQ?ZzmzIS?L+Z*7-(1Z&>Ut=I6b!Q!u(jXxi_O* zrVkdRf88Q5nxws;T`C3xwk3kK^LqPSs9EYGEOncPKzommSX!QVuE-SRDmCohs~PR! zC0ewA+O%`}p?IiSm@?ywx-cauX0)!G_A+0xbds;RtHQJ0S)AAzn3oiH{OpVk=Y3T) z@<$CLKVf`UVN(Oh{g^H&fjOe2Ztn=08vXpW3h!tnX;HQ)y{bKWE!SxmWUD$573D|L zmK#Lglon)H8rV}AN#2(3mUWd+TIIi0=d)hLexfn+kq+%3uPtAn1o;oOKHNX)Jmf|G zNQh{QS2n6YFaJ6z$t&t6JQFC_R?0Q?NA28EV3M|AFBX2G8->l6Kx!Zt7 zdLlhkp-G2wtx`-Id51w5O&NKM!MD=D5x>Ed+7z($ELHx=#wvie{jPO}V}?AY)F@&a z{0!x5kPkJClVN_VVf5jPPN1g| zZ!`csUiSMMfqv`Q*n1V@QGTNFAbFi<8-t{kw>Zw$@5ce!DrDZrU)WV17UMrTp5Es` zjxNLyVgxx&yj9-2pZ}ltVNWSPQ>ya`iY+r5203_l>QX5m=dU#6;#KsKp20+%y-3JlVsrD8=y;!R0PUx~574&xF;0y8b4Z&w)?$}xjv~u_MEJ+@ zyW$ZLxu;bTD0OI#K>&cq-7SYSWML_TVRO{f^bAI_Qdg2eJ+>@-_PaPuOPwn%$Dmv#TV$@4zX zx#v00``&v#IjNi+`x>EH5=ItU7f@5-=i8u6ru`lOM);ZRVF+3YhMA`r^e0*6>MKX5 z0j#0?7BmcsKO0GLuI}*<1W@9nL1%PE)4DNViu<>U1p$X}3n;fT^$x=#qK?_LE9|b} zT9FXBhuxqIlk>WL2hL;!iJs1yjlkOaM*D%AH{vpi_Gm@svTUuQp zzv>#$60zo4_t#}EHaey`scQV%gn{;3%&5sTs+zp04(1tT2hDyl%}9ay zxK`dv8z}c7-cP^p&0MoExnB9~v6tz&3lxJC5t^xCGWYJ$`v16_da}u(Y^j}*4DmiM zi1q&rf0<3vyE0o)KRIf)qD#TI%Ifan1|Kd}1!e)!7w>{f@HVGex=t z6PgP43LS{jqU|6hQetnX^_2Yzt(%$-w(j1b(ZT2U8M(q+H183j#3z2lz5^Udh*BBO zXBZWL({l^}6`;;Mb%J#zM}|JAPU(?V-Q^Um1EX-1cp!+>y_atQ`(q&P+4q$sD* jj130Bmnp&&zI?!y1>_ay-m*hRzz!V<#Za&lr}g>|N_D7h delta 1080 zcmZuuZD?Cn7=F)9ZgZM8vnH+i)SNV#4ZE#IhbU@Ex^*|1v5u}xkTF&^NB!YP1{PCB zsnLlkA~KI6B14Nh3}ai{EY7HL=zfX&k!%d-+G(apR)^)5Y^KpB*Y`H@pBJ9zeb0HH z^PK12tL%Pf_v{yhBzcxNkuQ<0rl~bh&QxPz0D;B%MuC%$(plkNfz0wHeb9d7EPy-H z79lB6cGh#N`oR9VR~RVY@d44&H(wQJ_pIvwap{2342^(tvKI6ke z<*w5ZC~xqD*z>>>H74Wfy7loLiW&e9QR1tB>QAeqbD?e_rS-?FLQ0UeZmp{E8Gcn9 zAYXHLi+i)9c6f{btX_7_&CDC|zOQO(!f?~;$MMgM|e60mIhY2YZ1+Bo_WvYSeFe*5Eel{N~GTQRC3a zDhn}Ltr%+j4@37|tPf}`91ByKX6*90R$X4L*j2)4POXS4-$ecUd@7SWa=_L~RQ|g( z*#fk0Ng0SvsM5=_N!I1T$1t#xXpi4E(LQ+0wj=wr^RxIT^P0g*$r~p@*Wk_4=`H08 z9yx>`*jERCxgbQH&ny^8fSxA6W)TsdHD4pk`~%A_(w|OA zibwDjwl^=EDc@ zdffG+Kt}nH`y#T3Nm|b~BPW;>`6#oJ(R7CGC0M$;AH>3kyd%gn-nWqN^I@NU%~wW~ z^hA$EZ;EMuyNMV1`_k*WeW2ssURl?w7x-lF@}rFm6g8cQ^8&CHj8aByqd-lFTg|AV g5$G^t65(kBdbN#z-gkFr%?#8p0_%YGbuSh9Upmrnr2qf` diff --git a/test-devices/composite-stm32/bin/bluepill-f103c8.bin b/test-devices/composite-stm32/bin/bluepill-f103c8.bin index fa6465296e208f1e3f507a1c041c00a116f1f635..84a855751e237ee900732d3678e70431c1eb4c1d 100755 GIT binary patch delta 1173 zcmZuvTTC2P82-=9?C#8Rk^2HmWnfF(cDgObppshH<#M=eDW)xIqSYcH(P&c=ZKO{i zwz7R_jGUN;_)xVZmMFNeMT_aWHDIEWCOgHZT$*&%lx@?{3~9;ivfUZa!1m3PeCNN; z_x*FuiM{#PTmD@LT_i4Kr+W*k6>cU$>4^61iV_ap|#DEA&B<`N3k;n}9@4Oi5FE?`GxXFJc#wF4@5cw&-8I(}6 z)@fZtv^E>BoDSaQ-R^R>#fV3Vi*r6VAi0$+^8V4?VezWRVZ`vXU!oT0l}}n33#Z5N#2Y z^nBPk-yp?g;LF{U`s@?5Vnj^J{!JRqrP-V_XCcjN zZ95bb-6Gc2*U1U9l*pd?Ci_aMVu7`@o|*L z8_^vm;9d7(_1=^HSeG&}8;0#74&IG@l7`zAM)<6dT@y^fx`zuTCui@^a=RL?)U7Uj zUzaXVuc434!RR@R5$}JLq?^H>ZOU%z>et4_TxTOTk%GMZPE)thikS{56W<0^p}p z_G26HiNdYim(>4(cx*>d4LNVCWgcrJVjIb?pc2X|ME21?%umU6li|X>$J!{#M-=BM zE>Kbf-=%U-;{UU+(jHCi*K!;TwnhfLAk{wlW?WPIH2RjEwU5q?*Za()#tX&qu@y!# z%bI$Oc#29bi}!rNh3iBX&GG7BxnhrX3r1gEELr42ez{XwXPv4H`?d zVUiiP7!32`A0!eo`4JX_*;W>)P@70%VpP(nfw1Zfpd=ck>$m_ql6;-ph5C12FtoXh zq3Ia_-_(+BGzRLE<#bVK-8FGQ0`(g`l46;}9UWMCCNt1zo=xiFcwbSNs}exMQ@9({ z(NZ{QzkyiowBDLZPvc0Wkza4-AJLEyc)Ft`5m0ZH>w8?ATpKs5Ml1M{dbkLznei7oH^vb&n%7Nxo(>D`=rj7g;CtLr8eAL92&7?Rbkfdd9xoZ%9>dTEjT08T z5@h<1=^P2N=}$!vG52hu%SHeG*px`>NVifOzdYMs%gI)yH_po~S@AlOAIfsFHw)65 zydba4cFMX!hph5H%CZf9QakLY~ebq^DyMq|Sd;ss5h( zV@Qy1v1*VwHdJc(Vx^|sRG%nR!XFkyzEecDy02t5=L$%QrPs6ojsQsJWugEdgYH;Y z9d%kdoIzGGvu{Hce~P|p@j3Zm&GjWwdrxmsib%xJ-k_ga0*?r*0mr&xU6|l054mjP zvxep|kc88QCK~jbCAhQ6kVthJr1=6S{}!4>z@ZtnJ-Tmz7_x)#S!j|-dRqOUD*o`k zs?O8y&8b(sXW}O(O@X_GKpce|I`0+Et)2bJPa^ELpD9CdR^g)F*K*eURrvb1Lh^kp zwmW8+@;L<3IAawZao$GP=({yrxfwBerRHrOm1#%)A=FEi`hzP@cmR(u`sx8E7X3OG z;EcO+ww=X$X~NZqHqx9c%-Idv;6Axjv;bEBhWxW^)cwVA&Gf3f?KvkCX=A*|*v&*u z-dsF;kpG|evYxW`ak(bI5qthX6y)%|&%Z2dhiJdYi{7INj}Prl9`k&NJV#0|+;&90 z@tfBD_qUv_UTEEPwyYhdZQd12+u3Tc_?as@S?*81uxv!yDcD9L)C(m!R&v`tY_;0 diff --git a/test-devices/composite-stm32/platformio.ini b/test-devices/composite-stm32/platformio.ini index d0c31313..0a2fda29 100644 --- a/test-devices/composite-stm32/platformio.ini +++ b/test-devices/composite-stm32/platformio.ini @@ -2,7 +2,9 @@ tinyusb_flags = -D CFG_TUD_CDC=1 -D CFG_VENDOR_ADVANCED=1 + -D CFG_VENDOR_ADVANCED_NUM_INTF=2 -D CFG_TUSB_RHPORT1_MODE=OPT_MODE_NONE + -D CFG_WINUSB=OPT_WINUSB_MSOS20 platform = ststm32 framework = cmsis debug_tool = stlink diff --git a/test-devices/composite-stm32/src/main.c b/test-devices/composite-stm32/src/main.c index 10f12572..034a3714 100644 --- a/test-devices/composite-stm32/src/main.c +++ b/test-devices/composite-stm32/src/main.c @@ -157,6 +157,12 @@ void cust_vendor_halt_cleared_cb(uint8_t ep_addr) { // --- Control messages (see README) +#define REQUEST_SAVE_VALUE 0x01 +#define REQUEST_SAVE_DATA 0x02 +#define REQUEST_SEND_DATA 0x03 +#define REQUEST_RESET_BUFFERS 0x04 +#define REQUEST_GET_INTF_NUM 0x05 + static uint32_t saved_value = 0; bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) { @@ -168,7 +174,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ switch (request->bRequest) { - case 0x01: + case REQUEST_SAVE_VALUE: if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 0) { // save value from wValue saved_value = request->wValue; @@ -176,27 +182,38 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ } break; - case 0x02: + case REQUEST_SAVE_DATA: if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 4) { // receive into `saved_value` return tud_control_xfer(rhport, request, &saved_value, 4); } break; - case 0x03: + case REQUEST_SEND_DATA: if (request->bmRequestType_bit.direction == TUSB_DIR_IN && request->wLength == 4) { // transmit from `saved_value` return tud_control_xfer(rhport, request, &saved_value, 4); } break; - case 0x04: + case REQUEST_RESET_BUFFERS: if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 0) { reset_buffers(); return tud_control_status(rhport, request); } break; + case REQUEST_GET_INTF_NUM: + if (request->bmRequestType_bit.direction == TUSB_DIR_IN && request->wLength == 1) { + uint8_t intf_num = request->wIndex & 0xff; + if (intf_num < 4) { + // return inteface number + return tud_control_xfer(rhport, request, &intf_num, 1); + } + } + break; + +#if CFG_WINUSB == OPT_WINUSB_MSOS20 case MSOS_VENDOR_CODE: if (request->wIndex == 7) { // Get Microsoft OS 2.0 compatible descriptor @@ -205,6 +222,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ return tud_control_xfer(rhport, request, (uint8_t*) desc_ms_os_20, total_len); } break; +#endif default: break; diff --git a/test-devices/composite-stm32/src/usb_descriptors.c b/test-devices/composite-stm32/src/usb_descriptors.c index 25b8f78c..f45bfa1d 100644 --- a/test-devices/composite-stm32/src/usb_descriptors.c +++ b/test-devices/composite-stm32/src/usb_descriptors.c @@ -49,20 +49,17 @@ uint8_t const* tud_descriptor_device_cb(void) { // --- Configuration Descriptor --- -enum { - INTF_CDC_COMM = 0, - INTF_CDC_DATA, - INTF_LOOPBACK, - INTF_NUM_TOTAL -}; - -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + 9 + 7 + 7) +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + 8 + 9 + 9 + 7 + 7) uint8_t const desc_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA TUD_CONFIG_DESCRIPTOR(1, INTF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 500), // CDC interfaces TUD_CDC_DESCRIPTOR(INTF_CDC_COMM, 0, EP_CDC_COMM, 8, EP_CDC_DATA_RX, EP_CDC_DATA_TX, BULK_MAX_PACKET_SIZE), + // Interface association descriptor (IAD) + CUSTOM_VENDOR_INTERFACE_ASSOCIATION(INTF_LOOPBACK_CTRL, 2, 0x04), + // Echo interface (no endpoint, just control messages) + CUSTOM_VENDOR_INTERFACE(INTF_LOOPBACK_CTRL, 0), // Loopback interface CUSTOM_VENDOR_INTERFACE(INTF_LOOPBACK, 2), // Loopback endpoint OUT @@ -82,6 +79,8 @@ uint8_t const* tud_descriptor_configuration_cb(uint8_t configuration_index) { // --- BOS Descriptor --- +#if CFG_WINUSB == OPT_WINUSB_MSOS20 + #define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN) #define MS_OS_20_DESC_LEN 0xB2 @@ -108,7 +107,7 @@ uint8_t const desc_ms_os_20[] = { U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A), // Function Subset header: length, type, first interface, reserved, subset length - U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), INTF_LOOPBACK, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08), + U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), INTF_LOOPBACK_CTRL, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08), // MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub compatible ID U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, @@ -129,6 +128,7 @@ uint8_t const desc_ms_os_20[] = { TU_VERIFY_STATIC(sizeof(desc_ms_os_20) == MS_OS_20_DESC_LEN, "Incorrect size"); +#endif // --- String Descriptors --- @@ -138,7 +138,8 @@ const char* const string_table[] = { 0, // 0 - supported languages (see below) "JavaDoesUSB", // 1 - manufacturer "Composite", // 2 - product - board_serial_num // 3 - serial number + board_serial_num, // 3 - serial number + "Loopback IAD" // 4 - interface association descriptor }; diff --git a/test-devices/composite-stm32/src/usb_descriptors.h b/test-devices/composite-stm32/src/usb_descriptors.h index 32edc120..1d6474c3 100644 --- a/test-devices/composite-stm32/src/usb_descriptors.h +++ b/test-devices/composite-stm32/src/usb_descriptors.h @@ -13,6 +13,24 @@ #include +#define OPT_WINUSB_NONE 0 +#define OPT_WINUSB_MSOS20 2 + +#ifndef CFG_WINUSB +#define CFG_WINUSB OPT_WINUSB_MSOS20 +#endif + + +// interfaces +enum { + INTF_CDC_COMM = 0, + INTF_CDC_DATA, + INTF_LOOPBACK_CTRL, + INTF_LOOPBACK, + INTF_NUM_TOTAL +}; + + #define INTR_MAX_PACKET_SIZE 16 #define BULK_MAX_PACKET_SIZE 64 @@ -24,8 +42,11 @@ #define EP_LOOPBACK_RX 0x01 #define EP_LOOPBACK_TX 0x82 -#define MSOS_VENDOR_CODE 0x44 +#if CFG_WINUSB == OPT_WINUSB_MSOS20 +#define MSOS_VENDOR_CODE 0x44 extern uint8_t const desc_ms_os_20[]; +#endif + void usb_init_serial_num(); diff --git a/test-devices/composite-stm32/src/vendor_custom.c b/test-devices/composite-stm32/src/vendor_custom.c index 36fe96ed..98c6c399 100644 --- a/test-devices/composite-stm32/src/vendor_custom.c +++ b/test-devices/composite-stm32/src/vendor_custom.c @@ -42,27 +42,30 @@ void cv_reset(uint8_t rhport) { // nothing to do } -uint16_t cv_open(uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t max_len) { - +uint16_t cv_open(uint8_t rhport, tusb_desc_interface_t const *desc_intf, uint16_t max_len) { // return 0 if interface class is not "vendor specific" TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_intf->bInterfaceClass, 0); - uint8_t const * p_desc = tu_desc_next(desc_intf); - uint8_t const * desc_end = p_desc + max_len; - int num_endpoints = desc_intf->bNumEndpoints; + uint8_t const *p_desc = (uint8_t const *)desc_intf; + uint8_t const *p_end = p_desc + max_len; + + for (int i = 0; i < CFG_VENDOR_ADVANCED_NUM_INTF; i++) { + TU_VERIFY(p_desc + sizeof(tusb_desc_interface_t) <= p_end, 0); + + tusb_desc_interface_t const *intf = (tusb_desc_interface_t const *)p_desc; + int num_endpoints = intf->bNumEndpoints; - // iterate all endpoints - while (num_endpoints > 0 && p_desc < desc_end) { + tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *)(p_desc + sizeof(tusb_desc_interface_t)); + TU_VERIFY((uint8_t const *)(desc_ep + num_endpoints) <= p_end, 0); - // open endpoint - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; - TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); + // open all endpoints + for (int i = 0; i < num_endpoints; i++) + TU_ASSERT(usbd_edpt_open(rhport, desc_ep + i)); - p_desc = tu_desc_next(p_desc); - num_endpoints--; + p_desc = (uint8_t const *)(desc_ep + num_endpoints); } - uint16_t processed_bytes = p_desc - (uint8_t const *) desc_intf; + uint16_t processed_bytes = p_desc - (uint8_t const *)desc_intf; cust_vendor_intf_open_cb(desc_intf->bInterfaceNumber); diff --git a/test-devices/composite-stm32/src/vendor_custom.h b/test-devices/composite-stm32/src/vendor_custom.h index 4d976a1a..da0618c0 100644 --- a/test-devices/composite-stm32/src/vendor_custom.h +++ b/test-devices/composite-stm32/src/vendor_custom.h @@ -32,6 +32,10 @@ /* Endpoint */\ 7, TUSB_DESC_ENDPOINT, _epaddr, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_packetsize), _interval +// Interface association descriptor: first interface index, number of interfaces, string index of description +#define CUSTOM_VENDOR_INTERFACE_ASSOCIATION(_firstintf, _numintf, _strIndex) \ + /* Interface Association */\ + 8, TUSB_DESC_INTERFACE_ASSOCIATION, _firstintf, _numintf, TUSB_CLASS_VENDOR_SPECIFIC, 0x00, 0x00, _strIndex // --- Application API diff --git a/test-devices/loopback-stm32/bin/blackpill-f401cc.bin b/test-devices/loopback-stm32/bin/blackpill-f401cc.bin index 852fc6dd8e7a0b2ef44b5af8e73ebd19a406a426..fd044b62bebb3eae874b9c31ba8d320cfca66d1d 100755 GIT binary patch delta 910 zcmZuwTWAwO6uq;XO(wN%Qkqtin07ZcG~J*TRN4q)A-ZWBOF>Q54>7hMf*?dx=$|jd zMF}GFp?<31<3o(D5n7F{R#4GmwzeP?B~mm2DQvCUr^Xw!e-4~;X70{Cd-u-Hn`l0o zd_X+68i3LiA93H~+xXVI({O^O0mmu;@fOobsO;hb7-MtsFaQx>GKphkP)l)*9LccH zrp;Bao&eZWrLAD}FPaqf-YF4`*DNS_njZGs(=aegK%{79PnEQmYy;!*Vx5}&8nP`L zC%E&*d~=^y<=eKSc{*=z0plb~2%cr<`t4p*8;?7pEG0BlMixZ{jLdi#hXD(QSPW;&SI>nAS@% z%xFf$!|^axXv(P!S@}$1=EZL!(sW_wHtVC4WKXbPqwm)j?=zN%YmLj9CH9Y{7?5(0oAJi#*X0ptQM@Yk#dOwH6|e&v;eK3tgE_f zqktKWh)%?DbSR?dUu9GkOPjW9V;op L3jw8290kN5OROq* delta 882 zcmZuvZ%7ki7=PZo-S%#3n>fum&+ca8b^{G0+=9qZ?z9O}y2=lc6n(G=uKFTm6!~RQ z67dT4H7Y3RpIjp>rcm^)au-U4WP+3vF)l2owp!09zxBfJ_j}*xp67SZJ?~}Wui}p$ z6Y+8gC{6M){|Mi~w?ABl^E3sxHUmhPnMqnp27iJzwW@0XM7qahj*(kNl56D1WA@p$ zqx{(zfG1hp4%WS#O-+nkkibf@s311qdFn~Q_zD4uqM0Y@YIk*l^&nT9c(mB+E}ABo zd3`N18c6URd(k|V@w9+-nhgnJ(ZEwrz}CTIhQ^XYsBC*qQo-8#%iRg`ZY#e9tk>+D zaH-V4#;N_IM3vN3CW6&PY{*_0=GORF<@tQJJDr7X=UHEEEdvoOqD$lgd*O_e zqs-^3Cnt=Zu1f;9;4t2}Ye+%Add7It#qN6t>&|Qh+K1@z0*(LE?d3qPRs4%>OnxY&ezQS|$U@r!LSAXNw6uGk{27RNtF)wN+GB_1MV*bp~0 zqp-Ntg?v}Kf*h3#9)0p4@{)W6c~1b@NCuwai;R| gH?X;zh^tPZBZ%AVt`hb}J=lp0e|ji}!pbB50Bp?|OaK4? diff --git a/test-devices/loopback-stm32/bin/blackpill-f411ce.bin b/test-devices/loopback-stm32/bin/blackpill-f411ce.bin index d0392747d2f3bd5bcd26c48777ce2af96a301844..ad2b198b2f317be00d97774764090d85531dc49e 100755 GIT binary patch delta 814 zcmZvaZAep57{{M;w|jRsolZ72UDJCf!|e{Vu+YMhB3&(`Fj-*`jb8Apk&=Ci^2;rW z7>7PpA4&?MK4>?qS<51$qM}`MAxL42n!O0O7xT63k?dOs{=fe@&v~AQ!^260zl3{l z6LO8kh#Q$Cb@u2y7|GeTdH_y*&U_prLt2b0=g0{AXx@-Fb2woxq-CHPSyI}@B- zlmM}CoR`-oN?%pVGrC*&ne0)`!S8xXE#B-8`Um|bYsTHe=aG~O!3o{nxK}NVND48E zXSv?Cc#-fHZ_L3l-L+X#{1^|;eoLeo-C1Zjw*USj2%*`&SDmDR0t5)YCB7&fZw^$vHMkB1`_- zanD3HvNNtO-`RYiCs0RRKs%OwcP`Ldd4FSvao??la)D^p0jryLpbR3Hy} z+{ja&d~!p(^e_~J@5780A0QSmfVl9no(q%LGq+J{`{MQZ20cd)J2;#)M?hj3c| u^n@JQCABdae3xO$`bruSV(O-~BF^C(OK`SOc}UUxf8(C4Tl_X%SgdaqUrv8W!H(wzD~@Y!U5qPQLyup3w@73i zN7bbQJ&2FjObB4N;R5sYfo%^ zzO+2^i^w!rTE5TT&>|URPi+Zuno0I1(rdKahXt-^HC{OyNZG$Sr+CuI#$7|cfjXeQ zNVf}U@~7-lO8Ixi>GU`rp{?v9eTMxXm7N7Af)>jG*(3ZW*YX4K1)$DPJ6w#0$dcfDG% zv_?#he~hk2)5as|1R-fd+17%_l5!{NUHJ-XSSk1DRfbT%D5p>pUQ{FNoy3ETK3|Ei x9L2u>xWg_57KL3H*~fa-P}NPm+%4pq4QK|r&F-o}SJ;U+vE$DTo1pxZklz-P3OWD) diff --git a/test-devices/loopback-stm32/bin/bluepill-f103c8.bin b/test-devices/loopback-stm32/bin/bluepill-f103c8.bin index c39ace153c40dff9461930563882c6635ae41917..0d10a31695f61edabc64cf5ef4b0dc454e861088 100755 GIT binary patch delta 798 zcmZvaUr19?9LIm>-rakTI(2J`Zlc~f#CdONRH6~mz`9FkCFP%9q+vuDL=y{q3H$TV zt?(hvQ%_+*;6q?t7ATA*ViqCn`iCSljFFp&a4l|bYd%|r%2c-T93U|i zw|Ky~L+VY%Sr11oWu``!cC?Yprt*S`l&FAFx}9@6=S*%hIL{jCgJ1;7py`pdGQ}u; zBS;aIP`r*#u#Rk z(uv8xNW}DEhe)@uhHj7!+=e>HOI(32YIFD)i-MZf>_XJkWKXi_3i)HXUoPYU{$&IF z%|h9=AFO~~yMC1V32n%li?Vedu(1Y9D;(f4GO@4Y=uO)6loF<_(g8cn?B@33|Ji=6 z%~s8Di*(=`d60h|J<%5P1qL;0-wQtRoR>=C(Z)(#S=lYr-J_MPSH`%{^ybTCQL46H f698YQbYj4_C_SWDmh(o;fHyMfmjyHItTg2xyW|jQ delta 770 zcmZvaUr19?7{JfDclX{ix8>H9rZ%~AitFCYAi+tE4DC*x6=oVe1WS=92yRH=Ls1yf zh3Fy9OFi@uBK1&UT!w$(HX=ldz+F%(?2lpOM1&g&Yn!ybfxdO%cfP-T=R4myfBHZ7 zPwdBdFKxh8uy^94cFz{FhO=t)2z`Kc+(eHvLENriVg|84X%sT~WFeDHBIHguJCIeI zw<+4oQ4v`NU1R;t&t}{PN~Rek5`;u|q6Bj4^Y-qbHnHAT>R7^%`7jrruF=@e(+G=3 z+T9Ar(TL6OxIW{qv30VL5v4=6x;>LQQ9+hxYuAZgCri6g;FMK3h^(jdiS3@JD#s`z z(^wG|BOQhc4jSR=WG2VPe76djGX*0}S__%W$(=5oP-!ZMYDf%=m2qTk(EHr^n`(kn z%9N<-9bv6F(<%w(zz8cfrnrw-@}?N6I)%iRWt+4w)huPrDn7F~rrG38b4BxYh2&5& z6bvY3%YJ@+VMRl7+6*WInm1M%H_|Hflu!EjuMn}xOArYu&aR>#TlT36{`Z2pS{df& z7k+B!zREUGZZ9}*(%Fvj9IQveRKD(X<9PHOON_CAOft&7wy z9Kz)^BGd;K!1o+bqiU2WBvGNfv9qZ{X7Mi;2|V5;y(4VkQ94Ze@DP1V>hTr*7dg!0 zM|y)Zh(YwY=2(1JDM*l2*A_aPxOGD>Zt01Vnm)V+4^4Kp$<9<+8_4L^ey{TOubat^)86A*A~_ diff --git a/test-devices/loopback-stm32/bin/disco_f723ie.bin b/test-devices/loopback-stm32/bin/disco_f723ie.bin index 1567e9e69d1836b83efbef599a18923f8a7ab3fd..5154fd69b1fcab8177f8008a67356b64a6775e0d 100755 GIT binary patch delta 977 zcmZuwZ)h837=NC-EA|{GrXIx00AFtx!ulN^o2CvNoGCYneI+bvo^rVZ;gb zgKVr0PgIJ$^qa%^XXri*+g|gbg^Et&B-?7oNxzu)iP z=Xrj=_wI$ae5iWptbosP6hg!;LciymDp=N-U-YxZ=c)bAN z&DHM(>&L1?)2B}$2dfL}ieCuh#?i4_zrf5W@$)QsIN&3p4u_)GwW0Vv*F z-M%_Sq5|_jRP1uQz(<+H_PL15bkO1nUgB?0MTKXF{Wpa4t)kaehmZ-CxXm z+Z+QT`Cj2DN1H~g-p5h#?gQ(kdk}fTsyzf&ji=;yed!HB8=FJT{+?b+?cqyuJ9hAz z+~OIpx-!s)N^k_M0Dq7jKJi-4sWocDX2Y0hjR?EqvUy}ojCT~Bix_Vx3h~w=D8aHb z-d&7d?TN3MA?ePwPjyG)Pjf{N55^L)LQH+Q9FlI9R&+?*FpuaFEtm<8pf$WMOl9+} z($Ca!B(9r{gApyJq4oUw9~Hm!S81UVkcv;0e$}Dl2XhM@kE^;RV~@0slq*5$^0gHm z6Bo@-^o1EQ{{EV*%rAO=mxYM7TtUUGK;d{2*rS`r^&TA=s$v%QX44T^<-152%ngJMRA)fc>)Ut{@cs^8h{HT|b&*Qfa_(e3L*lA{lND`E>zHox88 z69Cpu@HG=Qb)DXa{QuS(wgHP8OU+x+bIb+IT7~jy2JA4uz3t%6b2M~?aElNklMRtV z?ArbH|LK>;X}>D?&QsvWo1t%zzQgB&LpW)8LRSTxHGXLsN1WwH!=1#F;V$Cu!lA${ z{kkIq7<_tR&C%O$3F23z+4QV&FZ>Z1j5Cow+qcv8uT=>54&71eVnVn&ZgZaU8 z9O-0)^CA1WF6Z?knEi!#6hKh!uu+bY0fX=@JQ-o@#g2pfG61e*SvQyui-MN8a##U# zwlI>Sx)k#y#$o*GxlN&rqNNvHorkYlv-fYh(vZ2xfkFWkSJJ-4j_yZAHF5c4*9ylh z!J2D@wp3k$C_-#ISWYk}(PhJ#j@fnN~VW|r20`Gswej=S3noHmvsnzf%c?ApLyNkO8plH_;pFUmU95yd+Urh_%m zp@Z?HO{>tNx$-gI9OgR1Qf|)}A8yLpUXpNmmJ6@Sg3_KB!VTHh@Q<8NTzYXKAw<6A z-X{W@rzaE%WkPC2-YCX3zcPDnn$DQlbCc9P5O*!$E1y{H+tPo1m)1m2RwuLh`$ zSgb^N{_0#6(AMR631f$`Sha#Udu5>JC&(Y6KsPeCXGi-nEHV(!5hZM3VSYLHZ~Q-H z#(9s*xldrjBg;*PP)FGdZyz~eH29u#WXkyEpCDw49ja|YzEa!bpTeJpcaRr!Al`vz z--R~S8(! diff --git a/test-devices/loopback-stm32/src/main.c b/test-devices/loopback-stm32/src/main.c index b58c45f1..31d9ccad 100644 --- a/test-devices/loopback-stm32/src/main.c +++ b/test-devices/loopback-stm32/src/main.c @@ -189,6 +189,12 @@ void cust_vendor_halt_cleared_cb(uint8_t ep_addr) { // --- Control messages (see README) +#define REQUEST_SAVE_VALUE 0x01 +#define REQUEST_SAVE_DATA 0x02 +#define REQUEST_SEND_DATA 0x03 +#define REQUEST_RESET_BUFFERS 0x04 +#define REQUEST_GET_INTF_NUM 0x05 + static uint32_t saved_value = 0; bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) { @@ -200,7 +206,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ switch (request->bRequest) { - case 0x01: + case REQUEST_SAVE_VALUE: if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 0) { // save value from wValue saved_value = request->wValue; @@ -208,27 +214,37 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ } break; - case 0x02: + case REQUEST_SAVE_DATA: if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 4) { // receive into `saved_value` return tud_control_xfer(rhport, request, &saved_value, 4); } break; - case 0x03: + case REQUEST_SEND_DATA: if (request->bmRequestType_bit.direction == TUSB_DIR_IN && request->wLength == 4) { // transmit from `saved_value` return tud_control_xfer(rhport, request, &saved_value, 4); } break; - case 0x04: + case REQUEST_RESET_BUFFERS: if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 0) { reset_buffers(); return tud_control_status(rhport, request); } break; - + + case REQUEST_GET_INTF_NUM: + if (request->bmRequestType_bit.direction == TUSB_DIR_IN && request->wLength == 1) { + uint8_t intf_num = request->wIndex & 0xff; + if (intf_num < 4) { + // return inteface number + return tud_control_xfer(rhport, request, &intf_num, 1); + } + } + break; + // Microsoft WCID descriptor (for automatic WinUSB installation) case WCID_VENDOR_CODE: if (request->bmRequestType_bit.direction == TUSB_DIR_IN && request->wIndex == 0x0004) { From b31121cb43caad6e0f97e7a7b55675383a07965a Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 26 Sep 2023 20:20:32 +0200 Subject: [PATCH 289/433] Windows reference code: associated interfaces --- reference/windows/USB/tests.cpp | 47 +++++++++++++++++---- reference/windows/USB/tests.hpp | 5 +++ reference/windows/USB/usb_device.cpp | 62 +++++++++++++++++----------- reference/windows/USB/usb_device.hpp | 2 +- 4 files changed, 82 insertions(+), 34 deletions(-) diff --git a/reference/windows/USB/tests.cpp b/reference/windows/USB/tests.cpp index 894da2e1..54ac0169 100644 --- a/reference/windows/USB/tests.cpp +++ b/reference/windows/USB/tests.cpp @@ -43,15 +43,22 @@ void tests::run() { void tests::test_current_device() { try { std::cout << "Found test device" << std::endl; + + is_composite = test_device->product_id() == 0xcea0; + loopback_intf = is_composite ? 3 : 0; + loopback_ep_out = is_composite ? 1 : 1; + loopback_ep_in = is_composite ? 2 : 2; + test_device->open(); - test_device->claim_interface(0); + test_device->claim_interface(loopback_intf); test_control_transfers(); test_bulk_transfers(); test_speed(); - test_device->release_interface(0); + test_device->release_interface(loopback_intf); test_device->close(); + std::cout << "Test completed" << std::endl; } catch (const std::exception& e) { @@ -65,7 +72,7 @@ void tests::test_control_transfers() { usb_request_type::type_vendor, usb_request_type::recipient_interface); request_set_value_no_data.bRequest = 0x01; request_set_value_no_data.wValue = 0x9a41; - request_set_value_no_data.wIndex = 0; // interface number + request_set_value_no_data.wIndex = loopback_intf; request_set_value_no_data.wLength = 0; test_device->control_transfer(request_set_value_no_data); @@ -74,7 +81,7 @@ void tests::test_control_transfers() { usb_request_type::type_vendor, usb_request_type::recipient_interface); request_get_data.bRequest = 0x03; request_get_data.wValue = 0; - request_get_data.wIndex = 0; // interface number + request_get_data.wIndex = loopback_intf; request_get_data.wLength = 4; auto data = test_device->control_transfer_in(request_get_data); std::vector expected_data{ 0x41, 0x9a, 0x00, 0x00 }; @@ -86,14 +93,37 @@ void tests::test_control_transfers() { usb_request_type::type_vendor, usb_request_type::recipient_interface); request_set_value_data.bRequest = 0x02; request_set_value_data.wValue = 0; - request_set_value_data.wIndex = 0; // interface number + request_set_value_data.wIndex = loopback_intf; request_set_value_data.wLength = static_cast(sent_value.size()); test_device->control_transfer_out(request_set_value_data, sent_value); data = test_device->control_transfer_in(request_get_data); assert_equals(sent_value, data); + + test_control_transfer_intf(loopback_intf); + + if (is_composite) { + test_device->claim_interface(2); + test_control_transfer_intf(2); + test_device->release_interface(2); + } } +void tests::test_control_transfer_intf(int intf_num) { + usb_control_request request_get_intf_num = { 0 }; + request_get_intf_num.bmRequestType = usb_control_request::request_type(usb_request_type::direction_in, + usb_request_type::type_vendor, usb_request_type::recipient_interface); + request_get_intf_num.bRequest = 0x05; + request_get_intf_num.wValue = 0; + request_get_intf_num.wIndex = intf_num; + request_get_intf_num.wLength = 1; + auto data = test_device->control_transfer_in(request_get_intf_num); + + std::vector expected_data{ (uint8_t)intf_num }; + assert_equals(expected_data, data); +} + + void tests::test_bulk_transfers() { test_loopback(12); test_loopback(130); @@ -113,7 +143,7 @@ void tests::test_loopback(int num_bytes) { std::thread reader([this, &rx_data, num_bytes]() { size_t bytes_read = 0; while (bytes_read < num_bytes) { - auto data = test_device->transfer_in(2); + auto data = test_device->transfer_in(loopback_ep_in); rx_data.insert(rx_data.end(), data.begin(), data.end()); bytes_read += data.size(); } @@ -125,7 +155,7 @@ void tests::test_loopback(int num_bytes) { while (bytes_written < num_bytes) { int size = std::min(chunk_size, num_bytes - bytes_written); std::vector chunk = {random_data.begin() + bytes_written, random_data.begin() + bytes_written + size}; - test_device->transfer_out(1, chunk); + test_device->transfer_out(loopback_ep_out, chunk); bytes_written += size; } @@ -169,5 +199,6 @@ std::vector tests::random_bytes(int num) { } bool tests::is_test_device(usb_device_ptr device) { - return device->vendor_id() == 0xcafe && device->product_id() == 0xceaf; + return device->vendor_id() == 0xcafe + && (device->product_id() == 0xceaf || device->product_id() == 0xcea0); } diff --git a/reference/windows/USB/tests.hpp b/reference/windows/USB/tests.hpp index 11cf328f..dbcd0903 100644 --- a/reference/windows/USB/tests.hpp +++ b/reference/windows/USB/tests.hpp @@ -21,6 +21,7 @@ class tests { void test_control_transfers(); void test_bulk_transfers(); void test_speed(); + void test_control_transfer_intf(int intf_num); void test_loopback(int num_bytes); @@ -33,5 +34,9 @@ class tests { usb_device_ptr test_device; usb_registry registry; + bool is_composite; + int loopback_intf; + int loopback_ep_out; + int loopback_ep_in; }; diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp index cf700124..959e88d3 100644 --- a/reference/windows/USB/usb_device.cpp +++ b/reference/windows/USB/usb_device.cpp @@ -131,7 +131,7 @@ void usb_device::claim_interface(int interface_number) { interface_handle* intf_handle = get_interface_handle(interface_number); interface_handle* first_intf_handle = get_interface_handle(intf_handle->first_interface_num); - // open device if needed + // both the device and the first interface must be opened for any interface belonging to the same function if (first_intf_handle->device_handle == nullptr) { auto device_path = get_interface_device_path(first_intf_handle->interface_num); if (device_path.empty()) @@ -139,6 +139,7 @@ void usb_device::claim_interface(int interface_number) { std::wcerr << "opening device " << device_path << std::endl; + // open device first_intf_handle->device_handle = CreateFileW(device_path.c_str(), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, @@ -147,21 +148,26 @@ void usb_device::claim_interface(int interface_number) { FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr); if (first_intf_handle->device_handle == INVALID_HANDLE_VALUE) - usb_error::throw_error("cannot open USB device"); + usb_error::throw_error("failed to claim interface (cannot open USB device)"); - // open interface - if (!WinUsb_Initialize(first_intf_handle->device_handle, &first_intf_handle->intf_handle)) { + // open first interface + if (!WinUsb_Initialize(first_intf_handle->device_handle, &first_intf_handle->winusb_handle)) { auto err = GetLastError(); CloseHandle(first_intf_handle->device_handle); first_intf_handle->device_handle = nullptr; - throw usb_error("cannot open USB device (2)", err); + throw usb_error("failed to claim interface (cannot open associated interface)", err); } registry_->add_to_completion_port(first_intf_handle->device_handle); } + // open associated interface + if (intf_handle != first_intf_handle) { + if (!WinUsb_GetAssociatedInterface(first_intf_handle->winusb_handle, intf_handle->interface_num - first_intf_handle->interface_num - 1, &intf_handle->winusb_handle)) + throw usb_error("cannot open associated interface", GetLastError()); + } + first_intf_handle->device_open_count += 1; - intf_handle->intf_handle = first_intf_handle->intf_handle; intf->set_claimed(true); } @@ -179,13 +185,19 @@ void usb_device::release_interface(int interface_number) { interface_handle* intf_handle = get_interface_handle(interface_number); interface_handle* first_intf_handle = get_interface_handle(intf_handle->first_interface_num); - intf_handle->intf_handle = nullptr; intf->set_claimed(false); + if (intf_handle != first_intf_handle) { + // close assicated interface + if (!WinUsb_Free(intf_handle->winusb_handle)) + throw usb_error("failed to release associated interface", GetLastError()); + intf_handle->winusb_handle = nullptr; + } + // close device if needed first_intf_handle->device_open_count -= 1; if (first_intf_handle->device_open_count == 0) { - WinUsb_Free(first_intf_handle->intf_handle); + WinUsb_Free(first_intf_handle->winusb_handle); CloseHandle(first_intf_handle->device_handle); first_intf_handle->device_handle = nullptr; } @@ -193,18 +205,18 @@ void usb_device::release_interface(int interface_number) { std::vector usb_device::transfer_in(int endpoint_number, int timeout) { - auto intf_handle = check_valid_endpoint(usb_direction::in, endpoint_number)->intf_handle; + auto winusb_handle = check_valid_endpoint(usb_direction::in, endpoint_number)->winusb_handle; UCHAR endpoint_address = ep_address(usb_direction::in, endpoint_number); auto endpoint = get_endpoint_ptr(usb_direction::in, endpoint_number); ULONG value = timeout; - if (!WinUsb_SetPipePolicy(intf_handle, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) + if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) usb_error::throw_error("Failed to set endpoint timeout"); std::vector data(endpoint->packet_size()); DWORD len = 0; - if (!WinUsb_ReadPipe(intf_handle, endpoint_address, static_cast(data.data()), endpoint->packet_size(), &len, nullptr)) + if (!WinUsb_ReadPipe(winusb_handle, endpoint_address, static_cast(data.data()), endpoint->packet_size(), &len, nullptr)) usb_error::throw_error("Cannot receive from USB endpoint"); data.resize(len); @@ -215,15 +227,15 @@ void usb_device::transfer_out(int endpoint_number, const std::vector& d if (len < 0 || len > data.size()) len = static_cast(data.size()); - auto intf_handle = check_valid_endpoint(usb_direction::out, endpoint_number)->intf_handle; + auto winusb_handle = check_valid_endpoint(usb_direction::out, endpoint_number)->winusb_handle; UCHAR endpoint_address = ep_address(usb_direction::out, endpoint_number); ULONG value = timeout; - if (!WinUsb_SetPipePolicy(intf_handle, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) + if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) usb_error::throw_error("Failed to set endpoint timeout"); DWORD tlen = 0; - if (!WinUsb_WritePipe(intf_handle, endpoint_address, const_cast(data.data()), len, &tlen, nullptr)) + if (!WinUsb_WritePipe(winusb_handle, endpoint_address, const_cast(data.data()), len, &tlen, nullptr)) usb_error::throw_error("Failed to transmit to USB endpoint"); } @@ -232,10 +244,10 @@ int usb_device::control_transfer_core(const usb_control_request &request, uint8_ if (!is_open()) throw usb_error("USB device is not open"); - auto handle = get_control_transfer_interface_handle(request)->intf_handle; + auto winusb_handle = get_control_transfer_interface_handle(request)->winusb_handle; ULONG value = timeout; - if (!WinUsb_SetPipePolicy(handle, 0, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) + if (!WinUsb_SetPipePolicy(winusb_handle, 0, PIPE_TRANSFER_TIMEOUT, sizeof(value), &value)) usb_error::throw_error("Failed to set endpoint timeout"); WINUSB_SETUP_PACKET setup_packet = { 0 }; @@ -246,7 +258,7 @@ int usb_device::control_transfer_core(const usb_control_request &request, uint8_ setup_packet.Length = request.wLength; DWORD len = 0; - if (!WinUsb_ControlTransfer(handle, setup_packet, data, request.wLength, &len, nullptr)) + if (!WinUsb_ControlTransfer(winusb_handle, setup_packet, data, request.wLength, &len, nullptr)) usb_error::throw_error("Control transfer failed"); return len; @@ -400,24 +412,24 @@ void usb_device::remove_completion_handler(OVERLAPPED* overlapped) { } void usb_device::configure_for_async_io(usb_direction direction, int endpoint_number) { - auto intf_handle = check_valid_endpoint(direction, endpoint_number)->intf_handle; + auto winusb_handle = check_valid_endpoint(direction, endpoint_number)->winusb_handle; UCHAR endpoint_address = ep_address(direction, endpoint_number); ULONG timeout = 0; - if (!WinUsb_SetPipePolicy(intf_handle, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(timeout), &timeout)) + if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(timeout), &timeout)) usb_error::throw_error("Failed to set endpoint timeout"); UCHAR raw_io = 1; - if (!WinUsb_SetPipePolicy(intf_handle, endpoint_address, RAW_IO, sizeof(raw_io), &raw_io)) + if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address, RAW_IO, sizeof(raw_io), &raw_io)) usb_error::throw_error("Failed to set endpoint for raw IO"); } void usb_device::submit_transfer_in(int endpoint_number, uint8_t* buffer, int buffer_len, OVERLAPPED* overlapped) { - auto intf_handle = check_valid_endpoint(usb_direction::in, endpoint_number)->intf_handle; + auto winusb_handle = check_valid_endpoint(usb_direction::in, endpoint_number)->winusb_handle; UCHAR endpoint_address = ep_address(usb_direction::in, endpoint_number); - if (!WinUsb_ReadPipe(intf_handle, endpoint_address, buffer, buffer_len, nullptr, overlapped)) { + if (!WinUsb_ReadPipe(winusb_handle, endpoint_address, buffer, buffer_len, nullptr, overlapped)) { DWORD err = GetLastError(); if (err == ERROR_IO_PENDING) return; @@ -427,10 +439,10 @@ void usb_device::submit_transfer_in(int endpoint_number, uint8_t* buffer, int bu void usb_device::submit_transfer_out(int endpoint_number, uint8_t* data, int data_len, OVERLAPPED* overlapped) { - auto intf_handle = check_valid_endpoint(usb_direction::out, endpoint_number)->intf_handle; + auto winusb_handle = check_valid_endpoint(usb_direction::out, endpoint_number)->winusb_handle; UCHAR endpoint_address = ep_address(usb_direction::out, endpoint_number); - if (!WinUsb_WritePipe(intf_handle, endpoint_address, data, data_len, nullptr, overlapped)) { + if (!WinUsb_WritePipe(winusb_handle, endpoint_address, data, data_len, nullptr, overlapped)) { DWORD err = GetLastError(); if (err == ERROR_IO_PENDING) return; @@ -543,4 +555,4 @@ int usb_device::extract_interface_number(const std::vector& hardwa usb_device::interface_handle::interface_handle(int intf_num, int first_num, std::wstring&& path) : interface_num(intf_num), first_interface_num(first_num), - device_handle(nullptr), intf_handle(nullptr), device_open_count(0) { } + device_handle(nullptr), winusb_handle(nullptr), device_open_count(0) { } diff --git a/reference/windows/USB/usb_device.hpp b/reference/windows/USB/usb_device.hpp index 18a69dec..f651ef43 100644 --- a/reference/windows/USB/usb_device.hpp +++ b/reference/windows/USB/usb_device.hpp @@ -242,7 +242,7 @@ class usb_device { int interface_num; int first_interface_num; HANDLE device_handle; - WINUSB_INTERFACE_HANDLE intf_handle; + WINUSB_INTERFACE_HANDLE winusb_handle; int device_open_count; interface_handle(int intf_num, int first_num, std::wstring&& path); From 8a71956019ffebf595176f54b21995761a9dbd22 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 26 Sep 2023 22:32:09 +0200 Subject: [PATCH 290/433] Windows: improved handling of composite devices --- java-does-usb/pom.xml | 12 + .../usb/windows/InterfaceHandle.java | 13 +- .../usb/windows/WindowsUSBDevice.java | 268 ++++++++++++------ .../usb/windows/WindowsUSBDeviceRegistry.java | 102 +------ .../codecrete/usb/windows/winsdk/WinUSB2.java | 14 + .../src/test/resources/tinylog.properties | 3 + reference/windows/USB/usb_device.cpp | 14 +- reference/windows/USB/usb_device.hpp | 3 +- reference/windows/USB/usb_registry.cpp | 7 +- reference/windows/USB/usb_registry.hpp | 3 +- 10 files changed, 239 insertions(+), 200 deletions(-) create mode 100644 java-does-usb/src/test/resources/tinylog.properties diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 30c4f9e1..7f458d46 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -149,6 +149,18 @@ 3.24.2 test + + org.tinylog + tinylog-impl + 2.6.2 + test + + + org.tinylog + jsl-tinylog + 2.6.2 + test + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java index 91cc9bd4..f5c87375 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java @@ -13,6 +13,10 @@ * Handles for WinUSB devices and interfaces */ class InterfaceHandle { + InterfaceHandle(int interfaceNumber, int firstInterfaceNumber) { + this.interfaceNumber = interfaceNumber; + this.firstInterfaceNumber = firstInterfaceNumber; + } /** * The number of this interface. */ @@ -21,13 +25,6 @@ class InterfaceHandle { * The number of the first interface in the same composite function. */ int firstInterfaceNumber; - /** - * The device path. - *

- * This is only set for the first interface in a composite function. - *

- */ - String devicePath; /** * The file handle of the device. *

@@ -39,7 +36,7 @@ class InterfaceHandle { * The WinUSB handle of the interface. */ @SuppressWarnings("java:S1700") - MemorySegment interfaceHandle; + MemorySegment winusbHandle; /** * Count indicating how many interface depend on the device being open. */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index ed7601fe..f43c1584 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -7,10 +7,7 @@ package net.codecrete.usb.windows; -import net.codecrete.usb.USBControlTransfer; -import net.codecrete.usb.USBDirection; -import net.codecrete.usb.USBRecipient; -import net.codecrete.usb.USBTransferType; +import net.codecrete.usb.*; import net.codecrete.usb.common.Transfer; import net.codecrete.usb.common.USBDeviceImpl; import net.codecrete.usb.usbstandard.SetupPacket; @@ -23,13 +20,18 @@ import java.io.OutputStream; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.regex.Pattern; +import static java.lang.System.Logger.Level.DEBUG; +import static java.lang.System.Logger.Level.INFO; import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.common.ForeignMemory.dereference; +import static net.codecrete.usb.windows.DevicePropertyKey.Children; +import static net.codecrete.usb.windows.DevicePropertyKey.HardwareIds; import static net.codecrete.usb.windows.Win.allocateErrorState; import static net.codecrete.usb.windows.WindowsUSBException.throwException; import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; @@ -40,42 +42,36 @@ @SuppressWarnings("java:S2160") public class WindowsUSBDevice extends USBDeviceImpl { + private static final System.Logger LOG = System.getLogger(WindowsUSBDevice.class.getName()); + private final WindowsAsyncTask asyncTask; private List interfaceHandles; + // device paths by interface number (first interface of function) + private Map devicePaths; + /** * Indicates if {@link #open()} has been called. Since separate interfaces can have separate underlying * Windows device, {@link #claimInterface(int)} instead of {@link #open()} will open the Windows device. */ private boolean showAsOpen; - WindowsUSBDevice(String devicePath, Map children, - int vendorId, int productId, MemorySegment configDesc) { + WindowsUSBDevice(String devicePath, int vendorId, int productId, MemorySegment configDesc) { super(devicePath, vendorId, productId); asyncTask = WindowsAsyncTask.INSTANCE; - readDescription(configDesc, devicePath, children); + readDescription(configDesc); } - private void readDescription(MemorySegment configDesc, String devicePath, Map children) { + private void readDescription(MemorySegment configDesc) { var configuration = setConfigurationDescriptor(configDesc); // build list of interface handles - interfaceHandles = new ArrayList<>(); - for (var intf : configuration.interfaces()) { - var interfaceNumber = intf.number(); - var function = configuration.findFunction(interfaceNumber); - - var intfHandle = new InterfaceHandle(); - intfHandle.interfaceNumber = interfaceNumber; - if (function.firstInterfaceNumber() == interfaceNumber) { - if (children == null) { - intfHandle.devicePath = devicePath; - } else { - intfHandle.devicePath = children.get(interfaceNumber); - } - } - intfHandle.firstInterfaceNumber = function.firstInterfaceNumber(); - interfaceHandles.add(intfHandle); - } + interfaceHandles = configuration.interfaces().stream() + .map(intf -> { + var interfaceNumber = intf.number(); + var function = configuration.findFunction(interfaceNumber); + return new InterfaceHandle(interfaceNumber, function.firstInterfaceNumber()); + }). + toList(); } @Override @@ -107,55 +103,62 @@ public synchronized void close() { public synchronized void claimInterface(int interfaceNumber) { checkIsOpen(); - var intfHandle = getInterfaceHandle(interfaceNumber); - if (intfHandle.interfaceHandle != null) - throwException("interface %d has already been claimed", interfaceNumber); + getInterfaceWithCheck(interfaceNumber, false); + var intfHandle = getInterfaceHandle(interfaceNumber); var firstIntfHandle = intfHandle; if (intfHandle.firstInterfaceNumber != interfaceNumber) firstIntfHandle = getInterfaceHandle(intfHandle.firstInterfaceNumber); - if (firstIntfHandle.devicePath == null) - throwException("interface number %d cannot be claimed (non WinUSB device?)", interfaceNumber); - try (var arena = Arena.ofConfined()) { - - MemorySegment deviceHandle; var errorState = allocateErrorState(arena); - // open Windows device if needed + // both the device and the first interface must be opened for any interface belonging to the same function if (firstIntfHandle.deviceHandle == null) { - var pathSegment = Win.createSegmentFromString(firstIntfHandle.devicePath, arena); - deviceHandle = Kernel32B.CreateFileW(pathSegment, Kernel32.GENERIC_WRITE() | Kernel32.GENERIC_READ(), + var devicePath = getInterfaceDevicePath(firstIntfHandle.interfaceNumber); + if (devicePath == null) + throw new USBException("claiming interface failed (function has no device path, might be missing WinUSB driver)"); + + LOG.log(DEBUG, "opening device {0}", devicePath); + + // open Windows device if needed + var pathSegment = Win.createSegmentFromString(devicePath, arena); + var deviceHandle = Kernel32B.CreateFileW(pathSegment, Kernel32.GENERIC_WRITE() | Kernel32.GENERIC_READ(), Kernel32.FILE_SHARE_WRITE() | Kernel32.FILE_SHARE_READ(), NULL, Kernel32.OPEN_EXISTING(), Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), NULL, errorState); if (Win.isInvalidHandle(deviceHandle)) - throwLastError(errorState, "opening USB device %s failed", firstIntfHandle.devicePath); - - asyncTask.addDevice(deviceHandle); - - } else { - deviceHandle = firstIntfHandle.deviceHandle; + throwLastError(errorState, "claiming interface failed (opening USB device %s failed)", devicePath); + + try { + // open first interface + var interfaceHandleHolder = arena.allocate(ADDRESS); + if (WinUSB2.WinUsb_Initialize(deviceHandle, interfaceHandleHolder, errorState) == 0) + throwLastError(errorState, "claiming interface failed"); + var interfaceHandle = dereference(interfaceHandleHolder); + + firstIntfHandle.deviceHandle = deviceHandle; + firstIntfHandle.winusbHandle = interfaceHandle; + asyncTask.addDevice(deviceHandle); + + } catch (Exception e) { + Kernel32.CloseHandle(deviceHandle); + throw e; + } } - try { - // open interface + if (intfHandle != firstIntfHandle) { + // open associated interface var interfaceHandleHolder = arena.allocate(ADDRESS); - if (WinUSB2.WinUsb_Initialize(deviceHandle, interfaceHandleHolder, errorState) == 0) - throwLastError(errorState, "opening WinUSB device failed"); - var interfaceHandle = dereference(interfaceHandleHolder); - - firstIntfHandle.deviceHandle = deviceHandle; - firstIntfHandle.deviceOpenCount += 1; - intfHandle.interfaceHandle = interfaceHandle; - - } catch (Exception e) { - Kernel32.CloseHandle(deviceHandle); - throw e; + if (WinUSB2.WinUsb_GetAssociatedInterface(firstIntfHandle.winusbHandle, + (byte)(intfHandle.interfaceNumber - firstIntfHandle.interfaceNumber - 1), + interfaceHandleHolder, errorState) == 0) + throwLastError(errorState, "claiming (associated) interface failed"); + intfHandle.winusbHandle = dereference(interfaceHandleHolder); } } + firstIntfHandle.deviceOpenCount += 1; setClaimed(interfaceNumber, true); } @@ -163,11 +166,8 @@ public synchronized void claimInterface(int interfaceNumber) { public synchronized void selectAlternateSetting(int interfaceNumber, int alternateNumber) { checkIsOpen(); + var intf = getInterfaceWithCheck(interfaceNumber, true); var intfHandle = getInterfaceHandle(interfaceNumber); - if (intfHandle.interfaceHandle == null) - throwException("interface %d has not been claimed", interfaceNumber); - - var intf = getInterface(interfaceNumber); // check alternate setting var altSetting = intf.getAlternate(alternateNumber); @@ -177,7 +177,7 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); - if (WinUSB2.WinUsb_SetCurrentAlternateSetting(intfHandle.interfaceHandle, (byte) alternateNumber, + if (WinUSB2.WinUsb_SetCurrentAlternateSetting(intfHandle.winusbHandle, (byte) alternateNumber, errorState) == 0) throwLastError(errorState, "setting alternate interface failed"); } @@ -187,26 +187,30 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna public synchronized void releaseInterface(int interfaceNumber) { checkIsOpen(); - var intfHandle = getInterfaceHandle(interfaceNumber); - if (intfHandle.interfaceHandle == null) - throwException("interface %d has not been claimed", interfaceNumber); + getInterfaceWithCheck(interfaceNumber, true); + var intfHandle = getInterfaceHandle(interfaceNumber); var firstIntfHandle = intfHandle; if (intfHandle.firstInterfaceNumber != interfaceNumber) firstIntfHandle = getInterfaceHandle(intfHandle.firstInterfaceNumber); - // close interface - WinUSB.WinUsb_Free(intfHandle.interfaceHandle); - intfHandle.interfaceHandle = null; + setClaimed(interfaceNumber, false); - // close device + if (intfHandle != firstIntfHandle) { + // close associated interface + WinUSB.WinUsb_Free(intfHandle.winusbHandle); + intfHandle.winusbHandle = null; + } + + // close device if needed firstIntfHandle.deviceOpenCount -= 1; if (firstIntfHandle.deviceOpenCount == 0) { + WinUSB.WinUsb_Free(firstIntfHandle.winusbHandle); + firstIntfHandle.winusbHandle = null; + Kernel32.CloseHandle(firstIntfHandle.deviceHandle); firstIntfHandle.deviceHandle = null; } - - setClaimed(interfaceNumber, false); } @Override @@ -321,7 +325,7 @@ synchronized void submitControlTransfer(USBDirection direction, USBControlTransf asyncTask.prepareForSubmission(transfer); // submit transfer - if (WinUSB2.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket.segment(), transfer.data(), + if (WinUSB2.WinUsb_ControlTransfer(intfHandle.winusbHandle, setupPacket.segment(), transfer.data(), transfer.dataSize(), NULL, transfer.overlapped(), errorState) == 0) { var err = Win.getLastError(errorState); if (err != Kernel32.ERROR_IO_PENDING()) @@ -339,7 +343,7 @@ synchronized void submitTransferOut(int endpointNumber, WindowsTransfer transfer asyncTask.prepareForSubmission(transfer); // submit transfer - if (WinUSB2.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), transfer.data(), + if (WinUSB2.WinUsb_WritePipe(intfHandle.winusbHandle, endpoint.endpointAddress(), transfer.data(), transfer.dataSize(), NULL, transfer.overlapped(), errorState) == 0) { var err = Win.getLastError(errorState); if (err != Kernel32.ERROR_IO_PENDING()) @@ -357,7 +361,7 @@ synchronized void submitTransferIn(int endpointNumber, WindowsTransfer transfer) asyncTask.prepareForSubmission(transfer); // submit transfer - if (WinUSB2.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), transfer.data(), + if (WinUSB2.WinUsb_ReadPipe(intfHandle.winusbHandle, endpoint.endpointAddress(), transfer.data(), transfer.dataSize(), NULL, transfer.overlapped(), errorState) == 0) { var err = Win.getLastError(errorState); if (err != Kernel32.ERROR_IO_PENDING()) @@ -374,12 +378,12 @@ synchronized void configureForAsyncIo(USBDirection direction, int endpointNumber var errorState = allocateErrorState(arena); var timeoutHolder = arena.allocate(JAVA_INT, 0); - if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), + if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.winusbHandle, endpoint.endpointAddress(), WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder, errorState) == 0) throwLastError(errorState, "setting timeout failed"); var rawIoHolder = arena.allocate(JAVA_BYTE, (byte) 1); - if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(), WinUSB.RAW_IO(), + if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.winusbHandle, endpoint.endpointAddress(), WinUSB.RAW_IO(), (int) rawIoHolder.byteSize(), rawIoHolder, errorState) == 0) throwLastError(errorState, "setting raw IO failed"); } @@ -392,7 +396,7 @@ public synchronized void clearHalt(USBDirection direction, int endpointNumber) { try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); - if (WinUSB2.WinUsb_ResetPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), errorState) == 0) + if (WinUSB2.WinUsb_ResetPipe(intfHandle.winusbHandle, endpoint.endpointAddress(), errorState) == 0) throwLastError(errorState, "clearing halt failed"); } } @@ -404,7 +408,7 @@ public synchronized void abortTransfers(USBDirection direction, int endpointNumb try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); - if (WinUSB2.WinUsb_AbortPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), errorState) == 0) + if (WinUSB2.WinUsb_AbortPipe(intfHandle.winusbHandle, endpoint.endpointAddress(), errorState) == 0) throwLastError(errorState, "aborting transfers on endpoint failed"); } } @@ -457,18 +461,124 @@ private InterfaceHandle findControlTransferInterface(USBControlTransfer setup) { if (interfaceNumber >= 0) { var intfHandle = getInterfaceHandle(interfaceNumber); - if (intfHandle.interfaceHandle == null) + if (intfHandle.winusbHandle == null) throwException("interface number %d has not been claimed", interfaceNumber); return intfHandle; } // for control transfer to device, use any claimed interface for (var intfHandle : interfaceHandles) { - if (intfHandle.interfaceHandle != null) + if (intfHandle.winusbHandle != null) return intfHandle; } throwException("control transfer cannot be executed as no interface has been claimed"); throw new AssertionError("not reached"); } + + private String getInterfaceDevicePath(int interfaceNumber) { + var parentDevicePath = (String) getUniqueId(); // device path is id + if (interfaceNumber == 0) + return parentDevicePath; + + if (devicePaths != null) { + var devicePath = devicePaths.get(interfaceNumber); + if (devicePath != null) + return devicePath; + } + + // When a device is plugged in, a notification is sent. For composite devices, it is a notification + // that the information for the composite device is ready. Each composite function will be registered + // separately and the related information will be available with a delay. So for composite functions, + // several retries might be needed until the device path is available. + var numRetries = 30; // 30 x 100ms + while (true) { + try (var deviceInfoSet = DeviceInfoSet.ofPath(parentDevicePath)) { + if (!deviceInfoSet.isCompositeDevice()) + throwException("internal error: interface belongs to a separate function but device is not composite"); + + var childrenInstanceIDs = deviceInfoSet.getStringListProperty(Children); + if (childrenInstanceIDs == null) { + LOG.log(DEBUG, "missing children instance IDs for device {0}", parentDevicePath); + + } else { + LOG.log(DEBUG, "children instance IDs: {0}", childrenInstanceIDs); + + for (var instanceId : childrenInstanceIDs) { + var res = fetchChildDevicePath(instanceId, interfaceNumber); + if (res == 1) + return devicePaths.get(interfaceNumber); // success + if (res == -1) + break; // retry later + } + } + + numRetries -= 1; + if (numRetries == 0) + return null; // failure + + // sleep and retry + try { + LOG.log(DEBUG, "Sleeping for 100ms..."); + //noinspection BusyWait + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + } + + private int fetchChildDevicePath(String instanceId, int interfaceNumber) { + try (var deviceInfoSet = DeviceInfoSet.ofInstance(instanceId)) { + + // get hardware IDs (to extract interface number) + var hardwareIds = deviceInfoSet.getStringListProperty(HardwareIds); + if (hardwareIds == null) { + LOG.log(DEBUG, "child device {0} has no hardware IDs", instanceId); + return 0; // continue with next child + } + + var extractedNumber = extractInterfaceNumber(hardwareIds); + if (extractedNumber == -1) { + LOG.log(DEBUG, "child device {0} has no interface number", instanceId); + return 0; // continue with next child + } + + if (extractedNumber != interfaceNumber) + return 0; // continue with next child + + var devicePath = deviceInfoSet.getDevicePathByGUID(instanceId); + if (devicePath == null) { + LOG.log(INFO, "Child device {0} has no device path", instanceId); + return -1; // retry later + } + + if (devicePaths == null) + devicePaths = new HashMap<>(); + devicePaths.put(interfaceNumber, devicePath); + return 1; // success + } + } + + private static final Pattern MULTIPLE_INTERFACE_ID = Pattern.compile( + "USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); + + private static int extractInterfaceNumber(List hardwareIds) { + // Also see https://docs.microsoft.com/en-us/windows-hardware/drivers/install/standard-usb-identifiers#multiple-interface-usb-devices + + for (var id : hardwareIds) { + var matcher = MULTIPLE_INTERFACE_ID.matcher(id); + if (matcher.find()) { + var intfHexNumber = matcher.group(1); + try { + return Integer.parseInt(intfHexNumber, 16); + } catch (NumberFormatException e) { + // ignore and try next one + } + } + } + + return -1; + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index e9f05e69..474d6799 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -31,10 +31,7 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.*; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import static java.lang.System.Logger.Level.DEBUG; import static java.lang.System.Logger.Level.INFO; import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.*; @@ -177,61 +174,19 @@ private USBDevice createDeviceFromDeviceInfo(DeviceInfoSet deviceInfoSet, String hubHandles.put(hubPath, hubHandle); } - // check for composite device - var children = getChildDevices(deviceInfoSet, devicePath); - - return createDevice(devicePath, children, hubHandle, usbPortNum); - } - } - - @SuppressWarnings({"java:S106", "java:S1168"}) - private Map getChildDevices(DeviceInfoSet deviceInfoSet, String devicePath) { - if (!deviceInfoSet.isCompositeDevice()) - return null; - - // For certain devices, it seems to take some time until the "Device_Children" - // entry is present. So we retry a few times if needed and pause in between. - List childrenInstanceIDs; - var numTries = 5; - while (true) { - numTries -= 1; - childrenInstanceIDs = deviceInfoSet.getStringListProperty(Children); - if (childrenInstanceIDs != null || numTries == 0) - break; - - // sleep and retry - try { - LOG.log(DEBUG, "Sleeping for 200ms (after unsuccessfully retrieving DEVPKEY_Device_Children)"); - //noinspection BusyWait - Thread.sleep(200); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } + return createDevice(devicePath, hubHandle, usbPortNum); } - - if (childrenInstanceIDs == null) { - LOG.log(DEBUG, "unable to retrieve information about children of device {0} - ignoring", devicePath); - return null; - } - - // create children map (interface number -> device path) - return childrenInstanceIDs.stream() - .map(WindowsUSBDeviceRegistry::getNumberPathTuple) - .filter(Objects::nonNull) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } /** * Retrieve device descriptor and create {@code USBDevice} instance * * @param devicePath the device path - * @param children map of child device paths, indexed by the first interface number * @param hubHandle the hub handle (parent) * @param usbPortNum the USB port number * @return the {@code USBDevice} instance */ - private USBDevice createDevice(String devicePath, Map children, MemorySegment hubHandle, - int usbPortNum) { + private USBDevice createDevice(String devicePath, MemorySegment hubHandle, int usbPortNum) { try (var arena = Arena.ofConfined()) { @@ -253,7 +208,8 @@ private USBDevice createDevice(String devicePath, Map children, var configDesc = getDescriptor(hubHandle, usbPortNum, CONFIGURATION_DESCRIPTOR_TYPE, 0, (short) 0, arena); - var device = new WindowsUSBDevice(devicePath, children, vendorId, productId, configDesc); + // create new device + var device = new WindowsUSBDevice(devicePath, vendorId, productId, configDesc); device.setFromDeviceDescriptor(descriptorSegment); device.setProductString(descriptorSegment, index -> getStringDescriptor(hubHandle, usbPortNum, index)); @@ -397,54 +353,4 @@ protected int findDeviceIndex(List deviceList, Object deviceId) { } return -1; } - - /** - * Looks up the interface number and device path for the child device with the given instance ID. - * - * @param instanceId child instance ID - * @return tuple consisting of interface number and device path, or {@code null} if unsuccessful - */ - private static Map.Entry getNumberPathTuple(String instanceId) { - try (var deviceInfoSet = DeviceInfoSet.ofInstance(instanceId)) { - - // get hardware IDs (to extract interface number) - var hardwareIds = deviceInfoSet.getStringListProperty(HardwareIds); - if (hardwareIds == null) - throwException("internal error (device property 'HardwareIds' is missing)"); - var interfaceNumber = extractInterfaceNumber(hardwareIds); - if (interfaceNumber == -1) { - LOG.log(DEBUG, "Child device {0} has no interface number", instanceId); - return null; - } - - var devicePath = deviceInfoSet.getDevicePathByGUID(instanceId); - if (devicePath == null) { - LOG.log(DEBUG, "Child device {0} has no device path", instanceId); - return null; - } - - return new AbstractMap.SimpleImmutableEntry<>(interfaceNumber, devicePath); - } - } - - private static final Pattern MULTIPLE_INTERFACE_ID = Pattern.compile( - "USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); - - private static int extractInterfaceNumber(List hardwareIds) { - // Also see https://docs.microsoft.com/en-us/windows-hardware/drivers/install/standard-usb-identifiers#multiple-interface-usb-devices - - for (var id : hardwareIds) { - var matcher = MULTIPLE_INTERFACE_ID.matcher(id); - if (matcher.find()) { - var intfHexNumber = matcher.group(1); - try { - return Integer.parseInt(intfHexNumber, 16); - } catch (NumberFormatException e) { - // ignore and try next one - } - } - } - - return -1; - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java index 57aab265..940ae40e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java @@ -51,6 +51,20 @@ public static int WinUsb_Initialize(MemorySegment DeviceHandle, MemorySegment In } } + private static final FunctionDescriptor WinUsb_GetAssociatedInterface$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS); + + private static final MethodHandle WinUsb_GetAssociatedInterface$MH = + LINKER.downcallHandle(LOOKUP.find("WinUsb_GetAssociatedInterface").get(), WinUsb_GetAssociatedInterface$FUNC, Win.LAST_ERROR_STATE); + + public static int WinUsb_GetAssociatedInterface(MemorySegment InterfaceHandle, byte AssociatedInterfaceIndex, + MemorySegment AssociatedInterfaceHandle, MemorySegment lastErrorState) { + try { + return (int) WinUsb_GetAssociatedInterface$MH.invokeExact(lastErrorState, InterfaceHandle, AssociatedInterfaceIndex, AssociatedInterfaceHandle); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + private static final FunctionDescriptor WinUsb_SetCurrentAlternateSetting$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE); diff --git a/java-does-usb/src/test/resources/tinylog.properties b/java-does-usb/src/test/resources/tinylog.properties new file mode 100644 index 00000000..08b5f1d0 --- /dev/null +++ b/java-does-usb/src/test/resources/tinylog.properties @@ -0,0 +1,3 @@ +writer = console +writer.format = {date: HH:mm:ss.SSS} {level|size=5} [{class|size=40}] {message} +writer.level = debug diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp index 959e88d3..59c083c2 100644 --- a/reference/windows/USB/usb_device.cpp +++ b/reference/windows/USB/usb_device.cpp @@ -22,8 +22,8 @@ #include #include -usb_device::usb_device(usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, bool is_composite) -: registry_(registry), vendor_id_(vendor_id), product_id_(product_id), is_open_(false), device_path_(std::move(device_path)), is_composite_(is_composite) { +usb_device::usb_device(usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc) +: registry_(registry), vendor_id_(vendor_id), product_id_(product_id), is_open_(false), device_path_(std::move(device_path)) { config_parser parser{}; parser.parse(config_desc.data(), static_cast(config_desc.size())); @@ -513,27 +513,27 @@ int usb_device::get_child_device_path(const std::wstring& child_id, int interfac auto hardware_ids = dev_info_set.get_device_property_string_list(DEVPKEY_Device_HardwareIds); if (hardware_ids.empty()) { std::wcerr << "child device " << child_id << " has no hardware IDs" << std::endl; - return 0; + return 0; // continue with next child } auto intf_num = extract_interface_number(hardware_ids); if (intf_num == -1) { std::wcerr << "child device " << child_id << " has no interface number" << std::endl; - return 0; + return 0; // continue with next child } if (intf_num != interface_num) - return 0; + return 0; // continue with next child device_path = dev_info_set.get_device_path_by_guid(child_id); if (device_path.empty()) { std::wcerr << "child device " << child_id << " has no device path" << std::endl; - return -1; + return -1; // retry later } std::wcerr << "child device: interface=" << intf_num << ", device path=" << device_path << std::endl; interface_device_paths_[interface_num] = device_path; - return 1; + return 1; // success } static const std::wregex multiple_interface_id_pattern(L"USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); diff --git a/reference/windows/USB/usb_device.hpp b/reference/windows/USB/usb_device.hpp index f651ef43..520d8431 100644 --- a/reference/windows/USB/usb_device.hpp +++ b/reference/windows/USB/usb_device.hpp @@ -248,7 +248,7 @@ class usb_device { interface_handle(int intf_num, int first_num, std::wstring&& path); }; - usb_device(usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, bool is_composite); + usb_device(usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc); void set_product_names(const std::string& manufacturer, const std::string& product, const std::string& serial_number); void build_handles(const std::wstring& device_path); std::wstring get_interface_device_path(int interface_num); @@ -289,7 +289,6 @@ class usb_device { std::vector functions_; std::vector interface_handles_; std::map interface_device_paths_; - bool is_composite_; friend class usb_registry; friend class usb_istreambuf; diff --git a/reference/windows/USB/usb_registry.cpp b/reference/windows/USB/usb_registry.cpp index a92a1fbf..d3d3cc10 100644 --- a/reference/windows/USB/usb_registry.cpp +++ b/reference/windows/USB/usb_registry.cpp @@ -167,10 +167,10 @@ std::shared_ptr usb_registry::create_device_from_device_info(device_ hub_handles[hub_path] = hub_handle; } - return create_device(std::move(device_path), dev_info_set.is_composite_device(), hub_handle, usb_port_num); + return create_device(std::move(device_path), hub_handle, usb_port_num); } -std::shared_ptr usb_registry::create_device(std::wstring&& device_path, bool is_composite, HANDLE hub_handle, DWORD usb_port_num) { +std::shared_ptr usb_registry::create_device(std::wstring&& device_path, HANDLE hub_handle, DWORD usb_port_num) { // get device descriptor USB_NODE_CONNECTION_INFORMATION_EX conn_info = { 0 }; @@ -186,8 +186,7 @@ std::shared_ptr usb_registry::create_device(std::wstring&& device_pa auto config_desc = get_descriptor(hub_handle, usb_port_num, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0); // Create new device - // usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, std::map&& children - std::shared_ptr device(new usb_device(this, std::move(device_path), vendorId, productId, config_desc, is_composite)); + std::shared_ptr device(new usb_device(this, std::move(device_path), vendorId, productId, config_desc)); device->set_product_names( get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iManufacturer), get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iProduct), diff --git a/reference/windows/USB/usb_registry.hpp b/reference/windows/USB/usb_registry.hpp index 6ba0f946..0064dc9e 100644 --- a/reference/windows/USB/usb_registry.hpp +++ b/reference/windows/USB/usb_registry.hpp @@ -53,11 +53,10 @@ class usb_registry { void detect_present_devices(); std::shared_ptr create_device_from_device_info(device_info_set& dev_info_set, std::wstring&& device_path, std::map& hub_handles); - std::shared_ptr create_device(std::wstring&& device_path, bool is_composite, HANDLE hub_handle, DWORD usb_port_num); + std::shared_ptr create_device(std::wstring&& device_path, HANDLE hub_handle, DWORD usb_port_num); static std::string get_string(HANDLE hub_handle, ULONG usb_port_num, int index); static std::vector get_descriptor(HANDLE hub_handle, ULONG usb_port_num, uint16_t descriptor_type, int index, int language_id, int request_size = 0); - static int extract_interface_number(const std::vector& hardware_ids); void on_device_connected(const WCHAR* path); void on_device_disconnected(const WCHAR* path); From 09fe4842e095fe7d7155a6de0bc3123ff2b56eac Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 28 Sep 2023 20:25:56 +0200 Subject: [PATCH 291/433] Windows: don't block other threads while waiting --- .../usb/windows/WindowsUSBDevice.java | 106 +++++++++++------- .../codecrete/usb/special/MonitorDevices.java | 33 +++++- 2 files changed, 93 insertions(+), 46 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index f43c1584..5664dd00 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -44,6 +44,10 @@ public class WindowsUSBDevice extends USBDeviceImpl { private static final System.Logger LOG = System.getLogger(WindowsUSBDevice.class.getName()); + private static final int RETRY_LATER = 0; + private static final int TRY_NEXT_CHILD = 1; + private static final int SUCCESS = 2; + private final WindowsAsyncTask asyncTask; private List interfaceHandles; // device paths by interface number (first interface of function) @@ -100,7 +104,32 @@ public synchronized void close() { showAsOpen = false; } - public synchronized void claimInterface(int interfaceNumber) { + public void claimInterface(int interfaceNumber) { + // When a device is plugged in, a notification is sent. For composite devices, it is a notification + // that the composite device is ready. Each composite function will be registered separately and + // the related information will be available with a delay. So for composite functions, several + // retries might be needed until the device path is available. + var numRetries = 30; // 30 x 100ms + while (true) { + if (claimInteraceSynchronized(interfaceNumber)) + return; // success + + numRetries -= 1; + if (numRetries == 0) + throw new USBException("claiming interface failed (function has no device path, might be missing WinUSB driver)"); + + // sleep and retry + try { + LOG.log(DEBUG, "Sleeping for 100ms..."); + //noinspection BusyWait + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + + private synchronized boolean claimInteraceSynchronized(int interfaceNumber) { checkIsOpen(); getInterfaceWithCheck(interfaceNumber, false); @@ -117,7 +146,7 @@ public synchronized void claimInterface(int interfaceNumber) { if (firstIntfHandle.deviceHandle == null) { var devicePath = getInterfaceDevicePath(firstIntfHandle.interfaceNumber); if (devicePath == null) - throw new USBException("claiming interface failed (function has no device path, might be missing WinUSB driver)"); + return false; // retry later LOG.log(DEBUG, "opening device {0}", devicePath); @@ -160,6 +189,7 @@ public synchronized void claimInterface(int interfaceNumber) { firstIntfHandle.deviceOpenCount += 1; setClaimed(interfaceNumber, true); + return true; } @Override @@ -208,6 +238,15 @@ public synchronized void releaseInterface(int interfaceNumber) { WinUSB.WinUsb_Free(firstIntfHandle.winusbHandle); firstIntfHandle.winusbHandle = null; + var path = (String)getUniqueId(); + if (firstIntfHandle.interfaceNumber != 0) { + if (devicePaths != null) + path = devicePaths.get(firstIntfHandle.interfaceNumber); + else + path = null; + } + LOG.log(DEBUG, "closing device {0}", path); + Kernel32.CloseHandle(firstIntfHandle.deviceHandle); firstIntfHandle.deviceHandle = null; } @@ -487,46 +526,29 @@ private String getInterfaceDevicePath(int interfaceNumber) { return devicePath; } - // When a device is plugged in, a notification is sent. For composite devices, it is a notification - // that the information for the composite device is ready. Each composite function will be registered - // separately and the related information will be available with a delay. So for composite functions, - // several retries might be needed until the device path is available. - var numRetries = 30; // 30 x 100ms - while (true) { - try (var deviceInfoSet = DeviceInfoSet.ofPath(parentDevicePath)) { - if (!deviceInfoSet.isCompositeDevice()) - throwException("internal error: interface belongs to a separate function but device is not composite"); - - var childrenInstanceIDs = deviceInfoSet.getStringListProperty(Children); - if (childrenInstanceIDs == null) { - LOG.log(DEBUG, "missing children instance IDs for device {0}", parentDevicePath); - - } else { - LOG.log(DEBUG, "children instance IDs: {0}", childrenInstanceIDs); - - for (var instanceId : childrenInstanceIDs) { - var res = fetchChildDevicePath(instanceId, interfaceNumber); - if (res == 1) - return devicePaths.get(interfaceNumber); // success - if (res == -1) - break; // retry later - } - } + try (var deviceInfoSet = DeviceInfoSet.ofPath(parentDevicePath)) { + if (!deviceInfoSet.isCompositeDevice()) + throwException("internal error: interface belongs to a composite function but device is not composite"); - numRetries -= 1; - if (numRetries == 0) - return null; // failure + var childrenInstanceIDs = deviceInfoSet.getStringListProperty(Children); + if (childrenInstanceIDs == null) { + LOG.log(DEBUG, "missing children instance IDs for device {0}", parentDevicePath); + return null; - // sleep and retry - try { - LOG.log(DEBUG, "Sleeping for 100ms..."); - //noinspection BusyWait - Thread.sleep(100); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); + } else { + LOG.log(DEBUG, "children instance IDs: {0}", childrenInstanceIDs); + + for (var instanceId : childrenInstanceIDs) { + var res = fetchChildDevicePath(instanceId, interfaceNumber); + if (res == SUCCESS) + return devicePaths.get(interfaceNumber); + if (res == RETRY_LATER) + return null; // retry later } } } + + return null; // retry later } private int fetchChildDevicePath(String instanceId, int interfaceNumber) { @@ -536,28 +558,28 @@ private int fetchChildDevicePath(String instanceId, int interfaceNumber) { var hardwareIds = deviceInfoSet.getStringListProperty(HardwareIds); if (hardwareIds == null) { LOG.log(DEBUG, "child device {0} has no hardware IDs", instanceId); - return 0; // continue with next child + return TRY_NEXT_CHILD; } var extractedNumber = extractInterfaceNumber(hardwareIds); if (extractedNumber == -1) { LOG.log(DEBUG, "child device {0} has no interface number", instanceId); - return 0; // continue with next child + return TRY_NEXT_CHILD; } if (extractedNumber != interfaceNumber) - return 0; // continue with next child + return TRY_NEXT_CHILD; var devicePath = deviceInfoSet.getDevicePathByGUID(instanceId); if (devicePath == null) { LOG.log(INFO, "Child device {0} has no device path", instanceId); - return -1; // retry later + return RETRY_LATER; } if (devicePaths == null) devicePaths = new HashMap<>(); devicePaths.put(interfaceNumber, devicePath); - return 1; // success + return SUCCESS; } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java b/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java index 2aacff50..8fe853b2 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java @@ -7,12 +7,12 @@ package net.codecrete.usb.special; -import net.codecrete.usb.USB; +import net.codecrete.usb.*; import java.io.IOException; /** - * Sample program displaying information when USB devices are connected or disconnected. + * Test program that communicates with the device as soon as it has been pugged in. *

* Quit with Ctrl-C or whatever stops a program on your platform. *

@@ -20,14 +20,39 @@ public class MonitorDevices { public static void main(String[] args) throws IOException { - USB.setOnDeviceConnected((device) -> System.out.println("Connected: " + device.toString())); + USB.setOnDeviceConnected((device) -> { + System.out.println("Connected: " + device.toString()); + talkToTestDevice(device); + }); USB.setOnDeviceDisconnected((device) -> System.out.println("Disconnected: " + device.toString())); - for (var device : USB.getAllDevices()) + for (var device : USB.getAllDevices()) { System.out.println("Present: " + device.toString()); + talkToTestDevice(device); + } System.out.println("Monitoring..."); //noinspection ResultOfMethodCallIgnored System.in.read(); } + + private static void talkToTestDevice(USBDevice device) { + if (device.vendorId() != 0xcafe) + return; // no test device + + int interfaceNumber = device.productId() == 0xcea0 ? 2 : 0; + device.open(); + device.claimInterface(interfaceNumber); + var response = device.controlTransferIn( + new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, + (byte) 0x05, (short) 0, (short) interfaceNumber), + 1 + ); + + if (response.length == 1 || interfaceNumber == response[0]) { + System.out.println("Device responded"); + } else { + System.err.println("Invalid response from device"); + } + } } From 3c4e69c32d97191ae7b0b9b801b68bd77f9bc091 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 28 Sep 2023 22:17:28 +0200 Subject: [PATCH 292/433] Windows: more composite device handling improvements --- java-does-usb/pom.xml | 2 +- .../usb/windows/WindowsUSBDevice.java | 43 ++++++++++--------- .../usb/windows/WindowsUSBDeviceRegistry.java | 6 +-- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 7f458d46..2e484e24 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 0.6.0 + 0.6.1-SNAPSHOT 21 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index 5664dd00..c7dc99e0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -49,7 +49,13 @@ public class WindowsUSBDevice extends USBDeviceImpl { private static final int SUCCESS = 2; private final WindowsAsyncTask asyncTask; + /** + * Indicates if the device is a composite device + */ + private final boolean isComposite; + private List interfaceHandles; + // device paths by interface number (first interface of function) private Map devicePaths; @@ -59,9 +65,12 @@ public class WindowsUSBDevice extends USBDeviceImpl { */ private boolean showAsOpen; - WindowsUSBDevice(String devicePath, int vendorId, int productId, MemorySegment configDesc) { + WindowsUSBDevice(String devicePath, int vendorId, int productId, MemorySegment configDesc, boolean isComposite) { super(devicePath, vendorId, productId); asyncTask = WindowsAsyncTask.INSTANCE; + this.isComposite = isComposite; + if (isComposite) + devicePaths = new HashMap<>(); readDescription(configDesc); } @@ -238,14 +247,7 @@ public synchronized void releaseInterface(int interfaceNumber) { WinUSB.WinUsb_Free(firstIntfHandle.winusbHandle); firstIntfHandle.winusbHandle = null; - var path = (String)getUniqueId(); - if (firstIntfHandle.interfaceNumber != 0) { - if (devicePaths != null) - path = devicePaths.get(firstIntfHandle.interfaceNumber); - else - path = null; - } - LOG.log(DEBUG, "closing device {0}", path); + LOG.log(DEBUG, "closing device {0}", getCachedInterfaceDevicePath(interfaceNumber)); Kernel32.CloseHandle(firstIntfHandle.deviceHandle); firstIntfHandle.deviceHandle = null; @@ -516,20 +518,13 @@ private InterfaceHandle findControlTransferInterface(USBControlTransfer setup) { } private String getInterfaceDevicePath(int interfaceNumber) { - var parentDevicePath = (String) getUniqueId(); // device path is id - if (interfaceNumber == 0) - return parentDevicePath; - - if (devicePaths != null) { - var devicePath = devicePaths.get(interfaceNumber); - if (devicePath != null) - return devicePath; - } + var devicePath = getCachedInterfaceDevicePath(interfaceNumber); + if (devicePath != null) + return devicePath; - try (var deviceInfoSet = DeviceInfoSet.ofPath(parentDevicePath)) { - if (!deviceInfoSet.isCompositeDevice()) - throwException("internal error: interface belongs to a composite function but device is not composite"); + var parentDevicePath = (String) getUniqueId(); + try (var deviceInfoSet = DeviceInfoSet.ofPath(parentDevicePath)) { var childrenInstanceIDs = deviceInfoSet.getStringListProperty(Children); if (childrenInstanceIDs == null) { LOG.log(DEBUG, "missing children instance IDs for device {0}", parentDevicePath); @@ -551,6 +546,12 @@ private String getInterfaceDevicePath(int interfaceNumber) { return null; // retry later } + private String getCachedInterfaceDevicePath(int interfaceNumber) { + if (!isComposite) + return (String) getUniqueId(); + return devicePaths.get(interfaceNumber); + } + private int fetchChildDevicePath(String instanceId, int interfaceNumber) { try (var deviceInfoSet = DeviceInfoSet.ofInstance(instanceId)) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java index 474d6799..bc8ab227 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java @@ -174,7 +174,7 @@ private USBDevice createDeviceFromDeviceInfo(DeviceInfoSet deviceInfoSet, String hubHandles.put(hubPath, hubHandle); } - return createDevice(devicePath, hubHandle, usbPortNum); + return createDevice(devicePath, deviceInfoSet.isCompositeDevice(), hubHandle, usbPortNum); } } @@ -186,7 +186,7 @@ private USBDevice createDeviceFromDeviceInfo(DeviceInfoSet deviceInfoSet, String * @param usbPortNum the USB port number * @return the {@code USBDevice} instance */ - private USBDevice createDevice(String devicePath, MemorySegment hubHandle, int usbPortNum) { + private USBDevice createDevice(String devicePath, boolean isComposite, MemorySegment hubHandle, int usbPortNum) { try (var arena = Arena.ofConfined()) { @@ -209,7 +209,7 @@ private USBDevice createDevice(String devicePath, MemorySegment hubHandle, int u var configDesc = getDescriptor(hubHandle, usbPortNum, CONFIGURATION_DESCRIPTOR_TYPE, 0, (short) 0, arena); // create new device - var device = new WindowsUSBDevice(devicePath, vendorId, productId, configDesc); + var device = new WindowsUSBDevice(devicePath, vendorId, productId, configDesc, isComposite); device.setFromDeviceDescriptor(descriptorSegment); device.setProductString(descriptorSegment, index -> getStringDescriptor(hubHandle, usbPortNum, index)); From b5a414335907240fc6aa2e3262b95e0f5929d1e8 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 28 Sep 2023 23:27:44 +0200 Subject: [PATCH 293/433] Windows reference code: improvements for composite devices --- reference/windows/USB/usb_device.cpp | 9 +++------ reference/windows/USB/usb_device.hpp | 3 ++- reference/windows/USB/usb_registry.cpp | 6 +++--- reference/windows/USB/usb_registry.hpp | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp index 59c083c2..e1d68a45 100644 --- a/reference/windows/USB/usb_device.cpp +++ b/reference/windows/USB/usb_device.cpp @@ -22,8 +22,8 @@ #include #include -usb_device::usb_device(usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc) -: registry_(registry), vendor_id_(vendor_id), product_id_(product_id), is_open_(false), device_path_(std::move(device_path)) { +usb_device::usb_device(usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, bool is_composite) +: registry_(registry), vendor_id_(vendor_id), product_id_(product_id), is_open_(false), device_path_(std::move(device_path)), is_composite_(is_composite) { config_parser parser{}; parser.parse(config_desc.data(), static_cast(config_desc.size())); @@ -458,7 +458,7 @@ void usb_device::cancel_transfer(usb_direction direction, int endpoint_number, O } std::wstring usb_device::get_interface_device_path(int interface_num) { - if (interface_num == 0) + if (!is_composite_) return device_path_; auto it = interface_device_paths_.find(interface_num); @@ -471,9 +471,6 @@ std::wstring usb_device::get_interface_device_path(int interface_num) { auto dev_info_set = device_info_set::of_path(device_path_); - if (!dev_info_set.is_composite_device()) - throw usb_error("internal error: interface belongs to a separate function but device is not composite"); - auto children_instance_ids = dev_info_set.get_device_property_string_list(DEVPKEY_Device_Children); if (children_instance_ids.empty()) { std::wcerr << "missing children IDs for device " << device_path_ << std::endl; diff --git a/reference/windows/USB/usb_device.hpp b/reference/windows/USB/usb_device.hpp index 520d8431..100a58fb 100644 --- a/reference/windows/USB/usb_device.hpp +++ b/reference/windows/USB/usb_device.hpp @@ -248,7 +248,7 @@ class usb_device { interface_handle(int intf_num, int first_num, std::wstring&& path); }; - usb_device(usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc); + usb_device(usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, bool is_composite); void set_product_names(const std::string& manufacturer, const std::string& product, const std::string& serial_number); void build_handles(const std::wstring& device_path); std::wstring get_interface_device_path(int interface_num); @@ -285,6 +285,7 @@ class usb_device { std::string product_; std::string serial_number_; + bool is_composite_; std::vector interfaces_; std::vector functions_; std::vector interface_handles_; diff --git a/reference/windows/USB/usb_registry.cpp b/reference/windows/USB/usb_registry.cpp index d3d3cc10..309c6390 100644 --- a/reference/windows/USB/usb_registry.cpp +++ b/reference/windows/USB/usb_registry.cpp @@ -167,10 +167,10 @@ std::shared_ptr usb_registry::create_device_from_device_info(device_ hub_handles[hub_path] = hub_handle; } - return create_device(std::move(device_path), hub_handle, usb_port_num); + return create_device(std::move(device_path), dev_info_set.is_composite_device(), hub_handle, usb_port_num); } -std::shared_ptr usb_registry::create_device(std::wstring&& device_path, HANDLE hub_handle, DWORD usb_port_num) { +std::shared_ptr usb_registry::create_device(std::wstring&& device_path, bool is_composite, HANDLE hub_handle, DWORD usb_port_num) { // get device descriptor USB_NODE_CONNECTION_INFORMATION_EX conn_info = { 0 }; @@ -186,7 +186,7 @@ std::shared_ptr usb_registry::create_device(std::wstring&& device_pa auto config_desc = get_descriptor(hub_handle, usb_port_num, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0); // Create new device - std::shared_ptr device(new usb_device(this, std::move(device_path), vendorId, productId, config_desc)); + std::shared_ptr device(new usb_device(this, std::move(device_path), vendorId, productId, config_desc, is_composite)); device->set_product_names( get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iManufacturer), get_string(hub_handle, usb_port_num, conn_info.DeviceDescriptor.iProduct), diff --git a/reference/windows/USB/usb_registry.hpp b/reference/windows/USB/usb_registry.hpp index 0064dc9e..321bf18c 100644 --- a/reference/windows/USB/usb_registry.hpp +++ b/reference/windows/USB/usb_registry.hpp @@ -53,7 +53,7 @@ class usb_registry { void detect_present_devices(); std::shared_ptr create_device_from_device_info(device_info_set& dev_info_set, std::wstring&& device_path, std::map& hub_handles); - std::shared_ptr create_device(std::wstring&& device_path, HANDLE hub_handle, DWORD usb_port_num); + std::shared_ptr create_device(std::wstring&& device_path, bool is_composite, HANDLE hub_handle, DWORD usb_port_num); static std::string get_string(HANDLE hub_handle, ULONG usb_port_num, int index); static std::vector get_descriptor(HANDLE hub_handle, ULONG usb_port_num, uint16_t descriptor_type, int index, int language_id, int request_size = 0); From 43f4192fc668fd1476ae80c6284317402d933897 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 29 Sep 2023 21:33:04 +0200 Subject: [PATCH 294/433] Windows: give up earlier on waiting for child device --- .../usb/windows/WindowsUSBDevice.java | 28 +++---- reference/windows/USB/usb_device.cpp | 83 ++++++++++--------- reference/windows/USB/usb_device.hpp | 3 +- 3 files changed, 57 insertions(+), 57 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index c7dc99e0..f2d2d730 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -44,10 +44,6 @@ public class WindowsUSBDevice extends USBDeviceImpl { private static final System.Logger LOG = System.getLogger(WindowsUSBDevice.class.getName()); - private static final int RETRY_LATER = 0; - private static final int TRY_NEXT_CHILD = 1; - private static final int SUCCESS = 2; - private final WindowsAsyncTask asyncTask; /** * Indicates if the device is a composite device @@ -125,7 +121,7 @@ public void claimInterface(int interfaceNumber) { numRetries -= 1; if (numRetries == 0) - throw new USBException("claiming interface failed (function has no device path, might be missing WinUSB driver)"); + throw new USBException("claiming interface failed (function has no device path / interface GUID, might be missing WinUSB driver)"); // sleep and retry try { @@ -534,11 +530,9 @@ private String getInterfaceDevicePath(int interfaceNumber) { LOG.log(DEBUG, "children instance IDs: {0}", childrenInstanceIDs); for (var instanceId : childrenInstanceIDs) { - var res = fetchChildDevicePath(instanceId, interfaceNumber); - if (res == SUCCESS) - return devicePaths.get(interfaceNumber); - if (res == RETRY_LATER) - return null; // retry later + devicePath = getChildDevicePath(instanceId, interfaceNumber); + if (devicePath != null) + return devicePath; } } } @@ -552,35 +546,35 @@ private String getCachedInterfaceDevicePath(int interfaceNumber) { return devicePaths.get(interfaceNumber); } - private int fetchChildDevicePath(String instanceId, int interfaceNumber) { + private String getChildDevicePath(String instanceId, int interfaceNumber) { try (var deviceInfoSet = DeviceInfoSet.ofInstance(instanceId)) { // get hardware IDs (to extract interface number) var hardwareIds = deviceInfoSet.getStringListProperty(HardwareIds); if (hardwareIds == null) { LOG.log(DEBUG, "child device {0} has no hardware IDs", instanceId); - return TRY_NEXT_CHILD; + return null; } var extractedNumber = extractInterfaceNumber(hardwareIds); if (extractedNumber == -1) { LOG.log(DEBUG, "child device {0} has no interface number", instanceId); - return TRY_NEXT_CHILD; + return null; } if (extractedNumber != interfaceNumber) - return TRY_NEXT_CHILD; + return null; var devicePath = deviceInfoSet.getDevicePathByGUID(instanceId); if (devicePath == null) { - LOG.log(INFO, "Child device {0} has no device path", instanceId); - return RETRY_LATER; + LOG.log(INFO, "Child device {0} has no device path / interface GUID", instanceId); + throw new USBException("claiming interface failed (function has no device path / interface GUID, might be missing WinUSB driver)"); } if (devicePaths == null) devicePaths = new HashMap<>(); devicePaths.put(interfaceNumber, devicePath); - return SUCCESS; + return devicePath; } } diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp index e1d68a45..bcb8b72f 100644 --- a/reference/windows/USB/usb_device.cpp +++ b/reference/windows/USB/usb_device.cpp @@ -118,6 +118,26 @@ void usb_device::close() { } void usb_device::claim_interface(int interface_number) { + // When a device is plugged in, a notification is sent. For composite devices, it is a notification + // that the composite device is ready. Each composite function will be registered separately and + // the related information will be available with a delay. So for composite functions, several + // retries might be needed until the device path is available. + int num_retries = 30; // 30 x 100ms + while (true) { + if (try_claim_interface(interface_number)) + return; // success + + num_retries -= 1; + if (num_retries == 0) + throw usb_error("claiming interface failed (function has no device interface GUID/path, might be missing WinUSB driver)"); + + // sleep and retry + std::cerr << "Sleeping for 100ms..." << std::endl; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } +} + +bool usb_device::try_claim_interface(int interface_number) { if (!is_open()) throw usb_error("USB device is not open"); @@ -135,7 +155,7 @@ void usb_device::claim_interface(int interface_number) { if (first_intf_handle->device_handle == nullptr) { auto device_path = get_interface_device_path(first_intf_handle->interface_num); if (device_path.empty()) - throw usb_error("failed to claim interface (function has no device path, might be missing WinUSB driver)"); + return false; std::wcerr << "opening device " << device_path << std::endl; @@ -169,6 +189,7 @@ void usb_device::claim_interface(int interface_number) { first_intf_handle->device_open_count += 1; intf->set_claimed(true); + return true; } void usb_device::release_interface(int interface_number) { @@ -465,72 +486,56 @@ std::wstring usb_device::get_interface_device_path(int interface_num) { if (it != interface_device_paths_.end()) return it->second; - int num_retries = 30; // 30 x 100ms - - while (num_retries > 0) { - - auto dev_info_set = device_info_set::of_path(device_path_); - - auto children_instance_ids = dev_info_set.get_device_property_string_list(DEVPKEY_Device_Children); - if (children_instance_ids.empty()) { - std::wcerr << "missing children IDs for device " << device_path_ << std::endl; + auto dev_info_set = device_info_set::of_path(device_path_); - } else { + auto children_instance_ids = dev_info_set.get_device_property_string_list(DEVPKEY_Device_Children); - std::wcerr << "children IDs: "; - for (auto it = children_instance_ids.begin(); it < children_instance_ids.end(); it++) { - if (it != children_instance_ids.begin()) - std::wcerr << ", "; - std::wcerr << *it; - } - std::wcerr << std::endl; - - std::wstring child_path; - for (auto& child_id : children_instance_ids) { - auto res = get_child_device_path(child_id, interface_num, child_path); - if (res == 1) - return child_path; - if (res == -1) - break; - } - } + std::wcerr << "children IDs: "; + for (auto it = children_instance_ids.begin(); it < children_instance_ids.end(); it++) { + if (it != children_instance_ids.begin()) + std::wcerr << ", "; + std::wcerr << *it; + } + std::wcerr << std::endl; - std::cerr << "Sleeping for 100ms..." << std::endl; - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - num_retries -= 1; + std::wstring child_path; + for (auto& child_id : children_instance_ids) { + child_path = get_child_device_path(child_id, interface_num); + if (!child_path.empty()) + return child_path; } - return {}; + return {}; // retry later } -int usb_device::get_child_device_path(const std::wstring& child_id, int interface_num, std::wstring& device_path) { +std::wstring usb_device::get_child_device_path(const std::wstring& child_id, int interface_num) { auto dev_info_set = device_info_set::of_instance(child_id); auto hardware_ids = dev_info_set.get_device_property_string_list(DEVPKEY_Device_HardwareIds); if (hardware_ids.empty()) { std::wcerr << "child device " << child_id << " has no hardware IDs" << std::endl; - return 0; // continue with next child + return {}; // continue with next child } auto intf_num = extract_interface_number(hardware_ids); if (intf_num == -1) { std::wcerr << "child device " << child_id << " has no interface number" << std::endl; - return 0; // continue with next child + return {}; // continue with next child } if (intf_num != interface_num) - return 0; // continue with next child + return {}; // continue with next child - device_path = dev_info_set.get_device_path_by_guid(child_id); + auto device_path = dev_info_set.get_device_path_by_guid(child_id); if (device_path.empty()) { std::wcerr << "child device " << child_id << " has no device path" << std::endl; - return -1; // retry later + throw usb_error("claiming interface failed (function has no device interface GUID/path, might be missing WinUSB driver)"); } std::wcerr << "child device: interface=" << intf_num << ", device path=" << device_path << std::endl; interface_device_paths_[interface_num] = device_path; - return 1; // success + return device_path; // success } static const std::wregex multiple_interface_id_pattern(L"USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); diff --git a/reference/windows/USB/usb_device.hpp b/reference/windows/USB/usb_device.hpp index 100a58fb..6f5760c5 100644 --- a/reference/windows/USB/usb_device.hpp +++ b/reference/windows/USB/usb_device.hpp @@ -251,8 +251,9 @@ class usb_device { usb_device(usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, bool is_composite); void set_product_names(const std::string& manufacturer, const std::string& product, const std::string& serial_number); void build_handles(const std::wstring& device_path); + bool try_claim_interface(int interface_number); std::wstring get_interface_device_path(int interface_num); - int get_child_device_path(const std::wstring& child_id, int interface_num, std::wstring& device_path); + std::wstring get_child_device_path(const std::wstring& child_id, int interface_num); static int extract_interface_number(const std::vector& hardware_ids); int control_transfer_core(const usb_control_request& request, uint8_t* data, int timeout); From 632f53bab33546277b99894edf5a688b0aad676b Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 29 Sep 2023 21:43:00 +0200 Subject: [PATCH 295/433] Minor code cleanup --- java-does-usb/jextract/README.md | 2 +- .../main/java/net/codecrete/usb/windows/InterfaceHandle.java | 4 ++-- .../test/java/net/codecrete/usb/special/LogicAnalyzer.java | 3 ++- java-does-usb/src/test/resources/tinylog.properties | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index d700e3a8..3204b7ee 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -96,7 +96,7 @@ The known limitations are: *jextract* generates a comprehensive set of methods for each function, struct, struct member etc. Most of it will not be used as a typical application just uses a subset of struct members, might only read or write them etc. So a considerable amount of code is generated. For some types, it's a bit excessive. -The worst example is [`IOUSBInterfaceStruct190`](https://github.com/manuelbl/JavaDoesUSB/blob/main/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java) (macOS). This is a `struct` consisting of about 50 member functions. It's basically a vtable of a C++ class. For this single `struct`, *jextract* generates codes resulting in 70 class files with a total size of 227kByte.. +The worst example is [`IOUSBInterfaceStruct190`](https://github.com/manuelbl/JavaDoesUSB/blob/main/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java) (macOS). This is a `struct` consisting of about 50 member functions. It's basically a vtable of a C++ class. For this single `struct`, *jextract* generates codes resulting in 70 class files with a total size of 227kByte. The table below shows statistics for version 0.6.0 of the library: diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java index f5c87375..ea4160c4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java @@ -20,11 +20,11 @@ class InterfaceHandle { /** * The number of this interface. */ - int interfaceNumber; + final int interfaceNumber; /** * The number of the first interface in the same composite function. */ - int firstInterfaceNumber; + final int firstInterfaceNumber; /** * The file handle of the device. *

diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java b/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java index e146192a..7014dd7f 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java @@ -309,7 +309,8 @@ void checkFirmware() { void sleep(long milliseconds) { while (true) { try { - Thread.sleep(milliseconds); + //noinspection BusyWait + Thread.sleep(milliseconds); // NOSONAR return; } catch (InterruptedException e) { // ignore and try again diff --git a/java-does-usb/src/test/resources/tinylog.properties b/java-does-usb/src/test/resources/tinylog.properties index 08b5f1d0..9cf0c142 100644 --- a/java-does-usb/src/test/resources/tinylog.properties +++ b/java-does-usb/src/test/resources/tinylog.properties @@ -1,3 +1,3 @@ writer = console writer.format = {date: HH:mm:ss.SSS} {level|size=5} [{class|size=40}] {message} -writer.level = debug +writer.level = info From d24480be2600b0b1ce29fddecb5509b6da4b5ed3 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 2 Oct 2023 18:18:13 +0200 Subject: [PATCH 296/433] Increase version to 0.6.1 --- README.md | 4 ++-- examples/bulk_transfer/README.md | 2 +- examples/bulk_transfer/pom.xml | 4 ++-- examples/enumerate/README.md | 2 +- examples/enumerate/pom.xml | 4 ++-- examples/epaper_display/README.md | 4 ++-- examples/epaper_display/pom.xml | 4 ++-- examples/monitor/README.md | 2 +- examples/monitor/pom.xml | 4 ++-- examples/stm_dfu/README.md | 2 +- examples/stm_dfu/pom.xml | 4 ++-- java-does-usb/pom.xml | 2 +- 12 files changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index efcd3b3d..a482be5d 100644 --- a/README.md +++ b/README.md @@ -41,14 +41,14 @@ If you are using Maven, add the below dependency to your pom.xml: net.codecrete.usb java-does-usb - 0.6.0 + 0.6.1 ``` If you are using Gradle, add the below dependency to your build.gradle file: ```groovy -compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '0.6.0' +compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '0.6.1' ``` ```java diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index f5a32e88..9a7920c1 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] --------------< net.codecrete.usb.examples:bulk-transfer >-------------- -[INFO] Building bulk-transfer 0.6.0 +[INFO] Building bulk-transfer 0.6.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ bulk-transfer --- diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index fd9bbc9a..7d7974be 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples bulk-transfer - 0.6.0 + 0.6.1 bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.6.0 + 0.6.1 diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index bb939075..ad08e230 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] ----------------< net.codecrete.usb.examples:enumerate >---------------- -[INFO] Building enumerate 0.6.0 +[INFO] Building enumerate 0.6.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ enumerate --- diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index 3fb8a871..f2ac2475 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples enumerate - 0.6.0 + 0.6.1 enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.6.0 + 0.6.1 org.tinylog diff --git a/examples/epaper_display/README.md b/examples/epaper_display/README.md index f484c05b..3853b118 100644 --- a/examples/epaper_display/README.md +++ b/examples/epaper_display/README.md @@ -45,7 +45,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -------------< net.codecrete.usb.examples:epaper-display >-------------- -[INFO] Building epaper-display 0.6.0 +[INFO] Building epaper-display 0.6.1 [INFO] from pom.xml [INFO] --------------------------------[ jar ]--------------------------------- [INFO] @@ -81,6 +81,6 @@ $ sudo -i Password: $ cd /Users/me/Documents/JavaDoesUSB/examples/epaper_display $ export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-20.jdk/Contents/Home -$ $JAVA_HOME/bin/java --enable-preview --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/0.6.0/java-does-usb-0.6.0.jar net.codecrete.usb.examples.EPaperDisplay +$ $JAVA_HOME/bin/java --enable-preview --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/0.6.1/java-does-usb-0.6.1.jar net.codecrete.usb.examples.EPaperDisplay Display size: 1200 x 825 ``` diff --git a/examples/epaper_display/pom.xml b/examples/epaper_display/pom.xml index b5a33eb1..79874da5 100644 --- a/examples/epaper_display/pom.xml +++ b/examples/epaper_display/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples epaper-display - 0.6.0 + 0.6.1 epaper-display https://github.com/manuelbl/JavaDoesUSB/examples/epaper_display @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.6.0 + 0.6.1 diff --git a/examples/monitor/README.md b/examples/monitor/README.md index 44ff4348..27c84b4d 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -----------------< net.codecrete.usb.examples:monitor >----------------- -[INFO] Building monitor 0.6.0 +[INFO] Building monitor 0.6.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ monitor --- diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index 75d59896..b36fbf1e 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples monitor - 0.6.0 + 0.6.1 monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.6.0 + 0.6.1 org.tinylog diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index 8a430c5b..91bd87c4 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -58,7 +58,7 @@ Run the command below (adapting the file path depending on your specific board): ```shell $ mvn package -$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.6.0.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin +$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.6.1.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin DFU device found with serial 35A737883336. Target memory segment: Internal Flash Erasing page at 0x8000000 (size 0x4000) diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index a523f136..fe623b61 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples stm_dfu - 0.6.0 + 0.6.1 stm_dfu https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu @@ -19,7 +19,7 @@ net.codecrete.usb java-does-usb - 0.6.0 + 0.6.1 diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 2e484e24..7362a64a 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 0.6.1-SNAPSHOT + 0.6.1 21 From 8cb47de9553215930ffb283b57e0dee26c6fd939 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 6 Oct 2023 17:37:04 +0200 Subject: [PATCH 297/433] Configuration descriptor parser tests --- java-does-usb/pom.xml | 6 +- .../usb/common/ConfigurationParser.java | 7 +- .../usb/ConfigurationDescriptors.java | 509 ++++++++++++++++++ .../usb/ConfigurationParserTest.java | 258 +++++++++ .../net/codecrete/usb/DescriptorTest.java | 11 +- 5 files changed, 781 insertions(+), 10 deletions(-) create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/ConfigurationDescriptors.java create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 7362a64a..ee8e73a8 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 0.6.1 + 0.6.2-SNAPSHOT 21 @@ -75,7 +75,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.5.0 + 3.6.0 attach-javadocs @@ -140,7 +140,7 @@ org.junit.jupiter junit-jupiter - 5.9.3 + 5.10.0 test diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java index 16c989cd..7df741f6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java @@ -23,7 +23,12 @@ import static net.codecrete.usb.usbstandard.Constants.*; /** - * Parser for USB configuration descriptors + * Parser for USB configuration descriptors. + * + *

+ * It extracts the information about endpoints, interfaces (incl. alternate interfaces) and associations + * between interfaces to derive the functions. Other descriptor types are ignored. + *

*/ public class ConfigurationParser { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationDescriptors.java b/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationDescriptors.java new file mode 100644 index 00000000..7a2ae7c9 --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationDescriptors.java @@ -0,0 +1,509 @@ +package net.codecrete.usb; + +class ConfigurationDescriptors { + + // For convenience, the configuration descriptor are maintained as int arrays. + private static final int[] SIMPLE_INT_ARRAY = new int[] { + // configuration descriptor + 0x09, // bLength + 0x02, // bDescriptorType = configuration + 0x12, 0x00, // wTotalLength + 0x01, // bNumInterfaces + 0x01, // bConfigurationValue + 0x00, // iConfiguration + 0x34, // bmAttributes + 0x64, // bMaxPower + + // interface descriptor + 0x09, // bLength + 0x04, // bDescriptorType = interface + 0x00, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x00, // bNumEndpoints + 0xff, // bInterfaceClass + 0xdd, // bInterfaceSubClass + 0xcc, // bInterfaceProtocol + 0x00, // iInterface + }; + + private static final int[] LARGE_COMPOSITE_INT_ARRAY = new int[] { + // configuration descriptor + 0x09, // bLength = 9 + 0x02, // bDescriptorType = configuration + 0x5A, 0x04, // wTotalLength = 1114 + 0x04, // bNumInterfaces = 4 + 0x01, // bConfigurationValue + 0x00, // iConfiguration (string index) + 0xA0, // bmAttributes (remote wakeup) + 0x70, // bMaxPower = 224mA + + // interface association descriptor (IAD) + 0x08, // bLength = 9 + 0x0B, // bDescriptorType = iad + 0x00, // bFirstInterface = 0 + 0x03, // bInterfaceCount = 3 + 0x0E, // bFunctionClass = 0x0E (Video) + 0x03, // bFunctionSubClass = 0x03 (Video Interface Collection) + 0x00, // bFunctionProtocol = 0x00 (Undefined) + 0x00, // iFunction (string index) + + // interface descriptor + 0x09, // bLength + 0x04, // bDescriptorType = interface + 0x00, // bInterfaceNumber = 0 + 0x00, // bAlternateSetting = 0 + 0x01, // bNumEndpoints = 1 + 0x0E, // bInterfaceClass = 0x0E (Video) + 0x01, // bInterfaceSubClass = 0x01 (Video Control) + 0x00, // bInterfaceProtocol = 0x00 (Undefined) + 0x00, // iInterface (string index) + + 0x0E, // bLength = 14 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x01, 0x00, 0x01, 0xA9, 0x00, 0x80, 0xC3, 0xC9, 0x01, 0x02, 0x01, 0x02, + + 0x09, // bLength = 9 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x03, 0x04, 0x01, 0x01, 0x00, 0x02, 0x00, + + 0x09, // bLength = 9 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x03, 0x05, 0x01, 0x01, 0x00, 0x02, 0x00, + + 0x1B, // bLength = 27 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x06, 0x02, 0x6A, 0xD1, 0x49, 0x2C, 0xB8, 0x32, 0x85, 0x44, 0x3E, 0xA8, 0x64, 0x3A, 0x15, 0x23, 0x62, 0xF2, 0x06, 0x01, 0x06, 0x02, 0x3F, 0x00, 0x00, + + 0x1B, // bLength = 27 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x06, 0x06, 0xD0, 0x9E, 0xE4, 0x23, 0x78, 0x11, 0x31, 0x4F, 0xAE, 0x52, 0xD2, 0xFB, 0x8A, 0x8D, 0x3B, 0x48, 0x05, 0x01, 0x03, 0x02, 0xFF, 0x7F, 0x00, + + 0x1B, // bLength = 27 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x06, 0x0F, 0xDC, 0x95, 0x3F, 0x0F, 0x32, 0x26, 0x4E, 0x4C, 0x92, 0xC9, 0xA0, 0x47, 0x82, 0xF4, 0x3B, 0xC8, 0x02, 0x01, 0x03, 0x02, 0x20, 0x01, 0x00, + + 0x1D, // bLength = 29 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x06, 0x0E, 0xF2, 0x5D, 0xBD, 0xA8, 0x98, 0x1A, 0x4E, 0x47, 0x8D, 0xD0, 0xD9, 0x26, 0x72, 0xD1, 0x94, 0xFA, 0x02, 0x01, 0x03, 0x04, 0xFF, 0xF3, 0xF3, 0xFF, 0x00, + + 0x12, // bLength = 18 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x02, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x2E, 0x0A, 0x02, + + 0x0B, // bLength = 11 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x05, 0x03, 0x01, 0x00, 0x00, 0x02, 0x5B, 0x17, 0x00, + + // endpoint descriptor + 0x07, // bLength = 7 + 0x05, // bDescriptorType = endpoint + 0x85, // bEndpointAddress (IN) + 0x03, // bmAttributes (interrupt) + 0x40, 0x00, // wMaxPacketSize = 64 + 0x08, // bInterval = 8 + + 0x06, // bLength = 6 + 0x30, // bDescriptorType = 0x30 (video) + 0x00, 0x00, 0x08, 0x00, + + 0x05, // bLength = 5 + 0x25, // bDescriptorType = 0x25 (CS_ENDPOINT) + 0x03, 0x40, 0x00, + + // interface descriptor + 0x09, // bLength = 9 + 0x04, // bDescriptorType = interface + 0x01, // bInterfaceNumber = 1 + 0x00, // bAlternateSetting = 0 + 0x00, // bNumEndpoints = 0 + 0x0E, // bInterfaceClass = 0x0E (Video) + 0x02, // bInterfaceSubClass = 0x02 (Video Streaming) + 0x00, // bInterfaceProtocol = 0x00 (Undefined) + 0x00, // iInterface (sstring index) + + 0x10, // bLength = 16 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x01, 0x03, 0xD9, 0x02, 0x81, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + + 0x1B, // bLength = 27 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x04, 0x01, 0x06, 0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x05, 0x01, 0x00, 0x80, 0x02, 0xE0, 0x01, 0x00, 0x00, 0xCA, 0x08, 0x00, 0x00, 0xCA, 0x08, 0x00, 0x60, 0x09, 0x00, 0x15, 0x16, 0x05, 0x00, 0x01, 0x15, 0x16, 0x05, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x05, 0x02, 0x00, 0x80, 0x02, 0x68, 0x01, 0x00, 0x80, 0x97, 0x06, 0x00, 0x80, 0x97, 0x06, 0x00, 0x08, 0x07, 0x00, 0x15, 0x16, 0x05, 0x00, 0x01, 0x15, 0x16, 0x05, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x05, 0x03, 0x00, 0x00, 0x05, 0xD0, 0x02, 0x00, 0x00, 0x18, 0x15, 0x00, 0x00, 0x18, 0x15, 0x00, 0x20, 0x1C, 0x00, 0x9A, 0x5B, 0x06, 0x00, 0x01, 0x9A, 0x5B, 0x06, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x05, 0x04, 0x00, 0x00, 0x05, 0xD0, 0x02, 0x00, 0x00, 0x5E, 0x1A, 0x00, 0x00, 0x5E, 0x1A, 0x00, 0x20, 0x1C, 0x00, 0x15, 0x16, 0x05, 0x00, 0x01, 0x15, 0x16, 0x05, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x05, 0x05, 0x00, 0x80, 0x07, 0x38, 0x04, 0x00, 0x00, 0x76, 0x2F, 0x00, 0x00, 0x76, 0x2F, 0x00, 0x48, 0x3F, 0x00, 0x9A, 0x5B, 0x06, 0x00, 0x01, 0x9A, 0x5B, 0x06, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x05, 0x06, 0x00, 0x80, 0x07, 0x38, 0x04, 0x00, 0x80, 0x53, 0x3B, 0x00, 0x80, 0x53, 0x3B, 0x00, 0x48, 0x3F, 0x00, 0x15, 0x16, 0x05, 0x00, 0x01, 0x15, 0x16, 0x05, 0x00, + + 0x06, // bLength = 6 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x0D, 0x01, 0x01, 0x04, + + 0x0B, // bLength = 11 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x06, 0x02, 0x0B, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x07, 0x01, 0x00, 0x80, 0x02, 0xE0, 0x01, 0x00, 0x40, 0x38, 0x00, 0x00, 0x00, 0xA0, 0x05, 0x00, 0x00, 0x10, 0x00, 0x15, 0x16, 0x05, 0x00, 0x01, 0x15, 0x16, 0x05, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x07, 0x02, 0x00, 0x00, 0x05, 0xD0, 0x02, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x10, 0x00, 0x9A, 0x5B, 0x06, 0x00, 0x01, 0x9A, 0x5B, 0x06, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x07, 0x03, 0x00, 0x00, 0x05, 0xD0, 0x02, 0x00, 0x40, 0x38, 0x00, 0x00, 0x00, 0xA0, 0x05, 0x00, 0x00, 0x10, 0x00, 0x15, 0x16, 0x05, 0x00, 0x01, 0x15, 0x16, 0x05, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x07, 0x04, 0x00, 0x00, 0x05, 0xD0, 0x02, 0x00, 0x80, 0x70, 0x00, 0x00, 0x00, 0x40, 0x0B, 0x00, 0x00, 0x10, 0x00, 0x0A, 0x8B, 0x02, 0x00, 0x01, 0x0A, 0x8B, 0x02, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x07, 0x05, 0x00, 0x80, 0x07, 0x38, 0x04, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x10, 0x00, 0x9A, 0x5B, 0x06, 0x00, 0x01, 0x9A, 0x5B, 0x06, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x07, 0x06, 0x00, 0x80, 0x07, 0x38, 0x04, 0x00, 0x40, 0x38, 0x00, 0x00, 0x00, 0xA0, 0x05, 0x00, 0x00, 0x10, 0x00, 0x15, 0x16, 0x05, 0x00, 0x01, 0x15, 0x16, 0x05, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x07, 0x07, 0x00, 0x80, 0x07, 0x38, 0x04, 0x00, 0x80, 0x70, 0x00, 0x00, 0x00, 0x40, 0x0B, 0x00, 0x00, 0x10, 0x00, 0x0A, 0x8B, 0x02, 0x00, 0x01, 0x0A, 0x8B, 0x02, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x07, 0x08, 0x00, 0x00, 0x0A, 0xA0, 0x05, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x10, 0x00, 0x9A, 0x5B, 0x06, 0x00, 0x01, 0x9A, 0x5B, 0x06, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x07, 0x09, 0x00, 0x00, 0x0A, 0xA0, 0x05, 0x00, 0x40, 0x38, 0x00, 0x00, 0x00, 0xA0, 0x05, 0x00, 0x00, 0x10, 0x00, 0x15, 0x16, 0x05, 0x00, 0x01, 0x15, 0x16, 0x05, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x07, 0x0A, 0x00, 0x00, 0x0F, 0x70, 0x08, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x10, 0x00, 0x9A, 0x5B, 0x06, 0x00, 0x01, 0x9A, 0x5B, 0x06, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x07, 0x0B, 0x00, 0x00, 0x0F, 0x70, 0x08, 0x00, 0x40, 0x38, 0x00, 0x00, 0x00, 0xA0, 0x05, 0x00, 0x00, 0x10, 0x00, 0x15, 0x16, 0x05, 0x00, 0x01, 0x15, 0x16, 0x05, 0x00, + + 0x06, // bLength = 6 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x0D, 0x01, 0x01, 0x04, + + 0x1B, // bLength = 27 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x04, 0x03, 0x04, 0x4E, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71, 0x0C, 0x01, 0x00, 0x00, 0x00, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x05, 0x01, 0x00, 0x80, 0x02, 0xE0, 0x01, 0x00, 0x80, 0x97, 0x06, 0x00, 0x80, 0x97, 0x06, 0x00, 0x08, 0x07, 0x00, 0x15, 0x16, 0x05, 0x00, 0x01, 0x15, 0x16, 0x05, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x05, 0x02, 0x00, 0x80, 0x02, 0x68, 0x01, 0x00, 0xA0, 0xF1, 0x04, 0x00, 0xA0, 0xF1, 0x04, 0x00, 0x46, 0x05, 0x00, 0x15, 0x16, 0x05, 0x00, 0x01, 0x15, 0x16, 0x05, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x05, 0x03, 0x00, 0x00, 0x05, 0xD0, 0x02, 0x00, 0x80, 0xC6, 0x13, 0x00, 0x80, 0xC6, 0x13, 0x00, 0x18, 0x15, 0x00, 0x15, 0x16, 0x05, 0x00, 0x01, 0x15, 0x16, 0x05, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x05, 0x04, 0x00, 0x80, 0x07, 0x38, 0x04, 0x00, 0xA0, 0x7E, 0x2C, 0x00, 0xA0, 0x7E, 0x2C, 0x00, 0x76, 0x2F, 0x00, 0x15, 0x16, 0x05, 0x00, 0x01, 0x15, 0x16, 0x05, 0x00, + + 0x06, // bLength = 6 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x0D, 0x01, 0x01, 0x04, + + // interface descriptor + 0x09, // bLength = 9 + 0x04, // bDescriptorType = interface + 0x01, // bInterfaceNumber = 1 + 0x01, // bAlternateSetting = 1 + 0x01, // bNumEndpoints = 1 + 0x0E, // bInterfaceClass = 0x0E (Video) + 0x02, // bInterfaceSubClass = 0x02 (Video Streaming) + 0x00, // bInterfaceProtocol = 0x00 (Undefined) + 0x00, // iInterface (string index) + + // endpoint descriptor + 0x07, // bLength = 7 + 0x05, // bDescriptorType = endpoint + 0x81, // bEndpointAddress (IN) + 0x05, // bmAttributes (isochronous, async, data) + 0x00, 0x04, // wMaxPacketSize = 1024 + 0x01, // bInterval = 1 + + 0x06, // bLength = 6 + 0x30, // bDescriptorType = superspeed endpoint companion + 0x05, // bMaxBurst = 5 + 0x02, // bmAttributes.isochronous.mult = 2 + 0x00, 0x48, // wBytesPerInterval = 18432 + + // interface descriptor + 0x09, // bLength = 9 + 0x04, // bDescriptorType = interface + 0x02, // bInterfaceNumber = 2 + 0x00, // bAlternateSetting = 0 + 0x00, // bNumEndpoints = 0 + 0x0E, // bInterfaceClass = 0x0E (Video) + 0x02, // bInterfaceSubClass = 0x02 (Video Streaming) + 0x00, // bInterfaceProtocol = 0x00 (Undefined) + 0x00, // iInterface (string index) + + 0x0E, // bLength = 14 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x01, 0x01, 0x4D, 0x00, 0x82, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, + + 0x1B, // bLength = 27 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x04, 0x03, 0x01, 0x4E, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71, 0x0C, 0x01, 0x00, 0x00, 0x00, 0x00, + + 0x1E, // bLength = 30 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x05, 0x01, 0x00, 0x80, 0x02, 0xE0, 0x01, 0x00, 0x80, 0x97, 0x06, 0x00, 0x80, 0x97, 0x06, 0x00, 0x08, 0x07, 0x00, 0x15, 0x16, 0x05, 0x00, 0x01, 0x15, 0x16, 0x05, 0x00, + + 0x06, // bLength = 6 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x0D, 0x01, 0x01, 0x04, + + // interface descriptor + 0x09, // bLength = 9 + 0x04, // bDescriptorType = interface + 0x02, // bInterfaceNumber = 2 + 0x01, // bAlternateSetting = 1 + 0x01, // bNumEndpoints = 1 + 0x0E, // bInterfaceClass = 0x0E (Video) + 0x02, // bInterfaceSubClass = 0x02 (Video Streaming) + 0x00, // bInterfaceProtocol = 0x00 (Undefined) + 0x00, // iInterface (string index) + + // endpoint descriptor + 0x07, // bLength = 7 + 0x05, // bDescriptorType = endpoint + 0x82, // bEndpointAddress (IN) + 0x05, // bmAttributes (isochronous, async, data) + 0x00, 0x04, // wMaxPacketSize = 1024 + 0x01, // bInterval = 1 + + 0x06, // bLength = 6 + 0x30, // bDescriptorType = superspeed endpoint companion + 0x00, // bMaxBurst = 0 + 0x02, // bmAttributes.isochronous.mult = 2 + 0x00, 0x0C, // wBytesPerInterval = 3072 + + // interface descriptor + 0x09, // bLength = 9 + 0x04, // bDescriptorType = interface + 0x03, // bInterfaceNumber = 3 + 0x00, // bAlternateSetting = 0 + 0x01, // bNumEndpoints = 1 + 0x03, // bInterfaceClass = 0x03 (HID) + 0x00, // bInterfaceSubClass = 0x00 (No Subclass) + 0x00, // bInterfaceProtocol = 0x00 (None) + 0x00, // iInterface (string index) + + // HID descriptor + 0x09, // bLength = 9 + 0x21, // bDescriptorType = 0x21 (HID) + 0x10, 0x01, // bcdHID = 1.10 + 0x00, // bCountryCode = 0 (not localized) + 0x01, // bNumDescriptors = 1 + 0x22, // bDescriptorType = 0x22 (report) + 0x46, 0x02, // wDescriptorLength = 582 + + // endpoint descriptor + 0x07, // bLength = 7 + 0x05, // bDescriptorType = endpoint + 0x84, // bEndpointAddress (IN) + 0x03, // bmAttributes (interrupt) + 0x40, 0x00, // wMaxPacketSize = 64 + 0x0A, // bInterval = 10 + + 0x06, // bLength = 6 + 0x30, // bDescriptorType = superspeed endpoint companion + 0x00, // bMaxBurst = 0 + 0x00, // bmAttributes = 0 + 0x40, 0x00 // wBytesPerInterval = 64 + }; + + private static final int[] COMPOSITE_TEST_DEVICE_INT_ARRAY = new int[] { + // configuration descriptor + 0x09, // bLength = 9 + 0x02, // bDescriptorType = configuration + 0x73, 0x00, // wTotalLength = 115 + 0x04, // bNumInterfaces = 4 + 0x01, // bConfigurationValue = 1 + 0x00, // iConfiguration (string index) + 0x80, // bmAttributes = bus powered + 0xFA, // bMaxPower = 500mA + + // interface association descriptor (IAD) + 0x08, // bLength = 8 + 0x0B, // bDescriptorType = iad + 0x00, // bFirstInterface = 0 + 0x02, // bInterfaceCount = 2 + 0x02, // bFunctionClass = 2 (Communications) + 0x02, // bFunctionSubClass = 2 (Abstract) + 0x00, // bFunctionProtocol = 0 (None) + 0x00, // iFunction (string index) + + // interface descriptor + 0x09, // bLength = 9 + 0x04, // bDescriptorType = interface + 0x00, // bInterfaceNumber = 0 + 0x00, // bAlternateSetting = 0 + 0x01, // bNumEndpoints = 1 + 0x02, // bInterfaceClass = 2 (Communications) + 0x02, // bInterfaceSubClass = 2 (Abstract) + 0x00, // bInterfaceProtocol = 0 (None) + 0x00, // iInterface (string index) + + // CDC header functional descriptor + 0x05, // bLength = 5 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x00, // bDescriptorSubtype = 0 (Header) + 0x20, 0x01, // bcdCDC = 1.20 + + // CDC call management functional descriptor + 0x05, // bLength = 5 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x01, // bDescriptorSubtype = 1 (Call Management) + 0x00, // bmCapabilities = 0 (None) + 0x01, // bDataInterface = 1 (Data Class Interface 1) + + // CDC abstract control management functional descriptor + 0x04, // bLength = 4 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x02, // bDescriptorSubtype = 2 (Abstract Control Management) + 0x02, // bmCapabilities = 2 (Line Coding and Serial State) + + // CDC union functional descriptor + 0x05, // bLength = 5 + 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) + 0x06, // bDescriptorSubtype = 6 (Union) + 0x00, // bMasterInterface = 0 (Communications Class Interface 0) + 0x01, // bSlaveInterface0 = 1 (Data Class Interface 1) + + // endpoint descriptor + 0x07, // bLength = 7 + 0x05, // bDescriptorType = endpoint + 0x83, // bEndpointAddress (IN) + 0x03, // bmAttributes (interrupt) + 0x08, 0x00, // wMaxPacketSize = 8 + 0x10, // bInterval = 16 + + // interface descriptor + 0x09, // bLength = 9 + 0x04, // bDescriptorType = interface + 0x01, // bInterfaceNumber = 1 + 0x00, // bAlternateSetting = 0 + 0x02, // bNumEndpoints = 2 + 0x0A, // bInterfaceClass = 0x0A (CDC Data) + 0x00, // bInterfaceSubClass = 0 (None) + 0x00, // bInterfaceProtocol = 0 (None) + 0x00, // iInterface (string index) + + // endpoint descriptor + 0x07, // bLength = 7 + 0x05, // bDescriptorType = endpoint + 0x02, // bEndpointAddress (OUT) + 0x02, // bmAttributes (bulk) + 0x40, 0x00, // wMaxPacketSize = 64 + 0x00, // bInterval = 0 + + // endpoint descriptor + 0x07, // bLength = 7 + 0x05, // bDescriptorType = endpoint + 0x81, // bEndpointAddress (IN) + 0x02, // bmAttributes (Bulk) + 0x40, 0x00, // wMaxPacketSize = 64 + 0x00, // bInterval = 0 + + // interface association descriptor (IAD) + 0x08, // bLength = 8 + 0x0B, // bDescriptorType = iad + 0x02, // bFirstInterface = 2 + 0x02, // bInterfaceCount = 2 + 0xFF, // bFunctionClass = 0xFF (Vendor Specific) + 0x00, // bFunctionSubClass = 0 (None) + 0x00, // bFunctionProtocol = 0 (None) + 0x04, // iFunction (string index) + + // interface descriptor + 0x09, // bLength = 9 + 0x04, // bDescriptorType = interface + 0x02, // bInterfaceNumber = 2 + 0x00, // bAlternateSetting = 0 + 0x00, // bNumEndpoints = 0 + 0xFF, // bInterfaceClass = 0xFF (Vendor Specific) + 0x00, // bInterfaceSubClass = 0 (None) + 0x00, // bInterfaceProtocol = 0 (None) + 0x00, // iInterface (string index) + + // interface descriptor + 0x09, // bLength = 9 + 0x04, // bDescriptorType = interface + 0x03, // bInterfaceNumber = 3 + 0x00, // bAlternateSetting = 0 + 0x02, // bNumEndpoints = 2 + 0xFF, // bInterfaceClass = 0xFF (Vendor Specific) + 0x00, // bInterfaceSubClass = 0 (None) + 0x00, // bInterfaceProtocol = 0 (None) + 0x00, // iInterface (string index) + + // endpoint descriptor + 0x07, // bLength = 7 + 0x05, // bDescriptorType = endpoint + 0x01, // bEndpointAddress (OUT) + 0x02, // bmAttributes (Bulk) + 0x40, 0x00, // wMaxPacketSize = 64 + 0x00, // bInterval = 0 + + // endpoint descriptor + 0x07, // bLength = 7 + 0x05, // bDescriptorType = endpoint + 0x82, // bEndpointAddress (IN) + 0x02, // bmAttributes (Bulk) + 0x40, 0x00, // wMaxPacketSize = 64 + 0x00, // bInterval = 0 + }; + + static final byte[] SIMPLE; + + static final byte[] COMPOSITE_LARGE; + + static final byte[] COMPOSITE_TEST_DEVICE; + + static { + SIMPLE = new byte[SIMPLE_INT_ARRAY.length]; + for (int i = 0; i < SIMPLE_INT_ARRAY.length; i++) + SIMPLE[i] = (byte) SIMPLE_INT_ARRAY[i]; + + COMPOSITE_LARGE = new byte[LARGE_COMPOSITE_INT_ARRAY.length]; + for (int i = 0; i < LARGE_COMPOSITE_INT_ARRAY.length; i++) + COMPOSITE_LARGE[i] = (byte) LARGE_COMPOSITE_INT_ARRAY[i]; + + COMPOSITE_TEST_DEVICE = new byte[COMPOSITE_TEST_DEVICE_INT_ARRAY.length]; + for (int i = 0; i < COMPOSITE_TEST_DEVICE_INT_ARRAY.length; i++) + COMPOSITE_TEST_DEVICE[i] = (byte) COMPOSITE_TEST_DEVICE_INT_ARRAY[i]; + } +} diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java b/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java new file mode 100644 index 00000000..6a3d11d8 --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java @@ -0,0 +1,258 @@ +package net.codecrete.usb; + +import net.codecrete.usb.common.ConfigurationParser; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.Test; + +import java.lang.foreign.MemorySegment; + +import static net.codecrete.usb.ConfigurationDescriptors.*; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class ConfigurationParserTest { + + @Test + void simpleDescriptor_canBeParsed() { + + var configuration = ConfigurationParser.parseConfigurationDescriptor(MemorySegment.ofArray(SIMPLE)); + + var softly = new SoftAssertions(); + softly.assertThat(configuration.interfaces()) + .hasSize(1) + .singleElement().satisfies(intf -> { + softly.assertThat(intf.number()).isEqualTo(0); + softly.assertThat(intf.alternates()) + .hasSize(1) + .singleElement().satisfies(altIntf -> { + softly.assertThat(altIntf).isSameAs(intf.alternate()); + softly.assertThat(altIntf.number()).isEqualTo(0); + softly.assertThat(altIntf.endpoints()).isEmpty(); + softly.assertThat(altIntf.classCode()).isEqualTo(0x0ff); + softly.assertThat(altIntf.subclassCode()).isEqualTo(0x0dd); + softly.assertThat(altIntf.protocolCode()).isEqualTo(0x0cc); + }); + softly.assertThat(intf.isClaimed()).isFalse(); + }); + softly.assertThat(configuration.functions()).hasSize(1); + softly.assertThat(configuration.configValue()).isEqualTo(1); + softly.assertThat(configuration.attributes()).isEqualTo(0x34); + softly.assertThat(configuration.maxPower()).isEqualTo(0x64); + softly.assertAll(); + } + + @Test + @SuppressWarnings("java:S5961") + void largeCompositeDescriptor_canBeParsed() { + var configuration = ConfigurationParser.parseConfigurationDescriptor(MemorySegment.ofArray(COMPOSITE_LARGE)); + + var softly = new SoftAssertions(); + + // 2 functions + softly.assertThat(configuration.functions()) + .hasSize(2); + + // function 0: 3 interfaces + softly.assertThat(configuration.functions().get(0)).satisfies(function -> { + softly.assertThat(function.firstInterfaceNumber()).isEqualTo(0); + softly.assertThat(function.numInterfaces()).isEqualTo(3); + }); + + // function 1: 1 interface + softly.assertThat(configuration.functions().get(1)).satisfies(function -> { + softly.assertThat(function.firstInterfaceNumber()).isEqualTo(3); + softly.assertThat(function.numInterfaces()).isEqualTo(1); + }); + + softly.assertThat(configuration.interfaces()).hasSize(4); + + // interface 0 + softly.assertThat(configuration.interfaces().get(0)).satisfies(intf -> { + softly.assertThat(intf.number()).isEqualTo(0); + softly.assertThat(intf.alternates()).hasSize(1); + softly.assertThat(intf.alternate().endpoints()).hasSize(1); + softly.assertThat(intf.alternate().endpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(endpoint.number()).isEqualTo(5); + softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.IN); + softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.INTERRUPT); + }); + }); + + // interface 1 + softly.assertThat(configuration.interfaces().get(1)).satisfies(intf -> { + softly.assertThat(intf.number()).isEqualTo(1); + softly.assertThat(intf.alternates()).hasSize(2); + softly.assertThat(intf.alternates().get(0)).satisfies(alternate -> { + softly.assertThat(alternate.number()).isEqualTo(0); + softly.assertThat(alternate.endpoints()).isEmpty(); + }); + softly.assertThat(intf.alternates().get(1)).satisfies(alternate -> { + softly.assertThat(alternate.number()).isEqualTo(1); + softly.assertThat(alternate.endpoints()).hasSize(1); + softly.assertThat(alternate.endpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(endpoint.number()).isEqualTo(1); + softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.IN); + softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.ISOCHRONOUS); + }); + }); + }); + + // interface 2 + softly.assertThat(configuration.interfaces().get(2)).satisfies(intf -> { + softly.assertThat(intf.number()).isEqualTo(2); + softly.assertThat(intf.alternates()).hasSize(2); + softly.assertThat(intf.alternates().get(0)).satisfies(alternate -> { + softly.assertThat(alternate.number()).isEqualTo(0); + softly.assertThat(alternate.endpoints()).isEmpty(); + }); + softly.assertThat(intf.alternates().get(1)).satisfies(alternate -> { + softly.assertThat(alternate.number()).isEqualTo(1); + softly.assertThat(alternate.endpoints()).hasSize(1); + softly.assertThat(alternate.endpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(endpoint.number()).isEqualTo(2); + softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.IN); + softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.ISOCHRONOUS); + }); + }); + }); + + // interface 3 + softly.assertThat(configuration.interfaces().get(3)).satisfies(intf -> { + softly.assertThat(intf.number()).isEqualTo(3); + softly.assertThat(intf.alternates()).hasSize(1); + softly.assertThat(intf.alternates().get(0)).satisfies(alternate -> { + softly.assertThat(alternate.number()).isEqualTo(0); + softly.assertThat(alternate.endpoints()).hasSize(1); + softly.assertThat(alternate.endpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(endpoint.number()).isEqualTo(4); + softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.IN); + softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.INTERRUPT); + }); + }); + }); + + softly.assertAll(); + } + + + @Test + @SuppressWarnings("java:S5961") + void compositeTestDeviceDescriptor_canBeParsed() { + var configuration = ConfigurationParser.parseConfigurationDescriptor(MemorySegment.ofArray(COMPOSITE_TEST_DEVICE)); + + var softly = new SoftAssertions(); + + // 2 functions + softly.assertThat(configuration.functions()) + .hasSize(2); + + // function 0: 2 interfaces + softly.assertThat(configuration.functions().get(0)).satisfies(function -> { + softly.assertThat(function.firstInterfaceNumber()).isEqualTo(0); + softly.assertThat(function.numInterfaces()).isEqualTo(2); + }); + + // function 1: 2 interfaces + softly.assertThat(configuration.functions().get(1)).satisfies(function -> { + softly.assertThat(function.firstInterfaceNumber()).isEqualTo(2); + softly.assertThat(function.numInterfaces()).isEqualTo(2); + }); + + softly.assertThat(configuration.interfaces()).hasSize(4); + + // interface 0 + softly.assertThat(configuration.interfaces().get(0)).satisfies(intf -> { + softly.assertThat(intf.number()).isEqualTo(0); + softly.assertThat(intf.alternates()).hasSize(1); + softly.assertThat(intf.alternate().endpoints()).hasSize(1); + softly.assertThat(intf.alternate().endpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(endpoint.number()).isEqualTo(3); + softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.IN); + softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.INTERRUPT); + }); + }); + + // interface 1 + softly.assertThat(configuration.interfaces().get(1)).satisfies(intf -> { + softly.assertThat(intf.number()).isEqualTo(1); + softly.assertThat(intf.alternates()).hasSize(1); + softly.assertThat(intf.alternates().get(0)).satisfies(alternate -> { + softly.assertThat(alternate.number()).isEqualTo(0); + softly.assertThat(alternate.endpoints()).hasSize(2); + softly.assertThat(alternate.endpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(endpoint.number()).isEqualTo(2); + softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.OUT); + softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.BULK); + }); + softly.assertThat(alternate.endpoints().get(1)).satisfies(endpoint -> { + softly.assertThat(endpoint.number()).isEqualTo(1); + softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.IN); + softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.BULK); + }); + }); + }); + + // interface 2 + softly.assertThat(configuration.interfaces().get(2)).satisfies(intf -> { + softly.assertThat(intf.number()).isEqualTo(2); + softly.assertThat(intf.alternates()).hasSize(1); + softly.assertThat(intf.alternates().get(0)).satisfies(alternate -> { + softly.assertThat(alternate.number()).isEqualTo(0); + softly.assertThat(alternate.endpoints()).isEmpty(); + }); + }); + + // interface 3 + softly.assertThat(configuration.interfaces().get(3)).satisfies(intf -> { + softly.assertThat(intf.number()).isEqualTo(3); + softly.assertThat(intf.alternates()).hasSize(1); + softly.assertThat(intf.alternates().get(0)).satisfies(alternate -> { + softly.assertThat(alternate.number()).isEqualTo(0); + softly.assertThat(alternate.endpoints()).hasSize(2); + softly.assertThat(alternate.endpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(endpoint.number()).isEqualTo(1); + softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.OUT); + softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.BULK); + }); + softly.assertThat(alternate.endpoints().get(1)).satisfies(endpoint -> { + softly.assertThat(endpoint.number()).isEqualTo(2); + softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.IN); + softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.BULK); + }); + }); + }); + + softly.assertAll(); + } + + @Test + void tooShortDescriptor_throwsException() { + var desc = new byte[COMPOSITE_LARGE.length - 1]; + System.arraycopy(COMPOSITE_LARGE, 0, desc, 0, desc.length); + var segment = MemorySegment.ofArray(desc); + + assertThatThrownBy(() -> ConfigurationParser.parseConfigurationDescriptor(segment)) + .isInstanceOf(USBException.class) + .hasMessage("invalid USB configuration descriptor (invalid length)"); + } + + @Test + void tooLongDescriptor_throwsException() { + var desc = new byte[COMPOSITE_LARGE.length + 1]; + System.arraycopy(COMPOSITE_LARGE, 0, desc, 0, COMPOSITE_LARGE.length); + var segment = MemorySegment.ofArray(desc); + + assertThatThrownBy(() -> ConfigurationParser.parseConfigurationDescriptor(segment)) + .isInstanceOf(USBException.class) + .hasMessage("invalid USB configuration descriptor (invalid length)"); + } + + @Test + void invalidDescriptor_throwsException() { + var desc = new byte[] { 0x5a, 0x41, 0x03, 0x07 }; + var segment = MemorySegment.ofArray(desc); + + assertThatThrownBy(() -> ConfigurationParser.parseConfigurationDescriptor(segment)) + .isInstanceOf(USBException.class) + .hasMessage("invalid USB configuration descriptor"); + } +} diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptorTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptorTest.java index 85dc9057..3b4f4bba 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptorTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptorTest.java @@ -2,22 +2,21 @@ import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; class DescriptorTest extends TestDeviceBase { @Test void deviceDescriptor_isAvailable() { var desc = testDevice.deviceDescriptor(); - assertEquals(18, desc.length); - assertEquals(0x01, desc[1]); + assertThat(desc).hasSize(18); + assertThat(desc[1]).isEqualTo((byte) 0x01); } @Test void configurationDescriptor_isAvailable() { var desc = testDevice.configurationDescriptor(); - assertTrue(desc.length > 60); - assertEquals(0x02, desc[1]); + assertThat(desc).hasSizeGreaterThan(60); + assertThat(desc[1]).isEqualTo((byte) 0x02); } } From ae14ce894d872c7355f9350dd3db77aff4458e8c Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 10 Nov 2023 15:49:59 +0100 Subject: [PATCH 298/433] Kotlin-friendly API --- examples/bulk_transfer/pom.xml | 2 +- .../codecrete/usb/examples/BulkTransfer.java | 2 +- examples/enumerate/pom.xml | 2 +- .../net/codecrete/usb/examples/Enumerate.java | 74 +++--- examples/enumerate_kotlin/.gitignore | 38 +++ examples/enumerate_kotlin/pom.xml | 66 +++++ .../net/codecrete/usb/examples/Enumerate.kt | 95 +++++++ .../codecrete/usb/examples/UsbClassInfo.kt | 234 ++++++++++++++++++ examples/epaper_display/pom.xml | 2 +- .../codecrete/usb/examples/IT8951Driver.java | 10 +- examples/monitor/pom.xml | 2 +- .../net/codecrete/usb/examples/Monitor.java | 12 +- examples/stm_dfu/pom.xml | 2 +- .../java/net/codecrete/usb/dfu/DFUDevice.java | 49 ++-- .../java/net/codecrete/usb/dfu/STM32.java | 3 + .../java/net/codecrete/usb/dfu/Segment.java | 19 +- java-does-usb/pom.xml | 8 +- java-does-usb/src/main/java/module-info.java | 1 + .../net/codecrete/usb/{USB.java => Usb.java} | 49 ++-- ...erface.java => UsbAlternateInterface.java} | 23 +- ...lTransfer.java => UsbControlTransfer.java} | 6 +- .../usb/{USBDevice.java => UsbDevice.java} | 82 +++--- ...Predicate.java => UsbDevicePredicate.java} | 10 +- .../{USBDirection.java => UsbDirection.java} | 2 +- .../{USBEndpoint.java => UsbEndpoint.java} | 12 +- .../{USBException.java => UsbException.java} | 13 +- .../{USBInterface.java => UsbInterface.java} | 19 +- .../{USBRecipient.java => UsbRecipient.java} | 2 +- ...SBRequestType.java => UsbRequestType.java} | 2 +- ...lException.java => UsbStallException.java} | 8 +- ...xception.java => UsbTimeoutException.java} | 6 +- ...TransferType.java => UsbTransferType.java} | 2 +- .../main/java/net/codecrete/usb/Version.java | 8 +- .../codecrete/usb/common/Configuration.java | 12 +- .../usb/common/ConfigurationParser.java | 50 ++-- .../usb/common/EndpointInputStream.java | 17 +- .../usb/common/EndpointOutputStream.java | 11 +- .../usb/common/USBAlternateInterfaceImpl.java | 68 ----- .../usb/common/USBInterfaceImpl.java | 66 ----- .../usb/common/UsbAlternateInterfaceImpl.java | 74 ++++++ ...{USBDeviceImpl.java => UsbDeviceImpl.java} | 129 +++++----- ...ceRegistry.java => UsbDeviceRegistry.java} | 45 ++-- ...EndpointImpl.java => UsbEndpointImpl.java} | 24 +- .../usb/common/UsbInterfaceImpl.java | 75 ++++++ .../codecrete/usb/linux/LinuxAsyncTask.java | 18 +- .../usb/linux/LinuxEndpointInputStream.java | 6 +- .../usb/linux/LinuxEndpointOutputStream.java | 6 +- ...inuxUSBDevice.java => LinuxUsbDevice.java} | 112 ++++----- ...istry.java => LinuxUsbDeviceRegistry.java} | 20 +- ...BException.java => LinuxUsbException.java} | 14 +- .../linux/{USBDevFS.java => UsbDevFS.java} | 4 +- .../net/codecrete/usb/macos/IoKitHelper.java | 4 +- .../macos/{IoKitUSB.java => IoKitUsb.java} | 4 +- .../codecrete/usb/macos/MacosAsyncTask.java | 4 +- .../usb/macos/MacosEndpointInputStream.java | 4 +- .../usb/macos/MacosEndpointOutputStream.java | 4 +- ...acosUSBDevice.java => MacosUsbDevice.java} | 195 +++++++-------- ...istry.java => MacosUsbDeviceRegistry.java} | 28 +-- ...BException.java => MacosUsbException.java} | 18 +- .../codecrete/usb/windows/DeviceInfoSet.java | 4 +- .../{USBConstants.java => UsbConstants.java} | 4 +- .../usb/windows/WindowsAsyncTask.java | 2 +- .../windows/WindowsEndpointInputStream.java | 8 +- .../windows/WindowsEndpointOutputStream.java | 8 +- ...wsUSBDevice.java => WindowsUsbDevice.java} | 92 ++++--- ...try.java => WindowsUsbDeviceRegistry.java} | 42 ++-- ...xception.java => WindowsUsbException.java} | 14 +- .../codecrete/usb/AlternateInterfaceTest.java | 14 +- .../net/codecrete/usb/BulkTransferTest.java | 4 +- .../usb/ConfigurationParserTest.java | 178 ++++++------- .../codecrete/usb/ControlTransferTest.java | 18 +- .../net/codecrete/usb/DescriptionTest.java | 163 ++++++------ .../net/codecrete/usb/DescriptorTest.java | 4 +- .../codecrete/usb/DeviceEnumerationTest.java | 20 +- .../codecrete/usb/DeviceLifecycleTest.java | 36 +-- .../codecrete/usb/InvalidOperationTest.java | 20 +- .../java/net/codecrete/usb/SpeedTest.java | 2 +- .../java/net/codecrete/usb/StallTest.java | 22 +- .../net/codecrete/usb/TestDeviceBase.java | 22 +- .../java/net/codecrete/usb/TimeoutTest.java | 10 +- .../usb/special/EnumerateDevices.java | 4 +- .../codecrete/usb/special/LogicAnalyzer.java | 32 +-- .../codecrete/usb/special/MonitorDevices.java | 14 +- .../codecrete/usb/special/USBSerialTest.java | 26 +- .../net/codecrete/usb/special/Unplug.java | 28 +-- 85 files changed, 1588 insertions(+), 1080 deletions(-) create mode 100644 examples/enumerate_kotlin/.gitignore create mode 100644 examples/enumerate_kotlin/pom.xml create mode 100644 examples/enumerate_kotlin/src/main/kotlin/net/codecrete/usb/examples/Enumerate.kt create mode 100644 examples/enumerate_kotlin/src/main/kotlin/net/codecrete/usb/examples/UsbClassInfo.kt rename java-does-usb/src/main/java/net/codecrete/usb/{USB.java => Usb.java} (64%) rename java-does-usb/src/main/java/net/codecrete/usb/{USBAlternateInterface.java => UsbAlternateInterface.java} (74%) rename java-does-usb/src/main/java/net/codecrete/usb/{USBControlTransfer.java => UsbControlTransfer.java} (90%) rename java-does-usb/src/main/java/net/codecrete/usb/{USBDevice.java => UsbDevice.java} (86%) rename java-does-usb/src/main/java/net/codecrete/usb/{USBDevicePredicate.java => UsbDevicePredicate.java} (78%) rename java-does-usb/src/main/java/net/codecrete/usb/{USBDirection.java => UsbDirection.java} (92%) rename java-does-usb/src/main/java/net/codecrete/usb/{USBEndpoint.java => UsbEndpoint.java} (87%) rename java-does-usb/src/main/java/net/codecrete/usb/{USBException.java => UsbException.java} (74%) rename java-does-usb/src/main/java/net/codecrete/usb/{USBInterface.java => UsbInterface.java} (66%) rename java-does-usb/src/main/java/net/codecrete/usb/{USBRecipient.java => UsbRecipient.java} (93%) rename java-does-usb/src/main/java/net/codecrete/usb/{USBRequestType.java => UsbRequestType.java} (93%) rename java-does-usb/src/main/java/net/codecrete/usb/{USBStallException.java => UsbStallException.java} (73%) rename java-does-usb/src/main/java/net/codecrete/usb/{USBTimeoutException.java => UsbTimeoutException.java} (69%) rename java-does-usb/src/main/java/net/codecrete/usb/{USBTransferType.java => UsbTransferType.java} (93%) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/UsbAlternateInterfaceImpl.java rename java-does-usb/src/main/java/net/codecrete/usb/common/{USBDeviceImpl.java => UsbDeviceImpl.java} (74%) rename java-does-usb/src/main/java/net/codecrete/usb/common/{USBDeviceRegistry.java => UsbDeviceRegistry.java} (83%) rename java-does-usb/src/main/java/net/codecrete/usb/common/{USBEndpointImpl.java => UsbEndpointImpl.java} (51%) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/UsbInterfaceImpl.java rename java-does-usb/src/main/java/net/codecrete/usb/linux/{LinuxUSBDevice.java => LinuxUsbDevice.java} (73%) rename java-does-usb/src/main/java/net/codecrete/usb/linux/{LinuxUSBDeviceRegistry.java => LinuxUsbDeviceRegistry.java} (93%) rename java-does-usb/src/main/java/net/codecrete/usb/linux/{LinuxUSBException.java => LinuxUsbException.java} (85%) rename java-does-usb/src/main/java/net/codecrete/usb/linux/{USBDevFS.java => UsbDevFS.java} (95%) rename java-does-usb/src/main/java/net/codecrete/usb/macos/{IoKitUSB.java => IoKitUsb.java} (99%) rename java-does-usb/src/main/java/net/codecrete/usb/macos/{MacosUSBDevice.java => MacosUsbDevice.java} (78%) rename java-does-usb/src/main/java/net/codecrete/usb/macos/{MacosUSBDeviceRegistry.java => MacosUsbDeviceRegistry.java} (93%) rename java-does-usb/src/main/java/net/codecrete/usb/macos/{MacosUSBException.java => MacosUsbException.java} (79%) rename java-does-usb/src/main/java/net/codecrete/usb/windows/{USBConstants.java => UsbConstants.java} (95%) rename java-does-usb/src/main/java/net/codecrete/usb/windows/{WindowsUSBDevice.java => WindowsUsbDevice.java} (86%) rename java-does-usb/src/main/java/net/codecrete/usb/windows/{WindowsUSBDeviceRegistry.java => WindowsUsbDeviceRegistry.java} (92%) rename java-does-usb/src/main/java/net/codecrete/usb/windows/{WindowsUSBException.java => WindowsUsbException.java} (91%) diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index 7d7974be..8e34bba4 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.6.1 + 0.7.0-SNAPSHOT diff --git a/examples/bulk_transfer/src/main/java/net/codecrete/usb/examples/BulkTransfer.java b/examples/bulk_transfer/src/main/java/net/codecrete/usb/examples/BulkTransfer.java index bfef6131..4e738ef7 100644 --- a/examples/bulk_transfer/src/main/java/net/codecrete/usb/examples/BulkTransfer.java +++ b/examples/bulk_transfer/src/main/java/net/codecrete/usb/examples/BulkTransfer.java @@ -27,7 +27,7 @@ public class BulkTransfer { private static final int ENDPOINT_IN = 2; public static void main(String[] args) { - var optionalDevice = USB.getDevice(VID, PID); + var optionalDevice = Usb.findDevice(VID, PID); if (optionalDevice.isEmpty()) { System.out.printf("No USB device with VID=0x%04x and PID=0x%04x found.%n", VID, PID); return; diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index f2ac2475..7e3b68e5 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.6.1 + 0.7.0-SNAPSHOT org.tinylog diff --git a/examples/enumerate/src/main/java/net/codecrete/usb/examples/Enumerate.java b/examples/enumerate/src/main/java/net/codecrete/usb/examples/Enumerate.java index b575db86..4e387b8f 100644 --- a/examples/enumerate/src/main/java/net/codecrete/usb/examples/Enumerate.java +++ b/examples/enumerate/src/main/java/net/codecrete/usb/examples/Enumerate.java @@ -19,32 +19,32 @@ public class Enumerate { public static void main(String[] args) { // display the already present USB devices - for (var device : USB.getAllDevices()) + for (var device : Usb.getDevices()) printDevice(device); } - private static void printDevice(USBDevice device) { + private static void printDevice(UsbDevice device) { System.out.println("Device:"); - System.out.printf(" VID: 0x%04x%n", device.vendorId()); - System.out.printf(" PID: 0x%04x%n", device.productId()); - if (device.manufacturer() != null) - System.out.printf(" Manufacturer: %s%n", device.manufacturer()); - if (device.product() != null) - System.out.printf(" Product name: %s%n", device.product()); - if (device.serialNumber() != null) - System.out.printf(" Serial number: %s%n", device.serialNumber()); - System.out.printf(" Device class: 0x%02x", device.classCode()); - printInParens(USBClassInfo.lookupClass(device.classCode())); - System.out.printf(" Device subclass: 0x%02x", device.subclassCode()); - printInParens(USBClassInfo.lookupSubclass(device.classCode(), device.subclassCode())); - System.out.printf(" Device protocol: 0x%02x", device.protocolCode()); - printInParens(USBClassInfo.lookupProtocol(device.classCode(), device.subclassCode(), device.protocolCode())); - - for (var intf: device.interfaces()) + System.out.printf(" VID: 0x%04x%n", device.getVendorId()); + System.out.printf(" PID: 0x%04x%n", device.getProductId()); + if (device.getManufacturer() != null) + System.out.printf(" Manufacturer: %s%n", device.getManufacturer()); + if (device.getProduct() != null) + System.out.printf(" Product name: %s%n", device.getProduct()); + if (device.getSerialNumber() != null) + System.out.printf(" Serial number: %s%n", device.getSerialNumber()); + System.out.printf(" Device class: 0x%02x", device.getClassCode()); + printInParens(USBClassInfo.lookupClass(device.getClassCode())); + System.out.printf(" Device subclass: 0x%02x", device.getSubclassCode()); + printInParens(USBClassInfo.lookupSubclass(device.getClassCode(), device.getSubclassCode())); + System.out.printf(" Device protocol: 0x%02x", device.getProtocolCode()); + printInParens(USBClassInfo.lookupProtocol(device.getClassCode(), device.getSubclassCode(), device.getProtocolCode())); + + for (var intf: device.getInterfaces()) printInterface(intf); - printRawDescriptor("Device descriptor", device.deviceDescriptor()); - printRawDescriptor("Configuration descriptor", device.configurationDescriptor()); + printRawDescriptor("Device descriptor", device.getDeviceDescriptor()); + printRawDescriptor("Configuration descriptor", device.getConfigurationDescriptor()); System.out.println(); System.out.println(); @@ -59,36 +59,36 @@ private static void printInParens(Optional text) { } } - private static void printInterface(USBInterface intf) { - for (var alt : intf.alternates()) - printAlternate(alt, intf.number(), alt == intf.alternate()); + private static void printInterface(UsbInterface intf) { + for (var alt : intf.getAlternates()) + printAlternate(alt, intf.getNumber(), alt == intf.getCurrentAlternate()); } - private static void printAlternate(USBAlternateInterface alt, int intferaceNumber, boolean isDefault) { + private static void printAlternate(UsbAlternateInterface alt, int intferaceNumber, boolean isDefault) { System.out.println(); if (isDefault) { System.out.printf(" Interface %d%n", intferaceNumber); } else { - System.out.printf(" Interface %d (alternate %d)%n", intferaceNumber, alt.number()); + System.out.printf(" Interface %d (alternate %d)%n", intferaceNumber, alt.getNumber()); } - System.out.printf(" Interface class: 0x%02x", alt.classCode()); - printInParens(USBClassInfo.lookupClass(alt.classCode())); - System.out.printf(" Interface subclass: 0x%02x", alt.subclassCode()); - printInParens(USBClassInfo.lookupProtocol(alt.classCode(), alt.subclassCode(), alt.protocolCode())); - System.out.printf(" Interface protocol: 0x%02x", alt.protocolCode()); - printInParens(USBClassInfo.lookupProtocol(alt.classCode(), alt.subclassCode(), alt.protocolCode())); + System.out.printf(" Interface class: 0x%02x", alt.getClassCode()); + printInParens(USBClassInfo.lookupClass(alt.getClassCode())); + System.out.printf(" Interface subclass: 0x%02x", alt.getSubclassCode()); + printInParens(USBClassInfo.lookupProtocol(alt.getClassCode(), alt.getSubclassCode(), alt.getProtocolCode())); + System.out.printf(" Interface protocol: 0x%02x", alt.getProtocolCode()); + printInParens(USBClassInfo.lookupProtocol(alt.getClassCode(), alt.getSubclassCode(), alt.getProtocolCode())); - for (var endpoint : alt.endpoints()) + for (var endpoint : alt.getEndpoints()) printEndpoint(endpoint); } - private static void printEndpoint(USBEndpoint endpoint) { + private static void printEndpoint(UsbEndpoint endpoint) { System.out.println(); - System.out.printf(" Endpoint %d%n", endpoint.number()); - System.out.printf(" Direction: %s%n", endpoint.direction().name()); - System.out.printf(" Transfer type: %s%n", endpoint.transferType().name()); - System.out.printf(" Packet size: %d bytes%n", endpoint.packetSize()); + System.out.printf(" Endpoint %d%n", endpoint.getNumber()); + System.out.printf(" Direction: %s%n", endpoint.getDirection().name()); + System.out.printf(" Transfer type: %s%n", endpoint.getTransferType().name()); + System.out.printf(" Packet size: %d bytes%n", endpoint.getPacketSize()); } private static void printRawDescriptor(String title, byte[] descriptor) { diff --git a/examples/enumerate_kotlin/.gitignore b/examples/enumerate_kotlin/.gitignore new file mode 100644 index 00000000..5ff6309b --- /dev/null +++ b/examples/enumerate_kotlin/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/examples/enumerate_kotlin/pom.xml b/examples/enumerate_kotlin/pom.xml new file mode 100644 index 00000000..5110c7df --- /dev/null +++ b/examples/enumerate_kotlin/pom.xml @@ -0,0 +1,66 @@ + + 4.0.0 + + net.codecrete.usb.examples + kotlin + 0.6.1-SNAPSHOT + jar + + kotlin + https://github.com/manuelbl/JavaDoesUSB/examples/kotlin + + + 1.9.10 + true + UTF-8 + + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/test/kotlin + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + true + + + + + + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin.version} + + + net.codecrete.usb + java-does-usb + 0.7.0-SNAPSHOT + + + org.tinylog + tinylog-api + 2.6.2 + + + org.tinylog + tinylog-impl + 2.6.2 + + + org.tinylog + jsl-tinylog + 2.6.2 + + + junit + junit + 4.13.2 + test + + + diff --git a/examples/enumerate_kotlin/src/main/kotlin/net/codecrete/usb/examples/Enumerate.kt b/examples/enumerate_kotlin/src/main/kotlin/net/codecrete/usb/examples/Enumerate.kt new file mode 100644 index 00000000..cf741727 --- /dev/null +++ b/examples/enumerate_kotlin/src/main/kotlin/net/codecrete/usb/examples/Enumerate.kt @@ -0,0 +1,95 @@ +package net.codecrete.usb.examples + +import net.codecrete.usb.* +import kotlin.math.min + + +fun main() { + Enumerate().enumerate() +} + +class Enumerate { + + private var classInfo = UsbClassInfo() + + fun enumerate() { + for (device in Usb.getDevices()) { + printDevice(device) + } + } + + private fun printDevice(device: UsbDevice) { + println("Device:") + System.out.printf(" VID: 0x%04x%n", device.vendorId) + System.out.printf(" PID: 0x%04x%n", device.productId) + if (device.manufacturer != null) System.out.printf(" Manufacturer: %s%n", device.manufacturer) + if (device.product != null) System.out.printf(" Product name: %s%n", device.product) + if (device.serialNumber != null) System.out.printf(" Serial number: %s%n", device.serialNumber) + System.out.printf(" Device class: 0x%02x", device.classCode) + printInParens(classInfo.lookupClass(device.classCode)) + System.out.printf(" Device subclass: 0x%02x", device.subclassCode) + printInParens(classInfo.lookupSubclass(device.classCode, device.subclassCode)) + System.out.printf(" Device protocol: 0x%02x", device.protocolCode) + printInParens(classInfo.lookupProtocol(device.classCode, device.subclassCode, device.protocolCode)) + for (intf in device.interfaces) printInterface(intf) + printRawDescriptor("Device descriptor", device.deviceDescriptor) + printRawDescriptor("Configuration descriptor", device.configurationDescriptor) + println() + println() + } + + private fun printInParens(text: String?) { + if (text != null) { + System.out.printf(" (%s)%n", text) + } else { + println() + } + } + + private fun printInterface(intf: UsbInterface) { + for (alt in intf.alternates) printAlternate(alt, intf.number, alt === intf.currentAlternate) + } + + private fun printAlternate(alt: UsbAlternateInterface, intferfaceNumber: Int, isDefault: Boolean) { + println() + if (isDefault) { + System.out.printf(" Interface %d%n", intferfaceNumber) + } else { + System.out.printf(" Interface %d (alternate %d)%n", intferfaceNumber, alt.number) + } + System.out.printf(" Interface class: 0x%02x", alt.classCode) + printInParens(classInfo.lookupClass(alt.classCode)) + System.out.printf(" Interface subclass: 0x%02x", alt.subclassCode) + printInParens(classInfo.lookupProtocol(alt.classCode, alt.subclassCode, alt.protocolCode)) + System.out.printf(" Interface protocol: 0x%02x", alt.protocolCode) + printInParens(classInfo.lookupProtocol(alt.classCode, alt.subclassCode, alt.protocolCode)) + for (endpoint in alt.endpoints) + printEndpoint(endpoint) + } + + private fun printEndpoint(endpoint: UsbEndpoint) { + println() + System.out.printf(" Endpoint %d%n", endpoint.number) + System.out.printf(" Direction: %s%n", endpoint.direction.name) + System.out.printf(" Transfer type: %s%n", endpoint.transferType.name) + System.out.printf(" Packet size: %d bytes%n", endpoint.packetSize) + } + + private fun printRawDescriptor(title: String, descriptor: ByteArray) { + println() + println(title) + val len = descriptor.size + var i = 0 + while (i < len) { + System.out.printf("%04x ", i) + var j = i + while (j < min(i + 16, len)) { + System.out.printf(" %02x", descriptor[j].toInt() and 255) + j += 1 + } + println() + i += 16 + } + } + +} \ No newline at end of file diff --git a/examples/enumerate_kotlin/src/main/kotlin/net/codecrete/usb/examples/UsbClassInfo.kt b/examples/enumerate_kotlin/src/main/kotlin/net/codecrete/usb/examples/UsbClassInfo.kt new file mode 100644 index 00000000..56ee48dc --- /dev/null +++ b/examples/enumerate_kotlin/src/main/kotlin/net/codecrete/usb/examples/UsbClassInfo.kt @@ -0,0 +1,234 @@ +package net.codecrete.usb.examples + +import java.io.BufferedReader +import java.io.IOException +import java.io.StringReader +import java.util.* + + +class UsbClassInfo { + private val classCodes: MutableList = ArrayList() + private val subclassCodes: MutableList = ArrayList() + private val protocolCodes: MutableList = ArrayList() + + // List of known device classes, subclasses and + // from http://www.linux-usb.org/usb.ids + private val rawClassData = """ +C 00 (Defined at Interface level) +C 01 Audio + 01 Control Device + 02 Streaming + 03 MIDI Streaming +C 02 Communications + 01 Direct Line + 02 Abstract (modem) + 00 None + 01 AT-commands (v.25ter) + 02 AT-commands (PCCA101) + 03 AT-commands (PCCA101 + wakeup) + 04 AT-commands (GSM) + 05 AT-commands (3G) + 06 AT-commands (CDMA) + fe Defined by command set descriptor + ff Vendor Specific (MSFT RNDIS?) + 03 Telephone + 04 Multi-Channel + 05 CAPI Control + 06 Ethernet Networking + 07 ATM Networking + 08 Wireless Handset Control + 09 Device Management + 0a Mobile Direct Line + 0b OBEX + 0c Ethernet Emulation + 07 Ethernet Emulation (EEM) +C 03 Human Interface Device + 00 No Subclass + 00 None + 01 Keyboard + 02 Mouse + 01 Boot Interface Subclass + 00 None + 01 Keyboard + 02 Mouse +C 05 Physical Interface Device +C 06 Imaging + 01 Still Image Capture + 01 Picture Transfer Protocol (PIMA 15470) +C 07 Printer + 01 Printer + 00 Reserved/Undefined + 01 Unidirectional + 02 Bidirectional + 03 IEEE 1284.4 compatible bidirectional + ff Vendor Specific +C 08 Mass Storage + 01 RBC (typically Flash) + 00 Control/Bulk/Interrupt + 01 Control/Bulk + 50 Bulk-Only + 02 SFF-8020i, MMC-2 (ATAPI) + 03 QIC-157 + 04 Floppy (UFI) + 00 Control/Bulk/Interrupt + 01 Control/Bulk + 50 Bulk-Only + 05 SFF-8070i + 06 SCSI + 00 Control/Bulk/Interrupt + 01 Control/Bulk + 50 Bulk-Only +C 09 Hub + 00 Unused + 00 Full speed (or root) hub + 01 Single TT + 02 TT per port +C 0a CDC Data + 00 Unused + 30 I.430 ISDN BRI + 31 HDLC + 32 Transparent + 50 Q.921M + 51 Q.921 + 52 Q.921TM + 90 V.42bis + 91 Q.932 EuroISDN + 92 V.120 V.24 rate ISDN + 93 CAPI 2.0 + fd Host Based Driver + fe CDC PUF + ff Vendor specific +C 0b Chip/SmartCard +C 0d Content Security +C 0e Video + 00 Undefined + 01 Video Control + 02 Video Streaming + 03 Video Interface Collection +C 58 Xbox + 42 Controller +C dc Diagnostic + 01 Reprogrammable Diagnostics + 01 USB2 Compliance +C e0 Wireless + 01 Radio Frequency + 01 Bluetooth + 02 Ultra WideBand Radio Control + 03 RNDIS + 02 Wireless USB Wire Adapter + 01 Host Wire Adapter Control/Data Streaming + 02 Device Wire Adapter Control/Data Streaming + 03 Device Wire Adapter Isochronous Streaming +C ef Miscellaneous Device + 01 ? + 01 Microsoft ActiveSync + 02 Palm Sync + 02 ? + 01 Interface Association + 02 Wire Adapter Multifunction Peripheral + 03 ? + 01 Cable Based Association + 05 USB3 Vision +C fe Application Specific Interface + 01 Device Firmware Update + 02 IRDA Bridge + 03 Test and Measurement + 01 TMC + 02 USB488 +C ff Vendor Specific Class + ff Vendor Specific Subclass + ff Vendor Specific Protocol + """.trimIndent() + + + /** + * Provides the name of the specified USB class. + * + * @param classCode the USB class code + * @return an optional name + */ + fun lookupClass(classCode: Int): String? { + loadData() + return classCodes + .filter { cc -> cc.classCode == classCode } + .map { cc -> cc.name } + .firstOrNull() + } + + /** + * Provides the name of the specified USB subclass. + * + * @param classCode the USB class code + * @param subclassCode the USB subclass code + * @return an optional name + */ + fun lookupSubclass(classCode: Int, subclassCode: Int): String? { + loadData() + return subclassCodes + .filter { scc -> scc.classCode == classCode && scc.subclassCode == subclassCode } + .map { scc -> scc.name } + .firstOrNull() + } + + /** + * Provides the name of the specified USB protocol. + * + * @param classCode the USB class code + * @param subclassCode the USB subclass code + * @param protocolCode the USB protocol code + * @return an optional name + */ + fun lookupProtocol(classCode: Int, subclassCode: Int, protocolCode: Int): String? { + loadData() + return protocolCodes + .filter { prot -> prot.classCode == classCode && prot.subclassCode == subclassCode && prot.protocolCode == protocolCode } + .map { prot -> prot.name } + .firstOrNull() + } + + private fun loadData() { + if (classCodes.isNotEmpty()) + return + + try { + StringReader(rawClassData).use { stringReader -> + BufferedReader(stringReader).use { reader -> + var classCode = 0 + var subclassCode = 0 + var line = reader.readLine() + while (line != null) { + // protocol line + when { + line.startsWith("\t\t") -> { + val protocol = line.substring(2, 4).toInt(16) + protocolCodes.add(ProtocolCode(classCode, subclassCode, protocol, line.substring(6))) + // subclass line + } + line.startsWith("\t") -> { + subclassCode = line.substring(1, 3).toInt(16) + subclassCodes.add(SubclassCode(classCode, subclassCode, line.substring(5))) + // class line + } + line.startsWith("C ") -> { + classCode = line.substring(2, 4).toInt(16) + classCodes.add(ClassCode(classCode, line.substring(6))) + } + else -> { + error("Invalid raw data") + } + } + line = reader.readLine() + } + } + } + } catch (e: IOException) { + throw RuntimeException(e) + } + } + + internal data class ClassCode(val classCode: Int, val name: String) + + internal data class SubclassCode(val classCode: Int, val subclassCode: Int, val name: String) + + internal data class ProtocolCode(val classCode: Int, val subclassCode: Int, val protocolCode: Int, val name: String) +} \ No newline at end of file diff --git a/examples/epaper_display/pom.xml b/examples/epaper_display/pom.xml index 79874da5..9ea7e0e2 100644 --- a/examples/epaper_display/pom.xml +++ b/examples/epaper_display/pom.xml @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.6.1 + 0.7.0-SNAPSHOT diff --git a/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java b/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java index 7170fc71..47ae2b29 100644 --- a/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java +++ b/examples/epaper_display/src/main/java/net/codecrete/usb/examples/IT8951Driver.java @@ -7,8 +7,8 @@ package net.codecrete.usb.examples; -import net.codecrete.usb.USB; -import net.codecrete.usb.USBDevice; +import net.codecrete.usb.Usb; +import net.codecrete.usb.UsbDevice; import java.awt.image.BufferedImage; import java.awt.image.DataBufferByte; @@ -35,7 +35,7 @@ public class IT8951Driver { (byte)0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, (byte)0x94, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; - private USBDevice device; + private UsbDevice device; private int sequenceNo = 1; private DisplayInfo displayInfo; @@ -46,7 +46,7 @@ public class IT8951Driver { * @throws IllegalStateException if no IT8951 device is found */ public void open() { - var optionalDevice = USB.getDevice(0x048d, 0x8951); + var optionalDevice = Usb.findDevice(0x048d, 0x8951); if (optionalDevice.isEmpty()) throw new IllegalStateException("No IT8951 device found"); @@ -276,7 +276,7 @@ private Status readStatus() { if (result.length == 13) return Status.from(result); - throw new RuntimeException(String.format("Unexpected length of status block (%d)", result.length)); + throw new IllegalStateException(String.format("Unexpected length of status block (%d)", result.length)); } /** diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index b36fbf1e..4d2ae39e 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.6.1 + 0.7.0-SNAPSHOT org.tinylog diff --git a/examples/monitor/src/main/java/net/codecrete/usb/examples/Monitor.java b/examples/monitor/src/main/java/net/codecrete/usb/examples/Monitor.java index a897ba94..482d1b9f 100644 --- a/examples/monitor/src/main/java/net/codecrete/usb/examples/Monitor.java +++ b/examples/monitor/src/main/java/net/codecrete/usb/examples/Monitor.java @@ -7,8 +7,8 @@ package net.codecrete.usb.examples; -import net.codecrete.usb.USB; -import net.codecrete.usb.USBDevice; +import net.codecrete.usb.Usb; +import net.codecrete.usb.UsbDevice; import java.io.IOException; @@ -19,11 +19,11 @@ public class Monitor { public static void main(String[] args) throws IOException { // register callbacks for events - USB.setOnDeviceConnected((device) -> printDetails(device, "Connected")); - USB.setOnDeviceDisconnected((device) -> printDetails(device, "Disconnected")); + Usb.setOnDeviceConnected(device -> printDetails(device, "Connected")); + Usb.setOnDeviceDisconnected(device -> printDetails(device, "Disconnected")); // display the already present USB devices - for (var device : USB.getAllDevices()) + for (var device : Usb.getDevices()) printDetails(device, "Present"); // wait for ENTER to quit program @@ -31,7 +31,7 @@ public static void main(String[] args) throws IOException { System.in.read(); } - private static void printDetails(USBDevice device, String event) { + private static void printDetails(UsbDevice device, String event) { System.out.printf("%-14s", event + ":"); System.out.println(device.toString()); } diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index fe623b61..13ee51fe 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -19,7 +19,7 @@ net.codecrete.usb java-does-usb - 0.6.1 + 0.7.0-SNAPSHOT diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java index f5b12f88..c8b0d79f 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java @@ -11,7 +11,9 @@ import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; + +import static net.codecrete.usb.UsbRecipient.INTERFACE; +import static net.codecrete.usb.UsbRequestType.CLASS; /** * DFU device. @@ -21,7 +23,7 @@ */ public class DFUDevice { - private final USBDevice usbDevice_; + private final UsbDevice usbDevice_; private final int interfaceNumber_; private final int transferSize_; private final Version dfuVersion_; @@ -33,10 +35,10 @@ public class DFUDevice { * @return List of DFU devices */ public static List getAll() { - return USB.getAllDevices().stream() - .filter(DFUDevice::hasDFUDescriptor) + return Usb.findDevices(DFUDevice::hasDFUDescriptor) + .stream() .map(DFUDevice::new) - .collect(Collectors.toList()); + .toList(); } /** @@ -44,8 +46,8 @@ public static List getAll() { * @param device USB device * @return {@code true} if it has a DFU descriptor, {@code false} otherwise */ - public static boolean hasDFUDescriptor(USBDevice device) { - return getDFUDescriptorOffset(device.configurationDescriptor()) > 0 + public static boolean hasDFUDescriptor(UsbDevice device) { + return getDFUDescriptorOffset(device.getConfigurationDescriptor()) > 0 && getDFUInterfaceNumber(device) >= 0; } @@ -69,11 +71,11 @@ public static int getDFUDescriptorOffset(byte[] descriptor) { * @param device the USB device * @return the interface number, of -1 if not found */ - public static int getDFUInterfaceNumber(USBDevice device) { - for (var intf : device.interfaces()) { - var alt = intf.alternate(); - if (alt.classCode() == 0xFE && alt.subclassCode() == 0x01 && alt.protocolCode() == 0x02) - return intf.number(); + public static int getDFUInterfaceNumber(UsbDevice device) { + for (var intf : device.getInterfaces()) { + var alt = intf.getCurrentAlternate(); + if (alt.getClassCode() == 0xFE && alt.getSubclassCode() == 0x01 && alt.getProtocolCode() == 0x02) + return intf.getNumber(); } return -1; @@ -86,11 +88,11 @@ public static int getDFUInterfaceNumber(USBDevice device) { *

* @param usbDevice the USB device */ - public DFUDevice(USBDevice usbDevice) { + public DFUDevice(UsbDevice usbDevice) { usbDevice_ = usbDevice; interfaceNumber_ = getDFUInterfaceNumber(usbDevice); - var configDesc = usbDevice.configurationDescriptor(); + var configDesc = usbDevice.getConfigurationDescriptor(); int offset = getDFUDescriptorOffset(configDesc); assert offset > 0; @@ -111,7 +113,7 @@ public Version dfuVersion() { * @return the serial number */ public String serialNumber() { - return usbDevice_.serialNumber(); + return usbDevice_.getSerialNumber(); } /** @@ -135,7 +137,7 @@ public void close() { * Clears an error status. */ public void clearStatus() { - var setup = new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, DFURequest.CLEAR_STATUS.value(), 0, interfaceNumber_); + var setup = new UsbControlTransfer(CLASS, INTERFACE, DFURequest.CLEAR_STATUS.value(), 0, interfaceNumber_); usbDevice_.controlTransferOut(setup, null); } @@ -143,7 +145,7 @@ public void clearStatus() { * Aborts the download mode. */ public void abort() { - var setup = new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, DFURequest.ABORT.value(), 0, interfaceNumber_); + var setup = new UsbControlTransfer(CLASS, INTERFACE, DFURequest.ABORT.value(), 0, interfaceNumber_); usbDevice_.controlTransferOut(setup, null); } @@ -152,7 +154,7 @@ public void abort() { * @return the status */ public DFUStatus getStatus() { - var setup = new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, DFURequest.GET_STATUS.value(), 0, interfaceNumber_); + var setup = new UsbControlTransfer(CLASS, INTERFACE, DFURequest.GET_STATUS.value(), 0, interfaceNumber_); return DFUStatus.fromBytes(usbDevice_.controlTransferIn(setup, 6)); } @@ -176,7 +178,7 @@ public byte[] read(int address, int length) { int blockNum = 2; while (offset < length) { int chunkSize = Math.min(transferSize_, length - offset); - var setup = new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, DFURequest.UPLOAD.value(), blockNum, interfaceNumber_); + var setup = new UsbControlTransfer(CLASS, INTERFACE, DFURequest.UPLOAD.value(), blockNum, interfaceNumber_); var chunk = usbDevice_.controlTransferIn(setup, chunkSize); System.arraycopy(chunk, 0, result, offset, chunkSize); offset += chunkSize; @@ -184,7 +186,7 @@ public byte[] read(int address, int length) { } // request zero lenght chunk to exit out of upload mode - var setup = new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, DFURequest.UPLOAD.value(), blockNum, interfaceNumber_); + var setup = new UsbControlTransfer(CLASS, INTERFACE, DFURequest.UPLOAD.value(), blockNum, interfaceNumber_); usbDevice_.controlTransferIn(setup, 0); return result; @@ -223,7 +225,7 @@ public void download(byte[] firmware) { System.arraycopy(firmware, offset, chunk, 0, chunkSize); System.out.printf("Writing data at 0x%x (size 0x%x)%n", startAddress + offset, chunkSize); - var setup = new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, DFURequest.DOWNLOAD.value(), transaction, interfaceNumber_); + var setup = new UsbControlTransfer(CLASS, INTERFACE, DFURequest.DOWNLOAD.value(), transaction, interfaceNumber_); usbDevice_.controlTransferOut(setup, chunk); finishDownloadCommand("writing data"); @@ -272,7 +274,7 @@ public void setAddress(int address) { } private void execDownloadCommandWithAddress(byte command, String action, int address) { - var setup = new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, DFURequest.DOWNLOAD.value(), 0, interfaceNumber_); + var setup = new UsbControlTransfer(CLASS, INTERFACE, DFURequest.DOWNLOAD.value(), 0, interfaceNumber_); var data = new byte[] { command, (byte) address, @@ -325,7 +327,7 @@ private void exitDownloadMode() { public void startApplication() { expectState(DeviceState.DFU_IDLE, DeviceState.DFU_DNLOAD_IDLE); - var setup = new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, DFURequest.DOWNLOAD.value(), 2, interfaceNumber_); + var setup = new UsbControlTransfer(CLASS, INTERFACE, DFURequest.DOWNLOAD.value(), 2, interfaceNumber_); usbDevice_.controlTransferOut(setup, null); var status = getStatus(); @@ -359,6 +361,7 @@ private static void sleep(int millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { + Thread.currentThread().interrupt(); throw new DFUException("Sleep failed", e); } } diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/STM32.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/STM32.java index a157ca55..a9f40b57 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/STM32.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/STM32.java @@ -11,5 +11,8 @@ * STM32 specific constants */ public class STM32 { + + private STM32() { } + public static final int FLASH_BASE_ADDRESS = 0x08000000; } diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Segment.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Segment.java index eef8d1fc..740a845f 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Segment.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Segment.java @@ -7,15 +7,16 @@ package net.codecrete.usb.dfu; -import net.codecrete.usb.USBControlTransfer; -import net.codecrete.usb.USBDevice; -import net.codecrete.usb.USBRecipient; -import net.codecrete.usb.USBRequestType; +import net.codecrete.usb.UsbControlTransfer; +import net.codecrete.usb.UsbDevice; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import static net.codecrete.usb.UsbRecipient.DEVICE; +import static net.codecrete.usb.UsbRequestType.STANDARD; + /** * Represents a memory segment of the USB device, be it flash memory, RAM or any other type. */ @@ -27,12 +28,12 @@ public class Segment { * @param interfaceNumber the number of the DFU USB interface * @return list of segments */ - public static List getSegments(USBDevice device, int interfaceNumber) { + public static List getSegments(UsbDevice device, int interfaceNumber) { var result = new ArrayList(); // STM uses multiple alternate interface settings to represent segments. // The alternate interface settings name describes the sectors within the segment. - var configDesc = device.configurationDescriptor(); + var configDesc = device.getConfigurationDescriptor(); int offset = 0; while (offset < configDesc.length) { if (configDesc[offset + 1] == 4 && (configDesc[offset + 2] & 0xff) == interfaceNumber) { @@ -53,8 +54,8 @@ public static List getSegments(USBDevice device, int interfaceNumber) { * @param index the index of the string descriptor * @return the string */ - private static String getStringDescriptor(USBDevice device, int index) { - var setup = new USBControlTransfer(USBRequestType.STANDARD, USBRecipient.DEVICE, 6, (3 << 8) | index, 0); + private static String getStringDescriptor(UsbDevice device, int index) { + var setup = new UsbControlTransfer(STANDARD, DEVICE, 6, (3 << 8) | index, 0); byte[] stringDesc = device.controlTransferIn(setup, 255); int descLen = stringDesc[0] & 0xff; return new String(stringDesc, 2, descLen - 2, StandardCharsets.UTF_16LE); @@ -97,7 +98,7 @@ public static Page findPage(List segments, int address) { private Segment(int altSetting, String segmentDesc) { // The format is described in "UM0424 STM32 USB-FS-Device development kit", ch. 10.3.2 altSetting_ = altSetting; - sectors_ = new ArrayList(); + sectors_ = new ArrayList<>(); int offset = segmentDesc.indexOf('/', 1); name_ = segmentDesc.substring(1, offset).trim(); diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index ee8e73a8..99f2dea3 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 0.6.2-SNAPSHOT + 0.7.0-SNAPSHOT 21 @@ -137,6 +137,12 @@
+ + org.jetbrains + annotations + 24.0.1 + compile + org.junit.jupiter junit-jupiter diff --git a/java-does-usb/src/main/java/module-info.java b/java-does-usb/src/main/java/module-info.java index cf4daec9..496c87ec 100644 --- a/java-does-usb/src/main/java/module-info.java +++ b/java-does-usb/src/main/java/module-info.java @@ -9,5 +9,6 @@ * Java Does USB – work with USB devices */ module net.codecrete.usb { + requires org.jetbrains.annotations; exports net.codecrete.usb; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USB.java b/java-does-usb/src/main/java/net/codecrete/usb/Usb.java similarity index 64% rename from java-does-usb/src/main/java/net/codecrete/usb/USB.java rename to java-does-usb/src/main/java/net/codecrete/usb/Usb.java index 59564730..3c287303 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/Usb.java @@ -7,11 +7,16 @@ package net.codecrete.usb; -import net.codecrete.usb.common.USBDeviceRegistry; -import net.codecrete.usb.linux.LinuxUSBDeviceRegistry; -import net.codecrete.usb.macos.MacosUSBDeviceRegistry; -import net.codecrete.usb.windows.WindowsUSBDeviceRegistry; +import net.codecrete.usb.common.UsbDeviceRegistry; +import net.codecrete.usb.linux.LinuxUsbDeviceRegistry; +import net.codecrete.usb.macos.MacosUsbDeviceRegistry; +import net.codecrete.usb.windows.WindowsUsbDeviceRegistry; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Unmodifiable; +import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.function.Consumer; @@ -19,19 +24,19 @@ /** * Provides access to USB devices. */ -public class USB { +public class Usb { - private static USBDeviceRegistry createInstance() { + private static UsbDeviceRegistry createInstance() { var osName = System.getProperty("os.name"); var osArch = System.getProperty("os.arch"); - USBDeviceRegistry impl; + UsbDeviceRegistry impl; if (osName.equals("Mac OS X") && (osArch.equals("x86_64") || osArch.equals("aarch64"))) { - impl = new MacosUSBDeviceRegistry(); + impl = new MacosUsbDeviceRegistry(); } else if (osName.startsWith("Windows") && osArch.equals("amd64")) { - impl = new WindowsUSBDeviceRegistry(); + impl = new WindowsUsbDeviceRegistry(); } else if (osName.equals("Linux") && (osArch.equals("amd64") || osArch.equals("aarch64"))) { - impl = new LinuxUSBDeviceRegistry(); + impl = new LinuxUsbDeviceRegistry(); } else { throw new UnsupportedOperationException(String.format( "Java Does USB has no implementation for architecture %s/%s", @@ -40,9 +45,9 @@ private static USBDeviceRegistry createInstance() { return impl; } - private static USBDeviceRegistry singletonInstance = null; + private static UsbDeviceRegistry singletonInstance = null; - private static synchronized USBDeviceRegistry instance() { + private static synchronized UsbDeviceRegistry instance() { if (singletonInstance == null) { singletonInstance = createInstance(); singletonInstance.start(); @@ -51,7 +56,7 @@ private static synchronized USBDeviceRegistry instance() { } // Private, so no instance can be created - private USB() { + private Usb() { } /** @@ -64,8 +69,8 @@ private USB() { * * @return list of USB devices */ - public static List getAllDevices() { - return instance().getAllDevices(); + public static @NotNull @Unmodifiable Collection getDevices() { + return Collections.unmodifiableCollection(instance().getAllDevices()); } /** @@ -74,7 +79,7 @@ public static List getAllDevices() { * @param predicate device predicate * @return list of USB devices */ - public static List getDevices(USBDevicePredicate predicate) { + public static @NotNull @Unmodifiable List findDevices(@NotNull UsbDevicePredicate predicate) { return instance().getAllDevices().stream().filter(predicate::matches).toList(); } @@ -84,7 +89,7 @@ public static List getDevices(USBDevicePredicate predicate) { * @param predicate device predicate * @return optional USB device */ - public static Optional getDevice(USBDevicePredicate predicate) { + public static Optional findDevice(@NotNull UsbDevicePredicate predicate) { return instance().getAllDevices().stream().filter(predicate::matches).findFirst(); } @@ -95,8 +100,8 @@ public static Optional getDevice(USBDevicePredicate predicate) { * @param productId product ID * @return optional USB device */ - public static Optional getDevice(int vendorId, int productId) { - return getDevice(device -> device.vendorId() == vendorId && device.productId() == productId); + public static Optional findDevice(int vendorId, int productId) { + return findDevice(device -> device.getVendorId() == vendorId && device.getProductId() == productId); } /** @@ -104,21 +109,21 @@ public static Optional getDevice(int vendorId, int productId) { * * @param handler handler function, or {@code null} to remove a previous handler */ - public static void setOnDeviceConnected(Consumer handler) { + public static void setOnDeviceConnected(@Nullable Consumer handler) { instance().setOnDeviceConnected(handler); } /** * Sets the handler to be called when a USB device is disconnected. *

- * When the handler is called, the {@link USBDevice} instance has already been closed. + * When the handler is called, the {@link UsbDevice} instance has already been closed. * Descriptive information (such as vendor and product ID, serial number, interfaces, endpoints) * can still be accessed. *

* * @param handler handler function, or {@code null} to remove a previous handler */ - public static void setOnDeviceDisconnected(Consumer handler) { + public static void setOnDeviceDisconnected(@Nullable Consumer handler) { instance().setOnDeviceDisconnected(handler); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbAlternateInterface.java similarity index 74% rename from java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java rename to java-does-usb/src/main/java/net/codecrete/usb/UsbAlternateInterface.java index b0445f9c..68d3bcff 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBAlternateInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbAlternateInterface.java @@ -7,6 +7,9 @@ package net.codecrete.usb; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Unmodifiable; + import java.util.List; /** @@ -15,7 +18,7 @@ * Instances of this class describe an alternate setting of a USB interface. *

*/ -public interface USBAlternateInterface { +public interface UsbAlternateInterface { /** * Gets the alternate setting number. @@ -24,7 +27,7 @@ public interface USBAlternateInterface { * * @return the alternate setting number */ - int number(); + int getNumber(); /** * Gets the interface class. @@ -34,7 +37,7 @@ public interface USBAlternateInterface { * * @return the interface class */ - int classCode(); + int getClassCode(); /** * Gets the interface subclass. @@ -44,7 +47,7 @@ public interface USBAlternateInterface { * * @return the interface subclass */ - int subclassCode(); + int getSubclassCode(); /** * Gets the interface protocol. @@ -54,7 +57,7 @@ public interface USBAlternateInterface { * * @return the interface protocol */ - int protocolCode(); + int getProtocolCode(); /** * Gets the endpoints of this alternate interface settings. @@ -62,18 +65,22 @@ public interface USBAlternateInterface { * The endpoint list does not include endpoint 0, which * is always available and reserved for control transfers. *

+ *

+ * The returned list is sorted by endpoint number. + *

* * @return a list of endpoints. */ - List endpoints(); + @NotNull @Unmodifiable List getEndpoints(); /** * Gets the endpoint with the specified number and direction. * * @param endpointNumber endpoint number (in the range between 1 and 127, without the direction bit) * @param direction endpoint direction - * @return the endpoint, or {@code null} if no endpoint with the given number and direction exists + * @return the endpoint + * @exception UsbException if the endpoint does not exist */ - USBEndpoint getEndpoint(int endpointNumber, USBDirection direction); + @NotNull UsbEndpoint getEndpoint(int endpointNumber, UsbDirection direction); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbControlTransfer.java similarity index 90% rename from java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java rename to java-does-usb/src/main/java/net/codecrete/usb/UsbControlTransfer.java index ef937118..60089114 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBControlTransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbControlTransfer.java @@ -24,9 +24,9 @@ * @param value value (value between 0 and 65535, called {@code wValue} in USB specification) * @param index index (value between 0 and 65535, called {@code wIndex} in USB specification). */ -public record USBControlTransfer( - USBRequestType requestType, - USBRecipient recipient, +public record UsbControlTransfer( + UsbRequestType requestType, + UsbRecipient recipient, int request, int value, int index diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbDevice.java similarity index 86% rename from java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java rename to java-does-usb/src/main/java/net/codecrete/usb/UsbDevice.java index 67837476..acf03748 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbDevice.java @@ -7,6 +7,9 @@ package net.codecrete.usb; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Unmodifiable; + import java.io.InputStream; import java.io.OutputStream; import java.util.List; @@ -23,35 +26,35 @@ * closed state. *

*/ -public interface USBDevice { +public interface UsbDevice { /** * USB product ID. * * @return product ID */ - int productId(); + int getProductId(); /** * USB vendor ID. * * @return vendor ID */ - int vendorId(); + int getVendorId(); /** * Product name. * * @return product name or {@code null} if not provided by the device */ - String product(); + String getProduct(); /** * Manufacturer name * * @return manufacturer name or {@code null} if not provided by the device */ - String manufacturer(); + String getManufacturer(); /** * Serial number @@ -62,42 +65,42 @@ public interface USBDevice { * * @return serial number or {@code null} if not provided by the device */ - String serialNumber(); + String getSerialNumber(); /** * USB device class code ({@code bDeviceClass} from device descriptor). * * @return class code */ - int classCode(); + int getClassCode(); /** * USB device subclass code ({@code bDeviceSubClass} from device descriptor). * * @return subclass code */ - int subclassCode(); + int getSubclassCode(); /** * USB device protocol ({@code bDeviceProtocol} from device descriptor). * * @return protocol code */ - int protocolCode(); + int getProtocolCode(); /** * USB protocol version supported by this device. * * @return version */ - Version usbVersion(); + @NotNull Version getUsbVersion(); /** * Device version (as declared by the manufacturer). * * @return version */ - Version deviceVersion(); + @NotNull Version getDeviceVersion(); /** * Detaches the standard operating-system drivers of this device. @@ -159,7 +162,7 @@ public interface USBDevice { * * @return {@code true} if the device is open, {@code false} if it is closed. */ - boolean isOpen(); + boolean isOpened(); /** * Closes the device. @@ -168,27 +171,32 @@ public interface USBDevice { /** * Gets the interfaces of this device. + *

+ * The returned list is sorted by interface number. + *

* * @return a list of USB interfaces */ - List interfaces(); + @NotNull @Unmodifiable List getInterfaces(); /** * Gets the interface with the specified number. * * @param interfaceNumber the interface number - * @return the interface, or {@code null} if no interface with the given number exists + * @return the interface + * @exception UsbException if the interface does not exist */ - USBInterface getInterface(int interfaceNumber); + @NotNull UsbInterface getInterface(int interfaceNumber); /** * Gets the endpoint with the specified number. * * @param direction the endpoint direction * @param endpointNumber the endpoint number (between 1 and 127) - * @return the endpoint, or {@code null} if no endpoint with the given direction and number exists + * @return the endpoint + * @exception UsbException if the endpoint does not exist */ - USBEndpoint getEndpoint(USBDirection direction, int endpointNumber); + @NotNull UsbEndpoint getEndpoint(UsbDirection direction, int endpointNumber); /** * Claims the specified interface for exclusive use. @@ -231,11 +239,11 @@ public interface USBDevice { * or the interface of the addressed endpoint must have been claimed. *

* - * @param setup control transfer setup parameters + * @param transfer control transfer setup parameters * @param length maximum length of expected data * @return received data. */ - byte[] controlTransferIn(USBControlTransfer setup, int length); + byte @NotNull [] controlTransferIn(@NotNull UsbControlTransfer transfer, int length); /** * Executes a control transfer request and optionally sends data. @@ -253,10 +261,10 @@ public interface USBDevice { * or the interface of the addressed endpoint must have been claimed. *

* - * @param setup control transfer setup parameters + * @param transfer control transfer setup parameters * @param data data to send, or {@code null} if the transfer has no data stage. */ - void controlTransferOut(USBControlTransfer setup, byte[] data); + void controlTransferOut(@NotNull UsbControlTransfer transfer, byte[] data); /** * Sends data to this device. @@ -275,13 +283,13 @@ public interface USBDevice { * @param endpointNumber endpoint number (in the range between 1 and 127) * @param data data to send */ - void transferOut(int endpointNumber, byte[] data); + void transferOut(int endpointNumber, byte @NotNull [] data); /** * Sends data to this device. *

* This method blocks until the data has been sent, the timeout period has expired - * or an error has occurred. If the timeout expires, a {@link USBTimeoutException} is thrown. + * or an error has occurred. If the timeout expires, a {@link UsbTimeoutException} is thrown. *

*

* This method can send data to bulk and interrupt endpoints. @@ -296,13 +304,13 @@ public interface USBDevice { * @param data data to send * @param timeout the timeout period, in milliseconds (0 for no timeout) */ - void transferOut(int endpointNumber, byte[] data, int timeout); + void transferOut(int endpointNumber, byte @NotNull [] data, int timeout); /** * Sends data to this device. *

* This method blocks until the data has been sent, the timeout period has expired - * or an error has occurred. If the timeout expires, a {@link USBTimeoutException} is thrown. + * or an error has occurred. If the timeout expires, a {@link UsbTimeoutException} is thrown. *

*

* This method can send data to bulk and interrupt endpoints. @@ -319,7 +327,7 @@ public interface USBDevice { * @param length number of bytes to send * @param timeout the timeout period, in milliseconds (0 for no timeout) */ - void transferOut(int endpointNumber, byte[] data, int offset, int length, int timeout); + void transferOut(int endpointNumber, byte @NotNull [] data, int offset, int length, int timeout); /** * Receives data from this device. @@ -337,13 +345,13 @@ public interface USBDevice { * @param endpointNumber endpoint number (in the range between 1 and 127, i.e. without the direction bit) * @return received data */ - byte[] transferIn(int endpointNumber); + byte @NotNull [] transferIn(int endpointNumber); /** * Receives data from this device. *

* This method blocks until at least a packet has been received, the timeout period has expired - * or an error has occurred. If the timeout expired, a {@link USBTimeoutException} is thrown. + * or an error has occurred. If the timeout expired, a {@link UsbTimeoutException} is thrown. *

*

* The returned data is the payload of a packet. It can have a length of 0 if the USB device @@ -357,7 +365,7 @@ public interface USBDevice { * @param timeout the timeout period, in milliseconds (0 for no timeout) * @return received data */ - byte[] transferIn(int endpointNumber, int timeout); + byte @NotNull [] transferIn(int endpointNumber, int timeout); /** * Opens a new output stream to send data to a bulk endpoint. @@ -378,7 +386,7 @@ public interface USBDevice { * @param bufferSize approximate buffer size (in bytes) * @return the new output stream */ - OutputStream openOutputStream(int endpointNumber, int bufferSize); + @NotNull OutputStream openOutputStream(int endpointNumber, int bufferSize); /** * Opens a new output stream to send data to a bulk endpoint. @@ -389,7 +397,7 @@ public interface USBDevice { * @param endpointNumber bulk endpoint number (in the range between 1 and 127) * @return the new output stream */ - default OutputStream openOutputStream(int endpointNumber) { + default @NotNull OutputStream openOutputStream(int endpointNumber) { return openOutputStream(endpointNumber, 1); } @@ -409,7 +417,7 @@ default OutputStream openOutputStream(int endpointNumber) { * @param bufferSize approximate buffer size (in bytes) * @return the new input stream */ - InputStream openInputStream(int endpointNumber, int bufferSize); + @NotNull InputStream openInputStream(int endpointNumber, int bufferSize); /** * Opens a new input stream to receive data from a bulk endpoint. @@ -421,7 +429,7 @@ default OutputStream openOutputStream(int endpointNumber) { * @param endpointNumber bulk endpoint number (in the range between 1 and 127, i.e. without the direction bit) * @return the new input stream */ - default InputStream openInputStream(int endpointNumber) { + default @NotNull InputStream openInputStream(int endpointNumber) { return openInputStream(endpointNumber, 1); } @@ -434,7 +442,7 @@ default InputStream openInputStream(int endpointNumber) { * @param direction endpoint direction * @param endpointNumber endpoint number (in the range between 1 and 127) */ - void abortTransfers(USBDirection direction, int endpointNumber); + void abortTransfers(UsbDirection direction, int endpointNumber); /** * Clears an endpoint's halt condition. @@ -450,19 +458,19 @@ default InputStream openInputStream(int endpointNumber) { * @param direction endpoint direction * @param endpointNumber endpoint number (in the range between 1 and 127) */ - void clearHalt(USBDirection direction, int endpointNumber); + void clearHalt(UsbDirection direction, int endpointNumber); /** * Gets the device descriptor. * * @return the device descriptor (as a byte array) */ - byte[] deviceDescriptor(); + byte @NotNull [] getDeviceDescriptor(); /** * Gets the configuration descriptor. * * @return the configuration descriptor (as a byte array) */ - byte[] configurationDescriptor(); + byte @NotNull [] getConfigurationDescriptor(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDevicePredicate.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbDevicePredicate.java similarity index 78% rename from java-does-usb/src/main/java/net/codecrete/usb/USBDevicePredicate.java rename to java-does-usb/src/main/java/net/codecrete/usb/UsbDevicePredicate.java index 6b1b773b..609db9b4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDevicePredicate.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbDevicePredicate.java @@ -7,23 +7,25 @@ package net.codecrete.usb; +import org.jetbrains.annotations.NotNull; + import java.util.List; /** * Represents a predicate (boolean-valued function) of one argument, evaluated for a given USB device. *

- * This is a functional interface whose functional method is {@link #matches(USBDevice)}. + * This is a functional interface whose functional method is {@link #matches(UsbDevice)}. *

*/ @FunctionalInterface -public interface USBDevicePredicate { +public interface UsbDevicePredicate { /** * Evaluates this predicate on the given USB device. * * @param device the USB device * @return {@code true} of the devices matches the predicate, otherwise {@code false} */ - boolean matches(USBDevice device); + boolean matches(@NotNull UsbDevice device); /** * Test if the USB devices matches any of the filter conditions. @@ -32,7 +34,7 @@ public interface USBDevicePredicate { * @param predicates a list of filter predicates * @return {@code true} if it matches, {@code false} otherwise */ - static boolean matchesAny(USBDevice device, List predicates) { + static boolean matchesAny(@NotNull UsbDevice device, @NotNull List predicates) { return predicates.stream().anyMatch(predicate -> predicate.matches(device)); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBDirection.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbDirection.java similarity index 92% rename from java-does-usb/src/main/java/net/codecrete/usb/USBDirection.java rename to java-does-usb/src/main/java/net/codecrete/usb/UsbDirection.java index 8e2e7981..8e561dc4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBDirection.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbDirection.java @@ -10,7 +10,7 @@ /** * USB endpoint data direction enumeration. */ -public enum USBDirection { +public enum UsbDirection { /** * Direction OUT (host to device) */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBEndpoint.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbEndpoint.java similarity index 87% rename from java-does-usb/src/main/java/net/codecrete/usb/USBEndpoint.java rename to java-does-usb/src/main/java/net/codecrete/usb/UsbEndpoint.java index 434e0d34..1cebc06b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBEndpoint.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbEndpoint.java @@ -13,7 +13,7 @@ * Instances of this class describe a USB endpoint. *

*/ -public interface USBEndpoint { +public interface UsbEndpoint { /** * Gets the USB endpoint number. @@ -24,12 +24,12 @@ public interface USBEndpoint { *

*

* Use this number when calling any of the transfer methods of a - * {@link USBDevice} instance. + * {@link UsbDevice} instance. *

* * @return the endpoint number */ - int number(); + int getNumber(); /** * Gets the direction of the endpoint. @@ -40,14 +40,14 @@ public interface USBEndpoint { * * @return the direction */ - USBDirection direction(); + UsbDirection getDirection(); /** * Gets the USB endpoint transfer type. * * @return the transfer type */ - USBTransferType transferType(); + UsbTransferType getTransferType(); /** * Gets the packet size. @@ -58,5 +58,5 @@ public interface USBEndpoint { * * @return the packet size, in bytes. */ - int packetSize(); + int getPacketSize(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBException.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbException.java similarity index 74% rename from java-does-usb/src/main/java/net/codecrete/usb/USBException.java rename to java-does-usb/src/main/java/net/codecrete/usb/UsbException.java index dacc902a..e0c62acb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbException.java @@ -7,10 +7,13 @@ package net.codecrete.usb; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + /** * USB exception, thrown if an operation with USB devices fails. */ -public class USBException extends RuntimeException { +public class UsbException extends RuntimeException { /** * Error code. @@ -22,7 +25,7 @@ public class USBException extends RuntimeException { * * @param message the message */ - public USBException(String message) { + public UsbException(@NotNull String message) { super(message); code = -1; } @@ -33,7 +36,7 @@ public USBException(String message) { * @param message the message * @param errorCode the error code */ - public USBException(String message, int errorCode) { + public UsbException(@NotNull String message, int errorCode) { super(message + " (error code: " + errorCode + ")"); code = errorCode; } @@ -44,7 +47,7 @@ public USBException(String message, int errorCode) { * @param message the message * @param cause the causal exception */ - public USBException(String message, Throwable cause) { + public UsbException(@NotNull String message, @Nullable Throwable cause) { super(message, cause); code = -1; } @@ -54,7 +57,7 @@ public USBException(String message, Throwable cause) { * * @return the error code */ - public int errorCode() { + public int getErrorCode() { return code; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbInterface.java similarity index 66% rename from java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java rename to java-does-usb/src/main/java/net/codecrete/usb/UsbInterface.java index 8f63c649..372ebfd1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbInterface.java @@ -7,6 +7,9 @@ package net.codecrete.usb; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Unmodifiable; + import java.util.List; /** @@ -15,7 +18,7 @@ * Instances of this class describe an interface of a USB device. *

*/ -public interface USBInterface { +public interface UsbInterface { /** * Gets the interface number. @@ -25,10 +28,10 @@ public interface USBInterface { * * @return the interface number */ - int number(); + int getNumber(); /** - * Indicates if this interface is currently claimed for exclusive access. + * Indicates if this interface has been claimed by this program for exclusive access. * * @return {@code true} if it is claimed, {@code false} otherwise. */ @@ -42,20 +45,24 @@ public interface USBInterface { * * @return the alternate interface setting. */ - USBAlternateInterface alternate(); + @NotNull UsbAlternateInterface getCurrentAlternate(); /** * Gets the alternate interface settings with the specified number. * * @param alternateNumber alternate setting number * @return alternate interface setting + * @throws UsbException if the alternate setting does not exist */ - USBAlternateInterface getAlternate(int alternateNumber); + @NotNull UsbAlternateInterface getAlternate(int alternateNumber); /** * Gets all alternate settings of this interface. + *

+ * The returned list is sorted by alternate setting number. + *

* * @return a list of the alternate settings */ - List alternates(); + @NotNull @Unmodifiable List getAlternates(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBRecipient.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbRecipient.java similarity index 93% rename from java-does-usb/src/main/java/net/codecrete/usb/USBRecipient.java rename to java-does-usb/src/main/java/net/codecrete/usb/UsbRecipient.java index 250238a2..756027a2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBRecipient.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbRecipient.java @@ -10,7 +10,7 @@ /** * USB control transfer recipient enumeration. */ -public enum USBRecipient { +public enum UsbRecipient { /** * USB device */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBRequestType.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbRequestType.java similarity index 93% rename from java-does-usb/src/main/java/net/codecrete/usb/USBRequestType.java rename to java-does-usb/src/main/java/net/codecrete/usb/UsbRequestType.java index 05ede7e6..08dec0d6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBRequestType.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbRequestType.java @@ -10,7 +10,7 @@ /** * USB control transfer request type enumeration. */ -public enum USBRequestType { +public enum UsbRequestType { /** * Standard request type */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBStallException.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbStallException.java similarity index 73% rename from java-does-usb/src/main/java/net/codecrete/usb/USBStallException.java rename to java-does-usb/src/main/java/net/codecrete/usb/UsbStallException.java index 2b986a23..b6b7ed46 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBStallException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbStallException.java @@ -7,24 +7,26 @@ package net.codecrete.usb; +import org.jetbrains.annotations.NotNull; + /** * Exception thrown if a communication on a USB endpoint failed. *

* If a USB endpoint stalls, it is halted and the halt condition must be cleared - * using {@link USBDevice#clearHalt(USBDirection, int)} before communication can resume. + * using {@link UsbDevice#clearHalt(UsbDirection, int)} before communication can resume. *

*

* If the control endpoint 0 stalls, it throws this exception but is not halted. *

*/ -public class USBStallException extends USBException { +public class UsbStallException extends UsbException { /** * Creates a new instance with a message. * * @param message the message */ - public USBStallException(String message) { + public UsbStallException(@NotNull String message) { super(message); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBTimeoutException.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbTimeoutException.java similarity index 69% rename from java-does-usb/src/main/java/net/codecrete/usb/USBTimeoutException.java rename to java-does-usb/src/main/java/net/codecrete/usb/UsbTimeoutException.java index 3b18558f..28ae2f72 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBTimeoutException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbTimeoutException.java @@ -7,17 +7,19 @@ package net.codecrete.usb; +import org.jetbrains.annotations.NotNull; + /** * Exception thrown if a USB operation times out. */ -public class USBTimeoutException extends USBException { +public class UsbTimeoutException extends UsbException { /** * Creates a new instance with a message. * * @param message the message */ - public USBTimeoutException(String message) { + public UsbTimeoutException(@NotNull String message) { super(message); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/USBTransferType.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbTransferType.java similarity index 93% rename from java-does-usb/src/main/java/net/codecrete/usb/USBTransferType.java rename to java-does-usb/src/main/java/net/codecrete/usb/UsbTransferType.java index bfeaa0c0..f08a2e40 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/USBTransferType.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbTransferType.java @@ -10,7 +10,7 @@ /** * USB endpoint transfer type enumeration. */ -public enum USBTransferType { +public enum UsbTransferType { /** * Control transfer */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/Version.java b/java-does-usb/src/main/java/net/codecrete/usb/Version.java index 106d7b74..f9722ef8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/Version.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/Version.java @@ -34,7 +34,7 @@ public Version(int bcdVersion) { * * @return major version */ - public int major() { + public int getMajor() { return bcdVersion >> 8; } @@ -43,7 +43,7 @@ public int major() { * * @return minor version */ - public int minor() { + public int getMinor() { return (bcdVersion >> 4) & 0x0f; } @@ -52,13 +52,13 @@ public int minor() { * * @return subminor version */ - public int subminor() { + public int getSubminor() { return bcdVersion & 0x0f; } @Override public String toString() { - return String.format("%d.%d.%d", major(), minor(), subminor()); + return String.format("%d.%d.%d", getMajor(), getMinor(), getSubminor()); } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java b/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java index e1ad6992..87c54a71 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java @@ -7,7 +7,7 @@ package net.codecrete.usb.common; -import net.codecrete.usb.USBInterface; +import net.codecrete.usb.UsbInterface; import java.util.ArrayList; import java.util.List; @@ -17,7 +17,7 @@ */ public class Configuration { private final List functionList; - private final List interfaceList; + private final List interfaceList; private final int configurationValue; private final int configurationAttributes; private final int configurationMaxPower; @@ -42,7 +42,7 @@ public int maxPower() { return configurationMaxPower; } - public List interfaces() { + public List interfaces() { return interfaceList; } @@ -50,12 +50,12 @@ public List functions() { return functionList; } - public void addInterface(USBInterface intf) { + public void addInterface(UsbInterface intf) { interfaceList.add(intf); } - public USBInterfaceImpl findInterfaceByNumber(int number) { - return (USBInterfaceImpl) interfaceList.stream().filter(intf -> intf.number() == number).findFirst().orElse(null); + public UsbInterfaceImpl findInterfaceByNumber(int number) { + return (UsbInterfaceImpl) interfaceList.stream().filter(intf -> intf.getNumber() == number).findFirst().orElse(null); } public void addFunction(CompositeFunction function) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java index 7df741f6..31b8298e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java @@ -7,10 +7,10 @@ package net.codecrete.usb.common; -import net.codecrete.usb.USBAlternateInterface; -import net.codecrete.usb.USBDirection; -import net.codecrete.usb.USBException; -import net.codecrete.usb.USBTransferType; +import net.codecrete.usb.UsbAlternateInterface; +import net.codecrete.usb.UsbDirection; +import net.codecrete.usb.UsbException; +import net.codecrete.usb.UsbTransferType; import net.codecrete.usb.usbstandard.ConfigurationDescriptor; import net.codecrete.usb.usbstandard.EndpointDescriptor; import net.codecrete.usb.usbstandard.InterfaceAssociationDescriptor; @@ -58,7 +58,7 @@ public ConfigurationParser(MemorySegment descriptor) { public Configuration parse() { parseHeader(); - USBAlternateInterfaceImpl lastAlternate = null; + UsbAlternateInterfaceImpl lastAlternate = null; var offset = peekDescLength(0); while (offset < descriptor.byteSize()) { @@ -69,18 +69,18 @@ public Configuration parse() { if (descType == INTERFACE_DESCRIPTOR_TYPE) { var intf = parseInterface(offset); - var parent = configuration.findInterfaceByNumber(intf.number()); + var parent = configuration.findInterfaceByNumber(intf.getNumber()); if (parent != null) { - parent.addAlternate(intf.alternate()); + parent.addAlternate(intf.getCurrentAlternate()); } else { configuration.addInterface(intf); } - lastAlternate = (USBAlternateInterfaceImpl) intf.alternate(); + lastAlternate = (UsbAlternateInterfaceImpl) intf.getCurrentAlternate(); - var function = configuration.findFunction(intf.number()); + var function = configuration.findFunction(intf.getNumber()); if (function == null) { - function = new CompositeFunction(intf.number(), 1, lastAlternate.classCode(), - lastAlternate.subclassCode(), lastAlternate.protocolCode()); + function = new CompositeFunction(intf.getNumber(), 1, lastAlternate.getClassCode(), + lastAlternate.getSubclassCode(), lastAlternate.getProtocolCode()); configuration.addFunction(function); } @@ -102,22 +102,22 @@ public Configuration parse() { private void parseHeader() { var desc = new ConfigurationDescriptor(descriptor); if (CONFIGURATION_DESCRIPTOR_TYPE != desc.descriptorType()) - throw new USBException("invalid USB configuration descriptor"); + throw new UsbException("invalid USB configuration descriptor"); var totalLength = desc.totalLength(); if (descriptor.byteSize() != totalLength) - throw new USBException("invalid USB configuration descriptor (invalid length)"); + throw new UsbException("invalid USB configuration descriptor (invalid length)"); configuration = new Configuration(desc.configurationValue(), desc.attributes(), desc.maxPower()); } - private USBInterfaceImpl parseInterface(int offset) { + private UsbInterfaceImpl parseInterface(int offset) { var desc = new InterfaceDescriptor(descriptor, offset); - var alternate = new USBAlternateInterfaceImpl(desc.alternateSetting(), desc.interfaceClass(), + var alternate = new UsbAlternateInterfaceImpl(desc.alternateSetting(), desc.interfaceClass(), desc.interfaceSubClass(), desc.interfaceProtocol(), new ArrayList<>()); - var alternates = new ArrayList(); + var alternates = new ArrayList(); alternates.add(alternate); - return new USBInterfaceImpl(desc.interfaceNumber(), alternates); + return new UsbInterfaceImpl(desc.interfaceNumber(), alternates); } private void parseIAD(int offset) { @@ -127,26 +127,26 @@ private void parseIAD(int offset) { configuration.addFunction(function); } - private USBEndpointImpl parseEndpoint(int offset) { + private UsbEndpointImpl parseEndpoint(int offset) { var desc = new EndpointDescriptor(descriptor, offset); var address = desc.endpointAddress(); - return new USBEndpointImpl(getEndpointNumber(address), getEndpointDirection(address), + return new UsbEndpointImpl(getEndpointNumber(address), getEndpointDirection(address), getEndpointType(desc.attributes()), desc.maxPacketSize()); } - private static USBDirection getEndpointDirection(int address) { - return (address & 0x80) != 0 ? USBDirection.IN : USBDirection.OUT; + private static UsbDirection getEndpointDirection(int address) { + return (address & 0x80) != 0 ? UsbDirection.IN : UsbDirection.OUT; } private static int getEndpointNumber(int address) { return address & 0x7f; } - private static USBTransferType getEndpointType(int attributes) { + private static UsbTransferType getEndpointType(int attributes) { return switch (attributes & 0x3) { - case 1 -> USBTransferType.ISOCHRONOUS; - case 2 -> USBTransferType.BULK; - case 3 -> USBTransferType.INTERRUPT; + case 1 -> UsbTransferType.ISOCHRONOUS; + case 2 -> UsbTransferType.BULK; + case 3 -> UsbTransferType.INTERRUPT; default -> null; }; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index 7e00f1fb..5db3fb49 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -7,8 +7,9 @@ package net.codecrete.usb.common; -import net.codecrete.usb.USBDirection; -import net.codecrete.usb.USBException; +import net.codecrete.usb.UsbDirection; +import net.codecrete.usb.UsbException; +import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.io.InputStream; @@ -35,7 +36,7 @@ */ public abstract class EndpointInputStream extends InputStream { - protected USBDeviceImpl device; + protected UsbDeviceImpl device; protected final int endpointNumber; // Arena to allocate buffers and completion handlers protected final Arena arena; @@ -58,12 +59,12 @@ public abstract class EndpointInputStream extends InputStream { * @param endpointNumber endpoint number * @param bufferSize approximate buffer size (in bytes) */ - protected EndpointInputStream(USBDeviceImpl device, int endpointNumber, int bufferSize) { + protected EndpointInputStream(UsbDeviceImpl device, int endpointNumber, int bufferSize) { this.device = device; this.endpointNumber = endpointNumber; arena = Arena.ofShared(); - var packetSize = device.getEndpoint(USBDirection.IN, endpointNumber).packetSize(); + var packetSize = device.getEndpoint(UsbDirection.IN, endpointNumber).getPacketSize(); // use between 4 and 32 packets per transfer (256B to 2KB for FS, 2KB to 16KB for HS) var numPacketsPerTransfer = (int) Math.round(Math.sqrt((double) bufferSize / packetSize)); @@ -109,9 +110,9 @@ public void close() throws IOException { // abort all transfers on endpoint try { - device.abortTransfers(USBDirection.IN, endpointNumber); + device.abortTransfers(UsbDirection.IN, endpointNumber); - } catch (USBException e) { + } catch (UsbException e) { // If aborting the transfer is not possible, the device has // likely been closed or unplugged. So all outstanding // transfers will terminate anyway. @@ -135,7 +136,7 @@ public int read() throws IOException { } @Override - public int read(byte[] b, int off, int len) throws IOException { + public int read(byte @NotNull [] b, int off, int len) throws IOException { if (isClosed()) return -1; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java index 0a8c7f82..3fb6dc83 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -7,7 +7,8 @@ package net.codecrete.usb.common; -import net.codecrete.usb.USBDirection; +import net.codecrete.usb.UsbDirection; +import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.io.OutputStream; @@ -37,7 +38,7 @@ */ public abstract class EndpointOutputStream extends OutputStream { - protected USBDeviceImpl device; + protected UsbDeviceImpl device; protected final int endpointNumber; protected final Arena arena; // Endpoint packet size @@ -60,12 +61,12 @@ public abstract class EndpointOutputStream extends OutputStream { * @param endpointNumber endpoint number * @param bufferSize approximate buffer size (in bytes) */ - protected EndpointOutputStream(USBDeviceImpl device, int endpointNumber, int bufferSize) { + protected EndpointOutputStream(UsbDeviceImpl device, int endpointNumber, int bufferSize) { this.device = device; this.endpointNumber = endpointNumber; arena = Arena.ofShared(); - packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize(); + packetSize = device.getEndpoint(UsbDirection.OUT, endpointNumber).getPacketSize(); // use between 4 and 32 packets per transfer (256B to 2KB for FS, 2KB to 16KB for HS) var numPacketsPerTransfer = (int) Math.round(Math.sqrt((double) bufferSize / packetSize)); @@ -124,7 +125,7 @@ public void write(int b) throws IOException { } @Override - public void write(byte[] b, int off, int len) throws IOException { + public void write(byte @NotNull [] b, int off, int len) throws IOException { checkIsOpen(); while (len > 0) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java deleted file mode 100644 index 401ba45e..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBAlternateInterfaceImpl.java +++ /dev/null @@ -1,68 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.common; - -import net.codecrete.usb.USBAlternateInterface; -import net.codecrete.usb.USBDirection; -import net.codecrete.usb.USBEndpoint; - -import java.util.List; - -import static java.util.Collections.unmodifiableList; - -public class USBAlternateInterfaceImpl implements USBAlternateInterface { - - private final int alternateInterfaceNumber; - private final int alternateInterfaceClass; - private final int alternateInterfaceSubclass; - private final int alternateInterfaceProtocol; - private final List endpointList; - - public USBAlternateInterfaceImpl(int number, int classCode, int subclassCode, int protocolCode, - List endpoints) { - alternateInterfaceNumber = number; - alternateInterfaceClass = classCode; - alternateInterfaceSubclass = subclassCode; - alternateInterfaceProtocol = protocolCode; - endpointList = endpoints; - } - - @Override - public int number() { - return alternateInterfaceNumber; - } - - @Override - public int classCode() { - return alternateInterfaceClass; - } - - @Override - public int subclassCode() { - return alternateInterfaceSubclass; - } - - @Override - public int protocolCode() { - return alternateInterfaceProtocol; - } - - @Override - public List endpoints() { - return unmodifiableList(endpointList); - } - - void addEndpoint(USBEndpoint endpoint) { - endpointList.add(endpoint); - } - - @Override - public USBEndpoint getEndpoint(int endpointNumber, USBDirection direction) { - return endpointList.stream().filter(ep -> ep.number() == endpointNumber && ep.direction() == direction).findFirst().orElse(null); - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java deleted file mode 100644 index 07234665..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBInterfaceImpl.java +++ /dev/null @@ -1,66 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.common; - -import net.codecrete.usb.USBAlternateInterface; -import net.codecrete.usb.USBInterface; - -import java.util.Collections; -import java.util.List; - -public class USBInterfaceImpl implements USBInterface { - - private final int interfaceNumber; - private USBAlternateInterface currentAlternate; - private final List alternateInterfaces; - - private boolean claimed; - - public USBInterfaceImpl(int number, List alternates) { - interfaceNumber = number; - alternateInterfaces = alternates; - currentAlternate = alternates.get(0); - } - - @Override - public int number() { - return interfaceNumber; - } - - @Override - public boolean isClaimed() { - return claimed; - } - - public void setClaimed(boolean claimed) { - this.claimed = claimed; - } - - @Override - public USBAlternateInterface alternate() { - return currentAlternate; - } - - @Override - public USBAlternateInterface getAlternate(int alternateNumber) { - return alternateInterfaces.stream().filter(alt -> alt.number() == alternateNumber).findFirst().orElse(null); - } - - @Override - public List alternates() { - return Collections.unmodifiableList(alternateInterfaces); - } - - void addAlternate(USBAlternateInterface alt) { - alternateInterfaces.add(alt); - } - - public void setAlternate(USBAlternateInterface alternate) { - currentAlternate = alternate; - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbAlternateInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbAlternateInterfaceImpl.java new file mode 100644 index 00000000..9a7d70b1 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbAlternateInterfaceImpl.java @@ -0,0 +1,74 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +import net.codecrete.usb.UsbAlternateInterface; +import net.codecrete.usb.UsbDirection; +import net.codecrete.usb.UsbEndpoint; +import net.codecrete.usb.UsbException; +import org.jetbrains.annotations.NotNull; + +import java.util.Comparator; +import java.util.List; + +import static java.util.Collections.unmodifiableList; + +public class UsbAlternateInterfaceImpl implements UsbAlternateInterface { + + private final int alternateInterfaceNumber; + private final int alternateInterfaceClass; + private final int alternateInterfaceSubclass; + private final int alternateInterfaceProtocol; + private final List endpointList; + + public UsbAlternateInterfaceImpl(int number, int classCode, int subclassCode, int protocolCode, + List endpoints) { + alternateInterfaceNumber = number; + alternateInterfaceClass = classCode; + alternateInterfaceSubclass = subclassCode; + alternateInterfaceProtocol = protocolCode; + endpointList = endpoints; + endpointList.sort(Comparator.comparingInt(UsbEndpoint::getNumber)); + } + + @Override + public int getNumber() { + return alternateInterfaceNumber; + } + + @Override + public int getClassCode() { + return alternateInterfaceClass; + } + + @Override + public int getSubclassCode() { + return alternateInterfaceSubclass; + } + + @Override + public int getProtocolCode() { + return alternateInterfaceProtocol; + } + + @Override + public @NotNull List getEndpoints() { + return unmodifiableList(endpointList); + } + + void addEndpoint(UsbEndpoint endpoint) { + endpointList.add(endpoint); + } + + @Override + public @NotNull UsbEndpoint getEndpoint(int endpointNumber, UsbDirection direction) { + return endpointList.stream() + .filter(ep -> ep.getNumber() == endpointNumber && ep.getDirection() == direction).findFirst() + .orElseThrow(() -> new UsbException(String.format("Endpoint %d (%s) does not exist", endpointNumber, direction))); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java similarity index 74% rename from java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java rename to java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java index 6db36ed5..e17d566e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java @@ -9,16 +9,18 @@ import net.codecrete.usb.*; import net.codecrete.usb.usbstandard.DeviceDescriptor; +import org.jetbrains.annotations.NotNull; import java.lang.foreign.MemorySegment; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.function.IntFunction; import static java.lang.foreign.ValueLayout.JAVA_BYTE; @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") -public abstract class USBDeviceImpl implements USBDevice { +public abstract class UsbDeviceImpl implements UsbDevice { /** * Operating system-specific device ID used for {@link #equals(Object)} and {@link #hashCode()}. @@ -29,7 +31,7 @@ public abstract class USBDeviceImpl implements USBDevice { */ protected final Object uniqueDeviceId; - protected List interfaceList; + protected List interfaceList; protected byte[] rawDeviceDescriptor; @@ -44,7 +46,7 @@ public abstract class USBDeviceImpl implements USBDevice { protected int deviceClass; protected int deviceSubclass; protected int deviceProtocol; - protected Version versionUSB; + protected Version versionUsb; protected Version versionDevice; /** @@ -54,7 +56,7 @@ public abstract class USBDeviceImpl implements USBDevice { * @param vendorId USB vendor ID * @param productId USB product ID */ - protected USBDeviceImpl(Object id, int vendorId, int productId) { + protected UsbDeviceImpl(Object id, int vendorId, int productId) { assert id != null; @@ -65,82 +67,82 @@ protected USBDeviceImpl(Object id, int vendorId, int productId) { @Override public void detachStandardDrivers() { - if (isOpen()) - throw new USBException("detachStandardDrivers() must not be called while the device is open"); + if (isOpened()) + throw new UsbException("detachStandardDrivers() must not be called while the device is open"); // default implementation: do nothing } @Override public void attachStandardDrivers() { - if (isOpen()) - throw new USBException("attachStandardDrivers() must not be called while the device is open"); + if (isOpened()) + throw new UsbException("attachStandardDrivers() must not be called while the device is open"); // default implementation: do nothing } protected void checkIsOpen() { - if (!isOpen()) - throw new USBException("device needs to be opened first for this operation"); + if (!isOpened()) + throw new UsbException("device needs to be opened first for this operation"); } @Override - public int productId() { + public int getProductId() { return pid; } @Override - public int vendorId() { + public int getVendorId() { return vid; } @Override - public String product() { + public String getProduct() { return productString; } @Override - public String manufacturer() { + public String getManufacturer() { return manufacturerString; } @Override - public String serialNumber() { + public String getSerialNumber() { return serialString; } @Override - public int classCode() { + public int getClassCode() { return deviceClass; } @Override - public int subclassCode() { + public int getSubclassCode() { return deviceSubclass; } @Override - public int protocolCode() { + public int getProtocolCode() { return deviceProtocol; } @Override - public Version usbVersion() { - return versionUSB; + public @NotNull Version getUsbVersion() { + return versionUsb; } @Override - public Version deviceVersion() { + public @NotNull Version getDeviceVersion() { return versionDevice; } @Override - public byte[] configurationDescriptor() { + public byte @NotNull [] getConfigurationDescriptor() { return rawConfigurationDescriptor; } @Override - public byte[] deviceDescriptor() { + public byte @NotNull [] getDeviceDescriptor() { return rawDeviceDescriptor; } @@ -159,7 +161,7 @@ public void setFromDeviceDescriptor(MemorySegment descriptor) { deviceClass = deviceDescriptor.deviceClass() & 255; deviceSubclass = deviceDescriptor.deviceSubClass() & 255; deviceProtocol = deviceDescriptor.deviceProtocol() & 255; - versionUSB = new Version(deviceDescriptor.usbVersion()); + versionUsb = new Version(deviceDescriptor.usbVersion()); versionDevice = new Version(deviceDescriptor.deviceVersion()); } @@ -173,6 +175,7 @@ protected Configuration setConfigurationDescriptor(MemorySegment descriptor) { rawConfigurationDescriptor = descriptor.toArray(JAVA_BYTE); var configuration = ConfigurationParser.parseConfigurationDescriptor(descriptor); interfaceList = configuration.interfaces(); + interfaceList.sort(Comparator.comparingInt(UsbInterface::getNumber)); return configuration; } @@ -213,51 +216,51 @@ public void setClassCodes(int classCode, int subclassCode, int protocolCode) { } public void setVersions(int usbVersion, int deviceVersion) { - versionUSB = new Version(usbVersion); + versionUsb = new Version(usbVersion); versionDevice = new Version(deviceVersion); } @Override - public List interfaces() { + public @NotNull List getInterfaces() { return Collections.unmodifiableList(interfaceList); } public void setClaimed(int interfaceNumber, boolean claimed) { for (var intf : interfaceList) { - if (intf.number() == interfaceNumber) { - ((USBInterfaceImpl) intf).setClaimed(claimed); + if (intf.getNumber() == interfaceNumber) { + ((UsbInterfaceImpl) intf).setClaimed(claimed); return; } } - throw new USBException("internal error (interface not found)"); + throw new UsbException("internal error (interface not found)"); } @Override - public USBInterfaceImpl getInterface(int interfaceNumber) { - return (USBInterfaceImpl) interfaceList.stream().filter(intf -> intf.number() == interfaceNumber).findFirst().orElse(null); + public @NotNull UsbInterfaceImpl getInterface(int interfaceNumber) { + return (UsbInterfaceImpl) interfaceList.stream() + .filter(intf -> intf.getNumber() == interfaceNumber).findFirst() + .orElseThrow(() -> new UsbException(String.format("USB device has no interface %d", interfaceNumber))); } - public USBInterfaceImpl getInterfaceWithCheck(int interfaceNumber, boolean isClaimed) { + public UsbInterfaceImpl getInterfaceWithCheck(int interfaceNumber, boolean isClaimed) { var intf = getInterface(interfaceNumber); - if (intf == null) - throw new USBException(String.format("invalid interface number: %d", interfaceNumber)); if (isClaimed && !intf.isClaimed()) { - throw new USBException(String.format("interface %d must be claimed first", interfaceNumber)); + throw new UsbException(String.format("interface %d must be claimed first", interfaceNumber)); } else if (!isClaimed && intf.isClaimed()) { - throw new USBException(String.format("interface %d has already been claimed", interfaceNumber)); + throw new UsbException(String.format("interface %d has already been claimed", interfaceNumber)); } return intf; } @Override - public USBEndpoint getEndpoint(USBDirection direction, int endpointNumber) { + public @NotNull UsbEndpoint getEndpoint(UsbDirection direction, int endpointNumber) { for (var intf : interfaceList) { - for (var endpoint : intf.alternate().endpoints()) { - if (endpoint.direction() == direction && endpoint.number() == endpointNumber) + for (var endpoint : intf.getCurrentAlternate().getEndpoints()) { + if (endpoint.getDirection() == direction && endpoint.getNumber() == endpointNumber) return endpoint; } } - return null; + throw new UsbException(String.format("endpoint %d (%s) does not exist", endpointNumber, direction.name())); } /** @@ -270,20 +273,20 @@ public USBEndpoint getEndpoint(USBDirection direction, int endpointNumber) { * @return endpoint */ @SuppressWarnings("java:S3776") - protected EndpointInfo getEndpoint(USBDirection direction, int endpointNumber, USBTransferType transferType1, - USBTransferType transferType2) { + protected EndpointInfo getEndpoint(UsbDirection direction, int endpointNumber, UsbTransferType transferType1, + UsbTransferType transferType2) { checkIsOpen(); if (endpointNumber >= 1 && endpointNumber <= 127) { for (var intf : interfaceList) { if (intf.isClaimed()) { - for (var ep : intf.alternate().endpoints()) { - if (ep.number() == endpointNumber && ep.direction() == direction - && (ep.transferType() == transferType1 || ep.transferType() == transferType2)) - return new EndpointInfo(intf.number(), ep.number(), - (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)), - ep.packetSize(), ep.transferType()); + for (var ep : intf.getCurrentAlternate().getEndpoints()) { + if (ep.getNumber() == endpointNumber && ep.getDirection() == direction + && (ep.getTransferType() == transferType1 || ep.getTransferType() == transferType2)) + return new EndpointInfo(intf.getNumber(), ep.getNumber(), + (byte) (endpointNumber | (direction == UsbDirection.IN ? 0x80 : 0)), + ep.getPacketSize(), ep.getTransferType()); } } } @@ -293,27 +296,27 @@ protected EndpointInfo getEndpoint(USBDirection direction, int endpointNumber, U return null; // will never be reached } - protected void throwInvalidEndpointException(USBDirection direction, int endpointNumber, - USBTransferType transferType1, USBTransferType transferType2) { + protected void throwInvalidEndpointException(UsbDirection direction, int endpointNumber, + UsbTransferType transferType1, UsbTransferType transferType2) { String transferTypeDesc; if (transferType2 == null) transferTypeDesc = transferType1.name(); else transferTypeDesc = String.format("%s or %s", transferType1.name(), transferType2.name()); - throw new USBException(String.format( + throw new UsbException(String.format( "endpoint number %d does not exist, is not part of a claimed interface or is not valid for %s transfer in %s direction", endpointNumber, transferTypeDesc, direction.name())); } - protected int getInterfaceNumber(USBDirection direction, int endpointNumber) { + protected int getInterfaceNumber(UsbDirection direction, int endpointNumber) { if (endpointNumber < 1 || endpointNumber > 127) return -1; for (var intf : interfaceList) { if (intf.isClaimed()) { - for (var ep : intf.alternate().endpoints()) { - if (ep.number() == endpointNumber && ep.direction() == direction) - return intf.number(); + for (var ep : intf.getCurrentAlternate().getEndpoints()) { + if (ep.getNumber() == endpointNumber && ep.getDirection() == direction) + return intf.getNumber(); } } } @@ -322,21 +325,21 @@ protected int getInterfaceNumber(USBDirection direction, int endpointNumber) { } @Override - public void transferOut(int endpointNumber, byte[] data) { + public void transferOut(int endpointNumber, byte @NotNull [] data) { transferOut(endpointNumber, data, 0, data.length, 0); } @Override - public void transferOut(int endpointNumber, byte[] data, int timeout) { + public void transferOut(int endpointNumber, byte @NotNull [] data, int timeout) { transferOut(endpointNumber, data, 0, data.length, timeout); } @Override - public byte[] transferIn(int endpointNumber) { + public byte @NotNull [] transferIn(int endpointNumber) { return transferIn(endpointNumber, 0); } - protected void waitForTransfer(Transfer transfer, int timeout, USBDirection direction, int endpointNumber) { + protected void waitForTransfer(Transfer transfer, int timeout, UsbDirection direction, int endpointNumber) { if (timeout <= 0) { waitNoTimeout(transfer); @@ -347,7 +350,7 @@ protected void waitForTransfer(Transfer transfer, int timeout, USBDirection dire if (hasTimedOut && transfer.resultCode() == 0) { abortTransfers(direction, endpointNumber); waitNoTimeout(transfer); - throw new USBTimeoutException(getOperationDescription(direction, endpointNumber) + throw new UsbTimeoutException(getOperationDescription(direction, endpointNumber) + "aborted due to timeout"); } } @@ -389,7 +392,7 @@ private static boolean waitWithTimeout(Transfer transfer, int timeout) { return remainingTimeout <= 0; } - protected static String getOperationDescription(USBDirection direction, int endpointNumber) { + protected static String getOperationDescription(UsbDirection direction, int endpointNumber) { if (endpointNumber == 0) { return "control transfer"; } else { @@ -436,7 +439,7 @@ public boolean equals(Object o) { return true; if (o == null || getClass() != o.getClass()) return false; - var that = (USBDeviceImpl) o; + var that = (UsbDeviceImpl) o; return uniqueDeviceId.equals(that.uniqueDeviceId); } @@ -451,6 +454,6 @@ public String toString() { } public record EndpointInfo(int interfaceNumber, int endpointNumber, byte endpointAddress, int packetSize, - USBTransferType transferType) { + UsbTransferType transferType) { } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceRegistry.java similarity index 83% rename from java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java rename to java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceRegistry.java index b3224dfc..72268f15 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceRegistry.java @@ -7,11 +7,10 @@ package net.codecrete.usb.common; -import net.codecrete.usb.USBDevice; -import net.codecrete.usb.USBException; +import net.codecrete.usb.UsbDevice; +import net.codecrete.usb.UsbException; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; @@ -33,14 +32,14 @@ * and builds the initial device list. *

*/ -public abstract class USBDeviceRegistry { +public abstract class UsbDeviceRegistry { - private static final System.Logger LOG = System.getLogger(USBDeviceRegistry.class.getName()); + private static final System.Logger LOG = System.getLogger(UsbDeviceRegistry.class.getName()); - private List devices; + private List devices; private Throwable failureCause; - protected Consumer onDeviceConnectedHandler; - protected Consumer onDeviceDisconnectedHandler; + protected Consumer onDeviceConnectedHandler; + protected Consumer onDeviceDisconnectedHandler; private final Lock lock = new ReentrantLock(); private final Condition enumerationComplete = lock.newCondition(); @@ -74,19 +73,19 @@ public void start() { * * @return list of devices */ - public synchronized List getAllDevices() { - return Collections.unmodifiableList(devices); + public synchronized List getAllDevices() { + return devices; } - public void setOnDeviceConnected(Consumer handler) { + public void setOnDeviceConnected(Consumer handler) { onDeviceConnectedHandler = handler; } - public void setOnDeviceDisconnected(Consumer handler) { + public void setOnDeviceDisconnected(Consumer handler) { onDeviceDisconnectedHandler = handler; } - protected void emitOnDeviceConnected(USBDevice device) { + protected void emitOnDeviceConnected(UsbDevice device) { if (onDeviceConnectedHandler == null) return; @@ -98,7 +97,7 @@ protected void emitOnDeviceConnected(USBDevice device) { } } - protected void emitOnDeviceDisconnected(USBDevice device) { + protected void emitOnDeviceDisconnected(UsbDevice device) { if (onDeviceDisconnectedHandler == null) return; @@ -136,7 +135,7 @@ protected void startDeviceMonitor(Runnable monitorTask) { } if (failureCause != null) - throw new USBException("initial device enumeration has failed", failureCause); + throw new UsbException("initial device enumeration has failed", failureCause); } /** @@ -169,7 +168,7 @@ protected void enumerationFailed(Throwable e) { * * @param deviceList the device list */ - protected void setInitialDeviceList(List deviceList) { + protected void setInitialDeviceList(List deviceList) { synchronized (this) { devices = deviceList; } @@ -181,14 +180,14 @@ protected void setInitialDeviceList(List deviceList) { * * @param device device to add */ - protected void addDevice(USBDevice device) { + protected void addDevice(UsbDevice device) { synchronized (this) { // check for duplicates - if (findDeviceIndex(devices, ((USBDeviceImpl) device).getUniqueId()) >= 0) + if (findDeviceIndex(devices, ((UsbDeviceImpl) device).getUniqueId()) >= 0) return; // copy list - var newDeviceList = new ArrayList(devices.size() + 1); + var newDeviceList = new ArrayList(devices.size() + 1); newDeviceList.addAll(devices); newDeviceList.add(device); devices = newDeviceList; @@ -219,7 +218,7 @@ protected void closeAndRemoveDevice(Object deviceId) { * @param deviceId the unique ID of the device to remove */ protected void removeDevice(Object deviceId) { - USBDevice device; + UsbDevice device; synchronized (this) { // locate device to be removed int index = findDeviceIndex(devices, deviceId); @@ -244,9 +243,9 @@ protected void removeDevice(Object deviceId) { * @param deviceId the unique device ID * @return return the index, or -1 if the device is not found */ - protected int findDeviceIndex(List deviceList, Object deviceId) { + protected int findDeviceIndex(List deviceList, Object deviceId) { for (int i = 0; i < deviceList.size(); i++) { - var dev = (USBDeviceImpl) deviceList.get(i); + var dev = (UsbDeviceImpl) deviceList.get(i); if (deviceId.equals(dev.getUniqueId())) return i; } @@ -259,7 +258,7 @@ protected int findDeviceIndex(List deviceList, Object deviceId) { * @param deviceId the unique device ID * @return return device, or {@code null} if not found. */ - protected USBDevice findDevice(Object deviceId) { + protected UsbDevice findDevice(Object deviceId) { int index = findDeviceIndex(devices, deviceId); if (index < 0) return null; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/USBEndpointImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbEndpointImpl.java similarity index 51% rename from java-does-usb/src/main/java/net/codecrete/usb/common/USBEndpointImpl.java rename to java-does-usb/src/main/java/net/codecrete/usb/common/UsbEndpointImpl.java index f896b0f2..f40525ea 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/USBEndpointImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbEndpointImpl.java @@ -7,21 +7,21 @@ package net.codecrete.usb.common; -import net.codecrete.usb.USBDirection; -import net.codecrete.usb.USBEndpoint; -import net.codecrete.usb.USBTransferType; +import net.codecrete.usb.UsbDirection; +import net.codecrete.usb.UsbEndpoint; +import net.codecrete.usb.UsbTransferType; /** - * Implementation of {@code USBEndpoint} interface. + * Implementation of {@code UsbEndpoint} interface. */ -public class USBEndpointImpl implements USBEndpoint { +public class UsbEndpointImpl implements UsbEndpoint { private final int endpointNumber; - private final USBDirection transferDirection; - private final USBTransferType type; + private final UsbDirection transferDirection; + private final UsbTransferType type; private final int maxPacketSize; - public USBEndpointImpl(int number, USBDirection direction, USBTransferType type, int packetSize) { + public UsbEndpointImpl(int number, UsbDirection direction, UsbTransferType type, int packetSize) { endpointNumber = number; transferDirection = direction; this.type = type; @@ -29,22 +29,22 @@ public USBEndpointImpl(int number, USBDirection direction, USBTransferType type, } @Override - public int number() { + public int getNumber() { return endpointNumber; } @Override - public USBDirection direction() { + public UsbDirection getDirection() { return transferDirection; } @Override - public USBTransferType transferType() { + public UsbTransferType getTransferType() { return type; } @Override - public int packetSize() { + public int getPacketSize() { return maxPacketSize; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbInterfaceImpl.java new file mode 100644 index 00000000..8f6ea08e --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbInterfaceImpl.java @@ -0,0 +1,75 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +import net.codecrete.usb.UsbAlternateInterface; +import net.codecrete.usb.UsbException; +import net.codecrete.usb.UsbInterface; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class UsbInterfaceImpl implements UsbInterface { + + private final int interfaceNumber; + private UsbAlternateInterface currentAlternate; + private final List alternateInterfaces; + + private boolean claimed; + + public UsbInterfaceImpl(int number, List alternates) { + interfaceNumber = number; + alternateInterfaces = alternates; + currentAlternate = alternates.get(0); + alternateInterfaces.sort(Comparator.comparingInt(UsbAlternateInterface::getNumber)); + } + + @Override + public int getNumber() { + return interfaceNumber; + } + + @Override + public boolean isClaimed() { + return claimed; + } + + public void setClaimed(boolean claimed) { + this.claimed = claimed; + } + + @Override + public @NotNull UsbAlternateInterface getCurrentAlternate() { + return currentAlternate; + } + + @Override + public @NotNull UsbAlternateInterface getAlternate(int alternateNumber) { + return alternateInterfaces.stream() + .filter(alt -> alt.getNumber() == alternateNumber).findFirst() + .orElseThrow(() -> new UsbException(String.format( + "Interface %d does not have an alternate interface setting %d", + interfaceNumber, alternateNumber) + )); + } + + @Override + public @NotNull List getAlternates() { + return Collections.unmodifiableList(alternateInterfaces); + } + + void addAlternate(UsbAlternateInterface alt) { + alternateInterfaces.add(alt); + } + + public void setAlternate(UsbAlternateInterface alternate) { + currentAlternate = alternate; + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index 19d01492..524fe818 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -7,7 +7,7 @@ package net.codecrete.usb.linux; -import net.codecrete.usb.USBTransferType; +import net.codecrete.usb.UsbTransferType; import net.codecrete.usb.linux.gen.errno.errno; import net.codecrete.usb.linux.gen.poll.poll; import net.codecrete.usb.linux.gen.poll.pollfd; @@ -24,9 +24,9 @@ import static java.lang.foreign.ValueLayout.JAVA_LONG; import static net.codecrete.usb.common.ForeignMemory.dereference; import static net.codecrete.usb.linux.Linux.allocateErrorState; -import static net.codecrete.usb.linux.LinuxUSBException.throwException; -import static net.codecrete.usb.linux.LinuxUSBException.throwLastError; -import static net.codecrete.usb.linux.USBDevFS.*; +import static net.codecrete.usb.linux.LinuxUsbException.throwException; +import static net.codecrete.usb.linux.LinuxUsbException.throwLastError; +import static net.codecrete.usb.linux.UsbDevFS.*; import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.*; /** @@ -194,7 +194,7 @@ private void notifyAsyncIOTask() { * * @param device USB device */ - synchronized void addForAsyncIOCompletion(LinuxUSBDevice device) { + synchronized void addForAsyncIOCompletion(LinuxUsbDevice device) { var n = asyncFds != null ? asyncFds.length : 0; var fds = new int[n + 1]; if (n > 0) @@ -211,7 +211,7 @@ synchronized void addForAsyncIOCompletion(LinuxUSBDevice device) { * * @param device USB device */ - synchronized void removeFromAsyncIOCompletion(LinuxUSBDevice device) { + synchronized void removeFromAsyncIOCompletion(LinuxUsbDevice device) { removeFdFromAsyncIOCompletion(device.fileDescriptor()); notifyAsyncIOTask(); } @@ -237,7 +237,7 @@ private synchronized void removeFdFromAsyncIOCompletion(int fd) { asyncFds = fds; } - synchronized void submitTransfer(LinuxUSBDevice device, int endpointAddress, USBTransferType transferType, LinuxTransfer transfer) { + synchronized void submitTransfer(LinuxUsbDevice device, int endpointAddress, UsbTransferType transferType, LinuxTransfer transfer) { addURB(transfer); var urb = transfer.urb; @@ -258,7 +258,7 @@ synchronized void submitTransfer(LinuxUSBDevice device, int endpointAddress, USB } } - private static int urbTransferType(USBTransferType transferType) { + private static int urbTransferType(UsbTransferType transferType) { return switch (transferType) { case BULK -> USBDEVFS_URB_TYPE_BULK(); case INTERRUPT -> USBDEVFS_URB_TYPE_INTERRUPT(); @@ -295,7 +295,7 @@ private synchronized LinuxTransfer getTransferResult(MemorySegment urb) { } @SuppressWarnings("java:S1066") - synchronized void abortTransfers(LinuxUSBDevice device, byte endpointAddress) { + synchronized void abortTransfers(LinuxUsbDevice device, byte endpointAddress) { var fd = device.fileDescriptor(); try (var arena = Arena.ofConfined()) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java index 9d1f7ce0..2f48a0e6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java @@ -7,18 +7,18 @@ package net.codecrete.usb.linux; -import net.codecrete.usb.USBDirection; +import net.codecrete.usb.UsbDirection; import net.codecrete.usb.common.EndpointInputStream; import net.codecrete.usb.common.Transfer; public class LinuxEndpointInputStream extends EndpointInputStream { - LinuxEndpointInputStream(LinuxUSBDevice device, int endpointNumber, int bufferSize) { + LinuxEndpointInputStream(LinuxUsbDevice device, int endpointNumber, int bufferSize) { super(device, endpointNumber, bufferSize); } @Override protected void submitTransferIn(Transfer transfer) { - ((LinuxUSBDevice) device).submitTransfer(USBDirection.IN, endpointNumber, (LinuxTransfer) transfer); + ((LinuxUsbDevice) device).submitTransfer(UsbDirection.IN, endpointNumber, (LinuxTransfer) transfer); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java index ab5b997d..024b8da0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java @@ -7,18 +7,18 @@ package net.codecrete.usb.linux; -import net.codecrete.usb.USBDirection; +import net.codecrete.usb.UsbDirection; import net.codecrete.usb.common.EndpointOutputStream; import net.codecrete.usb.common.Transfer; public class LinuxEndpointOutputStream extends EndpointOutputStream { - LinuxEndpointOutputStream(LinuxUSBDevice device, int endpointNumber, int bufferSize) { + LinuxEndpointOutputStream(LinuxUsbDevice device, int endpointNumber, int bufferSize) { super(device, endpointNumber, bufferSize); } @Override protected void submitTransferOut(Transfer transfer) { - ((LinuxUSBDevice) device).submitTransfer(USBDirection.OUT, endpointNumber, (LinuxTransfer) transfer); + ((LinuxUsbDevice) device).submitTransfer(UsbDirection.OUT, endpointNumber, (LinuxTransfer) transfer); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java similarity index 73% rename from java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java rename to java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java index 897d3c16..d82aed8e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java @@ -7,13 +7,13 @@ package net.codecrete.usb.linux; -import net.codecrete.usb.USBControlTransfer; -import net.codecrete.usb.USBDirection; -import net.codecrete.usb.USBException; -import net.codecrete.usb.USBTransferType; +import net.codecrete.usb.UsbControlTransfer; +import net.codecrete.usb.UsbDirection; +import net.codecrete.usb.UsbException; +import net.codecrete.usb.UsbTransferType; import net.codecrete.usb.common.Transfer; -import net.codecrete.usb.common.USBDeviceImpl; -import net.codecrete.usb.common.USBInterfaceImpl; +import net.codecrete.usb.common.UsbDeviceImpl; +import net.codecrete.usb.common.UsbInterfaceImpl; import net.codecrete.usb.linux.gen.fcntl.fcntl; import net.codecrete.usb.linux.gen.unistd.unistd; import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_disconnect_claim; @@ -22,6 +22,7 @@ import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs; import net.codecrete.usb.usbstandard.DeviceDescriptor; import net.codecrete.usb.usbstandard.SetupPacket; +import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.io.InputStream; @@ -34,11 +35,11 @@ import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_INT; import static net.codecrete.usb.linux.Linux.allocateErrorState; -import static net.codecrete.usb.linux.LinuxUSBException.throwException; -import static net.codecrete.usb.linux.LinuxUSBException.throwLastError; +import static net.codecrete.usb.linux.LinuxUsbException.throwException; +import static net.codecrete.usb.linux.LinuxUsbException.throwLastError; @SuppressWarnings("java:S2160") -public class LinuxUSBDevice extends USBDeviceImpl { +public class LinuxUsbDevice extends UsbDeviceImpl { @SuppressWarnings("resource") private static final MemorySegment DRIVER_NAME_USBFS = Arena.global().allocateUtf8String("usbfs"); @@ -49,7 +50,7 @@ public class LinuxUSBDevice extends USBDeviceImpl { private boolean detachDrivers = false; - LinuxUSBDevice(Object id, int vendorId, int productId) { + LinuxUsbDevice(Object id, int vendorId, int productId) { super(id, vendorId, productId); asyncTask = LinuxAsyncTask.INSTANCE; loadDescription((String) id); @@ -60,7 +61,7 @@ private void loadDescription(String path) { try { descriptors = Files.readAllBytes(Path.of(path)); } catch (IOException e) { - throw new USBException("reading configuration descriptor failed", e); + throw new UsbException("reading configuration descriptor failed", e); } // `descriptors` contains the device descriptor followed by the configuration descriptor @@ -72,26 +73,26 @@ private void loadDescription(String path) { @Override public void detachStandardDrivers() { - if (isOpen()) + if (isOpened()) throwException("detachStandardDrivers() must not be called while the device is open"); detachDrivers = true; } @Override public void attachStandardDrivers() { - if (isOpen()) + if (isOpened()) throwException("attachStandardDrivers() must not be called while the device is open"); detachDrivers = false; } @Override - public boolean isOpen() { + public boolean isOpened() { return fd != -1; } @Override public synchronized void open() { - if (isOpen()) + if (isOpened()) throwException("device is already open"); try (var arena = Arena.ofConfined()) { @@ -106,13 +107,13 @@ public synchronized void open() { @Override public synchronized void close() { - if (!isOpen()) + if (!isOpened()) return; asyncTask.removeFromAsyncIOCompletion(this); for (var intf : interfaceList) - ((USBInterfaceImpl) intf).setClaimed(false); + ((UsbInterfaceImpl) intf).setClaimed(false); unistd.close(fd); fd = -1; @@ -137,12 +138,12 @@ public synchronized void claimInterface(int interfaceNumber) { usbdevfs_disconnect_claim.interface_$set(disconnectClaim, interfaceNumber); usbdevfs_disconnect_claim.flags$set(disconnectClaim, usbdevice_fs.USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER()); usbdevfs_disconnect_claim.driver$slice(disconnectClaim).copyFrom(DRIVER_NAME_USBFS); - ret = IO.ioctl(fd, USBDevFS.DISCONNECT_CLAIM, disconnectClaim, errorState); + ret = IO.ioctl(fd, UsbDevFS.DISCONNECT_CLAIM, disconnectClaim, errorState); } else { // claim interface (without detaching kernel driver) var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); - ret = IO.ioctl(fd, USBDevFS.CLAIMINTERFACE, intfNumSegment, errorState); + ret = IO.ioctl(fd, UsbDevFS.CLAIMINTERFACE, intfNumSegment, errorState); } if (ret != 0) @@ -160,16 +161,13 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna // check alternate setting var altSetting = intf.getAlternate(alternateNumber); - if (altSetting == null) - throwException("interface %d does not have an alternate interface setting %d", interfaceNumber, - alternateNumber); try (var arena = Arena.ofConfined()) { var setIntfSegment = usbdevfs_setinterface.allocate(arena); usbdevfs_setinterface.interface_$set(setIntfSegment, interfaceNumber); usbdevfs_setinterface.altsetting$set(setIntfSegment, alternateNumber); var errorState = allocateErrorState(arena); - var ret = IO.ioctl(fd, USBDevFS.SETINTERFACE, setIntfSegment, errorState); + var ret = IO.ioctl(fd, UsbDevFS.SETINTERFACE, setIntfSegment, errorState); if (ret != 0) throwLastError(errorState, "setting alternate interface failed"); } @@ -185,7 +183,7 @@ public synchronized void releaseInterface(int interfaceNumber) { try (var arena = Arena.ofConfined()) { var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); var errorState = allocateErrorState(arena); - var ret = IO.ioctl(fd, USBDevFS.RELEASEINTERFACE, intfNumSegment, errorState); + var ret = IO.ioctl(fd, UsbDevFS.RELEASEINTERFACE, intfNumSegment, errorState); if (ret != 0) throwLastError(errorState, "releasing USB interface failed"); @@ -195,36 +193,36 @@ public synchronized void releaseInterface(int interfaceNumber) { // reattach kernel driver var request = usbdevfs_ioctl.allocate(arena); usbdevfs_ioctl.ifno$set(request, interfaceNumber); - usbdevfs_ioctl.ioctl_code$set(request, USBDevFS.CONNECT); + usbdevfs_ioctl.ioctl_code$set(request, UsbDevFS.CONNECT); usbdevfs_ioctl.data$set(request, MemorySegment.NULL); - IO.ioctl(fd, USBDevFS.IOCTL, request, errorState); + IO.ioctl(fd, UsbDevFS.IOCTL, request, errorState); } } } @Override - public void controlTransferOut(USBControlTransfer setup, byte[] data) { + public void controlTransferOut(@NotNull UsbControlTransfer setup, byte[] data) { try (var arena = Arena.ofConfined()) { var dataLength = data != null ? data.length : 0; - var transfer = createSyncCtrlTransfer(arena, USBDirection.OUT, setup, dataLength); + var transfer = createSyncCtrlTransfer(arena, UsbDirection.OUT, setup, dataLength); if (dataLength != 0) transfer.data().asSlice(8).copyFrom(MemorySegment.ofArray(data)); synchronized (transfer) { - submitTransfer(USBDirection.OUT, 0, transfer); - waitForTransfer(transfer, 0, USBDirection.OUT, 0); + submitTransfer(UsbDirection.OUT, 0, transfer); + waitForTransfer(transfer, 0, UsbDirection.OUT, 0); } } } @Override - public byte[] controlTransferIn(USBControlTransfer setup, int length) { + public byte @NotNull [] controlTransferIn(@NotNull UsbControlTransfer setup, int length) { try (var arena = Arena.ofConfined()) { - var transfer = createSyncCtrlTransfer(arena, USBDirection.IN, setup, length); + var transfer = createSyncCtrlTransfer(arena, UsbDirection.IN, setup, length); synchronized (transfer) { - submitTransfer(USBDirection.IN, 0, transfer); - waitForTransfer(transfer, 0, USBDirection.IN, 0); + submitTransfer(UsbDirection.IN, 0, transfer); + waitForTransfer(transfer, 0, UsbDirection.IN, 0); } return transfer.data().asSlice(8, transfer.resultSize()).toArray(JAVA_BYTE); @@ -240,10 +238,10 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { * @param dataLength data length (in addition to setup data) * @return transfer object */ - private LinuxTransfer createSyncCtrlTransfer(Arena arena, USBDirection direction, USBControlTransfer setup, + private LinuxTransfer createSyncCtrlTransfer(Arena arena, UsbDirection direction, UsbControlTransfer setup, int dataLength) { var bmRequest = - (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); + (direction == UsbDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); var buffer = arena.allocate(8L + dataLength, 8); var setupPacket = new SetupPacket(buffer); setupPacket.setRequestType(bmRequest); @@ -256,36 +254,36 @@ private LinuxTransfer createSyncCtrlTransfer(Arena arena, USBDirection direction transfer.setData(buffer); transfer.setDataSize((int) buffer.byteSize()); transfer.setResultSize(-1); - transfer.setCompletion(USBDeviceImpl::onSyncTransferCompleted); + transfer.setCompletion(UsbDeviceImpl::onSyncTransferCompleted); return transfer; } @Override - public void transferOut(int endpointNumber, byte[] data, int offset, int length, int timeout) { + public void transferOut(int endpointNumber, byte @NotNull [] data, int offset, int length, int timeout) { try (var arena = Arena.ofConfined()) { var buffer = arena.allocate(length); buffer.copyFrom(MemorySegment.ofArray(data).asSlice(offset, length)); var transfer = createSyncTransfer(buffer); synchronized (transfer) { - submitTransfer(USBDirection.OUT, endpointNumber, transfer); - waitForTransfer(transfer, timeout, USBDirection.OUT, endpointNumber); + submitTransfer(UsbDirection.OUT, endpointNumber, transfer); + waitForTransfer(transfer, timeout, UsbDirection.OUT, endpointNumber); } } } @Override - public byte[] transferIn(int endpointNumber, int timeout) { - var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); + public byte @NotNull [] transferIn(int endpointNumber, int timeout) { + var endpoint = getEndpoint(UsbDirection.IN, endpointNumber, UsbTransferType.BULK, UsbTransferType.INTERRUPT); try (var arena = Arena.ofConfined()) { var buffer = arena.allocate(endpoint.packetSize()); var transfer = createSyncTransfer(buffer); synchronized (transfer) { - submitTransfer(USBDirection.IN, endpointNumber, transfer); - waitForTransfer(transfer, timeout, USBDirection.IN, endpointNumber); + submitTransfer(UsbDirection.IN, endpointNumber, transfer); + waitForTransfer(transfer, timeout, UsbDirection.IN, endpointNumber); } return buffer.asSlice(0, transfer.resultSize()).toArray(JAVA_BYTE); @@ -297,16 +295,16 @@ private LinuxTransfer createSyncTransfer(MemorySegment data) { transfer.setData(data); transfer.setDataSize((int) data.byteSize()); transfer.setResultSize(-1); - transfer.setCompletion(USBDeviceImpl::onSyncTransferCompleted); + transfer.setCompletion(UsbDeviceImpl::onSyncTransferCompleted); return transfer; } - synchronized void submitTransfer(USBDirection direction, int endpointNumber, LinuxTransfer transfer) { + synchronized void submitTransfer(UsbDirection direction, int endpointNumber, LinuxTransfer transfer) { if (endpointNumber != 0) { - var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); + var endpoint = getEndpoint(direction, endpointNumber, UsbTransferType.BULK, UsbTransferType.INTERRUPT); asyncTask.submitTransfer(this, endpoint.endpointAddress(), endpoint.transferType(), transfer); } else { - asyncTask.submitTransfer(this, 0, USBTransferType.CONTROL, transfer); + asyncTask.submitTransfer(this, 0, UsbTransferType.CONTROL, transfer); } } @@ -321,37 +319,37 @@ protected void throwOSException(int errorCode, String message, Object... args) { } @Override - public void clearHalt(USBDirection direction, int endpointNumber) { - var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); + public void clearHalt(UsbDirection direction, int endpointNumber) { + var endpoint = getEndpoint(direction, endpointNumber, UsbTransferType.BULK, UsbTransferType.INTERRUPT); try (var arena = Arena.ofConfined()) { var endpointAddrSegment = arena.allocate(JAVA_INT, endpoint.endpointAddress() & 0xff); var errorState = allocateErrorState(arena); - var res = IO.ioctl(fd, USBDevFS.CLEAR_HALT, endpointAddrSegment, errorState); + var res = IO.ioctl(fd, UsbDevFS.CLEAR_HALT, endpointAddrSegment, errorState); if (res < 0) throwLastError(errorState, "clearing halt failed"); } } @Override - public synchronized void abortTransfers(USBDirection direction, int endpointNumber) { - var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); + public synchronized void abortTransfers(UsbDirection direction, int endpointNumber) { + var endpoint = getEndpoint(direction, endpointNumber, UsbTransferType.BULK, UsbTransferType.INTERRUPT); asyncTask.abortTransfers(this, endpoint.endpointAddress()); } @Override - public synchronized InputStream openInputStream(int endpointNumber, int bufferSize) { + public synchronized @NotNull InputStream openInputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid - getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, null); + getEndpoint(UsbDirection.IN, endpointNumber, UsbTransferType.BULK, null); return new LinuxEndpointInputStream(this, endpointNumber, bufferSize); } @Override - public synchronized OutputStream openOutputStream(int endpointNumber, int bufferSize) { + public synchronized @NotNull OutputStream openOutputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid - getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, null); + getEndpoint(UsbDirection.OUT, endpointNumber, UsbTransferType.BULK, null); return new LinuxEndpointOutputStream(this, endpointNumber, bufferSize); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java similarity index 93% rename from java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java rename to java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java index ec12e75d..01051c95 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java @@ -7,9 +7,9 @@ package net.codecrete.usb.linux; -import net.codecrete.usb.USBDevice; +import net.codecrete.usb.UsbDevice; import net.codecrete.usb.common.ScopeCleanup; -import net.codecrete.usb.common.USBDeviceRegistry; +import net.codecrete.usb.common.UsbDeviceRegistry; import net.codecrete.usb.linux.gen.poll.poll; import net.codecrete.usb.linux.gen.poll.pollfd; import net.codecrete.usb.linux.gen.udev.udev; @@ -20,14 +20,14 @@ import java.util.List; import static java.lang.System.Logger.Level.INFO; -import static net.codecrete.usb.linux.LinuxUSBException.throwException; +import static net.codecrete.usb.linux.LinuxUsbException.throwException; /** * Linux implementation of USB device registry. */ -public class LinuxUSBDeviceRegistry extends USBDeviceRegistry { +public class LinuxUsbDeviceRegistry extends UsbDeviceRegistry { - private static final System.Logger LOG = System.getLogger(LinuxUSBDeviceRegistry.class.getName()); + private static final System.Logger LOG = System.getLogger(LinuxUsbDeviceRegistry.class.getName()); private static final MemorySegment SUBSYSTEM_USB; private static final MemorySegment MONITOR_NAME; @@ -118,8 +118,8 @@ protected void monitorDevices() { } @SuppressWarnings("java:S135") - private List enumeratePresentDevices(MemorySegment udevInstance) { - List result = new ArrayList<>(); + private List enumeratePresentDevices(MemorySegment udevInstance) { + List result = new ArrayList<>(); try (var outerCleanup = new ScopeCleanup()) { // create device enumerator @@ -181,7 +181,7 @@ private void onDeviceDisconnected(MemorySegment udevDevice) { } /** - * Retrieves the device details and returns a {@code USBDevice} instance. + * Retrieves the device details and returns a {@code UsbDevice} instance. *

* If the device is missing one of vendor ID, product ID or device path, * {@code null} is returned. @@ -191,7 +191,7 @@ private void onDeviceDisconnected(MemorySegment udevDevice) { * @return the device instance */ @SuppressWarnings("java:S106") - private USBDevice getDeviceDetails(MemorySegment udevDevice) { + private UsbDevice getDeviceDetails(MemorySegment udevDevice) { int vendorId = 0; int productId = 0; @@ -215,7 +215,7 @@ private USBDevice getDeviceDetails(MemorySegment udevDevice) { productId = Integer.parseInt(idProduct, 16); // create device instance - var device = new LinuxUSBDevice(devPath, vendorId, productId); + var device = new LinuxUsbDevice(devPath, vendorId, productId); device.setProductStrings(getDeviceAttribute(udevDevice, ATTR_MANUFACTURER), getDeviceAttribute(udevDevice , ATTR_PRODUCT), getDeviceAttribute(udevDevice, ATTR_SERIAL)); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbException.java similarity index 85% rename from java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java rename to java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbException.java index 43924a9a..4f0d95c5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbException.java @@ -6,8 +6,8 @@ // package net.codecrete.usb.linux; -import net.codecrete.usb.USBException; -import net.codecrete.usb.USBStallException; +import net.codecrete.usb.UsbException; +import net.codecrete.usb.UsbStallException; import net.codecrete.usb.linux.gen.errno.errno; import java.lang.foreign.MemorySegment; @@ -15,7 +15,7 @@ /** * Exception thrown if a Linux specific error occurs. */ -public class LinuxUSBException extends USBException { +public class LinuxUsbException extends UsbException { /** * Creates a new instance. @@ -26,7 +26,7 @@ public class LinuxUSBException extends USBException { * @param message exception message * @param errorCode Linux error code (returned by {@code errno}) */ - public LinuxUSBException(String message, int errorCode) { + public LinuxUsbException(String message, int errorCode) { super(String.format("%s: %s", message, Linux.getErrorMessage(errorCode)), errorCode); } @@ -43,9 +43,9 @@ public LinuxUSBException(String message, int errorCode) { static void throwException(int errorCode, String message, Object... args) { var formattedMessage = String.format(message, args); if (errorCode == errno.EPIPE()) { - throw new USBStallException(formattedMessage); + throw new UsbStallException(formattedMessage); } else { - throw new LinuxUSBException(formattedMessage, errorCode); + throw new LinuxUsbException(formattedMessage, errorCode); } } @@ -56,7 +56,7 @@ static void throwException(int errorCode, String message, Object... args) { * @param args arguments for exception message */ static void throwException(String message, Object... args) { - throw new USBException(String.format(message, args)); + throw new UsbException(String.format(message, args)); } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/UsbDevFS.java similarity index 95% rename from java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java rename to java-does-usb/src/main/java/net/codecrete/usb/linux/UsbDevFS.java index f3be0b38..72d9e5c0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/USBDevFS.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/UsbDevFS.java @@ -14,9 +14,9 @@ * Thus, they cannot be generated using jextract. *

*/ -class USBDevFS { +class UsbDevFS { - private USBDevFS() { + private UsbDevFS() { } static final long CLAIMINTERFACE = 0x8004550FL; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index b508a015..22786f0b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -124,8 +124,8 @@ static MemorySegment getInterface(int service, MemorySegment pluginType, MemoryS var refiid = CoreFoundation.CFUUIDGetUUIDBytes(arena, interfaceId); // MemorySegment for holding xxxInterface** var intfHolder = arena.allocate(ADDRESS, NULL); - ret = IoKitUSB.QueryInterface(plug, refiid, intfHolder); - IoKitUSB.Release(plug); + ret = IoKitUsb.QueryInterface(plug, refiid, intfHolder); + IoKitUsb.Release(plug); if (ret != 0) return null; return dereference(intfHolder, COM_OBJECT); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUsb.java similarity index 99% rename from java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java rename to java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUsb.java index 2ba04f12..6dd1e764 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUsb.java @@ -19,9 +19,9 @@ * Helper functions to call the virtual methods of IOKit USB interfaces. */ @SuppressWarnings({"java:S100", "java:S107", "UnusedReturnValue", "SameParameterValue"}) -class IoKitUSB { +class IoKitUsb { - private IoKitUSB() { + private IoKitUsb() { } // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java index 0ca192b5..c9992de0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java @@ -7,7 +7,7 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.USBException; +import net.codecrete.usb.UsbException; import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; import net.codecrete.usb.macos.gen.iokit.IOKit; @@ -116,7 +116,7 @@ private void startAsyncIOThread(MemorySegment firstSource) { Arena.global()); } catch (IllegalAccessException | NoSuchMethodException e) { - throw new USBException("internal error (creating method handle)", e); + throw new UsbException("internal error (creating method handle)", e); } var thread = new Thread(() -> asyncIOCompletionTask(firstSource), "USB async IO"); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java index e947caec..06dff333 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java @@ -12,12 +12,12 @@ public class MacosEndpointInputStream extends EndpointInputStream { - MacosEndpointInputStream(MacosUSBDevice device, int endpointNumber, int bufferSize) { + MacosEndpointInputStream(MacosUsbDevice device, int endpointNumber, int bufferSize) { super(device, endpointNumber, bufferSize); } @Override protected void submitTransferIn(Transfer transfer) { - ((MacosUSBDevice) device).submitTransferIn(endpointNumber, (MacosTransfer) transfer, 0); + ((MacosUsbDevice) device).submitTransferIn(endpointNumber, (MacosTransfer) transfer, 0); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java index d8f16f2c..898ab5e1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java @@ -12,12 +12,12 @@ public class MacosEndpointOutputStream extends EndpointOutputStream { - MacosEndpointOutputStream(MacosUSBDevice device, int endpointNumber, int bufferSize) { + MacosEndpointOutputStream(MacosUsbDevice device, int endpointNumber, int bufferSize) { super(device, endpointNumber, bufferSize); } @Override protected void submitTransferOut(Transfer request) { - ((MacosUSBDevice) device).submitTransferOut(endpointNumber, (MacosTransfer) request, 0); + ((MacosUsbDevice) device).submitTransferOut(endpointNumber, (MacosTransfer) request, 0); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java similarity index 78% rename from java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java rename to java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java index 18673d2c..512238c3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java @@ -10,12 +10,13 @@ import net.codecrete.usb.*; import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.common.Transfer; -import net.codecrete.usb.common.USBDeviceImpl; +import net.codecrete.usb.common.UsbDeviceImpl; import net.codecrete.usb.macos.gen.iokit.IOKit; import net.codecrete.usb.macos.gen.iokit.IOUSBDevRequest; import net.codecrete.usb.macos.gen.iokit.IOUSBFindInterfaceRequest; import net.codecrete.usb.usbstandard.ConfigurationDescriptor; import net.codecrete.usb.usbstandard.Constants; +import org.jetbrains.annotations.NotNull; import java.io.InputStream; import java.io.OutputStream; @@ -28,10 +29,10 @@ import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.common.ForeignMemory.dereference; -import static net.codecrete.usb.macos.MacosUSBException.throwException; +import static net.codecrete.usb.macos.MacosUsbException.throwException; /** - * MacOS implementation of {@link net.codecrete.usb.USBDevice}. + * MacOS implementation of {@link UsbDevice}. *

* All read and write operations on endpoints are submitted through synchronized methods in order to control * concurrency. If it wasn't controlled, the danger is that device and interface pointers are used, which have @@ -43,7 +44,7 @@ *

*/ @SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter", "java:S2160"}) -public class MacosUSBDevice extends USBDeviceImpl { +public class MacosUsbDevice extends UsbDeviceImpl { private final MacosAsyncTask asyncTask; // Native USB device interface (IOUSBDeviceInterface**) @@ -57,7 +58,7 @@ public class MacosUSBDevice extends USBDeviceImpl { private final long discoveryTime; - MacosUSBDevice(MemorySegment device, Object id, int vendorId, int productId) { + MacosUsbDevice(MemorySegment device, Object id, int vendorId, int productId) { super(id, vendorId, productId); discoveryTime = System.currentTimeMillis(); asyncTask = MacosAsyncTask.INSTANCE; @@ -65,36 +66,36 @@ public class MacosUSBDevice extends USBDeviceImpl { loadDescription(device); this.device = device; - IoKitUSB.AddRef(device); + IoKitUsb.AddRef(device); } @Override public void detachStandardDrivers() { - if (isOpen()) + if (isOpened()) throwException("detachStandardDrivers() must not be called while the device is open"); - var ret = IoKitUSB.USBDeviceReEnumerate(device, IOKit.kUSBReEnumerateCaptureDeviceMask()); + var ret = IoKitUsb.USBDeviceReEnumerate(device, IOKit.kUSBReEnumerateCaptureDeviceMask()); if (ret != 0) throwException(ret, "detaching standard drivers failed"); } @Override public void attachStandardDrivers() { - if (isOpen()) + if (isOpened()) throwException("attachStandardDrivers() must not be called while the device is open"); - var ret = IoKitUSB.USBDeviceReEnumerate(device, IOKit.kUSBReEnumerateReleaseDeviceMask()); + var ret = IoKitUsb.USBDeviceReEnumerate(device, IOKit.kUSBReEnumerateReleaseDeviceMask()); if (ret != 0) throwException(ret, "attaching standard drivers failed"); } @Override - public boolean isOpen() { + public boolean isOpened() { return claimedInterfaces != null; } @SuppressWarnings("java:S2276") @Override public synchronized void open() { - if (isOpen()) + if (isOpened()) throwException("device is already open"); // open device (several retries if device has just been connected/discovered) @@ -103,7 +104,7 @@ public synchronized void open() { var ret = 0; while (numTries > 0) { numTries -= 1; - ret = IoKitUSB.USBDeviceOpenSeize(device); + ret = IoKitUsb.USBDeviceOpenSeize(device); if (ret != IOKit.kIOReturnExclusiveAccess()) break; @@ -121,7 +122,7 @@ public synchronized void open() { addDeviceEventSource(); // set configuration - ret = IoKitUSB.SetConfiguration(device, (byte) configurationValue); + ret = IoKitUsb.SetConfiguration(device, (byte) configurationValue); if (ret != 0) throwException(ret, "setting configuration failed"); @@ -130,28 +131,28 @@ public synchronized void open() { @Override public synchronized void close() { - if (!isOpen()) + if (!isOpened()) return; for (var interfaceInfo : claimedInterfaces) { - IoKitUSB.USBInterfaceClose(interfaceInfo.iokitInterface); - IoKitUSB.Release(interfaceInfo.iokitInterface); + IoKitUsb.USBInterfaceClose(interfaceInfo.iokitInterface); + IoKitUsb.Release(interfaceInfo.iokitInterface); setClaimed(interfaceInfo.interfaceNumber, false); } claimedInterfaces = null; endpoints = null; - var source = IoKitUSB.GetDeviceAsyncEventSource(device); + var source = IoKitUsb.GetDeviceAsyncEventSource(device); if (source.address() != 0) asyncTask.removeEventSource(source); - IoKitUSB.USBDeviceClose(device); + IoKitUsb.USBDeviceClose(device); } synchronized void closeFully() { close(); - IoKitUSB.Release(device); + IoKitUsb.Release(device); device = null; } @@ -160,14 +161,14 @@ private void loadDescription(MemorySegment device) { // retrieve device descriptor using synchronous control transfer var data = arena.allocate(255); - var deviceRequest = createDeviceRequest(arena, USBDirection.IN, new USBControlTransfer( - USBRequestType.STANDARD, - USBRecipient.DEVICE, + var deviceRequest = createDeviceRequest(arena, UsbDirection.IN, new UsbControlTransfer( + UsbRequestType.STANDARD, + UsbRecipient.DEVICE, 6, // get descriptor Constants.DEVICE_DESCRIPTOR_TYPE << 8, 0 ), data); - var ret = IoKitUSB.DeviceRequest(device, deviceRequest); + var ret = IoKitUsb.DeviceRequest(device, deviceRequest); if (ret != 0) throwException(ret, "querying device descriptor failed"); @@ -178,7 +179,7 @@ private void loadDescription(MemorySegment device) { // retrieve information of first configuration var descPtrHolder = arena.allocate(ADDRESS); - ret = IoKitUSB.GetConfigurationDescriptorPtr(device, (byte) 0, descPtrHolder); + ret = IoKitUsb.GetConfigurationDescriptorPtr(device, (byte) 0, descPtrHolder); if (ret != 0) throwException(ret, "querying first configuration failed"); @@ -192,7 +193,7 @@ private void loadDescription(MemorySegment device) { } @SuppressWarnings("java:S135") - private InterfaceInfo findInterface(int interfaceNumber) { + private InterfaceInfo findInterfaceInfo(int interfaceNumber) { try (var arena = Arena.ofConfined(); var outerCleanup = new ScopeCleanup()) { var request = IOUSBFindInterfaceRequest.allocate(arena); @@ -202,7 +203,7 @@ private InterfaceInfo findInterface(int interfaceNumber) { IOUSBFindInterfaceRequest.bAlternateSetting$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); var iterHolder = arena.allocate(JAVA_INT); - var ret = IoKitUSB.CreateInterfaceIterator(device, request, iterHolder); + var ret = IoKitUsb.CreateInterfaceIterator(device, request, iterHolder); if (ret != 0) throwException("internal error (CreateInterfaceIterator)"); @@ -223,13 +224,13 @@ private InterfaceInfo findInterface(int interfaceNumber) { if (intf == null) continue; - cleanup.add(() -> IoKitUSB.Release(intf)); + cleanup.add(() -> IoKitUsb.Release(intf)); - IoKitUSB.GetInterfaceNumber(intf, intfNumberHolder); + IoKitUsb.GetInterfaceNumber(intf, intfNumberHolder); if (intfNumberHolder.get(JAVA_INT, 0) != interfaceNumber) continue; - IoKitUSB.AddRef(intf); + IoKitUsb.AddRef(intf); return new InterfaceInfo(intf, interfaceNumber); } } @@ -245,14 +246,14 @@ public synchronized void claimInterface(int interfaceNumber) { try (var cleanup = new ScopeCleanup()) { - var interfaceInfo = findInterface(interfaceNumber); - cleanup.add(() -> IoKitUSB.Release(interfaceInfo.iokitInterface())); + var interfaceInfo = findInterfaceInfo(interfaceNumber); + cleanup.add(() -> IoKitUsb.Release(interfaceInfo.iokitInterface())); - var ret = IoKitUSB.USBInterfaceOpen(interfaceInfo.iokitInterface()); + var ret = IoKitUsb.USBInterfaceOpen(interfaceInfo.iokitInterface()); if (ret != 0) throwException(ret, "claiming interface failed"); - IoKitUSB.AddRef(interfaceInfo.iokitInterface()); + IoKitUsb.AddRef(interfaceInfo.iokitInterface()); claimedInterfaces.add(interfaceInfo); setClaimed(interfaceNumber, true); addInterfaceEventSource(interfaceInfo); @@ -268,14 +269,10 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna // check alternate setting var altSetting = intf.getAlternate(alternateNumber); - if (altSetting == null) - throwException("interface %d does not have an alternate interface setting %d", interfaceNumber, - alternateNumber); - var intfInfo = claimedInterfaces.stream().filter(interf -> interf.interfaceNumber() == interfaceNumber).findFirst().get(); - var ret = IoKitUSB.SetAlternateInterface(intfInfo.iokitInterface(), (byte) alternateNumber); + var ret = IoKitUsb.SetAlternateInterface(intfInfo.iokitInterface(), (byte) alternateNumber); if (ret != 0) throwException(ret, "setting alternate interface failed"); @@ -292,16 +289,16 @@ public synchronized void releaseInterface(int interfaceNumber) { var interfaceInfo = claimedInterfaces.stream().filter(info -> info.interfaceNumber == interfaceNumber).findFirst().get(); - var source = IoKitUSB.GetInterfaceAsyncEventSource(interfaceInfo.iokitInterface()); + var source = IoKitUsb.GetInterfaceAsyncEventSource(interfaceInfo.iokitInterface()); if (source.address() != 0) asyncTask.removeEventSource(source); - var ret = IoKitUSB.USBInterfaceClose(interfaceInfo.iokitInterface()); + var ret = IoKitUsb.USBInterfaceClose(interfaceInfo.iokitInterface()); if (ret != 0) throwException(ret, "releasing interface failed"); claimedInterfaces.remove(interfaceInfo); - IoKitUSB.Release(interfaceInfo.iokitInterface()); + IoKitUsb.Release(interfaceInfo.iokitInterface()); setClaimed(interfaceNumber, false); updateEndpointList(); @@ -329,14 +326,14 @@ private void updateEndpointList() { var intf = interfaceInfo.iokitInterface(); var numEndpointsHolder = arena.allocate(JAVA_BYTE); - var ret = IoKitUSB.GetNumEndpoints(intf, numEndpointsHolder); + var ret = IoKitUsb.GetNumEndpoints(intf, numEndpointsHolder); if (ret != 0) throwException(ret, "internal error (GetNumEndpoints)"); var numEndpoints = numEndpointsHolder.get(JAVA_BYTE, 0) & 255; for (var pipeIndex = 1; pipeIndex <= numEndpoints; pipeIndex++) { - ret = IoKitUSB.GetPipeProperties(intf, (byte) pipeIndex, directionHolder, numberHolder, + ret = IoKitUsb.GetPipeProperties(intf, (byte) pipeIndex, directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); if (ret != 0) throwException(ret, "internal error (GetPipeProperties)"); @@ -355,10 +352,10 @@ private void updateEndpointList() { } @SuppressWarnings("SameParameterValue") - private synchronized EndpointInfo getEndpointInfo(int endpointNumber, USBDirection direction, - USBTransferType transferType1, USBTransferType transferType2) { + private synchronized EndpointInfo getEndpointInfo(int endpointNumber, UsbDirection direction, + UsbTransferType transferType1, UsbTransferType transferType2) { if (endpoints != null) { - var endpointAddress = (byte) (endpointNumber | (direction == USBDirection.IN ? 0x80 : 0)); + var endpointAddress = (byte) (endpointNumber | (direction == UsbDirection.IN ? 0x80 : 0)); var endpointInfo = endpoints.get(endpointAddress); if (endpointInfo != null && (endpointInfo.transferType == transferType1 || endpointInfo.transferType == transferType2)) return endpointInfo; @@ -376,11 +373,11 @@ private synchronized EndpointInfo getEndpointInfo(int endpointNumber, USBDirecti throw new AssertionError("not reached"); } - private static MemorySegment createDeviceRequest(Arena arena, USBDirection direction, USBControlTransfer setup, + private static MemorySegment createDeviceRequest(Arena arena, UsbDirection direction, UsbControlTransfer setup, MemorySegment data) { var deviceRequest = IOUSBDevRequest.allocate(arena); var bmRequestType = - (direction == USBDirection.IN ? 0x80 : 0x00) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); + (direction == UsbDirection.IN ? 0x80 : 0x00) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); IOUSBDevRequest.bmRequestType$set(deviceRequest, (byte) bmRequestType); IOUSBDevRequest.bRequest$set(deviceRequest, (byte) setup.request()); IOUSBDevRequest.wValue$set(deviceRequest, (short) setup.value()); @@ -391,17 +388,17 @@ private static MemorySegment createDeviceRequest(Arena arena, USBDirection direc } @Override - public byte[] controlTransferIn(USBControlTransfer setup, int length) { + public byte @NotNull [] controlTransferIn(@NotNull UsbControlTransfer setup, int length) { try (var arena = Arena.ofConfined()) { var data = arena.allocate(length); - var deviceRequest = createDeviceRequest(arena, USBDirection.IN, setup, data); + var deviceRequest = createDeviceRequest(arena, UsbDirection.IN, setup, data); var transfer = new MacosTransfer(); - transfer.setCompletion(USBDeviceImpl::onSyncTransferCompleted); + transfer.setCompletion(UsbDeviceImpl::onSyncTransferCompleted); synchronized (transfer) { submitControlTransfer(deviceRequest, transfer); - waitForTransfer(transfer, 0, USBDirection.IN, 0); + waitForTransfer(transfer, 0, UsbDirection.IN, 0); } return data.asSlice(0, transfer.resultSize()).toArray(JAVA_BYTE); @@ -409,29 +406,29 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { } @Override - public void controlTransferOut(USBControlTransfer setup, byte[] data) { + public void controlTransferOut(@NotNull UsbControlTransfer setup, byte[] data) { try (var arena = Arena.ofConfined()) { var dataLength = data != null ? data.length : 0; var dataSegment = arena.allocate(dataLength); if (dataLength > 0) dataSegment.copyFrom(MemorySegment.ofArray(data)); - var deviceRequest = createDeviceRequest(arena, USBDirection.OUT, setup, dataSegment); + var deviceRequest = createDeviceRequest(arena, UsbDirection.OUT, setup, dataSegment); var transfer = new MacosTransfer(); - transfer.setCompletion(USBDeviceImpl::onSyncTransferCompleted); + transfer.setCompletion(UsbDeviceImpl::onSyncTransferCompleted); synchronized (transfer) { submitControlTransfer(deviceRequest, transfer); - waitForTransfer(transfer, 0, USBDirection.OUT, 0); + waitForTransfer(transfer, 0, UsbDirection.OUT, 0); } } } @Override - public void transferOut(int endpointNumber, byte[] data, int offset, int length, int timeout) { + public void transferOut(int endpointNumber, byte @NotNull [] data, int offset, int length, int timeout) { - var epInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, - USBTransferType.INTERRUPT); + var epInfo = getEndpointInfo(endpointNumber, UsbDirection.OUT, UsbTransferType.BULK, + UsbTransferType.INTERRUPT); try (var arena = Arena.ofConfined()) { var nativeData = arena.allocateArray(JAVA_BYTE, length); @@ -440,28 +437,28 @@ public void transferOut(int endpointNumber, byte[] data, int offset, int length, var transfer = new MacosTransfer(); transfer.setData(nativeData); transfer.setDataSize(length); - transfer.setCompletion(USBDeviceImpl::onSyncTransferCompleted); + transfer.setCompletion(UsbDeviceImpl::onSyncTransferCompleted); synchronized (transfer) { - if (timeout <= 0 || epInfo.transferType() == USBTransferType.BULK) { + if (timeout <= 0 || epInfo.transferType() == UsbTransferType.BULK) { // no timeout or timeout handled by operating system submitTransferOut(endpointNumber, transfer, timeout); - waitForTransfer(transfer, 0, USBDirection.OUT, endpointNumber); + waitForTransfer(transfer, 0, UsbDirection.OUT, endpointNumber); } else { // interrupt transfer with timeout submitTransferOut(endpointNumber, transfer, 0); - waitForTransfer(transfer, timeout, USBDirection.OUT, endpointNumber); + waitForTransfer(transfer, timeout, UsbDirection.OUT, endpointNumber); } } } } @Override - public byte[] transferIn(int endpointNumber, int timeout) { + public byte @NotNull [] transferIn(int endpointNumber, int timeout) { - var epInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, - USBTransferType.INTERRUPT); + var epInfo = getEndpointInfo(endpointNumber, UsbDirection.IN, UsbTransferType.BULK, + UsbTransferType.INTERRUPT); try (var arena = Arena.ofConfined()) { var nativeData = arena.allocateArray(JAVA_BYTE, epInfo.packetSize()); @@ -469,18 +466,18 @@ public byte[] transferIn(int endpointNumber, int timeout) { var transfer = new MacosTransfer(); transfer.setData(nativeData); transfer.setDataSize(epInfo.packetSize()); - transfer.setCompletion(USBDeviceImpl::onSyncTransferCompleted); + transfer.setCompletion(UsbDeviceImpl::onSyncTransferCompleted); synchronized (transfer) { - if (timeout <= 0 || epInfo.transferType() == USBTransferType.BULK) { + if (timeout <= 0 || epInfo.transferType() == UsbTransferType.BULK) { // no timeout, or timeout handled by operating system submitTransferIn(endpointNumber, transfer, timeout); - waitForTransfer(transfer, 0, USBDirection.IN, endpointNumber); + waitForTransfer(transfer, 0, UsbDirection.IN, endpointNumber); } else { // interrupt transfer with timeout submitTransferIn(endpointNumber, transfer, 0); - waitForTransfer(transfer, timeout, USBDirection.IN, endpointNumber); + waitForTransfer(transfer, timeout, UsbDirection.IN, endpointNumber); } } @@ -500,17 +497,17 @@ public byte[] transferIn(int endpointNumber, int timeout) { */ synchronized void submitTransferIn(int endpointNumber, MacosTransfer transfer, int timeout) { - var epInfo = getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, - USBTransferType.INTERRUPT); + var epInfo = getEndpointInfo(endpointNumber, UsbDirection.IN, UsbTransferType.BULK, + UsbTransferType.INTERRUPT); asyncTask.prepareForSubmission(transfer); // submit transfer int ret; if (timeout <= 0) - ret = IoKitUSB.ReadPipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data(), + ret = IoKitUsb.ReadPipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data(), transfer.dataSize(), asyncTask.nativeCompletionCallback(), MemorySegment.ofAddress(transfer.id())); else - ret = IoKitUSB.ReadPipeAsyncTO(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data(), + ret = IoKitUsb.ReadPipeAsyncTO(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data(), transfer.dataSize(), timeout, timeout, asyncTask.nativeCompletionCallback(), MemorySegment.ofAddress(transfer.id())); @@ -530,17 +527,17 @@ synchronized void submitTransferIn(int endpointNumber, MacosTransfer transfer, i */ synchronized void submitTransferOut(int endpointNumber, MacosTransfer transfer, int timeout) { - var epInfo = getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, - USBTransferType.INTERRUPT); + var epInfo = getEndpointInfo(endpointNumber, UsbDirection.OUT, UsbTransferType.BULK, + UsbTransferType.INTERRUPT); asyncTask.prepareForSubmission(transfer); // submit transfer int ret; if (timeout <= 0) - ret = IoKitUSB.WritePipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data(), + ret = IoKitUsb.WritePipeAsync(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data(), transfer.dataSize(), asyncTask.nativeCompletionCallback(), MemorySegment.ofAddress(transfer.id())); else - ret = IoKitUSB.WritePipeAsyncTO(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data(), + ret = IoKitUsb.WritePipeAsyncTO(epInfo.iokitInterface(), epInfo.pipeIndex(), transfer.data(), transfer.dataSize(), timeout, timeout, asyncTask.nativeCompletionCallback(), MemorySegment.ofAddress(transfer.id())); @@ -560,7 +557,7 @@ synchronized void submitControlTransfer(MemorySegment deviceRequest, MacosTransf asyncTask.prepareForSubmission(transfer); // submit transfer - var ret = IoKitUSB.DeviceRequestAsync(device, deviceRequest, asyncTask.nativeCompletionCallback(), + var ret = IoKitUsb.DeviceRequestAsync(device, deviceRequest, asyncTask.nativeCompletionCallback(), MemorySegment.ofAddress(transfer.id())); if (ret != 0) @@ -573,37 +570,37 @@ protected Transfer createTransfer() { } @Override - public void abortTransfers(USBDirection direction, int endpointNumber) { - var epInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, - USBTransferType.INTERRUPT); + public void abortTransfers(UsbDirection direction, int endpointNumber) { + var epInfo = getEndpointInfo(endpointNumber, direction, UsbTransferType.BULK, + UsbTransferType.INTERRUPT); - var ret = IoKitUSB.AbortPipe(epInfo.iokitInterface(), epInfo.pipeIndex()); + var ret = IoKitUsb.AbortPipe(epInfo.iokitInterface(), epInfo.pipeIndex()); if (ret != 0) throwException(ret, "aborting transfers failed"); } @Override - public void clearHalt(USBDirection direction, int endpointNumber) { - var epInfo = getEndpointInfo(endpointNumber, direction, USBTransferType.BULK, - USBTransferType.INTERRUPT); + public void clearHalt(UsbDirection direction, int endpointNumber) { + var epInfo = getEndpointInfo(endpointNumber, direction, UsbTransferType.BULK, + UsbTransferType.INTERRUPT); - var ret = IoKitUSB.ClearPipeStallBothEnds(epInfo.iokitInterface(), epInfo.pipeIndex()); + var ret = IoKitUsb.ClearPipeStallBothEnds(epInfo.iokitInterface(), epInfo.pipeIndex()); if (ret != 0) throwException(ret, "clearing halt condition failed"); } @Override - public synchronized InputStream openInputStream(int endpointNumber, int bufferSize) { + public synchronized @NotNull InputStream openInputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid - getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, null); + getEndpointInfo(endpointNumber, UsbDirection.IN, UsbTransferType.BULK, null); return new MacosEndpointInputStream(this, endpointNumber, bufferSize); } @Override - public synchronized OutputStream openOutputStream(int endpointNumber, int bufferSize) { + public synchronized @NotNull OutputStream openOutputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid - getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, null); + getEndpointInfo(endpointNumber, UsbDirection.OUT, UsbTransferType.BULK, null); return new MacosEndpointOutputStream(this, endpointNumber, bufferSize); } @@ -613,11 +610,11 @@ protected void throwOSException(int errorCode, String message, Object... args) { throwException(errorCode, message, args); } - private static USBTransferType getTransferType(byte macosTransferType) { + private static UsbTransferType getTransferType(byte macosTransferType) { return switch (macosTransferType) { - case 1 -> USBTransferType.ISOCHRONOUS; - case 2 -> USBTransferType.BULK; - case 3 -> USBTransferType.INTERRUPT; + case 1 -> UsbTransferType.ISOCHRONOUS; + case 2 -> UsbTransferType.BULK; + case 3 -> UsbTransferType.INTERRUPT; default -> null; }; } @@ -625,7 +622,7 @@ private static USBTransferType getTransferType(byte macosTransferType) { private synchronized void addDeviceEventSource() { try (var innerArena = Arena.ofConfined()) { var sourceHolder = innerArena.allocate(ADDRESS); - var ret = IoKitUSB.CreateDeviceAsyncEventSource(device, sourceHolder); + var ret = IoKitUsb.CreateDeviceAsyncEventSource(device, sourceHolder); if (ret != 0) throwException(ret, "internal error (CreateDeviceAsyncEventSource)"); var source = dereference(sourceHolder); @@ -636,7 +633,7 @@ private synchronized void addDeviceEventSource() { private synchronized void addInterfaceEventSource(InterfaceInfo interfaceInfo) { try (var innerArena = Arena.ofConfined()) { var sourceHolder = innerArena.allocate(ADDRESS); - var ret = IoKitUSB.CreateInterfaceAsyncEventSource(interfaceInfo.iokitInterface(), sourceHolder); + var ret = IoKitUsb.CreateInterfaceAsyncEventSource(interfaceInfo.iokitInterface(), sourceHolder); if (ret != 0) throwException(ret, "internal error (CreateInterfaceAsyncEventSource)"); var source = dereference(sourceHolder); @@ -647,6 +644,6 @@ private synchronized void addInterfaceEventSource(InterfaceInfo interfaceInfo) { record InterfaceInfo(MemorySegment iokitInterface, int interfaceNumber) { } - record EndpointInfo(MemorySegment iokitInterface, byte pipeIndex, USBTransferType transferType, int packetSize) { + record EndpointInfo(MemorySegment iokitInterface, byte pipeIndex, UsbTransferType transferType, int packetSize) { } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java similarity index 93% rename from java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java rename to java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java index d2bb8c0a..dbb2ffc5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java @@ -7,9 +7,9 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.USBDevice; +import net.codecrete.usb.UsbDevice; import net.codecrete.usb.common.ScopeCleanup; -import net.codecrete.usb.common.USBDeviceRegistry; +import net.codecrete.usb.common.UsbDeviceRegistry; import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; import net.codecrete.usb.macos.gen.iokit.IOKit; @@ -24,15 +24,15 @@ import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.macos.CoreFoundationHelper.createCFStringRef; -import static net.codecrete.usb.macos.MacosUSBException.throwException; +import static net.codecrete.usb.macos.MacosUsbException.throwException; /** * MacOS implementation of USB device registry. */ @SuppressWarnings("java:S116") -public class MacosUSBDeviceRegistry extends USBDeviceRegistry { +public class MacosUsbDeviceRegistry extends UsbDeviceRegistry { - private static final System.Logger LOG = System.getLogger(MacosUSBDeviceRegistry.class.getName()); + private static final System.Logger LOG = System.getLogger(MacosUsbDeviceRegistry.class.getName()); private static final MemorySegment KEY_ID_VENDOR; private static final MemorySegment KEY_ID_PRODUCT; @@ -80,18 +80,18 @@ protected void monitorDevices() { CoreFoundation.CFRunLoopAddSource(runLoop, runLoopSource, IOKit.kCFRunLoopDefaultMode$get()); // setup notification for connected devices - var onDeviceConnectedMH = MethodHandles.lookup().findVirtual(MacosUSBDeviceRegistry.class, + var onDeviceConnectedMH = MethodHandles.lookup().findVirtual(MacosUsbDeviceRegistry.class, "onDevicesConnected", MethodType.methodType(void.class, MemorySegment.class, int.class)); var deviceConnectedIter = setupNotification(arena, notifyPort, IOKit.kIOFirstMatchNotification(), onDeviceConnectedMH); // iterate current devices in order to arm the notifications (and build initial device list) - var deviceList = new ArrayList(); + var deviceList = new ArrayList(); iterateDevices(deviceConnectedIter, device -> deviceList.add(device)); // NOSONAR setInitialDeviceList(deviceList); // setup notification for disconnected devices - var onDeviceDisconnectedMH = MethodHandles.lookup().findVirtual(MacosUSBDeviceRegistry.class, + var onDeviceDisconnectedMH = MethodHandles.lookup().findVirtual(MacosUsbDeviceRegistry.class, "onDevicesDisconnected", MethodType.methodType(void.class, MemorySegment.class, int.class)); var deviceDisconnectedIter = setupNotification(arena, notifyPort, IOKit.kIOTerminatedNotification(), onDeviceDisconnectedMH); @@ -130,7 +130,7 @@ private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { var device = IoKitHelper.getInterface(service, IoKitHelper.kIOUSBDeviceUserClientTypeID, IoKitHelper.kIOUSBDeviceInterfaceID187); if (device != null) - cleanup.add(() -> IoKitUSB.Release(device)); + cleanup.add(() -> IoKitUsb.Release(device)); // get entry ID (as unique ID) var ret = IOKit.IORegistryEntryGetRegistryEntryID(service, entryIdHolder); @@ -148,7 +148,7 @@ private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { /** * Calls the consumer for all devices produced by the iterator. *

- * This method tries to create a {@link USBDevice} instance. + * This method tries to create a {@link UsbDevice} instance. * If it fails, an information is printed, but the consumer is not called. *

* @@ -156,7 +156,7 @@ private void iterateDevices(int iterator, IOKitDeviceConsumer consumer) { * @param consumer the consumer */ @SuppressWarnings("java:S106") - private void iterateDevices(int iterator, Consumer consumer) { + private void iterateDevices(int iterator, Consumer consumer) { iterateDevices(iterator, (entryId, service, deviceIntf) -> { var deviceInfo = new VidPid(); @@ -172,7 +172,7 @@ private void iterateDevices(int iterator, Consumer consumer) { }); } - private USBDevice createDevice(Long entryID, int service, MemorySegment deviceIntf, VidPid info) { + private UsbDevice createDevice(Long entryID, int service, MemorySegment deviceIntf, VidPid info) { if (deviceIntf == null) return null; @@ -187,7 +187,7 @@ private USBDevice createDevice(Long entryID, int service, MemorySegment deviceIn info.vid = vendorId; info.pid = productId; - var device = new MacosUSBDevice(deviceIntf, entryID, vendorId, productId); + var device = new MacosUsbDevice(deviceIntf, entryID, vendorId, productId); var manufacturer = IoKitHelper.getPropertyString(service, KEY_VENDOR, arena); var product = IoKitHelper.getPropertyString(service, KEY_PRODUCT, arena); @@ -267,7 +267,7 @@ private void onDevicesDisconnected(MemorySegment ignoredRefCon, int iterator) { return; try { - ((MacosUSBDevice) device).closeFully(); + ((MacosUsbDevice) device).closeFully(); } catch (Exception e) { LOG.log(INFO, "failed to close USB device - ignoring exception", e); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbException.java similarity index 79% rename from java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java rename to java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbException.java index 90653942..3f0c6070 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbException.java @@ -6,16 +6,16 @@ // package net.codecrete.usb.macos; -import net.codecrete.usb.USBException; -import net.codecrete.usb.USBStallException; -import net.codecrete.usb.USBTimeoutException; +import net.codecrete.usb.UsbException; +import net.codecrete.usb.UsbStallException; +import net.codecrete.usb.UsbTimeoutException; import net.codecrete.usb.macos.gen.iokit.IOKit; import net.codecrete.usb.macos.gen.mach.mach; /** * Exception thrown if a macOS specific error occurs. */ -public class MacosUSBException extends USBException { +public class MacosUsbException extends UsbException { /** * Creates a new instance. @@ -26,7 +26,7 @@ public class MacosUSBException extends USBException { * @param message exception message * @param errorCode macOS error code (usually returned by macOS functions) */ - public MacosUSBException(String message, int errorCode) { + public MacosUsbException(String message, int errorCode) { super(String.format("%s: %s", message, machErrorMessage(errorCode)), errorCode); } @@ -48,11 +48,11 @@ private static String machErrorMessage(int errorCode) { static void throwException(int errorCode, String message, Object... args) { var formattedMessage = String.format(message, args); if (errorCode == IOKit.kIOUSBPipeStalled()) { - throw new USBStallException(formattedMessage); + throw new UsbStallException(formattedMessage); } else if (errorCode == IOKit.kIOUSBTransactionTimeout()) { - throw new USBTimeoutException(formattedMessage); + throw new UsbTimeoutException(formattedMessage); } else { - throw new MacosUSBException(formattedMessage, errorCode); + throw new MacosUsbException(formattedMessage, errorCode); } } @@ -63,7 +63,7 @@ static void throwException(int errorCode, String message, Object... args) { * @param args arguments for exception message */ static void throwException(String message, Object... args) { - throw new USBException(String.format(message, args)); + throw new UsbException(String.format(message, args)); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java index 623168f5..095c85ba 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java @@ -20,8 +20,8 @@ import static java.lang.foreign.ValueLayout.JAVA_INT; import static net.codecrete.usb.windows.DevicePropertyKey.Service; import static net.codecrete.usb.windows.Win.allocateErrorState; -import static net.codecrete.usb.windows.WindowsUSBException.throwException; -import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; +import static net.codecrete.usb.windows.WindowsUsbException.throwException; +import static net.codecrete.usb.windows.WindowsUsbException.throwLastError; /** * Device information set (of Windows Setup API). diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBConstants.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/UsbConstants.java similarity index 95% rename from java-does-usb/src/main/java/net/codecrete/usb/windows/USBConstants.java rename to java-does-usb/src/main/java/net/codecrete/usb/windows/UsbConstants.java index c4e18577..da14dffe 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/USBConstants.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/UsbConstants.java @@ -13,9 +13,9 @@ * USB constants (general ones and Windows specific ones) */ @SuppressWarnings({"java:S125", "java:S1192", "java:S115", "java:S100"}) -class USBConstants { +class UsbConstants { - private USBConstants() { + private UsbConstants() { } static final byte USB_REQUEST_GET_DESCRIPTOR = 0x06; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java index 3a509650..afc66e37 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java @@ -21,7 +21,7 @@ import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.windows.Win.allocateErrorState; -import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; +import static net.codecrete.usb.windows.WindowsUsbException.throwLastError; /** * Background task for handling asynchronous transfers. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java index d331954e..0c96fc94 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java @@ -7,23 +7,23 @@ package net.codecrete.usb.windows; -import net.codecrete.usb.USBDirection; +import net.codecrete.usb.UsbDirection; import net.codecrete.usb.common.EndpointInputStream; import net.codecrete.usb.common.Transfer; public class WindowsEndpointInputStream extends EndpointInputStream { - WindowsEndpointInputStream(WindowsUSBDevice device, int endpointNumber, int bufferSize) { + WindowsEndpointInputStream(WindowsUsbDevice device, int endpointNumber, int bufferSize) { super(device, endpointNumber, bufferSize); } @Override protected void submitTransferIn(Transfer transfer) { - ((WindowsUSBDevice) device).submitTransferIn(endpointNumber, (WindowsTransfer) transfer); + ((WindowsUsbDevice) device).submitTransferIn(endpointNumber, (WindowsTransfer) transfer); } @Override protected void configureEndpoint() { - ((WindowsUSBDevice) device).configureForAsyncIo(USBDirection.IN, endpointNumber); + ((WindowsUsbDevice) device).configureForAsyncIo(UsbDirection.IN, endpointNumber); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java index 46eb0f31..8125dd5a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointOutputStream.java @@ -7,23 +7,23 @@ package net.codecrete.usb.windows; -import net.codecrete.usb.USBDirection; +import net.codecrete.usb.UsbDirection; import net.codecrete.usb.common.EndpointOutputStream; import net.codecrete.usb.common.Transfer; public class WindowsEndpointOutputStream extends EndpointOutputStream { - WindowsEndpointOutputStream(WindowsUSBDevice device, int endpointNumber, int bufferSize) { + WindowsEndpointOutputStream(WindowsUsbDevice device, int endpointNumber, int bufferSize) { super(device, endpointNumber, bufferSize); } @Override protected void submitTransferOut(Transfer request) { - ((WindowsUSBDevice) device).submitTransferOut(endpointNumber, (WindowsTransfer) request); + ((WindowsUsbDevice) device).submitTransferOut(endpointNumber, (WindowsTransfer) request); } @Override protected void configureEndpoint() { - ((WindowsUSBDevice) device).configureForAsyncIo(USBDirection.OUT, endpointNumber); + ((WindowsUsbDevice) device).configureForAsyncIo(UsbDirection.OUT, endpointNumber); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java similarity index 86% rename from java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java rename to java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java index f2d2d730..28dce237 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java @@ -9,12 +9,13 @@ import net.codecrete.usb.*; import net.codecrete.usb.common.Transfer; -import net.codecrete.usb.common.USBDeviceImpl; +import net.codecrete.usb.common.UsbDeviceImpl; import net.codecrete.usb.usbstandard.SetupPacket; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.winusb.WinUSB; import net.codecrete.usb.windows.winsdk.Kernel32B; import net.codecrete.usb.windows.winsdk.WinUSB2; +import org.jetbrains.annotations.NotNull; import java.io.InputStream; import java.io.OutputStream; @@ -33,16 +34,16 @@ import static net.codecrete.usb.windows.DevicePropertyKey.Children; import static net.codecrete.usb.windows.DevicePropertyKey.HardwareIds; import static net.codecrete.usb.windows.Win.allocateErrorState; -import static net.codecrete.usb.windows.WindowsUSBException.throwException; -import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; +import static net.codecrete.usb.windows.WindowsUsbException.throwException; +import static net.codecrete.usb.windows.WindowsUsbException.throwLastError; /** * Windows implementation for USB device. */ @SuppressWarnings("java:S2160") -public class WindowsUSBDevice extends USBDeviceImpl { +public class WindowsUsbDevice extends UsbDeviceImpl { - private static final System.Logger LOG = System.getLogger(WindowsUSBDevice.class.getName()); + private static final System.Logger LOG = System.getLogger(WindowsUsbDevice.class.getName()); private final WindowsAsyncTask asyncTask; /** @@ -61,7 +62,7 @@ public class WindowsUSBDevice extends USBDeviceImpl { */ private boolean showAsOpen; - WindowsUSBDevice(String devicePath, int vendorId, int productId, MemorySegment configDesc, boolean isComposite) { + WindowsUsbDevice(String devicePath, int vendorId, int productId, MemorySegment configDesc, boolean isComposite) { super(devicePath, vendorId, productId); asyncTask = WindowsAsyncTask.INSTANCE; this.isComposite = isComposite; @@ -76,7 +77,7 @@ private void readDescription(MemorySegment configDesc) { // build list of interface handles interfaceHandles = configuration.interfaces().stream() .map(intf -> { - var interfaceNumber = intf.number(); + var interfaceNumber = intf.getNumber(); var function = configuration.findFunction(interfaceNumber); return new InterfaceHandle(interfaceNumber, function.firstInterfaceNumber()); }). @@ -84,13 +85,13 @@ private void readDescription(MemorySegment configDesc) { } @Override - public boolean isOpen() { + public boolean isOpened() { return showAsOpen; } @Override public synchronized void open() { - if (isOpen()) + if (isOpened()) throwException("device is already open"); showAsOpen = true; @@ -98,12 +99,12 @@ public synchronized void open() { @Override public synchronized void close() { - if (!isOpen()) + if (!isOpened()) return; for (var intf : interfaceList) { if (intf.isClaimed()) - releaseInterface(intf.number()); + releaseInterface(intf.getNumber()); } showAsOpen = false; @@ -121,7 +122,7 @@ public void claimInterface(int interfaceNumber) { numRetries -= 1; if (numRetries == 0) - throw new USBException("claiming interface failed (function has no device path / interface GUID, might be missing WinUSB driver)"); + throw new UsbException("claiming interface failed (function has no device path / interface GUID, might be missing WinUSB driver)"); // sleep and retry try { @@ -206,9 +207,6 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna // check alternate setting var altSetting = intf.getAlternate(alternateNumber); - if (altSetting == null) - throwException("interface %d does not have an alternate interface setting %d", interfaceNumber, - alternateNumber); try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); @@ -251,7 +249,7 @@ public synchronized void releaseInterface(int interfaceNumber) { } @Override - public void controlTransferOut(USBControlTransfer setup, byte[] data) { + public void controlTransferOut(@NotNull UsbControlTransfer setup, byte[] data) { try (var arena = Arena.ofConfined()) { // copy data to native memory @@ -267,22 +265,22 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) { } synchronized (transfer) { - submitControlTransfer(USBDirection.OUT, setup, transfer); - waitForTransfer(transfer, 0, USBDirection.OUT, 0); + submitControlTransfer(UsbDirection.OUT, setup, transfer); + waitForTransfer(transfer, 0, UsbDirection.OUT, 0); } } } @Override - public byte[] controlTransferIn(USBControlTransfer setup, int length) { + public byte @NotNull [] controlTransferIn(@NotNull UsbControlTransfer setup, int length) { try (var arena = Arena.ofConfined()) { var transfer = createSyncControlTransfer(); transfer.setData(arena.allocate(length)); transfer.setDataSize(length); synchronized (transfer) { - submitControlTransfer(USBDirection.IN, setup, transfer); - waitForTransfer(transfer, 0, USBDirection.IN, 0); + submitControlTransfer(UsbDirection.IN, setup, transfer); + waitForTransfer(transfer, 0, UsbDirection.IN, 0); } return transfer.data().asSlice(0, transfer.resultSize()).toArray(JAVA_BYTE); @@ -290,7 +288,7 @@ public byte[] controlTransferIn(USBControlTransfer setup, int length) { } @Override - public void transferOut(int endpointNumber, byte[] data, int offset, int length, int timeout) { + public void transferOut(int endpointNumber, byte @NotNull [] data, int offset, int length, int timeout) { try (var arena = Arena.ofConfined()) { var buffer = arena.allocate(data.length); buffer.copyFrom(MemorySegment.ofArray(data).asSlice(offset, length)); @@ -298,14 +296,14 @@ public void transferOut(int endpointNumber, byte[] data, int offset, int length, synchronized (transfer) { submitTransferOut(endpointNumber, transfer); - waitForTransfer(transfer, timeout, USBDirection.OUT, endpointNumber); + waitForTransfer(transfer, timeout, UsbDirection.OUT, endpointNumber); } } } @Override - public byte[] transferIn(int endpointNumber, int timeout) { - var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); + public byte @NotNull [] transferIn(int endpointNumber, int timeout) { + var endpoint = getEndpoint(UsbDirection.IN, endpointNumber, UsbTransferType.BULK, UsbTransferType.INTERRUPT); try (var arena = Arena.ofConfined()) { var buffer = arena.allocate(endpoint.packetSize()); @@ -313,7 +311,7 @@ public byte[] transferIn(int endpointNumber, int timeout) { synchronized (transfer) { submitTransferIn(endpointNumber, transfer); - waitForTransfer(transfer, timeout, USBDirection.IN, endpointNumber); + waitForTransfer(transfer, timeout, UsbDirection.IN, endpointNumber); } return buffer.asSlice(0, transfer.resultSize()).toArray(JAVA_BYTE); @@ -322,7 +320,7 @@ public byte[] transferIn(int endpointNumber, int timeout) { private WindowsTransfer createSyncControlTransfer() { var transfer = new WindowsTransfer(); - transfer.setCompletion(USBDeviceImpl::onSyncTransferCompleted); + transfer.setCompletion(UsbDeviceImpl::onSyncTransferCompleted); return transfer; } @@ -330,7 +328,7 @@ private WindowsTransfer createSyncTransfer(MemorySegment data) { var transfer = new WindowsTransfer(); transfer.setData(data); transfer.setDataSize((int) data.byteSize()); - transfer.setCompletion(USBDeviceImpl::onSyncTransferCompleted); + transfer.setCompletion(UsbDeviceImpl::onSyncTransferCompleted); return transfer; } @@ -344,14 +342,14 @@ protected void throwOSException(int errorCode, String message, Object... args) { throwException(errorCode, message, args); } - synchronized void submitControlTransfer(USBDirection direction, USBControlTransfer setup, WindowsTransfer transfer) { + synchronized void submitControlTransfer(UsbDirection direction, UsbControlTransfer setup, WindowsTransfer transfer) { checkIsOpen(); var intfHandle = findControlTransferInterface(setup); try (var arena = Arena.ofConfined()) { var setupPacket = new SetupPacket(arena); var bmRequest = - (direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); + (direction == UsbDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); setupPacket.setRequestType(bmRequest); setupPacket.setRequest(setup.request()); setupPacket.setValue(setup.value()); @@ -372,7 +370,7 @@ synchronized void submitControlTransfer(USBDirection direction, USBControlTransf } synchronized void submitTransferOut(int endpointNumber, WindowsTransfer transfer) { - var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); + var endpoint = getEndpoint(UsbDirection.OUT, endpointNumber, UsbTransferType.BULK, UsbTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.ofConfined()) { @@ -390,7 +388,7 @@ synchronized void submitTransferOut(int endpointNumber, WindowsTransfer transfer } synchronized void submitTransferIn(int endpointNumber, WindowsTransfer transfer) { - var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); + var endpoint = getEndpoint(UsbDirection.IN, endpointNumber, UsbTransferType.BULK, UsbTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.ofConfined()) { @@ -407,8 +405,8 @@ synchronized void submitTransferIn(int endpointNumber, WindowsTransfer transfer) } } - synchronized void configureForAsyncIo(USBDirection direction, int endpointNumber) { - var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); + synchronized void configureForAsyncIo(UsbDirection direction, int endpointNumber) { + var endpoint = getEndpoint(direction, endpointNumber, UsbTransferType.BULK, UsbTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.ofConfined()) { @@ -427,8 +425,8 @@ synchronized void configureForAsyncIo(USBDirection direction, int endpointNumber } @Override - public synchronized void clearHalt(USBDirection direction, int endpointNumber) { - var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); + public synchronized void clearHalt(UsbDirection direction, int endpointNumber) { + var endpoint = getEndpoint(direction, endpointNumber, UsbTransferType.BULK, UsbTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.ofConfined()) { @@ -439,8 +437,8 @@ public synchronized void clearHalt(USBDirection direction, int endpointNumber) { } @Override - public synchronized void abortTransfers(USBDirection direction, int endpointNumber) { - var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT); + public synchronized void abortTransfers(UsbDirection direction, int endpointNumber) { + var endpoint = getEndpoint(direction, endpointNumber, UsbTransferType.BULK, UsbTransferType.INTERRUPT); var intfHandle = getInterfaceHandle(endpoint.interfaceNumber()); try (var arena = Arena.ofConfined()) { @@ -451,17 +449,17 @@ public synchronized void abortTransfers(USBDirection direction, int endpointNumb } @Override - public synchronized InputStream openInputStream(int endpointNumber, int bufferSize) { + public synchronized @NotNull InputStream openInputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid - getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, null); + getEndpoint(UsbDirection.IN, endpointNumber, UsbTransferType.BULK, null); return new WindowsEndpointInputStream(this, endpointNumber, bufferSize); } @Override - public synchronized OutputStream openOutputStream(int endpointNumber, int bufferSize) { + public synchronized @NotNull OutputStream openOutputStream(int endpointNumber, int bufferSize) { // check that endpoint number is valid - getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, null); + getEndpoint(UsbDirection.OUT, endpointNumber, UsbTransferType.BULK, null); return new WindowsEndpointOutputStream(this, endpointNumber, bufferSize); } @@ -476,19 +474,19 @@ private InterfaceHandle getInterfaceHandle(int interfaceNumber) { throw new AssertionError("not reached"); } - private InterfaceHandle findControlTransferInterface(USBControlTransfer setup) { + private InterfaceHandle findControlTransferInterface(UsbControlTransfer setup) { var interfaceNumber = -1; int endpointNumber; - if (setup.recipient() == USBRecipient.INTERFACE) { + if (setup.recipient() == UsbRecipient.INTERFACE) { interfaceNumber = setup.index() & 0xff; - } else if (setup.recipient() == USBRecipient.ENDPOINT) { + } else if (setup.recipient() == UsbRecipient.ENDPOINT) { endpointNumber = setup.index() & 0x7f; - var direction = (setup.index() & 0x80) != 0 ? USBDirection.IN : USBDirection.OUT; + var direction = (setup.index() & 0x80) != 0 ? UsbDirection.IN : UsbDirection.OUT; if (endpointNumber != 0) { interfaceNumber = getInterfaceNumber(direction, endpointNumber); if (interfaceNumber == -1) @@ -568,7 +566,7 @@ private String getChildDevicePath(String instanceId, int interfaceNumber) { var devicePath = deviceInfoSet.getDevicePathByGUID(instanceId); if (devicePath == null) { LOG.log(INFO, "Child device {0} has no device path / interface GUID", instanceId); - throw new USBException("claiming interface failed (function has no device path / interface GUID, might be missing WinUSB driver)"); + throw new UsbException("claiming interface failed (function has no device path / interface GUID, might be missing WinUSB driver)"); } if (devicePaths == null) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java similarity index 92% rename from java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java rename to java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java index bc8ab227..03fe5dc2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java @@ -7,11 +7,11 @@ package net.codecrete.usb.windows; -import net.codecrete.usb.USBDevice; -import net.codecrete.usb.USBException; +import net.codecrete.usb.UsbDevice; +import net.codecrete.usb.UsbException; import net.codecrete.usb.common.ScopeCleanup; -import net.codecrete.usb.common.USBDeviceImpl; -import net.codecrete.usb.common.USBDeviceRegistry; +import net.codecrete.usb.common.UsbDeviceImpl; +import net.codecrete.usb.common.UsbDeviceRegistry; import net.codecrete.usb.usbstandard.ConfigurationDescriptor; import net.codecrete.usb.usbstandard.DeviceDescriptor; import net.codecrete.usb.usbstandard.SetupPacket; @@ -37,11 +37,11 @@ import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.usbstandard.Constants.*; import static net.codecrete.usb.windows.DevicePropertyKey.*; -import static net.codecrete.usb.windows.USBConstants.GUID_DEVINTERFACE_USB_DEVICE; -import static net.codecrete.usb.windows.USBConstants.GUID_DEVINTERFACE_USB_HUB; +import static net.codecrete.usb.windows.UsbConstants.GUID_DEVINTERFACE_USB_DEVICE; +import static net.codecrete.usb.windows.UsbConstants.GUID_DEVINTERFACE_USB_HUB; import static net.codecrete.usb.windows.Win.allocateErrorState; -import static net.codecrete.usb.windows.WindowsUSBException.throwException; -import static net.codecrete.usb.windows.WindowsUSBException.throwLastError; +import static net.codecrete.usb.windows.WindowsUsbException.throwException; +import static net.codecrete.usb.windows.WindowsUsbException.throwLastError; /** * Windows implementation of USB device registry. @@ -51,9 +51,9 @@ * the device's port number is needed. *

*/ -public class WindowsUSBDeviceRegistry extends USBDeviceRegistry { +public class WindowsUsbDeviceRegistry extends UsbDeviceRegistry { - private static final System.Logger LOG = System.getLogger(WindowsUSBDeviceRegistry.class.getName()); + private static final System.Logger LOG = System.getLogger(WindowsUsbDeviceRegistry.class.getName()); private static final long REQUEST_DATA_OFFSET = _USB_DESCRIPTOR_REQUEST.$LAYOUT().byteOffset(PathElement.groupElement("Data")); @@ -71,7 +71,7 @@ protected void monitorDevices() { final var instance = Kernel32.GetModuleHandleW(NULL); // create upcall for handling window messages - var handleWindowMessageMH = MethodHandles.lookup().findVirtual(WindowsUSBDeviceRegistry.class, + var handleWindowMessageMH = MethodHandles.lookup().findVirtual(WindowsUsbDeviceRegistry.class, "handleWindowMessage", MethodType.methodType(long.class, MemorySegment.class, int.class, long.class, long.class)).bindTo(this); var handleWindowMessageStub = Linker.nativeLinker().upcallStub(handleWindowMessageMH, @@ -128,7 +128,7 @@ protected void monitorDevices() { @SuppressWarnings("java:S106") private void enumeratePresentDevices() { - List deviceList = new ArrayList<>(); + List deviceList = new ArrayList<>(); try (var cleanup = new ScopeCleanup(); var deviceInfoSet = DeviceInfoSet.ofPresentDevices(GUID_DEVINTERFACE_USB_DEVICE, null)) { @@ -154,7 +154,7 @@ private void enumeratePresentDevices() { } } - private USBDevice createDeviceFromDeviceInfo(DeviceInfoSet deviceInfoSet, String devicePath, + private UsbDevice createDeviceFromDeviceInfo(DeviceInfoSet deviceInfoSet, String devicePath, HashMap hubHandles) { try (var arena = Arena.ofConfined()) { @@ -179,14 +179,14 @@ private USBDevice createDeviceFromDeviceInfo(DeviceInfoSet deviceInfoSet, String } /** - * Retrieve device descriptor and create {@code USBDevice} instance + * Retrieve device descriptor and create {@code UsbDevice} instance * * @param devicePath the device path * @param hubHandle the hub handle (parent) * @param usbPortNum the USB port number - * @return the {@code USBDevice} instance + * @return the {@code UsbDevice} instance */ - private USBDevice createDevice(String devicePath, boolean isComposite, MemorySegment hubHandle, int usbPortNum) { + private UsbDevice createDevice(String devicePath, boolean isComposite, MemorySegment hubHandle, int usbPortNum) { try (var arena = Arena.ofConfined()) { @@ -209,7 +209,7 @@ private USBDevice createDevice(String devicePath, boolean isComposite, MemorySeg var configDesc = getDescriptor(hubHandle, usbPortNum, CONFIGURATION_DESCRIPTOR_TYPE, 0, (short) 0, arena); // create new device - var device = new WindowsUSBDevice(devicePath, vendorId, productId, configDesc, isComposite); + var device = new WindowsUsbDevice(devicePath, vendorId, productId, configDesc, isComposite); device.setFromDeviceDescriptor(descriptorSegment); device.setProductString(descriptorSegment, index -> getStringDescriptor(hubHandle, usbPortNum, index)); @@ -232,7 +232,7 @@ private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, _USB_DESCRIPTOR_REQUEST.ConnectionIndex$set(descriptorRequest, usbPortNumber); var setupPacket = new SetupPacket(_USB_DESCRIPTOR_REQUEST.SetupPacket$slice(descriptorRequest)); setupPacket.setRequestType(0x80); // device-to-host / type standard / recipient device - setupPacket.setRequest(USBConstants.USB_REQUEST_GET_DESCRIPTOR); + setupPacket.setRequest(UsbConstants.USB_REQUEST_GET_DESCRIPTOR); setupPacket.setValue((descriptorType << 8) | index); setupPacket.setIndex(languageID); setupPacket.setLength(size - (int) REQUEST_DATA_OFFSET); @@ -277,7 +277,7 @@ private String getStringDescriptor(MemorySegment hubHandle, int usbPortNumber, i index, DEFAULT_LANGUAGE, arena)); return stringDesc.string(); - } catch (USBException e) { + } catch (UsbException e) { return null; } } @@ -344,10 +344,10 @@ private void onDeviceDisconnected(String devicePath) { * @return index, or -1 if not found */ @Override - protected int findDeviceIndex(List deviceList, Object deviceId) { + protected int findDeviceIndex(List deviceList, Object deviceId) { var id = deviceId.toString(); for (var i = 0; i < deviceList.size(); i++) { - var dev = (USBDeviceImpl) deviceList.get(i); + var dev = (UsbDeviceImpl) deviceList.get(i); if (id.equalsIgnoreCase(dev.getUniqueId().toString())) return i; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbException.java similarity index 91% rename from java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java rename to java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbException.java index 7b93a575..734a03f1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbException.java @@ -6,8 +6,8 @@ // package net.codecrete.usb.windows; -import net.codecrete.usb.USBException; -import net.codecrete.usb.USBStallException; +import net.codecrete.usb.UsbException; +import net.codecrete.usb.UsbStallException; import net.codecrete.usb.windows.gen.kernel32.Kernel32; import net.codecrete.usb.windows.gen.ntdll.NtDll; @@ -21,7 +21,7 @@ /** * Exception thrown if a Windows specific error occurs. */ -public class WindowsUSBException extends USBException { +public class WindowsUsbException extends UsbException { /** * Creates a new instance. @@ -32,7 +32,7 @@ public class WindowsUSBException extends USBException { * @param message exception message * @param errorCode Windows error code (usually returned from {@code GetLastError()}) */ - public WindowsUSBException(String message, int errorCode) { + public WindowsUsbException(String message, int errorCode) { super(String.format("%s: %s", message, getErrorMessage(errorCode)), errorCode); } @@ -49,9 +49,9 @@ public WindowsUSBException(String message, int errorCode) { static void throwException(int errorCode, String message, Object... args) { var formattedMessage = String.format(message, args); if (errorCode == Kernel32.ERROR_GEN_FAILURE() || errorCode == NtDll.STATUS_UNSUCCESSFUL()) { - throw new USBStallException(formattedMessage); + throw new UsbStallException(formattedMessage); } else { - throw new WindowsUSBException(formattedMessage, errorCode); + throw new WindowsUsbException(formattedMessage, errorCode); } } @@ -62,7 +62,7 @@ static void throwException(int errorCode, String message, Object... args) { * @param args arguments for exception message */ static void throwException(String message, Object... args) { - throw new USBException(String.format(message, args)); + throw new UsbException(String.format(message, args)); } /** diff --git a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java index 857b9b61..2cf058b2 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java @@ -28,19 +28,19 @@ void selectAlternateIntf_succeeds() { testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 1); - var altIntf = testDevice.getInterface(LOOPBACK_INTF_LOOPBACK).alternate(); + var altIntf = testDevice.getInterface(LOOPBACK_INTF_LOOPBACK).getCurrentAlternate(); assertNotNull(altIntf); - assertEquals(2, altIntf.endpoints().size()); - assertEquals(0xff, altIntf.classCode()); + assertEquals(2, altIntf.getEndpoints().size()); + assertEquals(0xff, altIntf.getClassCode()); testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 0); } @Test void selectInvalidAlternateIntf_fails() { - assertThrows(USBException.class, () -> testDevice.selectAlternateSetting(1, 0)); + assertThrows(UsbException.class, () -> testDevice.selectAlternateSetting(1, 0)); - assertThrows(USBException.class, () -> testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 2)); + assertThrows(UsbException.class, () -> testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 2)); } @Test @@ -57,8 +57,8 @@ void transferOnValidEndpoint_succeeds() { void transferOnInvalidEndpoint_fails() { testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 1); - assertThrows(USBException.class, () -> testDevice.transferOut(ECHO_EP_OUT, new byte[] { 1, 2, 3 })); + assertThrows(UsbException.class, () -> testDevice.transferOut(ECHO_EP_OUT, new byte[] { 1, 2, 3 })); - assertThrows(USBException.class, () -> testDevice.transferIn(ECHO_EP_IN)); + assertThrows(UsbException.class, () -> testDevice.transferIn(ECHO_EP_IN)); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java index 2418fd93..da1f5c7c 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java @@ -39,8 +39,8 @@ void mediumTransfer_succeeds() { @Test void transferWithZLP_succeeds() { - var inEndpoint = testDevice.getEndpoint(USBDirection.IN, LOOPBACK_EP_IN); - var sampleData = generateRandomBytes(inEndpoint.packetSize(), 97333894); + var inEndpoint = testDevice.getEndpoint(UsbDirection.IN, LOOPBACK_EP_IN); + var sampleData = generateRandomBytes(inEndpoint.getPacketSize(), 97333894); testDevice.transferOut(LOOPBACK_EP_OUT, sampleData); testDevice.transferOut(LOOPBACK_EP_OUT, new byte[0]); var data = testDevice.transferIn(LOOPBACK_EP_IN); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java b/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java index 6a3d11d8..ee55be37 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java @@ -20,16 +20,16 @@ void simpleDescriptor_canBeParsed() { softly.assertThat(configuration.interfaces()) .hasSize(1) .singleElement().satisfies(intf -> { - softly.assertThat(intf.number()).isEqualTo(0); - softly.assertThat(intf.alternates()) + softly.assertThat(intf.getNumber()).isEqualTo(0); + softly.assertThat(intf.getAlternates()) .hasSize(1) .singleElement().satisfies(altIntf -> { - softly.assertThat(altIntf).isSameAs(intf.alternate()); - softly.assertThat(altIntf.number()).isEqualTo(0); - softly.assertThat(altIntf.endpoints()).isEmpty(); - softly.assertThat(altIntf.classCode()).isEqualTo(0x0ff); - softly.assertThat(altIntf.subclassCode()).isEqualTo(0x0dd); - softly.assertThat(altIntf.protocolCode()).isEqualTo(0x0cc); + softly.assertThat(altIntf).isSameAs(intf.getCurrentAlternate()); + softly.assertThat(altIntf.getNumber()).isEqualTo(0); + softly.assertThat(altIntf.getEndpoints()).isEmpty(); + softly.assertThat(altIntf.getClassCode()).isEqualTo(0x0ff); + softly.assertThat(altIntf.getSubclassCode()).isEqualTo(0x0dd); + softly.assertThat(altIntf.getProtocolCode()).isEqualTo(0x0cc); }); softly.assertThat(intf.isClaimed()).isFalse(); }); @@ -67,65 +67,65 @@ void largeCompositeDescriptor_canBeParsed() { // interface 0 softly.assertThat(configuration.interfaces().get(0)).satisfies(intf -> { - softly.assertThat(intf.number()).isEqualTo(0); - softly.assertThat(intf.alternates()).hasSize(1); - softly.assertThat(intf.alternate().endpoints()).hasSize(1); - softly.assertThat(intf.alternate().endpoints().get(0)).satisfies(endpoint -> { - softly.assertThat(endpoint.number()).isEqualTo(5); - softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.IN); - softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.INTERRUPT); + softly.assertThat(intf.getNumber()).isEqualTo(0); + softly.assertThat(intf.getAlternates()).hasSize(1); + softly.assertThat(intf.getCurrentAlternate().getEndpoints()).hasSize(1); + softly.assertThat(intf.getCurrentAlternate().getEndpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(endpoint.getNumber()).isEqualTo(5); + softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); + softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.INTERRUPT); }); }); // interface 1 softly.assertThat(configuration.interfaces().get(1)).satisfies(intf -> { - softly.assertThat(intf.number()).isEqualTo(1); - softly.assertThat(intf.alternates()).hasSize(2); - softly.assertThat(intf.alternates().get(0)).satisfies(alternate -> { - softly.assertThat(alternate.number()).isEqualTo(0); - softly.assertThat(alternate.endpoints()).isEmpty(); + softly.assertThat(intf.getNumber()).isEqualTo(1); + softly.assertThat(intf.getAlternates()).hasSize(2); + softly.assertThat(intf.getAlternates().get(0)).satisfies(alternate -> { + softly.assertThat(alternate.getNumber()).isEqualTo(0); + softly.assertThat(alternate.getEndpoints()).isEmpty(); }); - softly.assertThat(intf.alternates().get(1)).satisfies(alternate -> { - softly.assertThat(alternate.number()).isEqualTo(1); - softly.assertThat(alternate.endpoints()).hasSize(1); - softly.assertThat(alternate.endpoints().get(0)).satisfies(endpoint -> { - softly.assertThat(endpoint.number()).isEqualTo(1); - softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.IN); - softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.ISOCHRONOUS); + softly.assertThat(intf.getAlternates().get(1)).satisfies(alternate -> { + softly.assertThat(alternate.getNumber()).isEqualTo(1); + softly.assertThat(alternate.getEndpoints()).hasSize(1); + softly.assertThat(alternate.getEndpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(endpoint.getNumber()).isEqualTo(1); + softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); + softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.ISOCHRONOUS); }); }); }); // interface 2 softly.assertThat(configuration.interfaces().get(2)).satisfies(intf -> { - softly.assertThat(intf.number()).isEqualTo(2); - softly.assertThat(intf.alternates()).hasSize(2); - softly.assertThat(intf.alternates().get(0)).satisfies(alternate -> { - softly.assertThat(alternate.number()).isEqualTo(0); - softly.assertThat(alternate.endpoints()).isEmpty(); + softly.assertThat(intf.getNumber()).isEqualTo(2); + softly.assertThat(intf.getAlternates()).hasSize(2); + softly.assertThat(intf.getAlternates().get(0)).satisfies(alternate -> { + softly.assertThat(alternate.getNumber()).isEqualTo(0); + softly.assertThat(alternate.getEndpoints()).isEmpty(); }); - softly.assertThat(intf.alternates().get(1)).satisfies(alternate -> { - softly.assertThat(alternate.number()).isEqualTo(1); - softly.assertThat(alternate.endpoints()).hasSize(1); - softly.assertThat(alternate.endpoints().get(0)).satisfies(endpoint -> { - softly.assertThat(endpoint.number()).isEqualTo(2); - softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.IN); - softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.ISOCHRONOUS); + softly.assertThat(intf.getAlternates().get(1)).satisfies(alternate -> { + softly.assertThat(alternate.getNumber()).isEqualTo(1); + softly.assertThat(alternate.getEndpoints()).hasSize(1); + softly.assertThat(alternate.getEndpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(endpoint.getNumber()).isEqualTo(2); + softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); + softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.ISOCHRONOUS); }); }); }); // interface 3 softly.assertThat(configuration.interfaces().get(3)).satisfies(intf -> { - softly.assertThat(intf.number()).isEqualTo(3); - softly.assertThat(intf.alternates()).hasSize(1); - softly.assertThat(intf.alternates().get(0)).satisfies(alternate -> { - softly.assertThat(alternate.number()).isEqualTo(0); - softly.assertThat(alternate.endpoints()).hasSize(1); - softly.assertThat(alternate.endpoints().get(0)).satisfies(endpoint -> { - softly.assertThat(endpoint.number()).isEqualTo(4); - softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.IN); - softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.INTERRUPT); + softly.assertThat(intf.getNumber()).isEqualTo(3); + softly.assertThat(intf.getAlternates()).hasSize(1); + softly.assertThat(intf.getAlternates().get(0)).satisfies(alternate -> { + softly.assertThat(alternate.getNumber()).isEqualTo(0); + softly.assertThat(alternate.getEndpoints()).hasSize(1); + softly.assertThat(alternate.getEndpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(endpoint.getNumber()).isEqualTo(4); + softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); + softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.INTERRUPT); }); }); }); @@ -161,62 +161,62 @@ void compositeTestDeviceDescriptor_canBeParsed() { // interface 0 softly.assertThat(configuration.interfaces().get(0)).satisfies(intf -> { - softly.assertThat(intf.number()).isEqualTo(0); - softly.assertThat(intf.alternates()).hasSize(1); - softly.assertThat(intf.alternate().endpoints()).hasSize(1); - softly.assertThat(intf.alternate().endpoints().get(0)).satisfies(endpoint -> { - softly.assertThat(endpoint.number()).isEqualTo(3); - softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.IN); - softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.INTERRUPT); + softly.assertThat(intf.getNumber()).isEqualTo(0); + softly.assertThat(intf.getAlternates()).hasSize(1); + softly.assertThat(intf.getCurrentAlternate().getEndpoints()).hasSize(1); + softly.assertThat(intf.getCurrentAlternate().getEndpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(endpoint.getNumber()).isEqualTo(3); + softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); + softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.INTERRUPT); }); }); // interface 1 softly.assertThat(configuration.interfaces().get(1)).satisfies(intf -> { - softly.assertThat(intf.number()).isEqualTo(1); - softly.assertThat(intf.alternates()).hasSize(1); - softly.assertThat(intf.alternates().get(0)).satisfies(alternate -> { - softly.assertThat(alternate.number()).isEqualTo(0); - softly.assertThat(alternate.endpoints()).hasSize(2); - softly.assertThat(alternate.endpoints().get(0)).satisfies(endpoint -> { - softly.assertThat(endpoint.number()).isEqualTo(2); - softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.OUT); - softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.BULK); + softly.assertThat(intf.getNumber()).isEqualTo(1); + softly.assertThat(intf.getAlternates()).hasSize(1); + softly.assertThat(intf.getAlternates().get(0)).satisfies(alternate -> { + softly.assertThat(alternate.getNumber()).isEqualTo(0); + softly.assertThat(alternate.getEndpoints()).hasSize(2); + softly.assertThat(alternate.getEndpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(endpoint.getNumber()).isEqualTo(2); + softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.OUT); + softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.BULK); }); - softly.assertThat(alternate.endpoints().get(1)).satisfies(endpoint -> { - softly.assertThat(endpoint.number()).isEqualTo(1); - softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.IN); - softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.BULK); + softly.assertThat(alternate.getEndpoints().get(1)).satisfies(endpoint -> { + softly.assertThat(endpoint.getNumber()).isEqualTo(1); + softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); + softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.BULK); }); }); }); // interface 2 softly.assertThat(configuration.interfaces().get(2)).satisfies(intf -> { - softly.assertThat(intf.number()).isEqualTo(2); - softly.assertThat(intf.alternates()).hasSize(1); - softly.assertThat(intf.alternates().get(0)).satisfies(alternate -> { - softly.assertThat(alternate.number()).isEqualTo(0); - softly.assertThat(alternate.endpoints()).isEmpty(); + softly.assertThat(intf.getNumber()).isEqualTo(2); + softly.assertThat(intf.getAlternates()).hasSize(1); + softly.assertThat(intf.getAlternates().get(0)).satisfies(alternate -> { + softly.assertThat(alternate.getNumber()).isEqualTo(0); + softly.assertThat(alternate.getEndpoints()).isEmpty(); }); }); // interface 3 softly.assertThat(configuration.interfaces().get(3)).satisfies(intf -> { - softly.assertThat(intf.number()).isEqualTo(3); - softly.assertThat(intf.alternates()).hasSize(1); - softly.assertThat(intf.alternates().get(0)).satisfies(alternate -> { - softly.assertThat(alternate.number()).isEqualTo(0); - softly.assertThat(alternate.endpoints()).hasSize(2); - softly.assertThat(alternate.endpoints().get(0)).satisfies(endpoint -> { - softly.assertThat(endpoint.number()).isEqualTo(1); - softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.OUT); - softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.BULK); + softly.assertThat(intf.getNumber()).isEqualTo(3); + softly.assertThat(intf.getAlternates()).hasSize(1); + softly.assertThat(intf.getAlternates().get(0)).satisfies(alternate -> { + softly.assertThat(alternate.getNumber()).isEqualTo(0); + softly.assertThat(alternate.getEndpoints()).hasSize(2); + softly.assertThat(alternate.getEndpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(endpoint.getNumber()).isEqualTo(1); + softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.OUT); + softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.BULK); }); - softly.assertThat(alternate.endpoints().get(1)).satisfies(endpoint -> { - softly.assertThat(endpoint.number()).isEqualTo(2); - softly.assertThat(endpoint.direction()).isEqualTo(USBDirection.IN); - softly.assertThat(endpoint.transferType()).isEqualTo(USBTransferType.BULK); + softly.assertThat(alternate.getEndpoints().get(1)).satisfies(endpoint -> { + softly.assertThat(endpoint.getNumber()).isEqualTo(2); + softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); + softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.BULK); }); }); }); @@ -231,7 +231,7 @@ void tooShortDescriptor_throwsException() { var segment = MemorySegment.ofArray(desc); assertThatThrownBy(() -> ConfigurationParser.parseConfigurationDescriptor(segment)) - .isInstanceOf(USBException.class) + .isInstanceOf(UsbException.class) .hasMessage("invalid USB configuration descriptor (invalid length)"); } @@ -242,7 +242,7 @@ void tooLongDescriptor_throwsException() { var segment = MemorySegment.ofArray(desc); assertThatThrownBy(() -> ConfigurationParser.parseConfigurationDescriptor(segment)) - .isInstanceOf(USBException.class) + .isInstanceOf(UsbException.class) .hasMessage("invalid USB configuration descriptor (invalid length)"); } @@ -252,7 +252,7 @@ void invalidDescriptor_throwsException() { var segment = MemorySegment.ofArray(desc); assertThatThrownBy(() -> ConfigurationParser.parseConfigurationDescriptor(segment)) - .isInstanceOf(USBException.class) + .isInstanceOf(UsbException.class) .hasMessage("invalid USB configuration descriptor"); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java index 98131c4e..de26d03f 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java @@ -11,8 +11,7 @@ import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.*; /** * Tests control transfers @@ -21,13 +20,14 @@ class ControlTransferTest extends TestDeviceBase { @Test void storeValue_succeeds() { - testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x01, (short) 10730, (short) interfaceNumber), null); + var setup = new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x01, (short) 10730, (short) interfaceNumber); + assertDoesNotThrow(() -> testDevice.controlTransferOut(setup, null)); } @Test void retrieveValue_isSameAsStored() { - testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x01, (short) 0x9a41, (short) interfaceNumber), null); - var valueBytes = testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) interfaceNumber), 4); + testDevice.controlTransferOut(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x01, (short) 0x9a41, (short) interfaceNumber), null); + var valueBytes = testDevice.controlTransferIn(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) interfaceNumber), 4); var expectedBytes = new byte[]{(byte) 0x41, (byte) 0x9a, (byte) 0x00, (byte) 0x00}; assertArrayEquals(expectedBytes, valueBytes); } @@ -35,19 +35,19 @@ void retrieveValue_isSameAsStored() { @Test void storeValueInDataStage_canBeRetrieved() { var sentValue = new byte[]{(byte) 0x83, (byte) 0x03, (byte) 0xda, (byte) 0x3e}; - testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x02, (short) 0, (short) interfaceNumber), sentValue); - var retrievedValue = testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) interfaceNumber), 4); + testDevice.controlTransferOut(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x02, (short) 0, (short) interfaceNumber), sentValue); + var retrievedValue = testDevice.controlTransferIn(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) interfaceNumber), 4); assertArrayEquals(sentValue, retrievedValue); } @Test void interfaceNumber_canBeRetrieved() { - var response = testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x05, (short) 0, (short) interfaceNumber), 1); + var response = testDevice.controlTransferIn(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x05, (short) 0, (short) interfaceNumber), 1); assertEquals(interfaceNumber, response[0] & 0xff); if (isCompositeDevce()) { testDevice.claimInterface(2); - response = testDevice.controlTransferIn(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x05, (short) 0, (short) 2), 1); + response = testDevice.controlTransferIn(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x05, (short) 0, (short) 2), 1); assertEquals(2, response[0] & 0xff); testDevice.releaseInterface(2); } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index fc443c50..79b2ca83 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -20,121 +20,134 @@ class DescriptionTest extends TestDeviceBase { @Test void deviceInfo_isCorrect() { - assertEquals("JavaDoesUSB", testDevice.manufacturer()); - assertEquals(isLoopbackDevice() ? "Loopback" : "Composite", testDevice.product()); - assertEquals(12, testDevice.serialNumber().length()); + assertEquals("JavaDoesUSB", testDevice.getManufacturer()); + assertEquals(isLoopbackDevice() ? "Loopback" : "Composite", testDevice.getProduct()); + assertEquals(12, testDevice.getSerialNumber().length()); if (isLoopbackDevice()) { // simple device - assertEquals(0xff, testDevice.classCode()); - assertEquals(0x00, testDevice.subclassCode()); - assertEquals(0x00, testDevice.protocolCode()); + assertEquals(0xff, testDevice.getClassCode()); + assertEquals(0x00, testDevice.getSubclassCode()); + assertEquals(0x00, testDevice.getProtocolCode()); } else { // composite device - assertEquals(0xef, testDevice.classCode()); - assertEquals(0x02, testDevice.subclassCode()); - assertEquals(0x01, testDevice.protocolCode()); + assertEquals(0xef, testDevice.getClassCode()); + assertEquals(0x02, testDevice.getSubclassCode()); + assertEquals(0x01, testDevice.getProtocolCode()); } var isComposite = isCompositeDevce(); - assertEquals(2, testDevice.usbVersion().major()); - assertEquals(isComposite ? 1 : 0, testDevice.usbVersion().minor()); - assertEquals(0, testDevice.usbVersion().subminor()); + assertEquals(2, testDevice.getUsbVersion().getMajor()); + assertEquals(isComposite ? 1 : 0, testDevice.getUsbVersion().getMinor()); + assertEquals(0, testDevice.getUsbVersion().getSubminor()); - assertEquals(0, testDevice.deviceVersion().major()); - assertEquals(isComposite ? 3 : 7, testDevice.deviceVersion().minor()); - assertEquals(isComposite ? 6 : 4, testDevice.deviceVersion().subminor()); + assertEquals(0, testDevice.getDeviceVersion().getMajor()); + assertEquals(isComposite ? 3 : 7, testDevice.getDeviceVersion().getMinor()); + assertEquals(isComposite ? 6 : 4, testDevice.getDeviceVersion().getSubminor()); } @Test void interfaceDescriptor_isCorrect() { - assertNotNull(testDevice.interfaces()); - assertEquals(interfaceNumber + 1, testDevice.interfaces().size()); + assertNotNull(testDevice.getInterfaces()); + assertEquals(interfaceNumber + 1, testDevice.getInterfaces().size()); - var intf = testDevice.interfaces().get(interfaceNumber); - assertEquals(interfaceNumber, intf.number()); - assertNotNull(intf.alternate()); + var intf = testDevice.getInterfaces().get(interfaceNumber); + assertEquals(interfaceNumber, intf.getNumber()); + assertNotNull(intf.getCurrentAlternate()); assertTrue(intf.isClaimed()); } + @Test + void invalidInterfaceNumber_shouldThrow() { + assertThrows(UsbException.class, () -> testDevice.getInterface(4)); + } + @Test void alternateInterfaceDescriptor_isCorrect() { - var intf = testDevice.interfaces().get(interfaceNumber); - var altIntf = intf.alternate(); - assertNotNull(intf.alternates()); - assertEquals(isLoopbackDevice() ? 2 : 1, intf.alternates().size()); - assertSame(intf.alternates().get(0), altIntf); - assertEquals(0, altIntf.number()); + var intf = testDevice.getInterfaces().get(interfaceNumber); + var altIntf = intf.getCurrentAlternate(); + assertNotNull(intf.getAlternates()); + assertEquals(isLoopbackDevice() ? 2 : 1, intf.getAlternates().size()); + assertSame(intf.getAlternates().get(0), altIntf); + assertEquals(0, altIntf.getNumber()); - assertEquals(0xff, altIntf.classCode()); - assertEquals(0x00, altIntf.subclassCode()); - assertEquals(0x00, altIntf.protocolCode()); + assertEquals(0xff, altIntf.getClassCode()); + assertEquals(0x00, altIntf.getSubclassCode()); + assertEquals(0x00, altIntf.getProtocolCode()); if (isLoopbackDevice()) { - altIntf = intf.alternates().get(1); - assertEquals(1, altIntf.number()); + altIntf = intf.getAlternates().get(1); + assertEquals(1, altIntf.getNumber()); - assertEquals(0xff, altIntf.classCode()); - assertEquals(0x00, altIntf.subclassCode()); - assertEquals(0x00, altIntf.protocolCode()); + assertEquals(0xff, altIntf.getClassCode()); + assertEquals(0x00, altIntf.getSubclassCode()); + assertEquals(0x00, altIntf.getProtocolCode()); } } @Test void endpointDescriptors_areCorrect() { - var altIntf = testDevice.interfaces().get(interfaceNumber).alternate(); - assertNotNull(altIntf.endpoints()); - assertEquals(isLoopbackDevice() ? 4 : 2, altIntf.endpoints().size()); - - var endpoint = altIntf.endpoints().get(0); - assertEquals(1, endpoint.number()); - assertEquals(USBDirection.OUT, endpoint.direction()); - assertEquals(USBTransferType.BULK, endpoint.transferType()); - assertTrue(endpoint.packetSize() == 64 || endpoint.packetSize() == 512); - - endpoint = altIntf.endpoints().get(1); - assertEquals(2, endpoint.number()); - assertEquals(USBDirection.IN, endpoint.direction()); - assertEquals(USBTransferType.BULK, endpoint.transferType()); - assertTrue(endpoint.packetSize() == 64 || endpoint.packetSize() == 512); + var altIntf = testDevice.getInterfaces().get(interfaceNumber).getCurrentAlternate(); + assertNotNull(altIntf.getEndpoints()); + assertEquals(isLoopbackDevice() ? 4 : 2, altIntf.getEndpoints().size()); + + var endpoint = altIntf.getEndpoints().get(0); + assertEquals(1, endpoint.getNumber()); + assertEquals(UsbDirection.OUT, endpoint.getDirection()); + assertEquals(UsbTransferType.BULK, endpoint.getTransferType()); + assertTrue(endpoint.getPacketSize() == 64 || endpoint.getPacketSize() == 512); + + endpoint = altIntf.getEndpoints().get(1); + assertEquals(2, endpoint.getNumber()); + assertEquals(UsbDirection.IN, endpoint.getDirection()); + assertEquals(UsbTransferType.BULK, endpoint.getTransferType()); + assertTrue(endpoint.getPacketSize() == 64 || endpoint.getPacketSize() == 512); if (isLoopbackDevice()) { - endpoint = altIntf.endpoints().get(2); - assertEquals(3, endpoint.number()); - assertEquals(USBDirection.OUT, endpoint.direction()); - assertEquals(USBTransferType.INTERRUPT, endpoint.transferType()); - assertEquals(16, endpoint.packetSize()); - - endpoint = altIntf.endpoints().get(3); - assertEquals(3, endpoint.number()); - assertEquals(USBDirection.IN, endpoint.direction()); - assertEquals(USBTransferType.INTERRUPT, endpoint.transferType()); - assertEquals(16, endpoint.packetSize()); + endpoint = altIntf.getEndpoints().get(2); + assertEquals(3, endpoint.getNumber()); + assertEquals(UsbDirection.OUT, endpoint.getDirection()); + assertEquals(UsbTransferType.INTERRUPT, endpoint.getTransferType()); + assertEquals(16, endpoint.getPacketSize()); + + endpoint = altIntf.getEndpoints().get(3); + assertEquals(3, endpoint.getNumber()); + assertEquals(UsbDirection.IN, endpoint.getDirection()); + assertEquals(UsbTransferType.INTERRUPT, endpoint.getTransferType()); + assertEquals(16, endpoint.getPacketSize()); // test alternate interface 1 - altIntf = testDevice.interfaces().get(interfaceNumber).alternates().get(1); - assertEquals(2, altIntf.endpoints().size()); - - endpoint = altIntf.endpoints().get(0); - assertEquals(1, endpoint.number()); - assertEquals(USBDirection.OUT, endpoint.direction()); - assertEquals(USBTransferType.BULK, endpoint.transferType()); - assertTrue(endpoint.packetSize() == 64 || endpoint.packetSize() == 512); - - endpoint = altIntf.endpoints().get(1); - assertEquals(2, endpoint.number()); - assertEquals(USBDirection.IN, endpoint.direction()); - assertEquals(USBTransferType.BULK, endpoint.transferType()); - assertTrue(endpoint.packetSize() == 64 || endpoint.packetSize() == 512); + altIntf = testDevice.getInterfaces().get(interfaceNumber).getAlternates().get(1); + assertEquals(2, altIntf.getEndpoints().size()); + + endpoint = altIntf.getEndpoints().get(0); + assertEquals(1, endpoint.getNumber()); + assertEquals(UsbDirection.OUT, endpoint.getDirection()); + assertEquals(UsbTransferType.BULK, endpoint.getTransferType()); + assertTrue(endpoint.getPacketSize() == 64 || endpoint.getPacketSize() == 512); + + endpoint = altIntf.getEndpoints().get(1); + assertEquals(2, endpoint.getNumber()); + assertEquals(UsbDirection.IN, endpoint.getDirection()); + assertEquals(UsbTransferType.BULK, endpoint.getTransferType()); + assertTrue(endpoint.getPacketSize() == 64 || endpoint.getPacketSize() == 512); } } + @Test + void invalidEndpoint_shouldThrow() { + assertThrows(UsbException.class, () -> testDevice.getEndpoint(UsbDirection.IN, 1)); + assertThrows(UsbException.class, () -> testDevice.getEndpoint(UsbDirection.OUT, 4)); + assertThrows(UsbException.class, () -> testDevice.getEndpoint(UsbDirection.IN, 0)); + assertThrows(UsbException.class, () -> testDevice.getEndpoint(UsbDirection.OUT, 0)); + } + @Test void configurationDescription_isAvailable() { var expectedLength = isLoopbackDevice() ? 69 : 115; - var configDesc = testDevice.configurationDescriptor(); + var configDesc = testDevice.getConfigurationDescriptor(); assertNotNull(configDesc); assertEquals(expectedLength, configDesc.length); assertEquals(2, configDesc[1]); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptorTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptorTest.java index 3b4f4bba..4ad8b7d7 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptorTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptorTest.java @@ -8,14 +8,14 @@ class DescriptorTest extends TestDeviceBase { @Test void deviceDescriptor_isAvailable() { - var desc = testDevice.deviceDescriptor(); + var desc = testDevice.getDeviceDescriptor(); assertThat(desc).hasSize(18); assertThat(desc[1]).isEqualTo((byte) 0x01); } @Test void configurationDescriptor_isAvailable() { - var desc = testDevice.configurationDescriptor(); + var desc = testDevice.getConfigurationDescriptor(); assertThat(desc).hasSizeGreaterThan(60); assertThat(desc[1]).isEqualTo((byte) 0x02); } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java index 02a3f84e..84384446 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java @@ -17,33 +17,33 @@ class DeviceEnumerationTest extends TestDeviceBase { @Test void getAllDevices_includesLoopback() { - var deviceList = USB.getAllDevices(); + var deviceList = Usb.getDevices(); assertThat(deviceList) .isNotEmpty() - .anyMatch(device -> device.vendorId() == vid && device.productId() == pid); + .anyMatch(device -> device.getVendorId() == vid && device.getProductId() == pid); } @Test void getDevices_includesLoopback() { - var deviceList = USB.getDevices(device -> device.vendorId() == vid && device.productId() == pid); + var deviceList = Usb.findDevices(device -> device.getVendorId() == vid && device.getProductId() == pid); assertThat(deviceList) .isNotEmpty() - .anyMatch(device -> device.vendorId() == vid && device.productId() == pid); + .anyMatch(device -> device.getVendorId() == vid && device.getProductId() == pid); } @Test void getDevicePredicate_returnsLoopback() { - var device = USB.getDevice(dev -> dev.vendorId() == vid && dev.productId() == pid); + var device = Usb.findDevice(dev -> dev.getVendorId() == vid && dev.getProductId() == pid); assertThat(device).isPresent(); - assertThat(device.get().productId()).isEqualTo(pid); - assertThat(device.get().vendorId()).isEqualTo(vid); + assertThat(device.get().getProductId()).isEqualTo(pid); + assertThat(device.get().getVendorId()).isEqualTo(vid); } @Test void getDeviceVidPid_returnsLoopback() { - var device = USB.getDevice(vid, pid); + var device = Usb.findDevice(vid, pid); assertThat(device).isPresent(); - assertThat(device.get().productId()).isEqualTo(pid); - assertThat(device.get().vendorId()).isEqualTo(vid); + assertThat(device.get().getProductId()).isEqualTo(pid); + assertThat(device.get().getVendorId()).isEqualTo(vid); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java index af45e92c..2e40e5d9 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java @@ -16,48 +16,48 @@ class DeviceLifecycleTest { - private USBDevice device; + private UsbDevice device; @Test void lifecycle_showsValidState() { device = TestDeviceBase.getDevice(); var interfaceNumber = TestDeviceBase.getInterfaceNumber(device); - var intf = device.interfaces().get(interfaceNumber); - assertEquals(interfaceNumber, intf.number()); + var intf = device.getInterfaces().get(interfaceNumber); + assertEquals(interfaceNumber, intf.getNumber()); - assertFalse(device.isOpen()); + assertFalse(device.isOpened()); assertFalse(intf.isClaimed()); - assertThrows(USBException.class, () -> device.claimInterface(interfaceNumber)); - assertThrows(USBException.class, () -> device.releaseInterface(interfaceNumber)); + assertThrows(UsbException.class, () -> device.claimInterface(interfaceNumber)); + assertThrows(UsbException.class, () -> device.releaseInterface(interfaceNumber)); device.open(); - assertTrue(device.isOpen()); + assertTrue(device.isOpened()); assertFalse(intf.isClaimed()); - assertThrows(USBException.class, () -> device.open()); - assertThrows(USBException.class, () -> device.releaseInterface(interfaceNumber)); + assertThrows(UsbException.class, () -> device.open()); + assertThrows(UsbException.class, () -> device.releaseInterface(interfaceNumber)); device.claimInterface(interfaceNumber); - assertTrue(device.isOpen()); + assertTrue(device.isOpened()); assertTrue(intf.isClaimed()); - assertThrows(USBException.class, () -> device.open()); - assertThrows(USBException.class, () -> device.claimInterface(interfaceNumber)); + assertThrows(UsbException.class, () -> device.open()); + assertThrows(UsbException.class, () -> device.claimInterface(interfaceNumber)); device.releaseInterface(interfaceNumber); - assertTrue(device.isOpen()); + assertTrue(device.isOpened()); assertFalse(intf.isClaimed()); - assertThrows(USBException.class, () -> device.open()); - assertThrows(USBException.class, () -> device.releaseInterface(interfaceNumber)); + assertThrows(UsbException.class, () -> device.open()); + assertThrows(UsbException.class, () -> device.releaseInterface(interfaceNumber)); device.close(); - assertFalse(device.isOpen()); + assertFalse(device.isOpened()); assertFalse(intf.isClaimed()); - assertThrows(USBException.class, () -> device.claimInterface(interfaceNumber)); - assertThrows(USBException.class, () -> device.releaseInterface(interfaceNumber)); + assertThrows(UsbException.class, () -> device.claimInterface(interfaceNumber)); + assertThrows(UsbException.class, () -> device.releaseInterface(interfaceNumber)); } @AfterEach diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java index 4ee735cd..7682009a 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java @@ -17,16 +17,16 @@ class InvalidOperationTest extends TestDeviceBase { @Test void claimInvalidInterface_throws() { // throws error because it's already claimed - Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(interfaceNumber)); + Assertions.assertThrows(UsbException.class, () -> testDevice.claimInterface(interfaceNumber)); // throws error because it's an invalid interface number - Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(3)); + Assertions.assertThrows(UsbException.class, () -> testDevice.claimInterface(3)); // throws error because it's an invalid interface number - Assertions.assertThrows(USBException.class, () -> testDevice.claimInterface(888)); + Assertions.assertThrows(UsbException.class, () -> testDevice.claimInterface(888)); } @Test void releaseInvalidInterface_throws() { - Assertions.assertThrows(USBException.class, () -> testDevice.releaseInterface(1)); + Assertions.assertThrows(UsbException.class, () -> testDevice.releaseInterface(1)); } @@ -34,16 +34,16 @@ void releaseInvalidInterface_throws() { void invalidEndpoint_throws() { var data = new byte[] { 34, 23, 99, 0, 17 }; - Assertions.assertThrows(USBException.class, () -> testDevice.transferOut(2, data)); + Assertions.assertThrows(UsbException.class, () -> testDevice.transferOut(2, data)); - Assertions.assertThrows(USBException.class, () -> testDevice.transferOut(0, data)); + Assertions.assertThrows(UsbException.class, () -> testDevice.transferOut(0, data)); - Assertions.assertThrows(USBException.class, () -> testDevice.transferOut(4, data)); + Assertions.assertThrows(UsbException.class, () -> testDevice.transferOut(4, data)); - Assertions.assertThrows(USBException.class, () -> testDevice.transferIn(1)); + Assertions.assertThrows(UsbException.class, () -> testDevice.transferIn(1)); - Assertions.assertThrows(USBException.class, () -> testDevice.transferIn(0)); + Assertions.assertThrows(UsbException.class, () -> testDevice.transferIn(0)); - Assertions.assertThrows(USBException.class, () -> testDevice.transferIn(5)); + Assertions.assertThrows(UsbException.class, () -> testDevice.transferIn(5)); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java index 732bd3bb..aa9b1c5c 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java @@ -20,7 +20,7 @@ class SpeedTest extends TestDeviceBase { @Test void loopback_isFast() throws Throwable { - final var isHighSpeed = testDevice.getEndpoint(USBDirection.IN, LOOPBACK_EP_IN).packetSize() == 512; + final var isHighSpeed = testDevice.getEndpoint(UsbDirection.IN, LOOPBACK_EP_IN).getPacketSize() == 512; final var numBytes = isHighSpeed ? 5000000 : 500000; var sampleData = generateRandomBytes(numBytes, 7219937602343L); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java index 6f97fe72..7fce14a1 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java @@ -18,12 +18,12 @@ class StallTest extends TestDeviceBase { @Test void stalledBulkTransferOut_recovers() { - haltEndpoint(USBDirection.OUT, LOOPBACK_EP_OUT); + haltEndpoint(UsbDirection.OUT, LOOPBACK_EP_OUT); var data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - assertThrows(USBStallException.class, () -> testDevice.transferOut(LOOPBACK_EP_OUT, data)); + assertThrows(UsbStallException.class, () -> testDevice.transferOut(LOOPBACK_EP_OUT, data)); - testDevice.clearHalt(USBDirection.OUT, LOOPBACK_EP_OUT); + testDevice.clearHalt(UsbDirection.OUT, LOOPBACK_EP_OUT); testDevice.transferOut(LOOPBACK_EP_OUT, data); var receivedData = testDevice.transferIn(LOOPBACK_EP_IN); @@ -32,11 +32,11 @@ void stalledBulkTransferOut_recovers() { @Test void stalledBulkTransferIn_recovers() { - haltEndpoint(USBDirection.IN, LOOPBACK_EP_IN); + haltEndpoint(UsbDirection.IN, LOOPBACK_EP_IN); - assertThrows(USBStallException.class, () -> testDevice.transferIn(LOOPBACK_EP_IN)); + assertThrows(UsbStallException.class, () -> testDevice.transferIn(LOOPBACK_EP_IN)); - testDevice.clearHalt(USBDirection.IN, LOOPBACK_EP_IN); + testDevice.clearHalt(UsbDirection.IN, LOOPBACK_EP_IN); var data = new byte[] { 9, 8, 7, 6, 5, 4, 3, 2 }; testDevice.transferOut(LOOPBACK_EP_OUT, data); @@ -46,15 +46,15 @@ void stalledBulkTransferIn_recovers() { @Test void invalidControlTransfer_throws() { - var request = new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, (byte) 0x08, + var request = new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x08, (short) 0, (short) interfaceNumber); - assertThrows(USBStallException.class, () -> testDevice.controlTransferIn(request, 2)); + assertThrows(UsbStallException.class, () -> testDevice.controlTransferIn(request, 2)); } - void haltEndpoint(USBDirection direction, int endpointNumber) { + void haltEndpoint(UsbDirection direction, int endpointNumber) { final var SET_FEATURE = 0x03; final var ENDPOINT_HALT = 0x00; - var endpointAddress = (direction == USBDirection.IN ? 0x80 : 0x00) | endpointNumber; - testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.STANDARD, USBRecipient.ENDPOINT, SET_FEATURE, ENDPOINT_HALT, endpointAddress), null); + var endpointAddress = (direction == UsbDirection.IN ? 0x80 : 0x00) | endpointNumber; + testDevice.controlTransferOut(new UsbControlTransfer(UsbRequestType.STANDARD, UsbRecipient.ENDPOINT, SET_FEATURE, ENDPOINT_HALT, endpointAddress), null); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index 34c5f338..c35f5cd9 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -54,26 +54,26 @@ public class TestDeviceBase { protected static final int ECHO_EP_OUT = 3; protected static final int ECHO_EP_IN = 3; protected static final int ECHO_MAX_PACKET_SIZE = 16; - protected static USBDevice testDevice; + protected static UsbDevice testDevice; - static USBDevice getDevice() { - var optionalDevice = USB.getDevice(VID_COMPOSITE, PID_COMPOSITE); + static UsbDevice getDevice() { + var optionalDevice = Usb.findDevice(VID_COMPOSITE, PID_COMPOSITE); if (optionalDevice.isEmpty()) - optionalDevice = USB.getDevice(VID_LOOPBACK, PID_LOOPBACK); + optionalDevice = Usb.findDevice(VID_LOOPBACK, PID_LOOPBACK); if (optionalDevice.isEmpty()) throw new IllegalStateException("No test device connected"); return optionalDevice.get(); } - static int getInterfaceNumber(USBDevice device) { - return device.productId() == PID_COMPOSITE ? LOOPBACK_INTF_COMPOSITE : LOOPBACK_INTF_LOOPBACK; + static int getInterfaceNumber(UsbDevice device) { + return device.getProductId() == PID_COMPOSITE ? LOOPBACK_INTF_COMPOSITE : LOOPBACK_INTF_LOOPBACK; } @BeforeAll static void openDevice() { testDevice = getDevice(); - vid = testDevice.vendorId(); - pid = testDevice.productId(); + vid = testDevice.getVendorId(); + pid = testDevice.getProductId(); interfaceNumber = getInterfaceNumber(testDevice); testDevice.open(); @@ -109,7 +109,7 @@ private static void resetDevice() { while (true) { try { testDevice.transferIn(LOOPBACK_EP_IN, 1); - } catch (USBTimeoutException e) { + } catch (UsbTimeoutException e) { break; } } @@ -119,7 +119,7 @@ private static void resetDevice() { while (true) { try { testDevice.transferIn(ECHO_EP_IN, 1); - } catch (USBTimeoutException e) { + } catch (UsbTimeoutException e) { break; } } @@ -130,7 +130,7 @@ private static void resetDevice() { } static void resetBuffers() { - testDevice.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, + testDevice.controlTransferOut(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x04, (short) 0, (short) interfaceNumber), null); } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java index a692aa13..619aded7 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java @@ -23,7 +23,7 @@ class TimeoutTest extends TestDeviceBase { @Test @Timeout(value = 1, unit = TimeUnit.SECONDS) void bulkTransferIn_timesOut() { - assertThrows(USBTimeoutException.class, () -> testDevice.transferIn(LOOPBACK_EP_IN, 200)); + assertThrows(UsbTimeoutException.class, () -> testDevice.transferIn(LOOPBACK_EP_IN, 200)); } @Test @@ -43,12 +43,12 @@ void bulkTransferOut_timesOut() { // The test device has an internal buffer of about 2KB for full-speed // and 16KB for high-speed. The first transfer should not time out. final var bufferSize = 32 * testDevice - .getEndpoint(USBDirection.OUT, LOOPBACK_EP_OUT).packetSize(); + .getEndpoint(UsbDirection.OUT, LOOPBACK_EP_OUT).getPacketSize(); var data = generateRandomBytes(100, 9383073929L); testDevice.transferOut(LOOPBACK_EP_OUT, data, 200); - assertThrows(USBTimeoutException.class, () -> { + assertThrows(UsbTimeoutException.class, () -> { for (var i = 0; i < bufferSize / data.length; i++) { testDevice.transferOut(LOOPBACK_EP_OUT, data, 200); } @@ -58,7 +58,7 @@ void bulkTransferOut_timesOut() { while (true) { try { testDevice.transferIn(LOOPBACK_EP_IN, 200); - } catch (USBTimeoutException e) { + } catch (UsbTimeoutException e) { break; } } @@ -70,7 +70,7 @@ void interruptTransferIn_timesOut() { Assumptions.assumeTrue(isLoopbackDevice(), "Interrupt transfer only supported by loopback test device"); - assertThrows(USBTimeoutException.class, () -> testDevice.transferIn(ECHO_EP_IN, 200)); + assertThrows(UsbTimeoutException.class, () -> testDevice.transferIn(ECHO_EP_IN, 200)); } @Test diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/EnumerateDevices.java b/java-does-usb/src/test/java/net/codecrete/usb/special/EnumerateDevices.java index 2951df4b..a88ff90f 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/EnumerateDevices.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/EnumerateDevices.java @@ -7,7 +7,7 @@ package net.codecrete.usb.special; -import net.codecrete.usb.USB; +import net.codecrete.usb.Usb; /** * Sample program displaying the connected USB devices @@ -15,7 +15,7 @@ public class EnumerateDevices { public static void main(String[] args) { - for (var device : USB.getAllDevices()) { + for (var device : Usb.getDevices()) { System.out.println(device); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java b/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java index 7014dd7f..c50b04e0 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java @@ -80,10 +80,10 @@ public static void main(String[] args) { } } - private USBDevice device; + private UsbDevice device; LogicAnalyzer() { - var optionalDevice = USB.getDevice(VID, PID); + var optionalDevice = Usb.findDevice(VID, PID); if (optionalDevice.isEmpty()) throw new IllegalStateException("no logic analyzer connected"); @@ -175,7 +175,7 @@ void startAcquisition() { // send the start command final int commandCodeStart = 0xb1; - device.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.DEVICE, commandCodeStart, 0, 0), cmd); + device.controlTransferOut(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.DEVICE, commandCodeStart, 0, 0), cmd); } void saveSamples() { @@ -196,7 +196,7 @@ void saveSamples() { activityValue = size; } - } catch (USBException e) { + } catch (UsbException e) { if (!stopped && !bufferOverrunDetected) throw e; @@ -230,7 +230,7 @@ void saveSamples() { void stopAcquisition() { // stop the acquisition by halting the bulk endpoint and clearing the halt stopped = true; - device.abortTransfers(USBDirection.IN, EP); + device.abortTransfers(UsbDirection.IN, EP); } void detectBufferOverrun() { @@ -255,7 +255,7 @@ void detectBufferOverrun() { } void checkFirmware() { - if (device.manufacturer() != null) { + if (device.getManufacturer() != null) { System.out.println("Device ready"); return; } @@ -274,19 +274,19 @@ void checkFirmware() { device.claimInterface(0); byte[] cmd = new byte[] { 1 }; - device.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.DEVICE, 0xa0, 0xe600, 0x0000), cmd); + device.controlTransferOut(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.DEVICE, 0xa0, 0xe600, 0x0000), cmd); final int len = firmware.length; int offset = 0; while (offset < len) { int n = Math.min(len - offset, 0x1000); byte[] chunk = Arrays.copyOfRange(firmware, offset, offset + n); - device.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.DEVICE, 0xa0, offset, 0x0000), chunk); + device.controlTransferOut(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.DEVICE, 0xa0, offset, 0x0000), chunk); offset += n; } cmd = new byte[] { 0 }; - device.controlTransferOut(new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.DEVICE, 0xa0, 0xe600, 0x0000), cmd); + device.controlTransferOut(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.DEVICE, 0xa0, 0xe600, 0x0000), cmd); device.close(); DeviceMonitor.instance().awaitDevice(false); @@ -296,11 +296,11 @@ void checkFirmware() { DeviceMonitor.instance().awaitDevice(true); sleep(200); - var optionalDevice = USB.getDevice(VID, PID); + var optionalDevice = Usb.findDevice(VID, PID); if (optionalDevice.isEmpty()) throw new IllegalStateException("no logic analyzer connected"); device = optionalDevice.get(); - if (device.manufacturer() == null) + if (device.getManufacturer() == null) throw new IllegalStateException("firmware upload failed"); System.out.println("Device is ready"); @@ -338,13 +338,13 @@ static synchronized DeviceMonitor instance() { private DeviceMonitor() { } private void start() { - USB.setOnDeviceConnected((device) -> onDeviceConnected(device, true)); - USB.setOnDeviceDisconnected((device) -> onDeviceConnected(device, false)); - isDeviceConnected = USB.getDevice(VID, PID).isPresent(); + Usb.setOnDeviceConnected((device) -> onDeviceConnected(device, true)); + Usb.setOnDeviceDisconnected((device) -> onDeviceConnected(device, false)); + isDeviceConnected = Usb.findDevice(VID, PID).isPresent(); } - private void onDeviceConnected(USBDevice device, boolean connected) { - if (device.vendorId() == VID && device.productId() == device.productId()) { + private void onDeviceConnected(UsbDevice device, boolean connected) { + if (device.getVendorId() == VID && device.getProductId() == device.getProductId()) { try { deviceLock.lock(); isDeviceConnected = connected; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java b/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java index 8fe853b2..c39388f4 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java @@ -20,13 +20,13 @@ public class MonitorDevices { public static void main(String[] args) throws IOException { - USB.setOnDeviceConnected((device) -> { + Usb.setOnDeviceConnected((device) -> { System.out.println("Connected: " + device.toString()); talkToTestDevice(device); }); - USB.setOnDeviceDisconnected((device) -> System.out.println("Disconnected: " + device.toString())); + Usb.setOnDeviceDisconnected((device) -> System.out.println("Disconnected: " + device.toString())); - for (var device : USB.getAllDevices()) { + for (var device : Usb.getDevices()) { System.out.println("Present: " + device.toString()); talkToTestDevice(device); } @@ -36,15 +36,15 @@ public static void main(String[] args) throws IOException { System.in.read(); } - private static void talkToTestDevice(USBDevice device) { - if (device.vendorId() != 0xcafe) + private static void talkToTestDevice(UsbDevice device) { + if (device.getVendorId() != 0xcafe) return; // no test device - int interfaceNumber = device.productId() == 0xcea0 ? 2 : 0; + int interfaceNumber = device.getProductId() == 0xcea0 ? 2 : 0; device.open(); device.claimInterface(interfaceNumber); var response = device.controlTransferIn( - new USBControlTransfer(USBRequestType.VENDOR, USBRecipient.INTERFACE, + new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x05, (short) 0, (short) interfaceNumber), 1 ); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/USBSerialTest.java b/java-does-usb/src/test/java/net/codecrete/usb/special/USBSerialTest.java index 053aa4f3..04964ba0 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/USBSerialTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/USBSerialTest.java @@ -29,7 +29,7 @@ public class USBSerialTest { public static void main(String[] args) { - for (var device : USB.getAllDevices()) { + for (var device : Usb.getDevices()) { int commInterfaceNum = getCDCCommInterfaceNum(device); if (commInterfaceNum >= 0) { System.out.printf("USB CDC device: %s%n", device); @@ -38,7 +38,7 @@ public static void main(String[] args) { } } - static void interact(USBDevice device, int commInterfaceNum) { + static void interact(UsbDevice device, int commInterfaceNum) { // communication and data interface must have consecutive numbers int dataInterfaceNum = commInterfaceNum + 1; @@ -50,7 +50,7 @@ static void interact(USBDevice device, int commInterfaceNum) { // set line coding (9600bps, 8 bit) byte[] coding = { (byte)0x80, 0x25, 0, 0, 0, 0, 8 }; device.controlTransferOut( - new USBControlTransfer(USBRequestType.CLASS, USBRecipient.INTERFACE, 0x20, 0, commInterfaceNum), + new UsbControlTransfer(UsbRequestType.CLASS, UsbRecipient.INTERFACE, 0x20, 0, commInterfaceNum), coding); // send some data @@ -64,29 +64,29 @@ static void interact(USBDevice device, int commInterfaceNum) { device.close(); } - static int getCDCCommInterfaceNum(USBDevice device) { + static int getCDCCommInterfaceNum(UsbDevice device) { // CDC ACM implementations consist of two consecutive interfaces // with certain class, subclass and protocol codes - int numInterfaces = device.interfaces().size(); + int numInterfaces = device.getInterfaces().size(); if (numInterfaces < 2) return -1; for (int i = 0; i < numInterfaces - 1; i += 1) { - var commIntf = device.getInterface(i).alternate(); - var dataIntf = device.getInterface(i + 1).alternate(); + var commIntf = device.getInterface(i).getCurrentAlternate(); + var dataIntf = device.getInterface(i + 1).getCurrentAlternate(); - if (commIntf.classCode() == 2 && commIntf.subclassCode() == 2 && commIntf.protocolCode() == 1 && dataIntf.classCode() == 10) + if (commIntf.getClassCode() == 2 && commIntf.getSubclassCode() == 2 && commIntf.getProtocolCode() == 1 && dataIntf.getClassCode() == 10) return i; } return -1; } - static int getDataOutEndpointNum(USBDevice device, int dataInterfaceNum) { - var altInterface = device.getInterface(dataInterfaceNum).alternate(); - for (var endpoint : altInterface.endpoints()) { - if (endpoint.direction() == USBDirection.OUT) - return endpoint.number(); + static int getDataOutEndpointNum(UsbDevice device, int dataInterfaceNum) { + var altInterface = device.getInterface(dataInterfaceNum).getCurrentAlternate(); + for (var endpoint : altInterface.getEndpoints()) { + if (endpoint.getDirection() == UsbDirection.OUT) + return endpoint.getNumber(); } return -1; } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java index 198ef74a..6d0e5f66 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java @@ -7,9 +7,9 @@ package net.codecrete.usb.special; -import net.codecrete.usb.USB; -import net.codecrete.usb.USBDevice; -import net.codecrete.usb.USBException; +import net.codecrete.usb.Usb; +import net.codecrete.usb.UsbDevice; +import net.codecrete.usb.UsbException; import java.io.IOException; import java.util.HashMap; @@ -42,21 +42,21 @@ public class Unplug { private static final int ECHO_EP_OUT = 3; private static final int ECHO_EP_IN = 3; - private static final HashMap activeDevices = new HashMap<>(); + private static final HashMap activeDevices = new HashMap<>(); public static void main(String[] args) throws IOException { System.out.println("Plug and unplug test device multiple times."); System.out.println("Hit ENTER to exit."); - USB.setOnDeviceConnected(Unplug::onPluggedDevice); - USB.setOnDeviceDisconnected(Unplug::onUnpluggedDevice); - USB.getAllDevices().forEach(Unplug::onPluggedDevice); + Usb.setOnDeviceConnected(Unplug::onPluggedDevice); + Usb.setOnDeviceDisconnected(Unplug::onUnpluggedDevice); + Usb.getDevices().forEach(Unplug::onPluggedDevice); //noinspection ResultOfMethodCallIgnored System.in.read(); } - private static void onPluggedDevice(USBDevice device) { + private static void onPluggedDevice(UsbDevice device) { if (!isTestDevice(device)) return; @@ -65,7 +65,7 @@ private static void onPluggedDevice(USBDevice device) { worker.start(); } - private static void onUnpluggedDevice(USBDevice device) { + private static void onUnpluggedDevice(UsbDevice device) { if (!isTestDevice(device)) return; @@ -75,13 +75,13 @@ private static void onUnpluggedDevice(USBDevice device) { } @SuppressWarnings("BooleanMethodIsAlwaysInverted") - private static boolean isTestDevice(USBDevice device) { - return device.vendorId() == VID_LOOPBACK && device.productId() == PID_LOOPBACK; + private static boolean isTestDevice(UsbDevice device) { + return device.getVendorId() == VID_LOOPBACK && device.getProductId() == PID_LOOPBACK; } static class DeviceWorker { - private final USBDevice device; + private final UsbDevice device; private final int seed; @@ -89,7 +89,7 @@ static class DeviceWorker { private final HashMap workTracking = new HashMap<>(); - DeviceWorker(USBDevice device) { + DeviceWorker(UsbDevice device) { this.device = device; this.seed = (int) System.currentTimeMillis(); } @@ -174,7 +174,7 @@ private void logWork(long amount) { private void runAction(Runnable action) { try { action.run(); - } catch (USBException e) { + } catch (UsbException e) { logFinish(); } } From 967e527ad55ba7d7881a5387f58f10cc79b3d0cd Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 10 Nov 2023 17:26:15 +0100 Subject: [PATCH 299/433] More Kotlin examples --- examples/monitor_kotlin/.gitignore | 38 +++++++++++ examples/monitor_kotlin/pom.xml | 66 +++++++++++++++++++ .../net/codecrete/usb/examples/Monitor.kt | 41 ++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 examples/monitor_kotlin/.gitignore create mode 100644 examples/monitor_kotlin/pom.xml create mode 100644 examples/monitor_kotlin/src/main/kotlin/net/codecrete/usb/examples/Monitor.kt diff --git a/examples/monitor_kotlin/.gitignore b/examples/monitor_kotlin/.gitignore new file mode 100644 index 00000000..5ff6309b --- /dev/null +++ b/examples/monitor_kotlin/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/examples/monitor_kotlin/pom.xml b/examples/monitor_kotlin/pom.xml new file mode 100644 index 00000000..78451d28 --- /dev/null +++ b/examples/monitor_kotlin/pom.xml @@ -0,0 +1,66 @@ + + 4.0.0 + + net.codecrete.usb.examples + monitor_kotlin + 0.7.0-SNAPSHOT + jar + + monitor_kotlin + https://github.com/manuelbl/JavaDoesUSB/examples/kotlin + + + 1.9.10 + true + UTF-8 + + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/test/kotlin + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + true + + + + + + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin.version} + + + net.codecrete.usb + java-does-usb + 0.7.0-SNAPSHOT + + + org.tinylog + tinylog-api + 2.6.2 + + + org.tinylog + tinylog-impl + 2.6.2 + + + org.tinylog + jsl-tinylog + 2.6.2 + + + junit + junit + 4.13.2 + test + + + diff --git a/examples/monitor_kotlin/src/main/kotlin/net/codecrete/usb/examples/Monitor.kt b/examples/monitor_kotlin/src/main/kotlin/net/codecrete/usb/examples/Monitor.kt new file mode 100644 index 00000000..b16d568a --- /dev/null +++ b/examples/monitor_kotlin/src/main/kotlin/net/codecrete/usb/examples/Monitor.kt @@ -0,0 +1,41 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +package net.codecrete.usb.examples + +import net.codecrete.usb.Usb +import net.codecrete.usb.UsbDevice + +/** + * Sample application monitoring USB devices as they are connected and disconnected. + */ + +fun main() { + Monitor().monitor() +} + +class Monitor { + fun monitor() { + // register callbacks for events + Usb.setOnDeviceConnected { device -> printDetails(device, "Connected") } + Usb.setOnDeviceDisconnected { device -> + printDetails( device, "Disconnected") + } + + // display the already present USB devices + for (device in Usb.getDevices()) + printDetails(device, "Present") + + // wait for ENTER to quit program + println("Monitoring... Press ENTER to quit.") + System.`in`.read() + } + + private fun printDetails(device: UsbDevice, event: String) { + print(String.format("%-14s", "$event:")) + println(device.toString()) + } +} \ No newline at end of file From f40045da9204e3da1db6f328c18d4bb1b06ae73a Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 10 Nov 2023 17:28:04 +0100 Subject: [PATCH 300/433] Build Kotlin examples --- .github/workflows/continuous-integration.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index ba1f23d0..1c554aab 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -46,9 +46,15 @@ jobs: - name: Example "enumerate" run: ./mvnw $MAVEN_ARGS clean compile working-directory: ./examples/enumerate + - name: Example "enumerate" (Kotlin) + run: ./mvnw $MAVEN_ARGS clean compile + working-directory: ./examples/enumerate_kotlin - name: Example "monitor" run: ./mvnw $MAVEN_ARGS clean compile working-directory: ./examples/monitor + - name: Example "monitor" (Kotlin) + run: ./mvnw $MAVEN_ARGS clean compile + working-directory: ./examples/monitor_kotlin - name: Example "stm_dfu" run: ./mvnw $MAVEN_ARGS clean compile working-directory: ./examples/stm_dfu From 77d4f1b34e0fb911b7ec48ae92d4ff9112607639 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 10 Nov 2023 17:32:09 +0100 Subject: [PATCH 301/433] Add Maven wrapper --- .../.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 + examples/enumerate_kotlin/mvnw | 308 ++++++++++++++++++ examples/enumerate_kotlin/mvnw.cmd | 205 ++++++++++++ .../.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 + examples/monitor_kotlin/mvnw | 308 ++++++++++++++++++ examples/monitor_kotlin/mvnw.cmd | 205 ++++++++++++ 8 files changed, 1062 insertions(+) create mode 100644 examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.jar create mode 100644 examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.properties create mode 100755 examples/enumerate_kotlin/mvnw create mode 100644 examples/enumerate_kotlin/mvnw.cmd create mode 100644 examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.jar create mode 100644 examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.properties create mode 100755 examples/monitor_kotlin/mvnw create mode 100644 examples/monitor_kotlin/mvnw.cmd diff --git a/examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.jar b/examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 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 A?*IS* literal 0 HcmV?d00001 diff --git a/examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.properties b/examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..eacdc9ed --- /dev/null +++ b/examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/enumerate_kotlin/mvnw b/examples/enumerate_kotlin/mvnw new file mode 100755 index 00000000..8d937f4c --- /dev/null +++ b/examples/enumerate_kotlin/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/examples/enumerate_kotlin/mvnw.cmd b/examples/enumerate_kotlin/mvnw.cmd new file mode 100644 index 00000000..c4586b56 --- /dev/null +++ b/examples/enumerate_kotlin/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.jar b/examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 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 A?*IS* literal 0 HcmV?d00001 diff --git a/examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.properties b/examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..eacdc9ed --- /dev/null +++ b/examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/monitor_kotlin/mvnw b/examples/monitor_kotlin/mvnw new file mode 100755 index 00000000..8d937f4c --- /dev/null +++ b/examples/monitor_kotlin/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/examples/monitor_kotlin/mvnw.cmd b/examples/monitor_kotlin/mvnw.cmd new file mode 100644 index 00000000..c4586b56 --- /dev/null +++ b/examples/monitor_kotlin/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% From fc4cee888b1c9810d51b445b47d622fbc3fbb069 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 23 Dec 2023 21:39:26 +0100 Subject: [PATCH 302/433] Linux reference code: epoll instead of poll --- reference/linux/usb_device.cpp | 4 +- reference/linux/usb_registry.cpp | 153 ++++++++++++------------------- reference/linux/usb_registry.hpp | 8 +- 3 files changed, 62 insertions(+), 103 deletions(-) diff --git a/reference/linux/usb_device.cpp b/reference/linux/usb_device.cpp index 387d4040..7d70c05d 100644 --- a/reference/linux/usb_device.cpp +++ b/reference/linux/usb_device.cpp @@ -314,6 +314,6 @@ void usb_device::submit_urb(usbdevfs_urb* urb) { void usb_device::cancel_urb(usbdevfs_urb* urb) { int result = ioctl(fd_, USBDEVFS_DISCARDURB, urb); - if (result < 0) - usb_error::throw_error("Failed to submit URB"); + if (result < 0 && errno != EINVAL) + usb_error::throw_error("Failed to cancel URB"); } diff --git a/reference/linux/usb_registry.cpp b/reference/linux/usb_registry.cpp index 865b2632..6ed42b4f 100644 --- a/reference/linux/usb_registry.cpp +++ b/reference/linux/usb_registry.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -30,7 +31,7 @@ usb_registry::usb_registry() : monitor_wake_event_fd(-1), on_connected_callback(nullptr), on_disconnected_callback(nullptr), is_device_list_ready(false), - async_io_update_event_fd(-1), async_io_update_request(0), async_io_update_response(0) { + async_io_epoll_fd(-1), async_io_exit_event_fd(-1) { } usb_registry::~usb_registry() { @@ -38,10 +39,10 @@ usb_registry::~usb_registry() { monitor_thread.join(); ::close(monitor_wake_event_fd); - if (async_io_update_event_fd != -1) { - eventfd_write(async_io_update_event_fd, 999999); + if (async_io_exit_event_fd != -1) { + eventfd_write(async_io_exit_event_fd, 999999); async_io_thread.join(); - ::close(async_io_update_event_fd); + ::close(async_io_exit_event_fd); } } @@ -251,66 +252,38 @@ std::shared_ptr usb_registry::get_shared_ptr(usb_device* device) { void usb_registry::async_io_run() { - { - std::lock_guard lock(async_io_mutex); - async_io_update_response = async_io_update_request; - async_io_condition.notify_all(); - } - - std::vector fds; - fds.resize(2); - fds[0].fd = async_io_update_event_fd; - fds[0].events = POLLIN; - while (true) { - - int num_fds = 1; - fds.resize(async_io_fds.size() + 1); - - { - std::lock_guard lock(async_io_mutex); - for (auto fd : async_io_fds) { - fds[num_fds].fd = fd; - fds[num_fds].events = POLLIN | POLLOUT; - num_fds += 1; - } - } - - int ret = poll(fds.data(), num_fds, -1); - if (ret < 0) - usb_error::throw_error("internal error (poll)"); - - for (auto it = fds.begin(); it != fds.end(); ++it) { - if (it->revents == 0) + struct epoll_event events[5]; + int ret = epoll_wait(async_io_epoll_fd, &events[0], 5, -1); + if (ret < 0) { + if (errno == EINTR) continue; + usb_error::throw_error("internal error (epoll)"); + } + + for (int i = 0; i < ret; i++) { + int fd = events[i].data.fd; + if (fd == async_io_exit_event_fd) + return; + reap_urbs(fd); + } + } +} - if (it->fd == async_io_update_event_fd) { - eventfd_t value = 0; - eventfd_read(async_io_update_event_fd, &value); - if (value >= 999999) - return; - - std::lock_guard lock(async_io_mutex); - async_io_update_response = async_io_update_request; - async_io_condition.notify_all(); - continue; - } - - if ((it->revents & POLLERR) != 0) { - // TODO - continue; - } - - if (it->revents != 0) { - usbdevfs_urb* urb = nullptr; - ret = ioctl(it->fd, USBDEVFS_REAPURB, &urb); - if (ret < 0) - usb_error::throw_error("internal error (reap URB)"); - - auto completion = reinterpret_cast(urb->usercontext); - (*completion)(); - } +void usb_registry::reap_urbs(int fd) { + while (true) { + usbdevfs_urb* urb = nullptr; + int ret = ioctl(fd, USBDEVFS_REAPURB, &urb); + if (ret < 0) { + if (errno == EAGAIN) + return; // no more pending URBs + if (errno == ENODEV) + return; // ignore, device might have been closed + usb_error::throw_error("internal error (reap URB)"); } + + auto completion = reinterpret_cast(urb->usercontext); + (*completion)(); } } @@ -321,50 +294,38 @@ void usb_registry::add_async_fd(int fd) { std::lock_guard lock(async_io_mutex); // start background thread if needed - if (async_io_update_event_fd == -1) { - async_io_update_event_fd = eventfd(0, 0); - if (async_io_update_event_fd < 0) + if (async_io_exit_event_fd == -1) { + async_io_exit_event_fd = eventfd(0, 0); + if (async_io_exit_event_fd < 0) usb_error::throw_error("internal error(eventfd)"); - async_io_thread = std::thread(&usb_registry::async_io_run, this); - } - - if (std::find(async_io_fds.begin(), async_io_fds.end(), fd) != async_io_fds.end()) - return; // already registered + async_io_epoll_fd = epoll_create(4); + if (async_io_epoll_fd < 0) + usb_error::throw_error("internal error(epoll_create)"); - async_io_fds.emplace_back(fd); - eventfd_write(async_io_update_event_fd, 1); + epoll_event event = {0}; + event.events = EPOLLIN; + event.data.fd = async_io_exit_event_fd; + int ret = epoll_ctl(async_io_epoll_fd, EPOLL_CTL_ADD, async_io_exit_event_fd, &event); + if (ret < 0) + usb_error::throw_error("internal error(epoll_ctl)"); - async_io_update_request += 1; - expected_request = async_io_update_request; + async_io_thread = std::thread(&usb_registry::async_io_run, this); + } } - // wait for background process to add file descriptor for polling - { - std::unique_lock wait_lock(async_io_mutex); - async_io_condition.wait(wait_lock, [this, expected_request] { return expected_request - async_io_update_response <= 0; }); - } + epoll_event event = {0}; + event.events = EPOLLOUT; + event.data.fd = fd; + int ret = epoll_ctl(async_io_epoll_fd, EPOLL_CTL_ADD, fd, &event); + if (ret < 0) + usb_error::throw_error("internal error(epoll_ctl)"); } void usb_registry::remove_async_fd(int fd) { - int expected_request; - - { - std::lock_guard lock(async_io_mutex); - - async_io_fds.erase( - std::remove(async_io_fds.begin(), async_io_fds.end(), fd), - async_io_fds.end() - ); - async_io_update_request += 1; - expected_request = async_io_update_request; - eventfd_write(async_io_update_event_fd, 1); - } - - // wait for background process to remove file descriptor from polling - { - std::unique_lock wait_lock(async_io_mutex); - async_io_condition.wait(wait_lock, [this, expected_request] { return expected_request - async_io_update_response <= 0; }); - } + epoll_event event = {0}; + int ret = epoll_ctl(async_io_epoll_fd, EPOLL_CTL_DEL, fd, &event); + if (ret < 0) + usb_error::throw_error("internal error(epoll_ctl)"); } diff --git a/reference/linux/usb_registry.hpp b/reference/linux/usb_registry.hpp index 6a95dcb2..ff251eaf 100644 --- a/reference/linux/usb_registry.hpp +++ b/reference/linux/usb_registry.hpp @@ -52,6 +52,7 @@ class usb_registry { void async_io_run(); void add_async_fd(int fd); void remove_async_fd(int fd); + void reap_urbs(int fd); std::shared_ptr create_device(udev_device* udev_dev); std::shared_ptr get_shared_ptr(usb_device* device); @@ -69,11 +70,8 @@ class usb_registry { std::thread async_io_thread; std::mutex async_io_mutex; - std::condition_variable async_io_condition; - std::vector async_io_fds; - int async_io_update_event_fd; - int async_io_update_request; - int async_io_update_response; + int async_io_epoll_fd; + int async_io_exit_event_fd; friend usb_device; }; From 2978e085aff99a07602b715836fc5d6fb208e124 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 27 Dec 2023 18:06:12 +0100 Subject: [PATCH 303/433] Update READMEs --- README.md | 16 ++++++++++++++-- examples/bulk_transfer/README.md | 6 +++--- examples/enumerate/README.md | 6 +++--- examples/monitor/README.md | 6 +++--- examples/stm_dfu/README.md | 6 +++--- 5 files changed, 26 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index a482be5d..90317fe3 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,13 @@ The library uses the [Foreign Function & Memory API](https://github.com/openjdk/panama-foreign) to access native APIs of the underlying operating system. It is written entirely in Java and does not need JNI or any native third-party library. The *Foreign Function & Memory API* (aka as project Panama) is currently in preview and will leave preview with Java 22. Currently, it can be used with Java 19, Java 20 or Java 21 (with preview features enabled). +| Version | Main New Features | Compatibility | +| - | - | - | +| 0.7.x | Prerelease: New setter/getter names for improved Kotlin support; Kotlin examples | JDK 21 | +| 0.6.x | Support for JDK 21; better handling of composite devices on Windows | JDK 21 | +| 0.5.x | Support for JDK 20; high-throuput I/O streams | JDK 20 | +| 0.4.x | Early release | JDK 19 | + *Note: The main branch and published versions ≥ 0.6.0 work with JDK 21 only. For JDK 20, use version 0.5.*. For JDK 19, use version 0.4.x. @@ -133,13 +140,18 @@ The Foreign Function & Memory API has not been implemented for 32-bit operating ## Code generation -Many bindings for the native APIs have been generated with *jextract*. See the [jextract](java-does-usb/jextract) subdirectory for more information. +Many bindings for the native APIs have been generated with *jextract*. See the [jextract](java-does-usb/jextract) subdirectory for more information. For functions that need to retain the error state (`errno` on Linux, `GetLastError()` on Windows), the bindings have been manually written as *jextract* does not support it. ## Testing -In order to run the unit tests, a special test device must be connected to the computer. See the [loopback-stm32](test-devices/loopback-stm32) directory. +In order to run the unit tests, a special test device must be connected to the computer, which can be easily created from very inexpensive microcontroller boards. Two variants exist: + +- [loopback-stm32](test-devices/loopback-stm32) +- [composite-stm32](test-devices/composite-stm32) + +The test device with the *loopback-stm32* code supports all tests. If the test device with the *composite-stm32* code is connected, some tests are skipped. However, if it is used, the correct handling of composite devices is verified. Tests can be run from the command line: diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index 9a7920c1..13d6e6e6 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -4,16 +4,16 @@ This sample shows how to find a device, open it and transfer data from and to bu ## Prerequisites -- Java 20 +- Java 21 - Apache Maven - 64-bit operating system (Windows, macOS, Linux) - A USB device with bulk IN and OUT endpoints (e.g. the test device, see https://github.com/manuelbl/JavaDoesUSB/tree/main/test-devices/loopback-stm32) ## How to run -### Install Java 20 +### Install Java 21 -Check that *Java 20* is installed: +Check that *Java 21* is installed: ```shell $ java -version diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index ad08e230..1881b25f 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -4,15 +4,15 @@ This sample enumerates the connected USB devices and provides information about ## Prerequisites -- Java 20 +- Java 21 - Apache Maven - 64-bit operating system (Windows, macOS, Linux) ## How to run -### Install Java 20 +### Install Java 21 -Check that *Java 20* is installed: +Check that *Java 21* is installed: ```shell $ java -version diff --git a/examples/monitor/README.md b/examples/monitor/README.md index 27c84b4d..c1789a99 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -4,15 +4,15 @@ This sample program monitors USB devices as they are connected and disconnected. ## Prerequisites -- Java 20 +- Java 21 - Apache Maven - 64-bit operating system (Windows, macOS, Linux) ## How to run -### Install Java 20 +### Install Java 21 -Check that *Java 20* is installed: +Check that *Java 21* is installed: ```shell $ java -version diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index 91bd87c4..b97cd35b 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -6,15 +6,15 @@ Even though the DFU ## Prerequisites -- Java 20 +- Java 21 - Apache Maven - 64-bit operating system (Windows, macOS, Linux) ## How to run -### Install Java 20 +### Install Java 21 -Check that *Java 20* is installed: +Check that *Java 21* is installed: ```shell $ java -version From be72c50182277ef43863935038bcf4a6f5aae420 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 27 Dec 2023 22:17:30 +0100 Subject: [PATCH 304/433] Linux: use epoll instead of poll --- java-does-usb/jextract/linux/epoll.h | 3 + java-does-usb/jextract/linux/gen_linux.sh | 30 ++-- .../java/net/codecrete/usb/linux/EPoll.java | 98 +++++++++++ .../main/java/net/codecrete/usb/linux/IO.java | 34 ---- .../codecrete/usb/linux/LinuxAsyncTask.java | 165 +++++------------- .../usb/linux/LinuxUsbDeviceRegistry.java | 70 ++++---- .../gen/{poll => epoll}/RuntimeHelper.java | 2 +- .../usb/linux/gen/epoll/constants$0.java | 27 +++ .../codecrete/usb/linux/gen/epoll/epoll.java | 52 ++++++ .../usb/linux/gen/epoll/epoll_event.java | 61 +++++++ .../codecrete/usb/linux/gen/errno/errno.java | 16 ++ .../usb/linux/gen/poll/constants$0.java | 35 ---- .../codecrete/usb/linux/gen/poll/poll.java | 62 ------- .../codecrete/usb/linux/gen/poll/pollfd.java | 113 ------------ 14 files changed, 346 insertions(+), 422 deletions(-) create mode 100644 java-does-usb/jextract/linux/epoll.h create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java rename java-does-usb/src/main/java/net/codecrete/usb/linux/gen/{poll => epoll}/RuntimeHelper.java (99%) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java diff --git a/java-does-usb/jextract/linux/epoll.h b/java-does-usb/jextract/linux/epoll.h new file mode 100644 index 00000000..c7c68b45 --- /dev/null +++ b/java-does-usb/jextract/linux/epoll.h @@ -0,0 +1,3 @@ +typedef unsigned int uint32_t; +typedef unsigned long int uint64_t; +#include diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index 31b8654f..429ccc24 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -10,6 +10,8 @@ $JEXTRACT --source --output ../../src/main/java \ --include-constant EAGAIN \ --include-constant EINVAL \ --include-constant ENODEV \ + --include-constant EINTR \ + --include-constant ENOENT \ /usr/include/errno.h # string.h @@ -45,16 +47,6 @@ $JEXTRACT --source --output ../../src/main/java \ --include-struct usbdevfs_urb \ --include-struct usbdevfs_disconnect_claim \ --include-struct usbdevfs_ioctl \ - --include-constant USBDEVFS_CONTROL \ - --include-constant USBDEVFS_BULK \ - --include-constant USBDEVFS_CLAIMINTERFACE \ - --include-constant USBDEVFS_RELEASEINTERFACE \ - --include-constant USBDEVFS_SETINTERFACE \ - --include-constant USBDEVFS_CLEAR_HALT \ - --include-constant USBDEVFS_SUBMITURB \ - --include-constant USBDEVFS_DISCARDURB \ - --include-constant USBDEVFS_REAPURB \ - --include-constant USBDEVFS_DISCONNECT_CLAIM \ --include-constant USBDEVFS_URB_TYPE_INTERRUPT \ --include-constant USBDEVFS_URB_TYPE_CONTROL \ --include-constant USBDEVFS_URB_TYPE_BULK \ @@ -89,14 +81,14 @@ $JEXTRACT --source --output ../../src/main/java \ --include-function udev_monitor_get_fd \ /usr/include/libudev.h -# poll.h +# epoll.h $JEXTRACT --source --output ../../src/main/java \ - --header-class-name poll \ - --target-package net.codecrete.usb.linux.gen.poll \ - --include-function poll \ - --include-struct pollfd \ - --include-constant POLLIN \ - --include-constant POLLOUT \ - --include-constant POLLERR \ - /usr/include/poll.h + --header-class-name epoll \ + --target-package net.codecrete.usb.linux.gen.epoll \ + --include-struct epoll_event \ + --include-constant EPOLL_CTL_ADD \ + --include-constant EPOLL_CTL_DEL \ + --include-constant EPOLLIN \ + --include-constant EPOLLOUT \ + epoll.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java new file mode 100644 index 00000000..83764679 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java @@ -0,0 +1,98 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.linux; + +import net.codecrete.usb.linux.gen.epoll.epoll_event; +import net.codecrete.usb.linux.gen.errno.errno; + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static net.codecrete.usb.linux.Linux.allocateErrorState; +import static net.codecrete.usb.linux.LinuxUsbException.throwLastError; +import static net.codecrete.usb.linux.gen.epoll.epoll.*; + +@SuppressWarnings({"OptionalGetWithoutIsPresent", "SameParameterValue", "java:S100"}) +public class EPoll { + private EPoll() {} + + private static final Linker linker = Linker.nativeLinker(); + + private static final FunctionDescriptor epoll_create$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT); + private static final MethodHandle epoll_create$MH = linker.downcallHandle(linker.defaultLookup().find( + "epoll_create").get(), epoll_create$FUNC, Linux.ERRNO_STATE); + + private static final FunctionDescriptor epoll_ctl$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_INT, JAVA_INT, ADDRESS); + private static final MethodHandle epoll_ctl$MH = linker.downcallHandle(linker.defaultLookup().find( + "epoll_ctl").get(), epoll_ctl$FUNC, Linux.ERRNO_STATE); + + private static final FunctionDescriptor epoll_wait$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS, JAVA_INT, JAVA_INT); + private static final MethodHandle epoll_wait$MH = linker.downcallHandle(linker.defaultLookup().find( + "epoll_wait").get(), epoll_wait$FUNC, Linux.ERRNO_STATE); + + private static final VarHandle epoll_event_data_fd$VH = epoll_event.$LAYOUT().varHandle( + MemoryLayout.PathElement.groupElement("data"), + MemoryLayout.PathElement.groupElement("fd") + ); + + static int epoll_create(int size, MemorySegment errno) { + try { + return (int) epoll_create$MH.invokeExact(errno, size); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + private static int epoll_ctl(int epfd, int op, int fd, MemorySegment event, MemorySegment errno) { + try { + return (int) epoll_ctl$MH.invokeExact(errno, epfd, op, fd, event); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static int epoll_wait(int epfd, MemorySegment events, int maxevent, int timeout, MemorySegment errno) { + try { + return (int) epoll_wait$MH.invokeExact(errno, epfd, events, maxevent, timeout); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static void addFileDescriptor(int epfd, int op, int fd) { + try (var arena = Arena.ofConfined()) { + var errorState = allocateErrorState(arena); + + var event = arena.allocate(epoll_event.$LAYOUT()); + epoll_event.events$set(event, op); + epoll_event_data_fd$VH.set(event, fd); + var ret = epoll_ctl(epfd, EPOLL_CTL_ADD(), fd, event, errorState); + if (ret < 0) + throwLastError(errorState, "internal error (epoll_ctl_add)"); + } + } + + static void removeFileDescriptor(int epfd, int fd) { + try (var arena = Arena.ofConfined()) { + var errorState = allocateErrorState(arena); + + var event = arena.allocate(epoll_event.$LAYOUT()); + epoll_event.events$set(event, 0); + epoll_event_data_fd$VH.set(event, fd); + var ret = epoll_ctl(epfd, EPOLL_CTL_DEL(), fd, event, errorState); + if (ret < 0) { + var err = Linux.getErrno(errorState); + if (err != errno.ENOENT()) + throwLastError(errorState, "internal error (epoll_ctl_del)"); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java index 88b6d364..bfdc9380 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java @@ -27,15 +27,6 @@ private IO() { private static final FunctionDescriptor open$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT); private static final MethodHandle open$MH = linker.downcallHandle(linker.defaultLookup().find("open").get(), open$FUNC, Linux.ERRNO_STATE); - private static final FunctionDescriptor eventfd$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_INT); - private static final MethodHandle eventfd$MH = linker.downcallHandle(linker.defaultLookup().find("eventfd").get() - , eventfd$FUNC, Linux.ERRNO_STATE); - private static final FunctionDescriptor eventfd_read$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS); - private static final MethodHandle eventfd_read$MH = linker.downcallHandle(linker.defaultLookup().find( - "eventfd_read").get(), eventfd_read$FUNC, Linux.ERRNO_STATE); - private static final FunctionDescriptor eventfd_write$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_LONG); - private static final MethodHandle eventfd_write$MH = linker.downcallHandle(linker.defaultLookup().find( - "eventfd_write").get(), eventfd_write$FUNC, Linux.ERRNO_STATE); static int ioctl(int fd, long request, MemorySegment segment, MemorySegment errno) { try { @@ -52,29 +43,4 @@ static int open(MemorySegment file, int oflag, MemorySegment errno) { throw new AssertionError(ex); } } - - static int eventfd(int count, int flags, MemorySegment errno) { - try { - return (int) eventfd$MH.invokeExact(errno, count, flags); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static int eventfd_read(int fd, MemorySegment value, MemorySegment errno) { - try { - return (int) eventfd_read$MH.invokeExact(errno, fd, value); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static int eventfd_write(int fd, long value, MemorySegment errno) { - try { - return (int) eventfd_write$MH.invokeExact(errno, fd, value); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index 524fe818..fb515ee4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -8,25 +8,29 @@ package net.codecrete.usb.linux; import net.codecrete.usb.UsbTransferType; +import net.codecrete.usb.linux.gen.epoll.epoll_event; import net.codecrete.usb.linux.gen.errno.errno; -import net.codecrete.usb.linux.gen.poll.poll; -import net.codecrete.usb.linux.gen.poll.pollfd; import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_urb; import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.common.ForeignMemory.dereference; +import static net.codecrete.usb.linux.EPoll.epoll_create; +import static net.codecrete.usb.linux.EPoll.epoll_wait; import static net.codecrete.usb.linux.Linux.allocateErrorState; import static net.codecrete.usb.linux.LinuxUsbException.throwException; import static net.codecrete.usb.linux.LinuxUsbException.throwLastError; import static net.codecrete.usb.linux.UsbDevFS.*; +import static net.codecrete.usb.linux.gen.epoll.epoll.*; +import static net.codecrete.usb.linux.gen.errno.errno.EINTR; import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.*; /** @@ -51,15 +55,20 @@ class LinuxAsyncTask { */ static final LinuxAsyncTask INSTANCE = new LinuxAsyncTask(); + private static final int NUM_EVENTS = 5; + + private static final VarHandle epoll_event_data_fd$VH = epoll_event.$LAYOUT().varHandle( + MemoryLayout.PathElement.groupElement("data"), + MemoryLayout.PathElement.groupElement("fd") + ); + private final Arena urbArena = Arena.ofAuto(); /// available URBs private final List availableURBs = new ArrayList<>(); /// map of URB addresses to transfer (for outstanding transfers) private final Map transfersByURB = new LinkedHashMap<>(); - /// array of file descriptors using asynchronous completion - private int[] asyncFds; - /// file descriptor to notify async IO background thread about an update - private int asyncIOWakeUpEventFd; + /// file descriptor of epoll + private int epollFd = -1; /** * Background task for handling asynchronous IO completions. @@ -67,85 +76,33 @@ class LinuxAsyncTask { * It polls on all registered file descriptors. If a file descriptor is * ready, the URB is "reaped". *

- *

- * Using an additional {@code eventfd} file descriptor, this background task - * can be woken up to refresh the list of polled file descriptors. - *

*/ @SuppressWarnings({"java:S2189", "java:S135", "java:S3776"}) private void asyncCompletionTask() { try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); - var pollfdArray = pollfd.allocateArray(100, arena); var urbPointerHolder = arena.allocate(ADDRESS); - var eventfdValueHolder = arena.allocate(JAVA_LONG); + var events = arena.allocateArray(epoll_event.$LAYOUT(), NUM_EVENTS); while (true) { - // get current file descriptor array - int[] fds; - synchronized (this) { - fds = asyncFds; + var res = epoll_wait(epollFd, events, NUM_EVENTS, -1, errorState); + if (res < 0) { + var err = Linux.getErrno(errorState); + if (err == EINTR()) + continue; + throwException(err, "internal error (epoll_wait)"); } - // poll for event - fillPollfdArray(pollfdArray, fds); - var n = fds.length; - var res = poll.poll(pollfdArray, n + 1L, -1); - if (res < 0) - throwException("internal error (poll)"); - - // acquire lock - synchronized (this) { - - // check for wakeup event - if ((pollfd.revents$get(pollfdArray, n) & poll.POLLIN()) != 0) { - // wakeup to refresh list of file descriptors - res = IO.eventfd_read(asyncIOWakeUpEventFd, eventfdValueHolder, errorState); - if (res < 0) - throwLastError(errorState, "internal error (eventfd_read)"); - continue; - } - - // check for USB device events - for (var i = 0; i < n + 1; i++) { - var revent = pollfd.revents$get(pollfdArray, i); - if (revent == 0) - continue; - - if ((revent & poll.POLLERR()) != 0) { - // most likely the device has been disconnected, - // remove from polled FD list to prevent further problems - var fd = pollfd.fd$get(pollfdArray, i); - removeFdFromAsyncIOCompletion(fd); - continue; - } - - // reap URB - var fd = pollfd.fd$get(pollfdArray, i); - reapURBs(fd, urbPointerHolder, errorState); - } + for (int i = 0; i < res; i++) { + var fd = (int) epoll_event_data_fd$VH.get(events.asSlice(epoll_event.sizeof() * i, epoll_event.sizeof())); + reapURBs(fd, urbPointerHolder, errorState); } } } } - void fillPollfdArray(MemorySegment asyncPolls, int[] fds) { - // device file descriptors - var n = fds.length; - for (var i = 0; i < n; i++) { - pollfd.fd$set(asyncPolls, i, fds[i]); - pollfd.events$set(asyncPolls, i, (short) poll.POLLOUT()); - pollfd.revents$set(asyncPolls, i, (short) 0); - } - - // entry n is the wake-up event file descriptor - pollfd.fd$set(asyncPolls, n, asyncIOWakeUpEventFd); - pollfd.events$set(asyncPolls, n, (short) poll.POLLIN()); - pollfd.revents$set(asyncPolls, n, (short) 0); - } - /** * Reap all pending URBs and handle the completed transfers. * @@ -160,8 +117,11 @@ private void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment erro var err = Linux.getErrno(errorState); if (err == errno.EAGAIN()) return; // no more pending URBs - if (err == errno.ENODEV()) - return; // ignore, device might have been closed + if (err == errno.ENODEV()) { + // device might have been unplugged + removeFdFromAsyncIOCompletion(fd); + return; + } throwException(err, "internal error (reap URB)"); } @@ -172,38 +132,17 @@ private void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment erro } } - /** - * Notifies background process about changed FD list - */ - private void notifyAsyncIOTask() { - // start background process if needed - if (asyncIOWakeUpEventFd == 0) { - startAsyncIOTask(); - return; - } - - try (var arena = Arena.ofConfined()) { - var errorState = allocateErrorState(arena); - if (IO.eventfd_write(asyncIOWakeUpEventFd, 1, errorState) < 0) - throwLastError(errorState, "internal error (eventfd_write)"); - } - } - /** * Register a device for asynchronous IO completion handling * * @param device USB device */ synchronized void addForAsyncIOCompletion(LinuxUsbDevice device) { - var n = asyncFds != null ? asyncFds.length : 0; - var fds = new int[n + 1]; - if (n > 0) - System.arraycopy(asyncFds, 0, fds, 0, n); - fds[n] = device.fileDescriptor(); - - // activate new array - asyncFds = fds; - notifyAsyncIOTask(); + // start background process if needed + if (epollFd < 0) + startAsyncIOTask(); + + EPoll.addFileDescriptor(epollFd, EPOLLOUT(), device.fileDescriptor()); } /** @@ -212,29 +151,11 @@ synchronized void addForAsyncIOCompletion(LinuxUsbDevice device) { * @param device USB device */ synchronized void removeFromAsyncIOCompletion(LinuxUsbDevice device) { - removeFdFromAsyncIOCompletion(device.fileDescriptor()); - notifyAsyncIOTask(); + EPoll.removeFileDescriptor(epollFd, device.fileDescriptor()); } private synchronized void removeFdFromAsyncIOCompletion(int fd) { - // copy file descriptor (except the device's) into new array - var n = asyncFds.length; - if (n == 0) - return; - - var fds = new int[n - 1]; - var tgt = 0; - for (var asyncFd : asyncFds) { - if (asyncFd != fd) { - if (tgt == n) - return; - fds[tgt] = asyncFd; - tgt += 1; - } - } - - // make new array to active one - asyncFds = fds; + EPoll.removeFileDescriptor(epollFd, fd); } synchronized void submitTransfer(LinuxUsbDevice device, int endpointAddress, UsbTransferType transferType, LinuxTransfer transfer) { @@ -319,11 +240,9 @@ synchronized void abortTransfers(LinuxUsbDevice device, byte endpointAddress) { private void startAsyncIOTask() { try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); - asyncIOWakeUpEventFd = IO.eventfd(0, 0, errorState); - if (asyncIOWakeUpEventFd == -1) { - asyncIOWakeUpEventFd = 0; - throwLastError(errorState, "internal error (eventfd)"); - } + epollFd = epoll_create(NUM_EVENTS, errorState); + if (epollFd < 0) + throwLastError(errorState, "internal error (epoll_create)"); } // start background thread for handling IO completion diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java index 01051c95..48480ce8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java @@ -10,8 +10,7 @@ import net.codecrete.usb.UsbDevice; import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.common.UsbDeviceRegistry; -import net.codecrete.usb.linux.gen.poll.poll; -import net.codecrete.usb.linux.gen.poll.pollfd; +import net.codecrete.usb.linux.gen.epoll.epoll_event; import net.codecrete.usb.linux.gen.udev.udev; import java.lang.foreign.Arena; @@ -20,7 +19,12 @@ import java.util.List; import static java.lang.System.Logger.Level.INFO; +import static net.codecrete.usb.linux.EPoll.epoll_create; +import static net.codecrete.usb.linux.EPoll.epoll_wait; +import static net.codecrete.usb.linux.Linux.allocateErrorState; import static net.codecrete.usb.linux.LinuxUsbException.throwException; +import static net.codecrete.usb.linux.LinuxUsbException.throwLastError; +import static net.codecrete.usb.linux.gen.epoll.epoll.*; /** * Linux implementation of USB device registry. @@ -90,28 +94,40 @@ protected void monitorDevices() { return; } - // monitor device changes - //noinspection InfiniteLoopStatement - while (true) { - try (var arena = Arena.ofConfined(); var cleanup = new ScopeCleanup()) { + try (var arena = Arena.ofConfined()) { + // create epoll + var errorState = allocateErrorState(arena); + var epfd = epoll_create(1, errorState); + if (epfd < 0) + throwLastError(errorState, "internal error (epoll_create)"); + EPoll.addFileDescriptor(epfd, EPOLLIN(), fd); - // wait for next change - waitForFileDescriptor(fd, arena); + // allocate event (as output for epoll_wait) + var event = arena.allocate(epoll_event.$LAYOUT()); - // retrieve change - var udevDevice = udev.udev_monitor_receive_device(monitor); - if (udevDevice == null) - continue; // shouldn't happen + // monitor device changes + //noinspection InfiniteLoopStatement + while (true) { + try (var cleanup = new ScopeCleanup()) { + + // wait for next change + epoll_wait(epfd, event, 1, -1, errorState); + + // retrieve change + var udevDevice = udev.udev_monitor_receive_device(monitor); + if (udevDevice == null) + continue; // shouldn't happen - cleanup.add(() -> udev.udev_device_unref(udevDevice)); + cleanup.add(() -> udev.udev_device_unref(udevDevice)); - // get details - var action = getDeviceAction(udevDevice); + // get details + var action = getDeviceAction(udevDevice); - if ("add".equals(action)) { - onDeviceConnected(udevDevice); - } else if ("remove".equals(action)) { - onDeviceDisconnected(udevDevice); + if ("add".equals(action)) { + onDeviceConnected(udevDevice); + } else if ("remove".equals(action)) { + onDeviceDisconnected(udevDevice); + } } } } @@ -243,20 +259,4 @@ private static String getDeviceName(MemorySegment udevDevice) { private static String getDeviceAction(MemorySegment udevDevice) { return udev.udev_device_get_action(udevDevice).getUtf8String(0); } - - /** - * Waits until the specified file descriptor becomes ready for reading. - * - * @param fd the file descriptor - * @param arena an arena for allocating memory - */ - private static void waitForFileDescriptor(int fd, Arena arena) { - var fds = pollfd.allocate(arena); - pollfd.fd$set(fds, fd); - pollfd.events$set(fds, (short) poll.POLLIN()); - int res = poll.poll(fds, 1, -1); - if (res < 0) - throwException("internal error (poll)"); - } - } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/RuntimeHelper.java similarity index 99% rename from java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/RuntimeHelper.java rename to java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/RuntimeHelper.java index 5fdcd815..6259819d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/RuntimeHelper.java @@ -1,4 +1,4 @@ -package net.codecrete.usb.linux.gen.poll; +package net.codecrete.usb.linux.gen.epoll; // Generated by jextract import java.lang.foreign.*; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/constants$0.java new file mode 100644 index 00000000..f5fe605a --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/constants$0.java @@ -0,0 +1,27 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.epoll; + +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +final class constants$0 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} + static final StructLayout const$0 = MemoryLayout.structLayout( + JAVA_INT.withByteAlignment(1).withName("events"), + MemoryLayout.unionLayout( + RuntimeHelper.POINTER.withByteAlignment(1).withName("ptr"), + JAVA_INT.withByteAlignment(1).withName("fd"), + JAVA_INT.withByteAlignment(1).withName("u32"), + JAVA_LONG.withByteAlignment(1).withName("u64") + ).withName("data") + ).withName("epoll_event"); + static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("events")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java new file mode 100644 index 00000000..a208a743 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java @@ -0,0 +1,52 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.epoll; + +import java.lang.foreign.AddressLayout; + +import static java.lang.foreign.ValueLayout.*; +public class epoll { + + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfLong C_LONG = JAVA_LONG; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; + /** + * {@snippet : + * #define EPOLL_CTL_ADD 1 + * } + */ + public static int EPOLL_CTL_ADD() { + return (int)1L; + } + /** + * {@snippet : + * #define EPOLL_CTL_DEL 2 + * } + */ + public static int EPOLL_CTL_DEL() { + return (int)2L; + } + /** + * {@snippet : + * enum EPOLL_EVENTS.EPOLLIN = 1; + * } + */ + public static int EPOLLIN() { + return (int)1L; + } + /** + * {@snippet : + * enum EPOLL_EVENTS.EPOLLOUT = 4; + * } + */ + public static int EPOLLOUT() { + return (int)4L; + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java new file mode 100644 index 00000000..e59d3532 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java @@ -0,0 +1,61 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.epoll; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct epoll_event { + * uint32_t events; + * epoll_data_t data; + * }; + * } + */ +public class epoll_event { + + public static MemoryLayout $LAYOUT() { + return constants$0.const$0; + } + public static VarHandle events$VH() { + return constants$0.const$1; + } + /** + * Getter for field: + * {@snippet : + * uint32_t events; + * } + */ + public static int events$get(MemorySegment seg) { + return (int)constants$0.const$1.get(seg); + } + /** + * Setter for field: + * {@snippet : + * uint32_t events; + * } + */ + public static void events$set(MemorySegment seg, int x) { + constants$0.const$1.set(seg, x); + } + public static int events$get(MemorySegment seg, long index) { + return (int)constants$0.const$1.get(seg.asSlice(index*sizeof())); + } + public static void events$set(MemorySegment seg, long index, int x) { + constants$0.const$1.set(seg.asSlice(index*sizeof()), x); + } + public static MemorySegment data$slice(MemorySegment seg) { + return seg.asSlice(4, 8); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java index 5db1b041..b9a9566e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -15,6 +15,22 @@ public class errno { public static final OfFloat C_FLOAT = JAVA_FLOAT; public static final OfDouble C_DOUBLE = JAVA_DOUBLE; public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; + /** + * {@snippet : + * #define ENOENT 2 + * } + */ + public static int ENOENT() { + return (int)2L; + } + /** + * {@snippet : + * #define EINTR 4 + * } + */ + public static int EINTR() { + return (int)4L; + } /** * {@snippet : * #define EAGAIN 11 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java deleted file mode 100644 index 112fe8b5..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java +++ /dev/null @@ -1,35 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.poll; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.*; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final StructLayout const$0 = MemoryLayout.structLayout( - JAVA_INT.withName("fd"), - JAVA_SHORT.withName("events"), - JAVA_SHORT.withName("revents") - ).withName("pollfd"); - static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("fd")); - static final VarHandle const$2 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("events")); - static final VarHandle const$3 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("revents")); - static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - JAVA_LONG, - JAVA_INT - ); - static final MethodHandle const$5 = RuntimeHelper.downcallHandle( - "poll", - constants$0.const$4 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java deleted file mode 100644 index c3002abe..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java +++ /dev/null @@ -1,62 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.poll; - -import java.lang.foreign.AddressLayout; -import java.lang.foreign.MemorySegment; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.*; -public class poll { - - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfLong C_LONG = JAVA_LONG; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; - /** - * {@snippet : - * #define POLLIN 1 - * } - */ - public static int POLLIN() { - return (int)1L; - } - /** - * {@snippet : - * #define POLLOUT 4 - * } - */ - public static int POLLOUT() { - return (int)4L; - } - /** - * {@snippet : - * #define POLLERR 8 - * } - */ - public static int POLLERR() { - return (int)8L; - } - public static MethodHandle poll$MH() { - return RuntimeHelper.requireNonNull(constants$0.const$5,"poll"); - } - /** - * {@snippet : - * int poll(struct pollfd* __fds, nfds_t __nfds, int __timeout); - * } - */ - public static int poll(MemorySegment __fds, long __nfds, int __timeout) { - var mh$ = poll$MH(); - try { - return (int)mh$.invokeExact(__fds, __nfds, __timeout); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java deleted file mode 100644 index 6d632aa7..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java +++ /dev/null @@ -1,113 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.poll; - -import java.lang.foreign.Arena; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; -/** - * {@snippet : - * struct pollfd { - * int fd; - * short events; - * short revents; - * }; - * } - */ -public class pollfd { - - public static MemoryLayout $LAYOUT() { - return constants$0.const$0; - } - public static VarHandle fd$VH() { - return constants$0.const$1; - } - /** - * Getter for field: - * {@snippet : - * int fd; - * } - */ - public static int fd$get(MemorySegment seg) { - return (int)constants$0.const$1.get(seg); - } - /** - * Setter for field: - * {@snippet : - * int fd; - * } - */ - public static void fd$set(MemorySegment seg, int x) { - constants$0.const$1.set(seg, x); - } - public static int fd$get(MemorySegment seg, long index) { - return (int)constants$0.const$1.get(seg.asSlice(index*sizeof())); - } - public static void fd$set(MemorySegment seg, long index, int x) { - constants$0.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static VarHandle events$VH() { - return constants$0.const$2; - } - /** - * Getter for field: - * {@snippet : - * short events; - * } - */ - public static short events$get(MemorySegment seg) { - return (short)constants$0.const$2.get(seg); - } - /** - * Setter for field: - * {@snippet : - * short events; - * } - */ - public static void events$set(MemorySegment seg, short x) { - constants$0.const$2.set(seg, x); - } - public static short events$get(MemorySegment seg, long index) { - return (short)constants$0.const$2.get(seg.asSlice(index*sizeof())); - } - public static void events$set(MemorySegment seg, long index, short x) { - constants$0.const$2.set(seg.asSlice(index*sizeof()), x); - } - public static VarHandle revents$VH() { - return constants$0.const$3; - } - /** - * Getter for field: - * {@snippet : - * short revents; - * } - */ - public static short revents$get(MemorySegment seg) { - return (short)constants$0.const$3.get(seg); - } - /** - * Setter for field: - * {@snippet : - * short revents; - * } - */ - public static void revents$set(MemorySegment seg, short x) { - constants$0.const$3.set(seg, x); - } - public static short revents$get(MemorySegment seg, long index) { - return (short)constants$0.const$3.get(seg.asSlice(index*sizeof())); - } - public static void revents$set(MemorySegment seg, long index, short x) { - constants$0.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } -} - - From b716e4049b1a2f304ccbe8795c480290ea078a9e Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 28 Dec 2023 10:09:01 +0100 Subject: [PATCH 305/433] Linux: varhandle for array access --- .../java/net/codecrete/usb/linux/EPoll.java | 26 ++++++++---- .../codecrete/usb/linux/LinuxAsyncTask.java | 41 +++++++++++-------- .../net/codecrete/usb/linux/UsbDevFS.java | 1 + 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java index 83764679..b4e30672 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java @@ -22,6 +22,23 @@ @SuppressWarnings({"OptionalGetWithoutIsPresent", "SameParameterValue", "java:S100"}) public class EPoll { + // Memory layout for an array of epoll_event structs + private static final SequenceLayout EVENT_ARRAY$LAYOUT = MemoryLayout.sequenceLayout(epoll_event.$LAYOUT()); + + // varhandle to access the "fd" field in an array of epoll_event structs + static final VarHandle EVENT_ARRAY_DATA_FD$VH = EVENT_ARRAY$LAYOUT.varHandle( + MemoryLayout.PathElement.sequenceElement(), + MemoryLayout.PathElement.groupElement("data"), + MemoryLayout.PathElement.groupElement("fd") + ); + + // varhandle to access the "fd" field in an epoll_event struct + static final VarHandle EVENT_DATA_FD$VH = epoll_event.$LAYOUT().varHandle( + MemoryLayout.PathElement.groupElement("data"), + MemoryLayout.PathElement.groupElement("fd") + ); + + private EPoll() {} private static final Linker linker = Linker.nativeLinker(); @@ -38,11 +55,6 @@ private EPoll() {} private static final MethodHandle epoll_wait$MH = linker.downcallHandle(linker.defaultLookup().find( "epoll_wait").get(), epoll_wait$FUNC, Linux.ERRNO_STATE); - private static final VarHandle epoll_event_data_fd$VH = epoll_event.$LAYOUT().varHandle( - MemoryLayout.PathElement.groupElement("data"), - MemoryLayout.PathElement.groupElement("fd") - ); - static int epoll_create(int size, MemorySegment errno) { try { return (int) epoll_create$MH.invokeExact(errno, size); @@ -73,7 +85,7 @@ static void addFileDescriptor(int epfd, int op, int fd) { var event = arena.allocate(epoll_event.$LAYOUT()); epoll_event.events$set(event, op); - epoll_event_data_fd$VH.set(event, fd); + EVENT_DATA_FD$VH.set(event, fd); var ret = epoll_ctl(epfd, EPOLL_CTL_ADD(), fd, event, errorState); if (ret < 0) throwLastError(errorState, "internal error (epoll_ctl_add)"); @@ -86,7 +98,7 @@ static void removeFileDescriptor(int epfd, int fd) { var event = arena.allocate(epoll_event.$LAYOUT()); epoll_event.events$set(event, 0); - epoll_event_data_fd$VH.set(event, fd); + EVENT_DATA_FD$VH.set(event, fd); var ret = epoll_ctl(epfd, EPOLL_CTL_DEL(), fd, event, errorState); if (ret < 0) { var err = Linux.getErrno(errorState); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index fb515ee4..caba302b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -13,9 +13,7 @@ import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_urb; import java.lang.foreign.Arena; -import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; -import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -57,11 +55,6 @@ class LinuxAsyncTask { private static final int NUM_EVENTS = 5; - private static final VarHandle epoll_event_data_fd$VH = epoll_event.$LAYOUT().varHandle( - MemoryLayout.PathElement.groupElement("data"), - MemoryLayout.PathElement.groupElement("fd") - ); - private final Arena urbArena = Arena.ofAuto(); /// available URBs private final List availableURBs = new ArrayList<>(); @@ -87,16 +80,18 @@ private void asyncCompletionTask() { while (true) { + // wait for file descriptor to be ready var res = epoll_wait(epollFd, events, NUM_EVENTS, -1, errorState); if (res < 0) { var err = Linux.getErrno(errorState); if (err == EINTR()) - continue; + continue; // continue on interrupt throwException(err, "internal error (epoll_wait)"); } + // for all ready file descriptors, reap URBs for (int i = 0; i < res; i++) { - var fd = (int) epoll_event_data_fd$VH.get(events.asSlice(epoll_event.sizeof() * i, epoll_event.sizeof())); + var fd = (int) EPoll.EVENT_ARRAY_DATA_FD$VH.get(events, i); reapURBs(fd, urbPointerHolder, errorState); } } @@ -111,6 +106,7 @@ private void asyncCompletionTask() { * @param errorState native memory to receive the errno */ private void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment errorState) { + while (true) { var res = IO.ioctl(fd, REAPURBNDELAY, urbPointerHolder, errorState); if (res < 0) { @@ -119,7 +115,7 @@ private void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment erro return; // no more pending URBs if (err == errno.ENODEV()) { // device might have been unplugged - removeFdFromAsyncIOCompletion(fd); + EPoll.removeFileDescriptor(epollFd, fd); return; } throwException(err, "internal error (reap URB)"); @@ -154,13 +150,9 @@ synchronized void removeFromAsyncIOCompletion(LinuxUsbDevice device) { EPoll.removeFileDescriptor(epollFd, device.fileDescriptor()); } - private synchronized void removeFdFromAsyncIOCompletion(int fd) { - EPoll.removeFileDescriptor(epollFd, fd); - } - synchronized void submitTransfer(LinuxUsbDevice device, int endpointAddress, UsbTransferType transferType, LinuxTransfer transfer) { - addURB(transfer); + linkToUrb(transfer); var urb = transfer.urb; usbdevfs_urb.type$set(urb, (byte) urbTransferType(transferType)); @@ -188,7 +180,15 @@ private static int urbTransferType(UsbTransferType transferType) { }; } - private void addURB(LinuxTransfer transfer) { + /** + * Links the specified transfer instance to a URB. + *

+ * The transfer is assigned an URB instance, and a list + * of associations from URB to transfer is maintained. + *

+ * @param transfer the transfer to assign a URB. + */ + private void linkToUrb(LinuxTransfer transfer) { MemorySegment urb; var size = availableURBs.size(); if (size > 0) { @@ -201,6 +201,15 @@ private void addURB(LinuxTransfer transfer) { transfersByURB.put(urb, transfer); } + /** + * Gets the transfer associated with the specified URB. + *

+ * The URB is returned into the list of URBs available for further transfers. + *

+ * + * @param urb URB instance + * @return transfer associated with the URB + */ @SuppressWarnings("java:S2259") private synchronized LinuxTransfer getTransferResult(MemorySegment urb) { var transfer = transfersByURB.remove(urb); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/UsbDevFS.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/UsbDevFS.java index 72d9e5c0..15f1d270 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/UsbDevFS.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/UsbDevFS.java @@ -19,6 +19,7 @@ class UsbDevFS { private UsbDevFS() { } + // constants that jextract cannot generate as they are built from function-like macros static final long CLAIMINTERFACE = 0x8004550FL; static final long RELEASEINTERFACE = 0x80045510L; static final long SETINTERFACE = 0x80085504L; From 3fd69af5b6c1cab227a8a5cf092e23f067e1a533 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 28 Dec 2023 11:32:46 +0100 Subject: [PATCH 306/433] Linux: improved clean-up when device is unplugged --- java-does-usb/jextract/linux/gen_linux.sh | 2 + .../java/net/codecrete/usb/linux/EPoll.java | 11 +-- .../codecrete/usb/linux/LinuxAsyncTask.java | 67 +++++++++++++------ .../usb/linux/LinuxUsbDeviceRegistry.java | 5 +- .../codecrete/usb/linux/gen/epoll/epoll.java | 8 +++ .../codecrete/usb/linux/gen/fcntl/fcntl.java | 8 +++ 6 files changed, 74 insertions(+), 27 deletions(-) diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index 429ccc24..3b41d80a 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -27,6 +27,7 @@ $JEXTRACT --source --output ../../src/main/java \ --target-package net.codecrete.usb.linux.gen.fcntl \ --include-constant O_CLOEXEC \ --include-constant O_RDWR \ + --include-constant FD_CLOEXEC \ /usr/include/fcntl.h # unistd.h @@ -90,5 +91,6 @@ $JEXTRACT --source --output ../../src/main/java \ --include-constant EPOLL_CTL_DEL \ --include-constant EPOLLIN \ --include-constant EPOLLOUT \ + --include-constant EPOLLWAKEUP \ epoll.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java index b4e30672..e9f8fb3e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java @@ -43,9 +43,9 @@ private EPoll() {} private static final Linker linker = Linker.nativeLinker(); - private static final FunctionDescriptor epoll_create$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT); - private static final MethodHandle epoll_create$MH = linker.downcallHandle(linker.defaultLookup().find( - "epoll_create").get(), epoll_create$FUNC, Linux.ERRNO_STATE); + private static final FunctionDescriptor epoll_create1$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT); + private static final MethodHandle epoll_create1$MH = linker.downcallHandle(linker.defaultLookup().find( + "epoll_create").get(), epoll_create1$FUNC, Linux.ERRNO_STATE); private static final FunctionDescriptor epoll_ctl$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_INT, JAVA_INT, ADDRESS); private static final MethodHandle epoll_ctl$MH = linker.downcallHandle(linker.defaultLookup().find( @@ -55,9 +55,9 @@ private EPoll() {} private static final MethodHandle epoll_wait$MH = linker.downcallHandle(linker.defaultLookup().find( "epoll_wait").get(), epoll_wait$FUNC, Linux.ERRNO_STATE); - static int epoll_create(int size, MemorySegment errno) { + static int epoll_create1(int flags, MemorySegment errno) { try { - return (int) epoll_create$MH.invokeExact(errno, size); + return (int) epoll_create1$MH.invokeExact(errno, flags); } catch (Throwable ex) { throw new AssertionError(ex); } @@ -102,6 +102,7 @@ static void removeFileDescriptor(int epfd, int fd) { var ret = epoll_ctl(epfd, EPOLL_CTL_DEL(), fd, event, errorState); if (ret < 0) { var err = Linux.getErrno(errorState); + // ignore ENOENT as this method might be called twice when cleaning up if (err != errno.ENOENT()) throwLastError(errorState, "internal error (epoll_ctl_del)"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index caba302b..a01d6dc4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -21,14 +21,15 @@ import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.common.ForeignMemory.dereference; -import static net.codecrete.usb.linux.EPoll.epoll_create; +import static net.codecrete.usb.linux.EPoll.epoll_create1; import static net.codecrete.usb.linux.EPoll.epoll_wait; import static net.codecrete.usb.linux.Linux.allocateErrorState; import static net.codecrete.usb.linux.LinuxUsbException.throwException; import static net.codecrete.usb.linux.LinuxUsbException.throwLastError; import static net.codecrete.usb.linux.UsbDevFS.*; import static net.codecrete.usb.linux.gen.epoll.epoll.*; -import static net.codecrete.usb.linux.gen.errno.errno.EINTR; +import static net.codecrete.usb.linux.gen.errno.errno.*; +import static net.codecrete.usb.linux.gen.fcntl.fcntl.FD_CLOEXEC; import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.*; /** @@ -105,7 +106,7 @@ private void asyncCompletionTask() { * @param urbPointerHolder native memory to receive the URB pointer * @param errorState native memory to receive the errno */ - private void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment errorState) { + private synchronized void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment errorState) { while (true) { var res = IO.ioctl(fd, REAPURBNDELAY, urbPointerHolder, errorState); @@ -123,7 +124,7 @@ private void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment erro // call completion handler var urb = dereference(urbPointerHolder); - var transfer = getTransferResult(urb); + var transfer = getTransferWithResult(urb); transfer.completion().completed(transfer); } } @@ -138,7 +139,7 @@ synchronized void addForAsyncIOCompletion(LinuxUsbDevice device) { if (epollFd < 0) startAsyncIOTask(); - EPoll.addFileDescriptor(epollFd, EPOLLOUT(), device.fileDescriptor()); + EPoll.addFileDescriptor(epollFd, EPOLLOUT() | EPOLLWAKEUP(), device.fileDescriptor()); } /** @@ -147,7 +148,31 @@ synchronized void addForAsyncIOCompletion(LinuxUsbDevice device) { * @param device USB device */ synchronized void removeFromAsyncIOCompletion(LinuxUsbDevice device) { - EPoll.removeFileDescriptor(epollFd, device.fileDescriptor()); + int fd = device.fileDescriptor(); + + // remove file descriptor from epoll + EPoll.removeFileDescriptor(epollFd, fd); + + // reap outstanding URBs + try (var arena = Arena.ofConfined()) { + var errorState = allocateErrorState(arena); + var urbPointerHolder = arena.allocate(ADDRESS); + reapURBs(fd, urbPointerHolder, errorState); + } + + // reclaim stale URBs + transfersByURB.entrySet().removeIf(e -> { + var urb = e.getKey(); + var isMatch = usbdevfs_urb.usercontext$get(urb).address() == fd; + if (isMatch) { + var transfer = e.getValue(); + transfer.urb = null; + transfer.setResultCode(ENOENT()); + transfer.setResultSize(0); + availableURBs.add(urb); + } + return isMatch; + }); } synchronized void submitTransfer(LinuxUsbDevice device, int endpointAddress, UsbTransferType transferType, LinuxTransfer transfer) { @@ -202,7 +227,7 @@ private void linkToUrb(LinuxTransfer transfer) { } /** - * Gets the transfer associated with the specified URB. + * Gets the transfer associated with the specified URB and adds the result. *

* The URB is returned into the list of URBs available for further transfers. *

@@ -211,7 +236,7 @@ private void linkToUrb(LinuxTransfer transfer) { * @return transfer associated with the URB */ @SuppressWarnings("java:S2259") - private synchronized LinuxTransfer getTransferResult(MemorySegment urb) { + private synchronized LinuxTransfer getTransferWithResult(MemorySegment urb) { var transfer = transfersByURB.remove(urb); if (transfer == null) throwException("internal error (unknown URB)"); @@ -221,6 +246,7 @@ private synchronized LinuxTransfer getTransferResult(MemorySegment urb) { availableURBs.add(transfer.urb); transfer.urb = null; + return transfer; } @@ -232,24 +258,25 @@ synchronized void abortTransfers(LinuxUsbDevice device, byte endpointAddress) { var errorState = allocateErrorState(arena); // iterate all URBs and discard the ones for the specified endpoint - for (var urb : transfersByURB.keySet()) { - if (fd != (int) usbdevfs_urb.usercontext$get(urb).address() - || endpointAddress != usbdevfs_urb.endpoint$get(urb)) - continue; - - if (IO.ioctl(fd, DISCARDURB, urb, errorState) < 0) { - // ignore EINVAL; it occurs if the URB has completed at the same time - if (Linux.getErrno(errorState) != errno.EINVAL()) - throwLastError(errorState, "error occurred while aborting transfer"); - } - } + transfersByURB.keySet().stream() + .filter(urb -> + usbdevfs_urb.usercontext$get(urb).address() == fd + && usbdevfs_urb.endpoint$get(urb) == endpointAddress) + .forEach(urb -> { + if (IO.ioctl(fd, DISCARDURB, urb, errorState) < 0) { + // ignore EINVAL; it occurs if the URB has completed at the same time + if (Linux.getErrno(errorState) != errno.EINVAL()) + throwLastError(errorState, "error occurred while aborting transfer"); + } + } + ); } } private void startAsyncIOTask() { try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); - epollFd = epoll_create(NUM_EVENTS, errorState); + epollFd = epoll_create1(FD_CLOEXEC(), errorState); if (epollFd < 0) throwLastError(errorState, "internal error (epoll_create)"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java index 48480ce8..8ff57088 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java @@ -19,12 +19,13 @@ import java.util.List; import static java.lang.System.Logger.Level.INFO; -import static net.codecrete.usb.linux.EPoll.epoll_create; +import static net.codecrete.usb.linux.EPoll.epoll_create1; import static net.codecrete.usb.linux.EPoll.epoll_wait; import static net.codecrete.usb.linux.Linux.allocateErrorState; import static net.codecrete.usb.linux.LinuxUsbException.throwException; import static net.codecrete.usb.linux.LinuxUsbException.throwLastError; import static net.codecrete.usb.linux.gen.epoll.epoll.*; +import static net.codecrete.usb.linux.gen.fcntl.fcntl.FD_CLOEXEC; /** * Linux implementation of USB device registry. @@ -97,7 +98,7 @@ protected void monitorDevices() { try (var arena = Arena.ofConfined()) { // create epoll var errorState = allocateErrorState(arena); - var epfd = epoll_create(1, errorState); + var epfd = epoll_create1(FD_CLOEXEC(), errorState); if (epfd < 0) throwLastError(errorState, "internal error (epoll_create)"); EPoll.addFileDescriptor(epfd, EPOLLIN(), fd); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java index a208a743..ee58d003 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java @@ -47,6 +47,14 @@ public static int EPOLLIN() { public static int EPOLLOUT() { return (int)4L; } + /** + * {@snippet : + * enum EPOLL_EVENTS.EPOLLWAKEUP = 536870912; + * } + */ + public static int EPOLLWAKEUP() { + return (int)536870912L; + } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java index a6dd2f36..d3f2f2e6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java @@ -23,6 +23,14 @@ public class fcntl { public static int O_RDWR() { return (int)2L; } + /** + * {@snippet : + * #define FD_CLOEXEC 1 + * } + */ + public static int FD_CLOEXEC() { + return (int)1L; + } /** * {@snippet : * #define O_CLOEXEC 524288 From e7a0e87bd43046b651f71277e164be53a134ff24 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 29 Dec 2023 15:16:31 +0100 Subject: [PATCH 307/433] Use Java 21 language features --- .../java/net/codecrete/usb/UsbException.java | 2 +- .../codecrete/usb/common/UsbDeviceImpl.java | 7 +++---- .../codecrete/usb/common/UsbInterfaceImpl.java | 2 +- .../codecrete/usb/ConfigurationParserTest.java | 18 +++++++++--------- .../net/codecrete/usb/DescriptionTest.java | 9 +++++---- .../codecrete/usb/special/MonitorDevices.java | 6 +++--- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/UsbException.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbException.java index e0c62acb..71a41140 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/UsbException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbException.java @@ -37,7 +37,7 @@ public UsbException(@NotNull String message) { * @param errorCode the error code */ public UsbException(@NotNull String message, int errorCode) { - super(message + " (error code: " + errorCode + ")"); + super(STR."\{message} (error code: \{errorCode})"); code = errorCode; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java index e17d566e..184ccb44 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java @@ -350,15 +350,14 @@ protected void waitForTransfer(Transfer transfer, int timeout, UsbDirection dire if (hasTimedOut && transfer.resultCode() == 0) { abortTransfers(direction, endpointNumber); waitNoTimeout(transfer); - throw new UsbTimeoutException(getOperationDescription(direction, endpointNumber) - + "aborted due to timeout"); + throw new UsbTimeoutException(STR."\{getOperationDescription(direction, endpointNumber)}aborted due to timeout"); } } // test for error if (transfer.resultCode() != 0) { var operation = getOperationDescription(direction, endpointNumber); - throwOSException(transfer.resultCode(), operation + " failed"); + throwOSException(transfer.resultCode(), STR."\{operation} failed"); } } @@ -450,7 +449,7 @@ public int hashCode() { @Override public String toString() { - return "VID: 0x" + String.format("%04x", vid) + ", PID: 0x" + String.format("%04x", pid) + ", " + "manufacturer: " + manufacturerString + ", product: " + productString + ", serial: " + serialString + ", ID: " + uniqueDeviceId; + return STR."VID: 0x\{String.format("%04x", vid)}, PID: 0x\{String.format("%04x", pid)}, manufacturer: \{manufacturerString}, product: \{productString}, serial: \{serialString}, ID: \{uniqueDeviceId}"; } public record EndpointInfo(int interfaceNumber, int endpointNumber, byte endpointAddress, int packetSize, diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbInterfaceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbInterfaceImpl.java index 8f6ea08e..64697e87 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbInterfaceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbInterfaceImpl.java @@ -27,7 +27,7 @@ public class UsbInterfaceImpl implements UsbInterface { public UsbInterfaceImpl(int number, List alternates) { interfaceNumber = number; alternateInterfaces = alternates; - currentAlternate = alternates.get(0); + currentAlternate = alternates.getFirst(); alternateInterfaces.sort(Comparator.comparingInt(UsbAlternateInterface::getNumber)); } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java b/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java index ee55be37..ee3a0911 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java @@ -70,7 +70,7 @@ void largeCompositeDescriptor_canBeParsed() { softly.assertThat(intf.getNumber()).isEqualTo(0); softly.assertThat(intf.getAlternates()).hasSize(1); softly.assertThat(intf.getCurrentAlternate().getEndpoints()).hasSize(1); - softly.assertThat(intf.getCurrentAlternate().getEndpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(intf.getCurrentAlternate().getEndpoints().getFirst()).satisfies(endpoint -> { softly.assertThat(endpoint.getNumber()).isEqualTo(5); softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.INTERRUPT); @@ -88,7 +88,7 @@ void largeCompositeDescriptor_canBeParsed() { softly.assertThat(intf.getAlternates().get(1)).satisfies(alternate -> { softly.assertThat(alternate.getNumber()).isEqualTo(1); softly.assertThat(alternate.getEndpoints()).hasSize(1); - softly.assertThat(alternate.getEndpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(alternate.getEndpoints().getFirst()).satisfies(endpoint -> { softly.assertThat(endpoint.getNumber()).isEqualTo(1); softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.ISOCHRONOUS); @@ -107,7 +107,7 @@ void largeCompositeDescriptor_canBeParsed() { softly.assertThat(intf.getAlternates().get(1)).satisfies(alternate -> { softly.assertThat(alternate.getNumber()).isEqualTo(1); softly.assertThat(alternate.getEndpoints()).hasSize(1); - softly.assertThat(alternate.getEndpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(alternate.getEndpoints().getFirst()).satisfies(endpoint -> { softly.assertThat(endpoint.getNumber()).isEqualTo(2); softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.ISOCHRONOUS); @@ -119,10 +119,10 @@ void largeCompositeDescriptor_canBeParsed() { softly.assertThat(configuration.interfaces().get(3)).satisfies(intf -> { softly.assertThat(intf.getNumber()).isEqualTo(3); softly.assertThat(intf.getAlternates()).hasSize(1); - softly.assertThat(intf.getAlternates().get(0)).satisfies(alternate -> { + softly.assertThat(intf.getAlternates().getFirst()).satisfies(alternate -> { softly.assertThat(alternate.getNumber()).isEqualTo(0); softly.assertThat(alternate.getEndpoints()).hasSize(1); - softly.assertThat(alternate.getEndpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(alternate.getEndpoints().getFirst()).satisfies(endpoint -> { softly.assertThat(endpoint.getNumber()).isEqualTo(4); softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.INTERRUPT); @@ -164,7 +164,7 @@ void compositeTestDeviceDescriptor_canBeParsed() { softly.assertThat(intf.getNumber()).isEqualTo(0); softly.assertThat(intf.getAlternates()).hasSize(1); softly.assertThat(intf.getCurrentAlternate().getEndpoints()).hasSize(1); - softly.assertThat(intf.getCurrentAlternate().getEndpoints().get(0)).satisfies(endpoint -> { + softly.assertThat(intf.getCurrentAlternate().getEndpoints().getFirst()).satisfies(endpoint -> { softly.assertThat(endpoint.getNumber()).isEqualTo(3); softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.INTERRUPT); @@ -175,7 +175,7 @@ void compositeTestDeviceDescriptor_canBeParsed() { softly.assertThat(configuration.interfaces().get(1)).satisfies(intf -> { softly.assertThat(intf.getNumber()).isEqualTo(1); softly.assertThat(intf.getAlternates()).hasSize(1); - softly.assertThat(intf.getAlternates().get(0)).satisfies(alternate -> { + softly.assertThat(intf.getAlternates().getFirst()).satisfies(alternate -> { softly.assertThat(alternate.getNumber()).isEqualTo(0); softly.assertThat(alternate.getEndpoints()).hasSize(2); softly.assertThat(alternate.getEndpoints().get(0)).satisfies(endpoint -> { @@ -195,7 +195,7 @@ void compositeTestDeviceDescriptor_canBeParsed() { softly.assertThat(configuration.interfaces().get(2)).satisfies(intf -> { softly.assertThat(intf.getNumber()).isEqualTo(2); softly.assertThat(intf.getAlternates()).hasSize(1); - softly.assertThat(intf.getAlternates().get(0)).satisfies(alternate -> { + softly.assertThat(intf.getAlternates().getFirst()).satisfies(alternate -> { softly.assertThat(alternate.getNumber()).isEqualTo(0); softly.assertThat(alternate.getEndpoints()).isEmpty(); }); @@ -205,7 +205,7 @@ void compositeTestDeviceDescriptor_canBeParsed() { softly.assertThat(configuration.interfaces().get(3)).satisfies(intf -> { softly.assertThat(intf.getNumber()).isEqualTo(3); softly.assertThat(intf.getAlternates()).hasSize(1); - softly.assertThat(intf.getAlternates().get(0)).satisfies(alternate -> { + softly.assertThat(intf.getAlternates().getFirst()).satisfies(alternate -> { softly.assertThat(alternate.getNumber()).isEqualTo(0); softly.assertThat(alternate.getEndpoints()).hasSize(2); softly.assertThat(alternate.getEndpoints().get(0)).satisfies(endpoint -> { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index 79b2ca83..90257e23 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -69,7 +69,7 @@ void alternateInterfaceDescriptor_isCorrect() { var altIntf = intf.getCurrentAlternate(); assertNotNull(intf.getAlternates()); assertEquals(isLoopbackDevice() ? 2 : 1, intf.getAlternates().size()); - assertSame(intf.getAlternates().get(0), altIntf); + assertSame(intf.getAlternates().getFirst(), altIntf); assertEquals(0, altIntf.getNumber()); assertEquals(0xff, altIntf.getClassCode()); @@ -92,7 +92,7 @@ void endpointDescriptors_areCorrect() { assertNotNull(altIntf.getEndpoints()); assertEquals(isLoopbackDevice() ? 4 : 2, altIntf.getEndpoints().size()); - var endpoint = altIntf.getEndpoints().get(0); + var endpoint = altIntf.getEndpoints().getFirst(); assertEquals(1, endpoint.getNumber()); assertEquals(UsbDirection.OUT, endpoint.getDirection()); assertEquals(UsbTransferType.BULK, endpoint.getTransferType()); @@ -121,7 +121,7 @@ void endpointDescriptors_areCorrect() { altIntf = testDevice.getInterfaces().get(interfaceNumber).getAlternates().get(1); assertEquals(2, altIntf.getEndpoints().size()); - endpoint = altIntf.getEndpoints().get(0); + endpoint = altIntf.getEndpoints().getFirst(); assertEquals(1, endpoint.getNumber()); assertEquals(UsbDirection.OUT, endpoint.getDirection()); assertEquals(UsbTransferType.BULK, endpoint.getTransferType()); @@ -137,7 +137,8 @@ void endpointDescriptors_areCorrect() { @Test void invalidEndpoint_shouldThrow() { - assertThrows(UsbException.class, () -> testDevice.getEndpoint(UsbDirection.IN, 1)); + int nonExistentInEndpoint = isLoopbackDevice() ? 1 : 4; + assertThrows(UsbException.class, () -> testDevice.getEndpoint(UsbDirection.IN, nonExistentInEndpoint)); assertThrows(UsbException.class, () -> testDevice.getEndpoint(UsbDirection.OUT, 4)); assertThrows(UsbException.class, () -> testDevice.getEndpoint(UsbDirection.IN, 0)); assertThrows(UsbException.class, () -> testDevice.getEndpoint(UsbDirection.OUT, 0)); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java b/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java index c39388f4..fd7fdc56 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java @@ -21,13 +21,13 @@ public class MonitorDevices { public static void main(String[] args) throws IOException { Usb.setOnDeviceConnected((device) -> { - System.out.println("Connected: " + device.toString()); + System.out.println(STR."Connected: \{device.toString()}"); talkToTestDevice(device); }); - Usb.setOnDeviceDisconnected((device) -> System.out.println("Disconnected: " + device.toString())); + Usb.setOnDeviceDisconnected((device) -> System.out.println(STR."Disconnected: \{device.toString()}")); for (var device : Usb.getDevices()) { - System.out.println("Present: " + device.toString()); + System.out.println(STR."Present: \{device.toString()}"); talkToTestDevice(device); } System.out.println("Monitoring..."); From 5be0873b6a95419712f227130022855a91a443bf Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 3 Jan 2024 11:58:53 +0100 Subject: [PATCH 308/433] Windows: minor code simplification --- .../main/java/net/codecrete/usb/windows/DeviceInfoSet.java | 6 +++--- .../net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java index 095c85ba..45c1fb1f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java @@ -102,7 +102,7 @@ static DeviceInfoSet ofPath(String devicePath) { * @return device info set */ private static DeviceInfoSet ofEmpty() { - return new DeviceInfoSet((arena, errorState) -> SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, errorState)); + return new DeviceInfoSet((_, errorState) -> SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, errorState)); } private DeviceInfoSet(InfoSetCreator creator) { @@ -321,10 +321,10 @@ private MemorySegment getVariableLengthProperty(MemorySegment propertyKey, int p if (propertyTypeHolder.get(JAVA_INT, 0) != propertyType) throwException("internal error (unexpected property type)"); - var stringLen = requiredSizeHolder.get(JAVA_INT, 0) / 2 - 1; + var stringLen = (requiredSizeHolder.get(JAVA_INT, 0) + 1) / 2; // allocate buffer - var propertyValueHolder = arena.allocateArray(JAVA_CHAR, stringLen + 1L); + var propertyValueHolder = arena.allocateArray(JAVA_CHAR, stringLen); // get property value if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java index 03fe5dc2..f8e5ba6e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java @@ -134,7 +134,7 @@ private void enumeratePresentDevices() { // ensure all hubs are closed later final var hubHandles = new HashMap(); - cleanup.add(() -> hubHandles.forEach((path, handle) -> Kernel32.CloseHandle(handle))); + cleanup.add(() -> hubHandles.forEach((_, handle) -> Kernel32.CloseHandle(handle))); // iterate all devices while (deviceInfoSet.next()) { @@ -313,7 +313,7 @@ private void onDeviceConnected(String devicePath) { // ensure all hubs are closed later final var hubHandles = new HashMap(); - cleanup.add(() -> hubHandles.forEach((path, handle) -> Kernel32.CloseHandle(handle))); + cleanup.add(() -> hubHandles.forEach((_, handle) -> Kernel32.CloseHandle(handle))); try { // create device instance From 29b4ac0564840514bec212129c6de7a453579503 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 3 Jan 2024 12:49:12 +0100 Subject: [PATCH 309/433] Windows: improved memory cleanup --- .../codecrete/usb/windows/DeviceInfoSet.java | 47 ++++++----- .../net/codecrete/usb/special/Unplug.java | 84 +++++++++++-------- 2 files changed, 74 insertions(+), 57 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java index 45c1fb1f..d9c9c5e9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java @@ -342,29 +342,30 @@ private MemorySegment getVariableLengthProperty(MemorySegment propertyKey, int p * @return the device path */ static String getDevicePath(String instanceId, MemorySegment interfaceGuid) { - try (var arena = Arena.ofConfined(); - var deviceInfoSet = DeviceInfoSet.ofPresentDevices(interfaceGuid, instanceId)) { - - // retrieve first element of enumeration - var errorState = allocateErrorState(arena); - var devIntfData = _SP_DEVICE_INTERFACE_DATA.allocate(arena); - _SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); - if (SetupAPI2.SetupDiEnumDeviceInterfaces(deviceInfoSet.devInfoSet, NULL, interfaceGuid, 0, devIntfData, - errorState) == 0) - throwLastError(errorState, "internal error (SetupDiEnumDeviceInterfaces)"); - - // get device path - // (SP_DEVICE_INTERFACE_DETAIL_DATA_W is of variable length and requires a bigger allocation so - // the device path fits) - final var devicePathOffset = 4; - var intfDetailData = arena.allocate(4L + 260 * 2); - _SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$set(intfDetailData, - (int) _SP_DEVICE_INTERFACE_DETAIL_DATA_W.sizeof()); - if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(deviceInfoSet.devInfoSet, devIntfData, intfDetailData, - (int) intfDetailData.byteSize(), NULL, NULL, errorState) == 0) - throwLastError(errorState, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); - - return Win.createStringFromSegment(intfDetailData.asSlice(devicePathOffset)); + try (var deviceInfoSet = DeviceInfoSet.ofPresentDevices(interfaceGuid, instanceId)) { + return deviceInfoSet.getDevicePathForGuid(interfaceGuid); } } + + private String getDevicePathForGuid(MemorySegment interfaceGuid) { + // retrieve first element of enumeration + devIntfData = _SP_DEVICE_INTERFACE_DATA.allocate(arena); + _SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); + if (SetupAPI2.SetupDiEnumDeviceInterfaces(devInfoSet, NULL, interfaceGuid, 0, devIntfData, + errorState) == 0) + throwLastError(errorState, "internal error (SetupDiEnumDeviceInterfaces)"); + + // get device path + // (SP_DEVICE_INTERFACE_DETAIL_DATA_W is of variable length and requires a bigger allocation so + // the device path fits) + final var devicePathOffset = 4; + var intfDetailData = arena.allocate(4L + 260 * 2); + _SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$set(intfDetailData, + (int) _SP_DEVICE_INTERFACE_DETAIL_DATA_W.sizeof()); + if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSet, devIntfData, intfDetailData, + (int) intfDetailData.byteSize(), NULL, NULL, errorState) == 0) + throwLastError(errorState, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); + + return Win.createStringFromSegment(intfDetailData.asSlice(devicePathOffset)); + } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java index 6d0e5f66..e77ad2d6 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java @@ -13,6 +13,8 @@ import java.io.IOException; import java.util.HashMap; +import java.util.Optional; +import java.util.stream.Stream; import static java.time.Duration.*; @@ -24,23 +26,25 @@ *

*/ public class Unplug { - /** - * Loopback test device vendor ID - */ - static final int VID_LOOPBACK = 0xcafe; - /** - * Loopback test device product ID - */ - static final int PID_LOOPBACK = 0xceaf; - /** - * Loopback test device loopback interface number - */ - static final int LOOPBACK_INTF = 0; - - private static final int LOOPBACK_EP_OUT = 1; - private static final int LOOPBACK_EP_IN = 2; - private static final int ECHO_EP_OUT = 3; - private static final int ECHO_EP_IN = 3; + static final DeviceConfig loopbackDevice = new DeviceConfig( + 0xcafe, + 0xceaf, + 0, + 1, + 2, + 3, + 3 + ); + + static final DeviceConfig compositeDevice = new DeviceConfig( + 0xcafe, + 0xcea0, + 3, + 1, + 2, + -1, + -1 + ); private static final HashMap activeDevices = new HashMap<>(); @@ -57,16 +61,18 @@ public static void main(String[] args) throws IOException { } private static void onPluggedDevice(UsbDevice device) { - if (!isTestDevice(device)) + var config = getTestDeviceConfig(device); + if (config.isEmpty()) return; - var worker = new DeviceWorker(device); + var worker = new DeviceWorker(device, config.get()); activeDevices.put(device, worker); worker.start(); } private static void onUnpluggedDevice(UsbDevice device) { - if (!isTestDevice(device)) + var config = getTestDeviceConfig(device); + if (config.isEmpty()) return; var worker = activeDevices.remove(device); @@ -74,14 +80,16 @@ private static void onUnpluggedDevice(UsbDevice device) { worker.join(); } - @SuppressWarnings("BooleanMethodIsAlwaysInverted") - private static boolean isTestDevice(UsbDevice device) { - return device.getVendorId() == VID_LOOPBACK && device.getProductId() == PID_LOOPBACK; + private static Optional getTestDeviceConfig(UsbDevice device) { + return Stream.of(loopbackDevice, compositeDevice) + .filter(config -> device.getVendorId() == config.vid() && device.getProductId() == config.pid()) + .findFirst(); } static class DeviceWorker { private final UsbDevice device; + private final DeviceConfig config; private final int seed; @@ -89,8 +97,9 @@ static class DeviceWorker { private final HashMap workTracking = new HashMap<>(); - DeviceWorker(UsbDevice device) { + DeviceWorker(UsbDevice device, DeviceConfig config) { this.device = device; + this.config = config; this.seed = (int) System.currentTimeMillis(); } @@ -98,15 +107,17 @@ void start() { System.out.println("Device connected"); device.open(); - device.claimInterface(LOOPBACK_INTF); + device.claimInterface(config.interfaceNumber()); // start loopback sender and receiver startThread((seed & 1) != 0 ? this::sendLoopbackDataStream : this::sendLoopbackData); startThread((seed & 2) != 0 ? this::receiveLoopbackDataStream : this::receiveLoopbackData); // start echo sender and receiver - startThread(this::sendEcho); - startThread(this::receiveEcho); + if (config.endpointEchoOut() > 0) { + startThread(this::sendEcho); + startThread(this::receiveEcho); + } } private void startThread(Runnable action) { @@ -186,7 +197,7 @@ private void sendLoopbackData() { //noinspection InfiniteLoopStatement while (true) { prng.fill(data); - device.transferOut(LOOPBACK_EP_OUT, data, 1000); + device.transferOut(config.endpointLoopbackOut(), data, 1000); logWork(data.length); } } @@ -196,7 +207,7 @@ private void receiveLoopbackData() { var prng = new PRNG(); //noinspection InfiniteLoopStatement while (true) { - byte[] data = device.transferIn(LOOPBACK_EP_IN); + byte[] data = device.transferIn(config.endpointLoopbackIn()); int index = prng.verify(data); if (index >= 0) throw new RuntimeException("invalid data received"); @@ -208,7 +219,7 @@ private void sendLoopbackDataStream() { logStart("sending loopback data with output stream", 300_000); var prng = new PRNG(); var data = new byte[5000]; - try (var os = device.openOutputStream(LOOPBACK_EP_OUT)) { + try (var os = device.openOutputStream(config.endpointLoopbackOut())) { //noinspection InfiniteLoopStatement while (true) { prng.fill(data); @@ -223,7 +234,7 @@ private void sendLoopbackDataStream() { private void receiveLoopbackDataStream() { logStart("receiving loopback data with input stream", 300_000); var prng = new PRNG(); - try (var is = device.openInputStream(LOOPBACK_EP_IN)) { + try (var is = device.openInputStream(config.endpointLoopbackIn())) { //noinspection InfiniteLoopStatement while (true) { var data = new byte[2000]; @@ -243,7 +254,7 @@ private void sendEcho() { var data = new byte[] { 0x03, 0x45, 0x73, (byte)0xb3, (byte)0x9f, 0x3f, 0x00, 0x6a }; //noinspection InfiniteLoopStatement while (true) { - device.transferOut(ECHO_EP_OUT, data); + device.transferOut(config.endpointEchoOut(), data); logWork(1); sleep(100); } @@ -253,12 +264,12 @@ private void receiveEcho() { logStart("receiving echo", 14); //noinspection InfiniteLoopStatement while (true) { - device.transferIn(ECHO_EP_IN); + device.transferIn(config.endpointEchoIn()); logWork(1); } } - @SuppressWarnings("SameParameterValue") + @SuppressWarnings({"SameParameterValue", "java:S2925"}) private static void sleep(long millis) { try { Thread.sleep(millis); @@ -324,4 +335,9 @@ int verify(byte[] data, int len) { return -1; } } + + record DeviceConfig(int vid, int pid, int interfaceNumber, + int endpointLoopbackOut, int endpointLoopbackIn, + int endpointEchoOut, int endpointEchoIn + ) {} } From 51c54c2d201f15426e732670f053174888c04332 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 3 Jan 2024 13:22:25 +0100 Subject: [PATCH 310/433] Windows: improve robustness --- .../net/codecrete/usb/windows/DeviceInfoSet.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java index d9c9c5e9..fbb62aba 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java @@ -77,7 +77,12 @@ static DeviceInfoSet ofPresentDevices(MemorySegment interfaceGuid, String instan */ static DeviceInfoSet ofInstance(String instanceId) { var devInfoSet = ofEmpty(); - devInfoSet.addInstanceId(instanceId); + try { + devInfoSet.addInstanceId(instanceId); + } catch (Throwable t) { + devInfoSet.close(); + throw t; + } return devInfoSet; } @@ -92,7 +97,12 @@ static DeviceInfoSet ofInstance(String instanceId) { */ static DeviceInfoSet ofPath(String devicePath) { var devInfoSet = ofEmpty(); - devInfoSet.addDevicePath(devicePath); + try { + devInfoSet.addDevicePath(devicePath); + } catch (Throwable t) { + devInfoSet.close(); + throw t; + } return devInfoSet; } From f5d0f921a4675d8c5eee5a6c2b8d8216f6dc8824 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 3 Jan 2024 14:21:09 +0100 Subject: [PATCH 311/433] Streamline configuration for test devices --- .../codecrete/usb/AlternateInterfaceTest.java | 23 ++++--- .../net/codecrete/usb/BulkTransferTest.java | 14 ++-- .../codecrete/usb/ControlTransferTest.java | 14 ++-- .../net/codecrete/usb/DescriptionTest.java | 13 ++-- .../codecrete/usb/DeviceEnumerationTest.java | 18 ++--- .../codecrete/usb/DeviceLifecycleTest.java | 2 +- .../codecrete/usb/InterruptTransferTest.java | 6 +- .../codecrete/usb/InvalidOperationTest.java | 1 + .../java/net/codecrete/usb/SpeedTest.java | 6 +- .../java/net/codecrete/usb/StallTest.java | 26 ++++--- .../java/net/codecrete/usb/StreamTest.java | 11 +-- .../net/codecrete/usb/TestDeviceBase.java | 68 ++++--------------- .../net/codecrete/usb/TestDeviceConfig.java | 66 ++++++++++++++++++ .../java/net/codecrete/usb/TimeoutTest.java | 28 +++++--- .../net/codecrete/usb/special/Unplug.java | 42 ++---------- test-devices/composite-stm32/README.md | 28 +++----- test-devices/loopback-stm32/README.md | 16 ++--- 17 files changed, 194 insertions(+), 188 deletions(-) create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/TestDeviceConfig.java diff --git a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java index 2cf058b2..12f05dcc 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java @@ -26,39 +26,42 @@ static void precondition() { @Test void selectAlternateIntf_succeeds() { - testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 1); + testDevice.selectAlternateSetting(config.interfaceNumber(), 1); - var altIntf = testDevice.getInterface(LOOPBACK_INTF_LOOPBACK).getCurrentAlternate(); + var altIntf = testDevice.getInterface(config.interfaceNumber()).getCurrentAlternate(); assertNotNull(altIntf); assertEquals(2, altIntf.getEndpoints().size()); assertEquals(0xff, altIntf.getClassCode()); - testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 0); + testDevice.selectAlternateSetting(config.interfaceNumber(), 0); } @Test void selectInvalidAlternateIntf_fails() { assertThrows(UsbException.class, () -> testDevice.selectAlternateSetting(1, 0)); - assertThrows(UsbException.class, () -> testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 2)); + var interface_number = config.interfaceNumber(); + assertThrows(UsbException.class, () -> testDevice.selectAlternateSetting(interface_number, 2)); } @Test void transferOnValidEndpoint_succeeds() { - testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 1); + testDevice.selectAlternateSetting(config.interfaceNumber(), 1); var sampleData = generateRandomBytes(12, 293872394); - testDevice.transferOut(LOOPBACK_EP_OUT, sampleData); - var received = testDevice.transferIn(LOOPBACK_EP_IN); + testDevice.transferOut(config.endpointLoopbackOut(), sampleData); + var received = testDevice.transferIn(config.endpointLoopbackIn()); assertArrayEquals(sampleData, received); } @Test void transferOnInvalidEndpoint_fails() { - testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 1); + testDevice.selectAlternateSetting(config.interfaceNumber(), 1); - assertThrows(UsbException.class, () -> testDevice.transferOut(ECHO_EP_OUT, new byte[] { 1, 2, 3 })); + var endpointOut = config.endpointEchoOut(); + assertThrows(UsbException.class, () -> testDevice.transferOut(endpointOut, new byte[] { 1, 2, 3 })); - assertThrows(UsbException.class, () -> testDevice.transferIn(ECHO_EP_IN)); + var endpointIn = config.endpointEchoIn(); + assertThrows(UsbException.class, () -> testDevice.transferIn(endpointIn)); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java index da1f5c7c..08e80e42 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java @@ -39,13 +39,13 @@ void mediumTransfer_succeeds() { @Test void transferWithZLP_succeeds() { - var inEndpoint = testDevice.getEndpoint(UsbDirection.IN, LOOPBACK_EP_IN); + var inEndpoint = testDevice.getEndpoint(UsbDirection.IN, config.endpointLoopbackIn()); var sampleData = generateRandomBytes(inEndpoint.getPacketSize(), 97333894); - testDevice.transferOut(LOOPBACK_EP_OUT, sampleData); - testDevice.transferOut(LOOPBACK_EP_OUT, new byte[0]); - var data = testDevice.transferIn(LOOPBACK_EP_IN); + testDevice.transferOut(config.endpointLoopbackOut(), sampleData); + testDevice.transferOut(config.endpointLoopbackOut(), new byte[0]); + var data = testDevice.transferIn(config.endpointLoopbackIn()); assertArrayEquals(sampleData, data); - data = testDevice.transferIn(LOOPBACK_EP_IN); + data = testDevice.transferIn(config.endpointLoopbackIn()); assertNotNull(data); assertEquals(0, data.length); } @@ -67,7 +67,7 @@ static void writeBytes(byte[] data) { var numBytes = 0; while (numBytes < data.length) { var size = Math.min(chunkSize, data.length - numBytes); - testDevice.transferOut(LOOPBACK_EP_OUT, Arrays.copyOfRange(data, numBytes, numBytes + size)); + testDevice.transferOut(config.endpointLoopbackOut(), Arrays.copyOfRange(data, numBytes, numBytes + size)); numBytes += size; } } @@ -75,7 +75,7 @@ static byte[] readBytes(int numBytes) { var buffer = new ByteArrayOutputStream(); var bytesRead = 0; while (bytesRead < numBytes) { - var data = testDevice.transferIn(LOOPBACK_EP_IN); + var data = testDevice.transferIn(config.endpointLoopbackIn()); buffer.writeBytes(data); bytesRead += data.length; } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java index de26d03f..9d09d4eb 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java @@ -20,14 +20,14 @@ class ControlTransferTest extends TestDeviceBase { @Test void storeValue_succeeds() { - var setup = new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x01, (short) 10730, (short) interfaceNumber); + var setup = new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x01, (short) 10730, (short) config.interfaceNumber()); assertDoesNotThrow(() -> testDevice.controlTransferOut(setup, null)); } @Test void retrieveValue_isSameAsStored() { - testDevice.controlTransferOut(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x01, (short) 0x9a41, (short) interfaceNumber), null); - var valueBytes = testDevice.controlTransferIn(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) interfaceNumber), 4); + testDevice.controlTransferOut(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x01, (short) 0x9a41, (short) config.interfaceNumber()), null); + var valueBytes = testDevice.controlTransferIn(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) config.interfaceNumber()), 4); var expectedBytes = new byte[]{(byte) 0x41, (byte) 0x9a, (byte) 0x00, (byte) 0x00}; assertArrayEquals(expectedBytes, valueBytes); } @@ -35,15 +35,15 @@ void retrieveValue_isSameAsStored() { @Test void storeValueInDataStage_canBeRetrieved() { var sentValue = new byte[]{(byte) 0x83, (byte) 0x03, (byte) 0xda, (byte) 0x3e}; - testDevice.controlTransferOut(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x02, (short) 0, (short) interfaceNumber), sentValue); - var retrievedValue = testDevice.controlTransferIn(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) interfaceNumber), 4); + testDevice.controlTransferOut(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x02, (short) 0, (short) config.interfaceNumber()), sentValue); + var retrievedValue = testDevice.controlTransferIn(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x03, (short) 0, (short) config.interfaceNumber()), 4); assertArrayEquals(sentValue, retrievedValue); } @Test void interfaceNumber_canBeRetrieved() { - var response = testDevice.controlTransferIn(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x05, (short) 0, (short) interfaceNumber), 1); - assertEquals(interfaceNumber, response[0] & 0xff); + var response = testDevice.controlTransferIn(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x05, (short) 0, (short) config.interfaceNumber()), 1); + assertEquals(config.interfaceNumber(), response[0] & 0xff); if (isCompositeDevce()) { testDevice.claimInterface(2); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index 90257e23..801f68f1 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -50,10 +50,10 @@ void deviceInfo_isCorrect() { @Test void interfaceDescriptor_isCorrect() { assertNotNull(testDevice.getInterfaces()); - assertEquals(interfaceNumber + 1, testDevice.getInterfaces().size()); + assertEquals(config.interfaceNumber() + 1, testDevice.getInterfaces().size()); - var intf = testDevice.getInterfaces().get(interfaceNumber); - assertEquals(interfaceNumber, intf.getNumber()); + var intf = testDevice.getInterfaces().get(config.interfaceNumber()); + assertEquals(config.interfaceNumber(), intf.getNumber()); assertNotNull(intf.getCurrentAlternate()); assertTrue(intf.isClaimed()); } @@ -65,7 +65,7 @@ void invalidInterfaceNumber_shouldThrow() { @Test void alternateInterfaceDescriptor_isCorrect() { - var intf = testDevice.getInterfaces().get(interfaceNumber); + var intf = testDevice.getInterfaces().get(config.interfaceNumber()); var altIntf = intf.getCurrentAlternate(); assertNotNull(intf.getAlternates()); assertEquals(isLoopbackDevice() ? 2 : 1, intf.getAlternates().size()); @@ -86,9 +86,10 @@ void alternateInterfaceDescriptor_isCorrect() { } } + @SuppressWarnings("java:S5961") @Test void endpointDescriptors_areCorrect() { - var altIntf = testDevice.getInterfaces().get(interfaceNumber).getCurrentAlternate(); + var altIntf = testDevice.getInterfaces().get(config.interfaceNumber()).getCurrentAlternate(); assertNotNull(altIntf.getEndpoints()); assertEquals(isLoopbackDevice() ? 4 : 2, altIntf.getEndpoints().size()); @@ -118,7 +119,7 @@ void endpointDescriptors_areCorrect() { assertEquals(16, endpoint.getPacketSize()); // test alternate interface 1 - altIntf = testDevice.getInterfaces().get(interfaceNumber).getAlternates().get(1); + altIntf = testDevice.getInterfaces().get(config.interfaceNumber()).getAlternates().get(1); assertEquals(2, altIntf.getEndpoints().size()); endpoint = altIntf.getEndpoints().getFirst(); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java index 84384446..7d3c259f 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceEnumerationTest.java @@ -20,30 +20,30 @@ void getAllDevices_includesLoopback() { var deviceList = Usb.getDevices(); assertThat(deviceList) .isNotEmpty() - .anyMatch(device -> device.getVendorId() == vid && device.getProductId() == pid); + .anyMatch(device -> device.getVendorId() == config.vid() && device.getProductId() == config.pid()); } @Test void getDevices_includesLoopback() { - var deviceList = Usb.findDevices(device -> device.getVendorId() == vid && device.getProductId() == pid); + var deviceList = Usb.findDevices(device -> device.getVendorId() == config.vid() && device.getProductId() == config.pid()); assertThat(deviceList) .isNotEmpty() - .anyMatch(device -> device.getVendorId() == vid && device.getProductId() == pid); + .anyMatch(device -> device.getVendorId() == config.vid() && device.getProductId() == config.pid()); } @Test void getDevicePredicate_returnsLoopback() { - var device = Usb.findDevice(dev -> dev.getVendorId() == vid && dev.getProductId() == pid); + var device = Usb.findDevice(dev -> dev.getVendorId() == config.vid() && dev.getProductId() == config.pid()); assertThat(device).isPresent(); - assertThat(device.get().getProductId()).isEqualTo(pid); - assertThat(device.get().getVendorId()).isEqualTo(vid); + assertThat(device.get().getProductId()).isEqualTo(config.pid()); + assertThat(device.get().getVendorId()).isEqualTo(config.vid()); } @Test void getDeviceVidPid_returnsLoopback() { - var device = Usb.findDevice(vid, pid); + var device = Usb.findDevice(config.vid(), config.pid()); assertThat(device).isPresent(); - assertThat(device.get().getProductId()).isEqualTo(pid); - assertThat(device.get().getVendorId()).isEqualTo(vid); + assertThat(device.get().getProductId()).isEqualTo(config.pid()); + assertThat(device.get().getVendorId()).isEqualTo(config.vid()); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java index 2e40e5d9..69ba2938 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java @@ -21,7 +21,7 @@ class DeviceLifecycleTest { @Test void lifecycle_showsValidState() { device = TestDeviceBase.getDevice(); - var interfaceNumber = TestDeviceBase.getInterfaceNumber(device); + var interfaceNumber = TestDeviceBase.getDeviceConfig().interfaceNumber(); var intf = device.getInterfaces().get(interfaceNumber); assertEquals(interfaceNumber, intf.getNumber()); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java index 5a2379a8..f59ab124 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InterruptTransferTest.java @@ -22,14 +22,14 @@ void smallTransfer_succeeds() { "Interrupt transfer only supported by loopback test device"); var sampleData = generateRandomBytes(12, 293872394); - testDevice.transferOut(ECHO_EP_OUT, sampleData); + testDevice.transferOut(config.endpointEchoOut(), sampleData); // receive first echo - var echo = testDevice.transferIn(ECHO_EP_IN); + var echo = testDevice.transferIn(config.endpointEchoIn()); assertArrayEquals(sampleData, echo); // receive second echo - echo = testDevice.transferIn(ECHO_EP_IN); + echo = testDevice.transferIn(config.endpointEchoIn()); assertArrayEquals(sampleData, echo); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java index 7682009a..014f4cb9 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java @@ -16,6 +16,7 @@ class InvalidOperationTest extends TestDeviceBase { @Test void claimInvalidInterface_throws() { + var interfaceNumber = config.interfaceNumber(); // throws error because it's already claimed Assertions.assertThrows(UsbException.class, () -> testDevice.claimInterface(interfaceNumber)); // throws error because it's an invalid interface number diff --git a/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java index aa9b1c5c..33d0b82f 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java @@ -20,7 +20,7 @@ class SpeedTest extends TestDeviceBase { @Test void loopback_isFast() throws Throwable { - final var isHighSpeed = testDevice.getEndpoint(UsbDirection.IN, LOOPBACK_EP_IN).getPacketSize() == 512; + final var isHighSpeed = testDevice.getEndpoint(UsbDirection.IN, config.endpointLoopbackIn()).getPacketSize() == 512; final var numBytes = isHighSpeed ? 5000000 : 500000; var sampleData = generateRandomBytes(numBytes, 7219937602343L); @@ -43,14 +43,14 @@ void loopback_isFast() throws Throwable { } static void writeBytes(byte[] data) { - try (var os = testDevice.openOutputStream(LOOPBACK_EP_OUT)) { + try (var os = testDevice.openOutputStream(config.endpointLoopbackOut())) { os.write(data); } catch (IOException e) { throw new RuntimeException(e); } } static byte[] readBytes(int numBytes) { - try (var is = testDevice.openInputStream(LOOPBACK_EP_IN)) { + try (var is = testDevice.openInputStream(config.endpointLoopbackIn())) { var buffer = new byte[numBytes]; var bytesRead = 0; while (bytesRead < numBytes) { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java index 7fce14a1..1fd63748 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java @@ -18,36 +18,40 @@ class StallTest extends TestDeviceBase { @Test void stalledBulkTransferOut_recovers() { - haltEndpoint(UsbDirection.OUT, LOOPBACK_EP_OUT); + var endpointIn = config.endpointLoopbackIn(); + var endpointOut = config.endpointLoopbackOut(); + haltEndpoint(UsbDirection.OUT, endpointOut); var data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - assertThrows(UsbStallException.class, () -> testDevice.transferOut(LOOPBACK_EP_OUT, data)); + assertThrows(UsbStallException.class, () -> testDevice.transferOut(endpointOut, data)); - testDevice.clearHalt(UsbDirection.OUT, LOOPBACK_EP_OUT); + testDevice.clearHalt(UsbDirection.OUT, endpointOut); - testDevice.transferOut(LOOPBACK_EP_OUT, data); - var receivedData = testDevice.transferIn(LOOPBACK_EP_IN); + testDevice.transferOut(endpointOut, data); + var receivedData = testDevice.transferIn(endpointIn); assertArrayEquals(data, receivedData); } @Test void stalledBulkTransferIn_recovers() { - haltEndpoint(UsbDirection.IN, LOOPBACK_EP_IN); + var endpointIn = config.endpointLoopbackIn(); + var endpointOut = config.endpointLoopbackOut(); + haltEndpoint(UsbDirection.IN, endpointIn); - assertThrows(UsbStallException.class, () -> testDevice.transferIn(LOOPBACK_EP_IN)); + assertThrows(UsbStallException.class, () -> testDevice.transferIn(endpointIn)); - testDevice.clearHalt(UsbDirection.IN, LOOPBACK_EP_IN); + testDevice.clearHalt(UsbDirection.IN, endpointIn); var data = new byte[] { 9, 8, 7, 6, 5, 4, 3, 2 }; - testDevice.transferOut(LOOPBACK_EP_OUT, data); - var receivedData = testDevice.transferIn(LOOPBACK_EP_IN); + testDevice.transferOut(endpointOut, data); + var receivedData = testDevice.transferIn(endpointIn); assertArrayEquals(data, receivedData); } @Test void invalidControlTransfer_throws() { var request = new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, (byte) 0x08, - (short) 0, (short) interfaceNumber); + (short) 0, (short) config.interfaceNumber()); assertThrows(UsbStallException.class, () -> testDevice.controlTransferIn(request, 2)); } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java index fb090bca..c6e0da3e 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java @@ -40,11 +40,12 @@ void mediumTransfer_succeeds() { @Test void transferWithZLP_succeeds() { - final var sampleData = generateRandomBytes(2 * LOOPBACK_MAX_PACKET_SIZE, 197007894); + var maxPacketSize = testDevice.getEndpoint(UsbDirection.OUT, config.endpointLoopbackOut()).getPacketSize(); + final var sampleData = generateRandomBytes(2 * maxPacketSize, 197007894); var writer = CompletableFuture.runAsync(() -> { - testDevice.transferOut(LOOPBACK_EP_OUT, Arrays.copyOfRange(sampleData, 0, LOOPBACK_MAX_PACKET_SIZE)); + testDevice.transferOut(config.endpointLoopbackOut(), Arrays.copyOfRange(sampleData, 0, maxPacketSize)); sleep(200); - testDevice.transferOut(LOOPBACK_EP_OUT, Arrays.copyOfRange(sampleData, LOOPBACK_MAX_PACKET_SIZE, 2 * LOOPBACK_MAX_PACKET_SIZE)); + testDevice.transferOut(config.endpointLoopbackOut(), Arrays.copyOfRange(sampleData, maxPacketSize, 2 * maxPacketSize)); }); var reader = CompletableFuture.supplyAsync(() -> readBytes(sampleData.length)); @@ -76,7 +77,7 @@ void largeTransferBigChunks_succeeds() { } static void writeBytes(byte[] data, int chunkSize) { - try (var os = testDevice.openOutputStream(LOOPBACK_EP_OUT)) { + try (var os = testDevice.openOutputStream(config.endpointLoopbackOut())) { var numBytes = 0; while (numBytes < data.length) { var size = Math.min(chunkSize, data.length - numBytes); @@ -90,7 +91,7 @@ static void writeBytes(byte[] data, int chunkSize) { } static byte[] readBytes(int numBytes) { var buffer = new byte[numBytes]; - try (var is = testDevice.openInputStream(LOOPBACK_EP_IN)) { + try (var is = testDevice.openInputStream(config.endpointLoopbackIn())) { var bytesRead = 0; while (bytesRead < numBytes) { var n = is.read(buffer, bytesRead, numBytes - bytesRead); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index c35f5cd9..9b81680f 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -18,66 +18,28 @@ * Base class for tests using the test device. */ public class TestDeviceBase { - /** - * Loopback test device vendor ID - */ - static final int VID_LOOPBACK = 0xcafe; - /** - * Loopback test device product ID - */ - static final int PID_LOOPBACK = 0xceaf; - /** - * Loopback test device loopback interface number - */ - static final int LOOPBACK_INTF_LOOPBACK = 0; - /** - * Composite test device vendor ID - */ - static final int VID_COMPOSITE = 0xcafe; - /** - * Composite test device product ID - */ - static final int PID_COMPOSITE = 0xcea0; - /** - * Composite test device loopback interface number - */ - static final int LOOPBACK_INTF_COMPOSITE = 3; - /** - * Interface number of connected test device - */ - protected static int vid = -1; - protected static int pid = -1; - protected static int interfaceNumber = -1; - protected static final int LOOPBACK_EP_OUT = 1; - protected static final int LOOPBACK_EP_IN = 2; - protected static final int LOOPBACK_MAX_PACKET_SIZE = 64; - protected static final int ECHO_EP_OUT = 3; - protected static final int ECHO_EP_IN = 3; - protected static final int ECHO_MAX_PACKET_SIZE = 16; + protected static UsbDevice testDevice; + protected static TestDeviceConfig config; static UsbDevice getDevice() { - var optionalDevice = Usb.findDevice(VID_COMPOSITE, PID_COMPOSITE); - if (optionalDevice.isEmpty()) - optionalDevice = Usb.findDevice(VID_LOOPBACK, PID_LOOPBACK); - if (optionalDevice.isEmpty()) + var device = Usb.findDevice(dev -> TestDeviceConfig.getConfig(dev).isPresent()); + if (device.isEmpty()) throw new IllegalStateException("No test device connected"); - return optionalDevice.get(); + return device.get(); } - static int getInterfaceNumber(UsbDevice device) { - return device.getProductId() == PID_COMPOSITE ? LOOPBACK_INTF_COMPOSITE : LOOPBACK_INTF_LOOPBACK; + static TestDeviceConfig getDeviceConfig() { + return TestDeviceConfig.getConfig(getDevice()).orElse(null); } @BeforeAll static void openDevice() { testDevice = getDevice(); - vid = testDevice.getVendorId(); - pid = testDevice.getProductId(); - interfaceNumber = getInterfaceNumber(testDevice); + config = getDeviceConfig(); testDevice.open(); - testDevice.claimInterface(interfaceNumber); + testDevice.claimInterface(config.interfaceNumber()); resetDevice(); } @@ -91,16 +53,16 @@ static void closeDevice() { } static boolean isLoopbackDevice() { - return pid == PID_LOOPBACK; + return !config.isComposite(); } static boolean isCompositeDevce() { - return pid == PID_COMPOSITE; + return config.isComposite(); } private static void resetDevice() { if (isLoopbackDevice()) - testDevice.selectAlternateSetting(LOOPBACK_INTF_LOOPBACK, 0); + testDevice.selectAlternateSetting(config.interfaceNumber(), 0); // reset buffers resetBuffers(); @@ -108,7 +70,7 @@ private static void resetDevice() { // drain loopback data while (true) { try { - testDevice.transferIn(LOOPBACK_EP_IN, 1); + testDevice.transferIn(config.endpointLoopbackIn(), 1); } catch (UsbTimeoutException e) { break; } @@ -118,7 +80,7 @@ private static void resetDevice() { if (isLoopbackDevice()) { while (true) { try { - testDevice.transferIn(ECHO_EP_IN, 1); + testDevice.transferIn(config.endpointEchoIn(), 1); } catch (UsbTimeoutException e) { break; } @@ -131,7 +93,7 @@ private static void resetDevice() { static void resetBuffers() { testDevice.controlTransferOut(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.INTERFACE, - (byte) 0x04, (short) 0, (short) interfaceNumber), null); + (byte) 0x04, (short) 0, (short) config.interfaceNumber()), null); } static byte[] generateRandomBytes(int numBytes, long seed) { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceConfig.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceConfig.java new file mode 100644 index 00000000..9e386734 --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceConfig.java @@ -0,0 +1,66 @@ +// +// Java Does USB +// Copyright (c) 2024 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Configuration information about test device +// + +package net.codecrete.usb; + +import java.util.Optional; +import java.util.stream.Stream; + +/** + * Test device configuration + * @param vid vendor ID + * @param pid product ID + * @param isComposite indicates if this is the composite test device + * @param interfaceNumber interface number for loopback and echo endpoints + * @param endpointLoopbackOut loopback OUT endpoint number + * @param endpointLoopbackIn loopback IN endpoint number + * @param endpointEchoOut echo OUT endpoint number + * @param endpointEchoIn echo IN endpoint number + */ +public record TestDeviceConfig(int vid, int pid, + boolean isComposite, + int interfaceNumber, + int endpointLoopbackOut, int endpointLoopbackIn, + int endpointEchoOut, int endpointEchoIn +) { + + private static final TestDeviceConfig LOOPBACK_DEVICE = new TestDeviceConfig( + 0xcafe, + 0xceaf, + false, + 0, + 1, + 2, + 3, + 3 + ); + + private static final TestDeviceConfig COMPOSITE_DEVICE = new TestDeviceConfig( + 0xcafe, + 0xcea0, + true, + 3, + 1, + 2, + -1, + -1 + ); + + + /** + * Gets the configuration fo the specified USB device. + * @param device USB device + * @return configuration, or empty if the USB device is not a test device + */ + public static Optional getConfig(UsbDevice device) { + return Stream.of(LOOPBACK_DEVICE, COMPOSITE_DEVICE) + .filter(config -> device.getVendorId() == config.vid() && device.getProductId() == config.pid()) + .findFirst(); + } +} diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java index 619aded7..b9028797 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java @@ -18,21 +18,23 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +@SuppressWarnings("DefaultAnnotationParam") class TimeoutTest extends TestDeviceBase { @Test @Timeout(value = 1, unit = TimeUnit.SECONDS) void bulkTransferIn_timesOut() { - assertThrows(UsbTimeoutException.class, () -> testDevice.transferIn(LOOPBACK_EP_IN, 200)); + var endpointIn = config.endpointLoopbackIn(); + assertThrows(UsbTimeoutException.class, () -> testDevice.transferIn(endpointIn, 200)); } @Test @Timeout(value = 1, unit = TimeUnit.SECONDS) void bulkTransfer_doesNotTimeOut() { var data = generateRandomBytes(20, 7280277392L); - testDevice.transferOut(LOOPBACK_EP_OUT, data); + testDevice.transferOut(config.endpointLoopbackOut(), data); - var received = testDevice.transferIn(LOOPBACK_EP_IN, 200); + var received = testDevice.transferIn(config.endpointLoopbackIn(), 200); assertArrayEquals(data, received); } @@ -40,24 +42,27 @@ void bulkTransfer_doesNotTimeOut() { @Test @Timeout(value = 1, unit = TimeUnit.SECONDS) void bulkTransferOut_timesOut() { + var endpointOut = config.endpointLoopbackOut(); + var endpointIn = config.endpointLoopbackIn(); + // The test device has an internal buffer of about 2KB for full-speed // and 16KB for high-speed. The first transfer should not time out. final var bufferSize = 32 * testDevice - .getEndpoint(UsbDirection.OUT, LOOPBACK_EP_OUT).getPacketSize(); + .getEndpoint(UsbDirection.OUT, endpointOut).getPacketSize(); var data = generateRandomBytes(100, 9383073929L); - testDevice.transferOut(LOOPBACK_EP_OUT, data, 200); + testDevice.transferOut(endpointOut, data, 200); assertThrows(UsbTimeoutException.class, () -> { for (var i = 0; i < bufferSize / data.length; i++) { - testDevice.transferOut(LOOPBACK_EP_OUT, data, 200); + testDevice.transferOut(endpointOut, data, 200); } }); // drain data in loopback loop while (true) { try { - testDevice.transferIn(LOOPBACK_EP_IN, 200); + testDevice.transferIn(endpointIn, 200); } catch (UsbTimeoutException e) { break; } @@ -70,7 +75,8 @@ void interruptTransferIn_timesOut() { Assumptions.assumeTrue(isLoopbackDevice(), "Interrupt transfer only supported by loopback test device"); - assertThrows(UsbTimeoutException.class, () -> testDevice.transferIn(ECHO_EP_IN, 200)); + var endpointIn = config.endpointEchoIn(); + assertThrows(UsbTimeoutException.class, () -> testDevice.transferIn(endpointIn, 200)); } @Test @@ -79,14 +85,14 @@ void interruptTransfer_doesNotTimeOut() { "Interrupt transfer only supported by loopback test device"); var sampleData = generateRandomBytes(12, 293872394); - testDevice.transferOut(ECHO_EP_OUT, sampleData, 200); + testDevice.transferOut(config.endpointEchoOut(), sampleData, 200); // receive first echo - var echo = testDevice.transferIn(ECHO_EP_IN, 200); + var echo = testDevice.transferIn(config.endpointEchoIn(), 200); assertArrayEquals(sampleData, echo); // receive second echo - echo = testDevice.transferIn(ECHO_EP_IN, 200); + echo = testDevice.transferIn(config.endpointEchoIn(), 200); assertArrayEquals(sampleData, echo); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java index e77ad2d6..a4ea7ee2 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java @@ -7,14 +7,13 @@ package net.codecrete.usb.special; +import net.codecrete.usb.TestDeviceConfig; import net.codecrete.usb.Usb; import net.codecrete.usb.UsbDevice; import net.codecrete.usb.UsbException; import java.io.IOException; import java.util.HashMap; -import java.util.Optional; -import java.util.stream.Stream; import static java.time.Duration.*; @@ -26,26 +25,6 @@ *

*/ public class Unplug { - static final DeviceConfig loopbackDevice = new DeviceConfig( - 0xcafe, - 0xceaf, - 0, - 1, - 2, - 3, - 3 - ); - - static final DeviceConfig compositeDevice = new DeviceConfig( - 0xcafe, - 0xcea0, - 3, - 1, - 2, - -1, - -1 - ); - private static final HashMap activeDevices = new HashMap<>(); public static void main(String[] args) throws IOException { @@ -61,7 +40,7 @@ public static void main(String[] args) throws IOException { } private static void onPluggedDevice(UsbDevice device) { - var config = getTestDeviceConfig(device); + var config = TestDeviceConfig.getConfig(device); if (config.isEmpty()) return; @@ -71,7 +50,7 @@ private static void onPluggedDevice(UsbDevice device) { } private static void onUnpluggedDevice(UsbDevice device) { - var config = getTestDeviceConfig(device); + var config = TestDeviceConfig.getConfig(device); if (config.isEmpty()) return; @@ -80,16 +59,10 @@ private static void onUnpluggedDevice(UsbDevice device) { worker.join(); } - private static Optional getTestDeviceConfig(UsbDevice device) { - return Stream.of(loopbackDevice, compositeDevice) - .filter(config -> device.getVendorId() == config.vid() && device.getProductId() == config.pid()) - .findFirst(); - } - static class DeviceWorker { private final UsbDevice device; - private final DeviceConfig config; + private final TestDeviceConfig config; private final int seed; @@ -97,7 +70,7 @@ static class DeviceWorker { private final HashMap workTracking = new HashMap<>(); - DeviceWorker(UsbDevice device, DeviceConfig config) { + DeviceWorker(UsbDevice device, TestDeviceConfig config) { this.device = device; this.config = config; this.seed = (int) System.currentTimeMillis(); @@ -335,9 +308,4 @@ int verify(byte[] data, int len) { return -1; } } - - record DeviceConfig(int vid, int pid, int interfaceNumber, - int endpointLoopbackOut, int endpointLoopbackIn, - int endpointEchoOut, int endpointEchoIn - ) {} } diff --git a/test-devices/composite-stm32/README.md b/test-devices/composite-stm32/README.md index eb8e508e..931eef4e 100644 --- a/test-devices/composite-stm32/README.md +++ b/test-devices/composite-stm32/README.md @@ -15,22 +15,14 @@ To upload the firmware, the STM32F4x microcontroller have a built-in USB bootloa ### Endpoints -#define EP_CDC_COMM 0x83 -#define EP_CDC_DATA_RX 0x02 -#define EP_CDC_DATA_TX 0x81 - -#define EP_LOOPBACK_RX 0x01 -#define EP_LOOPBACK_TX 0x82 - - -| Endpoint | Transfer Type | Direction | Packet Size | Function | -| - | - | - | - | - | -| 0x00 | Control | Bidirectional | | See *Control requests* below | -| 0x81 | Bulk | Device to host | 64 bytes | CDC: Serial data from device to host. | -| 0x02 | Bulk | Host to device | 64 bytes | CDC: Serial data from host to device. | -| 0x83 | Interrupt | Device to host | 64 bytes | CDC: Serial state events (not used). | -| 0x01 | Bulk | Host to device | 64 bytes | Loopback: all data received on this endpoint is transmitted on endpoint 0x82. | -| 0x82 | Bulk | Device to host | 64 bytes | Loopback: Transmits the data received on endpoint 0x01. | +| Endpoint | Transfer Type | Direction | Packet Size | Interface | Function | +| - | - | - | - | - | - | +| 0x00 | Control | Bidirectional | | 2 | See *Control requests* below | +| 0x81 | Bulk | Device to host | 64 bytes | 1 | CDC: Serial data from device to host. | +| 0x02 | Bulk | Host to device | 64 bytes | 1 | CDC: Serial data from host to device. | +| 0x83 | Interrupt | Device to host | 64 bytes | 0 | CDC: Serial state events (not used). | +| 0x01 | Bulk | Host to device | 64 bytes | 3 | Loopback: all data received on this endpoint is transmitted on endpoint 0x82. | +| 0x82 | Bulk | Device to host | 64 bytes | 3 | Loopback: Transmits the data received on endpoint 0x01. | The virtual serial port on interfaces 0 and 1 implements the CDC ACM class. All operating systems will recognize it as serial port and will automatically make it available as such. No drivers need to be installed. The implementations connects the incoming and outgoing data in a loopback configuration. So all data sent from the host to the device is send back to the host. Control requests to configure baud rates, parity etc. are accepted but have no effect. And the implementation does not send any state events. @@ -46,6 +38,8 @@ Several vendor-specific control requests are supported for testing: | 0x41 | 0x01 | *value* | 0 | 0 | none | Host to device: *value* is saved in device | | 0x41 | 0x02 | 0 | 0 | 4 | *value* (32-bit LE) | Host to device: *value* is saved in device | | 0xC1 | 0x03 | 0 | 0 | 4 | *value* (32-bit LE) | Device to host: saved *value* is transmitted | +| 0xC1 | 0x05 | 0 | 0 | 1 | *interface number* | Device to host: interface number is transmitted | + ## Building the firmware @@ -114,4 +108,4 @@ If you built the firmware yourself, you will find the firmware file in `.pio/bui This code uses the CMSIS 5 library (mainly for startup code and register definitions) and TinyUSB for USB. For easier use with PlatformIO, a copy of TinyUSB is integrated into the project. The used TinyUSB code in `lib/tinyusb` is an unmodified subset of the library. -Since the official TinyUSB vendor class is rather limited, an alternative implementation is provided (see [vendor_custom.h](include/vendor_custom.h) and [vendor_custom.c](src/vendor_custom.c)). \ No newline at end of file +Since the official TinyUSB vendor class is rather limited, an alternative implementation is provided (see [vendor_custom.h](src/vendor_custom.h) and [vendor_custom.c](src/vendor_custom.c)). \ No newline at end of file diff --git a/test-devices/loopback-stm32/README.md b/test-devices/loopback-stm32/README.md index a30ffa10..b485a64d 100644 --- a/test-devices/loopback-stm32/README.md +++ b/test-devices/loopback-stm32/README.md @@ -15,13 +15,13 @@ To upload the firmware, the STM32F4x microcontroller have a built-in USB bootloa ### Endpoints -| Endpoint | Transfer Type | Direction | Packet Size | Function | -| - | - | - | - | - | -| 0x00 | Control | Bidirectional | | See *Control requests* below | -| 0x01 | Bulk | Host to device | 64 bytes | Loopback: all data received on this endpoint are then transmitted on endpoint 0x82. | -| 0x82 | Bulk | Device to host | 64 bytes | Loopback: Transmits the data received on endpoint 0x01. | -| 0x03 | Interrupt | Host to device | 16 bytes | Echo: All packets received on this endpoint are transmitted twice on endpoint 0x83. | -| 0x83 | Interrupt | Device to host | 16 bytes | Echo: Transmits all packets received on endpoint 0x03 twice. | +| Endpoint | Transfer Type | Direction | Packet Size | Interface | Function | +| - | - | - | - | - | - | +| 0x00 | Control | Bidirectional | | 0 | See *Control requests* below | +| 0x01 | Bulk | Host to device | 64 bytes | 0 | Loopback: all data received on this endpoint are then transmitted on endpoint 0x82. | +| 0x82 | Bulk | Device to host | 64 bytes | 0 | Loopback: Transmits the data received on endpoint 0x01. | +| 0x03 | Interrupt | Host to device | 16 bytes | 0 | Echo: All packets received on this endpoint are transmitted twice on endpoint 0x83. | +| 0x83 | Interrupt | Device to host | 16 bytes | 0 | Echo: Transmits all packets received on endpoint 0x03 twice. | The bulk endpoints 0x01 and 0x82 use an internal buffer of about 500 bytes. Data up to this amount can be sent and received sequentially. If more data is sent without receiving at the same time, flow control kicks in and endpoint 0x01 will stop receiving data until there is room in the buffer. @@ -111,4 +111,4 @@ If you built the firmware yourself, you will find the firmware file in `.pio/bui This code uses the CMSIS 5 library (mainly for startup code and register definitions) and TinyUSB for USB. For easier use with PlatformIO, a copy of TinyUSB is integrated into the project. The used TinyUSB code in `lib/tinyusb` is an unmodified subset of the library. -Since the official TinyUSB vendor class is rather limited, an alternative implementation is provided (see [vendor_custom.h](include/vendor_custom.h) and [vendor_custom.c](src/vendor_custom.c)). \ No newline at end of file +Since the official TinyUSB vendor class is rather limited, an alternative implementation is provided (see [vendor_custom.h](src/vendor_custom.h) and [vendor_custom.c](src/vendor_custom.c)). \ No newline at end of file From 56d014596feeb80d73360e22da298df91868d398 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 3 Jan 2024 14:40:17 +0100 Subject: [PATCH 312/433] Add troubleshooting section --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 90317fe3..9d032457 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,13 @@ The test devices implement the required control requests. So the driver is insta The library has not been tested on Windows for ARM64. It might or might not work. +### Troubleshooting + +- The error `java.lang.ClassFormatError: Illegal field name "" in class net/codecrete/usb/windows/WindowsUsbDeviceRegistry` is caused by a bug in JDK 21, which has been fixed in the mean-time. Please upgrade to the latest release of JDK 21. + +- The error `Cannot open library: CoreFoundation.framework/CoreFoundation` is caused by an unfortunate build of the OpenJDK by Homebrew. Please use any other JDK edition instead, e.g. Zulu (`brew install zulu` or directly from https://www.azul.com/downloads/#zulu), Temurin (`brew install temurin` or from https://adoptium.net/en-GB/temurin/releases/), or download the official OpenJDK directly from https://openjdk.org/projects/jdk/21/. And don't forget to uninstall the Homebrew build (`brew uninstall openjdk`). + + ### 32-bit versions The Foreign Function & Memory API has not been implemented for 32-bit operating systems / JDKs (and likely never will be). From 8db08aab9fe295acb68181ea470a3095e6d0f8d3 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 3 Jan 2024 15:43:43 +0100 Subject: [PATCH 313/433] Prepare for release 0.7 --- .github/workflows/continuous-integration.yaml | 4 +- README.md | 27 ++++++++-- examples/bulk_transfer/README.md | 2 +- examples/bulk_transfer/pom.xml | 4 +- examples/enumerate/README.md | 2 +- examples/enumerate/pom.xml | 4 +- examples/enumerate_kotlin/README.md | 50 +++++++++++++++++++ examples/enumerate_kotlin/pom.xml | 37 +++++++++++--- examples/epaper_display/README.md | 4 +- examples/epaper_display/pom.xml | 4 +- examples/monitor/README.md | 2 +- examples/monitor/pom.xml | 4 +- examples/monitor_kotlin/README.md | 49 ++++++++++++++++++ examples/monitor_kotlin/pom.xml | 37 +++++++++++--- examples/stm_dfu/README.md | 2 +- examples/stm_dfu/pom.xml | 4 +- java-does-usb/pom.xml | 2 +- 17 files changed, 202 insertions(+), 36 deletions(-) create mode 100644 examples/enumerate_kotlin/README.md create mode 100644 examples/monitor_kotlin/README.md diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index 1c554aab..deef007d 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -47,13 +47,13 @@ jobs: run: ./mvnw $MAVEN_ARGS clean compile working-directory: ./examples/enumerate - name: Example "enumerate" (Kotlin) - run: ./mvnw $MAVEN_ARGS clean compile + run: ./mvnw $MAVEN_ARGS clean package working-directory: ./examples/enumerate_kotlin - name: Example "monitor" run: ./mvnw $MAVEN_ARGS clean compile working-directory: ./examples/monitor - name: Example "monitor" (Kotlin) - run: ./mvnw $MAVEN_ARGS clean compile + run: ./mvnw $MAVEN_ARGS clean package working-directory: ./examples/monitor_kotlin - name: Example "stm_dfu" run: ./mvnw $MAVEN_ARGS clean compile diff --git a/README.md b/README.md index 9d032457..7c9c48b5 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The library uses the [Foreign Function & Memory API](https://github.com/openjdk/ | Version | Main New Features | Compatibility | | - | - | - | -| 0.7.x | Prerelease: New setter/getter names for improved Kotlin support; Kotlin examples | JDK 21 | +| 0.7.x | New setter/getter names for improved Kotlin support; Kotlin examples | JDK 21 | | 0.6.x | Support for JDK 21; better handling of composite devices on Windows | JDK 21 | | 0.5.x | Support for JDK 20; high-throuput I/O streams | JDK 20 | | 0.4.x | Early release | JDK 19 | @@ -48,14 +48,14 @@ If you are using Maven, add the below dependency to your pom.xml: net.codecrete.usb java-does-usb - 0.6.1 + 0.7.0 ``` If you are using Gradle, add the below dependency to your build.gradle file: ```groovy -compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '0.6.1' +compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '0.7.0' ``` ```java @@ -134,9 +134,26 @@ The library has not been tested on Windows for ARM64. It might or might not work ### Troubleshooting -- The error `java.lang.ClassFormatError: Illegal field name "" in class net/codecrete/usb/windows/WindowsUsbDeviceRegistry` is caused by a bug in JDK 21, which has been fixed in the mean-time. Please upgrade to the latest release of JDK 21. +#### `ClassFormatError` (all platforms) -- The error `Cannot open library: CoreFoundation.framework/CoreFoundation` is caused by an unfortunate build of the OpenJDK by Homebrew. Please use any other JDK edition instead, e.g. Zulu (`brew install zulu` or directly from https://www.azul.com/downloads/#zulu), Temurin (`brew install temurin` or from https://adoptium.net/en-GB/temurin/releases/), or download the official OpenJDK directly from https://openjdk.org/projects/jdk/21/. And don't forget to uninstall the Homebrew build (`brew uninstall openjdk`). +The error `java.lang.ClassFormatError: Illegal field name "" in class net/codecrete/usb/windows/WindowsUsbDeviceRegistry` is caused by a bug in JDK 21, which has been fixed in the mean-time. Please upgrade to the latest release of JDK 21 (at least 21.0.1). + + +#### `Cannot open library` (macOS only) + +The error `Cannot open library: CoreFoundation.framework/CoreFoundation` is caused by an unfortunate build of the OpenJDK by Homebrew. Please use any other JDK edition instead, e.g. Zulu (`brew install zulu` or directly from https://www.azul.com/downloads/#zulu), Temurin (`brew install temurin` or from https://adoptium.net/en-GB/temurin/releases/), or download the official OpenJDK directly from https://openjdk.org/projects/jdk/21/. + +It will usually not be possible to uninstall the problematic build (`brew uninstall openjdk`) as it is a dependency of other brew packages. So to run an application, set `JAVA_HOME`: + +```shell +export JAVA_HOME=/Users/me/Documents/zulu21.30.15-ca-jdk21.0.1-macosx_aarch64 +``` + +If the JDK was "installed" as opposed to downloaded, the path for `JAVA_HOME` will likely be listed by: + +```sheel +/usr/libexec/java_home -V +``` ### 32-bit versions diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index 13d6e6e6..372082ec 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] --------------< net.codecrete.usb.examples:bulk-transfer >-------------- -[INFO] Building bulk-transfer 0.6.1 +[INFO] Building bulk-transfer 0.7.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ bulk-transfer --- diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index 8e34bba4..cfe4587b 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples bulk-transfer - 0.6.1 + 0.7.0 bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.7.0-SNAPSHOT + 0.7.0
diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index 1881b25f..5721c61d 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] ----------------< net.codecrete.usb.examples:enumerate >---------------- -[INFO] Building enumerate 0.6.1 +[INFO] Building enumerate 0.7.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ enumerate --- diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index 7e3b68e5..43e7b059 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples enumerate - 0.6.1 + 0.7.0 enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.7.0-SNAPSHOT + 0.7.0 org.tinylog diff --git a/examples/enumerate_kotlin/README.md b/examples/enumerate_kotlin/README.md new file mode 100644 index 00000000..94a74c46 --- /dev/null +++ b/examples/enumerate_kotlin/README.md @@ -0,0 +1,50 @@ +# USB Device Enumeration (Kotlin) + +This sample enumerates the connected USB devices and provides information about the interfaces and endpoints. + +## Prerequisites + +- Java 21 +- Apache Maven +- 64-bit operating system (Windows, macOS, Linux) + +## How to run + +### Install Java 21 + +Check that *Java 21* is installed: + +```shell +$ java -version +``` + +If not, download and install it, e.g. from [Azul](https://www.azul.com/downloads/?package=jdk). + +### Install Maven + +Check that *Maven* is installed: + +```shell +$ mvn -version +``` + +If it is not present, install it, typically using package manager like *Homebrew* on macOS, *Chocolately* on Windows and *apt* on Linux. + +### Build a self-contained jar file + +```shell +$ cd JavaDoesUSB/examples/enumerate_kotlin +$ mvn clean package +``` + +### Run the jar + +```shell +$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/enumerate-0.7.0-jar-with-dependencies.jar +Device: + VID: 0xcafe + PID: 0xceaf + Manufacturer: JavaDoesUSB + Product name: Loopback +... +``` diff --git a/examples/enumerate_kotlin/pom.xml b/examples/enumerate_kotlin/pom.xml index 5110c7df..a304b393 100644 --- a/examples/enumerate_kotlin/pom.xml +++ b/examples/enumerate_kotlin/pom.xml @@ -3,17 +3,18 @@ 4.0.0 net.codecrete.usb.examples - kotlin - 0.6.1-SNAPSHOT + enumerate + 0.7.0 jar - kotlin - https://github.com/manuelbl/JavaDoesUSB/examples/kotlin + enumerate + https://github.com/manuelbl/JavaDoesUSB/examples/enumerate_kotlin - 1.9.10 + 1.9.22 true UTF-8 + net.codecrete.usb.examples.EnumerateKt @@ -27,6 +28,30 @@ ${kotlin.version} true
+ + org.apache.maven.plugins + maven-assembly-plugin + 3.6.0 + + + make-assembly + package + + single + + + + + ${main.class} + + + + jar-with-dependencies + + + + +
@@ -39,7 +64,7 @@ net.codecrete.usb java-does-usb - 0.7.0-SNAPSHOT + 0.7.0 org.tinylog diff --git a/examples/epaper_display/README.md b/examples/epaper_display/README.md index 3853b118..954070f9 100644 --- a/examples/epaper_display/README.md +++ b/examples/epaper_display/README.md @@ -45,7 +45,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -------------< net.codecrete.usb.examples:epaper-display >-------------- -[INFO] Building epaper-display 0.6.1 +[INFO] Building epaper-display 0.7.0 [INFO] from pom.xml [INFO] --------------------------------[ jar ]--------------------------------- [INFO] @@ -81,6 +81,6 @@ $ sudo -i Password: $ cd /Users/me/Documents/JavaDoesUSB/examples/epaper_display $ export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-20.jdk/Contents/Home -$ $JAVA_HOME/bin/java --enable-preview --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/0.6.1/java-does-usb-0.6.1.jar net.codecrete.usb.examples.EPaperDisplay +$ $JAVA_HOME/bin/java --enable-preview --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/0.7.0/java-does-usb-0.7.0.jar net.codecrete.usb.examples.EPaperDisplay Display size: 1200 x 825 ``` diff --git a/examples/epaper_display/pom.xml b/examples/epaper_display/pom.xml index 9ea7e0e2..73293f75 100644 --- a/examples/epaper_display/pom.xml +++ b/examples/epaper_display/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples epaper-display - 0.6.1 + 0.7.0 epaper-display https://github.com/manuelbl/JavaDoesUSB/examples/epaper_display @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.7.0-SNAPSHOT + 0.7.0 diff --git a/examples/monitor/README.md b/examples/monitor/README.md index c1789a99..1fbcff58 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -----------------< net.codecrete.usb.examples:monitor >----------------- -[INFO] Building monitor 0.6.1 +[INFO] Building monitor 0.7.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ monitor --- diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index 4d2ae39e..8ce44839 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples monitor - 0.6.1 + 0.7.0 monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.7.0-SNAPSHOT + 0.7.0 org.tinylog diff --git a/examples/monitor_kotlin/README.md b/examples/monitor_kotlin/README.md new file mode 100644 index 00000000..c3c28c31 --- /dev/null +++ b/examples/monitor_kotlin/README.md @@ -0,0 +1,49 @@ +# USB Device Monitoring (Kotlin) + +This sample enumerates the connected USB devices and provides information about the interfaces and endpoints. + +## Prerequisites + +- Java 21 +- Apache Maven +- 64-bit operating system (Windows, macOS, Linux) + +## How to run + +### Install Java 21 + +Check that *Java 21* is installed: + +```shell +$ java -version +``` + +If not, download and install it, e.g. from [Azul](https://www.azul.com/downloads/?package=jdk). + +### Install Maven + +Check that *Maven* is installed: + +```shell +$ mvn -version +``` + +If it is not present, install it, typically using package manager like *Homebrew* on macOS, *Chocolately* on Windows and *apt* on Linux. + +### Build a self-contained jar file + +```shell +$ cd JavaDoesUSB/examples/monitor_kotlin +$ mvn clean package +``` + +### Run the jar + +```shell +$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/monitor-0.7.0-jar-with-dependencies.jar +WARNING: "public static final void net.codecrete.usb.examples.MonitorKt.main()" chosen over "public static void net.codecrete.usb.examples.MonitorKt.main(java.lang.String[])" +Present: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 35A737883336, ID: 4295265643 +Present: VID: 0x1a40, PID: 0x0801, manufacturer: null, product: USB 2.0 Hub, serial: null, ID: 4295259660 +Monitoring... Press ENTER to quit. +... +``` diff --git a/examples/monitor_kotlin/pom.xml b/examples/monitor_kotlin/pom.xml index 78451d28..9a0094b2 100644 --- a/examples/monitor_kotlin/pom.xml +++ b/examples/monitor_kotlin/pom.xml @@ -3,17 +3,18 @@ 4.0.0 net.codecrete.usb.examples - monitor_kotlin - 0.7.0-SNAPSHOT + monitor + 0.7.0 jar - monitor_kotlin - https://github.com/manuelbl/JavaDoesUSB/examples/kotlin + monitor + https://github.com/manuelbl/JavaDoesUSB/examples/monitor_kotlin - 1.9.10 + 1.9.22 true UTF-8 + net.codecrete.usb.examples.MonitorKt @@ -27,6 +28,30 @@ ${kotlin.version} true
+ + org.apache.maven.plugins + maven-assembly-plugin + 3.6.0 + + + make-assembly + package + + single + + + + + ${main.class} + + + + jar-with-dependencies + + + + + @@ -39,7 +64,7 @@ net.codecrete.usb java-does-usb - 0.7.0-SNAPSHOT + 0.7.0 org.tinylog diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index b97cd35b..f8d34ef6 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -58,7 +58,7 @@ Run the command below (adapting the file path depending on your specific board): ```shell $ mvn package -$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.6.1.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin +$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.7.0.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin DFU device found with serial 35A737883336. Target memory segment: Internal Flash Erasing page at 0x8000000 (size 0x4000) diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index 13ee51fe..91610544 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples stm_dfu - 0.6.1 + 0.7.0 stm_dfu https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu @@ -19,7 +19,7 @@ net.codecrete.usb java-does-usb - 0.7.0-SNAPSHOT + 0.7.0 diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 99f2dea3..3a543c07 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 0.7.0-SNAPSHOT + 0.7.0 21 From d7b1da8cd9605766bf263674f88c3123b5b7ba3c Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 3 Jan 2024 15:54:47 +0100 Subject: [PATCH 314/433] Link to Kotlin examples --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7c9c48b5..9c2ece68 100644 --- a/README.md +++ b/README.md @@ -82,8 +82,8 @@ public class EnumerateDevices { ## Examples - [Bulk Transfer](examples/bulk_transfer/) demonstrates how to find a USB device, open it and communicate using bulk transfer. -- [Enumeration](examples/enumerate/) lists all connected USB devices and displays information about interfaces and endpoints. -- [Monitor](examples/monitor/) lists the connected USB devices and then monitors for USB devices being connected and disconnnected. +- Enumeration ([Java](examples/enumerate/) / [Kotlin](examples/enumerate_kotlin/)) lists all connected USB devices and displays information about interfaces and endpoints. +- Monitor ([Java](examples/monitor/) / [Kotlin](examples/monitor_kotlin/)) lists the connected USB devices and then monitors for devices being connected and disconnnected. - [Device Firmware Upload (DFU) for STM32](examples/stm_dfu) uploads firmware to STM32 microcontrollers supporting the built-in DFU mode. - [ePaper Display](examples/epaper_display) communicates with an IT8951 controller for e-Paper displays and shows an image on the display. From 149c69da37157f04420c3690e61578561830962b Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 3 Jan 2024 23:06:50 +0100 Subject: [PATCH 315/433] macOS: Improve compatibility with JDK builds --- README.md | 4 ++-- examples/bulk_transfer/README.md | 2 +- examples/bulk_transfer/pom.xml | 4 ++-- examples/enumerate/README.md | 2 +- examples/enumerate/pom.xml | 4 ++-- examples/enumerate_kotlin/README.md | 2 +- examples/enumerate_kotlin/pom.xml | 4 ++-- examples/epaper_display/README.md | 4 ++-- examples/epaper_display/pom.xml | 4 ++-- examples/monitor/README.md | 2 +- examples/monitor/pom.xml | 4 ++-- examples/monitor_kotlin/README.md | 2 +- examples/monitor_kotlin/pom.xml | 4 ++-- examples/stm_dfu/README.md | 2 +- examples/stm_dfu/pom.xml | 4 ++-- java-does-usb/jextract/README.md | 2 +- java-does-usb/pom.xml | 2 +- .../codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java | 2 +- .../java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java | 2 +- 19 files changed, 28 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 9c2ece68..edd2c5be 100644 --- a/README.md +++ b/README.md @@ -48,14 +48,14 @@ If you are using Maven, add the below dependency to your pom.xml: net.codecrete.usb java-does-usb - 0.7.0 + 0.7.1 ``` If you are using Gradle, add the below dependency to your build.gradle file: ```groovy -compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '0.7.0' +compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '0.7.1' ``` ```java diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index 372082ec..dd25eb8c 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] --------------< net.codecrete.usb.examples:bulk-transfer >-------------- -[INFO] Building bulk-transfer 0.7.0 +[INFO] Building bulk-transfer 0.7.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ bulk-transfer --- diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index cfe4587b..fbf1a3c8 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples bulk-transfer - 0.7.0 + 0.7.1 bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.7.0 + 0.7.1 diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index 5721c61d..992275e2 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] ----------------< net.codecrete.usb.examples:enumerate >---------------- -[INFO] Building enumerate 0.7.0 +[INFO] Building enumerate 0.7.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ enumerate --- diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index 43e7b059..00aa0f97 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples enumerate - 0.7.0 + 0.7.1 enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.7.0 + 0.7.1 org.tinylog diff --git a/examples/enumerate_kotlin/README.md b/examples/enumerate_kotlin/README.md index 94a74c46..6a5e14e2 100644 --- a/examples/enumerate_kotlin/README.md +++ b/examples/enumerate_kotlin/README.md @@ -40,7 +40,7 @@ $ mvn clean package ### Run the jar ```shell -$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/enumerate-0.7.0-jar-with-dependencies.jar +$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/enumerate-0.7.1-jar-with-dependencies.jar Device: VID: 0xcafe PID: 0xceaf diff --git a/examples/enumerate_kotlin/pom.xml b/examples/enumerate_kotlin/pom.xml index a304b393..91d8b9af 100644 --- a/examples/enumerate_kotlin/pom.xml +++ b/examples/enumerate_kotlin/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples enumerate - 0.7.0 + 0.7.1 jar enumerate @@ -64,7 +64,7 @@ net.codecrete.usb java-does-usb - 0.7.0 + 0.7.1 org.tinylog diff --git a/examples/epaper_display/README.md b/examples/epaper_display/README.md index 954070f9..684bd25f 100644 --- a/examples/epaper_display/README.md +++ b/examples/epaper_display/README.md @@ -45,7 +45,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -------------< net.codecrete.usb.examples:epaper-display >-------------- -[INFO] Building epaper-display 0.7.0 +[INFO] Building epaper-display 0.7.1 [INFO] from pom.xml [INFO] --------------------------------[ jar ]--------------------------------- [INFO] @@ -81,6 +81,6 @@ $ sudo -i Password: $ cd /Users/me/Documents/JavaDoesUSB/examples/epaper_display $ export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-20.jdk/Contents/Home -$ $JAVA_HOME/bin/java --enable-preview --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/0.7.0/java-does-usb-0.7.0.jar net.codecrete.usb.examples.EPaperDisplay +$ $JAVA_HOME/bin/java --enable-preview --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/0.7.1/java-does-usb-0.7.1.jar net.codecrete.usb.examples.EPaperDisplay Display size: 1200 x 825 ``` diff --git a/examples/epaper_display/pom.xml b/examples/epaper_display/pom.xml index 73293f75..6f5ef1ac 100644 --- a/examples/epaper_display/pom.xml +++ b/examples/epaper_display/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples epaper-display - 0.7.0 + 0.7.1 epaper-display https://github.com/manuelbl/JavaDoesUSB/examples/epaper_display @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.7.0 + 0.7.1 diff --git a/examples/monitor/README.md b/examples/monitor/README.md index 1fbcff58..e267ff1e 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -----------------< net.codecrete.usb.examples:monitor >----------------- -[INFO] Building monitor 0.7.0 +[INFO] Building monitor 0.7.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ monitor --- diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index 8ce44839..8b3d614d 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples monitor - 0.7.0 + 0.7.1 monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 0.7.0 + 0.7.1 org.tinylog diff --git a/examples/monitor_kotlin/README.md b/examples/monitor_kotlin/README.md index c3c28c31..ba40402a 100644 --- a/examples/monitor_kotlin/README.md +++ b/examples/monitor_kotlin/README.md @@ -40,7 +40,7 @@ $ mvn clean package ### Run the jar ```shell -$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/monitor-0.7.0-jar-with-dependencies.jar +$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/monitor-0.7.1-jar-with-dependencies.jar WARNING: "public static final void net.codecrete.usb.examples.MonitorKt.main()" chosen over "public static void net.codecrete.usb.examples.MonitorKt.main(java.lang.String[])" Present: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 35A737883336, ID: 4295265643 Present: VID: 0x1a40, PID: 0x0801, manufacturer: null, product: USB 2.0 Hub, serial: null, ID: 4295259660 diff --git a/examples/monitor_kotlin/pom.xml b/examples/monitor_kotlin/pom.xml index 9a0094b2..b3e91b5e 100644 --- a/examples/monitor_kotlin/pom.xml +++ b/examples/monitor_kotlin/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples monitor - 0.7.0 + 0.7.1 jar monitor @@ -64,7 +64,7 @@ net.codecrete.usb java-does-usb - 0.7.0 + 0.7.1 org.tinylog diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index f8d34ef6..acab0b6c 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -58,7 +58,7 @@ Run the command below (adapting the file path depending on your specific board): ```shell $ mvn package -$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.7.0.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin +$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.7.1.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin DFU device found with serial 35A737883336. Target memory segment: Internal Flash Erasing page at 0x8000000 (size 0x4000) diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index 91610544..4891d1ee 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples stm_dfu - 0.7.0 + 0.7.1 stm_dfu https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu @@ -19,7 +19,7 @@ net.codecrete.usb java-does-usb - 0.7.0 + 0.7.1 diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index 3204b7ee..2054483a 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -70,7 +70,7 @@ SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so", MemorySessi Most of the required native functions on macOS are part of a framework. Frameworks internally have a more complex file organization of header and binary files than appears from the outside. Thus, they require a special logic to locate framework header files. *clang* supports it with the `-F`. *jextract* allows to specify the options via `compiler_flags.txt` file. Since the file must be in the local directory and since it does not apply to Linux and Windows, separate directories must be used for the operating systems. -The generated code has the same problem as the Linux code for *udev*. It must be manually changed to use `SymbolLookup.libraryLookup()` for the libraries `CoreFoundation.framework/CoreFoundation` and `IOKit.framework/IOKit` respectively. +The generated code has the same problem as the Linux code for *udev*. It must be manually changed to use `SymbolLookup.libraryLookup()` for the frameworks `CoreFoundation` and `IOKit` respectively, and use an absolute path starting with `/System/Library/Frameworks/`. ## Windows diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 3a543c07..5924998a 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 0.7.0 + 0.7.1 21 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java index 9fb56e43..69967de1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java @@ -23,7 +23,7 @@ final class RuntimeHelper { static { // System.loadLibrary("CoreFoundation.framework"); // SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SymbolLookup loaderLookup = SymbolLookup.libraryLookup("CoreFoundation.framework/CoreFoundation", Arena.global()); + SymbolLookup loaderLookup = SymbolLookup.libraryLookup("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", Arena.global()); SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java index 6b52deb2..02d78401 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java @@ -23,7 +23,7 @@ final class RuntimeHelper { static { // System.loadLibrary("IOKit.framework"); // SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SymbolLookup loaderLookup = SymbolLookup.libraryLookup("IOKit.framework/IOKit", Arena.global()); + SymbolLookup loaderLookup = SymbolLookup.libraryLookup("/System/Library/Frameworks/IOKit.framework/IOKit", Arena.global()); SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } From 92bc7c3c4d67a5fdd5803ce96d46e5bf527ae0bd Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 4 Jan 2024 09:38:31 +0100 Subject: [PATCH 316/433] Remove fixed issue from troubleshooting --- README.md | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/README.md b/README.md index edd2c5be..8a7e0b9c 100644 --- a/README.md +++ b/README.md @@ -139,22 +139,6 @@ The library has not been tested on Windows for ARM64. It might or might not work The error `java.lang.ClassFormatError: Illegal field name "" in class net/codecrete/usb/windows/WindowsUsbDeviceRegistry` is caused by a bug in JDK 21, which has been fixed in the mean-time. Please upgrade to the latest release of JDK 21 (at least 21.0.1). -#### `Cannot open library` (macOS only) - -The error `Cannot open library: CoreFoundation.framework/CoreFoundation` is caused by an unfortunate build of the OpenJDK by Homebrew. Please use any other JDK edition instead, e.g. Zulu (`brew install zulu` or directly from https://www.azul.com/downloads/#zulu), Temurin (`brew install temurin` or from https://adoptium.net/en-GB/temurin/releases/), or download the official OpenJDK directly from https://openjdk.org/projects/jdk/21/. - -It will usually not be possible to uninstall the problematic build (`brew uninstall openjdk`) as it is a dependency of other brew packages. So to run an application, set `JAVA_HOME`: - -```shell -export JAVA_HOME=/Users/me/Documents/zulu21.30.15-ca-jdk21.0.1-macosx_aarch64 -``` - -If the JDK was "installed" as opposed to downloaded, the path for `JAVA_HOME` will likely be listed by: - -```sheel -/usr/libexec/java_home -V -``` - ### 32-bit versions From 6ecf2bde21678362ffc7f559d8310c049a0cabbf Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 6 Jan 2024 12:08:49 +0100 Subject: [PATCH 317/433] macOS: remove event source on close --- .../src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java index 512238c3..ae672a6c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java @@ -135,6 +135,9 @@ public synchronized void close() { return; for (var interfaceInfo : claimedInterfaces) { + var source = IoKitUsb.GetInterfaceAsyncEventSource(interfaceInfo.iokitInterface()); + if (source.address() != 0) + asyncTask.removeEventSource(source); IoKitUsb.USBInterfaceClose(interfaceInfo.iokitInterface); IoKitUsb.Release(interfaceInfo.iokitInterface); setClaimed(interfaceInfo.interfaceNumber, false); From 3c5836340f7f1923da77f724ee34ce5724396d7d Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 18 Feb 2024 10:33:31 +0100 Subject: [PATCH 318/433] Linux: Upgrade to JDK 22 --- java-does-usb/jextract/linux/gen_linux.sh | 18 +- java-does-usb/pom.xml | 34 +- .../java/net/codecrete/usb/UsbException.java | 2 +- .../usb/common/ConfigurationParser.java | 5 +- .../codecrete/usb/common/UsbDeviceImpl.java | 16 +- .../java/net/codecrete/usb/linux/EPoll.java | 32 +- .../main/java/net/codecrete/usb/linux/IO.java | 4 +- .../java/net/codecrete/usb/linux/Linux.java | 7 +- .../codecrete/usb/linux/LinuxAsyncTask.java | 46 +- .../codecrete/usb/linux/LinuxUsbDevice.java | 30 +- .../usb/linux/LinuxUsbDeviceRegistry.java | 27 +- .../usb/linux/gen/epoll/RuntimeHelper.java | 227 ----- .../usb/linux/gen/epoll/constants$0.java | 27 - .../codecrete/usb/linux/gen/epoll/epoll.java | 98 +- .../usb/linux/gen/epoll/epoll_data.java | 267 +++++ .../usb/linux/gen/epoll/epoll_event.java | 166 +++- .../usb/linux/gen/errno/RuntimeHelper.java | 227 ----- .../usb/linux/gen/errno/constants$0.java | 11 - .../codecrete/usb/linux/gen/errno/errno.java | 95 +- .../usb/linux/gen/fcntl/RuntimeHelper.java | 227 ----- .../usb/linux/gen/fcntl/constants$0.java | 11 - .../codecrete/usb/linux/gen/fcntl/fcntl.java | 82 +- .../usb/linux/gen/string/RuntimeHelper.java | 227 ----- .../usb/linux/gen/string/constants$0.java | 22 - .../usb/linux/gen/string/string.java | 108 ++- .../usb/linux/gen/udev/RuntimeHelper.java | 228 ----- .../usb/linux/gen/udev/constants$0.java | 33 - .../usb/linux/gen/udev/constants$1.java | 37 - .../usb/linux/gen/udev/constants$2.java | 43 - .../usb/linux/gen/udev/constants$3.java | 39 - .../codecrete/usb/linux/gen/udev/udev.java | 915 +++++++++++++++--- .../usb/linux/gen/unistd/RuntimeHelper.java | 227 ----- .../usb/linux/gen/unistd/constants$0.java | 22 - .../usb/linux/gen/unistd/unistd.java | 107 +- .../linux/gen/usbdevice_fs/RuntimeHelper.java | 227 ----- .../linux/gen/usbdevice_fs/constants$0.java | 31 - .../linux/gen/usbdevice_fs/constants$1.java | 28 - .../linux/gen/usbdevice_fs/constants$2.java | 49 - .../linux/gen/usbdevice_fs/constants$3.java | 19 - .../linux/gen/usbdevice_fs/constants$4.java | 19 - .../linux/gen/usbdevice_fs/constants$5.java | 31 - .../linux/gen/usbdevice_fs/constants$6.java | 14 - .../usbdevice_fs/usbdevfs_bulktransfer.java | 268 +++-- .../usbdevice_fs/usbdevfs_ctrltransfer.java | 414 +++++--- .../usbdevfs_disconnect_claim.java | 246 ++++- .../gen/usbdevice_fs/usbdevfs_ioctl.java | 219 +++-- .../usbdevfs_iso_packet_desc.java | 219 +++++ .../usbdevice_fs/usbdevfs_setinterface.java | 168 +++- .../linux/gen/usbdevice_fs/usbdevfs_urb.java | 789 +++++++++++---- .../linux/gen/usbdevice_fs/usbdevice_fs.java | 92 +- .../usb/macos/CoreFoundationHelper.java | 4 +- .../net/codecrete/usb/macos/IoKitHelper.java | 8 +- .../codecrete/usb/macos/MacosUsbDevice.java | 16 +- .../usb/macos/MacosUsbDeviceRegistry.java | 10 +- .../usb/macos/MacosUsbException.java | 2 +- .../gen/corefoundation/CoreFoundation.java | 13 +- .../gen/corefoundation/RuntimeHelper.java | 18 +- .../codecrete/usb/macos/gen/iokit/IOKit.java | 13 +- .../usb/macos/gen/iokit/RuntimeHelper.java | 18 +- .../usb/macos/gen/iokit/constants$0.java | 4 +- .../usb/macos/gen/iokit/constants$33.java | 4 +- .../usb/macos/gen/iokit/constants$38.java | 4 +- .../usb/macos/gen/iokit/constants$44.java | 6 +- .../usb/macos/gen/mach/RuntimeHelper.java | 18 +- .../codecrete/usb/macos/gen/mach/mach.java | 13 +- .../usbstandard/ConfigurationDescriptor.java | 32 +- .../usb/usbstandard/DeviceDescriptor.java | 44 +- .../usb/usbstandard/EndpointDescriptor.java | 20 +- .../InterfaceAssociationDescriptor.java | 28 +- .../usb/usbstandard/InterfaceDescriptor.java | 32 +- .../usb/usbstandard/SetupPacket.java | 34 +- .../usb/usbstandard/StringDescriptor.java | 16 +- .../codecrete/usb/windows/DeviceInfoSet.java | 2 +- .../java/net/codecrete/usb/windows/Win.java | 9 +- .../usb/windows/WindowsAsyncTask.java | 10 +- .../usb/windows/WindowsUsbDevice.java | 15 +- .../usb/windows/WindowsUsbDeviceRegistry.java | 24 +- .../usb/windows/gen/advapi32/Advapi32.java | 13 +- .../windows/gen/advapi32/RuntimeHelper.java | 18 +- .../usb/windows/gen/kernel32/Kernel32.java | 13 +- .../windows/gen/kernel32/RuntimeHelper.java | 18 +- .../usb/windows/gen/kernel32/constants$0.java | 5 +- .../usb/windows/gen/ntdll/NtDll.java | 13 +- .../usb/windows/gen/ntdll/RuntimeHelper.java | 18 +- .../usb/windows/gen/ole32/Ole32.java | 13 +- .../usb/windows/gen/ole32/RuntimeHelper.java | 18 +- .../windows/gen/setupapi/RuntimeHelper.java | 18 +- .../usb/windows/gen/setupapi/SetupAPI.java | 13 +- .../usb/windows/gen/setupapi/constants$0.java | 5 +- .../usb/windows/gen/setupapi/constants$1.java | 5 +- .../windows/gen/usbioctl/RuntimeHelper.java | 18 +- .../usb/windows/gen/usbioctl/USBIoctl.java | 13 +- .../usb/windows/gen/usbioctl/constants$0.java | 4 +- .../usb/windows/gen/usbioctl/constants$1.java | 4 +- .../usb/windows/gen/user32/RuntimeHelper.java | 18 +- .../usb/windows/gen/user32/User32.java | 13 +- .../usb/windows/gen/user32/constants$4.java | 4 +- .../usb/windows/gen/winusb/RuntimeHelper.java | 18 +- .../usb/windows/gen/winusb/WinUSB.java | 13 +- .../usb/windows/winsdk/Kernel32B.java | 4 +- .../codecrete/usb/windows/winsdk/User32B.java | 4 +- .../codecrete/usb/windows/winsdk/WinUSB2.java | 4 +- .../codecrete/usb/AlternateInterfaceTest.java | 5 +- .../net/codecrete/usb/BulkTransferTest.java | 4 +- .../usb/ConfigurationParserTest.java | 4 +- .../codecrete/usb/ControlTransferTest.java | 4 +- .../net/codecrete/usb/DescriptionTest.java | 6 +- .../codecrete/usb/DeviceLifecycleTest.java | 5 +- .../java/net/codecrete/usb/SpeedTest.java | 3 +- .../codecrete/usb/special/LogicAnalyzer.java | 8 +- .../codecrete/usb/special/MonitorDevices.java | 12 +- .../{USBSerialTest.java => USBSerial.java} | 9 +- .../net/codecrete/usb/special/Unplug.java | 2 +- 113 files changed, 4118 insertions(+), 3148 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/constants$0.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_data.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$2.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$3.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$1.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$2.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$3.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$4.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$5.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$6.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java rename java-does-usb/src/test/java/net/codecrete/usb/special/{USBSerialTest.java => USBSerial.java} (92%) diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index 3b41d80a..b1eba46a 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -1,9 +1,9 @@ #!/bin/sh -JEXTRACT=../../../../jextract/build/jextract/bin/jextract +JEXTRACT=../../../../jextract-22/bin/jextract # errno.h -$JEXTRACT --source --output ../../src/main/java \ +$JEXTRACT --output ../../src/main/java \ --header-class-name errno \ --target-package net.codecrete.usb.linux.gen.errno \ --include-constant EPIPE \ @@ -15,14 +15,14 @@ $JEXTRACT --source --output ../../src/main/java \ /usr/include/errno.h # string.h -$JEXTRACT --source --output ../../src/main/java \ +$JEXTRACT --output ../../src/main/java \ --header-class-name string \ --target-package net.codecrete.usb.linux.gen.string \ --include-function strerror \ /usr/include/string.h # fcntl.h -$JEXTRACT --source --output ../../src/main/java \ +$JEXTRACT --output ../../src/main/java \ --header-class-name fcntl \ --target-package net.codecrete.usb.linux.gen.fcntl \ --include-constant O_CLOEXEC \ @@ -31,7 +31,7 @@ $JEXTRACT --source --output ../../src/main/java \ /usr/include/fcntl.h # unistd.h -$JEXTRACT --source --output ../../src/main/java \ +$JEXTRACT --output ../../src/main/java \ --header-class-name unistd \ --target-package net.codecrete.usb.linux.gen.unistd \ --include-function close \ @@ -39,7 +39,7 @@ $JEXTRACT --source --output ../../src/main/java \ # usbdevice_fs.h # Missing constants like USBDEVFS_CLAIMINTERFACE -$JEXTRACT --source --output ../../src/main/java \ +$JEXTRACT --output ../../src/main/java \ --header-class-name usbdevice_fs \ --target-package net.codecrete.usb.linux.gen.usbdevice_fs \ --include-struct usbdevfs_bulktransfer \ @@ -48,6 +48,7 @@ $JEXTRACT --source --output ../../src/main/java \ --include-struct usbdevfs_urb \ --include-struct usbdevfs_disconnect_claim \ --include-struct usbdevfs_ioctl \ + --include-struct usbdevfs_iso_packet_desc \ --include-constant USBDEVFS_URB_TYPE_INTERRUPT \ --include-constant USBDEVFS_URB_TYPE_CONTROL \ --include-constant USBDEVFS_URB_TYPE_BULK \ @@ -57,7 +58,7 @@ $JEXTRACT --source --output ../../src/main/java \ # libudev.h # (install libudev-dev if file is missing) -$JEXTRACT --source --output ../../src/main/java \ +$JEXTRACT --output ../../src/main/java \ --header-class-name udev \ --target-package net.codecrete.usb.linux.gen.udev \ -l udev \ @@ -83,10 +84,11 @@ $JEXTRACT --source --output ../../src/main/java \ /usr/include/libudev.h # epoll.h -$JEXTRACT --source --output ../../src/main/java \ +$JEXTRACT --output ../../src/main/java \ --header-class-name epoll \ --target-package net.codecrete.usb.linux.gen.epoll \ --include-struct epoll_event \ + --include-union epoll_data \ --include-constant EPOLL_CTL_ADD \ --include-constant EPOLL_CTL_DEL \ --include-constant EPOLLIN \ diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 5924998a..3b11a88d 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -9,8 +9,8 @@ 0.7.1 - 21 - 21 + 22 + 22 UTF-8 @@ -54,28 +54,25 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.1 - 21 - - --enable-preview - - 21 - 21 + 22 + 22 + 22 org.apache.maven.plugins maven-surefire-plugin - 3.1.2 + 3.2.5 - --enable-preview --enable-native-access=ALL-UNNAMED + --enable-native-access=ALL-UNNAMED org.apache.maven.plugins maven-javadoc-plugin - 3.6.0 + 3.6.3 attach-javadocs @@ -85,8 +82,7 @@ - 21 - --enable-preview + 22 ${java.home}/bin/javadoc @@ -140,31 +136,31 @@ org.jetbrains annotations - 24.0.1 + 24.1.0 compile org.junit.jupiter junit-jupiter - 5.10.0 + 5.10.2 test org.assertj assertj-core - 3.24.2 + 3.25.3 test org.tinylog tinylog-impl - 2.6.2 + 2.7.0 test org.tinylog jsl-tinylog - 2.6.2 + 2.7.0 test diff --git a/java-does-usb/src/main/java/net/codecrete/usb/UsbException.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbException.java index 71a41140..d5e07fa3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/UsbException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbException.java @@ -37,7 +37,7 @@ public UsbException(@NotNull String message) { * @param errorCode the error code */ public UsbException(@NotNull String message, int errorCode) { - super(STR."\{message} (error code: \{errorCode})"); + super(message + " (error code:" + errorCode + ")"); code = errorCode; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java index 31b8298e..f8023292 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ConfigurationParser.java @@ -20,7 +20,10 @@ import java.lang.foreign.ValueLayout; import java.util.ArrayList; -import static net.codecrete.usb.usbstandard.Constants.*; +import static net.codecrete.usb.usbstandard.Constants.CONFIGURATION_DESCRIPTOR_TYPE; +import static net.codecrete.usb.usbstandard.Constants.ENDPOINT_DESCRIPTOR_TYPE; +import static net.codecrete.usb.usbstandard.Constants.INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE; +import static net.codecrete.usb.usbstandard.Constants.INTERFACE_DESCRIPTOR_TYPE; /** * Parser for USB configuration descriptors. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java index 184ccb44..2d6a0c63 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java @@ -7,7 +7,14 @@ package net.codecrete.usb.common; -import net.codecrete.usb.*; +import net.codecrete.usb.UsbDevice; +import net.codecrete.usb.UsbDirection; +import net.codecrete.usb.UsbEndpoint; +import net.codecrete.usb.UsbException; +import net.codecrete.usb.UsbInterface; +import net.codecrete.usb.UsbTimeoutException; +import net.codecrete.usb.UsbTransferType; +import net.codecrete.usb.Version; import net.codecrete.usb.usbstandard.DeviceDescriptor; import org.jetbrains.annotations.NotNull; @@ -350,14 +357,14 @@ protected void waitForTransfer(Transfer transfer, int timeout, UsbDirection dire if (hasTimedOut && transfer.resultCode() == 0) { abortTransfers(direction, endpointNumber); waitNoTimeout(transfer); - throw new UsbTimeoutException(STR."\{getOperationDescription(direction, endpointNumber)}aborted due to timeout"); + throw new UsbTimeoutException(getOperationDescription(direction, endpointNumber) + " aborted due to timeout"); } } // test for error if (transfer.resultCode() != 0) { var operation = getOperationDescription(direction, endpointNumber); - throwOSException(transfer.resultCode(), STR."\{operation} failed"); + throwOSException(transfer.resultCode(), operation + " failed"); } } @@ -449,7 +456,8 @@ public int hashCode() { @Override public String toString() { - return STR."VID: 0x\{String.format("%04x", vid)}, PID: 0x\{String.format("%04x", pid)}, manufacturer: \{manufacturerString}, product: \{productString}, serial: \{serialString}, ID: \{uniqueDeviceId}"; + return String.format("VID: 0x%04x, PID: 0x%04x, manufacturer: %s, product: %s, serial: %s, ID: %s", + vid, pid, manufacturerString, productString, serialString, uniqueDeviceId); } public record EndpointInfo(int interfaceNumber, int endpointNumber, byte endpointAddress, int packetSize, diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java index e9f8fb3e..e8d0e051 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java @@ -7,10 +7,16 @@ package net.codecrete.usb.linux; +import net.codecrete.usb.linux.gen.epoll.epoll_data; import net.codecrete.usb.linux.gen.epoll.epoll_event; import net.codecrete.usb.linux.gen.errno.errno; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SequenceLayout; import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; @@ -18,12 +24,13 @@ import static java.lang.foreign.ValueLayout.JAVA_INT; import static net.codecrete.usb.linux.Linux.allocateErrorState; import static net.codecrete.usb.linux.LinuxUsbException.throwLastError; -import static net.codecrete.usb.linux.gen.epoll.epoll.*; +import static net.codecrete.usb.linux.gen.epoll.epoll.EPOLL_CTL_ADD; +import static net.codecrete.usb.linux.gen.epoll.epoll.EPOLL_CTL_DEL; @SuppressWarnings({"OptionalGetWithoutIsPresent", "SameParameterValue", "java:S100"}) public class EPoll { // Memory layout for an array of epoll_event structs - private static final SequenceLayout EVENT_ARRAY$LAYOUT = MemoryLayout.sequenceLayout(epoll_event.$LAYOUT()); + private static final SequenceLayout EVENT_ARRAY$LAYOUT = MemoryLayout.sequenceLayout(1, epoll_event.layout()); // varhandle to access the "fd" field in an array of epoll_event structs static final VarHandle EVENT_ARRAY_DATA_FD$VH = EVENT_ARRAY$LAYOUT.varHandle( @@ -33,7 +40,7 @@ public class EPoll { ); // varhandle to access the "fd" field in an epoll_event struct - static final VarHandle EVENT_DATA_FD$VH = epoll_event.$LAYOUT().varHandle( + static final VarHandle EVENT_DATA_FD$VH = epoll_event.layout().varHandle( MemoryLayout.PathElement.groupElement("data"), MemoryLayout.PathElement.groupElement("fd") ); @@ -83,9 +90,12 @@ static void addFileDescriptor(int epfd, int op, int fd) { try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); - var event = arena.allocate(epoll_event.$LAYOUT()); - epoll_event.events$set(event, op); - EVENT_DATA_FD$VH.set(event, fd); + var event = arena.allocate(epoll_event.layout()); + epoll_event.events(event, op); + // TODO: revert to varhandle + //EVENT_DATA_FD$VH.set(event, fd); + var data = epoll_event.data(event); + epoll_data.fd(data, fd); var ret = epoll_ctl(epfd, EPOLL_CTL_ADD(), fd, event, errorState); if (ret < 0) throwLastError(errorState, "internal error (epoll_ctl_add)"); @@ -96,9 +106,11 @@ static void removeFileDescriptor(int epfd, int fd) { try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); - var event = arena.allocate(epoll_event.$LAYOUT()); - epoll_event.events$set(event, 0); - EVENT_DATA_FD$VH.set(event, fd); + var event = arena.allocate(epoll_event.layout()); + epoll_event.events(event, 0); + // TODO: revert to varhandle + // EVENT_DATA_FD$VH.set(event, fd); + event.set(JAVA_INT, 0, fd); var ret = epoll_ctl(epfd, EPOLL_CTL_DEL(), fd, event, errorState); if (ret < 0) { var err = Linux.getErrno(errorState); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java index bfdc9380..367deb80 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java @@ -12,7 +12,9 @@ import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; @SuppressWarnings({"OptionalGetWithoutIsPresent", "SameParameterValue", "java:S100"}) class IO { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java index c8c7ac70..5046aec9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java @@ -14,6 +14,7 @@ import java.lang.foreign.MemoryLayout.PathElement; import java.lang.foreign.MemorySegment; import java.lang.foreign.StructLayout; +import java.lang.foreign.ValueLayout; import java.lang.invoke.VarHandle; /** @@ -43,7 +44,7 @@ static MemorySegment allocateErrorState(Arena arena) { * @return error message */ static String getErrorMessage(int err) { - return string.strerror(err).getUtf8String(0); + return string.strerror(err).getString(0); } /** @@ -56,6 +57,8 @@ static String getErrorMessage(int err) { * @return error code */ static int getErrno(MemorySegment errorState) { - return (int) callState_errno$VH.get(errorState); + return errorState.get(ValueLayout.JAVA_INT, 0); + // TODO: revert to varhandle + // return (int) callState_errno$VH.get(errorState); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index a01d6dc4..a58f0030 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -8,6 +8,7 @@ package net.codecrete.usb.linux; import net.codecrete.usb.UsbTransferType; +import net.codecrete.usb.linux.gen.epoll.epoll_data; import net.codecrete.usb.linux.gen.epoll.epoll_event; import net.codecrete.usb.linux.gen.errno.errno; import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_urb; @@ -19,18 +20,25 @@ import java.util.List; import java.util.Map; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; import static net.codecrete.usb.common.ForeignMemory.dereference; import static net.codecrete.usb.linux.EPoll.epoll_create1; import static net.codecrete.usb.linux.EPoll.epoll_wait; import static net.codecrete.usb.linux.Linux.allocateErrorState; import static net.codecrete.usb.linux.LinuxUsbException.throwException; import static net.codecrete.usb.linux.LinuxUsbException.throwLastError; -import static net.codecrete.usb.linux.UsbDevFS.*; -import static net.codecrete.usb.linux.gen.epoll.epoll.*; -import static net.codecrete.usb.linux.gen.errno.errno.*; +import static net.codecrete.usb.linux.UsbDevFS.DISCARDURB; +import static net.codecrete.usb.linux.UsbDevFS.REAPURBNDELAY; +import static net.codecrete.usb.linux.UsbDevFS.SUBMITURB; +import static net.codecrete.usb.linux.gen.epoll.epoll.EPOLLOUT; +import static net.codecrete.usb.linux.gen.epoll.epoll.EPOLLWAKEUP; +import static net.codecrete.usb.linux.gen.errno.errno.EINTR; +import static net.codecrete.usb.linux.gen.errno.errno.ENOENT; import static net.codecrete.usb.linux.gen.fcntl.fcntl.FD_CLOEXEC; -import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.*; +import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.USBDEVFS_URB_TYPE_BULK; +import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.USBDEVFS_URB_TYPE_CONTROL; +import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.USBDEVFS_URB_TYPE_INTERRUPT; +import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.USBDEVFS_URB_TYPE_ISO; /** * Background task for handling asynchronous transfers. @@ -77,7 +85,7 @@ private void asyncCompletionTask() { try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); var urbPointerHolder = arena.allocate(ADDRESS); - var events = arena.allocateArray(epoll_event.$LAYOUT(), NUM_EVENTS); + var events = arena.allocate(epoll_event.layout(), NUM_EVENTS); while (true) { @@ -92,7 +100,11 @@ private void asyncCompletionTask() { // for all ready file descriptors, reap URBs for (int i = 0; i < res; i++) { - var fd = (int) EPoll.EVENT_ARRAY_DATA_FD$VH.get(events, i); + var event = events.asSlice(i * epoll_event.layout().byteSize(), epoll_event.layout()); + var data = epoll_event.data(event); + var fd = epoll_data.fd(data); + // TODO: revert to varhandle + // var fd = (int) EPoll.EVENT_ARRAY_DATA_FD$VH.get(events, i); reapURBs(fd, urbPointerHolder, errorState); } } @@ -163,7 +175,7 @@ synchronized void removeFromAsyncIOCompletion(LinuxUsbDevice device) { // reclaim stale URBs transfersByURB.entrySet().removeIf(e -> { var urb = e.getKey(); - var isMatch = usbdevfs_urb.usercontext$get(urb).address() == fd; + var isMatch = usbdevfs_urb.usercontext(urb).address() == fd; if (isMatch) { var transfer = e.getValue(); transfer.urb = null; @@ -180,11 +192,11 @@ synchronized void submitTransfer(LinuxUsbDevice device, int endpointAddress, Usb linkToUrb(transfer); var urb = transfer.urb; - usbdevfs_urb.type$set(urb, (byte) urbTransferType(transferType)); - usbdevfs_urb.endpoint$set(urb, (byte) endpointAddress); - usbdevfs_urb.buffer$set(urb, transfer.data()); - usbdevfs_urb.buffer_length$set(urb, transfer.dataSize()); - usbdevfs_urb.usercontext$set(urb, MemorySegment.ofAddress(device.fileDescriptor())); + usbdevfs_urb.type(urb, (byte) urbTransferType(transferType)); + usbdevfs_urb.endpoint(urb, (byte) endpointAddress); + usbdevfs_urb.buffer(urb, transfer.data()); + usbdevfs_urb.buffer_length(urb, transfer.dataSize()); + usbdevfs_urb.usercontext(urb, MemorySegment.ofAddress(device.fileDescriptor())); try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); @@ -241,8 +253,8 @@ private synchronized LinuxTransfer getTransferWithResult(MemorySegment urb) { if (transfer == null) throwException("internal error (unknown URB)"); - transfer.setResultCode(-usbdevfs_urb.status$get(transfer.urb)); - transfer.setResultSize(usbdevfs_urb.actual_length$get(transfer.urb)); + transfer.setResultCode(-usbdevfs_urb.status(transfer.urb)); + transfer.setResultSize(usbdevfs_urb.actual_length(transfer.urb)); availableURBs.add(transfer.urb); transfer.urb = null; @@ -260,8 +272,8 @@ synchronized void abortTransfers(LinuxUsbDevice device, byte endpointAddress) { // iterate all URBs and discard the ones for the specified endpoint transfersByURB.keySet().stream() .filter(urb -> - usbdevfs_urb.usercontext$get(urb).address() == fd - && usbdevfs_urb.endpoint$get(urb) == endpointAddress) + usbdevfs_urb.usercontext(urb).address() == fd + && usbdevfs_urb.endpoint(urb) == endpointAddress) .forEach(urb -> { if (IO.ioctl(fd, DISCARDURB, urb, errorState) < 0) { // ignore EINVAL; it occurs if the URB has completed at the same time diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java index d82aed8e..b2fdf4d8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java @@ -41,8 +41,7 @@ @SuppressWarnings("java:S2160") public class LinuxUsbDevice extends UsbDeviceImpl { - @SuppressWarnings("resource") - private static final MemorySegment DRIVER_NAME_USBFS = Arena.global().allocateUtf8String("usbfs"); + private static final MemorySegment DRIVER_NAME_USBFS = Arena.global().allocateFrom("usbfs"); private int fd = -1; @@ -96,7 +95,7 @@ public synchronized void open() { throwException("device is already open"); try (var arena = Arena.ofConfined()) { - var pathUtf8 = arena.allocateUtf8String(uniqueDeviceId.toString()); + var pathUtf8 = arena.allocateFrom(uniqueDeviceId.toString()); var errorState = allocateErrorState(arena); fd = IO.open(pathUtf8, fcntl.O_RDWR() | fcntl.O_CLOEXEC(), errorState); if (fd == -1) @@ -135,14 +134,15 @@ public synchronized void claimInterface(int interfaceNumber) { if (detachDrivers) { // claim interface (detaching kernel driver) var disconnectClaim = usbdevfs_disconnect_claim.allocate(arena); - usbdevfs_disconnect_claim.interface_$set(disconnectClaim, interfaceNumber); - usbdevfs_disconnect_claim.flags$set(disconnectClaim, usbdevice_fs.USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER()); - usbdevfs_disconnect_claim.driver$slice(disconnectClaim).copyFrom(DRIVER_NAME_USBFS); + usbdevfs_disconnect_claim.interface_(disconnectClaim, interfaceNumber); + usbdevfs_disconnect_claim.flags(disconnectClaim, usbdevice_fs.USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER()); + usbdevfs_disconnect_claim.driver(disconnectClaim).copyFrom(DRIVER_NAME_USBFS); ret = IO.ioctl(fd, UsbDevFS.DISCONNECT_CLAIM, disconnectClaim, errorState); } else { // claim interface (without detaching kernel driver) - var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); + var intfNumSegment = arena.allocate(JAVA_INT); + intfNumSegment.setAtIndex(JAVA_INT, 0, interfaceNumber); ret = IO.ioctl(fd, UsbDevFS.CLAIMINTERFACE, intfNumSegment, errorState); } @@ -164,8 +164,8 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna try (var arena = Arena.ofConfined()) { var setIntfSegment = usbdevfs_setinterface.allocate(arena); - usbdevfs_setinterface.interface_$set(setIntfSegment, interfaceNumber); - usbdevfs_setinterface.altsetting$set(setIntfSegment, alternateNumber); + usbdevfs_setinterface.interface_(setIntfSegment, interfaceNumber); + usbdevfs_setinterface.altsetting(setIntfSegment, alternateNumber); var errorState = allocateErrorState(arena); var ret = IO.ioctl(fd, UsbDevFS.SETINTERFACE, setIntfSegment, errorState); if (ret != 0) @@ -181,7 +181,8 @@ public synchronized void releaseInterface(int interfaceNumber) { getInterfaceWithCheck(interfaceNumber, true); try (var arena = Arena.ofConfined()) { - var intfNumSegment = arena.allocate(JAVA_INT, interfaceNumber); + var intfNumSegment = arena.allocate(JAVA_INT); + intfNumSegment.setAtIndex(JAVA_INT, 0, interfaceNumber); var errorState = allocateErrorState(arena); var ret = IO.ioctl(fd, UsbDevFS.RELEASEINTERFACE, intfNumSegment, errorState); if (ret != 0) @@ -192,9 +193,9 @@ public synchronized void releaseInterface(int interfaceNumber) { if (detachDrivers) { // reattach kernel driver var request = usbdevfs_ioctl.allocate(arena); - usbdevfs_ioctl.ifno$set(request, interfaceNumber); - usbdevfs_ioctl.ioctl_code$set(request, UsbDevFS.CONNECT); - usbdevfs_ioctl.data$set(request, MemorySegment.NULL); + usbdevfs_ioctl.ifno(request, interfaceNumber); + usbdevfs_ioctl.ioctl_code(request, UsbDevFS.CONNECT); + usbdevfs_ioctl.data(request, MemorySegment.NULL); IO.ioctl(fd, UsbDevFS.IOCTL, request, errorState); } } @@ -323,7 +324,8 @@ public void clearHalt(UsbDirection direction, int endpointNumber) { var endpoint = getEndpoint(direction, endpointNumber, UsbTransferType.BULK, UsbTransferType.INTERRUPT); try (var arena = Arena.ofConfined()) { - var endpointAddrSegment = arena.allocate(JAVA_INT, endpoint.endpointAddress() & 0xff); + var endpointAddrSegment = arena.allocate(JAVA_INT); + endpointAddrSegment.setAtIndex(JAVA_INT, 0, endpoint.endpointAddress() & 0xff); var errorState = allocateErrorState(arena); var res = IO.ioctl(fd, UsbDevFS.CLEAR_HALT, endpointAddrSegment, errorState); if (res < 0) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java index 8ff57088..fa3fd8ba 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java @@ -24,7 +24,7 @@ import static net.codecrete.usb.linux.Linux.allocateErrorState; import static net.codecrete.usb.linux.LinuxUsbException.throwException; import static net.codecrete.usb.linux.LinuxUsbException.throwLastError; -import static net.codecrete.usb.linux.gen.epoll.epoll.*; +import static net.codecrete.usb.linux.gen.epoll.epoll.EPOLLIN; import static net.codecrete.usb.linux.gen.fcntl.fcntl.FD_CLOEXEC; /** @@ -45,18 +45,17 @@ public class LinuxUsbDeviceRegistry extends UsbDeviceRegistry { private static final MemorySegment ATTR_SERIAL; static { - @SuppressWarnings("resource") var global = Arena.global(); - SUBSYSTEM_USB = global.allocateUtf8String("usb"); - MONITOR_NAME = global.allocateUtf8String("udev"); - DEVTYPE_USB_DEVICE = global.allocateUtf8String("usb_device"); + SUBSYSTEM_USB = global.allocateFrom("usb"); + MONITOR_NAME = global.allocateFrom("udev"); + DEVTYPE_USB_DEVICE = global.allocateFrom("usb_device"); - ATTR_ID_VENDOR = global.allocateUtf8String("idVendor"); - ATTR_ID_PRODUCT = global.allocateUtf8String("idProduct"); - ATTR_MANUFACTURER = global.allocateUtf8String("manufacturer"); - ATTR_PRODUCT = global.allocateUtf8String("product"); - ATTR_SERIAL = global.allocateUtf8String("serial"); + ATTR_ID_VENDOR = global.allocateFrom("idVendor"); + ATTR_ID_PRODUCT = global.allocateFrom("idProduct"); + ATTR_MANUFACTURER = global.allocateFrom("manufacturer"); + ATTR_PRODUCT = global.allocateFrom("product"); + ATTR_SERIAL = global.allocateFrom("serial"); } @SuppressWarnings({"java:S1181", "java:S2189"}) @@ -104,7 +103,7 @@ protected void monitorDevices() { EPoll.addFileDescriptor(epfd, EPOLLIN(), fd); // allocate event (as output for epoll_wait) - var event = arena.allocate(epoll_event.$LAYOUT()); + var event = arena.allocate(epoll_event.layout()); // monitor device changes //noinspection InfiniteLoopStatement @@ -250,14 +249,14 @@ private static String getDeviceAttribute(MemorySegment udevDevice, MemorySegment if (value.address() == 0) return null; - return value.getUtf8String(0); + return value.getString(0); } private static String getDeviceName(MemorySegment udevDevice) { - return udev.udev_device_get_devnode(udevDevice).getUtf8String(0); + return udev.udev_device_get_devnode(udevDevice).getString(0); } private static String getDeviceAction(MemorySegment udevDevice) { - return udev.udev_device_get_action(udevDevice).getUtf8String(0); + return udev.udev_device_get_action(udevDevice).getString(0); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/RuntimeHelper.java deleted file mode 100644 index 6259819d..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/RuntimeHelper.java +++ /dev/null @@ -1,227 +0,0 @@ -package net.codecrete.usb.linux.gen.epoll; -// Generated by jextract - -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.*; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { - - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/constants$0.java deleted file mode 100644 index f5fe605a..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/constants$0.java +++ /dev/null @@ -1,27 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.epoll; - -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final StructLayout const$0 = MemoryLayout.structLayout( - JAVA_INT.withByteAlignment(1).withName("events"), - MemoryLayout.unionLayout( - RuntimeHelper.POINTER.withByteAlignment(1).withName("ptr"), - JAVA_INT.withByteAlignment(1).withName("fd"), - JAVA_INT.withByteAlignment(1).withName("u32"), - JAVA_LONG.withByteAlignment(1).withName("u64") - ).withName("data") - ).withName("epoll_event"); - static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("events")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java index ee58d003..670be9c3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java @@ -3,58 +3,106 @@ package net.codecrete.usb.linux.gen.epoll; import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; -import static java.lang.foreign.ValueLayout.*; -public class epoll { - - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfLong C_LONG = JAVA_LONG; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; + +public class epoll { + + epoll() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; + private static final int EPOLL_CTL_ADD = (int)1L; /** - * {@snippet : + * {@snippet lang=c : * #define EPOLL_CTL_ADD 1 * } */ public static int EPOLL_CTL_ADD() { - return (int)1L; + return EPOLL_CTL_ADD; } + private static final int EPOLL_CTL_DEL = (int)2L; /** - * {@snippet : + * {@snippet lang=c : * #define EPOLL_CTL_DEL 2 * } */ public static int EPOLL_CTL_DEL() { - return (int)2L; + return EPOLL_CTL_DEL; } + private static final int EPOLLIN = (int)1L; /** - * {@snippet : - * enum EPOLL_EVENTS.EPOLLIN = 1; + * {@snippet lang=c : + * enum EPOLL_EVENTS.EPOLLIN = 1 * } */ public static int EPOLLIN() { - return (int)1L; + return EPOLLIN; } + private static final int EPOLLOUT = (int)4L; /** - * {@snippet : - * enum EPOLL_EVENTS.EPOLLOUT = 4; + * {@snippet lang=c : + * enum EPOLL_EVENTS.EPOLLOUT = 4 * } */ public static int EPOLLOUT() { - return (int)4L; + return EPOLLOUT; } + private static final int EPOLLWAKEUP = (int)536870912L; /** - * {@snippet : - * enum EPOLL_EVENTS.EPOLLWAKEUP = 536870912; + * {@snippet lang=c : + * enum EPOLL_EVENTS.EPOLLWAKEUP = 536870912 * } */ public static int EPOLLWAKEUP() { - return (int)536870912L; + return EPOLLWAKEUP; } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_data.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_data.java new file mode 100644 index 00000000..567b218d --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_data.java @@ -0,0 +1,267 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.epoll; + +import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfLong; + +/** + * {@snippet lang=c : + * union epoll_data { + * void *ptr; + * int fd; + * uint32_t u32; + * uint64_t u64; + * } + * } + */ +public class epoll_data { + + epoll_data() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.unionLayout( + epoll.C_POINTER.withName("ptr").withByteAlignment(4), + epoll.C_INT.withName("fd"), + epoll.C_INT.withName("u32"), + epoll.C_LONG.withName("u64").withByteAlignment(4) + ).withName("epoll_data"); + + /** + * The layout of this union + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final AddressLayout ptr$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("ptr")); + + /** + * Layout for field: + * {@snippet lang=c : + * void *ptr + * } + */ + public static final AddressLayout ptr$layout() { + return ptr$LAYOUT; + } + + private static final long ptr$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * void *ptr + * } + */ + public static final long ptr$offset() { + return ptr$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * void *ptr + * } + */ + public static MemorySegment ptr(MemorySegment union) { + return union.get(ptr$LAYOUT, ptr$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * void *ptr + * } + */ + public static void ptr(MemorySegment union, MemorySegment fieldValue) { + union.set(ptr$LAYOUT, ptr$OFFSET, fieldValue); + } + + private static final OfInt fd$LAYOUT = (OfInt)$LAYOUT.select(groupElement("fd")); + + /** + * Layout for field: + * {@snippet lang=c : + * int fd + * } + */ + public static final OfInt fd$layout() { + return fd$LAYOUT; + } + + private static final long fd$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * int fd + * } + */ + public static final long fd$offset() { + return fd$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * int fd + * } + */ + public static int fd(MemorySegment union) { + return union.get(fd$LAYOUT, fd$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * int fd + * } + */ + public static void fd(MemorySegment union, int fieldValue) { + union.set(fd$LAYOUT, fd$OFFSET, fieldValue); + } + + private static final OfInt u32$LAYOUT = (OfInt)$LAYOUT.select(groupElement("u32")); + + /** + * Layout for field: + * {@snippet lang=c : + * uint32_t u32 + * } + */ + public static final OfInt u32$layout() { + return u32$LAYOUT; + } + + private static final long u32$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * uint32_t u32 + * } + */ + public static final long u32$offset() { + return u32$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * uint32_t u32 + * } + */ + public static int u32(MemorySegment union) { + return union.get(u32$LAYOUT, u32$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * uint32_t u32 + * } + */ + public static void u32(MemorySegment union, int fieldValue) { + union.set(u32$LAYOUT, u32$OFFSET, fieldValue); + } + + private static final OfLong u64$LAYOUT = (OfLong)$LAYOUT.select(groupElement("u64")); + + /** + * Layout for field: + * {@snippet lang=c : + * uint64_t u64 + * } + */ + public static final OfLong u64$layout() { + return u64$LAYOUT; + } + + private static final long u64$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * uint64_t u64 + * } + */ + public static final long u64$offset() { + return u64$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * uint64_t u64 + * } + */ + public static long u64(MemorySegment union) { + return union.get(u64$LAYOUT, u64$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * uint64_t u64 + * } + */ + public static void u64(MemorySegment union, long fieldValue) { + union.set(u64$LAYOUT, u64$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this union + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java index e59d3532..fc3bd418 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java @@ -3,59 +3,171 @@ package net.codecrete.usb.linux.gen.epoll; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfInt; + /** - * {@snippet : + * {@snippet lang=c : * struct epoll_event { * uint32_t events; * epoll_data_t data; - * }; + * } * } */ public class epoll_event { - public static MemoryLayout $LAYOUT() { - return constants$0.const$0; + epoll_event() { + // Should not be called directly } - public static VarHandle events$VH() { - return constants$0.const$1; + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + epoll.C_INT.withByteAlignment(1).withName("events"), + epoll_data.layout().withName("data") + ).withName("epoll_event"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } + + private static final OfInt events$LAYOUT = (OfInt)$LAYOUT.select(groupElement("events")); + + /** + * Layout for field: + * {@snippet lang=c : + * uint32_t events + * } + */ + public static final OfInt events$layout() { + return events$LAYOUT; + } + + private static final long events$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * uint32_t events + * } + */ + public static final long events$offset() { + return events$OFFSET; + } + /** * Getter for field: - * {@snippet : - * uint32_t events; + * {@snippet lang=c : + * uint32_t events * } */ - public static int events$get(MemorySegment seg) { - return (int)constants$0.const$1.get(seg); + public static int events(MemorySegment struct) { + return struct.get(events$LAYOUT, events$OFFSET); } + /** * Setter for field: - * {@snippet : - * uint32_t events; + * {@snippet lang=c : + * uint32_t events * } */ - public static void events$set(MemorySegment seg, int x) { - constants$0.const$1.set(seg, x); + public static void events(MemorySegment struct, int fieldValue) { + struct.set(events$LAYOUT, events$OFFSET, fieldValue); } - public static int events$get(MemorySegment seg, long index) { - return (int)constants$0.const$1.get(seg.asSlice(index*sizeof())); + + private static final GroupLayout data$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("data")); + + /** + * Layout for field: + * {@snippet lang=c : + * epoll_data_t data + * } + */ + public static final GroupLayout data$layout() { + return data$LAYOUT; } - public static void events$set(MemorySegment seg, long index, int x) { - constants$0.const$1.set(seg.asSlice(index*sizeof()), x); + + private static final long data$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * epoll_data_t data + * } + */ + public static final long data$offset() { + return data$OFFSET; } - public static MemorySegment data$slice(MemorySegment seg) { - return seg.asSlice(4, 8); + + /** + * Getter for field: + * {@snippet lang=c : + * epoll_data_t data + * } + */ + public static MemorySegment data(MemorySegment struct) { + return struct.asSlice(data$OFFSET, data$LAYOUT.byteSize()); + } + + /** + * Setter for field: + * {@snippet lang=c : + * epoll_data_t data + * } + */ + public static void data(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, data$OFFSET, data$LAYOUT.byteSize()); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } -} + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/RuntimeHelper.java deleted file mode 100644 index f46e44cf..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/RuntimeHelper.java +++ /dev/null @@ -1,227 +0,0 @@ -package net.codecrete.usb.linux.gen.errno; -// Generated by jextract - -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.*; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { - - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java deleted file mode 100644 index d06cfe72..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/constants$0.java +++ /dev/null @@ -1,11 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.errno; - -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java index b9a9566e..554aff6e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -3,66 +3,115 @@ package net.codecrete.usb.linux.gen.errno; import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; -import static java.lang.foreign.ValueLayout.*; -public class errno { +import static java.lang.foreign.ValueLayout.JAVA_BYTE; - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfLong C_LONG = JAVA_LONG; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; +public class errno { + + errno() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; + private static final int ENOENT = (int)2L; /** - * {@snippet : + * {@snippet lang=c : * #define ENOENT 2 * } */ public static int ENOENT() { - return (int)2L; + return ENOENT; } + private static final int EINTR = (int)4L; /** - * {@snippet : + * {@snippet lang=c : * #define EINTR 4 * } */ public static int EINTR() { - return (int)4L; + return EINTR; } + private static final int EAGAIN = (int)11L; /** - * {@snippet : + * {@snippet lang=c : * #define EAGAIN 11 * } */ public static int EAGAIN() { - return (int)11L; + return EAGAIN; } + private static final int ENODEV = (int)19L; /** - * {@snippet : + * {@snippet lang=c : * #define ENODEV 19 * } */ public static int ENODEV() { - return (int)19L; + return ENODEV; } + private static final int EINVAL = (int)22L; /** - * {@snippet : + * {@snippet lang=c : * #define EINVAL 22 * } */ public static int EINVAL() { - return (int)22L; + return EINVAL; } + private static final int EPIPE = (int)32L; /** - * {@snippet : + * {@snippet lang=c : * #define EPIPE 32 * } */ public static int EPIPE() { - return (int)32L; + return EPIPE; } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/RuntimeHelper.java deleted file mode 100644 index 6b36ff84..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/RuntimeHelper.java +++ /dev/null @@ -1,227 +0,0 @@ -package net.codecrete.usb.linux.gen.fcntl; -// Generated by jextract - -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.*; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { - - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java deleted file mode 100644 index 384b1450..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/constants$0.java +++ /dev/null @@ -1,11 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.fcntl; - -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java index d3f2f2e6..b02887b8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java @@ -3,42 +3,88 @@ package net.codecrete.usb.linux.gen.fcntl; import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; -import static java.lang.foreign.ValueLayout.*; -public class fcntl { - - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfLong C_LONG = JAVA_LONG; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; + +public class fcntl { + + fcntl() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; + private static final int O_RDWR = (int)2L; /** - * {@snippet : + * {@snippet lang=c : * #define O_RDWR 2 * } */ public static int O_RDWR() { - return (int)2L; + return O_RDWR; } + private static final int FD_CLOEXEC = (int)1L; /** - * {@snippet : + * {@snippet lang=c : * #define FD_CLOEXEC 1 * } */ public static int FD_CLOEXEC() { - return (int)1L; + return FD_CLOEXEC; } + private static final int O_CLOEXEC = (int)524288L; /** - * {@snippet : + * {@snippet lang=c : * #define O_CLOEXEC 524288 * } */ public static int O_CLOEXEC() { - return (int)524288L; + return O_CLOEXEC; } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/RuntimeHelper.java deleted file mode 100644 index e0a365d5..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/RuntimeHelper.java +++ /dev/null @@ -1,227 +0,0 @@ -package net.codecrete.usb.linux.gen.string; -// Generated by jextract - -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.*; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { - - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/constants$0.java deleted file mode 100644 index bfe9c830..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/constants$0.java +++ /dev/null @@ -1,22 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.string; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(RuntimeHelper.POINTER, - JAVA_INT - ); - static final MethodHandle const$1 = RuntimeHelper.downcallHandle( - "strerror", - constants$0.const$0 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java index 895d225f..9ed3f222 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java @@ -3,36 +3,108 @@ package net.codecrete.usb.linux.gen.string; import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; -import static java.lang.foreign.ValueLayout.*; -public class string { +import static java.lang.foreign.ValueLayout.JAVA_BYTE; - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfLong C_LONG = JAVA_LONG; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; - public static MethodHandle strerror$MH() { - return RuntimeHelper.requireNonNull(constants$0.const$1,"strerror"); +public class string { + + string() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; + + private static class strerror { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + string.C_POINTER, + string.C_INT + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + string.findOrThrow("strerror"), + DESC); } + /** - * {@snippet : - * char* strerror(int __errnum); + * Function descriptor for: + * {@snippet lang=c : + * extern char *strerror(int __errnum) + * } + */ + public static FunctionDescriptor strerror$descriptor() { + return strerror.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern char *strerror(int __errnum) + * } + */ + public static MethodHandle strerror$handle() { + return strerror.HANDLE; + } + /** + * {@snippet lang=c : + * extern char *strerror(int __errnum) * } */ public static MemorySegment strerror(int __errnum) { - var mh$ = strerror$MH(); + var mh$ = strerror.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(__errnum); + if (TRACE_DOWNCALLS) { + traceDowncall("strerror", __errnum); + } + return (MemorySegment)mh$.invokeExact(__errnum); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java deleted file mode 100644 index c2ccf243..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/RuntimeHelper.java +++ /dev/null @@ -1,228 +0,0 @@ -package net.codecrete.usb.linux.gen.udev; -// Generated by jextract - -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.*; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { -// System.loadLibrary("udev"); -// SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so.1", Arena.global()); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java deleted file mode 100644 index 1017f6fe..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$0.java +++ /dev/null @@ -1,33 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.udev; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(RuntimeHelper.POINTER); - static final MethodHandle const$1 = RuntimeHelper.downcallHandle( - "udev_new", - constants$0.const$0 - ); - static final FunctionDescriptor const$2 = FunctionDescriptor.of(RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$3 = RuntimeHelper.downcallHandle( - "udev_list_entry_get_next", - constants$0.const$2 - ); - static final MethodHandle const$4 = RuntimeHelper.downcallHandle( - "udev_list_entry_get_name", - constants$0.const$2 - ); - static final MethodHandle const$5 = RuntimeHelper.downcallHandle( - "udev_device_unref", - constants$0.const$2 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java deleted file mode 100644 index 9d318029..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$1.java +++ /dev/null @@ -1,37 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.udev; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; -final class constants$1 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$1() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$1 = RuntimeHelper.downcallHandle( - "udev_device_new_from_syspath", - constants$1.const$0 - ); - static final MethodHandle const$2 = RuntimeHelper.downcallHandle( - "udev_device_get_devtype", - constants$0.const$2 - ); - static final MethodHandle const$3 = RuntimeHelper.downcallHandle( - "udev_device_get_devnode", - constants$0.const$2 - ); - static final MethodHandle const$4 = RuntimeHelper.downcallHandle( - "udev_device_get_action", - constants$0.const$2 - ); - static final MethodHandle const$5 = RuntimeHelper.downcallHandle( - "udev_device_get_sysattr_value", - constants$1.const$0 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$2.java deleted file mode 100644 index 88ac3987..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$2.java +++ /dev/null @@ -1,43 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.udev; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$2 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$2() {} - static final MethodHandle const$0 = RuntimeHelper.downcallHandle( - "udev_monitor_new_from_netlink", - constants$1.const$0 - ); - static final FunctionDescriptor const$1 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER - ); - static final MethodHandle const$2 = RuntimeHelper.downcallHandle( - "udev_monitor_enable_receiving", - constants$2.const$1 - ); - static final MethodHandle const$3 = RuntimeHelper.downcallHandle( - "udev_monitor_get_fd", - constants$2.const$1 - ); - static final MethodHandle const$4 = RuntimeHelper.downcallHandle( - "udev_monitor_receive_device", - constants$0.const$2 - ); - static final FunctionDescriptor const$5 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$6 = RuntimeHelper.downcallHandle( - "udev_monitor_filter_add_match_subsystem_devtype", - constants$2.const$5 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$3.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$3.java deleted file mode 100644 index b469b77f..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/constants$3.java +++ /dev/null @@ -1,39 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.udev; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$3 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$3() {} - static final MethodHandle const$0 = RuntimeHelper.downcallHandle( - "udev_enumerate_unref", - constants$0.const$2 - ); - static final MethodHandle const$1 = RuntimeHelper.downcallHandle( - "udev_enumerate_new", - constants$0.const$2 - ); - static final FunctionDescriptor const$2 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$3 = RuntimeHelper.downcallHandle( - "udev_enumerate_add_match_subsystem", - constants$3.const$2 - ); - static final MethodHandle const$4 = RuntimeHelper.downcallHandle( - "udev_enumerate_scan_devices", - constants$2.const$1 - ); - static final MethodHandle const$5 = RuntimeHelper.downcallHandle( - "udev_enumerate_get_list_entry", - constants$0.const$2 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java index bcc40cb5..715246fe 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java @@ -3,324 +3,961 @@ package net.codecrete.usb.linux.gen.udev; import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; -import static java.lang.foreign.ValueLayout.*; -public class udev { +import static java.lang.foreign.ValueLayout.JAVA_BYTE; - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfLong C_LONG = JAVA_LONG; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; - public static MethodHandle udev_new$MH() { - return RuntimeHelper.requireNonNull(constants$0.const$1,"udev_new"); +public class udev { + + udev() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + // Manually fix. Otherwise, libudev will not be found if "libudev-dev" is not installed + // static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("udev"), LIBRARY_ARENA) + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup("libudev.so.1", LIBRARY_ARENA) + .or(SymbolLookup.loaderLookup()) + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; + + private static class udev_new { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_POINTER ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_new"), + DESC); } + /** - * {@snippet : - * struct udev* udev_new(); + * Function descriptor for: + * {@snippet lang=c : + * struct udev *udev_new() + * } + */ + public static FunctionDescriptor udev_new$descriptor() { + return udev_new.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * struct udev *udev_new() + * } + */ + public static MethodHandle udev_new$handle() { + return udev_new.HANDLE; + } + /** + * {@snippet lang=c : + * struct udev *udev_new() * } */ public static MemorySegment udev_new() { - var mh$ = udev_new$MH(); + var mh$ = udev_new.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(); + if (TRACE_DOWNCALLS) { + traceDowncall("udev_new"); + } + return (MemorySegment)mh$.invokeExact(); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_list_entry_get_next$MH() { - return RuntimeHelper.requireNonNull(constants$0.const$3,"udev_list_entry_get_next"); + + private static class udev_list_entry_get_next { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_POINTER, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_list_entry_get_next"), + DESC); } + /** - * {@snippet : - * struct udev_list_entry* udev_list_entry_get_next(struct udev_list_entry* list_entry); + * Function descriptor for: + * {@snippet lang=c : + * struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) + * } + */ + public static FunctionDescriptor udev_list_entry_get_next$descriptor() { + return udev_list_entry_get_next.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) + * } + */ + public static MethodHandle udev_list_entry_get_next$handle() { + return udev_list_entry_get_next.HANDLE; + } + /** + * {@snippet lang=c : + * struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) * } */ public static MemorySegment udev_list_entry_get_next(MemorySegment list_entry) { - var mh$ = udev_list_entry_get_next$MH(); + var mh$ = udev_list_entry_get_next.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(list_entry); + if (TRACE_DOWNCALLS) { + traceDowncall("udev_list_entry_get_next", list_entry); + } + return (MemorySegment)mh$.invokeExact(list_entry); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_list_entry_get_name$MH() { - return RuntimeHelper.requireNonNull(constants$0.const$4,"udev_list_entry_get_name"); + + private static class udev_list_entry_get_name { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_POINTER, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_list_entry_get_name"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) + * } + */ + public static FunctionDescriptor udev_list_entry_get_name$descriptor() { + return udev_list_entry_get_name.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) + * } + */ + public static MethodHandle udev_list_entry_get_name$handle() { + return udev_list_entry_get_name.HANDLE; } /** - * {@snippet : - * char* udev_list_entry_get_name(struct udev_list_entry* list_entry); + * {@snippet lang=c : + * const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) * } */ public static MemorySegment udev_list_entry_get_name(MemorySegment list_entry) { - var mh$ = udev_list_entry_get_name$MH(); + var mh$ = udev_list_entry_get_name.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(list_entry); + if (TRACE_DOWNCALLS) { + traceDowncall("udev_list_entry_get_name", list_entry); + } + return (MemorySegment)mh$.invokeExact(list_entry); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_device_unref$MH() { - return RuntimeHelper.requireNonNull(constants$0.const$5,"udev_device_unref"); + + private static class udev_device_unref { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_POINTER, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_device_unref"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * struct udev_device *udev_device_unref(struct udev_device *udev_device) + * } + */ + public static FunctionDescriptor udev_device_unref$descriptor() { + return udev_device_unref.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * struct udev_device *udev_device_unref(struct udev_device *udev_device) + * } + */ + public static MethodHandle udev_device_unref$handle() { + return udev_device_unref.HANDLE; } /** - * {@snippet : - * struct udev_device* udev_device_unref(struct udev_device* udev_device); + * {@snippet lang=c : + * struct udev_device *udev_device_unref(struct udev_device *udev_device) * } */ public static MemorySegment udev_device_unref(MemorySegment udev_device) { - var mh$ = udev_device_unref$MH(); + var mh$ = udev_device_unref.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev_device); + if (TRACE_DOWNCALLS) { + traceDowncall("udev_device_unref", udev_device); + } + return (MemorySegment)mh$.invokeExact(udev_device); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_device_new_from_syspath$MH() { - return RuntimeHelper.requireNonNull(constants$1.const$1,"udev_device_new_from_syspath"); + + private static class udev_device_new_from_syspath { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_POINTER, + udev.C_POINTER, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_device_new_from_syspath"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) + * } + */ + public static FunctionDescriptor udev_device_new_from_syspath$descriptor() { + return udev_device_new_from_syspath.DESC; } + /** - * {@snippet : - * struct udev_device* udev_device_new_from_syspath(struct udev* udev, char* syspath); + * Downcall method handle for: + * {@snippet lang=c : + * struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) + * } + */ + public static MethodHandle udev_device_new_from_syspath$handle() { + return udev_device_new_from_syspath.HANDLE; + } + /** + * {@snippet lang=c : + * struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) * } */ public static MemorySegment udev_device_new_from_syspath(MemorySegment udev, MemorySegment syspath) { - var mh$ = udev_device_new_from_syspath$MH(); + var mh$ = udev_device_new_from_syspath.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev, syspath); + if (TRACE_DOWNCALLS) { + traceDowncall("udev_device_new_from_syspath", udev, syspath); + } + return (MemorySegment)mh$.invokeExact(udev, syspath); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_device_get_devtype$MH() { - return RuntimeHelper.requireNonNull(constants$1.const$2,"udev_device_get_devtype"); + + private static class udev_device_get_devtype { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_POINTER, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_device_get_devtype"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * const char *udev_device_get_devtype(struct udev_device *udev_device) + * } + */ + public static FunctionDescriptor udev_device_get_devtype$descriptor() { + return udev_device_get_devtype.DESC; } + /** - * {@snippet : - * char* udev_device_get_devtype(struct udev_device* udev_device); + * Downcall method handle for: + * {@snippet lang=c : + * const char *udev_device_get_devtype(struct udev_device *udev_device) + * } + */ + public static MethodHandle udev_device_get_devtype$handle() { + return udev_device_get_devtype.HANDLE; + } + /** + * {@snippet lang=c : + * const char *udev_device_get_devtype(struct udev_device *udev_device) * } */ public static MemorySegment udev_device_get_devtype(MemorySegment udev_device) { - var mh$ = udev_device_get_devtype$MH(); + var mh$ = udev_device_get_devtype.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev_device); + if (TRACE_DOWNCALLS) { + traceDowncall("udev_device_get_devtype", udev_device); + } + return (MemorySegment)mh$.invokeExact(udev_device); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_device_get_devnode$MH() { - return RuntimeHelper.requireNonNull(constants$1.const$3,"udev_device_get_devnode"); + + private static class udev_device_get_devnode { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_POINTER, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_device_get_devnode"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * const char *udev_device_get_devnode(struct udev_device *udev_device) + * } + */ + public static FunctionDescriptor udev_device_get_devnode$descriptor() { + return udev_device_get_devnode.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * const char *udev_device_get_devnode(struct udev_device *udev_device) + * } + */ + public static MethodHandle udev_device_get_devnode$handle() { + return udev_device_get_devnode.HANDLE; } /** - * {@snippet : - * char* udev_device_get_devnode(struct udev_device* udev_device); + * {@snippet lang=c : + * const char *udev_device_get_devnode(struct udev_device *udev_device) * } */ public static MemorySegment udev_device_get_devnode(MemorySegment udev_device) { - var mh$ = udev_device_get_devnode$MH(); + var mh$ = udev_device_get_devnode.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev_device); + if (TRACE_DOWNCALLS) { + traceDowncall("udev_device_get_devnode", udev_device); + } + return (MemorySegment)mh$.invokeExact(udev_device); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_device_get_action$MH() { - return RuntimeHelper.requireNonNull(constants$1.const$4,"udev_device_get_action"); + + private static class udev_device_get_action { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_POINTER, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_device_get_action"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * const char *udev_device_get_action(struct udev_device *udev_device) + * } + */ + public static FunctionDescriptor udev_device_get_action$descriptor() { + return udev_device_get_action.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * const char *udev_device_get_action(struct udev_device *udev_device) + * } + */ + public static MethodHandle udev_device_get_action$handle() { + return udev_device_get_action.HANDLE; } /** - * {@snippet : - * char* udev_device_get_action(struct udev_device* udev_device); + * {@snippet lang=c : + * const char *udev_device_get_action(struct udev_device *udev_device) * } */ public static MemorySegment udev_device_get_action(MemorySegment udev_device) { - var mh$ = udev_device_get_action$MH(); + var mh$ = udev_device_get_action.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev_device); + if (TRACE_DOWNCALLS) { + traceDowncall("udev_device_get_action", udev_device); + } + return (MemorySegment)mh$.invokeExact(udev_device); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_device_get_sysattr_value$MH() { - return RuntimeHelper.requireNonNull(constants$1.const$5,"udev_device_get_sysattr_value"); + + private static class udev_device_get_sysattr_value { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_POINTER, + udev.C_POINTER, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_device_get_sysattr_value"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) + * } + */ + public static FunctionDescriptor udev_device_get_sysattr_value$descriptor() { + return udev_device_get_sysattr_value.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) + * } + */ + public static MethodHandle udev_device_get_sysattr_value$handle() { + return udev_device_get_sysattr_value.HANDLE; } /** - * {@snippet : - * char* udev_device_get_sysattr_value(struct udev_device* udev_device, char* sysattr); + * {@snippet lang=c : + * const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) * } */ public static MemorySegment udev_device_get_sysattr_value(MemorySegment udev_device, MemorySegment sysattr) { - var mh$ = udev_device_get_sysattr_value$MH(); + var mh$ = udev_device_get_sysattr_value.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev_device, sysattr); + if (TRACE_DOWNCALLS) { + traceDowncall("udev_device_get_sysattr_value", udev_device, sysattr); + } + return (MemorySegment)mh$.invokeExact(udev_device, sysattr); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_monitor_new_from_netlink$MH() { - return RuntimeHelper.requireNonNull(constants$2.const$0,"udev_monitor_new_from_netlink"); + + private static class udev_monitor_new_from_netlink { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_POINTER, + udev.C_POINTER, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_monitor_new_from_netlink"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name) + * } + */ + public static FunctionDescriptor udev_monitor_new_from_netlink$descriptor() { + return udev_monitor_new_from_netlink.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name) + * } + */ + public static MethodHandle udev_monitor_new_from_netlink$handle() { + return udev_monitor_new_from_netlink.HANDLE; } /** - * {@snippet : - * struct udev_monitor* udev_monitor_new_from_netlink(struct udev* udev, char* name); + * {@snippet lang=c : + * struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name) * } */ public static MemorySegment udev_monitor_new_from_netlink(MemorySegment udev, MemorySegment name) { - var mh$ = udev_monitor_new_from_netlink$MH(); + var mh$ = udev_monitor_new_from_netlink.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev, name); + if (TRACE_DOWNCALLS) { + traceDowncall("udev_monitor_new_from_netlink", udev, name); + } + return (MemorySegment)mh$.invokeExact(udev, name); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_monitor_enable_receiving$MH() { - return RuntimeHelper.requireNonNull(constants$2.const$2,"udev_monitor_enable_receiving"); + + private static class udev_monitor_enable_receiving { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_INT, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_monitor_enable_receiving"), + DESC); } + /** - * {@snippet : - * int udev_monitor_enable_receiving(struct udev_monitor* udev_monitor); + * Function descriptor for: + * {@snippet lang=c : + * int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) + * } + */ + public static FunctionDescriptor udev_monitor_enable_receiving$descriptor() { + return udev_monitor_enable_receiving.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) + * } + */ + public static MethodHandle udev_monitor_enable_receiving$handle() { + return udev_monitor_enable_receiving.HANDLE; + } + /** + * {@snippet lang=c : + * int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) * } */ public static int udev_monitor_enable_receiving(MemorySegment udev_monitor) { - var mh$ = udev_monitor_enable_receiving$MH(); + var mh$ = udev_monitor_enable_receiving.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("udev_monitor_enable_receiving", udev_monitor); + } return (int)mh$.invokeExact(udev_monitor); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_monitor_get_fd$MH() { - return RuntimeHelper.requireNonNull(constants$2.const$3,"udev_monitor_get_fd"); + + private static class udev_monitor_get_fd { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_INT, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_monitor_get_fd"), + DESC); } + /** - * {@snippet : - * int udev_monitor_get_fd(struct udev_monitor* udev_monitor); + * Function descriptor for: + * {@snippet lang=c : + * int udev_monitor_get_fd(struct udev_monitor *udev_monitor) + * } + */ + public static FunctionDescriptor udev_monitor_get_fd$descriptor() { + return udev_monitor_get_fd.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * int udev_monitor_get_fd(struct udev_monitor *udev_monitor) + * } + */ + public static MethodHandle udev_monitor_get_fd$handle() { + return udev_monitor_get_fd.HANDLE; + } + /** + * {@snippet lang=c : + * int udev_monitor_get_fd(struct udev_monitor *udev_monitor) * } */ public static int udev_monitor_get_fd(MemorySegment udev_monitor) { - var mh$ = udev_monitor_get_fd$MH(); + var mh$ = udev_monitor_get_fd.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("udev_monitor_get_fd", udev_monitor); + } return (int)mh$.invokeExact(udev_monitor); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_monitor_receive_device$MH() { - return RuntimeHelper.requireNonNull(constants$2.const$4,"udev_monitor_receive_device"); + + private static class udev_monitor_receive_device { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_POINTER, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_monitor_receive_device"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) + * } + */ + public static FunctionDescriptor udev_monitor_receive_device$descriptor() { + return udev_monitor_receive_device.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) + * } + */ + public static MethodHandle udev_monitor_receive_device$handle() { + return udev_monitor_receive_device.HANDLE; } /** - * {@snippet : - * struct udev_device* udev_monitor_receive_device(struct udev_monitor* udev_monitor); + * {@snippet lang=c : + * struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) * } */ public static MemorySegment udev_monitor_receive_device(MemorySegment udev_monitor) { - var mh$ = udev_monitor_receive_device$MH(); + var mh$ = udev_monitor_receive_device.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev_monitor); + if (TRACE_DOWNCALLS) { + traceDowncall("udev_monitor_receive_device", udev_monitor); + } + return (MemorySegment)mh$.invokeExact(udev_monitor); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_monitor_filter_add_match_subsystem_devtype$MH() { - return RuntimeHelper.requireNonNull(constants$2.const$6,"udev_monitor_filter_add_match_subsystem_devtype"); + + private static class udev_monitor_filter_add_match_subsystem_devtype { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_INT, + udev.C_POINTER, + udev.C_POINTER, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_monitor_filter_add_match_subsystem_devtype"), + DESC); } + /** - * {@snippet : - * int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor* udev_monitor, char* subsystem, char* devtype); + * Function descriptor for: + * {@snippet lang=c : + * int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) + * } + */ + public static FunctionDescriptor udev_monitor_filter_add_match_subsystem_devtype$descriptor() { + return udev_monitor_filter_add_match_subsystem_devtype.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) + * } + */ + public static MethodHandle udev_monitor_filter_add_match_subsystem_devtype$handle() { + return udev_monitor_filter_add_match_subsystem_devtype.HANDLE; + } + /** + * {@snippet lang=c : + * int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) * } */ public static int udev_monitor_filter_add_match_subsystem_devtype(MemorySegment udev_monitor, MemorySegment subsystem, MemorySegment devtype) { - var mh$ = udev_monitor_filter_add_match_subsystem_devtype$MH(); + var mh$ = udev_monitor_filter_add_match_subsystem_devtype.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("udev_monitor_filter_add_match_subsystem_devtype", udev_monitor, subsystem, devtype); + } return (int)mh$.invokeExact(udev_monitor, subsystem, devtype); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_enumerate_unref$MH() { - return RuntimeHelper.requireNonNull(constants$3.const$0,"udev_enumerate_unref"); + + private static class udev_enumerate_unref { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_POINTER, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_enumerate_unref"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate) + * } + */ + public static FunctionDescriptor udev_enumerate_unref$descriptor() { + return udev_enumerate_unref.DESC; } + /** - * {@snippet : - * struct udev_enumerate* udev_enumerate_unref(struct udev_enumerate* udev_enumerate); + * Downcall method handle for: + * {@snippet lang=c : + * struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate) + * } + */ + public static MethodHandle udev_enumerate_unref$handle() { + return udev_enumerate_unref.HANDLE; + } + /** + * {@snippet lang=c : + * struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate) * } */ public static MemorySegment udev_enumerate_unref(MemorySegment udev_enumerate) { - var mh$ = udev_enumerate_unref$MH(); + var mh$ = udev_enumerate_unref.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev_enumerate); + if (TRACE_DOWNCALLS) { + traceDowncall("udev_enumerate_unref", udev_enumerate); + } + return (MemorySegment)mh$.invokeExact(udev_enumerate); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_enumerate_new$MH() { - return RuntimeHelper.requireNonNull(constants$3.const$1,"udev_enumerate_new"); + + private static class udev_enumerate_new { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_POINTER, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_enumerate_new"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * struct udev_enumerate *udev_enumerate_new(struct udev *udev) + * } + */ + public static FunctionDescriptor udev_enumerate_new$descriptor() { + return udev_enumerate_new.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * struct udev_enumerate *udev_enumerate_new(struct udev *udev) + * } + */ + public static MethodHandle udev_enumerate_new$handle() { + return udev_enumerate_new.HANDLE; } /** - * {@snippet : - * struct udev_enumerate* udev_enumerate_new(struct udev* udev); + * {@snippet lang=c : + * struct udev_enumerate *udev_enumerate_new(struct udev *udev) * } */ public static MemorySegment udev_enumerate_new(MemorySegment udev) { - var mh$ = udev_enumerate_new$MH(); + var mh$ = udev_enumerate_new.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev); + if (TRACE_DOWNCALLS) { + traceDowncall("udev_enumerate_new", udev); + } + return (MemorySegment)mh$.invokeExact(udev); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_enumerate_add_match_subsystem$MH() { - return RuntimeHelper.requireNonNull(constants$3.const$3,"udev_enumerate_add_match_subsystem"); + + private static class udev_enumerate_add_match_subsystem { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_INT, + udev.C_POINTER, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_enumerate_add_match_subsystem"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) + * } + */ + public static FunctionDescriptor udev_enumerate_add_match_subsystem$descriptor() { + return udev_enumerate_add_match_subsystem.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) + * } + */ + public static MethodHandle udev_enumerate_add_match_subsystem$handle() { + return udev_enumerate_add_match_subsystem.HANDLE; } /** - * {@snippet : - * int udev_enumerate_add_match_subsystem(struct udev_enumerate* udev_enumerate, char* subsystem); + * {@snippet lang=c : + * int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) * } */ public static int udev_enumerate_add_match_subsystem(MemorySegment udev_enumerate, MemorySegment subsystem) { - var mh$ = udev_enumerate_add_match_subsystem$MH(); + var mh$ = udev_enumerate_add_match_subsystem.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("udev_enumerate_add_match_subsystem", udev_enumerate, subsystem); + } return (int)mh$.invokeExact(udev_enumerate, subsystem); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_enumerate_scan_devices$MH() { - return RuntimeHelper.requireNonNull(constants$3.const$4,"udev_enumerate_scan_devices"); + + private static class udev_enumerate_scan_devices { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_INT, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_enumerate_scan_devices"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) + * } + */ + public static FunctionDescriptor udev_enumerate_scan_devices$descriptor() { + return udev_enumerate_scan_devices.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) + * } + */ + public static MethodHandle udev_enumerate_scan_devices$handle() { + return udev_enumerate_scan_devices.HANDLE; } /** - * {@snippet : - * int udev_enumerate_scan_devices(struct udev_enumerate* udev_enumerate); + * {@snippet lang=c : + * int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) * } */ public static int udev_enumerate_scan_devices(MemorySegment udev_enumerate) { - var mh$ = udev_enumerate_scan_devices$MH(); + var mh$ = udev_enumerate_scan_devices.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("udev_enumerate_scan_devices", udev_enumerate); + } return (int)mh$.invokeExact(udev_enumerate); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle udev_enumerate_get_list_entry$MH() { - return RuntimeHelper.requireNonNull(constants$3.const$5,"udev_enumerate_get_list_entry"); + + private static class udev_enumerate_get_list_entry { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + udev.C_POINTER, + udev.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + udev.findOrThrow("udev_enumerate_get_list_entry"), + DESC); } + /** - * {@snippet : - * struct udev_list_entry* udev_enumerate_get_list_entry(struct udev_enumerate* udev_enumerate); + * Function descriptor for: + * {@snippet lang=c : + * struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) + * } + */ + public static FunctionDescriptor udev_enumerate_get_list_entry$descriptor() { + return udev_enumerate_get_list_entry.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) + * } + */ + public static MethodHandle udev_enumerate_get_list_entry$handle() { + return udev_enumerate_get_list_entry.HANDLE; + } + /** + * {@snippet lang=c : + * struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) * } */ public static MemorySegment udev_enumerate_get_list_entry(MemorySegment udev_enumerate) { - var mh$ = udev_enumerate_get_list_entry$MH(); + var mh$ = udev_enumerate_get_list_entry.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(udev_enumerate); + if (TRACE_DOWNCALLS) { + traceDowncall("udev_enumerate_get_list_entry", udev_enumerate); + } + return (MemorySegment)mh$.invokeExact(udev_enumerate); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/RuntimeHelper.java deleted file mode 100644 index f3cff469..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/RuntimeHelper.java +++ /dev/null @@ -1,227 +0,0 @@ -package net.codecrete.usb.linux.gen.unistd; -// Generated by jextract - -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.*; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { - - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java deleted file mode 100644 index 90d07fa3..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/constants$0.java +++ /dev/null @@ -1,22 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.unistd; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, - JAVA_INT - ); - static final MethodHandle const$1 = RuntimeHelper.downcallHandle( - "close", - constants$0.const$0 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java index 581e508e..b6300a9b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java @@ -3,35 +3,108 @@ package net.codecrete.usb.linux.gen.unistd; import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; -import static java.lang.foreign.ValueLayout.*; -public class unistd { +import static java.lang.foreign.ValueLayout.JAVA_BYTE; - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfLong C_LONG = JAVA_LONG; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; - public static MethodHandle close$MH() { - return RuntimeHelper.requireNonNull(constants$0.const$1,"close"); +public class unistd { + + unistd() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; + + private static class close { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + unistd.C_INT, + unistd.C_INT + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + unistd.findOrThrow("close"), + DESC); } + /** - * {@snippet : - * int close(int __fd); + * Function descriptor for: + * {@snippet lang=c : + * extern int close(int __fd) + * } + */ + public static FunctionDescriptor close$descriptor() { + return close.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern int close(int __fd) + * } + */ + public static MethodHandle close$handle() { + return close.HANDLE; + } + /** + * {@snippet lang=c : + * extern int close(int __fd) * } */ public static int close(int __fd) { - var mh$ = close$MH(); + var mh$ = close.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("close", __fd); + } return (int)mh$.invokeExact(__fd); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/RuntimeHelper.java deleted file mode 100644 index 5e6d3cd8..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/RuntimeHelper.java +++ /dev/null @@ -1,227 +0,0 @@ -package net.codecrete.usb.linux.gen.usbdevice_fs; -// Generated by jextract - -import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.*; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { - - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$0.java deleted file mode 100644 index 24688f13..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$0.java +++ /dev/null @@ -1,31 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.*; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final StructLayout const$0 = MemoryLayout.structLayout( - JAVA_BYTE.withName("bRequestType"), - JAVA_BYTE.withName("bRequest"), - JAVA_SHORT.withName("wValue"), - JAVA_SHORT.withName("wIndex"), - JAVA_SHORT.withName("wLength"), - JAVA_INT.withName("timeout"), - MemoryLayout.paddingLayout(4), - RuntimeHelper.POINTER.withName("data") - ).withName("usbdevfs_ctrltransfer"); - static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("bRequestType")); - static final VarHandle const$2 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("bRequest")); - static final VarHandle const$3 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("wValue")); - static final VarHandle const$4 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("wIndex")); - static final VarHandle const$5 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("wLength")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$1.java deleted file mode 100644 index 9666d212..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$1.java +++ /dev/null @@ -1,28 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$1 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$1() {} - static final VarHandle const$0 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("timeout")); - static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("data")); - static final StructLayout const$2 = MemoryLayout.structLayout( - JAVA_INT.withName("ep"), - JAVA_INT.withName("len"), - JAVA_INT.withName("timeout"), - MemoryLayout.paddingLayout(4), - RuntimeHelper.POINTER.withName("data") - ).withName("usbdevfs_bulktransfer"); - static final VarHandle const$3 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("ep")); - static final VarHandle const$4 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("len")); - static final VarHandle const$5 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("timeout")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$2.java deleted file mode 100644 index 384a0622..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$2.java +++ /dev/null @@ -1,49 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$2 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$2() {} - static final VarHandle const$0 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("data")); - static final StructLayout const$1 = MemoryLayout.structLayout( - JAVA_INT.withName("interface"), - JAVA_INT.withName("altsetting") - ).withName("usbdevfs_setinterface"); - static final VarHandle const$2 = constants$2.const$1.varHandle(MemoryLayout.PathElement.groupElement("interface")); - static final VarHandle const$3 = constants$2.const$1.varHandle(MemoryLayout.PathElement.groupElement("altsetting")); - static final StructLayout const$4 = MemoryLayout.structLayout( - JAVA_BYTE.withName("type"), - JAVA_BYTE.withName("endpoint"), - MemoryLayout.paddingLayout(2), - JAVA_INT.withName("status"), - JAVA_INT.withName("flags"), - MemoryLayout.paddingLayout(4), - RuntimeHelper.POINTER.withName("buffer"), - JAVA_INT.withName("buffer_length"), - JAVA_INT.withName("actual_length"), - JAVA_INT.withName("start_frame"), - MemoryLayout.unionLayout( - JAVA_INT.withName("number_of_packets"), - JAVA_INT.withName("stream_id") - ).withName("$anon$0"), - JAVA_INT.withName("error_count"), - JAVA_INT.withName("signr"), - RuntimeHelper.POINTER.withName("usercontext"), - MemoryLayout.sequenceLayout(0, MemoryLayout.structLayout( - JAVA_INT.withName("length"), - JAVA_INT.withName("actual_length"), - JAVA_INT.withName("status") - ).withName("usbdevfs_iso_packet_desc")).withName("iso_frame_desc") - ).withName("usbdevfs_urb"); - static final VarHandle const$5 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("type")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$3.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$3.java deleted file mode 100644 index 2f58300d..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$3.java +++ /dev/null @@ -1,19 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.VarHandle; -final class constants$3 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$3() {} - static final VarHandle const$0 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("endpoint")); - static final VarHandle const$1 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("status")); - static final VarHandle const$2 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("flags")); - static final VarHandle const$3 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("buffer")); - static final VarHandle const$4 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("buffer_length")); - static final VarHandle const$5 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("actual_length")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$4.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$4.java deleted file mode 100644 index dd410c61..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$4.java +++ /dev/null @@ -1,19 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.VarHandle; -final class constants$4 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$4() {} - static final VarHandle const$0 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("start_frame")); - static final VarHandle const$1 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("number_of_packets")); - static final VarHandle const$2 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("stream_id")); - static final VarHandle const$3 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("error_count")); - static final VarHandle const$4 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("signr")); - static final VarHandle const$5 = constants$2.const$4.varHandle(MemoryLayout.PathElement.groupElement("usercontext")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$5.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$5.java deleted file mode 100644 index fedeaec6..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$5.java +++ /dev/null @@ -1,31 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$5 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$5() {} - static final StructLayout const$0 = MemoryLayout.structLayout( - JAVA_INT.withName("ifno"), - JAVA_INT.withName("ioctl_code"), - RuntimeHelper.POINTER.withName("data") - ).withName("usbdevfs_ioctl"); - static final VarHandle const$1 = constants$5.const$0.varHandle(MemoryLayout.PathElement.groupElement("ifno")); - static final VarHandle const$2 = constants$5.const$0.varHandle(MemoryLayout.PathElement.groupElement("ioctl_code")); - static final VarHandle const$3 = constants$5.const$0.varHandle(MemoryLayout.PathElement.groupElement("data")); - static final StructLayout const$4 = MemoryLayout.structLayout( - JAVA_INT.withName("interface"), - JAVA_INT.withName("flags"), - MemoryLayout.sequenceLayout(256, JAVA_BYTE).withName("driver") - ).withName("usbdevfs_disconnect_claim"); - static final VarHandle const$5 = constants$5.const$4.varHandle(MemoryLayout.PathElement.groupElement("interface")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$6.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$6.java deleted file mode 100644 index 787c95d8..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/constants$6.java +++ /dev/null @@ -1,14 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.usbdevice_fs; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.VarHandle; -final class constants$6 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$6() {} - static final VarHandle const$0 = constants$5.const$4.varHandle(MemoryLayout.PathElement.groupElement("flags")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java index 07aa5f5e..e97624c8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java @@ -2,140 +2,266 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; +import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfInt; + /** - * {@snippet : + * {@snippet lang=c : * struct usbdevfs_bulktransfer { * unsigned int ep; * unsigned int len; * unsigned int timeout; - * void* data; - * }; + * void *data; + * } * } */ public class usbdevfs_bulktransfer { - public static MemoryLayout $LAYOUT() { - return constants$1.const$2; + usbdevfs_bulktransfer() { + // Should not be called directly } - public static VarHandle ep$VH() { - return constants$1.const$3; + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + usbdevice_fs.C_INT.withName("ep"), + usbdevice_fs.C_INT.withName("len"), + usbdevice_fs.C_INT.withName("timeout"), + MemoryLayout.paddingLayout(4), + usbdevice_fs.C_POINTER.withName("data") + ).withName("usbdevfs_bulktransfer"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } + + private static final OfInt ep$LAYOUT = (OfInt)$LAYOUT.select(groupElement("ep")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned int ep + * } + */ + public static final OfInt ep$layout() { + return ep$LAYOUT; + } + + private static final long ep$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned int ep + * } + */ + public static final long ep$offset() { + return ep$OFFSET; + } + /** * Getter for field: - * {@snippet : - * unsigned int ep; + * {@snippet lang=c : + * unsigned int ep * } */ - public static int ep$get(MemorySegment seg) { - return (int)constants$1.const$3.get(seg); + public static int ep(MemorySegment struct) { + return struct.get(ep$LAYOUT, ep$OFFSET); } + /** * Setter for field: - * {@snippet : - * unsigned int ep; + * {@snippet lang=c : + * unsigned int ep * } */ - public static void ep$set(MemorySegment seg, int x) { - constants$1.const$3.set(seg, x); + public static void ep(MemorySegment struct, int fieldValue) { + struct.set(ep$LAYOUT, ep$OFFSET, fieldValue); } - public static int ep$get(MemorySegment seg, long index) { - return (int)constants$1.const$3.get(seg.asSlice(index*sizeof())); - } - public static void ep$set(MemorySegment seg, long index, int x) { - constants$1.const$3.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt len$LAYOUT = (OfInt)$LAYOUT.select(groupElement("len")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned int len + * } + */ + public static final OfInt len$layout() { + return len$LAYOUT; } - public static VarHandle len$VH() { - return constants$1.const$4; + + private static final long len$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned int len + * } + */ + public static final long len$offset() { + return len$OFFSET; } + /** * Getter for field: - * {@snippet : - * unsigned int len; + * {@snippet lang=c : + * unsigned int len * } */ - public static int len$get(MemorySegment seg) { - return (int)constants$1.const$4.get(seg); + public static int len(MemorySegment struct) { + return struct.get(len$LAYOUT, len$OFFSET); } + /** * Setter for field: - * {@snippet : - * unsigned int len; + * {@snippet lang=c : + * unsigned int len * } */ - public static void len$set(MemorySegment seg, int x) { - constants$1.const$4.set(seg, x); + public static void len(MemorySegment struct, int fieldValue) { + struct.set(len$LAYOUT, len$OFFSET, fieldValue); } - public static int len$get(MemorySegment seg, long index) { - return (int)constants$1.const$4.get(seg.asSlice(index*sizeof())); - } - public static void len$set(MemorySegment seg, long index, int x) { - constants$1.const$4.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt timeout$LAYOUT = (OfInt)$LAYOUT.select(groupElement("timeout")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned int timeout + * } + */ + public static final OfInt timeout$layout() { + return timeout$LAYOUT; } - public static VarHandle timeout$VH() { - return constants$1.const$5; + + private static final long timeout$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned int timeout + * } + */ + public static final long timeout$offset() { + return timeout$OFFSET; } + /** * Getter for field: - * {@snippet : - * unsigned int timeout; + * {@snippet lang=c : + * unsigned int timeout * } */ - public static int timeout$get(MemorySegment seg) { - return (int)constants$1.const$5.get(seg); + public static int timeout(MemorySegment struct) { + return struct.get(timeout$LAYOUT, timeout$OFFSET); } + /** * Setter for field: - * {@snippet : - * unsigned int timeout; + * {@snippet lang=c : + * unsigned int timeout * } */ - public static void timeout$set(MemorySegment seg, int x) { - constants$1.const$5.set(seg, x); - } - public static int timeout$get(MemorySegment seg, long index) { - return (int)constants$1.const$5.get(seg.asSlice(index*sizeof())); + public static void timeout(MemorySegment struct, int fieldValue) { + struct.set(timeout$LAYOUT, timeout$OFFSET, fieldValue); } - public static void timeout$set(MemorySegment seg, long index, int x) { - constants$1.const$5.set(seg.asSlice(index*sizeof()), x); + + private static final AddressLayout data$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("data")); + + /** + * Layout for field: + * {@snippet lang=c : + * void *data + * } + */ + public static final AddressLayout data$layout() { + return data$LAYOUT; } - public static VarHandle data$VH() { - return constants$2.const$0; + + private static final long data$OFFSET = 16; + + /** + * Offset for field: + * {@snippet lang=c : + * void *data + * } + */ + public static final long data$offset() { + return data$OFFSET; } + /** * Getter for field: - * {@snippet : - * void* data; + * {@snippet lang=c : + * void *data * } */ - public static MemorySegment data$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$2.const$0.get(seg); + public static MemorySegment data(MemorySegment struct) { + return struct.get(data$LAYOUT, data$OFFSET); } + /** * Setter for field: - * {@snippet : - * void* data; + * {@snippet lang=c : + * void *data * } */ - public static void data$set(MemorySegment seg, MemorySegment x) { - constants$2.const$0.set(seg, x); + public static void data(MemorySegment struct, MemorySegment fieldValue) { + struct.set(data$LAYOUT, data$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static MemorySegment data$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$2.const$0.get(seg.asSlice(index*sizeof())); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static void data$set(MemorySegment seg, long index, MemorySegment x) { - constants$2.const$0.set(seg.asSlice(index*sizeof()), x); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java index c32eba2f..8abc32ac 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java @@ -2,13 +2,21 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; +import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfShort; + /** - * {@snippet : + * {@snippet lang=c : * struct usbdevfs_ctrltransfer { * __u8 bRequestType; * __u8 bRequest; @@ -16,210 +24,384 @@ * __u16 wIndex; * __u16 wLength; * __u32 timeout; - * void* data; - * }; + * void *data; + * } * } */ public class usbdevfs_ctrltransfer { - public static MemoryLayout $LAYOUT() { - return constants$0.const$0; + usbdevfs_ctrltransfer() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + usbdevice_fs.C_CHAR.withName("bRequestType"), + usbdevice_fs.C_CHAR.withName("bRequest"), + usbdevice_fs.C_SHORT.withName("wValue"), + usbdevice_fs.C_SHORT.withName("wIndex"), + usbdevice_fs.C_SHORT.withName("wLength"), + usbdevice_fs.C_INT.withName("timeout"), + MemoryLayout.paddingLayout(4), + usbdevice_fs.C_POINTER.withName("data") + ).withName("usbdevfs_ctrltransfer"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } - public static VarHandle bRequestType$VH() { - return constants$0.const$1; + + private static final OfByte bRequestType$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bRequestType")); + + /** + * Layout for field: + * {@snippet lang=c : + * __u8 bRequestType + * } + */ + public static final OfByte bRequestType$layout() { + return bRequestType$LAYOUT; + } + + private static final long bRequestType$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * __u8 bRequestType + * } + */ + public static final long bRequestType$offset() { + return bRequestType$OFFSET; } + /** * Getter for field: - * {@snippet : - * __u8 bRequestType; + * {@snippet lang=c : + * __u8 bRequestType * } */ - public static byte bRequestType$get(MemorySegment seg) { - return (byte)constants$0.const$1.get(seg); + public static byte bRequestType(MemorySegment struct) { + return struct.get(bRequestType$LAYOUT, bRequestType$OFFSET); } + /** * Setter for field: - * {@snippet : - * __u8 bRequestType; + * {@snippet lang=c : + * __u8 bRequestType * } */ - public static void bRequestType$set(MemorySegment seg, byte x) { - constants$0.const$1.set(seg, x); + public static void bRequestType(MemorySegment struct, byte fieldValue) { + struct.set(bRequestType$LAYOUT, bRequestType$OFFSET, fieldValue); } - public static byte bRequestType$get(MemorySegment seg, long index) { - return (byte)constants$0.const$1.get(seg.asSlice(index*sizeof())); - } - public static void bRequestType$set(MemorySegment seg, long index, byte x) { - constants$0.const$1.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte bRequest$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bRequest")); + + /** + * Layout for field: + * {@snippet lang=c : + * __u8 bRequest + * } + */ + public static final OfByte bRequest$layout() { + return bRequest$LAYOUT; } - public static VarHandle bRequest$VH() { - return constants$0.const$2; + + private static final long bRequest$OFFSET = 1; + + /** + * Offset for field: + * {@snippet lang=c : + * __u8 bRequest + * } + */ + public static final long bRequest$offset() { + return bRequest$OFFSET; } + /** * Getter for field: - * {@snippet : - * __u8 bRequest; + * {@snippet lang=c : + * __u8 bRequest * } */ - public static byte bRequest$get(MemorySegment seg) { - return (byte)constants$0.const$2.get(seg); + public static byte bRequest(MemorySegment struct) { + return struct.get(bRequest$LAYOUT, bRequest$OFFSET); } + /** * Setter for field: - * {@snippet : - * __u8 bRequest; + * {@snippet lang=c : + * __u8 bRequest * } */ - public static void bRequest$set(MemorySegment seg, byte x) { - constants$0.const$2.set(seg, x); + public static void bRequest(MemorySegment struct, byte fieldValue) { + struct.set(bRequest$LAYOUT, bRequest$OFFSET, fieldValue); } - public static byte bRequest$get(MemorySegment seg, long index) { - return (byte)constants$0.const$2.get(seg.asSlice(index*sizeof())); - } - public static void bRequest$set(MemorySegment seg, long index, byte x) { - constants$0.const$2.set(seg.asSlice(index*sizeof()), x); + + private static final OfShort wValue$LAYOUT = (OfShort)$LAYOUT.select(groupElement("wValue")); + + /** + * Layout for field: + * {@snippet lang=c : + * __u16 wValue + * } + */ + public static final OfShort wValue$layout() { + return wValue$LAYOUT; } - public static VarHandle wValue$VH() { - return constants$0.const$3; + + private static final long wValue$OFFSET = 2; + + /** + * Offset for field: + * {@snippet lang=c : + * __u16 wValue + * } + */ + public static final long wValue$offset() { + return wValue$OFFSET; } + /** * Getter for field: - * {@snippet : - * __u16 wValue; + * {@snippet lang=c : + * __u16 wValue * } */ - public static short wValue$get(MemorySegment seg) { - return (short)constants$0.const$3.get(seg); + public static short wValue(MemorySegment struct) { + return struct.get(wValue$LAYOUT, wValue$OFFSET); } + /** * Setter for field: - * {@snippet : - * __u16 wValue; + * {@snippet lang=c : + * __u16 wValue * } */ - public static void wValue$set(MemorySegment seg, short x) { - constants$0.const$3.set(seg, x); + public static void wValue(MemorySegment struct, short fieldValue) { + struct.set(wValue$LAYOUT, wValue$OFFSET, fieldValue); } - public static short wValue$get(MemorySegment seg, long index) { - return (short)constants$0.const$3.get(seg.asSlice(index*sizeof())); - } - public static void wValue$set(MemorySegment seg, long index, short x) { - constants$0.const$3.set(seg.asSlice(index*sizeof()), x); + + private static final OfShort wIndex$LAYOUT = (OfShort)$LAYOUT.select(groupElement("wIndex")); + + /** + * Layout for field: + * {@snippet lang=c : + * __u16 wIndex + * } + */ + public static final OfShort wIndex$layout() { + return wIndex$LAYOUT; } - public static VarHandle wIndex$VH() { - return constants$0.const$4; + + private static final long wIndex$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * __u16 wIndex + * } + */ + public static final long wIndex$offset() { + return wIndex$OFFSET; } + /** * Getter for field: - * {@snippet : - * __u16 wIndex; + * {@snippet lang=c : + * __u16 wIndex * } */ - public static short wIndex$get(MemorySegment seg) { - return (short)constants$0.const$4.get(seg); + public static short wIndex(MemorySegment struct) { + return struct.get(wIndex$LAYOUT, wIndex$OFFSET); } + /** * Setter for field: - * {@snippet : - * __u16 wIndex; + * {@snippet lang=c : + * __u16 wIndex * } */ - public static void wIndex$set(MemorySegment seg, short x) { - constants$0.const$4.set(seg, x); + public static void wIndex(MemorySegment struct, short fieldValue) { + struct.set(wIndex$LAYOUT, wIndex$OFFSET, fieldValue); } - public static short wIndex$get(MemorySegment seg, long index) { - return (short)constants$0.const$4.get(seg.asSlice(index*sizeof())); - } - public static void wIndex$set(MemorySegment seg, long index, short x) { - constants$0.const$4.set(seg.asSlice(index*sizeof()), x); + + private static final OfShort wLength$LAYOUT = (OfShort)$LAYOUT.select(groupElement("wLength")); + + /** + * Layout for field: + * {@snippet lang=c : + * __u16 wLength + * } + */ + public static final OfShort wLength$layout() { + return wLength$LAYOUT; } - public static VarHandle wLength$VH() { - return constants$0.const$5; + + private static final long wLength$OFFSET = 6; + + /** + * Offset for field: + * {@snippet lang=c : + * __u16 wLength + * } + */ + public static final long wLength$offset() { + return wLength$OFFSET; } + /** * Getter for field: - * {@snippet : - * __u16 wLength; + * {@snippet lang=c : + * __u16 wLength * } */ - public static short wLength$get(MemorySegment seg) { - return (short)constants$0.const$5.get(seg); + public static short wLength(MemorySegment struct) { + return struct.get(wLength$LAYOUT, wLength$OFFSET); } + /** * Setter for field: - * {@snippet : - * __u16 wLength; + * {@snippet lang=c : + * __u16 wLength * } */ - public static void wLength$set(MemorySegment seg, short x) { - constants$0.const$5.set(seg, x); - } - public static short wLength$get(MemorySegment seg, long index) { - return (short)constants$0.const$5.get(seg.asSlice(index*sizeof())); + public static void wLength(MemorySegment struct, short fieldValue) { + struct.set(wLength$LAYOUT, wLength$OFFSET, fieldValue); } - public static void wLength$set(MemorySegment seg, long index, short x) { - constants$0.const$5.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt timeout$LAYOUT = (OfInt)$LAYOUT.select(groupElement("timeout")); + + /** + * Layout for field: + * {@snippet lang=c : + * __u32 timeout + * } + */ + public static final OfInt timeout$layout() { + return timeout$LAYOUT; } - public static VarHandle timeout$VH() { - return constants$1.const$0; + + private static final long timeout$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * __u32 timeout + * } + */ + public static final long timeout$offset() { + return timeout$OFFSET; } + /** * Getter for field: - * {@snippet : - * __u32 timeout; + * {@snippet lang=c : + * __u32 timeout * } */ - public static int timeout$get(MemorySegment seg) { - return (int)constants$1.const$0.get(seg); + public static int timeout(MemorySegment struct) { + return struct.get(timeout$LAYOUT, timeout$OFFSET); } + /** * Setter for field: - * {@snippet : - * __u32 timeout; + * {@snippet lang=c : + * __u32 timeout * } */ - public static void timeout$set(MemorySegment seg, int x) { - constants$1.const$0.set(seg, x); - } - public static int timeout$get(MemorySegment seg, long index) { - return (int)constants$1.const$0.get(seg.asSlice(index*sizeof())); + public static void timeout(MemorySegment struct, int fieldValue) { + struct.set(timeout$LAYOUT, timeout$OFFSET, fieldValue); } - public static void timeout$set(MemorySegment seg, long index, int x) { - constants$1.const$0.set(seg.asSlice(index*sizeof()), x); + + private static final AddressLayout data$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("data")); + + /** + * Layout for field: + * {@snippet lang=c : + * void *data + * } + */ + public static final AddressLayout data$layout() { + return data$LAYOUT; } - public static VarHandle data$VH() { - return constants$1.const$1; + + private static final long data$OFFSET = 16; + + /** + * Offset for field: + * {@snippet lang=c : + * void *data + * } + */ + public static final long data$offset() { + return data$OFFSET; } + /** * Getter for field: - * {@snippet : - * void* data; + * {@snippet lang=c : + * void *data * } */ - public static MemorySegment data$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$1.const$1.get(seg); + public static MemorySegment data(MemorySegment struct) { + return struct.get(data$LAYOUT, data$OFFSET); } + /** * Setter for field: - * {@snippet : - * void* data; + * {@snippet lang=c : + * void *data * } */ - public static void data$set(MemorySegment seg, MemorySegment x) { - constants$1.const$1.set(seg, x); + public static void data(MemorySegment struct, MemorySegment fieldValue) { + struct.set(data$LAYOUT, data$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static MemorySegment data$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$1.const$1.get(seg.asSlice(index*sizeof())); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static void data$set(MemorySegment seg, long index, MemorySegment x) { - constants$1.const$1.set(seg.asSlice(index*sizeof()), x); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java index e238d86e..3569a55a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java @@ -3,87 +3,253 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SequenceLayout; import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; +import static java.lang.foreign.ValueLayout.OfInt; + /** - * {@snippet : + * {@snippet lang=c : * struct usbdevfs_disconnect_claim { * unsigned int interface; * unsigned int flags; * char driver[256]; - * }; + * } * } */ public class usbdevfs_disconnect_claim { - public static MemoryLayout $LAYOUT() { - return constants$5.const$4; + usbdevfs_disconnect_claim() { + // Should not be called directly } - public static VarHandle interface_$VH() { - return constants$5.const$5; + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + usbdevice_fs.C_INT.withName("interface"), + usbdevice_fs.C_INT.withName("flags"), + MemoryLayout.sequenceLayout(256, usbdevice_fs.C_CHAR).withName("driver") + ).withName("usbdevfs_disconnect_claim"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } + + private static final OfInt interface_$LAYOUT = (OfInt)$LAYOUT.select(groupElement("interface")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned int interface + * } + */ + public static final OfInt interface_$layout() { + return interface_$LAYOUT; + } + + private static final long interface_$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned int interface + * } + */ + public static final long interface_$offset() { + return interface_$OFFSET; + } + /** * Getter for field: - * {@snippet : - * unsigned int interface; + * {@snippet lang=c : + * unsigned int interface * } */ - public static int interface_$get(MemorySegment seg) { - return (int)constants$5.const$5.get(seg); + public static int interface_(MemorySegment struct) { + return struct.get(interface_$LAYOUT, interface_$OFFSET); } + /** * Setter for field: - * {@snippet : - * unsigned int interface; + * {@snippet lang=c : + * unsigned int interface + * } + */ + public static void interface_(MemorySegment struct, int fieldValue) { + struct.set(interface_$LAYOUT, interface_$OFFSET, fieldValue); + } + + private static final OfInt flags$LAYOUT = (OfInt)$LAYOUT.select(groupElement("flags")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned int flags * } */ - public static void interface_$set(MemorySegment seg, int x) { - constants$5.const$5.set(seg, x); + public static final OfInt flags$layout() { + return flags$LAYOUT; } - public static int interface_$get(MemorySegment seg, long index) { - return (int)constants$5.const$5.get(seg.asSlice(index*sizeof())); + + private static final long flags$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned int flags + * } + */ + public static final long flags$offset() { + return flags$OFFSET; } - public static void interface_$set(MemorySegment seg, long index, int x) { - constants$5.const$5.set(seg.asSlice(index*sizeof()), x); + + /** + * Getter for field: + * {@snippet lang=c : + * unsigned int flags + * } + */ + public static int flags(MemorySegment struct) { + return struct.get(flags$LAYOUT, flags$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * unsigned int flags + * } + */ + public static void flags(MemorySegment struct, int fieldValue) { + struct.set(flags$LAYOUT, flags$OFFSET, fieldValue); + } + + private static final SequenceLayout driver$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("driver")); + + /** + * Layout for field: + * {@snippet lang=c : + * char driver[256] + * } + */ + public static final SequenceLayout driver$layout() { + return driver$LAYOUT; } - public static VarHandle flags$VH() { - return constants$6.const$0; + + private static final long driver$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * char driver[256] + * } + */ + public static final long driver$offset() { + return driver$OFFSET; } + /** * Getter for field: - * {@snippet : - * unsigned int flags; + * {@snippet lang=c : + * char driver[256] * } */ - public static int flags$get(MemorySegment seg) { - return (int)constants$6.const$0.get(seg); + public static MemorySegment driver(MemorySegment struct) { + return struct.asSlice(driver$OFFSET, driver$LAYOUT.byteSize()); } + /** * Setter for field: - * {@snippet : - * unsigned int flags; + * {@snippet lang=c : + * char driver[256] + * } + */ + public static void driver(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, driver$OFFSET, driver$LAYOUT.byteSize()); + } + + private static long[] driver$DIMS = { 256 }; + + /** + * Dimensions for array field: + * {@snippet lang=c : + * char driver[256] + * } + */ + public static long[] driver$dimensions() { + return driver$DIMS; + } + private static final VarHandle driver$ELEM_HANDLE = driver$LAYOUT.varHandle(sequenceElement()); + + /** + * Indexed getter for field: + * {@snippet lang=c : + * char driver[256] + * } + */ + public static byte driver(MemorySegment struct, long index0) { + return (byte)driver$ELEM_HANDLE.get(struct, 0L, index0); + } + + /** + * Indexed setter for field: + * {@snippet lang=c : + * char driver[256] * } */ - public static void flags$set(MemorySegment seg, int x) { - constants$6.const$0.set(seg, x); + public static void driver(MemorySegment struct, long index0, byte fieldValue) { + driver$ELEM_HANDLE.set(struct, 0L, index0, fieldValue); } - public static int flags$get(MemorySegment seg, long index) { - return (int)constants$6.const$0.get(seg.asSlice(index*sizeof())); + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); } - public static void flags$set(MemorySegment seg, long index, int x) { - constants$6.const$0.set(seg.asSlice(index*sizeof()), x); + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static MemorySegment driver$slice(MemorySegment seg) { - return seg.asSlice(8, 256); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } -} + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java index 8135f579..c85f7ef2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java @@ -2,112 +2,219 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; +import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfInt; + /** - * {@snippet : + * {@snippet lang=c : * struct usbdevfs_ioctl { * int ifno; * int ioctl_code; - * void* data; - * }; + * void *data; + * } * } */ public class usbdevfs_ioctl { - public static MemoryLayout $LAYOUT() { - return constants$5.const$0; + usbdevfs_ioctl() { + // Should not be called directly } - public static VarHandle ifno$VH() { - return constants$5.const$1; + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + usbdevice_fs.C_INT.withName("ifno"), + usbdevice_fs.C_INT.withName("ioctl_code"), + usbdevice_fs.C_POINTER.withName("data") + ).withName("usbdevfs_ioctl"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfInt ifno$LAYOUT = (OfInt)$LAYOUT.select(groupElement("ifno")); + + /** + * Layout for field: + * {@snippet lang=c : + * int ifno + * } + */ + public static final OfInt ifno$layout() { + return ifno$LAYOUT; + } + + private static final long ifno$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * int ifno + * } + */ + public static final long ifno$offset() { + return ifno$OFFSET; } + /** * Getter for field: - * {@snippet : - * int ifno; + * {@snippet lang=c : + * int ifno * } */ - public static int ifno$get(MemorySegment seg) { - return (int)constants$5.const$1.get(seg); + public static int ifno(MemorySegment struct) { + return struct.get(ifno$LAYOUT, ifno$OFFSET); } + /** * Setter for field: - * {@snippet : - * int ifno; + * {@snippet lang=c : + * int ifno * } */ - public static void ifno$set(MemorySegment seg, int x) { - constants$5.const$1.set(seg, x); - } - public static int ifno$get(MemorySegment seg, long index) { - return (int)constants$5.const$1.get(seg.asSlice(index*sizeof())); + public static void ifno(MemorySegment struct, int fieldValue) { + struct.set(ifno$LAYOUT, ifno$OFFSET, fieldValue); } - public static void ifno$set(MemorySegment seg, long index, int x) { - constants$5.const$1.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt ioctl_code$LAYOUT = (OfInt)$LAYOUT.select(groupElement("ioctl_code")); + + /** + * Layout for field: + * {@snippet lang=c : + * int ioctl_code + * } + */ + public static final OfInt ioctl_code$layout() { + return ioctl_code$LAYOUT; } - public static VarHandle ioctl_code$VH() { - return constants$5.const$2; + + private static final long ioctl_code$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * int ioctl_code + * } + */ + public static final long ioctl_code$offset() { + return ioctl_code$OFFSET; } + /** * Getter for field: - * {@snippet : - * int ioctl_code; + * {@snippet lang=c : + * int ioctl_code * } */ - public static int ioctl_code$get(MemorySegment seg) { - return (int)constants$5.const$2.get(seg); + public static int ioctl_code(MemorySegment struct) { + return struct.get(ioctl_code$LAYOUT, ioctl_code$OFFSET); } + /** * Setter for field: - * {@snippet : - * int ioctl_code; + * {@snippet lang=c : + * int ioctl_code * } */ - public static void ioctl_code$set(MemorySegment seg, int x) { - constants$5.const$2.set(seg, x); + public static void ioctl_code(MemorySegment struct, int fieldValue) { + struct.set(ioctl_code$LAYOUT, ioctl_code$OFFSET, fieldValue); } - public static int ioctl_code$get(MemorySegment seg, long index) { - return (int)constants$5.const$2.get(seg.asSlice(index*sizeof())); - } - public static void ioctl_code$set(MemorySegment seg, long index, int x) { - constants$5.const$2.set(seg.asSlice(index*sizeof()), x); + + private static final AddressLayout data$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("data")); + + /** + * Layout for field: + * {@snippet lang=c : + * void *data + * } + */ + public static final AddressLayout data$layout() { + return data$LAYOUT; } - public static VarHandle data$VH() { - return constants$5.const$3; + + private static final long data$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * void *data + * } + */ + public static final long data$offset() { + return data$OFFSET; } + /** * Getter for field: - * {@snippet : - * void* data; + * {@snippet lang=c : + * void *data * } */ - public static MemorySegment data$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$5.const$3.get(seg); + public static MemorySegment data(MemorySegment struct) { + return struct.get(data$LAYOUT, data$OFFSET); } + /** * Setter for field: - * {@snippet : - * void* data; + * {@snippet lang=c : + * void *data * } */ - public static void data$set(MemorySegment seg, MemorySegment x) { - constants$5.const$3.set(seg, x); + public static void data(MemorySegment struct, MemorySegment fieldValue) { + struct.set(data$LAYOUT, data$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); } - public static MemorySegment data$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$5.const$3.get(seg.asSlice(index*sizeof())); + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static void data$set(MemorySegment seg, long index, MemorySegment x) { - constants$5.const$3.set(seg.asSlice(index*sizeof()), x); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } -} + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java new file mode 100644 index 00000000..71e32fab --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java @@ -0,0 +1,219 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfInt; + +/** + * {@snippet lang=c : + * struct usbdevfs_iso_packet_desc { + * unsigned int length; + * unsigned int actual_length; + * unsigned int status; + * } + * } + */ +public class usbdevfs_iso_packet_desc { + + usbdevfs_iso_packet_desc() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + usbdevice_fs.C_INT.withName("length"), + usbdevice_fs.C_INT.withName("actual_length"), + usbdevice_fs.C_INT.withName("status") + ).withName("usbdevfs_iso_packet_desc"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfInt length$LAYOUT = (OfInt)$LAYOUT.select(groupElement("length")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned int length + * } + */ + public static final OfInt length$layout() { + return length$LAYOUT; + } + + private static final long length$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned int length + * } + */ + public static final long length$offset() { + return length$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * unsigned int length + * } + */ + public static int length(MemorySegment struct) { + return struct.get(length$LAYOUT, length$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * unsigned int length + * } + */ + public static void length(MemorySegment struct, int fieldValue) { + struct.set(length$LAYOUT, length$OFFSET, fieldValue); + } + + private static final OfInt actual_length$LAYOUT = (OfInt)$LAYOUT.select(groupElement("actual_length")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned int actual_length + * } + */ + public static final OfInt actual_length$layout() { + return actual_length$LAYOUT; + } + + private static final long actual_length$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned int actual_length + * } + */ + public static final long actual_length$offset() { + return actual_length$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * unsigned int actual_length + * } + */ + public static int actual_length(MemorySegment struct) { + return struct.get(actual_length$LAYOUT, actual_length$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * unsigned int actual_length + * } + */ + public static void actual_length(MemorySegment struct, int fieldValue) { + struct.set(actual_length$LAYOUT, actual_length$OFFSET, fieldValue); + } + + private static final OfInt status$LAYOUT = (OfInt)$LAYOUT.select(groupElement("status")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned int status + * } + */ + public static final OfInt status$layout() { + return status$LAYOUT; + } + + private static final long status$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned int status + * } + */ + public static final long status$offset() { + return status$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * unsigned int status + * } + */ + public static int status(MemorySegment struct) { + return struct.get(status$LAYOUT, status$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * unsigned int status + * } + */ + public static void status(MemorySegment struct, int fieldValue) { + struct.set(status$LAYOUT, status$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java index b9989942..d18d8f20 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java @@ -3,83 +3,171 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfInt; + /** - * {@snippet : + * {@snippet lang=c : * struct usbdevfs_setinterface { * unsigned int interface; * unsigned int altsetting; - * }; + * } * } */ public class usbdevfs_setinterface { - public static MemoryLayout $LAYOUT() { - return constants$2.const$1; + usbdevfs_setinterface() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + usbdevice_fs.C_INT.withName("interface"), + usbdevice_fs.C_INT.withName("altsetting") + ).withName("usbdevfs_setinterface"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfInt interface_$LAYOUT = (OfInt)$LAYOUT.select(groupElement("interface")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned int interface + * } + */ + public static final OfInt interface_$layout() { + return interface_$LAYOUT; } - public static VarHandle interface_$VH() { - return constants$2.const$2; + + private static final long interface_$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned int interface + * } + */ + public static final long interface_$offset() { + return interface_$OFFSET; } + /** * Getter for field: - * {@snippet : - * unsigned int interface; + * {@snippet lang=c : + * unsigned int interface * } */ - public static int interface_$get(MemorySegment seg) { - return (int)constants$2.const$2.get(seg); + public static int interface_(MemorySegment struct) { + return struct.get(interface_$LAYOUT, interface_$OFFSET); } + /** * Setter for field: - * {@snippet : - * unsigned int interface; + * {@snippet lang=c : + * unsigned int interface * } */ - public static void interface_$set(MemorySegment seg, int x) { - constants$2.const$2.set(seg, x); + public static void interface_(MemorySegment struct, int fieldValue) { + struct.set(interface_$LAYOUT, interface_$OFFSET, fieldValue); } - public static int interface_$get(MemorySegment seg, long index) { - return (int)constants$2.const$2.get(seg.asSlice(index*sizeof())); - } - public static void interface_$set(MemorySegment seg, long index, int x) { - constants$2.const$2.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt altsetting$LAYOUT = (OfInt)$LAYOUT.select(groupElement("altsetting")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned int altsetting + * } + */ + public static final OfInt altsetting$layout() { + return altsetting$LAYOUT; } - public static VarHandle altsetting$VH() { - return constants$2.const$3; + + private static final long altsetting$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned int altsetting + * } + */ + public static final long altsetting$offset() { + return altsetting$OFFSET; } + /** * Getter for field: - * {@snippet : - * unsigned int altsetting; + * {@snippet lang=c : + * unsigned int altsetting * } */ - public static int altsetting$get(MemorySegment seg) { - return (int)constants$2.const$3.get(seg); + public static int altsetting(MemorySegment struct) { + return struct.get(altsetting$LAYOUT, altsetting$OFFSET); } + /** * Setter for field: - * {@snippet : - * unsigned int altsetting; + * {@snippet lang=c : + * unsigned int altsetting * } */ - public static void altsetting$set(MemorySegment seg, int x) { - constants$2.const$3.set(seg, x); + public static void altsetting(MemorySegment struct, int fieldValue) { + struct.set(altsetting$LAYOUT, altsetting$OFFSET, fieldValue); } - public static int altsetting$get(MemorySegment seg, long index) { - return (int)constants$2.const$3.get(seg.asSlice(index*sizeof())); + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); } - public static void altsetting$set(MemorySegment seg, long index, int x) { - constants$2.const$3.set(seg.asSlice(index*sizeof()), x); + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } -} + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java index ab7fd8e6..5966585a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java @@ -2,19 +2,29 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; +import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.lang.foreign.SequenceLayout; +import java.lang.invoke.MethodHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; +import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.OfInt; + /** - * {@snippet : + * {@snippet lang=c : * struct usbdevfs_urb { * unsigned char type; * unsigned char endpoint; * int status; * unsigned int flags; - * void* buffer; + * void *buffer; * int buffer_length; * int actual_length; * int start_frame; @@ -24,373 +34,740 @@ * }; * int error_count; * unsigned int signr; - * void* usercontext; + * void *usercontext; * struct usbdevfs_iso_packet_desc iso_frame_desc[0]; - * }; + * } * } */ public class usbdevfs_urb { - public static MemoryLayout $LAYOUT() { - return constants$2.const$4; + usbdevfs_urb() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + usbdevice_fs.C_CHAR.withName("type"), + usbdevice_fs.C_CHAR.withName("endpoint"), + MemoryLayout.paddingLayout(2), + usbdevice_fs.C_INT.withName("status"), + usbdevice_fs.C_INT.withName("flags"), + MemoryLayout.paddingLayout(4), + usbdevice_fs.C_POINTER.withName("buffer"), + usbdevice_fs.C_INT.withName("buffer_length"), + usbdevice_fs.C_INT.withName("actual_length"), + usbdevice_fs.C_INT.withName("start_frame"), + MemoryLayout.unionLayout( + usbdevice_fs.C_INT.withName("number_of_packets"), + usbdevice_fs.C_INT.withName("stream_id") + ).withName("$anon$126:2"), + usbdevice_fs.C_INT.withName("error_count"), + usbdevice_fs.C_INT.withName("signr"), + usbdevice_fs.C_POINTER.withName("usercontext"), + MemoryLayout.sequenceLayout(0, usbdevfs_iso_packet_desc.layout()).withName("iso_frame_desc") + ).withName("usbdevfs_urb"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } - public static VarHandle type$VH() { - return constants$2.const$5; + + private static final OfByte type$LAYOUT = (OfByte)$LAYOUT.select(groupElement("type")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned char type + * } + */ + public static final OfByte type$layout() { + return type$LAYOUT; + } + + private static final long type$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned char type + * } + */ + public static final long type$offset() { + return type$OFFSET; } + /** * Getter for field: - * {@snippet : - * unsigned char type; + * {@snippet lang=c : + * unsigned char type * } */ - public static byte type$get(MemorySegment seg) { - return (byte)constants$2.const$5.get(seg); + public static byte type(MemorySegment struct) { + return struct.get(type$LAYOUT, type$OFFSET); } + /** * Setter for field: - * {@snippet : - * unsigned char type; + * {@snippet lang=c : + * unsigned char type * } */ - public static void type$set(MemorySegment seg, byte x) { - constants$2.const$5.set(seg, x); + public static void type(MemorySegment struct, byte fieldValue) { + struct.set(type$LAYOUT, type$OFFSET, fieldValue); } - public static byte type$get(MemorySegment seg, long index) { - return (byte)constants$2.const$5.get(seg.asSlice(index*sizeof())); - } - public static void type$set(MemorySegment seg, long index, byte x) { - constants$2.const$5.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte endpoint$LAYOUT = (OfByte)$LAYOUT.select(groupElement("endpoint")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned char endpoint + * } + */ + public static final OfByte endpoint$layout() { + return endpoint$LAYOUT; } - public static VarHandle endpoint$VH() { - return constants$3.const$0; + + private static final long endpoint$OFFSET = 1; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned char endpoint + * } + */ + public static final long endpoint$offset() { + return endpoint$OFFSET; } + /** * Getter for field: - * {@snippet : - * unsigned char endpoint; + * {@snippet lang=c : + * unsigned char endpoint * } */ - public static byte endpoint$get(MemorySegment seg) { - return (byte)constants$3.const$0.get(seg); + public static byte endpoint(MemorySegment struct) { + return struct.get(endpoint$LAYOUT, endpoint$OFFSET); } + /** * Setter for field: - * {@snippet : - * unsigned char endpoint; + * {@snippet lang=c : + * unsigned char endpoint * } */ - public static void endpoint$set(MemorySegment seg, byte x) { - constants$3.const$0.set(seg, x); + public static void endpoint(MemorySegment struct, byte fieldValue) { + struct.set(endpoint$LAYOUT, endpoint$OFFSET, fieldValue); } - public static byte endpoint$get(MemorySegment seg, long index) { - return (byte)constants$3.const$0.get(seg.asSlice(index*sizeof())); - } - public static void endpoint$set(MemorySegment seg, long index, byte x) { - constants$3.const$0.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt status$LAYOUT = (OfInt)$LAYOUT.select(groupElement("status")); + + /** + * Layout for field: + * {@snippet lang=c : + * int status + * } + */ + public static final OfInt status$layout() { + return status$LAYOUT; } - public static VarHandle status$VH() { - return constants$3.const$1; + + private static final long status$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * int status + * } + */ + public static final long status$offset() { + return status$OFFSET; } + /** * Getter for field: - * {@snippet : - * int status; + * {@snippet lang=c : + * int status * } */ - public static int status$get(MemorySegment seg) { - return (int)constants$3.const$1.get(seg); + public static int status(MemorySegment struct) { + return struct.get(status$LAYOUT, status$OFFSET); } + /** * Setter for field: - * {@snippet : - * int status; + * {@snippet lang=c : + * int status * } */ - public static void status$set(MemorySegment seg, int x) { - constants$3.const$1.set(seg, x); + public static void status(MemorySegment struct, int fieldValue) { + struct.set(status$LAYOUT, status$OFFSET, fieldValue); } - public static int status$get(MemorySegment seg, long index) { - return (int)constants$3.const$1.get(seg.asSlice(index*sizeof())); - } - public static void status$set(MemorySegment seg, long index, int x) { - constants$3.const$1.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt flags$LAYOUT = (OfInt)$LAYOUT.select(groupElement("flags")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned int flags + * } + */ + public static final OfInt flags$layout() { + return flags$LAYOUT; } - public static VarHandle flags$VH() { - return constants$3.const$2; + + private static final long flags$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned int flags + * } + */ + public static final long flags$offset() { + return flags$OFFSET; } + /** * Getter for field: - * {@snippet : - * unsigned int flags; + * {@snippet lang=c : + * unsigned int flags * } */ - public static int flags$get(MemorySegment seg) { - return (int)constants$3.const$2.get(seg); + public static int flags(MemorySegment struct) { + return struct.get(flags$LAYOUT, flags$OFFSET); } + /** * Setter for field: - * {@snippet : - * unsigned int flags; + * {@snippet lang=c : + * unsigned int flags * } */ - public static void flags$set(MemorySegment seg, int x) { - constants$3.const$2.set(seg, x); - } - public static int flags$get(MemorySegment seg, long index) { - return (int)constants$3.const$2.get(seg.asSlice(index*sizeof())); + public static void flags(MemorySegment struct, int fieldValue) { + struct.set(flags$LAYOUT, flags$OFFSET, fieldValue); } - public static void flags$set(MemorySegment seg, long index, int x) { - constants$3.const$2.set(seg.asSlice(index*sizeof()), x); + + private static final AddressLayout buffer$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("buffer")); + + /** + * Layout for field: + * {@snippet lang=c : + * void *buffer + * } + */ + public static final AddressLayout buffer$layout() { + return buffer$LAYOUT; } - public static VarHandle buffer$VH() { - return constants$3.const$3; + + private static final long buffer$OFFSET = 16; + + /** + * Offset for field: + * {@snippet lang=c : + * void *buffer + * } + */ + public static final long buffer$offset() { + return buffer$OFFSET; } + /** * Getter for field: - * {@snippet : - * void* buffer; + * {@snippet lang=c : + * void *buffer * } */ - public static MemorySegment buffer$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$3.const$3.get(seg); + public static MemorySegment buffer(MemorySegment struct) { + return struct.get(buffer$LAYOUT, buffer$OFFSET); } + /** * Setter for field: - * {@snippet : - * void* buffer; + * {@snippet lang=c : + * void *buffer * } */ - public static void buffer$set(MemorySegment seg, MemorySegment x) { - constants$3.const$3.set(seg, x); - } - public static MemorySegment buffer$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$3.const$3.get(seg.asSlice(index*sizeof())); + public static void buffer(MemorySegment struct, MemorySegment fieldValue) { + struct.set(buffer$LAYOUT, buffer$OFFSET, fieldValue); } - public static void buffer$set(MemorySegment seg, long index, MemorySegment x) { - constants$3.const$3.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt buffer_length$LAYOUT = (OfInt)$LAYOUT.select(groupElement("buffer_length")); + + /** + * Layout for field: + * {@snippet lang=c : + * int buffer_length + * } + */ + public static final OfInt buffer_length$layout() { + return buffer_length$LAYOUT; } - public static VarHandle buffer_length$VH() { - return constants$3.const$4; + + private static final long buffer_length$OFFSET = 24; + + /** + * Offset for field: + * {@snippet lang=c : + * int buffer_length + * } + */ + public static final long buffer_length$offset() { + return buffer_length$OFFSET; } + /** * Getter for field: - * {@snippet : - * int buffer_length; + * {@snippet lang=c : + * int buffer_length * } */ - public static int buffer_length$get(MemorySegment seg) { - return (int)constants$3.const$4.get(seg); + public static int buffer_length(MemorySegment struct) { + return struct.get(buffer_length$LAYOUT, buffer_length$OFFSET); } + /** * Setter for field: - * {@snippet : - * int buffer_length; + * {@snippet lang=c : + * int buffer_length * } */ - public static void buffer_length$set(MemorySegment seg, int x) { - constants$3.const$4.set(seg, x); + public static void buffer_length(MemorySegment struct, int fieldValue) { + struct.set(buffer_length$LAYOUT, buffer_length$OFFSET, fieldValue); } - public static int buffer_length$get(MemorySegment seg, long index) { - return (int)constants$3.const$4.get(seg.asSlice(index*sizeof())); - } - public static void buffer_length$set(MemorySegment seg, long index, int x) { - constants$3.const$4.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt actual_length$LAYOUT = (OfInt)$LAYOUT.select(groupElement("actual_length")); + + /** + * Layout for field: + * {@snippet lang=c : + * int actual_length + * } + */ + public static final OfInt actual_length$layout() { + return actual_length$LAYOUT; } - public static VarHandle actual_length$VH() { - return constants$3.const$5; + + private static final long actual_length$OFFSET = 28; + + /** + * Offset for field: + * {@snippet lang=c : + * int actual_length + * } + */ + public static final long actual_length$offset() { + return actual_length$OFFSET; } + /** * Getter for field: - * {@snippet : - * int actual_length; + * {@snippet lang=c : + * int actual_length * } */ - public static int actual_length$get(MemorySegment seg) { - return (int)constants$3.const$5.get(seg); + public static int actual_length(MemorySegment struct) { + return struct.get(actual_length$LAYOUT, actual_length$OFFSET); } + /** * Setter for field: - * {@snippet : - * int actual_length; + * {@snippet lang=c : + * int actual_length * } */ - public static void actual_length$set(MemorySegment seg, int x) { - constants$3.const$5.set(seg, x); + public static void actual_length(MemorySegment struct, int fieldValue) { + struct.set(actual_length$LAYOUT, actual_length$OFFSET, fieldValue); } - public static int actual_length$get(MemorySegment seg, long index) { - return (int)constants$3.const$5.get(seg.asSlice(index*sizeof())); - } - public static void actual_length$set(MemorySegment seg, long index, int x) { - constants$3.const$5.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt start_frame$LAYOUT = (OfInt)$LAYOUT.select(groupElement("start_frame")); + + /** + * Layout for field: + * {@snippet lang=c : + * int start_frame + * } + */ + public static final OfInt start_frame$layout() { + return start_frame$LAYOUT; } - public static VarHandle start_frame$VH() { - return constants$4.const$0; + + private static final long start_frame$OFFSET = 32; + + /** + * Offset for field: + * {@snippet lang=c : + * int start_frame + * } + */ + public static final long start_frame$offset() { + return start_frame$OFFSET; } + /** * Getter for field: - * {@snippet : - * int start_frame; + * {@snippet lang=c : + * int start_frame * } */ - public static int start_frame$get(MemorySegment seg) { - return (int)constants$4.const$0.get(seg); + public static int start_frame(MemorySegment struct) { + return struct.get(start_frame$LAYOUT, start_frame$OFFSET); } + /** * Setter for field: - * {@snippet : - * int start_frame; + * {@snippet lang=c : + * int start_frame * } */ - public static void start_frame$set(MemorySegment seg, int x) { - constants$4.const$0.set(seg, x); - } - public static int start_frame$get(MemorySegment seg, long index) { - return (int)constants$4.const$0.get(seg.asSlice(index*sizeof())); + public static void start_frame(MemorySegment struct, int fieldValue) { + struct.set(start_frame$LAYOUT, start_frame$OFFSET, fieldValue); } - public static void start_frame$set(MemorySegment seg, long index, int x) { - constants$4.const$0.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt number_of_packets$LAYOUT = (OfInt)$LAYOUT.select(groupElement("$anon$126:2"), groupElement("number_of_packets")); + + /** + * Layout for field: + * {@snippet lang=c : + * int number_of_packets + * } + */ + public static final OfInt number_of_packets$layout() { + return number_of_packets$LAYOUT; } - public static VarHandle number_of_packets$VH() { - return constants$4.const$1; + + private static final long number_of_packets$OFFSET = 36; + + /** + * Offset for field: + * {@snippet lang=c : + * int number_of_packets + * } + */ + public static final long number_of_packets$offset() { + return number_of_packets$OFFSET; } + /** * Getter for field: - * {@snippet : - * int number_of_packets; + * {@snippet lang=c : + * int number_of_packets * } */ - public static int number_of_packets$get(MemorySegment seg) { - return (int)constants$4.const$1.get(seg); + public static int number_of_packets(MemorySegment struct) { + return struct.get(number_of_packets$LAYOUT, number_of_packets$OFFSET); } + /** * Setter for field: - * {@snippet : - * int number_of_packets; + * {@snippet lang=c : + * int number_of_packets * } */ - public static void number_of_packets$set(MemorySegment seg, int x) { - constants$4.const$1.set(seg, x); - } - public static int number_of_packets$get(MemorySegment seg, long index) { - return (int)constants$4.const$1.get(seg.asSlice(index*sizeof())); + public static void number_of_packets(MemorySegment struct, int fieldValue) { + struct.set(number_of_packets$LAYOUT, number_of_packets$OFFSET, fieldValue); } - public static void number_of_packets$set(MemorySegment seg, long index, int x) { - constants$4.const$1.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt stream_id$LAYOUT = (OfInt)$LAYOUT.select(groupElement("$anon$126:2"), groupElement("stream_id")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned int stream_id + * } + */ + public static final OfInt stream_id$layout() { + return stream_id$LAYOUT; } - public static VarHandle stream_id$VH() { - return constants$4.const$2; + + private static final long stream_id$OFFSET = 36; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned int stream_id + * } + */ + public static final long stream_id$offset() { + return stream_id$OFFSET; } + /** * Getter for field: - * {@snippet : - * unsigned int stream_id; + * {@snippet lang=c : + * unsigned int stream_id * } */ - public static int stream_id$get(MemorySegment seg) { - return (int)constants$4.const$2.get(seg); + public static int stream_id(MemorySegment struct) { + return struct.get(stream_id$LAYOUT, stream_id$OFFSET); } + /** * Setter for field: - * {@snippet : - * unsigned int stream_id; + * {@snippet lang=c : + * unsigned int stream_id * } */ - public static void stream_id$set(MemorySegment seg, int x) { - constants$4.const$2.set(seg, x); - } - public static int stream_id$get(MemorySegment seg, long index) { - return (int)constants$4.const$2.get(seg.asSlice(index*sizeof())); + public static void stream_id(MemorySegment struct, int fieldValue) { + struct.set(stream_id$LAYOUT, stream_id$OFFSET, fieldValue); } - public static void stream_id$set(MemorySegment seg, long index, int x) { - constants$4.const$2.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt error_count$LAYOUT = (OfInt)$LAYOUT.select(groupElement("error_count")); + + /** + * Layout for field: + * {@snippet lang=c : + * int error_count + * } + */ + public static final OfInt error_count$layout() { + return error_count$LAYOUT; } - public static VarHandle error_count$VH() { - return constants$4.const$3; + + private static final long error_count$OFFSET = 40; + + /** + * Offset for field: + * {@snippet lang=c : + * int error_count + * } + */ + public static final long error_count$offset() { + return error_count$OFFSET; } + /** * Getter for field: - * {@snippet : - * int error_count; + * {@snippet lang=c : + * int error_count * } */ - public static int error_count$get(MemorySegment seg) { - return (int)constants$4.const$3.get(seg); + public static int error_count(MemorySegment struct) { + return struct.get(error_count$LAYOUT, error_count$OFFSET); } + /** * Setter for field: - * {@snippet : - * int error_count; + * {@snippet lang=c : + * int error_count * } */ - public static void error_count$set(MemorySegment seg, int x) { - constants$4.const$3.set(seg, x); - } - public static int error_count$get(MemorySegment seg, long index) { - return (int)constants$4.const$3.get(seg.asSlice(index*sizeof())); + public static void error_count(MemorySegment struct, int fieldValue) { + struct.set(error_count$LAYOUT, error_count$OFFSET, fieldValue); } - public static void error_count$set(MemorySegment seg, long index, int x) { - constants$4.const$3.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt signr$LAYOUT = (OfInt)$LAYOUT.select(groupElement("signr")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned int signr + * } + */ + public static final OfInt signr$layout() { + return signr$LAYOUT; } - public static VarHandle signr$VH() { - return constants$4.const$4; + + private static final long signr$OFFSET = 44; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned int signr + * } + */ + public static final long signr$offset() { + return signr$OFFSET; } + /** * Getter for field: - * {@snippet : - * unsigned int signr; + * {@snippet lang=c : + * unsigned int signr * } */ - public static int signr$get(MemorySegment seg) { - return (int)constants$4.const$4.get(seg); + public static int signr(MemorySegment struct) { + return struct.get(signr$LAYOUT, signr$OFFSET); } + /** * Setter for field: - * {@snippet : - * unsigned int signr; + * {@snippet lang=c : + * unsigned int signr + * } + */ + public static void signr(MemorySegment struct, int fieldValue) { + struct.set(signr$LAYOUT, signr$OFFSET, fieldValue); + } + + private static final AddressLayout usercontext$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("usercontext")); + + /** + * Layout for field: + * {@snippet lang=c : + * void *usercontext + * } + */ + public static final AddressLayout usercontext$layout() { + return usercontext$LAYOUT; + } + + private static final long usercontext$OFFSET = 48; + + /** + * Offset for field: + * {@snippet lang=c : + * void *usercontext + * } + */ + public static final long usercontext$offset() { + return usercontext$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * void *usercontext * } */ - public static void signr$set(MemorySegment seg, int x) { - constants$4.const$4.set(seg, x); + public static MemorySegment usercontext(MemorySegment struct) { + return struct.get(usercontext$LAYOUT, usercontext$OFFSET); } - public static int signr$get(MemorySegment seg, long index) { - return (int)constants$4.const$4.get(seg.asSlice(index*sizeof())); + + /** + * Setter for field: + * {@snippet lang=c : + * void *usercontext + * } + */ + public static void usercontext(MemorySegment struct, MemorySegment fieldValue) { + struct.set(usercontext$LAYOUT, usercontext$OFFSET, fieldValue); } - public static void signr$set(MemorySegment seg, long index, int x) { - constants$4.const$4.set(seg.asSlice(index*sizeof()), x); + + private static final SequenceLayout iso_frame_desc$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("iso_frame_desc")); + + /** + * Layout for field: + * {@snippet lang=c : + * struct usbdevfs_iso_packet_desc iso_frame_desc[0] + * } + */ + public static final SequenceLayout iso_frame_desc$layout() { + return iso_frame_desc$LAYOUT; } - public static VarHandle usercontext$VH() { - return constants$4.const$5; + + private static final long iso_frame_desc$OFFSET = 56; + + /** + * Offset for field: + * {@snippet lang=c : + * struct usbdevfs_iso_packet_desc iso_frame_desc[0] + * } + */ + public static final long iso_frame_desc$offset() { + return iso_frame_desc$OFFSET; } + /** * Getter for field: - * {@snippet : - * void* usercontext; + * {@snippet lang=c : + * struct usbdevfs_iso_packet_desc iso_frame_desc[0] * } */ - public static MemorySegment usercontext$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$4.const$5.get(seg); + public static MemorySegment iso_frame_desc(MemorySegment struct) { + return struct.asSlice(iso_frame_desc$OFFSET, iso_frame_desc$LAYOUT.byteSize()); } + /** * Setter for field: - * {@snippet : - * void* usercontext; + * {@snippet lang=c : + * struct usbdevfs_iso_packet_desc iso_frame_desc[0] * } */ - public static void usercontext$set(MemorySegment seg, MemorySegment x) { - constants$4.const$5.set(seg, x); + public static void iso_frame_desc(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, iso_frame_desc$OFFSET, iso_frame_desc$LAYOUT.byteSize()); } - public static MemorySegment usercontext$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$4.const$5.get(seg.asSlice(index*sizeof())); + + private static long[] iso_frame_desc$DIMS = { 0 }; + + /** + * Dimensions for array field: + * {@snippet lang=c : + * struct usbdevfs_iso_packet_desc iso_frame_desc[0] + * } + */ + public static long[] iso_frame_desc$dimensions() { + return iso_frame_desc$DIMS; } - public static void usercontext$set(MemorySegment seg, long index, MemorySegment x) { - constants$4.const$5.set(seg.asSlice(index*sizeof()), x); + private static final MethodHandle iso_frame_desc$ELEM_HANDLE = iso_frame_desc$LAYOUT.sliceHandle(sequenceElement()); + + /** + * Indexed getter for field: + * {@snippet lang=c : + * struct usbdevfs_iso_packet_desc iso_frame_desc[0] + * } + */ + public static MemorySegment iso_frame_desc(MemorySegment struct, long index0) { + try { + return (MemorySegment)iso_frame_desc$ELEM_HANDLE.invokeExact(struct, 0L, index0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Indexed setter for field: + * {@snippet lang=c : + * struct usbdevfs_iso_packet_desc iso_frame_desc[0] + * } + */ + public static void iso_frame_desc(MemorySegment struct, long index0, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, iso_frame_desc(struct, index0), 0L, usbdevfs_iso_packet_desc.layout().byteSize()); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } -} + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java index 68d05fef..e5b878ee 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java @@ -3,58 +3,106 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; -import static java.lang.foreign.ValueLayout.*; -public class usbdevice_fs { - - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfLong C_LONG = JAVA_LONG; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; + +public class usbdevice_fs { + + usbdevice_fs() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; + private static final int USBDEVFS_URB_TYPE_ISO = (int)0L; /** - * {@snippet : + * {@snippet lang=c : * #define USBDEVFS_URB_TYPE_ISO 0 * } */ public static int USBDEVFS_URB_TYPE_ISO() { - return (int)0L; + return USBDEVFS_URB_TYPE_ISO; } + private static final int USBDEVFS_URB_TYPE_INTERRUPT = (int)1L; /** - * {@snippet : + * {@snippet lang=c : * #define USBDEVFS_URB_TYPE_INTERRUPT 1 * } */ public static int USBDEVFS_URB_TYPE_INTERRUPT() { - return (int)1L; + return USBDEVFS_URB_TYPE_INTERRUPT; } + private static final int USBDEVFS_URB_TYPE_CONTROL = (int)2L; /** - * {@snippet : + * {@snippet lang=c : * #define USBDEVFS_URB_TYPE_CONTROL 2 * } */ public static int USBDEVFS_URB_TYPE_CONTROL() { - return (int)2L; + return USBDEVFS_URB_TYPE_CONTROL; } + private static final int USBDEVFS_URB_TYPE_BULK = (int)3L; /** - * {@snippet : + * {@snippet lang=c : * #define USBDEVFS_URB_TYPE_BULK 3 * } */ public static int USBDEVFS_URB_TYPE_BULK() { - return (int)3L; + return USBDEVFS_URB_TYPE_BULK; } + private static final int USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER = (int)2L; /** - * {@snippet : + * {@snippet lang=c : * #define USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER 2 * } */ public static int USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER() { - return (int)2L; + return USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER; } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java index 74459d50..1f31e70b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java @@ -35,7 +35,7 @@ private CoreFoundationHelper() { static String stringFromCFStringRef(MemorySegment string, Arena arena) { var strLen = CoreFoundation.CFStringGetLength(string); - var buffer = arena.allocateArray(JAVA_CHAR, strLen); + var buffer = arena.allocate(JAVA_CHAR, strLen); var range = CFRange.allocate(arena); CFRange.location$set(range, 0); CFRange.length$set(range, strLen); @@ -56,7 +56,7 @@ static String stringFromCFStringRef(MemorySegment string, Arena arena) { */ static MemorySegment createCFStringRef(String string, SegmentAllocator allocator) { var charArray = string.toCharArray(); - var chars = allocator.allocateArray(JAVA_CHAR, charArray.length); + var chars = allocator.allocate(JAVA_CHAR, charArray.length); chars.copyFrom(MemorySegment.ofArray(charArray)); return CoreFoundation.CFStringCreateWithCharacters(NULL, chars, string.length()); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index 22786f0b..6fd60f63 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -111,9 +111,9 @@ static MemorySegment getVtable(MemorySegment self) { static MemorySegment getInterface(int service, MemorySegment pluginType, MemorySegment interfaceId) { try (var arena = Arena.ofConfined()) { // MemorySegment for holding IOCFPlugInInterface** - var plugHolder = arena.allocate(ADDRESS, NULL); + var plugHolder = arena.allocate(ADDRESS); // MemorySegment for holding score - var score = arena.allocate(JAVA_INT, 0); + var score = arena.allocate(JAVA_INT); var ret = IOKit.IOCreatePlugInInterfaceForService(service, pluginType, kIOCFPlugInInterfaceID, plugHolder , score); if (ret != 0) @@ -123,7 +123,7 @@ static MemorySegment getInterface(int service, MemorySegment pluginType, MemoryS // UUID bytes var refiid = CoreFoundation.CFUUIDGetUUIDBytes(arena, interfaceId); // MemorySegment for holding xxxInterface** - var intfHolder = arena.allocate(ADDRESS, NULL); + var intfHolder = arena.allocate(ADDRESS); ret = IoKitUsb.QueryInterface(plug, refiid, intfHolder); IoKitUsb.Release(plug); if (ret != 0) @@ -152,7 +152,7 @@ static Integer getPropertyInt(int service, MemorySegment key, Arena arena) { Integer result = null; var type = CoreFoundation.CFGetTypeID(value); if (type == CoreFoundation.CFNumberGetTypeID()) { - var numberValue = arena.allocate(JAVA_INT, 0); + var numberValue = arena.allocate(JAVA_INT); if (CoreFoundation.CFNumberGetValue(value, CoreFoundation.kCFNumberSInt32Type(), numberValue) != 0) result = numberValue.get(JAVA_INT, 0); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java index ae672a6c..d935b68a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java @@ -7,7 +7,12 @@ package net.codecrete.usb.macos; -import net.codecrete.usb.*; +import net.codecrete.usb.UsbControlTransfer; +import net.codecrete.usb.UsbDevice; +import net.codecrete.usb.UsbDirection; +import net.codecrete.usb.UsbRecipient; +import net.codecrete.usb.UsbRequestType; +import net.codecrete.usb.UsbTransferType; import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.common.Transfer; import net.codecrete.usb.common.UsbDeviceImpl; @@ -27,7 +32,10 @@ import java.util.List; import java.util.Map; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; import static net.codecrete.usb.common.ForeignMemory.dereference; import static net.codecrete.usb.macos.MacosUsbException.throwException; @@ -434,7 +442,7 @@ public void transferOut(int endpointNumber, byte @NotNull [] data, int offset, i UsbTransferType.INTERRUPT); try (var arena = Arena.ofConfined()) { - var nativeData = arena.allocateArray(JAVA_BYTE, length); + var nativeData = arena.allocate(JAVA_BYTE, length); nativeData.copyFrom(MemorySegment.ofArray(data).asSlice(offset, length)); var transfer = new MacosTransfer(); @@ -464,7 +472,7 @@ public void transferOut(int endpointNumber, byte @NotNull [] data, int offset, i UsbTransferType.INTERRUPT); try (var arena = Arena.ofConfined()) { - var nativeData = arena.allocateArray(JAVA_BYTE, epInfo.packetSize()); + var nativeData = arena.allocate(JAVA_BYTE, epInfo.packetSize()); var transfer = new MacosTransfer(); transfer.setData(nativeData); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java index dbb2ffc5..4dd8fc2f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java @@ -13,7 +13,11 @@ import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; import net.codecrete.usb.macos.gen.iokit.IOKit; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -22,7 +26,9 @@ import static java.lang.System.Logger.Level.INFO; import static java.lang.foreign.MemorySegment.NULL; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; import static net.codecrete.usb.macos.CoreFoundationHelper.createCFStringRef; import static net.codecrete.usb.macos.MacosUsbException.throwException; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbException.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbException.java index 3f0c6070..8731c61f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbException.java @@ -32,7 +32,7 @@ public MacosUsbException(String message, int errorCode) { private static String machErrorMessage(int errorCode) { var msg = mach.mach_error_string(errorCode); - return msg.getUtf8String(0); + return msg.getString(0); } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java index 3b1c3e58..92f76e89 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java @@ -7,7 +7,18 @@ import java.lang.foreign.SegmentAllocator; import java.lang.invoke.MethodHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_FLOAT; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; +import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.OfDouble; +import static java.lang.foreign.ValueLayout.OfFloat; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfLong; +import static java.lang.foreign.ValueLayout.OfShort; public class CoreFoundation { public static final OfByte C_CHAR = JAVA_BYTE; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java index 69967de1..c3b86b90 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java @@ -1,12 +1,24 @@ package net.codecrete.usb.macos.gen.corefoundation; // Generated by jextract -import java.lang.foreign.*; +import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_LONG; final class RuntimeHelper { @@ -15,7 +27,7 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = (size, align) -> Arena.ofAuto().allocate(size, align); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java index f03e1d08..70b02ae3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java @@ -8,7 +8,18 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_FLOAT; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; +import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.OfDouble; +import static java.lang.foreign.ValueLayout.OfFloat; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfLong; +import static java.lang.foreign.ValueLayout.OfShort; public class IOKit { public static final OfByte C_CHAR = JAVA_BYTE; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java index 02d78401..e628cf84 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java @@ -1,12 +1,24 @@ package net.codecrete.usb.macos.gen.iokit; // Generated by jextract -import java.lang.foreign.*; +import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_LONG; final class RuntimeHelper { @@ -15,7 +27,7 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = (size, align) -> Arena.ofAuto().allocate(size, align); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java index 0c05b256..31a87068 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java @@ -6,7 +6,9 @@ import java.lang.foreign.StructLayout; import java.lang.invoke.VarHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$33.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$33.java index ec150123..2976d004 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$33.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$33.java @@ -7,7 +7,9 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; final class constants$33 { // Suppresses default constructor, ensuring non-instantiability. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$38.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$38.java index ce319313..e2de4fe2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$38.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$38.java @@ -7,7 +7,9 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; final class constants$38 { // Suppresses default constructor, ensuring non-instantiability. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$44.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$44.java index c074540f..34e99d5a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$44.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$44.java @@ -7,9 +7,9 @@ final class constants$44 { // Suppresses default constructor, ensuring non-instantiability. private constants$44() {} - static final MemorySegment const$0 = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("IOServiceFirstMatch"); - static final MemorySegment const$1 = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("IOServiceTerminate"); - static final MemorySegment const$2 = RuntimeHelper.CONSTANT_ALLOCATOR.allocateUtf8String("IOUSBDevice"); + static final MemorySegment const$0 = RuntimeHelper.CONSTANT_ALLOCATOR.allocateFrom("IOServiceFirstMatch"); + static final MemorySegment const$1 = RuntimeHelper.CONSTANT_ALLOCATOR.allocateFrom("IOServiceTerminate"); + static final MemorySegment const$2 = RuntimeHelper.CONSTANT_ALLOCATOR.allocateFrom("IOUSBDevice"); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java index 1f0d63c5..98adf29e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java @@ -1,12 +1,24 @@ package net.codecrete.usb.macos.gen.mach; // Generated by jextract -import java.lang.foreign.*; +import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_LONG; final class RuntimeHelper { @@ -15,7 +27,7 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = (size, align) -> Arena.ofAuto().allocate(size, align); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java index b53bd86f..589791f2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java @@ -6,7 +6,18 @@ import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_FLOAT; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; +import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.OfDouble; +import static java.lang.foreign.ValueLayout.OfFloat; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfLong; +import static java.lang.foreign.ValueLayout.OfShort; public class mach { public static final OfByte C_CHAR = JAVA_BYTE; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java index 611e76f0..5f651820 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/ConfigurationDescriptor.java @@ -9,9 +9,7 @@ import java.lang.foreign.GroupLayout; import java.lang.foreign.MemorySegment; -import java.lang.invoke.VarHandle; -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; import static java.lang.foreign.MemoryLayout.structLayout; import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_SHORT_UNALIGNED; @@ -19,7 +17,7 @@ /** * USB configuration descriptor */ -@SuppressWarnings("java:S125") +@SuppressWarnings({"java:S115", "java:S125"}) public class ConfigurationDescriptor { private final MemorySegment descriptor; @@ -29,31 +27,31 @@ public ConfigurationDescriptor(MemorySegment descriptor) { } public int descriptorType() { - return 0xff & (byte) bDescriptorType$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bDescriptorType$OFFSET); } public int totalLength() { - return 0xffff & (short) wTotalLength$VH.get(descriptor); + return 0xffff & descriptor.get(JAVA_SHORT_UNALIGNED, wTotalLength$OFFSET); } public int numInterfaces() { - return 0xff & (byte) bNumInterfaces$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bNumInterfaces$OFFSET); } public int configurationValue() { - return 0xff & (byte) bConfigurationValue$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bConfigurationValue$OFFSET); } public int iConfiguration() { - return 0xff & (byte) iConfiguration$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, iConfiguration$OFFSET); } public int attributes() { - return 0xff & (byte) bmAttributes$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bmAttributes$OFFSET); } public int maxPower() { - return 0xff & (byte) bMaxPower$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bMaxPower$OFFSET); } @@ -78,13 +76,13 @@ public int maxPower() { JAVA_BYTE.withName("bMaxPower") ); - private static final VarHandle bDescriptorType$VH = LAYOUT.varHandle(groupElement("bDescriptorType")); - private static final VarHandle wTotalLength$VH = LAYOUT.varHandle(groupElement("wTotalLength")); - private static final VarHandle bNumInterfaces$VH = LAYOUT.varHandle(groupElement("bNumInterfaces")); - private static final VarHandle bConfigurationValue$VH = LAYOUT.varHandle(groupElement("bConfigurationValue")); - private static final VarHandle iConfiguration$VH = LAYOUT.varHandle(groupElement("iConfiguration")); - private static final VarHandle bmAttributes$VH = LAYOUT.varHandle(groupElement("bmAttributes")); - private static final VarHandle bMaxPower$VH = LAYOUT.varHandle(groupElement("bMaxPower")); + private static final long bDescriptorType$OFFSET = 1; + private static final long wTotalLength$OFFSET = 2; + private static final long bNumInterfaces$OFFSET = 4; + private static final long bConfigurationValue$OFFSET = 5; + private static final long iConfiguration$OFFSET = 6; + private static final long bmAttributes$OFFSET = 7; + private static final long bMaxPower$OFFSET = 8; static { assert LAYOUT.byteSize() == 9; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java index 686e2a14..d122711d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/DeviceDescriptor.java @@ -9,9 +9,7 @@ import java.lang.foreign.GroupLayout; import java.lang.foreign.MemorySegment; -import java.lang.invoke.VarHandle; -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; import static java.lang.foreign.MemoryLayout.structLayout; import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_SHORT_UNALIGNED; @@ -19,7 +17,7 @@ /** * USB device descriptor */ -@SuppressWarnings("java:S125") +@SuppressWarnings({"java:S115", "java:S125"}) public class DeviceDescriptor { private final MemorySegment descriptor; @@ -29,43 +27,43 @@ public DeviceDescriptor(MemorySegment descriptor) { } public int usbVersion() { - return 0xffff & (short) bcdUSB$VH.get(descriptor); + return 0xffff & descriptor.get(JAVA_SHORT_UNALIGNED, bcdUSB$OFFSET); } public int deviceClass() { - return 0xff & (byte) bDeviceClass$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bDeviceClass$OFFSET); } public int deviceSubClass() { - return 0xff & (byte) bDeviceSubClass$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bDeviceSubClass$OFFSET); } public int deviceProtocol() { - return 0xff & (byte) bDeviceProtocol$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bDeviceProtocol$OFFSET); } public int vendorID() { - return 0xffff & (short) idVendor$VH.get(descriptor); + return 0xffff & descriptor.get(JAVA_SHORT_UNALIGNED, idVendor$OFFSET); } public int productID() { - return 0xffff & (short) idProduct$VH.get(descriptor); + return 0xffff & descriptor.get(JAVA_SHORT_UNALIGNED, idProduct$OFFSET); } public int deviceVersion() { - return 0xffff & (short) bcdDevice$VH.get(descriptor); + return 0xffff & descriptor.get(JAVA_SHORT_UNALIGNED, bcdDevice$OFFSET); } public int iManufacturer() { - return 0xffff & (short) iManufacturer$VH.get(descriptor); + return 0xffff & descriptor.get(JAVA_SHORT_UNALIGNED, iManufacturer$OFFSET); } public int iProduct() { - return 0xffff & (short) iProduct$VH.get(descriptor); + return 0xffff & descriptor.get(JAVA_SHORT_UNALIGNED, iProduct$OFFSET); } public int iSerialNumber() { - return 0xffff & (short) iSerialNumber$VH.get(descriptor); + return 0xffff & descriptor.get(JAVA_SHORT_UNALIGNED, iSerialNumber$OFFSET); } // struct USBDeviceDescriptor { @@ -101,16 +99,16 @@ public int iSerialNumber() { JAVA_BYTE.withName("bNumConfigurations") ); - private static final VarHandle bcdUSB$VH = LAYOUT.varHandle(groupElement("bcdUSB")); - private static final VarHandle bDeviceClass$VH = LAYOUT.varHandle(groupElement("bDeviceClass")); - private static final VarHandle bDeviceSubClass$VH = LAYOUT.varHandle(groupElement("bDeviceSubClass")); - private static final VarHandle bDeviceProtocol$VH = LAYOUT.varHandle(groupElement("bDeviceProtocol")); - private static final VarHandle idVendor$VH = LAYOUT.varHandle(groupElement("idVendor")); - private static final VarHandle idProduct$VH = LAYOUT.varHandle(groupElement("idProduct")); - private static final VarHandle bcdDevice$VH = LAYOUT.varHandle(groupElement("bcdDevice")); - private static final VarHandle iManufacturer$VH = LAYOUT.varHandle(groupElement("iManufacturer")); - private static final VarHandle iProduct$VH = LAYOUT.varHandle(groupElement("iProduct")); - private static final VarHandle iSerialNumber$VH = LAYOUT.varHandle(groupElement("iSerialNumber")); + private static final long bcdUSB$OFFSET = 2; + private static final long bDeviceClass$OFFSET = 4; + private static final long bDeviceSubClass$OFFSET = 5; + private static final long bDeviceProtocol$OFFSET = 6; + private static final long idVendor$OFFSET = 8; + private static final long idProduct$OFFSET = 10; + private static final long bcdDevice$OFFSET = 12; + private static final long iManufacturer$OFFSET = 14; + private static final long iProduct$OFFSET = 15; + private static final long iSerialNumber$OFFSET = 16; static { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java index a6d5516c..c45c3179 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/EndpointDescriptor.java @@ -9,9 +9,7 @@ import java.lang.foreign.GroupLayout; import java.lang.foreign.MemorySegment; -import java.lang.invoke.VarHandle; -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; import static java.lang.foreign.MemoryLayout.structLayout; import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_SHORT_UNALIGNED; @@ -19,7 +17,7 @@ /** * USB endpoint descriptor */ -@SuppressWarnings("java:S125") +@SuppressWarnings({"java:S115", "java:S125"}) public class EndpointDescriptor { private final MemorySegment descriptor; @@ -33,19 +31,19 @@ public EndpointDescriptor(MemorySegment segment, long offset) { } public int endpointAddress() { - return 0xff & (byte) bEndpointAddress$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bEndpointAddress$OFFSET); } public int attributes() { - return 0xff & (byte) bmAttributes$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bmAttributes$OFFSET); } public int maxPacketSize() { - return 0xffff & (short) wMaxPacketSize$VH.get(descriptor); + return 0xffff & descriptor.get(JAVA_SHORT_UNALIGNED, wMaxPacketSize$OFFSET); } public int interval() { - return 0xff & (byte) bInterval$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bInterval$OFFSET); } // struct USBEndpointDescriptor { @@ -65,10 +63,10 @@ public int interval() { JAVA_BYTE.withName("bInterval") ); - private static final VarHandle bEndpointAddress$VH = LAYOUT.varHandle(groupElement("bEndpointAddress")); - private static final VarHandle bmAttributes$VH = LAYOUT.varHandle(groupElement("bmAttributes")); - private static final VarHandle wMaxPacketSize$VH = LAYOUT.varHandle(groupElement("wMaxPacketSize")); - private static final VarHandle bInterval$VH = LAYOUT.varHandle(groupElement("bInterval")); + private static final long bEndpointAddress$OFFSET = 2; + private static final long bmAttributes$OFFSET = 3; + private static final long wMaxPacketSize$OFFSET = 4; + private static final long bInterval$OFFSET = 6; static { assert LAYOUT.byteSize() == 7; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java index e5f343f8..b2b14350 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceAssociationDescriptor.java @@ -9,16 +9,14 @@ import java.lang.foreign.GroupLayout; import java.lang.foreign.MemorySegment; -import java.lang.invoke.VarHandle; -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; import static java.lang.foreign.MemoryLayout.structLayout; import static java.lang.foreign.ValueLayout.JAVA_BYTE; /** * USB interface association descriptor (IAD) */ -@SuppressWarnings("java:S125") +@SuppressWarnings({"java:S115", "java:S125"}) public class InterfaceAssociationDescriptor { private final MemorySegment descriptor; @@ -32,27 +30,27 @@ public InterfaceAssociationDescriptor(MemorySegment segment, long offset) { } public int firstInterface() { - return 0xff & (byte) bFirstInterface$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bFirstInterface$OFFSET); } public int interfaceCount() { - return 0xff & (byte) bInterfaceCount$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bInterfaceCount$OFFSET); } public int functionClass() { - return 0xff & (byte) bFunctionClass$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bFunctionClass$OFFSET); } public int functionSubClass() { - return 0xff & (byte) bFunctionSubClass$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bFunctionSubClass$OFFSET); } public int functionProtocol() { - return 0xff & (byte) bFunctionProtocol$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bFunctionProtocol$OFFSET); } public int function() { - return 0xff & (byte) iFunction$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, iFunction$OFFSET); } // struct USBInterfaceAssociationDescriptor { @@ -76,12 +74,12 @@ public int function() { JAVA_BYTE.withName("iFunction") ); - private static final VarHandle bFirstInterface$VH = LAYOUT.varHandle(groupElement("bFirstInterface")); - private static final VarHandle bInterfaceCount$VH = LAYOUT.varHandle(groupElement("bInterfaceCount")); - private static final VarHandle bFunctionClass$VH = LAYOUT.varHandle(groupElement("bFunctionClass")); - private static final VarHandle bFunctionSubClass$VH = LAYOUT.varHandle(groupElement("bFunctionSubClass")); - private static final VarHandle bFunctionProtocol$VH = LAYOUT.varHandle(groupElement("bFunctionProtocol")); - private static final VarHandle iFunction$VH = LAYOUT.varHandle(groupElement("iFunction")); + private static final long bFirstInterface$OFFSET = 2; + private static final long bInterfaceCount$OFFSET = 3; + private static final long bFunctionClass$OFFSET = 4; + private static final long bFunctionSubClass$OFFSET = 5; + private static final long bFunctionProtocol$OFFSET = 6; + private static final long iFunction$OFFSET = 7; static { assert LAYOUT.byteSize() == 8; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java index faf0032b..27351670 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/InterfaceDescriptor.java @@ -9,16 +9,14 @@ import java.lang.foreign.GroupLayout; import java.lang.foreign.MemorySegment; -import java.lang.invoke.VarHandle; -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; import static java.lang.foreign.MemoryLayout.structLayout; import static java.lang.foreign.ValueLayout.JAVA_BYTE; /** * USB interface descriptor */ -@SuppressWarnings("java:S125") +@SuppressWarnings({"java:S115", "java:S125"}) public class InterfaceDescriptor { private final MemorySegment descriptor; @@ -32,31 +30,31 @@ public InterfaceDescriptor(MemorySegment segment, long offset) { } public int interfaceNumber() { - return 0xff & (byte) bInterfaceNumber$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bInterfaceNumber$OFFSET); } public int alternateSetting() { - return 0xff & (byte) bAlternateSetting$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bAlternateSetting$OFFSET); } public int numEndpoints() { - return 0xff & (byte) bNumEndpoints$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bNumEndpoints$OFFSET); } public int interfaceClass() { - return 0xff & (byte) bInterfaceClass$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bInterfaceClass$OFFSET); } public int interfaceSubClass() { - return 0xff & (byte) bInterfaceSubClass$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bInterfaceSubClass$OFFSET); } public int interfaceProtocol() { - return 0xff & (byte) bInterfaceProtocol$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bInterfaceProtocol$OFFSET); } public int iInterface() { - return 0xff & (byte) iInterface$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, iInterface$OFFSET); } // struct USBInterfaceDescriptor { @@ -82,13 +80,13 @@ public int iInterface() { JAVA_BYTE.withName("iInterface") ); - private static final VarHandle bInterfaceNumber$VH = LAYOUT.varHandle(groupElement("bInterfaceNumber")); - private static final VarHandle bAlternateSetting$VH = LAYOUT.varHandle(groupElement("bAlternateSetting")); - private static final VarHandle bNumEndpoints$VH = LAYOUT.varHandle(groupElement("bNumEndpoints")); - private static final VarHandle bInterfaceClass$VH = LAYOUT.varHandle(groupElement("bInterfaceClass")); - private static final VarHandle bInterfaceSubClass$VH = LAYOUT.varHandle(groupElement("bInterfaceSubClass")); - private static final VarHandle bInterfaceProtocol$VH = LAYOUT.varHandle(groupElement("bInterfaceProtocol")); - private static final VarHandle iInterface$VH = LAYOUT.varHandle(groupElement("iInterface")); + private static final long bInterfaceNumber$OFFSET = 2; + private static final long bAlternateSetting$OFFSET = 3; + private static final long bNumEndpoints$OFFSET = 4; + private static final long bInterfaceClass$OFFSET = 5; + private static final long bInterfaceSubClass$OFFSET = 6; + private static final long bInterfaceProtocol$OFFSET = 7; + private static final long iInterface$OFFSET = 8; static { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java index c934631b..e907d42f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/SetupPacket.java @@ -3,9 +3,7 @@ import java.lang.foreign.Arena; import java.lang.foreign.GroupLayout; import java.lang.foreign.MemorySegment; -import java.lang.invoke.VarHandle; -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; import static java.lang.foreign.MemoryLayout.structLayout; import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_SHORT; @@ -13,7 +11,7 @@ /** * USB setup packet. */ -@SuppressWarnings("java:S125") +@SuppressWarnings({"java:S115", "java:S125"}) public class SetupPacket { private final MemorySegment descriptor; @@ -46,43 +44,43 @@ public MemorySegment segment() { } public int requestType() { - return 0xff & (byte) bmRequestType$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bmRequestType$OFFSET); } public void setRequestType(int requestType) { - bmRequestType$VH.set(descriptor, (byte) requestType); + descriptor.set(JAVA_BYTE, bmRequestType$OFFSET, (byte) requestType); } public int request() { - return 0xff & (byte) bRequest$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bRequest$OFFSET); } public void setRequest(int request) { - bRequest$VH.set(descriptor, (byte) request); + descriptor.set(JAVA_BYTE, bRequest$OFFSET, (byte) request); } public int value() { - return 0xffff & (short) wValue$VH.get(descriptor); + return 0xffff & descriptor.get(JAVA_SHORT, wValue$OFFSET); } public void setValue(int value) { - wValue$VH.set(descriptor, (short) value); + descriptor.set(JAVA_SHORT, wValue$OFFSET, (short) value); } public int index() { - return 0xffff & (short) wIndex$VH.get(descriptor); + return 0xffff & descriptor.get(JAVA_SHORT, wIndex$OFFSET); } public void setIndex(int index) { - wIndex$VH.set(descriptor, (short) index); + descriptor.set(JAVA_SHORT, wIndex$OFFSET, (short) index); } public int length() { - return 0xffff & (short) wLength$VH.get(descriptor); + return 0xffff & descriptor.get(JAVA_SHORT, wLength$OFFSET); } public void setLength(int length) { - wLength$VH.set(descriptor, (short) length); + descriptor.set(JAVA_SHORT, wLength$OFFSET, (short) length); } // struct USBSetupPacket { @@ -100,11 +98,11 @@ public void setLength(int length) { JAVA_SHORT.withName("wLength") ); - private static final VarHandle bmRequestType$VH = LAYOUT.varHandle(groupElement("bmRequestType")); - private static final VarHandle bRequest$VH = LAYOUT.varHandle(groupElement("bRequest")); - private static final VarHandle wValue$VH = LAYOUT.varHandle(groupElement("wValue")); - private static final VarHandle wIndex$VH = LAYOUT.varHandle(groupElement("wIndex")); - private static final VarHandle wLength$VH = LAYOUT.varHandle(groupElement("wLength")); + private static final long bmRequestType$OFFSET = 0; + private static final long bRequest$OFFSET = 1; + private static final long wValue$OFFSET = 2; + private static final long wIndex$OFFSET = 4; + private static final long wLength$OFFSET = 6; static { assert LAYOUT.byteSize() == 8; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java index 4863045f..6cd245aa 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java @@ -10,15 +10,15 @@ import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; -import java.lang.invoke.VarHandle; -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_CHAR; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; /** * USB string descriptor */ -@SuppressWarnings("java:S125") +@SuppressWarnings({"java:S115", "java:S125"}) public class StringDescriptor { private final MemorySegment descriptor; @@ -28,11 +28,11 @@ public StringDescriptor(MemorySegment descriptor) { } public int length() { - return 0xff & (byte) bLength$VH.get(descriptor); + return 0xff & descriptor.get(JAVA_BYTE, bLength$OFFSET); } public String string() { - var chars = descriptor.asSlice(string$offset, length() - 2L).toArray(JAVA_CHAR); + var chars = descriptor.asSlice(string$OFFSET, length() - 2L).toArray(JAVA_CHAR); return new String(chars); } @@ -47,6 +47,6 @@ public String string() { JAVA_SHORT.withName("string") ); - private static final VarHandle bLength$VH = LAYOUT.varHandle(groupElement("bLength")); - private static final long string$offset = LAYOUT.byteOffset(groupElement("string")); // NOSONAR + private static final long bLength$OFFSET = 0; + private static final long string$OFFSET = 2; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java index fbb62aba..f023433a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java @@ -334,7 +334,7 @@ private MemorySegment getVariableLengthProperty(MemorySegment propertyKey, int p var stringLen = (requiredSizeHolder.get(JAVA_INT, 0) + 1) / 2; // allocate buffer - var propertyValueHolder = arena.allocateArray(JAVA_CHAR, stringLen); + var propertyValueHolder = arena.allocate(JAVA_CHAR, stringLen); // get property value if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index 1bea7e6d..a9cd2476 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -9,8 +9,12 @@ import net.codecrete.usb.windows.gen.kernel32._GUID; -import java.lang.foreign.*; +import java.lang.foreign.Arena; +import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout.PathElement; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.StructLayout; +import java.lang.foreign.ValueLayout; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.List; @@ -70,7 +74,7 @@ public static boolean isInvalidHandle(MemorySegment handle) { */ public static MemorySegment createSegmentFromString(String str, Arena arena) { // allocate segment (including space for terminating null) - var segment = arena.allocateArray(ValueLayout.JAVA_CHAR, str.length() + 1L); + var segment = arena.allocate(ValueLayout.JAVA_CHAR, str.length() + 1L); // copy characters segment.copyFrom(MemorySegment.ofArray(str.toCharArray())); return segment; @@ -135,7 +139,6 @@ public static List createStringListFromSegment(MemorySegment segment) { public static MemorySegment createGUID(int data1, short data2, short data3, byte data4_0, byte data4_1, byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7) { - @SuppressWarnings("resource") var guid = Arena.global().allocate(_GUID.$LAYOUT()); setGUID(guid, data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4, data4_5, data4_6, data4_7); return guid; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java index afc66e37..ee888429 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java @@ -19,7 +19,9 @@ import java.util.Map; import static java.lang.foreign.MemorySegment.NULL; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; import static net.codecrete.usb.windows.Win.allocateErrorState; import static net.codecrete.usb.windows.WindowsUsbException.throwLastError; @@ -66,9 +68,9 @@ private void asyncCompletionTask() { try (var arena = Arena.ofConfined()) { - var overlappedHolder = arena.allocate(ADDRESS, NULL); - var numBytesHolder = arena.allocate(JAVA_INT, 0); - var completionKeyHolder = arena.allocate(JAVA_LONG, 0); + var overlappedHolder = arena.allocate(ADDRESS); + var numBytesHolder = arena.allocate(JAVA_INT); + var completionKeyHolder = arena.allocate(JAVA_LONG); var errorState = allocateErrorState(arena); while (true) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java index 28dce237..f5574a7d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java @@ -7,7 +7,11 @@ package net.codecrete.usb.windows; -import net.codecrete.usb.*; +import net.codecrete.usb.UsbControlTransfer; +import net.codecrete.usb.UsbDirection; +import net.codecrete.usb.UsbException; +import net.codecrete.usb.UsbRecipient; +import net.codecrete.usb.UsbTransferType; import net.codecrete.usb.common.Transfer; import net.codecrete.usb.common.UsbDeviceImpl; import net.codecrete.usb.usbstandard.SetupPacket; @@ -29,7 +33,9 @@ import static java.lang.System.Logger.Level.DEBUG; import static java.lang.System.Logger.Level.INFO; import static java.lang.foreign.MemorySegment.NULL; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; import static net.codecrete.usb.common.ForeignMemory.dereference; import static net.codecrete.usb.windows.DevicePropertyKey.Children; import static net.codecrete.usb.windows.DevicePropertyKey.HardwareIds; @@ -412,12 +418,13 @@ synchronized void configureForAsyncIo(UsbDirection direction, int endpointNumber try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); - var timeoutHolder = arena.allocate(JAVA_INT, 0); + var timeoutHolder = arena.allocate(JAVA_INT); if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.winusbHandle, endpoint.endpointAddress(), WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder, errorState) == 0) throwLastError(errorState, "setting timeout failed"); - var rawIoHolder = arena.allocate(JAVA_BYTE, (byte) 1); + var rawIoHolder = arena.allocate(JAVA_BYTE); + rawIoHolder.setAtIndex(JAVA_BYTE, 1, (byte) 1); if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.winusbHandle, endpoint.endpointAddress(), WinUSB.RAW_IO(), (int) rawIoHolder.byteSize(), rawIoHolder, errorState) == 0) throwLastError(errorState, "setting raw IO failed"); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java index f8e5ba6e..3dea1d97 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java @@ -20,7 +20,11 @@ import net.codecrete.usb.windows.gen.usbioctl.USBIoctl; import net.codecrete.usb.windows.gen.usbioctl._USB_DESCRIPTOR_REQUEST; import net.codecrete.usb.windows.gen.usbioctl._USB_NODE_CONNECTION_INFORMATION_EX; -import net.codecrete.usb.windows.gen.user32.*; +import net.codecrete.usb.windows.gen.user32.User32; +import net.codecrete.usb.windows.gen.user32._DEV_BROADCAST_DEVICEINTERFACE_W; +import net.codecrete.usb.windows.gen.user32._DEV_BROADCAST_HDR; +import net.codecrete.usb.windows.gen.user32.tagMSG; +import net.codecrete.usb.windows.gen.user32.tagWNDCLASSEXW; import net.codecrete.usb.windows.winsdk.Kernel32B; import net.codecrete.usb.windows.winsdk.User32B; @@ -30,13 +34,23 @@ import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import static java.lang.System.Logger.Level.INFO; import static java.lang.foreign.MemorySegment.NULL; -import static java.lang.foreign.ValueLayout.*; -import static net.codecrete.usb.usbstandard.Constants.*; -import static net.codecrete.usb.windows.DevicePropertyKey.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.PathElement; +import static net.codecrete.usb.usbstandard.Constants.CONFIGURATION_DESCRIPTOR_TYPE; +import static net.codecrete.usb.usbstandard.Constants.DEFAULT_LANGUAGE; +import static net.codecrete.usb.usbstandard.Constants.STRING_DESCRIPTOR_TYPE; +import static net.codecrete.usb.windows.DevicePropertyKey.Address; +import static net.codecrete.usb.windows.DevicePropertyKey.InstanceId; +import static net.codecrete.usb.windows.DevicePropertyKey.Parent; import static net.codecrete.usb.windows.UsbConstants.GUID_DEVINTERFACE_USB_DEVICE; import static net.codecrete.usb.windows.UsbConstants.GUID_DEVINTERFACE_USB_HUB; import static net.codecrete.usb.windows.Win.allocateErrorState; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java index 6152d8c1..41bf60ac 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java @@ -6,7 +6,18 @@ import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_FLOAT; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; +import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.OfDouble; +import static java.lang.foreign.ValueLayout.OfFloat; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfLong; +import static java.lang.foreign.ValueLayout.OfShort; public class Advapi32 { public static final OfByte C_CHAR = JAVA_BYTE; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java index 868da383..7f49ea96 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java @@ -1,12 +1,24 @@ package net.codecrete.usb.windows.gen.advapi32; // Generated by jextract -import java.lang.foreign.*; +import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_LONG; final class RuntimeHelper { @@ -15,7 +27,7 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = (size, align) -> Arena.ofAuto().allocate(size, align); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java index 4561b07f..f4755421 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -6,7 +6,18 @@ import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_FLOAT; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; +import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.OfDouble; +import static java.lang.foreign.ValueLayout.OfFloat; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfLong; +import static java.lang.foreign.ValueLayout.OfShort; public class Kernel32 { public static final OfByte C_CHAR = JAVA_BYTE; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java index 2f61c112..9e11909f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java @@ -1,12 +1,24 @@ package net.codecrete.usb.windows.gen.kernel32; // Generated by jextract -import java.lang.foreign.*; +import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_LONG; final class RuntimeHelper { @@ -15,7 +27,7 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = (size, align) -> Arena.ofAuto().allocate(size, align); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java index 18b60b9b..80a6d1ec 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java @@ -6,7 +6,10 @@ import java.lang.foreign.StructLayout; import java.lang.invoke.VarHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java index c7dbf69a..07405105 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java @@ -4,7 +4,18 @@ import java.lang.foreign.AddressLayout; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_FLOAT; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; +import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.OfDouble; +import static java.lang.foreign.ValueLayout.OfFloat; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfLong; +import static java.lang.foreign.ValueLayout.OfShort; public class NtDll { public static final OfByte C_CHAR = JAVA_BYTE; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/RuntimeHelper.java index 45bfd22b..8e26fb6a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/RuntimeHelper.java @@ -1,12 +1,24 @@ package net.codecrete.usb.windows.gen.ntdll; // Generated by jextract -import java.lang.foreign.*; +import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_LONG; final class RuntimeHelper { @@ -15,7 +27,7 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = (size, align) -> Arena.ofAuto().allocate(size, align); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java index 15bc34d0..c350c506 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java @@ -6,7 +6,18 @@ import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_FLOAT; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; +import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.OfDouble; +import static java.lang.foreign.ValueLayout.OfFloat; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfLong; +import static java.lang.foreign.ValueLayout.OfShort; public class Ole32 { public static final OfByte C_CHAR = JAVA_BYTE; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java index c58af8c4..47f1d66c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java @@ -1,12 +1,24 @@ package net.codecrete.usb.windows.gen.ole32; // Generated by jextract -import java.lang.foreign.*; +import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_LONG; final class RuntimeHelper { @@ -15,7 +27,7 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = (size, align) -> Arena.ofAuto().allocate(size, align); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java index 6a51526d..53c18558 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java @@ -1,12 +1,24 @@ package net.codecrete.usb.windows.gen.setupapi; // Generated by jextract -import java.lang.foreign.*; +import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_LONG; final class RuntimeHelper { @@ -15,7 +27,7 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = (size, align) -> Arena.ofAuto().allocate(size, align); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java index bccea11d..7e909856 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java @@ -6,7 +6,18 @@ import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_FLOAT; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; +import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.OfDouble; +import static java.lang.foreign.ValueLayout.OfFloat; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfLong; +import static java.lang.foreign.ValueLayout.OfShort; public class SetupAPI { public static final OfByte C_CHAR = JAVA_BYTE; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java index e5d398cb..0a5f6a70 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java @@ -6,7 +6,10 @@ import java.lang.foreign.StructLayout; import java.lang.invoke.VarHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java index 08aa9ba2..7c75f955 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java @@ -6,7 +6,10 @@ import java.lang.foreign.StructLayout; import java.lang.invoke.VarHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; final class constants$1 { // Suppresses default constructor, ensuring non-instantiability. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java index 099b08e3..31f89ede 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java @@ -1,12 +1,24 @@ package net.codecrete.usb.windows.gen.usbioctl; // Generated by jextract -import java.lang.foreign.*; +import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_LONG; final class RuntimeHelper { @@ -15,7 +27,7 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = (size, align) -> Arena.ofAuto().allocate(size, align); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java index 60c3662a..355093d3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java @@ -4,7 +4,18 @@ import java.lang.foreign.AddressLayout; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_FLOAT; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; +import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.OfDouble; +import static java.lang.foreign.ValueLayout.OfFloat; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfLong; +import static java.lang.foreign.ValueLayout.OfShort; public class USBIoctl { public static final OfByte C_CHAR = JAVA_BYTE; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$0.java index 45923e11..526d671f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$0.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$0.java @@ -6,7 +6,9 @@ import java.lang.foreign.StructLayout; import java.lang.invoke.VarHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; final class constants$0 { // Suppresses default constructor, ensuring non-instantiability. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$1.java index c6508243..4ecf2548 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$1.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$1.java @@ -6,7 +6,9 @@ import java.lang.foreign.StructLayout; import java.lang.invoke.VarHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; final class constants$1 { // Suppresses default constructor, ensuring non-instantiability. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java index c2ce369c..3fd0cdf5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java @@ -1,12 +1,24 @@ package net.codecrete.usb.windows.gen.user32; // Generated by jextract -import java.lang.foreign.*; +import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_LONG; final class RuntimeHelper { @@ -15,7 +27,7 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = (size, align) -> Arena.ofAuto().allocate(size, align); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java index 31903e05..6f4f3b90 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java @@ -6,7 +6,18 @@ import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_FLOAT; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; +import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.OfDouble; +import static java.lang.foreign.ValueLayout.OfFloat; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfLong; +import static java.lang.foreign.ValueLayout.OfShort; public class User32 { public static final OfByte C_CHAR = JAVA_BYTE; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$4.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$4.java index 441a40cc..cdf19c7f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$4.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$4.java @@ -7,7 +7,9 @@ import java.lang.foreign.StructLayout; import java.lang.invoke.VarHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; final class constants$4 { // Suppresses default constructor, ensuring non-instantiability. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java index c9ab3d52..9646daec 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java @@ -1,12 +1,24 @@ package net.codecrete.usb.windows.gen.winusb; // Generated by jextract -import java.lang.foreign.*; +import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_LONG; final class RuntimeHelper { @@ -15,7 +27,7 @@ final class RuntimeHelper { private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE)); + static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); final static SegmentAllocator CONSTANT_ALLOCATOR = (size, align) -> Arena.ofAuto().allocate(size, align); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java index a35ff11d..df73968f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java @@ -6,7 +6,18 @@ import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_FLOAT; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; +import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.OfDouble; +import static java.lang.foreign.ValueLayout.OfFloat; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfLong; +import static java.lang.foreign.ValueLayout.OfShort; public class WinUSB { public static final OfByte C_CHAR = JAVA_BYTE; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java index 4de451fa..f1779553 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java @@ -14,7 +14,9 @@ import java.lang.foreign.SymbolLookup; import java.lang.invoke.MethodHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; /** * Native function calls for Kernel32. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java index 05caa2f2..3d718927 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java @@ -14,7 +14,9 @@ import java.lang.foreign.SymbolLookup; import java.lang.invoke.MethodHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; /** * Native function calls for User32. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java index 940ae40e..f8d6cd8b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java @@ -15,7 +15,9 @@ import java.lang.foreign.SymbolLookup; import java.lang.invoke.MethodHandle; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT; /** * Native function calls for WinUSB. diff --git a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java index 12f05dcc..e268725c 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java @@ -13,7 +13,10 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; class AlternateInterfaceTest extends TestDeviceBase { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java index 08e80e42..582fca20 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java @@ -15,7 +15,9 @@ import java.util.Arrays; import java.util.concurrent.CompletableFuture; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; class BulkTransferTest extends TestDeviceBase { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java b/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java index ee3a0911..2117df2a 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java @@ -6,7 +6,9 @@ import java.lang.foreign.MemorySegment; -import static net.codecrete.usb.ConfigurationDescriptors.*; +import static net.codecrete.usb.ConfigurationDescriptors.COMPOSITE_LARGE; +import static net.codecrete.usb.ConfigurationDescriptors.COMPOSITE_TEST_DEVICE; +import static net.codecrete.usb.ConfigurationDescriptors.SIMPLE; import static org.assertj.core.api.Assertions.assertThatThrownBy; class ConfigurationParserTest { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java index 9d09d4eb..8a653679 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/ControlTransferTest.java @@ -11,7 +11,9 @@ import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests control transfers diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java index 801f68f1..42097c2f 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DescriptionTest.java @@ -11,7 +11,11 @@ import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Tests the interface, alternate settings and endpoint descriptions. diff --git a/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java index 69ba2938..da9b6ee1 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/DeviceLifecycleTest.java @@ -12,7 +12,10 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; class DeviceLifecycleTest { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java index 33d0b82f..1733b586 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java @@ -14,7 +14,8 @@ import java.io.IOException; import java.util.concurrent.CompletableFuture; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; class SpeedTest extends TestDeviceBase { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java b/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java index c50b04e0..12b9b6ed 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java @@ -10,7 +10,13 @@ package net.codecrete.usb.special; -import net.codecrete.usb.*; +import net.codecrete.usb.Usb; +import net.codecrete.usb.UsbControlTransfer; +import net.codecrete.usb.UsbDevice; +import net.codecrete.usb.UsbDirection; +import net.codecrete.usb.UsbException; +import net.codecrete.usb.UsbRecipient; +import net.codecrete.usb.UsbRequestType; import java.io.Closeable; import java.io.IOException; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java b/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java index fd7fdc56..cc318262 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java @@ -7,7 +7,11 @@ package net.codecrete.usb.special; -import net.codecrete.usb.*; +import net.codecrete.usb.Usb; +import net.codecrete.usb.UsbControlTransfer; +import net.codecrete.usb.UsbDevice; +import net.codecrete.usb.UsbRecipient; +import net.codecrete.usb.UsbRequestType; import java.io.IOException; @@ -21,13 +25,13 @@ public class MonitorDevices { public static void main(String[] args) throws IOException { Usb.setOnDeviceConnected((device) -> { - System.out.println(STR."Connected: \{device.toString()}"); + System.out.println("Connected: " + device.toString()); talkToTestDevice(device); }); - Usb.setOnDeviceDisconnected((device) -> System.out.println(STR."Disconnected: \{device.toString()}")); + Usb.setOnDeviceDisconnected((device) -> System.out.println("Disconnected: " + device.toString())); for (var device : Usb.getDevices()) { - System.out.println(STR."Present: \{device.toString()}"); + System.out.println("Present: " + device.toString()); talkToTestDevice(device); } System.out.println("Monitoring..."); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/USBSerialTest.java b/java-does-usb/src/test/java/net/codecrete/usb/special/USBSerial.java similarity index 92% rename from java-does-usb/src/test/java/net/codecrete/usb/special/USBSerialTest.java rename to java-does-usb/src/test/java/net/codecrete/usb/special/USBSerial.java index 04964ba0..efaaaf45 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/USBSerialTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/USBSerial.java @@ -7,7 +7,12 @@ package net.codecrete.usb.special; -import net.codecrete.usb.*; +import net.codecrete.usb.Usb; +import net.codecrete.usb.UsbControlTransfer; +import net.codecrete.usb.UsbDevice; +import net.codecrete.usb.UsbDirection; +import net.codecrete.usb.UsbRecipient; +import net.codecrete.usb.UsbRequestType; /** * Interacts with a USB CDC device (serial device) directly, without using the @@ -26,7 +31,7 @@ * apply for this test. *

*/ -public class USBSerialTest { +public class USBSerial { public static void main(String[] args) { for (var device : Usb.getDevices()) { diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java index a4ea7ee2..87a0463d 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java @@ -15,7 +15,7 @@ import java.io.IOException; import java.util.HashMap; -import static java.time.Duration.*; +import static java.time.Duration.ofSeconds; /** * Test for robustness when USB devices is unplugged during operation. From dd50175c06445cce6da7f09e2fc95d68c103144e Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 18 Feb 2024 11:28:33 +0100 Subject: [PATCH 319/433] Windows: upgrade to JDK 22 --- java-does-usb/jextract/windows/gen_win.cmd | 38 +- .../codecrete/usb/windows/DeviceInfoSet.java | 8 +- .../usb/windows/DevicePropertyKey.java | 6 +- .../java/net/codecrete/usb/windows/Win.java | 17 +- .../usb/windows/WindowsAsyncTask.java | 4 +- .../usb/windows/WindowsUsbDevice.java | 2 +- .../usb/windows/WindowsUsbDeviceRegistry.java | 28 +- .../usb/windows/gen/advapi32/Advapi32.java | 172 ++++- .../windows/gen/advapi32/RuntimeHelper.java | 239 ------ .../usb/windows/gen/advapi32/constants$0.java | 34 - .../usb/windows/gen/kernel32/GUID.java | 16 - .../usb/windows/gen/kernel32/Kernel32.java | 355 ++++++--- .../usb/windows/gen/kernel32/OVERLAPPED.java | 16 - .../windows/gen/kernel32/RuntimeHelper.java | 239 ------ .../usb/windows/gen/kernel32/_GUID.java | 295 +++++-- .../usb/windows/gen/kernel32/_OVERLAPPED.java | 366 ++++++--- .../usb/windows/gen/kernel32/constants$0.java | 41 - .../usb/windows/gen/kernel32/constants$1.java | 29 - .../usb/windows/gen/kernel32/constants$2.java | 39 - .../usb/windows/gen/ntdll/NtDll.java | 82 +- .../usb/windows/gen/ntdll/RuntimeHelper.java | 239 ------ .../usb/windows/gen/ntdll/constants$0.java | 11 - .../usb/windows/gen/ole32/Ole32.java | 120 ++- .../usb/windows/gen/ole32/RuntimeHelper.java | 239 ------ .../usb/windows/gen/ole32/constants$0.java | 23 - .../usb/windows/gen/setupapi/DEVPROPKEY.java | 16 - .../windows/gen/setupapi/RuntimeHelper.java | 239 ------ .../setupapi/SP_DEVICE_INTERFACE_DATA.java | 16 - .../SP_DEVICE_INTERFACE_DETAIL_DATA_W.java | 16 - .../windows/gen/setupapi/SP_DEVINFO_DATA.java | 16 - .../usb/windows/gen/setupapi/SetupAPI.java | 198 +++-- .../usb/windows/gen/setupapi/_DEVPROPKEY.java | 166 +++- .../usb/windows/gen/setupapi/_GUID.java | 302 ++++++++ .../setupapi/_SP_DEVICE_INTERFACE_DATA.java | 261 +++++-- .../_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java | 201 ++++- .../gen/setupapi/_SP_DEVINFO_DATA.java | 261 +++++-- .../usb/windows/gen/setupapi/constants$0.java | 43 -- .../usb/windows/gen/setupapi/constants$1.java | 39 - .../usb/windows/gen/setupapi/constants$2.java | 30 - .../windows/gen/usbioctl/RuntimeHelper.java | 239 ------ .../usb/windows/gen/usbioctl/USBIoctl.java | 87 ++- .../gen/usbioctl/USB_DESCRIPTOR_REQUEST.java | 16 - .../USB_NODE_CONNECTION_INFORMATION_EX.java | 16 - .../gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java | 591 +++++++++++--- .../gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java | 726 ++++++++++++++++++ .../usbioctl/_USB_ENDPOINT_DESCRIPTOR.java | 358 +++++++++ .../_USB_NODE_CONNECTION_INFORMATION_EX.java | 537 ++++++++++--- .../windows/gen/usbioctl/_USB_PIPE_INFO.java | 173 +++++ .../usb/windows/gen/usbioctl/constants$0.java | 40 - .../usb/windows/gen/usbioctl/constants$1.java | 59 -- .../usb/windows/gen/usbioctl/constants$2.java | 17 - .../DEV_BROADCAST_DEVICEINTERFACE_W.java | 16 - .../windows/gen/user32/DEV_BROADCAST_HDR.java | 16 - .../codecrete/usb/windows/gen/user32/MSG.java | 16 - .../usb/windows/gen/user32/RuntimeHelper.java | 239 ------ .../usb/windows/gen/user32/User32.java | 154 +++- .../usb/windows/gen/user32/WNDCLASSEXW.java | 16 - .../_DEV_BROADCAST_DEVICEINTERFACE_W.java | 339 ++++++-- .../gen/user32/_DEV_BROADCAST_HDR.java | 216 ++++-- .../usb/windows/gen/user32/_GUID.java | 302 ++++++++ .../usb/windows/gen/user32/constants$0.java | 35 - .../usb/windows/gen/user32/constants$1.java | 19 - .../usb/windows/gen/user32/constants$2.java | 35 - .../usb/windows/gen/user32/constants$3.java | 37 - .../usb/windows/gen/user32/constants$4.java | 37 - .../usb/windows/gen/user32/tagMSG.java | 360 ++++++--- .../usb/windows/gen/user32/tagPOINT.java | 173 +++++ .../windows/gen/user32/tagWNDCLASSEXW.java | 649 +++++++++++----- .../usb/windows/gen/winusb/RuntimeHelper.java | 239 ------ .../usb/windows/gen/winusb/WinUSB.java | 129 +++- .../usb/windows/gen/winusb/constants$0.java | 22 - 71 files changed, 6364 insertions(+), 4006 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/GUID.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/OVERLAPPED.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$2.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/DEVPROPKEY.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DATA.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVINFO_DATA.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_GUID.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$2.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USB_DESCRIPTOR_REQUEST.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USB_NODE_CONNECTION_INFORMATION_EX.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_ENDPOINT_DESCRIPTOR.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_PIPE_INFO.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$1.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$2.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_DEVICEINTERFACE_W.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_HDR.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/MSG.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/WNDCLASSEXW.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_GUID.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$1.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$2.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$3.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$4.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagPOINT.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index a4084d2c..752bca05 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -1,12 +1,12 @@ -set JEXTRACT=..\..\..\..\jextract\build\jextract\bin\jextract.bat +set JEXTRACT=..\..\..\..\jextract-22\bin\jextract.bat set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 -call %JEXTRACT% --source --output ../../src/main/java ^ +call %JEXTRACT% --output ../../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -I "%SDK_DIR%\um" ^ -I "%SDK_DIR%\shared" ^ -l Kernel32 ^ - --header-class-name Kernel32 ^ + --header-class-name Kernel32 ^ --target-package net.codecrete.usb.windows.gen.kernel32 ^ --include-function CloseHandle ^ --include-function GetModuleHandleW ^ @@ -32,12 +32,10 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-constant FORMAT_MESSAGE_FROM_HMODULE ^ --include-constant INFINITE ^ --include-struct _GUID ^ - --include-typedef GUID ^ --include-struct _OVERLAPPED ^ - --include-typedef OVERLAPPED ^ windows_headers.h -call %JEXTRACT% --source --output ../../src/main/java ^ +call %JEXTRACT% --output ../../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -I "%SDK_DIR%\um" ^ -I "%SDK_DIR%\shared" ^ @@ -47,13 +45,10 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-function SetupDiDestroyDeviceInfoList ^ --include-function SetupDiDeleteDeviceInterfaceData ^ --include-struct _SP_DEVINFO_DATA ^ - --include-typedef SP_DEVINFO_DATA ^ --include-struct _SP_DEVICE_INTERFACE_DATA ^ - --include-typedef SP_DEVICE_INTERFACE_DATA ^ --include-struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W ^ - --include-typedef SP_DEVICE_INTERFACE_DETAIL_DATA_W ^ --include-struct _DEVPROPKEY ^ - --include-typedef DEVPROPKEY ^ + --include-struct _GUID ^ --include-constant DIGCF_PRESENT ^ --include-constant DIGCF_DEVICEINTERFACE ^ --include-constant DEVPROP_TYPE_UINT32 ^ @@ -63,21 +58,22 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-constant DIREG_DEV ^ windows_headers.h -call %JEXTRACT% --source --output ../../src/main/java ^ +call %JEXTRACT% --output ../../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -I "%SDK_DIR%\um" ^ -I "%SDK_DIR%\shared" ^ --header-class-name USBIoctl ^ --target-package net.codecrete.usb.windows.gen.usbioctl ^ --include-struct _USB_NODE_CONNECTION_INFORMATION_EX ^ - --include-typedef USB_NODE_CONNECTION_INFORMATION_EX ^ --include-struct _USB_DESCRIPTOR_REQUEST ^ - --include-typedef USB_DESCRIPTOR_REQUEST ^ + --include-struct _USB_DEVICE_DESCRIPTOR ^ + --include-struct _USB_ENDPOINT_DESCRIPTOR ^ + --include-struct _USB_PIPE_INFO ^ --include-constant IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX ^ --include-constant IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION ^ windows_headers.h -call %JEXTRACT% --source --output ../../src/main/java ^ +call %JEXTRACT% --output ../../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -I "%SDK_DIR%\um" ^ -I "%SDK_DIR%\shared" ^ @@ -92,16 +88,14 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-constant DBT_DEVICEREMOVECOMPLETE ^ --include-constant DBT_DEVTYP_DEVICEINTERFACE ^ --include-struct tagMSG ^ - --include-typedef MSG ^ + --include-struct tagPOINT ^ --include-struct tagWNDCLASSEXW ^ - --include-typedef WNDCLASSEXW ^ --include-struct _DEV_BROADCAST_HDR ^ - --include-typedef DEV_BROADCAST_HDR ^ --include-struct _DEV_BROADCAST_DEVICEINTERFACE_W ^ - --include-typedef DEV_BROADCAST_DEVICEINTERFACE_W ^ + --include-struct _GUID ^ windows_headers.h -call %JEXTRACT% --source --output ../../src/main/java ^ +call %JEXTRACT% --output ../../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -I "%SDK_DIR%\um" ^ -I "%SDK_DIR%\shared" ^ @@ -113,7 +107,7 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-constant RAW_IO ^ windows_headers.h -call %JEXTRACT% --source --output ../../src/main/java ^ +call %JEXTRACT% --output ../../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -I "%SDK_DIR%\um" ^ -I "%SDK_DIR%\shared" ^ @@ -125,7 +119,7 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-constant KEY_READ ^ windows_headers.h -call %JEXTRACT% --source --output ../../src/main/java ^ +call %JEXTRACT% --output ../../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -I "%SDK_DIR%\um" ^ -I "%SDK_DIR%\shared" ^ @@ -135,7 +129,7 @@ call %JEXTRACT% --source --output ../../src/main/java ^ --include-function CLSIDFromString ^ windows_headers.h -call %JEXTRACT% --source --output ../../src/main/java ^ +call %JEXTRACT% --output ../../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -I "%SDK_DIR%\um" ^ -I "%SDK_DIR%\shared" ^ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java index f023433a..344753cf 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java @@ -126,7 +126,7 @@ private DeviceInfoSet(InfoSetCreator creator) { // allocate SP_DEVINFO_DATA (will receive device details) devInfoData = _SP_DEVINFO_DATA.allocate(arena); - _SP_DEVINFO_DATA.cbSize$set(devInfoData, (int) _SP_DEVINFO_DATA.$LAYOUT().byteSize()); + _SP_DEVINFO_DATA.cbSize(devInfoData, (int) _SP_DEVINFO_DATA.layout().byteSize()); } catch (Exception e) { arena.close(); @@ -154,7 +154,7 @@ private void addDevicePath(String devicePath) { // load device information into dev info set var intfData = _SP_DEVICE_INTERFACE_DATA.allocate(arena); - _SP_DEVICE_INTERFACE_DATA.cbSize$set(intfData, (int) intfData.byteSize()); + _SP_DEVICE_INTERFACE_DATA.cbSize(intfData, (int) intfData.byteSize()); var devicePathSegment = Win.createSegmentFromString(devicePath, arena); if (SetupAPI2.SetupDiOpenDeviceInterfaceW(devInfoSet, devicePathSegment, 0, intfData, errorState) == 0) throwLastError(errorState, "internal error (SetupDiOpenDeviceInterfaceW)"); @@ -360,7 +360,7 @@ static String getDevicePath(String instanceId, MemorySegment interfaceGuid) { private String getDevicePathForGuid(MemorySegment interfaceGuid) { // retrieve first element of enumeration devIntfData = _SP_DEVICE_INTERFACE_DATA.allocate(arena); - _SP_DEVICE_INTERFACE_DATA.cbSize$set(devIntfData, (int) devIntfData.byteSize()); + _SP_DEVICE_INTERFACE_DATA.cbSize(devIntfData, (int) devIntfData.byteSize()); if (SetupAPI2.SetupDiEnumDeviceInterfaces(devInfoSet, NULL, interfaceGuid, 0, devIntfData, errorState) == 0) throwLastError(errorState, "internal error (SetupDiEnumDeviceInterfaces)"); @@ -370,7 +370,7 @@ private String getDevicePathForGuid(MemorySegment interfaceGuid) { // the device path fits) final var devicePathOffset = 4; var intfDetailData = arena.allocate(4L + 260 * 2); - _SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize$set(intfDetailData, + _SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize(intfDetailData, (int) _SP_DEVICE_INTERFACE_DETAIL_DATA_W.sizeof()); if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSet, devIntfData, intfDetailData, (int) intfDetailData.byteSize(), NULL, NULL, errorState) == 0) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DevicePropertyKey.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DevicePropertyKey.java index 72b97501..18ff46e9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DevicePropertyKey.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DevicePropertyKey.java @@ -68,10 +68,10 @@ private static MemorySegment createDEVPROPKEY(int data1, short data2, short data byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7, int pid) { @SuppressWarnings("resource") - var propKey = Arena.global().allocate(_DEVPROPKEY.$LAYOUT()); - Win.setGUID(_DEVPROPKEY.fmtid$slice(propKey), data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4 + var propKey = Arena.global().allocate(_DEVPROPKEY.layout()); + Win.setGUID(_DEVPROPKEY.fmtid(propKey), data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4 , data4_5, data4_6, data4_7); - _DEVPROPKEY.pid$set(propKey, pid); + _DEVPROPKEY.pid(propKey, pid); return propKey; } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index a9cd2476..e1afdad0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -21,6 +21,7 @@ import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_CHAR; +import static java.lang.foreign.ValueLayout.JAVA_INT; /** * Windows helpers. @@ -49,7 +50,9 @@ static MemorySegment allocateErrorState(Arena arena) { * @return the error code */ public static int getLastError(MemorySegment callState) { - return (int) callState_GetLastError$VH.get(callState); + return callState.get(JAVA_INT, 0); + // TODO: revert to varhandle + // return (int) callState_GetLastError$VH.get(callState); } /** @@ -135,11 +138,11 @@ public static List createStringListFromSegment(MemorySegment segment) { * @param data4_7 Byte 7 of group 4 * @return GUID as memory segment */ - @SuppressWarnings({"java:S117", "java:S107"}) + @SuppressWarnings({"java:S117", "java:S107", "resource"}) public static MemorySegment createGUID(int data1, short data2, short data3, byte data4_0, byte data4_1, byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7) { - var guid = Arena.global().allocate(_GUID.$LAYOUT()); + var guid = Arena.global().allocate(_GUID.layout()); setGUID(guid, data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4, data4_5, data4_6, data4_7); return guid; } @@ -147,10 +150,10 @@ public static MemorySegment createGUID(int data1, short data2, short data3, byte @SuppressWarnings({"java:S117", "java:S107"}) public static void setGUID(MemorySegment guid, int data1, short data2, short data3, byte data4_0, byte data4_1, byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7) { - _GUID.Data1$set(guid, data1); - _GUID.Data2$set(guid, data2); - _GUID.Data3$set(guid, data3); - var data4 = _GUID.Data4$slice(guid); + _GUID.Data1(guid, data1); + _GUID.Data2(guid, data2); + _GUID.Data3(guid, data3); + var data4 = _GUID.Data4(guid); data4.set(JAVA_BYTE, 0, data4_0); data4.set(JAVA_BYTE, 1, data4_1); data4.set(JAVA_BYTE, 2, data4_2); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java index ee888429..8150b78a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java @@ -158,8 +158,8 @@ private synchronized void completeTransfer(long overlappedAddr) { if (transfer == null) return; - transfer.setResultCode((int) _OVERLAPPED.Internal$get(transfer.overlapped())); - transfer.setResultSize((int) _OVERLAPPED.InternalHigh$get(transfer.overlapped())); + transfer.setResultCode((int) _OVERLAPPED.Internal(transfer.overlapped())); + transfer.setResultSize((int) _OVERLAPPED.InternalHigh(transfer.overlapped())); availableOverlappedStructs.add(transfer.overlapped()); transfer.setOverlapped(null); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java index f5574a7d..c1f39869 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java @@ -424,7 +424,7 @@ synchronized void configureForAsyncIo(UsbDirection direction, int endpointNumber throwLastError(errorState, "setting timeout failed"); var rawIoHolder = arena.allocate(JAVA_BYTE); - rawIoHolder.setAtIndex(JAVA_BYTE, 1, (byte) 1); + rawIoHolder.setAtIndex(JAVA_BYTE, 0, (byte) 1); if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.winusbHandle, endpoint.endpointAddress(), WinUSB.RAW_IO(), (int) rawIoHolder.byteSize(), rawIoHolder, errorState) == 0) throwLastError(errorState, "setting raw IO failed"); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java index 3dea1d97..b6998125 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java @@ -70,7 +70,7 @@ public class WindowsUsbDeviceRegistry extends UsbDeviceRegistry { private static final System.Logger LOG = System.getLogger(WindowsUsbDeviceRegistry.class.getName()); private static final long REQUEST_DATA_OFFSET - = _USB_DESCRIPTOR_REQUEST.$LAYOUT().byteOffset(PathElement.groupElement("Data")); + = _USB_DESCRIPTOR_REQUEST.layout().byteOffset(PathElement.groupElement("Data")); @Override protected void monitorDevices() { @@ -93,10 +93,10 @@ protected void monitorDevices() { // register window class var wx = tagWNDCLASSEXW.allocate(arena); - tagWNDCLASSEXW.cbSize$set(wx, (int) wx.byteSize()); - tagWNDCLASSEXW.lpfnWndProc$set(wx, handleWindowMessageStub); - tagWNDCLASSEXW.hInstance$set(wx, instance); - tagWNDCLASSEXW.lpszClassName$set(wx, className); + tagWNDCLASSEXW.cbSize(wx, (int) wx.byteSize()); + tagWNDCLASSEXW.lpfnWndProc(wx, handleWindowMessageStub); + tagWNDCLASSEXW.hInstance(wx, instance); + tagWNDCLASSEXW.lpszClassName(wx, className); var atom = User32B.RegisterClassExW(wx, errorState); if (atom == 0) throwLastError(errorState, "internal error (RegisterClassExW)"); @@ -109,10 +109,10 @@ protected void monitorDevices() { // configure notifications var notificationFilter = _DEV_BROADCAST_DEVICEINTERFACE_W.allocate(arena); - _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size$set(notificationFilter, (int) notificationFilter.byteSize()); - _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype$set(notificationFilter, + _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size(notificationFilter, (int) notificationFilter.byteSize()); + _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype(notificationFilter, User32.DBT_DEVTYP_DEVICEINTERFACE()); - _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid$slice(notificationFilter).copyFrom(GUID_DEVINTERFACE_USB_DEVICE); + _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid(notificationFilter).copyFrom(GUID_DEVINTERFACE_USB_DEVICE); var notifyHandle = User32B.RegisterDeviceNotificationW(hwnd, notificationFilter, User32.DEVICE_NOTIFY_WINDOW_HANDLE(), errorState); @@ -206,7 +206,7 @@ private UsbDevice createDevice(String devicePath, boolean isComposite, MemorySeg // get device descriptor var connInfo = _USB_NODE_CONNECTION_INFORMATION_EX.allocate(arena); - _USB_NODE_CONNECTION_INFORMATION_EX.ConnectionIndex$set(connInfo, usbPortNum); + _USB_NODE_CONNECTION_INFORMATION_EX.ConnectionIndex(connInfo, usbPortNum); var sizeHolder = arena.allocate(JAVA_INT); var errorState = allocateErrorState(arena); if (Kernel32B.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), @@ -214,7 +214,7 @@ private UsbDevice createDevice(String devicePath, boolean isComposite, MemorySeg errorState) == 0) throwLastError(errorState, "internal error (getting device descriptor failed)"); - var descriptorSegment = _USB_NODE_CONNECTION_INFORMATION_EX.DeviceDescriptor$slice(connInfo); + var descriptorSegment = _USB_NODE_CONNECTION_INFORMATION_EX.DeviceDescriptor(connInfo); var deviceDescriptor = new DeviceDescriptor(descriptorSegment); var vendorId = deviceDescriptor.vendorID(); @@ -243,8 +243,8 @@ private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, // create descriptor requests var descriptorRequest = arena.allocate(size); - _USB_DESCRIPTOR_REQUEST.ConnectionIndex$set(descriptorRequest, usbPortNumber); - var setupPacket = new SetupPacket(_USB_DESCRIPTOR_REQUEST.SetupPacket$slice(descriptorRequest)); + _USB_DESCRIPTOR_REQUEST.ConnectionIndex(descriptorRequest, usbPortNumber); + var setupPacket = new SetupPacket(_USB_DESCRIPTOR_REQUEST.SetupPacket(descriptorRequest)); setupPacket.setRequestType(0x80); // device-to-host / type standard / recipient device setupPacket.setRequest(UsbConstants.USB_REQUEST_GET_DESCRIPTOR); setupPacket.setValue((descriptorType << 8) | index); @@ -302,11 +302,11 @@ private long handleWindowMessage(MemorySegment hWnd, int uMsg, long wParam, long // check for message related to connecting/disconnecting devices if (uMsg == User32.WM_DEVICECHANGE() && (wParam == User32.DBT_DEVICEARRIVAL() || wParam == User32.DBT_DEVICEREMOVECOMPLETE())) { var data = MemorySegment.ofAddress(lParam).reinterpret(_DEV_BROADCAST_DEVICEINTERFACE_W.sizeof()); - if (_DEV_BROADCAST_HDR.dbch_devicetype$get(data) == User32.DBT_DEVTYP_DEVICEINTERFACE()) { + if (_DEV_BROADCAST_HDR.dbch_devicetype(data) == User32.DBT_DEVTYP_DEVICEINTERFACE()) { // get device path var nameSlice = - MemorySegment.ofAddress(_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name$slice(data).address()).reinterpret(500); + MemorySegment.ofAddress(_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name(data).address()).reinterpret(500); var devicePath = Win.createStringFromSegment(nameSlice); if (wParam == User32.DBT_DEVICEARRIVAL()) onDeviceConnected(devicePath); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java index 41bf60ac..d72376d6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java @@ -3,71 +3,171 @@ package net.codecrete.usb.windows.gen.advapi32; import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_FLOAT; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -import static java.lang.foreign.ValueLayout.OfByte; -import static java.lang.foreign.ValueLayout.OfDouble; -import static java.lang.foreign.ValueLayout.OfFloat; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfLong; -import static java.lang.foreign.ValueLayout.OfShort; -public class Advapi32 { - - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfInt C_LONG = JAVA_INT; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; - public static MethodHandle RegCloseKey$MH() { - return RuntimeHelper.requireNonNull(constants$0.const$1,"RegCloseKey"); + +public class Advapi32 { + + Advapi32() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("Advapi32"), LIBRARY_ARENA) + .or(SymbolLookup.loaderLookup()) + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfInt C_LONG = ValueLayout.JAVA_INT; + public static final ValueLayout.OfDouble C_LONG_DOUBLE = ValueLayout.JAVA_DOUBLE; + + private static class RegCloseKey { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + Advapi32.C_LONG, + Advapi32.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + Advapi32.findOrThrow("RegCloseKey"), + DESC); } + /** - * {@snippet : - * LSTATUS RegCloseKey(HKEY hKey); + * Function descriptor for: + * {@snippet lang=c : + * LSTATUS RegCloseKey(HKEY hKey) + * } + */ + public static FunctionDescriptor RegCloseKey$descriptor() { + return RegCloseKey.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * LSTATUS RegCloseKey(HKEY hKey) + * } + */ + public static MethodHandle RegCloseKey$handle() { + return RegCloseKey.HANDLE; + } + /** + * {@snippet lang=c : + * LSTATUS RegCloseKey(HKEY hKey) * } */ public static int RegCloseKey(MemorySegment hKey) { - var mh$ = RegCloseKey$MH(); + var mh$ = RegCloseKey.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("RegCloseKey", hKey); + } return (int)mh$.invokeExact(hKey); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle RegQueryValueExW$MH() { - return RuntimeHelper.requireNonNull(constants$0.const$3,"RegQueryValueExW"); + + private static class RegQueryValueExW { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + Advapi32.C_LONG, + Advapi32.C_POINTER, + Advapi32.C_POINTER, + Advapi32.C_POINTER, + Advapi32.C_POINTER, + Advapi32.C_POINTER, + Advapi32.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + Advapi32.findOrThrow("RegQueryValueExW"), + DESC); } + /** - * {@snippet : - * LSTATUS RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData); + * Function descriptor for: + * {@snippet lang=c : + * LSTATUS RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) + * } + */ + public static FunctionDescriptor RegQueryValueExW$descriptor() { + return RegQueryValueExW.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * LSTATUS RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) + * } + */ + public static MethodHandle RegQueryValueExW$handle() { + return RegQueryValueExW.HANDLE; + } + /** + * {@snippet lang=c : + * LSTATUS RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) * } */ public static int RegQueryValueExW(MemorySegment hKey, MemorySegment lpValueName, MemorySegment lpReserved, MemorySegment lpType, MemorySegment lpData, MemorySegment lpcbData) { - var mh$ = RegQueryValueExW$MH(); + var mh$ = RegQueryValueExW.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("RegQueryValueExW", hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); + } return (int)mh$.invokeExact(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } + private static final int KEY_READ = (int)131097L; /** - * {@snippet : + * {@snippet lang=c : * #define KEY_READ 131097 * } */ public static int KEY_READ() { - return (int)131097L; + return KEY_READ; } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java deleted file mode 100644 index 7f49ea96..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/RuntimeHelper.java +++ /dev/null @@ -1,239 +0,0 @@ -package net.codecrete.usb.windows.gen.advapi32; -// Generated by jextract - -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_LONG; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { - System.loadLibrary("Advapi32"); - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/constants$0.java deleted file mode 100644 index ee2a9f73..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/constants$0.java +++ /dev/null @@ -1,34 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.advapi32; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER - ); - static final MethodHandle const$1 = RuntimeHelper.downcallHandle( - "RegCloseKey", - constants$0.const$0 - ); - static final FunctionDescriptor const$2 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$3 = RuntimeHelper.downcallHandle( - "RegQueryValueExW", - constants$0.const$2 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/GUID.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/GUID.java deleted file mode 100644 index 85b02bc1..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/GUID.java +++ /dev/null @@ -1,16 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.kernel32; - -/** - * {@snippet : - * typedef struct _GUID GUID; - * } - */ -public final class GUID extends _GUID { - - // Suppresses default constructor, ensuring non-instantiability. - private GUID() {} -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java index f4755421..cebfe457 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -3,247 +3,428 @@ package net.codecrete.usb.windows.gen.kernel32; import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_FLOAT; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -import static java.lang.foreign.ValueLayout.OfByte; -import static java.lang.foreign.ValueLayout.OfDouble; -import static java.lang.foreign.ValueLayout.OfFloat; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfLong; -import static java.lang.foreign.ValueLayout.OfShort; -public class Kernel32 { - - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfInt C_LONG = JAVA_INT; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; - /** - * {@snippet : + +public class Kernel32 { + + Kernel32() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("Kernel32"), LIBRARY_ARENA) + .or(SymbolLookup.loaderLookup()) + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfInt C_LONG = ValueLayout.JAVA_INT; + public static final ValueLayout.OfDouble C_LONG_DOUBLE = ValueLayout.JAVA_DOUBLE; + private static final int FILE_SHARE_READ = (int)1L; + /** + * {@snippet lang=c : * #define FILE_SHARE_READ 1 * } */ public static int FILE_SHARE_READ() { - return (int)1L; + return FILE_SHARE_READ; } + private static final int FILE_SHARE_WRITE = (int)2L; /** - * {@snippet : + * {@snippet lang=c : * #define FILE_SHARE_WRITE 2 * } */ public static int FILE_SHARE_WRITE() { - return (int)2L; + return FILE_SHARE_WRITE; } + private static final int FILE_ATTRIBUTE_NORMAL = (int)128L; /** - * {@snippet : + * {@snippet lang=c : * #define FILE_ATTRIBUTE_NORMAL 128 * } */ public static int FILE_ATTRIBUTE_NORMAL() { - return (int)128L; + return FILE_ATTRIBUTE_NORMAL; } + private static final int OPEN_EXISTING = (int)3L; /** - * {@snippet : + * {@snippet lang=c : * #define OPEN_EXISTING 3 * } */ public static int OPEN_EXISTING() { - return (int)3L; + return OPEN_EXISTING; } + private static final int FILE_FLAG_OVERLAPPED = (int)1073741824L; /** - * {@snippet : + * {@snippet lang=c : * #define FILE_FLAG_OVERLAPPED 1073741824 * } */ public static int FILE_FLAG_OVERLAPPED() { - return (int)1073741824L; + return FILE_FLAG_OVERLAPPED; } + private static final int FORMAT_MESSAGE_ALLOCATE_BUFFER = (int)256L; /** - * {@snippet : + * {@snippet lang=c : * #define FORMAT_MESSAGE_ALLOCATE_BUFFER 256 * } */ public static int FORMAT_MESSAGE_ALLOCATE_BUFFER() { - return (int)256L; + return FORMAT_MESSAGE_ALLOCATE_BUFFER; } + private static final int FORMAT_MESSAGE_IGNORE_INSERTS = (int)512L; /** - * {@snippet : + * {@snippet lang=c : * #define FORMAT_MESSAGE_IGNORE_INSERTS 512 * } */ public static int FORMAT_MESSAGE_IGNORE_INSERTS() { - return (int)512L; + return FORMAT_MESSAGE_IGNORE_INSERTS; } + private static final int FORMAT_MESSAGE_FROM_HMODULE = (int)2048L; /** - * {@snippet : + * {@snippet lang=c : * #define FORMAT_MESSAGE_FROM_HMODULE 2048 * } */ public static int FORMAT_MESSAGE_FROM_HMODULE() { - return (int)2048L; + return FORMAT_MESSAGE_FROM_HMODULE; } + private static final int FORMAT_MESSAGE_FROM_SYSTEM = (int)4096L; /** - * {@snippet : + * {@snippet lang=c : * #define FORMAT_MESSAGE_FROM_SYSTEM 4096 * } */ public static int FORMAT_MESSAGE_FROM_SYSTEM() { - return (int)4096L; + return FORMAT_MESSAGE_FROM_SYSTEM; + } + + private static class CloseHandle { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + Kernel32.C_INT, + Kernel32.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + Kernel32.findOrThrow("CloseHandle"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * BOOL CloseHandle(HANDLE hObject) + * } + */ + public static FunctionDescriptor CloseHandle$descriptor() { + return CloseHandle.DESC; } - public static MethodHandle CloseHandle$MH() { - return RuntimeHelper.requireNonNull(constants$1.const$6,"CloseHandle"); + + /** + * Downcall method handle for: + * {@snippet lang=c : + * BOOL CloseHandle(HANDLE hObject) + * } + */ + public static MethodHandle CloseHandle$handle() { + return CloseHandle.HANDLE; } /** - * {@snippet : - * BOOL CloseHandle(HANDLE hObject); + * {@snippet lang=c : + * BOOL CloseHandle(HANDLE hObject) * } */ public static int CloseHandle(MemorySegment hObject) { - var mh$ = CloseHandle$MH(); + var mh$ = CloseHandle.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("CloseHandle", hObject); + } return (int)mh$.invokeExact(hObject); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle GetModuleHandleW$MH() { - return RuntimeHelper.requireNonNull(constants$2.const$1,"GetModuleHandleW"); + + private static class GetModuleHandleW { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + Kernel32.C_POINTER, + Kernel32.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + Kernel32.findOrThrow("GetModuleHandleW"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * HMODULE GetModuleHandleW(LPCWSTR lpModuleName) + * } + */ + public static FunctionDescriptor GetModuleHandleW$descriptor() { + return GetModuleHandleW.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * HMODULE GetModuleHandleW(LPCWSTR lpModuleName) + * } + */ + public static MethodHandle GetModuleHandleW$handle() { + return GetModuleHandleW.HANDLE; } /** - * {@snippet : - * HMODULE GetModuleHandleW(LPCWSTR lpModuleName); + * {@snippet lang=c : + * HMODULE GetModuleHandleW(LPCWSTR lpModuleName) * } */ public static MemorySegment GetModuleHandleW(MemorySegment lpModuleName) { - var mh$ = GetModuleHandleW$MH(); + var mh$ = GetModuleHandleW.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(lpModuleName); + if (TRACE_DOWNCALLS) { + traceDowncall("GetModuleHandleW", lpModuleName); + } + return (MemorySegment)mh$.invokeExact(lpModuleName); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle LocalFree$MH() { - return RuntimeHelper.requireNonNull(constants$2.const$2,"LocalFree"); + + private static class LocalFree { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + Kernel32.C_POINTER, + Kernel32.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + Kernel32.findOrThrow("LocalFree"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * HLOCAL LocalFree(HLOCAL hMem) + * } + */ + public static FunctionDescriptor LocalFree$descriptor() { + return LocalFree.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * HLOCAL LocalFree(HLOCAL hMem) + * } + */ + public static MethodHandle LocalFree$handle() { + return LocalFree.HANDLE; } /** - * {@snippet : - * HLOCAL LocalFree(HLOCAL hMem); + * {@snippet lang=c : + * HLOCAL LocalFree(HLOCAL hMem) * } */ public static MemorySegment LocalFree(MemorySegment hMem) { - var mh$ = LocalFree$MH(); + var mh$ = LocalFree.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(hMem); + if (TRACE_DOWNCALLS) { + traceDowncall("LocalFree", hMem); + } + return (MemorySegment)mh$.invokeExact(hMem); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle FormatMessageW$MH() { - return RuntimeHelper.requireNonNull(constants$2.const$4,"FormatMessageW"); + + private static class FormatMessageW { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + Kernel32.C_LONG, + Kernel32.C_LONG, + Kernel32.C_POINTER, + Kernel32.C_LONG, + Kernel32.C_LONG, + Kernel32.C_POINTER, + Kernel32.C_LONG, + Kernel32.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + Kernel32.findOrThrow("FormatMessageW"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * DWORD FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments) + * } + */ + public static FunctionDescriptor FormatMessageW$descriptor() { + return FormatMessageW.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * DWORD FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments) + * } + */ + public static MethodHandle FormatMessageW$handle() { + return FormatMessageW.HANDLE; } /** - * {@snippet : - * DWORD FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list* Arguments); + * {@snippet lang=c : + * DWORD FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments) * } */ public static int FormatMessageW(int dwFlags, MemorySegment lpSource, int dwMessageId, int dwLanguageId, MemorySegment lpBuffer, int nSize, MemorySegment Arguments) { - var mh$ = FormatMessageW$MH(); + var mh$ = FormatMessageW.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("FormatMessageW", dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments); + } return (int)mh$.invokeExact(dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } + private static final int GENERIC_READ = (int)2147483648L; /** - * {@snippet : + * {@snippet lang=c : * #define GENERIC_READ 2147483648 * } */ public static int GENERIC_READ() { - return (int)2147483648L; + return GENERIC_READ; } + private static final int GENERIC_WRITE = (int)1073741824L; /** - * {@snippet : + * {@snippet lang=c : * #define GENERIC_WRITE 1073741824 * } */ public static int GENERIC_WRITE() { - return (int)1073741824L; + return GENERIC_WRITE; } + private static final int INFINITE = (int)4294967295L; /** - * {@snippet : + * {@snippet lang=c : * #define INFINITE 4294967295 * } */ public static int INFINITE() { - return (int)4294967295L; + return INFINITE; } + private static final int ERROR_FILE_NOT_FOUND = (int)2L; /** - * {@snippet : + * {@snippet lang=c : * #define ERROR_FILE_NOT_FOUND 2 * } */ public static int ERROR_FILE_NOT_FOUND() { - return (int)2L; + return ERROR_FILE_NOT_FOUND; } + private static final int ERROR_GEN_FAILURE = (int)31L; /** - * {@snippet : + * {@snippet lang=c : * #define ERROR_GEN_FAILURE 31 * } */ public static int ERROR_GEN_FAILURE() { - return (int)31L; + return ERROR_GEN_FAILURE; } + private static final int ERROR_INSUFFICIENT_BUFFER = (int)122L; /** - * {@snippet : + * {@snippet lang=c : * #define ERROR_INSUFFICIENT_BUFFER 122 * } */ public static int ERROR_INSUFFICIENT_BUFFER() { - return (int)122L; + return ERROR_INSUFFICIENT_BUFFER; } + private static final int ERROR_MORE_DATA = (int)234L; /** - * {@snippet : + * {@snippet lang=c : * #define ERROR_MORE_DATA 234 * } */ public static int ERROR_MORE_DATA() { - return (int)234L; + return ERROR_MORE_DATA; } + private static final int ERROR_NO_MORE_ITEMS = (int)259L; /** - * {@snippet : + * {@snippet lang=c : * #define ERROR_NO_MORE_ITEMS 259 * } */ public static int ERROR_NO_MORE_ITEMS() { - return (int)259L; + return ERROR_NO_MORE_ITEMS; } + private static final int ERROR_IO_PENDING = (int)997L; /** - * {@snippet : + * {@snippet lang=c : * #define ERROR_IO_PENDING 997 * } */ public static int ERROR_IO_PENDING() { - return (int)997L; + return ERROR_IO_PENDING; } + private static final int ERROR_NOT_FOUND = (int)1168L; /** - * {@snippet : + * {@snippet lang=c : * #define ERROR_NOT_FOUND 1168 * } */ public static int ERROR_NOT_FOUND() { - return (int)1168L; + return ERROR_NOT_FOUND; } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/OVERLAPPED.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/OVERLAPPED.java deleted file mode 100644 index 129b9892..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/OVERLAPPED.java +++ /dev/null @@ -1,16 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.kernel32; - -/** - * {@snippet : - * typedef struct _OVERLAPPED OVERLAPPED; - * } - */ -public final class OVERLAPPED extends _OVERLAPPED { - - // Suppresses default constructor, ensuring non-instantiability. - private OVERLAPPED() {} -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java deleted file mode 100644 index 9e11909f..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/RuntimeHelper.java +++ /dev/null @@ -1,239 +0,0 @@ -package net.codecrete.usb.windows.gen.kernel32; -// Generated by jextract - -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_LONG; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { - System.loadLibrary("Kernel32"); - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java index ead65d4b..34169dd9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java @@ -3,115 +3,300 @@ package net.codecrete.usb.windows.gen.kernel32; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SequenceLayout; import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfShort; + /** - * {@snippet : + * {@snippet lang=c : * struct _GUID { * unsigned long Data1; * unsigned short Data2; * unsigned short Data3; * unsigned char Data4[8]; - * }; + * } * } */ public class _GUID { - public static MemoryLayout $LAYOUT() { - return constants$0.const$0; + _GUID() { + // Should not be called directly } - public static VarHandle Data1$VH() { - return constants$0.const$1; + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + Kernel32.C_LONG.withName("Data1"), + Kernel32.C_SHORT.withName("Data2"), + Kernel32.C_SHORT.withName("Data3"), + MemoryLayout.sequenceLayout(8, Kernel32.C_CHAR).withName("Data4") + ).withName("_GUID"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } + + private static final OfInt Data1$LAYOUT = (OfInt)$LAYOUT.select(groupElement("Data1")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned long Data1 + * } + */ + public static final OfInt Data1$layout() { + return Data1$LAYOUT; + } + + private static final long Data1$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned long Data1 + * } + */ + public static final long Data1$offset() { + return Data1$OFFSET; + } + /** * Getter for field: - * {@snippet : - * unsigned long Data1; + * {@snippet lang=c : + * unsigned long Data1 * } */ - public static int Data1$get(MemorySegment seg) { - return (int)constants$0.const$1.get(seg); + public static int Data1(MemorySegment struct) { + return struct.get(Data1$LAYOUT, Data1$OFFSET); } + /** * Setter for field: - * {@snippet : - * unsigned long Data1; + * {@snippet lang=c : + * unsigned long Data1 * } */ - public static void Data1$set(MemorySegment seg, int x) { - constants$0.const$1.set(seg, x); + public static void Data1(MemorySegment struct, int fieldValue) { + struct.set(Data1$LAYOUT, Data1$OFFSET, fieldValue); } - public static int Data1$get(MemorySegment seg, long index) { - return (int)constants$0.const$1.get(seg.asSlice(index*sizeof())); - } - public static void Data1$set(MemorySegment seg, long index, int x) { - constants$0.const$1.set(seg.asSlice(index*sizeof()), x); + + private static final OfShort Data2$LAYOUT = (OfShort)$LAYOUT.select(groupElement("Data2")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned short Data2 + * } + */ + public static final OfShort Data2$layout() { + return Data2$LAYOUT; } - public static VarHandle Data2$VH() { - return constants$0.const$2; + + private static final long Data2$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned short Data2 + * } + */ + public static final long Data2$offset() { + return Data2$OFFSET; } + /** * Getter for field: - * {@snippet : - * unsigned short Data2; + * {@snippet lang=c : + * unsigned short Data2 * } */ - public static short Data2$get(MemorySegment seg) { - return (short)constants$0.const$2.get(seg); + public static short Data2(MemorySegment struct) { + return struct.get(Data2$LAYOUT, Data2$OFFSET); } + /** * Setter for field: - * {@snippet : - * unsigned short Data2; + * {@snippet lang=c : + * unsigned short Data2 * } */ - public static void Data2$set(MemorySegment seg, short x) { - constants$0.const$2.set(seg, x); + public static void Data2(MemorySegment struct, short fieldValue) { + struct.set(Data2$LAYOUT, Data2$OFFSET, fieldValue); } - public static short Data2$get(MemorySegment seg, long index) { - return (short)constants$0.const$2.get(seg.asSlice(index*sizeof())); + + private static final OfShort Data3$LAYOUT = (OfShort)$LAYOUT.select(groupElement("Data3")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned short Data3 + * } + */ + public static final OfShort Data3$layout() { + return Data3$LAYOUT; } - public static void Data2$set(MemorySegment seg, long index, short x) { - constants$0.const$2.set(seg.asSlice(index*sizeof()), x); + + private static final long Data3$OFFSET = 6; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned short Data3 + * } + */ + public static final long Data3$offset() { + return Data3$OFFSET; } - public static VarHandle Data3$VH() { - return constants$0.const$3; + + /** + * Getter for field: + * {@snippet lang=c : + * unsigned short Data3 + * } + */ + public static short Data3(MemorySegment struct) { + return struct.get(Data3$LAYOUT, Data3$OFFSET); } + + /** + * Setter for field: + * {@snippet lang=c : + * unsigned short Data3 + * } + */ + public static void Data3(MemorySegment struct, short fieldValue) { + struct.set(Data3$LAYOUT, Data3$OFFSET, fieldValue); + } + + private static final SequenceLayout Data4$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("Data4")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static final SequenceLayout Data4$layout() { + return Data4$LAYOUT; + } + + private static final long Data4$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static final long Data4$offset() { + return Data4$OFFSET; + } + /** * Getter for field: - * {@snippet : - * unsigned short Data3; + * {@snippet lang=c : + * unsigned char Data4[8] * } */ - public static short Data3$get(MemorySegment seg) { - return (short)constants$0.const$3.get(seg); + public static MemorySegment Data4(MemorySegment struct) { + return struct.asSlice(Data4$OFFSET, Data4$LAYOUT.byteSize()); } + /** * Setter for field: - * {@snippet : - * unsigned short Data3; + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static void Data4(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, Data4$OFFSET, Data4$LAYOUT.byteSize()); + } + + private static long[] Data4$DIMS = { 8 }; + + /** + * Dimensions for array field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static long[] Data4$dimensions() { + return Data4$DIMS; + } + private static final VarHandle Data4$ELEM_HANDLE = Data4$LAYOUT.varHandle(sequenceElement()); + + /** + * Indexed getter for field: + * {@snippet lang=c : + * unsigned char Data4[8] * } */ - public static void Data3$set(MemorySegment seg, short x) { - constants$0.const$3.set(seg, x); + public static byte Data4(MemorySegment struct, long index0) { + return (byte)Data4$ELEM_HANDLE.get(struct, 0L, index0); } - public static short Data3$get(MemorySegment seg, long index) { - return (short)constants$0.const$3.get(seg.asSlice(index*sizeof())); + + /** + * Indexed setter for field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static void Data4(MemorySegment struct, long index0, byte fieldValue) { + Data4$ELEM_HANDLE.set(struct, 0L, index0, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static void Data3$set(MemorySegment seg, long index, short x) { - constants$0.const$3.set(seg.asSlice(index*sizeof()), x); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static MemorySegment Data4$slice(MemorySegment seg) { - return seg.asSlice(8, 8); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java index 770014d6..31fdebc2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java @@ -2,13 +2,20 @@ package net.codecrete.usb.windows.gen.kernel32; +import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfLong; + /** - * {@snippet : + * {@snippet lang=c : * struct _OVERLAPPED { * ULONG_PTR Internal; * ULONG_PTR InternalHigh; @@ -20,182 +27,341 @@ * PVOID Pointer; * }; * HANDLE hEvent; - * }; + * } * } */ public class _OVERLAPPED { - public static MemoryLayout $LAYOUT() { - return constants$0.const$4; + _OVERLAPPED() { + // Should not be called directly } - public static VarHandle Internal$VH() { - return constants$0.const$5; + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + Kernel32.C_LONG_LONG.withName("Internal"), + Kernel32.C_LONG_LONG.withName("InternalHigh"), + MemoryLayout.unionLayout( + MemoryLayout.structLayout( + Kernel32.C_LONG.withName("Offset"), + Kernel32.C_LONG.withName("OffsetHigh") + ).withName("$anon$56:9"), + Kernel32.C_POINTER.withName("Pointer") + ).withName("$anon$55:5"), + Kernel32.C_POINTER.withName("hEvent") + ).withName("_OVERLAPPED"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } + + private static final OfLong Internal$LAYOUT = (OfLong)$LAYOUT.select(groupElement("Internal")); + + /** + * Layout for field: + * {@snippet lang=c : + * ULONG_PTR Internal + * } + */ + public static final OfLong Internal$layout() { + return Internal$LAYOUT; + } + + private static final long Internal$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * ULONG_PTR Internal + * } + */ + public static final long Internal$offset() { + return Internal$OFFSET; + } + /** * Getter for field: - * {@snippet : - * ULONG_PTR Internal; + * {@snippet lang=c : + * ULONG_PTR Internal * } */ - public static long Internal$get(MemorySegment seg) { - return (long)constants$0.const$5.get(seg); + public static long Internal(MemorySegment struct) { + return struct.get(Internal$LAYOUT, Internal$OFFSET); } + /** * Setter for field: - * {@snippet : - * ULONG_PTR Internal; + * {@snippet lang=c : + * ULONG_PTR Internal * } */ - public static void Internal$set(MemorySegment seg, long x) { - constants$0.const$5.set(seg, x); + public static void Internal(MemorySegment struct, long fieldValue) { + struct.set(Internal$LAYOUT, Internal$OFFSET, fieldValue); } - public static long Internal$get(MemorySegment seg, long index) { - return (long)constants$0.const$5.get(seg.asSlice(index*sizeof())); - } - public static void Internal$set(MemorySegment seg, long index, long x) { - constants$0.const$5.set(seg.asSlice(index*sizeof()), x); + + private static final OfLong InternalHigh$LAYOUT = (OfLong)$LAYOUT.select(groupElement("InternalHigh")); + + /** + * Layout for field: + * {@snippet lang=c : + * ULONG_PTR InternalHigh + * } + */ + public static final OfLong InternalHigh$layout() { + return InternalHigh$LAYOUT; } - public static VarHandle InternalHigh$VH() { - return constants$1.const$0; + + private static final long InternalHigh$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * ULONG_PTR InternalHigh + * } + */ + public static final long InternalHigh$offset() { + return InternalHigh$OFFSET; } + /** * Getter for field: - * {@snippet : - * ULONG_PTR InternalHigh; + * {@snippet lang=c : + * ULONG_PTR InternalHigh * } */ - public static long InternalHigh$get(MemorySegment seg) { - return (long)constants$1.const$0.get(seg); + public static long InternalHigh(MemorySegment struct) { + return struct.get(InternalHigh$LAYOUT, InternalHigh$OFFSET); } + /** * Setter for field: - * {@snippet : - * ULONG_PTR InternalHigh; + * {@snippet lang=c : + * ULONG_PTR InternalHigh * } */ - public static void InternalHigh$set(MemorySegment seg, long x) { - constants$1.const$0.set(seg, x); + public static void InternalHigh(MemorySegment struct, long fieldValue) { + struct.set(InternalHigh$LAYOUT, InternalHigh$OFFSET, fieldValue); } - public static long InternalHigh$get(MemorySegment seg, long index) { - return (long)constants$1.const$0.get(seg.asSlice(index*sizeof())); - } - public static void InternalHigh$set(MemorySegment seg, long index, long x) { - constants$1.const$0.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt Offset$LAYOUT = (OfInt)$LAYOUT.select(groupElement("$anon$55:5"), groupElement("$anon$56:9"), groupElement("Offset")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD Offset + * } + */ + public static final OfInt Offset$layout() { + return Offset$LAYOUT; } - public static VarHandle Offset$VH() { - return constants$1.const$1; + + private static final long Offset$OFFSET = 16; + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD Offset + * } + */ + public static final long Offset$offset() { + return Offset$OFFSET; } + /** * Getter for field: - * {@snippet : - * DWORD Offset; + * {@snippet lang=c : + * DWORD Offset * } */ - public static int Offset$get(MemorySegment seg) { - return (int)constants$1.const$1.get(seg); + public static int Offset(MemorySegment struct) { + return struct.get(Offset$LAYOUT, Offset$OFFSET); } + /** * Setter for field: - * {@snippet : - * DWORD Offset; + * {@snippet lang=c : + * DWORD Offset * } */ - public static void Offset$set(MemorySegment seg, int x) { - constants$1.const$1.set(seg, x); - } - public static int Offset$get(MemorySegment seg, long index) { - return (int)constants$1.const$1.get(seg.asSlice(index*sizeof())); + public static void Offset(MemorySegment struct, int fieldValue) { + struct.set(Offset$LAYOUT, Offset$OFFSET, fieldValue); } - public static void Offset$set(MemorySegment seg, long index, int x) { - constants$1.const$1.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt OffsetHigh$LAYOUT = (OfInt)$LAYOUT.select(groupElement("$anon$55:5"), groupElement("$anon$56:9"), groupElement("OffsetHigh")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD OffsetHigh + * } + */ + public static final OfInt OffsetHigh$layout() { + return OffsetHigh$LAYOUT; } - public static VarHandle OffsetHigh$VH() { - return constants$1.const$2; + + private static final long OffsetHigh$OFFSET = 20; + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD OffsetHigh + * } + */ + public static final long OffsetHigh$offset() { + return OffsetHigh$OFFSET; } + /** * Getter for field: - * {@snippet : - * DWORD OffsetHigh; + * {@snippet lang=c : + * DWORD OffsetHigh * } */ - public static int OffsetHigh$get(MemorySegment seg) { - return (int)constants$1.const$2.get(seg); + public static int OffsetHigh(MemorySegment struct) { + return struct.get(OffsetHigh$LAYOUT, OffsetHigh$OFFSET); } + /** * Setter for field: - * {@snippet : - * DWORD OffsetHigh; + * {@snippet lang=c : + * DWORD OffsetHigh * } */ - public static void OffsetHigh$set(MemorySegment seg, int x) { - constants$1.const$2.set(seg, x); - } - public static int OffsetHigh$get(MemorySegment seg, long index) { - return (int)constants$1.const$2.get(seg.asSlice(index*sizeof())); + public static void OffsetHigh(MemorySegment struct, int fieldValue) { + struct.set(OffsetHigh$LAYOUT, OffsetHigh$OFFSET, fieldValue); } - public static void OffsetHigh$set(MemorySegment seg, long index, int x) { - constants$1.const$2.set(seg.asSlice(index*sizeof()), x); + + private static final AddressLayout Pointer$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("$anon$55:5"), groupElement("Pointer")); + + /** + * Layout for field: + * {@snippet lang=c : + * PVOID Pointer + * } + */ + public static final AddressLayout Pointer$layout() { + return Pointer$LAYOUT; } - public static VarHandle Pointer$VH() { - return constants$1.const$3; + + private static final long Pointer$OFFSET = 16; + + /** + * Offset for field: + * {@snippet lang=c : + * PVOID Pointer + * } + */ + public static final long Pointer$offset() { + return Pointer$OFFSET; } + /** * Getter for field: - * {@snippet : - * PVOID Pointer; + * {@snippet lang=c : + * PVOID Pointer * } */ - public static MemorySegment Pointer$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$1.const$3.get(seg); + public static MemorySegment Pointer(MemorySegment struct) { + return struct.get(Pointer$LAYOUT, Pointer$OFFSET); } + /** * Setter for field: - * {@snippet : - * PVOID Pointer; + * {@snippet lang=c : + * PVOID Pointer * } */ - public static void Pointer$set(MemorySegment seg, MemorySegment x) { - constants$1.const$3.set(seg, x); - } - public static MemorySegment Pointer$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$1.const$3.get(seg.asSlice(index*sizeof())); + public static void Pointer(MemorySegment struct, MemorySegment fieldValue) { + struct.set(Pointer$LAYOUT, Pointer$OFFSET, fieldValue); } - public static void Pointer$set(MemorySegment seg, long index, MemorySegment x) { - constants$1.const$3.set(seg.asSlice(index*sizeof()), x); + + private static final AddressLayout hEvent$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("hEvent")); + + /** + * Layout for field: + * {@snippet lang=c : + * HANDLE hEvent + * } + */ + public static final AddressLayout hEvent$layout() { + return hEvent$LAYOUT; } - public static VarHandle hEvent$VH() { - return constants$1.const$4; + + private static final long hEvent$OFFSET = 24; + + /** + * Offset for field: + * {@snippet lang=c : + * HANDLE hEvent + * } + */ + public static final long hEvent$offset() { + return hEvent$OFFSET; } + /** * Getter for field: - * {@snippet : - * HANDLE hEvent; + * {@snippet lang=c : + * HANDLE hEvent * } */ - public static MemorySegment hEvent$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$1.const$4.get(seg); + public static MemorySegment hEvent(MemorySegment struct) { + return struct.get(hEvent$LAYOUT, hEvent$OFFSET); } + /** * Setter for field: - * {@snippet : - * HANDLE hEvent; + * {@snippet lang=c : + * HANDLE hEvent * } */ - public static void hEvent$set(MemorySegment seg, MemorySegment x) { - constants$1.const$4.set(seg, x); + public static void hEvent(MemorySegment struct, MemorySegment fieldValue) { + struct.set(hEvent$LAYOUT, hEvent$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static MemorySegment hEvent$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$1.const$4.get(seg.asSlice(index*sizeof())); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static void hEvent$set(MemorySegment seg, long index, MemorySegment x) { - constants$1.const$4.set(seg.asSlice(index*sizeof()), x); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java deleted file mode 100644 index 80a6d1ec..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$0.java +++ /dev/null @@ -1,41 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.kernel32; - -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final StructLayout const$0 = MemoryLayout.structLayout( - JAVA_INT.withName("Data1"), - JAVA_SHORT.withName("Data2"), - JAVA_SHORT.withName("Data3"), - MemoryLayout.sequenceLayout(8, JAVA_BYTE).withName("Data4") - ).withName("_GUID"); - static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("Data1")); - static final VarHandle const$2 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("Data2")); - static final VarHandle const$3 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("Data3")); - static final StructLayout const$4 = MemoryLayout.structLayout( - JAVA_LONG.withName("Internal"), - JAVA_LONG.withName("InternalHigh"), - MemoryLayout.unionLayout( - MemoryLayout.structLayout( - JAVA_INT.withName("Offset"), - JAVA_INT.withName("OffsetHigh") - ).withName("$anon$0"), - RuntimeHelper.POINTER.withName("Pointer") - ).withName("$anon$0"), - RuntimeHelper.POINTER.withName("hEvent") - ).withName("_OVERLAPPED"); - static final VarHandle const$5 = constants$0.const$4.varHandle(MemoryLayout.PathElement.groupElement("Internal")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java deleted file mode 100644 index b86794ff..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$1.java +++ /dev/null @@ -1,29 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.kernel32; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$1 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$1() {} - static final VarHandle const$0 = constants$0.const$4.varHandle(MemoryLayout.PathElement.groupElement("InternalHigh")); - static final VarHandle const$1 = constants$0.const$4.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("Offset")); - static final VarHandle const$2 = constants$0.const$4.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("OffsetHigh")); - static final VarHandle const$3 = constants$0.const$4.varHandle(MemoryLayout.PathElement.groupElement("$anon$0"), MemoryLayout.PathElement.groupElement("Pointer")); - static final VarHandle const$4 = constants$0.const$4.varHandle(MemoryLayout.PathElement.groupElement("hEvent")); - static final FunctionDescriptor const$5 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER - ); - static final MethodHandle const$6 = RuntimeHelper.downcallHandle( - "CloseHandle", - constants$1.const$5 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$2.java deleted file mode 100644 index 0f426d9c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/constants$2.java +++ /dev/null @@ -1,39 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.kernel32; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$2 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$2() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$1 = RuntimeHelper.downcallHandle( - "GetModuleHandleW", - constants$2.const$0 - ); - static final MethodHandle const$2 = RuntimeHelper.downcallHandle( - "LocalFree", - constants$2.const$0 - ); - static final FunctionDescriptor const$3 = FunctionDescriptor.of(JAVA_INT, - JAVA_INT, - RuntimeHelper.POINTER, - JAVA_INT, - JAVA_INT, - RuntimeHelper.POINTER, - JAVA_INT, - RuntimeHelper.POINTER - ); - static final MethodHandle const$4 = RuntimeHelper.downcallHandle( - "FormatMessageW", - constants$2.const$3 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java index 07405105..f5552ce1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java @@ -3,37 +3,71 @@ package net.codecrete.usb.windows.gen.ntdll; import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_FLOAT; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -import static java.lang.foreign.ValueLayout.OfByte; -import static java.lang.foreign.ValueLayout.OfDouble; -import static java.lang.foreign.ValueLayout.OfFloat; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfLong; -import static java.lang.foreign.ValueLayout.OfShort; -public class NtDll { - - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfInt C_LONG = JAVA_INT; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; + +public class NtDll { + + NtDll() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfInt C_LONG = ValueLayout.JAVA_INT; + public static final ValueLayout.OfDouble C_LONG_DOUBLE = ValueLayout.JAVA_DOUBLE; + private static final int STATUS_UNSUCCESSFUL = (int)-1073741823L; /** - * {@snippet : + * {@snippet lang=c : * #define STATUS_UNSUCCESSFUL -1073741823 * } */ public static int STATUS_UNSUCCESSFUL() { - return (int)-1073741823L; + return STATUS_UNSUCCESSFUL; } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/RuntimeHelper.java deleted file mode 100644 index 8e26fb6a..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/RuntimeHelper.java +++ /dev/null @@ -1,239 +0,0 @@ -package net.codecrete.usb.windows.gen.ntdll; -// Generated by jextract - -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_LONG; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { - - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/constants$0.java deleted file mode 100644 index 7bb245f6..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/constants$0.java +++ /dev/null @@ -1,11 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.ntdll; - -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java index c350c506..ba427c31 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java @@ -3,47 +3,111 @@ package net.codecrete.usb.windows.gen.ole32; import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_FLOAT; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -import static java.lang.foreign.ValueLayout.OfByte; -import static java.lang.foreign.ValueLayout.OfDouble; -import static java.lang.foreign.ValueLayout.OfFloat; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfLong; -import static java.lang.foreign.ValueLayout.OfShort; -public class Ole32 { - - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfInt C_LONG = JAVA_INT; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; - public static MethodHandle CLSIDFromString$MH() { - return RuntimeHelper.requireNonNull(constants$0.const$1,"CLSIDFromString"); + +public class Ole32 { + + Ole32() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("Ole32"), LIBRARY_ARENA) + .or(SymbolLookup.loaderLookup()) + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfInt C_LONG = ValueLayout.JAVA_INT; + public static final ValueLayout.OfDouble C_LONG_DOUBLE = ValueLayout.JAVA_DOUBLE; + + private static class CLSIDFromString { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + Ole32.C_LONG, + Ole32.C_POINTER, + Ole32.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + Ole32.findOrThrow("CLSIDFromString"), + DESC); + } + /** - * {@snippet : - * HRESULT CLSIDFromString(LPCOLESTR lpsz, LPCLSID pclsid); + * Function descriptor for: + * {@snippet lang=c : + * extern HRESULT CLSIDFromString(LPCOLESTR lpsz, LPCLSID pclsid) + * } + */ + public static FunctionDescriptor CLSIDFromString$descriptor() { + return CLSIDFromString.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern HRESULT CLSIDFromString(LPCOLESTR lpsz, LPCLSID pclsid) + * } + */ + public static MethodHandle CLSIDFromString$handle() { + return CLSIDFromString.HANDLE; + } + /** + * {@snippet lang=c : + * extern HRESULT CLSIDFromString(LPCOLESTR lpsz, LPCLSID pclsid) * } */ public static int CLSIDFromString(MemorySegment lpsz, MemorySegment pclsid) { - var mh$ = CLSIDFromString$MH(); + var mh$ = CLSIDFromString.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("CLSIDFromString", lpsz, pclsid); + } return (int)mh$.invokeExact(lpsz, pclsid); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java deleted file mode 100644 index 47f1d66c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/RuntimeHelper.java +++ /dev/null @@ -1,239 +0,0 @@ -package net.codecrete.usb.windows.gen.ole32; -// Generated by jextract - -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_LONG; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { - System.loadLibrary("Ole32"); - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/constants$0.java deleted file mode 100644 index bf4c2c05..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/constants$0.java +++ /dev/null @@ -1,23 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.ole32; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$1 = RuntimeHelper.downcallHandle( - "CLSIDFromString", - constants$0.const$0 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/DEVPROPKEY.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/DEVPROPKEY.java deleted file mode 100644 index 8162d9a9..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/DEVPROPKEY.java +++ /dev/null @@ -1,16 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.setupapi; - -/** - * {@snippet : - * typedef struct _DEVPROPKEY DEVPROPKEY; - * } - */ -public final class DEVPROPKEY extends _DEVPROPKEY { - - // Suppresses default constructor, ensuring non-instantiability. - private DEVPROPKEY() {} -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java deleted file mode 100644 index 53c18558..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/RuntimeHelper.java +++ /dev/null @@ -1,239 +0,0 @@ -package net.codecrete.usb.windows.gen.setupapi; -// Generated by jextract - -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_LONG; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { - System.loadLibrary("SetupAPI"); - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DATA.java deleted file mode 100644 index 13425fec..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DATA.java +++ /dev/null @@ -1,16 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.setupapi; - -/** - * {@snippet : - * typedef struct _SP_DEVICE_INTERFACE_DATA SP_DEVICE_INTERFACE_DATA; - * } - */ -public final class SP_DEVICE_INTERFACE_DATA extends _SP_DEVICE_INTERFACE_DATA { - - // Suppresses default constructor, ensuring non-instantiability. - private SP_DEVICE_INTERFACE_DATA() {} -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java deleted file mode 100644 index 7a9f76bc..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVICE_INTERFACE_DETAIL_DATA_W.java +++ /dev/null @@ -1,16 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.setupapi; - -/** - * {@snippet : - * typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W SP_DEVICE_INTERFACE_DETAIL_DATA_W; - * } - */ -public final class SP_DEVICE_INTERFACE_DETAIL_DATA_W extends _SP_DEVICE_INTERFACE_DETAIL_DATA_W { - - // Suppresses default constructor, ensuring non-instantiability. - private SP_DEVICE_INTERFACE_DETAIL_DATA_W() {} -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVINFO_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVINFO_DATA.java deleted file mode 100644 index ebc94bce..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SP_DEVINFO_DATA.java +++ /dev/null @@ -1,16 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.setupapi; - -/** - * {@snippet : - * typedef struct _SP_DEVINFO_DATA SP_DEVINFO_DATA; - * } - */ -public final class SP_DEVINFO_DATA extends _SP_DEVINFO_DATA { - - // Suppresses default constructor, ensuring non-instantiability. - private SP_DEVINFO_DATA() {} -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java index 7e909856..8f1c7ae8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java @@ -3,119 +3,221 @@ package net.codecrete.usb.windows.gen.setupapi; import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_FLOAT; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -import static java.lang.foreign.ValueLayout.OfByte; -import static java.lang.foreign.ValueLayout.OfDouble; -import static java.lang.foreign.ValueLayout.OfFloat; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfLong; -import static java.lang.foreign.ValueLayout.OfShort; -public class SetupAPI { - - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfInt C_LONG = JAVA_INT; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; + +public class SetupAPI { + + SetupAPI() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("SetupAPI"), LIBRARY_ARENA) + .or(SymbolLookup.loaderLookup()) + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfInt C_LONG = ValueLayout.JAVA_INT; + public static final ValueLayout.OfDouble C_LONG_DOUBLE = ValueLayout.JAVA_DOUBLE; + private static final int DEVPROP_TYPEMOD_LIST = (int)8192L; /** - * {@snippet : + * {@snippet lang=c : * #define DEVPROP_TYPEMOD_LIST 8192 * } */ public static int DEVPROP_TYPEMOD_LIST() { - return (int)8192L; + return DEVPROP_TYPEMOD_LIST; } + private static final int DEVPROP_TYPE_UINT32 = (int)7L; /** - * {@snippet : + * {@snippet lang=c : * #define DEVPROP_TYPE_UINT32 7 * } */ public static int DEVPROP_TYPE_UINT32() { - return (int)7L; + return DEVPROP_TYPE_UINT32; } + private static final int DEVPROP_TYPE_STRING = (int)18L; /** - * {@snippet : + * {@snippet lang=c : * #define DEVPROP_TYPE_STRING 18 * } */ public static int DEVPROP_TYPE_STRING() { - return (int)18L; + return DEVPROP_TYPE_STRING; } + private static final int DICS_FLAG_GLOBAL = (int)1L; /** - * {@snippet : + * {@snippet lang=c : * #define DICS_FLAG_GLOBAL 1 * } */ public static int DICS_FLAG_GLOBAL() { - return (int)1L; + return DICS_FLAG_GLOBAL; } + private static final int DIGCF_PRESENT = (int)2L; /** - * {@snippet : + * {@snippet lang=c : * #define DIGCF_PRESENT 2 * } */ public static int DIGCF_PRESENT() { - return (int)2L; + return DIGCF_PRESENT; } + private static final int DIGCF_DEVICEINTERFACE = (int)16L; /** - * {@snippet : + * {@snippet lang=c : * #define DIGCF_DEVICEINTERFACE 16 * } */ public static int DIGCF_DEVICEINTERFACE() { - return (int)16L; + return DIGCF_DEVICEINTERFACE; } + private static final int DIREG_DEV = (int)1L; /** - * {@snippet : + * {@snippet lang=c : * #define DIREG_DEV 1 * } */ public static int DIREG_DEV() { - return (int)1L; + return DIREG_DEV; } - public static MethodHandle SetupDiDestroyDeviceInfoList$MH() { - return RuntimeHelper.requireNonNull(constants$2.const$1,"SetupDiDestroyDeviceInfoList"); + + private static class SetupDiDestroyDeviceInfoList { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + SetupAPI.C_INT, + SetupAPI.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + SetupAPI.findOrThrow("SetupDiDestroyDeviceInfoList"), + DESC); } + /** - * {@snippet : - * BOOL SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet); + * Function descriptor for: + * {@snippet lang=c : + * BOOL SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet) + * } + */ + public static FunctionDescriptor SetupDiDestroyDeviceInfoList$descriptor() { + return SetupDiDestroyDeviceInfoList.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * BOOL SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet) + * } + */ + public static MethodHandle SetupDiDestroyDeviceInfoList$handle() { + return SetupDiDestroyDeviceInfoList.HANDLE; + } + /** + * {@snippet lang=c : + * BOOL SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet) * } */ public static int SetupDiDestroyDeviceInfoList(MemorySegment DeviceInfoSet) { - var mh$ = SetupDiDestroyDeviceInfoList$MH(); + var mh$ = SetupDiDestroyDeviceInfoList.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("SetupDiDestroyDeviceInfoList", DeviceInfoSet); + } return (int)mh$.invokeExact(DeviceInfoSet); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle SetupDiDeleteDeviceInterfaceData$MH() { - return RuntimeHelper.requireNonNull(constants$2.const$3,"SetupDiDeleteDeviceInterfaceData"); + + private static class SetupDiDeleteDeviceInterfaceData { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + SetupAPI.C_INT, + SetupAPI.C_POINTER, + SetupAPI.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + SetupAPI.findOrThrow("SetupDiDeleteDeviceInterfaceData"), + DESC); } + /** - * {@snippet : - * BOOL SetupDiDeleteDeviceInterfaceData(HDEVINFO DeviceInfoSet, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData); + * Function descriptor for: + * {@snippet lang=c : + * BOOL SetupDiDeleteDeviceInterfaceData(HDEVINFO DeviceInfoSet, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) + * } + */ + public static FunctionDescriptor SetupDiDeleteDeviceInterfaceData$descriptor() { + return SetupDiDeleteDeviceInterfaceData.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * BOOL SetupDiDeleteDeviceInterfaceData(HDEVINFO DeviceInfoSet, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) + * } + */ + public static MethodHandle SetupDiDeleteDeviceInterfaceData$handle() { + return SetupDiDeleteDeviceInterfaceData.HANDLE; + } + /** + * {@snippet lang=c : + * BOOL SetupDiDeleteDeviceInterfaceData(HDEVINFO DeviceInfoSet, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) * } */ public static int SetupDiDeleteDeviceInterfaceData(MemorySegment DeviceInfoSet, MemorySegment DeviceInterfaceData) { - var mh$ = SetupDiDeleteDeviceInterfaceData$MH(); + var mh$ = SetupDiDeleteDeviceInterfaceData.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("SetupDiDeleteDeviceInterfaceData", DeviceInfoSet, DeviceInterfaceData); + } return (int)mh$.invokeExact(DeviceInfoSet, DeviceInterfaceData); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java index 8389d24a..b1f43780 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java @@ -3,59 +3,171 @@ package net.codecrete.usb.windows.gen.setupapi; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfInt; + /** - * {@snippet : + * {@snippet lang=c : * struct _DEVPROPKEY { * DEVPROPGUID fmtid; * DEVPROPID pid; - * }; + * } * } */ public class _DEVPROPKEY { - public static MemoryLayout $LAYOUT() { - return constants$0.const$0; + _DEVPROPKEY() { + // Should not be called directly } - public static MemorySegment fmtid$slice(MemorySegment seg) { - return seg.asSlice(0, 16); + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + _GUID.layout().withName("fmtid"), + SetupAPI.C_LONG.withName("pid") + ).withName("_DEVPROPKEY"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } - public static VarHandle pid$VH() { - return constants$0.const$1; + + private static final GroupLayout fmtid$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("fmtid")); + + /** + * Layout for field: + * {@snippet lang=c : + * DEVPROPGUID fmtid + * } + */ + public static final GroupLayout fmtid$layout() { + return fmtid$LAYOUT; } + + private static final long fmtid$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * DEVPROPGUID fmtid + * } + */ + public static final long fmtid$offset() { + return fmtid$OFFSET; + } + /** * Getter for field: - * {@snippet : - * DEVPROPID pid; + * {@snippet lang=c : + * DEVPROPGUID fmtid * } */ - public static int pid$get(MemorySegment seg) { - return (int)constants$0.const$1.get(seg); + public static MemorySegment fmtid(MemorySegment struct) { + return struct.asSlice(fmtid$OFFSET, fmtid$LAYOUT.byteSize()); } + /** * Setter for field: - * {@snippet : - * DEVPROPID pid; + * {@snippet lang=c : + * DEVPROPGUID fmtid * } */ - public static void pid$set(MemorySegment seg, int x) { - constants$0.const$1.set(seg, x); + public static void fmtid(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, fmtid$OFFSET, fmtid$LAYOUT.byteSize()); } - public static int pid$get(MemorySegment seg, long index) { - return (int)constants$0.const$1.get(seg.asSlice(index*sizeof())); + + private static final OfInt pid$LAYOUT = (OfInt)$LAYOUT.select(groupElement("pid")); + + /** + * Layout for field: + * {@snippet lang=c : + * DEVPROPID pid + * } + */ + public static final OfInt pid$layout() { + return pid$LAYOUT; } - public static void pid$set(MemorySegment seg, long index, int x) { - constants$0.const$1.set(seg.asSlice(index*sizeof()), x); + + private static final long pid$OFFSET = 16; + + /** + * Offset for field: + * {@snippet lang=c : + * DEVPROPID pid + * } + */ + public static final long pid$offset() { + return pid$OFFSET; } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Getter for field: + * {@snippet lang=c : + * DEVPROPID pid + * } + */ + public static int pid(MemorySegment struct) { + return struct.get(pid$LAYOUT, pid$OFFSET); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } -} + /** + * Setter for field: + * {@snippet lang=c : + * DEVPROPID pid + * } + */ + public static void pid(MemorySegment struct, int fieldValue) { + struct.set(pid$LAYOUT, pid$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_GUID.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_GUID.java new file mode 100644 index 00000000..00de66c1 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_GUID.java @@ -0,0 +1,302 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.setupapi; + +import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SequenceLayout; +import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfShort; + +/** + * {@snippet lang=c : + * struct _GUID { + * unsigned long Data1; + * unsigned short Data2; + * unsigned short Data3; + * unsigned char Data4[8]; + * } + * } + */ +public class _GUID { + + _GUID() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + SetupAPI.C_LONG.withName("Data1"), + SetupAPI.C_SHORT.withName("Data2"), + SetupAPI.C_SHORT.withName("Data3"), + MemoryLayout.sequenceLayout(8, SetupAPI.C_CHAR).withName("Data4") + ).withName("_GUID"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfInt Data1$LAYOUT = (OfInt)$LAYOUT.select(groupElement("Data1")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned long Data1 + * } + */ + public static final OfInt Data1$layout() { + return Data1$LAYOUT; + } + + private static final long Data1$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned long Data1 + * } + */ + public static final long Data1$offset() { + return Data1$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * unsigned long Data1 + * } + */ + public static int Data1(MemorySegment struct) { + return struct.get(Data1$LAYOUT, Data1$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * unsigned long Data1 + * } + */ + public static void Data1(MemorySegment struct, int fieldValue) { + struct.set(Data1$LAYOUT, Data1$OFFSET, fieldValue); + } + + private static final OfShort Data2$LAYOUT = (OfShort)$LAYOUT.select(groupElement("Data2")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned short Data2 + * } + */ + public static final OfShort Data2$layout() { + return Data2$LAYOUT; + } + + private static final long Data2$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned short Data2 + * } + */ + public static final long Data2$offset() { + return Data2$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * unsigned short Data2 + * } + */ + public static short Data2(MemorySegment struct) { + return struct.get(Data2$LAYOUT, Data2$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * unsigned short Data2 + * } + */ + public static void Data2(MemorySegment struct, short fieldValue) { + struct.set(Data2$LAYOUT, Data2$OFFSET, fieldValue); + } + + private static final OfShort Data3$LAYOUT = (OfShort)$LAYOUT.select(groupElement("Data3")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned short Data3 + * } + */ + public static final OfShort Data3$layout() { + return Data3$LAYOUT; + } + + private static final long Data3$OFFSET = 6; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned short Data3 + * } + */ + public static final long Data3$offset() { + return Data3$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * unsigned short Data3 + * } + */ + public static short Data3(MemorySegment struct) { + return struct.get(Data3$LAYOUT, Data3$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * unsigned short Data3 + * } + */ + public static void Data3(MemorySegment struct, short fieldValue) { + struct.set(Data3$LAYOUT, Data3$OFFSET, fieldValue); + } + + private static final SequenceLayout Data4$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("Data4")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static final SequenceLayout Data4$layout() { + return Data4$LAYOUT; + } + + private static final long Data4$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static final long Data4$offset() { + return Data4$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static MemorySegment Data4(MemorySegment struct) { + return struct.asSlice(Data4$OFFSET, Data4$LAYOUT.byteSize()); + } + + /** + * Setter for field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static void Data4(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, Data4$OFFSET, Data4$LAYOUT.byteSize()); + } + + private static long[] Data4$DIMS = { 8 }; + + /** + * Dimensions for array field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static long[] Data4$dimensions() { + return Data4$DIMS; + } + private static final VarHandle Data4$ELEM_HANDLE = Data4$LAYOUT.varHandle(sequenceElement()); + + /** + * Indexed getter for field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static byte Data4(MemorySegment struct, long index0) { + return (byte)Data4$ELEM_HANDLE.get(struct, 0L, index0); + } + + /** + * Indexed setter for field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static void Data4(MemorySegment struct, long index0, byte fieldValue) { + Data4$ELEM_HANDLE.set(struct, 0L, index0, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java index c1b5e09f..1738fc5c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java @@ -3,115 +3,264 @@ package net.codecrete.usb.windows.gen.setupapi; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfLong; + /** - * {@snippet : + * {@snippet lang=c : * struct _SP_DEVICE_INTERFACE_DATA { * DWORD cbSize; * GUID InterfaceClassGuid; * DWORD Flags; * ULONG_PTR Reserved; - * }; + * } * } */ public class _SP_DEVICE_INTERFACE_DATA { - public static MemoryLayout $LAYOUT() { - return constants$1.const$0; + _SP_DEVICE_INTERFACE_DATA() { + // Should not be called directly } - public static VarHandle cbSize$VH() { - return constants$1.const$1; + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + SetupAPI.C_LONG.withName("cbSize"), + _GUID.layout().withName("InterfaceClassGuid"), + SetupAPI.C_LONG.withName("Flags"), + SetupAPI.C_LONG_LONG.withName("Reserved") + ).withName("_SP_DEVICE_INTERFACE_DATA"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } + + private static final OfInt cbSize$LAYOUT = (OfInt)$LAYOUT.select(groupElement("cbSize")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD cbSize + * } + */ + public static final OfInt cbSize$layout() { + return cbSize$LAYOUT; + } + + private static final long cbSize$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD cbSize + * } + */ + public static final long cbSize$offset() { + return cbSize$OFFSET; + } + /** * Getter for field: - * {@snippet : - * DWORD cbSize; + * {@snippet lang=c : + * DWORD cbSize * } */ - public static int cbSize$get(MemorySegment seg) { - return (int)constants$1.const$1.get(seg); + public static int cbSize(MemorySegment struct) { + return struct.get(cbSize$LAYOUT, cbSize$OFFSET); } + /** * Setter for field: - * {@snippet : - * DWORD cbSize; + * {@snippet lang=c : + * DWORD cbSize * } */ - public static void cbSize$set(MemorySegment seg, int x) { - constants$1.const$1.set(seg, x); + public static void cbSize(MemorySegment struct, int fieldValue) { + struct.set(cbSize$LAYOUT, cbSize$OFFSET, fieldValue); } - public static int cbSize$get(MemorySegment seg, long index) { - return (int)constants$1.const$1.get(seg.asSlice(index*sizeof())); + + private static final GroupLayout InterfaceClassGuid$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("InterfaceClassGuid")); + + /** + * Layout for field: + * {@snippet lang=c : + * GUID InterfaceClassGuid + * } + */ + public static final GroupLayout InterfaceClassGuid$layout() { + return InterfaceClassGuid$LAYOUT; } - public static void cbSize$set(MemorySegment seg, long index, int x) { - constants$1.const$1.set(seg.asSlice(index*sizeof()), x); + + private static final long InterfaceClassGuid$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * GUID InterfaceClassGuid + * } + */ + public static final long InterfaceClassGuid$offset() { + return InterfaceClassGuid$OFFSET; } - public static MemorySegment InterfaceClassGuid$slice(MemorySegment seg) { - return seg.asSlice(4, 16); + + /** + * Getter for field: + * {@snippet lang=c : + * GUID InterfaceClassGuid + * } + */ + public static MemorySegment InterfaceClassGuid(MemorySegment struct) { + return struct.asSlice(InterfaceClassGuid$OFFSET, InterfaceClassGuid$LAYOUT.byteSize()); } - public static VarHandle Flags$VH() { - return constants$1.const$2; + + /** + * Setter for field: + * {@snippet lang=c : + * GUID InterfaceClassGuid + * } + */ + public static void InterfaceClassGuid(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, InterfaceClassGuid$OFFSET, InterfaceClassGuid$LAYOUT.byteSize()); } + + private static final OfInt Flags$LAYOUT = (OfInt)$LAYOUT.select(groupElement("Flags")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD Flags + * } + */ + public static final OfInt Flags$layout() { + return Flags$LAYOUT; + } + + private static final long Flags$OFFSET = 20; + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD Flags + * } + */ + public static final long Flags$offset() { + return Flags$OFFSET; + } + /** * Getter for field: - * {@snippet : - * DWORD Flags; + * {@snippet lang=c : + * DWORD Flags * } */ - public static int Flags$get(MemorySegment seg) { - return (int)constants$1.const$2.get(seg); + public static int Flags(MemorySegment struct) { + return struct.get(Flags$LAYOUT, Flags$OFFSET); } + /** * Setter for field: - * {@snippet : - * DWORD Flags; + * {@snippet lang=c : + * DWORD Flags * } */ - public static void Flags$set(MemorySegment seg, int x) { - constants$1.const$2.set(seg, x); - } - public static int Flags$get(MemorySegment seg, long index) { - return (int)constants$1.const$2.get(seg.asSlice(index*sizeof())); + public static void Flags(MemorySegment struct, int fieldValue) { + struct.set(Flags$LAYOUT, Flags$OFFSET, fieldValue); } - public static void Flags$set(MemorySegment seg, long index, int x) { - constants$1.const$2.set(seg.asSlice(index*sizeof()), x); + + private static final OfLong Reserved$LAYOUT = (OfLong)$LAYOUT.select(groupElement("Reserved")); + + /** + * Layout for field: + * {@snippet lang=c : + * ULONG_PTR Reserved + * } + */ + public static final OfLong Reserved$layout() { + return Reserved$LAYOUT; } - public static VarHandle Reserved$VH() { - return constants$1.const$3; + + private static final long Reserved$OFFSET = 24; + + /** + * Offset for field: + * {@snippet lang=c : + * ULONG_PTR Reserved + * } + */ + public static final long Reserved$offset() { + return Reserved$OFFSET; } + /** * Getter for field: - * {@snippet : - * ULONG_PTR Reserved; + * {@snippet lang=c : + * ULONG_PTR Reserved * } */ - public static long Reserved$get(MemorySegment seg) { - return (long)constants$1.const$3.get(seg); + public static long Reserved(MemorySegment struct) { + return struct.get(Reserved$LAYOUT, Reserved$OFFSET); } + /** * Setter for field: - * {@snippet : - * ULONG_PTR Reserved; + * {@snippet lang=c : + * ULONG_PTR Reserved * } */ - public static void Reserved$set(MemorySegment seg, long x) { - constants$1.const$3.set(seg, x); + public static void Reserved(MemorySegment struct, long fieldValue) { + struct.set(Reserved$LAYOUT, Reserved$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static long Reserved$get(MemorySegment seg, long index) { - return (long)constants$1.const$3.get(seg.asSlice(index*sizeof())); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static void Reserved$set(MemorySegment seg, long index, long x) { - constants$1.const$3.set(seg.asSlice(index*sizeof()), x); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java index 4a837e91..f09c3ed7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java @@ -3,59 +3,208 @@ package net.codecrete.usb.windows.gen.setupapi; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SequenceLayout; import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; +import static java.lang.foreign.ValueLayout.OfInt; + /** - * {@snippet : + * {@snippet lang=c : * struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W { * DWORD cbSize; * WCHAR DevicePath[1]; - * }; + * } * } */ public class _SP_DEVICE_INTERFACE_DETAIL_DATA_W { - public static MemoryLayout $LAYOUT() { - return constants$1.const$4; + _SP_DEVICE_INTERFACE_DETAIL_DATA_W() { + // Should not be called directly } - public static VarHandle cbSize$VH() { - return constants$1.const$5; + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + SetupAPI.C_LONG.withName("cbSize"), + MemoryLayout.sequenceLayout(1, SetupAPI.C_SHORT).withName("DevicePath"), + MemoryLayout.paddingLayout(2) + ).withName("_SP_DEVICE_INTERFACE_DETAIL_DATA_W"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } + + private static final OfInt cbSize$LAYOUT = (OfInt)$LAYOUT.select(groupElement("cbSize")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD cbSize + * } + */ + public static final OfInt cbSize$layout() { + return cbSize$LAYOUT; + } + + private static final long cbSize$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD cbSize + * } + */ + public static final long cbSize$offset() { + return cbSize$OFFSET; + } + /** * Getter for field: - * {@snippet : - * DWORD cbSize; + * {@snippet lang=c : + * DWORD cbSize * } */ - public static int cbSize$get(MemorySegment seg) { - return (int)constants$1.const$5.get(seg); + public static int cbSize(MemorySegment struct) { + return struct.get(cbSize$LAYOUT, cbSize$OFFSET); } + /** * Setter for field: - * {@snippet : - * DWORD cbSize; + * {@snippet lang=c : + * DWORD cbSize * } */ - public static void cbSize$set(MemorySegment seg, int x) { - constants$1.const$5.set(seg, x); + public static void cbSize(MemorySegment struct, int fieldValue) { + struct.set(cbSize$LAYOUT, cbSize$OFFSET, fieldValue); } - public static int cbSize$get(MemorySegment seg, long index) { - return (int)constants$1.const$5.get(seg.asSlice(index*sizeof())); + + private static final SequenceLayout DevicePath$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("DevicePath")); + + /** + * Layout for field: + * {@snippet lang=c : + * WCHAR DevicePath[1] + * } + */ + public static final SequenceLayout DevicePath$layout() { + return DevicePath$LAYOUT; } - public static void cbSize$set(MemorySegment seg, long index, int x) { - constants$1.const$5.set(seg.asSlice(index*sizeof()), x); + + private static final long DevicePath$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * WCHAR DevicePath[1] + * } + */ + public static final long DevicePath$offset() { + return DevicePath$OFFSET; } - public static MemorySegment DevicePath$slice(MemorySegment seg) { - return seg.asSlice(4, 2); + + /** + * Getter for field: + * {@snippet lang=c : + * WCHAR DevicePath[1] + * } + */ + public static MemorySegment DevicePath(MemorySegment struct) { + return struct.asSlice(DevicePath$OFFSET, DevicePath$LAYOUT.byteSize()); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Setter for field: + * {@snippet lang=c : + * WCHAR DevicePath[1] + * } + */ + public static void DevicePath(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, DevicePath$OFFSET, DevicePath$LAYOUT.byteSize()); + } + + private static long[] DevicePath$DIMS = { 1 }; + + /** + * Dimensions for array field: + * {@snippet lang=c : + * WCHAR DevicePath[1] + * } + */ + public static long[] DevicePath$dimensions() { + return DevicePath$DIMS; + } + private static final VarHandle DevicePath$ELEM_HANDLE = DevicePath$LAYOUT.varHandle(sequenceElement()); + + /** + * Indexed getter for field: + * {@snippet lang=c : + * WCHAR DevicePath[1] + * } + */ + public static short DevicePath(MemorySegment struct, long index0) { + return (short)DevicePath$ELEM_HANDLE.get(struct, 0L, index0); + } + + /** + * Indexed setter for field: + * {@snippet lang=c : + * WCHAR DevicePath[1] + * } + */ + public static void DevicePath(MemorySegment struct, long index0, short fieldValue) { + DevicePath$ELEM_HANDLE.set(struct, 0L, index0, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } -} + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java index 8cf558b5..96c0f0cf 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java @@ -3,115 +3,264 @@ package net.codecrete.usb.windows.gen.setupapi; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfLong; + /** - * {@snippet : + * {@snippet lang=c : * struct _SP_DEVINFO_DATA { * DWORD cbSize; * GUID ClassGuid; * DWORD DevInst; * ULONG_PTR Reserved; - * }; + * } * } */ public class _SP_DEVINFO_DATA { - public static MemoryLayout $LAYOUT() { - return constants$0.const$2; + _SP_DEVINFO_DATA() { + // Should not be called directly } - public static VarHandle cbSize$VH() { - return constants$0.const$3; + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + SetupAPI.C_LONG.withName("cbSize"), + _GUID.layout().withName("ClassGuid"), + SetupAPI.C_LONG.withName("DevInst"), + SetupAPI.C_LONG_LONG.withName("Reserved") + ).withName("_SP_DEVINFO_DATA"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } + + private static final OfInt cbSize$LAYOUT = (OfInt)$LAYOUT.select(groupElement("cbSize")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD cbSize + * } + */ + public static final OfInt cbSize$layout() { + return cbSize$LAYOUT; + } + + private static final long cbSize$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD cbSize + * } + */ + public static final long cbSize$offset() { + return cbSize$OFFSET; + } + /** * Getter for field: - * {@snippet : - * DWORD cbSize; + * {@snippet lang=c : + * DWORD cbSize * } */ - public static int cbSize$get(MemorySegment seg) { - return (int)constants$0.const$3.get(seg); + public static int cbSize(MemorySegment struct) { + return struct.get(cbSize$LAYOUT, cbSize$OFFSET); } + /** * Setter for field: - * {@snippet : - * DWORD cbSize; + * {@snippet lang=c : + * DWORD cbSize * } */ - public static void cbSize$set(MemorySegment seg, int x) { - constants$0.const$3.set(seg, x); + public static void cbSize(MemorySegment struct, int fieldValue) { + struct.set(cbSize$LAYOUT, cbSize$OFFSET, fieldValue); } - public static int cbSize$get(MemorySegment seg, long index) { - return (int)constants$0.const$3.get(seg.asSlice(index*sizeof())); + + private static final GroupLayout ClassGuid$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("ClassGuid")); + + /** + * Layout for field: + * {@snippet lang=c : + * GUID ClassGuid + * } + */ + public static final GroupLayout ClassGuid$layout() { + return ClassGuid$LAYOUT; } - public static void cbSize$set(MemorySegment seg, long index, int x) { - constants$0.const$3.set(seg.asSlice(index*sizeof()), x); + + private static final long ClassGuid$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * GUID ClassGuid + * } + */ + public static final long ClassGuid$offset() { + return ClassGuid$OFFSET; } - public static MemorySegment ClassGuid$slice(MemorySegment seg) { - return seg.asSlice(4, 16); + + /** + * Getter for field: + * {@snippet lang=c : + * GUID ClassGuid + * } + */ + public static MemorySegment ClassGuid(MemorySegment struct) { + return struct.asSlice(ClassGuid$OFFSET, ClassGuid$LAYOUT.byteSize()); } - public static VarHandle DevInst$VH() { - return constants$0.const$4; + + /** + * Setter for field: + * {@snippet lang=c : + * GUID ClassGuid + * } + */ + public static void ClassGuid(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, ClassGuid$OFFSET, ClassGuid$LAYOUT.byteSize()); } + + private static final OfInt DevInst$LAYOUT = (OfInt)$LAYOUT.select(groupElement("DevInst")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD DevInst + * } + */ + public static final OfInt DevInst$layout() { + return DevInst$LAYOUT; + } + + private static final long DevInst$OFFSET = 20; + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD DevInst + * } + */ + public static final long DevInst$offset() { + return DevInst$OFFSET; + } + /** * Getter for field: - * {@snippet : - * DWORD DevInst; + * {@snippet lang=c : + * DWORD DevInst * } */ - public static int DevInst$get(MemorySegment seg) { - return (int)constants$0.const$4.get(seg); + public static int DevInst(MemorySegment struct) { + return struct.get(DevInst$LAYOUT, DevInst$OFFSET); } + /** * Setter for field: - * {@snippet : - * DWORD DevInst; + * {@snippet lang=c : + * DWORD DevInst * } */ - public static void DevInst$set(MemorySegment seg, int x) { - constants$0.const$4.set(seg, x); - } - public static int DevInst$get(MemorySegment seg, long index) { - return (int)constants$0.const$4.get(seg.asSlice(index*sizeof())); + public static void DevInst(MemorySegment struct, int fieldValue) { + struct.set(DevInst$LAYOUT, DevInst$OFFSET, fieldValue); } - public static void DevInst$set(MemorySegment seg, long index, int x) { - constants$0.const$4.set(seg.asSlice(index*sizeof()), x); + + private static final OfLong Reserved$LAYOUT = (OfLong)$LAYOUT.select(groupElement("Reserved")); + + /** + * Layout for field: + * {@snippet lang=c : + * ULONG_PTR Reserved + * } + */ + public static final OfLong Reserved$layout() { + return Reserved$LAYOUT; } - public static VarHandle Reserved$VH() { - return constants$0.const$5; + + private static final long Reserved$OFFSET = 24; + + /** + * Offset for field: + * {@snippet lang=c : + * ULONG_PTR Reserved + * } + */ + public static final long Reserved$offset() { + return Reserved$OFFSET; } + /** * Getter for field: - * {@snippet : - * ULONG_PTR Reserved; + * {@snippet lang=c : + * ULONG_PTR Reserved * } */ - public static long Reserved$get(MemorySegment seg) { - return (long)constants$0.const$5.get(seg); + public static long Reserved(MemorySegment struct) { + return struct.get(Reserved$LAYOUT, Reserved$OFFSET); } + /** * Setter for field: - * {@snippet : - * ULONG_PTR Reserved; + * {@snippet lang=c : + * ULONG_PTR Reserved * } */ - public static void Reserved$set(MemorySegment seg, long x) { - constants$0.const$5.set(seg, x); + public static void Reserved(MemorySegment struct, long fieldValue) { + struct.set(Reserved$LAYOUT, Reserved$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static long Reserved$get(MemorySegment seg, long index) { - return (long)constants$0.const$5.get(seg.asSlice(index*sizeof())); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static void Reserved$set(MemorySegment seg, long index, long x) { - constants$0.const$5.set(seg.asSlice(index*sizeof()), x); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java deleted file mode 100644 index 0a5f6a70..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$0.java +++ /dev/null @@ -1,43 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.setupapi; - -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final StructLayout const$0 = MemoryLayout.structLayout( - MemoryLayout.structLayout( - JAVA_INT.withName("Data1"), - JAVA_SHORT.withName("Data2"), - JAVA_SHORT.withName("Data3"), - MemoryLayout.sequenceLayout(8, JAVA_BYTE).withName("Data4") - ).withName("fmtid"), - JAVA_INT.withName("pid") - ).withName("_DEVPROPKEY"); - static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("pid")); - static final StructLayout const$2 = MemoryLayout.structLayout( - JAVA_INT.withName("cbSize"), - MemoryLayout.structLayout( - JAVA_INT.withName("Data1"), - JAVA_SHORT.withName("Data2"), - JAVA_SHORT.withName("Data3"), - MemoryLayout.sequenceLayout(8, JAVA_BYTE).withName("Data4") - ).withName("ClassGuid"), - JAVA_INT.withName("DevInst"), - JAVA_LONG.withName("Reserved") - ).withName("_SP_DEVINFO_DATA"); - static final VarHandle const$3 = constants$0.const$2.varHandle(MemoryLayout.PathElement.groupElement("cbSize")); - static final VarHandle const$4 = constants$0.const$2.varHandle(MemoryLayout.PathElement.groupElement("DevInst")); - static final VarHandle const$5 = constants$0.const$2.varHandle(MemoryLayout.PathElement.groupElement("Reserved")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java deleted file mode 100644 index 7c75f955..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$1.java +++ /dev/null @@ -1,39 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.setupapi; - -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -final class constants$1 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$1() {} - static final StructLayout const$0 = MemoryLayout.structLayout( - JAVA_INT.withName("cbSize"), - MemoryLayout.structLayout( - JAVA_INT.withName("Data1"), - JAVA_SHORT.withName("Data2"), - JAVA_SHORT.withName("Data3"), - MemoryLayout.sequenceLayout(8, JAVA_BYTE).withName("Data4") - ).withName("InterfaceClassGuid"), - JAVA_INT.withName("Flags"), - JAVA_LONG.withName("Reserved") - ).withName("_SP_DEVICE_INTERFACE_DATA"); - static final VarHandle const$1 = constants$1.const$0.varHandle(MemoryLayout.PathElement.groupElement("cbSize")); - static final VarHandle const$2 = constants$1.const$0.varHandle(MemoryLayout.PathElement.groupElement("Flags")); - static final VarHandle const$3 = constants$1.const$0.varHandle(MemoryLayout.PathElement.groupElement("Reserved")); - static final StructLayout const$4 = MemoryLayout.structLayout( - JAVA_INT.withName("cbSize"), - MemoryLayout.sequenceLayout(1, JAVA_SHORT).withName("DevicePath"), - MemoryLayout.paddingLayout(2) - ).withName("_SP_DEVICE_INTERFACE_DETAIL_DATA_W"); - static final VarHandle const$5 = constants$1.const$4.varHandle(MemoryLayout.PathElement.groupElement("cbSize")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$2.java deleted file mode 100644 index 5c778a87..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/constants$2.java +++ /dev/null @@ -1,30 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.setupapi; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$2 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$2() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER - ); - static final MethodHandle const$1 = RuntimeHelper.downcallHandle( - "SetupDiDestroyDeviceInfoList", - constants$2.const$0 - ); - static final FunctionDescriptor const$2 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$3 = RuntimeHelper.downcallHandle( - "SetupDiDeleteDeviceInterfaceData", - constants$2.const$2 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java deleted file mode 100644 index 31f89ede..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/RuntimeHelper.java +++ /dev/null @@ -1,239 +0,0 @@ -package net.codecrete.usb.windows.gen.usbioctl; -// Generated by jextract - -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_LONG; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { - - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java index 355093d3..871db75b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java @@ -3,45 +3,80 @@ package net.codecrete.usb.windows.gen.usbioctl; import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_FLOAT; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -import static java.lang.foreign.ValueLayout.OfByte; -import static java.lang.foreign.ValueLayout.OfDouble; -import static java.lang.foreign.ValueLayout.OfFloat; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfLong; -import static java.lang.foreign.ValueLayout.OfShort; -public class USBIoctl { - - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfInt C_LONG = JAVA_INT; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; + +public class USBIoctl { + + USBIoctl() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfInt C_LONG = ValueLayout.JAVA_INT; + public static final ValueLayout.OfDouble C_LONG_DOUBLE = ValueLayout.JAVA_DOUBLE; + private static final int IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION = (int)2229264L; /** - * {@snippet : + * {@snippet lang=c : * #define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 2229264 * } */ public static int IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION() { - return (int)2229264L; + return IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION; } + private static final int IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX = (int)2229320L; /** - * {@snippet : + * {@snippet lang=c : * #define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX 2229320 * } */ public static int IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX() { - return (int)2229320L; + return IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX; } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USB_DESCRIPTOR_REQUEST.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USB_DESCRIPTOR_REQUEST.java deleted file mode 100644 index 6a5de025..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USB_DESCRIPTOR_REQUEST.java +++ /dev/null @@ -1,16 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.usbioctl; - -/** - * {@snippet : - * typedef struct _USB_DESCRIPTOR_REQUEST USB_DESCRIPTOR_REQUEST; - * } - */ -public final class USB_DESCRIPTOR_REQUEST extends _USB_DESCRIPTOR_REQUEST { - - // Suppresses default constructor, ensuring non-instantiability. - private USB_DESCRIPTOR_REQUEST() {} -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USB_NODE_CONNECTION_INFORMATION_EX.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USB_NODE_CONNECTION_INFORMATION_EX.java deleted file mode 100644 index 9750d300..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USB_NODE_CONNECTION_INFORMATION_EX.java +++ /dev/null @@ -1,16 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.usbioctl; - -/** - * {@snippet : - * typedef struct _USB_NODE_CONNECTION_INFORMATION_EX USB_NODE_CONNECTION_INFORMATION_EX; - * } - */ -public final class USB_NODE_CONNECTION_INFORMATION_EX extends _USB_NODE_CONNECTION_INFORMATION_EX { - - // Suppresses default constructor, ensuring non-instantiability. - private USB_NODE_CONNECTION_INFORMATION_EX() {} -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java index 38d3f92f..ddc3f3be 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java @@ -3,221 +3,582 @@ package net.codecrete.usb.windows.gen.usbioctl; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SequenceLayout; import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; +import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfShort; + /** - * {@snippet : + * {@snippet lang=c : * struct _USB_DESCRIPTOR_REQUEST { * ULONG ConnectionIndex; - * struct SetupPacket; + * struct { + * UCHAR bmRequest; + * UCHAR bRequest; + * USHORT wValue; + * USHORT wIndex; + * USHORT wLength; + * } SetupPacket; * UCHAR Data[0]; - * }; + * } * } */ public class _USB_DESCRIPTOR_REQUEST { - public static MemoryLayout $LAYOUT() { - return constants$0.const$0; + _USB_DESCRIPTOR_REQUEST() { + // Should not be called directly } - public static VarHandle ConnectionIndex$VH() { - return constants$0.const$1; + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + USBIoctl.C_LONG.withByteAlignment(1).withName("ConnectionIndex"), + _USB_DESCRIPTOR_REQUEST.SetupPacket.layout().withName("SetupPacket"), + MemoryLayout.sequenceLayout(0, USBIoctl.C_CHAR).withName("Data") + ).withName("_USB_DESCRIPTOR_REQUEST"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } + + private static final OfInt ConnectionIndex$LAYOUT = (OfInt)$LAYOUT.select(groupElement("ConnectionIndex")); + /** - * Getter for field: - * {@snippet : - * ULONG ConnectionIndex; + * Layout for field: + * {@snippet lang=c : + * ULONG ConnectionIndex * } */ - public static int ConnectionIndex$get(MemorySegment seg) { - return (int)constants$0.const$1.get(seg); + public static final OfInt ConnectionIndex$layout() { + return ConnectionIndex$LAYOUT; } + + private static final long ConnectionIndex$OFFSET = 0; + /** - * Setter for field: - * {@snippet : - * ULONG ConnectionIndex; + * Offset for field: + * {@snippet lang=c : + * ULONG ConnectionIndex * } */ - public static void ConnectionIndex$set(MemorySegment seg, int x) { - constants$0.const$1.set(seg, x); + public static final long ConnectionIndex$offset() { + return ConnectionIndex$OFFSET; } - public static int ConnectionIndex$get(MemorySegment seg, long index) { - return (int)constants$0.const$1.get(seg.asSlice(index*sizeof())); + + /** + * Getter for field: + * {@snippet lang=c : + * ULONG ConnectionIndex + * } + */ + public static int ConnectionIndex(MemorySegment struct) { + return struct.get(ConnectionIndex$LAYOUT, ConnectionIndex$OFFSET); } - public static void ConnectionIndex$set(MemorySegment seg, long index, int x) { - constants$0.const$1.set(seg.asSlice(index*sizeof()), x); + + /** + * Setter for field: + * {@snippet lang=c : + * ULONG ConnectionIndex + * } + */ + public static void ConnectionIndex(MemorySegment struct, int fieldValue) { + struct.set(ConnectionIndex$LAYOUT, ConnectionIndex$OFFSET, fieldValue); } + /** - * {@snippet : + * {@snippet lang=c : * struct { * UCHAR bmRequest; * UCHAR bRequest; * USHORT wValue; * USHORT wIndex; * USHORT wLength; - * }; + * } * } */ - public static final class SetupPacket { + public static class SetupPacket { + + SetupPacket() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + USBIoctl.C_CHAR.withName("bmRequest"), + USBIoctl.C_CHAR.withName("bRequest"), + USBIoctl.C_SHORT.withByteAlignment(1).withName("wValue"), + USBIoctl.C_SHORT.withByteAlignment(1).withName("wIndex"), + USBIoctl.C_SHORT.withByteAlignment(1).withName("wLength") + ).withName("$anon$971:5"); - // Suppresses default constructor, ensuring non-instantiability. - private SetupPacket() {} - public static MemoryLayout $LAYOUT() { - return constants$0.const$2; + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfByte bmRequest$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bmRequest")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR bmRequest + * } + */ + public static final OfByte bmRequest$layout() { + return bmRequest$LAYOUT; } - public static VarHandle bmRequest$VH() { - return constants$0.const$3; + + private static final long bmRequest$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR bmRequest + * } + */ + public static final long bmRequest$offset() { + return bmRequest$OFFSET; } + /** * Getter for field: - * {@snippet : - * UCHAR bmRequest; + * {@snippet lang=c : + * UCHAR bmRequest * } */ - public static byte bmRequest$get(MemorySegment seg) { - return (byte)constants$0.const$3.get(seg); + public static byte bmRequest(MemorySegment struct) { + return struct.get(bmRequest$LAYOUT, bmRequest$OFFSET); } + /** * Setter for field: - * {@snippet : - * UCHAR bmRequest; + * {@snippet lang=c : + * UCHAR bmRequest * } */ - public static void bmRequest$set(MemorySegment seg, byte x) { - constants$0.const$3.set(seg, x); - } - public static byte bmRequest$get(MemorySegment seg, long index) { - return (byte)constants$0.const$3.get(seg.asSlice(index*sizeof())); + public static void bmRequest(MemorySegment struct, byte fieldValue) { + struct.set(bmRequest$LAYOUT, bmRequest$OFFSET, fieldValue); } - public static void bmRequest$set(MemorySegment seg, long index, byte x) { - constants$0.const$3.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte bRequest$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bRequest")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR bRequest + * } + */ + public static final OfByte bRequest$layout() { + return bRequest$LAYOUT; } - public static VarHandle bRequest$VH() { - return constants$0.const$4; + + private static final long bRequest$OFFSET = 1; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR bRequest + * } + */ + public static final long bRequest$offset() { + return bRequest$OFFSET; } + /** * Getter for field: - * {@snippet : - * UCHAR bRequest; + * {@snippet lang=c : + * UCHAR bRequest * } */ - public static byte bRequest$get(MemorySegment seg) { - return (byte)constants$0.const$4.get(seg); + public static byte bRequest(MemorySegment struct) { + return struct.get(bRequest$LAYOUT, bRequest$OFFSET); } + /** * Setter for field: - * {@snippet : - * UCHAR bRequest; + * {@snippet lang=c : + * UCHAR bRequest * } */ - public static void bRequest$set(MemorySegment seg, byte x) { - constants$0.const$4.set(seg, x); + public static void bRequest(MemorySegment struct, byte fieldValue) { + struct.set(bRequest$LAYOUT, bRequest$OFFSET, fieldValue); } - public static byte bRequest$get(MemorySegment seg, long index) { - return (byte)constants$0.const$4.get(seg.asSlice(index*sizeof())); - } - public static void bRequest$set(MemorySegment seg, long index, byte x) { - constants$0.const$4.set(seg.asSlice(index*sizeof()), x); + + private static final OfShort wValue$LAYOUT = (OfShort)$LAYOUT.select(groupElement("wValue")); + + /** + * Layout for field: + * {@snippet lang=c : + * USHORT wValue + * } + */ + public static final OfShort wValue$layout() { + return wValue$LAYOUT; } - public static VarHandle wValue$VH() { - return constants$0.const$5; + + private static final long wValue$OFFSET = 2; + + /** + * Offset for field: + * {@snippet lang=c : + * USHORT wValue + * } + */ + public static final long wValue$offset() { + return wValue$OFFSET; } + /** * Getter for field: - * {@snippet : - * USHORT wValue; + * {@snippet lang=c : + * USHORT wValue * } */ - public static short wValue$get(MemorySegment seg) { - return (short)constants$0.const$5.get(seg); + public static short wValue(MemorySegment struct) { + return struct.get(wValue$LAYOUT, wValue$OFFSET); } + /** * Setter for field: - * {@snippet : - * USHORT wValue; + * {@snippet lang=c : + * USHORT wValue * } */ - public static void wValue$set(MemorySegment seg, short x) { - constants$0.const$5.set(seg, x); - } - public static short wValue$get(MemorySegment seg, long index) { - return (short)constants$0.const$5.get(seg.asSlice(index*sizeof())); + public static void wValue(MemorySegment struct, short fieldValue) { + struct.set(wValue$LAYOUT, wValue$OFFSET, fieldValue); } - public static void wValue$set(MemorySegment seg, long index, short x) { - constants$0.const$5.set(seg.asSlice(index*sizeof()), x); + + private static final OfShort wIndex$LAYOUT = (OfShort)$LAYOUT.select(groupElement("wIndex")); + + /** + * Layout for field: + * {@snippet lang=c : + * USHORT wIndex + * } + */ + public static final OfShort wIndex$layout() { + return wIndex$LAYOUT; } - public static VarHandle wIndex$VH() { - return constants$1.const$0; + + private static final long wIndex$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * USHORT wIndex + * } + */ + public static final long wIndex$offset() { + return wIndex$OFFSET; } + /** * Getter for field: - * {@snippet : - * USHORT wIndex; + * {@snippet lang=c : + * USHORT wIndex * } */ - public static short wIndex$get(MemorySegment seg) { - return (short)constants$1.const$0.get(seg); + public static short wIndex(MemorySegment struct) { + return struct.get(wIndex$LAYOUT, wIndex$OFFSET); } + /** * Setter for field: - * {@snippet : - * USHORT wIndex; + * {@snippet lang=c : + * USHORT wIndex * } */ - public static void wIndex$set(MemorySegment seg, short x) { - constants$1.const$0.set(seg, x); - } - public static short wIndex$get(MemorySegment seg, long index) { - return (short)constants$1.const$0.get(seg.asSlice(index*sizeof())); + public static void wIndex(MemorySegment struct, short fieldValue) { + struct.set(wIndex$LAYOUT, wIndex$OFFSET, fieldValue); } - public static void wIndex$set(MemorySegment seg, long index, short x) { - constants$1.const$0.set(seg.asSlice(index*sizeof()), x); + + private static final OfShort wLength$LAYOUT = (OfShort)$LAYOUT.select(groupElement("wLength")); + + /** + * Layout for field: + * {@snippet lang=c : + * USHORT wLength + * } + */ + public static final OfShort wLength$layout() { + return wLength$LAYOUT; } - public static VarHandle wLength$VH() { - return constants$1.const$1; + + private static final long wLength$OFFSET = 6; + + /** + * Offset for field: + * {@snippet lang=c : + * USHORT wLength + * } + */ + public static final long wLength$offset() { + return wLength$OFFSET; } + /** * Getter for field: - * {@snippet : - * USHORT wLength; + * {@snippet lang=c : + * USHORT wLength * } */ - public static short wLength$get(MemorySegment seg) { - return (short)constants$1.const$1.get(seg); + public static short wLength(MemorySegment struct) { + return struct.get(wLength$LAYOUT, wLength$OFFSET); } + /** * Setter for field: - * {@snippet : - * USHORT wLength; + * {@snippet lang=c : + * USHORT wLength * } */ - public static void wLength$set(MemorySegment seg, short x) { - constants$1.const$1.set(seg, x); + public static void wLength(MemorySegment struct, short fieldValue) { + struct.set(wLength$LAYOUT, wLength$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static short wLength$get(MemorySegment seg, long index) { - return (short)constants$1.const$1.get(seg.asSlice(index*sizeof())); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static void wLength$set(MemorySegment seg, long index, short x) { - constants$1.const$1.set(seg.asSlice(index*sizeof()), x); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } - public static MemorySegment SetupPacket$slice(MemorySegment seg) { - return seg.asSlice(4, 8); + private static final GroupLayout SetupPacket$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("SetupPacket")); + + /** + * Layout for field: + * {@snippet lang=c : + * struct { + * UCHAR bmRequest; + * UCHAR bRequest; + * USHORT wValue; + * USHORT wIndex; + * USHORT wLength; + * } SetupPacket + * } + */ + public static final GroupLayout SetupPacket$layout() { + return SetupPacket$LAYOUT; } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + private static final long SetupPacket$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * struct { + * UCHAR bmRequest; + * UCHAR bRequest; + * USHORT wValue; + * USHORT wIndex; + * USHORT wLength; + * } SetupPacket + * } + */ + public static final long SetupPacket$offset() { + return SetupPacket$OFFSET; } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } -} + /** + * Getter for field: + * {@snippet lang=c : + * struct { + * UCHAR bmRequest; + * UCHAR bRequest; + * USHORT wValue; + * USHORT wIndex; + * USHORT wLength; + * } SetupPacket + * } + */ + public static MemorySegment SetupPacket(MemorySegment struct) { + return struct.asSlice(SetupPacket$OFFSET, SetupPacket$LAYOUT.byteSize()); + } + + /** + * Setter for field: + * {@snippet lang=c : + * struct { + * UCHAR bmRequest; + * UCHAR bRequest; + * USHORT wValue; + * USHORT wIndex; + * USHORT wLength; + * } SetupPacket + * } + */ + public static void SetupPacket(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, SetupPacket$OFFSET, SetupPacket$LAYOUT.byteSize()); + } + + private static final SequenceLayout Data$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("Data")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR Data[0] + * } + */ + public static final SequenceLayout Data$layout() { + return Data$LAYOUT; + } + + private static final long Data$OFFSET = 12; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR Data[0] + * } + */ + public static final long Data$offset() { + return Data$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UCHAR Data[0] + * } + */ + public static MemorySegment Data(MemorySegment struct) { + return struct.asSlice(Data$OFFSET, Data$LAYOUT.byteSize()); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UCHAR Data[0] + * } + */ + public static void Data(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, Data$OFFSET, Data$LAYOUT.byteSize()); + } + + private static long[] Data$DIMS = { 0 }; + + /** + * Dimensions for array field: + * {@snippet lang=c : + * UCHAR Data[0] + * } + */ + public static long[] Data$dimensions() { + return Data$DIMS; + } + private static final VarHandle Data$ELEM_HANDLE = Data$LAYOUT.varHandle(sequenceElement()); + + /** + * Indexed getter for field: + * {@snippet lang=c : + * UCHAR Data[0] + * } + */ + public static byte Data(MemorySegment struct, long index0) { + return (byte)Data$ELEM_HANDLE.get(struct, 0L, index0); + } + + /** + * Indexed setter for field: + * {@snippet lang=c : + * UCHAR Data[0] + * } + */ + public static void Data(MemorySegment struct, long index0, byte fieldValue) { + Data$ELEM_HANDLE.set(struct, 0L, index0, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java new file mode 100644 index 00000000..0bafcbae --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java @@ -0,0 +1,726 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.usbioctl; + +import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.OfShort; + +/** + * {@snippet lang=c : + * struct _USB_DEVICE_DESCRIPTOR { + * UCHAR bLength; + * UCHAR bDescriptorType; + * USHORT bcdUSB; + * UCHAR bDeviceClass; + * UCHAR bDeviceSubClass; + * UCHAR bDeviceProtocol; + * UCHAR bMaxPacketSize0; + * USHORT idVendor; + * USHORT idProduct; + * USHORT bcdDevice; + * UCHAR iManufacturer; + * UCHAR iProduct; + * UCHAR iSerialNumber; + * UCHAR bNumConfigurations; + * } + * } + */ +public class _USB_DEVICE_DESCRIPTOR { + + _USB_DEVICE_DESCRIPTOR() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + USBIoctl.C_CHAR.withName("bLength"), + USBIoctl.C_CHAR.withName("bDescriptorType"), + USBIoctl.C_SHORT.withByteAlignment(1).withName("bcdUSB"), + USBIoctl.C_CHAR.withName("bDeviceClass"), + USBIoctl.C_CHAR.withName("bDeviceSubClass"), + USBIoctl.C_CHAR.withName("bDeviceProtocol"), + USBIoctl.C_CHAR.withName("bMaxPacketSize0"), + USBIoctl.C_SHORT.withByteAlignment(1).withName("idVendor"), + USBIoctl.C_SHORT.withByteAlignment(1).withName("idProduct"), + USBIoctl.C_SHORT.withByteAlignment(1).withName("bcdDevice"), + USBIoctl.C_CHAR.withName("iManufacturer"), + USBIoctl.C_CHAR.withName("iProduct"), + USBIoctl.C_CHAR.withName("iSerialNumber"), + USBIoctl.C_CHAR.withName("bNumConfigurations") + ).withName("_USB_DEVICE_DESCRIPTOR"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfByte bLength$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bLength")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR bLength + * } + */ + public static final OfByte bLength$layout() { + return bLength$LAYOUT; + } + + private static final long bLength$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR bLength + * } + */ + public static final long bLength$offset() { + return bLength$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UCHAR bLength + * } + */ + public static byte bLength(MemorySegment struct) { + return struct.get(bLength$LAYOUT, bLength$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UCHAR bLength + * } + */ + public static void bLength(MemorySegment struct, byte fieldValue) { + struct.set(bLength$LAYOUT, bLength$OFFSET, fieldValue); + } + + private static final OfByte bDescriptorType$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bDescriptorType")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR bDescriptorType + * } + */ + public static final OfByte bDescriptorType$layout() { + return bDescriptorType$LAYOUT; + } + + private static final long bDescriptorType$OFFSET = 1; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR bDescriptorType + * } + */ + public static final long bDescriptorType$offset() { + return bDescriptorType$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UCHAR bDescriptorType + * } + */ + public static byte bDescriptorType(MemorySegment struct) { + return struct.get(bDescriptorType$LAYOUT, bDescriptorType$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UCHAR bDescriptorType + * } + */ + public static void bDescriptorType(MemorySegment struct, byte fieldValue) { + struct.set(bDescriptorType$LAYOUT, bDescriptorType$OFFSET, fieldValue); + } + + private static final OfShort bcdUSB$LAYOUT = (OfShort)$LAYOUT.select(groupElement("bcdUSB")); + + /** + * Layout for field: + * {@snippet lang=c : + * USHORT bcdUSB + * } + */ + public static final OfShort bcdUSB$layout() { + return bcdUSB$LAYOUT; + } + + private static final long bcdUSB$OFFSET = 2; + + /** + * Offset for field: + * {@snippet lang=c : + * USHORT bcdUSB + * } + */ + public static final long bcdUSB$offset() { + return bcdUSB$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * USHORT bcdUSB + * } + */ + public static short bcdUSB(MemorySegment struct) { + return struct.get(bcdUSB$LAYOUT, bcdUSB$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * USHORT bcdUSB + * } + */ + public static void bcdUSB(MemorySegment struct, short fieldValue) { + struct.set(bcdUSB$LAYOUT, bcdUSB$OFFSET, fieldValue); + } + + private static final OfByte bDeviceClass$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bDeviceClass")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR bDeviceClass + * } + */ + public static final OfByte bDeviceClass$layout() { + return bDeviceClass$LAYOUT; + } + + private static final long bDeviceClass$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR bDeviceClass + * } + */ + public static final long bDeviceClass$offset() { + return bDeviceClass$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UCHAR bDeviceClass + * } + */ + public static byte bDeviceClass(MemorySegment struct) { + return struct.get(bDeviceClass$LAYOUT, bDeviceClass$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UCHAR bDeviceClass + * } + */ + public static void bDeviceClass(MemorySegment struct, byte fieldValue) { + struct.set(bDeviceClass$LAYOUT, bDeviceClass$OFFSET, fieldValue); + } + + private static final OfByte bDeviceSubClass$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bDeviceSubClass")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR bDeviceSubClass + * } + */ + public static final OfByte bDeviceSubClass$layout() { + return bDeviceSubClass$LAYOUT; + } + + private static final long bDeviceSubClass$OFFSET = 5; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR bDeviceSubClass + * } + */ + public static final long bDeviceSubClass$offset() { + return bDeviceSubClass$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UCHAR bDeviceSubClass + * } + */ + public static byte bDeviceSubClass(MemorySegment struct) { + return struct.get(bDeviceSubClass$LAYOUT, bDeviceSubClass$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UCHAR bDeviceSubClass + * } + */ + public static void bDeviceSubClass(MemorySegment struct, byte fieldValue) { + struct.set(bDeviceSubClass$LAYOUT, bDeviceSubClass$OFFSET, fieldValue); + } + + private static final OfByte bDeviceProtocol$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bDeviceProtocol")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR bDeviceProtocol + * } + */ + public static final OfByte bDeviceProtocol$layout() { + return bDeviceProtocol$LAYOUT; + } + + private static final long bDeviceProtocol$OFFSET = 6; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR bDeviceProtocol + * } + */ + public static final long bDeviceProtocol$offset() { + return bDeviceProtocol$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UCHAR bDeviceProtocol + * } + */ + public static byte bDeviceProtocol(MemorySegment struct) { + return struct.get(bDeviceProtocol$LAYOUT, bDeviceProtocol$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UCHAR bDeviceProtocol + * } + */ + public static void bDeviceProtocol(MemorySegment struct, byte fieldValue) { + struct.set(bDeviceProtocol$LAYOUT, bDeviceProtocol$OFFSET, fieldValue); + } + + private static final OfByte bMaxPacketSize0$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bMaxPacketSize0")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR bMaxPacketSize0 + * } + */ + public static final OfByte bMaxPacketSize0$layout() { + return bMaxPacketSize0$LAYOUT; + } + + private static final long bMaxPacketSize0$OFFSET = 7; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR bMaxPacketSize0 + * } + */ + public static final long bMaxPacketSize0$offset() { + return bMaxPacketSize0$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UCHAR bMaxPacketSize0 + * } + */ + public static byte bMaxPacketSize0(MemorySegment struct) { + return struct.get(bMaxPacketSize0$LAYOUT, bMaxPacketSize0$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UCHAR bMaxPacketSize0 + * } + */ + public static void bMaxPacketSize0(MemorySegment struct, byte fieldValue) { + struct.set(bMaxPacketSize0$LAYOUT, bMaxPacketSize0$OFFSET, fieldValue); + } + + private static final OfShort idVendor$LAYOUT = (OfShort)$LAYOUT.select(groupElement("idVendor")); + + /** + * Layout for field: + * {@snippet lang=c : + * USHORT idVendor + * } + */ + public static final OfShort idVendor$layout() { + return idVendor$LAYOUT; + } + + private static final long idVendor$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * USHORT idVendor + * } + */ + public static final long idVendor$offset() { + return idVendor$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * USHORT idVendor + * } + */ + public static short idVendor(MemorySegment struct) { + return struct.get(idVendor$LAYOUT, idVendor$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * USHORT idVendor + * } + */ + public static void idVendor(MemorySegment struct, short fieldValue) { + struct.set(idVendor$LAYOUT, idVendor$OFFSET, fieldValue); + } + + private static final OfShort idProduct$LAYOUT = (OfShort)$LAYOUT.select(groupElement("idProduct")); + + /** + * Layout for field: + * {@snippet lang=c : + * USHORT idProduct + * } + */ + public static final OfShort idProduct$layout() { + return idProduct$LAYOUT; + } + + private static final long idProduct$OFFSET = 10; + + /** + * Offset for field: + * {@snippet lang=c : + * USHORT idProduct + * } + */ + public static final long idProduct$offset() { + return idProduct$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * USHORT idProduct + * } + */ + public static short idProduct(MemorySegment struct) { + return struct.get(idProduct$LAYOUT, idProduct$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * USHORT idProduct + * } + */ + public static void idProduct(MemorySegment struct, short fieldValue) { + struct.set(idProduct$LAYOUT, idProduct$OFFSET, fieldValue); + } + + private static final OfShort bcdDevice$LAYOUT = (OfShort)$LAYOUT.select(groupElement("bcdDevice")); + + /** + * Layout for field: + * {@snippet lang=c : + * USHORT bcdDevice + * } + */ + public static final OfShort bcdDevice$layout() { + return bcdDevice$LAYOUT; + } + + private static final long bcdDevice$OFFSET = 12; + + /** + * Offset for field: + * {@snippet lang=c : + * USHORT bcdDevice + * } + */ + public static final long bcdDevice$offset() { + return bcdDevice$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * USHORT bcdDevice + * } + */ + public static short bcdDevice(MemorySegment struct) { + return struct.get(bcdDevice$LAYOUT, bcdDevice$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * USHORT bcdDevice + * } + */ + public static void bcdDevice(MemorySegment struct, short fieldValue) { + struct.set(bcdDevice$LAYOUT, bcdDevice$OFFSET, fieldValue); + } + + private static final OfByte iManufacturer$LAYOUT = (OfByte)$LAYOUT.select(groupElement("iManufacturer")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR iManufacturer + * } + */ + public static final OfByte iManufacturer$layout() { + return iManufacturer$LAYOUT; + } + + private static final long iManufacturer$OFFSET = 14; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR iManufacturer + * } + */ + public static final long iManufacturer$offset() { + return iManufacturer$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UCHAR iManufacturer + * } + */ + public static byte iManufacturer(MemorySegment struct) { + return struct.get(iManufacturer$LAYOUT, iManufacturer$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UCHAR iManufacturer + * } + */ + public static void iManufacturer(MemorySegment struct, byte fieldValue) { + struct.set(iManufacturer$LAYOUT, iManufacturer$OFFSET, fieldValue); + } + + private static final OfByte iProduct$LAYOUT = (OfByte)$LAYOUT.select(groupElement("iProduct")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR iProduct + * } + */ + public static final OfByte iProduct$layout() { + return iProduct$LAYOUT; + } + + private static final long iProduct$OFFSET = 15; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR iProduct + * } + */ + public static final long iProduct$offset() { + return iProduct$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UCHAR iProduct + * } + */ + public static byte iProduct(MemorySegment struct) { + return struct.get(iProduct$LAYOUT, iProduct$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UCHAR iProduct + * } + */ + public static void iProduct(MemorySegment struct, byte fieldValue) { + struct.set(iProduct$LAYOUT, iProduct$OFFSET, fieldValue); + } + + private static final OfByte iSerialNumber$LAYOUT = (OfByte)$LAYOUT.select(groupElement("iSerialNumber")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR iSerialNumber + * } + */ + public static final OfByte iSerialNumber$layout() { + return iSerialNumber$LAYOUT; + } + + private static final long iSerialNumber$OFFSET = 16; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR iSerialNumber + * } + */ + public static final long iSerialNumber$offset() { + return iSerialNumber$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UCHAR iSerialNumber + * } + */ + public static byte iSerialNumber(MemorySegment struct) { + return struct.get(iSerialNumber$LAYOUT, iSerialNumber$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UCHAR iSerialNumber + * } + */ + public static void iSerialNumber(MemorySegment struct, byte fieldValue) { + struct.set(iSerialNumber$LAYOUT, iSerialNumber$OFFSET, fieldValue); + } + + private static final OfByte bNumConfigurations$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bNumConfigurations")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR bNumConfigurations + * } + */ + public static final OfByte bNumConfigurations$layout() { + return bNumConfigurations$LAYOUT; + } + + private static final long bNumConfigurations$OFFSET = 17; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR bNumConfigurations + * } + */ + public static final long bNumConfigurations$offset() { + return bNumConfigurations$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UCHAR bNumConfigurations + * } + */ + public static byte bNumConfigurations(MemorySegment struct) { + return struct.get(bNumConfigurations$LAYOUT, bNumConfigurations$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UCHAR bNumConfigurations + * } + */ + public static void bNumConfigurations(MemorySegment struct, byte fieldValue) { + struct.set(bNumConfigurations$LAYOUT, bNumConfigurations$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_ENDPOINT_DESCRIPTOR.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_ENDPOINT_DESCRIPTOR.java new file mode 100644 index 00000000..fc746185 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_ENDPOINT_DESCRIPTOR.java @@ -0,0 +1,358 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.usbioctl; + +import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.OfShort; + +/** + * {@snippet lang=c : + * struct _USB_ENDPOINT_DESCRIPTOR { + * UCHAR bLength; + * UCHAR bDescriptorType; + * UCHAR bEndpointAddress; + * UCHAR bmAttributes; + * USHORT wMaxPacketSize; + * UCHAR bInterval; + * } + * } + */ +public class _USB_ENDPOINT_DESCRIPTOR { + + _USB_ENDPOINT_DESCRIPTOR() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + USBIoctl.C_CHAR.withName("bLength"), + USBIoctl.C_CHAR.withName("bDescriptorType"), + USBIoctl.C_CHAR.withName("bEndpointAddress"), + USBIoctl.C_CHAR.withName("bmAttributes"), + USBIoctl.C_SHORT.withByteAlignment(1).withName("wMaxPacketSize"), + USBIoctl.C_CHAR.withName("bInterval") + ).withName("_USB_ENDPOINT_DESCRIPTOR"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfByte bLength$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bLength")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR bLength + * } + */ + public static final OfByte bLength$layout() { + return bLength$LAYOUT; + } + + private static final long bLength$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR bLength + * } + */ + public static final long bLength$offset() { + return bLength$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UCHAR bLength + * } + */ + public static byte bLength(MemorySegment struct) { + return struct.get(bLength$LAYOUT, bLength$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UCHAR bLength + * } + */ + public static void bLength(MemorySegment struct, byte fieldValue) { + struct.set(bLength$LAYOUT, bLength$OFFSET, fieldValue); + } + + private static final OfByte bDescriptorType$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bDescriptorType")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR bDescriptorType + * } + */ + public static final OfByte bDescriptorType$layout() { + return bDescriptorType$LAYOUT; + } + + private static final long bDescriptorType$OFFSET = 1; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR bDescriptorType + * } + */ + public static final long bDescriptorType$offset() { + return bDescriptorType$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UCHAR bDescriptorType + * } + */ + public static byte bDescriptorType(MemorySegment struct) { + return struct.get(bDescriptorType$LAYOUT, bDescriptorType$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UCHAR bDescriptorType + * } + */ + public static void bDescriptorType(MemorySegment struct, byte fieldValue) { + struct.set(bDescriptorType$LAYOUT, bDescriptorType$OFFSET, fieldValue); + } + + private static final OfByte bEndpointAddress$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bEndpointAddress")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR bEndpointAddress + * } + */ + public static final OfByte bEndpointAddress$layout() { + return bEndpointAddress$LAYOUT; + } + + private static final long bEndpointAddress$OFFSET = 2; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR bEndpointAddress + * } + */ + public static final long bEndpointAddress$offset() { + return bEndpointAddress$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UCHAR bEndpointAddress + * } + */ + public static byte bEndpointAddress(MemorySegment struct) { + return struct.get(bEndpointAddress$LAYOUT, bEndpointAddress$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UCHAR bEndpointAddress + * } + */ + public static void bEndpointAddress(MemorySegment struct, byte fieldValue) { + struct.set(bEndpointAddress$LAYOUT, bEndpointAddress$OFFSET, fieldValue); + } + + private static final OfByte bmAttributes$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bmAttributes")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR bmAttributes + * } + */ + public static final OfByte bmAttributes$layout() { + return bmAttributes$LAYOUT; + } + + private static final long bmAttributes$OFFSET = 3; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR bmAttributes + * } + */ + public static final long bmAttributes$offset() { + return bmAttributes$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UCHAR bmAttributes + * } + */ + public static byte bmAttributes(MemorySegment struct) { + return struct.get(bmAttributes$LAYOUT, bmAttributes$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UCHAR bmAttributes + * } + */ + public static void bmAttributes(MemorySegment struct, byte fieldValue) { + struct.set(bmAttributes$LAYOUT, bmAttributes$OFFSET, fieldValue); + } + + private static final OfShort wMaxPacketSize$LAYOUT = (OfShort)$LAYOUT.select(groupElement("wMaxPacketSize")); + + /** + * Layout for field: + * {@snippet lang=c : + * USHORT wMaxPacketSize + * } + */ + public static final OfShort wMaxPacketSize$layout() { + return wMaxPacketSize$LAYOUT; + } + + private static final long wMaxPacketSize$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * USHORT wMaxPacketSize + * } + */ + public static final long wMaxPacketSize$offset() { + return wMaxPacketSize$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * USHORT wMaxPacketSize + * } + */ + public static short wMaxPacketSize(MemorySegment struct) { + return struct.get(wMaxPacketSize$LAYOUT, wMaxPacketSize$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * USHORT wMaxPacketSize + * } + */ + public static void wMaxPacketSize(MemorySegment struct, short fieldValue) { + struct.set(wMaxPacketSize$LAYOUT, wMaxPacketSize$OFFSET, fieldValue); + } + + private static final OfByte bInterval$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bInterval")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR bInterval + * } + */ + public static final OfByte bInterval$layout() { + return bInterval$LAYOUT; + } + + private static final long bInterval$OFFSET = 6; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR bInterval + * } + */ + public static final long bInterval$offset() { + return bInterval$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UCHAR bInterval + * } + */ + public static byte bInterval(MemorySegment struct) { + return struct.get(bInterval$LAYOUT, bInterval$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UCHAR bInterval + * } + */ + public static void bInterval(MemorySegment struct, byte fieldValue) { + struct.set(bInterval$LAYOUT, bInterval$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java index 4527cdee..1b98e0b1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java @@ -3,12 +3,22 @@ package net.codecrete.usb.windows.gen.usbioctl; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.lang.foreign.SequenceLayout; +import java.lang.invoke.MethodHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; +import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfShort; + /** - * {@snippet : + * {@snippet lang=c : * struct _USB_NODE_CONNECTION_INFORMATION_EX { * ULONG ConnectionIndex; * USB_DEVICE_DESCRIPTOR DeviceDescriptor; @@ -19,212 +29,509 @@ * ULONG NumberOfOpenPipes; * USB_CONNECTION_STATUS ConnectionStatus; * USB_PIPE_INFO PipeList[0]; - * }; + * } * } */ public class _USB_NODE_CONNECTION_INFORMATION_EX { - public static MemoryLayout $LAYOUT() { - return constants$1.const$2; + _USB_NODE_CONNECTION_INFORMATION_EX() { + // Should not be called directly } - public static VarHandle ConnectionIndex$VH() { - return constants$1.const$3; + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + USBIoctl.C_LONG.withByteAlignment(1).withName("ConnectionIndex"), + _USB_DEVICE_DESCRIPTOR.layout().withName("DeviceDescriptor"), + USBIoctl.C_CHAR.withName("CurrentConfigurationValue"), + USBIoctl.C_CHAR.withName("Speed"), + USBIoctl.C_CHAR.withName("DeviceIsHub"), + USBIoctl.C_SHORT.withByteAlignment(1).withName("DeviceAddress"), + USBIoctl.C_LONG.withByteAlignment(1).withName("NumberOfOpenPipes"), + USBIoctl.C_INT.withByteAlignment(1).withName("ConnectionStatus"), + MemoryLayout.sequenceLayout(0, _USB_PIPE_INFO.layout()).withName("PipeList") + ).withName("_USB_NODE_CONNECTION_INFORMATION_EX"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } + + private static final OfInt ConnectionIndex$LAYOUT = (OfInt)$LAYOUT.select(groupElement("ConnectionIndex")); + + /** + * Layout for field: + * {@snippet lang=c : + * ULONG ConnectionIndex + * } + */ + public static final OfInt ConnectionIndex$layout() { + return ConnectionIndex$LAYOUT; + } + + private static final long ConnectionIndex$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * ULONG ConnectionIndex + * } + */ + public static final long ConnectionIndex$offset() { + return ConnectionIndex$OFFSET; + } + /** * Getter for field: - * {@snippet : - * ULONG ConnectionIndex; + * {@snippet lang=c : + * ULONG ConnectionIndex * } */ - public static int ConnectionIndex$get(MemorySegment seg) { - return (int)constants$1.const$3.get(seg); + public static int ConnectionIndex(MemorySegment struct) { + return struct.get(ConnectionIndex$LAYOUT, ConnectionIndex$OFFSET); } + /** * Setter for field: - * {@snippet : - * ULONG ConnectionIndex; + * {@snippet lang=c : + * ULONG ConnectionIndex * } */ - public static void ConnectionIndex$set(MemorySegment seg, int x) { - constants$1.const$3.set(seg, x); + public static void ConnectionIndex(MemorySegment struct, int fieldValue) { + struct.set(ConnectionIndex$LAYOUT, ConnectionIndex$OFFSET, fieldValue); } - public static int ConnectionIndex$get(MemorySegment seg, long index) { - return (int)constants$1.const$3.get(seg.asSlice(index*sizeof())); + + private static final GroupLayout DeviceDescriptor$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("DeviceDescriptor")); + + /** + * Layout for field: + * {@snippet lang=c : + * USB_DEVICE_DESCRIPTOR DeviceDescriptor + * } + */ + public static final GroupLayout DeviceDescriptor$layout() { + return DeviceDescriptor$LAYOUT; + } + + private static final long DeviceDescriptor$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * USB_DEVICE_DESCRIPTOR DeviceDescriptor + * } + */ + public static final long DeviceDescriptor$offset() { + return DeviceDescriptor$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * USB_DEVICE_DESCRIPTOR DeviceDescriptor + * } + */ + public static MemorySegment DeviceDescriptor(MemorySegment struct) { + return struct.asSlice(DeviceDescriptor$OFFSET, DeviceDescriptor$LAYOUT.byteSize()); } - public static void ConnectionIndex$set(MemorySegment seg, long index, int x) { - constants$1.const$3.set(seg.asSlice(index*sizeof()), x); + + /** + * Setter for field: + * {@snippet lang=c : + * USB_DEVICE_DESCRIPTOR DeviceDescriptor + * } + */ + public static void DeviceDescriptor(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, DeviceDescriptor$OFFSET, DeviceDescriptor$LAYOUT.byteSize()); } - public static MemorySegment DeviceDescriptor$slice(MemorySegment seg) { - return seg.asSlice(4, 18); + + private static final OfByte CurrentConfigurationValue$LAYOUT = (OfByte)$LAYOUT.select(groupElement("CurrentConfigurationValue")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR CurrentConfigurationValue + * } + */ + public static final OfByte CurrentConfigurationValue$layout() { + return CurrentConfigurationValue$LAYOUT; } - public static VarHandle CurrentConfigurationValue$VH() { - return constants$1.const$4; + + private static final long CurrentConfigurationValue$OFFSET = 22; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR CurrentConfigurationValue + * } + */ + public static final long CurrentConfigurationValue$offset() { + return CurrentConfigurationValue$OFFSET; } + /** * Getter for field: - * {@snippet : - * UCHAR CurrentConfigurationValue; + * {@snippet lang=c : + * UCHAR CurrentConfigurationValue * } */ - public static byte CurrentConfigurationValue$get(MemorySegment seg) { - return (byte)constants$1.const$4.get(seg); + public static byte CurrentConfigurationValue(MemorySegment struct) { + return struct.get(CurrentConfigurationValue$LAYOUT, CurrentConfigurationValue$OFFSET); } + /** * Setter for field: - * {@snippet : - * UCHAR CurrentConfigurationValue; + * {@snippet lang=c : + * UCHAR CurrentConfigurationValue * } */ - public static void CurrentConfigurationValue$set(MemorySegment seg, byte x) { - constants$1.const$4.set(seg, x); - } - public static byte CurrentConfigurationValue$get(MemorySegment seg, long index) { - return (byte)constants$1.const$4.get(seg.asSlice(index*sizeof())); + public static void CurrentConfigurationValue(MemorySegment struct, byte fieldValue) { + struct.set(CurrentConfigurationValue$LAYOUT, CurrentConfigurationValue$OFFSET, fieldValue); } - public static void CurrentConfigurationValue$set(MemorySegment seg, long index, byte x) { - constants$1.const$4.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte Speed$LAYOUT = (OfByte)$LAYOUT.select(groupElement("Speed")); + + /** + * Layout for field: + * {@snippet lang=c : + * UCHAR Speed + * } + */ + public static final OfByte Speed$layout() { + return Speed$LAYOUT; } - public static VarHandle Speed$VH() { - return constants$1.const$5; + + private static final long Speed$OFFSET = 23; + + /** + * Offset for field: + * {@snippet lang=c : + * UCHAR Speed + * } + */ + public static final long Speed$offset() { + return Speed$OFFSET; } + /** * Getter for field: - * {@snippet : - * UCHAR Speed; + * {@snippet lang=c : + * UCHAR Speed * } */ - public static byte Speed$get(MemorySegment seg) { - return (byte)constants$1.const$5.get(seg); + public static byte Speed(MemorySegment struct) { + return struct.get(Speed$LAYOUT, Speed$OFFSET); } + /** * Setter for field: - * {@snippet : - * UCHAR Speed; + * {@snippet lang=c : + * UCHAR Speed * } */ - public static void Speed$set(MemorySegment seg, byte x) { - constants$1.const$5.set(seg, x); + public static void Speed(MemorySegment struct, byte fieldValue) { + struct.set(Speed$LAYOUT, Speed$OFFSET, fieldValue); } - public static byte Speed$get(MemorySegment seg, long index) { - return (byte)constants$1.const$5.get(seg.asSlice(index*sizeof())); - } - public static void Speed$set(MemorySegment seg, long index, byte x) { - constants$1.const$5.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte DeviceIsHub$LAYOUT = (OfByte)$LAYOUT.select(groupElement("DeviceIsHub")); + + /** + * Layout for field: + * {@snippet lang=c : + * BOOLEAN DeviceIsHub + * } + */ + public static final OfByte DeviceIsHub$layout() { + return DeviceIsHub$LAYOUT; } - public static VarHandle DeviceIsHub$VH() { - return constants$2.const$0; + + private static final long DeviceIsHub$OFFSET = 24; + + /** + * Offset for field: + * {@snippet lang=c : + * BOOLEAN DeviceIsHub + * } + */ + public static final long DeviceIsHub$offset() { + return DeviceIsHub$OFFSET; } + /** * Getter for field: - * {@snippet : - * BOOLEAN DeviceIsHub; + * {@snippet lang=c : + * BOOLEAN DeviceIsHub * } */ - public static byte DeviceIsHub$get(MemorySegment seg) { - return (byte)constants$2.const$0.get(seg); + public static byte DeviceIsHub(MemorySegment struct) { + return struct.get(DeviceIsHub$LAYOUT, DeviceIsHub$OFFSET); } + /** * Setter for field: - * {@snippet : - * BOOLEAN DeviceIsHub; + * {@snippet lang=c : + * BOOLEAN DeviceIsHub * } */ - public static void DeviceIsHub$set(MemorySegment seg, byte x) { - constants$2.const$0.set(seg, x); - } - public static byte DeviceIsHub$get(MemorySegment seg, long index) { - return (byte)constants$2.const$0.get(seg.asSlice(index*sizeof())); + public static void DeviceIsHub(MemorySegment struct, byte fieldValue) { + struct.set(DeviceIsHub$LAYOUT, DeviceIsHub$OFFSET, fieldValue); } - public static void DeviceIsHub$set(MemorySegment seg, long index, byte x) { - constants$2.const$0.set(seg.asSlice(index*sizeof()), x); + + private static final OfShort DeviceAddress$LAYOUT = (OfShort)$LAYOUT.select(groupElement("DeviceAddress")); + + /** + * Layout for field: + * {@snippet lang=c : + * USHORT DeviceAddress + * } + */ + public static final OfShort DeviceAddress$layout() { + return DeviceAddress$LAYOUT; } - public static VarHandle DeviceAddress$VH() { - return constants$2.const$1; + + private static final long DeviceAddress$OFFSET = 25; + + /** + * Offset for field: + * {@snippet lang=c : + * USHORT DeviceAddress + * } + */ + public static final long DeviceAddress$offset() { + return DeviceAddress$OFFSET; } + /** * Getter for field: - * {@snippet : - * USHORT DeviceAddress; + * {@snippet lang=c : + * USHORT DeviceAddress * } */ - public static short DeviceAddress$get(MemorySegment seg) { - return (short)constants$2.const$1.get(seg); + public static short DeviceAddress(MemorySegment struct) { + return struct.get(DeviceAddress$LAYOUT, DeviceAddress$OFFSET); } + /** * Setter for field: - * {@snippet : - * USHORT DeviceAddress; + * {@snippet lang=c : + * USHORT DeviceAddress * } */ - public static void DeviceAddress$set(MemorySegment seg, short x) { - constants$2.const$1.set(seg, x); - } - public static short DeviceAddress$get(MemorySegment seg, long index) { - return (short)constants$2.const$1.get(seg.asSlice(index*sizeof())); + public static void DeviceAddress(MemorySegment struct, short fieldValue) { + struct.set(DeviceAddress$LAYOUT, DeviceAddress$OFFSET, fieldValue); } - public static void DeviceAddress$set(MemorySegment seg, long index, short x) { - constants$2.const$1.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt NumberOfOpenPipes$LAYOUT = (OfInt)$LAYOUT.select(groupElement("NumberOfOpenPipes")); + + /** + * Layout for field: + * {@snippet lang=c : + * ULONG NumberOfOpenPipes + * } + */ + public static final OfInt NumberOfOpenPipes$layout() { + return NumberOfOpenPipes$LAYOUT; } - public static VarHandle NumberOfOpenPipes$VH() { - return constants$2.const$2; + + private static final long NumberOfOpenPipes$OFFSET = 27; + + /** + * Offset for field: + * {@snippet lang=c : + * ULONG NumberOfOpenPipes + * } + */ + public static final long NumberOfOpenPipes$offset() { + return NumberOfOpenPipes$OFFSET; } + /** * Getter for field: - * {@snippet : - * ULONG NumberOfOpenPipes; + * {@snippet lang=c : + * ULONG NumberOfOpenPipes * } */ - public static int NumberOfOpenPipes$get(MemorySegment seg) { - return (int)constants$2.const$2.get(seg); + public static int NumberOfOpenPipes(MemorySegment struct) { + return struct.get(NumberOfOpenPipes$LAYOUT, NumberOfOpenPipes$OFFSET); } + /** * Setter for field: - * {@snippet : - * ULONG NumberOfOpenPipes; + * {@snippet lang=c : + * ULONG NumberOfOpenPipes * } */ - public static void NumberOfOpenPipes$set(MemorySegment seg, int x) { - constants$2.const$2.set(seg, x); + public static void NumberOfOpenPipes(MemorySegment struct, int fieldValue) { + struct.set(NumberOfOpenPipes$LAYOUT, NumberOfOpenPipes$OFFSET, fieldValue); } - public static int NumberOfOpenPipes$get(MemorySegment seg, long index) { - return (int)constants$2.const$2.get(seg.asSlice(index*sizeof())); + + private static final OfInt ConnectionStatus$LAYOUT = (OfInt)$LAYOUT.select(groupElement("ConnectionStatus")); + + /** + * Layout for field: + * {@snippet lang=c : + * USB_CONNECTION_STATUS ConnectionStatus + * } + */ + public static final OfInt ConnectionStatus$layout() { + return ConnectionStatus$LAYOUT; } - public static void NumberOfOpenPipes$set(MemorySegment seg, long index, int x) { - constants$2.const$2.set(seg.asSlice(index*sizeof()), x); + + private static final long ConnectionStatus$OFFSET = 31; + + /** + * Offset for field: + * {@snippet lang=c : + * USB_CONNECTION_STATUS ConnectionStatus + * } + */ + public static final long ConnectionStatus$offset() { + return ConnectionStatus$OFFSET; } - public static VarHandle ConnectionStatus$VH() { - return constants$2.const$3; + + /** + * Getter for field: + * {@snippet lang=c : + * USB_CONNECTION_STATUS ConnectionStatus + * } + */ + public static int ConnectionStatus(MemorySegment struct) { + return struct.get(ConnectionStatus$LAYOUT, ConnectionStatus$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * USB_CONNECTION_STATUS ConnectionStatus + * } + */ + public static void ConnectionStatus(MemorySegment struct, int fieldValue) { + struct.set(ConnectionStatus$LAYOUT, ConnectionStatus$OFFSET, fieldValue); } + + private static final SequenceLayout PipeList$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("PipeList")); + + /** + * Layout for field: + * {@snippet lang=c : + * USB_PIPE_INFO PipeList[0] + * } + */ + public static final SequenceLayout PipeList$layout() { + return PipeList$LAYOUT; + } + + private static final long PipeList$OFFSET = 35; + + /** + * Offset for field: + * {@snippet lang=c : + * USB_PIPE_INFO PipeList[0] + * } + */ + public static final long PipeList$offset() { + return PipeList$OFFSET; + } + /** * Getter for field: - * {@snippet : - * USB_CONNECTION_STATUS ConnectionStatus; + * {@snippet lang=c : + * USB_PIPE_INFO PipeList[0] * } */ - public static int ConnectionStatus$get(MemorySegment seg) { - return (int)constants$2.const$3.get(seg); + public static MemorySegment PipeList(MemorySegment struct) { + return struct.asSlice(PipeList$OFFSET, PipeList$LAYOUT.byteSize()); } + /** * Setter for field: - * {@snippet : - * USB_CONNECTION_STATUS ConnectionStatus; + * {@snippet lang=c : + * USB_PIPE_INFO PipeList[0] * } */ - public static void ConnectionStatus$set(MemorySegment seg, int x) { - constants$2.const$3.set(seg, x); + public static void PipeList(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, PipeList$OFFSET, PipeList$LAYOUT.byteSize()); } - public static int ConnectionStatus$get(MemorySegment seg, long index) { - return (int)constants$2.const$3.get(seg.asSlice(index*sizeof())); + + private static long[] PipeList$DIMS = { 0 }; + + /** + * Dimensions for array field: + * {@snippet lang=c : + * USB_PIPE_INFO PipeList[0] + * } + */ + public static long[] PipeList$dimensions() { + return PipeList$DIMS; } - public static void ConnectionStatus$set(MemorySegment seg, long index, int x) { - constants$2.const$3.set(seg.asSlice(index*sizeof()), x); + private static final MethodHandle PipeList$ELEM_HANDLE = PipeList$LAYOUT.sliceHandle(sequenceElement()); + + /** + * Indexed getter for field: + * {@snippet lang=c : + * USB_PIPE_INFO PipeList[0] + * } + */ + public static MemorySegment PipeList(MemorySegment struct, long index0) { + try { + return (MemorySegment)PipeList$ELEM_HANDLE.invokeExact(struct, 0L, index0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Indexed setter for field: + * {@snippet lang=c : + * USB_PIPE_INFO PipeList[0] + * } + */ + public static void PipeList(MemorySegment struct, long index0, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, PipeList(struct, index0), 0L, _USB_PIPE_INFO.layout().byteSize()); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } -} + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_PIPE_INFO.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_PIPE_INFO.java new file mode 100644 index 00000000..f529c8b7 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_PIPE_INFO.java @@ -0,0 +1,173 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.usbioctl; + +import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfInt; + +/** + * {@snippet lang=c : + * struct _USB_PIPE_INFO { + * USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + * ULONG ScheduleOffset; + * } + * } + */ +public class _USB_PIPE_INFO { + + _USB_PIPE_INFO() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + _USB_ENDPOINT_DESCRIPTOR.layout().withName("EndpointDescriptor"), + USBIoctl.C_LONG.withByteAlignment(1).withName("ScheduleOffset") + ).withName("_USB_PIPE_INFO"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final GroupLayout EndpointDescriptor$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("EndpointDescriptor")); + + /** + * Layout for field: + * {@snippet lang=c : + * USB_ENDPOINT_DESCRIPTOR EndpointDescriptor + * } + */ + public static final GroupLayout EndpointDescriptor$layout() { + return EndpointDescriptor$LAYOUT; + } + + private static final long EndpointDescriptor$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * USB_ENDPOINT_DESCRIPTOR EndpointDescriptor + * } + */ + public static final long EndpointDescriptor$offset() { + return EndpointDescriptor$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * USB_ENDPOINT_DESCRIPTOR EndpointDescriptor + * } + */ + public static MemorySegment EndpointDescriptor(MemorySegment struct) { + return struct.asSlice(EndpointDescriptor$OFFSET, EndpointDescriptor$LAYOUT.byteSize()); + } + + /** + * Setter for field: + * {@snippet lang=c : + * USB_ENDPOINT_DESCRIPTOR EndpointDescriptor + * } + */ + public static void EndpointDescriptor(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, EndpointDescriptor$OFFSET, EndpointDescriptor$LAYOUT.byteSize()); + } + + private static final OfInt ScheduleOffset$LAYOUT = (OfInt)$LAYOUT.select(groupElement("ScheduleOffset")); + + /** + * Layout for field: + * {@snippet lang=c : + * ULONG ScheduleOffset + * } + */ + public static final OfInt ScheduleOffset$layout() { + return ScheduleOffset$LAYOUT; + } + + private static final long ScheduleOffset$OFFSET = 7; + + /** + * Offset for field: + * {@snippet lang=c : + * ULONG ScheduleOffset + * } + */ + public static final long ScheduleOffset$offset() { + return ScheduleOffset$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * ULONG ScheduleOffset + * } + */ + public static int ScheduleOffset(MemorySegment struct) { + return struct.get(ScheduleOffset$LAYOUT, ScheduleOffset$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * ULONG ScheduleOffset + * } + */ + public static void ScheduleOffset(MemorySegment struct, int fieldValue) { + struct.set(ScheduleOffset$LAYOUT, ScheduleOffset$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$0.java deleted file mode 100644 index 526d671f..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$0.java +++ /dev/null @@ -1,40 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.usbioctl; - -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final StructLayout const$0 = MemoryLayout.structLayout( - JAVA_INT.withByteAlignment(1).withName("ConnectionIndex"), - MemoryLayout.structLayout( - JAVA_BYTE.withName("bmRequest"), - JAVA_BYTE.withName("bRequest"), - JAVA_SHORT.withByteAlignment(1).withName("wValue"), - JAVA_SHORT.withByteAlignment(1).withName("wIndex"), - JAVA_SHORT.withByteAlignment(1).withName("wLength") - ).withName("SetupPacket"), - MemoryLayout.sequenceLayout(0, JAVA_BYTE).withName("Data") - ).withName("_USB_DESCRIPTOR_REQUEST"); - static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("ConnectionIndex")); - static final StructLayout const$2 = MemoryLayout.structLayout( - JAVA_BYTE.withName("bmRequest"), - JAVA_BYTE.withName("bRequest"), - JAVA_SHORT.withByteAlignment(1).withName("wValue"), - JAVA_SHORT.withByteAlignment(1).withName("wIndex"), - JAVA_SHORT.withByteAlignment(1).withName("wLength") - ).withName(""); - static final VarHandle const$3 = constants$0.const$2.varHandle(MemoryLayout.PathElement.groupElement("bmRequest")); - static final VarHandle const$4 = constants$0.const$2.varHandle(MemoryLayout.PathElement.groupElement("bRequest")); - static final VarHandle const$5 = constants$0.const$2.varHandle(MemoryLayout.PathElement.groupElement("wValue")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$1.java deleted file mode 100644 index 4ecf2548..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$1.java +++ /dev/null @@ -1,59 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.usbioctl; - -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -final class constants$1 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$1() {} - static final VarHandle const$0 = constants$0.const$2.varHandle(MemoryLayout.PathElement.groupElement("wIndex")); - static final VarHandle const$1 = constants$0.const$2.varHandle(MemoryLayout.PathElement.groupElement("wLength")); - static final StructLayout const$2 = MemoryLayout.structLayout( - JAVA_INT.withByteAlignment(1).withName("ConnectionIndex"), - MemoryLayout.structLayout( - JAVA_BYTE.withName("bLength"), - JAVA_BYTE.withName("bDescriptorType"), - JAVA_SHORT.withByteAlignment(1).withName("bcdUSB"), - JAVA_BYTE.withName("bDeviceClass"), - JAVA_BYTE.withName("bDeviceSubClass"), - JAVA_BYTE.withName("bDeviceProtocol"), - JAVA_BYTE.withName("bMaxPacketSize0"), - JAVA_SHORT.withByteAlignment(1).withName("idVendor"), - JAVA_SHORT.withByteAlignment(1).withName("idProduct"), - JAVA_SHORT.withByteAlignment(1).withName("bcdDevice"), - JAVA_BYTE.withName("iManufacturer"), - JAVA_BYTE.withName("iProduct"), - JAVA_BYTE.withName("iSerialNumber"), - JAVA_BYTE.withName("bNumConfigurations") - ).withName("DeviceDescriptor"), - JAVA_BYTE.withName("CurrentConfigurationValue"), - JAVA_BYTE.withName("Speed"), - JAVA_BYTE.withName("DeviceIsHub"), - JAVA_SHORT.withByteAlignment(1).withName("DeviceAddress"), - JAVA_INT.withByteAlignment(1).withName("NumberOfOpenPipes"), - JAVA_INT.withByteAlignment(1).withName("ConnectionStatus"), - MemoryLayout.sequenceLayout(0, MemoryLayout.structLayout( - MemoryLayout.structLayout( - JAVA_BYTE.withName("bLength"), - JAVA_BYTE.withName("bDescriptorType"), - JAVA_BYTE.withName("bEndpointAddress"), - JAVA_BYTE.withName("bmAttributes"), - JAVA_SHORT.withByteAlignment(1).withName("wMaxPacketSize"), - JAVA_BYTE.withName("bInterval") - ).withName("EndpointDescriptor"), - JAVA_INT.withByteAlignment(1).withName("ScheduleOffset") - ).withName("_USB_PIPE_INFO")).withName("PipeList") - ).withName("_USB_NODE_CONNECTION_INFORMATION_EX"); - static final VarHandle const$3 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("ConnectionIndex")); - static final VarHandle const$4 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("CurrentConfigurationValue")); - static final VarHandle const$5 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("Speed")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$2.java deleted file mode 100644 index 5e83bb48..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/constants$2.java +++ /dev/null @@ -1,17 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.usbioctl; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.VarHandle; -final class constants$2 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$2() {} - static final VarHandle const$0 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("DeviceIsHub")); - static final VarHandle const$1 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("DeviceAddress")); - static final VarHandle const$2 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("NumberOfOpenPipes")); - static final VarHandle const$3 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("ConnectionStatus")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_DEVICEINTERFACE_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_DEVICEINTERFACE_W.java deleted file mode 100644 index e13c9de5..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_DEVICEINTERFACE_W.java +++ /dev/null @@ -1,16 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.user32; - -/** - * {@snippet : - * typedef struct _DEV_BROADCAST_DEVICEINTERFACE_W DEV_BROADCAST_DEVICEINTERFACE_W; - * } - */ -public final class DEV_BROADCAST_DEVICEINTERFACE_W extends _DEV_BROADCAST_DEVICEINTERFACE_W { - - // Suppresses default constructor, ensuring non-instantiability. - private DEV_BROADCAST_DEVICEINTERFACE_W() {} -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_HDR.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_HDR.java deleted file mode 100644 index 684c0ac3..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/DEV_BROADCAST_HDR.java +++ /dev/null @@ -1,16 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.user32; - -/** - * {@snippet : - * typedef struct _DEV_BROADCAST_HDR DEV_BROADCAST_HDR; - * } - */ -public final class DEV_BROADCAST_HDR extends _DEV_BROADCAST_HDR { - - // Suppresses default constructor, ensuring non-instantiability. - private DEV_BROADCAST_HDR() {} -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/MSG.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/MSG.java deleted file mode 100644 index 1717dd43..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/MSG.java +++ /dev/null @@ -1,16 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.user32; - -/** - * {@snippet : - * typedef struct tagMSG MSG; - * } - */ -public final class MSG extends tagMSG { - - // Suppresses default constructor, ensuring non-instantiability. - private MSG() {} -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java deleted file mode 100644 index 3fd0cdf5..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/RuntimeHelper.java +++ /dev/null @@ -1,239 +0,0 @@ -package net.codecrete.usb.windows.gen.user32; -// Generated by jextract - -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_LONG; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { - System.loadLibrary("User32"); - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java index 6f4f3b90..f91ff851 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java @@ -3,95 +3,167 @@ package net.codecrete.usb.windows.gen.user32; import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_FLOAT; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -import static java.lang.foreign.ValueLayout.OfByte; -import static java.lang.foreign.ValueLayout.OfDouble; -import static java.lang.foreign.ValueLayout.OfFloat; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfLong; -import static java.lang.foreign.ValueLayout.OfShort; -public class User32 { - - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfInt C_LONG = JAVA_INT; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; + +public class User32 { + + User32() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("User32"), LIBRARY_ARENA) + .or(SymbolLookup.loaderLookup()) + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfInt C_LONG = ValueLayout.JAVA_INT; + public static final ValueLayout.OfDouble C_LONG_DOUBLE = ValueLayout.JAVA_DOUBLE; + private static final int WM_DEVICECHANGE = (int)537L; /** - * {@snippet : + * {@snippet lang=c : * #define WM_DEVICECHANGE 537 * } */ public static int WM_DEVICECHANGE() { - return (int)537L; + return WM_DEVICECHANGE; } + private static final int DEVICE_NOTIFY_WINDOW_HANDLE = (int)0L; /** - * {@snippet : + * {@snippet lang=c : * #define DEVICE_NOTIFY_WINDOW_HANDLE 0 * } */ public static int DEVICE_NOTIFY_WINDOW_HANDLE() { - return (int)0L; + return DEVICE_NOTIFY_WINDOW_HANDLE; } + private static final int DBT_DEVICEARRIVAL = (int)32768L; /** - * {@snippet : + * {@snippet lang=c : * #define DBT_DEVICEARRIVAL 32768 * } */ public static int DBT_DEVICEARRIVAL() { - return (int)32768L; + return DBT_DEVICEARRIVAL; } + private static final int DBT_DEVICEREMOVECOMPLETE = (int)32772L; /** - * {@snippet : + * {@snippet lang=c : * #define DBT_DEVICEREMOVECOMPLETE 32772 * } */ public static int DBT_DEVICEREMOVECOMPLETE() { - return (int)32772L; + return DBT_DEVICEREMOVECOMPLETE; } + private static final int DBT_DEVTYP_DEVICEINTERFACE = (int)5L; /** - * {@snippet : + * {@snippet lang=c : * #define DBT_DEVTYP_DEVICEINTERFACE 5 * } */ public static int DBT_DEVTYP_DEVICEINTERFACE() { - return (int)5L; + return DBT_DEVTYP_DEVICEINTERFACE; } - public static MethodHandle DefWindowProcW$MH() { - return RuntimeHelper.requireNonNull(constants$3.const$2,"DefWindowProcW"); + + private static class DefWindowProcW { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + User32.C_LONG_LONG, + User32.C_POINTER, + User32.C_INT, + User32.C_LONG_LONG, + User32.C_LONG_LONG + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + User32.findOrThrow("DefWindowProcW"), + DESC); } + /** - * {@snippet : - * LRESULT DefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); + * Function descriptor for: + * {@snippet lang=c : + * LRESULT DefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) + * } + */ + public static FunctionDescriptor DefWindowProcW$descriptor() { + return DefWindowProcW.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * LRESULT DefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) + * } + */ + public static MethodHandle DefWindowProcW$handle() { + return DefWindowProcW.HANDLE; + } + /** + * {@snippet lang=c : + * LRESULT DefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) * } */ public static long DefWindowProcW(MemorySegment hWnd, int Msg, long wParam, long lParam) { - var mh$ = DefWindowProcW$MH(); + var mh$ = DefWindowProcW.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("DefWindowProcW", hWnd, Msg, wParam, lParam); + } return (long)mh$.invokeExact(hWnd, Msg, wParam, lParam); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } + private static final MemorySegment HWND_MESSAGE = MemorySegment.ofAddress(-3L); /** - * {@snippet : - * #define HWND_MESSAGE -3 + * {@snippet lang=c : + * #define HWND_MESSAGE (void*) -3 * } */ public static MemorySegment HWND_MESSAGE() { - return constants$4.const$5; + return HWND_MESSAGE; } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/WNDCLASSEXW.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/WNDCLASSEXW.java deleted file mode 100644 index aa336e43..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/WNDCLASSEXW.java +++ /dev/null @@ -1,16 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.user32; - -/** - * {@snippet : - * typedef struct tagWNDCLASSEXW WNDCLASSEXW; - * } - */ -public final class WNDCLASSEXW extends tagWNDCLASSEXW { - - // Suppresses default constructor, ensuring non-instantiability. - private WNDCLASSEXW() {} -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java index ff9172ce..6c3d5e10 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java @@ -3,119 +3,346 @@ package net.codecrete.usb.windows.gen.user32; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SequenceLayout; import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; +import static java.lang.foreign.ValueLayout.OfInt; + /** - * {@snippet : + * {@snippet lang=c : * struct _DEV_BROADCAST_DEVICEINTERFACE_W { * DWORD dbcc_size; * DWORD dbcc_devicetype; * DWORD dbcc_reserved; * GUID dbcc_classguid; * wchar_t dbcc_name[1]; - * }; + * } * } */ public class _DEV_BROADCAST_DEVICEINTERFACE_W { - public static MemoryLayout $LAYOUT() { - return constants$4.const$1; + _DEV_BROADCAST_DEVICEINTERFACE_W() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + User32.C_LONG.withName("dbcc_size"), + User32.C_LONG.withName("dbcc_devicetype"), + User32.C_LONG.withName("dbcc_reserved"), + _GUID.layout().withName("dbcc_classguid"), + MemoryLayout.sequenceLayout(1, User32.C_SHORT).withName("dbcc_name"), + MemoryLayout.paddingLayout(2) + ).withName("_DEV_BROADCAST_DEVICEINTERFACE_W"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfInt dbcc_size$LAYOUT = (OfInt)$LAYOUT.select(groupElement("dbcc_size")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD dbcc_size + * } + */ + public static final OfInt dbcc_size$layout() { + return dbcc_size$LAYOUT; } - public static VarHandle dbcc_size$VH() { - return constants$4.const$2; + + private static final long dbcc_size$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD dbcc_size + * } + */ + public static final long dbcc_size$offset() { + return dbcc_size$OFFSET; } + /** * Getter for field: - * {@snippet : - * DWORD dbcc_size; + * {@snippet lang=c : + * DWORD dbcc_size * } */ - public static int dbcc_size$get(MemorySegment seg) { - return (int)constants$4.const$2.get(seg); + public static int dbcc_size(MemorySegment struct) { + return struct.get(dbcc_size$LAYOUT, dbcc_size$OFFSET); } + /** * Setter for field: - * {@snippet : - * DWORD dbcc_size; + * {@snippet lang=c : + * DWORD dbcc_size * } */ - public static void dbcc_size$set(MemorySegment seg, int x) { - constants$4.const$2.set(seg, x); + public static void dbcc_size(MemorySegment struct, int fieldValue) { + struct.set(dbcc_size$LAYOUT, dbcc_size$OFFSET, fieldValue); } - public static int dbcc_size$get(MemorySegment seg, long index) { - return (int)constants$4.const$2.get(seg.asSlice(index*sizeof())); + + private static final OfInt dbcc_devicetype$LAYOUT = (OfInt)$LAYOUT.select(groupElement("dbcc_devicetype")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD dbcc_devicetype + * } + */ + public static final OfInt dbcc_devicetype$layout() { + return dbcc_devicetype$LAYOUT; } - public static void dbcc_size$set(MemorySegment seg, long index, int x) { - constants$4.const$2.set(seg.asSlice(index*sizeof()), x); + + private static final long dbcc_devicetype$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD dbcc_devicetype + * } + */ + public static final long dbcc_devicetype$offset() { + return dbcc_devicetype$OFFSET; } - public static VarHandle dbcc_devicetype$VH() { - return constants$4.const$3; + + /** + * Getter for field: + * {@snippet lang=c : + * DWORD dbcc_devicetype + * } + */ + public static int dbcc_devicetype(MemorySegment struct) { + return struct.get(dbcc_devicetype$LAYOUT, dbcc_devicetype$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * DWORD dbcc_devicetype + * } + */ + public static void dbcc_devicetype(MemorySegment struct, int fieldValue) { + struct.set(dbcc_devicetype$LAYOUT, dbcc_devicetype$OFFSET, fieldValue); } + + private static final OfInt dbcc_reserved$LAYOUT = (OfInt)$LAYOUT.select(groupElement("dbcc_reserved")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD dbcc_reserved + * } + */ + public static final OfInt dbcc_reserved$layout() { + return dbcc_reserved$LAYOUT; + } + + private static final long dbcc_reserved$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD dbcc_reserved + * } + */ + public static final long dbcc_reserved$offset() { + return dbcc_reserved$OFFSET; + } + /** * Getter for field: - * {@snippet : - * DWORD dbcc_devicetype; + * {@snippet lang=c : + * DWORD dbcc_reserved * } */ - public static int dbcc_devicetype$get(MemorySegment seg) { - return (int)constants$4.const$3.get(seg); + public static int dbcc_reserved(MemorySegment struct) { + return struct.get(dbcc_reserved$LAYOUT, dbcc_reserved$OFFSET); } + /** * Setter for field: - * {@snippet : - * DWORD dbcc_devicetype; + * {@snippet lang=c : + * DWORD dbcc_reserved + * } + */ + public static void dbcc_reserved(MemorySegment struct, int fieldValue) { + struct.set(dbcc_reserved$LAYOUT, dbcc_reserved$OFFSET, fieldValue); + } + + private static final GroupLayout dbcc_classguid$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("dbcc_classguid")); + + /** + * Layout for field: + * {@snippet lang=c : + * GUID dbcc_classguid + * } + */ + public static final GroupLayout dbcc_classguid$layout() { + return dbcc_classguid$LAYOUT; + } + + private static final long dbcc_classguid$OFFSET = 12; + + /** + * Offset for field: + * {@snippet lang=c : + * GUID dbcc_classguid + * } + */ + public static final long dbcc_classguid$offset() { + return dbcc_classguid$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * GUID dbcc_classguid * } */ - public static void dbcc_devicetype$set(MemorySegment seg, int x) { - constants$4.const$3.set(seg, x); + public static MemorySegment dbcc_classguid(MemorySegment struct) { + return struct.asSlice(dbcc_classguid$OFFSET, dbcc_classguid$LAYOUT.byteSize()); } - public static int dbcc_devicetype$get(MemorySegment seg, long index) { - return (int)constants$4.const$3.get(seg.asSlice(index*sizeof())); + + /** + * Setter for field: + * {@snippet lang=c : + * GUID dbcc_classguid + * } + */ + public static void dbcc_classguid(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, dbcc_classguid$OFFSET, dbcc_classguid$LAYOUT.byteSize()); } - public static void dbcc_devicetype$set(MemorySegment seg, long index, int x) { - constants$4.const$3.set(seg.asSlice(index*sizeof()), x); + + private static final SequenceLayout dbcc_name$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("dbcc_name")); + + /** + * Layout for field: + * {@snippet lang=c : + * wchar_t dbcc_name[1] + * } + */ + public static final SequenceLayout dbcc_name$layout() { + return dbcc_name$LAYOUT; } - public static VarHandle dbcc_reserved$VH() { - return constants$4.const$4; + + private static final long dbcc_name$OFFSET = 28; + + /** + * Offset for field: + * {@snippet lang=c : + * wchar_t dbcc_name[1] + * } + */ + public static final long dbcc_name$offset() { + return dbcc_name$OFFSET; } + /** * Getter for field: - * {@snippet : - * DWORD dbcc_reserved; + * {@snippet lang=c : + * wchar_t dbcc_name[1] * } */ - public static int dbcc_reserved$get(MemorySegment seg) { - return (int)constants$4.const$4.get(seg); + public static MemorySegment dbcc_name(MemorySegment struct) { + return struct.asSlice(dbcc_name$OFFSET, dbcc_name$LAYOUT.byteSize()); } + /** * Setter for field: - * {@snippet : - * DWORD dbcc_reserved; + * {@snippet lang=c : + * wchar_t dbcc_name[1] * } */ - public static void dbcc_reserved$set(MemorySegment seg, int x) { - constants$4.const$4.set(seg, x); + public static void dbcc_name(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, dbcc_name$OFFSET, dbcc_name$LAYOUT.byteSize()); } - public static int dbcc_reserved$get(MemorySegment seg, long index) { - return (int)constants$4.const$4.get(seg.asSlice(index*sizeof())); + + private static long[] dbcc_name$DIMS = { 1 }; + + /** + * Dimensions for array field: + * {@snippet lang=c : + * wchar_t dbcc_name[1] + * } + */ + public static long[] dbcc_name$dimensions() { + return dbcc_name$DIMS; } - public static void dbcc_reserved$set(MemorySegment seg, long index, int x) { - constants$4.const$4.set(seg.asSlice(index*sizeof()), x); + private static final VarHandle dbcc_name$ELEM_HANDLE = dbcc_name$LAYOUT.varHandle(sequenceElement()); + + /** + * Indexed getter for field: + * {@snippet lang=c : + * wchar_t dbcc_name[1] + * } + */ + public static short dbcc_name(MemorySegment struct, long index0) { + return (short)dbcc_name$ELEM_HANDLE.get(struct, 0L, index0); } - public static MemorySegment dbcc_classguid$slice(MemorySegment seg) { - return seg.asSlice(12, 16); + + /** + * Indexed setter for field: + * {@snippet lang=c : + * wchar_t dbcc_name[1] + * } + */ + public static void dbcc_name(MemorySegment struct, long index0, short fieldValue) { + dbcc_name$ELEM_HANDLE.set(struct, 0L, index0, fieldValue); } - public static MemorySegment dbcc_name$slice(MemorySegment seg) { - return seg.asSlice(28, 2); + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } -} + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java index 06d1ef76..9ccf303c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java @@ -3,111 +3,217 @@ package net.codecrete.usb.windows.gen.user32; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfInt; + /** - * {@snippet : + * {@snippet lang=c : * struct _DEV_BROADCAST_HDR { * DWORD dbch_size; * DWORD dbch_devicetype; * DWORD dbch_reserved; - * }; + * } * } */ public class _DEV_BROADCAST_HDR { - public static MemoryLayout $LAYOUT() { - return constants$3.const$3; + _DEV_BROADCAST_HDR() { + // Should not be called directly } - public static VarHandle dbch_size$VH() { - return constants$3.const$4; + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + User32.C_LONG.withName("dbch_size"), + User32.C_LONG.withName("dbch_devicetype"), + User32.C_LONG.withName("dbch_reserved") + ).withName("_DEV_BROADCAST_HDR"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfInt dbch_size$LAYOUT = (OfInt)$LAYOUT.select(groupElement("dbch_size")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD dbch_size + * } + */ + public static final OfInt dbch_size$layout() { + return dbch_size$LAYOUT; + } + + private static final long dbch_size$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD dbch_size + * } + */ + public static final long dbch_size$offset() { + return dbch_size$OFFSET; } + /** * Getter for field: - * {@snippet : - * DWORD dbch_size; + * {@snippet lang=c : + * DWORD dbch_size * } */ - public static int dbch_size$get(MemorySegment seg) { - return (int)constants$3.const$4.get(seg); + public static int dbch_size(MemorySegment struct) { + return struct.get(dbch_size$LAYOUT, dbch_size$OFFSET); } + /** * Setter for field: - * {@snippet : - * DWORD dbch_size; + * {@snippet lang=c : + * DWORD dbch_size * } */ - public static void dbch_size$set(MemorySegment seg, int x) { - constants$3.const$4.set(seg, x); - } - public static int dbch_size$get(MemorySegment seg, long index) { - return (int)constants$3.const$4.get(seg.asSlice(index*sizeof())); + public static void dbch_size(MemorySegment struct, int fieldValue) { + struct.set(dbch_size$LAYOUT, dbch_size$OFFSET, fieldValue); } - public static void dbch_size$set(MemorySegment seg, long index, int x) { - constants$3.const$4.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt dbch_devicetype$LAYOUT = (OfInt)$LAYOUT.select(groupElement("dbch_devicetype")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD dbch_devicetype + * } + */ + public static final OfInt dbch_devicetype$layout() { + return dbch_devicetype$LAYOUT; } - public static VarHandle dbch_devicetype$VH() { - return constants$3.const$5; + + private static final long dbch_devicetype$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD dbch_devicetype + * } + */ + public static final long dbch_devicetype$offset() { + return dbch_devicetype$OFFSET; } + /** * Getter for field: - * {@snippet : - * DWORD dbch_devicetype; + * {@snippet lang=c : + * DWORD dbch_devicetype * } */ - public static int dbch_devicetype$get(MemorySegment seg) { - return (int)constants$3.const$5.get(seg); + public static int dbch_devicetype(MemorySegment struct) { + return struct.get(dbch_devicetype$LAYOUT, dbch_devicetype$OFFSET); } + /** * Setter for field: - * {@snippet : - * DWORD dbch_devicetype; + * {@snippet lang=c : + * DWORD dbch_devicetype * } */ - public static void dbch_devicetype$set(MemorySegment seg, int x) { - constants$3.const$5.set(seg, x); + public static void dbch_devicetype(MemorySegment struct, int fieldValue) { + struct.set(dbch_devicetype$LAYOUT, dbch_devicetype$OFFSET, fieldValue); } - public static int dbch_devicetype$get(MemorySegment seg, long index) { - return (int)constants$3.const$5.get(seg.asSlice(index*sizeof())); - } - public static void dbch_devicetype$set(MemorySegment seg, long index, int x) { - constants$3.const$5.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt dbch_reserved$LAYOUT = (OfInt)$LAYOUT.select(groupElement("dbch_reserved")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD dbch_reserved + * } + */ + public static final OfInt dbch_reserved$layout() { + return dbch_reserved$LAYOUT; } - public static VarHandle dbch_reserved$VH() { - return constants$4.const$0; + + private static final long dbch_reserved$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD dbch_reserved + * } + */ + public static final long dbch_reserved$offset() { + return dbch_reserved$OFFSET; } + /** * Getter for field: - * {@snippet : - * DWORD dbch_reserved; + * {@snippet lang=c : + * DWORD dbch_reserved * } */ - public static int dbch_reserved$get(MemorySegment seg) { - return (int)constants$4.const$0.get(seg); + public static int dbch_reserved(MemorySegment struct) { + return struct.get(dbch_reserved$LAYOUT, dbch_reserved$OFFSET); } + /** * Setter for field: - * {@snippet : - * DWORD dbch_reserved; + * {@snippet lang=c : + * DWORD dbch_reserved * } */ - public static void dbch_reserved$set(MemorySegment seg, int x) { - constants$4.const$0.set(seg, x); + public static void dbch_reserved(MemorySegment struct, int fieldValue) { + struct.set(dbch_reserved$LAYOUT, dbch_reserved$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); } - public static int dbch_reserved$get(MemorySegment seg, long index) { - return (int)constants$4.const$0.get(seg.asSlice(index*sizeof())); + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static void dbch_reserved$set(MemorySegment seg, long index, int x) { - constants$4.const$0.set(seg.asSlice(index*sizeof()), x); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } -} + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_GUID.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_GUID.java new file mode 100644 index 00000000..6d079fe8 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_GUID.java @@ -0,0 +1,302 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.user32; + +import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SequenceLayout; +import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfShort; + +/** + * {@snippet lang=c : + * struct _GUID { + * unsigned long Data1; + * unsigned short Data2; + * unsigned short Data3; + * unsigned char Data4[8]; + * } + * } + */ +public class _GUID { + + _GUID() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + User32.C_LONG.withName("Data1"), + User32.C_SHORT.withName("Data2"), + User32.C_SHORT.withName("Data3"), + MemoryLayout.sequenceLayout(8, User32.C_CHAR).withName("Data4") + ).withName("_GUID"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfInt Data1$LAYOUT = (OfInt)$LAYOUT.select(groupElement("Data1")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned long Data1 + * } + */ + public static final OfInt Data1$layout() { + return Data1$LAYOUT; + } + + private static final long Data1$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned long Data1 + * } + */ + public static final long Data1$offset() { + return Data1$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * unsigned long Data1 + * } + */ + public static int Data1(MemorySegment struct) { + return struct.get(Data1$LAYOUT, Data1$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * unsigned long Data1 + * } + */ + public static void Data1(MemorySegment struct, int fieldValue) { + struct.set(Data1$LAYOUT, Data1$OFFSET, fieldValue); + } + + private static final OfShort Data2$LAYOUT = (OfShort)$LAYOUT.select(groupElement("Data2")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned short Data2 + * } + */ + public static final OfShort Data2$layout() { + return Data2$LAYOUT; + } + + private static final long Data2$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned short Data2 + * } + */ + public static final long Data2$offset() { + return Data2$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * unsigned short Data2 + * } + */ + public static short Data2(MemorySegment struct) { + return struct.get(Data2$LAYOUT, Data2$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * unsigned short Data2 + * } + */ + public static void Data2(MemorySegment struct, short fieldValue) { + struct.set(Data2$LAYOUT, Data2$OFFSET, fieldValue); + } + + private static final OfShort Data3$LAYOUT = (OfShort)$LAYOUT.select(groupElement("Data3")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned short Data3 + * } + */ + public static final OfShort Data3$layout() { + return Data3$LAYOUT; + } + + private static final long Data3$OFFSET = 6; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned short Data3 + * } + */ + public static final long Data3$offset() { + return Data3$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * unsigned short Data3 + * } + */ + public static short Data3(MemorySegment struct) { + return struct.get(Data3$LAYOUT, Data3$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * unsigned short Data3 + * } + */ + public static void Data3(MemorySegment struct, short fieldValue) { + struct.set(Data3$LAYOUT, Data3$OFFSET, fieldValue); + } + + private static final SequenceLayout Data4$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("Data4")); + + /** + * Layout for field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static final SequenceLayout Data4$layout() { + return Data4$LAYOUT; + } + + private static final long Data4$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static final long Data4$offset() { + return Data4$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static MemorySegment Data4(MemorySegment struct) { + return struct.asSlice(Data4$OFFSET, Data4$LAYOUT.byteSize()); + } + + /** + * Setter for field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static void Data4(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, Data4$OFFSET, Data4$LAYOUT.byteSize()); + } + + private static long[] Data4$DIMS = { 8 }; + + /** + * Dimensions for array field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static long[] Data4$dimensions() { + return Data4$DIMS; + } + private static final VarHandle Data4$ELEM_HANDLE = Data4$LAYOUT.varHandle(sequenceElement()); + + /** + * Indexed getter for field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static byte Data4(MemorySegment struct, long index0) { + return (byte)Data4$ELEM_HANDLE.get(struct, 0L, index0); + } + + /** + * Indexed setter for field: + * {@snippet lang=c : + * unsigned char Data4[8] + * } + */ + public static void Data4(MemorySegment struct, long index0, byte fieldValue) { + Data4$ELEM_HANDLE.set(struct, 0L, index0, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java deleted file mode 100644 index c4377aae..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$0.java +++ /dev/null @@ -1,35 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.user32; - -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final StructLayout const$0 = MemoryLayout.structLayout( - JAVA_INT.withName("cbSize"), - JAVA_INT.withName("style"), - RuntimeHelper.POINTER.withName("lpfnWndProc"), - JAVA_INT.withName("cbClsExtra"), - JAVA_INT.withName("cbWndExtra"), - RuntimeHelper.POINTER.withName("hInstance"), - RuntimeHelper.POINTER.withName("hIcon"), - RuntimeHelper.POINTER.withName("hCursor"), - RuntimeHelper.POINTER.withName("hbrBackground"), - RuntimeHelper.POINTER.withName("lpszMenuName"), - RuntimeHelper.POINTER.withName("lpszClassName"), - RuntimeHelper.POINTER.withName("hIconSm") - ).withName("tagWNDCLASSEXW"); - static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("cbSize")); - static final VarHandle const$2 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("style")); - static final VarHandle const$3 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("lpfnWndProc")); - static final VarHandle const$4 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("cbClsExtra")); - static final VarHandle const$5 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("cbWndExtra")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$1.java deleted file mode 100644 index 1836e3c4..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$1.java +++ /dev/null @@ -1,19 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.user32; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.VarHandle; -final class constants$1 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$1() {} - static final VarHandle const$0 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("hInstance")); - static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("hIcon")); - static final VarHandle const$2 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("hCursor")); - static final VarHandle const$3 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("hbrBackground")); - static final VarHandle const$4 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("lpszMenuName")); - static final VarHandle const$5 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("lpszClassName")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$2.java deleted file mode 100644 index 7fba5be6..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$2.java +++ /dev/null @@ -1,35 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.user32; - -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -final class constants$2 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$2() {} - static final VarHandle const$0 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("hIconSm")); - static final StructLayout const$1 = MemoryLayout.structLayout( - RuntimeHelper.POINTER.withName("hwnd"), - JAVA_INT.withName("message"), - MemoryLayout.paddingLayout(4), - JAVA_LONG.withName("wParam"), - JAVA_LONG.withName("lParam"), - JAVA_INT.withName("time"), - MemoryLayout.structLayout( - JAVA_INT.withName("x"), - JAVA_INT.withName("y") - ).withName("pt"), - MemoryLayout.paddingLayout(4) - ).withName("tagMSG"); - static final VarHandle const$2 = constants$2.const$1.varHandle(MemoryLayout.PathElement.groupElement("hwnd")); - static final VarHandle const$3 = constants$2.const$1.varHandle(MemoryLayout.PathElement.groupElement("message")); - static final VarHandle const$4 = constants$2.const$1.varHandle(MemoryLayout.PathElement.groupElement("wParam")); - static final VarHandle const$5 = constants$2.const$1.varHandle(MemoryLayout.PathElement.groupElement("lParam")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$3.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$3.java deleted file mode 100644 index 1ab09470..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$3.java +++ /dev/null @@ -1,37 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.user32; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -final class constants$3 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$3() {} - static final VarHandle const$0 = constants$2.const$1.varHandle(MemoryLayout.PathElement.groupElement("time")); - static final FunctionDescriptor const$1 = FunctionDescriptor.of(JAVA_LONG, - RuntimeHelper.POINTER, - JAVA_INT, - JAVA_LONG, - JAVA_LONG - ); - static final MethodHandle const$2 = RuntimeHelper.downcallHandle( - "DefWindowProcW", - constants$3.const$1 - ); - static final StructLayout const$3 = MemoryLayout.structLayout( - JAVA_INT.withName("dbch_size"), - JAVA_INT.withName("dbch_devicetype"), - JAVA_INT.withName("dbch_reserved") - ).withName("_DEV_BROADCAST_HDR"); - static final VarHandle const$4 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("dbch_size")); - static final VarHandle const$5 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("dbch_devicetype")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$4.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$4.java deleted file mode 100644 index cdf19c7f..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/constants$4.java +++ /dev/null @@ -1,37 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.user32; - -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.StructLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -final class constants$4 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$4() {} - static final VarHandle const$0 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("dbch_reserved")); - static final StructLayout const$1 = MemoryLayout.structLayout( - JAVA_INT.withName("dbcc_size"), - JAVA_INT.withName("dbcc_devicetype"), - JAVA_INT.withName("dbcc_reserved"), - MemoryLayout.structLayout( - JAVA_INT.withName("Data1"), - JAVA_SHORT.withName("Data2"), - JAVA_SHORT.withName("Data3"), - MemoryLayout.sequenceLayout(8, JAVA_BYTE).withName("Data4") - ).withName("dbcc_classguid"), - MemoryLayout.sequenceLayout(1, JAVA_SHORT).withName("dbcc_name"), - MemoryLayout.paddingLayout(2) - ).withName("_DEV_BROADCAST_DEVICEINTERFACE_W"); - static final VarHandle const$2 = constants$4.const$1.varHandle(MemoryLayout.PathElement.groupElement("dbcc_size")); - static final VarHandle const$3 = constants$4.const$1.varHandle(MemoryLayout.PathElement.groupElement("dbcc_devicetype")); - static final VarHandle const$4 = constants$4.const$1.varHandle(MemoryLayout.PathElement.groupElement("dbcc_reserved")); - static final MemorySegment const$5 = MemorySegment.ofAddress(-3L); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java index 98724ca8..d41d2f66 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java @@ -2,13 +2,20 @@ package net.codecrete.usb.windows.gen.user32; +import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.OfLong; + /** - * {@snippet : + * {@snippet lang=c : * struct tagMSG { * HWND hwnd; * UINT message; @@ -16,158 +23,339 @@ * LPARAM lParam; * DWORD time; * POINT pt; - * }; + * } * } */ public class tagMSG { - public static MemoryLayout $LAYOUT() { - return constants$2.const$1; + tagMSG() { + // Should not be called directly } - public static VarHandle hwnd$VH() { - return constants$2.const$2; + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + User32.C_POINTER.withName("hwnd"), + User32.C_INT.withName("message"), + MemoryLayout.paddingLayout(4), + User32.C_LONG_LONG.withName("wParam"), + User32.C_LONG_LONG.withName("lParam"), + User32.C_LONG.withName("time"), + tagPOINT.layout().withName("pt"), + MemoryLayout.paddingLayout(4) + ).withName("tagMSG"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } + + private static final AddressLayout hwnd$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("hwnd")); + + /** + * Layout for field: + * {@snippet lang=c : + * HWND hwnd + * } + */ + public static final AddressLayout hwnd$layout() { + return hwnd$LAYOUT; + } + + private static final long hwnd$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * HWND hwnd + * } + */ + public static final long hwnd$offset() { + return hwnd$OFFSET; + } + /** * Getter for field: - * {@snippet : - * HWND hwnd; + * {@snippet lang=c : + * HWND hwnd * } */ - public static MemorySegment hwnd$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$2.const$2.get(seg); + public static MemorySegment hwnd(MemorySegment struct) { + return struct.get(hwnd$LAYOUT, hwnd$OFFSET); } + /** * Setter for field: - * {@snippet : - * HWND hwnd; + * {@snippet lang=c : + * HWND hwnd * } */ - public static void hwnd$set(MemorySegment seg, MemorySegment x) { - constants$2.const$2.set(seg, x); - } - public static MemorySegment hwnd$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$2.const$2.get(seg.asSlice(index*sizeof())); + public static void hwnd(MemorySegment struct, MemorySegment fieldValue) { + struct.set(hwnd$LAYOUT, hwnd$OFFSET, fieldValue); } - public static void hwnd$set(MemorySegment seg, long index, MemorySegment x) { - constants$2.const$2.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt message$LAYOUT = (OfInt)$LAYOUT.select(groupElement("message")); + + /** + * Layout for field: + * {@snippet lang=c : + * UINT message + * } + */ + public static final OfInt message$layout() { + return message$LAYOUT; } - public static VarHandle message$VH() { - return constants$2.const$3; + + private static final long message$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * UINT message + * } + */ + public static final long message$offset() { + return message$OFFSET; } + /** * Getter for field: - * {@snippet : - * UINT message; + * {@snippet lang=c : + * UINT message * } */ - public static int message$get(MemorySegment seg) { - return (int)constants$2.const$3.get(seg); + public static int message(MemorySegment struct) { + return struct.get(message$LAYOUT, message$OFFSET); } + /** * Setter for field: - * {@snippet : - * UINT message; + * {@snippet lang=c : + * UINT message * } */ - public static void message$set(MemorySegment seg, int x) { - constants$2.const$3.set(seg, x); - } - public static int message$get(MemorySegment seg, long index) { - return (int)constants$2.const$3.get(seg.asSlice(index*sizeof())); + public static void message(MemorySegment struct, int fieldValue) { + struct.set(message$LAYOUT, message$OFFSET, fieldValue); } - public static void message$set(MemorySegment seg, long index, int x) { - constants$2.const$3.set(seg.asSlice(index*sizeof()), x); + + private static final OfLong wParam$LAYOUT = (OfLong)$LAYOUT.select(groupElement("wParam")); + + /** + * Layout for field: + * {@snippet lang=c : + * WPARAM wParam + * } + */ + public static final OfLong wParam$layout() { + return wParam$LAYOUT; } - public static VarHandle wParam$VH() { - return constants$2.const$4; + + private static final long wParam$OFFSET = 16; + + /** + * Offset for field: + * {@snippet lang=c : + * WPARAM wParam + * } + */ + public static final long wParam$offset() { + return wParam$OFFSET; } + /** * Getter for field: - * {@snippet : - * WPARAM wParam; + * {@snippet lang=c : + * WPARAM wParam * } */ - public static long wParam$get(MemorySegment seg) { - return (long)constants$2.const$4.get(seg); + public static long wParam(MemorySegment struct) { + return struct.get(wParam$LAYOUT, wParam$OFFSET); } + /** * Setter for field: - * {@snippet : - * WPARAM wParam; + * {@snippet lang=c : + * WPARAM wParam * } */ - public static void wParam$set(MemorySegment seg, long x) { - constants$2.const$4.set(seg, x); - } - public static long wParam$get(MemorySegment seg, long index) { - return (long)constants$2.const$4.get(seg.asSlice(index*sizeof())); + public static void wParam(MemorySegment struct, long fieldValue) { + struct.set(wParam$LAYOUT, wParam$OFFSET, fieldValue); } - public static void wParam$set(MemorySegment seg, long index, long x) { - constants$2.const$4.set(seg.asSlice(index*sizeof()), x); + + private static final OfLong lParam$LAYOUT = (OfLong)$LAYOUT.select(groupElement("lParam")); + + /** + * Layout for field: + * {@snippet lang=c : + * LPARAM lParam + * } + */ + public static final OfLong lParam$layout() { + return lParam$LAYOUT; } - public static VarHandle lParam$VH() { - return constants$2.const$5; + + private static final long lParam$OFFSET = 24; + + /** + * Offset for field: + * {@snippet lang=c : + * LPARAM lParam + * } + */ + public static final long lParam$offset() { + return lParam$OFFSET; } + /** * Getter for field: - * {@snippet : - * LPARAM lParam; + * {@snippet lang=c : + * LPARAM lParam * } */ - public static long lParam$get(MemorySegment seg) { - return (long)constants$2.const$5.get(seg); + public static long lParam(MemorySegment struct) { + return struct.get(lParam$LAYOUT, lParam$OFFSET); } + /** * Setter for field: - * {@snippet : - * LPARAM lParam; + * {@snippet lang=c : + * LPARAM lParam * } */ - public static void lParam$set(MemorySegment seg, long x) { - constants$2.const$5.set(seg, x); + public static void lParam(MemorySegment struct, long fieldValue) { + struct.set(lParam$LAYOUT, lParam$OFFSET, fieldValue); } - public static long lParam$get(MemorySegment seg, long index) { - return (long)constants$2.const$5.get(seg.asSlice(index*sizeof())); + + private static final OfInt time$LAYOUT = (OfInt)$LAYOUT.select(groupElement("time")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD time + * } + */ + public static final OfInt time$layout() { + return time$LAYOUT; } - public static void lParam$set(MemorySegment seg, long index, long x) { - constants$2.const$5.set(seg.asSlice(index*sizeof()), x); + + private static final long time$OFFSET = 32; + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD time + * } + */ + public static final long time$offset() { + return time$OFFSET; } - public static VarHandle time$VH() { - return constants$3.const$0; + + /** + * Getter for field: + * {@snippet lang=c : + * DWORD time + * } + */ + public static int time(MemorySegment struct) { + return struct.get(time$LAYOUT, time$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * DWORD time + * } + */ + public static void time(MemorySegment struct, int fieldValue) { + struct.set(time$LAYOUT, time$OFFSET, fieldValue); } + + private static final GroupLayout pt$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("pt")); + + /** + * Layout for field: + * {@snippet lang=c : + * POINT pt + * } + */ + public static final GroupLayout pt$layout() { + return pt$LAYOUT; + } + + private static final long pt$OFFSET = 36; + + /** + * Offset for field: + * {@snippet lang=c : + * POINT pt + * } + */ + public static final long pt$offset() { + return pt$OFFSET; + } + /** * Getter for field: - * {@snippet : - * DWORD time; + * {@snippet lang=c : + * POINT pt * } */ - public static int time$get(MemorySegment seg) { - return (int)constants$3.const$0.get(seg); + public static MemorySegment pt(MemorySegment struct) { + return struct.asSlice(pt$OFFSET, pt$LAYOUT.byteSize()); } + /** * Setter for field: - * {@snippet : - * DWORD time; + * {@snippet lang=c : + * POINT pt * } */ - public static void time$set(MemorySegment seg, int x) { - constants$3.const$0.set(seg, x); + public static void pt(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, pt$OFFSET, pt$LAYOUT.byteSize()); } - public static int time$get(MemorySegment seg, long index) { - return (int)constants$3.const$0.get(seg.asSlice(index*sizeof())); + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static void time$set(MemorySegment seg, long index, int x) { - constants$3.const$0.set(seg.asSlice(index*sizeof()), x); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static MemorySegment pt$slice(MemorySegment seg) { - return seg.asSlice(36, 8); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagPOINT.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagPOINT.java new file mode 100644 index 00000000..f77c4c42 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagPOINT.java @@ -0,0 +1,173 @@ +// Generated by jextract + +package net.codecrete.usb.windows.gen.user32; + +import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfInt; + +/** + * {@snippet lang=c : + * struct tagPOINT { + * LONG x; + * LONG y; + * } + * } + */ +public class tagPOINT { + + tagPOINT() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + User32.C_LONG.withName("x"), + User32.C_LONG.withName("y") + ).withName("tagPOINT"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfInt x$LAYOUT = (OfInt)$LAYOUT.select(groupElement("x")); + + /** + * Layout for field: + * {@snippet lang=c : + * LONG x + * } + */ + public static final OfInt x$layout() { + return x$LAYOUT; + } + + private static final long x$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * LONG x + * } + */ + public static final long x$offset() { + return x$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * LONG x + * } + */ + public static int x(MemorySegment struct) { + return struct.get(x$LAYOUT, x$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * LONG x + * } + */ + public static void x(MemorySegment struct, int fieldValue) { + struct.set(x$LAYOUT, x$OFFSET, fieldValue); + } + + private static final OfInt y$LAYOUT = (OfInt)$LAYOUT.select(groupElement("y")); + + /** + * Layout for field: + * {@snippet lang=c : + * LONG y + * } + */ + public static final OfInt y$layout() { + return y$LAYOUT; + } + + private static final long y$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * LONG y + * } + */ + public static final long y$offset() { + return y$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * LONG y + * } + */ + public static int y(MemorySegment struct) { + return struct.get(y$LAYOUT, y$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * LONG y + * } + */ + public static void y(MemorySegment struct, int fieldValue) { + struct.set(y$LAYOUT, y$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java index 6f6c3346..f1ed2467 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java @@ -2,13 +2,19 @@ package net.codecrete.usb.windows.gen.user32; +import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; +import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfInt; + /** - * {@snippet : + * {@snippet lang=c : * struct tagWNDCLASSEXW { * UINT cbSize; * UINT style; @@ -22,344 +28,607 @@ * LPCWSTR lpszMenuName; * LPCWSTR lpszClassName; * HICON hIconSm; - * }; + * } * } */ public class tagWNDCLASSEXW { - public static MemoryLayout $LAYOUT() { - return constants$0.const$0; + tagWNDCLASSEXW() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + User32.C_INT.withName("cbSize"), + User32.C_INT.withName("style"), + User32.C_POINTER.withName("lpfnWndProc"), + User32.C_INT.withName("cbClsExtra"), + User32.C_INT.withName("cbWndExtra"), + User32.C_POINTER.withName("hInstance"), + User32.C_POINTER.withName("hIcon"), + User32.C_POINTER.withName("hCursor"), + User32.C_POINTER.withName("hbrBackground"), + User32.C_POINTER.withName("lpszMenuName"), + User32.C_POINTER.withName("lpszClassName"), + User32.C_POINTER.withName("hIconSm") + ).withName("tagWNDCLASSEXW"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfInt cbSize$LAYOUT = (OfInt)$LAYOUT.select(groupElement("cbSize")); + + /** + * Layout for field: + * {@snippet lang=c : + * UINT cbSize + * } + */ + public static final OfInt cbSize$layout() { + return cbSize$LAYOUT; } - public static VarHandle cbSize$VH() { - return constants$0.const$1; + + private static final long cbSize$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * UINT cbSize + * } + */ + public static final long cbSize$offset() { + return cbSize$OFFSET; } + /** * Getter for field: - * {@snippet : - * UINT cbSize; + * {@snippet lang=c : + * UINT cbSize * } */ - public static int cbSize$get(MemorySegment seg) { - return (int)constants$0.const$1.get(seg); + public static int cbSize(MemorySegment struct) { + return struct.get(cbSize$LAYOUT, cbSize$OFFSET); } + /** * Setter for field: - * {@snippet : - * UINT cbSize; + * {@snippet lang=c : + * UINT cbSize * } */ - public static void cbSize$set(MemorySegment seg, int x) { - constants$0.const$1.set(seg, x); + public static void cbSize(MemorySegment struct, int fieldValue) { + struct.set(cbSize$LAYOUT, cbSize$OFFSET, fieldValue); } - public static int cbSize$get(MemorySegment seg, long index) { - return (int)constants$0.const$1.get(seg.asSlice(index*sizeof())); - } - public static void cbSize$set(MemorySegment seg, long index, int x) { - constants$0.const$1.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt style$LAYOUT = (OfInt)$LAYOUT.select(groupElement("style")); + + /** + * Layout for field: + * {@snippet lang=c : + * UINT style + * } + */ + public static final OfInt style$layout() { + return style$LAYOUT; } - public static VarHandle style$VH() { - return constants$0.const$2; + + private static final long style$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * UINT style + * } + */ + public static final long style$offset() { + return style$OFFSET; } + /** * Getter for field: - * {@snippet : - * UINT style; + * {@snippet lang=c : + * UINT style * } */ - public static int style$get(MemorySegment seg) { - return (int)constants$0.const$2.get(seg); + public static int style(MemorySegment struct) { + return struct.get(style$LAYOUT, style$OFFSET); } + /** * Setter for field: - * {@snippet : - * UINT style; + * {@snippet lang=c : + * UINT style * } */ - public static void style$set(MemorySegment seg, int x) { - constants$0.const$2.set(seg, x); - } - public static int style$get(MemorySegment seg, long index) { - return (int)constants$0.const$2.get(seg.asSlice(index*sizeof())); + public static void style(MemorySegment struct, int fieldValue) { + struct.set(style$LAYOUT, style$OFFSET, fieldValue); } - public static void style$set(MemorySegment seg, long index, int x) { - constants$0.const$2.set(seg.asSlice(index*sizeof()), x); + + private static final AddressLayout lpfnWndProc$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("lpfnWndProc")); + + /** + * Layout for field: + * {@snippet lang=c : + * WNDPROC lpfnWndProc + * } + */ + public static final AddressLayout lpfnWndProc$layout() { + return lpfnWndProc$LAYOUT; } - public static VarHandle lpfnWndProc$VH() { - return constants$0.const$3; + + private static final long lpfnWndProc$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * WNDPROC lpfnWndProc + * } + */ + public static final long lpfnWndProc$offset() { + return lpfnWndProc$OFFSET; } + /** * Getter for field: - * {@snippet : - * WNDPROC lpfnWndProc; + * {@snippet lang=c : + * WNDPROC lpfnWndProc * } */ - public static MemorySegment lpfnWndProc$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$0.const$3.get(seg); + public static MemorySegment lpfnWndProc(MemorySegment struct) { + return struct.get(lpfnWndProc$LAYOUT, lpfnWndProc$OFFSET); } + /** * Setter for field: - * {@snippet : - * WNDPROC lpfnWndProc; + * {@snippet lang=c : + * WNDPROC lpfnWndProc * } */ - public static void lpfnWndProc$set(MemorySegment seg, MemorySegment x) { - constants$0.const$3.set(seg, x); + public static void lpfnWndProc(MemorySegment struct, MemorySegment fieldValue) { + struct.set(lpfnWndProc$LAYOUT, lpfnWndProc$OFFSET, fieldValue); } - public static MemorySegment lpfnWndProc$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$0.const$3.get(seg.asSlice(index*sizeof())); - } - public static void lpfnWndProc$set(MemorySegment seg, long index, MemorySegment x) { - constants$0.const$3.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt cbClsExtra$LAYOUT = (OfInt)$LAYOUT.select(groupElement("cbClsExtra")); + + /** + * Layout for field: + * {@snippet lang=c : + * int cbClsExtra + * } + */ + public static final OfInt cbClsExtra$layout() { + return cbClsExtra$LAYOUT; } - public static VarHandle cbClsExtra$VH() { - return constants$0.const$4; + + private static final long cbClsExtra$OFFSET = 16; + + /** + * Offset for field: + * {@snippet lang=c : + * int cbClsExtra + * } + */ + public static final long cbClsExtra$offset() { + return cbClsExtra$OFFSET; } + /** * Getter for field: - * {@snippet : - * int cbClsExtra; + * {@snippet lang=c : + * int cbClsExtra * } */ - public static int cbClsExtra$get(MemorySegment seg) { - return (int)constants$0.const$4.get(seg); + public static int cbClsExtra(MemorySegment struct) { + return struct.get(cbClsExtra$LAYOUT, cbClsExtra$OFFSET); } + /** * Setter for field: - * {@snippet : - * int cbClsExtra; + * {@snippet lang=c : + * int cbClsExtra * } */ - public static void cbClsExtra$set(MemorySegment seg, int x) { - constants$0.const$4.set(seg, x); - } - public static int cbClsExtra$get(MemorySegment seg, long index) { - return (int)constants$0.const$4.get(seg.asSlice(index*sizeof())); + public static void cbClsExtra(MemorySegment struct, int fieldValue) { + struct.set(cbClsExtra$LAYOUT, cbClsExtra$OFFSET, fieldValue); } - public static void cbClsExtra$set(MemorySegment seg, long index, int x) { - constants$0.const$4.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt cbWndExtra$LAYOUT = (OfInt)$LAYOUT.select(groupElement("cbWndExtra")); + + /** + * Layout for field: + * {@snippet lang=c : + * int cbWndExtra + * } + */ + public static final OfInt cbWndExtra$layout() { + return cbWndExtra$LAYOUT; } - public static VarHandle cbWndExtra$VH() { - return constants$0.const$5; + + private static final long cbWndExtra$OFFSET = 20; + + /** + * Offset for field: + * {@snippet lang=c : + * int cbWndExtra + * } + */ + public static final long cbWndExtra$offset() { + return cbWndExtra$OFFSET; } + /** * Getter for field: - * {@snippet : - * int cbWndExtra; + * {@snippet lang=c : + * int cbWndExtra * } */ - public static int cbWndExtra$get(MemorySegment seg) { - return (int)constants$0.const$5.get(seg); + public static int cbWndExtra(MemorySegment struct) { + return struct.get(cbWndExtra$LAYOUT, cbWndExtra$OFFSET); } + /** * Setter for field: - * {@snippet : - * int cbWndExtra; + * {@snippet lang=c : + * int cbWndExtra * } */ - public static void cbWndExtra$set(MemorySegment seg, int x) { - constants$0.const$5.set(seg, x); + public static void cbWndExtra(MemorySegment struct, int fieldValue) { + struct.set(cbWndExtra$LAYOUT, cbWndExtra$OFFSET, fieldValue); } - public static int cbWndExtra$get(MemorySegment seg, long index) { - return (int)constants$0.const$5.get(seg.asSlice(index*sizeof())); - } - public static void cbWndExtra$set(MemorySegment seg, long index, int x) { - constants$0.const$5.set(seg.asSlice(index*sizeof()), x); + + private static final AddressLayout hInstance$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("hInstance")); + + /** + * Layout for field: + * {@snippet lang=c : + * HINSTANCE hInstance + * } + */ + public static final AddressLayout hInstance$layout() { + return hInstance$LAYOUT; } - public static VarHandle hInstance$VH() { - return constants$1.const$0; + + private static final long hInstance$OFFSET = 24; + + /** + * Offset for field: + * {@snippet lang=c : + * HINSTANCE hInstance + * } + */ + public static final long hInstance$offset() { + return hInstance$OFFSET; } + /** * Getter for field: - * {@snippet : - * HINSTANCE hInstance; + * {@snippet lang=c : + * HINSTANCE hInstance * } */ - public static MemorySegment hInstance$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$1.const$0.get(seg); + public static MemorySegment hInstance(MemorySegment struct) { + return struct.get(hInstance$LAYOUT, hInstance$OFFSET); } + /** * Setter for field: - * {@snippet : - * HINSTANCE hInstance; + * {@snippet lang=c : + * HINSTANCE hInstance * } */ - public static void hInstance$set(MemorySegment seg, MemorySegment x) { - constants$1.const$0.set(seg, x); - } - public static MemorySegment hInstance$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$1.const$0.get(seg.asSlice(index*sizeof())); + public static void hInstance(MemorySegment struct, MemorySegment fieldValue) { + struct.set(hInstance$LAYOUT, hInstance$OFFSET, fieldValue); } - public static void hInstance$set(MemorySegment seg, long index, MemorySegment x) { - constants$1.const$0.set(seg.asSlice(index*sizeof()), x); + + private static final AddressLayout hIcon$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("hIcon")); + + /** + * Layout for field: + * {@snippet lang=c : + * HICON hIcon + * } + */ + public static final AddressLayout hIcon$layout() { + return hIcon$LAYOUT; } - public static VarHandle hIcon$VH() { - return constants$1.const$1; + + private static final long hIcon$OFFSET = 32; + + /** + * Offset for field: + * {@snippet lang=c : + * HICON hIcon + * } + */ + public static final long hIcon$offset() { + return hIcon$OFFSET; } + /** * Getter for field: - * {@snippet : - * HICON hIcon; + * {@snippet lang=c : + * HICON hIcon * } */ - public static MemorySegment hIcon$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$1.const$1.get(seg); + public static MemorySegment hIcon(MemorySegment struct) { + return struct.get(hIcon$LAYOUT, hIcon$OFFSET); } + /** * Setter for field: - * {@snippet : - * HICON hIcon; + * {@snippet lang=c : + * HICON hIcon * } */ - public static void hIcon$set(MemorySegment seg, MemorySegment x) { - constants$1.const$1.set(seg, x); + public static void hIcon(MemorySegment struct, MemorySegment fieldValue) { + struct.set(hIcon$LAYOUT, hIcon$OFFSET, fieldValue); } - public static MemorySegment hIcon$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$1.const$1.get(seg.asSlice(index*sizeof())); - } - public static void hIcon$set(MemorySegment seg, long index, MemorySegment x) { - constants$1.const$1.set(seg.asSlice(index*sizeof()), x); + + private static final AddressLayout hCursor$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("hCursor")); + + /** + * Layout for field: + * {@snippet lang=c : + * HCURSOR hCursor + * } + */ + public static final AddressLayout hCursor$layout() { + return hCursor$LAYOUT; } - public static VarHandle hCursor$VH() { - return constants$1.const$2; + + private static final long hCursor$OFFSET = 40; + + /** + * Offset for field: + * {@snippet lang=c : + * HCURSOR hCursor + * } + */ + public static final long hCursor$offset() { + return hCursor$OFFSET; } + /** * Getter for field: - * {@snippet : - * HCURSOR hCursor; + * {@snippet lang=c : + * HCURSOR hCursor * } */ - public static MemorySegment hCursor$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$1.const$2.get(seg); + public static MemorySegment hCursor(MemorySegment struct) { + return struct.get(hCursor$LAYOUT, hCursor$OFFSET); } + /** * Setter for field: - * {@snippet : - * HCURSOR hCursor; + * {@snippet lang=c : + * HCURSOR hCursor * } */ - public static void hCursor$set(MemorySegment seg, MemorySegment x) { - constants$1.const$2.set(seg, x); - } - public static MemorySegment hCursor$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$1.const$2.get(seg.asSlice(index*sizeof())); + public static void hCursor(MemorySegment struct, MemorySegment fieldValue) { + struct.set(hCursor$LAYOUT, hCursor$OFFSET, fieldValue); } - public static void hCursor$set(MemorySegment seg, long index, MemorySegment x) { - constants$1.const$2.set(seg.asSlice(index*sizeof()), x); + + private static final AddressLayout hbrBackground$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("hbrBackground")); + + /** + * Layout for field: + * {@snippet lang=c : + * HBRUSH hbrBackground + * } + */ + public static final AddressLayout hbrBackground$layout() { + return hbrBackground$LAYOUT; } - public static VarHandle hbrBackground$VH() { - return constants$1.const$3; + + private static final long hbrBackground$OFFSET = 48; + + /** + * Offset for field: + * {@snippet lang=c : + * HBRUSH hbrBackground + * } + */ + public static final long hbrBackground$offset() { + return hbrBackground$OFFSET; } + /** * Getter for field: - * {@snippet : - * HBRUSH hbrBackground; + * {@snippet lang=c : + * HBRUSH hbrBackground * } */ - public static MemorySegment hbrBackground$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$1.const$3.get(seg); + public static MemorySegment hbrBackground(MemorySegment struct) { + return struct.get(hbrBackground$LAYOUT, hbrBackground$OFFSET); } + /** * Setter for field: - * {@snippet : - * HBRUSH hbrBackground; + * {@snippet lang=c : + * HBRUSH hbrBackground * } */ - public static void hbrBackground$set(MemorySegment seg, MemorySegment x) { - constants$1.const$3.set(seg, x); + public static void hbrBackground(MemorySegment struct, MemorySegment fieldValue) { + struct.set(hbrBackground$LAYOUT, hbrBackground$OFFSET, fieldValue); } - public static MemorySegment hbrBackground$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$1.const$3.get(seg.asSlice(index*sizeof())); - } - public static void hbrBackground$set(MemorySegment seg, long index, MemorySegment x) { - constants$1.const$3.set(seg.asSlice(index*sizeof()), x); + + private static final AddressLayout lpszMenuName$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("lpszMenuName")); + + /** + * Layout for field: + * {@snippet lang=c : + * LPCWSTR lpszMenuName + * } + */ + public static final AddressLayout lpszMenuName$layout() { + return lpszMenuName$LAYOUT; } - public static VarHandle lpszMenuName$VH() { - return constants$1.const$4; + + private static final long lpszMenuName$OFFSET = 56; + + /** + * Offset for field: + * {@snippet lang=c : + * LPCWSTR lpszMenuName + * } + */ + public static final long lpszMenuName$offset() { + return lpszMenuName$OFFSET; } + /** * Getter for field: - * {@snippet : - * LPCWSTR lpszMenuName; + * {@snippet lang=c : + * LPCWSTR lpszMenuName * } */ - public static MemorySegment lpszMenuName$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$1.const$4.get(seg); + public static MemorySegment lpszMenuName(MemorySegment struct) { + return struct.get(lpszMenuName$LAYOUT, lpszMenuName$OFFSET); } + /** * Setter for field: - * {@snippet : - * LPCWSTR lpszMenuName; + * {@snippet lang=c : + * LPCWSTR lpszMenuName * } */ - public static void lpszMenuName$set(MemorySegment seg, MemorySegment x) { - constants$1.const$4.set(seg, x); - } - public static MemorySegment lpszMenuName$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$1.const$4.get(seg.asSlice(index*sizeof())); + public static void lpszMenuName(MemorySegment struct, MemorySegment fieldValue) { + struct.set(lpszMenuName$LAYOUT, lpszMenuName$OFFSET, fieldValue); } - public static void lpszMenuName$set(MemorySegment seg, long index, MemorySegment x) { - constants$1.const$4.set(seg.asSlice(index*sizeof()), x); + + private static final AddressLayout lpszClassName$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("lpszClassName")); + + /** + * Layout for field: + * {@snippet lang=c : + * LPCWSTR lpszClassName + * } + */ + public static final AddressLayout lpszClassName$layout() { + return lpszClassName$LAYOUT; } - public static VarHandle lpszClassName$VH() { - return constants$1.const$5; + + private static final long lpszClassName$OFFSET = 64; + + /** + * Offset for field: + * {@snippet lang=c : + * LPCWSTR lpszClassName + * } + */ + public static final long lpszClassName$offset() { + return lpszClassName$OFFSET; } + /** * Getter for field: - * {@snippet : - * LPCWSTR lpszClassName; + * {@snippet lang=c : + * LPCWSTR lpszClassName * } */ - public static MemorySegment lpszClassName$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$1.const$5.get(seg); + public static MemorySegment lpszClassName(MemorySegment struct) { + return struct.get(lpszClassName$LAYOUT, lpszClassName$OFFSET); } + /** * Setter for field: - * {@snippet : - * LPCWSTR lpszClassName; + * {@snippet lang=c : + * LPCWSTR lpszClassName * } */ - public static void lpszClassName$set(MemorySegment seg, MemorySegment x) { - constants$1.const$5.set(seg, x); + public static void lpszClassName(MemorySegment struct, MemorySegment fieldValue) { + struct.set(lpszClassName$LAYOUT, lpszClassName$OFFSET, fieldValue); } - public static MemorySegment lpszClassName$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$1.const$5.get(seg.asSlice(index*sizeof())); - } - public static void lpszClassName$set(MemorySegment seg, long index, MemorySegment x) { - constants$1.const$5.set(seg.asSlice(index*sizeof()), x); + + private static final AddressLayout hIconSm$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("hIconSm")); + + /** + * Layout for field: + * {@snippet lang=c : + * HICON hIconSm + * } + */ + public static final AddressLayout hIconSm$layout() { + return hIconSm$LAYOUT; } - public static VarHandle hIconSm$VH() { - return constants$2.const$0; + + private static final long hIconSm$OFFSET = 72; + + /** + * Offset for field: + * {@snippet lang=c : + * HICON hIconSm + * } + */ + public static final long hIconSm$offset() { + return hIconSm$OFFSET; } + /** * Getter for field: - * {@snippet : - * HICON hIconSm; + * {@snippet lang=c : + * HICON hIconSm * } */ - public static MemorySegment hIconSm$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$2.const$0.get(seg); + public static MemorySegment hIconSm(MemorySegment struct) { + return struct.get(hIconSm$LAYOUT, hIconSm$OFFSET); } + /** * Setter for field: - * {@snippet : - * HICON hIconSm; + * {@snippet lang=c : + * HICON hIconSm * } */ - public static void hIconSm$set(MemorySegment seg, MemorySegment x) { - constants$2.const$0.set(seg, x); + public static void hIconSm(MemorySegment struct, MemorySegment fieldValue) { + struct.set(hIconSm$LAYOUT, hIconSm$OFFSET, fieldValue); } - public static MemorySegment hIconSm$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$2.const$0.get(seg.asSlice(index*sizeof())); + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); } - public static void hIconSm$set(MemorySegment seg, long index, MemorySegment x) { - constants$2.const$0.set(seg.asSlice(index*sizeof()), x); + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } -} + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java deleted file mode 100644 index 9646daec..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/RuntimeHelper.java +++ /dev/null @@ -1,239 +0,0 @@ -package net.codecrete.usb.windows.gen.winusb; -// Generated by jextract - -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_LONG; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { - System.loadLibrary("Winusb"); - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java index df73968f..8385a77b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java @@ -3,63 +3,128 @@ package net.codecrete.usb.windows.gen.winusb; import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_FLOAT; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -import static java.lang.foreign.ValueLayout.OfByte; -import static java.lang.foreign.ValueLayout.OfDouble; -import static java.lang.foreign.ValueLayout.OfFloat; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfLong; -import static java.lang.foreign.ValueLayout.OfShort; -public class WinUSB { - - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfInt C_LONG = JAVA_INT; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; + +public class WinUSB { + + WinUSB() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("Winusb"), LIBRARY_ARENA) + .or(SymbolLookup.loaderLookup()) + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfInt C_LONG = ValueLayout.JAVA_INT; + public static final ValueLayout.OfDouble C_LONG_DOUBLE = ValueLayout.JAVA_DOUBLE; + private static final int PIPE_TRANSFER_TIMEOUT = (int)3L; /** - * {@snippet : + * {@snippet lang=c : * #define PIPE_TRANSFER_TIMEOUT 3 * } */ public static int PIPE_TRANSFER_TIMEOUT() { - return (int)3L; + return PIPE_TRANSFER_TIMEOUT; } + private static final int RAW_IO = (int)7L; /** - * {@snippet : + * {@snippet lang=c : * #define RAW_IO 7 * } */ public static int RAW_IO() { - return (int)7L; + return RAW_IO; } - public static MethodHandle WinUsb_Free$MH() { - return RuntimeHelper.requireNonNull(constants$0.const$1,"WinUsb_Free"); + + private static class WinUsb_Free { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + WinUSB.C_INT, + WinUSB.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + WinUSB.findOrThrow("WinUsb_Free"), + DESC); } + /** - * {@snippet : - * BOOL WinUsb_Free(WINUSB_INTERFACE_HANDLE InterfaceHandle); + * Function descriptor for: + * {@snippet lang=c : + * BOOL WinUsb_Free(WINUSB_INTERFACE_HANDLE InterfaceHandle) + * } + */ + public static FunctionDescriptor WinUsb_Free$descriptor() { + return WinUsb_Free.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * BOOL WinUsb_Free(WINUSB_INTERFACE_HANDLE InterfaceHandle) + * } + */ + public static MethodHandle WinUsb_Free$handle() { + return WinUsb_Free.HANDLE; + } + /** + * {@snippet lang=c : + * BOOL WinUsb_Free(WINUSB_INTERFACE_HANDLE InterfaceHandle) * } */ public static int WinUsb_Free(MemorySegment InterfaceHandle) { - var mh$ = WinUsb_Free$MH(); + var mh$ = WinUsb_Free.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("WinUsb_Free", InterfaceHandle); + } return (int)mh$.invokeExact(InterfaceHandle); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java deleted file mode 100644 index 90f3902c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/constants$0.java +++ /dev/null @@ -1,22 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.winusb; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER - ); - static final MethodHandle const$1 = RuntimeHelper.downcallHandle( - "WinUsb_Free", - constants$0.const$0 - ); -} - - From 1b3a07691c11aa588f0d7e67ca7ba818d1d5e09a Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 18 Feb 2024 13:18:57 +0100 Subject: [PATCH 320/433] OpenJDK 22 for CI --- .github/workflows/continuous-integration.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index deef007d..bfb4da76 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -26,11 +26,11 @@ jobs: steps: - uses: actions/checkout@v3 - name: Setup Java - uses: actions/setup-java@v3 + uses: oracle-actions/setup-java@v1 with: - distribution: 'zulu' - java-version: '21' - cache: 'maven' + website: jdk.java.net + java-version: '22' + version: latest - name: Configure GPG key run: | echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import From 688b26dc5627781931b9bf37e08edfed3b806a5e Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 18 Feb 2024 13:25:35 +0100 Subject: [PATCH 321/433] CI: revert to JDK 21 --- .github/workflows/continuous-integration.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index bfb4da76..deef007d 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -26,11 +26,11 @@ jobs: steps: - uses: actions/checkout@v3 - name: Setup Java - uses: oracle-actions/setup-java@v1 + uses: actions/setup-java@v3 with: - website: jdk.java.net - java-version: '22' - version: latest + distribution: 'zulu' + java-version: '21' + cache: 'maven' - name: Configure GPG key run: | echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import From 59ddaf0b2f284a8197f892a5b6c355a195e473af Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 18 Feb 2024 13:26:11 +0100 Subject: [PATCH 322/433] CI: Use JDK 22 --- .github/workflows/continuous-integration.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index deef007d..bfb4da76 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -26,11 +26,11 @@ jobs: steps: - uses: actions/checkout@v3 - name: Setup Java - uses: actions/setup-java@v3 + uses: oracle-actions/setup-java@v1 with: - distribution: 'zulu' - java-version: '21' - cache: 'maven' + website: jdk.java.net + java-version: '22' + version: latest - name: Configure GPG key run: | echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import From 175845df1caf5a26fa0599126263e9e3a04ebd16 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 18 Feb 2024 13:39:59 +0100 Subject: [PATCH 323/433] CI: Upgrade maven wrapper --- java-does-usb/.mvn/wrapper/maven-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-does-usb/.mvn/wrapper/maven-wrapper.properties b/java-does-usb/.mvn/wrapper/maven-wrapper.properties index ac184013..346d645f 100644 --- a/java-does-usb/.mvn/wrapper/maven-wrapper.properties +++ b/java-does-usb/.mvn/wrapper/maven-wrapper.properties @@ -14,5 +14,5 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.4/apache-maven-3.9.4-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar From 83afded312c2e5ce1cd1205c7018f0e0d6516150 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 18 Feb 2024 13:50:02 +0100 Subject: [PATCH 324/433] CI: Next try with Java 22 --- .github/workflows/continuous-integration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index bfb4da76..5d883172 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -29,7 +29,7 @@ jobs: uses: oracle-actions/setup-java@v1 with: website: jdk.java.net - java-version: '22' + release: 22 version: latest - name: Configure GPG key run: | From d7338522b3a33d7b35eff279ee9cf1cb73378429 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 18 Feb 2024 13:52:08 +0100 Subject: [PATCH 325/433] Windows: reactivate varhandle --- java-does-usb/pom.xml | 2 +- .../src/main/java/net/codecrete/usb/windows/Win.java | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 3b11a88d..f3a4fffe 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 0.7.1 + 1.0.0-SNAPSHOT 22 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index e1afdad0..59b64f84 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -21,7 +21,6 @@ import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_CHAR; -import static java.lang.foreign.ValueLayout.JAVA_INT; /** * Windows helpers. @@ -50,9 +49,7 @@ static MemorySegment allocateErrorState(Arena arena) { * @return the error code */ public static int getLastError(MemorySegment callState) { - return callState.get(JAVA_INT, 0); - // TODO: revert to varhandle - // return (int) callState_GetLastError$VH.get(callState); + return (int) callState_GetLastError$VH.get(callState, 0); } /** From 9ca37167ca3763c67ca7b80cebfb62156c43d5ca Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 18 Feb 2024 15:07:03 +0100 Subject: [PATCH 326/433] Linux: revert to using varhandles --- .../src/main/java/net/codecrete/usb/linux/EPoll.java | 10 ++-------- .../src/main/java/net/codecrete/usb/linux/Linux.java | 5 +---- .../java/net/codecrete/usb/linux/LinuxAsyncTask.java | 7 +------ 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java index e8d0e051..9470d926 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java @@ -7,7 +7,6 @@ package net.codecrete.usb.linux; -import net.codecrete.usb.linux.gen.epoll.epoll_data; import net.codecrete.usb.linux.gen.epoll.epoll_event; import net.codecrete.usb.linux.gen.errno.errno; @@ -92,10 +91,7 @@ static void addFileDescriptor(int epfd, int op, int fd) { var event = arena.allocate(epoll_event.layout()); epoll_event.events(event, op); - // TODO: revert to varhandle - //EVENT_DATA_FD$VH.set(event, fd); - var data = epoll_event.data(event); - epoll_data.fd(data, fd); + EVENT_DATA_FD$VH.set(event, 0, fd); var ret = epoll_ctl(epfd, EPOLL_CTL_ADD(), fd, event, errorState); if (ret < 0) throwLastError(errorState, "internal error (epoll_ctl_add)"); @@ -108,9 +104,7 @@ static void removeFileDescriptor(int epfd, int fd) { var event = arena.allocate(epoll_event.layout()); epoll_event.events(event, 0); - // TODO: revert to varhandle - // EVENT_DATA_FD$VH.set(event, fd); - event.set(JAVA_INT, 0, fd); + EVENT_DATA_FD$VH.set(event, 0, fd); var ret = epoll_ctl(epfd, EPOLL_CTL_DEL(), fd, event, errorState); if (ret < 0) { var err = Linux.getErrno(errorState); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java index 5046aec9..ab494b91 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/Linux.java @@ -14,7 +14,6 @@ import java.lang.foreign.MemoryLayout.PathElement; import java.lang.foreign.MemorySegment; import java.lang.foreign.StructLayout; -import java.lang.foreign.ValueLayout; import java.lang.invoke.VarHandle; /** @@ -57,8 +56,6 @@ static String getErrorMessage(int err) { * @return error code */ static int getErrno(MemorySegment errorState) { - return errorState.get(ValueLayout.JAVA_INT, 0); - // TODO: revert to varhandle - // return (int) callState_errno$VH.get(errorState); + return (int) callState_errno$VH.get(errorState, 0); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index a58f0030..c72221d2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -8,7 +8,6 @@ package net.codecrete.usb.linux; import net.codecrete.usb.UsbTransferType; -import net.codecrete.usb.linux.gen.epoll.epoll_data; import net.codecrete.usb.linux.gen.epoll.epoll_event; import net.codecrete.usb.linux.gen.errno.errno; import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_urb; @@ -100,11 +99,7 @@ private void asyncCompletionTask() { // for all ready file descriptors, reap URBs for (int i = 0; i < res; i++) { - var event = events.asSlice(i * epoll_event.layout().byteSize(), epoll_event.layout()); - var data = epoll_event.data(event); - var fd = epoll_data.fd(data); - // TODO: revert to varhandle - // var fd = (int) EPoll.EVENT_ARRAY_DATA_FD$VH.get(events, i); + var fd = (int) EPoll.EVENT_ARRAY_DATA_FD$VH.get(events, 0, i); reapURBs(fd, urbPointerHolder, errorState); } } From 5fbfa68c019a2456b4e5f57186907136f958f404 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 18 Feb 2024 17:04:53 +0100 Subject: [PATCH 327/433] Upgrade examples --- README.md | 29 +- .../.mvn/wrapper/maven-wrapper.properties | 2 +- examples/bulk_transfer/README.md | 24 +- examples/bulk_transfer/mvnw.cmd | 410 +++++++++--------- examples/bulk_transfer/pom.xml | 42 +- .../.mvn/wrapper/maven-wrapper.properties | 2 +- examples/enumerate/README.md | 21 +- examples/enumerate/mvnw.cmd | 410 +++++++++--------- examples/enumerate/pom.xml | 42 +- .../.mvn/wrapper/maven-wrapper.properties | 2 +- examples/enumerate_kotlin/README.md | 8 +- examples/enumerate_kotlin/mvnw.cmd | 410 +++++++++--------- examples/enumerate_kotlin/pom.xml | 10 +- .../.mvn/wrapper/maven-wrapper.properties | 2 +- examples/epaper_display/README.md | 26 +- examples/epaper_display/mvnw.cmd | 410 +++++++++--------- examples/epaper_display/pom.xml | 36 +- .../.mvn/wrapper/maven-wrapper.properties | 2 +- examples/monitor/README.md | 34 +- examples/monitor/mvnw.cmd | 410 +++++++++--------- examples/monitor/pom.xml | 42 +- .../.mvn/wrapper/maven-wrapper.properties | 2 +- examples/monitor_kotlin/README.md | 16 +- examples/monitor_kotlin/mvnw.cmd | 410 +++++++++--------- examples/monitor_kotlin/pom.xml | 10 +- .../.mvn/wrapper/maven-wrapper.properties | 2 +- examples/stm_dfu/README.md | 8 +- examples/stm_dfu/mvnw.cmd | 410 +++++++++--------- examples/stm_dfu/pom.xml | 33 +- java-does-usb/pom.xml | 2 +- 30 files changed, 1624 insertions(+), 1643 deletions(-) diff --git a/README.md b/README.md index 8a7e0b9c..fb85e906 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,17 @@ *Java Does USB* is a Java library for working with USB devices. It allows to query information about all conntected USB devices and to communicate with USB devices using custom / vendor specific protocols. (It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc.) -The library uses the [Foreign Function & Memory API](https://github.com/openjdk/panama-foreign) to access native APIs of the underlying operating system. It is written entirely in Java and does not need JNI or any native third-party library. The *Foreign Function & Memory API* (aka as project Panama) is currently in preview and will leave preview with Java 22. Currently, it can be used with Java 19, Java 20 or Java 21 (with preview features enabled). +The library uses the [Foreign Function & Memory API](https://github.com/openjdk/panama-foreign) to access native APIs of the underlying operating system. It is written entirely in Java and does not need JNI or any native third-party library. The *Foreign Function & Memory API* (aka as project Panama) has been introduced with Java 22. Older versions of this library can be used with preview versions of the API that were available in Java 19, Java 20 or Java 21 (with preview features enabled). | Version | Main New Features | Compatibility | | - | - | - | +| 1.0.x | Release for final Java API | JDK 22 | | 0.7.x | New setter/getter names for improved Kotlin support; Kotlin examples | JDK 21 | | 0.6.x | Support for JDK 21; better handling of composite devices on Windows | JDK 21 | | 0.5.x | Support for JDK 20; high-throuput I/O streams | JDK 20 | | 0.4.x | Early release | JDK 19 | -*Note: The main branch and published versions ≥ 0.6.0 work with JDK 21 only. For JDK 20, use version 0.5.*. For JDK 19, use version 0.4.x. +*Note: The main branch and published versions ≥ 1.0 work with JDK 22 and later only. For JDK 21, user version 0.7.*. For JDK 20, use version 0.5.*. For JDK 19, use version 0.4.x. ## Features @@ -48,14 +49,14 @@ If you are using Maven, add the below dependency to your pom.xml: net.codecrete.usb java-does-usb - 0.7.1 + 1.0.0-SNAPSHOT ``` If you are using Gradle, add the below dependency to your build.gradle file: ```groovy -compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '0.7.1' +compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '1.0.0-SNAPSHOT' ``` ```java @@ -90,10 +91,10 @@ public class EnumerateDevices { ## Prerequisite -- Java 21, preview features enabled (available at https://www.azul.com/downloads/?package=jdk) +- Java 22 (available at https://www.azul.com/downloads/?package=jdk) - Windows (x86 64-bit), macOS (x86 64-bit, ARM 64-bit) or Linux 64 bit (x86 64-bit, ARM 64-bit) -For JDK 20, use the latest published version 0.5.x. For JDK 19, use the latest published version 0.4.x. +For JDK 21, use the latest published version 0.7.x. For JDK 20, use the latest published version 0.5.x. For JDK 19, use the latest published version 0.4.x. ## Platform-specific Considerations @@ -101,12 +102,12 @@ For JDK 20, use the latest published version 0.5.x. For JDK 19, use the latest p ### macOS -No special considerations apply. Using this library, a Java application can connect to any USB device and claim any interfaces that isn't claimed by an operating system driver or another application. Standard operation-system drivers can be unloaded if the application is run with root privileges. +No special considerations apply. Using this library, a Java application can connect to any USB device and claim any interfaces that isn't claimed by an operating system driver or another application. Standard operation-system drivers can be unloaded if the application is run with root privileges. It runs both on Macs with Apple Silicion and Intel processors. ### Linux -*libudev* is used to discover and monitor USB devices. It is closely tied to *systemd*. So the library only runs on Linux distributions with *systemd* and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfill this requirement. +*libudev* is used to discover and monitor USB devices. It is closely tied to *systemd*. So the library only runs on Linux distributions with *systemd* and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfill this requirement. It runs on both Intel and ARM64 processors. Similar to macOS, a Java application can connect to any USB device and claim any interfaces that isn't claimed by an operating system driver or another application. Standard operation system drivers can be unloaded (without the need for root privileges). @@ -129,17 +130,11 @@ USB devices can implement certain control requests to instruct Windows to automa The test devices implement the required control requests. So the driver is installed automatically. -The library has not been tested on Windows for ARM64. It might or might not work. +Windows for ARM64 is not yet supported. A port is probably easy, provided you have hardware to test it. ### Troubleshooting -#### `ClassFormatError` (all platforms) - -The error `java.lang.ClassFormatError: Illegal field name "" in class net/codecrete/usb/windows/WindowsUsbDeviceRegistry` is caused by a bug in JDK 21, which has been fixed in the mean-time. Please upgrade to the latest release of JDK 21 (at least 21.0.1). - - - ### 32-bit versions The Foreign Function & Memory API has not been implemented for 32-bit operating systems / JDKs (and likely never will be). @@ -170,11 +165,11 @@ mvn clean test If they are run from an IDE (such as IntelliJ IDEA), you must likely configure VM options to enable preview features and allow native access: ``` ---enable-preview --enable-native-access=net.codecrete.usb +--enable-native-access=net.codecrete.usb ``` Or (if modules are ignored): ``` ---enable-preview --enable-native-access=ALL-UNNAMED +--enable-native-access=ALL-UNNAMED ``` diff --git a/examples/bulk_transfer/.mvn/wrapper/maven-wrapper.properties b/examples/bulk_transfer/.mvn/wrapper/maven-wrapper.properties index 6d3a5665..f3283b08 100644 --- a/examples/bulk_transfer/.mvn/wrapper/maven-wrapper.properties +++ b/examples/bulk_transfer/.mvn/wrapper/maven-wrapper.properties @@ -14,5 +14,5 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index dd25eb8c..2758c3a3 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -4,16 +4,16 @@ This sample shows how to find a device, open it and transfer data from and to bu ## Prerequisites -- Java 21 +- Java 22 - Apache Maven - 64-bit operating system (Windows, macOS, Linux) - A USB device with bulk IN and OUT endpoints (e.g. the test device, see https://github.com/manuelbl/JavaDoesUSB/tree/main/test-devices/loopback-stm32) ## How to run -### Install Java 21 +### Install Java 22 -Check that *Java 21* is installed: +Check that *Java 22* is installed: ```shell $ java -version @@ -39,24 +39,22 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] --------------< net.codecrete.usb.examples:bulk-transfer >-------------- -[INFO] Building bulk-transfer 0.7.1 +[INFO] Building bulk-transfer 1.0.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] -[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ bulk-transfer --- -[INFO] Using 'UTF-8' encoding to copy filtered resources. -[INFO] skip non existing resourceDirectory /Users/me/Documents/JavaDoesUSB/examples/bulk_transfer/src/main/resources +[INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ bulk-transfer --- +[INFO] skip non existing resourceDirectory /home/user/Documents/JavaDoesUSB/examples/bulk_transfer/src/main/resources [INFO] -[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ bulk-transfer --- -[INFO] Changes detected - recompiling the module! -[INFO] Compiling 1 source file to /Users/me/Documents/JavaDoesUSB/examples/bulk_transfer/target/classes +[INFO] --- maven-compiler-plugin:3.12.1:compile (default-compile) @ bulk-transfer --- +[INFO] Nothing to compile - all classes are up to date. [INFO] -[INFO] --- exec-maven-plugin:3.1.0:exec (default-cli) @ bulk-transfer --- +[INFO] --- exec-maven-plugin:3.1.1:exec (default-cli) @ bulk-transfer --- 6 bytes sent. 6 bytes received. [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ -[INFO] Total time: 1.259 s -[INFO] Finished at: 2023-03-23T14:10:17+01:00 +[INFO] Total time: 1.228 s +[INFO] Finished at: 2024-02-18T16:23:29+01:00 [INFO] ------------------------------------------------------------------------ ``` diff --git a/examples/bulk_transfer/mvnw.cmd b/examples/bulk_transfer/mvnw.cmd index c4586b56..f80fbad3 100644 --- a/examples/bulk_transfer/mvnw.cmd +++ b/examples/bulk_transfer/mvnw.cmd @@ -1,205 +1,205 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.2.0 -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %WRAPPER_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file -SET WRAPPER_SHA_256_SUM="" -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B -) -IF NOT %WRAPPER_SHA_256_SUM%=="" ( - powershell -Command "&{"^ - "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ - "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ - " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ - " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ - " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ - " exit 1;"^ - "}"^ - "}" - if ERRORLEVEL 1 goto error -) - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index fbf1a3c8..6613a04f 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,86 +6,82 @@ net.codecrete.usb.examples bulk-transfer - 0.7.1 + 1.0.0-SNAPSHOT bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer UTF-8 - 21 - 21 + 22 + 22 net.codecrete.usb java-does-usb - 0.7.1 + 1.0.0-SNAPSHOT - + maven-clean-plugin - 3.1.0 + 3.3.2 maven-resources-plugin - 3.0.2 + 3.3.1 maven-compiler-plugin - 3.8.0 + 3.12.1 - 21 - - --enable-preview - - 21 - 21 + 22 + 22 + 22 maven-surefire-plugin - 2.22.1 + 3.2.5 - --enable-preview --enable-native-access=ALL-UNNAMED + --enable-native-access=ALL-UNNAMED maven-jar-plugin - 3.0.2 + 3.3.0 maven-install-plugin - 2.5.2 + 3.1.1 maven-deploy-plugin - 2.8.2 + 3.1.1 maven-site-plugin - 3.7.1 + 3.12.1 maven-project-info-reports-plugin - 3.0.0 + 3.5.0 org.codehaus.mojo exec-maven-plugin - 3.1.0 + 3.1.1 java - --enable-preview --enable-native-access=ALL-UNNAMED -classpath diff --git a/examples/enumerate/.mvn/wrapper/maven-wrapper.properties b/examples/enumerate/.mvn/wrapper/maven-wrapper.properties index 6d3a5665..f3283b08 100644 --- a/examples/enumerate/.mvn/wrapper/maven-wrapper.properties +++ b/examples/enumerate/.mvn/wrapper/maven-wrapper.properties @@ -14,5 +14,5 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index 992275e2..907e1cf0 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -4,15 +4,15 @@ This sample enumerates the connected USB devices and provides information about ## Prerequisites -- Java 21 +- Java 22 - Apache Maven - 64-bit operating system (Windows, macOS, Linux) ## How to run -### Install Java 21 +### Install Java 22 -Check that *Java 21* is installed: +Check that *Java 22* is installed: ```shell $ java -version @@ -38,22 +38,21 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] ----------------< net.codecrete.usb.examples:enumerate >---------------- -[INFO] Building enumerate 0.7.1 +[INFO] Building enumerate 1.0.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] -[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ enumerate --- -[INFO] Using 'UTF-8' encoding to copy filtered resources. -[INFO] skip non existing resourceDirectory /Users/me/Documents/JavaDoesUSB/examples/enumerate/src/main/resources +[INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ enumerate --- +[INFO] Copying 1 resource from src/main/resources to target/classes [INFO] -[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ enumerate --- -[INFO] Changes detected - recompiling the module! -[INFO] Compiling 2 source files to /Users/me/Documents/JavaDoesUSB/examples/enumerate/target/classes +[INFO] --- maven-compiler-plugin:3.12.1:compile (default-compile) @ enumerate --- +[INFO] Nothing to compile - all classes are up to date. [INFO] -[INFO] --- exec-maven-plugin:3.1.0:exec (default-cli) @ enumerate --- +[INFO] --- exec-maven-plugin:3.1.1:exec (default-cli) @ enumerate --- Device: VID: 0xcafe PID: 0xceaf Manufacturer: JavaDoesUSB Product name: Loopback + Serial number: 35A737883336 ... ``` diff --git a/examples/enumerate/mvnw.cmd b/examples/enumerate/mvnw.cmd index c4586b56..f80fbad3 100644 --- a/examples/enumerate/mvnw.cmd +++ b/examples/enumerate/mvnw.cmd @@ -1,205 +1,205 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.2.0 -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %WRAPPER_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file -SET WRAPPER_SHA_256_SUM="" -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B -) -IF NOT %WRAPPER_SHA_256_SUM%=="" ( - powershell -Command "&{"^ - "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ - "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ - " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ - " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ - " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ - " exit 1;"^ - "}"^ - "}" - if ERRORLEVEL 1 goto error -) - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index 00aa0f97..c4df53d9 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,22 +6,22 @@ net.codecrete.usb.examples enumerate - 0.7.1 + 1.0.0-SNAPSHOT enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate UTF-8 - 21 - 21 + 22 + 22 net.codecrete.usb java-does-usb - 0.7.1 + 1.0.0-SNAPSHOT org.tinylog @@ -41,66 +41,62 @@ - + maven-clean-plugin - 3.1.0 + 3.3.2 maven-resources-plugin - 3.0.2 + 3.3.1 maven-compiler-plugin - 3.8.0 + 3.12.1 - 21 - - --enable-preview - - 21 - 21 + 22 + 22 + 22 maven-surefire-plugin - 2.22.1 + 3.2.5 - --enable-preview --enable-native-access=ALL-UNNAMED + --enable-native-access=ALL-UNNAMED maven-jar-plugin - 3.0.2 + 3.3.0 maven-install-plugin - 2.5.2 + 3.1.1 maven-deploy-plugin - 2.8.2 + 3.1.1 maven-site-plugin - 3.7.1 + 3.12.1 maven-project-info-reports-plugin - 3.0.0 + 3.5.0 org.codehaus.mojo exec-maven-plugin - 3.1.0 + 3.1.1 java - --enable-preview --enable-native-access=ALL-UNNAMED -classpath diff --git a/examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.properties b/examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.properties index eacdc9ed..f3283b08 100644 --- a/examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.properties +++ b/examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.properties @@ -14,5 +14,5 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/enumerate_kotlin/README.md b/examples/enumerate_kotlin/README.md index 6a5e14e2..4f85c62f 100644 --- a/examples/enumerate_kotlin/README.md +++ b/examples/enumerate_kotlin/README.md @@ -4,15 +4,15 @@ This sample enumerates the connected USB devices and provides information about ## Prerequisites -- Java 21 +- Java 22 - Apache Maven - 64-bit operating system (Windows, macOS, Linux) ## How to run -### Install Java 21 +### Install Java 22 -Check that *Java 21* is installed: +Check that *Java 22* is installed: ```shell $ java -version @@ -40,7 +40,7 @@ $ mvn clean package ### Run the jar ```shell -$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/enumerate-0.7.1-jar-with-dependencies.jar +$ java --enable-native-access=ALL-UNNAMED -jar target/enumerate-1.0.0-SNAPSHOT-jar-with-dependencies.jar Device: VID: 0xcafe PID: 0xceaf diff --git a/examples/enumerate_kotlin/mvnw.cmd b/examples/enumerate_kotlin/mvnw.cmd index c4586b56..f80fbad3 100644 --- a/examples/enumerate_kotlin/mvnw.cmd +++ b/examples/enumerate_kotlin/mvnw.cmd @@ -1,205 +1,205 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.2.0 -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %WRAPPER_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file -SET WRAPPER_SHA_256_SUM="" -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B -) -IF NOT %WRAPPER_SHA_256_SUM%=="" ( - powershell -Command "&{"^ - "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ - "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ - " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ - " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ - " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ - " exit 1;"^ - "}"^ - "}" - if ERRORLEVEL 1 goto error -) - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/examples/enumerate_kotlin/pom.xml b/examples/enumerate_kotlin/pom.xml index 91d8b9af..c6e41240 100644 --- a/examples/enumerate_kotlin/pom.xml +++ b/examples/enumerate_kotlin/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples enumerate - 0.7.1 + 1.0.0-SNAPSHOT jar enumerate @@ -64,22 +64,22 @@ net.codecrete.usb java-does-usb - 0.7.1 + 1.0.0-SNAPSHOT org.tinylog tinylog-api - 2.6.2 + 2.7.0 org.tinylog tinylog-impl - 2.6.2 + 2.7.0 org.tinylog jsl-tinylog - 2.6.2 + 2.7.0 junit diff --git a/examples/epaper_display/.mvn/wrapper/maven-wrapper.properties b/examples/epaper_display/.mvn/wrapper/maven-wrapper.properties index 6d3a5665..f3283b08 100644 --- a/examples/epaper_display/.mvn/wrapper/maven-wrapper.properties +++ b/examples/epaper_display/.mvn/wrapper/maven-wrapper.properties @@ -14,5 +14,5 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/epaper_display/README.md b/examples/epaper_display/README.md index 684bd25f..7b98499c 100644 --- a/examples/epaper_display/README.md +++ b/examples/epaper_display/README.md @@ -4,7 +4,7 @@ This sample shows how to communicate with an IT8951 controller for e-paper displ ## Prerequisites -- Java 21 +- Java 22 - Apache Maven - 64-bit operating system (macOS, Linux, Windows) - IT8951 controller @@ -17,9 +17,9 @@ be temporarily detached.) ## How to run -### Install Java 21 +### Install Java 22 -Check that *Java 21* is installed: +Check that *Java 22* is installed: ```shell $ java -version @@ -45,24 +45,22 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -------------< net.codecrete.usb.examples:epaper-display >-------------- -[INFO] Building epaper-display 0.7.1 -[INFO] from pom.xml +[INFO] Building epaper-display 1.0.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] -[INFO] --- resources:3.3.1:resources (default-resources) @ epaper-display --- -[INFO] skip non existing resourceDirectory /Users/me/Documents/JavaDoesUSB/examples/epaper_display/src/main/resources +[INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ epaper-display --- +[INFO] skip non existing resourceDirectory /home/user/Documents/JavaDoesUSB/examples/epaper_display/src/main/resources [INFO] -[INFO] --- compiler:3.11.0:compile (default-compile) @ epaper-display --- -[INFO] Changes detected - recompiling the module! :source -[INFO] Compiling 2 source files with javac [debug release 20] to target/classes +[INFO] --- maven-compiler-plugin:3.12.1:compile (default-compile) @ epaper-display --- +[INFO] Nothing to compile - all classes are up to date. [INFO] -[INFO] --- exec:3.1.0:exec (default-cli) @ epaper-display --- +[INFO] --- exec-maven-plugin:3.1.1:exec (default-cli) @ epaper-display --- Display size: 1200 x 825 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ -[INFO] Total time: 1.502 s -[INFO] Finished at: 2023-07-02T14:08:50+02:00 +[INFO] Total time: 2.247 s +[INFO] Finished at: 2024-02-18T16:48:43+01:00 [INFO] ------------------------------------------------------------------------ ``` @@ -81,6 +79,6 @@ $ sudo -i Password: $ cd /Users/me/Documents/JavaDoesUSB/examples/epaper_display $ export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-20.jdk/Contents/Home -$ $JAVA_HOME/bin/java --enable-preview --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/0.7.1/java-does-usb-0.7.1.jar net.codecrete.usb.examples.EPaperDisplay +$ $JAVA_HOME/bin/java --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/1.0.0-SNAPSHOT/java-does-usb-1.0.0-SNAPSHOT.jar net.codecrete.usb.examples.EPaperDisplay Display size: 1200 x 825 ``` diff --git a/examples/epaper_display/mvnw.cmd b/examples/epaper_display/mvnw.cmd index c4586b56..f80fbad3 100644 --- a/examples/epaper_display/mvnw.cmd +++ b/examples/epaper_display/mvnw.cmd @@ -1,205 +1,205 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.2.0 -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %WRAPPER_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file -SET WRAPPER_SHA_256_SUM="" -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B -) -IF NOT %WRAPPER_SHA_256_SUM%=="" ( - powershell -Command "&{"^ - "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ - "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ - " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ - " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ - " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ - " exit 1;"^ - "}"^ - "}" - if ERRORLEVEL 1 goto error -) - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/examples/epaper_display/pom.xml b/examples/epaper_display/pom.xml index 6f5ef1ac..1cf46fb0 100644 --- a/examples/epaper_display/pom.xml +++ b/examples/epaper_display/pom.xml @@ -6,32 +6,32 @@ net.codecrete.usb.examples epaper-display - 0.7.1 + 1.0.0-SNAPSHOT epaper-display https://github.com/manuelbl/JavaDoesUSB/examples/epaper_display UTF-8 - 21 - 21 + 22 + 22 net.codecrete.usb java-does-usb - 0.7.1 + 1.0.0-SNAPSHOT - + maven-clean-plugin - 3.3.1 + 3.3.2 @@ -40,26 +40,23 @@ maven-compiler-plugin - 3.11.0 + 3.12.1 - 21 - - --enable-preview - - 21 - 21 + 22 + 22 + 22 maven-surefire-plugin - 2.22.1 + 3.2.5 - --enable-preview --enable-native-access=ALL-UNNAMED + --enable-native-access=ALL-UNNAMED maven-jar-plugin - 3.1.2 + 3.3.0 maven-install-plugin @@ -76,16 +73,15 @@ maven-project-info-reports-plugin - 3.4.5 + 3.5.0 org.codehaus.mojo exec-maven-plugin - 3.1.0 + 3.1.1 - ${JAVA_HOME}/bin/java + java - --enable-preview --enable-native-access=ALL-UNNAMED -classpath diff --git a/examples/monitor/.mvn/wrapper/maven-wrapper.properties b/examples/monitor/.mvn/wrapper/maven-wrapper.properties index 6d3a5665..f3283b08 100644 --- a/examples/monitor/.mvn/wrapper/maven-wrapper.properties +++ b/examples/monitor/.mvn/wrapper/maven-wrapper.properties @@ -14,5 +14,5 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/monitor/README.md b/examples/monitor/README.md index e267ff1e..6c758965 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -4,15 +4,15 @@ This sample program monitors USB devices as they are connected and disconnected. ## Prerequisites -- Java 21 +- Java 22 - Apache Maven - 64-bit operating system (Windows, macOS, Linux) ## How to run -### Install Java 21 +### Install Java 22 -Check that *Java 21* is installed: +Check that *Java 22* is installed: ```shell $ java -version @@ -35,22 +35,30 @@ If it is not present, install it, typically using package manager like *Homebrew ```shell $ cd JavaDoesUSB/examples/monitor $ mvn compile exec:exec + [INFO] Scanning for projects... [INFO] [INFO] -----------------< net.codecrete.usb.examples:monitor >----------------- -[INFO] Building monitor 0.7.1 +[INFO] Building monitor 1.0.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] -[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ monitor --- -[INFO] Using 'UTF-8' encoding to copy filtered resources. -[INFO] skip non existing resourceDirectory /Users/me/Documents/JavaDoesUSB/examples/monitor/src/main/resources +[INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ monitor --- +[INFO] Copying 1 resource from src/main/resources to target/classes [INFO] -[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ monitor --- -[INFO] Changes detected - recompiling the module! -[INFO] Compiling 1 source file to /Users/me/Documents/JavaDoesUSB/examples/monitor/target/classes +[INFO] --- maven-compiler-plugin:3.12.1:compile (default-compile) @ monitor --- +[INFO] Nothing to compile - all classes are up to date. [INFO] -[INFO] --- exec-maven-plugin:3.1.0:exec (default-cli) @ monitor --- -Present: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 8D8F515C5456, ID: 4295291950 -Present: VID: 0x1a40, PID: 0x0801, manufacturer: null, product: USB 2.0 Hub, serial: null, ID: 4295291734 +[INFO] --- exec-maven-plugin:3.1.1:exec (default-cli) @ monitor --- +Present: VID: 0x1d6b, PID: 0x0002, manufacturer: Linux 6.5.0-18-generic xhci-hcd, product: xHCI Host Controller, serial: 0000:00:14.0, ID: /dev/bus/usb/001/001 +Present: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 35A737883336, ID: /dev/bus/usb/001/005 Monitoring... Press ENTER to quit. +Disconnected: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 35A737883336, ID: /dev/bus/usb/001/005 +Connected: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 35A737883336, ID: /dev/bus/usb/001/009 + +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 17.647 s +[INFO] Finished at: 2024-02-18T16:50:59+01:00 +[INFO] ----------------------------------------------------------------------- ``` diff --git a/examples/monitor/mvnw.cmd b/examples/monitor/mvnw.cmd index c4586b56..f80fbad3 100644 --- a/examples/monitor/mvnw.cmd +++ b/examples/monitor/mvnw.cmd @@ -1,205 +1,205 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.2.0 -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %WRAPPER_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file -SET WRAPPER_SHA_256_SUM="" -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B -) -IF NOT %WRAPPER_SHA_256_SUM%=="" ( - powershell -Command "&{"^ - "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ - "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ - " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ - " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ - " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ - " exit 1;"^ - "}"^ - "}" - if ERRORLEVEL 1 goto error -) - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index 8b3d614d..190039cd 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,22 +6,22 @@ net.codecrete.usb.examples monitor - 0.7.1 + 1.0.0-SNAPSHOT monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor UTF-8 - 21 - 21 + 22 + 22 net.codecrete.usb java-does-usb - 0.7.1 + 1.0.0-SNAPSHOT org.tinylog @@ -41,66 +41,62 @@ - + maven-clean-plugin - 3.1.0 + 3.3.2 maven-resources-plugin - 3.0.2 + 3.3.1 maven-compiler-plugin - 3.8.0 + 3.12.1 - 21 - - --enable-preview - - 21 - 21 + 22 + 22 + 22 maven-surefire-plugin - 2.22.1 + 3.2.5 - --enable-preview --enable-native-access=ALL-UNNAMED + --enable-native-access=ALL-UNNAMED maven-jar-plugin - 3.0.2 + 3.3.0 maven-install-plugin - 2.5.2 + 3.1.1 maven-deploy-plugin - 2.8.2 + 3.1.1 maven-site-plugin - 3.7.1 + 3.12.1 maven-project-info-reports-plugin - 3.0.0 + 3.5.0 org.codehaus.mojo exec-maven-plugin - 3.1.0 + 3.1.1 java - --enable-preview --enable-native-access=ALL-UNNAMED -classpath diff --git a/examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.properties b/examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.properties index eacdc9ed..f3283b08 100644 --- a/examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.properties +++ b/examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.properties @@ -14,5 +14,5 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/monitor_kotlin/README.md b/examples/monitor_kotlin/README.md index ba40402a..af199253 100644 --- a/examples/monitor_kotlin/README.md +++ b/examples/monitor_kotlin/README.md @@ -4,15 +4,15 @@ This sample enumerates the connected USB devices and provides information about ## Prerequisites -- Java 21 +- Java 22 - Apache Maven - 64-bit operating system (Windows, macOS, Linux) ## How to run -### Install Java 21 +### Install Java 22 -Check that *Java 21* is installed: +Check that *Java 22* is installed: ```shell $ java -version @@ -40,10 +40,10 @@ $ mvn clean package ### Run the jar ```shell -$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/monitor-0.7.1-jar-with-dependencies.jar -WARNING: "public static final void net.codecrete.usb.examples.MonitorKt.main()" chosen over "public static void net.codecrete.usb.examples.MonitorKt.main(java.lang.String[])" -Present: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 35A737883336, ID: 4295265643 -Present: VID: 0x1a40, PID: 0x0801, manufacturer: null, product: USB 2.0 Hub, serial: null, ID: 4295259660 +$ java --enable-native-access=ALL-UNNAMED -jar target/monitor-1.0.0-SNAPSHOT-jar-with-dependencies.jar +Present: VID: 0x1d6b, PID: 0x0002, manufacturer: Linux 6.5.0-18-generic xhci-hcd, product: xHCI Host Controller, serial: 0000:00:14.0, ID: /dev/bus/usb/001/001 +Present: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 35A737883336, ID: /dev/bus/usb/001/009 Monitoring... Press ENTER to quit. -... +Disconnected: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 35A737883336, ID: /dev/bus/usb/001/009 +Connected: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 35A737883336, ID: /dev/bus/usb/001/010 ``` diff --git a/examples/monitor_kotlin/mvnw.cmd b/examples/monitor_kotlin/mvnw.cmd index c4586b56..f80fbad3 100644 --- a/examples/monitor_kotlin/mvnw.cmd +++ b/examples/monitor_kotlin/mvnw.cmd @@ -1,205 +1,205 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.2.0 -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %WRAPPER_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file -SET WRAPPER_SHA_256_SUM="" -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B -) -IF NOT %WRAPPER_SHA_256_SUM%=="" ( - powershell -Command "&{"^ - "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ - "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ - " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ - " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ - " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ - " exit 1;"^ - "}"^ - "}" - if ERRORLEVEL 1 goto error -) - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/examples/monitor_kotlin/pom.xml b/examples/monitor_kotlin/pom.xml index b3e91b5e..cdae381e 100644 --- a/examples/monitor_kotlin/pom.xml +++ b/examples/monitor_kotlin/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples monitor - 0.7.1 + 1.0.0-SNAPSHOT jar monitor @@ -64,22 +64,22 @@ net.codecrete.usb java-does-usb - 0.7.1 + 1.0.0-SNAPSHOT org.tinylog tinylog-api - 2.6.2 + 2.7.0 org.tinylog tinylog-impl - 2.6.2 + 2.7.0 org.tinylog jsl-tinylog - 2.6.2 + 2.7.0 junit diff --git a/examples/stm_dfu/.mvn/wrapper/maven-wrapper.properties b/examples/stm_dfu/.mvn/wrapper/maven-wrapper.properties index 6d3a5665..f3283b08 100644 --- a/examples/stm_dfu/.mvn/wrapper/maven-wrapper.properties +++ b/examples/stm_dfu/.mvn/wrapper/maven-wrapper.properties @@ -14,5 +14,5 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index acab0b6c..df76a714 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -6,15 +6,15 @@ Even though the DFU ## Prerequisites -- Java 21 +- Java 22 - Apache Maven - 64-bit operating system (Windows, macOS, Linux) ## How to run -### Install Java 21 +### Install Java 22 -Check that *Java 21* is installed: +Check that *Java 22* is installed: ```shell $ java -version @@ -58,7 +58,7 @@ Run the command below (adapting the file path depending on your specific board): ```shell $ mvn package -$ java --enable-preview --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-0.7.1.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin +$ java --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-1.0.0-SNAPSHOT.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin DFU device found with serial 35A737883336. Target memory segment: Internal Flash Erasing page at 0x8000000 (size 0x4000) diff --git a/examples/stm_dfu/mvnw.cmd b/examples/stm_dfu/mvnw.cmd index c4586b56..f80fbad3 100644 --- a/examples/stm_dfu/mvnw.cmd +++ b/examples/stm_dfu/mvnw.cmd @@ -1,205 +1,205 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.2.0 -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %WRAPPER_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file -SET WRAPPER_SHA_256_SUM="" -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B -) -IF NOT %WRAPPER_SHA_256_SUM%=="" ( - powershell -Command "&{"^ - "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ - "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ - " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ - " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ - " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ - " exit 1;"^ - "}"^ - "}" - if ERRORLEVEL 1 goto error -) - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index 4891d1ee..5a47b5a4 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -4,61 +4,60 @@ net.codecrete.usb.examples stm_dfu - 0.7.1 + 1.0.0-SNAPSHOT stm_dfu https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu UTF-8 - 21 - 21 + 22 + 22 net.codecrete.usb java-does-usb - 0.7.1 + 1.0.0-SNAPSHOT + maven-clean-plugin - 3.1.0 + 3.3.2 + maven-resources-plugin - 3.0.2 + 3.3.1 maven-compiler-plugin - 3.8.0 + 3.12.1 - 21 - - --enable-preview - - 21 - 21 + 22 + 22 + 22 maven-jar-plugin - 3.0.2 + 3.3.0 maven-surefire-plugin - 2.22.2 + 3.2.5 - --enable-preview --enable-native-access=ALL-UNNAMED + --enable-native-access=ALL-UNNAMED maven-shade-plugin - 3.3.0 + 3.5.1 package diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index f3a4fffe..3d3e0888 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -66,7 +66,7 @@ maven-surefire-plugin 3.2.5 - --enable-native-access=ALL-UNNAMED + --enable-native-access=net.codecrete.usb From 9f31481e4e5ad9a436fc64125234c05768001f34 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 20 Feb 2024 19:51:18 +0100 Subject: [PATCH 328/433] Linux: use latest jextract --- java-does-usb/jextract/README.md | 20 +++++-------------- java-does-usb/jextract/linux/gen_linux.sh | 2 +- .../codecrete/usb/linux/gen/epoll/epoll.java | 18 +++++++++++++++++ .../usb/linux/gen/epoll/epoll_data.java | 4 ++-- .../usb/linux/gen/epoll/epoll_event.java | 4 ++-- .../codecrete/usb/linux/gen/errno/errno.java | 18 +++++++++++++++++ .../codecrete/usb/linux/gen/fcntl/fcntl.java | 18 +++++++++++++++++ .../usb/linux/gen/string/string.java | 18 +++++++++++++++++ .../codecrete/usb/linux/gen/udev/udev.java | 18 +++++++++++++++++ .../usb/linux/gen/unistd/unistd.java | 18 +++++++++++++++++ .../linux/gen/usbdevice_fs/usbdevice_fs.java | 18 +++++++++++++++++ 11 files changed, 136 insertions(+), 20 deletions(-) diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index 2054483a..ce04242b 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -13,19 +13,11 @@ The resulting code is then committed to the source code repository. Before the c ## General limitations -- The binaries for *jextract* on https://jdk.java.net/jextract/ have not been updated for JDK 21. So it must be built from source. Instructions can be found at [Building & Testing](https://github.com/openjdk/jextract#building--testing). - - According to the jextract mailing list, it would be required to create separate code for Intel x64 and ARM64 architecture. And jextract would need to be run on each architecture separately (no cross-compilation). Fortunately, this doesn't seem to be the case. Linux code generated on Intel x64 also runs on ARM64 without change. The same holds for macOS. However, jextract needs to be run on each operating system separately. - JDK 20 introduced a new feature for saving the thread-specific error values (`GetLastError()` on Windows, `errno` on Linux). To use it, an additional parameter must be added to function calls. Unfortunately, this is not yet supported by jextract. So a good number of function bindings have to be written manually. -- `typedef` and `struct`: - - 1. If only the `typedef` is included (`--include-typedef`), an empty Java class is generated. - 2. If both *typedef* and the `struct` it refers to are included, the `typedef` class inherits from the `struct` class, which contains all the `struct` members. - 3. If the `typedef` refers to an unnamed `struct`, the generated class contains all the `struct` members. - - Case 1 looks like a bug. +- Dependencies: to be updated... - *jextract* is not really transparent about what it does. It often skips elements without providing any information. In particular, it will silently skip a requested element in these cases: @@ -37,7 +29,6 @@ The resulting code is then committed to the source code repository. Before the c - `--include-typedef mytypedef` if `mytypedef` is a `typedef` for a primitive type. - ## Linux To run the script, the header files for *libudev* must be present. In most cases, they aren't install by default (in contrast to the library itself): @@ -48,21 +39,20 @@ sudo apt-get install libudev-dev On Linux, the limitations are: -- `usbdevice_fs.h`: The macro `USBDEVFS_CONTROL` and all similar ones are not generated. They are probably considered function-like macros. *jextract* does not generate code for function-like macros. But `USBDEVFS_CONTROL` evaluates to a constant. +- `usbdevice_fs.h`: The macro `USBDEVFS_CONTROL` and all similar ones are not generated. They are probably considered function-like macros. *jextract* does not generate code for function-like macros. `USBDEVFS_CONTROL` would evaluate to a constant. - `sd-device.h` (header file for *libsystemd*): *jextract* fails with *"Error: /usr/include/inttypes.h:290:8: error: unknown type name 'intmax_t'"*. The reason is yet unknown. This code is currently not needed as *libudev* is used instead of *libsystemd*. They are related, *libsystemd* is the future solution, but it is missing support for monitoring devices. -- `libudev.h`: After code generation, the class `RuntimeHelper.java` in `.../linux/gen/udev` must be manually modified as the code to access the library does not work for the directory the library is located in. So replace: +- `libudev.h`: After code generation, the class `udev` in `.../linux/gen/udev` must be manually modified. In most Linux installations, there is no `libudev.so` alias to an actual version like `libudev.so.1.7.2`. The only alias is `libudev.so.1`. This is probably a deliberate decision by the authors as they do not plan to provide backward compatibility across major versions. But there does not seem to be a way to make *jextract* generate valid code for this setup. So manually replace: ``` -System.loadLibrary("udev"); -SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); +static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("udev"), LIBRARY_ARENA) ``` with: ``` -SymbolLookup loaderLookup = SymbolLookup.libraryLookup("libudev.so", MemorySession.openImplicit()); +static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup("libudev.so.1", LIBRARY_ARENA) ``` diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index b1eba46a..2e8b3af8 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -1,6 +1,6 @@ #!/bin/sh -JEXTRACT=../../../../jextract-22/bin/jextract +JEXTRACT=../../../../jextract/build/jextract/bin/jextract # errno.h $JEXTRACT --output ../../src/main/java \ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java index 670be9c3..b3851555 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java @@ -5,9 +5,13 @@ import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.StructLayout; import java.lang.foreign.SymbolLookup; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; @@ -46,6 +50,20 @@ static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fd } } + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() .or(Linker.nativeLinker().defaultLookup()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_data.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_data.java index 567b218d..c4fb6f1d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_data.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_data.java @@ -31,10 +31,10 @@ public class epoll_data { } private static final GroupLayout $LAYOUT = MemoryLayout.unionLayout( - epoll.C_POINTER.withName("ptr").withByteAlignment(4), + epoll.C_POINTER.withName("ptr"), epoll.C_INT.withName("fd"), epoll.C_INT.withName("u32"), - epoll.C_LONG.withName("u64").withByteAlignment(4) + epoll.C_LONG.withName("u64") ).withName("epoll_data"); /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java index fc3bd418..90269384 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java @@ -27,8 +27,8 @@ public class epoll_event { } private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - epoll.C_INT.withByteAlignment(1).withName("events"), - epoll_data.layout().withName("data") + epoll.align(epoll.C_INT, 1).withName("events"), + epoll.align(epoll_data.layout(), 1).withName("data") ).withName("epoll_event"); /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java index 554aff6e..dfb59b81 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -5,9 +5,13 @@ import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.StructLayout; import java.lang.foreign.SymbolLookup; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; @@ -46,6 +50,20 @@ static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fd } } + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() .or(Linker.nativeLinker().defaultLookup()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java index b02887b8..57e36438 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java @@ -5,9 +5,13 @@ import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.StructLayout; import java.lang.foreign.SymbolLookup; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; @@ -46,6 +50,20 @@ static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fd } } + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() .or(Linker.nativeLinker().defaultLookup()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java index 9ed3f222..c564f1f2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java @@ -5,9 +5,13 @@ import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.StructLayout; import java.lang.foreign.SymbolLookup; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; @@ -46,6 +50,20 @@ static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fd } } + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() .or(Linker.nativeLinker().defaultLookup()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java index 715246fe..295ca7be 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java @@ -5,9 +5,13 @@ import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.StructLayout; import java.lang.foreign.SymbolLookup; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; @@ -46,6 +50,20 @@ static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fd } } + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + // Manually fix. Otherwise, libudev will not be found if "libudev-dev" is not installed // static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("udev"), LIBRARY_ARENA) static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup("libudev.so.1", LIBRARY_ARENA) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java index b6300a9b..94151a73 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java @@ -5,9 +5,13 @@ import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.StructLayout; import java.lang.foreign.SymbolLookup; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; @@ -46,6 +50,20 @@ static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fd } } + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() .or(Linker.nativeLinker().defaultLookup()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java index e5b878ee..344dcf6c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java @@ -5,9 +5,13 @@ import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.StructLayout; import java.lang.foreign.SymbolLookup; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; @@ -46,6 +50,20 @@ static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fd } } + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() .or(Linker.nativeLinker().defaultLookup()); From 28a3f65fe4c235b7aea4c04537f48beec2ab63ed Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 20 Feb 2024 19:12:40 +0100 Subject: [PATCH 329/433] Windows: use latest jextract --- java-does-usb/jextract/README.md | 2 +- java-does-usb/jextract/windows/gen_win.cmd | 2 +- .../usb/windows/gen/advapi32/Advapi32.java | 18 ++++++++++++++++++ .../usb/windows/gen/kernel32/Kernel32.java | 18 ++++++++++++++++++ .../codecrete/usb/windows/gen/ntdll/NtDll.java | 18 ++++++++++++++++++ .../codecrete/usb/windows/gen/ole32/Ole32.java | 18 ++++++++++++++++++ .../usb/windows/gen/setupapi/SetupAPI.java | 18 ++++++++++++++++++ .../usb/windows/gen/usbioctl/USBIoctl.java | 18 ++++++++++++++++++ .../gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java | 8 ++++---- .../gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java | 8 ++++---- .../gen/usbioctl/_USB_ENDPOINT_DESCRIPTOR.java | 2 +- .../_USB_NODE_CONNECTION_INFORMATION_EX.java | 8 ++++---- .../windows/gen/usbioctl/_USB_PIPE_INFO.java | 2 +- .../usb/windows/gen/user32/User32.java | 18 ++++++++++++++++++ .../usb/windows/gen/winusb/WinUSB.java | 18 ++++++++++++++++++ 15 files changed, 160 insertions(+), 16 deletions(-) diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index ce04242b..25d6fc0e 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -65,7 +65,7 @@ The generated code has the same problem as the Linux code for *udev*. It must be ## Windows -Most Windows SDK header files are not independent. They require that `Windows.h` is included first. So instead of specifying the target header files directly, a helper header file (`windows_headers.h` in this directory) is specified. +Most Windows SDK header files are not independent. They require `Windows.h` to be included first. So instead of specifying the target header files directly, a helper header file (`windows_headers.h` in this directory) is specified. Compared to Linux and macOS, the code generation on Windows is very slow (about 1 min vs 3 seconds). And jextract crashes sometimes. diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index 752bca05..9970d958 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -1,4 +1,4 @@ -set JEXTRACT=..\..\..\..\jextract-22\bin\jextract.bat +set JEXTRACT=..\..\..\..\jextract\build\jextract\bin\jextract.bat set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 call %JEXTRACT% --output ../../src/main/java ^ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java index d72376d6..b015cf12 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java @@ -5,9 +5,13 @@ import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.StructLayout; import java.lang.foreign.SymbolLookup; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; @@ -46,6 +50,20 @@ static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fd } } + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("Advapi32"), LIBRARY_ARENA) .or(SymbolLookup.loaderLookup()) .or(Linker.nativeLinker().defaultLookup()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java index cebfe457..001fcc43 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -5,9 +5,13 @@ import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.StructLayout; import java.lang.foreign.SymbolLookup; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; @@ -46,6 +50,20 @@ static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fd } } + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("Kernel32"), LIBRARY_ARENA) .or(SymbolLookup.loaderLookup()) .or(Linker.nativeLinker().defaultLookup()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java index f5552ce1..6c991619 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java @@ -5,9 +5,13 @@ import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.StructLayout; import java.lang.foreign.SymbolLookup; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; @@ -46,6 +50,20 @@ static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fd } } + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() .or(Linker.nativeLinker().defaultLookup()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java index ba427c31..e141b311 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java @@ -5,9 +5,13 @@ import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.StructLayout; import java.lang.foreign.SymbolLookup; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; @@ -46,6 +50,20 @@ static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fd } } + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("Ole32"), LIBRARY_ARENA) .or(SymbolLookup.loaderLookup()) .or(Linker.nativeLinker().defaultLookup()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java index 8f1c7ae8..c8e234c6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java @@ -5,9 +5,13 @@ import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.StructLayout; import java.lang.foreign.SymbolLookup; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; @@ -46,6 +50,20 @@ static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fd } } + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("SetupAPI"), LIBRARY_ARENA) .or(SymbolLookup.loaderLookup()) .or(Linker.nativeLinker().defaultLookup()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java index 871db75b..7d36eaf8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java @@ -5,9 +5,13 @@ import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.StructLayout; import java.lang.foreign.SymbolLookup; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; @@ -46,6 +50,20 @@ static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fd } } + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() .or(Linker.nativeLinker().defaultLookup()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java index ddc3f3be..844ea50a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java @@ -39,7 +39,7 @@ public class _USB_DESCRIPTOR_REQUEST { } private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - USBIoctl.C_LONG.withByteAlignment(1).withName("ConnectionIndex"), + USBIoctl.align(USBIoctl.C_LONG, 1).withName("ConnectionIndex"), _USB_DESCRIPTOR_REQUEST.SetupPacket.layout().withName("SetupPacket"), MemoryLayout.sequenceLayout(0, USBIoctl.C_CHAR).withName("Data") ).withName("_USB_DESCRIPTOR_REQUEST"); @@ -115,9 +115,9 @@ public static class SetupPacket { private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( USBIoctl.C_CHAR.withName("bmRequest"), USBIoctl.C_CHAR.withName("bRequest"), - USBIoctl.C_SHORT.withByteAlignment(1).withName("wValue"), - USBIoctl.C_SHORT.withByteAlignment(1).withName("wIndex"), - USBIoctl.C_SHORT.withByteAlignment(1).withName("wLength") + USBIoctl.align(USBIoctl.C_SHORT, 1).withName("wValue"), + USBIoctl.align(USBIoctl.C_SHORT, 1).withName("wIndex"), + USBIoctl.align(USBIoctl.C_SHORT, 1).withName("wLength") ).withName("$anon$971:5"); /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java index 0bafcbae..5fad54ec 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java @@ -42,14 +42,14 @@ public class _USB_DEVICE_DESCRIPTOR { private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( USBIoctl.C_CHAR.withName("bLength"), USBIoctl.C_CHAR.withName("bDescriptorType"), - USBIoctl.C_SHORT.withByteAlignment(1).withName("bcdUSB"), + USBIoctl.align(USBIoctl.C_SHORT, 1).withName("bcdUSB"), USBIoctl.C_CHAR.withName("bDeviceClass"), USBIoctl.C_CHAR.withName("bDeviceSubClass"), USBIoctl.C_CHAR.withName("bDeviceProtocol"), USBIoctl.C_CHAR.withName("bMaxPacketSize0"), - USBIoctl.C_SHORT.withByteAlignment(1).withName("idVendor"), - USBIoctl.C_SHORT.withByteAlignment(1).withName("idProduct"), - USBIoctl.C_SHORT.withByteAlignment(1).withName("bcdDevice"), + USBIoctl.align(USBIoctl.C_SHORT, 1).withName("idVendor"), + USBIoctl.align(USBIoctl.C_SHORT, 1).withName("idProduct"), + USBIoctl.align(USBIoctl.C_SHORT, 1).withName("bcdDevice"), USBIoctl.C_CHAR.withName("iManufacturer"), USBIoctl.C_CHAR.withName("iProduct"), USBIoctl.C_CHAR.withName("iSerialNumber"), diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_ENDPOINT_DESCRIPTOR.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_ENDPOINT_DESCRIPTOR.java index fc746185..e25b0e6e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_ENDPOINT_DESCRIPTOR.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_ENDPOINT_DESCRIPTOR.java @@ -36,7 +36,7 @@ public class _USB_ENDPOINT_DESCRIPTOR { USBIoctl.C_CHAR.withName("bDescriptorType"), USBIoctl.C_CHAR.withName("bEndpointAddress"), USBIoctl.C_CHAR.withName("bmAttributes"), - USBIoctl.C_SHORT.withByteAlignment(1).withName("wMaxPacketSize"), + USBIoctl.align(USBIoctl.C_SHORT, 1).withName("wMaxPacketSize"), USBIoctl.C_CHAR.withName("bInterval") ).withName("_USB_ENDPOINT_DESCRIPTOR"); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java index 1b98e0b1..efcbaae3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java @@ -39,14 +39,14 @@ public class _USB_NODE_CONNECTION_INFORMATION_EX { } private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - USBIoctl.C_LONG.withByteAlignment(1).withName("ConnectionIndex"), + USBIoctl.align(USBIoctl.C_LONG, 1).withName("ConnectionIndex"), _USB_DEVICE_DESCRIPTOR.layout().withName("DeviceDescriptor"), USBIoctl.C_CHAR.withName("CurrentConfigurationValue"), USBIoctl.C_CHAR.withName("Speed"), USBIoctl.C_CHAR.withName("DeviceIsHub"), - USBIoctl.C_SHORT.withByteAlignment(1).withName("DeviceAddress"), - USBIoctl.C_LONG.withByteAlignment(1).withName("NumberOfOpenPipes"), - USBIoctl.C_INT.withByteAlignment(1).withName("ConnectionStatus"), + USBIoctl.align(USBIoctl.C_SHORT, 1).withName("DeviceAddress"), + USBIoctl.align(USBIoctl.C_LONG, 1).withName("NumberOfOpenPipes"), + USBIoctl.align(USBIoctl.C_INT, 1).withName("ConnectionStatus"), MemoryLayout.sequenceLayout(0, _USB_PIPE_INFO.layout()).withName("PipeList") ).withName("_USB_NODE_CONNECTION_INFORMATION_EX"); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_PIPE_INFO.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_PIPE_INFO.java index f529c8b7..0ea41864 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_PIPE_INFO.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_PIPE_INFO.java @@ -28,7 +28,7 @@ public class _USB_PIPE_INFO { private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( _USB_ENDPOINT_DESCRIPTOR.layout().withName("EndpointDescriptor"), - USBIoctl.C_LONG.withByteAlignment(1).withName("ScheduleOffset") + USBIoctl.align(USBIoctl.C_LONG, 1).withName("ScheduleOffset") ).withName("_USB_PIPE_INFO"); /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java index f91ff851..63b935db 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java @@ -5,9 +5,13 @@ import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.StructLayout; import java.lang.foreign.SymbolLookup; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; @@ -46,6 +50,20 @@ static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fd } } + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("User32"), LIBRARY_ARENA) .or(SymbolLookup.loaderLookup()) .or(Linker.nativeLinker().defaultLookup()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java index 8385a77b..8d1beb4b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java @@ -5,9 +5,13 @@ import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.StructLayout; import java.lang.foreign.SymbolLookup; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; @@ -46,6 +50,20 @@ static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fd } } + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("Winusb"), LIBRARY_ARENA) .or(SymbolLookup.loaderLookup()) .or(Linker.nativeLinker().defaultLookup()); From 319a83a21e98257f306835bf1943f75c1b531d04 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 20 Feb 2024 20:53:10 +0100 Subject: [PATCH 330/433] macOS: upgrade ot JDK 22 --- java-does-usb/jextract/macos/gen_macos.sh | 15 +- .../usb/macos/CoreFoundationHelper.java | 4 +- .../net/codecrete/usb/macos/IoKitHelper.java | 2 +- .../net/codecrete/usb/macos/IoKitUsb.java | 55 +- .../codecrete/usb/macos/MacosAsyncTask.java | 6 +- .../codecrete/usb/macos/MacosUsbDevice.java | 22 +- .../usb/macos/MacosUsbDeviceRegistry.java | 6 +- .../usb/macos/gen/corefoundation/CFRange.java | 172 +- .../macos/gen/corefoundation/CFUUIDBytes.java | 844 ++- .../gen/corefoundation/CoreFoundation.java | 708 +- .../gen/corefoundation/RuntimeHelper.java | 240 - .../macos/gen/corefoundation/constants$0.java | 38 - .../macos/gen/corefoundation/constants$1.java | 46 - .../macos/gen/corefoundation/constants$2.java | 39 - .../macos/gen/corefoundation/constants$3.java | 51 - .../macos/gen/corefoundation/constants$4.java | 19 - .../macos/gen/corefoundation/constants$5.java | 19 - .../macos/gen/corefoundation/constants$6.java | 68 - .../usb/macos/gen/iokit/CFUUIDBytes.java | 813 +++ .../macos/gen/iokit/IOCFPlugInInterface.java | 22 +- .../gen/iokit/IOCFPlugInInterfaceStruct.java | 925 ++- .../codecrete/usb/macos/gen/iokit/IOKit.java | 653 +- ...rviceAddMatchingNotification$callback.java | 64 + .../usb/macos/gen/iokit/IOUSBDevRequest.java | 415 +- .../gen/iokit/IOUSBDeviceInterface187.java | 51 +- .../macos/gen/iokit/IOUSBDeviceStruct187.java | 4796 +++++++++---- .../gen/iokit/IOUSBFindInterfaceRequest.java | 268 +- .../gen/iokit/IOUSBInterfaceInterface190.java | 62 +- .../gen/iokit/IOUSBInterfaceStruct190.java | 6333 ++++++++++++----- .../usb/macos/gen/iokit/RuntimeHelper.java | 240 - .../usb/macos/gen/iokit/constants$0.java | 33 - .../usb/macos/gen/iokit/constants$1.java | 27 - .../usb/macos/gen/iokit/constants$10.java | 20 - .../usb/macos/gen/iokit/constants$11.java | 20 - .../usb/macos/gen/iokit/constants$12.java | 20 - .../usb/macos/gen/iokit/constants$13.java | 30 - .../usb/macos/gen/iokit/constants$14.java | 33 - .../usb/macos/gen/iokit/constants$15.java | 22 - .../usb/macos/gen/iokit/constants$16.java | 30 - .../usb/macos/gen/iokit/constants$17.java | 20 - .../usb/macos/gen/iokit/constants$18.java | 20 - .../usb/macos/gen/iokit/constants$19.java | 26 - .../usb/macos/gen/iokit/constants$2.java | 30 - .../usb/macos/gen/iokit/constants$20.java | 73 - .../usb/macos/gen/iokit/constants$21.java | 20 - .../usb/macos/gen/iokit/constants$22.java | 20 - .../usb/macos/gen/iokit/constants$23.java | 20 - .../usb/macos/gen/iokit/constants$24.java | 20 - .../usb/macos/gen/iokit/constants$25.java | 20 - .../usb/macos/gen/iokit/constants$26.java | 20 - .../usb/macos/gen/iokit/constants$27.java | 20 - .../usb/macos/gen/iokit/constants$28.java | 30 - .../usb/macos/gen/iokit/constants$29.java | 36 - .../usb/macos/gen/iokit/constants$3.java | 45 - .../usb/macos/gen/iokit/constants$30.java | 20 - .../usb/macos/gen/iokit/constants$31.java | 31 - .../usb/macos/gen/iokit/constants$32.java | 38 - .../usb/macos/gen/iokit/constants$33.java | 36 - .../usb/macos/gen/iokit/constants$34.java | 22 - .../usb/macos/gen/iokit/constants$35.java | 33 - .../usb/macos/gen/iokit/constants$36.java | 42 - .../usb/macos/gen/iokit/constants$37.java | 22 - .../usb/macos/gen/iokit/constants$38.java | 30 - .../usb/macos/gen/iokit/constants$39.java | 34 - .../usb/macos/gen/iokit/constants$4.java | 79 - .../usb/macos/gen/iokit/constants$40.java | 36 - .../usb/macos/gen/iokit/constants$41.java | 20 - .../usb/macos/gen/iokit/constants$42.java | 34 - .../usb/macos/gen/iokit/constants$43.java | 34 - .../usb/macos/gen/iokit/constants$44.java | 15 - .../usb/macos/gen/iokit/constants$5.java | 49 - .../usb/macos/gen/iokit/constants$6.java | 28 - .../usb/macos/gen/iokit/constants$7.java | 24 - .../usb/macos/gen/iokit/constants$8.java | 20 - .../usb/macos/gen/iokit/constants$9.java | 20 - .../usb/macos/gen/mach/RuntimeHelper.java | 239 - .../usb/macos/gen/mach/constants$0.java | 22 - .../codecrete/usb/macos/gen/mach/mach.java | 130 +- 78 files changed, 11778 insertions(+), 6931 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$3.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$4.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$5.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$6.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/CFUUIDBytes.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOServiceAddMatchingNotification$callback.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$1.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$10.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$11.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$12.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$13.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$14.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$15.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$16.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$17.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$18.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$19.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$2.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$20.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$21.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$22.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$23.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$24.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$25.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$26.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$27.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$28.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$29.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$3.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$30.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$31.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$32.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$33.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$34.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$35.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$36.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$37.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$38.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$39.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$4.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$40.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$41.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$42.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$43.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$44.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$5.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$6.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$7.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$8.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$9.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index c74b5864..a8eb2ac1 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -5,13 +5,13 @@ JEXTRACT=../../../../jextract/build/jextract/bin/jextract SDK_DIR=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk # CoreFoundation -$JEXTRACT --source --output ../../src/main/java \ +$JEXTRACT --output ../../src/main/java \ -I $SDK_DIR/usr/include \ -lCoreFoundation.framework \ --header-class-name CoreFoundation \ --target-package net.codecrete.usb.macos.gen.corefoundation \ - --include-typedef CFRange \ - --include-typedef CFUUIDBytes \ + --include-struct CFRange \ + --include-struct CFUUIDBytes \ --include-function CFUUIDCreateFromUUIDBytes \ --include-function CFRelease \ --include-function CFStringGetLength \ @@ -30,7 +30,7 @@ $JEXTRACT --source --output ../../src/main/java \ cf_helper.h # IOKit -$JEXTRACT --source --output ../../src/main/java \ +$JEXTRACT --output ../../src/main/java \ -I $SDK_DIR/usr/include \ -lIOKit.framework \ --header-class-name IOKit \ @@ -55,8 +55,8 @@ $JEXTRACT --source --output ../../src/main/java \ --include-struct IOUSBDeviceStruct187 \ --include-typedef IOUSBDeviceInterface187 \ --include-constant kIOUSBFindInterfaceDontCare \ - --include-typedef IOUSBFindInterfaceRequest \ - --include-typedef IOUSBDevRequest \ + --include-struct IOUSBFindInterfaceRequest \ + --include-struct IOUSBDevRequest \ --include-struct IOUSBInterfaceStruct190 \ --include-typedef IOUSBInterfaceInterface190 \ --include-constant kIOUSBTransactionTimeout \ @@ -64,10 +64,11 @@ $JEXTRACT --source --output ../../src/main/java \ --include-constant kIOUSBPipeStalled \ --include-constant kUSBReEnumerateCaptureDeviceMask \ --include-constant kUSBReEnumerateReleaseDeviceMask \ + --include-struct CFUUIDBytes \ iokit_helper.h # mach.h -$JEXTRACT --source --output ../../src/main/java \ +$JEXTRACT --output ../../src/main/java \ -I $SDK_DIR/usr/include \ --header-class-name mach \ --target-package net.codecrete.usb.macos.gen.mach \ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java index 1f31e70b..206d7a63 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/CoreFoundationHelper.java @@ -37,8 +37,8 @@ static String stringFromCFStringRef(MemorySegment string, Arena arena) { var strLen = CoreFoundation.CFStringGetLength(string); var buffer = arena.allocate(JAVA_CHAR, strLen); var range = CFRange.allocate(arena); - CFRange.location$set(range, 0); - CFRange.length$set(range, strLen); + CFRange.location(range, 0); + CFRange.length(range, strLen); CoreFoundation.CFStringGetCharacters(string, range, buffer); return new String(buffer.toArray(JAVA_CHAR)); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java index 6fd60f63..08d35279 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitHelper.java @@ -93,7 +93,7 @@ private IoKitHelper() { * @return vtable */ static MemorySegment getVtable(MemorySegment self) { - return (MemorySegment) vtable$VH.get(self); + return (MemorySegment) vtable$VH.get(self, 0); } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUsb.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUsb.java index 6dd1e764..f15fa5b5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUsb.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUsb.java @@ -10,7 +10,6 @@ import net.codecrete.usb.macos.gen.iokit.IOUSBDeviceStruct187; import net.codecrete.usb.macos.gen.iokit.IOUSBInterfaceStruct190; -import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import static net.codecrete.usb.macos.IoKitHelper.getVtable; @@ -26,92 +25,92 @@ private IoKitUsb() { // HRESULT (STDMETHODCALLTYPE *QueryInterface)(void *thisPointer, REFIID iid, LPVOID *ppv) static int QueryInterface(MemorySegment self, MemorySegment iid, MemorySegment ppv) { - return IOUSBDeviceStruct187.QueryInterface(getVtable(self), Arena.global()).apply(self, iid, ppv); + return IOUSBDeviceStruct187.QueryInterface.invoke(IOUSBDeviceStruct187.QueryInterface(getVtable(self)), self, iid, ppv); } // ULONG (STDMETHODCALLTYPE *AddRef)(void *thisPointer) static int AddRef(MemorySegment self) { - return IOUSBDeviceStruct187.AddRef(getVtable(self), Arena.global()).apply(self); + return IOUSBDeviceStruct187.AddRef.invoke(IOUSBDeviceStruct187.AddRef(getVtable(self)), self); } // ULONG (STDMETHODCALLTYPE *Release)(void *thisPointer) static int Release(MemorySegment self) { - return IOUSBDeviceStruct187.Release(getVtable(self), Arena.global()).apply(self); + return IOUSBDeviceStruct187.Release.invoke(IOUSBDeviceStruct187.Release(getVtable(self)), self); } // IOReturn (* CreateDeviceAsyncEventSource)(void* self, CFRunLoopSourceRef* source) static int CreateDeviceAsyncEventSource(MemorySegment self, MemorySegment source) { - return IOUSBDeviceStruct187.CreateDeviceAsyncEventSource(getVtable(self), Arena.global()).apply(self, + return IOUSBDeviceStruct187.CreateDeviceAsyncEventSource.invoke(IOUSBDeviceStruct187.CreateDeviceAsyncEventSource(getVtable(self)), self, source); } // CFRunLoopSourceRef (* GetDeviceAsyncEventSource)(void* self) static MemorySegment GetDeviceAsyncEventSource(MemorySegment self) { - return IOUSBDeviceStruct187.GetDeviceAsyncEventSource(getVtable(self), Arena.global()).apply(self); + return IOUSBDeviceStruct187.GetDeviceAsyncEventSource.invoke(IOUSBDeviceStruct187.GetDeviceAsyncEventSource(getVtable(self)), self); } // IOReturn (*USBDeviceOpenSeize)(void *self) static int USBDeviceOpenSeize(MemorySegment self) { - return IOUSBDeviceStruct187.USBDeviceOpenSeize(getVtable(self), Arena.global()).apply(self); + return IOUSBDeviceStruct187.USBDeviceOpenSeize.invoke(IOUSBDeviceStruct187.USBDeviceOpenSeize(getVtable(self)), self); } // IOReturn (*USBDeviceClose)(void *self) static int USBDeviceClose(MemorySegment self) { - return IOUSBDeviceStruct187.USBDeviceClose(getVtable(self), Arena.global()).apply(self); + return IOUSBDeviceStruct187.USBDeviceClose.invoke(IOUSBDeviceStruct187.USBDeviceClose(getVtable(self)), self); } // IOReturn (* USBDeviceReEnumerate)(void* self, UInt32 options) static int USBDeviceReEnumerate(MemorySegment self, int options) { - return IOUSBDeviceStruct187.USBDeviceReEnumerate(getVtable(self), Arena.global()).apply(self, options); + return IOUSBDeviceStruct187.USBDeviceReEnumerate.invoke(IOUSBDeviceStruct187.USBDeviceReEnumerate(getVtable(self)), self, options); } // IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc) static int GetConfigurationDescriptorPtr(MemorySegment self, byte configIndex, MemorySegment descHolder) { - return IOUSBDeviceStruct187.GetConfigurationDescriptorPtr(getVtable(self), Arena.global()).apply(self, + return IOUSBDeviceStruct187.GetConfigurationDescriptorPtr.invoke(IOUSBDeviceStruct187.GetConfigurationDescriptorPtr(getVtable(self)), self, configIndex, descHolder); } // IOReturn (*SetConfiguration)(void *self, UInt8 configNum) static int SetConfiguration(MemorySegment self, byte configValue) { - return IOUSBDeviceStruct187.SetConfiguration(getVtable(self), Arena.global()).apply(self, configValue); + return IOUSBDeviceStruct187.SetConfiguration.invoke(IOUSBDeviceStruct187.SetConfiguration(getVtable(self)), self, configValue); } // IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter) static int CreateInterfaceIterator(MemorySegment self, MemorySegment req, MemorySegment iter) { - return IOUSBDeviceStruct187.CreateInterfaceIterator(getVtable(self), Arena.global()).apply(self, req, iter); + return IOUSBDeviceStruct187.CreateInterfaceIterator.invoke(IOUSBDeviceStruct187.CreateInterfaceIterator(getVtable(self)), self, req, iter); } // IOReturn (* DeviceRequest)(void* self, IOUSBDevRequest* req) static int DeviceRequest(MemorySegment self, MemorySegment deviceRequest) { - return IOUSBDeviceStruct187.DeviceRequest(getVtable(self), Arena.global()).apply(self, deviceRequest); + return IOUSBDeviceStruct187.DeviceRequest.invoke(IOUSBDeviceStruct187.DeviceRequest(getVtable(self)), self, deviceRequest); } // IOReturn (* DeviceRequestAsync)(void* self, IOUSBDevRequest* req, IOAsyncCallback1 callback, void* refCon) static int DeviceRequestAsync(MemorySegment self, MemorySegment deviceRequest, MemorySegment callback, MemorySegment refCon) { - return IOUSBDeviceStruct187.DeviceRequestAsync(getVtable(self), Arena.global()).apply(self, deviceRequest, + return IOUSBDeviceStruct187.DeviceRequestAsync.invoke(IOUSBDeviceStruct187.DeviceRequestAsync(getVtable(self)), self, deviceRequest, callback, refCon); } // IOReturn (*USBInterfaceOpen)(void *self) static int USBInterfaceOpen(MemorySegment self) { - return IOUSBInterfaceStruct190.USBInterfaceOpen(getVtable(self), Arena.global()).apply(self); + return IOUSBInterfaceStruct190.USBInterfaceOpen.invoke(IOUSBInterfaceStruct190.USBInterfaceOpen(getVtable(self)), self); } // IOReturn (*USBInterfaceClose)(void *self) static int USBInterfaceClose(MemorySegment self) { - return IOUSBInterfaceStruct190.USBInterfaceClose(getVtable(self), Arena.global()).apply(self); + return IOUSBInterfaceStruct190.USBInterfaceClose.invoke(IOUSBInterfaceStruct190.USBInterfaceClose(getVtable(self)), self); } // IOReturn (*GetInterfaceNumber)(void *self, UInt8 *intfNumber) static int GetInterfaceNumber(MemorySegment self, MemorySegment intfNumberHolder) { - return IOUSBInterfaceStruct190.GetInterfaceNumber(getVtable(self), Arena.global()).apply(self, + return IOUSBInterfaceStruct190.GetInterfaceNumber.invoke(IOUSBInterfaceStruct190.GetInterfaceNumber(getVtable(self)), self, intfNumberHolder); } // IOReturn (*GetNumEndpoints)(void *self, UInt8 *intfNumEndpoints) static int GetNumEndpoints(MemorySegment self, MemorySegment intfNumEndpointsHolder) { - return IOUSBInterfaceStruct190.GetNumEndpoints(getVtable(self), Arena.global()).apply(self, + return IOUSBInterfaceStruct190.GetNumEndpoints.invoke(IOUSBInterfaceStruct190.GetNumEndpoints(getVtable(self)), self, intfNumEndpointsHolder); } @@ -120,7 +119,7 @@ static int GetNumEndpoints(MemorySegment self, MemorySegment intfNumEndpointsHol static int GetPipeProperties(MemorySegment self, byte pipeRef, MemorySegment directionHolder, MemorySegment numberHolder, MemorySegment transferTypeHolder, MemorySegment maxPacketSizeHolder, MemorySegment intervalHolder) { - return IOUSBInterfaceStruct190.GetPipeProperties(getVtable(self), Arena.global()).apply(self, pipeRef, + return IOUSBInterfaceStruct190.GetPipeProperties.invoke(IOUSBInterfaceStruct190.GetPipeProperties(getVtable(self)), self, pipeRef, directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); } @@ -128,7 +127,7 @@ static int GetPipeProperties(MemorySegment self, byte pipeRef, MemorySegment dir // *refcon) static int ReadPipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceStruct190.ReadPipeAsync(getVtable(self), Arena.global()).apply(self, pipeRef, buf, + return IOUSBInterfaceStruct190.ReadPipeAsync.invoke(IOUSBInterfaceStruct190.ReadPipeAsync(getVtable(self)), self, pipeRef, buf, size, callback, refcon); } @@ -137,7 +136,7 @@ static int ReadPipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, in static int ReadPipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, int noDataTimeout, int completionTimeout, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceStruct190.ReadPipeAsyncTO(getVtable(self), Arena.global()).apply(self, pipeRef, buf, + return IOUSBInterfaceStruct190.ReadPipeAsyncTO.invoke(IOUSBInterfaceStruct190.ReadPipeAsyncTO(getVtable(self)), self, pipeRef, buf, size, noDataTimeout, completionTimeout, callback, refcon); } @@ -145,7 +144,7 @@ static int ReadPipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, // void *refcon) static int WritePipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceStruct190.WritePipeAsync(getVtable(self), Arena.global()).apply(self, pipeRef, buf, + return IOUSBInterfaceStruct190.WritePipeAsync.invoke(IOUSBInterfaceStruct190.WritePipeAsync(getVtable(self)), self, pipeRef, buf, size, callback, refcon); } @@ -154,34 +153,34 @@ static int WritePipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, i static int WritePipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, int noDataTimeout, int completionTimeout, MemorySegment callback, MemorySegment refcon) { - return IOUSBInterfaceStruct190.WritePipeAsyncTO(getVtable(self), Arena.global()).apply(self, pipeRef, buf, + return IOUSBInterfaceStruct190.WritePipeAsyncTO.invoke(IOUSBInterfaceStruct190.WritePipeAsyncTO(getVtable(self)), self, pipeRef, buf, size, noDataTimeout, completionTimeout, callback, refcon); } // IOReturn (* AbortPipe)(void* self, UInt8 pipeRef) static int AbortPipe(MemorySegment self, byte pipeRef) { - return IOUSBInterfaceStruct190.AbortPipe(getVtable(self), Arena.global()).apply(self, pipeRef); + return IOUSBInterfaceStruct190.AbortPipe.invoke(IOUSBInterfaceStruct190.AbortPipe(getVtable(self)), self, pipeRef); } // IOReturn (*SetAlternateInterface)(void *self, UInt8 alternateSetting) static int SetAlternateInterface(MemorySegment self, byte alternateSetting) { - return IOUSBInterfaceStruct190.SetAlternateInterface(getVtable(self), Arena.global()).apply(self, + return IOUSBInterfaceStruct190.SetAlternateInterface.invoke(IOUSBInterfaceStruct190.SetAlternateInterface(getVtable(self)), self, alternateSetting); } // IOReturn (* ClearPipeStallBothEnds)(void* self, UInt8 pipeRef) static int ClearPipeStallBothEnds(MemorySegment self, byte pipeRef) { - return IOUSBInterfaceStruct190.ClearPipeStallBothEnds(getVtable(self), Arena.global()).apply(self, pipeRef); + return IOUSBInterfaceStruct190.ClearPipeStallBothEnds.invoke(IOUSBInterfaceStruct190.ClearPipeStallBothEnds(getVtable(self)), self, pipeRef); } // CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void* self) static MemorySegment GetInterfaceAsyncEventSource(MemorySegment self) { - return IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource(getVtable(self), Arena.global()).apply(self); + return IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource.invoke(IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource(getVtable(self)), self); } // IOReturn (*CreateInterfaceAsyncEventSource)(void *self, CFRunLoopSourceRef *source) static int CreateInterfaceAsyncEventSource(MemorySegment self, MemorySegment source) { - return IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource(getVtable(self), Arena.global()).apply(self + return IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource.invoke(IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource(getVtable(self)), self , source); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java index c9992de0..ae03582c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java @@ -78,7 +78,7 @@ void addEventSource(MemorySegment source) { } } - CoreFoundation.CFRunLoopAddSource(asyncIoRunLoop, source, IOKit.kCFRunLoopDefaultMode$get()); + CoreFoundation.CFRunLoopAddSource(asyncIoRunLoop, source, IOKit.kCFRunLoopDefaultMode()); } finally { asyncIoLock.unlock(); @@ -96,7 +96,7 @@ private void waitForRunLoopReady() { * @param source event source */ void removeEventSource(MemorySegment source) { - CoreFoundation.CFRunLoopRemoveSource(asyncIoRunLoop, source, IOKit.kCFRunLoopDefaultMode$get()); + CoreFoundation.CFRunLoopRemoveSource(asyncIoRunLoop, source, IOKit.kCFRunLoopDefaultMode()); } /** @@ -137,7 +137,7 @@ private void asyncIOCompletionTask(MemorySegment firstSource) { try { asyncIoLock.lock(); asyncIoRunLoop = CoreFoundation.CFRunLoopGetCurrent(); - CoreFoundation.CFRunLoopAddSource(asyncIoRunLoop, firstSource, IOKit.kCFRunLoopDefaultMode$get()); + CoreFoundation.CFRunLoopAddSource(asyncIoRunLoop, firstSource, IOKit.kCFRunLoopDefaultMode()); state = TaskState.RUNNING; asyncIoReady.signalAll(); } finally { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java index d935b68a..b6a16e04 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java @@ -183,7 +183,7 @@ private void loadDescription(MemorySegment device) { if (ret != 0) throwException(ret, "querying device descriptor failed"); - var len = IOUSBDevRequest.wLenDone$get(deviceRequest); + var len = IOUSBDevRequest.wLenDone(deviceRequest); rawDeviceDescriptor = data.asSlice(0, len).toArray(JAVA_BYTE); configurationValue = 0; @@ -208,10 +208,10 @@ private InterfaceInfo findInterfaceInfo(int interfaceNumber) { try (var arena = Arena.ofConfined(); var outerCleanup = new ScopeCleanup()) { var request = IOUSBFindInterfaceRequest.allocate(arena); - IOUSBFindInterfaceRequest.bInterfaceClass$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); - IOUSBFindInterfaceRequest.bInterfaceSubClass$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); - IOUSBFindInterfaceRequest.bInterfaceProtocol$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); - IOUSBFindInterfaceRequest.bAlternateSetting$set(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); + IOUSBFindInterfaceRequest.bInterfaceClass(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); + IOUSBFindInterfaceRequest.bInterfaceSubClass(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); + IOUSBFindInterfaceRequest.bInterfaceProtocol(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); + IOUSBFindInterfaceRequest.bAlternateSetting(request, (short) IOKit.kIOUSBFindInterfaceDontCare()); var iterHolder = arena.allocate(JAVA_INT); var ret = IoKitUsb.CreateInterfaceIterator(device, request, iterHolder); @@ -389,12 +389,12 @@ private static MemorySegment createDeviceRequest(Arena arena, UsbDirection direc var deviceRequest = IOUSBDevRequest.allocate(arena); var bmRequestType = (direction == UsbDirection.IN ? 0x80 : 0x00) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal(); - IOUSBDevRequest.bmRequestType$set(deviceRequest, (byte) bmRequestType); - IOUSBDevRequest.bRequest$set(deviceRequest, (byte) setup.request()); - IOUSBDevRequest.wValue$set(deviceRequest, (short) setup.value()); - IOUSBDevRequest.wIndex$set(deviceRequest, (short) setup.index()); - IOUSBDevRequest.wLength$set(deviceRequest, (short) data.byteSize()); - IOUSBDevRequest.pData$set(deviceRequest, data); + IOUSBDevRequest.bmRequestType(deviceRequest, (byte) bmRequestType); + IOUSBDevRequest.bRequest(deviceRequest, (byte) setup.request()); + IOUSBDevRequest.wValue(deviceRequest, (short) setup.value()); + IOUSBDevRequest.wIndex(deviceRequest, (short) setup.index()); + IOUSBDevRequest.wLength(deviceRequest, (short) data.byteSize()); + IOUSBDevRequest.pData(deviceRequest, data); return deviceRequest; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java index 4dd8fc2f..36a9c5f5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java @@ -80,10 +80,10 @@ protected void monitorDevices() { try { // setup run loop, run loop source and notification port - var notifyPort = IOKit.IONotificationPortCreate(IOKit.kIOMasterPortDefault$get()); + var notifyPort = IOKit.IONotificationPortCreate(IOKit.kIOMasterPortDefault()); var runLoopSource = IOKit.IONotificationPortGetRunLoopSource(notifyPort); var runLoop = CoreFoundation.CFRunLoopGetCurrent(); - CoreFoundation.CFRunLoopAddSource(runLoop, runLoopSource, IOKit.kCFRunLoopDefaultMode$get()); + CoreFoundation.CFRunLoopAddSource(runLoop, runLoopSource, IOKit.kCFRunLoopDefaultMode()); // setup notification for connected devices var onDeviceConnectedMH = MethodHandles.lookup().findVirtual(MacosUsbDeviceRegistry.class, @@ -267,7 +267,7 @@ private void onDevicesConnected(MemorySegment ignoredRefCon, int iterator) { private void onDevicesDisconnected(MemorySegment ignoredRefCon, int iterator) { // process device iterator for disconnected devices - iterateDevices(iterator, (entryId, service, deviceIntf) -> { + iterateDevices(iterator, (entryId, _, _) -> { var device = findDevice(entryId); if (device == null) return; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java index f0f8887b..2f831a30 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java @@ -2,84 +2,168 @@ package net.codecrete.usb.macos.gen.corefoundation; -import java.lang.foreign.Arena; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.lang.foreign.*; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfLong; + /** - * {@snippet : + * {@snippet lang=c : * struct { * CFIndex location; * CFIndex length; - * }; + * } * } */ public class CFRange { - public static MemoryLayout $LAYOUT() { - return constants$0.const$0; + CFRange() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + CoreFoundation.C_LONG.withName("location"), + CoreFoundation.C_LONG.withName("length") + ).withName("CFRange"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfLong location$LAYOUT = (OfLong)$LAYOUT.select(groupElement("location")); + + /** + * Layout for field: + * {@snippet lang=c : + * CFIndex location + * } + */ + public static final OfLong location$layout() { + return location$LAYOUT; } - public static VarHandle location$VH() { - return constants$0.const$1; + + private static final long location$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * CFIndex location + * } + */ + public static final long location$offset() { + return location$OFFSET; } + /** * Getter for field: - * {@snippet : - * CFIndex location; + * {@snippet lang=c : + * CFIndex location * } */ - public static long location$get(MemorySegment seg) { - return (long)constants$0.const$1.get(seg); + public static long location(MemorySegment struct) { + return struct.get(location$LAYOUT, location$OFFSET); } + /** * Setter for field: - * {@snippet : - * CFIndex location; + * {@snippet lang=c : + * CFIndex location * } */ - public static void location$set(MemorySegment seg, long x) { - constants$0.const$1.set(seg, x); + public static void location(MemorySegment struct, long fieldValue) { + struct.set(location$LAYOUT, location$OFFSET, fieldValue); } - public static long location$get(MemorySegment seg, long index) { - return (long)constants$0.const$1.get(seg.asSlice(index*sizeof())); - } - public static void location$set(MemorySegment seg, long index, long x) { - constants$0.const$1.set(seg.asSlice(index*sizeof()), x); + + private static final OfLong length$LAYOUT = (OfLong)$LAYOUT.select(groupElement("length")); + + /** + * Layout for field: + * {@snippet lang=c : + * CFIndex length + * } + */ + public static final OfLong length$layout() { + return length$LAYOUT; } - public static VarHandle length$VH() { - return constants$0.const$2; + + private static final long length$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * CFIndex length + * } + */ + public static final long length$offset() { + return length$OFFSET; } + /** * Getter for field: - * {@snippet : - * CFIndex length; + * {@snippet lang=c : + * CFIndex length * } */ - public static long length$get(MemorySegment seg) { - return (long)constants$0.const$2.get(seg); + public static long length(MemorySegment struct) { + return struct.get(length$LAYOUT, length$OFFSET); } + /** * Setter for field: - * {@snippet : - * CFIndex length; + * {@snippet lang=c : + * CFIndex length * } */ - public static void length$set(MemorySegment seg, long x) { - constants$0.const$2.set(seg, x); + public static void length(MemorySegment struct, long fieldValue) { + struct.set(length$LAYOUT, length$OFFSET, fieldValue); } - public static long length$get(MemorySegment seg, long index) { - return (long)constants$0.const$2.get(seg.asSlice(index*sizeof())); + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); } - public static void length$set(MemorySegment seg, long index, long x) { - constants$0.const$2.set(seg.asSlice(index*sizeof()), x); + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } -} + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java index 26940ac9..aa02fd47 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java @@ -2,13 +2,14 @@ package net.codecrete.usb.macos.gen.corefoundation; -import java.lang.foreign.Arena; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.lang.foreign.*; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfByte; + /** - * {@snippet : + * {@snippet lang=c : * struct { * UInt8 byte0; * UInt8 byte1; @@ -26,452 +27,787 @@ * UInt8 byte13; * UInt8 byte14; * UInt8 byte15; - * }; + * } * } */ public class CFUUIDBytes { - public static MemoryLayout $LAYOUT() { - return constants$3.const$3; + CFUUIDBytes() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + CoreFoundation.C_CHAR.withName("byte0"), + CoreFoundation.C_CHAR.withName("byte1"), + CoreFoundation.C_CHAR.withName("byte2"), + CoreFoundation.C_CHAR.withName("byte3"), + CoreFoundation.C_CHAR.withName("byte4"), + CoreFoundation.C_CHAR.withName("byte5"), + CoreFoundation.C_CHAR.withName("byte6"), + CoreFoundation.C_CHAR.withName("byte7"), + CoreFoundation.C_CHAR.withName("byte8"), + CoreFoundation.C_CHAR.withName("byte9"), + CoreFoundation.C_CHAR.withName("byte10"), + CoreFoundation.C_CHAR.withName("byte11"), + CoreFoundation.C_CHAR.withName("byte12"), + CoreFoundation.C_CHAR.withName("byte13"), + CoreFoundation.C_CHAR.withName("byte14"), + CoreFoundation.C_CHAR.withName("byte15") + ).withName("CFUUIDBytes"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } - public static VarHandle byte0$VH() { - return constants$3.const$4; + + private static final OfByte byte0$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte0")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte0 + * } + */ + public static final OfByte byte0$layout() { + return byte0$LAYOUT; + } + + private static final long byte0$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte0 + * } + */ + public static final long byte0$offset() { + return byte0$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 byte0; + * {@snippet lang=c : + * UInt8 byte0 * } */ - public static byte byte0$get(MemorySegment seg) { - return (byte)constants$3.const$4.get(seg); + public static byte byte0(MemorySegment struct) { + return struct.get(byte0$LAYOUT, byte0$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 byte0; + * {@snippet lang=c : + * UInt8 byte0 * } */ - public static void byte0$set(MemorySegment seg, byte x) { - constants$3.const$4.set(seg, x); + public static void byte0(MemorySegment struct, byte fieldValue) { + struct.set(byte0$LAYOUT, byte0$OFFSET, fieldValue); } - public static byte byte0$get(MemorySegment seg, long index) { - return (byte)constants$3.const$4.get(seg.asSlice(index*sizeof())); - } - public static void byte0$set(MemorySegment seg, long index, byte x) { - constants$3.const$4.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte byte1$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte1")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte1 + * } + */ + public static final OfByte byte1$layout() { + return byte1$LAYOUT; } - public static VarHandle byte1$VH() { - return constants$3.const$5; + + private static final long byte1$OFFSET = 1; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte1 + * } + */ + public static final long byte1$offset() { + return byte1$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 byte1; + * {@snippet lang=c : + * UInt8 byte1 * } */ - public static byte byte1$get(MemorySegment seg) { - return (byte)constants$3.const$5.get(seg); + public static byte byte1(MemorySegment struct) { + return struct.get(byte1$LAYOUT, byte1$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 byte1; + * {@snippet lang=c : + * UInt8 byte1 * } */ - public static void byte1$set(MemorySegment seg, byte x) { - constants$3.const$5.set(seg, x); + public static void byte1(MemorySegment struct, byte fieldValue) { + struct.set(byte1$LAYOUT, byte1$OFFSET, fieldValue); } - public static byte byte1$get(MemorySegment seg, long index) { - return (byte)constants$3.const$5.get(seg.asSlice(index*sizeof())); - } - public static void byte1$set(MemorySegment seg, long index, byte x) { - constants$3.const$5.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte byte2$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte2")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte2 + * } + */ + public static final OfByte byte2$layout() { + return byte2$LAYOUT; } - public static VarHandle byte2$VH() { - return constants$4.const$0; + + private static final long byte2$OFFSET = 2; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte2 + * } + */ + public static final long byte2$offset() { + return byte2$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 byte2; + * {@snippet lang=c : + * UInt8 byte2 * } */ - public static byte byte2$get(MemorySegment seg) { - return (byte)constants$4.const$0.get(seg); + public static byte byte2(MemorySegment struct) { + return struct.get(byte2$LAYOUT, byte2$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 byte2; + * {@snippet lang=c : + * UInt8 byte2 * } */ - public static void byte2$set(MemorySegment seg, byte x) { - constants$4.const$0.set(seg, x); + public static void byte2(MemorySegment struct, byte fieldValue) { + struct.set(byte2$LAYOUT, byte2$OFFSET, fieldValue); } - public static byte byte2$get(MemorySegment seg, long index) { - return (byte)constants$4.const$0.get(seg.asSlice(index*sizeof())); - } - public static void byte2$set(MemorySegment seg, long index, byte x) { - constants$4.const$0.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte byte3$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte3")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte3 + * } + */ + public static final OfByte byte3$layout() { + return byte3$LAYOUT; } - public static VarHandle byte3$VH() { - return constants$4.const$1; + + private static final long byte3$OFFSET = 3; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte3 + * } + */ + public static final long byte3$offset() { + return byte3$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 byte3; + * {@snippet lang=c : + * UInt8 byte3 * } */ - public static byte byte3$get(MemorySegment seg) { - return (byte)constants$4.const$1.get(seg); + public static byte byte3(MemorySegment struct) { + return struct.get(byte3$LAYOUT, byte3$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 byte3; + * {@snippet lang=c : + * UInt8 byte3 * } */ - public static void byte3$set(MemorySegment seg, byte x) { - constants$4.const$1.set(seg, x); + public static void byte3(MemorySegment struct, byte fieldValue) { + struct.set(byte3$LAYOUT, byte3$OFFSET, fieldValue); } - public static byte byte3$get(MemorySegment seg, long index) { - return (byte)constants$4.const$1.get(seg.asSlice(index*sizeof())); - } - public static void byte3$set(MemorySegment seg, long index, byte x) { - constants$4.const$1.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte byte4$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte4")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte4 + * } + */ + public static final OfByte byte4$layout() { + return byte4$LAYOUT; } - public static VarHandle byte4$VH() { - return constants$4.const$2; + + private static final long byte4$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte4 + * } + */ + public static final long byte4$offset() { + return byte4$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 byte4; + * {@snippet lang=c : + * UInt8 byte4 * } */ - public static byte byte4$get(MemorySegment seg) { - return (byte)constants$4.const$2.get(seg); + public static byte byte4(MemorySegment struct) { + return struct.get(byte4$LAYOUT, byte4$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 byte4; + * {@snippet lang=c : + * UInt8 byte4 * } */ - public static void byte4$set(MemorySegment seg, byte x) { - constants$4.const$2.set(seg, x); - } - public static byte byte4$get(MemorySegment seg, long index) { - return (byte)constants$4.const$2.get(seg.asSlice(index*sizeof())); + public static void byte4(MemorySegment struct, byte fieldValue) { + struct.set(byte4$LAYOUT, byte4$OFFSET, fieldValue); } - public static void byte4$set(MemorySegment seg, long index, byte x) { - constants$4.const$2.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte byte5$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte5")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte5 + * } + */ + public static final OfByte byte5$layout() { + return byte5$LAYOUT; } - public static VarHandle byte5$VH() { - return constants$4.const$3; + + private static final long byte5$OFFSET = 5; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte5 + * } + */ + public static final long byte5$offset() { + return byte5$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 byte5; + * {@snippet lang=c : + * UInt8 byte5 * } */ - public static byte byte5$get(MemorySegment seg) { - return (byte)constants$4.const$3.get(seg); + public static byte byte5(MemorySegment struct) { + return struct.get(byte5$LAYOUT, byte5$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 byte5; + * {@snippet lang=c : + * UInt8 byte5 * } */ - public static void byte5$set(MemorySegment seg, byte x) { - constants$4.const$3.set(seg, x); - } - public static byte byte5$get(MemorySegment seg, long index) { - return (byte)constants$4.const$3.get(seg.asSlice(index*sizeof())); + public static void byte5(MemorySegment struct, byte fieldValue) { + struct.set(byte5$LAYOUT, byte5$OFFSET, fieldValue); } - public static void byte5$set(MemorySegment seg, long index, byte x) { - constants$4.const$3.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte byte6$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte6")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte6 + * } + */ + public static final OfByte byte6$layout() { + return byte6$LAYOUT; } - public static VarHandle byte6$VH() { - return constants$4.const$4; + + private static final long byte6$OFFSET = 6; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte6 + * } + */ + public static final long byte6$offset() { + return byte6$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 byte6; + * {@snippet lang=c : + * UInt8 byte6 * } */ - public static byte byte6$get(MemorySegment seg) { - return (byte)constants$4.const$4.get(seg); + public static byte byte6(MemorySegment struct) { + return struct.get(byte6$LAYOUT, byte6$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 byte6; + * {@snippet lang=c : + * UInt8 byte6 * } */ - public static void byte6$set(MemorySegment seg, byte x) { - constants$4.const$4.set(seg, x); - } - public static byte byte6$get(MemorySegment seg, long index) { - return (byte)constants$4.const$4.get(seg.asSlice(index*sizeof())); + public static void byte6(MemorySegment struct, byte fieldValue) { + struct.set(byte6$LAYOUT, byte6$OFFSET, fieldValue); } - public static void byte6$set(MemorySegment seg, long index, byte x) { - constants$4.const$4.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte byte7$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte7")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte7 + * } + */ + public static final OfByte byte7$layout() { + return byte7$LAYOUT; } - public static VarHandle byte7$VH() { - return constants$4.const$5; + + private static final long byte7$OFFSET = 7; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte7 + * } + */ + public static final long byte7$offset() { + return byte7$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 byte7; + * {@snippet lang=c : + * UInt8 byte7 * } */ - public static byte byte7$get(MemorySegment seg) { - return (byte)constants$4.const$5.get(seg); + public static byte byte7(MemorySegment struct) { + return struct.get(byte7$LAYOUT, byte7$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 byte7; + * {@snippet lang=c : + * UInt8 byte7 * } */ - public static void byte7$set(MemorySegment seg, byte x) { - constants$4.const$5.set(seg, x); + public static void byte7(MemorySegment struct, byte fieldValue) { + struct.set(byte7$LAYOUT, byte7$OFFSET, fieldValue); } - public static byte byte7$get(MemorySegment seg, long index) { - return (byte)constants$4.const$5.get(seg.asSlice(index*sizeof())); - } - public static void byte7$set(MemorySegment seg, long index, byte x) { - constants$4.const$5.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte byte8$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte8")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte8 + * } + */ + public static final OfByte byte8$layout() { + return byte8$LAYOUT; } - public static VarHandle byte8$VH() { - return constants$5.const$0; + + private static final long byte8$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte8 + * } + */ + public static final long byte8$offset() { + return byte8$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 byte8; + * {@snippet lang=c : + * UInt8 byte8 * } */ - public static byte byte8$get(MemorySegment seg) { - return (byte)constants$5.const$0.get(seg); + public static byte byte8(MemorySegment struct) { + return struct.get(byte8$LAYOUT, byte8$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 byte8; + * {@snippet lang=c : + * UInt8 byte8 * } */ - public static void byte8$set(MemorySegment seg, byte x) { - constants$5.const$0.set(seg, x); + public static void byte8(MemorySegment struct, byte fieldValue) { + struct.set(byte8$LAYOUT, byte8$OFFSET, fieldValue); } - public static byte byte8$get(MemorySegment seg, long index) { - return (byte)constants$5.const$0.get(seg.asSlice(index*sizeof())); - } - public static void byte8$set(MemorySegment seg, long index, byte x) { - constants$5.const$0.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte byte9$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte9")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte9 + * } + */ + public static final OfByte byte9$layout() { + return byte9$LAYOUT; } - public static VarHandle byte9$VH() { - return constants$5.const$1; + + private static final long byte9$OFFSET = 9; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte9 + * } + */ + public static final long byte9$offset() { + return byte9$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 byte9; + * {@snippet lang=c : + * UInt8 byte9 * } */ - public static byte byte9$get(MemorySegment seg) { - return (byte)constants$5.const$1.get(seg); + public static byte byte9(MemorySegment struct) { + return struct.get(byte9$LAYOUT, byte9$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 byte9; + * {@snippet lang=c : + * UInt8 byte9 * } */ - public static void byte9$set(MemorySegment seg, byte x) { - constants$5.const$1.set(seg, x); + public static void byte9(MemorySegment struct, byte fieldValue) { + struct.set(byte9$LAYOUT, byte9$OFFSET, fieldValue); } - public static byte byte9$get(MemorySegment seg, long index) { - return (byte)constants$5.const$1.get(seg.asSlice(index*sizeof())); - } - public static void byte9$set(MemorySegment seg, long index, byte x) { - constants$5.const$1.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte byte10$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte10")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte10 + * } + */ + public static final OfByte byte10$layout() { + return byte10$LAYOUT; } - public static VarHandle byte10$VH() { - return constants$5.const$2; + + private static final long byte10$OFFSET = 10; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte10 + * } + */ + public static final long byte10$offset() { + return byte10$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 byte10; + * {@snippet lang=c : + * UInt8 byte10 * } */ - public static byte byte10$get(MemorySegment seg) { - return (byte)constants$5.const$2.get(seg); + public static byte byte10(MemorySegment struct) { + return struct.get(byte10$LAYOUT, byte10$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 byte10; + * {@snippet lang=c : + * UInt8 byte10 * } */ - public static void byte10$set(MemorySegment seg, byte x) { - constants$5.const$2.set(seg, x); + public static void byte10(MemorySegment struct, byte fieldValue) { + struct.set(byte10$LAYOUT, byte10$OFFSET, fieldValue); } - public static byte byte10$get(MemorySegment seg, long index) { - return (byte)constants$5.const$2.get(seg.asSlice(index*sizeof())); - } - public static void byte10$set(MemorySegment seg, long index, byte x) { - constants$5.const$2.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte byte11$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte11")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte11 + * } + */ + public static final OfByte byte11$layout() { + return byte11$LAYOUT; } - public static VarHandle byte11$VH() { - return constants$5.const$3; + + private static final long byte11$OFFSET = 11; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte11 + * } + */ + public static final long byte11$offset() { + return byte11$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 byte11; + * {@snippet lang=c : + * UInt8 byte11 * } */ - public static byte byte11$get(MemorySegment seg) { - return (byte)constants$5.const$3.get(seg); + public static byte byte11(MemorySegment struct) { + return struct.get(byte11$LAYOUT, byte11$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 byte11; + * {@snippet lang=c : + * UInt8 byte11 * } */ - public static void byte11$set(MemorySegment seg, byte x) { - constants$5.const$3.set(seg, x); + public static void byte11(MemorySegment struct, byte fieldValue) { + struct.set(byte11$LAYOUT, byte11$OFFSET, fieldValue); } - public static byte byte11$get(MemorySegment seg, long index) { - return (byte)constants$5.const$3.get(seg.asSlice(index*sizeof())); - } - public static void byte11$set(MemorySegment seg, long index, byte x) { - constants$5.const$3.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte byte12$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte12")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte12 + * } + */ + public static final OfByte byte12$layout() { + return byte12$LAYOUT; } - public static VarHandle byte12$VH() { - return constants$5.const$4; + + private static final long byte12$OFFSET = 12; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte12 + * } + */ + public static final long byte12$offset() { + return byte12$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 byte12; + * {@snippet lang=c : + * UInt8 byte12 * } */ - public static byte byte12$get(MemorySegment seg) { - return (byte)constants$5.const$4.get(seg); + public static byte byte12(MemorySegment struct) { + return struct.get(byte12$LAYOUT, byte12$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 byte12; + * {@snippet lang=c : + * UInt8 byte12 * } */ - public static void byte12$set(MemorySegment seg, byte x) { - constants$5.const$4.set(seg, x); - } - public static byte byte12$get(MemorySegment seg, long index) { - return (byte)constants$5.const$4.get(seg.asSlice(index*sizeof())); + public static void byte12(MemorySegment struct, byte fieldValue) { + struct.set(byte12$LAYOUT, byte12$OFFSET, fieldValue); } - public static void byte12$set(MemorySegment seg, long index, byte x) { - constants$5.const$4.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte byte13$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte13")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte13 + * } + */ + public static final OfByte byte13$layout() { + return byte13$LAYOUT; } - public static VarHandle byte13$VH() { - return constants$5.const$5; + + private static final long byte13$OFFSET = 13; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte13 + * } + */ + public static final long byte13$offset() { + return byte13$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 byte13; + * {@snippet lang=c : + * UInt8 byte13 * } */ - public static byte byte13$get(MemorySegment seg) { - return (byte)constants$5.const$5.get(seg); + public static byte byte13(MemorySegment struct) { + return struct.get(byte13$LAYOUT, byte13$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 byte13; + * {@snippet lang=c : + * UInt8 byte13 * } */ - public static void byte13$set(MemorySegment seg, byte x) { - constants$5.const$5.set(seg, x); + public static void byte13(MemorySegment struct, byte fieldValue) { + struct.set(byte13$LAYOUT, byte13$OFFSET, fieldValue); } - public static byte byte13$get(MemorySegment seg, long index) { - return (byte)constants$5.const$5.get(seg.asSlice(index*sizeof())); - } - public static void byte13$set(MemorySegment seg, long index, byte x) { - constants$5.const$5.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte byte14$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte14")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte14 + * } + */ + public static final OfByte byte14$layout() { + return byte14$LAYOUT; } - public static VarHandle byte14$VH() { - return constants$6.const$0; + + private static final long byte14$OFFSET = 14; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte14 + * } + */ + public static final long byte14$offset() { + return byte14$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 byte14; + * {@snippet lang=c : + * UInt8 byte14 * } */ - public static byte byte14$get(MemorySegment seg) { - return (byte)constants$6.const$0.get(seg); + public static byte byte14(MemorySegment struct) { + return struct.get(byte14$LAYOUT, byte14$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 byte14; + * {@snippet lang=c : + * UInt8 byte14 * } */ - public static void byte14$set(MemorySegment seg, byte x) { - constants$6.const$0.set(seg, x); + public static void byte14(MemorySegment struct, byte fieldValue) { + struct.set(byte14$LAYOUT, byte14$OFFSET, fieldValue); } - public static byte byte14$get(MemorySegment seg, long index) { - return (byte)constants$6.const$0.get(seg.asSlice(index*sizeof())); - } - public static void byte14$set(MemorySegment seg, long index, byte x) { - constants$6.const$0.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte byte15$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte15")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte15 + * } + */ + public static final OfByte byte15$layout() { + return byte15$LAYOUT; } - public static VarHandle byte15$VH() { - return constants$6.const$1; + + private static final long byte15$OFFSET = 15; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte15 + * } + */ + public static final long byte15$offset() { + return byte15$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 byte15; + * {@snippet lang=c : + * UInt8 byte15 * } */ - public static byte byte15$get(MemorySegment seg) { - return (byte)constants$6.const$1.get(seg); + public static byte byte15(MemorySegment struct) { + return struct.get(byte15$LAYOUT, byte15$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 byte15; + * {@snippet lang=c : + * UInt8 byte15 * } */ - public static void byte15$set(MemorySegment seg, byte x) { - constants$6.const$1.set(seg, x); + public static void byte15(MemorySegment struct, byte fieldValue) { + struct.set(byte15$LAYOUT, byte15$OFFSET, fieldValue); } - public static byte byte15$get(MemorySegment seg, long index) { - return (byte)constants$6.const$1.get(seg.asSlice(index*sizeof())); + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); } - public static void byte15$set(MemorySegment seg, long index, byte x) { - constants$6.const$1.set(seg.asSlice(index*sizeof()), x); + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } -} + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java index 92f76e89..791879cf 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java @@ -2,265 +2,737 @@ package net.codecrete.usb.macos.gen.corefoundation; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.*; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_FLOAT; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -import static java.lang.foreign.ValueLayout.OfByte; -import static java.lang.foreign.ValueLayout.OfDouble; -import static java.lang.foreign.ValueLayout.OfFloat; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfLong; -import static java.lang.foreign.ValueLayout.OfShort; -public class CoreFoundation { - - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfLong C_LONG = JAVA_LONG; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; - public static MethodHandle CFGetTypeID$MH() { - return RuntimeHelper.requireNonNull(constants$0.const$4,"CFGetTypeID"); - } - /** - * {@snippet : - * CFTypeID CFGetTypeID(CFTypeRef cf); + +public class CoreFoundation { + + CoreFoundation() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + + // Manually fix. Otherwise, system library will not be found + // static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("CoreFoundation.framework"), LIBRARY_ARENA) + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", LIBRARY_ARENA) + .or(SymbolLookup.loaderLookup()) + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; + + private static class CFGetTypeID { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + CoreFoundation.C_LONG, + CoreFoundation.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFGetTypeID"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * extern CFTypeID CFGetTypeID(CFTypeRef cf) + * } + */ + public static FunctionDescriptor CFGetTypeID$descriptor() { + return CFGetTypeID.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern CFTypeID CFGetTypeID(CFTypeRef cf) + * } + */ + public static MethodHandle CFGetTypeID$handle() { + return CFGetTypeID.HANDLE; + } + /** + * {@snippet lang=c : + * extern CFTypeID CFGetTypeID(CFTypeRef cf) * } */ public static long CFGetTypeID(MemorySegment cf) { - var mh$ = CFGetTypeID$MH(); + var mh$ = CFGetTypeID.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("CFGetTypeID", cf); + } return (long)mh$.invokeExact(cf); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle CFRelease$MH() { - return RuntimeHelper.requireNonNull(constants$0.const$6,"CFRelease"); + + private static class CFRelease { + public static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid( + CoreFoundation.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFRelease"), + DESC); } + /** - * {@snippet : - * void CFRelease(CFTypeRef cf); + * Function descriptor for: + * {@snippet lang=c : + * extern void CFRelease(CFTypeRef cf) + * } + */ + public static FunctionDescriptor CFRelease$descriptor() { + return CFRelease.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern void CFRelease(CFTypeRef cf) + * } + */ + public static MethodHandle CFRelease$handle() { + return CFRelease.HANDLE; + } + /** + * {@snippet lang=c : + * extern void CFRelease(CFTypeRef cf) * } */ public static void CFRelease(MemorySegment cf) { - var mh$ = CFRelease$MH(); + var mh$ = CFRelease.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("CFRelease", cf); + } mh$.invokeExact(cf); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle CFStringGetTypeID$MH() { - return RuntimeHelper.requireNonNull(constants$1.const$1,"CFStringGetTypeID"); + + private static class CFStringGetTypeID { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + CoreFoundation.C_LONG ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFStringGetTypeID"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * extern CFTypeID CFStringGetTypeID(void) + * } + */ + public static FunctionDescriptor CFStringGetTypeID$descriptor() { + return CFStringGetTypeID.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern CFTypeID CFStringGetTypeID(void) + * } + */ + public static MethodHandle CFStringGetTypeID$handle() { + return CFStringGetTypeID.HANDLE; } /** - * {@snippet : - * CFTypeID CFStringGetTypeID(); + * {@snippet lang=c : + * extern CFTypeID CFStringGetTypeID(void) * } */ public static long CFStringGetTypeID() { - var mh$ = CFStringGetTypeID$MH(); + var mh$ = CFStringGetTypeID.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("CFStringGetTypeID"); + } return (long)mh$.invokeExact(); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle CFStringCreateWithCharacters$MH() { - return RuntimeHelper.requireNonNull(constants$1.const$3,"CFStringCreateWithCharacters"); + + private static class CFStringCreateWithCharacters { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER, + CoreFoundation.C_LONG + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFStringCreateWithCharacters"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * extern CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, const UniChar *chars, CFIndex numChars) + * } + */ + public static FunctionDescriptor CFStringCreateWithCharacters$descriptor() { + return CFStringCreateWithCharacters.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, const UniChar *chars, CFIndex numChars) + * } + */ + public static MethodHandle CFStringCreateWithCharacters$handle() { + return CFStringCreateWithCharacters.HANDLE; } /** - * {@snippet : - * CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, const UniChar* chars, CFIndex numChars); + * {@snippet lang=c : + * extern CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, const UniChar *chars, CFIndex numChars) * } */ public static MemorySegment CFStringCreateWithCharacters(MemorySegment alloc, MemorySegment chars, long numChars) { - var mh$ = CFStringCreateWithCharacters$MH(); + var mh$ = CFStringCreateWithCharacters.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(alloc, chars, numChars); + if (TRACE_DOWNCALLS) { + traceDowncall("CFStringCreateWithCharacters", alloc, chars, numChars); + } + return (MemorySegment)mh$.invokeExact(alloc, chars, numChars); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle CFStringGetLength$MH() { - return RuntimeHelper.requireNonNull(constants$1.const$4,"CFStringGetLength"); + + private static class CFStringGetLength { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + CoreFoundation.C_LONG, + CoreFoundation.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFStringGetLength"), + DESC); } + /** - * {@snippet : - * CFIndex CFStringGetLength(CFStringRef theString); + * Function descriptor for: + * {@snippet lang=c : + * extern CFIndex CFStringGetLength(CFStringRef theString) + * } + */ + public static FunctionDescriptor CFStringGetLength$descriptor() { + return CFStringGetLength.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern CFIndex CFStringGetLength(CFStringRef theString) + * } + */ + public static MethodHandle CFStringGetLength$handle() { + return CFStringGetLength.HANDLE; + } + /** + * {@snippet lang=c : + * extern CFIndex CFStringGetLength(CFStringRef theString) * } */ public static long CFStringGetLength(MemorySegment theString) { - var mh$ = CFStringGetLength$MH(); + var mh$ = CFStringGetLength.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("CFStringGetLength", theString); + } return (long)mh$.invokeExact(theString); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle CFStringGetCharacters$MH() { - return RuntimeHelper.requireNonNull(constants$1.const$6,"CFStringGetCharacters"); + + private static class CFStringGetCharacters { + public static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid( + CoreFoundation.C_POINTER, + CFRange.layout(), + CoreFoundation.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFStringGetCharacters"), + DESC); } + /** - * {@snippet : - * void CFStringGetCharacters(CFStringRef theString, CFRange range, UniChar* buffer); + * Function descriptor for: + * {@snippet lang=c : + * extern void CFStringGetCharacters(CFStringRef theString, CFRange range, UniChar *buffer) + * } + */ + public static FunctionDescriptor CFStringGetCharacters$descriptor() { + return CFStringGetCharacters.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern void CFStringGetCharacters(CFStringRef theString, CFRange range, UniChar *buffer) + * } + */ + public static MethodHandle CFStringGetCharacters$handle() { + return CFStringGetCharacters.HANDLE; + } + /** + * {@snippet lang=c : + * extern void CFStringGetCharacters(CFStringRef theString, CFRange range, UniChar *buffer) * } */ public static void CFStringGetCharacters(MemorySegment theString, MemorySegment range, MemorySegment buffer) { - var mh$ = CFStringGetCharacters$MH(); + var mh$ = CFStringGetCharacters.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("CFStringGetCharacters", theString, range, buffer); + } mh$.invokeExact(theString, range, buffer); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } + private static final int kCFNumberSInt32Type = (int)3L; /** - * {@snippet : - * enum .kCFNumberSInt32Type = 3; + * {@snippet lang=c : + * enum enum (unnamed at /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/CoreFoundation.framework/Headers/CFNumber.h:31:9).kCFNumberSInt32Type = 3 * } */ public static int kCFNumberSInt32Type() { - return (int)3L; + return kCFNumberSInt32Type; } - public static MethodHandle CFNumberGetTypeID$MH() { - return RuntimeHelper.requireNonNull(constants$2.const$0,"CFNumberGetTypeID"); + + private static class CFNumberGetTypeID { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + CoreFoundation.C_LONG ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFNumberGetTypeID"), + DESC); } + /** - * {@snippet : - * CFTypeID CFNumberGetTypeID(); + * Function descriptor for: + * {@snippet lang=c : + * extern CFTypeID CFNumberGetTypeID(void) + * } + */ + public static FunctionDescriptor CFNumberGetTypeID$descriptor() { + return CFNumberGetTypeID.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern CFTypeID CFNumberGetTypeID(void) + * } + */ + public static MethodHandle CFNumberGetTypeID$handle() { + return CFNumberGetTypeID.HANDLE; + } + /** + * {@snippet lang=c : + * extern CFTypeID CFNumberGetTypeID(void) * } */ public static long CFNumberGetTypeID() { - var mh$ = CFNumberGetTypeID$MH(); + var mh$ = CFNumberGetTypeID.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("CFNumberGetTypeID"); + } return (long)mh$.invokeExact(); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle CFNumberGetValue$MH() { - return RuntimeHelper.requireNonNull(constants$2.const$2,"CFNumberGetValue"); + + private static class CFNumberGetValue { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + CoreFoundation.C_CHAR, + CoreFoundation.C_POINTER, + CoreFoundation.C_LONG, + CoreFoundation.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFNumberGetValue"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * extern Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void *valuePtr) + * } + */ + public static FunctionDescriptor CFNumberGetValue$descriptor() { + return CFNumberGetValue.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void *valuePtr) + * } + */ + public static MethodHandle CFNumberGetValue$handle() { + return CFNumberGetValue.HANDLE; } /** - * {@snippet : - * Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void* valuePtr); + * {@snippet lang=c : + * extern Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void *valuePtr) * } */ public static byte CFNumberGetValue(MemorySegment number, long theType, MemorySegment valuePtr) { - var mh$ = CFNumberGetValue$MH(); + var mh$ = CFNumberGetValue.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("CFNumberGetValue", number, theType, valuePtr); + } return (byte)mh$.invokeExact(number, theType, valuePtr); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle CFRunLoopGetCurrent$MH() { - return RuntimeHelper.requireNonNull(constants$2.const$4,"CFRunLoopGetCurrent"); + + private static class CFRunLoopGetCurrent { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + CoreFoundation.C_POINTER ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFRunLoopGetCurrent"), + DESC); } + /** - * {@snippet : - * CFRunLoopRef CFRunLoopGetCurrent(); + * Function descriptor for: + * {@snippet lang=c : + * extern CFRunLoopRef CFRunLoopGetCurrent(void) + * } + */ + public static FunctionDescriptor CFRunLoopGetCurrent$descriptor() { + return CFRunLoopGetCurrent.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern CFRunLoopRef CFRunLoopGetCurrent(void) + * } + */ + public static MethodHandle CFRunLoopGetCurrent$handle() { + return CFRunLoopGetCurrent.HANDLE; + } + /** + * {@snippet lang=c : + * extern CFRunLoopRef CFRunLoopGetCurrent(void) * } */ public static MemorySegment CFRunLoopGetCurrent() { - var mh$ = CFRunLoopGetCurrent$MH(); + var mh$ = CFRunLoopGetCurrent.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(); + if (TRACE_DOWNCALLS) { + traceDowncall("CFRunLoopGetCurrent"); + } + return (MemorySegment)mh$.invokeExact(); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle CFRunLoopRun$MH() { - return RuntimeHelper.requireNonNull(constants$2.const$6,"CFRunLoopRun"); + + private static class CFRunLoopRun { + public static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid( ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFRunLoopRun"), + DESC); } + /** - * {@snippet : - * void CFRunLoopRun(); + * Function descriptor for: + * {@snippet lang=c : + * extern void CFRunLoopRun(void) + * } + */ + public static FunctionDescriptor CFRunLoopRun$descriptor() { + return CFRunLoopRun.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern void CFRunLoopRun(void) + * } + */ + public static MethodHandle CFRunLoopRun$handle() { + return CFRunLoopRun.HANDLE; + } + /** + * {@snippet lang=c : + * extern void CFRunLoopRun(void) * } */ public static void CFRunLoopRun() { - var mh$ = CFRunLoopRun$MH(); + var mh$ = CFRunLoopRun.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("CFRunLoopRun"); + } mh$.invokeExact(); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle CFRunLoopAddSource$MH() { - return RuntimeHelper.requireNonNull(constants$3.const$1,"CFRunLoopAddSource"); + + private static class CFRunLoopAddSource { + public static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid( + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFRunLoopAddSource"), + DESC); } + /** - * {@snippet : - * void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode); + * Function descriptor for: + * {@snippet lang=c : + * extern void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode) + * } + */ + public static FunctionDescriptor CFRunLoopAddSource$descriptor() { + return CFRunLoopAddSource.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode) + * } + */ + public static MethodHandle CFRunLoopAddSource$handle() { + return CFRunLoopAddSource.HANDLE; + } + /** + * {@snippet lang=c : + * extern void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode) * } */ public static void CFRunLoopAddSource(MemorySegment rl, MemorySegment source, MemorySegment mode) { - var mh$ = CFRunLoopAddSource$MH(); + var mh$ = CFRunLoopAddSource.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("CFRunLoopAddSource", rl, source, mode); + } mh$.invokeExact(rl, source, mode); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle CFRunLoopRemoveSource$MH() { - return RuntimeHelper.requireNonNull(constants$3.const$2,"CFRunLoopRemoveSource"); + + private static class CFRunLoopRemoveSource { + public static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid( + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFRunLoopRemoveSource"), + DESC); } + /** - * {@snippet : - * void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode); + * Function descriptor for: + * {@snippet lang=c : + * extern void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode) + * } + */ + public static FunctionDescriptor CFRunLoopRemoveSource$descriptor() { + return CFRunLoopRemoveSource.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode) + * } + */ + public static MethodHandle CFRunLoopRemoveSource$handle() { + return CFRunLoopRemoveSource.HANDLE; + } + /** + * {@snippet lang=c : + * extern void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode) * } */ public static void CFRunLoopRemoveSource(MemorySegment rl, MemorySegment source, MemorySegment mode) { - var mh$ = CFRunLoopRemoveSource$MH(); + var mh$ = CFRunLoopRemoveSource.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("CFRunLoopRemoveSource", rl, source, mode); + } mh$.invokeExact(rl, source, mode); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle CFUUIDGetUUIDBytes$MH() { - return RuntimeHelper.requireNonNull(constants$6.const$3,"CFUUIDGetUUIDBytes"); + + private static class CFUUIDGetUUIDBytes { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + CFUUIDBytes.layout(), + CoreFoundation.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFUUIDGetUUIDBytes"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * extern CFUUIDBytes CFUUIDGetUUIDBytes(CFUUIDRef uuid) + * } + */ + public static FunctionDescriptor CFUUIDGetUUIDBytes$descriptor() { + return CFUUIDGetUUIDBytes.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern CFUUIDBytes CFUUIDGetUUIDBytes(CFUUIDRef uuid) + * } + */ + public static MethodHandle CFUUIDGetUUIDBytes$handle() { + return CFUUIDGetUUIDBytes.HANDLE; } /** - * {@snippet : - * CFUUIDBytes CFUUIDGetUUIDBytes(CFUUIDRef uuid); + * {@snippet lang=c : + * extern CFUUIDBytes CFUUIDGetUUIDBytes(CFUUIDRef uuid) * } */ public static MemorySegment CFUUIDGetUUIDBytes(SegmentAllocator allocator, MemorySegment uuid) { - var mh$ = CFUUIDGetUUIDBytes$MH(); + var mh$ = CFUUIDGetUUIDBytes.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(allocator, uuid); + if (TRACE_DOWNCALLS) { + traceDowncall("CFUUIDGetUUIDBytes", allocator, uuid); + } + return (MemorySegment)mh$.invokeExact(allocator, uuid); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle CFUUIDCreateFromUUIDBytes$MH() { - return RuntimeHelper.requireNonNull(constants$6.const$5,"CFUUIDCreateFromUUIDBytes"); + + private static class CFUUIDCreateFromUUIDBytes { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER, + CFUUIDBytes.layout() + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFUUIDCreateFromUUIDBytes"), + DESC); } + + /** + * Function descriptor for: + * {@snippet lang=c : + * extern CFUUIDRef CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc, CFUUIDBytes bytes) + * } + */ + public static FunctionDescriptor CFUUIDCreateFromUUIDBytes$descriptor() { + return CFUUIDCreateFromUUIDBytes.DESC; + } + /** - * {@snippet : - * CFUUIDRef CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc, CFUUIDBytes bytes); + * Downcall method handle for: + * {@snippet lang=c : + * extern CFUUIDRef CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc, CFUUIDBytes bytes) + * } + */ + public static MethodHandle CFUUIDCreateFromUUIDBytes$handle() { + return CFUUIDCreateFromUUIDBytes.HANDLE; + } + /** + * {@snippet lang=c : + * extern CFUUIDRef CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc, CFUUIDBytes bytes) * } */ public static MemorySegment CFUUIDCreateFromUUIDBytes(MemorySegment alloc, MemorySegment bytes) { - var mh$ = CFUUIDCreateFromUUIDBytes$MH(); + var mh$ = CFUUIDCreateFromUUIDBytes.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(alloc, bytes); + if (TRACE_DOWNCALLS) { + traceDowncall("CFUUIDCreateFromUUIDBytes", alloc, bytes); + } + return (MemorySegment)mh$.invokeExact(alloc, bytes); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java deleted file mode 100644 index c3b86b90..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/RuntimeHelper.java +++ /dev/null @@ -1,240 +0,0 @@ -package net.codecrete.usb.macos.gen.corefoundation; -// Generated by jextract - -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_LONG; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { -// System.loadLibrary("CoreFoundation.framework"); -// SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SymbolLookup loaderLookup = SymbolLookup.libraryLookup("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", Arena.global()); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$0.java deleted file mode 100644 index ec347d54..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$0.java +++ /dev/null @@ -1,38 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.corefoundation; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_LONG; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final StructLayout const$0 = MemoryLayout.structLayout( - JAVA_LONG.withName("location"), - JAVA_LONG.withName("length") - ).withName(""); - static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("location")); - static final VarHandle const$2 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("length")); - static final FunctionDescriptor const$3 = FunctionDescriptor.of(JAVA_LONG, - RuntimeHelper.POINTER - ); - static final MethodHandle const$4 = RuntimeHelper.downcallHandle( - "CFGetTypeID", - constants$0.const$3 - ); - static final FunctionDescriptor const$5 = FunctionDescriptor.ofVoid( - RuntimeHelper.POINTER - ); - static final MethodHandle const$6 = RuntimeHelper.downcallHandle( - "CFRelease", - constants$0.const$5 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java deleted file mode 100644 index d7550d1a..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$1.java +++ /dev/null @@ -1,46 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.corefoundation; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.JAVA_LONG; -final class constants$1 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$1() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_LONG); - static final MethodHandle const$1 = RuntimeHelper.downcallHandle( - "CFStringGetTypeID", - constants$1.const$0 - ); - static final FunctionDescriptor const$2 = FunctionDescriptor.of(RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - JAVA_LONG - ); - static final MethodHandle const$3 = RuntimeHelper.downcallHandle( - "CFStringCreateWithCharacters", - constants$1.const$2 - ); - static final MethodHandle const$4 = RuntimeHelper.downcallHandle( - "CFStringGetLength", - constants$0.const$3 - ); - static final FunctionDescriptor const$5 = FunctionDescriptor.ofVoid( - RuntimeHelper.POINTER, - MemoryLayout.structLayout( - JAVA_LONG.withName("location"), - JAVA_LONG.withName("length") - ).withName(""), - RuntimeHelper.POINTER - ); - static final MethodHandle const$6 = RuntimeHelper.downcallHandle( - "CFStringGetCharacters", - constants$1.const$5 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java deleted file mode 100644 index 7db1c6cc..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$2.java +++ /dev/null @@ -1,39 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.corefoundation; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -final class constants$2 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$2() {} - static final MethodHandle const$0 = RuntimeHelper.downcallHandle( - "CFNumberGetTypeID", - constants$1.const$0 - ); - static final FunctionDescriptor const$1 = FunctionDescriptor.of(JAVA_BYTE, - RuntimeHelper.POINTER, - JAVA_LONG, - RuntimeHelper.POINTER - ); - static final MethodHandle const$2 = RuntimeHelper.downcallHandle( - "CFNumberGetValue", - constants$2.const$1 - ); - static final FunctionDescriptor const$3 = FunctionDescriptor.of(RuntimeHelper.POINTER); - static final MethodHandle const$4 = RuntimeHelper.downcallHandle( - "CFRunLoopGetCurrent", - constants$2.const$3 - ); - static final FunctionDescriptor const$5 = FunctionDescriptor.ofVoid(); - static final MethodHandle const$6 = RuntimeHelper.downcallHandle( - "CFRunLoopRun", - constants$2.const$5 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$3.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$3.java deleted file mode 100644 index 1a0a9ed3..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$3.java +++ /dev/null @@ -1,51 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.corefoundation; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -final class constants$3 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$3() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.ofVoid( - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$1 = RuntimeHelper.downcallHandle( - "CFRunLoopAddSource", - constants$3.const$0 - ); - static final MethodHandle const$2 = RuntimeHelper.downcallHandle( - "CFRunLoopRemoveSource", - constants$3.const$0 - ); - static final StructLayout const$3 = MemoryLayout.structLayout( - JAVA_BYTE.withName("byte0"), - JAVA_BYTE.withName("byte1"), - JAVA_BYTE.withName("byte2"), - JAVA_BYTE.withName("byte3"), - JAVA_BYTE.withName("byte4"), - JAVA_BYTE.withName("byte5"), - JAVA_BYTE.withName("byte6"), - JAVA_BYTE.withName("byte7"), - JAVA_BYTE.withName("byte8"), - JAVA_BYTE.withName("byte9"), - JAVA_BYTE.withName("byte10"), - JAVA_BYTE.withName("byte11"), - JAVA_BYTE.withName("byte12"), - JAVA_BYTE.withName("byte13"), - JAVA_BYTE.withName("byte14"), - JAVA_BYTE.withName("byte15") - ).withName(""); - static final VarHandle const$4 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte0")); - static final VarHandle const$5 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte1")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$4.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$4.java deleted file mode 100644 index 52637eb6..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$4.java +++ /dev/null @@ -1,19 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.corefoundation; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.VarHandle; -final class constants$4 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$4() {} - static final VarHandle const$0 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte2")); - static final VarHandle const$1 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte3")); - static final VarHandle const$2 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte4")); - static final VarHandle const$3 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte5")); - static final VarHandle const$4 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte6")); - static final VarHandle const$5 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte7")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$5.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$5.java deleted file mode 100644 index 075afe34..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$5.java +++ /dev/null @@ -1,19 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.corefoundation; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.VarHandle; -final class constants$5 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$5() {} - static final VarHandle const$0 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte8")); - static final VarHandle const$1 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte9")); - static final VarHandle const$2 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte10")); - static final VarHandle const$3 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte11")); - static final VarHandle const$4 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte12")); - static final VarHandle const$5 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte13")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$6.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$6.java deleted file mode 100644 index 748e65c4..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/constants$6.java +++ /dev/null @@ -1,68 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.corefoundation; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -final class constants$6 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$6() {} - static final VarHandle const$0 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte14")); - static final VarHandle const$1 = constants$3.const$3.varHandle(MemoryLayout.PathElement.groupElement("byte15")); - static final FunctionDescriptor const$2 = FunctionDescriptor.of(MemoryLayout.structLayout( - JAVA_BYTE.withName("byte0"), - JAVA_BYTE.withName("byte1"), - JAVA_BYTE.withName("byte2"), - JAVA_BYTE.withName("byte3"), - JAVA_BYTE.withName("byte4"), - JAVA_BYTE.withName("byte5"), - JAVA_BYTE.withName("byte6"), - JAVA_BYTE.withName("byte7"), - JAVA_BYTE.withName("byte8"), - JAVA_BYTE.withName("byte9"), - JAVA_BYTE.withName("byte10"), - JAVA_BYTE.withName("byte11"), - JAVA_BYTE.withName("byte12"), - JAVA_BYTE.withName("byte13"), - JAVA_BYTE.withName("byte14"), - JAVA_BYTE.withName("byte15") - ).withName(""), - RuntimeHelper.POINTER - ); - static final MethodHandle const$3 = RuntimeHelper.downcallHandle( - "CFUUIDGetUUIDBytes", - constants$6.const$2 - ); - static final FunctionDescriptor const$4 = FunctionDescriptor.of(RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - MemoryLayout.structLayout( - JAVA_BYTE.withName("byte0"), - JAVA_BYTE.withName("byte1"), - JAVA_BYTE.withName("byte2"), - JAVA_BYTE.withName("byte3"), - JAVA_BYTE.withName("byte4"), - JAVA_BYTE.withName("byte5"), - JAVA_BYTE.withName("byte6"), - JAVA_BYTE.withName("byte7"), - JAVA_BYTE.withName("byte8"), - JAVA_BYTE.withName("byte9"), - JAVA_BYTE.withName("byte10"), - JAVA_BYTE.withName("byte11"), - JAVA_BYTE.withName("byte12"), - JAVA_BYTE.withName("byte13"), - JAVA_BYTE.withName("byte14"), - JAVA_BYTE.withName("byte15") - ).withName("") - ); - static final MethodHandle const$5 = RuntimeHelper.downcallHandle( - "CFUUIDCreateFromUUIDBytes", - constants$6.const$4 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/CFUUIDBytes.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/CFUUIDBytes.java new file mode 100644 index 00000000..1b7dcaa5 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/CFUUIDBytes.java @@ -0,0 +1,813 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.*; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfByte; + +/** + * {@snippet lang=c : + * struct { + * UInt8 byte0; + * UInt8 byte1; + * UInt8 byte2; + * UInt8 byte3; + * UInt8 byte4; + * UInt8 byte5; + * UInt8 byte6; + * UInt8 byte7; + * UInt8 byte8; + * UInt8 byte9; + * UInt8 byte10; + * UInt8 byte11; + * UInt8 byte12; + * UInt8 byte13; + * UInt8 byte14; + * UInt8 byte15; + * } + * } + */ +public class CFUUIDBytes { + + CFUUIDBytes() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + IOKit.C_CHAR.withName("byte0"), + IOKit.C_CHAR.withName("byte1"), + IOKit.C_CHAR.withName("byte2"), + IOKit.C_CHAR.withName("byte3"), + IOKit.C_CHAR.withName("byte4"), + IOKit.C_CHAR.withName("byte5"), + IOKit.C_CHAR.withName("byte6"), + IOKit.C_CHAR.withName("byte7"), + IOKit.C_CHAR.withName("byte8"), + IOKit.C_CHAR.withName("byte9"), + IOKit.C_CHAR.withName("byte10"), + IOKit.C_CHAR.withName("byte11"), + IOKit.C_CHAR.withName("byte12"), + IOKit.C_CHAR.withName("byte13"), + IOKit.C_CHAR.withName("byte14"), + IOKit.C_CHAR.withName("byte15") + ).withName("CFUUIDBytes"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfByte byte0$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte0")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte0 + * } + */ + public static final OfByte byte0$layout() { + return byte0$LAYOUT; + } + + private static final long byte0$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte0 + * } + */ + public static final long byte0$offset() { + return byte0$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UInt8 byte0 + * } + */ + public static byte byte0(MemorySegment struct) { + return struct.get(byte0$LAYOUT, byte0$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UInt8 byte0 + * } + */ + public static void byte0(MemorySegment struct, byte fieldValue) { + struct.set(byte0$LAYOUT, byte0$OFFSET, fieldValue); + } + + private static final OfByte byte1$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte1")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte1 + * } + */ + public static final OfByte byte1$layout() { + return byte1$LAYOUT; + } + + private static final long byte1$OFFSET = 1; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte1 + * } + */ + public static final long byte1$offset() { + return byte1$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UInt8 byte1 + * } + */ + public static byte byte1(MemorySegment struct) { + return struct.get(byte1$LAYOUT, byte1$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UInt8 byte1 + * } + */ + public static void byte1(MemorySegment struct, byte fieldValue) { + struct.set(byte1$LAYOUT, byte1$OFFSET, fieldValue); + } + + private static final OfByte byte2$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte2")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte2 + * } + */ + public static final OfByte byte2$layout() { + return byte2$LAYOUT; + } + + private static final long byte2$OFFSET = 2; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte2 + * } + */ + public static final long byte2$offset() { + return byte2$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UInt8 byte2 + * } + */ + public static byte byte2(MemorySegment struct) { + return struct.get(byte2$LAYOUT, byte2$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UInt8 byte2 + * } + */ + public static void byte2(MemorySegment struct, byte fieldValue) { + struct.set(byte2$LAYOUT, byte2$OFFSET, fieldValue); + } + + private static final OfByte byte3$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte3")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte3 + * } + */ + public static final OfByte byte3$layout() { + return byte3$LAYOUT; + } + + private static final long byte3$OFFSET = 3; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte3 + * } + */ + public static final long byte3$offset() { + return byte3$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UInt8 byte3 + * } + */ + public static byte byte3(MemorySegment struct) { + return struct.get(byte3$LAYOUT, byte3$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UInt8 byte3 + * } + */ + public static void byte3(MemorySegment struct, byte fieldValue) { + struct.set(byte3$LAYOUT, byte3$OFFSET, fieldValue); + } + + private static final OfByte byte4$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte4")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte4 + * } + */ + public static final OfByte byte4$layout() { + return byte4$LAYOUT; + } + + private static final long byte4$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte4 + * } + */ + public static final long byte4$offset() { + return byte4$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UInt8 byte4 + * } + */ + public static byte byte4(MemorySegment struct) { + return struct.get(byte4$LAYOUT, byte4$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UInt8 byte4 + * } + */ + public static void byte4(MemorySegment struct, byte fieldValue) { + struct.set(byte4$LAYOUT, byte4$OFFSET, fieldValue); + } + + private static final OfByte byte5$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte5")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte5 + * } + */ + public static final OfByte byte5$layout() { + return byte5$LAYOUT; + } + + private static final long byte5$OFFSET = 5; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte5 + * } + */ + public static final long byte5$offset() { + return byte5$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UInt8 byte5 + * } + */ + public static byte byte5(MemorySegment struct) { + return struct.get(byte5$LAYOUT, byte5$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UInt8 byte5 + * } + */ + public static void byte5(MemorySegment struct, byte fieldValue) { + struct.set(byte5$LAYOUT, byte5$OFFSET, fieldValue); + } + + private static final OfByte byte6$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte6")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte6 + * } + */ + public static final OfByte byte6$layout() { + return byte6$LAYOUT; + } + + private static final long byte6$OFFSET = 6; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte6 + * } + */ + public static final long byte6$offset() { + return byte6$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UInt8 byte6 + * } + */ + public static byte byte6(MemorySegment struct) { + return struct.get(byte6$LAYOUT, byte6$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UInt8 byte6 + * } + */ + public static void byte6(MemorySegment struct, byte fieldValue) { + struct.set(byte6$LAYOUT, byte6$OFFSET, fieldValue); + } + + private static final OfByte byte7$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte7")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte7 + * } + */ + public static final OfByte byte7$layout() { + return byte7$LAYOUT; + } + + private static final long byte7$OFFSET = 7; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte7 + * } + */ + public static final long byte7$offset() { + return byte7$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UInt8 byte7 + * } + */ + public static byte byte7(MemorySegment struct) { + return struct.get(byte7$LAYOUT, byte7$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UInt8 byte7 + * } + */ + public static void byte7(MemorySegment struct, byte fieldValue) { + struct.set(byte7$LAYOUT, byte7$OFFSET, fieldValue); + } + + private static final OfByte byte8$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte8")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte8 + * } + */ + public static final OfByte byte8$layout() { + return byte8$LAYOUT; + } + + private static final long byte8$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte8 + * } + */ + public static final long byte8$offset() { + return byte8$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UInt8 byte8 + * } + */ + public static byte byte8(MemorySegment struct) { + return struct.get(byte8$LAYOUT, byte8$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UInt8 byte8 + * } + */ + public static void byte8(MemorySegment struct, byte fieldValue) { + struct.set(byte8$LAYOUT, byte8$OFFSET, fieldValue); + } + + private static final OfByte byte9$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte9")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte9 + * } + */ + public static final OfByte byte9$layout() { + return byte9$LAYOUT; + } + + private static final long byte9$OFFSET = 9; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte9 + * } + */ + public static final long byte9$offset() { + return byte9$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UInt8 byte9 + * } + */ + public static byte byte9(MemorySegment struct) { + return struct.get(byte9$LAYOUT, byte9$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UInt8 byte9 + * } + */ + public static void byte9(MemorySegment struct, byte fieldValue) { + struct.set(byte9$LAYOUT, byte9$OFFSET, fieldValue); + } + + private static final OfByte byte10$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte10")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte10 + * } + */ + public static final OfByte byte10$layout() { + return byte10$LAYOUT; + } + + private static final long byte10$OFFSET = 10; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte10 + * } + */ + public static final long byte10$offset() { + return byte10$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UInt8 byte10 + * } + */ + public static byte byte10(MemorySegment struct) { + return struct.get(byte10$LAYOUT, byte10$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UInt8 byte10 + * } + */ + public static void byte10(MemorySegment struct, byte fieldValue) { + struct.set(byte10$LAYOUT, byte10$OFFSET, fieldValue); + } + + private static final OfByte byte11$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte11")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte11 + * } + */ + public static final OfByte byte11$layout() { + return byte11$LAYOUT; + } + + private static final long byte11$OFFSET = 11; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte11 + * } + */ + public static final long byte11$offset() { + return byte11$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UInt8 byte11 + * } + */ + public static byte byte11(MemorySegment struct) { + return struct.get(byte11$LAYOUT, byte11$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UInt8 byte11 + * } + */ + public static void byte11(MemorySegment struct, byte fieldValue) { + struct.set(byte11$LAYOUT, byte11$OFFSET, fieldValue); + } + + private static final OfByte byte12$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte12")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte12 + * } + */ + public static final OfByte byte12$layout() { + return byte12$LAYOUT; + } + + private static final long byte12$OFFSET = 12; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte12 + * } + */ + public static final long byte12$offset() { + return byte12$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UInt8 byte12 + * } + */ + public static byte byte12(MemorySegment struct) { + return struct.get(byte12$LAYOUT, byte12$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UInt8 byte12 + * } + */ + public static void byte12(MemorySegment struct, byte fieldValue) { + struct.set(byte12$LAYOUT, byte12$OFFSET, fieldValue); + } + + private static final OfByte byte13$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte13")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte13 + * } + */ + public static final OfByte byte13$layout() { + return byte13$LAYOUT; + } + + private static final long byte13$OFFSET = 13; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte13 + * } + */ + public static final long byte13$offset() { + return byte13$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UInt8 byte13 + * } + */ + public static byte byte13(MemorySegment struct) { + return struct.get(byte13$LAYOUT, byte13$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UInt8 byte13 + * } + */ + public static void byte13(MemorySegment struct, byte fieldValue) { + struct.set(byte13$LAYOUT, byte13$OFFSET, fieldValue); + } + + private static final OfByte byte14$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte14")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte14 + * } + */ + public static final OfByte byte14$layout() { + return byte14$LAYOUT; + } + + private static final long byte14$OFFSET = 14; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte14 + * } + */ + public static final long byte14$offset() { + return byte14$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UInt8 byte14 + * } + */ + public static byte byte14(MemorySegment struct) { + return struct.get(byte14$LAYOUT, byte14$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UInt8 byte14 + * } + */ + public static void byte14(MemorySegment struct, byte fieldValue) { + struct.set(byte14$LAYOUT, byte14$OFFSET, fieldValue); + } + + private static final OfByte byte15$LAYOUT = (OfByte)$LAYOUT.select(groupElement("byte15")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 byte15 + * } + */ + public static final OfByte byte15$layout() { + return byte15$LAYOUT; + } + + private static final long byte15$OFFSET = 15; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 byte15 + * } + */ + public static final long byte15$offset() { + return byte15$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * UInt8 byte15 + * } + */ + public static byte byte15(MemorySegment struct) { + return struct.get(byte15$LAYOUT, byte15$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * UInt8 byte15 + * } + */ + public static void byte15(MemorySegment struct, byte fieldValue) { + struct.set(byte15$LAYOUT, byte15$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterface.java index 0b23bb51..5fe6f2d9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterface.java @@ -3,14 +3,24 @@ package net.codecrete.usb.macos.gen.iokit; /** - * {@snippet : - * typedef struct IOCFPlugInInterfaceStruct IOCFPlugInInterface; + * {@snippet lang=c : + * typedef struct IOCFPlugInInterfaceStruct { + * void *_reserved; + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *); + * ULONG (*AddRef)(void *); + * ULONG (*Release)(void *); + * UInt16 version; + * UInt16 revision; + * IOReturn (*Probe)(void *, CFDictionaryRef, io_service_t, SInt32 *); + * IOReturn (*Start)(void *, CFDictionaryRef, io_service_t); + * IOReturn (*Stop)(void *); + * } IOCFPlugInInterface * } */ -public final class IOCFPlugInInterface extends IOCFPlugInInterfaceStruct { +public class IOCFPlugInInterface extends IOCFPlugInInterfaceStruct { - // Suppresses default constructor, ensuring non-instantiability. - private IOCFPlugInInterface() {} + IOCFPlugInInterface() { + // Should not be called directly + } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java index 92d54afc..b52221ce 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java @@ -2,436 +2,823 @@ package net.codecrete.usb.macos.gen.iokit; -import java.lang.foreign.Arena; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfShort; + /** - * {@snippet : + * {@snippet lang=c : * struct IOCFPlugInInterfaceStruct { - * void* _reserved; - * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); - * ULONG (*AddRef)(void*); - * ULONG (*Release)(void*); + * void *_reserved; + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *); + * ULONG (*AddRef)(void *); + * ULONG (*Release)(void *); * UInt16 version; * UInt16 revision; - * IOReturn (*Probe)(void*,CFDictionaryRef,io_service_t,SInt32*); - * IOReturn (*Start)(void*,CFDictionaryRef,io_service_t); - * IOReturn (*Stop)(void*); - * }; + * IOReturn (*Probe)(void *, CFDictionaryRef, io_service_t, SInt32 *); + * IOReturn (*Start)(void *, CFDictionaryRef, io_service_t); + * IOReturn (*Stop)(void *); + * } * } */ public class IOCFPlugInInterfaceStruct { - public static MemoryLayout $LAYOUT() { - return constants$40.const$2; + IOCFPlugInInterfaceStruct() { + // Should not be called directly } - public static VarHandle _reserved$VH() { - return constants$40.const$3; + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + IOKit.C_POINTER.withName("_reserved"), + IOKit.C_POINTER.withName("QueryInterface"), + IOKit.C_POINTER.withName("AddRef"), + IOKit.C_POINTER.withName("Release"), + IOKit.C_SHORT.withName("version"), + IOKit.C_SHORT.withName("revision"), + MemoryLayout.paddingLayout(4), + IOKit.C_POINTER.withName("Probe"), + IOKit.C_POINTER.withName("Start"), + IOKit.C_POINTER.withName("Stop") + ).withName("IOCFPlugInInterfaceStruct"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } + + private static final AddressLayout _reserved$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("_reserved")); + /** - * Getter for field: - * {@snippet : - * void* _reserved; + * Layout for field: + * {@snippet lang=c : + * void *_reserved * } */ - public static MemorySegment _reserved$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$40.const$3.get(seg); + public static final AddressLayout _reserved$layout() { + return _reserved$LAYOUT; } + + private static final long _reserved$OFFSET = 0; + /** - * Setter for field: - * {@snippet : - * void* _reserved; + * Offset for field: + * {@snippet lang=c : + * void *_reserved * } */ - public static void _reserved$set(MemorySegment seg, MemorySegment x) { - constants$40.const$3.set(seg, x); + public static final long _reserved$offset() { + return _reserved$OFFSET; } - public static MemorySegment _reserved$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$40.const$3.get(seg.asSlice(index*sizeof())); + + /** + * Getter for field: + * {@snippet lang=c : + * void *_reserved + * } + */ + public static MemorySegment _reserved(MemorySegment struct) { + return struct.get(_reserved$LAYOUT, _reserved$OFFSET); } - public static void _reserved$set(MemorySegment seg, long index, MemorySegment x) { - constants$40.const$3.set(seg.asSlice(index*sizeof()), x); + + /** + * Setter for field: + * {@snippet lang=c : + * void *_reserved + * } + */ + public static void _reserved(MemorySegment struct, MemorySegment fieldValue) { + struct.set(_reserved$LAYOUT, _reserved$OFFSET, fieldValue); } + /** - * {@snippet : - * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * {@snippet lang=c : + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) * } */ - public interface QueryInterface { + public static class QueryInterface { + + QueryInterface() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1, MemorySegment _x2); + } - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(QueryInterface fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$40.const$4, fi, constants$5.const$1, scope); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + CFUUIDBytes.layout(), + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; } - static QueryInterface ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { - try { - return (int)constants$5.const$3.invokeExact(symbol, __x0, __x1, __x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + private static final MethodHandle UP$MH = IOKit.upcallHandle(QueryInterface.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(QueryInterface.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout QueryInterface$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("QueryInterface")); + + /** + * Layout for field: + * {@snippet lang=c : + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) + * } + */ + public static final AddressLayout QueryInterface$layout() { + return QueryInterface$LAYOUT; } - public static VarHandle QueryInterface$VH() { - return constants$40.const$5; + private static final long QueryInterface$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) + * } + */ + public static final long QueryInterface$offset() { + return QueryInterface$OFFSET; } + /** * Getter for field: - * {@snippet : - * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * {@snippet lang=c : + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) * } */ - public static MemorySegment QueryInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$40.const$5.get(seg); + public static MemorySegment QueryInterface(MemorySegment struct) { + return struct.get(QueryInterface$LAYOUT, QueryInterface$OFFSET); } + /** * Setter for field: - * {@snippet : - * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * {@snippet lang=c : + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) * } */ - public static void QueryInterface$set(MemorySegment seg, MemorySegment x) { - constants$40.const$5.set(seg, x); - } - public static MemorySegment QueryInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$40.const$5.get(seg.asSlice(index*sizeof())); - } - public static void QueryInterface$set(MemorySegment seg, long index, MemorySegment x) { - constants$40.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static QueryInterface QueryInterface(MemorySegment segment, Arena scope) { - return QueryInterface.ofAddress(QueryInterface$get(segment), scope); + public static void QueryInterface(MemorySegment struct, MemorySegment fieldValue) { + struct.set(QueryInterface$LAYOUT, QueryInterface$OFFSET, fieldValue); } + /** - * {@snippet : - * ULONG (*AddRef)(void*); + * {@snippet lang=c : + * ULONG (*AddRef)(void *) * } */ - public interface AddRef { + public static class AddRef { - int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(AddRef fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$41.const$0, fi, constants$5.const$5, scope); + AddRef() { + // Should not be called directly } - static AddRef ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (int)constants$6.const$1.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0); } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(AddRef.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(AddRef.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout AddRef$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("AddRef")); + + /** + * Layout for field: + * {@snippet lang=c : + * ULONG (*AddRef)(void *) + * } + */ + public static final AddressLayout AddRef$layout() { + return AddRef$LAYOUT; } - public static VarHandle AddRef$VH() { - return constants$41.const$1; + private static final long AddRef$OFFSET = 16; + + /** + * Offset for field: + * {@snippet lang=c : + * ULONG (*AddRef)(void *) + * } + */ + public static final long AddRef$offset() { + return AddRef$OFFSET; } + /** * Getter for field: - * {@snippet : - * ULONG (*AddRef)(void*); + * {@snippet lang=c : + * ULONG (*AddRef)(void *) * } */ - public static MemorySegment AddRef$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$41.const$1.get(seg); + public static MemorySegment AddRef(MemorySegment struct) { + return struct.get(AddRef$LAYOUT, AddRef$OFFSET); } + /** * Setter for field: - * {@snippet : - * ULONG (*AddRef)(void*); + * {@snippet lang=c : + * ULONG (*AddRef)(void *) * } */ - public static void AddRef$set(MemorySegment seg, MemorySegment x) { - constants$41.const$1.set(seg, x); - } - public static MemorySegment AddRef$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$41.const$1.get(seg.asSlice(index*sizeof())); - } - public static void AddRef$set(MemorySegment seg, long index, MemorySegment x) { - constants$41.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static AddRef AddRef(MemorySegment segment, Arena scope) { - return AddRef.ofAddress(AddRef$get(segment), scope); + public static void AddRef(MemorySegment struct, MemorySegment fieldValue) { + struct.set(AddRef$LAYOUT, AddRef$OFFSET, fieldValue); } + /** - * {@snippet : - * ULONG (*Release)(void*); + * {@snippet lang=c : + * ULONG (*Release)(void *) * } */ - public interface Release { + public static class Release { + + Release() { + // Should not be called directly + } - int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(Release fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$41.const$2, fi, constants$5.const$5, scope); + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0); } - static Release ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (int)constants$6.const$1.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(Release.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(Release.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout Release$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("Release")); + + /** + * Layout for field: + * {@snippet lang=c : + * ULONG (*Release)(void *) + * } + */ + public static final AddressLayout Release$layout() { + return Release$LAYOUT; } - public static VarHandle Release$VH() { - return constants$41.const$3; + private static final long Release$OFFSET = 24; + + /** + * Offset for field: + * {@snippet lang=c : + * ULONG (*Release)(void *) + * } + */ + public static final long Release$offset() { + return Release$OFFSET; } + /** * Getter for field: - * {@snippet : - * ULONG (*Release)(void*); + * {@snippet lang=c : + * ULONG (*Release)(void *) * } */ - public static MemorySegment Release$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$41.const$3.get(seg); + public static MemorySegment Release(MemorySegment struct) { + return struct.get(Release$LAYOUT, Release$OFFSET); } + /** * Setter for field: - * {@snippet : - * ULONG (*Release)(void*); + * {@snippet lang=c : + * ULONG (*Release)(void *) * } */ - public static void Release$set(MemorySegment seg, MemorySegment x) { - constants$41.const$3.set(seg, x); + public static void Release(MemorySegment struct, MemorySegment fieldValue) { + struct.set(Release$LAYOUT, Release$OFFSET, fieldValue); } - public static MemorySegment Release$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$41.const$3.get(seg.asSlice(index*sizeof())); - } - public static void Release$set(MemorySegment seg, long index, MemorySegment x) { - constants$41.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static Release Release(MemorySegment segment, Arena scope) { - return Release.ofAddress(Release$get(segment), scope); + + private static final OfShort version$LAYOUT = (OfShort)$LAYOUT.select(groupElement("version")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt16 version + * } + */ + public static final OfShort version$layout() { + return version$LAYOUT; } - public static VarHandle version$VH() { - return constants$41.const$4; + + private static final long version$OFFSET = 32; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt16 version + * } + */ + public static final long version$offset() { + return version$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt16 version; + * {@snippet lang=c : + * UInt16 version * } */ - public static short version$get(MemorySegment seg) { - return (short)constants$41.const$4.get(seg); + public static short version(MemorySegment struct) { + return struct.get(version$LAYOUT, version$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt16 version; + * {@snippet lang=c : + * UInt16 version * } */ - public static void version$set(MemorySegment seg, short x) { - constants$41.const$4.set(seg, x); - } - public static short version$get(MemorySegment seg, long index) { - return (short)constants$41.const$4.get(seg.asSlice(index*sizeof())); + public static void version(MemorySegment struct, short fieldValue) { + struct.set(version$LAYOUT, version$OFFSET, fieldValue); } - public static void version$set(MemorySegment seg, long index, short x) { - constants$41.const$4.set(seg.asSlice(index*sizeof()), x); + + private static final OfShort revision$LAYOUT = (OfShort)$LAYOUT.select(groupElement("revision")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt16 revision + * } + */ + public static final OfShort revision$layout() { + return revision$LAYOUT; } - public static VarHandle revision$VH() { - return constants$41.const$5; + + private static final long revision$OFFSET = 34; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt16 revision + * } + */ + public static final long revision$offset() { + return revision$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt16 revision; + * {@snippet lang=c : + * UInt16 revision * } */ - public static short revision$get(MemorySegment seg) { - return (short)constants$41.const$5.get(seg); + public static short revision(MemorySegment struct) { + return struct.get(revision$LAYOUT, revision$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt16 revision; + * {@snippet lang=c : + * UInt16 revision * } */ - public static void revision$set(MemorySegment seg, short x) { - constants$41.const$5.set(seg, x); - } - public static short revision$get(MemorySegment seg, long index) { - return (short)constants$41.const$5.get(seg.asSlice(index*sizeof())); - } - public static void revision$set(MemorySegment seg, long index, short x) { - constants$41.const$5.set(seg.asSlice(index*sizeof()), x); + public static void revision(MemorySegment struct, short fieldValue) { + struct.set(revision$LAYOUT, revision$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*Probe)(void*,CFDictionaryRef,io_service_t,SInt32*); + * {@snippet lang=c : + * IOReturn (*Probe)(void *, CFDictionaryRef, io_service_t, SInt32 *) * } */ - public interface Probe { + public static class Probe { + + Probe() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1, int _x2, MemorySegment _x3); + } - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, int _x2, java.lang.foreign.MemorySegment _x3); - static MemorySegment allocate(Probe fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$42.const$1, fi, constants$42.const$0, scope); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; } - static Probe ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, int __x2, java.lang.foreign.MemorySegment __x3) -> { - try { - return (int)constants$42.const$2.invokeExact(symbol, __x0, __x1, __x2, __x3); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + private static final MethodHandle UP$MH = IOKit.upcallHandle(Probe.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(Probe.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, int _x2, MemorySegment _x3) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout Probe$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("Probe")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*Probe)(void *, CFDictionaryRef, io_service_t, SInt32 *) + * } + */ + public static final AddressLayout Probe$layout() { + return Probe$LAYOUT; } - public static VarHandle Probe$VH() { - return constants$42.const$3; + private static final long Probe$OFFSET = 40; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*Probe)(void *, CFDictionaryRef, io_service_t, SInt32 *) + * } + */ + public static final long Probe$offset() { + return Probe$OFFSET; } + /** * Getter for field: - * {@snippet : - * IOReturn (*Probe)(void*,CFDictionaryRef,io_service_t,SInt32*); + * {@snippet lang=c : + * IOReturn (*Probe)(void *, CFDictionaryRef, io_service_t, SInt32 *) * } */ - public static MemorySegment Probe$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$42.const$3.get(seg); + public static MemorySegment Probe(MemorySegment struct) { + return struct.get(Probe$LAYOUT, Probe$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*Probe)(void*,CFDictionaryRef,io_service_t,SInt32*); + * {@snippet lang=c : + * IOReturn (*Probe)(void *, CFDictionaryRef, io_service_t, SInt32 *) * } */ - public static void Probe$set(MemorySegment seg, MemorySegment x) { - constants$42.const$3.set(seg, x); - } - public static MemorySegment Probe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$42.const$3.get(seg.asSlice(index*sizeof())); - } - public static void Probe$set(MemorySegment seg, long index, MemorySegment x) { - constants$42.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static Probe Probe(MemorySegment segment, Arena scope) { - return Probe.ofAddress(Probe$get(segment), scope); + public static void Probe(MemorySegment struct, MemorySegment fieldValue) { + struct.set(Probe$LAYOUT, Probe$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*Start)(void*,CFDictionaryRef,io_service_t); + * {@snippet lang=c : + * IOReturn (*Start)(void *, CFDictionaryRef, io_service_t) * } */ - public interface Start { + public static class Start { + + Start() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1, int _x2); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_INT + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(Start.Function.class, "apply", $DESC); - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, int _x2); - static MemorySegment allocate(Start fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$42.const$5, fi, constants$42.const$4, scope); + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(Start.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); } - static Start ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, int __x2) -> { - try { - return (int)constants$43.const$0.invokeExact(symbol, __x0, __x1, __x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, int _x2) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } } } - public static VarHandle Start$VH() { - return constants$43.const$1; + private static final AddressLayout Start$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("Start")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*Start)(void *, CFDictionaryRef, io_service_t) + * } + */ + public static final AddressLayout Start$layout() { + return Start$LAYOUT; + } + + private static final long Start$OFFSET = 48; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*Start)(void *, CFDictionaryRef, io_service_t) + * } + */ + public static final long Start$offset() { + return Start$OFFSET; } + /** * Getter for field: - * {@snippet : - * IOReturn (*Start)(void*,CFDictionaryRef,io_service_t); + * {@snippet lang=c : + * IOReturn (*Start)(void *, CFDictionaryRef, io_service_t) * } */ - public static MemorySegment Start$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$43.const$1.get(seg); + public static MemorySegment Start(MemorySegment struct) { + return struct.get(Start$LAYOUT, Start$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*Start)(void*,CFDictionaryRef,io_service_t); + * {@snippet lang=c : + * IOReturn (*Start)(void *, CFDictionaryRef, io_service_t) * } */ - public static void Start$set(MemorySegment seg, MemorySegment x) { - constants$43.const$1.set(seg, x); - } - public static MemorySegment Start$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$43.const$1.get(seg.asSlice(index*sizeof())); - } - public static void Start$set(MemorySegment seg, long index, MemorySegment x) { - constants$43.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static Start Start(MemorySegment segment, Arena scope) { - return Start.ofAddress(Start$get(segment), scope); + public static void Start(MemorySegment struct, MemorySegment fieldValue) { + struct.set(Start$LAYOUT, Start$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*Stop)(void*); + * {@snippet lang=c : + * IOReturn (*Stop)(void *) * } */ - public interface Stop { + public static class Stop { + + Stop() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(Stop.Function.class, "apply", $DESC); - int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(Stop fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$43.const$2, fi, constants$5.const$5, scope); + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(Stop.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); } - static Stop ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (int)constants$6.const$1.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } } } - public static VarHandle Stop$VH() { - return constants$43.const$3; + private static final AddressLayout Stop$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("Stop")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*Stop)(void *) + * } + */ + public static final AddressLayout Stop$layout() { + return Stop$LAYOUT; } + + private static final long Stop$OFFSET = 56; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*Stop)(void *) + * } + */ + public static final long Stop$offset() { + return Stop$OFFSET; + } + /** * Getter for field: - * {@snippet : - * IOReturn (*Stop)(void*); + * {@snippet lang=c : + * IOReturn (*Stop)(void *) * } */ - public static MemorySegment Stop$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$43.const$3.get(seg); + public static MemorySegment Stop(MemorySegment struct) { + return struct.get(Stop$LAYOUT, Stop$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*Stop)(void*); + * {@snippet lang=c : + * IOReturn (*Stop)(void *) * } */ - public static void Stop$set(MemorySegment seg, MemorySegment x) { - constants$43.const$3.set(seg, x); + public static void Stop(MemorySegment struct, MemorySegment fieldValue) { + struct.set(Stop$LAYOUT, Stop$OFFSET, fieldValue); } - public static MemorySegment Stop$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$43.const$3.get(seg.asSlice(index*sizeof())); + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); } - public static void Stop$set(MemorySegment seg, long index, MemorySegment x) { - constants$43.const$3.set(seg.asSlice(index*sizeof()), x); + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static Stop Stop(MemorySegment segment, Arena scope) { - return Stop.ofAddress(Stop$get(segment), scope); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } -} + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java index 70b02ae3..9c010236 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java @@ -2,312 +2,699 @@ package net.codecrete.usb.macos.gen.iokit; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; +import java.lang.foreign.*; import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_FLOAT; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -import static java.lang.foreign.ValueLayout.OfByte; -import static java.lang.foreign.ValueLayout.OfDouble; -import static java.lang.foreign.ValueLayout.OfFloat; import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfLong; -import static java.lang.foreign.ValueLayout.OfShort; -public class IOKit { - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfLong C_LONG = JAVA_LONG; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; +public class IOKit { + + IOKit() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + + + // Manually fix. Otherwise, system library will not be found + // static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("IOKit.framework"), LIBRARY_ARENA) + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup("/System/Library/Frameworks/IOKit.framework/IOKit", LIBRARY_ARENA) + .or(SymbolLookup.loaderLookup()) + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; + private static final int kIOUSBFindInterfaceDontCare = (int)65535L; /** - * {@snippet : - * enum .kIOUSBFindInterfaceDontCare = 65535; + * {@snippet lang=c : + * enum enum (unnamed at /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/IOKit.framework/Headers/usb/USB.h:898:1).kIOUSBFindInterfaceDontCare = 65535 * } */ public static int kIOUSBFindInterfaceDontCare() { - return (int)65535L; + return kIOUSBFindInterfaceDontCare; } + private static final int kUSBReEnumerateCaptureDeviceMask = (int)1073741824L; /** - * {@snippet : - * enum .kUSBReEnumerateCaptureDeviceMask = 1073741824; + * {@snippet lang=c : + * enum USBReEnumerateOptions.kUSBReEnumerateCaptureDeviceMask = 1073741824 * } */ public static int kUSBReEnumerateCaptureDeviceMask() { - return (int)1073741824L; + return kUSBReEnumerateCaptureDeviceMask; } + private static final int kUSBReEnumerateReleaseDeviceMask = (int)536870912L; /** - * {@snippet : - * enum .kUSBReEnumerateReleaseDeviceMask = 536870912; + * {@snippet lang=c : + * enum USBReEnumerateOptions.kUSBReEnumerateReleaseDeviceMask = 536870912 * } */ public static int kUSBReEnumerateReleaseDeviceMask() { - return (int)536870912L; + return kUSBReEnumerateReleaseDeviceMask; } - public static MemoryLayout kCFRunLoopDefaultMode$LAYOUT() { - return RuntimeHelper.POINTER; + + private static class kCFRunLoopDefaultMode$constants { + public static final AddressLayout LAYOUT = IOKit.C_POINTER; + public static final MemorySegment SEGMENT = IOKit.findOrThrow("kCFRunLoopDefaultMode").reinterpret(LAYOUT.byteSize()); } - public static VarHandle kCFRunLoopDefaultMode$VH() { - return constants$2.const$1; + + /** + * Layout for variable: + * {@snippet lang=c : + * extern const CFRunLoopMode kCFRunLoopDefaultMode + * } + */ + public static AddressLayout kCFRunLoopDefaultMode$layout() { + return kCFRunLoopDefaultMode$constants.LAYOUT; } - public static MemorySegment kCFRunLoopDefaultMode$SEGMENT() { - return RuntimeHelper.requireNonNull(constants$2.const$2,"kCFRunLoopDefaultMode"); + + /** + * Segment for variable: + * {@snippet lang=c : + * extern const CFRunLoopMode kCFRunLoopDefaultMode + * } + */ + public static MemorySegment kCFRunLoopDefaultMode$segment() { + return kCFRunLoopDefaultMode$constants.SEGMENT; } + /** * Getter for variable: - * {@snippet : - * const CFRunLoopMode kCFRunLoopDefaultMode; + * {@snippet lang=c : + * extern const CFRunLoopMode kCFRunLoopDefaultMode * } */ - public static MemorySegment kCFRunLoopDefaultMode$get() { - return (java.lang.foreign.MemorySegment) constants$2.const$1.get(RuntimeHelper.requireNonNull(constants$2.const$2, "kCFRunLoopDefaultMode")); + public static MemorySegment kCFRunLoopDefaultMode() { + return kCFRunLoopDefaultMode$constants.SEGMENT.get(kCFRunLoopDefaultMode$constants.LAYOUT, 0L); } + /** * Setter for variable: - * {@snippet : - * const CFRunLoopMode kCFRunLoopDefaultMode; + * {@snippet lang=c : + * extern const CFRunLoopMode kCFRunLoopDefaultMode * } */ - public static void kCFRunLoopDefaultMode$set(MemorySegment x) { - constants$2.const$1.set(RuntimeHelper.requireNonNull(constants$2.const$2, "kCFRunLoopDefaultMode"), x); + public static void kCFRunLoopDefaultMode(MemorySegment varValue) { + kCFRunLoopDefaultMode$constants.SEGMENT.set(kCFRunLoopDefaultMode$constants.LAYOUT, 0L, varValue); } - public static MemoryLayout kIOMasterPortDefault$LAYOUT() { - return JAVA_INT; + + private static class kIOMasterPortDefault$constants { + public static final OfInt LAYOUT = IOKit.C_INT; + public static final MemorySegment SEGMENT = IOKit.findOrThrow("kIOMasterPortDefault").reinterpret(LAYOUT.byteSize()); } - public static VarHandle kIOMasterPortDefault$VH() { - return constants$2.const$3; + + /** + * Layout for variable: + * {@snippet lang=c : + * extern const mach_port_t kIOMasterPortDefault + * } + */ + public static OfInt kIOMasterPortDefault$layout() { + return kIOMasterPortDefault$constants.LAYOUT; } - public static MemorySegment kIOMasterPortDefault$SEGMENT() { - return RuntimeHelper.requireNonNull(constants$2.const$4,"kIOMasterPortDefault"); + + /** + * Segment for variable: + * {@snippet lang=c : + * extern const mach_port_t kIOMasterPortDefault + * } + */ + public static MemorySegment kIOMasterPortDefault$segment() { + return kIOMasterPortDefault$constants.SEGMENT; } + /** * Getter for variable: - * {@snippet : - * const mach_port_t kIOMasterPortDefault; + * {@snippet lang=c : + * extern const mach_port_t kIOMasterPortDefault * } */ - public static int kIOMasterPortDefault$get() { - return (int) constants$2.const$3.get(RuntimeHelper.requireNonNull(constants$2.const$4, "kIOMasterPortDefault")); + public static int kIOMasterPortDefault() { + return kIOMasterPortDefault$constants.SEGMENT.get(kIOMasterPortDefault$constants.LAYOUT, 0L); } + /** * Setter for variable: - * {@snippet : - * const mach_port_t kIOMasterPortDefault; + * {@snippet lang=c : + * extern const mach_port_t kIOMasterPortDefault * } */ - public static void kIOMasterPortDefault$set(int x) { - constants$2.const$3.set(RuntimeHelper.requireNonNull(constants$2.const$4, "kIOMasterPortDefault"), x); + public static void kIOMasterPortDefault(int varValue) { + kIOMasterPortDefault$constants.SEGMENT.set(kIOMasterPortDefault$constants.LAYOUT, 0L, varValue); } - public static MethodHandle IONotificationPortCreate$MH() { - return RuntimeHelper.requireNonNull(constants$2.const$6,"IONotificationPortCreate"); + + private static class IONotificationPortCreate { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + IOKit.C_POINTER, + IOKit.C_INT + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + IOKit.findOrThrow("IONotificationPortCreate"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * IONotificationPortRef IONotificationPortCreate(mach_port_t mainPort) + * } + */ + public static FunctionDescriptor IONotificationPortCreate$descriptor() { + return IONotificationPortCreate.DESC; } + /** - * {@snippet : - * IONotificationPortRef IONotificationPortCreate(mach_port_t mainPort); + * Downcall method handle for: + * {@snippet lang=c : + * IONotificationPortRef IONotificationPortCreate(mach_port_t mainPort) + * } + */ + public static MethodHandle IONotificationPortCreate$handle() { + return IONotificationPortCreate.HANDLE; + } + /** + * {@snippet lang=c : + * IONotificationPortRef IONotificationPortCreate(mach_port_t mainPort) * } */ public static MemorySegment IONotificationPortCreate(int mainPort) { - var mh$ = IONotificationPortCreate$MH(); + var mh$ = IONotificationPortCreate.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(mainPort); + if (TRACE_DOWNCALLS) { + traceDowncall("IONotificationPortCreate", mainPort); + } + return (MemorySegment)mh$.invokeExact(mainPort); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle IONotificationPortGetRunLoopSource$MH() { - return RuntimeHelper.requireNonNull(constants$3.const$1,"IONotificationPortGetRunLoopSource"); + + private static class IONotificationPortGetRunLoopSource { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + IOKit.findOrThrow("IONotificationPortGetRunLoopSource"), + DESC); } + /** - * {@snippet : - * CFRunLoopSourceRef IONotificationPortGetRunLoopSource(IONotificationPortRef notify); + * Function descriptor for: + * {@snippet lang=c : + * CFRunLoopSourceRef IONotificationPortGetRunLoopSource(IONotificationPortRef notify) + * } + */ + public static FunctionDescriptor IONotificationPortGetRunLoopSource$descriptor() { + return IONotificationPortGetRunLoopSource.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * CFRunLoopSourceRef IONotificationPortGetRunLoopSource(IONotificationPortRef notify) + * } + */ + public static MethodHandle IONotificationPortGetRunLoopSource$handle() { + return IONotificationPortGetRunLoopSource.HANDLE; + } + /** + * {@snippet lang=c : + * CFRunLoopSourceRef IONotificationPortGetRunLoopSource(IONotificationPortRef notify) * } */ public static MemorySegment IONotificationPortGetRunLoopSource(MemorySegment notify) { - var mh$ = IONotificationPortGetRunLoopSource$MH(); + var mh$ = IONotificationPortGetRunLoopSource.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(notify); + if (TRACE_DOWNCALLS) { + traceDowncall("IONotificationPortGetRunLoopSource", notify); + } + return (MemorySegment)mh$.invokeExact(notify); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle IOObjectRelease$MH() { - return RuntimeHelper.requireNonNull(constants$3.const$3,"IOObjectRelease"); + + private static class IOObjectRelease { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_INT + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + IOKit.findOrThrow("IOObjectRelease"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * kern_return_t IOObjectRelease(io_object_t object) + * } + */ + public static FunctionDescriptor IOObjectRelease$descriptor() { + return IOObjectRelease.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * kern_return_t IOObjectRelease(io_object_t object) + * } + */ + public static MethodHandle IOObjectRelease$handle() { + return IOObjectRelease.HANDLE; } /** - * {@snippet : - * kern_return_t IOObjectRelease(io_object_t object); + * {@snippet lang=c : + * kern_return_t IOObjectRelease(io_object_t object) * } */ public static int IOObjectRelease(int object) { - var mh$ = IOObjectRelease$MH(); + var mh$ = IOObjectRelease.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("IOObjectRelease", object); + } return (int)mh$.invokeExact(object); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle IOIteratorNext$MH() { - return RuntimeHelper.requireNonNull(constants$3.const$4,"IOIteratorNext"); + + private static class IOIteratorNext { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_INT + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + IOKit.findOrThrow("IOIteratorNext"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * io_object_t IOIteratorNext(io_iterator_t iterator) + * } + */ + public static FunctionDescriptor IOIteratorNext$descriptor() { + return IOIteratorNext.DESC; } + /** - * {@snippet : - * io_object_t IOIteratorNext(io_iterator_t iterator); + * Downcall method handle for: + * {@snippet lang=c : + * io_object_t IOIteratorNext(io_iterator_t iterator) + * } + */ + public static MethodHandle IOIteratorNext$handle() { + return IOIteratorNext.HANDLE; + } + /** + * {@snippet lang=c : + * io_object_t IOIteratorNext(io_iterator_t iterator) * } */ public static int IOIteratorNext(int iterator) { - var mh$ = IOIteratorNext$MH(); + var mh$ = IOIteratorNext.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("IOIteratorNext", iterator); + } return (int)mh$.invokeExact(iterator); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle IOServiceAddMatchingNotification$MH() { - return RuntimeHelper.requireNonNull(constants$3.const$6,"IOServiceAddMatchingNotification"); + + private static class IOServiceAddMatchingNotification { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + IOKit.findOrThrow("IOServiceAddMatchingNotification"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * kern_return_t IOServiceAddMatchingNotification(IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void *refCon, io_iterator_t *notification) + * } + */ + public static FunctionDescriptor IOServiceAddMatchingNotification$descriptor() { + return IOServiceAddMatchingNotification.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * kern_return_t IOServiceAddMatchingNotification(IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void *refCon, io_iterator_t *notification) + * } + */ + public static MethodHandle IOServiceAddMatchingNotification$handle() { + return IOServiceAddMatchingNotification.HANDLE; } /** - * {@snippet : - * kern_return_t IOServiceAddMatchingNotification(IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void* refCon, io_iterator_t* notification); + * {@snippet lang=c : + * kern_return_t IOServiceAddMatchingNotification(IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void *refCon, io_iterator_t *notification) * } */ public static int IOServiceAddMatchingNotification(MemorySegment notifyPort, MemorySegment notificationType, MemorySegment matching, MemorySegment callback, MemorySegment refCon, MemorySegment notification) { - var mh$ = IOServiceAddMatchingNotification$MH(); + var mh$ = IOServiceAddMatchingNotification.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("IOServiceAddMatchingNotification", notifyPort, notificationType, matching, callback, refCon, notification); + } return (int)mh$.invokeExact(notifyPort, notificationType, matching, callback, refCon, notification); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle IORegistryEntryGetRegistryEntryID$MH() { - return RuntimeHelper.requireNonNull(constants$4.const$1,"IORegistryEntryGetRegistryEntryID"); + + private static class IORegistryEntryGetRegistryEntryID { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_INT, + IOKit.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + IOKit.findOrThrow("IORegistryEntryGetRegistryEntryID"), + DESC); } + /** - * {@snippet : - * kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t* entryID); + * Function descriptor for: + * {@snippet lang=c : + * kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t *entryID) + * } + */ + public static FunctionDescriptor IORegistryEntryGetRegistryEntryID$descriptor() { + return IORegistryEntryGetRegistryEntryID.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t *entryID) + * } + */ + public static MethodHandle IORegistryEntryGetRegistryEntryID$handle() { + return IORegistryEntryGetRegistryEntryID.HANDLE; + } + /** + * {@snippet lang=c : + * kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t *entryID) * } */ public static int IORegistryEntryGetRegistryEntryID(int entry, MemorySegment entryID) { - var mh$ = IORegistryEntryGetRegistryEntryID$MH(); + var mh$ = IORegistryEntryGetRegistryEntryID.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("IORegistryEntryGetRegistryEntryID", entry, entryID); + } return (int)mh$.invokeExact(entry, entryID); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle IORegistryEntryCreateCFProperty$MH() { - return RuntimeHelper.requireNonNull(constants$4.const$3,"IORegistryEntryCreateCFProperty"); + + private static class IORegistryEntryCreateCFProperty { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + IOKit.C_POINTER, + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_INT + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + IOKit.findOrThrow("IORegistryEntryCreateCFProperty"), + DESC); } + /** - * {@snippet : - * CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options); + * Function descriptor for: + * {@snippet lang=c : + * CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options) + * } + */ + public static FunctionDescriptor IORegistryEntryCreateCFProperty$descriptor() { + return IORegistryEntryCreateCFProperty.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options) + * } + */ + public static MethodHandle IORegistryEntryCreateCFProperty$handle() { + return IORegistryEntryCreateCFProperty.HANDLE; + } + /** + * {@snippet lang=c : + * CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options) * } */ public static MemorySegment IORegistryEntryCreateCFProperty(int entry, MemorySegment key, MemorySegment allocator, int options) { - var mh$ = IORegistryEntryCreateCFProperty$MH(); + var mh$ = IORegistryEntryCreateCFProperty.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(entry, key, allocator, options); + if (TRACE_DOWNCALLS) { + traceDowncall("IORegistryEntryCreateCFProperty", entry, key, allocator, options); + } + return (MemorySegment)mh$.invokeExact(entry, key, allocator, options); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle IOServiceMatching$MH() { - return RuntimeHelper.requireNonNull(constants$4.const$4,"IOServiceMatching"); + + private static class IOServiceMatching { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + IOKit.findOrThrow("IOServiceMatching"), + DESC); } + /** - * {@snippet : - * CFMutableDictionaryRef IOServiceMatching(char* name); + * Function descriptor for: + * {@snippet lang=c : + * CFMutableDictionaryRef IOServiceMatching(const char *name) + * } + */ + public static FunctionDescriptor IOServiceMatching$descriptor() { + return IOServiceMatching.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * CFMutableDictionaryRef IOServiceMatching(const char *name) + * } + */ + public static MethodHandle IOServiceMatching$handle() { + return IOServiceMatching.HANDLE; + } + /** + * {@snippet lang=c : + * CFMutableDictionaryRef IOServiceMatching(const char *name) * } */ public static MemorySegment IOServiceMatching(MemorySegment name) { - var mh$ = IOServiceMatching$MH(); + var mh$ = IOServiceMatching.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(name); + if (TRACE_DOWNCALLS) { + traceDowncall("IOServiceMatching", name); + } + return (MemorySegment)mh$.invokeExact(name); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } - public static MethodHandle IOCreatePlugInInterfaceForService$MH() { - return RuntimeHelper.requireNonNull(constants$43.const$5,"IOCreatePlugInInterfaceForService"); + + private static class IOCreatePlugInInterfaceForService { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + IOKit.findOrThrow("IOCreatePlugInInterfaceForService"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * kern_return_t IOCreatePlugInInterfaceForService(io_service_t service, CFUUIDRef pluginType, CFUUIDRef interfaceType, IOCFPlugInInterface ***theInterface, SInt32 *theScore) + * } + */ + public static FunctionDescriptor IOCreatePlugInInterfaceForService$descriptor() { + return IOCreatePlugInInterfaceForService.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * kern_return_t IOCreatePlugInInterfaceForService(io_service_t service, CFUUIDRef pluginType, CFUUIDRef interfaceType, IOCFPlugInInterface ***theInterface, SInt32 *theScore) + * } + */ + public static MethodHandle IOCreatePlugInInterfaceForService$handle() { + return IOCreatePlugInInterfaceForService.HANDLE; } /** - * {@snippet : - * kern_return_t IOCreatePlugInInterfaceForService(io_service_t service, CFUUIDRef pluginType, CFUUIDRef interfaceType, IOCFPlugInInterface*** theInterface, SInt32* theScore); + * {@snippet lang=c : + * kern_return_t IOCreatePlugInInterfaceForService(io_service_t service, CFUUIDRef pluginType, CFUUIDRef interfaceType, IOCFPlugInInterface ***theInterface, SInt32 *theScore) * } */ public static int IOCreatePlugInInterfaceForService(int service, MemorySegment pluginType, MemorySegment interfaceType, MemorySegment theInterface, MemorySegment theScore) { - var mh$ = IOCreatePlugInInterfaceForService$MH(); + var mh$ = IOCreatePlugInInterfaceForService.HANDLE; try { + if (TRACE_DOWNCALLS) { + traceDowncall("IOCreatePlugInInterfaceForService", service, pluginType, interfaceType, theInterface, theScore); + } return (int)mh$.invokeExact(service, pluginType, interfaceType, theInterface, theScore); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } + private static final int kIOReturnExclusiveAccess = (int)-536870203L; /** - * {@snippet : + * {@snippet lang=c : * #define kIOReturnExclusiveAccess -536870203 * } */ public static int kIOReturnExclusiveAccess() { - return (int)-536870203L; + return kIOReturnExclusiveAccess; } + private static final int kIOReturnAborted = (int)-536870165L; /** - * {@snippet : + * {@snippet lang=c : * #define kIOReturnAborted -536870165 * } */ public static int kIOReturnAborted() { - return (int)-536870165L; + return kIOReturnAborted; } + private static final int kIOUSBPipeStalled = (int)-536854449L; /** - * {@snippet : + * {@snippet lang=c : * #define kIOUSBPipeStalled -536854449 * } */ public static int kIOUSBPipeStalled() { - return (int)-536854449L; + return kIOUSBPipeStalled; } + private static final int kIOUSBTransactionTimeout = (int)-536854447L; /** - * {@snippet : + * {@snippet lang=c : * #define kIOUSBTransactionTimeout -536854447 * } */ public static int kIOUSBTransactionTimeout() { - return (int)-536854447L; + return kIOUSBTransactionTimeout; } /** - * {@snippet : + * {@snippet lang=c : * #define kIOFirstMatchNotification "IOServiceFirstMatch" * } */ public static MemorySegment kIOFirstMatchNotification() { - return constants$44.const$0; + class Holder { + static final MemorySegment kIOFirstMatchNotification + = IOKit.LIBRARY_ARENA.allocateFrom("IOServiceFirstMatch"); + } + return Holder.kIOFirstMatchNotification; } /** - * {@snippet : + * {@snippet lang=c : * #define kIOTerminatedNotification "IOServiceTerminate" * } */ public static MemorySegment kIOTerminatedNotification() { - return constants$44.const$1; + class Holder { + static final MemorySegment kIOTerminatedNotification + = IOKit.LIBRARY_ARENA.allocateFrom("IOServiceTerminate"); + } + return Holder.kIOTerminatedNotification; } /** - * {@snippet : + * {@snippet lang=c : * #define kIOUSBDeviceClassName "IOUSBDevice" * } */ public static MemorySegment kIOUSBDeviceClassName() { - return constants$44.const$2; + class Holder { + static final MemorySegment kIOUSBDeviceClassName + = IOKit.LIBRARY_ARENA.allocateFrom("IOUSBDevice"); + } + return Holder.kIOUSBDeviceClassName; } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOServiceAddMatchingNotification$callback.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOServiceAddMatchingNotification$callback.java new file mode 100644 index 00000000..0987141e --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOServiceAddMatchingNotification$callback.java @@ -0,0 +1,64 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; + +/** + * {@snippet lang=c : + * IOServiceMatchingCallback callback + * } + */ +public class IOServiceAddMatchingNotification$callback { + + IOServiceAddMatchingNotification$callback() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + void apply(MemorySegment _x0, int _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.ofVoid( + IOKit.C_POINTER, + IOKit.C_INT + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(IOServiceAddMatchingNotification$callback.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(IOServiceAddMatchingNotification$callback.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static void invoke(MemorySegment funcPtr,MemorySegment _x0, int _x1) { + try { + DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java index ae3953ce..1e41040a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java @@ -2,224 +2,399 @@ package net.codecrete.usb.macos.gen.iokit; -import java.lang.foreign.Arena; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.lang.foreign.*; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.*; + /** - * {@snippet : + * {@snippet lang=c : * struct { * UInt8 bmRequestType; * UInt8 bRequest; * UInt16 wValue; * UInt16 wIndex; * UInt16 wLength; - * void* pData; + * void *pData; * UInt32 wLenDone; - * }; + * } * } */ public class IOUSBDevRequest { - public static MemoryLayout $LAYOUT() { - return constants$0.const$0; + IOUSBDevRequest() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + IOKit.C_CHAR.withName("bmRequestType"), + IOKit.C_CHAR.withName("bRequest"), + IOKit.C_SHORT.withName("wValue"), + IOKit.C_SHORT.withName("wIndex"), + IOKit.C_SHORT.withName("wLength"), + IOKit.C_POINTER.withName("pData"), + IOKit.C_INT.withName("wLenDone"), + MemoryLayout.paddingLayout(4) + ).withName("IOUSBDevRequest"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } - public static VarHandle bmRequestType$VH() { - return constants$0.const$1; + + private static final OfByte bmRequestType$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bmRequestType")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 bmRequestType + * } + */ + public static final OfByte bmRequestType$layout() { + return bmRequestType$LAYOUT; + } + + private static final long bmRequestType$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 bmRequestType + * } + */ + public static final long bmRequestType$offset() { + return bmRequestType$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 bmRequestType; + * {@snippet lang=c : + * UInt8 bmRequestType * } */ - public static byte bmRequestType$get(MemorySegment seg) { - return (byte)constants$0.const$1.get(seg); + public static byte bmRequestType(MemorySegment struct) { + return struct.get(bmRequestType$LAYOUT, bmRequestType$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 bmRequestType; + * {@snippet lang=c : + * UInt8 bmRequestType * } */ - public static void bmRequestType$set(MemorySegment seg, byte x) { - constants$0.const$1.set(seg, x); + public static void bmRequestType(MemorySegment struct, byte fieldValue) { + struct.set(bmRequestType$LAYOUT, bmRequestType$OFFSET, fieldValue); } - public static byte bmRequestType$get(MemorySegment seg, long index) { - return (byte)constants$0.const$1.get(seg.asSlice(index*sizeof())); - } - public static void bmRequestType$set(MemorySegment seg, long index, byte x) { - constants$0.const$1.set(seg.asSlice(index*sizeof()), x); + + private static final OfByte bRequest$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bRequest")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt8 bRequest + * } + */ + public static final OfByte bRequest$layout() { + return bRequest$LAYOUT; } - public static VarHandle bRequest$VH() { - return constants$0.const$2; + + private static final long bRequest$OFFSET = 1; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt8 bRequest + * } + */ + public static final long bRequest$offset() { + return bRequest$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt8 bRequest; + * {@snippet lang=c : + * UInt8 bRequest * } */ - public static byte bRequest$get(MemorySegment seg) { - return (byte)constants$0.const$2.get(seg); + public static byte bRequest(MemorySegment struct) { + return struct.get(bRequest$LAYOUT, bRequest$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt8 bRequest; + * {@snippet lang=c : + * UInt8 bRequest * } */ - public static void bRequest$set(MemorySegment seg, byte x) { - constants$0.const$2.set(seg, x); + public static void bRequest(MemorySegment struct, byte fieldValue) { + struct.set(bRequest$LAYOUT, bRequest$OFFSET, fieldValue); } - public static byte bRequest$get(MemorySegment seg, long index) { - return (byte)constants$0.const$2.get(seg.asSlice(index*sizeof())); - } - public static void bRequest$set(MemorySegment seg, long index, byte x) { - constants$0.const$2.set(seg.asSlice(index*sizeof()), x); + + private static final OfShort wValue$LAYOUT = (OfShort)$LAYOUT.select(groupElement("wValue")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt16 wValue + * } + */ + public static final OfShort wValue$layout() { + return wValue$LAYOUT; } - public static VarHandle wValue$VH() { - return constants$0.const$3; + + private static final long wValue$OFFSET = 2; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt16 wValue + * } + */ + public static final long wValue$offset() { + return wValue$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt16 wValue; + * {@snippet lang=c : + * UInt16 wValue * } */ - public static short wValue$get(MemorySegment seg) { - return (short)constants$0.const$3.get(seg); + public static short wValue(MemorySegment struct) { + return struct.get(wValue$LAYOUT, wValue$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt16 wValue; + * {@snippet lang=c : + * UInt16 wValue * } */ - public static void wValue$set(MemorySegment seg, short x) { - constants$0.const$3.set(seg, x); + public static void wValue(MemorySegment struct, short fieldValue) { + struct.set(wValue$LAYOUT, wValue$OFFSET, fieldValue); } - public static short wValue$get(MemorySegment seg, long index) { - return (short)constants$0.const$3.get(seg.asSlice(index*sizeof())); - } - public static void wValue$set(MemorySegment seg, long index, short x) { - constants$0.const$3.set(seg.asSlice(index*sizeof()), x); + + private static final OfShort wIndex$LAYOUT = (OfShort)$LAYOUT.select(groupElement("wIndex")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt16 wIndex + * } + */ + public static final OfShort wIndex$layout() { + return wIndex$LAYOUT; } - public static VarHandle wIndex$VH() { - return constants$0.const$4; + + private static final long wIndex$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt16 wIndex + * } + */ + public static final long wIndex$offset() { + return wIndex$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt16 wIndex; + * {@snippet lang=c : + * UInt16 wIndex * } */ - public static short wIndex$get(MemorySegment seg) { - return (short)constants$0.const$4.get(seg); + public static short wIndex(MemorySegment struct) { + return struct.get(wIndex$LAYOUT, wIndex$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt16 wIndex; + * {@snippet lang=c : + * UInt16 wIndex * } */ - public static void wIndex$set(MemorySegment seg, short x) { - constants$0.const$4.set(seg, x); + public static void wIndex(MemorySegment struct, short fieldValue) { + struct.set(wIndex$LAYOUT, wIndex$OFFSET, fieldValue); } - public static short wIndex$get(MemorySegment seg, long index) { - return (short)constants$0.const$4.get(seg.asSlice(index*sizeof())); - } - public static void wIndex$set(MemorySegment seg, long index, short x) { - constants$0.const$4.set(seg.asSlice(index*sizeof()), x); + + private static final OfShort wLength$LAYOUT = (OfShort)$LAYOUT.select(groupElement("wLength")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt16 wLength + * } + */ + public static final OfShort wLength$layout() { + return wLength$LAYOUT; } - public static VarHandle wLength$VH() { - return constants$0.const$5; + + private static final long wLength$OFFSET = 6; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt16 wLength + * } + */ + public static final long wLength$offset() { + return wLength$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt16 wLength; + * {@snippet lang=c : + * UInt16 wLength * } */ - public static short wLength$get(MemorySegment seg) { - return (short)constants$0.const$5.get(seg); + public static short wLength(MemorySegment struct) { + return struct.get(wLength$LAYOUT, wLength$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt16 wLength; + * {@snippet lang=c : + * UInt16 wLength * } */ - public static void wLength$set(MemorySegment seg, short x) { - constants$0.const$5.set(seg, x); - } - public static short wLength$get(MemorySegment seg, long index) { - return (short)constants$0.const$5.get(seg.asSlice(index*sizeof())); + public static void wLength(MemorySegment struct, short fieldValue) { + struct.set(wLength$LAYOUT, wLength$OFFSET, fieldValue); } - public static void wLength$set(MemorySegment seg, long index, short x) { - constants$0.const$5.set(seg.asSlice(index*sizeof()), x); + + private static final AddressLayout pData$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("pData")); + + /** + * Layout for field: + * {@snippet lang=c : + * void *pData + * } + */ + public static final AddressLayout pData$layout() { + return pData$LAYOUT; } - public static VarHandle pData$VH() { - return constants$1.const$0; + + private static final long pData$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * void *pData + * } + */ + public static final long pData$offset() { + return pData$OFFSET; } + /** * Getter for field: - * {@snippet : - * void* pData; + * {@snippet lang=c : + * void *pData * } */ - public static MemorySegment pData$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$1.const$0.get(seg); + public static MemorySegment pData(MemorySegment struct) { + return struct.get(pData$LAYOUT, pData$OFFSET); } + /** * Setter for field: - * {@snippet : - * void* pData; + * {@snippet lang=c : + * void *pData * } */ - public static void pData$set(MemorySegment seg, MemorySegment x) { - constants$1.const$0.set(seg, x); - } - public static MemorySegment pData$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$1.const$0.get(seg.asSlice(index*sizeof())); + public static void pData(MemorySegment struct, MemorySegment fieldValue) { + struct.set(pData$LAYOUT, pData$OFFSET, fieldValue); } - public static void pData$set(MemorySegment seg, long index, MemorySegment x) { - constants$1.const$0.set(seg.asSlice(index*sizeof()), x); + + private static final OfInt wLenDone$LAYOUT = (OfInt)$LAYOUT.select(groupElement("wLenDone")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt32 wLenDone + * } + */ + public static final OfInt wLenDone$layout() { + return wLenDone$LAYOUT; } - public static VarHandle wLenDone$VH() { - return constants$1.const$1; + + private static final long wLenDone$OFFSET = 16; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt32 wLenDone + * } + */ + public static final long wLenDone$offset() { + return wLenDone$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt32 wLenDone; + * {@snippet lang=c : + * UInt32 wLenDone * } */ - public static int wLenDone$get(MemorySegment seg) { - return (int)constants$1.const$1.get(seg); + public static int wLenDone(MemorySegment struct) { + return struct.get(wLenDone$LAYOUT, wLenDone$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt32 wLenDone; + * {@snippet lang=c : + * UInt32 wLenDone * } */ - public static void wLenDone$set(MemorySegment seg, int x) { - constants$1.const$1.set(seg, x); + public static void wLenDone(MemorySegment struct, int fieldValue) { + struct.set(wLenDone$LAYOUT, wLenDone$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static int wLenDone$get(MemorySegment seg, long index) { - return (int)constants$1.const$1.get(seg.asSlice(index*sizeof())); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static void wLenDone$set(MemorySegment seg, long index, int x) { - constants$1.const$1.set(seg.asSlice(index*sizeof()), x); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface187.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface187.java index be0be089..739a592d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface187.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface187.java @@ -3,14 +3,53 @@ package net.codecrete.usb.macos.gen.iokit; /** - * {@snippet : - * typedef struct IOUSBDeviceStruct187 IOUSBDeviceInterface187; + * {@snippet lang=c : + * typedef struct IOUSBDeviceStruct187 { + * void *_reserved; + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *); + * ULONG (*AddRef)(void *); + * ULONG (*Release)(void *); + * IOReturn (*CreateDeviceAsyncEventSource)(void *, CFRunLoopSourceRef *); + * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void *); + * IOReturn (*CreateDeviceAsyncPort)(void *, mach_port_t *); + * mach_port_t (*GetDeviceAsyncPort)(void *); + * IOReturn (*USBDeviceOpen)(void *); + * IOReturn (*USBDeviceClose)(void *); + * IOReturn (*GetDeviceClass)(void *, UInt8 *); + * IOReturn (*GetDeviceSubClass)(void *, UInt8 *); + * IOReturn (*GetDeviceProtocol)(void *, UInt8 *); + * IOReturn (*GetDeviceVendor)(void *, UInt16 *); + * IOReturn (*GetDeviceProduct)(void *, UInt16 *); + * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *); + * IOReturn (*GetDeviceAddress)(void *, USBDeviceAddress *); + * IOReturn (*GetDeviceBusPowerAvailable)(void *, UInt32 *); + * IOReturn (*GetDeviceSpeed)(void *, UInt8 *); + * IOReturn (*GetNumberOfConfigurations)(void *, UInt8 *); + * IOReturn (*GetLocationID)(void *, UInt32 *); + * IOReturn (*GetConfigurationDescriptorPtr)(void *, UInt8, IOUSBConfigurationDescriptorPtr *); + * IOReturn (*GetConfiguration)(void *, UInt8 *); + * IOReturn (*SetConfiguration)(void *, UInt8); + * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *); + * IOReturn (*ResetDevice)(void *); + * IOReturn (*DeviceRequest)(void *, IOUSBDevRequest *); + * IOReturn (*DeviceRequestAsync)(void *, IOUSBDevRequest *, IOAsyncCallback1, void *); + * IOReturn (*CreateInterfaceIterator)(void *, IOUSBFindInterfaceRequest *, io_iterator_t *); + * IOReturn (*USBDeviceOpenSeize)(void *); + * IOReturn (*DeviceRequestTO)(void *, IOUSBDevRequestTO *); + * IOReturn (*DeviceRequestAsyncTO)(void *, IOUSBDevRequestTO *, IOAsyncCallback1, void *); + * IOReturn (*USBDeviceSuspend)(void *, Boolean); + * IOReturn (*USBDeviceAbortPipeZero)(void *); + * IOReturn (*USBGetManufacturerStringIndex)(void *, UInt8 *); + * IOReturn (*USBGetProductStringIndex)(void *, UInt8 *); + * IOReturn (*USBGetSerialNumberStringIndex)(void *, UInt8 *); + * IOReturn (*USBDeviceReEnumerate)(void *, UInt32); + * } IOUSBDeviceInterface187 * } */ -public final class IOUSBDeviceInterface187 extends IOUSBDeviceStruct187 { +public class IOUSBDeviceInterface187 extends IOUSBDeviceStruct187 { - // Suppresses default constructor, ensuring non-instantiability. - private IOUSBDeviceInterface187() {} + IOUSBDeviceInterface187() { + // Should not be called directly + } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java index ad8d79c2..46b5d14c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java @@ -2,2054 +2,3858 @@ package net.codecrete.usb.macos.gen.iokit; -import java.lang.foreign.Arena; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; + /** - * {@snippet : + * {@snippet lang=c : * struct IOUSBDeviceStruct187 { - * void* _reserved; - * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); - * ULONG (*AddRef)(void*); - * ULONG (*Release)(void*); - * IOReturn (*CreateDeviceAsyncEventSource)(void*,CFRunLoopSourceRef*); - * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void*); - * IOReturn (*CreateDeviceAsyncPort)(void*,mach_port_t*); - * mach_port_t (*GetDeviceAsyncPort)(void*); - * IOReturn (*USBDeviceOpen)(void*); - * IOReturn (*USBDeviceClose)(void*); - * IOReturn (*GetDeviceClass)(void*,UInt8*); - * IOReturn (*GetDeviceSubClass)(void*,UInt8*); - * IOReturn (*GetDeviceProtocol)(void*,UInt8*); - * IOReturn (*GetDeviceVendor)(void*,UInt16*); - * IOReturn (*GetDeviceProduct)(void*,UInt16*); - * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); - * IOReturn (*GetDeviceAddress)(void*,USBDeviceAddress*); - * IOReturn (*GetDeviceBusPowerAvailable)(void*,UInt32*); - * IOReturn (*GetDeviceSpeed)(void*,UInt8*); - * IOReturn (*GetNumberOfConfigurations)(void*,UInt8*); - * IOReturn (*GetLocationID)(void*,UInt32*); - * IOReturn (*GetConfigurationDescriptorPtr)(void*,UInt8,IOUSBConfigurationDescriptorPtr*); - * IOReturn (*GetConfiguration)(void*,UInt8*); - * IOReturn (*SetConfiguration)(void*,UInt8); - * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); - * IOReturn (*ResetDevice)(void*); - * IOReturn (*DeviceRequest)(void*,IOUSBDevRequest*); - * IOReturn (*DeviceRequestAsync)(void*,IOUSBDevRequest*,IOAsyncCallback1,void*); - * IOReturn (*CreateInterfaceIterator)(void*,IOUSBFindInterfaceRequest*,io_iterator_t*); - * IOReturn (*USBDeviceOpenSeize)(void*); - * IOReturn (*DeviceRequestTO)(void*,IOUSBDevRequestTO*); - * IOReturn (*DeviceRequestAsyncTO)(void*,IOUSBDevRequestTO*,IOAsyncCallback1,void*); - * IOReturn (*USBDeviceSuspend)(void*,Boolean); - * IOReturn (*USBDeviceAbortPipeZero)(void*); - * IOReturn (*USBGetManufacturerStringIndex)(void*,UInt8*); - * IOReturn (*USBGetProductStringIndex)(void*,UInt8*); - * IOReturn (*USBGetSerialNumberStringIndex)(void*,UInt8*); - * IOReturn (*USBDeviceReEnumerate)(void*,UInt32); - * }; + * void *_reserved; + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *); + * ULONG (*AddRef)(void *); + * ULONG (*Release)(void *); + * IOReturn (*CreateDeviceAsyncEventSource)(void *, CFRunLoopSourceRef *); + * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void *); + * IOReturn (*CreateDeviceAsyncPort)(void *, mach_port_t *); + * mach_port_t (*GetDeviceAsyncPort)(void *); + * IOReturn (*USBDeviceOpen)(void *); + * IOReturn (*USBDeviceClose)(void *); + * IOReturn (*GetDeviceClass)(void *, UInt8 *); + * IOReturn (*GetDeviceSubClass)(void *, UInt8 *); + * IOReturn (*GetDeviceProtocol)(void *, UInt8 *); + * IOReturn (*GetDeviceVendor)(void *, UInt16 *); + * IOReturn (*GetDeviceProduct)(void *, UInt16 *); + * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *); + * IOReturn (*GetDeviceAddress)(void *, USBDeviceAddress *); + * IOReturn (*GetDeviceBusPowerAvailable)(void *, UInt32 *); + * IOReturn (*GetDeviceSpeed)(void *, UInt8 *); + * IOReturn (*GetNumberOfConfigurations)(void *, UInt8 *); + * IOReturn (*GetLocationID)(void *, UInt32 *); + * IOReturn (*GetConfigurationDescriptorPtr)(void *, UInt8, IOUSBConfigurationDescriptorPtr *); + * IOReturn (*GetConfiguration)(void *, UInt8 *); + * IOReturn (*SetConfiguration)(void *, UInt8); + * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *); + * IOReturn (*ResetDevice)(void *); + * IOReturn (*DeviceRequest)(void *, IOUSBDevRequest *); + * IOReturn (*DeviceRequestAsync)(void *, IOUSBDevRequest *, IOAsyncCallback1, void *); + * IOReturn (*CreateInterfaceIterator)(void *, IOUSBFindInterfaceRequest *, io_iterator_t *); + * IOReturn (*USBDeviceOpenSeize)(void *); + * IOReturn (*DeviceRequestTO)(void *, IOUSBDevRequestTO *); + * IOReturn (*DeviceRequestAsyncTO)(void *, IOUSBDevRequestTO *, IOAsyncCallback1, void *); + * IOReturn (*USBDeviceSuspend)(void *, Boolean); + * IOReturn (*USBDeviceAbortPipeZero)(void *); + * IOReturn (*USBGetManufacturerStringIndex)(void *, UInt8 *); + * IOReturn (*USBGetProductStringIndex)(void *, UInt8 *); + * IOReturn (*USBGetSerialNumberStringIndex)(void *, UInt8 *); + * IOReturn (*USBDeviceReEnumerate)(void *, UInt32); + * } * } */ public class IOUSBDeviceStruct187 { - public static MemoryLayout $LAYOUT() { - return constants$4.const$5; - } - public static VarHandle _reserved$VH() { - return constants$5.const$0; + IOUSBDeviceStruct187() { + // Should not be called directly } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + IOKit.C_POINTER.withName("_reserved"), + IOKit.C_POINTER.withName("QueryInterface"), + IOKit.C_POINTER.withName("AddRef"), + IOKit.C_POINTER.withName("Release"), + IOKit.C_POINTER.withName("CreateDeviceAsyncEventSource"), + IOKit.C_POINTER.withName("GetDeviceAsyncEventSource"), + IOKit.C_POINTER.withName("CreateDeviceAsyncPort"), + IOKit.C_POINTER.withName("GetDeviceAsyncPort"), + IOKit.C_POINTER.withName("USBDeviceOpen"), + IOKit.C_POINTER.withName("USBDeviceClose"), + IOKit.C_POINTER.withName("GetDeviceClass"), + IOKit.C_POINTER.withName("GetDeviceSubClass"), + IOKit.C_POINTER.withName("GetDeviceProtocol"), + IOKit.C_POINTER.withName("GetDeviceVendor"), + IOKit.C_POINTER.withName("GetDeviceProduct"), + IOKit.C_POINTER.withName("GetDeviceReleaseNumber"), + IOKit.C_POINTER.withName("GetDeviceAddress"), + IOKit.C_POINTER.withName("GetDeviceBusPowerAvailable"), + IOKit.C_POINTER.withName("GetDeviceSpeed"), + IOKit.C_POINTER.withName("GetNumberOfConfigurations"), + IOKit.C_POINTER.withName("GetLocationID"), + IOKit.C_POINTER.withName("GetConfigurationDescriptorPtr"), + IOKit.C_POINTER.withName("GetConfiguration"), + IOKit.C_POINTER.withName("SetConfiguration"), + IOKit.C_POINTER.withName("GetBusFrameNumber"), + IOKit.C_POINTER.withName("ResetDevice"), + IOKit.C_POINTER.withName("DeviceRequest"), + IOKit.C_POINTER.withName("DeviceRequestAsync"), + IOKit.C_POINTER.withName("CreateInterfaceIterator"), + IOKit.C_POINTER.withName("USBDeviceOpenSeize"), + IOKit.C_POINTER.withName("DeviceRequestTO"), + IOKit.C_POINTER.withName("DeviceRequestAsyncTO"), + IOKit.C_POINTER.withName("USBDeviceSuspend"), + IOKit.C_POINTER.withName("USBDeviceAbortPipeZero"), + IOKit.C_POINTER.withName("USBGetManufacturerStringIndex"), + IOKit.C_POINTER.withName("USBGetProductStringIndex"), + IOKit.C_POINTER.withName("USBGetSerialNumberStringIndex"), + IOKit.C_POINTER.withName("USBDeviceReEnumerate") + ).withName("IOUSBDeviceStruct187"); + /** - * Getter for field: - * {@snippet : - * void* _reserved; - * } + * The layout of this struct */ - public static MemorySegment _reserved$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$5.const$0.get(seg); + public static final GroupLayout layout() { + return $LAYOUT; } + + private static final AddressLayout _reserved$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("_reserved")); + /** - * Setter for field: - * {@snippet : - * void* _reserved; + * Layout for field: + * {@snippet lang=c : + * void *_reserved * } */ - public static void _reserved$set(MemorySegment seg, MemorySegment x) { - constants$5.const$0.set(seg, x); - } - public static MemorySegment _reserved$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$5.const$0.get(seg.asSlice(index*sizeof())); - } - public static void _reserved$set(MemorySegment seg, long index, MemorySegment x) { - constants$5.const$0.set(seg.asSlice(index*sizeof()), x); + public static final AddressLayout _reserved$layout() { + return _reserved$LAYOUT; } + + private static final long _reserved$OFFSET = 0; + /** - * {@snippet : - * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * Offset for field: + * {@snippet lang=c : + * void *_reserved * } */ - public interface QueryInterface { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(QueryInterface fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$5.const$2, fi, constants$5.const$1, scope); - } - static QueryInterface ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { - try { - return (int)constants$5.const$3.invokeExact(symbol, __x0, __x1, __x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long _reserved$offset() { + return _reserved$OFFSET; } - public static VarHandle QueryInterface$VH() { - return constants$5.const$4; - } /** * Getter for field: - * {@snippet : - * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * {@snippet lang=c : + * void *_reserved * } */ - public static MemorySegment QueryInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$5.const$4.get(seg); + public static MemorySegment _reserved(MemorySegment struct) { + return struct.get(_reserved$LAYOUT, _reserved$OFFSET); } + /** * Setter for field: - * {@snippet : - * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * {@snippet lang=c : + * void *_reserved * } */ - public static void QueryInterface$set(MemorySegment seg, MemorySegment x) { - constants$5.const$4.set(seg, x); - } - public static MemorySegment QueryInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$5.const$4.get(seg.asSlice(index*sizeof())); - } - public static void QueryInterface$set(MemorySegment seg, long index, MemorySegment x) { - constants$5.const$4.set(seg.asSlice(index*sizeof()), x); - } - public static QueryInterface QueryInterface(MemorySegment segment, Arena scope) { - return QueryInterface.ofAddress(QueryInterface$get(segment), scope); + public static void _reserved(MemorySegment struct, MemorySegment fieldValue) { + struct.set(_reserved$LAYOUT, _reserved$OFFSET, fieldValue); } + /** - * {@snippet : - * ULONG (*AddRef)(void*); + * {@snippet lang=c : + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) * } */ - public interface AddRef { + public static class QueryInterface { - int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(AddRef fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$6.const$0, fi, constants$5.const$5, scope); + QueryInterface() { + // Should not be called directly } - static AddRef ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (int)constants$6.const$1.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1, MemorySegment _x2); } - } - public static VarHandle AddRef$VH() { - return constants$6.const$2; - } - /** - * Getter for field: - * {@snippet : - * ULONG (*AddRef)(void*); - * } - */ - public static MemorySegment AddRef$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$6.const$2.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + CFUUIDBytes.layout(), + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(QueryInterface.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(QueryInterface.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout QueryInterface$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("QueryInterface")); + /** - * Setter for field: - * {@snippet : - * ULONG (*AddRef)(void*); + * Layout for field: + * {@snippet lang=c : + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) * } */ - public static void AddRef$set(MemorySegment seg, MemorySegment x) { - constants$6.const$2.set(seg, x); - } - public static MemorySegment AddRef$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$6.const$2.get(seg.asSlice(index*sizeof())); - } - public static void AddRef$set(MemorySegment seg, long index, MemorySegment x) { - constants$6.const$2.set(seg.asSlice(index*sizeof()), x); - } - public static AddRef AddRef(MemorySegment segment, Arena scope) { - return AddRef.ofAddress(AddRef$get(segment), scope); + public static final AddressLayout QueryInterface$layout() { + return QueryInterface$LAYOUT; } + + private static final long QueryInterface$OFFSET = 8; + /** - * {@snippet : - * ULONG (*Release)(void*); + * Offset for field: + * {@snippet lang=c : + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) * } */ - public interface Release { - - int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(Release fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$6.const$3, fi, constants$5.const$5, scope); - } - static Release ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (int)constants$6.const$1.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long QueryInterface$offset() { + return QueryInterface$OFFSET; } - public static VarHandle Release$VH() { - return constants$6.const$4; - } /** * Getter for field: - * {@snippet : - * ULONG (*Release)(void*); + * {@snippet lang=c : + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) * } */ - public static MemorySegment Release$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$6.const$4.get(seg); + public static MemorySegment QueryInterface(MemorySegment struct) { + return struct.get(QueryInterface$LAYOUT, QueryInterface$OFFSET); } + /** * Setter for field: - * {@snippet : - * ULONG (*Release)(void*); + * {@snippet lang=c : + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) * } */ - public static void Release$set(MemorySegment seg, MemorySegment x) { - constants$6.const$4.set(seg, x); - } - public static MemorySegment Release$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$6.const$4.get(seg.asSlice(index*sizeof())); - } - public static void Release$set(MemorySegment seg, long index, MemorySegment x) { - constants$6.const$4.set(seg.asSlice(index*sizeof()), x); - } - public static Release Release(MemorySegment segment, Arena scope) { - return Release.ofAddress(Release$get(segment), scope); + public static void QueryInterface(MemorySegment struct, MemorySegment fieldValue) { + struct.set(QueryInterface$LAYOUT, QueryInterface$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*CreateDeviceAsyncEventSource)(void*,CFRunLoopSourceRef*); + * {@snippet lang=c : + * ULONG (*AddRef)(void *) * } */ - public interface CreateDeviceAsyncEventSource { + public static class AddRef { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(CreateDeviceAsyncEventSource fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$7.const$0, fi, constants$6.const$5, scope); + AddRef() { + // Should not be called directly } - static CreateDeviceAsyncEventSource ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0); } - } - public static VarHandle CreateDeviceAsyncEventSource$VH() { - return constants$7.const$2; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*CreateDeviceAsyncEventSource)(void*,CFRunLoopSourceRef*); - * } - */ - public static MemorySegment CreateDeviceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$7.const$2.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(AddRef.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(AddRef.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout AddRef$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("AddRef")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*CreateDeviceAsyncEventSource)(void*,CFRunLoopSourceRef*); + * Layout for field: + * {@snippet lang=c : + * ULONG (*AddRef)(void *) * } */ - public static void CreateDeviceAsyncEventSource$set(MemorySegment seg, MemorySegment x) { - constants$7.const$2.set(seg, x); - } - public static MemorySegment CreateDeviceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$7.const$2.get(seg.asSlice(index*sizeof())); - } - public static void CreateDeviceAsyncEventSource$set(MemorySegment seg, long index, MemorySegment x) { - constants$7.const$2.set(seg.asSlice(index*sizeof()), x); - } - public static CreateDeviceAsyncEventSource CreateDeviceAsyncEventSource(MemorySegment segment, Arena scope) { - return CreateDeviceAsyncEventSource.ofAddress(CreateDeviceAsyncEventSource$get(segment), scope); + public static final AddressLayout AddRef$layout() { + return AddRef$LAYOUT; } + + private static final long AddRef$OFFSET = 16; + /** - * {@snippet : - * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void*); + * Offset for field: + * {@snippet lang=c : + * ULONG (*AddRef)(void *) * } */ - public interface GetDeviceAsyncEventSource { - - java.lang.foreign.MemorySegment apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(GetDeviceAsyncEventSource fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$7.const$3, fi, constants$3.const$0, scope); - } - static GetDeviceAsyncEventSource ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (java.lang.foreign.MemorySegment)constants$7.const$4.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long AddRef$offset() { + return AddRef$OFFSET; } - public static VarHandle GetDeviceAsyncEventSource$VH() { - return constants$7.const$5; - } /** * Getter for field: - * {@snippet : - * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void*); + * {@snippet lang=c : + * ULONG (*AddRef)(void *) * } */ - public static MemorySegment GetDeviceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$7.const$5.get(seg); + public static MemorySegment AddRef(MemorySegment struct) { + return struct.get(AddRef$LAYOUT, AddRef$OFFSET); } + /** * Setter for field: - * {@snippet : - * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void*); + * {@snippet lang=c : + * ULONG (*AddRef)(void *) * } */ - public static void GetDeviceAsyncEventSource$set(MemorySegment seg, MemorySegment x) { - constants$7.const$5.set(seg, x); - } - public static MemorySegment GetDeviceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$7.const$5.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceAsyncEventSource$set(MemorySegment seg, long index, MemorySegment x) { - constants$7.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceAsyncEventSource GetDeviceAsyncEventSource(MemorySegment segment, Arena scope) { - return GetDeviceAsyncEventSource.ofAddress(GetDeviceAsyncEventSource$get(segment), scope); + public static void AddRef(MemorySegment struct, MemorySegment fieldValue) { + struct.set(AddRef$LAYOUT, AddRef$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*CreateDeviceAsyncPort)(void*,mach_port_t*); + * {@snippet lang=c : + * ULONG (*Release)(void *) * } */ - public interface CreateDeviceAsyncPort { + public static class Release { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(CreateDeviceAsyncPort fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$8.const$0, fi, constants$6.const$5, scope); + Release() { + // Should not be called directly } - static CreateDeviceAsyncPort ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0); } - } - public static VarHandle CreateDeviceAsyncPort$VH() { - return constants$8.const$1; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*CreateDeviceAsyncPort)(void*,mach_port_t*); - * } - */ - public static MemorySegment CreateDeviceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$8.const$1.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(Release.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(Release.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout Release$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("Release")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*CreateDeviceAsyncPort)(void*,mach_port_t*); + * Layout for field: + * {@snippet lang=c : + * ULONG (*Release)(void *) * } */ - public static void CreateDeviceAsyncPort$set(MemorySegment seg, MemorySegment x) { - constants$8.const$1.set(seg, x); - } - public static MemorySegment CreateDeviceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$8.const$1.get(seg.asSlice(index*sizeof())); - } - public static void CreateDeviceAsyncPort$set(MemorySegment seg, long index, MemorySegment x) { - constants$8.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static CreateDeviceAsyncPort CreateDeviceAsyncPort(MemorySegment segment, Arena scope) { - return CreateDeviceAsyncPort.ofAddress(CreateDeviceAsyncPort$get(segment), scope); + public static final AddressLayout Release$layout() { + return Release$LAYOUT; } + + private static final long Release$OFFSET = 24; + /** - * {@snippet : - * mach_port_t (*GetDeviceAsyncPort)(void*); + * Offset for field: + * {@snippet lang=c : + * ULONG (*Release)(void *) * } */ - public interface GetDeviceAsyncPort { - - int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(GetDeviceAsyncPort fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$8.const$2, fi, constants$5.const$5, scope); - } - static GetDeviceAsyncPort ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (int)constants$6.const$1.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long Release$offset() { + return Release$OFFSET; } - public static VarHandle GetDeviceAsyncPort$VH() { - return constants$8.const$3; - } /** * Getter for field: - * {@snippet : - * mach_port_t (*GetDeviceAsyncPort)(void*); + * {@snippet lang=c : + * ULONG (*Release)(void *) * } */ - public static MemorySegment GetDeviceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$8.const$3.get(seg); + public static MemorySegment Release(MemorySegment struct) { + return struct.get(Release$LAYOUT, Release$OFFSET); } + /** * Setter for field: - * {@snippet : - * mach_port_t (*GetDeviceAsyncPort)(void*); + * {@snippet lang=c : + * ULONG (*Release)(void *) * } */ - public static void GetDeviceAsyncPort$set(MemorySegment seg, MemorySegment x) { - constants$8.const$3.set(seg, x); - } - public static MemorySegment GetDeviceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$8.const$3.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceAsyncPort$set(MemorySegment seg, long index, MemorySegment x) { - constants$8.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceAsyncPort GetDeviceAsyncPort(MemorySegment segment, Arena scope) { - return GetDeviceAsyncPort.ofAddress(GetDeviceAsyncPort$get(segment), scope); + public static void Release(MemorySegment struct, MemorySegment fieldValue) { + struct.set(Release$LAYOUT, Release$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*USBDeviceOpen)(void*); + * {@snippet lang=c : + * IOReturn (*CreateDeviceAsyncEventSource)(void *, CFRunLoopSourceRef *) * } */ - public interface USBDeviceOpen { + public static class CreateDeviceAsyncEventSource { - int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(USBDeviceOpen fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$8.const$4, fi, constants$5.const$5, scope); + CreateDeviceAsyncEventSource() { + // Should not be called directly } - static USBDeviceOpen ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (int)constants$6.const$1.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - } - public static VarHandle USBDeviceOpen$VH() { - return constants$8.const$5; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*USBDeviceOpen)(void*); - * } - */ - public static MemorySegment USBDeviceOpen$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$8.const$5.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(CreateDeviceAsyncEventSource.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(CreateDeviceAsyncEventSource.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout CreateDeviceAsyncEventSource$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("CreateDeviceAsyncEventSource")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*USBDeviceOpen)(void*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*CreateDeviceAsyncEventSource)(void *, CFRunLoopSourceRef *) * } */ - public static void USBDeviceOpen$set(MemorySegment seg, MemorySegment x) { - constants$8.const$5.set(seg, x); - } - public static MemorySegment USBDeviceOpen$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$8.const$5.get(seg.asSlice(index*sizeof())); - } - public static void USBDeviceOpen$set(MemorySegment seg, long index, MemorySegment x) { - constants$8.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static USBDeviceOpen USBDeviceOpen(MemorySegment segment, Arena scope) { - return USBDeviceOpen.ofAddress(USBDeviceOpen$get(segment), scope); + public static final AddressLayout CreateDeviceAsyncEventSource$layout() { + return CreateDeviceAsyncEventSource$LAYOUT; } + + private static final long CreateDeviceAsyncEventSource$OFFSET = 32; + /** - * {@snippet : - * IOReturn (*USBDeviceClose)(void*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*CreateDeviceAsyncEventSource)(void *, CFRunLoopSourceRef *) * } */ - public interface USBDeviceClose { - - int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(USBDeviceClose fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$9.const$0, fi, constants$5.const$5, scope); - } - static USBDeviceClose ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (int)constants$6.const$1.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long CreateDeviceAsyncEventSource$offset() { + return CreateDeviceAsyncEventSource$OFFSET; } - public static VarHandle USBDeviceClose$VH() { - return constants$9.const$1; - } /** * Getter for field: - * {@snippet : - * IOReturn (*USBDeviceClose)(void*); + * {@snippet lang=c : + * IOReturn (*CreateDeviceAsyncEventSource)(void *, CFRunLoopSourceRef *) * } */ - public static MemorySegment USBDeviceClose$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$9.const$1.get(seg); + public static MemorySegment CreateDeviceAsyncEventSource(MemorySegment struct) { + return struct.get(CreateDeviceAsyncEventSource$LAYOUT, CreateDeviceAsyncEventSource$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*USBDeviceClose)(void*); + * {@snippet lang=c : + * IOReturn (*CreateDeviceAsyncEventSource)(void *, CFRunLoopSourceRef *) * } */ - public static void USBDeviceClose$set(MemorySegment seg, MemorySegment x) { - constants$9.const$1.set(seg, x); - } - public static MemorySegment USBDeviceClose$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$9.const$1.get(seg.asSlice(index*sizeof())); - } - public static void USBDeviceClose$set(MemorySegment seg, long index, MemorySegment x) { - constants$9.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static USBDeviceClose USBDeviceClose(MemorySegment segment, Arena scope) { - return USBDeviceClose.ofAddress(USBDeviceClose$get(segment), scope); + public static void CreateDeviceAsyncEventSource(MemorySegment struct, MemorySegment fieldValue) { + struct.set(CreateDeviceAsyncEventSource$LAYOUT, CreateDeviceAsyncEventSource$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*GetDeviceClass)(void*,UInt8*); + * {@snippet lang=c : + * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void *) * } */ - public interface GetDeviceClass { + public static class GetDeviceAsyncEventSource { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceClass fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$9.const$2, fi, constants$6.const$5, scope); + GetDeviceAsyncEventSource() { + // Should not be called directly } - static GetDeviceClass ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + MemorySegment apply(MemorySegment _x0); } - } - public static VarHandle GetDeviceClass$VH() { - return constants$9.const$3; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*GetDeviceClass)(void*,UInt8*); - * } - */ - public static MemorySegment GetDeviceClass$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$9.const$3.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceAsyncEventSource.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetDeviceAsyncEventSource.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static MemorySegment invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (MemorySegment) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout GetDeviceAsyncEventSource$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetDeviceAsyncEventSource")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*GetDeviceClass)(void*,UInt8*); + * Layout for field: + * {@snippet lang=c : + * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void *) * } */ - public static void GetDeviceClass$set(MemorySegment seg, MemorySegment x) { - constants$9.const$3.set(seg, x); - } - public static MemorySegment GetDeviceClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$9.const$3.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceClass$set(MemorySegment seg, long index, MemorySegment x) { - constants$9.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceClass GetDeviceClass(MemorySegment segment, Arena scope) { - return GetDeviceClass.ofAddress(GetDeviceClass$get(segment), scope); + public static final AddressLayout GetDeviceAsyncEventSource$layout() { + return GetDeviceAsyncEventSource$LAYOUT; } + + private static final long GetDeviceAsyncEventSource$OFFSET = 40; + /** - * {@snippet : - * IOReturn (*GetDeviceSubClass)(void*,UInt8*); + * Offset for field: + * {@snippet lang=c : + * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void *) * } */ - public interface GetDeviceSubClass { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceSubClass fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$9.const$4, fi, constants$6.const$5, scope); - } - static GetDeviceSubClass ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long GetDeviceAsyncEventSource$offset() { + return GetDeviceAsyncEventSource$OFFSET; } - public static VarHandle GetDeviceSubClass$VH() { - return constants$9.const$5; - } /** * Getter for field: - * {@snippet : - * IOReturn (*GetDeviceSubClass)(void*,UInt8*); + * {@snippet lang=c : + * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void *) * } */ - public static MemorySegment GetDeviceSubClass$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$9.const$5.get(seg); + public static MemorySegment GetDeviceAsyncEventSource(MemorySegment struct) { + return struct.get(GetDeviceAsyncEventSource$LAYOUT, GetDeviceAsyncEventSource$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetDeviceSubClass)(void*,UInt8*); + * {@snippet lang=c : + * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void *) * } */ - public static void GetDeviceSubClass$set(MemorySegment seg, MemorySegment x) { - constants$9.const$5.set(seg, x); - } - public static MemorySegment GetDeviceSubClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$9.const$5.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceSubClass$set(MemorySegment seg, long index, MemorySegment x) { - constants$9.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceSubClass GetDeviceSubClass(MemorySegment segment, Arena scope) { - return GetDeviceSubClass.ofAddress(GetDeviceSubClass$get(segment), scope); + public static void GetDeviceAsyncEventSource(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetDeviceAsyncEventSource$LAYOUT, GetDeviceAsyncEventSource$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*GetDeviceProtocol)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*CreateDeviceAsyncPort)(void *, mach_port_t *) * } */ - public interface GetDeviceProtocol { + public static class CreateDeviceAsyncPort { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceProtocol fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$10.const$0, fi, constants$6.const$5, scope); + CreateDeviceAsyncPort() { + // Should not be called directly } - static GetDeviceProtocol ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - } - public static VarHandle GetDeviceProtocol$VH() { - return constants$10.const$1; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*GetDeviceProtocol)(void*,UInt8*); - * } - */ - public static MemorySegment GetDeviceProtocol$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$10.const$1.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(CreateDeviceAsyncPort.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(CreateDeviceAsyncPort.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout CreateDeviceAsyncPort$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("CreateDeviceAsyncPort")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*GetDeviceProtocol)(void*,UInt8*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*CreateDeviceAsyncPort)(void *, mach_port_t *) * } */ - public static void GetDeviceProtocol$set(MemorySegment seg, MemorySegment x) { - constants$10.const$1.set(seg, x); - } - public static MemorySegment GetDeviceProtocol$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$10.const$1.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceProtocol$set(MemorySegment seg, long index, MemorySegment x) { - constants$10.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceProtocol GetDeviceProtocol(MemorySegment segment, Arena scope) { - return GetDeviceProtocol.ofAddress(GetDeviceProtocol$get(segment), scope); + public static final AddressLayout CreateDeviceAsyncPort$layout() { + return CreateDeviceAsyncPort$LAYOUT; } + + private static final long CreateDeviceAsyncPort$OFFSET = 48; + /** - * {@snippet : - * IOReturn (*GetDeviceVendor)(void*,UInt16*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*CreateDeviceAsyncPort)(void *, mach_port_t *) * } */ - public interface GetDeviceVendor { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceVendor fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$10.const$2, fi, constants$6.const$5, scope); - } - static GetDeviceVendor ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long CreateDeviceAsyncPort$offset() { + return CreateDeviceAsyncPort$OFFSET; } - public static VarHandle GetDeviceVendor$VH() { - return constants$10.const$3; - } /** * Getter for field: - * {@snippet : - * IOReturn (*GetDeviceVendor)(void*,UInt16*); + * {@snippet lang=c : + * IOReturn (*CreateDeviceAsyncPort)(void *, mach_port_t *) * } */ - public static MemorySegment GetDeviceVendor$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$10.const$3.get(seg); + public static MemorySegment CreateDeviceAsyncPort(MemorySegment struct) { + return struct.get(CreateDeviceAsyncPort$LAYOUT, CreateDeviceAsyncPort$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetDeviceVendor)(void*,UInt16*); + * {@snippet lang=c : + * IOReturn (*CreateDeviceAsyncPort)(void *, mach_port_t *) * } */ - public static void GetDeviceVendor$set(MemorySegment seg, MemorySegment x) { - constants$10.const$3.set(seg, x); - } - public static MemorySegment GetDeviceVendor$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$10.const$3.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceVendor$set(MemorySegment seg, long index, MemorySegment x) { - constants$10.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceVendor GetDeviceVendor(MemorySegment segment, Arena scope) { - return GetDeviceVendor.ofAddress(GetDeviceVendor$get(segment), scope); + public static void CreateDeviceAsyncPort(MemorySegment struct, MemorySegment fieldValue) { + struct.set(CreateDeviceAsyncPort$LAYOUT, CreateDeviceAsyncPort$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*GetDeviceProduct)(void*,UInt16*); + * {@snippet lang=c : + * mach_port_t (*GetDeviceAsyncPort)(void *) * } */ - public interface GetDeviceProduct { + public static class GetDeviceAsyncPort { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceProduct fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$10.const$4, fi, constants$6.const$5, scope); + GetDeviceAsyncPort() { + // Should not be called directly } - static GetDeviceProduct ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0); } - } - public static VarHandle GetDeviceProduct$VH() { - return constants$10.const$5; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*GetDeviceProduct)(void*,UInt16*); - * } - */ - public static MemorySegment GetDeviceProduct$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$10.const$5.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceAsyncPort.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetDeviceAsyncPort.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout GetDeviceAsyncPort$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetDeviceAsyncPort")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*GetDeviceProduct)(void*,UInt16*); + * Layout for field: + * {@snippet lang=c : + * mach_port_t (*GetDeviceAsyncPort)(void *) * } */ - public static void GetDeviceProduct$set(MemorySegment seg, MemorySegment x) { - constants$10.const$5.set(seg, x); - } - public static MemorySegment GetDeviceProduct$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$10.const$5.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceProduct$set(MemorySegment seg, long index, MemorySegment x) { - constants$10.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceProduct GetDeviceProduct(MemorySegment segment, Arena scope) { - return GetDeviceProduct.ofAddress(GetDeviceProduct$get(segment), scope); + public static final AddressLayout GetDeviceAsyncPort$layout() { + return GetDeviceAsyncPort$LAYOUT; } + + private static final long GetDeviceAsyncPort$OFFSET = 56; + /** - * {@snippet : - * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); + * Offset for field: + * {@snippet lang=c : + * mach_port_t (*GetDeviceAsyncPort)(void *) * } */ - public interface GetDeviceReleaseNumber { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceReleaseNumber fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$11.const$0, fi, constants$6.const$5, scope); - } - static GetDeviceReleaseNumber ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long GetDeviceAsyncPort$offset() { + return GetDeviceAsyncPort$OFFSET; } - public static VarHandle GetDeviceReleaseNumber$VH() { - return constants$11.const$1; - } /** * Getter for field: - * {@snippet : - * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); + * {@snippet lang=c : + * mach_port_t (*GetDeviceAsyncPort)(void *) * } */ - public static MemorySegment GetDeviceReleaseNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$11.const$1.get(seg); + public static MemorySegment GetDeviceAsyncPort(MemorySegment struct) { + return struct.get(GetDeviceAsyncPort$LAYOUT, GetDeviceAsyncPort$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); + * {@snippet lang=c : + * mach_port_t (*GetDeviceAsyncPort)(void *) * } */ - public static void GetDeviceReleaseNumber$set(MemorySegment seg, MemorySegment x) { - constants$11.const$1.set(seg, x); - } - public static MemorySegment GetDeviceReleaseNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$11.const$1.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceReleaseNumber$set(MemorySegment seg, long index, MemorySegment x) { - constants$11.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceReleaseNumber GetDeviceReleaseNumber(MemorySegment segment, Arena scope) { - return GetDeviceReleaseNumber.ofAddress(GetDeviceReleaseNumber$get(segment), scope); + public static void GetDeviceAsyncPort(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetDeviceAsyncPort$LAYOUT, GetDeviceAsyncPort$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*GetDeviceAddress)(void*,USBDeviceAddress*); + * {@snippet lang=c : + * IOReturn (*USBDeviceOpen)(void *) * } */ - public interface GetDeviceAddress { + public static class USBDeviceOpen { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceAddress fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$11.const$2, fi, constants$6.const$5, scope); + USBDeviceOpen() { + // Should not be called directly } - static GetDeviceAddress ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0); } - } - public static VarHandle GetDeviceAddress$VH() { - return constants$11.const$3; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*GetDeviceAddress)(void*,USBDeviceAddress*); - * } - */ - public static MemorySegment GetDeviceAddress$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$11.const$3.get(seg); - } + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(USBDeviceOpen.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(USBDeviceOpen.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout USBDeviceOpen$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("USBDeviceOpen")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*GetDeviceAddress)(void*,USBDeviceAddress*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*USBDeviceOpen)(void *) * } */ - public static void GetDeviceAddress$set(MemorySegment seg, MemorySegment x) { - constants$11.const$3.set(seg, x); + public static final AddressLayout USBDeviceOpen$layout() { + return USBDeviceOpen$LAYOUT; } - public static MemorySegment GetDeviceAddress$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$11.const$3.get(seg.asSlice(index*sizeof())); + + private static final long USBDeviceOpen$OFFSET = 64; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*USBDeviceOpen)(void *) + * } + */ + public static final long USBDeviceOpen$offset() { + return USBDeviceOpen$OFFSET; } - public static void GetDeviceAddress$set(MemorySegment seg, long index, MemorySegment x) { - constants$11.const$3.set(seg.asSlice(index*sizeof()), x); + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*USBDeviceOpen)(void *) + * } + */ + public static MemorySegment USBDeviceOpen(MemorySegment struct) { + return struct.get(USBDeviceOpen$LAYOUT, USBDeviceOpen$OFFSET); } - public static GetDeviceAddress GetDeviceAddress(MemorySegment segment, Arena scope) { - return GetDeviceAddress.ofAddress(GetDeviceAddress$get(segment), scope); + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*USBDeviceOpen)(void *) + * } + */ + public static void USBDeviceOpen(MemorySegment struct, MemorySegment fieldValue) { + struct.set(USBDeviceOpen$LAYOUT, USBDeviceOpen$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*GetDeviceBusPowerAvailable)(void*,UInt32*); + * {@snippet lang=c : + * IOReturn (*USBDeviceClose)(void *) * } */ - public interface GetDeviceBusPowerAvailable { + public static class USBDeviceClose { + + USBDeviceClose() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0); + } - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceBusPowerAvailable fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$11.const$4, fi, constants$6.const$5, scope); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(USBDeviceClose.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(USBDeviceClose.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); } - static GetDeviceBusPowerAvailable ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } } } - public static VarHandle GetDeviceBusPowerAvailable$VH() { - return constants$11.const$5; + private static final AddressLayout USBDeviceClose$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("USBDeviceClose")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*USBDeviceClose)(void *) + * } + */ + public static final AddressLayout USBDeviceClose$layout() { + return USBDeviceClose$LAYOUT; + } + + private static final long USBDeviceClose$OFFSET = 72; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*USBDeviceClose)(void *) + * } + */ + public static final long USBDeviceClose$offset() { + return USBDeviceClose$OFFSET; } + /** * Getter for field: - * {@snippet : - * IOReturn (*GetDeviceBusPowerAvailable)(void*,UInt32*); + * {@snippet lang=c : + * IOReturn (*USBDeviceClose)(void *) * } */ - public static MemorySegment GetDeviceBusPowerAvailable$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$11.const$5.get(seg); + public static MemorySegment USBDeviceClose(MemorySegment struct) { + return struct.get(USBDeviceClose$LAYOUT, USBDeviceClose$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetDeviceBusPowerAvailable)(void*,UInt32*); + * {@snippet lang=c : + * IOReturn (*USBDeviceClose)(void *) * } */ - public static void GetDeviceBusPowerAvailable$set(MemorySegment seg, MemorySegment x) { - constants$11.const$5.set(seg, x); - } - public static MemorySegment GetDeviceBusPowerAvailable$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$11.const$5.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceBusPowerAvailable$set(MemorySegment seg, long index, MemorySegment x) { - constants$11.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceBusPowerAvailable GetDeviceBusPowerAvailable(MemorySegment segment, Arena scope) { - return GetDeviceBusPowerAvailable.ofAddress(GetDeviceBusPowerAvailable$get(segment), scope); + public static void USBDeviceClose(MemorySegment struct, MemorySegment fieldValue) { + struct.set(USBDeviceClose$LAYOUT, USBDeviceClose$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*GetDeviceSpeed)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*GetDeviceClass)(void *, UInt8 *) * } */ - public interface GetDeviceSpeed { + public static class GetDeviceClass { + + GetDeviceClass() { + // Should not be called directly + } - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceSpeed fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$12.const$0, fi, constants$6.const$5, scope); + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - static GetDeviceSpeed ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceClass.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetDeviceClass.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } } } - public static VarHandle GetDeviceSpeed$VH() { - return constants$12.const$1; + private static final AddressLayout GetDeviceClass$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetDeviceClass")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceClass)(void *, UInt8 *) + * } + */ + public static final AddressLayout GetDeviceClass$layout() { + return GetDeviceClass$LAYOUT; + } + + private static final long GetDeviceClass$OFFSET = 80; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceClass)(void *, UInt8 *) + * } + */ + public static final long GetDeviceClass$offset() { + return GetDeviceClass$OFFSET; } + /** * Getter for field: - * {@snippet : - * IOReturn (*GetDeviceSpeed)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*GetDeviceClass)(void *, UInt8 *) * } */ - public static MemorySegment GetDeviceSpeed$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$12.const$1.get(seg); + public static MemorySegment GetDeviceClass(MemorySegment struct) { + return struct.get(GetDeviceClass$LAYOUT, GetDeviceClass$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetDeviceSpeed)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*GetDeviceClass)(void *, UInt8 *) * } */ - public static void GetDeviceSpeed$set(MemorySegment seg, MemorySegment x) { - constants$12.const$1.set(seg, x); - } - public static MemorySegment GetDeviceSpeed$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$12.const$1.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceSpeed$set(MemorySegment seg, long index, MemorySegment x) { - constants$12.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceSpeed GetDeviceSpeed(MemorySegment segment, Arena scope) { - return GetDeviceSpeed.ofAddress(GetDeviceSpeed$get(segment), scope); + public static void GetDeviceClass(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetDeviceClass$LAYOUT, GetDeviceClass$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*GetNumberOfConfigurations)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*GetDeviceSubClass)(void *, UInt8 *) * } */ - public interface GetNumberOfConfigurations { + public static class GetDeviceSubClass { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetNumberOfConfigurations fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$12.const$2, fi, constants$6.const$5, scope); + GetDeviceSubClass() { + // Should not be called directly } - static GetNumberOfConfigurations ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceSubClass.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetDeviceSubClass.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } } } - public static VarHandle GetNumberOfConfigurations$VH() { - return constants$12.const$3; + private static final AddressLayout GetDeviceSubClass$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetDeviceSubClass")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceSubClass)(void *, UInt8 *) + * } + */ + public static final AddressLayout GetDeviceSubClass$layout() { + return GetDeviceSubClass$LAYOUT; + } + + private static final long GetDeviceSubClass$OFFSET = 88; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceSubClass)(void *, UInt8 *) + * } + */ + public static final long GetDeviceSubClass$offset() { + return GetDeviceSubClass$OFFSET; } + /** * Getter for field: - * {@snippet : - * IOReturn (*GetNumberOfConfigurations)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*GetDeviceSubClass)(void *, UInt8 *) * } */ - public static MemorySegment GetNumberOfConfigurations$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$12.const$3.get(seg); + public static MemorySegment GetDeviceSubClass(MemorySegment struct) { + return struct.get(GetDeviceSubClass$LAYOUT, GetDeviceSubClass$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetNumberOfConfigurations)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*GetDeviceSubClass)(void *, UInt8 *) + * } + */ + public static void GetDeviceSubClass(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetDeviceSubClass$LAYOUT, GetDeviceSubClass$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetDeviceProtocol)(void *, UInt8 *) + * } + */ + public static class GetDeviceProtocol { + + GetDeviceProtocol() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceProtocol.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetDeviceProtocol.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetDeviceProtocol$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetDeviceProtocol")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceProtocol)(void *, UInt8 *) * } */ - public static void GetNumberOfConfigurations$set(MemorySegment seg, MemorySegment x) { - constants$12.const$3.set(seg, x); + public static final AddressLayout GetDeviceProtocol$layout() { + return GetDeviceProtocol$LAYOUT; } - public static MemorySegment GetNumberOfConfigurations$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$12.const$3.get(seg.asSlice(index*sizeof())); + + private static final long GetDeviceProtocol$OFFSET = 96; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceProtocol)(void *, UInt8 *) + * } + */ + public static final long GetDeviceProtocol$offset() { + return GetDeviceProtocol$OFFSET; } - public static void GetNumberOfConfigurations$set(MemorySegment seg, long index, MemorySegment x) { - constants$12.const$3.set(seg.asSlice(index*sizeof()), x); + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceProtocol)(void *, UInt8 *) + * } + */ + public static MemorySegment GetDeviceProtocol(MemorySegment struct) { + return struct.get(GetDeviceProtocol$LAYOUT, GetDeviceProtocol$OFFSET); } - public static GetNumberOfConfigurations GetNumberOfConfigurations(MemorySegment segment, Arena scope) { - return GetNumberOfConfigurations.ofAddress(GetNumberOfConfigurations$get(segment), scope); + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceProtocol)(void *, UInt8 *) + * } + */ + public static void GetDeviceProtocol(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetDeviceProtocol$LAYOUT, GetDeviceProtocol$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*GetLocationID)(void*,UInt32*); + * {@snippet lang=c : + * IOReturn (*GetDeviceVendor)(void *, UInt16 *) * } */ - public interface GetLocationID { + public static class GetDeviceVendor { + + GetDeviceVendor() { + // Should not be called directly + } - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetLocationID fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$12.const$4, fi, constants$6.const$5, scope); + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - static GetLocationID ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceVendor.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetDeviceVendor.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } } } - public static VarHandle GetLocationID$VH() { - return constants$12.const$5; + private static final AddressLayout GetDeviceVendor$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetDeviceVendor")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceVendor)(void *, UInt16 *) + * } + */ + public static final AddressLayout GetDeviceVendor$layout() { + return GetDeviceVendor$LAYOUT; + } + + private static final long GetDeviceVendor$OFFSET = 104; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceVendor)(void *, UInt16 *) + * } + */ + public static final long GetDeviceVendor$offset() { + return GetDeviceVendor$OFFSET; } + /** * Getter for field: - * {@snippet : - * IOReturn (*GetLocationID)(void*,UInt32*); + * {@snippet lang=c : + * IOReturn (*GetDeviceVendor)(void *, UInt16 *) * } */ - public static MemorySegment GetLocationID$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$12.const$5.get(seg); + public static MemorySegment GetDeviceVendor(MemorySegment struct) { + return struct.get(GetDeviceVendor$LAYOUT, GetDeviceVendor$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetLocationID)(void*,UInt32*); + * {@snippet lang=c : + * IOReturn (*GetDeviceVendor)(void *, UInt16 *) + * } + */ + public static void GetDeviceVendor(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetDeviceVendor$LAYOUT, GetDeviceVendor$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetDeviceProduct)(void *, UInt16 *) + * } + */ + public static class GetDeviceProduct { + + GetDeviceProduct() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceProduct.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetDeviceProduct.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetDeviceProduct$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetDeviceProduct")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceProduct)(void *, UInt16 *) * } */ - public static void GetLocationID$set(MemorySegment seg, MemorySegment x) { - constants$12.const$5.set(seg, x); + public static final AddressLayout GetDeviceProduct$layout() { + return GetDeviceProduct$LAYOUT; } - public static MemorySegment GetLocationID$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$12.const$5.get(seg.asSlice(index*sizeof())); + + private static final long GetDeviceProduct$OFFSET = 112; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceProduct)(void *, UInt16 *) + * } + */ + public static final long GetDeviceProduct$offset() { + return GetDeviceProduct$OFFSET; } - public static void GetLocationID$set(MemorySegment seg, long index, MemorySegment x) { - constants$12.const$5.set(seg.asSlice(index*sizeof()), x); + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceProduct)(void *, UInt16 *) + * } + */ + public static MemorySegment GetDeviceProduct(MemorySegment struct) { + return struct.get(GetDeviceProduct$LAYOUT, GetDeviceProduct$OFFSET); } - public static GetLocationID GetLocationID(MemorySegment segment, Arena scope) { - return GetLocationID.ofAddress(GetLocationID$get(segment), scope); + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceProduct)(void *, UInt16 *) + * } + */ + public static void GetDeviceProduct(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetDeviceProduct$LAYOUT, GetDeviceProduct$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*GetConfigurationDescriptorPtr)(void*,UInt8,IOUSBConfigurationDescriptorPtr*); + * {@snippet lang=c : + * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *) * } */ - public interface GetConfigurationDescriptorPtr { + public static class GetDeviceReleaseNumber { + + GetDeviceReleaseNumber() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); + } - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(GetConfigurationDescriptorPtr fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$13.const$1, fi, constants$13.const$0, scope); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceReleaseNumber.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetDeviceReleaseNumber.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); } - static GetConfigurationDescriptorPtr ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2) -> { - try { - return (int)constants$13.const$2.invokeExact(symbol, __x0, __x1, __x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } } } - public static VarHandle GetConfigurationDescriptorPtr$VH() { - return constants$13.const$3; + private static final AddressLayout GetDeviceReleaseNumber$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetDeviceReleaseNumber")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *) + * } + */ + public static final AddressLayout GetDeviceReleaseNumber$layout() { + return GetDeviceReleaseNumber$LAYOUT; + } + + private static final long GetDeviceReleaseNumber$OFFSET = 120; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *) + * } + */ + public static final long GetDeviceReleaseNumber$offset() { + return GetDeviceReleaseNumber$OFFSET; } + /** * Getter for field: - * {@snippet : - * IOReturn (*GetConfigurationDescriptorPtr)(void*,UInt8,IOUSBConfigurationDescriptorPtr*); + * {@snippet lang=c : + * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *) * } */ - public static MemorySegment GetConfigurationDescriptorPtr$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$13.const$3.get(seg); + public static MemorySegment GetDeviceReleaseNumber(MemorySegment struct) { + return struct.get(GetDeviceReleaseNumber$LAYOUT, GetDeviceReleaseNumber$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetConfigurationDescriptorPtr)(void*,UInt8,IOUSBConfigurationDescriptorPtr*); + * {@snippet lang=c : + * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *) + * } + */ + public static void GetDeviceReleaseNumber(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetDeviceReleaseNumber$LAYOUT, GetDeviceReleaseNumber$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetDeviceAddress)(void *, USBDeviceAddress *) * } */ - public static void GetConfigurationDescriptorPtr$set(MemorySegment seg, MemorySegment x) { - constants$13.const$3.set(seg, x); + public static class GetDeviceAddress { + + GetDeviceAddress() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceAddress.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetDeviceAddress.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } - public static MemorySegment GetConfigurationDescriptorPtr$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$13.const$3.get(seg.asSlice(index*sizeof())); + + private static final AddressLayout GetDeviceAddress$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetDeviceAddress")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceAddress)(void *, USBDeviceAddress *) + * } + */ + public static final AddressLayout GetDeviceAddress$layout() { + return GetDeviceAddress$LAYOUT; } - public static void GetConfigurationDescriptorPtr$set(MemorySegment seg, long index, MemorySegment x) { - constants$13.const$3.set(seg.asSlice(index*sizeof()), x); + + private static final long GetDeviceAddress$OFFSET = 128; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceAddress)(void *, USBDeviceAddress *) + * } + */ + public static final long GetDeviceAddress$offset() { + return GetDeviceAddress$OFFSET; } - public static GetConfigurationDescriptorPtr GetConfigurationDescriptorPtr(MemorySegment segment, Arena scope) { - return GetConfigurationDescriptorPtr.ofAddress(GetConfigurationDescriptorPtr$get(segment), scope); + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceAddress)(void *, USBDeviceAddress *) + * } + */ + public static MemorySegment GetDeviceAddress(MemorySegment struct) { + return struct.get(GetDeviceAddress$LAYOUT, GetDeviceAddress$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceAddress)(void *, USBDeviceAddress *) + * } + */ + public static void GetDeviceAddress(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetDeviceAddress$LAYOUT, GetDeviceAddress$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetDeviceBusPowerAvailable)(void *, UInt32 *) + * } + */ + public static class GetDeviceBusPowerAvailable { + + GetDeviceBusPowerAvailable() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceBusPowerAvailable.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetDeviceBusPowerAvailable.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetDeviceBusPowerAvailable$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetDeviceBusPowerAvailable")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceBusPowerAvailable)(void *, UInt32 *) + * } + */ + public static final AddressLayout GetDeviceBusPowerAvailable$layout() { + return GetDeviceBusPowerAvailable$LAYOUT; + } + + private static final long GetDeviceBusPowerAvailable$OFFSET = 136; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceBusPowerAvailable)(void *, UInt32 *) + * } + */ + public static final long GetDeviceBusPowerAvailable$offset() { + return GetDeviceBusPowerAvailable$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceBusPowerAvailable)(void *, UInt32 *) + * } + */ + public static MemorySegment GetDeviceBusPowerAvailable(MemorySegment struct) { + return struct.get(GetDeviceBusPowerAvailable$LAYOUT, GetDeviceBusPowerAvailable$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceBusPowerAvailable)(void *, UInt32 *) + * } + */ + public static void GetDeviceBusPowerAvailable(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetDeviceBusPowerAvailable$LAYOUT, GetDeviceBusPowerAvailable$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetDeviceSpeed)(void *, UInt8 *) + * } + */ + public static class GetDeviceSpeed { + + GetDeviceSpeed() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceSpeed.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetDeviceSpeed.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetDeviceSpeed$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetDeviceSpeed")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceSpeed)(void *, UInt8 *) + * } + */ + public static final AddressLayout GetDeviceSpeed$layout() { + return GetDeviceSpeed$LAYOUT; + } + + private static final long GetDeviceSpeed$OFFSET = 144; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceSpeed)(void *, UInt8 *) + * } + */ + public static final long GetDeviceSpeed$offset() { + return GetDeviceSpeed$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceSpeed)(void *, UInt8 *) + * } + */ + public static MemorySegment GetDeviceSpeed(MemorySegment struct) { + return struct.get(GetDeviceSpeed$LAYOUT, GetDeviceSpeed$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceSpeed)(void *, UInt8 *) + * } + */ + public static void GetDeviceSpeed(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetDeviceSpeed$LAYOUT, GetDeviceSpeed$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetNumberOfConfigurations)(void *, UInt8 *) + * } + */ + public static class GetNumberOfConfigurations { + + GetNumberOfConfigurations() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetNumberOfConfigurations.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetNumberOfConfigurations.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetNumberOfConfigurations$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetNumberOfConfigurations")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetNumberOfConfigurations)(void *, UInt8 *) + * } + */ + public static final AddressLayout GetNumberOfConfigurations$layout() { + return GetNumberOfConfigurations$LAYOUT; + } + + private static final long GetNumberOfConfigurations$OFFSET = 152; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetNumberOfConfigurations)(void *, UInt8 *) + * } + */ + public static final long GetNumberOfConfigurations$offset() { + return GetNumberOfConfigurations$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetNumberOfConfigurations)(void *, UInt8 *) + * } + */ + public static MemorySegment GetNumberOfConfigurations(MemorySegment struct) { + return struct.get(GetNumberOfConfigurations$LAYOUT, GetNumberOfConfigurations$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetNumberOfConfigurations)(void *, UInt8 *) + * } + */ + public static void GetNumberOfConfigurations(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetNumberOfConfigurations$LAYOUT, GetNumberOfConfigurations$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetLocationID)(void *, UInt32 *) + * } + */ + public static class GetLocationID { + + GetLocationID() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetLocationID.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetLocationID.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetLocationID$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetLocationID")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetLocationID)(void *, UInt32 *) + * } + */ + public static final AddressLayout GetLocationID$layout() { + return GetLocationID$LAYOUT; + } + + private static final long GetLocationID$OFFSET = 160; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetLocationID)(void *, UInt32 *) + * } + */ + public static final long GetLocationID$offset() { + return GetLocationID$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetLocationID)(void *, UInt32 *) + * } + */ + public static MemorySegment GetLocationID(MemorySegment struct) { + return struct.get(GetLocationID$LAYOUT, GetLocationID$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetLocationID)(void *, UInt32 *) + * } + */ + public static void GetLocationID(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetLocationID$LAYOUT, GetLocationID$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetConfigurationDescriptorPtr)(void *, UInt8, IOUSBConfigurationDescriptorPtr *) + * } + */ + public static class GetConfigurationDescriptorPtr { + + GetConfigurationDescriptorPtr() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, MemorySegment _x2); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetConfigurationDescriptorPtr.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetConfigurationDescriptorPtr.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetConfigurationDescriptorPtr$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetConfigurationDescriptorPtr")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetConfigurationDescriptorPtr)(void *, UInt8, IOUSBConfigurationDescriptorPtr *) + * } + */ + public static final AddressLayout GetConfigurationDescriptorPtr$layout() { + return GetConfigurationDescriptorPtr$LAYOUT; + } + + private static final long GetConfigurationDescriptorPtr$OFFSET = 168; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetConfigurationDescriptorPtr)(void *, UInt8, IOUSBConfigurationDescriptorPtr *) + * } + */ + public static final long GetConfigurationDescriptorPtr$offset() { + return GetConfigurationDescriptorPtr$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetConfigurationDescriptorPtr)(void *, UInt8, IOUSBConfigurationDescriptorPtr *) + * } + */ + public static MemorySegment GetConfigurationDescriptorPtr(MemorySegment struct) { + return struct.get(GetConfigurationDescriptorPtr$LAYOUT, GetConfigurationDescriptorPtr$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetConfigurationDescriptorPtr)(void *, UInt8, IOUSBConfigurationDescriptorPtr *) + * } + */ + public static void GetConfigurationDescriptorPtr(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetConfigurationDescriptorPtr$LAYOUT, GetConfigurationDescriptorPtr$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetConfiguration)(void *, UInt8 *) + * } + */ + public static class GetConfiguration { + + GetConfiguration() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetConfiguration.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetConfiguration.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetConfiguration$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetConfiguration")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetConfiguration)(void *, UInt8 *) + * } + */ + public static final AddressLayout GetConfiguration$layout() { + return GetConfiguration$LAYOUT; + } + + private static final long GetConfiguration$OFFSET = 176; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetConfiguration)(void *, UInt8 *) + * } + */ + public static final long GetConfiguration$offset() { + return GetConfiguration$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetConfiguration)(void *, UInt8 *) + * } + */ + public static MemorySegment GetConfiguration(MemorySegment struct) { + return struct.get(GetConfiguration$LAYOUT, GetConfiguration$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetConfiguration)(void *, UInt8 *) + * } + */ + public static void GetConfiguration(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetConfiguration$LAYOUT, GetConfiguration$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*SetConfiguration)(void *, UInt8) + * } + */ + public static class SetConfiguration { + + SetConfiguration() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(SetConfiguration.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(SetConfiguration.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout SetConfiguration$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("SetConfiguration")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*SetConfiguration)(void *, UInt8) + * } + */ + public static final AddressLayout SetConfiguration$layout() { + return SetConfiguration$LAYOUT; + } + + private static final long SetConfiguration$OFFSET = 184; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*SetConfiguration)(void *, UInt8) + * } + */ + public static final long SetConfiguration$offset() { + return SetConfiguration$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*SetConfiguration)(void *, UInt8) + * } + */ + public static MemorySegment SetConfiguration(MemorySegment struct) { + return struct.get(SetConfiguration$LAYOUT, SetConfiguration$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*SetConfiguration)(void *, UInt8) + * } + */ + public static void SetConfiguration(MemorySegment struct, MemorySegment fieldValue) { + struct.set(SetConfiguration$LAYOUT, SetConfiguration$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *) + * } + */ + public static class GetBusFrameNumber { + + GetBusFrameNumber() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1, MemorySegment _x2); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetBusFrameNumber.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetBusFrameNumber.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetBusFrameNumber$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetBusFrameNumber")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *) + * } + */ + public static final AddressLayout GetBusFrameNumber$layout() { + return GetBusFrameNumber$LAYOUT; + } + + private static final long GetBusFrameNumber$OFFSET = 192; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *) + * } + */ + public static final long GetBusFrameNumber$offset() { + return GetBusFrameNumber$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *) + * } + */ + public static MemorySegment GetBusFrameNumber(MemorySegment struct) { + return struct.get(GetBusFrameNumber$LAYOUT, GetBusFrameNumber$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *) + * } + */ + public static void GetBusFrameNumber(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetBusFrameNumber$LAYOUT, GetBusFrameNumber$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*ResetDevice)(void *) + * } + */ + public static class ResetDevice { + + ResetDevice() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(ResetDevice.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(ResetDevice.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout ResetDevice$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("ResetDevice")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*ResetDevice)(void *) + * } + */ + public static final AddressLayout ResetDevice$layout() { + return ResetDevice$LAYOUT; + } + + private static final long ResetDevice$OFFSET = 200; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*ResetDevice)(void *) + * } + */ + public static final long ResetDevice$offset() { + return ResetDevice$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*ResetDevice)(void *) + * } + */ + public static MemorySegment ResetDevice(MemorySegment struct) { + return struct.get(ResetDevice$LAYOUT, ResetDevice$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*ResetDevice)(void *) + * } + */ + public static void ResetDevice(MemorySegment struct, MemorySegment fieldValue) { + struct.set(ResetDevice$LAYOUT, ResetDevice$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*DeviceRequest)(void *, IOUSBDevRequest *) + * } + */ + public static class DeviceRequest { + + DeviceRequest() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(DeviceRequest.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(DeviceRequest.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout DeviceRequest$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("DeviceRequest")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*DeviceRequest)(void *, IOUSBDevRequest *) + * } + */ + public static final AddressLayout DeviceRequest$layout() { + return DeviceRequest$LAYOUT; + } + + private static final long DeviceRequest$OFFSET = 208; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*DeviceRequest)(void *, IOUSBDevRequest *) + * } + */ + public static final long DeviceRequest$offset() { + return DeviceRequest$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*DeviceRequest)(void *, IOUSBDevRequest *) + * } + */ + public static MemorySegment DeviceRequest(MemorySegment struct) { + return struct.get(DeviceRequest$LAYOUT, DeviceRequest$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*DeviceRequest)(void *, IOUSBDevRequest *) + * } + */ + public static void DeviceRequest(MemorySegment struct, MemorySegment fieldValue) { + struct.set(DeviceRequest$LAYOUT, DeviceRequest$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*DeviceRequestAsync)(void *, IOUSBDevRequest *, IOAsyncCallback1, void *) + * } + */ + public static class DeviceRequestAsync { + + DeviceRequestAsync() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1, MemorySegment _x2, MemorySegment _x3); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(DeviceRequestAsync.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(DeviceRequestAsync.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, MemorySegment _x2, MemorySegment _x3) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout DeviceRequestAsync$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("DeviceRequestAsync")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*DeviceRequestAsync)(void *, IOUSBDevRequest *, IOAsyncCallback1, void *) + * } + */ + public static final AddressLayout DeviceRequestAsync$layout() { + return DeviceRequestAsync$LAYOUT; + } + + private static final long DeviceRequestAsync$OFFSET = 216; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*DeviceRequestAsync)(void *, IOUSBDevRequest *, IOAsyncCallback1, void *) + * } + */ + public static final long DeviceRequestAsync$offset() { + return DeviceRequestAsync$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*DeviceRequestAsync)(void *, IOUSBDevRequest *, IOAsyncCallback1, void *) + * } + */ + public static MemorySegment DeviceRequestAsync(MemorySegment struct) { + return struct.get(DeviceRequestAsync$LAYOUT, DeviceRequestAsync$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*DeviceRequestAsync)(void *, IOUSBDevRequest *, IOAsyncCallback1, void *) + * } + */ + public static void DeviceRequestAsync(MemorySegment struct, MemorySegment fieldValue) { + struct.set(DeviceRequestAsync$LAYOUT, DeviceRequestAsync$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*CreateInterfaceIterator)(void *, IOUSBFindInterfaceRequest *, io_iterator_t *) + * } + */ + public static class CreateInterfaceIterator { + + CreateInterfaceIterator() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1, MemorySegment _x2); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(CreateInterfaceIterator.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(CreateInterfaceIterator.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout CreateInterfaceIterator$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("CreateInterfaceIterator")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*CreateInterfaceIterator)(void *, IOUSBFindInterfaceRequest *, io_iterator_t *) + * } + */ + public static final AddressLayout CreateInterfaceIterator$layout() { + return CreateInterfaceIterator$LAYOUT; + } + + private static final long CreateInterfaceIterator$OFFSET = 224; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*CreateInterfaceIterator)(void *, IOUSBFindInterfaceRequest *, io_iterator_t *) + * } + */ + public static final long CreateInterfaceIterator$offset() { + return CreateInterfaceIterator$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*CreateInterfaceIterator)(void *, IOUSBFindInterfaceRequest *, io_iterator_t *) + * } + */ + public static MemorySegment CreateInterfaceIterator(MemorySegment struct) { + return struct.get(CreateInterfaceIterator$LAYOUT, CreateInterfaceIterator$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*CreateInterfaceIterator)(void *, IOUSBFindInterfaceRequest *, io_iterator_t *) + * } + */ + public static void CreateInterfaceIterator(MemorySegment struct, MemorySegment fieldValue) { + struct.set(CreateInterfaceIterator$LAYOUT, CreateInterfaceIterator$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*USBDeviceOpenSeize)(void *) + * } + */ + public static class USBDeviceOpenSeize { + + USBDeviceOpenSeize() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(USBDeviceOpenSeize.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(USBDeviceOpenSeize.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout USBDeviceOpenSeize$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("USBDeviceOpenSeize")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*USBDeviceOpenSeize)(void *) + * } + */ + public static final AddressLayout USBDeviceOpenSeize$layout() { + return USBDeviceOpenSeize$LAYOUT; + } + + private static final long USBDeviceOpenSeize$OFFSET = 232; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*USBDeviceOpenSeize)(void *) + * } + */ + public static final long USBDeviceOpenSeize$offset() { + return USBDeviceOpenSeize$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*USBDeviceOpenSeize)(void *) + * } + */ + public static MemorySegment USBDeviceOpenSeize(MemorySegment struct) { + return struct.get(USBDeviceOpenSeize$LAYOUT, USBDeviceOpenSeize$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*USBDeviceOpenSeize)(void *) + * } + */ + public static void USBDeviceOpenSeize(MemorySegment struct, MemorySegment fieldValue) { + struct.set(USBDeviceOpenSeize$LAYOUT, USBDeviceOpenSeize$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*DeviceRequestTO)(void *, IOUSBDevRequestTO *) + * } + */ + public static class DeviceRequestTO { + + DeviceRequestTO() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(DeviceRequestTO.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(DeviceRequestTO.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout DeviceRequestTO$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("DeviceRequestTO")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*DeviceRequestTO)(void *, IOUSBDevRequestTO *) + * } + */ + public static final AddressLayout DeviceRequestTO$layout() { + return DeviceRequestTO$LAYOUT; } + + private static final long DeviceRequestTO$OFFSET = 240; + /** - * {@snippet : - * IOReturn (*GetConfiguration)(void*,UInt8*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*DeviceRequestTO)(void *, IOUSBDevRequestTO *) * } */ - public interface GetConfiguration { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetConfiguration fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$13.const$4, fi, constants$6.const$5, scope); - } - static GetConfiguration ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long DeviceRequestTO$offset() { + return DeviceRequestTO$OFFSET; } - public static VarHandle GetConfiguration$VH() { - return constants$13.const$5; - } /** * Getter for field: - * {@snippet : - * IOReturn (*GetConfiguration)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*DeviceRequestTO)(void *, IOUSBDevRequestTO *) * } */ - public static MemorySegment GetConfiguration$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$13.const$5.get(seg); + public static MemorySegment DeviceRequestTO(MemorySegment struct) { + return struct.get(DeviceRequestTO$LAYOUT, DeviceRequestTO$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetConfiguration)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*DeviceRequestTO)(void *, IOUSBDevRequestTO *) * } */ - public static void GetConfiguration$set(MemorySegment seg, MemorySegment x) { - constants$13.const$5.set(seg, x); - } - public static MemorySegment GetConfiguration$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$13.const$5.get(seg.asSlice(index*sizeof())); - } - public static void GetConfiguration$set(MemorySegment seg, long index, MemorySegment x) { - constants$13.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static GetConfiguration GetConfiguration(MemorySegment segment, Arena scope) { - return GetConfiguration.ofAddress(GetConfiguration$get(segment), scope); + public static void DeviceRequestTO(MemorySegment struct, MemorySegment fieldValue) { + struct.set(DeviceRequestTO$LAYOUT, DeviceRequestTO$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*SetConfiguration)(void*,UInt8); + * {@snippet lang=c : + * IOReturn (*DeviceRequestAsyncTO)(void *, IOUSBDevRequestTO *, IOAsyncCallback1, void *) * } */ - public interface SetConfiguration { + public static class DeviceRequestAsyncTO { - int apply(java.lang.foreign.MemorySegment _x0, byte _x1); - static MemorySegment allocate(SetConfiguration fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$14.const$1, fi, constants$14.const$0, scope); + DeviceRequestAsyncTO() { + // Should not be called directly } - static SetConfiguration ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { - try { - return (int)constants$14.const$2.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1, MemorySegment _x2, MemorySegment _x3); } - } - public static VarHandle SetConfiguration$VH() { - return constants$14.const$3; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*SetConfiguration)(void*,UInt8); - * } - */ - public static MemorySegment SetConfiguration$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$14.const$3.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(DeviceRequestAsyncTO.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(DeviceRequestAsyncTO.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, MemorySegment _x2, MemorySegment _x3) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout DeviceRequestAsyncTO$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("DeviceRequestAsyncTO")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*SetConfiguration)(void*,UInt8); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*DeviceRequestAsyncTO)(void *, IOUSBDevRequestTO *, IOAsyncCallback1, void *) * } */ - public static void SetConfiguration$set(MemorySegment seg, MemorySegment x) { - constants$14.const$3.set(seg, x); - } - public static MemorySegment SetConfiguration$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$14.const$3.get(seg.asSlice(index*sizeof())); - } - public static void SetConfiguration$set(MemorySegment seg, long index, MemorySegment x) { - constants$14.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static SetConfiguration SetConfiguration(MemorySegment segment, Arena scope) { - return SetConfiguration.ofAddress(SetConfiguration$get(segment), scope); + public static final AddressLayout DeviceRequestAsyncTO$layout() { + return DeviceRequestAsyncTO$LAYOUT; } + + private static final long DeviceRequestAsyncTO$OFFSET = 248; + /** - * {@snippet : - * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*DeviceRequestAsyncTO)(void *, IOUSBDevRequestTO *, IOAsyncCallback1, void *) * } */ - public interface GetBusFrameNumber { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(GetBusFrameNumber fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$14.const$5, fi, constants$14.const$4, scope); - } - static GetBusFrameNumber ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { - try { - return (int)constants$15.const$0.invokeExact(symbol, __x0, __x1, __x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long DeviceRequestAsyncTO$offset() { + return DeviceRequestAsyncTO$OFFSET; } - public static VarHandle GetBusFrameNumber$VH() { - return constants$15.const$1; - } /** * Getter for field: - * {@snippet : - * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); + * {@snippet lang=c : + * IOReturn (*DeviceRequestAsyncTO)(void *, IOUSBDevRequestTO *, IOAsyncCallback1, void *) * } */ - public static MemorySegment GetBusFrameNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$15.const$1.get(seg); + public static MemorySegment DeviceRequestAsyncTO(MemorySegment struct) { + return struct.get(DeviceRequestAsyncTO$LAYOUT, DeviceRequestAsyncTO$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); + * {@snippet lang=c : + * IOReturn (*DeviceRequestAsyncTO)(void *, IOUSBDevRequestTO *, IOAsyncCallback1, void *) * } */ - public static void GetBusFrameNumber$set(MemorySegment seg, MemorySegment x) { - constants$15.const$1.set(seg, x); - } - public static MemorySegment GetBusFrameNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$15.const$1.get(seg.asSlice(index*sizeof())); - } - public static void GetBusFrameNumber$set(MemorySegment seg, long index, MemorySegment x) { - constants$15.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static GetBusFrameNumber GetBusFrameNumber(MemorySegment segment, Arena scope) { - return GetBusFrameNumber.ofAddress(GetBusFrameNumber$get(segment), scope); + public static void DeviceRequestAsyncTO(MemorySegment struct, MemorySegment fieldValue) { + struct.set(DeviceRequestAsyncTO$LAYOUT, DeviceRequestAsyncTO$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*ResetDevice)(void*); + * {@snippet lang=c : + * IOReturn (*USBDeviceSuspend)(void *, Boolean) * } */ - public interface ResetDevice { + public static class USBDeviceSuspend { - int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(ResetDevice fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$15.const$2, fi, constants$5.const$5, scope); + USBDeviceSuspend() { + // Should not be called directly } - static ResetDevice ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (int)constants$6.const$1.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1); } - } - public static VarHandle ResetDevice$VH() { - return constants$15.const$3; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*ResetDevice)(void*); - * } - */ - public static MemorySegment ResetDevice$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$15.const$3.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(USBDeviceSuspend.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(USBDeviceSuspend.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout USBDeviceSuspend$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("USBDeviceSuspend")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*ResetDevice)(void*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*USBDeviceSuspend)(void *, Boolean) * } */ - public static void ResetDevice$set(MemorySegment seg, MemorySegment x) { - constants$15.const$3.set(seg, x); - } - public static MemorySegment ResetDevice$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$15.const$3.get(seg.asSlice(index*sizeof())); - } - public static void ResetDevice$set(MemorySegment seg, long index, MemorySegment x) { - constants$15.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static ResetDevice ResetDevice(MemorySegment segment, Arena scope) { - return ResetDevice.ofAddress(ResetDevice$get(segment), scope); + public static final AddressLayout USBDeviceSuspend$layout() { + return USBDeviceSuspend$LAYOUT; } + + private static final long USBDeviceSuspend$OFFSET = 256; + /** - * {@snippet : - * IOReturn (*DeviceRequest)(void*,IOUSBDevRequest*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*USBDeviceSuspend)(void *, Boolean) * } */ - public interface DeviceRequest { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(DeviceRequest fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$15.const$4, fi, constants$6.const$5, scope); - } - static DeviceRequest ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long USBDeviceSuspend$offset() { + return USBDeviceSuspend$OFFSET; } - public static VarHandle DeviceRequest$VH() { - return constants$15.const$5; - } /** * Getter for field: - * {@snippet : - * IOReturn (*DeviceRequest)(void*,IOUSBDevRequest*); + * {@snippet lang=c : + * IOReturn (*USBDeviceSuspend)(void *, Boolean) * } */ - public static MemorySegment DeviceRequest$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$15.const$5.get(seg); + public static MemorySegment USBDeviceSuspend(MemorySegment struct) { + return struct.get(USBDeviceSuspend$LAYOUT, USBDeviceSuspend$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*DeviceRequest)(void*,IOUSBDevRequest*); + * {@snippet lang=c : + * IOReturn (*USBDeviceSuspend)(void *, Boolean) * } */ - public static void DeviceRequest$set(MemorySegment seg, MemorySegment x) { - constants$15.const$5.set(seg, x); - } - public static MemorySegment DeviceRequest$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$15.const$5.get(seg.asSlice(index*sizeof())); - } - public static void DeviceRequest$set(MemorySegment seg, long index, MemorySegment x) { - constants$15.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static DeviceRequest DeviceRequest(MemorySegment segment, Arena scope) { - return DeviceRequest.ofAddress(DeviceRequest$get(segment), scope); + public static void USBDeviceSuspend(MemorySegment struct, MemorySegment fieldValue) { + struct.set(USBDeviceSuspend$LAYOUT, USBDeviceSuspend$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*DeviceRequestAsync)(void*,IOUSBDevRequest*,IOAsyncCallback1,void*); + * {@snippet lang=c : + * IOReturn (*USBDeviceAbortPipeZero)(void *) * } */ - public interface DeviceRequestAsync { + public static class USBDeviceAbortPipeZero { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3); - static MemorySegment allocate(DeviceRequestAsync fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$16.const$1, fi, constants$16.const$0, scope); + USBDeviceAbortPipeZero() { + // Should not be called directly } - static DeviceRequestAsync ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3) -> { - try { - return (int)constants$16.const$2.invokeExact(symbol, __x0, __x1, __x2, __x3); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0); } - } - public static VarHandle DeviceRequestAsync$VH() { - return constants$16.const$3; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*DeviceRequestAsync)(void*,IOUSBDevRequest*,IOAsyncCallback1,void*); - * } - */ - public static MemorySegment DeviceRequestAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$16.const$3.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(USBDeviceAbortPipeZero.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(USBDeviceAbortPipeZero.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout USBDeviceAbortPipeZero$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("USBDeviceAbortPipeZero")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*DeviceRequestAsync)(void*,IOUSBDevRequest*,IOAsyncCallback1,void*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*USBDeviceAbortPipeZero)(void *) * } */ - public static void DeviceRequestAsync$set(MemorySegment seg, MemorySegment x) { - constants$16.const$3.set(seg, x); - } - public static MemorySegment DeviceRequestAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$16.const$3.get(seg.asSlice(index*sizeof())); - } - public static void DeviceRequestAsync$set(MemorySegment seg, long index, MemorySegment x) { - constants$16.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static DeviceRequestAsync DeviceRequestAsync(MemorySegment segment, Arena scope) { - return DeviceRequestAsync.ofAddress(DeviceRequestAsync$get(segment), scope); + public static final AddressLayout USBDeviceAbortPipeZero$layout() { + return USBDeviceAbortPipeZero$LAYOUT; } + + private static final long USBDeviceAbortPipeZero$OFFSET = 264; + /** - * {@snippet : - * IOReturn (*CreateInterfaceIterator)(void*,IOUSBFindInterfaceRequest*,io_iterator_t*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*USBDeviceAbortPipeZero)(void *) * } */ - public interface CreateInterfaceIterator { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(CreateInterfaceIterator fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$16.const$4, fi, constants$14.const$4, scope); - } - static CreateInterfaceIterator ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { - try { - return (int)constants$15.const$0.invokeExact(symbol, __x0, __x1, __x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long USBDeviceAbortPipeZero$offset() { + return USBDeviceAbortPipeZero$OFFSET; } - public static VarHandle CreateInterfaceIterator$VH() { - return constants$16.const$5; - } /** * Getter for field: - * {@snippet : - * IOReturn (*CreateInterfaceIterator)(void*,IOUSBFindInterfaceRequest*,io_iterator_t*); + * {@snippet lang=c : + * IOReturn (*USBDeviceAbortPipeZero)(void *) * } */ - public static MemorySegment CreateInterfaceIterator$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$16.const$5.get(seg); + public static MemorySegment USBDeviceAbortPipeZero(MemorySegment struct) { + return struct.get(USBDeviceAbortPipeZero$LAYOUT, USBDeviceAbortPipeZero$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*CreateInterfaceIterator)(void*,IOUSBFindInterfaceRequest*,io_iterator_t*); + * {@snippet lang=c : + * IOReturn (*USBDeviceAbortPipeZero)(void *) * } */ - public static void CreateInterfaceIterator$set(MemorySegment seg, MemorySegment x) { - constants$16.const$5.set(seg, x); - } - public static MemorySegment CreateInterfaceIterator$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$16.const$5.get(seg.asSlice(index*sizeof())); - } - public static void CreateInterfaceIterator$set(MemorySegment seg, long index, MemorySegment x) { - constants$16.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static CreateInterfaceIterator CreateInterfaceIterator(MemorySegment segment, Arena scope) { - return CreateInterfaceIterator.ofAddress(CreateInterfaceIterator$get(segment), scope); + public static void USBDeviceAbortPipeZero(MemorySegment struct, MemorySegment fieldValue) { + struct.set(USBDeviceAbortPipeZero$LAYOUT, USBDeviceAbortPipeZero$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*USBDeviceOpenSeize)(void*); + * {@snippet lang=c : + * IOReturn (*USBGetManufacturerStringIndex)(void *, UInt8 *) * } */ - public interface USBDeviceOpenSeize { + public static class USBGetManufacturerStringIndex { - int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(USBDeviceOpenSeize fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$17.const$0, fi, constants$5.const$5, scope); + USBGetManufacturerStringIndex() { + // Should not be called directly } - static USBDeviceOpenSeize ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (int)constants$6.const$1.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - } - public static VarHandle USBDeviceOpenSeize$VH() { - return constants$17.const$1; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*USBDeviceOpenSeize)(void*); - * } - */ - public static MemorySegment USBDeviceOpenSeize$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$17.const$1.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(USBGetManufacturerStringIndex.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(USBGetManufacturerStringIndex.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout USBGetManufacturerStringIndex$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("USBGetManufacturerStringIndex")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*USBDeviceOpenSeize)(void*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*USBGetManufacturerStringIndex)(void *, UInt8 *) * } */ - public static void USBDeviceOpenSeize$set(MemorySegment seg, MemorySegment x) { - constants$17.const$1.set(seg, x); - } - public static MemorySegment USBDeviceOpenSeize$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$17.const$1.get(seg.asSlice(index*sizeof())); - } - public static void USBDeviceOpenSeize$set(MemorySegment seg, long index, MemorySegment x) { - constants$17.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static USBDeviceOpenSeize USBDeviceOpenSeize(MemorySegment segment, Arena scope) { - return USBDeviceOpenSeize.ofAddress(USBDeviceOpenSeize$get(segment), scope); + public static final AddressLayout USBGetManufacturerStringIndex$layout() { + return USBGetManufacturerStringIndex$LAYOUT; } + + private static final long USBGetManufacturerStringIndex$OFFSET = 272; + /** - * {@snippet : - * IOReturn (*DeviceRequestTO)(void*,IOUSBDevRequestTO*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*USBGetManufacturerStringIndex)(void *, UInt8 *) * } */ - public interface DeviceRequestTO { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(DeviceRequestTO fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$17.const$2, fi, constants$6.const$5, scope); - } - static DeviceRequestTO ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long USBGetManufacturerStringIndex$offset() { + return USBGetManufacturerStringIndex$OFFSET; } - public static VarHandle DeviceRequestTO$VH() { - return constants$17.const$3; - } /** * Getter for field: - * {@snippet : - * IOReturn (*DeviceRequestTO)(void*,IOUSBDevRequestTO*); + * {@snippet lang=c : + * IOReturn (*USBGetManufacturerStringIndex)(void *, UInt8 *) * } */ - public static MemorySegment DeviceRequestTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$17.const$3.get(seg); + public static MemorySegment USBGetManufacturerStringIndex(MemorySegment struct) { + return struct.get(USBGetManufacturerStringIndex$LAYOUT, USBGetManufacturerStringIndex$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*DeviceRequestTO)(void*,IOUSBDevRequestTO*); + * {@snippet lang=c : + * IOReturn (*USBGetManufacturerStringIndex)(void *, UInt8 *) * } */ - public static void DeviceRequestTO$set(MemorySegment seg, MemorySegment x) { - constants$17.const$3.set(seg, x); - } - public static MemorySegment DeviceRequestTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$17.const$3.get(seg.asSlice(index*sizeof())); - } - public static void DeviceRequestTO$set(MemorySegment seg, long index, MemorySegment x) { - constants$17.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static DeviceRequestTO DeviceRequestTO(MemorySegment segment, Arena scope) { - return DeviceRequestTO.ofAddress(DeviceRequestTO$get(segment), scope); + public static void USBGetManufacturerStringIndex(MemorySegment struct, MemorySegment fieldValue) { + struct.set(USBGetManufacturerStringIndex$LAYOUT, USBGetManufacturerStringIndex$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*DeviceRequestAsyncTO)(void*,IOUSBDevRequestTO*,IOAsyncCallback1,void*); + * {@snippet lang=c : + * IOReturn (*USBGetProductStringIndex)(void *, UInt8 *) * } */ - public interface DeviceRequestAsyncTO { + public static class USBGetProductStringIndex { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3); - static MemorySegment allocate(DeviceRequestAsyncTO fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$17.const$4, fi, constants$16.const$0, scope); + USBGetProductStringIndex() { + // Should not be called directly } - static DeviceRequestAsyncTO ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3) -> { - try { - return (int)constants$16.const$2.invokeExact(symbol, __x0, __x1, __x2, __x3); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - } - public static VarHandle DeviceRequestAsyncTO$VH() { - return constants$17.const$5; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*DeviceRequestAsyncTO)(void*,IOUSBDevRequestTO*,IOAsyncCallback1,void*); - * } - */ - public static MemorySegment DeviceRequestAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$17.const$5.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(USBGetProductStringIndex.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(USBGetProductStringIndex.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout USBGetProductStringIndex$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("USBGetProductStringIndex")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*DeviceRequestAsyncTO)(void*,IOUSBDevRequestTO*,IOAsyncCallback1,void*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*USBGetProductStringIndex)(void *, UInt8 *) * } */ - public static void DeviceRequestAsyncTO$set(MemorySegment seg, MemorySegment x) { - constants$17.const$5.set(seg, x); - } - public static MemorySegment DeviceRequestAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$17.const$5.get(seg.asSlice(index*sizeof())); - } - public static void DeviceRequestAsyncTO$set(MemorySegment seg, long index, MemorySegment x) { - constants$17.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static DeviceRequestAsyncTO DeviceRequestAsyncTO(MemorySegment segment, Arena scope) { - return DeviceRequestAsyncTO.ofAddress(DeviceRequestAsyncTO$get(segment), scope); + public static final AddressLayout USBGetProductStringIndex$layout() { + return USBGetProductStringIndex$LAYOUT; } + + private static final long USBGetProductStringIndex$OFFSET = 280; + /** - * {@snippet : - * IOReturn (*USBDeviceSuspend)(void*,Boolean); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*USBGetProductStringIndex)(void *, UInt8 *) * } */ - public interface USBDeviceSuspend { - - int apply(java.lang.foreign.MemorySegment _x0, byte _x1); - static MemorySegment allocate(USBDeviceSuspend fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$18.const$0, fi, constants$14.const$0, scope); - } - static USBDeviceSuspend ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { - try { - return (int)constants$14.const$2.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long USBGetProductStringIndex$offset() { + return USBGetProductStringIndex$OFFSET; } - public static VarHandle USBDeviceSuspend$VH() { - return constants$18.const$1; - } /** * Getter for field: - * {@snippet : - * IOReturn (*USBDeviceSuspend)(void*,Boolean); + * {@snippet lang=c : + * IOReturn (*USBGetProductStringIndex)(void *, UInt8 *) * } */ - public static MemorySegment USBDeviceSuspend$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$18.const$1.get(seg); + public static MemorySegment USBGetProductStringIndex(MemorySegment struct) { + return struct.get(USBGetProductStringIndex$LAYOUT, USBGetProductStringIndex$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*USBDeviceSuspend)(void*,Boolean); + * {@snippet lang=c : + * IOReturn (*USBGetProductStringIndex)(void *, UInt8 *) * } */ - public static void USBDeviceSuspend$set(MemorySegment seg, MemorySegment x) { - constants$18.const$1.set(seg, x); - } - public static MemorySegment USBDeviceSuspend$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$18.const$1.get(seg.asSlice(index*sizeof())); - } - public static void USBDeviceSuspend$set(MemorySegment seg, long index, MemorySegment x) { - constants$18.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static USBDeviceSuspend USBDeviceSuspend(MemorySegment segment, Arena scope) { - return USBDeviceSuspend.ofAddress(USBDeviceSuspend$get(segment), scope); + public static void USBGetProductStringIndex(MemorySegment struct, MemorySegment fieldValue) { + struct.set(USBGetProductStringIndex$LAYOUT, USBGetProductStringIndex$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*USBDeviceAbortPipeZero)(void*); + * {@snippet lang=c : + * IOReturn (*USBGetSerialNumberStringIndex)(void *, UInt8 *) * } */ - public interface USBDeviceAbortPipeZero { + public static class USBGetSerialNumberStringIndex { - int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(USBDeviceAbortPipeZero fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$18.const$2, fi, constants$5.const$5, scope); + USBGetSerialNumberStringIndex() { + // Should not be called directly } - static USBDeviceAbortPipeZero ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (int)constants$6.const$1.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - } - public static VarHandle USBDeviceAbortPipeZero$VH() { - return constants$18.const$3; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*USBDeviceAbortPipeZero)(void*); - * } - */ - public static MemorySegment USBDeviceAbortPipeZero$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$18.const$3.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(USBGetSerialNumberStringIndex.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(USBGetSerialNumberStringIndex.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout USBGetSerialNumberStringIndex$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("USBGetSerialNumberStringIndex")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*USBDeviceAbortPipeZero)(void*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*USBGetSerialNumberStringIndex)(void *, UInt8 *) * } */ - public static void USBDeviceAbortPipeZero$set(MemorySegment seg, MemorySegment x) { - constants$18.const$3.set(seg, x); - } - public static MemorySegment USBDeviceAbortPipeZero$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$18.const$3.get(seg.asSlice(index*sizeof())); - } - public static void USBDeviceAbortPipeZero$set(MemorySegment seg, long index, MemorySegment x) { - constants$18.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static USBDeviceAbortPipeZero USBDeviceAbortPipeZero(MemorySegment segment, Arena scope) { - return USBDeviceAbortPipeZero.ofAddress(USBDeviceAbortPipeZero$get(segment), scope); + public static final AddressLayout USBGetSerialNumberStringIndex$layout() { + return USBGetSerialNumberStringIndex$LAYOUT; } + + private static final long USBGetSerialNumberStringIndex$OFFSET = 288; + /** - * {@snippet : - * IOReturn (*USBGetManufacturerStringIndex)(void*,UInt8*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*USBGetSerialNumberStringIndex)(void *, UInt8 *) * } */ - public interface USBGetManufacturerStringIndex { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(USBGetManufacturerStringIndex fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$18.const$4, fi, constants$6.const$5, scope); - } - static USBGetManufacturerStringIndex ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long USBGetSerialNumberStringIndex$offset() { + return USBGetSerialNumberStringIndex$OFFSET; } - public static VarHandle USBGetManufacturerStringIndex$VH() { - return constants$18.const$5; - } /** * Getter for field: - * {@snippet : - * IOReturn (*USBGetManufacturerStringIndex)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*USBGetSerialNumberStringIndex)(void *, UInt8 *) * } */ - public static MemorySegment USBGetManufacturerStringIndex$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$18.const$5.get(seg); + public static MemorySegment USBGetSerialNumberStringIndex(MemorySegment struct) { + return struct.get(USBGetSerialNumberStringIndex$LAYOUT, USBGetSerialNumberStringIndex$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*USBGetManufacturerStringIndex)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*USBGetSerialNumberStringIndex)(void *, UInt8 *) * } */ - public static void USBGetManufacturerStringIndex$set(MemorySegment seg, MemorySegment x) { - constants$18.const$5.set(seg, x); - } - public static MemorySegment USBGetManufacturerStringIndex$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$18.const$5.get(seg.asSlice(index*sizeof())); - } - public static void USBGetManufacturerStringIndex$set(MemorySegment seg, long index, MemorySegment x) { - constants$18.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static USBGetManufacturerStringIndex USBGetManufacturerStringIndex(MemorySegment segment, Arena scope) { - return USBGetManufacturerStringIndex.ofAddress(USBGetManufacturerStringIndex$get(segment), scope); + public static void USBGetSerialNumberStringIndex(MemorySegment struct, MemorySegment fieldValue) { + struct.set(USBGetSerialNumberStringIndex$LAYOUT, USBGetSerialNumberStringIndex$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*USBGetProductStringIndex)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*USBDeviceReEnumerate)(void *, UInt32) * } */ - public interface USBGetProductStringIndex { + public static class USBDeviceReEnumerate { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(USBGetProductStringIndex fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$19.const$0, fi, constants$6.const$5, scope); + USBDeviceReEnumerate() { + // Should not be called directly } - static USBGetProductStringIndex ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, int _x1); } - } - public static VarHandle USBGetProductStringIndex$VH() { - return constants$19.const$1; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*USBGetProductStringIndex)(void*,UInt8*); - * } - */ - public static MemorySegment USBGetProductStringIndex$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$19.const$1.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_INT + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(USBDeviceReEnumerate.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(USBDeviceReEnumerate.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, int _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout USBDeviceReEnumerate$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("USBDeviceReEnumerate")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*USBGetProductStringIndex)(void*,UInt8*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*USBDeviceReEnumerate)(void *, UInt32) * } */ - public static void USBGetProductStringIndex$set(MemorySegment seg, MemorySegment x) { - constants$19.const$1.set(seg, x); - } - public static MemorySegment USBGetProductStringIndex$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$19.const$1.get(seg.asSlice(index*sizeof())); - } - public static void USBGetProductStringIndex$set(MemorySegment seg, long index, MemorySegment x) { - constants$19.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static USBGetProductStringIndex USBGetProductStringIndex(MemorySegment segment, Arena scope) { - return USBGetProductStringIndex.ofAddress(USBGetProductStringIndex$get(segment), scope); + public static final AddressLayout USBDeviceReEnumerate$layout() { + return USBDeviceReEnumerate$LAYOUT; } + + private static final long USBDeviceReEnumerate$OFFSET = 296; + /** - * {@snippet : - * IOReturn (*USBGetSerialNumberStringIndex)(void*,UInt8*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*USBDeviceReEnumerate)(void *, UInt32) * } */ - public interface USBGetSerialNumberStringIndex { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(USBGetSerialNumberStringIndex fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$19.const$2, fi, constants$6.const$5, scope); - } - static USBGetSerialNumberStringIndex ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long USBDeviceReEnumerate$offset() { + return USBDeviceReEnumerate$OFFSET; } - public static VarHandle USBGetSerialNumberStringIndex$VH() { - return constants$19.const$3; - } /** * Getter for field: - * {@snippet : - * IOReturn (*USBGetSerialNumberStringIndex)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*USBDeviceReEnumerate)(void *, UInt32) * } */ - public static MemorySegment USBGetSerialNumberStringIndex$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$19.const$3.get(seg); + public static MemorySegment USBDeviceReEnumerate(MemorySegment struct) { + return struct.get(USBDeviceReEnumerate$LAYOUT, USBDeviceReEnumerate$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*USBGetSerialNumberStringIndex)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*USBDeviceReEnumerate)(void *, UInt32) * } */ - public static void USBGetSerialNumberStringIndex$set(MemorySegment seg, MemorySegment x) { - constants$19.const$3.set(seg, x); + public static void USBDeviceReEnumerate(MemorySegment struct, MemorySegment fieldValue) { + struct.set(USBDeviceReEnumerate$LAYOUT, USBDeviceReEnumerate$OFFSET, fieldValue); } - public static MemorySegment USBGetSerialNumberStringIndex$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$19.const$3.get(seg.asSlice(index*sizeof())); - } - public static void USBGetSerialNumberStringIndex$set(MemorySegment seg, long index, MemorySegment x) { - constants$19.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static USBGetSerialNumberStringIndex USBGetSerialNumberStringIndex(MemorySegment segment, Arena scope) { - return USBGetSerialNumberStringIndex.ofAddress(USBGetSerialNumberStringIndex$get(segment), scope); + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); } + /** - * {@snippet : - * IOReturn (*USBDeviceReEnumerate)(void*,UInt32); - * } + * The size (in bytes) of this struct */ - public interface USBDeviceReEnumerate { + public static long sizeof() { return layout().byteSize(); } - int apply(java.lang.foreign.MemorySegment _x0, int _x1); - static MemorySegment allocate(USBDeviceReEnumerate fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$19.const$5, fi, constants$19.const$4, scope); - } - static USBDeviceReEnumerate ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, int __x1) -> { - try { - return (int)constants$20.const$0.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static VarHandle USBDeviceReEnumerate$VH() { - return constants$20.const$1; - } /** - * Getter for field: - * {@snippet : - * IOReturn (*USBDeviceReEnumerate)(void*,UInt32); - * } + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. */ - public static MemorySegment USBDeviceReEnumerate$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$20.const$1.get(seg); + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } + /** - * Setter for field: - * {@snippet : - * IOReturn (*USBDeviceReEnumerate)(void*,UInt32); - * } + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} */ - public static void USBDeviceReEnumerate$set(MemorySegment seg, MemorySegment x) { - constants$20.const$1.set(seg, x); - } - public static MemorySegment USBDeviceReEnumerate$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$20.const$1.get(seg.asSlice(index*sizeof())); - } - public static void USBDeviceReEnumerate$set(MemorySegment seg, long index, MemorySegment x) { - constants$20.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static USBDeviceReEnumerate USBDeviceReEnumerate(MemorySegment segment, Arena scope) { - return USBDeviceReEnumerate.ofAddress(USBDeviceReEnumerate$get(segment), scope); + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java index 007fbbfb..f38e6b48 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java @@ -2,140 +2,260 @@ package net.codecrete.usb.macos.gen.iokit; -import java.lang.foreign.Arena; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.lang.foreign.*; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfShort; + /** - * {@snippet : + * {@snippet lang=c : * struct { * UInt16 bInterfaceClass; * UInt16 bInterfaceSubClass; * UInt16 bInterfaceProtocol; * UInt16 bAlternateSetting; - * }; + * } * } */ public class IOUSBFindInterfaceRequest { - public static MemoryLayout $LAYOUT() { - return constants$1.const$2; + IOUSBFindInterfaceRequest() { + // Should not be called directly } - public static VarHandle bInterfaceClass$VH() { - return constants$1.const$3; + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + IOKit.C_SHORT.withName("bInterfaceClass"), + IOKit.C_SHORT.withName("bInterfaceSubClass"), + IOKit.C_SHORT.withName("bInterfaceProtocol"), + IOKit.C_SHORT.withName("bAlternateSetting") + ).withName("IOUSBFindInterfaceRequest"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; } + + private static final OfShort bInterfaceClass$LAYOUT = (OfShort)$LAYOUT.select(groupElement("bInterfaceClass")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt16 bInterfaceClass + * } + */ + public static final OfShort bInterfaceClass$layout() { + return bInterfaceClass$LAYOUT; + } + + private static final long bInterfaceClass$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt16 bInterfaceClass + * } + */ + public static final long bInterfaceClass$offset() { + return bInterfaceClass$OFFSET; + } + /** * Getter for field: - * {@snippet : - * UInt16 bInterfaceClass; + * {@snippet lang=c : + * UInt16 bInterfaceClass * } */ - public static short bInterfaceClass$get(MemorySegment seg) { - return (short)constants$1.const$3.get(seg); + public static short bInterfaceClass(MemorySegment struct) { + return struct.get(bInterfaceClass$LAYOUT, bInterfaceClass$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt16 bInterfaceClass; + * {@snippet lang=c : + * UInt16 bInterfaceClass * } */ - public static void bInterfaceClass$set(MemorySegment seg, short x) { - constants$1.const$3.set(seg, x); + public static void bInterfaceClass(MemorySegment struct, short fieldValue) { + struct.set(bInterfaceClass$LAYOUT, bInterfaceClass$OFFSET, fieldValue); } - public static short bInterfaceClass$get(MemorySegment seg, long index) { - return (short)constants$1.const$3.get(seg.asSlice(index*sizeof())); - } - public static void bInterfaceClass$set(MemorySegment seg, long index, short x) { - constants$1.const$3.set(seg.asSlice(index*sizeof()), x); + + private static final OfShort bInterfaceSubClass$LAYOUT = (OfShort)$LAYOUT.select(groupElement("bInterfaceSubClass")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt16 bInterfaceSubClass + * } + */ + public static final OfShort bInterfaceSubClass$layout() { + return bInterfaceSubClass$LAYOUT; } - public static VarHandle bInterfaceSubClass$VH() { - return constants$1.const$4; + + private static final long bInterfaceSubClass$OFFSET = 2; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt16 bInterfaceSubClass + * } + */ + public static final long bInterfaceSubClass$offset() { + return bInterfaceSubClass$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt16 bInterfaceSubClass; + * {@snippet lang=c : + * UInt16 bInterfaceSubClass * } */ - public static short bInterfaceSubClass$get(MemorySegment seg) { - return (short)constants$1.const$4.get(seg); + public static short bInterfaceSubClass(MemorySegment struct) { + return struct.get(bInterfaceSubClass$LAYOUT, bInterfaceSubClass$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt16 bInterfaceSubClass; + * {@snippet lang=c : + * UInt16 bInterfaceSubClass * } */ - public static void bInterfaceSubClass$set(MemorySegment seg, short x) { - constants$1.const$4.set(seg, x); + public static void bInterfaceSubClass(MemorySegment struct, short fieldValue) { + struct.set(bInterfaceSubClass$LAYOUT, bInterfaceSubClass$OFFSET, fieldValue); } - public static short bInterfaceSubClass$get(MemorySegment seg, long index) { - return (short)constants$1.const$4.get(seg.asSlice(index*sizeof())); - } - public static void bInterfaceSubClass$set(MemorySegment seg, long index, short x) { - constants$1.const$4.set(seg.asSlice(index*sizeof()), x); + + private static final OfShort bInterfaceProtocol$LAYOUT = (OfShort)$LAYOUT.select(groupElement("bInterfaceProtocol")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt16 bInterfaceProtocol + * } + */ + public static final OfShort bInterfaceProtocol$layout() { + return bInterfaceProtocol$LAYOUT; } - public static VarHandle bInterfaceProtocol$VH() { - return constants$1.const$5; + + private static final long bInterfaceProtocol$OFFSET = 4; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt16 bInterfaceProtocol + * } + */ + public static final long bInterfaceProtocol$offset() { + return bInterfaceProtocol$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt16 bInterfaceProtocol; + * {@snippet lang=c : + * UInt16 bInterfaceProtocol * } */ - public static short bInterfaceProtocol$get(MemorySegment seg) { - return (short)constants$1.const$5.get(seg); + public static short bInterfaceProtocol(MemorySegment struct) { + return struct.get(bInterfaceProtocol$LAYOUT, bInterfaceProtocol$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt16 bInterfaceProtocol; + * {@snippet lang=c : + * UInt16 bInterfaceProtocol * } */ - public static void bInterfaceProtocol$set(MemorySegment seg, short x) { - constants$1.const$5.set(seg, x); - } - public static short bInterfaceProtocol$get(MemorySegment seg, long index) { - return (short)constants$1.const$5.get(seg.asSlice(index*sizeof())); + public static void bInterfaceProtocol(MemorySegment struct, short fieldValue) { + struct.set(bInterfaceProtocol$LAYOUT, bInterfaceProtocol$OFFSET, fieldValue); } - public static void bInterfaceProtocol$set(MemorySegment seg, long index, short x) { - constants$1.const$5.set(seg.asSlice(index*sizeof()), x); + + private static final OfShort bAlternateSetting$LAYOUT = (OfShort)$LAYOUT.select(groupElement("bAlternateSetting")); + + /** + * Layout for field: + * {@snippet lang=c : + * UInt16 bAlternateSetting + * } + */ + public static final OfShort bAlternateSetting$layout() { + return bAlternateSetting$LAYOUT; } - public static VarHandle bAlternateSetting$VH() { - return constants$2.const$0; + + private static final long bAlternateSetting$OFFSET = 6; + + /** + * Offset for field: + * {@snippet lang=c : + * UInt16 bAlternateSetting + * } + */ + public static final long bAlternateSetting$offset() { + return bAlternateSetting$OFFSET; } + /** * Getter for field: - * {@snippet : - * UInt16 bAlternateSetting; + * {@snippet lang=c : + * UInt16 bAlternateSetting * } */ - public static short bAlternateSetting$get(MemorySegment seg) { - return (short)constants$2.const$0.get(seg); + public static short bAlternateSetting(MemorySegment struct) { + return struct.get(bAlternateSetting$LAYOUT, bAlternateSetting$OFFSET); } + /** * Setter for field: - * {@snippet : - * UInt16 bAlternateSetting; + * {@snippet lang=c : + * UInt16 bAlternateSetting * } */ - public static void bAlternateSetting$set(MemorySegment seg, short x) { - constants$2.const$0.set(seg, x); + public static void bAlternateSetting(MemorySegment struct, short fieldValue) { + struct.set(bAlternateSetting$LAYOUT, bAlternateSetting$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static short bAlternateSetting$get(MemorySegment seg, long index) { - return (short)constants$2.const$0.get(seg.asSlice(index*sizeof())); + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } - public static void bAlternateSetting$set(MemorySegment seg, long index, short x) { - constants$2.const$0.set(seg.asSlice(index*sizeof()), x); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface190.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface190.java index 44ead20b..15e4f195 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface190.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface190.java @@ -3,14 +3,64 @@ package net.codecrete.usb.macos.gen.iokit; /** - * {@snippet : - * typedef struct IOUSBInterfaceStruct190 IOUSBInterfaceInterface190; + * {@snippet lang=c : + * typedef struct IOUSBInterfaceStruct190 { + * void *_reserved; + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *); + * ULONG (*AddRef)(void *); + * ULONG (*Release)(void *); + * IOReturn (*CreateInterfaceAsyncEventSource)(void *, CFRunLoopSourceRef *); + * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void *); + * IOReturn (*CreateInterfaceAsyncPort)(void *, mach_port_t *); + * mach_port_t (*GetInterfaceAsyncPort)(void *); + * IOReturn (*USBInterfaceOpen)(void *); + * IOReturn (*USBInterfaceClose)(void *); + * IOReturn (*GetInterfaceClass)(void *, UInt8 *); + * IOReturn (*GetInterfaceSubClass)(void *, UInt8 *); + * IOReturn (*GetInterfaceProtocol)(void *, UInt8 *); + * IOReturn (*GetDeviceVendor)(void *, UInt16 *); + * IOReturn (*GetDeviceProduct)(void *, UInt16 *); + * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *); + * IOReturn (*GetConfigurationValue)(void *, UInt8 *); + * IOReturn (*GetInterfaceNumber)(void *, UInt8 *); + * IOReturn (*GetAlternateSetting)(void *, UInt8 *); + * IOReturn (*GetNumEndpoints)(void *, UInt8 *); + * IOReturn (*GetLocationID)(void *, UInt32 *); + * IOReturn (*GetDevice)(void *, io_service_t *); + * IOReturn (*SetAlternateInterface)(void *, UInt8); + * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *); + * IOReturn (*ControlRequest)(void *, UInt8, IOUSBDevRequest *); + * IOReturn (*ControlRequestAsync)(void *, UInt8, IOUSBDevRequest *, IOAsyncCallback1, void *); + * IOReturn (*GetPipeProperties)(void *, UInt8, UInt8 *, UInt8 *, UInt8 *, UInt16 *, UInt8 *); + * IOReturn (*GetPipeStatus)(void *, UInt8); + * IOReturn (*AbortPipe)(void *, UInt8); + * IOReturn (*ResetPipe)(void *, UInt8); + * IOReturn (*ClearPipeStall)(void *, UInt8); + * IOReturn (*ReadPipe)(void *, UInt8, void *, UInt32 *); + * IOReturn (*WritePipe)(void *, UInt8, void *, UInt32); + * IOReturn (*ReadPipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *); + * IOReturn (*WritePipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *); + * IOReturn (*ReadIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *); + * IOReturn (*WriteIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *); + * IOReturn (*ControlRequestTO)(void *, UInt8, IOUSBDevRequestTO *); + * IOReturn (*ControlRequestAsyncTO)(void *, UInt8, IOUSBDevRequestTO *, IOAsyncCallback1, void *); + * IOReturn (*ReadPipeTO)(void *, UInt8, void *, UInt32 *, UInt32, UInt32); + * IOReturn (*WritePipeTO)(void *, UInt8, void *, UInt32, UInt32, UInt32); + * IOReturn (*ReadPipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *); + * IOReturn (*WritePipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *); + * IOReturn (*USBInterfaceGetStringIndex)(void *, UInt8 *); + * IOReturn (*USBInterfaceOpenSeize)(void *); + * IOReturn (*ClearPipeStallBothEnds)(void *, UInt8); + * IOReturn (*SetPipePolicy)(void *, UInt8, UInt16, UInt8); + * IOReturn (*GetBandwidthAvailable)(void *, UInt32 *); + * IOReturn (*GetEndpointProperties)(void *, UInt8, UInt8, UInt8, UInt8 *, UInt16 *, UInt8 *); + * } IOUSBInterfaceInterface190 * } */ -public final class IOUSBInterfaceInterface190 extends IOUSBInterfaceStruct190 { +public class IOUSBInterfaceInterface190 extends IOUSBInterfaceStruct190 { - // Suppresses default constructor, ensuring non-instantiability. - private IOUSBInterfaceInterface190() {} + IOUSBInterfaceInterface190() { + // Should not be called directly + } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java index 0cdc7159..41ed672b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java @@ -2,2648 +2,5029 @@ package net.codecrete.usb.macos.gen.iokit; -import java.lang.foreign.Arena; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; + /** - * {@snippet : + * {@snippet lang=c : * struct IOUSBInterfaceStruct190 { - * void* _reserved; - * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); - * ULONG (*AddRef)(void*); - * ULONG (*Release)(void*); - * IOReturn (*CreateInterfaceAsyncEventSource)(void*,CFRunLoopSourceRef*); - * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void*); - * IOReturn (*CreateInterfaceAsyncPort)(void*,mach_port_t*); - * mach_port_t (*GetInterfaceAsyncPort)(void*); - * IOReturn (*USBInterfaceOpen)(void*); - * IOReturn (*USBInterfaceClose)(void*); - * IOReturn (*GetInterfaceClass)(void*,UInt8*); - * IOReturn (*GetInterfaceSubClass)(void*,UInt8*); - * IOReturn (*GetInterfaceProtocol)(void*,UInt8*); - * IOReturn (*GetDeviceVendor)(void*,UInt16*); - * IOReturn (*GetDeviceProduct)(void*,UInt16*); - * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); - * IOReturn (*GetConfigurationValue)(void*,UInt8*); - * IOReturn (*GetInterfaceNumber)(void*,UInt8*); - * IOReturn (*GetAlternateSetting)(void*,UInt8*); - * IOReturn (*GetNumEndpoints)(void*,UInt8*); - * IOReturn (*GetLocationID)(void*,UInt32*); - * IOReturn (*GetDevice)(void*,io_service_t*); - * IOReturn (*SetAlternateInterface)(void*,UInt8); - * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); - * IOReturn (*ControlRequest)(void*,UInt8,IOUSBDevRequest*); - * IOReturn (*ControlRequestAsync)(void*,UInt8,IOUSBDevRequest*,IOAsyncCallback1,void*); - * IOReturn (*GetPipeProperties)(void*,UInt8,UInt8*,UInt8*,UInt8*,UInt16*,UInt8*); - * IOReturn (*GetPipeStatus)(void*,UInt8); - * IOReturn (*AbortPipe)(void*,UInt8); - * IOReturn (*ResetPipe)(void*,UInt8); - * IOReturn (*ClearPipeStall)(void*,UInt8); - * IOReturn (*ReadPipe)(void*,UInt8,void*,UInt32*); - * IOReturn (*WritePipe)(void*,UInt8,void*,UInt32); - * IOReturn (*ReadPipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); - * IOReturn (*WritePipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); - * IOReturn (*ReadIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); - * IOReturn (*WriteIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); - * IOReturn (*ControlRequestTO)(void*,UInt8,IOUSBDevRequestTO*); - * IOReturn (*ControlRequestAsyncTO)(void*,UInt8,IOUSBDevRequestTO*,IOAsyncCallback1,void*); - * IOReturn (*ReadPipeTO)(void*,UInt8,void*,UInt32*,UInt32,UInt32); - * IOReturn (*WritePipeTO)(void*,UInt8,void*,UInt32,UInt32,UInt32); - * IOReturn (*ReadPipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); - * IOReturn (*WritePipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); - * IOReturn (*USBInterfaceGetStringIndex)(void*,UInt8*); - * IOReturn (*USBInterfaceOpenSeize)(void*); - * IOReturn (*ClearPipeStallBothEnds)(void*,UInt8); - * IOReturn (*SetPipePolicy)(void*,UInt8,UInt16,UInt8); - * IOReturn (*GetBandwidthAvailable)(void*,UInt32*); - * IOReturn (*GetEndpointProperties)(void*,UInt8,UInt8,UInt8,UInt8*,UInt16*,UInt8*); - * }; + * void *_reserved; + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *); + * ULONG (*AddRef)(void *); + * ULONG (*Release)(void *); + * IOReturn (*CreateInterfaceAsyncEventSource)(void *, CFRunLoopSourceRef *); + * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void *); + * IOReturn (*CreateInterfaceAsyncPort)(void *, mach_port_t *); + * mach_port_t (*GetInterfaceAsyncPort)(void *); + * IOReturn (*USBInterfaceOpen)(void *); + * IOReturn (*USBInterfaceClose)(void *); + * IOReturn (*GetInterfaceClass)(void *, UInt8 *); + * IOReturn (*GetInterfaceSubClass)(void *, UInt8 *); + * IOReturn (*GetInterfaceProtocol)(void *, UInt8 *); + * IOReturn (*GetDeviceVendor)(void *, UInt16 *); + * IOReturn (*GetDeviceProduct)(void *, UInt16 *); + * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *); + * IOReturn (*GetConfigurationValue)(void *, UInt8 *); + * IOReturn (*GetInterfaceNumber)(void *, UInt8 *); + * IOReturn (*GetAlternateSetting)(void *, UInt8 *); + * IOReturn (*GetNumEndpoints)(void *, UInt8 *); + * IOReturn (*GetLocationID)(void *, UInt32 *); + * IOReturn (*GetDevice)(void *, io_service_t *); + * IOReturn (*SetAlternateInterface)(void *, UInt8); + * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *); + * IOReturn (*ControlRequest)(void *, UInt8, IOUSBDevRequest *); + * IOReturn (*ControlRequestAsync)(void *, UInt8, IOUSBDevRequest *, IOAsyncCallback1, void *); + * IOReturn (*GetPipeProperties)(void *, UInt8, UInt8 *, UInt8 *, UInt8 *, UInt16 *, UInt8 *); + * IOReturn (*GetPipeStatus)(void *, UInt8); + * IOReturn (*AbortPipe)(void *, UInt8); + * IOReturn (*ResetPipe)(void *, UInt8); + * IOReturn (*ClearPipeStall)(void *, UInt8); + * IOReturn (*ReadPipe)(void *, UInt8, void *, UInt32 *); + * IOReturn (*WritePipe)(void *, UInt8, void *, UInt32); + * IOReturn (*ReadPipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *); + * IOReturn (*WritePipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *); + * IOReturn (*ReadIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *); + * IOReturn (*WriteIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *); + * IOReturn (*ControlRequestTO)(void *, UInt8, IOUSBDevRequestTO *); + * IOReturn (*ControlRequestAsyncTO)(void *, UInt8, IOUSBDevRequestTO *, IOAsyncCallback1, void *); + * IOReturn (*ReadPipeTO)(void *, UInt8, void *, UInt32 *, UInt32, UInt32); + * IOReturn (*WritePipeTO)(void *, UInt8, void *, UInt32, UInt32, UInt32); + * IOReturn (*ReadPipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *); + * IOReturn (*WritePipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *); + * IOReturn (*USBInterfaceGetStringIndex)(void *, UInt8 *); + * IOReturn (*USBInterfaceOpenSeize)(void *); + * IOReturn (*ClearPipeStallBothEnds)(void *, UInt8); + * IOReturn (*SetPipePolicy)(void *, UInt8, UInt16, UInt8); + * IOReturn (*GetBandwidthAvailable)(void *, UInt32 *); + * IOReturn (*GetEndpointProperties)(void *, UInt8, UInt8, UInt8, UInt8 *, UInt16 *, UInt8 *); + * } * } */ public class IOUSBInterfaceStruct190 { - public static MemoryLayout $LAYOUT() { - return constants$20.const$2; - } - public static VarHandle _reserved$VH() { - return constants$20.const$3; + IOUSBInterfaceStruct190() { + // Should not be called directly } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + IOKit.C_POINTER.withName("_reserved"), + IOKit.C_POINTER.withName("QueryInterface"), + IOKit.C_POINTER.withName("AddRef"), + IOKit.C_POINTER.withName("Release"), + IOKit.C_POINTER.withName("CreateInterfaceAsyncEventSource"), + IOKit.C_POINTER.withName("GetInterfaceAsyncEventSource"), + IOKit.C_POINTER.withName("CreateInterfaceAsyncPort"), + IOKit.C_POINTER.withName("GetInterfaceAsyncPort"), + IOKit.C_POINTER.withName("USBInterfaceOpen"), + IOKit.C_POINTER.withName("USBInterfaceClose"), + IOKit.C_POINTER.withName("GetInterfaceClass"), + IOKit.C_POINTER.withName("GetInterfaceSubClass"), + IOKit.C_POINTER.withName("GetInterfaceProtocol"), + IOKit.C_POINTER.withName("GetDeviceVendor"), + IOKit.C_POINTER.withName("GetDeviceProduct"), + IOKit.C_POINTER.withName("GetDeviceReleaseNumber"), + IOKit.C_POINTER.withName("GetConfigurationValue"), + IOKit.C_POINTER.withName("GetInterfaceNumber"), + IOKit.C_POINTER.withName("GetAlternateSetting"), + IOKit.C_POINTER.withName("GetNumEndpoints"), + IOKit.C_POINTER.withName("GetLocationID"), + IOKit.C_POINTER.withName("GetDevice"), + IOKit.C_POINTER.withName("SetAlternateInterface"), + IOKit.C_POINTER.withName("GetBusFrameNumber"), + IOKit.C_POINTER.withName("ControlRequest"), + IOKit.C_POINTER.withName("ControlRequestAsync"), + IOKit.C_POINTER.withName("GetPipeProperties"), + IOKit.C_POINTER.withName("GetPipeStatus"), + IOKit.C_POINTER.withName("AbortPipe"), + IOKit.C_POINTER.withName("ResetPipe"), + IOKit.C_POINTER.withName("ClearPipeStall"), + IOKit.C_POINTER.withName("ReadPipe"), + IOKit.C_POINTER.withName("WritePipe"), + IOKit.C_POINTER.withName("ReadPipeAsync"), + IOKit.C_POINTER.withName("WritePipeAsync"), + IOKit.C_POINTER.withName("ReadIsochPipeAsync"), + IOKit.C_POINTER.withName("WriteIsochPipeAsync"), + IOKit.C_POINTER.withName("ControlRequestTO"), + IOKit.C_POINTER.withName("ControlRequestAsyncTO"), + IOKit.C_POINTER.withName("ReadPipeTO"), + IOKit.C_POINTER.withName("WritePipeTO"), + IOKit.C_POINTER.withName("ReadPipeAsyncTO"), + IOKit.C_POINTER.withName("WritePipeAsyncTO"), + IOKit.C_POINTER.withName("USBInterfaceGetStringIndex"), + IOKit.C_POINTER.withName("USBInterfaceOpenSeize"), + IOKit.C_POINTER.withName("ClearPipeStallBothEnds"), + IOKit.C_POINTER.withName("SetPipePolicy"), + IOKit.C_POINTER.withName("GetBandwidthAvailable"), + IOKit.C_POINTER.withName("GetEndpointProperties") + ).withName("IOUSBInterfaceStruct190"); + /** - * Getter for field: - * {@snippet : - * void* _reserved; - * } + * The layout of this struct */ - public static MemorySegment _reserved$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$20.const$3.get(seg); + public static final GroupLayout layout() { + return $LAYOUT; } + + private static final AddressLayout _reserved$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("_reserved")); + /** - * Setter for field: - * {@snippet : - * void* _reserved; + * Layout for field: + * {@snippet lang=c : + * void *_reserved * } */ - public static void _reserved$set(MemorySegment seg, MemorySegment x) { - constants$20.const$3.set(seg, x); - } - public static MemorySegment _reserved$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$20.const$3.get(seg.asSlice(index*sizeof())); - } - public static void _reserved$set(MemorySegment seg, long index, MemorySegment x) { - constants$20.const$3.set(seg.asSlice(index*sizeof()), x); + public static final AddressLayout _reserved$layout() { + return _reserved$LAYOUT; } + + private static final long _reserved$OFFSET = 0; + /** - * {@snippet : - * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * Offset for field: + * {@snippet lang=c : + * void *_reserved * } */ - public interface QueryInterface { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(QueryInterface fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$20.const$4, fi, constants$5.const$1, scope); - } - static QueryInterface ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { - try { - return (int)constants$5.const$3.invokeExact(symbol, __x0, __x1, __x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long _reserved$offset() { + return _reserved$OFFSET; } - public static VarHandle QueryInterface$VH() { - return constants$20.const$5; - } /** * Getter for field: - * {@snippet : - * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * {@snippet lang=c : + * void *_reserved * } */ - public static MemorySegment QueryInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$20.const$5.get(seg); + public static MemorySegment _reserved(MemorySegment struct) { + return struct.get(_reserved$LAYOUT, _reserved$OFFSET); } + /** * Setter for field: - * {@snippet : - * HRESULT (*QueryInterface)(void*,REFIID,LPVOID*); + * {@snippet lang=c : + * void *_reserved * } */ - public static void QueryInterface$set(MemorySegment seg, MemorySegment x) { - constants$20.const$5.set(seg, x); - } - public static MemorySegment QueryInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$20.const$5.get(seg.asSlice(index*sizeof())); - } - public static void QueryInterface$set(MemorySegment seg, long index, MemorySegment x) { - constants$20.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static QueryInterface QueryInterface(MemorySegment segment, Arena scope) { - return QueryInterface.ofAddress(QueryInterface$get(segment), scope); + public static void _reserved(MemorySegment struct, MemorySegment fieldValue) { + struct.set(_reserved$LAYOUT, _reserved$OFFSET, fieldValue); } + /** - * {@snippet : - * ULONG (*AddRef)(void*); + * {@snippet lang=c : + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) * } */ - public interface AddRef { + public static class QueryInterface { - int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(AddRef fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$21.const$0, fi, constants$5.const$5, scope); + QueryInterface() { + // Should not be called directly } - static AddRef ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (int)constants$6.const$1.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1, MemorySegment _x2); } - } - public static VarHandle AddRef$VH() { - return constants$21.const$1; - } - /** - * Getter for field: - * {@snippet : - * ULONG (*AddRef)(void*); - * } - */ - public static MemorySegment AddRef$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$21.const$1.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + CFUUIDBytes.layout(), + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(QueryInterface.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(QueryInterface.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout QueryInterface$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("QueryInterface")); + /** - * Setter for field: - * {@snippet : - * ULONG (*AddRef)(void*); + * Layout for field: + * {@snippet lang=c : + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) * } */ - public static void AddRef$set(MemorySegment seg, MemorySegment x) { - constants$21.const$1.set(seg, x); - } - public static MemorySegment AddRef$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$21.const$1.get(seg.asSlice(index*sizeof())); - } - public static void AddRef$set(MemorySegment seg, long index, MemorySegment x) { - constants$21.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static AddRef AddRef(MemorySegment segment, Arena scope) { - return AddRef.ofAddress(AddRef$get(segment), scope); + public static final AddressLayout QueryInterface$layout() { + return QueryInterface$LAYOUT; } + + private static final long QueryInterface$OFFSET = 8; + /** - * {@snippet : - * ULONG (*Release)(void*); + * Offset for field: + * {@snippet lang=c : + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) * } */ - public interface Release { - - int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(Release fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$21.const$2, fi, constants$5.const$5, scope); - } - static Release ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (int)constants$6.const$1.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long QueryInterface$offset() { + return QueryInterface$OFFSET; } - public static VarHandle Release$VH() { - return constants$21.const$3; - } /** * Getter for field: - * {@snippet : - * ULONG (*Release)(void*); + * {@snippet lang=c : + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) * } */ - public static MemorySegment Release$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$21.const$3.get(seg); + public static MemorySegment QueryInterface(MemorySegment struct) { + return struct.get(QueryInterface$LAYOUT, QueryInterface$OFFSET); } + /** * Setter for field: - * {@snippet : - * ULONG (*Release)(void*); + * {@snippet lang=c : + * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) * } */ - public static void Release$set(MemorySegment seg, MemorySegment x) { - constants$21.const$3.set(seg, x); - } - public static MemorySegment Release$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$21.const$3.get(seg.asSlice(index*sizeof())); - } - public static void Release$set(MemorySegment seg, long index, MemorySegment x) { - constants$21.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static Release Release(MemorySegment segment, Arena scope) { - return Release.ofAddress(Release$get(segment), scope); + public static void QueryInterface(MemorySegment struct, MemorySegment fieldValue) { + struct.set(QueryInterface$LAYOUT, QueryInterface$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*CreateInterfaceAsyncEventSource)(void*,CFRunLoopSourceRef*); + * {@snippet lang=c : + * ULONG (*AddRef)(void *) * } */ - public interface CreateInterfaceAsyncEventSource { + public static class AddRef { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(CreateInterfaceAsyncEventSource fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$21.const$4, fi, constants$6.const$5, scope); + AddRef() { + // Should not be called directly } - static CreateInterfaceAsyncEventSource ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0); } - } - public static VarHandle CreateInterfaceAsyncEventSource$VH() { - return constants$21.const$5; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*CreateInterfaceAsyncEventSource)(void*,CFRunLoopSourceRef*); - * } - */ - public static MemorySegment CreateInterfaceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$21.const$5.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(AddRef.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(AddRef.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout AddRef$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("AddRef")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*CreateInterfaceAsyncEventSource)(void*,CFRunLoopSourceRef*); + * Layout for field: + * {@snippet lang=c : + * ULONG (*AddRef)(void *) * } */ - public static void CreateInterfaceAsyncEventSource$set(MemorySegment seg, MemorySegment x) { - constants$21.const$5.set(seg, x); - } - public static MemorySegment CreateInterfaceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$21.const$5.get(seg.asSlice(index*sizeof())); - } - public static void CreateInterfaceAsyncEventSource$set(MemorySegment seg, long index, MemorySegment x) { - constants$21.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static CreateInterfaceAsyncEventSource CreateInterfaceAsyncEventSource(MemorySegment segment, Arena scope) { - return CreateInterfaceAsyncEventSource.ofAddress(CreateInterfaceAsyncEventSource$get(segment), scope); + public static final AddressLayout AddRef$layout() { + return AddRef$LAYOUT; } + + private static final long AddRef$OFFSET = 16; + /** - * {@snippet : - * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void*); + * Offset for field: + * {@snippet lang=c : + * ULONG (*AddRef)(void *) * } */ - public interface GetInterfaceAsyncEventSource { - - java.lang.foreign.MemorySegment apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(GetInterfaceAsyncEventSource fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$22.const$0, fi, constants$3.const$0, scope); - } - static GetInterfaceAsyncEventSource ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (java.lang.foreign.MemorySegment)constants$7.const$4.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long AddRef$offset() { + return AddRef$OFFSET; } - public static VarHandle GetInterfaceAsyncEventSource$VH() { - return constants$22.const$1; - } /** * Getter for field: - * {@snippet : - * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void*); + * {@snippet lang=c : + * ULONG (*AddRef)(void *) * } */ - public static MemorySegment GetInterfaceAsyncEventSource$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$22.const$1.get(seg); + public static MemorySegment AddRef(MemorySegment struct) { + return struct.get(AddRef$LAYOUT, AddRef$OFFSET); } + /** * Setter for field: - * {@snippet : - * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void*); + * {@snippet lang=c : + * ULONG (*AddRef)(void *) * } */ - public static void GetInterfaceAsyncEventSource$set(MemorySegment seg, MemorySegment x) { - constants$22.const$1.set(seg, x); - } - public static MemorySegment GetInterfaceAsyncEventSource$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$22.const$1.get(seg.asSlice(index*sizeof())); - } - public static void GetInterfaceAsyncEventSource$set(MemorySegment seg, long index, MemorySegment x) { - constants$22.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static GetInterfaceAsyncEventSource GetInterfaceAsyncEventSource(MemorySegment segment, Arena scope) { - return GetInterfaceAsyncEventSource.ofAddress(GetInterfaceAsyncEventSource$get(segment), scope); + public static void AddRef(MemorySegment struct, MemorySegment fieldValue) { + struct.set(AddRef$LAYOUT, AddRef$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*CreateInterfaceAsyncPort)(void*,mach_port_t*); + * {@snippet lang=c : + * ULONG (*Release)(void *) * } */ - public interface CreateInterfaceAsyncPort { + public static class Release { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(CreateInterfaceAsyncPort fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$22.const$2, fi, constants$6.const$5, scope); + Release() { + // Should not be called directly } - static CreateInterfaceAsyncPort ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0); } - } - public static VarHandle CreateInterfaceAsyncPort$VH() { - return constants$22.const$3; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*CreateInterfaceAsyncPort)(void*,mach_port_t*); - * } - */ - public static MemorySegment CreateInterfaceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$22.const$3.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(Release.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(Release.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout Release$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("Release")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*CreateInterfaceAsyncPort)(void*,mach_port_t*); + * Layout for field: + * {@snippet lang=c : + * ULONG (*Release)(void *) * } */ - public static void CreateInterfaceAsyncPort$set(MemorySegment seg, MemorySegment x) { - constants$22.const$3.set(seg, x); - } - public static MemorySegment CreateInterfaceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$22.const$3.get(seg.asSlice(index*sizeof())); - } - public static void CreateInterfaceAsyncPort$set(MemorySegment seg, long index, MemorySegment x) { - constants$22.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static CreateInterfaceAsyncPort CreateInterfaceAsyncPort(MemorySegment segment, Arena scope) { - return CreateInterfaceAsyncPort.ofAddress(CreateInterfaceAsyncPort$get(segment), scope); + public static final AddressLayout Release$layout() { + return Release$LAYOUT; } + + private static final long Release$OFFSET = 24; + /** - * {@snippet : - * mach_port_t (*GetInterfaceAsyncPort)(void*); + * Offset for field: + * {@snippet lang=c : + * ULONG (*Release)(void *) * } */ - public interface GetInterfaceAsyncPort { - - int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(GetInterfaceAsyncPort fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$22.const$4, fi, constants$5.const$5, scope); - } - static GetInterfaceAsyncPort ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (int)constants$6.const$1.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long Release$offset() { + return Release$OFFSET; } - public static VarHandle GetInterfaceAsyncPort$VH() { - return constants$22.const$5; - } /** * Getter for field: - * {@snippet : - * mach_port_t (*GetInterfaceAsyncPort)(void*); + * {@snippet lang=c : + * ULONG (*Release)(void *) * } */ - public static MemorySegment GetInterfaceAsyncPort$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$22.const$5.get(seg); + public static MemorySegment Release(MemorySegment struct) { + return struct.get(Release$LAYOUT, Release$OFFSET); } + /** * Setter for field: - * {@snippet : - * mach_port_t (*GetInterfaceAsyncPort)(void*); + * {@snippet lang=c : + * ULONG (*Release)(void *) * } */ - public static void GetInterfaceAsyncPort$set(MemorySegment seg, MemorySegment x) { - constants$22.const$5.set(seg, x); - } - public static MemorySegment GetInterfaceAsyncPort$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$22.const$5.get(seg.asSlice(index*sizeof())); - } - public static void GetInterfaceAsyncPort$set(MemorySegment seg, long index, MemorySegment x) { - constants$22.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static GetInterfaceAsyncPort GetInterfaceAsyncPort(MemorySegment segment, Arena scope) { - return GetInterfaceAsyncPort.ofAddress(GetInterfaceAsyncPort$get(segment), scope); + public static void Release(MemorySegment struct, MemorySegment fieldValue) { + struct.set(Release$LAYOUT, Release$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*USBInterfaceOpen)(void*); + * {@snippet lang=c : + * IOReturn (*CreateInterfaceAsyncEventSource)(void *, CFRunLoopSourceRef *) * } */ - public interface USBInterfaceOpen { + public static class CreateInterfaceAsyncEventSource { - int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(USBInterfaceOpen fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$23.const$0, fi, constants$5.const$5, scope); + CreateInterfaceAsyncEventSource() { + // Should not be called directly } - static USBInterfaceOpen ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (int)constants$6.const$1.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - } - public static VarHandle USBInterfaceOpen$VH() { - return constants$23.const$1; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*USBInterfaceOpen)(void*); - * } - */ - public static MemorySegment USBInterfaceOpen$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$23.const$1.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(CreateInterfaceAsyncEventSource.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(CreateInterfaceAsyncEventSource.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout CreateInterfaceAsyncEventSource$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("CreateInterfaceAsyncEventSource")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*USBInterfaceOpen)(void*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*CreateInterfaceAsyncEventSource)(void *, CFRunLoopSourceRef *) * } */ - public static void USBInterfaceOpen$set(MemorySegment seg, MemorySegment x) { - constants$23.const$1.set(seg, x); - } - public static MemorySegment USBInterfaceOpen$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$23.const$1.get(seg.asSlice(index*sizeof())); - } - public static void USBInterfaceOpen$set(MemorySegment seg, long index, MemorySegment x) { - constants$23.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static USBInterfaceOpen USBInterfaceOpen(MemorySegment segment, Arena scope) { - return USBInterfaceOpen.ofAddress(USBInterfaceOpen$get(segment), scope); + public static final AddressLayout CreateInterfaceAsyncEventSource$layout() { + return CreateInterfaceAsyncEventSource$LAYOUT; } + + private static final long CreateInterfaceAsyncEventSource$OFFSET = 32; + /** - * {@snippet : - * IOReturn (*USBInterfaceClose)(void*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*CreateInterfaceAsyncEventSource)(void *, CFRunLoopSourceRef *) * } */ - public interface USBInterfaceClose { - - int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(USBInterfaceClose fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$23.const$2, fi, constants$5.const$5, scope); - } - static USBInterfaceClose ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (int)constants$6.const$1.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long CreateInterfaceAsyncEventSource$offset() { + return CreateInterfaceAsyncEventSource$OFFSET; } - public static VarHandle USBInterfaceClose$VH() { - return constants$23.const$3; - } /** * Getter for field: - * {@snippet : - * IOReturn (*USBInterfaceClose)(void*); + * {@snippet lang=c : + * IOReturn (*CreateInterfaceAsyncEventSource)(void *, CFRunLoopSourceRef *) * } */ - public static MemorySegment USBInterfaceClose$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$23.const$3.get(seg); + public static MemorySegment CreateInterfaceAsyncEventSource(MemorySegment struct) { + return struct.get(CreateInterfaceAsyncEventSource$LAYOUT, CreateInterfaceAsyncEventSource$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*USBInterfaceClose)(void*); + * {@snippet lang=c : + * IOReturn (*CreateInterfaceAsyncEventSource)(void *, CFRunLoopSourceRef *) * } */ - public static void USBInterfaceClose$set(MemorySegment seg, MemorySegment x) { - constants$23.const$3.set(seg, x); - } - public static MemorySegment USBInterfaceClose$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$23.const$3.get(seg.asSlice(index*sizeof())); - } - public static void USBInterfaceClose$set(MemorySegment seg, long index, MemorySegment x) { - constants$23.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static USBInterfaceClose USBInterfaceClose(MemorySegment segment, Arena scope) { - return USBInterfaceClose.ofAddress(USBInterfaceClose$get(segment), scope); + public static void CreateInterfaceAsyncEventSource(MemorySegment struct, MemorySegment fieldValue) { + struct.set(CreateInterfaceAsyncEventSource$LAYOUT, CreateInterfaceAsyncEventSource$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*GetInterfaceClass)(void*,UInt8*); + * {@snippet lang=c : + * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void *) * } */ - public interface GetInterfaceClass { + public static class GetInterfaceAsyncEventSource { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetInterfaceClass fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$23.const$4, fi, constants$6.const$5, scope); + GetInterfaceAsyncEventSource() { + // Should not be called directly } - static GetInterfaceClass ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + MemorySegment apply(MemorySegment _x0); } - } - public static VarHandle GetInterfaceClass$VH() { - return constants$23.const$5; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*GetInterfaceClass)(void*,UInt8*); - * } - */ - public static MemorySegment GetInterfaceClass$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$23.const$5.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetInterfaceAsyncEventSource.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetInterfaceAsyncEventSource.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static MemorySegment invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (MemorySegment) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout GetInterfaceAsyncEventSource$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetInterfaceAsyncEventSource")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*GetInterfaceClass)(void*,UInt8*); + * Layout for field: + * {@snippet lang=c : + * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void *) * } */ - public static void GetInterfaceClass$set(MemorySegment seg, MemorySegment x) { - constants$23.const$5.set(seg, x); - } - public static MemorySegment GetInterfaceClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$23.const$5.get(seg.asSlice(index*sizeof())); - } - public static void GetInterfaceClass$set(MemorySegment seg, long index, MemorySegment x) { - constants$23.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static GetInterfaceClass GetInterfaceClass(MemorySegment segment, Arena scope) { - return GetInterfaceClass.ofAddress(GetInterfaceClass$get(segment), scope); + public static final AddressLayout GetInterfaceAsyncEventSource$layout() { + return GetInterfaceAsyncEventSource$LAYOUT; } + + private static final long GetInterfaceAsyncEventSource$OFFSET = 40; + /** - * {@snippet : - * IOReturn (*GetInterfaceSubClass)(void*,UInt8*); + * Offset for field: + * {@snippet lang=c : + * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void *) * } */ - public interface GetInterfaceSubClass { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetInterfaceSubClass fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$24.const$0, fi, constants$6.const$5, scope); - } - static GetInterfaceSubClass ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long GetInterfaceAsyncEventSource$offset() { + return GetInterfaceAsyncEventSource$OFFSET; } - public static VarHandle GetInterfaceSubClass$VH() { - return constants$24.const$1; - } /** * Getter for field: - * {@snippet : - * IOReturn (*GetInterfaceSubClass)(void*,UInt8*); + * {@snippet lang=c : + * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void *) * } */ - public static MemorySegment GetInterfaceSubClass$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$24.const$1.get(seg); + public static MemorySegment GetInterfaceAsyncEventSource(MemorySegment struct) { + return struct.get(GetInterfaceAsyncEventSource$LAYOUT, GetInterfaceAsyncEventSource$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetInterfaceSubClass)(void*,UInt8*); + * {@snippet lang=c : + * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void *) * } */ - public static void GetInterfaceSubClass$set(MemorySegment seg, MemorySegment x) { - constants$24.const$1.set(seg, x); - } - public static MemorySegment GetInterfaceSubClass$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$24.const$1.get(seg.asSlice(index*sizeof())); - } - public static void GetInterfaceSubClass$set(MemorySegment seg, long index, MemorySegment x) { - constants$24.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static GetInterfaceSubClass GetInterfaceSubClass(MemorySegment segment, Arena scope) { - return GetInterfaceSubClass.ofAddress(GetInterfaceSubClass$get(segment), scope); + public static void GetInterfaceAsyncEventSource(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetInterfaceAsyncEventSource$LAYOUT, GetInterfaceAsyncEventSource$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*GetInterfaceProtocol)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*CreateInterfaceAsyncPort)(void *, mach_port_t *) * } */ - public interface GetInterfaceProtocol { + public static class CreateInterfaceAsyncPort { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetInterfaceProtocol fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$24.const$2, fi, constants$6.const$5, scope); + CreateInterfaceAsyncPort() { + // Should not be called directly } - static GetInterfaceProtocol ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - } - public static VarHandle GetInterfaceProtocol$VH() { - return constants$24.const$3; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*GetInterfaceProtocol)(void*,UInt8*); - * } - */ - public static MemorySegment GetInterfaceProtocol$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$24.const$3.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(CreateInterfaceAsyncPort.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(CreateInterfaceAsyncPort.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout CreateInterfaceAsyncPort$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("CreateInterfaceAsyncPort")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*GetInterfaceProtocol)(void*,UInt8*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*CreateInterfaceAsyncPort)(void *, mach_port_t *) * } */ - public static void GetInterfaceProtocol$set(MemorySegment seg, MemorySegment x) { - constants$24.const$3.set(seg, x); - } - public static MemorySegment GetInterfaceProtocol$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$24.const$3.get(seg.asSlice(index*sizeof())); - } - public static void GetInterfaceProtocol$set(MemorySegment seg, long index, MemorySegment x) { - constants$24.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static GetInterfaceProtocol GetInterfaceProtocol(MemorySegment segment, Arena scope) { - return GetInterfaceProtocol.ofAddress(GetInterfaceProtocol$get(segment), scope); + public static final AddressLayout CreateInterfaceAsyncPort$layout() { + return CreateInterfaceAsyncPort$LAYOUT; } + + private static final long CreateInterfaceAsyncPort$OFFSET = 48; + /** - * {@snippet : - * IOReturn (*GetDeviceVendor)(void*,UInt16*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*CreateInterfaceAsyncPort)(void *, mach_port_t *) * } */ - public interface GetDeviceVendor { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceVendor fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$24.const$4, fi, constants$6.const$5, scope); - } - static GetDeviceVendor ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long CreateInterfaceAsyncPort$offset() { + return CreateInterfaceAsyncPort$OFFSET; } - public static VarHandle GetDeviceVendor$VH() { - return constants$24.const$5; - } /** * Getter for field: - * {@snippet : - * IOReturn (*GetDeviceVendor)(void*,UInt16*); + * {@snippet lang=c : + * IOReturn (*CreateInterfaceAsyncPort)(void *, mach_port_t *) * } */ - public static MemorySegment GetDeviceVendor$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$24.const$5.get(seg); + public static MemorySegment CreateInterfaceAsyncPort(MemorySegment struct) { + return struct.get(CreateInterfaceAsyncPort$LAYOUT, CreateInterfaceAsyncPort$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetDeviceVendor)(void*,UInt16*); + * {@snippet lang=c : + * IOReturn (*CreateInterfaceAsyncPort)(void *, mach_port_t *) * } */ - public static void GetDeviceVendor$set(MemorySegment seg, MemorySegment x) { - constants$24.const$5.set(seg, x); - } - public static MemorySegment GetDeviceVendor$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$24.const$5.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceVendor$set(MemorySegment seg, long index, MemorySegment x) { - constants$24.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceVendor GetDeviceVendor(MemorySegment segment, Arena scope) { - return GetDeviceVendor.ofAddress(GetDeviceVendor$get(segment), scope); + public static void CreateInterfaceAsyncPort(MemorySegment struct, MemorySegment fieldValue) { + struct.set(CreateInterfaceAsyncPort$LAYOUT, CreateInterfaceAsyncPort$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*GetDeviceProduct)(void*,UInt16*); + * {@snippet lang=c : + * mach_port_t (*GetInterfaceAsyncPort)(void *) * } */ - public interface GetDeviceProduct { + public static class GetInterfaceAsyncPort { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceProduct fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$25.const$0, fi, constants$6.const$5, scope); + GetInterfaceAsyncPort() { + // Should not be called directly } - static GetDeviceProduct ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0); } - } - public static VarHandle GetDeviceProduct$VH() { - return constants$25.const$1; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*GetDeviceProduct)(void*,UInt16*); - * } - */ - public static MemorySegment GetDeviceProduct$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$25.const$1.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetInterfaceAsyncPort.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetInterfaceAsyncPort.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout GetInterfaceAsyncPort$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetInterfaceAsyncPort")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*GetDeviceProduct)(void*,UInt16*); + * Layout for field: + * {@snippet lang=c : + * mach_port_t (*GetInterfaceAsyncPort)(void *) * } */ - public static void GetDeviceProduct$set(MemorySegment seg, MemorySegment x) { - constants$25.const$1.set(seg, x); - } - public static MemorySegment GetDeviceProduct$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$25.const$1.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceProduct$set(MemorySegment seg, long index, MemorySegment x) { - constants$25.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceProduct GetDeviceProduct(MemorySegment segment, Arena scope) { - return GetDeviceProduct.ofAddress(GetDeviceProduct$get(segment), scope); + public static final AddressLayout GetInterfaceAsyncPort$layout() { + return GetInterfaceAsyncPort$LAYOUT; } + + private static final long GetInterfaceAsyncPort$OFFSET = 56; + /** - * {@snippet : - * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); + * Offset for field: + * {@snippet lang=c : + * mach_port_t (*GetInterfaceAsyncPort)(void *) * } */ - public interface GetDeviceReleaseNumber { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDeviceReleaseNumber fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$25.const$2, fi, constants$6.const$5, scope); - } - static GetDeviceReleaseNumber ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long GetInterfaceAsyncPort$offset() { + return GetInterfaceAsyncPort$OFFSET; } - public static VarHandle GetDeviceReleaseNumber$VH() { - return constants$25.const$3; - } /** * Getter for field: - * {@snippet : - * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); + * {@snippet lang=c : + * mach_port_t (*GetInterfaceAsyncPort)(void *) * } */ - public static MemorySegment GetDeviceReleaseNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$25.const$3.get(seg); + public static MemorySegment GetInterfaceAsyncPort(MemorySegment struct) { + return struct.get(GetInterfaceAsyncPort$LAYOUT, GetInterfaceAsyncPort$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetDeviceReleaseNumber)(void*,UInt16*); + * {@snippet lang=c : + * mach_port_t (*GetInterfaceAsyncPort)(void *) * } */ - public static void GetDeviceReleaseNumber$set(MemorySegment seg, MemorySegment x) { - constants$25.const$3.set(seg, x); - } - public static MemorySegment GetDeviceReleaseNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$25.const$3.get(seg.asSlice(index*sizeof())); - } - public static void GetDeviceReleaseNumber$set(MemorySegment seg, long index, MemorySegment x) { - constants$25.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static GetDeviceReleaseNumber GetDeviceReleaseNumber(MemorySegment segment, Arena scope) { - return GetDeviceReleaseNumber.ofAddress(GetDeviceReleaseNumber$get(segment), scope); + public static void GetInterfaceAsyncPort(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetInterfaceAsyncPort$LAYOUT, GetInterfaceAsyncPort$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*GetConfigurationValue)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*USBInterfaceOpen)(void *) * } */ - public interface GetConfigurationValue { + public static class USBInterfaceOpen { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetConfigurationValue fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$25.const$4, fi, constants$6.const$5, scope); + USBInterfaceOpen() { + // Should not be called directly } - static GetConfigurationValue ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0); } - } - public static VarHandle GetConfigurationValue$VH() { - return constants$25.const$5; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*GetConfigurationValue)(void*,UInt8*); - * } - */ - public static MemorySegment GetConfigurationValue$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$25.const$5.get(seg); - } + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(USBInterfaceOpen.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(USBInterfaceOpen.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout USBInterfaceOpen$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("USBInterfaceOpen")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*GetConfigurationValue)(void*,UInt8*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*USBInterfaceOpen)(void *) * } */ - public static void GetConfigurationValue$set(MemorySegment seg, MemorySegment x) { - constants$25.const$5.set(seg, x); - } - public static MemorySegment GetConfigurationValue$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$25.const$5.get(seg.asSlice(index*sizeof())); - } - public static void GetConfigurationValue$set(MemorySegment seg, long index, MemorySegment x) { - constants$25.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static GetConfigurationValue GetConfigurationValue(MemorySegment segment, Arena scope) { - return GetConfigurationValue.ofAddress(GetConfigurationValue$get(segment), scope); + public static final AddressLayout USBInterfaceOpen$layout() { + return USBInterfaceOpen$LAYOUT; } + + private static final long USBInterfaceOpen$OFFSET = 64; + /** - * {@snippet : - * IOReturn (*GetInterfaceNumber)(void*,UInt8*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*USBInterfaceOpen)(void *) * } */ - public interface GetInterfaceNumber { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetInterfaceNumber fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$26.const$0, fi, constants$6.const$5, scope); - } - static GetInterfaceNumber ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long USBInterfaceOpen$offset() { + return USBInterfaceOpen$OFFSET; } - public static VarHandle GetInterfaceNumber$VH() { - return constants$26.const$1; - } /** * Getter for field: - * {@snippet : - * IOReturn (*GetInterfaceNumber)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*USBInterfaceOpen)(void *) * } */ - public static MemorySegment GetInterfaceNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$26.const$1.get(seg); + public static MemorySegment USBInterfaceOpen(MemorySegment struct) { + return struct.get(USBInterfaceOpen$LAYOUT, USBInterfaceOpen$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetInterfaceNumber)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*USBInterfaceOpen)(void *) * } */ - public static void GetInterfaceNumber$set(MemorySegment seg, MemorySegment x) { - constants$26.const$1.set(seg, x); - } - public static MemorySegment GetInterfaceNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$26.const$1.get(seg.asSlice(index*sizeof())); - } - public static void GetInterfaceNumber$set(MemorySegment seg, long index, MemorySegment x) { - constants$26.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static GetInterfaceNumber GetInterfaceNumber(MemorySegment segment, Arena scope) { - return GetInterfaceNumber.ofAddress(GetInterfaceNumber$get(segment), scope); + public static void USBInterfaceOpen(MemorySegment struct, MemorySegment fieldValue) { + struct.set(USBInterfaceOpen$LAYOUT, USBInterfaceOpen$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*GetAlternateSetting)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*USBInterfaceClose)(void *) * } */ - public interface GetAlternateSetting { + public static class USBInterfaceClose { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetAlternateSetting fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$26.const$2, fi, constants$6.const$5, scope); + USBInterfaceClose() { + // Should not be called directly } - static GetAlternateSetting ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0); } - } - public static VarHandle GetAlternateSetting$VH() { - return constants$26.const$3; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*GetAlternateSetting)(void*,UInt8*); - * } - */ - public static MemorySegment GetAlternateSetting$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$26.const$3.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(USBInterfaceClose.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(USBInterfaceClose.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout USBInterfaceClose$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("USBInterfaceClose")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*GetAlternateSetting)(void*,UInt8*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*USBInterfaceClose)(void *) * } */ - public static void GetAlternateSetting$set(MemorySegment seg, MemorySegment x) { - constants$26.const$3.set(seg, x); - } - public static MemorySegment GetAlternateSetting$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$26.const$3.get(seg.asSlice(index*sizeof())); - } - public static void GetAlternateSetting$set(MemorySegment seg, long index, MemorySegment x) { - constants$26.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static GetAlternateSetting GetAlternateSetting(MemorySegment segment, Arena scope) { - return GetAlternateSetting.ofAddress(GetAlternateSetting$get(segment), scope); + public static final AddressLayout USBInterfaceClose$layout() { + return USBInterfaceClose$LAYOUT; } + + private static final long USBInterfaceClose$OFFSET = 72; + /** - * {@snippet : - * IOReturn (*GetNumEndpoints)(void*,UInt8*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*USBInterfaceClose)(void *) * } */ - public interface GetNumEndpoints { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetNumEndpoints fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$26.const$4, fi, constants$6.const$5, scope); - } - static GetNumEndpoints ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long USBInterfaceClose$offset() { + return USBInterfaceClose$OFFSET; } - public static VarHandle GetNumEndpoints$VH() { - return constants$26.const$5; - } /** * Getter for field: - * {@snippet : - * IOReturn (*GetNumEndpoints)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*USBInterfaceClose)(void *) * } */ - public static MemorySegment GetNumEndpoints$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$26.const$5.get(seg); + public static MemorySegment USBInterfaceClose(MemorySegment struct) { + return struct.get(USBInterfaceClose$LAYOUT, USBInterfaceClose$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetNumEndpoints)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*USBInterfaceClose)(void *) * } */ - public static void GetNumEndpoints$set(MemorySegment seg, MemorySegment x) { - constants$26.const$5.set(seg, x); - } - public static MemorySegment GetNumEndpoints$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$26.const$5.get(seg.asSlice(index*sizeof())); - } - public static void GetNumEndpoints$set(MemorySegment seg, long index, MemorySegment x) { - constants$26.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static GetNumEndpoints GetNumEndpoints(MemorySegment segment, Arena scope) { - return GetNumEndpoints.ofAddress(GetNumEndpoints$get(segment), scope); + public static void USBInterfaceClose(MemorySegment struct, MemorySegment fieldValue) { + struct.set(USBInterfaceClose$LAYOUT, USBInterfaceClose$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*GetLocationID)(void*,UInt32*); + * {@snippet lang=c : + * IOReturn (*GetInterfaceClass)(void *, UInt8 *) * } */ - public interface GetLocationID { + public static class GetInterfaceClass { - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetLocationID fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$27.const$0, fi, constants$6.const$5, scope); + GetInterfaceClass() { + // Should not be called directly } - static GetLocationID ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - } - public static VarHandle GetLocationID$VH() { - return constants$27.const$1; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*GetLocationID)(void*,UInt32*); - * } - */ - public static MemorySegment GetLocationID$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$27.const$1.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetInterfaceClass.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetInterfaceClass.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout GetInterfaceClass$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetInterfaceClass")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*GetLocationID)(void*,UInt32*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetInterfaceClass)(void *, UInt8 *) * } */ - public static void GetLocationID$set(MemorySegment seg, MemorySegment x) { - constants$27.const$1.set(seg, x); - } - public static MemorySegment GetLocationID$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$27.const$1.get(seg.asSlice(index*sizeof())); - } - public static void GetLocationID$set(MemorySegment seg, long index, MemorySegment x) { - constants$27.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static GetLocationID GetLocationID(MemorySegment segment, Arena scope) { - return GetLocationID.ofAddress(GetLocationID$get(segment), scope); + public static final AddressLayout GetInterfaceClass$layout() { + return GetInterfaceClass$LAYOUT; } + + private static final long GetInterfaceClass$OFFSET = 80; + /** - * {@snippet : - * IOReturn (*GetDevice)(void*,io_service_t*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetInterfaceClass)(void *, UInt8 *) * } */ - public interface GetDevice { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetDevice fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$27.const$2, fi, constants$6.const$5, scope); - } - static GetDevice ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long GetInterfaceClass$offset() { + return GetInterfaceClass$OFFSET; } - public static VarHandle GetDevice$VH() { - return constants$27.const$3; - } /** * Getter for field: - * {@snippet : - * IOReturn (*GetDevice)(void*,io_service_t*); + * {@snippet lang=c : + * IOReturn (*GetInterfaceClass)(void *, UInt8 *) * } */ - public static MemorySegment GetDevice$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$27.const$3.get(seg); + public static MemorySegment GetInterfaceClass(MemorySegment struct) { + return struct.get(GetInterfaceClass$LAYOUT, GetInterfaceClass$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetDevice)(void*,io_service_t*); + * {@snippet lang=c : + * IOReturn (*GetInterfaceClass)(void *, UInt8 *) * } */ - public static void GetDevice$set(MemorySegment seg, MemorySegment x) { - constants$27.const$3.set(seg, x); - } - public static MemorySegment GetDevice$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$27.const$3.get(seg.asSlice(index*sizeof())); - } - public static void GetDevice$set(MemorySegment seg, long index, MemorySegment x) { - constants$27.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static GetDevice GetDevice(MemorySegment segment, Arena scope) { - return GetDevice.ofAddress(GetDevice$get(segment), scope); + public static void GetInterfaceClass(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetInterfaceClass$LAYOUT, GetInterfaceClass$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*SetAlternateInterface)(void*,UInt8); + * {@snippet lang=c : + * IOReturn (*GetInterfaceSubClass)(void *, UInt8 *) * } */ - public interface SetAlternateInterface { + public static class GetInterfaceSubClass { - int apply(java.lang.foreign.MemorySegment _x0, byte _x1); - static MemorySegment allocate(SetAlternateInterface fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$27.const$4, fi, constants$14.const$0, scope); + GetInterfaceSubClass() { + // Should not be called directly } - static SetAlternateInterface ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { - try { - return (int)constants$14.const$2.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - } - public static VarHandle SetAlternateInterface$VH() { - return constants$27.const$5; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*SetAlternateInterface)(void*,UInt8); - * } - */ - public static MemorySegment SetAlternateInterface$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$27.const$5.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetInterfaceSubClass.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetInterfaceSubClass.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout GetInterfaceSubClass$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetInterfaceSubClass")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*SetAlternateInterface)(void*,UInt8); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetInterfaceSubClass)(void *, UInt8 *) * } */ - public static void SetAlternateInterface$set(MemorySegment seg, MemorySegment x) { - constants$27.const$5.set(seg, x); - } - public static MemorySegment SetAlternateInterface$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$27.const$5.get(seg.asSlice(index*sizeof())); - } - public static void SetAlternateInterface$set(MemorySegment seg, long index, MemorySegment x) { - constants$27.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static SetAlternateInterface SetAlternateInterface(MemorySegment segment, Arena scope) { - return SetAlternateInterface.ofAddress(SetAlternateInterface$get(segment), scope); + public static final AddressLayout GetInterfaceSubClass$layout() { + return GetInterfaceSubClass$LAYOUT; } + + private static final long GetInterfaceSubClass$OFFSET = 88; + /** - * {@snippet : - * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetInterfaceSubClass)(void *, UInt8 *) * } */ - public interface GetBusFrameNumber { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(GetBusFrameNumber fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$28.const$0, fi, constants$14.const$4, scope); - } - static GetBusFrameNumber ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1, java.lang.foreign.MemorySegment __x2) -> { - try { - return (int)constants$15.const$0.invokeExact(symbol, __x0, __x1, __x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long GetInterfaceSubClass$offset() { + return GetInterfaceSubClass$OFFSET; } - public static VarHandle GetBusFrameNumber$VH() { - return constants$28.const$1; - } /** * Getter for field: - * {@snippet : - * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); + * {@snippet lang=c : + * IOReturn (*GetInterfaceSubClass)(void *, UInt8 *) * } */ - public static MemorySegment GetBusFrameNumber$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$28.const$1.get(seg); + public static MemorySegment GetInterfaceSubClass(MemorySegment struct) { + return struct.get(GetInterfaceSubClass$LAYOUT, GetInterfaceSubClass$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetBusFrameNumber)(void*,UInt64*,AbsoluteTime*); + * {@snippet lang=c : + * IOReturn (*GetInterfaceSubClass)(void *, UInt8 *) * } */ - public static void GetBusFrameNumber$set(MemorySegment seg, MemorySegment x) { - constants$28.const$1.set(seg, x); - } - public static MemorySegment GetBusFrameNumber$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$28.const$1.get(seg.asSlice(index*sizeof())); - } - public static void GetBusFrameNumber$set(MemorySegment seg, long index, MemorySegment x) { - constants$28.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static GetBusFrameNumber GetBusFrameNumber(MemorySegment segment, Arena scope) { - return GetBusFrameNumber.ofAddress(GetBusFrameNumber$get(segment), scope); + public static void GetInterfaceSubClass(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetInterfaceSubClass$LAYOUT, GetInterfaceSubClass$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*ControlRequest)(void*,UInt8,IOUSBDevRequest*); + * {@snippet lang=c : + * IOReturn (*GetInterfaceProtocol)(void *, UInt8 *) * } */ - public interface ControlRequest { + public static class GetInterfaceProtocol { - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(ControlRequest fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$28.const$2, fi, constants$13.const$0, scope); + GetInterfaceProtocol() { + // Should not be called directly } - static ControlRequest ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2) -> { - try { - return (int)constants$13.const$2.invokeExact(symbol, __x0, __x1, __x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - } - public static VarHandle ControlRequest$VH() { - return constants$28.const$3; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*ControlRequest)(void*,UInt8,IOUSBDevRequest*); - * } - */ - public static MemorySegment ControlRequest$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$28.const$3.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetInterfaceProtocol.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetInterfaceProtocol.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout GetInterfaceProtocol$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetInterfaceProtocol")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*ControlRequest)(void*,UInt8,IOUSBDevRequest*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetInterfaceProtocol)(void *, UInt8 *) * } */ - public static void ControlRequest$set(MemorySegment seg, MemorySegment x) { - constants$28.const$3.set(seg, x); - } - public static MemorySegment ControlRequest$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$28.const$3.get(seg.asSlice(index*sizeof())); - } - public static void ControlRequest$set(MemorySegment seg, long index, MemorySegment x) { - constants$28.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static ControlRequest ControlRequest(MemorySegment segment, Arena scope) { - return ControlRequest.ofAddress(ControlRequest$get(segment), scope); + public static final AddressLayout GetInterfaceProtocol$layout() { + return GetInterfaceProtocol$LAYOUT; } + + private static final long GetInterfaceProtocol$OFFSET = 96; + /** - * {@snippet : - * IOReturn (*ControlRequestAsync)(void*,UInt8,IOUSBDevRequest*,IOAsyncCallback1,void*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetInterfaceProtocol)(void *, UInt8 *) * } */ - public interface ControlRequestAsync { - - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3, java.lang.foreign.MemorySegment _x4); - static MemorySegment allocate(ControlRequestAsync fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$28.const$5, fi, constants$28.const$4, scope); - } - static ControlRequestAsync ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3, java.lang.foreign.MemorySegment __x4) -> { - try { - return (int)constants$29.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long GetInterfaceProtocol$offset() { + return GetInterfaceProtocol$OFFSET; } - public static VarHandle ControlRequestAsync$VH() { - return constants$29.const$1; - } /** * Getter for field: - * {@snippet : - * IOReturn (*ControlRequestAsync)(void*,UInt8,IOUSBDevRequest*,IOAsyncCallback1,void*); + * {@snippet lang=c : + * IOReturn (*GetInterfaceProtocol)(void *, UInt8 *) * } */ - public static MemorySegment ControlRequestAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$29.const$1.get(seg); + public static MemorySegment GetInterfaceProtocol(MemorySegment struct) { + return struct.get(GetInterfaceProtocol$LAYOUT, GetInterfaceProtocol$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*ControlRequestAsync)(void*,UInt8,IOUSBDevRequest*,IOAsyncCallback1,void*); + * {@snippet lang=c : + * IOReturn (*GetInterfaceProtocol)(void *, UInt8 *) * } */ - public static void ControlRequestAsync$set(MemorySegment seg, MemorySegment x) { - constants$29.const$1.set(seg, x); - } - public static MemorySegment ControlRequestAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$29.const$1.get(seg.asSlice(index*sizeof())); - } - public static void ControlRequestAsync$set(MemorySegment seg, long index, MemorySegment x) { - constants$29.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static ControlRequestAsync ControlRequestAsync(MemorySegment segment, Arena scope) { - return ControlRequestAsync.ofAddress(ControlRequestAsync$get(segment), scope); + public static void GetInterfaceProtocol(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetInterfaceProtocol$LAYOUT, GetInterfaceProtocol$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*GetPipeProperties)(void*,UInt8,UInt8*,UInt8*,UInt8*,UInt16*,UInt8*); + * {@snippet lang=c : + * IOReturn (*GetDeviceVendor)(void *, UInt16 *) * } */ - public interface GetPipeProperties { + public static class GetDeviceVendor { - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3, java.lang.foreign.MemorySegment _x4, java.lang.foreign.MemorySegment _x5, java.lang.foreign.MemorySegment _x6); - static MemorySegment allocate(GetPipeProperties fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$29.const$3, fi, constants$29.const$2, scope); + GetDeviceVendor() { + // Should not be called directly } - static GetPipeProperties ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3, java.lang.foreign.MemorySegment __x4, java.lang.foreign.MemorySegment __x5, java.lang.foreign.MemorySegment __x6) -> { - try { - return (int)constants$29.const$4.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - } - public static VarHandle GetPipeProperties$VH() { - return constants$29.const$5; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*GetPipeProperties)(void*,UInt8,UInt8*,UInt8*,UInt8*,UInt16*,UInt8*); - * } - */ - public static MemorySegment GetPipeProperties$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$29.const$5.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceVendor.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetDeviceVendor.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout GetDeviceVendor$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetDeviceVendor")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*GetPipeProperties)(void*,UInt8,UInt8*,UInt8*,UInt8*,UInt16*,UInt8*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceVendor)(void *, UInt16 *) * } */ - public static void GetPipeProperties$set(MemorySegment seg, MemorySegment x) { - constants$29.const$5.set(seg, x); - } - public static MemorySegment GetPipeProperties$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$29.const$5.get(seg.asSlice(index*sizeof())); - } - public static void GetPipeProperties$set(MemorySegment seg, long index, MemorySegment x) { - constants$29.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static GetPipeProperties GetPipeProperties(MemorySegment segment, Arena scope) { - return GetPipeProperties.ofAddress(GetPipeProperties$get(segment), scope); + public static final AddressLayout GetDeviceVendor$layout() { + return GetDeviceVendor$LAYOUT; } + + private static final long GetDeviceVendor$OFFSET = 104; + /** - * {@snippet : - * IOReturn (*GetPipeStatus)(void*,UInt8); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceVendor)(void *, UInt16 *) * } */ - public interface GetPipeStatus { - - int apply(java.lang.foreign.MemorySegment _x0, byte _x1); - static MemorySegment allocate(GetPipeStatus fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$30.const$0, fi, constants$14.const$0, scope); - } - static GetPipeStatus ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { - try { - return (int)constants$14.const$2.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long GetDeviceVendor$offset() { + return GetDeviceVendor$OFFSET; } - public static VarHandle GetPipeStatus$VH() { - return constants$30.const$1; - } /** * Getter for field: - * {@snippet : - * IOReturn (*GetPipeStatus)(void*,UInt8); + * {@snippet lang=c : + * IOReturn (*GetDeviceVendor)(void *, UInt16 *) * } */ - public static MemorySegment GetPipeStatus$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$30.const$1.get(seg); + public static MemorySegment GetDeviceVendor(MemorySegment struct) { + return struct.get(GetDeviceVendor$LAYOUT, GetDeviceVendor$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetPipeStatus)(void*,UInt8); + * {@snippet lang=c : + * IOReturn (*GetDeviceVendor)(void *, UInt16 *) * } */ - public static void GetPipeStatus$set(MemorySegment seg, MemorySegment x) { - constants$30.const$1.set(seg, x); - } - public static MemorySegment GetPipeStatus$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$30.const$1.get(seg.asSlice(index*sizeof())); - } - public static void GetPipeStatus$set(MemorySegment seg, long index, MemorySegment x) { - constants$30.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static GetPipeStatus GetPipeStatus(MemorySegment segment, Arena scope) { - return GetPipeStatus.ofAddress(GetPipeStatus$get(segment), scope); + public static void GetDeviceVendor(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetDeviceVendor$LAYOUT, GetDeviceVendor$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*AbortPipe)(void*,UInt8); + * {@snippet lang=c : + * IOReturn (*GetDeviceProduct)(void *, UInt16 *) * } */ - public interface AbortPipe { + public static class GetDeviceProduct { - int apply(java.lang.foreign.MemorySegment _x0, byte _x1); - static MemorySegment allocate(AbortPipe fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$30.const$2, fi, constants$14.const$0, scope); + GetDeviceProduct() { + // Should not be called directly } - static AbortPipe ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { - try { - return (int)constants$14.const$2.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - } - public static VarHandle AbortPipe$VH() { - return constants$30.const$3; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*AbortPipe)(void*,UInt8); - * } - */ - public static MemorySegment AbortPipe$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$30.const$3.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceProduct.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetDeviceProduct.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout GetDeviceProduct$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetDeviceProduct")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*AbortPipe)(void*,UInt8); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceProduct)(void *, UInt16 *) * } */ - public static void AbortPipe$set(MemorySegment seg, MemorySegment x) { - constants$30.const$3.set(seg, x); - } - public static MemorySegment AbortPipe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$30.const$3.get(seg.asSlice(index*sizeof())); - } - public static void AbortPipe$set(MemorySegment seg, long index, MemorySegment x) { - constants$30.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static AbortPipe AbortPipe(MemorySegment segment, Arena scope) { - return AbortPipe.ofAddress(AbortPipe$get(segment), scope); + public static final AddressLayout GetDeviceProduct$layout() { + return GetDeviceProduct$LAYOUT; } + + private static final long GetDeviceProduct$OFFSET = 112; + /** - * {@snippet : - * IOReturn (*ResetPipe)(void*,UInt8); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceProduct)(void *, UInt16 *) * } */ - public interface ResetPipe { - - int apply(java.lang.foreign.MemorySegment _x0, byte _x1); - static MemorySegment allocate(ResetPipe fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$30.const$4, fi, constants$14.const$0, scope); - } - static ResetPipe ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { - try { - return (int)constants$14.const$2.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long GetDeviceProduct$offset() { + return GetDeviceProduct$OFFSET; } - public static VarHandle ResetPipe$VH() { - return constants$30.const$5; - } /** * Getter for field: - * {@snippet : - * IOReturn (*ResetPipe)(void*,UInt8); + * {@snippet lang=c : + * IOReturn (*GetDeviceProduct)(void *, UInt16 *) * } */ - public static MemorySegment ResetPipe$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$30.const$5.get(seg); + public static MemorySegment GetDeviceProduct(MemorySegment struct) { + return struct.get(GetDeviceProduct$LAYOUT, GetDeviceProduct$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*ResetPipe)(void*,UInt8); + * {@snippet lang=c : + * IOReturn (*GetDeviceProduct)(void *, UInt16 *) * } */ - public static void ResetPipe$set(MemorySegment seg, MemorySegment x) { - constants$30.const$5.set(seg, x); - } - public static MemorySegment ResetPipe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$30.const$5.get(seg.asSlice(index*sizeof())); - } - public static void ResetPipe$set(MemorySegment seg, long index, MemorySegment x) { - constants$30.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static ResetPipe ResetPipe(MemorySegment segment, Arena scope) { - return ResetPipe.ofAddress(ResetPipe$get(segment), scope); + public static void GetDeviceProduct(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetDeviceProduct$LAYOUT, GetDeviceProduct$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*ClearPipeStall)(void*,UInt8); + * {@snippet lang=c : + * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *) * } */ - public interface ClearPipeStall { + public static class GetDeviceReleaseNumber { - int apply(java.lang.foreign.MemorySegment _x0, byte _x1); - static MemorySegment allocate(ClearPipeStall fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$31.const$0, fi, constants$14.const$0, scope); + GetDeviceReleaseNumber() { + // Should not be called directly } - static ClearPipeStall ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { - try { - return (int)constants$14.const$2.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - } - public static VarHandle ClearPipeStall$VH() { - return constants$31.const$1; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*ClearPipeStall)(void*,UInt8); - * } - */ - public static MemorySegment ClearPipeStall$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$31.const$1.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceReleaseNumber.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetDeviceReleaseNumber.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout GetDeviceReleaseNumber$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetDeviceReleaseNumber")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*ClearPipeStall)(void*,UInt8); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *) * } */ - public static void ClearPipeStall$set(MemorySegment seg, MemorySegment x) { - constants$31.const$1.set(seg, x); - } - public static MemorySegment ClearPipeStall$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$31.const$1.get(seg.asSlice(index*sizeof())); - } - public static void ClearPipeStall$set(MemorySegment seg, long index, MemorySegment x) { - constants$31.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static ClearPipeStall ClearPipeStall(MemorySegment segment, Arena scope) { - return ClearPipeStall.ofAddress(ClearPipeStall$get(segment), scope); + public static final AddressLayout GetDeviceReleaseNumber$layout() { + return GetDeviceReleaseNumber$LAYOUT; } + + private static final long GetDeviceReleaseNumber$OFFSET = 120; + /** - * {@snippet : - * IOReturn (*ReadPipe)(void*,UInt8,void*,UInt32*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *) * } */ - public interface ReadPipe { - - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3); - static MemorySegment allocate(ReadPipe fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$31.const$3, fi, constants$31.const$2, scope); - } - static ReadPipe ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3) -> { - try { - return (int)constants$31.const$4.invokeExact(symbol, __x0, __x1, __x2, __x3); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long GetDeviceReleaseNumber$offset() { + return GetDeviceReleaseNumber$OFFSET; } - public static VarHandle ReadPipe$VH() { - return constants$31.const$5; - } /** * Getter for field: - * {@snippet : - * IOReturn (*ReadPipe)(void*,UInt8,void*,UInt32*); + * {@snippet lang=c : + * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *) * } */ - public static MemorySegment ReadPipe$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$31.const$5.get(seg); + public static MemorySegment GetDeviceReleaseNumber(MemorySegment struct) { + return struct.get(GetDeviceReleaseNumber$LAYOUT, GetDeviceReleaseNumber$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*ReadPipe)(void*,UInt8,void*,UInt32*); + * {@snippet lang=c : + * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *) * } */ - public static void ReadPipe$set(MemorySegment seg, MemorySegment x) { - constants$31.const$5.set(seg, x); - } - public static MemorySegment ReadPipe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$31.const$5.get(seg.asSlice(index*sizeof())); - } - public static void ReadPipe$set(MemorySegment seg, long index, MemorySegment x) { - constants$31.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static ReadPipe ReadPipe(MemorySegment segment, Arena scope) { - return ReadPipe.ofAddress(ReadPipe$get(segment), scope); + public static void GetDeviceReleaseNumber(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetDeviceReleaseNumber$LAYOUT, GetDeviceReleaseNumber$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*WritePipe)(void*,UInt8,void*,UInt32); + * {@snippet lang=c : + * IOReturn (*GetConfigurationValue)(void *, UInt8 *) * } */ - public interface WritePipe { + public static class GetConfigurationValue { - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3); - static MemorySegment allocate(WritePipe fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$32.const$1, fi, constants$32.const$0, scope); + GetConfigurationValue() { + // Should not be called directly } - static WritePipe ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3) -> { - try { - return (int)constants$32.const$2.invokeExact(symbol, __x0, __x1, __x2, __x3); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - } - public static VarHandle WritePipe$VH() { - return constants$32.const$3; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*WritePipe)(void*,UInt8,void*,UInt32); - * } + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetConfigurationValue.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetConfigurationValue.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetConfigurationValue$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetConfigurationValue")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetConfigurationValue)(void *, UInt8 *) + * } + */ + public static final AddressLayout GetConfigurationValue$layout() { + return GetConfigurationValue$LAYOUT; + } + + private static final long GetConfigurationValue$OFFSET = 128; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetConfigurationValue)(void *, UInt8 *) + * } + */ + public static final long GetConfigurationValue$offset() { + return GetConfigurationValue$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetConfigurationValue)(void *, UInt8 *) + * } + */ + public static MemorySegment GetConfigurationValue(MemorySegment struct) { + return struct.get(GetConfigurationValue$LAYOUT, GetConfigurationValue$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetConfigurationValue)(void *, UInt8 *) + * } + */ + public static void GetConfigurationValue(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetConfigurationValue$LAYOUT, GetConfigurationValue$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetInterfaceNumber)(void *, UInt8 *) + * } + */ + public static class GetInterfaceNumber { + + GetInterfaceNumber() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetInterfaceNumber.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetInterfaceNumber.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetInterfaceNumber$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetInterfaceNumber")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetInterfaceNumber)(void *, UInt8 *) + * } + */ + public static final AddressLayout GetInterfaceNumber$layout() { + return GetInterfaceNumber$LAYOUT; + } + + private static final long GetInterfaceNumber$OFFSET = 136; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetInterfaceNumber)(void *, UInt8 *) + * } + */ + public static final long GetInterfaceNumber$offset() { + return GetInterfaceNumber$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetInterfaceNumber)(void *, UInt8 *) + * } + */ + public static MemorySegment GetInterfaceNumber(MemorySegment struct) { + return struct.get(GetInterfaceNumber$LAYOUT, GetInterfaceNumber$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetInterfaceNumber)(void *, UInt8 *) + * } + */ + public static void GetInterfaceNumber(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetInterfaceNumber$LAYOUT, GetInterfaceNumber$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetAlternateSetting)(void *, UInt8 *) + * } + */ + public static class GetAlternateSetting { + + GetAlternateSetting() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetAlternateSetting.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetAlternateSetting.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetAlternateSetting$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetAlternateSetting")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetAlternateSetting)(void *, UInt8 *) + * } + */ + public static final AddressLayout GetAlternateSetting$layout() { + return GetAlternateSetting$LAYOUT; + } + + private static final long GetAlternateSetting$OFFSET = 144; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetAlternateSetting)(void *, UInt8 *) + * } + */ + public static final long GetAlternateSetting$offset() { + return GetAlternateSetting$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetAlternateSetting)(void *, UInt8 *) + * } + */ + public static MemorySegment GetAlternateSetting(MemorySegment struct) { + return struct.get(GetAlternateSetting$LAYOUT, GetAlternateSetting$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetAlternateSetting)(void *, UInt8 *) + * } + */ + public static void GetAlternateSetting(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetAlternateSetting$LAYOUT, GetAlternateSetting$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetNumEndpoints)(void *, UInt8 *) + * } + */ + public static class GetNumEndpoints { + + GetNumEndpoints() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetNumEndpoints.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetNumEndpoints.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetNumEndpoints$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetNumEndpoints")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetNumEndpoints)(void *, UInt8 *) + * } + */ + public static final AddressLayout GetNumEndpoints$layout() { + return GetNumEndpoints$LAYOUT; + } + + private static final long GetNumEndpoints$OFFSET = 152; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetNumEndpoints)(void *, UInt8 *) + * } + */ + public static final long GetNumEndpoints$offset() { + return GetNumEndpoints$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetNumEndpoints)(void *, UInt8 *) + * } + */ + public static MemorySegment GetNumEndpoints(MemorySegment struct) { + return struct.get(GetNumEndpoints$LAYOUT, GetNumEndpoints$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetNumEndpoints)(void *, UInt8 *) + * } + */ + public static void GetNumEndpoints(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetNumEndpoints$LAYOUT, GetNumEndpoints$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetLocationID)(void *, UInt32 *) + * } + */ + public static class GetLocationID { + + GetLocationID() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetLocationID.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetLocationID.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetLocationID$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetLocationID")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetLocationID)(void *, UInt32 *) + * } + */ + public static final AddressLayout GetLocationID$layout() { + return GetLocationID$LAYOUT; + } + + private static final long GetLocationID$OFFSET = 160; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetLocationID)(void *, UInt32 *) + * } + */ + public static final long GetLocationID$offset() { + return GetLocationID$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetLocationID)(void *, UInt32 *) + * } + */ + public static MemorySegment GetLocationID(MemorySegment struct) { + return struct.get(GetLocationID$LAYOUT, GetLocationID$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetLocationID)(void *, UInt32 *) + * } + */ + public static void GetLocationID(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetLocationID$LAYOUT, GetLocationID$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetDevice)(void *, io_service_t *) + * } + */ + public static class GetDevice { + + GetDevice() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDevice.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetDevice.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetDevice$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetDevice")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetDevice)(void *, io_service_t *) + * } + */ + public static final AddressLayout GetDevice$layout() { + return GetDevice$LAYOUT; + } + + private static final long GetDevice$OFFSET = 168; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetDevice)(void *, io_service_t *) + * } + */ + public static final long GetDevice$offset() { + return GetDevice$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetDevice)(void *, io_service_t *) + * } + */ + public static MemorySegment GetDevice(MemorySegment struct) { + return struct.get(GetDevice$LAYOUT, GetDevice$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetDevice)(void *, io_service_t *) + * } + */ + public static void GetDevice(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetDevice$LAYOUT, GetDevice$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*SetAlternateInterface)(void *, UInt8) + * } + */ + public static class SetAlternateInterface { + + SetAlternateInterface() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(SetAlternateInterface.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(SetAlternateInterface.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout SetAlternateInterface$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("SetAlternateInterface")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*SetAlternateInterface)(void *, UInt8) + * } + */ + public static final AddressLayout SetAlternateInterface$layout() { + return SetAlternateInterface$LAYOUT; + } + + private static final long SetAlternateInterface$OFFSET = 176; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*SetAlternateInterface)(void *, UInt8) + * } + */ + public static final long SetAlternateInterface$offset() { + return SetAlternateInterface$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*SetAlternateInterface)(void *, UInt8) + * } + */ + public static MemorySegment SetAlternateInterface(MemorySegment struct) { + return struct.get(SetAlternateInterface$LAYOUT, SetAlternateInterface$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*SetAlternateInterface)(void *, UInt8) + * } + */ + public static void SetAlternateInterface(MemorySegment struct, MemorySegment fieldValue) { + struct.set(SetAlternateInterface$LAYOUT, SetAlternateInterface$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *) + * } + */ + public static class GetBusFrameNumber { + + GetBusFrameNumber() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1, MemorySegment _x2); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetBusFrameNumber.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetBusFrameNumber.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetBusFrameNumber$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetBusFrameNumber")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *) + * } + */ + public static final AddressLayout GetBusFrameNumber$layout() { + return GetBusFrameNumber$LAYOUT; + } + + private static final long GetBusFrameNumber$OFFSET = 184; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *) + * } + */ + public static final long GetBusFrameNumber$offset() { + return GetBusFrameNumber$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *) + * } + */ + public static MemorySegment GetBusFrameNumber(MemorySegment struct) { + return struct.get(GetBusFrameNumber$LAYOUT, GetBusFrameNumber$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *) + * } + */ + public static void GetBusFrameNumber(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetBusFrameNumber$LAYOUT, GetBusFrameNumber$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*ControlRequest)(void *, UInt8, IOUSBDevRequest *) + * } + */ + public static class ControlRequest { + + ControlRequest() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, MemorySegment _x2); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(ControlRequest.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(ControlRequest.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout ControlRequest$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("ControlRequest")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*ControlRequest)(void *, UInt8, IOUSBDevRequest *) + * } + */ + public static final AddressLayout ControlRequest$layout() { + return ControlRequest$LAYOUT; + } + + private static final long ControlRequest$OFFSET = 192; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*ControlRequest)(void *, UInt8, IOUSBDevRequest *) + * } + */ + public static final long ControlRequest$offset() { + return ControlRequest$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*ControlRequest)(void *, UInt8, IOUSBDevRequest *) + * } + */ + public static MemorySegment ControlRequest(MemorySegment struct) { + return struct.get(ControlRequest$LAYOUT, ControlRequest$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*ControlRequest)(void *, UInt8, IOUSBDevRequest *) + * } + */ + public static void ControlRequest(MemorySegment struct, MemorySegment fieldValue) { + struct.set(ControlRequest$LAYOUT, ControlRequest$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*ControlRequestAsync)(void *, UInt8, IOUSBDevRequest *, IOAsyncCallback1, void *) + * } + */ + public static class ControlRequestAsync { + + ControlRequestAsync() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, MemorySegment _x4); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(ControlRequestAsync.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(ControlRequestAsync.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, MemorySegment _x4) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout ControlRequestAsync$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("ControlRequestAsync")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*ControlRequestAsync)(void *, UInt8, IOUSBDevRequest *, IOAsyncCallback1, void *) + * } + */ + public static final AddressLayout ControlRequestAsync$layout() { + return ControlRequestAsync$LAYOUT; + } + + private static final long ControlRequestAsync$OFFSET = 200; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*ControlRequestAsync)(void *, UInt8, IOUSBDevRequest *, IOAsyncCallback1, void *) + * } + */ + public static final long ControlRequestAsync$offset() { + return ControlRequestAsync$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*ControlRequestAsync)(void *, UInt8, IOUSBDevRequest *, IOAsyncCallback1, void *) + * } + */ + public static MemorySegment ControlRequestAsync(MemorySegment struct) { + return struct.get(ControlRequestAsync$LAYOUT, ControlRequestAsync$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*ControlRequestAsync)(void *, UInt8, IOUSBDevRequest *, IOAsyncCallback1, void *) + * } + */ + public static void ControlRequestAsync(MemorySegment struct, MemorySegment fieldValue) { + struct.set(ControlRequestAsync$LAYOUT, ControlRequestAsync$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetPipeProperties)(void *, UInt8, UInt8 *, UInt8 *, UInt8 *, UInt16 *, UInt8 *) + * } + */ + public static class GetPipeProperties { + + GetPipeProperties() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, MemorySegment _x4, MemorySegment _x5, MemorySegment _x6); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetPipeProperties.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetPipeProperties.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, MemorySegment _x4, MemorySegment _x5, MemorySegment _x6) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5, _x6); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetPipeProperties$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetPipeProperties")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetPipeProperties)(void *, UInt8, UInt8 *, UInt8 *, UInt8 *, UInt16 *, UInt8 *) + * } + */ + public static final AddressLayout GetPipeProperties$layout() { + return GetPipeProperties$LAYOUT; + } + + private static final long GetPipeProperties$OFFSET = 208; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetPipeProperties)(void *, UInt8, UInt8 *, UInt8 *, UInt8 *, UInt16 *, UInt8 *) + * } + */ + public static final long GetPipeProperties$offset() { + return GetPipeProperties$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetPipeProperties)(void *, UInt8, UInt8 *, UInt8 *, UInt8 *, UInt16 *, UInt8 *) + * } + */ + public static MemorySegment GetPipeProperties(MemorySegment struct) { + return struct.get(GetPipeProperties$LAYOUT, GetPipeProperties$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetPipeProperties)(void *, UInt8, UInt8 *, UInt8 *, UInt8 *, UInt16 *, UInt8 *) + * } + */ + public static void GetPipeProperties(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetPipeProperties$LAYOUT, GetPipeProperties$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*GetPipeStatus)(void *, UInt8) + * } + */ + public static class GetPipeStatus { + + GetPipeStatus() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetPipeStatus.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetPipeStatus.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout GetPipeStatus$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetPipeStatus")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetPipeStatus)(void *, UInt8) + * } + */ + public static final AddressLayout GetPipeStatus$layout() { + return GetPipeStatus$LAYOUT; + } + + private static final long GetPipeStatus$OFFSET = 216; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetPipeStatus)(void *, UInt8) + * } + */ + public static final long GetPipeStatus$offset() { + return GetPipeStatus$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*GetPipeStatus)(void *, UInt8) + * } + */ + public static MemorySegment GetPipeStatus(MemorySegment struct) { + return struct.get(GetPipeStatus$LAYOUT, GetPipeStatus$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*GetPipeStatus)(void *, UInt8) + * } + */ + public static void GetPipeStatus(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetPipeStatus$LAYOUT, GetPipeStatus$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*AbortPipe)(void *, UInt8) + * } + */ + public static class AbortPipe { + + AbortPipe() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(AbortPipe.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(AbortPipe.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout AbortPipe$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("AbortPipe")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*AbortPipe)(void *, UInt8) + * } + */ + public static final AddressLayout AbortPipe$layout() { + return AbortPipe$LAYOUT; + } + + private static final long AbortPipe$OFFSET = 224; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*AbortPipe)(void *, UInt8) + * } + */ + public static final long AbortPipe$offset() { + return AbortPipe$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*AbortPipe)(void *, UInt8) + * } + */ + public static MemorySegment AbortPipe(MemorySegment struct) { + return struct.get(AbortPipe$LAYOUT, AbortPipe$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*AbortPipe)(void *, UInt8) + * } + */ + public static void AbortPipe(MemorySegment struct, MemorySegment fieldValue) { + struct.set(AbortPipe$LAYOUT, AbortPipe$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*ResetPipe)(void *, UInt8) + * } + */ + public static class ResetPipe { + + ResetPipe() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(ResetPipe.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(ResetPipe.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout ResetPipe$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("ResetPipe")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*ResetPipe)(void *, UInt8) + * } + */ + public static final AddressLayout ResetPipe$layout() { + return ResetPipe$LAYOUT; + } + + private static final long ResetPipe$OFFSET = 232; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*ResetPipe)(void *, UInt8) + * } + */ + public static final long ResetPipe$offset() { + return ResetPipe$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*ResetPipe)(void *, UInt8) + * } + */ + public static MemorySegment ResetPipe(MemorySegment struct) { + return struct.get(ResetPipe$LAYOUT, ResetPipe$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*ResetPipe)(void *, UInt8) + * } + */ + public static void ResetPipe(MemorySegment struct, MemorySegment fieldValue) { + struct.set(ResetPipe$LAYOUT, ResetPipe$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*ClearPipeStall)(void *, UInt8) + * } + */ + public static class ClearPipeStall { + + ClearPipeStall() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(ClearPipeStall.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(ClearPipeStall.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout ClearPipeStall$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("ClearPipeStall")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*ClearPipeStall)(void *, UInt8) + * } + */ + public static final AddressLayout ClearPipeStall$layout() { + return ClearPipeStall$LAYOUT; + } + + private static final long ClearPipeStall$OFFSET = 240; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*ClearPipeStall)(void *, UInt8) + * } + */ + public static final long ClearPipeStall$offset() { + return ClearPipeStall$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*ClearPipeStall)(void *, UInt8) + * } + */ + public static MemorySegment ClearPipeStall(MemorySegment struct) { + return struct.get(ClearPipeStall$LAYOUT, ClearPipeStall$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*ClearPipeStall)(void *, UInt8) + * } + */ + public static void ClearPipeStall(MemorySegment struct, MemorySegment fieldValue) { + struct.set(ClearPipeStall$LAYOUT, ClearPipeStall$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*ReadPipe)(void *, UInt8, void *, UInt32 *) + * } + */ + public static class ReadPipe { + + ReadPipe() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(ReadPipe.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(ReadPipe.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout ReadPipe$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("ReadPipe")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*ReadPipe)(void *, UInt8, void *, UInt32 *) + * } + */ + public static final AddressLayout ReadPipe$layout() { + return ReadPipe$LAYOUT; + } + + private static final long ReadPipe$OFFSET = 248; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*ReadPipe)(void *, UInt8, void *, UInt32 *) + * } + */ + public static final long ReadPipe$offset() { + return ReadPipe$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*ReadPipe)(void *, UInt8, void *, UInt32 *) + * } + */ + public static MemorySegment ReadPipe(MemorySegment struct) { + return struct.get(ReadPipe$LAYOUT, ReadPipe$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*ReadPipe)(void *, UInt8, void *, UInt32 *) + * } + */ + public static void ReadPipe(MemorySegment struct, MemorySegment fieldValue) { + struct.set(ReadPipe$LAYOUT, ReadPipe$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*WritePipe)(void *, UInt8, void *, UInt32) + * } + */ + public static class WritePipe { + + WritePipe() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_POINTER, + IOKit.C_INT + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(WritePipe.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(WritePipe.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout WritePipe$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("WritePipe")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*WritePipe)(void *, UInt8, void *, UInt32) + * } + */ + public static final AddressLayout WritePipe$layout() { + return WritePipe$LAYOUT; + } + + private static final long WritePipe$OFFSET = 256; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*WritePipe)(void *, UInt8, void *, UInt32) + * } + */ + public static final long WritePipe$offset() { + return WritePipe$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*WritePipe)(void *, UInt8, void *, UInt32) + * } + */ + public static MemorySegment WritePipe(MemorySegment struct) { + return struct.get(WritePipe$LAYOUT, WritePipe$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*WritePipe)(void *, UInt8, void *, UInt32) + * } + */ + public static void WritePipe(MemorySegment struct, MemorySegment fieldValue) { + struct.set(WritePipe$LAYOUT, WritePipe$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*ReadPipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *) + * } + */ + public static class ReadPipeAsync { + + ReadPipeAsync() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, MemorySegment _x4, MemorySegment _x5); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_POINTER, + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(ReadPipeAsync.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(ReadPipeAsync.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, MemorySegment _x4, MemorySegment _x5) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout ReadPipeAsync$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("ReadPipeAsync")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*ReadPipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *) + * } + */ + public static final AddressLayout ReadPipeAsync$layout() { + return ReadPipeAsync$LAYOUT; + } + + private static final long ReadPipeAsync$OFFSET = 264; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*ReadPipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *) + * } + */ + public static final long ReadPipeAsync$offset() { + return ReadPipeAsync$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*ReadPipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *) + * } + */ + public static MemorySegment ReadPipeAsync(MemorySegment struct) { + return struct.get(ReadPipeAsync$LAYOUT, ReadPipeAsync$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*ReadPipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *) + * } + */ + public static void ReadPipeAsync(MemorySegment struct, MemorySegment fieldValue) { + struct.set(ReadPipeAsync$LAYOUT, ReadPipeAsync$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*WritePipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *) + * } + */ + public static class WritePipeAsync { + + WritePipeAsync() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, MemorySegment _x4, MemorySegment _x5); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_POINTER, + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(WritePipeAsync.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(WritePipeAsync.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, MemorySegment _x4, MemorySegment _x5) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout WritePipeAsync$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("WritePipeAsync")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*WritePipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *) + * } + */ + public static final AddressLayout WritePipeAsync$layout() { + return WritePipeAsync$LAYOUT; + } + + private static final long WritePipeAsync$OFFSET = 272; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*WritePipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *) + * } + */ + public static final long WritePipeAsync$offset() { + return WritePipeAsync$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*WritePipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *) + * } + */ + public static MemorySegment WritePipeAsync(MemorySegment struct) { + return struct.get(WritePipeAsync$LAYOUT, WritePipeAsync$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*WritePipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *) + * } + */ + public static void WritePipeAsync(MemorySegment struct, MemorySegment fieldValue) { + struct.set(WritePipeAsync$LAYOUT, WritePipeAsync$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*ReadIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *) + * } + */ + public static class ReadIsochPipeAsync { + + ReadIsochPipeAsync() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, long _x3, int _x4, MemorySegment _x5, MemorySegment _x6, MemorySegment _x7); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_POINTER, + IOKit.C_LONG_LONG, + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(ReadIsochPipeAsync.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(ReadIsochPipeAsync.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, long _x3, int _x4, MemorySegment _x5, MemorySegment _x6, MemorySegment _x7) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5, _x6, _x7); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout ReadIsochPipeAsync$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("ReadIsochPipeAsync")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*ReadIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *) + * } + */ + public static final AddressLayout ReadIsochPipeAsync$layout() { + return ReadIsochPipeAsync$LAYOUT; + } + + private static final long ReadIsochPipeAsync$OFFSET = 280; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*ReadIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *) + * } + */ + public static final long ReadIsochPipeAsync$offset() { + return ReadIsochPipeAsync$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*ReadIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *) + * } + */ + public static MemorySegment ReadIsochPipeAsync(MemorySegment struct) { + return struct.get(ReadIsochPipeAsync$LAYOUT, ReadIsochPipeAsync$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*ReadIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *) + * } + */ + public static void ReadIsochPipeAsync(MemorySegment struct, MemorySegment fieldValue) { + struct.set(ReadIsochPipeAsync$LAYOUT, ReadIsochPipeAsync$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*WriteIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *) + * } + */ + public static class WriteIsochPipeAsync { + + WriteIsochPipeAsync() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, long _x3, int _x4, MemorySegment _x5, MemorySegment _x6, MemorySegment _x7); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_POINTER, + IOKit.C_LONG_LONG, + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(WriteIsochPipeAsync.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(WriteIsochPipeAsync.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, long _x3, int _x4, MemorySegment _x5, MemorySegment _x6, MemorySegment _x7) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5, _x6, _x7); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout WriteIsochPipeAsync$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("WriteIsochPipeAsync")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*WriteIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *) + * } + */ + public static final AddressLayout WriteIsochPipeAsync$layout() { + return WriteIsochPipeAsync$LAYOUT; + } + + private static final long WriteIsochPipeAsync$OFFSET = 288; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*WriteIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *) + * } + */ + public static final long WriteIsochPipeAsync$offset() { + return WriteIsochPipeAsync$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*WriteIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *) + * } + */ + public static MemorySegment WriteIsochPipeAsync(MemorySegment struct) { + return struct.get(WriteIsochPipeAsync$LAYOUT, WriteIsochPipeAsync$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*WriteIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *) + * } + */ + public static void WriteIsochPipeAsync(MemorySegment struct, MemorySegment fieldValue) { + struct.set(WriteIsochPipeAsync$LAYOUT, WriteIsochPipeAsync$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*ControlRequestTO)(void *, UInt8, IOUSBDevRequestTO *) + * } + */ + public static class ControlRequestTO { + + ControlRequestTO() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, MemorySegment _x2); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(ControlRequestTO.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(ControlRequestTO.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout ControlRequestTO$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("ControlRequestTO")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*ControlRequestTO)(void *, UInt8, IOUSBDevRequestTO *) + * } + */ + public static final AddressLayout ControlRequestTO$layout() { + return ControlRequestTO$LAYOUT; + } + + private static final long ControlRequestTO$OFFSET = 296; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*ControlRequestTO)(void *, UInt8, IOUSBDevRequestTO *) + * } + */ + public static final long ControlRequestTO$offset() { + return ControlRequestTO$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*ControlRequestTO)(void *, UInt8, IOUSBDevRequestTO *) + * } + */ + public static MemorySegment ControlRequestTO(MemorySegment struct) { + return struct.get(ControlRequestTO$LAYOUT, ControlRequestTO$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*ControlRequestTO)(void *, UInt8, IOUSBDevRequestTO *) + * } + */ + public static void ControlRequestTO(MemorySegment struct, MemorySegment fieldValue) { + struct.set(ControlRequestTO$LAYOUT, ControlRequestTO$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*ControlRequestAsyncTO)(void *, UInt8, IOUSBDevRequestTO *, IOAsyncCallback1, void *) + * } + */ + public static class ControlRequestAsyncTO { + + ControlRequestAsyncTO() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, MemorySegment _x4); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(ControlRequestAsyncTO.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(ControlRequestAsyncTO.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, MemorySegment _x4) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout ControlRequestAsyncTO$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("ControlRequestAsyncTO")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*ControlRequestAsyncTO)(void *, UInt8, IOUSBDevRequestTO *, IOAsyncCallback1, void *) + * } + */ + public static final AddressLayout ControlRequestAsyncTO$layout() { + return ControlRequestAsyncTO$LAYOUT; + } + + private static final long ControlRequestAsyncTO$OFFSET = 304; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*ControlRequestAsyncTO)(void *, UInt8, IOUSBDevRequestTO *, IOAsyncCallback1, void *) + * } + */ + public static final long ControlRequestAsyncTO$offset() { + return ControlRequestAsyncTO$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*ControlRequestAsyncTO)(void *, UInt8, IOUSBDevRequestTO *, IOAsyncCallback1, void *) + * } + */ + public static MemorySegment ControlRequestAsyncTO(MemorySegment struct) { + return struct.get(ControlRequestAsyncTO$LAYOUT, ControlRequestAsyncTO$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*ControlRequestAsyncTO)(void *, UInt8, IOUSBDevRequestTO *, IOAsyncCallback1, void *) + * } + */ + public static void ControlRequestAsyncTO(MemorySegment struct, MemorySegment fieldValue) { + struct.set(ControlRequestAsyncTO$LAYOUT, ControlRequestAsyncTO$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*ReadPipeTO)(void *, UInt8, void *, UInt32 *, UInt32, UInt32) + * } + */ + public static class ReadPipeTO { + + ReadPipeTO() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, int _x4, int _x5); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_INT, + IOKit.C_INT + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(ReadPipeTO.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(ReadPipeTO.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, int _x4, int _x5) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout ReadPipeTO$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("ReadPipeTO")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*ReadPipeTO)(void *, UInt8, void *, UInt32 *, UInt32, UInt32) + * } + */ + public static final AddressLayout ReadPipeTO$layout() { + return ReadPipeTO$LAYOUT; + } + + private static final long ReadPipeTO$OFFSET = 312; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*ReadPipeTO)(void *, UInt8, void *, UInt32 *, UInt32, UInt32) + * } + */ + public static final long ReadPipeTO$offset() { + return ReadPipeTO$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*ReadPipeTO)(void *, UInt8, void *, UInt32 *, UInt32, UInt32) + * } */ - public static MemorySegment WritePipe$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$32.const$3.get(seg); + public static MemorySegment ReadPipeTO(MemorySegment struct) { + return struct.get(ReadPipeTO$LAYOUT, ReadPipeTO$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*WritePipe)(void*,UInt8,void*,UInt32); + * {@snippet lang=c : + * IOReturn (*ReadPipeTO)(void *, UInt8, void *, UInt32 *, UInt32, UInt32) + * } + */ + public static void ReadPipeTO(MemorySegment struct, MemorySegment fieldValue) { + struct.set(ReadPipeTO$LAYOUT, ReadPipeTO$OFFSET, fieldValue); + } + + /** + * {@snippet lang=c : + * IOReturn (*WritePipeTO)(void *, UInt8, void *, UInt32, UInt32, UInt32) + * } + */ + public static class WritePipeTO { + + WritePipeTO() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, int _x4, int _x5); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_POINTER, + IOKit.C_INT, + IOKit.C_INT, + IOKit.C_INT + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(WritePipeTO.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(WritePipeTO.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, int _x4, int _x5) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } + + private static final AddressLayout WritePipeTO$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("WritePipeTO")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*WritePipeTO)(void *, UInt8, void *, UInt32, UInt32, UInt32) + * } + */ + public static final AddressLayout WritePipeTO$layout() { + return WritePipeTO$LAYOUT; + } + + private static final long WritePipeTO$OFFSET = 320; + + /** + * Offset for field: + * {@snippet lang=c : + * IOReturn (*WritePipeTO)(void *, UInt8, void *, UInt32, UInt32, UInt32) * } */ - public static void WritePipe$set(MemorySegment seg, MemorySegment x) { - constants$32.const$3.set(seg, x); + public static final long WritePipeTO$offset() { + return WritePipeTO$OFFSET; } - public static MemorySegment WritePipe$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$32.const$3.get(seg.asSlice(index*sizeof())); + + /** + * Getter for field: + * {@snippet lang=c : + * IOReturn (*WritePipeTO)(void *, UInt8, void *, UInt32, UInt32, UInt32) + * } + */ + public static MemorySegment WritePipeTO(MemorySegment struct) { + return struct.get(WritePipeTO$LAYOUT, WritePipeTO$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * IOReturn (*WritePipeTO)(void *, UInt8, void *, UInt32, UInt32, UInt32) + * } + */ + public static void WritePipeTO(MemorySegment struct, MemorySegment fieldValue) { + struct.set(WritePipeTO$LAYOUT, WritePipeTO$OFFSET, fieldValue); } - public static void WritePipe$set(MemorySegment seg, long index, MemorySegment x) { - constants$32.const$3.set(seg.asSlice(index*sizeof()), x); + + /** + * {@snippet lang=c : + * IOReturn (*ReadPipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *) + * } + */ + public static class ReadPipeAsyncTO { + + ReadPipeAsyncTO() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, int _x4, int _x5, MemorySegment _x6, MemorySegment _x7); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_POINTER, + IOKit.C_INT, + IOKit.C_INT, + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(ReadPipeAsyncTO.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(ReadPipeAsyncTO.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, int _x4, int _x5, MemorySegment _x6, MemorySegment _x7) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5, _x6, _x7); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } - public static WritePipe WritePipe(MemorySegment segment, Arena scope) { - return WritePipe.ofAddress(WritePipe$get(segment), scope); + + private static final AddressLayout ReadPipeAsyncTO$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("ReadPipeAsyncTO")); + + /** + * Layout for field: + * {@snippet lang=c : + * IOReturn (*ReadPipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *) + * } + */ + public static final AddressLayout ReadPipeAsyncTO$layout() { + return ReadPipeAsyncTO$LAYOUT; } + + private static final long ReadPipeAsyncTO$OFFSET = 328; + /** - * {@snippet : - * IOReturn (*ReadPipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*ReadPipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *) * } */ - public interface ReadPipeAsync { - - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3, java.lang.foreign.MemorySegment _x4, java.lang.foreign.MemorySegment _x5); - static MemorySegment allocate(ReadPipeAsync fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$32.const$5, fi, constants$32.const$4, scope); - } - static ReadPipeAsync ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3, java.lang.foreign.MemorySegment __x4, java.lang.foreign.MemorySegment __x5) -> { - try { - return (int)constants$33.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long ReadPipeAsyncTO$offset() { + return ReadPipeAsyncTO$OFFSET; } - public static VarHandle ReadPipeAsync$VH() { - return constants$33.const$1; - } /** * Getter for field: - * {@snippet : - * IOReturn (*ReadPipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); + * {@snippet lang=c : + * IOReturn (*ReadPipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *) * } */ - public static MemorySegment ReadPipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$33.const$1.get(seg); + public static MemorySegment ReadPipeAsyncTO(MemorySegment struct) { + return struct.get(ReadPipeAsyncTO$LAYOUT, ReadPipeAsyncTO$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*ReadPipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); + * {@snippet lang=c : + * IOReturn (*ReadPipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *) * } */ - public static void ReadPipeAsync$set(MemorySegment seg, MemorySegment x) { - constants$33.const$1.set(seg, x); - } - public static MemorySegment ReadPipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$33.const$1.get(seg.asSlice(index*sizeof())); - } - public static void ReadPipeAsync$set(MemorySegment seg, long index, MemorySegment x) { - constants$33.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static ReadPipeAsync ReadPipeAsync(MemorySegment segment, Arena scope) { - return ReadPipeAsync.ofAddress(ReadPipeAsync$get(segment), scope); + public static void ReadPipeAsyncTO(MemorySegment struct, MemorySegment fieldValue) { + struct.set(ReadPipeAsyncTO$LAYOUT, ReadPipeAsyncTO$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*WritePipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); + * {@snippet lang=c : + * IOReturn (*WritePipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *) * } */ - public interface WritePipeAsync { + public static class WritePipeAsyncTO { - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3, java.lang.foreign.MemorySegment _x4, java.lang.foreign.MemorySegment _x5); - static MemorySegment allocate(WritePipeAsync fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$33.const$2, fi, constants$32.const$4, scope); + WritePipeAsyncTO() { + // Should not be called directly } - static WritePipeAsync ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3, java.lang.foreign.MemorySegment __x4, java.lang.foreign.MemorySegment __x5) -> { - try { - return (int)constants$33.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, int _x4, int _x5, MemorySegment _x6, MemorySegment _x7); } - } - public static VarHandle WritePipeAsync$VH() { - return constants$33.const$3; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*WritePipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); - * } - */ - public static MemorySegment WritePipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$33.const$3.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_POINTER, + IOKit.C_INT, + IOKit.C_INT, + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(WritePipeAsyncTO.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(WritePipeAsyncTO.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, int _x4, int _x5, MemorySegment _x6, MemorySegment _x7) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5, _x6, _x7); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout WritePipeAsyncTO$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("WritePipeAsyncTO")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*WritePipeAsync)(void*,UInt8,void*,UInt32,IOAsyncCallback1,void*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*WritePipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *) * } */ - public static void WritePipeAsync$set(MemorySegment seg, MemorySegment x) { - constants$33.const$3.set(seg, x); - } - public static MemorySegment WritePipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$33.const$3.get(seg.asSlice(index*sizeof())); - } - public static void WritePipeAsync$set(MemorySegment seg, long index, MemorySegment x) { - constants$33.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static WritePipeAsync WritePipeAsync(MemorySegment segment, Arena scope) { - return WritePipeAsync.ofAddress(WritePipeAsync$get(segment), scope); + public static final AddressLayout WritePipeAsyncTO$layout() { + return WritePipeAsyncTO$LAYOUT; } + + private static final long WritePipeAsyncTO$OFFSET = 336; + /** - * {@snippet : - * IOReturn (*ReadIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*WritePipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *) * } */ - public interface ReadIsochPipeAsync { - - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, long _x3, int _x4, java.lang.foreign.MemorySegment _x5, java.lang.foreign.MemorySegment _x6, java.lang.foreign.MemorySegment _x7); - static MemorySegment allocate(ReadIsochPipeAsync fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$33.const$5, fi, constants$33.const$4, scope); - } - static ReadIsochPipeAsync ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, long __x3, int __x4, java.lang.foreign.MemorySegment __x5, java.lang.foreign.MemorySegment __x6, java.lang.foreign.MemorySegment __x7) -> { - try { - return (int)constants$34.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long WritePipeAsyncTO$offset() { + return WritePipeAsyncTO$OFFSET; } - public static VarHandle ReadIsochPipeAsync$VH() { - return constants$34.const$1; - } /** * Getter for field: - * {@snippet : - * IOReturn (*ReadIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); + * {@snippet lang=c : + * IOReturn (*WritePipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *) * } */ - public static MemorySegment ReadIsochPipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$34.const$1.get(seg); + public static MemorySegment WritePipeAsyncTO(MemorySegment struct) { + return struct.get(WritePipeAsyncTO$LAYOUT, WritePipeAsyncTO$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*ReadIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); + * {@snippet lang=c : + * IOReturn (*WritePipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *) * } */ - public static void ReadIsochPipeAsync$set(MemorySegment seg, MemorySegment x) { - constants$34.const$1.set(seg, x); - } - public static MemorySegment ReadIsochPipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$34.const$1.get(seg.asSlice(index*sizeof())); - } - public static void ReadIsochPipeAsync$set(MemorySegment seg, long index, MemorySegment x) { - constants$34.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static ReadIsochPipeAsync ReadIsochPipeAsync(MemorySegment segment, Arena scope) { - return ReadIsochPipeAsync.ofAddress(ReadIsochPipeAsync$get(segment), scope); + public static void WritePipeAsyncTO(MemorySegment struct, MemorySegment fieldValue) { + struct.set(WritePipeAsyncTO$LAYOUT, WritePipeAsyncTO$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*WriteIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); + * {@snippet lang=c : + * IOReturn (*USBInterfaceGetStringIndex)(void *, UInt8 *) * } */ - public interface WriteIsochPipeAsync { + public static class USBInterfaceGetStringIndex { - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, long _x3, int _x4, java.lang.foreign.MemorySegment _x5, java.lang.foreign.MemorySegment _x6, java.lang.foreign.MemorySegment _x7); - static MemorySegment allocate(WriteIsochPipeAsync fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$34.const$2, fi, constants$33.const$4, scope); + USBInterfaceGetStringIndex() { + // Should not be called directly } - static WriteIsochPipeAsync ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, long __x3, int __x4, java.lang.foreign.MemorySegment __x5, java.lang.foreign.MemorySegment __x6, java.lang.foreign.MemorySegment __x7) -> { - try { - return (int)constants$34.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - } - public static VarHandle WriteIsochPipeAsync$VH() { - return constants$34.const$3; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*WriteIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); - * } - */ - public static MemorySegment WriteIsochPipeAsync$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$34.const$3.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(USBInterfaceGetStringIndex.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(USBInterfaceGetStringIndex.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout USBInterfaceGetStringIndex$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("USBInterfaceGetStringIndex")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*WriteIsochPipeAsync)(void*,UInt8,void*,UInt64,UInt32,IOUSBIsocFrame*,IOAsyncCallback1,void*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*USBInterfaceGetStringIndex)(void *, UInt8 *) * } */ - public static void WriteIsochPipeAsync$set(MemorySegment seg, MemorySegment x) { - constants$34.const$3.set(seg, x); - } - public static MemorySegment WriteIsochPipeAsync$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$34.const$3.get(seg.asSlice(index*sizeof())); - } - public static void WriteIsochPipeAsync$set(MemorySegment seg, long index, MemorySegment x) { - constants$34.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static WriteIsochPipeAsync WriteIsochPipeAsync(MemorySegment segment, Arena scope) { - return WriteIsochPipeAsync.ofAddress(WriteIsochPipeAsync$get(segment), scope); + public static final AddressLayout USBInterfaceGetStringIndex$layout() { + return USBInterfaceGetStringIndex$LAYOUT; } + + private static final long USBInterfaceGetStringIndex$OFFSET = 344; + /** - * {@snippet : - * IOReturn (*ControlRequestTO)(void*,UInt8,IOUSBDevRequestTO*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*USBInterfaceGetStringIndex)(void *, UInt8 *) * } */ - public interface ControlRequestTO { - - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2); - static MemorySegment allocate(ControlRequestTO fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$34.const$4, fi, constants$13.const$0, scope); - } - static ControlRequestTO ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2) -> { - try { - return (int)constants$13.const$2.invokeExact(symbol, __x0, __x1, __x2); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long USBInterfaceGetStringIndex$offset() { + return USBInterfaceGetStringIndex$OFFSET; } - public static VarHandle ControlRequestTO$VH() { - return constants$34.const$5; - } /** * Getter for field: - * {@snippet : - * IOReturn (*ControlRequestTO)(void*,UInt8,IOUSBDevRequestTO*); + * {@snippet lang=c : + * IOReturn (*USBInterfaceGetStringIndex)(void *, UInt8 *) * } */ - public static MemorySegment ControlRequestTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$34.const$5.get(seg); + public static MemorySegment USBInterfaceGetStringIndex(MemorySegment struct) { + return struct.get(USBInterfaceGetStringIndex$LAYOUT, USBInterfaceGetStringIndex$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*ControlRequestTO)(void*,UInt8,IOUSBDevRequestTO*); + * {@snippet lang=c : + * IOReturn (*USBInterfaceGetStringIndex)(void *, UInt8 *) * } */ - public static void ControlRequestTO$set(MemorySegment seg, MemorySegment x) { - constants$34.const$5.set(seg, x); - } - public static MemorySegment ControlRequestTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$34.const$5.get(seg.asSlice(index*sizeof())); - } - public static void ControlRequestTO$set(MemorySegment seg, long index, MemorySegment x) { - constants$34.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static ControlRequestTO ControlRequestTO(MemorySegment segment, Arena scope) { - return ControlRequestTO.ofAddress(ControlRequestTO$get(segment), scope); + public static void USBInterfaceGetStringIndex(MemorySegment struct, MemorySegment fieldValue) { + struct.set(USBInterfaceGetStringIndex$LAYOUT, USBInterfaceGetStringIndex$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*ControlRequestAsyncTO)(void*,UInt8,IOUSBDevRequestTO*,IOAsyncCallback1,void*); + * {@snippet lang=c : + * IOReturn (*USBInterfaceOpenSeize)(void *) * } */ - public interface ControlRequestAsyncTO { + public static class USBInterfaceOpenSeize { - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3, java.lang.foreign.MemorySegment _x4); - static MemorySegment allocate(ControlRequestAsyncTO fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$35.const$0, fi, constants$28.const$4, scope); + USBInterfaceOpenSeize() { + // Should not be called directly } - static ControlRequestAsyncTO ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3, java.lang.foreign.MemorySegment __x4) -> { - try { - return (int)constants$29.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0); } - } - public static VarHandle ControlRequestAsyncTO$VH() { - return constants$35.const$1; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*ControlRequestAsyncTO)(void*,UInt8,IOUSBDevRequestTO*,IOAsyncCallback1,void*); - * } - */ - public static MemorySegment ControlRequestAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$35.const$1.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(USBInterfaceOpenSeize.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(USBInterfaceOpenSeize.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout USBInterfaceOpenSeize$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("USBInterfaceOpenSeize")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*ControlRequestAsyncTO)(void*,UInt8,IOUSBDevRequestTO*,IOAsyncCallback1,void*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*USBInterfaceOpenSeize)(void *) * } */ - public static void ControlRequestAsyncTO$set(MemorySegment seg, MemorySegment x) { - constants$35.const$1.set(seg, x); - } - public static MemorySegment ControlRequestAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$35.const$1.get(seg.asSlice(index*sizeof())); - } - public static void ControlRequestAsyncTO$set(MemorySegment seg, long index, MemorySegment x) { - constants$35.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static ControlRequestAsyncTO ControlRequestAsyncTO(MemorySegment segment, Arena scope) { - return ControlRequestAsyncTO.ofAddress(ControlRequestAsyncTO$get(segment), scope); + public static final AddressLayout USBInterfaceOpenSeize$layout() { + return USBInterfaceOpenSeize$LAYOUT; } + + private static final long USBInterfaceOpenSeize$OFFSET = 352; + /** - * {@snippet : - * IOReturn (*ReadPipeTO)(void*,UInt8,void*,UInt32*,UInt32,UInt32); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*USBInterfaceOpenSeize)(void *) * } */ - public interface ReadPipeTO { - - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, java.lang.foreign.MemorySegment _x3, int _x4, int _x5); - static MemorySegment allocate(ReadPipeTO fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$35.const$3, fi, constants$35.const$2, scope); - } - static ReadPipeTO ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, java.lang.foreign.MemorySegment __x3, int __x4, int __x5) -> { - try { - return (int)constants$35.const$4.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long USBInterfaceOpenSeize$offset() { + return USBInterfaceOpenSeize$OFFSET; } - public static VarHandle ReadPipeTO$VH() { - return constants$35.const$5; - } /** * Getter for field: - * {@snippet : - * IOReturn (*ReadPipeTO)(void*,UInt8,void*,UInt32*,UInt32,UInt32); + * {@snippet lang=c : + * IOReturn (*USBInterfaceOpenSeize)(void *) * } */ - public static MemorySegment ReadPipeTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$35.const$5.get(seg); + public static MemorySegment USBInterfaceOpenSeize(MemorySegment struct) { + return struct.get(USBInterfaceOpenSeize$LAYOUT, USBInterfaceOpenSeize$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*ReadPipeTO)(void*,UInt8,void*,UInt32*,UInt32,UInt32); + * {@snippet lang=c : + * IOReturn (*USBInterfaceOpenSeize)(void *) * } */ - public static void ReadPipeTO$set(MemorySegment seg, MemorySegment x) { - constants$35.const$5.set(seg, x); - } - public static MemorySegment ReadPipeTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$35.const$5.get(seg.asSlice(index*sizeof())); - } - public static void ReadPipeTO$set(MemorySegment seg, long index, MemorySegment x) { - constants$35.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static ReadPipeTO ReadPipeTO(MemorySegment segment, Arena scope) { - return ReadPipeTO.ofAddress(ReadPipeTO$get(segment), scope); + public static void USBInterfaceOpenSeize(MemorySegment struct, MemorySegment fieldValue) { + struct.set(USBInterfaceOpenSeize$LAYOUT, USBInterfaceOpenSeize$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*WritePipeTO)(void*,UInt8,void*,UInt32,UInt32,UInt32); + * {@snippet lang=c : + * IOReturn (*ClearPipeStallBothEnds)(void *, UInt8) * } */ - public interface WritePipeTO { + public static class ClearPipeStallBothEnds { - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3, int _x4, int _x5); - static MemorySegment allocate(WritePipeTO fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$36.const$1, fi, constants$36.const$0, scope); + ClearPipeStallBothEnds() { + // Should not be called directly } - static WritePipeTO ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3, int __x4, int __x5) -> { - try { - return (int)constants$36.const$2.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1); } - } - public static VarHandle WritePipeTO$VH() { - return constants$36.const$3; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*WritePipeTO)(void*,UInt8,void*,UInt32,UInt32,UInt32); - * } - */ - public static MemorySegment WritePipeTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$36.const$3.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(ClearPipeStallBothEnds.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(ClearPipeStallBothEnds.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout ClearPipeStallBothEnds$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("ClearPipeStallBothEnds")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*WritePipeTO)(void*,UInt8,void*,UInt32,UInt32,UInt32); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*ClearPipeStallBothEnds)(void *, UInt8) * } */ - public static void WritePipeTO$set(MemorySegment seg, MemorySegment x) { - constants$36.const$3.set(seg, x); - } - public static MemorySegment WritePipeTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$36.const$3.get(seg.asSlice(index*sizeof())); - } - public static void WritePipeTO$set(MemorySegment seg, long index, MemorySegment x) { - constants$36.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static WritePipeTO WritePipeTO(MemorySegment segment, Arena scope) { - return WritePipeTO.ofAddress(WritePipeTO$get(segment), scope); + public static final AddressLayout ClearPipeStallBothEnds$layout() { + return ClearPipeStallBothEnds$LAYOUT; } + + private static final long ClearPipeStallBothEnds$OFFSET = 360; + /** - * {@snippet : - * IOReturn (*ReadPipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*ClearPipeStallBothEnds)(void *, UInt8) * } */ - public interface ReadPipeAsyncTO { - - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3, int _x4, int _x5, java.lang.foreign.MemorySegment _x6, java.lang.foreign.MemorySegment _x7); - static MemorySegment allocate(ReadPipeAsyncTO fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$36.const$5, fi, constants$36.const$4, scope); - } - static ReadPipeAsyncTO ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3, int __x4, int __x5, java.lang.foreign.MemorySegment __x6, java.lang.foreign.MemorySegment __x7) -> { - try { - return (int)constants$37.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long ClearPipeStallBothEnds$offset() { + return ClearPipeStallBothEnds$OFFSET; } - public static VarHandle ReadPipeAsyncTO$VH() { - return constants$37.const$1; - } /** * Getter for field: - * {@snippet : - * IOReturn (*ReadPipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); + * {@snippet lang=c : + * IOReturn (*ClearPipeStallBothEnds)(void *, UInt8) * } */ - public static MemorySegment ReadPipeAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$37.const$1.get(seg); + public static MemorySegment ClearPipeStallBothEnds(MemorySegment struct) { + return struct.get(ClearPipeStallBothEnds$LAYOUT, ClearPipeStallBothEnds$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*ReadPipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); + * {@snippet lang=c : + * IOReturn (*ClearPipeStallBothEnds)(void *, UInt8) * } */ - public static void ReadPipeAsyncTO$set(MemorySegment seg, MemorySegment x) { - constants$37.const$1.set(seg, x); - } - public static MemorySegment ReadPipeAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$37.const$1.get(seg.asSlice(index*sizeof())); - } - public static void ReadPipeAsyncTO$set(MemorySegment seg, long index, MemorySegment x) { - constants$37.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static ReadPipeAsyncTO ReadPipeAsyncTO(MemorySegment segment, Arena scope) { - return ReadPipeAsyncTO.ofAddress(ReadPipeAsyncTO$get(segment), scope); + public static void ClearPipeStallBothEnds(MemorySegment struct, MemorySegment fieldValue) { + struct.set(ClearPipeStallBothEnds$LAYOUT, ClearPipeStallBothEnds$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*WritePipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); + * {@snippet lang=c : + * IOReturn (*SetPipePolicy)(void *, UInt8, UInt16, UInt8) * } */ - public interface WritePipeAsyncTO { + public static class SetPipePolicy { - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, java.lang.foreign.MemorySegment _x2, int _x3, int _x4, int _x5, java.lang.foreign.MemorySegment _x6, java.lang.foreign.MemorySegment _x7); - static MemorySegment allocate(WritePipeAsyncTO fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$37.const$2, fi, constants$36.const$4, scope); + SetPipePolicy() { + // Should not be called directly } - static WritePipeAsyncTO ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, java.lang.foreign.MemorySegment __x2, int __x3, int __x4, int __x5, java.lang.foreign.MemorySegment __x6, java.lang.foreign.MemorySegment __x7) -> { - try { - return (int)constants$37.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, short _x2, byte _x3); } - } - public static VarHandle WritePipeAsyncTO$VH() { - return constants$37.const$3; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*WritePipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); - * } - */ - public static MemorySegment WritePipeAsyncTO$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$37.const$3.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_SHORT, + IOKit.C_CHAR + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(SetPipePolicy.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(SetPipePolicy.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, short _x2, byte _x3) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout SetPipePolicy$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("SetPipePolicy")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*WritePipeAsyncTO)(void*,UInt8,void*,UInt32,UInt32,UInt32,IOAsyncCallback1,void*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*SetPipePolicy)(void *, UInt8, UInt16, UInt8) * } */ - public static void WritePipeAsyncTO$set(MemorySegment seg, MemorySegment x) { - constants$37.const$3.set(seg, x); - } - public static MemorySegment WritePipeAsyncTO$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$37.const$3.get(seg.asSlice(index*sizeof())); - } - public static void WritePipeAsyncTO$set(MemorySegment seg, long index, MemorySegment x) { - constants$37.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static WritePipeAsyncTO WritePipeAsyncTO(MemorySegment segment, Arena scope) { - return WritePipeAsyncTO.ofAddress(WritePipeAsyncTO$get(segment), scope); + public static final AddressLayout SetPipePolicy$layout() { + return SetPipePolicy$LAYOUT; } + + private static final long SetPipePolicy$OFFSET = 368; + /** - * {@snippet : - * IOReturn (*USBInterfaceGetStringIndex)(void*,UInt8*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*SetPipePolicy)(void *, UInt8, UInt16, UInt8) * } */ - public interface USBInterfaceGetStringIndex { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(USBInterfaceGetStringIndex fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$37.const$4, fi, constants$6.const$5, scope); - } - static USBInterfaceGetStringIndex ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long SetPipePolicy$offset() { + return SetPipePolicy$OFFSET; } - public static VarHandle USBInterfaceGetStringIndex$VH() { - return constants$37.const$5; - } /** * Getter for field: - * {@snippet : - * IOReturn (*USBInterfaceGetStringIndex)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*SetPipePolicy)(void *, UInt8, UInt16, UInt8) * } */ - public static MemorySegment USBInterfaceGetStringIndex$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$37.const$5.get(seg); + public static MemorySegment SetPipePolicy(MemorySegment struct) { + return struct.get(SetPipePolicy$LAYOUT, SetPipePolicy$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*USBInterfaceGetStringIndex)(void*,UInt8*); + * {@snippet lang=c : + * IOReturn (*SetPipePolicy)(void *, UInt8, UInt16, UInt8) * } */ - public static void USBInterfaceGetStringIndex$set(MemorySegment seg, MemorySegment x) { - constants$37.const$5.set(seg, x); - } - public static MemorySegment USBInterfaceGetStringIndex$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$37.const$5.get(seg.asSlice(index*sizeof())); - } - public static void USBInterfaceGetStringIndex$set(MemorySegment seg, long index, MemorySegment x) { - constants$37.const$5.set(seg.asSlice(index*sizeof()), x); - } - public static USBInterfaceGetStringIndex USBInterfaceGetStringIndex(MemorySegment segment, Arena scope) { - return USBInterfaceGetStringIndex.ofAddress(USBInterfaceGetStringIndex$get(segment), scope); + public static void SetPipePolicy(MemorySegment struct, MemorySegment fieldValue) { + struct.set(SetPipePolicy$LAYOUT, SetPipePolicy$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*USBInterfaceOpenSeize)(void*); + * {@snippet lang=c : + * IOReturn (*GetBandwidthAvailable)(void *, UInt32 *) * } */ - public interface USBInterfaceOpenSeize { + public static class GetBandwidthAvailable { - int apply(java.lang.foreign.MemorySegment _x0); - static MemorySegment allocate(USBInterfaceOpenSeize fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$38.const$0, fi, constants$5.const$5, scope); + GetBandwidthAvailable() { + // Should not be called directly } - static USBInterfaceOpenSeize ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0) -> { - try { - return (int)constants$6.const$1.invokeExact(symbol, __x0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, MemorySegment _x1); } - } - public static VarHandle USBInterfaceOpenSeize$VH() { - return constants$38.const$1; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*USBInterfaceOpenSeize)(void*); - * } - */ - public static MemorySegment USBInterfaceOpenSeize$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$38.const$1.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetBandwidthAvailable.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetBandwidthAvailable.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout GetBandwidthAvailable$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetBandwidthAvailable")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*USBInterfaceOpenSeize)(void*); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetBandwidthAvailable)(void *, UInt32 *) * } */ - public static void USBInterfaceOpenSeize$set(MemorySegment seg, MemorySegment x) { - constants$38.const$1.set(seg, x); - } - public static MemorySegment USBInterfaceOpenSeize$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$38.const$1.get(seg.asSlice(index*sizeof())); - } - public static void USBInterfaceOpenSeize$set(MemorySegment seg, long index, MemorySegment x) { - constants$38.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static USBInterfaceOpenSeize USBInterfaceOpenSeize(MemorySegment segment, Arena scope) { - return USBInterfaceOpenSeize.ofAddress(USBInterfaceOpenSeize$get(segment), scope); + public static final AddressLayout GetBandwidthAvailable$layout() { + return GetBandwidthAvailable$LAYOUT; } + + private static final long GetBandwidthAvailable$OFFSET = 376; + /** - * {@snippet : - * IOReturn (*ClearPipeStallBothEnds)(void*,UInt8); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetBandwidthAvailable)(void *, UInt32 *) * } */ - public interface ClearPipeStallBothEnds { - - int apply(java.lang.foreign.MemorySegment _x0, byte _x1); - static MemorySegment allocate(ClearPipeStallBothEnds fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$38.const$2, fi, constants$14.const$0, scope); - } - static ClearPipeStallBothEnds ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1) -> { - try { - return (int)constants$14.const$2.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long GetBandwidthAvailable$offset() { + return GetBandwidthAvailable$OFFSET; } - public static VarHandle ClearPipeStallBothEnds$VH() { - return constants$38.const$3; - } /** * Getter for field: - * {@snippet : - * IOReturn (*ClearPipeStallBothEnds)(void*,UInt8); + * {@snippet lang=c : + * IOReturn (*GetBandwidthAvailable)(void *, UInt32 *) * } */ - public static MemorySegment ClearPipeStallBothEnds$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$38.const$3.get(seg); + public static MemorySegment GetBandwidthAvailable(MemorySegment struct) { + return struct.get(GetBandwidthAvailable$LAYOUT, GetBandwidthAvailable$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*ClearPipeStallBothEnds)(void*,UInt8); + * {@snippet lang=c : + * IOReturn (*GetBandwidthAvailable)(void *, UInt32 *) * } */ - public static void ClearPipeStallBothEnds$set(MemorySegment seg, MemorySegment x) { - constants$38.const$3.set(seg, x); - } - public static MemorySegment ClearPipeStallBothEnds$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$38.const$3.get(seg.asSlice(index*sizeof())); - } - public static void ClearPipeStallBothEnds$set(MemorySegment seg, long index, MemorySegment x) { - constants$38.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static ClearPipeStallBothEnds ClearPipeStallBothEnds(MemorySegment segment, Arena scope) { - return ClearPipeStallBothEnds.ofAddress(ClearPipeStallBothEnds$get(segment), scope); + public static void GetBandwidthAvailable(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetBandwidthAvailable$LAYOUT, GetBandwidthAvailable$OFFSET, fieldValue); } + /** - * {@snippet : - * IOReturn (*SetPipePolicy)(void*,UInt8,UInt16,UInt8); + * {@snippet lang=c : + * IOReturn (*GetEndpointProperties)(void *, UInt8, UInt8, UInt8, UInt8 *, UInt16 *, UInt8 *) * } */ - public interface SetPipePolicy { + public static class GetEndpointProperties { - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, short _x2, byte _x3); - static MemorySegment allocate(SetPipePolicy fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$38.const$5, fi, constants$38.const$4, scope); + GetEndpointProperties() { + // Should not be called directly } - static SetPipePolicy ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, short __x2, byte __x3) -> { - try { - return (int)constants$39.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + int apply(MemorySegment _x0, byte _x1, byte _x2, byte _x3, MemorySegment _x4, MemorySegment _x5, MemorySegment _x6); } - } - public static VarHandle SetPipePolicy$VH() { - return constants$39.const$1; - } - /** - * Getter for field: - * {@snippet : - * IOReturn (*SetPipePolicy)(void*,UInt8,UInt16,UInt8); - * } - */ - public static MemorySegment SetPipePolicy$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$39.const$1.get(seg); + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + IOKit.C_INT, + IOKit.C_POINTER, + IOKit.C_CHAR, + IOKit.C_CHAR, + IOKit.C_CHAR, + IOKit.C_POINTER, + IOKit.C_POINTER, + IOKit.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = IOKit.upcallHandle(GetEndpointProperties.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(GetEndpointProperties.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, byte _x2, byte _x3, MemorySegment _x4, MemorySegment _x5, MemorySegment _x6) { + try { + return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5, _x6); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } + + private static final AddressLayout GetEndpointProperties$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("GetEndpointProperties")); + /** - * Setter for field: - * {@snippet : - * IOReturn (*SetPipePolicy)(void*,UInt8,UInt16,UInt8); + * Layout for field: + * {@snippet lang=c : + * IOReturn (*GetEndpointProperties)(void *, UInt8, UInt8, UInt8, UInt8 *, UInt16 *, UInt8 *) * } */ - public static void SetPipePolicy$set(MemorySegment seg, MemorySegment x) { - constants$39.const$1.set(seg, x); - } - public static MemorySegment SetPipePolicy$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$39.const$1.get(seg.asSlice(index*sizeof())); - } - public static void SetPipePolicy$set(MemorySegment seg, long index, MemorySegment x) { - constants$39.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static SetPipePolicy SetPipePolicy(MemorySegment segment, Arena scope) { - return SetPipePolicy.ofAddress(SetPipePolicy$get(segment), scope); + public static final AddressLayout GetEndpointProperties$layout() { + return GetEndpointProperties$LAYOUT; } + + private static final long GetEndpointProperties$OFFSET = 384; + /** - * {@snippet : - * IOReturn (*GetBandwidthAvailable)(void*,UInt32*); + * Offset for field: + * {@snippet lang=c : + * IOReturn (*GetEndpointProperties)(void *, UInt8, UInt8, UInt8, UInt8 *, UInt16 *, UInt8 *) * } */ - public interface GetBandwidthAvailable { - - int apply(java.lang.foreign.MemorySegment _x0, java.lang.foreign.MemorySegment _x1); - static MemorySegment allocate(GetBandwidthAvailable fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$39.const$2, fi, constants$6.const$5, scope); - } - static GetBandwidthAvailable ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, java.lang.foreign.MemorySegment __x1) -> { - try { - return (int)constants$7.const$1.invokeExact(symbol, __x0, __x1); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + public static final long GetEndpointProperties$offset() { + return GetEndpointProperties$OFFSET; } - public static VarHandle GetBandwidthAvailable$VH() { - return constants$39.const$3; - } /** * Getter for field: - * {@snippet : - * IOReturn (*GetBandwidthAvailable)(void*,UInt32*); + * {@snippet lang=c : + * IOReturn (*GetEndpointProperties)(void *, UInt8, UInt8, UInt8, UInt8 *, UInt16 *, UInt8 *) * } */ - public static MemorySegment GetBandwidthAvailable$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$39.const$3.get(seg); + public static MemorySegment GetEndpointProperties(MemorySegment struct) { + return struct.get(GetEndpointProperties$LAYOUT, GetEndpointProperties$OFFSET); } + /** * Setter for field: - * {@snippet : - * IOReturn (*GetBandwidthAvailable)(void*,UInt32*); + * {@snippet lang=c : + * IOReturn (*GetEndpointProperties)(void *, UInt8, UInt8, UInt8, UInt8 *, UInt16 *, UInt8 *) * } */ - public static void GetBandwidthAvailable$set(MemorySegment seg, MemorySegment x) { - constants$39.const$3.set(seg, x); + public static void GetEndpointProperties(MemorySegment struct, MemorySegment fieldValue) { + struct.set(GetEndpointProperties$LAYOUT, GetEndpointProperties$OFFSET, fieldValue); } - public static MemorySegment GetBandwidthAvailable$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$39.const$3.get(seg.asSlice(index*sizeof())); - } - public static void GetBandwidthAvailable$set(MemorySegment seg, long index, MemorySegment x) { - constants$39.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static GetBandwidthAvailable GetBandwidthAvailable(MemorySegment segment, Arena scope) { - return GetBandwidthAvailable.ofAddress(GetBandwidthAvailable$get(segment), scope); + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); } + /** - * {@snippet : - * IOReturn (*GetEndpointProperties)(void*,UInt8,UInt8,UInt8,UInt8*,UInt16*,UInt8*); - * } + * The size (in bytes) of this struct */ - public interface GetEndpointProperties { + public static long sizeof() { return layout().byteSize(); } - int apply(java.lang.foreign.MemorySegment _x0, byte _x1, byte _x2, byte _x3, java.lang.foreign.MemorySegment _x4, java.lang.foreign.MemorySegment _x5, java.lang.foreign.MemorySegment _x6); - static MemorySegment allocate(GetEndpointProperties fi, Arena scope) { - return RuntimeHelper.upcallStub(constants$39.const$5, fi, constants$39.const$4, scope); - } - static GetEndpointProperties ofAddress(MemorySegment addr, Arena arena) { - MemorySegment symbol = addr.reinterpret(arena, null); - return (java.lang.foreign.MemorySegment __x0, byte __x1, byte __x2, byte __x3, java.lang.foreign.MemorySegment __x4, java.lang.foreign.MemorySegment __x5, java.lang.foreign.MemorySegment __x6) -> { - try { - return (int)constants$40.const$0.invokeExact(symbol, __x0, __x1, __x2, __x3, __x4, __x5, __x6); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - }; - } + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); } - public static VarHandle GetEndpointProperties$VH() { - return constants$40.const$1; - } /** - * Getter for field: - * {@snippet : - * IOReturn (*GetEndpointProperties)(void*,UInt8,UInt8,UInt8,UInt8*,UInt16*,UInt8*); - * } + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. */ - public static MemorySegment GetEndpointProperties$get(MemorySegment seg) { - return (java.lang.foreign.MemorySegment)constants$40.const$1.get(seg); + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); } + /** - * Setter for field: - * {@snippet : - * IOReturn (*GetEndpointProperties)(void*,UInt8,UInt8,UInt8,UInt8*,UInt16*,UInt8*); - * } + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code layout().byteSize()} */ - public static void GetEndpointProperties$set(MemorySegment seg, MemorySegment x) { - constants$40.const$1.set(seg, x); - } - public static MemorySegment GetEndpointProperties$get(MemorySegment seg, long index) { - return (java.lang.foreign.MemorySegment)constants$40.const$1.get(seg.asSlice(index*sizeof())); - } - public static void GetEndpointProperties$set(MemorySegment seg, long index, MemorySegment x) { - constants$40.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static GetEndpointProperties GetEndpointProperties(MemorySegment segment, Arena scope) { - return GetEndpointProperties.ofAddress(GetEndpointProperties$get(segment), scope); + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } } - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java deleted file mode 100644 index e628cf84..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/RuntimeHelper.java +++ /dev/null @@ -1,240 +0,0 @@ -package net.codecrete.usb.macos.gen.iokit; -// Generated by jextract - -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_LONG; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { -// System.loadLibrary("IOKit.framework"); -// SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SymbolLookup loaderLookup = SymbolLookup.libraryLookup("/System/Library/Frameworks/IOKit.framework/IOKit", Arena.global()); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java deleted file mode 100644 index 31a87068..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$0.java +++ /dev/null @@ -1,33 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final StructLayout const$0 = MemoryLayout.structLayout( - JAVA_BYTE.withName("bmRequestType"), - JAVA_BYTE.withName("bRequest"), - JAVA_SHORT.withName("wValue"), - JAVA_SHORT.withName("wIndex"), - JAVA_SHORT.withName("wLength"), - RuntimeHelper.POINTER.withName("pData"), - JAVA_INT.withName("wLenDone"), - MemoryLayout.paddingLayout(4) - ).withName(""); - static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("bmRequestType")); - static final VarHandle const$2 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("bRequest")); - static final VarHandle const$3 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("wValue")); - static final VarHandle const$4 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("wIndex")); - static final VarHandle const$5 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("wLength")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$1.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$1.java deleted file mode 100644 index 7f197c64..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$1.java +++ /dev/null @@ -1,27 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -final class constants$1 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$1() {} - static final VarHandle const$0 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("pData")); - static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("wLenDone")); - static final StructLayout const$2 = MemoryLayout.structLayout( - JAVA_SHORT.withName("bInterfaceClass"), - JAVA_SHORT.withName("bInterfaceSubClass"), - JAVA_SHORT.withName("bInterfaceProtocol"), - JAVA_SHORT.withName("bAlternateSetting") - ).withName(""); - static final VarHandle const$3 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("bInterfaceClass")); - static final VarHandle const$4 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("bInterfaceSubClass")); - static final VarHandle const$5 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("bInterfaceProtocol")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$10.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$10.java deleted file mode 100644 index 45874636..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$10.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$10 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$10() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceProtocol.class, "apply", constants$6.const$5); - static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProtocol")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceVendor.class, "apply", constants$6.const$5); - static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceVendor")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceProduct.class, "apply", constants$6.const$5); - static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProduct")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$11.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$11.java deleted file mode 100644 index 9e28e1bf..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$11.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$11 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$11() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceReleaseNumber.class, "apply", constants$6.const$5); - static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceReleaseNumber")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceAddress.class, "apply", constants$6.const$5); - static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAddress")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceBusPowerAvailable.class, "apply", constants$6.const$5); - static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceBusPowerAvailable")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$12.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$12.java deleted file mode 100644 index 13c8d1fd..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$12.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$12 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$12() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceSpeed.class, "apply", constants$6.const$5); - static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceSpeed")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetNumberOfConfigurations.class, "apply", constants$6.const$5); - static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetNumberOfConfigurations")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetLocationID.class, "apply", constants$6.const$5); - static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetLocationID")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$13.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$13.java deleted file mode 100644 index 39624ca6..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$13.java +++ /dev/null @@ -1,30 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$13 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$13() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - JAVA_BYTE, - RuntimeHelper.POINTER - ); - static final MethodHandle const$1 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetConfigurationDescriptorPtr.class, "apply", constants$13.const$0); - static final MethodHandle const$2 = RuntimeHelper.downcallHandle( - constants$13.const$0 - ); - static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetConfigurationDescriptorPtr")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetConfiguration.class, "apply", constants$6.const$5); - static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetConfiguration")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$14.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$14.java deleted file mode 100644 index f392ab2d..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$14.java +++ /dev/null @@ -1,33 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$14 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$14() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - JAVA_BYTE - ); - static final MethodHandle const$1 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.SetConfiguration.class, "apply", constants$14.const$0); - static final MethodHandle const$2 = RuntimeHelper.downcallHandle( - constants$14.const$0 - ); - static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("SetConfiguration")); - static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetBusFrameNumber.class, "apply", constants$14.const$4); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$15.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$15.java deleted file mode 100644 index 79a39ca9..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$15.java +++ /dev/null @@ -1,22 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$15 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$15() {} - static final MethodHandle const$0 = RuntimeHelper.downcallHandle( - constants$14.const$4 - ); - static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetBusFrameNumber")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.ResetDevice.class, "apply", constants$5.const$5); - static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("ResetDevice")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.DeviceRequest.class, "apply", constants$6.const$5); - static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequest")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$16.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$16.java deleted file mode 100644 index 4aaba200..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$16.java +++ /dev/null @@ -1,30 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$16 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$16() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$1 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.DeviceRequestAsync.class, "apply", constants$16.const$0); - static final MethodHandle const$2 = RuntimeHelper.downcallHandle( - constants$16.const$0 - ); - static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestAsync")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.CreateInterfaceIterator.class, "apply", constants$14.const$4); - static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceIterator")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$17.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$17.java deleted file mode 100644 index 18fbc0e1..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$17.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$17 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$17() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBDeviceOpenSeize.class, "apply", constants$5.const$5); - static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceOpenSeize")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.DeviceRequestTO.class, "apply", constants$6.const$5); - static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestTO")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.DeviceRequestAsyncTO.class, "apply", constants$16.const$0); - static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("DeviceRequestAsyncTO")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$18.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$18.java deleted file mode 100644 index c5cc1d28..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$18.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$18 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$18() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBDeviceSuspend.class, "apply", constants$14.const$0); - static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceSuspend")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBDeviceAbortPipeZero.class, "apply", constants$5.const$5); - static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceAbortPipeZero")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBGetManufacturerStringIndex.class, "apply", constants$6.const$5); - static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBGetManufacturerStringIndex")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$19.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$19.java deleted file mode 100644 index a1df6f77..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$19.java +++ /dev/null @@ -1,26 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$19 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$19() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBGetProductStringIndex.class, "apply", constants$6.const$5); - static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBGetProductStringIndex")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBGetSerialNumberStringIndex.class, "apply", constants$6.const$5); - static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBGetSerialNumberStringIndex")); - static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - JAVA_INT - ); - static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBDeviceReEnumerate.class, "apply", constants$19.const$4); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$2.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$2.java deleted file mode 100644 index 0e4c4512..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$2.java +++ /dev/null @@ -1,30 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$2 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$2() {} - static final VarHandle const$0 = constants$1.const$2.varHandle(MemoryLayout.PathElement.groupElement("bAlternateSetting")); - static final VarHandle const$1 = RuntimeHelper.POINTER.varHandle(); - static final MemorySegment const$2 = RuntimeHelper.lookupGlobalVariable("kCFRunLoopDefaultMode", RuntimeHelper.POINTER); - static final VarHandle const$3 = JAVA_INT.varHandle(); - static final MemorySegment const$4 = RuntimeHelper.lookupGlobalVariable("kIOMasterPortDefault", JAVA_INT); - static final FunctionDescriptor const$5 = FunctionDescriptor.of(RuntimeHelper.POINTER, - JAVA_INT - ); - static final MethodHandle const$6 = RuntimeHelper.downcallHandle( - "IONotificationPortCreate", - constants$2.const$5 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$20.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$20.java deleted file mode 100644 index a7e481c4..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$20.java +++ /dev/null @@ -1,73 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$20 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$20() {} - static final MethodHandle const$0 = RuntimeHelper.downcallHandle( - constants$19.const$4 - ); - static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceReEnumerate")); - static final StructLayout const$2 = MemoryLayout.structLayout( - RuntimeHelper.POINTER.withName("_reserved"), - RuntimeHelper.POINTER.withName("QueryInterface"), - RuntimeHelper.POINTER.withName("AddRef"), - RuntimeHelper.POINTER.withName("Release"), - RuntimeHelper.POINTER.withName("CreateInterfaceAsyncEventSource"), - RuntimeHelper.POINTER.withName("GetInterfaceAsyncEventSource"), - RuntimeHelper.POINTER.withName("CreateInterfaceAsyncPort"), - RuntimeHelper.POINTER.withName("GetInterfaceAsyncPort"), - RuntimeHelper.POINTER.withName("USBInterfaceOpen"), - RuntimeHelper.POINTER.withName("USBInterfaceClose"), - RuntimeHelper.POINTER.withName("GetInterfaceClass"), - RuntimeHelper.POINTER.withName("GetInterfaceSubClass"), - RuntimeHelper.POINTER.withName("GetInterfaceProtocol"), - RuntimeHelper.POINTER.withName("GetDeviceVendor"), - RuntimeHelper.POINTER.withName("GetDeviceProduct"), - RuntimeHelper.POINTER.withName("GetDeviceReleaseNumber"), - RuntimeHelper.POINTER.withName("GetConfigurationValue"), - RuntimeHelper.POINTER.withName("GetInterfaceNumber"), - RuntimeHelper.POINTER.withName("GetAlternateSetting"), - RuntimeHelper.POINTER.withName("GetNumEndpoints"), - RuntimeHelper.POINTER.withName("GetLocationID"), - RuntimeHelper.POINTER.withName("GetDevice"), - RuntimeHelper.POINTER.withName("SetAlternateInterface"), - RuntimeHelper.POINTER.withName("GetBusFrameNumber"), - RuntimeHelper.POINTER.withName("ControlRequest"), - RuntimeHelper.POINTER.withName("ControlRequestAsync"), - RuntimeHelper.POINTER.withName("GetPipeProperties"), - RuntimeHelper.POINTER.withName("GetPipeStatus"), - RuntimeHelper.POINTER.withName("AbortPipe"), - RuntimeHelper.POINTER.withName("ResetPipe"), - RuntimeHelper.POINTER.withName("ClearPipeStall"), - RuntimeHelper.POINTER.withName("ReadPipe"), - RuntimeHelper.POINTER.withName("WritePipe"), - RuntimeHelper.POINTER.withName("ReadPipeAsync"), - RuntimeHelper.POINTER.withName("WritePipeAsync"), - RuntimeHelper.POINTER.withName("ReadIsochPipeAsync"), - RuntimeHelper.POINTER.withName("WriteIsochPipeAsync"), - RuntimeHelper.POINTER.withName("ControlRequestTO"), - RuntimeHelper.POINTER.withName("ControlRequestAsyncTO"), - RuntimeHelper.POINTER.withName("ReadPipeTO"), - RuntimeHelper.POINTER.withName("WritePipeTO"), - RuntimeHelper.POINTER.withName("ReadPipeAsyncTO"), - RuntimeHelper.POINTER.withName("WritePipeAsyncTO"), - RuntimeHelper.POINTER.withName("USBInterfaceGetStringIndex"), - RuntimeHelper.POINTER.withName("USBInterfaceOpenSeize"), - RuntimeHelper.POINTER.withName("ClearPipeStallBothEnds"), - RuntimeHelper.POINTER.withName("SetPipePolicy"), - RuntimeHelper.POINTER.withName("GetBandwidthAvailable"), - RuntimeHelper.POINTER.withName("GetEndpointProperties") - ).withName("IOUSBInterfaceStruct190"); - static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("_reserved")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.QueryInterface.class, "apply", constants$5.const$1); - static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("QueryInterface")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$21.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$21.java deleted file mode 100644 index 11a65d3b..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$21.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$21 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$21() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.AddRef.class, "apply", constants$5.const$5); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("AddRef")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.Release.class, "apply", constants$5.const$5); - static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("Release")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.CreateInterfaceAsyncEventSource.class, "apply", constants$6.const$5); - static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceAsyncEventSource")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$22.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$22.java deleted file mode 100644 index c7b34333..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$22.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$22 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$22() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetInterfaceAsyncEventSource.class, "apply", constants$3.const$0); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceAsyncEventSource")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.CreateInterfaceAsyncPort.class, "apply", constants$6.const$5); - static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("CreateInterfaceAsyncPort")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetInterfaceAsyncPort.class, "apply", constants$5.const$5); - static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceAsyncPort")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$23.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$23.java deleted file mode 100644 index 51f5726d..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$23.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$23 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$23() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.USBInterfaceOpen.class, "apply", constants$5.const$5); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceOpen")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.USBInterfaceClose.class, "apply", constants$5.const$5); - static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceClose")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetInterfaceClass.class, "apply", constants$6.const$5); - static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceClass")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$24.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$24.java deleted file mode 100644 index 5f698e5c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$24.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$24 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$24() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetInterfaceSubClass.class, "apply", constants$6.const$5); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceSubClass")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetInterfaceProtocol.class, "apply", constants$6.const$5); - static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceProtocol")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetDeviceVendor.class, "apply", constants$6.const$5); - static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceVendor")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$25.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$25.java deleted file mode 100644 index ac0ee5fd..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$25.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$25 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$25() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetDeviceProduct.class, "apply", constants$6.const$5); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceProduct")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetDeviceReleaseNumber.class, "apply", constants$6.const$5); - static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceReleaseNumber")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetConfigurationValue.class, "apply", constants$6.const$5); - static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetConfigurationValue")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$26.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$26.java deleted file mode 100644 index 63ae0b5c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$26.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$26 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$26() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetInterfaceNumber.class, "apply", constants$6.const$5); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetInterfaceNumber")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetAlternateSetting.class, "apply", constants$6.const$5); - static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetAlternateSetting")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetNumEndpoints.class, "apply", constants$6.const$5); - static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetNumEndpoints")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$27.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$27.java deleted file mode 100644 index 3623d41b..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$27.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$27 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$27() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetLocationID.class, "apply", constants$6.const$5); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetLocationID")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetDevice.class, "apply", constants$6.const$5); - static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetDevice")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.SetAlternateInterface.class, "apply", constants$14.const$0); - static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("SetAlternateInterface")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$28.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$28.java deleted file mode 100644 index b34eb80a..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$28.java +++ /dev/null @@ -1,30 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$28 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$28() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetBusFrameNumber.class, "apply", constants$14.const$4); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetBusFrameNumber")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ControlRequest.class, "apply", constants$13.const$0); - static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ControlRequest")); - static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - JAVA_BYTE, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ControlRequestAsync.class, "apply", constants$28.const$4); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$29.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$29.java deleted file mode 100644 index a5466229..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$29.java +++ /dev/null @@ -1,36 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$29 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$29() {} - static final MethodHandle const$0 = RuntimeHelper.downcallHandle( - constants$28.const$4 - ); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ControlRequestAsync")); - static final FunctionDescriptor const$2 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - JAVA_BYTE, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$3 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetPipeProperties.class, "apply", constants$29.const$2); - static final MethodHandle const$4 = RuntimeHelper.downcallHandle( - constants$29.const$2 - ); - static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetPipeProperties")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$3.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$3.java deleted file mode 100644 index 320ddc7f..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$3.java +++ /dev/null @@ -1,45 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$3 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$3() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$1 = RuntimeHelper.downcallHandle( - "IONotificationPortGetRunLoopSource", - constants$3.const$0 - ); - static final FunctionDescriptor const$2 = FunctionDescriptor.of(JAVA_INT, - JAVA_INT - ); - static final MethodHandle const$3 = RuntimeHelper.downcallHandle( - "IOObjectRelease", - constants$3.const$2 - ); - static final MethodHandle const$4 = RuntimeHelper.downcallHandle( - "IOIteratorNext", - constants$3.const$2 - ); - static final FunctionDescriptor const$5 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$6 = RuntimeHelper.downcallHandle( - "IOServiceAddMatchingNotification", - constants$3.const$5 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$30.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$30.java deleted file mode 100644 index ab553ef3..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$30.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$30 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$30() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetPipeStatus.class, "apply", constants$14.const$0); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetPipeStatus")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.AbortPipe.class, "apply", constants$14.const$0); - static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("AbortPipe")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ResetPipe.class, "apply", constants$14.const$0); - static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ResetPipe")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$31.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$31.java deleted file mode 100644 index ea1c0dbc..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$31.java +++ /dev/null @@ -1,31 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$31 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$31() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ClearPipeStall.class, "apply", constants$14.const$0); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ClearPipeStall")); - static final FunctionDescriptor const$2 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - JAVA_BYTE, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$3 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ReadPipe.class, "apply", constants$31.const$2); - static final MethodHandle const$4 = RuntimeHelper.downcallHandle( - constants$31.const$2 - ); - static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ReadPipe")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$32.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$32.java deleted file mode 100644 index ee057f97..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$32.java +++ /dev/null @@ -1,38 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$32 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$32() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - JAVA_BYTE, - RuntimeHelper.POINTER, - JAVA_INT - ); - static final MethodHandle const$1 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.WritePipe.class, "apply", constants$32.const$0); - static final MethodHandle const$2 = RuntimeHelper.downcallHandle( - constants$32.const$0 - ); - static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("WritePipe")); - static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - JAVA_BYTE, - RuntimeHelper.POINTER, - JAVA_INT, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ReadPipeAsync.class, "apply", constants$32.const$4); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$33.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$33.java deleted file mode 100644 index 2976d004..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$33.java +++ /dev/null @@ -1,36 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -final class constants$33 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$33() {} - static final MethodHandle const$0 = RuntimeHelper.downcallHandle( - constants$32.const$4 - ); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ReadPipeAsync")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.WritePipeAsync.class, "apply", constants$32.const$4); - static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("WritePipeAsync")); - static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - JAVA_BYTE, - RuntimeHelper.POINTER, - JAVA_LONG, - JAVA_INT, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ReadIsochPipeAsync.class, "apply", constants$33.const$4); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$34.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$34.java deleted file mode 100644 index 0dd3c4c6..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$34.java +++ /dev/null @@ -1,22 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$34 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$34() {} - static final MethodHandle const$0 = RuntimeHelper.downcallHandle( - constants$33.const$4 - ); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ReadIsochPipeAsync")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.WriteIsochPipeAsync.class, "apply", constants$33.const$4); - static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("WriteIsochPipeAsync")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ControlRequestTO.class, "apply", constants$13.const$0); - static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ControlRequestTO")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$35.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$35.java deleted file mode 100644 index 315b2f75..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$35.java +++ /dev/null @@ -1,33 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$35 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$35() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ControlRequestAsyncTO.class, "apply", constants$28.const$4); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ControlRequestAsyncTO")); - static final FunctionDescriptor const$2 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - JAVA_BYTE, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - JAVA_INT, - JAVA_INT - ); - static final MethodHandle const$3 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ReadPipeTO.class, "apply", constants$35.const$2); - static final MethodHandle const$4 = RuntimeHelper.downcallHandle( - constants$35.const$2 - ); - static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ReadPipeTO")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$36.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$36.java deleted file mode 100644 index bd7bf064..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$36.java +++ /dev/null @@ -1,42 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$36 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$36() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - JAVA_BYTE, - RuntimeHelper.POINTER, - JAVA_INT, - JAVA_INT, - JAVA_INT - ); - static final MethodHandle const$1 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.WritePipeTO.class, "apply", constants$36.const$0); - static final MethodHandle const$2 = RuntimeHelper.downcallHandle( - constants$36.const$0 - ); - static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("WritePipeTO")); - static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - JAVA_BYTE, - RuntimeHelper.POINTER, - JAVA_INT, - JAVA_INT, - JAVA_INT, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ReadPipeAsyncTO.class, "apply", constants$36.const$4); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$37.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$37.java deleted file mode 100644 index 0d52f7d0..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$37.java +++ /dev/null @@ -1,22 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$37 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$37() {} - static final MethodHandle const$0 = RuntimeHelper.downcallHandle( - constants$36.const$4 - ); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ReadPipeAsyncTO")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.WritePipeAsyncTO.class, "apply", constants$36.const$4); - static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("WritePipeAsyncTO")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.USBInterfaceGetStringIndex.class, "apply", constants$6.const$5); - static final VarHandle const$5 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceGetStringIndex")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$38.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$38.java deleted file mode 100644 index e2de4fe2..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$38.java +++ /dev/null @@ -1,30 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -final class constants$38 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$38() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.USBInterfaceOpenSeize.class, "apply", constants$5.const$5); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("USBInterfaceOpenSeize")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.ClearPipeStallBothEnds.class, "apply", constants$14.const$0); - static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("ClearPipeStallBothEnds")); - static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - JAVA_BYTE, - JAVA_SHORT, - JAVA_BYTE - ); - static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.SetPipePolicy.class, "apply", constants$38.const$4); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$39.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$39.java deleted file mode 100644 index 0aaa0f85..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$39.java +++ /dev/null @@ -1,34 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$39 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$39() {} - static final MethodHandle const$0 = RuntimeHelper.downcallHandle( - constants$38.const$4 - ); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("SetPipePolicy")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetBandwidthAvailable.class, "apply", constants$6.const$5); - static final VarHandle const$3 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetBandwidthAvailable")); - static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - JAVA_BYTE, - JAVA_BYTE, - JAVA_BYTE, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOUSBInterfaceStruct190.GetEndpointProperties.class, "apply", constants$39.const$4); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$4.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$4.java deleted file mode 100644 index 2118e4f6..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$4.java +++ /dev/null @@ -1,79 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$4 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$4() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, - JAVA_INT, - RuntimeHelper.POINTER - ); - static final MethodHandle const$1 = RuntimeHelper.downcallHandle( - "IORegistryEntryGetRegistryEntryID", - constants$4.const$0 - ); - static final FunctionDescriptor const$2 = FunctionDescriptor.of(RuntimeHelper.POINTER, - JAVA_INT, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - JAVA_INT - ); - static final MethodHandle const$3 = RuntimeHelper.downcallHandle( - "IORegistryEntryCreateCFProperty", - constants$4.const$2 - ); - static final MethodHandle const$4 = RuntimeHelper.downcallHandle( - "IOServiceMatching", - constants$3.const$0 - ); - static final StructLayout const$5 = MemoryLayout.structLayout( - RuntimeHelper.POINTER.withName("_reserved"), - RuntimeHelper.POINTER.withName("QueryInterface"), - RuntimeHelper.POINTER.withName("AddRef"), - RuntimeHelper.POINTER.withName("Release"), - RuntimeHelper.POINTER.withName("CreateDeviceAsyncEventSource"), - RuntimeHelper.POINTER.withName("GetDeviceAsyncEventSource"), - RuntimeHelper.POINTER.withName("CreateDeviceAsyncPort"), - RuntimeHelper.POINTER.withName("GetDeviceAsyncPort"), - RuntimeHelper.POINTER.withName("USBDeviceOpen"), - RuntimeHelper.POINTER.withName("USBDeviceClose"), - RuntimeHelper.POINTER.withName("GetDeviceClass"), - RuntimeHelper.POINTER.withName("GetDeviceSubClass"), - RuntimeHelper.POINTER.withName("GetDeviceProtocol"), - RuntimeHelper.POINTER.withName("GetDeviceVendor"), - RuntimeHelper.POINTER.withName("GetDeviceProduct"), - RuntimeHelper.POINTER.withName("GetDeviceReleaseNumber"), - RuntimeHelper.POINTER.withName("GetDeviceAddress"), - RuntimeHelper.POINTER.withName("GetDeviceBusPowerAvailable"), - RuntimeHelper.POINTER.withName("GetDeviceSpeed"), - RuntimeHelper.POINTER.withName("GetNumberOfConfigurations"), - RuntimeHelper.POINTER.withName("GetLocationID"), - RuntimeHelper.POINTER.withName("GetConfigurationDescriptorPtr"), - RuntimeHelper.POINTER.withName("GetConfiguration"), - RuntimeHelper.POINTER.withName("SetConfiguration"), - RuntimeHelper.POINTER.withName("GetBusFrameNumber"), - RuntimeHelper.POINTER.withName("ResetDevice"), - RuntimeHelper.POINTER.withName("DeviceRequest"), - RuntimeHelper.POINTER.withName("DeviceRequestAsync"), - RuntimeHelper.POINTER.withName("CreateInterfaceIterator"), - RuntimeHelper.POINTER.withName("USBDeviceOpenSeize"), - RuntimeHelper.POINTER.withName("DeviceRequestTO"), - RuntimeHelper.POINTER.withName("DeviceRequestAsyncTO"), - RuntimeHelper.POINTER.withName("USBDeviceSuspend"), - RuntimeHelper.POINTER.withName("USBDeviceAbortPipeZero"), - RuntimeHelper.POINTER.withName("USBGetManufacturerStringIndex"), - RuntimeHelper.POINTER.withName("USBGetProductStringIndex"), - RuntimeHelper.POINTER.withName("USBGetSerialNumberStringIndex"), - RuntimeHelper.POINTER.withName("USBDeviceReEnumerate") - ).withName("IOUSBDeviceStruct187"); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$40.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$40.java deleted file mode 100644 index e5407f3a..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$40.java +++ /dev/null @@ -1,36 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -final class constants$40 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$40() {} - static final MethodHandle const$0 = RuntimeHelper.downcallHandle( - constants$39.const$4 - ); - static final VarHandle const$1 = constants$20.const$2.varHandle(MemoryLayout.PathElement.groupElement("GetEndpointProperties")); - static final StructLayout const$2 = MemoryLayout.structLayout( - RuntimeHelper.POINTER.withName("_reserved"), - RuntimeHelper.POINTER.withName("QueryInterface"), - RuntimeHelper.POINTER.withName("AddRef"), - RuntimeHelper.POINTER.withName("Release"), - JAVA_SHORT.withName("version"), - JAVA_SHORT.withName("revision"), - MemoryLayout.paddingLayout(4), - RuntimeHelper.POINTER.withName("Probe"), - RuntimeHelper.POINTER.withName("Start"), - RuntimeHelper.POINTER.withName("Stop") - ).withName("IOCFPlugInInterfaceStruct"); - static final VarHandle const$3 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("_reserved")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOCFPlugInInterfaceStruct.QueryInterface.class, "apply", constants$5.const$1); - static final VarHandle const$5 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("QueryInterface")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$41.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$41.java deleted file mode 100644 index 8b77227c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$41.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$41 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$41() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOCFPlugInInterfaceStruct.AddRef.class, "apply", constants$5.const$5); - static final VarHandle const$1 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("AddRef")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOCFPlugInInterfaceStruct.Release.class, "apply", constants$5.const$5); - static final VarHandle const$3 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("Release")); - static final VarHandle const$4 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("version")); - static final VarHandle const$5 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("revision")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$42.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$42.java deleted file mode 100644 index 4ed42f8d..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$42.java +++ /dev/null @@ -1,34 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$42 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$42() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - JAVA_INT, - RuntimeHelper.POINTER - ); - static final MethodHandle const$1 = RuntimeHelper.upcallHandle(IOCFPlugInInterfaceStruct.Probe.class, "apply", constants$42.const$0); - static final MethodHandle const$2 = RuntimeHelper.downcallHandle( - constants$42.const$0 - ); - static final VarHandle const$3 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("Probe")); - static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - JAVA_INT - ); - static final MethodHandle const$5 = RuntimeHelper.upcallHandle(IOCFPlugInInterfaceStruct.Start.class, "apply", constants$42.const$4); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$43.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$43.java deleted file mode 100644 index 8ad9ceff..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$43.java +++ /dev/null @@ -1,34 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$43 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$43() {} - static final MethodHandle const$0 = RuntimeHelper.downcallHandle( - constants$42.const$4 - ); - static final VarHandle const$1 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("Start")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOCFPlugInInterfaceStruct.Stop.class, "apply", constants$5.const$5); - static final VarHandle const$3 = constants$40.const$2.varHandle(MemoryLayout.PathElement.groupElement("Stop")); - static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, - JAVA_INT, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); - static final MethodHandle const$5 = RuntimeHelper.downcallHandle( - "IOCreatePlugInInterfaceForService", - constants$43.const$4 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$44.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$44.java deleted file mode 100644 index 34e99d5a..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$44.java +++ /dev/null @@ -1,15 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemorySegment; -final class constants$44 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$44() {} - static final MemorySegment const$0 = RuntimeHelper.CONSTANT_ALLOCATOR.allocateFrom("IOServiceFirstMatch"); - static final MemorySegment const$1 = RuntimeHelper.CONSTANT_ALLOCATOR.allocateFrom("IOServiceTerminate"); - static final MemorySegment const$2 = RuntimeHelper.CONSTANT_ALLOCATOR.allocateFrom("IOUSBDevice"); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$5.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$5.java deleted file mode 100644 index b604c1c6..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$5.java +++ /dev/null @@ -1,49 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$5 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$5() {} - static final VarHandle const$0 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("_reserved")); - static final FunctionDescriptor const$1 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - MemoryLayout.structLayout( - JAVA_BYTE.withName("byte0"), - JAVA_BYTE.withName("byte1"), - JAVA_BYTE.withName("byte2"), - JAVA_BYTE.withName("byte3"), - JAVA_BYTE.withName("byte4"), - JAVA_BYTE.withName("byte5"), - JAVA_BYTE.withName("byte6"), - JAVA_BYTE.withName("byte7"), - JAVA_BYTE.withName("byte8"), - JAVA_BYTE.withName("byte9"), - JAVA_BYTE.withName("byte10"), - JAVA_BYTE.withName("byte11"), - JAVA_BYTE.withName("byte12"), - JAVA_BYTE.withName("byte13"), - JAVA_BYTE.withName("byte14"), - JAVA_BYTE.withName("byte15") - ).withName(""), - RuntimeHelper.POINTER - ); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.QueryInterface.class, "apply", constants$5.const$1); - static final MethodHandle const$3 = RuntimeHelper.downcallHandle( - constants$5.const$1 - ); - static final VarHandle const$4 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("QueryInterface")); - static final FunctionDescriptor const$5 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$6.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$6.java deleted file mode 100644 index eef323d4..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$6.java +++ /dev/null @@ -1,28 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$6 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$6() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.AddRef.class, "apply", constants$5.const$5); - static final MethodHandle const$1 = RuntimeHelper.downcallHandle( - constants$5.const$5 - ); - static final VarHandle const$2 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("AddRef")); - static final MethodHandle const$3 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.Release.class, "apply", constants$5.const$5); - static final VarHandle const$4 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("Release")); - static final FunctionDescriptor const$5 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - RuntimeHelper.POINTER - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$7.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$7.java deleted file mode 100644 index 5ac5bfcb..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$7.java +++ /dev/null @@ -1,24 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$7 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$7() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.CreateDeviceAsyncEventSource.class, "apply", constants$6.const$5); - static final MethodHandle const$1 = RuntimeHelper.downcallHandle( - constants$6.const$5 - ); - static final VarHandle const$2 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("CreateDeviceAsyncEventSource")); - static final MethodHandle const$3 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceAsyncEventSource.class, "apply", constants$3.const$0); - static final MethodHandle const$4 = RuntimeHelper.downcallHandle( - constants$3.const$0 - ); - static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncEventSource")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$8.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$8.java deleted file mode 100644 index 9793b458..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$8.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$8 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$8() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.CreateDeviceAsyncPort.class, "apply", constants$6.const$5); - static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("CreateDeviceAsyncPort")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceAsyncPort.class, "apply", constants$5.const$5); - static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceAsyncPort")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBDeviceOpen.class, "apply", constants$5.const$5); - static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceOpen")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$9.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$9.java deleted file mode 100644 index fccbf566..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/constants$9.java +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -final class constants$9 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$9() {} - static final MethodHandle const$0 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.USBDeviceClose.class, "apply", constants$5.const$5); - static final VarHandle const$1 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("USBDeviceClose")); - static final MethodHandle const$2 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceClass.class, "apply", constants$6.const$5); - static final VarHandle const$3 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceClass")); - static final MethodHandle const$4 = RuntimeHelper.upcallHandle(IOUSBDeviceStruct187.GetDeviceSubClass.class, "apply", constants$6.const$5); - static final VarHandle const$5 = constants$4.const$5.varHandle(MemoryLayout.PathElement.groupElement("GetDeviceSubClass")); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java deleted file mode 100644 index 98adf29e..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/RuntimeHelper.java +++ /dev/null @@ -1,239 +0,0 @@ -package net.codecrete.usb.macos.gen.mach; -// Generated by jextract - -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_LONG; - -final class RuntimeHelper { - - private static final Linker LINKER = Linker.nativeLinker(); - private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(1, JAVA_BYTE)); - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> Arena.ofAuto().allocate(size, align); - - static { - - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); - } - - // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.find(name) - .map(s -> s.reinterpret(layout.byteSize())) - .orElse(null); - } - - static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.find(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MH_LOOKUP.findVirtual(fi, name, fdesc.toMethodType()); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment upcallStub(MethodHandle fiHandle, Z z, FunctionDescriptor fdesc, Arena scope) { - try { - fiHandle = fiHandle.bindTo(z); - return LINKER.upcallStub(fiHandle, fdesc, scope); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); - } - - // Internals only below this point - - private static final class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return valueLayout.carrier(); - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; - if (needsAllocator) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (c == MemorySegment.class) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (c == MemorySegment.class) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java deleted file mode 100644 index 433609ea..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/constants$0.java +++ /dev/null @@ -1,22 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.mach; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final FunctionDescriptor const$0 = FunctionDescriptor.of(RuntimeHelper.POINTER, - JAVA_INT - ); - static final MethodHandle const$1 = RuntimeHelper.downcallHandle( - "mach_error_string", - constants$0.const$0 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java index 589791f2..b229596a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java @@ -2,48 +2,116 @@ package net.codecrete.usb.macos.gen.mach; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.MemorySegment; +import java.lang.foreign.*; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; -import static java.lang.foreign.ValueLayout.JAVA_FLOAT; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; -import static java.lang.foreign.ValueLayout.OfByte; -import static java.lang.foreign.ValueLayout.OfDouble; -import static java.lang.foreign.ValueLayout.OfFloat; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfLong; -import static java.lang.foreign.ValueLayout.OfShort; -public class mach { - - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfLong C_LONG = JAVA_LONG; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; - public static MethodHandle mach_error_string$MH() { - return RuntimeHelper.requireNonNull(constants$0.const$1,"mach_error_string"); + +public class mach { + + mach() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.find(symbol) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() + .or(Linker.nativeLinker().defaultLookup()); + + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + public static final AddressLayout C_POINTER = ValueLayout.ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); + public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; + + private static class mach_error_string { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + mach.C_POINTER, + mach.C_INT + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + mach.findOrThrow("mach_error_string"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * char *mach_error_string(mach_error_t error_value) + * } + */ + public static FunctionDescriptor mach_error_string$descriptor() { + return mach_error_string.DESC; + } + /** - * {@snippet : - * char* mach_error_string(mach_error_t error_value); + * Downcall method handle for: + * {@snippet lang=c : + * char *mach_error_string(mach_error_t error_value) + * } + */ + public static MethodHandle mach_error_string$handle() { + return mach_error_string.HANDLE; + } + /** + * {@snippet lang=c : + * char *mach_error_string(mach_error_t error_value) * } */ public static MemorySegment mach_error_string(int error_value) { - var mh$ = mach_error_string$MH(); + var mh$ = mach_error_string.HANDLE; try { - return (java.lang.foreign.MemorySegment)mh$.invokeExact(error_value); + if (TRACE_DOWNCALLS) { + traceDowncall("mach_error_string", error_value); + } + return (MemorySegment)mh$.invokeExact(error_value); } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); + throw new AssertionError("should not reach here", ex$); } } } - From c4a19ee1ed5e226d52f3eab907b3e1ac0d74ff3f Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 20 Feb 2024 21:01:27 +0100 Subject: [PATCH 331/433] macOS: upgrade ot JDK 22 --- java-does-usb/jextract/README.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index 25d6fc0e..729896af 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -17,8 +17,6 @@ The resulting code is then committed to the source code repository. Before the c - JDK 20 introduced a new feature for saving the thread-specific error values (`GetLastError()` on Windows, `errno` on Linux). To use it, an additional parameter must be added to function calls. Unfortunately, this is not yet supported by jextract. So a good number of function bindings have to be written manually. -- Dependencies: to be updated... - - *jextract* is not really transparent about what it does. It often skips elements without providing any information. In particular, it will silently skip a requested element in these cases: - `--include-var myvar` if `myvar` is declared as `static`. @@ -60,8 +58,21 @@ static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup("libudev.so Most of the required native functions on macOS are part of a framework. Frameworks internally have a more complex file organization of header and binary files than appears from the outside. Thus, they require a special logic to locate framework header files. *clang* supports it with the `-F`. *jextract* allows to specify the options via `compiler_flags.txt` file. Since the file must be in the local directory and since it does not apply to Linux and Windows, separate directories must be used for the operating systems. -The generated code has the same problem as the Linux code for *udev*. It must be manually changed to use `SymbolLookup.libraryLookup()` for the frameworks `CoreFoundation` and `IOKit` respectively, and use an absolute path starting with `/System/Library/Frameworks/`. +The generated code however is unable to locate the framework at run-time. There does not seem to be a way to instruct *jextract* to generate the required code. So it must be manually changed, from: + +``` +static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("CoreFoundation.framework"), LIBRARY_ARENA) +``` + +to: + +``` +static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", LIBRARY_ARENA) +``` + +This is in the class `CoreFoundation`. The analogous change must be made in the class `IOKit`. +These aren't actual paths. But they are the correct and future-proof path to locate the framework at run-time (see man pages of `ld` on macOS). ## Windows From a1ad5b01a78cdeb982aab8704acf218c94678b22 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 20 Feb 2024 21:23:14 +0100 Subject: [PATCH 332/433] macOS: remove unnecessary typedef includes --- java-does-usb/jextract/README.md | 2 + java-does-usb/jextract/macos/gen_macos.sh | 3 - .../macos/gen/iokit/IOCFPlugInInterface.java | 26 -------- .../gen/iokit/IOUSBDeviceInterface187.java | 55 ---------------- .../gen/iokit/IOUSBInterfaceInterface190.java | 66 ------------------- 5 files changed, 2 insertions(+), 150 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterface.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface187.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface190.java diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index 729896af..85ad11e0 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -26,6 +26,8 @@ The resulting code is then committed to the source code repository. Before the c - `--include-typedef mystruct` if `mystruct` is actually a `struct`. - `--include-typedef mytypedef` if `mytypedef` is a `typedef` for a primitive type. +- *jextract* resolves all _typedef_s to their actual types. So this library does not use any _--include-typedef_ option. And there does not seem any obvious use for it. + ## Linux diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index a8eb2ac1..1c5db86b 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -42,7 +42,6 @@ $JEXTRACT --output ../../src/main/java \ --include-constant kIOReturnExclusiveAccess \ --include-var kCFRunLoopDefaultMode \ --include-struct IOCFPlugInInterfaceStruct \ - --include-typedef IOCFPlugInInterface \ --include-function IOObjectRelease \ --include-function IOIteratorNext \ --include-function IOCreatePlugInInterfaceForService \ @@ -53,12 +52,10 @@ $JEXTRACT --output ../../src/main/java \ --include-function IOServiceAddMatchingNotification \ --include-function IOServiceMatching \ --include-struct IOUSBDeviceStruct187 \ - --include-typedef IOUSBDeviceInterface187 \ --include-constant kIOUSBFindInterfaceDontCare \ --include-struct IOUSBFindInterfaceRequest \ --include-struct IOUSBDevRequest \ --include-struct IOUSBInterfaceStruct190 \ - --include-typedef IOUSBInterfaceInterface190 \ --include-constant kIOUSBTransactionTimeout \ --include-constant kIOReturnAborted \ --include-constant kIOUSBPipeStalled \ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterface.java deleted file mode 100644 index 5fe6f2d9..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterface.java +++ /dev/null @@ -1,26 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -/** - * {@snippet lang=c : - * typedef struct IOCFPlugInInterfaceStruct { - * void *_reserved; - * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *); - * ULONG (*AddRef)(void *); - * ULONG (*Release)(void *); - * UInt16 version; - * UInt16 revision; - * IOReturn (*Probe)(void *, CFDictionaryRef, io_service_t, SInt32 *); - * IOReturn (*Start)(void *, CFDictionaryRef, io_service_t); - * IOReturn (*Stop)(void *); - * } IOCFPlugInInterface - * } - */ -public class IOCFPlugInInterface extends IOCFPlugInInterfaceStruct { - - IOCFPlugInInterface() { - // Should not be called directly - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface187.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface187.java deleted file mode 100644 index 739a592d..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceInterface187.java +++ /dev/null @@ -1,55 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -/** - * {@snippet lang=c : - * typedef struct IOUSBDeviceStruct187 { - * void *_reserved; - * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *); - * ULONG (*AddRef)(void *); - * ULONG (*Release)(void *); - * IOReturn (*CreateDeviceAsyncEventSource)(void *, CFRunLoopSourceRef *); - * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void *); - * IOReturn (*CreateDeviceAsyncPort)(void *, mach_port_t *); - * mach_port_t (*GetDeviceAsyncPort)(void *); - * IOReturn (*USBDeviceOpen)(void *); - * IOReturn (*USBDeviceClose)(void *); - * IOReturn (*GetDeviceClass)(void *, UInt8 *); - * IOReturn (*GetDeviceSubClass)(void *, UInt8 *); - * IOReturn (*GetDeviceProtocol)(void *, UInt8 *); - * IOReturn (*GetDeviceVendor)(void *, UInt16 *); - * IOReturn (*GetDeviceProduct)(void *, UInt16 *); - * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *); - * IOReturn (*GetDeviceAddress)(void *, USBDeviceAddress *); - * IOReturn (*GetDeviceBusPowerAvailable)(void *, UInt32 *); - * IOReturn (*GetDeviceSpeed)(void *, UInt8 *); - * IOReturn (*GetNumberOfConfigurations)(void *, UInt8 *); - * IOReturn (*GetLocationID)(void *, UInt32 *); - * IOReturn (*GetConfigurationDescriptorPtr)(void *, UInt8, IOUSBConfigurationDescriptorPtr *); - * IOReturn (*GetConfiguration)(void *, UInt8 *); - * IOReturn (*SetConfiguration)(void *, UInt8); - * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *); - * IOReturn (*ResetDevice)(void *); - * IOReturn (*DeviceRequest)(void *, IOUSBDevRequest *); - * IOReturn (*DeviceRequestAsync)(void *, IOUSBDevRequest *, IOAsyncCallback1, void *); - * IOReturn (*CreateInterfaceIterator)(void *, IOUSBFindInterfaceRequest *, io_iterator_t *); - * IOReturn (*USBDeviceOpenSeize)(void *); - * IOReturn (*DeviceRequestTO)(void *, IOUSBDevRequestTO *); - * IOReturn (*DeviceRequestAsyncTO)(void *, IOUSBDevRequestTO *, IOAsyncCallback1, void *); - * IOReturn (*USBDeviceSuspend)(void *, Boolean); - * IOReturn (*USBDeviceAbortPipeZero)(void *); - * IOReturn (*USBGetManufacturerStringIndex)(void *, UInt8 *); - * IOReturn (*USBGetProductStringIndex)(void *, UInt8 *); - * IOReturn (*USBGetSerialNumberStringIndex)(void *, UInt8 *); - * IOReturn (*USBDeviceReEnumerate)(void *, UInt32); - * } IOUSBDeviceInterface187 - * } - */ -public class IOUSBDeviceInterface187 extends IOUSBDeviceStruct187 { - - IOUSBDeviceInterface187() { - // Should not be called directly - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface190.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface190.java deleted file mode 100644 index 15e4f195..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceInterface190.java +++ /dev/null @@ -1,66 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.macos.gen.iokit; - -/** - * {@snippet lang=c : - * typedef struct IOUSBInterfaceStruct190 { - * void *_reserved; - * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *); - * ULONG (*AddRef)(void *); - * ULONG (*Release)(void *); - * IOReturn (*CreateInterfaceAsyncEventSource)(void *, CFRunLoopSourceRef *); - * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void *); - * IOReturn (*CreateInterfaceAsyncPort)(void *, mach_port_t *); - * mach_port_t (*GetInterfaceAsyncPort)(void *); - * IOReturn (*USBInterfaceOpen)(void *); - * IOReturn (*USBInterfaceClose)(void *); - * IOReturn (*GetInterfaceClass)(void *, UInt8 *); - * IOReturn (*GetInterfaceSubClass)(void *, UInt8 *); - * IOReturn (*GetInterfaceProtocol)(void *, UInt8 *); - * IOReturn (*GetDeviceVendor)(void *, UInt16 *); - * IOReturn (*GetDeviceProduct)(void *, UInt16 *); - * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *); - * IOReturn (*GetConfigurationValue)(void *, UInt8 *); - * IOReturn (*GetInterfaceNumber)(void *, UInt8 *); - * IOReturn (*GetAlternateSetting)(void *, UInt8 *); - * IOReturn (*GetNumEndpoints)(void *, UInt8 *); - * IOReturn (*GetLocationID)(void *, UInt32 *); - * IOReturn (*GetDevice)(void *, io_service_t *); - * IOReturn (*SetAlternateInterface)(void *, UInt8); - * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *); - * IOReturn (*ControlRequest)(void *, UInt8, IOUSBDevRequest *); - * IOReturn (*ControlRequestAsync)(void *, UInt8, IOUSBDevRequest *, IOAsyncCallback1, void *); - * IOReturn (*GetPipeProperties)(void *, UInt8, UInt8 *, UInt8 *, UInt8 *, UInt16 *, UInt8 *); - * IOReturn (*GetPipeStatus)(void *, UInt8); - * IOReturn (*AbortPipe)(void *, UInt8); - * IOReturn (*ResetPipe)(void *, UInt8); - * IOReturn (*ClearPipeStall)(void *, UInt8); - * IOReturn (*ReadPipe)(void *, UInt8, void *, UInt32 *); - * IOReturn (*WritePipe)(void *, UInt8, void *, UInt32); - * IOReturn (*ReadPipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *); - * IOReturn (*WritePipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *); - * IOReturn (*ReadIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *); - * IOReturn (*WriteIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *); - * IOReturn (*ControlRequestTO)(void *, UInt8, IOUSBDevRequestTO *); - * IOReturn (*ControlRequestAsyncTO)(void *, UInt8, IOUSBDevRequestTO *, IOAsyncCallback1, void *); - * IOReturn (*ReadPipeTO)(void *, UInt8, void *, UInt32 *, UInt32, UInt32); - * IOReturn (*WritePipeTO)(void *, UInt8, void *, UInt32, UInt32, UInt32); - * IOReturn (*ReadPipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *); - * IOReturn (*WritePipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *); - * IOReturn (*USBInterfaceGetStringIndex)(void *, UInt8 *); - * IOReturn (*USBInterfaceOpenSeize)(void *); - * IOReturn (*ClearPipeStallBothEnds)(void *, UInt8); - * IOReturn (*SetPipePolicy)(void *, UInt8, UInt16, UInt8); - * IOReturn (*GetBandwidthAvailable)(void *, UInt32 *); - * IOReturn (*GetEndpointProperties)(void *, UInt8, UInt8, UInt8, UInt8 *, UInt16 *, UInt8 *); - * } IOUSBInterfaceInterface190 - * } - */ -public class IOUSBInterfaceInterface190 extends IOUSBInterfaceStruct190 { - - IOUSBInterfaceInterface190() { - // Should not be called directly - } -} - From 7c8eeeea28eff09bdf0281d1ff8a8b3a499cb0ff Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 20 Feb 2024 23:20:03 +0100 Subject: [PATCH 333/433] macOS: use new jextract options to specify system library --- java-does-usb/jextract/README.md | 14 -------------- java-does-usb/jextract/macos/gen_macos.sh | 4 ++-- .../macos/gen/corefoundation/CoreFoundation.java | 2 -- .../net/codecrete/usb/macos/gen/iokit/IOKit.java | 3 --- 4 files changed, 2 insertions(+), 21 deletions(-) diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index 85ad11e0..170a55ed 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -60,21 +60,7 @@ static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup("libudev.so Most of the required native functions on macOS are part of a framework. Frameworks internally have a more complex file organization of header and binary files than appears from the outside. Thus, they require a special logic to locate framework header files. *clang* supports it with the `-F`. *jextract* allows to specify the options via `compiler_flags.txt` file. Since the file must be in the local directory and since it does not apply to Linux and Windows, separate directories must be used for the operating systems. -The generated code however is unable to locate the framework at run-time. There does not seem to be a way to instruct *jextract* to generate the required code. So it must be manually changed, from: -``` -static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("CoreFoundation.framework"), LIBRARY_ARENA) -``` - -to: - -``` -static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", LIBRARY_ARENA) -``` - -This is in the class `CoreFoundation`. The analogous change must be made in the class `IOKit`. - -These aren't actual paths. But they are the correct and future-proof path to locate the framework at run-time (see man pages of `ld` on macOS). ## Windows diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index 1c5db86b..9e93e0ea 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -7,7 +7,7 @@ SDK_DIR=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Dev # CoreFoundation $JEXTRACT --output ../../src/main/java \ -I $SDK_DIR/usr/include \ - -lCoreFoundation.framework \ + -l :/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation \ --header-class-name CoreFoundation \ --target-package net.codecrete.usb.macos.gen.corefoundation \ --include-struct CFRange \ @@ -32,7 +32,7 @@ $JEXTRACT --output ../../src/main/java \ # IOKit $JEXTRACT --output ../../src/main/java \ -I $SDK_DIR/usr/include \ - -lIOKit.framework \ + -l :/System/Library/Frameworks/IOKit.framework/IOKit \ --header-class-name IOKit \ --target-package net.codecrete.usb.macos.gen.iokit \ --include-var kIOMasterPortDefault \ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java index 791879cf..78d44fcb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java @@ -53,8 +53,6 @@ static MemoryLayout align(MemoryLayout layout, long align) { }; } - // Manually fix. Otherwise, system library will not be found - // static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("CoreFoundation.framework"), LIBRARY_ARENA) static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", LIBRARY_ARENA) .or(SymbolLookup.loaderLookup()) .or(Linker.nativeLinker().defaultLookup()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java index 9c010236..727ae616 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java @@ -54,9 +54,6 @@ static MemoryLayout align(MemoryLayout layout, long align) { }; } - - // Manually fix. Otherwise, system library will not be found - // static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("IOKit.framework"), LIBRARY_ARENA) static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup("/System/Library/Frameworks/IOKit.framework/IOKit", LIBRARY_ARENA) .or(SymbolLookup.loaderLookup()) .or(Linker.nativeLinker().defaultLookup()); From 0326bb9af17cc2c6673ff70ca6dec5d6e0e437c7 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Tue, 20 Feb 2024 23:26:19 +0100 Subject: [PATCH 334/433] Linux: use new jextract option for libudev --- java-does-usb/jextract/README.md | 11 ----------- java-does-usb/jextract/linux/gen_linux.sh | 2 +- .../java/net/codecrete/usb/linux/gen/udev/udev.java | 2 -- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index 170a55ed..718d20ad 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -43,17 +43,6 @@ On Linux, the limitations are: - `sd-device.h` (header file for *libsystemd*): *jextract* fails with *"Error: /usr/include/inttypes.h:290:8: error: unknown type name 'intmax_t'"*. The reason is yet unknown. This code is currently not needed as *libudev* is used instead of *libsystemd*. They are related, *libsystemd* is the future solution, but it is missing support for monitoring devices. -- `libudev.h`: After code generation, the class `udev` in `.../linux/gen/udev` must be manually modified. In most Linux installations, there is no `libudev.so` alias to an actual version like `libudev.so.1.7.2`. The only alias is `libudev.so.1`. This is probably a deliberate decision by the authors as they do not plan to provide backward compatibility across major versions. But there does not seem to be a way to make *jextract* generate valid code for this setup. So manually replace: - -``` -static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("udev"), LIBRARY_ARENA) -``` - -with: - -``` -static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup("libudev.so.1", LIBRARY_ARENA) -``` ## MacOS diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index 2e8b3af8..0010d483 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -61,7 +61,7 @@ $JEXTRACT --output ../../src/main/java \ $JEXTRACT --output ../../src/main/java \ --header-class-name udev \ --target-package net.codecrete.usb.linux.gen.udev \ - -l udev \ + -l :libudev.so.1 \ --include-function udev_new \ --include-function udev_enumerate_new \ --include-function udev_enumerate_add_match_subsystem \ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java index 295ca7be..b958af64 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java @@ -64,8 +64,6 @@ static MemoryLayout align(MemoryLayout layout, long align) { }; } - // Manually fix. Otherwise, libudev will not be found if "libudev-dev" is not installed - // static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("udev"), LIBRARY_ARENA) static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup("libudev.so.1", LIBRARY_ARENA) .or(SymbolLookup.loaderLookup()) .or(Linker.nativeLinker().defaultLookup()); From cf268dcc269ceb6eedec3143dba16f2eba9bb6e4 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 23 Feb 2024 19:32:15 +0100 Subject: [PATCH 335/433] Update code size statistics --- java-does-usb/jextract/README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index 718d20ad..68ab7a64 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -74,18 +74,19 @@ The known limitations are: *jextract* generates a comprehensive set of methods for each function, struct, struct member etc. Most of it will not be used as a typical application just uses a subset of struct members, might only read or write them etc. So a considerable amount of code is generated. For some types, it's a bit excessive. -The worst example is [`IOUSBInterfaceStruct190`](https://github.com/manuelbl/JavaDoesUSB/blob/main/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java) (macOS). This is a `struct` consisting of about 50 member functions. It's basically a vtable of a C++ class. For this single `struct`, *jextract* generates codes resulting in 70 class files with a total size of 227kByte. +The worst example is [`IOUSBInterfaceStruct190`](https://github.com/manuelbl/JavaDoesUSB/blob/main/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java) (macOS). This is a `struct` consisting of about 50 member functions. It's basically a vtable of a C++ class. For this single `struct`, *jextract* generates codes resulting in 100 class files with a total size of 213kByte. -The table below shows statistics for version 0.6.0 of the library: +The table below shows class file size statistics for version 1.0.0 of the library: -| Operating Systems | Manually Created | % | Generated | % | Total | % | -|-------------------|-----------------:|-------:|----------:|-------:|----------:|--------:| -| Linux | 48,516 | 3.64% | 197,169 | 14.79% | 245,685 | 18.42% | -| macOS | 78,718 | 5.90% | 546,907 | 41.01% | 625,625 | 46.91% | -| Windows | 104,811 | 7.86% | 256,079 | 19.20% | 360,890 | 27.06% | -| Common | 101,364 | 7.60% | | | 101,364 | 7.60% | -| Grand Total | 333,409 | 25.00% | 1,000,155 | 75.00% | 1,333,564 | 100.00% | +| Operating Systems | Manually Created | % | Generated | % | Total | % | +|-------------------|-----------------:|------:|----------:|------:|----------:|--------:| +| Linux | 54,022 | 4.3% | 162,099 | 12.8% | 216,121 | 17.1% | +| macOS | 77,149 | 6.1% | 529,347 | 41.8% | 606,496 | 47.9% | +| Windows | 106,358 | 8.4% | 232,395 | 18.3% | 338,753 | 26.7% | +| Common | 105,423 | 8.3% | | | 105,423 | 8.3% | +| Grand Total | 342,952 | 27.1% | 923,841 | 72.9% | 1,266,793 | 100.00% | -*Code Size (compiled), in bytes and percentage of total size* + +*Class File Size (compiled), in bytes and percentage of total size* If *jextract* could generate code for error state capturing, there would be even more generated and less manually written code. From b88b267bd02820204aee2dcf7668ddb2d03a6a97 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 25 Feb 2024 10:48:19 +0100 Subject: [PATCH 336/433] Improve README --- README.md | 82 +++++++++++-------- .../src/main/java/net/codecrete/usb/Usb.java | 23 ++++++ reference/README.md | 2 +- 3 files changed, 74 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index fb85e906..69aa89e4 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,10 @@ [![javadoc](https://javadoc.io/badge2/net.codecrete.usb/java-does-usb/javadoc.svg)](https://javadoc.io/doc/net.codecrete.usb/java-does-usb) -*Java Does USB* is a Java library for working with USB devices. It allows to query information about all conntected USB devices and to communicate with USB devices using custom / vendor specific protocols. (It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc.) +*Java Does USB* is a Java library for working with USB devices. It allows to query the conntected USB devices and to communicate with them using custom / vendor specific protocols. (It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc.) -The library uses the [Foreign Function & Memory API](https://github.com/openjdk/panama-foreign) to access native APIs of the underlying operating system. It is written entirely in Java and does not need JNI or any native third-party library. The *Foreign Function & Memory API* (aka as project Panama) has been introduced with Java 22. Older versions of this library can be used with preview versions of the API that were available in Java 19, Java 20 or Java 21 (with preview features enabled). +The library uses the [Foreign Function and Memory API](https://docs.oracle.com/en/java/javase/21/core/foreign-function-and-memory-api.html#GUID-FBE990DA-C356-46E8-9109-C75567849BA8) to access native APIs of the underlying operating system. It is written entirely in Java and does not use JNI or any native third-party library. The *Foreign Function and Memory API* has been introduced with Java 22. Preview versions were available in several earlier releases. -| Version | Main New Features | Compatibility | -| - | - | - | -| 1.0.x | Release for final Java API | JDK 22 | -| 0.7.x | New setter/getter names for improved Kotlin support; Kotlin examples | JDK 21 | -| 0.6.x | Support for JDK 21; better handling of composite devices on Windows | JDK 21 | -| 0.5.x | Support for JDK 20; high-throuput I/O streams | JDK 20 | -| 0.4.x | Early release | JDK 19 | - -*Note: The main branch and published versions ≥ 1.0 work with JDK 22 and later only. For JDK 21, user version 0.7.*. For JDK 20, use version 0.5.*. For JDK 19, use version 0.4.x. ## Features @@ -26,17 +17,8 @@ The library uses the [Foreign Function & Memory API](https://github.com/openjdk/ - Descriptive information about interfaces, settings and endpoints - High-throughput input/output streams - Support for alternate interface settings, composite devices and interface association -- Published on Maven Central - -### Planned - -- Isochronous transfer - -### Not planned +- Published on Maven Central and licensed under the permissive MIT license -- Changing configuration: The library selects the first configuration. Changing configurations is rarely used and not supported on Windows (limitation of WinUSB). -- USB 3.0 streams: Not supported on Windows (limitation of WinUSB). -- Providing information about USB buses, controllers and hubs ## Getting Started @@ -75,11 +57,14 @@ public class EnumerateDevices { ``` + ## Documentation - [Javadoc](https://javadoc.io/doc/net.codecrete.usb/java-does-usb) + + ## Examples - [Bulk Transfer](examples/bulk_transfer/) demonstrates how to find a USB device, open it and communicate using bulk transfer. @@ -89,12 +74,12 @@ public class EnumerateDevices { - [ePaper Display](examples/epaper_display) communicates with an IT8951 controller for e-Paper displays and shows an image on the display. + ## Prerequisite -- Java 22 (available at https://www.azul.com/downloads/?package=jdk) +- Java 22 available at [jdk.java.net](https://jdk.java.net/21/), [Azul](https://www.azul.com/downloads/?package=jdk), [Adoptium](https://adoptium.net/temurin/releases/) or with your favorite package manager. - Windows (x86 64-bit), macOS (x86 64-bit, ARM 64-bit) or Linux 64 bit (x86 64-bit, ARM 64-bit) -For JDK 21, use the latest published version 0.7.x. For JDK 20, use the latest published version 0.5.x. For JDK 19, use the latest published version 0.4.x. ## Platform-specific Considerations @@ -102,7 +87,7 @@ For JDK 21, use the latest published version 0.7.x. For JDK 20, use the latest p ### macOS -No special considerations apply. Using this library, a Java application can connect to any USB device and claim any interfaces that isn't claimed by an operating system driver or another application. Standard operation-system drivers can be unloaded if the application is run with root privileges. It runs both on Macs with Apple Silicion and Intel processors. +No special considerations apply. Using this library, a Java application can connect to any USB device and claim any interfaces that isn't claimed by an operating system driver or another application. Standard operation system drivers can be unloaded if the application is run with root privileges. It runs both on Macs with Apple Silicon and Intel processors. ### Linux @@ -111,7 +96,7 @@ No special considerations apply. Using this library, a Java application can conn Similar to macOS, a Java application can connect to any USB device and claim any interfaces that isn't claimed by an operating system driver or another application. Standard operation system drivers can be unloaded (without the need for root privileges). -Most Linux distributions by default set up user accounts without permissions to access USB devices directly. The *udev* system daemon is responsible for assigning permissions to USB devices. It can be configured to assign specific permissions or ownership: +Most Linux distributions set up user accounts without permissions to access USB devices. The *udev* system daemon is responsible for assigning permissions to USB devices. It can be configured to assign specific permissions or ownership: Create a file called `/etc/udev/rules.d/80-javadoesusb-udev.rules` with the below content: @@ -121,29 +106,54 @@ SUBSYSTEM=="usb", ATTRS{idVendor}=="cafe", MODE="0666" This adds the rule to assign permission mode 0666 to all USB devices with vendor ID `0xCAFE`. This unregistered vendor ID is used by the test devices. +Without the *udev* rule, it is still possible to enumerate and query all USB devices. + ### Windows -The Windows driver model is more rigid than the ones of macOS or Linux. It's not possible to open any USB device that is not claimed. Instead, only devices using the *WinUSB* driver can be opened. This even applies to devices with no installed driver. +The Windows driver model is rather rigid. It's not possible to open any USB device unless it uses the *WinUSB* driver. This even applies to devices with no installed driver. Enumerating and querying USB devices is possible independent of the driver. -USB devices can implement certain control requests to instruct Windows to automatically install the WinUSB driver (search for *WCID* or *Microsoft OS Compatibility Descriptors*). The WinUSB driver can also be manually installed or replaced using a software called [Zadig](https://zadig.akeo.ie/). +USB devices can implement special control requests to instruct Windows to automatically install the WinUSB driver (search for *WCID* or *Microsoft OS Compatibility Descriptors*). The WinUSB driver can also be manually installed or replaced using a software called [Zadig](https://zadig.akeo.ie/). The test devices implement the required control requests. So the driver is installed automatically. Windows for ARM64 is not yet supported. A port is probably easy, provided you have hardware to test it. -### Troubleshooting + +## Troubleshooting ### 32-bit versions -The Foreign Function & Memory API has not been implemented for 32-bit operating systems / JDKs (and likely never will be). +The *Foreign Function And Memory API* has not been implemented for 32-bit operating systems / JDKs (and likely never will be). -## Code generation +## Running on older JDK versions -Many bindings for the native APIs have been generated with *jextract*. See the [jextract](java-does-usb/jextract) subdirectory for more information. For functions that need to retain the error state (`errno` on Linux, `GetLastError()` on Windows), the bindings have been manually written as *jextract* does not support it. +The *Foreign Function And Memory API* has been available as a preview feature in JDKs before 22. However, incompatible changes were made from preview to preview to release. Earlier versions can be used with specific versions of this library: + +| Version | Main New Features | Compatibility | +| - | - | - | +| 1.0.x | Release for final Java API | JDK 22 | +| 0.7.x | New setter/getter names for improved Kotlin support; Kotlin examples | JDK 21 | +| 0.6.x | Support for JDK 21; better handling of composite devices on Windows | JDK 21 | +| 0.5.x | Support for JDK 20; high-throuput I/O streams | JDK 20 | +| 0.4.x | Early release | JDK 19 | + +When using an older JDK, preview features must be enabled using the `--enable-preview` VM option. + + + +## Building from source + +To build from source, run the following command: + +``` +mvn clean install -DskipTests +``` + +The tests are skipped as they require that a special test device is connected to the computer. See the next section for more information. @@ -162,7 +172,7 @@ Tests can be run from the command line: mvn clean test ``` -If they are run from an IDE (such as IntelliJ IDEA), you must likely configure VM options to enable preview features and allow native access: +If they are run from an IDE (such as IntelliJ IDEA), you must likely configure VM options to allow native access: ``` --enable-native-access=net.codecrete.usb @@ -173,3 +183,11 @@ Or (if modules are ignored): ``` --enable-native-access=ALL-UNNAMED ``` + + + +## Code generation + +Many bindings for the native APIs have been generated with *jextract*. See the [jextract](java-does-usb/jextract) subdirectory for more information. For functions that need to retain the error state (`errno` on Linux, `GetLastError()` on Windows), the bindings have been manually written as *jextract* does not support it. + +Since the code can only be generated for the current operating system, it must be generated on separate computers for Linux, Windows and macOS. Thus, the generated code is included in the repository. The generated code is compilable on all operating systems. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/Usb.java b/java-does-usb/src/main/java/net/codecrete/usb/Usb.java index 3c287303..99381a85 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/Usb.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/Usb.java @@ -106,6 +106,15 @@ public static Optional findDevice(int vendorId, int productId) { /** * Sets the handler to be called when a USB device is connected. + *

+ * The handler is called from a background thread. + *

+ *

+ * The handler should not execute any time-consuming operations but rather return quickly. + * While the handler is being executed, maintaining the list of connected devices is paused, + * methods of this class (such as {@link #getDevices()}) will possibly work with an outdated list + * of connected devices and handlers for connect and disconnect events will not be called. + *

* * @param handler handler function, or {@code null} to remove a previous handler */ @@ -116,10 +125,24 @@ public static void setOnDeviceConnected(@Nullable Consumer handler) { /** * Sets the handler to be called when a USB device is disconnected. *

+ * The handler is called from a background thread. + *

+ *

* When the handler is called, the {@link UsbDevice} instance has already been closed. * Descriptive information (such as vendor and product ID, serial number, interfaces, endpoints) * can still be accessed. *

+ *

+ * If the application was communicating with the device when it was disconnected, it will also receive + * an error for those operations. Due to the concurrency of the USB stack, there is no particular order + * for the disconnect event and the transmission errors. + *

+ *

+ * The handler should not execute any time-consuming operations but rather return quickly. + * While the handler is being executed, maintaining the list of connected devices is paused, + * methods of this class (such as {@link #getDevices()}) will possibly work with an outdated list + * of connected devices and handlers for connect and disconnect events will not be called. + *

* * @param handler handler function, or {@code null} to remove a previous handler */ diff --git a/reference/README.md b/reference/README.md index 6b5c71d1..a8d4b960 100644 --- a/reference/README.md +++ b/reference/README.md @@ -6,4 +6,4 @@ The C++ code contains less error checking, less test cases and does not cover al - [MacOS](macos) (for use with Xcode) - [Windows](windows) (for use with Visual Studio) -- [LInux](linux) (for use with CMake) +- [Linux](linux) (for use with CMake) From 88f38466d15a27ce2398dc1459e70aa9608178ec Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 3 Mar 2024 12:20:54 +0100 Subject: [PATCH 337/433] macOS: jextract without import cleanup --- java-does-usb/jextract/README.md | 19 ++++++++++--------- java-does-usb/jextract/macos/gen_macos.sh | 2 +- .../usb/macos/gen/corefoundation/CFRange.java | 10 +++++++--- .../macos/gen/corefoundation/CFUUIDBytes.java | 10 +++++++--- .../gen/corefoundation/CoreFoundation.java | 12 +++++++----- .../usb/macos/gen/iokit/CFUUIDBytes.java | 10 +++++++--- .../gen/iokit/IOCFPlugInInterfaceStruct.java | 11 +++++++---- .../codecrete/usb/macos/gen/iokit/IOKit.java | 13 +++++++------ ...rviceAddMatchingNotification$callback.java | 14 +++++++++----- .../usb/macos/gen/iokit/IOUSBDevRequest.java | 8 ++++++-- .../macos/gen/iokit/IOUSBDeviceStruct187.java | 10 +++++++--- .../gen/iokit/IOUSBFindInterfaceRequest.java | 10 +++++++--- .../gen/iokit/IOUSBInterfaceStruct190.java | 10 +++++++--- .../codecrete/usb/macos/gen/mach/mach.java | 12 +++++++----- 14 files changed, 96 insertions(+), 55 deletions(-) diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index 68ab7a64..eb94c181 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -1,21 +1,21 @@ # Code Generation with *jextract* -Some of the binding code for accessing native functions and data structures is generated with [jextract](https://jdk.java.net/jextract/). The tool is still under construction and has its limitations. +A major part of the binding code for accessing native functions and data structures is generated with [jextract](https://jdk.java.net/jextract/). *jextract* is not bundled with the JDK. The binaries can be downloaded from [jdk.java.net/jextract](https://jdk.java.net/jextract/) -In order to generate the code, the scripts in the subdirectories have to be run (`linux/gen_linux.sh`, `macos/gen_macos.sh` and `/windowsgen_win.cmd`). Each script has to be run on the particular operating system. +In order to generate the code, the scripts in the subdirectories have to be run (`linux/gen_linux.sh`, `macos/gen_macos.sh` and `windows/gen_win.cmd`). Each script has to be run on the particular operating system. The scripts expect the *jextract* binary to be in a *jextract* directory at the same parent directory as the *Java Does USB* project. If that is not the case, the *jextract* path can be modified at the top of the scripts. -The code is generated in directories below `gen`, i.e. `main/java/net/codecrete/usb/linux/gen` and similar for the other operating systems. For each library (`xxx.so` or `xxx.dll`) and each macOS framework, a separate package is created. +The code is generated in directories below `gen`, i.e. `main/java/net/codecrete/usb/linux/gen` and similarly for the other operating systems. For each library (`xxx.so` or `xxx.dll`) and each macOS framework, a separate package is created. -The scripts explicitly specify the functions, structs etc. to include as generating code for entire operating system header files can result in an excessive amount of Java source files and classes. +The scripts explicitly specify the functions, structs etc. to include as generating code for entire operating system header files will result in an excessive amount of Java source files and classes. -The resulting code is then committed to the source code repository. Before the commit, imports are cleaned up to get rid of superfluous imports. Most IDEs provide a convenient command to execute this on entire directories. +The resulting code is then committed to the source code repository. ## General limitations - According to the jextract mailing list, it would be required to create separate code for Intel x64 and ARM64 architecture. And jextract would need to be run on each architecture separately (no cross-compilation). Fortunately, this doesn't seem to be the case. Linux code generated on Intel x64 also runs on ARM64 without change. The same holds for macOS. However, jextract needs to be run on each operating system separately. -- JDK 20 introduced a new feature for saving the thread-specific error values (`GetLastError()` on Windows, `errno` on Linux). To use it, an additional parameter must be added to function calls. Unfortunately, this is not yet supported by jextract. So a good number of function bindings have to be written manually. +- The *Foreign Function And Memory* API has the abilitiy to save the thread-specific error values (`GetLastError()` on Windows, `errno` on Linux). This is required as the JVM calls operation system functions as well, which overwrite the result values. To save the values, an additional parameter must be added to function calls. Unfortunately, this is not supported by jextract. So a good number of function bindings have to be written manually. - *jextract* is not really transparent about what it does. It often skips elements without providing any information. In particular, it will silently skip a requested element in these cases: @@ -26,7 +26,7 @@ The resulting code is then committed to the source code repository. Before the c - `--include-typedef mystruct` if `mystruct` is actually a `struct`. - `--include-typedef mytypedef` if `mytypedef` is a `typedef` for a primitive type. -- *jextract* resolves all _typedef_s to their actual types. So this library does not use any _--include-typedef_ option. And there does not seem any obvious use for it. +- *jextract* resolves all _typedef_s to their actual types. So this library does not use any _--include-typedef_ option. And there does not seem any obvious use for it beyond cosmetics. ## Linux @@ -70,6 +70,7 @@ The known limitations are: - *jextract* turns off *echo mode*. So the first call will behave differently than the following calls. + ## Code Size *jextract* generates a comprehensive set of methods for each function, struct, struct member etc. Most of it will not be used as a typical application just uses a subset of struct members, might only read or write them etc. So a considerable amount of code is generated. For some types, it's a bit excessive. @@ -78,13 +79,13 @@ The worst example is [`IOUSBInterfaceStruct190`](https://github.com/manuelbl/Jav The table below shows class file size statistics for version 1.0.0 of the library: -| Operating Systems | Manually Created | % | Generated | % | Total | % | +| Operating Systems | Manually Written | % | Generated | % | Total | % | |-------------------|-----------------:|------:|----------:|------:|----------:|--------:| | Linux | 54,022 | 4.3% | 162,099 | 12.8% | 216,121 | 17.1% | | macOS | 77,149 | 6.1% | 529,347 | 41.8% | 606,496 | 47.9% | | Windows | 106,358 | 8.4% | 232,395 | 18.3% | 338,753 | 26.7% | | Common | 105,423 | 8.3% | | | 105,423 | 8.3% | -| Grand Total | 342,952 | 27.1% | 923,841 | 72.9% | 1,266,793 | 100.00% | +| Grand Total | 342,952 | 27.1% | 923,841 | 72.9% | 1,266,793 | 100.0% | *Class File Size (compiled), in bytes and percentage of total size* diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index 9e93e0ea..fd5a9f70 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -1,6 +1,6 @@ #!/bin/sh -JEXTRACT=../../../../jextract/build/jextract/bin/jextract +JEXTRACT=../../../../jextract/bin/jextract # If SDK_DIR is changed, it needs to be changed in compile_flags.txt as well. SDK_DIR=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java index 2f831a30..07ec2197 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java @@ -2,11 +2,15 @@ package net.codecrete.usb.macos.gen.corefoundation; +import java.lang.invoke.*; import java.lang.foreign.*; -import java.util.function.Consumer; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfLong; +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java index aa02fd47..bcbb50a6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java @@ -2,11 +2,15 @@ package net.codecrete.usb.macos.gen.corefoundation; +import java.lang.invoke.*; import java.lang.foreign.*; -import java.util.function.Consumer; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java index 78d44fcb..26bfb887 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java @@ -2,13 +2,15 @@ package net.codecrete.usb.macos.gen.corefoundation; +import java.lang.invoke.*; import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class CoreFoundation { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/CFUUIDBytes.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/CFUUIDBytes.java index 1b7dcaa5..4885f492 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/CFUUIDBytes.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/CFUUIDBytes.java @@ -2,11 +2,15 @@ package net.codecrete.usb.macos.gen.iokit; +import java.lang.invoke.*; import java.lang.foreign.*; -import java.util.function.Consumer; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfByte; +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java index b52221ce..26862c8c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java @@ -2,12 +2,15 @@ package net.codecrete.usb.macos.gen.iokit; +import java.lang.invoke.*; import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.util.function.Consumer; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfShort; +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java index 727ae616..ff608624 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java @@ -2,14 +2,15 @@ package net.codecrete.usb.macos.gen.iokit; +import java.lang.invoke.*; import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.OfInt; +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class IOKit { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOServiceAddMatchingNotification$callback.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOServiceAddMatchingNotification$callback.java index 0987141e..c57ad0c0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOServiceAddMatchingNotification$callback.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOServiceAddMatchingNotification$callback.java @@ -2,11 +2,15 @@ package net.codecrete.usb.macos.gen.iokit; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.Linker; -import java.lang.foreign.MemorySegment; -import java.lang.invoke.MethodHandle; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java index 1e41040a..d57579d5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java @@ -2,11 +2,15 @@ package net.codecrete.usb.macos.gen.iokit; +import java.lang.invoke.*; import java.lang.foreign.*; -import java.util.function.Consumer; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java index 46b5d14c..dbbe8e33 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java @@ -2,11 +2,15 @@ package net.codecrete.usb.macos.gen.iokit; +import java.lang.invoke.*; import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.util.function.Consumer; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java index f38e6b48..9f543412 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java @@ -2,11 +2,15 @@ package net.codecrete.usb.macos.gen.iokit; +import java.lang.invoke.*; import java.lang.foreign.*; -import java.util.function.Consumer; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfShort; +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java index 41ed672b..46cc32e1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java @@ -2,11 +2,15 @@ package net.codecrete.usb.macos.gen.iokit; +import java.lang.invoke.*; import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.util.function.Consumer; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java index b229596a..6c7ce22a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java @@ -2,13 +2,15 @@ package net.codecrete.usb.macos.gen.mach; +import java.lang.invoke.*; import java.lang.foreign.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class mach { From 9d45fdfdd5a7baebae8c0ca38b98006581cea4f0 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 3 Mar 2024 12:34:45 +0100 Subject: [PATCH 338/433] Linux: latest jextract, no import cleanup --- java-does-usb/jextract/linux/gen_linux.sh | 2 +- .../codecrete/usb/linux/gen/epoll/epoll.java | 25 ++++++----------- .../usb/linux/gen/epoll/epoll_data.java | 20 +++++++------- .../usb/linux/gen/epoll/epoll_event.java | 18 ++++++------- .../codecrete/usb/linux/gen/errno/errno.java | 25 ++++++----------- .../codecrete/usb/linux/gen/fcntl/fcntl.java | 25 ++++++----------- .../usb/linux/gen/string/string.java | 27 +++++++------------ .../codecrete/usb/linux/gen/udev/udev.java | 27 +++++++------------ .../usb/linux/gen/unistd/unistd.java | 27 +++++++------------ .../usbdevice_fs/usbdevfs_bulktransfer.java | 19 +++++++------ .../usbdevice_fs/usbdevfs_ctrltransfer.java | 21 +++++++-------- .../usbdevfs_disconnect_claim.java | 21 +++++++-------- .../gen/usbdevice_fs/usbdevfs_ioctl.java | 19 +++++++------ .../usbdevfs_iso_packet_desc.java | 18 ++++++------- .../usbdevice_fs/usbdevfs_setinterface.java | 18 ++++++------- .../linux/gen/usbdevice_fs/usbdevfs_urb.java | 23 +++++++--------- .../linux/gen/usbdevice_fs/usbdevice_fs.java | 25 ++++++----------- 17 files changed, 141 insertions(+), 219 deletions(-) diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index 0010d483..c444821e 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -1,6 +1,6 @@ #!/bin/sh -JEXTRACT=../../../../jextract/build/jextract/bin/jextract +JEXTRACT=../../../../jextract/bin/jextract # errno.h $JEXTRACT --output ../../src/main/java \ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java index b3851555..99a00787 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java @@ -2,24 +2,15 @@ package net.codecrete.usb.linux.gen.epoll; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.PaddingLayout; -import java.lang.foreign.SequenceLayout; -import java.lang.foreign.StructLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class epoll { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_data.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_data.java index c4fb6f1d..9bf1e677 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_data.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_data.java @@ -2,17 +2,15 @@ package net.codecrete.usb.linux.gen.epoll; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfLong; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java index 90269384..c6348dd2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java @@ -2,15 +2,15 @@ package net.codecrete.usb.linux.gen.epoll; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfInt; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java index dfb59b81..3d970a3c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -2,24 +2,15 @@ package net.codecrete.usb.linux.gen.errno; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.PaddingLayout; -import java.lang.foreign.SequenceLayout; -import java.lang.foreign.StructLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class errno { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java index 57e36438..1fb52864 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java @@ -2,24 +2,15 @@ package net.codecrete.usb.linux.gen.fcntl; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.PaddingLayout; -import java.lang.foreign.SequenceLayout; -import java.lang.foreign.StructLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class fcntl { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java index c564f1f2..f5cfc2d7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java @@ -2,24 +2,15 @@ package net.codecrete.usb.linux.gen.string; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.PaddingLayout; -import java.lang.foreign.SequenceLayout; -import java.lang.foreign.StructLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class string { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java index b958af64..937cf781 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java @@ -2,24 +2,15 @@ package net.codecrete.usb.linux.gen.udev; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.PaddingLayout; -import java.lang.foreign.SequenceLayout; -import java.lang.foreign.StructLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class udev { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java index 94151a73..b0b3a136 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java @@ -2,24 +2,15 @@ package net.codecrete.usb.linux.gen.unistd; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.PaddingLayout; -import java.lang.foreign.SequenceLayout; -import java.lang.foreign.StructLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class unistd { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java index e97624c8..f241c02e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java @@ -2,16 +2,15 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfInt; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java index 8abc32ac..e857dd12 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java @@ -2,18 +2,15 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfByte; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfShort; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java index 3569a55a..5fbea293 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java @@ -2,18 +2,15 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SequenceLayout; -import java.lang.invoke.VarHandle; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; -import static java.lang.foreign.ValueLayout.OfInt; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java index c85f7ef2..0e8d44d6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java @@ -2,16 +2,15 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfInt; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java index 71e32fab..d4a335a0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java @@ -2,15 +2,15 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfInt; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java index d18d8f20..26b6181f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java @@ -2,15 +2,15 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfInt; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java index 5966585a..6165e167 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java @@ -2,20 +2,15 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SequenceLayout; -import java.lang.invoke.MethodHandle; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; -import static java.lang.foreign.ValueLayout.OfByte; -import static java.lang.foreign.ValueLayout.OfInt; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java index 344dcf6c..8153386f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java @@ -2,24 +2,15 @@ package net.codecrete.usb.linux.gen.usbdevice_fs; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.PaddingLayout; -import java.lang.foreign.SequenceLayout; -import java.lang.foreign.StructLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class usbdevice_fs { From e054ec33ec033611c51161ede46dc8fb5db92eff Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 3 Mar 2024 12:38:46 +0100 Subject: [PATCH 339/433] Improved build instructions --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 69aa89e4..193708ac 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,7 @@ When using an older JDK, preview features must be enabled using the `--enable-pr To build from source, run the following command: ``` +cd java-does-usb mvn clean install -DskipTests ``` @@ -169,6 +170,7 @@ The test device with the *loopback-stm32* code supports all tests. If the test d Tests can be run from the command line: ``` +cd java-does-usb mvn clean test ``` From 3355f39164a0d476133eb97e020a61f4160acc20 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 3 Mar 2024 13:04:45 +0100 Subject: [PATCH 340/433] Windows: use latest jextract, no import cleanup --- java-does-usb/jextract/linux/gen_linux.sh | 2 ++ java-does-usb/jextract/macos/gen_macos.sh | 2 ++ java-does-usb/jextract/windows/gen_win.cmd | 5 +++- .../usb/windows/gen/advapi32/Advapi32.java | 27 +++++++------------ .../usb/windows/gen/kernel32/Kernel32.java | 25 ++++++----------- .../usb/windows/gen/kernel32/_GUID.java | 22 +++++++-------- .../usb/windows/gen/kernel32/_OVERLAPPED.java | 20 +++++++------- .../usb/windows/gen/ntdll/NtDll.java | 25 ++++++----------- .../usb/windows/gen/ole32/Ole32.java | 27 +++++++------------ .../usb/windows/gen/setupapi/SetupAPI.java | 27 +++++++------------ .../usb/windows/gen/setupapi/_DEVPROPKEY.java | 18 ++++++------- .../usb/windows/gen/setupapi/_GUID.java | 22 +++++++-------- .../setupapi/_SP_DEVICE_INTERFACE_DATA.java | 19 +++++++------ .../_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java | 21 +++++++-------- .../gen/setupapi/_SP_DEVINFO_DATA.java | 19 +++++++------ .../usb/windows/gen/usbioctl/USBIoctl.java | 25 ++++++----------- .../gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java | 23 +++++++--------- .../gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java | 19 +++++++------ .../usbioctl/_USB_ENDPOINT_DESCRIPTOR.java | 19 +++++++------ .../_USB_NODE_CONNECTION_INFORMATION_EX.java | 23 +++++++--------- .../windows/gen/usbioctl/_USB_PIPE_INFO.java | 18 ++++++------- .../usb/windows/gen/user32/User32.java | 27 +++++++------------ .../_DEV_BROADCAST_DEVICEINTERFACE_W.java | 21 +++++++-------- .../gen/user32/_DEV_BROADCAST_HDR.java | 18 ++++++------- .../usb/windows/gen/user32/_GUID.java | 22 +++++++-------- .../usb/windows/gen/user32/tagMSG.java | 20 +++++++------- .../usb/windows/gen/user32/tagPOINT.java | 18 ++++++------- .../windows/gen/user32/tagWNDCLASSEXW.java | 19 +++++++------ .../usb/windows/gen/winusb/WinUSB.java | 27 +++++++------------ 29 files changed, 239 insertions(+), 341 deletions(-) diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index c444821e..3b20567c 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -2,6 +2,8 @@ JEXTRACT=../../../../jextract/bin/jextract +rm -rf ../../src/main/java/net/codecrete/usb/linux/gen + # errno.h $JEXTRACT --output ../../src/main/java \ --header-class-name errno \ diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index fd5a9f70..dd38523c 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -4,6 +4,8 @@ JEXTRACT=../../../../jextract/bin/jextract # If SDK_DIR is changed, it needs to be changed in compile_flags.txt as well. SDK_DIR=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk +rm -rf ../../src/main/java/net/codecrete/usb/macos/gen + # CoreFoundation $JEXTRACT --output ../../src/main/java \ -I $SDK_DIR/usr/include \ diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index 9970d958..d0cf4f12 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -1,6 +1,9 @@ -set JEXTRACT=..\..\..\..\jextract\build\jextract\bin\jextract.bat +set JEXTRACT=..\..\..\..\jextract\bin\jextract.bat set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 +del /s /q ..\..\src\main\java\net\codecrete\usb\windows\gen +rmdir /s /q ..\..\src\main\java\net\codecrete\usb\windows\gen + call %JEXTRACT% --output ../../src/main/java ^ -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ -I "%SDK_DIR%\um" ^ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java index b015cf12..aa61da82 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java @@ -2,24 +2,15 @@ package net.codecrete.usb.windows.gen.advapi32; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.PaddingLayout; -import java.lang.foreign.SequenceLayout; -import java.lang.foreign.StructLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class Advapi32 { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java index 001fcc43..fcd1d7b3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -2,24 +2,15 @@ package net.codecrete.usb.windows.gen.kernel32; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.PaddingLayout; -import java.lang.foreign.SequenceLayout; -import java.lang.foreign.StructLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class Kernel32 { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java index 34169dd9..3464e8f0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java @@ -2,19 +2,15 @@ package net.codecrete.usb.windows.gen.kernel32; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SequenceLayout; -import java.lang.invoke.VarHandle; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfShort; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java index 31fdebc2..9bc7d1c7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java @@ -2,17 +2,15 @@ package net.codecrete.usb.windows.gen.kernel32; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfLong; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java index 6c991619..43434083 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java @@ -2,24 +2,15 @@ package net.codecrete.usb.windows.gen.ntdll; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.PaddingLayout; -import java.lang.foreign.SequenceLayout; -import java.lang.foreign.StructLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class NtDll { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java index e141b311..a94f7735 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java @@ -2,24 +2,15 @@ package net.codecrete.usb.windows.gen.ole32; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.PaddingLayout; -import java.lang.foreign.SequenceLayout; -import java.lang.foreign.StructLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class Ole32 { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java index c8e234c6..d206dd3e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java @@ -2,24 +2,15 @@ package net.codecrete.usb.windows.gen.setupapi; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.PaddingLayout; -import java.lang.foreign.SequenceLayout; -import java.lang.foreign.StructLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class SetupAPI { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java index b1f43780..56dae5a6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java @@ -2,15 +2,15 @@ package net.codecrete.usb.windows.gen.setupapi; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfInt; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_GUID.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_GUID.java index 00de66c1..019decc9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_GUID.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_GUID.java @@ -2,19 +2,15 @@ package net.codecrete.usb.windows.gen.setupapi; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SequenceLayout; -import java.lang.invoke.VarHandle; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfShort; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java index 1738fc5c..b97ad0d7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java @@ -2,16 +2,15 @@ package net.codecrete.usb.windows.gen.setupapi; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfLong; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java index f09c3ed7..7a07f13e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java @@ -2,18 +2,15 @@ package net.codecrete.usb.windows.gen.setupapi; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SequenceLayout; -import java.lang.invoke.VarHandle; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; -import static java.lang.foreign.ValueLayout.OfInt; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java index 96c0f0cf..03699c70 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java @@ -2,16 +2,15 @@ package net.codecrete.usb.windows.gen.setupapi; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfLong; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java index 7d36eaf8..3ce529cc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java @@ -2,24 +2,15 @@ package net.codecrete.usb.windows.gen.usbioctl; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.PaddingLayout; -import java.lang.foreign.SequenceLayout; -import java.lang.foreign.StructLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class USBIoctl { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java index 844ea50a..c3e9a665 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java @@ -2,20 +2,15 @@ package net.codecrete.usb.windows.gen.usbioctl; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SequenceLayout; -import java.lang.invoke.VarHandle; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; -import static java.lang.foreign.ValueLayout.OfByte; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfShort; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java index 5fad54ec..c8c41cb3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java @@ -2,16 +2,15 @@ package net.codecrete.usb.windows.gen.usbioctl; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfByte; -import static java.lang.foreign.ValueLayout.OfShort; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_ENDPOINT_DESCRIPTOR.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_ENDPOINT_DESCRIPTOR.java index e25b0e6e..965cedf2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_ENDPOINT_DESCRIPTOR.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_ENDPOINT_DESCRIPTOR.java @@ -2,16 +2,15 @@ package net.codecrete.usb.windows.gen.usbioctl; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfByte; -import static java.lang.foreign.ValueLayout.OfShort; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java index efcbaae3..199c11c9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java @@ -2,20 +2,15 @@ package net.codecrete.usb.windows.gen.usbioctl; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SequenceLayout; -import java.lang.invoke.MethodHandle; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; -import static java.lang.foreign.ValueLayout.OfByte; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfShort; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_PIPE_INFO.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_PIPE_INFO.java index 0ea41864..0777bc3c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_PIPE_INFO.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_PIPE_INFO.java @@ -2,15 +2,15 @@ package net.codecrete.usb.windows.gen.usbioctl; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfInt; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java index 63b935db..f22968ba 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java @@ -2,24 +2,15 @@ package net.codecrete.usb.windows.gen.user32; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.PaddingLayout; -import java.lang.foreign.SequenceLayout; -import java.lang.foreign.StructLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class User32 { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java index 6c3d5e10..67bbb286 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java @@ -2,18 +2,15 @@ package net.codecrete.usb.windows.gen.user32; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SequenceLayout; -import java.lang.invoke.VarHandle; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; -import static java.lang.foreign.ValueLayout.OfInt; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java index 9ccf303c..c6723356 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java @@ -2,15 +2,15 @@ package net.codecrete.usb.windows.gen.user32; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfInt; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_GUID.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_GUID.java index 6d079fe8..ecef1ab6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_GUID.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_GUID.java @@ -2,19 +2,15 @@ package net.codecrete.usb.windows.gen.user32; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.SequenceLayout; -import java.lang.invoke.VarHandle; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfShort; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java index d41d2f66..b75ef832 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java @@ -2,17 +2,15 @@ package net.codecrete.usb.windows.gen.user32; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfInt; -import static java.lang.foreign.ValueLayout.OfLong; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagPOINT.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagPOINT.java index f77c4c42..54888fc4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagPOINT.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagPOINT.java @@ -2,15 +2,15 @@ package net.codecrete.usb.windows.gen.user32; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfInt; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java index f1ed2467..525ff27b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java @@ -2,16 +2,15 @@ package net.codecrete.usb.windows.gen.user32; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.util.function.Consumer; - -import static java.lang.foreign.MemoryLayout.PathElement.groupElement; -import static java.lang.foreign.ValueLayout.OfInt; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java index 8d1beb4b..5d9a82ff 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java @@ -2,24 +2,15 @@ package net.codecrete.usb.windows.gen.winusb; -import java.lang.foreign.AddressLayout; -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.PaddingLayout; -import java.lang.foreign.SequenceLayout; -import java.lang.foreign.StructLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.stream.Collectors; - -import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; public class WinUSB { From 6b57956e16994ed6e350645b4455cceaef0e6680 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 3 Mar 2024 19:03:21 +0100 Subject: [PATCH 341/433] macOS: handle all messages on disconnect --- java-does-usb/jextract/macos/gen_macos.sh | 6 + .../codecrete/usb/macos/MacosAsyncTask.java | 74 +++-- .../codecrete/usb/macos/MacosUsbDevice.java | 9 +- .../CFMessagePortCreateLocal$callout.java | 71 +++++ .../gen/corefoundation/CoreFoundation.java | 297 ++++++++++++++++++ .../net/codecrete/usb/special/Continuous.java | 57 ++++ 6 files changed, 490 insertions(+), 24 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFMessagePortCreateLocal$callout.java create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/special/Continuous.java diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index dd38523c..24a0c05d 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -27,6 +27,12 @@ $JEXTRACT --output ../../src/main/java \ --include-function CFRunLoopAddSource \ --include-function CFRunLoopRemoveSource \ --include-function CFRunLoopRun \ + --include-function CFMessagePortCreateLocal \ + --include-function CFMessagePortCreateRunLoopSource \ + --include-function CFMessagePortCreateRemote \ + --include-function CFMessagePortSendRequest \ + --include-function CFDataCreate \ + --include-function CFDataGetBytePtr \ --include-function CFUUIDGetUUIDBytes \ --include-constant kCFNumberSInt32Type \ cf_helper.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java index ae03582c..65a1f923 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java @@ -22,8 +22,9 @@ import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.MemorySegment.NULL; +import static java.lang.foreign.ValueLayout.*; + /** * Background task for handling asynchronous transfers. @@ -54,6 +55,7 @@ enum TaskState { private TaskState state = TaskState.NOT_STARTED; private MemorySegment asyncIoRunLoop; private MemorySegment completionUpcallStub; + private MemorySegment messagePort; private long lastTransferId; private final Map transfersById = new HashMap<>(); @@ -67,15 +69,9 @@ void addEventSource(MemorySegment source) { asyncIoLock.lock(); if (state != TaskState.RUNNING) { - if (state == TaskState.NOT_STARTED) { - startAsyncIOThread(source); - waitForRunLoopReady(); - return; - - } else { - // special case: run loop is not ready yet but background process is already starting - waitForRunLoopReady(); - } + if (state == TaskState.NOT_STARTED) + startAsyncIOThread(); + waitForRunLoopReady(); } CoreFoundation.CFRunLoopAddSource(asyncIoRunLoop, source, IOKit.kCFRunLoopDefaultMode()); @@ -92,34 +88,60 @@ private void waitForRunLoopReady() { /** * Removes an event source from this background task. - * + *

+ * The event source is not immediately removed. Instead, it is posted to a message queue + * processed by the same background thread processing the completion callbacks. This ensures + * that the events from releasing interfaces and closing devices are processed. + *

* @param source event source */ void removeEventSource(MemorySegment source) { - CoreFoundation.CFRunLoopRemoveSource(asyncIoRunLoop, source, IOKit.kCFRunLoopDefaultMode()); + try (var arena = Arena.ofConfined()) { + var eventSourceRef = arena.allocate(JAVA_LONG, 1); + eventSourceRef.set(JAVA_LONG, 0, source.address()); + var dataRef = CoreFoundation.CFDataCreate(NULL, eventSourceRef, eventSourceRef.byteSize()); + CoreFoundation.CFMessagePortSendRequest(messagePort, 0, dataRef, 0, 0, NULL, NULL); + CoreFoundation.CFRelease(dataRef); + } } /** * Starts the background thread. - * - * @param firstSource first event source */ - private void startAsyncIOThread(MemorySegment firstSource) { + @SuppressWarnings("java:S125") + private void startAsyncIOThread() { + MemorySegment messagePortSource; + try { state = TaskState.STARTING; + + // create descriptor for completion callback function var completionHandlerFuncDesc = FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT, ADDRESS); var asyncIOCompletedMH = MethodHandles.lookup().findVirtual(MacosAsyncTask.class, "asyncIOCompleted", MethodType.methodType(void.class, MemorySegment.class, int.class, MemorySegment.class)); var methodHandle = asyncIOCompletedMH.bindTo(this); - completionUpcallStub = Linker.nativeLinker().upcallStub(methodHandle, completionHandlerFuncDesc, - Arena.global()); + completionUpcallStub = Linker.nativeLinker().upcallStub(methodHandle, completionHandlerFuncDesc, Arena.global()); + + // create descriptor for message port callback function + var messagePortCallbackFuncDec = FunctionDescriptor.of(ADDRESS, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); + var messagePortCallbackMH = MethodHandles.lookup().findVirtual(MacosAsyncTask.class, "messagePortCallback", + MethodType.methodType(MemorySegment.class, MemorySegment.class, int.class, MemorySegment.class, MemorySegment.class)); + var messagePortCallbackHandle = messagePortCallbackMH.bindTo(this); + var messagePortCallbackStub = Linker.nativeLinker().upcallStub(messagePortCallbackHandle, messagePortCallbackFuncDec, Arena.global()); + + // create local and remote message ports + var pid = ProcessHandle.current().pid(); + var portName = CoreFoundationHelper.createCFStringRef("net.codecrete.usb.macos.eventsource." + pid, Arena.global()); + var localPort = CoreFoundation.CFMessagePortCreateLocal(NULL, portName, messagePortCallbackStub, NULL, NULL); + messagePortSource = CoreFoundation.CFMessagePortCreateRunLoopSource(NULL, localPort, 0); + messagePort = CoreFoundation.CFMessagePortCreateRemote(NULL, portName); } catch (IllegalAccessException | NoSuchMethodException e) { throw new UsbException("internal error (creating method handle)", e); } - var thread = new Thread(() -> asyncIOCompletionTask(firstSource), "USB async IO"); + var thread = new Thread(() -> asyncIOCompletionTask(messagePortSource), "USB async IO"); thread.setDaemon(true); thread.start(); } @@ -184,6 +206,20 @@ private void asyncIOCompleted(MemorySegment refcon, int result, MemorySegment ar transfer.completion().completed(transfer); } + /** + * Callback function called when a message is received on the message port. + *

+ * All messages are related to removing event sources. They just contain the run loop source reference. + *

+ */ + @SuppressWarnings({"java:S1144", "unused"}) + private MemorySegment messagePortCallback(MemorySegment local, int msgid, MemorySegment data, MemorySegment info) { + var runloopSourceRefPtr = CoreFoundation.CFDataGetBytePtr(data); + var runloopSourceRef = MemorySegment.ofAddress(runloopSourceRefPtr.get(JAVA_LONG_UNALIGNED, 0)); + CoreFoundation.CFRunLoopRemoveSource(asyncIoRunLoop, runloopSourceRef, IOKit.kCFRunLoopDefaultMode()); + return NULL; + } + /** * Gets the native IO completion callback function for asynchronous transfers * to be handled by this background task. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java index b6a16e04..63ffd5ca 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java @@ -143,22 +143,21 @@ public synchronized void close() { return; for (var interfaceInfo : claimedInterfaces) { + setClaimed(interfaceInfo.interfaceNumber, false); var source = IoKitUsb.GetInterfaceAsyncEventSource(interfaceInfo.iokitInterface()); - if (source.address() != 0) - asyncTask.removeEventSource(source); IoKitUsb.USBInterfaceClose(interfaceInfo.iokitInterface); IoKitUsb.Release(interfaceInfo.iokitInterface); - setClaimed(interfaceInfo.interfaceNumber, false); + if (source.address() != 0) + asyncTask.removeEventSource(source); } claimedInterfaces = null; endpoints = null; var source = IoKitUsb.GetDeviceAsyncEventSource(device); + IoKitUsb.USBDeviceClose(device); if (source.address() != 0) asyncTask.removeEventSource(source); - - IoKitUsb.USBDeviceClose(device); } synchronized void closeFully() { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFMessagePortCreateLocal$callout.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFMessagePortCreateLocal$callout.java new file mode 100644 index 00000000..df8fbeda --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFMessagePortCreateLocal$callout.java @@ -0,0 +1,71 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.corefoundation; + +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; + +/** + * {@snippet lang=c : + * CFMessagePortCallBack callout + * } + */ +public class CFMessagePortCreateLocal$callout { + + CFMessagePortCreateLocal$callout() { + // Should not be called directly + } + + /** + * The function pointer signature, expressed as a functional interface + */ + public interface Function { + MemorySegment apply(MemorySegment _x0, int _x1, MemorySegment _x2, MemorySegment _x3); + } + + private static final FunctionDescriptor $DESC = FunctionDescriptor.of( + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER, + CoreFoundation.C_INT, + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER + ); + + /** + * The descriptor of this function pointer + */ + public static FunctionDescriptor descriptor() { + return $DESC; + } + + private static final MethodHandle UP$MH = CoreFoundation.upcallHandle(CFMessagePortCreateLocal$callout.Function.class, "apply", $DESC); + + /** + * Allocates a new upcall stub, whose implementation is defined by {@code fi}. + * The lifetime of the returned segment is managed by {@code arena} + */ + public static MemorySegment allocate(CFMessagePortCreateLocal$callout.Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); + } + + private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); + + /** + * Invoke the upcall stub {@code funcPtr}, with given parameters + */ + public static MemorySegment invoke(MemorySegment funcPtr,MemorySegment _x0, int _x1, MemorySegment _x2, MemorySegment _x3) { + try { + return (MemorySegment) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java index 26bfb887..0413e52c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java @@ -163,6 +163,102 @@ public static void CFRelease(MemorySegment cf) { } } + private static class CFDataCreate { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER, + CoreFoundation.C_LONG + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFDataCreate"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * extern CFDataRef CFDataCreate(CFAllocatorRef allocator, const UInt8 *bytes, CFIndex length) + * } + */ + public static FunctionDescriptor CFDataCreate$descriptor() { + return CFDataCreate.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern CFDataRef CFDataCreate(CFAllocatorRef allocator, const UInt8 *bytes, CFIndex length) + * } + */ + public static MethodHandle CFDataCreate$handle() { + return CFDataCreate.HANDLE; + } + /** + * {@snippet lang=c : + * extern CFDataRef CFDataCreate(CFAllocatorRef allocator, const UInt8 *bytes, CFIndex length) + * } + */ + public static MemorySegment CFDataCreate(MemorySegment allocator, MemorySegment bytes, long length) { + var mh$ = CFDataCreate.HANDLE; + try { + if (TRACE_DOWNCALLS) { + traceDowncall("CFDataCreate", allocator, bytes, length); + } + return (MemorySegment)mh$.invokeExact(allocator, bytes, length); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + + private static class CFDataGetBytePtr { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFDataGetBytePtr"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * extern const UInt8 *CFDataGetBytePtr(CFDataRef theData) + * } + */ + public static FunctionDescriptor CFDataGetBytePtr$descriptor() { + return CFDataGetBytePtr.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern const UInt8 *CFDataGetBytePtr(CFDataRef theData) + * } + */ + public static MethodHandle CFDataGetBytePtr$handle() { + return CFDataGetBytePtr.HANDLE; + } + /** + * {@snippet lang=c : + * extern const UInt8 *CFDataGetBytePtr(CFDataRef theData) + * } + */ + public static MemorySegment CFDataGetBytePtr(MemorySegment theData) { + var mh$ = CFDataGetBytePtr.HANDLE; + try { + if (TRACE_DOWNCALLS) { + traceDowncall("CFDataGetBytePtr", theData); + } + return (MemorySegment)mh$.invokeExact(theData); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + private static class CFStringGetTypeID { public static final FunctionDescriptor DESC = FunctionDescriptor.of( CoreFoundation.C_LONG ); @@ -734,5 +830,206 @@ public static MemorySegment CFUUIDCreateFromUUIDBytes(MemorySegment alloc, Memor throw new AssertionError("should not reach here", ex$); } } + + private static class CFMessagePortCreateLocal { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFMessagePortCreateLocal"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * extern CFMessagePortRef CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo) + * } + */ + public static FunctionDescriptor CFMessagePortCreateLocal$descriptor() { + return CFMessagePortCreateLocal.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern CFMessagePortRef CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo) + * } + */ + public static MethodHandle CFMessagePortCreateLocal$handle() { + return CFMessagePortCreateLocal.HANDLE; + } + /** + * {@snippet lang=c : + * extern CFMessagePortRef CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo) + * } + */ + public static MemorySegment CFMessagePortCreateLocal(MemorySegment allocator, MemorySegment name, MemorySegment callout, MemorySegment context, MemorySegment shouldFreeInfo) { + var mh$ = CFMessagePortCreateLocal.HANDLE; + try { + if (TRACE_DOWNCALLS) { + traceDowncall("CFMessagePortCreateLocal", allocator, name, callout, context, shouldFreeInfo); + } + return (MemorySegment)mh$.invokeExact(allocator, name, callout, context, shouldFreeInfo); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + + private static class CFMessagePortCreateRemote { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFMessagePortCreateRemote"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * extern CFMessagePortRef CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef name) + * } + */ + public static FunctionDescriptor CFMessagePortCreateRemote$descriptor() { + return CFMessagePortCreateRemote.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern CFMessagePortRef CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef name) + * } + */ + public static MethodHandle CFMessagePortCreateRemote$handle() { + return CFMessagePortCreateRemote.HANDLE; + } + /** + * {@snippet lang=c : + * extern CFMessagePortRef CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef name) + * } + */ + public static MemorySegment CFMessagePortCreateRemote(MemorySegment allocator, MemorySegment name) { + var mh$ = CFMessagePortCreateRemote.HANDLE; + try { + if (TRACE_DOWNCALLS) { + traceDowncall("CFMessagePortCreateRemote", allocator, name); + } + return (MemorySegment)mh$.invokeExact(allocator, name); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + + private static class CFMessagePortSendRequest { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + CoreFoundation.C_INT, + CoreFoundation.C_POINTER, + CoreFoundation.C_INT, + CoreFoundation.C_POINTER, + CoreFoundation.C_DOUBLE, + CoreFoundation.C_DOUBLE, + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFMessagePortSendRequest"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * extern SInt32 CFMessagePortSendRequest(CFMessagePortRef remote, SInt32 msgid, CFDataRef data, CFTimeInterval sendTimeout, CFTimeInterval rcvTimeout, CFStringRef replyMode, CFDataRef *returnData) + * } + */ + public static FunctionDescriptor CFMessagePortSendRequest$descriptor() { + return CFMessagePortSendRequest.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern SInt32 CFMessagePortSendRequest(CFMessagePortRef remote, SInt32 msgid, CFDataRef data, CFTimeInterval sendTimeout, CFTimeInterval rcvTimeout, CFStringRef replyMode, CFDataRef *returnData) + * } + */ + public static MethodHandle CFMessagePortSendRequest$handle() { + return CFMessagePortSendRequest.HANDLE; + } + /** + * {@snippet lang=c : + * extern SInt32 CFMessagePortSendRequest(CFMessagePortRef remote, SInt32 msgid, CFDataRef data, CFTimeInterval sendTimeout, CFTimeInterval rcvTimeout, CFStringRef replyMode, CFDataRef *returnData) + * } + */ + public static int CFMessagePortSendRequest(MemorySegment remote, int msgid, MemorySegment data, double sendTimeout, double rcvTimeout, MemorySegment replyMode, MemorySegment returnData) { + var mh$ = CFMessagePortSendRequest.HANDLE; + try { + if (TRACE_DOWNCALLS) { + traceDowncall("CFMessagePortSendRequest", remote, msgid, data, sendTimeout, rcvTimeout, replyMode, returnData); + } + return (int)mh$.invokeExact(remote, msgid, data, sendTimeout, rcvTimeout, replyMode, returnData); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + + private static class CFMessagePortCreateRunLoopSource { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER, + CoreFoundation.C_POINTER, + CoreFoundation.C_LONG + ); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( + CoreFoundation.findOrThrow("CFMessagePortCreateRunLoopSource"), + DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * extern CFRunLoopSourceRef CFMessagePortCreateRunLoopSource(CFAllocatorRef allocator, CFMessagePortRef local, CFIndex order) + * } + */ + public static FunctionDescriptor CFMessagePortCreateRunLoopSource$descriptor() { + return CFMessagePortCreateRunLoopSource.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * extern CFRunLoopSourceRef CFMessagePortCreateRunLoopSource(CFAllocatorRef allocator, CFMessagePortRef local, CFIndex order) + * } + */ + public static MethodHandle CFMessagePortCreateRunLoopSource$handle() { + return CFMessagePortCreateRunLoopSource.HANDLE; + } + /** + * {@snippet lang=c : + * extern CFRunLoopSourceRef CFMessagePortCreateRunLoopSource(CFAllocatorRef allocator, CFMessagePortRef local, CFIndex order) + * } + */ + public static MemorySegment CFMessagePortCreateRunLoopSource(MemorySegment allocator, MemorySegment local, long order) { + var mh$ = CFMessagePortCreateRunLoopSource.HANDLE; + try { + if (TRACE_DOWNCALLS) { + traceDowncall("CFMessagePortCreateRunLoopSource", allocator, local, order); + } + return (MemorySegment)mh$.invokeExact(allocator, local, order); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/Continuous.java b/java-does-usb/src/test/java/net/codecrete/usb/special/Continuous.java new file mode 100644 index 00000000..1df4bcf1 --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/Continuous.java @@ -0,0 +1,57 @@ +package net.codecrete.usb.special; + +import net.codecrete.usb.Usb; +import net.codecrete.usb.UsbDevice; +import net.codecrete.usb.UsbException; + +import java.io.IOException; +import java.util.Random; + +public class Continuous { + + @SuppressWarnings("ResultOfMethodCallIgnored") + public static void main(String[] args) throws IOException { + var device = Usb.findDevice(0xcafe, 0xceaf) + .or(() -> Usb.findDevice(0xcafe, 0xcea0)) + .orElseThrow(() -> new IllegalStateException("No test device connected")); + var interfaceNumber = device.getProductId() == 0xceaf ? 0 : 3; + + device.open(); + device.claimInterface(interfaceNumber); + + new Thread(() -> readData(device)).start(); + new Thread(() -> sendData(device)).start(); + + System.out.println("Press Enter to exit"); + System.in.read(); + device.close(); + } + + @SuppressWarnings({"java:S2925", "BusyWait"}) + private static void sendData(UsbDevice device) { + var random = new Random(); + var buffer = new byte[80]; + + while (true) { + random.nextBytes(buffer); + try { + device.transferOut(1, buffer); + Thread.sleep(3000); + } catch (UsbException e) { + return; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + + private static void readData(UsbDevice device) { + while (true) { + try { + device.transferIn(2); + } catch (UsbException e) { + return; + } + } + } +} From 84f84b70e85cadd8a563cc54c242c9c0d86240d3 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 11 Mar 2024 22:44:38 +0100 Subject: [PATCH 342/433] Test device: suspend and resume --- .../loopback-stm32/.vscode/settings.json | 5 +- .../loopback-stm32/bin/blackpill-f401cc.bin | Bin 10984 -> 11144 bytes .../loopback-stm32/bin/blackpill-f411ce.bin | Bin 10988 -> 11148 bytes .../loopback-stm32/bin/bluepill-f103c8.bin | Bin 11128 -> 11260 bytes .../loopback-stm32/bin/disco_f723ie.bin | Bin 11772 -> 11748 bytes test-devices/loopback-stm32/src/board.h | 3 + test-devices/loopback-stm32/src/board_f1.c | 44 ++++++++++++- test-devices/loopback-stm32/src/board_f4.c | 61 +++++++++++++++++- test-devices/loopback-stm32/src/board_f7.c | 4 ++ test-devices/loopback-stm32/src/main.c | 10 +-- .../loopback-stm32/src/usb_descriptors.c | 2 +- 11 files changed, 113 insertions(+), 16 deletions(-) diff --git a/test-devices/loopback-stm32/.vscode/settings.json b/test-devices/loopback-stm32/.vscode/settings.json index a92d1337..1a7c2ee4 100644 --- a/test-devices/loopback-stm32/.vscode/settings.json +++ b/test-devices/loopback-stm32/.vscode/settings.json @@ -3,6 +3,9 @@ "usbd.h": "c", "usbd_pvt.h": "c", "dwc2_stm32.h": "c", - "stm32f7xx.h": "c" + "stm32f7xx.h": "c", + "stm32f4xx.h": "c", + "stm32f401xc.h": "c", + "stm32f401xe.h": "c" } } \ No newline at end of file diff --git a/test-devices/loopback-stm32/bin/blackpill-f401cc.bin b/test-devices/loopback-stm32/bin/blackpill-f401cc.bin index fd044b62bebb3eae874b9c31ba8d320cfca66d1d..ee327901eec0ba936ab6e30e832d4047a95162f6 100755 GIT binary patch delta 1402 zcmZuxZ)_7~7=PZo>vk)+U1__ug>KjD#-H8xlDmRbpuG6DTy%;e8pVnWb?Mki)^3B!(AcRufA-@N3>@80*` z=Xrj=-}|(a9sN6xHj@0?n@@A&4q8qskC7HKN?XZ`)rkm*Vvg6B4)M)=;_Q9Mhu1w(03w?zRk&j{24-n}hsf%r%lxK^w+OFm(x-02ZJsDCjz_4? zc{{?*PV*>V91kZ1^KKJoWm4T5XM_@*sZ49p=rlw*BY^J*ql#s5(dkSoU^q?1%Jeu5 zUovTk<`tIJ6V;rCgtd;5;<%gc<<$y4DP44%VeINQ?1D*83x0Z$tM|_2?7|^i*Y(zb zskbPWzy*vX9pdBUbNY~9Rr8^J(i}s!T5r2npM2kNnQ9ATpF#F+V-?*ZR4uJds>YaE z+ZwjCJ!7bcVUv~F<2Gd4D?HKQ(IK>bI-`)@&aOcdSu2C6f?>cY*YQjDk(r3Q)0oM_ zh%^BcYa2KXfYa!8!SiYwZIfQMYoL*6a0e!c?laNXkw!FI(0xPOEl3S^rQ_SDAvOCe zjDW~#>6~wyuf^Yrd+pgSWnKW`+qJNvnx16X;&^qQCXZ&g9$kkpFKF!uqc6;xbbKyi zjy;ZAIZRcJ@Vt9r0~=z|be=VWa%f|WAq|=|1rtm^yi{Q!Qvke!Ne!e*c zM9xo28d$w_z!BVia9C1=W*$$(hhby_Yy6BciBXz^TDvef2k($DI?!FwEG48?*EX;= z7v&gOPySQUf)`@hYrz_wvkMz+)m&$O5jYyXKjz*l_o+A_>uFg@uWRWn7wfw~Vsb1$ z*?^rF(SedWm7C>tU&byxZRaON%`WU4Szx~yt3O*T(?KC}zyNEC-Yz-scRl3JrSsJ# zKYaI7zo6c_;Yo&KD`Uh8(le!16(C~g18kuU|ujSB+REFk&ZX0v|OxSVi)Q! zvE^$x3=C<6c8cprI~@>LgaC8D#}DavIxfbk&T0_x7s)_S}^quBfCtyeG&qdf$8CvD+eu77oM%>@i9YRPNmP0Uo`E z@h3(Nrn2C%6x&-^{~w;slB#P2e~mYMUV;7B(0jg3;%`_V@S*kot=zjxw#WZ1$F-?6 zy6i54<-yeqb_CZkcrzFXw4q6Y4kYl*%^9Jg31|8WVmjWYW-kSwBX}%ZUGo$}xTuU{h$m)V|PRw)!K~%^;;P$bO~_a}0ax=J;|0J1oTWDt%?uFOGY7D}T|wku^(p hm4Ub$qtyxGevGa%dMXm}Jdlu;6GtBwGc{mi{0ljmykr0X delta 1276 zcmZuwT}&KR6h3!mcK5QSFv~)hSp;Txm6lx#Z8Zu8k}2EnvO7>Lx?{QYbGrCX|Pk#E?u{a94I>;cLHp00}w*_&g0D zpDAS%q$cacLolY6<6!_IU-L6B*GDg5mU85M!g~2<_r#+PeQEG|kT(dgDo)L*pR%Q< z-clvqWAH@MME!D*%qO<*R2{=tH^^w$6j8*f2!rf7|-l?l~K5XdJ(u;f35!J1G4S{oOVRn-blNKfk zrNwpWuk}f^rF6Waltxc$4t-0VX*02AvxKz>t^!XqpiSzYdY_@RO`>&^gGQpwsTDFN zZ0`gg-?20Tqfo&q6rms>4vO^ZP8(El$~H3wP7$YJ8gORMV?0hkt^jx$D6Vl*;?Z<5 zQS)^i;b;|V1T}x4VICU4Xo-g#3}{@rhxJj*MV&f%&Z({IKqj5W*hK(wFtZkn;gk^S z9_W(6xW1wfQPmd7?@mDC{FgObM&(e~`H@*sG2dPo7SZq$nxNQB9JJTk>%jOSubJp7rT{Ys0p+Jo}n69(|bufpksnUXJ z<%kAECzdhM_GE88{y)x6e&zaukaMhE$`e)>&!*XN=_R@q>sKS#Z_+OAA5SvJ{X56? z``OG>Gba69SZ2~f;SQ7hMQ(RL4oFaexL=!C5-NfQ$6rB?hx`4>=AveTvgF0$7ffag za-&I6Pmf7|de%zWy#J}liijx2U diff --git a/test-devices/loopback-stm32/bin/blackpill-f411ce.bin b/test-devices/loopback-stm32/bin/blackpill-f411ce.bin index ad2b198b2f317be00d97774764090d85531dc49e..b278a5a0f44d86df6b37c3517469a0e86b801d48 100755 GIT binary patch delta 1460 zcmZuwZERCj7=F*ack5k&?Ur_1Td3T&e7N2P22&Y0^xBek>+Sg1_|W~py8+2HIxS3b zArh9M$xH}g91?NzOA~{UucbDGVHqD1LyXECGeL}Q_%RY4xk^n(EvxS-@XsGlo^#H9 z&v~EcIrsdzasTFn_2gpTs!zEaMYNPu93n9?OqJn}{L~^5c z+QBPjd{p|}ZuqgGUC(C>dP;E73tV;iR5G90lh-t@$!%ycpDA!|JxY^&gq)-I`Kt9F z=RY(?P^jA3qE<&g(rtzkW5T;pxLvP`;+g3hdngTdyB;W13Ve$?KdR^>#{4F~scs!X zbBse~_g1?u(>H~sdmS2h*QUFDq_efH-w5KUUw0SSt(R)}rG4L2z}~7)rC>-JgRz=A zPQ?@vAU}cQYXsyvfOQ~p>gyP(v^zf!>WK>DFh(?|fte50W38Y$2iBU<+}{?DtW866 zb^?ZQ&t5g2bgps6Tur#xl4$c4gcB6**A>GN^_v{86lC)lm+j$Q2?fhFL(Gm)i1Enu z1IrxlRCIqKUcZhF@yvLNiGxyD#|%ImRA~~%I1G%`*4p()3PC33<@4x`x%Rc9PE?3a zq~y#7FpuYiaPL5m3}%Y1D)KBpHYi~tQ|MkqcT&>YV2y!!GUx9-{YR*5#!Z5iN3wNi zeZ72RGY~m-TT;R7q7Rzf#E*frmo-Wa zQj={Bn5%Mf7|bW{m&NeD%zO=)Ur*;V%kzq{%(&n_7`!`TUoCej_(#>!S;d{UIaw~; zb(VzXaO!p)cAi1|iWd-$o+;9n48OUVO%7yT_f5ryeW*>H06df^u`% z5%q>24-?Zv2P~E3XL{ALB`8YJhBlWn>GTXh=UC2_v8lq)=Y{tg< zO!awI_YVFYjNc2;E#flLLi@x;UI91%h#%sScti|~NmuxC34bl08J#Awn966)&>P|; z>7ieiY$V&M$GXVVF@1dkARp^|c~$g$|cpC121Fq>bcC z;xB0h&snpy+VM6v9dPVh__PzmDuk;X#PWxHAIF<3AFNeYfT&c^*7BodF3pthm^Chf zXyQL}4|@#LH!3!-_ykKw5O)!N+{$3VquAP``TubuQB?UYai7cY_-&>(r|SpH-hVny z%+^48HvQ6xQ+J`8-f^xJC$S$sFrYQA)!h5O#4gu29JfKC;kmaM1w4xxwR)B@I^c1; zH(-o{2E_gRcT+-L2p`QQDu^o+M~)T`beHv8M# z&S;a5QDV?H$T8lvV45%8h8-TkP-sup??rd;-m#ZQ}Kx{9eCj$Y; RJqcA=@pZsV<_7YJ{{ZkV%k}^O delta 1264 zcmZuwe@q)?82-MymVWIzxY8ErY2n%mTib;JCd!n>gR&NSErcRLNpv@G;ry{!#?06j zBW{|YE(`E2S)%xli^j!~j1;!4v9d9Y;^rIz{vpXirW+(ma*1_?uJ-(njrfn3JbCVY z^L+37e9z@hw*T2SSOcv?yT8IlSTqbnuoQ>k>(qHSjzdPD4?`?=r(>t1?L6fvLaotDDkQR8eXqHBFnT0n5o8*vbXcHOfst+dnD{Fa^ zxWCaL4bqu~{S6xFj*pW2Bb_`Yc0H_;d|fAxb7|Jr5e$k*nov)40A;*ScW}yw& z(q8+Xpb$1oLdZoHnnfkmqBIJuq=}*}4knk#jNb`X2y_$R z2_3@1ML7a5T$G1&|lBO6r*6m8zsG>|otrbLM)k z&r9MyjAwFsP3|=1@4F2BoIkNrO*Y$bSXb(0(zH<2ucV$=5-W&TQm;*Jx;K*P-5I?A zoRDKhAV0vL>Mq$z)~O58L~+jT`QHXK-o;r<(Ba?ihq4zRK!tD>zmImZhdcn)lMK`> z)Vn|z9R&^1z=#LmM8)Nlz~7(FXGJw{4UthobMolH|7ulwmwXqMQ*N9^Rq!mX)NgaV zLgv;GL<7+P@}mix|C*k@rKG;gLJlRA)H!@azX}iGZbKVv#|gtW``+yQGT`Qx8UO6^ zNwVrZ!IuO-<^ZIP!7XoUp&s`zGw>pQ*3<^|u_4ngn#!!>8kbeBYw#W(4~Thy~E`FBP&i@M_?{KQ_!=u6agf!f~DO$fUMYB*uG0ojy*}xN^pXV zQPKUVw^{!mn`56B{sh@krRT0uc&zVN-8+9D7|j=e_qpV&quJCs1)s7#gDT0sS^|8_ zR!^-vVg>9?iW>Ledyn5y=?8ncN@;tQO6A2YJ5D0h2mrD#{Jf^A_Q@1IMK~H5_ryAj zUxq{$n<{xqWt`?BDm6JysdU@1F)G)2T&;$kohsempjd}1u5OJLlx6AMX|iDx-+Qpr sb5GkuS{-<+cW3@p;`JKAm>!^6f^QLS@_H;UGQ^dE{5Ze})JGxs7qQBmt^fc4 diff --git a/test-devices/loopback-stm32/bin/bluepill-f103c8.bin b/test-devices/loopback-stm32/bin/bluepill-f103c8.bin index 0d10a31695f61edabc64cf5ef4b0dc454e861088..a4561ee4e43f16e687a9bb23e775951d3771037b 100755 GIT binary patch delta 1289 zcmZuwZ%i9y7=PZoqkRi4^jZ*F*4g&hW@wx^62%2r3#5e}j16QDRL1zi ztV^kEH)0``U>x(b(U4D7Nl0r8xnczC%or00*@&GHL)xOa#iJ&NHhIpGf@jvP_*I^3 zQ8~^X({mG9uya8H0bVZ1I=LO>cQ(k?kJ7ZB8`rzF{9%u5ln9t!9d#%luP^^Y_V;6# zZ(2DdiU!@WN8}5GEtqj3Zb*u9ey~LYZaywXdlgAbNUd73z8Blw&~2ON){>HO?w&Qe z1GlhYwXD&`ZY?=rlKW$HG-F?Y1px3G^MREFsX&5o4;F}Ar6eMdZN!)$S6%B?lRfTu zB7&to`TLMHavRcU^*Xv7oq@QdIHHou@e(dsQhDAPE8AMVu(A5Otl<~Xujib)U%7*q z!tu}b2BjEM_Xgq(nN8A-ff5k3FTnyAbt9)`jrcwX?U|A>lx>dan)JqTbTu2Wn`;^bz6D=!uoNeBb04|}4O$ozdb)E~4Op&lR zoLOwZ&Lym=Xjg#C^Kw;E&poSW7HLq=oy=}eZ^aIudR?QuU*$=oaqhi`36Mr4ri=s@s@jw%Yrq|0ZTJk6hpjDT z;A6KEp+{MoWN3doP_RA-Y*Dz2#MzqAm6Wr4`rPVVK;%Rm^m*bQ^^B!_r7P-E-CPu0 z@mBS_fS{#1BR+TBt)|8D6_>gzT&ejv!8-D^q~FcC;MaQnu6PxmvtUgUs@7{SI{aGE zv7y6L$M5J&kctkfB#|nhjG-ShVp{2uhV{l0X6hpj_1x->zsTOl<4u(zuw}&OicgNn zkpP#($>GV70HtvaC@A+&-&OyE?fI?AQ&Q>AkfmLgtXZ-B-Kwb4Ug3OOf-P7)I zF+2c7sf-Q$Wwsz~Kl{y0DD8Uze01 z@RoAz{@Md|eb5@?#{IyvYli;3;Z-};&t0eef6qC4l@nfE$QXOfG-kiIBm_@Plb{mJ z6}z!>6I(Fd?UhSnv@vDq2aQ~j`V9T4{O0sF?C?zq+%!rQR~+~%+ilKnBfNS=IGe~d zn}3^M8kfA+W?O?hgU$#+y)|0|Yl`szJ7Q_+@ZCJ` zAW_%)ekEkZv=@&5H?A;8E0-4StL^L^OQ&F2V_#Z!v~tW|KqNwm5Dn67Q}8RRc-hdu zy-gH~U+5ENrOV`5rqdyEnC-XT(|q*yd;yfXf*hPJyoJ3!MSP4nX#zTB%1l_BMImcu z=WIWaUsI!1#4cZ$*^|ygd!Iw@hlo7lI_gv~w~^b7|Ia3!nVZh5gj`^k>gy## zKfl6?^*wX}J1isEuC4vTdu^FhTg?IqXI^Xk*=!2o_I;V*7Eg6eKf0SZ$kOcv^Dnr* oKib(TZ-@P93(#i}M<~#j5Th*T^=_HA0oAJT27?X%8UO?FFNXPmYybcN diff --git a/test-devices/loopback-stm32/bin/disco_f723ie.bin b/test-devices/loopback-stm32/bin/disco_f723ie.bin index 5154fd69b1fcab8177f8008a67356b64a6775e0d..01ed7764ab8929232e1f76300903192b22b89f07 100755 GIT binary patch delta 906 zcmZuvYe*DP6h3EXA9r@$nzeKvB94wrE@lrbQYFK-9orNiBh?gwQVYh-4;;IC7NrWwP$M| zfYOsy3&y>)HJs?)r-Jcnv@s=gN7R>SftCxWt4sRSaPLQD!M+RT>fOsqFZ7+|O$30d z^f>FB?7pAY66ZhFOmw|Mp1C+$kt#}{YK^W0(+Ng9yUcmh=g{*Sq0}~D*IVg}-QhZM zSt+tcCH6HCIwpnOzd>6z)KaZPflyOwl_g-TO)E=LRqDW4{R;}08JQVie5HAgL!Qb} zOL$ib!{#?ua8ii+9YItn*73Qs?trqb*f#*%xpDG9+lUq1#8XSTd^>v_9gI`#~2>dMxkbpFtWu5;g^g^mSgOg_qa2gfs; zS%DvV5m=7R$xz-?3w9=d<+mbs(%ypU%-sd$`JH@WFbHp~I$&V+lONU!&9F!}S>usT zLeA0Vk6hf!+*Z7mdAN8pkFE(mFw=r18OeQ>6aL|P va^}=IXq(Ngg|xkFx+mxaF@=%i0x_ErqOP*4$#*;;&R6qK4_W3BAj9|rpEwvw delta 925 zcmZvYZAesU6vxlGcXaNZap;bw>yPTuIm6JL+WiHuP$=FSKhQO)o;* z##ZYtt5g(w)(;CCAr%!QC0B`rVJh-dL|78`GO@6QE=%lPaGg~qZ|9QHmp=Ud=XnnQ zbI$Xe7u&MiPJfJT1GN#v4(i0?xSde&vj&6)*GLwO_-rByU{jw_hd_8hN3l|rep~|5 zVF6UC%UxO6nF3IT@*2T-l(lKy13#!>{6#&vfymgfl7!TGHc9}hGUQn8VApsy)P3#m zh6T>2$j&>nRX0kzQMEO#hvcME2gVsn=LVvehLuuVlgN%e!;m_`Jx(*fGWH=evtSNF zty4!oQJR1-q%FzHcY5 zG-YF#5Nn+}wD0}ha`y6Wt$2}6%AVi=-=-O92#mt4*eu3`^1PIy6>Cz`$`8!{lO7=NLH{5Y=D+w-eM9H(=ICow=PiheGOctI*-+(pcMoZ<6^;4w-b=w|wDcp4T@&^IMKR4Bhmt#a`X*e<k-{uGZ+o~E2LA=c|5gpV~J?p+eWoEA=Pp?G+iyVe2H UDkkjY{WJB{8?M1LjfM-}0AbG{ApigX diff --git a/test-devices/loopback-stm32/src/board.h b/test-devices/loopback-stm32/src/board.h index 4e032fd4..8d073409 100644 --- a/test-devices/loopback-stm32/src/board.h +++ b/test-devices/loopback-stm32/src/board.h @@ -28,6 +28,9 @@ void board_led_write(bool on); // Return the number of milliseconds since a time in the past uint32_t board_millis(void); +// Enter sleep or stop mode and wake up on USB resume +void board_sleep(void); + // USB serial number extern char board_serial_num[13]; diff --git a/test-devices/loopback-stm32/src/board_f1.c b/test-devices/loopback-stm32/src/board_f1.c index ac547f68..d0690d88 100644 --- a/test-devices/loopback-stm32/src/board_f1.c +++ b/test-devices/loopback-stm32/src/board_f1.c @@ -15,6 +15,8 @@ #include "stm32f1xx.h" #include "device/usbd.h" +#define EXTI_USBWakeUp_Line EXTI_IMR_IM18 + extern uint32_t SystemCoreClock; void SystemCoreClockUpdate(void); @@ -180,6 +182,12 @@ void board_init(void) { gpio_set_mode(GPIOB, 12, GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSH_PULL); usb_init_serial_num(); + + // Wake up event is only available as interrupt, not as an event. + // See product errata sheet + set_reg(&EXTI->RTSR, EXTI_USBWakeUp_Line, EXTI_USBWakeUp_Line); + set_reg(&EXTI->IMR, EXTI_USBWakeUp_Line, EXTI_USBWakeUp_Line); + NVIC_EnableIRQ(USBWakeUp_IRQn); } uint32_t board_millis(void) { @@ -188,9 +196,38 @@ uint32_t board_millis(void) { void board_led_write(bool on) { if (on) - gpio_set(GPIOB, 12); - else gpio_clear(GPIOB, 12); + else + gpio_set(GPIOB, 12); +} + +void board_sleep(void) { + + // turn off LED + board_led_write(false); + + // pause systick interrupts + set_reg(&SysTick->CTRL, 0, SysTick_CTRL_TICKINT_Msk); + + // enter Stop mode when the CPU enters deep sleep + set_reg(&PWR->CR, 0, PWR_CR_PDDS_Msk | PWR_CR_LPDS_Msk); + + set_reg(&SCB->SCR, SCB_SCR_SLEEPDEEP_Msk, SCB_SCR_SLEEPDEEP_Msk); + + // sleep until an interrupt occurs + __WFI(); + + // reset SLEEPDEEP bit + set_reg(&SCB->SCR, 0, SCB_SCR_SLEEPDEEP_Msk); + + // after wakeup, re-enable PLL as clock source + rcc_clock_setup_in_hse_8mhz_out_72mhz(); + + // resume systick interrupts + set_reg(&SysTick->CTRL, SysTick_CTRL_TICKINT_Msk, SysTick_CTRL_TICKINT_Msk); + + // turn on LED + board_led_write(true); } @@ -201,7 +238,8 @@ void SysTick_Handler (void) { } void USBWakeUp_IRQHandler(void) { - tud_int_handler(0); + // clear interrupt + EXTI->PR = EXTI_USBWakeUp_Line; } void USB_HP_IRQHandler(void) { diff --git a/test-devices/loopback-stm32/src/board_f4.c b/test-devices/loopback-stm32/src/board_f4.c index 4499e8c9..687b5171 100644 --- a/test-devices/loopback-stm32/src/board_f4.c +++ b/test-devices/loopback-stm32/src/board_f4.c @@ -15,6 +15,9 @@ #include "stm32f4xx.h" #include "device/usbd.h" +#define EXTI_USBWakeUp_Line EXTI_IMR_IM18 + + extern uint32_t SystemCoreClock; void SystemCoreClockUpdate(void); @@ -59,7 +62,7 @@ const rcc_clock_setup_t clock_setup_hse_value_out_84mhz_3v3 = { .hpre = RCC_CFGR_HPRE_DIV1, .ppre1 = RCC_CFGR_PPRE1_DIV2, .ppre2 = RCC_CFGR_PPRE2_DIV1, - .voltage_scale = PWR_CR_VOS_SCALE1, + .voltage_scale = PWR_CR_VOS_SCALE2, .flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_2WS }; @@ -85,6 +88,11 @@ const rcc_clock_setup_t clock_setup_hse_value_out_84mhz_3v3 = { #define GPIO_OSPEED_HIGH 3 +// --- additional USB register +#define PCGCCTL ((volatile uint32_t *)((uint32_t)USB_OTG_FS + USB_OTG_PCGCCTL_BASE)) + + + static inline void rcc_wait_for_osc_ready(uint32_t rcc_cr_clk_rdy) { while (get_reg(&RCC->CR, rcc_cr_clk_rdy) == 0) ; @@ -254,6 +262,13 @@ void board_init(void) { gpio_mode_setup(GPIOC, 13, GPIO_MODE_OUTPUT, GPIO_PUPD_NO_PULL); usb_init_serial_num(); + + // enable USB wakeup interrupt + EXTI->PR = EXTI_USBWakeUp_Line; + EXTI->RTSR |= EXTI_USBWakeUp_Line; + EXTI->IMR |= EXTI_USBWakeUp_Line; + NVIC_SetPriority(OTG_FS_WKUP_IRQn, 0); + NVIC_EnableIRQ(OTG_FS_WKUP_IRQn); } uint32_t board_millis(void) { @@ -262,9 +277,44 @@ uint32_t board_millis(void) { void board_led_write(bool on) { if (on) - gpio_set(GPIOC, 13); - else gpio_clear(GPIOC, 13); + else + gpio_set(GPIOC, 13); +} + +void board_sleep(void) { + + // turn off LED + board_led_write(false); + + // stop PCLK to USB + set_reg(PCGCCTL, USB_OTG_PCGCCTL_STOPCLK, USB_OTG_PCGCCTL_STOPCLK_Msk); + + // pause systick interrupts + set_reg(&SysTick->CTRL, 0, SysTick_CTRL_TICKINT_Msk); + + // enter stop mode when the CPU enters deep sleep + set_reg(&PWR->CR, 0, PWR_CR_PDDS_Msk | PWR_CR_LPDS_Msk); + + // use deep sleep mode + set_reg(&SCB->SCR, SCB_SCR_SLEEPDEEP_Msk, SCB_SCR_SLEEPDEEP_Msk); + + __WFI(); + + // reset to regular sleep mode + set_reg(&SCB->SCR, 0, SCB_SCR_SLEEPDEEP_Msk); + + // after wakeup, re-enable PLL as clock source + rcc_clock_setup_pll(&clock_setup_hse_value_out_84mhz_3v3); + + // resume systick interrupts + set_reg(&SysTick->CTRL, SysTick_CTRL_TICKINT_Msk, SysTick_CTRL_TICKINT_Msk); + + // restart PCLK to USB + set_reg(PCGCCTL, 0, USB_OTG_PCGCCTL_STOPCLK_Msk); + + // turn on LED + board_led_write(true); } @@ -278,4 +328,9 @@ void OTG_FS_IRQHandler(void) { tud_int_handler(0); } +void OTG_FS_WKUP_IRQHandler(void) { + // clear interrupt + EXTI->PR = EXTI_USBWakeUp_Line; +} + #endif diff --git a/test-devices/loopback-stm32/src/board_f7.c b/test-devices/loopback-stm32/src/board_f7.c index bdff30b4..34d40bf5 100644 --- a/test-devices/loopback-stm32/src/board_f7.c +++ b/test-devices/loopback-stm32/src/board_f7.c @@ -284,6 +284,10 @@ void board_init(void) { usb_init_serial_num(); } +void board_sleep(void) { + // not implemented yet +} + uint32_t board_millis(void) { return millis_count; } diff --git a/test-devices/loopback-stm32/src/main.c b/test-devices/loopback-stm32/src/main.c index 31d9ccad..6e75657c 100644 --- a/test-devices/loopback-stm32/src/main.c +++ b/test-devices/loopback-stm32/src/main.c @@ -42,7 +42,6 @@ int num_echos; enum { BLINK_NOT_MOUNTED = 250, BLINK_MOUNTED = 1000, - BLINK_SUSPENDED = 2500, }; static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; @@ -288,12 +287,7 @@ void tud_umount_cb(void) { // Within 7ms, device must draw an average of current less than 2.5 mA from bus void tud_suspend_cb(bool remote_wakeup_en) { (void) remote_wakeup_en; - blink_interval_ms = BLINK_SUSPENDED; -} - -// Invoked when usb bus is resumed -void tud_resume_cb(void) { - blink_interval_ms = BLINK_MOUNTED; + board_sleep(); } @@ -305,7 +299,7 @@ void led_blinking_task(void) { // Blink every interval ms if ( board_millis() - start_ms < blink_interval_ms) - return; // not enough time + return; // interval not elapsed yet start_ms += blink_interval_ms; board_led_write(led_state); diff --git a/test-devices/loopback-stm32/src/usb_descriptors.c b/test-devices/loopback-stm32/src/usb_descriptors.c index 49893982..9aa5028e 100644 --- a/test-devices/loopback-stm32/src/usb_descriptors.c +++ b/test-devices/loopback-stm32/src/usb_descriptors.c @@ -57,7 +57,7 @@ enum { uint8_t const desc_fs_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA - TUD_CONFIG_DESCRIPTOR(1, INTF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 500), + TUD_CONFIG_DESCRIPTOR(1, INTF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x80, 500), // Loopback interface (alternate 0) CUSTOM_VENDOR_INTERFACE(0, 4), // Loopback endpoint OUT From ac833312ed9079e40d785247051de6fc18cc09a5 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 16 Mar 2024 10:29:22 +0100 Subject: [PATCH 343/433] Loopback test device: update README --- test-devices/loopback-stm32/README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test-devices/loopback-stm32/README.md b/test-devices/loopback-stm32/README.md index b485a64d..75e28b80 100644 --- a/test-devices/loopback-stm32/README.md +++ b/test-devices/loopback-stm32/README.md @@ -7,8 +7,9 @@ For testing the *Java Does USB* library, a dedicated USB test device is needed. - BlackPill with STM32F401CC microcontroller - BlackPill with STM32F411CE microcontroller - BluePill with STM32F103C8 microcontroller +- STM32F723 Discovery board -To upload the firmware, the STM32F4x microcontroller have a built-in USB bootloader. The STM32F1x microcontrollers need an ST-Link debug adapter (or a USB-to-serial converter). +To upload the firmware, the STM32F4x microcontroller have a built-in USB bootloader. The STM32F1x microcontrollers need an ST-Link debug adapter (or a USB-to-serial converter). The STM32F723 Discovery board has a built-in ST-Link programmer. ## Test features @@ -45,6 +46,13 @@ Two alternate interfaces are implemented: - Alternate 1: only the control endpoint and the bulk endpoints (0x01 and 0x82) are available +### Suspend / resume + +The device can be put into suspend mode by the host. It will go into a low-power mode. This is indicated by the user LED turning off. The power LED will stay on. The device can be woken up by the host. + +A MacBook with macOS usually puts the device into suspend mode about 1 minuate after is has gone to sleep if it is not connected to a power supply. The device will wake up when the MacBook is woken up. + + ## Building the firmware This project requires [PlatformIO](https://platformio.org/). The easiest way to get up and running is to use Visual Studio Code and then install the [PlatformIO IDE extension](https://marketplace.visualstudio.com/items?itemName=platformio.platformio-ide). @@ -69,6 +77,7 @@ The directory `bin` contains a pre-built firmware: - `blackpill-f401cc.bin`: Firmware for BlackPill with STM32F401CC microcontroller - `blackpill-f411ce.bin`: Firmware for BlackPill with STM32F411CE microcontroller - `bluepill-f103c8.bin`: Firmware for BluePill with STM32F103C8 microcontroller +- `disco_f723ie.bin`: Firmware for STM32F723 Discovery board ### Upload using built-in bootloader From a3c18bc1c4e480bb6e81cac6ee5a28262238aa3f Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 16 Mar 2024 10:52:37 +0100 Subject: [PATCH 344/433] Test program: log output --- .../test/java/net/codecrete/usb/special/Continuous.java | 8 ++++++-- test-devices/loopback-stm32/README.md | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/Continuous.java b/java-does-usb/src/test/java/net/codecrete/usb/special/Continuous.java index 1df4bcf1..820637d3 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/Continuous.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/Continuous.java @@ -5,6 +5,8 @@ import net.codecrete.usb.UsbException; import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.Random; public class Continuous { @@ -30,7 +32,7 @@ public static void main(String[] args) throws IOException { @SuppressWarnings({"java:S2925", "BusyWait"}) private static void sendData(UsbDevice device) { var random = new Random(); - var buffer = new byte[80]; + var buffer = new byte[40]; while (true) { random.nextBytes(buffer); @@ -46,9 +48,11 @@ private static void sendData(UsbDevice device) { } private static void readData(UsbDevice device) { + var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); while (true) { try { - device.transferIn(2); + var packet = device.transferIn(2); + System.out.printf("%s packet of %d bytes received\n", LocalDateTime.now().format(formatter), packet.length); } catch (UsbException e) { return; } diff --git a/test-devices/loopback-stm32/README.md b/test-devices/loopback-stm32/README.md index 75e28b80..14767c56 100644 --- a/test-devices/loopback-stm32/README.md +++ b/test-devices/loopback-stm32/README.md @@ -52,6 +52,8 @@ The device can be put into suspend mode by the host. It will go into a low-power A MacBook with macOS usually puts the device into suspend mode about 1 minuate after is has gone to sleep if it is not connected to a power supply. The device will wake up when the MacBook is woken up. +On Windows, the device is put to sleep immediately when the Windows computer is put to sleep. + ## Building the firmware From fc36c352aeb58efeb866055fd25395a579043a9c Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 16 Mar 2024 12:49:03 +0100 Subject: [PATCH 345/433] Linux: improve resume handling --- .../codecrete/usb/linux/LinuxAsyncTask.java | 5 +- .../usb/linux/LinuxUsbDeviceRegistry.java | 57 ++++++++++++------- .../net/codecrete/usb/special/Continuous.java | 2 +- test-devices/loopback-stm32/README.md | 2 +- 4 files changed, 40 insertions(+), 26 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index c72221d2..13553907 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -32,7 +32,7 @@ import static net.codecrete.usb.linux.gen.epoll.epoll.EPOLLOUT; import static net.codecrete.usb.linux.gen.epoll.epoll.EPOLLWAKEUP; import static net.codecrete.usb.linux.gen.errno.errno.EINTR; -import static net.codecrete.usb.linux.gen.errno.errno.ENOENT; +import static net.codecrete.usb.linux.gen.errno.errno.ENODEV; import static net.codecrete.usb.linux.gen.fcntl.fcntl.FD_CLOEXEC; import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.USBDEVFS_URB_TYPE_BULK; import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.USBDEVFS_URB_TYPE_CONTROL; @@ -174,8 +174,9 @@ synchronized void removeFromAsyncIOCompletion(LinuxUsbDevice device) { if (isMatch) { var transfer = e.getValue(); transfer.urb = null; - transfer.setResultCode(ENOENT()); + transfer.setResultCode(ENODEV()); transfer.setResultSize(0); + transfer.completion().completed(transfer); availableURBs.add(urb); } return isMatch; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java index fa3fd8ba..72aeb5f6 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java @@ -19,12 +19,14 @@ import java.util.List; import static java.lang.System.Logger.Level.INFO; +import static java.lang.foreign.MemorySegment.NULL; import static net.codecrete.usb.linux.EPoll.epoll_create1; import static net.codecrete.usb.linux.EPoll.epoll_wait; import static net.codecrete.usb.linux.Linux.allocateErrorState; import static net.codecrete.usb.linux.LinuxUsbException.throwException; import static net.codecrete.usb.linux.LinuxUsbException.throwLastError; import static net.codecrete.usb.linux.gen.epoll.epoll.EPOLLIN; +import static net.codecrete.usb.linux.gen.errno.errno.EINTR; import static net.codecrete.usb.linux.gen.fcntl.fcntl.FD_CLOEXEC; /** @@ -44,6 +46,9 @@ public class LinuxUsbDeviceRegistry extends UsbDeviceRegistry { private static final MemorySegment ATTR_PRODUCT; private static final MemorySegment ATTR_SERIAL; + private MemorySegment monitor; + private int monitorFd; + static { var global = Arena.global(); @@ -58,13 +63,8 @@ public class LinuxUsbDeviceRegistry extends UsbDeviceRegistry { ATTR_SERIAL = global.allocateFrom("serial"); } - @SuppressWarnings({"java:S1181", "java:S2189"}) - @Override - protected void monitorDevices() { - - int fd; - MemorySegment monitor; - + @SuppressWarnings("java:S1181") + private boolean setupMonitor() { try { // setup udev monitor var udevInstance = udev.udev_new(); @@ -81,18 +81,26 @@ protected void monitorDevices() { if (udev.udev_monitor_enable_receiving(monitor) < 0) throwException("internal error (udev_monitor_enable_receiving)"); - fd = udev.udev_monitor_get_fd(monitor); - if (fd < 0) + monitorFd = udev.udev_monitor_get_fd(monitor); + if (monitorFd < 0) throwException("internal error (udev_monitor_get_fd)"); // create initial list of devices var deviceList = enumeratePresentDevices(udevInstance); setInitialDeviceList(deviceList); + return true; } catch (Throwable e) { enumerationFailed(e); - return; + return false; } + } + + @SuppressWarnings("java:S2189") + @Override + protected void monitorDevices() { + if (!setupMonitor()) + return; try (var arena = Arena.ofConfined()) { // create epoll @@ -100,7 +108,7 @@ protected void monitorDevices() { var epfd = epoll_create1(FD_CLOEXEC(), errorState); if (epfd < 0) throwLastError(errorState, "internal error (epoll_create)"); - EPoll.addFileDescriptor(epfd, EPOLLIN(), fd); + EPoll.addFileDescriptor(epfd, EPOLLIN(), monitorFd); // allocate event (as output for epoll_wait) var event = arena.allocate(epoll_event.layout()); @@ -111,22 +119,27 @@ protected void monitorDevices() { try (var cleanup = new ScopeCleanup()) { // wait for next change - epoll_wait(epfd, event, 1, -1, errorState); + int res = epoll_wait(epfd, event, 1, -1, errorState); + if (res < 0) { + var err = Linux.getErrno(errorState); + if (err == EINTR()) + continue; // continue on interrupt + throwException(err, "internal error (epoll_wait)"); + } // retrieve change var udevDevice = udev.udev_monitor_receive_device(monitor); - if (udevDevice == null) - continue; // shouldn't happen - - cleanup.add(() -> udev.udev_device_unref(udevDevice)); + if (udevDevice != NULL) { + cleanup.add(() -> udev.udev_device_unref(udevDevice)); - // get details - var action = getDeviceAction(udevDevice); + // get details + var action = getDeviceAction(udevDevice); - if ("add".equals(action)) { - onDeviceConnected(udevDevice); - } else if ("remove".equals(action)) { - onDeviceDisconnected(udevDevice); + if ("add".equals(action)) { + onDeviceConnected(udevDevice); + } else if ("remove".equals(action)) { + onDeviceDisconnected(udevDevice); + } } } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/Continuous.java b/java-does-usb/src/test/java/net/codecrete/usb/special/Continuous.java index 820637d3..d9c6ad44 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/Continuous.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/Continuous.java @@ -24,7 +24,7 @@ public static void main(String[] args) throws IOException { new Thread(() -> readData(device)).start(); new Thread(() -> sendData(device)).start(); - System.out.println("Press Enter to exit"); + System.out.println("Press RETURN to exit"); System.in.read(); device.close(); } diff --git a/test-devices/loopback-stm32/README.md b/test-devices/loopback-stm32/README.md index 14767c56..9ed5ce56 100644 --- a/test-devices/loopback-stm32/README.md +++ b/test-devices/loopback-stm32/README.md @@ -52,7 +52,7 @@ The device can be put into suspend mode by the host. It will go into a low-power A MacBook with macOS usually puts the device into suspend mode about 1 minuate after is has gone to sleep if it is not connected to a power supply. The device will wake up when the MacBook is woken up. -On Windows, the device is put to sleep immediately when the Windows computer is put to sleep. +On Windows and Linux, the device is put to sleep immediately when the computer is put to sleep or suspended. ## Building the firmware From a33e1695006bfc8dbffcc4a0d4453cd06843a371 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 16 Mar 2024 19:58:20 +0100 Subject: [PATCH 346/433] Linux: latest jextract --- .../codecrete/usb/linux/gen/udev/udev.java | 6 +- .../linux/gen/usbdevice_fs/usbdevfs_urb.java | 88 ------------------- 2 files changed, 3 insertions(+), 91 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java index 937cf781..be48336d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java @@ -82,7 +82,7 @@ private static class udev_new { /** * Function descriptor for: * {@snippet lang=c : - * struct udev *udev_new() + * struct udev *udev_new(void) * } */ public static FunctionDescriptor udev_new$descriptor() { @@ -92,7 +92,7 @@ private static class udev_new { /** * Downcall method handle for: * {@snippet lang=c : - * struct udev *udev_new() + * struct udev *udev_new(void) * } */ public static MethodHandle udev_new$handle() { @@ -100,7 +100,7 @@ private static class udev_new { } /** * {@snippet lang=c : - * struct udev *udev_new() + * struct udev *udev_new(void) * } */ public static MemorySegment udev_new() { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java index 6165e167..dff5ddb5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java @@ -420,94 +420,6 @@ public static void start_frame(MemorySegment struct, int fieldValue) { struct.set(start_frame$LAYOUT, start_frame$OFFSET, fieldValue); } - private static final OfInt number_of_packets$LAYOUT = (OfInt)$LAYOUT.select(groupElement("$anon$126:2"), groupElement("number_of_packets")); - - /** - * Layout for field: - * {@snippet lang=c : - * int number_of_packets - * } - */ - public static final OfInt number_of_packets$layout() { - return number_of_packets$LAYOUT; - } - - private static final long number_of_packets$OFFSET = 36; - - /** - * Offset for field: - * {@snippet lang=c : - * int number_of_packets - * } - */ - public static final long number_of_packets$offset() { - return number_of_packets$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * int number_of_packets - * } - */ - public static int number_of_packets(MemorySegment struct) { - return struct.get(number_of_packets$LAYOUT, number_of_packets$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * int number_of_packets - * } - */ - public static void number_of_packets(MemorySegment struct, int fieldValue) { - struct.set(number_of_packets$LAYOUT, number_of_packets$OFFSET, fieldValue); - } - - private static final OfInt stream_id$LAYOUT = (OfInt)$LAYOUT.select(groupElement("$anon$126:2"), groupElement("stream_id")); - - /** - * Layout for field: - * {@snippet lang=c : - * unsigned int stream_id - * } - */ - public static final OfInt stream_id$layout() { - return stream_id$LAYOUT; - } - - private static final long stream_id$OFFSET = 36; - - /** - * Offset for field: - * {@snippet lang=c : - * unsigned int stream_id - * } - */ - public static final long stream_id$offset() { - return stream_id$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * unsigned int stream_id - * } - */ - public static int stream_id(MemorySegment struct) { - return struct.get(stream_id$LAYOUT, stream_id$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * unsigned int stream_id - * } - */ - public static void stream_id(MemorySegment struct, int fieldValue) { - struct.set(stream_id$LAYOUT, stream_id$OFFSET, fieldValue); - } - private static final OfInt error_count$LAYOUT = (OfInt)$LAYOUT.select(groupElement("error_count")); /** From f4ef64e30b6a8ed815d8ecf188776729eb2a94da Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 16 Mar 2024 20:07:32 +0100 Subject: [PATCH 347/433] Linux: latest jextract (2) --- .../codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java index dff5ddb5..8649bc81 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java @@ -51,10 +51,7 @@ public class usbdevfs_urb { usbdevice_fs.C_INT.withName("buffer_length"), usbdevice_fs.C_INT.withName("actual_length"), usbdevice_fs.C_INT.withName("start_frame"), - MemoryLayout.unionLayout( - usbdevice_fs.C_INT.withName("number_of_packets"), - usbdevice_fs.C_INT.withName("stream_id") - ).withName("$anon$126:2"), + MemoryLayout.paddingLayout(4), usbdevice_fs.C_INT.withName("error_count"), usbdevice_fs.C_INT.withName("signr"), usbdevice_fs.C_POINTER.withName("usercontext"), From ae9f7e2ce1c37be14ddc7f604fe5cacdb2dfd821 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 16 Mar 2024 20:50:40 +0100 Subject: [PATCH 348/433] Linux ARM64: fix incompatibility with epoll --- java-does-usb/jextract/linux/gen_linux.sh | 4 +- .../java/net/codecrete/usb/linux/EPoll.java | 44 ++- .../codecrete/usb/linux/LinuxAsyncTask.java | 3 +- .../usb/linux/LinuxUsbDeviceRegistry.java | 3 +- .../usb/linux/gen/epoll/epoll_data.java | 265 ------------------ .../usb/linux/gen/epoll/epoll_event.java | 173 ------------ .../linux/gen/usbdevice_fs/usbdevfs_urb.java | 47 +--- 7 files changed, 44 insertions(+), 495 deletions(-) delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_data.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index 3b20567c..99ebe244 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -1,6 +1,6 @@ #!/bin/sh -JEXTRACT=../../../../jextract/bin/jextract +JEXTRACT=../../../../jextract/build/jextract/bin/jextract rm -rf ../../src/main/java/net/codecrete/usb/linux/gen @@ -89,8 +89,6 @@ $JEXTRACT --output ../../src/main/java \ $JEXTRACT --output ../../src/main/java \ --header-class-name epoll \ --target-package net.codecrete.usb.linux.gen.epoll \ - --include-struct epoll_event \ - --include-union epoll_data \ --include-constant EPOLL_CTL_ADD \ --include-constant EPOLL_CTL_DEL \ --include-constant EPOLLIN \ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java index 9470d926..3a7ff751 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java @@ -7,20 +7,25 @@ package net.codecrete.usb.linux; -import net.codecrete.usb.linux.gen.epoll.epoll_event; import net.codecrete.usb.linux.gen.errno.errno; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SequenceLayout; +import java.lang.foreign.MemoryLayout.PathElement; +import java.lang.foreign.ValueLayout.OfInt; import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.ADDRESS_UNALIGNED; import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_INT_UNALIGNED; +import static java.lang.foreign.ValueLayout.JAVA_LONG_UNALIGNED; import static net.codecrete.usb.linux.Linux.allocateErrorState; import static net.codecrete.usb.linux.LinuxUsbException.throwLastError; import static net.codecrete.usb.linux.gen.epoll.epoll.EPOLL_CTL_ADD; @@ -28,8 +33,28 @@ @SuppressWarnings({"OptionalGetWithoutIsPresent", "SameParameterValue", "java:S100"}) public class EPoll { + private EPoll() {} + + private static final boolean IS_AARCH64 = System.getProperty("os.arch").equals("aarch64"); + + private static final GroupLayout DATA$LAYOUT = MemoryLayout.unionLayout( + ADDRESS_UNALIGNED.withName("ptr"), + JAVA_INT_UNALIGNED.withName("fd"), + JAVA_INT_UNALIGNED.withName("u32"), + JAVA_LONG_UNALIGNED.withName("u64") + ).withName("epoll_data"); + + static final GroupLayout EVENT$LAYOUT = IS_AARCH64 + ? MemoryLayout.structLayout( + JAVA_INT.withName("events"), + MemoryLayout.paddingLayout(4), + DATA$LAYOUT.withName("data")).withName("epoll_event") + : MemoryLayout.structLayout( + JAVA_INT_UNALIGNED.withName("events"), + DATA$LAYOUT.withName("data")).withName("epoll_event"); + // Memory layout for an array of epoll_event structs - private static final SequenceLayout EVENT_ARRAY$LAYOUT = MemoryLayout.sequenceLayout(1, epoll_event.layout()); + private static final SequenceLayout EVENT_ARRAY$LAYOUT = MemoryLayout.sequenceLayout(1, EVENT$LAYOUT); // varhandle to access the "fd" field in an array of epoll_event structs static final VarHandle EVENT_ARRAY_DATA_FD$VH = EVENT_ARRAY$LAYOUT.varHandle( @@ -39,13 +64,16 @@ public class EPoll { ); // varhandle to access the "fd" field in an epoll_event struct - static final VarHandle EVENT_DATA_FD$VH = epoll_event.layout().varHandle( + static final VarHandle EVENT_DATA_FD$VH = EVENT$LAYOUT.varHandle( MemoryLayout.PathElement.groupElement("data"), MemoryLayout.PathElement.groupElement("fd") ); + private static final OfInt EVENT_EVENTS$LAYOUT = (OfInt)EVENT$LAYOUT.select(PathElement.groupElement("events")); - private EPoll() {} + private static void event_events(MemorySegment struct, int fieldValue) { + struct.set(EVENT_EVENTS$LAYOUT, 0, fieldValue); + } private static final Linker linker = Linker.nativeLinker(); @@ -89,8 +117,8 @@ static void addFileDescriptor(int epfd, int op, int fd) { try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); - var event = arena.allocate(epoll_event.layout()); - epoll_event.events(event, op); + var event = arena.allocate(EVENT$LAYOUT); + event_events(event, op); EVENT_DATA_FD$VH.set(event, 0, fd); var ret = epoll_ctl(epfd, EPOLL_CTL_ADD(), fd, event, errorState); if (ret < 0) @@ -102,8 +130,8 @@ static void removeFileDescriptor(int epfd, int fd) { try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); - var event = arena.allocate(epoll_event.layout()); - epoll_event.events(event, 0); + var event = arena.allocate(EVENT$LAYOUT); + event_events(event, 0); EVENT_DATA_FD$VH.set(event, 0, fd); var ret = epoll_ctl(epfd, EPOLL_CTL_DEL(), fd, event, errorState); if (ret < 0) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index 13553907..1a33d164 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -8,7 +8,6 @@ package net.codecrete.usb.linux; import net.codecrete.usb.UsbTransferType; -import net.codecrete.usb.linux.gen.epoll.epoll_event; import net.codecrete.usb.linux.gen.errno.errno; import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_urb; @@ -84,7 +83,7 @@ private void asyncCompletionTask() { try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); var urbPointerHolder = arena.allocate(ADDRESS); - var events = arena.allocate(epoll_event.layout(), NUM_EVENTS); + var events = arena.allocate(EPoll.EVENT$LAYOUT, NUM_EVENTS); while (true) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java index 72aeb5f6..6c39abe9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java @@ -10,7 +10,6 @@ import net.codecrete.usb.UsbDevice; import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.common.UsbDeviceRegistry; -import net.codecrete.usb.linux.gen.epoll.epoll_event; import net.codecrete.usb.linux.gen.udev.udev; import java.lang.foreign.Arena; @@ -111,7 +110,7 @@ protected void monitorDevices() { EPoll.addFileDescriptor(epfd, EPOLLIN(), monitorFd); // allocate event (as output for epoll_wait) - var event = arena.allocate(epoll_event.layout()); + var event = arena.allocate(EPoll.EVENT$LAYOUT); // monitor device changes //noinspection InfiniteLoopStatement diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_data.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_data.java deleted file mode 100644 index 9bf1e677..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_data.java +++ /dev/null @@ -1,265 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.epoll; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * union epoll_data { - * void *ptr; - * int fd; - * uint32_t u32; - * uint64_t u64; - * } - * } - */ -public class epoll_data { - - epoll_data() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.unionLayout( - epoll.C_POINTER.withName("ptr"), - epoll.C_INT.withName("fd"), - epoll.C_INT.withName("u32"), - epoll.C_LONG.withName("u64") - ).withName("epoll_data"); - - /** - * The layout of this union - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final AddressLayout ptr$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("ptr")); - - /** - * Layout for field: - * {@snippet lang=c : - * void *ptr - * } - */ - public static final AddressLayout ptr$layout() { - return ptr$LAYOUT; - } - - private static final long ptr$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * void *ptr - * } - */ - public static final long ptr$offset() { - return ptr$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * void *ptr - * } - */ - public static MemorySegment ptr(MemorySegment union) { - return union.get(ptr$LAYOUT, ptr$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * void *ptr - * } - */ - public static void ptr(MemorySegment union, MemorySegment fieldValue) { - union.set(ptr$LAYOUT, ptr$OFFSET, fieldValue); - } - - private static final OfInt fd$LAYOUT = (OfInt)$LAYOUT.select(groupElement("fd")); - - /** - * Layout for field: - * {@snippet lang=c : - * int fd - * } - */ - public static final OfInt fd$layout() { - return fd$LAYOUT; - } - - private static final long fd$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * int fd - * } - */ - public static final long fd$offset() { - return fd$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * int fd - * } - */ - public static int fd(MemorySegment union) { - return union.get(fd$LAYOUT, fd$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * int fd - * } - */ - public static void fd(MemorySegment union, int fieldValue) { - union.set(fd$LAYOUT, fd$OFFSET, fieldValue); - } - - private static final OfInt u32$LAYOUT = (OfInt)$LAYOUT.select(groupElement("u32")); - - /** - * Layout for field: - * {@snippet lang=c : - * uint32_t u32 - * } - */ - public static final OfInt u32$layout() { - return u32$LAYOUT; - } - - private static final long u32$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * uint32_t u32 - * } - */ - public static final long u32$offset() { - return u32$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * uint32_t u32 - * } - */ - public static int u32(MemorySegment union) { - return union.get(u32$LAYOUT, u32$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * uint32_t u32 - * } - */ - public static void u32(MemorySegment union, int fieldValue) { - union.set(u32$LAYOUT, u32$OFFSET, fieldValue); - } - - private static final OfLong u64$LAYOUT = (OfLong)$LAYOUT.select(groupElement("u64")); - - /** - * Layout for field: - * {@snippet lang=c : - * uint64_t u64 - * } - */ - public static final OfLong u64$layout() { - return u64$LAYOUT; - } - - private static final long u64$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * uint64_t u64 - * } - */ - public static final long u64$offset() { - return u64$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * uint64_t u64 - * } - */ - public static long u64(MemorySegment union) { - return union.get(u64$LAYOUT, u64$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * uint64_t u64 - * } - */ - public static void u64(MemorySegment union, long fieldValue) { - union.set(u64$LAYOUT, u64$OFFSET, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this union - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java deleted file mode 100644 index c6348dd2..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java +++ /dev/null @@ -1,173 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.epoll; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct epoll_event { - * uint32_t events; - * epoll_data_t data; - * } - * } - */ -public class epoll_event { - - epoll_event() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - epoll.align(epoll.C_INT, 1).withName("events"), - epoll.align(epoll_data.layout(), 1).withName("data") - ).withName("epoll_event"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final OfInt events$LAYOUT = (OfInt)$LAYOUT.select(groupElement("events")); - - /** - * Layout for field: - * {@snippet lang=c : - * uint32_t events - * } - */ - public static final OfInt events$layout() { - return events$LAYOUT; - } - - private static final long events$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * uint32_t events - * } - */ - public static final long events$offset() { - return events$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * uint32_t events - * } - */ - public static int events(MemorySegment struct) { - return struct.get(events$LAYOUT, events$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * uint32_t events - * } - */ - public static void events(MemorySegment struct, int fieldValue) { - struct.set(events$LAYOUT, events$OFFSET, fieldValue); - } - - private static final GroupLayout data$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("data")); - - /** - * Layout for field: - * {@snippet lang=c : - * epoll_data_t data - * } - */ - public static final GroupLayout data$layout() { - return data$LAYOUT; - } - - private static final long data$OFFSET = 4; - - /** - * Offset for field: - * {@snippet lang=c : - * epoll_data_t data - * } - */ - public static final long data$offset() { - return data$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * epoll_data_t data - * } - */ - public static MemorySegment data(MemorySegment struct) { - return struct.asSlice(data$OFFSET, data$LAYOUT.byteSize()); - } - - /** - * Setter for field: - * {@snippet lang=c : - * epoll_data_t data - * } - */ - public static void data(MemorySegment struct, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, struct, data$OFFSET, data$LAYOUT.byteSize()); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java index 8649bc81..648718b9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java @@ -30,7 +30,7 @@ * int error_count; * unsigned int signr; * void *usercontext; - * struct usbdevfs_iso_packet_desc iso_frame_desc[0]; + * struct usbdevfs_iso_packet_desc iso_frame_desc[]; * } * } */ @@ -554,7 +554,7 @@ public static void usercontext(MemorySegment struct, MemorySegment fieldValue) { /** * Layout for field: * {@snippet lang=c : - * struct usbdevfs_iso_packet_desc iso_frame_desc[0] + * struct usbdevfs_iso_packet_desc iso_frame_desc[] * } */ public static final SequenceLayout iso_frame_desc$layout() { @@ -566,7 +566,7 @@ public static void usercontext(MemorySegment struct, MemorySegment fieldValue) { /** * Offset for field: * {@snippet lang=c : - * struct usbdevfs_iso_packet_desc iso_frame_desc[0] + * struct usbdevfs_iso_packet_desc iso_frame_desc[] * } */ public static final long iso_frame_desc$offset() { @@ -576,7 +576,7 @@ public static void usercontext(MemorySegment struct, MemorySegment fieldValue) { /** * Getter for field: * {@snippet lang=c : - * struct usbdevfs_iso_packet_desc iso_frame_desc[0] + * struct usbdevfs_iso_packet_desc iso_frame_desc[] * } */ public static MemorySegment iso_frame_desc(MemorySegment struct) { @@ -586,50 +586,13 @@ public static MemorySegment iso_frame_desc(MemorySegment struct) { /** * Setter for field: * {@snippet lang=c : - * struct usbdevfs_iso_packet_desc iso_frame_desc[0] + * struct usbdevfs_iso_packet_desc iso_frame_desc[] * } */ public static void iso_frame_desc(MemorySegment struct, MemorySegment fieldValue) { MemorySegment.copy(fieldValue, 0L, struct, iso_frame_desc$OFFSET, iso_frame_desc$LAYOUT.byteSize()); } - private static long[] iso_frame_desc$DIMS = { 0 }; - - /** - * Dimensions for array field: - * {@snippet lang=c : - * struct usbdevfs_iso_packet_desc iso_frame_desc[0] - * } - */ - public static long[] iso_frame_desc$dimensions() { - return iso_frame_desc$DIMS; - } - private static final MethodHandle iso_frame_desc$ELEM_HANDLE = iso_frame_desc$LAYOUT.sliceHandle(sequenceElement()); - - /** - * Indexed getter for field: - * {@snippet lang=c : - * struct usbdevfs_iso_packet_desc iso_frame_desc[0] - * } - */ - public static MemorySegment iso_frame_desc(MemorySegment struct, long index0) { - try { - return (MemorySegment)iso_frame_desc$ELEM_HANDLE.invokeExact(struct, 0L, index0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - /** - * Indexed setter for field: - * {@snippet lang=c : - * struct usbdevfs_iso_packet_desc iso_frame_desc[0] - * } - */ - public static void iso_frame_desc(MemorySegment struct, long index0, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, iso_frame_desc(struct, index0), 0L, usbdevfs_iso_packet_desc.layout().byteSize()); - } - /** * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} From ac4dfb2e1f3b9441fd5a49ce9de2f444431e8f06 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 16 Mar 2024 21:04:45 +0100 Subject: [PATCH 349/433] Minor cleanup --- .../java/net/codecrete/usb/linux/EPoll.java | 18 +++++++----------- .../codecrete/usb/macos/MacosAsyncTask.java | 5 ++++- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java index 3a7ff751..e644dd47 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java @@ -16,8 +16,6 @@ import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.SequenceLayout; -import java.lang.foreign.MemoryLayout.PathElement; -import java.lang.foreign.ValueLayout.OfInt; import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; @@ -31,7 +29,7 @@ import static net.codecrete.usb.linux.gen.epoll.epoll.EPOLL_CTL_ADD; import static net.codecrete.usb.linux.gen.epoll.epoll.EPOLL_CTL_DEL; -@SuppressWarnings({"OptionalGetWithoutIsPresent", "SameParameterValue", "java:S100"}) +@SuppressWarnings({"OptionalGetWithoutIsPresent", "SameParameterValue", "java:S100", "java:S1192"}) public class EPoll { private EPoll() {} @@ -64,16 +62,14 @@ private EPoll() {} ); // varhandle to access the "fd" field in an epoll_event struct - static final VarHandle EVENT_DATA_FD$VH = EVENT$LAYOUT.varHandle( + private static final VarHandle EVENT_DATA_FD$VH = EVENT$LAYOUT.varHandle( MemoryLayout.PathElement.groupElement("data"), MemoryLayout.PathElement.groupElement("fd") ); - private static final OfInt EVENT_EVENTS$LAYOUT = (OfInt)EVENT$LAYOUT.select(PathElement.groupElement("events")); - - private static void event_events(MemorySegment struct, int fieldValue) { - struct.set(EVENT_EVENTS$LAYOUT, 0, fieldValue); - } + private static final VarHandle EVENTS$VH = EVENT$LAYOUT.varHandle( + MemoryLayout.PathElement.groupElement("events") + ); private static final Linker linker = Linker.nativeLinker(); @@ -118,7 +114,7 @@ static void addFileDescriptor(int epfd, int op, int fd) { var errorState = allocateErrorState(arena); var event = arena.allocate(EVENT$LAYOUT); - event_events(event, op); + EVENTS$VH.set(event, 0, op); EVENT_DATA_FD$VH.set(event, 0, fd); var ret = epoll_ctl(epfd, EPOLL_CTL_ADD(), fd, event, errorState); if (ret < 0) @@ -131,7 +127,7 @@ static void removeFileDescriptor(int epfd, int fd) { var errorState = allocateErrorState(arena); var event = arena.allocate(EVENT$LAYOUT); - event_events(event, 0); + EVENTS$VH.set(event, 0, 0); EVENT_DATA_FD$VH.set(event, 0, fd); var ret = epoll_ctl(epfd, EPOLL_CTL_DEL(), fd, event, errorState); if (ret < 0) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java index 65a1f923..ec0bd96d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java @@ -23,7 +23,10 @@ import java.util.concurrent.locks.ReentrantLock; import static java.lang.foreign.MemorySegment.NULL; -import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.JAVA_LONG_UNALIGNED; /** From 2939dfd3b8881aca51c078a2687e2018eca21f05 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 16 Mar 2024 23:52:16 +0100 Subject: [PATCH 350/433] Loopback test device: improved LED feedback --- test-devices/loopback-stm32/README.md | 3 +- test-devices/loopback-stm32/src/main.c | 63 ++++++++++++++++---------- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/test-devices/loopback-stm32/README.md b/test-devices/loopback-stm32/README.md index 9ed5ce56..60b70550 100644 --- a/test-devices/loopback-stm32/README.md +++ b/test-devices/loopback-stm32/README.md @@ -50,9 +50,8 @@ Two alternate interfaces are implemented: The device can be put into suspend mode by the host. It will go into a low-power mode. This is indicated by the user LED turning off. The power LED will stay on. The device can be woken up by the host. -A MacBook with macOS usually puts the device into suspend mode about 1 minuate after is has gone to sleep if it is not connected to a power supply. The device will wake up when the MacBook is woken up. +To put the device into suspended mode, put the host computer to sleep or supended mode. To wake it up, wake up the host computer. -On Windows and Linux, the device is put to sleep immediately when the computer is put to sleep or suspended. ## Building the firmware diff --git a/test-devices/loopback-stm32/src/main.c b/test-devices/loopback-stm32/src/main.c index 6e75657c..94495653 100644 --- a/test-devices/loopback-stm32/src/main.c +++ b/test-devices/loopback-stm32/src/main.c @@ -38,14 +38,16 @@ int echo_buffer_len; int num_echos; -// Blink durations -enum { - BLINK_NOT_MOUNTED = 250, - BLINK_MOUNTED = 1000, -}; +static bool is_blinking = true; +static uint32_t led_on_until = 0; +static uint32_t blink_toogle_at = 0; +static bool is_blink_on = true; -static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; +static inline bool has_expired(uint32_t deadline, uint32_t now) { + return (int32_t)(now - deadline) >= 0; +} +static void led_busy(void); static void led_blinking_task(void); static void loopback_init(void); static void loopback_check_rx(void); @@ -93,6 +95,7 @@ void loopback_check_tx(void) { n = max_size; cust_vendor_start_transmit_fifo(EP_LOOPBACK_TX, &loopback_fifo, n); + led_busy(); } } @@ -110,6 +113,7 @@ void loopback_check_rx(void) { void echo_update_state(void) { if (num_echos > 0) { cust_vendor_start_transmit(EP_ECHO_TX, echo_buffer, echo_buffer_len); + led_busy(); } else { cust_vendor_prepare_recv(EP_ECHO_RX, echo_buffer, sizeof(echo_buffer)); } @@ -129,6 +133,7 @@ void cust_vendor_rx_cb(uint8_t ep_addr, uint32_t recv_bytes) { echo_buffer_len = recv_bytes; echo_update_state(); } + led_busy(); } // Invoked when last tx transfer finished @@ -139,8 +144,10 @@ void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes) { // check ZLP if ((sent_bytes & (bulk_packet_size - 1)) == 0 - && !cust_vendor_is_transmitting(ep_addr)) + && !cust_vendor_is_transmitting(ep_addr)) { cust_vendor_start_transmit(EP_LOOPBACK_TX, NULL, 0); + led_busy(); + } } else if (ep_addr == EP_ECHO_TX) { num_echos--; @@ -153,6 +160,7 @@ void cust_vendor_intf_open_cb(uint8_t intf) { bulk_packet_size = cust_vendor_packet_size(EP_LOOPBACK_RX); loopback_check_rx(); echo_update_state(); + led_busy(); } // Invoked when an alternate interface has been selected @@ -162,6 +170,7 @@ void cust_vendor_alt_intf_selected_cb(uint8_t intf, uint8_t alt) { loopback_check_rx(); if (alt == 0) echo_update_state(); + led_busy(); } void cust_vendor_halt_cleared_cb(uint8_t ep_addr) { @@ -183,6 +192,7 @@ void cust_vendor_halt_cleared_cb(uint8_t ep_addr) { default: break; } + led_busy(); } @@ -209,6 +219,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 0) { // save value from wValue saved_value = request->wValue; + led_busy(); return tud_control_status(rhport, request); } break; @@ -216,6 +227,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ case REQUEST_SAVE_DATA: if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 4) { // receive into `saved_value` + led_busy(); return tud_control_xfer(rhport, request, &saved_value, 4); } break; @@ -223,6 +235,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ case REQUEST_SEND_DATA: if (request->bmRequestType_bit.direction == TUSB_DIR_IN && request->wLength == 4) { // transmit from `saved_value` + led_busy(); return tud_control_xfer(rhport, request, &saved_value, 4); } break; @@ -230,6 +243,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ case REQUEST_RESET_BUFFERS: if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 0) { reset_buffers(); + led_busy(); return tud_control_status(rhport, request); } break; @@ -238,6 +252,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ if (request->bmRequestType_bit.direction == TUSB_DIR_IN && request->wLength == 1) { uint8_t intf_num = request->wIndex & 0xff; if (intf_num < 4) { + led_busy(); // return inteface number return tud_control_xfer(rhport, request, &intf_num, 1); } @@ -247,6 +262,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ // Microsoft WCID descriptor (for automatic WinUSB installation) case WCID_VENDOR_CODE: if (request->bmRequestType_bit.direction == TUSB_DIR_IN && request->wIndex == 0x0004) { + led_busy(); // transmit WCID feature descriptor int len = sizeof(wcid_feature_desc); if (len >= request->wLength) @@ -274,12 +290,7 @@ usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) { // Invoked when device is mounted void tud_mount_cb(void) { - blink_interval_ms = BLINK_MOUNTED; -} - -// Invoked when device is unmounted -void tud_umount_cb(void) { - blink_interval_ms = BLINK_NOT_MOUNTED; + is_blinking = false; } // Invoked when usb bus is suspended @@ -293,15 +304,21 @@ void tud_suspend_cb(bool remote_wakeup_en) { // --- LED blinking --- -void led_blinking_task(void) { - static uint32_t start_ms = 0; - static bool led_state = false; - - // Blink every interval ms - if ( board_millis() - start_ms < blink_interval_ms) - return; // interval not elapsed yet - start_ms += blink_interval_ms; +void led_busy(void) { + led_on_until = board_millis() + 100; + board_led_write(true); +} - board_led_write(led_state); - led_state = 1 - led_state; // toggle +void led_blinking_task(void) { + uint32_t now = board_millis(); + if (is_blinking) { + if (has_expired(blink_toogle_at, now)) { + is_blink_on = !is_blink_on; + blink_toogle_at = now + 250; + } + board_led_write(is_blink_on && (now & 7) == 0); + + } else if (has_expired(led_on_until, now)) { + board_led_write((now & 3) == 0); + } } From 0d912c38542206d7a96ee0e59e11bcff5dad49f0 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 17 Mar 2024 08:58:31 +0100 Subject: [PATCH 351/433] Composite test-device: better LED feedback --- test-devices/composite-stm32/README.md | 2 +- .../composite-stm32/bin/blackpill-f401cc.bin | Bin 11756 -> 11832 bytes .../composite-stm32/bin/blackpill-f411ce.bin | Bin 11760 -> 11836 bytes .../composite-stm32/bin/bluepill-f103c8.bin | Bin 12244 -> 12316 bytes test-devices/composite-stm32/src/board_f1.c | 10 +-- test-devices/composite-stm32/src/board_f4.c | 6 +- test-devices/composite-stm32/src/main.c | 70 +++++++++--------- test-devices/loopback-stm32/README.md | 4 + .../loopback-stm32/bin/blackpill-f401cc.bin | Bin 11144 -> 11244 bytes .../loopback-stm32/bin/blackpill-f411ce.bin | Bin 11148 -> 11248 bytes .../loopback-stm32/bin/bluepill-f103c8.bin | Bin 11260 -> 11360 bytes .../loopback-stm32/bin/disco_f723ie.bin | Bin 11748 -> 11848 bytes test-devices/loopback-stm32/src/board_f4.c | 2 +- 13 files changed, 48 insertions(+), 46 deletions(-) diff --git a/test-devices/composite-stm32/README.md b/test-devices/composite-stm32/README.md index 931eef4e..bdea2084 100644 --- a/test-devices/composite-stm32/README.md +++ b/test-devices/composite-stm32/README.md @@ -75,7 +75,7 @@ To upload using the BlackPill's built-in bootloader: 2. Press the *Boot* button while connecting the board via USB to your computer. By pressing the *Boot* button, the device enters bootloader mode. 3. Verify with `dfu-util --list` that the bootloader is available via USB. If not unplug the device and repeat step 2. 4. Run the below command from the project directory. -5. Unplug and reconnect the board from your computer. The LED should now blink about twice a second. +5. Unplug and reconnect the board from your computer. Both the power and user LED should be lit and the device should appear as a serial device (aka as COM port on Windows). ``` dfu-util --device 0483:df11 --alt 0 --dfuse-address 0x08000000 --reset --download bin/blackpill-fxxx.bin diff --git a/test-devices/composite-stm32/bin/blackpill-f401cc.bin b/test-devices/composite-stm32/bin/blackpill-f401cc.bin index 1df99e219a50ca704741324be6f6161601b5ec96..81f2e061a3aca9754630c9dbf6a70d88eac82508 100755 GIT binary patch delta 1371 zcmZuwZA@EL7=F*~Ej>c{2%S<2gG)=c!ey1oLfE1i;=C=?iDHa16NPQj#rUHUU5Gy{ zqCdJN`h#m`{8~bcQDTUct|&j68k=CUY0|PGU+UNrEZM+Z1ae!p_V^yk{&~{pJm=$i zKTq%K$sb=DyG*Lg4M1tw;H?N6+6|uXH(-E90EdJ>bAvif+KOWLK>H=_a{~~m(xuvk zA)&S*G$FVI`ysS0d52XKuk|bnqAh48dac1u4Z1$-^|?DY)jVUBed%NA^I1bwT8A$<6&(=KEsj)_=A=+pP_2|wQY_$s`e7%$wMg)bg4sP>#6;rv$ zn0}5q`eQ*$d%@Y54dha9-lDC4P$PoP2kYBHeosZe9Q2oHrebpxGn8P-sxbW&yONZ5 z45k)KG()kLbYeBUBHj%n;!%W%py3PSMo(TlCX-=$00X|xa=kkd<$7LNOW3Fsd(2ou zbLN9KXH--wgTvzm*qK?h>0->UzrnuBqX{QUo=yvjb&@E&oo(sJN((+i6Fx((olJjW z*L_`-IBD1zA9Uu$a{;9&(>*MeWO^OjN|L%h47*3^O<4M48;@HA*_3#$-yk1~8|R2z z92ey3I7k&sM)|S0|KV%LQ)qAhI;W4=gEv$*(oKy=Na=0?`q(WK-Q$?dgd?*8h+Kf9}`9d9vIUda|={l_!2 z{N^+Unq2rjKwJ}vp}_RGq5i{^NgA7D`VZMArEuLO%p{34m4xUW{68PVw)1WfhrtIP zpZod&pu`Jyo6qOwPs7jVQOEh!U4F7boiMpbLR~gF9{dRnd~TncDl}ZK#2zrjnO>mo zr3Z`mGD#_kfOIcOmF?uL+D+TZ?a()r!@(y|!%jR`f5J{9C6-OS~W- z-F#(qC*vcPc54R1@$h``6m}Lkh2E;XE(oGa?WmsSR3+8#?4(CHy(`&lq6?_#1!6lf zof2D~&;-NJ$Ue8|3XMxI6O@HY?aiFk4o4TKOOB5?xoY_?G+6sD4-h)Hzf>&RgU;^5 z>Iz+yZ;``a;!BMne#NgSg#01}dJ-{;cpK4;;OU;v2Refw1wg+>^s2!F4l5x5?^%F4 NjUbhPd8aOh^M5B@-=_co delta 1295 zcmZuwZ%i9y7=PcpD}C1i!qAU9KI_$IbfJ4FsQJl{b=~zLXA0G94I#jvDP#YLYAXFFK?8U=K z^%vq9uIX6hlz`NQtUCspzSTVe!!(P*b}ic! zbKAIfEX0?H8>z!F5~qIi4D=h7!>B>mE*8-H*bWW!TG}n%>ZhuoMgjFiUXY+%q3X#F zRc}J|SRKkhh&qw&j<{{iFqOZ_GQ*5SB|b-=H?z9-mM-?}>KW(XZC#u;w+Ve>x2~Pm z?R}?J%-a1kX$KUi4Ybj@0eb)>`t~U2HMApjF0X4J>+z)kaqC(zvC*k3YLLpkrO=Qo zf2P%u;3RA0!l(%*orQoCx~`qkKP@q(9N_UxmXRDWEX9{xZn~Y;m}_lfUF%I?2a`Mn z@OyOam4vQ!z?SijM<9EpbTDP^n^=C_%!tO+{y-lqI+KPOES4u3u_lRxss)3%JL#Bi z6Ei6}WEAhE>i3z??pYYjq9!E%d22d^#NSf)`#M8>cfEwwyE!)86koUgcF?#c>1Re)jeR*A)u_z)+<#r$`mgOj zzEuKEG60Dw^F_{zGDCJ^O>QRkZLdNFzsK((5{Xtz6Pwtiu5FTEBF$SWbwR3#BVjd7 zq+I%Sd6=~0UzBBnO=Vq1L@r|_gaMz(*!&Y-kZ+q0;4Y=5@+8aY8p+7vsvzDkH(LS^ zqL&b}>@CNAb0hDp;_Y5=Ul!xl3D7`E+u4%$9O4kLRAA?15K7{#$QyI?ngvzj2 zf&HE_r&16OV{lUr+jdiyhwPn{ezm_tslS10%6AQSX#wTxgIl@suOZn6CY{QnxQJVx zg|kC|N%-fF1D6p*wg8R-b^z`J(9Rz-A#xTF1$1pjWSg9K+ATS-JZwh9VL(C!DqR~< Ghvz>IOul&l diff --git a/test-devices/composite-stm32/bin/blackpill-f411ce.bin b/test-devices/composite-stm32/bin/blackpill-f411ce.bin index c92dcc7df4b1d1804bed983c27d5759a0906f7ac..1f9993c74e352fa004c6dfbff0cc1c0624452f7d 100755 GIT binary patch delta 1345 zcmZuwZA@EL7=F)fOV9YMRG}1vOFOY}S!Kf@GwP5mm$EuAEYl@A2U8i(4A zS2fvwaE*zZF=56;V#p}9n=Cd>tifbzY?<4DO4gCgvPIm*L2iqq$M?|k&zn5=dCxiT z=X35=U;6&#$?u3@YE~{0E2nFuvov}i)Soh*E&xFkol1i+Dma>hmjtI^Yi|Z>I?3vY z+cJm_k#+!4@3sVbRp>i2;OXjJQwj~WzN--c8e-ZFrgy*AV(BMhc$s!EZ7~9o4h*Ra z6}!kdsQzp?t#26$jEJD7GtW=sN)$dDZu&YhY~y>&8KxzeVe)8N|8I>BL>i(lP?t9M zISS_qo-brtraNr+vc(#1ohobQ3h4Z)<4&) zvKFW(>O>m0vUma=HesCG$&4^A$lTh!!QX#j2cI&gz0K_2Xu#ZEG#IslRPHWFSiK`E z5v(3q-4F`gQBs+Kc)0jS=FYAwz7$Q4q@&6eCP?v2==Q zjch$d8i%m#gYrP!?2X=g)+|WI_#v-OdOT*BBT`vRkm_O}RwoV8)3L{{?3dDU#c!0> z;|;z8^|JY++T>^kT0mM!T=9c+C(g9hY`y!q-`Za!S#x_D+C^2$Y0KxNO_8d`DgYmK1(KNppttg+3`NRP)suU_!kFI>cM&@aO59URofvWxl6p4~>yg>CzTK`0x*w2HRj2ZWSb?6w3*sw;bA_#q zv(jVl<8;n`n$w=0d=>m)=Rdqi@Z_WA`cez#-A0Wwct%m3;>t$3Aza&KR?ZS!vRTZ`IwaS!Zem!LY*CbnM$D#Z@Pl=U zmW&ze;*4-=B2g29A0&hfxDo6^(?!rk-AoJ903#7+T$fCj+hkr_Dd+P-_rb(Ve)oI+ z-S2tc=k6w-(Viapig44Ca)AhpekKhipRIs4kq!9)IPr={*}?U4i;{YQtL2=3NI*+Z z8r39d@4$kD7eM5L_R;2LXz4o^@;7UW)m(M-Tmqnad}DwNf)-khXZX7I(NiL5OIcqG zJ(2sQtLDo@my^YkS@TG1hX1G11R@=$0njex_qwg~1as5bx|q+&HxV&@gZe-lRQk=f z$j~Z$NL<*m)81qcR2-~$60{R}QAYjM@&nD9Q3np9eVhSQn98<|`kdS#v%kx7gPhDP zA;<1NWexouL+aSsaZ&i7;o7XNQ4C9MhTd(s!rdA%xk7VkH%`SSYh(vS>;Z`2m}kcL zfVl~@g}kAEZm{7Dy(_^A7da5U<7T-eP>ch4^QRl!30|%o?H{w^(dM!Kgkk8Xje#O- z%8eCIWjWa$BXazP*T>e;5c9^Fj-huZh?`5ELWKN=emr65&A3+bP~=gRFO!d?Y~iWD z_Srbek~$PNNuH#6jz}d*PTH0Pv3$ua?M}L98>LK2iCUz)DaU@>yL*;;vrq@pt*f(9 zkZz_P2)0CpHit~KJ2}%xU3@+J%hlhaytJ6wy5AwYF}IS_((9R-h1==g$eP6EHHq(2 zC3vbA@~m*NP;_x&HcF&;sy8|_W~w=xv4|6Mn{Hb;hdiGq;t%P8hXLQ^`dW$06oNp= z|DFdZ7i?ZW*(tQK?~1LO1anU2F`Ene{+`~vo~v08{I{5i^q?@~ssiUFrHIxNUD-ul zTf*2OI%Lp^w~GW{7fW9K@A0m2>Ggm0{XMuB$pF)=jMzpyvsQ zBZw~)v+Y;1q@--Xf>>;!h zc4fi-DXCIkujt?U2Fh!H!ctEW(3cCXVpgSAc&z>?KGTgDK*UjxVWJSb=l>tKtNp@d zQn{+1%fIw{ad2CB!4kRKK3p0EY47rL!>jsGUO7|gw2xyuC|qoWx6%Iyp-xv`;kZeU z(pNph=vA?1%@cPr`cV{wNn9i!1R@-n$?)DMG|u!ja>zgFQ8~x61k2Rtox2$;eXbTp zw_NWtdTTrL)S2yfSOfLj2RHL2mr(2;k{#@I0y$3N*f^8FO34e=tvgV=&# klkc+vJ&TATS~mi%P)M!Ip2JMN4XE1;Vks1_9nrx1zZkBxT>t<8 diff --git a/test-devices/composite-stm32/bin/bluepill-f103c8.bin b/test-devices/composite-stm32/bin/bluepill-f103c8.bin index 84a855751e237ee900732d3678e70431c1eb4c1d..70d232b42b108127e8332ceca0de8ce5c5c34ae0 100755 GIT binary patch delta 1276 zcmZuwUrbw782`>~Z+rMRDjiS?8@B~r*$vPIjnmD5KrZd-#>6O7v&hs3v+Ut!n5-|e zfF@Qm65%?HMq?KDAP*=|t3z#W43T8hWv!D9A!e9mmQ2x$KyC{w$M4ee=1qR*`_6ZM z-=Fh4xxc*dQO`T)_{%1s*M^3=hmM+us%*oA4imFNNiETodQyq2pET!hWI%fGLY6EdWAww9rRJKs&V=OPRgB;{yU{sr1oF+zH$VeS1Gs``kusF^xHlA3L5hZxotA zpi$}rZ6?#~$^Vt$`CQsNX;f};oBYOJour|dLHx-C0@OlO8Dn}igLg?y=PI0b``ws+ zCL>6o*_iNz>u{&Wyx=0*4=LnhIeEOr&5aoTLYf=lB*WXcZmfUdDDN?*zshQYQ{#4j z!7Ecv5K97CWc z4rvU^qZ)=H2N7ljjlMm>`z(IYzR55>j15n+taiuL?ThV?@=~#{5HC@ed85^%nx(4o z3ljx+wQn;lq<3M`DfX#_COk+vlIA4GB#{g`Thp<{{rC(`_zYP&nckf%U#Aiejq>pU zk0qXMD5y;Lu~d@jb!;t3>Uy#5PU%F#9-LZv+|G&C#8W|&_+Xr$C1P=$6RYDOR4#;g z@v(U0^>#6pP{LMmE%Cr1mt=oy_rh=*ydW;kUk`(LH^KDf%@@N$z}e%HJQC6JH@Go5 zmgUUP{}DDf%p&L3W|LHo`3A$jv6Rf7|2X$|&YRw+CSdonjexueOs8)4G$ zRbn{&^Mq;dV9F|t%`*LKELgN`>?K*3D{PFe0S zp2vvAkZ0IKIa`NTjvkwA`8TiC7I?0Y)R3kfzUQHBRe8-)MjlqqTWU%#Vj;Oh?w}Hl zR!CEMra03Jl&h9~#k-gw*&)g{r zR0ij)p|!42TL8r7)gz-@10Srcb&Oy)qr34L6KpxSM1qwm!Vy>G^sXBg{vXtAF><)J zCa)-k?l$g4&eq>1kM?6|5b+)U-tVL3tw61aXAv$$9>S>mP#(~J#3)ms1n delta 1180 zcmZuwZ)jUp6hHU9B=07+wQH6p{WJHPbdc?lwG-6VO`Dbanyzk7RTMTR<+39iU$+AO#XLn>Rrsl#MZ*LIWDjTu2Euh{vLbjkC)HWfek;CIje zbAI<+-Uod@K67N$_yZ3#JvO%Aa2}PhCHpurGD;fB3FaYncy^IC%cTM+y}3Z==_WQ# zrnwmplQ}1s^hBQLb`taQP)}`tpwq9gN&c?j>!&q!C84Rg1iJv%45ZN*3kUy z)UXK3V$K^wOXQ9YZ99<|a_YWh&KQ0=Ygj2WfJmd%2TG#Q=C;fejGfCh$KtGnj7#`V1Kc@UuyqAaYb9u3|hF8?wNID%acEblLfGAQ|C^l{A;(BlZ4cxgS_NP8s~^qk>sShB#8D!qjYc5o$ipbDHal>Td9UU z);D)8j_05mq(3jGLm>T;YLI(E_1(37M5$ll!_D!v=+(>DLk8&zM%}V)4^iAJN@gu` zabc;XU0Cf9{5DmAw|cOkr(P+AW){*RBE?hVp^MY}wzso__~l&rlE5{{^BE$3mpQy0 zs2A6$Z;QD20Qdr(fhM5->xn}9Q_wRF6|BaP$H~*WgH+dNw>yj(U zUp;Knw4FT3elfYoQ;Y~!VrDjB$DJEBQLc=GcsoPod}b@_6}rf8k>ArQB=+dWwJ; zMugb>h8yG?mZ<6_=7`Pu5^pG~ipEB(N69^`#(sFq)f%7|5J#(l#!B)vJJ1!!n(uwo zzhJZW54qb#_MGEW+ZJrE+=Rskj6iLrQ3u$jnw_nCvHTUpdx+!MPRHjZ-@5&Oa(`s3 z<`Stds&5n?zfs;@H@F}KZ}pt4>;|cAdEd#RI$U5Qb&ZaGoCc*&XRrh9-H6CcU6yb$ zF>+?p&nDw%_zoXO-feW5%fqOy<5XnUbDiAZimrzcU*X^AM;XWZ1Y&~#bROl`2z|s& j3bfS>^Z>$a0Xl18*P5J;JcevlKpiF!E1_(ajE3hwETWk! diff --git a/test-devices/composite-stm32/src/board_f1.c b/test-devices/composite-stm32/src/board_f1.c index e3dc0eb5..344cae68 100644 --- a/test-devices/composite-stm32/src/board_f1.c +++ b/test-devices/composite-stm32/src/board_f1.c @@ -188,20 +188,16 @@ uint32_t board_millis(void) { void board_led_write(bool on) { if (on) - gpio_set(GPIOB, 12); - else gpio_clear(GPIOB, 12); + else + gpio_set(GPIOB, 12); } // --- Interrupt handlers --- void SysTick_Handler (void) { - millis_count++; -} - -void USBWakeUp_IRQHandler(void) { - tud_int_handler(0); + millis_count++; } void USB_HP_IRQHandler(void) { diff --git a/test-devices/composite-stm32/src/board_f4.c b/test-devices/composite-stm32/src/board_f4.c index 6f83803f..927320d5 100644 --- a/test-devices/composite-stm32/src/board_f4.c +++ b/test-devices/composite-stm32/src/board_f4.c @@ -262,16 +262,16 @@ uint32_t board_millis(void) { void board_led_write(bool on) { if (on) - gpio_set(GPIOC, 13); - else gpio_clear(GPIOC, 13); + else + gpio_set(GPIOC, 13); } // --- Interrupt handlers --- void SysTick_Handler (void) { - millis_count++; + millis_count++; } void OTG_FS_IRQHandler(void) { diff --git a/test-devices/composite-stm32/src/main.c b/test-devices/composite-stm32/src/main.c index 034a3714..0ae69a2f 100644 --- a/test-devices/composite-stm32/src/main.c +++ b/test-devices/composite-stm32/src/main.c @@ -25,15 +25,16 @@ uint8_t loopback_buffer[512]; // RX buffer for loopback uint8_t loopback_rx_buffer[64]; -// Blink durations -enum { - BLINK_NOT_MOUNTED = 250, - BLINK_MOUNTED = 1000, - BLINK_SUSPENDED = 2500, -}; +static bool is_blinking = true; +static uint32_t led_on_until = 0; +static uint32_t blink_toogle_at = 0; +static bool is_blink_on = true; -static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; +static inline bool has_expired(uint32_t deadline, uint32_t now) { + return (int32_t)(now - deadline) >= 0; +} +static void led_busy(void); static void led_blinking_task(void); static void cdc_task(void); static void loopback_init(void); @@ -82,6 +83,7 @@ void loopback_check_tx(void) { n = 128; cust_vendor_start_transmit(EP_LOOPBACK_TX, info.ptr_lin, n); + led_busy(); } } @@ -105,6 +107,7 @@ void cdc_task(void) { tud_cdc_write(buf, n); tud_cdc_write_flush(); + led_busy(); } @@ -115,6 +118,7 @@ void cust_vendor_rx_cb(uint8_t ep_addr, uint32_t recv_bytes) { tu_fifo_write_n(&loopback_fifo, loopback_rx_buffer, recv_bytes); loopback_check_rx(); loopback_check_tx(); + led_busy(); } // Invoked when last tx transfer finished @@ -134,11 +138,14 @@ void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes) { if ((sent_bytes & (BULK_MAX_PACKET_SIZE - 1)) == 0 && !cust_vendor_is_transmitting(ep_addr)) cust_vendor_start_transmit(EP_LOOPBACK_TX, NULL, 0); + + led_busy(); } // Invoked when interface has been opened void cust_vendor_intf_open_cb(uint8_t intf) { loopback_check_rx(); + led_busy(); } void cust_vendor_halt_cleared_cb(uint8_t ep_addr) { @@ -152,6 +159,7 @@ void cust_vendor_halt_cleared_cb(uint8_t ep_addr) { default: break; } + led_busy(); } @@ -176,6 +184,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ case REQUEST_SAVE_VALUE: if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 0) { + led_busy(); // save value from wValue saved_value = request->wValue; return tud_control_status(rhport, request); @@ -184,6 +193,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ case REQUEST_SAVE_DATA: if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 4) { + led_busy(); // receive into `saved_value` return tud_control_xfer(rhport, request, &saved_value, 4); } @@ -191,6 +201,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ case REQUEST_SEND_DATA: if (request->bmRequestType_bit.direction == TUSB_DIR_IN && request->wLength == 4) { + led_busy(); // transmit from `saved_value` return tud_control_xfer(rhport, request, &saved_value, 4); } @@ -198,6 +209,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ case REQUEST_RESET_BUFFERS: if (request->bmRequestType_bit.direction == TUSB_DIR_OUT && request->wLength == 0) { + led_busy(); reset_buffers(); return tud_control_status(rhport, request); } @@ -207,6 +219,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ if (request->bmRequestType_bit.direction == TUSB_DIR_IN && request->wLength == 1) { uint8_t intf_num = request->wIndex & 0xff; if (intf_num < 4) { + led_busy(); // return inteface number return tud_control_xfer(rhport, request, &intf_num, 1); } @@ -247,38 +260,27 @@ usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) { // Invoked when device is mounted void tud_mount_cb(void) { - blink_interval_ms = BLINK_MOUNTED; + is_blinking = false; } -// Invoked when device is unmounted -void tud_umount_cb(void) { - blink_interval_ms = BLINK_NOT_MOUNTED; -} -// Invoked when usb bus is suspended -// remote_wakeup_en: if host allow us to perform remote wakeup -// Within 7ms, device must draw an average of current less than 2.5 mA from bus -void tud_suspend_cb(bool remote_wakeup_en) { - (void) remote_wakeup_en; - blink_interval_ms = BLINK_SUSPENDED; -} +// --- LED blinking --- -// Invoked when usb bus is resumed -void tud_resume_cb(void) { - blink_interval_ms = BLINK_MOUNTED; +void led_busy(void) { + led_on_until = board_millis() + 100; + board_led_write(true); } -// --- LED blinking --- - void led_blinking_task(void) { - static uint32_t start_ms = 0; - static bool led_state = false; - - // Blink every interval ms - if ( board_millis() - start_ms < blink_interval_ms) - return; // not enough time - start_ms += blink_interval_ms; - - board_led_write(led_state); - led_state = 1 - led_state; // toggle + uint32_t now = board_millis(); + if (is_blinking) { + if (has_expired(blink_toogle_at, now)) { + is_blink_on = !is_blink_on; + blink_toogle_at = now + 250; + } + board_led_write(is_blink_on && (now & 7) == 0); + + } else if (has_expired(led_on_until, now)) { + board_led_write((now & 3) == 0); + } } diff --git a/test-devices/loopback-stm32/README.md b/test-devices/loopback-stm32/README.md index 60b70550..45332099 100644 --- a/test-devices/loopback-stm32/README.md +++ b/test-devices/loopback-stm32/README.md @@ -52,6 +52,10 @@ The device can be put into suspend mode by the host. It will go into a low-power To put the device into suspended mode, put the host computer to sleep or supended mode. To wake it up, wake up the host computer. +NOTE: *Due to a limitation of TinyUSB, the device will only go into suspended mode if the host has set a USB configuration. Usually it means that an application has communicated with the device after it was plugged in. The LED blinks as long as no USB configuration has been set.* + +NOTE: *Suspend/resume has not been implemented for the STM32F723 Discovery board.* + ## Building the firmware diff --git a/test-devices/loopback-stm32/bin/blackpill-f401cc.bin b/test-devices/loopback-stm32/bin/blackpill-f401cc.bin index ee327901eec0ba936ab6e30e832d4047a95162f6..bb69371130a8eaff19825d80f75fc1862463a151 100755 GIT binary patch delta 1921 zcmZuydu&rx7(eIU+xFhFvW~8-4>oRFCS4m~W{E2glZCOnbsdg}W+r5=5QsDUQ)4hy zW4df6R3jmBFur1V$RC(s+}LiiF-wgEoia=dL#LZ&WP?J$a3|p1#_07s-5NEq>F=I% zzQ^x-oOAAtx7=;%K7-3wAS5FAb^8#{%WTNm!v@)gFYlucK0)Oo{JTjS*Opr6krJGX z)FXt&lppa_Nxdn)CQmY5c&Jxqni}h_0_Sk~<2K!dWGf3GrFG@(+`PkNkT+NDBiIh88O?7Gh=wMIG(|*B${L4c6 zF-Nph!HgqNZ{k`EXhg4cWt*`i?do%b;YwicW7p<|LD31;<)& z+^sDQIpcVvfAjJ*t)P64k>UebqVp2yNB}zGN_Ke-XIs*!4qTg4SM4FNJge^P{DqvhY~Op-)`98OLkSrBBAM zoMnB7W(;EAsHX1AR!OF512dMv;*YS6QMim-pfmX{VGkQY4UzieAji;KM?Q}yEjl`rN!nbE zZA2(qgNI3VQJvieQl4r66M%nw-Y?Qjc`41ckDORmtE2WZ*=ku&+!nV$^;BmA$*zB` zdMr*XlgpNB9ksB*%t1WGrHiY&;uuHYmc2v8JT5)`oF^Z(?ONHc=~@1LX)1?5fW(zM5NY zcOCqXULrSK9$**TUAkOc@}9e`D4#(9d??cff;~Hd{yEPelS_h9Zvbqeq<~6nMw@yo zo-nYcT;?DWDxYoMM4qm=Y8rxk@)#zizKpN~BrgDliOKITx(J*09Y8iB{u+9ad_{ssb?kFEd! delta 1814 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 delta 1884 zcmZuyeQZ-z6uX;PZ9mlB-;b+Bgy4rzix&w(oDDe!*e15|`zh2TB&mKW*jvaL-dHv90I9XP zXb>Sre9MOfFpAsBq4;1P35s3)N|(R z4IV|5d(R}ZmH@S$9I_;lG7XubF3}P%YAk9&>UXnJtpD!Dg~c~8_RKe61#k1U8~i* zrLH~|vr_a)J6rnH2)M_MXCegft&w-1aaRstC_(zg3`7 zkBjT|_~V>xmaP!CUDvh!x;f;C;kCXEwlpowkz?ep1eQfPne}%EkXk&{=P{=FW@`km zwF0Fd675&~NqUXrP>>L(SI6YoP$Yj8bS#o)36gPf3cojy>IcDjMwdaH&3z2_#*sR&tJJ?=2v9i5D!ZeKR-2nLMt_f?6<5;>U^IVwups1;onenWp0OK-$0lRgcOm^v?AjUDdwAL? z4qZ3@X=GgTtqc~^8Kl_Yo!JDZr)|z3Myg|@s4*IB00W)=eec-A^rW=^IFy4fM}t(> zwP(&#zYpPEqU-0R(^QMMkz*#Qx&`bU#NPy4G#CvEvJkJ3hfQos*T&|sC?s|5M>1hL zSKkkwCjqAchX6+b>OC}m7*>DW(1Ii>Y?gKH6P=SS11Gz5t#?k8{mFhZR@90+NpK5n9EDCN;XbIBFX^pk*uv#|YvOjz1^DkaFe z(mGs8_LeTkm&u9J7b+@2TS6^>+kk&#@Kd_Epry5*C1&eJp86+9!dg#0wz^H!PHmN- zdHso9mCb<@q~2D?QxC}ZSQ@Z(bGlZP8(h6ez}0KZkx&DuScHT{kJg7Ex0lW9$`&KR zM>-aN2{r4BJF94RS|w$jfYZ_3GjRSiJt;X*w(Yr75IF*v0!Y9_VFYHXEA0Po9V{DM zP;OwHl=&9`y)E>_Lo?kI$SQlY`Ivh?@%&XBw72qEaGoW%?9bvXF+1L@r+XS;b0Zgq zX+5MMh3en~od3k;WtnS6k*0`MW`~h<=?+sH4Q9!JW7u4XrrBr7fyyhmjcl%(G_}E~ zZGri1CiTu`pzCnfR#6@Ov~wYZ?XO&$=KPY%u$N$s2HVJhvkbQl{_Nb2VW|=8u$lVP z$|z3*+3gDES@-34N!LgJu{V>gZVB@2b@%c4+~lEqdugGH28f|d>&b3u8_-{r&M_4Q z<9aYQQc}Q5Y(as+&z?52=6v;_GOcWD4UkhcBj%k@PXQ5f(3>&+0WVVykRtEA`?3KnX-E;O(Q}ME+n(779WfA;c!eWC4=S z5kt{n0xt#=Li`vc8X*q4ssp+UAt+J77KVb`%*(?$o91sM`r06Ce z<1S{ENF?SJ5a~Dk5+qS zLFzn5-z3wCF)Ju<%hm*ve`kt%gjEu3BI9f^8jgHLLn!q+WTVYoac;UpVV&yX-(>Y0x;} zXzx@p;|QaPG~*6A+r_h1)nqA>A!Pv#+az7H>Axypv-!wQ;eGpIznvF9@4dU^a%yY`6@cS{@?o%ABiGyG_@@{8#=6OM>8%d;)U9#bf!C;m}9)tKN>aE{shtknL4Sw z$t8Iutg=)06`OIQ|2xHQyb26ddnHv2M`u~OI5;OXpg4?)Tcc52dp`9^^u{^XcWBBa z^xW399pGV}FfjuP7OulKj*Ey}3!TY#347Qus%{9^m(x!cK0rq}Tu%>*t}%TG;;kT{ zlXKaBGVQpj*|`6S!9XTSwNYvrgeF4 zcE}nrd@+eSV%Cy!Tr*jYxZeQRN&vYrUWzzNZvG?8M@VDo3A~mlr8{QR3}{Z&6~RSw zn1EK?p;eQeWgAy)1?9Vd&jCM!D}|hk<)8m=+!gz)tc=N)aTUyaNJ(WGzDsHU+I#upowmw(QUMI5|;O1>AVm zx8^)|=`1)$sZi%_<&obtHc*bN8jP0@A&UzN_Bk?)ME3yFyQbHY^$_0Ry*p9hd zSblF#voChd{VH3Mw`hUzjLmaTdoZ652V%SDEyCb>!n+IZ{QR%rerf*Y;#J_7M_>Ut z;v40^funo_aFM(vilr}eh}#TkmARX`zMKpcw delta 1768 zcmZuyeQZ-z6ut+nd`Qii4?{_9@EgM$EWMVupF z;S)^GLqz5~<_`~qJ-+=>LOWHOpMEg@u1 zmA4_Kewq^#XL<#sWD4OlA277nB;qK3_RIBdNf0w*=GNY`)Ou>boI%nUg9Io-FsI5O zwsG3n=}Pq9*-$y}8U~-w3%;~7!L~n#u#kyCC{p%8SSiR5u!oUXcS8?JY~el#I51## za_uZg{sAOqfjkEo0ib$AN>j@;^eJ`)C(y3Sb~7YAUl2s3R6VHJT=8sWC#nl7+A^e^ ze5k3+fB)Y!ss2P)t+TXs&3Vf>~GOc76g#X(4S;JqKt7U^k!A$(s6w zmKoz)HT7+Yb@MXg2es=Qe_* zsST2*>LeWu!kgAqpTrbLGIgE4A2b*@?MvyzYH^!viLy$FY4sT7T~XH4oYjqBk0r}^ z7G;rO8`XJMWE-!p^xT*2`hSK`BslLq`DS8qhuiCx+^(la?fN^h+|2~?j>&c6u7nL5 zij;>M(;vw!(*Fh)&U+0kZqd?#m3jC7&e!NCa#!+JeKvP1ftoMN6)^3!g^EC(xG3Zn zNAouQ(D2O!_72KlC$5}jJ%{fbgn<#$xPhq?Z{)Ec=aKY2T#$`$dOGGTvkFe*Vk4+6 z;y(?B;KVy`Vkm>2l+M2Z_k!-Itf^1`K>a2?aKm6VkV(UG{4;6dT@9UJe+%L}0TF-1 z&x?G@Dh?UhtfmgnV1b9*be`ez zG@m&Y)zsb@LG)$%Nw+bGyGhE}So``+E{}w(d9x_zDF@}EoK`*Jw~#60F(b`F8ILB9 zm-R5lZ3e_&fbBU_XWD9_QW|g(aEZKUT8SMbZCZ-|Bze;&s{^#0{mG{sh>Oyu5fPYmCjs#FHyrud-DoiXEVyrTKP=3mZ%7jmhE0Cor(;n)bkRZ_{~r zHhG3Ba==)^h?f*Rw~ViVYBykz-1d6sk3;|O0e|2aI~@h+U@Ksa3GowU N@GpVNi#^rg`7bx$NKpU) diff --git a/test-devices/loopback-stm32/bin/disco_f723ie.bin b/test-devices/loopback-stm32/bin/disco_f723ie.bin index 01ed7764ab8929232e1f76300903192b22b89f07..da78a59215b2719629163d8dc30577c6166a02eb 100755 GIT binary patch delta 1947 zcmZuyeQZ-z6uac=PT@xT#AA_j>CBrZXdEe5S2 z*tz{dQ5Qe1CPahb>kmj~+~}GxNO_5ZEEvcN!vF&r!L1Mnyn))Sj6Tn8Y1G6fzutS! z`JLZ6@7(wC+s2{S`lc~oj*x)h*Gn){riHE0OB_tSln&s&|BQE-R*ey=aeAH~4E7E1XCU12P+P3sU%LrUa?F-8+;A{Wh*>}|-$ z-{7Tgfp4<4AteU#w6UYI(Zx1tGHoK|gA-xke**Xnpoa@dK0)r5KRWBIO^9H(wb8l; zDZyFm%UH0kM#{TSkh4Wm7l)8iq^ij`RbTLAzq{>68}gM%x=~xOOTmn-9ZjVeSHK?h z^&1s^QGpCS3uw$Ds>${0uZfxr|JtZg(G)3(UMNhP)b^j&hip+VZjzaN^we`p*z)rL7J33+sRY(N~tK#)4&y)hqYI*r(ig%cl}hC zhac|tB;#D>0Q0UtOsGjU{Q&;2rzaDdjQ37l4JC`z@dOpZ3*L!p#Zqxo+!WL(0jAcg zk8cTTyi2LD*F4O4-NQ(z7}I)J3@^I0%sU;o>;AfYD9rjE!Hf>4Z--sY9-l|{xGiIL z-QAJfVdR^LZwWgj8%+1hv{UqmSgD&~`r2c2byr6w!ff>~@sOI_ovsl}o3mkQ=0U=u zn;JQnuPtrrHasL5@hVVKf0 zqX{frfMYyeg}9Y4ncS4HThopj+Z!gqk72g9_VxyPpQy&9_Y@6`!vjj!B|^VHD#D%BOiW ze+P%S@5q__Lp)X71Nb7+QE-;!&+~{I0JD$0RNQKyyC~o|V2B(jUS_bs4oiE3^opzKM&KRO*Hsv+m4tqzb~rg|;qN6CWH$beWbiEU+sl*ld4lIn5#V`$woVa@bso=k2y4ZUGi-Ha!qJ6!7QQ7LFcQ|0j*9uNP+ zcQEsuNlx4b@FSPAXq;Hi$-7B0p7K6q%30)ph#DqnF=9^yU)?8-;nKEUVXtEw7H VEyB2}1aZA}@C`%-bXG_O{0&9gghK!T delta 1984 zcmZuye@s(X6u$Sp*YXNf3k8L?;DZODQgH@{mT58u_}cPN;_z3LY{kW`bNi#)vW!hh z5%!}b8Z~!uW6{M;m$+q1kgl6W*>k#0<6P1zW-_P2;H-u$c`C7h$lJLE=C-WqmwWCx z-}%nD=iS$yZMw0kdlVZ4gy4%%Ey2uOT@mbRNgh*^7nwln`fM3!S3Oj*=biW zaK0ILMhb&i;5<(wnu*likVW}4FGaQne8{1@s+T(iy~pB1>PNk%Le9fNYI84Ab^>V+ z;C)ICYYF2d5*tR^s!bk5uxN6dRw8xdglQEPO!Y|J@DLR=sM;c=-kH=At(wDE?mKDO zQ+@BExmIX#c(ufvn%L5zVpjCuj(3CRVJ3hCH*~`RssPx|hjlS6(WUj>;;Xd88wzXZ zV>+2Bw0Jo=*E{7stnhI1ndaK<&M+q#B{Sqbt7(aCno+g}@iIqsR!oqPS~<>0EfFly z**ReX^Lsn&DKTB0*@u^z10d;yLfaH)ax7Go57W^JmU z$fytt7B5oM##55aCpBAy4jFQknMae_UaY#t zm_WC`FJFHRLY(7DEUT_SvP)QP9J?FO(U0_Bi0A5~{WpVX;V-dSaJe2lm?cw2zIQNg z(VxCF6vU2`u}^~+df3ukqbWk~W#gR`ra-zH$3iTQlqPs5YT@+svLz2AvVP?DyWR#r zBR7n^^{Ut6r6;A&AIszLl>IJhYl&yRqr_HtZ|J%kRz8eWae}R5WyYSan4}zu@9P5p zwdq*)e`3_%wSX*4Eni`tK!vOn>%rwas^h<{vNbmqkIpgOkF)NZaU|S`*F(vA=t%_l zU49oY_8E6%% zxGyx2euguwH6Z>NY`-R-XEYkA6#<+8oF|6NrA8ZASpKkuPBKDPW|rZDWLxHnT1=btlR~e-vWLGu#inLJnfs= z|KIvS=uVEA$)m#O0d%woK6^p9bGlF~DX^|LwiZp5of^?Q)&|`OaCtIdeGHEfgYBhC zx~Gk06`}&{#%k&@q);FH+&9w)le8tS4*5Jjv&5c8;;GxrV!vyId}TXhoXMuud9ow# zXJ&s{XjOhYHtdHx*@Tg>jttBz0WV>M@+H)XuA@OtM%c39!YJnyRfatUtKUUqkNh?N z@Q1bvA7d(qteBNQ-YQYS$$@BG-$a%Sc)@ z0YIhd$lBsYTHuS~b4>P3v<{+crdjo&PJ4(kCJzKI!=g0}^&yYLfoGk7c4lz0EY!YW z2{u%K? Date: Sun, 17 Mar 2024 09:08:30 +0100 Subject: [PATCH 352/433] Release 1.0.0 --- README.md | 4 ++-- examples/bulk_transfer/README.md | 2 +- examples/bulk_transfer/pom.xml | 4 ++-- examples/enumerate/README.md | 2 +- examples/enumerate/pom.xml | 4 ++-- examples/enumerate_kotlin/README.md | 2 +- examples/enumerate_kotlin/pom.xml | 4 ++-- examples/epaper_display/README.md | 4 ++-- examples/epaper_display/pom.xml | 4 ++-- examples/monitor/README.md | 2 +- examples/monitor/pom.xml | 4 ++-- examples/monitor_kotlin/README.md | 2 +- examples/monitor_kotlin/pom.xml | 4 ++-- examples/stm_dfu/README.md | 2 +- examples/stm_dfu/pom.xml | 4 ++-- java-does-usb/pom.xml | 2 +- 16 files changed, 25 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 193708ac..ba85c80a 100644 --- a/README.md +++ b/README.md @@ -31,14 +31,14 @@ If you are using Maven, add the below dependency to your pom.xml: net.codecrete.usb java-does-usb - 1.0.0-SNAPSHOT + 1.0.0 ``` If you are using Gradle, add the below dependency to your build.gradle file: ```groovy -compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '1.0.0-SNAPSHOT' +compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '1.0.0' ``` ```java diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index 2758c3a3..4e03d796 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] --------------< net.codecrete.usb.examples:bulk-transfer >-------------- -[INFO] Building bulk-transfer 1.0.0-SNAPSHOT +[INFO] Building bulk-transfer 1.0.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ bulk-transfer --- diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index 6613a04f..a7f46a50 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples bulk-transfer - 1.0.0-SNAPSHOT + 1.0.0 bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.0.0-SNAPSHOT + 1.0.0 diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index 907e1cf0..fcb26056 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] ----------------< net.codecrete.usb.examples:enumerate >---------------- -[INFO] Building enumerate 1.0.0-SNAPSHOT +[INFO] Building enumerate 1.0.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ enumerate --- diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index c4df53d9..b4f4cf4d 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples enumerate - 1.0.0-SNAPSHOT + 1.0.0 enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.0.0-SNAPSHOT + 1.0.0 org.tinylog diff --git a/examples/enumerate_kotlin/README.md b/examples/enumerate_kotlin/README.md index 4f85c62f..57b40728 100644 --- a/examples/enumerate_kotlin/README.md +++ b/examples/enumerate_kotlin/README.md @@ -40,7 +40,7 @@ $ mvn clean package ### Run the jar ```shell -$ java --enable-native-access=ALL-UNNAMED -jar target/enumerate-1.0.0-SNAPSHOT-jar-with-dependencies.jar +$ java --enable-native-access=ALL-UNNAMED -jar target/enumerate-1.0.0-jar-with-dependencies.jar Device: VID: 0xcafe PID: 0xceaf diff --git a/examples/enumerate_kotlin/pom.xml b/examples/enumerate_kotlin/pom.xml index c6e41240..57234065 100644 --- a/examples/enumerate_kotlin/pom.xml +++ b/examples/enumerate_kotlin/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples enumerate - 1.0.0-SNAPSHOT + 1.0.0 jar enumerate @@ -64,7 +64,7 @@ net.codecrete.usb java-does-usb - 1.0.0-SNAPSHOT + 1.0.0 org.tinylog diff --git a/examples/epaper_display/README.md b/examples/epaper_display/README.md index 7b98499c..27789d50 100644 --- a/examples/epaper_display/README.md +++ b/examples/epaper_display/README.md @@ -45,7 +45,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -------------< net.codecrete.usb.examples:epaper-display >-------------- -[INFO] Building epaper-display 1.0.0-SNAPSHOT +[INFO] Building epaper-display 1.0.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ epaper-display --- @@ -79,6 +79,6 @@ $ sudo -i Password: $ cd /Users/me/Documents/JavaDoesUSB/examples/epaper_display $ export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-20.jdk/Contents/Home -$ $JAVA_HOME/bin/java --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/1.0.0-SNAPSHOT/java-does-usb-1.0.0-SNAPSHOT.jar net.codecrete.usb.examples.EPaperDisplay +$ $JAVA_HOME/bin/java --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/1.0.0/java-does-usb-1.0.0.jar net.codecrete.usb.examples.EPaperDisplay Display size: 1200 x 825 ``` diff --git a/examples/epaper_display/pom.xml b/examples/epaper_display/pom.xml index 1cf46fb0..98b8da45 100644 --- a/examples/epaper_display/pom.xml +++ b/examples/epaper_display/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples epaper-display - 1.0.0-SNAPSHOT + 1.0.0 epaper-display https://github.com/manuelbl/JavaDoesUSB/examples/epaper_display @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.0.0-SNAPSHOT + 1.0.0 diff --git a/examples/monitor/README.md b/examples/monitor/README.md index 6c758965..dcd2f672 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -----------------< net.codecrete.usb.examples:monitor >----------------- -[INFO] Building monitor 1.0.0-SNAPSHOT +[INFO] Building monitor 1.0.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ monitor --- diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index 190039cd..99c09f6f 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples monitor - 1.0.0-SNAPSHOT + 1.0.0 monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.0.0-SNAPSHOT + 1.0.0 org.tinylog diff --git a/examples/monitor_kotlin/README.md b/examples/monitor_kotlin/README.md index af199253..9941837d 100644 --- a/examples/monitor_kotlin/README.md +++ b/examples/monitor_kotlin/README.md @@ -40,7 +40,7 @@ $ mvn clean package ### Run the jar ```shell -$ java --enable-native-access=ALL-UNNAMED -jar target/monitor-1.0.0-SNAPSHOT-jar-with-dependencies.jar +$ java --enable-native-access=ALL-UNNAMED -jar target/monitor-1.0.0-jar-with-dependencies.jar Present: VID: 0x1d6b, PID: 0x0002, manufacturer: Linux 6.5.0-18-generic xhci-hcd, product: xHCI Host Controller, serial: 0000:00:14.0, ID: /dev/bus/usb/001/001 Present: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 35A737883336, ID: /dev/bus/usb/001/009 Monitoring... Press ENTER to quit. diff --git a/examples/monitor_kotlin/pom.xml b/examples/monitor_kotlin/pom.xml index cdae381e..c359f204 100644 --- a/examples/monitor_kotlin/pom.xml +++ b/examples/monitor_kotlin/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples monitor - 1.0.0-SNAPSHOT + 1.0.0 jar monitor @@ -64,7 +64,7 @@ net.codecrete.usb java-does-usb - 1.0.0-SNAPSHOT + 1.0.0 org.tinylog diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index df76a714..83b7e793 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -58,7 +58,7 @@ Run the command below (adapting the file path depending on your specific board): ```shell $ mvn package -$ java --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-1.0.0-SNAPSHOT.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin +$ java --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-1.0.0.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin DFU device found with serial 35A737883336. Target memory segment: Internal Flash Erasing page at 0x8000000 (size 0x4000) diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index 5a47b5a4..19d2f508 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples stm_dfu - 1.0.0-SNAPSHOT + 1.0.0 stm_dfu https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu @@ -19,7 +19,7 @@ net.codecrete.usb java-does-usb - 1.0.0-SNAPSHOT + 1.0.0 diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 3d3e0888..5eb88b45 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 1.0.0-SNAPSHOT + 1.0.0 22 From 5d474d6f82bf9312118061fe55f0916841fdc893 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 17 Mar 2024 11:09:07 +0100 Subject: [PATCH 353/433] Mention code examples --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ba85c80a..cd2831f5 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,8 @@ public class EnumerateDevices { ## Documentation -- [Javadoc](https://javadoc.io/doc/net.codecrete.usb/java-does-usb) - +- [Code Examples](https://github.com/manuelbl/JavaDoesUSB/wiki/Java-Does-USB-By-Examples) +- [Javadoc](https://javadoc.io/doc/net.codecrete.usb/java-does-usb) From 8dd5333637ab355e9030ad79910c45b73f3a5a20 Mon Sep 17 00:00:00 2001 From: Michael Pollmeier Date: Fri, 19 Apr 2024 12:16:02 +0200 Subject: [PATCH 354/433] readme: fix getting started example --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cd2831f5..329cca3a 100644 --- a/README.md +++ b/README.md @@ -44,12 +44,12 @@ compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '1.0.0' ```java package net.codecrete.usb.sample; -import net.codecrete.usb.USB; +import net.codecrete.usb.Usb; public class EnumerateDevices { public static void main(String[] args) { - for (var device : USB.getAllDevices()) { + for (var device : Usb.getDevices()) { System.out.println(device); } } From 3719ce89c3a486140481fe481f01094aba2bf10a Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 19 Apr 2024 14:31:49 +0200 Subject: [PATCH 355/433] Upgrade GitHub actions to nodejs 20 --- .github/workflows/continuous-integration.yaml | 4 +++- .github/workflows/test-devices.yaml | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index 5d883172..e7b98f4e 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -24,7 +24,7 @@ jobs: os: [ubuntu-latest, macOS-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Java uses: oracle-actions/setup-java@v1 with: @@ -33,6 +33,8 @@ jobs: version: latest - name: Configure GPG key run: | + gpg --version + echo "Encoded key length: ${#GPG_SIGNING_KEY}" echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import env: GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} diff --git a/.github/workflows/test-devices.yaml b/.github/workflows/test-devices.yaml index 4ad663f7..bc6d1c5a 100644 --- a/.github/workflows/test-devices.yaml +++ b/.github/workflows/test-devices.yaml @@ -15,14 +15,14 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/cache@v3 + - uses: actions/checkout@v4 + - uses: actions/cache@v4 with: path: | ~/.cache/pip ~/.platformio/.cache key: ${{ runner.os }}-pio - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.9' - name: Install PlatformIO Core From e019f50d22e012fc7f4c5a80a14301b205875790 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 20 Apr 2024 11:18:07 +0200 Subject: [PATCH 356/433] macOS: check that device has not been disconnected --- .../java/net/codecrete/usb/UsbDevice.java | 12 +++++++ .../codecrete/usb/common/UsbDeviceImpl.java | 7 +++++ .../codecrete/usb/macos/MacosUsbDevice.java | 25 +++++++++------ .../net/codecrete/usb/special/Unplug.java | 31 +++++++++++++------ 4 files changed, 55 insertions(+), 20 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/UsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbDevice.java index acf03748..427f5e21 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/UsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbDevice.java @@ -152,6 +152,18 @@ public interface UsbDevice { */ void attachStandardDrivers(); + /** + * Indicates if the device is connected. + *

+ * When a {@link UsbDevice} instance is initially returned by {@link Usb#getDevices()} and related methods, + * it is connected. When the user unplugs the device, the application can still hold on to instance of + * {@link UsbDevice} even though the actual USB device is gone. This method can be used to check if the + * device is still connected. + *

+ * @return {@code true} if the device is connected, {@code false} if it is no longer connected + */ + boolean isConnected(); + /** * Opens the device for communication. */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java index 2d6a0c63..3db6d2d0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java @@ -55,6 +55,7 @@ public abstract class UsbDeviceImpl implements UsbDevice { protected int deviceProtocol; protected Version versionUsb; protected Version versionDevice; + protected boolean connected; /** * Creates a new instance. @@ -70,6 +71,7 @@ protected UsbDeviceImpl(Object id, int vendorId, int productId) { uniqueDeviceId = id; vid = vendorId; pid = productId; + connected = true; } @Override @@ -157,6 +159,11 @@ public Object getUniqueId() { return uniqueDeviceId; } + @Override + public boolean isConnected() { + return connected; + } + /** * Sets the class codes and version for the device descriptor. * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java index 63ffd5ca..37b81c8f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java @@ -78,18 +78,16 @@ public class MacosUsbDevice extends UsbDeviceImpl { } @Override - public void detachStandardDrivers() { - if (isOpened()) - throwException("detachStandardDrivers() must not be called while the device is open"); + public synchronized void detachStandardDrivers() { + checkIsClosed("detachStandardDrivers() must not be called while the device is open"); var ret = IoKitUsb.USBDeviceReEnumerate(device, IOKit.kUSBReEnumerateCaptureDeviceMask()); if (ret != 0) throwException(ret, "detaching standard drivers failed"); } @Override - public void attachStandardDrivers() { - if (isOpened()) - throwException("attachStandardDrivers() must not be called while the device is open"); + public synchronized void attachStandardDrivers() { + checkIsClosed("attachStandardDrivers() must not be called while the device is open"); var ret = IoKitUsb.USBDeviceReEnumerate(device, IOKit.kUSBReEnumerateReleaseDeviceMask()); if (ret != 0) throwException(ret, "attaching standard drivers failed"); @@ -100,11 +98,17 @@ public boolean isOpened() { return claimedInterfaces != null; } + private void checkIsClosed(String message) { + if (!connected) + throwException("device has been disconnected"); + if (isOpened()) + throwException(message); + } + @SuppressWarnings("java:S2276") @Override public synchronized void open() { - if (isOpened()) - throwException("device is already open"); + checkIsClosed("device is already open"); // open device (several retries if device has just been connected/discovered) var duration = System.currentTimeMillis() - discoveryTime; @@ -161,6 +165,7 @@ public synchronized void close() { } synchronized void closeFully() { + connected = false; close(); IoKitUsb.Release(device); device = null; @@ -580,7 +585,7 @@ protected Transfer createTransfer() { } @Override - public void abortTransfers(UsbDirection direction, int endpointNumber) { + public synchronized void abortTransfers(UsbDirection direction, int endpointNumber) { var epInfo = getEndpointInfo(endpointNumber, direction, UsbTransferType.BULK, UsbTransferType.INTERRUPT); @@ -590,7 +595,7 @@ public void abortTransfers(UsbDirection direction, int endpointNumber) { } @Override - public void clearHalt(UsbDirection direction, int endpointNumber) { + public synchronized void clearHalt(UsbDirection direction, int endpointNumber) { var epInfo = getEndpointInfo(endpointNumber, direction, UsbTransferType.BULK, UsbTransferType.INTERRUPT); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java index 87a0463d..a1380414 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java @@ -57,6 +57,27 @@ private static void onUnpluggedDevice(UsbDevice device) { var worker = activeDevices.remove(device); worker.setDisconnectTime(System.currentTimeMillis()); worker.join(); + + // test handling of disconnected devices + new Thread(() -> { + sleep(2000); + try { + device.open(); + System.err.println("Device should not be openable after disconnect"); + } catch (UsbException e) { + // expected + } + }).start(); + } + + @SuppressWarnings({"SameParameterValue", "java:S2925"}) + private static void sleep(long millis) { + try { + Thread.sleep(millis); + + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } } static class DeviceWorker { @@ -241,16 +262,6 @@ private void receiveEcho() { logWork(1); } } - - @SuppressWarnings({"SameParameterValue", "java:S2925"}) - private static void sleep(long millis) { - try { - Thread.sleep(millis); - - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } } static class Work { From c8c49a6a4ca3a5c67c89df77a999247e5738d4a5 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 20 Apr 2024 12:41:08 +0200 Subject: [PATCH 357/433] Linux: check that device has not been disconnected --- .../net/codecrete/usb/common/UsbDeviceImpl.java | 12 ++++++++++++ .../codecrete/usb/common/UsbDeviceRegistry.java | 4 ++-- .../net/codecrete/usb/linux/LinuxUsbDevice.java | 13 +++++-------- .../net/codecrete/usb/macos/MacosUsbDevice.java | 13 +++---------- .../usb/macos/MacosUsbDeviceRegistry.java | 14 +------------- .../java/net/codecrete/usb/special/Unplug.java | 3 ++- 6 files changed, 25 insertions(+), 34 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java index 3db6d2d0..137d6c86 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java @@ -95,6 +95,18 @@ protected void checkIsOpen() { throw new UsbException("device needs to be opened first for this operation"); } + protected void checkIsClosed(String message) { + if (!connected) + throw new UsbException("device has been disconnected"); + if (isOpened()) + throw new UsbException(message); + } + + protected synchronized void disconnect() { + connected = false; + close(); + } + @Override public int getProductId() { return pid; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceRegistry.java index 72268f15..54521bbd 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceRegistry.java @@ -204,9 +204,9 @@ protected void closeAndRemoveDevice(Object deviceId) { return; try { - device.close(); + ((UsbDeviceImpl)device).disconnect(); } catch (Exception e) { - LOG.log(INFO, "failed to close USB device - ignoring exception", e); + LOG.log(INFO, "failed to close disconnected USB device - ignoring exception", e); } removeDevice(deviceId); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java index b2fdf4d8..4e8c66a7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java @@ -71,16 +71,14 @@ private void loadDescription(String path) { } @Override - public void detachStandardDrivers() { - if (isOpened()) - throwException("detachStandardDrivers() must not be called while the device is open"); + public synchronized void detachStandardDrivers() { + checkIsClosed("detachStandardDrivers() must not be called while the device is open"); detachDrivers = true; } @Override - public void attachStandardDrivers() { - if (isOpened()) - throwException("attachStandardDrivers() must not be called while the device is open"); + public synchronized void attachStandardDrivers() { + checkIsClosed("attachStandardDrivers() must not be called while the device is open"); detachDrivers = false; } @@ -91,8 +89,7 @@ public boolean isOpened() { @Override public synchronized void open() { - if (isOpened()) - throwException("device is already open"); + checkIsClosed("device is already open"); try (var arena = Arena.ofConfined()) { var pathUtf8 = arena.allocateFrom(uniqueDeviceId.toString()); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java index 37b81c8f..c4b2046c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java @@ -98,13 +98,6 @@ public boolean isOpened() { return claimedInterfaces != null; } - private void checkIsClosed(String message) { - if (!connected) - throwException("device has been disconnected"); - if (isOpened()) - throwException(message); - } - @SuppressWarnings("java:S2276") @Override public synchronized void open() { @@ -164,9 +157,9 @@ public synchronized void close() { asyncTask.removeEventSource(source); } - synchronized void closeFully() { - connected = false; - close(); + @Override + protected synchronized void disconnect() { + super.disconnect(); IoKitUsb.Release(device); device = null; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java index 36a9c5f5..3654be7a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java @@ -267,19 +267,7 @@ private void onDevicesConnected(MemorySegment ignoredRefCon, int iterator) { private void onDevicesDisconnected(MemorySegment ignoredRefCon, int iterator) { // process device iterator for disconnected devices - iterateDevices(iterator, (entryId, _, _) -> { - var device = findDevice(entryId); - if (device == null) - return; - - try { - ((MacosUsbDevice) device).closeFully(); - } catch (Exception e) { - LOG.log(INFO, "failed to close USB device - ignoring exception", e); - } - - removeDevice(entryId); - }); + iterateDevices(iterator, (entryId, _, _) -> closeAndRemoveDevice(entryId)); } @FunctionalInterface diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java index a1380414..eddffdb0 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java @@ -65,7 +65,8 @@ private static void onUnpluggedDevice(UsbDevice device) { device.open(); System.err.println("Device should not be openable after disconnect"); } catch (UsbException e) { - // expected + if (!e.getMessage().contains("disconnected")) + System.err.println(STR."Unexpected error: \{e.getMessage()}"); } }).start(); } From c12a2d21f8cb24bfb53c21104636d966b6a8270a Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 20 Apr 2024 13:07:04 +0200 Subject: [PATCH 358/433] Windows: check that device is still connected --- .../main/java/net/codecrete/usb/windows/WindowsUsbDevice.java | 4 +--- .../src/test/java/net/codecrete/usb/special/Unplug.java | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java index c1f39869..f2a11b05 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java @@ -97,9 +97,7 @@ public boolean isOpened() { @Override public synchronized void open() { - if (isOpened()) - throwException("device is already open"); - + checkIsClosed("device is already open"); showAsOpen = true; } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java index eddffdb0..cc5e7671 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java @@ -66,7 +66,7 @@ private static void onUnpluggedDevice(UsbDevice device) { System.err.println("Device should not be openable after disconnect"); } catch (UsbException e) { if (!e.getMessage().contains("disconnected")) - System.err.println(STR."Unexpected error: \{e.getMessage()}"); + System.err.println("Unexpected error: " + e.getMessage()); } }).start(); } From 485328265e82556704b85708dcd7b5448374467f Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 20 Apr 2024 13:51:46 +0200 Subject: [PATCH 359/433] Use unprotected key for unit tests --- .github/workflows/continuous-integration.yaml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index e7b98f4e..c2f02057 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -31,13 +31,11 @@ jobs: website: jdk.java.net release: 22 version: latest - - name: Configure GPG key + - name: Configure unit test GPG key run: | - gpg --version - echo "Encoded key length: ${#GPG_SIGNING_KEY}" - echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import + echo -n "$UNIT_TEST_SIGNING_KEY" | base64 --decode | gpg --import env: - GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} + UNIT_TEST_SIGNING_KEY: ${{ env.UNIT_TEST_SIGNING_KEY }} shell: bash - name: Build java-does-usb run: ./mvnw $MAVEN_ARGS -DskipTests clean install javadoc:javadoc From 575ee7b7a7089331ceff068f3ef656d0ccedf7e3 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 20 Apr 2024 14:17:25 +0200 Subject: [PATCH 360/433] Fix GPG import --- .github/workflows/continuous-integration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index c2f02057..44fa638c 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -35,7 +35,7 @@ jobs: run: | echo -n "$UNIT_TEST_SIGNING_KEY" | base64 --decode | gpg --import env: - UNIT_TEST_SIGNING_KEY: ${{ env.UNIT_TEST_SIGNING_KEY }} + UNIT_TEST_SIGNING_KEY: ${{ vars.UNIT_TEST_SIGNING_KEY }} shell: bash - name: Build java-does-usb run: ./mvnw $MAVEN_ARGS -DskipTests clean install javadoc:javadoc From 78aa0dd5dc7f5af73b38a74d0198096996f7898d Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 5 May 2024 09:49:14 +0200 Subject: [PATCH 361/433] Upgrade to latest TinyUSB version --- .../composite-stm32/bin/blackpill-f401cc.bin | Bin 11832 -> 12248 bytes .../composite-stm32/bin/blackpill-f411ce.bin | Bin 11836 -> 12252 bytes .../composite-stm32/bin/bluepill-f103c8.bin | Bin 12316 -> 12408 bytes test-devices/composite-stm32/copy_tinyusb.sh | 17 + .../lib/tinyusb/class/audio/audio.h | 935 ------ .../lib/tinyusb/class/audio/audio_device.c | 2567 ----------------- .../lib/tinyusb/class/audio/audio_device.h | 699 ----- .../lib/tinyusb/class/bth/bth_device.c | 260 -- .../lib/tinyusb/class/bth/bth_device.h | 109 - .../lib/tinyusb/class/cdc/cdc.h | 34 +- .../lib/tinyusb/class/cdc/cdc_device.c | 66 +- .../lib/tinyusb/class/cdc/cdc_device.h | 1 + .../lib/tinyusb/class/cdc/cdc_host.c | 987 +++++-- .../lib/tinyusb/class/cdc/cdc_host.h | 18 +- .../lib/tinyusb/class/cdc/serial/ch34x.h | 84 + .../lib/tinyusb/class/cdc/serial/cp210x.h | 2 - .../lib/tinyusb/class/cdc/serial/ftdi_sio.h | 5 +- .../lib/tinyusb/class/dfu/dfu.h | 119 - .../lib/tinyusb/class/dfu/dfu_device.c | 460 --- .../lib/tinyusb/class/dfu/dfu_device.h | 98 - .../lib/tinyusb/class/dfu/dfu_rt_device.c | 128 - .../lib/tinyusb/class/dfu/dfu_rt_device.h | 54 - .../lib/tinyusb/class/hid/hid.h | 1131 -------- .../lib/tinyusb/class/hid/hid_device.c | 415 --- .../lib/tinyusb/class/hid/hid_device.h | 418 --- .../lib/tinyusb/class/hid/hid_host.c | 772 ----- .../lib/tinyusb/class/hid/hid_host.h | 168 -- .../lib/tinyusb/class/midi/midi.h | 212 -- .../lib/tinyusb/class/midi/midi_device.c | 546 ---- .../lib/tinyusb/class/midi/midi_device.h | 173 -- .../lib/tinyusb/class/msc/msc.h | 382 --- .../lib/tinyusb/class/msc/msc_device.c | 952 ------ .../lib/tinyusb/class/msc/msc_device.h | 162 -- .../lib/tinyusb/class/msc/msc_host.c | 525 ---- .../lib/tinyusb/class/msc/msc_host.h | 126 - .../lib/tinyusb/class/net/ecm_rndis_device.c | 450 --- .../lib/tinyusb/class/net/ncm.h | 69 - .../lib/tinyusb/class/net/ncm_device.c | 511 ---- .../lib/tinyusb/class/net/net_device.h | 118 - .../lib/tinyusb/class/usbtmc/usbtmc.h | 318 -- .../lib/tinyusb/class/usbtmc/usbtmc_device.c | 890 ------ .../lib/tinyusb/class/usbtmc/usbtmc_device.h | 112 - .../lib/tinyusb/class/vendor/vendor_device.c | 287 -- .../lib/tinyusb/class/vendor/vendor_device.h | 150 - .../lib/tinyusb/class/vendor/vendor_host.c | 146 - .../lib/tinyusb/class/vendor/vendor_host.h | 67 - .../lib/tinyusb/class/video/video.h | 559 ---- .../lib/tinyusb/class/video/video_device.c | 1257 -------- .../lib/tinyusb/class/video/video_device.h | 97 - .../lib/tinyusb/common/tusb_common.h | 48 +- .../lib/tinyusb/common/tusb_compiler.h | 10 +- .../lib/tinyusb/common/tusb_debug.h | 43 +- .../lib/tinyusb/common/tusb_fifo.c | 3 +- .../lib/tinyusb/common/tusb_fifo.h | 31 +- .../lib/tinyusb/common/tusb_mcu.h | 115 +- .../lib/tinyusb/common/tusb_private.h | 36 +- .../lib/tinyusb/common/tusb_timeout.h | 80 - .../lib/tinyusb/common/tusb_types.h | 196 +- .../lib/tinyusb/common/tusb_verify.h | 59 +- .../composite-stm32/lib/tinyusb/device/dcd.h | 52 +- .../composite-stm32/lib/tinyusb/device/usbd.c | 981 +++---- .../composite-stm32/lib/tinyusb/device/usbd.h | 45 +- .../lib/tinyusb/device/usbd_control.c | 133 +- .../lib/tinyusb/device/usbd_pvt.h | 22 +- .../lib/tinyusb/dwc2/hwcfg_list.md | 777 ----- .../composite-stm32/lib/tinyusb/osal/osal.h | 3 + .../lib/tinyusb/osal/osal_freertos.h | 215 -- .../lib/tinyusb/osal/osal_mynewt.h | 176 -- .../lib/tinyusb/osal/osal_none.h | 83 +- .../lib/tinyusb/osal/osal_pico.h | 184 -- .../lib/tinyusb/osal/osal_rtthread.h | 132 - .../lib/tinyusb/osal/osal_rtx4.h | 170 -- .../st}/stm32_fsdev/dcd_stm32_fsdev.c | 1172 ++++---- .../st/stm32_fsdev/dcd_stm32_fsdev.h} | 408 ++- .../{ => portable/synopsys}/dwc2/dcd_dwc2.c | 970 +++---- .../{ => portable/synopsys}/dwc2/dwc2_bcm.h | 0 .../{ => portable/synopsys}/dwc2/dwc2_efm32.h | 0 .../{ => portable/synopsys}/dwc2/dwc2_esp32.h | 0 .../{ => portable/synopsys}/dwc2/dwc2_gd32.h | 0 .../portable/synopsys/dwc2/dwc2_info.md | 55 + .../portable/synopsys/dwc2/dwc2_info.py | 169 ++ .../{ => portable/synopsys}/dwc2/dwc2_stm32.h | 137 +- .../{ => portable/synopsys}/dwc2/dwc2_type.h | 1791 ++++++------ .../{ => portable/synopsys}/dwc2/dwc2_xmc.h | 0 .../composite-stm32/lib/tinyusb/tusb.c | 310 +- .../composite-stm32/lib/tinyusb/tusb.h | 14 +- .../composite-stm32/lib/tinyusb/tusb_option.h | 168 +- .../loopback-stm32/.vscode/settings.json | 3 +- .../loopback-stm32/bin/blackpill-f401cc.bin | Bin 11244 -> 11360 bytes .../loopback-stm32/bin/blackpill-f411ce.bin | Bin 11248 -> 11364 bytes .../loopback-stm32/bin/bluepill-f103c8.bin | Bin 11360 -> 10892 bytes .../loopback-stm32/bin/disco_f723ie.bin | Bin 11848 -> 11920 bytes test-devices/loopback-stm32/copy_tinyusb.sh | 15 + .../lib/{tinyusb => config}/tusb_config.h | 0 .../lib/tinyusb/class/audio/audio.h | 935 ------ .../lib/tinyusb/class/audio/audio_device.c | 2567 ----------------- .../lib/tinyusb/class/audio/audio_device.h | 699 ----- .../lib/tinyusb/class/bth/bth_device.c | 260 -- .../lib/tinyusb/class/bth/bth_device.h | 109 - .../lib/tinyusb/class/cdc/cdc.h | 424 --- .../lib/tinyusb/class/cdc/cdc_device.c | 483 ---- .../lib/tinyusb/class/cdc/cdc_device.h | 259 -- .../lib/tinyusb/class/cdc/cdc_host.c | 1177 -------- .../lib/tinyusb/class/cdc/cdc_host.h | 204 -- .../lib/tinyusb/class/cdc/cdc_rndis.h | 301 -- .../lib/tinyusb/class/cdc/cdc_rndis_host.c | 289 -- .../lib/tinyusb/class/cdc/cdc_rndis_host.h | 63 - .../lib/tinyusb/class/cdc/serial/cp210x.h | 64 - .../lib/tinyusb/class/cdc/serial/ftdi_sio.h | 249 -- .../lib/tinyusb/class/dfu/dfu.h | 119 - .../lib/tinyusb/class/dfu/dfu_device.c | 460 --- .../lib/tinyusb/class/dfu/dfu_device.h | 98 - .../lib/tinyusb/class/dfu/dfu_rt_device.c | 128 - .../lib/tinyusb/class/dfu/dfu_rt_device.h | 54 - .../lib/tinyusb/class/hid/hid.h | 1131 -------- .../lib/tinyusb/class/hid/hid_device.c | 415 --- .../lib/tinyusb/class/hid/hid_device.h | 418 --- .../lib/tinyusb/class/hid/hid_host.c | 772 ----- .../lib/tinyusb/class/hid/hid_host.h | 168 -- .../lib/tinyusb/class/midi/midi.h | 212 -- .../lib/tinyusb/class/midi/midi_device.c | 546 ---- .../lib/tinyusb/class/midi/midi_device.h | 173 -- .../lib/tinyusb/class/msc/msc.h | 382 --- .../lib/tinyusb/class/msc/msc_device.c | 952 ------ .../lib/tinyusb/class/msc/msc_device.h | 162 -- .../lib/tinyusb/class/msc/msc_host.c | 525 ---- .../lib/tinyusb/class/msc/msc_host.h | 126 - .../lib/tinyusb/class/net/ecm_rndis_device.c | 450 --- .../lib/tinyusb/class/net/ncm.h | 69 - .../lib/tinyusb/class/net/ncm_device.c | 511 ---- .../lib/tinyusb/class/net/net_device.h | 118 - .../lib/tinyusb/class/usbtmc/usbtmc.h | 318 -- .../lib/tinyusb/class/usbtmc/usbtmc_device.c | 890 ------ .../lib/tinyusb/class/usbtmc/usbtmc_device.h | 112 - .../lib/tinyusb/class/vendor/vendor_device.c | 287 -- .../lib/tinyusb/class/vendor/vendor_device.h | 150 - .../lib/tinyusb/class/vendor/vendor_host.c | 146 - .../lib/tinyusb/class/vendor/vendor_host.h | 67 - .../lib/tinyusb/class/video/video.h | 559 ---- .../lib/tinyusb/class/video/video_device.c | 1257 -------- .../lib/tinyusb/class/video/video_device.h | 97 - .../lib/tinyusb/common/tusb_common.h | 48 +- .../lib/tinyusb/common/tusb_compiler.h | 10 +- .../lib/tinyusb/common/tusb_debug.h | 43 +- .../lib/tinyusb/common/tusb_fifo.c | 3 +- .../lib/tinyusb/common/tusb_fifo.h | 31 +- .../lib/tinyusb/common/tusb_mcu.h | 115 +- .../lib/tinyusb/common/tusb_private.h | 36 +- .../lib/tinyusb/common/tusb_timeout.h | 80 - .../lib/tinyusb/common/tusb_types.h | 196 +- .../lib/tinyusb/common/tusb_verify.h | 59 +- .../loopback-stm32/lib/tinyusb/device/dcd.h | 52 +- .../loopback-stm32/lib/tinyusb/device/usbd.c | 981 +++---- .../loopback-stm32/lib/tinyusb/device/usbd.h | 45 +- .../lib/tinyusb/device/usbd_control.c | 133 +- .../lib/tinyusb/device/usbd_pvt.h | 22 +- .../lib/tinyusb/dwc2/hwcfg_list.md | 777 ----- .../loopback-stm32/lib/tinyusb/osal/osal.h | 3 + .../lib/tinyusb/osal/osal_freertos.h | 215 -- .../lib/tinyusb/osal/osal_mynewt.h | 176 -- .../lib/tinyusb/osal/osal_none.h | 83 +- .../lib/tinyusb/osal/osal_pico.h | 184 -- .../lib/tinyusb/osal/osal_rtthread.h | 132 - .../lib/tinyusb/osal/osal_rtx4.h | 170 -- .../st}/stm32_fsdev/dcd_stm32_fsdev.c | 1172 ++++---- .../st/stm32_fsdev/dcd_stm32_fsdev.h} | 408 ++- .../{ => portable/synopsys}/dwc2/dcd_dwc2.c | 979 +++---- .../{ => portable/synopsys}/dwc2/dwc2_bcm.h | 0 .../{ => portable/synopsys}/dwc2/dwc2_efm32.h | 0 .../{ => portable/synopsys}/dwc2/dwc2_esp32.h | 0 .../{ => portable/synopsys}/dwc2/dwc2_gd32.h | 0 .../portable/synopsys/dwc2/dwc2_info.md | 55 + .../portable/synopsys/dwc2/dwc2_info.py | 169 ++ .../{ => portable/synopsys}/dwc2/dwc2_stm32.h | 137 +- .../{ => portable/synopsys}/dwc2/dwc2_type.h | 1791 ++++++------ .../{ => portable/synopsys}/dwc2/dwc2_xmc.h | 0 .../loopback-stm32/lib/tinyusb/tusb.c | 310 +- .../loopback-stm32/lib/tinyusb/tusb.h | 14 +- .../loopback-stm32/lib/tinyusb/tusb_option.h | 168 +- .../loopback-stm32/src/vendor_custom.c | 4 + 180 files changed, 8232 insertions(+), 46986 deletions(-) create mode 100755 test-devices/composite-stm32/copy_tinyusb.sh delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/audio/audio.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.c delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.h delete mode 100755 test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.c delete mode 100755 test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.h create mode 100644 test-devices/composite-stm32/lib/tinyusb/class/cdc/serial/ch34x.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_device.c delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_device.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/hid/hid.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.c delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.c delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/midi/midi.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.c delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/msc/msc.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.c delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.c delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/net/ecm_rndis_device.c delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/net/ncm.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/net/ncm_device.c delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/net/net_device.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.c delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.c delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/video/video.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/video/video_device.c delete mode 100644 test-devices/composite-stm32/lib/tinyusb/class/video/video_device.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/common/tusb_timeout.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/dwc2/hwcfg_list.md delete mode 100644 test-devices/composite-stm32/lib/tinyusb/osal/osal_freertos.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/osal/osal_mynewt.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/osal/osal_pico.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/osal/osal_rtthread.h delete mode 100644 test-devices/composite-stm32/lib/tinyusb/osal/osal_rtx4.h rename test-devices/composite-stm32/lib/tinyusb/{ => portable/st}/stm32_fsdev/dcd_stm32_fsdev.c (53%) rename test-devices/{loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h => composite-stm32/lib/tinyusb/portable/st/stm32_fsdev/dcd_stm32_fsdev.h} (53%) rename test-devices/composite-stm32/lib/tinyusb/{ => portable/synopsys}/dwc2/dcd_dwc2.c (61%) rename test-devices/composite-stm32/lib/tinyusb/{ => portable/synopsys}/dwc2/dwc2_bcm.h (100%) rename test-devices/composite-stm32/lib/tinyusb/{ => portable/synopsys}/dwc2/dwc2_efm32.h (100%) rename test-devices/composite-stm32/lib/tinyusb/{ => portable/synopsys}/dwc2/dwc2_esp32.h (100%) rename test-devices/composite-stm32/lib/tinyusb/{ => portable/synopsys}/dwc2/dwc2_gd32.h (100%) create mode 100644 test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_info.md create mode 100644 test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_info.py rename test-devices/composite-stm32/lib/tinyusb/{ => portable/synopsys}/dwc2/dwc2_stm32.h (63%) rename test-devices/composite-stm32/lib/tinyusb/{ => portable/synopsys}/dwc2/dwc2_type.h (71%) rename test-devices/composite-stm32/lib/tinyusb/{ => portable/synopsys}/dwc2/dwc2_xmc.h (100%) create mode 100755 test-devices/loopback-stm32/copy_tinyusb.sh rename test-devices/loopback-stm32/lib/{tinyusb => config}/tusb_config.h (100%) delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/audio/audio.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/audio/audio_device.c delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/audio/audio_device.h delete mode 100755 test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.c delete mode 100755 test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.c delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.c delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/serial/cp210x.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/cdc/serial/ftdi_sio.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_device.c delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_device.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/hid/hid.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.c delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.c delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/midi/midi.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.c delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/msc/msc.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.c delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.c delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/net/ecm_rndis_device.c delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/net/ncm.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/net/ncm_device.c delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/net/net_device.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.c delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.c delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/video/video.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.c delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/common/tusb_timeout.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/dwc2/hwcfg_list.md delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/osal/osal_freertos.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/osal/osal_mynewt.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/osal/osal_pico.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtthread.h delete mode 100644 test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtx4.h rename test-devices/loopback-stm32/lib/tinyusb/{ => portable/st}/stm32_fsdev/dcd_stm32_fsdev.c (53%) rename test-devices/{composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h => loopback-stm32/lib/tinyusb/portable/st/stm32_fsdev/dcd_stm32_fsdev.h} (53%) rename test-devices/loopback-stm32/lib/tinyusb/{ => portable/synopsys}/dwc2/dcd_dwc2.c (60%) rename test-devices/loopback-stm32/lib/tinyusb/{ => portable/synopsys}/dwc2/dwc2_bcm.h (100%) rename test-devices/loopback-stm32/lib/tinyusb/{ => portable/synopsys}/dwc2/dwc2_efm32.h (100%) rename test-devices/loopback-stm32/lib/tinyusb/{ => portable/synopsys}/dwc2/dwc2_esp32.h (100%) rename test-devices/loopback-stm32/lib/tinyusb/{ => portable/synopsys}/dwc2/dwc2_gd32.h (100%) create mode 100644 test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_info.md create mode 100644 test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_info.py rename test-devices/loopback-stm32/lib/tinyusb/{ => portable/synopsys}/dwc2/dwc2_stm32.h (63%) rename test-devices/loopback-stm32/lib/tinyusb/{ => portable/synopsys}/dwc2/dwc2_type.h (71%) rename test-devices/loopback-stm32/lib/tinyusb/{ => portable/synopsys}/dwc2/dwc2_xmc.h (100%) diff --git a/test-devices/composite-stm32/bin/blackpill-f401cc.bin b/test-devices/composite-stm32/bin/blackpill-f401cc.bin index 81f2e061a3aca9754630c9dbf6a70d88eac82508..71988d4f67b70fd52d0fc7e3c03ce61d035e07cf 100755 GIT binary patch delta 5917 zcmZu#3wTpiw%+@kJWk)CDUd!n$>EVUEe#a42u{8d9cQ>R-rE%F6d2{rsbsvK(v+N%Ho0r3#jD?U z^L1yhtiAWz>+$ck*Y5F$Mj!2Z59b^zKn&AMJ2JcJb#!It1oATd2tF+Q9V!rpu{Hap z86^FA%2k07W=|9%hKy#-wSNjLs3z(}!LdJ51}b@oLToWY8xccU{#GDdSFBY~(uc=| zrOKuFRbhkDo7-K<_uaD^`^Dcrk)GKtM z#nDh(1igZ}svvsOu+C7)Z9vk?Gc1p!sfd1kl@v82J(j+aVLnK6bz2P7VM1S=q7G9$ zq3*d&zHbU40yXf(7vN_LKhs(p9%E$&tFDV2$^L)pw8tI?<6 zv%25tNdUdC32mxe%nE-}?WLXz3qMk`)ZVc0wAz5T3a_aP?`>L+m@@DVk%T$gg(_VY zJHTt$feaZgSA`PB2=57)NBRf^fb?G!2o$r4sxA~BVBW!X0v)%k{C33LcdRFm*Yo{j zE(?-A7;yDRLtp!F%%;FVG<4hN>P6!krGhttu8QdrYZVQjc&G-Cv zfbjN25bNq^dKLDn;43@nFk&@kB=v=v{$|k1)l0bX>#J>5w<1qh-HPs9qU*6X`!aZq zd4CUEhNQ2g4J zRLjfEFl|p583RMgfPyLJTVzUuq=E=CULG1-wWKVUw;0Hr55r_c!B=&s6oO>e0 zeM(2B^St`A5j5~O5lL)><^LiQrKPXY#bifJ^`{hJv`Wbn#lZmA?wIOXt3Y*rIg-wX zRXjnAEnH%x&JrsQM$L0pXnW_a2W_83dX}f8C#Hm!c$SS1V-5)b%yB0M6A+ScnCjBR z%*L#%LO2uO%sOUV-N~yK+};yB1n7u{E=N8Sm8L8H+?e9J8R6N4ho}ux!nuUSlwoRr z;_G;w@cYEgMccsaLH~Tf)65hy4){_2iJ>&9MAhd%?6!cGho%+a!=9lcekDK4d0$wP z^dI<~@OIK_sy`}RPim&zQNfkGfZ7oinv?%XX`+H9QUX7R=-xc5C zKNmOgt9c8LrI#beexUgjQ%7e6RqCf65Knwxjk+ZQ{i$DT_`xJ1Qd$9j3I7zW7*l5JZPSU{eNgceXjr zd`kshby|E6BeofiKri$pUR}^D9GQ2yHQhR}waZ7o2Ytw=i=i-)SMm#Z#tFO`&bbm0 zhxG*ix(bqmgcdCen#(r*dd?j+DS3mR{UKXPG{(}G)8_1G=-z0yBc~?Y!F6XtNG7MU z9lDxKu<|MI1=+a|EnV%t33f8WMt+G4NpDBVF{z1SHaTWj(%G|fc5UrTap;^H2_rm& z-~jcH$xSia);DE3@!iPu%}`6ls7SPiq{tHUu0k78BZinv%p~R#(+j?emfGCZ8YQ2| zD@@wa3uClI-ej=kQV}RuC<6YpS7a8QRI5j{F>CP|xXAj^Kv)F+#+1r( z2`iC%570>39z{mU4}5dY1fqdweq}-I$L`ny7|DZI2G)AKS2hSY&v6~rn{ zZ=yrzCijXr8oy27iv8t(LRrW?V|okwaaM`=j~7wJQZ$rw97iS)io^6avue5L-Yr^n`ddl z*PD@48iq~Hv{XaYy3OQlnz1j z`e!cD(jpq0kaVo^zSETHqQ71CWN82gw9<5LbSwHx+;yF*tVKqyyMHlY^-3d++p0>O zp9VfvsRPfcP@Y9P-`FmvvpA0)Iw@Ulr1O0KemTQz>ce?P-XdLUjE0s*(ejd@qf<4m z!Kx$VqFFRUF5m07i5Xw2OD6B@eCZ;a$HL}W<`fS&`dDKY+0?9m<~3{5upKP=DDV;1 z1{yJv{?Mp8qFF)2Oi#Cq=w^H4sSK+l%Rq(kig6L;d4ir!P{|x;D!H|*6Cd0pb5eR1 zV&b5+=@1jjob5-_5%bs_{SDAzXsWm11if*)UCz*u9LPpEH-RAM`sa1#NWGhqlkdY^ z`Xv}QBLTJ6yIZa1p?de4SYh$<%$sha)=#G2bfGo`PJP{5opZ7$61p1EbVIT;sfOl* zDHqh9$>p7Bz$AYB4ClUoUhRZJyMJEYM7fr8*_sE1N7EBLi$;?GGd}~5AalJ-b(m-q zoO<*6?3F;0D#0)mo=}6Ji<2tEkmO1d>!rD5yVIRuqJ2f~S7rLZEnSs_<9E6hrVss8 zTU%yZ4=o@L3y`7q5jQ)^mz{BUiDz4p=C4K*Fg zM>vruoXj%fKL}rCWu~n-;nm-Q+j$Ihn1&Xs#?rF$=+qNqLTUDW_;taPomq4>EQwIv zf$VE=30|FBKxCzn8m$tZR8Z;>A=sg-1tGpM;j`?8|4KM=Z(&sqzs7wkt~+pgk&<7_ zrw#p}+XT|ismYxz$L{3Skad0;UDJ@zhuKN-UY>>&-%=rqznem4WKx|!?nK71p_P2j zI`aIvFQ>?}3*hGWC&je-1hg6yDSe!stb(VM@v5KXn^j>i$U%}hd_p97Eiw9C-HE|^ z2g0u2EFGyEmhO7jsvgbxUVZ55r&pee%c`!rv7egf|9B#aE-KrKQi|$4+uM3tt*T+I zJ+(QbtY`9o=kh=5>o9v=>~JPm)^5*KRr@v}y1Cl7zeih^Ue*mW{G*Vzyn~YmcG_-G zR^@mJtq3$J>T0flLk~gXBMw~)FJyTC;l1u`#|zC_)maWDK=|u8Wx%4M11jyu6Y?cqNS4Zg@9$Y{VRl8tL0e(%8P4Q)HvizUZ$EQ3*;7i*P*WABp70M$pX; zO>nV`sY8XrtL#eB{U@7IPKFiW%Z%z_Sy4=GoR6V*RSvqPzpBz0nsY*RK`Qj$Q`ct6K1N{Ne+kt)`=;|j0>o%ZY2f7>hbwKY2+Fd7D z9|8I)!@)@n%=wKknM>g=I}JhCCadt@`gPl?f_v(@TCSm0HGM|I5$Zfpbq)0mT3dZ> zowMEvea%8gM{S4GCVA*{@>Iguxkecr7C0Y95j^5#BO4BDhfH^Q4%&zoW7y%`yn5}Yg| z&emmCr|yz^;cA?RmS$BA$^hiW@9~#v`3RZu-55o25P{ z#>Jxb+PBd<2NXC(3urHn<34#nPAmRI))fEFp)ov-GQ5R%|JJdsuA>gbuI40~2C=JO zbXW{qnzl5aku_^<(n&Zdnl&8_wxEUUsC`?JJp%uy0@cpQOz|L8<>Z2XOK4oO?5=-{ zELWzI(fayY@*-OfFS3>JBD>p+^$ITGt-W%7*Iv2690@%TK?SMjsw8Bq7rt1sD6TZ( zRBK1JIiC=eOZA@o$hMk1b@m9uJz$^RC)GVTk;G;69c(a240W&;89+J<(piwsVm)p6 zRyvy~L_!IXfU0z)qk)q&bVn`K22QRi+D=O;>cNTl^uY<64X;r`W%_q0KeW;^v>APX z>;NwoDFQanJX{13H(4cA2hlgNA}~{N(XfotQSN|`^rh0i(vP8EC{kRtsG9U{Ds;?q zraIGWw$#)&jH>=}1{@aKJeNk}Z+o}X+7YUaYPFSZ0#!11DFxM}rd}mvIp{!w7A=kw zlx>%Kehtx__Igrc_o*sSvGDJ65%@For^O3$<$<4LrLeiI+PU$Vori7jkA!wlCpwg^ zt-8(6JIX>86POJ1uK6wa;(OXzS57qQdw6arSx53%y%2j>wF;>pO6*B#?z>#u{XS zojHSIc?z>XE7&W$CIw9QMmhCZk?75~o-(V&1XSQF)WWE!GwvqgM&v80V)ywvHf? zK1F{;Bdkw&i{2jzeK}3Hs)X!ZeZuo$yz02f=!eCJg>|`0sAJQDD>t9o5*A+1&BONz zr*fC!0bxAXwDh6r0Wq)PnO_?n`ytC1eewL^2Kq)L-D({gbvGEhnb#tr+qVU4-cPm2 z7ia!a6-ida(Xq?p*hhIWysHdY;bG5>B{dKZk8LL>imc0m6iL#`l% ywnBdt+P_1C;wZ*@BOWndLmP)i>Zp&P{X&>2SeEu;)4TkZAGI+xprSVcUj&wx-&x(RDj0 zcGY&>KBl`xxwcl@-f9c-Xj)NuRIPnj?@dI!_}EJ8V=QUE4ie4CBia86c)#v`n~yW+ z%>O+8zw>_&-K&qTYWNJN#$+Of@z9RsMtVM7e54;$F|7!G2KbA~6wYJY#8X2^`ue`B z2qA1p$wCa7O&M*sg&9;em7dxBIc1_^zo(EP2cboXq4H;C3bzz<6lB$Od9Fl?|{4-gf09>E$+8 zYdH98JC5AxP+K@S(C+e}KCM#0nE~s)!94T0OFz2FT^EF^8VT(eVV!2&n&oYTRvbbG zS1aRDl#~YE-aro`gVu_qPX?LRoq)>a0qTndcGW^fpBBB)bE9H8J(PK(l!?7X5r*M-`?7m?Hpy8T8Zyrf@IPqbqMnPL#l zN}2UmlaeEv?*?R~x51sMOJ*({Je2%9kUG!U1#q49$Y|gwsZkahq6{g_AZC#Ow$|sw ziaxMmDLgoIeva7dtH zcP1SRSvjf!#I{3|ysPP=xP&98W2rtQd=UFNwIn30itC|%92WkdO`hPk@$eWqQKFGhsZ- z+@gx82Q38sxLWN_D_2u=NhAzB(1?y)o)}KajprCAlBN!`&Y573*hs8aU!(xQ+D1J{ zV|^QWzS4%;^`KkfPdWoHdy*GsxWgGLF4dQ~AgP$(!qT`Q!^CiKdU%2(rEG$OZJYqQ zknfLo=*tpHQF?CV7R-4om*qmzHjpQh9u8rH2Jo%{yw;X6fLAABTH!@)ax3kuDY_x* zx%=V>V+NQL;5`^+7=AA*audm8cT>5qG$^?kj<&>iU%O39)br_?4+}dICh{{Jsm_F! zY^MPvFqN|c$O9oIM=01(Q-r1!dX)`Q>tsig`=a`OSCZQ%DX8nBsYK`QR`+%3-0S+c z(K^=^F&xBUL!-S?*I4N^yK9Q@>|D15s=0H10<2xGzVi3Ah&?B(tmot?Yn>ds$ZB!# zmK9bdyIWRTV;vI#j3ojFA2I`&RUs9Cv5bJpYVnQe%>!y{7SUuyDL7aA=*=T)`%L(1 zoF)FR1IYZF*9aI<;6{Mg9Wvl=Y%=zq_ZkIv_9pqWw0S_WQ+tvdRG+M#zN>3rz=Cc8vMnApKOuD_s#kVeiX=lbJxh`qp*2h|GdcN zbrGb$-wZLa^fR#Yuw_>R#OZBKpqfmG(vQoE+?pZ-r#uu6Mh{z@3NB(NnMhi@ZJ#{O zigVQ#bVt~B?Y2&0kPf{`t)pJ1($GBWRi4@>C!lcf#4wWL2j6q-ll6wZuJhsuwGpW5 z!CD8heCs7y`;7R`0+?CEy2;I0*L6MuawF+MoEzVk4OT+g4*ke@TVzbqf`0(cE>lTm z>ayu^z8xU3*Ua*CFyM455E8`MHkeqX$IOE~z@a21E9Bk50Dk@-8X>M-hy z!LdDt=~}YG8fWR?yHg5!+~J@RQpmB<1tiQrHT<23rhf{{60I7`$KCkA5}B1ydv-En zjL-%rAZE;He@Ty+(xeeuKaAChh*5ovq)l++BrQpgM~8{TD3I7>kvUx9rsUX1F{?Uc z=H?^GFpvV`PI{xly{B-7x5Awp$*6_HAGryTzM+p?Eqy31-K*&fTRWOU!LqQn5u%4h z<(&;eyr$;wt~i3)o)qRK8TqL0OhmG6qo7~&m!ZA^QqL@_Ac)Y)V&OzWJ%<#J27F~wMFlb_P<<$PFa&j+IWO>Ty?y71?EY}S`4&jp7Ye=!@gpzrCd}LrH$-;4QBPc=AHbz( zL&066dta%i-96&k$O=BP;tqjt#TGuWv7VR#17^Tm{!V-ji0k@K(E*WlpX$$#uVo+= z&^kMF*aTKWvE8>uOf~P`vicEQJqiU-USM%OF=o|aVkCn=;RCnoz{9LMsZ7BKZ1u!) zqjIq&@7~;cBqiOCyaR~e>Y2k7FUKzY1P)FFT(oy$Ck+$n^?=i0YQYvWr}u?}dxnpK z-Q@+2*QpLOz=|;X8mc)Y1!UsfKdAHW*42G|tCI)V^q(Qyln>toOV(>MNbpq9{sIy_ zb=@RLpze*N-v<5M7IiHTtPLa1-Xp(yvm0FXvB8`c0~mBSL zUb>k8DbEK6zrJpK3ChR|JYT1Gcl384qKId1#(j-`2O;s&X@Ul8} zO-<3`H`OHKPl9EO>QLLlnOsX0Gt1u%qS-a;%mGK_rwHvTp zh9;DyX3$$s+z@uBK8p7XXH%2;$A%;kst~9!N7Bj2Vsc&rDL0_1Pi-HeVTXPVNhahl z%qdEcbG}o@(Wel5@@FdBRYd46&-4YU9P9p8)9CL^gQ~~-heivWK9b>}N`?$)cIX<7 z9JwT08J*sO4gF9A&=4qVie&Na`^btcsw?}Q$b8E?lS_qA(<$so%PzhS*5dP#>g9_1 zB*^+pkuowRWEYhD<{Lf|H2Mds;2b3VHgG~DiXRicAre>*#1oOhZR1sq0>0H2z&8{p zj5D5P$Q$^0zTh>bQ;IC%o@plOGT5X-GNo`JoV4t`tjHnJ@FeuEB0|scJW)bpC3j)j zA4}M^$uY?a!4~6PS|ZpqUg~buOu?q~E+Ur~cCl0VE9#*OY$dV`UB2$Lm#_iXQhQ+k z((7gOV1;0NsyiR{{Zr&w(S6{qD*nLT|5zf}R>SxTjE}*1C5*p-@v`-T?MWEF3*$zh zFNN`2Fm{&yt1NFXRlaO?yPV^UzXrF zxaOdfWW|GJL|%@tTU4>9L^b=R$gu6AhHVw2*yCa}+akuWUx;H^j|hVKAw88JpM$C- zPr(8TAJp%3r)@?OPrqkVb>~MEM4SP{-rAvg^sx_?y}A?m?MjtjIsRmS6t#Zq?oAJE zxR~-e<7s;1_@f2Sp{JjXd#K(Pb3XgA**mieKEJ!4SN?Yv5uExeoO4Bds$Ai>Yrl1S zWwa7Yw8|DhybWjBdjHKfgR}K2sRRh*Rf~}^%HAO(%LO^btj)#-G(h+3?5E|FoMYlO z`NfV4a(d4R8KE7C8wy#J-jwrts~6*G^LlxNBTWB@CPmpZ>}O;&m9RYx&PGgw7#y*$9BAOyI7zQx z2Kh^8^^Dux0f1sk5Sz&1?5j;5+NeGQMR#i)T2oS$wG||la9T#mCfSezeWFR$ru2f) z5%bdMc|rJ|xFLKsX$Izm;G{`P4(JO6<775s)z}mczAh}B?BK~BQhOb9DDmqJ|G1nI z8Y^F{jLA<3RIRS&Xup!0>n#mbE#0tY!se#pD)4qBZ5eC?WI9(viOvPrHk$&Wa=4rM za??9Dbmv?Zxx*R2uVK%~2{~tEZO)$oH;V2Z%|V+gxc6WnUi-B9*4L{nsO zc*&W&<;(_TIwxlt&dDOszqJRm8_(to7YgatC#0KOG|Ogss53&Q@JM>BvmtEUrFGp;&tGSZ5 zN3a=b)OW0^oR05;&3i2cPb^Q~tQ1stwG}EM)j|8CbtqjUC~JRgdJR+=vo$V~tJMBt zefOw#zJdNYc*>&vrM<;ET3A}J%;{<_;Q;93Q1G$gF%Ej~Uj5Qtj>3NQCWKx{MjxmqLso0k$~d^jw7Tb>H?o-h8t5~{*B}UWL(~H`fVwA<_S5fm zB9ZhpIpM&QJm?8c7G$RCPSYEO{JlAFus%oCr^RRUuc+sAmG*LpYQF~iWG0zWr*&x* zGrDrtZg3ReVQ`JDrkyduEQ`~ ztoFj%v+C$B%y!7a$&C2u69ahmQIRp87gq__GA2=LhXs`-liEEX%(7(Qxx#A86kIRt zuvj$XhTFu9%1y6L5sq7usV@eFZp-syHP**VN!%iuiR8xS<(WDhn*d?tLDOdmo2Pw( zspiR9v+Qxdl7 Q5Mx$CctkN|5eh^5ACb#>UjP6A diff --git a/test-devices/composite-stm32/bin/blackpill-f411ce.bin b/test-devices/composite-stm32/bin/blackpill-f411ce.bin index 1f9993c74e352fa004c6dfbff0cc1c0624452f7d..e3ba54a6c179771c33d21462a5a804a871b96578 100755 GIT binary patch delta 5859 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 delta 5460 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 NzCNN1vIt4g{tr@f=t=+p diff --git a/test-devices/composite-stm32/copy_tinyusb.sh b/test-devices/composite-stm32/copy_tinyusb.sh new file mode 100755 index 00000000..1b1a2f3b --- /dev/null +++ b/test-devices/composite-stm32/copy_tinyusb.sh @@ -0,0 +1,17 @@ +#!/bin/sh +TINYUSB_DIR=../../../tinyusb +rm -rf lib/tinyusb/* +mkdir lib/tinyusb/osal +mkdir lib/tinyusb/class +mkdir lib/tinyusb/portable +mkdir lib/tinyusb/portable/synopsys +mkdir lib/tinyusb/portable/st +cp -R $TINYUSB_DIR/src/class/cdc lib/tinyusb/class +cp -R $TINYUSB_DIR/src/common lib/tinyusb +cp -R $TINYUSB_DIR/src/device lib/tinyusb +cp $TINYUSB_DIR/src/osal/osal.h lib/tinyusb/osal +cp $TINYUSB_DIR/src/osal/osal_none.h lib/tinyusb/osal +cp -R $TINYUSB_DIR/src/portable/synopsys/dwc2 lib/tinyusb/portable/synopsys +cp -R $TINYUSB_DIR/src/portable/st/stm32_fsdev lib/tinyusb/portable/st +cp $TINYUSB_DIR/src/*.c lib/tinyusb +cp $TINYUSB_DIR/src/*.h lib/tinyusb diff --git a/test-devices/composite-stm32/lib/tinyusb/class/audio/audio.h b/test-devices/composite-stm32/lib/tinyusb/class/audio/audio.h deleted file mode 100644 index 70d43128..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/audio/audio.h +++ /dev/null @@ -1,935 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * Copyright (c) 2020 Reinhard Panhuber - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -/** \ingroup group_class - * \defgroup ClassDriver_Audio Audio - * Currently only MIDI subclass is supported - * @{ */ - -#ifndef _TUSB_AUDIO_H__ -#define _TUSB_AUDIO_H__ - -#include "common/tusb_common.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/// Audio Device Class Codes - -/// A.2 - Audio Function Subclass Codes -typedef enum -{ - AUDIO_FUNCTION_SUBCLASS_UNDEFINED = 0x00, -} audio_function_subclass_type_t; - -/// A.3 - Audio Function Protocol Codes -typedef enum -{ - AUDIO_FUNC_PROTOCOL_CODE_UNDEF = 0x00, - AUDIO_FUNC_PROTOCOL_CODE_V2 = 0x20, ///< Version 2.0 -} audio_function_protocol_code_t; - -/// A.5 - Audio Interface Subclass Codes -typedef enum -{ - AUDIO_SUBCLASS_UNDEFINED = 0x00, - AUDIO_SUBCLASS_CONTROL , ///< Audio Control - AUDIO_SUBCLASS_STREAMING , ///< Audio Streaming - AUDIO_SUBCLASS_MIDI_STREAMING , ///< MIDI Streaming -} audio_subclass_type_t; - -/// A.6 - Audio Interface Protocol Codes -typedef enum -{ - AUDIO_INT_PROTOCOL_CODE_UNDEF = 0x00, - AUDIO_INT_PROTOCOL_CODE_V2 = 0x20, ///< Version 2.0 -} audio_interface_protocol_code_t; - -/// A.7 - Audio Function Category Codes -typedef enum -{ - AUDIO_FUNC_UNDEF = 0x00, - AUDIO_FUNC_DESKTOP_SPEAKER = 0x01, - AUDIO_FUNC_HOME_THEATER = 0x02, - AUDIO_FUNC_MICROPHONE = 0x03, - AUDIO_FUNC_HEADSET = 0x04, - AUDIO_FUNC_TELEPHONE = 0x05, - AUDIO_FUNC_CONVERTER = 0x06, - AUDIO_FUNC_SOUND_RECODER = 0x07, - AUDIO_FUNC_IO_BOX = 0x08, - AUDIO_FUNC_MUSICAL_INSTRUMENT = 0x09, - AUDIO_FUNC_PRO_AUDIO = 0x0A, - AUDIO_FUNC_AUDIO_VIDEO = 0x0B, - AUDIO_FUNC_CONTROL_PANEL = 0x0C, - AUDIO_FUNC_OTHER = 0xFF, -} audio_function_code_t; - -/// A.9 - Audio Class-Specific AC Interface Descriptor Subtypes UAC2 -typedef enum -{ - AUDIO_CS_AC_INTERFACE_AC_DESCRIPTOR_UNDEF = 0x00, - AUDIO_CS_AC_INTERFACE_HEADER = 0x01, - AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL = 0x02, - AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL = 0x03, - AUDIO_CS_AC_INTERFACE_MIXER_UNIT = 0x04, - AUDIO_CS_AC_INTERFACE_SELECTOR_UNIT = 0x05, - AUDIO_CS_AC_INTERFACE_FEATURE_UNIT = 0x06, - AUDIO_CS_AC_INTERFACE_EFFECT_UNIT = 0x07, - AUDIO_CS_AC_INTERFACE_PROCESSING_UNIT = 0x08, - AUDIO_CS_AC_INTERFACE_EXTENSION_UNIT = 0x09, - AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE = 0x0A, - AUDIO_CS_AC_INTERFACE_CLOCK_SELECTOR = 0x0B, - AUDIO_CS_AC_INTERFACE_CLOCK_MULTIPLIER = 0x0C, - AUDIO_CS_AC_INTERFACE_SAMPLE_RATE_CONVERTER = 0x0D, -} audio_cs_ac_interface_subtype_t; - -/// A.10 - Audio Class-Specific AS Interface Descriptor Subtypes UAC2 -typedef enum -{ - AUDIO_CS_AS_INTERFACE_AS_DESCRIPTOR_UNDEF = 0x00, - AUDIO_CS_AS_INTERFACE_AS_GENERAL = 0x01, - AUDIO_CS_AS_INTERFACE_FORMAT_TYPE = 0x02, - AUDIO_CS_AS_INTERFACE_ENCODER = 0x03, - AUDIO_CS_AS_INTERFACE_DECODER = 0x04, -} audio_cs_as_interface_subtype_t; - -/// A.11 - Effect Unit Effect Types -typedef enum -{ - AUDIO_EFFECT_TYPE_UNDEF = 0x00, - AUDIO_EFFECT_TYPE_PARAM_EQ_SECTION = 0x01, - AUDIO_EFFECT_TYPE_REVERBERATION = 0x02, - AUDIO_EFFECT_TYPE_MOD_DELAY = 0x03, - AUDIO_EFFECT_TYPE_DYN_RANGE_COMP = 0x04, -} audio_effect_unit_effect_type_t; - -/// A.12 - Processing Unit Process Types -typedef enum -{ - AUDIO_PROCESS_TYPE_UNDEF = 0x00, - AUDIO_PROCESS_TYPE_UP_DOWN_MIX = 0x01, - AUDIO_PROCESS_TYPE_DOLBY_PROLOGIC = 0x02, - AUDIO_PROCESS_TYPE_STEREO_EXTENDER = 0x03, -} audio_processing_unit_process_type_t; - -/// A.13 - Audio Class-Specific EP Descriptor Subtypes UAC2 -typedef enum -{ - AUDIO_CS_EP_SUBTYPE_UNDEF = 0x00, - AUDIO_CS_EP_SUBTYPE_GENERAL = 0x01, -} audio_cs_ep_subtype_t; - -/// A.14 - Audio Class-Specific Request Codes -typedef enum -{ - AUDIO_CS_REQ_UNDEF = 0x00, - AUDIO_CS_REQ_CUR = 0x01, - AUDIO_CS_REQ_RANGE = 0x02, - AUDIO_CS_REQ_MEM = 0x03, -} audio_cs_req_t; - -/// A.17 - Control Selector Codes - -/// A.17.1 - Clock Source Control Selectors -typedef enum -{ - AUDIO_CS_CTRL_UNDEF = 0x00, - AUDIO_CS_CTRL_SAM_FREQ = 0x01, - AUDIO_CS_CTRL_CLK_VALID = 0x02, -} audio_clock_src_control_selector_t; - -/// A.17.2 - Clock Selector Control Selectors -typedef enum -{ - AUDIO_CX_CTRL_UNDEF = 0x00, - AUDIO_CX_CTRL_CONTROL = 0x01, -} audio_clock_sel_control_selector_t; - -/// A.17.3 - Clock Multiplier Control Selectors -typedef enum -{ - AUDIO_CM_CTRL_UNDEF = 0x00, - AUDIO_CM_CTRL_NUMERATOR_CONTROL = 0x01, - AUDIO_CM_CTRL_DENOMINATOR_CONTROL = 0x02, -} audio_clock_mul_control_selector_t; - -/// A.17.4 - Terminal Control Selectors -typedef enum -{ - AUDIO_TE_CTRL_UNDEF = 0x00, - AUDIO_TE_CTRL_COPY_PROTECT = 0x01, - AUDIO_TE_CTRL_CONNECTOR = 0x02, - AUDIO_TE_CTRL_OVERLOAD = 0x03, - AUDIO_TE_CTRL_CLUSTER = 0x04, - AUDIO_TE_CTRL_UNDERFLOW = 0x05, - AUDIO_TE_CTRL_OVERFLOW = 0x06, - AUDIO_TE_CTRL_LATENCY = 0x07, -} audio_terminal_control_selector_t; - -/// A.17.5 - Mixer Control Selectors -typedef enum -{ - AUDIO_MU_CTRL_UNDEF = 0x00, - AUDIO_MU_CTRL_MIXER = 0x01, - AUDIO_MU_CTRL_CLUSTER = 0x02, - AUDIO_MU_CTRL_UNDERFLOW = 0x03, - AUDIO_MU_CTRL_OVERFLOW = 0x04, - AUDIO_MU_CTRL_LATENCY = 0x05, -} audio_mixer_control_selector_t; - -/// A.17.6 - Selector Control Selectors -typedef enum -{ - AUDIO_SU_CTRL_UNDEF = 0x00, - AUDIO_SU_CTRL_SELECTOR = 0x01, - AUDIO_SU_CTRL_LATENCY = 0x02, -} audio_sel_control_selector_t; - -/// A.17.7 - Feature Unit Control Selectors -typedef enum -{ - AUDIO_FU_CTRL_UNDEF = 0x00, - AUDIO_FU_CTRL_MUTE = 0x01, - AUDIO_FU_CTRL_VOLUME = 0x02, - AUDIO_FU_CTRL_BASS = 0x03, - AUDIO_FU_CTRL_MID = 0x04, - AUDIO_FU_CTRL_TREBLE = 0x05, - AUDIO_FU_CTRL_GRAPHIC_EQUALIZER = 0x06, - AUDIO_FU_CTRL_AGC = 0x07, - AUDIO_FU_CTRL_DELAY = 0x08, - AUDIO_FU_CTRL_BASS_BOOST = 0x09, - AUDIO_FU_CTRL_LOUDNESS = 0x0A, - AUDIO_FU_CTRL_INPUT_GAIN = 0x0B, - AUDIO_FU_CTRL_GAIN_PAD = 0x0C, - AUDIO_FU_CTRL_INVERTER = 0x0D, - AUDIO_FU_CTRL_UNDERFLOW = 0x0E, - AUDIO_FU_CTRL_OVERVLOW = 0x0F, - AUDIO_FU_CTRL_LATENCY = 0x10, -} audio_feature_unit_control_selector_t; - -/// A.17.8 Effect Unit Control Selectors - -/// A.17.8.1 Parametric Equalizer Section Effect Unit Control Selectors -typedef enum -{ - AUDIO_PE_CTRL_UNDEF = 0x00, - AUDIO_PE_CTRL_ENABLE = 0x01, - AUDIO_PE_CTRL_CENTERFREQ = 0x02, - AUDIO_PE_CTRL_QFACTOR = 0x03, - AUDIO_PE_CTRL_GAIN = 0x04, - AUDIO_PE_CTRL_UNDERFLOW = 0x05, - AUDIO_PE_CTRL_OVERFLOW = 0x06, - AUDIO_PE_CTRL_LATENCY = 0x07, -} audio_parametric_equalizer_control_selector_t; - -/// A.17.8.2 Reverberation Effect Unit Control Selectors -typedef enum -{ - AUDIO_RV_CTRL_UNDEF = 0x00, - AUDIO_RV_CTRL_ENABLE = 0x01, - AUDIO_RV_CTRL_TYPE = 0x02, - AUDIO_RV_CTRL_LEVEL = 0x03, - AUDIO_RV_CTRL_TIME = 0x04, - AUDIO_RV_CTRL_FEEDBACK = 0x05, - AUDIO_RV_CTRL_PREDELAY = 0x06, - AUDIO_RV_CTRL_DENSITY = 0x07, - AUDIO_RV_CTRL_HIFREQ_ROLLOFF = 0x08, - AUDIO_RV_CTRL_UNDERFLOW = 0x09, - AUDIO_RV_CTRL_OVERFLOW = 0x0A, - AUDIO_RV_CTRL_LATENCY = 0x0B, -} audio_reverberation_effect_control_selector_t; - -/// A.17.8.3 Modulation Delay Effect Unit Control Selectors -typedef enum -{ - AUDIO_MD_CTRL_UNDEF = 0x00, - AUDIO_MD_CTRL_ENABLE = 0x01, - AUDIO_MD_CTRL_BALANCE = 0x02, - AUDIO_MD_CTRL_RATE = 0x03, - AUDIO_MD_CTRL_DEPTH = 0x04, - AUDIO_MD_CTRL_TIME = 0x05, - AUDIO_MD_CTRL_FEEDBACK = 0x06, - AUDIO_MD_CTRL_UNDERFLOW = 0x07, - AUDIO_MD_CTRL_OVERFLOW = 0x08, - AUDIO_MD_CTRL_LATENCY = 0x09, -} audio_modulation_delay_control_selector_t; - -/// A.17.8.4 Dynamic Range Compressor Effect Unit Control Selectors -typedef enum -{ - AUDIO_DR_CTRL_UNDEF = 0x00, - AUDIO_DR_CTRL_ENABLE = 0x01, - AUDIO_DR_CTRL_COMPRESSION_RATE = 0x02, - AUDIO_DR_CTRL_MAXAMPL = 0x03, - AUDIO_DR_CTRL_THRESHOLD = 0x04, - AUDIO_DR_CTRL_ATTACK_TIME = 0x05, - AUDIO_DR_CTRL_RELEASE_TIME = 0x06, - AUDIO_DR_CTRL_UNDERFLOW = 0x07, - AUDIO_DR_CTRL_OVERFLOW = 0x08, - AUDIO_DR_CTRL_LATENCY = 0x09, -} audio_dynamic_range_compression_control_selector_t; - -/// A.17.9 Processing Unit Control Selectors - -/// A.17.9.1 Up/Down-mix Processing Unit Control Selectors -typedef enum -{ - AUDIO_UD_CTRL_UNDEF = 0x00, - AUDIO_UD_CTRL_ENABLE = 0x01, - AUDIO_UD_CTRL_MODE_SELECT = 0x02, - AUDIO_UD_CTRL_CLUSTER = 0x03, - AUDIO_UD_CTRL_UNDERFLOW = 0x04, - AUDIO_UD_CTRL_OVERFLOW = 0x05, - AUDIO_UD_CTRL_LATENCY = 0x06, -} audio_up_down_mix_control_selector_t; - -/// A.17.9.2 Dolby Prologic ™ Processing Unit Control Selectors -typedef enum -{ - AUDIO_DP_CTRL_UNDEF = 0x00, - AUDIO_DP_CTRL_ENABLE = 0x01, - AUDIO_DP_CTRL_MODE_SELECT = 0x02, - AUDIO_DP_CTRL_CLUSTER = 0x03, - AUDIO_DP_CTRL_UNDERFLOW = 0x04, - AUDIO_DP_CTRL_OVERFLOW = 0x05, - AUDIO_DP_CTRL_LATENCY = 0x06, -} audio_dolby_prologic_control_selector_t; - -/// A.17.9.3 Stereo Extender Processing Unit Control Selectors -typedef enum -{ - AUDIO_ST_EXT_CTRL_UNDEF = 0x00, - AUDIO_ST_EXT_CTRL_ENABLE = 0x01, - AUDIO_ST_EXT_CTRL_WIDTH = 0x02, - AUDIO_ST_EXT_CTRL_UNDERFLOW = 0x03, - AUDIO_ST_EXT_CTRL_OVERFLOW = 0x04, - AUDIO_ST_EXT_CTRL_LATENCY = 0x05, -} audio_stereo_extender_control_selector_t; - -/// A.17.10 Extension Unit Control Selectors -typedef enum -{ - AUDIO_XU_CTRL_UNDEF = 0x00, - AUDIO_XU_CTRL_ENABLE = 0x01, - AUDIO_XU_CTRL_CLUSTER = 0x02, - AUDIO_XU_CTRL_UNDERFLOW = 0x03, - AUDIO_XU_CTRL_OVERFLOW = 0x04, - AUDIO_XU_CTRL_LATENCY = 0x05, -} audio_extension_unit_control_selector_t; - -/// A.17.11 AudioStreaming Interface Control Selectors -typedef enum -{ - AUDIO_AS_CTRL_UNDEF = 0x00, - AUDIO_AS_CTRL_ACT_ALT_SETTING = 0x01, - AUDIO_AS_CTRL_VAL_ALT_SETTINGS = 0x02, - AUDIO_AS_CTRL_AUDIO_DATA_FORMAT = 0x03, -} audio_audiostreaming_interface_control_selector_t; - -/// A.17.12 Encoder Control Selectors -typedef enum -{ - AUDIO_EN_CTRL_UNDEF = 0x00, - AUDIO_EN_CTRL_BIT_RATE = 0x01, - AUDIO_EN_CTRL_QUALITY = 0x02, - AUDIO_EN_CTRL_VBR = 0x03, - AUDIO_EN_CTRL_TYPE = 0x04, - AUDIO_EN_CTRL_UNDERFLOW = 0x05, - AUDIO_EN_CTRL_OVERFLOW = 0x06, - AUDIO_EN_CTRL_ENCODER_ERROR = 0x07, - AUDIO_EN_CTRL_PARAM1 = 0x08, - AUDIO_EN_CTRL_PARAM2 = 0x09, - AUDIO_EN_CTRL_PARAM3 = 0x0A, - AUDIO_EN_CTRL_PARAM4 = 0x0B, - AUDIO_EN_CTRL_PARAM5 = 0x0C, - AUDIO_EN_CTRL_PARAM6 = 0x0D, - AUDIO_EN_CTRL_PARAM7 = 0x0E, - AUDIO_EN_CTRL_PARAM8 = 0x0F, -} audio_encoder_control_selector_t; - -/// A.17.13 Decoder Control Selectors - -/// A.17.13.1 MPEG Decoder Control Selectors -typedef enum -{ - AUDIO_MPD_CTRL_UNDEF = 0x00, - AUDIO_MPD_CTRL_DUAL_CHANNEL = 0x01, - AUDIO_MPD_CTRL_SECOND_STEREO = 0x02, - AUDIO_MPD_CTRL_MULTILINGUAL = 0x03, - AUDIO_MPD_CTRL_DYN_RANGE = 0x04, - AUDIO_MPD_CTRL_SCALING = 0x05, - AUDIO_MPD_CTRL_HILO_SCALING = 0x06, - AUDIO_MPD_CTRL_UNDERFLOW = 0x07, - AUDIO_MPD_CTRL_OVERFLOW = 0x08, - AUDIO_MPD_CTRL_DECODER_ERROR = 0x09, -} audio_MPEG_decoder_control_selector_t; - -/// A.17.13.2 AC-3 Decoder Control Selectors -typedef enum -{ - AUDIO_AD_CTRL_UNDEF = 0x00, - AUDIO_AD_CTRL_MODE = 0x01, - AUDIO_AD_CTRL_DYN_RANGE = 0x02, - AUDIO_AD_CTRL_SCALING = 0x03, - AUDIO_AD_CTRL_HILO_SCALING = 0x04, - AUDIO_AD_CTRL_UNDERFLOW = 0x05, - AUDIO_AD_CTRL_OVERFLOW = 0x06, - AUDIO_AD_CTRL_DECODER_ERROR = 0x07, -} audio_AC3_decoder_control_selector_t; - -/// A.17.13.3 WMA Decoder Control Selectors -typedef enum -{ - AUDIO_WD_CTRL_UNDEF = 0x00, - AUDIO_WD_CTRL_UNDERFLOW = 0x01, - AUDIO_WD_CTRL_OVERFLOW = 0x02, - AUDIO_WD_CTRL_DECODER_ERROR = 0x03, -} audio_WMA_decoder_control_selector_t; - -/// A.17.13.4 DTS Decoder Control Selectors -typedef enum -{ - AUDIO_DD_CTRL_UNDEF = 0x00, - AUDIO_DD_CTRL_UNDERFLOW = 0x01, - AUDIO_DD_CTRL_OVERFLOW = 0x02, - AUDIO_DD_CTRL_DECODER_ERROR = 0x03, -} audio_DTS_decoder_control_selector_t; - -/// A.17.14 Endpoint Control Selectors -typedef enum -{ - AUDIO_EP_CTRL_UNDEF = 0x00, - AUDIO_EP_CTRL_PITCH = 0x01, - AUDIO_EP_CTRL_DATA_OVERRUN = 0x02, - AUDIO_EP_CTRL_DATA_UNDERRUN = 0x03, -} audio_EP_control_selector_t; - -/// Terminal Types - -/// 2.1 - Audio Class-Terminal Types UAC2 -typedef enum -{ - AUDIO_TERM_TYPE_USB_UNDEFINED = 0x0100, - AUDIO_TERM_TYPE_USB_STREAMING = 0x0101, - AUDIO_TERM_TYPE_USB_VENDOR_SPEC = 0x01FF, -} audio_terminal_type_t; - -/// 2.2 - Audio Class-Input Terminal Types UAC2 -typedef enum -{ - AUDIO_TERM_TYPE_IN_UNDEFINED = 0x0200, - AUDIO_TERM_TYPE_IN_GENERIC_MIC = 0x0201, - AUDIO_TERM_TYPE_IN_DESKTOP_MIC = 0x0202, - AUDIO_TERM_TYPE_IN_PERSONAL_MIC = 0x0203, - AUDIO_TERM_TYPE_IN_OMNI_MIC = 0x0204, - AUDIO_TERM_TYPE_IN_ARRAY_MIC = 0x0205, - AUDIO_TERM_TYPE_IN_PROC_ARRAY_MIC = 0x0206, -} audio_terminal_input_type_t; - -/// 2.3 - Audio Class-Output Terminal Types UAC2 -typedef enum -{ - AUDIO_TERM_TYPE_OUT_UNDEFINED = 0x0300, - AUDIO_TERM_TYPE_OUT_GENERIC_SPEAKER = 0x0301, - AUDIO_TERM_TYPE_OUT_HEADPHONES = 0x0302, - AUDIO_TERM_TYPE_OUT_HEAD_MNT_DISP_AUIDO = 0x0303, - AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER = 0x0304, - AUDIO_TERM_TYPE_OUT_ROOM_SPEAKER = 0x0305, - AUDIO_TERM_TYPE_OUT_COMMUNICATION_SPEAKER = 0x0306, - AUDIO_TERM_TYPE_OUT_LOW_FRQ_EFFECTS_SPEAKER = 0x0307, -} audio_terminal_output_type_t; - -/// Rest is yet to be implemented - -/// Additional Audio Device Class Codes - Source: Audio Data Formats - -/// A.1 - Audio Class-Format Type Codes UAC2 -typedef enum -{ - AUDIO_FORMAT_TYPE_UNDEFINED = 0x00, - AUDIO_FORMAT_TYPE_I = 0x01, - AUDIO_FORMAT_TYPE_II = 0x02, - AUDIO_FORMAT_TYPE_III = 0x03, - AUDIO_FORMAT_TYPE_IV = 0x04, - AUDIO_EXT_FORMAT_TYPE_I = 0x81, - AUDIO_EXT_FORMAT_TYPE_II = 0x82, - AUDIO_EXT_FORMAT_TYPE_III = 0x83, -} audio_format_type_t; - -// A.2.1 - Audio Class-Audio Data Format Type I UAC2 -typedef enum -{ - AUDIO_DATA_FORMAT_TYPE_I_PCM = (uint32_t) (1 << 0), - AUDIO_DATA_FORMAT_TYPE_I_PCM8 = (uint32_t) (1 << 1), - AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT = (uint32_t) (1 << 2), - AUDIO_DATA_FORMAT_TYPE_I_ALAW = (uint32_t) (1 << 3), - AUDIO_DATA_FORMAT_TYPE_I_MULAW = (uint32_t) (1 << 4), - AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA = 0x80000000, -} audio_data_format_type_I_t; - -/// All remaining definitions are taken from the descriptor descriptions in the UAC2 main specification - -/// Audio Class-Control Values UAC2 -typedef enum -{ - AUDIO_CTRL_NONE = 0x00, ///< No Host access - AUDIO_CTRL_R = 0x01, ///< Host read access only - AUDIO_CTRL_RW = 0x03, ///< Host read write access -} audio_control_t; - -/// Audio Class-Specific AC Interface Descriptor Controls UAC2 -typedef enum -{ - AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS = 0, -} audio_cs_ac_interface_control_pos_t; - -/// Audio Class-Specific AS Interface Descriptor Controls UAC2 -typedef enum -{ - AUDIO_CS_AS_INTERFACE_CTRL_ACTIVE_ALT_SET_POS = 0, - AUDIO_CS_AS_INTERFACE_CTRL_VALID_ALT_SET_POS = 2, -} audio_cs_as_interface_control_pos_t; - -/// Audio Class-Specific AS Isochronous Data EP Attributes UAC2 -typedef enum -{ - AUDIO_CS_AS_ISO_DATA_EP_ATT_MAX_PACKETS_ONLY = 0x80, - AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK = 0x00, -} audio_cs_as_iso_data_ep_attribute_t; - -/// Audio Class-Specific AS Isochronous Data EP Controls UAC2 -typedef enum -{ - AUDIO_CS_AS_ISO_DATA_EP_CTRL_PITCH_POS = 0, - AUDIO_CS_AS_ISO_DATA_EP_CTRL_DATA_OVERRUN_POS = 2, - AUDIO_CS_AS_ISO_DATA_EP_CTRL_DATA_UNDERRUN_POS = 4, -} audio_cs_as_iso_data_ep_control_pos_t; - -/// Audio Class-Specific AS Isochronous Data EP Lock Delay Units UAC2 -typedef enum -{ - AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED = 0x00, - AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC = 0x01, - AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_PCM_SAMPLES = 0x02, -} audio_cs_as_iso_data_ep_lock_delay_unit_t; - -/// Audio Class-Clock Source Attributes UAC2 -typedef enum -{ - AUDIO_CLOCK_SOURCE_ATT_EXT_CLK = 0x00, - AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK = 0x01, - AUDIO_CLOCK_SOURCE_ATT_INT_VAR_CLK = 0x02, - AUDIO_CLOCK_SOURCE_ATT_INT_PRO_CLK = 0x03, - AUDIO_CLOCK_SOURCE_ATT_CLK_SYC_SOF = 0x04, -} audio_clock_source_attribute_t; - -/// Audio Class-Clock Source Controls UAC2 -typedef enum -{ - AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS = 0, - AUDIO_CLOCK_SOURCE_CTRL_CLK_VAL_POS = 2, -} audio_clock_source_control_pos_t; - -/// Audio Class-Clock Selector Controls UAC2 -typedef enum -{ - AUDIO_CLOCK_SELECTOR_CTRL_POS = 0, -} audio_clock_selector_control_pos_t; - -/// Audio Class-Clock Multiplier Controls UAC2 -typedef enum -{ - AUDIO_CLOCK_MULTIPLIER_CTRL_NUMERATOR_POS = 0, - AUDIO_CLOCK_MULTIPLIER_CTRL_DENOMINATOR_POS = 2, -} audio_clock_multiplier_control_pos_t; - -/// Audio Class-Input Terminal Controls UAC2 -typedef enum -{ - AUDIO_IN_TERM_CTRL_CPY_PROT_POS = 0, - AUDIO_IN_TERM_CTRL_CONNECTOR_POS = 2, - AUDIO_IN_TERM_CTRL_OVERLOAD_POS = 4, - AUDIO_IN_TERM_CTRL_CLUSTER_POS = 6, - AUDIO_IN_TERM_CTRL_UNDERFLOW_POS = 8, - AUDIO_IN_TERM_CTRL_OVERFLOW_POS = 10, -} audio_terminal_input_control_pos_t; - -/// Audio Class-Output Terminal Controls UAC2 -typedef enum -{ - AUDIO_OUT_TERM_CTRL_CPY_PROT_POS = 0, - AUDIO_OUT_TERM_CTRL_CONNECTOR_POS = 2, - AUDIO_OUT_TERM_CTRL_OVERLOAD_POS = 4, - AUDIO_OUT_TERM_CTRL_UNDERFLOW_POS = 6, - AUDIO_OUT_TERM_CTRL_OVERFLOW_POS = 8, -} audio_terminal_output_control_pos_t; - -/// Audio Class-Feature Unit Controls UAC2 -typedef enum -{ - AUDIO_FEATURE_UNIT_CTRL_MUTE_POS = 0, - AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS = 2, - AUDIO_FEATURE_UNIT_CTRL_BASS_POS = 4, - AUDIO_FEATURE_UNIT_CTRL_MID_POS = 6, - AUDIO_FEATURE_UNIT_CTRL_TREBLE_POS = 8, - AUDIO_FEATURE_UNIT_CTRL_GRAPHIC_EQU_POS = 10, - AUDIO_FEATURE_UNIT_CTRL_AGC_POS = 12, - AUDIO_FEATURE_UNIT_CTRL_DELAY_POS = 14, - AUDIO_FEATURE_UNIT_CTRL_BASS_BOOST_POS = 16, - AUDIO_FEATURE_UNIT_CTRL_LOUDNESS_POS = 18, - AUDIO_FEATURE_UNIT_CTRL_INPUT_GAIN_POS = 20, - AUDIO_FEATURE_UNIT_CTRL_INPUT_GAIN_PAD_POS = 22, - AUDIO_FEATURE_UNIT_CTRL_PHASE_INV_POS = 24, - AUDIO_FEATURE_UNIT_CTRL_UNDERFLOW_POS = 26, - AUDIO_FEATURE_UNIT_CTRL_OVERFLOW_POS = 28, -} audio_feature_unit_control_pos_t; - -/// Audio Class-Audio Channel Configuration UAC2 -typedef enum -{ - AUDIO_CHANNEL_CONFIG_NON_PREDEFINED = 0x00000000, - AUDIO_CHANNEL_CONFIG_FRONT_LEFT = 0x00000001, - AUDIO_CHANNEL_CONFIG_FRONT_RIGHT = 0x00000002, - AUDIO_CHANNEL_CONFIG_FRONT_CENTER = 0x00000004, - AUDIO_CHANNEL_CONFIG_LOW_FRQ_EFFECTS = 0x00000008, - AUDIO_CHANNEL_CONFIG_BACK_LEFT = 0x00000010, - AUDIO_CHANNEL_CONFIG_BACK_RIGHT = 0x00000020, - AUDIO_CHANNEL_CONFIG_FRONT_LEFT_OF_CENTER = 0x00000040, - AUDIO_CHANNEL_CONFIG_FRONT_RIGHT_OF_CENTER = 0x00000080, - AUDIO_CHANNEL_CONFIG_BACK_CENTER = 0x00000100, - AUDIO_CHANNEL_CONFIG_SIDE_LEFT = 0x00000200, - AUDIO_CHANNEL_CONFIG_SIDE_RIGHT = 0x00000400, - AUDIO_CHANNEL_CONFIG_TOP_CENTER = 0x00000800, - AUDIO_CHANNEL_CONFIG_TOP_FRONT_LEFT = 0x00001000, - AUDIO_CHANNEL_CONFIG_TOP_FRONT_CENTER = 0x00002000, - AUDIO_CHANNEL_CONFIG_TOP_FRONT_RIGHT = 0x00004000, - AUDIO_CHANNEL_CONFIG_TOP_BACK_LEFT = 0x00008000, - AUDIO_CHANNEL_CONFIG_TOP_BACK_CENTER = 0x00010000, - AUDIO_CHANNEL_CONFIG_TOP_BACK_RIGHT = 0x00020000, - AUDIO_CHANNEL_CONFIG_TOP_FRONT_LEFT_OF_CENTER = 0x00040000, - AUDIO_CHANNEL_CONFIG_TOP_FRONT_RIGHT_OF_CENTER = 0x00080000, - AUDIO_CHANNEL_CONFIG_LEFT_LOW_FRQ_EFFECTS = 0x00100000, - AUDIO_CHANNEL_CONFIG_RIGHT_LOW_FRQ_EFFECTS = 0x00200000, - AUDIO_CHANNEL_CONFIG_TOP_SIDE_LEFT = 0x00400000, - AUDIO_CHANNEL_CONFIG_TOP_SIDE_RIGHT = 0x00800000, - AUDIO_CHANNEL_CONFIG_BOTTOM_CENTER = 0x01000000, - AUDIO_CHANNEL_CONFIG_BACK_LEFT_OF_CENTER = 0x02000000, - AUDIO_CHANNEL_CONFIG_BACK_RIGHT_OF_CENTER = 0x04000000, - AUDIO_CHANNEL_CONFIG_RAW_DATA = 0x80000000, -} audio_channel_config_t; - -/// AUDIO Channel Cluster Descriptor (4.1) -typedef struct TU_ATTR_PACKED { - uint8_t bNrChannels; ///< Number of channels currently connected. - audio_channel_config_t bmChannelConfig; ///< Bitmap according to 'audio_channel_config_t' with a 1 set if channel is connected and 0 else. In case channels are non-predefined ignore them here (see UAC2 specification 4.1 Audio Channel Cluster Descriptor. - uint8_t iChannelNames; ///< Index of a string descriptor, describing the name of the first inserted channel with a non-predefined spatial location. -} audio_desc_channel_cluster_t; - -/// AUDIO Class-Specific AC Interface Header Descriptor (4.7.2) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes: 9. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_HEADER. - uint16_t bcdADC ; ///< Audio Device Class Specification Release Number in Binary-Coded Decimal. Value: U16_TO_U8S_LE(0x0200). - uint8_t bCategory ; ///< Constant, indicating the primary use of this audio function, as intended by the manufacturer. See: audio_function_t. - uint16_t wTotalLength ; ///< Total number of bytes returned for the class-specific AudioControl interface descriptor. Includes the combined length of this descriptor header and all Clock Source, Unit and Terminal descriptors. - uint8_t bmControls ; ///< See: audio_cs_ac_interface_control_pos_t. -} audio_desc_cs_ac_interface_t; - -/// AUDIO Clock Source Descriptor (4.7.2.1) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes: 8. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE. - uint8_t bClockID ; ///< Constant uniquely identifying the Clock Source Entity within the audio function. This value is used in all requests to address this Entity. - uint8_t bmAttributes ; ///< See: audio_clock_source_attribute_t. - uint8_t bmControls ; ///< See: audio_clock_source_control_pos_t. - uint8_t bAssocTerminal ; ///< Terminal ID of the Terminal that is associated with this Clock Source. - uint8_t iClockSource ; ///< Index of a string descriptor, describing the Clock Source Entity. -} audio_desc_clock_source_t; - -/// AUDIO Clock Selector Descriptor (4.7.2.2) for ONE pin -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor, in bytes: 7+p. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_SELECTOR. - uint8_t bClockID ; ///< Constant uniquely identifying the Clock Selector Entity within the audio function. This value is used in all requests to address this Entity. - uint8_t bNrInPins ; ///< Number of Input Pins of this Unit: p = 1 thus bNrInPins = 1. - uint8_t baCSourceID ; ///< ID of the Clock Entity to which the first Clock Input Pin of this Clock Selector Entity is connected.. - uint8_t bmControls ; ///< See: audio_clock_selector_control_pos_t. - uint8_t iClockSource ; ///< Index of a string descriptor, describing the Clock Selector Entity. -} audio_desc_clock_selector_t; - -/// AUDIO Clock Selector Descriptor (4.7.2.2) for multiple pins -#define audio_desc_clock_selector_n_t(source_num) \ - struct TU_ATTR_PACKED { \ - uint8_t bLength ; \ - uint8_t bDescriptorType ; \ - uint8_t bDescriptorSubType ; \ - uint8_t bClockID ; \ - uint8_t bNrInPins ; \ - struct TU_ATTR_PACKED { \ - uint8_t baSourceID ; \ - } sourceID[source_num] ; \ - uint8_t bmControls ; \ - uint8_t iClockSource ; \ -} - -/// AUDIO Clock Multiplier Descriptor (4.7.2.3) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor, in bytes: 7. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_MULTIPLIER. - uint8_t bClockID ; ///< Constant uniquely identifying the Clock Multiplier Entity within the audio function. This value is used in all requests to address this Entity. - uint8_t bCSourceID ; ///< ID of the Clock Entity to which the last Clock Input Pin of this Clock Selector Entity is connected. - uint8_t bmControls ; ///< See: audio_clock_multiplier_control_pos_t. - uint8_t iClockSource ; ///< Index of a string descriptor, describing the Clock Multiplier Entity. -} audio_desc_clock_multiplier_t; - -/// AUDIO Input Terminal Descriptor(4.7.2.4) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor, in bytes: 17. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL. - uint8_t bTerminalID ; ///< Constant uniquely identifying the Terminal within the audio function. This value is used in all requests to address this terminal. - uint16_t wTerminalType ; ///< Constant characterizing the type of Terminal. See: audio_terminal_type_t for USB streaming and audio_terminal_input_type_t for other input types. - uint8_t bAssocTerminal ; ///< ID of the Output Terminal to which this Input Terminal is associated. - uint8_t bCSourceID ; ///< ID of the Clock Entity to which this Input Terminal is connected. - uint8_t bNrChannels ; ///< Number of logical output channels in the Terminal’s output audio channel cluster. - uint32_t bmChannelConfig ; ///< Describes the spatial location of the logical channels. See:audio_channel_config_t. - uint8_t iChannelNames ; ///< Index of a string descriptor, describing the name of the first logical channel. - uint16_t bmControls ; ///< See: audio_terminal_input_control_pos_t. - uint8_t iTerminal ; ///< Index of a string descriptor, describing the Input Terminal. -} audio_desc_input_terminal_t; - -/// AUDIO Output Terminal Descriptor(4.7.2.5) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor, in bytes: 12. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL. - uint8_t bTerminalID ; ///< Constant uniquely identifying the Terminal within the audio function. This value is used in all requests to address this Terminal. - uint16_t wTerminalType ; ///< Constant characterizing the type of Terminal. See: audio_terminal_type_t for USB streaming and audio_terminal_output_type_t for other output types. - uint8_t bAssocTerminal ; ///< Constant, identifying the Input Terminal to which this Output Terminal is associated. - uint8_t bSourceID ; ///< ID of the Unit or Terminal to which this Terminal is connected. - uint8_t bCSourceID ; ///< ID of the Clock Entity to which this Output Terminal is connected. - uint16_t bmControls ; ///< See: audio_terminal_output_type_t. - uint8_t iTerminal ; ///< Index of a string descriptor, describing the Output Terminal. -} audio_desc_output_terminal_t; - -/// AUDIO Feature Unit Descriptor(4.7.2.8) for ONE channel -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor, in bytes: 14. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_FEATURE_UNIT. - uint8_t bUnitID ; ///< Constant uniquely identifying the Unit within the audio function. This value is used in all requests to address this Unit. - uint8_t bSourceID ; ///< ID of the Unit or Terminal to which this Feature Unit is connected. - struct TU_ATTR_PACKED { - uint32_t bmaControls ; ///< See: audio_feature_unit_control_pos_t. Controls0 is master channel 0 (always present) and Controls1 is logical channel 1. - } controls[2] ; - uint8_t iTerminal ; ///< Index of a string descriptor, describing this Feature Unit. -} audio_desc_feature_unit_t; - -/// AUDIO Feature Unit Descriptor(4.7.2.8) for multiple channels -#define audio_desc_feature_unit_n_t(ch_num)\ - struct TU_ATTR_PACKED { \ - uint8_t bLength ; /* 6+(ch_num+1)*4 */\ - uint8_t bDescriptorType ; \ - uint8_t bDescriptorSubType ; \ - uint8_t bUnitID ; \ - uint8_t bSourceID ; \ - struct TU_ATTR_PACKED { \ - uint32_t bmaControls ; \ - } controls[ch_num+1] ; \ - uint8_t iTerminal ; \ -} - -/// AUDIO Class-Specific AS Interface Descriptor(4.9.2) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor, in bytes: 16. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AS_INTERFACE_AS_GENERAL. - uint8_t bTerminalLink ; ///< The Terminal ID of the Terminal to which this interface is connected. - uint8_t bmControls ; ///< See: audio_cs_as_interface_control_pos_t. - uint8_t bFormatType ; ///< Constant identifying the Format Type the AudioStreaming interface is using. See: audio_format_type_t. - uint32_t bmFormats ; ///< The Audio Data Format(s) that can be used to communicate with this interface.See: audio_data_format_type_I_t. - uint8_t bNrChannels ; ///< Number of physical channels in the AS Interface audio channel cluster. - uint32_t bmChannelConfig ; ///< Describes the spatial location of the physical channels. See: audio_channel_config_t. - uint8_t iChannelNames ; ///< Index of a string descriptor, describing the name of the first physical channel. -} audio_desc_cs_as_interface_t; - -/// AUDIO Type I Format Type Descriptor(2.3.1.6 - Audio Formats) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor, in bytes: 6. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AS_INTERFACE_FORMAT_TYPE. - uint8_t bFormatType ; ///< Constant identifying the Format Type the AudioStreaming interface is using. Value: AUDIO_FORMAT_TYPE_I. - uint8_t bSubslotSize ; ///< The number of bytes occupied by one audio subslot. Can be 1, 2, 3 or 4. - uint8_t bBitResolution ; ///< The number of effectively used bits from the available bits in an audio subslot. -} audio_desc_type_I_format_t; - -/// AUDIO Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor, in bytes: 8. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_ENDPOINT. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_EP_SUBTYPE_GENERAL. - uint8_t bmAttributes ; ///< See: audio_cs_as_iso_data_ep_attribute_t. - uint8_t bmControls ; ///< See: audio_cs_as_iso_data_ep_control_pos_t. - uint8_t bLockDelayUnits ; ///< Indicates the units used for the wLockDelay field. See: audio_cs_as_iso_data_ep_lock_delay_unit_t. - uint16_t wLockDelay ; ///< Indicates the time it takes this endpoint to reliably lock its internal clock recovery circuitry. Units used depend on the value of the bLockDelayUnits field. -} audio_desc_cs_as_iso_data_ep_t; - -// 5.2.2 Control Request Layout -typedef struct TU_ATTR_PACKED -{ - union - { - struct TU_ATTR_PACKED - { - uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t. - uint8_t type : 2; ///< Request type tusb_request_type_t. - uint8_t direction : 1; ///< Direction type. tusb_dir_t - } bmRequestType_bit; - - uint8_t bmRequestType; - }; - - uint8_t bRequest; ///< Request type audio_cs_req_t - uint8_t bChannelNumber; - uint8_t bControlSelector; - union - { - uint8_t bInterface; - uint8_t bEndpoint; - }; - uint8_t bEntityID; - uint16_t wLength; -} audio_control_request_t; - -//// 5.2.3 Control Request Parameter Block Layout - -// 5.2.3.1 1-byte Control CUR Parameter Block -typedef struct TU_ATTR_PACKED -{ - int8_t bCur ; ///< The setting for the CUR attribute of the addressed Control -} audio_control_cur_1_t; - -// 5.2.3.2 2-byte Control CUR Parameter Block -typedef struct TU_ATTR_PACKED -{ - int16_t bCur ; ///< The setting for the CUR attribute of the addressed Control -} audio_control_cur_2_t; - -// 5.2.3.3 4-byte Control CUR Parameter Block -typedef struct TU_ATTR_PACKED -{ - int32_t bCur ; ///< The setting for the CUR attribute of the addressed Control -} audio_control_cur_4_t; - -// Use the following ONLY for RECEIVED data - compiler does not know how many subranges are defined! Use the one below for predefined lengths - or if you know what you are doing do what you like -// 5.2.3.1 1-byte Control RANGE Parameter Block -typedef struct TU_ATTR_PACKED { - uint16_t wNumSubRanges; - struct TU_ATTR_PACKED { - int8_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/ - int8_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/ - uint8_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/ - } subrange[] ; -} audio_control_range_1_t; - -// 5.2.3.2 2-byte Control RANGE Parameter Block -typedef struct TU_ATTR_PACKED { - uint16_t wNumSubRanges; - struct TU_ATTR_PACKED { - int16_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/ - int16_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/ - uint16_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/ - } subrange[] ; -} audio_control_range_2_t; - -// 5.2.3.3 4-byte Control RANGE Parameter Block -typedef struct TU_ATTR_PACKED { - uint16_t wNumSubRanges; - struct TU_ATTR_PACKED { - int32_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/ - int32_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/ - uint32_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/ - } subrange[] ; -} audio_control_range_4_t; - -// 5.2.3.1 1-byte Control RANGE Parameter Block -#define audio_control_range_1_n_t(numSubRanges) \ - struct TU_ATTR_PACKED { \ - uint16_t wNumSubRanges; \ - struct TU_ATTR_PACKED { \ - int8_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/\ - int8_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/\ - uint8_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/\ - } subrange[numSubRanges] ; \ -} - -/// 5.2.3.2 2-byte Control RANGE Parameter Block -#define audio_control_range_2_n_t(numSubRanges) \ - struct TU_ATTR_PACKED { \ - uint16_t wNumSubRanges; \ - struct TU_ATTR_PACKED { \ - int16_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/\ - int16_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/\ - uint16_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/\ - } subrange[numSubRanges]; \ -} - -// 5.2.3.3 4-byte Control RANGE Parameter Block -#define audio_control_range_4_n_t(numSubRanges) \ - struct TU_ATTR_PACKED { \ - uint16_t wNumSubRanges; \ - struct TU_ATTR_PACKED { \ - int32_t bMin ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/\ - int32_t bMax ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/\ - uint32_t bRes ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/\ - } subrange[numSubRanges]; \ -} - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif - -/** @} */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.c b/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.c deleted file mode 100644 index f487fe60..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.c +++ /dev/null @@ -1,2567 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Reinhard Panhuber, Jerzy Kasenberg - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -/* - * This driver supports at most one out EP, one in EP, one control EP, and one feedback EP and one alternative interface other than zero. Hence, only one input terminal and one output terminal are support, if you need more adjust the driver! - * It supports multiple TX and RX channels. - * - * In case you need more alternate interfaces, you need to define additional defines for this specific alternate interface. Just define them and set them in the set_interface function. - * - * There are three data flow structures currently implemented, where at least one SW-FIFO is used to decouple the asynchronous processes MCU vs. host - * - * 1. Input data -> SW-FIFO -> MCU USB - * - * The most easiest version, available in case the target MCU can handle the software FIFO (SW-FIFO) and if it is implemented in the device driver (if yes then dcd_edpt_xfer_fifo() is available) - * - * 2. Input data -> SW-FIFO -> Linear buffer -> MCU USB - * - * In case the target MCU can not handle a SW-FIFO, a linear buffer is used. This uses the default function dcd_edpt_xfer(). In this case more memory is required. - * - * 3. (Input data 1 | Input data 2 | ... | Input data N) -> (SW-FIFO 1 | SW-FIFO 2 | ... | SW-FIFO N) -> Linear buffer -> MCU USB - * - * This case is used if you have more channels which need to be combined into one stream. Every channel has its own SW-FIFO. All data is encoded into an Linear buffer. - * - * The same holds in the RX case. - * - * */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_AUDIO) - -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "audio_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -// Use ring buffer if it's available, some MCUs need extra RAM requirements -#ifndef TUD_AUDIO_PREFER_RING_BUFFER - #if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT - #define TUD_AUDIO_PREFER_RING_BUFFER 0 - #else - #define TUD_AUDIO_PREFER_RING_BUFFER 1 - #endif -#endif - -// Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer -// is available or driver is would need to be changed dramatically - -// Only STM32 and dcd_transdimension use non-linear buffer for now -// dwc2 except esp32sx (since it may use dcd_esp32sx) -#if (defined(TUP_USBIP_DWC2) && !TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)) || \ - defined(TUP_USBIP_FSDEV) || \ - CFG_TUSB_MCU == OPT_MCU_RX63X || \ - CFG_TUSB_MCU == OPT_MCU_RX65X || \ - CFG_TUSB_MCU == OPT_MCU_RX72N || \ - CFG_TUSB_MCU == OPT_MCU_LPC18XX || \ - CFG_TUSB_MCU == OPT_MCU_LPC43XX || \ - CFG_TUSB_MCU == OPT_MCU_MIMXRT || \ - CFG_TUSB_MCU == OPT_MCU_MSP432E4 - #if TUD_AUDIO_PREFER_RING_BUFFER - #define USE_LINEAR_BUFFER 0 - #else - #define USE_LINEAR_BUFFER 1 - #endif -#else - #define USE_LINEAR_BUFFER 1 -#endif - -// Temporarily put the check here for stm32_fsdev -#ifdef TUP_USBIP_FSDEV - #define USE_ISO_EP_ALLOCATION 1 -#else - #define USE_ISO_EP_ALLOCATION 0 -#endif - -// Declaration of buffers - -// Check for maximum supported numbers -#if CFG_TUD_AUDIO > 3 -#error Maximum number of audio functions restricted to three! -#endif - -// EP IN software buffers and mutexes -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO - #endif - #endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 - - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO - #endif - #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 - - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO - #endif - #endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - -// Linear buffer TX in case: -// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR -// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into -#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) - #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX]; - #endif - - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX]; - #endif - - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX]; - #endif -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) - -// EP OUT software buffers and mutexes -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING - #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO - #endif - #endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 - - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO - #endif - #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 - - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO - #endif - #endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING - -// Linear buffer RX in case: -// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR -// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) - #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX]; - #endif - - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX]; - #endif - - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX]; - #endif -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) - -// Control buffers -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ]; - -#if CFG_TUD_AUDIO > 1 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ]; -#endif - -#if CFG_TUD_AUDIO > 2 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ]; -#endif - -// Active alternate setting of interfaces -uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT]; - -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 -uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT]; -#endif - -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 -uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; -#endif - -// Software encoding/decoding support FIFOs -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - #if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ]; - tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO - #endif - #endif - - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ]; - tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO - #endif - #endif - - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ]; - tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO - #endif - #endif -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - #if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ]; - tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO - #endif - #endif - - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ]; - tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO - #endif - #endif - - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ]; - tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO - #endif - #endif -#endif - -typedef struct -{ - uint8_t rhport; - uint8_t const * p_desc; // Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function - -#if CFG_TUD_AUDIO_ENABLE_EP_IN - uint8_t ep_in; // TX audio data EP. - uint16_t ep_in_sz; // Current size of TX EP - uint8_t ep_in_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to output terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - uint8_t ep_out; // Incoming (into uC) audio data EP. - uint16_t ep_out_sz; // Current size of RX EP - uint8_t ep_out_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to input terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) - -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - uint8_t ep_fb; // Feedback EP. -#endif - -#endif - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - uint8_t ep_int_ctr; // Audio control interrupt EP. -#endif - - /*------------- From this point, data is not cleared by bus reset -------------*/ - - uint16_t desc_length; // Length of audio function descriptor - - // Buffer for control requests - uint8_t * ctrl_buf; - uint8_t ctrl_buf_sz; - - // Current active alternate settings - uint8_t * alt_setting; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! - - // EP Transfer buffers and FIFOs -#if CFG_TUD_AUDIO_ENABLE_EP_OUT -#if !CFG_TUD_AUDIO_ENABLE_DECODING - tu_fifo_t ep_out_ff; -#endif - -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - struct { - CFG_TUSB_MEM_ALIGN uint32_t value; // Feedback value for asynchronous mode (in 16.16 format). - uint32_t min_value; // min value according to UAC2 FMT-2.0 section 2.3.1.1. - uint32_t max_value; // max value according to UAC2 FMT-2.0 section 2.3.1.1. - - uint8_t frame_shift; // bInterval-1 in unit of frame (FS), micro-frame (HS) - uint8_t compute_method; - - union { - uint8_t power_of_2; // pre-computed power of 2 shift - float float_const; // pre-computed float constant - - struct { - uint32_t sample_freq; - uint32_t mclk_freq; - }fixed; - -#if 0 // implement later - struct { - uint32_t nominal_value; - uint32_t threshold_bytes; - }fifo_count; -#endif - }compute; - - } feedback; -#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - tu_fifo_t ep_in_ff; -#endif - - // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74) -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE]; -#endif - - // Decoding parameters - parameters are set when alternate AS interface is set by host - // Coding is currently only supported for EP. Software coding corresponding to AS interfaces without EPs are not supported currently. -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - audio_format_type_t format_type_rx; - uint8_t n_channels_rx; - -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - audio_data_format_type_I_t format_type_I_rx; - uint8_t n_bytes_per_sampe_rx; - uint8_t n_channels_per_ff_rx; - uint8_t n_ff_used_rx; -#endif -#endif - - // Encoding parameters - parameters are set when alternate AS interface is set by host -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - audio_format_type_t format_type_tx; - uint8_t n_channels_tx; - -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - audio_data_format_type_I_t format_type_I_tx; - uint8_t n_bytes_per_sampe_tx; - uint8_t n_channels_per_ff_tx; - uint8_t n_ff_used_tx; -#endif -#endif - - // Support FIFOs for software encoding and decoding -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - tu_fifo_t * rx_supp_ff; - uint8_t n_rx_supp_ff; - uint16_t rx_supp_ff_sz_max; -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - tu_fifo_t * tx_supp_ff; - uint8_t n_tx_supp_ff; - uint16_t tx_supp_ff_sz_max; -#endif - - // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR the support FIFOs are used -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) - uint8_t * lin_buf_out; -#define USE_LINEAR_BUFFER_RX 1 -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) - uint8_t * lin_buf_in; -#define USE_LINEAR_BUFFER_TX 1 -#endif - -} audiod_function_t; - -#ifndef USE_LINEAR_BUFFER_TX -#define USE_LINEAR_BUFFER_TX 0 -#endif - -#ifndef USE_LINEAR_BUFFER_RX -#define USE_LINEAR_BUFFER_RX 0 -#endif - -#define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ctrl_buf) - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO]; - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT -static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received); -#endif - -#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT -static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN -static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t* audio); -#endif - -#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN -static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio); -#endif - -static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request); -static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request); - -static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int); -static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int); -static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id); -static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id); -static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id); -static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio); - -#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING -static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf); - -static inline uint8_t tu_desc_subtype(void const* desc) -{ - return ((uint8_t const*) desc)[2]; -} -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq); -#endif - -bool tud_audio_n_mounted(uint8_t func_id) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO); - audiod_function_t* audio = &_audiod_fct[func_id]; - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - if (audio->ep_out == 0) return false; -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN - if (audio->ep_in == 0) return false; -#endif - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - if (audio->ep_int_ctr == 0) return false; -#endif - -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - if (audio->ep_fb == 0) return false; -#endif - - return true; -} - -//--------------------------------------------------------------------+ -// READ API -//--------------------------------------------------------------------+ - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING - -uint16_t tud_audio_n_available(uint8_t func_id) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - return tu_fifo_count(&_audiod_fct[func_id].ep_out_ff); -} - -uint16_t tud_audio_n_read(uint8_t func_id, void* buffer, uint16_t bufsize) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - return tu_fifo_read_n(&_audiod_fct[func_id].ep_out_ff, buffer, bufsize); -} - -bool tud_audio_n_clear_ep_out_ff(uint8_t func_id) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - return tu_fifo_clear(&_audiod_fct[func_id].ep_out_ff); -} - -tu_fifo_t* tud_audio_n_get_ep_out_ff(uint8_t func_id) -{ - if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_out_ff; - return NULL; -} - -#endif - -#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT -// Delete all content in the support RX FIFOs -bool tud_audio_n_clear_rx_support_ff(uint8_t func_id, uint8_t ff_idx) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); - return tu_fifo_clear(&_audiod_fct[func_id].rx_supp_ff[ff_idx]); -} - -uint16_t tud_audio_n_available_support_ff(uint8_t func_id, uint8_t ff_idx) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); - return tu_fifo_count(&_audiod_fct[func_id].rx_supp_ff[ff_idx]); -} - -uint16_t tud_audio_n_read_support_ff(uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); - return tu_fifo_read_n(&_audiod_fct[func_id].rx_supp_ff[ff_idx], buffer, bufsize); -} - -tu_fifo_t* tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx) -{ - if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff) return &_audiod_fct[func_id].rx_supp_ff[ff_idx]; - return NULL; -} -#endif - -// This function is called once an audio packet is received by the USB and is responsible for putting data from USB memory into EP_OUT_FIFO (or support FIFOs + decoding of received stream into audio channels). -// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_DECODING = 0. - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - -static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received) -{ - uint8_t idxItf = 0; - uint8_t const *dummy2; - uint8_t idx_audio_fct = 0; - - if (tud_audio_rx_done_pre_read_cb || tud_audio_rx_done_post_read_cb) - { - idx_audio_fct = audiod_get_audio_fct_idx(audio); - TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2)); - } - - // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO (or decoded into support RX software FIFO) - if (tud_audio_rx_done_pre_read_cb) - { - TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); - } - -#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT - - switch (audio->format_type_rx) - { - case AUDIO_FORMAT_TYPE_UNDEFINED: - // INDIVIDUAL DECODING PROCEDURE REQUIRED HERE! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n"); - TU_BREAKPOINT(); - break; - - case AUDIO_FORMAT_TYPE_I: - - switch (audio->format_type_I_rx) - { - case AUDIO_DATA_FORMAT_TYPE_I_PCM: - TU_VERIFY(audiod_decode_type_I_pcm(rhport, audio, n_bytes_received)); - break; - - default: - // DESIRED CFG_TUD_AUDIO_FORMAT_TYPE_I_RX NOT IMPLEMENTED! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_RX encoding not implemented!\r\n"); - TU_BREAKPOINT(); - break; - } - break; - - default: - // Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented!\r\n"); - TU_BREAKPOINT(); - break; - } - - // Prepare for next transmission - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); - -#else - -#if USE_LINEAR_BUFFER_RX - // Data currently is in linear buffer, copy into EP OUT FIFO - TU_VERIFY(tu_fifo_write_n(&audio->ep_out_ff, audio->lin_buf_out, n_bytes_received)); - - // Schedule for next receive - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); -#else - // Data is already placed in EP FIFO, schedule for next receive - TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false); -#endif - -#endif - - // Call a weak callback here - a possibility for user to get informed decoding was completed - if (tud_audio_rx_done_post_read_cb) - { - TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); - } - - return true; -} - -#endif //CFG_TUD_AUDIO_ENABLE_EP_OUT - -// The following functions are used in case CFG_TUD_AUDIO_ENABLE_DECODING != 0 -#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT - -// Decoding according to 2.3.1.5 Audio Streams - -// Helper function -static inline uint8_t * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesToCopy, void * dst, uint8_t * dst_end, uint8_t * src, uint8_t const n_ff_used) -{ - - // This function is an optimized version of - // while((uint8_t *)dst < dst_end) - // { - // memcpy(dst, src, nBytesToCopy); - // dst = (uint8_t *)dst + nBytesToCopy; - // src += nBytesToCopy * n_ff_used; - // } - - // Optimize for fast half word copies - typedef struct{ - uint16_t val; - } __attribute((__packed__)) unaligned_uint16_t; - - // Optimize for fast word copies - typedef struct{ - uint32_t val; - } __attribute((__packed__)) unaligned_uint32_t; - - switch (nBytesToCopy) - { - case 1: - while((uint8_t *)dst < dst_end) - { - *(uint8_t *)dst++ = *src; - src += n_ff_used; - } - break; - - case 2: - while((uint8_t *)dst < dst_end) - { - *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src; - dst += 2; - src += 2 * n_ff_used; - } - break; - - case 3: - while((uint8_t *)dst < dst_end) - { - // memcpy(dst, src, 3); - // dst = (uint8_t *)dst + 3; - // src += 3 * n_ff_used; - - // TODO: Is there a faster way to copy 3 bytes? - *(uint8_t *)dst++ = *src++; - *(uint8_t *)dst++ = *src++; - *(uint8_t *)dst++ = *src++; - - src += 3 * (n_ff_used - 1); - } - break; - - case 4: - while((uint8_t *)dst < dst_end) - { - *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src; - dst += 4; - src += 4 * n_ff_used; - } - break; - } - - return src; -} - -static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received) -{ - (void) rhport; - - // Determine amount of samples - uint8_t const n_ff_used = audio->n_ff_used_rx; - uint16_t const nBytesPerFFToRead = n_bytes_received / n_ff_used; - uint8_t cnt_ff; - - // Decode - uint8_t * src; - uint8_t * dst_end; - - tu_fifo_buffer_info_t info; - - for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) - { - tu_fifo_get_write_info(&audio->rx_supp_ff[cnt_ff], &info); - - if (info.len_lin != 0) - { - info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin); - src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx]; - dst_end = info.ptr_lin + info.len_lin; - src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_lin, dst_end, src, n_ff_used); - - // Handle wrapped part of FIFO - info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap); - if (info.len_wrap != 0) - { - dst_end = info.ptr_wrap + info.len_wrap; - audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_wrap, dst_end, src, n_ff_used); - } - tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], info.len_lin + info.len_wrap); - } - } - - // Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it - // TU_VERIFY(cnt != n_bytes); - - return true; -} -#endif //CFG_TUD_AUDIO_ENABLE_DECODING - -//--------------------------------------------------------------------+ -// WRITE API -//--------------------------------------------------------------------+ - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - -/** - * \brief Write data to EP in buffer - * - * Write data to buffer. If it is full, new data can be inserted once a transmit was scheduled. See audiod_tx_done_cb(). - * If TX FIFOs are used, this function is not available in order to not let the user mess up the encoding process. - * - * \param[in] func_id: Index of audio function interface - * \param[in] data: Pointer to data array to be copied from - * \param[in] len: # of array elements to copy - * \return Number of bytes actually written - */ -uint16_t tud_audio_n_write(uint8_t func_id, const void * data, uint16_t len) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - return tu_fifo_write_n(&_audiod_fct[func_id].ep_in_ff, data, len); -} - -bool tud_audio_n_clear_ep_in_ff(uint8_t func_id) // Delete all content in the EP IN FIFO -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - return tu_fifo_clear(&_audiod_fct[func_id].ep_in_ff); -} - -tu_fifo_t* tud_audio_n_get_ep_in_ff(uint8_t func_id) -{ - if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_in_ff; - return NULL; -} - -#endif - -#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN - -uint16_t tud_audio_n_flush_tx_support_ff(uint8_t func_id) // Force all content in the support TX FIFOs to be written into linear buffer and schedule a transmit -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - audiod_function_t* audio = &_audiod_fct[func_id]; - - uint16_t n_bytes_copied = tu_fifo_count(&audio->tx_supp_ff[0]); - - TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio)); - - n_bytes_copied -= tu_fifo_count(&audio->tx_supp_ff[0]); - n_bytes_copied = n_bytes_copied*audio->tx_supp_ff[0].item_size; - - return n_bytes_copied; -} - -bool tud_audio_n_clear_tx_support_ff(uint8_t func_id, uint8_t ff_idx) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff); - return tu_fifo_clear(&_audiod_fct[func_id].tx_supp_ff[ff_idx]); -} - -uint16_t tud_audio_n_write_support_ff(uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff); - return tu_fifo_write_n(&_audiod_fct[func_id].tx_supp_ff[ff_idx], data, len); -} - -tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx) -{ - if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff) return &_audiod_fct[func_id].tx_supp_ff[ff_idx]; - return NULL; -} - -#endif - - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - -// If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_ctr_done_cb() is called in inform user -uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint16_t len) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - - // We write directly into the EP's buffer - abort if previous transfer not complete - TU_VERIFY(!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr)); - - TU_VERIFY(tu_memcpy_s(_audiod_fct[func_id].ep_int_ctr_buf, CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE, buffer, len)==0); - - // Schedule transmit - TU_VERIFY(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr, _audiod_fct[func_id].ep_int_ctr_buf, len)); - - return true; -} - -#endif - - -// This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission. -// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_ENCODING = 0 and use tud_audio_n_write. - -// n_bytes_copied - Informs caller how many bytes were loaded. In case n_bytes_copied = 0, a ZLP is scheduled to inform host no data is available for current frame. -#if CFG_TUD_AUDIO_ENABLE_EP_IN -static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio) -{ - uint8_t idxItf; - uint8_t const *dummy2; - - uint8_t idx_audio_fct = audiod_get_audio_fct_idx(audio); - TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, audio, &idxItf, &dummy2)); - - // Only send something if current alternate interface is not 0 as in this case nothing is to be sent due to UAC2 specifications - if (audio->alt_setting[idxItf] == 0) return false; - - // Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer (in case FIFOs are used) or - // if no FIFOs are used the user may use this call back to load its data into the EP IN buffer by use of tud_audio_n_write_ep_in_buffer(). - if (tud_audio_tx_done_pre_load_cb) TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); - - // Send everything in ISO EP FIFO - uint16_t n_bytes_tx; - - // If support FIFOs are used, encode and schedule transmit -#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN - switch (audio->format_type_tx) - { - case AUDIO_FORMAT_TYPE_UNDEFINED: - // INDIVIDUAL ENCODING PROCEDURE REQUIRED HERE! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n"); - TU_BREAKPOINT(); - n_bytes_tx = 0; - break; - - case AUDIO_FORMAT_TYPE_I: - - switch (audio->format_type_I_tx) - { - case AUDIO_DATA_FORMAT_TYPE_I_PCM: - - n_bytes_tx = audiod_encode_type_I_pcm(rhport, audio); - break; - - default: - // YOUR ENCODING IS REQUIRED HERE! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_TX encoding not implemented!\r\n"); - TU_BREAKPOINT(); - n_bytes_tx = 0; - break; - } - break; - - default: - // Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!\r\n"); - TU_BREAKPOINT(); - n_bytes_tx = 0; - break; - } - - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx)); - -#else - // No support FIFOs, if no linear buffer required schedule transmit, else put data into linear buffer and schedule - - n_bytes_tx = tu_min16(tu_fifo_count(&audio->ep_in_ff), audio->ep_in_sz); // Limit up to max packet size, more can not be done for ISO - -#if USE_LINEAR_BUFFER_TX - tu_fifo_read_n(&audio->ep_in_ff, audio->lin_buf_in, n_bytes_tx); - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx)); -#else - // Send everything in ISO EP FIFO - TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx)); -#endif - -#endif - - // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame - if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); - - return true; -} - -#endif //CFG_TUD_AUDIO_ENABLE_EP_IN - -#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN -// Take samples from the support buffer and encode them into the IN EP software FIFO -// Returns number of bytes written into linear buffer - -/* 2.3.1.7.1 PCM Format -The PCM (Pulse Coded Modulation) format is the most commonly used audio format to represent audio -data streams. The audio data is not compressed and uses a signed two’s-complement fixed point format. It -is left-justified (the sign bit is the Msb) and data is padded with trailing zeros to fill the remaining unused -bits of the subslot. The binary point is located to the right of the sign bit so that all values lie within the -range [-1, +1) - */ - -/* - * This function encodes channels saved within the support FIFOs into one stream by interleaving the PCM samples - * in the support FIFOs according to 2.3.1.5 Audio Streams. It does not control justification (left or right) and - * does not change the number of bytes per sample. - * */ - -// Helper function -static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, uint8_t * src, uint8_t * src_end, uint8_t * dst, uint8_t const n_ff_used) -{ - // Optimize for fast half word copies - typedef struct{ - uint16_t val; - } __attribute((__packed__)) unaligned_uint16_t; - - // Optimize for fast word copies - typedef struct{ - uint32_t val; - } __attribute((__packed__)) unaligned_uint32_t; - - switch (nBytesToCopy) - { - case 1: - while(src < src_end) - { - *dst = *src++; - dst += n_ff_used; - } - break; - - case 2: - while(src < src_end) - { - *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src; - src += 2; - dst += 2 * n_ff_used; - } - break; - - case 3: - while(src < src_end) - { - // memcpy(dst, src, 3); - // src = (uint8_t *)src + 3; - // dst += 3 * n_ff_used; - - // TODO: Is there a faster way to copy 3 bytes? - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - - dst += 3 * (n_ff_used - 1); - } - break; - - case 4: - while(src < src_end) - { - *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src; - src += 4; - dst += 4 * n_ff_used; - } - break; - } - - return dst; -} - -static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio) -{ - // This function relies on the fact that the length of the support FIFOs was configured to be a multiple of the active sample size in bytes s.t. no sample is split within a wrap - // This is ensured within set_interface, where the FIFOs are reconfigured according to this size - - // We encode directly into IN EP's linear buffer - abort if previous transfer not complete - TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); - - // Determine amount of samples - uint8_t const n_ff_used = audio->n_ff_used_tx; - uint16_t const nBytesToCopy = audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx; - uint16_t const capPerFF = audio->ep_in_sz / n_ff_used; // Sample capacity per FIFO in bytes - uint16_t nBytesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]); - uint8_t cnt_ff; - - for (cnt_ff = 1; cnt_ff < n_ff_used; cnt_ff++) - { - uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cnt_ff]); - if (count < nBytesPerFFToSend) - { - nBytesPerFFToSend = count; - } - } - - // Check if there is enough - if (nBytesPerFFToSend == 0) return 0; - - // Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT! - nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, capPerFF); - - // Round to full number of samples (flooring) - nBytesPerFFToSend = (nBytesPerFFToSend / nBytesToCopy) * nBytesToCopy; - - // Encode - uint8_t * dst; - uint8_t * src_end; - - tu_fifo_buffer_info_t info; - - for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) - { - dst = &audio->lin_buf_in[cnt_ff*audio->n_channels_per_ff_tx*audio->n_bytes_per_sampe_tx]; - - tu_fifo_get_read_info(&audio->tx_supp_ff[cnt_ff], &info); - - if (info.len_lin != 0) - { - info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin); // Limit up to desired length - src_end = (uint8_t *)info.ptr_lin + info.len_lin; - dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_lin, src_end, dst, n_ff_used); - - // Limit up to desired length - info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap); - - // Handle wrapped part of FIFO - if (info.len_wrap != 0) - { - src_end = (uint8_t *)info.ptr_wrap + info.len_wrap; - audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_wrap, src_end, dst, n_ff_used); - } - - tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], info.len_lin + info.len_wrap); - } - } - - return nBytesPerFFToSend * n_ff_used; -} -#endif //CFG_TUD_AUDIO_ENABLE_ENCODING - -// This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio) -{ - return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->feedback.value, 4); -} -#endif - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void audiod_init(void) -{ - tu_memclr(_audiod_fct, sizeof(_audiod_fct)); - - for(uint8_t i=0; ictrl_buf = ctrl_buf_1; - audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ; - break; -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ > 0 - case 1: - audio->ctrl_buf = ctrl_buf_2; - audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ; - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ > 0 - case 2: - audio->ctrl_buf = ctrl_buf_3; - audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ; - break; -#endif - } - - // Initialize active alternate interface buffers - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0 - case 0: - audio->alt_setting = alt_setting_1; - break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 - case 1: - audio->alt_setting = alt_setting_2; - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 - case 2: - audio->alt_setting = alt_setting_3; - break; -#endif - } - - // Initialize IN EP FIFO if required -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 - case 0: - tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_1), NULL); -#endif - break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 - case 1: - tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_2), NULL); -#endif - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 - case 2: - tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_3), NULL); -#endif - break; -#endif - } -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - - // Initialize linear buffers -#if USE_LINEAR_BUFFER_TX - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 - case 0: - audio->lin_buf_in = lin_buf_in_1; - break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 - case 1: - audio->lin_buf_in = lin_buf_in_2; - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 - case 2: - audio->lin_buf_in = lin_buf_in_3; - break; -#endif - } -#endif // USE_LINEAR_BUFFER_TX - - // Initialize OUT EP FIFO if required -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING - - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 - case 0: - tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_1)); -#endif - break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 - case 1: - tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_2)); -#endif - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 - case 2: - tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_3)); -#endif - break; -#endif - } -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING - - // Initialize linear buffers -#if USE_LINEAR_BUFFER_RX - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 - case 0: - audio->lin_buf_out = lin_buf_out_1; - break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 - case 1: - audio->lin_buf_out = lin_buf_out_2; - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 - case 2: - audio->lin_buf_out = lin_buf_out_3; - break; -#endif - } -#endif // USE_LINEAR_BUFFER_TX - - // Initialize TX support FIFOs if required -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 - case 0: - audio->tx_supp_ff = tx_supp_ff_1; - audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; - audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++) - { - tu_fifo_config(&tx_supp_ff_1[cnt], tx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&tx_supp_ff_1[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_1[cnt]), NULL); -#endif - } - - break; -#endif // CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 - -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - case 1: - audio->tx_supp_ff = tx_supp_ff_2; - audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; - audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; cnt++) - { - tu_fifo_config(&tx_supp_ff_2[cnt], tx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&tx_supp_ff_2[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_2[cnt]), NULL); -#endif - } - - break; -#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 - case 2: - audio->tx_supp_ff = tx_supp_ff_3; - audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; - audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; cnt++) - { - tu_fifo_config(&tx_supp_ff_3[cnt], tx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&tx_supp_ff_3[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_3[cnt]), NULL); -#endif - } - - break; -#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - } -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - - // Set encoding parameters for Type_I formats -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 - case 0: - audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX; - break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - case 1: - audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX; - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 - case 2: - audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX; - break; -#endif - } -#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - - // Initialize RX support FIFOs if required -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 - case 0: - audio->rx_supp_ff = rx_supp_ff_1; - audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; - audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; cnt++) - { - tu_fifo_config(&rx_supp_ff_1[cnt], rx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&rx_supp_ff_1[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_1[cnt]), NULL); -#endif - } - - break; -#endif // CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 - -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - case 1: - audio->rx_supp_ff = rx_supp_ff_2; - audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; - audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; cnt++) - { - tu_fifo_config(&rx_supp_ff_2[cnt], rx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&rx_supp_ff_2[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_2[cnt]), NULL); -#endif - } - - break; -#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 - case 2: - audio->rx_supp_ff = rx_supp_ff_3; - audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; - audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; cnt++) - { - tu_fifo_config(&rx_supp_ff_3[cnt], rx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&rx_supp_ff_3[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_3[cnt]), NULL); -#endif - } - - break; -#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - } -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - - // Set encoding parameters for Type_I formats -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 - case 0: - audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX; - break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - case 1: - audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX; - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 - case 2: - audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX; - break; -#endif - } -#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - } -} - -void audiod_reset(uint8_t rhport) -{ - (void) rhport; - - for(uint8_t i=0; iep_in_ff); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING - tu_fifo_clear(&audio->ep_out_ff); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) - { - tu_fifo_clear(&audio->tx_supp_ff[cnt]); - } -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) - { - tu_fifo_clear(&audio->rx_supp_ff[cnt]); - } -#endif - } -} - -uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ - (void) max_len; - - TU_VERIFY ( TUSB_CLASS_AUDIO == itf_desc->bInterfaceClass && - AUDIO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass); - - // Verify version is correct - this check can be omitted - TU_VERIFY(itf_desc->bInterfaceProtocol == AUDIO_INT_PROTOCOL_CODE_V2); - - // Verify interrupt control EP is enabled if demanded by descriptor - this should be best some static check however - this check can be omitted - if (itf_desc->bNumEndpoints == 1) // 0 or 1 EPs are allowed - { - TU_VERIFY(CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0); - } - - // Alternate setting MUST be zero - this check can be omitted - TU_VERIFY(itf_desc->bAlternateSetting == 0); - - // Find available audio driver interface - uint8_t i; - for (i = 0; i < CFG_TUD_AUDIO; i++) - { - if (!_audiod_fct[i].p_desc) - { - _audiod_fct[i].p_desc = (uint8_t const *)itf_desc; // Save pointer to AC descriptor which is by specification always the first one - _audiod_fct[i].rhport = rhport; - - // Setup descriptor lengths - switch (i) - { - case 0: - _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_1_DESC_LEN; - break; -#if CFG_TUD_AUDIO > 1 - case 1: - _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_2_DESC_LEN; - break; -#endif -#if CFG_TUD_AUDIO > 2 - case 2: - _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_3_DESC_LEN; - break; -#endif - } - -#if USE_ISO_EP_ALLOCATION - #if CFG_TUD_AUDIO_ENABLE_EP_IN - uint8_t ep_in = 0; - uint16_t ep_in_size = 0; - #endif - - #if CFG_TUD_AUDIO_ENABLE_EP_OUT - uint8_t ep_out = 0; - uint16_t ep_out_size = 0; - #endif - - #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - uint8_t ep_fb = 0; - #endif - - uint8_t const *p_desc = _audiod_fct[i].p_desc; - uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; - while (p_desc < p_desc_end) - { - if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) - { - tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; - if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) - { - #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // Explicit feedback EP - if (desc_ep->bmAttributes.usage == 1) - { - ep_fb = desc_ep->bEndpointAddress; - } - #endif - // Data EP - if (desc_ep->bmAttributes.usage == 0) - { - if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) - { - #if CFG_TUD_AUDIO_ENABLE_EP_IN - ep_in = desc_ep->bEndpointAddress; - ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size); - #endif - } else - { - #if CFG_TUD_AUDIO_ENABLE_EP_OUT - ep_out = desc_ep->bEndpointAddress; - ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size); - #endif - } - } - - } - } - p_desc = tu_desc_next(p_desc); - } - - #if CFG_TUD_AUDIO_ENABLE_EP_IN - if (ep_in) - { - usbd_edpt_iso_alloc(rhport, ep_in, ep_in_size); - } - #endif - - #if CFG_TUD_AUDIO_ENABLE_EP_OUT - if (ep_out) - { - usbd_edpt_iso_alloc(rhport, ep_out, ep_out_size); - } - #endif - - #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - if (ep_fb) - { - usbd_edpt_iso_alloc(rhport, ep_fb, 4); - } - #endif - -#endif // USE_ISO_EP_ALLOCATION - - break; - } - } - - // Verify we found a free one - TU_ASSERT( i < CFG_TUD_AUDIO ); - - // This is all we need so far - the EPs are setup by a later set_interface request (as per UAC2 specification) - uint16_t drv_len = _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; // - TUD_AUDIO_DESC_IAD_LEN since tinyUSB already handles the IAD descriptor - - return drv_len; -} - -static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request) -{ - uint8_t const itf = tu_u16_low(p_request->wIndex); - - // Find index of audio streaming interface - uint8_t func_id, idxItf; - uint8_t const *dummy; - - TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &dummy)); - TU_VERIFY(tud_control_xfer(rhport, p_request, &_audiod_fct[func_id].alt_setting[idxItf], 1)); - - TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf, _audiod_fct[func_id].alt_setting[idxItf]); - - return true; -} - -static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request) -{ - (void) rhport; - - // Here we need to do the following: - - // 1. Find the audio driver assigned to the given interface to be set - // Since one audio driver interface has to be able to cover an unknown number of interfaces (AC, AS + its alternate settings), the best memory efficient way to solve this is to always search through the descriptors. - // The audio driver is mapped to an audio function by a reference pointer to the corresponding AC interface of this audio function which serves as a starting point for searching - - // 2. Close EPs which are currently open - // To do so it is not necessary to know the current active alternate interface since we already save the current EP addresses - we simply close them - - // 3. Open new EP - - uint8_t const itf = tu_u16_low(p_request->wIndex); - uint8_t const alt = tu_u16_low(p_request->wValue); - - TU_LOG2(" Set itf: %u - alt: %u\r\n", itf, alt); - - // Find index of audio streaming interface and index of interface - uint8_t func_id, idxItf; - uint8_t const *p_desc; - TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &p_desc)); - - audiod_function_t* audio = &_audiod_fct[func_id]; - - // Look if there is an EP to be closed - for this driver, there are only 3 possible EPs which may be closed (only AS related EPs can be closed, AC EP (if present) is always open) -#if CFG_TUD_AUDIO_ENABLE_EP_IN - if (audio->ep_in_as_intf_num == itf) - { - audio->ep_in_as_intf_num = 0; - #if !USE_ISO_EP_ALLOCATION - usbd_edpt_close(rhport, audio->ep_in); - #endif - - // Clear FIFOs, since data is no longer valid - #if !CFG_TUD_AUDIO_ENABLE_ENCODING - tu_fifo_clear(&audio->ep_in_ff); - #else - for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) - { - tu_fifo_clear(&audio->tx_supp_ff[cnt]); - } - #endif - - // Invoke callback - can be used to stop data sampling - if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); - - audio->ep_in = 0; // Necessary? - - } -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - if (audio->ep_out_as_intf_num == itf) - { - audio->ep_out_as_intf_num = 0; - #if !USE_ISO_EP_ALLOCATION - usbd_edpt_close(rhport, audio->ep_out); - #endif - - // Clear FIFOs, since data is no longer valid - #if !CFG_TUD_AUDIO_ENABLE_DECODING - tu_fifo_clear(&audio->ep_out_ff); - #else - for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) - { - tu_fifo_clear(&audio->rx_supp_ff[cnt]); - } - #endif - - // Invoke callback - can be used to stop data sampling - if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); - - audio->ep_out = 0; // Necessary? - - // Close corresponding feedback EP - #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - #if !USE_ISO_EP_ALLOCATION - usbd_edpt_close(rhport, audio->ep_fb); - #endif - audio->ep_fb = 0; - tu_memclr(&audio->feedback, sizeof(audio->feedback)); - #endif - } -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT - - // Save current alternative interface setting - audio->alt_setting[idxItf] = alt; - - // Open new EP if necessary - EPs are only to be closed or opened for AS interfaces - Look for AS interface with correct alternate interface - // Get pointer at end - uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; - - // p_desc starts at required interface with alternate setting zero - while (p_desc < p_desc_end) - { - // Find correct interface - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == alt) - { -#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING - uint8_t const * p_desc_parse_for_params = p_desc; -#endif - // From this point forward follow the EP descriptors associated to the current alternate setting interface - Open EPs if necessary - uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints; - while (foundEPs < nEps && p_desc < p_desc_end) - { - if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) - { - tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc; -#if USE_ISO_EP_ALLOCATION - TU_ASSERT(usbd_edpt_iso_activate(rhport, desc_ep)); -#else - TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); -#endif - uint8_t const ep_addr = desc_ep->bEndpointAddress; - - //TODO: We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND! - usbd_edpt_clear_stall(rhport, ep_addr); - -#if CFG_TUD_AUDIO_ENABLE_EP_IN - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 0x00) // Check if usage is data EP - { - // Save address - audio->ep_in = ep_addr; - audio->ep_in_as_intf_num = itf; - audio->ep_in_sz = tu_edpt_packet_size(desc_ep); - - // If software encoding is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters - #if CFG_TUD_AUDIO_ENABLE_ENCODING - audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf); - - // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap - #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / audio->n_bytes_per_sampe_tx) * audio->n_bytes_per_sampe_tx); - for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) - { - tu_fifo_config(&audio->tx_supp_ff[cnt], audio->tx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); - } - audio->n_ff_used_tx = audio->n_channels_tx / audio->n_channels_per_ff_tx; - TU_ASSERT( audio->n_ff_used_tx <= audio->n_tx_supp_ff ); - #endif - #endif - - // Schedule first transmit if alternate interface is not zero i.e. streaming is disabled - in case no sample data is available a ZLP is loaded - // It is necessary to trigger this here since the refill is done with an RX FIFO empty interrupt which can only trigger if something was in there - TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_fct[func_id])); - } -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - - if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) // Checking usage not necessary - { - // Save address - audio->ep_out = ep_addr; - audio->ep_out_as_intf_num = itf; - audio->ep_out_sz = tu_edpt_packet_size(desc_ep); - - #if CFG_TUD_AUDIO_ENABLE_DECODING - audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf); - - // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap - #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sampe_rx) * audio->n_bytes_per_sampe_rx; - for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) - { - tu_fifo_config(&audio->rx_supp_ff[cnt], audio->rx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); - } - audio->n_ff_used_rx = audio->n_channels_rx / audio->n_channels_per_ff_rx; - TU_ASSERT( audio->n_ff_used_rx <= audio->n_rx_supp_ff ); - #endif - #endif - - // Prepare for incoming data - #if USE_LINEAR_BUFFER_RX - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); - #else - TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false); - #endif - } - - #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 1) // Check if usage is explicit data feedback - { - audio->ep_fb = ep_addr; - audio->feedback.frame_shift = desc_ep->bInterval -1; - - // Enable SOF interrupt if callback is implemented - if (tud_audio_feedback_interval_isr) usbd_sof_enable(rhport, true); - } - #endif -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT - - foundEPs += 1; - } - p_desc = tu_desc_next(p_desc); - } - - TU_VERIFY(foundEPs == nEps); - - // Invoke one callback for a final set interface - if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); - -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // Prepare feedback computation if callback is available - if (tud_audio_feedback_params_cb) - { - audio_feedback_params_t fb_param; - - tud_audio_feedback_params_cb(func_id, alt, &fb_param); - audio->feedback.compute_method = fb_param.method; - - // Minimal/Maximum value in 16.16 format for full speed (1ms per frame) or high speed (125 us per frame) - uint32_t const frame_div = (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000; - audio->feedback.min_value = (fb_param.sample_freq/frame_div - 1) << 16; - audio->feedback.max_value = (fb_param.sample_freq/frame_div + 1) << 16; - - switch(fb_param.method) - { - case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: - case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT: - case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2: - set_fb_params_freq(audio, fb_param.sample_freq, fb_param.frequency.mclk_freq); - break; - - #if 0 // implement later - case AUDIO_FEEDBACK_METHOD_FIFO_COUNT: - { - uint64_t fb64 = ((uint64_t) fb_param.sample_freq) << 16; - audio->feedback.compute.fifo_count.nominal_value = (uint32_t) (fb64 / frame_div); - audio->feedback.compute.fifo_count.threshold_bytes = fb_param.fifo_count.threshold_bytes; - - tud_audio_fb_set(audio->feedback.compute.fifo_count.nominal_value); - } - break; - #endif - - // nothing to do - default: break; - } - } -#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - - // We are done - abort loop - break; - } - - // Moving forward - p_desc = tu_desc_next(p_desc); - } - -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // Disable SOF interrupt if no driver has any enabled feedback EP - bool disable = true; - for(uint8_t i=0; i < CFG_TUD_AUDIO; i++) - { - if (_audiod_fct[i].ep_fb != 0) - { - disable = false; - break; - } - } - if (disable) usbd_sof_enable(rhport, false); -#endif - - tud_control_status(rhport, p_request); - - return true; -} - -// Invoked when class request DATA stage is finished. -// return false to stall control EP (e.g Host send non-sense DATA) -static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const * p_request) -{ - // Handle audio class specific set requests - if(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) - { - uint8_t func_id; - - switch (p_request->bmRequestType_bit.recipient) - { - case TUSB_REQ_RCPT_INTERFACE: - { - uint8_t itf = TU_U16_LOW(p_request->wIndex); - uint8_t entityID = TU_U16_HIGH(p_request->wIndex); - - if (entityID != 0) - { - if (tud_audio_set_req_entity_cb) - { - // Check if entity is present and get corresponding driver index - TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); - - // Invoke callback - return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); - } - else - { - TU_LOG2(" No entity set request callback available!\r\n"); - return false; // In case no callback function is present or request can not be conducted we stall it - } - } - else - { - if (tud_audio_set_req_itf_cb) - { - // Find index of audio driver structure and verify interface really exists - TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); - - // Invoke callback - return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); - } - else - { - TU_LOG2(" No interface set request callback available!\r\n"); - return false; // In case no callback function is present or request can not be conducted we stall it - } - } - } - break; - - case TUSB_REQ_RCPT_ENDPOINT: - { - uint8_t ep = TU_U16_LOW(p_request->wIndex); - - if (tud_audio_set_req_ep_cb) - { - // Check if entity is present and get corresponding driver index - TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); - - // Invoke callback - return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); - } - else - { - TU_LOG2(" No EP set request callback available!\r\n"); - return false; // In case no callback function is present or request can not be conducted we stall it - } - } - break; - // Unknown/Unsupported recipient - default: TU_BREAKPOINT(); return false; - } - } - return true; -} - -// Handle class control request -// return false to stall control endpoint (e.g unsupported request) -static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const * p_request) -{ - (void) rhport; - - // Handle standard requests - standard set requests usually have no data stage so we also handle set requests here - if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) - { - switch (p_request->bRequest) - { - case TUSB_REQ_GET_INTERFACE: - return audiod_get_interface(rhport, p_request); - - case TUSB_REQ_SET_INTERFACE: - return audiod_set_interface(rhport, p_request); - - // Unknown/Unsupported request - default: TU_BREAKPOINT(); return false; - } - } - - // Handle class requests - if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) - { - uint8_t itf = TU_U16_LOW(p_request->wIndex); - uint8_t func_id; - - // Conduct checks which depend on the recipient - switch (p_request->bmRequestType_bit.recipient) - { - case TUSB_REQ_RCPT_INTERFACE: - { - uint8_t entityID = TU_U16_HIGH(p_request->wIndex); - - // Verify if entity is present - if (entityID != 0) - { - // Find index of audio driver structure and verify entity really exists - TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); - - // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests - if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) - { - if (tud_audio_get_req_entity_cb) - { - return tud_audio_get_req_entity_cb(rhport, p_request); - } - else - { - TU_LOG2(" No entity get request callback available!\r\n"); - return false; // Stall - } - } - } - else - { - // Find index of audio driver structure and verify interface really exists - TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); - - // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests - if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) - { - if (tud_audio_get_req_itf_cb) - { - return tud_audio_get_req_itf_cb(rhport, p_request); - } - else - { - TU_LOG2(" No interface get request callback available!\r\n"); - return false; // Stall - } - } - } - } - break; - - case TUSB_REQ_RCPT_ENDPOINT: - { - uint8_t ep = TU_U16_LOW(p_request->wIndex); - - // Find index of audio driver structure and verify EP really exists - TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); - - // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests - if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) - { - if (tud_audio_get_req_ep_cb) - { - return tud_audio_get_req_ep_cb(rhport, p_request); - } - else - { - TU_LOG2(" No EP get request callback available!\r\n"); - return false; // Stall - } - } - } - break; - - // Unknown/Unsupported recipient - default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false; - } - - // If we end here, the received request is a set request - we schedule a receive for the data stage and return true here. We handle the rest later in audiod_control_complete() once the data stage was finished - TU_VERIFY(tud_control_xfer(rhport, p_request, _audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz)); - return true; - } - - // There went something wrong - unsupported control request type - TU_BREAKPOINT(); - return false; -} - -bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - if ( stage == CONTROL_STAGE_SETUP ) - { - return audiod_control_request(rhport, request); - } - else if ( stage == CONTROL_STAGE_DATA ) - { - return audiod_control_complete(rhport, request); - } - - return true; -} - -bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void) result; - (void) xferred_bytes; - - // Search for interface belonging to given end point address and proceed as required - for (uint8_t func_id = 0; func_id < CFG_TUD_AUDIO; func_id++) - { - audiod_function_t* audio = &_audiod_fct[func_id]; - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - - // Data transmission of control interrupt finished - if (audio->ep_int_ctr == ep_addr) - { - // According to USB2 specification, maximum payload of interrupt EP is 8 bytes on low speed, 64 bytes on full speed, and 1024 bytes on high speed (but only if an alternate interface other than 0 is used - see specification p. 49) - // In case there is nothing to send we have to return a NAK - this is taken care of by PHY ??? - // In case of an erroneous transmission a retransmission is conducted - this is taken care of by PHY ??? - - // I assume here, that things above are handled by PHY - // All transmission is done - what remains to do is to inform job was completed - - if (tud_audio_int_ctr_done_cb) TU_VERIFY(tud_audio_int_ctr_done_cb(rhport, (uint16_t) xferred_bytes)); - } - -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN - - // Data transmission of audio packet finished - if (audio->ep_in == ep_addr && audio->alt_setting != 0) - { - // USB 2.0, section 5.6.4, third paragraph, states "An isochronous endpoint must specify its required bus access period. However, an isochronous endpoint must be prepared to handle poll rates faster than the one specified." - // That paragraph goes on to say "An isochronous IN endpoint must return a zero-length packet whenever data is requested at a faster interval than the specified interval and data is not available." - // This can only be solved reliably if we load a ZLP after every IN transmission since we can not say if the host requests samples earlier than we declared! Once all samples are collected we overwrite the loaded ZLP. - - // Check if there is data to load into EPs buffer - if not load it with ZLP - // Be aware - we as a device are not able to know if the host polls for data with a faster rate as we stated this in the descriptors. Therefore we always have to put something into the EPs buffer. However, once we did that, there is no way of aborting this or replacing what we put into the buffer before! - // This is the only place where we can fill something into the EPs buffer! - - // Load new data - TU_VERIFY(audiod_tx_done_cb(rhport, audio)); - - // Transmission of ZLP is done by audiod_tx_done_cb() - return true; - } -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - - // New audio packet received - if (audio->ep_out == ep_addr) - { - TU_VERIFY(audiod_rx_done_cb(rhport, audio, (uint16_t) xferred_bytes)); - return true; - } - - -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // Transmission of feedback EP finished - if (audio->ep_fb == ep_addr) - { - if (tud_audio_fb_done_cb) tud_audio_fb_done_cb(func_id); - - // Schedule a transmit with the new value if EP is not busy - if (!usbd_edpt_busy(rhport, audio->ep_fb)) - { - // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent - return audiod_fb_send(rhport, audio); - } - } -#endif -#endif - } - - return false; -} - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - -static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq) -{ - // Check if frame interval is within sane limits - // The interval value n_frames was taken from the descriptors within audiod_set_interface() - - // n_frames_min is ceil(2^10 * f_s / f_m) for full speed and ceil(2^13 * f_s / f_m) for high speed - // this lower limit ensures the measures feedback value has sufficient precision - uint32_t const k = (TUSB_SPEED_FULL == tud_speed_get()) ? 10 : 13; - uint32_t const n_frame = (1UL << audio->feedback.frame_shift); - - if ( (((1UL << k) * sample_freq / mclk_freq) + 1) > n_frame ) - { - TU_LOG1(" UAC2 feedback interval too small\r\n"); TU_BREAKPOINT(); return false; - } - - // Check if parameters really allow for a power of two division - if ((mclk_freq % sample_freq) == 0 && tu_is_power_of_two(mclk_freq / sample_freq)) - { - audio->feedback.compute_method = AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2; - audio->feedback.compute.power_of_2 = 16 - audio->feedback.frame_shift - tu_log2(mclk_freq / sample_freq); - } - else if ( audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT) - { - audio->feedback.compute.float_const = (float)sample_freq / mclk_freq * (1UL << (16 - audio->feedback.frame_shift)); - } - else - { - audio->feedback.compute.fixed.sample_freq = sample_freq; - audio->feedback.compute.fixed.mclk_freq = mclk_freq; - } - - return true; -} - -uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles) -{ - audiod_function_t* audio = &_audiod_fct[func_id]; - uint32_t feedback; - - switch (audio->feedback.compute_method) - { - case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2: - feedback = (cycles << audio->feedback.compute.power_of_2); - break; - - case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT: - feedback = (uint32_t) ((float) cycles * audio->feedback.compute.float_const); - break; - - case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: - { - uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - audio->feedback.frame_shift); - feedback = (uint32_t) (fb64 / audio->feedback.compute.fixed.mclk_freq); - } - break; - - default: return 0; - } - - // For Windows: https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/usb-2-0-audio-drivers - // The size of isochronous packets created by the device must be within the limits specified in FMT-2.0 section 2.3.1.1. - // This means that the deviation of actual packet size from nominal size must not exceed +/- one audio slot - // (audio slot = channel count samples). - if ( feedback > audio->feedback.max_value ) feedback = audio->feedback.max_value; - if ( feedback < audio->feedback.min_value ) feedback = audio->feedback.min_value; - - tud_audio_n_fb_set(func_id, feedback); - - return feedback; -} -#endif - -TU_ATTR_FAST_FUNC void audiod_sof_isr (uint8_t rhport, uint32_t frame_count) -{ - (void) rhport; - (void) frame_count; - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // Determine feedback value - The feedback method is described in 5.12.4.2 of the USB 2.0 spec - // Boiled down, the feedback value Ff = n_samples / (micro)frame. - // Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s) - // The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where P = min( ceil(log2(f_m / f_s)), K) - // feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames - - // Iterate over audio functions and set feedback value - for(uint8_t i=0; i < CFG_TUD_AUDIO; i++) - { - audiod_function_t* audio = &_audiod_fct[i]; - - if (audio->ep_fb != 0) - { - // HS shift need to be adjusted since SOF event is generated for frame only - uint8_t const hs_adjust = (TUSB_SPEED_HIGH == tud_speed_get()) ? 3 : 0; - uint32_t const interval = 1UL << (audio->feedback.frame_shift - hs_adjust); - if ( 0 == (frame_count & (interval-1)) ) - { - if(tud_audio_feedback_interval_isr) tud_audio_feedback_interval_isr(i, frame_count, audio->feedback.frame_shift); - } - } - } -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -} - -bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len) -{ - // Handles only sending of data not receiving - if (p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) return false; - - // Get corresponding driver index - uint8_t func_id; - uint8_t itf = TU_U16_LOW(p_request->wIndex); - - // Conduct checks which depend on the recipient - switch (p_request->bmRequestType_bit.recipient) - { - case TUSB_REQ_RCPT_INTERFACE: - { - uint8_t entityID = TU_U16_HIGH(p_request->wIndex); - - // Verify if entity is present - if (entityID != 0) - { - // Find index of audio driver structure and verify entity really exists - TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); - } - else - { - // Find index of audio driver structure and verify interface really exists - TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); - } - } - break; - - case TUSB_REQ_RCPT_ENDPOINT: - { - uint8_t ep = TU_U16_LOW(p_request->wIndex); - - // Find index of audio driver structure and verify EP really exists - TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); - } - break; - - // Unknown/Unsupported recipient - default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false; - } - - // Crop length - if (len > _audiod_fct[func_id].ctrl_buf_sz) len = _audiod_fct[func_id].ctrl_buf_sz; - - // Copy into buffer - TU_VERIFY(0 == tu_memcpy_s(_audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz, data, (size_t)len)); - - // Schedule transmit - return tud_control_xfer(rhport, p_request, (void*)_audiod_fct[func_id].ctrl_buf, len); -} - -// This helper function finds for a given audio function and AS interface number the index of the attached driver structure, the index of the interface in the audio function -// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and -// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero. -static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int) -{ - if (audio->p_desc) - { - // Get pointer at end - uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; - - // Advance past AC descriptors - uint8_t const *p_desc = tu_desc_next(audio->p_desc); - p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength; - - uint8_t tmp = 0; - while (p_desc < p_desc_end) - { - // We assume the number of alternate settings is increasing thus we return the index of alternate setting zero! - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0) - { - if (((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf) - { - *idxItf = tmp; - *pp_desc_int = p_desc; - return true; - } - // Increase index, bytes read, and pointer - tmp++; - } - p_desc = tu_desc_next(p_desc); - } - } - return false; -} - -// This helper function finds for a given AS interface number the index of the attached driver structure, the index of the interface in the audio function -// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and -// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero. -static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int) -{ - // Loop over audio driver interfaces - uint8_t i; - for (i = 0; i < CFG_TUD_AUDIO; i++) - { - if (audiod_get_AS_interface_index(itf, &_audiod_fct[i], idxItf, pp_desc_int)) - { - *func_id = i; - return true; - } - } - - return false; -} - -// Verify an entity with the given ID exists and returns also the corresponding driver index -static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id) -{ - uint8_t i; - for (i = 0; i < CFG_TUD_AUDIO; i++) - { - // Look for the correct driver by checking if the unique standard AC interface number fits - if (_audiod_fct[i].p_desc && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf) - { - // Get pointers after class specific AC descriptors and end of AC descriptors - entities are defined in between - uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc); // Points to CS AC descriptor - uint8_t const *p_desc_end = ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength + p_desc; - p_desc = tu_desc_next(p_desc); // Get past CS AC descriptor - - while (p_desc < p_desc_end) - { - if (p_desc[3] == entityID) // Entity IDs are always at offset 3 - { - *func_id = i; - return true; - } - p_desc = tu_desc_next(p_desc); - } - } - } - return false; -} - -static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id) -{ - uint8_t i; - for (i = 0; i < CFG_TUD_AUDIO; i++) - { - if (_audiod_fct[i].p_desc) - { - // Get pointer at beginning and end - uint8_t const *p_desc = _audiod_fct[i].p_desc; - uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; - - while (p_desc < p_desc_end) - { - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf) - { - *func_id = i; - return true; - } - p_desc = tu_desc_next(p_desc); - } - } - } - return false; -} - -static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id) -{ - uint8_t i; - for (i = 0; i < CFG_TUD_AUDIO; i++) - { - if (_audiod_fct[i].p_desc) - { - // Get pointer at end - uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length; - - // Advance past AC descriptors - EP we look for are streaming EPs - uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc); - p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength; - - while (p_desc < p_desc_end) - { - if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT && ((tusb_desc_endpoint_t const * )p_desc)->bEndpointAddress == ep) - { - *func_id = i; - return true; - } - p_desc = tu_desc_next(p_desc); - } - } - } - return false; -} - -#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING -// p_desc points to the AS interface of alternate setting zero -// itf is the interface number of the corresponding interface - we check if the interface belongs to EP in or EP out to see if it is a TX or RX parameter -// Currently, only AS interfaces with an EP (in or out) are supposed to be parsed for! -static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf) -{ -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) return; // Abort, this interface has no EP, this driver does not support this currently -#endif -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_in_as_intf_num) return; -#endif -#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_out_as_intf_num) return; -#endif - - p_desc = tu_desc_next(p_desc); // Exclude standard AS interface descriptor of current alternate interface descriptor - - while (p_desc < p_desc_end) - { - // Abort if follow up descriptor is a new standard interface descriptor - indicates the last AS descriptor was already finished - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) break; - - // Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format type and format and also to get number of physical channels - if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL) - { -#if CFG_TUD_AUDIO_ENABLE_EP_IN - if (as_itf == audio->ep_in_as_intf_num) - { - audio->n_channels_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels; - audio->format_type_tx = (audio_format_type_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType); - -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - audio->format_type_I_tx = (audio_data_format_type_I_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats); -#endif - } -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf == audio->ep_out_as_intf_num) - { - audio->n_channels_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels; - audio->format_type_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType; -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - audio->format_type_I_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats; -#endif - } -#endif - } - - // Look for a Type I Format Type Descriptor(2.3.1.6 - Audio Formats) -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_FORMAT_TYPE && ((audio_desc_type_I_format_t const * )p_desc)->bFormatType == AUDIO_FORMAT_TYPE_I) - { -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) break; // Abort loop, this interface has no EP, this driver does not support this currently -#endif -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_in_as_intf_num) break; -#endif -#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_out_as_intf_num) break; -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN - if (as_itf == audio->ep_in_as_intf_num) - { - audio->n_bytes_per_sampe_tx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; - } -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf == audio->ep_out_as_intf_num) - { - audio->n_bytes_per_sampe_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; - } -#endif - } -#endif - - // Other format types are not supported yet - - p_desc = tu_desc_next(p_desc); - } -} -#endif - -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - -bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - - // Format the feedback value -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION - if ( TUSB_SPEED_FULL == tud_speed_get() ) - { - uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].feedback.value; - - // For FS format is 10.14 - *(fb++) = (feedback >> 2) & 0xFF; - *(fb++) = (feedback >> 10) & 0xFF; - *(fb++) = (feedback >> 18) & 0xFF; - // 4th byte is needed to work correctly with MS Windows - *fb = 0; - }else -#else - { - // Send value as-is, caller will choose the appropriate format - _audiod_fct[func_id].feedback.value = feedback; - } -#endif - - // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value - if (!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb)) - { - return audiod_fb_send(_audiod_fct[func_id].rhport, &_audiod_fct[func_id]); - } - - return true; -} -#endif - -// No security checks here - internal function only which should always succeed -uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio) -{ - for (uint8_t cnt=0; cnt < CFG_TUD_AUDIO; cnt++) - { - if (&_audiod_fct[cnt] == audio) return cnt; - } - return 0; -} - -#endif //CFG_TUD_ENABLED && CFG_TUD_AUDIO diff --git a/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.h b/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.h deleted file mode 100644 index 7c88b99f..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/audio/audio_device.h +++ /dev/null @@ -1,699 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Ha Thach (tinyusb.org) - * Copyright (c) 2020 Reinhard Panhuber - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_AUDIO_DEVICE_H_ -#define _TUSB_AUDIO_DEVICE_H_ - -#include "audio.h" - -//--------------------------------------------------------------------+ -// Class Driver Configuration -//--------------------------------------------------------------------+ - -// All sizes are in bytes! - -#ifndef CFG_TUD_AUDIO_FUNC_1_DESC_LEN -#error You must tell the driver the length of the audio function descriptor including IAD descriptor -#endif -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_DESC_LEN -#error You must tell the driver the length of the audio function descriptor including IAD descriptor -#endif -#endif -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_DESC_LEN -#error You must tell the driver the length of the audio function descriptor including IAD descriptor -#endif -#endif - -// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces -#ifndef CFG_TUD_AUDIO_FUNC_1_N_AS_INT -#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! -#endif -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_N_AS_INT -#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! -#endif -#endif -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_N_AS_INT -#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! -#endif -#endif - -// Size of control buffer used to receive and send control messages via EP0 - has to be big enough to hold your biggest request structure e.g. range requests with multiple intervals defined or cluster descriptors -#ifndef CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ -#error You must define an audio class control request buffer size! -#endif - -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ -#error You must define an audio class control request buffer size! -#endif -#endif - -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ -#error You must define an audio class control request buffer size! -#endif -#endif - -// End point sizes IN BYTES - Limits: Full Speed <= 1023, High Speed <= 1024 -#ifndef CFG_TUD_AUDIO_ENABLE_EP_IN -#define CFG_TUD_AUDIO_ENABLE_EP_IN 0 // TX -#endif - -#ifndef CFG_TUD_AUDIO_ENABLE_EP_OUT -#define CFG_TUD_AUDIO_ENABLE_EP_OUT 0 // RX -#endif - -// Maximum EP sizes for all alternate AS interface settings - used for checks and buffer allocation -#if CFG_TUD_AUDIO_ENABLE_EP_IN -#ifndef CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX -#error You must tell the driver the biggest EP IN size! -#endif -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX -#error You must tell the driver the biggest EP IN size! -#endif -#endif -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX -#error You must tell the driver the biggest EP IN size! -#endif -#endif -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT -#ifndef CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX -#error You must tell the driver the biggest EP OUT size! -#endif -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX -#error You must tell the driver the biggest EP OUT size! -#endif -#endif -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX -#error You must tell the driver the biggest EP OUT size! -#endif -#endif -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT - -// Software EP FIFO buffer sizes - must be >= max EP SIZEs! -#ifndef CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ -#define CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ -#define CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ 0 -#endif - -#ifndef CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ -#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ -#define CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ -#define CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ 0 -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN -#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX -#error EP software buffer size MUST BE at least as big as maximum EP size -#endif - -#if CFG_TUD_AUDIO > 1 -#if CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX -#error EP software buffer size MUST BE at least as big as maximum EP size -#endif -#endif - -#if CFG_TUD_AUDIO > 2 -#if CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX -#error EP software buffer size MUST BE at least as big as maximum EP size -#endif -#endif -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT -#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX -#error EP software buffer size MUST BE at least as big as maximum EP size -#endif - -#if CFG_TUD_AUDIO > 1 -#if CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX -#error EP software buffer size MUST BE at least as big as maximum EP size -#endif -#endif - -#if CFG_TUD_AUDIO > 2 -#if CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX -#error EP software buffer size MUST BE at least as big as maximum EP size -#endif -#endif -#endif - -// Enable/disable feedback EP (required for asynchronous RX applications) -#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // Feedback - 0 or 1 -#endif - -// Enable/disable conversion from 16.16 to 10.14 format on full-speed devices. See tud_audio_n_fb_set(). -#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION -#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 0 // 0 or 1 -#endif - -// Audio interrupt control EP size - disabled if 0 -#ifndef CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 // Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74) -#endif - -#ifndef CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE -#define CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE 6 // Buffer size of audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74) -#endif - -// Use software encoding/decoding - -// The software coding feature of the driver is not mandatory. It is useful if, for instance, you have two I2S streams which need to be interleaved -// into a single PCM stream as SAMPLE_1 | SAMPLE_2 | SAMPLE_3 | SAMPLE_4. -// -// Currently, only PCM type I encoding/decoding is supported! -// -// If the coding feature is to be used, support FIFOs need to be configured. Their sizes and numbers are defined below. - -// Encoding/decoding is done in software and thus time consuming. If you can encode/decode your stream more efficiently do not use the -// support FIFOs but write/read directly into/from the EP_X_SW_BUFFER_FIFOs using -// - tud_audio_n_write() or -// - tud_audio_n_read(). -// To write/read to/from the support FIFOs use -// - tud_audio_n_write_support_ff() or -// - tud_audio_n_read_support_ff(). -// -// The encoding/decoding format type done is defined below. -// -// The encoding/decoding starts when the private callback functions -// - audio_tx_done_cb() -// - audio_rx_done_cb() -// are invoked. If support FIFOs are used, the corresponding encoding/decoding functions are called from there. -// Once encoding/decoding is done the result is put directly into the EP_X_SW_BUFFER_FIFOs. You can use the public callback functions -// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb() -// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb() -// if you want to get informed what happened. -// -// If you don't use the support FIFOs you may use the public callback functions -// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb() -// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb() -// to write/read from/into the EP_X_SW_BUFFER_FIFOs at the right time. -// -// If you need a different encoding which is not support so far implement it in the -// - audio_tx_done_cb() -// - audio_rx_done_cb() -// functions. - -// Enable encoding/decodings - for these to work, support FIFOs need to be setup in appropriate numbers and size -// The actual coding parameters of active AS alternate interface is parsed from the descriptors - -// The item size of the FIFO is always fixed to one i.e. bytes! Furthermore, the actively used FIFO depth is reconfigured such that the depth is a multiple of the current sample size in order to avoid samples to get split up in case of a wrap in the FIFO ring buffer (depth = (max_depth / sampe_sz) * sampe_sz)! -// This is important to remind in case you use DMAs! If the sample sizes changes, the DMA MUST BE RECONFIGURED just like the FIFOs for a different depth!!! - -// For PCM encoding/decoding - -#ifndef CFG_TUD_AUDIO_ENABLE_ENCODING -#define CFG_TUD_AUDIO_ENABLE_ENCODING 0 -#endif - -#ifndef CFG_TUD_AUDIO_ENABLE_DECODING -#define CFG_TUD_AUDIO_ENABLE_DECODING 0 -#endif - -// This enabling allows to save the current coding parameters e.g. # of bytes per sample etc. - TYPE_I includes common PCM encoding -#ifndef CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING -#define CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING 0 -#endif - -#ifndef CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING -#define CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING 0 -#endif - -// Type I Coding parameters not given within UAC2 descriptors -// It would be possible to allow for a more flexible setting and not fix this parameter as done below. However, this is most often not needed and kept for later if really necessary. The more flexible setting could be implemented within set_interface(), however, how the values are saved per alternate setting is to be determined! -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING -#ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#endif -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#endif -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING -#ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#endif -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#endif -#endif - -// Remaining types not support so far - -// Number of support FIFOs to set up - multiple channels can be handled by one FIFO - very common is two channels per FIFO stemming from one I2S interface -#ifndef CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO 0 -#endif - -#ifndef CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO 0 -#endif - -// Size of support FIFOs IN BYTES - if size > 0 there are as many FIFOs set up as CFG_TUD_AUDIO_FUNC_X_N_TX_SUPP_SW_FIFO and CFG_TUD_AUDIO_FUNC_X_N_RX_SUPP_SW_FIFO -#ifndef CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ 0 // FIFO size - minimum size: ceil(f_s/1000) * max(# of TX channels) / (# of TX support FIFOs) * max(# of bytes per sample) -#endif -#ifndef CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ 0 -#endif - -#ifndef CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ 0 // FIFO size - minimum size: ceil(f_s/1000) * max(# of RX channels) / (# of RX support FIFOs) * max(# of bytes per sample) -#endif -#ifndef CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ 0 -#endif - -//static_assert(sizeof(tud_audio_desc_lengths) != CFG_TUD_AUDIO, "Supply audio function descriptor pack length!"); - -// Supported types of this driver: -// AUDIO_DATA_FORMAT_TYPE_I_PCM - Required definitions: CFG_TUD_AUDIO_N_CHANNELS and CFG_TUD_AUDIO_BYTES_PER_CHANNEL - -#ifdef __cplusplus -extern "C" { -#endif - -/** \addtogroup AUDIO_Serial Serial - * @{ - * \defgroup AUDIO_Serial_Device Device - * @{ */ - -//--------------------------------------------------------------------+ -// Application API (Multiple Interfaces) -// CFG_TUD_AUDIO > 1 -//--------------------------------------------------------------------+ -bool tud_audio_n_mounted (uint8_t func_id); - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING -uint16_t tud_audio_n_available (uint8_t func_id); -uint16_t tud_audio_n_read (uint8_t func_id, void* buffer, uint16_t bufsize); -bool tud_audio_n_clear_ep_out_ff (uint8_t func_id); // Delete all content in the EP OUT FIFO -tu_fifo_t* tud_audio_n_get_ep_out_ff (uint8_t func_id); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING -bool tud_audio_n_clear_rx_support_ff (uint8_t func_id, uint8_t ff_idx); // Delete all content in the support RX FIFOs -uint16_t tud_audio_n_available_support_ff (uint8_t func_id, uint8_t ff_idx); -uint16_t tud_audio_n_read_support_ff (uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize); -tu_fifo_t* tud_audio_n_get_rx_support_ff (uint8_t func_id, uint8_t ff_idx); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING -uint16_t tud_audio_n_write (uint8_t func_id, const void * data, uint16_t len); -bool tud_audio_n_clear_ep_in_ff (uint8_t func_id); // Delete all content in the EP IN FIFO -tu_fifo_t* tud_audio_n_get_ep_in_ff (uint8_t func_id); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING -uint16_t tud_audio_n_flush_tx_support_ff (uint8_t func_id); // Force all content in the support TX FIFOs to be written into EP SW FIFO -bool tud_audio_n_clear_tx_support_ff (uint8_t func_id, uint8_t ff_idx); -uint16_t tud_audio_n_write_support_ff (uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len); -tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_idx); -#endif - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -uint16_t tud_audio_int_ctr_n_write (uint8_t func_id, uint8_t const* buffer, uint16_t len); -#endif - -//--------------------------------------------------------------------+ -// Application API (Interface0) -//--------------------------------------------------------------------+ - -static inline bool tud_audio_mounted (void); - -// RX API - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING -static inline uint16_t tud_audio_available (void); -static inline bool tud_audio_clear_ep_out_ff (void); // Delete all content in the EP OUT FIFO -static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize); -static inline tu_fifo_t* tud_audio_get_ep_out_ff (void); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING -static inline bool tud_audio_clear_rx_support_ff (uint8_t ff_idx); -static inline uint16_t tud_audio_available_support_ff (uint8_t ff_idx); -static inline uint16_t tud_audio_read_support_ff (uint8_t ff_idx, void* buffer, uint16_t bufsize); -static inline tu_fifo_t* tud_audio_get_rx_support_ff (uint8_t ff_idx); -#endif - -// TX API - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING -static inline uint16_t tud_audio_write (const void * data, uint16_t len); -static inline bool tud_audio_clear_ep_in_ff (void); -static inline tu_fifo_t* tud_audio_get_ep_in_ff (void); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING -static inline uint16_t tud_audio_flush_tx_support_ff (void); -static inline uint16_t tud_audio_clear_tx_support_ff (uint8_t ff_idx); -static inline uint16_t tud_audio_write_support_ff (uint8_t ff_idx, const void * data, uint16_t len); -static inline tu_fifo_t* tud_audio_get_tx_support_ff (uint8_t ff_idx); -#endif - -// INT CTR API - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -static inline uint16_t tud_audio_int_ctr_write (uint8_t const* buffer, uint16_t len); -#endif - -// Buffer control EP data and schedule a transmit -// This function is intended to be used if you do not have a persistent buffer or memory location available (e.g. non-local variables) and need to answer onto a -// get request. This function buffers your answer request frame into the control buffer of the corresponding audio driver and schedules a transmit for sending it. -// Since transmission is triggered via interrupts, a persistent memory location is required onto which the buffer pointer in pointing. If you already have such -// available you may directly use 'tud_control_xfer(...)'. In this case data does not need to be copied into an additional buffer and you save some time. -// If the request's wLength is zero, a status packet is sent instead. -bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len); - -//--------------------------------------------------------------------+ -// Application Callback API (weak is optional) -//--------------------------------------------------------------------+ - -#if CFG_TUD_AUDIO_ENABLE_EP_IN -TU_ATTR_WEAK bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting); -TU_ATTR_WEAK bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT -TU_ATTR_WEAK bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting); -TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id); - - -// determined by the user itself and set by use of tud_audio_n_fb_set(). The feedback value may be determined e.g. from some fill status of some FIFO buffer. Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus less CPU load, disadvantage: typically a larger FIFO is needed to compensate for jitter (e.g. 8 frames), i.e. a larger delay is introduced. - -// Feedback value is calculated within the audio driver by use of SOF interrupt. The driver needs information about the master clock f_m from which the audio sample frequency f_s is derived, f_s itself, and the cycle count of f_m at time of the SOF interrupt (e.g. by use of a hardware counter) - see tud_audio_set_fb_params(). Advantage: Reduced jitter in the feedback value computation, hence, the receive FIFO can be smaller (e.g. 2 frames) and thus a smaller delay is possible, disadvantage: higher CPU load due to SOF ISR handling every frame i.e. 1ms or 125us. This option is a great starting point to try the SOF ISR option but depending on your hardware setup (performance of the CPU) it might not work. If so, figure out why and use the next option. (The most critical point is the reading of the cycle counter value of f_m. It is read from within the SOF ISR - see: audiod_sof() -, hence, the ISR must has a high priority such that no software dependent "random" delay i.e. jitter is introduced). - -// Feedback value is determined by the user by use of SOF interrupt. The user may use tud_audio_sof_isr() which is called every SOF (of course only invoked when an alternate interface other than zero was set). The number of frames used to determine the feedback value for the currently active alternate setting can be get by tud_audio_get_fb_n_frames(). The feedback value must be set by use of tud_audio_n_fb_set(). - -// This function is used to provide data rate feedback from an asynchronous sink. Feedback value will be sent at FB endpoint interval till it's changed. -// -// The feedback format is specified to be 16.16 for HS and 10.14 for FS devices (see Universal Serial Bus Specification Revision 2.0 5.12.4.2). By default, -// the choice of format is left to the caller and feedback argument is sent as-is. If CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION is set, then tinyusb -// expects 16.16 format and handles the conversion to 10.14 on FS. -// -// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 devices. On Linux and macOS it seems the -// driver can work with either format. So a good compromise is to keep format correction disabled and stick to 16.16 format. - -// Feedback value can be determined from within the SOF ISR of the audio driver. This should reduce jitter. If the feature is used, the user can not set the feedback value. - -// Determine feedback value - The feedback method is described in 5.12.4.2 of the USB 2.0 spec -// Boiled down, the feedback value Ff = n_samples / (micro)frame. -// Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s) -// The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where P = min( ceil(log2(f_m / f_s)), K) -// feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames - -bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback); -static inline bool tud_audio_fb_set(uint32_t feedback); - -// Update feedback value with passed cycles since last time this update function is called. -// Typically called within tud_audio_sof_isr(). Required tud_audio_feedback_params_cb() is implemented -// This function will also call tud_audio_feedback_set() -// return feedback value in 16.16 for reference (0 for error) -uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles); - -enum { - AUDIO_FEEDBACK_METHOD_DISABLED, - AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED, - AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT, - AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2, - - // impelemnt later - // AUDIO_FEEDBACK_METHOD_FIFO_COUNT -}; - -typedef struct { - uint8_t method; - uint32_t sample_freq; // sample frequency in Hz - - union { - struct { - uint32_t mclk_freq; // Main clock frequency in Hz i.e. master clock to which sample clock is based on - }frequency; - -#if 0 // implement later - struct { - uint32_t threshold_bytes; // minimum number of bytes received to be considered as filled/ready - }fifo_count; -#endif - }; -}audio_feedback_params_t; - -// Invoked when needed to set feedback parameters -TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param); - -// Callback in ISR context, invoked periodically according to feedback endpoint bInterval. -// Could be used to compute and update feedback value, should be placed in RAM if possible -// frame_number : current SOF count -// interval_shift: number of bit shift i.e log2(interval) from Feedback endpoint descriptor -TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift); - -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t n_bytes_copied); -#endif - -// Invoked when audio set interface request received -TU_ATTR_WEAK bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request); - -// Invoked when audio set interface request received which closes an EP -TU_ATTR_WEAK bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request); - -// Invoked when audio class specific set request received for an EP -TU_ATTR_WEAK bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); - -// Invoked when audio class specific set request received for an interface -TU_ATTR_WEAK bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); - -// Invoked when audio class specific set request received for an entity -TU_ATTR_WEAK bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); - -// Invoked when audio class specific get request received for an EP -TU_ATTR_WEAK bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request); - -// Invoked when audio class specific get request received for an interface -TU_ATTR_WEAK bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request); - -// Invoked when audio class specific get request received for an entity -TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request); - -//--------------------------------------------------------------------+ -// Inline Functions -//--------------------------------------------------------------------+ - -static inline bool tud_audio_mounted(void) -{ - return tud_audio_n_mounted(0); -} - -// RX API - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING - -static inline uint16_t tud_audio_available(void) -{ - return tud_audio_n_available(0); -} - -static inline uint16_t tud_audio_read(void* buffer, uint16_t bufsize) -{ - return tud_audio_n_read(0, buffer, bufsize); -} - -static inline bool tud_audio_clear_ep_out_ff(void) -{ - return tud_audio_n_clear_ep_out_ff(0); -} - -static inline tu_fifo_t* tud_audio_get_ep_out_ff(void) -{ - return tud_audio_n_get_ep_out_ff(0); -} - -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - -static inline bool tud_audio_clear_rx_support_ff(uint8_t ff_idx) -{ - return tud_audio_n_clear_rx_support_ff(0, ff_idx); -} - -static inline uint16_t tud_audio_available_support_ff(uint8_t ff_idx) -{ - return tud_audio_n_available_support_ff(0, ff_idx); -} - -static inline uint16_t tud_audio_read_support_ff(uint8_t ff_idx, void* buffer, uint16_t bufsize) -{ - return tud_audio_n_read_support_ff(0, ff_idx, buffer, bufsize); -} - -static inline tu_fifo_t* tud_audio_get_rx_support_ff(uint8_t ff_idx) -{ - return tud_audio_n_get_rx_support_ff(0, ff_idx); -} - -#endif - -// TX API - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - -static inline uint16_t tud_audio_write(const void * data, uint16_t len) -{ - return tud_audio_n_write(0, data, len); -} - -static inline bool tud_audio_clear_ep_in_ff(void) -{ - return tud_audio_n_clear_ep_in_ff(0); -} - -static inline tu_fifo_t* tud_audio_get_ep_in_ff(void) -{ - return tud_audio_n_get_ep_in_ff(0); -} - -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - -static inline uint16_t tud_audio_flush_tx_support_ff(void) -{ - return tud_audio_n_flush_tx_support_ff(0); -} - -static inline uint16_t tud_audio_clear_tx_support_ff(uint8_t ff_idx) -{ - return tud_audio_n_clear_tx_support_ff(0, ff_idx); -} - -static inline uint16_t tud_audio_write_support_ff(uint8_t ff_idx, const void * data, uint16_t len) -{ - return tud_audio_n_write_support_ff(0, ff_idx, data, len); -} - -static inline tu_fifo_t* tud_audio_get_tx_support_ff(uint8_t ff_idx) -{ - return tud_audio_n_get_tx_support_ff(0, ff_idx); -} - -#endif - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t len) -{ - return tud_audio_int_ctr_n_write(0, buffer, len); -} -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - -static inline bool tud_audio_fb_set(uint32_t feedback) -{ - return tud_audio_n_fb_set(0, feedback); -} - -#endif - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void audiod_init (void); -void audiod_reset (uint8_t rhport); -uint16_t audiod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -bool audiod_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); -void audiod_sof_isr (uint8_t rhport, uint32_t frame_count); - -#ifdef __cplusplus -} -#endif - -#endif /* _TUSB_AUDIO_DEVICE_H_ */ - -/** @} */ -/** @} */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.c b/test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.c deleted file mode 100755 index f96bb355..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Jerzy Kasenberg - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_BTH) - -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "bth_device.h" -#include - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -typedef struct -{ - uint8_t itf_num; - uint8_t ep_ev; - uint8_t ep_acl_in; - uint8_t ep_acl_out; - uint8_t ep_voice[2]; // Not used yet - uint8_t ep_voice_size[2][CFG_TUD_BTH_ISO_ALT_COUNT]; - - // Endpoint Transfer buffer - CFG_TUSB_MEM_ALIGN bt_hci_cmd_t hci_cmd; - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_BTH_DATA_EPSIZE]; - -} btd_interface_t; - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION btd_interface_t _btd_itf; - -static bool bt_tx_data(uint8_t ep, void *data, uint16_t len) -{ - uint8_t const rhport = 0; - - // skip if previous transfer not complete - TU_VERIFY(!usbd_edpt_busy(rhport, ep)); - - TU_ASSERT(usbd_edpt_xfer(rhport, ep, data, len)); - - return true; -} - -//--------------------------------------------------------------------+ -// READ API -//--------------------------------------------------------------------+ - - -//--------------------------------------------------------------------+ -// WRITE API -//--------------------------------------------------------------------+ - -bool tud_bt_event_send(void *event, uint16_t event_len) -{ - return bt_tx_data(_btd_itf.ep_ev, event, event_len); -} - -bool tud_bt_acl_data_send(void *event, uint16_t event_len) -{ - return bt_tx_data(_btd_itf.ep_acl_in, event, event_len); -} - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void btd_init(void) -{ - tu_memclr(&_btd_itf, sizeof(_btd_itf)); -} - -void btd_reset(uint8_t rhport) -{ - (void)rhport; -} - -uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) -{ - tusb_desc_endpoint_t const *desc_ep; - uint16_t drv_len = 0; - // Size of single alternative of ISO interface - const uint16_t iso_alt_itf_size = sizeof(tusb_desc_interface_t) + 2 * sizeof(tusb_desc_endpoint_t); - // Size of hci interface - const uint16_t hci_itf_size = sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t); - // Ensure this is BT Primary Controller - TU_VERIFY(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass && - TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass && - TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0); - - TU_ASSERT(itf_desc->bNumEndpoints == 3 && max_len >= hci_itf_size); - - _btd_itf.itf_num = itf_desc->bInterfaceNumber; - - desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); - - TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer, 0); - TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); - _btd_itf.ep_ev = desc_ep->bEndpointAddress; - - // Open endpoint pair - TU_ASSERT(usbd_open_edpt_pair(rhport, tu_desc_next(desc_ep), 2, TUSB_XFER_BULK, &_btd_itf.ep_acl_out, - &_btd_itf.ep_acl_in), 0); - - itf_desc = (tusb_desc_interface_t const *)tu_desc_next(tu_desc_next(tu_desc_next(desc_ep))); - - // Prepare for incoming data from host - TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE), 0); - - drv_len = hci_itf_size; - - // Ensure this is still BT Primary Controller - TU_ASSERT(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass && - TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass && - TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0); - TU_ASSERT(itf_desc->bNumEndpoints == 2 && max_len >= iso_alt_itf_size + drv_len); - - uint8_t dir; - - desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc); - TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0); - TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0); - dir = tu_edpt_dir(desc_ep->bEndpointAddress); - _btd_itf.ep_voice[dir] = desc_ep->bEndpointAddress; - // Store endpoint size for alternative - _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); - - desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep); - TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0); - dir = tu_edpt_dir(desc_ep->bEndpointAddress); - _btd_itf.ep_voice[dir] = desc_ep->bEndpointAddress; - // Store endpoint size for alternative - _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); - drv_len += iso_alt_itf_size; - - for (int i = 1; i < CFG_TUD_BTH_ISO_ALT_COUNT && drv_len + iso_alt_itf_size <= max_len; ++i) { - // Make sure rest of alternatives matches - itf_desc = (tusb_desc_interface_t const *)tu_desc_next(desc_ep); - if (itf_desc->bDescriptorType != TUSB_DESC_INTERFACE || - TUSB_CLASS_WIRELESS_CONTROLLER != itf_desc->bInterfaceClass || - TUD_BT_APP_SUBCLASS != itf_desc->bInterfaceSubClass || - TUD_BT_PROTOCOL_PRIMARY_CONTROLLER != itf_desc->bInterfaceProtocol) - { - // Not an Iso interface instance - break; - } - TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0); - - desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc); - dir = tu_edpt_dir(desc_ep->bEndpointAddress); - // Verify that alternative endpoint are same as first ones - TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT && - _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0); - _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); - - desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep); - dir = tu_edpt_dir(desc_ep->bEndpointAddress); - // Verify that alternative endpoint are same as first ones - TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT && - _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0); - _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); - drv_len += iso_alt_itf_size; - } - - return drv_len; -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) -{ - (void)rhport; - - if ( stage == CONTROL_STAGE_SETUP ) - { - if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && - request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE) - { - // HCI command packet addressing for single function Primary Controllers - TU_VERIFY(request->bRequest == 0 && request->wValue == 0 && request->wIndex == 0); - } - else if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE) - { - if (request->bRequest == TUSB_REQ_SET_INTERFACE && _btd_itf.itf_num + 1 == request->wIndex) - { - // TODO: Set interface it would involve changing size of endpoint size - } - else - { - // HCI command packet for Primary Controller function in a composite device - TU_VERIFY(request->bRequest == 0 && request->wValue == 0 && request->wIndex == _btd_itf.itf_num); - } - } - else return false; - - return tud_control_xfer(rhport, request, &_btd_itf.hci_cmd, sizeof(_btd_itf.hci_cmd)); - } - else if ( stage == CONTROL_STAGE_DATA ) - { - // Handle class request only - TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); - - if (tud_bt_hci_cmd_cb) tud_bt_hci_cmd_cb(&_btd_itf.hci_cmd, tu_min16(request->wLength, sizeof(_btd_itf.hci_cmd))); - } - - return true; -} - -bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void)result; - - // received new data from host - if (ep_addr == _btd_itf.ep_acl_out) - { - if (tud_bt_acl_data_received_cb) tud_bt_acl_data_received_cb(_btd_itf.epout_buf, xferred_bytes); - - // prepare for next data - TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE)); - } - else if (ep_addr == _btd_itf.ep_ev) - { - if (tud_bt_event_sent_cb) tud_bt_event_sent_cb((uint16_t)xferred_bytes); - } - else if (ep_addr == _btd_itf.ep_acl_in) - { - if (tud_bt_acl_data_sent_cb) tud_bt_acl_data_sent_cb((uint16_t)xferred_bytes); - } - - return true; -} - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.h b/test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.h deleted file mode 100755 index 921bd7a1..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/bth/bth_device.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Jerzy Kasenberg - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_BTH_DEVICE_H_ -#define _TUSB_BTH_DEVICE_H_ - -#include -#include - -//--------------------------------------------------------------------+ -// Class Driver Configuration -//--------------------------------------------------------------------+ -#ifndef CFG_TUD_BTH_EVENT_EPSIZE -#define CFG_TUD_BTH_EVENT_EPSIZE 16 -#endif -#ifndef CFG_TUD_BTH_DATA_EPSIZE -#define CFG_TUD_BTH_DATA_EPSIZE 64 -#endif - -typedef struct TU_ATTR_PACKED -{ - uint16_t op_code; - uint8_t param_length; - uint8_t param[255]; -} bt_hci_cmd_t; - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Application Callback API (weak is optional) -//--------------------------------------------------------------------+ - -// Invoked when HCI command was received over USB from Bluetooth host. -// Detailed format is described in Bluetooth core specification Vol 2, -// Part E, 5.4.1. -// Length of the command is from 3 bytes (2 bytes for OpCode, -// 1 byte for parameter total length) to 258. -TU_ATTR_WEAK void tud_bt_hci_cmd_cb(void *hci_cmd, size_t cmd_len); - -// Invoked when ACL data was received over USB from Bluetooth host. -// Detailed format is described in Bluetooth core specification Vol 2, -// Part E, 5.4.2. -// Length is from 4 bytes, (12 bits for Handle, 4 bits for flags -// and 16 bits for data total length) to endpoint size. -TU_ATTR_WEAK void tud_bt_acl_data_received_cb(void *acl_data, uint16_t data_len); - -// Called when event sent with tud_bt_event_send() was delivered to BT stack. -// Controller can release/reuse buffer with Event packet at this point. -TU_ATTR_WEAK void tud_bt_event_sent_cb(uint16_t sent_bytes); - -// Called when ACL data that was sent with tud_bt_acl_data_send() -// was delivered to BT stack. -// Controller can release/reuse buffer with ACL packet at this point. -TU_ATTR_WEAK void tud_bt_acl_data_sent_cb(uint16_t sent_bytes); - -// Bluetooth controller calls this function when it wants to send even packet -// as described in Bluetooth core specification Vol 2, Part E, 5.4.4. -// Event has at least 2 bytes, first is Event code second contains parameter -// total length. Controller can release/reuse event memory after -// tud_bt_event_sent_cb() is called. -bool tud_bt_event_send(void *event, uint16_t event_len); - -// Bluetooth controller calls this to send ACL data packet -// as described in Bluetooth core specification Vol 2, Part E, 5.4.2 -// Minimum length is 4 bytes, (12 bits for Handle, 4 bits for flags -// and 16 bits for data total length). Upper limit is not limited -// to endpoint size since buffer is allocate by controller -// and must not be reused till tud_bt_acl_data_sent_cb() is called. -bool tud_bt_acl_data_send(void *acl_data, uint16_t data_len); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void btd_init (void); -void btd_reset (uint8_t rhport); -uint16_t btd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool btd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); -bool btd_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_BTH_DEVICE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc.h b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc.h index 4658e43a..5cbd658f 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc.h @@ -136,8 +136,7 @@ typedef enum{ //--------------------------------------------------------------------+ /// Communication Interface Management Element Request Codes -typedef enum -{ +typedef enum { CDC_REQUEST_SEND_ENCAPSULATED_COMMAND = 0x00, ///< is used to issue a command in the format of the supported control protocol of the Communications Class interface CDC_REQUEST_GET_ENCAPSULATED_RESPONSE = 0x01, ///< is used to request a response in the format of the supported control protocol of the Communications Class interface. CDC_REQUEST_SET_COMM_FEATURE = 0x02, @@ -180,37 +179,38 @@ typedef enum CDC_REQUEST_GET_ATM_VC_STATISTICS = 0x53, CDC_REQUEST_MDLM_SEMANTIC_MODEL = 0x60, -}cdc_management_request_t; +} cdc_management_request_t; -enum -{ +typedef enum { CDC_CONTROL_LINE_STATE_DTR = 0x01, CDC_CONTROL_LINE_STATE_RTS = 0x02, -}; +} cdc_control_line_state_t; -enum -{ - CDC_LINE_CONDING_STOP_BITS_1 = 0, // 1 bit - CDC_LINE_CONDING_STOP_BITS_1_5 = 1, // 1.5 bits - CDC_LINE_CONDING_STOP_BITS_2 = 2, // 2 bits -}; +typedef enum { + CDC_LINE_CODING_STOP_BITS_1 = 0, // 1 bit + CDC_LINE_CODING_STOP_BITS_1_5 = 1, // 1.5 bits + CDC_LINE_CODING_STOP_BITS_2 = 2, // 2 bits +} cdc_line_coding_stopbits_t; -enum -{ +// TODO Backward compatible for typos. Maybe removed in the future release +#define CDC_LINE_CONDING_STOP_BITS_1 CDC_LINE_CODING_STOP_BITS_1 +#define CDC_LINE_CONDING_STOP_BITS_1_5 CDC_LINE_CODING_STOP_BITS_1_5 +#define CDC_LINE_CONDING_STOP_BITS_2 CDC_LINE_CODING_STOP_BITS_2 + +typedef enum { CDC_LINE_CODING_PARITY_NONE = 0, CDC_LINE_CODING_PARITY_ODD = 1, CDC_LINE_CODING_PARITY_EVEN = 2, CDC_LINE_CODING_PARITY_MARK = 3, CDC_LINE_CODING_PARITY_SPACE = 4, -}; +} cdc_line_coding_parity_t; //--------------------------------------------------------------------+ // Management Element Notification (Notification Endpoint) //--------------------------------------------------------------------+ /// 6.3 Notification Codes -typedef enum -{ +typedef enum { CDC_NOTIF_NETWORK_CONNECTION = 0x00, ///< This notification allows the device to notify the host about network connection status. CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request. CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08, diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.c b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.c index 5adce521..2e0a0c30 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.c @@ -33,13 +33,17 @@ #include "cdc_device.h" +// Level where CFG_TUSB_DEBUG must be at least for this driver is logged +#ifndef CFG_TUD_CDC_LOG_LEVEL + #define CFG_TUD_CDC_LOG_LEVEL CFG_TUD_LOG_LEVEL +#endif + +#define TU_LOG_DRV(...) TU_LOG(CFG_TUD_CDC_LOG_LEVEL, __VA_ARGS__) + //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -enum -{ - BULK_PACKET_SIZE = (TUD_OPT_HIGH_SPEED ? 512 : 64) -}; +#define BULK_PACKET_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) typedef struct { @@ -76,7 +80,7 @@ typedef struct //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION tu_static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; +CFG_TUD_MEM_SECTION tu_static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; static bool _prep_out_transaction (cdcd_interface_t* p_cdc) { @@ -143,7 +147,7 @@ uint32_t tud_cdc_n_available(uint8_t itf) uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize) { cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; - uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, (uint16_t) bufsize); + uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX)); _prep_out_transaction(p_cdc); return num_read; } @@ -166,12 +170,14 @@ void tud_cdc_n_read_flush (uint8_t itf) uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) { cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; - uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) bufsize); + uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX)); // flush if queue more than packet size - // may need to suppress -Wunreachable-code since most of the time CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE - if ( (tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE) || ((CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE) && tu_fifo_full(&p_cdc->tx_ff)) ) - { + if ( tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE + #if CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE + || tu_fifo_full(&p_cdc->tx_ff) // check full if fifo size is less than packet size + #endif + ) { tud_cdc_n_write_flush(itf); } @@ -246,9 +252,37 @@ void cdcd_init(void) // In this way, the most current data is prioritized. tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, true); - tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, osal_mutex_create(&p_cdc->rx_ff_mutex)); - tu_fifo_config_mutex(&p_cdc->tx_ff, osal_mutex_create(&p_cdc->tx_ff_mutex), NULL); + #if OSAL_MUTEX_REQUIRED + osal_mutex_t mutex_rd = osal_mutex_create(&p_cdc->rx_ff_mutex); + osal_mutex_t mutex_wr = osal_mutex_create(&p_cdc->tx_ff_mutex); + TU_ASSERT(mutex_rd != NULL && mutex_wr != NULL, ); + + tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, mutex_rd); + tu_fifo_config_mutex(&p_cdc->tx_ff, mutex_wr, NULL); + #endif + } +} + +bool cdcd_deinit(void) { + #if OSAL_MUTEX_REQUIRED + for(uint8_t i=0; irx_ff.mutex_rd; + osal_mutex_t mutex_wr = p_cdc->tx_ff.mutex_wr; + + if (mutex_rd) { + osal_mutex_delete(mutex_rd); + tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, NULL); + } + + if (mutex_wr) { + osal_mutex_delete(mutex_wr); + tu_fifo_config_mutex(&p_cdc->tx_ff, NULL, NULL); + } } + #endif + + return true; } void cdcd_reset(uint8_t rhport) @@ -353,7 +387,7 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t case CDC_REQUEST_SET_LINE_CODING: if (stage == CONTROL_STAGE_SETUP) { - TU_LOG2(" Set Line Coding\r\n"); + TU_LOG_DRV(" Set Line Coding\r\n"); tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); } else if ( stage == CONTROL_STAGE_ACK) @@ -365,7 +399,7 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t case CDC_REQUEST_GET_LINE_CODING: if (stage == CONTROL_STAGE_SETUP) { - TU_LOG2(" Get Line Coding\r\n"); + TU_LOG_DRV(" Get Line Coding\r\n"); tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); } break; @@ -390,7 +424,7 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t // Disable fifo overwriting if DTR bit is set tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr); - TU_LOG2(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); + TU_LOG_DRV(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); // Invoke callback if ( tud_cdc_line_state_cb ) tud_cdc_line_state_cb(itf, dtr, rts); @@ -403,7 +437,7 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t } else if (stage == CONTROL_STAGE_ACK) { - TU_LOG2(" Send Break\r\n"); + TU_LOG_DRV(" Send Break\r\n"); if ( tud_cdc_send_break_cb ) tud_cdc_send_break_cb(itf, request->wValue); } break; diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.h b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.h index a6e07aa5..20e90845 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_device.h @@ -247,6 +247,7 @@ static inline bool tud_cdc_write_clear(void) // INTERNAL USBD-CLASS DRIVER API //--------------------------------------------------------------------+ void cdcd_init (void); +bool cdcd_deinit (void); void cdcd_reset (uint8_t rhport); uint16_t cdcd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); bool cdcd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.c b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.c index fe3691bf..133a10f6 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.c +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.c @@ -22,6 +22,9 @@ * THE SOFTWARE. * * This file is part of the TinyUSB stack. + * + * Contribution + * - Heiko Kuester: CH34x support */ #include "tusb_option.h" @@ -29,14 +32,16 @@ #if (CFG_TUH_ENABLED && CFG_TUH_CDC) #include "host/usbh.h" -#include "host/usbh_classdriver.h" +#include "host/usbh_pvt.h" #include "cdc_host.h" -// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message -#define CDCH_DEBUG 2 +// Level where CFG_TUSB_DEBUG must be at least for this driver is logged +#ifndef CFG_TUH_CDC_LOG_LEVEL + #define CFG_TUH_CDC_LOG_LEVEL CFG_TUH_LOG_LEVEL +#endif -#define TU_LOG_CDCH(...) TU_LOG(CDCH_DEBUG, __VA_ARGS__) +#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__) //--------------------------------------------------------------------+ // Host CDC Interface @@ -48,12 +53,18 @@ typedef struct { uint8_t bInterfaceSubClass; uint8_t bInterfaceProtocol; + uint8_t ep_notif; uint8_t serial_drid; // Serial Driver ID + bool mounted; // Enumeration is complete cdc_acm_capability_t acm_capability; - uint8_t ep_notif; - uint8_t line_state; // DTR (bit0), RTS (bit1) TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width + uint8_t line_state; // DTR (bit0), RTS (bit1) + + #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X + cdc_line_coding_t requested_line_coding; + // 1 byte padding + #endif tuh_xfer_cb_t user_control_cb; @@ -67,7 +78,6 @@ typedef struct { uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; CFG_TUH_MEM_ALIGN uint8_t rx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; } stream; - } cdch_interface_t; CFG_TUH_MEM_SECTION @@ -78,47 +88,60 @@ static cdch_interface_t cdch_data[CFG_TUH_CDC]; //--------------------------------------------------------------------+ //------------- ACM prototypes -------------// +static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); static void acm_process_config(tuh_xfer_t* xfer); +static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); //------------- FTDI prototypes -------------// #if CFG_TUH_CDC_FTDI #include "serial/ftdi_sio.h" -static uint16_t const ftdi_pids[] = { TU_FTDI_PID_LIST }; -enum { - FTDI_PID_COUNT = sizeof(ftdi_pids) / sizeof(ftdi_pids[0]) -}; - -// Store last request baudrate since divisor to baudrate is not easy -static uint32_t _ftdi_requested_baud; +static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST}; static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); static void ftdi_process_config(tuh_xfer_t* xfer); -static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- CP210X prototypes -------------// #if CFG_TUH_CDC_CP210X #include "serial/cp210x.h" -static uint16_t const cp210x_pids[] = { TU_CP210X_PID_LIST }; -enum { - CP210X_PID_COUNT = sizeof(cp210x_pids) / sizeof(cp210x_pids[0]) -}; +static uint16_t const cp210x_vid_pid_list[][2] = {CFG_TUH_CDC_CP210X_VID_PID_LIST}; static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); static void cp210x_process_config(tuh_xfer_t* xfer); -static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +#endif + +//------------- CH34x prototypes -------------// +#if CFG_TUH_CDC_CH34X +#include "serial/ch34x.h" + +static uint16_t const ch34x_vid_pid_list[][2] = {CFG_TUH_CDC_CH34X_VID_PID_LIST}; + +static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len); +static void ch34x_process_config(tuh_xfer_t* xfer); + +static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif +//------------- Common -------------// enum { SERIAL_DRIVER_ACM = 0, @@ -129,60 +152,96 @@ enum { #if CFG_TUH_CDC_CP210X SERIAL_DRIVER_CP210X, #endif + +#if CFG_TUH_CDC_CH34X + SERIAL_DRIVER_CH34X, +#endif + + SERIAL_DRIVER_COUNT }; typedef struct { + uint16_t const (*vid_pid_list)[2]; + uint16_t const vid_pid_count; + bool (*const open)(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); void (*const process_set_config)(tuh_xfer_t* xfer); bool (*const set_control_line_state)(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_baudrate)(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_data_format)(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_line_coding)(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); } cdch_serial_driver_t; // Note driver list must be in the same order as SERIAL_DRIVER enum static const cdch_serial_driver_t serial_drivers[] = { - { .process_set_config = acm_process_config, - .set_control_line_state = acm_set_control_line_state, - .set_baudrate = acm_set_baudrate + { + .vid_pid_list = NULL, + .vid_pid_count = 0, + .open = acm_open, + .process_set_config = acm_process_config, + .set_control_line_state = acm_set_control_line_state, + .set_baudrate = acm_set_baudrate, + .set_data_format = acm_set_data_format, + .set_line_coding = acm_set_line_coding }, #if CFG_TUH_CDC_FTDI - { .process_set_config = ftdi_process_config, - .set_control_line_state = ftdi_sio_set_modem_ctrl, - .set_baudrate = ftdi_sio_set_baudrate + { + .vid_pid_list = ftdi_vid_pid_list, + .vid_pid_count = TU_ARRAY_SIZE(ftdi_vid_pid_list), + .open = ftdi_open, + .process_set_config = ftdi_process_config, + .set_control_line_state = ftdi_sio_set_modem_ctrl, + .set_baudrate = ftdi_sio_set_baudrate, + .set_data_format = ftdi_set_data_format, + .set_line_coding = ftdi_set_line_coding }, #endif #if CFG_TUH_CDC_CP210X - { .process_set_config = cp210x_process_config, - .set_control_line_state = cp210x_set_modem_ctrl, - .set_baudrate = cp210x_set_baudrate + { + .vid_pid_list = cp210x_vid_pid_list, + .vid_pid_count = TU_ARRAY_SIZE(cp210x_vid_pid_list), + .open = cp210x_open, + .process_set_config = cp210x_process_config, + .set_control_line_state = cp210x_set_modem_ctrl, + .set_baudrate = cp210x_set_baudrate, + .set_data_format = cp210x_set_data_format, + .set_line_coding = cp210x_set_line_coding }, #endif -}; -enum { - SERIAL_DRIVER_COUNT = sizeof(serial_drivers) / sizeof(serial_drivers[0]) + #if CFG_TUH_CDC_CH34X + { + .vid_pid_list = ch34x_vid_pid_list, + .vid_pid_count = TU_ARRAY_SIZE(ch34x_vid_pid_list), + .open = ch34x_open, + .process_set_config = ch34x_process_config, + .set_control_line_state = ch34x_set_modem_ctrl, + .set_baudrate = ch34x_set_baudrate, + .set_data_format = ch34x_set_data_format, + .set_line_coding = ch34x_set_line_coding + }, + #endif }; +TU_VERIFY_STATIC(TU_ARRAY_SIZE(serial_drivers) == SERIAL_DRIVER_COUNT, "Serial driver count mismatch"); + //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -static inline cdch_interface_t* get_itf(uint8_t idx) -{ +static inline cdch_interface_t* get_itf(uint8_t idx) { TU_ASSERT(idx < CFG_TUH_CDC, NULL); cdch_interface_t* p_cdc = &cdch_data[idx]; return (p_cdc->daddr != 0) ? p_cdc : NULL; } -static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) -{ - for(uint8_t i=0; idaddr == daddr) && - (ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr)) - { + (ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr)) { return i; } } @@ -190,14 +249,10 @@ static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) return TUSB_INDEX_INVALID_8; } - -static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const *itf_desc) -{ - for(uint8_t i=0; idaddr = daddr; p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber; p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; @@ -218,20 +273,16 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer); // APPLICATION API //--------------------------------------------------------------------+ -uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num) -{ - for(uint8_t i=0; idaddr == daddr && p_cdc->bInterfaceNumber == itf_num) return i; } return TUSB_INDEX_INVALID_8; } -bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) -{ +bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc && info); @@ -253,30 +304,27 @@ bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) return true; } -bool tuh_cdc_mounted(uint8_t idx) -{ +bool tuh_cdc_mounted(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); - return p_cdc != NULL; + TU_VERIFY(p_cdc); + return p_cdc->mounted; } -bool tuh_cdc_get_dtr(uint8_t idx) -{ +bool tuh_cdc_get_dtr(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR) ? true : false; } -bool tuh_cdc_get_rts(uint8_t idx) -{ +bool tuh_cdc_get_rts(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS) ? true : false; } -bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) -{ +bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); @@ -289,32 +337,28 @@ bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) // Write //--------------------------------------------------------------------+ -uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) -{ +uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_write(&p_cdc->stream.tx, buffer, bufsize); } -uint32_t tuh_cdc_write_flush(uint8_t idx) -{ +uint32_t tuh_cdc_write_flush(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_write_xfer(&p_cdc->stream.tx); } -bool tuh_cdc_write_clear(uint8_t idx) -{ +bool tuh_cdc_write_clear(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_clear(&p_cdc->stream.tx); } -uint32_t tuh_cdc_write_available(uint8_t idx) -{ +uint32_t tuh_cdc_write_available(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); @@ -325,32 +369,28 @@ uint32_t tuh_cdc_write_available(uint8_t idx) // Read //--------------------------------------------------------------------+ -uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) -{ +uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_read(&p_cdc->stream.rx, buffer, bufsize); } -uint32_t tuh_cdc_read_available(uint8_t idx) -{ +uint32_t tuh_cdc_read_available(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_read_available(&p_cdc->stream.rx); } -bool tuh_cdc_peek(uint8_t idx, uint8_t* ch) -{ +bool tuh_cdc_peek(uint8_t idx, uint8_t* ch) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_peek(&p_cdc->stream.rx, ch); } -bool tuh_cdc_read_clear (uint8_t idx) -{ +bool tuh_cdc_read_clear (uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); @@ -363,28 +403,25 @@ bool tuh_cdc_read_clear (uint8_t idx) // Control Endpoint API //--------------------------------------------------------------------+ -// internal control complete to update state such as line state, encoding -static void cdch_internal_control_complete(tuh_xfer_t* xfer) -{ - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); +static void process_internal_control_complete(tuh_xfer_t* xfer, uint8_t itf_num) { uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); + uint16_t const value = tu_le16toh(xfer->setup->wValue); - if (xfer->result == XFER_RESULT_SUCCESS) - { + if (xfer->result == XFER_RESULT_SUCCESS) { switch (p_cdc->serial_drid) { case SERIAL_DRIVER_ACM: switch (xfer->setup->bRequest) { case CDC_REQUEST_SET_CONTROL_LINE_STATE: - p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + p_cdc->line_state = (uint8_t) value; break; case CDC_REQUEST_SET_LINE_CODING: { uint16_t const len = tu_min16(sizeof(cdc_line_coding_t), tu_le16toh(xfer->setup->wLength)); memcpy(&p_cdc->line_coding, xfer->buffer, len); - } break; + } default: break; } @@ -394,12 +431,11 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) case SERIAL_DRIVER_FTDI: switch (xfer->setup->bRequest) { case FTDI_SIO_MODEM_CTRL: - p_cdc->line_state = (uint8_t) (tu_le16toh(xfer->setup->wValue) & 0x00ff); + p_cdc->line_state = (uint8_t) value; break; case FTDI_SIO_SET_BAUD_RATE: - // convert from divisor to baudrate is not supported - p_cdc->line_coding.bit_rate = _ftdi_requested_baud; + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; break; default: break; @@ -411,15 +447,61 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) case SERIAL_DRIVER_CP210X: switch(xfer->setup->bRequest) { case CP210X_SET_MHS: - p_cdc->line_state = (uint8_t) (tu_le16toh(xfer->setup->wValue) & 0x00ff); + p_cdc->line_state = (uint8_t) value; break; case CP210X_SET_BAUDRATE: { uint32_t baudrate; memcpy(&baudrate, xfer->buffer, sizeof(uint32_t)); p_cdc->line_coding.bit_rate = tu_le32toh(baudrate); + break; } + + default: break; + } + break; + #endif + + #if CFG_TUH_CDC_CH34X + case SERIAL_DRIVER_CH34X: + switch (xfer->setup->bRequest) { + case CH34X_REQ_WRITE_REG: + // register write request + switch (value) { + case CH34X_REG16_DIVISOR_PRESCALER: + // baudrate + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + break; + + case CH32X_REG16_LCR2_LCR: + // data format + p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits; + p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity; + p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits; + break; + + default: break; + } break; + + case CH34X_REQ_MODEM_CTRL: { + // set modem controls RTS/DTR request. Note: signals are inverted + uint16_t const modem_signal = ~value; + if (modem_signal & CH34X_BIT_RTS) { + p_cdc->line_state |= CDC_CONTROL_LINE_STATE_RTS; + } else { + p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_RTS; + } + + if (modem_signal & CH34X_BIT_DTR) { + p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR; + } else { + p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_DTR; + } + break; + } + + default: break; } break; #endif @@ -434,14 +516,20 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) } } +// internal control complete to update state such as line state, encoding +static void cdch_internal_control_complete(tuh_xfer_t* xfer) { + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + process_internal_control_complete(xfer, itf_num); +} + bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; - if ( complete_cb ) { + if (complete_cb) { return driver->set_control_line_state(p_cdc, line_state, complete_cb, user_data); - }else { + } else { // blocking xfer_result_t result = XFER_RESULT_INVALID; bool ret = driver->set_control_line_state(p_cdc, line_state, complete_cb, (uintptr_t) &result); @@ -452,7 +540,6 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c } TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); - p_cdc->line_state = (uint8_t) line_state; return true; } @@ -463,9 +550,9 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; - if ( complete_cb ) { + if (complete_cb) { return driver->set_baudrate(p_cdc, baudrate, complete_cb, user_data); - }else { + } else { // blocking xfer_result_t result = XFER_RESULT_INVALID; bool ret = driver->set_baudrate(p_cdc, baudrate, complete_cb, (uintptr_t) &result); @@ -476,25 +563,23 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete } TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); - p_cdc->line_coding.bit_rate = baudrate; return true; } } -bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t* p_cdc = get_itf(idx); - // only ACM support this set line coding request - TU_VERIFY(p_cdc && p_cdc->serial_drid == SERIAL_DRIVER_ACM); - TU_VERIFY(p_cdc->acm_capability.support_line_request); + TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; - if ( complete_cb ) { - return acm_set_line_coding(p_cdc, line_coding, complete_cb, user_data); - }else { + if (complete_cb) { + return driver->set_data_format(p_cdc, stop_bits, parity, data_bits, complete_cb, user_data); + } else { // blocking xfer_result_t result = XFER_RESULT_INVALID; - bool ret = acm_set_line_coding(p_cdc, line_coding, complete_cb, (uintptr_t) &result); + bool ret = driver->set_data_format(p_cdc, stop_bits, parity, data_bits, complete_cb, (uintptr_t) &result); if (user_data) { // user_data is not NULL, return result via user_data @@ -502,7 +587,31 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, } TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); + p_cdc->line_coding.stop_bits = stop_bits; + p_cdc->line_coding.parity = parity; + p_cdc->line_coding.data_bits = data_bits; + return true; + } +} + +bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + + if ( complete_cb ) { + return driver->set_line_coding(p_cdc, line_coding, complete_cb, user_data); + } else { + // blocking + xfer_result_t result = XFER_RESULT_INVALID; + bool ret = driver->set_line_coding(p_cdc, line_coding, complete_cb, (uintptr_t) &result); + + if (user_data) { + // user_data is not NULL, return result via user_data + *((xfer_result_t*) user_data) = result; + } + TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); p_cdc->line_coding = *line_coding; return true; } @@ -512,45 +621,51 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, // CLASS-USBH API //--------------------------------------------------------------------+ -void cdch_init(void) -{ +bool cdch_init(void) { + TU_LOG_DRV("sizeof(cdch_interface_t) = %u\r\n", sizeof(cdch_interface_t)); tu_memclr(cdch_data, sizeof(cdch_data)); - - for(size_t i=0; istream.tx, true, true, false, - p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, - p_cdc->stream.tx_ep_buf, CFG_TUH_CDC_TX_EPSIZE); + p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, + p_cdc->stream.tx_ep_buf, CFG_TUH_CDC_TX_EPSIZE); tu_edpt_stream_init(&p_cdc->stream.rx, true, false, false, - p_cdc->stream.rx_ff_buf, CFG_TUH_CDC_RX_BUFSIZE, - p_cdc->stream.rx_ep_buf, CFG_TUH_CDC_RX_EPSIZE); + p_cdc->stream.rx_ff_buf, CFG_TUH_CDC_RX_BUFSIZE, + p_cdc->stream.rx_ep_buf, CFG_TUH_CDC_RX_EPSIZE); } + + return true; } -void cdch_close(uint8_t daddr) -{ - for(uint8_t idx=0; idxstream.tx); + tu_edpt_stream_deinit(&p_cdc->stream.rx); + } + return true; +} + +void cdch_close(uint8_t daddr) { + for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) { cdch_interface_t* p_cdc = &cdch_data[idx]; - if (p_cdc->daddr == daddr) - { + if (p_cdc->daddr == daddr) { + TU_LOG_DRV(" CDCh close addr = %u index = %u\r\n", daddr, idx); + // Invoke application callback if (tuh_cdc_umount_cb) tuh_cdc_umount_cb(idx); - //tu_memclr(p_cdc, sizeof(cdch_interface_t)); p_cdc->daddr = 0; p_cdc->bInterfaceNumber = 0; + p_cdc->mounted = false; tu_edpt_stream_close(&p_cdc->stream.tx); tu_edpt_stream_close(&p_cdc->stream.rx); } } } -bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) -{ +bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) { // TODO handle stall response, retry failed transfer ... TU_ASSERT(event == XFER_RESULT_SUCCESS); @@ -558,41 +673,35 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc); - if ( ep_addr == p_cdc->stream.tx.ep_addr ) - { + if ( ep_addr == p_cdc->stream.tx.ep_addr ) { // invoke tx complete callback to possibly refill tx fifo if (tuh_cdc_tx_complete_cb) tuh_cdc_tx_complete_cb(idx); - if ( 0 == tu_edpt_stream_write_xfer(&p_cdc->stream.tx) ) - { + if ( 0 == tu_edpt_stream_write_xfer(&p_cdc->stream.tx) ) { // If there is no data left, a ZLP should be sent if: // - xferred_bytes is multiple of EP Packet size and not zero tu_edpt_stream_write_zlp_if_needed(&p_cdc->stream.tx, xferred_bytes); } - } - else if ( ep_addr == p_cdc->stream.rx.ep_addr ) - { - tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); - + } else if ( ep_addr == p_cdc->stream.rx.ep_addr ) { #if CFG_TUH_CDC_FTDI - // FTDI reserve 2 bytes for status if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI) { - uint8_t status[2]; - tu_edpt_stream_read(&p_cdc->stream.rx, status, 2); - (void) status; // TODO handle status - } + // FTDI reserve 2 bytes for status + // uint8_t status[2] = {p_cdc->stream.rx.ep_buf[0], p_cdc->stream.rx.ep_buf[1]}; + tu_edpt_stream_read_xfer_complete_offset(&p_cdc->stream.rx, xferred_bytes, 2); + }else #endif + { + tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); + } // invoke receive callback if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(idx); // prepare for next transfer if needed tu_edpt_stream_read_xfer(&p_cdc->stream.rx); - }else if ( ep_addr == p_cdc->ep_notif ) - { + }else if ( ep_addr == p_cdc->ep_notif ) { // TODO handle notification endpoint - }else - { + }else { TU_ASSERT(false); } @@ -603,22 +712,15 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t // Enumeration //--------------------------------------------------------------------+ -static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); - -static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t const *desc_ep) -{ - for(size_t i=0; i<2; i++) - { +static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t const* desc_ep) { + for (size_t i = 0; i < 2; i++) { TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && - TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); - + TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); TU_ASSERT(tuh_edpt_open(p_cdc->daddr, desc_ep)); - if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) - { + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { tu_edpt_stream_open(&p_cdc->stream.rx, p_cdc->daddr, desc_ep); - }else - { + } else { tu_edpt_stream_open(&p_cdc->stream.tx, p_cdc->daddr, desc_ep); } @@ -628,49 +730,36 @@ static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t co return true; } -bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) -{ +bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { (void) rhport; - // Only support ACM subclass + // For CDC: only support ACM subclass // Note: Protocol 0xFF can be RNDIS device - if ( TUSB_CLASS_CDC == itf_desc->bInterfaceClass && - CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) - { + if (TUSB_CLASS_CDC == itf_desc->bInterfaceClass && + CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) { return acm_open(daddr, itf_desc, max_len); } - #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X - else if ( 0xff == itf_desc->bInterfaceClass ) - { + else if (SERIAL_DRIVER_COUNT > 1 && + TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) { uint16_t vid, pid; TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); - #if CFG_TUH_CDC_FTDI - if (TU_FTDI_VID == vid) { - for (size_t i = 0; i < FTDI_PID_COUNT; i++) { - if (ftdi_pids[i] == pid) { - return ftdi_open(daddr, itf_desc, max_len); - } - } - } - #endif - - #if CFG_TUH_CDC_CP210X - if (TU_CP210X_VID == vid) { - for (size_t i = 0; i < CP210X_PID_COUNT; i++) { - if (cp210x_pids[i] == pid) { - return cp210x_open(daddr, itf_desc, max_len); + for (size_t dr = 1; dr < SERIAL_DRIVER_COUNT; dr++) { + cdch_serial_driver_t const* driver = &serial_drivers[dr]; + for (size_t i = 0; i < driver->vid_pid_count; i++) { + if (driver->vid_pid_list[i][0] == vid && driver->vid_pid_list[i][1] == pid) { + return driver->open(daddr, itf_desc, max_len); } } } - #endif } - #endif return false; } static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num) { + TU_LOG_DRV("CDCh Set Configure complete\r\n"); + p_cdc->mounted = true; if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); // Prepare for incoming data @@ -680,9 +769,7 @@ static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t i usbh_driver_set_config_complete(p_cdc->daddr, itf_num); } - -bool cdch_set_config(uint8_t daddr, uint8_t itf_num) -{ +bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { tusb_control_request_t request; request.wIndex = tu_htole16((uint16_t) itf_num); @@ -711,100 +798,90 @@ enum { CONFIG_ACM_COMPLETE, }; -static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) -{ - uint8_t const * p_desc_end = ((uint8_t const*) itf_desc) + max_len; +static bool acm_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) { + uint8_t const* p_desc_end = ((uint8_t const*) itf_desc) + max_len; - cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); - p_cdc->serial_drid = SERIAL_DRIVER_ACM; //------------- Control Interface -------------// - uint8_t const * p_desc = tu_desc_next(itf_desc); + uint8_t const* p_desc = tu_desc_next(itf_desc); // Communication Functional Descriptors - while( (p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc)) ) - { - if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) ) - { + while ((p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc))) { + if (CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc)) { // save ACM bmCapabilities - p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities; + p_cdc->acm_capability = ((cdc_desc_func_acm_t const*) p_desc)->bmCapabilities; } p_desc = tu_desc_next(p_desc); } // Open notification endpoint of control interface if any - if (itf_desc->bNumEndpoints == 1) - { + if (itf_desc->bNumEndpoints == 1) { TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)); - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; + tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc; - TU_ASSERT( tuh_edpt_open(daddr, desc_ep) ); + TU_ASSERT(tuh_edpt_open(daddr, desc_ep)); p_cdc->ep_notif = desc_ep->bEndpointAddress; p_desc = tu_desc_next(p_desc); } //------------- Data Interface (if any) -------------// - if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && - (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) - { + if ((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && + (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const*) p_desc)->bInterfaceClass)) { // next to endpoint descriptor p_desc = tu_desc_next(p_desc); // data endpoints expected to be in pairs - TU_ASSERT(open_ep_stream_pair(p_cdc, (tusb_desc_endpoint_t const *) p_desc)); + TU_ASSERT(open_ep_stream_pair(p_cdc, (tusb_desc_endpoint_t const*) p_desc)); } return true; } -static void acm_process_config(tuh_xfer_t* xfer) -{ +static void acm_process_config(tuh_xfer_t* xfer) { uintptr_t const state = xfer->user_data; uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); + cdch_interface_t* p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); - switch(state) - { + switch (state) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - if (p_cdc->acm_capability.support_line_request) - { - TU_ASSERT(acm_set_control_line_state(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, acm_process_config, - CONFIG_ACM_SET_LINE_CODING), ); + if (p_cdc->acm_capability.support_line_request) { + TU_ASSERT(acm_set_control_line_state(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, acm_process_config, CONFIG_ACM_SET_LINE_CODING),); break; } - #endif + #endif TU_ATTR_FALLTHROUGH; case CONFIG_ACM_SET_LINE_CODING: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - if (p_cdc->acm_capability.support_line_request) - { + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + if (p_cdc->acm_capability.support_line_request) { cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(acm_set_line_coding(p_cdc, &line_coding, acm_process_config, CONFIG_ACM_COMPLETE), ); + TU_ASSERT(acm_set_line_coding(p_cdc, &line_coding, acm_process_config, CONFIG_ACM_COMPLETE),); break; } - #endif + #endif TU_ATTR_FALLTHROUGH; case CONFIG_ACM_COMPLETE: // itf_num+1 to account for data interface as well - set_config_complete(p_cdc, idx, itf_num+1); + set_config_complete(p_cdc, idx, itf_num + 1); break; - default: break; + default: + break; } } static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); - TU_LOG_CDCH("CDC ACM Set Control Line State\r\n"); + TU_LOG_DRV("CDC ACM Set Control Line State\r\n"); tusb_control_request_t const request = { .bmRequestType_bit = { @@ -834,7 +911,7 @@ static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_st } static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG_CDCH("CDC ACM Set Line Conding\r\n"); + TU_LOG_DRV("CDC ACM Set Line Conding\r\n"); tusb_control_request_t const request = { .bmRequestType_bit = { @@ -866,6 +943,19 @@ static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const return true; } +static bool acm_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_LOG_DRV("CDC ACM Set Data Format\r\n"); + + cdc_line_coding_t line_coding; + line_coding.bit_rate = p_cdc->line_coding.bit_rate; + line_coding.stop_bits = stop_bits; + line_coding.parity = parity; + line_coding.data_bits = data_bits; + + return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data); +} + static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); cdc_line_coding_t line_coding = p_cdc->line_coding; @@ -894,8 +984,7 @@ static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); - TU_LOG_CDCH("FTDI opened\r\n"); - + TU_LOG_DRV("FTDI opened\r\n"); p_cdc->serial_drid = SERIAL_DRIVER_FTDI; // endpoint pair @@ -931,22 +1020,40 @@ static bool ftdi_sio_set_request(cdch_interface_t* p_cdc, uint8_t command, uint1 return tuh_control_xfer(&xfer); } -static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data); } -static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - TU_LOG_CDCH("CDC FTDI Set Control Line State\r\n"); +static bool ftdi_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + (void) p_cdc; + (void) stop_bits; + (void) parity; + (void) data_bits; + (void) complete_cb; + (void) user_data; + // TODO not implemented yet + return false; +} + +static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + (void) p_cdc; + (void) line_coding; + (void) complete_cb; + (void) user_data; + // TODO not implemented yet + return false; +} + +static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_LOG_DRV("CDC FTDI Set Control Line State\r\n"); p_cdc->user_control_cb = complete_cb; TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | line_state, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } -static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) -{ +static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) { const uint8_t divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; uint32_t divisor; @@ -966,18 +1073,16 @@ static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) return divisor; } -static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) -{ +static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) { return ftdi_232bm_baud_base_to_divisor(baud, 48000000u); } -static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate); - TU_LOG_CDCH("CDC FTDI Set BaudRate = %lu, divisor = 0x%04x\n", baudrate, divisor); + TU_LOG_DRV("CDC FTDI Set BaudRate = %" PRIu32 ", divisor = 0x%04x\r\n", baudrate, divisor); p_cdc->user_control_cb = complete_cb; - _ftdi_requested_baud = baudrate; + p_cdc->requested_line_coding.bit_rate = baudrate; TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor, complete_cb ? cdch_internal_control_complete : NULL, user_data)); @@ -999,8 +1104,7 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { case CONFIG_FTDI_MODEM_CTRL: #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - TU_ASSERT( - ftdi_sio_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),); + TU_ASSERT(ftdi_sio_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),); break; #else TU_ATTR_FALLTHROUGH; @@ -1061,7 +1165,7 @@ static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, ui cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); - TU_LOG_CDCH("CP210x opened\r\n"); + TU_LOG_DRV("CP210x opened\r\n"); p_cdc->serial_drid = SERIAL_DRIVER_CP210X; // endpoint pair @@ -1108,17 +1212,37 @@ static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfe return cp210x_set_request(p_cdc, CP210X_IFC_ENABLE, enabled, NULL, 0, complete_cb, user_data); } +static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // TODO implement later + (void) p_cdc; + (void) line_coding; + (void) complete_cb; + (void) user_data; + return false; +} + static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG_CDCH("CDC CP210x Set BaudRate = %lu\n", baudrate); + TU_LOG_DRV("CDC CP210x Set BaudRate = %" PRIu32 "\r\n", baudrate); uint32_t baud_le = tu_htole32(baudrate); p_cdc->user_control_cb = complete_cb; return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, complete_cb ? cdch_internal_control_complete : NULL, user_data); } -static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - TU_LOG_CDCH("CDC CP210x Set Control Line State\r\n"); +static bool cp210x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + (void) p_cdc; + (void) stop_bits; + (void) parity; + (void) data_bits; + (void) complete_cb; + (void) user_data; + // TODO not implemented yet + return false; +} + +static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_LOG_DRV("CDC CP210x Set Control Line State\r\n"); p_cdc->user_control_cb = complete_cb; return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | line_state, NULL, 0, complete_cb ? cdch_internal_control_complete : NULL, user_data); @@ -1157,8 +1281,7 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { case CONFIG_CP210X_SET_DTR_RTS: #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - TU_ASSERT( - cp210x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, cp210x_process_config, CONFIG_CP210X_COMPLETE),); + TU_ASSERT(cp210x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, cp210x_process_config, CONFIG_CP210X_COMPLETE),); break; #else TU_ATTR_FALLTHROUGH; @@ -1174,4 +1297,374 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { #endif +//--------------------------------------------------------------------+ +// CH34x (CH340 & CH341) +//--------------------------------------------------------------------+ + +#if CFG_TUH_CDC_CH34X + +static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits); +static uint16_t ch34x_get_divisor_prescaler(uint32_t baval); + +//------------- control request -------------// + +static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value, + uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + tusb_control_request_t const request_setup = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_VENDOR, + .direction = direction & 0x01u + }, + .bRequest = request, + .wValue = tu_htole16 (value), + .wIndex = tu_htole16 (index), + .wLength = tu_htole16 (length) + }; + + // use usbh enum buf since application variable does not live long enough + uint8_t* enum_buf = NULL; + + if (buffer && length > 0) { + enum_buf = usbh_get_enum_buf(); + if (direction == TUSB_DIR_OUT) { + tu_memcpy_s(enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length); + } + } + + tuh_xfer_t xfer = { + .daddr = p_cdc->daddr, + .ep_addr = 0, + .setup = &request_setup, + .buffer = enum_buf, + .complete_cb = complete_cb, + .user_data = user_data + }; + + return tuh_control_xfer(&xfer); +} + +static inline bool ch34x_control_out(cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + return ch34x_set_request(p_cdc, TUSB_DIR_OUT, request, value, index, NULL, 0, complete_cb, user_data); +} + +static inline bool ch34x_control_in(cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, + uint8_t* buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + return ch34x_set_request(p_cdc, TUSB_DIR_IN, request, value, index, buffer, buffersize, + complete_cb, user_data); +} + +static inline bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16_t reg_value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + return ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, reg, reg_value, complete_cb, user_data); +} + +//static bool ch34x_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, +// uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +//{ +// return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, 0, buffer, buffersize, complete_cb, user_data ); +//} + +static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate); + TU_VERIFY(div_ps); + TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, + complete_cb, user_data)); + return true; +} + +//------------- Driver API -------------// + +// internal control complete to update state such as line state, encoding +static void ch34x_control_complete(tuh_xfer_t* xfer) { + // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber + process_internal_control_complete(xfer, 0); +} + +static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->requested_line_coding.stop_bits = stop_bits; + p_cdc->requested_line_coding.parity = parity; + p_cdc->requested_line_coding.data_bits = data_bits; + + uint8_t const lcr = ch34x_get_lcr(stop_bits, parity, data_bits); + TU_VERIFY(lcr); + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr, + complete_cb ? ch34x_control_complete : NULL, user_data)); + return true; +} + +static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->requested_line_coding.bit_rate = baudrate; + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, baudrate, + complete_cb ? ch34x_control_complete : NULL, user_data)); + return true; +} + +static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t* xfer) { + // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber + uint8_t const itf_num = 0; + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t* p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); + + if (xfer->result == XFER_RESULT_SUCCESS) { + // stage 1 success, continue to stage 2 + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + TU_ASSERT(ch34x_set_data_format(p_cdc, p_cdc->requested_line_coding.stop_bits, p_cdc->requested_line_coding.parity, + p_cdc->requested_line_coding.data_bits, ch34x_control_complete, xfer->user_data), ); + } else { + // stage 1 failed, notify user + xfer->complete_cb = p_cdc->user_control_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } + } +} + +// 2 stages: set baudrate (stage1) + set data format (stage2) +static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->requested_line_coding = *line_coding; + p_cdc->user_control_cb = complete_cb; + + if (complete_cb) { + // stage 1 set baudrate + TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, line_coding->bit_rate, + ch34x_set_line_coding_stage1_complete, user_data)); + } else { + // sync call + xfer_result_t result; + + // stage 1 set baudrate + TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, line_coding->bit_rate, NULL, (uintptr_t) &result)); + TU_VERIFY(result == XFER_RESULT_SUCCESS); + p_cdc->line_coding.bit_rate = line_coding->bit_rate; + + // stage 2 set data format + TU_ASSERT(ch34x_set_data_format(p_cdc, line_coding->stop_bits, line_coding->parity, line_coding->data_bits, + NULL, (uintptr_t) &result)); + TU_VERIFY(result == XFER_RESULT_SUCCESS); + p_cdc->line_coding.stop_bits = line_coding->stop_bits; + p_cdc->line_coding.parity = line_coding->parity; + p_cdc->line_coding.data_bits = line_coding->data_bits; + + // update transfer result, user_data is expected to point to xfer_result_t + if (user_data) { + *((xfer_result_t*) user_data) = result; + } + } + + return true; +} + +static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint8_t control = 0; + if (line_state & CDC_CONTROL_LINE_STATE_RTS) { + control |= CH34X_BIT_RTS; + } + if (line_state & CDC_CONTROL_LINE_STATE_DTR) { + control |= CH34X_BIT_DTR; + } + + // CH34x signals are inverted + control = ~control; + + p_cdc->user_control_cb = complete_cb; + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, + complete_cb ? ch34x_control_complete : NULL, user_data)); + return true; +} + +//------------- Enumeration -------------// +enum { + CONFIG_CH34X_READ_VERSION = 0, + CONFIG_CH34X_SERIAL_INIT, + CONFIG_CH34X_SPECIAL_REG_WRITE, + CONFIG_CH34X_FLOW_CONTROL, + CONFIG_CH34X_MODEM_CONTROL, + CONFIG_CH34X_COMPLETE +}; + +static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) { + // CH34x Interface includes 1 vendor interface + 2 bulk + 1 interrupt endpoints + TU_VERIFY (itf_desc->bNumEndpoints == 3); + TU_VERIFY (sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t) <= max_len); + + cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc); + TU_VERIFY (p_cdc); + + TU_LOG_DRV ("CH34x opened\r\n"); + p_cdc->serial_drid = SERIAL_DRIVER_CH34X; + + tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(itf_desc); + + // data endpoints expected to be in pairs + TU_ASSERT(open_ep_stream_pair(p_cdc, desc_ep)); + desc_ep += 2; + + // Interrupt endpoint: not used for now + TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(desc_ep) && + TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer); + TU_ASSERT(tuh_edpt_open(daddr, desc_ep)); + p_cdc->ep_notif = desc_ep->bEndpointAddress; + + return true; +} + +static void ch34x_process_config(tuh_xfer_t* xfer) { + // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber + uint8_t const itf_num = 0; + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t* p_cdc = get_itf(idx); + uintptr_t const state = xfer->user_data; + uint8_t buffer[2]; // TODO remove + TU_ASSERT (p_cdc,); + TU_ASSERT (xfer->result == XFER_RESULT_SUCCESS,); + + switch (state) { + case CONFIG_CH34X_READ_VERSION: + TU_LOG_DRV("[%u] CDCh CH34x attempt to read Chip Version\r\n", p_cdc->daddr); + TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); + break; + + case CONFIG_CH34X_SERIAL_INIT: { + // handle version read data, set CH34x line coding (incl. baudrate) + uint8_t const version = xfer->buffer[0]; + TU_LOG_DRV("[%u] CDCh CH34x Chip Version = %02x\r\n", p_cdc->daddr, version); + // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD + TU_ASSERT (version >= 0x30,); + // init CH34x with line coding + cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; + uint16_t const div_ps = ch34x_get_divisor_prescaler(line_coding.bit_rate); + TU_ASSERT(div_ps, ); + uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits); + TU_ASSERT(lcr, ); + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, + ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); + break; + } + + case CONFIG_CH34X_SPECIAL_REG_WRITE: + // overtake line coding and do special reg write, purpose unknown, overtaken from WCH driver + p_cdc->line_coding = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X); + TU_ASSERT (ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); + break; + + case CONFIG_CH34X_FLOW_CONTROL: + // no hardware flow control + TU_ASSERT (ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),); + break; + + case CONFIG_CH34X_MODEM_CONTROL: + // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) + TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, CONFIG_CH34X_COMPLETE),); + break; + + case CONFIG_CH34X_COMPLETE: + set_config_complete(p_cdc, idx, itf_num); + break; + + default: + TU_ASSERT (false,); + break; + } +} + +//------------- CH34x helper -------------// + +// calculate divisor and prescaler for baudrate, return it as 16-bit combined value +static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { + uint8_t a; + uint8_t b; + uint32_t c; + + TU_VERIFY(baval != 0 && baval <= 2000000, 0); + switch (baval) { + case 921600: + a = 0xf3; + b = 7; + break; + + case 307200: + a = 0xd9; + b = 7; + break; + + default: + if (baval > 6000000 / 255) { + b = 3; + c = 6000000; + } else if (baval > 750000 / 255) { + b = 2; + c = 750000; + } else if (baval > 93750 / 255) { + b = 1; + c = 93750; + } else { + b = 0; + c = 11719; + } + a = (uint8_t) (c / baval); + if (a == 0 || a == 0xFF) { + return 0; + } + if ((c / a - baval) > (baval - c / (a + 1))) { + a++; + } + a = (uint8_t) (256 - a); + break; + } + + // reg divisor = a, reg prescaler = b + // According to linux code we need to set bit 7 of UCHCOM_REG_BPS_PRE, + // otherwise the chip will buffer data. + return (uint16_t) ((uint16_t)a << 8 | 0x80 | b); +} + +// calculate lcr value from data coding +static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits) { + uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; + TU_VERIFY(data_bits >= 5 && data_bits <= 8, 0); + lcr |= (uint8_t) (data_bits - 5); + + switch(parity) { + case CDC_LINE_CODING_PARITY_NONE: + break; + + case CDC_LINE_CODING_PARITY_ODD: + lcr |= CH34X_LCR_ENABLE_PAR; + break; + + case CDC_LINE_CODING_PARITY_EVEN: + lcr |= CH34X_LCR_ENABLE_PAR | CH34X_LCR_PAR_EVEN; + break; + + case CDC_LINE_CODING_PARITY_MARK: + lcr |= CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE; + break; + + case CDC_LINE_CODING_PARITY_SPACE: + lcr |= CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE | CH34X_LCR_PAR_EVEN; + break; + + default: break; + } + + // 1.5 stop bits not supported + TU_VERIFY(stop_bits != CDC_LINE_CODING_STOP_BITS_1_5, 0); + if (stop_bits == CDC_LINE_CODING_STOP_BITS_2) { + lcr |= CH34X_LCR_STOP_BITS_2; + } + + return lcr; +} + + +#endif // CFG_TUH_CDC_CH34X + #endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.h b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.h index 19552f1e..b63dd153 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/cdc_host.h @@ -44,7 +44,7 @@ // Set Line Coding on enumeration/mounted, value for cdc_line_coding_t //#ifndef CFG_TUH_CDC_LINE_CODING_ON_ENUM -//#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } +//#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } //#endif // RX FIFO size @@ -148,8 +148,11 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c // Request to set baudrate bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -// Request to Set Line Coding (ACM only) -// Should only use if you don't work with serial devices such as FTDI/CP210x +// Request to set data format +bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + +// Request to Set Line Coding = baudrate + data format +// Note: only implemented by ACM and CH34x, not supported by FTDI and CP210x yet bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); // Request to Get Line Coding (ACM only) @@ -159,15 +162,13 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, // Connect by set both DTR, RTS TU_ATTR_ALWAYS_INLINE static inline -bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return tuh_cdc_set_control_line_state(idx, CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS, complete_cb, user_data); } // Disconnect by clear both DTR, RTS TU_ATTR_ALWAYS_INLINE static inline -bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return tuh_cdc_set_control_line_state(idx, 0x00, complete_cb, user_data); } @@ -191,7 +192,8 @@ TU_ATTR_WEAK extern void tuh_cdc_tx_complete_cb(uint8_t idx); //--------------------------------------------------------------------+ // Internal Class Driver API //--------------------------------------------------------------------+ -void cdch_init (void); +bool cdch_init (void); +bool cdch_deinit (void); bool cdch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); bool cdch_set_config (uint8_t dev_addr, uint8_t itf_num); bool cdch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/serial/ch34x.h b/test-devices/composite-stm32/lib/tinyusb/class/cdc/serial/ch34x.h new file mode 100644 index 00000000..c18066f5 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/serial/ch34x.h @@ -0,0 +1,84 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Heiko Kuester + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _CH34X_H_ +#define _CH34X_H_ + +// There is no official documentation for the CH34x (CH340, CH341) chips. Reference can be found +// - https://github.com/WCHSoftGroup/ch341ser_linux +// - https://github.com/torvalds/linux/blob/master/drivers/usb/serial/ch341.c +// - https://github.com/freebsd/freebsd-src/blob/main/sys/dev/usb/serial/uchcom.c + +// set line_coding @ enumeration +#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM +#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X CFG_TUH_CDC_LINE_CODING_ON_ENUM +#else // this default is necessary to work properly +#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X { 9600, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } +#endif + +// USB requests +#define CH34X_REQ_READ_VERSION 0x5F // dec 95 +#define CH34X_REQ_WRITE_REG 0x9A // dec 154 +#define CH34X_REQ_READ_REG 0x95 // dec 149 +#define CH34X_REQ_SERIAL_INIT 0xA1 // dec 161 +#define CH34X_REQ_MODEM_CTRL 0xA4 // dev 164 + +// registers +#define CH34X_REG_BREAK 0x05 +#define CH34X_REG_PRESCALER 0x12 +#define CH34X_REG_DIVISOR 0x13 +#define CH34X_REG_LCR 0x18 +#define CH34X_REG_LCR2 0x25 +#define CH34X_REG_MCR_MSR 0x06 +#define CH34X_REG_MCR_MSR2 0x07 +#define CH34X_NBREAK_BITS 0x01 + +#define CH341_REG_0x0F 0x0F // undocumented register +#define CH341_REG_0x2C 0x2C // undocumented register +#define CH341_REG_0x27 0x27 // hardware flow control (cts/rts) + +#define CH34X_REG16_DIVISOR_PRESCALER TU_U16(CH34X_REG_DIVISOR, CH34X_REG_PRESCALER) +#define CH32X_REG16_LCR2_LCR TU_U16(CH34X_REG_LCR2, CH34X_REG_LCR) + +// modem control bits +#define CH34X_BIT_RTS ( 1 << 6 ) +#define CH34X_BIT_DTR ( 1 << 5 ) + +// line control bits +#define CH34X_LCR_ENABLE_RX 0x80 +#define CH34X_LCR_ENABLE_TX 0x40 +#define CH34X_LCR_MARK_SPACE 0x20 +#define CH34X_LCR_PAR_EVEN 0x10 +#define CH34X_LCR_ENABLE_PAR 0x08 +#define CH34X_LCR_PAR_MASK 0x38 // all parity bits +#define CH34X_LCR_STOP_BITS_2 0x04 +#define CH34X_LCR_CS8 0x03 +#define CH34X_LCR_CS7 0x02 +#define CH34X_LCR_CS6 0x01 +#define CH34X_LCR_CS5 0x00 +#define CH34X_LCR_CS_MASK 0x03 // all CSx bits + +#endif /* _CH34X_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/serial/cp210x.h b/test-devices/composite-stm32/lib/tinyusb/class/cdc/serial/cp210x.h index b0141709..2c749f52 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/cdc/serial/cp210x.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/serial/cp210x.h @@ -29,8 +29,6 @@ // https://www.silabs.com/documents/public/application-notes/AN571.pdf #define TU_CP210X_VID 0x10C4 -#define TU_CP210X_PID_LIST \ - 0xEA60, 0xEA70 /* Config request codes */ #define CP210X_IFC_ENABLE 0x00 diff --git a/test-devices/composite-stm32/lib/tinyusb/class/cdc/serial/ftdi_sio.h b/test-devices/composite-stm32/lib/tinyusb/class/cdc/serial/ftdi_sio.h index 6916e403..0825f071 100644 --- a/test-devices/composite-stm32/lib/tinyusb/class/cdc/serial/ftdi_sio.h +++ b/test-devices/composite-stm32/lib/tinyusb/class/cdc/serial/ftdi_sio.h @@ -25,11 +25,8 @@ #ifndef TUSB_FTDI_SIO_H #define TUSB_FTDI_SIO_H -// VID/PID for matching FTDI devices +// VID for matching FTDI devices #define TU_FTDI_VID 0x0403 -#define TU_FTDI_PID_LIST \ - 0x6001, 0x6006, 0x6010, 0x6011, 0x6014, 0x6015, 0x8372, 0xFBFA, \ - 0xcd18 // Commands #define FTDI_SIO_RESET 0 /* Reset the port */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu.h b/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu.h deleted file mode 100644 index 114c827b..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2021 XMOS LIMITED - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_DFU_H_ -#define _TUSB_DFU_H_ - -#include "common/tusb_common.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Common Definitions -//--------------------------------------------------------------------+ - -// DFU Protocol -typedef enum -{ - DFU_PROTOCOL_RT = 0x01, - DFU_PROTOCOL_DFU = 0x02, -} dfu_protocol_type_t; - -// DFU Descriptor Type -typedef enum -{ - DFU_DESC_FUNCTIONAL = 0x21, -} dfu_descriptor_type_t; - -// DFU Requests -typedef enum { - DFU_REQUEST_DETACH = 0, - DFU_REQUEST_DNLOAD = 1, - DFU_REQUEST_UPLOAD = 2, - DFU_REQUEST_GETSTATUS = 3, - DFU_REQUEST_CLRSTATUS = 4, - DFU_REQUEST_GETSTATE = 5, - DFU_REQUEST_ABORT = 6, -} dfu_requests_t; - -// DFU States -typedef enum { - APP_IDLE = 0, - APP_DETACH = 1, - DFU_IDLE = 2, - DFU_DNLOAD_SYNC = 3, - DFU_DNBUSY = 4, - DFU_DNLOAD_IDLE = 5, - DFU_MANIFEST_SYNC = 6, - DFU_MANIFEST = 7, - DFU_MANIFEST_WAIT_RESET = 8, - DFU_UPLOAD_IDLE = 9, - DFU_ERROR = 10, -} dfu_state_t; - -// DFU Status -typedef enum { - DFU_STATUS_OK = 0x00, - DFU_STATUS_ERR_TARGET = 0x01, - DFU_STATUS_ERR_FILE = 0x02, - DFU_STATUS_ERR_WRITE = 0x03, - DFU_STATUS_ERR_ERASE = 0x04, - DFU_STATUS_ERR_CHECK_ERASED = 0x05, - DFU_STATUS_ERR_PROG = 0x06, - DFU_STATUS_ERR_VERIFY = 0x07, - DFU_STATUS_ERR_ADDRESS = 0x08, - DFU_STATUS_ERR_NOTDONE = 0x09, - DFU_STATUS_ERR_FIRMWARE = 0x0A, - DFU_STATUS_ERR_VENDOR = 0x0B, - DFU_STATUS_ERR_USBR = 0x0C, - DFU_STATUS_ERR_POR = 0x0D, - DFU_STATUS_ERR_UNKNOWN = 0x0E, - DFU_STATUS_ERR_STALLEDPKT = 0x0F, -} dfu_status_t; - -#define DFU_ATTR_CAN_DOWNLOAD (1u << 0) -#define DFU_ATTR_CAN_UPLOAD (1u << 1) -#define DFU_ATTR_MANIFESTATION_TOLERANT (1u << 2) -#define DFU_ATTR_WILL_DETACH (1u << 3) - -// DFU Status Request Payload -typedef struct TU_ATTR_PACKED -{ - uint8_t bStatus; - uint8_t bwPollTimeout[3]; - uint8_t bState; - uint8_t iString; -} dfu_status_response_t; - -TU_VERIFY_STATIC( sizeof(dfu_status_response_t) == 6, "size is not correct"); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_DFU_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_device.c b/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_device.c deleted file mode 100644 index 464c4bd6..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_device.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2021 XMOS LIMITED - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_DFU) - -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "dfu_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -typedef struct -{ - uint8_t attrs; - uint8_t alt; - - dfu_state_t state; - dfu_status_t status; - - bool flashing_in_progress; - uint16_t block; - uint16_t length; - - CFG_TUSB_MEM_ALIGN uint8_t transfer_buf[CFG_TUD_DFU_XFER_BUFSIZE]; -} dfu_state_ctx_t; - -// Only a single dfu state is allowed -CFG_TUSB_MEM_SECTION tu_static dfu_state_ctx_t _dfu_ctx; - -static void reset_state(void) -{ - _dfu_ctx.state = DFU_IDLE; - _dfu_ctx.status = DFU_STATUS_OK; - _dfu_ctx.flashing_in_progress = false; -} - -static bool reply_getstatus(uint8_t rhport, tusb_control_request_t const * request, dfu_state_t state, dfu_status_t status, uint32_t timeout); -static bool process_download_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); - -//--------------------------------------------------------------------+ -// Debug -//--------------------------------------------------------------------+ -#if CFG_TUSB_DEBUG >= 2 - -tu_static tu_lookup_entry_t const _dfu_request_lookup[] = -{ - { .key = DFU_REQUEST_DETACH , .data = "DETACH" }, - { .key = DFU_REQUEST_DNLOAD , .data = "DNLOAD" }, - { .key = DFU_REQUEST_UPLOAD , .data = "UPLOAD" }, - { .key = DFU_REQUEST_GETSTATUS , .data = "GETSTATUS" }, - { .key = DFU_REQUEST_CLRSTATUS , .data = "CLRSTATUS" }, - { .key = DFU_REQUEST_GETSTATE , .data = "GETSTATE" }, - { .key = DFU_REQUEST_ABORT , .data = "ABORT" }, -}; - -tu_static tu_lookup_table_t const _dfu_request_table = -{ - .count = TU_ARRAY_SIZE(_dfu_request_lookup), - .items = _dfu_request_lookup -}; - -tu_static tu_lookup_entry_t const _dfu_state_lookup[] = -{ - { .key = APP_IDLE , .data = "APP_IDLE" }, - { .key = APP_DETACH , .data = "APP_DETACH" }, - { .key = DFU_IDLE , .data = "IDLE" }, - { .key = DFU_DNLOAD_SYNC , .data = "DNLOAD_SYNC" }, - { .key = DFU_DNBUSY , .data = "DNBUSY" }, - { .key = DFU_DNLOAD_IDLE , .data = "DNLOAD_IDLE" }, - { .key = DFU_MANIFEST_SYNC , .data = "MANIFEST_SYNC" }, - { .key = DFU_MANIFEST , .data = "MANIFEST" }, - { .key = DFU_MANIFEST_WAIT_RESET , .data = "MANIFEST_WAIT_RESET" }, - { .key = DFU_UPLOAD_IDLE , .data = "UPLOAD_IDLE" }, - { .key = DFU_ERROR , .data = "ERROR" }, -}; - -tu_static tu_lookup_table_t const _dfu_state_table = -{ - .count = TU_ARRAY_SIZE(_dfu_state_lookup), - .items = _dfu_state_lookup -}; - -tu_static tu_lookup_entry_t const _dfu_status_lookup[] = -{ - { .key = DFU_STATUS_OK , .data = "OK" }, - { .key = DFU_STATUS_ERR_TARGET , .data = "errTARGET" }, - { .key = DFU_STATUS_ERR_FILE , .data = "errFILE" }, - { .key = DFU_STATUS_ERR_WRITE , .data = "errWRITE" }, - { .key = DFU_STATUS_ERR_ERASE , .data = "errERASE" }, - { .key = DFU_STATUS_ERR_CHECK_ERASED , .data = "errCHECK_ERASED" }, - { .key = DFU_STATUS_ERR_PROG , .data = "errPROG" }, - { .key = DFU_STATUS_ERR_VERIFY , .data = "errVERIFY" }, - { .key = DFU_STATUS_ERR_ADDRESS , .data = "errADDRESS" }, - { .key = DFU_STATUS_ERR_NOTDONE , .data = "errNOTDONE" }, - { .key = DFU_STATUS_ERR_FIRMWARE , .data = "errFIRMWARE" }, - { .key = DFU_STATUS_ERR_VENDOR , .data = "errVENDOR" }, - { .key = DFU_STATUS_ERR_USBR , .data = "errUSBR" }, - { .key = DFU_STATUS_ERR_POR , .data = "errPOR" }, - { .key = DFU_STATUS_ERR_UNKNOWN , .data = "errUNKNOWN" }, - { .key = DFU_STATUS_ERR_STALLEDPKT , .data = "errSTALLEDPKT" }, -}; - -tu_static tu_lookup_table_t const _dfu_status_table = -{ - .count = TU_ARRAY_SIZE(_dfu_status_lookup), - .items = _dfu_status_lookup -}; - -#endif - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void dfu_moded_reset(uint8_t rhport) -{ - (void) rhport; - - _dfu_ctx.attrs = 0; - _dfu_ctx.alt = 0; - - reset_state(); -} - -void dfu_moded_init(void) -{ - dfu_moded_reset(0); -} - -uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ - (void) rhport; - - //------------- Interface (with Alt) descriptor -------------// - uint8_t const itf_num = itf_desc->bInterfaceNumber; - uint8_t alt_count = 0; - - uint16_t drv_len = 0; - TU_VERIFY(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS && itf_desc->bInterfaceProtocol == DFU_PROTOCOL_DFU, 0); - - while(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS && itf_desc->bInterfaceProtocol == DFU_PROTOCOL_DFU) - { - TU_ASSERT(max_len > drv_len, 0); - - // Alternate must have the same interface number - TU_ASSERT(itf_desc->bInterfaceNumber == itf_num, 0); - - // Alt should increase by one every time - TU_ASSERT(itf_desc->bAlternateSetting == alt_count, 0); - alt_count++; - - drv_len += tu_desc_len(itf_desc); - itf_desc = (tusb_desc_interface_t const *) tu_desc_next(itf_desc); - } - - //------------- DFU Functional descriptor -------------// - tusb_desc_dfu_functional_t const *func_desc = (tusb_desc_dfu_functional_t const *) itf_desc; - TU_ASSERT(tu_desc_type(func_desc) == TUSB_DESC_FUNCTIONAL, 0); - drv_len += sizeof(tusb_desc_dfu_functional_t); - - _dfu_ctx.attrs = func_desc->bAttributes; - - // CFG_TUD_DFU_XFER_BUFSIZE has to be set to the buffer size used in TUD_DFU_DESCRIPTOR - uint16_t const transfer_size = tu_le16toh( tu_unaligned_read16((uint8_t const*) func_desc + offsetof(tusb_desc_dfu_functional_t, wTransferSize)) ); - TU_ASSERT(transfer_size <= CFG_TUD_DFU_XFER_BUFSIZE, drv_len); - - return drv_len; -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); - - TU_LOG2(" DFU State : %s, Status: %s\r\n", tu_lookup_find(&_dfu_state_table, _dfu_ctx.state), tu_lookup_find(&_dfu_status_table, _dfu_ctx.status)); - - if ( request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD ) - { - // Standard request include GET/SET_INTERFACE - switch ( request->bRequest ) - { - case TUSB_REQ_SET_INTERFACE: - if ( stage == CONTROL_STAGE_SETUP ) - { - // Switch Alt interface and reset state machine - _dfu_ctx.alt = (uint8_t) request->wValue; - reset_state(); - return tud_control_status(rhport, request); - } - break; - - case TUSB_REQ_GET_INTERFACE: - if(stage == CONTROL_STAGE_SETUP) - { - return tud_control_xfer(rhport, request, &_dfu_ctx.alt, 1); - } - break; - - // unsupported request - default: return false; - } - } - else if ( request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS ) - { - TU_LOG2(" DFU Request: %s\r\n", tu_lookup_find(&_dfu_request_table, request->bRequest)); - - // Class request - switch ( request->bRequest ) - { - case DFU_REQUEST_DETACH: - if ( stage == CONTROL_STAGE_SETUP ) - { - tud_control_status(rhport, request); - } - else if ( stage == CONTROL_STAGE_ACK ) - { - if ( tud_dfu_detach_cb ) tud_dfu_detach_cb(); - } - break; - - case DFU_REQUEST_CLRSTATUS: - if ( stage == CONTROL_STAGE_SETUP ) - { - reset_state(); - tud_control_status(rhport, request); - } - break; - - case DFU_REQUEST_GETSTATE: - if ( stage == CONTROL_STAGE_SETUP ) - { - tud_control_xfer(rhport, request, &_dfu_ctx.state, 1); - } - break; - - case DFU_REQUEST_ABORT: - if ( stage == CONTROL_STAGE_SETUP ) - { - reset_state(); - tud_control_status(rhport, request); - } - else if ( stage == CONTROL_STAGE_ACK ) - { - if ( tud_dfu_abort_cb ) tud_dfu_abort_cb(_dfu_ctx.alt); - } - break; - - case DFU_REQUEST_UPLOAD: - if ( stage == CONTROL_STAGE_SETUP ) - { - TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_UPLOAD); - TU_VERIFY(tud_dfu_upload_cb); - TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE); - - uint16_t const xfer_len = tud_dfu_upload_cb(_dfu_ctx.alt, request->wValue, _dfu_ctx.transfer_buf, request->wLength); - - return tud_control_xfer(rhport, request, _dfu_ctx.transfer_buf, xfer_len); - } - break; - - case DFU_REQUEST_DNLOAD: - if ( stage == CONTROL_STAGE_SETUP ) - { - TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_DOWNLOAD); - TU_VERIFY(_dfu_ctx.state == DFU_IDLE || _dfu_ctx.state == DFU_DNLOAD_IDLE); - TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE); - - // set to true for both download and manifest - _dfu_ctx.flashing_in_progress = true; - - // save block and length for flashing - _dfu_ctx.block = request->wValue; - _dfu_ctx.length = request->wLength; - - if ( request->wLength ) - { - // Download with payload -> transition to DOWNLOAD SYNC - _dfu_ctx.state = DFU_DNLOAD_SYNC; - return tud_control_xfer(rhport, request, _dfu_ctx.transfer_buf, request->wLength); - } - else - { - // Download is complete -> transition to MANIFEST SYNC - _dfu_ctx.state = DFU_MANIFEST_SYNC; - return tud_control_status(rhport, request); - } - } - break; - - case DFU_REQUEST_GETSTATUS: - switch ( _dfu_ctx.state ) - { - case DFU_DNLOAD_SYNC: - return process_download_get_status(rhport, stage, request); - break; - - case DFU_MANIFEST_SYNC: - return process_manifest_get_status(rhport, stage, request); - break; - - default: - if ( stage == CONTROL_STAGE_SETUP ) return reply_getstatus(rhport, request, _dfu_ctx.state, _dfu_ctx.status, 0); - break; - } - break; - - default: return false; // stall unsupported request - } - }else - { - return false; // unsupported request - } - - return true; -} - -void tud_dfu_finish_flashing(uint8_t status) -{ - _dfu_ctx.flashing_in_progress = false; - - if ( status == DFU_STATUS_OK ) - { - if (_dfu_ctx.state == DFU_DNBUSY) - { - _dfu_ctx.state = DFU_DNLOAD_SYNC; - } - else if (_dfu_ctx.state == DFU_MANIFEST) - { - _dfu_ctx.state = (_dfu_ctx.attrs & DFU_ATTR_MANIFESTATION_TOLERANT) - ? DFU_MANIFEST_SYNC : DFU_MANIFEST_WAIT_RESET; - } - } - else - { - // failed while flashing, move to dfuError - _dfu_ctx.state = DFU_ERROR; - _dfu_ctx.status = (dfu_status_t)status; - } -} - -static bool process_download_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - if ( stage == CONTROL_STAGE_SETUP ) - { - // only transition to next state on CONTROL_STAGE_ACK - dfu_state_t next_state; - uint32_t timeout; - - if ( _dfu_ctx.flashing_in_progress ) - { - next_state = DFU_DNBUSY; - timeout = tud_dfu_get_timeout_cb(_dfu_ctx.alt, (uint8_t) next_state); - } - else - { - next_state = DFU_DNLOAD_IDLE; - timeout = 0; - } - - return reply_getstatus(rhport, request, next_state, _dfu_ctx.status, timeout); - } - else if ( stage == CONTROL_STAGE_ACK ) - { - if ( _dfu_ctx.flashing_in_progress ) - { - _dfu_ctx.state = DFU_DNBUSY; - tud_dfu_download_cb(_dfu_ctx.alt, _dfu_ctx.block, _dfu_ctx.transfer_buf, _dfu_ctx.length); - }else - { - _dfu_ctx.state = DFU_DNLOAD_IDLE; - } - } - - return true; -} - -static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - if ( stage == CONTROL_STAGE_SETUP ) - { - // only transition to next state on CONTROL_STAGE_ACK - dfu_state_t next_state; - uint32_t timeout; - - if ( _dfu_ctx.flashing_in_progress ) - { - next_state = DFU_MANIFEST; - timeout = tud_dfu_get_timeout_cb(_dfu_ctx.alt, next_state); - } - else - { - next_state = DFU_IDLE; - timeout = 0; - } - - return reply_getstatus(rhport, request, next_state, _dfu_ctx.status, timeout); - } - else if ( stage == CONTROL_STAGE_ACK ) - { - if ( _dfu_ctx.flashing_in_progress ) - { - _dfu_ctx.state = DFU_MANIFEST; - tud_dfu_manifest_cb(_dfu_ctx.alt); - } - else - { - _dfu_ctx.state = DFU_IDLE; - } - } - - return true; -} - -static bool reply_getstatus(uint8_t rhport, tusb_control_request_t const * request, dfu_state_t state, dfu_status_t status, uint32_t timeout) -{ - dfu_status_response_t resp; - resp.bStatus = (uint8_t) status; - resp.bwPollTimeout[0] = TU_U32_BYTE0(timeout); - resp.bwPollTimeout[1] = TU_U32_BYTE1(timeout); - resp.bwPollTimeout[2] = TU_U32_BYTE2(timeout); - resp.bState = (uint8_t) state; - resp.iString = 0; - - return tud_control_xfer(rhport, request, &resp, sizeof(dfu_status_response_t)); -} - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_device.h b/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_device.h deleted file mode 100644 index fecf8596..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_device.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2021 XMOS LIMITED - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_DFU_DEVICE_H_ -#define _TUSB_DFU_DEVICE_H_ - -#include "dfu.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Class Driver Default Configure & Validation -//--------------------------------------------------------------------+ - -#if !defined(CFG_TUD_DFU_XFER_BUFSIZE) - #error "CFG_TUD_DFU_XFER_BUFSIZE must be defined, it has to be set to the buffer size used in TUD_DFU_DESCRIPTOR" -#endif - -//--------------------------------------------------------------------+ -// Application API -//--------------------------------------------------------------------+ - -// Must be called when the application is done with flashing started by -// tud_dfu_download_cb() and tud_dfu_manifest_cb(). -// status is DFU_STATUS_OK if successful, any other error status will cause state to enter dfuError -void tud_dfu_finish_flashing(uint8_t status); - -//--------------------------------------------------------------------+ -// Application Callback API (weak is optional) -//--------------------------------------------------------------------+ - -// Note: alt is used as the partition number, in order to support multiple partitions like FLASH, EEPROM, etc. - -// Invoked right before tud_dfu_download_cb() (state=DFU_DNBUSY) or tud_dfu_manifest_cb() (state=DFU_MANIFEST) -// Application return timeout in milliseconds (bwPollTimeout) for the next download/manifest operation. -// During this period, USB host won't try to communicate with us. -uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state); - -// Invoked when received DFU_DNLOAD (wLength>0) following by DFU_GETSTATUS (state=DFU_DNBUSY) requests -// This callback could be returned before flashing op is complete (async). -// Once finished flashing, application must call tud_dfu_finish_flashing() -void tud_dfu_download_cb (uint8_t alt, uint16_t block_num, uint8_t const *data, uint16_t length); - -// Invoked when download process is complete, received DFU_DNLOAD (wLength=0) following by DFU_GETSTATUS (state=Manifest) -// Application can do checksum, or actual flashing if buffered entire image previously. -// Once finished flashing, application must call tud_dfu_finish_flashing() -void tud_dfu_manifest_cb(uint8_t alt); - -// Invoked when received DFU_UPLOAD request -// Application must populate data with up to length bytes and -// Return the number of written bytes -TU_ATTR_WEAK uint16_t tud_dfu_upload_cb(uint8_t alt, uint16_t block_num, uint8_t* data, uint16_t length); - -// Invoked when a DFU_DETACH request is received -TU_ATTR_WEAK void tud_dfu_detach_cb(void); - -// Invoked when the Host has terminated a download or upload transfer -TU_ATTR_WEAK void tud_dfu_abort_cb(uint8_t alt); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void dfu_moded_init(void); -void dfu_moded_reset(uint8_t rhport); -uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); - - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_DFU_MODE_DEVICE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c b/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c deleted file mode 100644 index 7b77b3f8..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Sylvain Munaut - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_DFU_RUNTIME) - -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "dfu_rt_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void dfu_rtd_init(void) -{ -} - -void dfu_rtd_reset(uint8_t rhport) -{ - (void) rhport; -} - -uint16_t dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ - (void) rhport; - (void) max_len; - - // Ensure this is DFU Runtime - TU_VERIFY((itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS) && - (itf_desc->bInterfaceProtocol == DFU_PROTOCOL_RT), 0); - - uint8_t const * p_desc = tu_desc_next( itf_desc ); - uint16_t drv_len = sizeof(tusb_desc_interface_t); - - if ( TUSB_DESC_FUNCTIONAL == tu_desc_type(p_desc) ) - { - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - return drv_len; -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - // nothing to do with DATA or ACK stage - if ( stage != CONTROL_STAGE_SETUP ) return true; - - TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); - - // dfu-util will try to claim the interface with SET_INTERFACE request before sending DFU request - if ( TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type && - TUSB_REQ_SET_INTERFACE == request->bRequest ) - { - tud_control_status(rhport, request); - return true; - } - - // Handle class request only from here - TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); - - switch (request->bRequest) - { - case DFU_REQUEST_DETACH: - { - TU_LOG2(" DFU RT Request: DETACH\r\n"); - tud_control_status(rhport, request); - tud_dfu_runtime_reboot_to_dfu_cb(); - } - break; - - case DFU_REQUEST_GETSTATUS: - { - TU_LOG2(" DFU RT Request: GETSTATUS\r\n"); - dfu_status_response_t resp; - // Status = OK, Poll timeout is ignored during RT, State = APP_IDLE, IString = 0 - TU_VERIFY(tu_memset_s(&resp, sizeof(resp), 0x00, sizeof(resp))==0); - tud_control_xfer(rhport, request, &resp, sizeof(dfu_status_response_t)); - } - break; - - default: - { - TU_LOG2(" DFU RT Unexpected Request: %d\r\n", request->bRequest); - return false; // stall unsupported request - } - } - - return true; -} - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.h b/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.h deleted file mode 100644 index babaa821..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/dfu/dfu_rt_device.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Sylvain Munaut - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_DFU_RT_DEVICE_H_ -#define _TUSB_DFU_RT_DEVICE_H_ - -#include "dfu.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Application Callback API (weak is optional) -//--------------------------------------------------------------------+ -// Invoked when a DFU_DETACH request is received and bitWillDetach is set -void tud_dfu_runtime_reboot_to_dfu_cb(void); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void dfu_rtd_init(void); -void dfu_rtd_reset(uint8_t rhport); -uint16_t dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_DFU_RT_DEVICE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid.h b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid.h deleted file mode 100644 index fbd3eef3..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid.h +++ /dev/null @@ -1,1131 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -/** \ingroup group_class - * \defgroup ClassDriver_HID Human Interface Device (HID) - * @{ */ - -#ifndef _TUSB_HID_H_ -#define _TUSB_HID_H_ - -#include "common/tusb_common.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Common Definitions -//--------------------------------------------------------------------+ -/** \defgroup ClassDriver_HID_Common Common Definitions - * @{ */ - -/// USB HID Descriptor -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength; /**< Numeric expression that is the total size of the HID descriptor */ - uint8_t bDescriptorType; /**< Constant name specifying type of HID descriptor. */ - - uint16_t bcdHID; /**< Numeric expression identifying the HID Class Specification release */ - uint8_t bCountryCode; /**< Numeric expression identifying country code of the localized hardware. */ - uint8_t bNumDescriptors; /**< Numeric expression specifying the number of class descriptors */ - - uint8_t bReportType; /**< Type of HID class report. */ - uint16_t wReportLength; /**< the total size of the Report descriptor. */ -} tusb_hid_descriptor_hid_t; - -/// HID Subclass -typedef enum -{ - HID_SUBCLASS_NONE = 0, ///< No Subclass - HID_SUBCLASS_BOOT = 1 ///< Boot Interface Subclass -}hid_subclass_enum_t; - -/// HID Interface Protocol -typedef enum -{ - HID_ITF_PROTOCOL_NONE = 0, ///< None - HID_ITF_PROTOCOL_KEYBOARD = 1, ///< Keyboard - HID_ITF_PROTOCOL_MOUSE = 2 ///< Mouse -}hid_interface_protocol_enum_t; - -/// HID Descriptor Type -typedef enum -{ - HID_DESC_TYPE_HID = 0x21, ///< HID Descriptor - HID_DESC_TYPE_REPORT = 0x22, ///< Report Descriptor - HID_DESC_TYPE_PHYSICAL = 0x23 ///< Physical Descriptor -}hid_descriptor_enum_t; - -/// HID Request Report Type -typedef enum -{ - HID_REPORT_TYPE_INVALID = 0, - HID_REPORT_TYPE_INPUT, ///< Input - HID_REPORT_TYPE_OUTPUT, ///< Output - HID_REPORT_TYPE_FEATURE ///< Feature -}hid_report_type_t; - -/// HID Class Specific Control Request -typedef enum -{ - HID_REQ_CONTROL_GET_REPORT = 0x01, ///< Get Report - HID_REQ_CONTROL_GET_IDLE = 0x02, ///< Get Idle - HID_REQ_CONTROL_GET_PROTOCOL = 0x03, ///< Get Protocol - HID_REQ_CONTROL_SET_REPORT = 0x09, ///< Set Report - HID_REQ_CONTROL_SET_IDLE = 0x0a, ///< Set Idle - HID_REQ_CONTROL_SET_PROTOCOL = 0x0b ///< Set Protocol -}hid_request_enum_t; - -/// HID Local Code -typedef enum -{ - HID_LOCAL_NotSupported = 0 , ///< NotSupported - HID_LOCAL_Arabic , ///< Arabic - HID_LOCAL_Belgian , ///< Belgian - HID_LOCAL_Canadian_Bilingual , ///< Canadian_Bilingual - HID_LOCAL_Canadian_French , ///< Canadian_French - HID_LOCAL_Czech_Republic , ///< Czech_Republic - HID_LOCAL_Danish , ///< Danish - HID_LOCAL_Finnish , ///< Finnish - HID_LOCAL_French , ///< French - HID_LOCAL_German , ///< German - HID_LOCAL_Greek , ///< Greek - HID_LOCAL_Hebrew , ///< Hebrew - HID_LOCAL_Hungary , ///< Hungary - HID_LOCAL_International , ///< International - HID_LOCAL_Italian , ///< Italian - HID_LOCAL_Japan_Katakana , ///< Japan_Katakana - HID_LOCAL_Korean , ///< Korean - HID_LOCAL_Latin_American , ///< Latin_American - HID_LOCAL_Netherlands_Dutch , ///< Netherlands/Dutch - HID_LOCAL_Norwegian , ///< Norwegian - HID_LOCAL_Persian_Farsi , ///< Persian (Farsi) - HID_LOCAL_Poland , ///< Poland - HID_LOCAL_Portuguese , ///< Portuguese - HID_LOCAL_Russia , ///< Russia - HID_LOCAL_Slovakia , ///< Slovakia - HID_LOCAL_Spanish , ///< Spanish - HID_LOCAL_Swedish , ///< Swedish - HID_LOCAL_Swiss_French , ///< Swiss/French - HID_LOCAL_Swiss_German , ///< Swiss/German - HID_LOCAL_Switzerland , ///< Switzerland - HID_LOCAL_Taiwan , ///< Taiwan - HID_LOCAL_Turkish_Q , ///< Turkish-Q - HID_LOCAL_UK , ///< UK - HID_LOCAL_US , ///< US - HID_LOCAL_Yugoslavia , ///< Yugoslavia - HID_LOCAL_Turkish_F ///< Turkish-F -} hid_local_enum_t; - -// HID protocol value used by GetProtocol / SetProtocol -typedef enum -{ - HID_PROTOCOL_BOOT = 0, - HID_PROTOCOL_REPORT = 1 -} hid_protocol_mode_enum_t; - -/** @} */ - -//--------------------------------------------------------------------+ -// GAMEPAD -//--------------------------------------------------------------------+ -/** \addtogroup ClassDriver_HID_Gamepad Gamepad - * @{ */ - -/* From https://www.kernel.org/doc/html/latest/input/gamepad.html - ____________________________ __ - / [__ZL__] [__ZR__] \ | - / [__ TL __] [__ TR __] \ | Front Triggers - __/________________________________\__ __| - / _ \ | - / /\ __ (N) \ | - / || __ |MO| __ _ _ \ | Main Pad - | <===DP===> |SE| |ST| (W) -|- (E) | | - \ || ___ ___ _ / | - /\ \/ / \ / \ (S) /\ __| - / \________ | LS | ____ | RS | ________/ \ | -| / \ \___/ / \ \___/ / \ | | Control Sticks -| / \_____/ \_____/ \ | __| -| / \ | - \_____/ \_____/ - - |________|______| |______|___________| - D-Pad Left Right Action Pad - Stick Stick - - |_____________| - Menu Pad - - Most gamepads have the following features: - - Action-Pad 4 buttons in diamonds-shape (on the right side) NORTH, SOUTH, WEST and EAST. - - D-Pad (Direction-pad) 4 buttons (on the left side) that point up, down, left and right. - - Menu-Pad Different constellations, but most-times 2 buttons: SELECT - START. - - Analog-Sticks provide freely moveable sticks to control directions, Analog-sticks may also - provide a digital button if you press them. - - Triggers are located on the upper-side of the pad in vertical direction. The upper buttons - are normally named Left- and Right-Triggers, the lower buttons Z-Left and Z-Right. - - Rumble Many devices provide force-feedback features. But are mostly just simple rumble motors. - */ - -/// HID Gamepad Protocol Report. -typedef struct TU_ATTR_PACKED -{ - int8_t x; ///< Delta x movement of left analog-stick - int8_t y; ///< Delta y movement of left analog-stick - int8_t z; ///< Delta z movement of right analog-joystick - int8_t rz; ///< Delta Rz movement of right analog-joystick - int8_t rx; ///< Delta Rx movement of analog left trigger - int8_t ry; ///< Delta Ry movement of analog right trigger - uint8_t hat; ///< Buttons mask for currently pressed buttons in the DPad/hat - uint32_t buttons; ///< Buttons mask for currently pressed buttons -}hid_gamepad_report_t; - -/// Standard Gamepad Buttons Bitmap -typedef enum -{ - GAMEPAD_BUTTON_0 = TU_BIT(0), - GAMEPAD_BUTTON_1 = TU_BIT(1), - GAMEPAD_BUTTON_2 = TU_BIT(2), - GAMEPAD_BUTTON_3 = TU_BIT(3), - GAMEPAD_BUTTON_4 = TU_BIT(4), - GAMEPAD_BUTTON_5 = TU_BIT(5), - GAMEPAD_BUTTON_6 = TU_BIT(6), - GAMEPAD_BUTTON_7 = TU_BIT(7), - GAMEPAD_BUTTON_8 = TU_BIT(8), - GAMEPAD_BUTTON_9 = TU_BIT(9), - GAMEPAD_BUTTON_10 = TU_BIT(10), - GAMEPAD_BUTTON_11 = TU_BIT(11), - GAMEPAD_BUTTON_12 = TU_BIT(12), - GAMEPAD_BUTTON_13 = TU_BIT(13), - GAMEPAD_BUTTON_14 = TU_BIT(14), - GAMEPAD_BUTTON_15 = TU_BIT(15), - GAMEPAD_BUTTON_16 = TU_BIT(16), - GAMEPAD_BUTTON_17 = TU_BIT(17), - GAMEPAD_BUTTON_18 = TU_BIT(18), - GAMEPAD_BUTTON_19 = TU_BIT(19), - GAMEPAD_BUTTON_20 = TU_BIT(20), - GAMEPAD_BUTTON_21 = TU_BIT(21), - GAMEPAD_BUTTON_22 = TU_BIT(22), - GAMEPAD_BUTTON_23 = TU_BIT(23), - GAMEPAD_BUTTON_24 = TU_BIT(24), - GAMEPAD_BUTTON_25 = TU_BIT(25), - GAMEPAD_BUTTON_26 = TU_BIT(26), - GAMEPAD_BUTTON_27 = TU_BIT(27), - GAMEPAD_BUTTON_28 = TU_BIT(28), - GAMEPAD_BUTTON_29 = TU_BIT(29), - GAMEPAD_BUTTON_30 = TU_BIT(30), - GAMEPAD_BUTTON_31 = TU_BIT(31), -}hid_gamepad_button_bm_t; - -/// Standard Gamepad Buttons Naming from Linux input event codes -/// https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h -#define GAMEPAD_BUTTON_A GAMEPAD_BUTTON_0 -#define GAMEPAD_BUTTON_SOUTH GAMEPAD_BUTTON_0 - -#define GAMEPAD_BUTTON_B GAMEPAD_BUTTON_1 -#define GAMEPAD_BUTTON_EAST GAMEPAD_BUTTON_1 - -#define GAMEPAD_BUTTON_C GAMEPAD_BUTTON_2 - -#define GAMEPAD_BUTTON_X GAMEPAD_BUTTON_3 -#define GAMEPAD_BUTTON_NORTH GAMEPAD_BUTTON_3 - -#define GAMEPAD_BUTTON_Y GAMEPAD_BUTTON_4 -#define GAMEPAD_BUTTON_WEST GAMEPAD_BUTTON_4 - -#define GAMEPAD_BUTTON_Z GAMEPAD_BUTTON_5 -#define GAMEPAD_BUTTON_TL GAMEPAD_BUTTON_6 -#define GAMEPAD_BUTTON_TR GAMEPAD_BUTTON_7 -#define GAMEPAD_BUTTON_TL2 GAMEPAD_BUTTON_8 -#define GAMEPAD_BUTTON_TR2 GAMEPAD_BUTTON_9 -#define GAMEPAD_BUTTON_SELECT GAMEPAD_BUTTON_10 -#define GAMEPAD_BUTTON_START GAMEPAD_BUTTON_11 -#define GAMEPAD_BUTTON_MODE GAMEPAD_BUTTON_12 -#define GAMEPAD_BUTTON_THUMBL GAMEPAD_BUTTON_13 -#define GAMEPAD_BUTTON_THUMBR GAMEPAD_BUTTON_14 - -/// Standard Gamepad HAT/DPAD Buttons (from Linux input event codes) -typedef enum -{ - GAMEPAD_HAT_CENTERED = 0, ///< DPAD_CENTERED - GAMEPAD_HAT_UP = 1, ///< DPAD_UP - GAMEPAD_HAT_UP_RIGHT = 2, ///< DPAD_UP_RIGHT - GAMEPAD_HAT_RIGHT = 3, ///< DPAD_RIGHT - GAMEPAD_HAT_DOWN_RIGHT = 4, ///< DPAD_DOWN_RIGHT - GAMEPAD_HAT_DOWN = 5, ///< DPAD_DOWN - GAMEPAD_HAT_DOWN_LEFT = 6, ///< DPAD_DOWN_LEFT - GAMEPAD_HAT_LEFT = 7, ///< DPAD_LEFT - GAMEPAD_HAT_UP_LEFT = 8, ///< DPAD_UP_LEFT -}hid_gamepad_hat_t; - -/// @} - -//--------------------------------------------------------------------+ -// MOUSE -//--------------------------------------------------------------------+ -/** \addtogroup ClassDriver_HID_Mouse Mouse - * @{ */ - -/// Standard HID Boot Protocol Mouse Report. -typedef struct TU_ATTR_PACKED -{ - uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */ - int8_t x; /**< Current delta x movement of the mouse. */ - int8_t y; /**< Current delta y movement on the mouse. */ - int8_t wheel; /**< Current delta wheel movement on the mouse. */ - int8_t pan; // using AC Pan -} hid_mouse_report_t; - -/// Standard Mouse Buttons Bitmap -typedef enum -{ - MOUSE_BUTTON_LEFT = TU_BIT(0), ///< Left button - MOUSE_BUTTON_RIGHT = TU_BIT(1), ///< Right button - MOUSE_BUTTON_MIDDLE = TU_BIT(2), ///< Middle button - MOUSE_BUTTON_BACKWARD = TU_BIT(3), ///< Backward button, - MOUSE_BUTTON_FORWARD = TU_BIT(4), ///< Forward button, -}hid_mouse_button_bm_t; - -/// @} - -//--------------------------------------------------------------------+ -// Keyboard -//--------------------------------------------------------------------+ -/** \addtogroup ClassDriver_HID_Keyboard Keyboard - * @{ */ - -/// Standard HID Boot Protocol Keyboard Report. -typedef struct TU_ATTR_PACKED -{ - uint8_t modifier; /**< Keyboard modifier (KEYBOARD_MODIFIER_* masks). */ - uint8_t reserved; /**< Reserved for OEM use, always set to 0. */ - uint8_t keycode[6]; /**< Key codes of the currently pressed keys. */ -} hid_keyboard_report_t; - -/// Keyboard modifier codes bitmap -typedef enum -{ - KEYBOARD_MODIFIER_LEFTCTRL = TU_BIT(0), ///< Left Control - KEYBOARD_MODIFIER_LEFTSHIFT = TU_BIT(1), ///< Left Shift - KEYBOARD_MODIFIER_LEFTALT = TU_BIT(2), ///< Left Alt - KEYBOARD_MODIFIER_LEFTGUI = TU_BIT(3), ///< Left Window - KEYBOARD_MODIFIER_RIGHTCTRL = TU_BIT(4), ///< Right Control - KEYBOARD_MODIFIER_RIGHTSHIFT = TU_BIT(5), ///< Right Shift - KEYBOARD_MODIFIER_RIGHTALT = TU_BIT(6), ///< Right Alt - KEYBOARD_MODIFIER_RIGHTGUI = TU_BIT(7) ///< Right Window -}hid_keyboard_modifier_bm_t; - -typedef enum -{ - KEYBOARD_LED_NUMLOCK = TU_BIT(0), ///< Num Lock LED - KEYBOARD_LED_CAPSLOCK = TU_BIT(1), ///< Caps Lock LED - KEYBOARD_LED_SCROLLLOCK = TU_BIT(2), ///< Scroll Lock LED - KEYBOARD_LED_COMPOSE = TU_BIT(3), ///< Composition Mode - KEYBOARD_LED_KANA = TU_BIT(4) ///< Kana mode -}hid_keyboard_led_bm_t; - -/// @} - -//--------------------------------------------------------------------+ -// HID KEYCODE -//--------------------------------------------------------------------+ -#define HID_KEY_NONE 0x00 -#define HID_KEY_A 0x04 -#define HID_KEY_B 0x05 -#define HID_KEY_C 0x06 -#define HID_KEY_D 0x07 -#define HID_KEY_E 0x08 -#define HID_KEY_F 0x09 -#define HID_KEY_G 0x0A -#define HID_KEY_H 0x0B -#define HID_KEY_I 0x0C -#define HID_KEY_J 0x0D -#define HID_KEY_K 0x0E -#define HID_KEY_L 0x0F -#define HID_KEY_M 0x10 -#define HID_KEY_N 0x11 -#define HID_KEY_O 0x12 -#define HID_KEY_P 0x13 -#define HID_KEY_Q 0x14 -#define HID_KEY_R 0x15 -#define HID_KEY_S 0x16 -#define HID_KEY_T 0x17 -#define HID_KEY_U 0x18 -#define HID_KEY_V 0x19 -#define HID_KEY_W 0x1A -#define HID_KEY_X 0x1B -#define HID_KEY_Y 0x1C -#define HID_KEY_Z 0x1D -#define HID_KEY_1 0x1E -#define HID_KEY_2 0x1F -#define HID_KEY_3 0x20 -#define HID_KEY_4 0x21 -#define HID_KEY_5 0x22 -#define HID_KEY_6 0x23 -#define HID_KEY_7 0x24 -#define HID_KEY_8 0x25 -#define HID_KEY_9 0x26 -#define HID_KEY_0 0x27 -#define HID_KEY_ENTER 0x28 -#define HID_KEY_ESCAPE 0x29 -#define HID_KEY_BACKSPACE 0x2A -#define HID_KEY_TAB 0x2B -#define HID_KEY_SPACE 0x2C -#define HID_KEY_MINUS 0x2D -#define HID_KEY_EQUAL 0x2E -#define HID_KEY_BRACKET_LEFT 0x2F -#define HID_KEY_BRACKET_RIGHT 0x30 -#define HID_KEY_BACKSLASH 0x31 -#define HID_KEY_EUROPE_1 0x32 -#define HID_KEY_SEMICOLON 0x33 -#define HID_KEY_APOSTROPHE 0x34 -#define HID_KEY_GRAVE 0x35 -#define HID_KEY_COMMA 0x36 -#define HID_KEY_PERIOD 0x37 -#define HID_KEY_SLASH 0x38 -#define HID_KEY_CAPS_LOCK 0x39 -#define HID_KEY_F1 0x3A -#define HID_KEY_F2 0x3B -#define HID_KEY_F3 0x3C -#define HID_KEY_F4 0x3D -#define HID_KEY_F5 0x3E -#define HID_KEY_F6 0x3F -#define HID_KEY_F7 0x40 -#define HID_KEY_F8 0x41 -#define HID_KEY_F9 0x42 -#define HID_KEY_F10 0x43 -#define HID_KEY_F11 0x44 -#define HID_KEY_F12 0x45 -#define HID_KEY_PRINT_SCREEN 0x46 -#define HID_KEY_SCROLL_LOCK 0x47 -#define HID_KEY_PAUSE 0x48 -#define HID_KEY_INSERT 0x49 -#define HID_KEY_HOME 0x4A -#define HID_KEY_PAGE_UP 0x4B -#define HID_KEY_DELETE 0x4C -#define HID_KEY_END 0x4D -#define HID_KEY_PAGE_DOWN 0x4E -#define HID_KEY_ARROW_RIGHT 0x4F -#define HID_KEY_ARROW_LEFT 0x50 -#define HID_KEY_ARROW_DOWN 0x51 -#define HID_KEY_ARROW_UP 0x52 -#define HID_KEY_NUM_LOCK 0x53 -#define HID_KEY_KEYPAD_DIVIDE 0x54 -#define HID_KEY_KEYPAD_MULTIPLY 0x55 -#define HID_KEY_KEYPAD_SUBTRACT 0x56 -#define HID_KEY_KEYPAD_ADD 0x57 -#define HID_KEY_KEYPAD_ENTER 0x58 -#define HID_KEY_KEYPAD_1 0x59 -#define HID_KEY_KEYPAD_2 0x5A -#define HID_KEY_KEYPAD_3 0x5B -#define HID_KEY_KEYPAD_4 0x5C -#define HID_KEY_KEYPAD_5 0x5D -#define HID_KEY_KEYPAD_6 0x5E -#define HID_KEY_KEYPAD_7 0x5F -#define HID_KEY_KEYPAD_8 0x60 -#define HID_KEY_KEYPAD_9 0x61 -#define HID_KEY_KEYPAD_0 0x62 -#define HID_KEY_KEYPAD_DECIMAL 0x63 -#define HID_KEY_EUROPE_2 0x64 -#define HID_KEY_APPLICATION 0x65 -#define HID_KEY_POWER 0x66 -#define HID_KEY_KEYPAD_EQUAL 0x67 -#define HID_KEY_F13 0x68 -#define HID_KEY_F14 0x69 -#define HID_KEY_F15 0x6A -#define HID_KEY_F16 0x6B -#define HID_KEY_F17 0x6C -#define HID_KEY_F18 0x6D -#define HID_KEY_F19 0x6E -#define HID_KEY_F20 0x6F -#define HID_KEY_F21 0x70 -#define HID_KEY_F22 0x71 -#define HID_KEY_F23 0x72 -#define HID_KEY_F24 0x73 -#define HID_KEY_EXECUTE 0x74 -#define HID_KEY_HELP 0x75 -#define HID_KEY_MENU 0x76 -#define HID_KEY_SELECT 0x77 -#define HID_KEY_STOP 0x78 -#define HID_KEY_AGAIN 0x79 -#define HID_KEY_UNDO 0x7A -#define HID_KEY_CUT 0x7B -#define HID_KEY_COPY 0x7C -#define HID_KEY_PASTE 0x7D -#define HID_KEY_FIND 0x7E -#define HID_KEY_MUTE 0x7F -#define HID_KEY_VOLUME_UP 0x80 -#define HID_KEY_VOLUME_DOWN 0x81 -#define HID_KEY_LOCKING_CAPS_LOCK 0x82 -#define HID_KEY_LOCKING_NUM_LOCK 0x83 -#define HID_KEY_LOCKING_SCROLL_LOCK 0x84 -#define HID_KEY_KEYPAD_COMMA 0x85 -#define HID_KEY_KEYPAD_EQUAL_SIGN 0x86 -#define HID_KEY_KANJI1 0x87 -#define HID_KEY_KANJI2 0x88 -#define HID_KEY_KANJI3 0x89 -#define HID_KEY_KANJI4 0x8A -#define HID_KEY_KANJI5 0x8B -#define HID_KEY_KANJI6 0x8C -#define HID_KEY_KANJI7 0x8D -#define HID_KEY_KANJI8 0x8E -#define HID_KEY_KANJI9 0x8F -#define HID_KEY_LANG1 0x90 -#define HID_KEY_LANG2 0x91 -#define HID_KEY_LANG3 0x92 -#define HID_KEY_LANG4 0x93 -#define HID_KEY_LANG5 0x94 -#define HID_KEY_LANG6 0x95 -#define HID_KEY_LANG7 0x96 -#define HID_KEY_LANG8 0x97 -#define HID_KEY_LANG9 0x98 -#define HID_KEY_ALTERNATE_ERASE 0x99 -#define HID_KEY_SYSREQ_ATTENTION 0x9A -#define HID_KEY_CANCEL 0x9B -#define HID_KEY_CLEAR 0x9C -#define HID_KEY_PRIOR 0x9D -#define HID_KEY_RETURN 0x9E -#define HID_KEY_SEPARATOR 0x9F -#define HID_KEY_OUT 0xA0 -#define HID_KEY_OPER 0xA1 -#define HID_KEY_CLEAR_AGAIN 0xA2 -#define HID_KEY_CRSEL_PROPS 0xA3 -#define HID_KEY_EXSEL 0xA4 -// RESERVED 0xA5-DF -#define HID_KEY_CONTROL_LEFT 0xE0 -#define HID_KEY_SHIFT_LEFT 0xE1 -#define HID_KEY_ALT_LEFT 0xE2 -#define HID_KEY_GUI_LEFT 0xE3 -#define HID_KEY_CONTROL_RIGHT 0xE4 -#define HID_KEY_SHIFT_RIGHT 0xE5 -#define HID_KEY_ALT_RIGHT 0xE6 -#define HID_KEY_GUI_RIGHT 0xE7 - - -//--------------------------------------------------------------------+ -// REPORT DESCRIPTOR -//--------------------------------------------------------------------+ - -//------------- ITEM & TAG -------------// -#define HID_REPORT_DATA_0(data) -#define HID_REPORT_DATA_1(data) , data -#define HID_REPORT_DATA_2(data) , U16_TO_U8S_LE(data) -#define HID_REPORT_DATA_3(data) , U32_TO_U8S_LE(data) - -#define HID_REPORT_ITEM(data, tag, type, size) \ - (((tag) << 4) | ((type) << 2) | (size)) HID_REPORT_DATA_##size(data) - -// Report Item Types -enum { - RI_TYPE_MAIN = 0, - RI_TYPE_GLOBAL = 1, - RI_TYPE_LOCAL = 2 -}; - -//------------- Main Items - HID 1.11 section 6.2.2.4 -------------// - -// Report Item Main group -enum { - RI_MAIN_INPUT = 8, - RI_MAIN_OUTPUT = 9, - RI_MAIN_COLLECTION = 10, - RI_MAIN_FEATURE = 11, - RI_MAIN_COLLECTION_END = 12 -}; - -#define HID_INPUT(x) HID_REPORT_ITEM(x, RI_MAIN_INPUT , RI_TYPE_MAIN, 1) -#define HID_OUTPUT(x) HID_REPORT_ITEM(x, RI_MAIN_OUTPUT , RI_TYPE_MAIN, 1) -#define HID_COLLECTION(x) HID_REPORT_ITEM(x, RI_MAIN_COLLECTION , RI_TYPE_MAIN, 1) -#define HID_FEATURE(x) HID_REPORT_ITEM(x, RI_MAIN_FEATURE , RI_TYPE_MAIN, 1) -#define HID_COLLECTION_END HID_REPORT_ITEM(x, RI_MAIN_COLLECTION_END, RI_TYPE_MAIN, 0) - -//------------- Input, Output, Feature - HID 1.11 section 6.2.2.5 -------------// -#define HID_DATA (0<<0) -#define HID_CONSTANT (1<<0) - -#define HID_ARRAY (0<<1) -#define HID_VARIABLE (1<<1) - -#define HID_ABSOLUTE (0<<2) -#define HID_RELATIVE (1<<2) - -#define HID_WRAP_NO (0<<3) -#define HID_WRAP (1<<3) - -#define HID_LINEAR (0<<4) -#define HID_NONLINEAR (1<<4) - -#define HID_PREFERRED_STATE (0<<5) -#define HID_PREFERRED_NO (1<<5) - -#define HID_NO_NULL_POSITION (0<<6) -#define HID_NULL_STATE (1<<6) - -#define HID_NON_VOLATILE (0<<7) -#define HID_VOLATILE (1<<7) - -#define HID_BITFIELD (0<<8) -#define HID_BUFFERED_BYTES (1<<8) - -//------------- Collection Item - HID 1.11 section 6.2.2.6 -------------// -enum { - HID_COLLECTION_PHYSICAL = 0, - HID_COLLECTION_APPLICATION, - HID_COLLECTION_LOGICAL, - HID_COLLECTION_REPORT, - HID_COLLECTION_NAMED_ARRAY, - HID_COLLECTION_USAGE_SWITCH, - HID_COLLECTION_USAGE_MODIFIER -}; - -//------------- Global Items - HID 1.11 section 6.2.2.7 -------------// - -// Report Item Global group -enum { - RI_GLOBAL_USAGE_PAGE = 0, - RI_GLOBAL_LOGICAL_MIN = 1, - RI_GLOBAL_LOGICAL_MAX = 2, - RI_GLOBAL_PHYSICAL_MIN = 3, - RI_GLOBAL_PHYSICAL_MAX = 4, - RI_GLOBAL_UNIT_EXPONENT = 5, - RI_GLOBAL_UNIT = 6, - RI_GLOBAL_REPORT_SIZE = 7, - RI_GLOBAL_REPORT_ID = 8, - RI_GLOBAL_REPORT_COUNT = 9, - RI_GLOBAL_PUSH = 10, - RI_GLOBAL_POP = 11 -}; - -#define HID_USAGE_PAGE(x) HID_REPORT_ITEM(x, RI_GLOBAL_USAGE_PAGE, RI_TYPE_GLOBAL, 1) -#define HID_USAGE_PAGE_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_USAGE_PAGE, RI_TYPE_GLOBAL, n) - -#define HID_LOGICAL_MIN(x) HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MIN, RI_TYPE_GLOBAL, 1) -#define HID_LOGICAL_MIN_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MIN, RI_TYPE_GLOBAL, n) - -#define HID_LOGICAL_MAX(x) HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MAX, RI_TYPE_GLOBAL, 1) -#define HID_LOGICAL_MAX_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MAX, RI_TYPE_GLOBAL, n) - -#define HID_PHYSICAL_MIN(x) HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MIN, RI_TYPE_GLOBAL, 1) -#define HID_PHYSICAL_MIN_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MIN, RI_TYPE_GLOBAL, n) - -#define HID_PHYSICAL_MAX(x) HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MAX, RI_TYPE_GLOBAL, 1) -#define HID_PHYSICAL_MAX_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MAX, RI_TYPE_GLOBAL, n) - -#define HID_UNIT_EXPONENT(x) HID_REPORT_ITEM(x, RI_GLOBAL_UNIT_EXPONENT, RI_TYPE_GLOBAL, 1) -#define HID_UNIT_EXPONENT_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_UNIT_EXPONENT, RI_TYPE_GLOBAL, n) - -#define HID_UNIT(x) HID_REPORT_ITEM(x, RI_GLOBAL_UNIT, RI_TYPE_GLOBAL, 1) -#define HID_UNIT_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_UNIT, RI_TYPE_GLOBAL, n) - -#define HID_REPORT_SIZE(x) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_SIZE, RI_TYPE_GLOBAL, 1) -#define HID_REPORT_SIZE_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_SIZE, RI_TYPE_GLOBAL, n) - -#define HID_REPORT_ID(x) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_ID, RI_TYPE_GLOBAL, 1), -#define HID_REPORT_ID_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_ID, RI_TYPE_GLOBAL, n), - -#define HID_REPORT_COUNT(x) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_COUNT, RI_TYPE_GLOBAL, 1) -#define HID_REPORT_COUNT_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_COUNT, RI_TYPE_GLOBAL, n) - -#define HID_PUSH HID_REPORT_ITEM(x, RI_GLOBAL_PUSH, RI_TYPE_GLOBAL, 0) -#define HID_POP HID_REPORT_ITEM(x, RI_GLOBAL_POP, RI_TYPE_GLOBAL, 0) - -//------------- LOCAL ITEMS 6.2.2.8 -------------// - -enum { - RI_LOCAL_USAGE = 0, - RI_LOCAL_USAGE_MIN = 1, - RI_LOCAL_USAGE_MAX = 2, - RI_LOCAL_DESIGNATOR_INDEX = 3, - RI_LOCAL_DESIGNATOR_MIN = 4, - RI_LOCAL_DESIGNATOR_MAX = 5, - // 6 is reserved - RI_LOCAL_STRING_INDEX = 7, - RI_LOCAL_STRING_MIN = 8, - RI_LOCAL_STRING_MAX = 9, - RI_LOCAL_DELIMITER = 10, -}; - -#define HID_USAGE(x) HID_REPORT_ITEM(x, RI_LOCAL_USAGE, RI_TYPE_LOCAL, 1) -#define HID_USAGE_N(x, n) HID_REPORT_ITEM(x, RI_LOCAL_USAGE, RI_TYPE_LOCAL, n) - -#define HID_USAGE_MIN(x) HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MIN, RI_TYPE_LOCAL, 1) -#define HID_USAGE_MIN_N(x, n) HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MIN, RI_TYPE_LOCAL, n) - -#define HID_USAGE_MAX(x) HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MAX, RI_TYPE_LOCAL, 1) -#define HID_USAGE_MAX_N(x, n) HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MAX, RI_TYPE_LOCAL, n) - -//--------------------------------------------------------------------+ -// Usage Table -//--------------------------------------------------------------------+ - -/// HID Usage Table - Table 1: Usage Page Summary -enum { - HID_USAGE_PAGE_DESKTOP = 0x01, - HID_USAGE_PAGE_SIMULATE = 0x02, - HID_USAGE_PAGE_VIRTUAL_REALITY = 0x03, - HID_USAGE_PAGE_SPORT = 0x04, - HID_USAGE_PAGE_GAME = 0x05, - HID_USAGE_PAGE_GENERIC_DEVICE = 0x06, - HID_USAGE_PAGE_KEYBOARD = 0x07, - HID_USAGE_PAGE_LED = 0x08, - HID_USAGE_PAGE_BUTTON = 0x09, - HID_USAGE_PAGE_ORDINAL = 0x0a, - HID_USAGE_PAGE_TELEPHONY = 0x0b, - HID_USAGE_PAGE_CONSUMER = 0x0c, - HID_USAGE_PAGE_DIGITIZER = 0x0d, - HID_USAGE_PAGE_PID = 0x0f, - HID_USAGE_PAGE_UNICODE = 0x10, - HID_USAGE_PAGE_ALPHA_DISPLAY = 0x14, - HID_USAGE_PAGE_MEDICAL = 0x40, - HID_USAGE_PAGE_MONITOR = 0x80, //0x80 - 0x83 - HID_USAGE_PAGE_POWER = 0x84, // 0x084 - 0x87 - HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c, - HID_USAGE_PAGE_SCALE = 0x8d, - HID_USAGE_PAGE_MSR = 0x8e, - HID_USAGE_PAGE_CAMERA = 0x90, - HID_USAGE_PAGE_ARCADE = 0x91, - HID_USAGE_PAGE_FIDO = 0xF1D0, // FIDO alliance HID usage page - HID_USAGE_PAGE_VENDOR = 0xFF00 // 0xFF00 - 0xFFFF -}; - -/// HID Usage Table - Table 6: Generic Desktop Page -enum { - HID_USAGE_DESKTOP_POINTER = 0x01, - HID_USAGE_DESKTOP_MOUSE = 0x02, - HID_USAGE_DESKTOP_JOYSTICK = 0x04, - HID_USAGE_DESKTOP_GAMEPAD = 0x05, - HID_USAGE_DESKTOP_KEYBOARD = 0x06, - HID_USAGE_DESKTOP_KEYPAD = 0x07, - HID_USAGE_DESKTOP_MULTI_AXIS_CONTROLLER = 0x08, - HID_USAGE_DESKTOP_TABLET_PC_SYSTEM = 0x09, - HID_USAGE_DESKTOP_X = 0x30, - HID_USAGE_DESKTOP_Y = 0x31, - HID_USAGE_DESKTOP_Z = 0x32, - HID_USAGE_DESKTOP_RX = 0x33, - HID_USAGE_DESKTOP_RY = 0x34, - HID_USAGE_DESKTOP_RZ = 0x35, - HID_USAGE_DESKTOP_SLIDER = 0x36, - HID_USAGE_DESKTOP_DIAL = 0x37, - HID_USAGE_DESKTOP_WHEEL = 0x38, - HID_USAGE_DESKTOP_HAT_SWITCH = 0x39, - HID_USAGE_DESKTOP_COUNTED_BUFFER = 0x3a, - HID_USAGE_DESKTOP_BYTE_COUNT = 0x3b, - HID_USAGE_DESKTOP_MOTION_WAKEUP = 0x3c, - HID_USAGE_DESKTOP_START = 0x3d, - HID_USAGE_DESKTOP_SELECT = 0x3e, - HID_USAGE_DESKTOP_VX = 0x40, - HID_USAGE_DESKTOP_VY = 0x41, - HID_USAGE_DESKTOP_VZ = 0x42, - HID_USAGE_DESKTOP_VBRX = 0x43, - HID_USAGE_DESKTOP_VBRY = 0x44, - HID_USAGE_DESKTOP_VBRZ = 0x45, - HID_USAGE_DESKTOP_VNO = 0x46, - HID_USAGE_DESKTOP_FEATURE_NOTIFICATION = 0x47, - HID_USAGE_DESKTOP_RESOLUTION_MULTIPLIER = 0x48, - HID_USAGE_DESKTOP_SYSTEM_CONTROL = 0x80, - HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN = 0x81, - HID_USAGE_DESKTOP_SYSTEM_SLEEP = 0x82, - HID_USAGE_DESKTOP_SYSTEM_WAKE_UP = 0x83, - HID_USAGE_DESKTOP_SYSTEM_CONTEXT_MENU = 0x84, - HID_USAGE_DESKTOP_SYSTEM_MAIN_MENU = 0x85, - HID_USAGE_DESKTOP_SYSTEM_APP_MENU = 0x86, - HID_USAGE_DESKTOP_SYSTEM_MENU_HELP = 0x87, - HID_USAGE_DESKTOP_SYSTEM_MENU_EXIT = 0x88, - HID_USAGE_DESKTOP_SYSTEM_MENU_SELECT = 0x89, - HID_USAGE_DESKTOP_SYSTEM_MENU_RIGHT = 0x8A, - HID_USAGE_DESKTOP_SYSTEM_MENU_LEFT = 0x8B, - HID_USAGE_DESKTOP_SYSTEM_MENU_UP = 0x8C, - HID_USAGE_DESKTOP_SYSTEM_MENU_DOWN = 0x8D, - HID_USAGE_DESKTOP_SYSTEM_COLD_RESTART = 0x8E, - HID_USAGE_DESKTOP_SYSTEM_WARM_RESTART = 0x8F, - HID_USAGE_DESKTOP_DPAD_UP = 0x90, - HID_USAGE_DESKTOP_DPAD_DOWN = 0x91, - HID_USAGE_DESKTOP_DPAD_RIGHT = 0x92, - HID_USAGE_DESKTOP_DPAD_LEFT = 0x93, - HID_USAGE_DESKTOP_SYSTEM_DOCK = 0xA0, - HID_USAGE_DESKTOP_SYSTEM_UNDOCK = 0xA1, - HID_USAGE_DESKTOP_SYSTEM_SETUP = 0xA2, - HID_USAGE_DESKTOP_SYSTEM_BREAK = 0xA3, - HID_USAGE_DESKTOP_SYSTEM_DEBUGGER_BREAK = 0xA4, - HID_USAGE_DESKTOP_APPLICATION_BREAK = 0xA5, - HID_USAGE_DESKTOP_APPLICATION_DEBUGGER_BREAK = 0xA6, - HID_USAGE_DESKTOP_SYSTEM_SPEAKER_MUTE = 0xA7, - HID_USAGE_DESKTOP_SYSTEM_HIBERNATE = 0xA8, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INVERT = 0xB0, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INTERNAL = 0xB1, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_EXTERNAL = 0xB2, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_BOTH = 0xB3, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_DUAL = 0xB4, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_TOGGLE_INT_EXT = 0xB5, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_SWAP_PRIMARY_SECONDARY = 0xB6, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_LCD_AUTOSCALE = 0xB7 -}; - - -/// HID Usage Table: Consumer Page (0x0C) -/// Only contains controls that supported by Windows (whole list is too long) -enum -{ - // Generic Control - HID_USAGE_CONSUMER_CONTROL = 0x0001, - - // Power Control - HID_USAGE_CONSUMER_POWER = 0x0030, - HID_USAGE_CONSUMER_RESET = 0x0031, - HID_USAGE_CONSUMER_SLEEP = 0x0032, - - // Screen Brightness - HID_USAGE_CONSUMER_BRIGHTNESS_INCREMENT = 0x006F, - HID_USAGE_CONSUMER_BRIGHTNESS_DECREMENT = 0x0070, - - // These HID usages operate only on mobile systems (battery powered) and - // require Windows 8 (build 8302 or greater). - HID_USAGE_CONSUMER_WIRELESS_RADIO_CONTROLS = 0x000C, - HID_USAGE_CONSUMER_WIRELESS_RADIO_BUTTONS = 0x00C6, - HID_USAGE_CONSUMER_WIRELESS_RADIO_LED = 0x00C7, - HID_USAGE_CONSUMER_WIRELESS_RADIO_SLIDER_SWITCH = 0x00C8, - - // Media Control - HID_USAGE_CONSUMER_PLAY_PAUSE = 0x00CD, - HID_USAGE_CONSUMER_SCAN_NEXT = 0x00B5, - HID_USAGE_CONSUMER_SCAN_PREVIOUS = 0x00B6, - HID_USAGE_CONSUMER_STOP = 0x00B7, - HID_USAGE_CONSUMER_VOLUME = 0x00E0, - HID_USAGE_CONSUMER_MUTE = 0x00E2, - HID_USAGE_CONSUMER_BASS = 0x00E3, - HID_USAGE_CONSUMER_TREBLE = 0x00E4, - HID_USAGE_CONSUMER_BASS_BOOST = 0x00E5, - HID_USAGE_CONSUMER_VOLUME_INCREMENT = 0x00E9, - HID_USAGE_CONSUMER_VOLUME_DECREMENT = 0x00EA, - HID_USAGE_CONSUMER_BASS_INCREMENT = 0x0152, - HID_USAGE_CONSUMER_BASS_DECREMENT = 0x0153, - HID_USAGE_CONSUMER_TREBLE_INCREMENT = 0x0154, - HID_USAGE_CONSUMER_TREBLE_DECREMENT = 0x0155, - - // Application Launcher - HID_USAGE_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION = 0x0183, - HID_USAGE_CONSUMER_AL_EMAIL_READER = 0x018A, - HID_USAGE_CONSUMER_AL_CALCULATOR = 0x0192, - HID_USAGE_CONSUMER_AL_LOCAL_BROWSER = 0x0194, - - // Browser/Explorer Specific - HID_USAGE_CONSUMER_AC_SEARCH = 0x0221, - HID_USAGE_CONSUMER_AC_HOME = 0x0223, - HID_USAGE_CONSUMER_AC_BACK = 0x0224, - HID_USAGE_CONSUMER_AC_FORWARD = 0x0225, - HID_USAGE_CONSUMER_AC_STOP = 0x0226, - HID_USAGE_CONSUMER_AC_REFRESH = 0x0227, - HID_USAGE_CONSUMER_AC_BOOKMARKS = 0x022A, - - // Mouse Horizontal scroll - HID_USAGE_CONSUMER_AC_PAN = 0x0238, -}; - -/// HID Usage Table: FIDO Alliance Page (0xF1D0) -enum -{ - HID_USAGE_FIDO_U2FHID = 0x01, // U2FHID usage for top-level collection - HID_USAGE_FIDO_DATA_IN = 0x20, // Raw IN data report - HID_USAGE_FIDO_DATA_OUT = 0x21 // Raw OUT data report -}; - -/*-------------------------------------------------------------------- - * ASCII to KEYCODE Conversion - * Expand to array of [128][2] (shift, keycode) - * - * Usage: example to convert input chr into keyboard report (modifier + keycode) - * - * uint8_t const conv_table[128][2] = { HID_ASCII_TO_KEYCODE }; - * - * uint8_t keycode[6] = { 0 }; - * uint8_t modifier = 0; - * - * if ( conv_table[chr][0] ) modifier = KEYBOARD_MODIFIER_LEFTSHIFT; - * keycode[0] = conv_table[chr][1]; - * tud_hid_keyboard_report(report_id, modifier, keycode); - * - *--------------------------------------------------------------------*/ -#define HID_ASCII_TO_KEYCODE \ - {0, 0 }, /* 0x00 Null */ \ - {0, 0 }, /* 0x01 */ \ - {0, 0 }, /* 0x02 */ \ - {0, 0 }, /* 0x03 */ \ - {0, 0 }, /* 0x04 */ \ - {0, 0 }, /* 0x05 */ \ - {0, 0 }, /* 0x06 */ \ - {0, 0 }, /* 0x07 */ \ - {0, HID_KEY_BACKSPACE }, /* 0x08 Backspace */ \ - {0, HID_KEY_TAB }, /* 0x09 Tab */ \ - {0, HID_KEY_ENTER }, /* 0x0A Line Feed */ \ - {0, 0 }, /* 0x0B */ \ - {0, 0 }, /* 0x0C */ \ - {0, HID_KEY_ENTER }, /* 0x0D CR */ \ - {0, 0 }, /* 0x0E */ \ - {0, 0 }, /* 0x0F */ \ - {0, 0 }, /* 0x10 */ \ - {0, 0 }, /* 0x11 */ \ - {0, 0 }, /* 0x12 */ \ - {0, 0 }, /* 0x13 */ \ - {0, 0 }, /* 0x14 */ \ - {0, 0 }, /* 0x15 */ \ - {0, 0 }, /* 0x16 */ \ - {0, 0 }, /* 0x17 */ \ - {0, 0 }, /* 0x18 */ \ - {0, 0 }, /* 0x19 */ \ - {0, 0 }, /* 0x1A */ \ - {0, HID_KEY_ESCAPE }, /* 0x1B Escape */ \ - {0, 0 }, /* 0x1C */ \ - {0, 0 }, /* 0x1D */ \ - {0, 0 }, /* 0x1E */ \ - {0, 0 }, /* 0x1F */ \ - \ - {0, HID_KEY_SPACE }, /* 0x20 */ \ - {1, HID_KEY_1 }, /* 0x21 ! */ \ - {1, HID_KEY_APOSTROPHE }, /* 0x22 " */ \ - {1, HID_KEY_3 }, /* 0x23 # */ \ - {1, HID_KEY_4 }, /* 0x24 $ */ \ - {1, HID_KEY_5 }, /* 0x25 % */ \ - {1, HID_KEY_7 }, /* 0x26 & */ \ - {0, HID_KEY_APOSTROPHE }, /* 0x27 ' */ \ - {1, HID_KEY_9 }, /* 0x28 ( */ \ - {1, HID_KEY_0 }, /* 0x29 ) */ \ - {1, HID_KEY_8 }, /* 0x2A * */ \ - {1, HID_KEY_EQUAL }, /* 0x2B + */ \ - {0, HID_KEY_COMMA }, /* 0x2C , */ \ - {0, HID_KEY_MINUS }, /* 0x2D - */ \ - {0, HID_KEY_PERIOD }, /* 0x2E . */ \ - {0, HID_KEY_SLASH }, /* 0x2F / */ \ - {0, HID_KEY_0 }, /* 0x30 0 */ \ - {0, HID_KEY_1 }, /* 0x31 1 */ \ - {0, HID_KEY_2 }, /* 0x32 2 */ \ - {0, HID_KEY_3 }, /* 0x33 3 */ \ - {0, HID_KEY_4 }, /* 0x34 4 */ \ - {0, HID_KEY_5 }, /* 0x35 5 */ \ - {0, HID_KEY_6 }, /* 0x36 6 */ \ - {0, HID_KEY_7 }, /* 0x37 7 */ \ - {0, HID_KEY_8 }, /* 0x38 8 */ \ - {0, HID_KEY_9 }, /* 0x39 9 */ \ - {1, HID_KEY_SEMICOLON }, /* 0x3A : */ \ - {0, HID_KEY_SEMICOLON }, /* 0x3B ; */ \ - {1, HID_KEY_COMMA }, /* 0x3C < */ \ - {0, HID_KEY_EQUAL }, /* 0x3D = */ \ - {1, HID_KEY_PERIOD }, /* 0x3E > */ \ - {1, HID_KEY_SLASH }, /* 0x3F ? */ \ - \ - {1, HID_KEY_2 }, /* 0x40 @ */ \ - {1, HID_KEY_A }, /* 0x41 A */ \ - {1, HID_KEY_B }, /* 0x42 B */ \ - {1, HID_KEY_C }, /* 0x43 C */ \ - {1, HID_KEY_D }, /* 0x44 D */ \ - {1, HID_KEY_E }, /* 0x45 E */ \ - {1, HID_KEY_F }, /* 0x46 F */ \ - {1, HID_KEY_G }, /* 0x47 G */ \ - {1, HID_KEY_H }, /* 0x48 H */ \ - {1, HID_KEY_I }, /* 0x49 I */ \ - {1, HID_KEY_J }, /* 0x4A J */ \ - {1, HID_KEY_K }, /* 0x4B K */ \ - {1, HID_KEY_L }, /* 0x4C L */ \ - {1, HID_KEY_M }, /* 0x4D M */ \ - {1, HID_KEY_N }, /* 0x4E N */ \ - {1, HID_KEY_O }, /* 0x4F O */ \ - {1, HID_KEY_P }, /* 0x50 P */ \ - {1, HID_KEY_Q }, /* 0x51 Q */ \ - {1, HID_KEY_R }, /* 0x52 R */ \ - {1, HID_KEY_S }, /* 0x53 S */ \ - {1, HID_KEY_T }, /* 0x55 T */ \ - {1, HID_KEY_U }, /* 0x55 U */ \ - {1, HID_KEY_V }, /* 0x56 V */ \ - {1, HID_KEY_W }, /* 0x57 W */ \ - {1, HID_KEY_X }, /* 0x58 X */ \ - {1, HID_KEY_Y }, /* 0x59 Y */ \ - {1, HID_KEY_Z }, /* 0x5A Z */ \ - {0, HID_KEY_BRACKET_LEFT }, /* 0x5B [ */ \ - {0, HID_KEY_BACKSLASH }, /* 0x5C '\' */ \ - {0, HID_KEY_BRACKET_RIGHT }, /* 0x5D ] */ \ - {1, HID_KEY_6 }, /* 0x5E ^ */ \ - {1, HID_KEY_MINUS }, /* 0x5F _ */ \ - \ - {0, HID_KEY_GRAVE }, /* 0x60 ` */ \ - {0, HID_KEY_A }, /* 0x61 a */ \ - {0, HID_KEY_B }, /* 0x62 b */ \ - {0, HID_KEY_C }, /* 0x63 c */ \ - {0, HID_KEY_D }, /* 0x66 d */ \ - {0, HID_KEY_E }, /* 0x65 e */ \ - {0, HID_KEY_F }, /* 0x66 f */ \ - {0, HID_KEY_G }, /* 0x67 g */ \ - {0, HID_KEY_H }, /* 0x68 h */ \ - {0, HID_KEY_I }, /* 0x69 i */ \ - {0, HID_KEY_J }, /* 0x6A j */ \ - {0, HID_KEY_K }, /* 0x6B k */ \ - {0, HID_KEY_L }, /* 0x6C l */ \ - {0, HID_KEY_M }, /* 0x6D m */ \ - {0, HID_KEY_N }, /* 0x6E n */ \ - {0, HID_KEY_O }, /* 0x6F o */ \ - {0, HID_KEY_P }, /* 0x70 p */ \ - {0, HID_KEY_Q }, /* 0x71 q */ \ - {0, HID_KEY_R }, /* 0x72 r */ \ - {0, HID_KEY_S }, /* 0x73 s */ \ - {0, HID_KEY_T }, /* 0x75 t */ \ - {0, HID_KEY_U }, /* 0x75 u */ \ - {0, HID_KEY_V }, /* 0x76 v */ \ - {0, HID_KEY_W }, /* 0x77 w */ \ - {0, HID_KEY_X }, /* 0x78 x */ \ - {0, HID_KEY_Y }, /* 0x79 y */ \ - {0, HID_KEY_Z }, /* 0x7A z */ \ - {1, HID_KEY_BRACKET_LEFT }, /* 0x7B { */ \ - {1, HID_KEY_BACKSLASH }, /* 0x7C | */ \ - {1, HID_KEY_BRACKET_RIGHT }, /* 0x7D } */ \ - {1, HID_KEY_GRAVE }, /* 0x7E ~ */ \ - {0, HID_KEY_DELETE } /* 0x7F Delete */ \ - -/*-------------------------------------------------------------------- - * KEYCODE to Ascii Conversion - * Expand to array of [128][2] (ascii without shift, ascii with shift) - * - * Usage: example to convert ascii from keycode (key) and shift modifier (shift). - * Here we assume key < 128 ( printable ) - * - * uint8_t const conv_table[128][2] = { HID_KEYCODE_TO_ASCII }; - * char ch = shift ? conv_table[chr][1] : conv_table[chr][0]; - * - *--------------------------------------------------------------------*/ -#define HID_KEYCODE_TO_ASCII \ - {0 , 0 }, /* 0x00 */ \ - {0 , 0 }, /* 0x01 */ \ - {0 , 0 }, /* 0x02 */ \ - {0 , 0 }, /* 0x03 */ \ - {'a' , 'A' }, /* 0x04 */ \ - {'b' , 'B' }, /* 0x05 */ \ - {'c' , 'C' }, /* 0x06 */ \ - {'d' , 'D' }, /* 0x07 */ \ - {'e' , 'E' }, /* 0x08 */ \ - {'f' , 'F' }, /* 0x09 */ \ - {'g' , 'G' }, /* 0x0a */ \ - {'h' , 'H' }, /* 0x0b */ \ - {'i' , 'I' }, /* 0x0c */ \ - {'j' , 'J' }, /* 0x0d */ \ - {'k' , 'K' }, /* 0x0e */ \ - {'l' , 'L' }, /* 0x0f */ \ - {'m' , 'M' }, /* 0x10 */ \ - {'n' , 'N' }, /* 0x11 */ \ - {'o' , 'O' }, /* 0x12 */ \ - {'p' , 'P' }, /* 0x13 */ \ - {'q' , 'Q' }, /* 0x14 */ \ - {'r' , 'R' }, /* 0x15 */ \ - {'s' , 'S' }, /* 0x16 */ \ - {'t' , 'T' }, /* 0x17 */ \ - {'u' , 'U' }, /* 0x18 */ \ - {'v' , 'V' }, /* 0x19 */ \ - {'w' , 'W' }, /* 0x1a */ \ - {'x' , 'X' }, /* 0x1b */ \ - {'y' , 'Y' }, /* 0x1c */ \ - {'z' , 'Z' }, /* 0x1d */ \ - {'1' , '!' }, /* 0x1e */ \ - {'2' , '@' }, /* 0x1f */ \ - {'3' , '#' }, /* 0x20 */ \ - {'4' , '$' }, /* 0x21 */ \ - {'5' , '%' }, /* 0x22 */ \ - {'6' , '^' }, /* 0x23 */ \ - {'7' , '&' }, /* 0x24 */ \ - {'8' , '*' }, /* 0x25 */ \ - {'9' , '(' }, /* 0x26 */ \ - {'0' , ')' }, /* 0x27 */ \ - {'\r' , '\r' }, /* 0x28 */ \ - {'\x1b', '\x1b' }, /* 0x29 */ \ - {'\b' , '\b' }, /* 0x2a */ \ - {'\t' , '\t' }, /* 0x2b */ \ - {' ' , ' ' }, /* 0x2c */ \ - {'-' , '_' }, /* 0x2d */ \ - {'=' , '+' }, /* 0x2e */ \ - {'[' , '{' }, /* 0x2f */ \ - {']' , '}' }, /* 0x30 */ \ - {'\\' , '|' }, /* 0x31 */ \ - {'#' , '~' }, /* 0x32 */ \ - {';' , ':' }, /* 0x33 */ \ - {'\'' , '\"' }, /* 0x34 */ \ - {'`' , '~' }, /* 0x35 */ \ - {',' , '<' }, /* 0x36 */ \ - {'.' , '>' }, /* 0x37 */ \ - {'/' , '?' }, /* 0x38 */ \ - \ - {0 , 0 }, /* 0x39 */ \ - {0 , 0 }, /* 0x3a */ \ - {0 , 0 }, /* 0x3b */ \ - {0 , 0 }, /* 0x3c */ \ - {0 , 0 }, /* 0x3d */ \ - {0 , 0 }, /* 0x3e */ \ - {0 , 0 }, /* 0x3f */ \ - {0 , 0 }, /* 0x40 */ \ - {0 , 0 }, /* 0x41 */ \ - {0 , 0 }, /* 0x42 */ \ - {0 , 0 }, /* 0x43 */ \ - {0 , 0 }, /* 0x44 */ \ - {0 , 0 }, /* 0x45 */ \ - {0 , 0 }, /* 0x46 */ \ - {0 , 0 }, /* 0x47 */ \ - {0 , 0 }, /* 0x48 */ \ - {0 , 0 }, /* 0x49 */ \ - {0 , 0 }, /* 0x4a */ \ - {0 , 0 }, /* 0x4b */ \ - {0 , 0 }, /* 0x4c */ \ - {0 , 0 }, /* 0x4d */ \ - {0 , 0 }, /* 0x4e */ \ - {0 , 0 }, /* 0x4f */ \ - {0 , 0 }, /* 0x50 */ \ - {0 , 0 }, /* 0x51 */ \ - {0 , 0 }, /* 0x52 */ \ - {0 , 0 }, /* 0x53 */ \ - \ - {'/' , '/' }, /* 0x54 */ \ - {'*' , '*' }, /* 0x55 */ \ - {'-' , '-' }, /* 0x56 */ \ - {'+' , '+' }, /* 0x57 */ \ - {'\r' , '\r' }, /* 0x58 */ \ - {'1' , 0 }, /* 0x59 */ \ - {'2' , 0 }, /* 0x5a */ \ - {'3' , 0 }, /* 0x5b */ \ - {'4' , 0 }, /* 0x5c */ \ - {'5' , '5' }, /* 0x5d */ \ - {'6' , 0 }, /* 0x5e */ \ - {'7' , 0 }, /* 0x5f */ \ - {'8' , 0 }, /* 0x60 */ \ - {'9' , 0 }, /* 0x61 */ \ - {'0' , 0 }, /* 0x62 */ \ - {'.' , 0 }, /* 0x63 */ \ - {0 , 0 }, /* 0x64 */ \ - {0 , 0 }, /* 0x65 */ \ - {0 , 0 }, /* 0x66 */ \ - {'=' , '=' }, /* 0x67 */ \ - - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_HID_H__ */ - -/// @} diff --git a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.c b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.c deleted file mode 100644 index 9240fe2c..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.c +++ /dev/null @@ -1,415 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_HID) - -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "hid_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -typedef struct -{ - uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; // optional Out endpoint - uint8_t itf_protocol; // Boot mouse or keyboard - - uint8_t protocol_mode; // Boot (0) or Report protocol (1) - uint8_t idle_rate; // up to application to handle idle rate - uint16_t report_desc_len; - - CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE]; - - // TODO save hid descriptor since host can specifically request this after enumeration - // Note: HID descriptor may be not available from application after enumeration - tusb_hid_descriptor_hid_t const * hid_descriptor; -} hidd_interface_t; - -CFG_TUSB_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID]; - -/*------------- Helpers -------------*/ -static inline uint8_t get_index_by_itfnum(uint8_t itf_num) -{ - for (uint8_t i=0; i < CFG_TUD_HID; i++ ) - { - if ( itf_num == _hidd_itf[i].itf_num ) return i; - } - - return 0xFF; -} - -//--------------------------------------------------------------------+ -// APPLICATION API -//--------------------------------------------------------------------+ -bool tud_hid_n_ready(uint8_t instance) -{ - uint8_t const rhport = 0; - uint8_t const ep_in = _hidd_itf[instance].ep_in; - return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(rhport, ep_in); -} - -bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint16_t len) -{ - uint8_t const rhport = 0; - hidd_interface_t * p_hid = &_hidd_itf[instance]; - - // claim endpoint - TU_VERIFY( usbd_edpt_claim(rhport, p_hid->ep_in) ); - - // prepare data - if (report_id) - { - p_hid->epin_buf[0] = report_id; - TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf+1, CFG_TUD_HID_EP_BUFSIZE-1, report, len)); - len++; - }else - { - TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf, CFG_TUD_HID_EP_BUFSIZE, report, len)); - } - - return usbd_edpt_xfer(rhport, p_hid->ep_in, p_hid->epin_buf, len); -} - -uint8_t tud_hid_n_interface_protocol(uint8_t instance) -{ - return _hidd_itf[instance].itf_protocol; -} - -uint8_t tud_hid_n_get_protocol(uint8_t instance) -{ - return _hidd_itf[instance].protocol_mode; -} - -bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6]) -{ - hid_keyboard_report_t report; - - report.modifier = modifier; - report.reserved = 0; - - if ( keycode ) - { - memcpy(report.keycode, keycode, sizeof(report.keycode)); - }else - { - tu_memclr(report.keycode, 6); - } - - return tud_hid_n_report(instance, report_id, &report, sizeof(report)); -} - -bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, - uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) -{ - hid_mouse_report_t report = - { - .buttons = buttons, - .x = x, - .y = y, - .wheel = vertical, - .pan = horizontal - }; - - return tud_hid_n_report(instance, report_id, &report, sizeof(report)); -} - -bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, - int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) { - hid_gamepad_report_t report = - { - .x = x, - .y = y, - .z = z, - .rz = rz, - .rx = rx, - .ry = ry, - .hat = hat, - .buttons = buttons, - }; - - return tud_hid_n_report(instance, report_id, &report, sizeof(report)); -} - -//--------------------------------------------------------------------+ -// USBD-CLASS API -//--------------------------------------------------------------------+ -void hidd_init(void) -{ - hidd_reset(0); -} - -void hidd_reset(uint8_t rhport) -{ - (void) rhport; - tu_memclr(_hidd_itf, sizeof(_hidd_itf)); -} - -uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) - { - TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0); - - // len = interface + hid + n*endpoints - uint16_t const drv_len = - (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + - desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); - TU_ASSERT(max_len >= drv_len, 0); - - // Find available interface - hidd_interface_t * p_hid = NULL; - uint8_t hid_id; - for(hid_id=0; hid_idhid_descriptor = (tusb_hid_descriptor_hid_t const *) p_desc; - - //------------- Endpoint Descriptor -------------// - p_desc = tu_desc_next(p_desc); - TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_INTERRUPT, &p_hid->ep_out, &p_hid->ep_in), 0); - - if ( desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT ) p_hid->itf_protocol = desc_itf->bInterfaceProtocol; - - p_hid->protocol_mode = HID_PROTOCOL_REPORT; // Per Specs: default is report mode - p_hid->itf_num = desc_itf->bInterfaceNumber; - - // Use offsetof to avoid pointer to the odd/misaligned address - p_hid->report_desc_len = tu_unaligned_read16((uint8_t const*) p_hid->hid_descriptor + offsetof(tusb_hid_descriptor_hid_t, wReportLength)); - - // Prepare for output endpoint - if (p_hid->ep_out) - { - if ( !usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)) ) - { - TU_LOG_FAILED(); - TU_BREAKPOINT(); - } - } - - return drv_len; -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); - - uint8_t const hid_itf = get_index_by_itfnum((uint8_t) request->wIndex); - TU_VERIFY(hid_itf < CFG_TUD_HID); - - hidd_interface_t* p_hid = &_hidd_itf[hid_itf]; - - if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) - { - //------------- STD Request -------------// - if ( stage == CONTROL_STAGE_SETUP ) - { - uint8_t const desc_type = tu_u16_high(request->wValue); - //uint8_t const desc_index = tu_u16_low (request->wValue); - - if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_HID) - { - TU_VERIFY(p_hid->hid_descriptor); - TU_VERIFY(tud_control_xfer(rhport, request, (void*)(uintptr_t) p_hid->hid_descriptor, p_hid->hid_descriptor->bLength)); - } - else if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT) - { - uint8_t const * desc_report = tud_hid_descriptor_report_cb(hid_itf); - tud_control_xfer(rhport, request, (void*)(uintptr_t) desc_report, p_hid->report_desc_len); - } - else - { - return false; // stall unsupported request - } - } - } - else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) - { - //------------- Class Specific Request -------------// - switch( request->bRequest ) - { - case HID_REQ_CONTROL_GET_REPORT: - if ( stage == CONTROL_STAGE_SETUP ) - { - uint8_t const report_type = tu_u16_high(request->wValue); - uint8_t const report_id = tu_u16_low(request->wValue); - - uint8_t* report_buf = p_hid->epin_buf; - uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); - - uint16_t xferlen = 0; - - // If host request a specific Report ID, add ID to as 1 byte of response - if ( (report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1) ) - { - *report_buf++ = report_id; - req_len--; - - xferlen++; - } - - xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len); - TU_ASSERT( xferlen > 0 ); - - tud_control_xfer(rhport, request, p_hid->epin_buf, xferlen); - } - break; - - case HID_REQ_CONTROL_SET_REPORT: - if ( stage == CONTROL_STAGE_SETUP ) - { - TU_VERIFY(request->wLength <= sizeof(p_hid->epout_buf)); - tud_control_xfer(rhport, request, p_hid->epout_buf, request->wLength); - } - else if ( stage == CONTROL_STAGE_ACK ) - { - uint8_t const report_type = tu_u16_high(request->wValue); - uint8_t const report_id = tu_u16_low(request->wValue); - - uint8_t const* report_buf = p_hid->epout_buf; - uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); - - // If host request a specific Report ID, extract report ID in buffer before invoking callback - if ( (report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0]) ) - { - report_buf++; - report_len--; - } - - tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, report_len); - } - break; - - case HID_REQ_CONTROL_SET_IDLE: - if ( stage == CONTROL_STAGE_SETUP ) - { - p_hid->idle_rate = tu_u16_high(request->wValue); - if ( tud_hid_set_idle_cb ) - { - // stall request if callback return false - TU_VERIFY( tud_hid_set_idle_cb( hid_itf, p_hid->idle_rate) ); - } - - tud_control_status(rhport, request); - } - break; - - case HID_REQ_CONTROL_GET_IDLE: - if ( stage == CONTROL_STAGE_SETUP ) - { - // TODO idle rate of report - tud_control_xfer(rhport, request, &p_hid->idle_rate, 1); - } - break; - - case HID_REQ_CONTROL_GET_PROTOCOL: - if ( stage == CONTROL_STAGE_SETUP ) - { - tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1); - } - break; - - case HID_REQ_CONTROL_SET_PROTOCOL: - if ( stage == CONTROL_STAGE_SETUP ) - { - tud_control_status(rhport, request); - } - else if ( stage == CONTROL_STAGE_ACK ) - { - p_hid->protocol_mode = (uint8_t) request->wValue; - if (tud_hid_set_protocol_cb) - { - tud_hid_set_protocol_cb(hid_itf, p_hid->protocol_mode); - } - } - break; - - default: return false; // stall unsupported request - } - }else - { - return false; // stall unsupported request - } - - return true; -} - -bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void) result; - - uint8_t instance = 0; - hidd_interface_t * p_hid = _hidd_itf; - - // Identify which interface to use - for (instance = 0; instance < CFG_TUD_HID; instance++) - { - p_hid = &_hidd_itf[instance]; - if ( (ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in) ) break; - } - TU_ASSERT(instance < CFG_TUD_HID); - - // Sent report successfully - if (ep_addr == p_hid->ep_in) - { - if (tud_hid_report_complete_cb) - { - tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t) xferred_bytes); - } - } - // Received report - else if (ep_addr == p_hid->ep_out) - { - tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, (uint16_t) xferred_bytes); - TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))); - } - - return true; -} - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.h b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.h deleted file mode 100644 index 17b24def..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_device.h +++ /dev/null @@ -1,418 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_HID_DEVICE_H_ -#define _TUSB_HID_DEVICE_H_ - -#include "hid.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Class Driver Default Configure & Validation -//--------------------------------------------------------------------+ - -#if !defined(CFG_TUD_HID_EP_BUFSIZE) & defined(CFG_TUD_HID_BUFSIZE) - // TODO warn user to use new name later on - // #warning CFG_TUD_HID_BUFSIZE is renamed to CFG_TUD_HID_EP_BUFSIZE, please update to use the new name - #define CFG_TUD_HID_EP_BUFSIZE CFG_TUD_HID_BUFSIZE -#endif - -#ifndef CFG_TUD_HID_EP_BUFSIZE - #define CFG_TUD_HID_EP_BUFSIZE 64 -#endif - -//--------------------------------------------------------------------+ -// Application API (Multiple Instances) -// CFG_TUD_HID > 1 -//--------------------------------------------------------------------+ - -// Check if the interface is ready to use -bool tud_hid_n_ready(uint8_t instance); - -// Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values -uint8_t tud_hid_n_interface_protocol(uint8_t instance); - -// Get current active protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) -uint8_t tud_hid_n_get_protocol(uint8_t instance); - -// Send report to host -bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint16_t len); - -// KEYBOARD: convenient helper to send keyboard report if application -// use template layout report as defined by hid_keyboard_report_t -bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6]); - -// MOUSE: convenient helper to send mouse report if application -// use template layout report as defined by hid_mouse_report_t -bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal); - -// Gamepad: convenient helper to send gamepad report if application -// use template layout report TUD_HID_REPORT_DESC_GAMEPAD -bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); - -//--------------------------------------------------------------------+ -// Application API (Single Port) -//--------------------------------------------------------------------+ -static inline bool tud_hid_ready(void); -static inline uint8_t tud_hid_interface_protocol(void); -static inline uint8_t tud_hid_get_protocol(void); -static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len); -static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]); -static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal); -static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); - -//--------------------------------------------------------------------+ -// Callbacks (Weak is optional) -//--------------------------------------------------------------------+ - -// Invoked when received GET HID REPORT DESCRIPTOR request -// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete -uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance); - -// Invoked when received GET_REPORT control request -// Application must fill buffer report's content and return its length. -// Return zero will cause the stack to STALL request -uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen); - -// Invoked when received SET_REPORT control request or -// received data on OUT endpoint ( Report ID = 0, Type = 0 ) -void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize); - -// Invoked when received SET_PROTOCOL request -// protocol is either HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) -TU_ATTR_WEAK void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol); - -// Invoked when received SET_IDLE request. return false will stall the request -// - Idle Rate = 0 : only send report if there is changes, i.e skip duplication -// - Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms). -TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate); - -// Invoked when sent REPORT successfully to host -// Application can use this to send the next report -// Note: For composite reports, report[0] is report ID -TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len); - - -//--------------------------------------------------------------------+ -// Inline Functions -//--------------------------------------------------------------------+ -static inline bool tud_hid_ready(void) -{ - return tud_hid_n_ready(0); -} - -static inline uint8_t tud_hid_interface_protocol(void) -{ - return tud_hid_n_interface_protocol(0); -} - -static inline uint8_t tud_hid_get_protocol(void) -{ - return tud_hid_n_get_protocol(0); -} - -static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len) -{ - return tud_hid_n_report(0, report_id, report, len); -} - -static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]) -{ - return tud_hid_n_keyboard_report(0, report_id, modifier, keycode); -} - -static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) -{ - return tud_hid_n_mouse_report(0, report_id, buttons, x, y, vertical, horizontal); -} - -static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) -{ - return tud_hid_n_gamepad_report(0, report_id, x, y, z, rz, rx, ry, hat, buttons); -} - -/* --------------------------------------------------------------------+ - * HID Report Descriptor Template - * - * Convenient for declaring popular HID device (keyboard, mouse, consumer, - * gamepad etc...). Templates take "HID_REPORT_ID(n)" as input, leave - * empty if multiple reports is not used - * - * - Only 1 report: no parameter - * uint8_t const report_desc[] = { TUD_HID_REPORT_DESC_KEYBOARD() }; - * - * - Multiple Reports: "HID_REPORT_ID(ID)" must be passed to template - * uint8_t const report_desc[] = - * { - * TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(1) ) , - * TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(2) ) - * }; - *--------------------------------------------------------------------*/ - -// Keyboard Report Descriptor Template -#define TUD_HID_REPORT_DESC_KEYBOARD(...) \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_KEYBOARD ) ,\ - HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ - /* Report ID if any */\ - __VA_ARGS__ \ - /* 8 bits Modifier Keys (Shift, Control, Alt) */ \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\ - HID_USAGE_MIN ( 224 ) ,\ - HID_USAGE_MAX ( 231 ) ,\ - HID_LOGICAL_MIN ( 0 ) ,\ - HID_LOGICAL_MAX ( 1 ) ,\ - HID_REPORT_COUNT ( 8 ) ,\ - HID_REPORT_SIZE ( 1 ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ - /* 8 bit reserved */ \ - HID_REPORT_COUNT ( 1 ) ,\ - HID_REPORT_SIZE ( 8 ) ,\ - HID_INPUT ( HID_CONSTANT ) ,\ - /* Output 5-bit LED Indicator Kana | Compose | ScrollLock | CapsLock | NumLock */ \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_LED ) ,\ - HID_USAGE_MIN ( 1 ) ,\ - HID_USAGE_MAX ( 5 ) ,\ - HID_REPORT_COUNT ( 5 ) ,\ - HID_REPORT_SIZE ( 1 ) ,\ - HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ - /* led padding */ \ - HID_REPORT_COUNT ( 1 ) ,\ - HID_REPORT_SIZE ( 3 ) ,\ - HID_OUTPUT ( HID_CONSTANT ) ,\ - /* 6-byte Keycodes */ \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\ - HID_USAGE_MIN ( 0 ) ,\ - HID_USAGE_MAX_N ( 255, 2 ) ,\ - HID_LOGICAL_MIN ( 0 ) ,\ - HID_LOGICAL_MAX_N( 255, 2 ) ,\ - HID_REPORT_COUNT ( 6 ) ,\ - HID_REPORT_SIZE ( 8 ) ,\ - HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\ - HID_COLLECTION_END \ - -// Mouse Report Descriptor Template -#define TUD_HID_REPORT_DESC_MOUSE(...) \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ) ,\ - HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ - /* Report ID if any */\ - __VA_ARGS__ \ - HID_USAGE ( HID_USAGE_DESKTOP_POINTER ) ,\ - HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\ - HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\ - HID_USAGE_MIN ( 1 ) ,\ - HID_USAGE_MAX ( 5 ) ,\ - HID_LOGICAL_MIN ( 0 ) ,\ - HID_LOGICAL_MAX ( 1 ) ,\ - /* Left, Right, Middle, Backward, Forward buttons */ \ - HID_REPORT_COUNT( 5 ) ,\ - HID_REPORT_SIZE ( 1 ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ - /* 3 bit padding */ \ - HID_REPORT_COUNT( 1 ) ,\ - HID_REPORT_SIZE ( 3 ) ,\ - HID_INPUT ( HID_CONSTANT ) ,\ - HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ - /* X, Y position [-127, 127] */ \ - HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\ - HID_LOGICAL_MIN ( 0x81 ) ,\ - HID_LOGICAL_MAX ( 0x7f ) ,\ - HID_REPORT_COUNT( 2 ) ,\ - HID_REPORT_SIZE ( 8 ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\ - /* Verital wheel scroll [-127, 127] */ \ - HID_USAGE ( HID_USAGE_DESKTOP_WHEEL ) ,\ - HID_LOGICAL_MIN ( 0x81 ) ,\ - HID_LOGICAL_MAX ( 0x7f ) ,\ - HID_REPORT_COUNT( 1 ) ,\ - HID_REPORT_SIZE ( 8 ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\ - HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ), \ - /* Horizontal wheel scroll [-127, 127] */ \ - HID_USAGE_N ( HID_USAGE_CONSUMER_AC_PAN, 2 ), \ - HID_LOGICAL_MIN ( 0x81 ), \ - HID_LOGICAL_MAX ( 0x7f ), \ - HID_REPORT_COUNT( 1 ), \ - HID_REPORT_SIZE ( 8 ), \ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), \ - HID_COLLECTION_END , \ - HID_COLLECTION_END \ - -// Consumer Control Report Descriptor Template -#define TUD_HID_REPORT_DESC_CONSUMER(...) \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ) ,\ - HID_USAGE ( HID_USAGE_CONSUMER_CONTROL ) ,\ - HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ - /* Report ID if any */\ - __VA_ARGS__ \ - HID_LOGICAL_MIN ( 0x00 ) ,\ - HID_LOGICAL_MAX_N( 0x03FF, 2 ) ,\ - HID_USAGE_MIN ( 0x00 ) ,\ - HID_USAGE_MAX_N ( 0x03FF, 2 ) ,\ - HID_REPORT_COUNT ( 1 ) ,\ - HID_REPORT_SIZE ( 16 ) ,\ - HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\ - HID_COLLECTION_END \ - -/* System Control Report Descriptor Template - * 0x00 - do nothing - * 0x01 - Power Off - * 0x02 - Standby - * 0x03 - Wake Host - */ -#define TUD_HID_REPORT_DESC_SYSTEM_CONTROL(...) \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_CONTROL ) ,\ - HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ - /* Report ID if any */\ - __VA_ARGS__ \ - /* 2 bit system power control */ \ - HID_LOGICAL_MIN ( 1 ) ,\ - HID_LOGICAL_MAX ( 3 ) ,\ - HID_REPORT_COUNT ( 1 ) ,\ - HID_REPORT_SIZE ( 2 ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_SLEEP ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_WAKE_UP ) ,\ - HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\ - /* 6 bit padding */ \ - HID_REPORT_COUNT ( 1 ) ,\ - HID_REPORT_SIZE ( 6 ) ,\ - HID_INPUT ( HID_CONSTANT ) ,\ - HID_COLLECTION_END \ - -// Gamepad Report Descriptor Template -// with 32 buttons, 2 joysticks and 1 hat/dpad with following layout -// | X | Y | Z | Rz | Rx | Ry (1 byte each) | hat/DPAD (1 byte) | Button Map (4 bytes) | -#define TUD_HID_REPORT_DESC_GAMEPAD(...) \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_GAMEPAD ) ,\ - HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ - /* Report ID if any */\ - __VA_ARGS__ \ - /* 8 bit X, Y, Z, Rz, Rx, Ry (min -127, max 127 ) */ \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_Z ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_RZ ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_RX ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_RY ) ,\ - HID_LOGICAL_MIN ( 0x81 ) ,\ - HID_LOGICAL_MAX ( 0x7f ) ,\ - HID_REPORT_COUNT ( 6 ) ,\ - HID_REPORT_SIZE ( 8 ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ - /* 8 bit DPad/Hat Button Map */ \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_HAT_SWITCH ) ,\ - HID_LOGICAL_MIN ( 1 ) ,\ - HID_LOGICAL_MAX ( 8 ) ,\ - HID_PHYSICAL_MIN ( 0 ) ,\ - HID_PHYSICAL_MAX_N ( 315, 2 ) ,\ - HID_REPORT_COUNT ( 1 ) ,\ - HID_REPORT_SIZE ( 8 ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ - /* 32 bit Button Map */ \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\ - HID_USAGE_MIN ( 1 ) ,\ - HID_USAGE_MAX ( 32 ) ,\ - HID_LOGICAL_MIN ( 0 ) ,\ - HID_LOGICAL_MAX ( 1 ) ,\ - HID_REPORT_COUNT ( 32 ) ,\ - HID_REPORT_SIZE ( 1 ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ - HID_COLLECTION_END \ - -// FIDO U2F Authenticator Descriptor Template -// - 1st parameter is report size, which is 64 bytes maximum in U2F -// - 2nd parameter is HID_REPORT_ID(n) (optional) -#define TUD_HID_REPORT_DESC_FIDO_U2F(report_size, ...) \ - HID_USAGE_PAGE_N ( HID_USAGE_PAGE_FIDO, 2 ) ,\ - HID_USAGE ( HID_USAGE_FIDO_U2FHID ) ,\ - HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ - /* Report ID if any */ \ - __VA_ARGS__ \ - /* Usage Data In */ \ - HID_USAGE ( HID_USAGE_FIDO_DATA_IN ) ,\ - HID_LOGICAL_MIN ( 0 ) ,\ - HID_LOGICAL_MAX_N ( 0xff, 2 ) ,\ - HID_REPORT_SIZE ( 8 ) ,\ - HID_REPORT_COUNT ( report_size ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ - /* Usage Data Out */ \ - HID_USAGE ( HID_USAGE_FIDO_DATA_OUT ) ,\ - HID_LOGICAL_MIN ( 0 ) ,\ - HID_LOGICAL_MAX_N ( 0xff, 2 ) ,\ - HID_REPORT_SIZE ( 8 ) ,\ - HID_REPORT_COUNT ( report_size ) ,\ - HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ - HID_COLLECTION_END \ - -// HID Generic Input & Output -// - 1st parameter is report size (mandatory) -// - 2nd parameter is report id HID_REPORT_ID(n) (optional) -#define TUD_HID_REPORT_DESC_GENERIC_INOUT(report_size, ...) \ - HID_USAGE_PAGE_N ( HID_USAGE_PAGE_VENDOR, 2 ),\ - HID_USAGE ( 0x01 ),\ - HID_COLLECTION ( HID_COLLECTION_APPLICATION ),\ - /* Report ID if any */\ - __VA_ARGS__ \ - /* Input */ \ - HID_USAGE ( 0x02 ),\ - HID_LOGICAL_MIN ( 0x00 ),\ - HID_LOGICAL_MAX_N ( 0xff, 2 ),\ - HID_REPORT_SIZE ( 8 ),\ - HID_REPORT_COUNT( report_size ),\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\ - /* Output */ \ - HID_USAGE ( 0x03 ),\ - HID_LOGICAL_MIN ( 0x00 ),\ - HID_LOGICAL_MAX_N ( 0xff, 2 ),\ - HID_REPORT_SIZE ( 8 ),\ - HID_REPORT_COUNT( report_size ),\ - HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\ - HID_COLLECTION_END \ - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void hidd_init (void); -void hidd_reset (uint8_t rhport); -uint16_t hidd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -bool hidd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_HID_DEVICE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.c b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.c deleted file mode 100644 index d95d3ef3..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.c +++ /dev/null @@ -1,772 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUH_ENABLED && CFG_TUH_HID) - -#include "host/usbh.h" -#include "host/usbh_classdriver.h" - -#include "hid_host.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -typedef struct -{ - uint8_t daddr; - - uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; - - uint8_t itf_protocol; // None, Keyboard, Mouse - uint8_t protocol_mode; // Boot (0) or Report protocol (1) - - uint8_t report_desc_type; - uint16_t report_desc_len; - - uint16_t epin_size; - uint16_t epout_size; - - CFG_TUH_MEM_ALIGN uint8_t epin_buf[CFG_TUH_HID_EPIN_BUFSIZE]; - CFG_TUH_MEM_ALIGN uint8_t epout_buf[CFG_TUH_HID_EPOUT_BUFSIZE]; -} hidh_interface_t; - -CFG_TUH_MEM_SECTION -tu_static hidh_interface_t _hidh_itf[CFG_TUH_HID]; - -//--------------------------------------------------------------------+ -// Helper -//--------------------------------------------------------------------+ - -TU_ATTR_ALWAYS_INLINE static inline -hidh_interface_t* get_hid_itf(uint8_t daddr, uint8_t idx) -{ - TU_ASSERT(daddr && idx < CFG_TUH_HID, NULL); - hidh_interface_t* p_hid = &_hidh_itf[idx]; - return (p_hid->daddr == daddr) ? p_hid : NULL; -} - -// Get instance ID by endpoint address -static uint8_t get_idx_by_epaddr(uint8_t daddr, uint8_t ep_addr) -{ - for ( uint8_t idx = 0; idx < CFG_TUH_HID; idx++ ) - { - hidh_interface_t const * p_hid = &_hidh_itf[idx]; - - if ( p_hid->daddr == daddr && - (p_hid->ep_in == ep_addr || p_hid->ep_out == ep_addr) ) - { - return idx; - } - } - - return TUSB_INDEX_INVALID_8; -} - -static hidh_interface_t* find_new_itf(void) -{ - for(uint8_t i=0; idaddr = daddr; - - // re-construct descriptor - tusb_desc_interface_t* desc = &info->desc; - desc->bLength = sizeof(tusb_desc_interface_t); - desc->bDescriptorType = TUSB_DESC_INTERFACE; - - desc->bInterfaceNumber = p_hid->itf_num; - desc->bAlternateSetting = 0; - desc->bNumEndpoints = (uint8_t) ((p_hid->ep_in ? 1u : 0u) + (p_hid->ep_out ? 1u : 0u)); - desc->bInterfaceClass = TUSB_CLASS_HID; - desc->bInterfaceSubClass = (p_hid->itf_protocol ? HID_SUBCLASS_BOOT : HID_SUBCLASS_NONE); - desc->bInterfaceProtocol = p_hid->itf_protocol; - desc->iInterface = 0; // not used yet - - return true; -} - -uint8_t tuh_hid_itf_get_index(uint8_t daddr, uint8_t itf_num) -{ - for ( uint8_t idx = 0; idx < CFG_TUH_HID; idx++ ) - { - hidh_interface_t const * p_hid = &_hidh_itf[idx]; - - if ( p_hid->daddr == daddr && p_hid->itf_num == itf_num) return idx; - } - - return TUSB_INDEX_INVALID_8; -} - -uint8_t tuh_hid_interface_protocol(uint8_t daddr, uint8_t idx) -{ - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - return p_hid ? p_hid->itf_protocol : 0; -} - -//--------------------------------------------------------------------+ -// Control Endpoint API -//--------------------------------------------------------------------+ - -uint8_t tuh_hid_get_protocol(uint8_t daddr, uint8_t idx) -{ - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - return p_hid ? p_hid->protocol_mode : 0; -} - -static void set_protocol_complete(tuh_xfer_t* xfer) -{ - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const daddr = xfer->daddr; - uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num); - - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid, ); - - if (XFER_RESULT_SUCCESS == xfer->result) - { - p_hid->protocol_mode = (uint8_t) tu_le16toh(xfer->setup->wValue); - } - - if (tuh_hid_set_protocol_complete_cb) - { - tuh_hid_set_protocol_complete_cb(daddr, idx, p_hid->protocol_mode); - } -} - -static bool _hidh_set_protocol(uint8_t daddr, uint8_t itf_num, uint8_t protocol, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - TU_LOG2("HID Set Protocol = %d\r\n", protocol); - - tusb_control_request_t const request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = HID_REQ_CONTROL_SET_PROTOCOL, - .wValue = protocol, - .wIndex = itf_num, - .wLength = 0 - }; - - tuh_xfer_t xfer = - { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = NULL, - .complete_cb = complete_cb, - .user_data = user_data - }; - - return tuh_control_xfer(&xfer); -} - -bool tuh_hid_set_protocol(uint8_t daddr, uint8_t idx, uint8_t protocol) -{ - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid && p_hid->itf_protocol != HID_ITF_PROTOCOL_NONE); - - return _hidh_set_protocol(daddr, p_hid->itf_num, protocol, set_protocol_complete, 0); -} - -static void set_report_complete(tuh_xfer_t* xfer) -{ - TU_LOG2("HID Set Report complete\r\n"); - - if (tuh_hid_set_report_complete_cb) - { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num); - - uint8_t const report_type = tu_u16_high(xfer->setup->wValue); - uint8_t const report_id = tu_u16_low(xfer->setup->wValue); - - tuh_hid_set_report_complete_cb(xfer->daddr, idx, report_id, report_type, - (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0); - } -} - -bool tuh_hid_set_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) -{ - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid); - - TU_LOG2("HID Set Report: id = %u, type = %u, len = %u\r\n", report_id, report_type, len); - - tusb_control_request_t const request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = HID_REQ_CONTROL_SET_REPORT, - .wValue = tu_htole16(tu_u16(report_type, report_id)), - .wIndex = tu_htole16((uint16_t)p_hid->itf_num), - .wLength = len - }; - - tuh_xfer_t xfer = - { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = report, - .complete_cb = set_report_complete, - .user_data = 0 - }; - - return tuh_control_xfer(&xfer); -} - -static bool _hidh_set_idle(uint8_t daddr, uint8_t itf_num, uint16_t idle_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - // SET IDLE request, device can stall if not support this request - TU_LOG2("HID Set Idle \r\n"); - - tusb_control_request_t const request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = HID_REQ_CONTROL_SET_IDLE, - .wValue = tu_htole16(idle_rate), - .wIndex = tu_htole16((uint16_t)itf_num), - .wLength = 0 - }; - - tuh_xfer_t xfer = - { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = NULL, - .complete_cb = complete_cb, - .user_data = user_data - }; - - return tuh_control_xfer(&xfer); -} - -//--------------------------------------------------------------------+ -// Interrupt Endpoint API -//--------------------------------------------------------------------+ - -// Check if HID interface is ready to receive report -bool tuh_hid_receive_ready(uint8_t dev_addr, uint8_t idx) -{ - hidh_interface_t* p_hid = get_hid_itf(dev_addr, idx); - TU_VERIFY(p_hid); - - return !usbh_edpt_busy(dev_addr, p_hid->ep_in); -} - -bool tuh_hid_receive_report(uint8_t daddr, uint8_t idx) -{ - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid); - - // claim endpoint - TU_VERIFY( usbh_edpt_claim(daddr, p_hid->ep_in) ); - - if ( !usbh_edpt_xfer(daddr, p_hid->ep_in, p_hid->epin_buf, p_hid->epin_size) ) - { - usbh_edpt_release(daddr, p_hid->ep_in); - return false; - } - - return true; -} - -bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx) -{ - hidh_interface_t* p_hid = get_hid_itf(dev_addr, idx); - TU_VERIFY(p_hid); - - return !usbh_edpt_busy(dev_addr, p_hid->ep_out); -} - -bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const void* report, uint16_t len) -{ - TU_LOG2("HID Send Report %d\r\n", report_id); - - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid); - - if (p_hid->ep_out == 0) - { - // This HID does not have an out endpoint (other than control) - return false; - } - else if (len > CFG_TUH_HID_EPOUT_BUFSIZE || - (report_id != 0 && len > (CFG_TUH_HID_EPOUT_BUFSIZE - 1))) - { - // ep_out buffer is not large enough to hold contents - return false; - } - - // claim endpoint - TU_VERIFY( usbh_edpt_claim(daddr, p_hid->ep_out) ); - - if (report_id == 0) - { - // No report ID in transmission - memcpy(&p_hid->epout_buf[0], report, len); - } - else - { - p_hid->epout_buf[0] = report_id; - memcpy(&p_hid->epout_buf[1], report, len); - ++len; // 1 more byte for report_id - } - - TU_LOG3_MEM(p_hid->epout_buf, len, 2); - - if ( !usbh_edpt_xfer(daddr, p_hid->ep_out, p_hid->epout_buf, len) ) - { - usbh_edpt_release(daddr, p_hid->ep_out); - return false; - } - - return true; -} - -//--------------------------------------------------------------------+ -// USBH API -//--------------------------------------------------------------------+ -void hidh_init(void) -{ - tu_memclr(_hidh_itf, sizeof(_hidh_itf)); -} - -bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void) result; - - uint8_t const dir = tu_edpt_dir(ep_addr); - uint8_t const idx = get_idx_by_epaddr(daddr, ep_addr); - - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid); - - if ( dir == TUSB_DIR_IN ) - { - TU_LOG2(" Get Report callback (%u, %u)\r\n", daddr, idx); - TU_LOG3_MEM(p_hid->epin_buf, xferred_bytes, 2); - tuh_hid_report_received_cb(daddr, idx, p_hid->epin_buf, (uint16_t) xferred_bytes); - }else - { - if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(daddr, idx, p_hid->epout_buf, (uint16_t) xferred_bytes); - } - - return true; -} - -void hidh_close(uint8_t daddr) -{ - for(uint8_t i=0; idaddr == daddr) - { - if(tuh_hid_umount_cb) tuh_hid_umount_cb(daddr, i); - p_hid->daddr = 0; - } - } -} - -//--------------------------------------------------------------------+ -// Enumeration -//--------------------------------------------------------------------+ - -bool hidh_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) -{ - (void) rhport; - (void) max_len; - - TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass); - - TU_LOG2("[%u] HID opening Interface %u\r\n", daddr, desc_itf->bInterfaceNumber); - - // len = interface + hid + n*endpoints - uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + - desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); - TU_ASSERT(max_len >= drv_len); - - uint8_t const *p_desc = (uint8_t const *) desc_itf; - - //------------- HID descriptor -------------// - p_desc = tu_desc_next(p_desc); - tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc; - TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType); - - hidh_interface_t* p_hid = find_new_itf(); - TU_ASSERT(p_hid); // not enough interface, try to increase CFG_TUH_HID - p_hid->daddr = daddr; - - //------------- Endpoint Descriptors -------------// - p_desc = tu_desc_next(p_desc); - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; - - for(int i = 0; i < desc_itf->bNumEndpoints; i++) - { - TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType); - TU_ASSERT( tuh_edpt_open(daddr, desc_ep) ); - - if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) - { - p_hid->ep_in = desc_ep->bEndpointAddress; - p_hid->epin_size = tu_edpt_packet_size(desc_ep); - } - else - { - p_hid->ep_out = desc_ep->bEndpointAddress; - p_hid->epout_size = tu_edpt_packet_size(desc_ep); - } - - p_desc = tu_desc_next(p_desc); - desc_ep = (tusb_desc_endpoint_t const *) p_desc; - } - - p_hid->itf_num = desc_itf->bInterfaceNumber; - - // Assume bNumDescriptors = 1 - p_hid->report_desc_type = desc_hid->bReportType; - p_hid->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength); - - // Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config - p_hid->protocol_mode = HID_PROTOCOL_BOOT; - if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass ) - { - p_hid->itf_protocol = desc_itf->bInterfaceProtocol; - } - - return true; -} - -//--------------------------------------------------------------------+ -// Set Configure -//--------------------------------------------------------------------+ - -enum { - CONFG_SET_IDLE, - CONFIG_SET_PROTOCOL, - CONFIG_GET_REPORT_DESC, - CONFIG_COMPLETE -}; - -static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t const* desc_report, uint16_t desc_len); -static void process_set_config(tuh_xfer_t* xfer); - -bool hidh_set_config(uint8_t daddr, uint8_t itf_num) -{ - tusb_control_request_t request; - request.wIndex = tu_htole16((uint16_t) itf_num); - - tuh_xfer_t xfer; - xfer.daddr = daddr; - xfer.result = XFER_RESULT_SUCCESS; - xfer.setup = &request; - xfer.user_data = CONFG_SET_IDLE; - - // fake request to kick-off the set config process - process_set_config(&xfer); - - return true; -} - -static void process_set_config(tuh_xfer_t* xfer) -{ - // Stall is a valid response for SET_IDLE, sometime SET_PROTOCOL as well - // therefore we could ignore its result - if ( !(xfer->setup->bRequest == HID_REQ_CONTROL_SET_IDLE || - xfer->setup->bRequest == HID_REQ_CONTROL_SET_PROTOCOL) ) - { - TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, ); - } - - uintptr_t const state = xfer->user_data; - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const daddr = xfer->daddr; - - uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num); - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid, ); - - switch(state) - { - case CONFG_SET_IDLE: - { - // Idle rate = 0 mean only report when there is changes - const uint16_t idle_rate = 0; - const uintptr_t next_state = (p_hid->itf_protocol != HID_ITF_PROTOCOL_NONE) ? CONFIG_SET_PROTOCOL : CONFIG_GET_REPORT_DESC; - _hidh_set_idle(daddr, itf_num, idle_rate, process_set_config, next_state); - } - break; - - case CONFIG_SET_PROTOCOL: - _hidh_set_protocol(daddr, p_hid->itf_num, HID_PROTOCOL_BOOT, process_set_config, CONFIG_GET_REPORT_DESC); - break; - - case CONFIG_GET_REPORT_DESC: - // Get Report Descriptor if possible - // using usbh enumeration buffer since report descriptor can be very long - if( p_hid->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE ) - { - TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", p_hid->report_desc_len); - - // Driver is mounted without report descriptor - config_driver_mount_complete(daddr, idx, NULL, 0); - }else - { - tuh_descriptor_get_hid_report(daddr, itf_num, p_hid->report_desc_type, 0, usbh_get_enum_buf(), p_hid->report_desc_len, process_set_config, CONFIG_COMPLETE); - } - break; - - case CONFIG_COMPLETE: - { - uint8_t const* desc_report = usbh_get_enum_buf(); - uint16_t const desc_len = tu_le16toh(xfer->setup->wLength); - - config_driver_mount_complete(daddr, idx, desc_report, desc_len); - } - break; - - default: break; - } -} - -static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t const* desc_report, uint16_t desc_len) -{ - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid, ); - - // enumeration is complete - if (tuh_hid_mount_cb) tuh_hid_mount_cb(daddr, idx, desc_report, desc_len); - - // notify usbh that driver enumeration is complete - usbh_driver_set_config_complete(daddr, p_hid->itf_num); -} - -//--------------------------------------------------------------------+ -// Report Descriptor Parser -//--------------------------------------------------------------------+ - -uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) -{ - // Report Item 6.2.2.2 USB HID 1.11 - union TU_ATTR_PACKED - { - uint8_t byte; - struct TU_ATTR_PACKED - { - uint8_t size : 2; - uint8_t type : 2; - uint8_t tag : 4; - }; - } header; - - tu_memclr(report_info_arr, arr_count*sizeof(tuh_hid_report_info_t)); - - uint8_t report_num = 0; - tuh_hid_report_info_t* info = report_info_arr; - - // current parsed report count & size from descriptor -// uint8_t ri_report_count = 0; -// uint8_t ri_report_size = 0; - - uint8_t ri_collection_depth = 0; - - while(desc_len && report_num < arr_count) - { - header.byte = *desc_report++; - desc_len--; - - uint8_t const tag = header.tag; - uint8_t const type = header.type; - uint8_t const size = header.size; - - uint8_t const data8 = desc_report[0]; - - TU_LOG(3, "tag = %d, type = %d, size = %d, data = ", tag, type, size); - for(uint32_t i=0; iusage_page, desc_report, size); - break; - - case RI_GLOBAL_LOGICAL_MIN : break; - case RI_GLOBAL_LOGICAL_MAX : break; - case RI_GLOBAL_PHYSICAL_MIN : break; - case RI_GLOBAL_PHYSICAL_MAX : break; - - case RI_GLOBAL_REPORT_ID: - info->report_id = data8; - break; - - case RI_GLOBAL_REPORT_SIZE: -// ri_report_size = data8; - break; - - case RI_GLOBAL_REPORT_COUNT: -// ri_report_count = data8; - break; - - case RI_GLOBAL_UNIT_EXPONENT : break; - case RI_GLOBAL_UNIT : break; - case RI_GLOBAL_PUSH : break; - case RI_GLOBAL_POP : break; - - default: break; - } - break; - - case RI_TYPE_LOCAL: - switch(tag) - { - case RI_LOCAL_USAGE: - // only take in account the "usage" before starting REPORT ID - if ( ri_collection_depth == 0 ) info->usage = data8; - break; - - case RI_LOCAL_USAGE_MIN : break; - case RI_LOCAL_USAGE_MAX : break; - case RI_LOCAL_DESIGNATOR_INDEX : break; - case RI_LOCAL_DESIGNATOR_MIN : break; - case RI_LOCAL_DESIGNATOR_MAX : break; - case RI_LOCAL_STRING_INDEX : break; - case RI_LOCAL_STRING_MIN : break; - case RI_LOCAL_STRING_MAX : break; - case RI_LOCAL_DELIMITER : break; - default: break; - } - break; - - // error - default: break; - } - - desc_report += size; - desc_len -= size; - } - - for ( uint8_t i = 0; i < report_num; i++ ) - { - info = report_info_arr+i; - TU_LOG2("%u: id = %u, usage_page = %u, usage = %u\r\n", i, info->report_id, info->usage_page, info->usage); - } - - return report_num; -} - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.h b/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.h deleted file mode 100644 index 08ad421d..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/hid/hid_host.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_HID_HOST_H_ -#define _TUSB_HID_HOST_H_ - -#include "hid.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Class Driver Configuration -//--------------------------------------------------------------------+ - -// TODO Highspeed interrupt can be up to 512 bytes -#ifndef CFG_TUH_HID_EPIN_BUFSIZE -#define CFG_TUH_HID_EPIN_BUFSIZE 64 -#endif - -#ifndef CFG_TUH_HID_EPOUT_BUFSIZE -#define CFG_TUH_HID_EPOUT_BUFSIZE 64 -#endif - - -typedef struct -{ - uint8_t report_id; - uint8_t usage; - uint16_t usage_page; - - // TODO still use the endpoint size for now -// uint8_t in_len; // length of IN report -// uint8_t out_len; // length of OUT report -} tuh_hid_report_info_t; - -//--------------------------------------------------------------------+ -// Interface API -//--------------------------------------------------------------------+ - -// Get the total number of mounted HID interfaces of a device -uint8_t tuh_hid_itf_get_count(uint8_t dev_addr); - -// Get all mounted interfaces across devices -uint8_t tuh_hid_itf_get_total_count(void); - -// backward compatible rename -#define tuh_hid_instance_count tuh_hid_itf_get_count - -// Get Interface information -bool tuh_hid_itf_get_info(uint8_t daddr, uint8_t idx, tuh_itf_info_t* itf_info); - -// Get Interface index from device address + interface number -// return TUSB_INDEX_INVALID_8 (0xFF) if not found -uint8_t tuh_hid_itf_get_index(uint8_t daddr, uint8_t itf_num); - -// Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values -uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t idx); - -// Check if HID interface is mounted -bool tuh_hid_mounted(uint8_t dev_addr, uint8_t idx); - -// Parse report descriptor into array of report_info struct and return number of reports. -// For complicated report, application should write its own parser. -uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED; - -//--------------------------------------------------------------------+ -// Control Endpoint API -//--------------------------------------------------------------------+ - -// Get current protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) -// Note: Device will be initialized in Boot protocol for simplicity. -// Application can use set_protocol() to switch back to Report protocol. -uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t idx); - -// Set protocol to HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) -// This function is only supported by Boot interface (tuh_n_hid_interface_protocol() != NONE) -bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t idx, uint8_t protocol); - -// Set Report using control endpoint -// report_type is either Input, Output or Feature, (value from hid_report_type_t) -bool tuh_hid_set_report(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len); - -//--------------------------------------------------------------------+ -// Interrupt Endpoint API -//--------------------------------------------------------------------+ - -// Check if HID interface is ready to receive report -bool tuh_hid_receive_ready(uint8_t dev_addr, uint8_t idx); - -// Try to receive next report on Interrupt Endpoint. Immediately return -// - true If succeeded, tuh_hid_report_received_cb() callback will be invoked when report is available -// - false if failed to queue the transfer e.g endpoint is busy -bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t idx); - -// Check if HID interface is ready to send report -bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx); - -// Send report using interrupt endpoint -// If report_id > 0 (composite), it will be sent as 1st byte, then report contents. Otherwise only report content is sent. -bool tuh_hid_send_report(uint8_t dev_addr, uint8_t idx, uint8_t report_id, const void* report, uint16_t len); - -//--------------------------------------------------------------------+ -// Callbacks (Weak is optional) -//--------------------------------------------------------------------+ - -// Invoked when device with hid interface is mounted -// Report descriptor is also available for use. tuh_hid_parse_report_descriptor() -// can be used to parse common/simple enough descriptor. -// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped -// therefore report_desc = NULL, desc_len = 0 -TU_ATTR_WEAK void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report_desc, uint16_t desc_len); - -// Invoked when device with hid interface is un-mounted -TU_ATTR_WEAK void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t idx); - -// Invoked when received report from device via interrupt endpoint -// Note: if there is report ID (composite), it is 1st byte of report -void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len); - -// Invoked when sent report to device successfully via interrupt endpoint -TU_ATTR_WEAK void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len); - -// Invoked when Sent Report to device via either control endpoint -// len = 0 indicate there is error in the transfer e.g stalled response -TU_ATTR_WEAK void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len); - -// Invoked when Set Protocol request is complete -TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t protocol); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void hidh_init (void); -bool hidh_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); -bool hidh_set_config (uint8_t dev_addr, uint8_t itf_num); -bool hidh_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); -void hidh_close (uint8_t dev_addr); - -#ifdef __cplusplus -} -#endif - -#endif /* _TUSB_HID_HOST_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/midi/midi.h b/test-devices/composite-stm32/lib/tinyusb/class/midi/midi.h deleted file mode 100644 index 8ddcdfda..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/midi/midi.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -/** \ingroup group_class - * \defgroup ClassDriver_CDC Communication Device Class (CDC) - * Currently only Abstract Control Model subclass is supported - * @{ */ - -#ifndef _TUSB_MIDI_H__ -#define _TUSB_MIDI_H__ - -#include "common/tusb_common.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Class Specific Descriptor -//--------------------------------------------------------------------+ - -typedef enum -{ - MIDI_CS_INTERFACE_HEADER = 0x01, - MIDI_CS_INTERFACE_IN_JACK = 0x02, - MIDI_CS_INTERFACE_OUT_JACK = 0x03, - MIDI_CS_INTERFACE_ELEMENT = 0x04, -} midi_cs_interface_subtype_t; - -typedef enum -{ - MIDI_CS_ENDPOINT_GENERAL = 0x01 -} midi_cs_endpoint_subtype_t; - -typedef enum -{ - MIDI_JACK_EMBEDDED = 0x01, - MIDI_JACK_EXTERNAL = 0x02 -} midi_jack_type_t; - -typedef enum -{ - MIDI_CIN_MISC = 0, - MIDI_CIN_CABLE_EVENT = 1, - MIDI_CIN_SYSCOM_2BYTE = 2, // 2 byte system common message e.g MTC, SongSelect - MIDI_CIN_SYSCOM_3BYTE = 3, // 3 byte system common message e.g SPP - MIDI_CIN_SYSEX_START = 4, // SysEx starts or continue - MIDI_CIN_SYSEX_END_1BYTE = 5, // SysEx ends with 1 data, or 1 byte system common message - MIDI_CIN_SYSEX_END_2BYTE = 6, // SysEx ends with 2 data - MIDI_CIN_SYSEX_END_3BYTE = 7, // SysEx ends with 3 data - MIDI_CIN_NOTE_OFF = 8, - MIDI_CIN_NOTE_ON = 9, - MIDI_CIN_POLY_KEYPRESS = 10, - MIDI_CIN_CONTROL_CHANGE = 11, - MIDI_CIN_PROGRAM_CHANGE = 12, - MIDI_CIN_CHANNEL_PRESSURE = 13, - MIDI_CIN_PITCH_BEND_CHANGE = 14, - MIDI_CIN_1BYTE_DATA = 15 -} midi_code_index_number_t; - -// MIDI 1.0 status byte -enum -{ - //------------- System Exclusive -------------// - MIDI_STATUS_SYSEX_START = 0xF0, - MIDI_STATUS_SYSEX_END = 0xF7, - - //------------- System Common -------------// - MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME = 0xF1, - MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER = 0xF2, - MIDI_STATUS_SYSCOM_SONG_SELECT = 0xF3, - // F4, F5 is undefined - MIDI_STATUS_SYSCOM_TUNE_REQUEST = 0xF6, - - //------------- System RealTime -------------// - MIDI_STATUS_SYSREAL_TIMING_CLOCK = 0xF8, - // 0xF9 is undefined - MIDI_STATUS_SYSREAL_START = 0xFA, - MIDI_STATUS_SYSREAL_CONTINUE = 0xFB, - MIDI_STATUS_SYSREAL_STOP = 0xFC, - // 0xFD is undefined - MIDI_STATUS_SYSREAL_ACTIVE_SENSING = 0xFE, - MIDI_STATUS_SYSREAL_SYSTEM_RESET = 0xFF, -}; - -/// MIDI Interface Header Descriptor -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType - uint16_t bcdMSC ; ///< MidiStreaming SubClass release number in Binary-Coded Decimal - uint16_t wTotalLength ; -} midi_desc_header_t; - -/// MIDI In Jack Descriptor -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType - uint8_t bJackType ; ///< Embedded or External - uint8_t bJackID ; ///< Unique ID for MIDI IN Jack - uint8_t iJack ; ///< string descriptor -} midi_desc_in_jack_t; - - -/// MIDI Out Jack Descriptor with single pin -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType - uint8_t bJackType ; ///< Embedded or External - uint8_t bJackID ; ///< Unique ID for MIDI IN Jack - uint8_t bNrInputPins; - - uint8_t baSourceID; - uint8_t baSourcePin; - - uint8_t iJack ; ///< string descriptor -} midi_desc_out_jack_t ; - -/// MIDI Out Jack Descriptor with multiple pins -#define midi_desc_out_jack_n_t(input_num) \ - struct TU_ATTR_PACKED { \ - uint8_t bLength ; \ - uint8_t bDescriptorType ; \ - uint8_t bDescriptorSubType ; \ - uint8_t bJackType ; \ - uint8_t bJackID ; \ - uint8_t bNrInputPins ; \ - struct TU_ATTR_PACKED { \ - uint8_t baSourceID; \ - uint8_t baSourcePin; \ - } pins[input_num]; \ - uint8_t iJack ; \ - } - -/// MIDI Element Descriptor -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType - uint8_t bElementID; - - uint8_t bNrInputPins; - uint8_t baSourceID; - uint8_t baSourcePin; - - uint8_t bNrOutputPins; - uint8_t bInTerminalLink; - uint8_t bOutTerminalLink; - uint8_t bElCapsSize; - - uint16_t bmElementCaps; - uint8_t iElement; -} midi_desc_element_t; - -/// MIDI Element Descriptor with multiple pins -#define midi_desc_element_n_t(input_num) \ - struct TU_ATTR_PACKED { \ - uint8_t bLength; \ - uint8_t bDescriptorType; \ - uint8_t bDescriptorSubType; \ - uint8_t bElementID; \ - uint8_t bNrInputPins; \ - struct TU_ATTR_PACKED { \ - uint8_t baSourceID; \ - uint8_t baSourcePin; \ - } pins[input_num]; \ - uint8_t bNrOutputPins; \ - uint8_t bInTerminalLink; \ - uint8_t bOutTerminalLink; \ - uint8_t bElCapsSize; \ - uint16_t bmElementCaps; \ - uint8_t iElement; \ - } - -/** @} */ - -#ifdef __cplusplus - } -#endif - -#endif - -/** @} */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.c b/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.c deleted file mode 100644 index e3e7826d..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_MIDI) - -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "midi_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -typedef struct -{ - uint8_t buffer[4]; - uint8_t index; - uint8_t total; -}midid_stream_t; - -typedef struct -{ - uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; - - // For Stream read()/write() API - // Messages are always 4 bytes long, queue them for reading and writing so the - // callers can use the Stream interface with single-byte read/write calls. - midid_stream_t stream_write; - midid_stream_t stream_read; - - /*------------- From this point, data is not cleared by bus reset -------------*/ - // FIFO - tu_fifo_t rx_ff; - tu_fifo_t tx_ff; - uint8_t rx_ff_buf[CFG_TUD_MIDI_RX_BUFSIZE]; - uint8_t tx_ff_buf[CFG_TUD_MIDI_TX_BUFSIZE]; - - #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_ff_mutex; - osal_mutex_def_t tx_ff_mutex; - #endif - - // Endpoint Transfer buffer - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_MIDI_EP_BUFSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_MIDI_EP_BUFSIZE]; - -} midid_interface_t; - -#define ITF_MEM_RESET_SIZE offsetof(midid_interface_t, rx_ff) - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION midid_interface_t _midid_itf[CFG_TUD_MIDI]; - -bool tud_midi_n_mounted (uint8_t itf) -{ - midid_interface_t* midi = &_midid_itf[itf]; - return midi->ep_in && midi->ep_out; -} - -static void _prep_out_transaction (midid_interface_t* p_midi) -{ - uint8_t const rhport = 0; - uint16_t available = tu_fifo_remaining(&p_midi->rx_ff); - - // Prepare for incoming data but only allow what we can store in the ring buffer. - // TODO Actually we can still carry out the transfer, keeping count of received bytes - // and slowly move it to the FIFO when read(). - // This pre-check reduces endpoint claiming - TU_VERIFY(available >= sizeof(p_midi->epout_buf), ); - - // claim endpoint - TU_VERIFY(usbd_edpt_claim(rhport, p_midi->ep_out), ); - - // fifo can be changed before endpoint is claimed - available = tu_fifo_remaining(&p_midi->rx_ff); - - if ( available >= sizeof(p_midi->epout_buf) ) { - usbd_edpt_xfer(rhport, p_midi->ep_out, p_midi->epout_buf, sizeof(p_midi->epout_buf)); - }else - { - // Release endpoint since we don't make any transfer - usbd_edpt_release(rhport, p_midi->ep_out); - } -} - -//--------------------------------------------------------------------+ -// READ API -//--------------------------------------------------------------------+ -uint32_t tud_midi_n_available(uint8_t itf, uint8_t cable_num) -{ - (void) cable_num; - - midid_interface_t* midi = &_midid_itf[itf]; - midid_stream_t const* stream = &midi->stream_read; - - // when using with packet API stream total & index are both zero - return tu_fifo_count(&midi->rx_ff) + (uint8_t) (stream->total - stream->index); -} - -uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize) -{ - (void) cable_num; - TU_VERIFY(bufsize, 0); - - uint8_t* buf8 = (uint8_t*) buffer; - - midid_interface_t* midi = &_midid_itf[itf]; - midid_stream_t* stream = &midi->stream_read; - - uint32_t total_read = 0; - while( bufsize ) - { - // Get new packet from fifo, then set packet expected bytes - if ( stream->total == 0 ) - { - // return if there is no more data from fifo - if ( !tud_midi_n_packet_read(itf, stream->buffer) ) return total_read; - - uint8_t const code_index = stream->buffer[0] & 0x0f; - - // MIDI 1.0 Table 4-1: Code Index Number Classifications - switch(code_index) - { - case MIDI_CIN_MISC: - case MIDI_CIN_CABLE_EVENT: - // These are reserved and unused, possibly issue somewhere, skip this packet - return 0; - break; - - case MIDI_CIN_SYSEX_END_1BYTE: - case MIDI_CIN_1BYTE_DATA: - stream->total = 1; - break; - - case MIDI_CIN_SYSCOM_2BYTE : - case MIDI_CIN_SYSEX_END_2BYTE : - case MIDI_CIN_PROGRAM_CHANGE : - case MIDI_CIN_CHANNEL_PRESSURE : - stream->total = 2; - break; - - default: - stream->total = 3; - break; - } - } - - // Copy data up to bufsize - uint8_t const count = (uint8_t) tu_min32(stream->total - stream->index, bufsize); - - // Skip the header (1st byte) in the buffer - TU_VERIFY(0 == tu_memcpy_s(buf8, bufsize, stream->buffer + 1 + stream->index, count)); - - total_read += count; - stream->index += count; - buf8 += count; - bufsize -= count; - - // complete current event packet, reset stream - if ( stream->total == stream->index ) - { - stream->index = 0; - stream->total = 0; - } - } - - return total_read; -} - -bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]) -{ - midid_interface_t* midi = &_midid_itf[itf]; - TU_VERIFY(midi->ep_out); - - uint32_t const num_read = tu_fifo_read_n(&midi->rx_ff, packet, 4); - _prep_out_transaction(midi); - return (num_read == 4); -} - -//--------------------------------------------------------------------+ -// WRITE API -//--------------------------------------------------------------------+ - -static uint32_t write_flush(midid_interface_t* midi) -{ - // No data to send - if ( !tu_fifo_count(&midi->tx_ff) ) return 0; - - uint8_t const rhport = 0; - - // skip if previous transfer not complete - TU_VERIFY( usbd_edpt_claim(rhport, midi->ep_in), 0 ); - - uint16_t count = tu_fifo_read_n(&midi->tx_ff, midi->epin_buf, CFG_TUD_MIDI_EP_BUFSIZE); - - if (count) - { - TU_ASSERT( usbd_edpt_xfer(rhport, midi->ep_in, midi->epin_buf, count), 0 ); - return count; - }else - { - // Release endpoint since we don't make any transfer - usbd_edpt_release(rhport, midi->ep_in); - return 0; - } -} - -uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) -{ - midid_interface_t* midi = &_midid_itf[itf]; - TU_VERIFY(midi->ep_in, 0); - - midid_stream_t* stream = &midi->stream_write; - - uint32_t i = 0; - while ( (i < bufsize) && (tu_fifo_remaining(&midi->tx_ff) >= 4) ) - { - uint8_t const data = buffer[i]; - i++; - - if ( stream->index == 0 ) - { - //------------- New event packet -------------// - - uint8_t const msg = data >> 4; - - stream->index = 2; - stream->buffer[1] = data; - - // Check to see if we're still in a SysEx transmit. - if ( ((stream->buffer[0]) & 0xF) == MIDI_CIN_SYSEX_START ) - { - if ( data == MIDI_STATUS_SYSEX_END ) - { - stream->buffer[0] = (uint8_t) ((cable_num << 4) | MIDI_CIN_SYSEX_END_1BYTE); - stream->total = 2; - } - else - { - stream->total = 4; - } - } - else if ( (msg >= 0x8 && msg <= 0xB) || msg == 0xE ) - { - // Channel Voice Messages - stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg); - stream->total = 4; - } - else if ( msg == 0xC || msg == 0xD) - { - // Channel Voice Messages, two-byte variants (Program Change and Channel Pressure) - stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg); - stream->total = 3; - } - else if ( msg == 0xf ) - { - // System message - if ( data == MIDI_STATUS_SYSEX_START ) - { - stream->buffer[0] = MIDI_CIN_SYSEX_START; - stream->total = 4; - } - else if ( data == MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME || data == MIDI_STATUS_SYSCOM_SONG_SELECT ) - { - stream->buffer[0] = MIDI_CIN_SYSCOM_2BYTE; - stream->total = 3; - } - else if ( data == MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER ) - { - stream->buffer[0] = MIDI_CIN_SYSCOM_3BYTE; - stream->total = 4; - } - else - { - stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; - stream->total = 2; - } - stream->buffer[0] |= (uint8_t)(cable_num << 4); - } - else - { - // Pack individual bytes if we don't support packing them into words. - stream->buffer[0] = (uint8_t) (cable_num << 4 | 0xf); - stream->buffer[2] = 0; - stream->buffer[3] = 0; - stream->index = 2; - stream->total = 2; - } - } - else - { - //------------- On-going (buffering) packet -------------// - - TU_ASSERT(stream->index < 4, i); - stream->buffer[stream->index] = data; - stream->index++; - - // See if this byte ends a SysEx. - if ( (stream->buffer[0] & 0xF) == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END ) - { - stream->buffer[0] = (uint8_t) ((cable_num << 4) | (MIDI_CIN_SYSEX_START + (stream->index - 1))); - stream->total = stream->index; - } - } - - // Send out packet - if ( stream->index == stream->total ) - { - // zeroes unused bytes - for(uint8_t idx = stream->total; idx < 4; idx++) stream->buffer[idx] = 0; - - uint16_t const count = tu_fifo_write_n(&midi->tx_ff, stream->buffer, 4); - - // complete current event packet, reset stream - stream->index = stream->total = 0; - - // FIFO overflown, since we already check fifo remaining. It is probably race condition - TU_ASSERT(count == 4, i); - } - } - - write_flush(midi); - - return i; -} - -bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]) -{ - midid_interface_t* midi = &_midid_itf[itf]; - TU_VERIFY(midi->ep_in); - - if (tu_fifo_remaining(&midi->tx_ff) < 4) return false; - - tu_fifo_write_n(&midi->tx_ff, packet, 4); - write_flush(midi); - - return true; -} - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void midid_init(void) -{ - tu_memclr(_midid_itf, sizeof(_midid_itf)); - - for(uint8_t i=0; irx_ff, midi->rx_ff_buf, CFG_TUD_MIDI_RX_BUFSIZE, 1, false); // true, true - tu_fifo_config(&midi->tx_ff, midi->tx_ff_buf, CFG_TUD_MIDI_TX_BUFSIZE, 1, false); // OBVS. - - #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&midi->rx_ff, NULL, osal_mutex_create(&midi->rx_ff_mutex)); - tu_fifo_config_mutex(&midi->tx_ff, osal_mutex_create(&midi->tx_ff_mutex), NULL); - #endif - } -} - -void midid_reset(uint8_t rhport) -{ - (void) rhport; - - for(uint8_t i=0; irx_ff); - tu_fifo_clear(&midi->tx_ff); - } -} - -uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) -{ - // 1st Interface is Audio Control v1 - TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass && - AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass && - AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_itf->bInterfaceProtocol, 0); - - uint16_t drv_len = tu_desc_len(desc_itf); - uint8_t const * p_desc = tu_desc_next(desc_itf); - - // Skip Class Specific descriptors - while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) - { - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - // 2nd Interface is MIDI Streaming - TU_VERIFY(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); - tusb_desc_interface_t const * desc_midi = (tusb_desc_interface_t const *) p_desc; - - TU_VERIFY(TUSB_CLASS_AUDIO == desc_midi->bInterfaceClass && - AUDIO_SUBCLASS_MIDI_STREAMING == desc_midi->bInterfaceSubClass && - AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_midi->bInterfaceProtocol, 0); - - // Find available interface - midid_interface_t * p_midi = NULL; - for(uint8_t i=0; iitf_num = desc_midi->bInterfaceNumber; - (void) p_midi->itf_num; - - // next descriptor - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - - // Find and open endpoint descriptors - uint8_t found_endpoints = 0; - while ( (found_endpoints < desc_midi->bNumEndpoints) && (drv_len <= max_len) ) - { - if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) - { - TU_ASSERT(usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0); - uint8_t ep_addr = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; - - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) - { - p_midi->ep_in = ep_addr; - } else { - p_midi->ep_out = ep_addr; - } - - // Class Specific MIDI Stream endpoint descriptor - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - - found_endpoints += 1; - } - - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - // Prepare for incoming data - _prep_out_transaction(p_midi); - - return drv_len; -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool midid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - (void) rhport; - (void) stage; - (void) request; - - // driver doesn't support any request yet - return false; -} - -bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void) result; - (void) rhport; - - uint8_t itf; - midid_interface_t* p_midi; - - // Identify which interface to use - for (itf = 0; itf < CFG_TUD_MIDI; itf++) - { - p_midi = &_midid_itf[itf]; - if ( ( ep_addr == p_midi->ep_out ) || ( ep_addr == p_midi->ep_in ) ) break; - } - TU_ASSERT(itf < CFG_TUD_MIDI); - - // receive new data - if ( ep_addr == p_midi->ep_out ) - { - tu_fifo_write_n(&p_midi->rx_ff, p_midi->epout_buf, (uint16_t) xferred_bytes); - - // invoke receive callback if available - if (tud_midi_rx_cb) tud_midi_rx_cb(itf); - - // prepare for next - // TODO for now ep_out is not used by public API therefore there is no race condition, - // and does not need to claim like ep_in - _prep_out_transaction(p_midi); - } - else if ( ep_addr == p_midi->ep_in ) - { - if (0 == write_flush(p_midi)) - { - // If there is no data left, a ZLP should be sent if - // xferred_bytes is multiple of EP size and not zero - if ( !tu_fifo_count(&p_midi->tx_ff) && xferred_bytes && (0 == (xferred_bytes % CFG_TUD_MIDI_EP_BUFSIZE)) ) - { - if ( usbd_edpt_claim(rhport, p_midi->ep_in) ) - { - usbd_edpt_xfer(rhport, p_midi->ep_in, NULL, 0); - } - } - } - } - - return true; -} - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.h b/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.h deleted file mode 100644 index 1c6f996b..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/midi/midi_device.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_MIDI_DEVICE_H_ -#define _TUSB_MIDI_DEVICE_H_ - -#include "class/audio/audio.h" -#include "midi.h" - -//--------------------------------------------------------------------+ -// Class Driver Configuration -//--------------------------------------------------------------------+ - -#if !defined(CFG_TUD_MIDI_EP_BUFSIZE) && defined(CFG_TUD_MIDI_EPSIZE) - #warning CFG_TUD_MIDI_EPSIZE is renamed to CFG_TUD_MIDI_EP_BUFSIZE, please update to use the new name - #define CFG_TUD_MIDI_EP_BUFSIZE CFG_TUD_MIDI_EPSIZE -#endif - -#ifndef CFG_TUD_MIDI_EP_BUFSIZE - #define CFG_TUD_MIDI_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) -#endif - -#ifdef __cplusplus - extern "C" { -#endif - -/** \addtogroup MIDI_Serial Serial - * @{ - * \defgroup MIDI_Serial_Device Device - * @{ */ - -//--------------------------------------------------------------------+ -// Application API (Multiple Interfaces) -// CFG_TUD_MIDI > 1 -//--------------------------------------------------------------------+ - -// Check if midi interface is mounted -bool tud_midi_n_mounted (uint8_t itf); - -// Get the number of bytes available for reading -uint32_t tud_midi_n_available (uint8_t itf, uint8_t cable_num); - -// Read byte stream (legacy) -uint32_t tud_midi_n_stream_read (uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize); - -// Write byte Stream (legacy) -uint32_t tud_midi_n_stream_write (uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); - -// Read event packet (4 bytes) -bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]); - -// Write event packet (4 bytes) -bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]); - -//--------------------------------------------------------------------+ -// Application API (Single Interface) -//--------------------------------------------------------------------+ -static inline bool tud_midi_mounted (void); -static inline uint32_t tud_midi_available (void); - -static inline uint32_t tud_midi_stream_read (void* buffer, uint32_t bufsize); -static inline uint32_t tud_midi_stream_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); - -static inline bool tud_midi_packet_read (uint8_t packet[4]); -static inline bool tud_midi_packet_write (uint8_t const packet[4]); - -//------------- Deprecated API name -------------// -// TODO remove after 0.10.0 release - -TU_ATTR_DEPRECATED("tud_midi_read() is renamed to tud_midi_stream_read()") -static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize) -{ - return tud_midi_stream_read(buffer, bufsize); -} - -TU_ATTR_DEPRECATED("tud_midi_write() is renamed to tud_midi_stream_write()") -static inline uint32_t tud_midi_write(uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) -{ - return tud_midi_stream_write(cable_num, buffer, bufsize); -} - - -TU_ATTR_DEPRECATED("tud_midi_send() is renamed to tud_midi_packet_write()") -static inline bool tud_midi_send(uint8_t packet[4]) -{ - return tud_midi_packet_write(packet); -} - -TU_ATTR_DEPRECATED("tud_midi_receive() is renamed to tud_midi_packet_read()") -static inline bool tud_midi_receive(uint8_t packet[4]) -{ - return tud_midi_packet_read(packet); -} - -//--------------------------------------------------------------------+ -// Application Callback API (weak is optional) -//--------------------------------------------------------------------+ -TU_ATTR_WEAK void tud_midi_rx_cb(uint8_t itf); - -//--------------------------------------------------------------------+ -// Inline Functions -//--------------------------------------------------------------------+ - -static inline bool tud_midi_mounted (void) -{ - return tud_midi_n_mounted(0); -} - -static inline uint32_t tud_midi_available (void) -{ - return tud_midi_n_available(0, 0); -} - -static inline uint32_t tud_midi_stream_read (void* buffer, uint32_t bufsize) -{ - return tud_midi_n_stream_read(0, 0, buffer, bufsize); -} - -static inline uint32_t tud_midi_stream_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) -{ - return tud_midi_n_stream_write(0, cable_num, buffer, bufsize); -} - -static inline bool tud_midi_packet_read (uint8_t packet[4]) -{ - return tud_midi_n_packet_read(0, packet); -} - -static inline bool tud_midi_packet_write (uint8_t const packet[4]) -{ - return tud_midi_n_packet_write(0, packet); -} - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void midid_init (void); -void midid_reset (uint8_t rhport); -uint16_t midid_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool midid_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -bool midid_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_MIDI_DEVICE_H_ */ - -/** @} */ -/** @} */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc.h b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc.h deleted file mode 100644 index 7f25a29b..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc.h +++ /dev/null @@ -1,382 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_MSC_H_ -#define _TUSB_MSC_H_ - -#include "common/tusb_common.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Mass Storage Class Constant -//--------------------------------------------------------------------+ -/// MassStorage Subclass -typedef enum -{ - MSC_SUBCLASS_RBC = 1 , ///< Reduced Block Commands (RBC) T10 Project 1240-D - MSC_SUBCLASS_SFF_MMC , ///< SFF-8020i, MMC-2 (ATAPI). Typically used by a CD/DVD device - MSC_SUBCLASS_QIC , ///< QIC-157. Typically used by a tape device - MSC_SUBCLASS_UFI , ///< UFI. Typically used by Floppy Disk Drive (FDD) device - MSC_SUBCLASS_SFF , ///< SFF-8070i. Can be used by Floppy Disk Drive (FDD) device - MSC_SUBCLASS_SCSI ///< SCSI transparent command set -}msc_subclass_type_t; - -enum { - MSC_CBW_SIGNATURE = 0x43425355, ///< Constant value of 43425355h (little endian) - MSC_CSW_SIGNATURE = 0x53425355 ///< Constant value of 53425355h (little endian) -}; - -/// \brief MassStorage Protocol. -/// \details CBI only approved to use with full-speed floopy disk & should not used with highspeed or device other than floopy -typedef enum -{ - MSC_PROTOCOL_CBI = 0 , ///< Control/Bulk/Interrupt protocol (with command completion interrupt) - MSC_PROTOCOL_CBI_NO_INTERRUPT = 1 , ///< Control/Bulk/Interrupt protocol (without command completion interrupt) - MSC_PROTOCOL_BOT = 0x50 ///< Bulk-Only Transport -}msc_protocol_type_t; - -/// MassStorage Class-Specific Control Request -typedef enum -{ - MSC_REQ_GET_MAX_LUN = 254, ///< The Get Max LUN device request is used to determine the number of logical units supported by the device. Logical Unit Numbers on the device shall be numbered contiguously starting from LUN 0 to a maximum LUN of 15 - MSC_REQ_RESET = 255 ///< This request is used to reset the mass storage device and its associated interface. This class-specific request shall ready the device for the next CBW from the host. -}msc_request_type_t; - -/// \brief Command Block Status Values -/// \details Indicates the success or failure of the command. The device shall set this byte to zero if the command completed -/// successfully. A non-zero value shall indicate a failure during command execution according to the following -typedef enum -{ - MSC_CSW_STATUS_PASSED = 0 , ///< MSC_CSW_STATUS_PASSED - MSC_CSW_STATUS_FAILED , ///< MSC_CSW_STATUS_FAILED - MSC_CSW_STATUS_PHASE_ERROR ///< MSC_CSW_STATUS_PHASE_ERROR -}msc_csw_status_t; - -/// Command Block Wrapper -typedef struct TU_ATTR_PACKED -{ - uint32_t signature; ///< Signature that helps identify this data packet as a CBW. The signature field shall contain the value 43425355h (little endian), indicating a CBW. - uint32_t tag; ///< Tag sent by the host. The device shall echo the contents of this field back to the host in the dCSWTagfield of the associated CSW. The dCSWTagpositively associates a CSW with the corresponding CBW. - uint32_t total_bytes; ///< The number of bytes of data that the host expects to transfer on the Bulk-In or Bulk-Out endpoint (as indicated by the Direction bit) during the execution of this command. If this field is zero, the device and the host shall transfer no data between the CBW and the associated CSW, and the device shall ignore the value of the Direction bit in bmCBWFlags. - uint8_t dir; ///< Bit 7 of this field define transfer direction \n - 0 : Data-Out from host to the device. \n - 1 : Data-In from the device to the host. - uint8_t lun; ///< The device Logical Unit Number (LUN) to which the command block is being sent. For devices that support multiple LUNs, the host shall place into this field the LUN to which this command block is addressed. Otherwise, the host shall set this field to zero. - uint8_t cmd_len; ///< The valid length of the CBWCBin bytes. This defines the valid length of the command block. The only legal values are 1 through 16 - uint8_t command[16]; ///< The command block to be executed by the device. The device shall interpret the first cmd_len bytes in this field as a command block -}msc_cbw_t; - -TU_VERIFY_STATIC(sizeof(msc_cbw_t) == 31, "size is not correct"); - -/// Command Status Wrapper -typedef struct TU_ATTR_PACKED -{ - uint32_t signature ; ///< Signature that helps identify this data packet as a CSW. The signature field shall contain the value 53425355h (little endian), indicating CSW. - uint32_t tag ; ///< The device shall set this field to the value received in the dCBWTag of the associated CBW. - uint32_t data_residue ; ///< For Data-Out the device shall report in the dCSWDataResiduethe difference between the amount of data expected as stated in the dCBWDataTransferLength, and the actual amount of data processed by the device. For Data-In the device shall report in the dCSWDataResiduethe difference between the amount of data expected as stated in the dCBWDataTransferLengthand the actual amount of relevant data sent by the device - uint8_t status ; ///< indicates the success or failure of the command. Values from \ref msc_csw_status_t -}msc_csw_t; - -TU_VERIFY_STATIC(sizeof(msc_csw_t) == 13, "size is not correct"); - -//--------------------------------------------------------------------+ -// SCSI Constant -//--------------------------------------------------------------------+ - -/// SCSI Command Operation Code -typedef enum -{ - SCSI_CMD_TEST_UNIT_READY = 0x00, ///< The SCSI Test Unit Ready command is used to determine if a device is ready to transfer data (read/write), i.e. if a disk has spun up, if a tape is loaded and ready etc. The device does not perform a self-test operation. - SCSI_CMD_INQUIRY = 0x12, ///< The SCSI Inquiry command is used to obtain basic information from a target device. - SCSI_CMD_MODE_SELECT_6 = 0x15, ///< provides a means for the application client to specify medium, logical unit, or peripheral device parameters to the device server. Device servers that implement the MODE SELECT(6) command shall also implement the MODE SENSE(6) command. Application clients should issue MODE SENSE(6) prior to each MODE SELECT(6) to determine supported mode pages, page lengths, and other parameters. - SCSI_CMD_MODE_SENSE_6 = 0x1A, ///< provides a means for a device server to report parameters to an application client. It is a complementary command to the MODE SELECT(6) command. Device servers that implement the MODE SENSE(6) command shall also implement the MODE SELECT(6) command. - SCSI_CMD_START_STOP_UNIT = 0x1B, - SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1E, - SCSI_CMD_READ_CAPACITY_10 = 0x25, ///< The SCSI Read Capacity command is used to obtain data capacity information from a target device. - SCSI_CMD_REQUEST_SENSE = 0x03, ///< The SCSI Request Sense command is part of the SCSI computer protocol standard. This command is used to obtain sense data -- status/error information -- from a target device. - SCSI_CMD_READ_FORMAT_CAPACITY = 0x23, ///< The command allows the Host to request a list of the possible format capacities for an installed writable media. This command also has the capability to report the writable capacity for a media when it is installed - SCSI_CMD_READ_10 = 0x28, ///< The READ (10) command requests that the device server read the specified logical block(s) and transfer them to the data-in buffer. - SCSI_CMD_WRITE_10 = 0x2A, ///< The WRITE (10) command requests thatthe device server transfer the specified logical block(s) from the data-out buffer and write them. -}scsi_cmd_type_t; - -/// SCSI Sense Key -typedef enum -{ - SCSI_SENSE_NONE = 0x00, ///< no specific Sense Key. This would be the case for a successful command - SCSI_SENSE_RECOVERED_ERROR = 0x01, ///< ndicates the last command completed successfully with some recovery action performed by the disc drive. - SCSI_SENSE_NOT_READY = 0x02, ///< Indicates the logical unit addressed cannot be accessed. - SCSI_SENSE_MEDIUM_ERROR = 0x03, ///< Indicates the command terminated with a non-recovered error condition. - SCSI_SENSE_HARDWARE_ERROR = 0x04, ///< Indicates the disc drive detected a nonrecoverable hardware failure while performing the command or during a self test. - SCSI_SENSE_ILLEGAL_REQUEST = 0x05, ///< Indicates an illegal parameter in the command descriptor block or in the additional parameters - SCSI_SENSE_UNIT_ATTENTION = 0x06, ///< Indicates the disc drive may have been reset. - SCSI_SENSE_DATA_PROTECT = 0x07, ///< Indicates that a command that reads or writes the medium was attempted on a block that is protected from this operation. The read or write operation is not performed. - SCSI_SENSE_FIRMWARE_ERROR = 0x08, ///< Vendor specific sense key. - SCSI_SENSE_ABORTED_COMMAND = 0x0b, ///< Indicates the disc drive aborted the command. - SCSI_SENSE_EQUAL = 0x0c, ///< Indicates a SEARCH DATA command has satisfied an equal comparison. - SCSI_SENSE_VOLUME_OVERFLOW = 0x0d, ///< Indicates a buffered peripheral device has reached the end of medium partition and data remains in the buffer that has not been written to the medium. - SCSI_SENSE_MISCOMPARE = 0x0e ///< ndicates that the source data did not match the data read from the medium. -}scsi_sense_key_type_t; - -//--------------------------------------------------------------------+ -// SCSI Primary Command (SPC-4) -//--------------------------------------------------------------------+ - -/// SCSI Test Unit Ready Command -typedef struct TU_ATTR_PACKED -{ - uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_TEST_UNIT_READY - uint8_t lun ; ///< Logical Unit - uint8_t reserved[3] ; - uint8_t control ; -} scsi_test_unit_ready_t; - -TU_VERIFY_STATIC(sizeof(scsi_test_unit_ready_t) == 6, "size is not correct"); - -/// SCSI Inquiry Command -typedef struct TU_ATTR_PACKED -{ - uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_INQUIRY - uint8_t reserved1 ; - uint8_t page_code ; - uint8_t reserved2 ; - uint8_t alloc_length ; ///< specifies the maximum number of bytes that USB host has allocated in the Data-In Buffer. An allocation length of zero specifies that no data shall be transferred. - uint8_t control ; -} scsi_inquiry_t, scsi_request_sense_t; - -TU_VERIFY_STATIC(sizeof(scsi_inquiry_t) == 6, "size is not correct"); - -/// SCSI Inquiry Response Data -typedef struct TU_ATTR_PACKED -{ - uint8_t peripheral_device_type : 5; - uint8_t peripheral_qualifier : 3; - - uint8_t : 7; - uint8_t is_removable : 1; - - uint8_t version; - - uint8_t response_data_format : 4; - uint8_t hierarchical_support : 1; - uint8_t normal_aca : 1; - uint8_t : 2; - - uint8_t additional_length; - - uint8_t protect : 1; - uint8_t : 2; - uint8_t third_party_copy : 1; - uint8_t target_port_group_support : 2; - uint8_t access_control_coordinator : 1; - uint8_t scc_support : 1; - - uint8_t addr16 : 1; - uint8_t : 3; - uint8_t multi_port : 1; - uint8_t : 1; // vendor specific - uint8_t enclosure_service : 1; - uint8_t : 1; - - uint8_t : 1; // vendor specific - uint8_t cmd_que : 1; - uint8_t : 2; - uint8_t sync : 1; - uint8_t wbus16 : 1; - uint8_t : 2; - - uint8_t vendor_id[8] ; ///< 8 bytes of ASCII data identifying the vendor of the product. - uint8_t product_id[16]; ///< 16 bytes of ASCII data defined by the vendor. - uint8_t product_rev[4]; ///< 4 bytes of ASCII data defined by the vendor. -} scsi_inquiry_resp_t; - -TU_VERIFY_STATIC(sizeof(scsi_inquiry_resp_t) == 36, "size is not correct"); - - -typedef struct TU_ATTR_PACKED -{ - uint8_t response_code : 7; ///< 70h - current errors, Fixed Format 71h - deferred errors, Fixed Format - uint8_t valid : 1; - - uint8_t reserved; - - uint8_t sense_key : 4; - uint8_t : 1; - uint8_t ili : 1; ///< Incorrect length indicator - uint8_t end_of_medium : 1; - uint8_t filemark : 1; - - uint32_t information; - uint8_t add_sense_len; - uint32_t command_specific_info; - uint8_t add_sense_code; - uint8_t add_sense_qualifier; - uint8_t field_replaceable_unit_code; - - uint8_t sense_key_specific[3]; ///< sense key specific valid bit is bit 7 of key[0], aka MSB in Big Endian layout - -} scsi_sense_fixed_resp_t; - -TU_VERIFY_STATIC(sizeof(scsi_sense_fixed_resp_t) == 18, "size is not correct"); - -typedef struct TU_ATTR_PACKED -{ - uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_MODE_SENSE_6 - - uint8_t : 3; - uint8_t disable_block_descriptor : 1; - uint8_t : 4; - - uint8_t page_code : 6; - uint8_t page_control : 2; - - uint8_t subpage_code; - uint8_t alloc_length; - uint8_t control; -} scsi_mode_sense6_t; - -TU_VERIFY_STATIC( sizeof(scsi_mode_sense6_t) == 6, "size is not correct"); - -// This is only a Mode parameter header(6). -typedef struct TU_ATTR_PACKED -{ - uint8_t data_len; - uint8_t medium_type; - - uint8_t reserved : 7; - bool write_protected : 1; - - uint8_t block_descriptor_len; -} scsi_mode_sense6_resp_t; - -TU_VERIFY_STATIC( sizeof(scsi_mode_sense6_resp_t) == 4, "size is not correct"); - -typedef struct TU_ATTR_PACKED -{ - uint8_t cmd_code; ///< SCSI OpCode for \ref SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL - uint8_t reserved[3]; - uint8_t prohibit_removal; - uint8_t control; -} scsi_prevent_allow_medium_removal_t; - -TU_VERIFY_STATIC( sizeof(scsi_prevent_allow_medium_removal_t) == 6, "size is not correct"); - -typedef struct TU_ATTR_PACKED -{ - uint8_t cmd_code; - - uint8_t immded : 1; - uint8_t : 7; - - uint8_t TU_RESERVED; - - uint8_t power_condition_mod : 4; - uint8_t : 4; - - uint8_t start : 1; - uint8_t load_eject : 1; - uint8_t no_flush : 1; - uint8_t : 1; - uint8_t power_condition : 4; - - uint8_t control; -} scsi_start_stop_unit_t; - -TU_VERIFY_STATIC( sizeof(scsi_start_stop_unit_t) == 6, "size is not correct"); - -//--------------------------------------------------------------------+ -// SCSI MMC -//--------------------------------------------------------------------+ -/// SCSI Read Format Capacity: Write Capacity -typedef struct TU_ATTR_PACKED -{ - uint8_t cmd_code; - uint8_t reserved[6]; - uint16_t alloc_length; - uint8_t control; -} scsi_read_format_capacity_t; - -TU_VERIFY_STATIC( sizeof(scsi_read_format_capacity_t) == 10, "size is not correct"); - -typedef struct TU_ATTR_PACKED{ - uint8_t reserved[3]; - uint8_t list_length; /// must be 8*n, length in bytes of formattable capacity descriptor followed it. - - uint32_t block_num; /// Number of Logical Blocks - uint8_t descriptor_type; // 00: reserved, 01 unformatted media , 10 Formatted media, 11 No media present - - uint8_t reserved2; - uint16_t block_size_u16; - -} scsi_read_format_capacity_data_t; - -TU_VERIFY_STATIC( sizeof(scsi_read_format_capacity_data_t) == 12, "size is not correct"); - -//--------------------------------------------------------------------+ -// SCSI Block Command (SBC-3) -// NOTE: All data in SCSI command are in Big Endian -//--------------------------------------------------------------------+ - -/// SCSI Read Capacity 10 Command: Read Capacity -typedef struct TU_ATTR_PACKED -{ - uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_READ_CAPACITY_10 - uint8_t reserved1 ; - uint32_t lba ; ///< The first Logical Block Address (LBA) accessed by this command - uint16_t reserved2 ; - uint8_t partial_medium_indicator ; - uint8_t control ; -} scsi_read_capacity10_t; - -TU_VERIFY_STATIC(sizeof(scsi_read_capacity10_t) == 10, "size is not correct"); - -/// SCSI Read Capacity 10 Response Data -typedef struct { - uint32_t last_lba ; ///< The last Logical Block Address of the device - uint32_t block_size ; ///< Block size in bytes -} scsi_read_capacity10_resp_t; - -TU_VERIFY_STATIC(sizeof(scsi_read_capacity10_resp_t) == 8, "size is not correct"); - -/// SCSI Read 10 Command -typedef struct TU_ATTR_PACKED -{ - uint8_t cmd_code ; ///< SCSI OpCode - uint8_t reserved ; // has LUN according to wiki - uint32_t lba ; ///< The first Logical Block Address (LBA) accessed by this command - uint8_t reserved2 ; - uint16_t block_count ; ///< Number of Blocks used by this command - uint8_t control ; -} scsi_read10_t, scsi_write10_t; - -TU_VERIFY_STATIC(sizeof(scsi_read10_t) == 10, "size is not correct"); -TU_VERIFY_STATIC(sizeof(scsi_write10_t) == 10, "size is not correct"); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_MSC_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.c b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.c deleted file mode 100644 index 159a1125..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.c +++ /dev/null @@ -1,952 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_MSC) - -#include "device/dcd.h" // for faking dcd_event_xfer_complete -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "msc_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -// Can be selectively disabled to reduce logging when troubleshooting other driver -#define MSC_DEBUG 2 - -enum -{ - MSC_STAGE_CMD = 0, - MSC_STAGE_DATA, - MSC_STAGE_STATUS, - MSC_STAGE_STATUS_SENT, - MSC_STAGE_NEED_RESET, -}; - -typedef struct -{ - // TODO optimize alignment - CFG_TUSB_MEM_ALIGN msc_cbw_t cbw; - CFG_TUSB_MEM_ALIGN msc_csw_t csw; - - uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; - - // Bulk Only Transfer (BOT) Protocol - uint8_t stage; - uint32_t total_len; // byte to be transferred, can be smaller than total_bytes in cbw - uint32_t xferred_len; // numbered of bytes transferred so far in the Data Stage - - // Sense Response Data - uint8_t sense_key; - uint8_t add_sense_code; - uint8_t add_sense_qualifier; -}mscd_interface_t; - -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static mscd_interface_t _mscd_itf; -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t _mscd_buf[CFG_TUD_MSC_EP_BUFSIZE]; - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize); -static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc); - -static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc); -static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes); - -TU_ATTR_ALWAYS_INLINE static inline bool is_data_in(uint8_t dir) -{ - return tu_bit_test(dir, 7); -} - -static inline bool send_csw(uint8_t rhport, mscd_interface_t* p_msc) -{ - // Data residue is always = host expect - actual transferred - p_msc->csw.data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len; - - p_msc->stage = MSC_STAGE_STATUS_SENT; - return usbd_edpt_xfer(rhport, p_msc->ep_in , (uint8_t*) &p_msc->csw, sizeof(msc_csw_t)); -} - -static inline bool prepare_cbw(uint8_t rhport, mscd_interface_t* p_msc) -{ - p_msc->stage = MSC_STAGE_CMD; - return usbd_edpt_xfer(rhport, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)); -} - -static void fail_scsi_op(uint8_t rhport, mscd_interface_t* p_msc, uint8_t status) -{ - msc_cbw_t const * p_cbw = &p_msc->cbw; - msc_csw_t * p_csw = &p_msc->csw; - - p_csw->status = status; - p_csw->data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len; - p_msc->stage = MSC_STAGE_STATUS; - - // failed but sense key is not set: default to Illegal Request - if ( p_msc->sense_key == 0 ) tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); - - // If there is data stage and not yet complete, stall it - if ( p_cbw->total_bytes && p_csw->data_residue ) - { - if ( is_data_in(p_cbw->dir) ) - { - usbd_edpt_stall(rhport, p_msc->ep_in); - } - else - { - usbd_edpt_stall(rhport, p_msc->ep_out); - } - } -} - -static inline uint32_t rdwr10_get_lba(uint8_t const command[]) -{ - // use offsetof to avoid pointer to the odd/unaligned address - uint32_t const lba = tu_unaligned_read32(command + offsetof(scsi_write10_t, lba)); - - // lba is in Big Endian - return tu_ntohl(lba); -} - -static inline uint16_t rdwr10_get_blockcount(msc_cbw_t const* cbw) -{ - uint16_t const block_count = tu_unaligned_read16(cbw->command + offsetof(scsi_write10_t, block_count)); - return tu_ntohs(block_count); -} - -static inline uint16_t rdwr10_get_blocksize(msc_cbw_t const* cbw) -{ - // first extract block count in the command - uint16_t const block_count = rdwr10_get_blockcount(cbw); - - // invalid block count - if (block_count == 0) return 0; - - return (uint16_t) (cbw->total_bytes / block_count); -} - -uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw) -{ - uint8_t status = MSC_CSW_STATUS_PASSED; - uint16_t const block_count = rdwr10_get_blockcount(cbw); - - if ( cbw->total_bytes == 0 ) - { - if ( block_count ) - { - TU_LOG(MSC_DEBUG, " SCSI case 2 (Hn < Di) or case 3 (Hn < Do) \r\n"); - status = MSC_CSW_STATUS_PHASE_ERROR; - }else - { - // no data transfer, only exist in complaint test suite - } - }else - { - if ( SCSI_CMD_READ_10 == cbw->command[0] && !is_data_in(cbw->dir) ) - { - TU_LOG(MSC_DEBUG, " SCSI case 10 (Ho <> Di)\r\n"); - status = MSC_CSW_STATUS_PHASE_ERROR; - } - else if ( SCSI_CMD_WRITE_10 == cbw->command[0] && is_data_in(cbw->dir) ) - { - TU_LOG(MSC_DEBUG, " SCSI case 8 (Hi <> Do)\r\n"); - status = MSC_CSW_STATUS_PHASE_ERROR; - } - else if ( 0 == block_count ) - { - TU_LOG(MSC_DEBUG, " SCSI case 4 Hi > Dn (READ10) or case 9 Ho > Dn (WRITE10) \r\n"); - status = MSC_CSW_STATUS_FAILED; - } - else if ( cbw->total_bytes / block_count == 0 ) - { - TU_LOG(MSC_DEBUG, " Computed block size = 0. SCSI case 7 Hi < Di (READ10) or case 13 Ho < Do (WRIT10)\r\n"); - status = MSC_CSW_STATUS_PHASE_ERROR; - } - } - - return status; -} - -//--------------------------------------------------------------------+ -// Debug -//--------------------------------------------------------------------+ -#if CFG_TUSB_DEBUG >= 2 - -TU_ATTR_UNUSED tu_static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] = -{ - { .key = SCSI_CMD_TEST_UNIT_READY , .data = "Test Unit Ready" }, - { .key = SCSI_CMD_INQUIRY , .data = "Inquiry" }, - { .key = SCSI_CMD_MODE_SELECT_6 , .data = "Mode_Select 6" }, - { .key = SCSI_CMD_MODE_SENSE_6 , .data = "Mode_Sense 6" }, - { .key = SCSI_CMD_START_STOP_UNIT , .data = "Start Stop Unit" }, - { .key = SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL , .data = "Prevent/Allow Medium Removal" }, - { .key = SCSI_CMD_READ_CAPACITY_10 , .data = "Read Capacity10" }, - { .key = SCSI_CMD_REQUEST_SENSE , .data = "Request Sense" }, - { .key = SCSI_CMD_READ_FORMAT_CAPACITY , .data = "Read Format Capacity" }, - { .key = SCSI_CMD_READ_10 , .data = "Read10" }, - { .key = SCSI_CMD_WRITE_10 , .data = "Write10" } -}; - -TU_ATTR_UNUSED tu_static tu_lookup_table_t const _msc_scsi_cmd_table = -{ - .count = TU_ARRAY_SIZE(_msc_scsi_cmd_lookup), - .items = _msc_scsi_cmd_lookup -}; - -#endif - -//--------------------------------------------------------------------+ -// APPLICATION API -//--------------------------------------------------------------------+ -bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier) -{ - (void) lun; - - _mscd_itf.sense_key = sense_key; - _mscd_itf.add_sense_code = add_sense_code; - _mscd_itf.add_sense_qualifier = add_sense_qualifier; - - return true; -} - -static inline void set_sense_medium_not_present(uint8_t lun) -{ - // default sense is NOT READY, MEDIUM NOT PRESENT - tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00); -} - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void mscd_init(void) -{ - tu_memclr(&_mscd_itf, sizeof(mscd_interface_t)); -} - -void mscd_reset(uint8_t rhport) -{ - (void) rhport; - tu_memclr(&_mscd_itf, sizeof(mscd_interface_t)); -} - -uint16_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ - // only support SCSI's BOT protocol - TU_VERIFY(TUSB_CLASS_MSC == itf_desc->bInterfaceClass && - MSC_SUBCLASS_SCSI == itf_desc->bInterfaceSubClass && - MSC_PROTOCOL_BOT == itf_desc->bInterfaceProtocol, 0); - - // msc driver length is fixed - uint16_t const drv_len = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t); - - // Max length must be at least 1 interface + 2 endpoints - TU_ASSERT(max_len >= drv_len, 0); - - mscd_interface_t * p_msc = &_mscd_itf; - p_msc->itf_num = itf_desc->bInterfaceNumber; - - // Open endpoint pair - TU_ASSERT( usbd_open_edpt_pair(rhport, tu_desc_next(itf_desc), 2, TUSB_XFER_BULK, &p_msc->ep_out, &p_msc->ep_in), 0 ); - - // Prepare for Command Block Wrapper - TU_ASSERT( prepare_cbw(rhport, p_msc), drv_len); - - return drv_len; -} - -static void proc_bot_reset(mscd_interface_t* p_msc) -{ - p_msc->stage = MSC_STAGE_CMD; - p_msc->total_len = 0; - p_msc->xferred_len = 0; - - p_msc->sense_key = 0; - p_msc->add_sense_code = 0; - p_msc->add_sense_qualifier = 0; -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - // nothing to do with DATA & ACK stage - if (stage != CONTROL_STAGE_SETUP) return true; - - mscd_interface_t* p_msc = &_mscd_itf; - - // Clear Endpoint Feature (stall) for recovery - if ( TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type && - TUSB_REQ_RCPT_ENDPOINT == request->bmRequestType_bit.recipient && - TUSB_REQ_CLEAR_FEATURE == request->bRequest && - TUSB_REQ_FEATURE_EDPT_HALT == request->wValue ) - { - uint8_t const ep_addr = tu_u16_low(request->wIndex); - - if ( p_msc->stage == MSC_STAGE_NEED_RESET ) - { - // reset recovery is required to recover from this stage - // Clear Stall request cannot resolve this -> continue to stall endpoint - usbd_edpt_stall(rhport, ep_addr); - } - else - { - if ( ep_addr == p_msc->ep_in ) - { - if ( p_msc->stage == MSC_STAGE_STATUS ) - { - // resume sending SCSI status if we are in this stage previously before stalled - TU_ASSERT( send_csw(rhport, p_msc) ); - } - } - else if ( ep_addr == p_msc->ep_out ) - { - if ( p_msc->stage == MSC_STAGE_CMD ) - { - // part of reset recovery (probably due to invalid CBW) -> prepare for new command - // Note: skip if already queued previously - if ( usbd_edpt_ready(rhport, p_msc->ep_out) ) - { - TU_ASSERT( prepare_cbw(rhport, p_msc) ); - } - } - } - } - - return true; - } - - // From this point only handle class request only - TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); - - switch ( request->bRequest ) - { - case MSC_REQ_RESET: - TU_LOG(MSC_DEBUG, " MSC BOT Reset\r\n"); - TU_VERIFY(request->wValue == 0 && request->wLength == 0); - - // driver state reset - proc_bot_reset(p_msc); - - tud_control_status(rhport, request); - break; - - case MSC_REQ_GET_MAX_LUN: - { - TU_LOG(MSC_DEBUG, " MSC Get Max Lun\r\n"); - TU_VERIFY(request->wValue == 0 && request->wLength == 1); - - uint8_t maxlun = 1; - if (tud_msc_get_maxlun_cb) maxlun = tud_msc_get_maxlun_cb(); - TU_VERIFY(maxlun); - - // MAX LUN is minus 1 by specs - maxlun--; - - tud_control_xfer(rhport, request, &maxlun, 1); - } - break; - - default: return false; // stall unsupported request - } - - return true; -} - -bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) -{ - (void) event; - - mscd_interface_t* p_msc = &_mscd_itf; - msc_cbw_t const * p_cbw = &p_msc->cbw; - msc_csw_t * p_csw = &p_msc->csw; - - switch (p_msc->stage) - { - case MSC_STAGE_CMD: - //------------- new CBW received -------------// - // Complete IN while waiting for CMD is usually Status of previous SCSI op, ignore it - if(ep_addr != p_msc->ep_out) return true; - - if ( !(xferred_bytes == sizeof(msc_cbw_t) && p_cbw->signature == MSC_CBW_SIGNATURE) ) - { - TU_LOG(MSC_DEBUG, " SCSI CBW is not valid\r\n"); - - // BOT 6.6.1 If CBW is not valid stall both endpoints until reset recovery - p_msc->stage = MSC_STAGE_NEED_RESET; - - // invalid CBW stall both endpoints - usbd_edpt_stall(rhport, p_msc->ep_in); - usbd_edpt_stall(rhport, p_msc->ep_out); - - return false; - } - - TU_LOG(MSC_DEBUG, " SCSI Command [Lun%u]: %s\r\n", p_cbw->lun, tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0])); - //TU_LOG_MEM(MSC_DEBUG, p_cbw, xferred_bytes, 2); - - p_csw->signature = MSC_CSW_SIGNATURE; - p_csw->tag = p_cbw->tag; - p_csw->data_residue = 0; - p_csw->status = MSC_CSW_STATUS_PASSED; - - /*------------- Parse command and prepare DATA -------------*/ - p_msc->stage = MSC_STAGE_DATA; - p_msc->total_len = p_cbw->total_bytes; - p_msc->xferred_len = 0; - - // Read10 or Write10 - if ( (SCSI_CMD_READ_10 == p_cbw->command[0]) || (SCSI_CMD_WRITE_10 == p_cbw->command[0]) ) - { - uint8_t const status = rdwr10_validate_cmd(p_cbw); - - if ( status != MSC_CSW_STATUS_PASSED) - { - fail_scsi_op(rhport, p_msc, status); - }else if ( p_cbw->total_bytes ) - { - if (SCSI_CMD_READ_10 == p_cbw->command[0]) - { - proc_read10_cmd(rhport, p_msc); - }else - { - proc_write10_cmd(rhport, p_msc); - } - }else - { - // no data transfer, only exist in complaint test suite - p_msc->stage = MSC_STAGE_STATUS; - } - } - else - { - // For other SCSI commands - // 1. OUT : queue transfer (invoke app callback after done) - // 2. IN & Zero: Process if is built-in, else Invoke app callback. Skip DATA if zero length - if ( (p_cbw->total_bytes > 0 ) && !is_data_in(p_cbw->dir) ) - { - if (p_cbw->total_bytes > sizeof(_mscd_buf)) - { - TU_LOG(MSC_DEBUG, " SCSI reject non READ10/WRITE10 with large data\r\n"); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); - }else - { - // Didn't check for case 9 (Ho > Dn), which requires examining scsi command first - // but it is OK to just receive data then responded with failed status - TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, (uint16_t) p_msc->total_len) ); - } - }else - { - // First process if it is a built-in commands - int32_t resplen = proc_builtin_scsi(p_cbw->lun, p_cbw->command, _mscd_buf, sizeof(_mscd_buf)); - - // Invoke user callback if not built-in - if ( (resplen < 0) && (p_msc->sense_key == 0) ) - { - resplen = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, (uint16_t) p_msc->total_len); - } - - if ( resplen < 0 ) - { - // unsupported command - TU_LOG(MSC_DEBUG, " SCSI unsupported or failed command\r\n"); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); - } - else if (resplen == 0) - { - if (p_cbw->total_bytes) - { - // 6.7 The 13 Cases: case 4 (Hi > Dn) - // TU_LOG(MSC_DEBUG, " SCSI case 4 (Hi > Dn): %lu\r\n", p_cbw->total_bytes); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); - }else - { - // case 1 Hn = Dn: all good - p_msc->stage = MSC_STAGE_STATUS; - } - } - else - { - if ( p_cbw->total_bytes == 0 ) - { - // 6.7 The 13 Cases: case 2 (Hn < Di) - // TU_LOG(MSC_DEBUG, " SCSI case 2 (Hn < Di): %lu\r\n", p_cbw->total_bytes); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); - }else - { - // cannot return more than host expect - p_msc->total_len = tu_min32((uint32_t) resplen, p_cbw->total_bytes); - TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, (uint16_t) p_msc->total_len) ); - } - } - } - } - break; - - case MSC_STAGE_DATA: - TU_LOG(MSC_DEBUG, " SCSI Data [Lun%u]\r\n", p_cbw->lun); - //TU_LOG_MEM(MSC_DEBUG, _mscd_buf, xferred_bytes, 2); - - if (SCSI_CMD_READ_10 == p_cbw->command[0]) - { - p_msc->xferred_len += xferred_bytes; - - if ( p_msc->xferred_len >= p_msc->total_len ) - { - // Data Stage is complete - p_msc->stage = MSC_STAGE_STATUS; - }else - { - proc_read10_cmd(rhport, p_msc); - } - } - else if (SCSI_CMD_WRITE_10 == p_cbw->command[0]) - { - proc_write10_new_data(rhport, p_msc, xferred_bytes); - } - else - { - p_msc->xferred_len += xferred_bytes; - - // OUT transfer, invoke callback if needed - if ( !is_data_in(p_cbw->dir) ) - { - int32_t cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, (uint16_t) p_msc->total_len); - - if ( cb_result < 0 ) - { - // unsupported command - TU_LOG(MSC_DEBUG, " SCSI unsupported command\r\n"); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); - }else - { - // TODO haven't implement this scenario any further yet - } - } - - if ( p_msc->xferred_len >= p_msc->total_len ) - { - // Data Stage is complete - p_msc->stage = MSC_STAGE_STATUS; - } - else - { - // This scenario with command that take more than one transfer is already rejected at Command stage - TU_BREAKPOINT(); - } - } - break; - - case MSC_STAGE_STATUS: - // processed immediately after this switch, supposedly to be empty - break; - - case MSC_STAGE_STATUS_SENT: - // Wait for the Status phase to complete - if( (ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t)) ) - { - TU_LOG(MSC_DEBUG, " SCSI Status [Lun%u] = %u\r\n", p_cbw->lun, p_csw->status); - // TU_LOG_MEM(MSC_DEBUG, p_csw, xferred_bytes, 2); - - // Invoke complete callback if defined - // Note: There is racing issue with samd51 + qspi flash testing with arduino - // if complete_cb() is invoked after queuing the status. - switch(p_cbw->command[0]) - { - case SCSI_CMD_READ_10: - if ( tud_msc_read10_complete_cb ) tud_msc_read10_complete_cb(p_cbw->lun); - break; - - case SCSI_CMD_WRITE_10: - if ( tud_msc_write10_complete_cb ) tud_msc_write10_complete_cb(p_cbw->lun); - break; - - default: - if ( tud_msc_scsi_complete_cb ) tud_msc_scsi_complete_cb(p_cbw->lun, p_cbw->command); - break; - } - - TU_ASSERT( prepare_cbw(rhport, p_msc) ); - }else - { - // Any xfer ended here is consider unknown error, ignore it - TU_LOG1(" Warning expect SCSI Status but received unknown data\r\n"); - } - break; - - default : break; - } - - if ( p_msc->stage == MSC_STAGE_STATUS ) - { - // skip status if epin is currently stalled, will do it when received Clear Stall request - if ( !usbd_edpt_stalled(rhport, p_msc->ep_in) ) - { - if ( (p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir) ) - { - // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status - // TU_LOG(MSC_DEBUG, " SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len); - usbd_edpt_stall(rhport, p_msc->ep_in); - }else - { - TU_ASSERT( send_csw(rhport, p_msc) ); - } - } - - #if TU_CHECK_MCU(OPT_MCU_CXD56) - // WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD. - // There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and - // hope everything will work - if ( usbd_edpt_stalled(rhport, p_msc->ep_in) ) - { - usbd_edpt_clear_stall(rhport, p_msc->ep_in); - send_csw(rhport, p_msc); - } - #endif - } - - return true; -} - -/*------------------------------------------------------------------*/ -/* SCSI Command Process - *------------------------------------------------------------------*/ - -// return response's length (copied to buffer). Negative if it is not an built-in command or indicate Failed status (CSW) -// In case of a failed status, sense key must be set for reason of failure -static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize) -{ - (void) bufsize; // TODO refractor later - int32_t resplen; - - mscd_interface_t* p_msc = &_mscd_itf; - - switch ( scsi_cmd[0] ) - { - case SCSI_CMD_TEST_UNIT_READY: - resplen = 0; - if ( !tud_msc_test_unit_ready_cb(lun) ) - { - // Failed status response - resplen = - 1; - - // set default sense if not set by callback - if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); - } - break; - - case SCSI_CMD_START_STOP_UNIT: - resplen = 0; - - if (tud_msc_start_stop_cb) - { - scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const *) scsi_cmd; - if ( !tud_msc_start_stop_cb(lun, start_stop->power_condition, start_stop->start, start_stop->load_eject) ) - { - // Failed status response - resplen = - 1; - - // set default sense if not set by callback - if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); - } - } - break; - - case SCSI_CMD_READ_CAPACITY_10: - { - uint32_t block_count; - uint32_t block_size; - uint16_t block_size_u16; - - tud_msc_capacity_cb(lun, &block_count, &block_size_u16); - block_size = (uint32_t) block_size_u16; - - // Invalid block size/count from callback, possibly unit is not ready - // stall this request, set sense key to NOT READY - if (block_count == 0 || block_size == 0) - { - resplen = -1; - - // set default sense if not set by callback - if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); - }else - { - scsi_read_capacity10_resp_t read_capa10; - - read_capa10.last_lba = tu_htonl(block_count-1); - read_capa10.block_size = tu_htonl(block_size); - - resplen = sizeof(read_capa10); - TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &read_capa10, (size_t) resplen)); - } - } - break; - - case SCSI_CMD_READ_FORMAT_CAPACITY: - { - scsi_read_format_capacity_data_t read_fmt_capa = - { - .list_length = 8, - .block_num = 0, - .descriptor_type = 2, // formatted media - .block_size_u16 = 0 - }; - - uint32_t block_count; - uint16_t block_size; - - tud_msc_capacity_cb(lun, &block_count, &block_size); - - // Invalid block size/count from callback, possibly unit is not ready - // stall this request, set sense key to NOT READY - if (block_count == 0 || block_size == 0) - { - resplen = -1; - - // set default sense if not set by callback - if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); - }else - { - read_fmt_capa.block_num = tu_htonl(block_count); - read_fmt_capa.block_size_u16 = tu_htons(block_size); - - resplen = sizeof(read_fmt_capa); - TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &read_fmt_capa, (size_t) resplen)); - } - } - break; - - case SCSI_CMD_INQUIRY: - { - scsi_inquiry_resp_t inquiry_rsp = - { - .is_removable = 1, - .version = 2, - .response_data_format = 2, - .additional_length = sizeof(scsi_inquiry_resp_t) - 5, - }; - - // vendor_id, product_id, product_rev is space padded string - memset(inquiry_rsp.vendor_id , ' ', sizeof(inquiry_rsp.vendor_id)); - memset(inquiry_rsp.product_id , ' ', sizeof(inquiry_rsp.product_id)); - memset(inquiry_rsp.product_rev, ' ', sizeof(inquiry_rsp.product_rev)); - - tud_msc_inquiry_cb(lun, inquiry_rsp.vendor_id, inquiry_rsp.product_id, inquiry_rsp.product_rev); - - resplen = sizeof(inquiry_rsp); - TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &inquiry_rsp, (size_t) resplen)); - } - break; - - case SCSI_CMD_MODE_SENSE_6: - { - scsi_mode_sense6_resp_t mode_resp = - { - .data_len = 3, - .medium_type = 0, - .write_protected = false, - .reserved = 0, - .block_descriptor_len = 0 // no block descriptor are included - }; - - bool writable = true; - if ( tud_msc_is_writable_cb ) - { - writable = tud_msc_is_writable_cb(lun); - } - - mode_resp.write_protected = !writable; - - resplen = sizeof(mode_resp); - TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &mode_resp, (size_t) resplen)); - } - break; - - case SCSI_CMD_REQUEST_SENSE: - { - scsi_sense_fixed_resp_t sense_rsp = - { - .response_code = 0x70, // current, fixed format - .valid = 1 - }; - - sense_rsp.add_sense_len = sizeof(scsi_sense_fixed_resp_t) - 8; - sense_rsp.sense_key = (uint8_t) (p_msc->sense_key & 0x0F); - sense_rsp.add_sense_code = p_msc->add_sense_code; - sense_rsp.add_sense_qualifier = p_msc->add_sense_qualifier; - - resplen = sizeof(sense_rsp); - TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &sense_rsp, (size_t) resplen)); - - // request sense callback could overwrite the sense data - if (tud_msc_request_sense_cb) - { - resplen = tud_msc_request_sense_cb(lun, buffer, (uint16_t) bufsize); - } - - // Clear sense data after copy - tud_msc_set_sense(lun, 0, 0, 0); - } - break; - - default: resplen = -1; break; - } - - return resplen; -} - -static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc) -{ - msc_cbw_t const * p_cbw = &p_msc->cbw; - - // block size already verified not zero - uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); - - // Adjust lba with transferred bytes - uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz); - - // remaining bytes capped at class buffer - int32_t nbytes = (int32_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len); - - // Application can consume smaller bytes - uint32_t const offset = p_msc->xferred_len % block_sz; - nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_buf, (uint32_t) nbytes); - - if ( nbytes < 0 ) - { - // negative means error -> endpoint is stalled & status in CSW set to failed - TU_LOG(MSC_DEBUG, " tud_msc_read10_cb() return -1\r\n"); - - // set sense - set_sense_medium_not_present(p_cbw->lun); - - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); - } - else if ( nbytes == 0 ) - { - // zero means not ready -> simulate an transfer complete so that this driver callback will fired again - dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false); - } - else - { - TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, (uint16_t) nbytes), ); - } -} - -static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc) -{ - msc_cbw_t const * p_cbw = &p_msc->cbw; - bool writable = true; - - if ( tud_msc_is_writable_cb ) - { - writable = tud_msc_is_writable_cb(p_cbw->lun); - } - - if ( !writable ) - { - // Not writable, complete this SCSI op with error - // Sense = Write protected - tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_DATA_PROTECT, 0x27, 0x00); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); - return; - } - - // remaining bytes capped at class buffer - uint16_t nbytes = (uint16_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len); - - // Write10 callback will be called later when usb transfer complete - TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, nbytes), ); -} - -// process new data arrived from WRITE10 -static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes) -{ - msc_cbw_t const * p_cbw = &p_msc->cbw; - - // block size already verified not zero - uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); - - // Adjust lba with transferred bytes - uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz); - - // Invoke callback to consume new data - uint32_t const offset = p_msc->xferred_len % block_sz; - int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_buf, xferred_bytes); - - if ( nbytes < 0 ) - { - // negative means error -> failed this scsi op - TU_LOG(MSC_DEBUG, " tud_msc_write10_cb() return -1\r\n"); - - // update actual byte before failed - p_msc->xferred_len += xferred_bytes; - - // Set sense - set_sense_medium_not_present(p_cbw->lun); - - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); - }else - { - // Application consume less than what we got (including zero) - if ( (uint32_t) nbytes < xferred_bytes ) - { - uint32_t const left_over = xferred_bytes - (uint32_t) nbytes; - if ( nbytes > 0 ) - { - p_msc->xferred_len += (uint16_t) nbytes; - memmove(_mscd_buf, _mscd_buf+nbytes, left_over); - } - - // simulate an transfer complete with adjusted parameters --> callback will be invoked with adjusted parameter - dcd_event_xfer_complete(rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false); - } - else - { - // Application consume all bytes in our buffer - p_msc->xferred_len += xferred_bytes; - - if ( p_msc->xferred_len >= p_msc->total_len ) - { - // Data Stage is complete - p_msc->stage = MSC_STAGE_STATUS; - }else - { - // prepare to receive more data from host - proc_write10_cmd(rhport, p_msc); - } - } - } -} - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.h b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.h deleted file mode 100644 index 72f95be0..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_device.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_MSC_DEVICE_H_ -#define _TUSB_MSC_DEVICE_H_ - -#include "common/tusb_common.h" -#include "msc.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Class Driver Configuration -//--------------------------------------------------------------------+ - -#if !defined(CFG_TUD_MSC_EP_BUFSIZE) & defined(CFG_TUD_MSC_BUFSIZE) - // TODO warn user to use new name later on - // #warning CFG_TUD_MSC_BUFSIZE is renamed to CFG_TUD_MSC_EP_BUFSIZE, please update to use the new name - #define CFG_TUD_MSC_EP_BUFSIZE CFG_TUD_MSC_BUFSIZE -#endif - -#ifndef CFG_TUD_MSC_EP_BUFSIZE - #error CFG_TUD_MSC_EP_BUFSIZE must be defined, value of a block size should work well, the more the better -#endif - -TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct"); - -//--------------------------------------------------------------------+ -// Application API -//--------------------------------------------------------------------+ - -// Set SCSI sense response -bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier); - -//--------------------------------------------------------------------+ -// Application Callbacks (WEAK is optional) -//--------------------------------------------------------------------+ - -// Invoked when received SCSI READ10 command -// - Address = lba * BLOCK_SIZE + offset -// - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. -// -// - Application fill the buffer (up to bufsize) with address contents and return number of read byte. If -// - read < bufsize : These bytes are transferred first and callback invoked again for remaining data. -// -// - read == 0 : Indicate application is not ready yet e.g disk I/O busy. -// Callback invoked again with the same parameters later on. -// -// - read < 0 : Indicate application error e.g invalid address. This request will be STALLed -// and return failed status in command status wrapper phase. -int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); - -// Invoked when received SCSI WRITE10 command -// - Address = lba * BLOCK_SIZE + offset -// - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. -// -// - Application write data from buffer to address contents (up to bufsize) and return number of written byte. If -// - write < bufsize : callback invoked again with remaining data later on. -// -// - write == 0 : Indicate application is not ready yet e.g disk I/O busy. -// Callback invoked again with the same parameters later on. -// -// - write < 0 : Indicate application error e.g invalid address. This request will be STALLed -// and return failed status in command status wrapper phase. -// -// TODO change buffer to const uint8_t* -int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize); - -// Invoked when received SCSI_CMD_INQUIRY -// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively -void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]); - -// Invoked when received Test Unit Ready command. -// return true allowing host to read/write this LUN e.g SD card inserted -bool tud_msc_test_unit_ready_cb(uint8_t lun); - -// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size -// Application update block count and block size -void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size); - -/** - * Invoked when received an SCSI command not in built-in list below. - * - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, TEST_UNIT_READY, START_STOP_UNIT, MODE_SENSE6, REQUEST_SENSE - * - READ10 and WRITE10 has their own callbacks - * - * \param[in] lun Logical unit number - * \param[in] scsi_cmd SCSI command contents which application must examine to response accordingly - * \param[out] buffer Buffer for SCSI Data Stage. - * - For INPUT: application must fill this with response. - * - For OUTPUT it holds the Data from host - * \param[in] bufsize Buffer's length. - * - * \return Actual bytes processed, can be zero for no-data command. - * \retval negative Indicate error e.g unsupported command, tinyusb will \b STALL the corresponding - * endpoint and return failed status in command status wrapper phase. - */ -int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize); - -/*------------- Optional callbacks -------------*/ - -// Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation -TU_ATTR_WEAK uint8_t tud_msc_get_maxlun_cb(void); - -// Invoked when received Start Stop Unit command -// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage -// - Start = 1 : active mode, if load_eject = 1 : load disk storage -TU_ATTR_WEAK bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject); - -// Invoked when received REQUEST_SENSE -TU_ATTR_WEAK int32_t tud_msc_request_sense_cb(uint8_t lun, void* buffer, uint16_t bufsize); - -// Invoked when Read10 command is complete -TU_ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun); - -// Invoke when Write10 command is complete, can be used to flush flash caching -TU_ATTR_WEAK void tud_msc_write10_complete_cb(uint8_t lun); - -// Invoked when command in tud_msc_scsi_cb is complete -TU_ATTR_WEAK void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16]); - -// Invoked to check if device is writable as part of SCSI WRITE10 -TU_ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void mscd_init (void); -void mscd_reset (uint8_t rhport); -uint16_t mscd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool mscd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * p_request); -bool mscd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_MSC_DEVICE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.c b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.c deleted file mode 100644 index 1b48813e..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.c +++ /dev/null @@ -1,525 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if CFG_TUH_ENABLED && CFG_TUH_MSC - -#include "host/usbh.h" -#include "host/usbh_classdriver.h" - -#include "msc_host.h" - -// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message -#define MSCH_DEBUG 2 - -#define TU_LOG_MSCH(...) TU_LOG(MSCH_DEBUG, __VA_ARGS__) - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -enum -{ - MSC_STAGE_IDLE = 0, - MSC_STAGE_CMD, - MSC_STAGE_DATA, - MSC_STAGE_STATUS, -}; - -typedef struct -{ - uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; - - uint8_t max_lun; - - volatile bool configured; // Receive SET_CONFIGURE - volatile bool mounted; // Enumeration is complete - - struct { - uint32_t block_size; - uint32_t block_count; - } capacity[CFG_TUH_MSC_MAXLUN]; - - //------------- SCSI -------------// - uint8_t stage; - void* buffer; - tuh_msc_complete_cb_t complete_cb; - uintptr_t complete_arg; - - CFG_TUH_MEM_ALIGN msc_cbw_t cbw; - CFG_TUH_MEM_ALIGN msc_csw_t csw; -}msch_interface_t; - -CFG_TUH_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUH_DEVICE_MAX]; - -// buffer used to read scsi information when mounted -// largest response data currently is inquiry TODO Inquiry is not part of enum anymore -CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN -static uint8_t _msch_buffer[sizeof(scsi_inquiry_resp_t)]; - -TU_ATTR_ALWAYS_INLINE -static inline msch_interface_t* get_itf(uint8_t dev_addr) -{ - return &_msch_itf[dev_addr-1]; -} - -//--------------------------------------------------------------------+ -// PUBLIC API -//--------------------------------------------------------------------+ -uint8_t tuh_msc_get_maxlun(uint8_t dev_addr) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - return p_msc->max_lun; -} - -uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - return p_msc->capacity[lun].block_count; -} - -uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - return p_msc->capacity[lun].block_size; -} - -bool tuh_msc_mounted(uint8_t dev_addr) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - return p_msc->mounted; -} - -bool tuh_msc_ready(uint8_t dev_addr) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - return p_msc->mounted && !usbh_edpt_busy(dev_addr, p_msc->ep_in); -} - -//--------------------------------------------------------------------+ -// PUBLIC API: SCSI COMMAND -//--------------------------------------------------------------------+ -static inline void cbw_init(msc_cbw_t *cbw, uint8_t lun) -{ - tu_memclr(cbw, sizeof(msc_cbw_t)); - cbw->signature = MSC_CBW_SIGNATURE; - cbw->tag = 0x54555342; // TUSB - cbw->lun = lun; -} - -bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - TU_VERIFY(p_msc->configured); - - // TODO claim endpoint - - p_msc->cbw = *cbw; - p_msc->stage = MSC_STAGE_CMD; - p_msc->buffer = data; - p_msc->complete_cb = complete_cb; - p_msc->complete_arg = arg; - - TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t))); - - return true; -} - -bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - TU_VERIFY(p_msc->configured); - - msc_cbw_t cbw; - cbw_init(&cbw, lun); - - cbw.total_bytes = sizeof(scsi_read_capacity10_resp_t); - cbw.dir = TUSB_DIR_IN_MASK; - cbw.cmd_len = sizeof(scsi_read_capacity10_t); - cbw.command[0] = SCSI_CMD_READ_CAPACITY_10; - - return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg); -} - -bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - TU_VERIFY(p_msc->mounted); - - msc_cbw_t cbw; - cbw_init(&cbw, lun); - - cbw.total_bytes = sizeof(scsi_inquiry_resp_t); - cbw.dir = TUSB_DIR_IN_MASK; - cbw.cmd_len = sizeof(scsi_inquiry_t); - - scsi_inquiry_t const cmd_inquiry = - { - .cmd_code = SCSI_CMD_INQUIRY, - .alloc_length = sizeof(scsi_inquiry_resp_t) - }; - memcpy(cbw.command, &cmd_inquiry, cbw.cmd_len); - - return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg); -} - -bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - TU_VERIFY(p_msc->configured); - - msc_cbw_t cbw; - cbw_init(&cbw, lun); - - cbw.total_bytes = 0; - cbw.dir = TUSB_DIR_OUT; - cbw.cmd_len = sizeof(scsi_test_unit_ready_t); - cbw.command[0] = SCSI_CMD_TEST_UNIT_READY; - cbw.command[1] = lun; // according to wiki TODO need verification - - return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb, arg); -} - -bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ - msc_cbw_t cbw; - cbw_init(&cbw, lun); - - cbw.total_bytes = 18; // TODO sense response - cbw.dir = TUSB_DIR_IN_MASK; - cbw.cmd_len = sizeof(scsi_request_sense_t); - - scsi_request_sense_t const cmd_request_sense = - { - .cmd_code = SCSI_CMD_REQUEST_SENSE, - .alloc_length = 18 - }; - - memcpy(cbw.command, &cmd_request_sense, cbw.cmd_len); - - return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg); -} - -bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - TU_VERIFY(p_msc->mounted); - - msc_cbw_t cbw; - cbw_init(&cbw, lun); - - cbw.total_bytes = block_count*p_msc->capacity[lun].block_size; - cbw.dir = TUSB_DIR_IN_MASK; - cbw.cmd_len = sizeof(scsi_read10_t); - - scsi_read10_t const cmd_read10 = - { - .cmd_code = SCSI_CMD_READ_10, - .lba = tu_htonl(lba), - .block_count = tu_htons(block_count) - }; - - memcpy(cbw.command, &cmd_read10, cbw.cmd_len); - - return tuh_msc_scsi_command(dev_addr, &cbw, buffer, complete_cb, arg); -} - -bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - TU_VERIFY(p_msc->mounted); - - msc_cbw_t cbw; - cbw_init(&cbw, lun); - - cbw.total_bytes = block_count*p_msc->capacity[lun].block_size; - cbw.dir = TUSB_DIR_OUT; - cbw.cmd_len = sizeof(scsi_write10_t); - - scsi_write10_t const cmd_write10 = - { - .cmd_code = SCSI_CMD_WRITE_10, - .lba = tu_htonl(lba), - .block_count = tu_htons(block_count) - }; - - memcpy(cbw.command, &cmd_write10, cbw.cmd_len); - - return tuh_msc_scsi_command(dev_addr, &cbw, (void*)(uintptr_t) buffer, complete_cb, arg); -} - -#if 0 -// MSC interface Reset (not used now) -bool tuh_msc_reset(uint8_t dev_addr) -{ - tusb_control_request_t const new_request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = MSC_REQ_RESET, - .wValue = 0, - .wIndex = p_msc->itf_num, - .wLength = 0 - }; - TU_ASSERT( usbh_control_xfer( dev_addr, &new_request, NULL ) ); -} -#endif - -//--------------------------------------------------------------------+ -// CLASS-USBH API -//--------------------------------------------------------------------+ -void msch_init(void) -{ - tu_memclr(_msch_itf, sizeof(_msch_itf)); -} - -void msch_close(uint8_t dev_addr) -{ - TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); - - msch_interface_t* p_msc = get_itf(dev_addr); - - // invoke Application Callback - if (p_msc->mounted && tuh_msc_umount_cb) tuh_msc_umount_cb(dev_addr); - - tu_memclr(p_msc, sizeof(msch_interface_t)); -} - -bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - msc_cbw_t const * cbw = &p_msc->cbw; - msc_csw_t * csw = &p_msc->csw; - - switch (p_msc->stage) - { - case MSC_STAGE_CMD: - // Must be Command Block - TU_ASSERT(ep_addr == p_msc->ep_out && event == XFER_RESULT_SUCCESS && xferred_bytes == sizeof(msc_cbw_t)); - - if ( cbw->total_bytes && p_msc->buffer ) - { - // Data stage if any - p_msc->stage = MSC_STAGE_DATA; - - uint8_t const ep_data = (cbw->dir & TUSB_DIR_IN_MASK) ? p_msc->ep_in : p_msc->ep_out; - TU_ASSERT(usbh_edpt_xfer(dev_addr, ep_data, p_msc->buffer, (uint16_t) cbw->total_bytes)); - }else - { - // Status stage - p_msc->stage = MSC_STAGE_STATUS; - TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t))); - } - break; - - case MSC_STAGE_DATA: - // Status stage - p_msc->stage = MSC_STAGE_STATUS; - TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t))); - break; - - case MSC_STAGE_STATUS: - // SCSI op is complete - p_msc->stage = MSC_STAGE_IDLE; - - if (p_msc->complete_cb) - { - tuh_msc_complete_data_t const cb_data = - { - .cbw = cbw, - .csw = csw, - .scsi_data = p_msc->buffer, - .user_arg = p_msc->complete_arg - }; - p_msc->complete_cb(dev_addr, &cb_data); - } - break; - - // unknown state - default: break; - } - - return true; -} - -//--------------------------------------------------------------------+ -// MSC Enumeration -//--------------------------------------------------------------------+ - -static void config_get_maxlun_complete (tuh_xfer_t* xfer); -static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data); -static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); -static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); - -bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) -{ - (void) rhport; - TU_VERIFY (MSC_SUBCLASS_SCSI == desc_itf->bInterfaceSubClass && - MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol); - - // msc driver length is fixed - uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); - TU_ASSERT(drv_len <= max_len); - - msch_interface_t* p_msc = get_itf(dev_addr); - tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(desc_itf); - - for(uint32_t i=0; i<2; i++) - { - TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer); - TU_ASSERT(tuh_edpt_open(dev_addr, ep_desc)); - - if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN ) - { - p_msc->ep_in = ep_desc->bEndpointAddress; - }else - { - p_msc->ep_out = ep_desc->bEndpointAddress; - } - - ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(ep_desc); - } - - p_msc->itf_num = desc_itf->bInterfaceNumber; - - return true; -} - -bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - TU_ASSERT(p_msc->itf_num == itf_num); - - p_msc->configured = true; - - //------------- Get Max Lun -------------// - TU_LOG_MSCH("MSC Get Max Lun\r\n"); - tusb_control_request_t const request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_IN - }, - .bRequest = MSC_REQ_GET_MAX_LUN, - .wValue = 0, - .wIndex = itf_num, - .wLength = 1 - }; - - tuh_xfer_t xfer = - { - .daddr = dev_addr, - .ep_addr = 0, - .setup = &request, - .buffer = &p_msc->max_lun, - .complete_cb = config_get_maxlun_complete, - .user_data = 0 - }; - TU_ASSERT(tuh_control_xfer(&xfer)); - - return true; -} - -static void config_get_maxlun_complete (tuh_xfer_t* xfer) -{ - uint8_t const daddr = xfer->daddr; - msch_interface_t* p_msc = get_itf(daddr); - - // STALL means zero - p_msc->max_lun = (XFER_RESULT_SUCCESS == xfer->result) ? _msch_buffer[0] : 0; - p_msc->max_lun++; // MAX LUN is minus 1 by specs - - // TODO multiple LUN support - TU_LOG_MSCH("SCSI Test Unit Ready\r\n"); - uint8_t const lun = 0; - tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete, 0); -} - -static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) -{ - msc_cbw_t const* cbw = cb_data->cbw; - msc_csw_t const* csw = cb_data->csw; - - if (csw->status == 0) - { - // Unit is ready, read its capacity - TU_LOG_MSCH("SCSI Read Capacity\r\n"); - tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete, 0); - }else - { - // Note: During enumeration, some device fails Test Unit Ready and require a few retries - // with Request Sense to start working !! - // TODO limit number of retries - TU_LOG_MSCH("SCSI Request Sense\r\n"); - TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, _msch_buffer, config_request_sense_complete, 0)); - } - - return true; -} - -static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) -{ - msc_cbw_t const* cbw = cb_data->cbw; - msc_csw_t const* csw = cb_data->csw; - - TU_ASSERT(csw->status == 0); - TU_ASSERT(tuh_msc_test_unit_ready(dev_addr, cbw->lun, config_test_unit_ready_complete, 0)); - return true; -} - -static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) -{ - msc_cbw_t const* cbw = cb_data->cbw; - msc_csw_t const* csw = cb_data->csw; - - TU_ASSERT(csw->status == 0); - - msch_interface_t* p_msc = get_itf(dev_addr); - - // Capacity response field: Block size and Last LBA are both Big-Endian - scsi_read_capacity10_resp_t* resp = (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer); - p_msc->capacity[cbw->lun].block_count = tu_ntohl(resp->last_lba) + 1; - p_msc->capacity[cbw->lun].block_size = tu_ntohl(resp->block_size); - - // Mark enumeration is complete - p_msc->mounted = true; - if (tuh_msc_mount_cb) tuh_msc_mount_cb(dev_addr); - - // notify usbh that driver enumeration is complete - usbh_driver_set_config_complete(dev_addr, p_msc->itf_num); - - return true; -} - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.h b/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.h deleted file mode 100644 index 6c0e5c9d..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/msc/msc_host.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_MSC_HOST_H_ -#define _TUSB_MSC_HOST_H_ - -#include "msc.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Class Driver Configuration -//--------------------------------------------------------------------+ - -#ifndef CFG_TUH_MSC_MAXLUN -#define CFG_TUH_MSC_MAXLUN 4 -#endif - -typedef struct { - msc_cbw_t const* cbw; // SCSI command - msc_csw_t const* csw; // SCSI status - void* scsi_data; // SCSI Data - uintptr_t user_arg; // user argument -}tuh_msc_complete_data_t; - -typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); - -//--------------------------------------------------------------------+ -// Application API -//--------------------------------------------------------------------+ - -// Check if device supports MassStorage interface. -// This function true after tuh_msc_mounted_cb() and false after tuh_msc_unmounted_cb() -bool tuh_msc_mounted(uint8_t dev_addr); - -// Check if the interface is currently ready or busy transferring data -bool tuh_msc_ready(uint8_t dev_addr); - -// Get Max Lun -uint8_t tuh_msc_get_maxlun(uint8_t dev_addr); - -// Get number of block -uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun); - -// Get block size in bytes -uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun); - -// Perform a full SCSI command (cbw, data, csw) in non-blocking manner. -// Complete callback is invoked when SCSI op is complete. -// return true if success, false if there is already pending operation. -bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); - -// Perform SCSI Inquiry command -// Complete callback is invoked when SCSI op is complete. -bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); - -// Perform SCSI Test Unit Ready command -// Complete callback is invoked when SCSI op is complete. -bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); - -// Perform SCSI Request Sense 10 command -// Complete callback is invoked when SCSI op is complete. -bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); - -// Perform SCSI Read 10 command. Read n blocks starting from LBA to buffer -// Complete callback is invoked when SCSI op is complete. -bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); - -// Perform SCSI Write 10 command. Write n blocks starting from LBA to device -// Complete callback is invoked when SCSI op is complete. -bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); - -// Perform SCSI Read Capacity 10 command -// Complete callback is invoked when SCSI op is complete. -// Note: during enumeration, host stack already carried out this request. Application can retrieve capacity by -// simply call tuh_msc_get_block_count() and tuh_msc_get_block_size() -bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); - -//------------- Application Callback -------------// - -// Invoked when a device with MassStorage interface is mounted -TU_ATTR_WEAK void tuh_msc_mount_cb(uint8_t dev_addr); - -// Invoked when a device with MassStorage interface is unmounted -TU_ATTR_WEAK void tuh_msc_umount_cb(uint8_t dev_addr); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ - -void msch_init (void); -bool msch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); -bool msch_set_config (uint8_t dev_addr, uint8_t itf_num); -void msch_close (uint8_t dev_addr); -bool msch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_MSC_HOST_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/net/ecm_rndis_device.c b/test-devices/composite-stm32/lib/tinyusb/class/net/ecm_rndis_device.c deleted file mode 100644 index 8ac7cbd0..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/net/ecm_rndis_device.c +++ /dev/null @@ -1,450 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Peter Lawrence - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if ( CFG_TUD_ENABLED && CFG_TUD_ECM_RNDIS ) - -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "net_device.h" -#include "rndis_protocol.h" - -void rndis_class_set_handler(uint8_t *data, int size); /* found in ./misc/networking/rndis_reports.c */ - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -typedef struct -{ - uint8_t itf_num; // Index number of Management Interface, +1 for Data Interface - uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active - - uint8_t ep_notif; - uint8_t ep_in; - uint8_t ep_out; - - bool ecm_mode; - - // Endpoint descriptor use to open/close when receiving SetInterface - // TODO since configuration descriptor may not be long-lived memory, we should - // keep a copy of endpoint attribute instead - uint8_t const * ecm_desc_epdata; - -} netd_interface_t; - -#define CFG_TUD_NET_PACKET_PREFIX_LEN sizeof(rndis_data_packet_t) -#define CFG_TUD_NET_PACKET_SUFFIX_LEN 0 - -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static -uint8_t received[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; - -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static -uint8_t transmitted[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; - -struct ecm_notify_struct -{ - tusb_control_request_t header; - uint32_t downlink, uplink; -}; - -tu_static const struct ecm_notify_struct ecm_notify_nc = -{ - .header = { - .bmRequestType = 0xA1, - .bRequest = 0 /* NETWORK_CONNECTION aka NetworkConnection */, - .wValue = 1 /* Connected */, - .wLength = 0, - }, -}; - -tu_static const struct ecm_notify_struct ecm_notify_csc = -{ - .header = { - .bmRequestType = 0xA1, - .bRequest = 0x2A /* CONNECTION_SPEED_CHANGE aka ConnectionSpeedChange */, - .wLength = 8, - }, - .downlink = 9728000, - .uplink = 9728000, -}; - -// TODO remove CFG_TUSB_MEM_SECTION, control internal buffer is already in this special section -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static union -{ - uint8_t rndis_buf[120]; - struct ecm_notify_struct ecm_buf; -} notify; - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -// TODO remove CFG_TUSB_MEM_SECTION -CFG_TUSB_MEM_SECTION tu_static netd_interface_t _netd_itf; - -tu_static bool can_xmit; - -void tud_network_recv_renew(void) -{ - usbd_edpt_xfer(0, _netd_itf.ep_out, received, sizeof(received)); -} - -static void do_in_xfer(uint8_t *buf, uint16_t len) -{ - can_xmit = false; - usbd_edpt_xfer(0, _netd_itf.ep_in, buf, len); -} - -void netd_report(uint8_t *buf, uint16_t len) -{ - uint8_t const rhport = 0; - - // skip if previous report not yet acknowledged by host - if ( usbd_edpt_busy(rhport, _netd_itf.ep_notif) ) return; - usbd_edpt_xfer(rhport, _netd_itf.ep_notif, buf, len); -} - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void netd_init(void) -{ - tu_memclr(&_netd_itf, sizeof(_netd_itf)); -} - -void netd_reset(uint8_t rhport) -{ - (void) rhport; - - netd_init(); -} - -uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ - bool const is_rndis = (TUD_RNDIS_ITF_CLASS == itf_desc->bInterfaceClass && - TUD_RNDIS_ITF_SUBCLASS == itf_desc->bInterfaceSubClass && - TUD_RNDIS_ITF_PROTOCOL == itf_desc->bInterfaceProtocol); - - bool const is_ecm = (TUSB_CLASS_CDC == itf_desc->bInterfaceClass && - CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL == itf_desc->bInterfaceSubClass && - 0x00 == itf_desc->bInterfaceProtocol); - - TU_VERIFY(is_rndis || is_ecm, 0); - - // confirm interface hasn't already been allocated - TU_ASSERT(0 == _netd_itf.ep_notif, 0); - - // sanity check the descriptor - _netd_itf.ecm_mode = is_ecm; - - //------------- Management Interface -------------// - _netd_itf.itf_num = itf_desc->bInterfaceNumber; - - uint16_t drv_len = sizeof(tusb_desc_interface_t); - uint8_t const * p_desc = tu_desc_next( itf_desc ); - - // Communication Functional Descriptors - while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) - { - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - // notification endpoint (if any) - if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) - { - TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 ); - - _netd_itf.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; - - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - //------------- Data Interface -------------// - // - RNDIS Data followed immediately by a pair of endpoints - // - CDC-ECM data interface has 2 alternate settings - // - 0 : zero endpoints for inactive (default) - // - 1 : IN & OUT endpoints for active networking - TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); - - do - { - tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc; - TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass, 0); - - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - }while( _netd_itf.ecm_mode && (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (drv_len <= max_len) ); - - // Pair of endpoints - TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0); - - if ( _netd_itf.ecm_mode ) - { - // ECM by default is in-active, save the endpoint attribute - // to open later when received setInterface - _netd_itf.ecm_desc_epdata = p_desc; - }else - { - // Open endpoint pair for RNDIS - TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in), 0 ); - - tud_network_init_cb(); - - // we are ready to transmit a packet - can_xmit = true; - - // prepare for incoming packets - tud_network_recv_renew(); - } - - drv_len += 2*sizeof(tusb_desc_endpoint_t); - - return drv_len; -} - -static void ecm_report(bool nc) -{ - notify.ecm_buf = (nc) ? ecm_notify_nc : ecm_notify_csc; - notify.ecm_buf.header.wIndex = _netd_itf.itf_num; - netd_report((uint8_t *)¬ify.ecm_buf, (nc) ? sizeof(notify.ecm_buf.header) : sizeof(notify.ecm_buf)); -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - if ( stage == CONTROL_STAGE_SETUP ) - { - switch ( request->bmRequestType_bit.type ) - { - case TUSB_REQ_TYPE_STANDARD: - switch ( request->bRequest ) - { - case TUSB_REQ_GET_INTERFACE: - { - uint8_t const req_itfnum = (uint8_t) request->wIndex; - TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum); - - tud_control_xfer(rhport, request, &_netd_itf.itf_data_alt, 1); - } - break; - - case TUSB_REQ_SET_INTERFACE: - { - uint8_t const req_itfnum = (uint8_t) request->wIndex; - uint8_t const req_alt = (uint8_t) request->wValue; - - // Only valid for Data Interface with Alternate is either 0 or 1 - TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum && req_alt < 2); - - // ACM-ECM only: qequest to enable/disable network activities - TU_VERIFY(_netd_itf.ecm_mode); - - _netd_itf.itf_data_alt = req_alt; - - if ( _netd_itf.itf_data_alt ) - { - // TODO since we don't actually close endpoint - // hack here to not re-open it - if ( _netd_itf.ep_in == 0 && _netd_itf.ep_out == 0 ) - { - TU_ASSERT(_netd_itf.ecm_desc_epdata); - TU_ASSERT( usbd_open_edpt_pair(rhport, _netd_itf.ecm_desc_epdata, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in) ); - - // TODO should be merge with RNDIS's after endpoint opened - // Also should have opposite callback for application to disable network !! - tud_network_init_cb(); - can_xmit = true; // we are ready to transmit a packet - tud_network_recv_renew(); // prepare for incoming packets - } - }else - { - // TODO close the endpoint pair - // For now pretend that we did, this should have no harm since host won't try to - // communicate with the endpoints again - // _netd_itf.ep_in = _netd_itf.ep_out = 0 - } - - tud_control_status(rhport, request); - } - break; - - // unsupported request - default: return false; - } - break; - - case TUSB_REQ_TYPE_CLASS: - TU_VERIFY (_netd_itf.itf_num == request->wIndex); - - if (_netd_itf.ecm_mode) - { - /* the only required CDC-ECM Management Element Request is SetEthernetPacketFilter */ - if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest) - { - tud_control_xfer(rhport, request, NULL, 0); - ecm_report(true); - } - } - else - { - if (request->bmRequestType_bit.direction == TUSB_DIR_IN) - { - rndis_generic_msg_t *rndis_msg = (rndis_generic_msg_t *) ((void*) notify.rndis_buf); - uint32_t msglen = tu_le32toh(rndis_msg->MessageLength); - TU_ASSERT(msglen <= sizeof(notify.rndis_buf)); - tud_control_xfer(rhport, request, notify.rndis_buf, (uint16_t) msglen); - } - else - { - tud_control_xfer(rhport, request, notify.rndis_buf, (uint16_t) sizeof(notify.rndis_buf)); - } - } - break; - - // unsupported request - default: return false; - } - } - else if ( stage == CONTROL_STAGE_DATA ) - { - // Handle RNDIS class control OUT only - if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && - request->bmRequestType_bit.direction == TUSB_DIR_OUT && - _netd_itf.itf_num == request->wIndex) - { - if ( !_netd_itf.ecm_mode ) - { - rndis_class_set_handler(notify.rndis_buf, request->wLength); - } - } - } - - return true; -} - -static void handle_incoming_packet(uint32_t len) -{ - uint8_t *pnt = received; - uint32_t size = 0; - - if (_netd_itf.ecm_mode) - { - size = len; - } - else - { - rndis_data_packet_t *r = (rndis_data_packet_t *) ((void*) pnt); - if (len >= sizeof(rndis_data_packet_t)) - if ( (r->MessageType == REMOTE_NDIS_PACKET_MSG) && (r->MessageLength <= len)) - if ( (r->DataOffset + offsetof(rndis_data_packet_t, DataOffset) + r->DataLength) <= len) - { - pnt = &received[r->DataOffset + offsetof(rndis_data_packet_t, DataOffset)]; - size = r->DataLength; - } - } - - if (!tud_network_recv_cb(pnt, (uint16_t) size)) - { - /* if a buffer was never handled by user code, we must renew on the user's behalf */ - tud_network_recv_renew(); - } -} - -bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void) rhport; - (void) result; - - /* new packet received */ - if ( ep_addr == _netd_itf.ep_out ) - { - handle_incoming_packet(xferred_bytes); - } - - /* data transmission finished */ - if ( ep_addr == _netd_itf.ep_in ) - { - /* TinyUSB requires the class driver to implement ZLP (since ZLP usage is class-specific) */ - - if ( xferred_bytes && (0 == (xferred_bytes % CFG_TUD_NET_ENDPOINT_SIZE)) ) - { - do_in_xfer(NULL, 0); /* a ZLP is needed */ - } - else - { - /* we're finally finished */ - can_xmit = true; - } - } - - if ( _netd_itf.ecm_mode && (ep_addr == _netd_itf.ep_notif) ) - { - if (sizeof(notify.ecm_buf.header) == xferred_bytes) ecm_report(false); - } - - return true; -} - -bool tud_network_can_xmit(uint16_t size) -{ - (void)size; - - return can_xmit; -} - -void tud_network_xmit(void *ref, uint16_t arg) -{ - uint8_t *data; - uint16_t len; - - if (!can_xmit) - return; - - len = (_netd_itf.ecm_mode) ? 0 : CFG_TUD_NET_PACKET_PREFIX_LEN; - data = transmitted + len; - - len += tud_network_xmit_cb(data, ref, arg); - - if (!_netd_itf.ecm_mode) - { - rndis_data_packet_t *hdr = (rndis_data_packet_t *) ((void*) transmitted); - memset(hdr, 0, sizeof(rndis_data_packet_t)); - hdr->MessageType = REMOTE_NDIS_PACKET_MSG; - hdr->MessageLength = len; - hdr->DataOffset = sizeof(rndis_data_packet_t) - offsetof(rndis_data_packet_t, DataOffset); - hdr->DataLength = len - sizeof(rndis_data_packet_t); - } - - do_in_xfer(transmitted, len); -} - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/net/ncm.h b/test-devices/composite-stm32/lib/tinyusb/class/net/ncm.h deleted file mode 100644 index 96ba11fb..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/net/ncm.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - - -#ifndef _TUSB_NCM_H_ -#define _TUSB_NCM_H_ - -#include "common/tusb_common.h" - -#ifdef __cplusplus - extern "C" { -#endif - -// Table 4.3 Data Class Interface Protocol Codes -typedef enum -{ - NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK = 0x01 -} ncm_data_interface_protocol_code_t; - - -// Table 6.2 Class-Specific Request Codes for Network Control Model subclass -typedef enum -{ - NCM_SET_ETHERNET_MULTICAST_FILTERS = 0x40, - NCM_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x41, - NCM_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x42, - NCM_SET_ETHERNET_PACKET_FILTER = 0x43, - NCM_GET_ETHERNET_STATISTIC = 0x44, - NCM_GET_NTB_PARAMETERS = 0x80, - NCM_GET_NET_ADDRESS = 0x81, - NCM_SET_NET_ADDRESS = 0x82, - NCM_GET_NTB_FORMAT = 0x83, - NCM_SET_NTB_FORMAT = 0x84, - NCM_GET_NTB_INPUT_SIZE = 0x85, - NCM_SET_NTB_INPUT_SIZE = 0x86, - NCM_GET_MAX_DATAGRAM_SIZE = 0x87, - NCM_SET_MAX_DATAGRAM_SIZE = 0x88, - NCM_GET_CRC_MODE = 0x89, - NCM_SET_CRC_MODE = 0x8A, -} ncm_request_code_t; - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/net/ncm_device.c b/test-devices/composite-stm32/lib/tinyusb/class/net/ncm_device.c deleted file mode 100644 index 9e958024..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/net/ncm_device.c +++ /dev/null @@ -1,511 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Jacob Berg Potter - * Copyright (c) 2020 Peter Lawrence - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if ( CFG_TUD_ENABLED && CFG_TUD_NCM ) - -#include "device/usbd.h" -#include "device/usbd_pvt.h" -#include "net_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -#define NTH16_SIGNATURE 0x484D434E -#define NDP16_SIGNATURE_NCM0 0x304D434E -#define NDP16_SIGNATURE_NCM1 0x314D434E - -typedef struct TU_ATTR_PACKED -{ - uint16_t wLength; - uint16_t bmNtbFormatsSupported; - uint32_t dwNtbInMaxSize; - uint16_t wNdbInDivisor; - uint16_t wNdbInPayloadRemainder; - uint16_t wNdbInAlignment; - uint16_t wReserved; - uint32_t dwNtbOutMaxSize; - uint16_t wNdbOutDivisor; - uint16_t wNdbOutPayloadRemainder; - uint16_t wNdbOutAlignment; - uint16_t wNtbOutMaxDatagrams; -} ntb_parameters_t; - -typedef struct TU_ATTR_PACKED -{ - uint32_t dwSignature; - uint16_t wHeaderLength; - uint16_t wSequence; - uint16_t wBlockLength; - uint16_t wNdpIndex; -} nth16_t; - -typedef struct TU_ATTR_PACKED -{ - uint16_t wDatagramIndex; - uint16_t wDatagramLength; -} ndp16_datagram_t; - -typedef struct TU_ATTR_PACKED -{ - uint32_t dwSignature; - uint16_t wLength; - uint16_t wNextNdpIndex; - ndp16_datagram_t datagram[]; -} ndp16_t; - -typedef union TU_ATTR_PACKED { - struct { - nth16_t nth; - ndp16_t ndp; - }; - uint8_t data[CFG_TUD_NCM_IN_NTB_MAX_SIZE]; -} transmit_ntb_t; - -struct ecm_notify_struct -{ - tusb_control_request_t header; - uint32_t downlink, uplink; -}; - -typedef struct -{ - uint8_t itf_num; // Index number of Management Interface, +1 for Data Interface - uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active - - uint8_t ep_notif; - uint8_t ep_in; - uint8_t ep_out; - - const ndp16_t *ndp; - uint8_t num_datagrams, current_datagram_index; - - enum { - REPORT_SPEED, - REPORT_CONNECTED, - REPORT_DONE - } report_state; - bool report_pending; - - uint8_t current_ntb; // Index in transmit_ntb[] that is currently being filled with datagrams - uint8_t datagram_count; // Number of datagrams in transmit_ntb[current_ntb] - uint16_t next_datagram_offset; // Offset in transmit_ntb[current_ntb].data to place the next datagram - uint16_t ntb_in_size; // Maximum size of transmitted (IN to host) NTBs; initially CFG_TUD_NCM_IN_NTB_MAX_SIZE - uint8_t max_datagrams_per_ntb; // Maximum number of datagrams per NTB; initially CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB - - uint16_t nth_sequence; // Sequence number counter for transmitted NTBs - - bool transferring; - -} ncm_interface_t; - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ - -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static const ntb_parameters_t ntb_parameters = { - .wLength = sizeof(ntb_parameters_t), - .bmNtbFormatsSupported = 0x01, - .dwNtbInMaxSize = CFG_TUD_NCM_IN_NTB_MAX_SIZE, - .wNdbInDivisor = 4, - .wNdbInPayloadRemainder = 0, - .wNdbInAlignment = CFG_TUD_NCM_ALIGNMENT, - .wReserved = 0, - .dwNtbOutMaxSize = CFG_TUD_NCM_OUT_NTB_MAX_SIZE, - .wNdbOutDivisor = 4, - .wNdbOutPayloadRemainder = 0, - .wNdbOutAlignment = CFG_TUD_NCM_ALIGNMENT, - .wNtbOutMaxDatagrams = 0 -}; - -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static transmit_ntb_t transmit_ntb[2]; - -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t receive_ntb[CFG_TUD_NCM_OUT_NTB_MAX_SIZE]; - -tu_static ncm_interface_t ncm_interface; - -/* - * Set up the NTB state in ncm_interface to be ready to add datagrams. - */ -static void ncm_prepare_for_tx(void) { - ncm_interface.datagram_count = 0; - // datagrams start after all the headers - ncm_interface.next_datagram_offset = sizeof(nth16_t) + sizeof(ndp16_t) - + ((CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB + 1) * sizeof(ndp16_datagram_t)); -} - -/* - * If not already transmitting, start sending the current NTB to the host and swap buffers - * to start filling the other one with datagrams. - */ -static void ncm_start_tx(void) { - if (ncm_interface.transferring) { - return; - } - - transmit_ntb_t *ntb = &transmit_ntb[ncm_interface.current_ntb]; - size_t ntb_length = ncm_interface.next_datagram_offset; - - // Fill in NTB header - ntb->nth.dwSignature = NTH16_SIGNATURE; - ntb->nth.wHeaderLength = sizeof(nth16_t); - ntb->nth.wSequence = ncm_interface.nth_sequence++; - ntb->nth.wBlockLength = ntb_length; - ntb->nth.wNdpIndex = sizeof(nth16_t); - - // Fill in NDP16 header and terminator - ntb->ndp.dwSignature = NDP16_SIGNATURE_NCM0; - ntb->ndp.wLength = sizeof(ndp16_t) + (ncm_interface.datagram_count + 1) * sizeof(ndp16_datagram_t); - ntb->ndp.wNextNdpIndex = 0; - ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramIndex = 0; - ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramLength = 0; - - // Kick off an endpoint transfer - usbd_edpt_xfer(0, ncm_interface.ep_in, ntb->data, ntb_length); - ncm_interface.transferring = true; - - // Swap to the other NTB and clear it out - ncm_interface.current_ntb = 1 - ncm_interface.current_ntb; - ncm_prepare_for_tx(); -} - -tu_static struct ecm_notify_struct ncm_notify_connected = -{ - .header = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_IN - }, - .bRequest = CDC_NOTIF_NETWORK_CONNECTION, - .wValue = 1 /* Connected */, - .wLength = 0, - }, -}; - -tu_static struct ecm_notify_struct ncm_notify_speed_change = -{ - .header = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_IN - }, - .bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE, - .wLength = 8, - }, - .downlink = 10000000, - .uplink = 10000000, -}; - -void tud_network_recv_renew(void) -{ - if (!ncm_interface.num_datagrams) - { - usbd_edpt_xfer(0, ncm_interface.ep_out, receive_ntb, sizeof(receive_ntb)); - return; - } - - const ndp16_t *ndp = ncm_interface.ndp; - const int i = ncm_interface.current_datagram_index; - ncm_interface.current_datagram_index++; - ncm_interface.num_datagrams--; - - tud_network_recv_cb(receive_ntb + ndp->datagram[i].wDatagramIndex, ndp->datagram[i].wDatagramLength); -} - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ - -void netd_init(void) -{ - tu_memclr(&ncm_interface, sizeof(ncm_interface)); - ncm_interface.ntb_in_size = CFG_TUD_NCM_IN_NTB_MAX_SIZE; - ncm_interface.max_datagrams_per_ntb = CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB; - ncm_prepare_for_tx(); -} - -void netd_reset(uint8_t rhport) -{ - (void) rhport; - - netd_init(); -} - -uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ - // confirm interface hasn't already been allocated - TU_ASSERT(0 == ncm_interface.ep_notif, 0); - - //------------- Management Interface -------------// - ncm_interface.itf_num = itf_desc->bInterfaceNumber; - - uint16_t drv_len = sizeof(tusb_desc_interface_t); - uint8_t const * p_desc = tu_desc_next( itf_desc ); - - // Communication Functional Descriptors - while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) - { - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - // notification endpoint (if any) - if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) - { - TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 ); - - ncm_interface.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; - - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - //------------- Data Interface -------------// - // - CDC-NCM data interface has 2 alternate settings - // - 0 : zero endpoints for inactive (default) - // - 1 : IN & OUT endpoints for transfer of NTBs - TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); - - do - { - tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc; - TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass, 0); - - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } while((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (drv_len <= max_len)); - - // Pair of endpoints - TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0); - - TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &ncm_interface.ep_out, &ncm_interface.ep_in) ); - - drv_len += 2*sizeof(tusb_desc_endpoint_t); - - return drv_len; -} - -static void ncm_report(void) -{ - uint8_t const rhport = 0; - if (ncm_interface.report_state == REPORT_SPEED) { - ncm_notify_speed_change.header.wIndex = ncm_interface.itf_num; - usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_speed_change, sizeof(ncm_notify_speed_change)); - ncm_interface.report_state = REPORT_CONNECTED; - ncm_interface.report_pending = true; - } else if (ncm_interface.report_state == REPORT_CONNECTED) { - ncm_notify_connected.header.wIndex = ncm_interface.itf_num; - usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_connected, sizeof(ncm_notify_connected)); - ncm_interface.report_state = REPORT_DONE; - ncm_interface.report_pending = true; - } -} - -TU_ATTR_WEAK void tud_network_link_state_cb(bool state) -{ - (void)state; -} - -// Handle class control request -// return false to stall control endpoint (e.g unsupported request) -bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - if ( stage != CONTROL_STAGE_SETUP ) return true; - - switch ( request->bmRequestType_bit.type ) - { - case TUSB_REQ_TYPE_STANDARD: - switch ( request->bRequest ) - { - case TUSB_REQ_GET_INTERFACE: - { - uint8_t const req_itfnum = (uint8_t) request->wIndex; - TU_VERIFY(ncm_interface.itf_num + 1 == req_itfnum); - - tud_control_xfer(rhport, request, &ncm_interface.itf_data_alt, 1); - } - break; - - case TUSB_REQ_SET_INTERFACE: - { - uint8_t const req_itfnum = (uint8_t) request->wIndex; - uint8_t const req_alt = (uint8_t) request->wValue; - - // Only valid for Data Interface with Alternate is either 0 or 1 - TU_VERIFY(ncm_interface.itf_num + 1 == req_itfnum && req_alt < 2); - - if (req_alt != ncm_interface.itf_data_alt) { - ncm_interface.itf_data_alt = req_alt; - - if (ncm_interface.itf_data_alt) { - if (!usbd_edpt_busy(rhport, ncm_interface.ep_out)) { - tud_network_recv_renew(); // prepare for incoming datagrams - } - if (!ncm_interface.report_pending) { - ncm_report(); - } - } - - tud_network_link_state_cb(ncm_interface.itf_data_alt); - } - - tud_control_status(rhport, request); - } - break; - - // unsupported request - default: return false; - } - break; - - case TUSB_REQ_TYPE_CLASS: - TU_VERIFY (ncm_interface.itf_num == request->wIndex); - - if (NCM_GET_NTB_PARAMETERS == request->bRequest) - { - tud_control_xfer(rhport, request, (void*)(uintptr_t) &ntb_parameters, sizeof(ntb_parameters)); - } - - break; - - // unsupported request - default: return false; - } - - return true; -} - -static void handle_incoming_datagram(uint32_t len) -{ - uint32_t size = len; - - if (len == 0) { - return; - } - - TU_ASSERT(size >= sizeof(nth16_t), ); - - const nth16_t *hdr = (const nth16_t *)receive_ntb; - TU_ASSERT(hdr->dwSignature == NTH16_SIGNATURE, ); - TU_ASSERT(hdr->wNdpIndex >= sizeof(nth16_t) && (hdr->wNdpIndex + sizeof(ndp16_t)) <= len, ); - - const ndp16_t *ndp = (const ndp16_t *)(receive_ntb + hdr->wNdpIndex); - TU_ASSERT(ndp->dwSignature == NDP16_SIGNATURE_NCM0 || ndp->dwSignature == NDP16_SIGNATURE_NCM1, ); - TU_ASSERT(hdr->wNdpIndex + ndp->wLength <= len, ); - - int num_datagrams = (ndp->wLength - 12) / 4; - ncm_interface.current_datagram_index = 0; - ncm_interface.num_datagrams = 0; - ncm_interface.ndp = ndp; - for (int i = 0; i < num_datagrams && ndp->datagram[i].wDatagramIndex && ndp->datagram[i].wDatagramLength; i++) - { - ncm_interface.num_datagrams++; - } - - tud_network_recv_renew(); -} - -bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void) rhport; - (void) result; - - /* new datagram receive_ntb */ - if (ep_addr == ncm_interface.ep_out ) - { - handle_incoming_datagram(xferred_bytes); - } - - /* data transmission finished */ - if (ep_addr == ncm_interface.ep_in ) - { - if (ncm_interface.transferring) { - ncm_interface.transferring = false; - } - - // If there are datagrams queued up that we tried to send while this NTB was being emitted, send them now - if (ncm_interface.datagram_count && ncm_interface.itf_data_alt == 1) { - ncm_start_tx(); - } - } - - if (ep_addr == ncm_interface.ep_notif ) - { - ncm_interface.report_pending = false; - ncm_report(); - } - - return true; -} - -// poll network driver for its ability to accept another packet to transmit -bool tud_network_can_xmit(uint16_t size) -{ - TU_VERIFY(ncm_interface.itf_data_alt == 1); - - if (ncm_interface.datagram_count >= ncm_interface.max_datagrams_per_ntb) { - TU_LOG2("NTB full [by count]\r\n"); - return false; - } - - size_t next_datagram_offset = ncm_interface.next_datagram_offset; - if (next_datagram_offset + size > ncm_interface.ntb_in_size) { - TU_LOG2("ntb full [by size]\r\n"); - return false; - } - - return true; -} - -void tud_network_xmit(void *ref, uint16_t arg) -{ - transmit_ntb_t *ntb = &transmit_ntb[ncm_interface.current_ntb]; - size_t next_datagram_offset = ncm_interface.next_datagram_offset; - - uint16_t size = tud_network_xmit_cb(ntb->data + next_datagram_offset, ref, arg); - - ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramIndex = ncm_interface.next_datagram_offset; - ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramLength = size; - - ncm_interface.datagram_count++; - next_datagram_offset += size; - - // round up so the next datagram is aligned correctly - next_datagram_offset += (CFG_TUD_NCM_ALIGNMENT - 1); - next_datagram_offset -= (next_datagram_offset % CFG_TUD_NCM_ALIGNMENT); - - ncm_interface.next_datagram_offset = next_datagram_offset; - - ncm_start_tx(); -} - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/net/net_device.h b/test-devices/composite-stm32/lib/tinyusb/class/net/net_device.h deleted file mode 100644 index 39991635..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/net/net_device.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Peter Lawrence - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_NET_DEVICE_H_ -#define _TUSB_NET_DEVICE_H_ - -#include "class/cdc/cdc.h" - -#if CFG_TUD_ECM_RNDIS && CFG_TUD_NCM -#error "Cannot enable both ECM_RNDIS and NCM network drivers" -#endif - -#include "ncm.h" - -/* declared here, NOT in usb_descriptors.c, so that the driver can intelligently ZLP as needed */ -#define CFG_TUD_NET_ENDPOINT_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) - -/* Maximum Transmission Unit (in bytes) of the network, including Ethernet header */ -#ifndef CFG_TUD_NET_MTU -#define CFG_TUD_NET_MTU 1514 -#endif - -#ifndef CFG_TUD_NCM_IN_NTB_MAX_SIZE -#define CFG_TUD_NCM_IN_NTB_MAX_SIZE 3200 -#endif - -#ifndef CFG_TUD_NCM_OUT_NTB_MAX_SIZE -#define CFG_TUD_NCM_OUT_NTB_MAX_SIZE 3200 -#endif - -#ifndef CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB -#define CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB 8 -#endif - -#ifndef CFG_TUD_NCM_ALIGNMENT -#define CFG_TUD_NCM_ALIGNMENT 4 -#endif - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Application API -//--------------------------------------------------------------------+ - -// indicate to network driver that client has finished with the packet provided to network_recv_cb() -void tud_network_recv_renew(void); - -// poll network driver for its ability to accept another packet to transmit -bool tud_network_can_xmit(uint16_t size); - -// if network_can_xmit() returns true, network_xmit() can be called once -void tud_network_xmit(void *ref, uint16_t arg); - -//--------------------------------------------------------------------+ -// Application Callbacks (WEAK is optional) -//--------------------------------------------------------------------+ - -// client must provide this: return false if the packet buffer was not accepted -bool tud_network_recv_cb(const uint8_t *src, uint16_t size); - -// client must provide this: copy from network stack packet pointer to dst -uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg); - -//------------- ECM/RNDIS -------------// - -// client must provide this: initialize any network state back to the beginning -void tud_network_init_cb(void); - -// client must provide this: 48-bit MAC address -// TODO removed later since it is not part of tinyusb stack -extern uint8_t tud_network_mac_address[6]; - -//------------- NCM -------------// - -// callback to client providing optional indication of internal state of network driver -void tud_network_link_state_cb(bool state); - -//--------------------------------------------------------------------+ -// INTERNAL USBD-CLASS DRIVER API -//--------------------------------------------------------------------+ -void netd_init (void); -void netd_reset (uint8_t rhport); -uint16_t netd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -bool netd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); -void netd_report (uint8_t *buf, uint16_t len); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_NET_DEVICE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc.h b/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc.h deleted file mode 100644 index 090ab3c4..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc.h +++ /dev/null @@ -1,318 +0,0 @@ - -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 N Conrad - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_USBTMC_H__ -#define _TUSB_USBTMC_H__ - -#include "common/tusb_common.h" - - -/* Implements USBTMC Revision 1.0, April 14, 2003 - - String descriptors must have a "LANGID=0x409"/US English string. - Characters must be 0x20 (' ') to 0x7E ('~') ASCII, - But MUST not contain: "/:?\* - Also must not have leading or trailing space (' ') - Device descriptor must state USB version 0x0200 or greater - - If USB488DeviceCapabilites.D2 = 1 (SR1), then there must be a INT endpoint. -*/ - -#define USBTMC_VERSION 0x0100 -#define USBTMC_488_VERSION 0x0100 - -typedef enum { - USBTMC_MSGID_DEV_DEP_MSG_OUT = 1u, - USBTMC_MSGID_DEV_DEP_MSG_IN = 2u, - USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT = 126u, - USBTMC_MSGID_VENDOR_SPECIFIC_IN = 127u, - USBTMC_MSGID_USB488_TRIGGER = 128u, -} usbtmc_msgid_enum; - -/// \brief Message header (For BULK OUT and BULK IN); 4 bytes -typedef struct TU_ATTR_PACKED -{ - uint8_t MsgID ; ///< Message type ID (usbtmc_msgid_enum) - uint8_t bTag ; ///< Transfer ID 1<=bTag<=255 - uint8_t bTagInverse ; ///< Complement of the tag - uint8_t _reserved ; ///< Must be 0x00 -} usbtmc_msg_header_t; - -typedef struct TU_ATTR_PACKED -{ - usbtmc_msg_header_t header; - uint8_t data[8]; -} usbtmc_msg_generic_t; - -/* Uses on the bulk-out endpoint: */ -// Next 8 bytes are message-specific -typedef struct TU_ATTR_PACKED { - usbtmc_msg_header_t header ; ///< Header - uint32_t TransferSize ; ///< Transfer size; LSB first - struct TU_ATTR_PACKED - { - unsigned int EOM : 1 ; ///< EOM set on last byte - } bmTransferAttributes; - uint8_t _reserved[3]; -} usbtmc_msg_request_dev_dep_out; - -TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_dev_dep_out) == 12u, "struct wrong length"); - -// Next 8 bytes are message-specific -typedef struct TU_ATTR_PACKED -{ - usbtmc_msg_header_t header ; ///< Header - uint32_t TransferSize ; ///< Transfer size; LSB first - struct TU_ATTR_PACKED - { - unsigned int TermCharEnabled : 1 ; ///< "The Bulk-IN transfer must terminate on the specified TermChar."; CAPABILITIES must list TermChar - } bmTransferAttributes; - uint8_t TermChar; - uint8_t _reserved[2]; -} usbtmc_msg_request_dev_dep_in; - -TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_dev_dep_in) == 12u, "struct wrong length"); - -/* Bulk-in headers */ - -typedef struct TU_ATTR_PACKED -{ - usbtmc_msg_header_t header; - uint32_t TransferSize; - struct TU_ATTR_PACKED - { - uint8_t EOM: 1; ///< Last byte of transfer is the end of the message - uint8_t UsingTermChar: 1; ///< Support TermChar && Request.TermCharEnabled && last char in transfer is TermChar - } bmTransferAttributes; - uint8_t _reserved[3]; -} usbtmc_msg_dev_dep_msg_in_header_t; - -TU_VERIFY_STATIC(sizeof(usbtmc_msg_dev_dep_msg_in_header_t) == 12u, "struct wrong length"); - -/* Unsupported vendor things.... Are these ever used?*/ - -typedef struct TU_ATTR_PACKED -{ - usbtmc_msg_header_t header ; ///< Header - uint32_t TransferSize ; ///< Transfer size; LSB first - uint8_t _reserved[4]; -} usbtmc_msg_request_vendor_specific_out; - - -TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_vendor_specific_out) == 12u, "struct wrong length"); - -typedef struct TU_ATTR_PACKED -{ - usbtmc_msg_header_t header ; ///< Header - uint32_t TransferSize ; ///< Transfer size; LSB first - uint8_t _reserved[4]; -} usbtmc_msg_request_vendor_specific_in; - -TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_vendor_specific_in) == 12u, "struct wrong length"); - -// Control request type should use tusb_control_request_t - -/* -typedef struct TU_ATTR_PACKED { - struct { - unsigned int Recipient : 5 ; ///< EOM set on last byte - unsigned int Type : 2 ; ///< EOM set on last byte - unsigned int DirectionToHost : 1 ; ///< 0 is OUT, 1 is IN - } bmRequestType; - uint8_t bRequest ; ///< If bmRequestType.Type = Class, see usmtmc_request_type_enum - uint16_t wValue ; - uint16_t wIndex ; - uint16_t wLength ; // Number of bytes in data stage -} usbtmc_class_specific_control_req; - -*/ -// bulk-in protocol errors -enum { - USBTMC_BULK_IN_ERR_INCOMPLETE_HEADER = 1u, - USBTMC_BULK_IN_ERR_UNSUPPORTED = 2u, - USBTMC_BULK_IN_ERR_BAD_PARAMETER = 3u, - USBTMC_BULK_IN_ERR_DATA_TOO_SHORT = 4u, - USBTMC_BULK_IN_ERR_DATA_TOO_LONG = 5u, -}; -// built-in halt errors -enum { - USBTMC_BULK_IN_ERR = 1u, ///< receives a USBTMC command message that expects a response while a - /// Bulk-IN transfer is in progress -}; - -typedef enum { - USBTMC_bREQUEST_INITIATE_ABORT_BULK_OUT = 1u, - USBTMC_bREQUEST_CHECK_ABORT_BULK_OUT_STATUS = 2u, - USBTMC_bREQUEST_INITIATE_ABORT_BULK_IN = 3u, - USBTMC_bREQUEST_CHECK_ABORT_BULK_IN_STATUS = 4u, - USBTMC_bREQUEST_INITIATE_CLEAR = 5u, - USBTMC_bREQUEST_CHECK_CLEAR_STATUS = 6u, - USBTMC_bREQUEST_GET_CAPABILITIES = 7u, - - USBTMC_bREQUEST_INDICATOR_PULSE = 64u, // Optional - - /****** USBTMC 488 *************/ - USB488_bREQUEST_READ_STATUS_BYTE = 128u, - USB488_bREQUEST_REN_CONTROL = 160u, - USB488_bREQUEST_GO_TO_LOCAL = 161u, - USB488_bREQUEST_LOCAL_LOCKOUT = 162u, - -} usmtmc_request_type_enum; - -typedef enum { - USBTMC_STATUS_SUCCESS = 0x01, - USBTMC_STATUS_PENDING = 0x02, - USBTMC_STATUS_FAILED = 0x80, - USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS = 0x81, - USBTMC_STATUS_SPLIT_NOT_IN_PROGRESS = 0x82, - USBTMC_STATUS_SPLIT_IN_PROGRESS = 0x83, - - /****** USBTMC 488 *************/ - USB488_STATUS_INTERRUPT_IN_BUSY = 0x20 -} usbtmc_status_enum; - -/************************************************************ - * Control Responses - */ - -typedef struct TU_ATTR_PACKED { - uint8_t USBTMC_status; ///< usbtmc_status_enum - uint8_t _reserved; - uint16_t bcdUSBTMC; ///< USBTMC_VERSION - - struct TU_ATTR_PACKED - { - unsigned int listenOnly :1; - unsigned int talkOnly :1; - unsigned int supportsIndicatorPulse :1; - } bmIntfcCapabilities; - struct TU_ATTR_PACKED - { - unsigned int canEndBulkInOnTermChar :1; - } bmDevCapabilities; - uint8_t _reserved2[6]; - uint8_t _reserved3[12]; -} usbtmc_response_capabilities_t; - -TU_VERIFY_STATIC(sizeof(usbtmc_response_capabilities_t) == 0x18, "struct wrong length"); - -typedef struct TU_ATTR_PACKED -{ - uint8_t USBTMC_status; - struct TU_ATTR_PACKED - { - unsigned int BulkInFifoBytes :1; - } bmClear; -} usbtmc_get_clear_status_rsp_t; - -TU_VERIFY_STATIC(sizeof(usbtmc_get_clear_status_rsp_t) == 2u, "struct wrong length"); - -// Used for both abort bulk IN and bulk OUT -typedef struct TU_ATTR_PACKED -{ - uint8_t USBTMC_status; - uint8_t bTag; -} usbtmc_initiate_abort_rsp_t; - -TU_VERIFY_STATIC(sizeof(usbtmc_get_clear_status_rsp_t) == 2u, "struct wrong length"); - -// Used for both check_abort_bulk_in_status and check_abort_bulk_out_status -typedef struct TU_ATTR_PACKED -{ - uint8_t USBTMC_status; - struct TU_ATTR_PACKED - { - unsigned int BulkInFifoBytes : 1; ///< Has queued data or a short packet that is queued - } bmAbortBulkIn; - uint8_t _reserved[2]; ///< Must be zero - uint32_t NBYTES_RXD_TXD; -} usbtmc_check_abort_bulk_rsp_t; - -TU_VERIFY_STATIC(sizeof(usbtmc_check_abort_bulk_rsp_t) == 8u, "struct wrong length"); - -typedef struct TU_ATTR_PACKED -{ - uint8_t USBTMC_status; ///< usbtmc_status_enum - uint8_t _reserved; - uint16_t bcdUSBTMC; ///< USBTMC_VERSION - - struct TU_ATTR_PACKED - { - uint8_t listenOnly :1; - uint8_t talkOnly :1; - uint8_t supportsIndicatorPulse :1; - } bmIntfcCapabilities; - - struct TU_ATTR_PACKED - { - uint8_t canEndBulkInOnTermChar :1; - } bmDevCapabilities; - - uint8_t _reserved2[6]; - uint16_t bcdUSB488; - - struct TU_ATTR_PACKED - { - uint8_t supportsTrigger :1; - uint8_t supportsREN_GTL_LLO :1; - uint8_t is488_2 :1; - } bmIntfcCapabilities488; - - struct TU_ATTR_PACKED - { - uint8_t DT1 :1; - uint8_t RL1 :1; - uint8_t SR1 :1; - uint8_t SCPI :1; - } bmDevCapabilities488; - uint8_t _reserved3[8]; -} usbtmc_response_capabilities_488_t; - -TU_VERIFY_STATIC(sizeof(usbtmc_response_capabilities_488_t) == 0x18, "struct wrong length"); - -typedef struct TU_ATTR_PACKED -{ - uint8_t USBTMC_status; - uint8_t bTag; - uint8_t statusByte; -} usbtmc_read_stb_rsp_488_t; - -TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_rsp_488_t) == 3u, "struct wrong length"); - -typedef struct TU_ATTR_PACKED -{ - struct TU_ATTR_PACKED - { - unsigned int bTag : 7; - unsigned int one : 1; - } bNotify1; - uint8_t StatusByte; -} usbtmc_read_stb_interrupt_488_t; - -TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_interrupt_488_t) == 2u, "struct wrong length"); - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c b/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c deleted file mode 100644 index 4e320a77..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c +++ /dev/null @@ -1,890 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Nathan Conrad - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -/* - * This library is not fully reentrant, though it is reentrant from the view - * of either the application layer or the USB stack. Due to its locking, - * it is not safe to call its functions from interrupts. - * - * The one exception is that its functions may not be called from the application - * until the USB stack is initialized. This should not be a problem since the - * device shouldn't be sending messages until it receives a request from the - * host. - */ - - -/* - * In the case of single-CPU "no OS", this task is never preempted other than by - * interrupts, and the USBTMC code isn't called by interrupts, so all is OK. For "no OS", - * the mutex structure's main effect is to disable the USB interrupts. - * With an OS, this class driver uses the OSAL to perform locking. The code uses a single lock - * and does not call outside of this class with a lock held, so deadlocks won't happen. - */ - -//Limitations: -// "vendor-specific" commands are not handled. -// Dealing with "termchar" must be handled by the application layer, -// though additional error checking is does in this module. -// talkOnly and listenOnly are NOT supported. They're not permitted -// in USB488, anyway. - -/* Supported: - * - * Notification pulse - * Trigger - * Read status byte (both by interrupt endpoint and control message) - * - */ - - -// TODO: -// USBTMC 3.2.2 error conditions not strictly followed -// No local lock-out, REN, or GTL. -// Clear message available status byte at the correct time? (488 4.3.1.3) -// Ability to defer status byte transmission -// Transmission of status byte in response to USB488 SRQ condition - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_USBTMC) - -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "usbtmc_device.h" - -#ifdef xDEBUG -#include "uart_util.h" -tu_static char logMsg[150]; -#endif - -// Buffer size must be an exact multiple of the max packet size for both -// bulk (up to 64 bytes for FS, 512 bytes for HS). In addation, this driver -// imposes a minimum buffer size of 32 bytes. -#define USBTMCD_BUFFER_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) - -/* - * The state machine does not allow simultaneous reading and writing. This is - * consistent with USBTMC. - */ - -typedef enum -{ - STATE_CLOSED, // Endpoints have not yet been opened since USB reset - STATE_NAK, // Bulk-out endpoint is in NAK state. - STATE_IDLE, // Bulk-out endpoint is waiting for CMD. - STATE_RCV, // Bulk-out is receiving DEV_DEP message - STATE_TX_REQUESTED, - STATE_TX_INITIATED, - STATE_TX_SHORTED, - STATE_CLEARING, - STATE_ABORTING_BULK_IN, - STATE_ABORTING_BULK_IN_SHORTED, // aborting, and short packet has been queued for transmission - STATE_ABORTING_BULK_IN_ABORTED, // aborting, and short packet has been transmitted - STATE_ABORTING_BULK_OUT, - STATE_NUM_STATES -} usbtmcd_state_enum; - -#if (CFG_TUD_USBTMC_ENABLE_488) - typedef usbtmc_response_capabilities_488_t usbtmc_capabilities_specific_t; -#else - typedef usbtmc_response_capabilities_t usbtmc_capabilities_specific_t; -#endif - - -typedef struct -{ - volatile usbtmcd_state_enum state; - - uint8_t itf_id; - uint8_t rhport; - uint8_t ep_bulk_in; - uint8_t ep_bulk_out; - uint8_t ep_int_in; - // IN buffer is only used for first packet, not the remainder - // in order to deal with prepending header - CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_in_buf[USBTMCD_BUFFER_SIZE]; - uint32_t ep_bulk_in_wMaxPacketSize; - // OUT buffer receives one packet at a time - CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_out_buf[USBTMCD_BUFFER_SIZE]; - uint32_t ep_bulk_out_wMaxPacketSize; - - uint32_t transfer_size_remaining; // also used for requested length for bulk IN. - uint32_t transfer_size_sent; // To keep track of data bytes that have been queued in FIFO (not header bytes) - - uint8_t lastBulkOutTag; // used for aborts (mostly) - uint8_t lastBulkInTag; // used for aborts (mostly) - - uint8_t const * devInBuffer; // pointer to application-layer used for transmissions - - usbtmc_capabilities_specific_t const * capabilities; -} usbtmc_interface_state_t; - -CFG_TUSB_MEM_SECTION tu_static usbtmc_interface_state_t usbtmc_state = -{ - .itf_id = 0xFF, -}; - -// We need all headers to fit in a single packet in this implementation, 32 bytes will fit all standard USBTMC headers -TU_VERIFY_STATIC(USBTMCD_BUFFER_SIZE >= 32u,"USBTMC dev buffer size too small"); - -static bool handle_devMsgOutStart(uint8_t rhport, void *data, size_t len); -static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t packetLen); - -#ifndef NDEBUG -tu_static uint8_t termChar; -#endif - -tu_static uint8_t termCharRequested = false; - -#if OSAL_MUTEX_REQUIRED -static OSAL_MUTEX_DEF(usbtmcLockBuffer); -#endif -osal_mutex_t usbtmcLock; - -// Our own private lock, mostly for the state variable. -#define criticalEnter() do { (void) osal_mutex_lock(usbtmcLock,OSAL_TIMEOUT_WAIT_FOREVER); } while (0) -#define criticalLeave() do { (void) osal_mutex_unlock(usbtmcLock); } while (0) - -bool atomicChangeState(usbtmcd_state_enum expectedState, usbtmcd_state_enum newState) -{ - bool ret = true; - criticalEnter(); - usbtmcd_state_enum oldState = usbtmc_state.state; - if (oldState == expectedState) - { - usbtmc_state.state = newState; - } - else - { - ret = false; - } - criticalLeave(); - return ret; -} - -// called from app -// We keep a reference to the buffer, so it MUST not change until the app is -// notified that the transfer is complete. -// length of data is specified in the hdr. - -// We can't just send the whole thing at once because we need to concatanate the -// header with the data. -bool tud_usbtmc_transmit_dev_msg_data( - const void * data, size_t len, - bool endOfMessage, - bool usingTermChar) -{ - const unsigned int txBufLen = sizeof(usbtmc_state.ep_bulk_in_buf); - -#ifndef NDEBUG - TU_ASSERT(len > 0u); - TU_ASSERT(len <= usbtmc_state.transfer_size_remaining); - TU_ASSERT(usbtmc_state.transfer_size_sent == 0u); - if(usingTermChar) - { - TU_ASSERT(usbtmc_state.capabilities->bmDevCapabilities.canEndBulkInOnTermChar); - TU_ASSERT(termCharRequested); - TU_ASSERT(((uint8_t const*)data)[len-1u] == termChar); - } -#endif - - TU_VERIFY(usbtmc_state.state == STATE_TX_REQUESTED); - usbtmc_msg_dev_dep_msg_in_header_t *hdr = (usbtmc_msg_dev_dep_msg_in_header_t*)usbtmc_state.ep_bulk_in_buf; - tu_varclr(hdr); - hdr->header.MsgID = USBTMC_MSGID_DEV_DEP_MSG_IN; - hdr->header.bTag = usbtmc_state.lastBulkInTag; - hdr->header.bTagInverse = (uint8_t)~(usbtmc_state.lastBulkInTag); - hdr->TransferSize = len; - hdr->bmTransferAttributes.EOM = endOfMessage; - hdr->bmTransferAttributes.UsingTermChar = usingTermChar; - - // Copy in the header - const size_t headerLen = sizeof(*hdr); - const size_t dataLen = ((headerLen + hdr->TransferSize) <= txBufLen) ? - len : (txBufLen - headerLen); - const size_t packetLen = headerLen + dataLen; - - memcpy((uint8_t*)(usbtmc_state.ep_bulk_in_buf) + headerLen, data, dataLen); - usbtmc_state.transfer_size_remaining = len - dataLen; - usbtmc_state.transfer_size_sent = dataLen; - usbtmc_state.devInBuffer = (uint8_t const*) data + (dataLen); - - bool stateChanged = - atomicChangeState(STATE_TX_REQUESTED, (packetLen >= txBufLen) ? STATE_TX_INITIATED : STATE_TX_SHORTED); - TU_VERIFY(stateChanged); - TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf, (uint16_t)packetLen)); - return true; -} - -void usbtmcd_init_cb(void) -{ - usbtmc_state.capabilities = tud_usbtmc_get_capabilities_cb(); -#ifndef NDEBUG -# if CFG_TUD_USBTMC_ENABLE_488 - if (usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger) { - TU_ASSERT(&tud_usbtmc_msg_trigger_cb != NULL,); - } - // Per USB488 spec: table 8 - TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.listenOnly,); - TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.talkOnly,); -# endif - if (usbtmc_state.capabilities->bmIntfcCapabilities.supportsIndicatorPulse) { - TU_ASSERT(&tud_usbtmc_indicator_pulse_cb != NULL,); - } -#endif - - usbtmcLock = osal_mutex_create(&usbtmcLockBuffer); -} - -uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ - (void)rhport; - - uint16_t drv_len; - uint8_t const * p_desc; - uint8_t found_endpoints = 0; - - TU_VERIFY(itf_desc->bInterfaceClass == TUD_USBTMC_APP_CLASS , 0); - TU_VERIFY(itf_desc->bInterfaceSubClass == TUD_USBTMC_APP_SUBCLASS, 0); - -#ifndef NDEBUG - // Only 2 or 3 endpoints are allowed for USBTMC. - TU_ASSERT((itf_desc->bNumEndpoints == 2) || (itf_desc->bNumEndpoints ==3), 0); -#endif - - TU_ASSERT(usbtmc_state.state == STATE_CLOSED, 0); - - // Interface - drv_len = 0u; - p_desc = (uint8_t const *) itf_desc; - - usbtmc_state.itf_id = itf_desc->bInterfaceNumber; - usbtmc_state.rhport = rhport; - - while (found_endpoints < itf_desc->bNumEndpoints && drv_len <= max_len) - { - if ( TUSB_DESC_ENDPOINT == p_desc[DESC_OFFSET_TYPE]) - { - tusb_desc_endpoint_t const *ep_desc = (tusb_desc_endpoint_t const *)p_desc; - switch(ep_desc->bmAttributes.xfer) { - case TUSB_XFER_BULK: - // Ensure buffer is an exact multiple of the maxPacketSize - TU_ASSERT((USBTMCD_BUFFER_SIZE % tu_edpt_packet_size(ep_desc)) == 0, 0); - if (tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN) - { - usbtmc_state.ep_bulk_in = ep_desc->bEndpointAddress; - usbtmc_state.ep_bulk_in_wMaxPacketSize = tu_edpt_packet_size(ep_desc); - } else { - usbtmc_state.ep_bulk_out = ep_desc->bEndpointAddress; - usbtmc_state.ep_bulk_out_wMaxPacketSize = tu_edpt_packet_size(ep_desc); - } - - break; - case TUSB_XFER_INTERRUPT: -#ifndef NDEBUG - TU_ASSERT(tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN, 0); - TU_ASSERT(usbtmc_state.ep_int_in == 0, 0); -#endif - usbtmc_state.ep_int_in = ep_desc->bEndpointAddress; - break; - default: - TU_ASSERT(false, 0); - } - TU_ASSERT( usbd_edpt_open(rhport, ep_desc), 0); - found_endpoints++; - } - - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - // bulk endpoints are required, but interrupt IN is optional -#ifndef NDEBUG - TU_ASSERT(usbtmc_state.ep_bulk_in != 0, 0); - TU_ASSERT(usbtmc_state.ep_bulk_out != 0, 0); - if (itf_desc->bNumEndpoints == 2) - { - TU_ASSERT(usbtmc_state.ep_int_in == 0, 0); - } - else if (itf_desc->bNumEndpoints == 3) - { - TU_ASSERT(usbtmc_state.ep_int_in != 0, 0); - } -#if (CFG_TUD_USBTMC_ENABLE_488) - if(usbtmc_state.capabilities->bmIntfcCapabilities488.is488_2 || - usbtmc_state.capabilities->bmDevCapabilities488.SR1) - { - TU_ASSERT(usbtmc_state.ep_int_in != 0, 0); - } -#endif -#endif - atomicChangeState(STATE_CLOSED, STATE_NAK); - tud_usbtmc_open_cb(itf_desc->iInterface); - - return drv_len; -} -// Tell USBTMC class to set its bulk-in EP to ACK so that it can -// receive USBTMC commands. -// Returns false if it was already in an ACK state or is busy -// processing a command (such as a clear). Returns true if it was -// in the NAK state and successfully transitioned to the ACK wait -// state. -bool tud_usbtmc_start_bus_read() -{ - usbtmcd_state_enum oldState = usbtmc_state.state; - switch(oldState) - { - // These may transition to IDLE - case STATE_NAK: - case STATE_ABORTING_BULK_IN_ABORTED: - TU_VERIFY(atomicChangeState(oldState, STATE_IDLE)); - break; - // When receiving, let it remain receiving - case STATE_RCV: - break; - default: - return false; - } - TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, (uint16_t)usbtmc_state.ep_bulk_out_wMaxPacketSize)); - return true; -} - -void usbtmcd_reset_cb(uint8_t rhport) -{ - (void)rhport; - usbtmc_capabilities_specific_t const * capabilities = tud_usbtmc_get_capabilities_cb(); - - criticalEnter(); - tu_varclr(&usbtmc_state); - usbtmc_state.capabilities = capabilities; - usbtmc_state.itf_id = 0xFFu; - criticalLeave(); -} - -static bool handle_devMsgOutStart(uint8_t rhport, void *data, size_t len) -{ - (void)rhport; - // return true upon failure, as we can assume error is being handled elsewhere. - TU_VERIFY(atomicChangeState(STATE_IDLE, STATE_RCV), true); - usbtmc_state.transfer_size_sent = 0u; - - // must be a header, should have been confirmed before calling here. - usbtmc_msg_request_dev_dep_out *msg = (usbtmc_msg_request_dev_dep_out*)data; - usbtmc_state.transfer_size_remaining = msg->TransferSize; - TU_VERIFY(tud_usbtmc_msgBulkOut_start_cb(msg)); - - TU_VERIFY(handle_devMsgOut(rhport, (uint8_t*)data + sizeof(*msg), len - sizeof(*msg), len)); - usbtmc_state.lastBulkOutTag = msg->header.bTag; - return true; -} - -static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t packetLen) -{ - (void)rhport; - // return true upon failure, as we can assume error is being handled elsewhere. - TU_VERIFY(usbtmc_state.state == STATE_RCV,true); - - bool shortPacket = (packetLen < usbtmc_state.ep_bulk_out_wMaxPacketSize); - - // Packet is to be considered complete when we get enough data or at a short packet. - bool atEnd = false; - if(len >= usbtmc_state.transfer_size_remaining || shortPacket) - { - atEnd = true; - TU_VERIFY(atomicChangeState(STATE_RCV, STATE_NAK)); - } - - len = tu_min32(len, usbtmc_state.transfer_size_remaining); - - usbtmc_state.transfer_size_remaining -= len; - usbtmc_state.transfer_size_sent += len; - - // App may (should?) call the wait_for_bus() command at this point - if(!tud_usbtmc_msg_data_cb(data, len, atEnd)) - { - // TODO: Go to an error state upon failure other than just stalling the EP? - return false; - } - - - return true; -} - -static bool handle_devMsgIn(void *data, size_t len) -{ - TU_VERIFY(len == sizeof(usbtmc_msg_request_dev_dep_in)); - usbtmc_msg_request_dev_dep_in *msg = (usbtmc_msg_request_dev_dep_in*)data; - bool stateChanged = atomicChangeState(STATE_IDLE, STATE_TX_REQUESTED); - TU_VERIFY(stateChanged); - usbtmc_state.lastBulkInTag = msg->header.bTag; - usbtmc_state.transfer_size_remaining = msg->TransferSize; - usbtmc_state.transfer_size_sent = 0u; - - termCharRequested = msg->bmTransferAttributes.TermCharEnabled; - -#ifndef NDEBUG - termChar = msg->TermChar; -#endif - - if(termCharRequested) - TU_VERIFY(usbtmc_state.capabilities->bmDevCapabilities.canEndBulkInOnTermChar); - - TU_VERIFY(tud_usbtmc_msgBulkIn_request_cb(msg)); - return true; -} - -bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - TU_VERIFY(result == XFER_RESULT_SUCCESS); - //uart_tx_str_sync("TMC XFER CB\r\n"); - if(usbtmc_state.state == STATE_CLEARING) { - return true; /* I think we can ignore everything here */ - } - - if(ep_addr == usbtmc_state.ep_bulk_out) - { - usbtmc_msg_generic_t *msg = NULL; - - switch(usbtmc_state.state) - { - case STATE_IDLE: - { - TU_VERIFY(xferred_bytes >= sizeof(usbtmc_msg_generic_t)); - msg = (usbtmc_msg_generic_t*)(usbtmc_state.ep_bulk_out_buf); - uint8_t invInvTag = (uint8_t)~(msg->header.bTagInverse); - TU_VERIFY(msg->header.bTag == invInvTag); - TU_VERIFY(msg->header.bTag != 0x00); - - switch(msg->header.MsgID) { - case USBTMC_MSGID_DEV_DEP_MSG_OUT: - if(!handle_devMsgOutStart(rhport, msg, xferred_bytes)) - { - usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); - return false; - } - break; - - case USBTMC_MSGID_DEV_DEP_MSG_IN: - TU_VERIFY(handle_devMsgIn(msg, xferred_bytes)); - break; - -#if (CFG_TUD_USBTMC_ENABLE_488) - case USBTMC_MSGID_USB488_TRIGGER: - // Spec says we halt the EP if we didn't declare we support it. - TU_VERIFY(usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger); - TU_VERIFY(tud_usbtmc_msg_trigger_cb(msg)); - - break; -#endif - case USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT: - case USBTMC_MSGID_VENDOR_SPECIFIC_IN: - default: - usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); - return false; - } - return true; - } - case STATE_RCV: - if(!handle_devMsgOut(rhport, usbtmc_state.ep_bulk_out_buf, xferred_bytes, xferred_bytes)) - { - usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); - return false; - } - return true; - - case STATE_ABORTING_BULK_OUT: - // Should be stalled by now, shouldn't have received a packet. - return false; - - case STATE_TX_REQUESTED: - case STATE_TX_INITIATED: - case STATE_ABORTING_BULK_IN: - case STATE_ABORTING_BULK_IN_SHORTED: - case STATE_ABORTING_BULK_IN_ABORTED: - default: - return false; - } - } - else if(ep_addr == usbtmc_state.ep_bulk_in) - { - switch(usbtmc_state.state) { - case STATE_TX_SHORTED: - TU_VERIFY(atomicChangeState(STATE_TX_SHORTED, STATE_NAK)); - TU_VERIFY(tud_usbtmc_msgBulkIn_complete_cb()); - break; - - case STATE_TX_INITIATED: - if(usbtmc_state.transfer_size_remaining >= sizeof(usbtmc_state.ep_bulk_in_buf)) - { - // FIXME! This removes const below! - TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, - (void*)(uintptr_t) usbtmc_state.devInBuffer, sizeof(usbtmc_state.ep_bulk_in_buf))); - usbtmc_state.devInBuffer += sizeof(usbtmc_state.ep_bulk_in_buf); - usbtmc_state.transfer_size_remaining -= sizeof(usbtmc_state.ep_bulk_in_buf); - usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.ep_bulk_in_buf); - } - else // last packet - { - size_t packetLen = usbtmc_state.transfer_size_remaining; - memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, usbtmc_state.transfer_size_remaining); - usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.transfer_size_remaining); - usbtmc_state.transfer_size_remaining = 0; - usbtmc_state.devInBuffer = NULL; - TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf, (uint16_t)packetLen) ); - if(((packetLen % usbtmc_state.ep_bulk_in_wMaxPacketSize) != 0) || (packetLen == 0 )) - { - usbtmc_state.state = STATE_TX_SHORTED; - } - } - return true; - - case STATE_ABORTING_BULK_IN: - // need to send short packet (ZLP?) - TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,(uint16_t)0u)); - usbtmc_state.state = STATE_ABORTING_BULK_IN_SHORTED; - return true; - - case STATE_ABORTING_BULK_IN_SHORTED: - /* Done. :)*/ - usbtmc_state.state = STATE_ABORTING_BULK_IN_ABORTED; - return true; - - default: - TU_ASSERT(false); - } - } - else if (ep_addr == usbtmc_state.ep_int_in) { - // Good? - return true; - } - return false; -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - // nothing to do with DATA and ACK stage - if ( stage != CONTROL_STAGE_SETUP ) return true; - - uint8_t tmcStatusCode = USBTMC_STATUS_FAILED; -#if (CFG_TUD_USBTMC_ENABLE_488) - uint8_t bTag; -#endif - - if((request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) && - (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_ENDPOINT) && - (request->bRequest == TUSB_REQ_CLEAR_FEATURE) && - (request->wValue == TUSB_REQ_FEATURE_EDPT_HALT)) - { - uint32_t ep_addr = (request->wIndex); - - // At this point, a transfer MAY be in progress. Based on USB spec, when clearing bulk EP HALT, - // the EP transfer buffer needs to be cleared and DTOG needs to be reset, even if - // the EP is not halted. The only USBD API interface to do this is to stall and then un-stall the EP. - if(ep_addr == usbtmc_state.ep_bulk_out) - { - criticalEnter(); - usbd_edpt_stall(rhport, (uint8_t)ep_addr); - usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr); - usbtmc_state.state = STATE_NAK; // USBD core has placed EP in NAK state for us - criticalLeave(); - tud_usbtmc_bulkOut_clearFeature_cb(); - } - else if (ep_addr == usbtmc_state.ep_bulk_in) - { - usbd_edpt_stall(rhport, (uint8_t)ep_addr); - usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr); - tud_usbtmc_bulkIn_clearFeature_cb(); - } - else if ((usbtmc_state.ep_int_in != 0) && (ep_addr == usbtmc_state.ep_int_in)) - { - // Clearing interrupt in EP - usbd_edpt_stall(rhport, (uint8_t)ep_addr); - usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr); - } - else - { - return false; - } - return true; - } - - // Otherwise, we only handle class requests. - if(request->bmRequestType_bit.type != TUSB_REQ_TYPE_CLASS) - { - return false; - } - - // Verification that we own the interface is unneeded since it's been routed to us specifically. - - switch(request->bRequest) - { - // USBTMC required requests - case USBTMC_bREQUEST_INITIATE_ABORT_BULK_OUT: - { - usbtmc_initiate_abort_rsp_t rsp = { - .bTag = usbtmc_state.lastBulkOutTag, - }; - TU_VERIFY(request->bmRequestType == 0xA2); // in,class,interface - TU_VERIFY(request->wLength == sizeof(rsp)); - TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_out); - - // wValue is the requested bTag to abort - if(usbtmc_state.state != STATE_RCV) - { - rsp.USBTMC_status = USBTMC_STATUS_FAILED; - } - else if(usbtmc_state.lastBulkOutTag == (request->wValue & 0x7Fu)) - { - rsp.USBTMC_status = USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS; - } - else - { - rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; - // Check if we've queued a short packet - criticalEnter(); - usbtmc_state.state = STATE_ABORTING_BULK_OUT; - criticalLeave(); - TU_VERIFY(tud_usbtmc_initiate_abort_bulk_out_cb(&(rsp.USBTMC_status))); - usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); - } - TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); - return true; - } - - case USBTMC_bREQUEST_CHECK_ABORT_BULK_OUT_STATUS: - { - usbtmc_check_abort_bulk_rsp_t rsp = { - .USBTMC_status = USBTMC_STATUS_SUCCESS, - .NBYTES_RXD_TXD = usbtmc_state.transfer_size_sent - }; - TU_VERIFY(request->bmRequestType == 0xA2); // in,class,EP - TU_VERIFY(request->wLength == sizeof(rsp)); - TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_out); - TU_VERIFY(tud_usbtmc_check_abort_bulk_out_cb(&rsp)); - TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); - return true; - } - - case USBTMC_bREQUEST_INITIATE_ABORT_BULK_IN: - { - usbtmc_initiate_abort_rsp_t rsp = { - .bTag = usbtmc_state.lastBulkInTag, - }; - TU_VERIFY(request->bmRequestType == 0xA2); // in,class,interface - TU_VERIFY(request->wLength == sizeof(rsp)); - TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_in); - // wValue is the requested bTag to abort - if((usbtmc_state.state == STATE_TX_REQUESTED || usbtmc_state.state == STATE_TX_INITIATED) && - usbtmc_state.lastBulkInTag == (request->wValue & 0x7Fu)) - { - rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; - usbtmc_state.transfer_size_remaining = 0u; - // Check if we've queued a short packet - criticalEnter(); - usbtmc_state.state = ((usbtmc_state.transfer_size_sent % usbtmc_state.ep_bulk_in_wMaxPacketSize) == 0) ? - STATE_ABORTING_BULK_IN : STATE_ABORTING_BULK_IN_SHORTED; - criticalLeave(); - if(usbtmc_state.transfer_size_sent == 0) - { - // Send short packet, nothing is in the buffer yet - TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,(uint16_t)0u)); - usbtmc_state.state = STATE_ABORTING_BULK_IN_SHORTED; - } - TU_VERIFY(tud_usbtmc_initiate_abort_bulk_in_cb(&(rsp.USBTMC_status))); - } - else if((usbtmc_state.state == STATE_TX_REQUESTED || usbtmc_state.state == STATE_TX_INITIATED)) - { // FIXME: Unsure how to check if the OUT endpoint fifo is non-empty.... - rsp.USBTMC_status = USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS; - } - else - { - rsp.USBTMC_status = USBTMC_STATUS_FAILED; - } - TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); - return true; - } - - case USBTMC_bREQUEST_CHECK_ABORT_BULK_IN_STATUS: - { - TU_VERIFY(request->bmRequestType == 0xA2); // in,class,EP - TU_VERIFY(request->wLength == 8u); - - usbtmc_check_abort_bulk_rsp_t rsp = - { - .USBTMC_status = USBTMC_STATUS_FAILED, - .bmAbortBulkIn = - { - .BulkInFifoBytes = (usbtmc_state.state != STATE_ABORTING_BULK_IN_ABORTED) - }, - .NBYTES_RXD_TXD = usbtmc_state.transfer_size_sent, - }; - TU_VERIFY(tud_usbtmc_check_abort_bulk_in_cb(&rsp)); - criticalEnter(); - switch(usbtmc_state.state) - { - case STATE_ABORTING_BULK_IN_ABORTED: - rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; - usbtmc_state.state = STATE_IDLE; - break; - case STATE_ABORTING_BULK_IN: - case STATE_ABORTING_BULK_OUT: - rsp.USBTMC_status = USBTMC_STATUS_PENDING; - break; - default: - break; - } - criticalLeave(); - TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); - - return true; - } - - case USBTMC_bREQUEST_INITIATE_CLEAR: - { - TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface - TU_VERIFY(request->wLength == sizeof(tmcStatusCode)); - // After receiving an INITIATE_CLEAR request, the device must Halt the Bulk-OUT endpoint, queue the - // control endpoint response shown in Table 31, and clear all input buffers and output buffers. - usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); - usbtmc_state.transfer_size_remaining = 0; - criticalEnter(); - usbtmc_state.state = STATE_CLEARING; - criticalLeave(); - TU_VERIFY(tud_usbtmc_initiate_clear_cb(&tmcStatusCode)); - TU_VERIFY(tud_control_xfer(rhport, request, (void*)&tmcStatusCode,sizeof(tmcStatusCode))); - return true; - } - - case USBTMC_bREQUEST_CHECK_CLEAR_STATUS: - { - TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface - usbtmc_get_clear_status_rsp_t clearStatusRsp = {0}; - TU_VERIFY(request->wLength == sizeof(clearStatusRsp)); - - if(usbd_edpt_busy(rhport, usbtmc_state.ep_bulk_in)) - { - // Stuff stuck in TX buffer? - clearStatusRsp.bmClear.BulkInFifoBytes = 1; - clearStatusRsp.USBTMC_status = USBTMC_STATUS_PENDING; - } - else - { - // Let app check if it's clear - TU_VERIFY(tud_usbtmc_check_clear_cb(&clearStatusRsp)); - } - if(clearStatusRsp.USBTMC_status == USBTMC_STATUS_SUCCESS) - { - criticalEnter(); - usbtmc_state.state = STATE_IDLE; - criticalLeave(); - } - TU_VERIFY(tud_control_xfer(rhport, request, (void*)&clearStatusRsp,sizeof(clearStatusRsp))); - return true; - } - - case USBTMC_bREQUEST_GET_CAPABILITIES: - { - TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface - TU_VERIFY(request->wLength == sizeof(*(usbtmc_state.capabilities))); - TU_VERIFY(tud_control_xfer(rhport, request, (void*)(uintptr_t) usbtmc_state.capabilities, sizeof(*usbtmc_state.capabilities))); - return true; - } - // USBTMC Optional Requests - - case USBTMC_bREQUEST_INDICATOR_PULSE: // Optional - { - TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface - TU_VERIFY(request->wLength == sizeof(tmcStatusCode)); - TU_VERIFY(usbtmc_state.capabilities->bmIntfcCapabilities.supportsIndicatorPulse); - TU_VERIFY(tud_usbtmc_indicator_pulse_cb(request, &tmcStatusCode)); - TU_VERIFY(tud_control_xfer(rhport, request, (void*)&tmcStatusCode, sizeof(tmcStatusCode))); - return true; - } -#if (CFG_TUD_USBTMC_ENABLE_488) - - // USB488 required requests - case USB488_bREQUEST_READ_STATUS_BYTE: - { - usbtmc_read_stb_rsp_488_t rsp; - TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface - TU_VERIFY(request->wLength == sizeof(rsp)); // in,class,interface - - bTag = request->wValue & 0x7F; - TU_VERIFY(request->bmRequestType == 0xA1); - TU_VERIFY((request->wValue & (~0x7F)) == 0u); // Other bits are required to be zero (USB488v1.0 Table 11) - TU_VERIFY(bTag >= 0x02 && bTag <= 127); - TU_VERIFY(request->wIndex == usbtmc_state.itf_id); - TU_VERIFY(request->wLength == 0x0003); - rsp.bTag = (uint8_t)bTag; - if(usbtmc_state.ep_int_in != 0) - { - rsp.statusByte = 0x00; // Use interrupt endpoint, instead. Must be 0x00 (USB488v1.0 4.3.1.2) - if(usbd_edpt_busy(rhport, usbtmc_state.ep_int_in)) - { - rsp.USBTMC_status = USB488_STATUS_INTERRUPT_IN_BUSY; - } - else - { - rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; - usbtmc_read_stb_interrupt_488_t intMsg = - { - .bNotify1 = { - .one = 1, - .bTag = bTag & 0x7Fu, - }, - .StatusByte = tud_usbtmc_get_stb_cb(&(rsp.USBTMC_status)) - }; - // Must be queued before control request response sent (USB488v1.0 4.3.1.2) - usbd_edpt_xfer(rhport, usbtmc_state.ep_int_in, (void*)&intMsg, sizeof(intMsg)); - } - } - else - { - rsp.statusByte = tud_usbtmc_get_stb_cb(&(rsp.USBTMC_status)); - } - TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp, sizeof(rsp))); - return true; - } - // USB488 optional requests - case USB488_bREQUEST_REN_CONTROL: - case USB488_bREQUEST_GO_TO_LOCAL: - case USB488_bREQUEST_LOCAL_LOCKOUT: - { - TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface - return false; - } -#endif - - default: - return false; - } -} - -#endif /* CFG_TUD_TSMC */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h b/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h deleted file mode 100644 index c1298ddb..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 N Conrad - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - - -#ifndef CLASS_USBTMC_USBTMC_DEVICE_H_ -#define CLASS_USBTMC_USBTMC_DEVICE_H_ - -#include "usbtmc.h" - -// Enable 488 mode by default -#if !defined(CFG_TUD_USBTMC_ENABLE_488) -#define CFG_TUD_USBTMC_ENABLE_488 (1) -#endif - -/*********************************************** - * Functions to be implemented by the class implementation - */ - -// In order to proceed, app must call call tud_usbtmc_start_bus_read(rhport) during or soon after: -// * tud_usbtmc_open_cb -// * tud_usbtmc_msg_data_cb -// * tud_usbtmc_msgBulkIn_complete_cb -// * tud_usbtmc_msg_trigger_cb -// * (successful) tud_usbtmc_check_abort_bulk_out_cb -// * (successful) tud_usbtmc_check_abort_bulk_in_cb -// * (successful) tud_usmtmc_bulkOut_clearFeature_cb - -#if (CFG_TUD_USBTMC_ENABLE_488) -usbtmc_response_capabilities_488_t const * tud_usbtmc_get_capabilities_cb(void); -#else -usbtmc_response_capabilities_t const * tud_usbtmc_get_capabilities_cb(void); -#endif - -void tud_usbtmc_open_cb(uint8_t interface_id); - -bool tud_usbtmc_msgBulkOut_start_cb(usbtmc_msg_request_dev_dep_out const * msgHeader); -// transfer_complete does not imply that a message is complete. -bool tud_usbtmc_msg_data_cb( void *data, size_t len, bool transfer_complete); -void tud_usbtmc_bulkOut_clearFeature_cb(void); // Notice to clear and abort the pending BULK out transfer - -bool tud_usbtmc_msgBulkIn_request_cb(usbtmc_msg_request_dev_dep_in const * request); -bool tud_usbtmc_msgBulkIn_complete_cb(void); -void tud_usbtmc_bulkIn_clearFeature_cb(void); // Notice to clear and abort the pending BULK out transfer - -bool tud_usbtmc_initiate_abort_bulk_in_cb(uint8_t *tmcResult); -bool tud_usbtmc_initiate_abort_bulk_out_cb(uint8_t *tmcResult); -bool tud_usbtmc_initiate_clear_cb(uint8_t *tmcResult); - -bool tud_usbtmc_check_abort_bulk_in_cb(usbtmc_check_abort_bulk_rsp_t *rsp); -bool tud_usbtmc_check_abort_bulk_out_cb(usbtmc_check_abort_bulk_rsp_t *rsp); -bool tud_usbtmc_check_clear_cb(usbtmc_get_clear_status_rsp_t *rsp); - -// Indicator pulse should be 0.5 to 1.0 seconds long -TU_ATTR_WEAK bool tud_usbtmc_indicator_pulse_cb(tusb_control_request_t const * msg, uint8_t *tmcResult); - -#if (CFG_TUD_USBTMC_ENABLE_488) -uint8_t tud_usbtmc_get_stb_cb(uint8_t *tmcResult); -TU_ATTR_WEAK bool tud_usbtmc_msg_trigger_cb(usbtmc_msg_generic_t* msg); -//TU_ATTR_WEAK bool tud_usbtmc_app_go_to_local_cb(); -#endif - -/******************************************* - * Called from app - * - * We keep a reference to the buffer, so it MUST not change until the app is - * notified that the transfer is complete. - ******************************************/ - -bool tud_usbtmc_transmit_dev_msg_data( - const void * data, size_t len, - bool endOfMessage, bool usingTermChar); - -bool tud_usbtmc_start_bus_read(void); - - -/* "callbacks" from USB device core */ - -uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -void usbtmcd_reset_cb(uint8_t rhport); -bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); -bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -void usbtmcd_init_cb(void); - -/************************************************************ - * USBTMC Descriptor Templates - *************************************************************/ - - -#endif /* CLASS_USBTMC_USBTMC_DEVICE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.c b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.c deleted file mode 100644 index 93596ee3..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_VENDOR) - -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "vendor_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -typedef struct -{ - uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; - - /*------------- From this point, data is not cleared by bus reset -------------*/ - tu_fifo_t rx_ff; - tu_fifo_t tx_ff; - - uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE]; - uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE]; - -#if CFG_FIFO_MUTEX - osal_mutex_def_t rx_ff_mutex; - osal_mutex_def_t tx_ff_mutex; -#endif - - // Endpoint Transfer buffer - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_VENDOR_EPSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_VENDOR_EPSIZE]; -} vendord_interface_t; - -CFG_TUSB_MEM_SECTION tu_static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR]; - -#define ITF_MEM_RESET_SIZE offsetof(vendord_interface_t, rx_ff) - - -bool tud_vendor_n_mounted (uint8_t itf) -{ - return _vendord_itf[itf].ep_in && _vendord_itf[itf].ep_out; -} - -uint32_t tud_vendor_n_available (uint8_t itf) -{ - return tu_fifo_count(&_vendord_itf[itf].rx_ff); -} - -bool tud_vendor_n_peek(uint8_t itf, uint8_t* u8) -{ - return tu_fifo_peek(&_vendord_itf[itf].rx_ff, u8); -} - -//--------------------------------------------------------------------+ -// Read API -//--------------------------------------------------------------------+ -static void _prep_out_transaction (vendord_interface_t* p_itf) -{ - uint8_t const rhport = 0; - - // claim endpoint - TU_VERIFY(usbd_edpt_claim(rhport, p_itf->ep_out), ); - - // Prepare for incoming data but only allow what we can store in the ring buffer. - uint16_t max_read = tu_fifo_remaining(&p_itf->rx_ff); - if ( max_read >= CFG_TUD_VENDOR_EPSIZE ) - { - usbd_edpt_xfer(rhport, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE); - } - else - { - // Release endpoint since we don't make any transfer - usbd_edpt_release(rhport, p_itf->ep_out); - } -} - -uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize) -{ - vendord_interface_t* p_itf = &_vendord_itf[itf]; - uint32_t num_read = tu_fifo_read_n(&p_itf->rx_ff, buffer, (uint16_t) bufsize); - _prep_out_transaction(p_itf); - return num_read; -} - -void tud_vendor_n_read_flush (uint8_t itf) -{ - vendord_interface_t* p_itf = &_vendord_itf[itf]; - tu_fifo_clear(&p_itf->rx_ff); - _prep_out_transaction(p_itf); -} - -//--------------------------------------------------------------------+ -// Write API -//--------------------------------------------------------------------+ -uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize) -{ - vendord_interface_t* p_itf = &_vendord_itf[itf]; - uint16_t ret = tu_fifo_write_n(&p_itf->tx_ff, buffer, (uint16_t) bufsize); - - // flush if queue more than packet size - if (tu_fifo_count(&p_itf->tx_ff) >= CFG_TUD_VENDOR_EPSIZE) { - tud_vendor_n_write_flush(itf); - } - return ret; -} - -uint32_t tud_vendor_n_write_flush (uint8_t itf) -{ - vendord_interface_t* p_itf = &_vendord_itf[itf]; - - // Skip if usb is not ready yet - TU_VERIFY( tud_ready(), 0 ); - - // No data to send - if ( !tu_fifo_count(&p_itf->tx_ff) ) return 0; - - uint8_t const rhport = 0; - - // Claim the endpoint - TU_VERIFY( usbd_edpt_claim(rhport, p_itf->ep_in), 0 ); - - // Pull data from FIFO - uint16_t const count = tu_fifo_read_n(&p_itf->tx_ff, p_itf->epin_buf, sizeof(p_itf->epin_buf)); - - if ( count ) - { - TU_ASSERT( usbd_edpt_xfer(rhport, p_itf->ep_in, p_itf->epin_buf, count), 0 ); - return count; - }else - { - // Release endpoint since we don't make any transfer - // Note: data is dropped if terminal is not connected - usbd_edpt_release(rhport, p_itf->ep_in); - return 0; - } -} - -uint32_t tud_vendor_n_write_available (uint8_t itf) -{ - return tu_fifo_remaining(&_vendord_itf[itf].tx_ff); -} - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void vendord_init(void) -{ - tu_memclr(_vendord_itf, sizeof(_vendord_itf)); - - for(uint8_t i=0; irx_ff, p_itf->rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, 1, false); - tu_fifo_config(&p_itf->tx_ff, p_itf->tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, 1, false); - -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&p_itf->rx_ff, NULL, osal_mutex_create(&p_itf->rx_ff_mutex)); - tu_fifo_config_mutex(&p_itf->tx_ff, osal_mutex_create(&p_itf->tx_ff_mutex), NULL); -#endif - } -} - -void vendord_reset(uint8_t rhport) -{ - (void) rhport; - - for(uint8_t i=0; irx_ff); - tu_fifo_clear(&p_itf->tx_ff); - } -} - -uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) -{ - TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0); - - uint8_t const * p_desc = tu_desc_next(desc_itf); - uint8_t const * desc_end = p_desc + max_len; - - // Find available interface - vendord_interface_t* p_vendor = NULL; - for(uint8_t i=0; iitf_num = desc_itf->bInterfaceNumber; - if (desc_itf->bNumEndpoints) - { - // skip non-endpoint descriptors - while ( (TUSB_DESC_ENDPOINT != tu_desc_type(p_desc)) && (p_desc < desc_end) ) - { - p_desc = tu_desc_next(p_desc); - } - - // Open endpoint pair with usbd helper - TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_BULK, &p_vendor->ep_out, &p_vendor->ep_in), 0); - - p_desc += desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t); - - // Prepare for incoming data - if ( p_vendor->ep_out ) - { - _prep_out_transaction(p_vendor); - } - - if ( p_vendor->ep_in ) tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); - } - - return (uint16_t) ((uintptr_t) p_desc - (uintptr_t) desc_itf); -} - -bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void) rhport; - (void) result; - - uint8_t itf = 0; - vendord_interface_t* p_itf = _vendord_itf; - - for ( ; ; itf++, p_itf++) - { - if (itf >= TU_ARRAY_SIZE(_vendord_itf)) return false; - - if ( ( ep_addr == p_itf->ep_out ) || ( ep_addr == p_itf->ep_in ) ) break; - } - - if ( ep_addr == p_itf->ep_out ) - { - // Receive new data - tu_fifo_write_n(&p_itf->rx_ff, p_itf->epout_buf, (uint16_t) xferred_bytes); - - // Invoked callback if any - if (tud_vendor_rx_cb) tud_vendor_rx_cb(itf); - - _prep_out_transaction(p_itf); - } - else if ( ep_addr == p_itf->ep_in ) - { - if (tud_vendor_tx_cb) tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes); - // Send complete, try to send more if possible - tud_vendor_n_write_flush(itf); - } - - return true; -} - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.h b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.h deleted file mode 100644 index d239406b..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_device.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_VENDOR_DEVICE_H_ -#define _TUSB_VENDOR_DEVICE_H_ - -#include "common/tusb_common.h" - -#ifndef CFG_TUD_VENDOR_EPSIZE -#define CFG_TUD_VENDOR_EPSIZE 64 -#endif - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Application API (Multiple Interfaces) -//--------------------------------------------------------------------+ -bool tud_vendor_n_mounted (uint8_t itf); - -uint32_t tud_vendor_n_available (uint8_t itf); -uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize); -bool tud_vendor_n_peek (uint8_t itf, uint8_t* ui8); -void tud_vendor_n_read_flush (uint8_t itf); - -uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize); -uint32_t tud_vendor_n_write_flush (uint8_t itf); -uint32_t tud_vendor_n_write_available (uint8_t itf); - -static inline uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str); - -// backward compatible -#define tud_vendor_n_flush(itf) tud_vendor_n_write_flush(itf) - -//--------------------------------------------------------------------+ -// Application API (Single Port) -//--------------------------------------------------------------------+ -static inline bool tud_vendor_mounted (void); -static inline uint32_t tud_vendor_available (void); -static inline uint32_t tud_vendor_read (void* buffer, uint32_t bufsize); -static inline bool tud_vendor_peek (uint8_t* ui8); -static inline void tud_vendor_read_flush (void); -static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize); -static inline uint32_t tud_vendor_write_str (char const* str); -static inline uint32_t tud_vendor_write_available (void); -static inline uint32_t tud_vendor_write_flush (void); - -// backward compatible -#define tud_vendor_flush() tud_vendor_write_flush() - -//--------------------------------------------------------------------+ -// Application Callback API (weak is optional) -//--------------------------------------------------------------------+ - -// Invoked when received new data -TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf); -// Invoked when last rx transfer finished -TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes); - -//--------------------------------------------------------------------+ -// Inline Functions -//--------------------------------------------------------------------+ - -static inline uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str) -{ - return tud_vendor_n_write(itf, str, strlen(str)); -} - -static inline bool tud_vendor_mounted (void) -{ - return tud_vendor_n_mounted(0); -} - -static inline uint32_t tud_vendor_available (void) -{ - return tud_vendor_n_available(0); -} - -static inline uint32_t tud_vendor_read (void* buffer, uint32_t bufsize) -{ - return tud_vendor_n_read(0, buffer, bufsize); -} - -static inline bool tud_vendor_peek (uint8_t* ui8) -{ - return tud_vendor_n_peek(0, ui8); -} - -static inline void tud_vendor_read_flush(void) -{ - tud_vendor_n_read_flush(0); -} - -static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize) -{ - return tud_vendor_n_write(0, buffer, bufsize); -} - -static inline uint32_t tud_vendor_write_flush (void) -{ - return tud_vendor_n_write_flush(0); -} - -static inline uint32_t tud_vendor_write_str (char const* str) -{ - return tud_vendor_n_write_str(0, str); -} - -static inline uint32_t tud_vendor_write_available (void) -{ - return tud_vendor_n_write_available(0); -} - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void vendord_init(void); -void vendord_reset(uint8_t rhport); -uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_VENDOR_DEVICE_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.c b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.c deleted file mode 100644 index e66c5007..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUH_ENABLED && CFG_TUH_VENDOR) - -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "host/usbh.h" -#include "vendor_host.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -custom_interface_info_t custom_interface[CFG_TUH_DEVICE_MAX]; - -static tusb_error_t cush_validate_paras(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length) -{ - if ( !tusbh_custom_is_mounted(dev_addr, vendor_id, product_id) ) - { - return TUSB_ERROR_DEVICE_NOT_READY; - } - - TU_ASSERT( p_buffer != NULL && length != 0, TUSB_ERROR_INVALID_PARA); - - return TUSB_ERROR_NONE; -} -//--------------------------------------------------------------------+ -// APPLICATION API (need to check parameters) -//--------------------------------------------------------------------+ -tusb_error_t tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length) -{ - TU_ASSERT_ERR( cush_validate_paras(dev_addr, vendor_id, product_id, p_buffer, length) ); - - if ( !hcd_pipe_is_idle(custom_interface[dev_addr-1].pipe_in) ) - { - return TUSB_ERROR_INTERFACE_IS_BUSY; - } - - (void) usbh_edpt_xfer( custom_interface[dev_addr-1].pipe_in, p_buffer, length); - - return TUSB_ERROR_NONE; -} - -tusb_error_t tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length) -{ - TU_ASSERT_ERR( cush_validate_paras(dev_addr, vendor_id, product_id, p_data, length) ); - - if ( !hcd_pipe_is_idle(custom_interface[dev_addr-1].pipe_out) ) - { - return TUSB_ERROR_INTERFACE_IS_BUSY; - } - - (void) usbh_edpt_xfer( custom_interface[dev_addr-1].pipe_out, p_data, length); - - return TUSB_ERROR_NONE; -} - -//--------------------------------------------------------------------+ -// USBH-CLASS API -//--------------------------------------------------------------------+ -void cush_init(void) -{ - tu_memclr(&custom_interface, sizeof(custom_interface_info_t) * CFG_TUH_DEVICE_MAX); -} - -tusb_error_t cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length) -{ - // FIXME quick hack to test lpc1k custom class with 2 bulk endpoints - uint8_t const *p_desc = (uint8_t const *) p_interface_desc; - p_desc = tu_desc_next(p_desc); - - //------------- Bulk Endpoints Descriptor -------------// - for(uint32_t i=0; i<2; i++) - { - tusb_desc_endpoint_t const *p_endpoint = (tusb_desc_endpoint_t const *) p_desc; - TU_ASSERT(TUSB_DESC_ENDPOINT == p_endpoint->bDescriptorType, TUSB_ERROR_INVALID_PARA); - - pipe_handle_t * p_pipe_hdl = ( p_endpoint->bEndpointAddress & TUSB_DIR_IN_MASK ) ? - &custom_interface[dev_addr-1].pipe_in : &custom_interface[dev_addr-1].pipe_out; - *p_pipe_hdl = usbh_edpt_open(dev_addr, p_endpoint, TUSB_CLASS_VENDOR_SPECIFIC); - TU_ASSERT ( pipehandle_is_valid(*p_pipe_hdl), TUSB_ERROR_HCD_OPEN_PIPE_FAILED ); - - p_desc = tu_desc_next(p_desc); - } - - (*p_length) = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t); - return TUSB_ERROR_NONE; -} - -void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event) -{ - -} - -void cush_close(uint8_t dev_addr) -{ - tusb_error_t err1, err2; - custom_interface_info_t * p_interface = &custom_interface[dev_addr-1]; - - // TODO re-consider to check pipe valid before calling pipe_close - if( pipehandle_is_valid( p_interface->pipe_in ) ) - { - err1 = hcd_pipe_close( p_interface->pipe_in ); - } - - if ( pipehandle_is_valid( p_interface->pipe_out ) ) - { - err2 = hcd_pipe_close( p_interface->pipe_out ); - } - - tu_memclr(p_interface, sizeof(custom_interface_info_t)); - - TU_ASSERT(err1 == TUSB_ERROR_NONE && err2 == TUSB_ERROR_NONE, (void) 0 ); -} - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.h b/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.h deleted file mode 100644 index acfebe7a..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/vendor/vendor_host.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_VENDOR_HOST_H_ -#define _TUSB_VENDOR_HOST_H_ - -#include "common/tusb_common.h" - -#ifdef __cplusplus - extern "C" { -#endif - -typedef struct { - pipe_handle_t pipe_in; - pipe_handle_t pipe_out; -}custom_interface_info_t; - -//--------------------------------------------------------------------+ -// USBH-CLASS DRIVER API -//--------------------------------------------------------------------+ -static inline bool tusbh_custom_is_mounted(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id) -{ - (void) vendor_id; // TODO check this later - (void) product_id; -// return (tusbh_device_get_mounted_class_flag(dev_addr) & TU_BIT(TUSB_CLASS_MAPPED_INDEX_END-1) ) != 0; - return false; -} - -bool tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length); -bool tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void cush_init(void); -bool cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length); -void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event); -void cush_close(uint8_t dev_addr); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_VENDOR_HOST_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/class/video/video.h b/test-devices/composite-stm32/lib/tinyusb/class/video/video.h deleted file mode 100644 index c0088c4f..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/video/video.h +++ /dev/null @@ -1,559 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2021 Koji KITAYAMA - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef TUSB_VIDEO_H_ -#define TUSB_VIDEO_H_ - -#include "common/tusb_common.h" - -// Table 3-19 Color Matching Descriptor -typedef enum { - VIDEO_COLOR_PRIMARIES_UNDEFINED = 0x00, - VIDEO_COLOR_PRIMARIES_BT709, // sRGB (default) - VIDEO_COLOR_PRIMARIES_BT470_2M, - VIDEO_COLOR_PRIMARIES_BT470_2BG, - VIDEO_COLOR_PRIMARIES_SMPTE170M, - VIDEO_COLOR_PRIMARIES_SMPTE240M, -} video_color_primaries_t; - -// Table 3-19 Color Matching Descriptor -typedef enum { - VIDEO_COLOR_XFER_CH_UNDEFINED = 0x00, - VIDEO_COLOR_XFER_CH_BT709, // default - VIDEO_COLOR_XFER_CH_BT470_2M, - VIDEO_COLOR_XFER_CH_BT470_2BG, - VIDEO_COLOR_XFER_CH_SMPTE170M, - VIDEO_COLOR_XFER_CH_SMPTE240M, - VIDEO_COLOR_XFER_CH_LINEAR, - VIDEO_COLOR_XFER_CH_SRGB, -} video_color_transfer_characteristics_t; - -// Table 3-19 Color Matching Descriptor -typedef enum { - VIDEO_COLOR_COEF_UNDEFINED = 0x00, - VIDEO_COLOR_COEF_BT709, - VIDEO_COLOR_COEF_FCC, - VIDEO_COLOR_COEF_BT470_2BG, - VIDEO_COLOR_COEF_SMPTE170M, // BT.601 default - VIDEO_COLOR_COEF_SMPTE240M, -} video_color_matrix_coefficients_t; - -/* 4.2.1.2 Request Error Code Control */ -typedef enum { - VIDEO_ERROR_NONE = 0, /* The request succeeded. */ - VIDEO_ERROR_NOT_READY, - VIDEO_ERROR_WRONG_STATE, - VIDEO_ERROR_POWER, - VIDEO_ERROR_OUT_OF_RANGE, - VIDEO_ERROR_INVALID_UNIT, - VIDEO_ERROR_INVALID_CONTROL, - VIDEO_ERROR_INVALID_REQUEST, - VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE, - VIDEO_ERROR_UNKNOWN = 0xFF, -} video_error_code_t; - -/* A.2 Interface Subclass */ -typedef enum { - VIDEO_SUBCLASS_UNDEFINED = 0x00, - VIDEO_SUBCLASS_CONTROL, - VIDEO_SUBCLASS_STREAMING, - VIDEO_SUBCLASS_INTERFACE_COLLECTION, -} video_subclass_type_t; - -/* A.3 Interface Protocol */ -typedef enum { - VIDEO_ITF_PROTOCOL_UNDEFINED = 0x00, - VIDEO_ITF_PROTOCOL_15, -} video_interface_protocol_code_t; - -/* A.5 Class-Specific VideoControl Interface Descriptor Subtypes */ -typedef enum { - VIDEO_CS_ITF_VC_UNDEFINED = 0x00, - VIDEO_CS_ITF_VC_HEADER, - VIDEO_CS_ITF_VC_INPUT_TERMINAL, - VIDEO_CS_ITF_VC_OUTPUT_TERMINAL, - VIDEO_CS_ITF_VC_SELECTOR_UNIT, - VIDEO_CS_ITF_VC_PROCESSING_UNIT, - VIDEO_CS_ITF_VC_EXTENSION_UNIT, - VIDEO_CS_ITF_VC_ENCODING_UNIT, - VIDEO_CS_ITF_VC_MAX, -} video_cs_vc_interface_subtype_t; - -/* A.6 Class-Specific VideoStreaming Interface Descriptor Subtypes */ -typedef enum { - VIDEO_CS_ITF_VS_UNDEFINED = 0x00, - VIDEO_CS_ITF_VS_INPUT_HEADER = 0x01, - VIDEO_CS_ITF_VS_OUTPUT_HEADER = 0x02, - VIDEO_CS_ITF_VS_STILL_IMAGE_FRAME = 0x03, - VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED = 0x04, - VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED = 0x05, - VIDEO_CS_ITF_VS_FORMAT_MJPEG = 0x06, - VIDEO_CS_ITF_VS_FRAME_MJPEG = 0x07, - VIDEO_CS_ITF_VS_FORMAT_MPEG2TS = 0x0A, - VIDEO_CS_ITF_VS_FORMAT_DV = 0x0C, - VIDEO_CS_ITF_VS_COLORFORMAT = 0x0D, - VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED = 0x10, - VIDEO_CS_ITF_VS_FRAME_FRAME_BASED = 0x11, - VIDEO_CS_ITF_VS_FORMAT_STREAM_BASED = 0x12, - VIDEO_CS_ITF_VS_FORMAT_H264 = 0x13, - VIDEO_CS_ITF_VS_FRAME_H264 = 0x14, - VIDEO_CS_ITF_VS_FORMAT_H264_SIMULCAST = 0x15, - VIDEO_CS_ITF_VS_FORMAT_VP8 = 0x16, - VIDEO_CS_ITF_VS_FRAME_VP8 = 0x17, - VIDEO_CS_ITF_VS_FORMAT_VP8_SIMULCAST = 0x18, -} video_cs_vs_interface_subtype_t; - -/* A.7. Class-Specific Endpoint Descriptor Subtypes */ -typedef enum { - VIDEO_CS_EP_UNDEFINED = 0x00, - VIDEO_CS_EP_GENERAL, - VIDEO_CS_EP_ENDPOINT, - VIDEO_CS_EP_INTERRUPT -} video_cs_ep_subtype_t; - -/* A.8 Class-Specific Request Codes */ -typedef enum { - VIDEO_REQUEST_UNDEFINED = 0x00, - VIDEO_REQUEST_SET_CUR = 0x01, - VIDEO_REQUEST_SET_CUR_ALL = 0x11, - VIDEO_REQUEST_GET_CUR = 0x81, - VIDEO_REQUEST_GET_MIN = 0x82, - VIDEO_REQUEST_GET_MAX = 0x83, - VIDEO_REQUEST_GET_RES = 0x84, - VIDEO_REQUEST_GET_LEN = 0x85, - VIDEO_REQUEST_GET_INFO = 0x86, - VIDEO_REQUEST_GET_DEF = 0x87, - VIDEO_REQUEST_GET_CUR_ALL = 0x91, - VIDEO_REQUEST_GET_MIN_ALL = 0x92, - VIDEO_REQUEST_GET_MAX_ALL = 0x93, - VIDEO_REQUEST_GET_RES_ALL = 0x94, - VIDEO_REQUEST_GET_DEF_ALL = 0x97 -} video_control_request_t; - -/* A.9.1 VideoControl Interface Control Selectors */ -typedef enum { - VIDEO_VC_CTL_UNDEFINED = 0x00, - VIDEO_VC_CTL_VIDEO_POWER_MODE, - VIDEO_VC_CTL_REQUEST_ERROR_CODE, -} video_interface_control_selector_t; - -/* A.9.8 VideoStreaming Interface Control Selectors */ -typedef enum { - VIDEO_VS_CTL_UNDEFINED = 0x00, - VIDEO_VS_CTL_PROBE, - VIDEO_VS_CTL_COMMIT, - VIDEO_VS_CTL_STILL_PROBE, - VIDEO_VS_CTL_STILL_COMMIT, - VIDEO_VS_CTL_STILL_IMAGE_TRIGGER, - VIDEO_VS_CTL_STREAM_ERROR_CODE, - VIDEO_VS_CTL_GENERATE_KEY_FRAME, - VIDEO_VS_CTL_UPDATE_FRAME_SEGMENT, - VIDEO_VS_CTL_SYNCH_DELAY_CONTROL, -} video_interface_streaming_selector_t; - -/* B. Terminal Types */ -typedef enum { - // Terminal - VIDEO_TT_VENDOR_SPECIFIC = 0x0100, - VIDEO_TT_STREAMING = 0x0101, - - // Input - VIDEO_ITT_VENDOR_SPECIFIC = 0x0200, - VIDEO_ITT_CAMERA = 0x0201, - VIDEO_ITT_MEDIA_TRANSPORT_INPUT = 0x0202, - - // Output - VIDEO_OTT_VENDOR_SPECIFIC = 0x0300, - VIDEO_OTT_DISPLAY = 0x0301, - VIDEO_OTT_MEDIA_TRANSPORT_OUTPUT = 0x0302, - - // External - VIDEO_ETT_VENDOR_SPEIFIC = 0x0400, - VIDEO_ETT_COMPOSITE_CONNECTOR = 0x0401, - VIDEO_ETT_SVIDEO_CONNECTOR = 0x0402, - VIDEO_ETT_COMPONENT_CONNECTOR = 0x0403, -} video_terminal_type_t; - -//--------------------------------------------------------------------+ -// Descriptors -//--------------------------------------------------------------------+ - -/* 2.3.4.2 */ -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint16_t bcdUVC; - uint16_t wTotalLength; - uint32_t dwClockFrequency; - uint8_t bInCollection; - uint8_t baInterfaceNr[]; -} tusb_desc_cs_video_ctl_itf_hdr_t; - -/* 2.4.3.3 */ -typedef struct TU_ATTR_PACKED { - uint8_t bHeaderLength; - union { - uint8_t bmHeaderInfo; - struct { - uint8_t FrameID: 1; - uint8_t EndOfFrame: 1; - uint8_t PresentationTime: 1; - uint8_t SourceClockReference: 1; - uint8_t PayloadSpecific: 1; - uint8_t StillImage: 1; - uint8_t Error: 1; - uint8_t EndOfHeader: 1; - }; - }; -} tusb_video_payload_header_t; - -/* 3.9.2.1 */ -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bNumFormats; - uint16_t wTotalLength; - uint8_t bEndpointAddress; - uint8_t bmInfo; - uint8_t bTerminalLink; - uint8_t bStillCaptureMethod; - uint8_t bTriggerSupport; - uint8_t bTriggerUsage; - uint8_t bControlSize; - uint8_t bmaControls[]; -} tusb_desc_cs_video_stm_itf_in_hdr_t; - -/* 3.9.2.2 */ -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bNumFormats; - uint16_t wTotalLength; - uint8_t bEndpointAddress; - uint8_t bTerminalLink; - uint8_t bControlSize; - uint8_t bmaControls[]; -} tusb_desc_cs_video_stm_itf_out_hdr_t; - -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bNumFormats; - uint16_t wTotalLength; - uint8_t bEndpointAddress; - union { - struct { - uint8_t bmInfo; - uint8_t bTerminalLink; - uint8_t bStillCaptureMethod; - uint8_t bTriggerSupport; - uint8_t bTriggerUsage; - uint8_t bControlSize; - uint8_t bmaControls[]; - } input; - struct { - uint8_t bEndpointAddress; - uint8_t bTerminalLink; - uint8_t bControlSize; - uint8_t bmaControls[]; - } output; - }; -} tusb_desc_cs_video_stm_itf_hdr_t; - -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bFormatIndex; - uint8_t bNumFrameDescriptors; - uint8_t guidFormat[16]; - uint8_t bBitsPerPixel; - uint8_t bDefaultFrameIndex; - uint8_t bAspectRatioX; - uint8_t bAspectRatioY; - uint8_t bmInterlaceFlags; - uint8_t bCopyProtect; -} tusb_desc_cs_video_fmt_uncompressed_t; - -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bFormatIndex; - uint8_t bNumFrameDescriptors; - uint8_t bmFlags; - uint8_t bDefaultFrameIndex; - uint8_t bAspectRatioX; - uint8_t bAspectRatioY; - uint8_t bmInterlaceFlags; - uint8_t bCopyProtect; -} tusb_desc_cs_video_fmt_mjpeg_t; - -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bFormatIndex; - uint32_t dwMaxVideoFrameBufferSize; /* deprecated */ - uint8_t bFormatType; -} tusb_desc_cs_video_fmt_dv_t; - -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bFormatIndex; - uint8_t bNumFrameDescriptors; - uint8_t guidFormat[16]; - uint8_t bBitsPerPixel; - uint8_t bDefaultFrameIndex; - uint8_t bAspectRatioX; - uint8_t bAspectRatioY; - uint8_t bmInterlaceFlags; - uint8_t bCopyProtect; - uint8_t bVaribaleSize; -} tusb_desc_cs_video_fmt_frame_based_t; - -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bFrameIndex; - uint8_t bmCapabilities; - uint16_t wWidth; - uint16_t wHeight; - uint32_t dwMinBitRate; - uint32_t dwMaxBitRate; - uint32_t dwMaxVideoFrameBufferSize; /* deprecated */ - uint32_t dwDefaultFrameInterval; - uint8_t bFrameIntervalType; - uint32_t dwFrameInterval[]; -} tusb_desc_cs_video_frm_uncompressed_t; - -typedef tusb_desc_cs_video_frm_uncompressed_t tusb_desc_cs_video_frm_mjpeg_t; - -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bFrameIndex; - uint8_t bmCapabilities; - uint16_t wWidth; - uint16_t wHeight; - uint32_t dwMinBitRate; - uint32_t dwMaxBitRate; - uint32_t dwDefaultFrameInterval; - uint8_t bFrameIntervalType; - uint32_t dwBytesPerLine; - uint32_t dwFrameInterval[]; -} tusb_desc_cs_video_frm_frame_based_t; - -//--------------------------------------------------------------------+ -// Requests -//--------------------------------------------------------------------+ - -/* 4.3.1.1 */ -typedef struct TU_ATTR_PACKED { - union { - uint8_t bmHint; - struct TU_ATTR_PACKED { - uint16_t dwFrameInterval: 1; - uint16_t wKeyFrameRatel : 1; - uint16_t wPFrameRate : 1; - uint16_t wCompQuality : 1; - uint16_t wCompWindowSize: 1; - uint16_t : 0; - } Hint; - }; - uint8_t bFormatIndex; - uint8_t bFrameIndex; - uint32_t dwFrameInterval; - uint16_t wKeyFrameRate; - uint16_t wPFrameRate; - uint16_t wCompQuality; - uint16_t wCompWindowSize; - uint16_t wDelay; - uint32_t dwMaxVideoFrameSize; - uint32_t dwMaxPayloadTransferSize; - uint32_t dwClockFrequency; - union { - uint8_t bmFramingInfo; - struct TU_ATTR_PACKED { - uint8_t FrameID : 1; - uint8_t EndOfFrame: 1; - uint8_t EndOfSlice: 1; - uint8_t : 0; - } FramingInfo; - }; - uint8_t bPreferedVersion; - uint8_t bMinVersion; - uint8_t bMaxVersion; - uint8_t bUsage; - uint8_t bBitDepthLuma; - uint8_t bmSettings; - uint8_t bMaxNumberOfRefFramesPlus1; - uint16_t bmRateControlModes; - uint64_t bmLayoutPerStream; -} video_probe_and_commit_control_t; - -TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not correct"); - -#define TUD_VIDEO_DESC_IAD_LEN 8 -#define TUD_VIDEO_DESC_STD_VC_LEN 9 -#define TUD_VIDEO_DESC_CS_VC_LEN 12 -#define TUD_VIDEO_DESC_INPUT_TERM_LEN 8 -#define TUD_VIDEO_DESC_OUTPUT_TERM_LEN 9 -#define TUD_VIDEO_DESC_CAMERA_TERM_LEN 18 -#define TUD_VIDEO_DESC_STD_VS_LEN 9 -#define TUD_VIDEO_DESC_CS_VS_IN_LEN 13 -#define TUD_VIDEO_DESC_CS_VS_OUT_LEN 9 -#define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN 27 -#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN 11 -#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN 38 -#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN 26 -#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN 38 -#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN 26 -#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN 6 - -/* 2.2 compression formats */ -#define TUD_VIDEO_GUID_YUY2 0x59,0x55,0x59,0x32,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 -#define TUD_VIDEO_GUID_NV12 0x4E,0x56,0x31,0x32,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 -#define TUD_VIDEO_GUID_M420 0x4D,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 -#define TUD_VIDEO_GUID_I420 0x49,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 - -#define TUD_VIDEO_DESC_IAD(_firstitfs, _nitfs, _stridx) \ - TUD_VIDEO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, \ - _firstitfs, _nitfs, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_INTERFACE_COLLECTION, \ - VIDEO_ITF_PROTOCOL_UNDEFINED, _stridx - -#define TUD_VIDEO_DESC_STD_VC(_itfnum, _nEPs, _stridx) \ - TUD_VIDEO_DESC_STD_VC_LEN, TUSB_DESC_INTERFACE, _itfnum, /* fixed to zero */ 0x00, \ - _nEPs, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_CONTROL, VIDEO_ITF_PROTOCOL_15, _stridx - -/* 3.7.2 */ -#define TUD_VIDEO_DESC_CS_VC(_bcdUVC, _totallen, _clkfreq, ...) \ - TUD_VIDEO_DESC_CS_VC_LEN + (TU_ARGS_NUM(__VA_ARGS__)), TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_HEADER, \ - U16_TO_U8S_LE(_bcdUVC), U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VC_LEN + (TU_ARGS_NUM(__VA_ARGS__))), \ - U32_TO_U8S_LE(_clkfreq), TU_ARGS_NUM(__VA_ARGS__), __VA_ARGS__ - -/* 3.7.2.1 */ -#define TUD_VIDEO_DESC_INPUT_TERM(_tid, _tt, _at, _stridx) \ - TUD_VIDEO_DESC_INPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_INPUT_TERMINAL, \ - _tid, U16_TO_U8S_LE(_tt), _at, _stridx - -/* 3.7.2.2 */ -#define TUD_VIDEO_DESC_OUTPUT_TERM(_tid, _tt, _at, _srcid, _stridx) \ - TUD_VIDEO_DESC_OUTPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_OUTPUT_TERMINAL, \ - _tid, U16_TO_U8S_LE(_tt), _at, _srcid, _stridx - -/* 3.7.2.3 */ -#define TUD_VIDEO_DESC_CAMERA_TERM(_tid, _at, _stridx, _focal_min, _focal_max, _focal, _ctls) \ - TUD_VIDEO_DESC_CAMERA_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_INPUT_TERMINAL, \ - _tid, U16_TO_U8S_LE(VIDEO_ITT_CAMERA), _at, _stridx, \ - U16_TO_U8S_LE(_focal_min), U16_TO_U8S_LE(_focal_max), U16_TO_U8S_LE(_focal), 3, \ - TU_U32_BYTE0(_ctls), TU_U32_BYTE1(_ctls), TU_U32_BYTE2(_ctls) - -/* 3.9.1 */ -#define TUD_VIDEO_DESC_STD_VS(_itfnum, _alt, _epn, _stridx) \ - TUD_VIDEO_DESC_STD_VS_LEN, TUSB_DESC_INTERFACE, _itfnum, _alt, \ - _epn, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_STREAMING, VIDEO_ITF_PROTOCOL_15, _stridx - -/* 3.9.2.1 */ -#define TUD_VIDEO_DESC_CS_VS_INPUT(_numfmt, _totallen, _ep, _inf, _termlnk, _sticaptmeth, _trgspt, _trgusg, ...) \ - TUD_VIDEO_DESC_CS_VS_IN_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__)), TUSB_DESC_CS_INTERFACE, \ - VIDEO_CS_ITF_VS_INPUT_HEADER, _numfmt, \ - U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VS_IN_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__))), \ - _ep, _inf, _termlnk, _sticaptmeth, _trgspt, _trgusg, (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ - -/* 3.9.2.2 */ -#define TUD_VIDEO_DESC_CS_VS_OUTPUT(_numfmt, _totallen, _ep, _inf, _termlnk, ...) \ - TUD_VIDEO_DESC_CS_VS_OUT_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__)), TUSB_DESC_CS_INTERFACE, \ - VIDEO_CS_ITF_VS_OUTPUT_HEADER, _numfmt, \ - U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VS_OUT_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__))), \ - _ep, _inf, _termlnk, (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ - -/* Uncompressed 3.1.1 */ -#define TUD_VIDEO_GUID(_g0,_g1,_g2,_g3,_g4,_g5,_g6,_g7,_g8,_g9,_g10,_g11,_g12,_g13,_g14,_g15) _g0,_g1,_g2,_g3,_g4,_g5,_g6,_g7,_g8,_g9,_g10,_g11,_g12,_g13,_g14,_g15 - -#define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR(_fmtidx, _numfrmdesc, \ - _guid, _bitsperpix, _frmidx, _asrx, _asry, _interlace, _cp) \ - TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED, \ - _fmtidx, _numfrmdesc, TUD_VIDEO_GUID(_guid), \ - _bitsperpix, _frmidx, _asrx, _asry, _interlace, _cp - -/* Uncompressed 3.1.2 Table 3-3 */ -#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, _minfrminterval, _maxfrminterval, _frmintervalstep) \ - TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, \ - _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ - U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), 0, \ - U32_TO_U8S_LE(_minfrminterval), U32_TO_U8S_LE(_maxfrminterval), U32_TO_U8S_LE(_frmintervalstep) - -/* Uncompressed 3.1.2 Table 3-4 */ -#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, ...) \ - TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN + (TU_ARGS_NUM(__VA_ARGS__)) * 4, \ - TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, \ - _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ - U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ - -/* Motion-JPEG 3.1.1 Table 3-1 */ -#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG(_fmtidx, _numfrmdesc, _fixed_sz, _frmidx, _asrx, _asry, _interlace, _cp) \ - TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_MJPEG, \ - _fmtidx, _numfrmdesc, _fixed_sz, _frmidx, _asrx, _asry, _interlace, _cp - -/* Motion-JPEG 3.1.1 Table 3-2 and 3-3 */ -#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, _minfrminterval, _maxfrminterval, _frmintervalstep) \ - TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_MJPEG, \ - _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ - U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), 0, \ - U32_TO_U8S_LE(_minfrminterval), U32_TO_U8S_LE(_maxfrminterval), U32_TO_U8S_LE(_frmintervalstep) - -/* Motion-JPEG 3.1.1 Table 3-2 and 3-4 */ -#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, ...) \ - TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN + (TU_ARGS_NUM(__VA_ARGS__)) * 4, \ - TUSB_DESC_CS_INTERFACE, VIDEO_CS_VS_INTERFACE_FRAME_MJPEG, \ - _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ - U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ - -/* 3.9.2.6 */ -#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(_color, _trns, _mat) \ - TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN, \ - TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_COLORFORMAT, \ - _color, _trns, _mat - -/* 3.10.1.1 */ -#define TUD_VIDEO_DESC_EP_ISO(_ep, _epsize, _ep_interval) \ - 7, TUSB_DESC_ENDPOINT, _ep, (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS),\ - U16_TO_U8S_LE(_epsize), _ep_interval - -/* 3.10.1.2 */ -#define TUD_VIDEO_DESC_EP_BULK(_ep, _epsize, _ep_interval) \ - 7, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), _ep_interval - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/video/video_device.c b/test-devices/composite-stm32/lib/tinyusb/class/video/video_device.c deleted file mode 100644 index d6e98602..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/video/video_device.c +++ /dev/null @@ -1,1257 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2021 Koji KITAYAMA - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_VIDEO && CFG_TUD_VIDEO_STREAMING) - -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "video_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -typedef struct { - tusb_desc_interface_t std; - tusb_desc_cs_video_ctl_itf_hdr_t ctl; -} tusb_desc_vc_itf_t; - -typedef struct { - tusb_desc_interface_t std; - tusb_desc_cs_video_stm_itf_hdr_t stm; -} tusb_desc_vs_itf_t; - -typedef union { - tusb_desc_cs_video_ctl_itf_hdr_t ctl; - tusb_desc_cs_video_stm_itf_hdr_t stm; -} tusb_desc_video_itf_hdr_t; - -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubtype; - uint8_t bEntityId; -} tusb_desc_cs_video_entity_itf_t; - -typedef union { - struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bFormatIndex; - uint8_t bNumFrameDescriptors; - }; - tusb_desc_cs_video_fmt_uncompressed_t uncompressed; - tusb_desc_cs_video_fmt_mjpeg_t mjpeg; - tusb_desc_cs_video_fmt_frame_based_t frame_based; -} tusb_desc_cs_video_fmt_t; - -typedef union { - struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bFrameIndex; - uint8_t bmCapabilities; - uint16_t wWidth; - uint16_t wHeight; - }; - tusb_desc_cs_video_frm_uncompressed_t uncompressed; - tusb_desc_cs_video_frm_mjpeg_t mjpeg; - tusb_desc_cs_video_frm_frame_based_t frame_based; -} tusb_desc_cs_video_frm_t; - -/* video streaming interface */ -typedef struct TU_ATTR_PACKED { - uint8_t index_vc; /* index of bound video control interface */ - uint8_t index_vs; /* index from the video control interface */ - struct { - uint16_t beg; /* Offset of the begging of video streaming interface descriptor */ - uint16_t end; /* Offset of the end of video streaming interface descriptor */ - uint16_t cur; /* Offset of the current settings */ - uint16_t ep[2]; /* Offset of endpoint descriptors. 0: streaming, 1: still capture */ - } desc; - uint8_t *buffer; /* frame buffer. assume linear buffer. no support for stride access */ - uint32_t bufsize; /* frame buffer size */ - uint32_t offset; /* offset for the next payload transfer */ - uint32_t max_payload_transfer_size; - uint8_t error_code;/* error code */ - /*------------- From this point, data is not cleared by bus reset -------------*/ - CFG_TUSB_MEM_ALIGN uint8_t ep_buf[CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE]; /* EP transfer buffer for streaming */ -} videod_streaming_interface_t; - -/* video control interface */ -typedef struct TU_ATTR_PACKED { - uint8_t const *beg; /* The head of the first video control interface descriptor */ - uint16_t len; /* Byte length of the descriptors */ - uint16_t cur; /* offset for current video control interface */ - uint8_t stm[CFG_TUD_VIDEO_STREAMING]; /* Indices of streaming interface */ - uint8_t error_code; /* error code */ - uint8_t power_mode; - - /*------------- From this point, data is not cleared by bus reset -------------*/ - // CFG_TUSB_MEM_ALIGN uint8_t ctl_buf[64]; /* EP transfer buffer for interrupt transfer */ - -} videod_interface_t; - -#define ITF_STM_MEM_RESET_SIZE offsetof(videod_streaming_interface_t, ep_buf) - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION tu_static videod_interface_t _videod_itf[CFG_TUD_VIDEO]; -CFG_TUSB_MEM_SECTION tu_static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING]; - -tu_static uint8_t const _cap_get = 0x1u; /* support for GET */ -tu_static uint8_t const _cap_get_set = 0x3u; /* support for GET and SET */ - -/** Get interface number from the interface descriptor - * - * @param[in] desc interface descriptor - * - * @return bInterfaceNumber */ -static inline uint8_t _desc_itfnum(void const *desc) -{ - return ((uint8_t const*)desc)[2]; -} - -/** Get endpoint address from the endpoint descriptor - * - * @param[in] desc endpoint descriptor - * - * @return bEndpointAddress */ -static inline uint8_t _desc_ep_addr(void const *desc) -{ - return ((uint8_t const*)desc)[2]; -} - -/** Get instance of streaming interface - * - * @param[in] ctl_idx instance number of video control - * @param[in] stm_idx index number of streaming interface - * - * @return instance */ -static videod_streaming_interface_t* _get_instance_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) -{ - videod_interface_t *ctl = &_videod_itf[ctl_idx]; - if (!ctl->beg) return NULL; - videod_streaming_interface_t *stm = &_videod_streaming_itf[ctl->stm[stm_idx]]; - if (!stm->desc.beg) return NULL; - return stm; -} - -static tusb_desc_vc_itf_t const* _get_desc_vc(videod_interface_t const *self) -{ - return (tusb_desc_vc_itf_t const *)(self->beg + self->cur); -} - -static tusb_desc_vs_itf_t const* _get_desc_vs(videod_streaming_interface_t const *self) -{ - if (!self->desc.cur) return NULL; - uint8_t const *desc = _videod_itf[self->index_vc].beg; - return (tusb_desc_vs_itf_t const*)(desc + self->desc.cur); -} - -/** Find the first descriptor of a given type - * - * @param[in] beg The head of descriptor byte array. - * @param[in] end The tail of descriptor byte array. - * @param[in] desc_type The target descriptor type. - * - * @return The pointer for interface descriptor. - * @retval end did not found interface descriptor */ -static void const* _find_desc(void const *beg, void const *end, uint_fast8_t desc_type) -{ - void const *cur = beg; - while ((cur < end) && (desc_type != tu_desc_type(cur))) { - cur = tu_desc_next(cur); - } - return cur; -} - -/** Find the first descriptor specified by the arguments - * - * @param[in] beg The head of descriptor byte array. - * @param[in] end The tail of descriptor byte array. - * @param[in] desc_type The target descriptor type - * @param[in] element_0 The target element following the desc_type - * @param[in] element_1 The target element following the element_0 - * - * @return The pointer for interface descriptor. - * @retval end did not found interface descriptor */ -static void const* _find_desc_3(void const *beg, void const *end, - uint_fast8_t desc_type, - uint_fast8_t element_0, - uint_fast8_t element_1) -{ - for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, desc_type)) { - uint8_t const *p = (uint8_t const *)cur; - if ((p[2] == element_0) && (p[3] == element_1)) { - return cur; - } - cur = tu_desc_next(cur); - } - return end; -} - -/** Return the next interface descriptor which has another interface number. - * - * @param[in] beg The head of descriptor byte array. - * @param[in] end The tail of descriptor byte array. - * - * @return The pointer for interface descriptor. - * @retval end did not found interface descriptor */ -static void const* _next_desc_itf(void const *beg, void const *end) -{ - void const *cur = beg; - uint_fast8_t itfnum = ((tusb_desc_interface_t const*)cur)->bInterfaceNumber; - while ((cur < end) && - (itfnum == ((tusb_desc_interface_t const*)cur)->bInterfaceNumber)) { - cur = _find_desc(tu_desc_next(cur), end, TUSB_DESC_INTERFACE); - } - return cur; -} - -/** Find the first interface descriptor with the specified interface number and alternate setting number. - * - * @param[in] beg The head of descriptor byte array. - * @param[in] end The tail of descriptor byte array. - * @param[in] itfnum The target interface number. - * @param[in] altnum The target alternate setting number. - * - * @return The pointer for interface descriptor. - * @retval end did not found interface descriptor */ -static inline uint8_t const* _find_desc_itf(void const *beg, void const *end, uint_fast8_t itfnum, uint_fast8_t altnum) -{ - return (uint8_t const*) _find_desc_3(beg, end, TUSB_DESC_INTERFACE, itfnum, altnum); -} - -/** Find the first endpoint descriptor belonging to the current interface descriptor. - * - * The search range is from `beg` to `end` or the next interface descriptor. - * - * @param[in] beg The head of descriptor byte array. - * @param[in] end The tail of descriptor byte array. - * - * @return The pointer for endpoint descriptor. - * @retval end did not found endpoint descriptor */ -static void const* _find_desc_ep(void const *beg, void const *end) -{ - for (void const *cur = beg; cur < end; cur = tu_desc_next(cur)) { - uint_fast8_t desc_type = tu_desc_type(cur); - if (TUSB_DESC_ENDPOINT == desc_type) return cur; - if (TUSB_DESC_INTERFACE == desc_type) break; - } - return end; -} - -/** Return the end of the video control descriptor. */ -static inline void const* _end_of_control_descriptor(void const *desc) -{ - tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const *)desc; - return ((uint8_t const*) desc) + vc->std.bLength + tu_le16toh(vc->ctl.wTotalLength); -} - -/** Find the first entity descriptor with the entity ID - * specified by the argument belonging to the current video control descriptor. - * - * @param[in] desc The video control interface descriptor. - * @param[in] entityid The target entity id. - * - * @return The pointer for interface descriptor. - * @retval end did not found interface descriptor */ -static void const* _find_desc_entity(void const *desc, uint_fast8_t entityid) -{ - void const *end = _end_of_control_descriptor(desc); - for (void const *cur = desc; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) { - tusb_desc_cs_video_entity_itf_t const *itf = (tusb_desc_cs_video_entity_itf_t const *)cur; - if ((VIDEO_CS_ITF_VC_INPUT_TERMINAL <= itf->bDescriptorSubtype - && itf->bDescriptorSubtype < VIDEO_CS_ITF_VC_MAX) - && itf->bEntityId == entityid) { - return itf; - } - cur = tu_desc_next(cur); - } - return end; -} - -/** Return the end of the video streaming descriptor. */ -static inline void const* _end_of_streaming_descriptor(void const *desc) -{ - tusb_desc_vs_itf_t const *vs = (tusb_desc_vs_itf_t const *)desc; - return ((uint8_t const*) desc) + vs->std.bLength + tu_le16toh(vs->stm.wTotalLength); -} - -/** Find the first format descriptor with the specified format number. */ -static inline void const *_find_desc_format(void const *beg, void const *end, uint_fast8_t fmtnum) -{ - for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) { - uint8_t const *p = (uint8_t const *)cur; - uint_fast8_t fmt = p[2]; - if ((fmt == VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED || - fmt == VIDEO_CS_ITF_VS_FORMAT_MJPEG || - fmt == VIDEO_CS_ITF_VS_FORMAT_DV || - fmt == VIDEO_CS_ITF_VS_FRAME_FRAME_BASED) && - fmtnum == p[3]) { - return cur; - } - cur = tu_desc_next(cur); - } - return end; -} - -/** Find the first frame descriptor with the specified format number. */ -static inline void const *_find_desc_frame(void const *beg, void const *end, uint_fast8_t frmnum) -{ - for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) { - uint8_t const *p = (uint8_t const *)cur; - uint_fast8_t frm = p[2]; - if ((frm == VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED || - frm == VIDEO_CS_ITF_VS_FRAME_MJPEG || - frm == VIDEO_CS_ITF_VS_FRAME_FRAME_BASED) && - frmnum == p[3]) { - return cur; - } - cur = tu_desc_next(cur); - } - return end; -} - -/** Set uniquely determined values to variables that have not been set - * - * @param[in,out] param Target */ -static bool _update_streaming_parameters(videod_streaming_interface_t const *stm, - video_probe_and_commit_control_t *param) -{ - tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); - uint_fast8_t fmtnum = param->bFormatIndex; - TU_ASSERT(vs && fmtnum <= vs->stm.bNumFormats); - if (!fmtnum) { - if (1 < vs->stm.bNumFormats) return true; /* Need to negotiate all variables. */ - fmtnum = 1; - param->bFormatIndex = 1; - } - - /* Set the parameters determined by the format */ - param->wKeyFrameRate = 1; - param->wPFrameRate = 0; - param->wCompWindowSize = 1; /* GOP size? */ - param->wDelay = 0; /* milliseconds */ - param->dwClockFrequency = 27000000; /* same as MPEG-2 system time clock */ - param->bmFramingInfo = 0x3; /* enables FrameID and EndOfFrame */ - param->bPreferedVersion = 1; - param->bMinVersion = 1; - param->bMaxVersion = 1; - param->bUsage = 0; - param->bBitDepthLuma = 8; - - void const *end = _end_of_streaming_descriptor(vs); - tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); - TU_ASSERT(fmt != end); - - switch (fmt->bDescriptorSubType) { - case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED: - param->wCompQuality = 1; /* 1 to 10000 */ - break; - case VIDEO_CS_ITF_VS_FORMAT_MJPEG: - break; - default: return false; - } - - uint_fast8_t frmnum = param->bFrameIndex; - TU_ASSERT(frmnum <= fmt->bNumFrameDescriptors); - if (!frmnum) { - if (1 < fmt->bNumFrameDescriptors) return true; - frmnum = 1; - param->bFrameIndex = 1; - } - tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); - TU_ASSERT(frm != end); - - /* Set the parameters determined by the frame */ - uint_fast32_t frame_size = param->dwMaxVideoFrameSize; - if (!frame_size) { - switch (fmt->bDescriptorSubType) { - case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED: - frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->uncompressed.bBitsPerPixel / 8; - break; - case VIDEO_CS_ITF_VS_FORMAT_MJPEG: - frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */ - break; - default: break; - } - param->dwMaxVideoFrameSize = frame_size; - } - - uint_fast32_t interval = param->dwFrameInterval; - if (!interval) { - if ((1 < frm->uncompressed.bFrameIntervalType) || - ((0 == frm->uncompressed.bFrameIntervalType) && - (frm->uncompressed.dwFrameInterval[1] != frm->uncompressed.dwFrameInterval[0]))) { - return true; - } - interval = frm->uncompressed.dwFrameInterval[0]; - param->dwFrameInterval = interval; - } - uint_fast32_t interval_ms = interval / 10000; - TU_ASSERT(interval_ms); - uint_fast32_t payload_size = (frame_size + interval_ms - 1) / interval_ms + 2; - if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) - payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE; - param->dwMaxPayloadTransferSize = payload_size; - return true; -} - -/** Set the minimum, maximum, default values or resolutions to variables which need to negotiate with the host - * - * @param[in] request GET_MAX, GET_MIN, GET_RES or GET_DEF - * @param[in,out] param Target - */ -static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *stm, uint_fast8_t request, - video_probe_and_commit_control_t *param) -{ - uint_fast8_t const fmtnum = param->bFormatIndex; - if (!fmtnum) { - switch (request) { - case VIDEO_REQUEST_GET_MAX: - if (_get_desc_vs(stm)) - param->bFormatIndex = _get_desc_vs(stm)->stm.bNumFormats; - break; - case VIDEO_REQUEST_GET_MIN: - case VIDEO_REQUEST_GET_DEF: - param->bFormatIndex = 1; - break; - default: return false; - } - /* Set the parameters determined by the format */ - param->wKeyFrameRate = 1; - param->wPFrameRate = 0; - param->wCompQuality = 1; /* 1 to 10000 */ - param->wCompWindowSize = 1; /* GOP size? */ - param->wDelay = 0; /* milliseconds */ - param->dwClockFrequency = 27000000; /* same as MPEG-2 system time clock */ - param->bmFramingInfo = 0x3; /* enables FrameID and EndOfFrame */ - param->bPreferedVersion = 1; - param->bMinVersion = 1; - param->bMaxVersion = 1; - param->bUsage = 0; - param->bBitDepthLuma = 8; - return true; - } - - uint_fast8_t frmnum = param->bFrameIndex; - if (!frmnum) { - tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); - TU_ASSERT(vs); - void const *end = _end_of_streaming_descriptor(vs); - tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); - switch (request) { - case VIDEO_REQUEST_GET_MAX: - frmnum = fmt->bNumFrameDescriptors; - break; - case VIDEO_REQUEST_GET_MIN: - frmnum = 1; - break; - case VIDEO_REQUEST_GET_DEF: - switch (fmt->bDescriptorSubType) { - case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED: - frmnum = fmt->uncompressed.bDefaultFrameIndex; - break; - case VIDEO_CS_ITF_VS_FORMAT_MJPEG: - frmnum = fmt->mjpeg.bDefaultFrameIndex; - break; - default: return false; - } - break; - default: return false; - } - param->bFrameIndex = (uint8_t)frmnum; - /* Set the parameters determined by the frame */ - tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); - uint_fast32_t frame_size; - switch (fmt->bDescriptorSubType) { - case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED: - frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->uncompressed.bBitsPerPixel / 8; - break; - case VIDEO_CS_ITF_VS_FORMAT_MJPEG: - frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */ - break; - default: return false; - } - param->dwMaxVideoFrameSize = frame_size; - return true; - } - - if (!param->dwFrameInterval) { - tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); - TU_ASSERT(vs); - void const *end = _end_of_streaming_descriptor(vs); - tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); - tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); - - uint_fast32_t interval, interval_ms; - switch (request) { - case VIDEO_REQUEST_GET_MAX: - { - uint_fast32_t min_interval, max_interval; - uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType; - max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1]; - min_interval = frm->uncompressed.dwFrameInterval[0]; - interval = max_interval; - interval_ms = min_interval / 10000; - } - break; - case VIDEO_REQUEST_GET_MIN: - { - uint_fast32_t min_interval, max_interval; - uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType; - max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1]; - min_interval = frm->uncompressed.dwFrameInterval[0]; - interval = min_interval; - interval_ms = max_interval / 10000; - } - break; - case VIDEO_REQUEST_GET_DEF: - interval = frm->uncompressed.dwDefaultFrameInterval; - interval_ms = interval / 10000; - break; - case VIDEO_REQUEST_GET_RES: - { - uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType; - if (num_intervals) { - interval = 0; - } else { - interval = frm->uncompressed.dwFrameInterval[2]; - interval_ms = interval / 10000; - } - } - break; - default: return false; - } - param->dwFrameInterval = interval; - if (!interval) { - param->dwMaxPayloadTransferSize = 0; - } else { - uint_fast32_t frame_size = param->dwMaxVideoFrameSize; - uint_fast32_t payload_size; - if (!interval_ms) { - payload_size = frame_size + 2; - } else { - payload_size = (frame_size + interval_ms - 1) / interval_ms + 2; - } - if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) - payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE; - param->dwMaxPayloadTransferSize = payload_size; - } - return true; - } - return true; -} - -/** Close current video control interface. - * - * @param[in,out] self Video control interface context. - * @param[in] altnum The target alternate setting number. */ -static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self) -{ - tusb_desc_vc_itf_t const *vc = _get_desc_vc(self); - - /* The next descriptor after the class-specific VC interface header descriptor. */ - void const *cur = (uint8_t const*)vc + vc->std.bLength + vc->ctl.bLength; - - /* The end of the video control interface descriptor. */ - void const *end = _end_of_control_descriptor(vc); - if (vc->std.bNumEndpoints) { - /* Find the notification endpoint descriptor. */ - cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT); - TU_ASSERT(cur < end); - tusb_desc_endpoint_t const *notif = (tusb_desc_endpoint_t const *)cur; - usbd_edpt_close(rhport, notif->bEndpointAddress); - } - self->cur = 0; - return true; -} - -/** Set the alternate setting to own video control interface. - * - * @param[in,out] self Video control interface context. - * @param[in] altnum The target alternate setting number. */ -static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t altnum) -{ - TU_LOG2(" open VC %d\n", altnum); - uint8_t const *beg = self->beg; - uint8_t const *end = beg + self->len; - - /* The first descriptor is a video control interface descriptor. */ - uint8_t const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); - TU_LOG2(" cur %d\n", cur - beg); - TU_VERIFY(cur < end); - - tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const *)cur; - TU_LOG2(" bInCollection %d\n", vc->ctl.bInCollection); - /* Support for up to 2 streaming interfaces only. */ - TU_ASSERT(vc->ctl.bInCollection <= CFG_TUD_VIDEO_STREAMING); - - /* Update to point the end of the video control interface descriptor. */ - end = _end_of_control_descriptor(cur); - - /* Advance to the next descriptor after the class-specific VC interface header descriptor. */ - cur += vc->std.bLength + vc->ctl.bLength; - TU_LOG2(" bNumEndpoints %d\n", vc->std.bNumEndpoints); - /* Open the notification endpoint if it exist. */ - if (vc->std.bNumEndpoints) { - /* Support for 1 endpoint only. */ - TU_VERIFY(1 == vc->std.bNumEndpoints); - /* Find the notification endpoint descriptor. */ - cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT); - TU_VERIFY(cur < end); - tusb_desc_endpoint_t const *notif = (tusb_desc_endpoint_t const *)cur; - /* Open the notification endpoint */ - TU_ASSERT(usbd_edpt_open(rhport, notif)); - } - self->cur = (uint16_t) ((uint8_t const*)vc - beg); - return true; -} - -/** Set the alternate setting to own video streaming interface. - * - * @param[in,out] stm Streaming interface context. - * @param[in] altnum The target alternate setting number. */ -static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint_fast8_t altnum) -{ - uint_fast8_t i; - TU_LOG2(" reopen VS %d\n", altnum); - uint8_t const *desc = _videod_itf[stm->index_vc].beg; - - /* Close endpoints of previous settings. */ - for (i = 0; i < TU_ARRAY_SIZE(stm->desc.ep); ++i) { - uint_fast16_t ofs_ep = stm->desc.ep[i]; - if (!ofs_ep) break; - uint8_t ep_adr = _desc_ep_addr(desc + ofs_ep); - usbd_edpt_close(rhport, ep_adr); - stm->desc.ep[i] = 0; - TU_LOG2(" close EP%02x\n", ep_adr); - } - - /* clear transfer management information */ - stm->buffer = NULL; - stm->bufsize = 0; - stm->offset = 0; - - /* Find a alternate interface */ - uint8_t const *beg = desc + stm->desc.beg; - uint8_t const *end = desc + stm->desc.end; - uint8_t const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); - TU_VERIFY(cur < end); - - uint_fast8_t numeps = ((tusb_desc_interface_t const *)cur)->bNumEndpoints; - TU_ASSERT(numeps <= TU_ARRAY_SIZE(stm->desc.ep)); - stm->desc.cur = (uint16_t) (cur - desc); /* Save the offset of the new settings */ - if (!altnum) { - /* initialize streaming settings */ - stm->max_payload_transfer_size = 0; - video_probe_and_commit_control_t *param = - (video_probe_and_commit_control_t *)&stm->ep_buf; - tu_memclr(param, sizeof(*param)); - TU_LOG2(" done 0\n"); - return _update_streaming_parameters(stm, param); - } - /* Open endpoints of the new settings. */ - for (i = 0, cur = tu_desc_next(cur); i < numeps; ++i, cur = tu_desc_next(cur)) { - cur = _find_desc_ep(cur, end); - TU_ASSERT(cur < end); - tusb_desc_endpoint_t const *ep = (tusb_desc_endpoint_t const*)cur; - if (!stm->max_payload_transfer_size) { - video_probe_and_commit_control_t const *param = (video_probe_and_commit_control_t const*)&stm->ep_buf; - uint_fast32_t max_size = param->dwMaxPayloadTransferSize; - if ((TUSB_XFER_ISOCHRONOUS == ep->bmAttributes.xfer) && - (tu_edpt_packet_size(ep) < max_size)) - { - /* FS must be less than or equal to max packet size */ - return false; - } - /* Set the negotiated value */ - stm->max_payload_transfer_size = max_size; - } - TU_ASSERT(usbd_edpt_open(rhport, ep)); - stm->desc.ep[i] = (uint16_t) (cur - desc); - TU_LOG2(" open EP%02x\n", _desc_ep_addr(cur)); - } - /* initialize payload header */ - tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf; - hdr->bHeaderLength = sizeof(*hdr); - hdr->bmHeaderInfo = 0; - - TU_LOG2(" done\n"); - return true; -} - -/** Prepare the next packet payload. */ -static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm) -{ - uint_fast16_t remaining = stm->bufsize - stm->offset; - uint_fast16_t hdr_len = stm->ep_buf[0]; - uint_fast16_t pkt_len = stm->max_payload_transfer_size; - if (hdr_len + remaining < pkt_len) { - pkt_len = hdr_len + remaining; - } - uint_fast16_t data_len = pkt_len - hdr_len; - memcpy(&stm->ep_buf[hdr_len], stm->buffer + stm->offset, data_len); - stm->offset += data_len; - remaining -= data_len; - if (!remaining) { - tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf; - hdr->EndOfFrame = 1; - } - return hdr_len + data_len; -} - -/** Handle a standard request to the video control interface. */ -static int handle_video_ctl_std_req(uint8_t rhport, uint8_t stage, - tusb_control_request_t const *request, - uint_fast8_t ctl_idx) -{ - switch (request->bRequest) { - case TUSB_REQ_GET_INTERFACE: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); - tusb_desc_vc_itf_t const *vc = _get_desc_vc(&_videod_itf[ctl_idx]); - TU_VERIFY(vc, VIDEO_ERROR_UNKNOWN); - - uint8_t alt_num = vc->std.bAlternateSetting; - - TU_VERIFY(tud_control_xfer(rhport, request, &alt_num, sizeof(alt_num)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case TUSB_REQ_SET_INTERFACE: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(0 == request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(_close_vc_itf(rhport, &_videod_itf[ctl_idx]), VIDEO_ERROR_UNKNOWN); - TU_VERIFY(_open_vc_itf(rhport, &_videod_itf[ctl_idx], request->wValue), VIDEO_ERROR_UNKNOWN); - tud_control_status(rhport, request); - } - return VIDEO_ERROR_NONE; - - default: /* Unknown/Unsupported request */ - TU_BREAKPOINT(); - return VIDEO_ERROR_INVALID_REQUEST; - } -} - -static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage, - tusb_control_request_t const *request, - uint_fast8_t ctl_idx) -{ - videod_interface_t *self = &_videod_itf[ctl_idx]; - - /* 4.2.1 Interface Control Request */ - switch (TU_U16_HIGH(request->wValue)) { - case VIDEO_VC_CTL_VIDEO_POWER_MODE: - switch (request->bRequest) { - case VIDEO_REQUEST_SET_CUR: - if (stage == CONTROL_STAGE_SETUP) { - TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, &self->power_mode, sizeof(self->power_mode)), VIDEO_ERROR_UNKNOWN); - } else if (stage == CONTROL_STAGE_DATA) { - if (tud_video_power_mode_cb) return tud_video_power_mode_cb(ctl_idx, self->power_mode); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_CUR: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, &self->power_mode, sizeof(self->power_mode)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_INFO: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - default: break; - } - break; - - case VIDEO_VC_CTL_REQUEST_ERROR_CODE: - switch (request->bRequest) { - case VIDEO_REQUEST_GET_CUR: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(tud_control_xfer(rhport, request, &self->error_code, sizeof(uint8_t)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_INFO: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get, sizeof(_cap_get)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - default: break; - } - break; - - default: break; - } - - /* Unknown/Unsupported request */ - TU_BREAKPOINT(); - return VIDEO_ERROR_INVALID_REQUEST; -} - -static int handle_video_ctl_req(uint8_t rhport, uint8_t stage, - tusb_control_request_t const *request, - uint_fast8_t ctl_idx) -{ - uint_fast8_t entity_id; - switch (request->bmRequestType_bit.type) { - case TUSB_REQ_TYPE_STANDARD: - return handle_video_ctl_std_req(rhport, stage, request, ctl_idx); - - case TUSB_REQ_TYPE_CLASS: - entity_id = TU_U16_HIGH(request->wIndex); - if (!entity_id) { - return handle_video_ctl_cs_req(rhport, stage, request, ctl_idx); - } else { - TU_VERIFY(_find_desc_entity(_get_desc_vc(&_videod_itf[ctl_idx]), entity_id), VIDEO_ERROR_INVALID_REQUEST); - return VIDEO_ERROR_NONE; - } - - default: - return VIDEO_ERROR_INVALID_REQUEST; - } -} - -static int handle_video_stm_std_req(uint8_t rhport, uint8_t stage, - tusb_control_request_t const *request, - uint_fast8_t stm_idx) -{ - videod_streaming_interface_t *self = &_videod_streaming_itf[stm_idx]; - switch (request->bRequest) { - case TUSB_REQ_GET_INTERFACE: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); - tusb_desc_vs_itf_t const *vs = _get_desc_vs(self); - TU_VERIFY(vs, VIDEO_ERROR_UNKNOWN); - uint8_t alt_num = vs->std.bAlternateSetting; - - TU_VERIFY(tud_control_xfer(rhport, request, &alt_num, sizeof(alt_num)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case TUSB_REQ_SET_INTERFACE: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(_open_vs_itf(rhport, self, request->wValue), VIDEO_ERROR_UNKNOWN); - tud_control_status(rhport, request); - } - return VIDEO_ERROR_NONE; - - default: /* Unknown/Unsupported request */ - TU_BREAKPOINT(); - return VIDEO_ERROR_INVALID_REQUEST; - } -} - -static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, - tusb_control_request_t const *request, - uint_fast8_t stm_idx) -{ - (void)rhport; - videod_streaming_interface_t *self = &_videod_streaming_itf[stm_idx]; - - /* 4.2.1 Interface Control Request */ - switch (TU_U16_HIGH(request->wValue)) { - case VIDEO_VS_CTL_STREAM_ERROR_CODE: - switch (request->bRequest) { - case VIDEO_REQUEST_GET_CUR: - if (stage == CONTROL_STAGE_SETUP) - { - /* TODO */ - TU_VERIFY(tud_control_xfer(rhport, request, &self->error_code, sizeof(uint8_t)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_INFO: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get, sizeof(_cap_get)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - default: break; - } - break; - - case VIDEO_VS_CTL_PROBE: - switch (request->bRequest) { - case VIDEO_REQUEST_SET_CUR: - if (stage == CONTROL_STAGE_SETUP) { - TU_VERIFY(sizeof(video_probe_and_commit_control_t) >= request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), - VIDEO_ERROR_UNKNOWN); - } else if (stage == CONTROL_STAGE_DATA) { - TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf), - VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_CUR: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_MIN: - case VIDEO_REQUEST_GET_MAX: - case VIDEO_REQUEST_GET_RES: - case VIDEO_REQUEST_GET_DEF: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN); - video_probe_and_commit_control_t tmp; - tmp = *(video_probe_and_commit_control_t*)&self->ep_buf; - TU_VERIFY(_negotiate_streaming_parameters(self, request->bRequest, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); - TU_VERIFY(tud_control_xfer(rhport, request, &tmp, sizeof(tmp)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_LEN: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN); - uint16_t len = sizeof(video_probe_and_commit_control_t); - TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_INFO: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t)&_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - default: break; - } - break; - - case VIDEO_VS_CTL_COMMIT: - switch (request->bRequest) { - case VIDEO_REQUEST_SET_CUR: - if (stage == CONTROL_STAGE_SETUP) { - TU_VERIFY(sizeof(video_probe_and_commit_control_t) >= request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); - } else if (stage == CONTROL_STAGE_DATA) { - TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); - if (tud_video_commit_cb) { - return tud_video_commit_cb(self->index_vc, self->index_vs, (video_probe_and_commit_control_t*)self->ep_buf); - } - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_CUR: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_LEN: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN); - uint16_t len = sizeof(video_probe_and_commit_control_t); - TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_INFO: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - default: break; - } - break; - - case VIDEO_VS_CTL_STILL_PROBE: - case VIDEO_VS_CTL_STILL_COMMIT: - case VIDEO_VS_CTL_STILL_IMAGE_TRIGGER: - case VIDEO_VS_CTL_GENERATE_KEY_FRAME: - case VIDEO_VS_CTL_UPDATE_FRAME_SEGMENT: - case VIDEO_VS_CTL_SYNCH_DELAY_CONTROL: - /* TODO */ - break; - - default: break; - } - - /* Unknown/Unsupported request */ - TU_BREAKPOINT(); - return VIDEO_ERROR_INVALID_REQUEST; -} - -static int handle_video_stm_req(uint8_t rhport, uint8_t stage, - tusb_control_request_t const *request, - uint_fast8_t stm_idx) -{ - switch (request->bmRequestType_bit.type) { - case TUSB_REQ_TYPE_STANDARD: - return handle_video_stm_std_req(rhport, stage, request, stm_idx); - - case TUSB_REQ_TYPE_CLASS: - if (TU_U16_HIGH(request->wIndex)) return VIDEO_ERROR_INVALID_REQUEST; - return handle_video_stm_cs_req(rhport, stage, request, stm_idx); - - default: return VIDEO_ERROR_INVALID_REQUEST; - } -} - -//--------------------------------------------------------------------+ -// APPLICATION API -//--------------------------------------------------------------------+ - -bool tud_video_n_connected(uint_fast8_t ctl_idx) -{ - TU_ASSERT(ctl_idx < CFG_TUD_VIDEO); - videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, 0); - if (stm) return true; - return false; -} - -bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) -{ - TU_ASSERT(ctl_idx < CFG_TUD_VIDEO); - TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING); - videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx); - if (!stm || !stm->desc.ep[0]) return false; - return true; -} - -bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *buffer, size_t bufsize) -{ - TU_ASSERT(ctl_idx < CFG_TUD_VIDEO); - TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING); - if (!buffer || !bufsize) return false; - videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx); - if (!stm || !stm->desc.ep[0] || stm->buffer) return false; - - /* Find EP address */ - uint8_t const *desc = _videod_itf[stm->index_vc].beg; - uint8_t ep_addr = 0; - for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { - uint_fast16_t ofs_ep = stm->desc.ep[i]; - if (!ofs_ep) continue; - ep_addr = _desc_ep_addr(desc + ofs_ep); - break; - } - if (!ep_addr) return false; - - TU_VERIFY( usbd_edpt_claim(0, ep_addr) ); - /* update the packet header */ - tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf; - hdr->FrameID ^= 1; - hdr->EndOfFrame = 0; - /* update the packet data */ - stm->buffer = (uint8_t*)buffer; - stm->bufsize = bufsize; - uint_fast16_t pkt_len = _prepare_in_payload(stm); - TU_ASSERT( usbd_edpt_xfer(0, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0); - return true; -} - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void videod_init(void) -{ - for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) { - videod_interface_t* ctl = &_videod_itf[i]; - tu_memclr(ctl, sizeof(*ctl)); - } - for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { - videod_streaming_interface_t *stm = &_videod_streaming_itf[i]; - tu_memclr(stm, ITF_STM_MEM_RESET_SIZE); - } -} - -void videod_reset(uint8_t rhport) -{ - (void) rhport; - for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) { - videod_interface_t* ctl = &_videod_itf[i]; - tu_memclr(ctl, sizeof(*ctl)); - } - for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { - videod_streaming_interface_t *stm = &_videod_streaming_itf[i]; - tu_memclr(stm, ITF_STM_MEM_RESET_SIZE); - } -} - -uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ - TU_VERIFY((TUSB_CLASS_VIDEO == itf_desc->bInterfaceClass) && - (VIDEO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass) && - (VIDEO_ITF_PROTOCOL_15 == itf_desc->bInterfaceProtocol), 0); - - /* Find available interface */ - videod_interface_t *self = NULL; - uint8_t ctl_idx; - for (ctl_idx = 0; ctl_idx < CFG_TUD_VIDEO; ++ctl_idx) { - if (_videod_itf[ctl_idx].beg) continue; - self = &_videod_itf[ctl_idx]; - break; - } - TU_ASSERT(ctl_idx < CFG_TUD_VIDEO, 0); - - uint8_t const *end = (uint8_t const*)itf_desc + max_len; - self->beg = (uint8_t const*) itf_desc; - self->len = max_len; - - /*------------- Video Control Interface -------------*/ - TU_VERIFY(_open_vc_itf(rhport, self, 0), 0); - tusb_desc_vc_itf_t const *vc = _get_desc_vc(self); - uint_fast8_t bInCollection = vc->ctl.bInCollection; - - /* Find the end of the video interface descriptor */ - void const *cur = _next_desc_itf(itf_desc, end); - for (uint8_t stm_idx = 0; stm_idx < bInCollection; ++stm_idx) { - videod_streaming_interface_t *stm = NULL; - /* find free streaming interface handle */ - for (uint8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { - if (_videod_streaming_itf[i].desc.beg) continue; - stm = &_videod_streaming_itf[i]; - self->stm[stm_idx] = i; - break; - } - TU_ASSERT(stm, 0); - stm->index_vc = ctl_idx; - stm->index_vs = stm_idx; - stm->desc.beg = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); - cur = _next_desc_itf(cur, end); - stm->desc.end = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); - } - self->len = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); - return (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - int err; - TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); - uint_fast8_t itfnum = tu_u16_low(request->wIndex); - - /* Identify which control interface to use */ - uint_fast8_t itf; - for (itf = 0; itf < CFG_TUD_VIDEO; ++itf) { - void const *desc = _videod_itf[itf].beg; - if (!desc) continue; - if (itfnum == _desc_itfnum(desc)) break; - } - - if (itf < CFG_TUD_VIDEO) { - err = handle_video_ctl_req(rhport, stage, request, itf); - _videod_itf[itf].error_code = (uint8_t)err; - if (err) return false; - return true; - } - - /* Identify which streaming interface to use */ - for (itf = 0; itf < CFG_TUD_VIDEO_STREAMING; ++itf) { - videod_streaming_interface_t *stm = &_videod_streaming_itf[itf]; - if (!stm->desc.beg) continue; - uint8_t const *desc = _videod_itf[stm->index_vc].beg; - if (itfnum == _desc_itfnum(desc + stm->desc.beg)) break; - } - - if (itf < CFG_TUD_VIDEO_STREAMING) { - err = handle_video_stm_req(rhport, stage, request, itf); - _videod_streaming_itf[itf].error_code = (uint8_t)err; - if (err) return false; - return true; - } - return false; -} - -bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void)result; (void)xferred_bytes; - - /* find streaming handle */ - uint_fast8_t itf; - videod_interface_t *ctl; - videod_streaming_interface_t *stm; - for (itf = 0; itf < CFG_TUD_VIDEO_STREAMING; ++itf) { - stm = &_videod_streaming_itf[itf]; - uint_fast16_t const ep_ofs = stm->desc.ep[0]; - if (!ep_ofs) continue; - ctl = &_videod_itf[stm->index_vc]; - uint8_t const *desc = ctl->beg; - if (ep_addr == _desc_ep_addr(desc + ep_ofs)) break; - } - - TU_ASSERT(itf < CFG_TUD_VIDEO_STREAMING); - if (stm->offset < stm->bufsize) { - /* Claim the endpoint */ - TU_VERIFY( usbd_edpt_claim(rhport, ep_addr), 0); - uint_fast16_t pkt_len = _prepare_in_payload(stm); - TU_ASSERT( usbd_edpt_xfer(rhport, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0); - } else { - stm->buffer = NULL; - stm->bufsize = 0; - stm->offset = 0; - if (tud_video_frame_xfer_complete_cb) { - tud_video_frame_xfer_complete_cb(stm->index_vc, stm->index_vs); - } - } - return true; -} - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/class/video/video_device.h b/test-devices/composite-stm32/lib/tinyusb/class/video/video_device.h deleted file mode 100644 index ee2fcb9d..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/class/video/video_device.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * Copyright (c) 2021 Koji KITAYAMA - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef TUSB_VIDEO_DEVICE_H_ -#define TUSB_VIDEO_DEVICE_H_ - -#include "common/tusb_common.h" -#include "video.h" - -#ifdef __cplusplus -extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Application API (Multiple Ports) -// CFG_TUD_VIDEO > 1 -//--------------------------------------------------------------------+ - -/** Return true if streaming - * - * @param[in] ctl_idx Destination control interface index - * @param[in] stm_idx Destination streaming interface index */ -bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx); - -/** Transfer a frame - * - * @param[in] ctl_idx Destination control interface index - * @param[in] stm_idx Destination streaming interface index - * @param[in] buffer Frame buffer. The caller must not use this buffer until the operation is completed. - * @param[in] bufsize Byte size of the frame buffer */ -bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *buffer, size_t bufsize); - -/*------------- Optional callbacks -------------*/ -/** Invoked when compeletion of a frame transfer - * - * @param[in] ctl_idx Destination control interface index - * @param[in] stm_idx Destination streaming interface index */ -TU_ATTR_WEAK void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx); - -//--------------------------------------------------------------------+ -// Application Callback API (weak is optional) -//--------------------------------------------------------------------+ - -/** Invoked when SET_POWER_MODE request received - * - * @param[in] ctl_idx Destination control interface index - * @param[in] stm_idx Destination streaming interface index - * @return video_error_code_t */ -TU_ATTR_WEAK int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod); - -/** Invoked when VS_COMMIT_CONTROL(SET_CUR) request received - * - * @param[in] ctl_idx Destination control interface index - * @param[in] stm_idx Destination streaming interface index - * @param[in] parameters Video streaming parameters - * @return video_error_code_t */ -TU_ATTR_WEAK int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, - video_probe_and_commit_control_t const *parameters); - -//--------------------------------------------------------------------+ -// INTERNAL USBD-CLASS DRIVER API -//--------------------------------------------------------------------+ -void videod_init (void); -void videod_reset (uint8_t rhport); -uint16_t videod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -bool videod_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_common.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_common.h index 957491aa..0d4082c0 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_common.h +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_common.h @@ -37,6 +37,7 @@ #define TU_ARRAY_SIZE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) ) #define TU_MIN(_x, _y) ( ( (_x) < (_y) ) ? (_x) : (_y) ) #define TU_MAX(_x, _y) ( ( (_x) > (_y) ) ? (_x) : (_y) ) +#define TU_DIV_CEIL(n, d) (((n) + (d) - 1) / (d)) #define TU_U16(_high, _low) ((uint16_t) (((_high) << 8) | (_low))) #define TU_U16_HIGH(_u16) ((uint8_t) (((_u16) >> 8) & 0x00ff)) @@ -53,6 +54,8 @@ #define U32_TO_U8S_LE(_u32) TU_U32_BYTE0(_u32), TU_U32_BYTE1(_u32), TU_U32_BYTE2(_u32), TU_U32_BYTE3(_u32) #define TU_BIT(n) (1UL << (n)) + +// Generate a mask with bit from high (31) to low (0) set, e.g TU_GENMASK(3, 0) = 0b1111 #define TU_GENMASK(h, l) ( (UINT32_MAX << (l)) & (UINT32_MAX >> (31 - (h))) ) //--------------------------------------------------------------------+ @@ -62,6 +65,7 @@ // Standard Headers #include #include +#include #include #include #include @@ -73,8 +77,6 @@ #include "tusb_types.h" #include "tusb_debug.h" -#include "tusb_timeout.h" // TODO remove - //--------------------------------------------------------------------+ // Optional API implemented by application if needed // TODO move to a more ovious place/file @@ -99,10 +101,9 @@ TU_ATTR_WEAK extern void* tusb_app_phys_to_virt(void *phys_addr); #define tu_varclr(_var) tu_memclr(_var, sizeof(*(_var))) // This is a backport of memset_s from c11 -TU_ATTR_ALWAYS_INLINE static inline int tu_memset_s(void *dest, size_t destsz, int ch, size_t count) -{ +TU_ATTR_ALWAYS_INLINE static inline int tu_memset_s(void *dest, size_t destsz, int ch, size_t count) { // TODO may check if desst and src is not NULL - if (count > destsz) { + if ( count > destsz ) { return -1; } memset(dest, ch, count); @@ -110,10 +111,9 @@ TU_ATTR_ALWAYS_INLINE static inline int tu_memset_s(void *dest, size_t destsz, i } // This is a backport of memcpy_s from c11 -TU_ATTR_ALWAYS_INLINE static inline int tu_memcpy_s(void *dest, size_t destsz, const void * src, size_t count ) -{ +TU_ATTR_ALWAYS_INLINE static inline int tu_memcpy_s(void *dest, size_t destsz, const void *src, size_t count) { // TODO may check if desst and src is not NULL - if (count > destsz) { + if ( count > destsz ) { return -1; } memcpy(dest, src, count); @@ -122,13 +122,11 @@ TU_ATTR_ALWAYS_INLINE static inline int tu_memcpy_s(void *dest, size_t destsz, c //------------- Bytes -------------// -TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_u32(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_u32(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0) { return ( ((uint32_t) b3) << 24) | ( ((uint32_t) b2) << 16) | ( ((uint32_t) b1) << 8) | b0; } -TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u16(uint8_t high, uint8_t low) -{ +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u16(uint8_t high, uint8_t low) { return (uint16_t) ((((uint16_t) high) << 8) | low); } @@ -159,16 +157,20 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_max16 (uint16_t x, uint16_t y) { TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_max32 (uint32_t x, uint32_t y) { return (x > y) ? x : y; } //------------- Align -------------// -TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align(uint32_t value, uint32_t alignment) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align(uint32_t value, uint32_t alignment) { return value & ((uint32_t) ~(alignment-1)); } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align4 (uint32_t value) { return (value & 0xFFFFFFFCUL); } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align8 (uint32_t value) { return (value & 0xFFFFFFF8UL); } TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align16 (uint32_t value) { return (value & 0xFFFFFFF0UL); } TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align32 (uint32_t value) { return (value & 0xFFFFFFE0UL); } TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align4k (uint32_t value) { return (value & 0xFFFFF000UL); } TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_offset4k(uint32_t value) { return (value & 0xFFFUL); } +TU_ATTR_ALWAYS_INLINE static inline bool tu_is_aligned32(uint32_t value) { return (value & 0x1FUL) == 0; } +TU_ATTR_ALWAYS_INLINE static inline bool tu_is_aligned64(uint64_t value) { return (value & 0x3FUL) == 0; } + //------------- Mathematics -------------// TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_div_ceil(uint32_t v, uint32_t d) { return (v + d -1)/d; } @@ -260,11 +262,21 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void* mem, uint16_ #else // MCU that could access unaligned memory natively -TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32 (const void* mem) { return *((uint32_t const *) mem); } -TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16 (const void* mem) { return *((uint16_t const *) mem); } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32(const void *mem) { + return *((uint32_t const *) mem); +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16(const void *mem) { + return *((uint16_t const *) mem); +} -TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32 (void* mem, uint32_t value ) { *((uint32_t*) mem) = value; } -TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16 (void* mem, uint16_t value ) { *((uint16_t*) mem) = value; } +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32(void *mem, uint32_t value) { + *((uint32_t *) mem) = value; +} + +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void *mem, uint16_t value) { + *((uint16_t *) mem) = value; +} #endif diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_compiler.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_compiler.h index 5ab56e14..0d5570b1 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_compiler.h +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_compiler.h @@ -56,7 +56,7 @@ #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L #define TU_VERIFY_STATIC _Static_assert #elif defined(__CCRX__) - #define TU_VERIFY_STATIC(const_expr, _mess) typedef char TU_XSTRCAT(Line, __LINE__)[(const_expr) ? 1 : 0]; + #define TU_VERIFY_STATIC(const_expr, _mess) typedef char TU_XSTRCAT(_verify_static_, _TU_COUNTER_)[(const_expr) ? 1 : 0]; #else #define TU_VERIFY_STATIC(const_expr, _mess) enum { TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1/(!!(const_expr)) } #endif @@ -128,7 +128,9 @@ #define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name))) #define TU_ATTR_PACKED __attribute__ ((packed)) #define TU_ATTR_WEAK __attribute__ ((weak)) - #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) + #ifndef TU_ATTR_ALWAYS_INLINE // allow to override for debug + #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) + #endif #define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used #define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused #define TU_ATTR_USED __attribute__ ((used)) // Function/Variable is meant to be used @@ -205,7 +207,9 @@ #define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name))) #define TU_ATTR_PACKED __attribute__ ((packed)) #define TU_ATTR_WEAK __attribute__ ((weak)) - #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) + #ifndef TU_ATTR_ALWAYS_INLINE // allow to override for debug + #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) + #endif #define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used #define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused #define TU_ATTR_USED __attribute__ ((used)) // Function/Variable is meant to be used diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_debug.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_debug.h index 82f68204..2e9f1d9c 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_debug.h +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_debug.h @@ -43,9 +43,10 @@ #if CFG_TUSB_DEBUG // Enum to String for debugging purposes -#if CFG_TUSB_DEBUG >= 2 +#if CFG_TUSB_DEBUG >= CFG_TUH_LOG_LEVEL || CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL extern char const* const tu_str_speed[]; extern char const* const tu_str_std_request[]; +extern char const* const tu_str_xfer_result[]; #endif void tu_print_mem(void const *buf, uint32_t count, uint8_t indent); @@ -57,16 +58,15 @@ void tu_print_mem(void const *buf, uint32_t count, uint8_t indent); #define tu_printf printf #endif -static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) -{ +static inline void tu_print_buf(uint8_t const* buf, uint32_t bufsize) { for(uint32_t i=0; i= 2 #define TU_LOG2 TU_LOG1 #define TU_LOG2_MEM TU_LOG1_MEM - #define TU_LOG2_ARR TU_LOG1_ARR - #define TU_LOG2_PTR TU_LOG1_PTR + #define TU_LOG2_BUF TU_LOG1_BUF #define TU_LOG2_INT TU_LOG1_INT #define TU_LOG2_HEX TU_LOG1_HEX #endif @@ -94,30 +92,25 @@ static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) #if CFG_TUSB_DEBUG >= 3 #define TU_LOG3 TU_LOG1 #define TU_LOG3_MEM TU_LOG1_MEM - #define TU_LOG3_ARR TU_LOG1_ARR - #define TU_LOG3_PTR TU_LOG1_PTR + #define TU_LOG3_BUF TU_LOG1_BUF #define TU_LOG3_INT TU_LOG1_INT #define TU_LOG3_HEX TU_LOG1_HEX #endif -typedef struct -{ +typedef struct { uint32_t key; const char* data; } tu_lookup_entry_t; -typedef struct -{ +typedef struct { uint16_t count; tu_lookup_entry_t const* items; } tu_lookup_table_t; -static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) -{ +static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) { tu_static char not_found[11]; - for(uint16_t i=0; icount; i++) - { + for(uint16_t i=0; icount; i++) { if (p_table->items[i].key == key) return p_table->items[i].data; } @@ -132,7 +125,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG #define TU_LOG(n, ...) #define TU_LOG_MEM(n, ...) - #define TU_LOG_PTR(n, ...) + #define TU_LOG_BUF(n, ...) #define TU_LOG_INT(n, ...) #define TU_LOG_HEX(n, ...) #define TU_LOG_LOCATION() @@ -143,14 +136,14 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #define TU_LOG0(...) #define TU_LOG0_MEM(...) -#define TU_LOG0_PTR(...) +#define TU_LOG0_BUF(...) #define TU_LOG0_INT(...) #define TU_LOG0_HEX(...) #ifndef TU_LOG1 #define TU_LOG1(...) #define TU_LOG1_MEM(...) - #define TU_LOG1_PTR(...) + #define TU_LOG1_BUF(...) #define TU_LOG1_INT(...) #define TU_LOG1_HEX(...) #endif @@ -158,7 +151,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG2 #define TU_LOG2(...) #define TU_LOG2_MEM(...) - #define TU_LOG2_PTR(...) + #define TU_LOG2_BUF(...) #define TU_LOG2_INT(...) #define TU_LOG2_HEX(...) #endif @@ -166,7 +159,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG3 #define TU_LOG3(...) #define TU_LOG3_MEM(...) - #define TU_LOG3_PTR(...) + #define TU_LOG3_BUF(...) #define TU_LOG3_INT(...) #define TU_LOG3_HEX(...) #endif diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.c b/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.c index a52c9226..76696396 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.c +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.c @@ -224,6 +224,7 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t if (wrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, wrap_bytes); } break; + default: break; } } @@ -539,7 +540,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu // Advance index f->wr_idx = advance_index(f->depth, wr_idx, n); - TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\n", f->wr_idx); + TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\r\n", f->wr_idx); } _ff_unlock(f->mutex_wr); diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.h index 2f60ec2f..2d9f5e66 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.h +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_fifo.h @@ -102,10 +102,8 @@ extern "C" { * | * ------------------------- * | R | 1 | 2 | W | 4 | 5 | - */ -typedef struct -{ +typedef struct { uint8_t* buffer ; // buffer pointer uint16_t depth ; // max items @@ -124,16 +122,14 @@ typedef struct } tu_fifo_t; -typedef struct -{ +typedef struct { uint16_t len_lin ; ///< linear length in item size uint16_t len_wrap ; ///< wrapped length in item size void * ptr_lin ; ///< linear part start pointer void * ptr_wrap ; ///< wrapped part start pointer } tu_fifo_buffer_info_t; -#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable) \ -{ \ +#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable){\ .buffer = _buffer, \ .depth = _depth, \ .item_size = sizeof(_type), \ @@ -144,23 +140,18 @@ typedef struct uint8_t _name##_buf[_depth*sizeof(_type)]; \ tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _type, _overwritable) - bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable); bool tu_fifo_clear(tu_fifo_t *f); bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable); #if OSAL_MUTEX_REQUIRED -TU_ATTR_ALWAYS_INLINE static inline -void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_mutex) -{ - f->mutex_wr = wr_mutex; - f->mutex_rd = rd_mutex; -} - + TU_ATTR_ALWAYS_INLINE static inline + void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_mutex) { + f->mutex_wr = wr_mutex; + f->mutex_rd = rd_mutex; + } #else - -#define tu_fifo_config_mutex(_f, _wr_mutex, _rd_mutex) - + #define tu_fifo_config_mutex(_f, _wr_mutex, _rd_mutex) #endif bool tu_fifo_write (tu_fifo_t* f, void const * p_data); @@ -182,8 +173,7 @@ bool tu_fifo_overflowed (tu_fifo_t* f); void tu_fifo_correct_read_pointer (tu_fifo_t* f); TU_ATTR_ALWAYS_INLINE static inline -uint16_t tu_fifo_depth(tu_fifo_t* f) -{ +uint16_t tu_fifo_depth(tu_fifo_t* f) { return f->depth; } @@ -198,7 +188,6 @@ void tu_fifo_advance_read_pointer (tu_fifo_t *f, uint16_t n); void tu_fifo_get_read_info (tu_fifo_t *f, tu_fifo_buffer_info_t *info); void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info); - #ifdef __cplusplus } #endif diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_mcu.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_mcu.h index ba8976a8..5a567f2d 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_mcu.h +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_mcu.h @@ -34,10 +34,16 @@ //------------- Unaligned Memory Access -------------// -// ARMv7+ (M3-M7, M23-M33) can access unaligned memory -#if (defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) - #define TUP_ARCH_STRICT_ALIGN 0 +#ifdef __ARM_ARCH + // ARM Architecture set __ARM_FEATURE_UNALIGNED to 1 for mcu supports unaligned access + #if defined(__ARM_FEATURE_UNALIGNED) && __ARM_FEATURE_UNALIGNED == 1 + #define TUP_ARCH_STRICT_ALIGN 0 + #else + #define TUP_ARCH_STRICT_ALIGN 1 + #endif #else + // TODO default to strict align for others + // Should investigate other architecture such as risv, xtensa, mips for optimal setting #define TUP_ARCH_STRICT_ALIGN 1 #endif @@ -52,6 +58,7 @@ // NXP //--------------------------------------------------------------------+ #if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX) + #define TUP_USBIP_IP3511 #define TUP_DCD_ENDPOINT_MAX 5 #elif TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX) @@ -59,33 +66,55 @@ #define TUP_USBIP_OHCI #define TUP_OHCI_RHPORTS 2 -#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX) - // TODO USB0 has 6, USB1 has 4 - #define TUP_USBIP_CHIPIDEA_HS - #define TUP_USBIP_EHCI - - #define TUP_DCD_ENDPOINT_MAX 6 - #define TUP_RHPORT_HIGHSPEED 1 // Port0 HS, Port1 FS - #elif TU_CHECK_MCU(OPT_MCU_LPC51UXX) + #define TUP_USBIP_IP3511 #define TUP_DCD_ENDPOINT_MAX 5 -#elif TU_CHECK_MCU(OPT_MCU_LPC54XXX) +#elif TU_CHECK_MCU(OPT_MCU_LPC54) // TODO USB0 has 5, USB1 has 6 + #define TUP_USBIP_IP3511 #define TUP_DCD_ENDPOINT_MAX 6 -#elif TU_CHECK_MCU(OPT_MCU_LPC55XX) +#elif TU_CHECK_MCU(OPT_MCU_LPC55) // TODO USB0 has 5, USB1 has 6 + #define TUP_USBIP_IP3511 #define TUP_DCD_ENDPOINT_MAX 6 -#elif TU_CHECK_MCU(OPT_MCU_MIMXRT) +#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX) + // USB0 has 6 with HS PHY, USB1 has 4 only FS + #define TUP_USBIP_CHIPIDEA_HS + #define TUP_USBIP_EHCI + + #define TUP_DCD_ENDPOINT_MAX 6 + #define TUP_RHPORT_HIGHSPEED 1 + +#elif TU_CHECK_MCU(OPT_MCU_MCXN9) + // USB0 is chipidea FS + #define TUP_USBIP_CHIPIDEA_FS + #define TUP_USBIP_CHIPIDEA_FS_MCX + + // USB1 is chipidea HS + #define TUP_USBIP_CHIPIDEA_HS + #define TUP_USBIP_EHCI + + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_RHPORT_HIGHSPEED 1 + +#elif TU_CHECK_MCU(OPT_MCU_MCXA15) + // USB0 is chipidea FS + #define TUP_USBIP_CHIPIDEA_FS + #define TUP_USBIP_CHIPIDEA_FS_MCX + + #define TUP_DCD_ENDPOINT_MAX 16 + +#elif TU_CHECK_MCU(OPT_MCU_MIMXRT1XXX) #define TUP_USBIP_CHIPIDEA_HS #define TUP_USBIP_EHCI #define TUP_DCD_ENDPOINT_MAX 8 - #define TUP_RHPORT_HIGHSPEED 1 // Port0 HS, Port1 HS + #define TUP_RHPORT_HIGHSPEED 1 -#elif TU_CHECK_MCU(OPT_MCU_KINETIS_KL, OPT_MCU_KINETIS_K32) +#elif TU_CHECK_MCU(OPT_MCU_KINETIS_KL, OPT_MCU_KINETIS_K32L, OPT_MCU_KINETIS_K) #define TUP_USBIP_CHIPIDEA_FS #define TUP_USBIP_CHIPIDEA_FS_KINETIS #define TUP_DCD_ENDPOINT_MAX 16 @@ -188,7 +217,22 @@ #define TUP_DCD_ENDPOINT_MAX 9 +#elif TU_CHECK_MCU(OPT_MCU_STM32H5) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 + #define TUP_DCD_ENDPOINT_MAX 8 + #elif TU_CHECK_MCU(OPT_MCU_STM32G4) + // Device controller + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 + + // TypeC controller + #define TUP_USBIP_TYPEC_STM32 + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_TYPEC_RHPORTS_NUM 1 + +#elif TU_CHECK_MCU(OPT_MCU_STM32G0) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 @@ -227,14 +271,21 @@ #elif TU_CHECK_MCU(OPT_MCU_STM32U5) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 - #define TUP_DCD_ENDPOINT_MAX 6 + + // U59x/5Ax/5Fx/5Gx are highspeed with built-in HS PHY + #if defined(STM32U595xx) || defined(STM32U599xx) || defined(STM32U5A5xx) || defined(STM32U5A9xx) || \ + defined(STM32U5F7xx) || defined(STM32U5F9xx) || defined(STM32U5G7xx) || defined(STM32U5G9xx) + #define TUP_DCD_ENDPOINT_MAX 9 + #define TUP_RHPORT_HIGHSPEED 1 + #else + #define TUP_DCD_ENDPOINT_MAX 6 + #endif #elif TU_CHECK_MCU(OPT_MCU_STM32L5) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 - //--------------------------------------------------------------------+ // Sony //--------------------------------------------------------------------+ @@ -278,6 +329,9 @@ #define TUP_USBIP_DWC2 #define TUP_DCD_ENDPOINT_MAX 6 +#elif TU_CHECK_MCU(OPT_MCU_ESP32) && (CFG_TUD_ENABLED || !(defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421)) + #error "MCUs are only supported with CFG_TUH_MAX3421 enabled" + //--------------------------------------------------------------------+ // Dialog //--------------------------------------------------------------------+ @@ -303,6 +357,7 @@ // Renesas //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N, OPT_MCU_RAXXX) + #define TUP_USBIP_RUSB2 #define TUP_DCD_ENDPOINT_MAX 10 //--------------------------------------------------------------------+ @@ -348,8 +403,24 @@ #elif TU_CHECK_MCU(OPT_MCU_CH32V307) #define TUP_DCD_ENDPOINT_MAX 16 #define TUP_RHPORT_HIGHSPEED 1 + +#elif TU_CHECK_MCU(OPT_MCU_CH32F20X) + #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_RHPORT_HIGHSPEED 1 +#endif + + +//--------------------------------------------------------------------+ +// External USB controller +//--------------------------------------------------------------------+ + +#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 + #ifndef CFG_TUH_MAX3421_ENDPOINT_TOTAL + #define CFG_TUH_MAX3421_ENDPOINT_TOTAL (8 + 4*(CFG_TUH_DEVICE_MAX-1)) + #endif #endif + //--------------------------------------------------------------------+ // Default Values //--------------------------------------------------------------------+ @@ -358,8 +429,8 @@ #define TUP_MCU_MULTIPLE_CORE 0 #endif -#ifndef TUP_DCD_ENDPOINT_MAX - #warning "TUP_DCD_ENDPOINT_MAX is not defined for this MCU, default to 8" +#if !defined(TUP_DCD_ENDPOINT_MAX) && defined(CFG_TUD_ENABLED) && CFG_TUD_ENABLED +#warning "TUP_DCD_ENDPOINT_MAX is not defined for this MCU, default to 8" #define TUP_DCD_ENDPOINT_MAX 8 #endif @@ -373,4 +444,8 @@ #define TU_ATTR_FAST_FUNC #endif +#if defined(TUP_USBIP_DWC2) || defined(TUP_USBIP_FSDEV) + #define TUP_DCD_EDPT_ISO_ALLOC +#endif + #endif diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_private.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_private.h index d5541856..373a5025 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_private.h +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_private.h @@ -60,7 +60,7 @@ typedef struct { tu_fifo_t ff; // mutex: read if ep rx, write if e tx - OSAL_MUTEX_DEF(ff_mutex); + OSAL_MUTEX_DEF(ff_mutexdef); }tu_edpt_stream_t; @@ -87,15 +87,17 @@ bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex); // Endpoint Stream //--------------------------------------------------------------------+ -// Init an stream, should only be called once +// Init an endpoint stream bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool overwritable, void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize); +// Deinit an endpoint stream +bool tu_edpt_stream_deinit(tu_edpt_stream_t* s); + // Open an stream for an endpoint // hwid is either device address (host mode) or rhport (device mode) TU_ATTR_ALWAYS_INLINE static inline -void tu_edpt_stream_open(tu_edpt_stream_t* s, uint8_t hwid, tusb_desc_endpoint_t const *desc_ep) -{ +void tu_edpt_stream_open(tu_edpt_stream_t* s, uint8_t hwid, tusb_desc_endpoint_t const *desc_ep) { tu_fifo_clear(&s->ff); s->hwid = hwid; s->ep_addr = desc_ep->bEndpointAddress; @@ -103,16 +105,14 @@ void tu_edpt_stream_open(tu_edpt_stream_t* s, uint8_t hwid, tusb_desc_endpoint_t } TU_ATTR_ALWAYS_INLINE static inline -void tu_edpt_stream_close(tu_edpt_stream_t* s) -{ +void tu_edpt_stream_close(tu_edpt_stream_t* s) { s->hwid = 0; s->ep_addr = 0; } // Clear fifo TU_ATTR_ALWAYS_INLINE static inline -bool tu_edpt_stream_clear(tu_edpt_stream_t* s) -{ +bool tu_edpt_stream_clear(tu_edpt_stream_t* s) { return tu_fifo_clear(&s->ff); } @@ -131,8 +131,7 @@ bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferr // Get the number of bytes available for writing TU_ATTR_ALWAYS_INLINE static inline -uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) -{ +uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) { return (uint32_t) tu_fifo_remaining(&s->ff); } @@ -148,21 +147,26 @@ uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s); // Must be called in the transfer complete callback TU_ATTR_ALWAYS_INLINE static inline -void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) -{ +void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) { tu_fifo_write_n(&s->ff, s->ep_buf, (uint16_t) xferred_bytes); } +// Same as tu_edpt_stream_read_xfer_complete but skip the first n bytes +TU_ATTR_ALWAYS_INLINE static inline +void tu_edpt_stream_read_xfer_complete_offset(tu_edpt_stream_t* s, uint32_t xferred_bytes, uint32_t skip_offset) { + if (skip_offset < xferred_bytes) { + tu_fifo_write_n(&s->ff, s->ep_buf + skip_offset, (uint16_t) (xferred_bytes - skip_offset)); + } +} + // Get the number of bytes available for reading TU_ATTR_ALWAYS_INLINE static inline -uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t* s) -{ +uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t* s) { return (uint32_t) tu_fifo_count(&s->ff); } TU_ATTR_ALWAYS_INLINE static inline -bool tu_edpt_stream_peek(tu_edpt_stream_t* s, uint8_t* ch) -{ +bool tu_edpt_stream_peek(tu_edpt_stream_t* s, uint8_t* ch) { return tu_fifo_peek(&s->ff, ch); } diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_timeout.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_timeout.h deleted file mode 100644 index 533e67ab..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_timeout.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -/** \ingroup Group_Common Common Files - * \defgroup Group_TimeoutTimer timeout timer - * @{ */ - -#ifndef _TUSB_TIMEOUT_H_ -#define _TUSB_TIMEOUT_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - uint32_t start; - uint32_t interval; -}tu_timeout_t; - -#if 0 - -extern uint32_t tusb_hal_millis(void); - -static inline void tu_timeout_set(tu_timeout_t* tt, uint32_t msec) -{ - tt->interval = msec; - tt->start = tusb_hal_millis(); -} - -static inline bool tu_timeout_expired(tu_timeout_t* tt) -{ - return ( tusb_hal_millis() - tt->start ) >= tt->interval; -} - -// For used with periodic event to prevent drift -static inline void tu_timeout_reset(tu_timeout_t* tt) -{ - tt->start += tt->interval; -} - -static inline void tu_timeout_restart(tu_timeout_t* tt) -{ - tt->start = tusb_hal_millis(); -} - -#endif - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_TIMEOUT_H_ */ - -/** @} */ diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_types.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_types.h index 39a2d456..b571f9b7 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_types.h +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_types.h @@ -24,12 +24,8 @@ * This file is part of the TinyUSB stack. */ -/** \ingroup group_usb_definitions - * \defgroup USBDef_Type USB Types - * @{ */ - -#ifndef _TUSB_TYPES_H_ -#define _TUSB_TYPES_H_ +#ifndef TUSB_TYPES_H_ +#define TUSB_TYPES_H_ #include #include @@ -44,43 +40,38 @@ *------------------------------------------------------------------*/ /// defined base on EHCI specs value for Endpoint Speed -typedef enum -{ +typedef enum { TUSB_SPEED_FULL = 0, TUSB_SPEED_LOW = 1, TUSB_SPEED_HIGH = 2, TUSB_SPEED_INVALID = 0xff, -}tusb_speed_t; +} tusb_speed_t; /// defined base on USB Specs Endpoint's bmAttributes -typedef enum -{ +typedef enum { TUSB_XFER_CONTROL = 0 , TUSB_XFER_ISOCHRONOUS , TUSB_XFER_BULK , TUSB_XFER_INTERRUPT -}tusb_xfer_type_t; +} tusb_xfer_type_t; -typedef enum -{ +typedef enum { TUSB_DIR_OUT = 0, TUSB_DIR_IN = 1, TUSB_DIR_IN_MASK = 0x80 -}tusb_dir_t; +} tusb_dir_t; -enum -{ +enum { TUSB_EPSIZE_BULK_FS = 64, - TUSB_EPSIZE_BULK_HS= 512, + TUSB_EPSIZE_BULK_HS = 512, TUSB_EPSIZE_ISO_FS_MAX = 1023, TUSB_EPSIZE_ISO_HS_MAX = 1024, }; -/// Isochronous End Point Attributes -typedef enum -{ +/// Isochronous Endpoint Attributes +typedef enum { TUSB_ISO_EP_ATT_NO_SYNC = 0x00, TUSB_ISO_EP_ATT_ASYNCHRONOUS = 0x04, TUSB_ISO_EP_ATT_ADAPTIVE = 0x08, @@ -88,11 +79,10 @@ typedef enum TUSB_ISO_EP_ATT_DATA = 0x00, ///< Data End Point TUSB_ISO_EP_ATT_EXPLICIT_FB = 0x10, ///< Feedback End Point TUSB_ISO_EP_ATT_IMPLICIT_FB = 0x20, ///< Data endpoint that also serves as an implicit feedback -}tusb_iso_ep_attribute_t; +} tusb_iso_ep_attribute_t; /// USB Descriptor Types -typedef enum -{ +typedef enum { TUSB_DESC_DEVICE = 0x01, TUSB_DESC_CONFIGURATION = 0x02, TUSB_DESC_STRING = 0x03, @@ -119,10 +109,9 @@ typedef enum TUSB_DESC_SUPERSPEED_ENDPOINT_COMPANION = 0x30, TUSB_DESC_SUPERSPEED_ISO_ENDPOINT_COMPANION = 0x31 -}tusb_desc_type_t; +} tusb_desc_type_t; -typedef enum -{ +typedef enum { TUSB_REQ_GET_STATUS = 0 , TUSB_REQ_CLEAR_FEATURE = 1 , TUSB_REQ_RESERVED = 2 , @@ -136,25 +125,22 @@ typedef enum TUSB_REQ_GET_INTERFACE = 10 , TUSB_REQ_SET_INTERFACE = 11 , TUSB_REQ_SYNCH_FRAME = 12 -}tusb_request_code_t; +} tusb_request_code_t; -typedef enum -{ +typedef enum { TUSB_REQ_FEATURE_EDPT_HALT = 0, TUSB_REQ_FEATURE_REMOTE_WAKEUP = 1, TUSB_REQ_FEATURE_TEST_MODE = 2 -}tusb_request_feature_selector_t; +} tusb_request_feature_selector_t; -typedef enum -{ +typedef enum { TUSB_REQ_TYPE_STANDARD = 0, TUSB_REQ_TYPE_CLASS, TUSB_REQ_TYPE_VENDOR, TUSB_REQ_TYPE_INVALID } tusb_request_type_t; -typedef enum -{ +typedef enum { TUSB_REQ_RCPT_DEVICE =0, TUSB_REQ_RCPT_INTERFACE, TUSB_REQ_RCPT_ENDPOINT, @@ -162,8 +148,7 @@ typedef enum } tusb_request_recipient_t; // https://www.usb.org/defined-class-codes -typedef enum -{ +typedef enum { TUSB_CLASS_UNSPECIFIED = 0 , TUSB_CLASS_AUDIO = 1 , TUSB_CLASS_CDC = 2 , @@ -187,26 +172,23 @@ typedef enum TUSB_CLASS_MISC = 0xEF , TUSB_CLASS_APPLICATION_SPECIFIC = 0xFE , TUSB_CLASS_VENDOR_SPECIFIC = 0xFF -}tusb_class_code_t; +} tusb_class_code_t; typedef enum { MISC_SUBCLASS_COMMON = 2 }misc_subclass_type_t; -typedef enum -{ +typedef enum { MISC_PROTOCOL_IAD = 1 -}misc_protocol_type_t; +} misc_protocol_type_t; -typedef enum -{ +typedef enum { APP_SUBCLASS_USBTMC = 0x03, APP_SUBCLASS_DFU_RUNTIME = 0x01 } app_subclass_type_t; -typedef enum -{ +typedef enum { DEVICE_CAPABILITY_WIRELESS_USB = 0x01, DEVICE_CAPABILITY_USB20_EXTENSION = 0x02, DEVICE_CAPABILITY_SUPERSPEED_USB = 0x03, @@ -223,37 +205,37 @@ typedef enum DEVICE_CAPABILITY_AUTHENTICATION = 0x0E, DEVICE_CAPABILITY_BILLBOARD_EX = 0x0F, DEVICE_CAPABILITY_CONFIGURATION_SUMMARY = 0x10 -}device_capability_type_t; +} device_capability_type_t; enum { - TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = TU_BIT(5), - TUSB_DESC_CONFIG_ATT_SELF_POWERED = TU_BIT(6), + TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = 1u << 5, + TUSB_DESC_CONFIG_ATT_SELF_POWERED = 1u << 6, }; #define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2) -typedef enum -{ +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ +typedef enum { XFER_RESULT_SUCCESS = 0, XFER_RESULT_FAILED, XFER_RESULT_STALLED, XFER_RESULT_TIMEOUT, XFER_RESULT_INVALID -}xfer_result_t; +} xfer_result_t; -enum // TODO remove -{ +// TODO remove +enum { DESC_OFFSET_LEN = 0, DESC_OFFSET_TYPE = 1 }; -enum -{ +enum { INTERFACE_INVALID_NUMBER = 0xff }; -typedef enum -{ +typedef enum { MS_OS_20_SET_HEADER_DESCRIPTOR = 0x00, MS_OS_20_SUBSET_HEADER_CONFIGURATION = 0x01, MS_OS_20_SUBSET_HEADER_FUNCTION = 0x02, @@ -265,16 +247,14 @@ typedef enum MS_OS_20_FEATURE_VENDOR_REVISION = 0x08 } microsoft_os_20_type_t; -enum -{ +enum { CONTROL_STAGE_IDLE, CONTROL_STAGE_SETUP, CONTROL_STAGE_DATA, CONTROL_STAGE_ACK }; -enum -{ +enum { TUSB_INDEX_INVALID_8 = 0xFFu }; @@ -287,15 +267,14 @@ TU_ATTR_PACKED_BEGIN TU_ATTR_BIT_FIELD_ORDER_BEGIN /// USB Device Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes. uint8_t bDescriptorType ; ///< DEVICE Descriptor Type. - uint16_t bcdUSB ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). This field identifies the release of the USB Specification with which the device and its descriptors are compliant. + uint16_t bcdUSB ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). - uint8_t bDeviceClass ; ///< Class code (assigned by the USB-IF). \li If this field is reset to zero, each interface within a configuration specifies its own class information and the various interfaces operate independently. \li If this field is set to a value between 1 and FEH, the device supports different class specifications on different interfaces and the interfaces may not operate independently. This value identifies the class definition used for the aggregate interfaces. \li If this field is set to FFH, the device class is vendor-specific. - uint8_t bDeviceSubClass ; ///< Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass field. \li If the bDeviceClass field is reset to zero, this field must also be reset to zero. \li If the bDeviceClass field is not set to FFH, all values are reserved for assignment by the USB-IF. - uint8_t bDeviceProtocol ; ///< Protocol code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass and the bDeviceSubClass fields. If a device supports class-specific protocols on a device basis as opposed to an interface basis, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use class-specific protocols on a device basis. However, it may use classspecific protocols on an interface basis. \li If this field is set to FFH, the device uses a vendor-specific protocol on a device basis. + uint8_t bDeviceClass ; ///< Class code (assigned by the USB-IF). + uint8_t bDeviceSubClass ; ///< Subclass code (assigned by the USB-IF). + uint8_t bDeviceProtocol ; ///< Protocol code (assigned by the USB-IF). uint8_t bMaxPacketSize0 ; ///< Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid). For HS devices is fixed to 64. uint16_t idVendor ; ///< Vendor ID (assigned by the USB-IF). @@ -311,8 +290,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_device_t) == 18, "size is not correct"); // USB Binary Device Object Store (BOS) Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type uint16_t wTotalLength ; ///< Total length of data returned for this descriptor @@ -322,8 +300,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_bos_t) == 5, "size is not correct"); /// USB Configuration Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type uint16_t wTotalLength ; ///< Total length of data returned for this configuration. Includes the combined length of all descriptors (configuration, interface, endpoint, and class- or vendor-specific) returned for this configuration. @@ -338,8 +315,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_configuration_t) == 9, "size is not correct"); /// USB Interface Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< INTERFACE Descriptor Type @@ -355,8 +331,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_interface_t) == 9, "size is not correct"); /// USB Endpoint Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; // Size of this descriptor in bytes uint8_t bDescriptorType ; // ENDPOINT Descriptor Type @@ -376,8 +351,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_endpoint_t) == 7, "size is not correct"); /// USB Other Speed Configuration Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of descriptor uint8_t bDescriptorType ; ///< Other_speed_Configuration Type uint16_t wTotalLength ; ///< Total length of data returned @@ -390,8 +364,7 @@ typedef struct TU_ATTR_PACKED } tusb_desc_other_speed_t; /// USB Device Qualifier Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of descriptor uint8_t bDescriptorType ; ///< Device Qualifier Type uint16_t bcdUSB ; ///< USB specification version number (e.g., 0200H for V2.00) @@ -408,8 +381,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_device_qualifier_t) == 10, "size is not correct"); /// USB Interface Association Descriptor (IAD ECN) -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of descriptor uint8_t bDescriptorType ; ///< Other_speed_Configuration Type @@ -423,17 +395,17 @@ typedef struct TU_ATTR_PACKED uint8_t iFunction ; ///< Index of the string descriptor describing the interface association. } tusb_desc_interface_assoc_t; +TU_VERIFY_STATIC( sizeof(tusb_desc_interface_assoc_t) == 8, "size is not correct"); + // USB String Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< Descriptor Type uint16_t unicode_string[]; } tusb_desc_string_t; // USB Binary Device Object Store (BOS) -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType ; uint8_t bDevCapabilityType; @@ -442,9 +414,8 @@ typedef struct TU_ATTR_PACKED uint8_t CapabilityData[]; } tusb_desc_bos_platform_t; -// USB WebuSB URL Descriptor -typedef struct TU_ATTR_PACKED -{ +// USB WebUSB URL Descriptor +typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType; uint8_t bScheme; @@ -452,8 +423,7 @@ typedef struct TU_ATTR_PACKED } tusb_desc_webusb_url_t; // DFU Functional Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType; @@ -474,10 +444,11 @@ typedef struct TU_ATTR_PACKED uint16_t bcdDFUVersion; } tusb_desc_dfu_functional_t; -/*------------------------------------------------------------------*/ -/* Types - *------------------------------------------------------------------*/ -typedef struct TU_ATTR_PACKED{ +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +typedef struct TU_ATTR_PACKED { union { struct TU_ATTR_PACKED { uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t. @@ -496,7 +467,6 @@ typedef struct TU_ATTR_PACKED{ TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "size is not correct"); - TU_ATTR_PACKED_END // End of all packed definitions TU_ATTR_BIT_FIELD_ORDER_END @@ -505,36 +475,25 @@ TU_ATTR_BIT_FIELD_ORDER_END //--------------------------------------------------------------------+ // Get direction from Endpoint address -TU_ATTR_ALWAYS_INLINE static inline tusb_dir_t tu_edpt_dir(uint8_t addr) -{ +TU_ATTR_ALWAYS_INLINE static inline tusb_dir_t tu_edpt_dir(uint8_t addr) { return (addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; } // Get Endpoint number from address -TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_number(uint8_t addr) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_number(uint8_t addr) { return (uint8_t)(addr & (~TUSB_DIR_IN_MASK)); } -TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir) { return (uint8_t)(num | (dir ? TUSB_DIR_IN_MASK : 0)); } -TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep) -{ - return tu_le16toh(desc_ep->wMaxPacketSize) & TU_GENMASK(10, 0); +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep) { + return tu_le16toh(desc_ep->wMaxPacketSize) & 0x7FF; } #if CFG_TUSB_DEBUG -TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_dir_str(tusb_dir_t dir) -{ - tu_static const char *str[] = {"out", "in"}; - return str[dir]; -} - -TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_t t) -{ +TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_t t) { tu_static const char *str[] = {"control", "isochronous", "bulk", "interrupt"}; return str[t]; } @@ -545,21 +504,18 @@ TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_ //--------------------------------------------------------------------+ // return next descriptor -TU_ATTR_ALWAYS_INLINE static inline uint8_t const * tu_desc_next(void const* desc) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t const * tu_desc_next(void const* desc) { uint8_t const* desc8 = (uint8_t const*) desc; return desc8 + desc8[DESC_OFFSET_LEN]; } // get descriptor type -TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_type(void const* desc) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_type(void const* desc) { return ((uint8_t const*) desc)[DESC_OFFSET_TYPE]; } // get descriptor length -TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc) { return ((uint8_t const*) desc)[DESC_OFFSET_LEN]; } @@ -576,6 +532,4 @@ uint8_t const * tu_desc_find3(uint8_t const* desc, uint8_t const* end, uint8_t b } #endif -#endif /* _TUSB_TYPES_H_ */ - -/** @} */ +#endif // TUSB_TYPES_H_ diff --git a/test-devices/composite-stm32/lib/tinyusb/common/tusb_verify.h b/test-devices/composite-stm32/lib/tinyusb/common/tusb_verify.h index 12355e8b..0a9549c9 100644 --- a/test-devices/composite-stm32/lib/tinyusb/common/tusb_verify.h +++ b/test-devices/composite-stm32/lib/tinyusb/common/tusb_verify.h @@ -56,12 +56,8 @@ * #define TU_VERIFY(cond) if(cond) return false; * #define TU_VERIFY(cond,ret) if(cond) return ret; * - * #define TU_VERIFY_HDLR(cond,handler) if(cond) {handler; return false;} - * #define TU_VERIFY_HDLR(cond,ret,handler) if(cond) {handler; return ret;} - * * #define TU_ASSERT(cond) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return false;} * #define TU_ASSERT(cond,ret) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return ret;} - * *------------------------------------------------------------------*/ #ifdef __cplusplus @@ -79,15 +75,16 @@ #define _MESS_FAILED() do {} while (0) #endif -// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7, M33 -#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__) +// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7, M33. M55 +#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8_1M_MAIN__) || \ + defined(__ARM7M__) || defined (__ARM7EM__) || defined(__ARM8M_MAINLINE__) || defined(__ARM8EM_MAINLINE__) #define TU_BREAKPOINT() do \ { \ volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \ if ( (*ARM_CM_DHCSR) & 1UL ) __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */ \ } while(0) -#elif defined(__riscv) +#elif defined(__riscv) && !TUP_MCU_ESPRESSIF #define TU_BREAKPOINT() do { __asm("ebreak\n"); } while(0) #elif defined(_mips) @@ -97,40 +94,23 @@ #define TU_BREAKPOINT() do {} while (0) #endif -/*------------------------------------------------------------------*/ -/* Macro Generator - *------------------------------------------------------------------*/ - // Helper to implement optional parameter for TU_VERIFY Macro family #define _GET_3RD_ARG(arg1, arg2, arg3, ...) arg3 -#define _GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4 - -/*------------- Generator for TU_VERIFY and TU_VERIFY_HDLR -------------*/ -#define TU_VERIFY_DEFINE(_cond, _handler, _ret) do \ -{ \ - if ( !(_cond) ) { _handler; return _ret; } \ -} while(0) /*------------------------------------------------------------------*/ /* TU_VERIFY * - TU_VERIFY_1ARGS : return false if failed * - TU_VERIFY_2ARGS : return provided value if failed *------------------------------------------------------------------*/ -#define TU_VERIFY_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, , false) -#define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, , _ret) +#define TU_VERIFY_DEFINE(_cond, _ret) \ + do { \ + if ( !(_cond) ) { return _ret; } \ + } while(0) -#define TU_VERIFY(...) _GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, UNUSED)(__VA_ARGS__) +#define TU_VERIFY_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, false) +#define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _ret) - -/*------------------------------------------------------------------*/ -/* TU_VERIFY WITH HANDLER - * - TU_VERIFY_HDLR_2ARGS : execute handler, return false if failed - * - TU_VERIFY_HDLR_3ARGS : execute handler, return provided error if failed - *------------------------------------------------------------------*/ -#define TU_VERIFY_HDLR_2ARGS(_cond, _handler) TU_VERIFY_DEFINE(_cond, _handler, false) -#define TU_VERIFY_HDLR_3ARGS(_cond, _handler, _ret) TU_VERIFY_DEFINE(_cond, _handler, _ret) - -#define TU_VERIFY_HDLR(...) _GET_4TH_ARG(__VA_ARGS__, TU_VERIFY_HDLR_3ARGS, TU_VERIFY_HDLR_2ARGS,UNUSED)(__VA_ARGS__) +#define TU_VERIFY(...) _GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, _dummy)(__VA_ARGS__) /*------------------------------------------------------------------*/ /* ASSERT @@ -138,19 +118,20 @@ * - 1 arg : return false if failed * - 2 arg : return error if failed *------------------------------------------------------------------*/ -#define ASSERT_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), false) -#define ASSERT_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), _ret) +#define TU_ASSERT_DEFINE(_cond, _ret) \ + do { \ + if ( !(_cond) ) { _MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \ + } while(0) + +#define TU_ASSERT_1ARGS(_cond) TU_ASSERT_DEFINE(_cond, false) +#define TU_ASSERT_2ARGS(_cond, _ret) TU_ASSERT_DEFINE(_cond, _ret) #ifndef TU_ASSERT -#define TU_ASSERT(...) _GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS,UNUSED)(__VA_ARGS__) +#define TU_ASSERT(...) _GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__) #endif -/*------------------------------------------------------------------*/ -/* ASSERT HDLR - *------------------------------------------------------------------*/ - #ifdef __cplusplus } #endif -#endif /* TUSB_VERIFY_H_ */ +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/device/dcd.h b/test-devices/composite-stm32/lib/tinyusb/device/dcd.h index 00419ff0..d4f105aa 100644 --- a/test-devices/composite-stm32/lib/tinyusb/device/dcd.h +++ b/test-devices/composite-stm32/lib/tinyusb/device/dcd.h @@ -47,8 +47,7 @@ // MACRO CONSTANT TYPEDEF PROTYPES //--------------------------------------------------------------------+ -typedef enum -{ +typedef enum { DCD_EVENT_INVALID = 0, DCD_EVENT_BUS_RESET, DCD_EVENT_UNPLUGGED, @@ -65,13 +64,11 @@ typedef enum DCD_EVENT_COUNT } dcd_eventid_t; -typedef struct TU_ATTR_ALIGNED(4) -{ +typedef struct TU_ATTR_ALIGNED(4) { uint8_t rhport; uint8_t event_id; - union - { + union { // BUS RESET struct { tusb_speed_t speed; @@ -102,12 +99,31 @@ typedef struct TU_ATTR_ALIGNED(4) //TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct"); +//--------------------------------------------------------------------+ +// Memory API +//--------------------------------------------------------------------+ + +// clean/flush data cache: write cache -> memory. +// Required before an DMA TX transfer to make sure data is in memory +void dcd_dcache_clean(void const* addr, uint32_t data_size) TU_ATTR_WEAK; + +// invalidate data cache: mark cache as invalid, next read will read from memory +// Required BOTH before and after an DMA RX transfer +void dcd_dcache_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK; + +// clean and invalidate data cache +// Required before an DMA transfer where memory is both read/write by DMA +void dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK; + //--------------------------------------------------------------------+ // Controller API //--------------------------------------------------------------------+ // Initialize controller to device mode -void dcd_init (uint8_t rhport); +void dcd_init(uint8_t rhport); + +// Deinitialize controller, unset device mode. +bool dcd_deinit(uint8_t rhport); // Interrupt Handler void dcd_int_handler(uint8_t rhport); @@ -139,7 +155,7 @@ void dcd_sof_enable(uint8_t rhport, bool en); // Invoked when a control transfer's status stage is complete. // May help DCD to prepare for next control transfer, this API is optional. -void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) TU_ATTR_WEAK; +void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request); // Configure endpoint's registers according to descriptor bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_ep); @@ -168,11 +184,12 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr); // Allocate packet buffer used by ISO endpoints -// Some MCU need manual packet buffer allocation, we allocation largest size to avoid clustering +// Some MCU need manual packet buffer allocation, we allocate the largest size to avoid clustering TU_ATTR_WEAK bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size); // Configure and enable an ISO endpoint according to descriptor -TU_ATTR_WEAK bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); +TU_ATTR_WEAK bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); + //--------------------------------------------------------------------+ // Event API (implemented by stack) //--------------------------------------------------------------------+ @@ -181,23 +198,20 @@ TU_ATTR_WEAK bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t co extern void dcd_event_handler(dcd_event_t const * event, bool in_isr); // helper to send bus signal event -TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr) -{ +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr) { dcd_event_t event = { .rhport = rhport, .event_id = eid }; dcd_event_handler(&event, in_isr); } // helper to send bus reset event -TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_reset (uint8_t rhport, tusb_speed_t speed, bool in_isr) -{ +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_reset (uint8_t rhport, tusb_speed_t speed, bool in_isr) { dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_BUS_RESET }; event.bus_reset.speed = speed; dcd_event_handler(&event, in_isr); } // helper to send setup received -TU_ATTR_ALWAYS_INLINE static inline void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr) -{ +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr) { dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SETUP_RECEIVED }; memcpy(&event.setup_received, setup, sizeof(tusb_control_request_t)); @@ -205,8 +219,7 @@ TU_ATTR_ALWAYS_INLINE static inline void dcd_event_setup_received(uint8_t rhport } // helper to send transfer complete event -TU_ATTR_ALWAYS_INLINE static inline void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr) -{ +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr) { dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_XFER_COMPLETE }; event.xfer_complete.ep_addr = ep_addr; @@ -216,8 +229,7 @@ TU_ATTR_ALWAYS_INLINE static inline void dcd_event_xfer_complete (uint8_t rhport dcd_event_handler(&event, in_isr); } -static inline void dcd_event_sof(uint8_t rhport, uint32_t frame_count, bool in_isr) -{ +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_sof(uint8_t rhport, uint32_t frame_count, bool in_isr) { dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SOF }; event.sof.frame_count = frame_count; dcd_event_handler(&event, in_isr); diff --git a/test-devices/composite-stm32/lib/tinyusb/device/usbd.c b/test-devices/composite-stm32/lib/tinyusb/device/usbd.c index cee56af6..e51aa0fc 100644 --- a/test-devices/composite-stm32/lib/tinyusb/device/usbd.c +++ b/test-devices/composite-stm32/lib/tinyusb/device/usbd.c @@ -38,13 +38,23 @@ //--------------------------------------------------------------------+ // USBD Configuration //--------------------------------------------------------------------+ - #ifndef CFG_TUD_TASK_QUEUE_SZ #define CFG_TUD_TASK_QUEUE_SZ 16 #endif -// Debug level of USBD -#define USBD_DBG 2 +//--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK bool dcd_deinit(uint8_t rhport) { + (void) rhport; + return false; +} + +TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) { + (void)rhport; + (void)eventid; + (void)in_isr; +} //--------------------------------------------------------------------+ // Device Data @@ -53,10 +63,8 @@ // Invalid driver ID in itf2drv[] ep2drv[][] mapping enum { DRVID_INVALID = 0xFFu }; -typedef struct -{ - struct TU_ATTR_PACKED - { +typedef struct { + struct TU_ATTR_PACKED { volatile uint8_t connected : 1; volatile uint8_t addressed : 1; volatile uint8_t suspended : 1; @@ -65,9 +73,9 @@ typedef struct uint8_t remote_wakeup_support : 1; // configuration descriptor's attribute uint8_t self_powered : 1; // configuration descriptor's attribute }; - volatile uint8_t cfg_num; // current active configuration (0x00 is not configured) uint8_t speed; + volatile uint8_t setup_count; uint8_t itf2drv[CFG_TUD_INTERFACE_MAX]; // map interface number to driver (0xff is invalid) uint8_t ep2drv[CFG_TUD_ENDPPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid ), can use only 4-bit each @@ -81,158 +89,169 @@ tu_static usbd_device_t _usbd_dev; //--------------------------------------------------------------------+ // Class Driver //--------------------------------------------------------------------+ -#if CFG_TUSB_DEBUG >= 2 +#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL #define DRIVER_NAME(_name) .name = _name, #else #define DRIVER_NAME(_name) #endif // Built-in class drivers -tu_static usbd_class_driver_t const _usbd_driver[] = -{ - #if CFG_TUD_CDC - { - DRIVER_NAME("CDC") - .init = cdcd_init, - .reset = cdcd_reset, - .open = cdcd_open, - .control_xfer_cb = cdcd_control_xfer_cb, - .xfer_cb = cdcd_xfer_cb, - .sof = NULL - }, - #endif - - #if CFG_TUD_MSC - { - DRIVER_NAME("MSC") - .init = mscd_init, - .reset = mscd_reset, - .open = mscd_open, - .control_xfer_cb = mscd_control_xfer_cb, - .xfer_cb = mscd_xfer_cb, - .sof = NULL - }, - #endif - - #if CFG_TUD_HID - { - DRIVER_NAME("HID") - .init = hidd_init, - .reset = hidd_reset, - .open = hidd_open, - .control_xfer_cb = hidd_control_xfer_cb, - .xfer_cb = hidd_xfer_cb, - .sof = NULL - }, - #endif - - #if CFG_TUD_AUDIO - { - DRIVER_NAME("AUDIO") - .init = audiod_init, - .reset = audiod_reset, - .open = audiod_open, - .control_xfer_cb = audiod_control_xfer_cb, - .xfer_cb = audiod_xfer_cb, - .sof = audiod_sof_isr - }, - #endif - - #if CFG_TUD_VIDEO - { - DRIVER_NAME("VIDEO") - .init = videod_init, - .reset = videod_reset, - .open = videod_open, - .control_xfer_cb = videod_control_xfer_cb, - .xfer_cb = videod_xfer_cb, - .sof = NULL - }, - #endif - - #if CFG_TUD_MIDI - { - DRIVER_NAME("MIDI") - .init = midid_init, - .open = midid_open, - .reset = midid_reset, - .control_xfer_cb = midid_control_xfer_cb, - .xfer_cb = midid_xfer_cb, - .sof = NULL - }, - #endif - - #if CFG_TUD_VENDOR - { - DRIVER_NAME("VENDOR") - .init = vendord_init, - .reset = vendord_reset, - .open = vendord_open, - .control_xfer_cb = tud_vendor_control_xfer_cb, - .xfer_cb = vendord_xfer_cb, - .sof = NULL - }, - #endif - - #if CFG_TUD_USBTMC - { - DRIVER_NAME("TMC") - .init = usbtmcd_init_cb, - .reset = usbtmcd_reset_cb, - .open = usbtmcd_open_cb, - .control_xfer_cb = usbtmcd_control_xfer_cb, - .xfer_cb = usbtmcd_xfer_cb, - .sof = NULL - }, - #endif - - #if CFG_TUD_DFU_RUNTIME - { - DRIVER_NAME("DFU-RUNTIME") - .init = dfu_rtd_init, - .reset = dfu_rtd_reset, - .open = dfu_rtd_open, - .control_xfer_cb = dfu_rtd_control_xfer_cb, - .xfer_cb = NULL, - .sof = NULL - }, - #endif - - #if CFG_TUD_DFU - { - DRIVER_NAME("DFU") - .init = dfu_moded_init, - .reset = dfu_moded_reset, - .open = dfu_moded_open, - .control_xfer_cb = dfu_moded_control_xfer_cb, - .xfer_cb = NULL, - .sof = NULL - }, - #endif - - #if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM - { - DRIVER_NAME("NET") - .init = netd_init, - .reset = netd_reset, - .open = netd_open, - .control_xfer_cb = netd_control_xfer_cb, - .xfer_cb = netd_xfer_cb, - .sof = NULL, - }, - #endif - - #if CFG_TUD_BTH - { - DRIVER_NAME("BTH") - .init = btd_init, - .reset = btd_reset, - .open = btd_open, - .control_xfer_cb = btd_control_xfer_cb, - .xfer_cb = btd_xfer_cb, - .sof = NULL - }, - #endif +tu_static usbd_class_driver_t const _usbd_driver[] = { + #if CFG_TUD_CDC + { + DRIVER_NAME("CDC") + .init = cdcd_init, + .deinit = cdcd_deinit, + .reset = cdcd_reset, + .open = cdcd_open, + .control_xfer_cb = cdcd_control_xfer_cb, + .xfer_cb = cdcd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_MSC + { + DRIVER_NAME("MSC") + .init = mscd_init, + .deinit = NULL, + .reset = mscd_reset, + .open = mscd_open, + .control_xfer_cb = mscd_control_xfer_cb, + .xfer_cb = mscd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_HID + { + DRIVER_NAME("HID") + .init = hidd_init, + .deinit = hidd_deinit, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hidd_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_AUDIO + { + DRIVER_NAME("AUDIO") + .init = audiod_init, + .deinit = audiod_deinit, + .reset = audiod_reset, + .open = audiod_open, + .control_xfer_cb = audiod_control_xfer_cb, + .xfer_cb = audiod_xfer_cb, + .sof = audiod_sof_isr + }, + #endif + + #if CFG_TUD_VIDEO + { + DRIVER_NAME("VIDEO") + .init = videod_init, + .deinit = videod_deinit, + .reset = videod_reset, + .open = videod_open, + .control_xfer_cb = videod_control_xfer_cb, + .xfer_cb = videod_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_MIDI + { + DRIVER_NAME("MIDI") + .init = midid_init, + .deinit = midid_deinit, + .open = midid_open, + .reset = midid_reset, + .control_xfer_cb = midid_control_xfer_cb, + .xfer_cb = midid_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_VENDOR + { + DRIVER_NAME("VENDOR") + .init = vendord_init, + .deinit = vendord_deinit, + .reset = vendord_reset, + .open = vendord_open, + .control_xfer_cb = tud_vendor_control_xfer_cb, + .xfer_cb = vendord_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_USBTMC + { + DRIVER_NAME("TMC") + .init = usbtmcd_init_cb, + .deinit = usbtmcd_deinit, + .reset = usbtmcd_reset_cb, + .open = usbtmcd_open_cb, + .control_xfer_cb = usbtmcd_control_xfer_cb, + .xfer_cb = usbtmcd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_DFU_RUNTIME + { + DRIVER_NAME("DFU-RUNTIME") + .init = dfu_rtd_init, + .deinit = dfu_rtd_deinit, + .reset = dfu_rtd_reset, + .open = dfu_rtd_open, + .control_xfer_cb = dfu_rtd_control_xfer_cb, + .xfer_cb = NULL, + .sof = NULL + }, + #endif + + #if CFG_TUD_DFU + { + DRIVER_NAME("DFU") + .init = dfu_moded_init, + .deinit = dfu_moded_deinit, + .reset = dfu_moded_reset, + .open = dfu_moded_open, + .control_xfer_cb = dfu_moded_control_xfer_cb, + .xfer_cb = NULL, + .sof = NULL + }, + #endif + + #if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM + { + DRIVER_NAME("NET") + .init = netd_init, + .deinit = netd_deinit, + .reset = netd_reset, + .open = netd_open, + .control_xfer_cb = netd_control_xfer_cb, + .xfer_cb = netd_xfer_cb, + .sof = NULL, + }, + #endif + + #if CFG_TUD_BTH + { + DRIVER_NAME("BTH") + .init = btd_init, + .deinit = btd_deinit, + .reset = btd_reset, + .open = btd_open, + .control_xfer_cb = btd_control_xfer_cb, + .xfer_cb = btd_xfer_cb, + .sof = NULL + }, + #endif }; enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(_usbd_driver) }; @@ -241,25 +260,21 @@ enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(_usbd_driver) }; tu_static usbd_class_driver_t const * _app_driver = NULL; tu_static uint8_t _app_driver_count = 0; +#define TOTAL_DRIVER_COUNT (_app_driver_count + BUILTIN_DRIVER_COUNT) + // virtually joins built-in and application drivers together. // Application is positioned first to allow overwriting built-in ones. -static inline usbd_class_driver_t const * get_driver(uint8_t drvid) -{ - // Application drivers - if ( usbd_app_driver_get_cb ) - { - if ( drvid < _app_driver_count ) return &_app_driver[drvid]; - drvid -= _app_driver_count; +TU_ATTR_ALWAYS_INLINE static inline usbd_class_driver_t const * get_driver(uint8_t drvid) { + usbd_class_driver_t const * driver = NULL; + if ( drvid < _app_driver_count ) { + // Application drivers + driver = &_app_driver[drvid]; + } else if ( drvid < TOTAL_DRIVER_COUNT && BUILTIN_DRIVER_COUNT > 0 ){ + driver = &_usbd_driver[drvid - _app_driver_count]; } - - // Built-in drivers - if (drvid < BUILTIN_DRIVER_COUNT) return &_usbd_driver[drvid]; - - return NULL; + return driver; } -#define TOTAL_DRIVER_COUNT (_app_driver_count + BUILTIN_DRIVER_COUNT) - //--------------------------------------------------------------------+ // DCD Event //--------------------------------------------------------------------+ @@ -280,6 +295,11 @@ tu_static osal_queue_t _usbd_q; #define _usbd_mutex NULL #endif +TU_ATTR_ALWAYS_INLINE static inline bool queue_event(dcd_event_t const * event, bool in_isr) { + TU_ASSERT(osal_queue_send(_usbd_q, event, in_isr)); + tud_event_hook_cb(event->rhport, event->event_id, in_isr); + return true; +} //--------------------------------------------------------------------+ // Prototypes @@ -298,29 +318,25 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, //--------------------------------------------------------------------+ // Debug //--------------------------------------------------------------------+ -#if CFG_TUSB_DEBUG >= 2 -tu_static char const* const _usbd_event_str[DCD_EVENT_COUNT] = -{ - "Invalid" , - "Bus Reset" , - "Unplugged" , - "SOF" , - "Suspend" , - "Resume" , - "Setup Received" , - "Xfer Complete" , - "Func Call" +#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL +tu_static char const* const _usbd_event_str[DCD_EVENT_COUNT] = { + "Invalid", + "Bus Reset", + "Unplugged", + "SOF", + "Suspend", + "Resume", + "Setup Received", + "Xfer Complete", + "Func Call" }; // for usbd_control to print the name of control complete driver -void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback) -{ - for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) - { - usbd_class_driver_t const * driver = get_driver(i); - if ( driver && driver->control_xfer_cb == callback ) - { - TU_LOG(USBD_DBG, " %s control complete\r\n", driver->name); +void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback) { + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) { + usbd_class_driver_t const* driver = get_driver(i); + if (driver && driver->control_xfer_cb == callback) { + TU_LOG_USBD("%s control complete\r\n", driver->name); return; } } @@ -331,43 +347,36 @@ void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback) //--------------------------------------------------------------------+ // Application API //--------------------------------------------------------------------+ -tusb_speed_t tud_speed_get(void) -{ +tusb_speed_t tud_speed_get(void) { return (tusb_speed_t) _usbd_dev.speed; } -bool tud_connected(void) -{ +bool tud_connected(void) { return _usbd_dev.connected; } -bool tud_mounted(void) -{ +bool tud_mounted(void) { return _usbd_dev.cfg_num ? true : false; } -bool tud_suspended(void) -{ +bool tud_suspended(void) { return _usbd_dev.suspended; } -bool tud_remote_wakeup(void) -{ +bool tud_remote_wakeup(void) { // only wake up host if this feature is supported and enabled and we are suspended - TU_VERIFY (_usbd_dev.suspended && _usbd_dev.remote_wakeup_support && _usbd_dev.remote_wakeup_en ); + TU_VERIFY (_usbd_dev.suspended && _usbd_dev.remote_wakeup_support && _usbd_dev.remote_wakeup_en); dcd_remote_wakeup(_usbd_rhport); return true; } -bool tud_disconnect(void) -{ +bool tud_disconnect(void) { TU_VERIFY(dcd_disconnect); dcd_disconnect(_usbd_rhport); return true; } -bool tud_connect(void) -{ +bool tud_connect(void) { TU_VERIFY(dcd_connect); dcd_connect(_usbd_rhport); return true; @@ -376,20 +385,19 @@ bool tud_connect(void) //--------------------------------------------------------------------+ // USBD Task //--------------------------------------------------------------------+ -bool tud_inited(void) -{ +bool tud_inited(void) { return _usbd_rhport != RHPORT_INVALID; } -bool tud_init (uint8_t rhport) -{ +bool tud_init(uint8_t rhport) { // skip if already initialized - if ( tud_inited() ) return true; + if (tud_inited()) return true; - TU_LOG(USBD_DBG, "USBD init on controller %u\r\n", rhport); - TU_LOG_INT(USBD_DBG, sizeof(usbd_device_t)); - TU_LOG_INT(USBD_DBG, sizeof(tu_fifo_t)); - TU_LOG_INT(USBD_DBG, sizeof(tu_edpt_stream_t)); + TU_LOG_USBD("USBD init on controller %u\r\n", rhport); + TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(usbd_device_t)); + TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(dcd_event_t)); + TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_fifo_t)); + TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_edpt_stream_t)); tu_varclr(&_usbd_dev); @@ -404,17 +412,15 @@ bool tud_init (uint8_t rhport) TU_ASSERT(_usbd_q); // Get application driver if available - if ( usbd_app_driver_get_cb ) - { + if (usbd_app_driver_get_cb) { _app_driver = usbd_app_driver_get_cb(&_app_driver_count); } // Init class drivers - for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) - { - usbd_class_driver_t const * driver = get_driver(i); - TU_ASSERT(driver); - TU_LOG(USBD_DBG, "%s init\r\n", driver->name); + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) { + usbd_class_driver_t const* driver = get_driver(i); + TU_ASSERT(driver && driver->init); + TU_LOG_USBD("%s init\r\n", driver->name); driver->init(); } @@ -427,31 +433,61 @@ bool tud_init (uint8_t rhport) return true; } -static void configuration_reset(uint8_t rhport) -{ - for ( uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++ ) - { - usbd_class_driver_t const * driver = get_driver(i); - TU_ASSERT(driver, ); +bool tud_deinit(uint8_t rhport) { + // skip if not initialized + if (!tud_inited()) return true; + + TU_LOG_USBD("USBD deinit on controller %u\r\n", rhport); + + // Deinit device controller driver + dcd_int_disable(rhport); + dcd_disconnect(rhport); + dcd_deinit(rhport); + + // Deinit class drivers + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) { + usbd_class_driver_t const* driver = get_driver(i); + if(driver && driver->deinit) { + TU_LOG_USBD("%s deinit\r\n", driver->name); + driver->deinit(); + } + } + + // Deinit device queue & task + osal_queue_delete(_usbd_q); + _usbd_q = NULL; + +#if OSAL_MUTEX_REQUIRED + // TODO make sure there is no task waiting on this mutex + osal_mutex_delete(_usbd_mutex); + _usbd_mutex = NULL; +#endif + + _usbd_rhport = RHPORT_INVALID; + + return true; +} + +static void configuration_reset(uint8_t rhport) { + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) { + usbd_class_driver_t const* driver = get_driver(i); + TU_ASSERT(driver,); driver->reset(rhport); } tu_varclr(&_usbd_dev); memset(_usbd_dev.itf2drv, DRVID_INVALID, sizeof(_usbd_dev.itf2drv)); // invalid mapping - memset(_usbd_dev.ep2drv , DRVID_INVALID, sizeof(_usbd_dev.ep2drv )); // invalid mapping + memset(_usbd_dev.ep2drv, DRVID_INVALID, sizeof(_usbd_dev.ep2drv)); // invalid mapping } -static void usbd_reset(uint8_t rhport) -{ +static void usbd_reset(uint8_t rhport) { configuration_reset(rhport); usbd_control_reset(); } -bool tud_task_event_ready(void) -{ +bool tud_task_event_ready(void) { // Skip if stack is not initialized - if ( !tud_inited() ) return false; - + if (!tud_inited()) return false; return !osal_queue_empty(_usbd_q); } @@ -459,139 +495,126 @@ bool tud_task_event_ready(void) * This top level thread manages all device controller event and delegates events to class-specific drivers. * This should be called periodically within the mainloop or rtos thread. * - @code - int main(void) - { + int main(void) { application_init(); tusb_init(); - while(1) // the mainloop - { + while(1) { // the mainloop application_code(); tud_task(); // tinyusb device task } } - @endcode */ -void tud_task_ext(uint32_t timeout_ms, bool in_isr) -{ +void tud_task_ext(uint32_t timeout_ms, bool in_isr) { (void) in_isr; // not implemented yet // Skip if stack is not initialized - if ( !tud_inited() ) return; + if (!tud_inited()) return; // Loop until there is no more events in the queue - while (1) - { + while (1) { dcd_event_t event; - if ( !osal_queue_receive(_usbd_q, &event, timeout_ms) ) return; + if (!osal_queue_receive(_usbd_q, &event, timeout_ms)) return; -#if CFG_TUSB_DEBUG >= 2 - if (event.event_id == DCD_EVENT_SETUP_RECEIVED) TU_LOG(USBD_DBG, "\r\n"); // extra line for setup - TU_LOG(USBD_DBG, "USBD %s ", event.event_id < DCD_EVENT_COUNT ? _usbd_event_str[event.event_id] : "CORRUPTED"); +#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL + if (event.event_id == DCD_EVENT_SETUP_RECEIVED) TU_LOG_USBD("\r\n"); // extra line for setup + TU_LOG_USBD("USBD %s ", event.event_id < DCD_EVENT_COUNT ? _usbd_event_str[event.event_id] : "CORRUPTED"); #endif - switch ( event.event_id ) - { + switch (event.event_id) { case DCD_EVENT_BUS_RESET: - TU_LOG(USBD_DBG, ": %s Speed\r\n", tu_str_speed[event.bus_reset.speed]); + TU_LOG_USBD(": %s Speed\r\n", tu_str_speed[event.bus_reset.speed]); usbd_reset(event.rhport); _usbd_dev.speed = event.bus_reset.speed; - break; + break; case DCD_EVENT_UNPLUGGED: - TU_LOG(USBD_DBG, "\r\n"); + TU_LOG_USBD("\r\n"); usbd_reset(event.rhport); - - // invoke callback if (tud_umount_cb) tud_umount_cb(); - break; + break; case DCD_EVENT_SETUP_RECEIVED: - TU_LOG_PTR(USBD_DBG, &event.setup_received); - TU_LOG(USBD_DBG, "\r\n"); + _usbd_dev.setup_count--; + TU_LOG_BUF(CFG_TUD_LOG_LEVEL, &event.setup_received, 8); + if (_usbd_dev.setup_count) { + TU_LOG_USBD(" Skipped since there is other SETUP in queue\r\n"); + break; + } // Mark as connected after receiving 1st setup packet. // But it is easier to set it every time instead of wasting time to check then set _usbd_dev.connected = 1; // mark both in & out control as free - _usbd_dev.ep_status[0][TUSB_DIR_OUT].busy = false; + _usbd_dev.ep_status[0][TUSB_DIR_OUT].busy = 0; _usbd_dev.ep_status[0][TUSB_DIR_OUT].claimed = 0; - _usbd_dev.ep_status[0][TUSB_DIR_IN ].busy = false; - _usbd_dev.ep_status[0][TUSB_DIR_IN ].claimed = 0; + _usbd_dev.ep_status[0][TUSB_DIR_IN].busy = 0; + _usbd_dev.ep_status[0][TUSB_DIR_IN].claimed = 0; // Process control request - if ( !process_control_request(event.rhport, &event.setup_received) ) - { - TU_LOG(USBD_DBG, " Stall EP0\r\n"); + if (!process_control_request(event.rhport, &event.setup_received)) { + TU_LOG_USBD(" Stall EP0\r\n"); // Failed -> stall both control endpoint IN and OUT dcd_edpt_stall(event.rhport, 0); dcd_edpt_stall(event.rhport, 0 | TUSB_DIR_IN_MASK); } - break; + break; - case DCD_EVENT_XFER_COMPLETE: - { + case DCD_EVENT_XFER_COMPLETE: { // Invoke the class callback associated with the endpoint address uint8_t const ep_addr = event.xfer_complete.ep_addr; - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const ep_dir = tu_edpt_dir(ep_addr); + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const ep_dir = tu_edpt_dir(ep_addr); - TU_LOG(USBD_DBG, "on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len); + TU_LOG_USBD("on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len); - _usbd_dev.ep_status[epnum][ep_dir].busy = false; + _usbd_dev.ep_status[epnum][ep_dir].busy = 0; _usbd_dev.ep_status[epnum][ep_dir].claimed = 0; - if ( 0 == epnum ) - { - usbd_control_xfer_cb(event.rhport, ep_addr, (xfer_result_t)event.xfer_complete.result, event.xfer_complete.len); - } - else - { - usbd_class_driver_t const * driver = get_driver( _usbd_dev.ep2drv[epnum][ep_dir] ); - TU_ASSERT(driver, ); + if (0 == epnum) { + usbd_control_xfer_cb(event.rhport, ep_addr, (xfer_result_t) event.xfer_complete.result, + event.xfer_complete.len); + } else { + usbd_class_driver_t const* driver = get_driver(_usbd_dev.ep2drv[epnum][ep_dir]); + TU_ASSERT(driver,); - TU_LOG(USBD_DBG, " %s xfer callback\r\n", driver->name); - driver->xfer_cb(event.rhport, ep_addr, (xfer_result_t)event.xfer_complete.result, event.xfer_complete.len); + TU_LOG_USBD(" %s xfer callback\r\n", driver->name); + driver->xfer_cb(event.rhport, ep_addr, (xfer_result_t) event.xfer_complete.result, event.xfer_complete.len); } + break; } - break; case DCD_EVENT_SUSPEND: // NOTE: When plugging/unplugging device, the D+/D- state are unstable and // can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ), which result in a series of event // e.g suspend -> resume -> unplug/plug. Skip suspend/resume if not connected - if ( _usbd_dev.connected ) - { - TU_LOG(USBD_DBG, ": Remote Wakeup = %u\r\n", _usbd_dev.remote_wakeup_en); + if (_usbd_dev.connected) { + TU_LOG_USBD(": Remote Wakeup = %u\r\n", _usbd_dev.remote_wakeup_en); if (tud_suspend_cb) tud_suspend_cb(_usbd_dev.remote_wakeup_en); - }else - { - TU_LOG(USBD_DBG, " Skipped\r\n"); + } else { + TU_LOG_USBD(" Skipped\r\n"); } - break; + break; case DCD_EVENT_RESUME: - if ( _usbd_dev.connected ) - { - TU_LOG(USBD_DBG, "\r\n"); + if (_usbd_dev.connected) { + TU_LOG_USBD("\r\n"); if (tud_resume_cb) tud_resume_cb(); - }else - { - TU_LOG(USBD_DBG, " Skipped\r\n"); + } else { + TU_LOG_USBD(" Skipped\r\n"); } - break; + break; case USBD_EVENT_FUNC_CALL: - TU_LOG(USBD_DBG, "\r\n"); - if ( event.func_call.func ) event.func_call.func(event.func_call.param); - break; + TU_LOG_USBD("\r\n"); + if (event.func_call.func) event.func_call.func(event.func_call.param); + break; case DCD_EVENT_SOF: default: TU_BREAKPOINT(); - break; + break; } #if CFG_TUSB_OS != OPT_OS_NONE && CFG_TUSB_OS != OPT_OS_PICO @@ -606,44 +629,37 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) //--------------------------------------------------------------------+ // Helper to invoke class driver control request handler -static bool invoke_class_control(uint8_t rhport, usbd_class_driver_t const * driver, tusb_control_request_t const * request) -{ +static bool invoke_class_control(uint8_t rhport, usbd_class_driver_t const * driver, tusb_control_request_t const * request) { usbd_control_set_complete_callback(driver->control_xfer_cb); - TU_LOG(USBD_DBG, " %s control request\r\n", driver->name); + TU_LOG_USBD(" %s control request\r\n", driver->name); return driver->control_xfer_cb(rhport, CONTROL_STAGE_SETUP, request); } // This handles the actual request and its response. -// return false will cause its caller to stall control endpoint -static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request) -{ +// Returns false if unable to complete the request, causing caller to stall control endpoints. +static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request) { usbd_control_set_complete_callback(NULL); - TU_ASSERT(p_request->bmRequestType_bit.type < TUSB_REQ_TYPE_INVALID); // Vendor request - if ( p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR ) - { + if ( p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR ) { TU_VERIFY(tud_vendor_control_xfer_cb); usbd_control_set_complete_callback(tud_vendor_control_xfer_cb); return tud_vendor_control_xfer_cb(rhport, CONTROL_STAGE_SETUP, p_request); } -#if CFG_TUSB_DEBUG >= 2 - if (TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type && p_request->bRequest <= TUSB_REQ_SYNCH_FRAME) - { - TU_LOG(USBD_DBG, " %s", tu_str_std_request[p_request->bRequest]); - if (TUSB_REQ_GET_DESCRIPTOR != p_request->bRequest) TU_LOG(USBD_DBG, "\r\n"); +#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL + if (TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type && p_request->bRequest <= TUSB_REQ_SYNCH_FRAME) { + TU_LOG_USBD(" %s", tu_str_std_request[p_request->bRequest]); + if (TUSB_REQ_GET_DESCRIPTOR != p_request->bRequest) TU_LOG_USBD("\r\n"); } #endif - switch ( p_request->bmRequestType_bit.recipient ) - { + switch ( p_request->bmRequestType_bit.recipient ) { //------------- Device Requests e.g in enumeration -------------// case TUSB_REQ_RCPT_DEVICE: - if ( TUSB_REQ_TYPE_CLASS == p_request->bmRequestType_bit.type ) - { + if ( TUSB_REQ_TYPE_CLASS == p_request->bmRequestType_bit.type ) { uint8_t const itf = tu_u16_low(p_request->wIndex); TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv)); @@ -654,15 +670,13 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const return invoke_class_control(rhport, driver, p_request); } - if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) - { + if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) { // Non standard request is not supported TU_BREAKPOINT(); return false; } - switch ( p_request->bRequest ) - { + switch ( p_request->bRequest ) { case TUSB_REQ_SET_ADDRESS: // Depending on mcu, status phase could be sent either before or after changing device address, // or even require stack to not response with status at all @@ -673,24 +687,20 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const _usbd_dev.addressed = 1; break; - case TUSB_REQ_GET_CONFIGURATION: - { + case TUSB_REQ_GET_CONFIGURATION: { uint8_t cfg_num = _usbd_dev.cfg_num; tud_control_xfer(rhport, p_request, &cfg_num, 1); } break; - case TUSB_REQ_SET_CONFIGURATION: - { + case TUSB_REQ_SET_CONFIGURATION: { uint8_t const cfg_num = (uint8_t) p_request->wValue; // Only process if new configure is different - if (_usbd_dev.cfg_num != cfg_num) - { - if ( _usbd_dev.cfg_num ) - { + if (_usbd_dev.cfg_num != cfg_num) { + if ( _usbd_dev.cfg_num ) { // already configured: need to clear all endpoints and driver first - TU_LOG(USBD_DBG, " Clear current Configuration (%u) before switching\r\n", _usbd_dev.cfg_num); + TU_LOG_USBD(" Clear current Configuration (%u) before switching\r\n", _usbd_dev.cfg_num); // close all non-control endpoints, cancel all pending transfers if any dcd_edpt_close_all(rhport); @@ -702,8 +712,14 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const _usbd_dev.speed = speed; // restore speed } - // switch to new configuration if not zero - if ( cfg_num ) TU_ASSERT( process_set_config(rhport, cfg_num) ); + // Handle the new configuration and execute the corresponding callback + if ( cfg_num ) { + // switch to new configuration if not zero + TU_ASSERT( process_set_config(rhport, cfg_num) ); + if ( tud_mount_cb ) tud_mount_cb(); + } else { + if ( tud_umount_cb ) tud_umount_cb(); + } } _usbd_dev.cfg_num = cfg_num; @@ -719,7 +735,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const // Only support remote wakeup for device feature TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue); - TU_LOG(USBD_DBG, " Enable Remote Wakeup\r\n"); + TU_LOG_USBD(" Enable Remote Wakeup\r\n"); // Host may enable remote wake up before suspending especially HID device _usbd_dev.remote_wakeup_en = true; @@ -730,22 +746,21 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const // Only support remote wakeup for device feature TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue); - TU_LOG(USBD_DBG, " Disable Remote Wakeup\r\n"); + TU_LOG_USBD(" Disable Remote Wakeup\r\n"); // Host may disable remote wake up after resuming _usbd_dev.remote_wakeup_en = false; tud_control_status(rhport, p_request); break; - case TUSB_REQ_GET_STATUS: - { + case TUSB_REQ_GET_STATUS: { // Device status bit mask // - Bit 0: Self Powered // - Bit 1: Remote Wakeup enabled uint16_t status = (uint16_t) ((_usbd_dev.self_powered ? 1u : 0u) | (_usbd_dev.remote_wakeup_en ? 2u : 0u)); tud_control_xfer(rhport, p_request, &status, 2); + break; } - break; // Unknown/Unsupported request default: TU_BREAKPOINT(); return false; @@ -753,8 +768,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const break; //------------- Class/Interface Specific Request -------------// - case TUSB_REQ_RCPT_INTERFACE: - { + case TUSB_REQ_RCPT_INTERFACE: { uint8_t const itf = tu_u16_low(p_request->wIndex); TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv)); @@ -763,25 +777,21 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const // all requests to Interface (STD or Class) is forwarded to class driver. // notable requests are: GET HID REPORT DESCRIPTOR, SET_INTERFACE, GET_INTERFACE - if ( !invoke_class_control(rhport, driver, p_request) ) - { + if ( !invoke_class_control(rhport, driver, p_request) ) { // For GET_INTERFACE and SET_INTERFACE, it is mandatory to respond even if the class // driver doesn't use alternate settings or implement this TU_VERIFY(TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type); - switch(p_request->bRequest) - { + switch(p_request->bRequest) { case TUSB_REQ_GET_INTERFACE: case TUSB_REQ_SET_INTERFACE: // Clear complete callback if driver set since it can also stall the request. usbd_control_set_complete_callback(NULL); - if (TUSB_REQ_GET_INTERFACE == p_request->bRequest) - { + if (TUSB_REQ_GET_INTERFACE == p_request->bRequest) { uint8_t alternate = 0; tud_control_xfer(rhport, p_request, &alternate, 1); - }else - { + }else { tud_control_status(rhport, p_request); } break; @@ -789,54 +799,42 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const default: return false; } } + break; } - break; //------------- Endpoint Request -------------// - case TUSB_REQ_RCPT_ENDPOINT: - { + case TUSB_REQ_RCPT_ENDPOINT: { uint8_t const ep_addr = tu_u16_low(p_request->wIndex); uint8_t const ep_num = tu_edpt_number(ep_addr); uint8_t const ep_dir = tu_edpt_dir(ep_addr); TU_ASSERT(ep_num < TU_ARRAY_SIZE(_usbd_dev.ep2drv) ); - usbd_class_driver_t const * driver = get_driver(_usbd_dev.ep2drv[ep_num][ep_dir]); - if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) - { + if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) { // Forward class request to its driver TU_VERIFY(driver); return invoke_class_control(rhport, driver, p_request); - } - else - { + } else { // Handle STD request to endpoint - switch ( p_request->bRequest ) - { - case TUSB_REQ_GET_STATUS: - { + switch ( p_request->bRequest ) { + case TUSB_REQ_GET_STATUS: { uint16_t status = usbd_edpt_stalled(rhport, ep_addr) ? 0x0001 : 0x0000; tud_control_xfer(rhport, p_request, &status, 2); } break; case TUSB_REQ_CLEAR_FEATURE: - case TUSB_REQ_SET_FEATURE: - { - if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) - { - if ( TUSB_REQ_CLEAR_FEATURE == p_request->bRequest ) - { + case TUSB_REQ_SET_FEATURE: { + if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) { + if ( TUSB_REQ_CLEAR_FEATURE == p_request->bRequest ) { usbd_edpt_clear_stall(rhport, ep_addr); - }else - { + }else { usbd_edpt_stall(rhport, ep_addr); } } - if (driver) - { + if (driver) { // Some classes such as USBTMC needs to clear/re-init its buffer when receiving CLEAR_FEATURE request // We will also forward std request targeted endpoint to class drivers as well @@ -852,14 +850,18 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const break; // Unknown/Unsupported request - default: TU_BREAKPOINT(); return false; + default: + TU_BREAKPOINT(); + return false; } } } break; // Unknown recipient - default: TU_BREAKPOINT(); return false; + default: + TU_BREAKPOINT(); + return false; } return true; @@ -913,7 +915,7 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num) if ( (sizeof(tusb_desc_interface_t) <= drv_len) && (drv_len <= remaining_len) ) { // Open successfully - TU_LOG(USBD_DBG, " %s opened\r\n", driver->name); + TU_LOG_USBD(" %s opened\r\n", driver->name); // Some drivers use 2 or more interfaces but may not have IAD e.g MIDI (always) or // BTH (even CDC) with class in device descriptor (single interface) @@ -956,9 +958,6 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num) TU_ASSERT(drv_id < TOTAL_DRIVER_COUNT); } - // invoke callback - if (tud_mount_cb) tud_mount_cb(); - return true; } @@ -972,7 +971,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const { case TUSB_DESC_DEVICE: { - TU_LOG(USBD_DBG, " Device\r\n"); + TU_LOG_USBD(" Device\r\n"); void* desc_device = (void*) (uintptr_t) tud_descriptor_device_cb(); @@ -996,7 +995,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const case TUSB_DESC_BOS: { - TU_LOG(USBD_DBG, " BOS\r\n"); + TU_LOG_USBD(" BOS\r\n"); // requested by host if USB > 2.0 ( i.e 2.1 or 3.x ) if (!tud_descriptor_bos_cb) return false; @@ -1018,12 +1017,12 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const if ( desc_type == TUSB_DESC_CONFIGURATION ) { - TU_LOG(USBD_DBG, " Configuration[%u]\r\n", desc_index); + TU_LOG_USBD(" Configuration[%u]\r\n", desc_index); desc_config = (uintptr_t) tud_descriptor_configuration_cb(desc_index); }else { // Host only request this after getting Device Qualifier descriptor - TU_LOG(USBD_DBG, " Other Speed Configuration\r\n"); + TU_LOG_USBD(" Other Speed Configuration\r\n"); TU_VERIFY( tud_descriptor_other_speed_configuration_cb ); desc_config = (uintptr_t) tud_descriptor_other_speed_configuration_cb(desc_index); } @@ -1039,7 +1038,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const case TUSB_DESC_STRING: { - TU_LOG(USBD_DBG, " String[%u]\r\n", desc_index); + TU_LOG_USBD(" String[%u]\r\n", desc_index); // String Descriptor always uses the desc set from user uint8_t const* desc_str = (uint8_t const*) tud_descriptor_string_cb(desc_index, tu_le16toh(p_request->wIndex)); @@ -1052,7 +1051,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const case TUSB_DESC_DEVICE_QUALIFIER: { - TU_LOG(USBD_DBG, " Device Qualifier\r\n"); + TU_LOG_USBD(" Device Qualifier\r\n"); TU_VERIFY( tud_descriptor_device_qualifier_cb ); @@ -1071,66 +1070,69 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const //--------------------------------------------------------------------+ // DCD Event Handler //--------------------------------------------------------------------+ -TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const * event, bool in_isr) -{ - switch (event->event_id) - { +TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr) { + bool send = false; + switch (event->event_id) { case DCD_EVENT_UNPLUGGED: - _usbd_dev.connected = 0; - _usbd_dev.addressed = 0; - _usbd_dev.cfg_num = 0; - _usbd_dev.suspended = 0; - osal_queue_send(_usbd_q, event, in_isr); - break; + _usbd_dev.connected = 0; + _usbd_dev.addressed = 0; + _usbd_dev.cfg_num = 0; + _usbd_dev.suspended = 0; + send = true; + break; case DCD_EVENT_SUSPEND: // NOTE: When plugging/unplugging device, the D+/D- state are unstable and // can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ). // In addition, some MCUs such as SAMD or boards that haven no VBUS detection cannot distinguish // suspended vs disconnected. We will skip handling SUSPEND/RESUME event if not currently connected - if ( _usbd_dev.connected ) - { + if (_usbd_dev.connected) { _usbd_dev.suspended = 1; - osal_queue_send(_usbd_q, event, in_isr); + send = true; } - break; + break; case DCD_EVENT_RESUME: // skip event if not connected (especially required for SAMD) - if ( _usbd_dev.connected ) - { + if (_usbd_dev.connected) { _usbd_dev.suspended = 0; - osal_queue_send(_usbd_q, event, in_isr); + send = true; } - break; + break; case DCD_EVENT_SOF: - // SOF driver handler in ISR context - for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) - { - usbd_class_driver_t const * driver = get_driver(i); - if (driver && driver->sof) - { - driver->sof(event->rhport, event->sof.frame_count); - } - } - // Some MCUs after running dcd_remote_wakeup() does not have way to detect the end of remote wakeup // which last 1-15 ms. DCD can use SOF as a clear indicator that bus is back to operational - if ( _usbd_dev.suspended ) - { + if (_usbd_dev.suspended) { _usbd_dev.suspended = 0; - dcd_event_t const event_resume = { .rhport = event->rhport, .event_id = DCD_EVENT_RESUME }; - osal_queue_send(_usbd_q, &event_resume, in_isr); + dcd_event_t const event_resume = {.rhport = event->rhport, .event_id = DCD_EVENT_RESUME}; + queue_event(&event_resume, in_isr); + } + + // SOF driver handler in ISR context + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) { + usbd_class_driver_t const* driver = get_driver(i); + if (driver && driver->sof) { + driver->sof(event->rhport, event->sof.frame_count); + } } // skip osal queue for SOF in usbd task - break; + break; + + case DCD_EVENT_SETUP_RECEIVED: + _usbd_dev.setup_count++; + send = true; + break; default: - osal_queue_send(_usbd_q, event, in_isr); - break; + send = true; + break; + } + + if (send) { + queue_event(event, in_isr); } } @@ -1174,26 +1176,22 @@ bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count } // Helper to defer an isr function -void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr) -{ - dcd_event_t event = - { +void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr) { + dcd_event_t event = { .rhport = 0, .event_id = USBD_EVENT_FUNC_CALL, }; - event.func_call.func = func; event.func_call.param = param; - dcd_event_handler(&event, in_isr); + queue_event(&event, in_isr); } //--------------------------------------------------------------------+ // USBD Endpoint API //--------------------------------------------------------------------+ -bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) -{ +bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { rhport = _usbd_rhport; TU_ASSERT(tu_edpt_number(desc_ep->bEndpointAddress) < CFG_TUD_ENDPPOINT_MAX); @@ -1202,59 +1200,59 @@ bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) return dcd_edpt_open(rhport, desc_ep); } -bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr) -{ +bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr) { (void) rhport; // TODO add this check later, also make sure we don't starve an out endpoint while suspending // TU_VERIFY(tud_ready()); - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir]; return tu_edpt_claim(ep_state, _usbd_mutex); } -bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr) -{ +bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr) { (void) rhport; - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir]; return tu_edpt_release(ep_state, _usbd_mutex); } -bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) -{ +bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { rhport = _usbd_rhport; uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); // TODO skip ready() check for now since enumeration also use this API // TU_VERIFY(tud_ready()); - TU_LOG(USBD_DBG, " Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes); + TU_LOG_USBD(" Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes); +#if CFG_TUD_LOG_LEVEL >= 3 + if(dir == TUSB_DIR_IN) { + TU_LOG_MEM(CFG_TUD_LOG_LEVEL, buffer, total_bytes, 2); + } +#endif // Attempt to transfer on a busy endpoint, sound like an race condition ! TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0); // Set busy first since the actual transfer can be complete before dcd_edpt_xfer() // could return and USBD task can preempt and clear the busy - _usbd_dev.ep_status[epnum][dir].busy = true; + _usbd_dev.ep_status[epnum][dir].busy = 1; - if ( dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes) ) - { + if (dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes)) { return true; - }else - { + } else { // DCD error, mark endpoint as ready to allow next transfer - _usbd_dev.ep_status[epnum][dir].busy = false; + _usbd_dev.ep_status[epnum][dir].busy = 0; _usbd_dev.ep_status[epnum][dir].claimed = 0; - TU_LOG(USBD_DBG, "FAILED\r\n"); + TU_LOG_USBD("FAILED\r\n"); TU_BREAKPOINT(); return false; } @@ -1264,117 +1262,100 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t // bytes should be written and second to keep the return value free to give back a boolean // success message. If total_bytes is too big, the FIFO will copy only what is available // into the USB buffer! -bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) -{ +bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t total_bytes) { rhport = _usbd_rhport; uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); - TU_LOG(USBD_DBG, " Queue ISO EP %02X with %u bytes ... ", ep_addr, total_bytes); + TU_LOG_USBD(" Queue ISO EP %02X with %u bytes ... ", ep_addr, total_bytes); // Attempt to transfer on a busy endpoint, sound like an race condition ! TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0); // Set busy first since the actual transfer can be complete before dcd_edpt_xfer() could return // and usbd task can preempt and clear the busy - _usbd_dev.ep_status[epnum][dir].busy = true; + _usbd_dev.ep_status[epnum][dir].busy = 1; - if (dcd_edpt_xfer_fifo(rhport, ep_addr, ff, total_bytes)) - { - TU_LOG(USBD_DBG, "OK\r\n"); + if (dcd_edpt_xfer_fifo(rhport, ep_addr, ff, total_bytes)) { + TU_LOG_USBD("OK\r\n"); return true; - }else - { + } else { // DCD error, mark endpoint as ready to allow next transfer - _usbd_dev.ep_status[epnum][dir].busy = false; + _usbd_dev.ep_status[epnum][dir].busy = 0; _usbd_dev.ep_status[epnum][dir].claimed = 0; - TU_LOG(USBD_DBG, "failed\r\n"); + TU_LOG_USBD("failed\r\n"); TU_BREAKPOINT(); return false; } } -bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr) -{ +bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr) { (void) rhport; uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); return _usbd_dev.ep_status[epnum][dir].busy; } -void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr) -{ +void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { rhport = _usbd_rhport; uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); // only stalled if currently cleared - if ( !_usbd_dev.ep_status[epnum][dir].stalled ) - { - TU_LOG(USBD_DBG, " Stall EP %02X\r\n", ep_addr); - dcd_edpt_stall(rhport, ep_addr); - _usbd_dev.ep_status[epnum][dir].stalled = true; - _usbd_dev.ep_status[epnum][dir].busy = true; - } + TU_LOG_USBD(" Stall EP %02X\r\n", ep_addr); + dcd_edpt_stall(rhport, ep_addr); + _usbd_dev.ep_status[epnum][dir].stalled = 1; + _usbd_dev.ep_status[epnum][dir].busy = 1; } -void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) -{ +void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { rhport = _usbd_rhport; uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); // only clear if currently stalled - if ( _usbd_dev.ep_status[epnum][dir].stalled ) - { - TU_LOG(USBD_DBG, " Clear Stall EP %02X\r\n", ep_addr); - dcd_edpt_clear_stall(rhport, ep_addr); - _usbd_dev.ep_status[epnum][dir].stalled = false; - _usbd_dev.ep_status[epnum][dir].busy = false; - } + TU_LOG_USBD(" Clear Stall EP %02X\r\n", ep_addr); + dcd_edpt_clear_stall(rhport, ep_addr); + _usbd_dev.ep_status[epnum][dir].stalled = 0; + _usbd_dev.ep_status[epnum][dir].busy = 0; } -bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr) -{ +bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr) { (void) rhport; uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); return _usbd_dev.ep_status[epnum][dir].stalled; } /** * usbd_edpt_close will disable an endpoint. - * * In progress transfers on this EP may be delivered after this call. - * */ -void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) -{ +void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) { rhport = _usbd_rhport; TU_ASSERT(dcd_edpt_close, /**/); - TU_LOG(USBD_DBG, " CLOSING Endpoint: 0x%02X\r\n", ep_addr); + TU_LOG_USBD(" CLOSING Endpoint: 0x%02X\r\n", ep_addr); uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); dcd_edpt_close(rhport, ep_addr); - _usbd_dev.ep_status[epnum][dir].stalled = false; - _usbd_dev.ep_status[epnum][dir].busy = false; - _usbd_dev.ep_status[epnum][dir].claimed = false; + _usbd_dev.ep_status[epnum][dir].stalled = 0; + _usbd_dev.ep_status[epnum][dir].busy = 0; + _usbd_dev.ep_status[epnum][dir].claimed = 0; return; } -void usbd_sof_enable(uint8_t rhport, bool en) -{ +void usbd_sof_enable(uint8_t rhport, bool en) { rhport = _usbd_rhport; // TODO: Check needed if all drivers including the user sof_cb does not need an active SOF ISR any more. @@ -1382,8 +1363,7 @@ void usbd_sof_enable(uint8_t rhport, bool en) dcd_sof_enable(rhport, en); } -bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) -{ +bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { rhport = _usbd_rhport; TU_ASSERT(dcd_edpt_iso_alloc); @@ -1392,20 +1372,19 @@ bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packe return dcd_edpt_iso_alloc(rhport, ep_addr, largest_packet_size); } -bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) -{ +bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { rhport = _usbd_rhport; uint8_t const epnum = tu_edpt_number(desc_ep->bEndpointAddress); - uint8_t const dir = tu_edpt_dir(desc_ep->bEndpointAddress); + uint8_t const dir = tu_edpt_dir(desc_ep->bEndpointAddress); TU_ASSERT(dcd_edpt_iso_activate); TU_ASSERT(epnum < CFG_TUD_ENDPPOINT_MAX); TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed)); - _usbd_dev.ep_status[epnum][dir].stalled = false; - _usbd_dev.ep_status[epnum][dir].busy = false; - _usbd_dev.ep_status[epnum][dir].claimed = false; + _usbd_dev.ep_status[epnum][dir].stalled = 0; + _usbd_dev.ep_status[epnum][dir].busy = 0; + _usbd_dev.ep_status[epnum][dir].claimed = 0; return dcd_edpt_iso_activate(rhport, desc_ep); } diff --git a/test-devices/composite-stm32/lib/tinyusb/device/usbd.h b/test-devices/composite-stm32/lib/tinyusb/device/usbd.h index 255e5a84..f3673404 100644 --- a/test-devices/composite-stm32/lib/tinyusb/device/usbd.h +++ b/test-devices/composite-stm32/lib/tinyusb/device/usbd.h @@ -37,9 +37,12 @@ extern "C" { // Application API //--------------------------------------------------------------------+ -// Init device stack +// Init device stack on roothub port bool tud_init (uint8_t rhport); +// Deinit device stack on roothub port +bool tud_deinit(uint8_t rhport); + // Check if device stack is already initialized bool tud_inited(void); @@ -50,8 +53,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr); // Task function should be called in main/rtos loop TU_ATTR_ALWAYS_INLINE static inline -void tud_task (void) -{ +void tud_task (void) { tud_task_ext(UINT32_MAX, false); } @@ -80,8 +82,7 @@ bool tud_suspended(void); // Check if device is ready to transfer TU_ATTR_ALWAYS_INLINE static inline -bool tud_ready(void) -{ +bool tud_ready(void) { return tud_mounted() && !tud_suspended(); } @@ -148,6 +149,9 @@ TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en); // Invoked when usb bus is resumed TU_ATTR_WEAK void tud_resume_cb(void); +// Invoked when there is a new usb event, which need to be processed by tud_task()/tud_task_ext() +void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr); + // Invoked when received control request with VENDOR TYPE TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); @@ -217,8 +221,8 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\ /* CDC Call */\ 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (uint8_t)((_itfnum) + 1),\ - /* CDC ACM: support line request */\ - 4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 2,\ + /* CDC ACM: support line request + send break */\ + 4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 6,\ /* CDC Union */\ 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\ /* Endpoint Notification */\ @@ -347,8 +351,8 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Standard Interface Association Descriptor (IAD) */ #define TUD_AUDIO_DESC_IAD_LEN 8 -#define TUD_AUDIO_DESC_IAD(_firstitfs, _nitfs, _stridx) \ - TUD_AUDIO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, _firstitfs, _nitfs, TUSB_CLASS_AUDIO, AUDIO_FUNCTION_SUBCLASS_UNDEFINED, AUDIO_FUNC_PROTOCOL_CODE_V2, _stridx +#define TUD_AUDIO_DESC_IAD(_firstitf, _nitfs, _stridx) \ + TUD_AUDIO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, _firstitf, _nitfs, TUSB_CLASS_AUDIO, AUDIO_FUNCTION_SUBCLASS_UNDEFINED, AUDIO_FUNC_PROTOCOL_CODE_V2, _stridx /* Standard AC Interface Descriptor(4.7.1) */ #define TUD_AUDIO_DESC_STD_AC_LEN 9 @@ -392,6 +396,11 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb // For more channels, add definitions here +/* Standard AC Interrupt Endpoint Descriptor(4.8.2.1) */ +#define TUD_AUDIO_DESC_STD_AC_INT_EP_LEN 7 +#define TUD_AUDIO_DESC_STD_AC_INT_EP(_ep, _interval) \ + TUD_AUDIO_DESC_STD_AC_INT_EP_LEN, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(6), _interval + /* Standard AS Interface Descriptor(4.9.1) */ #define TUD_AUDIO_DESC_STD_AS_INT_LEN 9 #define TUD_AUDIO_DESC_STD_AS_INT(_itfnum, _altset, _nEPs, _stridx) \ @@ -420,7 +429,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */ #define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN 7 #define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_ep, _interval) \ - TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_NO_SYNC | TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_NO_SYNC | (uint8_t)TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval // AUDIO simple descriptor (UAC2) for 1 microphone input // - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source @@ -443,7 +452,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb #define TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ /* Standard Interface Association Descriptor (IAD) */\ - TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ @@ -467,7 +476,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) @@ -492,7 +501,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb #define TUD_AUDIO_MIC_FOUR_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ /* Standard Interface Association Descriptor (IAD) */\ - TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ @@ -516,7 +525,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) @@ -540,7 +549,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb #define TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize, _epfb) \ /* Standard Interface Association Descriptor (IAD) */\ - TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ @@ -564,7 +573,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\ /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\ @@ -773,10 +782,6 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb #define TUD_BT_PROTOCOL_PRIMARY_CONTROLLER 0x01 #define TUD_BT_PROTOCOL_AMP_CONTROLLER 0x02 -#ifndef CFG_TUD_BTH_ISO_ALT_COUNT -#define CFG_TUD_BTH_ISO_ALT_COUNT 0 -#endif - // Length of template descriptor: 38 bytes + number of ISO alternatives * 23 #define TUD_BTH_DESC_LEN (8 + 9 + 7 + 7 + 7 + (CFG_TUD_BTH_ISO_ALT_COUNT) * (9 + 7 + 7)) diff --git a/test-devices/composite-stm32/lib/tinyusb/device/usbd_control.c b/test-devices/composite-stm32/lib/tinyusb/device/usbd_control.c index ea8eef28..35cce1f7 100644 --- a/test-devices/composite-stm32/lib/tinyusb/device/usbd_control.c +++ b/test-devices/composite-stm32/lib/tinyusb/device/usbd_control.c @@ -32,30 +32,38 @@ #include "tusb.h" #include "device/usbd_pvt.h" -#if CFG_TUSB_DEBUG >= 2 +//--------------------------------------------------------------------+ +// Callback weak stubs (called if application does not provide) +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) { + (void) rhport; + (void) request; +} + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL extern void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback); #endif -enum -{ +enum { EDPT_CTRL_OUT = 0x00, - EDPT_CTRL_IN = 0x80 + EDPT_CTRL_IN = 0x80 }; -typedef struct -{ +typedef struct { tusb_control_request_t request; - uint8_t* buffer; uint16_t data_len; uint16_t total_xferred; - usbd_control_xfer_cb_t complete_cb; } usbd_control_xfer_t; tu_static usbd_control_xfer_t _ctrl_xfer; -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN +CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t _usbd_ctrl_buf[CFG_TUD_ENDPOINT0_SIZE]; //--------------------------------------------------------------------+ @@ -63,20 +71,18 @@ tu_static uint8_t _usbd_ctrl_buf[CFG_TUD_ENDPOINT0_SIZE]; //--------------------------------------------------------------------+ // Queue ZLP status transaction -static inline bool _status_stage_xact(uint8_t rhport, tusb_control_request_t const * request) -{ +static inline bool _status_stage_xact(uint8_t rhport, tusb_control_request_t const* request) { // Opposite to endpoint in Data Phase uint8_t const ep_addr = request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN; return usbd_edpt_xfer(rhport, ep_addr, NULL, 0); } // Status phase -bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request) -{ - _ctrl_xfer.request = (*request); - _ctrl_xfer.buffer = NULL; +bool tud_control_status(uint8_t rhport, tusb_control_request_t const* request) { + _ctrl_xfer.request = (*request); + _ctrl_xfer.buffer = NULL; _ctrl_xfer.total_xferred = 0; - _ctrl_xfer.data_len = 0; + _ctrl_xfer.data_len = 0; return _status_stage_xact(rhport, request); } @@ -84,16 +90,15 @@ bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request) // Queue a transaction in Data Stage // Each transaction has up to Endpoint0's max packet size. // This function can also transfer an zero-length packet -static bool _data_stage_xact(uint8_t rhport) -{ - uint16_t const xact_len = tu_min16(_ctrl_xfer.data_len - _ctrl_xfer.total_xferred, CFG_TUD_ENDPOINT0_SIZE); +static bool _data_stage_xact(uint8_t rhport) { + uint16_t const xact_len = tu_min16(_ctrl_xfer.data_len - _ctrl_xfer.total_xferred, + CFG_TUD_ENDPOINT0_SIZE); uint8_t ep_addr = EDPT_CTRL_OUT; - if ( _ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN ) - { + if (_ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN) { ep_addr = EDPT_CTRL_IN; - if ( xact_len ) { + if (xact_len) { TU_VERIFY(0 == tu_memcpy_s(_usbd_ctrl_buf, CFG_TUD_ENDPOINT0_SIZE, _ctrl_xfer.buffer, xact_len)); } } @@ -103,29 +108,24 @@ static bool _data_stage_xact(uint8_t rhport) // Transmit data to/from the control endpoint. // If the request's wLength is zero, a status packet is sent instead. -bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len) -{ - _ctrl_xfer.request = (*request); - _ctrl_xfer.buffer = (uint8_t*) buffer; +bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const* request, void* buffer, uint16_t len) { + _ctrl_xfer.request = (*request); + _ctrl_xfer.buffer = (uint8_t*) buffer; _ctrl_xfer.total_xferred = 0U; - _ctrl_xfer.data_len = tu_min16(len, request->wLength); + _ctrl_xfer.data_len = tu_min16(len, request->wLength); - if (request->wLength > 0U) - { - if(_ctrl_xfer.data_len > 0U) - { + if (request->wLength > 0U) { + if (_ctrl_xfer.data_len > 0U) { TU_ASSERT(buffer); } // TU_LOG2(" Control total data length is %u bytes\r\n", _ctrl_xfer.data_len); // Data stage - TU_ASSERT( _data_stage_xact(rhport) ); - } - else - { + TU_ASSERT(_data_stage_xact(rhport)); + } else { // Status stage - TU_ASSERT( _status_stage_xact(rhport, request) ); + TU_ASSERT(_status_stage_xact(rhport, request)); } return true; @@ -134,49 +134,42 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, vo //--------------------------------------------------------------------+ // USBD API //--------------------------------------------------------------------+ - void usbd_control_reset(void); -void usbd_control_set_request(tusb_control_request_t const *request); -void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp ); -bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); +void usbd_control_set_request(tusb_control_request_t const* request); +void usbd_control_set_complete_callback(usbd_control_xfer_cb_t fp); +bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); -void usbd_control_reset(void) -{ +void usbd_control_reset(void) { tu_varclr(&_ctrl_xfer); } // Set complete callback -void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp ) -{ +void usbd_control_set_complete_callback(usbd_control_xfer_cb_t fp) { _ctrl_xfer.complete_cb = fp; } // for dcd_set_address where DCD is responsible for status response -void usbd_control_set_request(tusb_control_request_t const *request) -{ - _ctrl_xfer.request = (*request); - _ctrl_xfer.buffer = NULL; +void usbd_control_set_request(tusb_control_request_t const* request) { + _ctrl_xfer.request = (*request); + _ctrl_xfer.buffer = NULL; _ctrl_xfer.total_xferred = 0; - _ctrl_xfer.data_len = 0; + _ctrl_xfer.data_len = 0; } // callback when a transaction complete on // - DATA stage of control endpoint or // - Status stage -bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ +bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { (void) result; // Endpoint Address is opposite to direction bit, this is Status Stage complete event - if ( tu_edpt_dir(ep_addr) != _ctrl_xfer.request.bmRequestType_bit.direction ) - { + if (tu_edpt_dir(ep_addr) != _ctrl_xfer.request.bmRequestType_bit.direction) { TU_ASSERT(0 == xferred_bytes); // invoke optional dcd hook if available - if (dcd_edpt0_status_complete) dcd_edpt0_status_complete(rhport, &_ctrl_xfer.request); + dcd_edpt0_status_complete(rhport, &_ctrl_xfer.request); - if (_ctrl_xfer.complete_cb) - { + if (_ctrl_xfer.complete_cb) { // TODO refactor with usbd_driver_print_control_complete_name _ctrl_xfer.complete_cb(rhport, CONTROL_STAGE_ACK, &_ctrl_xfer.request); } @@ -184,11 +177,10 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result return true; } - if ( _ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_OUT ) - { + if (_ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_OUT) { TU_VERIFY(_ctrl_xfer.buffer); memcpy(_ctrl_xfer.buffer, _usbd_ctrl_buf, xferred_bytes); - TU_LOG_MEM(2, _usbd_ctrl_buf, xferred_bytes, 2); + TU_LOG_MEM(CFG_TUD_LOG_LEVEL, _usbd_ctrl_buf, xferred_bytes, 2); } _ctrl_xfer.total_xferred += (uint16_t) xferred_bytes; @@ -196,37 +188,32 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result // Data Stage is complete when all request's length are transferred or // a short packet is sent including zero-length packet. - if ( (_ctrl_xfer.request.wLength == _ctrl_xfer.total_xferred) || (xferred_bytes < CFG_TUD_ENDPOINT0_SIZE) ) - { + if ((_ctrl_xfer.request.wLength == _ctrl_xfer.total_xferred) || + (xferred_bytes < CFG_TUD_ENDPOINT0_SIZE)) { // DATA stage is complete bool is_ok = true; // invoke complete callback if set // callback can still stall control in status phase e.g out data does not make sense - if ( _ctrl_xfer.complete_cb ) - { - #if CFG_TUSB_DEBUG >= 2 + if (_ctrl_xfer.complete_cb) { + #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL usbd_driver_print_control_complete_name(_ctrl_xfer.complete_cb); #endif is_ok = _ctrl_xfer.complete_cb(rhport, CONTROL_STAGE_DATA, &_ctrl_xfer.request); } - if ( is_ok ) - { + if (is_ok) { // Send status - TU_ASSERT( _status_stage_xact(rhport, &_ctrl_xfer.request) ); - }else - { + TU_ASSERT(_status_stage_xact(rhport, &_ctrl_xfer.request)); + } else { // Stall both IN and OUT control endpoint dcd_edpt_stall(rhport, EDPT_CTRL_OUT); dcd_edpt_stall(rhport, EDPT_CTRL_IN); } - } - else - { + } else { // More data to transfer - TU_ASSERT( _data_stage_xact(rhport) ); + TU_ASSERT(_data_stage_xact(rhport)); } return true; diff --git a/test-devices/composite-stm32/lib/tinyusb/device/usbd_pvt.h b/test-devices/composite-stm32/lib/tinyusb/device/usbd_pvt.h index 8393d346..47752f32 100644 --- a/test-devices/composite-stm32/lib/tinyusb/device/usbd_pvt.h +++ b/test-devices/composite-stm32/lib/tinyusb/device/usbd_pvt.h @@ -23,8 +23,8 @@ * * This file is part of the TinyUSB stack. */ -#ifndef USBD_PVT_H_ -#define USBD_PVT_H_ +#ifndef _TUSB_USBD_PVT_H_ +#define _TUSB_USBD_PVT_H_ #include "osal/osal.h" #include "common/tusb_fifo.h" @@ -33,17 +33,19 @@ extern "C" { #endif +#define TU_LOG_USBD(...) TU_LOG(CFG_TUD_LOG_LEVEL, __VA_ARGS__) + //--------------------------------------------------------------------+ // Class Driver API //--------------------------------------------------------------------+ -typedef struct -{ - #if CFG_TUSB_DEBUG >= 2 +typedef struct { + #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL char const* name; #endif void (* init ) (void); + bool (* deinit ) (void); void (* reset ) (uint8_t rhport); uint16_t (* open ) (uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t max_len); bool (* control_xfer_cb ) (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); @@ -52,7 +54,7 @@ typedef struct } usbd_class_driver_t; // Invoked when initializing device stack to get additional class drivers. -// Can optionally implemented by application to extend/overwrite class driver support. +// Can be implemented by application to extend/overwrite class driver support. // Note: The drivers array must be accessible at all time when stack is active usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) TU_ATTR_WEAK; @@ -104,8 +106,7 @@ bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endp // Check if endpoint is ready (not busy and not stalled) TU_ATTR_ALWAYS_INLINE static inline -bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr) -{ +bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr) { return !usbd_edpt_busy(rhport, ep_addr) && !usbd_edpt_stalled(rhport, ep_addr); } @@ -117,11 +118,10 @@ void usbd_sof_enable(uint8_t rhport, bool en); *------------------------------------------------------------------*/ bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in); -void usbd_defer_func( osal_task_func_t func, void* param, bool in_isr ); - +void usbd_defer_func(osal_task_func_t func, void *param, bool in_isr); #ifdef __cplusplus } #endif -#endif /* USBD_PVT_H_ */ +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/hwcfg_list.md b/test-devices/composite-stm32/lib/tinyusb/dwc2/hwcfg_list.md deleted file mode 100644 index b5590da0..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/dwc2/hwcfg_list.md +++ /dev/null @@ -1,777 +0,0 @@ -# DWC2 Hardware Configuration Registers - -## Broadcom BCM2711 (Pi4) - -dwc2->guid = 2708A000 -dwc2->gsnpsid = 4F54280A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 228DDD50 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 2 -hw_cfg2->point2point = 0 -hw_cfg2->hs_phy_type = 1 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 7 -hw_cfg2->num_host_ch = 7 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 0 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = FF000E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 0 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 0 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 0 -hw_cfg3->lpm_mode = 0 -hw_cfg3->total_fifo_size = 4080 - -dwc2->ghwcfg4 = 1FF00020 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 0 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 0 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 15 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## EFM32GG FS - -dwc2->guid = 0 -dwc2->gsnpsid = 4F54330A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 228F5910 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 2 -hw_cfg2->point2point = 0 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 6 -hw_cfg2->num_host_ch = 13 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 0 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 1F204E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 0 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 1 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 0 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 0 -hw_cfg3->lpm_mode = 0 -hw_cfg3->total_fifo_size = 498 - -dwc2->ghwcfg4 = 1BF08030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 2 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 13 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## ESP32-S2 Fullspeed - -dwc2->guid = 0 -dwc2->gsnpsid = 4F54400A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 224DD930 -hw_cfg2->op_mode = 2 -hw_cfg2->arch = 3 -hw_cfg2->point2point = 0 -hw_cfg2->hs_phy_type = 1 -hw_cfg2->fs_phy_type = 2 -hw_cfg2->num_dev_ep = 6 -hw_cfg2->num_host_ch = 9 -hw_cfg2->period_channel_support = 0 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 1 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 22 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = C804B5 -hw_cfg3->xfer_size_width = 10 -hw_cfg3->packet_size_width = 5 -hw_cfg3->otg_enable = 0 -hw_cfg3->i2c_enable = 0 -hw_cfg3->vendor_ctrl_itf = 1 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 1 -hw_cfg3->otg_adp_support = 1 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 1 -hw_cfg3->lpm_mode = 0 -hw_cfg3->total_fifo_size = 23130 - -dwc2->ghwcfg4 = D3F0A030 -hw_cfg4->num_dev_period_in_ep = 10 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 0 -hw_cfg4->hibernation = 1 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 1 -hw_cfg4->acg_enable = 1 -hw_cfg4->utmi_phy_data_width = 1 -hw_cfg4->dev_ctrl_ep_num = 10 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 0 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 0 -hw_cfg4->dedicated_fifos = 0 -hw_cfg4->num_dev_in_eps = 13 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 1 - -## STM32F407 and STM32F207 - -STM32F407 and STM32F207 are exactly the same - -### STM32F407 Fullspeed - -dwc2->guid = 1200 -dwc2->gsnpsid = 4F54281A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229DCD20 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 0 -hw_cfg2->point2point = 1 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 3 -hw_cfg2->num_host_ch = 7 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 20001E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 1 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 0 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 0 -hw_cfg3->lpm_mode = 0 -hw_cfg3->total_fifo_size = 512 - -dwc2->ghwcfg4 = FF08030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 2 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 7 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -### STM32F407 Highspeed - -dwc2->guid = 1100 -dwc2->gsnpsid = 4F54281A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229ED590 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 2 -hw_cfg2->point2point = 0 -hw_cfg2->hs_phy_type = 2 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 5 -hw_cfg2->num_host_ch = 11 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 3F403E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 1 -hw_cfg3->vendor_ctrl_itf = 1 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 0 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 0 -hw_cfg3->lpm_mode = 0 -hw_cfg3->total_fifo_size = 1012 - -dwc2->ghwcfg4 = 17F00030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 0 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 11 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## STM32F411 Fullspeed - -dwc2->guid = 1200 -dwc2->gsnpsid = 4F54281A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229DCD20 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 0 -hw_cfg2->point2point = 1 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 3 -hw_cfg2->num_host_ch = 7 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 20001E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 1 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 0 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 0 -hw_cfg3->lpm_mode = 0 -hw_cfg3->total_fifo_size = 512 - -dwc2->ghwcfg4 = FF08030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 2 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 7 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## STM32F412 FS - -dwc2->guid = 2000 -dwc2->gsnpsid = 4F54320A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229ED520 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 0 -hw_cfg2->point2point = 1 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 5 -hw_cfg2->num_host_ch = 11 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 200D1E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 1 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 1 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 1 -hw_cfg3->lpm_mode = 1 -hw_cfg3->total_fifo_size = 512 - -dwc2->ghwcfg4 = 17F08030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 2 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 11 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## STM32F723 - -### STM32F723 HighSpeed - -dwc2->guid = 3100 -dwc2->gsnpsid = 4F54330A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229FE1D0 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 2 -hw_cfg2->point2point = 0 -hw_cfg2->hs_phy_type = 3 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 8 -hw_cfg2->num_host_ch = 15 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 3EED2E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 0 -hw_cfg3->vendor_ctrl_itf = 1 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 1 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 1 -hw_cfg3->lpm_mode = 1 -hw_cfg3->total_fifo_size = 1006 - -dwc2->ghwcfg4 = 23F00030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 0 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 1 -hw_cfg4->dma_desc_enable = 1 -hw_cfg4->dma_dynamic = 0 - -### STM32F723 Fullspeed - -dwc2->guid = 3000 -dwc2->gsnpsid = 4F54330A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229ED520 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 0 -hw_cfg2->point2point = 1 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 5 -hw_cfg2->num_host_ch = 11 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 200D1E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 1 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 1 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 1 -hw_cfg3->lpm_mode = 1 -hw_cfg3->total_fifo_size = 512 - -dwc2->ghwcfg4 = 17F08030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 2 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 11 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## STM32F767 FS - -dwc2->guid = 2000 -dwc2->gsnpsid = 4F54320A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229ED520 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 0 -hw_cfg2->point2point = 1 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 5 -hw_cfg2->num_host_ch = 11 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 200D1E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 1 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 1 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 1 -hw_cfg3->lpm_mode = 1 -hw_cfg3->total_fifo_size = 512 - -dwc2->ghwcfg4 = 17F08030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 2 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 11 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## STM32H743 (both cores HS) - -dwc2->guid = 2300 -dwc2->gsnpsid = 4F54330A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229FE190 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 2 -hw_cfg2->point2point = 0 -hw_cfg2->hs_phy_type = 2 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 8 -hw_cfg2->num_host_ch = 15 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 3B8D2E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 0 -hw_cfg3->vendor_ctrl_itf = 1 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 1 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 1 -hw_cfg3->lpm_mode = 1 -hw_cfg3->total_fifo_size = 952 - -dwc2->ghwcfg4 = E3F00030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 0 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 1 -hw_cfg4->dma_desc_enable = 1 -hw_cfg4->dma_dynamic = 1 - -## STM32L476 FS - -dwc2->guid = 2000 -dwc2->gsnpsid = 4F54310A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229ED520 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 0 -hw_cfg2->point2point = 1 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 5 -hw_cfg2->num_host_ch = 11 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 200D1E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 1 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 1 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 1 -hw_cfg3->lpm_mode = 1 -hw_cfg3->total_fifo_size = 512 - -dwc2->ghwcfg4 = 17F08030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 2 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 11 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## GD32VF103 Fullspeed - -dwc2->guid = 1000 -dwc2->gsnpsid = 0 -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 0 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 0 -hw_cfg2->point2point = 0 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 0 -hw_cfg2->num_dev_ep = 0 -hw_cfg2->num_host_ch = 0 -hw_cfg2->period_channel_support = 0 -hw_cfg2->enable_dynamic_fifo = 0 -hw_cfg2->mul_cpu_int = 0 -hw_cfg2->nperiod_tx_q_depth = 0 -hw_cfg2->host_period_tx_q_depth = 0 -hw_cfg2->dev_token_q_depth = 0 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 0 -hw_cfg3->xfer_size_width = 0 -hw_cfg3->packet_size_width = 0 -hw_cfg3->otg_enable = 0 -hw_cfg3->i2c_enable = 0 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 0 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 0 -hw_cfg3->lpm_mode = 0 -hw_cfg3->total_fifo_size = 0 - -dwc2->ghwcfg4 = 0 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 0 -hw_cfg4->ahb_freq_min = 0 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 0 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 0 -hw_cfg4->vbus_valid_filter_enabled = 0 -hw_cfg4->a_valid_filter_enabled = 0 -hw_cfg4->b_valid_filter_enabled = 0 -hw_cfg4->dedicated_fifos = 0 -hw_cfg4->num_dev_in_eps = 0 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## XMC4500 - -dwc2->guid = AEC000 -dwc2->gsnpsid = 4F54292A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 228F5930 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 2 -hw_cfg2->point2point = 1 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 6 -hw_cfg2->num_host_ch = 13 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 0 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 27A01E5 -hw_cfg3->xfer_size_width = 5 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 1 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 0 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 0 -hw_cfg3->lpm_mode = 0 -hw_cfg3->total_fifo_size = 634 - -dwc2->ghwcfg4 = DBF08030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 2 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 13 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 1 diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal.h index f092e8ff..8f45ea5c 100644 --- a/test-devices/composite-stm32/lib/tinyusb/osal/osal.h +++ b/test-devices/composite-stm32/lib/tinyusb/osal/osal.h @@ -74,15 +74,18 @@ typedef void (*osal_task_func_t)( void * ); // Should be implemented as static inline function in osal_port.h header /* osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef); + bool osal_semaphore_delete(osal_semaphore_t semd_hdl); bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr); bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec); void osal_semaphore_reset(osal_semaphore_t sem_hdl); // TODO removed osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef); + bool osal_mutex_delete(osal_mutex_t mutex_hdl) bool osal_mutex_lock (osal_mutex_t sem_hdl, uint32_t msec); bool osal_mutex_unlock(osal_mutex_t mutex_hdl); osal_queue_t osal_queue_create(osal_queue_def_t* qdef); + bool osal_queue_delete(osal_queue_t qhdl); bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec); bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr); bool osal_queue_empty(osal_queue_t qhdl); diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal_freertos.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal_freertos.h deleted file mode 100644 index 477f6489..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/osal/osal_freertos.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_OSAL_FREERTOS_H_ -#define _TUSB_OSAL_FREERTOS_H_ - -// FreeRTOS Headers -#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,FreeRTOS.h) -#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,semphr.h) -#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,queue.h) -#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,task.h) - -#ifdef __cplusplus -extern "C" { -#endif - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF PROTYPES -//--------------------------------------------------------------------+ - -#if configSUPPORT_STATIC_ALLOCATION - typedef StaticSemaphore_t osal_semaphore_def_t; - typedef StaticSemaphore_t osal_mutex_def_t; -#else - // not used therefore defined to smallest possible type to save space - typedef uint8_t osal_semaphore_def_t; - typedef uint8_t osal_mutex_def_t; -#endif - -typedef SemaphoreHandle_t osal_semaphore_t; -typedef SemaphoreHandle_t osal_mutex_t; - -// _int_set is not used with an RTOS -#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ - static _type _name##_##buf[_depth];\ - osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf }; - -typedef struct -{ - uint16_t depth; - uint16_t item_sz; - void* buf; -#if configSUPPORT_STATIC_ALLOCATION - StaticQueue_t sq; -#endif -}osal_queue_def_t; - -typedef QueueHandle_t osal_queue_t; - -//--------------------------------------------------------------------+ -// TASK API -//--------------------------------------------------------------------+ - -TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec) -{ - if (msec == OSAL_TIMEOUT_WAIT_FOREVER) return portMAX_DELAY; - if (msec == 0) return 0; - - uint32_t ticks = pdMS_TO_TICKS(msec); - - // configTICK_RATE_HZ is less than 1000 and 1 tick > 1 ms - // we still need to delay at least 1 tick - if (ticks == 0) ticks =1 ; - - return ticks; -} - -TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) -{ - vTaskDelay( pdMS_TO_TICKS(msec) ); -} - -//--------------------------------------------------------------------+ -// Semaphore API -//--------------------------------------------------------------------+ - -TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) -{ -#if configSUPPORT_STATIC_ALLOCATION - return xSemaphoreCreateBinaryStatic(semdef); -#else - (void) semdef; - return xSemaphoreCreateBinary(); -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) -{ - if ( !in_isr ) - { - return xSemaphoreGive(sem_hdl) != 0; - } - else - { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - BaseType_t res = xSemaphoreGiveFromISR(sem_hdl, &xHigherPriorityTaskWoken); - -#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3 - // not needed after https://github.com/espressif/esp-idf/commit/c5fd79547ac9b7bae06fa660e9f814d18d3390b7 - if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR(); -#else - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); -#endif - - return res != 0; - } -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) -{ - return xSemaphoreTake(sem_hdl, _osal_ms2tick(msec)); -} - -TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) -{ - xQueueReset(sem_hdl); -} - -//--------------------------------------------------------------------+ -// MUTEX API (priority inheritance) -//--------------------------------------------------------------------+ - -TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) -{ -#if configSUPPORT_STATIC_ALLOCATION - return xSemaphoreCreateMutexStatic(mdef); -#else - (void) mdef; - return xSemaphoreCreateMutex(); -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) -{ - return osal_semaphore_wait(mutex_hdl, msec); -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) -{ - return xSemaphoreGive(mutex_hdl); -} - -//--------------------------------------------------------------------+ -// QUEUE API -//--------------------------------------------------------------------+ - -TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) -{ -#if configSUPPORT_STATIC_ALLOCATION - return xQueueCreateStatic(qdef->depth, qdef->item_sz, (uint8_t*) qdef->buf, &qdef->sq); -#else - return xQueueCreate(qdef->depth, qdef->item_sz); -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) -{ - return xQueueReceive(qhdl, data, _osal_ms2tick(msec)); -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) -{ - if ( !in_isr ) - { - return xQueueSendToBack(qhdl, data, OSAL_TIMEOUT_WAIT_FOREVER) != 0; - } - else - { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - BaseType_t res = xQueueSendToBackFromISR(qhdl, data, &xHigherPriorityTaskWoken); - -#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3 - // not needed after https://github.com/espressif/esp-idf/commit/c5fd79547ac9b7bae06fa660e9f814d18d3390b7 - if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR(); -#else - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); -#endif - - return res != 0; - } -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) -{ - return uxQueueMessagesWaiting(qhdl) == 0; -} - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal_mynewt.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal_mynewt.h deleted file mode 100644 index b8ea2087..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/osal/osal_mynewt.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef OSAL_MYNEWT_H_ -#define OSAL_MYNEWT_H_ - -#include "os/os.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// TASK API -//--------------------------------------------------------------------+ -TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) -{ - os_time_delay( os_time_ms_to_ticks32(msec) ); -} - -//--------------------------------------------------------------------+ -// Semaphore API -//--------------------------------------------------------------------+ -typedef struct os_sem osal_semaphore_def_t; -typedef struct os_sem* osal_semaphore_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) -{ - return (os_sem_init(semdef, 0) == OS_OK) ? (osal_semaphore_t) semdef : NULL; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) -{ - (void) in_isr; - return os_sem_release(sem_hdl) == OS_OK; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) -{ - uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? OS_TIMEOUT_NEVER : os_time_ms_to_ticks32(msec); - return os_sem_pend(sem_hdl, ticks) == OS_OK; -} - -static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) -{ - // TODO implement later -} - -//--------------------------------------------------------------------+ -// MUTEX API (priority inheritance) -//--------------------------------------------------------------------+ -typedef struct os_mutex osal_mutex_def_t; -typedef struct os_mutex* osal_mutex_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) -{ - return (os_mutex_init(mdef) == OS_OK) ? (osal_mutex_t) mdef : NULL; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) -{ - uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? OS_TIMEOUT_NEVER : os_time_ms_to_ticks32(msec); - return os_mutex_pend(mutex_hdl, ticks) == OS_OK; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) -{ - return os_mutex_release(mutex_hdl) == OS_OK; -} - -//--------------------------------------------------------------------+ -// QUEUE API -//--------------------------------------------------------------------+ - -// role device/host is used by OS NONE for mutex (disable usb isr) only -#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ - static _type _name##_##buf[_depth];\ - static struct os_event _name##_##evbuf[_depth];\ - osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf, .evbuf = _name##_##evbuf};\ - -typedef struct -{ - uint16_t depth; - uint16_t item_sz; - void* buf; - void* evbuf; - - struct os_mempool mpool; - struct os_mempool epool; - - struct os_eventq evq; -}osal_queue_def_t; - -typedef osal_queue_def_t* osal_queue_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) -{ - if ( OS_OK != os_mempool_init(&qdef->mpool, qdef->depth, qdef->item_sz, qdef->buf, "usbd queue") ) return NULL; - if ( OS_OK != os_mempool_init(&qdef->epool, qdef->depth, sizeof(struct os_event), qdef->evbuf, "usbd evqueue") ) return NULL; - - os_eventq_init(&qdef->evq); - return (osal_queue_t) qdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) -{ - (void) msec; // os_eventq_get() does not take timeout, always behave as msec = WAIT_FOREVER - - struct os_event* ev; - ev = os_eventq_get(&qhdl->evq); - - memcpy(data, ev->ev_arg, qhdl->item_sz); // copy message - os_memblock_put(&qhdl->mpool, ev->ev_arg); // put back mem block - os_memblock_put(&qhdl->epool, ev); // put back ev block - - return true; -} - -static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) -{ - (void) in_isr; - - // get a block from mem pool for data - void* ptr = os_memblock_get(&qhdl->mpool); - if (!ptr) return false; - memcpy(ptr, data, qhdl->item_sz); - - // get a block from event pool to put into queue - struct os_event* ev = (struct os_event*) os_memblock_get(&qhdl->epool); - if (!ev) - { - os_memblock_put(&qhdl->mpool, ptr); - return false; - } - tu_memclr(ev, sizeof(struct os_event)); - ev->ev_arg = ptr; - - os_eventq_put(&qhdl->evq, ev); - - return true; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) -{ - return STAILQ_EMPTY(&qhdl->evq.evq_list); -} - - -#ifdef __cplusplus - } -#endif - -#endif /* OSAL_MYNEWT_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal_none.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal_none.h index 5f407378..c93f7a86 100644 --- a/test-devices/composite-stm32/lib/tinyusb/osal/osal_none.h +++ b/test-devices/composite-stm32/lib/tinyusb/osal/osal_none.h @@ -24,11 +24,11 @@ * This file is part of the TinyUSB stack. */ -#ifndef _TUSB_OSAL_NONE_H_ -#define _TUSB_OSAL_NONE_H_ +#ifndef TUSB_OSAL_NONE_H_ +#define TUSB_OSAL_NONE_H_ #ifdef __cplusplus - extern "C" { +extern "C" { #endif //--------------------------------------------------------------------+ @@ -37,45 +37,46 @@ #if CFG_TUH_ENABLED // currently only needed/available in host mode -void osal_task_delay(uint32_t msec); +TU_ATTR_WEAK void osal_task_delay(uint32_t msec); #endif //--------------------------------------------------------------------+ // Binary Semaphore API //--------------------------------------------------------------------+ -typedef struct -{ +typedef struct { volatile uint16_t count; -}osal_semaphore_def_t; +} osal_semaphore_def_t; typedef osal_semaphore_def_t* osal_semaphore_t; -TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) -{ +TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) { semdef->count = 0; return semdef; } -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) -{ +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t semd_hdl) { + (void) semd_hdl; + return true; // nothing to do +} + + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) { (void) in_isr; sem_hdl->count++; return true; } // TODO blocking for now -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) -{ +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) { (void) msec; - while (sem_hdl->count == 0) { } + while (sem_hdl->count == 0) {} sem_hdl->count--; return true; } -TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) -{ +TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) { sem_hdl->count = 0; } @@ -90,19 +91,21 @@ typedef osal_semaphore_t osal_mutex_t; // Note: multiple cores MCUs usually do provide IPC API for mutex // or we can use std atomic function -TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) -{ +TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) { mdef->count = 1; return mdef; } -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) -{ +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl) { + (void) mutex_hdl; + return true; // nothing to do +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) { return osal_semaphore_wait(mutex_hdl, msec); } -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) -{ +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) { return osal_semaphore_post(mutex_hdl, false); } @@ -119,11 +122,10 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd //--------------------------------------------------------------------+ #include "common/tusb_fifo.h" -typedef struct -{ - void (*interrupt_set)(bool); +typedef struct { + void (* interrupt_set)(bool); tu_fifo_t ff; -}osal_queue_def_t; +} osal_queue_def_t; typedef osal_queue_def_t* osal_queue_t; @@ -136,27 +138,28 @@ typedef osal_queue_def_t* osal_queue_t; } // lock queue by disable USB interrupt -TU_ATTR_ALWAYS_INLINE static inline void _osal_q_lock(osal_queue_t qhdl) -{ +TU_ATTR_ALWAYS_INLINE static inline void _osal_q_lock(osal_queue_t qhdl) { // disable dcd/hcd interrupt qhdl->interrupt_set(false); } // unlock queue -TU_ATTR_ALWAYS_INLINE static inline void _osal_q_unlock(osal_queue_t qhdl) -{ +TU_ATTR_ALWAYS_INLINE static inline void _osal_q_unlock(osal_queue_t qhdl) { // enable dcd/hcd interrupt qhdl->interrupt_set(true); } -TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) -{ +TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) { tu_fifo_clear(&qdef->ff); return (osal_queue_t) qdef; } -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) -{ +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) { + (void) qhdl; + return true; // nothing to do +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) { (void) msec; // not used, always behave as msec = 0 _osal_q_lock(qhdl); @@ -166,8 +169,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, v return success; } -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) -{ +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const* data, bool in_isr) { if (!in_isr) { _osal_q_lock(qhdl); } @@ -178,20 +180,17 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void _osal_q_unlock(qhdl); } - TU_ASSERT(success); - return success; } -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) -{ +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) { // Skip queue lock/unlock since this function is primarily called // with interrupt disabled before going into low power mode return tu_fifo_empty(&qhdl->ff); } #ifdef __cplusplus - } +} #endif -#endif /* _TUSB_OSAL_NONE_H_ */ +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal_pico.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal_pico.h deleted file mode 100644 index e6efa096..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/osal/osal_pico.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_OSAL_PICO_H_ -#define _TUSB_OSAL_PICO_H_ - -#include "pico/time.h" -#include "pico/sem.h" -#include "pico/mutex.h" -#include "pico/critical_section.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// TASK API -//--------------------------------------------------------------------+ -TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) -{ - sleep_ms(msec); -} - -//--------------------------------------------------------------------+ -// Binary Semaphore API -//--------------------------------------------------------------------+ -typedef struct semaphore osal_semaphore_def_t, *osal_semaphore_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) -{ - sem_init(semdef, 0, 255); - return semdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) -{ - (void) in_isr; - sem_release(sem_hdl); - return true; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) -{ - return sem_acquire_timeout_ms(sem_hdl, msec); -} - -TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) -{ - sem_reset(sem_hdl, 0); -} - -//--------------------------------------------------------------------+ -// MUTEX API -// Within tinyusb, mutex is never used in ISR context -//--------------------------------------------------------------------+ -typedef struct mutex osal_mutex_def_t, *osal_mutex_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) -{ - mutex_init(mdef); - return mdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) -{ - return mutex_enter_timeout_ms(mutex_hdl, msec); -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) -{ - mutex_exit(mutex_hdl); - return true; -} - -//--------------------------------------------------------------------+ -// QUEUE API -//--------------------------------------------------------------------+ -#include "common/tusb_fifo.h" - -typedef struct -{ - tu_fifo_t ff; - struct critical_section critsec; // osal_queue may be used in IRQs, so need critical section -} osal_queue_def_t; - -typedef osal_queue_def_t* osal_queue_t; - -// role device/host is used by OS NONE for mutex (disable usb isr) only -#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ - uint8_t _name##_buf[_depth*sizeof(_type)]; \ - osal_queue_def_t _name = { \ - .ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \ - } - -// lock queue by disable USB interrupt -TU_ATTR_ALWAYS_INLINE static inline void _osal_q_lock(osal_queue_t qhdl) -{ - critical_section_enter_blocking(&qhdl->critsec); -} - -// unlock queue -TU_ATTR_ALWAYS_INLINE static inline void _osal_q_unlock(osal_queue_t qhdl) -{ - critical_section_exit(&qhdl->critsec); -} - -TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) -{ - critical_section_init(&qdef->critsec); - tu_fifo_clear(&qdef->ff); - return (osal_queue_t) qdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) -{ - (void) msec; // not used, always behave as msec = 0 - - // TODO: revisit... docs say that mutexes are never used from IRQ context, - // however osal_queue_recieve may be. therefore my assumption is that - // the fifo mutex is not populated for queues used from an IRQ context - //assert(!qhdl->ff.mutex); - - _osal_q_lock(qhdl); - bool success = tu_fifo_read(&qhdl->ff, data); - _osal_q_unlock(qhdl); - - return success; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) -{ - // TODO: revisit... docs say that mutexes are never used from IRQ context, - // however osal_queue_recieve may be. therefore my assumption is that - // the fifo mutex is not populated for queues used from an IRQ context - //assert(!qhdl->ff.mutex); - (void) in_isr; - - _osal_q_lock(qhdl); - bool success = tu_fifo_write(&qhdl->ff, data); - _osal_q_unlock(qhdl); - - TU_ASSERT(success); - - return success; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) -{ - // TODO: revisit; whether this is true or not currently, tu_fifo_empty is a single - // volatile read. - - // Skip queue lock/unlock since this function is primarily called - // with interrupt disabled before going into low power mode - return tu_fifo_empty(&qhdl->ff); -} - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_OSAL_PICO_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtthread.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtthread.h deleted file mode 100644 index 18eb9c69..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtthread.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 tfx2001 (2479727366@qq.com) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_OSAL_RTTHREAD_H_ -#define _TUSB_OSAL_RTTHREAD_H_ - -// RT-Thread Headers -#include "rtthread.h" - -#ifdef __cplusplus -extern "C" { -#endif - -//--------------------------------------------------------------------+ -// TASK API -//--------------------------------------------------------------------+ -TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) { - rt_thread_mdelay(msec); -} - -//--------------------------------------------------------------------+ -// Semaphore API -//--------------------------------------------------------------------+ -typedef struct rt_semaphore osal_semaphore_def_t; -typedef rt_sem_t osal_semaphore_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t -osal_semaphore_create(osal_semaphore_def_t *semdef) { - rt_sem_init(semdef, "tusb", 0, RT_IPC_FLAG_PRIO); - return semdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) { - (void) in_isr; - return rt_sem_release(sem_hdl) == RT_EOK; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) { - return rt_sem_take(sem_hdl, rt_tick_from_millisecond((rt_int32_t) msec)) == RT_EOK; -} - -TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) { - rt_sem_control(sem_hdl, RT_IPC_CMD_RESET, 0); -} - -//--------------------------------------------------------------------+ -// MUTEX API (priority inheritance) -//--------------------------------------------------------------------+ -typedef struct rt_mutex osal_mutex_def_t; -typedef rt_mutex_t osal_mutex_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) { - rt_mutex_init(mdef, "tusb", RT_IPC_FLAG_PRIO); - return mdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) { - return rt_mutex_take(mutex_hdl, rt_tick_from_millisecond((rt_int32_t) msec)) == RT_EOK; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) { - return rt_mutex_release(mutex_hdl) == RT_EOK; -} - -//--------------------------------------------------------------------+ -// QUEUE API -//--------------------------------------------------------------------+ - -// role device/host is used by OS NONE for mutex (disable usb isr) only -#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ - static _type _name##_##buf[_depth]; \ - osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf }; - -typedef struct { - uint16_t depth; - uint16_t item_sz; - void *buf; - - struct rt_messagequeue sq; -} osal_queue_def_t; - -typedef rt_mq_t osal_queue_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t *qdef) { - rt_mq_init(&(qdef->sq), "tusb", qdef->buf, qdef->item_sz, - qdef->item_sz * qdef->depth, RT_IPC_FLAG_PRIO); - return &(qdef->sq); -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void *data, uint32_t msec) { - - rt_tick_t tick = rt_tick_from_millisecond((rt_int32_t) msec); - return rt_mq_recv(qhdl, data, qhdl->msg_size, tick) == RT_EOK; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const *data, bool in_isr) { - (void) in_isr; - return rt_mq_send(qhdl, (void *)data, qhdl->msg_size) == RT_EOK; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) { - return (qhdl->entry) == 0; -} - -#ifdef __cplusplus -} -#endif - -#endif /* _TUSB_OSAL_RTTHREAD_H_ */ diff --git a/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtx4.h b/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtx4.h deleted file mode 100644 index e443135e..00000000 --- a/test-devices/composite-stm32/lib/tinyusb/osal/osal_rtx4.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2021 Tian Yunhao (t123yh) - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_OSAL_RTX4_H_ -#define _TUSB_OSAL_RTX4_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -//--------------------------------------------------------------------+ -// TASK API -//--------------------------------------------------------------------+ -TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) -{ - uint16_t hi = msec >> 16; - uint16_t lo = msec; - while (hi--) { - os_dly_wait(0xFFFE); - } - os_dly_wait(lo); -} - -TU_ATTR_ALWAYS_INLINE static inline uint16_t msec2wait(uint32_t msec) { - if (msec == OSAL_TIMEOUT_WAIT_FOREVER) - return 0xFFFF; - else if (msec >= 0xFFFE) - return 0xFFFE; - else - return msec; -} - -//--------------------------------------------------------------------+ -// Semaphore API -//--------------------------------------------------------------------+ -typedef OS_SEM osal_semaphore_def_t; -typedef OS_ID osal_semaphore_t; - -TU_ATTR_ALWAYS_INLINE static inline OS_ID osal_semaphore_create(osal_semaphore_def_t* semdef) { - os_sem_init(semdef, 0); - return semdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) { - if ( !in_isr ) { - os_sem_send(sem_hdl); - } else { - isr_sem_send(sem_hdl); - } - return true; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) { - return os_sem_wait(sem_hdl, msec2wait(msec)) != OS_R_TMO; -} - -TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) { - // TODO: implement -} - -//--------------------------------------------------------------------+ -// MUTEX API (priority inheritance) -//--------------------------------------------------------------------+ -typedef OS_MUT osal_mutex_def_t; -typedef OS_ID osal_mutex_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) -{ - os_mut_init(mdef); - return mdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) -{ - return os_mut_wait(mutex_hdl, msec2wait(msec)) != OS_R_TMO; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) -{ - return os_mut_release(mutex_hdl) == OS_R_OK; -} - -//--------------------------------------------------------------------+ -// QUEUE API -//--------------------------------------------------------------------+ - -// role device/host is used by OS NONE for mutex (disable usb isr) only -#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ - os_mbx_declare(_name##__mbox, _depth); \ - _declare_box(_name##__pool, sizeof(_type), _depth); \ - osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .pool = _name##__pool, .mbox = _name##__mbox }; - - -typedef struct -{ - uint16_t depth; - uint16_t item_sz; - U32* pool; - U32* mbox; -}osal_queue_def_t; - -typedef osal_queue_def_t* osal_queue_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) -{ - os_mbx_init(qdef->mbox, (qdef->depth + 4) * 4); - _init_box(qdef->pool, ((qdef->item_sz+3)/4)*(qdef->depth) + 3, qdef->item_sz); - return qdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) -{ - void* buf; - os_mbx_wait(qhdl->mbox, &buf, msec2wait(msec)); - memcpy(data, buf, qhdl->item_sz); - _free_box(qhdl->pool, buf); - return true; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) -{ - void* buf = _alloc_box(qhdl->pool); - memcpy(buf, data, qhdl->item_sz); - if ( !in_isr ) - { - os_mbx_send(qhdl->mbox, buf, 0xFFFF); - } - else - { - isr_mbx_send(qhdl->mbox, buf); - } - return true; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) -{ - return os_mbx_check(qhdl->mbox) == qhdl->depth; -} - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c b/test-devices/composite-stm32/lib/tinyusb/portable/st/stm32_fsdev/dcd_stm32_fsdev.c similarity index 53% rename from test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c rename to test-devices/composite-stm32/lib/tinyusb/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 30a2e9c8..a26c6689 100644 --- a/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c +++ b/test-devices/composite-stm32/lib/tinyusb/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -44,6 +44,7 @@ * L0x2, L0x3 1024 byte buffer * L1 512 byte buffer * L4x2, L4x3 1024 byte buffer + * G0 2048 byte buffer * * To use this driver, you must: * - If you are using a device with crystal-less USB, set up the clock recovery system (CRS) @@ -106,9 +107,9 @@ #include "device/dcd.h" #ifdef TUP_USBIP_FSDEV_STM32 - // Undefine to reduce the dependence on HAL - #undef USE_HAL_DRIVER - #include "dcd_stm32_fsdev_pvt_st.h" +// Undefine to reduce the dependence on HAL +#undef USE_HAL_DRIVER +#include "portable/st/stm32_fsdev/dcd_stm32_fsdev.h" #endif /***************************************************** @@ -118,17 +119,17 @@ // HW supports max of 8 bidirectional endpoints, but this can be reduced to save RAM // (8u here would mean 8 IN and 8 OUT) #ifndef MAX_EP_COUNT -# define MAX_EP_COUNT 8U +#define MAX_EP_COUNT 8U #endif // If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it // Both of these MUST be a multiple of 2, and are in byte units. #ifndef DCD_STM32_BTABLE_BASE -# define DCD_STM32_BTABLE_BASE 0U +#define DCD_STM32_BTABLE_BASE 0U #endif -#ifndef DCD_STM32_BTABLE_LENGTH -# define DCD_STM32_BTABLE_LENGTH (PMA_LENGTH - DCD_STM32_BTABLE_BASE) +#ifndef DCD_STM32_BTABLE_SIZE +#define DCD_STM32_BTABLE_SIZE (FSDEV_PMA_SIZE - DCD_STM32_BTABLE_BASE) #endif /*************************************************** @@ -136,7 +137,7 @@ */ TU_VERIFY_STATIC((MAX_EP_COUNT) <= STFSDEV_EP_COUNT, "Only 8 endpoints supported on the hardware"); -TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_LENGTH))<=(PMA_LENGTH), "BTABLE does not fit in PMA RAM"); +TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_SIZE)) <= (FSDEV_PMA_SIZE), "BTABLE does not fit in PMA RAM"); TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligned to 8 bytes"); //--------------------------------------------------------------------+ @@ -144,21 +145,18 @@ TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligne //--------------------------------------------------------------------+ // One of these for every EP IN & OUT, uses a bit of RAM.... -typedef struct -{ - uint8_t * buffer; - tu_fifo_t * ff; +typedef struct { + uint8_t *buffer; + tu_fifo_t *ff; uint16_t total_len; uint16_t queued_len; - uint16_t pma_ptr; uint16_t max_packet_size; - uint16_t pma_alloc_size; - uint8_t ep_idx; // index for USB_EPnR register + uint8_t ep_idx; // index for USB_EPnR register + bool iso_in_sending; // Workaround for ISO IN EP doesn't have interrupt mask } xfer_ctl_t; // EP allocator -typedef struct -{ +typedef struct { uint8_t ep_num; uint8_t ep_type; bool allocated[2]; @@ -178,28 +176,25 @@ static uint8_t remoteWakeCountdown; // When wake is requested // into the stack. static void dcd_handle_bus_reset(void); -static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix); +static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix); +static bool edpt_xfer(uint8_t rhport, uint8_t ep_addr); static void dcd_ep_ctr_handler(void); // PMA allocation/access -static uint8_t open_ep_count; static uint16_t ep_buf_ptr; ///< Points to first free memory location -static void dcd_pma_alloc_reset(void); -static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length); -static void dcd_pma_free(uint8_t ep_addr); -static void dcd_ep_free(uint8_t ep_addr); +static uint32_t dcd_pma_alloc(uint16_t length, bool dbuf); static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type); -static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes); -static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes); +static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes); +static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes); -static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes); -static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes); +static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes); +static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes); //--------------------------------------------------------------------+ // Inline helper //--------------------------------------------------------------------+ -TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t ep_addr) +TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint32_t ep_addr) { uint8_t epnum = tu_edpt_number(ep_addr); uint8_t dir = tu_edpt_dir(ep_addr); @@ -209,22 +204,11 @@ TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t ep_addr) return &xfer_status[epnum][dir]; } -// Using a function due to better type checks -// This seems better than having to do type casts everywhere else -TU_ATTR_ALWAYS_INLINE static inline void reg16_clear_bits(__IO uint16_t *reg, uint16_t mask) { - *reg = (uint16_t)(*reg & ~mask); -} - -// Bits in ISTR are cleared upon writing 0 -TU_ATTR_ALWAYS_INLINE static inline void clear_istr_bits(uint16_t mask) { - USB->ISTR = ~mask; -} - //--------------------------------------------------------------------+ // Controller API //--------------------------------------------------------------------+ -void dcd_init (uint8_t rhport) +void dcd_init(uint8_t rhport) { /* Clocks should already be enabled */ /* Use __HAL_RCC_USB_CLK_ENABLE(); to enable the clocks before calling this function */ @@ -232,40 +216,41 @@ void dcd_init (uint8_t rhport) /* The RM mentions to use a special ordering of PDWN and FRES, but this isn't done in HAL. * Here, the RM is followed. */ - for(uint32_t i = 0; i<200; i++) // should be a few us - { + for (uint32_t i = 0; i < 200; i++) { // should be a few us asm("NOP"); } // Perform USB peripheral reset USB->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; - for(uint32_t i = 0; i<200; i++) // should be a few us - { + for (uint32_t i = 0; i < 200; i++) { // should be a few us asm("NOP"); } - reg16_clear_bits(&USB->CNTR, USB_CNTR_PDWN);// Remove powerdown + + USB->CNTR &= ~USB_CNTR_PDWN; + // Wait startup time, for F042 and F070, this is <= 1 us. - for(uint32_t i = 0; i<200; i++) // should be a few us - { + for (uint32_t i = 0; i < 200; i++) { // should be a few us asm("NOP"); } USB->CNTR = 0; // Enable USB +#if !defined(STM32G0) && !defined(STM32H5) // BTABLE register does not exist any more on STM32G0, it is fixed to USB SRAM base address USB->BTABLE = DCD_STM32_BTABLE_BASE; - +#endif USB->ISTR = 0; // Clear pending interrupts // Reset endpoints to disabled - for(uint32_t i=0; iCNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; dcd_handle_bus_reset(); // Enable pull-up if supported - if ( dcd_connect ) dcd_connect(rhport); + if (dcd_connect) { + dcd_connect(rhport); + } } // Define only on MCU with internal pull-up. BSP can define on MCU without internal PU. @@ -274,14 +259,14 @@ void dcd_init (uint8_t rhport) // Disable internal D+ PU void dcd_disconnect(uint8_t rhport) { - (void) rhport; + (void)rhport; USB->BCDR &= ~(USB_BCDR_DPPU); } // Enable internal D+ PU void dcd_connect(uint8_t rhport) { - (void) rhport; + (void)rhport; USB->BCDR |= USB_BCDR_DPPU; } @@ -289,60 +274,54 @@ void dcd_connect(uint8_t rhport) // Disable internal D+ PU void dcd_disconnect(uint8_t rhport) { - (void) rhport; + (void)rhport; SYSCFG->PMC &= ~(SYSCFG_PMC_USB_PU); } // Enable internal D+ PU void dcd_connect(uint8_t rhport) { - (void) rhport; + (void)rhport; SYSCFG->PMC |= SYSCFG_PMC_USB_PU; } #endif void dcd_sof_enable(uint8_t rhport, bool en) { - (void) rhport; - (void) en; + (void)rhport; + (void)en; - if (en) - { + if (en) { USB->CNTR |= USB_CNTR_SOFM; - } - else - { - USB->CNTR &= (uint16_t) ~USB_CNTR_SOFM; + } else { + USB->CNTR &= ~USB_CNTR_SOFM; } } // Enable device interrupt -void dcd_int_enable (uint8_t rhport) +void dcd_int_enable(uint8_t rhport) { (void)rhport; // Member here forces write to RAM before allowing ISR to execute __DSB(); __ISB(); -#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || \ - CFG_TUSB_MCU == OPT_MCU_STM32L4 +#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || CFG_TUSB_MCU == OPT_MCU_STM32L4 NVIC_EnableIRQ(USB_IRQn); #elif CFG_TUSB_MCU == OPT_MCU_STM32L1 NVIC_EnableIRQ(USB_LP_IRQn); #elif CFG_TUSB_MCU == OPT_MCU_STM32F3 - // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from - // shared USB/CAN IRQs to separate CAN and USB IRQs. - // This dynamically checks if this remap is active to enable the right IRQs. - #ifdef SYSCFG_CFGR1_USB_IT_RMP - if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) - { +// Some STM32F302/F303 devices allow to remap the USB interrupt vectors from +// shared USB/CAN IRQs to separate CAN and USB IRQs. +// This dynamically checks if this remap is active to enable the right IRQs. +#ifdef SYSCFG_CFGR1_USB_IT_RMP + if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) { NVIC_EnableIRQ(USB_HP_IRQn); NVIC_EnableIRQ(USB_LP_IRQn); NVIC_EnableIRQ(USBWakeUp_RMP_IRQn); - } - else - #endif + } else +#endif { NVIC_EnableIRQ(USB_HP_CAN_TX_IRQn); NVIC_EnableIRQ(USB_LP_CAN_RX0_IRQn); @@ -358,6 +337,16 @@ void dcd_int_enable (uint8_t rhport) NVIC_EnableIRQ(USB_LP_IRQn); NVIC_EnableIRQ(USBWakeUp_IRQn); +#elif CFG_TUSB_MCU == OPT_MCU_STM32G0 +#ifdef STM32G0B0xx + NVIC_EnableIRQ(USB_IRQn); +#else + NVIC_EnableIRQ(USB_UCPD1_2_IRQn); +#endif + +#elif CFG_TUSB_MCU == OPT_MCU_STM32H5 + NVIC_EnableIRQ(USB_DRD_FS_IRQn); + #elif CFG_TUSB_MCU == OPT_MCU_STM32WB NVIC_EnableIRQ(USB_HP_IRQn); NVIC_EnableIRQ(USB_LP_IRQn); @@ -366,7 +355,7 @@ void dcd_int_enable (uint8_t rhport) NVIC_EnableIRQ(USB_FS_IRQn); #else - #error Unknown arch in USB driver +#error Unknown arch in USB driver #endif } @@ -375,24 +364,21 @@ void dcd_int_disable(uint8_t rhport) { (void)rhport; -#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || \ - CFG_TUSB_MCU == OPT_MCU_STM32L4 +#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || CFG_TUSB_MCU == OPT_MCU_STM32L4 NVIC_DisableIRQ(USB_IRQn); #elif CFG_TUSB_MCU == OPT_MCU_STM32L1 NVIC_DisableIRQ(USB_LP_IRQn); #elif CFG_TUSB_MCU == OPT_MCU_STM32F3 - // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from - // shared USB/CAN IRQs to separate CAN and USB IRQs. - // This dynamically checks if this remap is active to disable the right IRQs. - #ifdef SYSCFG_CFGR1_USB_IT_RMP - if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) - { +// Some STM32F302/F303 devices allow to remap the USB interrupt vectors from +// shared USB/CAN IRQs to separate CAN and USB IRQs. +// This dynamically checks if this remap is active to disable the right IRQs. +#ifdef SYSCFG_CFGR1_USB_IT_RMP + if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) { NVIC_DisableIRQ(USB_HP_IRQn); NVIC_DisableIRQ(USB_LP_IRQn); NVIC_DisableIRQ(USBWakeUp_RMP_IRQn); - } - else - #endif + } else +#endif { NVIC_DisableIRQ(USB_HP_CAN_TX_IRQn); NVIC_DisableIRQ(USB_LP_CAN_RX0_IRQn); @@ -408,6 +394,16 @@ void dcd_int_disable(uint8_t rhport) NVIC_DisableIRQ(USB_LP_IRQn); NVIC_DisableIRQ(USBWakeUp_IRQn); +#elif CFG_TUSB_MCU == OPT_MCU_STM32G0 +#ifdef STM32G0B0xx + NVIC_DisableIRQ(USB_IRQn); +#else + NVIC_DisableIRQ(USB_UCPD1_2_IRQn); +#endif + +#elif CFG_TUSB_MCU == OPT_MCU_STM32H5 + NVIC_DisableIRQ(USB_DRD_FS_IRQn); + #elif CFG_TUSB_MCU == OPT_MCU_STM32WB NVIC_DisableIRQ(USB_HP_IRQn); NVIC_DisableIRQ(USB_LP_IRQn); @@ -416,7 +412,7 @@ void dcd_int_disable(uint8_t rhport) NVIC_DisableIRQ(USB_FS_IRQn); #else - #error Unknown arch in USB driver +#error Unknown arch in USB driver #endif // CMSIS has a membar after disabling interrupts @@ -425,8 +421,8 @@ void dcd_int_disable(uint8_t rhport) // Receive Set Address request, mcu port must also include status IN response void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { - (void) rhport; - (void) dev_addr; + (void)rhport; + (void)dev_addr; // Respond with status dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK | 0x00, NULL, 0); @@ -437,45 +433,35 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) void dcd_remote_wakeup(uint8_t rhport) { - (void) rhport; + (void)rhport; - USB->CNTR |= (uint16_t) USB_CNTR_RESUME; + USB->CNTR |= USB_CNTR_RESUME; remoteWakeCountdown = 4u; // required to be 1 to 15 ms, ESOF should trigger every 1ms. } -static const tusb_desc_endpoint_t ep0OUT_desc = -{ - .bLength = sizeof(tusb_desc_endpoint_t), - .bDescriptorType = TUSB_DESC_ENDPOINT, - - .bEndpointAddress = 0x00, - .bmAttributes = { .xfer = TUSB_XFER_CONTROL }, - .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE, - .bInterval = 0 +static const tusb_desc_endpoint_t ep0OUT_desc = { + .bLength = sizeof(tusb_desc_endpoint_t), + .bDescriptorType = TUSB_DESC_ENDPOINT, + .bEndpointAddress = 0x00, + .bmAttributes = {.xfer = TUSB_XFER_CONTROL}, + .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE, + .bInterval = 0 }; -static const tusb_desc_endpoint_t ep0IN_desc = -{ - .bLength = sizeof(tusb_desc_endpoint_t), - .bDescriptorType = TUSB_DESC_ENDPOINT, - - .bEndpointAddress = 0x80, - .bmAttributes = { .xfer = TUSB_XFER_CONTROL }, - .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE, - .bInterval = 0 +static const tusb_desc_endpoint_t ep0IN_desc = { + .bLength = sizeof(tusb_desc_endpoint_t), + .bDescriptorType = TUSB_DESC_ENDPOINT, + .bEndpointAddress = 0x80, + .bmAttributes = {.xfer = TUSB_XFER_CONTROL}, + .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE, + .bInterval = 0 }; static void dcd_handle_bus_reset(void) { - //__IO uint16_t * const epreg = &(EPREG(0)); USB->DADDR = 0u; // disable USB peripheral by clearing the EF flag - - for(uint32_t i=0; iDADDR = USB_DADDR_EF; // Set enable flag, and leaving the device address as zero. } @@ -501,30 +489,63 @@ static void dcd_ep_ctr_tx_handler(uint32_t wIstr) // Verify the CTR_TX bit is set. This was in the ST Micro code, // but I'm not sure it's actually necessary? - if((wEPRegVal & USB_EP_CTR_TX) == 0U) - { + if ((wEPRegVal & USB_EP_CTR_TX) == 0U) { return; } /* clear int flag */ pcd_clear_tx_ep_ctr(USB, EPindex); - xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); - if((xfer->total_len != xfer->queued_len)) /* TX not complete */ - { - dcd_transmit_packet(xfer, EPindex); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); + + if ((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) { + // Ignore spurious interrupts that we don't schedule + // host can send IN token while there is no data to send, since ISO does not have NAK + // this will result to zero length packet --> trigger interrupt (which cannot be masked) + if (!xfer->iso_in_sending) { + return; + } + xfer->iso_in_sending = false; + + if (wEPRegVal & USB_EP_DTOG_TX) { + pcd_set_ep_tx_dbuf0_cnt(USB, EPindex, 0); + } else { + pcd_set_ep_tx_dbuf1_cnt(USB, EPindex, 0); + } } - else /* TX Complete */ - { + + if ((xfer->total_len != xfer->queued_len)) { + dcd_transmit_packet(xfer, EPindex); + } else { dcd_event_xfer_complete(0, ep_addr, xfer->total_len, XFER_RESULT_SUCCESS, true); } } // Handle CTR interrupt for the RX/OUT direction -// // Upon call, (wIstr & USB_ISTR_DIR) == 0U static void dcd_ep_ctr_rx_handler(uint32_t wIstr) { +#ifdef FSDEV_BUS_32BIT + /* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf + * From STM32H503 errata 2.15.1: Buffer description table update completes after CTR interrupt triggers + * Description: + * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses + * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct. + * Workaround: + * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay + * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode + * - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code + * also takes time, so we'll wait 60 cycles (count = 20). + * - Since Low Speed mode is not supported/popular, we will ignore it for now. + * + * Note: this errata also seems to apply to G0, U5, H5 etc. + */ + volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver + while (cycle_count > 0U) { + cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare) + } +#endif + uint32_t EPindex = wIstr & USB_ISTR_EP_ID; uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex); uint8_t ep_addr = wEPRegVal & USB_EPADDR_FIELD; @@ -533,92 +554,83 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr) // Verify the CTR_RX bit is set. This was in the ST Micro code, // but I'm not sure it's actually necessary? - if((wEPRegVal & USB_EP_CTR_RX) == 0U) - { + if ((wEPRegVal & USB_EP_CTR_RX) == 0U) { return; } - if((ep_addr == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) /* Setup packet */ - { - // The setup_received function uses memcpy, so this must first copy the setup data into - // user memory, to allow for the 32-bit access that memcpy performs. - uint8_t userMemBuf[8]; + if ((ep_addr == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) { + /* Setup packet */ uint32_t count = pcd_get_ep_rx_cnt(USB, EPindex); - /* Get SETUP Packet*/ - if(count == 8) // Setup packet should always be 8 bytes. If not, ignore it, and try again. - { + // Setup packet should always be 8 bytes. If not, ignore it, and try again. + if (count == 8) { // Must reset EP to NAK (in case it had been stalling) (though, maybe too late here) - pcd_set_ep_rx_status(USB,0u,USB_EP_RX_NAK); - pcd_set_ep_tx_status(USB,0u,USB_EP_TX_NAK); - dcd_read_packet_memory(userMemBuf, *pcd_ep_rx_address_ptr(USB,EPindex), 8); - dcd_event_setup_received(0, (uint8_t*)userMemBuf, true); + pcd_set_ep_rx_status(USB, 0u, USB_EP_RX_NAK); + pcd_set_ep_tx_status(USB, 0u, USB_EP_TX_NAK); +#ifdef FSDEV_BUS_32BIT + dcd_event_setup_received(0, (uint8_t *)(USB_PMAADDR + pcd_get_ep_rx_address(USB, EPindex)), true); +#else + // The setup_received function uses memcpy, so this must first copy the setup data into + // user memory, to allow for the 32-bit access that memcpy performs. + uint8_t userMemBuf[8]; + dcd_read_packet_memory(userMemBuf, pcd_get_ep_rx_address(USB, EPindex), 8); + dcd_event_setup_received(0, (uint8_t *)userMemBuf, true); +#endif } - } - else - { + } else { + // Clear RX CTR interrupt flag + if (ep_addr != 0u) { + pcd_clear_rx_ep_ctr(USB, EPindex); + } + uint32_t count; + uint16_t addr; /* Read from correct register when ISOCHRONOUS (double buffered) */ - if ( (wEPRegVal & USB_EP_DTOG_RX) && ( (wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) ) { - count = pcd_get_ep_tx_cnt(USB, EPindex); + if ((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) { + if (wEPRegVal & USB_EP_DTOG_RX) { + count = pcd_get_ep_dbuf0_cnt(USB, EPindex); + addr = pcd_get_ep_dbuf0_address(USB, EPindex); + } else { + count = pcd_get_ep_dbuf1_cnt(USB, EPindex); + addr = pcd_get_ep_dbuf1_address(USB, EPindex); + } } else { count = pcd_get_ep_rx_cnt(USB, EPindex); + addr = pcd_get_ep_rx_address(USB, EPindex); } TU_ASSERT(count <= xfer->max_packet_size, /**/); - // Clear RX CTR interrupt flag - if(ep_addr != 0u) - { - pcd_clear_rx_ep_ctr(USB, EPindex); - } - - if (count != 0U) - { - uint16_t addr = *pcd_ep_rx_address_ptr(USB, EPindex); - - if (xfer->ff) - { + if (count != 0U) { + if (xfer->ff) { dcd_read_packet_memory_ff(xfer->ff, addr, count); - } - else - { + } else { dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), addr, count); } xfer->queued_len = (uint16_t)(xfer->queued_len + count); } - if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len)) - { - /* RX COMPLETE */ + if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len)) { + // all bytes received or short packet dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true); - // Though the host could still send, we don't know. - // Does the bulk pipe need to be reset to valid to allow for a ZLP? - } - else - { - uint32_t remaining = (uint32_t)xfer->total_len - (uint32_t)xfer->queued_len; - if(remaining >= xfer->max_packet_size) { - pcd_set_ep_rx_bufsize(USB, EPindex,xfer->max_packet_size); - } else { - pcd_set_ep_rx_bufsize(USB, EPindex,remaining); - } - - if (!((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS)) { - /* Set endpoint active again for receiving more data. - * Note that isochronous endpoints stay active always */ - pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID); + } else { + /* Set endpoint active again for receiving more data. + * Note that isochronous endpoints stay active always */ + if ((wEPRegVal & USB_EP_TYPE_MASK) != USB_EP_ISOCHRONOUS) { + uint16_t remaining = xfer->total_len - xfer->queued_len; + uint16_t cnt = tu_min16(remaining, xfer->max_packet_size); + pcd_set_ep_rx_cnt(USB, EPindex, cnt); } + pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID); } } // For EP0, prepare to receive another SETUP packet. // Clear CTR last so that a new packet does not overwrite the packing being read. // (Based on the docs, it seems SETUP will always be accepted after CTR is cleared) - if(ep_addr == 0u) - { - // Always be prepared for a status packet... - pcd_set_ep_rx_bufsize(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE); + if (ep_addr == 0u) { + // Always be prepared for a status packet... + pcd_set_ep_rx_cnt(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE); pcd_clear_rx_ep_ctr(USB, EPindex); } } @@ -628,64 +640,60 @@ static void dcd_ep_ctr_handler(void) uint32_t wIstr; /* stay in loop while pending interrupts */ - while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U) - { - - if ((wIstr & USB_ISTR_DIR) == 0U) /* TX/IN */ - { + while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U) { + if ((wIstr & USB_ISTR_DIR) == 0U) { + /* TX/IN */ dcd_ep_ctr_tx_handler(wIstr); - } - else /* RX/OUT*/ - { + } else { + /* RX/OUT*/ dcd_ep_ctr_rx_handler(wIstr); } } } -void dcd_int_handler(uint8_t rhport) { +void dcd_int_handler(uint8_t rhport) +{ - (void) rhport; + (void)rhport; uint32_t int_status = USB->ISTR; - //const uint32_t handled_ints = USB_ISTR_CTR | USB_ISTR_RESET | USB_ISTR_WKUP - // | USB_ISTR_SUSP | USB_ISTR_SOF | USB_ISTR_ESOF; - // unused IRQs: (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_L1REQ ) + // const uint32_t handled_ints = USB_ISTR_CTR | USB_ISTR_RESET | USB_ISTR_WKUP + // | USB_ISTR_SUSP | USB_ISTR_SOF | USB_ISTR_ESOF; + // unused IRQs: (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_L1REQ ) // The ST driver loops here on the CTR bit, but that loop has been moved into the // dcd_ep_ctr_handler(), so less need to loop here. The other interrupts shouldn't // be triggered repeatedly. /* Put SOF flag at the beginning of ISR in case to get least amount of jitter if it is used for timing purposes */ - if(int_status & USB_ISTR_SOF) { - clear_istr_bits(USB_ISTR_SOF); + if (int_status & USB_ISTR_SOF) { + USB->ISTR = (fsdev_bus_t)~USB_ISTR_SOF; dcd_event_sof(0, USB->FNR & USB_FNR_FN, true); } - if(int_status & USB_ISTR_RESET) { + if (int_status & USB_ISTR_RESET) { // USBRST is start of reset. - clear_istr_bits(USB_ISTR_RESET); + USB->ISTR = (fsdev_bus_t)~USB_ISTR_RESET; dcd_handle_bus_reset(); dcd_event_bus_reset(0, TUSB_SPEED_FULL, true); return; // Don't do the rest of the things here; perhaps they've been cleared? } - if (int_status & USB_ISTR_CTR) - { + if (int_status & USB_ISTR_CTR) { /* servicing of the endpoint correct transfer interrupt */ /* clear of the CTR flag into the sub */ dcd_ep_ctr_handler(); } - if (int_status & USB_ISTR_WKUP) - { - reg16_clear_bits(&USB->CNTR, USB_CNTR_LPMODE); - reg16_clear_bits(&USB->CNTR, USB_CNTR_FSUSP); - clear_istr_bits(USB_ISTR_WKUP); + if (int_status & USB_ISTR_WKUP) { + USB->CNTR &= ~USB_CNTR_LPMODE; + USB->CNTR &= ~USB_CNTR_FSUSP; + + USB->ISTR = (fsdev_bus_t)~USB_ISTR_WKUP; dcd_event_bus_signal(0, DCD_EVENT_RESUME, true); } - if (int_status & USB_ISTR_SUSP) - { + if (int_status & USB_ISTR_SUSP) { /* Suspend is asserted for both suspend and unplug events. without Vbus monitoring, * these events cannot be differentiated, so we only trigger suspend. */ @@ -694,20 +702,18 @@ void dcd_int_handler(uint8_t rhport) { USB->CNTR |= USB_CNTR_LPMODE; /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ - clear_istr_bits(USB_ISTR_SUSP); + USB->ISTR = (fsdev_bus_t)~USB_ISTR_SUSP; dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); } - if(int_status & USB_ISTR_ESOF) { - if(remoteWakeCountdown == 1u) - { - USB->CNTR &= (uint16_t)(~USB_CNTR_RESUME); + if (int_status & USB_ISTR_ESOF) { + if (remoteWakeCountdown == 1u) { + USB->CNTR &= ~USB_CNTR_RESUME; } - if(remoteWakeCountdown > 0u) - { + if (remoteWakeCountdown > 0u) { remoteWakeCountdown--; } - clear_istr_bits(USB_ISTR_ESOF); + USB->ISTR = (fsdev_bus_t)~USB_ISTR_ESOF; } } @@ -717,130 +723,73 @@ void dcd_int_handler(uint8_t rhport) { // Invoked when a control transfer's status stage is complete. // May help DCD to prepare for next control transfer, this API is optional. -void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) +void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) { - (void) rhport; + (void)rhport; if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && - request->bRequest == TUSB_REQ_SET_ADDRESS ) - { - uint8_t const dev_addr = (uint8_t) request->wValue; + request->bRequest == TUSB_REQ_SET_ADDRESS) { + uint8_t const dev_addr = (uint8_t)request->wValue; // Setting new address after the whole request is complete - reg16_clear_bits(&USB->DADDR, USB_DADDR_ADD); - USB->DADDR = (uint16_t)(USB->DADDR | dev_addr); // leave the enable bit set - } -} - -static void dcd_pma_alloc_reset(void) -{ - open_ep_count = 0; - ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT; // 8 bytes per endpoint (two TX and two RX words, each) - //TU_LOG2("dcd_pma_alloc_reset()\r\n"); - for(uint32_t i=0; ipma_alloc_size = 0U; - xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_alloc_size = 0U; - xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_OUT))->pma_ptr = 0U; - xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_ptr = 0U; + USB->DADDR &= ~USB_DADDR_ADD; + USB->DADDR |= dev_addr; // leave the enable bit set } } /*** * Allocate a section of PMA - * - * If the EP number has already been allocated, and the new allocation - * is larger than the old allocation, then this will fail with a TU_ASSERT. - * (This is done to simplify the code. More complicated algorithms could be used) - * + * In case of double buffering, high 16bit is the address of 2nd buffer * During failure, TU_ASSERT is used. If this happens, rework/reallocate memory manually. */ -static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length) +static uint32_t dcd_pma_alloc(uint16_t length, bool dbuf) { - xfer_ctl_t* epXferCtl = xfer_ctl_ptr(ep_addr); - - if(epXferCtl->pma_alloc_size != 0U) - { - //TU_LOG2("dcd_pma_alloc(%x,%x)=%x (cached)\r\n",ep_addr,length,epXferCtl->pma_ptr); - // Previously allocated - TU_ASSERT(length <= epXferCtl->pma_alloc_size, 0xFFFF); // Verify no larger than previous alloc - return epXferCtl->pma_ptr; - } - - open_ep_count++; + // Ensure allocated buffer is aligned +#ifdef FSDEV_BUS_32BIT + length = (length + 3) & ~0x03; +#else + length = (length + 1) & ~0x01; +#endif - uint16_t addr = ep_buf_ptr; + uint32_t addr = ep_buf_ptr; ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer - // Verify no overflow - TU_ASSERT(ep_buf_ptr <= PMA_LENGTH, 0xFFFF); + if (dbuf) { + addr |= ((uint32_t)ep_buf_ptr) << 16; + ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer + } - epXferCtl->pma_ptr = addr; - epXferCtl->pma_alloc_size = length; - //TU_LOG2("dcd_pma_alloc(%x,%x)=%x\r\n",ep_addr,length,addr); + // Verify packet buffer is not overflowed + TU_ASSERT(ep_buf_ptr <= FSDEV_PMA_SIZE, 0xFFFF); return addr; } -/*** - * Free a block of PMA space - */ -static void dcd_pma_free(uint8_t ep_addr) -{ - // Presently, this should never be called for EP0 IN/OUT - TU_ASSERT(open_ep_count > 2, /**/); - TU_ASSERT(xfer_ctl_ptr(ep_addr)->max_packet_size != 0, /**/); - open_ep_count--; - - // If count is 2, only EP0 should be open, so allocations can be mostly reset. - - if(open_ep_count == 2) - { - ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT + 2*CFG_TUD_ENDPOINT0_SIZE; // 8 bytes per endpoint (two TX and two RX words, each), and EP0 - - // Skip EP0 - for(uint32_t i=1; ipma_alloc_size = 0U; - xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_alloc_size = 0U; - xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_OUT))->pma_ptr = 0U; - xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_ptr = 0U; - } - } -} - /*** * Allocate hardware endpoint */ static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type) { uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); - for(uint8_t i = 0; i < STFSDEV_EP_COUNT; i++) - { + for (uint8_t i = 0; i < STFSDEV_EP_COUNT; i++) { // Check if already allocated - if(ep_alloc_status[i].allocated[dir] && - ep_alloc_status[i].ep_type == ep_type && - ep_alloc_status[i].ep_num == epnum) - { + if (ep_alloc_status[i].allocated[dir] && + ep_alloc_status[i].ep_type == ep_type && + ep_alloc_status[i].ep_num == epnum) { return i; } // If EP of current direction is not allocated // Except for ISO endpoint, both direction should be free - if(!ep_alloc_status[i].allocated[dir] && - (ep_type != TUSB_XFER_ISOCHRONOUS || !ep_alloc_status[i].allocated[dir ^ 1])) - { + if (!ep_alloc_status[i].allocated[dir] && + (ep_type != TUSB_XFER_ISOCHRONOUS || !ep_alloc_status[i].allocated[dir ^ 1])) { // Check if EP number is the same - if(ep_alloc_status[i].ep_num == 0xFF || - ep_alloc_status[i].ep_num == epnum) - { + if (ep_alloc_status[i].ep_num == 0xFF || ep_alloc_status[i].ep_num == epnum) { // One EP pair has to be the same type - if(ep_alloc_status[i].ep_type == 0xFF || - ep_alloc_status[i].ep_type == ep_type) - { + if (ep_alloc_status[i].ep_type == 0xFF || ep_alloc_status[i].ep_type == ep_type) { ep_alloc_status[i].ep_num = epnum; ep_alloc_status[i].ep_type = ep_type; ep_alloc_status[i].allocated[dir] = true; @@ -855,121 +804,79 @@ static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type) TU_ASSERT(0); } -/*** - * Free hardware endpoint - */ -static void dcd_ep_free(uint8_t ep_addr) -{ - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - - for(uint8_t i = 0; i < STFSDEV_EP_COUNT; i++) - { - // Check if EP number & dir are the same - if(ep_alloc_status[i].ep_num == epnum && - ep_alloc_status[i].allocated[dir] == dir) - { - ep_alloc_status[i].allocated[dir] = false; - // Reset entry if ISO endpoint or both direction are free - if(ep_alloc_status[i].ep_type == TUSB_XFER_ISOCHRONOUS || - !ep_alloc_status[i].allocated[dir ^ 1]) - { - ep_alloc_status[i].ep_num = 0xFF; - ep_alloc_status[i].ep_type = 0xFF; - - return; - } - } - } -} - // The STM32F0 doesn't seem to like |= or &= to manipulate the EP#R registers, // so I'm using the #define from HAL here, instead. -bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) +bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc) { (void)rhport; - uint8_t const ep_idx = dcd_ep_alloc(p_endpoint_desc->bEndpointAddress, p_endpoint_desc->bmAttributes.xfer); - uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); + uint8_t const ep_addr = p_endpoint_desc->bEndpointAddress; + uint8_t const ep_idx = dcd_ep_alloc(ep_addr, p_endpoint_desc->bmAttributes.xfer); + uint8_t const dir = tu_edpt_dir(ep_addr); const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc); const uint16_t buffer_size = pcd_aligned_buffer_size(packet_size); uint16_t pma_addr; uint32_t wType; TU_ASSERT(ep_idx < STFSDEV_EP_COUNT); - TU_ASSERT(buffer_size <= 1024); + TU_ASSERT(buffer_size <= 64); // Set type - switch(p_endpoint_desc->bmAttributes.xfer) { - case TUSB_XFER_CONTROL: - wType = USB_EP_CONTROL; - break; - case TUSB_XFER_ISOCHRONOUS: - wType = USB_EP_ISOCHRONOUS; - break; - case TUSB_XFER_BULK: - wType = USB_EP_CONTROL; - break; - - case TUSB_XFER_INTERRUPT: - wType = USB_EP_INTERRUPT; - break; - - default: - TU_ASSERT(false); + switch (p_endpoint_desc->bmAttributes.xfer) { + case TUSB_XFER_CONTROL: + wType = USB_EP_CONTROL; + break; + case TUSB_XFER_BULK: + wType = USB_EP_CONTROL; + break; + + case TUSB_XFER_INTERRUPT: + wType = USB_EP_INTERRUPT; + break; + + default: + // Note: ISO endpoint should use alloc / active functions + TU_ASSERT(false); } pcd_set_eptype(USB, ep_idx, wType); - pcd_set_ep_address(USB, ep_idx, tu_edpt_number(p_endpoint_desc->bEndpointAddress)); - // Be normal, for now, instead of only accepting zero-byte packets (on control endpoint) - // or being double-buffered (bulk endpoints) - pcd_clear_ep_kind(USB,0); + pcd_set_ep_address(USB, ep_idx, tu_edpt_number(ep_addr)); - /* Create a packet memory buffer area. For isochronous endpoints, - * use the same buffer as the double buffer, essentially disabling double buffering */ - pma_addr = dcd_pma_alloc(p_endpoint_desc->bEndpointAddress, buffer_size); + /* Create a packet memory buffer area. */ + pma_addr = dcd_pma_alloc(buffer_size, false); - if( (dir == TUSB_DIR_IN) || (wType == USB_EP_ISOCHRONOUS) ) - { - *pcd_ep_tx_address_ptr(USB, ep_idx) = pma_addr; - pcd_set_ep_tx_bufsize(USB, ep_idx, buffer_size); + if (dir == TUSB_DIR_IN) { + pcd_set_ep_tx_address(USB, ep_idx, pma_addr); + pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK); pcd_clear_tx_dtog(USB, ep_idx); - } - - if( (dir == TUSB_DIR_OUT) || (wType == USB_EP_ISOCHRONOUS) ) - { - *pcd_ep_rx_address_ptr(USB, ep_idx) = pma_addr; - pcd_set_ep_rx_bufsize(USB, ep_idx, buffer_size); + } else { + pcd_set_ep_rx_address(USB, ep_idx, pma_addr); + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK); pcd_clear_rx_dtog(USB, ep_idx); } - /* Enable endpoint */ - if (dir == TUSB_DIR_IN) - { - if(wType == USB_EP_ISOCHRONOUS) { - pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); - } else { - pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK); - } - } else - { - if(wType == USB_EP_ISOCHRONOUS) { - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); - } else { - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK); - } - } - - xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->max_packet_size = packet_size; - xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->ep_idx = ep_idx; + xfer_ctl_ptr(ep_addr)->max_packet_size = packet_size; + xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx; return true; } -void dcd_edpt_close_all (uint8_t rhport) +void dcd_edpt_close_all(uint8_t rhport) { - (void) rhport; - // TODO implement dcd_edpt_close_all() + (void)rhport; + + for (uint32_t i = 1; i < STFSDEV_EP_COUNT; i++) { + // Reset endpoint + pcd_set_endpoint(USB, i, 0); + // Clear EP allocation status + ep_alloc_status[i].ep_num = 0xFF; + ep_alloc_status[i].ep_type = 0xFF; + ep_alloc_status[i].allocated[0] = false; + ep_alloc_status[i].allocated[1] = false; + } + + // Reset PMA allocation + ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * MAX_EP_COUNT + 2 * CFG_TUD_ENDPOINT0_SIZE; } /** @@ -979,223 +886,203 @@ void dcd_edpt_close_all (uint8_t rhport) * * This also clears transfers in progress, should there be any. */ -void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { (void)rhport; - xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); uint8_t const ep_idx = xfer->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); - if(dir == TUSB_DIR_IN) - { + if (dir == TUSB_DIR_IN) { pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); - } - else - { + } else { pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); } - - dcd_ep_free(ep_addr); - - dcd_pma_free(ep_addr); } bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { (void)rhport; - TU_ASSERT(largest_packet_size <= 1024); - uint8_t const ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS); const uint16_t buffer_size = pcd_aligned_buffer_size(largest_packet_size); - /* Create a packet memory buffer area. For isochronous endpoints, - * use the same buffer as the double buffer, essentially disabling double buffering */ - uint16_t pma_addr = dcd_pma_alloc(ep_addr, buffer_size); - - xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx; + /* Create a packet memory buffer area. Enable double buffering for devices with 2048 bytes PMA, + for smaller devices double buffering occupy too much space. */ +#if FSDEV_PMA_SIZE > 1024u + uint32_t pma_addr = dcd_pma_alloc(buffer_size, true); + uint16_t pma_addr2 = pma_addr >> 16; +#else + uint32_t pma_addr = dcd_pma_alloc(buffer_size, true); + uint16_t pma_addr2 = pma_addr; +#endif + pcd_set_ep_tx_address(USB, ep_idx, pma_addr); + pcd_set_ep_rx_address(USB, ep_idx, pma_addr2); pcd_set_eptype(USB, ep_idx, USB_EP_ISOCHRONOUS); - *pcd_ep_tx_address_ptr(USB, ep_idx) = pma_addr; - *pcd_ep_rx_address_ptr(USB, ep_idx) = pma_addr; + xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx; return true; } -bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc) { (void)rhport; - uint8_t const ep_idx = xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->ep_idx; - uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); + uint8_t const ep_addr = p_endpoint_desc->bEndpointAddress; + uint8_t const ep_idx = xfer_ctl_ptr(ep_addr)->ep_idx; + uint8_t const dir = tu_edpt_dir(ep_addr); const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc); - const uint16_t buffer_size = pcd_aligned_buffer_size(packet_size); - /* Disable endpoint */ - if(dir == TUSB_DIR_IN) - { - pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); - } - else - { - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); - } + pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); - pcd_set_ep_address(USB, ep_idx, tu_edpt_number(p_endpoint_desc->bEndpointAddress)); - // Be normal, for now, instead of only accepting zero-byte packets (on control endpoint) - // or being double-buffered (bulk endpoints) - pcd_clear_ep_kind(USB,0); + pcd_set_ep_address(USB, ep_idx, tu_edpt_number(ep_addr)); - pcd_set_ep_tx_bufsize(USB, ep_idx, buffer_size); - pcd_set_ep_rx_bufsize(USB, ep_idx, buffer_size); pcd_clear_tx_dtog(USB, ep_idx); pcd_clear_rx_dtog(USB, ep_idx); - xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->max_packet_size = packet_size; + if (dir == TUSB_DIR_IN) { + pcd_rx_dtog(USB, ep_idx); + } else { + pcd_tx_dtog(USB, ep_idx); + } + + xfer_ctl_ptr(ep_addr)->max_packet_size = packet_size; return true; } // Currently, single-buffered, and only 64 bytes at a time (max) -static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix) +static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) { uint16_t len = (uint16_t)(xfer->total_len - xfer->queued_len); - - if(len > xfer->max_packet_size) // max packet size for FS transfer - { + if (len > xfer->max_packet_size) { len = xfer->max_packet_size; } uint16_t ep_reg = pcd_get_endpoint(USB, ep_ix); - uint16_t addr_ptr = *pcd_ep_tx_address_ptr(USB,ep_ix); + bool const is_iso = (ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS; + uint16_t addr_ptr; - if (xfer->ff) - { - dcd_write_packet_memory_ff(xfer->ff, addr_ptr, len); - } - else - { - dcd_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len); + if (is_iso) { + if (ep_reg & USB_EP_DTOG_TX) { + addr_ptr = pcd_get_ep_dbuf1_address(USB, ep_ix); + pcd_set_ep_tx_dbuf1_cnt(USB, ep_ix, len); + } else { + addr_ptr = pcd_get_ep_dbuf0_address(USB, ep_ix); + pcd_set_ep_tx_dbuf0_cnt(USB, ep_ix, len); + } + } else { + addr_ptr = pcd_get_ep_tx_address(USB, ep_ix); + pcd_set_ep_tx_cnt(USB, ep_ix, len); } - xfer->queued_len = (uint16_t)(xfer->queued_len + len); - /* Write into correct register when ISOCHRONOUS (double buffered) */ - if ( (ep_reg & USB_EP_DTOG_TX) && ( (ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) ) { - pcd_set_ep_rx_cnt(USB, ep_ix, len); + if (xfer->ff) { + dcd_write_packet_memory_ff(xfer->ff, addr_ptr, len); } else { - pcd_set_ep_tx_cnt(USB, ep_ix, len); + dcd_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len); } + xfer->queued_len = (uint16_t)(xfer->queued_len + len); + dcd_int_disable(0); pcd_set_ep_tx_status(USB, ep_ix, USB_EP_TX_VALID); + if (is_iso) { + xfer->iso_in_sending = true; + } + dcd_int_enable(0); } -bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +static bool edpt_xfer(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; + (void)rhport; - xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); uint8_t const ep_idx = xfer->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); - xfer->buffer = buffer; - xfer->ff = NULL; - xfer->total_len = total_bytes; - xfer->queued_len = 0; - - if ( dir == TUSB_DIR_OUT ) - { + if (dir == TUSB_DIR_IN) { + dcd_transmit_packet(xfer, ep_idx); + } else { // A setup token can occur immediately after an OUT STATUS packet so make sure we have a valid // buffer for the control endpoint. - if (ep_idx == 0 && buffer == NULL) - { - xfer->buffer = (uint8_t*)_setup_packet; + if (ep_idx == 0 && xfer->buffer == NULL) { + xfer->buffer = (uint8_t *)_setup_packet; } - if(total_bytes > xfer->max_packet_size) - { - pcd_set_ep_rx_bufsize(USB,ep_idx,xfer->max_packet_size); + uint32_t cnt = (uint32_t ) tu_min16(xfer->total_len, xfer->max_packet_size); + uint16_t ep_reg = pcd_get_endpoint(USB, ep_idx); + + if ((ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) { + pcd_set_ep_rx_dbuf0_cnt(USB, ep_idx, cnt); + pcd_set_ep_rx_dbuf1_cnt(USB, ep_idx, cnt); } else { - pcd_set_ep_rx_bufsize(USB,ep_idx,total_bytes); + pcd_set_ep_rx_cnt(USB, ep_idx, cnt); } + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_VALID); } - else // IN - { - dcd_transmit_packet(xfer,ep_idx); - } + return true; } -bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) { - (void) rhport; + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); - xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); - uint8_t const epnum = xfer->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); + xfer->buffer = buffer; + xfer->ff = NULL; + xfer->total_len = total_bytes; + xfer->queued_len = 0; + return edpt_xfer(rhport, ep_addr); +} + +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes) +{ + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); xfer->buffer = NULL; - xfer->ff = ff; + xfer->ff = ff; xfer->total_len = total_bytes; xfer->queued_len = 0; - if ( dir == TUSB_DIR_OUT ) - { - if(total_bytes > xfer->max_packet_size) - { - pcd_set_ep_rx_bufsize(USB,epnum,xfer->max_packet_size); - } else { - pcd_set_ep_rx_bufsize(USB,epnum,total_bytes); - } - pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_VALID); - } - else // IN - { - dcd_transmit_packet(xfer,epnum); - } - return true; + return edpt_xfer(rhport, ep_addr); } -void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { (void)rhport; - xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); uint8_t const ep_idx = xfer->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); - if (dir == TUSB_DIR_IN) - { // IN + if (dir == TUSB_DIR_IN) { pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_STALL); - } - else - { // OUT + } else { pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_STALL); } } -void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) +void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { (void)rhport; - xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); uint8_t const ep_idx = xfer->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); - if (dir == TUSB_DIR_IN) - { // IN - if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) { + if (dir == TUSB_DIR_IN) { // IN + if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) { pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK); } /* Reset to DATA0 if clearing stall condition. */ pcd_clear_tx_dtog(USB, ep_idx); - } - else - { // OUT - if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) { + } else { // OUT + if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) { pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK); } /* Reset to DATA0 if clearing stall condition. */ @@ -1203,89 +1090,144 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) } } +#ifdef FSDEV_BUS_32BIT +static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes) +{ + const uint8_t *srcVal = src; + volatile uint32_t *dst32 = (volatile uint32_t *)(USB_PMAADDR + dst); + + for (uint32_t n = wNBytes / 4; n > 0; --n) { + *dst32++ = tu_unaligned_read32(srcVal); + srcVal += 4; + } + + wNBytes = wNBytes & 0x03; + if (wNBytes) { + uint32_t wrVal = *srcVal; + wNBytes--; + + if (wNBytes) { + wrVal |= *++srcVal << 8; + wNBytes--; + + if (wNBytes) { + wrVal |= *++srcVal << 16; + } + } + + *dst32 = wrVal; + } + + return true; +} +#else // Packet buffer access can only be 8- or 16-bit. /** - * @brief Copy a buffer from user memory area to packet memory area (PMA). - * This uses byte-access for user memory (so support non-aligned buffers) - * and 16-bit access for packet memory. - * @param dst, byte address in PMA; must be 16-bit aligned - * @param src pointer to user memory area. - * @param wPMABufAddr address into PMA. - * @param wNBytes no. of bytes to be copied. - * @retval None - */ -static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes) + * @brief Copy a buffer from user memory area to packet memory area (PMA). + * This uses byte-access for user memory (so support non-aligned buffers) + * and 16-bit access for packet memory. + * @param dst, byte address in PMA; must be 16-bit aligned + * @param src pointer to user memory area. + * @param wPMABufAddr address into PMA. + * @param wNBytes no. of bytes to be copied. + * @retval None + */ +static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes) { uint32_t n = (uint32_t)wNBytes >> 1U; uint16_t temp1, temp2; - const uint8_t * srcVal; + const uint8_t *srcVal; // The GCC optimizer will combine access to 32-bit sizes if we let it. Force // it volatile so that it won't do that. __IO uint16_t *pdwVal; srcVal = src; - pdwVal = &pma[PMA_STRIDE*(dst>>1)]; + pdwVal = &pma[FSDEV_PMA_STRIDE * (dst >> 1)]; - while (n--) - { + while (n--) { temp1 = (uint16_t)*srcVal; srcVal++; - temp2 = temp1 | ((uint16_t)(((uint16_t)(*srcVal)) << 8U)) ; + temp2 = temp1 | ((uint16_t)(((uint16_t)(*srcVal)) << 8U)); *pdwVal = temp2; - pdwVal += PMA_STRIDE; + pdwVal += FSDEV_PMA_STRIDE; srcVal++; } - if (wNBytes & 0x01) - { + if (wNBytes) { temp1 = *srcVal; *pdwVal = temp1; } return true; } +#endif /** - * @brief Copy from FIFO to packet memory area (PMA). - * Uses byte-access of system memory and 16-bit access of packet memory - * @param wNBytes no. of bytes to be copied. - * @retval None - */ -static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes) + * @brief Copy from FIFO to packet memory area (PMA). + * Uses byte-access of system memory and 16-bit access of packet memory + * @param wNBytes no. of bytes to be copied. + * @retval None + */ +static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes) { // Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies tu_fifo_buffer_info_t info; tu_fifo_get_read_info(ff, &info); - uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin); + uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin); uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap); // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part, // last lin byte will be combined with wrapped part - // To ensure PMA is always access 16bit aligned (dst aligned to 16 bit) - if((cnt_lin & 0x01) && cnt_wrap) - { + // To ensure PMA is always access aligned (dst aligned to 16 or 32 bit) +#ifdef FSDEV_BUS_32BIT + if ((cnt_lin & 0x03) && cnt_wrap) { // Copy first linear part - dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin &~0x01); - dst += cnt_lin &~0x01; + dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin & ~0x03); + dst += cnt_lin & ~0x03; + + // Copy last linear bytes & first wrapped bytes to buffer + uint32_t i; + uint8_t tmp[4]; + for (i = 0; i < (cnt_lin & 0x03); i++) { + tmp[i] = ((uint8_t *)info.ptr_lin)[(cnt_lin & ~0x03) + i]; + } + uint32_t wCnt = cnt_wrap; + for (; i < 4 && wCnt > 0; i++, wCnt--) { + tmp[i] = *(uint8_t *)info.ptr_wrap; + info.ptr_wrap = (uint8_t *)info.ptr_wrap + 1; + } + + // Write unaligned buffer + dcd_write_packet_memory(dst, &tmp, 4); + dst += 4; + + // Copy rest of wrapped byte + if (wCnt) + dcd_write_packet_memory(dst, info.ptr_wrap, wCnt); + } +#else + if ((cnt_lin & 0x01) && cnt_wrap) { + // Copy first linear part + dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin & ~0x01); + dst += cnt_lin & ~0x01; // Copy last linear byte & first wrapped byte - uint16_t tmp = ((uint8_t*)info.ptr_lin)[cnt_lin - 1] | ((uint16_t)(((uint8_t*)info.ptr_wrap)[0]) << 8U); + uint16_t tmp = ((uint8_t *)info.ptr_lin)[cnt_lin - 1] | ((uint16_t)(((uint8_t *)info.ptr_wrap)[0]) << 8U); dcd_write_packet_memory(dst, &tmp, 2); dst += 2; // Copy rest of wrapped byte - dcd_write_packet_memory(dst, ((uint8_t*)info.ptr_wrap) + 1, cnt_wrap - 1); + dcd_write_packet_memory(dst, ((uint8_t *)info.ptr_wrap) + 1, cnt_wrap - 1); } - else - { +#endif + else { // Copy linear part dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin); dst += info.len_lin; - if(info.len_wrap) - { + if (info.len_wrap) { // Copy wrapped byte dcd_write_packet_memory(dst, info.ptr_wrap, cnt_wrap); } @@ -1296,13 +1238,44 @@ static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wN return true; } +#ifdef FSDEV_BUS_32BIT +static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes) +{ + uint8_t *dstVal = dst; + volatile uint32_t *src32 = (volatile uint32_t *)(USB_PMAADDR + src); + + for (uint32_t n = wNBytes / 4; n > 0; --n) { + tu_unaligned_write32(dstVal, *src32++); + dstVal += 4; + } + + wNBytes = wNBytes & 0x03; + if (wNBytes) { + uint32_t rdVal = *src32; + + *dstVal = tu_u32_byte0(rdVal); + wNBytes--; + + if (wNBytes) { + *++dstVal = tu_u32_byte1(rdVal); + wNBytes--; + + if (wNBytes) { + *++dstVal = tu_u32_byte2(rdVal); + } + } + } + + return true; +} +#else /** - * @brief Copy a buffer from packet memory area (PMA) to user memory area. - * Uses byte-access of system memory and 16-bit access of packet memory - * @param wNBytes no. of bytes to be copied. - * @retval None - */ -static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes) + * @brief Copy a buffer from packet memory area (PMA) to user memory area. + * Uses byte-access of system memory and 16-bit access of packet memory + * @param wNBytes no. of bytes to be copied. + * @retval None + */ +static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes) { uint32_t n = (uint32_t)wNBytes >> 1U; // The GCC optimizer will combine access to 32-bit sizes if we let it. Force @@ -1310,70 +1283,93 @@ static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wN __IO const uint16_t *pdwVal; uint32_t temp; - pdwVal = &pma[PMA_STRIDE*(src>>1)]; - uint8_t *dstVal = (uint8_t*)dst; + pdwVal = &pma[FSDEV_PMA_STRIDE * (src >> 1)]; + uint8_t *dstVal = (uint8_t *)dst; - while (n--) - { + while (n--) { temp = *pdwVal; - pdwVal += PMA_STRIDE; + pdwVal += FSDEV_PMA_STRIDE; *dstVal++ = ((temp >> 0) & 0xFF); *dstVal++ = ((temp >> 8) & 0xFF); } - if (wNBytes & 0x01) - { + if (wNBytes & 0x01) { temp = *pdwVal; - pdwVal += PMA_STRIDE; + pdwVal += FSDEV_PMA_STRIDE; *dstVal++ = ((temp >> 0) & 0xFF); } return true; } +#endif /** - * @brief Copy a buffer from user packet memory area (PMA) to FIFO. - * Uses byte-access of system memory and 16-bit access of packet memory - * @param wNBytes no. of bytes to be copied. - * @retval None - */ -static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes) + * @brief Copy a buffer from user packet memory area (PMA) to FIFO. + * Uses byte-access of system memory and 16-bit access of packet memory + * @param wNBytes no. of bytes to be copied. + * @retval None + */ +static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes) { // Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies // Check for first linear part tu_fifo_buffer_info_t info; - tu_fifo_get_write_info(ff, &info); // We want to read from the FIFO + tu_fifo_get_write_info(ff, &info); // We want to read from the FIFO - uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin); + uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin); uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap); // We want to read from PMA and write it into the FIFO, if LIN part is ODD and has WRAPPED part, // last lin byte will be combined with wrapped part - // To ensure PMA is always access 16bit aligned (src aligned to 16 bit) - if((cnt_lin & 0x01) && cnt_wrap) - { + // To ensure PMA is always access aligned (src aligned to 16 or 32 bit) +#ifdef FSDEV_BUS_32BIT + if ((cnt_lin & 0x03) && cnt_wrap) { // Copy first linear part - dcd_read_packet_memory(info.ptr_lin, src, cnt_lin &~0x01); - src += cnt_lin &~0x01; + dcd_read_packet_memory(info.ptr_lin, src, cnt_lin & ~0x03); + src += cnt_lin & ~0x03; - // Copy last linear byte & first wrapped byte - uint16_t tmp; - dcd_read_packet_memory(&tmp, src, 2); + // Copy last linear bytes & first wrapped bytes + uint8_t tmp[4]; + dcd_read_packet_memory(tmp, src, 4); + src += 4; + + uint32_t i; + for (i = 0; i < (cnt_lin & 0x03); i++) { + ((uint8_t *)info.ptr_lin)[(cnt_lin & ~0x03) + i] = tmp[i]; + } + uint32_t wCnt = cnt_wrap; + for (; i < 4 && wCnt > 0; i++, wCnt--) { + *(uint8_t *)info.ptr_wrap = tmp[i]; + info.ptr_wrap = (uint8_t *)info.ptr_wrap + 1; + } - ((uint8_t*)info.ptr_lin)[cnt_lin - 1] = (uint8_t)tmp; - ((uint8_t*)info.ptr_wrap)[0] = (uint8_t)(tmp >> 8U); + // Copy rest of wrapped byte + if (wCnt) + dcd_read_packet_memory(info.ptr_wrap, src, wCnt); + } +#else + if ((cnt_lin & 0x01) && cnt_wrap) { + // Copy first linear part + dcd_read_packet_memory(info.ptr_lin, src, cnt_lin & ~0x01); + src += cnt_lin & ~0x01; + + // Copy last linear byte & first wrapped byte + uint8_t tmp[2]; + dcd_read_packet_memory(tmp, src, 2); src += 2; + ((uint8_t *)info.ptr_lin)[cnt_lin - 1] = tmp[0]; + ((uint8_t *)info.ptr_wrap)[0] = tmp[1]; + // Copy rest of wrapped byte - dcd_read_packet_memory(((uint8_t*)info.ptr_wrap) + 1, src, cnt_wrap - 1); + dcd_read_packet_memory(((uint8_t *)info.ptr_wrap) + 1, src, cnt_wrap - 1); } - else - { +#endif + else { // Copy linear part dcd_read_packet_memory(info.ptr_lin, src, cnt_lin); src += cnt_lin; - if(info.len_wrap) - { + if (info.len_wrap) { // Copy wrapped byte dcd_read_packet_memory(info.ptr_wrap, src, cnt_wrap); } diff --git a/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h b/test-devices/composite-stm32/lib/tinyusb/portable/st/stm32_fsdev/dcd_stm32_fsdev.h similarity index 53% rename from test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h rename to test-devices/composite-stm32/lib/tinyusb/portable/st/stm32_fsdev/dcd_stm32_fsdev.h index e3fc8aeb..7992f34a 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h +++ b/test-devices/composite-stm32/lib/tinyusb/portable/st/stm32_fsdev/dcd_stm32_fsdev.h @@ -1,34 +1,36 @@ -/** - * Copyright(c) 2016 STMicroelectronics - * Copyright(c) N Conrad - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ +/* + * Copyright(c) 2016 STMicroelectronics + * Copyright(c) N Conrad + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the TinyUSB stack. + */ // This file contains source copied from ST's HAL, and thus should have their copyright statement. -// PMA_LENGTH is PMA buffer size in bytes. +// FSDEV_PMA_SIZE is PMA buffer size in bytes. // On 512-byte devices, access with a stride of two words (use every other 16-bit address) // On 1024-byte devices, access with a stride of one word (use every 16-bit address) @@ -37,7 +39,7 @@ #if CFG_TUSB_MCU == OPT_MCU_STM32F0 #include "stm32f0xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) // F0x2 models are crystal-less // All have internal D+ pull-up // 070RB: 2 x 16 bits/word memory LPM Support, BCD Support @@ -45,7 +47,7 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32F1 #include "stm32f1xx.h" - #define PMA_LENGTH (512u) + #define FSDEV_PMA_SIZE (512u) // NO internal Pull-ups // *B, and *C: 2 x 16 bits/word @@ -56,7 +58,7 @@ defined(STM32F303xB) || defined(STM32F303xC) || \ defined(STM32F373xC) #include "stm32f3xx.h" - #define PMA_LENGTH (512u) + #define FSDEV_PMA_SIZE (512u) // NO internal Pull-ups // *B, and *C: 1 x 16 bits/word // PMA dedicated to USB (no sharing with CAN) @@ -65,37 +67,98 @@ defined(STM32F302xD) || defined(STM32F302xE) || \ defined(STM32F303xD) || defined(STM32F303xE) #include "stm32f3xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) // NO internal Pull-ups // *6, *8, *D, and *E: 2 x 16 bits/word LPM Support // When CAN clock is enabled, USB can use first 768 bytes ONLY. #elif CFG_TUSB_MCU == OPT_MCU_STM32L0 #include "stm32l0xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) #elif CFG_TUSB_MCU == OPT_MCU_STM32L1 #include "stm32l1xx.h" - #define PMA_LENGTH (512u) + #define FSDEV_PMA_SIZE (512u) #elif CFG_TUSB_MCU == OPT_MCU_STM32G4 #include "stm32g4xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) + +#elif CFG_TUSB_MCU == OPT_MCU_STM32G0 + #include "stm32g0xx.h" + #define FSDEV_BUS_32BIT + #define FSDEV_PMA_SIZE (2048u) + #undef USB_PMAADDR + #define USB_PMAADDR USB_DRD_PMAADDR + #define USB_TypeDef USB_DRD_TypeDef + #define EP0R CHEP0R + #define USB_EP_CTR_RX USB_EP_VTRX + #define USB_EP_CTR_TX USB_EP_VTTX + #define USB_EP_T_FIELD USB_CHEP_UTYPE + #define USB_EPREG_MASK USB_CHEP_REG_MASK + #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK + #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK + #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1 + #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2 + #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1 + #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 + #define USB_EPRX_STAT USB_CH_RX_VALID + #define USB_EPKIND_MASK USB_EP_KIND_MASK + #define USB USB_DRD_FS + #define USB_CNTR_FRES USB_CNTR_USBRST + #define USB_CNTR_RESUME USB_CNTR_L2RES + #define USB_ISTR_EP_ID USB_ISTR_IDN + #define USB_EPADDR_FIELD USB_CHEP_ADDR + #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY + #define USB_CNTR_FSUSP USB_CNTR_SUSPEN + +#elif CFG_TUSB_MCU == OPT_MCU_STM32H5 + #include "stm32h5xx.h" + #define FSDEV_BUS_32BIT + + #if !defined(USB_DRD_BASE) && defined(USB_DRD_FS_BASE) + #define USB_DRD_BASE USB_DRD_FS_BASE + #endif + + #define FSDEV_PMA_SIZE (2048u) + #undef USB_PMAADDR + #define USB_PMAADDR USB_DRD_PMAADDR + #define USB_TypeDef USB_DRD_TypeDef + #define EP0R CHEP0R + #define USB_EP_CTR_RX USB_EP_VTRX + #define USB_EP_CTR_TX USB_EP_VTTX + #define USB_EP_T_FIELD USB_CHEP_UTYPE + #define USB_EPREG_MASK USB_CHEP_REG_MASK + #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK + #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK + #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1 + #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2 + #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1 + #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 + #define USB_EPRX_STAT USB_CH_RX_VALID + #define USB_EPKIND_MASK USB_EP_KIND_MASK + #define USB USB_DRD_FS + #define USB_CNTR_FRES USB_CNTR_USBRST + #define USB_CNTR_RESUME USB_CNTR_L2RES + #define USB_ISTR_EP_ID USB_ISTR_IDN + #define USB_EPADDR_FIELD USB_CHEP_ADDR + #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY + #define USB_CNTR_FSUSP USB_CNTR_SUSPEN #elif CFG_TUSB_MCU == OPT_MCU_STM32WB #include "stm32wbxx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) /* ST provided header has incorrect value */ #undef USB_PMAADDR #define USB_PMAADDR USB1_PMAADDR #elif CFG_TUSB_MCU == OPT_MCU_STM32L4 #include "stm32l4xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) #elif CFG_TUSB_MCU == OPT_MCU_STM32L5 #include "stm32l5xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) #ifndef USB_PMAADDR #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS)) @@ -107,25 +170,41 @@ #endif // For purposes of accessing the packet -#if ((PMA_LENGTH) == 512u) - #define PMA_STRIDE (2u) -#elif ((PMA_LENGTH) == 1024u) - #define PMA_STRIDE (1u) +#if ((FSDEV_PMA_SIZE) == 512u) + #define FSDEV_PMA_STRIDE (2u) +#elif ((FSDEV_PMA_SIZE) == 1024u) + #define FSDEV_PMA_STRIDE (1u) #endif -// And for type-safety create a new macro for the volatile address of PMAADDR +// The fsdev_bus_t type can be used for both register and PMA access necessities +// For type-safety create a new macro for the volatile address of PMAADDR // The compiler should warn us if we cast it to a non-volatile type? +#ifdef FSDEV_BUS_32BIT +typedef uint32_t fsdev_bus_t; +static __IO uint32_t * const pma32 = (__IO uint32_t*)USB_PMAADDR; + +#else +typedef uint16_t fsdev_bus_t; // Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden) static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR; -// prototypes -TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx); -TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx); -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue); +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) { + size_t total_word_offset = (((USBx)->BTABLE)>>1) + x; + total_word_offset *= FSDEV_PMA_STRIDE; + return &(pma[total_word_offset]); +} + +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { + return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 1u); +} + +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { + return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 3u); +} +#endif /* Aligned buffer size according to hardware */ -TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t size) -{ +TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t size) { /* The STM32 full speed USB peripheral supports only a limited set of * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */ uint16_t blocksize = (size > 62) ? 32 : 2; @@ -136,21 +215,28 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t si return numblocks * blocksize; } -/* SetENDPOINT */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + __O uint32_t *reg = (__O uint32_t *)(USB_DRD_BASE + bEpIdx*4); + *reg = wRegValue; +#else __O uint16_t *reg = (__O uint16_t *)((&USBx->EP0R) + bEpIdx*2u); *reg = (uint16_t)wRegValue; +#endif } -/* GetENDPOINT */ -TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx) { +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + __I uint32_t *reg = (__I uint32_t *)(USB_DRD_BASE + bEpIdx*4); +#else __I uint16_t *reg = (__I uint16_t *)((&USBx->EP0R) + bEpIdx*2u); +#endif return *reg; } -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wType) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wType) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= (uint32_t)USB_EP_T_MASK; regVal |= wType; @@ -158,20 +244,19 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint pcd_set_endpoint(USBx, bEpIdx, regVal); } -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EP_T_FIELD; return regVal; } + /** * @brief Clears bit CTR_RX / CTR_TX in the endpoint register. * @param USBx USB peripheral instance register address. * @param bEpIdx Endpoint Number. * @retval None */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal &= ~USB_EP_CTR_RX; @@ -179,51 +264,42 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, pcd_set_endpoint(USBx, bEpIdx, regVal); } -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal &= ~USB_EP_CTR_TX; regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0) pcd_set_endpoint(USBx, bEpIdx,regVal); } + /** * @brief gets counter of the tx buffer. * @param USBx USB peripheral instance register address. * @param bEpIdx Endpoint Number. * @retval Counter value */ -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + return (pma32[2*bEpIdx] & 0x03FF0000) >> 16; +#else __I uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpIdx); return *regPtr & 0x3ffU; +#endif } -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + return (pma32[2*bEpIdx + 1] & 0x03FF0000) >> 16; +#else __I uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpIdx); return *regPtr & 0x3ffU; +#endif } -/** - * @brief Sets counter of rx buffer with no. of blocks. - * @param dwReg Register - * @param wCount Counter. - * @param wNBlocks no. of Blocks. - * @retval None - */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_cnt_reg(__O uint16_t * pdwReg, size_t wCount) -{ - /* We assume that the buffer size is already aligned to hardware requirements. */ - uint16_t blocksize = (wCount > 62) ? 1 : 0; - uint16_t numblocks = wCount / (blocksize ? 32 : 2); - - /* There should be no remainder in the above calculation */ - TU_ASSERT((wCount - (numblocks * (blocksize ? 32 : 2))) == 0, /**/); - - /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ - *pdwReg = (blocksize << 15) | ((numblocks - blocksize) << 10); -} +#define pcd_get_ep_dbuf0_cnt pcd_get_ep_tx_cnt +#define pcd_get_ep_dbuf1_cnt pcd_get_ep_rx_cnt /** * @brief Sets address in an endpoint register. @@ -232,8 +308,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_cnt_reg(__O uint16_t * pdwRe * @param bAddr Address. * @retval None */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t bAddr) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t bAddr) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal |= bAddr; @@ -241,59 +316,106 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, pcd_set_endpoint(USBx, bEpIdx,regVal); } -TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) -{ - size_t total_word_offset = (((USBx)->BTABLE)>>1) + x; - total_word_offset *= PMA_STRIDE; - return &(pma[total_word_offset]); +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + return pma32[2*bEpIdx] & 0x0000FFFFu ; +#else + return *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 0u); +#endif } -// Pointers to the PMA table entries (using the ARM address space) -TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_address_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) -{ - return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 0u); -} -TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) -{ - return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 1u); +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + return pma32[2*bEpIdx + 1] & 0x0000FFFFu; +#else + return *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 2u); +#endif } -TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_address_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) -{ - return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 2u); +#define pcd_get_ep_dbuf0_address pcd_get_ep_tx_address +#define pcd_get_ep_dbuf1_address pcd_get_ep_rx_address + +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + pma32[2*bEpIdx] = (pma32[2*bEpIdx] & 0xFFFF0000u) | (addr & 0x0000FFFCu); +#else + *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 0u) = addr; +#endif } -TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) -{ - return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 3u); +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & 0xFFFF0000u) | (addr & 0x0000FFFCu); +#else + *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 2u) = addr; +#endif } -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) -{ +#define pcd_set_ep_dbuf0_address pcd_set_ep_tx_address +#define pcd_set_ep_dbuf1_address pcd_set_ep_rx_address + +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + pma32[2*bEpIdx] = (pma32[2*bEpIdx] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16); +#else __IO uint16_t * reg = pcd_ep_tx_cnt_ptr(USBx, bEpIdx); *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU); +#endif } -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) -{ +#define pcd_set_ep_tx_dbuf0_cnt pcd_set_ep_tx_cnt + +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_dbuf1_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16); +#else __IO uint16_t * reg = pcd_ep_rx_cnt_ptr(USBx, bEpIdx); *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU); +#endif } -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) -{ - __IO uint16_t *pdwReg = pcd_ep_tx_cnt_ptr((USBx),(bEpIdx)); - wCount = pcd_aligned_buffer_size(wCount); - pcd_set_ep_cnt_reg(pdwReg, wCount); +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDef * USBx, uint32_t rxtx_idx, + uint32_t blocksize, uint32_t numblocks) { + /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ +#ifdef FSDEV_BUS_32BIT + (void) USBx; + pma32[rxtx_idx] = (pma32[rxtx_idx] & 0x0000FFFFu) | (blocksize << 31) | ((numblocks - blocksize) << 26); +#else + __IO uint16_t *pdwReg = pcd_btable_word_ptr(USBx, rxtx_idx*2u + 1u); + *pdwReg = (blocksize << 15) | ((numblocks - blocksize) << 10); +#endif } -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) -{ - __IO uint16_t *pdwReg = pcd_ep_rx_cnt_ptr((USBx),(bEpIdx)); +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_bufsize(USB_TypeDef * USBx, uint32_t rxtx_idx, uint32_t wCount) { wCount = pcd_aligned_buffer_size(wCount); - pcd_set_ep_cnt_reg(pdwReg, wCount); + + /* We assume that the buffer size is already aligned to hardware requirements. */ + uint16_t blocksize = (wCount > 62) ? 1 : 0; + uint16_t numblocks = wCount / (blocksize ? 32 : 2); + + /* There should be no remainder in the above calculation */ + TU_ASSERT((wCount - (numblocks * (blocksize ? 32 : 2))) == 0, /**/); + + /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ + pcd_set_ep_blsize_num_blocks(USBx, rxtx_idx, blocksize, numblocks); +} + +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_dbuf0_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { + pcd_set_ep_bufsize(USBx, 2*bEpIdx, wCount); +} + +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { + pcd_set_ep_bufsize(USBx, 2*bEpIdx + 1, wCount); } +#define pcd_set_ep_rx_dbuf1_cnt pcd_set_ep_rx_cnt + /** * @brief sets the status for tx transfer (bits STAT_TX[1:0]). * @param USBx USB peripheral instance register address. @@ -301,8 +423,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_bufsize(USB_TypeDef * USB * @param wState new state * @retval None */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPTX_DTOGMASK; @@ -319,7 +440,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; pcd_set_endpoint(USBx, bEpIdx, regVal); -} /* pcd_set_ep_tx_status */ +} /** * @brief sets the status for rx transfer (bits STAT_TX[1:0]) @@ -329,31 +450,27 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx * @retval None */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPRX_DTOGMASK; /* toggle first bit ? */ - if((USB_EPRX_DTOG1 & wState)!= 0U) - { + if((USB_EPRX_DTOG1 & wState)!= 0U) { regVal ^= USB_EPRX_DTOG1; } /* toggle second bit ? */ - if((USB_EPRX_DTOG2 & wState)!= 0U) - { + if((USB_EPRX_DTOG2 & wState)!= 0U) { regVal ^= USB_EPRX_DTOG2; } regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; pcd_set_endpoint(USBx, bEpIdx, regVal); -} /* pcd_set_ep_rx_status */ +} -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); return (regVal & USB_EPRX_STAT) >> (12u); -} /* pcd_get_ep_rx_status */ +} /** @@ -362,16 +479,14 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * * @param bEpIdx Endpoint Number. * @retval None */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_RX; pcd_set_endpoint(USBx, bEpIdx, regVal); } -TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_TX; @@ -384,21 +499,16 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32 * @param bEpIdx Endpoint Number. * @retval None */ - -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - if((regVal & USB_EP_DTOG_RX) != 0) - { + if((regVal & USB_EP_DTOG_RX) != 0) { pcd_rx_dtog(USBx,bEpIdx); } } -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - if((regVal & USB_EP_DTOG_TX) != 0) - { + if((regVal & USB_EP_DTOG_TX) != 0) { pcd_tx_dtog(USBx,bEpIdx); } } @@ -409,17 +519,15 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, * @param bEpIdx Endpoint Number. * @retval None */ - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal |= USB_EP_KIND; regVal &= USB_EPREG_MASK; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; pcd_set_endpoint(USBx, bEpIdx, regVal); } -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) -{ + +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPKIND_MASK; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dcd_dwc2.c b/test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dcd_dwc2.c similarity index 61% rename from test-devices/composite-stm32/lib/tinyusb/dwc2/dcd_dwc2.c rename to test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dcd_dwc2.c index 22c82201..692096fc 100644 --- a/test-devices/composite-stm32/lib/tinyusb/dwc2/dcd_dwc2.c +++ b/test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dcd_dwc2.c @@ -82,8 +82,8 @@ static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2]; typedef struct { - uint8_t * buffer; - tu_fifo_t * ff; + uint8_t* buffer; + tu_fifo_t* ff; uint16_t total_len; uint16_t max_size; uint8_t interval; @@ -93,45 +93,182 @@ static xfer_ctl_t xfer_status[DWC2_EP_MAX][2]; #define XFER_CTL_BASE(_ep, _dir) (&xfer_status[_ep][_dir]) // EP0 transfers are limited to 1 packet - larger sizes has to be split -static uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type +static uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type // TX FIFO RAM allocation so far in words - RX FIFO size is readily available from dwc2->grxfsiz -static uint16_t _allocated_fifo_words_tx; // TX FIFO size in words (IN EPs) -static bool _out_ep_closed; // Flag to check if RX FIFO size needs an update (reduce its size) +static uint16_t _allocated_fifo_words_tx; // TX FIFO size in words (IN EPs) // SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by static bool _sof_en; -// Calculate the RX FIFO size according to recommendations from reference manual -static inline uint16_t calc_grxfsiz(uint16_t max_ep_size, uint8_t ep_count) -{ - return 15 + 2*(max_ep_size/4) + 2*ep_count; +// Calculate the RX FIFO size according to minimum recommendations from reference manual +// RxFIFO = (5 * number of control endpoints + 8) + +// ((largest USB packet used / 4) + 1 for status information) + +// (2 * number of OUT endpoints) + 1 for Global NAK +// with number of control endpoints = 1 we have +// RxFIFO = 15 + (largest USB packet used / 4) + 2 * number of OUT endpoints +// we double the largest USB packet size to be able to hold up to 2 packets +static inline uint16_t calc_grxfsiz(uint16_t max_ep_size, uint8_t ep_count) { + return 15 + 2 * (max_ep_size / 4) + 2 * ep_count; } -static void update_grxfsiz(uint8_t rhport) -{ - dwc2_regs_t * dwc2 = DWC2_REG(rhport); +TU_ATTR_ALWAYS_INLINE static inline void fifo_flush_tx(dwc2_regs_t* dwc2, uint8_t epnum) { + // flush TX fifo and wait for it cleared + dwc2->grstctl = GRSTCTL_TXFFLSH | (epnum << GRSTCTL_TXFNUM_Pos); + while (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) {} +} +TU_ATTR_ALWAYS_INLINE static inline void fifo_flush_rx(dwc2_regs_t* dwc2) { + // flush RX fifo and wait for it cleared + dwc2->grstctl = GRSTCTL_RXFFLSH; + while (dwc2->grstctl & GRSTCTL_RXFFLSH_Msk) {} +} + +static bool fifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + TU_ASSERT(epnum < ep_count); + + uint16_t fifo_size = tu_div_ceil(packet_size, 4); + + // "USB Data FIFOs" section in reference manual + // Peripheral FIFO architecture + // + // --------------- 320 or 1024 ( 1280 or 4096 bytes ) + // | IN FIFO 0 | + // --------------- (320 or 1024) - 16 + // | IN FIFO 1 | + // --------------- (320 or 1024) - 16 - x + // | . . . . | + // --------------- (320 or 1024) - 16 - x - y - ... - z + // | IN FIFO MAX | + // --------------- + // | FREE | + // --------------- GRXFSIZ + // | OUT FIFO | + // | ( Shared ) | + // --------------- 0 + // + // In FIFO is allocated by following rules: + // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n". + if (dir == TUSB_DIR_OUT) { + // Calculate required size of RX FIFO + uint16_t const sz = calc_grxfsiz(4 * fifo_size, ep_count); + + // If size_rx needs to be extended check if possible and if so enlarge it + if (dwc2->grxfsiz < sz) { + TU_ASSERT(sz + _allocated_fifo_words_tx <= _dwc2_controller[rhport].ep_fifo_size / 4); - // Determine largest EP size for RX FIFO - uint16_t max_epsize = 0; - for (uint8_t epnum = 0; epnum < ep_count; epnum++) - { - max_epsize = tu_max16(max_epsize, xfer_status[epnum][TUSB_DIR_OUT].max_size); + // Enlarge RX FIFO + dwc2->grxfsiz = sz; + } + } else { + // Note if The TXFELVL is configured as half empty. In order + // to be able to write a packet at that point, the fifo must be twice the max_size. + if ((dwc2->gahbcfg & GAHBCFG_TXFELVL) == 0) { + fifo_size *= 2; + } + + // Check if free space is available + TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= _dwc2_controller[rhport].ep_fifo_size / 4); + _allocated_fifo_words_tx += fifo_size; + TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %" PRIu32, fifo_size * 4, + _dwc2_controller[rhport].ep_fifo_size - _allocated_fifo_words_tx * 4); + + // DIEPTXF starts at FIFO #1. + // Both TXFD and TXSA are in unit of 32-bit words. + dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | + (_dwc2_controller[rhport].ep_fifo_size / 4 - _allocated_fifo_words_tx); } - // Update size of RX FIFO - dwc2->grxfsiz = calc_grxfsiz(max_epsize, ep_count); + return true; +} + +static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); + uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); + + xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir); + xfer->max_size = tu_edpt_packet_size(p_endpoint_desc); + xfer->interval = p_endpoint_desc->bInterval; + + // USBAEP, EPTYP, SD0PID_SEVNFRM, MPSIZ are the same for IN and OUT endpoints. + uint32_t const dxepctl = (1 << DOEPCTL_USBAEP_Pos) | + (p_endpoint_desc->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) | + (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) | + (xfer->max_size << DOEPCTL_MPSIZ_Pos); + + if (dir == TUSB_DIR_OUT) { + dwc2->epout[epnum].doepctl = dxepctl; + dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum); + } else { + dwc2->epin[epnum].diepctl = dxepctl | (epnum << DIEPCTL_TXFNUM_Pos); + dwc2->daintmsk |= (1 << (DAINTMSK_IEPM_Pos + epnum)); + } +} + +static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) { + (void) rhport; + + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + if (dir == TUSB_DIR_IN) { + dwc2_epin_t* epin = dwc2->epin; + + // Only disable currently enabled non-control endpoint + if ((epnum == 0) || !(epin[epnum].diepctl & DIEPCTL_EPENA)) { + epin[epnum].diepctl |= DIEPCTL_SNAK | (stall ? DIEPCTL_STALL : 0); + } else { + // Stop transmitting packets and NAK IN xfers. + epin[epnum].diepctl |= DIEPCTL_SNAK; + while ((epin[epnum].diepint & DIEPINT_INEPNE) == 0) {} + + // Disable the endpoint. + epin[epnum].diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0); + while ((epin[epnum].diepint & DIEPINT_EPDISD_Msk) == 0) {} + + epin[epnum].diepint = DIEPINT_EPDISD; + } + + // Flush the FIFO, and wait until we have confirmed it cleared. + fifo_flush_tx(dwc2, epnum); + } else { + dwc2_epout_t* epout = dwc2->epout; + + // Only disable currently enabled non-control endpoint + if ((epnum == 0) || !(epout[epnum].doepctl & DOEPCTL_EPENA)) { + epout[epnum].doepctl |= stall ? DOEPCTL_STALL : 0; + } else { + // Asserting GONAK is required to STALL an OUT endpoint. + // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt + // anyway, and it can't be cleared by user code. If this while loop never + // finishes, we have bigger problems than just the stack. + dwc2->dctl |= DCTL_SGONAK; + while ((dwc2->gintsts & GINTSTS_BOUTNAKEFF_Msk) == 0) {} + + // Ditto here- disable the endpoint. + epout[epnum].doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0); + while ((epout[epnum].doepint & DOEPINT_EPDISD_Msk) == 0) {} + + epout[epnum].doepint = DOEPINT_EPDISD; + + // Allow other OUT endpoints to keep receiving. + dwc2->dctl |= DCTL_CGONAK; + } + } } // Start of Bus Reset -static void bus_reset(uint8_t rhport) -{ - dwc2_regs_t * dwc2 = DWC2_REG(rhport); +static void bus_reset(uint8_t rhport) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint8_t const ep_count = _dwc2_controller[rhport].ep_count; tu_memclr(xfer_status, sizeof(xfer_status)); - _out_ep_closed = false; _sof_en = false; @@ -139,15 +276,24 @@ static void bus_reset(uint8_t rhport) dwc2->dcfg &= ~DCFG_DAD_Msk; // 1. NAK for all OUT endpoints - for ( uint8_t n = 0; n < ep_count; n++ ) - { + for (uint8_t n = 0; n < ep_count; n++) { dwc2->epout[n].doepctl |= DOEPCTL_SNAK; } - // 2. Set up interrupt mask + // 2. Disable all IN endpoints + for (uint8_t n = 0; n < ep_count; n++) { + if (dwc2->epin[n].diepctl & DIEPCTL_EPENA) { + dwc2->epin[n].diepctl |= DIEPCTL_SNAK | DIEPCTL_EPDIS; + } + } + + fifo_flush_tx(dwc2, 0x10); // all tx fifo + fifo_flush_rx(dwc2); + + // 3. Set up interrupt mask dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos); - dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM; - dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM; + dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM; + dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM; // "USB Data FIFOs" section in reference manual // Peripheral FIFO architecture @@ -206,36 +352,34 @@ static void bus_reset(uint8_t rhport) _allocated_fifo_words_tx = 16; // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word ) - dwc2->dieptxf0 = (16 << DIEPTXF0_TX0FD_Pos) | (_dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx); + dwc2->dieptxf0 = (16 << DIEPTXF0_TX0FD_Pos) | (_dwc2_controller[rhport].ep_fifo_size / 4 - _allocated_fifo_words_tx); // Fixed control EP0 size to 64 bytes dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos); xfer_status[0][TUSB_DIR_OUT].max_size = 64; - xfer_status[0][TUSB_DIR_IN ].max_size = 64; + xfer_status[0][TUSB_DIR_IN].max_size = 64; dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); dwc2->gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT; } -static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets, uint16_t total_bytes) -{ +static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets, + uint16_t total_bytes) { (void) rhport; - dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2_regs_t* dwc2 = DWC2_REG(rhport); // EP0 is limited to one packet each xfer // We use multiple transaction of xfer->max_size length to get a whole transfer done - if ( epnum == 0 ) - { - xfer_ctl_t *const xfer = XFER_CTL_BASE(epnum, dir); + if (epnum == 0) { + xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir); total_bytes = tu_min16(ep0_pending[dir], xfer->max_size); ep0_pending[dir] -= total_bytes; } // IN and OUT endpoint xfers are interrupt-driven, we just schedule them here. - if ( dir == TUSB_DIR_IN ) - { + if (dir == TUSB_DIR_IN) { dwc2_epin_t* epin = dwc2->epin; // A full IN transfer (multiple packets, possibly) triggers XFRC. @@ -245,20 +389,16 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c epin[epnum].diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK; // For ISO endpoint set correct odd/even bit for next frame. - if ( (epin[epnum].diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1 ) - { + if ((epin[epnum].diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1) { // Take odd/even bit from frame counter. uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); epin[epnum].diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk); } // Enable fifo empty interrupt only if there are something to put in the fifo. - if ( total_bytes != 0 ) - { + if (total_bytes != 0) { dwc2->diepempmsk |= (1 << epnum); } - } - else - { + } else { dwc2_epout_t* epout = dwc2->epout; // A full OUT transfer (multiple packets, possibly) triggers XFRC. @@ -267,9 +407,8 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c ((total_bytes << DOEPTSIZ_XFRSIZ_Pos) & DOEPTSIZ_XFRSIZ_Msk); epout[epnum].doepctl |= DOEPCTL_EPENA | DOEPCTL_CNAK; - if ( (epout[epnum].doepctl & DOEPCTL_EPTYP) == DOEPCTL_EPTYP_0 && - XFER_CTL_BASE(epnum, dir)->interval == 1 ) - { + if ((epout[epnum].doepctl & DOEPCTL_EPTYP) == DOEPCTL_EPTYP_0 && + XFER_CTL_BASE(epnum, dir)->interval == 1) { // Take odd/even bit from frame counter. uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); epout[epnum].doepctl |= (odd_frame_now ? DOEPCTL_SD0PID_SEVNFRM_Msk : DOEPCTL_SODDFRM_Msk); @@ -281,103 +420,46 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c /* Controller API *------------------------------------------------------------------*/ #if CFG_TUSB_DEBUG >= DWC2_DEBUG -void print_dwc2_info(dwc2_regs_t * dwc2) -{ - dwc2_ghwcfg2_t const * hw_cfg2 = &dwc2->ghwcfg2_bm; - dwc2_ghwcfg3_t const * hw_cfg3 = &dwc2->ghwcfg3_bm; - dwc2_ghwcfg4_t const * hw_cfg4 = &dwc2->ghwcfg4_bm; - -// TU_LOG_HEX(DWC2_DEBUG, dwc2->gotgctl); -// TU_LOG_HEX(DWC2_DEBUG, dwc2->gusbcfg); -// TU_LOG_HEX(DWC2_DEBUG, dwc2->dcfg); - TU_LOG_HEX(DWC2_DEBUG, dwc2->guid); - TU_LOG_HEX(DWC2_DEBUG, dwc2->gsnpsid); - TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg1); - - // HW configure 2 - TU_LOG(DWC2_DEBUG, "\r\n"); - TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg2); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->op_mode ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->arch ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->point2point ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->hs_phy_type ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->fs_phy_type ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->num_dev_ep ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->num_host_ch ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->period_channel_support ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->enable_dynamic_fifo ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->mul_cpu_int ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->nperiod_tx_q_depth ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->host_period_tx_q_depth ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->dev_token_q_depth ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->otg_enable_ic_usb ); - - // HW configure 3 - TU_LOG(DWC2_DEBUG, "\r\n"); - TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg3); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->xfer_size_width ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->packet_size_width ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_enable ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->i2c_enable ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->vendor_ctrl_itf ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->optional_feature_removed ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->synch_reset ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_adp_support ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_enable_hsic ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->battery_charger_support ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->lpm_mode ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->total_fifo_size ); - - // HW configure 4 - TU_LOG(DWC2_DEBUG, "\r\n"); - TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg4); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->num_dev_period_in_ep ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->power_optimized ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->ahb_freq_min ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->hibernation ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->service_interval_mode ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->ipg_isoc_en ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->acg_enable ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->utmi_phy_data_width ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dev_ctrl_ep_num ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->iddg_filter_enabled ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->vbus_valid_filter_enabled ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->a_valid_filter_enabled ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->b_valid_filter_enabled ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dedicated_fifos ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->num_dev_in_eps ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dma_desc_enable ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dma_dynamic ); +void print_dwc2_info(dwc2_regs_t* dwc2) { + // print guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4 + // use dwc2_info.py/md for bit-field value and comparison with other ports + volatile uint32_t const* p = (volatile uint32_t const*) &dwc2->guid; + TU_LOG(DWC2_DEBUG, "guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4\r\n"); + for (size_t i = 0; i < 5; i++) { + TU_LOG(DWC2_DEBUG, "0x%08" PRIX32 ", ", p[i]); + } + TU_LOG(DWC2_DEBUG, "0x%08" PRIX32 "\r\n", p[5]); } #endif -static void reset_core(dwc2_regs_t * dwc2) -{ +static void reset_core(dwc2_regs_t* dwc2) { // reset core dwc2->grstctl |= GRSTCTL_CSRST; // wait for reset bit is cleared // TODO version 4.20a should wait for RESET DONE mask - while (dwc2->grstctl & GRSTCTL_CSRST) { } + while (dwc2->grstctl & GRSTCTL_CSRST) {} // wait for AHB master IDLE - while ( !(dwc2->grstctl & GRSTCTL_AHBIDL) ) { } + while (!(dwc2->grstctl & GRSTCTL_AHBIDL)) {} // wait for device mode ? } -static bool phy_hs_supported(dwc2_regs_t * dwc2) -{ - // note: esp32 incorrect report its hs_phy_type as utmi +static bool phy_hs_supported(dwc2_regs_t* dwc2) { + (void) dwc2; + #if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + // note: esp32 incorrect report its hs_phy_type as utmi + return false; +#elif !TUD_OPT_HIGH_SPEED return false; #else - return TUD_OPT_HIGH_SPEED && dwc2->ghwcfg2_bm.hs_phy_type != HS_PHY_TYPE_NONE; + return dwc2->ghwcfg2_bm.hs_phy_type != HS_PHY_TYPE_NONE; #endif } -static void phy_fs_init(dwc2_regs_t * dwc2) -{ +static void phy_fs_init(dwc2_regs_t* dwc2) { TU_LOG(DWC2_DEBUG, "Fullspeed PHY init\r\n"); // Select FS PHY @@ -401,15 +483,13 @@ static void phy_fs_init(dwc2_regs_t * dwc2) dwc2->dcfg = (dwc2->dcfg & ~DCFG_DSPD_Msk) | (DCFG_DSPD_FS << DCFG_DSPD_Pos); } -static void phy_hs_init(dwc2_regs_t * dwc2) -{ +static void phy_hs_init(dwc2_regs_t* dwc2) { uint32_t gusbcfg = dwc2->gusbcfg; // De-select FS PHY gusbcfg &= ~GUSBCFG_PHYSEL; - if (dwc2->ghwcfg2_bm.hs_phy_type == HS_PHY_TYPE_ULPI) - { + if (dwc2->ghwcfg2_bm.hs_phy_type == HS_PHY_TYPE_ULPI) { TU_LOG(DWC2_DEBUG, "Highspeed ULPI PHY init\r\n"); // Select ULPI @@ -423,8 +503,7 @@ static void phy_hs_init(dwc2_regs_t * dwc2) // Disable FS/LS ULPI gusbcfg &= ~(GUSBCFG_ULPIFSLS | GUSBCFG_ULPICSM); - }else - { + } else { TU_LOG(DWC2_DEBUG, "Highspeed UTMI+ PHY init\r\n"); // Select UTMI+ with 8-bit interface @@ -465,8 +544,7 @@ static void phy_hs_init(dwc2_regs_t * dwc2) dwc2->dcfg = dcfg; } -static bool check_dwc2(dwc2_regs_t * dwc2) -{ +static bool check_dwc2(dwc2_regs_t* dwc2) { #if CFG_TUSB_DEBUG >= DWC2_DEBUG print_dwc2_info(dwc2); #endif @@ -481,41 +559,35 @@ static bool check_dwc2(dwc2_regs_t * dwc2) return true; } -void dcd_init (uint8_t rhport) -{ +void dcd_init(uint8_t rhport) { // Programming model begins in the last section of the chapter on the USB // peripheral in each Reference Manual. - dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2_regs_t* dwc2 = DWC2_REG(rhport); // Check Synopsys ID register, failed if controller clock/power is not enabled - TU_VERIFY(check_dwc2(dwc2), ); - + if (!check_dwc2(dwc2)) return; dcd_disconnect(rhport); // max number of endpoints & total_fifo_size are: // hw_cfg2->num_dev_ep, hw_cfg2->total_fifo_size - if( phy_hs_supported(dwc2) ) - { - // Highspeed - phy_hs_init(dwc2); - }else - { - // core does not support highspeed or hs-phy is not present - phy_fs_init(dwc2); + if (phy_hs_supported(dwc2)) { + phy_hs_init(dwc2); // Highspeed + } else { + phy_fs_init(dwc2); // core does not support highspeed or hs phy is not present } // Restart PHY clock dwc2->pcgctl &= ~(PCGCTL_STOPPCLK | PCGCTL_GATEHCLK | PCGCTL_PWRCLMP | PCGCTL_RSTPDWNMODULE); - /* Set HS/FS Timeout Calibration to 7 (max available value). - * The number of PHY clocks that the application programs in - * this field is added to the high/full speed interpacket timeout - * duration in the core to account for any additional delays - * introduced by the PHY. This can be required, because the delay - * introduced by the PHY in generating the linestate condition - * can vary from one PHY to another. - */ + /* Set HS/FS Timeout Calibration to 7 (max available value). + * The number of PHY clocks that the application programs in + * this field is added to the high/full speed interpacket timeout + * duration in the core to account for any additional delays + * introduced by the PHY. This can be required, because the delay + * introduced by the PHY in generating the linestate condition + * can vary from one PHY to another. + */ dwc2->gusbcfg |= (7ul << GUSBCFG_TOCAL_Pos); // Force device mode @@ -528,6 +600,9 @@ void dcd_init (uint8_t rhport) // (non zero-length packet), send STALL back and discard. dwc2->dcfg |= DCFG_NZLSOHSK; + fifo_flush_tx(dwc2, 0x10); // all tx fifo + fifo_flush_rx(dwc2); + // Clear all interrupts uint32_t int_mask = dwc2->gintsts; dwc2->gintsts |= int_mask; @@ -535,11 +610,12 @@ void dcd_init (uint8_t rhport) dwc2->gotgint |= int_mask; // Required as part of core initialization. - // TODO: How should mode mismatch be handled? It will cause - // the core to stop working/require reset. - dwc2->gintmsk = GINTMSK_OTGINT | GINTMSK_MMISM | GINTMSK_RXFLVLM | + dwc2->gintmsk = GINTMSK_OTGINT | GINTMSK_RXFLVLM | GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM; + // Configure TX FIFO empty level for interrupt. Default is complete empty + dwc2->gahbcfg |= GAHBCFG_TXFELVL; + // Enable global interrupt dwc2->gahbcfg |= GAHBCFG_GINT; @@ -554,30 +630,26 @@ void dcd_init (uint8_t rhport) dcd_connect(rhport); } -void dcd_int_enable (uint8_t rhport) -{ +void dcd_int_enable(uint8_t rhport) { dwc2_dcd_int_enable(rhport); } -void dcd_int_disable (uint8_t rhport) -{ +void dcd_int_disable(uint8_t rhport) { dwc2_dcd_int_disable(rhport); } -void dcd_set_address (uint8_t rhport, uint8_t dev_addr) -{ - dwc2_regs_t * dwc2 = DWC2_REG(rhport); +void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); dwc2->dcfg = (dwc2->dcfg & ~DCFG_DAD_Msk) | (dev_addr << DCFG_DAD_Pos); // Response with status after changing device address dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); } -void dcd_remote_wakeup(uint8_t rhport) -{ +void dcd_remote_wakeup(uint8_t rhport) { (void) rhport; - dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2_regs_t* dwc2 = DWC2_REG(rhport); // set remote wakeup dwc2->dctl |= DCTL_RWUSIG; @@ -592,35 +664,29 @@ void dcd_remote_wakeup(uint8_t rhport) dwc2->dctl &= ~DCTL_RWUSIG; } -void dcd_connect(uint8_t rhport) -{ +void dcd_connect(uint8_t rhport) { (void) rhport; - dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2_regs_t* dwc2 = DWC2_REG(rhport); dwc2->dctl &= ~DCTL_SDIS; } -void dcd_disconnect(uint8_t rhport) -{ +void dcd_disconnect(uint8_t rhport) { (void) rhport; - dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2_regs_t* dwc2 = DWC2_REG(rhport); dwc2->dctl |= DCTL_SDIS; } // Be advised: audio, video and possibly other iso-ep classes use dcd_sof_enable() to enable/disable its corresponding ISR on purpose! -void dcd_sof_enable(uint8_t rhport, bool en) -{ +void dcd_sof_enable(uint8_t rhport, bool en) { (void) rhport; - dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2_regs_t* dwc2 = DWC2_REG(rhport); _sof_en = en; - if (en) - { + if (en) { dwc2->gintsts = GINTSTS_SOF; dwc2->gintmsk |= GINTMSK_SOFM; - } - else - { + } else { dwc2->gintmsk &= ~GINTMSK_SOFM; } } @@ -629,140 +695,78 @@ void dcd_sof_enable(uint8_t rhport, bool en) /* DCD Endpoint port *------------------------------------------------------------------*/ -bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) -{ - (void) rhport; - - dwc2_regs_t * dwc2 = DWC2_REG(rhport); - uint8_t const ep_count = _dwc2_controller[rhport].ep_count; - - uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress); - uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress); - - TU_ASSERT(epnum < ep_count); - - xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); - xfer->max_size = tu_edpt_packet_size(desc_edpt); - xfer->interval = desc_edpt->bInterval; - - uint16_t const fifo_size = tu_div_ceil(xfer->max_size, 4); - - if(dir == TUSB_DIR_OUT) - { - // Calculate required size of RX FIFO - uint16_t const sz = calc_grxfsiz(4*fifo_size, ep_count); - - // If size_rx needs to be extended check if possible and if so enlarge it - if (dwc2->grxfsiz < sz) - { - TU_ASSERT(sz + _allocated_fifo_words_tx <= _dwc2_controller[rhport].ep_fifo_size/4); - - // Enlarge RX FIFO - dwc2->grxfsiz = sz; - } - - dwc2->epout[epnum].doepctl |= (1 << DOEPCTL_USBAEP_Pos) | - (desc_edpt->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) | - (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) | - (xfer->max_size << DOEPCTL_MPSIZ_Pos); - - dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum); - } - else - { - // "USB Data FIFOs" section in reference manual - // Peripheral FIFO architecture - // - // --------------- 320 or 1024 ( 1280 or 4096 bytes ) - // | IN FIFO 0 | - // --------------- (320 or 1024) - 16 - // | IN FIFO 1 | - // --------------- (320 or 1024) - 16 - x - // | . . . . | - // --------------- (320 or 1024) - 16 - x - y - ... - z - // | IN FIFO MAX | - // --------------- - // | FREE | - // --------------- GRXFSIZ - // | OUT FIFO | - // | ( Shared ) | - // --------------- 0 - // - // In FIFO is allocated by following rules: - // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n". - - // Check if free space is available - TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= _dwc2_controller[rhport].ep_fifo_size/4); - - _allocated_fifo_words_tx += fifo_size; - - TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %lu", fifo_size*4, _dwc2_controller[rhport].ep_fifo_size-_allocated_fifo_words_tx*4); - - // DIEPTXF starts at FIFO #1. - // Both TXFD and TXSA are in unit of 32-bit words. - dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | (_dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx); - - dwc2->epin[epnum].diepctl |= (1 << DIEPCTL_USBAEP_Pos) | - (epnum << DIEPCTL_TXFNUM_Pos) | - (desc_edpt->bmAttributes.xfer << DIEPCTL_EPTYP_Pos) | - (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DIEPCTL_SD0PID_SEVNFRM : 0) | - (xfer->max_size << DIEPCTL_MPSIZ_Pos); - - dwc2->daintmsk |= (1 << (DAINTMSK_IEPM_Pos + epnum)); - } - +bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { + TU_ASSERT(fifo_alloc(rhport, desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt))); + edpt_activate(rhport, desc_edpt); return true; } // Close all non-control endpoints, cancel all pending transfers if any. -void dcd_edpt_close_all (uint8_t rhport) -{ - dwc2_regs_t * dwc2 = DWC2_REG(rhport); +void dcd_edpt_close_all(uint8_t rhport) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint8_t const ep_count = _dwc2_controller[rhport].ep_count; // Disable non-control interrupt dwc2->daintmsk = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos); - for(uint8_t n = 1; n < ep_count; n++) - { + for (uint8_t n = 1; n < ep_count; n++) { // disable OUT endpoint - dwc2->epout[n].doepctl = 0; + if (dwc2->epout[n].doepctl & DOEPCTL_EPENA) { + dwc2->epout[n].doepctl |= DOEPCTL_SNAK | DOEPCTL_EPDIS; + } xfer_status[n][TUSB_DIR_OUT].max_size = 0; // disable IN endpoint - dwc2->epin[n].diepctl = 0; + if (dwc2->epin[n].diepctl & DIEPCTL_EPENA) { + dwc2->epin[n].diepctl |= DIEPCTL_SNAK | DIEPCTL_EPDIS; + } xfer_status[n][TUSB_DIR_IN].max_size = 0; } + // reset allocated fifo OUT + dwc2->grxfsiz = calc_grxfsiz(64, ep_count); // reset allocated fifo IN _allocated_fifo_words_tx = 16; + + fifo_flush_tx(dwc2, 0x10); // all tx fifo + fifo_flush_rx(dwc2); +} + +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + TU_ASSERT(fifo_alloc(rhport, ep_addr, largest_packet_size)); + return true; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) { + // Disable EP to clear potential incomplete transfers + edpt_disable(rhport, p_endpoint_desc->bEndpointAddress, false); + + edpt_activate(rhport, p_endpoint_desc); + + return true; } -bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) -{ +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); - xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); - xfer->buffer = buffer; - xfer->ff = NULL; - xfer->total_len = total_bytes; + xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir); + xfer->buffer = buffer; + xfer->ff = NULL; + xfer->total_len = total_bytes; // EP0 can only handle one packet - if(epnum == 0) - { + if (epnum == 0) { ep0_pending[dir] = total_bytes; // Schedule the first transaction for EP0 transfer edpt_schedule_packets(rhport, epnum, dir, 1, ep0_pending[dir]); - } - else - { + } else { uint16_t num_packets = (total_bytes / xfer->max_size); uint16_t const short_packet_size = total_bytes % xfer->max_size; // Zero-size packet is special case. - if ( (short_packet_size > 0) || (total_bytes == 0) ) num_packets++; + if ((short_packet_size > 0) || (total_bytes == 0)) num_packets++; // Schedule packets to be sent within interrupt edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes); @@ -775,24 +779,23 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t // bytes should be written and second to keep the return value free to give back a boolean // success message. If total_bytes is too big, the FIFO will copy only what is available // into the USB buffer! -bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) -{ +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t total_bytes) { // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1 TU_ASSERT(ff->item_size == 1); uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); - xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); - xfer->buffer = NULL; - xfer->ff = ff; - xfer->total_len = total_bytes; + xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir); + xfer->buffer = NULL; + xfer->ff = ff; + xfer->total_len = total_bytes; uint16_t num_packets = (total_bytes / xfer->max_size); uint16_t const short_packet_size = total_bytes % xfer->max_size; // Zero-size packet is special case. - if ( short_packet_size > 0 || (total_bytes == 0) ) num_packets++; + if (short_packet_size > 0 || (total_bytes == 0)) num_packets++; // Schedule packets to be sent within interrupt edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes); @@ -800,123 +803,27 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 return true; } -static void dcd_edpt_disable (uint8_t rhport, uint8_t ep_addr, bool stall) -{ - (void) rhport; - - dwc2_regs_t *dwc2 = DWC2_REG(rhport); - - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - - if ( dir == TUSB_DIR_IN ) - { - dwc2_epin_t* epin = dwc2->epin; - - // Only disable currently enabled non-control endpoint - if ( (epnum == 0) || !(epin[epnum].diepctl & DIEPCTL_EPENA) ) - { - epin[epnum].diepctl |= DIEPCTL_SNAK | (stall ? DIEPCTL_STALL : 0); - } - else - { - // Stop transmitting packets and NAK IN xfers. - epin[epnum].diepctl |= DIEPCTL_SNAK; - while ( (epin[epnum].diepint & DIEPINT_INEPNE) == 0 ) {} - - // Disable the endpoint. - epin[epnum].diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0); - while ( (epin[epnum].diepint & DIEPINT_EPDISD_Msk) == 0 ) {} - - epin[epnum].diepint = DIEPINT_EPDISD; - } - - // Flush the FIFO, and wait until we have confirmed it cleared. - dwc2->grstctl = ((epnum << GRSTCTL_TXFNUM_Pos) | GRSTCTL_TXFFLSH); - while ( (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) != 0 ) {} - } - else - { - dwc2_epout_t* epout = dwc2->epout; - - // Only disable currently enabled non-control endpoint - if ( (epnum == 0) || !(epout[epnum].doepctl & DOEPCTL_EPENA) ) - { - epout[epnum].doepctl |= stall ? DOEPCTL_STALL : 0; - } - else - { - // Asserting GONAK is required to STALL an OUT endpoint. - // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt - // anyway, and it can't be cleared by user code. If this while loop never - // finishes, we have bigger problems than just the stack. - dwc2->dctl |= DCTL_SGONAK; - while ( (dwc2->gintsts & GINTSTS_BOUTNAKEFF_Msk) == 0 ) {} - - // Ditto here- disable the endpoint. - epout[epnum].doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0); - while ( (epout[epnum].doepint & DOEPINT_EPDISD_Msk) == 0 ) {} - - epout[epnum].doepint = DOEPINT_EPDISD; - - // Allow other OUT endpoints to keep receiving. - dwc2->dctl |= DCTL_CGONAK; - } - } +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { + edpt_disable(rhport, ep_addr, false); } -/** - * Close an endpoint. - */ -void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) -{ - dwc2_regs_t * dwc2 = DWC2_REG(rhport); - - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - - dcd_edpt_disable(rhport, ep_addr, false); - - // Update max_size - xfer_status[epnum][dir].max_size = 0; // max_size = 0 marks a disabled EP - required for changing FIFO allocation - - if (dir == TUSB_DIR_IN) - { - uint16_t const fifo_size = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXFD_Msk) >> DIEPTXF_INEPTXFD_Pos; - uint16_t const fifo_start = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXSA_Msk) >> DIEPTXF_INEPTXSA_Pos; - - // For now only the last opened endpoint can be closed without fuss. - TU_ASSERT(fifo_start == _dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx,); - _allocated_fifo_words_tx -= fifo_size; - } - else - { - _out_ep_closed = true; // Set flag such that RX FIFO gets reduced in size once RX FIFO is empty - } +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { + edpt_disable(rhport, ep_addr, true); } -void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) -{ - dcd_edpt_disable(rhport, ep_addr, true); -} - -void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) -{ +void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { (void) rhport; - dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); // Clear stall and reset data toggle - if ( dir == TUSB_DIR_IN ) - { + if (dir == TUSB_DIR_IN) { dwc2->epin[epnum].diepctl &= ~DIEPCTL_STALL; dwc2->epin[epnum].diepctl |= DIEPCTL_SD0PID_SEVNFRM; - } - else - { + } else { dwc2->epout[epnum].doepctl &= ~DOEPCTL_STALL; dwc2->epout[epnum].doepctl |= DOEPCTL_SD0PID_SEVNFRM; } @@ -925,70 +832,63 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) /*------------------------------------------------------------------*/ // Read a single data packet from receive FIFO -static void read_fifo_packet(uint8_t rhport, uint8_t * dst, uint16_t len) -{ +static void read_fifo_packet(uint8_t rhport, uint8_t* dst, uint16_t len) { (void) rhport; - dwc2_regs_t * dwc2 = DWC2_REG(rhport); - volatile const uint32_t * rx_fifo = dwc2->fifo[0]; + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + volatile const uint32_t* rx_fifo = dwc2->fifo[0]; // Reading full available 32 bit words from fifo uint16_t full_words = len >> 2; - while(full_words--) - { + while (full_words--) { tu_unaligned_write32(dst, *rx_fifo); dst += 4; } // Read the remaining 1-3 bytes from fifo uint8_t const bytes_rem = len & 0x03; - if ( bytes_rem != 0 ) - { + if (bytes_rem != 0) { uint32_t const tmp = *rx_fifo; dst[0] = tu_u32_byte0(tmp); - if ( bytes_rem > 1 ) dst[1] = tu_u32_byte1(tmp); - if ( bytes_rem > 2 ) dst[2] = tu_u32_byte2(tmp); + if (bytes_rem > 1) dst[1] = tu_u32_byte1(tmp); + if (bytes_rem > 2) dst[2] = tu_u32_byte2(tmp); } } // Write a single data packet to EPIN FIFO -static void write_fifo_packet(uint8_t rhport, uint8_t fifo_num, uint8_t const * src, uint16_t len) -{ +static void write_fifo_packet(uint8_t rhport, uint8_t fifo_num, uint8_t const* src, uint16_t len) { (void) rhport; - dwc2_regs_t * dwc2 = DWC2_REG(rhport); - volatile uint32_t * tx_fifo = dwc2->fifo[fifo_num]; + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + volatile uint32_t* tx_fifo = dwc2->fifo[fifo_num]; // Pushing full available 32 bit words to fifo uint16_t full_words = len >> 2; - while(full_words--) - { + while (full_words--) { *tx_fifo = tu_unaligned_read32(src); src += 4; } // Write the remaining 1-3 bytes into fifo uint8_t const bytes_rem = len & 0x03; - if ( bytes_rem ) - { + if (bytes_rem) { uint32_t tmp_word = src[0]; - if ( bytes_rem > 1 ) tmp_word |= (src[1] << 8); - if ( bytes_rem > 2 ) tmp_word |= (src[2] << 16); + if (bytes_rem > 1) tmp_word |= (src[1] << 8); + if (bytes_rem > 2) tmp_word |= (src[2] << 16); *tx_fifo = tmp_word; } } -static void handle_rxflvl_irq(uint8_t rhport) -{ - dwc2_regs_t * dwc2 = DWC2_REG(rhport); - volatile uint32_t const * rx_fifo = dwc2->fifo[0]; +static void handle_rxflvl_irq(uint8_t rhport) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + volatile uint32_t const* rx_fifo = dwc2->fifo[0]; // Pop control word off FIFO uint32_t const ctl_word = dwc2->grxstsp; - uint8_t const pktsts = (ctl_word & GRXSTSP_PKTSTS_Msk ) >> GRXSTSP_PKTSTS_Pos; - uint8_t const epnum = (ctl_word & GRXSTSP_EPNUM_Msk ) >> GRXSTSP_EPNUM_Pos; - uint16_t const bcnt = (ctl_word & GRXSTSP_BCNT_Msk ) >> GRXSTSP_BCNT_Pos; + uint8_t const pktsts = (ctl_word & GRXSTSP_PKTSTS_Msk) >> GRXSTSP_PKTSTS_Pos; + uint8_t const epnum = (ctl_word & GRXSTSP_EPNUM_Msk) >> GRXSTSP_EPNUM_Pos; + uint16_t const bcnt = (ctl_word & GRXSTSP_BCNT_Msk) >> GRXSTSP_BCNT_Pos; dwc2_epout_t* epout = &dwc2->epout[epnum]; @@ -1003,10 +903,10 @@ static void handle_rxflvl_irq(uint8_t rhport) // TU_LOG(DWC2_DEBUG, " daint = %08lX, doepint = %04X\r\n", (unsigned long) dwc2->daint, (unsigned int) epout->doepint); //#endif - switch ( pktsts ) - { + switch (pktsts) { // Global OUT NAK: do nothing - case GRXSTS_PKTSTS_GLOBALOUTNAK: break; + case GRXSTS_PKTSTS_GLOBALOUTNAK: + break; case GRXSTS_PKTSTS_SETUPRX: // Setup packet received @@ -1015,26 +915,22 @@ static void handle_rxflvl_irq(uint8_t rhport) // only the last one is valid. _setup_packet[0] = (*rx_fifo); _setup_packet[1] = (*rx_fifo); - break; + break; case GRXSTS_PKTSTS_SETUPDONE: // Setup packet done (Interrupt) epout->doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); - break; + break; - case GRXSTS_PKTSTS_OUTRX: - { + case GRXSTS_PKTSTS_OUTRX: { // Out packet received - xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); + xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); // Read packet off RxFIFO - if ( xfer->ff ) - { + if (xfer->ff) { // Ring buffer tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void*) (uintptr_t) rx_fifo, bcnt); - } - else - { + } else { // Linear buffer read_fifo_packet(rhport, xfer->buffer, bcnt); @@ -1043,73 +939,64 @@ static void handle_rxflvl_irq(uint8_t rhport) } // Truncate transfer length in case of short packet - if ( bcnt < xfer->max_size ) - { + if (bcnt < xfer->max_size) { xfer->total_len -= (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos; - if ( epnum == 0 ) - { + if (epnum == 0) { xfer->total_len -= ep0_pending[TUSB_DIR_OUT]; ep0_pending[TUSB_DIR_OUT] = 0; } } } - break; + break; - // Out packet done (Interrupt) + // Out packet done (Interrupt) case GRXSTS_PKTSTS_OUTDONE: - // Occurred on STM32L47 with dwc2 version 3.10a but not found on other version like 2.80a or 3.30a - // May (or not) be 3.10a specific feature/bug or depending on MCU configuration - // XFRC complete is additionally generated when - // - setup packet is received - // - complete the data stage of control write is complete - if ((epnum == 0) && (bcnt == 0) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) - { - uint32_t doepint = epout->doepint; - - if (doepint & (DOEPINT_STPKTRX | DOEPINT_OTEPSPR)) - { - // skip this "no-data" transfer complete event - // Note: STPKTRX will be clear later by setup received handler - uint32_t clear_flags = DOEPINT_XFRC; - - if (doepint & DOEPINT_OTEPSPR) clear_flags |= DOEPINT_OTEPSPR; - - epout->doepint = clear_flags; - - // TU_LOG(DWC2_DEBUG, " FIX extra transfer complete on setup/data compete\r\n"); - } + // Occurred on STM32L47 with dwc2 version 3.10a but not found on other version like 2.80a or 3.30a + // May (or not) be 3.10a specific feature/bug or depending on MCU configuration + // XFRC complete is additionally generated when + // - setup packet is received + // - complete the data stage of control write is complete + if ((epnum == 0) && (bcnt == 0) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) { + uint32_t doepint = epout->doepint; + + if (doepint & (DOEPINT_STPKTRX | DOEPINT_OTEPSPR)) { + // skip this "no-data" transfer complete event + // Note: STPKTRX will be clear later by setup received handler + uint32_t clear_flags = DOEPINT_XFRC; + + if (doepint & DOEPINT_OTEPSPR) clear_flags |= DOEPINT_OTEPSPR; + + epout->doepint = clear_flags; + + // TU_LOG(DWC2_DEBUG, " FIX extra transfer complete on setup/data compete\r\n"); } - break; + } + break; default: // Invalid TU_BREAKPOINT(); - break; + break; } } -static void handle_epout_irq (uint8_t rhport) -{ - dwc2_regs_t * dwc2 = DWC2_REG(rhport); +static void handle_epout_irq(uint8_t rhport) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint8_t const ep_count = _dwc2_controller[rhport].ep_count; // DAINT for a given EP clears when DOEPINTx is cleared. // OEPINT will be cleared when DAINT's out bits are cleared. - for ( uint8_t n = 0; n < ep_count; n++ ) - { - if ( dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + n) ) - { + for (uint8_t n = 0; n < ep_count; n++) { + if (dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + n)) { dwc2_epout_t* epout = &dwc2->epout[n]; uint32_t const doepint = epout->doepint; // SETUP packet Setup Phase done. - if ( doepint & DOEPINT_STUP ) - { + if (doepint & DOEPINT_STUP) { uint32_t clear_flag = DOEPINT_STUP; // STPKTRX is only available for version from 3_00a - if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) - { + if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) { clear_flag |= DOEPINT_STPKTRX; } @@ -1118,20 +1005,16 @@ static void handle_epout_irq (uint8_t rhport) } // OUT XFER complete - if ( epout->doepint & DOEPINT_XFRC ) - { + if (epout->doepint & DOEPINT_XFRC) { epout->doepint = DOEPINT_XFRC; - xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT); + xfer_ctl_t* xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT); // EP0 can only handle one packet - if ( (n == 0) && ep0_pending[TUSB_DIR_OUT] ) - { + if ((n == 0) && ep0_pending[TUSB_DIR_OUT]) { // Schedule another packet to be received. edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); - } - else - { + } else { dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true); } } @@ -1139,40 +1022,32 @@ static void handle_epout_irq (uint8_t rhport) } } -static void handle_epin_irq (uint8_t rhport) -{ - dwc2_regs_t * dwc2 = DWC2_REG(rhport); +static void handle_epin_irq(uint8_t rhport) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint8_t const ep_count = _dwc2_controller[rhport].ep_count; - dwc2_epin_t* epin = dwc2->epin; + dwc2_epin_t* epin = dwc2->epin; // DAINT for a given EP clears when DIEPINTx is cleared. // IEPINT will be cleared when DAINT's out bits are cleared. - for ( uint8_t n = 0; n < ep_count; n++ ) - { - if ( dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + n) ) - { + for (uint8_t n = 0; n < ep_count; n++) { + if (dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + n)) { // IN XFER complete (entire xfer). - xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_IN); + xfer_ctl_t* xfer = XFER_CTL_BASE(n, TUSB_DIR_IN); - if ( epin[n].diepint & DIEPINT_XFRC ) - { + if (epin[n].diepint & DIEPINT_XFRC) { epin[n].diepint = DIEPINT_XFRC; // EP0 can only handle one packet - if ( (n == 0) && ep0_pending[TUSB_DIR_IN] ) - { + if ((n == 0) && ep0_pending[TUSB_DIR_IN]) { // Schedule another packet to be transmitted. edpt_schedule_packets(rhport, n, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]); - } - else - { + } else { dcd_event_xfer_complete(rhport, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); } } // XFER FIFO empty - if ( (epin[n].diepint & DIEPINT_TXFE) && (dwc2->diepempmsk & (1 << n)) ) - { + if ((epin[n].diepint & DIEPINT_TXFE) && (dwc2->diepempmsk & (1 << n))) { // diepint's TXFE bit is read-only, software cannot clear it. // It will only be cleared by hardware when written bytes is more than // - 64 bytes or @@ -1181,8 +1056,7 @@ static void handle_epin_irq (uint8_t rhport) uint16_t remaining_packets = (epin[n].dieptsiz & DIEPTSIZ_PKTCNT_Msk) >> DIEPTSIZ_PKTCNT_Pos; // Process every single packet (only whole packets can be written to fifo) - for ( uint16_t i = 0; i < remaining_packets; i++ ) - { + for (uint16_t i = 0; i < remaining_packets; i++) { uint16_t const remaining_bytes = (epin[n].dieptsiz & DIEPTSIZ_XFRSIZ_Msk) >> DIEPTSIZ_XFRSIZ_Pos; // Packet can not be larger than ep max size @@ -1190,16 +1064,13 @@ static void handle_epin_irq (uint8_t rhport) // It's only possible to write full packets into FIFO. Therefore DTXFSTS register of current // EP has to be checked if the buffer can take another WHOLE packet - if ( packet_size > ((epin[n].dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2) ) break; + if (packet_size > ((epin[n].dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2)) break; // Push packet to Tx-FIFO - if ( xfer->ff ) - { - volatile uint32_t *tx_fifo = dwc2->fifo[n]; + if (xfer->ff) { + volatile uint32_t* tx_fifo = dwc2->fifo[n]; tu_fifo_read_n_const_addr_full_words(xfer->ff, (void*) (uintptr_t) tx_fifo, packet_size); - } - else - { + } else { write_fifo_packet(rhport, n, xfer->buffer, packet_size); // Increment pointer to xfer data @@ -1208,8 +1079,7 @@ static void handle_epin_irq (uint8_t rhport) } // Turn off TXFE if all bytes are written. - if ( ((epin[n].dieptsiz & DIEPTSIZ_XFRSIZ_Msk) >> DIEPTSIZ_XFRSIZ_Pos) == 0 ) - { + if (((epin[n].dieptsiz & DIEPTSIZ_XFRSIZ_Msk) >> DIEPTSIZ_XFRSIZ_Pos) == 0) { dwc2->diepempmsk &= ~(1 << n); } } @@ -1217,55 +1087,50 @@ static void handle_epin_irq (uint8_t rhport) } } -void dcd_int_handler(uint8_t rhport) -{ - dwc2_regs_t *dwc2 = DWC2_REG(rhport); +void dcd_int_handler(uint8_t rhport) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint32_t const int_mask = dwc2->gintmsk; uint32_t const int_status = dwc2->gintsts & int_mask; - if(int_status & GINTSTS_USBRST) - { + if (int_status & GINTSTS_USBRST) { // USBRST is start of reset. dwc2->gintsts = GINTSTS_USBRST; bus_reset(rhport); } - if(int_status & GINTSTS_ENUMDNE) - { + if (int_status & GINTSTS_ENUMDNE) { // ENUMDNE is the end of reset where speed of the link is detected - dwc2->gintsts = GINTSTS_ENUMDNE; tusb_speed_t speed; - switch ((dwc2->dsts & DSTS_ENUMSPD_Msk) >> DSTS_ENUMSPD_Pos) - { + switch ((dwc2->dsts & DSTS_ENUMSPD_Msk) >> DSTS_ENUMSPD_Pos) { case DSTS_ENUMSPD_HS: speed = TUSB_SPEED_HIGH; - break; + break; case DSTS_ENUMSPD_LS: speed = TUSB_SPEED_LOW; - break; + break; case DSTS_ENUMSPD_FS_HSPHY: case DSTS_ENUMSPD_FS: default: speed = TUSB_SPEED_FULL; - break; + break; } + // TODO must update GUSBCFG_TRDT according to link speed + dcd_event_bus_reset(rhport, speed, true); } - if(int_status & GINTSTS_USBSUSP) - { + if (int_status & GINTSTS_USBSUSP) { dwc2->gintsts = GINTSTS_USBSUSP; dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); } - if(int_status & GINTSTS_WKUINT) - { + if (int_status & GINTSTS_WKUINT) { dwc2->gintsts = GINTSTS_WKUINT; dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); } @@ -1273,73 +1138,52 @@ void dcd_int_handler(uint8_t rhport) // TODO check GINTSTS_DISCINT for disconnect detection // if(int_status & GINTSTS_DISCINT) - if(int_status & GINTSTS_OTGINT) - { + if (int_status & GINTSTS_OTGINT) { // OTG INT bit is read-only uint32_t const otg_int = dwc2->gotgint; - if (otg_int & GOTGINT_SEDET) - { + if (otg_int & GOTGINT_SEDET) { dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); } dwc2->gotgint = otg_int; } - if(int_status & GINTSTS_SOF) - { - dwc2->gotgint = GINTSTS_SOF; + if(int_status & GINTSTS_SOF) { + dwc2->gintsts = GINTSTS_SOF; + const uint32_t frame = (dwc2->dsts & DSTS_FNSOF) >> DSTS_FNSOF_Pos; - if (_sof_en) - { - uint32_t frame = (dwc2->dsts & (DSTS_FNSOF)) >> 8; - dcd_event_sof(rhport, frame, true); - } - else - { - // Disable SOF interrupt if SOF was not explicitly enabled. SOF was used for remote wakeup detection + // Disable SOF interrupt if SOF was not explicitly enabled since SOF was used for remote wakeup detection + if (!_sof_en) { dwc2->gintmsk &= ~GINTMSK_SOFM; } - dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true); + dcd_event_sof(rhport, frame, true); } // RxFIFO non-empty interrupt handling. - if(int_status & GINTSTS_RXFLVL) - { + if (int_status & GINTSTS_RXFLVL) { // RXFLVL bit is read-only // Mask out RXFLVL while reading data from FIFO dwc2->gintmsk &= ~GINTMSK_RXFLVLM; // Loop until all available packets were handled - do - { + do { handle_rxflvl_irq(rhport); } while(dwc2->gintsts & GINTSTS_RXFLVL); - // Manage RX FIFO size - if (_out_ep_closed) - { - update_grxfsiz(rhport); - - // Disable flag - _out_ep_closed = false; - } - dwc2->gintmsk |= GINTMSK_RXFLVLM; } // OUT endpoint interrupt handling. - if(int_status & GINTSTS_OEPINT) - { + if (int_status & GINTSTS_OEPINT) { // OEPINT is read-only, clear using DOEPINTn handle_epout_irq(rhport); } // IN endpoint interrupt handling. - if(int_status & GINTSTS_IEPINT) - { + if (int_status & GINTSTS_IEPINT) { // IEPINT bit read-only, clear using DIEPINTn handle_epin_irq(rhport); } diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_bcm.h b/test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_bcm.h similarity index 100% rename from test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_bcm.h rename to test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_bcm.h diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_efm32.h b/test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_efm32.h similarity index 100% rename from test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_efm32.h rename to test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_efm32.h diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_esp32.h b/test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_esp32.h similarity index 100% rename from test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_esp32.h rename to test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_esp32.h diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_gd32.h b/test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_gd32.h similarity index 100% rename from test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_gd32.h rename to test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_gd32.h diff --git a/test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_info.md b/test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_info.md new file mode 100644 index 00000000..8690a075 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_info.md @@ -0,0 +1,55 @@ +| | BCM2711 (Pi4) | EFM32GG FullSpeed | ESP32-S2 | STM32F407 Fullspeed | STM32F407 Highspeed | STM32F411 Fullspeed | STM32F412 Fullspeed | STM32F429 Fullspeed | STM32F429 Highspeed | STM32F723 Fullspeed | STM32F723 HighSpeed | STM32F767 Fullspeed | STM32H743 Highspeed | STM32L476 Fullspeed | STM32U5A5 Highspeed | GD32VF103 Fullspeed | XMC4500 | +|:----------------------------|:----------------|:--------------------|:-----------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:-----------| +| guid | 0x2708A000 | 0x00000000 | 0x00000000 | 0x00001200 | 0x00001100 | 0x00001200 | 0x00002000 | 0x00001200 | 0x00001100 | 0x00003000 | 0x00003100 | 0x00002000 | 0x00002300 | 0x00002000 | 0x00005000 | 0x00001000 | 0x00AEC000 | +| gsnpsid | 0x4F54280A | 0x4F54330A | 0x4F54400A | 0x4F54281A | 0x4F54281A | 0x4F54281A | 0x4F54320A | 0x4F54281A | 0x4F54281A | 0x4F54330A | 0x4F54330A | 0x4F54320A | 0x4F54330A | 0x4F54310A | 0x4F54411A | 0x00000000 | 0x4F54292A | +| - specs version | 2.80a | 3.30a | 4.00a | 2.81a | 2.81a | 2.81a | 3.20a | 2.81a | 2.81a | 3.30a | 3.30a | 3.20a | 3.30a | 3.10a | 4.11a | 0.00W | 2.92a | +| ghwcfg1 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | +| ghwcfg2 | 0x228DDD50 | 0x228F5910 | 0x224DD930 | 0x229DCD20 | 0x229ED590 | 0x229DCD20 | 0x229ED520 | 0x229DCD20 | 0x229ED590 | 0x229ED520 | 0x229FE1D0 | 0x229ED520 | 0x229FE190 | 0x229ED520 | 0x228FE052 | 0x00000000 | 0x228F5930 | +| - op_mode | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | +| - arch | 2 | 2 | 2 | 0 | 2 | 0 | 0 | 0 | 2 | 0 | 2 | 0 | 2 | 0 | 2 | 0 | 2 | +| - point2point | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | +| - hs_phy_type | 1 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 2 | 0 | 3 | 0 | 2 | 0 | 1 | 0 | 0 | +| - fs_phy_type | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | +| - num_dev_ep | 7 | 6 | 6 | 3 | 5 | 3 | 5 | 3 | 5 | 5 | 8 | 5 | 8 | 5 | 8 | 0 | 6 | +| - num_host_ch | 7 | 13 | 7 | 7 | 11 | 7 | 11 | 7 | 11 | 11 | 15 | 11 | 15 | 11 | 15 | 0 | 13 | +| - period_channel_support | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | +| - enable_dynamic_fifo | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | +| - mul_cpu_int | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | +| - reserved21 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| - nperiod_tx_q_depth | 2 | 2 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 0 | 2 | +| - host_period_tx_q_depth | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 0 | 2 | +| - dev_token_q_depth | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 0 | 8 | +| - otg_enable_ic_usb | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| ghwcfg3 | 0x0FF000E8 | 0x01F204E8 | 0x00C804B5 | 0x020001E8 | 0x03F403E8 | 0x020001E8 | 0x0200D1E8 | 0x020001E8 | 0x03F403E8 | 0x0200D1E8 | 0x03EED2E8 | 0x0200D1E8 | 0x03B8D2E8 | 0x0200D1E8 | 0x03B882E8 | 0x00000000 | 0x027A01E5 | +| - xfer_size_width | 8 | 8 | 5 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 0 | 5 | +| - packet_size_width | 6 | 6 | 3 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 0 | 6 | +| - otg_enable | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | +| - i2c_enable | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | +| - vendor_ctrl_itf | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | +| - optional_feature_removed | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| - synch_reset | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| - otg_adp_support | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | +| - otg_enable_hsic | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| - battery_charger_support | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | +| - lpm_mode | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | +| - total_fifo_size | 4080 | 498 | 200 | 512 | 1012 | 512 | 512 | 512 | 1012 | 512 | 1006 | 512 | 952 | 512 | 952 | 0 | 634 | +| ghwcfg4 | 0x1FF00020 | 0x1BF08030 | 0xD3F0A030 | 0x0FF08030 | 0x17F00030 | 0x0FF08030 | 0x17F08030 | 0x0FF08030 | 0x17F00030 | 0x17F08030 | 0x23F00030 | 0x17F08030 | 0xE3F00030 | 0x17F08030 | 0xE2103E30 | 0x00000000 | 0xDBF08030 | +| - num_dev_period_in_ep | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| - power_optimized | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | +| - ahb_freq_min | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | +| - hibernation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| - reserved7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | +| - service_interval_mode | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | +| - ipg_isoc_en | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | +| - acg_enable | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | +| - reserved13 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | +| - utmi_phy_data_width | 0 | 2 | 2 | 2 | 0 | 2 | 2 | 2 | 0 | 2 | 0 | 2 | 0 | 2 | 0 | 0 | 2 | +| - dev_ctrl_ep_num | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| - iddg_filter_enabled | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | +| - vbus_valid_filter_enabled | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | +| - a_valid_filter_enabled | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | +| - b_valid_filter_enabled | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | +| - dedicated_fifos | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | +| - num_dev_in_eps | 15 | 13 | 9 | 7 | 11 | 7 | 11 | 7 | 11 | 11 | 1 | 11 | 1 | 11 | 1 | 0 | 13 | +| - dma_desc_enable | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | +| - dma_dynamic | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | diff --git a/test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_info.py b/test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_info.py new file mode 100644 index 00000000..55bec3d2 --- /dev/null +++ b/test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_info.py @@ -0,0 +1,169 @@ +import click +import ctypes +import pandas as pd + +# hex value for register: guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4 +dwc2_reg_list = ['guid', 'gsnpsid', 'ghwcfg1', 'ghwcfg2', 'ghwcfg3', 'ghwcfg4'] +dwc2_reg_value = { + 'BCM2711 (Pi4)': [0x2708A000, 0x4F54280A, 0, 0x228DDD50, 0xFF000E8, 0x1FF00020], + 'EFM32GG FullSpeed': [0, 0x4F54330A, 0, 0x228F5910, 0x1F204E8, 0x1BF08030], + 'ESP32-S2': [0, 0x4F54400A, 0, 0x224DD930, 0xC804B5, 0xD3F0A030], + 'STM32F407 Fullspeed': [0x1200, 0x4F54281A, 0, 0x229DCD20, 0x20001E8, 0xFF08030], + 'STM32F407 Highspeed': [0x1100, 0x4F54281A, 0, 0x229ED590, 0x3F403E8, 0x17F00030], + 'STM32F411 Fullspeed': [0x1200, 0x4F54281A, 0, 0x229DCD20, 0x20001E8, 0xFF08030], + 'STM32F412 Fullspeed': [0x2000, 0x4F54320A, 0, 0x229ED520, 0x200D1E8, 0x17F08030], + 'STM32F429 Fullspeed': [0x1200, 0x4F54281A, 0, 0x229DCD20, 0x20001E8, 0xFF08030], + 'STM32F429 Highspeed': [0x1100, 0x4F54281A, 0, 0x229ED590, 0x3F403E8, 0x17F00030], + 'STM32F723 Fullspeed': [0x3000, 0x4F54330A, 0, 0x229ED520, 0x200D1E8, 0x17F08030], + 'STM32F723 HighSpeed': [0x3100, 0x4F54330A, 0, 0x229FE1D0, 0x3EED2E8, 0x23F00030], + 'STM32F767 Fullspeed': [0x2000, 0x4F54320A, 0, 0x229ED520, 0x200D1E8, 0x17F08030], + 'STM32H743 Highspeed': [0x2300, 0x4F54330A, 0, 0x229FE190, 0x3B8D2E8, 0xE3F00030], # both HS cores + 'STM32L476 Fullspeed': [0x2000, 0x4F54310A, 0, 0x229ED520, 0x200D1E8, 0x17F08030], + 'STM32U5A5 Highspeed': [0x00005000, 0x4F54411A, 0x00000000, 0x228FE052, 0x03B882E8, 0xE2103E30], + 'GD32VF103 Fullspeed': [0x1000, 0, 0, 0, 0, 0], + 'XMC4500': [0xAEC000, 0x4F54292A, 0, 0x228F5930, 0x27A01E5, 0xDBF08030] +} + +# Combine dwc2_info with dwc2_reg_list +# dwc2_info = { +# 'BCM2711 (Pi4)': { +# 'guid': 0x2708A000, +# 'gsnpsid': 0x4F54280A, +# 'ghwcfg1': 0, +# 'ghwcfg2': 0x228DDD50, +# 'ghwcfg3': 0xFF000E8, +# 'ghwcfg4': 0x1FF00020 +# }, +dwc2_info = {key: {field: value for field, value in zip(dwc2_reg_list, values)} for key, values in dwc2_reg_value.items()} + + +class GHWCFG2(ctypes.LittleEndianStructure): + _fields_ = [ + ("op_mode", ctypes.c_uint32, 3), + ("arch", ctypes.c_uint32, 2), + ("point2point", ctypes.c_uint32, 1), + ("hs_phy_type", ctypes.c_uint32, 2), + ("fs_phy_type", ctypes.c_uint32, 2), + ("num_dev_ep", ctypes.c_uint32, 4), + ("num_host_ch", ctypes.c_uint32, 4), + ("period_channel_support", ctypes.c_uint32, 1), + ("enable_dynamic_fifo", ctypes.c_uint32, 1), + ("mul_cpu_int", ctypes.c_uint32, 1), + ("reserved21", ctypes.c_uint32, 1), + ("nperiod_tx_q_depth", ctypes.c_uint32, 2), + ("host_period_tx_q_depth", ctypes.c_uint32, 2), + ("dev_token_q_depth", ctypes.c_uint32, 5), + ("otg_enable_ic_usb", ctypes.c_uint32, 1) + ] + + +class GHWCFG3(ctypes.LittleEndianStructure): + _fields_ = [ + ("xfer_size_width", ctypes.c_uint32, 4), + ("packet_size_width", ctypes.c_uint32, 3), + ("otg_enable", ctypes.c_uint32, 1), + ("i2c_enable", ctypes.c_uint32, 1), + ("vendor_ctrl_itf", ctypes.c_uint32, 1), + ("optional_feature_removed", ctypes.c_uint32, 1), + ("synch_reset", ctypes.c_uint32, 1), + ("otg_adp_support", ctypes.c_uint32, 1), + ("otg_enable_hsic", ctypes.c_uint32, 1), + ("battery_charger_support", ctypes.c_uint32, 1), + ("lpm_mode", ctypes.c_uint32, 1), + ("total_fifo_size", ctypes.c_uint32, 16) + ] + + +class GHWCFG4(ctypes.LittleEndianStructure): + _fields_ = [ + ("num_dev_period_in_ep", ctypes.c_uint32, 4), + ("power_optimized", ctypes.c_uint32, 1), + ("ahb_freq_min", ctypes.c_uint32, 1), + ("hibernation", ctypes.c_uint32, 1), + ("reserved7", ctypes.c_uint32, 3), + ("service_interval_mode", ctypes.c_uint32, 1), + ("ipg_isoc_en", ctypes.c_uint32, 1), + ("acg_enable", ctypes.c_uint32, 1), + ("reserved13", ctypes.c_uint32, 1), + ("utmi_phy_data_width", ctypes.c_uint32, 2), + ("dev_ctrl_ep_num", ctypes.c_uint32, 4), + ("iddg_filter_enabled", ctypes.c_uint32, 1), + ("vbus_valid_filter_enabled", ctypes.c_uint32, 1), + ("a_valid_filter_enabled", ctypes.c_uint32, 1), + ("b_valid_filter_enabled", ctypes.c_uint32, 1), + ("dedicated_fifos", ctypes.c_uint32, 1), + ("num_dev_in_eps", ctypes.c_uint32, 4), + ("dma_desc_enable", ctypes.c_uint32, 1), + ("dma_dynamic", ctypes.c_uint32, 1) + ] + + +@click.group() +def cli(): + pass + + +@cli.command() +@click.argument('mcus', nargs=-1) +@click.option('-a', '--all', is_flag=True, help='Print all bit-field values') +def info(mcus, all): + """Print DWC2 register values for given MCU(s)""" + if len(mcus) == 0: + mcus = dwc2_info + + for mcu in mcus: + for entry in dwc2_info: + if mcu.lower() in entry.lower(): + print(f"## {entry}") + for r_name, r_value in dwc2_info[entry].items(): + print(f"{r_name} = 0x{r_value:08X}") + # Print bit-field values + if all and r_name.upper() in globals(): + class_name = globals()[r_name.upper()] + ghwcfg = class_name.from_buffer_copy(r_value.to_bytes(4, byteorder='little')) + for field_name, field_type, _ in class_name._fields_: + print(f" {field_name} = {getattr(ghwcfg, field_name)}") + + +@cli.command() +def render_md(): + """Render dwc2_info to Markdown table""" + # Create an empty list to hold the dictionaries + dwc2_info_list = [] + + # Iterate over the dwc2_info dictionary and extract fields + for device, reg_values in dwc2_info.items(): + entry_dict = {"Device": device} + for r_name, r_value in reg_values.items(): + entry_dict[r_name] = f"0x{r_value:08X}" + + if r_name == 'gsnpsid': + # Get dwc2 specs version + major = ((r_value >> 8) >> 4) & 0x0F + minor = (r_value >> 4) & 0xFF + patch = chr((r_value & 0x0F) + ord('a') - 0xA) + entry_dict[f' - specs version'] = f"{major:X}.{minor:02X}{patch}" + elif r_name.upper() in globals(): + # Get bit-field values which exist as ctypes structures + class_name = globals()[r_name.upper()] + ghwcfg = class_name.from_buffer_copy(r_value.to_bytes(4, byteorder='little')) + for field_name, field_type, _ in class_name._fields_: + entry_dict[f' - {field_name}'] = getattr(ghwcfg, field_name) + + dwc2_info_list.append(entry_dict) + + # Create a Pandas DataFrame from the list of dictionaries + df = pd.DataFrame(dwc2_info_list).set_index('Device') + + # Transpose the DataFrame to switch rows and columns + df = df.T + #print(df) + + # Write the Markdown table to a file + with open('dwc2_info.md', 'w') as md_file: + md_file.write(df.to_markdown()) + md_file.write('\n') + + +if __name__ == '__main__': + cli() diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_stm32.h b/test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_stm32.h similarity index 63% rename from test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_stm32.h rename to test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_stm32.h index cb455bd9..3237a50f 100644 --- a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_stm32.h +++ b/test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_stm32.h @@ -24,11 +24,11 @@ * This file is part of the TinyUSB stack. */ -#ifndef _DWC2_STM32_H_ -#define _DWC2_STM32_H_ +#ifndef DWC2_STM32_H_ +#define DWC2_STM32_H_ #ifdef __cplusplus - extern "C" { +extern "C" { #endif // EP_MAX : Max number of bi-directional endpoints including EP0 @@ -84,10 +84,16 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32U5 #include "stm32u5xx.h" - #define USB_OTG_FS_PERIPH_BASE USB_OTG_FS_BASE - #define EP_MAX_FS 6 - #define EP_FIFO_SIZE_FS 1280 - + // U59x/5Ax/5Fx/5Gx are highspeed with built-in HS PHY + #ifdef USB_OTG_FS + #define USB_OTG_FS_PERIPH_BASE USB_OTG_FS_BASE + #define EP_MAX_FS 6 + #define EP_FIFO_SIZE_FS 1280 + #else + #define USB_OTG_HS_PERIPH_BASE USB_OTG_HS_BASE + #define EP_MAX_HS 9 + #define EP_FIFO_SIZE_HS 4096 + #endif #else #error "Unsupported MCUs" #endif @@ -101,15 +107,14 @@ // On STM32 for consistency we associate // - Port0 to OTG_FS, and Port1 to OTG_HS -static const dwc2_controller_t _dwc2_controller[] = -{ -#ifdef USB_OTG_FS_PERIPH_BASE - { .reg_base = USB_OTG_FS_PERIPH_BASE, .irqnum = OTG_FS_IRQn, .ep_count = EP_MAX_FS, .ep_fifo_size = EP_FIFO_SIZE_FS }, -#endif - -#ifdef USB_OTG_HS_PERIPH_BASE - { .reg_base = USB_OTG_HS_PERIPH_BASE, .irqnum = OTG_HS_IRQn, .ep_count = EP_MAX_HS, .ep_fifo_size = EP_FIFO_SIZE_HS }, -#endif +static const dwc2_controller_t _dwc2_controller[] = { + #ifdef USB_OTG_FS_PERIPH_BASE + { .reg_base = USB_OTG_FS_PERIPH_BASE, .irqnum = OTG_FS_IRQn, .ep_count = EP_MAX_FS, .ep_fifo_size = EP_FIFO_SIZE_FS }, + #endif + + #ifdef USB_OTG_HS_PERIPH_BASE + { .reg_base = USB_OTG_HS_PERIPH_BASE, .irqnum = OTG_HS_IRQn, .ep_count = EP_MAX_HS, .ep_fifo_size = EP_FIFO_SIZE_HS }, + #endif }; //--------------------------------------------------------------------+ @@ -119,42 +124,59 @@ static const dwc2_controller_t _dwc2_controller[] = // SystemCoreClock is already included by family header // extern uint32_t SystemCoreClock; -TU_ATTR_ALWAYS_INLINE -static inline void dwc2_dcd_int_enable(uint8_t rhport) -{ - NVIC_EnableIRQ((IRQn_Type)_dwc2_controller[rhport].irqnum); +TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_enable(uint8_t rhport) { + NVIC_EnableIRQ((IRQn_Type) _dwc2_controller[rhport].irqnum); } -TU_ATTR_ALWAYS_INLINE -static inline void dwc2_dcd_int_disable (uint8_t rhport) -{ - NVIC_DisableIRQ((IRQn_Type)_dwc2_controller[rhport].irqnum); +TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_disable(uint8_t rhport) { + NVIC_DisableIRQ((IRQn_Type) _dwc2_controller[rhport].irqnum); } -TU_ATTR_ALWAYS_INLINE -static inline void dwc2_remote_wakeup_delay(void) -{ +TU_ATTR_ALWAYS_INLINE static inline void dwc2_remote_wakeup_delay(void) { // try to delay for 1 ms uint32_t count = SystemCoreClock / 1000; - while ( count-- ) __NOP(); + while (count--) __NOP(); } // MCU specific PHY init, called BEFORE core reset -static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) -{ - if ( hs_phy_type == HS_PHY_TYPE_NONE ) - { +// - dwc2 3.30a (H5) use USB_HS_PHYC +// - dwc2 4.11a (U5) use femtoPHY +static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) { + if (hs_phy_type == HS_PHY_TYPE_NONE) { // Enable on-chip FS PHY dwc2->stm32_gccfg |= STM32_GCCFG_PWRDWN; - }else - { - // Disable FS PHY + + // https://community.st.com/t5/stm32cubemx-mcus/why-stm32h743-usb-fs-doesn-t-work-if-freertos-tickless-idle/m-p/349480#M18867 + // H7 running on full-speed phy need to disable ULPI clock in sleep mode. + // Otherwise, USB won't work when mcu executing WFI/WFE instruction i.e tick-less RTOS. + // Note: there may be other family that is affected by this, but only H7 and F7 is tested so far + #if defined(USB_OTG_FS_PERIPH_BASE) && defined(RCC_AHB1LPENR_USB2OTGFSULPILPEN) + if ( USB_OTG_FS_PERIPH_BASE == (uint32_t) dwc2 ) { + RCC->AHB1LPENR &= ~RCC_AHB1LPENR_USB2OTGFSULPILPEN; + } + #endif + + #if defined(USB_OTG_HS_PERIPH_BASE) && defined(RCC_AHB1LPENR_USB1OTGHSULPILPEN) + if ( USB_OTG_HS_PERIPH_BASE == (uint32_t) dwc2 ) { + RCC->AHB1LPENR &= ~RCC_AHB1LPENR_USB1OTGHSULPILPEN; + } + #endif + + #if defined(USB_OTG_HS_PERIPH_BASE) && defined(RCC_AHB1LPENR_OTGHSULPILPEN) + if ( USB_OTG_HS_PERIPH_BASE == (uint32_t) dwc2 ) { + RCC->AHB1LPENR &= ~RCC_AHB1LPENR_OTGHSULPILPEN; + } + #endif + + } else { +#if CFG_TUSB_MCU != OPT_MCU_STM32U5 + // Disable FS PHY, TODO on U5A5 (dwc2 4.11a) 16th bit is 'Host CDP behavior enable' dwc2->stm32_gccfg &= ~STM32_GCCFG_PWRDWN; +#endif // Enable on-chip HS PHY - if (hs_phy_type == HS_PHY_TYPE_UTMI || hs_phy_type == HS_PHY_TYPE_UTMI_ULPI) - { -#ifdef USB_HS_PHYC + if (hs_phy_type == HS_PHY_TYPE_UTMI || hs_phy_type == HS_PHY_TYPE_UTMI_ULPI) { + #ifdef USB_HS_PHYC // Enable UTMI HS PHY dwc2->stm32_gccfg |= STM32_GCCFG_PHYHSEN; @@ -186,40 +208,47 @@ static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) // Enable PLL internal PHY USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL_PLLEN; -#endif + #else + + #endif } } } // MCU specific PHY update, it is called AFTER init() and core reset -static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) -{ +static inline void dwc2_phy_update(dwc2_regs_t* dwc2, uint8_t hs_phy_type) { // used to set turnaround time for fullspeed, nothing to do in highspeed mode - if ( hs_phy_type == HS_PHY_TYPE_NONE ) - { + if (hs_phy_type == HS_PHY_TYPE_NONE) { // Turnaround timeout depends on the AHB clock dictated by STM32 Reference Manual uint32_t turnaround; - if ( SystemCoreClock >= 32000000u ) + if (SystemCoreClock >= 32000000u) { turnaround = 0x6u; - else if ( SystemCoreClock >= 27500000u ) + } else if (SystemCoreClock >= 27500000u) { turnaround = 0x7u; - else if ( SystemCoreClock >= 24000000u ) + } else if (SystemCoreClock >= 24000000u) { turnaround = 0x8u; - else if ( SystemCoreClock >= 21800000u ) + } else if (SystemCoreClock >= 21800000u) { turnaround = 0x9u; - else if ( SystemCoreClock >= 20000000u ) + } + else if (SystemCoreClock >= 20000000u) { turnaround = 0xAu; - else if ( SystemCoreClock >= 18500000u ) + } + else if (SystemCoreClock >= 18500000u) { turnaround = 0xBu; - else if ( SystemCoreClock >= 17200000u ) + } + else if (SystemCoreClock >= 17200000u) { turnaround = 0xCu; - else if ( SystemCoreClock >= 16000000u ) + } + else if (SystemCoreClock >= 16000000u) { turnaround = 0xDu; - else if ( SystemCoreClock >= 15000000u ) + } + else if (SystemCoreClock >= 15000000u) { turnaround = 0xEu; - else + } + else { turnaround = 0xFu; + } dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (turnaround << GUSBCFG_TRDT_Pos); } @@ -229,4 +258,4 @@ static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) } #endif -#endif /* _DWC2_STM32_H_ */ +#endif diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_type.h b/test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_type.h similarity index 71% rename from test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_type.h rename to test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_type.h index 3fc97933..c1577123 100644 --- a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_type.h +++ b/test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_type.h @@ -32,7 +32,7 @@ typedef struct uint32_t ep_fifo_size; }dwc2_controller_t; -/* DWC OTG HW Release versions */ +// DWC OTG HW Release versions #define DWC2_CORE_REV_2_71a 0x4f54271a #define DWC2_CORE_REV_2_72a 0x4f54272a #define DWC2_CORE_REV_2_80a 0x4f54280a @@ -43,12 +43,13 @@ typedef struct #define DWC2_CORE_REV_3_00a 0x4f54300a #define DWC2_CORE_REV_3_10a 0x4f54310a #define DWC2_CORE_REV_4_00a 0x4f54400a +#define DWC2_CORE_REV_4_11a 0x4f54411a #define DWC2_CORE_REV_4_20a 0x4f54420a #define DWC2_FS_IOT_REV_1_00a 0x5531100a #define DWC2_HS_IOT_REV_1_00a 0x5532100a #define DWC2_CORE_REV_MASK 0x0000ffff -/* DWC OTG HW Core ID */ +// DWC OTG HW Core ID #define DWC2_OTG_ID 0x4f540000 #define DWC2_FS_IOT_ID 0x55310000 #define DWC2_HS_IOT_ID 0x55320000 @@ -57,13 +58,13 @@ typedef struct // HS PHY typedef struct { - volatile uint32_t HS_PHYC_PLL; // This register is used to control the PLL of the HS PHY. 000h */ - volatile uint32_t Reserved04; // Reserved 004h */ - volatile uint32_t Reserved08; // Reserved 008h */ - volatile uint32_t HS_PHYC_TUNE; // This register is used to control the tuning interface of the High Speed PHY. 00Ch */ - volatile uint32_t Reserved10; // Reserved 010h */ - volatile uint32_t Reserved14; // Reserved 014h */ - volatile uint32_t HS_PHYC_LDO; // This register is used to control the regulator (LDO). 018h */ + volatile uint32_t HS_PHYC_PLL; // 000h This register is used to control the PLL of the HS PHY. + volatile uint32_t Reserved04; // 004h Reserved + volatile uint32_t Reserved08; // 008h Reserved + volatile uint32_t HS_PHYC_TUNE; // 00Ch This register is used to control the tuning interface of the High Speed PHY. + volatile uint32_t Reserved10; // 010h Reserved + volatile uint32_t Reserved14; // 014h Reserved + volatile uint32_t HS_PHYC_LDO; // 018h This register is used to control the regulator (LDO). } HS_PHYC_GlobalTypeDef; #endif @@ -298,103 +299,103 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size"); /******************** Bit definition for GOTGCTL register ********************/ #define GOTGCTL_SRQSCS_Pos (0U) -#define GOTGCTL_SRQSCS_Msk (0x1UL << GOTGCTL_SRQSCS_Pos) // 0x00000001 */ -#define GOTGCTL_SRQSCS GOTGCTL_SRQSCS_Msk // Session request success */ +#define GOTGCTL_SRQSCS_Msk (0x1UL << GOTGCTL_SRQSCS_Pos) // 0x00000001 +#define GOTGCTL_SRQSCS GOTGCTL_SRQSCS_Msk // Session request success #define GOTGCTL_SRQ_Pos (1U) -#define GOTGCTL_SRQ_Msk (0x1UL << GOTGCTL_SRQ_Pos) // 0x00000002 */ -#define GOTGCTL_SRQ GOTGCTL_SRQ_Msk // Session request */ +#define GOTGCTL_SRQ_Msk (0x1UL << GOTGCTL_SRQ_Pos) // 0x00000002 +#define GOTGCTL_SRQ GOTGCTL_SRQ_Msk // Session request #define GOTGCTL_VBVALOEN_Pos (2U) -#define GOTGCTL_VBVALOEN_Msk (0x1UL << GOTGCTL_VBVALOEN_Pos) // 0x00000004 */ -#define GOTGCTL_VBVALOEN GOTGCTL_VBVALOEN_Msk // VBUS valid override enable */ +#define GOTGCTL_VBVALOEN_Msk (0x1UL << GOTGCTL_VBVALOEN_Pos) // 0x00000004 +#define GOTGCTL_VBVALOEN GOTGCTL_VBVALOEN_Msk // VBUS valid override enable #define GOTGCTL_VBVALOVAL_Pos (3U) -#define GOTGCTL_VBVALOVAL_Msk (0x1UL << GOTGCTL_VBVALOVAL_Pos) // 0x00000008 */ -#define GOTGCTL_VBVALOVAL GOTGCTL_VBVALOVAL_Msk // VBUS valid override value */ +#define GOTGCTL_VBVALOVAL_Msk (0x1UL << GOTGCTL_VBVALOVAL_Pos) // 0x00000008 +#define GOTGCTL_VBVALOVAL GOTGCTL_VBVALOVAL_Msk // VBUS valid override value #define GOTGCTL_AVALOEN_Pos (4U) -#define GOTGCTL_AVALOEN_Msk (0x1UL << GOTGCTL_AVALOEN_Pos) // 0x00000010 */ -#define GOTGCTL_AVALOEN GOTGCTL_AVALOEN_Msk // A-peripheral session valid override enable */ +#define GOTGCTL_AVALOEN_Msk (0x1UL << GOTGCTL_AVALOEN_Pos) // 0x00000010 +#define GOTGCTL_AVALOEN GOTGCTL_AVALOEN_Msk // A-peripheral session valid override enable #define GOTGCTL_AVALOVAL_Pos (5U) -#define GOTGCTL_AVALOVAL_Msk (0x1UL << GOTGCTL_AVALOVAL_Pos) // 0x00000020 */ -#define GOTGCTL_AVALOVAL GOTGCTL_AVALOVAL_Msk // A-peripheral session valid override value */ +#define GOTGCTL_AVALOVAL_Msk (0x1UL << GOTGCTL_AVALOVAL_Pos) // 0x00000020 +#define GOTGCTL_AVALOVAL GOTGCTL_AVALOVAL_Msk // A-peripheral session valid override value #define GOTGCTL_BVALOEN_Pos (6U) -#define GOTGCTL_BVALOEN_Msk (0x1UL << GOTGCTL_BVALOEN_Pos) // 0x00000040 */ -#define GOTGCTL_BVALOEN GOTGCTL_BVALOEN_Msk // B-peripheral session valid override enable */ +#define GOTGCTL_BVALOEN_Msk (0x1UL << GOTGCTL_BVALOEN_Pos) // 0x00000040 +#define GOTGCTL_BVALOEN GOTGCTL_BVALOEN_Msk // B-peripheral session valid override enable #define GOTGCTL_BVALOVAL_Pos (7U) -#define GOTGCTL_BVALOVAL_Msk (0x1UL << GOTGCTL_BVALOVAL_Pos) // 0x00000080 */ -#define GOTGCTL_BVALOVAL GOTGCTL_BVALOVAL_Msk // B-peripheral session valid override value */ +#define GOTGCTL_BVALOVAL_Msk (0x1UL << GOTGCTL_BVALOVAL_Pos) // 0x00000080 +#define GOTGCTL_BVALOVAL GOTGCTL_BVALOVAL_Msk // B-peripheral session valid override value #define GOTGCTL_HNGSCS_Pos (8U) -#define GOTGCTL_HNGSCS_Msk (0x1UL << GOTGCTL_HNGSCS_Pos) // 0x00000100 */ -#define GOTGCTL_HNGSCS GOTGCTL_HNGSCS_Msk // Host set HNP enable */ +#define GOTGCTL_HNGSCS_Msk (0x1UL << GOTGCTL_HNGSCS_Pos) // 0x00000100 +#define GOTGCTL_HNGSCS GOTGCTL_HNGSCS_Msk // Host set HNP enable #define GOTGCTL_HNPRQ_Pos (9U) -#define GOTGCTL_HNPRQ_Msk (0x1UL << GOTGCTL_HNPRQ_Pos) // 0x00000200 */ -#define GOTGCTL_HNPRQ GOTGCTL_HNPRQ_Msk // HNP request */ +#define GOTGCTL_HNPRQ_Msk (0x1UL << GOTGCTL_HNPRQ_Pos) // 0x00000200 +#define GOTGCTL_HNPRQ GOTGCTL_HNPRQ_Msk // HNP request #define GOTGCTL_HSHNPEN_Pos (10U) -#define GOTGCTL_HSHNPEN_Msk (0x1UL << GOTGCTL_HSHNPEN_Pos) // 0x00000400 */ -#define GOTGCTL_HSHNPEN GOTGCTL_HSHNPEN_Msk // Host set HNP enable */ +#define GOTGCTL_HSHNPEN_Msk (0x1UL << GOTGCTL_HSHNPEN_Pos) // 0x00000400 +#define GOTGCTL_HSHNPEN GOTGCTL_HSHNPEN_Msk // Host set HNP enable #define GOTGCTL_DHNPEN_Pos (11U) -#define GOTGCTL_DHNPEN_Msk (0x1UL << GOTGCTL_DHNPEN_Pos) // 0x00000800 */ -#define GOTGCTL_DHNPEN GOTGCTL_DHNPEN_Msk // Device HNP enabled */ +#define GOTGCTL_DHNPEN_Msk (0x1UL << GOTGCTL_DHNPEN_Pos) // 0x00000800 +#define GOTGCTL_DHNPEN GOTGCTL_DHNPEN_Msk // Device HNP enabled #define GOTGCTL_EHEN_Pos (12U) -#define GOTGCTL_EHEN_Msk (0x1UL << GOTGCTL_EHEN_Pos) // 0x00001000 */ -#define GOTGCTL_EHEN GOTGCTL_EHEN_Msk // Embedded host enable */ +#define GOTGCTL_EHEN_Msk (0x1UL << GOTGCTL_EHEN_Pos) // 0x00001000 +#define GOTGCTL_EHEN GOTGCTL_EHEN_Msk // Embedded host enable #define GOTGCTL_CIDSTS_Pos (16U) -#define GOTGCTL_CIDSTS_Msk (0x1UL << GOTGCTL_CIDSTS_Pos) // 0x00010000 */ -#define GOTGCTL_CIDSTS GOTGCTL_CIDSTS_Msk // Connector ID status */ +#define GOTGCTL_CIDSTS_Msk (0x1UL << GOTGCTL_CIDSTS_Pos) // 0x00010000 +#define GOTGCTL_CIDSTS GOTGCTL_CIDSTS_Msk // Connector ID status #define GOTGCTL_DBCT_Pos (17U) -#define GOTGCTL_DBCT_Msk (0x1UL << GOTGCTL_DBCT_Pos) // 0x00020000 */ -#define GOTGCTL_DBCT GOTGCTL_DBCT_Msk // Long/short debounce time */ +#define GOTGCTL_DBCT_Msk (0x1UL << GOTGCTL_DBCT_Pos) // 0x00020000 +#define GOTGCTL_DBCT GOTGCTL_DBCT_Msk // Long/short debounce time #define GOTGCTL_ASVLD_Pos (18U) -#define GOTGCTL_ASVLD_Msk (0x1UL << GOTGCTL_ASVLD_Pos) // 0x00040000 */ -#define GOTGCTL_ASVLD GOTGCTL_ASVLD_Msk // A-session valid */ +#define GOTGCTL_ASVLD_Msk (0x1UL << GOTGCTL_ASVLD_Pos) // 0x00040000 +#define GOTGCTL_ASVLD GOTGCTL_ASVLD_Msk // A-session valid #define GOTGCTL_BSESVLD_Pos (19U) -#define GOTGCTL_BSESVLD_Msk (0x1UL << GOTGCTL_BSESVLD_Pos) // 0x00080000 */ -#define GOTGCTL_BSESVLD GOTGCTL_BSESVLD_Msk // B-session valid */ +#define GOTGCTL_BSESVLD_Msk (0x1UL << GOTGCTL_BSESVLD_Pos) // 0x00080000 +#define GOTGCTL_BSESVLD GOTGCTL_BSESVLD_Msk // B-session valid #define GOTGCTL_OTGVER_Pos (20U) -#define GOTGCTL_OTGVER_Msk (0x1UL << GOTGCTL_OTGVER_Pos) // 0x00100000 */ -#define GOTGCTL_OTGVER GOTGCTL_OTGVER_Msk // OTG version */ +#define GOTGCTL_OTGVER_Msk (0x1UL << GOTGCTL_OTGVER_Pos) // 0x00100000 +#define GOTGCTL_OTGVER GOTGCTL_OTGVER_Msk // OTG version /******************** Bit definition for HCFG register ********************/ #define HCFG_FSLSPCS_Pos (0U) -#define HCFG_FSLSPCS_Msk (0x3UL << HCFG_FSLSPCS_Pos) // 0x00000003 */ -#define HCFG_FSLSPCS HCFG_FSLSPCS_Msk // FS/LS PHY clock select */ -#define HCFG_FSLSPCS_0 (0x1UL << HCFG_FSLSPCS_Pos) // 0x00000001 */ -#define HCFG_FSLSPCS_1 (0x2UL << HCFG_FSLSPCS_Pos) // 0x00000002 */ +#define HCFG_FSLSPCS_Msk (0x3UL << HCFG_FSLSPCS_Pos) // 0x00000003 +#define HCFG_FSLSPCS HCFG_FSLSPCS_Msk // FS/LS PHY clock select +#define HCFG_FSLSPCS_0 (0x1UL << HCFG_FSLSPCS_Pos) // 0x00000001 +#define HCFG_FSLSPCS_1 (0x2UL << HCFG_FSLSPCS_Pos) // 0x00000002 #define HCFG_FSLSS_Pos (2U) -#define HCFG_FSLSS_Msk (0x1UL << HCFG_FSLSS_Pos) // 0x00000004 */ -#define HCFG_FSLSS HCFG_FSLSS_Msk // FS- and LS-only support */ +#define HCFG_FSLSS_Msk (0x1UL << HCFG_FSLSS_Pos) // 0x00000004 +#define HCFG_FSLSS HCFG_FSLSS_Msk // FS- and LS-only support /******************** Bit definition for PCGCR register ********************/ #define PCGCR_STPPCLK_Pos (0U) -#define PCGCR_STPPCLK_Msk (0x1UL << PCGCR_STPPCLK_Pos) // 0x00000001 */ -#define PCGCR_STPPCLK PCGCR_STPPCLK_Msk // Stop PHY clock */ +#define PCGCR_STPPCLK_Msk (0x1UL << PCGCR_STPPCLK_Pos) // 0x00000001 +#define PCGCR_STPPCLK PCGCR_STPPCLK_Msk // Stop PHY clock #define PCGCR_GATEHCLK_Pos (1U) -#define PCGCR_GATEHCLK_Msk (0x1UL << PCGCR_GATEHCLK_Pos) // 0x00000002 */ -#define PCGCR_GATEHCLK PCGCR_GATEHCLK_Msk // Gate HCLK */ +#define PCGCR_GATEHCLK_Msk (0x1UL << PCGCR_GATEHCLK_Pos) // 0x00000002 +#define PCGCR_GATEHCLK PCGCR_GATEHCLK_Msk // Gate HCLK #define PCGCR_PHYSUSP_Pos (4U) -#define PCGCR_PHYSUSP_Msk (0x1UL << PCGCR_PHYSUSP_Pos) // 0x00000010 */ -#define PCGCR_PHYSUSP PCGCR_PHYSUSP_Msk // PHY suspended */ +#define PCGCR_PHYSUSP_Msk (0x1UL << PCGCR_PHYSUSP_Pos) // 0x00000010 +#define PCGCR_PHYSUSP PCGCR_PHYSUSP_Msk // PHY suspended /******************** Bit definition for GOTGINT register ********************/ #define GOTGINT_SEDET_Pos (2U) -#define GOTGINT_SEDET_Msk (0x1UL << GOTGINT_SEDET_Pos) // 0x00000004 */ -#define GOTGINT_SEDET GOTGINT_SEDET_Msk // Session end detected */ +#define GOTGINT_SEDET_Msk (0x1UL << GOTGINT_SEDET_Pos) // 0x00000004 +#define GOTGINT_SEDET GOTGINT_SEDET_Msk // Session end detected #define GOTGINT_SRSSCHG_Pos (8U) -#define GOTGINT_SRSSCHG_Msk (0x1UL << GOTGINT_SRSSCHG_Pos) // 0x00000100 */ -#define GOTGINT_SRSSCHG GOTGINT_SRSSCHG_Msk // Session request success status change */ +#define GOTGINT_SRSSCHG_Msk (0x1UL << GOTGINT_SRSSCHG_Pos) // 0x00000100 +#define GOTGINT_SRSSCHG GOTGINT_SRSSCHG_Msk // Session request success status change #define GOTGINT_HNSSCHG_Pos (9U) -#define GOTGINT_HNSSCHG_Msk (0x1UL << GOTGINT_HNSSCHG_Pos) // 0x00000200 */ -#define GOTGINT_HNSSCHG GOTGINT_HNSSCHG_Msk // Host negotiation success status change */ +#define GOTGINT_HNSSCHG_Msk (0x1UL << GOTGINT_HNSSCHG_Pos) // 0x00000200 +#define GOTGINT_HNSSCHG GOTGINT_HNSSCHG_Msk // Host negotiation success status change #define GOTGINT_HNGDET_Pos (17U) -#define GOTGINT_HNGDET_Msk (0x1UL << GOTGINT_HNGDET_Pos) // 0x00020000 */ -#define GOTGINT_HNGDET GOTGINT_HNGDET_Msk // Host negotiation detected */ +#define GOTGINT_HNGDET_Msk (0x1UL << GOTGINT_HNGDET_Pos) // 0x00020000 +#define GOTGINT_HNGDET GOTGINT_HNGDET_Msk // Host negotiation detected #define GOTGINT_ADTOCHG_Pos (18U) -#define GOTGINT_ADTOCHG_Msk (0x1UL << GOTGINT_ADTOCHG_Pos) // 0x00040000 */ -#define GOTGINT_ADTOCHG GOTGINT_ADTOCHG_Msk // A-device timeout change */ +#define GOTGINT_ADTOCHG_Msk (0x1UL << GOTGINT_ADTOCHG_Pos) // 0x00040000 +#define GOTGINT_ADTOCHG GOTGINT_ADTOCHG_Msk // A-device timeout change #define GOTGINT_DBCDNE_Pos (19U) -#define GOTGINT_DBCDNE_Msk (0x1UL << GOTGINT_DBCDNE_Pos) // 0x00080000 */ -#define GOTGINT_DBCDNE GOTGINT_DBCDNE_Msk // Debounce done */ +#define GOTGINT_DBCDNE_Msk (0x1UL << GOTGINT_DBCDNE_Pos) // 0x00080000 +#define GOTGINT_DBCDNE GOTGINT_DBCDNE_Msk // Debounce done #define GOTGINT_IDCHNG_Pos (20U) -#define GOTGINT_IDCHNG_Msk (0x1UL << GOTGINT_IDCHNG_Pos) // 0x00100000 */ -#define GOTGINT_IDCHNG GOTGINT_IDCHNG_Msk // Change in ID pin input value */ +#define GOTGINT_IDCHNG_Msk (0x1UL << GOTGINT_IDCHNG_Pos) // 0x00100000 +#define GOTGINT_IDCHNG GOTGINT_IDCHNG_Msk // Change in ID pin input value /******************** Bit definition for DCFG register ********************/ #define DCFG_DSPD_Pos (0U) @@ -405,92 +406,92 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size"); #define DCFG_DSPD_FS 3 // Fullspeed on FS PHY #define DCFG_NZLSOHSK_Pos (2U) -#define DCFG_NZLSOHSK_Msk (0x1UL << DCFG_NZLSOHSK_Pos) // 0x00000004 */ -#define DCFG_NZLSOHSK DCFG_NZLSOHSK_Msk // Nonzero-length status OUT handshake */ +#define DCFG_NZLSOHSK_Msk (0x1UL << DCFG_NZLSOHSK_Pos) // 0x00000004 +#define DCFG_NZLSOHSK DCFG_NZLSOHSK_Msk // Nonzero-length status OUT handshake #define DCFG_DAD_Pos (4U) -#define DCFG_DAD_Msk (0x7FUL << DCFG_DAD_Pos) // 0x000007F0 */ -#define DCFG_DAD DCFG_DAD_Msk // Device address */ -#define DCFG_DAD_0 (0x01UL << DCFG_DAD_Pos) // 0x00000010 */ -#define DCFG_DAD_1 (0x02UL << DCFG_DAD_Pos) // 0x00000020 */ -#define DCFG_DAD_2 (0x04UL << DCFG_DAD_Pos) // 0x00000040 */ -#define DCFG_DAD_3 (0x08UL << DCFG_DAD_Pos) // 0x00000080 */ -#define DCFG_DAD_4 (0x10UL << DCFG_DAD_Pos) // 0x00000100 */ -#define DCFG_DAD_5 (0x20UL << DCFG_DAD_Pos) // 0x00000200 */ -#define DCFG_DAD_6 (0x40UL << DCFG_DAD_Pos) // 0x00000400 */ +#define DCFG_DAD_Msk (0x7FUL << DCFG_DAD_Pos) // 0x000007F0 +#define DCFG_DAD DCFG_DAD_Msk // Device address +#define DCFG_DAD_0 (0x01UL << DCFG_DAD_Pos) // 0x00000010 +#define DCFG_DAD_1 (0x02UL << DCFG_DAD_Pos) // 0x00000020 +#define DCFG_DAD_2 (0x04UL << DCFG_DAD_Pos) // 0x00000040 +#define DCFG_DAD_3 (0x08UL << DCFG_DAD_Pos) // 0x00000080 +#define DCFG_DAD_4 (0x10UL << DCFG_DAD_Pos) // 0x00000100 +#define DCFG_DAD_5 (0x20UL << DCFG_DAD_Pos) // 0x00000200 +#define DCFG_DAD_6 (0x40UL << DCFG_DAD_Pos) // 0x00000400 #define DCFG_PFIVL_Pos (11U) -#define DCFG_PFIVL_Msk (0x3UL << DCFG_PFIVL_Pos) // 0x00001800 */ -#define DCFG_PFIVL DCFG_PFIVL_Msk // Periodic (micro)frame interval */ -#define DCFG_PFIVL_0 (0x1UL << DCFG_PFIVL_Pos) // 0x00000800 */ -#define DCFG_PFIVL_1 (0x2UL << DCFG_PFIVL_Pos) // 0x00001000 */ +#define DCFG_PFIVL_Msk (0x3UL << DCFG_PFIVL_Pos) // 0x00001800 +#define DCFG_PFIVL DCFG_PFIVL_Msk // Periodic (micro)frame interval +#define DCFG_PFIVL_0 (0x1UL << DCFG_PFIVL_Pos) // 0x00000800 +#define DCFG_PFIVL_1 (0x2UL << DCFG_PFIVL_Pos) // 0x00001000 #define DCFG_XCVRDLY_Pos (14U) -#define DCFG_XCVRDLY_Msk (0x1UL << DCFG_XCVRDLY_Pos) /*!< 0x00004000 */ +#define DCFG_XCVRDLY_Msk (0x1UL << DCFG_XCVRDLY_Pos) // 0x00004000 #define DCFG_XCVRDLY DCFG_XCVRDLY_Msk // Enables delay between xcvr_sel and txvalid during device chirp #define DCFG_PERSCHIVL_Pos (24U) -#define DCFG_PERSCHIVL_Msk (0x3UL << DCFG_PERSCHIVL_Pos) // 0x03000000 */ -#define DCFG_PERSCHIVL DCFG_PERSCHIVL_Msk // Periodic scheduling interval */ -#define DCFG_PERSCHIVL_0 (0x1UL << DCFG_PERSCHIVL_Pos) // 0x01000000 */ -#define DCFG_PERSCHIVL_1 (0x2UL << DCFG_PERSCHIVL_Pos) // 0x02000000 */ +#define DCFG_PERSCHIVL_Msk (0x3UL << DCFG_PERSCHIVL_Pos) // 0x03000000 +#define DCFG_PERSCHIVL DCFG_PERSCHIVL_Msk // Periodic scheduling interval +#define DCFG_PERSCHIVL_0 (0x1UL << DCFG_PERSCHIVL_Pos) // 0x01000000 +#define DCFG_PERSCHIVL_1 (0x2UL << DCFG_PERSCHIVL_Pos) // 0x02000000 /******************** Bit definition for DCTL register ********************/ #define DCTL_RWUSIG_Pos (0U) -#define DCTL_RWUSIG_Msk (0x1UL << DCTL_RWUSIG_Pos) // 0x00000001 */ -#define DCTL_RWUSIG DCTL_RWUSIG_Msk // Remote wakeup signaling */ +#define DCTL_RWUSIG_Msk (0x1UL << DCTL_RWUSIG_Pos) // 0x00000001 +#define DCTL_RWUSIG DCTL_RWUSIG_Msk // Remote wakeup signaling #define DCTL_SDIS_Pos (1U) -#define DCTL_SDIS_Msk (0x1UL << DCTL_SDIS_Pos) // 0x00000002 */ -#define DCTL_SDIS DCTL_SDIS_Msk // Soft disconnect */ +#define DCTL_SDIS_Msk (0x1UL << DCTL_SDIS_Pos) // 0x00000002 +#define DCTL_SDIS DCTL_SDIS_Msk // Soft disconnect #define DCTL_GINSTS_Pos (2U) -#define DCTL_GINSTS_Msk (0x1UL << DCTL_GINSTS_Pos) // 0x00000004 */ -#define DCTL_GINSTS DCTL_GINSTS_Msk // Global IN NAK status */ +#define DCTL_GINSTS_Msk (0x1UL << DCTL_GINSTS_Pos) // 0x00000004 +#define DCTL_GINSTS DCTL_GINSTS_Msk // Global IN NAK status #define DCTL_GONSTS_Pos (3U) -#define DCTL_GONSTS_Msk (0x1UL << DCTL_GONSTS_Pos) // 0x00000008 */ -#define DCTL_GONSTS DCTL_GONSTS_Msk // Global OUT NAK status */ +#define DCTL_GONSTS_Msk (0x1UL << DCTL_GONSTS_Pos) // 0x00000008 +#define DCTL_GONSTS DCTL_GONSTS_Msk // Global OUT NAK status #define DCTL_TCTL_Pos (4U) -#define DCTL_TCTL_Msk (0x7UL << DCTL_TCTL_Pos) // 0x00000070 */ -#define DCTL_TCTL DCTL_TCTL_Msk // Test control */ -#define DCTL_TCTL_0 (0x1UL << DCTL_TCTL_Pos) // 0x00000010 */ -#define DCTL_TCTL_1 (0x2UL << DCTL_TCTL_Pos) // 0x00000020 */ -#define DCTL_TCTL_2 (0x4UL << DCTL_TCTL_Pos) // 0x00000040 */ +#define DCTL_TCTL_Msk (0x7UL << DCTL_TCTL_Pos) // 0x00000070 +#define DCTL_TCTL DCTL_TCTL_Msk // Test control +#define DCTL_TCTL_0 (0x1UL << DCTL_TCTL_Pos) // 0x00000010 +#define DCTL_TCTL_1 (0x2UL << DCTL_TCTL_Pos) // 0x00000020 +#define DCTL_TCTL_2 (0x4UL << DCTL_TCTL_Pos) // 0x00000040 #define DCTL_SGINAK_Pos (7U) -#define DCTL_SGINAK_Msk (0x1UL << DCTL_SGINAK_Pos) // 0x00000080 */ -#define DCTL_SGINAK DCTL_SGINAK_Msk // Set global IN NAK */ +#define DCTL_SGINAK_Msk (0x1UL << DCTL_SGINAK_Pos) // 0x00000080 +#define DCTL_SGINAK DCTL_SGINAK_Msk // Set global IN NAK #define DCTL_CGINAK_Pos (8U) -#define DCTL_CGINAK_Msk (0x1UL << DCTL_CGINAK_Pos) // 0x00000100 */ -#define DCTL_CGINAK DCTL_CGINAK_Msk // Clear global IN NAK */ +#define DCTL_CGINAK_Msk (0x1UL << DCTL_CGINAK_Pos) // 0x00000100 +#define DCTL_CGINAK DCTL_CGINAK_Msk // Clear global IN NAK #define DCTL_SGONAK_Pos (9U) -#define DCTL_SGONAK_Msk (0x1UL << DCTL_SGONAK_Pos) // 0x00000200 */ -#define DCTL_SGONAK DCTL_SGONAK_Msk // Set global OUT NAK */ +#define DCTL_SGONAK_Msk (0x1UL << DCTL_SGONAK_Pos) // 0x00000200 +#define DCTL_SGONAK DCTL_SGONAK_Msk // Set global OUT NAK #define DCTL_CGONAK_Pos (10U) -#define DCTL_CGONAK_Msk (0x1UL << DCTL_CGONAK_Pos) // 0x00000400 */ -#define DCTL_CGONAK DCTL_CGONAK_Msk // Clear global OUT NAK */ +#define DCTL_CGONAK_Msk (0x1UL << DCTL_CGONAK_Pos) // 0x00000400 +#define DCTL_CGONAK DCTL_CGONAK_Msk // Clear global OUT NAK #define DCTL_POPRGDNE_Pos (11U) -#define DCTL_POPRGDNE_Msk (0x1UL << DCTL_POPRGDNE_Pos) // 0x00000800 */ -#define DCTL_POPRGDNE DCTL_POPRGDNE_Msk // Power-on programming done */ +#define DCTL_POPRGDNE_Msk (0x1UL << DCTL_POPRGDNE_Pos) // 0x00000800 +#define DCTL_POPRGDNE DCTL_POPRGDNE_Msk // Power-on programming done /******************** Bit definition for HFIR register ********************/ #define HFIR_FRIVL_Pos (0U) -#define HFIR_FRIVL_Msk (0xFFFFUL << HFIR_FRIVL_Pos) // 0x0000FFFF */ -#define HFIR_FRIVL HFIR_FRIVL_Msk // Frame interval */ +#define HFIR_FRIVL_Msk (0xFFFFUL << HFIR_FRIVL_Pos) // 0x0000FFFF +#define HFIR_FRIVL HFIR_FRIVL_Msk // Frame interval /******************** Bit definition for HFNUM register ********************/ #define HFNUM_FRNUM_Pos (0U) -#define HFNUM_FRNUM_Msk (0xFFFFUL << HFNUM_FRNUM_Pos) // 0x0000FFFF */ -#define HFNUM_FRNUM HFNUM_FRNUM_Msk // Frame number */ +#define HFNUM_FRNUM_Msk (0xFFFFUL << HFNUM_FRNUM_Pos) // 0x0000FFFF +#define HFNUM_FRNUM HFNUM_FRNUM_Msk // Frame number #define HFNUM_FTREM_Pos (16U) -#define HFNUM_FTREM_Msk (0xFFFFUL << HFNUM_FTREM_Pos) // 0xFFFF0000 */ -#define HFNUM_FTREM HFNUM_FTREM_Msk // Frame time remaining */ +#define HFNUM_FTREM_Msk (0xFFFFUL << HFNUM_FTREM_Pos) // 0xFFFF0000 +#define HFNUM_FTREM HFNUM_FTREM_Msk // Frame time remaining /******************** Bit definition for DSTS register ********************/ #define DSTS_SUSPSTS_Pos (0U) -#define DSTS_SUSPSTS_Msk (0x1UL << DSTS_SUSPSTS_Pos) // 0x00000001 */ -#define DSTS_SUSPSTS DSTS_SUSPSTS_Msk // Suspend status */ +#define DSTS_SUSPSTS_Msk (0x1UL << DSTS_SUSPSTS_Pos) // 0x00000001 +#define DSTS_SUSPSTS DSTS_SUSPSTS_Msk // Suspend status #define DSTS_ENUMSPD_Pos (1U) -#define DSTS_ENUMSPD_Msk (0x3UL << DSTS_ENUMSPD_Pos) // 0x00000006 */ -#define DSTS_ENUMSPD DSTS_ENUMSPD_Msk // Enumerated speed */ +#define DSTS_ENUMSPD_Msk (0x3UL << DSTS_ENUMSPD_Pos) // 0x00000006 +#define DSTS_ENUMSPD DSTS_ENUMSPD_Msk // Enumerated speed #define DSTS_ENUMSPD_HS 0 // Highspeed #define DSTS_ENUMSPD_FS_HSPHY 1 // Fullspeed on HS PHY #define DSTS_ENUMSPD_LS 2 // Lowspeed @@ -498,427 +499,427 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size"); #define DSTS_EERR_Pos (3U) -#define DSTS_EERR_Msk (0x1UL << DSTS_EERR_Pos) // 0x00000008 */ -#define DSTS_EERR DSTS_EERR_Msk // Erratic error */ +#define DSTS_EERR_Msk (0x1UL << DSTS_EERR_Pos) // 0x00000008 +#define DSTS_EERR DSTS_EERR_Msk // Erratic error #define DSTS_FNSOF_Pos (8U) -#define DSTS_FNSOF_Msk (0x3FFFUL << DSTS_FNSOF_Pos) // 0x003FFF00 */ -#define DSTS_FNSOF DSTS_FNSOF_Msk // Frame number of the received SOF */ +#define DSTS_FNSOF_Msk (0x3FFFUL << DSTS_FNSOF_Pos) // 0x003FFF00 +#define DSTS_FNSOF DSTS_FNSOF_Msk // Frame number of the received SOF /******************** Bit definition for GAHBCFG register ********************/ #define GAHBCFG_GINT_Pos (0U) -#define GAHBCFG_GINT_Msk (0x1UL << GAHBCFG_GINT_Pos) // 0x00000001 */ -#define GAHBCFG_GINT GAHBCFG_GINT_Msk // Global interrupt mask */ +#define GAHBCFG_GINT_Msk (0x1UL << GAHBCFG_GINT_Pos) // 0x00000001 +#define GAHBCFG_GINT GAHBCFG_GINT_Msk // Global interrupt mask #define GAHBCFG_HBSTLEN_Pos (1U) -#define GAHBCFG_HBSTLEN_Msk (0xFUL << GAHBCFG_HBSTLEN_Pos) // 0x0000001E */ -#define GAHBCFG_HBSTLEN GAHBCFG_HBSTLEN_Msk // Burst length/type */ -#define GAHBCFG_HBSTLEN_0 (0x0UL << GAHBCFG_HBSTLEN_Pos) // Single */ -#define GAHBCFG_HBSTLEN_1 (0x1UL << GAHBCFG_HBSTLEN_Pos) // INCR */ -#define GAHBCFG_HBSTLEN_2 (0x3UL << GAHBCFG_HBSTLEN_Pos) // INCR4 */ -#define GAHBCFG_HBSTLEN_3 (0x5UL << GAHBCFG_HBSTLEN_Pos) // INCR8 */ -#define GAHBCFG_HBSTLEN_4 (0x7UL << GAHBCFG_HBSTLEN_Pos) // INCR16 */ +#define GAHBCFG_HBSTLEN_Msk (0xFUL << GAHBCFG_HBSTLEN_Pos) // 0x0000001E +#define GAHBCFG_HBSTLEN GAHBCFG_HBSTLEN_Msk // Burst length/type +#define GAHBCFG_HBSTLEN_0 (0x0UL << GAHBCFG_HBSTLEN_Pos) // Single +#define GAHBCFG_HBSTLEN_1 (0x1UL << GAHBCFG_HBSTLEN_Pos) // INCR +#define GAHBCFG_HBSTLEN_2 (0x3UL << GAHBCFG_HBSTLEN_Pos) // INCR4 +#define GAHBCFG_HBSTLEN_3 (0x5UL << GAHBCFG_HBSTLEN_Pos) // INCR8 +#define GAHBCFG_HBSTLEN_4 (0x7UL << GAHBCFG_HBSTLEN_Pos) // INCR16 #define GAHBCFG_DMAEN_Pos (5U) -#define GAHBCFG_DMAEN_Msk (0x1UL << GAHBCFG_DMAEN_Pos) // 0x00000020 */ -#define GAHBCFG_DMAEN GAHBCFG_DMAEN_Msk // DMA enable */ +#define GAHBCFG_DMAEN_Msk (0x1UL << GAHBCFG_DMAEN_Pos) // 0x00000020 +#define GAHBCFG_DMAEN GAHBCFG_DMAEN_Msk // DMA enable #define GAHBCFG_TXFELVL_Pos (7U) -#define GAHBCFG_TXFELVL_Msk (0x1UL << GAHBCFG_TXFELVL_Pos) // 0x00000080 */ -#define GAHBCFG_TXFELVL GAHBCFG_TXFELVL_Msk // TxFIFO empty level */ +#define GAHBCFG_TXFELVL_Msk (0x1UL << GAHBCFG_TXFELVL_Pos) // 0x00000080 +#define GAHBCFG_TXFELVL GAHBCFG_TXFELVL_Msk // TxFIFO empty level #define GAHBCFG_PTXFELVL_Pos (8U) -#define GAHBCFG_PTXFELVL_Msk (0x1UL << GAHBCFG_PTXFELVL_Pos) // 0x00000100 */ -#define GAHBCFG_PTXFELVL GAHBCFG_PTXFELVL_Msk // Periodic TxFIFO empty level */ +#define GAHBCFG_PTXFELVL_Msk (0x1UL << GAHBCFG_PTXFELVL_Pos) // 0x00000100 +#define GAHBCFG_PTXFELVL GAHBCFG_PTXFELVL_Msk // Periodic TxFIFO empty level #define GSNPSID_ID_MASK TU_GENMASK(31, 16) /******************** Bit definition for GUSBCFG register ********************/ #define GUSBCFG_TOCAL_Pos (0U) -#define GUSBCFG_TOCAL_Msk (0x7UL << GUSBCFG_TOCAL_Pos) // 0x00000007 */ -#define GUSBCFG_TOCAL GUSBCFG_TOCAL_Msk // FS timeout calibration */ +#define GUSBCFG_TOCAL_Msk (0x7UL << GUSBCFG_TOCAL_Pos) // 0x00000007 +#define GUSBCFG_TOCAL GUSBCFG_TOCAL_Msk // FS timeout calibration #define GUSBCFG_PHYIF16_Pos (3U) -#define GUSBCFG_PHYIF16_Msk (0x1UL << GUSBCFG_PHYIF16_Pos) // 0x00000008 */ -#define GUSBCFG_PHYIF16 GUSBCFG_PHYIF16_Msk // PHY Interface (PHYIf) */ +#define GUSBCFG_PHYIF16_Msk (0x1UL << GUSBCFG_PHYIF16_Pos) // 0x00000008 +#define GUSBCFG_PHYIF16 GUSBCFG_PHYIF16_Msk // PHY Interface (PHYIf) #define GUSBCFG_ULPI_UTMI_SEL_Pos (4U) -#define GUSBCFG_ULPI_UTMI_SEL_Msk (0x1UL << GUSBCFG_ULPI_UTMI_SEL_Pos) // 0x00000010 */ -#define GUSBCFG_ULPI_UTMI_SEL GUSBCFG_ULPI_UTMI_SEL_Msk // ULPI or UTMI+ Select (ULPI_UTMI_Sel) */ +#define GUSBCFG_ULPI_UTMI_SEL_Msk (0x1UL << GUSBCFG_ULPI_UTMI_SEL_Pos) // 0x00000010 +#define GUSBCFG_ULPI_UTMI_SEL GUSBCFG_ULPI_UTMI_SEL_Msk // ULPI or UTMI+ Select (ULPI_UTMI_Sel) #define GUSBCFG_PHYSEL_Pos (6U) -#define GUSBCFG_PHYSEL_Msk (0x1UL << GUSBCFG_PHYSEL_Pos) // 0x00000040 */ -#define GUSBCFG_PHYSEL GUSBCFG_PHYSEL_Msk // USB 2.0 high-speed ULPI PHY or USB 1.1 full-speed serial transceiver select */ +#define GUSBCFG_PHYSEL_Msk (0x1UL << GUSBCFG_PHYSEL_Pos) // 0x00000040 +#define GUSBCFG_PHYSEL GUSBCFG_PHYSEL_Msk // USB 2.0 high-speed ULPI PHY or USB 1.1 full-speed serial transceiver select #define GUSBCFG_DDRSEL TU_BIT(7) // Single Data Rate (SDR) or Double Data Rate (DDR) or ULPI interface. #define GUSBCFG_SRPCAP_Pos (8U) -#define GUSBCFG_SRPCAP_Msk (0x1UL << GUSBCFG_SRPCAP_Pos) // 0x00000100 */ -#define GUSBCFG_SRPCAP GUSBCFG_SRPCAP_Msk // SRP-capable */ +#define GUSBCFG_SRPCAP_Msk (0x1UL << GUSBCFG_SRPCAP_Pos) // 0x00000100 +#define GUSBCFG_SRPCAP GUSBCFG_SRPCAP_Msk // SRP-capable #define GUSBCFG_HNPCAP_Pos (9U) -#define GUSBCFG_HNPCAP_Msk (0x1UL << GUSBCFG_HNPCAP_Pos) // 0x00000200 */ -#define GUSBCFG_HNPCAP GUSBCFG_HNPCAP_Msk // HNP-capable */ +#define GUSBCFG_HNPCAP_Msk (0x1UL << GUSBCFG_HNPCAP_Pos) // 0x00000200 +#define GUSBCFG_HNPCAP GUSBCFG_HNPCAP_Msk // HNP-capable #define GUSBCFG_TRDT_Pos (10U) -#define GUSBCFG_TRDT_Msk (0xFUL << GUSBCFG_TRDT_Pos) // 0x00003C00 */ -#define GUSBCFG_TRDT GUSBCFG_TRDT_Msk // USB turnaround time */ +#define GUSBCFG_TRDT_Msk (0xFUL << GUSBCFG_TRDT_Pos) // 0x00003C00 +#define GUSBCFG_TRDT GUSBCFG_TRDT_Msk // USB turnaround time #define GUSBCFG_PHYLPCS_Pos (15U) -#define GUSBCFG_PHYLPCS_Msk (0x1UL << GUSBCFG_PHYLPCS_Pos) // 0x00008000 */ -#define GUSBCFG_PHYLPCS GUSBCFG_PHYLPCS_Msk // PHY Low-power clock select */ +#define GUSBCFG_PHYLPCS_Msk (0x1UL << GUSBCFG_PHYLPCS_Pos) // 0x00008000 +#define GUSBCFG_PHYLPCS GUSBCFG_PHYLPCS_Msk // PHY Low-power clock select #define GUSBCFG_ULPIFSLS_Pos (17U) -#define GUSBCFG_ULPIFSLS_Msk (0x1UL << GUSBCFG_ULPIFSLS_Pos) // 0x00020000 */ -#define GUSBCFG_ULPIFSLS GUSBCFG_ULPIFSLS_Msk // ULPI FS/LS select */ +#define GUSBCFG_ULPIFSLS_Msk (0x1UL << GUSBCFG_ULPIFSLS_Pos) // 0x00020000 +#define GUSBCFG_ULPIFSLS GUSBCFG_ULPIFSLS_Msk // ULPI FS/LS select #define GUSBCFG_ULPIAR_Pos (18U) -#define GUSBCFG_ULPIAR_Msk (0x1UL << GUSBCFG_ULPIAR_Pos) // 0x00040000 */ -#define GUSBCFG_ULPIAR GUSBCFG_ULPIAR_Msk // ULPI Auto-resume */ +#define GUSBCFG_ULPIAR_Msk (0x1UL << GUSBCFG_ULPIAR_Pos) // 0x00040000 +#define GUSBCFG_ULPIAR GUSBCFG_ULPIAR_Msk // ULPI Auto-resume #define GUSBCFG_ULPICSM_Pos (19U) -#define GUSBCFG_ULPICSM_Msk (0x1UL << GUSBCFG_ULPICSM_Pos) // 0x00080000 */ -#define GUSBCFG_ULPICSM GUSBCFG_ULPICSM_Msk // ULPI Clock SuspendM */ +#define GUSBCFG_ULPICSM_Msk (0x1UL << GUSBCFG_ULPICSM_Pos) // 0x00080000 +#define GUSBCFG_ULPICSM GUSBCFG_ULPICSM_Msk // ULPI Clock SuspendM #define GUSBCFG_ULPIEVBUSD_Pos (20U) -#define GUSBCFG_ULPIEVBUSD_Msk (0x1UL << GUSBCFG_ULPIEVBUSD_Pos) // 0x00100000 */ -#define GUSBCFG_ULPIEVBUSD GUSBCFG_ULPIEVBUSD_Msk // ULPI External VBUS Drive */ +#define GUSBCFG_ULPIEVBUSD_Msk (0x1UL << GUSBCFG_ULPIEVBUSD_Pos) // 0x00100000 +#define GUSBCFG_ULPIEVBUSD GUSBCFG_ULPIEVBUSD_Msk // ULPI External VBUS Drive #define GUSBCFG_ULPIEVBUSI_Pos (21U) -#define GUSBCFG_ULPIEVBUSI_Msk (0x1UL << GUSBCFG_ULPIEVBUSI_Pos) // 0x00200000 */ -#define GUSBCFG_ULPIEVBUSI GUSBCFG_ULPIEVBUSI_Msk // ULPI external VBUS indicator */ +#define GUSBCFG_ULPIEVBUSI_Msk (0x1UL << GUSBCFG_ULPIEVBUSI_Pos) // 0x00200000 +#define GUSBCFG_ULPIEVBUSI GUSBCFG_ULPIEVBUSI_Msk // ULPI external VBUS indicator #define GUSBCFG_TSDPS_Pos (22U) -#define GUSBCFG_TSDPS_Msk (0x1UL << GUSBCFG_TSDPS_Pos) // 0x00400000 */ -#define GUSBCFG_TSDPS GUSBCFG_TSDPS_Msk // TermSel DLine pulsing selection */ +#define GUSBCFG_TSDPS_Msk (0x1UL << GUSBCFG_TSDPS_Pos) // 0x00400000 +#define GUSBCFG_TSDPS GUSBCFG_TSDPS_Msk // TermSel DLine pulsing selection #define GUSBCFG_PCCI_Pos (23U) -#define GUSBCFG_PCCI_Msk (0x1UL << GUSBCFG_PCCI_Pos) // 0x00800000 */ -#define GUSBCFG_PCCI GUSBCFG_PCCI_Msk // Indicator complement */ +#define GUSBCFG_PCCI_Msk (0x1UL << GUSBCFG_PCCI_Pos) // 0x00800000 +#define GUSBCFG_PCCI GUSBCFG_PCCI_Msk // Indicator complement #define GUSBCFG_PTCI_Pos (24U) -#define GUSBCFG_PTCI_Msk (0x1UL << GUSBCFG_PTCI_Pos) // 0x01000000 */ -#define GUSBCFG_PTCI GUSBCFG_PTCI_Msk // Indicator pass through */ +#define GUSBCFG_PTCI_Msk (0x1UL << GUSBCFG_PTCI_Pos) // 0x01000000 +#define GUSBCFG_PTCI GUSBCFG_PTCI_Msk // Indicator pass through #define GUSBCFG_ULPIIPD_Pos (25U) -#define GUSBCFG_ULPIIPD_Msk (0x1UL << GUSBCFG_ULPIIPD_Pos) // 0x02000000 */ -#define GUSBCFG_ULPIIPD GUSBCFG_ULPIIPD_Msk // ULPI interface protect disable */ +#define GUSBCFG_ULPIIPD_Msk (0x1UL << GUSBCFG_ULPIIPD_Pos) // 0x02000000 +#define GUSBCFG_ULPIIPD GUSBCFG_ULPIIPD_Msk // ULPI interface protect disable #define GUSBCFG_FHMOD_Pos (29U) -#define GUSBCFG_FHMOD_Msk (0x1UL << GUSBCFG_FHMOD_Pos) // 0x20000000 */ -#define GUSBCFG_FHMOD GUSBCFG_FHMOD_Msk // Forced host mode */ +#define GUSBCFG_FHMOD_Msk (0x1UL << GUSBCFG_FHMOD_Pos) // 0x20000000 +#define GUSBCFG_FHMOD GUSBCFG_FHMOD_Msk // Forced host mode #define GUSBCFG_FDMOD_Pos (30U) -#define GUSBCFG_FDMOD_Msk (0x1UL << GUSBCFG_FDMOD_Pos) // 0x40000000 */ -#define GUSBCFG_FDMOD GUSBCFG_FDMOD_Msk // Forced peripheral mode */ +#define GUSBCFG_FDMOD_Msk (0x1UL << GUSBCFG_FDMOD_Pos) // 0x40000000 +#define GUSBCFG_FDMOD GUSBCFG_FDMOD_Msk // Forced peripheral mode #define GUSBCFG_CTXPKT_Pos (31U) -#define GUSBCFG_CTXPKT_Msk (0x1UL << GUSBCFG_CTXPKT_Pos) // 0x80000000 */ -#define GUSBCFG_CTXPKT GUSBCFG_CTXPKT_Msk // Corrupt Tx packet */ +#define GUSBCFG_CTXPKT_Msk (0x1UL << GUSBCFG_CTXPKT_Pos) // 0x80000000 +#define GUSBCFG_CTXPKT GUSBCFG_CTXPKT_Msk // Corrupt Tx packet /******************** Bit definition for GRSTCTL register ********************/ #define GRSTCTL_CSRST_Pos (0U) -#define GRSTCTL_CSRST_Msk (0x1UL << GRSTCTL_CSRST_Pos) // 0x00000001 */ -#define GRSTCTL_CSRST GRSTCTL_CSRST_Msk // Core soft reset */ +#define GRSTCTL_CSRST_Msk (0x1UL << GRSTCTL_CSRST_Pos) // 0x00000001 +#define GRSTCTL_CSRST GRSTCTL_CSRST_Msk // Core soft reset #define GRSTCTL_HSRST_Pos (1U) -#define GRSTCTL_HSRST_Msk (0x1UL << GRSTCTL_HSRST_Pos) // 0x00000002 */ -#define GRSTCTL_HSRST GRSTCTL_HSRST_Msk // HCLK soft reset */ +#define GRSTCTL_HSRST_Msk (0x1UL << GRSTCTL_HSRST_Pos) // 0x00000002 +#define GRSTCTL_HSRST GRSTCTL_HSRST_Msk // HCLK soft reset #define GRSTCTL_FCRST_Pos (2U) -#define GRSTCTL_FCRST_Msk (0x1UL << GRSTCTL_FCRST_Pos) // 0x00000004 */ -#define GRSTCTL_FCRST GRSTCTL_FCRST_Msk // Host frame counter reset */ +#define GRSTCTL_FCRST_Msk (0x1UL << GRSTCTL_FCRST_Pos) // 0x00000004 +#define GRSTCTL_FCRST GRSTCTL_FCRST_Msk // Host frame counter reset #define GRSTCTL_RXFFLSH_Pos (4U) -#define GRSTCTL_RXFFLSH_Msk (0x1UL << GRSTCTL_RXFFLSH_Pos) // 0x00000010 */ -#define GRSTCTL_RXFFLSH GRSTCTL_RXFFLSH_Msk // RxFIFO flush */ +#define GRSTCTL_RXFFLSH_Msk (0x1UL << GRSTCTL_RXFFLSH_Pos) // 0x00000010 +#define GRSTCTL_RXFFLSH GRSTCTL_RXFFLSH_Msk // RxFIFO flush #define GRSTCTL_TXFFLSH_Pos (5U) -#define GRSTCTL_TXFFLSH_Msk (0x1UL << GRSTCTL_TXFFLSH_Pos) // 0x00000020 */ -#define GRSTCTL_TXFFLSH GRSTCTL_TXFFLSH_Msk // TxFIFO flush */ +#define GRSTCTL_TXFFLSH_Msk (0x1UL << GRSTCTL_TXFFLSH_Pos) // 0x00000020 +#define GRSTCTL_TXFFLSH GRSTCTL_TXFFLSH_Msk // TxFIFO flush #define GRSTCTL_TXFNUM_Pos (6U) -#define GRSTCTL_TXFNUM_Msk (0x1FUL << GRSTCTL_TXFNUM_Pos) // 0x000007C0 */ -#define GRSTCTL_TXFNUM GRSTCTL_TXFNUM_Msk // TxFIFO number */ -#define GRSTCTL_TXFNUM_0 (0x01UL << GRSTCTL_TXFNUM_Pos) // 0x00000040 */ -#define GRSTCTL_TXFNUM_1 (0x02UL << GRSTCTL_TXFNUM_Pos) // 0x00000080 */ -#define GRSTCTL_TXFNUM_2 (0x04UL << GRSTCTL_TXFNUM_Pos) // 0x00000100 */ -#define GRSTCTL_TXFNUM_3 (0x08UL << GRSTCTL_TXFNUM_Pos) // 0x00000200 */ -#define GRSTCTL_TXFNUM_4 (0x10UL << GRSTCTL_TXFNUM_Pos) // 0x00000400 */ +#define GRSTCTL_TXFNUM_Msk (0x1FUL << GRSTCTL_TXFNUM_Pos) // 0x000007C0 +#define GRSTCTL_TXFNUM GRSTCTL_TXFNUM_Msk // TxFIFO number +#define GRSTCTL_TXFNUM_0 (0x01UL << GRSTCTL_TXFNUM_Pos) // 0x00000040 +#define GRSTCTL_TXFNUM_1 (0x02UL << GRSTCTL_TXFNUM_Pos) // 0x00000080 +#define GRSTCTL_TXFNUM_2 (0x04UL << GRSTCTL_TXFNUM_Pos) // 0x00000100 +#define GRSTCTL_TXFNUM_3 (0x08UL << GRSTCTL_TXFNUM_Pos) // 0x00000200 +#define GRSTCTL_TXFNUM_4 (0x10UL << GRSTCTL_TXFNUM_Pos) // 0x00000400 #define GRSTCTL_CSFTRST_DONE_Pos (29) #define GRSTCTL_CSFTRST_DONE (1u << GRSTCTL_CSFTRST_DONE_Pos) // Reset Done, only available from v4.20a #define GRSTCTL_DMAREQ_Pos (30U) -#define GRSTCTL_DMAREQ_Msk (0x1UL << GRSTCTL_DMAREQ_Pos) // 0x40000000 */ -#define GRSTCTL_DMAREQ GRSTCTL_DMAREQ_Msk // DMA request signal */ +#define GRSTCTL_DMAREQ_Msk (0x1UL << GRSTCTL_DMAREQ_Pos) // 0x40000000 +#define GRSTCTL_DMAREQ GRSTCTL_DMAREQ_Msk // DMA request signal #define GRSTCTL_AHBIDL_Pos (31U) -#define GRSTCTL_AHBIDL_Msk (0x1UL << GRSTCTL_AHBIDL_Pos) // 0x80000000 */ -#define GRSTCTL_AHBIDL GRSTCTL_AHBIDL_Msk // AHB master idle */ +#define GRSTCTL_AHBIDL_Msk (0x1UL << GRSTCTL_AHBIDL_Pos) // 0x80000000 +#define GRSTCTL_AHBIDL GRSTCTL_AHBIDL_Msk // AHB master idle /******************** Bit definition for DIEPMSK register ********************/ #define DIEPMSK_XFRCM_Pos (0U) -#define DIEPMSK_XFRCM_Msk (0x1UL << DIEPMSK_XFRCM_Pos) // 0x00000001 */ -#define DIEPMSK_XFRCM DIEPMSK_XFRCM_Msk // Transfer completed interrupt mask */ +#define DIEPMSK_XFRCM_Msk (0x1UL << DIEPMSK_XFRCM_Pos) // 0x00000001 +#define DIEPMSK_XFRCM DIEPMSK_XFRCM_Msk // Transfer completed interrupt mask #define DIEPMSK_EPDM_Pos (1U) -#define DIEPMSK_EPDM_Msk (0x1UL << DIEPMSK_EPDM_Pos) // 0x00000002 */ -#define DIEPMSK_EPDM DIEPMSK_EPDM_Msk // Endpoint disabled interrupt mask */ +#define DIEPMSK_EPDM_Msk (0x1UL << DIEPMSK_EPDM_Pos) // 0x00000002 +#define DIEPMSK_EPDM DIEPMSK_EPDM_Msk // Endpoint disabled interrupt mask #define DIEPMSK_TOM_Pos (3U) -#define DIEPMSK_TOM_Msk (0x1UL << DIEPMSK_TOM_Pos) // 0x00000008 */ -#define DIEPMSK_TOM DIEPMSK_TOM_Msk // Timeout condition mask (nonisochronous endpoints) */ +#define DIEPMSK_TOM_Msk (0x1UL << DIEPMSK_TOM_Pos) // 0x00000008 +#define DIEPMSK_TOM DIEPMSK_TOM_Msk // Timeout condition mask (nonisochronous endpoints) #define DIEPMSK_ITTXFEMSK_Pos (4U) -#define DIEPMSK_ITTXFEMSK_Msk (0x1UL << DIEPMSK_ITTXFEMSK_Pos) // 0x00000010 */ -#define DIEPMSK_ITTXFEMSK DIEPMSK_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask */ +#define DIEPMSK_ITTXFEMSK_Msk (0x1UL << DIEPMSK_ITTXFEMSK_Pos) // 0x00000010 +#define DIEPMSK_ITTXFEMSK DIEPMSK_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask #define DIEPMSK_INEPNMM_Pos (5U) -#define DIEPMSK_INEPNMM_Msk (0x1UL << DIEPMSK_INEPNMM_Pos) // 0x00000020 */ -#define DIEPMSK_INEPNMM DIEPMSK_INEPNMM_Msk // IN token received with EP mismatch mask */ +#define DIEPMSK_INEPNMM_Msk (0x1UL << DIEPMSK_INEPNMM_Pos) // 0x00000020 +#define DIEPMSK_INEPNMM DIEPMSK_INEPNMM_Msk // IN token received with EP mismatch mask #define DIEPMSK_INEPNEM_Pos (6U) -#define DIEPMSK_INEPNEM_Msk (0x1UL << DIEPMSK_INEPNEM_Pos) // 0x00000040 */ -#define DIEPMSK_INEPNEM DIEPMSK_INEPNEM_Msk // IN endpoint NAK effective mask */ +#define DIEPMSK_INEPNEM_Msk (0x1UL << DIEPMSK_INEPNEM_Pos) // 0x00000040 +#define DIEPMSK_INEPNEM DIEPMSK_INEPNEM_Msk // IN endpoint NAK effective mask #define DIEPMSK_TXFURM_Pos (8U) -#define DIEPMSK_TXFURM_Msk (0x1UL << DIEPMSK_TXFURM_Pos) // 0x00000100 */ -#define DIEPMSK_TXFURM DIEPMSK_TXFURM_Msk // FIFO underrun mask */ +#define DIEPMSK_TXFURM_Msk (0x1UL << DIEPMSK_TXFURM_Pos) // 0x00000100 +#define DIEPMSK_TXFURM DIEPMSK_TXFURM_Msk // FIFO underrun mask #define DIEPMSK_BIM_Pos (9U) -#define DIEPMSK_BIM_Msk (0x1UL << DIEPMSK_BIM_Pos) // 0x00000200 */ -#define DIEPMSK_BIM DIEPMSK_BIM_Msk // BNA interrupt mask */ +#define DIEPMSK_BIM_Msk (0x1UL << DIEPMSK_BIM_Pos) // 0x00000200 +#define DIEPMSK_BIM DIEPMSK_BIM_Msk // BNA interrupt mask /******************** Bit definition for HPTXSTS register ********************/ #define HPTXSTS_PTXFSAVL_Pos (0U) -#define HPTXSTS_PTXFSAVL_Msk (0xFFFFUL << HPTXSTS_PTXFSAVL_Pos) // 0x0000FFFF */ -#define HPTXSTS_PTXFSAVL HPTXSTS_PTXFSAVL_Msk // Periodic transmit data FIFO space available */ +#define HPTXSTS_PTXFSAVL_Msk (0xFFFFUL << HPTXSTS_PTXFSAVL_Pos) // 0x0000FFFF +#define HPTXSTS_PTXFSAVL HPTXSTS_PTXFSAVL_Msk // Periodic transmit data FIFO space available #define HPTXSTS_PTXQSAV_Pos (16U) -#define HPTXSTS_PTXQSAV_Msk (0xFFUL << HPTXSTS_PTXQSAV_Pos) // 0x00FF0000 */ -#define HPTXSTS_PTXQSAV HPTXSTS_PTXQSAV_Msk // Periodic transmit request queue space available */ -#define HPTXSTS_PTXQSAV_0 (0x01UL << HPTXSTS_PTXQSAV_Pos) // 0x00010000 */ -#define HPTXSTS_PTXQSAV_1 (0x02UL << HPTXSTS_PTXQSAV_Pos) // 0x00020000 */ -#define HPTXSTS_PTXQSAV_2 (0x04UL << HPTXSTS_PTXQSAV_Pos) // 0x00040000 */ -#define HPTXSTS_PTXQSAV_3 (0x08UL << HPTXSTS_PTXQSAV_Pos) // 0x00080000 */ -#define HPTXSTS_PTXQSAV_4 (0x10UL << HPTXSTS_PTXQSAV_Pos) // 0x00100000 */ -#define HPTXSTS_PTXQSAV_5 (0x20UL << HPTXSTS_PTXQSAV_Pos) // 0x00200000 */ -#define HPTXSTS_PTXQSAV_6 (0x40UL << HPTXSTS_PTXQSAV_Pos) // 0x00400000 */ -#define HPTXSTS_PTXQSAV_7 (0x80UL << HPTXSTS_PTXQSAV_Pos) // 0x00800000 */ +#define HPTXSTS_PTXQSAV_Msk (0xFFUL << HPTXSTS_PTXQSAV_Pos) // 0x00FF0000 +#define HPTXSTS_PTXQSAV HPTXSTS_PTXQSAV_Msk // Periodic transmit request queue space available +#define HPTXSTS_PTXQSAV_0 (0x01UL << HPTXSTS_PTXQSAV_Pos) // 0x00010000 +#define HPTXSTS_PTXQSAV_1 (0x02UL << HPTXSTS_PTXQSAV_Pos) // 0x00020000 +#define HPTXSTS_PTXQSAV_2 (0x04UL << HPTXSTS_PTXQSAV_Pos) // 0x00040000 +#define HPTXSTS_PTXQSAV_3 (0x08UL << HPTXSTS_PTXQSAV_Pos) // 0x00080000 +#define HPTXSTS_PTXQSAV_4 (0x10UL << HPTXSTS_PTXQSAV_Pos) // 0x00100000 +#define HPTXSTS_PTXQSAV_5 (0x20UL << HPTXSTS_PTXQSAV_Pos) // 0x00200000 +#define HPTXSTS_PTXQSAV_6 (0x40UL << HPTXSTS_PTXQSAV_Pos) // 0x00400000 +#define HPTXSTS_PTXQSAV_7 (0x80UL << HPTXSTS_PTXQSAV_Pos) // 0x00800000 #define HPTXSTS_PTXQTOP_Pos (24U) -#define HPTXSTS_PTXQTOP_Msk (0xFFUL << HPTXSTS_PTXQTOP_Pos) // 0xFF000000 */ -#define HPTXSTS_PTXQTOP HPTXSTS_PTXQTOP_Msk // Top of the periodic transmit request queue */ -#define HPTXSTS_PTXQTOP_0 (0x01UL << HPTXSTS_PTXQTOP_Pos) // 0x01000000 */ -#define HPTXSTS_PTXQTOP_1 (0x02UL << HPTXSTS_PTXQTOP_Pos) // 0x02000000 */ -#define HPTXSTS_PTXQTOP_2 (0x04UL << HPTXSTS_PTXQTOP_Pos) // 0x04000000 */ -#define HPTXSTS_PTXQTOP_3 (0x08UL << HPTXSTS_PTXQTOP_Pos) // 0x08000000 */ -#define HPTXSTS_PTXQTOP_4 (0x10UL << HPTXSTS_PTXQTOP_Pos) // 0x10000000 */ -#define HPTXSTS_PTXQTOP_5 (0x20UL << HPTXSTS_PTXQTOP_Pos) // 0x20000000 */ -#define HPTXSTS_PTXQTOP_6 (0x40UL << HPTXSTS_PTXQTOP_Pos) // 0x40000000 */ -#define HPTXSTS_PTXQTOP_7 (0x80UL << HPTXSTS_PTXQTOP_Pos) // 0x80000000 */ +#define HPTXSTS_PTXQTOP_Msk (0xFFUL << HPTXSTS_PTXQTOP_Pos) // 0xFF000000 +#define HPTXSTS_PTXQTOP HPTXSTS_PTXQTOP_Msk // Top of the periodic transmit request queue +#define HPTXSTS_PTXQTOP_0 (0x01UL << HPTXSTS_PTXQTOP_Pos) // 0x01000000 +#define HPTXSTS_PTXQTOP_1 (0x02UL << HPTXSTS_PTXQTOP_Pos) // 0x02000000 +#define HPTXSTS_PTXQTOP_2 (0x04UL << HPTXSTS_PTXQTOP_Pos) // 0x04000000 +#define HPTXSTS_PTXQTOP_3 (0x08UL << HPTXSTS_PTXQTOP_Pos) // 0x08000000 +#define HPTXSTS_PTXQTOP_4 (0x10UL << HPTXSTS_PTXQTOP_Pos) // 0x10000000 +#define HPTXSTS_PTXQTOP_5 (0x20UL << HPTXSTS_PTXQTOP_Pos) // 0x20000000 +#define HPTXSTS_PTXQTOP_6 (0x40UL << HPTXSTS_PTXQTOP_Pos) // 0x40000000 +#define HPTXSTS_PTXQTOP_7 (0x80UL << HPTXSTS_PTXQTOP_Pos) // 0x80000000 /******************** Bit definition for HAINT register ********************/ #define HAINT_HAINT_Pos (0U) -#define HAINT_HAINT_Msk (0xFFFFUL << HAINT_HAINT_Pos) // 0x0000FFFF */ -#define HAINT_HAINT HAINT_HAINT_Msk // Channel interrupts */ +#define HAINT_HAINT_Msk (0xFFFFUL << HAINT_HAINT_Pos) // 0x0000FFFF +#define HAINT_HAINT HAINT_HAINT_Msk // Channel interrupts /******************** Bit definition for DOEPMSK register ********************/ #define DOEPMSK_XFRCM_Pos (0U) -#define DOEPMSK_XFRCM_Msk (0x1UL << DOEPMSK_XFRCM_Pos) // 0x00000001 */ -#define DOEPMSK_XFRCM DOEPMSK_XFRCM_Msk // Transfer completed interrupt mask */ +#define DOEPMSK_XFRCM_Msk (0x1UL << DOEPMSK_XFRCM_Pos) // 0x00000001 +#define DOEPMSK_XFRCM DOEPMSK_XFRCM_Msk // Transfer completed interrupt mask #define DOEPMSK_EPDM_Pos (1U) -#define DOEPMSK_EPDM_Msk (0x1UL << DOEPMSK_EPDM_Pos) // 0x00000002 */ -#define DOEPMSK_EPDM DOEPMSK_EPDM_Msk // Endpoint disabled interrupt mask */ +#define DOEPMSK_EPDM_Msk (0x1UL << DOEPMSK_EPDM_Pos) // 0x00000002 +#define DOEPMSK_EPDM DOEPMSK_EPDM_Msk // Endpoint disabled interrupt mask #define DOEPMSK_AHBERRM_Pos (2U) -#define DOEPMSK_AHBERRM_Msk (0x1UL << DOEPMSK_AHBERRM_Pos) // 0x00000004 */ -#define DOEPMSK_AHBERRM DOEPMSK_AHBERRM_Msk // OUT transaction AHB Error interrupt mask */ +#define DOEPMSK_AHBERRM_Msk (0x1UL << DOEPMSK_AHBERRM_Pos) // 0x00000004 +#define DOEPMSK_AHBERRM DOEPMSK_AHBERRM_Msk // OUT transaction AHB Error interrupt mask #define DOEPMSK_STUPM_Pos (3U) -#define DOEPMSK_STUPM_Msk (0x1UL << DOEPMSK_STUPM_Pos) // 0x00000008 */ -#define DOEPMSK_STUPM DOEPMSK_STUPM_Msk // SETUP phase done mask */ +#define DOEPMSK_STUPM_Msk (0x1UL << DOEPMSK_STUPM_Pos) // 0x00000008 +#define DOEPMSK_STUPM DOEPMSK_STUPM_Msk // SETUP phase done mask #define DOEPMSK_OTEPDM_Pos (4U) -#define DOEPMSK_OTEPDM_Msk (0x1UL << DOEPMSK_OTEPDM_Pos) // 0x00000010 */ -#define DOEPMSK_OTEPDM DOEPMSK_OTEPDM_Msk // OUT token received when endpoint disabled mask */ +#define DOEPMSK_OTEPDM_Msk (0x1UL << DOEPMSK_OTEPDM_Pos) // 0x00000010 +#define DOEPMSK_OTEPDM DOEPMSK_OTEPDM_Msk // OUT token received when endpoint disabled mask #define DOEPMSK_OTEPSPRM_Pos (5U) -#define DOEPMSK_OTEPSPRM_Msk (0x1UL << DOEPMSK_OTEPSPRM_Pos) // 0x00000020 */ -#define DOEPMSK_OTEPSPRM DOEPMSK_OTEPSPRM_Msk // Status Phase Received mask */ +#define DOEPMSK_OTEPSPRM_Msk (0x1UL << DOEPMSK_OTEPSPRM_Pos) // 0x00000020 +#define DOEPMSK_OTEPSPRM DOEPMSK_OTEPSPRM_Msk // Status Phase Received mask #define DOEPMSK_B2BSTUP_Pos (6U) -#define DOEPMSK_B2BSTUP_Msk (0x1UL << DOEPMSK_B2BSTUP_Pos) // 0x00000040 */ -#define DOEPMSK_B2BSTUP DOEPMSK_B2BSTUP_Msk // Back-to-back SETUP packets received mask */ +#define DOEPMSK_B2BSTUP_Msk (0x1UL << DOEPMSK_B2BSTUP_Pos) // 0x00000040 +#define DOEPMSK_B2BSTUP DOEPMSK_B2BSTUP_Msk // Back-to-back SETUP packets received mask #define DOEPMSK_OPEM_Pos (8U) -#define DOEPMSK_OPEM_Msk (0x1UL << DOEPMSK_OPEM_Pos) // 0x00000100 */ -#define DOEPMSK_OPEM DOEPMSK_OPEM_Msk // OUT packet error mask */ +#define DOEPMSK_OPEM_Msk (0x1UL << DOEPMSK_OPEM_Pos) // 0x00000100 +#define DOEPMSK_OPEM DOEPMSK_OPEM_Msk // OUT packet error mask #define DOEPMSK_BOIM_Pos (9U) -#define DOEPMSK_BOIM_Msk (0x1UL << DOEPMSK_BOIM_Pos) // 0x00000200 */ -#define DOEPMSK_BOIM DOEPMSK_BOIM_Msk // BNA interrupt mask */ +#define DOEPMSK_BOIM_Msk (0x1UL << DOEPMSK_BOIM_Pos) // 0x00000200 +#define DOEPMSK_BOIM DOEPMSK_BOIM_Msk // BNA interrupt mask #define DOEPMSK_BERRM_Pos (12U) -#define DOEPMSK_BERRM_Msk (0x1UL << DOEPMSK_BERRM_Pos) // 0x00001000 */ -#define DOEPMSK_BERRM DOEPMSK_BERRM_Msk // Babble error interrupt mask */ +#define DOEPMSK_BERRM_Msk (0x1UL << DOEPMSK_BERRM_Pos) // 0x00001000 +#define DOEPMSK_BERRM DOEPMSK_BERRM_Msk // Babble error interrupt mask #define DOEPMSK_NAKM_Pos (13U) -#define DOEPMSK_NAKM_Msk (0x1UL << DOEPMSK_NAKM_Pos) // 0x00002000 */ -#define DOEPMSK_NAKM DOEPMSK_NAKM_Msk // OUT Packet NAK interrupt mask */ +#define DOEPMSK_NAKM_Msk (0x1UL << DOEPMSK_NAKM_Pos) // 0x00002000 +#define DOEPMSK_NAKM DOEPMSK_NAKM_Msk // OUT Packet NAK interrupt mask #define DOEPMSK_NYETM_Pos (14U) -#define DOEPMSK_NYETM_Msk (0x1UL << DOEPMSK_NYETM_Pos) // 0x00004000 */ -#define DOEPMSK_NYETM DOEPMSK_NYETM_Msk // NYET interrupt mask */ +#define DOEPMSK_NYETM_Msk (0x1UL << DOEPMSK_NYETM_Pos) // 0x00004000 +#define DOEPMSK_NYETM DOEPMSK_NYETM_Msk // NYET interrupt mask /******************** Bit definition for GINTSTS register ********************/ #define GINTSTS_CMOD_Pos (0U) -#define GINTSTS_CMOD_Msk (0x1UL << GINTSTS_CMOD_Pos) // 0x00000001 */ -#define GINTSTS_CMOD GINTSTS_CMOD_Msk // Current mode of operation */ +#define GINTSTS_CMOD_Msk (0x1UL << GINTSTS_CMOD_Pos) // 0x00000001 +#define GINTSTS_CMOD GINTSTS_CMOD_Msk // Current mode of operation #define GINTSTS_MMIS_Pos (1U) -#define GINTSTS_MMIS_Msk (0x1UL << GINTSTS_MMIS_Pos) // 0x00000002 */ -#define GINTSTS_MMIS GINTSTS_MMIS_Msk // Mode mismatch interrupt */ +#define GINTSTS_MMIS_Msk (0x1UL << GINTSTS_MMIS_Pos) // 0x00000002 +#define GINTSTS_MMIS GINTSTS_MMIS_Msk // Mode mismatch interrupt #define GINTSTS_OTGINT_Pos (2U) -#define GINTSTS_OTGINT_Msk (0x1UL << GINTSTS_OTGINT_Pos) // 0x00000004 */ -#define GINTSTS_OTGINT GINTSTS_OTGINT_Msk // OTG interrupt */ +#define GINTSTS_OTGINT_Msk (0x1UL << GINTSTS_OTGINT_Pos) // 0x00000004 +#define GINTSTS_OTGINT GINTSTS_OTGINT_Msk // OTG interrupt #define GINTSTS_SOF_Pos (3U) -#define GINTSTS_SOF_Msk (0x1UL << GINTSTS_SOF_Pos) // 0x00000008 */ -#define GINTSTS_SOF GINTSTS_SOF_Msk // Start of frame */ +#define GINTSTS_SOF_Msk (0x1UL << GINTSTS_SOF_Pos) // 0x00000008 +#define GINTSTS_SOF GINTSTS_SOF_Msk // Start of frame #define GINTSTS_RXFLVL_Pos (4U) -#define GINTSTS_RXFLVL_Msk (0x1UL << GINTSTS_RXFLVL_Pos) // 0x00000010 */ -#define GINTSTS_RXFLVL GINTSTS_RXFLVL_Msk // RxFIFO nonempty */ +#define GINTSTS_RXFLVL_Msk (0x1UL << GINTSTS_RXFLVL_Pos) // 0x00000010 +#define GINTSTS_RXFLVL GINTSTS_RXFLVL_Msk // RxFIFO nonempty #define GINTSTS_NPTXFE_Pos (5U) -#define GINTSTS_NPTXFE_Msk (0x1UL << GINTSTS_NPTXFE_Pos) // 0x00000020 */ -#define GINTSTS_NPTXFE GINTSTS_NPTXFE_Msk // Nonperiodic TxFIFO empty */ +#define GINTSTS_NPTXFE_Msk (0x1UL << GINTSTS_NPTXFE_Pos) // 0x00000020 +#define GINTSTS_NPTXFE GINTSTS_NPTXFE_Msk // Nonperiodic TxFIFO empty #define GINTSTS_GINAKEFF_Pos (6U) -#define GINTSTS_GINAKEFF_Msk (0x1UL << GINTSTS_GINAKEFF_Pos) // 0x00000040 */ -#define GINTSTS_GINAKEFF GINTSTS_GINAKEFF_Msk // Global IN nonperiodic NAK effective */ +#define GINTSTS_GINAKEFF_Msk (0x1UL << GINTSTS_GINAKEFF_Pos) // 0x00000040 +#define GINTSTS_GINAKEFF GINTSTS_GINAKEFF_Msk // Global IN nonperiodic NAK effective #define GINTSTS_BOUTNAKEFF_Pos (7U) -#define GINTSTS_BOUTNAKEFF_Msk (0x1UL << GINTSTS_BOUTNAKEFF_Pos) // 0x00000080 */ -#define GINTSTS_BOUTNAKEFF GINTSTS_BOUTNAKEFF_Msk // Global OUT NAK effective */ +#define GINTSTS_BOUTNAKEFF_Msk (0x1UL << GINTSTS_BOUTNAKEFF_Pos) // 0x00000080 +#define GINTSTS_BOUTNAKEFF GINTSTS_BOUTNAKEFF_Msk // Global OUT NAK effective #define GINTSTS_ESUSP_Pos (10U) -#define GINTSTS_ESUSP_Msk (0x1UL << GINTSTS_ESUSP_Pos) // 0x00000400 */ -#define GINTSTS_ESUSP GINTSTS_ESUSP_Msk // Early suspend */ +#define GINTSTS_ESUSP_Msk (0x1UL << GINTSTS_ESUSP_Pos) // 0x00000400 +#define GINTSTS_ESUSP GINTSTS_ESUSP_Msk // Early suspend #define GINTSTS_USBSUSP_Pos (11U) -#define GINTSTS_USBSUSP_Msk (0x1UL << GINTSTS_USBSUSP_Pos) // 0x00000800 */ -#define GINTSTS_USBSUSP GINTSTS_USBSUSP_Msk // USB suspend */ +#define GINTSTS_USBSUSP_Msk (0x1UL << GINTSTS_USBSUSP_Pos) // 0x00000800 +#define GINTSTS_USBSUSP GINTSTS_USBSUSP_Msk // USB suspend #define GINTSTS_USBRST_Pos (12U) -#define GINTSTS_USBRST_Msk (0x1UL << GINTSTS_USBRST_Pos) // 0x00001000 */ -#define GINTSTS_USBRST GINTSTS_USBRST_Msk // USB reset */ +#define GINTSTS_USBRST_Msk (0x1UL << GINTSTS_USBRST_Pos) // 0x00001000 +#define GINTSTS_USBRST GINTSTS_USBRST_Msk // USB reset #define GINTSTS_ENUMDNE_Pos (13U) -#define GINTSTS_ENUMDNE_Msk (0x1UL << GINTSTS_ENUMDNE_Pos) // 0x00002000 */ -#define GINTSTS_ENUMDNE GINTSTS_ENUMDNE_Msk // Enumeration done */ +#define GINTSTS_ENUMDNE_Msk (0x1UL << GINTSTS_ENUMDNE_Pos) // 0x00002000 +#define GINTSTS_ENUMDNE GINTSTS_ENUMDNE_Msk // Enumeration done #define GINTSTS_ISOODRP_Pos (14U) -#define GINTSTS_ISOODRP_Msk (0x1UL << GINTSTS_ISOODRP_Pos) // 0x00004000 */ -#define GINTSTS_ISOODRP GINTSTS_ISOODRP_Msk // Isochronous OUT packet dropped interrupt */ +#define GINTSTS_ISOODRP_Msk (0x1UL << GINTSTS_ISOODRP_Pos) // 0x00004000 +#define GINTSTS_ISOODRP GINTSTS_ISOODRP_Msk // Isochronous OUT packet dropped interrupt #define GINTSTS_EOPF_Pos (15U) -#define GINTSTS_EOPF_Msk (0x1UL << GINTSTS_EOPF_Pos) // 0x00008000 */ -#define GINTSTS_EOPF GINTSTS_EOPF_Msk // End of periodic frame interrupt */ +#define GINTSTS_EOPF_Msk (0x1UL << GINTSTS_EOPF_Pos) // 0x00008000 +#define GINTSTS_EOPF GINTSTS_EOPF_Msk // End of periodic frame interrupt #define GINTSTS_IEPINT_Pos (18U) -#define GINTSTS_IEPINT_Msk (0x1UL << GINTSTS_IEPINT_Pos) // 0x00040000 */ -#define GINTSTS_IEPINT GINTSTS_IEPINT_Msk // IN endpoint interrupt */ +#define GINTSTS_IEPINT_Msk (0x1UL << GINTSTS_IEPINT_Pos) // 0x00040000 +#define GINTSTS_IEPINT GINTSTS_IEPINT_Msk // IN endpoint interrupt #define GINTSTS_OEPINT_Pos (19U) -#define GINTSTS_OEPINT_Msk (0x1UL << GINTSTS_OEPINT_Pos) // 0x00080000 */ -#define GINTSTS_OEPINT GINTSTS_OEPINT_Msk // OUT endpoint interrupt */ +#define GINTSTS_OEPINT_Msk (0x1UL << GINTSTS_OEPINT_Pos) // 0x00080000 +#define GINTSTS_OEPINT GINTSTS_OEPINT_Msk // OUT endpoint interrupt #define GINTSTS_IISOIXFR_Pos (20U) -#define GINTSTS_IISOIXFR_Msk (0x1UL << GINTSTS_IISOIXFR_Pos) // 0x00100000 */ -#define GINTSTS_IISOIXFR GINTSTS_IISOIXFR_Msk // Incomplete isochronous IN transfer */ +#define GINTSTS_IISOIXFR_Msk (0x1UL << GINTSTS_IISOIXFR_Pos) // 0x00100000 +#define GINTSTS_IISOIXFR GINTSTS_IISOIXFR_Msk // Incomplete isochronous IN transfer #define GINTSTS_PXFR_INCOMPISOOUT_Pos (21U) -#define GINTSTS_PXFR_INCOMPISOOUT_Msk (0x1UL << GINTSTS_PXFR_INCOMPISOOUT_Pos) // 0x00200000 */ -#define GINTSTS_PXFR_INCOMPISOOUT GINTSTS_PXFR_INCOMPISOOUT_Msk // Incomplete periodic transfer */ +#define GINTSTS_PXFR_INCOMPISOOUT_Msk (0x1UL << GINTSTS_PXFR_INCOMPISOOUT_Pos) // 0x00200000 +#define GINTSTS_PXFR_INCOMPISOOUT GINTSTS_PXFR_INCOMPISOOUT_Msk // Incomplete periodic transfer #define GINTSTS_DATAFSUSP_Pos (22U) -#define GINTSTS_DATAFSUSP_Msk (0x1UL << GINTSTS_DATAFSUSP_Pos) // 0x00400000 */ -#define GINTSTS_DATAFSUSP GINTSTS_DATAFSUSP_Msk // Data fetch suspended */ +#define GINTSTS_DATAFSUSP_Msk (0x1UL << GINTSTS_DATAFSUSP_Pos) // 0x00400000 +#define GINTSTS_DATAFSUSP GINTSTS_DATAFSUSP_Msk // Data fetch suspended #define GINTSTS_RSTDET_Pos (23U) -#define GINTSTS_RSTDET_Msk (0x1UL << GINTSTS_RSTDET_Pos) // 0x00800000 */ -#define GINTSTS_RSTDET GINTSTS_RSTDET_Msk // Reset detected interrupt */ +#define GINTSTS_RSTDET_Msk (0x1UL << GINTSTS_RSTDET_Pos) // 0x00800000 +#define GINTSTS_RSTDET GINTSTS_RSTDET_Msk // Reset detected interrupt #define GINTSTS_HPRTINT_Pos (24U) -#define GINTSTS_HPRTINT_Msk (0x1UL << GINTSTS_HPRTINT_Pos) // 0x01000000 */ -#define GINTSTS_HPRTINT GINTSTS_HPRTINT_Msk // Host port interrupt */ +#define GINTSTS_HPRTINT_Msk (0x1UL << GINTSTS_HPRTINT_Pos) // 0x01000000 +#define GINTSTS_HPRTINT GINTSTS_HPRTINT_Msk // Host port interrupt #define GINTSTS_HCINT_Pos (25U) -#define GINTSTS_HCINT_Msk (0x1UL << GINTSTS_HCINT_Pos) // 0x02000000 */ -#define GINTSTS_HCINT GINTSTS_HCINT_Msk // Host channels interrupt */ +#define GINTSTS_HCINT_Msk (0x1UL << GINTSTS_HCINT_Pos) // 0x02000000 +#define GINTSTS_HCINT GINTSTS_HCINT_Msk // Host channels interrupt #define GINTSTS_PTXFE_Pos (26U) -#define GINTSTS_PTXFE_Msk (0x1UL << GINTSTS_PTXFE_Pos) // 0x04000000 */ -#define GINTSTS_PTXFE GINTSTS_PTXFE_Msk // Periodic TxFIFO empty */ +#define GINTSTS_PTXFE_Msk (0x1UL << GINTSTS_PTXFE_Pos) // 0x04000000 +#define GINTSTS_PTXFE GINTSTS_PTXFE_Msk // Periodic TxFIFO empty #define GINTSTS_LPMINT_Pos (27U) -#define GINTSTS_LPMINT_Msk (0x1UL << GINTSTS_LPMINT_Pos) // 0x08000000 */ -#define GINTSTS_LPMINT GINTSTS_LPMINT_Msk // LPM interrupt */ +#define GINTSTS_LPMINT_Msk (0x1UL << GINTSTS_LPMINT_Pos) // 0x08000000 +#define GINTSTS_LPMINT GINTSTS_LPMINT_Msk // LPM interrupt #define GINTSTS_CIDSCHG_Pos (28U) -#define GINTSTS_CIDSCHG_Msk (0x1UL << GINTSTS_CIDSCHG_Pos) // 0x10000000 */ -#define GINTSTS_CIDSCHG GINTSTS_CIDSCHG_Msk // Connector ID status change */ +#define GINTSTS_CIDSCHG_Msk (0x1UL << GINTSTS_CIDSCHG_Pos) // 0x10000000 +#define GINTSTS_CIDSCHG GINTSTS_CIDSCHG_Msk // Connector ID status change #define GINTSTS_DISCINT_Pos (29U) -#define GINTSTS_DISCINT_Msk (0x1UL << GINTSTS_DISCINT_Pos) // 0x20000000 */ -#define GINTSTS_DISCINT GINTSTS_DISCINT_Msk // Disconnect detected interrupt */ +#define GINTSTS_DISCINT_Msk (0x1UL << GINTSTS_DISCINT_Pos) // 0x20000000 +#define GINTSTS_DISCINT GINTSTS_DISCINT_Msk // Disconnect detected interrupt #define GINTSTS_SRQINT_Pos (30U) -#define GINTSTS_SRQINT_Msk (0x1UL << GINTSTS_SRQINT_Pos) // 0x40000000 */ -#define GINTSTS_SRQINT GINTSTS_SRQINT_Msk // Session request/new session detected interrupt */ +#define GINTSTS_SRQINT_Msk (0x1UL << GINTSTS_SRQINT_Pos) // 0x40000000 +#define GINTSTS_SRQINT GINTSTS_SRQINT_Msk // Session request/new session detected interrupt #define GINTSTS_WKUINT_Pos (31U) -#define GINTSTS_WKUINT_Msk (0x1UL << GINTSTS_WKUINT_Pos) // 0x80000000 */ -#define GINTSTS_WKUINT GINTSTS_WKUINT_Msk // Resume/remote wakeup detected interrupt */ +#define GINTSTS_WKUINT_Msk (0x1UL << GINTSTS_WKUINT_Pos) // 0x80000000 +#define GINTSTS_WKUINT GINTSTS_WKUINT_Msk // Resume/remote wakeup detected interrupt /******************** Bit definition for GINTMSK register ********************/ #define GINTMSK_MMISM_Pos (1U) -#define GINTMSK_MMISM_Msk (0x1UL << GINTMSK_MMISM_Pos) // 0x00000002 */ -#define GINTMSK_MMISM GINTMSK_MMISM_Msk // Mode mismatch interrupt mask */ +#define GINTMSK_MMISM_Msk (0x1UL << GINTMSK_MMISM_Pos) // 0x00000002 +#define GINTMSK_MMISM GINTMSK_MMISM_Msk // Mode mismatch interrupt mask #define GINTMSK_OTGINT_Pos (2U) -#define GINTMSK_OTGINT_Msk (0x1UL << GINTMSK_OTGINT_Pos) // 0x00000004 */ -#define GINTMSK_OTGINT GINTMSK_OTGINT_Msk // OTG interrupt mask */ +#define GINTMSK_OTGINT_Msk (0x1UL << GINTMSK_OTGINT_Pos) // 0x00000004 +#define GINTMSK_OTGINT GINTMSK_OTGINT_Msk // OTG interrupt mask #define GINTMSK_SOFM_Pos (3U) -#define GINTMSK_SOFM_Msk (0x1UL << GINTMSK_SOFM_Pos) // 0x00000008 */ -#define GINTMSK_SOFM GINTMSK_SOFM_Msk // Start of frame mask */ +#define GINTMSK_SOFM_Msk (0x1UL << GINTMSK_SOFM_Pos) // 0x00000008 +#define GINTMSK_SOFM GINTMSK_SOFM_Msk // Start of frame mask #define GINTMSK_RXFLVLM_Pos (4U) -#define GINTMSK_RXFLVLM_Msk (0x1UL << GINTMSK_RXFLVLM_Pos) // 0x00000010 */ -#define GINTMSK_RXFLVLM GINTMSK_RXFLVLM_Msk // Receive FIFO nonempty mask */ +#define GINTMSK_RXFLVLM_Msk (0x1UL << GINTMSK_RXFLVLM_Pos) // 0x00000010 +#define GINTMSK_RXFLVLM GINTMSK_RXFLVLM_Msk // Receive FIFO nonempty mask #define GINTMSK_NPTXFEM_Pos (5U) -#define GINTMSK_NPTXFEM_Msk (0x1UL << GINTMSK_NPTXFEM_Pos) // 0x00000020 */ -#define GINTMSK_NPTXFEM GINTMSK_NPTXFEM_Msk // Nonperiodic TxFIFO empty mask */ +#define GINTMSK_NPTXFEM_Msk (0x1UL << GINTMSK_NPTXFEM_Pos) // 0x00000020 +#define GINTMSK_NPTXFEM GINTMSK_NPTXFEM_Msk // Nonperiodic TxFIFO empty mask #define GINTMSK_GINAKEFFM_Pos (6U) -#define GINTMSK_GINAKEFFM_Msk (0x1UL << GINTMSK_GINAKEFFM_Pos) // 0x00000040 */ -#define GINTMSK_GINAKEFFM GINTMSK_GINAKEFFM_Msk // Global nonperiodic IN NAK effective mask */ +#define GINTMSK_GINAKEFFM_Msk (0x1UL << GINTMSK_GINAKEFFM_Pos) // 0x00000040 +#define GINTMSK_GINAKEFFM GINTMSK_GINAKEFFM_Msk // Global nonperiodic IN NAK effective mask #define GINTMSK_GONAKEFFM_Pos (7U) -#define GINTMSK_GONAKEFFM_Msk (0x1UL << GINTMSK_GONAKEFFM_Pos) // 0x00000080 */ -#define GINTMSK_GONAKEFFM GINTMSK_GONAKEFFM_Msk // Global OUT NAK effective mask */ +#define GINTMSK_GONAKEFFM_Msk (0x1UL << GINTMSK_GONAKEFFM_Pos) // 0x00000080 +#define GINTMSK_GONAKEFFM GINTMSK_GONAKEFFM_Msk // Global OUT NAK effective mask #define GINTMSK_ESUSPM_Pos (10U) -#define GINTMSK_ESUSPM_Msk (0x1UL << GINTMSK_ESUSPM_Pos) // 0x00000400 */ -#define GINTMSK_ESUSPM GINTMSK_ESUSPM_Msk // Early suspend mask */ +#define GINTMSK_ESUSPM_Msk (0x1UL << GINTMSK_ESUSPM_Pos) // 0x00000400 +#define GINTMSK_ESUSPM GINTMSK_ESUSPM_Msk // Early suspend mask #define GINTMSK_USBSUSPM_Pos (11U) -#define GINTMSK_USBSUSPM_Msk (0x1UL << GINTMSK_USBSUSPM_Pos) // 0x00000800 */ -#define GINTMSK_USBSUSPM GINTMSK_USBSUSPM_Msk // USB suspend mask */ +#define GINTMSK_USBSUSPM_Msk (0x1UL << GINTMSK_USBSUSPM_Pos) // 0x00000800 +#define GINTMSK_USBSUSPM GINTMSK_USBSUSPM_Msk // USB suspend mask #define GINTMSK_USBRST_Pos (12U) -#define GINTMSK_USBRST_Msk (0x1UL << GINTMSK_USBRST_Pos) // 0x00001000 */ -#define GINTMSK_USBRST GINTMSK_USBRST_Msk // USB reset mask */ +#define GINTMSK_USBRST_Msk (0x1UL << GINTMSK_USBRST_Pos) // 0x00001000 +#define GINTMSK_USBRST GINTMSK_USBRST_Msk // USB reset mask #define GINTMSK_ENUMDNEM_Pos (13U) -#define GINTMSK_ENUMDNEM_Msk (0x1UL << GINTMSK_ENUMDNEM_Pos) // 0x00002000 */ -#define GINTMSK_ENUMDNEM GINTMSK_ENUMDNEM_Msk // Enumeration done mask */ +#define GINTMSK_ENUMDNEM_Msk (0x1UL << GINTMSK_ENUMDNEM_Pos) // 0x00002000 +#define GINTMSK_ENUMDNEM GINTMSK_ENUMDNEM_Msk // Enumeration done mask #define GINTMSK_ISOODRPM_Pos (14U) -#define GINTMSK_ISOODRPM_Msk (0x1UL << GINTMSK_ISOODRPM_Pos) // 0x00004000 */ -#define GINTMSK_ISOODRPM GINTMSK_ISOODRPM_Msk // Isochronous OUT packet dropped interrupt mask */ +#define GINTMSK_ISOODRPM_Msk (0x1UL << GINTMSK_ISOODRPM_Pos) // 0x00004000 +#define GINTMSK_ISOODRPM GINTMSK_ISOODRPM_Msk // Isochronous OUT packet dropped interrupt mask #define GINTMSK_EOPFM_Pos (15U) -#define GINTMSK_EOPFM_Msk (0x1UL << GINTMSK_EOPFM_Pos) // 0x00008000 */ -#define GINTMSK_EOPFM GINTMSK_EOPFM_Msk // End of periodic frame interrupt mask */ +#define GINTMSK_EOPFM_Msk (0x1UL << GINTMSK_EOPFM_Pos) // 0x00008000 +#define GINTMSK_EOPFM GINTMSK_EOPFM_Msk // End of periodic frame interrupt mask #define GINTMSK_EPMISM_Pos (17U) -#define GINTMSK_EPMISM_Msk (0x1UL << GINTMSK_EPMISM_Pos) // 0x00020000 */ -#define GINTMSK_EPMISM GINTMSK_EPMISM_Msk // Endpoint mismatch interrupt mask */ +#define GINTMSK_EPMISM_Msk (0x1UL << GINTMSK_EPMISM_Pos) // 0x00020000 +#define GINTMSK_EPMISM GINTMSK_EPMISM_Msk // Endpoint mismatch interrupt mask #define GINTMSK_IEPINT_Pos (18U) -#define GINTMSK_IEPINT_Msk (0x1UL << GINTMSK_IEPINT_Pos) // 0x00040000 */ -#define GINTMSK_IEPINT GINTMSK_IEPINT_Msk // IN endpoints interrupt mask */ +#define GINTMSK_IEPINT_Msk (0x1UL << GINTMSK_IEPINT_Pos) // 0x00040000 +#define GINTMSK_IEPINT GINTMSK_IEPINT_Msk // IN endpoints interrupt mask #define GINTMSK_OEPINT_Pos (19U) -#define GINTMSK_OEPINT_Msk (0x1UL << GINTMSK_OEPINT_Pos) // 0x00080000 */ -#define GINTMSK_OEPINT GINTMSK_OEPINT_Msk // OUT endpoints interrupt mask */ +#define GINTMSK_OEPINT_Msk (0x1UL << GINTMSK_OEPINT_Pos) // 0x00080000 +#define GINTMSK_OEPINT GINTMSK_OEPINT_Msk // OUT endpoints interrupt mask #define GINTMSK_IISOIXFRM_Pos (20U) -#define GINTMSK_IISOIXFRM_Msk (0x1UL << GINTMSK_IISOIXFRM_Pos) // 0x00100000 */ -#define GINTMSK_IISOIXFRM GINTMSK_IISOIXFRM_Msk // Incomplete isochronous IN transfer mask */ +#define GINTMSK_IISOIXFRM_Msk (0x1UL << GINTMSK_IISOIXFRM_Pos) // 0x00100000 +#define GINTMSK_IISOIXFRM GINTMSK_IISOIXFRM_Msk // Incomplete isochronous IN transfer mask #define GINTMSK_PXFRM_IISOOXFRM_Pos (21U) -#define GINTMSK_PXFRM_IISOOXFRM_Msk (0x1UL << GINTMSK_PXFRM_IISOOXFRM_Pos) // 0x00200000 */ -#define GINTMSK_PXFRM_IISOOXFRM GINTMSK_PXFRM_IISOOXFRM_Msk // Incomplete periodic transfer mask */ +#define GINTMSK_PXFRM_IISOOXFRM_Msk (0x1UL << GINTMSK_PXFRM_IISOOXFRM_Pos) // 0x00200000 +#define GINTMSK_PXFRM_IISOOXFRM GINTMSK_PXFRM_IISOOXFRM_Msk // Incomplete periodic transfer mask #define GINTMSK_FSUSPM_Pos (22U) -#define GINTMSK_FSUSPM_Msk (0x1UL << GINTMSK_FSUSPM_Pos) // 0x00400000 */ -#define GINTMSK_FSUSPM GINTMSK_FSUSPM_Msk // Data fetch suspended mask */ +#define GINTMSK_FSUSPM_Msk (0x1UL << GINTMSK_FSUSPM_Pos) // 0x00400000 +#define GINTMSK_FSUSPM GINTMSK_FSUSPM_Msk // Data fetch suspended mask #define GINTMSK_RSTDEM_Pos (23U) -#define GINTMSK_RSTDEM_Msk (0x1UL << GINTMSK_RSTDEM_Pos) // 0x00800000 */ -#define GINTMSK_RSTDEM GINTMSK_RSTDEM_Msk // Reset detected interrupt mask */ +#define GINTMSK_RSTDEM_Msk (0x1UL << GINTMSK_RSTDEM_Pos) // 0x00800000 +#define GINTMSK_RSTDEM GINTMSK_RSTDEM_Msk // Reset detected interrupt mask #define GINTMSK_PRTIM_Pos (24U) -#define GINTMSK_PRTIM_Msk (0x1UL << GINTMSK_PRTIM_Pos) // 0x01000000 */ -#define GINTMSK_PRTIM GINTMSK_PRTIM_Msk // Host port interrupt mask */ +#define GINTMSK_PRTIM_Msk (0x1UL << GINTMSK_PRTIM_Pos) // 0x01000000 +#define GINTMSK_PRTIM GINTMSK_PRTIM_Msk // Host port interrupt mask #define GINTMSK_HCIM_Pos (25U) -#define GINTMSK_HCIM_Msk (0x1UL << GINTMSK_HCIM_Pos) // 0x02000000 */ -#define GINTMSK_HCIM GINTMSK_HCIM_Msk // Host channels interrupt mask */ +#define GINTMSK_HCIM_Msk (0x1UL << GINTMSK_HCIM_Pos) // 0x02000000 +#define GINTMSK_HCIM GINTMSK_HCIM_Msk // Host channels interrupt mask #define GINTMSK_PTXFEM_Pos (26U) -#define GINTMSK_PTXFEM_Msk (0x1UL << GINTMSK_PTXFEM_Pos) // 0x04000000 */ -#define GINTMSK_PTXFEM GINTMSK_PTXFEM_Msk // Periodic TxFIFO empty mask */ +#define GINTMSK_PTXFEM_Msk (0x1UL << GINTMSK_PTXFEM_Pos) // 0x04000000 +#define GINTMSK_PTXFEM GINTMSK_PTXFEM_Msk // Periodic TxFIFO empty mask #define GINTMSK_LPMINTM_Pos (27U) -#define GINTMSK_LPMINTM_Msk (0x1UL << GINTMSK_LPMINTM_Pos) // 0x08000000 */ -#define GINTMSK_LPMINTM GINTMSK_LPMINTM_Msk // LPM interrupt Mask */ +#define GINTMSK_LPMINTM_Msk (0x1UL << GINTMSK_LPMINTM_Pos) // 0x08000000 +#define GINTMSK_LPMINTM GINTMSK_LPMINTM_Msk // LPM interrupt Mask #define GINTMSK_CIDSCHGM_Pos (28U) -#define GINTMSK_CIDSCHGM_Msk (0x1UL << GINTMSK_CIDSCHGM_Pos) // 0x10000000 */ -#define GINTMSK_CIDSCHGM GINTMSK_CIDSCHGM_Msk // Connector ID status change mask */ +#define GINTMSK_CIDSCHGM_Msk (0x1UL << GINTMSK_CIDSCHGM_Pos) // 0x10000000 +#define GINTMSK_CIDSCHGM GINTMSK_CIDSCHGM_Msk // Connector ID status change mask #define GINTMSK_DISCINT_Pos (29U) -#define GINTMSK_DISCINT_Msk (0x1UL << GINTMSK_DISCINT_Pos) // 0x20000000 */ -#define GINTMSK_DISCINT GINTMSK_DISCINT_Msk // Disconnect detected interrupt mask */ +#define GINTMSK_DISCINT_Msk (0x1UL << GINTMSK_DISCINT_Pos) // 0x20000000 +#define GINTMSK_DISCINT GINTMSK_DISCINT_Msk // Disconnect detected interrupt mask #define GINTMSK_SRQIM_Pos (30U) -#define GINTMSK_SRQIM_Msk (0x1UL << GINTMSK_SRQIM_Pos) // 0x40000000 */ -#define GINTMSK_SRQIM GINTMSK_SRQIM_Msk // Session request/new session detected interrupt mask */ +#define GINTMSK_SRQIM_Msk (0x1UL << GINTMSK_SRQIM_Pos) // 0x40000000 +#define GINTMSK_SRQIM GINTMSK_SRQIM_Msk // Session request/new session detected interrupt mask #define GINTMSK_WUIM_Pos (31U) -#define GINTMSK_WUIM_Msk (0x1UL << GINTMSK_WUIM_Pos) // 0x80000000 */ -#define GINTMSK_WUIM GINTMSK_WUIM_Msk // Resume/remote wakeup detected interrupt mask */ +#define GINTMSK_WUIM_Msk (0x1UL << GINTMSK_WUIM_Pos) // 0x80000000 +#define GINTMSK_WUIM GINTMSK_WUIM_Msk // Resume/remote wakeup detected interrupt mask /******************** Bit definition for DAINT register ********************/ #define DAINT_IEPINT_Pos (0U) -#define DAINT_IEPINT_Msk (0xFFFFUL << DAINT_IEPINT_Pos) // 0x0000FFFF */ -#define DAINT_IEPINT DAINT_IEPINT_Msk // IN endpoint interrupt bits */ +#define DAINT_IEPINT_Msk (0xFFFFUL << DAINT_IEPINT_Pos) // 0x0000FFFF +#define DAINT_IEPINT DAINT_IEPINT_Msk // IN endpoint interrupt bits #define DAINT_OEPINT_Pos (16U) -#define DAINT_OEPINT_Msk (0xFFFFUL << DAINT_OEPINT_Pos) // 0xFFFF0000 */ -#define DAINT_OEPINT DAINT_OEPINT_Msk // OUT endpoint interrupt bits */ +#define DAINT_OEPINT_Msk (0xFFFFUL << DAINT_OEPINT_Pos) // 0xFFFF0000 +#define DAINT_OEPINT DAINT_OEPINT_Msk // OUT endpoint interrupt bits /******************** Bit definition for HAINTMSK register ********************/ #define HAINTMSK_HAINTM_Pos (0U) -#define HAINTMSK_HAINTM_Msk (0xFFFFUL << HAINTMSK_HAINTM_Pos) // 0x0000FFFF */ -#define HAINTMSK_HAINTM HAINTMSK_HAINTM_Msk // Channel interrupt mask */ +#define HAINTMSK_HAINTM_Msk (0xFFFFUL << HAINTMSK_HAINTM_Pos) // 0x0000FFFF +#define HAINTMSK_HAINTM HAINTMSK_HAINTM_Msk // Channel interrupt mask /******************** Bit definition for GRXSTSP register ********************/ #define GRXSTSP_EPNUM_Pos (0U) -#define GRXSTSP_EPNUM_Msk (0xFUL << GRXSTSP_EPNUM_Pos) // 0x0000000F */ -#define GRXSTSP_EPNUM GRXSTSP_EPNUM_Msk // IN EP interrupt mask bits */ +#define GRXSTSP_EPNUM_Msk (0xFUL << GRXSTSP_EPNUM_Pos) // 0x0000000F +#define GRXSTSP_EPNUM GRXSTSP_EPNUM_Msk // IN EP interrupt mask bits #define GRXSTSP_BCNT_Pos (4U) -#define GRXSTSP_BCNT_Msk (0x7FFUL << GRXSTSP_BCNT_Pos) // 0x00007FF0 */ -#define GRXSTSP_BCNT GRXSTSP_BCNT_Msk // OUT EP interrupt mask bits */ +#define GRXSTSP_BCNT_Msk (0x7FFUL << GRXSTSP_BCNT_Pos) // 0x00007FF0 +#define GRXSTSP_BCNT GRXSTSP_BCNT_Msk // OUT EP interrupt mask bits #define GRXSTSP_DPID_Pos (15U) -#define GRXSTSP_DPID_Msk (0x3UL << GRXSTSP_DPID_Pos) // 0x00018000 */ -#define GRXSTSP_DPID GRXSTSP_DPID_Msk // OUT EP interrupt mask bits */ +#define GRXSTSP_DPID_Msk (0x3UL << GRXSTSP_DPID_Pos) // 0x00018000 +#define GRXSTSP_DPID GRXSTSP_DPID_Msk // OUT EP interrupt mask bits #define GRXSTSP_PKTSTS_Pos (17U) -#define GRXSTSP_PKTSTS_Msk (0xFUL << GRXSTSP_PKTSTS_Pos) // 0x001E0000 */ -#define GRXSTSP_PKTSTS GRXSTSP_PKTSTS_Msk // OUT EP interrupt mask bits */ +#define GRXSTSP_PKTSTS_Msk (0xFUL << GRXSTSP_PKTSTS_Pos) // 0x001E0000 +#define GRXSTSP_PKTSTS GRXSTSP_PKTSTS_Msk // OUT EP interrupt mask bits #define GRXSTS_PKTSTS_GLOBALOUTNAK 1 #define GRXSTS_PKTSTS_OUTRX 2 @@ -933,773 +934,803 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size"); /******************** Bit definition for DAINTMSK register ********************/ #define DAINTMSK_IEPM_Pos (0U) -#define DAINTMSK_IEPM_Msk (0xFFFFUL << DAINTMSK_IEPM_Pos) // 0x0000FFFF */ -#define DAINTMSK_IEPM DAINTMSK_IEPM_Msk // IN EP interrupt mask bits */ +#define DAINTMSK_IEPM_Msk (0xFFFFUL << DAINTMSK_IEPM_Pos) // 0x0000FFFF +#define DAINTMSK_IEPM DAINTMSK_IEPM_Msk // IN EP interrupt mask bits #define DAINTMSK_OEPM_Pos (16U) -#define DAINTMSK_OEPM_Msk (0xFFFFUL << DAINTMSK_OEPM_Pos) // 0xFFFF0000 */ -#define DAINTMSK_OEPM DAINTMSK_OEPM_Msk // OUT EP interrupt mask bits */ +#define DAINTMSK_OEPM_Msk (0xFFFFUL << DAINTMSK_OEPM_Pos) // 0xFFFF0000 +#define DAINTMSK_OEPM DAINTMSK_OEPM_Msk // OUT EP interrupt mask bits #if 0 /******************** Bit definition for OTG register ********************/ #define CHNUM_Pos (0U) -#define CHNUM_Msk (0xFUL << CHNUM_Pos) // 0x0000000F */ -#define CHNUM CHNUM_Msk // Channel number */ -#define CHNUM_0 (0x1UL << CHNUM_Pos) // 0x00000001 */ -#define CHNUM_1 (0x2UL << CHNUM_Pos) // 0x00000002 */ -#define CHNUM_2 (0x4UL << CHNUM_Pos) // 0x00000004 */ -#define CHNUM_3 (0x8UL << CHNUM_Pos) // 0x00000008 */ +#define CHNUM_Msk (0xFUL << CHNUM_Pos) // 0x0000000F +#define CHNUM CHNUM_Msk // Channel number +#define CHNUM_0 (0x1UL << CHNUM_Pos) // 0x00000001 +#define CHNUM_1 (0x2UL << CHNUM_Pos) // 0x00000002 +#define CHNUM_2 (0x4UL << CHNUM_Pos) // 0x00000004 +#define CHNUM_3 (0x8UL << CHNUM_Pos) // 0x00000008 #define BCNT_Pos (4U) -#define BCNT_Msk (0x7FFUL << BCNT_Pos) // 0x00007FF0 */ -#define BCNT BCNT_Msk // Byte count */ +#define BCNT_Msk (0x7FFUL << BCNT_Pos) // 0x00007FF0 +#define BCNT BCNT_Msk // Byte count #define DPID_Pos (15U) -#define DPID_Msk (0x3UL << DPID_Pos) // 0x00018000 */ -#define DPID DPID_Msk // Data PID */ -#define DPID_0 (0x1UL << DPID_Pos) // 0x00008000 */ -#define DPID_1 (0x2UL << DPID_Pos) // 0x00010000 */ +#define DPID_Msk (0x3UL << DPID_Pos) // 0x00018000 +#define DPID DPID_Msk // Data PID +#define DPID_0 (0x1UL << DPID_Pos) // 0x00008000 +#define DPID_1 (0x2UL << DPID_Pos) // 0x00010000 #define PKTSTS_Pos (17U) -#define PKTSTS_Msk (0xFUL << PKTSTS_Pos) // 0x001E0000 */ -#define PKTSTS PKTSTS_Msk // Packet status */ -#define PKTSTS_0 (0x1UL << PKTSTS_Pos) // 0x00020000 */ -#define PKTSTS_1 (0x2UL << PKTSTS_Pos) // 0x00040000 */ -#define PKTSTS_2 (0x4UL << PKTSTS_Pos) // 0x00080000 */ -#define PKTSTS_3 (0x8UL << PKTSTS_Pos) // 0x00100000 */ +#define PKTSTS_Msk (0xFUL << PKTSTS_Pos) // 0x001E0000 +#define PKTSTS PKTSTS_Msk // Packet status +#define PKTSTS_0 (0x1UL << PKTSTS_Pos) // 0x00020000 +#define PKTSTS_1 (0x2UL << PKTSTS_Pos) // 0x00040000 +#define PKTSTS_2 (0x4UL << PKTSTS_Pos) // 0x00080000 +#define PKTSTS_3 (0x8UL << PKTSTS_Pos) // 0x00100000 #define EPNUM_Pos (0U) -#define EPNUM_Msk (0xFUL << EPNUM_Pos) // 0x0000000F */ -#define EPNUM EPNUM_Msk // Endpoint number */ -#define EPNUM_0 (0x1UL << EPNUM_Pos) // 0x00000001 */ -#define EPNUM_1 (0x2UL << EPNUM_Pos) // 0x00000002 */ -#define EPNUM_2 (0x4UL << EPNUM_Pos) // 0x00000004 */ -#define EPNUM_3 (0x8UL << EPNUM_Pos) // 0x00000008 */ +#define EPNUM_Msk (0xFUL << EPNUM_Pos) // 0x0000000F +#define EPNUM EPNUM_Msk // Endpoint number +#define EPNUM_0 (0x1UL << EPNUM_Pos) // 0x00000001 +#define EPNUM_1 (0x2UL << EPNUM_Pos) // 0x00000002 +#define EPNUM_2 (0x4UL << EPNUM_Pos) // 0x00000004 +#define EPNUM_3 (0x8UL << EPNUM_Pos) // 0x00000008 #define FRMNUM_Pos (21U) -#define FRMNUM_Msk (0xFUL << FRMNUM_Pos) // 0x01E00000 */ -#define FRMNUM FRMNUM_Msk // Frame number */ -#define FRMNUM_0 (0x1UL << FRMNUM_Pos) // 0x00200000 */ -#define FRMNUM_1 (0x2UL << FRMNUM_Pos) // 0x00400000 */ -#define FRMNUM_2 (0x4UL << FRMNUM_Pos) // 0x00800000 */ -#define FRMNUM_3 (0x8UL << FRMNUM_Pos) // 0x01000000 */ +#define FRMNUM_Msk (0xFUL << FRMNUM_Pos) // 0x01E00000 +#define FRMNUM FRMNUM_Msk // Frame number +#define FRMNUM_0 (0x1UL << FRMNUM_Pos) // 0x00200000 +#define FRMNUM_1 (0x2UL << FRMNUM_Pos) // 0x00400000 +#define FRMNUM_2 (0x4UL << FRMNUM_Pos) // 0x00800000 +#define FRMNUM_3 (0x8UL << FRMNUM_Pos) // 0x01000000 #endif /******************** Bit definition for GRXFSIZ register ********************/ #define GRXFSIZ_RXFD_Pos (0U) -#define GRXFSIZ_RXFD_Msk (0xFFFFUL << GRXFSIZ_RXFD_Pos) // 0x0000FFFF */ -#define GRXFSIZ_RXFD GRXFSIZ_RXFD_Msk // RxFIFO depth */ +#define GRXFSIZ_RXFD_Msk (0xFFFFUL << GRXFSIZ_RXFD_Pos) // 0x0000FFFF +#define GRXFSIZ_RXFD GRXFSIZ_RXFD_Msk // RxFIFO depth /******************** Bit definition for DVBUSDIS register ********************/ #define DVBUSDIS_VBUSDT_Pos (0U) -#define DVBUSDIS_VBUSDT_Msk (0xFFFFUL << DVBUSDIS_VBUSDT_Pos) // 0x0000FFFF */ -#define DVBUSDIS_VBUSDT DVBUSDIS_VBUSDT_Msk // Device VBUS discharge time */ +#define DVBUSDIS_VBUSDT_Msk (0xFFFFUL << DVBUSDIS_VBUSDT_Pos) // 0x0000FFFF +#define DVBUSDIS_VBUSDT DVBUSDIS_VBUSDT_Msk // Device VBUS discharge time /******************** Bit definition for OTG register ********************/ #define GNPTXFSIZ_NPTXFSA_Pos (0U) -#define GNPTXFSIZ_NPTXFSA_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFSA_Pos) // 0x0000FFFF */ -#define GNPTXFSIZ_NPTXFSA GNPTXFSIZ_NPTXFSA_Msk // Nonperiodic transmit RAM start address */ +#define GNPTXFSIZ_NPTXFSA_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFSA_Pos) // 0x0000FFFF +#define GNPTXFSIZ_NPTXFSA GNPTXFSIZ_NPTXFSA_Msk // Nonperiodic transmit RAM start address #define GNPTXFSIZ_NPTXFD_Pos (16U) -#define GNPTXFSIZ_NPTXFD_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFD_Pos) // 0xFFFF0000 */ -#define GNPTXFSIZ_NPTXFD GNPTXFSIZ_NPTXFD_Msk // Nonperiodic TxFIFO depth */ +#define GNPTXFSIZ_NPTXFD_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFD_Pos) // 0xFFFF0000 +#define GNPTXFSIZ_NPTXFD GNPTXFSIZ_NPTXFD_Msk // Nonperiodic TxFIFO depth #define DIEPTXF0_TX0FSA_Pos (0U) -#define DIEPTXF0_TX0FSA_Msk (0xFFFFUL << DIEPTXF0_TX0FSA_Pos) // 0x0000FFFF */ -#define DIEPTXF0_TX0FSA DIEPTXF0_TX0FSA_Msk // Endpoint 0 transmit RAM start address */ +#define DIEPTXF0_TX0FSA_Msk (0xFFFFUL << DIEPTXF0_TX0FSA_Pos) // 0x0000FFFF +#define DIEPTXF0_TX0FSA DIEPTXF0_TX0FSA_Msk // Endpoint 0 transmit RAM start address #define DIEPTXF0_TX0FD_Pos (16U) -#define DIEPTXF0_TX0FD_Msk (0xFFFFUL << DIEPTXF0_TX0FD_Pos) // 0xFFFF0000 */ -#define DIEPTXF0_TX0FD DIEPTXF0_TX0FD_Msk // Endpoint 0 TxFIFO depth */ +#define DIEPTXF0_TX0FD_Msk (0xFFFFUL << DIEPTXF0_TX0FD_Pos) // 0xFFFF0000 +#define DIEPTXF0_TX0FD DIEPTXF0_TX0FD_Msk // Endpoint 0 TxFIFO depth /******************** Bit definition for DVBUSPULSE register ********************/ #define DVBUSPULSE_DVBUSP_Pos (0U) -#define DVBUSPULSE_DVBUSP_Msk (0xFFFUL << DVBUSPULSE_DVBUSP_Pos) // 0x00000FFF */ -#define DVBUSPULSE_DVBUSP DVBUSPULSE_DVBUSP_Msk // Device VBUS pulsing time */ +#define DVBUSPULSE_DVBUSP_Msk (0xFFFUL << DVBUSPULSE_DVBUSP_Pos) // 0x00000FFF +#define DVBUSPULSE_DVBUSP DVBUSPULSE_DVBUSP_Msk // Device VBUS pulsing time /******************** Bit definition for GNPTXSTS register ********************/ #define GNPTXSTS_NPTXFSAV_Pos (0U) -#define GNPTXSTS_NPTXFSAV_Msk (0xFFFFUL << GNPTXSTS_NPTXFSAV_Pos) // 0x0000FFFF */ -#define GNPTXSTS_NPTXFSAV GNPTXSTS_NPTXFSAV_Msk // Nonperiodic TxFIFO space available */ +#define GNPTXSTS_NPTXFSAV_Msk (0xFFFFUL << GNPTXSTS_NPTXFSAV_Pos) // 0x0000FFFF +#define GNPTXSTS_NPTXFSAV GNPTXSTS_NPTXFSAV_Msk // Nonperiodic TxFIFO space available #define GNPTXSTS_NPTQXSAV_Pos (16U) -#define GNPTXSTS_NPTQXSAV_Msk (0xFFUL << GNPTXSTS_NPTQXSAV_Pos) // 0x00FF0000 */ -#define GNPTXSTS_NPTQXSAV GNPTXSTS_NPTQXSAV_Msk // Nonperiodic transmit request queue space available */ -#define GNPTXSTS_NPTQXSAV_0 (0x01UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00010000 */ -#define GNPTXSTS_NPTQXSAV_1 (0x02UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00020000 */ -#define GNPTXSTS_NPTQXSAV_2 (0x04UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00040000 */ -#define GNPTXSTS_NPTQXSAV_3 (0x08UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00080000 */ -#define GNPTXSTS_NPTQXSAV_4 (0x10UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00100000 */ -#define GNPTXSTS_NPTQXSAV_5 (0x20UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00200000 */ -#define GNPTXSTS_NPTQXSAV_6 (0x40UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00400000 */ -#define GNPTXSTS_NPTQXSAV_7 (0x80UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00800000 */ +#define GNPTXSTS_NPTQXSAV_Msk (0xFFUL << GNPTXSTS_NPTQXSAV_Pos) // 0x00FF0000 +#define GNPTXSTS_NPTQXSAV GNPTXSTS_NPTQXSAV_Msk // Nonperiodic transmit request queue space available +#define GNPTXSTS_NPTQXSAV_0 (0x01UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00010000 +#define GNPTXSTS_NPTQXSAV_1 (0x02UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00020000 +#define GNPTXSTS_NPTQXSAV_2 (0x04UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00040000 +#define GNPTXSTS_NPTQXSAV_3 (0x08UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00080000 +#define GNPTXSTS_NPTQXSAV_4 (0x10UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00100000 +#define GNPTXSTS_NPTQXSAV_5 (0x20UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00200000 +#define GNPTXSTS_NPTQXSAV_6 (0x40UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00400000 +#define GNPTXSTS_NPTQXSAV_7 (0x80UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00800000 #define GNPTXSTS_NPTXQTOP_Pos (24U) -#define GNPTXSTS_NPTXQTOP_Msk (0x7FUL << GNPTXSTS_NPTXQTOP_Pos) // 0x7F000000 */ -#define GNPTXSTS_NPTXQTOP GNPTXSTS_NPTXQTOP_Msk // Top of the nonperiodic transmit request queue */ -#define GNPTXSTS_NPTXQTOP_0 (0x01UL << GNPTXSTS_NPTXQTOP_Pos) // 0x01000000 */ -#define GNPTXSTS_NPTXQTOP_1 (0x02UL << GNPTXSTS_NPTXQTOP_Pos) // 0x02000000 */ -#define GNPTXSTS_NPTXQTOP_2 (0x04UL << GNPTXSTS_NPTXQTOP_Pos) // 0x04000000 */ -#define GNPTXSTS_NPTXQTOP_3 (0x08UL << GNPTXSTS_NPTXQTOP_Pos) // 0x08000000 */ -#define GNPTXSTS_NPTXQTOP_4 (0x10UL << GNPTXSTS_NPTXQTOP_Pos) // 0x10000000 */ -#define GNPTXSTS_NPTXQTOP_5 (0x20UL << GNPTXSTS_NPTXQTOP_Pos) // 0x20000000 */ -#define GNPTXSTS_NPTXQTOP_6 (0x40UL << GNPTXSTS_NPTXQTOP_Pos) // 0x40000000 */ +#define GNPTXSTS_NPTXQTOP_Msk (0x7FUL << GNPTXSTS_NPTXQTOP_Pos) // 0x7F000000 +#define GNPTXSTS_NPTXQTOP GNPTXSTS_NPTXQTOP_Msk // Top of the nonperiodic transmit request queue +#define GNPTXSTS_NPTXQTOP_0 (0x01UL << GNPTXSTS_NPTXQTOP_Pos) // 0x01000000 +#define GNPTXSTS_NPTXQTOP_1 (0x02UL << GNPTXSTS_NPTXQTOP_Pos) // 0x02000000 +#define GNPTXSTS_NPTXQTOP_2 (0x04UL << GNPTXSTS_NPTXQTOP_Pos) // 0x04000000 +#define GNPTXSTS_NPTXQTOP_3 (0x08UL << GNPTXSTS_NPTXQTOP_Pos) // 0x08000000 +#define GNPTXSTS_NPTXQTOP_4 (0x10UL << GNPTXSTS_NPTXQTOP_Pos) // 0x10000000 +#define GNPTXSTS_NPTXQTOP_5 (0x20UL << GNPTXSTS_NPTXQTOP_Pos) // 0x20000000 +#define GNPTXSTS_NPTXQTOP_6 (0x40UL << GNPTXSTS_NPTXQTOP_Pos) // 0x40000000 /******************** Bit definition for DTHRCTL register ********************/ #define DTHRCTL_NONISOTHREN_Pos (0U) -#define DTHRCTL_NONISOTHREN_Msk (0x1UL << DTHRCTL_NONISOTHREN_Pos) // 0x00000001 */ -#define DTHRCTL_NONISOTHREN DTHRCTL_NONISOTHREN_Msk // Nonisochronous IN endpoints threshold enable */ +#define DTHRCTL_NONISOTHREN_Msk (0x1UL << DTHRCTL_NONISOTHREN_Pos) // 0x00000001 +#define DTHRCTL_NONISOTHREN DTHRCTL_NONISOTHREN_Msk // Nonisochronous IN endpoints threshold enable #define DTHRCTL_ISOTHREN_Pos (1U) -#define DTHRCTL_ISOTHREN_Msk (0x1UL << DTHRCTL_ISOTHREN_Pos) // 0x00000002 */ -#define DTHRCTL_ISOTHREN DTHRCTL_ISOTHREN_Msk // ISO IN endpoint threshold enable */ +#define DTHRCTL_ISOTHREN_Msk (0x1UL << DTHRCTL_ISOTHREN_Pos) // 0x00000002 +#define DTHRCTL_ISOTHREN DTHRCTL_ISOTHREN_Msk // ISO IN endpoint threshold enable #define DTHRCTL_TXTHRLEN_Pos (2U) -#define DTHRCTL_TXTHRLEN_Msk (0x1FFUL << DTHRCTL_TXTHRLEN_Pos) // 0x000007FC */ -#define DTHRCTL_TXTHRLEN DTHRCTL_TXTHRLEN_Msk // Transmit threshold length */ -#define DTHRCTL_TXTHRLEN_0 (0x001UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000004 */ -#define DTHRCTL_TXTHRLEN_1 (0x002UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000008 */ -#define DTHRCTL_TXTHRLEN_2 (0x004UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000010 */ -#define DTHRCTL_TXTHRLEN_3 (0x008UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000020 */ -#define DTHRCTL_TXTHRLEN_4 (0x010UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000040 */ -#define DTHRCTL_TXTHRLEN_5 (0x020UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000080 */ -#define DTHRCTL_TXTHRLEN_6 (0x040UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000100 */ -#define DTHRCTL_TXTHRLEN_7 (0x080UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000200 */ -#define DTHRCTL_TXTHRLEN_8 (0x100UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000400 */ +#define DTHRCTL_TXTHRLEN_Msk (0x1FFUL << DTHRCTL_TXTHRLEN_Pos) // 0x000007FC +#define DTHRCTL_TXTHRLEN DTHRCTL_TXTHRLEN_Msk // Transmit threshold length +#define DTHRCTL_TXTHRLEN_0 (0x001UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000004 +#define DTHRCTL_TXTHRLEN_1 (0x002UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000008 +#define DTHRCTL_TXTHRLEN_2 (0x004UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000010 +#define DTHRCTL_TXTHRLEN_3 (0x008UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000020 +#define DTHRCTL_TXTHRLEN_4 (0x010UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000040 +#define DTHRCTL_TXTHRLEN_5 (0x020UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000080 +#define DTHRCTL_TXTHRLEN_6 (0x040UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000100 +#define DTHRCTL_TXTHRLEN_7 (0x080UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000200 +#define DTHRCTL_TXTHRLEN_8 (0x100UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000400 #define DTHRCTL_RXTHREN_Pos (16U) -#define DTHRCTL_RXTHREN_Msk (0x1UL << DTHRCTL_RXTHREN_Pos) // 0x00010000 */ -#define DTHRCTL_RXTHREN DTHRCTL_RXTHREN_Msk // Receive threshold enable */ +#define DTHRCTL_RXTHREN_Msk (0x1UL << DTHRCTL_RXTHREN_Pos) // 0x00010000 +#define DTHRCTL_RXTHREN DTHRCTL_RXTHREN_Msk // Receive threshold enable #define DTHRCTL_RXTHRLEN_Pos (17U) -#define DTHRCTL_RXTHRLEN_Msk (0x1FFUL << DTHRCTL_RXTHRLEN_Pos) // 0x03FE0000 */ -#define DTHRCTL_RXTHRLEN DTHRCTL_RXTHRLEN_Msk // Receive threshold length */ -#define DTHRCTL_RXTHRLEN_0 (0x001UL << DTHRCTL_RXTHRLEN_Pos) // 0x00020000 */ -#define DTHRCTL_RXTHRLEN_1 (0x002UL << DTHRCTL_RXTHRLEN_Pos) // 0x00040000 */ -#define DTHRCTL_RXTHRLEN_2 (0x004UL << DTHRCTL_RXTHRLEN_Pos) // 0x00080000 */ -#define DTHRCTL_RXTHRLEN_3 (0x008UL << DTHRCTL_RXTHRLEN_Pos) // 0x00100000 */ -#define DTHRCTL_RXTHRLEN_4 (0x010UL << DTHRCTL_RXTHRLEN_Pos) // 0x00200000 */ -#define DTHRCTL_RXTHRLEN_5 (0x020UL << DTHRCTL_RXTHRLEN_Pos) // 0x00400000 */ -#define DTHRCTL_RXTHRLEN_6 (0x040UL << DTHRCTL_RXTHRLEN_Pos) // 0x00800000 */ -#define DTHRCTL_RXTHRLEN_7 (0x080UL << DTHRCTL_RXTHRLEN_Pos) // 0x01000000 */ -#define DTHRCTL_RXTHRLEN_8 (0x100UL << DTHRCTL_RXTHRLEN_Pos) // 0x02000000 */ +#define DTHRCTL_RXTHRLEN_Msk (0x1FFUL << DTHRCTL_RXTHRLEN_Pos) // 0x03FE0000 +#define DTHRCTL_RXTHRLEN DTHRCTL_RXTHRLEN_Msk // Receive threshold length +#define DTHRCTL_RXTHRLEN_0 (0x001UL << DTHRCTL_RXTHRLEN_Pos) // 0x00020000 +#define DTHRCTL_RXTHRLEN_1 (0x002UL << DTHRCTL_RXTHRLEN_Pos) // 0x00040000 +#define DTHRCTL_RXTHRLEN_2 (0x004UL << DTHRCTL_RXTHRLEN_Pos) // 0x00080000 +#define DTHRCTL_RXTHRLEN_3 (0x008UL << DTHRCTL_RXTHRLEN_Pos) // 0x00100000 +#define DTHRCTL_RXTHRLEN_4 (0x010UL << DTHRCTL_RXTHRLEN_Pos) // 0x00200000 +#define DTHRCTL_RXTHRLEN_5 (0x020UL << DTHRCTL_RXTHRLEN_Pos) // 0x00400000 +#define DTHRCTL_RXTHRLEN_6 (0x040UL << DTHRCTL_RXTHRLEN_Pos) // 0x00800000 +#define DTHRCTL_RXTHRLEN_7 (0x080UL << DTHRCTL_RXTHRLEN_Pos) // 0x01000000 +#define DTHRCTL_RXTHRLEN_8 (0x100UL << DTHRCTL_RXTHRLEN_Pos) // 0x02000000 #define DTHRCTL_ARPEN_Pos (27U) -#define DTHRCTL_ARPEN_Msk (0x1UL << DTHRCTL_ARPEN_Pos) // 0x08000000 */ -#define DTHRCTL_ARPEN DTHRCTL_ARPEN_Msk // Arbiter parking enable */ +#define DTHRCTL_ARPEN_Msk (0x1UL << DTHRCTL_ARPEN_Pos) // 0x08000000 +#define DTHRCTL_ARPEN DTHRCTL_ARPEN_Msk // Arbiter parking enable /******************** Bit definition for DIEPEMPMSK register ********************/ #define DIEPEMPMSK_INEPTXFEM_Pos (0U) -#define DIEPEMPMSK_INEPTXFEM_Msk (0xFFFFUL << DIEPEMPMSK_INEPTXFEM_Pos) // 0x0000FFFF */ -#define DIEPEMPMSK_INEPTXFEM DIEPEMPMSK_INEPTXFEM_Msk // IN EP Tx FIFO empty interrupt mask bits */ +#define DIEPEMPMSK_INEPTXFEM_Msk (0xFFFFUL << DIEPEMPMSK_INEPTXFEM_Pos) // 0x0000FFFF +#define DIEPEMPMSK_INEPTXFEM DIEPEMPMSK_INEPTXFEM_Msk // IN EP Tx FIFO empty interrupt mask bits /******************** Bit definition for DEACHINT register ********************/ #define DEACHINT_IEP1INT_Pos (1U) -#define DEACHINT_IEP1INT_Msk (0x1UL << DEACHINT_IEP1INT_Pos) // 0x00000002 */ -#define DEACHINT_IEP1INT DEACHINT_IEP1INT_Msk // IN endpoint 1interrupt bit */ +#define DEACHINT_IEP1INT_Msk (0x1UL << DEACHINT_IEP1INT_Pos) // 0x00000002 +#define DEACHINT_IEP1INT DEACHINT_IEP1INT_Msk // IN endpoint 1interrupt bit #define DEACHINT_OEP1INT_Pos (17U) -#define DEACHINT_OEP1INT_Msk (0x1UL << DEACHINT_OEP1INT_Pos) // 0x00020000 */ -#define DEACHINT_OEP1INT DEACHINT_OEP1INT_Msk // OUT endpoint 1 interrupt bit */ +#define DEACHINT_OEP1INT_Msk (0x1UL << DEACHINT_OEP1INT_Pos) // 0x00020000 +#define DEACHINT_OEP1INT DEACHINT_OEP1INT_Msk // OUT endpoint 1 interrupt bit /******************** Bit definition for GCCFG register ********************/ #define STM32_GCCFG_DCDET_Pos (0U) -#define STM32_GCCFG_DCDET_Msk (0x1UL << STM32_GCCFG_DCDET_Pos) // 0x00000001 */ -#define STM32_GCCFG_DCDET STM32_GCCFG_DCDET_Msk // Data contact detection (DCD) status */ +#define STM32_GCCFG_DCDET_Msk (0x1UL << STM32_GCCFG_DCDET_Pos) // 0x00000001 +#define STM32_GCCFG_DCDET STM32_GCCFG_DCDET_Msk // Data contact detection (DCD) status + #define STM32_GCCFG_PDET_Pos (1U) -#define STM32_GCCFG_PDET_Msk (0x1UL << STM32_GCCFG_PDET_Pos) // 0x00000002 */ -#define STM32_GCCFG_PDET STM32_GCCFG_PDET_Msk // Primary detection (PD) status */ +#define STM32_GCCFG_PDET_Msk (0x1UL << STM32_GCCFG_PDET_Pos) // 0x00000002 +#define STM32_GCCFG_PDET STM32_GCCFG_PDET_Msk // Primary detection (PD) status + #define STM32_GCCFG_SDET_Pos (2U) -#define STM32_GCCFG_SDET_Msk (0x1UL << STM32_GCCFG_SDET_Pos) // 0x00000004 */ -#define STM32_GCCFG_SDET STM32_GCCFG_SDET_Msk // Secondary detection (SD) status */ +#define STM32_GCCFG_SDET_Msk (0x1UL << STM32_GCCFG_SDET_Pos) // 0x00000004 +#define STM32_GCCFG_SDET STM32_GCCFG_SDET_Msk // Secondary detection (SD) status + #define STM32_GCCFG_PS2DET_Pos (3U) -#define STM32_GCCFG_PS2DET_Msk (0x1UL << STM32_GCCFG_PS2DET_Pos) // 0x00000008 */ -#define STM32_GCCFG_PS2DET STM32_GCCFG_PS2DET_Msk // DM pull-up detection status */ +#define STM32_GCCFG_PS2DET_Msk (0x1UL << STM32_GCCFG_PS2DET_Pos) // 0x00000008 +#define STM32_GCCFG_PS2DET STM32_GCCFG_PS2DET_Msk // DM pull-up detection status + #define STM32_GCCFG_PWRDWN_Pos (16U) -#define STM32_GCCFG_PWRDWN_Msk (0x1UL << STM32_GCCFG_PWRDWN_Pos) // 0x00010000 */ -#define STM32_GCCFG_PWRDWN STM32_GCCFG_PWRDWN_Msk // Power down */ +#define STM32_GCCFG_PWRDWN_Msk (0x1UL << STM32_GCCFG_PWRDWN_Pos) // 0x00010000 +#define STM32_GCCFG_PWRDWN STM32_GCCFG_PWRDWN_Msk // Power down + #define STM32_GCCFG_BCDEN_Pos (17U) -#define STM32_GCCFG_BCDEN_Msk (0x1UL << STM32_GCCFG_BCDEN_Pos) // 0x00020000 */ -#define STM32_GCCFG_BCDEN STM32_GCCFG_BCDEN_Msk // Battery charging detector (BCD) enable */ +#define STM32_GCCFG_BCDEN_Msk (0x1UL << STM32_GCCFG_BCDEN_Pos) // 0x00020000 +#define STM32_GCCFG_BCDEN STM32_GCCFG_BCDEN_Msk // Battery charging detector (BCD) enable + #define STM32_GCCFG_DCDEN_Pos (18U) -#define STM32_GCCFG_DCDEN_Msk (0x1UL << STM32_GCCFG_DCDEN_Pos) // 0x00040000 */ +#define STM32_GCCFG_DCDEN_Msk (0x1UL << STM32_GCCFG_DCDEN_Pos) // 0x00040000 #define STM32_GCCFG_DCDEN STM32_GCCFG_DCDEN_Msk // Data contact detection (DCD) mode enable*/ + #define STM32_GCCFG_PDEN_Pos (19U) -#define STM32_GCCFG_PDEN_Msk (0x1UL << STM32_GCCFG_PDEN_Pos) // 0x00080000 */ +#define STM32_GCCFG_PDEN_Msk (0x1UL << STM32_GCCFG_PDEN_Pos) // 0x00080000 #define STM32_GCCFG_PDEN STM32_GCCFG_PDEN_Msk // Primary detection (PD) mode enable*/ + #define STM32_GCCFG_SDEN_Pos (20U) -#define STM32_GCCFG_SDEN_Msk (0x1UL << STM32_GCCFG_SDEN_Pos) // 0x00100000 */ -#define STM32_GCCFG_SDEN STM32_GCCFG_SDEN_Msk // Secondary detection (SD) mode enable */ +#define STM32_GCCFG_SDEN_Msk (0x1UL << STM32_GCCFG_SDEN_Pos) // 0x00100000 +#define STM32_GCCFG_SDEN STM32_GCCFG_SDEN_Msk // Secondary detection (SD) mode enable + #define STM32_GCCFG_VBDEN_Pos (21U) -#define STM32_GCCFG_VBDEN_Msk (0x1UL << STM32_GCCFG_VBDEN_Pos) // 0x00200000 */ -#define STM32_GCCFG_VBDEN STM32_GCCFG_VBDEN_Msk // VBUS mode enable */ +#define STM32_GCCFG_VBDEN_Msk (0x1UL << STM32_GCCFG_VBDEN_Pos) // 0x00200000 +#define STM32_GCCFG_VBDEN STM32_GCCFG_VBDEN_Msk // VBUS mode enable + #define STM32_GCCFG_OTGIDEN_Pos (22U) -#define STM32_GCCFG_OTGIDEN_Msk (0x1UL << STM32_GCCFG_OTGIDEN_Pos) // 0x00400000 */ -#define STM32_GCCFG_OTGIDEN STM32_GCCFG_OTGIDEN_Msk // OTG Id enable */ +#define STM32_GCCFG_OTGIDEN_Msk (0x1UL << STM32_GCCFG_OTGIDEN_Pos) // 0x00400000 +#define STM32_GCCFG_OTGIDEN STM32_GCCFG_OTGIDEN_Msk // OTG Id enable + #define STM32_GCCFG_PHYHSEN_Pos (23U) -#define STM32_GCCFG_PHYHSEN_Msk (0x1UL << STM32_GCCFG_PHYHSEN_Pos) // 0x00800000 */ -#define STM32_GCCFG_PHYHSEN STM32_GCCFG_PHYHSEN_Msk // HS PHY enable */ +#define STM32_GCCFG_PHYHSEN_Msk (0x1UL << STM32_GCCFG_PHYHSEN_Pos) // 0x00800000 +#define STM32_GCCFG_PHYHSEN STM32_GCCFG_PHYHSEN_Msk // HS PHY enable + +// TODO stm32u5a5 SDEN is 22nd bit, conflict with 20th bit above +//#define STM32_GCCFG_SDEN_Pos (22U) +//#define STM32_GCCFG_SDEN_Msk (0x1U << STM32_GCCFG_SDEN_Pos) // 0x00400000 +//#define STM32_GCCFG_SDEN STM32_GCCFG_SDEN_Msk // Secondary detection (PD) mode enable + +// TODO stm32u5a5 VBVALOVA is 23rd bit, conflict with PHYHSEN bit above +#define STM32_GCCFG_VBVALOVAL_Pos (23U) +#define STM32_GCCFG_VBVALOVAL_Msk (0x1U << STM32_GCCFG_VBVALOVAL_Pos) // 0x00800000 +#define STM32_GCCFG_VBVALOVAL STM32_GCCFG_VBVALOVAL_Msk // Value of VBUSVLDEXT0 femtoPHY input + +#define STM32_GCCFG_VBVALEXTOEN_Pos (24U) +#define STM32_GCCFG_VBVALEXTOEN_Msk (0x1U << STM32_GCCFG_VBVALEXTOEN_Pos) // 0x01000000 +#define STM32_GCCFG_VBVALEXTOEN STM32_GCCFG_VBVALEXTOEN_Msk // Enables of VBUSVLDEXT0 femtoPHY input override + +#define STM32_GCCFG_PULLDOWNEN_Pos (25U) +#define STM32_GCCFG_PULLDOWNEN_Msk (0x1U << STM32_GCCFG_PULLDOWNEN_Pos) // 0x02000000 +#define STM32_GCCFG_PULLDOWNEN STM32_GCCFG_PULLDOWNEN_Msk // Enables of femtoPHY pulldown resistors, used when ID PAD is disabled + /******************** Bit definition for DEACHINTMSK register ********************/ #define DEACHINTMSK_IEP1INTM_Pos (1U) -#define DEACHINTMSK_IEP1INTM_Msk (0x1UL << DEACHINTMSK_IEP1INTM_Pos) // 0x00000002 */ -#define DEACHINTMSK_IEP1INTM DEACHINTMSK_IEP1INTM_Msk // IN Endpoint 1 interrupt mask bit */ +#define DEACHINTMSK_IEP1INTM_Msk (0x1UL << DEACHINTMSK_IEP1INTM_Pos) // 0x00000002 +#define DEACHINTMSK_IEP1INTM DEACHINTMSK_IEP1INTM_Msk // IN Endpoint 1 interrupt mask bit #define DEACHINTMSK_OEP1INTM_Pos (17U) -#define DEACHINTMSK_OEP1INTM_Msk (0x1UL << DEACHINTMSK_OEP1INTM_Pos) // 0x00020000 */ -#define DEACHINTMSK_OEP1INTM DEACHINTMSK_OEP1INTM_Msk // OUT Endpoint 1 interrupt mask bit */ +#define DEACHINTMSK_OEP1INTM_Msk (0x1UL << DEACHINTMSK_OEP1INTM_Pos) // 0x00020000 +#define DEACHINTMSK_OEP1INTM DEACHINTMSK_OEP1INTM_Msk // OUT Endpoint 1 interrupt mask bit /******************** Bit definition for CID register ********************/ #define CID_PRODUCT_ID_Pos (0U) -#define CID_PRODUCT_ID_Msk (0xFFFFFFFFUL << CID_PRODUCT_ID_Pos) // 0xFFFFFFFF */ -#define CID_PRODUCT_ID CID_PRODUCT_ID_Msk // Product ID field */ +#define CID_PRODUCT_ID_Msk (0xFFFFFFFFUL << CID_PRODUCT_ID_Pos) // 0xFFFFFFFF +#define CID_PRODUCT_ID CID_PRODUCT_ID_Msk // Product ID field /******************** Bit definition for GLPMCFG register ********************/ #define GLPMCFG_LPMEN_Pos (0U) -#define GLPMCFG_LPMEN_Msk (0x1UL << GLPMCFG_LPMEN_Pos) // 0x00000001 */ -#define GLPMCFG_LPMEN GLPMCFG_LPMEN_Msk // LPM support enable */ +#define GLPMCFG_LPMEN_Msk (0x1UL << GLPMCFG_LPMEN_Pos) // 0x00000001 +#define GLPMCFG_LPMEN GLPMCFG_LPMEN_Msk // LPM support enable #define GLPMCFG_LPMACK_Pos (1U) -#define GLPMCFG_LPMACK_Msk (0x1UL << GLPMCFG_LPMACK_Pos) // 0x00000002 */ -#define GLPMCFG_LPMACK GLPMCFG_LPMACK_Msk // LPM Token acknowledge enable */ +#define GLPMCFG_LPMACK_Msk (0x1UL << GLPMCFG_LPMACK_Pos) // 0x00000002 +#define GLPMCFG_LPMACK GLPMCFG_LPMACK_Msk // LPM Token acknowledge enable #define GLPMCFG_BESL_Pos (2U) -#define GLPMCFG_BESL_Msk (0xFUL << GLPMCFG_BESL_Pos) // 0x0000003C */ -#define GLPMCFG_BESL GLPMCFG_BESL_Msk // BESL value received with last ACKed LPM Token */ +#define GLPMCFG_BESL_Msk (0xFUL << GLPMCFG_BESL_Pos) // 0x0000003C +#define GLPMCFG_BESL GLPMCFG_BESL_Msk // BESL value received with last ACKed LPM Token #define GLPMCFG_REMWAKE_Pos (6U) -#define GLPMCFG_REMWAKE_Msk (0x1UL << GLPMCFG_REMWAKE_Pos) // 0x00000040 */ -#define GLPMCFG_REMWAKE GLPMCFG_REMWAKE_Msk // bRemoteWake value received with last ACKed LPM Token */ +#define GLPMCFG_REMWAKE_Msk (0x1UL << GLPMCFG_REMWAKE_Pos) // 0x00000040 +#define GLPMCFG_REMWAKE GLPMCFG_REMWAKE_Msk // bRemoteWake value received with last ACKed LPM Token #define GLPMCFG_L1SSEN_Pos (7U) -#define GLPMCFG_L1SSEN_Msk (0x1UL << GLPMCFG_L1SSEN_Pos) // 0x00000080 */ -#define GLPMCFG_L1SSEN GLPMCFG_L1SSEN_Msk // L1 shallow sleep enable */ +#define GLPMCFG_L1SSEN_Msk (0x1UL << GLPMCFG_L1SSEN_Pos) // 0x00000080 +#define GLPMCFG_L1SSEN GLPMCFG_L1SSEN_Msk // L1 shallow sleep enable #define GLPMCFG_BESLTHRS_Pos (8U) -#define GLPMCFG_BESLTHRS_Msk (0xFUL << GLPMCFG_BESLTHRS_Pos) // 0x00000F00 */ -#define GLPMCFG_BESLTHRS GLPMCFG_BESLTHRS_Msk // BESL threshold */ +#define GLPMCFG_BESLTHRS_Msk (0xFUL << GLPMCFG_BESLTHRS_Pos) // 0x00000F00 +#define GLPMCFG_BESLTHRS GLPMCFG_BESLTHRS_Msk // BESL threshold #define GLPMCFG_L1DSEN_Pos (12U) -#define GLPMCFG_L1DSEN_Msk (0x1UL << GLPMCFG_L1DSEN_Pos) // 0x00001000 */ -#define GLPMCFG_L1DSEN GLPMCFG_L1DSEN_Msk // L1 deep sleep enable */ +#define GLPMCFG_L1DSEN_Msk (0x1UL << GLPMCFG_L1DSEN_Pos) // 0x00001000 +#define GLPMCFG_L1DSEN GLPMCFG_L1DSEN_Msk // L1 deep sleep enable #define GLPMCFG_LPMRSP_Pos (13U) -#define GLPMCFG_LPMRSP_Msk (0x3UL << GLPMCFG_LPMRSP_Pos) // 0x00006000 */ -#define GLPMCFG_LPMRSP GLPMCFG_LPMRSP_Msk // LPM response */ +#define GLPMCFG_LPMRSP_Msk (0x3UL << GLPMCFG_LPMRSP_Pos) // 0x00006000 +#define GLPMCFG_LPMRSP GLPMCFG_LPMRSP_Msk // LPM response #define GLPMCFG_SLPSTS_Pos (15U) -#define GLPMCFG_SLPSTS_Msk (0x1UL << GLPMCFG_SLPSTS_Pos) // 0x00008000 */ -#define GLPMCFG_SLPSTS GLPMCFG_SLPSTS_Msk // Port sleep status */ +#define GLPMCFG_SLPSTS_Msk (0x1UL << GLPMCFG_SLPSTS_Pos) // 0x00008000 +#define GLPMCFG_SLPSTS GLPMCFG_SLPSTS_Msk // Port sleep status #define GLPMCFG_L1RSMOK_Pos (16U) -#define GLPMCFG_L1RSMOK_Msk (0x1UL << GLPMCFG_L1RSMOK_Pos) // 0x00010000 */ -#define GLPMCFG_L1RSMOK GLPMCFG_L1RSMOK_Msk // Sleep State Resume OK */ +#define GLPMCFG_L1RSMOK_Msk (0x1UL << GLPMCFG_L1RSMOK_Pos) // 0x00010000 +#define GLPMCFG_L1RSMOK GLPMCFG_L1RSMOK_Msk // Sleep State Resume OK #define GLPMCFG_LPMCHIDX_Pos (17U) -#define GLPMCFG_LPMCHIDX_Msk (0xFUL << GLPMCFG_LPMCHIDX_Pos) // 0x001E0000 */ -#define GLPMCFG_LPMCHIDX GLPMCFG_LPMCHIDX_Msk // LPM Channel Index */ +#define GLPMCFG_LPMCHIDX_Msk (0xFUL << GLPMCFG_LPMCHIDX_Pos) // 0x001E0000 +#define GLPMCFG_LPMCHIDX GLPMCFG_LPMCHIDX_Msk // LPM Channel Index #define GLPMCFG_LPMRCNT_Pos (21U) -#define GLPMCFG_LPMRCNT_Msk (0x7UL << GLPMCFG_LPMRCNT_Pos) // 0x00E00000 */ -#define GLPMCFG_LPMRCNT GLPMCFG_LPMRCNT_Msk // LPM retry count */ +#define GLPMCFG_LPMRCNT_Msk (0x7UL << GLPMCFG_LPMRCNT_Pos) // 0x00E00000 +#define GLPMCFG_LPMRCNT GLPMCFG_LPMRCNT_Msk // LPM retry count #define GLPMCFG_SNDLPM_Pos (24U) -#define GLPMCFG_SNDLPM_Msk (0x1UL << GLPMCFG_SNDLPM_Pos) // 0x01000000 */ -#define GLPMCFG_SNDLPM GLPMCFG_SNDLPM_Msk // Send LPM transaction */ +#define GLPMCFG_SNDLPM_Msk (0x1UL << GLPMCFG_SNDLPM_Pos) // 0x01000000 +#define GLPMCFG_SNDLPM GLPMCFG_SNDLPM_Msk // Send LPM transaction #define GLPMCFG_LPMRCNTSTS_Pos (25U) -#define GLPMCFG_LPMRCNTSTS_Msk (0x7UL << GLPMCFG_LPMRCNTSTS_Pos) // 0x0E000000 */ -#define GLPMCFG_LPMRCNTSTS GLPMCFG_LPMRCNTSTS_Msk // LPM retry count status */ +#define GLPMCFG_LPMRCNTSTS_Msk (0x7UL << GLPMCFG_LPMRCNTSTS_Pos) // 0x0E000000 +#define GLPMCFG_LPMRCNTSTS GLPMCFG_LPMRCNTSTS_Msk // LPM retry count status #define GLPMCFG_ENBESL_Pos (28U) -#define GLPMCFG_ENBESL_Msk (0x1UL << GLPMCFG_ENBESL_Pos) // 0x10000000 */ -#define GLPMCFG_ENBESL GLPMCFG_ENBESL_Msk // Enable best effort service latency */ +#define GLPMCFG_ENBESL_Msk (0x1UL << GLPMCFG_ENBESL_Pos) // 0x10000000 +#define GLPMCFG_ENBESL GLPMCFG_ENBESL_Msk // Enable best effort service latency /******************** Bit definition for DIEPEACHMSK1 register ********************/ #define DIEPEACHMSK1_XFRCM_Pos (0U) -#define DIEPEACHMSK1_XFRCM_Msk (0x1UL << DIEPEACHMSK1_XFRCM_Pos) // 0x00000001 */ -#define DIEPEACHMSK1_XFRCM DIEPEACHMSK1_XFRCM_Msk // Transfer completed interrupt mask */ +#define DIEPEACHMSK1_XFRCM_Msk (0x1UL << DIEPEACHMSK1_XFRCM_Pos) // 0x00000001 +#define DIEPEACHMSK1_XFRCM DIEPEACHMSK1_XFRCM_Msk // Transfer completed interrupt mask #define DIEPEACHMSK1_EPDM_Pos (1U) -#define DIEPEACHMSK1_EPDM_Msk (0x1UL << DIEPEACHMSK1_EPDM_Pos) // 0x00000002 */ -#define DIEPEACHMSK1_EPDM DIEPEACHMSK1_EPDM_Msk // Endpoint disabled interrupt mask */ +#define DIEPEACHMSK1_EPDM_Msk (0x1UL << DIEPEACHMSK1_EPDM_Pos) // 0x00000002 +#define DIEPEACHMSK1_EPDM DIEPEACHMSK1_EPDM_Msk // Endpoint disabled interrupt mask #define DIEPEACHMSK1_TOM_Pos (3U) -#define DIEPEACHMSK1_TOM_Msk (0x1UL << DIEPEACHMSK1_TOM_Pos) // 0x00000008 */ -#define DIEPEACHMSK1_TOM DIEPEACHMSK1_TOM_Msk // Timeout condition mask (nonisochronous endpoints) */ +#define DIEPEACHMSK1_TOM_Msk (0x1UL << DIEPEACHMSK1_TOM_Pos) // 0x00000008 +#define DIEPEACHMSK1_TOM DIEPEACHMSK1_TOM_Msk // Timeout condition mask (nonisochronous endpoints) #define DIEPEACHMSK1_ITTXFEMSK_Pos (4U) -#define DIEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << DIEPEACHMSK1_ITTXFEMSK_Pos) // 0x00000010 */ -#define DIEPEACHMSK1_ITTXFEMSK DIEPEACHMSK1_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask */ +#define DIEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << DIEPEACHMSK1_ITTXFEMSK_Pos) // 0x00000010 +#define DIEPEACHMSK1_ITTXFEMSK DIEPEACHMSK1_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask #define DIEPEACHMSK1_INEPNMM_Pos (5U) -#define DIEPEACHMSK1_INEPNMM_Msk (0x1UL << DIEPEACHMSK1_INEPNMM_Pos) // 0x00000020 */ -#define DIEPEACHMSK1_INEPNMM DIEPEACHMSK1_INEPNMM_Msk // IN token received with EP mismatch mask */ +#define DIEPEACHMSK1_INEPNMM_Msk (0x1UL << DIEPEACHMSK1_INEPNMM_Pos) // 0x00000020 +#define DIEPEACHMSK1_INEPNMM DIEPEACHMSK1_INEPNMM_Msk // IN token received with EP mismatch mask #define DIEPEACHMSK1_INEPNEM_Pos (6U) -#define DIEPEACHMSK1_INEPNEM_Msk (0x1UL << DIEPEACHMSK1_INEPNEM_Pos) // 0x00000040 */ -#define DIEPEACHMSK1_INEPNEM DIEPEACHMSK1_INEPNEM_Msk // IN endpoint NAK effective mask */ +#define DIEPEACHMSK1_INEPNEM_Msk (0x1UL << DIEPEACHMSK1_INEPNEM_Pos) // 0x00000040 +#define DIEPEACHMSK1_INEPNEM DIEPEACHMSK1_INEPNEM_Msk // IN endpoint NAK effective mask #define DIEPEACHMSK1_TXFURM_Pos (8U) -#define DIEPEACHMSK1_TXFURM_Msk (0x1UL << DIEPEACHMSK1_TXFURM_Pos) // 0x00000100 */ -#define DIEPEACHMSK1_TXFURM DIEPEACHMSK1_TXFURM_Msk // FIFO underrun mask */ +#define DIEPEACHMSK1_TXFURM_Msk (0x1UL << DIEPEACHMSK1_TXFURM_Pos) // 0x00000100 +#define DIEPEACHMSK1_TXFURM DIEPEACHMSK1_TXFURM_Msk // FIFO underrun mask #define DIEPEACHMSK1_BIM_Pos (9U) -#define DIEPEACHMSK1_BIM_Msk (0x1UL << DIEPEACHMSK1_BIM_Pos) // 0x00000200 */ -#define DIEPEACHMSK1_BIM DIEPEACHMSK1_BIM_Msk // BNA interrupt mask */ +#define DIEPEACHMSK1_BIM_Msk (0x1UL << DIEPEACHMSK1_BIM_Pos) // 0x00000200 +#define DIEPEACHMSK1_BIM DIEPEACHMSK1_BIM_Msk // BNA interrupt mask #define DIEPEACHMSK1_NAKM_Pos (13U) -#define DIEPEACHMSK1_NAKM_Msk (0x1UL << DIEPEACHMSK1_NAKM_Pos) // 0x00002000 */ -#define DIEPEACHMSK1_NAKM DIEPEACHMSK1_NAKM_Msk // NAK interrupt mask */ +#define DIEPEACHMSK1_NAKM_Msk (0x1UL << DIEPEACHMSK1_NAKM_Pos) // 0x00002000 +#define DIEPEACHMSK1_NAKM DIEPEACHMSK1_NAKM_Msk // NAK interrupt mask /******************** Bit definition for HPRT register ********************/ #define HPRT_PCSTS_Pos (0U) -#define HPRT_PCSTS_Msk (0x1UL << HPRT_PCSTS_Pos) // 0x00000001 */ -#define HPRT_PCSTS HPRT_PCSTS_Msk // Port connect status */ +#define HPRT_PCSTS_Msk (0x1UL << HPRT_PCSTS_Pos) // 0x00000001 +#define HPRT_PCSTS HPRT_PCSTS_Msk // Port connect status #define HPRT_PCDET_Pos (1U) -#define HPRT_PCDET_Msk (0x1UL << HPRT_PCDET_Pos) // 0x00000002 */ -#define HPRT_PCDET HPRT_PCDET_Msk // Port connect detected */ +#define HPRT_PCDET_Msk (0x1UL << HPRT_PCDET_Pos) // 0x00000002 +#define HPRT_PCDET HPRT_PCDET_Msk // Port connect detected #define HPRT_PENA_Pos (2U) -#define HPRT_PENA_Msk (0x1UL << HPRT_PENA_Pos) // 0x00000004 */ -#define HPRT_PENA HPRT_PENA_Msk // Port enable */ +#define HPRT_PENA_Msk (0x1UL << HPRT_PENA_Pos) // 0x00000004 +#define HPRT_PENA HPRT_PENA_Msk // Port enable #define HPRT_PENCHNG_Pos (3U) -#define HPRT_PENCHNG_Msk (0x1UL << HPRT_PENCHNG_Pos) // 0x00000008 */ -#define HPRT_PENCHNG HPRT_PENCHNG_Msk // Port enable/disable change */ +#define HPRT_PENCHNG_Msk (0x1UL << HPRT_PENCHNG_Pos) // 0x00000008 +#define HPRT_PENCHNG HPRT_PENCHNG_Msk // Port enable/disable change #define HPRT_POCA_Pos (4U) -#define HPRT_POCA_Msk (0x1UL << HPRT_POCA_Pos) // 0x00000010 */ -#define HPRT_POCA HPRT_POCA_Msk // Port overcurrent active */ +#define HPRT_POCA_Msk (0x1UL << HPRT_POCA_Pos) // 0x00000010 +#define HPRT_POCA HPRT_POCA_Msk // Port overcurrent active #define HPRT_POCCHNG_Pos (5U) -#define HPRT_POCCHNG_Msk (0x1UL << HPRT_POCCHNG_Pos) // 0x00000020 */ -#define HPRT_POCCHNG HPRT_POCCHNG_Msk // Port overcurrent change */ +#define HPRT_POCCHNG_Msk (0x1UL << HPRT_POCCHNG_Pos) // 0x00000020 +#define HPRT_POCCHNG HPRT_POCCHNG_Msk // Port overcurrent change #define HPRT_PRES_Pos (6U) -#define HPRT_PRES_Msk (0x1UL << HPRT_PRES_Pos) // 0x00000040 */ -#define HPRT_PRES HPRT_PRES_Msk // Port resume */ +#define HPRT_PRES_Msk (0x1UL << HPRT_PRES_Pos) // 0x00000040 +#define HPRT_PRES HPRT_PRES_Msk // Port resume #define HPRT_PSUSP_Pos (7U) -#define HPRT_PSUSP_Msk (0x1UL << HPRT_PSUSP_Pos) // 0x00000080 */ -#define HPRT_PSUSP HPRT_PSUSP_Msk // Port suspend */ +#define HPRT_PSUSP_Msk (0x1UL << HPRT_PSUSP_Pos) // 0x00000080 +#define HPRT_PSUSP HPRT_PSUSP_Msk // Port suspend #define HPRT_PRST_Pos (8U) -#define HPRT_PRST_Msk (0x1UL << HPRT_PRST_Pos) // 0x00000100 */ -#define HPRT_PRST HPRT_PRST_Msk // Port reset */ +#define HPRT_PRST_Msk (0x1UL << HPRT_PRST_Pos) // 0x00000100 +#define HPRT_PRST HPRT_PRST_Msk // Port reset #define HPRT_PLSTS_Pos (10U) -#define HPRT_PLSTS_Msk (0x3UL << HPRT_PLSTS_Pos) // 0x00000C00 */ -#define HPRT_PLSTS HPRT_PLSTS_Msk // Port line status */ -#define HPRT_PLSTS_0 (0x1UL << HPRT_PLSTS_Pos) // 0x00000400 */ -#define HPRT_PLSTS_1 (0x2UL << HPRT_PLSTS_Pos) // 0x00000800 */ +#define HPRT_PLSTS_Msk (0x3UL << HPRT_PLSTS_Pos) // 0x00000C00 +#define HPRT_PLSTS HPRT_PLSTS_Msk // Port line status +#define HPRT_PLSTS_0 (0x1UL << HPRT_PLSTS_Pos) // 0x00000400 +#define HPRT_PLSTS_1 (0x2UL << HPRT_PLSTS_Pos) // 0x00000800 #define HPRT_PPWR_Pos (12U) -#define HPRT_PPWR_Msk (0x1UL << HPRT_PPWR_Pos) // 0x00001000 */ -#define HPRT_PPWR HPRT_PPWR_Msk // Port power */ +#define HPRT_PPWR_Msk (0x1UL << HPRT_PPWR_Pos) // 0x00001000 +#define HPRT_PPWR HPRT_PPWR_Msk // Port power #define HPRT_PTCTL_Pos (13U) -#define HPRT_PTCTL_Msk (0xFUL << HPRT_PTCTL_Pos) // 0x0001E000 */ -#define HPRT_PTCTL HPRT_PTCTL_Msk // Port test control */ -#define HPRT_PTCTL_0 (0x1UL << HPRT_PTCTL_Pos) // 0x00002000 */ -#define HPRT_PTCTL_1 (0x2UL << HPRT_PTCTL_Pos) // 0x00004000 */ -#define HPRT_PTCTL_2 (0x4UL << HPRT_PTCTL_Pos) // 0x00008000 */ -#define HPRT_PTCTL_3 (0x8UL << HPRT_PTCTL_Pos) // 0x00010000 */ +#define HPRT_PTCTL_Msk (0xFUL << HPRT_PTCTL_Pos) // 0x0001E000 +#define HPRT_PTCTL HPRT_PTCTL_Msk // Port test control +#define HPRT_PTCTL_0 (0x1UL << HPRT_PTCTL_Pos) // 0x00002000 +#define HPRT_PTCTL_1 (0x2UL << HPRT_PTCTL_Pos) // 0x00004000 +#define HPRT_PTCTL_2 (0x4UL << HPRT_PTCTL_Pos) // 0x00008000 +#define HPRT_PTCTL_3 (0x8UL << HPRT_PTCTL_Pos) // 0x00010000 #define HPRT_PSPD_Pos (17U) -#define HPRT_PSPD_Msk (0x3UL << HPRT_PSPD_Pos) // 0x00060000 */ -#define HPRT_PSPD HPRT_PSPD_Msk // Port speed */ -#define HPRT_PSPD_0 (0x1UL << HPRT_PSPD_Pos) // 0x00020000 */ -#define HPRT_PSPD_1 (0x2UL << HPRT_PSPD_Pos) // 0x00040000 */ +#define HPRT_PSPD_Msk (0x3UL << HPRT_PSPD_Pos) // 0x00060000 +#define HPRT_PSPD HPRT_PSPD_Msk // Port speed +#define HPRT_PSPD_0 (0x1UL << HPRT_PSPD_Pos) // 0x00020000 +#define HPRT_PSPD_1 (0x2UL << HPRT_PSPD_Pos) // 0x00040000 /******************** Bit definition for DOEPEACHMSK1 register ********************/ #define DOEPEACHMSK1_XFRCM_Pos (0U) -#define DOEPEACHMSK1_XFRCM_Msk (0x1UL << DOEPEACHMSK1_XFRCM_Pos) // 0x00000001 */ -#define DOEPEACHMSK1_XFRCM DOEPEACHMSK1_XFRCM_Msk // Transfer completed interrupt mask */ +#define DOEPEACHMSK1_XFRCM_Msk (0x1UL << DOEPEACHMSK1_XFRCM_Pos) // 0x00000001 +#define DOEPEACHMSK1_XFRCM DOEPEACHMSK1_XFRCM_Msk // Transfer completed interrupt mask #define DOEPEACHMSK1_EPDM_Pos (1U) -#define DOEPEACHMSK1_EPDM_Msk (0x1UL << DOEPEACHMSK1_EPDM_Pos) // 0x00000002 */ -#define DOEPEACHMSK1_EPDM DOEPEACHMSK1_EPDM_Msk // Endpoint disabled interrupt mask */ +#define DOEPEACHMSK1_EPDM_Msk (0x1UL << DOEPEACHMSK1_EPDM_Pos) // 0x00000002 +#define DOEPEACHMSK1_EPDM DOEPEACHMSK1_EPDM_Msk // Endpoint disabled interrupt mask #define DOEPEACHMSK1_TOM_Pos (3U) -#define DOEPEACHMSK1_TOM_Msk (0x1UL << DOEPEACHMSK1_TOM_Pos) // 0x00000008 */ -#define DOEPEACHMSK1_TOM DOEPEACHMSK1_TOM_Msk // Timeout condition mask */ +#define DOEPEACHMSK1_TOM_Msk (0x1UL << DOEPEACHMSK1_TOM_Pos) // 0x00000008 +#define DOEPEACHMSK1_TOM DOEPEACHMSK1_TOM_Msk // Timeout condition mask #define DOEPEACHMSK1_ITTXFEMSK_Pos (4U) -#define DOEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << DOEPEACHMSK1_ITTXFEMSK_Pos) // 0x00000010 */ -#define DOEPEACHMSK1_ITTXFEMSK DOEPEACHMSK1_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask */ +#define DOEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << DOEPEACHMSK1_ITTXFEMSK_Pos) // 0x00000010 +#define DOEPEACHMSK1_ITTXFEMSK DOEPEACHMSK1_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask #define DOEPEACHMSK1_INEPNMM_Pos (5U) -#define DOEPEACHMSK1_INEPNMM_Msk (0x1UL << DOEPEACHMSK1_INEPNMM_Pos) // 0x00000020 */ -#define DOEPEACHMSK1_INEPNMM DOEPEACHMSK1_INEPNMM_Msk // IN token received with EP mismatch mask */ +#define DOEPEACHMSK1_INEPNMM_Msk (0x1UL << DOEPEACHMSK1_INEPNMM_Pos) // 0x00000020 +#define DOEPEACHMSK1_INEPNMM DOEPEACHMSK1_INEPNMM_Msk // IN token received with EP mismatch mask #define DOEPEACHMSK1_INEPNEM_Pos (6U) -#define DOEPEACHMSK1_INEPNEM_Msk (0x1UL << DOEPEACHMSK1_INEPNEM_Pos) // 0x00000040 */ -#define DOEPEACHMSK1_INEPNEM DOEPEACHMSK1_INEPNEM_Msk // IN endpoint NAK effective mask */ +#define DOEPEACHMSK1_INEPNEM_Msk (0x1UL << DOEPEACHMSK1_INEPNEM_Pos) // 0x00000040 +#define DOEPEACHMSK1_INEPNEM DOEPEACHMSK1_INEPNEM_Msk // IN endpoint NAK effective mask #define DOEPEACHMSK1_TXFURM_Pos (8U) -#define DOEPEACHMSK1_TXFURM_Msk (0x1UL << DOEPEACHMSK1_TXFURM_Pos) // 0x00000100 */ -#define DOEPEACHMSK1_TXFURM DOEPEACHMSK1_TXFURM_Msk // OUT packet error mask */ +#define DOEPEACHMSK1_TXFURM_Msk (0x1UL << DOEPEACHMSK1_TXFURM_Pos) // 0x00000100 +#define DOEPEACHMSK1_TXFURM DOEPEACHMSK1_TXFURM_Msk // OUT packet error mask #define DOEPEACHMSK1_BIM_Pos (9U) -#define DOEPEACHMSK1_BIM_Msk (0x1UL << DOEPEACHMSK1_BIM_Pos) // 0x00000200 */ -#define DOEPEACHMSK1_BIM DOEPEACHMSK1_BIM_Msk // BNA interrupt mask */ +#define DOEPEACHMSK1_BIM_Msk (0x1UL << DOEPEACHMSK1_BIM_Pos) // 0x00000200 +#define DOEPEACHMSK1_BIM DOEPEACHMSK1_BIM_Msk // BNA interrupt mask #define DOEPEACHMSK1_BERRM_Pos (12U) -#define DOEPEACHMSK1_BERRM_Msk (0x1UL << DOEPEACHMSK1_BERRM_Pos) // 0x00001000 */ -#define DOEPEACHMSK1_BERRM DOEPEACHMSK1_BERRM_Msk // Bubble error interrupt mask */ +#define DOEPEACHMSK1_BERRM_Msk (0x1UL << DOEPEACHMSK1_BERRM_Pos) // 0x00001000 +#define DOEPEACHMSK1_BERRM DOEPEACHMSK1_BERRM_Msk // Bubble error interrupt mask #define DOEPEACHMSK1_NAKM_Pos (13U) -#define DOEPEACHMSK1_NAKM_Msk (0x1UL << DOEPEACHMSK1_NAKM_Pos) // 0x00002000 */ -#define DOEPEACHMSK1_NAKM DOEPEACHMSK1_NAKM_Msk // NAK interrupt mask */ +#define DOEPEACHMSK1_NAKM_Msk (0x1UL << DOEPEACHMSK1_NAKM_Pos) // 0x00002000 +#define DOEPEACHMSK1_NAKM DOEPEACHMSK1_NAKM_Msk // NAK interrupt mask #define DOEPEACHMSK1_NYETM_Pos (14U) -#define DOEPEACHMSK1_NYETM_Msk (0x1UL << DOEPEACHMSK1_NYETM_Pos) // 0x00004000 */ -#define DOEPEACHMSK1_NYETM DOEPEACHMSK1_NYETM_Msk // NYET interrupt mask */ +#define DOEPEACHMSK1_NYETM_Msk (0x1UL << DOEPEACHMSK1_NYETM_Pos) // 0x00004000 +#define DOEPEACHMSK1_NYETM DOEPEACHMSK1_NYETM_Msk // NYET interrupt mask /******************** Bit definition for HPTXFSIZ register ********************/ #define HPTXFSIZ_PTXSA_Pos (0U) -#define HPTXFSIZ_PTXSA_Msk (0xFFFFUL << HPTXFSIZ_PTXSA_Pos) // 0x0000FFFF */ -#define HPTXFSIZ_PTXSA HPTXFSIZ_PTXSA_Msk // Host periodic TxFIFO start address */ +#define HPTXFSIZ_PTXSA_Msk (0xFFFFUL << HPTXFSIZ_PTXSA_Pos) // 0x0000FFFF +#define HPTXFSIZ_PTXSA HPTXFSIZ_PTXSA_Msk // Host periodic TxFIFO start address #define HPTXFSIZ_PTXFD_Pos (16U) -#define HPTXFSIZ_PTXFD_Msk (0xFFFFUL << HPTXFSIZ_PTXFD_Pos) // 0xFFFF0000 */ -#define HPTXFSIZ_PTXFD HPTXFSIZ_PTXFD_Msk // Host periodic TxFIFO depth */ +#define HPTXFSIZ_PTXFD_Msk (0xFFFFUL << HPTXFSIZ_PTXFD_Pos) // 0xFFFF0000 +#define HPTXFSIZ_PTXFD HPTXFSIZ_PTXFD_Msk // Host periodic TxFIFO depth /******************** Bit definition for DIEPCTL register ********************/ #define DIEPCTL_MPSIZ_Pos (0U) -#define DIEPCTL_MPSIZ_Msk (0x7FFUL << DIEPCTL_MPSIZ_Pos) // 0x000007FF */ -#define DIEPCTL_MPSIZ DIEPCTL_MPSIZ_Msk // Maximum packet size */ +#define DIEPCTL_MPSIZ_Msk (0x7FFUL << DIEPCTL_MPSIZ_Pos) // 0x000007FF +#define DIEPCTL_MPSIZ DIEPCTL_MPSIZ_Msk // Maximum packet size #define DIEPCTL_USBAEP_Pos (15U) -#define DIEPCTL_USBAEP_Msk (0x1UL << DIEPCTL_USBAEP_Pos) // 0x00008000 */ -#define DIEPCTL_USBAEP DIEPCTL_USBAEP_Msk // USB active endpoint */ +#define DIEPCTL_USBAEP_Msk (0x1UL << DIEPCTL_USBAEP_Pos) // 0x00008000 +#define DIEPCTL_USBAEP DIEPCTL_USBAEP_Msk // USB active endpoint #define DIEPCTL_EONUM_DPID_Pos (16U) -#define DIEPCTL_EONUM_DPID_Msk (0x1UL << DIEPCTL_EONUM_DPID_Pos) // 0x00010000 */ -#define DIEPCTL_EONUM_DPID DIEPCTL_EONUM_DPID_Msk // Even/odd frame */ +#define DIEPCTL_EONUM_DPID_Msk (0x1UL << DIEPCTL_EONUM_DPID_Pos) // 0x00010000 +#define DIEPCTL_EONUM_DPID DIEPCTL_EONUM_DPID_Msk // Even/odd frame #define DIEPCTL_NAKSTS_Pos (17U) -#define DIEPCTL_NAKSTS_Msk (0x1UL << DIEPCTL_NAKSTS_Pos) // 0x00020000 */ -#define DIEPCTL_NAKSTS DIEPCTL_NAKSTS_Msk // NAK status */ +#define DIEPCTL_NAKSTS_Msk (0x1UL << DIEPCTL_NAKSTS_Pos) // 0x00020000 +#define DIEPCTL_NAKSTS DIEPCTL_NAKSTS_Msk // NAK status #define DIEPCTL_EPTYP_Pos (18U) -#define DIEPCTL_EPTYP_Msk (0x3UL << DIEPCTL_EPTYP_Pos) // 0x000C0000 */ -#define DIEPCTL_EPTYP DIEPCTL_EPTYP_Msk // Endpoint type */ -#define DIEPCTL_EPTYP_0 (0x1UL << DIEPCTL_EPTYP_Pos) // 0x00040000 */ -#define DIEPCTL_EPTYP_1 (0x2UL << DIEPCTL_EPTYP_Pos) // 0x00080000 */ +#define DIEPCTL_EPTYP_Msk (0x3UL << DIEPCTL_EPTYP_Pos) // 0x000C0000 +#define DIEPCTL_EPTYP DIEPCTL_EPTYP_Msk // Endpoint type +#define DIEPCTL_EPTYP_0 (0x1UL << DIEPCTL_EPTYP_Pos) // 0x00040000 +#define DIEPCTL_EPTYP_1 (0x2UL << DIEPCTL_EPTYP_Pos) // 0x00080000 #define DIEPCTL_STALL_Pos (21U) -#define DIEPCTL_STALL_Msk (0x1UL << DIEPCTL_STALL_Pos) // 0x00200000 */ -#define DIEPCTL_STALL DIEPCTL_STALL_Msk // STALL handshake */ +#define DIEPCTL_STALL_Msk (0x1UL << DIEPCTL_STALL_Pos) // 0x00200000 +#define DIEPCTL_STALL DIEPCTL_STALL_Msk // STALL handshake #define DIEPCTL_TXFNUM_Pos (22U) -#define DIEPCTL_TXFNUM_Msk (0xFUL << DIEPCTL_TXFNUM_Pos) // 0x03C00000 */ -#define DIEPCTL_TXFNUM DIEPCTL_TXFNUM_Msk // TxFIFO number */ -#define DIEPCTL_TXFNUM_0 (0x1UL << DIEPCTL_TXFNUM_Pos) // 0x00400000 */ -#define DIEPCTL_TXFNUM_1 (0x2UL << DIEPCTL_TXFNUM_Pos) // 0x00800000 */ -#define DIEPCTL_TXFNUM_2 (0x4UL << DIEPCTL_TXFNUM_Pos) // 0x01000000 */ -#define DIEPCTL_TXFNUM_3 (0x8UL << DIEPCTL_TXFNUM_Pos) // 0x02000000 */ +#define DIEPCTL_TXFNUM_Msk (0xFUL << DIEPCTL_TXFNUM_Pos) // 0x03C00000 +#define DIEPCTL_TXFNUM DIEPCTL_TXFNUM_Msk // TxFIFO number +#define DIEPCTL_TXFNUM_0 (0x1UL << DIEPCTL_TXFNUM_Pos) // 0x00400000 +#define DIEPCTL_TXFNUM_1 (0x2UL << DIEPCTL_TXFNUM_Pos) // 0x00800000 +#define DIEPCTL_TXFNUM_2 (0x4UL << DIEPCTL_TXFNUM_Pos) // 0x01000000 +#define DIEPCTL_TXFNUM_3 (0x8UL << DIEPCTL_TXFNUM_Pos) // 0x02000000 #define DIEPCTL_CNAK_Pos (26U) -#define DIEPCTL_CNAK_Msk (0x1UL << DIEPCTL_CNAK_Pos) // 0x04000000 */ -#define DIEPCTL_CNAK DIEPCTL_CNAK_Msk // Clear NAK */ +#define DIEPCTL_CNAK_Msk (0x1UL << DIEPCTL_CNAK_Pos) // 0x04000000 +#define DIEPCTL_CNAK DIEPCTL_CNAK_Msk // Clear NAK #define DIEPCTL_SNAK_Pos (27U) -#define DIEPCTL_SNAK_Msk (0x1UL << DIEPCTL_SNAK_Pos) // 0x08000000 */ -#define DIEPCTL_SNAK DIEPCTL_SNAK_Msk // Set NAK */ +#define DIEPCTL_SNAK_Msk (0x1UL << DIEPCTL_SNAK_Pos) // 0x08000000 +#define DIEPCTL_SNAK DIEPCTL_SNAK_Msk // Set NAK #define DIEPCTL_SD0PID_SEVNFRM_Pos (28U) -#define DIEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << DIEPCTL_SD0PID_SEVNFRM_Pos) // 0x10000000 */ -#define DIEPCTL_SD0PID_SEVNFRM DIEPCTL_SD0PID_SEVNFRM_Msk // Set DATA0 PID */ +#define DIEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << DIEPCTL_SD0PID_SEVNFRM_Pos) // 0x10000000 +#define DIEPCTL_SD0PID_SEVNFRM DIEPCTL_SD0PID_SEVNFRM_Msk // Set DATA0 PID #define DIEPCTL_SODDFRM_Pos (29U) -#define DIEPCTL_SODDFRM_Msk (0x1UL << DIEPCTL_SODDFRM_Pos) // 0x20000000 */ -#define DIEPCTL_SODDFRM DIEPCTL_SODDFRM_Msk // Set odd frame */ +#define DIEPCTL_SODDFRM_Msk (0x1UL << DIEPCTL_SODDFRM_Pos) // 0x20000000 +#define DIEPCTL_SODDFRM DIEPCTL_SODDFRM_Msk // Set odd frame #define DIEPCTL_EPDIS_Pos (30U) -#define DIEPCTL_EPDIS_Msk (0x1UL << DIEPCTL_EPDIS_Pos) // 0x40000000 */ -#define DIEPCTL_EPDIS DIEPCTL_EPDIS_Msk // Endpoint disable */ +#define DIEPCTL_EPDIS_Msk (0x1UL << DIEPCTL_EPDIS_Pos) // 0x40000000 +#define DIEPCTL_EPDIS DIEPCTL_EPDIS_Msk // Endpoint disable #define DIEPCTL_EPENA_Pos (31U) -#define DIEPCTL_EPENA_Msk (0x1UL << DIEPCTL_EPENA_Pos) // 0x80000000 */ -#define DIEPCTL_EPENA DIEPCTL_EPENA_Msk // Endpoint enable */ +#define DIEPCTL_EPENA_Msk (0x1UL << DIEPCTL_EPENA_Pos) // 0x80000000 +#define DIEPCTL_EPENA DIEPCTL_EPENA_Msk // Endpoint enable /******************** Bit definition for HCCHAR register ********************/ #define HCCHAR_MPSIZ_Pos (0U) -#define HCCHAR_MPSIZ_Msk (0x7FFUL << HCCHAR_MPSIZ_Pos) // 0x000007FF */ -#define HCCHAR_MPSIZ HCCHAR_MPSIZ_Msk // Maximum packet size */ +#define HCCHAR_MPSIZ_Msk (0x7FFUL << HCCHAR_MPSIZ_Pos) // 0x000007FF +#define HCCHAR_MPSIZ HCCHAR_MPSIZ_Msk // Maximum packet size #define HCCHAR_EPNUM_Pos (11U) -#define HCCHAR_EPNUM_Msk (0xFUL << HCCHAR_EPNUM_Pos) // 0x00007800 */ -#define HCCHAR_EPNUM HCCHAR_EPNUM_Msk // Endpoint number */ -#define HCCHAR_EPNUM_0 (0x1UL << HCCHAR_EPNUM_Pos) // 0x00000800 */ -#define HCCHAR_EPNUM_1 (0x2UL << HCCHAR_EPNUM_Pos) // 0x00001000 */ -#define HCCHAR_EPNUM_2 (0x4UL << HCCHAR_EPNUM_Pos) // 0x00002000 */ -#define HCCHAR_EPNUM_3 (0x8UL << HCCHAR_EPNUM_Pos) // 0x00004000 */ +#define HCCHAR_EPNUM_Msk (0xFUL << HCCHAR_EPNUM_Pos) // 0x00007800 +#define HCCHAR_EPNUM HCCHAR_EPNUM_Msk // Endpoint number +#define HCCHAR_EPNUM_0 (0x1UL << HCCHAR_EPNUM_Pos) // 0x00000800 +#define HCCHAR_EPNUM_1 (0x2UL << HCCHAR_EPNUM_Pos) // 0x00001000 +#define HCCHAR_EPNUM_2 (0x4UL << HCCHAR_EPNUM_Pos) // 0x00002000 +#define HCCHAR_EPNUM_3 (0x8UL << HCCHAR_EPNUM_Pos) // 0x00004000 #define HCCHAR_EPDIR_Pos (15U) -#define HCCHAR_EPDIR_Msk (0x1UL << HCCHAR_EPDIR_Pos) // 0x00008000 */ -#define HCCHAR_EPDIR HCCHAR_EPDIR_Msk // Endpoint direction */ +#define HCCHAR_EPDIR_Msk (0x1UL << HCCHAR_EPDIR_Pos) // 0x00008000 +#define HCCHAR_EPDIR HCCHAR_EPDIR_Msk // Endpoint direction #define HCCHAR_LSDEV_Pos (17U) -#define HCCHAR_LSDEV_Msk (0x1UL << HCCHAR_LSDEV_Pos) // 0x00020000 */ -#define HCCHAR_LSDEV HCCHAR_LSDEV_Msk // Low-speed device */ +#define HCCHAR_LSDEV_Msk (0x1UL << HCCHAR_LSDEV_Pos) // 0x00020000 +#define HCCHAR_LSDEV HCCHAR_LSDEV_Msk // Low-speed device #define HCCHAR_EPTYP_Pos (18U) -#define HCCHAR_EPTYP_Msk (0x3UL << HCCHAR_EPTYP_Pos) // 0x000C0000 */ -#define HCCHAR_EPTYP HCCHAR_EPTYP_Msk // Endpoint type */ -#define HCCHAR_EPTYP_0 (0x1UL << HCCHAR_EPTYP_Pos) // 0x00040000 */ -#define HCCHAR_EPTYP_1 (0x2UL << HCCHAR_EPTYP_Pos) // 0x00080000 */ +#define HCCHAR_EPTYP_Msk (0x3UL << HCCHAR_EPTYP_Pos) // 0x000C0000 +#define HCCHAR_EPTYP HCCHAR_EPTYP_Msk // Endpoint type +#define HCCHAR_EPTYP_0 (0x1UL << HCCHAR_EPTYP_Pos) // 0x00040000 +#define HCCHAR_EPTYP_1 (0x2UL << HCCHAR_EPTYP_Pos) // 0x00080000 #define HCCHAR_MC_Pos (20U) -#define HCCHAR_MC_Msk (0x3UL << HCCHAR_MC_Pos) // 0x00300000 */ -#define HCCHAR_MC HCCHAR_MC_Msk // Multi Count (MC) / Error Count (EC) */ -#define HCCHAR_MC_0 (0x1UL << HCCHAR_MC_Pos) // 0x00100000 */ -#define HCCHAR_MC_1 (0x2UL << HCCHAR_MC_Pos) // 0x00200000 */ +#define HCCHAR_MC_Msk (0x3UL << HCCHAR_MC_Pos) // 0x00300000 +#define HCCHAR_MC HCCHAR_MC_Msk // Multi Count (MC) / Error Count (EC) +#define HCCHAR_MC_0 (0x1UL << HCCHAR_MC_Pos) // 0x00100000 +#define HCCHAR_MC_1 (0x2UL << HCCHAR_MC_Pos) // 0x00200000 #define HCCHAR_DAD_Pos (22U) -#define HCCHAR_DAD_Msk (0x7FUL << HCCHAR_DAD_Pos) // 0x1FC00000 */ -#define HCCHAR_DAD HCCHAR_DAD_Msk // Device address */ -#define HCCHAR_DAD_0 (0x01UL << HCCHAR_DAD_Pos) // 0x00400000 */ -#define HCCHAR_DAD_1 (0x02UL << HCCHAR_DAD_Pos) // 0x00800000 */ -#define HCCHAR_DAD_2 (0x04UL << HCCHAR_DAD_Pos) // 0x01000000 */ -#define HCCHAR_DAD_3 (0x08UL << HCCHAR_DAD_Pos) // 0x02000000 */ -#define HCCHAR_DAD_4 (0x10UL << HCCHAR_DAD_Pos) // 0x04000000 */ -#define HCCHAR_DAD_5 (0x20UL << HCCHAR_DAD_Pos) // 0x08000000 */ -#define HCCHAR_DAD_6 (0x40UL << HCCHAR_DAD_Pos) // 0x10000000 */ +#define HCCHAR_DAD_Msk (0x7FUL << HCCHAR_DAD_Pos) // 0x1FC00000 +#define HCCHAR_DAD HCCHAR_DAD_Msk // Device address +#define HCCHAR_DAD_0 (0x01UL << HCCHAR_DAD_Pos) // 0x00400000 +#define HCCHAR_DAD_1 (0x02UL << HCCHAR_DAD_Pos) // 0x00800000 +#define HCCHAR_DAD_2 (0x04UL << HCCHAR_DAD_Pos) // 0x01000000 +#define HCCHAR_DAD_3 (0x08UL << HCCHAR_DAD_Pos) // 0x02000000 +#define HCCHAR_DAD_4 (0x10UL << HCCHAR_DAD_Pos) // 0x04000000 +#define HCCHAR_DAD_5 (0x20UL << HCCHAR_DAD_Pos) // 0x08000000 +#define HCCHAR_DAD_6 (0x40UL << HCCHAR_DAD_Pos) // 0x10000000 #define HCCHAR_ODDFRM_Pos (29U) -#define HCCHAR_ODDFRM_Msk (0x1UL << HCCHAR_ODDFRM_Pos) // 0x20000000 */ -#define HCCHAR_ODDFRM HCCHAR_ODDFRM_Msk // Odd frame */ +#define HCCHAR_ODDFRM_Msk (0x1UL << HCCHAR_ODDFRM_Pos) // 0x20000000 +#define HCCHAR_ODDFRM HCCHAR_ODDFRM_Msk // Odd frame #define HCCHAR_CHDIS_Pos (30U) -#define HCCHAR_CHDIS_Msk (0x1UL << HCCHAR_CHDIS_Pos) // 0x40000000 */ -#define HCCHAR_CHDIS HCCHAR_CHDIS_Msk // Channel disable */ +#define HCCHAR_CHDIS_Msk (0x1UL << HCCHAR_CHDIS_Pos) // 0x40000000 +#define HCCHAR_CHDIS HCCHAR_CHDIS_Msk // Channel disable #define HCCHAR_CHENA_Pos (31U) -#define HCCHAR_CHENA_Msk (0x1UL << HCCHAR_CHENA_Pos) // 0x80000000 */ -#define HCCHAR_CHENA HCCHAR_CHENA_Msk // Channel enable */ +#define HCCHAR_CHENA_Msk (0x1UL << HCCHAR_CHENA_Pos) // 0x80000000 +#define HCCHAR_CHENA HCCHAR_CHENA_Msk // Channel enable /******************** Bit definition for HCSPLT register ********************/ #define HCSPLT_PRTADDR_Pos (0U) -#define HCSPLT_PRTADDR_Msk (0x7FUL << HCSPLT_PRTADDR_Pos) // 0x0000007F */ -#define HCSPLT_PRTADDR HCSPLT_PRTADDR_Msk // Port address */ -#define HCSPLT_PRTADDR_0 (0x01UL << HCSPLT_PRTADDR_Pos) // 0x00000001 */ -#define HCSPLT_PRTADDR_1 (0x02UL << HCSPLT_PRTADDR_Pos) // 0x00000002 */ -#define HCSPLT_PRTADDR_2 (0x04UL << HCSPLT_PRTADDR_Pos) // 0x00000004 */ -#define HCSPLT_PRTADDR_3 (0x08UL << HCSPLT_PRTADDR_Pos) // 0x00000008 */ -#define HCSPLT_PRTADDR_4 (0x10UL << HCSPLT_PRTADDR_Pos) // 0x00000010 */ -#define HCSPLT_PRTADDR_5 (0x20UL << HCSPLT_PRTADDR_Pos) // 0x00000020 */ -#define HCSPLT_PRTADDR_6 (0x40UL << HCSPLT_PRTADDR_Pos) // 0x00000040 */ +#define HCSPLT_PRTADDR_Msk (0x7FUL << HCSPLT_PRTADDR_Pos) // 0x0000007F +#define HCSPLT_PRTADDR HCSPLT_PRTADDR_Msk // Port address +#define HCSPLT_PRTADDR_0 (0x01UL << HCSPLT_PRTADDR_Pos) // 0x00000001 +#define HCSPLT_PRTADDR_1 (0x02UL << HCSPLT_PRTADDR_Pos) // 0x00000002 +#define HCSPLT_PRTADDR_2 (0x04UL << HCSPLT_PRTADDR_Pos) // 0x00000004 +#define HCSPLT_PRTADDR_3 (0x08UL << HCSPLT_PRTADDR_Pos) // 0x00000008 +#define HCSPLT_PRTADDR_4 (0x10UL << HCSPLT_PRTADDR_Pos) // 0x00000010 +#define HCSPLT_PRTADDR_5 (0x20UL << HCSPLT_PRTADDR_Pos) // 0x00000020 +#define HCSPLT_PRTADDR_6 (0x40UL << HCSPLT_PRTADDR_Pos) // 0x00000040 #define HCSPLT_HUBADDR_Pos (7U) -#define HCSPLT_HUBADDR_Msk (0x7FUL << HCSPLT_HUBADDR_Pos) // 0x00003F80 */ -#define HCSPLT_HUBADDR HCSPLT_HUBADDR_Msk // Hub address */ -#define HCSPLT_HUBADDR_0 (0x01UL << HCSPLT_HUBADDR_Pos) // 0x00000080 */ -#define HCSPLT_HUBADDR_1 (0x02UL << HCSPLT_HUBADDR_Pos) // 0x00000100 */ -#define HCSPLT_HUBADDR_2 (0x04UL << HCSPLT_HUBADDR_Pos) // 0x00000200 */ -#define HCSPLT_HUBADDR_3 (0x08UL << HCSPLT_HUBADDR_Pos) // 0x00000400 */ -#define HCSPLT_HUBADDR_4 (0x10UL << HCSPLT_HUBADDR_Pos) // 0x00000800 */ -#define HCSPLT_HUBADDR_5 (0x20UL << HCSPLT_HUBADDR_Pos) // 0x00001000 */ -#define HCSPLT_HUBADDR_6 (0x40UL << HCSPLT_HUBADDR_Pos) // 0x00002000 */ +#define HCSPLT_HUBADDR_Msk (0x7FUL << HCSPLT_HUBADDR_Pos) // 0x00003F80 +#define HCSPLT_HUBADDR HCSPLT_HUBADDR_Msk // Hub address +#define HCSPLT_HUBADDR_0 (0x01UL << HCSPLT_HUBADDR_Pos) // 0x00000080 +#define HCSPLT_HUBADDR_1 (0x02UL << HCSPLT_HUBADDR_Pos) // 0x00000100 +#define HCSPLT_HUBADDR_2 (0x04UL << HCSPLT_HUBADDR_Pos) // 0x00000200 +#define HCSPLT_HUBADDR_3 (0x08UL << HCSPLT_HUBADDR_Pos) // 0x00000400 +#define HCSPLT_HUBADDR_4 (0x10UL << HCSPLT_HUBADDR_Pos) // 0x00000800 +#define HCSPLT_HUBADDR_5 (0x20UL << HCSPLT_HUBADDR_Pos) // 0x00001000 +#define HCSPLT_HUBADDR_6 (0x40UL << HCSPLT_HUBADDR_Pos) // 0x00002000 #define HCSPLT_XACTPOS_Pos (14U) -#define HCSPLT_XACTPOS_Msk (0x3UL << HCSPLT_XACTPOS_Pos) // 0x0000C000 */ -#define HCSPLT_XACTPOS HCSPLT_XACTPOS_Msk // XACTPOS */ -#define HCSPLT_XACTPOS_0 (0x1UL << HCSPLT_XACTPOS_Pos) // 0x00004000 */ -#define HCSPLT_XACTPOS_1 (0x2UL << HCSPLT_XACTPOS_Pos) // 0x00008000 */ +#define HCSPLT_XACTPOS_Msk (0x3UL << HCSPLT_XACTPOS_Pos) // 0x0000C000 +#define HCSPLT_XACTPOS HCSPLT_XACTPOS_Msk // XACTPOS +#define HCSPLT_XACTPOS_0 (0x1UL << HCSPLT_XACTPOS_Pos) // 0x00004000 +#define HCSPLT_XACTPOS_1 (0x2UL << HCSPLT_XACTPOS_Pos) // 0x00008000 #define HCSPLT_COMPLSPLT_Pos (16U) -#define HCSPLT_COMPLSPLT_Msk (0x1UL << HCSPLT_COMPLSPLT_Pos) // 0x00010000 */ -#define HCSPLT_COMPLSPLT HCSPLT_COMPLSPLT_Msk // Do complete split */ +#define HCSPLT_COMPLSPLT_Msk (0x1UL << HCSPLT_COMPLSPLT_Pos) // 0x00010000 +#define HCSPLT_COMPLSPLT HCSPLT_COMPLSPLT_Msk // Do complete split #define HCSPLT_SPLITEN_Pos (31U) -#define HCSPLT_SPLITEN_Msk (0x1UL << HCSPLT_SPLITEN_Pos) // 0x80000000 */ -#define HCSPLT_SPLITEN HCSPLT_SPLITEN_Msk // Split enable */ +#define HCSPLT_SPLITEN_Msk (0x1UL << HCSPLT_SPLITEN_Pos) // 0x80000000 +#define HCSPLT_SPLITEN HCSPLT_SPLITEN_Msk // Split enable /******************** Bit definition for HCINT register ********************/ #define HCINT_XFRC_Pos (0U) -#define HCINT_XFRC_Msk (0x1UL << HCINT_XFRC_Pos) // 0x00000001 */ -#define HCINT_XFRC HCINT_XFRC_Msk // Transfer completed */ +#define HCINT_XFRC_Msk (0x1UL << HCINT_XFRC_Pos) // 0x00000001 +#define HCINT_XFRC HCINT_XFRC_Msk // Transfer completed #define HCINT_CHH_Pos (1U) -#define HCINT_CHH_Msk (0x1UL << HCINT_CHH_Pos) // 0x00000002 */ -#define HCINT_CHH HCINT_CHH_Msk // Channel halted */ +#define HCINT_CHH_Msk (0x1UL << HCINT_CHH_Pos) // 0x00000002 +#define HCINT_CHH HCINT_CHH_Msk // Channel halted #define HCINT_AHBERR_Pos (2U) -#define HCINT_AHBERR_Msk (0x1UL << HCINT_AHBERR_Pos) // 0x00000004 */ -#define HCINT_AHBERR HCINT_AHBERR_Msk // AHB error */ +#define HCINT_AHBERR_Msk (0x1UL << HCINT_AHBERR_Pos) // 0x00000004 +#define HCINT_AHBERR HCINT_AHBERR_Msk // AHB error #define HCINT_STALL_Pos (3U) -#define HCINT_STALL_Msk (0x1UL << HCINT_STALL_Pos) // 0x00000008 */ -#define HCINT_STALL HCINT_STALL_Msk // STALL response received interrupt */ +#define HCINT_STALL_Msk (0x1UL << HCINT_STALL_Pos) // 0x00000008 +#define HCINT_STALL HCINT_STALL_Msk // STALL response received interrupt #define HCINT_NAK_Pos (4U) -#define HCINT_NAK_Msk (0x1UL << HCINT_NAK_Pos) // 0x00000010 */ -#define HCINT_NAK HCINT_NAK_Msk // NAK response received interrupt */ +#define HCINT_NAK_Msk (0x1UL << HCINT_NAK_Pos) // 0x00000010 +#define HCINT_NAK HCINT_NAK_Msk // NAK response received interrupt #define HCINT_ACK_Pos (5U) -#define HCINT_ACK_Msk (0x1UL << HCINT_ACK_Pos) // 0x00000020 */ -#define HCINT_ACK HCINT_ACK_Msk // ACK response received/transmitted interrupt */ +#define HCINT_ACK_Msk (0x1UL << HCINT_ACK_Pos) // 0x00000020 +#define HCINT_ACK HCINT_ACK_Msk // ACK response received/transmitted interrupt #define HCINT_NYET_Pos (6U) -#define HCINT_NYET_Msk (0x1UL << HCINT_NYET_Pos) // 0x00000040 */ -#define HCINT_NYET HCINT_NYET_Msk // Response received interrupt */ +#define HCINT_NYET_Msk (0x1UL << HCINT_NYET_Pos) // 0x00000040 +#define HCINT_NYET HCINT_NYET_Msk // Response received interrupt #define HCINT_TXERR_Pos (7U) -#define HCINT_TXERR_Msk (0x1UL << HCINT_TXERR_Pos) // 0x00000080 */ -#define HCINT_TXERR HCINT_TXERR_Msk // Transaction error */ +#define HCINT_TXERR_Msk (0x1UL << HCINT_TXERR_Pos) // 0x00000080 +#define HCINT_TXERR HCINT_TXERR_Msk // Transaction error #define HCINT_BBERR_Pos (8U) -#define HCINT_BBERR_Msk (0x1UL << HCINT_BBERR_Pos) // 0x00000100 */ -#define HCINT_BBERR HCINT_BBERR_Msk // Babble error */ +#define HCINT_BBERR_Msk (0x1UL << HCINT_BBERR_Pos) // 0x00000100 +#define HCINT_BBERR HCINT_BBERR_Msk // Babble error #define HCINT_FRMOR_Pos (9U) -#define HCINT_FRMOR_Msk (0x1UL << HCINT_FRMOR_Pos) // 0x00000200 */ -#define HCINT_FRMOR HCINT_FRMOR_Msk // Frame overrun */ +#define HCINT_FRMOR_Msk (0x1UL << HCINT_FRMOR_Pos) // 0x00000200 +#define HCINT_FRMOR HCINT_FRMOR_Msk // Frame overrun #define HCINT_DTERR_Pos (10U) -#define HCINT_DTERR_Msk (0x1UL << HCINT_DTERR_Pos) // 0x00000400 */ -#define HCINT_DTERR HCINT_DTERR_Msk // Data toggle error */ +#define HCINT_DTERR_Msk (0x1UL << HCINT_DTERR_Pos) // 0x00000400 +#define HCINT_DTERR HCINT_DTERR_Msk // Data toggle error /******************** Bit definition for DIEPINT register ********************/ #define DIEPINT_XFRC_Pos (0U) -#define DIEPINT_XFRC_Msk (0x1UL << DIEPINT_XFRC_Pos) // 0x00000001 */ -#define DIEPINT_XFRC DIEPINT_XFRC_Msk // Transfer completed interrupt */ +#define DIEPINT_XFRC_Msk (0x1UL << DIEPINT_XFRC_Pos) // 0x00000001 +#define DIEPINT_XFRC DIEPINT_XFRC_Msk // Transfer completed interrupt #define DIEPINT_EPDISD_Pos (1U) -#define DIEPINT_EPDISD_Msk (0x1UL << DIEPINT_EPDISD_Pos) // 0x00000002 */ -#define DIEPINT_EPDISD DIEPINT_EPDISD_Msk // Endpoint disabled interrupt */ +#define DIEPINT_EPDISD_Msk (0x1UL << DIEPINT_EPDISD_Pos) // 0x00000002 +#define DIEPINT_EPDISD DIEPINT_EPDISD_Msk // Endpoint disabled interrupt #define DIEPINT_AHBERR_Pos (2U) -#define DIEPINT_AHBERR_Msk (0x1UL << DIEPINT_AHBERR_Pos) // 0x00000004 */ -#define DIEPINT_AHBERR DIEPINT_AHBERR_Msk // AHB Error (AHBErr) during an IN transaction */ +#define DIEPINT_AHBERR_Msk (0x1UL << DIEPINT_AHBERR_Pos) // 0x00000004 +#define DIEPINT_AHBERR DIEPINT_AHBERR_Msk // AHB Error (AHBErr) during an IN transaction #define DIEPINT_TOC_Pos (3U) -#define DIEPINT_TOC_Msk (0x1UL << DIEPINT_TOC_Pos) // 0x00000008 */ -#define DIEPINT_TOC DIEPINT_TOC_Msk // Timeout condition */ +#define DIEPINT_TOC_Msk (0x1UL << DIEPINT_TOC_Pos) // 0x00000008 +#define DIEPINT_TOC DIEPINT_TOC_Msk // Timeout condition #define DIEPINT_ITTXFE_Pos (4U) -#define DIEPINT_ITTXFE_Msk (0x1UL << DIEPINT_ITTXFE_Pos) // 0x00000010 */ -#define DIEPINT_ITTXFE DIEPINT_ITTXFE_Msk // IN token received when TxFIFO is empty */ +#define DIEPINT_ITTXFE_Msk (0x1UL << DIEPINT_ITTXFE_Pos) // 0x00000010 +#define DIEPINT_ITTXFE DIEPINT_ITTXFE_Msk // IN token received when TxFIFO is empty #define DIEPINT_INEPNM_Pos (5U) -#define DIEPINT_INEPNM_Msk (0x1UL << DIEPINT_INEPNM_Pos) // 0x00000020 */ -#define DIEPINT_INEPNM DIEPINT_INEPNM_Msk // IN token received with EP mismatch */ +#define DIEPINT_INEPNM_Msk (0x1UL << DIEPINT_INEPNM_Pos) // 0x00000020 +#define DIEPINT_INEPNM DIEPINT_INEPNM_Msk // IN token received with EP mismatch #define DIEPINT_INEPNE_Pos (6U) -#define DIEPINT_INEPNE_Msk (0x1UL << DIEPINT_INEPNE_Pos) // 0x00000040 */ -#define DIEPINT_INEPNE DIEPINT_INEPNE_Msk // IN endpoint NAK effective */ +#define DIEPINT_INEPNE_Msk (0x1UL << DIEPINT_INEPNE_Pos) // 0x00000040 +#define DIEPINT_INEPNE DIEPINT_INEPNE_Msk // IN endpoint NAK effective #define DIEPINT_TXFE_Pos (7U) -#define DIEPINT_TXFE_Msk (0x1UL << DIEPINT_TXFE_Pos) // 0x00000080 */ -#define DIEPINT_TXFE DIEPINT_TXFE_Msk // Transmit FIFO empty */ +#define DIEPINT_TXFE_Msk (0x1UL << DIEPINT_TXFE_Pos) // 0x00000080 +#define DIEPINT_TXFE DIEPINT_TXFE_Msk // Transmit FIFO empty #define DIEPINT_TXFIFOUDRN_Pos (8U) -#define DIEPINT_TXFIFOUDRN_Msk (0x1UL << DIEPINT_TXFIFOUDRN_Pos) // 0x00000100 */ -#define DIEPINT_TXFIFOUDRN DIEPINT_TXFIFOUDRN_Msk // Transmit Fifo Underrun */ +#define DIEPINT_TXFIFOUDRN_Msk (0x1UL << DIEPINT_TXFIFOUDRN_Pos) // 0x00000100 +#define DIEPINT_TXFIFOUDRN DIEPINT_TXFIFOUDRN_Msk // Transmit Fifo Underrun #define DIEPINT_BNA_Pos (9U) -#define DIEPINT_BNA_Msk (0x1UL << DIEPINT_BNA_Pos) // 0x00000200 */ -#define DIEPINT_BNA DIEPINT_BNA_Msk // Buffer not available interrupt */ +#define DIEPINT_BNA_Msk (0x1UL << DIEPINT_BNA_Pos) // 0x00000200 +#define DIEPINT_BNA DIEPINT_BNA_Msk // Buffer not available interrupt #define DIEPINT_PKTDRPSTS_Pos (11U) -#define DIEPINT_PKTDRPSTS_Msk (0x1UL << DIEPINT_PKTDRPSTS_Pos) // 0x00000800 */ -#define DIEPINT_PKTDRPSTS DIEPINT_PKTDRPSTS_Msk // Packet dropped status */ +#define DIEPINT_PKTDRPSTS_Msk (0x1UL << DIEPINT_PKTDRPSTS_Pos) // 0x00000800 +#define DIEPINT_PKTDRPSTS DIEPINT_PKTDRPSTS_Msk // Packet dropped status #define DIEPINT_BERR_Pos (12U) -#define DIEPINT_BERR_Msk (0x1UL << DIEPINT_BERR_Pos) // 0x00001000 */ -#define DIEPINT_BERR DIEPINT_BERR_Msk // Babble error interrupt */ +#define DIEPINT_BERR_Msk (0x1UL << DIEPINT_BERR_Pos) // 0x00001000 +#define DIEPINT_BERR DIEPINT_BERR_Msk // Babble error interrupt #define DIEPINT_NAK_Pos (13U) -#define DIEPINT_NAK_Msk (0x1UL << DIEPINT_NAK_Pos) // 0x00002000 */ -#define DIEPINT_NAK DIEPINT_NAK_Msk // NAK interrupt */ +#define DIEPINT_NAK_Msk (0x1UL << DIEPINT_NAK_Pos) // 0x00002000 +#define DIEPINT_NAK DIEPINT_NAK_Msk // NAK interrupt /******************** Bit definition for HCINTMSK register ********************/ #define HCINTMSK_XFRCM_Pos (0U) -#define HCINTMSK_XFRCM_Msk (0x1UL << HCINTMSK_XFRCM_Pos) // 0x00000001 */ -#define HCINTMSK_XFRCM HCINTMSK_XFRCM_Msk // Transfer completed mask */ +#define HCINTMSK_XFRCM_Msk (0x1UL << HCINTMSK_XFRCM_Pos) // 0x00000001 +#define HCINTMSK_XFRCM HCINTMSK_XFRCM_Msk // Transfer completed mask #define HCINTMSK_CHHM_Pos (1U) -#define HCINTMSK_CHHM_Msk (0x1UL << HCINTMSK_CHHM_Pos) // 0x00000002 */ -#define HCINTMSK_CHHM HCINTMSK_CHHM_Msk // Channel halted mask */ +#define HCINTMSK_CHHM_Msk (0x1UL << HCINTMSK_CHHM_Pos) // 0x00000002 +#define HCINTMSK_CHHM HCINTMSK_CHHM_Msk // Channel halted mask #define HCINTMSK_AHBERR_Pos (2U) -#define HCINTMSK_AHBERR_Msk (0x1UL << HCINTMSK_AHBERR_Pos) // 0x00000004 */ -#define HCINTMSK_AHBERR HCINTMSK_AHBERR_Msk // AHB error */ +#define HCINTMSK_AHBERR_Msk (0x1UL << HCINTMSK_AHBERR_Pos) // 0x00000004 +#define HCINTMSK_AHBERR HCINTMSK_AHBERR_Msk // AHB error #define HCINTMSK_STALLM_Pos (3U) -#define HCINTMSK_STALLM_Msk (0x1UL << HCINTMSK_STALLM_Pos) // 0x00000008 */ -#define HCINTMSK_STALLM HCINTMSK_STALLM_Msk // STALL response received interrupt mask */ +#define HCINTMSK_STALLM_Msk (0x1UL << HCINTMSK_STALLM_Pos) // 0x00000008 +#define HCINTMSK_STALLM HCINTMSK_STALLM_Msk // STALL response received interrupt mask #define HCINTMSK_NAKM_Pos (4U) -#define HCINTMSK_NAKM_Msk (0x1UL << HCINTMSK_NAKM_Pos) // 0x00000010 */ -#define HCINTMSK_NAKM HCINTMSK_NAKM_Msk // NAK response received interrupt mask */ +#define HCINTMSK_NAKM_Msk (0x1UL << HCINTMSK_NAKM_Pos) // 0x00000010 +#define HCINTMSK_NAKM HCINTMSK_NAKM_Msk // NAK response received interrupt mask #define HCINTMSK_ACKM_Pos (5U) -#define HCINTMSK_ACKM_Msk (0x1UL << HCINTMSK_ACKM_Pos) // 0x00000020 */ -#define HCINTMSK_ACKM HCINTMSK_ACKM_Msk // ACK response received/transmitted interrupt mask */ +#define HCINTMSK_ACKM_Msk (0x1UL << HCINTMSK_ACKM_Pos) // 0x00000020 +#define HCINTMSK_ACKM HCINTMSK_ACKM_Msk // ACK response received/transmitted interrupt mask #define HCINTMSK_NYET_Pos (6U) -#define HCINTMSK_NYET_Msk (0x1UL << HCINTMSK_NYET_Pos) // 0x00000040 */ -#define HCINTMSK_NYET HCINTMSK_NYET_Msk // response received interrupt mask */ +#define HCINTMSK_NYET_Msk (0x1UL << HCINTMSK_NYET_Pos) // 0x00000040 +#define HCINTMSK_NYET HCINTMSK_NYET_Msk // response received interrupt mask #define HCINTMSK_TXERRM_Pos (7U) -#define HCINTMSK_TXERRM_Msk (0x1UL << HCINTMSK_TXERRM_Pos) // 0x00000080 */ -#define HCINTMSK_TXERRM HCINTMSK_TXERRM_Msk // Transaction error mask */ +#define HCINTMSK_TXERRM_Msk (0x1UL << HCINTMSK_TXERRM_Pos) // 0x00000080 +#define HCINTMSK_TXERRM HCINTMSK_TXERRM_Msk // Transaction error mask #define HCINTMSK_BBERRM_Pos (8U) -#define HCINTMSK_BBERRM_Msk (0x1UL << HCINTMSK_BBERRM_Pos) // 0x00000100 */ -#define HCINTMSK_BBERRM HCINTMSK_BBERRM_Msk // Babble error mask */ +#define HCINTMSK_BBERRM_Msk (0x1UL << HCINTMSK_BBERRM_Pos) // 0x00000100 +#define HCINTMSK_BBERRM HCINTMSK_BBERRM_Msk // Babble error mask #define HCINTMSK_FRMORM_Pos (9U) -#define HCINTMSK_FRMORM_Msk (0x1UL << HCINTMSK_FRMORM_Pos) // 0x00000200 */ -#define HCINTMSK_FRMORM HCINTMSK_FRMORM_Msk // Frame overrun mask */ +#define HCINTMSK_FRMORM_Msk (0x1UL << HCINTMSK_FRMORM_Pos) // 0x00000200 +#define HCINTMSK_FRMORM HCINTMSK_FRMORM_Msk // Frame overrun mask #define HCINTMSK_DTERRM_Pos (10U) -#define HCINTMSK_DTERRM_Msk (0x1UL << HCINTMSK_DTERRM_Pos) // 0x00000400 */ -#define HCINTMSK_DTERRM HCINTMSK_DTERRM_Msk // Data toggle error mask */ +#define HCINTMSK_DTERRM_Msk (0x1UL << HCINTMSK_DTERRM_Pos) // 0x00000400 +#define HCINTMSK_DTERRM HCINTMSK_DTERRM_Msk // Data toggle error mask /******************** Bit definition for DIEPTSIZ register ********************/ #define DIEPTSIZ_XFRSIZ_Pos (0U) -#define DIEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << DIEPTSIZ_XFRSIZ_Pos) // 0x0007FFFF */ -#define DIEPTSIZ_XFRSIZ DIEPTSIZ_XFRSIZ_Msk // Transfer size */ +#define DIEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << DIEPTSIZ_XFRSIZ_Pos) // 0x0007FFFF +#define DIEPTSIZ_XFRSIZ DIEPTSIZ_XFRSIZ_Msk // Transfer size #define DIEPTSIZ_PKTCNT_Pos (19U) -#define DIEPTSIZ_PKTCNT_Msk (0x3FFUL << DIEPTSIZ_PKTCNT_Pos) // 0x1FF80000 */ -#define DIEPTSIZ_PKTCNT DIEPTSIZ_PKTCNT_Msk // Packet count */ +#define DIEPTSIZ_PKTCNT_Msk (0x3FFUL << DIEPTSIZ_PKTCNT_Pos) // 0x1FF80000 +#define DIEPTSIZ_PKTCNT DIEPTSIZ_PKTCNT_Msk // Packet count #define DIEPTSIZ_MULCNT_Pos (29U) -#define DIEPTSIZ_MULCNT_Msk (0x3UL << DIEPTSIZ_MULCNT_Pos) // 0x60000000 */ -#define DIEPTSIZ_MULCNT DIEPTSIZ_MULCNT_Msk // Packet count */ +#define DIEPTSIZ_MULCNT_Msk (0x3UL << DIEPTSIZ_MULCNT_Pos) // 0x60000000 +#define DIEPTSIZ_MULCNT DIEPTSIZ_MULCNT_Msk // Packet count /******************** Bit definition for HCTSIZ register ********************/ #define HCTSIZ_XFRSIZ_Pos (0U) -#define HCTSIZ_XFRSIZ_Msk (0x7FFFFUL << HCTSIZ_XFRSIZ_Pos) // 0x0007FFFF */ -#define HCTSIZ_XFRSIZ HCTSIZ_XFRSIZ_Msk // Transfer size */ +#define HCTSIZ_XFRSIZ_Msk (0x7FFFFUL << HCTSIZ_XFRSIZ_Pos) // 0x0007FFFF +#define HCTSIZ_XFRSIZ HCTSIZ_XFRSIZ_Msk // Transfer size #define HCTSIZ_PKTCNT_Pos (19U) -#define HCTSIZ_PKTCNT_Msk (0x3FFUL << HCTSIZ_PKTCNT_Pos) // 0x1FF80000 */ -#define HCTSIZ_PKTCNT HCTSIZ_PKTCNT_Msk // Packet count */ +#define HCTSIZ_PKTCNT_Msk (0x3FFUL << HCTSIZ_PKTCNT_Pos) // 0x1FF80000 +#define HCTSIZ_PKTCNT HCTSIZ_PKTCNT_Msk // Packet count #define HCTSIZ_DOPING_Pos (31U) -#define HCTSIZ_DOPING_Msk (0x1UL << HCTSIZ_DOPING_Pos) // 0x80000000 */ -#define HCTSIZ_DOPING HCTSIZ_DOPING_Msk // Do PING */ +#define HCTSIZ_DOPING_Msk (0x1UL << HCTSIZ_DOPING_Pos) // 0x80000000 +#define HCTSIZ_DOPING HCTSIZ_DOPING_Msk // Do PING #define HCTSIZ_DPID_Pos (29U) -#define HCTSIZ_DPID_Msk (0x3UL << HCTSIZ_DPID_Pos) // 0x60000000 */ -#define HCTSIZ_DPID HCTSIZ_DPID_Msk // Data PID */ -#define HCTSIZ_DPID_0 (0x1UL << HCTSIZ_DPID_Pos) // 0x20000000 */ -#define HCTSIZ_DPID_1 (0x2UL << HCTSIZ_DPID_Pos) // 0x40000000 */ +#define HCTSIZ_DPID_Msk (0x3UL << HCTSIZ_DPID_Pos) // 0x60000000 +#define HCTSIZ_DPID HCTSIZ_DPID_Msk // Data PID +#define HCTSIZ_DPID_0 (0x1UL << HCTSIZ_DPID_Pos) // 0x20000000 +#define HCTSIZ_DPID_1 (0x2UL << HCTSIZ_DPID_Pos) // 0x40000000 /******************** Bit definition for DIEPDMA register ********************/ #define DIEPDMA_DMAADDR_Pos (0U) -#define DIEPDMA_DMAADDR_Msk (0xFFFFFFFFUL << DIEPDMA_DMAADDR_Pos) // 0xFFFFFFFF */ -#define DIEPDMA_DMAADDR DIEPDMA_DMAADDR_Msk // DMA address */ +#define DIEPDMA_DMAADDR_Msk (0xFFFFFFFFUL << DIEPDMA_DMAADDR_Pos) // 0xFFFFFFFF +#define DIEPDMA_DMAADDR DIEPDMA_DMAADDR_Msk // DMA address /******************** Bit definition for HCDMA register ********************/ #define HCDMA_DMAADDR_Pos (0U) -#define HCDMA_DMAADDR_Msk (0xFFFFFFFFUL << HCDMA_DMAADDR_Pos) // 0xFFFFFFFF */ -#define HCDMA_DMAADDR HCDMA_DMAADDR_Msk // DMA address */ +#define HCDMA_DMAADDR_Msk (0xFFFFFFFFUL << HCDMA_DMAADDR_Pos) // 0xFFFFFFFF +#define HCDMA_DMAADDR HCDMA_DMAADDR_Msk // DMA address /******************** Bit definition for DTXFSTS register ********************/ #define DTXFSTS_INEPTFSAV_Pos (0U) -#define DTXFSTS_INEPTFSAV_Msk (0xFFFFUL << DTXFSTS_INEPTFSAV_Pos) // 0x0000FFFF */ -#define DTXFSTS_INEPTFSAV DTXFSTS_INEPTFSAV_Msk // IN endpoint TxFIFO space available */ +#define DTXFSTS_INEPTFSAV_Msk (0xFFFFUL << DTXFSTS_INEPTFSAV_Pos) // 0x0000FFFF +#define DTXFSTS_INEPTFSAV DTXFSTS_INEPTFSAV_Msk // IN endpoint TxFIFO space available /******************** Bit definition for DIEPTXF register ********************/ #define DIEPTXF_INEPTXSA_Pos (0U) -#define DIEPTXF_INEPTXSA_Msk (0xFFFFUL << DIEPTXF_INEPTXSA_Pos) // 0x0000FFFF */ -#define DIEPTXF_INEPTXSA DIEPTXF_INEPTXSA_Msk // IN endpoint FIFOx transmit RAM start address */ +#define DIEPTXF_INEPTXSA_Msk (0xFFFFUL << DIEPTXF_INEPTXSA_Pos) // 0x0000FFFF +#define DIEPTXF_INEPTXSA DIEPTXF_INEPTXSA_Msk // IN endpoint FIFOx transmit RAM start address #define DIEPTXF_INEPTXFD_Pos (16U) -#define DIEPTXF_INEPTXFD_Msk (0xFFFFUL << DIEPTXF_INEPTXFD_Pos) // 0xFFFF0000 */ -#define DIEPTXF_INEPTXFD DIEPTXF_INEPTXFD_Msk // IN endpoint TxFIFO depth */ +#define DIEPTXF_INEPTXFD_Msk (0xFFFFUL << DIEPTXF_INEPTXFD_Pos) // 0xFFFF0000 +#define DIEPTXF_INEPTXFD DIEPTXF_INEPTXFD_Msk // IN endpoint TxFIFO depth /******************** Bit definition for DOEPCTL register ********************/ #define DOEPCTL_MPSIZ_Pos (0U) -#define DOEPCTL_MPSIZ_Msk (0x7FFUL << DOEPCTL_MPSIZ_Pos) // 0x000007FF */ -#define DOEPCTL_MPSIZ DOEPCTL_MPSIZ_Msk // Maximum packet size */ //Bit 1 */ +#define DOEPCTL_MPSIZ_Msk (0x7FFUL << DOEPCTL_MPSIZ_Pos) // 0x000007FF +#define DOEPCTL_MPSIZ DOEPCTL_MPSIZ_Msk // Maximum packet size //Bit 1 #define DOEPCTL_USBAEP_Pos (15U) -#define DOEPCTL_USBAEP_Msk (0x1UL << DOEPCTL_USBAEP_Pos) // 0x00008000 */ -#define DOEPCTL_USBAEP DOEPCTL_USBAEP_Msk // USB active endpoint */ +#define DOEPCTL_USBAEP_Msk (0x1UL << DOEPCTL_USBAEP_Pos) // 0x00008000 +#define DOEPCTL_USBAEP DOEPCTL_USBAEP_Msk // USB active endpoint #define DOEPCTL_NAKSTS_Pos (17U) -#define DOEPCTL_NAKSTS_Msk (0x1UL << DOEPCTL_NAKSTS_Pos) // 0x00020000 */ -#define DOEPCTL_NAKSTS DOEPCTL_NAKSTS_Msk // NAK status */ +#define DOEPCTL_NAKSTS_Msk (0x1UL << DOEPCTL_NAKSTS_Pos) // 0x00020000 +#define DOEPCTL_NAKSTS DOEPCTL_NAKSTS_Msk // NAK status #define DOEPCTL_SD0PID_SEVNFRM_Pos (28U) -#define DOEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << DOEPCTL_SD0PID_SEVNFRM_Pos) // 0x10000000 */ -#define DOEPCTL_SD0PID_SEVNFRM DOEPCTL_SD0PID_SEVNFRM_Msk // Set DATA0 PID */ +#define DOEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << DOEPCTL_SD0PID_SEVNFRM_Pos) // 0x10000000 +#define DOEPCTL_SD0PID_SEVNFRM DOEPCTL_SD0PID_SEVNFRM_Msk // Set DATA0 PID #define DOEPCTL_SODDFRM_Pos (29U) -#define DOEPCTL_SODDFRM_Msk (0x1UL << DOEPCTL_SODDFRM_Pos) // 0x20000000 */ -#define DOEPCTL_SODDFRM DOEPCTL_SODDFRM_Msk // Set odd frame */ +#define DOEPCTL_SODDFRM_Msk (0x1UL << DOEPCTL_SODDFRM_Pos) // 0x20000000 +#define DOEPCTL_SODDFRM DOEPCTL_SODDFRM_Msk // Set odd frame #define DOEPCTL_EPTYP_Pos (18U) -#define DOEPCTL_EPTYP_Msk (0x3UL << DOEPCTL_EPTYP_Pos) // 0x000C0000 */ -#define DOEPCTL_EPTYP DOEPCTL_EPTYP_Msk // Endpoint type */ -#define DOEPCTL_EPTYP_0 (0x1UL << DOEPCTL_EPTYP_Pos) // 0x00040000 */ -#define DOEPCTL_EPTYP_1 (0x2UL << DOEPCTL_EPTYP_Pos) // 0x00080000 */ +#define DOEPCTL_EPTYP_Msk (0x3UL << DOEPCTL_EPTYP_Pos) // 0x000C0000 +#define DOEPCTL_EPTYP DOEPCTL_EPTYP_Msk // Endpoint type +#define DOEPCTL_EPTYP_0 (0x1UL << DOEPCTL_EPTYP_Pos) // 0x00040000 +#define DOEPCTL_EPTYP_1 (0x2UL << DOEPCTL_EPTYP_Pos) // 0x00080000 #define DOEPCTL_SNPM_Pos (20U) -#define DOEPCTL_SNPM_Msk (0x1UL << DOEPCTL_SNPM_Pos) // 0x00100000 */ -#define DOEPCTL_SNPM DOEPCTL_SNPM_Msk // Snoop mode */ +#define DOEPCTL_SNPM_Msk (0x1UL << DOEPCTL_SNPM_Pos) // 0x00100000 +#define DOEPCTL_SNPM DOEPCTL_SNPM_Msk // Snoop mode #define DOEPCTL_STALL_Pos (21U) -#define DOEPCTL_STALL_Msk (0x1UL << DOEPCTL_STALL_Pos) // 0x00200000 */ -#define DOEPCTL_STALL DOEPCTL_STALL_Msk // STALL handshake */ +#define DOEPCTL_STALL_Msk (0x1UL << DOEPCTL_STALL_Pos) // 0x00200000 +#define DOEPCTL_STALL DOEPCTL_STALL_Msk // STALL handshake #define DOEPCTL_CNAK_Pos (26U) -#define DOEPCTL_CNAK_Msk (0x1UL << DOEPCTL_CNAK_Pos) // 0x04000000 */ -#define DOEPCTL_CNAK DOEPCTL_CNAK_Msk // Clear NAK */ +#define DOEPCTL_CNAK_Msk (0x1UL << DOEPCTL_CNAK_Pos) // 0x04000000 +#define DOEPCTL_CNAK DOEPCTL_CNAK_Msk // Clear NAK #define DOEPCTL_SNAK_Pos (27U) -#define DOEPCTL_SNAK_Msk (0x1UL << DOEPCTL_SNAK_Pos) // 0x08000000 */ -#define DOEPCTL_SNAK DOEPCTL_SNAK_Msk // Set NAK */ +#define DOEPCTL_SNAK_Msk (0x1UL << DOEPCTL_SNAK_Pos) // 0x08000000 +#define DOEPCTL_SNAK DOEPCTL_SNAK_Msk // Set NAK #define DOEPCTL_EPDIS_Pos (30U) -#define DOEPCTL_EPDIS_Msk (0x1UL << DOEPCTL_EPDIS_Pos) // 0x40000000 */ -#define DOEPCTL_EPDIS DOEPCTL_EPDIS_Msk // Endpoint disable */ +#define DOEPCTL_EPDIS_Msk (0x1UL << DOEPCTL_EPDIS_Pos) // 0x40000000 +#define DOEPCTL_EPDIS DOEPCTL_EPDIS_Msk // Endpoint disable #define DOEPCTL_EPENA_Pos (31U) -#define DOEPCTL_EPENA_Msk (0x1UL << DOEPCTL_EPENA_Pos) // 0x80000000 */ -#define DOEPCTL_EPENA DOEPCTL_EPENA_Msk // Endpoint enable */ +#define DOEPCTL_EPENA_Msk (0x1UL << DOEPCTL_EPENA_Pos) // 0x80000000 +#define DOEPCTL_EPENA DOEPCTL_EPENA_Msk // Endpoint enable /******************** Bit definition for DOEPINT register ********************/ #define DOEPINT_XFRC_Pos (0U) -#define DOEPINT_XFRC_Msk (0x1UL << DOEPINT_XFRC_Pos) // 0x00000001 */ -#define DOEPINT_XFRC DOEPINT_XFRC_Msk // Transfer completed interrupt */ +#define DOEPINT_XFRC_Msk (0x1UL << DOEPINT_XFRC_Pos) // 0x00000001 +#define DOEPINT_XFRC DOEPINT_XFRC_Msk // Transfer completed interrupt #define DOEPINT_EPDISD_Pos (1U) -#define DOEPINT_EPDISD_Msk (0x1UL << DOEPINT_EPDISD_Pos) // 0x00000002 */ -#define DOEPINT_EPDISD DOEPINT_EPDISD_Msk // Endpoint disabled interrupt */ +#define DOEPINT_EPDISD_Msk (0x1UL << DOEPINT_EPDISD_Pos) // 0x00000002 +#define DOEPINT_EPDISD DOEPINT_EPDISD_Msk // Endpoint disabled interrupt #define DOEPINT_AHBERR_Pos (2U) -#define DOEPINT_AHBERR_Msk (0x1UL << DOEPINT_AHBERR_Pos) // 0x00000004 */ -#define DOEPINT_AHBERR DOEPINT_AHBERR_Msk // AHB Error (AHBErr) during an OUT transaction */ +#define DOEPINT_AHBERR_Msk (0x1UL << DOEPINT_AHBERR_Pos) // 0x00000004 +#define DOEPINT_AHBERR DOEPINT_AHBERR_Msk // AHB Error (AHBErr) during an OUT transaction #define DOEPINT_STUP_Pos (3U) -#define DOEPINT_STUP_Msk (0x1UL << DOEPINT_STUP_Pos) // 0x00000008 */ -#define DOEPINT_STUP DOEPINT_STUP_Msk // SETUP phase done */ +#define DOEPINT_STUP_Msk (0x1UL << DOEPINT_STUP_Pos) // 0x00000008 +#define DOEPINT_STUP DOEPINT_STUP_Msk // SETUP phase done #define DOEPINT_OTEPDIS_Pos (4U) -#define DOEPINT_OTEPDIS_Msk (0x1UL << DOEPINT_OTEPDIS_Pos) // 0x00000010 */ -#define DOEPINT_OTEPDIS DOEPINT_OTEPDIS_Msk // OUT token received when endpoint disabled */ +#define DOEPINT_OTEPDIS_Msk (0x1UL << DOEPINT_OTEPDIS_Pos) // 0x00000010 +#define DOEPINT_OTEPDIS DOEPINT_OTEPDIS_Msk // OUT token received when endpoint disabled #define DOEPINT_OTEPSPR_Pos (5U) -#define DOEPINT_OTEPSPR_Msk (0x1UL << DOEPINT_OTEPSPR_Pos) // 0x00000020 */ -#define DOEPINT_OTEPSPR DOEPINT_OTEPSPR_Msk // Status Phase Received For Control Write */ +#define DOEPINT_OTEPSPR_Msk (0x1UL << DOEPINT_OTEPSPR_Pos) // 0x00000020 +#define DOEPINT_OTEPSPR DOEPINT_OTEPSPR_Msk // Status Phase Received For Control Write #define DOEPINT_B2BSTUP_Pos (6U) -#define DOEPINT_B2BSTUP_Msk (0x1UL << DOEPINT_B2BSTUP_Pos) // 0x00000040 */ -#define DOEPINT_B2BSTUP DOEPINT_B2BSTUP_Msk // Back-to-back SETUP packets received */ +#define DOEPINT_B2BSTUP_Msk (0x1UL << DOEPINT_B2BSTUP_Pos) // 0x00000040 +#define DOEPINT_B2BSTUP DOEPINT_B2BSTUP_Msk // Back-to-back SETUP packets received #define DOEPINT_OUTPKTERR_Pos (8U) -#define DOEPINT_OUTPKTERR_Msk (0x1UL << DOEPINT_OUTPKTERR_Pos) // 0x00000100 */ -#define DOEPINT_OUTPKTERR DOEPINT_OUTPKTERR_Msk // OUT packet error */ +#define DOEPINT_OUTPKTERR_Msk (0x1UL << DOEPINT_OUTPKTERR_Pos) // 0x00000100 +#define DOEPINT_OUTPKTERR DOEPINT_OUTPKTERR_Msk // OUT packet error #define DOEPINT_NAK_Pos (13U) -#define DOEPINT_NAK_Msk (0x1UL << DOEPINT_NAK_Pos) // 0x00002000 */ -#define DOEPINT_NAK DOEPINT_NAK_Msk // NAK Packet is transmitted by the device */ +#define DOEPINT_NAK_Msk (0x1UL << DOEPINT_NAK_Pos) // 0x00002000 +#define DOEPINT_NAK DOEPINT_NAK_Msk // NAK Packet is transmitted by the device #define DOEPINT_NYET_Pos (14U) -#define DOEPINT_NYET_Msk (0x1UL << DOEPINT_NYET_Pos) // 0x00004000 */ -#define DOEPINT_NYET DOEPINT_NYET_Msk // NYET interrupt */ +#define DOEPINT_NYET_Msk (0x1UL << DOEPINT_NYET_Pos) // 0x00004000 +#define DOEPINT_NYET DOEPINT_NYET_Msk // NYET interrupt #define DOEPINT_STPKTRX_Pos (15U) -#define DOEPINT_STPKTRX_Msk (0x1UL << DOEPINT_STPKTRX_Pos) // 0x00008000 */ -#define DOEPINT_STPKTRX DOEPINT_STPKTRX_Msk // Setup Packet Received */ +#define DOEPINT_STPKTRX_Msk (0x1UL << DOEPINT_STPKTRX_Pos) // 0x00008000 +#define DOEPINT_STPKTRX DOEPINT_STPKTRX_Msk // Setup Packet Received /******************** Bit definition for DOEPTSIZ register ********************/ #define DOEPTSIZ_XFRSIZ_Pos (0U) -#define DOEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << DOEPTSIZ_XFRSIZ_Pos) // 0x0007FFFF */ -#define DOEPTSIZ_XFRSIZ DOEPTSIZ_XFRSIZ_Msk // Transfer size */ +#define DOEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << DOEPTSIZ_XFRSIZ_Pos) // 0x0007FFFF +#define DOEPTSIZ_XFRSIZ DOEPTSIZ_XFRSIZ_Msk // Transfer size #define DOEPTSIZ_PKTCNT_Pos (19U) -#define DOEPTSIZ_PKTCNT_Msk (0x3FFUL << DOEPTSIZ_PKTCNT_Pos) // 0x1FF80000 */ -#define DOEPTSIZ_PKTCNT DOEPTSIZ_PKTCNT_Msk // Packet count */ +#define DOEPTSIZ_PKTCNT_Msk (0x3FFUL << DOEPTSIZ_PKTCNT_Pos) // 0x1FF80000 +#define DOEPTSIZ_PKTCNT DOEPTSIZ_PKTCNT_Msk // Packet count #define DOEPTSIZ_STUPCNT_Pos (29U) -#define DOEPTSIZ_STUPCNT_Msk (0x3UL << DOEPTSIZ_STUPCNT_Pos) // 0x60000000 */ -#define DOEPTSIZ_STUPCNT DOEPTSIZ_STUPCNT_Msk // SETUP packet count */ -#define DOEPTSIZ_STUPCNT_0 (0x1UL << DOEPTSIZ_STUPCNT_Pos) // 0x20000000 */ -#define DOEPTSIZ_STUPCNT_1 (0x2UL << DOEPTSIZ_STUPCNT_Pos) // 0x40000000 */ +#define DOEPTSIZ_STUPCNT_Msk (0x3UL << DOEPTSIZ_STUPCNT_Pos) // 0x60000000 +#define DOEPTSIZ_STUPCNT DOEPTSIZ_STUPCNT_Msk // SETUP packet count +#define DOEPTSIZ_STUPCNT_0 (0x1UL << DOEPTSIZ_STUPCNT_Pos) // 0x20000000 +#define DOEPTSIZ_STUPCNT_1 (0x2UL << DOEPTSIZ_STUPCNT_Pos) // 0x40000000 /******************** Bit definition for PCGCTL register ********************/ #define PCGCTL_IF_DEV_MODE TU_BIT(31) diff --git a/test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_xmc.h b/test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_xmc.h similarity index 100% rename from test-devices/composite-stm32/lib/tinyusb/dwc2/dwc2_xmc.h rename to test-devices/composite-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_xmc.h diff --git a/test-devices/composite-stm32/lib/tinyusb/tusb.c b/test-devices/composite-stm32/lib/tinyusb/tusb.c index 85fe5a3c..0092267a 100644 --- a/test-devices/composite-stm32/lib/tinyusb/tusb.c +++ b/test-devices/composite-stm32/lib/tinyusb/tusb.c @@ -36,39 +36,37 @@ #endif #if CFG_TUH_ENABLED -#include "host/usbh_classdriver.h" +#include "host/usbh_pvt.h" #endif //--------------------------------------------------------------------+ // Public API //--------------------------------------------------------------------+ -bool tusb_init(void) -{ -#if CFG_TUD_ENABLED && defined(TUD_OPT_RHPORT) +bool tusb_init(void) { + #if CFG_TUD_ENABLED && defined(TUD_OPT_RHPORT) // init device stack CFG_TUSB_RHPORTx_MODE must be defined TU_ASSERT ( tud_init(TUD_OPT_RHPORT) ); -#endif + #endif -#if CFG_TUH_ENABLED && defined(TUH_OPT_RHPORT) + #if CFG_TUH_ENABLED && defined(TUH_OPT_RHPORT) // init host stack CFG_TUSB_RHPORTx_MODE must be defined TU_ASSERT( tuh_init(TUH_OPT_RHPORT) ); -#endif + #endif return true; } -bool tusb_inited(void) -{ +bool tusb_inited(void) { bool ret = false; -#if CFG_TUD_ENABLED + #if CFG_TUD_ENABLED ret = ret || tud_inited(); -#endif + #endif -#if CFG_TUH_ENABLED + #if CFG_TUH_ENABLED ret = ret || tuh_inited(); -#endif + #endif return ret; } @@ -77,43 +75,35 @@ bool tusb_inited(void) // Descriptor helper //--------------------------------------------------------------------+ -uint8_t const * tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byte1) -{ - while(desc+1 < end) - { - if ( desc[1] == byte1 ) return desc; +uint8_t const* tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byte1) { + while (desc + 1 < end) { + if (desc[1] == byte1) return desc; desc += desc[DESC_OFFSET_LEN]; } return NULL; } -uint8_t const * tu_desc_find2(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2) -{ - while(desc+2 < end) - { - if ( desc[1] == byte1 && desc[2] == byte2) return desc; +uint8_t const* tu_desc_find2(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2) { + while (desc + 2 < end) { + if (desc[1] == byte1 && desc[2] == byte2) return desc; desc += desc[DESC_OFFSET_LEN]; } return NULL; } -uint8_t const * tu_desc_find3(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2, uint8_t byte3) -{ - while(desc+3 < end) - { +uint8_t const* tu_desc_find3(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2, uint8_t byte3) { + while (desc + 3 < end) { if (desc[1] == byte1 && desc[2] == byte2 && desc[3] == byte3) return desc; desc += desc[DESC_OFFSET_LEN]; } return NULL; } - //--------------------------------------------------------------------+ // Endpoint Helper for both Host and Device stack //--------------------------------------------------------------------+ -bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex) -{ +bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex) { (void) mutex; // pre-check to help reducing mutex lock @@ -122,111 +112,93 @@ bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex) // can only claim the endpoint if it is not busy and not claimed yet. bool const available = (ep_state->busy == 0) && (ep_state->claimed == 0); - if (available) - { + if (available) { ep_state->claimed = 1; } (void) osal_mutex_unlock(mutex); - return available; } -bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex) -{ +bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex) { (void) mutex; - (void) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); // can only release the endpoint if it is claimed and not busy bool const ret = (ep_state->claimed == 1) && (ep_state->busy == 0); - if (ret) - { + if (ret) { ep_state->claimed = 0; } (void) osal_mutex_unlock(mutex); - return ret; } -bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed) -{ +bool tu_edpt_validate(tusb_desc_endpoint_t const* desc_ep, tusb_speed_t speed) { uint16_t const max_packet_size = tu_edpt_packet_size(desc_ep); TU_LOG2(" Open EP %02X with Size = %u\r\n", desc_ep->bEndpointAddress, max_packet_size); - switch (desc_ep->bmAttributes.xfer) - { - case TUSB_XFER_ISOCHRONOUS: - { + switch (desc_ep->bmAttributes.xfer) { + case TUSB_XFER_ISOCHRONOUS: { uint16_t const spec_size = (speed == TUSB_SPEED_HIGH ? 1024 : 1023); TU_ASSERT(max_packet_size <= spec_size); + break; } - break; case TUSB_XFER_BULK: - if (speed == TUSB_SPEED_HIGH) - { + if (speed == TUSB_SPEED_HIGH) { // Bulk highspeed must be EXACTLY 512 TU_ASSERT(max_packet_size == 512); - }else - { + } else { // TODO Bulk fullspeed can only be 8, 16, 32, 64 TU_ASSERT(max_packet_size <= 64); } - break; + break; - case TUSB_XFER_INTERRUPT: - { + case TUSB_XFER_INTERRUPT: { uint16_t const spec_size = (speed == TUSB_SPEED_HIGH ? 1024 : 64); TU_ASSERT(max_packet_size <= spec_size); + break; } - break; - default: return false; + default: + return false; } return true; } -void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* desc_itf, uint16_t desc_len, uint8_t driver_id) -{ +void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* desc_itf, uint16_t desc_len, + uint8_t driver_id) { uint8_t const* p_desc = (uint8_t const*) desc_itf; uint8_t const* desc_end = p_desc + desc_len; - while( p_desc < desc_end ) - { - if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) - { + while (p_desc < desc_end) { + if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) { uint8_t const ep_addr = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress; - TU_LOG(2, " Bind EP %02x to driver id %u\r\n", ep_addr, driver_id); ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)] = driver_id; } - p_desc = tu_desc_next(p_desc); } } -uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len) -{ +uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len) { uint8_t const* p_desc = (uint8_t const*) desc_itf; uint16_t len = 0; - while (itf_count--) - { + while (itf_count--) { // Next on interface desc len += tu_desc_len(desc_itf); p_desc = tu_desc_next(p_desc); - while (len < max_len) - { + while (len < max_len) { // return on IAD regardless of itf count - if ( tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION ) return len; - - if ( (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) && - ((tusb_desc_interface_t const*) p_desc)->bAlternateSetting == 0 ) - { + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION) { + return len; + } + if ((tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) && + ((tusb_desc_interface_t const*) p_desc)->bAlternateSetting == 0) { break; } @@ -243,9 +215,8 @@ uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, //--------------------------------------------------------------------+ bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool overwritable, - void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize) -{ - osal_mutex_t new_mutex = osal_mutex_create(&s->ff_mutex); + void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize) { + osal_mutex_t new_mutex = osal_mutex_create(&s->ff_mutexdef); (void) new_mutex; (void) is_tx; @@ -259,92 +230,82 @@ bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool ove return true; } +bool tu_edpt_stream_deinit(tu_edpt_stream_t* s) { + (void) s; + #if OSAL_MUTEX_REQUIRED + if (s->ff.mutex_wr) osal_mutex_delete(s->ff.mutex_wr); + if (s->ff.mutex_rd) osal_mutex_delete(s->ff.mutex_rd); + #endif + return true; +} + TU_ATTR_ALWAYS_INLINE static inline -bool stream_claim(tu_edpt_stream_t* s) -{ - if (s->is_host) - { +bool stream_claim(tu_edpt_stream_t* s) { + if (s->is_host) { #if CFG_TUH_ENABLED return usbh_edpt_claim(s->daddr, s->ep_addr); #endif - }else - { + } else { #if CFG_TUD_ENABLED return usbd_edpt_claim(s->rhport, s->ep_addr); #endif } - return false; } TU_ATTR_ALWAYS_INLINE static inline -bool stream_xfer(tu_edpt_stream_t* s, uint16_t count) -{ - if (s->is_host) - { +bool stream_xfer(tu_edpt_stream_t* s, uint16_t count) { + if (s->is_host) { #if CFG_TUH_ENABLED return usbh_edpt_xfer(s->daddr, s->ep_addr, count ? s->ep_buf : NULL, count); #endif - }else - { + } else { #if CFG_TUD_ENABLED return usbd_edpt_xfer(s->rhport, s->ep_addr, count ? s->ep_buf : NULL, count); #endif } - return false; } TU_ATTR_ALWAYS_INLINE static inline -bool stream_release(tu_edpt_stream_t* s) -{ - if (s->is_host) - { +bool stream_release(tu_edpt_stream_t* s) { + if (s->is_host) { #if CFG_TUH_ENABLED return usbh_edpt_release(s->daddr, s->ep_addr); #endif - }else - { + } else { #if CFG_TUD_ENABLED return usbd_edpt_release(s->rhport, s->ep_addr); #endif } - return false; } //--------------------------------------------------------------------+ // Stream Write //--------------------------------------------------------------------+ - -bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes) -{ +bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes) { // ZLP condition: no pending data, last transferred bytes is multiple of packet size - TU_VERIFY( !tu_fifo_count(&s->ff) && last_xferred_bytes && (0 == (last_xferred_bytes & (s->ep_packetsize-1))) ); - - TU_VERIFY( stream_claim(s) ); - TU_ASSERT( stream_xfer(s, 0) ); - + TU_VERIFY(!tu_fifo_count(&s->ff) && last_xferred_bytes && (0 == (last_xferred_bytes & (s->ep_packetsize - 1)))); + TU_VERIFY(stream_claim(s)); + TU_ASSERT(stream_xfer(s, 0)); return true; } -uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) -{ +uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) { // skip if no data - TU_VERIFY( tu_fifo_count(&s->ff), 0 ); + TU_VERIFY(tu_fifo_count(&s->ff), 0); // Claim the endpoint - TU_VERIFY( stream_claim(s), 0 ); + TU_VERIFY(stream_claim(s), 0); // Pull data from FIFO -> EP buf uint16_t const count = tu_fifo_read_n(&s->ff, s->ep_buf, s->ep_bufsize); - if ( count ) - { - TU_ASSERT( stream_xfer(s, count), 0 ); + if (count) { + TU_ASSERT(stream_xfer(s, count), 0); return count; - }else - { + } else { // Release endpoint since we don't make any transfer // Note: data is dropped if terminal is not connected stream_release(s); @@ -352,16 +313,13 @@ uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) } } -uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize) -{ +uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const* buffer, uint32_t bufsize) { TU_VERIFY(bufsize); // TODO support ZLP - uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); // flush if fifo has more than packet size or // in rare case: fifo depth is configured too small (which never reach packet size) - if ( (tu_fifo_count(&s->ff) >= s->ep_packetsize) || (tu_fifo_depth(&s->ff) < s->ep_packetsize) ) - { + if ((tu_fifo_count(&s->ff) >= s->ep_packetsize) || (tu_fifo_depth(&s->ff) < s->ep_packetsize)) { tu_edpt_stream_write_xfer(s); } @@ -371,9 +329,7 @@ uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const *buffer, uint32_t //--------------------------------------------------------------------+ // Stream Read //--------------------------------------------------------------------+ - -uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) -{ +uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) { uint16_t available = tu_fifo_remaining(&s->ff); // Prepare for incoming data but only allow what we can store in the ring buffer. @@ -388,25 +344,21 @@ uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) // get available again since fifo can be changed before endpoint is claimed available = tu_fifo_remaining(&s->ff); - if ( available >= s->ep_packetsize ) - { + if (available >= s->ep_packetsize) { // multiple of packet size limit by ep bufsize - uint16_t count = (uint16_t) (available & ~(s->ep_packetsize -1)); + uint16_t count = (uint16_t) (available & ~(s->ep_packetsize - 1)); count = tu_min16(count, s->ep_bufsize); - TU_ASSERT( stream_xfer(s, count), 0 ); - + TU_ASSERT(stream_xfer(s, count), 0); return count; - }else - { + } else { // Release endpoint since we don't make any transfer stream_release(s); return 0; } } -uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize) -{ +uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize) { uint32_t num_read = tu_fifo_read_n(&s->ff, buffer, (uint16_t) bufsize); tu_edpt_stream_read_xfer(s); return num_read; @@ -419,39 +371,36 @@ uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize #if CFG_TUSB_DEBUG #include -#if CFG_TUSB_DEBUG >= 2 - -char const* const tu_str_speed[] = { "Full", "Low", "High" }; -char const* const tu_str_std_request[] = -{ - "Get Status" , - "Clear Feature" , - "Reserved" , - "Set Feature" , - "Reserved" , - "Set Address" , - "Get Descriptor" , - "Set Descriptor" , - "Get Configuration" , - "Set Configuration" , - "Get Interface" , - "Set Interface" , - "Synch Frame" +#if CFG_TUSB_DEBUG >= CFG_TUH_LOG_LEVEL || CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL +char const* const tu_str_speed[] = {"Full", "Low", "High"}; +char const* const tu_str_std_request[] = { + "Get Status", + "Clear Feature", + "Reserved", + "Set Feature", + "Reserved", + "Set Address", + "Get Descriptor", + "Set Descriptor", + "Get Configuration", + "Set Configuration", + "Get Interface", + "Set Interface", + "Synch Frame" }; +char const* const tu_str_xfer_result[] = { + "OK", "FAILED", "STALLED", "TIMEOUT" +}; #endif -static void dump_str_line(uint8_t const* buf, uint16_t count) -{ +static void dump_str_line(uint8_t const* buf, uint16_t count) { tu_printf(" |"); - // each line is 16 bytes - for(uint16_t i=0; i= 900 && CFG_TUSB_MCU < 1000) // check if Espressif MCU // Dialog #define OPT_MCU_DA1469X 1000 ///< Dialog Semiconductor DA1469x @@ -119,7 +132,9 @@ // NXP Kinetis #define OPT_MCU_KINETIS_KL 1200 ///< NXP KL series -#define OPT_MCU_KINETIS_K32 1201 ///< NXP K32 series +#define OPT_MCU_KINETIS_K32L 1201 ///< NXP K32L series +#define OPT_MCU_KINETIS_K32 1201 ///< Alias to K32L +#define OPT_MCU_KINETIS_K 1202 ///< NXP K series #define OPT_MCU_MKL25ZXX 1200 ///< Alias to KL (obsolete) #define OPT_MCU_K32L2BXX 1201 ///< Alias to K32 (obsolete) @@ -133,7 +148,6 @@ #define OPT_MCU_RX72N 1402 ///< Renesas RX72N #define OPT_MCU_RAXXX 1403 ///< Renesas RAxxx families - // Mind Motion #define OPT_MCU_MM32F327X 1500 ///< Mind Motion MM32F327 @@ -165,11 +179,17 @@ // WCH #define OPT_MCU_CH32V307 2200 ///< WCH CH32V307 +#define OPT_MCU_CH32F20X 2210 ///< WCH CH32F20x + -// Helper to check if configured MCU is one of listed +// NXP LPC MCX +#define OPT_MCU_MCXN9 2300 ///< NXP MCX N9 Series +#define OPT_MCU_MCXA15 2301 ///< NXP MCX A15 Series + +// Check if configured MCU is one of listed // Apply _TU_CHECK_MCU with || as separator to list of input -#define _TU_CHECK_MCU(_m) (CFG_TUSB_MCU == _m) -#define TU_CHECK_MCU(...) (TU_ARGS_APPLY(_TU_CHECK_MCU, ||, __VA_ARGS__)) +#define _TU_CHECK_MCU(_m) (CFG_TUSB_MCU == _m) +#define TU_CHECK_MCU(...) (TU_ARGS_APPLY(_TU_CHECK_MCU, ||, __VA_ARGS__)) //--------------------------------------------------------------------+ // Supported OS @@ -274,7 +294,7 @@ // In case TUP_MCU_STRICT_ALIGN = 1 and TUP_ARCH_STRICT_ALIGN =0, we will not reply on compiler // to generate unaligned access code. // LPC_IP3511 Highspeed cannot access unaligned memory on USB_RAM -#if TUD_OPT_HIGH_SPEED && (CFG_TUSB_MCU == OPT_MCU_LPC54XXX || CFG_TUSB_MCU == OPT_MCU_LPC55XX) +#if TUD_OPT_HIGH_SPEED && TU_CHECK_MCU(OPT_MCU_LPC54XXX, OPT_MCU_LPC55XX) #define TUP_MCU_STRICT_ALIGN 1 #else #define TUP_MCU_STRICT_ALIGN 0 @@ -290,15 +310,24 @@ #define CFG_TUSB_DEBUG 0 #endif -// TODO MEM_SECTION can be different for host and device controller -// should use CFG_TUD_MEM_SECTION, CFG_TUH_MEM_SECTION +// Level where CFG_TUSB_DEBUG must be at least for USBH is logged +#ifndef CFG_TUH_LOG_LEVEL + #define CFG_TUH_LOG_LEVEL 2 +#endif + +// Level where CFG_TUSB_DEBUG must be at least for USBD is logged +#ifndef CFG_TUD_LOG_LEVEL + #define CFG_TUD_LOG_LEVEL 2 +#endif + +// Memory section for placing buffer used for usb transferring. If MEM_SECTION is different for +// host and device use: CFG_TUD_MEM_SECTION, CFG_TUH_MEM_SECTION instead #ifndef CFG_TUSB_MEM_SECTION #define CFG_TUSB_MEM_SECTION #endif -// alignment requirement of buffer used for endpoint transferring -// TODO MEM_ALIGN can be different for host and device controller -// should use CFG_TUD_MEM_ALIGN, CFG_TUH_MEM_ALIGN +// Alignment requirement of buffer used for usb transferring. if MEM_ALIGN is different for +// host and device controller use: CFG_TUD_MEM_ALIGN, CFG_TUH_MEM_ALIGN instead #ifndef CFG_TUSB_MEM_ALIGN #define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4) #endif @@ -316,24 +345,14 @@ // Device Options (Default) //-------------------------------------------------------------------- -// Attribute to place data in accessible RAM for device controller -// default to CFG_TUSB_MEM_SECTION for backward-compatible +// Attribute to place data in accessible RAM for device controller (default: CFG_TUSB_MEM_SECTION) #ifndef CFG_TUD_MEM_SECTION - #ifdef CFG_TUSB_MEM_SECTION - #define CFG_TUD_MEM_SECTION CFG_TUSB_MEM_SECTION - #else - #define CFG_TUD_MEM_SECTION - #endif + #define CFG_TUD_MEM_SECTION CFG_TUSB_MEM_SECTION #endif -// Attribute to align memory for device controller -// default to CFG_TUSB_MEM_ALIGN for backward-compatible +// Attribute to align memory for device controller (default: CFG_TUSB_MEM_ALIGN) #ifndef CFG_TUD_MEM_ALIGN - #ifdef CFG_TUSB_MEM_ALIGN - #define CFG_TUD_MEM_ALIGN CFG_TUSB_MEM_ALIGN - #else - #define CFG_TUD_MEM_ALIGN TU_ATTR_ALIGNED(4) - #endif + #define CFG_TUD_MEM_ALIGN CFG_TUSB_MEM_ALIGN #endif #ifndef CFG_TUD_ENDPOINT0_SIZE @@ -344,6 +363,15 @@ #define CFG_TUD_INTERFACE_MAX 16 #endif +//------------- Device Class Driver -------------// +#ifndef CFG_TUD_BTH + #define CFG_TUD_BTH 0 +#endif + +#if CFG_TUD_BTH && !defined(CFG_TUD_BTH_ISO_ALT_COUNT) +#error CFG_TUD_BTH_ISO_ALT_COUNT must be defined to tell Bluetooth driver the number of ISO endpoints to use +#endif + #ifndef CFG_TUD_CDC #define CFG_TUD_CDC 0 #endif @@ -384,10 +412,6 @@ #define CFG_TUD_DFU 0 #endif -#ifndef CFG_TUD_BTH - #define CFG_TUD_BTH 0 -#endif - #ifndef CFG_TUD_ECM_RNDIS #ifdef CFG_TUD_NET #warning "CFG_TUD_NET is renamed to CFG_TUD_ECM_RNDIS" @@ -414,29 +438,24 @@ #endif #endif // CFG_TUH_ENABLED -// Attribute to place data in accessible RAM for host controller -// default to CFG_TUSB_MEM_SECTION for backward-compatible +// Attribute to place data in accessible RAM for host controller (default: CFG_TUSB_MEM_SECTION) #ifndef CFG_TUH_MEM_SECTION - #ifdef CFG_TUSB_MEM_SECTION - #define CFG_TUH_MEM_SECTION CFG_TUSB_MEM_SECTION - #else - #define CFG_TUH_MEM_SECTION - #endif + #define CFG_TUH_MEM_SECTION CFG_TUSB_MEM_SECTION #endif // Attribute to align memory for host controller #ifndef CFG_TUH_MEM_ALIGN - #define CFG_TUH_MEM_ALIGN TU_ATTR_ALIGNED(4) + #define CFG_TUH_MEM_ALIGN CFG_TUSB_MEM_ALIGN #endif //------------- CLASS -------------// #ifndef CFG_TUH_HUB -#define CFG_TUH_HUB 0 + #define CFG_TUH_HUB 0 #endif #ifndef CFG_TUH_CDC -#define CFG_TUH_CDC 0 + #define CFG_TUH_CDC 0 #endif #ifndef CFG_TUH_CDC_FTDI @@ -444,40 +463,85 @@ #define CFG_TUH_CDC_FTDI 0 #endif +#ifndef CFG_TUH_CDC_FTDI_VID_PID_LIST + // List of product IDs that can use the FTDI CDC driver. 0x0403 is FTDI's VID + #define CFG_TUH_CDC_FTDI_VID_PID_LIST \ + {0x0403, 0x6001}, {0x0403, 0x6006}, {0x0403, 0x6010}, {0x0403, 0x6011}, \ + {0x0403, 0x6014}, {0x0403, 0x6015}, {0x0403, 0x8372}, {0x0403, 0xFBFA}, \ + {0x0403, 0xCD18} +#endif + #ifndef CFG_TUH_CDC_CP210X // CP210X is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CP210X 0 #endif +#ifndef CFG_TUH_CDC_CP210X_VID_PID_LIST + // List of product IDs that can use the CP210X CDC driver. 0x10C4 is Silicon Labs' VID + #define CFG_TUH_CDC_CP210X_VID_PID_LIST \ + {0x10C4, 0xEA60}, {0x10C4, 0xEA70} +#endif + +#ifndef CFG_TUH_CDC_CH34X + // CH34X is not part of CDC class, only to re-use CDC driver API + #define CFG_TUH_CDC_CH34X 0 +#endif + +#ifndef CFG_TUH_CDC_CH34X_VID_PID_LIST + // List of product IDs that can use the CH34X CDC driver + #define CFG_TUH_CDC_CH34X_VID_PID_LIST \ + { 0x1a86, 0x5523 }, /* ch341 chip */ \ + { 0x1a86, 0x7522 }, /* ch340k chip */ \ + { 0x1a86, 0x7523 }, /* ch340 chip */ \ + { 0x1a86, 0xe523 }, /* ch330 chip */ \ + { 0x4348, 0x5523 }, /* ch340 custom chip */ \ + { 0x2184, 0x0057 }, /* overtaken from Linux Kernel driver /drivers/usb/serial/ch341.c */ \ + { 0x9986, 0x7523 } /* overtaken from Linux Kernel driver /drivers/usb/serial/ch341.c */ +#endif + #ifndef CFG_TUH_HID -#define CFG_TUH_HID 0 + #define CFG_TUH_HID 0 #endif #ifndef CFG_TUH_MIDI -#define CFG_TUH_MIDI 0 + #define CFG_TUH_MIDI 0 #endif #ifndef CFG_TUH_MSC -#define CFG_TUH_MSC 0 + #define CFG_TUH_MSC 0 #endif #ifndef CFG_TUH_VENDOR -#define CFG_TUH_VENDOR 0 + #define CFG_TUH_VENDOR 0 #endif #ifndef CFG_TUH_API_EDPT_XFER -#define CFG_TUH_API_EDPT_XFER 0 + #define CFG_TUH_API_EDPT_XFER 0 #endif // Enable PIO-USB software host controller #ifndef CFG_TUH_RPI_PIO_USB -#define CFG_TUH_RPI_PIO_USB 0 + #define CFG_TUH_RPI_PIO_USB 0 #endif #ifndef CFG_TUD_RPI_PIO_USB -#define CFG_TUD_RPI_PIO_USB 0 + #define CFG_TUD_RPI_PIO_USB 0 #endif +// MAX3421 Host controller option +#ifndef CFG_TUH_MAX3421 + #define CFG_TUH_MAX3421 0 +#endif + +//--------------------------------------------------------------------+ +// TypeC Options (Default) +//--------------------------------------------------------------------+ + +#ifndef CFG_TUC_ENABLED +#define CFG_TUC_ENABLED 0 + +#define tuc_int_handler(_p) +#endif //------------------------------------------------------------------ // Configuration Validation diff --git a/test-devices/loopback-stm32/.vscode/settings.json b/test-devices/loopback-stm32/.vscode/settings.json index 1a7c2ee4..11ada5d0 100644 --- a/test-devices/loopback-stm32/.vscode/settings.json +++ b/test-devices/loopback-stm32/.vscode/settings.json @@ -6,6 +6,7 @@ "stm32f7xx.h": "c", "stm32f4xx.h": "c", "stm32f401xc.h": "c", - "stm32f401xe.h": "c" + "stm32f401xe.h": "c", + "tusb_option.h": "c" } } \ No newline at end of file diff --git a/test-devices/loopback-stm32/bin/blackpill-f401cc.bin b/test-devices/loopback-stm32/bin/blackpill-f401cc.bin index bb69371130a8eaff19825d80f75fc1862463a151..58d4a27d5cabbd94a28622f092484ed2c0b403e2 100755 GIT binary patch delta 6311 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 delta 6201 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 bhtxg%%-Ocos$?iZ;^6*7@KT454DG)GeQ|~7 diff --git a/test-devices/loopback-stm32/bin/bluepill-f103c8.bin b/test-devices/loopback-stm32/bin/bluepill-f103c8.bin index d123d88a09985ef705bdcf3c51198d425e555f53..cec3c4df7542f623da8a524ec7499af6351494cd 100755 GIT binary patch delta 6872 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 delta 7370 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 KzzTl~lz#v##)&il diff --git a/test-devices/loopback-stm32/bin/disco_f723ie.bin b/test-devices/loopback-stm32/bin/disco_f723ie.bin index da78a59215b2719629163d8dc30577c6166a02eb..499eee8fba952664802ca42754f2e9a5fa6ba980 100755 GIT binary patch delta 6199 zcma(#3v^Rew&&cN&rLrxZK|Y6Ta#Xdwy_XeKb5F0NqhTAwfvrz&uB_VNp+mbh(0bp zoutK2i!xR&GuC#PLFzaNw9wYhSf#YkH;nih6QEc?2N*sV$#Z#21G)4=-acvdIdA#a zdRgmapX{^G-uvv|*(V>ZYWm4G3QGc}jPRXCInoj)k@V!4rvxE|>FK$MK?s>rr-w&) zp4vb$Io%YUODpv`h^}kIalLB~adtxeLN?~<^ZP*)hB*dP=K>N?J{N9WPY*Lgh zL1Y(_KKwx2N9f5urYFW}bR&!AD~)r5NmFK+v|y*jTd0^bi%T!b--RwP8ZzL>bs*a3LvWOzqVBB4KkRt~V0Sk4zo+zxETA zUlsnyl;Br|ZD+7jIPSFk>0TJVeRk%k%joMu znYsQfXPPSuPMsqJVp6=F#Z2IojI79#{v|eHsdFOTneJivwDQ!VefHraHN4U?6zD9T z9WZl?IJ_B24HLMfq4#EIsykW2iZnmkPw(x!B)x`h*rbnj z?^?g`GBRh#IxWs46fB=w^moye&z%t=vcN1mU^Kwk3`6<`o!Jer5k`IwVwDx~9P5gN zUydj^ZRZX?60Q=2*ev{v&=;F_*Taz{C)>HB!ORVGMZ)*q$l~%jEIH)!BA%NNa5uPn zY3UZ4vV0ZLl%mX&{v8d3u2@Kn%fY-*5SKPnxexUdnVud67tdi1n{I~id6=x>G~xBQ zn{bivr??mKUxl3byYUWTO?)G+5k}%?;)evyj2=88^v^hpUlHC)FyiOC`w|3=8}_OwD-U`dtvmz=!J0@204VnY2>w?dN{zx z-hKkU>PP*0SoHM7aZ2uHj)ByBd6ISKa+w@9_g(T7>Ptuk!OmtLU_W7)^R?_qe?ZCQ z@{#O}Kw1S+I2F{qZ_<<&3I94`aHhHpV0A-jB)n_f;MBX&teKUkWtR^Qs#y>{CNu2K zGMb?sPRGsn-b1w#_7>v8JSMnDgV(be7mDJ&Z&26C5$jc5`r2aZ)h(0he#BL zY8E}61n@HrV!k^uIc3h*k%bOk$;EM$O<~aupT0y(^n$GU8xZG2W&{6=QA8O8TBm!c zz?tq&?#*+Xz;0Qb71WR1P;&%>P0b}}-lKv1sD+Ec!j3a}P6K~jT`*+e?UI5zEzT>~ z@x$u7hIGKOp4NH35VHZZTz#wH)y?$M{3cmpRkE98rPcfcIrv>7=im?IyxeO5DJP?T zM6>h{=qpJ?#TKW^35gq_6wq_ z{3ws}PIVpiG?>H;u9nY)e9%U|f{-AdBgP^IiW*C}ptGa}#!=?CelvKx?@~S#*s~B1 zgo2p3M|eH?rn|STA5g1@v{41|G03?-w0~Uu+)=?L!#(9fKziEoooA|C;6AXrXSh+i_wMO?}hOApS|8_l=V0vTPuxxLuzHbRV^u+A1f5H}}9by?%VFtT+9^+2T1OPGR2$?9azronB-)?B6qre22t0D$eoP zcB<=~=NwN<5ri!J0xS>YiyRWBSQPKqd`biKxQO0Mtoj#^ao_WZJmVFcHY_bp|NTPmOrsYIxV77^8D^cxQXP0f z#!aes3BS~_!xz``u@+5#E|1w!{?GcSct!Tn0B)(2Q0!*o<}PaUBV(_~3wV3+eJ7I2 zQ_V?kJkDgG>;wKIa@@B09MzJ^(SpB($*kw-R_h6>rQV)%6q(b`Oci>P`jQvENIpSF zh)A}NFo+@7#R({+dwD#cDtfPU(OCTz?fOXOZvyqQ!uK&;O(RF=a}O3dxFuXWRQt~B zHr`R(I{cy-JAz~16C>fr$L66Wn*de+;gJ^+@<0If#SPINjUAD2hFu;7?NYUo@ZIv%=3jNt{2B4NClp-yrocti6$NCd~&Fz~Q+AnB*qqrX85v4h!(*mo|LmFtRX zicEQ}>j%A~g>)Yn{-=}AoBf`M>Bv4Vboe;t94FXJ>K^;MCYjG`Ao$uU%z> zI-%N0@~>zdf?4`pCgtrP>Vm80_C*(`t~}EDkT55o>k!@}B*XzHq#9@E!#fAc(~Pno z-XcGC6ObE)T=C>~IU}C9Re08TC%#MQG#ZofKA-s-T(2SE$zW)tpji^WG-lKP{4gYF zQt$QtKH~1grfcGs>&O}d-6yida=ZI|W@L_p-y4@iXvv_3y8sQw`Dr#JBa@-0!ti`J z4)-x(jh*^x(tkzgoT41L%iKDS9z^WHucZ!VF=H$XvTQJs3E>~Bd zs!(HyPvylF6Zc!08Q5K{9ya|;e<$_Pxra69mseiiOeF;lj>glgAFnA|=|u^7tx$i| zM{X*Y+(`|FqOM?5!r9@P)!1}FY;)%qotEzzFsdGVe4mW8RsBoQpu4Jnb5|>qSk#cx zZ2xq)v8&*Yl?FxdMa6EQa9pPBt6k)6Q31~{qF^a;To1yV_%!FnhSVx0RLE~MM(4rN z7)lvjQ>dbYD&2~@U#~yRr?0h#kOND!3eTO-IWE8Ci0daWPv7EL$CJHiq>5UC+ZLe_ zErm_T%$7SDAvW{6;%cRGUq;-5dt;i~&F6|SBs03y!6hi4= z#*rVZK(_~B2+Pv9318ka3s(r(l$REzJ4-rxgbh_kWJNv;SJpv*o{|b-v1w)&p`h_I z<({5nRZ8yZa`tD&IHN+a$N8Ts7wj58b=8+E*p>cY2(O#c^4ok{tqZUr zw~m!Qq8*Z!Zql4{ZGYnFfIZ~P-CpxZ`4+n(@NikolNplF9`mSh+%z{`7uh10!f{bP zB@IxlMAN=(9B_nuaCDR}%rfWKREA!tVXN8N7S+TtElXynV79t8ldGxKIclm`yKCG4 zUAfM->NdAS^3iQB0x`fyxGeJTA}dwVXl|pQl;W4fjHosT)lEa&p8$_g+iPYCe=yIn ztP>qlA$`u(_5_H}Ypc;Ye+T;N%5_h&lFy-gl&y_6OCbM*aMqmSt-C?gc7V!Hi&M5= zR*BI3e8{)V|Ud55Xh=i|BC^>7dDw-GM4VKAy`plda zqCbC92CqhW;B;rDgcA*VV-+?fJuCH~*@lWiIaPlbcc5#d*Pb}M1ZmCla#yUrxjfMa zW?F5iHq^dO%#=Z9M_>kt5iCp$$Y>?XQJy5QSZXRh01)QOAA4~cyL=kEe9g<)YP$XN z=z&Q5koXQm=M3qG)8OI1Y~Z{`#VLXdX{Qm#1!;AKOq&pUZ{2^m7Q>q>gJYqo#4P#^ zREkM#qW4ODd}GhJbVcYw<4H@P3+avT#gLTfHyLo=phyCAm2k%_vv+?qslq*J+|h=a z+~DX8=m;6V?qBkp@B>v;A8TfmL0=O`1v%P?Kh-ak>4ECTHLhFhdd5dWZC!XgdD+`t z3XrubwGCv=2g_!HKK~GjWy!%%MkM@~eHgyq+lO$X^JC%BTOD5FN7AqNIFO%le zcD-RoSC0D-J2g8++*6ZRombl$jbbtzh8g%*r_J!9Ly+$pcAgMBTNBspT({cbE6ku; zEk%N9w%)tRxnjeLy5q9e=8y&)hX8ihIzokPclBF}w4urnTDrFSxXk1a!b=1}6a6P& zOZrm#(uMGMlsR_CCi%9#pUHDgpUJtVcKJ@zCOJpDNw!*VgilSf$|SPChS068M)2T_ z(prJm3ba-QU~*D`^w1=_E$Jj!-0?$F!9P3M+c~*Lts7eB=G6&9i2Z@Y@3~Nf3o!ZJ zaExW;rwoB$k5H^Toh`A=2hPfDQl2Dmq13eSAV8d#BvR~hQGM07WUe#Oo#ak&t#GXce|>Ze3?CJ3rqRf5 z-)cH($V;`NSyYRq=)vX2XO)8LsR$I|gS!>iat~9iE z>FVBx2g9EOOnG9%_WNbzTWQ!SGuDpplXls3;#L48`9-%@UVal-UW@z+n6Fv^8T;AS ziX=rVwzYPxEmjC=ffR{`T&hDtOjf3Mg-ltUMdk3lOH{UgDI?^N6|qX;m`LP$L$!Oz zgT)(qbdT+4O>iN2uetVoAv3npD<(>3F9-u}>XL1uhcx|)ii+XXKAe3j6h#XkO&v)SI<&zRLg4Vtlw-aH^PMr0=O z*)Gr3s$iC*eWHv$On*%y5_31g4@}T4gxU|3pQvMpFbjKZD|$Zw{R=x$QzBOdMPO(Q z-}%1Cn2(4*aZcriP?(+m2s?36JPyLo6%MQOhg7X=@K-6jp!bOZHoIJnA6AqvX?Us| zZLZ=Bz~r5=U2dal))3A(F5jL{jVWaPWjZ0%Z>fb0(F~3rcBq9medT3(fhrh7Gr~PW ze>OW~-^E;KHI&h5u~K&WU7wEc7qe^Ezp}Y&j&mdYLmtDuTT5TAqg(9$VZJuAlX>$- z_|q}X2-XaWnm28=5WoWpAx2nfaok=m$00+}f@;60XkH{MjEW|P`#YTVI9wkZ>#|Bx z=tuy3*9A;OXe7LE*%$vasBzy7Pj}sIcVW$0_=EQw7|#g@a^}U8hWE7?#B7R1OuKMB W$Cj*2g4Wj#|Iwp3vWVax1oYp%wT_Db delta 6113 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 V78r6;5c`%35-WldAO2)${|jS SW-FIFO -> MCU USB - * - * The most easiest version, available in case the target MCU can handle the software FIFO (SW-FIFO) and if it is implemented in the device driver (if yes then dcd_edpt_xfer_fifo() is available) - * - * 2. Input data -> SW-FIFO -> Linear buffer -> MCU USB - * - * In case the target MCU can not handle a SW-FIFO, a linear buffer is used. This uses the default function dcd_edpt_xfer(). In this case more memory is required. - * - * 3. (Input data 1 | Input data 2 | ... | Input data N) -> (SW-FIFO 1 | SW-FIFO 2 | ... | SW-FIFO N) -> Linear buffer -> MCU USB - * - * This case is used if you have more channels which need to be combined into one stream. Every channel has its own SW-FIFO. All data is encoded into an Linear buffer. - * - * The same holds in the RX case. - * - * */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_AUDIO) - -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "audio_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -// Use ring buffer if it's available, some MCUs need extra RAM requirements -#ifndef TUD_AUDIO_PREFER_RING_BUFFER - #if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT - #define TUD_AUDIO_PREFER_RING_BUFFER 0 - #else - #define TUD_AUDIO_PREFER_RING_BUFFER 1 - #endif -#endif - -// Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer -// is available or driver is would need to be changed dramatically - -// Only STM32 and dcd_transdimension use non-linear buffer for now -// dwc2 except esp32sx (since it may use dcd_esp32sx) -#if (defined(TUP_USBIP_DWC2) && !TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)) || \ - defined(TUP_USBIP_FSDEV) || \ - CFG_TUSB_MCU == OPT_MCU_RX63X || \ - CFG_TUSB_MCU == OPT_MCU_RX65X || \ - CFG_TUSB_MCU == OPT_MCU_RX72N || \ - CFG_TUSB_MCU == OPT_MCU_LPC18XX || \ - CFG_TUSB_MCU == OPT_MCU_LPC43XX || \ - CFG_TUSB_MCU == OPT_MCU_MIMXRT || \ - CFG_TUSB_MCU == OPT_MCU_MSP432E4 - #if TUD_AUDIO_PREFER_RING_BUFFER - #define USE_LINEAR_BUFFER 0 - #else - #define USE_LINEAR_BUFFER 1 - #endif -#else - #define USE_LINEAR_BUFFER 1 -#endif - -// Temporarily put the check here for stm32_fsdev -#ifdef TUP_USBIP_FSDEV - #define USE_ISO_EP_ALLOCATION 1 -#else - #define USE_ISO_EP_ALLOCATION 0 -#endif - -// Declaration of buffers - -// Check for maximum supported numbers -#if CFG_TUD_AUDIO > 3 -#error Maximum number of audio functions restricted to three! -#endif - -// EP IN software buffers and mutexes -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO - #endif - #endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 - - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO - #endif - #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 - - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO - #endif - #endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - -// Linear buffer TX in case: -// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR -// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into -#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) - #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX]; - #endif - - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX]; - #endif - - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX]; - #endif -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) - -// EP OUT software buffers and mutexes -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING - #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO - #endif - #endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 - - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO - #endif - #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 - - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO - #endif - #endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING - -// Linear buffer RX in case: -// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR -// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) - #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX]; - #endif - - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX]; - #endif - - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX]; - #endif -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) - -// Control buffers -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ]; - -#if CFG_TUD_AUDIO > 1 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ]; -#endif - -#if CFG_TUD_AUDIO > 2 -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ]; -#endif - -// Active alternate setting of interfaces -uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT]; - -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 -uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT]; -#endif - -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 -uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; -#endif - -// Software encoding/decoding support FIFOs -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - #if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ]; - tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO - #endif - #endif - - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ]; - tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO - #endif - #endif - - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ]; - tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO - #endif - #endif -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - #if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ]; - tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO - #endif - #endif - - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ]; - tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO - #endif - #endif - - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ]; - tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO - #endif - #endif -#endif - -typedef struct -{ - uint8_t rhport; - uint8_t const * p_desc; // Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function - -#if CFG_TUD_AUDIO_ENABLE_EP_IN - uint8_t ep_in; // TX audio data EP. - uint16_t ep_in_sz; // Current size of TX EP - uint8_t ep_in_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to output terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - uint8_t ep_out; // Incoming (into uC) audio data EP. - uint16_t ep_out_sz; // Current size of RX EP - uint8_t ep_out_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to input terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) - -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - uint8_t ep_fb; // Feedback EP. -#endif - -#endif - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - uint8_t ep_int_ctr; // Audio control interrupt EP. -#endif - - /*------------- From this point, data is not cleared by bus reset -------------*/ - - uint16_t desc_length; // Length of audio function descriptor - - // Buffer for control requests - uint8_t * ctrl_buf; - uint8_t ctrl_buf_sz; - - // Current active alternate settings - uint8_t * alt_setting; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! - - // EP Transfer buffers and FIFOs -#if CFG_TUD_AUDIO_ENABLE_EP_OUT -#if !CFG_TUD_AUDIO_ENABLE_DECODING - tu_fifo_t ep_out_ff; -#endif - -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - struct { - CFG_TUSB_MEM_ALIGN uint32_t value; // Feedback value for asynchronous mode (in 16.16 format). - uint32_t min_value; // min value according to UAC2 FMT-2.0 section 2.3.1.1. - uint32_t max_value; // max value according to UAC2 FMT-2.0 section 2.3.1.1. - - uint8_t frame_shift; // bInterval-1 in unit of frame (FS), micro-frame (HS) - uint8_t compute_method; - - union { - uint8_t power_of_2; // pre-computed power of 2 shift - float float_const; // pre-computed float constant - - struct { - uint32_t sample_freq; - uint32_t mclk_freq; - }fixed; - -#if 0 // implement later - struct { - uint32_t nominal_value; - uint32_t threshold_bytes; - }fifo_count; -#endif - }compute; - - } feedback; -#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - tu_fifo_t ep_in_ff; -#endif - - // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74) -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE]; -#endif - - // Decoding parameters - parameters are set when alternate AS interface is set by host - // Coding is currently only supported for EP. Software coding corresponding to AS interfaces without EPs are not supported currently. -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - audio_format_type_t format_type_rx; - uint8_t n_channels_rx; - -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - audio_data_format_type_I_t format_type_I_rx; - uint8_t n_bytes_per_sampe_rx; - uint8_t n_channels_per_ff_rx; - uint8_t n_ff_used_rx; -#endif -#endif - - // Encoding parameters - parameters are set when alternate AS interface is set by host -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - audio_format_type_t format_type_tx; - uint8_t n_channels_tx; - -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - audio_data_format_type_I_t format_type_I_tx; - uint8_t n_bytes_per_sampe_tx; - uint8_t n_channels_per_ff_tx; - uint8_t n_ff_used_tx; -#endif -#endif - - // Support FIFOs for software encoding and decoding -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - tu_fifo_t * rx_supp_ff; - uint8_t n_rx_supp_ff; - uint16_t rx_supp_ff_sz_max; -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - tu_fifo_t * tx_supp_ff; - uint8_t n_tx_supp_ff; - uint16_t tx_supp_ff_sz_max; -#endif - - // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR the support FIFOs are used -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) - uint8_t * lin_buf_out; -#define USE_LINEAR_BUFFER_RX 1 -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) - uint8_t * lin_buf_in; -#define USE_LINEAR_BUFFER_TX 1 -#endif - -} audiod_function_t; - -#ifndef USE_LINEAR_BUFFER_TX -#define USE_LINEAR_BUFFER_TX 0 -#endif - -#ifndef USE_LINEAR_BUFFER_RX -#define USE_LINEAR_BUFFER_RX 0 -#endif - -#define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ctrl_buf) - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO]; - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT -static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received); -#endif - -#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT -static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN -static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t* audio); -#endif - -#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN -static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio); -#endif - -static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request); -static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request); - -static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int); -static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int); -static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id); -static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id); -static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id); -static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio); - -#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING -static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf); - -static inline uint8_t tu_desc_subtype(void const* desc) -{ - return ((uint8_t const*) desc)[2]; -} -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq); -#endif - -bool tud_audio_n_mounted(uint8_t func_id) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO); - audiod_function_t* audio = &_audiod_fct[func_id]; - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - if (audio->ep_out == 0) return false; -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN - if (audio->ep_in == 0) return false; -#endif - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - if (audio->ep_int_ctr == 0) return false; -#endif - -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - if (audio->ep_fb == 0) return false; -#endif - - return true; -} - -//--------------------------------------------------------------------+ -// READ API -//--------------------------------------------------------------------+ - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING - -uint16_t tud_audio_n_available(uint8_t func_id) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - return tu_fifo_count(&_audiod_fct[func_id].ep_out_ff); -} - -uint16_t tud_audio_n_read(uint8_t func_id, void* buffer, uint16_t bufsize) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - return tu_fifo_read_n(&_audiod_fct[func_id].ep_out_ff, buffer, bufsize); -} - -bool tud_audio_n_clear_ep_out_ff(uint8_t func_id) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - return tu_fifo_clear(&_audiod_fct[func_id].ep_out_ff); -} - -tu_fifo_t* tud_audio_n_get_ep_out_ff(uint8_t func_id) -{ - if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_out_ff; - return NULL; -} - -#endif - -#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT -// Delete all content in the support RX FIFOs -bool tud_audio_n_clear_rx_support_ff(uint8_t func_id, uint8_t ff_idx) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); - return tu_fifo_clear(&_audiod_fct[func_id].rx_supp_ff[ff_idx]); -} - -uint16_t tud_audio_n_available_support_ff(uint8_t func_id, uint8_t ff_idx) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); - return tu_fifo_count(&_audiod_fct[func_id].rx_supp_ff[ff_idx]); -} - -uint16_t tud_audio_n_read_support_ff(uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); - return tu_fifo_read_n(&_audiod_fct[func_id].rx_supp_ff[ff_idx], buffer, bufsize); -} - -tu_fifo_t* tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx) -{ - if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff) return &_audiod_fct[func_id].rx_supp_ff[ff_idx]; - return NULL; -} -#endif - -// This function is called once an audio packet is received by the USB and is responsible for putting data from USB memory into EP_OUT_FIFO (or support FIFOs + decoding of received stream into audio channels). -// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_DECODING = 0. - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - -static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received) -{ - uint8_t idxItf = 0; - uint8_t const *dummy2; - uint8_t idx_audio_fct = 0; - - if (tud_audio_rx_done_pre_read_cb || tud_audio_rx_done_post_read_cb) - { - idx_audio_fct = audiod_get_audio_fct_idx(audio); - TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2)); - } - - // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO (or decoded into support RX software FIFO) - if (tud_audio_rx_done_pre_read_cb) - { - TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); - } - -#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT - - switch (audio->format_type_rx) - { - case AUDIO_FORMAT_TYPE_UNDEFINED: - // INDIVIDUAL DECODING PROCEDURE REQUIRED HERE! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n"); - TU_BREAKPOINT(); - break; - - case AUDIO_FORMAT_TYPE_I: - - switch (audio->format_type_I_rx) - { - case AUDIO_DATA_FORMAT_TYPE_I_PCM: - TU_VERIFY(audiod_decode_type_I_pcm(rhport, audio, n_bytes_received)); - break; - - default: - // DESIRED CFG_TUD_AUDIO_FORMAT_TYPE_I_RX NOT IMPLEMENTED! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_RX encoding not implemented!\r\n"); - TU_BREAKPOINT(); - break; - } - break; - - default: - // Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented!\r\n"); - TU_BREAKPOINT(); - break; - } - - // Prepare for next transmission - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); - -#else - -#if USE_LINEAR_BUFFER_RX - // Data currently is in linear buffer, copy into EP OUT FIFO - TU_VERIFY(tu_fifo_write_n(&audio->ep_out_ff, audio->lin_buf_out, n_bytes_received)); - - // Schedule for next receive - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); -#else - // Data is already placed in EP FIFO, schedule for next receive - TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false); -#endif - -#endif - - // Call a weak callback here - a possibility for user to get informed decoding was completed - if (tud_audio_rx_done_post_read_cb) - { - TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); - } - - return true; -} - -#endif //CFG_TUD_AUDIO_ENABLE_EP_OUT - -// The following functions are used in case CFG_TUD_AUDIO_ENABLE_DECODING != 0 -#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT - -// Decoding according to 2.3.1.5 Audio Streams - -// Helper function -static inline uint8_t * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesToCopy, void * dst, uint8_t * dst_end, uint8_t * src, uint8_t const n_ff_used) -{ - - // This function is an optimized version of - // while((uint8_t *)dst < dst_end) - // { - // memcpy(dst, src, nBytesToCopy); - // dst = (uint8_t *)dst + nBytesToCopy; - // src += nBytesToCopy * n_ff_used; - // } - - // Optimize for fast half word copies - typedef struct{ - uint16_t val; - } __attribute((__packed__)) unaligned_uint16_t; - - // Optimize for fast word copies - typedef struct{ - uint32_t val; - } __attribute((__packed__)) unaligned_uint32_t; - - switch (nBytesToCopy) - { - case 1: - while((uint8_t *)dst < dst_end) - { - *(uint8_t *)dst++ = *src; - src += n_ff_used; - } - break; - - case 2: - while((uint8_t *)dst < dst_end) - { - *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src; - dst += 2; - src += 2 * n_ff_used; - } - break; - - case 3: - while((uint8_t *)dst < dst_end) - { - // memcpy(dst, src, 3); - // dst = (uint8_t *)dst + 3; - // src += 3 * n_ff_used; - - // TODO: Is there a faster way to copy 3 bytes? - *(uint8_t *)dst++ = *src++; - *(uint8_t *)dst++ = *src++; - *(uint8_t *)dst++ = *src++; - - src += 3 * (n_ff_used - 1); - } - break; - - case 4: - while((uint8_t *)dst < dst_end) - { - *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src; - dst += 4; - src += 4 * n_ff_used; - } - break; - } - - return src; -} - -static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received) -{ - (void) rhport; - - // Determine amount of samples - uint8_t const n_ff_used = audio->n_ff_used_rx; - uint16_t const nBytesPerFFToRead = n_bytes_received / n_ff_used; - uint8_t cnt_ff; - - // Decode - uint8_t * src; - uint8_t * dst_end; - - tu_fifo_buffer_info_t info; - - for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) - { - tu_fifo_get_write_info(&audio->rx_supp_ff[cnt_ff], &info); - - if (info.len_lin != 0) - { - info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin); - src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx]; - dst_end = info.ptr_lin + info.len_lin; - src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_lin, dst_end, src, n_ff_used); - - // Handle wrapped part of FIFO - info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap); - if (info.len_wrap != 0) - { - dst_end = info.ptr_wrap + info.len_wrap; - audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_wrap, dst_end, src, n_ff_used); - } - tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], info.len_lin + info.len_wrap); - } - } - - // Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it - // TU_VERIFY(cnt != n_bytes); - - return true; -} -#endif //CFG_TUD_AUDIO_ENABLE_DECODING - -//--------------------------------------------------------------------+ -// WRITE API -//--------------------------------------------------------------------+ - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - -/** - * \brief Write data to EP in buffer - * - * Write data to buffer. If it is full, new data can be inserted once a transmit was scheduled. See audiod_tx_done_cb(). - * If TX FIFOs are used, this function is not available in order to not let the user mess up the encoding process. - * - * \param[in] func_id: Index of audio function interface - * \param[in] data: Pointer to data array to be copied from - * \param[in] len: # of array elements to copy - * \return Number of bytes actually written - */ -uint16_t tud_audio_n_write(uint8_t func_id, const void * data, uint16_t len) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - return tu_fifo_write_n(&_audiod_fct[func_id].ep_in_ff, data, len); -} - -bool tud_audio_n_clear_ep_in_ff(uint8_t func_id) // Delete all content in the EP IN FIFO -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - return tu_fifo_clear(&_audiod_fct[func_id].ep_in_ff); -} - -tu_fifo_t* tud_audio_n_get_ep_in_ff(uint8_t func_id) -{ - if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_in_ff; - return NULL; -} - -#endif - -#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN - -uint16_t tud_audio_n_flush_tx_support_ff(uint8_t func_id) // Force all content in the support TX FIFOs to be written into linear buffer and schedule a transmit -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - audiod_function_t* audio = &_audiod_fct[func_id]; - - uint16_t n_bytes_copied = tu_fifo_count(&audio->tx_supp_ff[0]); - - TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio)); - - n_bytes_copied -= tu_fifo_count(&audio->tx_supp_ff[0]); - n_bytes_copied = n_bytes_copied*audio->tx_supp_ff[0].item_size; - - return n_bytes_copied; -} - -bool tud_audio_n_clear_tx_support_ff(uint8_t func_id, uint8_t ff_idx) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff); - return tu_fifo_clear(&_audiod_fct[func_id].tx_supp_ff[ff_idx]); -} - -uint16_t tud_audio_n_write_support_ff(uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff); - return tu_fifo_write_n(&_audiod_fct[func_id].tx_supp_ff[ff_idx], data, len); -} - -tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx) -{ - if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff) return &_audiod_fct[func_id].tx_supp_ff[ff_idx]; - return NULL; -} - -#endif - - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - -// If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_ctr_done_cb() is called in inform user -uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint16_t len) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - - // We write directly into the EP's buffer - abort if previous transfer not complete - TU_VERIFY(!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr)); - - TU_VERIFY(tu_memcpy_s(_audiod_fct[func_id].ep_int_ctr_buf, CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE, buffer, len)==0); - - // Schedule transmit - TU_VERIFY(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr, _audiod_fct[func_id].ep_int_ctr_buf, len)); - - return true; -} - -#endif - - -// This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission. -// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_ENCODING = 0 and use tud_audio_n_write. - -// n_bytes_copied - Informs caller how many bytes were loaded. In case n_bytes_copied = 0, a ZLP is scheduled to inform host no data is available for current frame. -#if CFG_TUD_AUDIO_ENABLE_EP_IN -static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio) -{ - uint8_t idxItf; - uint8_t const *dummy2; - - uint8_t idx_audio_fct = audiod_get_audio_fct_idx(audio); - TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, audio, &idxItf, &dummy2)); - - // Only send something if current alternate interface is not 0 as in this case nothing is to be sent due to UAC2 specifications - if (audio->alt_setting[idxItf] == 0) return false; - - // Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer (in case FIFOs are used) or - // if no FIFOs are used the user may use this call back to load its data into the EP IN buffer by use of tud_audio_n_write_ep_in_buffer(). - if (tud_audio_tx_done_pre_load_cb) TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); - - // Send everything in ISO EP FIFO - uint16_t n_bytes_tx; - - // If support FIFOs are used, encode and schedule transmit -#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN - switch (audio->format_type_tx) - { - case AUDIO_FORMAT_TYPE_UNDEFINED: - // INDIVIDUAL ENCODING PROCEDURE REQUIRED HERE! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n"); - TU_BREAKPOINT(); - n_bytes_tx = 0; - break; - - case AUDIO_FORMAT_TYPE_I: - - switch (audio->format_type_I_tx) - { - case AUDIO_DATA_FORMAT_TYPE_I_PCM: - - n_bytes_tx = audiod_encode_type_I_pcm(rhport, audio); - break; - - default: - // YOUR ENCODING IS REQUIRED HERE! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_TX encoding not implemented!\r\n"); - TU_BREAKPOINT(); - n_bytes_tx = 0; - break; - } - break; - - default: - // Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!\r\n"); - TU_BREAKPOINT(); - n_bytes_tx = 0; - break; - } - - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx)); - -#else - // No support FIFOs, if no linear buffer required schedule transmit, else put data into linear buffer and schedule - - n_bytes_tx = tu_min16(tu_fifo_count(&audio->ep_in_ff), audio->ep_in_sz); // Limit up to max packet size, more can not be done for ISO - -#if USE_LINEAR_BUFFER_TX - tu_fifo_read_n(&audio->ep_in_ff, audio->lin_buf_in, n_bytes_tx); - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx)); -#else - // Send everything in ISO EP FIFO - TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx)); -#endif - -#endif - - // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame - if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); - - return true; -} - -#endif //CFG_TUD_AUDIO_ENABLE_EP_IN - -#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN -// Take samples from the support buffer and encode them into the IN EP software FIFO -// Returns number of bytes written into linear buffer - -/* 2.3.1.7.1 PCM Format -The PCM (Pulse Coded Modulation) format is the most commonly used audio format to represent audio -data streams. The audio data is not compressed and uses a signed two’s-complement fixed point format. It -is left-justified (the sign bit is the Msb) and data is padded with trailing zeros to fill the remaining unused -bits of the subslot. The binary point is located to the right of the sign bit so that all values lie within the -range [-1, +1) - */ - -/* - * This function encodes channels saved within the support FIFOs into one stream by interleaving the PCM samples - * in the support FIFOs according to 2.3.1.5 Audio Streams. It does not control justification (left or right) and - * does not change the number of bytes per sample. - * */ - -// Helper function -static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, uint8_t * src, uint8_t * src_end, uint8_t * dst, uint8_t const n_ff_used) -{ - // Optimize for fast half word copies - typedef struct{ - uint16_t val; - } __attribute((__packed__)) unaligned_uint16_t; - - // Optimize for fast word copies - typedef struct{ - uint32_t val; - } __attribute((__packed__)) unaligned_uint32_t; - - switch (nBytesToCopy) - { - case 1: - while(src < src_end) - { - *dst = *src++; - dst += n_ff_used; - } - break; - - case 2: - while(src < src_end) - { - *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src; - src += 2; - dst += 2 * n_ff_used; - } - break; - - case 3: - while(src < src_end) - { - // memcpy(dst, src, 3); - // src = (uint8_t *)src + 3; - // dst += 3 * n_ff_used; - - // TODO: Is there a faster way to copy 3 bytes? - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - - dst += 3 * (n_ff_used - 1); - } - break; - - case 4: - while(src < src_end) - { - *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src; - src += 4; - dst += 4 * n_ff_used; - } - break; - } - - return dst; -} - -static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio) -{ - // This function relies on the fact that the length of the support FIFOs was configured to be a multiple of the active sample size in bytes s.t. no sample is split within a wrap - // This is ensured within set_interface, where the FIFOs are reconfigured according to this size - - // We encode directly into IN EP's linear buffer - abort if previous transfer not complete - TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); - - // Determine amount of samples - uint8_t const n_ff_used = audio->n_ff_used_tx; - uint16_t const nBytesToCopy = audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx; - uint16_t const capPerFF = audio->ep_in_sz / n_ff_used; // Sample capacity per FIFO in bytes - uint16_t nBytesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]); - uint8_t cnt_ff; - - for (cnt_ff = 1; cnt_ff < n_ff_used; cnt_ff++) - { - uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cnt_ff]); - if (count < nBytesPerFFToSend) - { - nBytesPerFFToSend = count; - } - } - - // Check if there is enough - if (nBytesPerFFToSend == 0) return 0; - - // Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT! - nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, capPerFF); - - // Round to full number of samples (flooring) - nBytesPerFFToSend = (nBytesPerFFToSend / nBytesToCopy) * nBytesToCopy; - - // Encode - uint8_t * dst; - uint8_t * src_end; - - tu_fifo_buffer_info_t info; - - for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) - { - dst = &audio->lin_buf_in[cnt_ff*audio->n_channels_per_ff_tx*audio->n_bytes_per_sampe_tx]; - - tu_fifo_get_read_info(&audio->tx_supp_ff[cnt_ff], &info); - - if (info.len_lin != 0) - { - info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin); // Limit up to desired length - src_end = (uint8_t *)info.ptr_lin + info.len_lin; - dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_lin, src_end, dst, n_ff_used); - - // Limit up to desired length - info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap); - - // Handle wrapped part of FIFO - if (info.len_wrap != 0) - { - src_end = (uint8_t *)info.ptr_wrap + info.len_wrap; - audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_wrap, src_end, dst, n_ff_used); - } - - tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], info.len_lin + info.len_wrap); - } - } - - return nBytesPerFFToSend * n_ff_used; -} -#endif //CFG_TUD_AUDIO_ENABLE_ENCODING - -// This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio) -{ - return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->feedback.value, 4); -} -#endif - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void audiod_init(void) -{ - tu_memclr(_audiod_fct, sizeof(_audiod_fct)); - - for(uint8_t i=0; ictrl_buf = ctrl_buf_1; - audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ; - break; -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ > 0 - case 1: - audio->ctrl_buf = ctrl_buf_2; - audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ; - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ > 0 - case 2: - audio->ctrl_buf = ctrl_buf_3; - audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ; - break; -#endif - } - - // Initialize active alternate interface buffers - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0 - case 0: - audio->alt_setting = alt_setting_1; - break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 - case 1: - audio->alt_setting = alt_setting_2; - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 - case 2: - audio->alt_setting = alt_setting_3; - break; -#endif - } - - // Initialize IN EP FIFO if required -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 - case 0: - tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_1), NULL); -#endif - break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 - case 1: - tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_2), NULL); -#endif - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 - case 2: - tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_3), NULL); -#endif - break; -#endif - } -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - - // Initialize linear buffers -#if USE_LINEAR_BUFFER_TX - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 - case 0: - audio->lin_buf_in = lin_buf_in_1; - break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 - case 1: - audio->lin_buf_in = lin_buf_in_2; - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 - case 2: - audio->lin_buf_in = lin_buf_in_3; - break; -#endif - } -#endif // USE_LINEAR_BUFFER_TX - - // Initialize OUT EP FIFO if required -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING - - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 - case 0: - tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_1)); -#endif - break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 - case 1: - tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_2)); -#endif - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 - case 2: - tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_3)); -#endif - break; -#endif - } -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING - - // Initialize linear buffers -#if USE_LINEAR_BUFFER_RX - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 - case 0: - audio->lin_buf_out = lin_buf_out_1; - break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 - case 1: - audio->lin_buf_out = lin_buf_out_2; - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 - case 2: - audio->lin_buf_out = lin_buf_out_3; - break; -#endif - } -#endif // USE_LINEAR_BUFFER_TX - - // Initialize TX support FIFOs if required -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 - case 0: - audio->tx_supp_ff = tx_supp_ff_1; - audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; - audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++) - { - tu_fifo_config(&tx_supp_ff_1[cnt], tx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&tx_supp_ff_1[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_1[cnt]), NULL); -#endif - } - - break; -#endif // CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 - -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - case 1: - audio->tx_supp_ff = tx_supp_ff_2; - audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; - audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; cnt++) - { - tu_fifo_config(&tx_supp_ff_2[cnt], tx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&tx_supp_ff_2[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_2[cnt]), NULL); -#endif - } - - break; -#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 - case 2: - audio->tx_supp_ff = tx_supp_ff_3; - audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; - audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; cnt++) - { - tu_fifo_config(&tx_supp_ff_3[cnt], tx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&tx_supp_ff_3[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_3[cnt]), NULL); -#endif - } - - break; -#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - } -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - - // Set encoding parameters for Type_I formats -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 - case 0: - audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX; - break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - case 1: - audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX; - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 - case 2: - audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX; - break; -#endif - } -#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - - // Initialize RX support FIFOs if required -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 - case 0: - audio->rx_supp_ff = rx_supp_ff_1; - audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; - audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; cnt++) - { - tu_fifo_config(&rx_supp_ff_1[cnt], rx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&rx_supp_ff_1[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_1[cnt]), NULL); -#endif - } - - break; -#endif // CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 - -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - case 1: - audio->rx_supp_ff = rx_supp_ff_2; - audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; - audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; cnt++) - { - tu_fifo_config(&rx_supp_ff_2[cnt], rx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&rx_supp_ff_2[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_2[cnt]), NULL); -#endif - } - - break; -#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 - case 2: - audio->rx_supp_ff = rx_supp_ff_3; - audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; - audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; cnt++) - { - tu_fifo_config(&rx_supp_ff_3[cnt], rx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&rx_supp_ff_3[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_3[cnt]), NULL); -#endif - } - - break; -#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - } -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - - // Set encoding parameters for Type_I formats -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 - case 0: - audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX; - break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - case 1: - audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX; - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 - case 2: - audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX; - break; -#endif - } -#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - } -} - -void audiod_reset(uint8_t rhport) -{ - (void) rhport; - - for(uint8_t i=0; iep_in_ff); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING - tu_fifo_clear(&audio->ep_out_ff); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) - { - tu_fifo_clear(&audio->tx_supp_ff[cnt]); - } -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) - { - tu_fifo_clear(&audio->rx_supp_ff[cnt]); - } -#endif - } -} - -uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ - (void) max_len; - - TU_VERIFY ( TUSB_CLASS_AUDIO == itf_desc->bInterfaceClass && - AUDIO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass); - - // Verify version is correct - this check can be omitted - TU_VERIFY(itf_desc->bInterfaceProtocol == AUDIO_INT_PROTOCOL_CODE_V2); - - // Verify interrupt control EP is enabled if demanded by descriptor - this should be best some static check however - this check can be omitted - if (itf_desc->bNumEndpoints == 1) // 0 or 1 EPs are allowed - { - TU_VERIFY(CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0); - } - - // Alternate setting MUST be zero - this check can be omitted - TU_VERIFY(itf_desc->bAlternateSetting == 0); - - // Find available audio driver interface - uint8_t i; - for (i = 0; i < CFG_TUD_AUDIO; i++) - { - if (!_audiod_fct[i].p_desc) - { - _audiod_fct[i].p_desc = (uint8_t const *)itf_desc; // Save pointer to AC descriptor which is by specification always the first one - _audiod_fct[i].rhport = rhport; - - // Setup descriptor lengths - switch (i) - { - case 0: - _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_1_DESC_LEN; - break; -#if CFG_TUD_AUDIO > 1 - case 1: - _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_2_DESC_LEN; - break; -#endif -#if CFG_TUD_AUDIO > 2 - case 2: - _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_3_DESC_LEN; - break; -#endif - } - -#if USE_ISO_EP_ALLOCATION - #if CFG_TUD_AUDIO_ENABLE_EP_IN - uint8_t ep_in = 0; - uint16_t ep_in_size = 0; - #endif - - #if CFG_TUD_AUDIO_ENABLE_EP_OUT - uint8_t ep_out = 0; - uint16_t ep_out_size = 0; - #endif - - #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - uint8_t ep_fb = 0; - #endif - - uint8_t const *p_desc = _audiod_fct[i].p_desc; - uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; - while (p_desc < p_desc_end) - { - if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) - { - tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; - if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) - { - #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // Explicit feedback EP - if (desc_ep->bmAttributes.usage == 1) - { - ep_fb = desc_ep->bEndpointAddress; - } - #endif - // Data EP - if (desc_ep->bmAttributes.usage == 0) - { - if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) - { - #if CFG_TUD_AUDIO_ENABLE_EP_IN - ep_in = desc_ep->bEndpointAddress; - ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size); - #endif - } else - { - #if CFG_TUD_AUDIO_ENABLE_EP_OUT - ep_out = desc_ep->bEndpointAddress; - ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size); - #endif - } - } - - } - } - p_desc = tu_desc_next(p_desc); - } - - #if CFG_TUD_AUDIO_ENABLE_EP_IN - if (ep_in) - { - usbd_edpt_iso_alloc(rhport, ep_in, ep_in_size); - } - #endif - - #if CFG_TUD_AUDIO_ENABLE_EP_OUT - if (ep_out) - { - usbd_edpt_iso_alloc(rhport, ep_out, ep_out_size); - } - #endif - - #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - if (ep_fb) - { - usbd_edpt_iso_alloc(rhport, ep_fb, 4); - } - #endif - -#endif // USE_ISO_EP_ALLOCATION - - break; - } - } - - // Verify we found a free one - TU_ASSERT( i < CFG_TUD_AUDIO ); - - // This is all we need so far - the EPs are setup by a later set_interface request (as per UAC2 specification) - uint16_t drv_len = _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; // - TUD_AUDIO_DESC_IAD_LEN since tinyUSB already handles the IAD descriptor - - return drv_len; -} - -static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request) -{ - uint8_t const itf = tu_u16_low(p_request->wIndex); - - // Find index of audio streaming interface - uint8_t func_id, idxItf; - uint8_t const *dummy; - - TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &dummy)); - TU_VERIFY(tud_control_xfer(rhport, p_request, &_audiod_fct[func_id].alt_setting[idxItf], 1)); - - TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf, _audiod_fct[func_id].alt_setting[idxItf]); - - return true; -} - -static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request) -{ - (void) rhport; - - // Here we need to do the following: - - // 1. Find the audio driver assigned to the given interface to be set - // Since one audio driver interface has to be able to cover an unknown number of interfaces (AC, AS + its alternate settings), the best memory efficient way to solve this is to always search through the descriptors. - // The audio driver is mapped to an audio function by a reference pointer to the corresponding AC interface of this audio function which serves as a starting point for searching - - // 2. Close EPs which are currently open - // To do so it is not necessary to know the current active alternate interface since we already save the current EP addresses - we simply close them - - // 3. Open new EP - - uint8_t const itf = tu_u16_low(p_request->wIndex); - uint8_t const alt = tu_u16_low(p_request->wValue); - - TU_LOG2(" Set itf: %u - alt: %u\r\n", itf, alt); - - // Find index of audio streaming interface and index of interface - uint8_t func_id, idxItf; - uint8_t const *p_desc; - TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &p_desc)); - - audiod_function_t* audio = &_audiod_fct[func_id]; - - // Look if there is an EP to be closed - for this driver, there are only 3 possible EPs which may be closed (only AS related EPs can be closed, AC EP (if present) is always open) -#if CFG_TUD_AUDIO_ENABLE_EP_IN - if (audio->ep_in_as_intf_num == itf) - { - audio->ep_in_as_intf_num = 0; - #if !USE_ISO_EP_ALLOCATION - usbd_edpt_close(rhport, audio->ep_in); - #endif - - // Clear FIFOs, since data is no longer valid - #if !CFG_TUD_AUDIO_ENABLE_ENCODING - tu_fifo_clear(&audio->ep_in_ff); - #else - for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) - { - tu_fifo_clear(&audio->tx_supp_ff[cnt]); - } - #endif - - // Invoke callback - can be used to stop data sampling - if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); - - audio->ep_in = 0; // Necessary? - - } -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - if (audio->ep_out_as_intf_num == itf) - { - audio->ep_out_as_intf_num = 0; - #if !USE_ISO_EP_ALLOCATION - usbd_edpt_close(rhport, audio->ep_out); - #endif - - // Clear FIFOs, since data is no longer valid - #if !CFG_TUD_AUDIO_ENABLE_DECODING - tu_fifo_clear(&audio->ep_out_ff); - #else - for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) - { - tu_fifo_clear(&audio->rx_supp_ff[cnt]); - } - #endif - - // Invoke callback - can be used to stop data sampling - if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); - - audio->ep_out = 0; // Necessary? - - // Close corresponding feedback EP - #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - #if !USE_ISO_EP_ALLOCATION - usbd_edpt_close(rhport, audio->ep_fb); - #endif - audio->ep_fb = 0; - tu_memclr(&audio->feedback, sizeof(audio->feedback)); - #endif - } -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT - - // Save current alternative interface setting - audio->alt_setting[idxItf] = alt; - - // Open new EP if necessary - EPs are only to be closed or opened for AS interfaces - Look for AS interface with correct alternate interface - // Get pointer at end - uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; - - // p_desc starts at required interface with alternate setting zero - while (p_desc < p_desc_end) - { - // Find correct interface - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == alt) - { -#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING - uint8_t const * p_desc_parse_for_params = p_desc; -#endif - // From this point forward follow the EP descriptors associated to the current alternate setting interface - Open EPs if necessary - uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints; - while (foundEPs < nEps && p_desc < p_desc_end) - { - if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) - { - tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc; -#if USE_ISO_EP_ALLOCATION - TU_ASSERT(usbd_edpt_iso_activate(rhport, desc_ep)); -#else - TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); -#endif - uint8_t const ep_addr = desc_ep->bEndpointAddress; - - //TODO: We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND! - usbd_edpt_clear_stall(rhport, ep_addr); - -#if CFG_TUD_AUDIO_ENABLE_EP_IN - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 0x00) // Check if usage is data EP - { - // Save address - audio->ep_in = ep_addr; - audio->ep_in_as_intf_num = itf; - audio->ep_in_sz = tu_edpt_packet_size(desc_ep); - - // If software encoding is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters - #if CFG_TUD_AUDIO_ENABLE_ENCODING - audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf); - - // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap - #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / audio->n_bytes_per_sampe_tx) * audio->n_bytes_per_sampe_tx); - for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) - { - tu_fifo_config(&audio->tx_supp_ff[cnt], audio->tx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); - } - audio->n_ff_used_tx = audio->n_channels_tx / audio->n_channels_per_ff_tx; - TU_ASSERT( audio->n_ff_used_tx <= audio->n_tx_supp_ff ); - #endif - #endif - - // Schedule first transmit if alternate interface is not zero i.e. streaming is disabled - in case no sample data is available a ZLP is loaded - // It is necessary to trigger this here since the refill is done with an RX FIFO empty interrupt which can only trigger if something was in there - TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_fct[func_id])); - } -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - - if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) // Checking usage not necessary - { - // Save address - audio->ep_out = ep_addr; - audio->ep_out_as_intf_num = itf; - audio->ep_out_sz = tu_edpt_packet_size(desc_ep); - - #if CFG_TUD_AUDIO_ENABLE_DECODING - audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf); - - // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap - #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sampe_rx) * audio->n_bytes_per_sampe_rx; - for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) - { - tu_fifo_config(&audio->rx_supp_ff[cnt], audio->rx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); - } - audio->n_ff_used_rx = audio->n_channels_rx / audio->n_channels_per_ff_rx; - TU_ASSERT( audio->n_ff_used_rx <= audio->n_rx_supp_ff ); - #endif - #endif - - // Prepare for incoming data - #if USE_LINEAR_BUFFER_RX - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); - #else - TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false); - #endif - } - - #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 1) // Check if usage is explicit data feedback - { - audio->ep_fb = ep_addr; - audio->feedback.frame_shift = desc_ep->bInterval -1; - - // Enable SOF interrupt if callback is implemented - if (tud_audio_feedback_interval_isr) usbd_sof_enable(rhport, true); - } - #endif -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT - - foundEPs += 1; - } - p_desc = tu_desc_next(p_desc); - } - - TU_VERIFY(foundEPs == nEps); - - // Invoke one callback for a final set interface - if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); - -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // Prepare feedback computation if callback is available - if (tud_audio_feedback_params_cb) - { - audio_feedback_params_t fb_param; - - tud_audio_feedback_params_cb(func_id, alt, &fb_param); - audio->feedback.compute_method = fb_param.method; - - // Minimal/Maximum value in 16.16 format for full speed (1ms per frame) or high speed (125 us per frame) - uint32_t const frame_div = (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000; - audio->feedback.min_value = (fb_param.sample_freq/frame_div - 1) << 16; - audio->feedback.max_value = (fb_param.sample_freq/frame_div + 1) << 16; - - switch(fb_param.method) - { - case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: - case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT: - case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2: - set_fb_params_freq(audio, fb_param.sample_freq, fb_param.frequency.mclk_freq); - break; - - #if 0 // implement later - case AUDIO_FEEDBACK_METHOD_FIFO_COUNT: - { - uint64_t fb64 = ((uint64_t) fb_param.sample_freq) << 16; - audio->feedback.compute.fifo_count.nominal_value = (uint32_t) (fb64 / frame_div); - audio->feedback.compute.fifo_count.threshold_bytes = fb_param.fifo_count.threshold_bytes; - - tud_audio_fb_set(audio->feedback.compute.fifo_count.nominal_value); - } - break; - #endif - - // nothing to do - default: break; - } - } -#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - - // We are done - abort loop - break; - } - - // Moving forward - p_desc = tu_desc_next(p_desc); - } - -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // Disable SOF interrupt if no driver has any enabled feedback EP - bool disable = true; - for(uint8_t i=0; i < CFG_TUD_AUDIO; i++) - { - if (_audiod_fct[i].ep_fb != 0) - { - disable = false; - break; - } - } - if (disable) usbd_sof_enable(rhport, false); -#endif - - tud_control_status(rhport, p_request); - - return true; -} - -// Invoked when class request DATA stage is finished. -// return false to stall control EP (e.g Host send non-sense DATA) -static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const * p_request) -{ - // Handle audio class specific set requests - if(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) - { - uint8_t func_id; - - switch (p_request->bmRequestType_bit.recipient) - { - case TUSB_REQ_RCPT_INTERFACE: - { - uint8_t itf = TU_U16_LOW(p_request->wIndex); - uint8_t entityID = TU_U16_HIGH(p_request->wIndex); - - if (entityID != 0) - { - if (tud_audio_set_req_entity_cb) - { - // Check if entity is present and get corresponding driver index - TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); - - // Invoke callback - return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); - } - else - { - TU_LOG2(" No entity set request callback available!\r\n"); - return false; // In case no callback function is present or request can not be conducted we stall it - } - } - else - { - if (tud_audio_set_req_itf_cb) - { - // Find index of audio driver structure and verify interface really exists - TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); - - // Invoke callback - return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); - } - else - { - TU_LOG2(" No interface set request callback available!\r\n"); - return false; // In case no callback function is present or request can not be conducted we stall it - } - } - } - break; - - case TUSB_REQ_RCPT_ENDPOINT: - { - uint8_t ep = TU_U16_LOW(p_request->wIndex); - - if (tud_audio_set_req_ep_cb) - { - // Check if entity is present and get corresponding driver index - TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); - - // Invoke callback - return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); - } - else - { - TU_LOG2(" No EP set request callback available!\r\n"); - return false; // In case no callback function is present or request can not be conducted we stall it - } - } - break; - // Unknown/Unsupported recipient - default: TU_BREAKPOINT(); return false; - } - } - return true; -} - -// Handle class control request -// return false to stall control endpoint (e.g unsupported request) -static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const * p_request) -{ - (void) rhport; - - // Handle standard requests - standard set requests usually have no data stage so we also handle set requests here - if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) - { - switch (p_request->bRequest) - { - case TUSB_REQ_GET_INTERFACE: - return audiod_get_interface(rhport, p_request); - - case TUSB_REQ_SET_INTERFACE: - return audiod_set_interface(rhport, p_request); - - // Unknown/Unsupported request - default: TU_BREAKPOINT(); return false; - } - } - - // Handle class requests - if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) - { - uint8_t itf = TU_U16_LOW(p_request->wIndex); - uint8_t func_id; - - // Conduct checks which depend on the recipient - switch (p_request->bmRequestType_bit.recipient) - { - case TUSB_REQ_RCPT_INTERFACE: - { - uint8_t entityID = TU_U16_HIGH(p_request->wIndex); - - // Verify if entity is present - if (entityID != 0) - { - // Find index of audio driver structure and verify entity really exists - TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); - - // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests - if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) - { - if (tud_audio_get_req_entity_cb) - { - return tud_audio_get_req_entity_cb(rhport, p_request); - } - else - { - TU_LOG2(" No entity get request callback available!\r\n"); - return false; // Stall - } - } - } - else - { - // Find index of audio driver structure and verify interface really exists - TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); - - // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests - if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) - { - if (tud_audio_get_req_itf_cb) - { - return tud_audio_get_req_itf_cb(rhport, p_request); - } - else - { - TU_LOG2(" No interface get request callback available!\r\n"); - return false; // Stall - } - } - } - } - break; - - case TUSB_REQ_RCPT_ENDPOINT: - { - uint8_t ep = TU_U16_LOW(p_request->wIndex); - - // Find index of audio driver structure and verify EP really exists - TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); - - // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests - if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) - { - if (tud_audio_get_req_ep_cb) - { - return tud_audio_get_req_ep_cb(rhport, p_request); - } - else - { - TU_LOG2(" No EP get request callback available!\r\n"); - return false; // Stall - } - } - } - break; - - // Unknown/Unsupported recipient - default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false; - } - - // If we end here, the received request is a set request - we schedule a receive for the data stage and return true here. We handle the rest later in audiod_control_complete() once the data stage was finished - TU_VERIFY(tud_control_xfer(rhport, p_request, _audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz)); - return true; - } - - // There went something wrong - unsupported control request type - TU_BREAKPOINT(); - return false; -} - -bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - if ( stage == CONTROL_STAGE_SETUP ) - { - return audiod_control_request(rhport, request); - } - else if ( stage == CONTROL_STAGE_DATA ) - { - return audiod_control_complete(rhport, request); - } - - return true; -} - -bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void) result; - (void) xferred_bytes; - - // Search for interface belonging to given end point address and proceed as required - for (uint8_t func_id = 0; func_id < CFG_TUD_AUDIO; func_id++) - { - audiod_function_t* audio = &_audiod_fct[func_id]; - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - - // Data transmission of control interrupt finished - if (audio->ep_int_ctr == ep_addr) - { - // According to USB2 specification, maximum payload of interrupt EP is 8 bytes on low speed, 64 bytes on full speed, and 1024 bytes on high speed (but only if an alternate interface other than 0 is used - see specification p. 49) - // In case there is nothing to send we have to return a NAK - this is taken care of by PHY ??? - // In case of an erroneous transmission a retransmission is conducted - this is taken care of by PHY ??? - - // I assume here, that things above are handled by PHY - // All transmission is done - what remains to do is to inform job was completed - - if (tud_audio_int_ctr_done_cb) TU_VERIFY(tud_audio_int_ctr_done_cb(rhport, (uint16_t) xferred_bytes)); - } - -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN - - // Data transmission of audio packet finished - if (audio->ep_in == ep_addr && audio->alt_setting != 0) - { - // USB 2.0, section 5.6.4, third paragraph, states "An isochronous endpoint must specify its required bus access period. However, an isochronous endpoint must be prepared to handle poll rates faster than the one specified." - // That paragraph goes on to say "An isochronous IN endpoint must return a zero-length packet whenever data is requested at a faster interval than the specified interval and data is not available." - // This can only be solved reliably if we load a ZLP after every IN transmission since we can not say if the host requests samples earlier than we declared! Once all samples are collected we overwrite the loaded ZLP. - - // Check if there is data to load into EPs buffer - if not load it with ZLP - // Be aware - we as a device are not able to know if the host polls for data with a faster rate as we stated this in the descriptors. Therefore we always have to put something into the EPs buffer. However, once we did that, there is no way of aborting this or replacing what we put into the buffer before! - // This is the only place where we can fill something into the EPs buffer! - - // Load new data - TU_VERIFY(audiod_tx_done_cb(rhport, audio)); - - // Transmission of ZLP is done by audiod_tx_done_cb() - return true; - } -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - - // New audio packet received - if (audio->ep_out == ep_addr) - { - TU_VERIFY(audiod_rx_done_cb(rhport, audio, (uint16_t) xferred_bytes)); - return true; - } - - -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // Transmission of feedback EP finished - if (audio->ep_fb == ep_addr) - { - if (tud_audio_fb_done_cb) tud_audio_fb_done_cb(func_id); - - // Schedule a transmit with the new value if EP is not busy - if (!usbd_edpt_busy(rhport, audio->ep_fb)) - { - // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent - return audiod_fb_send(rhport, audio); - } - } -#endif -#endif - } - - return false; -} - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - -static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq) -{ - // Check if frame interval is within sane limits - // The interval value n_frames was taken from the descriptors within audiod_set_interface() - - // n_frames_min is ceil(2^10 * f_s / f_m) for full speed and ceil(2^13 * f_s / f_m) for high speed - // this lower limit ensures the measures feedback value has sufficient precision - uint32_t const k = (TUSB_SPEED_FULL == tud_speed_get()) ? 10 : 13; - uint32_t const n_frame = (1UL << audio->feedback.frame_shift); - - if ( (((1UL << k) * sample_freq / mclk_freq) + 1) > n_frame ) - { - TU_LOG1(" UAC2 feedback interval too small\r\n"); TU_BREAKPOINT(); return false; - } - - // Check if parameters really allow for a power of two division - if ((mclk_freq % sample_freq) == 0 && tu_is_power_of_two(mclk_freq / sample_freq)) - { - audio->feedback.compute_method = AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2; - audio->feedback.compute.power_of_2 = 16 - audio->feedback.frame_shift - tu_log2(mclk_freq / sample_freq); - } - else if ( audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT) - { - audio->feedback.compute.float_const = (float)sample_freq / mclk_freq * (1UL << (16 - audio->feedback.frame_shift)); - } - else - { - audio->feedback.compute.fixed.sample_freq = sample_freq; - audio->feedback.compute.fixed.mclk_freq = mclk_freq; - } - - return true; -} - -uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles) -{ - audiod_function_t* audio = &_audiod_fct[func_id]; - uint32_t feedback; - - switch (audio->feedback.compute_method) - { - case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2: - feedback = (cycles << audio->feedback.compute.power_of_2); - break; - - case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT: - feedback = (uint32_t) ((float) cycles * audio->feedback.compute.float_const); - break; - - case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: - { - uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - audio->feedback.frame_shift); - feedback = (uint32_t) (fb64 / audio->feedback.compute.fixed.mclk_freq); - } - break; - - default: return 0; - } - - // For Windows: https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/usb-2-0-audio-drivers - // The size of isochronous packets created by the device must be within the limits specified in FMT-2.0 section 2.3.1.1. - // This means that the deviation of actual packet size from nominal size must not exceed +/- one audio slot - // (audio slot = channel count samples). - if ( feedback > audio->feedback.max_value ) feedback = audio->feedback.max_value; - if ( feedback < audio->feedback.min_value ) feedback = audio->feedback.min_value; - - tud_audio_n_fb_set(func_id, feedback); - - return feedback; -} -#endif - -TU_ATTR_FAST_FUNC void audiod_sof_isr (uint8_t rhport, uint32_t frame_count) -{ - (void) rhport; - (void) frame_count; - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // Determine feedback value - The feedback method is described in 5.12.4.2 of the USB 2.0 spec - // Boiled down, the feedback value Ff = n_samples / (micro)frame. - // Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s) - // The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where P = min( ceil(log2(f_m / f_s)), K) - // feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames - - // Iterate over audio functions and set feedback value - for(uint8_t i=0; i < CFG_TUD_AUDIO; i++) - { - audiod_function_t* audio = &_audiod_fct[i]; - - if (audio->ep_fb != 0) - { - // HS shift need to be adjusted since SOF event is generated for frame only - uint8_t const hs_adjust = (TUSB_SPEED_HIGH == tud_speed_get()) ? 3 : 0; - uint32_t const interval = 1UL << (audio->feedback.frame_shift - hs_adjust); - if ( 0 == (frame_count & (interval-1)) ) - { - if(tud_audio_feedback_interval_isr) tud_audio_feedback_interval_isr(i, frame_count, audio->feedback.frame_shift); - } - } - } -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -} - -bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len) -{ - // Handles only sending of data not receiving - if (p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) return false; - - // Get corresponding driver index - uint8_t func_id; - uint8_t itf = TU_U16_LOW(p_request->wIndex); - - // Conduct checks which depend on the recipient - switch (p_request->bmRequestType_bit.recipient) - { - case TUSB_REQ_RCPT_INTERFACE: - { - uint8_t entityID = TU_U16_HIGH(p_request->wIndex); - - // Verify if entity is present - if (entityID != 0) - { - // Find index of audio driver structure and verify entity really exists - TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); - } - else - { - // Find index of audio driver structure and verify interface really exists - TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); - } - } - break; - - case TUSB_REQ_RCPT_ENDPOINT: - { - uint8_t ep = TU_U16_LOW(p_request->wIndex); - - // Find index of audio driver structure and verify EP really exists - TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); - } - break; - - // Unknown/Unsupported recipient - default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false; - } - - // Crop length - if (len > _audiod_fct[func_id].ctrl_buf_sz) len = _audiod_fct[func_id].ctrl_buf_sz; - - // Copy into buffer - TU_VERIFY(0 == tu_memcpy_s(_audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz, data, (size_t)len)); - - // Schedule transmit - return tud_control_xfer(rhport, p_request, (void*)_audiod_fct[func_id].ctrl_buf, len); -} - -// This helper function finds for a given audio function and AS interface number the index of the attached driver structure, the index of the interface in the audio function -// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and -// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero. -static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int) -{ - if (audio->p_desc) - { - // Get pointer at end - uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; - - // Advance past AC descriptors - uint8_t const *p_desc = tu_desc_next(audio->p_desc); - p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength; - - uint8_t tmp = 0; - while (p_desc < p_desc_end) - { - // We assume the number of alternate settings is increasing thus we return the index of alternate setting zero! - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0) - { - if (((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf) - { - *idxItf = tmp; - *pp_desc_int = p_desc; - return true; - } - // Increase index, bytes read, and pointer - tmp++; - } - p_desc = tu_desc_next(p_desc); - } - } - return false; -} - -// This helper function finds for a given AS interface number the index of the attached driver structure, the index of the interface in the audio function -// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and -// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero. -static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int) -{ - // Loop over audio driver interfaces - uint8_t i; - for (i = 0; i < CFG_TUD_AUDIO; i++) - { - if (audiod_get_AS_interface_index(itf, &_audiod_fct[i], idxItf, pp_desc_int)) - { - *func_id = i; - return true; - } - } - - return false; -} - -// Verify an entity with the given ID exists and returns also the corresponding driver index -static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id) -{ - uint8_t i; - for (i = 0; i < CFG_TUD_AUDIO; i++) - { - // Look for the correct driver by checking if the unique standard AC interface number fits - if (_audiod_fct[i].p_desc && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf) - { - // Get pointers after class specific AC descriptors and end of AC descriptors - entities are defined in between - uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc); // Points to CS AC descriptor - uint8_t const *p_desc_end = ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength + p_desc; - p_desc = tu_desc_next(p_desc); // Get past CS AC descriptor - - while (p_desc < p_desc_end) - { - if (p_desc[3] == entityID) // Entity IDs are always at offset 3 - { - *func_id = i; - return true; - } - p_desc = tu_desc_next(p_desc); - } - } - } - return false; -} - -static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id) -{ - uint8_t i; - for (i = 0; i < CFG_TUD_AUDIO; i++) - { - if (_audiod_fct[i].p_desc) - { - // Get pointer at beginning and end - uint8_t const *p_desc = _audiod_fct[i].p_desc; - uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; - - while (p_desc < p_desc_end) - { - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf) - { - *func_id = i; - return true; - } - p_desc = tu_desc_next(p_desc); - } - } - } - return false; -} - -static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id) -{ - uint8_t i; - for (i = 0; i < CFG_TUD_AUDIO; i++) - { - if (_audiod_fct[i].p_desc) - { - // Get pointer at end - uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length; - - // Advance past AC descriptors - EP we look for are streaming EPs - uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc); - p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength; - - while (p_desc < p_desc_end) - { - if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT && ((tusb_desc_endpoint_t const * )p_desc)->bEndpointAddress == ep) - { - *func_id = i; - return true; - } - p_desc = tu_desc_next(p_desc); - } - } - } - return false; -} - -#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING -// p_desc points to the AS interface of alternate setting zero -// itf is the interface number of the corresponding interface - we check if the interface belongs to EP in or EP out to see if it is a TX or RX parameter -// Currently, only AS interfaces with an EP (in or out) are supposed to be parsed for! -static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf) -{ -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) return; // Abort, this interface has no EP, this driver does not support this currently -#endif -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_in_as_intf_num) return; -#endif -#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_out_as_intf_num) return; -#endif - - p_desc = tu_desc_next(p_desc); // Exclude standard AS interface descriptor of current alternate interface descriptor - - while (p_desc < p_desc_end) - { - // Abort if follow up descriptor is a new standard interface descriptor - indicates the last AS descriptor was already finished - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) break; - - // Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format type and format and also to get number of physical channels - if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL) - { -#if CFG_TUD_AUDIO_ENABLE_EP_IN - if (as_itf == audio->ep_in_as_intf_num) - { - audio->n_channels_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels; - audio->format_type_tx = (audio_format_type_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType); - -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - audio->format_type_I_tx = (audio_data_format_type_I_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats); -#endif - } -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf == audio->ep_out_as_intf_num) - { - audio->n_channels_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels; - audio->format_type_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType; -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - audio->format_type_I_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats; -#endif - } -#endif - } - - // Look for a Type I Format Type Descriptor(2.3.1.6 - Audio Formats) -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_FORMAT_TYPE && ((audio_desc_type_I_format_t const * )p_desc)->bFormatType == AUDIO_FORMAT_TYPE_I) - { -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) break; // Abort loop, this interface has no EP, this driver does not support this currently -#endif -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_in_as_intf_num) break; -#endif -#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_out_as_intf_num) break; -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN - if (as_itf == audio->ep_in_as_intf_num) - { - audio->n_bytes_per_sampe_tx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; - } -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf == audio->ep_out_as_intf_num) - { - audio->n_bytes_per_sampe_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; - } -#endif - } -#endif - - // Other format types are not supported yet - - p_desc = tu_desc_next(p_desc); - } -} -#endif - -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - -bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - - // Format the feedback value -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION - if ( TUSB_SPEED_FULL == tud_speed_get() ) - { - uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].feedback.value; - - // For FS format is 10.14 - *(fb++) = (feedback >> 2) & 0xFF; - *(fb++) = (feedback >> 10) & 0xFF; - *(fb++) = (feedback >> 18) & 0xFF; - // 4th byte is needed to work correctly with MS Windows - *fb = 0; - }else -#else - { - // Send value as-is, caller will choose the appropriate format - _audiod_fct[func_id].feedback.value = feedback; - } -#endif - - // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value - if (!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb)) - { - return audiod_fb_send(_audiod_fct[func_id].rhport, &_audiod_fct[func_id]); - } - - return true; -} -#endif - -// No security checks here - internal function only which should always succeed -uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio) -{ - for (uint8_t cnt=0; cnt < CFG_TUD_AUDIO; cnt++) - { - if (&_audiod_fct[cnt] == audio) return cnt; - } - return 0; -} - -#endif //CFG_TUD_ENABLED && CFG_TUD_AUDIO diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/audio/audio_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/audio/audio_device.h deleted file mode 100644 index 7c88b99f..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/audio/audio_device.h +++ /dev/null @@ -1,699 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Ha Thach (tinyusb.org) - * Copyright (c) 2020 Reinhard Panhuber - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_AUDIO_DEVICE_H_ -#define _TUSB_AUDIO_DEVICE_H_ - -#include "audio.h" - -//--------------------------------------------------------------------+ -// Class Driver Configuration -//--------------------------------------------------------------------+ - -// All sizes are in bytes! - -#ifndef CFG_TUD_AUDIO_FUNC_1_DESC_LEN -#error You must tell the driver the length of the audio function descriptor including IAD descriptor -#endif -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_DESC_LEN -#error You must tell the driver the length of the audio function descriptor including IAD descriptor -#endif -#endif -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_DESC_LEN -#error You must tell the driver the length of the audio function descriptor including IAD descriptor -#endif -#endif - -// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces -#ifndef CFG_TUD_AUDIO_FUNC_1_N_AS_INT -#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! -#endif -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_N_AS_INT -#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! -#endif -#endif -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_N_AS_INT -#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! -#endif -#endif - -// Size of control buffer used to receive and send control messages via EP0 - has to be big enough to hold your biggest request structure e.g. range requests with multiple intervals defined or cluster descriptors -#ifndef CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ -#error You must define an audio class control request buffer size! -#endif - -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ -#error You must define an audio class control request buffer size! -#endif -#endif - -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ -#error You must define an audio class control request buffer size! -#endif -#endif - -// End point sizes IN BYTES - Limits: Full Speed <= 1023, High Speed <= 1024 -#ifndef CFG_TUD_AUDIO_ENABLE_EP_IN -#define CFG_TUD_AUDIO_ENABLE_EP_IN 0 // TX -#endif - -#ifndef CFG_TUD_AUDIO_ENABLE_EP_OUT -#define CFG_TUD_AUDIO_ENABLE_EP_OUT 0 // RX -#endif - -// Maximum EP sizes for all alternate AS interface settings - used for checks and buffer allocation -#if CFG_TUD_AUDIO_ENABLE_EP_IN -#ifndef CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX -#error You must tell the driver the biggest EP IN size! -#endif -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX -#error You must tell the driver the biggest EP IN size! -#endif -#endif -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX -#error You must tell the driver the biggest EP IN size! -#endif -#endif -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT -#ifndef CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX -#error You must tell the driver the biggest EP OUT size! -#endif -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX -#error You must tell the driver the biggest EP OUT size! -#endif -#endif -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX -#error You must tell the driver the biggest EP OUT size! -#endif -#endif -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT - -// Software EP FIFO buffer sizes - must be >= max EP SIZEs! -#ifndef CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ -#define CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ -#define CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ 0 -#endif - -#ifndef CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ -#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ -#define CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ -#define CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ 0 -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN -#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX -#error EP software buffer size MUST BE at least as big as maximum EP size -#endif - -#if CFG_TUD_AUDIO > 1 -#if CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX -#error EP software buffer size MUST BE at least as big as maximum EP size -#endif -#endif - -#if CFG_TUD_AUDIO > 2 -#if CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX -#error EP software buffer size MUST BE at least as big as maximum EP size -#endif -#endif -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT -#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX -#error EP software buffer size MUST BE at least as big as maximum EP size -#endif - -#if CFG_TUD_AUDIO > 1 -#if CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX -#error EP software buffer size MUST BE at least as big as maximum EP size -#endif -#endif - -#if CFG_TUD_AUDIO > 2 -#if CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX -#error EP software buffer size MUST BE at least as big as maximum EP size -#endif -#endif -#endif - -// Enable/disable feedback EP (required for asynchronous RX applications) -#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // Feedback - 0 or 1 -#endif - -// Enable/disable conversion from 16.16 to 10.14 format on full-speed devices. See tud_audio_n_fb_set(). -#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION -#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 0 // 0 or 1 -#endif - -// Audio interrupt control EP size - disabled if 0 -#ifndef CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 // Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74) -#endif - -#ifndef CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE -#define CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE 6 // Buffer size of audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74) -#endif - -// Use software encoding/decoding - -// The software coding feature of the driver is not mandatory. It is useful if, for instance, you have two I2S streams which need to be interleaved -// into a single PCM stream as SAMPLE_1 | SAMPLE_2 | SAMPLE_3 | SAMPLE_4. -// -// Currently, only PCM type I encoding/decoding is supported! -// -// If the coding feature is to be used, support FIFOs need to be configured. Their sizes and numbers are defined below. - -// Encoding/decoding is done in software and thus time consuming. If you can encode/decode your stream more efficiently do not use the -// support FIFOs but write/read directly into/from the EP_X_SW_BUFFER_FIFOs using -// - tud_audio_n_write() or -// - tud_audio_n_read(). -// To write/read to/from the support FIFOs use -// - tud_audio_n_write_support_ff() or -// - tud_audio_n_read_support_ff(). -// -// The encoding/decoding format type done is defined below. -// -// The encoding/decoding starts when the private callback functions -// - audio_tx_done_cb() -// - audio_rx_done_cb() -// are invoked. If support FIFOs are used, the corresponding encoding/decoding functions are called from there. -// Once encoding/decoding is done the result is put directly into the EP_X_SW_BUFFER_FIFOs. You can use the public callback functions -// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb() -// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb() -// if you want to get informed what happened. -// -// If you don't use the support FIFOs you may use the public callback functions -// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb() -// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb() -// to write/read from/into the EP_X_SW_BUFFER_FIFOs at the right time. -// -// If you need a different encoding which is not support so far implement it in the -// - audio_tx_done_cb() -// - audio_rx_done_cb() -// functions. - -// Enable encoding/decodings - for these to work, support FIFOs need to be setup in appropriate numbers and size -// The actual coding parameters of active AS alternate interface is parsed from the descriptors - -// The item size of the FIFO is always fixed to one i.e. bytes! Furthermore, the actively used FIFO depth is reconfigured such that the depth is a multiple of the current sample size in order to avoid samples to get split up in case of a wrap in the FIFO ring buffer (depth = (max_depth / sampe_sz) * sampe_sz)! -// This is important to remind in case you use DMAs! If the sample sizes changes, the DMA MUST BE RECONFIGURED just like the FIFOs for a different depth!!! - -// For PCM encoding/decoding - -#ifndef CFG_TUD_AUDIO_ENABLE_ENCODING -#define CFG_TUD_AUDIO_ENABLE_ENCODING 0 -#endif - -#ifndef CFG_TUD_AUDIO_ENABLE_DECODING -#define CFG_TUD_AUDIO_ENABLE_DECODING 0 -#endif - -// This enabling allows to save the current coding parameters e.g. # of bytes per sample etc. - TYPE_I includes common PCM encoding -#ifndef CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING -#define CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING 0 -#endif - -#ifndef CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING -#define CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING 0 -#endif - -// Type I Coding parameters not given within UAC2 descriptors -// It would be possible to allow for a more flexible setting and not fix this parameter as done below. However, this is most often not needed and kept for later if really necessary. The more flexible setting could be implemented within set_interface(), however, how the values are saved per alternate setting is to be determined! -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING -#ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#endif -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#endif -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING -#ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#endif -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#endif -#endif - -// Remaining types not support so far - -// Number of support FIFOs to set up - multiple channels can be handled by one FIFO - very common is two channels per FIFO stemming from one I2S interface -#ifndef CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO 0 -#endif - -#ifndef CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO 0 -#endif - -// Size of support FIFOs IN BYTES - if size > 0 there are as many FIFOs set up as CFG_TUD_AUDIO_FUNC_X_N_TX_SUPP_SW_FIFO and CFG_TUD_AUDIO_FUNC_X_N_RX_SUPP_SW_FIFO -#ifndef CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ 0 // FIFO size - minimum size: ceil(f_s/1000) * max(# of TX channels) / (# of TX support FIFOs) * max(# of bytes per sample) -#endif -#ifndef CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ 0 -#endif - -#ifndef CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ 0 // FIFO size - minimum size: ceil(f_s/1000) * max(# of RX channels) / (# of RX support FIFOs) * max(# of bytes per sample) -#endif -#ifndef CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ 0 -#endif - -//static_assert(sizeof(tud_audio_desc_lengths) != CFG_TUD_AUDIO, "Supply audio function descriptor pack length!"); - -// Supported types of this driver: -// AUDIO_DATA_FORMAT_TYPE_I_PCM - Required definitions: CFG_TUD_AUDIO_N_CHANNELS and CFG_TUD_AUDIO_BYTES_PER_CHANNEL - -#ifdef __cplusplus -extern "C" { -#endif - -/** \addtogroup AUDIO_Serial Serial - * @{ - * \defgroup AUDIO_Serial_Device Device - * @{ */ - -//--------------------------------------------------------------------+ -// Application API (Multiple Interfaces) -// CFG_TUD_AUDIO > 1 -//--------------------------------------------------------------------+ -bool tud_audio_n_mounted (uint8_t func_id); - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING -uint16_t tud_audio_n_available (uint8_t func_id); -uint16_t tud_audio_n_read (uint8_t func_id, void* buffer, uint16_t bufsize); -bool tud_audio_n_clear_ep_out_ff (uint8_t func_id); // Delete all content in the EP OUT FIFO -tu_fifo_t* tud_audio_n_get_ep_out_ff (uint8_t func_id); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING -bool tud_audio_n_clear_rx_support_ff (uint8_t func_id, uint8_t ff_idx); // Delete all content in the support RX FIFOs -uint16_t tud_audio_n_available_support_ff (uint8_t func_id, uint8_t ff_idx); -uint16_t tud_audio_n_read_support_ff (uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize); -tu_fifo_t* tud_audio_n_get_rx_support_ff (uint8_t func_id, uint8_t ff_idx); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING -uint16_t tud_audio_n_write (uint8_t func_id, const void * data, uint16_t len); -bool tud_audio_n_clear_ep_in_ff (uint8_t func_id); // Delete all content in the EP IN FIFO -tu_fifo_t* tud_audio_n_get_ep_in_ff (uint8_t func_id); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING -uint16_t tud_audio_n_flush_tx_support_ff (uint8_t func_id); // Force all content in the support TX FIFOs to be written into EP SW FIFO -bool tud_audio_n_clear_tx_support_ff (uint8_t func_id, uint8_t ff_idx); -uint16_t tud_audio_n_write_support_ff (uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len); -tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_idx); -#endif - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -uint16_t tud_audio_int_ctr_n_write (uint8_t func_id, uint8_t const* buffer, uint16_t len); -#endif - -//--------------------------------------------------------------------+ -// Application API (Interface0) -//--------------------------------------------------------------------+ - -static inline bool tud_audio_mounted (void); - -// RX API - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING -static inline uint16_t tud_audio_available (void); -static inline bool tud_audio_clear_ep_out_ff (void); // Delete all content in the EP OUT FIFO -static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize); -static inline tu_fifo_t* tud_audio_get_ep_out_ff (void); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING -static inline bool tud_audio_clear_rx_support_ff (uint8_t ff_idx); -static inline uint16_t tud_audio_available_support_ff (uint8_t ff_idx); -static inline uint16_t tud_audio_read_support_ff (uint8_t ff_idx, void* buffer, uint16_t bufsize); -static inline tu_fifo_t* tud_audio_get_rx_support_ff (uint8_t ff_idx); -#endif - -// TX API - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING -static inline uint16_t tud_audio_write (const void * data, uint16_t len); -static inline bool tud_audio_clear_ep_in_ff (void); -static inline tu_fifo_t* tud_audio_get_ep_in_ff (void); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING -static inline uint16_t tud_audio_flush_tx_support_ff (void); -static inline uint16_t tud_audio_clear_tx_support_ff (uint8_t ff_idx); -static inline uint16_t tud_audio_write_support_ff (uint8_t ff_idx, const void * data, uint16_t len); -static inline tu_fifo_t* tud_audio_get_tx_support_ff (uint8_t ff_idx); -#endif - -// INT CTR API - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -static inline uint16_t tud_audio_int_ctr_write (uint8_t const* buffer, uint16_t len); -#endif - -// Buffer control EP data and schedule a transmit -// This function is intended to be used if you do not have a persistent buffer or memory location available (e.g. non-local variables) and need to answer onto a -// get request. This function buffers your answer request frame into the control buffer of the corresponding audio driver and schedules a transmit for sending it. -// Since transmission is triggered via interrupts, a persistent memory location is required onto which the buffer pointer in pointing. If you already have such -// available you may directly use 'tud_control_xfer(...)'. In this case data does not need to be copied into an additional buffer and you save some time. -// If the request's wLength is zero, a status packet is sent instead. -bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len); - -//--------------------------------------------------------------------+ -// Application Callback API (weak is optional) -//--------------------------------------------------------------------+ - -#if CFG_TUD_AUDIO_ENABLE_EP_IN -TU_ATTR_WEAK bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting); -TU_ATTR_WEAK bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT -TU_ATTR_WEAK bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting); -TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id); - - -// determined by the user itself and set by use of tud_audio_n_fb_set(). The feedback value may be determined e.g. from some fill status of some FIFO buffer. Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus less CPU load, disadvantage: typically a larger FIFO is needed to compensate for jitter (e.g. 8 frames), i.e. a larger delay is introduced. - -// Feedback value is calculated within the audio driver by use of SOF interrupt. The driver needs information about the master clock f_m from which the audio sample frequency f_s is derived, f_s itself, and the cycle count of f_m at time of the SOF interrupt (e.g. by use of a hardware counter) - see tud_audio_set_fb_params(). Advantage: Reduced jitter in the feedback value computation, hence, the receive FIFO can be smaller (e.g. 2 frames) and thus a smaller delay is possible, disadvantage: higher CPU load due to SOF ISR handling every frame i.e. 1ms or 125us. This option is a great starting point to try the SOF ISR option but depending on your hardware setup (performance of the CPU) it might not work. If so, figure out why and use the next option. (The most critical point is the reading of the cycle counter value of f_m. It is read from within the SOF ISR - see: audiod_sof() -, hence, the ISR must has a high priority such that no software dependent "random" delay i.e. jitter is introduced). - -// Feedback value is determined by the user by use of SOF interrupt. The user may use tud_audio_sof_isr() which is called every SOF (of course only invoked when an alternate interface other than zero was set). The number of frames used to determine the feedback value for the currently active alternate setting can be get by tud_audio_get_fb_n_frames(). The feedback value must be set by use of tud_audio_n_fb_set(). - -// This function is used to provide data rate feedback from an asynchronous sink. Feedback value will be sent at FB endpoint interval till it's changed. -// -// The feedback format is specified to be 16.16 for HS and 10.14 for FS devices (see Universal Serial Bus Specification Revision 2.0 5.12.4.2). By default, -// the choice of format is left to the caller and feedback argument is sent as-is. If CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION is set, then tinyusb -// expects 16.16 format and handles the conversion to 10.14 on FS. -// -// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 devices. On Linux and macOS it seems the -// driver can work with either format. So a good compromise is to keep format correction disabled and stick to 16.16 format. - -// Feedback value can be determined from within the SOF ISR of the audio driver. This should reduce jitter. If the feature is used, the user can not set the feedback value. - -// Determine feedback value - The feedback method is described in 5.12.4.2 of the USB 2.0 spec -// Boiled down, the feedback value Ff = n_samples / (micro)frame. -// Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s) -// The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where P = min( ceil(log2(f_m / f_s)), K) -// feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames - -bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback); -static inline bool tud_audio_fb_set(uint32_t feedback); - -// Update feedback value with passed cycles since last time this update function is called. -// Typically called within tud_audio_sof_isr(). Required tud_audio_feedback_params_cb() is implemented -// This function will also call tud_audio_feedback_set() -// return feedback value in 16.16 for reference (0 for error) -uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles); - -enum { - AUDIO_FEEDBACK_METHOD_DISABLED, - AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED, - AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT, - AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2, - - // impelemnt later - // AUDIO_FEEDBACK_METHOD_FIFO_COUNT -}; - -typedef struct { - uint8_t method; - uint32_t sample_freq; // sample frequency in Hz - - union { - struct { - uint32_t mclk_freq; // Main clock frequency in Hz i.e. master clock to which sample clock is based on - }frequency; - -#if 0 // implement later - struct { - uint32_t threshold_bytes; // minimum number of bytes received to be considered as filled/ready - }fifo_count; -#endif - }; -}audio_feedback_params_t; - -// Invoked when needed to set feedback parameters -TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param); - -// Callback in ISR context, invoked periodically according to feedback endpoint bInterval. -// Could be used to compute and update feedback value, should be placed in RAM if possible -// frame_number : current SOF count -// interval_shift: number of bit shift i.e log2(interval) from Feedback endpoint descriptor -TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift); - -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t n_bytes_copied); -#endif - -// Invoked when audio set interface request received -TU_ATTR_WEAK bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request); - -// Invoked when audio set interface request received which closes an EP -TU_ATTR_WEAK bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request); - -// Invoked when audio class specific set request received for an EP -TU_ATTR_WEAK bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); - -// Invoked when audio class specific set request received for an interface -TU_ATTR_WEAK bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); - -// Invoked when audio class specific set request received for an entity -TU_ATTR_WEAK bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); - -// Invoked when audio class specific get request received for an EP -TU_ATTR_WEAK bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request); - -// Invoked when audio class specific get request received for an interface -TU_ATTR_WEAK bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request); - -// Invoked when audio class specific get request received for an entity -TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request); - -//--------------------------------------------------------------------+ -// Inline Functions -//--------------------------------------------------------------------+ - -static inline bool tud_audio_mounted(void) -{ - return tud_audio_n_mounted(0); -} - -// RX API - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING - -static inline uint16_t tud_audio_available(void) -{ - return tud_audio_n_available(0); -} - -static inline uint16_t tud_audio_read(void* buffer, uint16_t bufsize) -{ - return tud_audio_n_read(0, buffer, bufsize); -} - -static inline bool tud_audio_clear_ep_out_ff(void) -{ - return tud_audio_n_clear_ep_out_ff(0); -} - -static inline tu_fifo_t* tud_audio_get_ep_out_ff(void) -{ - return tud_audio_n_get_ep_out_ff(0); -} - -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - -static inline bool tud_audio_clear_rx_support_ff(uint8_t ff_idx) -{ - return tud_audio_n_clear_rx_support_ff(0, ff_idx); -} - -static inline uint16_t tud_audio_available_support_ff(uint8_t ff_idx) -{ - return tud_audio_n_available_support_ff(0, ff_idx); -} - -static inline uint16_t tud_audio_read_support_ff(uint8_t ff_idx, void* buffer, uint16_t bufsize) -{ - return tud_audio_n_read_support_ff(0, ff_idx, buffer, bufsize); -} - -static inline tu_fifo_t* tud_audio_get_rx_support_ff(uint8_t ff_idx) -{ - return tud_audio_n_get_rx_support_ff(0, ff_idx); -} - -#endif - -// TX API - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - -static inline uint16_t tud_audio_write(const void * data, uint16_t len) -{ - return tud_audio_n_write(0, data, len); -} - -static inline bool tud_audio_clear_ep_in_ff(void) -{ - return tud_audio_n_clear_ep_in_ff(0); -} - -static inline tu_fifo_t* tud_audio_get_ep_in_ff(void) -{ - return tud_audio_n_get_ep_in_ff(0); -} - -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - -static inline uint16_t tud_audio_flush_tx_support_ff(void) -{ - return tud_audio_n_flush_tx_support_ff(0); -} - -static inline uint16_t tud_audio_clear_tx_support_ff(uint8_t ff_idx) -{ - return tud_audio_n_clear_tx_support_ff(0, ff_idx); -} - -static inline uint16_t tud_audio_write_support_ff(uint8_t ff_idx, const void * data, uint16_t len) -{ - return tud_audio_n_write_support_ff(0, ff_idx, data, len); -} - -static inline tu_fifo_t* tud_audio_get_tx_support_ff(uint8_t ff_idx) -{ - return tud_audio_n_get_tx_support_ff(0, ff_idx); -} - -#endif - -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t len) -{ - return tud_audio_int_ctr_n_write(0, buffer, len); -} -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - -static inline bool tud_audio_fb_set(uint32_t feedback) -{ - return tud_audio_n_fb_set(0, feedback); -} - -#endif - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void audiod_init (void); -void audiod_reset (uint8_t rhport); -uint16_t audiod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -bool audiod_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); -void audiod_sof_isr (uint8_t rhport, uint32_t frame_count); - -#ifdef __cplusplus -} -#endif - -#endif /* _TUSB_AUDIO_DEVICE_H_ */ - -/** @} */ -/** @} */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.c deleted file mode 100755 index f96bb355..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Jerzy Kasenberg - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_BTH) - -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "bth_device.h" -#include - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -typedef struct -{ - uint8_t itf_num; - uint8_t ep_ev; - uint8_t ep_acl_in; - uint8_t ep_acl_out; - uint8_t ep_voice[2]; // Not used yet - uint8_t ep_voice_size[2][CFG_TUD_BTH_ISO_ALT_COUNT]; - - // Endpoint Transfer buffer - CFG_TUSB_MEM_ALIGN bt_hci_cmd_t hci_cmd; - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_BTH_DATA_EPSIZE]; - -} btd_interface_t; - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION btd_interface_t _btd_itf; - -static bool bt_tx_data(uint8_t ep, void *data, uint16_t len) -{ - uint8_t const rhport = 0; - - // skip if previous transfer not complete - TU_VERIFY(!usbd_edpt_busy(rhport, ep)); - - TU_ASSERT(usbd_edpt_xfer(rhport, ep, data, len)); - - return true; -} - -//--------------------------------------------------------------------+ -// READ API -//--------------------------------------------------------------------+ - - -//--------------------------------------------------------------------+ -// WRITE API -//--------------------------------------------------------------------+ - -bool tud_bt_event_send(void *event, uint16_t event_len) -{ - return bt_tx_data(_btd_itf.ep_ev, event, event_len); -} - -bool tud_bt_acl_data_send(void *event, uint16_t event_len) -{ - return bt_tx_data(_btd_itf.ep_acl_in, event, event_len); -} - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void btd_init(void) -{ - tu_memclr(&_btd_itf, sizeof(_btd_itf)); -} - -void btd_reset(uint8_t rhport) -{ - (void)rhport; -} - -uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) -{ - tusb_desc_endpoint_t const *desc_ep; - uint16_t drv_len = 0; - // Size of single alternative of ISO interface - const uint16_t iso_alt_itf_size = sizeof(tusb_desc_interface_t) + 2 * sizeof(tusb_desc_endpoint_t); - // Size of hci interface - const uint16_t hci_itf_size = sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t); - // Ensure this is BT Primary Controller - TU_VERIFY(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass && - TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass && - TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0); - - TU_ASSERT(itf_desc->bNumEndpoints == 3 && max_len >= hci_itf_size); - - _btd_itf.itf_num = itf_desc->bInterfaceNumber; - - desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); - - TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer, 0); - TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); - _btd_itf.ep_ev = desc_ep->bEndpointAddress; - - // Open endpoint pair - TU_ASSERT(usbd_open_edpt_pair(rhport, tu_desc_next(desc_ep), 2, TUSB_XFER_BULK, &_btd_itf.ep_acl_out, - &_btd_itf.ep_acl_in), 0); - - itf_desc = (tusb_desc_interface_t const *)tu_desc_next(tu_desc_next(tu_desc_next(desc_ep))); - - // Prepare for incoming data from host - TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE), 0); - - drv_len = hci_itf_size; - - // Ensure this is still BT Primary Controller - TU_ASSERT(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass && - TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass && - TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0); - TU_ASSERT(itf_desc->bNumEndpoints == 2 && max_len >= iso_alt_itf_size + drv_len); - - uint8_t dir; - - desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc); - TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0); - TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0); - dir = tu_edpt_dir(desc_ep->bEndpointAddress); - _btd_itf.ep_voice[dir] = desc_ep->bEndpointAddress; - // Store endpoint size for alternative - _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); - - desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep); - TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0); - dir = tu_edpt_dir(desc_ep->bEndpointAddress); - _btd_itf.ep_voice[dir] = desc_ep->bEndpointAddress; - // Store endpoint size for alternative - _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); - drv_len += iso_alt_itf_size; - - for (int i = 1; i < CFG_TUD_BTH_ISO_ALT_COUNT && drv_len + iso_alt_itf_size <= max_len; ++i) { - // Make sure rest of alternatives matches - itf_desc = (tusb_desc_interface_t const *)tu_desc_next(desc_ep); - if (itf_desc->bDescriptorType != TUSB_DESC_INTERFACE || - TUSB_CLASS_WIRELESS_CONTROLLER != itf_desc->bInterfaceClass || - TUD_BT_APP_SUBCLASS != itf_desc->bInterfaceSubClass || - TUD_BT_PROTOCOL_PRIMARY_CONTROLLER != itf_desc->bInterfaceProtocol) - { - // Not an Iso interface instance - break; - } - TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0); - - desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc); - dir = tu_edpt_dir(desc_ep->bEndpointAddress); - // Verify that alternative endpoint are same as first ones - TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT && - _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0); - _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); - - desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep); - dir = tu_edpt_dir(desc_ep->bEndpointAddress); - // Verify that alternative endpoint are same as first ones - TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT && - _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0); - _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); - drv_len += iso_alt_itf_size; - } - - return drv_len; -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) -{ - (void)rhport; - - if ( stage == CONTROL_STAGE_SETUP ) - { - if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && - request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE) - { - // HCI command packet addressing for single function Primary Controllers - TU_VERIFY(request->bRequest == 0 && request->wValue == 0 && request->wIndex == 0); - } - else if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE) - { - if (request->bRequest == TUSB_REQ_SET_INTERFACE && _btd_itf.itf_num + 1 == request->wIndex) - { - // TODO: Set interface it would involve changing size of endpoint size - } - else - { - // HCI command packet for Primary Controller function in a composite device - TU_VERIFY(request->bRequest == 0 && request->wValue == 0 && request->wIndex == _btd_itf.itf_num); - } - } - else return false; - - return tud_control_xfer(rhport, request, &_btd_itf.hci_cmd, sizeof(_btd_itf.hci_cmd)); - } - else if ( stage == CONTROL_STAGE_DATA ) - { - // Handle class request only - TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); - - if (tud_bt_hci_cmd_cb) tud_bt_hci_cmd_cb(&_btd_itf.hci_cmd, tu_min16(request->wLength, sizeof(_btd_itf.hci_cmd))); - } - - return true; -} - -bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void)result; - - // received new data from host - if (ep_addr == _btd_itf.ep_acl_out) - { - if (tud_bt_acl_data_received_cb) tud_bt_acl_data_received_cb(_btd_itf.epout_buf, xferred_bytes); - - // prepare for next data - TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE)); - } - else if (ep_addr == _btd_itf.ep_ev) - { - if (tud_bt_event_sent_cb) tud_bt_event_sent_cb((uint16_t)xferred_bytes); - } - else if (ep_addr == _btd_itf.ep_acl_in) - { - if (tud_bt_acl_data_sent_cb) tud_bt_acl_data_sent_cb((uint16_t)xferred_bytes); - } - - return true; -} - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.h deleted file mode 100755 index 921bd7a1..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/bth/bth_device.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Jerzy Kasenberg - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_BTH_DEVICE_H_ -#define _TUSB_BTH_DEVICE_H_ - -#include -#include - -//--------------------------------------------------------------------+ -// Class Driver Configuration -//--------------------------------------------------------------------+ -#ifndef CFG_TUD_BTH_EVENT_EPSIZE -#define CFG_TUD_BTH_EVENT_EPSIZE 16 -#endif -#ifndef CFG_TUD_BTH_DATA_EPSIZE -#define CFG_TUD_BTH_DATA_EPSIZE 64 -#endif - -typedef struct TU_ATTR_PACKED -{ - uint16_t op_code; - uint8_t param_length; - uint8_t param[255]; -} bt_hci_cmd_t; - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Application Callback API (weak is optional) -//--------------------------------------------------------------------+ - -// Invoked when HCI command was received over USB from Bluetooth host. -// Detailed format is described in Bluetooth core specification Vol 2, -// Part E, 5.4.1. -// Length of the command is from 3 bytes (2 bytes for OpCode, -// 1 byte for parameter total length) to 258. -TU_ATTR_WEAK void tud_bt_hci_cmd_cb(void *hci_cmd, size_t cmd_len); - -// Invoked when ACL data was received over USB from Bluetooth host. -// Detailed format is described in Bluetooth core specification Vol 2, -// Part E, 5.4.2. -// Length is from 4 bytes, (12 bits for Handle, 4 bits for flags -// and 16 bits for data total length) to endpoint size. -TU_ATTR_WEAK void tud_bt_acl_data_received_cb(void *acl_data, uint16_t data_len); - -// Called when event sent with tud_bt_event_send() was delivered to BT stack. -// Controller can release/reuse buffer with Event packet at this point. -TU_ATTR_WEAK void tud_bt_event_sent_cb(uint16_t sent_bytes); - -// Called when ACL data that was sent with tud_bt_acl_data_send() -// was delivered to BT stack. -// Controller can release/reuse buffer with ACL packet at this point. -TU_ATTR_WEAK void tud_bt_acl_data_sent_cb(uint16_t sent_bytes); - -// Bluetooth controller calls this function when it wants to send even packet -// as described in Bluetooth core specification Vol 2, Part E, 5.4.4. -// Event has at least 2 bytes, first is Event code second contains parameter -// total length. Controller can release/reuse event memory after -// tud_bt_event_sent_cb() is called. -bool tud_bt_event_send(void *event, uint16_t event_len); - -// Bluetooth controller calls this to send ACL data packet -// as described in Bluetooth core specification Vol 2, Part E, 5.4.2 -// Minimum length is 4 bytes, (12 bits for Handle, 4 bits for flags -// and 16 bits for data total length). Upper limit is not limited -// to endpoint size since buffer is allocate by controller -// and must not be reused till tud_bt_acl_data_sent_cb() is called. -bool tud_bt_acl_data_send(void *acl_data, uint16_t data_len); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void btd_init (void); -void btd_reset (uint8_t rhport); -uint16_t btd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool btd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); -bool btd_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_BTH_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc.h b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc.h deleted file mode 100644 index 4658e43a..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc.h +++ /dev/null @@ -1,424 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -/** \ingroup group_class - * \defgroup ClassDriver_CDC Communication Device Class (CDC) - * Currently only Abstract Control Model subclass is supported - * @{ */ - -#ifndef _TUSB_CDC_H__ -#define _TUSB_CDC_H__ - -#include "common/tusb_common.h" - -#ifdef __cplusplus - extern "C" { -#endif - -/** \defgroup ClassDriver_CDC_Common Common Definitions - * @{ */ - -//--------------------------------------------------------------------+ -// CDC Communication Interface Class -//--------------------------------------------------------------------+ - -/// Communication Interface Subclass Codes -typedef enum -{ - CDC_COMM_SUBCLASS_DIRECT_LINE_CONTROL_MODEL = 0x01 , ///< Direct Line Control Model [USBPSTN1.2] - CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL = 0x02 , ///< Abstract Control Model [USBPSTN1.2] - CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL = 0x03 , ///< Telephone Control Model [USBPSTN1.2] - CDC_COMM_SUBCLASS_MULTICHANNEL_CONTROL_MODEL = 0x04 , ///< Multi-Channel Control Model [USBISDN1.2] - CDC_COMM_SUBCLASS_CAPI_CONTROL_MODEL = 0x05 , ///< CAPI Control Model [USBISDN1.2] - CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL = 0x06 , ///< Ethernet Networking Control Model [USBECM1.2] - CDC_COMM_SUBCLASS_ATM_NETWORKING_CONTROL_MODEL = 0x07 , ///< ATM Networking Control Model [USBATM1.2] - CDC_COMM_SUBCLASS_WIRELESS_HANDSET_CONTROL_MODEL = 0x08 , ///< Wireless Handset Control Model [USBWMC1.1] - CDC_COMM_SUBCLASS_DEVICE_MANAGEMENT = 0x09 , ///< Device Management [USBWMC1.1] - CDC_COMM_SUBCLASS_MOBILE_DIRECT_LINE_MODEL = 0x0A , ///< Mobile Direct Line Model [USBWMC1.1] - CDC_COMM_SUBCLASS_OBEX = 0x0B , ///< OBEX [USBWMC1.1] - CDC_COMM_SUBCLASS_ETHERNET_EMULATION_MODEL = 0x0C , ///< Ethernet Emulation Model [USBEEM1.0] - CDC_COMM_SUBCLASS_NETWORK_CONTROL_MODEL = 0x0D ///< Network Control Model [USBNCM1.0] -} cdc_comm_sublcass_type_t; - -/// Communication Interface Protocol Codes -typedef enum -{ - CDC_COMM_PROTOCOL_NONE = 0x00 , ///< No specific protocol - CDC_COMM_PROTOCOL_ATCOMMAND = 0x01 , ///< AT Commands: V.250 etc - CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101 = 0x02 , ///< AT Commands defined by PCCA-101 - CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101_AND_ANNEXO = 0x03 , ///< AT Commands defined by PCCA-101 & Annex O - CDC_COMM_PROTOCOL_ATCOMMAND_GSM_707 = 0x04 , ///< AT Commands defined by GSM 07.07 - CDC_COMM_PROTOCOL_ATCOMMAND_3GPP_27007 = 0x05 , ///< AT Commands defined by 3GPP 27.007 - CDC_COMM_PROTOCOL_ATCOMMAND_CDMA = 0x06 , ///< AT Commands defined by TIA for CDMA - CDC_COMM_PROTOCOL_ETHERNET_EMULATION_MODEL = 0x07 ///< Ethernet Emulation Model -} cdc_comm_protocol_type_t; - -//------------- SubType Descriptor in COMM Functional Descriptor -------------// -/// Communication Interface SubType Descriptor -typedef enum -{ - CDC_FUNC_DESC_HEADER = 0x00 , ///< Header Functional Descriptor, which marks the beginning of the concatenated set of functional descriptors for the interface. - CDC_FUNC_DESC_CALL_MANAGEMENT = 0x01 , ///< Call Management Functional Descriptor. - CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT = 0x02 , ///< Abstract Control Management Functional Descriptor. - CDC_FUNC_DESC_DIRECT_LINE_MANAGEMENT = 0x03 , ///< Direct Line Management Functional Descriptor. - CDC_FUNC_DESC_TELEPHONE_RINGER = 0x04 , ///< Telephone Ringer Functional Descriptor. - CDC_FUNC_DESC_TELEPHONE_CALL_AND_LINE_STATE_REPORTING_CAPACITY = 0x05 , ///< Telephone Call and Line State Reporting Capabilities Functional Descriptor. - CDC_FUNC_DESC_UNION = 0x06 , ///< Union Functional Descriptor - CDC_FUNC_DESC_COUNTRY_SELECTION = 0x07 , ///< Country Selection Functional Descriptor - CDC_FUNC_DESC_TELEPHONE_OPERATIONAL_MODES = 0x08 , ///< Telephone Operational ModesFunctional Descriptor - CDC_FUNC_DESC_USB_TERMINAL = 0x09 , ///< USB Terminal Functional Descriptor - CDC_FUNC_DESC_NETWORK_CHANNEL_TERMINAL = 0x0A , ///< Network Channel Terminal Descriptor - CDC_FUNC_DESC_PROTOCOL_UNIT = 0x0B , ///< Protocol Unit Functional Descriptor - CDC_FUNC_DESC_EXTENSION_UNIT = 0x0C , ///< Extension Unit Functional Descriptor - CDC_FUNC_DESC_MULTICHANEL_MANAGEMENT = 0x0D , ///< Multi-Channel Management Functional Descriptor - CDC_FUNC_DESC_CAPI_CONTROL_MANAGEMENT = 0x0E , ///< CAPI Control Management Functional Descriptor - CDC_FUNC_DESC_ETHERNET_NETWORKING = 0x0F , ///< Ethernet Networking Functional Descriptor - CDC_FUNC_DESC_ATM_NETWORKING = 0x10 , ///< ATM Networking Functional Descriptor - CDC_FUNC_DESC_WIRELESS_HANDSET_CONTROL_MODEL = 0x11 , ///< Wireless Handset Control Model Functional Descriptor - CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL = 0x12 , ///< Mobile Direct Line Model Functional Descriptor - CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL_DETAIL = 0x13 , ///< MDLM Detail Functional Descriptor - CDC_FUNC_DESC_DEVICE_MANAGEMENT_MODEL = 0x14 , ///< Device Management Model Functional Descriptor - CDC_FUNC_DESC_OBEX = 0x15 , ///< OBEX Functional Descriptor - CDC_FUNC_DESC_COMMAND_SET = 0x16 , ///< Command Set Functional Descriptor - CDC_FUNC_DESC_COMMAND_SET_DETAIL = 0x17 , ///< Command Set Detail Functional Descriptor - CDC_FUNC_DESC_TELEPHONE_CONTROL_MODEL = 0x18 , ///< Telephone Control Model Functional Descriptor - CDC_FUNC_DESC_OBEX_SERVICE_IDENTIFIER = 0x19 , ///< OBEX Service Identifier Functional Descriptor - CDC_FUNC_DESC_NCM = 0x1A , ///< NCM Functional Descriptor -}cdc_func_desc_type_t; - -//--------------------------------------------------------------------+ -// CDC Data Interface Class -//--------------------------------------------------------------------+ - -// SUBCLASS code of Data Interface is not used and should/must be zero - -// Data Interface Protocol Codes -typedef enum{ - CDC_DATA_PROTOCOL_ISDN_BRI = 0x30, ///< Physical interface protocol for ISDN BRI - CDC_DATA_PROTOCOL_HDLC = 0x31, ///< HDLC - CDC_DATA_PROTOCOL_TRANSPARENT = 0x32, ///< Transparent - CDC_DATA_PROTOCOL_Q921_MANAGEMENT = 0x50, ///< Management protocol for Q.921 data link protocol - CDC_DATA_PROTOCOL_Q921_DATA_LINK = 0x51, ///< Data link protocol for Q.931 - CDC_DATA_PROTOCOL_Q921_TEI_MULTIPLEXOR = 0x52, ///< TEI-multiplexor for Q.921 data link protocol - CDC_DATA_PROTOCOL_V42BIS_DATA_COMPRESSION = 0x90, ///< Data compression procedures - CDC_DATA_PROTOCOL_EURO_ISDN = 0x91, ///< Euro-ISDN protocol control - CDC_DATA_PROTOCOL_V24_RATE_ADAPTION_TO_ISDN = 0x92, ///< V.24 rate adaptation to ISDN - CDC_DATA_PROTOCOL_CAPI_COMMAND = 0x93, ///< CAPI Commands - CDC_DATA_PROTOCOL_HOST_BASED_DRIVER = 0xFD, ///< Host based driver. Note: This protocol code should only be used in messages between host and device to identify the host driver portion of a protocol stack. - CDC_DATA_PROTOCOL_IN_PROTOCOL_UNIT_FUNCTIONAL_DESCRIPTOR = 0xFE ///< The protocol(s) are described using a ProtocolUnit Functional Descriptors on Communications Class Interface -}cdc_data_protocol_type_t; - -//--------------------------------------------------------------------+ -// Management Element Request (Control Endpoint) -//--------------------------------------------------------------------+ - -/// Communication Interface Management Element Request Codes -typedef enum -{ - CDC_REQUEST_SEND_ENCAPSULATED_COMMAND = 0x00, ///< is used to issue a command in the format of the supported control protocol of the Communications Class interface - CDC_REQUEST_GET_ENCAPSULATED_RESPONSE = 0x01, ///< is used to request a response in the format of the supported control protocol of the Communications Class interface. - CDC_REQUEST_SET_COMM_FEATURE = 0x02, - CDC_REQUEST_GET_COMM_FEATURE = 0x03, - CDC_REQUEST_CLEAR_COMM_FEATURE = 0x04, - - CDC_REQUEST_SET_AUX_LINE_STATE = 0x10, - CDC_REQUEST_SET_HOOK_STATE = 0x11, - CDC_REQUEST_PULSE_SETUP = 0x12, - CDC_REQUEST_SEND_PULSE = 0x13, - CDC_REQUEST_SET_PULSE_TIME = 0x14, - CDC_REQUEST_RING_AUX_JACK = 0x15, - - CDC_REQUEST_SET_LINE_CODING = 0x20, - CDC_REQUEST_GET_LINE_CODING = 0x21, - CDC_REQUEST_SET_CONTROL_LINE_STATE = 0x22, - CDC_REQUEST_SEND_BREAK = 0x23, - - CDC_REQUEST_SET_RINGER_PARMS = 0x30, - CDC_REQUEST_GET_RINGER_PARMS = 0x31, - CDC_REQUEST_SET_OPERATION_PARMS = 0x32, - CDC_REQUEST_GET_OPERATION_PARMS = 0x33, - CDC_REQUEST_SET_LINE_PARMS = 0x34, - CDC_REQUEST_GET_LINE_PARMS = 0x35, - CDC_REQUEST_DIAL_DIGITS = 0x36, - CDC_REQUEST_SET_UNIT_PARAMETER = 0x37, - CDC_REQUEST_GET_UNIT_PARAMETER = 0x38, - CDC_REQUEST_CLEAR_UNIT_PARAMETER = 0x39, - CDC_REQUEST_GET_PROFILE = 0x3A, - - CDC_REQUEST_SET_ETHERNET_MULTICAST_FILTERS = 0x40, - CDC_REQUEST_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x41, - CDC_REQUEST_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x42, - CDC_REQUEST_SET_ETHERNET_PACKET_FILTER = 0x43, - CDC_REQUEST_GET_ETHERNET_STATISTIC = 0x44, - - CDC_REQUEST_SET_ATM_DATA_FORMAT = 0x50, - CDC_REQUEST_GET_ATM_DEVICE_STATISTICS = 0x51, - CDC_REQUEST_SET_ATM_DEFAULT_VC = 0x52, - CDC_REQUEST_GET_ATM_VC_STATISTICS = 0x53, - - CDC_REQUEST_MDLM_SEMANTIC_MODEL = 0x60, -}cdc_management_request_t; - -enum -{ - CDC_CONTROL_LINE_STATE_DTR = 0x01, - CDC_CONTROL_LINE_STATE_RTS = 0x02, -}; - -enum -{ - CDC_LINE_CONDING_STOP_BITS_1 = 0, // 1 bit - CDC_LINE_CONDING_STOP_BITS_1_5 = 1, // 1.5 bits - CDC_LINE_CONDING_STOP_BITS_2 = 2, // 2 bits -}; - -enum -{ - CDC_LINE_CODING_PARITY_NONE = 0, - CDC_LINE_CODING_PARITY_ODD = 1, - CDC_LINE_CODING_PARITY_EVEN = 2, - CDC_LINE_CODING_PARITY_MARK = 3, - CDC_LINE_CODING_PARITY_SPACE = 4, -}; - -//--------------------------------------------------------------------+ -// Management Element Notification (Notification Endpoint) -//--------------------------------------------------------------------+ - -/// 6.3 Notification Codes -typedef enum -{ - CDC_NOTIF_NETWORK_CONNECTION = 0x00, ///< This notification allows the device to notify the host about network connection status. - CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request. - CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08, - CDC_NOTIF_RING_DETECT = 0x09, - CDC_NOTIF_SERIAL_STATE = 0x20, - CDC_NOTIF_CALL_STATE_CHANGE = 0x28, - CDC_NOTIF_LINE_STATE_CHANGE = 0x29, - CDC_NOTIF_CONNECTION_SPEED_CHANGE = 0x2A, ///< This notification allows the device to inform the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred - CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40, -}cdc_notification_request_t; - -//--------------------------------------------------------------------+ -// Class Specific Functional Descriptor (Communication Interface) -//--------------------------------------------------------------------+ - -// Start of all packed definitions for compiler without per-type packed -TU_ATTR_PACKED_BEGIN -TU_ATTR_BIT_FIELD_ORDER_BEGIN - -/// Header Functional Descriptor (Communication Interface) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUNC_DESC_ - uint16_t bcdCDC ; ///< CDC release number in Binary-Coded Decimal -}cdc_desc_func_header_t; - -/// Union Functional Descriptor (Communication Interface) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ - uint8_t bControlInterface ; ///< Interface number of Communication Interface - uint8_t bSubordinateInterface ; ///< Array of Interface number of Data Interface -}cdc_desc_func_union_t; - -#define cdc_desc_func_union_n_t(no_slave)\ - struct TU_ATTR_PACKED { \ - uint8_t bLength ;\ - uint8_t bDescriptorType ;\ - uint8_t bDescriptorSubType ;\ - uint8_t bControlInterface ;\ - uint8_t bSubordinateInterface[no_slave] ;\ -} - -/// Country Selection Functional Descriptor (Communication Interface) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ - uint8_t iCountryCodeRelDate ; ///< Index of a string giving the release date for the implemented ISO 3166 Country Codes. - uint16_t wCountryCode ; ///< Country code in the format as defined in [ISO3166], release date as specified inoffset 3 for the first supported country. -}cdc_desc_func_country_selection_t; - -#define cdc_desc_func_country_selection_n_t(no_country) \ - struct TU_ATTR_PACKED { \ - uint8_t bLength ;\ - uint8_t bDescriptorType ;\ - uint8_t bDescriptorSubType ;\ - uint8_t iCountryCodeRelDate ;\ - uint16_t wCountryCode[no_country] ;\ -} - -//--------------------------------------------------------------------+ -// PUBLIC SWITCHED TELEPHONE NETWORK (PSTN) SUBCLASS -//--------------------------------------------------------------------+ - -/// \brief Call Management Functional Descriptor -/// \details This functional descriptor describes the processing of calls for the Communications Class interface. -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ - - struct { - uint8_t handle_call : 1; ///< 0 - Device sends/receives call management information only over the Communications Class interface. 1 - Device can send/receive call management information over a Data Class interface. - uint8_t send_recv_call : 1; ///< 0 - Device does not handle call management itself. 1 - Device handles call management itself. - uint8_t TU_RESERVED : 6; - } bmCapabilities; - - uint8_t bDataInterface; -}cdc_desc_func_call_management_t; - -typedef struct TU_ATTR_PACKED -{ - uint8_t support_comm_request : 1; ///< Device supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature. - uint8_t support_line_request : 1; ///< Device supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State. - uint8_t support_send_break : 1; ///< Device supports the request Send_Break - uint8_t support_notification_network_connection : 1; ///< Device supports the notification Network_Connection. - uint8_t TU_RESERVED : 4; -}cdc_acm_capability_t; - -TU_VERIFY_STATIC(sizeof(cdc_acm_capability_t) == 1, "mostly problem with compiler"); - -/// Abstract Control Management Functional Descriptor -/// This functional descriptor describes the commands supported by by the Communications Class interface with SubClass code of \ref CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ - cdc_acm_capability_t bmCapabilities ; -}cdc_desc_func_acm_t; - -/// \brief Direct Line Management Functional Descriptor -/// \details This functional descriptor describes the commands supported by the Communications Class interface with SubClass code of \ref CDC_FUNC_DESC_DIRECT_LINE_MANAGEMENT -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ - struct { - uint8_t require_pulse_setup : 1; ///< Device requires extra Pulse_Setup request during pulse dialing sequence to disengage holding circuit. - uint8_t support_aux_request : 1; ///< Device supports the request combination of Set_Aux_Line_State, Ring_Aux_Jack, and notification Aux_Jack_Hook_State. - uint8_t support_pulse_request : 1; ///< Device supports the request combination of Pulse_Setup, Send_Pulse, and Set_Pulse_Time. - uint8_t TU_RESERVED : 5; - } bmCapabilities; -}cdc_desc_func_direct_line_management_t; - -/// \brief Telephone Ringer Functional Descriptor -/// \details The Telephone Ringer functional descriptor describes the ringer capabilities supported by the Communications Class interface, -/// with the SubClass code of \ref CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ - uint8_t bRingerVolSteps ; - uint8_t bNumRingerPatterns ; -}cdc_desc_func_telephone_ringer_t; - -/// \brief Telephone Operational Modes Functional Descriptor -/// \details The Telephone Operational Modes functional descriptor describes the operational modes supported by -/// the Communications Class interface, with the SubClass code of \ref CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ - struct { - uint8_t simple_mode : 1; - uint8_t standalone_mode : 1; - uint8_t computer_centric_mode : 1; - uint8_t TU_RESERVED : 5; - } bmCapabilities; -}cdc_desc_func_telephone_operational_modes_t; - -/// \brief Telephone Call and Line State Reporting Capabilities Descriptor -/// \details The Telephone Call and Line State Reporting Capabilities functional descriptor describes the abilities of a -/// telephone device to report optional call and line states. -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ - struct { - uint32_t interrupted_dialtone : 1; ///< 0 : Reports only dialtone (does not differentiate between normal and interrupted dialtone). 1 : Reports interrupted dialtone in addition to normal dialtone - uint32_t ringback_busy_fastbusy : 1; ///< 0 : Reports only dialing state. 1 : Reports ringback, busy, and fast busy states. - uint32_t caller_id : 1; ///< 0 : Does not report caller ID. 1 : Reports caller ID information. - uint32_t incoming_distinctive : 1; ///< 0 : Reports only incoming ringing. 1 : Reports incoming distinctive ringing patterns. - uint32_t dual_tone_multi_freq : 1; ///< 0 : Cannot report dual tone multi-frequency (DTMF) digits input remotely over the telephone line. 1 : Can report DTMF digits input remotely over the telephone line. - uint32_t line_state_change : 1; ///< 0 : Does not support line state change notification. 1 : Does support line state change notification - uint32_t TU_RESERVED0 : 2; - uint32_t TU_RESERVED1 : 16; - uint32_t TU_RESERVED2 : 8; - } bmCapabilities; -}cdc_desc_func_telephone_call_state_reporting_capabilities_t; - -// TODO remove -static inline uint8_t cdc_functional_desc_typeof(uint8_t const * p_desc) -{ - return p_desc[2]; -} - -//--------------------------------------------------------------------+ -// Requests -//--------------------------------------------------------------------+ -typedef struct TU_ATTR_PACKED -{ - uint32_t bit_rate; - uint8_t stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits - uint8_t parity; ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space - uint8_t data_bits; ///< can be 5, 6, 7, 8 or 16 -} cdc_line_coding_t; - -TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct"); - -typedef struct TU_ATTR_PACKED -{ - uint16_t dtr : 1; - uint16_t rts : 1; - uint16_t : 6; - uint16_t : 8; -} cdc_line_control_state_t; - -TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct"); - -TU_ATTR_PACKED_END // End of all packed definitions -TU_ATTR_BIT_FIELD_ORDER_END - -#ifdef __cplusplus - } -#endif - -#endif - -/** @} */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.c deleted file mode 100644 index 5adce521..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.c +++ /dev/null @@ -1,483 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_CDC) - -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "cdc_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -enum -{ - BULK_PACKET_SIZE = (TUD_OPT_HIGH_SPEED ? 512 : 64) -}; - -typedef struct -{ - uint8_t itf_num; - uint8_t ep_notif; - uint8_t ep_in; - uint8_t ep_out; - - // Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) - uint8_t line_state; - - /*------------- From this point, data is not cleared by bus reset -------------*/ - char wanted_char; - TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; - - // FIFO - tu_fifo_t rx_ff; - tu_fifo_t tx_ff; - - uint8_t rx_ff_buf[CFG_TUD_CDC_RX_BUFSIZE]; - uint8_t tx_ff_buf[CFG_TUD_CDC_TX_BUFSIZE]; - - OSAL_MUTEX_DEF(rx_ff_mutex); - OSAL_MUTEX_DEF(tx_ff_mutex); - - // Endpoint Transfer buffer - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EP_BUFSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CDC_EP_BUFSIZE]; - -}cdcd_interface_t; - -#define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, wanted_char) - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION tu_static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; - -static bool _prep_out_transaction (cdcd_interface_t* p_cdc) -{ - uint8_t const rhport = 0; - uint16_t available = tu_fifo_remaining(&p_cdc->rx_ff); - - // Prepare for incoming data but only allow what we can store in the ring buffer. - // TODO Actually we can still carry out the transfer, keeping count of received bytes - // and slowly move it to the FIFO when read(). - // This pre-check reduces endpoint claiming - TU_VERIFY(available >= sizeof(p_cdc->epout_buf)); - - // claim endpoint - TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_out)); - - // fifo can be changed before endpoint is claimed - available = tu_fifo_remaining(&p_cdc->rx_ff); - - if ( available >= sizeof(p_cdc->epout_buf) ) - { - return usbd_edpt_xfer(rhport, p_cdc->ep_out, p_cdc->epout_buf, sizeof(p_cdc->epout_buf)); - }else - { - // Release endpoint since we don't make any transfer - usbd_edpt_release(rhport, p_cdc->ep_out); - - return false; - } -} - -//--------------------------------------------------------------------+ -// APPLICATION API -//--------------------------------------------------------------------+ -bool tud_cdc_n_connected(uint8_t itf) -{ - // DTR (bit 0) active is considered as connected - return tud_ready() && tu_bit_test(_cdcd_itf[itf].line_state, 0); -} - -uint8_t tud_cdc_n_get_line_state (uint8_t itf) -{ - return _cdcd_itf[itf].line_state; -} - -void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding) -{ - (*coding) = _cdcd_itf[itf].line_coding; -} - -void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted) -{ - _cdcd_itf[itf].wanted_char = wanted; -} - - -//--------------------------------------------------------------------+ -// READ API -//--------------------------------------------------------------------+ -uint32_t tud_cdc_n_available(uint8_t itf) -{ - return tu_fifo_count(&_cdcd_itf[itf].rx_ff); -} - -uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize) -{ - cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; - uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, (uint16_t) bufsize); - _prep_out_transaction(p_cdc); - return num_read; -} - -bool tud_cdc_n_peek(uint8_t itf, uint8_t* chr) -{ - return tu_fifo_peek(&_cdcd_itf[itf].rx_ff, chr); -} - -void tud_cdc_n_read_flush (uint8_t itf) -{ - cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; - tu_fifo_clear(&p_cdc->rx_ff); - _prep_out_transaction(p_cdc); -} - -//--------------------------------------------------------------------+ -// WRITE API -//--------------------------------------------------------------------+ -uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) -{ - cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; - uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) bufsize); - - // flush if queue more than packet size - // may need to suppress -Wunreachable-code since most of the time CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE - if ( (tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE) || ((CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE) && tu_fifo_full(&p_cdc->tx_ff)) ) - { - tud_cdc_n_write_flush(itf); - } - - return ret; -} - -uint32_t tud_cdc_n_write_flush (uint8_t itf) -{ - cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; - - // Skip if usb is not ready yet - TU_VERIFY( tud_ready(), 0 ); - - // No data to send - if ( !tu_fifo_count(&p_cdc->tx_ff) ) return 0; - - uint8_t const rhport = 0; - - // Claim the endpoint - TU_VERIFY( usbd_edpt_claim(rhport, p_cdc->ep_in), 0 ); - - // Pull data from FIFO - uint16_t const count = tu_fifo_read_n(&p_cdc->tx_ff, p_cdc->epin_buf, sizeof(p_cdc->epin_buf)); - - if ( count ) - { - TU_ASSERT( usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 ); - return count; - }else - { - // Release endpoint since we don't make any transfer - // Note: data is dropped if terminal is not connected - usbd_edpt_release(rhport, p_cdc->ep_in); - return 0; - } -} - -uint32_t tud_cdc_n_write_available (uint8_t itf) -{ - return tu_fifo_remaining(&_cdcd_itf[itf].tx_ff); -} - -bool tud_cdc_n_write_clear (uint8_t itf) -{ - return tu_fifo_clear(&_cdcd_itf[itf].tx_ff); -} - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void cdcd_init(void) -{ - tu_memclr(_cdcd_itf, sizeof(_cdcd_itf)); - - for(uint8_t i=0; iwanted_char = (char) -1; - - // default line coding is : stop bit = 1, parity = none, data bits = 8 - p_cdc->line_coding.bit_rate = 115200; - p_cdc->line_coding.stop_bits = 0; - p_cdc->line_coding.parity = 0; - p_cdc->line_coding.data_bits = 8; - - // Config RX fifo - tu_fifo_config(&p_cdc->rx_ff, p_cdc->rx_ff_buf, TU_ARRAY_SIZE(p_cdc->rx_ff_buf), 1, false); - - // Config TX fifo as overwritable at initialization and will be changed to non-overwritable - // if terminal supports DTR bit. Without DTR we do not know if data is actually polled by terminal. - // In this way, the most current data is prioritized. - tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, true); - - tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, osal_mutex_create(&p_cdc->rx_ff_mutex)); - tu_fifo_config_mutex(&p_cdc->tx_ff, osal_mutex_create(&p_cdc->tx_ff_mutex), NULL); - } -} - -void cdcd_reset(uint8_t rhport) -{ - (void) rhport; - - for(uint8_t i=0; irx_ff); - tu_fifo_clear(&p_cdc->tx_ff); - tu_fifo_set_overwritable(&p_cdc->tx_ff, true); - } -} - -uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ - // Only support ACM subclass - TU_VERIFY( TUSB_CLASS_CDC == itf_desc->bInterfaceClass && - CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass, 0); - - // Find available interface - cdcd_interface_t * p_cdc = NULL; - for(uint8_t cdc_id=0; cdc_iditf_num = itf_desc->bInterfaceNumber; - - uint16_t drv_len = sizeof(tusb_desc_interface_t); - uint8_t const * p_desc = tu_desc_next( itf_desc ); - - // Communication Functional Descriptors - while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) - { - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) - { - // notification endpoint - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; - - TU_ASSERT( usbd_edpt_open(rhport, desc_ep), 0 ); - p_cdc->ep_notif = desc_ep->bEndpointAddress; - - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - //------------- Data Interface (if any) -------------// - if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && - (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) - { - // next to endpoint descriptor - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - - // Open endpoint pair - TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in), 0 ); - - drv_len += 2*sizeof(tusb_desc_endpoint_t); - } - - // Prepare for incoming data - _prep_out_transaction(p_cdc); - - return drv_len; -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - // Handle class request only - TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); - - uint8_t itf = 0; - cdcd_interface_t* p_cdc = _cdcd_itf; - - // Identify which interface to use - for ( ; ; itf++, p_cdc++) - { - if (itf >= TU_ARRAY_SIZE(_cdcd_itf)) return false; - - if ( p_cdc->itf_num == request->wIndex ) break; - } - - switch ( request->bRequest ) - { - case CDC_REQUEST_SET_LINE_CODING: - if (stage == CONTROL_STAGE_SETUP) - { - TU_LOG2(" Set Line Coding\r\n"); - tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); - } - else if ( stage == CONTROL_STAGE_ACK) - { - if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding); - } - break; - - case CDC_REQUEST_GET_LINE_CODING: - if (stage == CONTROL_STAGE_SETUP) - { - TU_LOG2(" Get Line Coding\r\n"); - tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); - } - break; - - case CDC_REQUEST_SET_CONTROL_LINE_STATE: - if (stage == CONTROL_STAGE_SETUP) - { - tud_control_status(rhport, request); - } - else if (stage == CONTROL_STAGE_ACK) - { - // CDC PSTN v1.2 section 6.3.12 - // Bit 0: Indicates if DTE is present or not. - // This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR (Data Terminal Ready) - // Bit 1: Carrier control for half-duplex modems. - // This signal corresponds to V.24 signal 105 and RS-232 signal RTS (Request to Send) - bool const dtr = tu_bit_test(request->wValue, 0); - bool const rts = tu_bit_test(request->wValue, 1); - - p_cdc->line_state = (uint8_t) request->wValue; - - // Disable fifo overwriting if DTR bit is set - tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr); - - TU_LOG2(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); - - // Invoke callback - if ( tud_cdc_line_state_cb ) tud_cdc_line_state_cb(itf, dtr, rts); - } - break; - case CDC_REQUEST_SEND_BREAK: - if (stage == CONTROL_STAGE_SETUP) - { - tud_control_status(rhport, request); - } - else if (stage == CONTROL_STAGE_ACK) - { - TU_LOG2(" Send Break\r\n"); - if ( tud_cdc_send_break_cb ) tud_cdc_send_break_cb(itf, request->wValue); - } - break; - - default: return false; // stall unsupported request - } - - return true; -} - -bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void) result; - - uint8_t itf; - cdcd_interface_t* p_cdc; - - // Identify which interface to use - for (itf = 0; itf < CFG_TUD_CDC; itf++) - { - p_cdc = &_cdcd_itf[itf]; - if ( ( ep_addr == p_cdc->ep_out ) || ( ep_addr == p_cdc->ep_in ) ) break; - } - TU_ASSERT(itf < CFG_TUD_CDC); - - // Received new data - if ( ep_addr == p_cdc->ep_out ) - { - tu_fifo_write_n(&p_cdc->rx_ff, p_cdc->epout_buf, (uint16_t) xferred_bytes); - - // Check for wanted char and invoke callback if needed - if ( tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1) ) - { - for ( uint32_t i = 0; i < xferred_bytes; i++ ) - { - if ( (p_cdc->wanted_char == p_cdc->epout_buf[i]) && !tu_fifo_empty(&p_cdc->rx_ff) ) - { - tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char); - } - } - } - - // invoke receive callback (if there is still data) - if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf); - - // prepare for OUT transaction - _prep_out_transaction(p_cdc); - } - - // Data sent to host, we continue to fetch from tx fifo to send. - // Note: This will cause incorrect baudrate set in line coding. - // Though maybe the baudrate is not really important !!! - if ( ep_addr == p_cdc->ep_in ) - { - // invoke transmit callback to possibly refill tx fifo - if ( tud_cdc_tx_complete_cb ) tud_cdc_tx_complete_cb(itf); - - if ( 0 == tud_cdc_n_write_flush(itf) ) - { - // If there is no data left, a ZLP should be sent if - // xferred_bytes is multiple of EP Packet size and not zero - if ( !tu_fifo_count(&p_cdc->tx_ff) && xferred_bytes && (0 == (xferred_bytes & (BULK_PACKET_SIZE-1))) ) - { - if ( usbd_edpt_claim(rhport, p_cdc->ep_in) ) - { - usbd_edpt_xfer(rhport, p_cdc->ep_in, NULL, 0); - } - } - } - } - - // nothing to do with notif endpoint for now - - return true; -} - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.h deleted file mode 100644 index a6e07aa5..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_device.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_CDC_DEVICE_H_ -#define _TUSB_CDC_DEVICE_H_ - -#include "cdc.h" - -//--------------------------------------------------------------------+ -// Class Driver Configuration -//--------------------------------------------------------------------+ -#if !defined(CFG_TUD_CDC_EP_BUFSIZE) && defined(CFG_TUD_CDC_EPSIZE) - #warning CFG_TUD_CDC_EPSIZE is renamed to CFG_TUD_CDC_EP_BUFSIZE, please update to use the new name - #define CFG_TUD_CDC_EP_BUFSIZE CFG_TUD_CDC_EPSIZE -#endif - -#ifndef CFG_TUD_CDC_EP_BUFSIZE - #define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) -#endif - -#ifdef __cplusplus - extern "C" { -#endif - -/** \addtogroup CDC_Serial Serial - * @{ - * \defgroup CDC_Serial_Device Device - * @{ */ - -//--------------------------------------------------------------------+ -// Application API (Multiple Ports) -// CFG_TUD_CDC > 1 -//--------------------------------------------------------------------+ - -// Check if terminal is connected to this port -bool tud_cdc_n_connected (uint8_t itf); - -// Get current line state. Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) -uint8_t tud_cdc_n_get_line_state (uint8_t itf); - -// Get current line encoding: bit rate, stop bits parity etc .. -void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding); - -// Set special character that will trigger tud_cdc_rx_wanted_cb() callback on receiving -void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted); - -// Get the number of bytes available for reading -uint32_t tud_cdc_n_available (uint8_t itf); - -// Read received bytes -uint32_t tud_cdc_n_read (uint8_t itf, void* buffer, uint32_t bufsize); - -// Read a byte, return -1 if there is none -static inline -int32_t tud_cdc_n_read_char (uint8_t itf); - -// Clear the received FIFO -void tud_cdc_n_read_flush (uint8_t itf); - -// Get a byte from FIFO without removing it -bool tud_cdc_n_peek (uint8_t itf, uint8_t* ui8); - -// Write bytes to TX FIFO, data may remain in the FIFO for a while -uint32_t tud_cdc_n_write (uint8_t itf, void const* buffer, uint32_t bufsize); - -// Write a byte -static inline -uint32_t tud_cdc_n_write_char (uint8_t itf, char ch); - -// Write a null-terminated string -static inline -uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str); - -// Force sending data if possible, return number of forced bytes -uint32_t tud_cdc_n_write_flush (uint8_t itf); - -// Return the number of bytes (characters) available for writing to TX FIFO buffer in a single n_write operation. -uint32_t tud_cdc_n_write_available (uint8_t itf); - -// Clear the transmit FIFO -bool tud_cdc_n_write_clear (uint8_t itf); - -//--------------------------------------------------------------------+ -// Application API (Single Port) -//--------------------------------------------------------------------+ -static inline bool tud_cdc_connected (void); -static inline uint8_t tud_cdc_get_line_state (void); -static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding); -static inline void tud_cdc_set_wanted_char (char wanted); - -static inline uint32_t tud_cdc_available (void); -static inline int32_t tud_cdc_read_char (void); -static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize); -static inline void tud_cdc_read_flush (void); -static inline bool tud_cdc_peek (uint8_t* ui8); - -static inline uint32_t tud_cdc_write_char (char ch); -static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize); -static inline uint32_t tud_cdc_write_str (char const* str); -static inline uint32_t tud_cdc_write_flush (void); -static inline uint32_t tud_cdc_write_available (void); -static inline bool tud_cdc_write_clear (void); - -//--------------------------------------------------------------------+ -// Application Callback API (weak is optional) -//--------------------------------------------------------------------+ - -// Invoked when received new data -TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf); - -// Invoked when received `wanted_char` -TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char); - -// Invoked when a TX is complete and therefore space becomes available in TX buffer -TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf); - -// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE -TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts); - -// Invoked when line coding is change via SET_LINE_CODING -TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding); - -// Invoked when received send break -TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms); - -//--------------------------------------------------------------------+ -// Inline Functions -//--------------------------------------------------------------------+ -static inline int32_t tud_cdc_n_read_char (uint8_t itf) -{ - uint8_t ch; - return tud_cdc_n_read(itf, &ch, 1) ? (int32_t) ch : -1; -} - -static inline uint32_t tud_cdc_n_write_char(uint8_t itf, char ch) -{ - return tud_cdc_n_write(itf, &ch, 1); -} - -static inline uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str) -{ - return tud_cdc_n_write(itf, str, strlen(str)); -} - -static inline bool tud_cdc_connected (void) -{ - return tud_cdc_n_connected(0); -} - -static inline uint8_t tud_cdc_get_line_state (void) -{ - return tud_cdc_n_get_line_state(0); -} - -static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding) -{ - tud_cdc_n_get_line_coding(0, coding); -} - -static inline void tud_cdc_set_wanted_char (char wanted) -{ - tud_cdc_n_set_wanted_char(0, wanted); -} - -static inline uint32_t tud_cdc_available (void) -{ - return tud_cdc_n_available(0); -} - -static inline int32_t tud_cdc_read_char (void) -{ - return tud_cdc_n_read_char(0); -} - -static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize) -{ - return tud_cdc_n_read(0, buffer, bufsize); -} - -static inline void tud_cdc_read_flush (void) -{ - tud_cdc_n_read_flush(0); -} - -static inline bool tud_cdc_peek (uint8_t* ui8) -{ - return tud_cdc_n_peek(0, ui8); -} - -static inline uint32_t tud_cdc_write_char (char ch) -{ - return tud_cdc_n_write_char(0, ch); -} - -static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize) -{ - return tud_cdc_n_write(0, buffer, bufsize); -} - -static inline uint32_t tud_cdc_write_str (char const* str) -{ - return tud_cdc_n_write_str(0, str); -} - -static inline uint32_t tud_cdc_write_flush (void) -{ - return tud_cdc_n_write_flush(0); -} - -static inline uint32_t tud_cdc_write_available(void) -{ - return tud_cdc_n_write_available(0); -} - -static inline bool tud_cdc_write_clear(void) -{ - return tud_cdc_n_write_clear(0); -} - -/** @} */ -/** @} */ - -//--------------------------------------------------------------------+ -// INTERNAL USBD-CLASS DRIVER API -//--------------------------------------------------------------------+ -void cdcd_init (void); -void cdcd_reset (uint8_t rhport); -uint16_t cdcd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool cdcd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -bool cdcd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_CDC_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.c b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.c deleted file mode 100644 index fe3691bf..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.c +++ /dev/null @@ -1,1177 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUH_ENABLED && CFG_TUH_CDC) - -#include "host/usbh.h" -#include "host/usbh_classdriver.h" - -#include "cdc_host.h" - -// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message -#define CDCH_DEBUG 2 - -#define TU_LOG_CDCH(...) TU_LOG(CDCH_DEBUG, __VA_ARGS__) - -//--------------------------------------------------------------------+ -// Host CDC Interface -//--------------------------------------------------------------------+ - -typedef struct { - uint8_t daddr; - uint8_t bInterfaceNumber; - uint8_t bInterfaceSubClass; - uint8_t bInterfaceProtocol; - - uint8_t serial_drid; // Serial Driver ID - cdc_acm_capability_t acm_capability; - uint8_t ep_notif; - - uint8_t line_state; // DTR (bit0), RTS (bit1) - TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width - - tuh_xfer_cb_t user_control_cb; - - struct { - tu_edpt_stream_t tx; - tu_edpt_stream_t rx; - - uint8_t tx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; - CFG_TUH_MEM_ALIGN uint8_t tx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; - - uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; - CFG_TUH_MEM_ALIGN uint8_t rx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; - } stream; - -} cdch_interface_t; - -CFG_TUH_MEM_SECTION -static cdch_interface_t cdch_data[CFG_TUH_CDC]; - -//--------------------------------------------------------------------+ -// Serial Driver -//--------------------------------------------------------------------+ - -//------------- ACM prototypes -------------// -static void acm_process_config(tuh_xfer_t* xfer); - -static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - -//------------- FTDI prototypes -------------// -#if CFG_TUH_CDC_FTDI -#include "serial/ftdi_sio.h" - -static uint16_t const ftdi_pids[] = { TU_FTDI_PID_LIST }; -enum { - FTDI_PID_COUNT = sizeof(ftdi_pids) / sizeof(ftdi_pids[0]) -}; - -// Store last request baudrate since divisor to baudrate is not easy -static uint32_t _ftdi_requested_baud; - -static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); -static void ftdi_process_config(tuh_xfer_t* xfer); - -static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -#endif - -//------------- CP210X prototypes -------------// -#if CFG_TUH_CDC_CP210X -#include "serial/cp210x.h" - -static uint16_t const cp210x_pids[] = { TU_CP210X_PID_LIST }; -enum { - CP210X_PID_COUNT = sizeof(cp210x_pids) / sizeof(cp210x_pids[0]) -}; - -static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); -static void cp210x_process_config(tuh_xfer_t* xfer); - -static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -#endif - -enum { - SERIAL_DRIVER_ACM = 0, - -#if CFG_TUH_CDC_FTDI - SERIAL_DRIVER_FTDI, -#endif - -#if CFG_TUH_CDC_CP210X - SERIAL_DRIVER_CP210X, -#endif -}; - -typedef struct { - void (*const process_set_config)(tuh_xfer_t* xfer); - bool (*const set_control_line_state)(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - bool (*const set_baudrate)(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -} cdch_serial_driver_t; - -// Note driver list must be in the same order as SERIAL_DRIVER enum -static const cdch_serial_driver_t serial_drivers[] = { - { .process_set_config = acm_process_config, - .set_control_line_state = acm_set_control_line_state, - .set_baudrate = acm_set_baudrate - }, - - #if CFG_TUH_CDC_FTDI - { .process_set_config = ftdi_process_config, - .set_control_line_state = ftdi_sio_set_modem_ctrl, - .set_baudrate = ftdi_sio_set_baudrate - }, - #endif - - #if CFG_TUH_CDC_CP210X - { .process_set_config = cp210x_process_config, - .set_control_line_state = cp210x_set_modem_ctrl, - .set_baudrate = cp210x_set_baudrate - }, - #endif -}; - -enum { - SERIAL_DRIVER_COUNT = sizeof(serial_drivers) / sizeof(serial_drivers[0]) -}; - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ - -static inline cdch_interface_t* get_itf(uint8_t idx) -{ - TU_ASSERT(idx < CFG_TUH_CDC, NULL); - cdch_interface_t* p_cdc = &cdch_data[idx]; - - return (p_cdc->daddr != 0) ? p_cdc : NULL; -} - -static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) -{ - for(uint8_t i=0; idaddr == daddr) && - (ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr)) - { - return i; - } - } - - return TUSB_INDEX_INVALID_8; -} - - -static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const *itf_desc) -{ - for(uint8_t i=0; idaddr = daddr; - p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber; - p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; - p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol; - p_cdc->line_state = 0; - return p_cdc; - } - } - - return NULL; -} - -static bool open_ep_stream_pair(cdch_interface_t* p_cdc , tusb_desc_endpoint_t const *desc_ep); -static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num); -static void cdch_internal_control_complete(tuh_xfer_t* xfer); - -//--------------------------------------------------------------------+ -// APPLICATION API -//--------------------------------------------------------------------+ - -uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num) -{ - for(uint8_t i=0; idaddr == daddr && p_cdc->bInterfaceNumber == itf_num) return i; - } - - return TUSB_INDEX_INVALID_8; -} - -bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) -{ - cdch_interface_t* p_cdc = get_itf(idx); - TU_VERIFY(p_cdc && info); - - info->daddr = p_cdc->daddr; - - // re-construct descriptor - tusb_desc_interface_t* desc = &info->desc; - desc->bLength = sizeof(tusb_desc_interface_t); - desc->bDescriptorType = TUSB_DESC_INTERFACE; - - desc->bInterfaceNumber = p_cdc->bInterfaceNumber; - desc->bAlternateSetting = 0; - desc->bNumEndpoints = 2u + (p_cdc->ep_notif ? 1u : 0u); - desc->bInterfaceClass = TUSB_CLASS_CDC; - desc->bInterfaceSubClass = p_cdc->bInterfaceSubClass; - desc->bInterfaceProtocol = p_cdc->bInterfaceProtocol; - desc->iInterface = 0; // not used yet - - return true; -} - -bool tuh_cdc_mounted(uint8_t idx) -{ - cdch_interface_t* p_cdc = get_itf(idx); - return p_cdc != NULL; -} - -bool tuh_cdc_get_dtr(uint8_t idx) -{ - cdch_interface_t* p_cdc = get_itf(idx); - TU_VERIFY(p_cdc); - - return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR) ? true : false; -} - -bool tuh_cdc_get_rts(uint8_t idx) -{ - cdch_interface_t* p_cdc = get_itf(idx); - TU_VERIFY(p_cdc); - - return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS) ? true : false; -} - -bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) -{ - cdch_interface_t* p_cdc = get_itf(idx); - TU_VERIFY(p_cdc); - - *line_coding = p_cdc->line_coding; - - return true; -} - -//--------------------------------------------------------------------+ -// Write -//--------------------------------------------------------------------+ - -uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) -{ - cdch_interface_t* p_cdc = get_itf(idx); - TU_VERIFY(p_cdc); - - return tu_edpt_stream_write(&p_cdc->stream.tx, buffer, bufsize); -} - -uint32_t tuh_cdc_write_flush(uint8_t idx) -{ - cdch_interface_t* p_cdc = get_itf(idx); - TU_VERIFY(p_cdc); - - return tu_edpt_stream_write_xfer(&p_cdc->stream.tx); -} - -bool tuh_cdc_write_clear(uint8_t idx) -{ - cdch_interface_t* p_cdc = get_itf(idx); - TU_VERIFY(p_cdc); - - return tu_edpt_stream_clear(&p_cdc->stream.tx); -} - -uint32_t tuh_cdc_write_available(uint8_t idx) -{ - cdch_interface_t* p_cdc = get_itf(idx); - TU_VERIFY(p_cdc); - - return tu_edpt_stream_write_available(&p_cdc->stream.tx); -} - -//--------------------------------------------------------------------+ -// Read -//--------------------------------------------------------------------+ - -uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) -{ - cdch_interface_t* p_cdc = get_itf(idx); - TU_VERIFY(p_cdc); - - return tu_edpt_stream_read(&p_cdc->stream.rx, buffer, bufsize); -} - -uint32_t tuh_cdc_read_available(uint8_t idx) -{ - cdch_interface_t* p_cdc = get_itf(idx); - TU_VERIFY(p_cdc); - - return tu_edpt_stream_read_available(&p_cdc->stream.rx); -} - -bool tuh_cdc_peek(uint8_t idx, uint8_t* ch) -{ - cdch_interface_t* p_cdc = get_itf(idx); - TU_VERIFY(p_cdc); - - return tu_edpt_stream_peek(&p_cdc->stream.rx, ch); -} - -bool tuh_cdc_read_clear (uint8_t idx) -{ - cdch_interface_t* p_cdc = get_itf(idx); - TU_VERIFY(p_cdc); - - bool ret = tu_edpt_stream_clear(&p_cdc->stream.rx); - tu_edpt_stream_read_xfer(&p_cdc->stream.rx); - return ret; -} - -//--------------------------------------------------------------------+ -// Control Endpoint API -//--------------------------------------------------------------------+ - -// internal control complete to update state such as line state, encoding -static void cdch_internal_control_complete(tuh_xfer_t* xfer) -{ - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t* p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); - - if (xfer->result == XFER_RESULT_SUCCESS) - { - switch (p_cdc->serial_drid) { - case SERIAL_DRIVER_ACM: - switch (xfer->setup->bRequest) { - case CDC_REQUEST_SET_CONTROL_LINE_STATE: - p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); - break; - - case CDC_REQUEST_SET_LINE_CODING: { - uint16_t const len = tu_min16(sizeof(cdc_line_coding_t), tu_le16toh(xfer->setup->wLength)); - memcpy(&p_cdc->line_coding, xfer->buffer, len); - } - break; - - default: break; - } - break; - - #if CFG_TUH_CDC_FTDI - case SERIAL_DRIVER_FTDI: - switch (xfer->setup->bRequest) { - case FTDI_SIO_MODEM_CTRL: - p_cdc->line_state = (uint8_t) (tu_le16toh(xfer->setup->wValue) & 0x00ff); - break; - - case FTDI_SIO_SET_BAUD_RATE: - // convert from divisor to baudrate is not supported - p_cdc->line_coding.bit_rate = _ftdi_requested_baud; - break; - - default: break; - } - break; - #endif - - #if CFG_TUH_CDC_CP210X - case SERIAL_DRIVER_CP210X: - switch(xfer->setup->bRequest) { - case CP210X_SET_MHS: - p_cdc->line_state = (uint8_t) (tu_le16toh(xfer->setup->wValue) & 0x00ff); - break; - - case CP210X_SET_BAUDRATE: { - uint32_t baudrate; - memcpy(&baudrate, xfer->buffer, sizeof(uint32_t)); - p_cdc->line_coding.bit_rate = tu_le32toh(baudrate); - } - break; - } - break; - #endif - - default: break; - } - } - - xfer->complete_cb = p_cdc->user_control_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); - } -} - -bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - cdch_interface_t* p_cdc = get_itf(idx); - TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; - - if ( complete_cb ) { - return driver->set_control_line_state(p_cdc, line_state, complete_cb, user_data); - }else { - // blocking - xfer_result_t result = XFER_RESULT_INVALID; - bool ret = driver->set_control_line_state(p_cdc, line_state, complete_cb, (uintptr_t) &result); - - if (user_data) { - // user_data is not NULL, return result via user_data - *((xfer_result_t*) user_data) = result; - } - - TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); - - p_cdc->line_state = (uint8_t) line_state; - return true; - } -} - -bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - cdch_interface_t* p_cdc = get_itf(idx); - TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; - - if ( complete_cb ) { - return driver->set_baudrate(p_cdc, baudrate, complete_cb, user_data); - }else { - // blocking - xfer_result_t result = XFER_RESULT_INVALID; - bool ret = driver->set_baudrate(p_cdc, baudrate, complete_cb, (uintptr_t) &result); - - if (user_data) { - // user_data is not NULL, return result via user_data - *((xfer_result_t*) user_data) = result; - } - - TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); - - p_cdc->line_coding.bit_rate = baudrate; - return true; - } -} - -bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - cdch_interface_t* p_cdc = get_itf(idx); - // only ACM support this set line coding request - TU_VERIFY(p_cdc && p_cdc->serial_drid == SERIAL_DRIVER_ACM); - TU_VERIFY(p_cdc->acm_capability.support_line_request); - - if ( complete_cb ) { - return acm_set_line_coding(p_cdc, line_coding, complete_cb, user_data); - }else { - // blocking - xfer_result_t result = XFER_RESULT_INVALID; - bool ret = acm_set_line_coding(p_cdc, line_coding, complete_cb, (uintptr_t) &result); - - if (user_data) { - // user_data is not NULL, return result via user_data - *((xfer_result_t*) user_data) = result; - } - - TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); - - p_cdc->line_coding = *line_coding; - return true; - } -} - -//--------------------------------------------------------------------+ -// CLASS-USBH API -//--------------------------------------------------------------------+ - -void cdch_init(void) -{ - tu_memclr(cdch_data, sizeof(cdch_data)); - - for(size_t i=0; istream.tx, true, true, false, - p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, - p_cdc->stream.tx_ep_buf, CFG_TUH_CDC_TX_EPSIZE); - - tu_edpt_stream_init(&p_cdc->stream.rx, true, false, false, - p_cdc->stream.rx_ff_buf, CFG_TUH_CDC_RX_BUFSIZE, - p_cdc->stream.rx_ep_buf, CFG_TUH_CDC_RX_EPSIZE); - } -} - -void cdch_close(uint8_t daddr) -{ - for(uint8_t idx=0; idxdaddr == daddr) - { - // Invoke application callback - if (tuh_cdc_umount_cb) tuh_cdc_umount_cb(idx); - - //tu_memclr(p_cdc, sizeof(cdch_interface_t)); - p_cdc->daddr = 0; - p_cdc->bInterfaceNumber = 0; - tu_edpt_stream_close(&p_cdc->stream.tx); - tu_edpt_stream_close(&p_cdc->stream.rx); - } - } -} - -bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) -{ - // TODO handle stall response, retry failed transfer ... - TU_ASSERT(event == XFER_RESULT_SUCCESS); - - uint8_t const idx = get_idx_by_ep_addr(daddr, ep_addr); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc); - - if ( ep_addr == p_cdc->stream.tx.ep_addr ) - { - // invoke tx complete callback to possibly refill tx fifo - if (tuh_cdc_tx_complete_cb) tuh_cdc_tx_complete_cb(idx); - - if ( 0 == tu_edpt_stream_write_xfer(&p_cdc->stream.tx) ) - { - // If there is no data left, a ZLP should be sent if: - // - xferred_bytes is multiple of EP Packet size and not zero - tu_edpt_stream_write_zlp_if_needed(&p_cdc->stream.tx, xferred_bytes); - } - } - else if ( ep_addr == p_cdc->stream.rx.ep_addr ) - { - tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); - - #if CFG_TUH_CDC_FTDI - // FTDI reserve 2 bytes for status - if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI) { - uint8_t status[2]; - tu_edpt_stream_read(&p_cdc->stream.rx, status, 2); - (void) status; // TODO handle status - } - #endif - - // invoke receive callback - if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(idx); - - // prepare for next transfer if needed - tu_edpt_stream_read_xfer(&p_cdc->stream.rx); - }else if ( ep_addr == p_cdc->ep_notif ) - { - // TODO handle notification endpoint - }else - { - TU_ASSERT(false); - } - - return true; -} - -//--------------------------------------------------------------------+ -// Enumeration -//--------------------------------------------------------------------+ - -static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); - -static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t const *desc_ep) -{ - for(size_t i=0; i<2; i++) - { - TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && - TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); - - TU_ASSERT(tuh_edpt_open(p_cdc->daddr, desc_ep)); - - if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) - { - tu_edpt_stream_open(&p_cdc->stream.rx, p_cdc->daddr, desc_ep); - }else - { - tu_edpt_stream_open(&p_cdc->stream.tx, p_cdc->daddr, desc_ep); - } - - desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(desc_ep); - } - - return true; -} - -bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) -{ - (void) rhport; - - // Only support ACM subclass - // Note: Protocol 0xFF can be RNDIS device - if ( TUSB_CLASS_CDC == itf_desc->bInterfaceClass && - CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) - { - return acm_open(daddr, itf_desc, max_len); - } - #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X - else if ( 0xff == itf_desc->bInterfaceClass ) - { - uint16_t vid, pid; - TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); - - #if CFG_TUH_CDC_FTDI - if (TU_FTDI_VID == vid) { - for (size_t i = 0; i < FTDI_PID_COUNT; i++) { - if (ftdi_pids[i] == pid) { - return ftdi_open(daddr, itf_desc, max_len); - } - } - } - #endif - - #if CFG_TUH_CDC_CP210X - if (TU_CP210X_VID == vid) { - for (size_t i = 0; i < CP210X_PID_COUNT; i++) { - if (cp210x_pids[i] == pid) { - return cp210x_open(daddr, itf_desc, max_len); - } - } - } - #endif - } - #endif - - return false; -} - -static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num) { - if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); - - // Prepare for incoming data - tu_edpt_stream_read_xfer(&p_cdc->stream.rx); - - // notify usbh that driver enumeration is complete - usbh_driver_set_config_complete(p_cdc->daddr, itf_num); -} - - -bool cdch_set_config(uint8_t daddr, uint8_t itf_num) -{ - tusb_control_request_t request; - request.wIndex = tu_htole16((uint16_t) itf_num); - - // fake transfer to kick-off process - tuh_xfer_t xfer; - xfer.daddr = daddr; - xfer.result = XFER_RESULT_SUCCESS; - xfer.setup = &request; - xfer.user_data = 0; // initial state - - uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - - serial_drivers[p_cdc->serial_drid].process_set_config(&xfer); - return true; -} - -//--------------------------------------------------------------------+ -// ACM -//--------------------------------------------------------------------+ - -enum { - CONFIG_ACM_SET_CONTROL_LINE_STATE = 0, - CONFIG_ACM_SET_LINE_CODING, - CONFIG_ACM_COMPLETE, -}; - -static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) -{ - uint8_t const * p_desc_end = ((uint8_t const*) itf_desc) + max_len; - - cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); - TU_VERIFY(p_cdc); - - p_cdc->serial_drid = SERIAL_DRIVER_ACM; - - //------------- Control Interface -------------// - uint8_t const * p_desc = tu_desc_next(itf_desc); - - // Communication Functional Descriptors - while( (p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc)) ) - { - if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) ) - { - // save ACM bmCapabilities - p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities; - } - - p_desc = tu_desc_next(p_desc); - } - - // Open notification endpoint of control interface if any - if (itf_desc->bNumEndpoints == 1) - { - TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)); - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; - - TU_ASSERT( tuh_edpt_open(daddr, desc_ep) ); - p_cdc->ep_notif = desc_ep->bEndpointAddress; - - p_desc = tu_desc_next(p_desc); - } - - //------------- Data Interface (if any) -------------// - if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && - (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) - { - // next to endpoint descriptor - p_desc = tu_desc_next(p_desc); - - // data endpoints expected to be in pairs - TU_ASSERT(open_ep_stream_pair(p_cdc, (tusb_desc_endpoint_t const *) p_desc)); - } - - return true; -} - -static void acm_process_config(tuh_xfer_t* xfer) -{ - uintptr_t const state = xfer->user_data; - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); - - switch(state) - { - case CONFIG_ACM_SET_CONTROL_LINE_STATE: - #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - if (p_cdc->acm_capability.support_line_request) - { - TU_ASSERT(acm_set_control_line_state(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, acm_process_config, - CONFIG_ACM_SET_LINE_CODING), ); - break; - } - #endif - TU_ATTR_FALLTHROUGH; - - case CONFIG_ACM_SET_LINE_CODING: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - if (p_cdc->acm_capability.support_line_request) - { - cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(acm_set_line_coding(p_cdc, &line_coding, acm_process_config, CONFIG_ACM_COMPLETE), ); - break; - } - #endif - TU_ATTR_FALLTHROUGH; - - case CONFIG_ACM_COMPLETE: - // itf_num+1 to account for data interface as well - set_config_complete(p_cdc, idx, itf_num+1); - break; - - default: break; - } -} - -static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->acm_capability.support_line_request); - TU_LOG_CDCH("CDC ACM Set Control Line State\r\n"); - - tusb_control_request_t const request = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, - .wValue = tu_htole16(line_state), - .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), - .wLength = 0 - }; - - p_cdc->user_control_cb = complete_cb; - - tuh_xfer_t xfer = { - .daddr = p_cdc->daddr, - .ep_addr = 0, - .setup = &request, - .buffer = NULL, - .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call - .user_data = user_data - }; - - TU_ASSERT(tuh_control_xfer(&xfer)); - return true; -} - -static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG_CDCH("CDC ACM Set Line Conding\r\n"); - - tusb_control_request_t const request = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = CDC_REQUEST_SET_LINE_CODING, - .wValue = 0, - .wIndex = tu_htole16(p_cdc->bInterfaceNumber), - .wLength = tu_htole16(sizeof(cdc_line_coding_t)) - }; - - // use usbh enum buf to hold line coding since user line_coding variable does not live long enough - uint8_t* enum_buf = usbh_get_enum_buf(); - memcpy(enum_buf, line_coding, sizeof(cdc_line_coding_t)); - - p_cdc->user_control_cb = complete_cb; - tuh_xfer_t xfer = { - .daddr = p_cdc->daddr, - .ep_addr = 0, - .setup = &request, - .buffer = enum_buf, - .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call - .user_data = user_data - }; - - TU_ASSERT(tuh_control_xfer(&xfer)); - return true; -} - -static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->acm_capability.support_line_request); - cdc_line_coding_t line_coding = p_cdc->line_coding; - line_coding.bit_rate = baudrate; - return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data); -} - -//--------------------------------------------------------------------+ -// FTDI -//--------------------------------------------------------------------+ -#if CFG_TUH_CDC_FTDI - -enum { - CONFIG_FTDI_RESET = 0, - CONFIG_FTDI_MODEM_CTRL, - CONFIG_FTDI_SET_BAUDRATE, - CONFIG_FTDI_SET_DATA, - CONFIG_FTDI_COMPLETE -}; - -static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) { - // FTDI Interface includes 1 vendor interface + 2 bulk endpoints - TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff && itf_desc->bNumEndpoints == 2); - TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); - - cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); - TU_VERIFY(p_cdc); - - TU_LOG_CDCH("FTDI opened\r\n"); - - p_cdc->serial_drid = SERIAL_DRIVER_FTDI; - - // endpoint pair - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); - - // data endpoints expected to be in pairs - return open_ep_stream_pair(p_cdc, desc_ep); -} - -// set request without data -static bool ftdi_sio_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - tusb_control_request_t const request = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_DEVICE, - .type = TUSB_REQ_TYPE_VENDOR, - .direction = TUSB_DIR_OUT - }, - .bRequest = command, - .wValue = tu_htole16(value), - .wIndex = 0, - .wLength = 0 - }; - - tuh_xfer_t xfer = { - .daddr = p_cdc->daddr, - .ep_addr = 0, - .setup = &request, - .buffer = NULL, - .complete_cb = complete_cb, - .user_data = user_data - }; - - return tuh_control_xfer(&xfer); -} - -static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data); -} - -static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - TU_LOG_CDCH("CDC FTDI Set Control Line State\r\n"); - p_cdc->user_control_cb = complete_cb; - TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | line_state, - complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; -} - -static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) -{ - const uint8_t divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; - uint32_t divisor; - - /* divisor shifted 3 bits to the left */ - uint32_t divisor3 = base / (2 * baud); - divisor = (divisor3 >> 3); - divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14; - - /* Deal with special cases for highest baud rates. */ - if (divisor == 1) { /* 1.0 */ - divisor = 0; - } - else if (divisor == 0x4001) { /* 1.5 */ - divisor = 1; - } - - return divisor; -} - -static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) -{ - return ftdi_232bm_baud_base_to_divisor(baud, 48000000u); -} - -static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate); - TU_LOG_CDCH("CDC FTDI Set BaudRate = %lu, divisor = 0x%04x\n", baudrate, divisor); - - p_cdc->user_control_cb = complete_cb; - _ftdi_requested_baud = baudrate; - TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor, - complete_cb ? cdch_internal_control_complete : NULL, user_data)); - - return true; -} - -static void ftdi_process_config(tuh_xfer_t* xfer) { - uintptr_t const state = xfer->user_data; - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); - - switch(state) { - // Note may need to read FTDI eeprom - case CONFIG_FTDI_RESET: - TU_ASSERT(ftdi_sio_reset(p_cdc, ftdi_process_config, CONFIG_FTDI_MODEM_CTRL),); - break; - - case CONFIG_FTDI_MODEM_CTRL: - #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - TU_ASSERT( - ftdi_sio_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - - case CONFIG_FTDI_SET_BAUDRATE: { - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(ftdi_sio_set_baudrate(p_cdc, line_coding.bit_rate, ftdi_process_config, CONFIG_FTDI_SET_DATA),); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - } - - case CONFIG_FTDI_SET_DATA: { - #if 0 // TODO set data format - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(ftdi_sio_set_data(p_cdc, process_ftdi_config, CONFIG_FTDI_COMPLETE),); - break; - #endif - #endif - - TU_ATTR_FALLTHROUGH; - } - - case CONFIG_FTDI_COMPLETE: - set_config_complete(p_cdc, idx, itf_num); - break; - - default: - break; - } -} - -#endif - -//--------------------------------------------------------------------+ -// CP210x -//--------------------------------------------------------------------+ - -#if CFG_TUH_CDC_CP210X - -enum { - CONFIG_CP210X_IFC_ENABLE = 0, - CONFIG_CP210X_SET_BAUDRATE, - CONFIG_CP210X_SET_LINE_CTL, - CONFIG_CP210X_SET_DTR_RTS, - CONFIG_CP210X_COMPLETE -}; - -static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { - // CP210x Interface includes 1 vendor interface + 2 bulk endpoints - TU_VERIFY(itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0 && itf_desc->bNumEndpoints == 2); - TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); - - cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); - TU_VERIFY(p_cdc); - - TU_LOG_CDCH("CP210x opened\r\n"); - p_cdc->serial_drid = SERIAL_DRIVER_CP210X; - - // endpoint pair - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); - - // data endpoints expected to be in pairs - return open_ep_stream_pair(p_cdc, desc_ep); -} - -static bool cp210x_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - tusb_control_request_t const request = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_VENDOR, - .direction = TUSB_DIR_OUT - }, - .bRequest = command, - .wValue = tu_htole16(value), - .wIndex = p_cdc->bInterfaceNumber, - .wLength = tu_htole16(length) - }; - - // use usbh enum buf since application variable does not live long enough - uint8_t* enum_buf = NULL; - - if (buffer && length > 0) { - enum_buf = usbh_get_enum_buf(); - tu_memcpy_s(enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length); - } - - tuh_xfer_t xfer = { - .daddr = p_cdc->daddr, - .ep_addr = 0, - .setup = &request, - .buffer = enum_buf, - .complete_cb = complete_cb, - .user_data = user_data - }; - - return tuh_control_xfer(&xfer); -} - -static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return cp210x_set_request(p_cdc, CP210X_IFC_ENABLE, enabled, NULL, 0, complete_cb, user_data); -} - -static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG_CDCH("CDC CP210x Set BaudRate = %lu\n", baudrate); - uint32_t baud_le = tu_htole32(baudrate); - p_cdc->user_control_cb = complete_cb; - return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, - complete_cb ? cdch_internal_control_complete : NULL, user_data); -} - -static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - TU_LOG_CDCH("CDC CP210x Set Control Line State\r\n"); - p_cdc->user_control_cb = complete_cb; - return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | line_state, NULL, 0, - complete_cb ? cdch_internal_control_complete : NULL, user_data); -} - -static void cp210x_process_config(tuh_xfer_t* xfer) { - uintptr_t const state = xfer->user_data; - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT(p_cdc,); - - switch (state) { - case CONFIG_CP210X_IFC_ENABLE: - TU_ASSERT(cp210x_ifc_enable(p_cdc, 1, cp210x_process_config, CONFIG_CP210X_SET_BAUDRATE),); - break; - - case CONFIG_CP210X_SET_BAUDRATE: { - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(cp210x_set_baudrate(p_cdc, line_coding.bit_rate, cp210x_process_config, CONFIG_CP210X_SET_LINE_CTL),); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - } - - case CONFIG_CP210X_SET_LINE_CTL: { - #if defined(CFG_TUH_CDC_LINE_CODING_ON_ENUM) && 0 // skip for now - cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - } - - case CONFIG_CP210X_SET_DTR_RTS: - #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - TU_ASSERT( - cp210x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, cp210x_process_config, CONFIG_CP210X_COMPLETE),); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - - case CONFIG_CP210X_COMPLETE: - set_config_complete(p_cdc, idx, itf_num); - break; - - default: break; - } -} - -#endif - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.h b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.h deleted file mode 100644 index 19552f1e..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_host.h +++ /dev/null @@ -1,204 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_CDC_HOST_H_ -#define _TUSB_CDC_HOST_H_ - -#include "cdc.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Class Driver Configuration -//--------------------------------------------------------------------+ - -// Set Line Control state on enumeration/mounted: DTR ( bit 0), RTS (bit 1) -#ifndef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM -#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0 -#endif - -// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t -//#ifndef CFG_TUH_CDC_LINE_CODING_ON_ENUM -//#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } -//#endif - -// RX FIFO size -#ifndef CFG_TUH_CDC_RX_BUFSIZE -#define CFG_TUH_CDC_RX_BUFSIZE USBH_EPSIZE_BULK_MAX -#endif - -// RX Endpoint size -#ifndef CFG_TUH_CDC_RX_EPSIZE -#define CFG_TUH_CDC_RX_EPSIZE USBH_EPSIZE_BULK_MAX -#endif - -// TX FIFO size -#ifndef CFG_TUH_CDC_TX_BUFSIZE -#define CFG_TUH_CDC_TX_BUFSIZE USBH_EPSIZE_BULK_MAX -#endif - -// TX Endpoint size -#ifndef CFG_TUH_CDC_TX_EPSIZE -#define CFG_TUH_CDC_TX_EPSIZE USBH_EPSIZE_BULK_MAX -#endif - -//--------------------------------------------------------------------+ -// Application API -//--------------------------------------------------------------------+ - -// Get Interface index from device address + interface number -// return TUSB_INDEX_INVALID_8 (0xFF) if not found -uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num); - -// Get Interface information -// return true if index is correct and interface is currently mounted -bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info); - -// Check if a interface is mounted -bool tuh_cdc_mounted(uint8_t idx); - -// Get current DTR status -bool tuh_cdc_get_dtr(uint8_t idx); - -// Get current RTS status -bool tuh_cdc_get_rts(uint8_t idx); - -// Check if interface is connected (DTR active) -TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) -{ - return tuh_cdc_get_dtr(idx); -} - -// Get local (saved/cached) version of line coding. -// This function should return correct values if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding() -// are invoked previously or CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined. -// NOTE: This function does not make any USB transfer request to device. -bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding); - -//--------------------------------------------------------------------+ -// Write API -//--------------------------------------------------------------------+ - -// Get the number of bytes available for writing -uint32_t tuh_cdc_write_available(uint8_t idx); - -// Write to cdc interface -uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize); - -// Force sending data if possible, return number of forced bytes -uint32_t tuh_cdc_write_flush(uint8_t idx); - -// Clear the transmit FIFO -bool tuh_cdc_write_clear(uint8_t idx); - -//--------------------------------------------------------------------+ -// Read API -//--------------------------------------------------------------------+ - -// Get the number of bytes available for reading -uint32_t tuh_cdc_read_available(uint8_t idx); - -// Read from cdc interface -uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize); - -// Get a byte from RX FIFO without removing it -bool tuh_cdc_peek(uint8_t idx, uint8_t* ch); - -// Clear the received FIFO -bool tuh_cdc_read_clear (uint8_t idx); - -//--------------------------------------------------------------------+ -// Control Endpoint (Request) API -// Each Function will make a USB control transfer request to/from device -// - If complete_cb is provided, the function will return immediately and invoke -// the callback when request is complete. -// - If complete_cb is NULL, the function will block until request is complete. -// - In this case, user_data should be pointed to xfer_result_t to hold the transfer result. -// - The function will return true if transfer is successful, false otherwise. -//--------------------------------------------------------------------+ - -// Request to Set Control Line State: DTR (bit 0), RTS (bit 1) -bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - -// Request to set baudrate -bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - -// Request to Set Line Coding (ACM only) -// Should only use if you don't work with serial devices such as FTDI/CP210x -bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - -// Request to Get Line Coding (ACM only) -// Should only use if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding() never got invoked and -// CFG_TUH_CDC_LINE_CODING_ON_ENUM is not defined -// bool tuh_cdc_get_line_coding(uint8_t idx, cdc_line_coding_t* coding); - -// Connect by set both DTR, RTS -TU_ATTR_ALWAYS_INLINE static inline -bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - return tuh_cdc_set_control_line_state(idx, CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS, complete_cb, user_data); -} - -// Disconnect by clear both DTR, RTS -TU_ATTR_ALWAYS_INLINE static inline -bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - return tuh_cdc_set_control_line_state(idx, 0x00, complete_cb, user_data); -} - -//--------------------------------------------------------------------+ -// CDC APPLICATION CALLBACKS -//--------------------------------------------------------------------+ - -// Invoked when a device with CDC interface is mounted -// idx is index of cdc interface in the internal pool. -TU_ATTR_WEAK extern void tuh_cdc_mount_cb(uint8_t idx); - -// Invoked when a device with CDC interface is unmounted -TU_ATTR_WEAK extern void tuh_cdc_umount_cb(uint8_t idx); - -// Invoked when received new data -TU_ATTR_WEAK extern void tuh_cdc_rx_cb(uint8_t idx); - -// Invoked when a TX is complete and therefore space becomes available in TX buffer -TU_ATTR_WEAK extern void tuh_cdc_tx_complete_cb(uint8_t idx); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void cdch_init (void); -bool cdch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); -bool cdch_set_config (uint8_t dev_addr, uint8_t itf_num); -bool cdch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); -void cdch_close (uint8_t dev_addr); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_CDC_HOST_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis.h b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis.h deleted file mode 100644 index ad153e0a..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis.h +++ /dev/null @@ -1,301 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -/** \ingroup ClassDriver_CDC Communication Device Class (CDC) - * \defgroup CDC_RNDIS Remote Network Driver Interface Specification (RNDIS) - * @{ - * \defgroup CDC_RNDIS_Common Common Definitions - * @{ */ - -#ifndef _TUSB_CDC_RNDIS_H_ -#define _TUSB_CDC_RNDIS_H_ - -#include "cdc.h" - -#ifdef __cplusplus - extern "C" { -#endif - -#ifdef __CC_ARM -#pragma diag_suppress 66 // Suppress Keil warnings #66-D: enumeration value is out of "int" range -#endif - -/// RNDIS Message Types -typedef enum -{ - RNDIS_MSG_PACKET = 0x00000001UL, ///< The host and device use this to send network data to one another. - - RNDIS_MSG_INITIALIZE = 0x00000002UL, ///< Sent by the host to initialize the device. - RNDIS_MSG_INITIALIZE_CMPLT = 0x80000002UL, ///< Device response to an initialize message. - - RNDIS_MSG_HALT = 0x00000003UL, ///< Sent by the host to halt the device. This does not have a response. It is optional for the device to send this message to the host. - - RNDIS_MSG_QUERY = 0x00000004UL, ///< Sent by the host to send a query OID. - RNDIS_MSG_QUERY_CMPLT = 0x80000004UL, ///< Device response to a query OID. - - RNDIS_MSG_SET = 0x00000005UL, ///< Sent by the host to send a set OID. - RNDIS_MSG_SET_CMPLT = 0x80000005UL, ///< Device response to a set OID. - - RNDIS_MSG_RESET = 0x00000006UL, ///< Sent by the host to perform a soft reset on the device. - RNDIS_MSG_RESET_CMPLT = 0x80000006UL, ///< Device response to reset message. - - RNDIS_MSG_INDICATE_STATUS = 0x00000007UL, ///< Sent by the device to indicate its status or an error when an unrecognized message is received. - - RNDIS_MSG_KEEP_ALIVE = 0x00000008UL, ///< During idle periods, sent every few seconds by the host to check that the device is still responsive. It is optional for the device to send this message to check if the host is active. - RNDIS_MSG_KEEP_ALIVE_CMPLT = 0x80000008UL ///< The device response to a keepalivemessage. The host can respond with this message to a keepalive message from the device when the device implements the optional KeepAliveTimer. -}rndis_msg_type_t; - -/// RNDIS Message Status Values -typedef enum -{ - RNDIS_STATUS_SUCCESS = 0x00000000UL, ///< Success - RNDIS_STATUS_FAILURE = 0xC0000001UL, ///< Unspecified error - RNDIS_STATUS_INVALID_DATA = 0xC0010015UL, ///< Invalid data error - RNDIS_STATUS_NOT_SUPPORTED = 0xC00000BBUL, ///< Unsupported request error - RNDIS_STATUS_MEDIA_CONNECT = 0x4001000BUL, ///< Device is connected to a network medium. - RNDIS_STATUS_MEDIA_DISCONNECT = 0x4001000CUL ///< Device is disconnected from the medium. -}rndis_msg_status_t; - -#ifdef __CC_ARM -#pragma diag_default 66 // return Keil 66 to normal severity -#endif - -//--------------------------------------------------------------------+ -// MESSAGE STRUCTURE -//--------------------------------------------------------------------+ - -//------------- Initialize -------------// -/// \brief Initialize Message -/// \details This message MUST be sent by the host to initialize the device. -typedef struct { - uint32_t type ; ///< Message type, must be \ref RNDIS_MSG_INITIALIZE - uint32_t length ; ///< Message length in bytes, must be 0x18 - uint32_t request_id ; ///< A 32-bit integer value, generated by the host, used to match the host's sent request to the response from the device. - uint32_t major_version ; ///< The major version of the RNDIS Protocol implemented by the host. - uint32_t minor_version ; ///< The minor version of the RNDIS Protocol implemented by the host - uint32_t max_xfer_size ; ///< The maximum size, in bytes, of any single bus data transfer that the host expects to receive from the device. -}rndis_msg_initialize_t; - -/// \brief Initialize Complete Message -/// \details This message MUST be sent by the device in response to an initialize message. -typedef struct { - uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_INITIALIZE_CMPLT - uint32_t length ; ///< Message length in bytes, must be 0x30 - uint32_t request_id ; ///< A 32-bit integer value from \a request_id field of the \ref rndis_msg_initialize_t to which this message is a response. - uint32_t status ; ///< The initialization status of the device, has value from \ref rndis_msg_status_t - uint32_t major_version ; ///< the highest-numbered RNDIS Protocol version supported by the device. - uint32_t minor_version ; ///< the highest-numbered RNDIS Protocol version supported by the device. - uint32_t device_flags ; ///< MUST be set to 0x000000010. Other values are reserved for future use. - uint32_t medium ; ///< is 0x00 for RNDIS_MEDIUM_802_3 - uint32_t max_packet_per_xfer ; ///< The maximum number of concatenated \ref RNDIS_MSG_PACKET messages that the device can handle in a single bus transfer to it. This value MUST be at least 1. - uint32_t max_xfer_size ; ///< The maximum size, in bytes, of any single bus data transfer that the device expects to receive from the host. - uint32_t packet_alignment_factor ; ///< The byte alignment the device expects for each RNDIS message that is part of a multimessage transfer to it. The value is specified as an exponent of 2; for example, the host uses 2{PacketAlignmentFactor} as the alignment value. - uint32_t reserved[2] ; -} rndis_msg_initialize_cmplt_t; - -//------------- Query -------------// -/// \brief Query Message -/// \details This message MUST be sent by the host to query an OID. -typedef struct { - uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_QUERY - uint32_t length ; ///< Message length in bytes, including the header and the \a oid_buffer - uint32_t request_id ; ///< A 32-bit integer value, generated by the host, used to match the host's sent request to the response from the device. - uint32_t oid ; ///< The integer value of the host operating system-defined identifier, for the parameter of the device being queried for. - uint32_t buffer_length ; ///< The length, in bytes, of the input data required for the OID query. This MUST be set to 0 when there is no input data associated with the OID. - uint32_t buffer_offset ; ///< The offset, in bytes, from the beginning of \a request_id field where the input data for the query is located in the message. This value MUST be set to 0 when there is no input data associated with the OID. - uint32_t reserved ; - uint8_t oid_buffer[] ; ///< Flexible array contains the input data supplied by the host, required for the OID query request processing by the device, as per the host NDIS specification. -} rndis_msg_query_t, rndis_msg_set_t; - -TU_VERIFY_STATIC(sizeof(rndis_msg_query_t) == 28, "Make sure flexible array member does not affect layout"); - -/// \brief Query Complete Message -/// \details This message MUST be sent by the device in response to a query OID message. -typedef struct { - uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_QUERY_CMPLT - uint32_t length ; ///< Message length in bytes, including the header and the \a oid_buffer - uint32_t request_id ; ///< A 32-bit integer value from \a request_id field of the \ref rndis_msg_query_t to which this message is a response. - uint32_t status ; ///< The status of processing for the query request, has value from \ref rndis_msg_status_t. - uint32_t buffer_length ; ///< The length, in bytes, of the data in the response to the query. This MUST be set to 0 when there is no OIDInputBuffer. - uint32_t buffer_offset ; ///< The offset, in bytes, from the beginning of \a request_id field where the response data for the query is located in the message. This MUST be set to 0 when there is no \ref oid_buffer. - uint8_t oid_buffer[] ; ///< Flexible array member contains the response data to the OID query request as specified by the host. -} rndis_msg_query_cmplt_t; - -TU_VERIFY_STATIC(sizeof(rndis_msg_query_cmplt_t) == 24, "Make sure flexible array member does not affect layout"); - -//------------- Reset -------------// -/// \brief Reset Message -/// \details This message MUST be sent by the host to perform a soft reset on the device. -typedef struct { - uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_RESET - uint32_t length ; ///< Message length in bytes, MUST be 0x06 - uint32_t reserved ; -} rndis_msg_reset_t; - -/// \brief Reset Complete Message -/// \details This message MUST be sent by the device in response to a reset message. -typedef struct { - uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_RESET_CMPLT - uint32_t length ; ///< Message length in bytes, MUST be 0x10 - uint32_t status ; ///< The status of processing for the \ref rndis_msg_reset_t, has value from \ref rndis_msg_status_t. - uint32_t addressing_reset ; ///< This field indicates whether the addressing information, which is the multicast address list or packet filter, has been lost during the reset operation. This MUST be set to 0x00000001 if the device requires that the host to resend addressing information or MUST be set to zero otherwise. -} rndis_msg_reset_cmplt_t; - -//typedef struct { -// uint32_t type; -// uint32_t length; -// uint32_t status; -// uint32_t buffer_length; -// uint32_t buffer_offset; -// uint32_t diagnostic_status; // optional -// uint32_t diagnostic_error_offset; // optional -// uint32_t status_buffer[0]; // optional -//} rndis_msg_indicate_status_t; - -/// \brief Keep Alive Message -/// \details This message MUST be sent by the host to check that device is still responsive. It is optional for the device to send this message to check if the host is active -typedef struct { - uint32_t type ; ///< Message Type - uint32_t length ; ///< Message length in bytes, MUST be 0x10 - uint32_t request_id ; -} rndis_msg_keep_alive_t, rndis_msg_halt_t; - -/// \brief Set Complete Message -/// \brief This message MUST be sent in response to a the request message -typedef struct { - uint32_t type ; ///< Message Type - uint32_t length ; ///< Message length in bytes, MUST be 0x10 - uint32_t request_id ; ///< must be the same as requesting message - uint32_t status ; ///< The status of processing for the request message request by the device to which this message is the response. -} rndis_msg_set_cmplt_t, rndis_msg_keep_alive_cmplt_t; - -/// \brief Packet Data Message -/// \brief This message MUST be used by the host and the device to send network data to one another. -typedef struct { - uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_PACKET - uint32_t length ; ///< Message length in bytes, The total length of this RNDIS message including the header, payload, and padding. - uint32_t data_offset ; ///< Specifies the offset, in bytes, from the start of this \a data_offset field of this message to the start of the data. This MUST be an integer multiple of 4. - uint32_t data_length ; ///< Specifies the number of bytes in the payload of this message. - uint32_t out_of_band_data_offet ; ///< Specifies the offset, in bytes, of the first out-of-band data record from the start of the DataOffset field in this message. MUST be an integer multiple of 4 when out-of-band data is present or set to 0 otherwise. When there are multiple out-ofband data records, each subsequent record MUST immediately follow the previous out-of-band data record. - uint32_t out_of_band_data_length ; ///< Specifies, in bytes, the total length of the out-of-band data. - uint32_t num_out_of_band_data_elements ; ///< Specifies the number of out-of-band records in this message. - uint32_t per_packet_info_offset ; ///< Specifies the offset, in bytes, of the start of per-packet-info data record from the start of the \a data_offset field in this message. MUST be an integer multiple of 4 when per-packet-info data record is present or MUST be set to 0 otherwise. When there are multiple per-packet-info data records, each subsequent record MUST immediately follow the previous record. - uint32_t per_packet_info_length ; ///< Specifies, in bytes, the total length of per-packetinformation contained in this message. - uint32_t reserved[2] ; - uint32_t payload[0] ; ///< Network data contained in this message. - - // uint8_t padding[0] - // Additional bytes of zeros added at the end of the message to comply with - // the internal and external padding requirements. Internal padding SHOULD be as per the - // specification of the out-of-band data record and per-packet-info data record. The external - //padding size SHOULD be determined based on the PacketAlignmentFactor field specification - //in REMOTE_NDIS_INITIALIZE_CMPLT message by the device, when multiple - //REMOTE_NDIS_PACKET_MSG messages are bundled together in a single bus-native message. - //In this case, all but the very last REMOTE_NDIS_PACKET_MSG MUST respect the - //PacketAlignmentFactor field. - - // rndis_msg_packet_t [0] : (optional) more packet if multiple packet per bus transaction is supported -} rndis_msg_packet_t; - - -typedef struct { - uint32_t size ; ///< Length, in bytes, of this header and appended data and padding. This value MUST be an integer multiple of 4. - uint32_t type ; ///< MUST be as per host operating system specification. - uint32_t offset ; ///< The byte offset from the beginning of this record to the beginning of data. - uint32_t data[0] ; ///< Flexible array contains data -} rndis_msg_out_of_band_data_t, rndis_msg_per_packet_info_t; - -//--------------------------------------------------------------------+ -// NDIS Object ID -//--------------------------------------------------------------------+ - -/// NDIS Object ID -typedef enum -{ - //------------- General Required OIDs -------------// - RNDIS_OID_GEN_SUPPORTED_LIST = 0x00010101, ///< List of supported OIDs - RNDIS_OID_GEN_HARDWARE_STATUS = 0x00010102, ///< Hardware status - RNDIS_OID_GEN_MEDIA_SUPPORTED = 0x00010103, ///< Media types supported (encoded) - RNDIS_OID_GEN_MEDIA_IN_USE = 0x00010104, ///< Media types in use (encoded) - RNDIS_OID_GEN_MAXIMUM_LOOKAHEAD = 0x00010105, ///< - RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE = 0x00010106, ///< Maximum frame size in bytes - RNDIS_OID_GEN_LINK_SPEED = 0x00010107, ///< Link speed in units of 100 bps - RNDIS_OID_GEN_TRANSMIT_BUFFER_SPACE = 0x00010108, ///< Transmit buffer space - RNDIS_OID_GEN_RECEIVE_BUFFER_SPACE = 0x00010109, ///< Receive buffer space - RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE = 0x0001010A, ///< Minimum amount of storage, in bytes, that a single packet occupies in the transmit buffer space of the NIC - RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE = 0x0001010B, ///< Amount of storage, in bytes, that a single packet occupies in the receive buffer space of the NIC - RNDIS_OID_GEN_VENDOR_ID = 0x0001010C, ///< Vendor NIC code - RNDIS_OID_GEN_VENDOR_DESCRIPTION = 0x0001010D, ///< Vendor network card description - RNDIS_OID_GEN_CURRENT_PACKET_FILTER = 0x0001010E, ///< Current packet filter (encoded) - RNDIS_OID_GEN_CURRENT_LOOKAHEAD = 0x0001010F, ///< Current lookahead size in bytes - RNDIS_OID_GEN_DRIVER_VERSION = 0x00010110, ///< NDIS version number used by the driver - RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE = 0x00010111, ///< Maximum total packet length in bytes - RNDIS_OID_GEN_PROTOCOL_OPTIONS = 0x00010112, ///< Optional protocol flags (encoded) - RNDIS_OID_GEN_MAC_OPTIONS = 0x00010113, ///< Optional NIC flags (encoded) - RNDIS_OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114, ///< Whether the NIC is connected to the network - RNDIS_OID_GEN_MAXIMUM_SEND_PACKETS = 0x00010115, ///< The maximum number of send packets the driver can accept per call to its MiniportSendPacketsfunction - - //------------- General Optional OIDs -------------// - RNDIS_OID_GEN_VENDOR_DRIVER_VERSION = 0x00010116, ///< Vendor-assigned version number of the driver - RNDIS_OID_GEN_SUPPORTED_GUIDS = 0x00010117, ///< The custom GUIDs (Globally Unique Identifier) supported by the miniport driver - RNDIS_OID_GEN_NETWORK_LAYER_ADDRESSES = 0x00010118, ///< List of network-layer addresses associated with the binding between a transport and the driver - RNDIS_OID_GEN_TRANSPORT_HEADER_OFFSET = 0x00010119, ///< Size of packets' additional headers - RNDIS_OID_GEN_MEDIA_CAPABILITIES = 0x00010201, ///< - RNDIS_OID_GEN_PHYSICAL_MEDIUM = 0x00010202, ///< Physical media supported by the miniport driver (encoded) - - //------------- 802.3 Objects (Ethernet) -------------// - RNDIS_OID_802_3_PERMANENT_ADDRESS = 0x01010101, ///< Permanent station address - RNDIS_OID_802_3_CURRENT_ADDRESS = 0x01010102, ///< Current station address - RNDIS_OID_802_3_MULTICAST_LIST = 0x01010103, ///< Current multicast address list - RNDIS_OID_802_3_MAXIMUM_LIST_SIZE = 0x01010104, ///< Maximum size of multicast address list -} rndis_oid_type_t; - -/// RNDIS Packet Filter Bits \ref RNDIS_OID_GEN_CURRENT_PACKET_FILTER. -typedef enum -{ - RNDIS_PACKET_TYPE_DIRECTED = 0x00000001, ///< Directed packets. Directed packets contain a destination address equal to the station address of the NIC. - RNDIS_PACKET_TYPE_MULTICAST = 0x00000002, ///< Multicast address packets sent to addresses in the multicast address list. - RNDIS_PACKET_TYPE_ALL_MULTICAST = 0x00000004, ///< All multicast address packets, not just the ones enumerated in the multicast address list. - RNDIS_PACKET_TYPE_BROADCAST = 0x00000008, ///< Broadcast packets. - RNDIS_PACKET_TYPE_SOURCE_ROUTING = 0x00000010, ///< All source routing packets. If the protocol driver sets this bit, the NDIS library attempts to act as a source routing bridge. - RNDIS_PACKET_TYPE_PROMISCUOUS = 0x00000020, ///< Specifies all packets regardless of whether VLAN filtering is enabled or not and whether the VLAN identifier matches or not. - RNDIS_PACKET_TYPE_SMT = 0x00000040, ///< SMT packets that an FDDI NIC receives. - RNDIS_PACKET_TYPE_ALL_LOCAL = 0x00000080, ///< All packets sent by installed protocols and all packets indicated by the NIC that is identified by a given NdisBindingHandle. - RNDIS_PACKET_TYPE_GROUP = 0x00001000, ///< Packets sent to the current group address. - RNDIS_PACKET_TYPE_ALL_FUNCTIONAL = 0x00002000, ///< All functional address packets, not just the ones in the current functional address. - RNDIS_PACKET_TYPE_FUNCTIONAL = 0x00004000, ///< Functional address packets sent to addresses included in the current functional address. - RNDIS_PACKET_TYPE_MAC_FRAME = 0x00008000, ///< NIC driver frames that a Token Ring NIC receives. - RNDIS_PACKET_TYPE_NO_LOCAL = 0x00010000, -} rndis_packet_filter_type_t; - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_CDC_RNDIS_H_ */ - -/** @} */ -/** @} */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c deleted file mode 100644 index 11a5355a..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.c +++ /dev/null @@ -1,289 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUH_ENABLED && CFG_TUH_CDC && CFG_TUH_CDC_RNDIS) - -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "common/tusb_common.h" -#include "cdc_host.h" -#include "cdc_rndis_host.h" - -#if 0 // TODO remove subtask related macros later -// Sub Task -#define OSAL_SUBTASK_BEGIN -#define OSAL_SUBTASK_END return TUSB_ERROR_NONE; - -#define STASK_RETURN(_error) return _error; -#define STASK_INVOKE(_subtask, _status) (_status) = _subtask -#define STASK_ASSERT(_cond) TU_VERIFY(_cond, TUSB_ERROR_OSAL_TASK_FAILED) -#endif - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -#define RNDIS_MSG_PAYLOAD_MAX (1024*4) - -CFG_TUH_MEM_SECTION static uint8_t msg_notification[CFG_TUH_DEVICE_MAX][8]; -CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN static uint8_t msg_payload[RNDIS_MSG_PAYLOAD_MAX]; - -static rndish_data_t rndish_data[CFG_TUH_DEVICE_MAX]; - -// TODO Microsoft requires message length for any get command must be at least 4096 bytes - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -static tusb_error_t rndis_body_subtask(void); -static tusb_error_t send_message_get_response_subtask( uint8_t dev_addr, cdch_data_t *p_cdc, - uint8_t * p_mess, uint32_t mess_length, - uint8_t *p_response ); - -//--------------------------------------------------------------------+ -// APPLICATION API -//--------------------------------------------------------------------+ -tusb_error_t tusbh_cdc_rndis_get_mac_addr(uint8_t dev_addr, uint8_t mac_address[6]) -{ - TU_ASSERT( tusbh_cdc_rndis_is_mounted(dev_addr), TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED); - TU_VERIFY( mac_address, TUSB_ERROR_INVALID_PARA); - - memcpy(mac_address, rndish_data[dev_addr-1].mac_address, 6); - - return TUSB_ERROR_NONE; -} - -//--------------------------------------------------------------------+ -// IMPLEMENTATION -//--------------------------------------------------------------------+ - -// To enable the TASK_ASSERT style (quick return on false condition) in a real RTOS, a task must act as a wrapper -// and is used mainly to call subtasks. Within a subtask return statement can be called freely, the task with -// forever loop cannot have any return at all. -OSAL_TASK_FUNCTION(cdch_rndis_task) (void* param;) -{ - OSAL_TASK_BEGIN - rndis_body_subtask(); - OSAL_TASK_END -} - -static tusb_error_t rndis_body_subtask(void) -{ - static uint8_t relative_addr; - - OSAL_SUBTASK_BEGIN - - for (relative_addr = 0; relative_addr < CFG_TUH_DEVICE_MAX; relative_addr++) - { - - } - - osal_task_delay(100); - - OSAL_SUBTASK_END -} - -//--------------------------------------------------------------------+ -// RNDIS-CDC Driver API -//--------------------------------------------------------------------+ -void rndish_init(void) -{ - tu_memclr(rndish_data, sizeof(rndish_data_t)*CFG_TUH_DEVICE_MAX); - - //------------- Task creation -------------// - - //------------- semaphore creation for notification pipe -------------// - for(uint8_t i=0; itype == RNDIS_MSG_INITIALIZE_CMPLT && p_init_cmpt->status == RNDIS_STATUS_SUCCESS && - p_init_cmpt->max_packet_per_xfer == 1 && p_init_cmpt->max_xfer_size <= RNDIS_MSG_PAYLOAD_MAX); - rndish_data[dev_addr-1].max_xfer_size = p_init_cmpt->max_xfer_size; - - //------------- Message Query 802.3 Permanent Address -------------// - memcpy(msg_payload, &msg_query_permanent_addr, sizeof(rndis_msg_query_t)); - tu_memclr(msg_payload + sizeof(rndis_msg_query_t), 6); // 6 bytes for MAC address - - STASK_INVOKE( - send_message_get_response_subtask( dev_addr, p_cdc, - msg_payload, sizeof(rndis_msg_query_t) + 6, - msg_payload), - error - ); - if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error); - - rndis_msg_query_cmplt_t * const p_query_cmpt = (rndis_msg_query_cmplt_t *) msg_payload; - STASK_ASSERT(p_query_cmpt->type == RNDIS_MSG_QUERY_CMPLT && p_query_cmpt->status == RNDIS_STATUS_SUCCESS); - memcpy(rndish_data[dev_addr-1].mac_address, msg_payload + 8 + p_query_cmpt->buffer_offset, 6); - - //------------- Set OID_GEN_CURRENT_PACKET_FILTER to (DIRECTED | MULTICAST | BROADCAST) -------------// - memcpy(msg_payload, &msg_set_packet_filter, sizeof(rndis_msg_set_t)); - tu_memclr(msg_payload + sizeof(rndis_msg_set_t), 4); // 4 bytes for filter flags - ((rndis_msg_set_t*) msg_payload)->oid_buffer[0] = (RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_MULTICAST | RNDIS_PACKET_TYPE_BROADCAST); - - STASK_INVOKE( - send_message_get_response_subtask( dev_addr, p_cdc, - msg_payload, sizeof(rndis_msg_set_t) + 4, - msg_payload), - error - ); - if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error); - - rndis_msg_set_cmplt_t * const p_set_cmpt = (rndis_msg_set_cmplt_t *) msg_payload; - STASK_ASSERT(p_set_cmpt->type == RNDIS_MSG_SET_CMPLT && p_set_cmpt->status == RNDIS_STATUS_SUCCESS); - - tusbh_cdc_rndis_mounted_cb(dev_addr); - - OSAL_SUBTASK_END -} - -void rndish_xfer_isr(cdch_data_t *p_cdc, pipe_handle_t pipe_hdl, xfer_result_t event, uint32_t xferred_bytes) -{ - if ( pipehandle_is_equal(pipe_hdl, p_cdc->pipe_notification) ) - { - osal_semaphore_post( rndish_data[pipe_hdl.dev_addr-1].sem_notification_hdl ); - } -} - -//--------------------------------------------------------------------+ -// INTERNAL & HELPER -//--------------------------------------------------------------------+ -static tusb_error_t send_message_get_response_subtask( uint8_t dev_addr, cdch_data_t *p_cdc, - uint8_t * p_mess, uint32_t mess_length, - uint8_t *p_response) -{ - tusb_error_t error; - - OSAL_SUBTASK_BEGIN - - //------------- Send RNDIS Control Message -------------// - STASK_INVOKE( - usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_OUT, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_INTERFACE), - CDC_REQUEST_SEND_ENCAPSULATED_COMMAND, 0, p_cdc->interface_number, - mess_length, p_mess), - error - ); - if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error); - - //------------- waiting for Response Available notification -------------// - (void) usbh_edpt_xfer(p_cdc->pipe_notification, msg_notification[dev_addr-1], 8); - osal_semaphore_wait(rndish_data[dev_addr-1].sem_notification_hdl, OSAL_TIMEOUT_NORMAL, &error); - if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error); - STASK_ASSERT(msg_notification[dev_addr-1][0] == 1); - - //------------- Get RNDIS Message Initialize Complete -------------// - STASK_INVOKE( - usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_INTERFACE), - CDC_REQUEST_GET_ENCAPSULATED_RESPONSE, 0, p_cdc->interface_number, - RNDIS_MSG_PAYLOAD_MAX, p_response), - error - ); - if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error); - - OSAL_SUBTASK_END -} - -//static tusb_error_t send_process_msg_initialize_subtask(uint8_t dev_addr, cdch_data_t *p_cdc) -//{ -// tusb_error_t error; -// -// OSAL_SUBTASK_BEGIN -// -// *((rndis_msg_initialize_t*) msg_payload) = (rndis_msg_initialize_t) -// { -// .type = RNDIS_MSG_INITIALIZE, -// .length = sizeof(rndis_msg_initialize_t), -// .request_id = 1, // TODO should use some magic number -// .major_version = 1, -// .minor_version = 0, -// .max_xfer_size = 0x4000 // TODO mimic windows -// }; -// -// -// -// OSAL_SUBTASK_END -//} -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.h b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.h deleted file mode 100644 index bb431ec1..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/cdc_rndis_host.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -/** \ingroup CDC_RNDIS - * \defgroup CDC_RNSID_Host Host - * @{ */ - -#ifndef _TUSB_CDC_RNDIS_HOST_H_ -#define _TUSB_CDC_RNDIS_HOST_H_ - -#include "common/tusb_common.h" -#include "host/usbh.h" -#include "cdc_rndis.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// INTERNAL RNDIS-CDC Driver API -//--------------------------------------------------------------------+ -typedef struct { - OSAL_SEM_DEF(semaphore_notification); - osal_semaphore_handle_t sem_notification_hdl; // used to wait on notification pipe - uint32_t max_xfer_size; // got from device's msg initialize complete - uint8_t mac_address[6]; -}rndish_data_t; - -void rndish_init(void); -bool rndish_open_subtask(uint8_t dev_addr, cdch_data_t *p_cdc); -void rndish_xfer_isr(cdch_data_t *p_cdc, pipe_handle_t pipe_hdl, xfer_result_t event, uint32_t xferred_bytes); -void rndish_close(uint8_t dev_addr); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_CDC_RNDIS_HOST_H_ */ - -/** @} */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/serial/cp210x.h b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/serial/cp210x.h deleted file mode 100644 index b0141709..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/serial/cp210x.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2023 Ha Thach (thach@tinyusb.org) for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef TUSB_CP210X_H -#define TUSB_CP210X_H - -// Protocol details can be found at AN571: CP210x Virtual COM Port Interface -// https://www.silabs.com/documents/public/application-notes/AN571.pdf - -#define TU_CP210X_VID 0x10C4 -#define TU_CP210X_PID_LIST \ - 0xEA60, 0xEA70 - -/* Config request codes */ -#define CP210X_IFC_ENABLE 0x00 -#define CP210X_SET_BAUDDIV 0x01 -#define CP210X_GET_BAUDDIV 0x02 -#define CP210X_SET_LINE_CTL 0x03 // Set parity, data bits, stop bits -#define CP210X_GET_LINE_CTL 0x04 -#define CP210X_SET_BREAK 0x05 -#define CP210X_IMM_CHAR 0x06 -#define CP210X_SET_MHS 0x07 // Set DTR, RTS -#define CP210X_GET_MDMSTS 0x08 // Get modem status (DTR, RTS, CTS, DSR, RI, DCD) -#define CP210X_SET_XON 0x09 -#define CP210X_SET_XOFF 0x0A -#define CP210X_SET_EVENTMASK 0x0B -#define CP210X_GET_EVENTMASK 0x0C -#define CP210X_SET_CHAR 0x0D -#define CP210X_GET_CHARS 0x0E -#define CP210X_GET_PROPS 0x0F -#define CP210X_GET_COMM_STATUS 0x10 -#define CP210X_RESET 0x11 -#define CP210X_PURGE 0x12 -#define CP210X_SET_FLOW 0x13 -#define CP210X_GET_FLOW 0x14 -#define CP210X_EMBED_EVENTS 0x15 -#define CP210X_GET_EVENTSTATE 0x16 -#define CP210X_SET_CHARS 0x19 -#define CP210X_GET_BAUDRATE 0x1D -#define CP210X_SET_BAUDRATE 0x1E -#define CP210X_VENDOR_SPECIFIC 0xFF // GPIO, Recipient must be Device - -#endif //TUSB_CP210X_H diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/serial/ftdi_sio.h b/test-devices/loopback-stm32/lib/tinyusb/class/cdc/serial/ftdi_sio.h deleted file mode 100644 index 6916e403..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/cdc/serial/ftdi_sio.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2023 Ha Thach (thach@tinyusb.org) for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef TUSB_FTDI_SIO_H -#define TUSB_FTDI_SIO_H - -// VID/PID for matching FTDI devices -#define TU_FTDI_VID 0x0403 -#define TU_FTDI_PID_LIST \ - 0x6001, 0x6006, 0x6010, 0x6011, 0x6014, 0x6015, 0x8372, 0xFBFA, \ - 0xcd18 - -// Commands -#define FTDI_SIO_RESET 0 /* Reset the port */ -#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ -#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */ -#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */ -#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */ -#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem status register */ -#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ -#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ -#define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */ -#define FTDI_SIO_GET_LATENCY_TIMER 0x0a /* Get the latency timer */ -#define FTDI_SIO_SET_BITMODE 0x0b /* Set bitbang mode */ -#define FTDI_SIO_READ_PINS 0x0c /* Read immediate value of pins */ -#define FTDI_SIO_READ_EEPROM 0x90 /* Read EEPROM */ - -/* FTDI_SIO_RESET */ -#define FTDI_SIO_RESET_SIO 0 -#define FTDI_SIO_RESET_PURGE_RX 1 -#define FTDI_SIO_RESET_PURGE_TX 2 - -/* - * BmRequestType: 0100 0000B - * bRequest: FTDI_SIO_RESET - * wValue: Control Value - * 0 = Reset SIO - * 1 = Purge RX buffer - * 2 = Purge TX buffer - * wIndex: Port - * wLength: 0 - * Data: None - * - * The Reset SIO command has this effect: - * - * Sets flow control set to 'none' - * Event char = $0D - * Event trigger = disabled - * Purge RX buffer - * Purge TX buffer - * Clear DTR - * Clear RTS - * baud and data format not reset - * - * The Purge RX and TX buffer commands affect nothing except the buffers - * - */ - -/* FTDI_SIO_MODEM_CTRL */ -/* - * BmRequestType: 0100 0000B - * bRequest: FTDI_SIO_MODEM_CTRL - * wValue: ControlValue (see below) - * wIndex: Port - * wLength: 0 - * Data: None - * - * NOTE: If the device is in RTS/CTS flow control, the RTS set by this - * command will be IGNORED without an error being returned - * Also - you can not set DTR and RTS with one control message - */ - -#define FTDI_SIO_SET_DTR_MASK 0x1 -#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1) -#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0) -#define FTDI_SIO_SET_RTS_MASK 0x2 -#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2) -#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0) - -/* - * ControlValue - * B0 DTR state - * 0 = reset - * 1 = set - * B1 RTS state - * 0 = reset - * 1 = set - * B2..7 Reserved - * B8 DTR state enable - * 0 = ignore - * 1 = use DTR state - * B9 RTS state enable - * 0 = ignore - * 1 = use RTS state - * B10..15 Reserved - */ - -/* FTDI_SIO_SET_FLOW_CTRL */ -#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 -#define FTDI_SIO_RTS_CTS_HS (0x1 << 8) -#define FTDI_SIO_DTR_DSR_HS (0x2 << 8) -#define FTDI_SIO_XON_XOFF_HS (0x4 << 8) - -/* - * BmRequestType: 0100 0000b - * bRequest: FTDI_SIO_SET_FLOW_CTRL - * wValue: Xoff/Xon - * wIndex: Protocol/Port - hIndex is protocol / lIndex is port - * wLength: 0 - * Data: None - * - * hIndex protocol is: - * B0 Output handshaking using RTS/CTS - * 0 = disabled - * 1 = enabled - * B1 Output handshaking using DTR/DSR - * 0 = disabled - * 1 = enabled - * B2 Xon/Xoff handshaking - * 0 = disabled - * 1 = enabled - * - * A value of zero in the hIndex field disables handshaking - * - * If Xon/Xoff handshaking is specified, the hValue field should contain the - * XOFF character and the lValue field contains the XON character. - */ - -/* FTDI_SIO_SET_BAUD_RATE */ -/* - * BmRequestType: 0100 0000B - * bRequest: FTDI_SIO_SET_BAUDRATE - * wValue: BaudDivisor value - see below - * wIndex: Port - * wLength: 0 - * Data: None - * The BaudDivisor values are calculated as follows (too complicated): - */ - -/* FTDI_SIO_SET_DATA */ -#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8) -#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8) -#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8) -#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8) -#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8) -#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) -#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) -#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11) -#define FTDI_SIO_SET_BREAK (0x1 << 14) - -/* - * BmRequestType: 0100 0000B - * bRequest: FTDI_SIO_SET_DATA - * wValue: Data characteristics (see below) - * wIndex: Port - * wLength: 0 - * Data: No - * - * Data characteristics - * - * B0..7 Number of data bits - * B8..10 Parity - * 0 = None - * 1 = Odd - * 2 = Even - * 3 = Mark - * 4 = Space - * B11..13 Stop Bits - * 0 = 1 - * 1 = 1.5 - * 2 = 2 - * B14 - * 1 = TX ON (break) - * 0 = TX OFF (normal state) - * B15 Reserved - * - */ - -/* -* DATA FORMAT -* -* IN Endpoint -* -* The device reserves the first two bytes of data on this endpoint to contain -* the current values of the modem and line status registers. In the absence of -* data, the device generates a message consisting of these two status bytes - * every 40 ms - * - * Byte 0: Modem Status -* -* Offset Description -* B0 Reserved - must be 1 -* B1 Reserved - must be 0 -* B2 Reserved - must be 0 -* B3 Reserved - must be 0 -* B4 Clear to Send (CTS) -* B5 Data Set Ready (DSR) -* B6 Ring Indicator (RI) -* B7 Receive Line Signal Detect (RLSD) -* -* Byte 1: Line Status -* -* Offset Description -* B0 Data Ready (DR) -* B1 Overrun Error (OE) -* B2 Parity Error (PE) -* B3 Framing Error (FE) -* B4 Break Interrupt (BI) -* B5 Transmitter Holding Register (THRE) -* B6 Transmitter Empty (TEMT) -* B7 Error in RCVR FIFO -* -*/ -#define FTDI_RS0_CTS (1 << 4) -#define FTDI_RS0_DSR (1 << 5) -#define FTDI_RS0_RI (1 << 6) -#define FTDI_RS0_RLSD (1 << 7) - -#define FTDI_RS_DR 1 -#define FTDI_RS_OE (1<<1) -#define FTDI_RS_PE (1<<2) -#define FTDI_RS_FE (1<<3) -#define FTDI_RS_BI (1<<4) -#define FTDI_RS_THRE (1<<5) -#define FTDI_RS_TEMT (1<<6) -#define FTDI_RS_FIFO (1<<7) - -#endif //TUSB_FTDI_SIO_H diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu.h b/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu.h deleted file mode 100644 index 114c827b..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2021 XMOS LIMITED - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_DFU_H_ -#define _TUSB_DFU_H_ - -#include "common/tusb_common.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Common Definitions -//--------------------------------------------------------------------+ - -// DFU Protocol -typedef enum -{ - DFU_PROTOCOL_RT = 0x01, - DFU_PROTOCOL_DFU = 0x02, -} dfu_protocol_type_t; - -// DFU Descriptor Type -typedef enum -{ - DFU_DESC_FUNCTIONAL = 0x21, -} dfu_descriptor_type_t; - -// DFU Requests -typedef enum { - DFU_REQUEST_DETACH = 0, - DFU_REQUEST_DNLOAD = 1, - DFU_REQUEST_UPLOAD = 2, - DFU_REQUEST_GETSTATUS = 3, - DFU_REQUEST_CLRSTATUS = 4, - DFU_REQUEST_GETSTATE = 5, - DFU_REQUEST_ABORT = 6, -} dfu_requests_t; - -// DFU States -typedef enum { - APP_IDLE = 0, - APP_DETACH = 1, - DFU_IDLE = 2, - DFU_DNLOAD_SYNC = 3, - DFU_DNBUSY = 4, - DFU_DNLOAD_IDLE = 5, - DFU_MANIFEST_SYNC = 6, - DFU_MANIFEST = 7, - DFU_MANIFEST_WAIT_RESET = 8, - DFU_UPLOAD_IDLE = 9, - DFU_ERROR = 10, -} dfu_state_t; - -// DFU Status -typedef enum { - DFU_STATUS_OK = 0x00, - DFU_STATUS_ERR_TARGET = 0x01, - DFU_STATUS_ERR_FILE = 0x02, - DFU_STATUS_ERR_WRITE = 0x03, - DFU_STATUS_ERR_ERASE = 0x04, - DFU_STATUS_ERR_CHECK_ERASED = 0x05, - DFU_STATUS_ERR_PROG = 0x06, - DFU_STATUS_ERR_VERIFY = 0x07, - DFU_STATUS_ERR_ADDRESS = 0x08, - DFU_STATUS_ERR_NOTDONE = 0x09, - DFU_STATUS_ERR_FIRMWARE = 0x0A, - DFU_STATUS_ERR_VENDOR = 0x0B, - DFU_STATUS_ERR_USBR = 0x0C, - DFU_STATUS_ERR_POR = 0x0D, - DFU_STATUS_ERR_UNKNOWN = 0x0E, - DFU_STATUS_ERR_STALLEDPKT = 0x0F, -} dfu_status_t; - -#define DFU_ATTR_CAN_DOWNLOAD (1u << 0) -#define DFU_ATTR_CAN_UPLOAD (1u << 1) -#define DFU_ATTR_MANIFESTATION_TOLERANT (1u << 2) -#define DFU_ATTR_WILL_DETACH (1u << 3) - -// DFU Status Request Payload -typedef struct TU_ATTR_PACKED -{ - uint8_t bStatus; - uint8_t bwPollTimeout[3]; - uint8_t bState; - uint8_t iString; -} dfu_status_response_t; - -TU_VERIFY_STATIC( sizeof(dfu_status_response_t) == 6, "size is not correct"); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_DFU_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_device.c deleted file mode 100644 index 464c4bd6..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_device.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2021 XMOS LIMITED - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_DFU) - -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "dfu_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -typedef struct -{ - uint8_t attrs; - uint8_t alt; - - dfu_state_t state; - dfu_status_t status; - - bool flashing_in_progress; - uint16_t block; - uint16_t length; - - CFG_TUSB_MEM_ALIGN uint8_t transfer_buf[CFG_TUD_DFU_XFER_BUFSIZE]; -} dfu_state_ctx_t; - -// Only a single dfu state is allowed -CFG_TUSB_MEM_SECTION tu_static dfu_state_ctx_t _dfu_ctx; - -static void reset_state(void) -{ - _dfu_ctx.state = DFU_IDLE; - _dfu_ctx.status = DFU_STATUS_OK; - _dfu_ctx.flashing_in_progress = false; -} - -static bool reply_getstatus(uint8_t rhport, tusb_control_request_t const * request, dfu_state_t state, dfu_status_t status, uint32_t timeout); -static bool process_download_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); - -//--------------------------------------------------------------------+ -// Debug -//--------------------------------------------------------------------+ -#if CFG_TUSB_DEBUG >= 2 - -tu_static tu_lookup_entry_t const _dfu_request_lookup[] = -{ - { .key = DFU_REQUEST_DETACH , .data = "DETACH" }, - { .key = DFU_REQUEST_DNLOAD , .data = "DNLOAD" }, - { .key = DFU_REQUEST_UPLOAD , .data = "UPLOAD" }, - { .key = DFU_REQUEST_GETSTATUS , .data = "GETSTATUS" }, - { .key = DFU_REQUEST_CLRSTATUS , .data = "CLRSTATUS" }, - { .key = DFU_REQUEST_GETSTATE , .data = "GETSTATE" }, - { .key = DFU_REQUEST_ABORT , .data = "ABORT" }, -}; - -tu_static tu_lookup_table_t const _dfu_request_table = -{ - .count = TU_ARRAY_SIZE(_dfu_request_lookup), - .items = _dfu_request_lookup -}; - -tu_static tu_lookup_entry_t const _dfu_state_lookup[] = -{ - { .key = APP_IDLE , .data = "APP_IDLE" }, - { .key = APP_DETACH , .data = "APP_DETACH" }, - { .key = DFU_IDLE , .data = "IDLE" }, - { .key = DFU_DNLOAD_SYNC , .data = "DNLOAD_SYNC" }, - { .key = DFU_DNBUSY , .data = "DNBUSY" }, - { .key = DFU_DNLOAD_IDLE , .data = "DNLOAD_IDLE" }, - { .key = DFU_MANIFEST_SYNC , .data = "MANIFEST_SYNC" }, - { .key = DFU_MANIFEST , .data = "MANIFEST" }, - { .key = DFU_MANIFEST_WAIT_RESET , .data = "MANIFEST_WAIT_RESET" }, - { .key = DFU_UPLOAD_IDLE , .data = "UPLOAD_IDLE" }, - { .key = DFU_ERROR , .data = "ERROR" }, -}; - -tu_static tu_lookup_table_t const _dfu_state_table = -{ - .count = TU_ARRAY_SIZE(_dfu_state_lookup), - .items = _dfu_state_lookup -}; - -tu_static tu_lookup_entry_t const _dfu_status_lookup[] = -{ - { .key = DFU_STATUS_OK , .data = "OK" }, - { .key = DFU_STATUS_ERR_TARGET , .data = "errTARGET" }, - { .key = DFU_STATUS_ERR_FILE , .data = "errFILE" }, - { .key = DFU_STATUS_ERR_WRITE , .data = "errWRITE" }, - { .key = DFU_STATUS_ERR_ERASE , .data = "errERASE" }, - { .key = DFU_STATUS_ERR_CHECK_ERASED , .data = "errCHECK_ERASED" }, - { .key = DFU_STATUS_ERR_PROG , .data = "errPROG" }, - { .key = DFU_STATUS_ERR_VERIFY , .data = "errVERIFY" }, - { .key = DFU_STATUS_ERR_ADDRESS , .data = "errADDRESS" }, - { .key = DFU_STATUS_ERR_NOTDONE , .data = "errNOTDONE" }, - { .key = DFU_STATUS_ERR_FIRMWARE , .data = "errFIRMWARE" }, - { .key = DFU_STATUS_ERR_VENDOR , .data = "errVENDOR" }, - { .key = DFU_STATUS_ERR_USBR , .data = "errUSBR" }, - { .key = DFU_STATUS_ERR_POR , .data = "errPOR" }, - { .key = DFU_STATUS_ERR_UNKNOWN , .data = "errUNKNOWN" }, - { .key = DFU_STATUS_ERR_STALLEDPKT , .data = "errSTALLEDPKT" }, -}; - -tu_static tu_lookup_table_t const _dfu_status_table = -{ - .count = TU_ARRAY_SIZE(_dfu_status_lookup), - .items = _dfu_status_lookup -}; - -#endif - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void dfu_moded_reset(uint8_t rhport) -{ - (void) rhport; - - _dfu_ctx.attrs = 0; - _dfu_ctx.alt = 0; - - reset_state(); -} - -void dfu_moded_init(void) -{ - dfu_moded_reset(0); -} - -uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ - (void) rhport; - - //------------- Interface (with Alt) descriptor -------------// - uint8_t const itf_num = itf_desc->bInterfaceNumber; - uint8_t alt_count = 0; - - uint16_t drv_len = 0; - TU_VERIFY(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS && itf_desc->bInterfaceProtocol == DFU_PROTOCOL_DFU, 0); - - while(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS && itf_desc->bInterfaceProtocol == DFU_PROTOCOL_DFU) - { - TU_ASSERT(max_len > drv_len, 0); - - // Alternate must have the same interface number - TU_ASSERT(itf_desc->bInterfaceNumber == itf_num, 0); - - // Alt should increase by one every time - TU_ASSERT(itf_desc->bAlternateSetting == alt_count, 0); - alt_count++; - - drv_len += tu_desc_len(itf_desc); - itf_desc = (tusb_desc_interface_t const *) tu_desc_next(itf_desc); - } - - //------------- DFU Functional descriptor -------------// - tusb_desc_dfu_functional_t const *func_desc = (tusb_desc_dfu_functional_t const *) itf_desc; - TU_ASSERT(tu_desc_type(func_desc) == TUSB_DESC_FUNCTIONAL, 0); - drv_len += sizeof(tusb_desc_dfu_functional_t); - - _dfu_ctx.attrs = func_desc->bAttributes; - - // CFG_TUD_DFU_XFER_BUFSIZE has to be set to the buffer size used in TUD_DFU_DESCRIPTOR - uint16_t const transfer_size = tu_le16toh( tu_unaligned_read16((uint8_t const*) func_desc + offsetof(tusb_desc_dfu_functional_t, wTransferSize)) ); - TU_ASSERT(transfer_size <= CFG_TUD_DFU_XFER_BUFSIZE, drv_len); - - return drv_len; -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); - - TU_LOG2(" DFU State : %s, Status: %s\r\n", tu_lookup_find(&_dfu_state_table, _dfu_ctx.state), tu_lookup_find(&_dfu_status_table, _dfu_ctx.status)); - - if ( request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD ) - { - // Standard request include GET/SET_INTERFACE - switch ( request->bRequest ) - { - case TUSB_REQ_SET_INTERFACE: - if ( stage == CONTROL_STAGE_SETUP ) - { - // Switch Alt interface and reset state machine - _dfu_ctx.alt = (uint8_t) request->wValue; - reset_state(); - return tud_control_status(rhport, request); - } - break; - - case TUSB_REQ_GET_INTERFACE: - if(stage == CONTROL_STAGE_SETUP) - { - return tud_control_xfer(rhport, request, &_dfu_ctx.alt, 1); - } - break; - - // unsupported request - default: return false; - } - } - else if ( request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS ) - { - TU_LOG2(" DFU Request: %s\r\n", tu_lookup_find(&_dfu_request_table, request->bRequest)); - - // Class request - switch ( request->bRequest ) - { - case DFU_REQUEST_DETACH: - if ( stage == CONTROL_STAGE_SETUP ) - { - tud_control_status(rhport, request); - } - else if ( stage == CONTROL_STAGE_ACK ) - { - if ( tud_dfu_detach_cb ) tud_dfu_detach_cb(); - } - break; - - case DFU_REQUEST_CLRSTATUS: - if ( stage == CONTROL_STAGE_SETUP ) - { - reset_state(); - tud_control_status(rhport, request); - } - break; - - case DFU_REQUEST_GETSTATE: - if ( stage == CONTROL_STAGE_SETUP ) - { - tud_control_xfer(rhport, request, &_dfu_ctx.state, 1); - } - break; - - case DFU_REQUEST_ABORT: - if ( stage == CONTROL_STAGE_SETUP ) - { - reset_state(); - tud_control_status(rhport, request); - } - else if ( stage == CONTROL_STAGE_ACK ) - { - if ( tud_dfu_abort_cb ) tud_dfu_abort_cb(_dfu_ctx.alt); - } - break; - - case DFU_REQUEST_UPLOAD: - if ( stage == CONTROL_STAGE_SETUP ) - { - TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_UPLOAD); - TU_VERIFY(tud_dfu_upload_cb); - TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE); - - uint16_t const xfer_len = tud_dfu_upload_cb(_dfu_ctx.alt, request->wValue, _dfu_ctx.transfer_buf, request->wLength); - - return tud_control_xfer(rhport, request, _dfu_ctx.transfer_buf, xfer_len); - } - break; - - case DFU_REQUEST_DNLOAD: - if ( stage == CONTROL_STAGE_SETUP ) - { - TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_DOWNLOAD); - TU_VERIFY(_dfu_ctx.state == DFU_IDLE || _dfu_ctx.state == DFU_DNLOAD_IDLE); - TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE); - - // set to true for both download and manifest - _dfu_ctx.flashing_in_progress = true; - - // save block and length for flashing - _dfu_ctx.block = request->wValue; - _dfu_ctx.length = request->wLength; - - if ( request->wLength ) - { - // Download with payload -> transition to DOWNLOAD SYNC - _dfu_ctx.state = DFU_DNLOAD_SYNC; - return tud_control_xfer(rhport, request, _dfu_ctx.transfer_buf, request->wLength); - } - else - { - // Download is complete -> transition to MANIFEST SYNC - _dfu_ctx.state = DFU_MANIFEST_SYNC; - return tud_control_status(rhport, request); - } - } - break; - - case DFU_REQUEST_GETSTATUS: - switch ( _dfu_ctx.state ) - { - case DFU_DNLOAD_SYNC: - return process_download_get_status(rhport, stage, request); - break; - - case DFU_MANIFEST_SYNC: - return process_manifest_get_status(rhport, stage, request); - break; - - default: - if ( stage == CONTROL_STAGE_SETUP ) return reply_getstatus(rhport, request, _dfu_ctx.state, _dfu_ctx.status, 0); - break; - } - break; - - default: return false; // stall unsupported request - } - }else - { - return false; // unsupported request - } - - return true; -} - -void tud_dfu_finish_flashing(uint8_t status) -{ - _dfu_ctx.flashing_in_progress = false; - - if ( status == DFU_STATUS_OK ) - { - if (_dfu_ctx.state == DFU_DNBUSY) - { - _dfu_ctx.state = DFU_DNLOAD_SYNC; - } - else if (_dfu_ctx.state == DFU_MANIFEST) - { - _dfu_ctx.state = (_dfu_ctx.attrs & DFU_ATTR_MANIFESTATION_TOLERANT) - ? DFU_MANIFEST_SYNC : DFU_MANIFEST_WAIT_RESET; - } - } - else - { - // failed while flashing, move to dfuError - _dfu_ctx.state = DFU_ERROR; - _dfu_ctx.status = (dfu_status_t)status; - } -} - -static bool process_download_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - if ( stage == CONTROL_STAGE_SETUP ) - { - // only transition to next state on CONTROL_STAGE_ACK - dfu_state_t next_state; - uint32_t timeout; - - if ( _dfu_ctx.flashing_in_progress ) - { - next_state = DFU_DNBUSY; - timeout = tud_dfu_get_timeout_cb(_dfu_ctx.alt, (uint8_t) next_state); - } - else - { - next_state = DFU_DNLOAD_IDLE; - timeout = 0; - } - - return reply_getstatus(rhport, request, next_state, _dfu_ctx.status, timeout); - } - else if ( stage == CONTROL_STAGE_ACK ) - { - if ( _dfu_ctx.flashing_in_progress ) - { - _dfu_ctx.state = DFU_DNBUSY; - tud_dfu_download_cb(_dfu_ctx.alt, _dfu_ctx.block, _dfu_ctx.transfer_buf, _dfu_ctx.length); - }else - { - _dfu_ctx.state = DFU_DNLOAD_IDLE; - } - } - - return true; -} - -static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - if ( stage == CONTROL_STAGE_SETUP ) - { - // only transition to next state on CONTROL_STAGE_ACK - dfu_state_t next_state; - uint32_t timeout; - - if ( _dfu_ctx.flashing_in_progress ) - { - next_state = DFU_MANIFEST; - timeout = tud_dfu_get_timeout_cb(_dfu_ctx.alt, next_state); - } - else - { - next_state = DFU_IDLE; - timeout = 0; - } - - return reply_getstatus(rhport, request, next_state, _dfu_ctx.status, timeout); - } - else if ( stage == CONTROL_STAGE_ACK ) - { - if ( _dfu_ctx.flashing_in_progress ) - { - _dfu_ctx.state = DFU_MANIFEST; - tud_dfu_manifest_cb(_dfu_ctx.alt); - } - else - { - _dfu_ctx.state = DFU_IDLE; - } - } - - return true; -} - -static bool reply_getstatus(uint8_t rhport, tusb_control_request_t const * request, dfu_state_t state, dfu_status_t status, uint32_t timeout) -{ - dfu_status_response_t resp; - resp.bStatus = (uint8_t) status; - resp.bwPollTimeout[0] = TU_U32_BYTE0(timeout); - resp.bwPollTimeout[1] = TU_U32_BYTE1(timeout); - resp.bwPollTimeout[2] = TU_U32_BYTE2(timeout); - resp.bState = (uint8_t) state; - resp.iString = 0; - - return tud_control_xfer(rhport, request, &resp, sizeof(dfu_status_response_t)); -} - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_device.h deleted file mode 100644 index fecf8596..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_device.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2021 XMOS LIMITED - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_DFU_DEVICE_H_ -#define _TUSB_DFU_DEVICE_H_ - -#include "dfu.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Class Driver Default Configure & Validation -//--------------------------------------------------------------------+ - -#if !defined(CFG_TUD_DFU_XFER_BUFSIZE) - #error "CFG_TUD_DFU_XFER_BUFSIZE must be defined, it has to be set to the buffer size used in TUD_DFU_DESCRIPTOR" -#endif - -//--------------------------------------------------------------------+ -// Application API -//--------------------------------------------------------------------+ - -// Must be called when the application is done with flashing started by -// tud_dfu_download_cb() and tud_dfu_manifest_cb(). -// status is DFU_STATUS_OK if successful, any other error status will cause state to enter dfuError -void tud_dfu_finish_flashing(uint8_t status); - -//--------------------------------------------------------------------+ -// Application Callback API (weak is optional) -//--------------------------------------------------------------------+ - -// Note: alt is used as the partition number, in order to support multiple partitions like FLASH, EEPROM, etc. - -// Invoked right before tud_dfu_download_cb() (state=DFU_DNBUSY) or tud_dfu_manifest_cb() (state=DFU_MANIFEST) -// Application return timeout in milliseconds (bwPollTimeout) for the next download/manifest operation. -// During this period, USB host won't try to communicate with us. -uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state); - -// Invoked when received DFU_DNLOAD (wLength>0) following by DFU_GETSTATUS (state=DFU_DNBUSY) requests -// This callback could be returned before flashing op is complete (async). -// Once finished flashing, application must call tud_dfu_finish_flashing() -void tud_dfu_download_cb (uint8_t alt, uint16_t block_num, uint8_t const *data, uint16_t length); - -// Invoked when download process is complete, received DFU_DNLOAD (wLength=0) following by DFU_GETSTATUS (state=Manifest) -// Application can do checksum, or actual flashing if buffered entire image previously. -// Once finished flashing, application must call tud_dfu_finish_flashing() -void tud_dfu_manifest_cb(uint8_t alt); - -// Invoked when received DFU_UPLOAD request -// Application must populate data with up to length bytes and -// Return the number of written bytes -TU_ATTR_WEAK uint16_t tud_dfu_upload_cb(uint8_t alt, uint16_t block_num, uint8_t* data, uint16_t length); - -// Invoked when a DFU_DETACH request is received -TU_ATTR_WEAK void tud_dfu_detach_cb(void); - -// Invoked when the Host has terminated a download or upload transfer -TU_ATTR_WEAK void tud_dfu_abort_cb(uint8_t alt); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void dfu_moded_init(void); -void dfu_moded_reset(uint8_t rhport); -uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); - - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_DFU_MODE_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c deleted file mode 100644 index 7b77b3f8..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Sylvain Munaut - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_DFU_RUNTIME) - -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "dfu_rt_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void dfu_rtd_init(void) -{ -} - -void dfu_rtd_reset(uint8_t rhport) -{ - (void) rhport; -} - -uint16_t dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ - (void) rhport; - (void) max_len; - - // Ensure this is DFU Runtime - TU_VERIFY((itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS) && - (itf_desc->bInterfaceProtocol == DFU_PROTOCOL_RT), 0); - - uint8_t const * p_desc = tu_desc_next( itf_desc ); - uint16_t drv_len = sizeof(tusb_desc_interface_t); - - if ( TUSB_DESC_FUNCTIONAL == tu_desc_type(p_desc) ) - { - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - return drv_len; -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - // nothing to do with DATA or ACK stage - if ( stage != CONTROL_STAGE_SETUP ) return true; - - TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); - - // dfu-util will try to claim the interface with SET_INTERFACE request before sending DFU request - if ( TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type && - TUSB_REQ_SET_INTERFACE == request->bRequest ) - { - tud_control_status(rhport, request); - return true; - } - - // Handle class request only from here - TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); - - switch (request->bRequest) - { - case DFU_REQUEST_DETACH: - { - TU_LOG2(" DFU RT Request: DETACH\r\n"); - tud_control_status(rhport, request); - tud_dfu_runtime_reboot_to_dfu_cb(); - } - break; - - case DFU_REQUEST_GETSTATUS: - { - TU_LOG2(" DFU RT Request: GETSTATUS\r\n"); - dfu_status_response_t resp; - // Status = OK, Poll timeout is ignored during RT, State = APP_IDLE, IString = 0 - TU_VERIFY(tu_memset_s(&resp, sizeof(resp), 0x00, sizeof(resp))==0); - tud_control_xfer(rhport, request, &resp, sizeof(dfu_status_response_t)); - } - break; - - default: - { - TU_LOG2(" DFU RT Unexpected Request: %d\r\n", request->bRequest); - return false; // stall unsupported request - } - } - - return true; -} - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.h deleted file mode 100644 index babaa821..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/dfu/dfu_rt_device.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Sylvain Munaut - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_DFU_RT_DEVICE_H_ -#define _TUSB_DFU_RT_DEVICE_H_ - -#include "dfu.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Application Callback API (weak is optional) -//--------------------------------------------------------------------+ -// Invoked when a DFU_DETACH request is received and bitWillDetach is set -void tud_dfu_runtime_reboot_to_dfu_cb(void); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void dfu_rtd_init(void); -void dfu_rtd_reset(uint8_t rhport); -uint16_t dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_DFU_RT_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid.h b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid.h deleted file mode 100644 index fbd3eef3..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid.h +++ /dev/null @@ -1,1131 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -/** \ingroup group_class - * \defgroup ClassDriver_HID Human Interface Device (HID) - * @{ */ - -#ifndef _TUSB_HID_H_ -#define _TUSB_HID_H_ - -#include "common/tusb_common.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Common Definitions -//--------------------------------------------------------------------+ -/** \defgroup ClassDriver_HID_Common Common Definitions - * @{ */ - -/// USB HID Descriptor -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength; /**< Numeric expression that is the total size of the HID descriptor */ - uint8_t bDescriptorType; /**< Constant name specifying type of HID descriptor. */ - - uint16_t bcdHID; /**< Numeric expression identifying the HID Class Specification release */ - uint8_t bCountryCode; /**< Numeric expression identifying country code of the localized hardware. */ - uint8_t bNumDescriptors; /**< Numeric expression specifying the number of class descriptors */ - - uint8_t bReportType; /**< Type of HID class report. */ - uint16_t wReportLength; /**< the total size of the Report descriptor. */ -} tusb_hid_descriptor_hid_t; - -/// HID Subclass -typedef enum -{ - HID_SUBCLASS_NONE = 0, ///< No Subclass - HID_SUBCLASS_BOOT = 1 ///< Boot Interface Subclass -}hid_subclass_enum_t; - -/// HID Interface Protocol -typedef enum -{ - HID_ITF_PROTOCOL_NONE = 0, ///< None - HID_ITF_PROTOCOL_KEYBOARD = 1, ///< Keyboard - HID_ITF_PROTOCOL_MOUSE = 2 ///< Mouse -}hid_interface_protocol_enum_t; - -/// HID Descriptor Type -typedef enum -{ - HID_DESC_TYPE_HID = 0x21, ///< HID Descriptor - HID_DESC_TYPE_REPORT = 0x22, ///< Report Descriptor - HID_DESC_TYPE_PHYSICAL = 0x23 ///< Physical Descriptor -}hid_descriptor_enum_t; - -/// HID Request Report Type -typedef enum -{ - HID_REPORT_TYPE_INVALID = 0, - HID_REPORT_TYPE_INPUT, ///< Input - HID_REPORT_TYPE_OUTPUT, ///< Output - HID_REPORT_TYPE_FEATURE ///< Feature -}hid_report_type_t; - -/// HID Class Specific Control Request -typedef enum -{ - HID_REQ_CONTROL_GET_REPORT = 0x01, ///< Get Report - HID_REQ_CONTROL_GET_IDLE = 0x02, ///< Get Idle - HID_REQ_CONTROL_GET_PROTOCOL = 0x03, ///< Get Protocol - HID_REQ_CONTROL_SET_REPORT = 0x09, ///< Set Report - HID_REQ_CONTROL_SET_IDLE = 0x0a, ///< Set Idle - HID_REQ_CONTROL_SET_PROTOCOL = 0x0b ///< Set Protocol -}hid_request_enum_t; - -/// HID Local Code -typedef enum -{ - HID_LOCAL_NotSupported = 0 , ///< NotSupported - HID_LOCAL_Arabic , ///< Arabic - HID_LOCAL_Belgian , ///< Belgian - HID_LOCAL_Canadian_Bilingual , ///< Canadian_Bilingual - HID_LOCAL_Canadian_French , ///< Canadian_French - HID_LOCAL_Czech_Republic , ///< Czech_Republic - HID_LOCAL_Danish , ///< Danish - HID_LOCAL_Finnish , ///< Finnish - HID_LOCAL_French , ///< French - HID_LOCAL_German , ///< German - HID_LOCAL_Greek , ///< Greek - HID_LOCAL_Hebrew , ///< Hebrew - HID_LOCAL_Hungary , ///< Hungary - HID_LOCAL_International , ///< International - HID_LOCAL_Italian , ///< Italian - HID_LOCAL_Japan_Katakana , ///< Japan_Katakana - HID_LOCAL_Korean , ///< Korean - HID_LOCAL_Latin_American , ///< Latin_American - HID_LOCAL_Netherlands_Dutch , ///< Netherlands/Dutch - HID_LOCAL_Norwegian , ///< Norwegian - HID_LOCAL_Persian_Farsi , ///< Persian (Farsi) - HID_LOCAL_Poland , ///< Poland - HID_LOCAL_Portuguese , ///< Portuguese - HID_LOCAL_Russia , ///< Russia - HID_LOCAL_Slovakia , ///< Slovakia - HID_LOCAL_Spanish , ///< Spanish - HID_LOCAL_Swedish , ///< Swedish - HID_LOCAL_Swiss_French , ///< Swiss/French - HID_LOCAL_Swiss_German , ///< Swiss/German - HID_LOCAL_Switzerland , ///< Switzerland - HID_LOCAL_Taiwan , ///< Taiwan - HID_LOCAL_Turkish_Q , ///< Turkish-Q - HID_LOCAL_UK , ///< UK - HID_LOCAL_US , ///< US - HID_LOCAL_Yugoslavia , ///< Yugoslavia - HID_LOCAL_Turkish_F ///< Turkish-F -} hid_local_enum_t; - -// HID protocol value used by GetProtocol / SetProtocol -typedef enum -{ - HID_PROTOCOL_BOOT = 0, - HID_PROTOCOL_REPORT = 1 -} hid_protocol_mode_enum_t; - -/** @} */ - -//--------------------------------------------------------------------+ -// GAMEPAD -//--------------------------------------------------------------------+ -/** \addtogroup ClassDriver_HID_Gamepad Gamepad - * @{ */ - -/* From https://www.kernel.org/doc/html/latest/input/gamepad.html - ____________________________ __ - / [__ZL__] [__ZR__] \ | - / [__ TL __] [__ TR __] \ | Front Triggers - __/________________________________\__ __| - / _ \ | - / /\ __ (N) \ | - / || __ |MO| __ _ _ \ | Main Pad - | <===DP===> |SE| |ST| (W) -|- (E) | | - \ || ___ ___ _ / | - /\ \/ / \ / \ (S) /\ __| - / \________ | LS | ____ | RS | ________/ \ | -| / \ \___/ / \ \___/ / \ | | Control Sticks -| / \_____/ \_____/ \ | __| -| / \ | - \_____/ \_____/ - - |________|______| |______|___________| - D-Pad Left Right Action Pad - Stick Stick - - |_____________| - Menu Pad - - Most gamepads have the following features: - - Action-Pad 4 buttons in diamonds-shape (on the right side) NORTH, SOUTH, WEST and EAST. - - D-Pad (Direction-pad) 4 buttons (on the left side) that point up, down, left and right. - - Menu-Pad Different constellations, but most-times 2 buttons: SELECT - START. - - Analog-Sticks provide freely moveable sticks to control directions, Analog-sticks may also - provide a digital button if you press them. - - Triggers are located on the upper-side of the pad in vertical direction. The upper buttons - are normally named Left- and Right-Triggers, the lower buttons Z-Left and Z-Right. - - Rumble Many devices provide force-feedback features. But are mostly just simple rumble motors. - */ - -/// HID Gamepad Protocol Report. -typedef struct TU_ATTR_PACKED -{ - int8_t x; ///< Delta x movement of left analog-stick - int8_t y; ///< Delta y movement of left analog-stick - int8_t z; ///< Delta z movement of right analog-joystick - int8_t rz; ///< Delta Rz movement of right analog-joystick - int8_t rx; ///< Delta Rx movement of analog left trigger - int8_t ry; ///< Delta Ry movement of analog right trigger - uint8_t hat; ///< Buttons mask for currently pressed buttons in the DPad/hat - uint32_t buttons; ///< Buttons mask for currently pressed buttons -}hid_gamepad_report_t; - -/// Standard Gamepad Buttons Bitmap -typedef enum -{ - GAMEPAD_BUTTON_0 = TU_BIT(0), - GAMEPAD_BUTTON_1 = TU_BIT(1), - GAMEPAD_BUTTON_2 = TU_BIT(2), - GAMEPAD_BUTTON_3 = TU_BIT(3), - GAMEPAD_BUTTON_4 = TU_BIT(4), - GAMEPAD_BUTTON_5 = TU_BIT(5), - GAMEPAD_BUTTON_6 = TU_BIT(6), - GAMEPAD_BUTTON_7 = TU_BIT(7), - GAMEPAD_BUTTON_8 = TU_BIT(8), - GAMEPAD_BUTTON_9 = TU_BIT(9), - GAMEPAD_BUTTON_10 = TU_BIT(10), - GAMEPAD_BUTTON_11 = TU_BIT(11), - GAMEPAD_BUTTON_12 = TU_BIT(12), - GAMEPAD_BUTTON_13 = TU_BIT(13), - GAMEPAD_BUTTON_14 = TU_BIT(14), - GAMEPAD_BUTTON_15 = TU_BIT(15), - GAMEPAD_BUTTON_16 = TU_BIT(16), - GAMEPAD_BUTTON_17 = TU_BIT(17), - GAMEPAD_BUTTON_18 = TU_BIT(18), - GAMEPAD_BUTTON_19 = TU_BIT(19), - GAMEPAD_BUTTON_20 = TU_BIT(20), - GAMEPAD_BUTTON_21 = TU_BIT(21), - GAMEPAD_BUTTON_22 = TU_BIT(22), - GAMEPAD_BUTTON_23 = TU_BIT(23), - GAMEPAD_BUTTON_24 = TU_BIT(24), - GAMEPAD_BUTTON_25 = TU_BIT(25), - GAMEPAD_BUTTON_26 = TU_BIT(26), - GAMEPAD_BUTTON_27 = TU_BIT(27), - GAMEPAD_BUTTON_28 = TU_BIT(28), - GAMEPAD_BUTTON_29 = TU_BIT(29), - GAMEPAD_BUTTON_30 = TU_BIT(30), - GAMEPAD_BUTTON_31 = TU_BIT(31), -}hid_gamepad_button_bm_t; - -/// Standard Gamepad Buttons Naming from Linux input event codes -/// https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h -#define GAMEPAD_BUTTON_A GAMEPAD_BUTTON_0 -#define GAMEPAD_BUTTON_SOUTH GAMEPAD_BUTTON_0 - -#define GAMEPAD_BUTTON_B GAMEPAD_BUTTON_1 -#define GAMEPAD_BUTTON_EAST GAMEPAD_BUTTON_1 - -#define GAMEPAD_BUTTON_C GAMEPAD_BUTTON_2 - -#define GAMEPAD_BUTTON_X GAMEPAD_BUTTON_3 -#define GAMEPAD_BUTTON_NORTH GAMEPAD_BUTTON_3 - -#define GAMEPAD_BUTTON_Y GAMEPAD_BUTTON_4 -#define GAMEPAD_BUTTON_WEST GAMEPAD_BUTTON_4 - -#define GAMEPAD_BUTTON_Z GAMEPAD_BUTTON_5 -#define GAMEPAD_BUTTON_TL GAMEPAD_BUTTON_6 -#define GAMEPAD_BUTTON_TR GAMEPAD_BUTTON_7 -#define GAMEPAD_BUTTON_TL2 GAMEPAD_BUTTON_8 -#define GAMEPAD_BUTTON_TR2 GAMEPAD_BUTTON_9 -#define GAMEPAD_BUTTON_SELECT GAMEPAD_BUTTON_10 -#define GAMEPAD_BUTTON_START GAMEPAD_BUTTON_11 -#define GAMEPAD_BUTTON_MODE GAMEPAD_BUTTON_12 -#define GAMEPAD_BUTTON_THUMBL GAMEPAD_BUTTON_13 -#define GAMEPAD_BUTTON_THUMBR GAMEPAD_BUTTON_14 - -/// Standard Gamepad HAT/DPAD Buttons (from Linux input event codes) -typedef enum -{ - GAMEPAD_HAT_CENTERED = 0, ///< DPAD_CENTERED - GAMEPAD_HAT_UP = 1, ///< DPAD_UP - GAMEPAD_HAT_UP_RIGHT = 2, ///< DPAD_UP_RIGHT - GAMEPAD_HAT_RIGHT = 3, ///< DPAD_RIGHT - GAMEPAD_HAT_DOWN_RIGHT = 4, ///< DPAD_DOWN_RIGHT - GAMEPAD_HAT_DOWN = 5, ///< DPAD_DOWN - GAMEPAD_HAT_DOWN_LEFT = 6, ///< DPAD_DOWN_LEFT - GAMEPAD_HAT_LEFT = 7, ///< DPAD_LEFT - GAMEPAD_HAT_UP_LEFT = 8, ///< DPAD_UP_LEFT -}hid_gamepad_hat_t; - -/// @} - -//--------------------------------------------------------------------+ -// MOUSE -//--------------------------------------------------------------------+ -/** \addtogroup ClassDriver_HID_Mouse Mouse - * @{ */ - -/// Standard HID Boot Protocol Mouse Report. -typedef struct TU_ATTR_PACKED -{ - uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */ - int8_t x; /**< Current delta x movement of the mouse. */ - int8_t y; /**< Current delta y movement on the mouse. */ - int8_t wheel; /**< Current delta wheel movement on the mouse. */ - int8_t pan; // using AC Pan -} hid_mouse_report_t; - -/// Standard Mouse Buttons Bitmap -typedef enum -{ - MOUSE_BUTTON_LEFT = TU_BIT(0), ///< Left button - MOUSE_BUTTON_RIGHT = TU_BIT(1), ///< Right button - MOUSE_BUTTON_MIDDLE = TU_BIT(2), ///< Middle button - MOUSE_BUTTON_BACKWARD = TU_BIT(3), ///< Backward button, - MOUSE_BUTTON_FORWARD = TU_BIT(4), ///< Forward button, -}hid_mouse_button_bm_t; - -/// @} - -//--------------------------------------------------------------------+ -// Keyboard -//--------------------------------------------------------------------+ -/** \addtogroup ClassDriver_HID_Keyboard Keyboard - * @{ */ - -/// Standard HID Boot Protocol Keyboard Report. -typedef struct TU_ATTR_PACKED -{ - uint8_t modifier; /**< Keyboard modifier (KEYBOARD_MODIFIER_* masks). */ - uint8_t reserved; /**< Reserved for OEM use, always set to 0. */ - uint8_t keycode[6]; /**< Key codes of the currently pressed keys. */ -} hid_keyboard_report_t; - -/// Keyboard modifier codes bitmap -typedef enum -{ - KEYBOARD_MODIFIER_LEFTCTRL = TU_BIT(0), ///< Left Control - KEYBOARD_MODIFIER_LEFTSHIFT = TU_BIT(1), ///< Left Shift - KEYBOARD_MODIFIER_LEFTALT = TU_BIT(2), ///< Left Alt - KEYBOARD_MODIFIER_LEFTGUI = TU_BIT(3), ///< Left Window - KEYBOARD_MODIFIER_RIGHTCTRL = TU_BIT(4), ///< Right Control - KEYBOARD_MODIFIER_RIGHTSHIFT = TU_BIT(5), ///< Right Shift - KEYBOARD_MODIFIER_RIGHTALT = TU_BIT(6), ///< Right Alt - KEYBOARD_MODIFIER_RIGHTGUI = TU_BIT(7) ///< Right Window -}hid_keyboard_modifier_bm_t; - -typedef enum -{ - KEYBOARD_LED_NUMLOCK = TU_BIT(0), ///< Num Lock LED - KEYBOARD_LED_CAPSLOCK = TU_BIT(1), ///< Caps Lock LED - KEYBOARD_LED_SCROLLLOCK = TU_BIT(2), ///< Scroll Lock LED - KEYBOARD_LED_COMPOSE = TU_BIT(3), ///< Composition Mode - KEYBOARD_LED_KANA = TU_BIT(4) ///< Kana mode -}hid_keyboard_led_bm_t; - -/// @} - -//--------------------------------------------------------------------+ -// HID KEYCODE -//--------------------------------------------------------------------+ -#define HID_KEY_NONE 0x00 -#define HID_KEY_A 0x04 -#define HID_KEY_B 0x05 -#define HID_KEY_C 0x06 -#define HID_KEY_D 0x07 -#define HID_KEY_E 0x08 -#define HID_KEY_F 0x09 -#define HID_KEY_G 0x0A -#define HID_KEY_H 0x0B -#define HID_KEY_I 0x0C -#define HID_KEY_J 0x0D -#define HID_KEY_K 0x0E -#define HID_KEY_L 0x0F -#define HID_KEY_M 0x10 -#define HID_KEY_N 0x11 -#define HID_KEY_O 0x12 -#define HID_KEY_P 0x13 -#define HID_KEY_Q 0x14 -#define HID_KEY_R 0x15 -#define HID_KEY_S 0x16 -#define HID_KEY_T 0x17 -#define HID_KEY_U 0x18 -#define HID_KEY_V 0x19 -#define HID_KEY_W 0x1A -#define HID_KEY_X 0x1B -#define HID_KEY_Y 0x1C -#define HID_KEY_Z 0x1D -#define HID_KEY_1 0x1E -#define HID_KEY_2 0x1F -#define HID_KEY_3 0x20 -#define HID_KEY_4 0x21 -#define HID_KEY_5 0x22 -#define HID_KEY_6 0x23 -#define HID_KEY_7 0x24 -#define HID_KEY_8 0x25 -#define HID_KEY_9 0x26 -#define HID_KEY_0 0x27 -#define HID_KEY_ENTER 0x28 -#define HID_KEY_ESCAPE 0x29 -#define HID_KEY_BACKSPACE 0x2A -#define HID_KEY_TAB 0x2B -#define HID_KEY_SPACE 0x2C -#define HID_KEY_MINUS 0x2D -#define HID_KEY_EQUAL 0x2E -#define HID_KEY_BRACKET_LEFT 0x2F -#define HID_KEY_BRACKET_RIGHT 0x30 -#define HID_KEY_BACKSLASH 0x31 -#define HID_KEY_EUROPE_1 0x32 -#define HID_KEY_SEMICOLON 0x33 -#define HID_KEY_APOSTROPHE 0x34 -#define HID_KEY_GRAVE 0x35 -#define HID_KEY_COMMA 0x36 -#define HID_KEY_PERIOD 0x37 -#define HID_KEY_SLASH 0x38 -#define HID_KEY_CAPS_LOCK 0x39 -#define HID_KEY_F1 0x3A -#define HID_KEY_F2 0x3B -#define HID_KEY_F3 0x3C -#define HID_KEY_F4 0x3D -#define HID_KEY_F5 0x3E -#define HID_KEY_F6 0x3F -#define HID_KEY_F7 0x40 -#define HID_KEY_F8 0x41 -#define HID_KEY_F9 0x42 -#define HID_KEY_F10 0x43 -#define HID_KEY_F11 0x44 -#define HID_KEY_F12 0x45 -#define HID_KEY_PRINT_SCREEN 0x46 -#define HID_KEY_SCROLL_LOCK 0x47 -#define HID_KEY_PAUSE 0x48 -#define HID_KEY_INSERT 0x49 -#define HID_KEY_HOME 0x4A -#define HID_KEY_PAGE_UP 0x4B -#define HID_KEY_DELETE 0x4C -#define HID_KEY_END 0x4D -#define HID_KEY_PAGE_DOWN 0x4E -#define HID_KEY_ARROW_RIGHT 0x4F -#define HID_KEY_ARROW_LEFT 0x50 -#define HID_KEY_ARROW_DOWN 0x51 -#define HID_KEY_ARROW_UP 0x52 -#define HID_KEY_NUM_LOCK 0x53 -#define HID_KEY_KEYPAD_DIVIDE 0x54 -#define HID_KEY_KEYPAD_MULTIPLY 0x55 -#define HID_KEY_KEYPAD_SUBTRACT 0x56 -#define HID_KEY_KEYPAD_ADD 0x57 -#define HID_KEY_KEYPAD_ENTER 0x58 -#define HID_KEY_KEYPAD_1 0x59 -#define HID_KEY_KEYPAD_2 0x5A -#define HID_KEY_KEYPAD_3 0x5B -#define HID_KEY_KEYPAD_4 0x5C -#define HID_KEY_KEYPAD_5 0x5D -#define HID_KEY_KEYPAD_6 0x5E -#define HID_KEY_KEYPAD_7 0x5F -#define HID_KEY_KEYPAD_8 0x60 -#define HID_KEY_KEYPAD_9 0x61 -#define HID_KEY_KEYPAD_0 0x62 -#define HID_KEY_KEYPAD_DECIMAL 0x63 -#define HID_KEY_EUROPE_2 0x64 -#define HID_KEY_APPLICATION 0x65 -#define HID_KEY_POWER 0x66 -#define HID_KEY_KEYPAD_EQUAL 0x67 -#define HID_KEY_F13 0x68 -#define HID_KEY_F14 0x69 -#define HID_KEY_F15 0x6A -#define HID_KEY_F16 0x6B -#define HID_KEY_F17 0x6C -#define HID_KEY_F18 0x6D -#define HID_KEY_F19 0x6E -#define HID_KEY_F20 0x6F -#define HID_KEY_F21 0x70 -#define HID_KEY_F22 0x71 -#define HID_KEY_F23 0x72 -#define HID_KEY_F24 0x73 -#define HID_KEY_EXECUTE 0x74 -#define HID_KEY_HELP 0x75 -#define HID_KEY_MENU 0x76 -#define HID_KEY_SELECT 0x77 -#define HID_KEY_STOP 0x78 -#define HID_KEY_AGAIN 0x79 -#define HID_KEY_UNDO 0x7A -#define HID_KEY_CUT 0x7B -#define HID_KEY_COPY 0x7C -#define HID_KEY_PASTE 0x7D -#define HID_KEY_FIND 0x7E -#define HID_KEY_MUTE 0x7F -#define HID_KEY_VOLUME_UP 0x80 -#define HID_KEY_VOLUME_DOWN 0x81 -#define HID_KEY_LOCKING_CAPS_LOCK 0x82 -#define HID_KEY_LOCKING_NUM_LOCK 0x83 -#define HID_KEY_LOCKING_SCROLL_LOCK 0x84 -#define HID_KEY_KEYPAD_COMMA 0x85 -#define HID_KEY_KEYPAD_EQUAL_SIGN 0x86 -#define HID_KEY_KANJI1 0x87 -#define HID_KEY_KANJI2 0x88 -#define HID_KEY_KANJI3 0x89 -#define HID_KEY_KANJI4 0x8A -#define HID_KEY_KANJI5 0x8B -#define HID_KEY_KANJI6 0x8C -#define HID_KEY_KANJI7 0x8D -#define HID_KEY_KANJI8 0x8E -#define HID_KEY_KANJI9 0x8F -#define HID_KEY_LANG1 0x90 -#define HID_KEY_LANG2 0x91 -#define HID_KEY_LANG3 0x92 -#define HID_KEY_LANG4 0x93 -#define HID_KEY_LANG5 0x94 -#define HID_KEY_LANG6 0x95 -#define HID_KEY_LANG7 0x96 -#define HID_KEY_LANG8 0x97 -#define HID_KEY_LANG9 0x98 -#define HID_KEY_ALTERNATE_ERASE 0x99 -#define HID_KEY_SYSREQ_ATTENTION 0x9A -#define HID_KEY_CANCEL 0x9B -#define HID_KEY_CLEAR 0x9C -#define HID_KEY_PRIOR 0x9D -#define HID_KEY_RETURN 0x9E -#define HID_KEY_SEPARATOR 0x9F -#define HID_KEY_OUT 0xA0 -#define HID_KEY_OPER 0xA1 -#define HID_KEY_CLEAR_AGAIN 0xA2 -#define HID_KEY_CRSEL_PROPS 0xA3 -#define HID_KEY_EXSEL 0xA4 -// RESERVED 0xA5-DF -#define HID_KEY_CONTROL_LEFT 0xE0 -#define HID_KEY_SHIFT_LEFT 0xE1 -#define HID_KEY_ALT_LEFT 0xE2 -#define HID_KEY_GUI_LEFT 0xE3 -#define HID_KEY_CONTROL_RIGHT 0xE4 -#define HID_KEY_SHIFT_RIGHT 0xE5 -#define HID_KEY_ALT_RIGHT 0xE6 -#define HID_KEY_GUI_RIGHT 0xE7 - - -//--------------------------------------------------------------------+ -// REPORT DESCRIPTOR -//--------------------------------------------------------------------+ - -//------------- ITEM & TAG -------------// -#define HID_REPORT_DATA_0(data) -#define HID_REPORT_DATA_1(data) , data -#define HID_REPORT_DATA_2(data) , U16_TO_U8S_LE(data) -#define HID_REPORT_DATA_3(data) , U32_TO_U8S_LE(data) - -#define HID_REPORT_ITEM(data, tag, type, size) \ - (((tag) << 4) | ((type) << 2) | (size)) HID_REPORT_DATA_##size(data) - -// Report Item Types -enum { - RI_TYPE_MAIN = 0, - RI_TYPE_GLOBAL = 1, - RI_TYPE_LOCAL = 2 -}; - -//------------- Main Items - HID 1.11 section 6.2.2.4 -------------// - -// Report Item Main group -enum { - RI_MAIN_INPUT = 8, - RI_MAIN_OUTPUT = 9, - RI_MAIN_COLLECTION = 10, - RI_MAIN_FEATURE = 11, - RI_MAIN_COLLECTION_END = 12 -}; - -#define HID_INPUT(x) HID_REPORT_ITEM(x, RI_MAIN_INPUT , RI_TYPE_MAIN, 1) -#define HID_OUTPUT(x) HID_REPORT_ITEM(x, RI_MAIN_OUTPUT , RI_TYPE_MAIN, 1) -#define HID_COLLECTION(x) HID_REPORT_ITEM(x, RI_MAIN_COLLECTION , RI_TYPE_MAIN, 1) -#define HID_FEATURE(x) HID_REPORT_ITEM(x, RI_MAIN_FEATURE , RI_TYPE_MAIN, 1) -#define HID_COLLECTION_END HID_REPORT_ITEM(x, RI_MAIN_COLLECTION_END, RI_TYPE_MAIN, 0) - -//------------- Input, Output, Feature - HID 1.11 section 6.2.2.5 -------------// -#define HID_DATA (0<<0) -#define HID_CONSTANT (1<<0) - -#define HID_ARRAY (0<<1) -#define HID_VARIABLE (1<<1) - -#define HID_ABSOLUTE (0<<2) -#define HID_RELATIVE (1<<2) - -#define HID_WRAP_NO (0<<3) -#define HID_WRAP (1<<3) - -#define HID_LINEAR (0<<4) -#define HID_NONLINEAR (1<<4) - -#define HID_PREFERRED_STATE (0<<5) -#define HID_PREFERRED_NO (1<<5) - -#define HID_NO_NULL_POSITION (0<<6) -#define HID_NULL_STATE (1<<6) - -#define HID_NON_VOLATILE (0<<7) -#define HID_VOLATILE (1<<7) - -#define HID_BITFIELD (0<<8) -#define HID_BUFFERED_BYTES (1<<8) - -//------------- Collection Item - HID 1.11 section 6.2.2.6 -------------// -enum { - HID_COLLECTION_PHYSICAL = 0, - HID_COLLECTION_APPLICATION, - HID_COLLECTION_LOGICAL, - HID_COLLECTION_REPORT, - HID_COLLECTION_NAMED_ARRAY, - HID_COLLECTION_USAGE_SWITCH, - HID_COLLECTION_USAGE_MODIFIER -}; - -//------------- Global Items - HID 1.11 section 6.2.2.7 -------------// - -// Report Item Global group -enum { - RI_GLOBAL_USAGE_PAGE = 0, - RI_GLOBAL_LOGICAL_MIN = 1, - RI_GLOBAL_LOGICAL_MAX = 2, - RI_GLOBAL_PHYSICAL_MIN = 3, - RI_GLOBAL_PHYSICAL_MAX = 4, - RI_GLOBAL_UNIT_EXPONENT = 5, - RI_GLOBAL_UNIT = 6, - RI_GLOBAL_REPORT_SIZE = 7, - RI_GLOBAL_REPORT_ID = 8, - RI_GLOBAL_REPORT_COUNT = 9, - RI_GLOBAL_PUSH = 10, - RI_GLOBAL_POP = 11 -}; - -#define HID_USAGE_PAGE(x) HID_REPORT_ITEM(x, RI_GLOBAL_USAGE_PAGE, RI_TYPE_GLOBAL, 1) -#define HID_USAGE_PAGE_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_USAGE_PAGE, RI_TYPE_GLOBAL, n) - -#define HID_LOGICAL_MIN(x) HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MIN, RI_TYPE_GLOBAL, 1) -#define HID_LOGICAL_MIN_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MIN, RI_TYPE_GLOBAL, n) - -#define HID_LOGICAL_MAX(x) HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MAX, RI_TYPE_GLOBAL, 1) -#define HID_LOGICAL_MAX_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MAX, RI_TYPE_GLOBAL, n) - -#define HID_PHYSICAL_MIN(x) HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MIN, RI_TYPE_GLOBAL, 1) -#define HID_PHYSICAL_MIN_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MIN, RI_TYPE_GLOBAL, n) - -#define HID_PHYSICAL_MAX(x) HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MAX, RI_TYPE_GLOBAL, 1) -#define HID_PHYSICAL_MAX_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MAX, RI_TYPE_GLOBAL, n) - -#define HID_UNIT_EXPONENT(x) HID_REPORT_ITEM(x, RI_GLOBAL_UNIT_EXPONENT, RI_TYPE_GLOBAL, 1) -#define HID_UNIT_EXPONENT_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_UNIT_EXPONENT, RI_TYPE_GLOBAL, n) - -#define HID_UNIT(x) HID_REPORT_ITEM(x, RI_GLOBAL_UNIT, RI_TYPE_GLOBAL, 1) -#define HID_UNIT_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_UNIT, RI_TYPE_GLOBAL, n) - -#define HID_REPORT_SIZE(x) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_SIZE, RI_TYPE_GLOBAL, 1) -#define HID_REPORT_SIZE_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_SIZE, RI_TYPE_GLOBAL, n) - -#define HID_REPORT_ID(x) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_ID, RI_TYPE_GLOBAL, 1), -#define HID_REPORT_ID_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_ID, RI_TYPE_GLOBAL, n), - -#define HID_REPORT_COUNT(x) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_COUNT, RI_TYPE_GLOBAL, 1) -#define HID_REPORT_COUNT_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_COUNT, RI_TYPE_GLOBAL, n) - -#define HID_PUSH HID_REPORT_ITEM(x, RI_GLOBAL_PUSH, RI_TYPE_GLOBAL, 0) -#define HID_POP HID_REPORT_ITEM(x, RI_GLOBAL_POP, RI_TYPE_GLOBAL, 0) - -//------------- LOCAL ITEMS 6.2.2.8 -------------// - -enum { - RI_LOCAL_USAGE = 0, - RI_LOCAL_USAGE_MIN = 1, - RI_LOCAL_USAGE_MAX = 2, - RI_LOCAL_DESIGNATOR_INDEX = 3, - RI_LOCAL_DESIGNATOR_MIN = 4, - RI_LOCAL_DESIGNATOR_MAX = 5, - // 6 is reserved - RI_LOCAL_STRING_INDEX = 7, - RI_LOCAL_STRING_MIN = 8, - RI_LOCAL_STRING_MAX = 9, - RI_LOCAL_DELIMITER = 10, -}; - -#define HID_USAGE(x) HID_REPORT_ITEM(x, RI_LOCAL_USAGE, RI_TYPE_LOCAL, 1) -#define HID_USAGE_N(x, n) HID_REPORT_ITEM(x, RI_LOCAL_USAGE, RI_TYPE_LOCAL, n) - -#define HID_USAGE_MIN(x) HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MIN, RI_TYPE_LOCAL, 1) -#define HID_USAGE_MIN_N(x, n) HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MIN, RI_TYPE_LOCAL, n) - -#define HID_USAGE_MAX(x) HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MAX, RI_TYPE_LOCAL, 1) -#define HID_USAGE_MAX_N(x, n) HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MAX, RI_TYPE_LOCAL, n) - -//--------------------------------------------------------------------+ -// Usage Table -//--------------------------------------------------------------------+ - -/// HID Usage Table - Table 1: Usage Page Summary -enum { - HID_USAGE_PAGE_DESKTOP = 0x01, - HID_USAGE_PAGE_SIMULATE = 0x02, - HID_USAGE_PAGE_VIRTUAL_REALITY = 0x03, - HID_USAGE_PAGE_SPORT = 0x04, - HID_USAGE_PAGE_GAME = 0x05, - HID_USAGE_PAGE_GENERIC_DEVICE = 0x06, - HID_USAGE_PAGE_KEYBOARD = 0x07, - HID_USAGE_PAGE_LED = 0x08, - HID_USAGE_PAGE_BUTTON = 0x09, - HID_USAGE_PAGE_ORDINAL = 0x0a, - HID_USAGE_PAGE_TELEPHONY = 0x0b, - HID_USAGE_PAGE_CONSUMER = 0x0c, - HID_USAGE_PAGE_DIGITIZER = 0x0d, - HID_USAGE_PAGE_PID = 0x0f, - HID_USAGE_PAGE_UNICODE = 0x10, - HID_USAGE_PAGE_ALPHA_DISPLAY = 0x14, - HID_USAGE_PAGE_MEDICAL = 0x40, - HID_USAGE_PAGE_MONITOR = 0x80, //0x80 - 0x83 - HID_USAGE_PAGE_POWER = 0x84, // 0x084 - 0x87 - HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c, - HID_USAGE_PAGE_SCALE = 0x8d, - HID_USAGE_PAGE_MSR = 0x8e, - HID_USAGE_PAGE_CAMERA = 0x90, - HID_USAGE_PAGE_ARCADE = 0x91, - HID_USAGE_PAGE_FIDO = 0xF1D0, // FIDO alliance HID usage page - HID_USAGE_PAGE_VENDOR = 0xFF00 // 0xFF00 - 0xFFFF -}; - -/// HID Usage Table - Table 6: Generic Desktop Page -enum { - HID_USAGE_DESKTOP_POINTER = 0x01, - HID_USAGE_DESKTOP_MOUSE = 0x02, - HID_USAGE_DESKTOP_JOYSTICK = 0x04, - HID_USAGE_DESKTOP_GAMEPAD = 0x05, - HID_USAGE_DESKTOP_KEYBOARD = 0x06, - HID_USAGE_DESKTOP_KEYPAD = 0x07, - HID_USAGE_DESKTOP_MULTI_AXIS_CONTROLLER = 0x08, - HID_USAGE_DESKTOP_TABLET_PC_SYSTEM = 0x09, - HID_USAGE_DESKTOP_X = 0x30, - HID_USAGE_DESKTOP_Y = 0x31, - HID_USAGE_DESKTOP_Z = 0x32, - HID_USAGE_DESKTOP_RX = 0x33, - HID_USAGE_DESKTOP_RY = 0x34, - HID_USAGE_DESKTOP_RZ = 0x35, - HID_USAGE_DESKTOP_SLIDER = 0x36, - HID_USAGE_DESKTOP_DIAL = 0x37, - HID_USAGE_DESKTOP_WHEEL = 0x38, - HID_USAGE_DESKTOP_HAT_SWITCH = 0x39, - HID_USAGE_DESKTOP_COUNTED_BUFFER = 0x3a, - HID_USAGE_DESKTOP_BYTE_COUNT = 0x3b, - HID_USAGE_DESKTOP_MOTION_WAKEUP = 0x3c, - HID_USAGE_DESKTOP_START = 0x3d, - HID_USAGE_DESKTOP_SELECT = 0x3e, - HID_USAGE_DESKTOP_VX = 0x40, - HID_USAGE_DESKTOP_VY = 0x41, - HID_USAGE_DESKTOP_VZ = 0x42, - HID_USAGE_DESKTOP_VBRX = 0x43, - HID_USAGE_DESKTOP_VBRY = 0x44, - HID_USAGE_DESKTOP_VBRZ = 0x45, - HID_USAGE_DESKTOP_VNO = 0x46, - HID_USAGE_DESKTOP_FEATURE_NOTIFICATION = 0x47, - HID_USAGE_DESKTOP_RESOLUTION_MULTIPLIER = 0x48, - HID_USAGE_DESKTOP_SYSTEM_CONTROL = 0x80, - HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN = 0x81, - HID_USAGE_DESKTOP_SYSTEM_SLEEP = 0x82, - HID_USAGE_DESKTOP_SYSTEM_WAKE_UP = 0x83, - HID_USAGE_DESKTOP_SYSTEM_CONTEXT_MENU = 0x84, - HID_USAGE_DESKTOP_SYSTEM_MAIN_MENU = 0x85, - HID_USAGE_DESKTOP_SYSTEM_APP_MENU = 0x86, - HID_USAGE_DESKTOP_SYSTEM_MENU_HELP = 0x87, - HID_USAGE_DESKTOP_SYSTEM_MENU_EXIT = 0x88, - HID_USAGE_DESKTOP_SYSTEM_MENU_SELECT = 0x89, - HID_USAGE_DESKTOP_SYSTEM_MENU_RIGHT = 0x8A, - HID_USAGE_DESKTOP_SYSTEM_MENU_LEFT = 0x8B, - HID_USAGE_DESKTOP_SYSTEM_MENU_UP = 0x8C, - HID_USAGE_DESKTOP_SYSTEM_MENU_DOWN = 0x8D, - HID_USAGE_DESKTOP_SYSTEM_COLD_RESTART = 0x8E, - HID_USAGE_DESKTOP_SYSTEM_WARM_RESTART = 0x8F, - HID_USAGE_DESKTOP_DPAD_UP = 0x90, - HID_USAGE_DESKTOP_DPAD_DOWN = 0x91, - HID_USAGE_DESKTOP_DPAD_RIGHT = 0x92, - HID_USAGE_DESKTOP_DPAD_LEFT = 0x93, - HID_USAGE_DESKTOP_SYSTEM_DOCK = 0xA0, - HID_USAGE_DESKTOP_SYSTEM_UNDOCK = 0xA1, - HID_USAGE_DESKTOP_SYSTEM_SETUP = 0xA2, - HID_USAGE_DESKTOP_SYSTEM_BREAK = 0xA3, - HID_USAGE_DESKTOP_SYSTEM_DEBUGGER_BREAK = 0xA4, - HID_USAGE_DESKTOP_APPLICATION_BREAK = 0xA5, - HID_USAGE_DESKTOP_APPLICATION_DEBUGGER_BREAK = 0xA6, - HID_USAGE_DESKTOP_SYSTEM_SPEAKER_MUTE = 0xA7, - HID_USAGE_DESKTOP_SYSTEM_HIBERNATE = 0xA8, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INVERT = 0xB0, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INTERNAL = 0xB1, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_EXTERNAL = 0xB2, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_BOTH = 0xB3, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_DUAL = 0xB4, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_TOGGLE_INT_EXT = 0xB5, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_SWAP_PRIMARY_SECONDARY = 0xB6, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_LCD_AUTOSCALE = 0xB7 -}; - - -/// HID Usage Table: Consumer Page (0x0C) -/// Only contains controls that supported by Windows (whole list is too long) -enum -{ - // Generic Control - HID_USAGE_CONSUMER_CONTROL = 0x0001, - - // Power Control - HID_USAGE_CONSUMER_POWER = 0x0030, - HID_USAGE_CONSUMER_RESET = 0x0031, - HID_USAGE_CONSUMER_SLEEP = 0x0032, - - // Screen Brightness - HID_USAGE_CONSUMER_BRIGHTNESS_INCREMENT = 0x006F, - HID_USAGE_CONSUMER_BRIGHTNESS_DECREMENT = 0x0070, - - // These HID usages operate only on mobile systems (battery powered) and - // require Windows 8 (build 8302 or greater). - HID_USAGE_CONSUMER_WIRELESS_RADIO_CONTROLS = 0x000C, - HID_USAGE_CONSUMER_WIRELESS_RADIO_BUTTONS = 0x00C6, - HID_USAGE_CONSUMER_WIRELESS_RADIO_LED = 0x00C7, - HID_USAGE_CONSUMER_WIRELESS_RADIO_SLIDER_SWITCH = 0x00C8, - - // Media Control - HID_USAGE_CONSUMER_PLAY_PAUSE = 0x00CD, - HID_USAGE_CONSUMER_SCAN_NEXT = 0x00B5, - HID_USAGE_CONSUMER_SCAN_PREVIOUS = 0x00B6, - HID_USAGE_CONSUMER_STOP = 0x00B7, - HID_USAGE_CONSUMER_VOLUME = 0x00E0, - HID_USAGE_CONSUMER_MUTE = 0x00E2, - HID_USAGE_CONSUMER_BASS = 0x00E3, - HID_USAGE_CONSUMER_TREBLE = 0x00E4, - HID_USAGE_CONSUMER_BASS_BOOST = 0x00E5, - HID_USAGE_CONSUMER_VOLUME_INCREMENT = 0x00E9, - HID_USAGE_CONSUMER_VOLUME_DECREMENT = 0x00EA, - HID_USAGE_CONSUMER_BASS_INCREMENT = 0x0152, - HID_USAGE_CONSUMER_BASS_DECREMENT = 0x0153, - HID_USAGE_CONSUMER_TREBLE_INCREMENT = 0x0154, - HID_USAGE_CONSUMER_TREBLE_DECREMENT = 0x0155, - - // Application Launcher - HID_USAGE_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION = 0x0183, - HID_USAGE_CONSUMER_AL_EMAIL_READER = 0x018A, - HID_USAGE_CONSUMER_AL_CALCULATOR = 0x0192, - HID_USAGE_CONSUMER_AL_LOCAL_BROWSER = 0x0194, - - // Browser/Explorer Specific - HID_USAGE_CONSUMER_AC_SEARCH = 0x0221, - HID_USAGE_CONSUMER_AC_HOME = 0x0223, - HID_USAGE_CONSUMER_AC_BACK = 0x0224, - HID_USAGE_CONSUMER_AC_FORWARD = 0x0225, - HID_USAGE_CONSUMER_AC_STOP = 0x0226, - HID_USAGE_CONSUMER_AC_REFRESH = 0x0227, - HID_USAGE_CONSUMER_AC_BOOKMARKS = 0x022A, - - // Mouse Horizontal scroll - HID_USAGE_CONSUMER_AC_PAN = 0x0238, -}; - -/// HID Usage Table: FIDO Alliance Page (0xF1D0) -enum -{ - HID_USAGE_FIDO_U2FHID = 0x01, // U2FHID usage for top-level collection - HID_USAGE_FIDO_DATA_IN = 0x20, // Raw IN data report - HID_USAGE_FIDO_DATA_OUT = 0x21 // Raw OUT data report -}; - -/*-------------------------------------------------------------------- - * ASCII to KEYCODE Conversion - * Expand to array of [128][2] (shift, keycode) - * - * Usage: example to convert input chr into keyboard report (modifier + keycode) - * - * uint8_t const conv_table[128][2] = { HID_ASCII_TO_KEYCODE }; - * - * uint8_t keycode[6] = { 0 }; - * uint8_t modifier = 0; - * - * if ( conv_table[chr][0] ) modifier = KEYBOARD_MODIFIER_LEFTSHIFT; - * keycode[0] = conv_table[chr][1]; - * tud_hid_keyboard_report(report_id, modifier, keycode); - * - *--------------------------------------------------------------------*/ -#define HID_ASCII_TO_KEYCODE \ - {0, 0 }, /* 0x00 Null */ \ - {0, 0 }, /* 0x01 */ \ - {0, 0 }, /* 0x02 */ \ - {0, 0 }, /* 0x03 */ \ - {0, 0 }, /* 0x04 */ \ - {0, 0 }, /* 0x05 */ \ - {0, 0 }, /* 0x06 */ \ - {0, 0 }, /* 0x07 */ \ - {0, HID_KEY_BACKSPACE }, /* 0x08 Backspace */ \ - {0, HID_KEY_TAB }, /* 0x09 Tab */ \ - {0, HID_KEY_ENTER }, /* 0x0A Line Feed */ \ - {0, 0 }, /* 0x0B */ \ - {0, 0 }, /* 0x0C */ \ - {0, HID_KEY_ENTER }, /* 0x0D CR */ \ - {0, 0 }, /* 0x0E */ \ - {0, 0 }, /* 0x0F */ \ - {0, 0 }, /* 0x10 */ \ - {0, 0 }, /* 0x11 */ \ - {0, 0 }, /* 0x12 */ \ - {0, 0 }, /* 0x13 */ \ - {0, 0 }, /* 0x14 */ \ - {0, 0 }, /* 0x15 */ \ - {0, 0 }, /* 0x16 */ \ - {0, 0 }, /* 0x17 */ \ - {0, 0 }, /* 0x18 */ \ - {0, 0 }, /* 0x19 */ \ - {0, 0 }, /* 0x1A */ \ - {0, HID_KEY_ESCAPE }, /* 0x1B Escape */ \ - {0, 0 }, /* 0x1C */ \ - {0, 0 }, /* 0x1D */ \ - {0, 0 }, /* 0x1E */ \ - {0, 0 }, /* 0x1F */ \ - \ - {0, HID_KEY_SPACE }, /* 0x20 */ \ - {1, HID_KEY_1 }, /* 0x21 ! */ \ - {1, HID_KEY_APOSTROPHE }, /* 0x22 " */ \ - {1, HID_KEY_3 }, /* 0x23 # */ \ - {1, HID_KEY_4 }, /* 0x24 $ */ \ - {1, HID_KEY_5 }, /* 0x25 % */ \ - {1, HID_KEY_7 }, /* 0x26 & */ \ - {0, HID_KEY_APOSTROPHE }, /* 0x27 ' */ \ - {1, HID_KEY_9 }, /* 0x28 ( */ \ - {1, HID_KEY_0 }, /* 0x29 ) */ \ - {1, HID_KEY_8 }, /* 0x2A * */ \ - {1, HID_KEY_EQUAL }, /* 0x2B + */ \ - {0, HID_KEY_COMMA }, /* 0x2C , */ \ - {0, HID_KEY_MINUS }, /* 0x2D - */ \ - {0, HID_KEY_PERIOD }, /* 0x2E . */ \ - {0, HID_KEY_SLASH }, /* 0x2F / */ \ - {0, HID_KEY_0 }, /* 0x30 0 */ \ - {0, HID_KEY_1 }, /* 0x31 1 */ \ - {0, HID_KEY_2 }, /* 0x32 2 */ \ - {0, HID_KEY_3 }, /* 0x33 3 */ \ - {0, HID_KEY_4 }, /* 0x34 4 */ \ - {0, HID_KEY_5 }, /* 0x35 5 */ \ - {0, HID_KEY_6 }, /* 0x36 6 */ \ - {0, HID_KEY_7 }, /* 0x37 7 */ \ - {0, HID_KEY_8 }, /* 0x38 8 */ \ - {0, HID_KEY_9 }, /* 0x39 9 */ \ - {1, HID_KEY_SEMICOLON }, /* 0x3A : */ \ - {0, HID_KEY_SEMICOLON }, /* 0x3B ; */ \ - {1, HID_KEY_COMMA }, /* 0x3C < */ \ - {0, HID_KEY_EQUAL }, /* 0x3D = */ \ - {1, HID_KEY_PERIOD }, /* 0x3E > */ \ - {1, HID_KEY_SLASH }, /* 0x3F ? */ \ - \ - {1, HID_KEY_2 }, /* 0x40 @ */ \ - {1, HID_KEY_A }, /* 0x41 A */ \ - {1, HID_KEY_B }, /* 0x42 B */ \ - {1, HID_KEY_C }, /* 0x43 C */ \ - {1, HID_KEY_D }, /* 0x44 D */ \ - {1, HID_KEY_E }, /* 0x45 E */ \ - {1, HID_KEY_F }, /* 0x46 F */ \ - {1, HID_KEY_G }, /* 0x47 G */ \ - {1, HID_KEY_H }, /* 0x48 H */ \ - {1, HID_KEY_I }, /* 0x49 I */ \ - {1, HID_KEY_J }, /* 0x4A J */ \ - {1, HID_KEY_K }, /* 0x4B K */ \ - {1, HID_KEY_L }, /* 0x4C L */ \ - {1, HID_KEY_M }, /* 0x4D M */ \ - {1, HID_KEY_N }, /* 0x4E N */ \ - {1, HID_KEY_O }, /* 0x4F O */ \ - {1, HID_KEY_P }, /* 0x50 P */ \ - {1, HID_KEY_Q }, /* 0x51 Q */ \ - {1, HID_KEY_R }, /* 0x52 R */ \ - {1, HID_KEY_S }, /* 0x53 S */ \ - {1, HID_KEY_T }, /* 0x55 T */ \ - {1, HID_KEY_U }, /* 0x55 U */ \ - {1, HID_KEY_V }, /* 0x56 V */ \ - {1, HID_KEY_W }, /* 0x57 W */ \ - {1, HID_KEY_X }, /* 0x58 X */ \ - {1, HID_KEY_Y }, /* 0x59 Y */ \ - {1, HID_KEY_Z }, /* 0x5A Z */ \ - {0, HID_KEY_BRACKET_LEFT }, /* 0x5B [ */ \ - {0, HID_KEY_BACKSLASH }, /* 0x5C '\' */ \ - {0, HID_KEY_BRACKET_RIGHT }, /* 0x5D ] */ \ - {1, HID_KEY_6 }, /* 0x5E ^ */ \ - {1, HID_KEY_MINUS }, /* 0x5F _ */ \ - \ - {0, HID_KEY_GRAVE }, /* 0x60 ` */ \ - {0, HID_KEY_A }, /* 0x61 a */ \ - {0, HID_KEY_B }, /* 0x62 b */ \ - {0, HID_KEY_C }, /* 0x63 c */ \ - {0, HID_KEY_D }, /* 0x66 d */ \ - {0, HID_KEY_E }, /* 0x65 e */ \ - {0, HID_KEY_F }, /* 0x66 f */ \ - {0, HID_KEY_G }, /* 0x67 g */ \ - {0, HID_KEY_H }, /* 0x68 h */ \ - {0, HID_KEY_I }, /* 0x69 i */ \ - {0, HID_KEY_J }, /* 0x6A j */ \ - {0, HID_KEY_K }, /* 0x6B k */ \ - {0, HID_KEY_L }, /* 0x6C l */ \ - {0, HID_KEY_M }, /* 0x6D m */ \ - {0, HID_KEY_N }, /* 0x6E n */ \ - {0, HID_KEY_O }, /* 0x6F o */ \ - {0, HID_KEY_P }, /* 0x70 p */ \ - {0, HID_KEY_Q }, /* 0x71 q */ \ - {0, HID_KEY_R }, /* 0x72 r */ \ - {0, HID_KEY_S }, /* 0x73 s */ \ - {0, HID_KEY_T }, /* 0x75 t */ \ - {0, HID_KEY_U }, /* 0x75 u */ \ - {0, HID_KEY_V }, /* 0x76 v */ \ - {0, HID_KEY_W }, /* 0x77 w */ \ - {0, HID_KEY_X }, /* 0x78 x */ \ - {0, HID_KEY_Y }, /* 0x79 y */ \ - {0, HID_KEY_Z }, /* 0x7A z */ \ - {1, HID_KEY_BRACKET_LEFT }, /* 0x7B { */ \ - {1, HID_KEY_BACKSLASH }, /* 0x7C | */ \ - {1, HID_KEY_BRACKET_RIGHT }, /* 0x7D } */ \ - {1, HID_KEY_GRAVE }, /* 0x7E ~ */ \ - {0, HID_KEY_DELETE } /* 0x7F Delete */ \ - -/*-------------------------------------------------------------------- - * KEYCODE to Ascii Conversion - * Expand to array of [128][2] (ascii without shift, ascii with shift) - * - * Usage: example to convert ascii from keycode (key) and shift modifier (shift). - * Here we assume key < 128 ( printable ) - * - * uint8_t const conv_table[128][2] = { HID_KEYCODE_TO_ASCII }; - * char ch = shift ? conv_table[chr][1] : conv_table[chr][0]; - * - *--------------------------------------------------------------------*/ -#define HID_KEYCODE_TO_ASCII \ - {0 , 0 }, /* 0x00 */ \ - {0 , 0 }, /* 0x01 */ \ - {0 , 0 }, /* 0x02 */ \ - {0 , 0 }, /* 0x03 */ \ - {'a' , 'A' }, /* 0x04 */ \ - {'b' , 'B' }, /* 0x05 */ \ - {'c' , 'C' }, /* 0x06 */ \ - {'d' , 'D' }, /* 0x07 */ \ - {'e' , 'E' }, /* 0x08 */ \ - {'f' , 'F' }, /* 0x09 */ \ - {'g' , 'G' }, /* 0x0a */ \ - {'h' , 'H' }, /* 0x0b */ \ - {'i' , 'I' }, /* 0x0c */ \ - {'j' , 'J' }, /* 0x0d */ \ - {'k' , 'K' }, /* 0x0e */ \ - {'l' , 'L' }, /* 0x0f */ \ - {'m' , 'M' }, /* 0x10 */ \ - {'n' , 'N' }, /* 0x11 */ \ - {'o' , 'O' }, /* 0x12 */ \ - {'p' , 'P' }, /* 0x13 */ \ - {'q' , 'Q' }, /* 0x14 */ \ - {'r' , 'R' }, /* 0x15 */ \ - {'s' , 'S' }, /* 0x16 */ \ - {'t' , 'T' }, /* 0x17 */ \ - {'u' , 'U' }, /* 0x18 */ \ - {'v' , 'V' }, /* 0x19 */ \ - {'w' , 'W' }, /* 0x1a */ \ - {'x' , 'X' }, /* 0x1b */ \ - {'y' , 'Y' }, /* 0x1c */ \ - {'z' , 'Z' }, /* 0x1d */ \ - {'1' , '!' }, /* 0x1e */ \ - {'2' , '@' }, /* 0x1f */ \ - {'3' , '#' }, /* 0x20 */ \ - {'4' , '$' }, /* 0x21 */ \ - {'5' , '%' }, /* 0x22 */ \ - {'6' , '^' }, /* 0x23 */ \ - {'7' , '&' }, /* 0x24 */ \ - {'8' , '*' }, /* 0x25 */ \ - {'9' , '(' }, /* 0x26 */ \ - {'0' , ')' }, /* 0x27 */ \ - {'\r' , '\r' }, /* 0x28 */ \ - {'\x1b', '\x1b' }, /* 0x29 */ \ - {'\b' , '\b' }, /* 0x2a */ \ - {'\t' , '\t' }, /* 0x2b */ \ - {' ' , ' ' }, /* 0x2c */ \ - {'-' , '_' }, /* 0x2d */ \ - {'=' , '+' }, /* 0x2e */ \ - {'[' , '{' }, /* 0x2f */ \ - {']' , '}' }, /* 0x30 */ \ - {'\\' , '|' }, /* 0x31 */ \ - {'#' , '~' }, /* 0x32 */ \ - {';' , ':' }, /* 0x33 */ \ - {'\'' , '\"' }, /* 0x34 */ \ - {'`' , '~' }, /* 0x35 */ \ - {',' , '<' }, /* 0x36 */ \ - {'.' , '>' }, /* 0x37 */ \ - {'/' , '?' }, /* 0x38 */ \ - \ - {0 , 0 }, /* 0x39 */ \ - {0 , 0 }, /* 0x3a */ \ - {0 , 0 }, /* 0x3b */ \ - {0 , 0 }, /* 0x3c */ \ - {0 , 0 }, /* 0x3d */ \ - {0 , 0 }, /* 0x3e */ \ - {0 , 0 }, /* 0x3f */ \ - {0 , 0 }, /* 0x40 */ \ - {0 , 0 }, /* 0x41 */ \ - {0 , 0 }, /* 0x42 */ \ - {0 , 0 }, /* 0x43 */ \ - {0 , 0 }, /* 0x44 */ \ - {0 , 0 }, /* 0x45 */ \ - {0 , 0 }, /* 0x46 */ \ - {0 , 0 }, /* 0x47 */ \ - {0 , 0 }, /* 0x48 */ \ - {0 , 0 }, /* 0x49 */ \ - {0 , 0 }, /* 0x4a */ \ - {0 , 0 }, /* 0x4b */ \ - {0 , 0 }, /* 0x4c */ \ - {0 , 0 }, /* 0x4d */ \ - {0 , 0 }, /* 0x4e */ \ - {0 , 0 }, /* 0x4f */ \ - {0 , 0 }, /* 0x50 */ \ - {0 , 0 }, /* 0x51 */ \ - {0 , 0 }, /* 0x52 */ \ - {0 , 0 }, /* 0x53 */ \ - \ - {'/' , '/' }, /* 0x54 */ \ - {'*' , '*' }, /* 0x55 */ \ - {'-' , '-' }, /* 0x56 */ \ - {'+' , '+' }, /* 0x57 */ \ - {'\r' , '\r' }, /* 0x58 */ \ - {'1' , 0 }, /* 0x59 */ \ - {'2' , 0 }, /* 0x5a */ \ - {'3' , 0 }, /* 0x5b */ \ - {'4' , 0 }, /* 0x5c */ \ - {'5' , '5' }, /* 0x5d */ \ - {'6' , 0 }, /* 0x5e */ \ - {'7' , 0 }, /* 0x5f */ \ - {'8' , 0 }, /* 0x60 */ \ - {'9' , 0 }, /* 0x61 */ \ - {'0' , 0 }, /* 0x62 */ \ - {'.' , 0 }, /* 0x63 */ \ - {0 , 0 }, /* 0x64 */ \ - {0 , 0 }, /* 0x65 */ \ - {0 , 0 }, /* 0x66 */ \ - {'=' , '=' }, /* 0x67 */ \ - - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_HID_H__ */ - -/// @} diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.c deleted file mode 100644 index 9240fe2c..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.c +++ /dev/null @@ -1,415 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_HID) - -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "hid_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -typedef struct -{ - uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; // optional Out endpoint - uint8_t itf_protocol; // Boot mouse or keyboard - - uint8_t protocol_mode; // Boot (0) or Report protocol (1) - uint8_t idle_rate; // up to application to handle idle rate - uint16_t report_desc_len; - - CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE]; - - // TODO save hid descriptor since host can specifically request this after enumeration - // Note: HID descriptor may be not available from application after enumeration - tusb_hid_descriptor_hid_t const * hid_descriptor; -} hidd_interface_t; - -CFG_TUSB_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID]; - -/*------------- Helpers -------------*/ -static inline uint8_t get_index_by_itfnum(uint8_t itf_num) -{ - for (uint8_t i=0; i < CFG_TUD_HID; i++ ) - { - if ( itf_num == _hidd_itf[i].itf_num ) return i; - } - - return 0xFF; -} - -//--------------------------------------------------------------------+ -// APPLICATION API -//--------------------------------------------------------------------+ -bool tud_hid_n_ready(uint8_t instance) -{ - uint8_t const rhport = 0; - uint8_t const ep_in = _hidd_itf[instance].ep_in; - return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(rhport, ep_in); -} - -bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint16_t len) -{ - uint8_t const rhport = 0; - hidd_interface_t * p_hid = &_hidd_itf[instance]; - - // claim endpoint - TU_VERIFY( usbd_edpt_claim(rhport, p_hid->ep_in) ); - - // prepare data - if (report_id) - { - p_hid->epin_buf[0] = report_id; - TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf+1, CFG_TUD_HID_EP_BUFSIZE-1, report, len)); - len++; - }else - { - TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf, CFG_TUD_HID_EP_BUFSIZE, report, len)); - } - - return usbd_edpt_xfer(rhport, p_hid->ep_in, p_hid->epin_buf, len); -} - -uint8_t tud_hid_n_interface_protocol(uint8_t instance) -{ - return _hidd_itf[instance].itf_protocol; -} - -uint8_t tud_hid_n_get_protocol(uint8_t instance) -{ - return _hidd_itf[instance].protocol_mode; -} - -bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6]) -{ - hid_keyboard_report_t report; - - report.modifier = modifier; - report.reserved = 0; - - if ( keycode ) - { - memcpy(report.keycode, keycode, sizeof(report.keycode)); - }else - { - tu_memclr(report.keycode, 6); - } - - return tud_hid_n_report(instance, report_id, &report, sizeof(report)); -} - -bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, - uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) -{ - hid_mouse_report_t report = - { - .buttons = buttons, - .x = x, - .y = y, - .wheel = vertical, - .pan = horizontal - }; - - return tud_hid_n_report(instance, report_id, &report, sizeof(report)); -} - -bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, - int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) { - hid_gamepad_report_t report = - { - .x = x, - .y = y, - .z = z, - .rz = rz, - .rx = rx, - .ry = ry, - .hat = hat, - .buttons = buttons, - }; - - return tud_hid_n_report(instance, report_id, &report, sizeof(report)); -} - -//--------------------------------------------------------------------+ -// USBD-CLASS API -//--------------------------------------------------------------------+ -void hidd_init(void) -{ - hidd_reset(0); -} - -void hidd_reset(uint8_t rhport) -{ - (void) rhport; - tu_memclr(_hidd_itf, sizeof(_hidd_itf)); -} - -uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) - { - TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0); - - // len = interface + hid + n*endpoints - uint16_t const drv_len = - (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + - desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); - TU_ASSERT(max_len >= drv_len, 0); - - // Find available interface - hidd_interface_t * p_hid = NULL; - uint8_t hid_id; - for(hid_id=0; hid_idhid_descriptor = (tusb_hid_descriptor_hid_t const *) p_desc; - - //------------- Endpoint Descriptor -------------// - p_desc = tu_desc_next(p_desc); - TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_INTERRUPT, &p_hid->ep_out, &p_hid->ep_in), 0); - - if ( desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT ) p_hid->itf_protocol = desc_itf->bInterfaceProtocol; - - p_hid->protocol_mode = HID_PROTOCOL_REPORT; // Per Specs: default is report mode - p_hid->itf_num = desc_itf->bInterfaceNumber; - - // Use offsetof to avoid pointer to the odd/misaligned address - p_hid->report_desc_len = tu_unaligned_read16((uint8_t const*) p_hid->hid_descriptor + offsetof(tusb_hid_descriptor_hid_t, wReportLength)); - - // Prepare for output endpoint - if (p_hid->ep_out) - { - if ( !usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)) ) - { - TU_LOG_FAILED(); - TU_BREAKPOINT(); - } - } - - return drv_len; -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); - - uint8_t const hid_itf = get_index_by_itfnum((uint8_t) request->wIndex); - TU_VERIFY(hid_itf < CFG_TUD_HID); - - hidd_interface_t* p_hid = &_hidd_itf[hid_itf]; - - if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) - { - //------------- STD Request -------------// - if ( stage == CONTROL_STAGE_SETUP ) - { - uint8_t const desc_type = tu_u16_high(request->wValue); - //uint8_t const desc_index = tu_u16_low (request->wValue); - - if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_HID) - { - TU_VERIFY(p_hid->hid_descriptor); - TU_VERIFY(tud_control_xfer(rhport, request, (void*)(uintptr_t) p_hid->hid_descriptor, p_hid->hid_descriptor->bLength)); - } - else if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT) - { - uint8_t const * desc_report = tud_hid_descriptor_report_cb(hid_itf); - tud_control_xfer(rhport, request, (void*)(uintptr_t) desc_report, p_hid->report_desc_len); - } - else - { - return false; // stall unsupported request - } - } - } - else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) - { - //------------- Class Specific Request -------------// - switch( request->bRequest ) - { - case HID_REQ_CONTROL_GET_REPORT: - if ( stage == CONTROL_STAGE_SETUP ) - { - uint8_t const report_type = tu_u16_high(request->wValue); - uint8_t const report_id = tu_u16_low(request->wValue); - - uint8_t* report_buf = p_hid->epin_buf; - uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); - - uint16_t xferlen = 0; - - // If host request a specific Report ID, add ID to as 1 byte of response - if ( (report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1) ) - { - *report_buf++ = report_id; - req_len--; - - xferlen++; - } - - xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len); - TU_ASSERT( xferlen > 0 ); - - tud_control_xfer(rhport, request, p_hid->epin_buf, xferlen); - } - break; - - case HID_REQ_CONTROL_SET_REPORT: - if ( stage == CONTROL_STAGE_SETUP ) - { - TU_VERIFY(request->wLength <= sizeof(p_hid->epout_buf)); - tud_control_xfer(rhport, request, p_hid->epout_buf, request->wLength); - } - else if ( stage == CONTROL_STAGE_ACK ) - { - uint8_t const report_type = tu_u16_high(request->wValue); - uint8_t const report_id = tu_u16_low(request->wValue); - - uint8_t const* report_buf = p_hid->epout_buf; - uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); - - // If host request a specific Report ID, extract report ID in buffer before invoking callback - if ( (report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0]) ) - { - report_buf++; - report_len--; - } - - tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, report_len); - } - break; - - case HID_REQ_CONTROL_SET_IDLE: - if ( stage == CONTROL_STAGE_SETUP ) - { - p_hid->idle_rate = tu_u16_high(request->wValue); - if ( tud_hid_set_idle_cb ) - { - // stall request if callback return false - TU_VERIFY( tud_hid_set_idle_cb( hid_itf, p_hid->idle_rate) ); - } - - tud_control_status(rhport, request); - } - break; - - case HID_REQ_CONTROL_GET_IDLE: - if ( stage == CONTROL_STAGE_SETUP ) - { - // TODO idle rate of report - tud_control_xfer(rhport, request, &p_hid->idle_rate, 1); - } - break; - - case HID_REQ_CONTROL_GET_PROTOCOL: - if ( stage == CONTROL_STAGE_SETUP ) - { - tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1); - } - break; - - case HID_REQ_CONTROL_SET_PROTOCOL: - if ( stage == CONTROL_STAGE_SETUP ) - { - tud_control_status(rhport, request); - } - else if ( stage == CONTROL_STAGE_ACK ) - { - p_hid->protocol_mode = (uint8_t) request->wValue; - if (tud_hid_set_protocol_cb) - { - tud_hid_set_protocol_cb(hid_itf, p_hid->protocol_mode); - } - } - break; - - default: return false; // stall unsupported request - } - }else - { - return false; // stall unsupported request - } - - return true; -} - -bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void) result; - - uint8_t instance = 0; - hidd_interface_t * p_hid = _hidd_itf; - - // Identify which interface to use - for (instance = 0; instance < CFG_TUD_HID; instance++) - { - p_hid = &_hidd_itf[instance]; - if ( (ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in) ) break; - } - TU_ASSERT(instance < CFG_TUD_HID); - - // Sent report successfully - if (ep_addr == p_hid->ep_in) - { - if (tud_hid_report_complete_cb) - { - tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t) xferred_bytes); - } - } - // Received report - else if (ep_addr == p_hid->ep_out) - { - tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, (uint16_t) xferred_bytes); - TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))); - } - - return true; -} - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.h deleted file mode 100644 index 17b24def..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_device.h +++ /dev/null @@ -1,418 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_HID_DEVICE_H_ -#define _TUSB_HID_DEVICE_H_ - -#include "hid.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Class Driver Default Configure & Validation -//--------------------------------------------------------------------+ - -#if !defined(CFG_TUD_HID_EP_BUFSIZE) & defined(CFG_TUD_HID_BUFSIZE) - // TODO warn user to use new name later on - // #warning CFG_TUD_HID_BUFSIZE is renamed to CFG_TUD_HID_EP_BUFSIZE, please update to use the new name - #define CFG_TUD_HID_EP_BUFSIZE CFG_TUD_HID_BUFSIZE -#endif - -#ifndef CFG_TUD_HID_EP_BUFSIZE - #define CFG_TUD_HID_EP_BUFSIZE 64 -#endif - -//--------------------------------------------------------------------+ -// Application API (Multiple Instances) -// CFG_TUD_HID > 1 -//--------------------------------------------------------------------+ - -// Check if the interface is ready to use -bool tud_hid_n_ready(uint8_t instance); - -// Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values -uint8_t tud_hid_n_interface_protocol(uint8_t instance); - -// Get current active protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) -uint8_t tud_hid_n_get_protocol(uint8_t instance); - -// Send report to host -bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint16_t len); - -// KEYBOARD: convenient helper to send keyboard report if application -// use template layout report as defined by hid_keyboard_report_t -bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6]); - -// MOUSE: convenient helper to send mouse report if application -// use template layout report as defined by hid_mouse_report_t -bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal); - -// Gamepad: convenient helper to send gamepad report if application -// use template layout report TUD_HID_REPORT_DESC_GAMEPAD -bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); - -//--------------------------------------------------------------------+ -// Application API (Single Port) -//--------------------------------------------------------------------+ -static inline bool tud_hid_ready(void); -static inline uint8_t tud_hid_interface_protocol(void); -static inline uint8_t tud_hid_get_protocol(void); -static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len); -static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]); -static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal); -static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); - -//--------------------------------------------------------------------+ -// Callbacks (Weak is optional) -//--------------------------------------------------------------------+ - -// Invoked when received GET HID REPORT DESCRIPTOR request -// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete -uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance); - -// Invoked when received GET_REPORT control request -// Application must fill buffer report's content and return its length. -// Return zero will cause the stack to STALL request -uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen); - -// Invoked when received SET_REPORT control request or -// received data on OUT endpoint ( Report ID = 0, Type = 0 ) -void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize); - -// Invoked when received SET_PROTOCOL request -// protocol is either HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) -TU_ATTR_WEAK void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol); - -// Invoked when received SET_IDLE request. return false will stall the request -// - Idle Rate = 0 : only send report if there is changes, i.e skip duplication -// - Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms). -TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate); - -// Invoked when sent REPORT successfully to host -// Application can use this to send the next report -// Note: For composite reports, report[0] is report ID -TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len); - - -//--------------------------------------------------------------------+ -// Inline Functions -//--------------------------------------------------------------------+ -static inline bool tud_hid_ready(void) -{ - return tud_hid_n_ready(0); -} - -static inline uint8_t tud_hid_interface_protocol(void) -{ - return tud_hid_n_interface_protocol(0); -} - -static inline uint8_t tud_hid_get_protocol(void) -{ - return tud_hid_n_get_protocol(0); -} - -static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len) -{ - return tud_hid_n_report(0, report_id, report, len); -} - -static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]) -{ - return tud_hid_n_keyboard_report(0, report_id, modifier, keycode); -} - -static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) -{ - return tud_hid_n_mouse_report(0, report_id, buttons, x, y, vertical, horizontal); -} - -static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) -{ - return tud_hid_n_gamepad_report(0, report_id, x, y, z, rz, rx, ry, hat, buttons); -} - -/* --------------------------------------------------------------------+ - * HID Report Descriptor Template - * - * Convenient for declaring popular HID device (keyboard, mouse, consumer, - * gamepad etc...). Templates take "HID_REPORT_ID(n)" as input, leave - * empty if multiple reports is not used - * - * - Only 1 report: no parameter - * uint8_t const report_desc[] = { TUD_HID_REPORT_DESC_KEYBOARD() }; - * - * - Multiple Reports: "HID_REPORT_ID(ID)" must be passed to template - * uint8_t const report_desc[] = - * { - * TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(1) ) , - * TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(2) ) - * }; - *--------------------------------------------------------------------*/ - -// Keyboard Report Descriptor Template -#define TUD_HID_REPORT_DESC_KEYBOARD(...) \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_KEYBOARD ) ,\ - HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ - /* Report ID if any */\ - __VA_ARGS__ \ - /* 8 bits Modifier Keys (Shift, Control, Alt) */ \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\ - HID_USAGE_MIN ( 224 ) ,\ - HID_USAGE_MAX ( 231 ) ,\ - HID_LOGICAL_MIN ( 0 ) ,\ - HID_LOGICAL_MAX ( 1 ) ,\ - HID_REPORT_COUNT ( 8 ) ,\ - HID_REPORT_SIZE ( 1 ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ - /* 8 bit reserved */ \ - HID_REPORT_COUNT ( 1 ) ,\ - HID_REPORT_SIZE ( 8 ) ,\ - HID_INPUT ( HID_CONSTANT ) ,\ - /* Output 5-bit LED Indicator Kana | Compose | ScrollLock | CapsLock | NumLock */ \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_LED ) ,\ - HID_USAGE_MIN ( 1 ) ,\ - HID_USAGE_MAX ( 5 ) ,\ - HID_REPORT_COUNT ( 5 ) ,\ - HID_REPORT_SIZE ( 1 ) ,\ - HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ - /* led padding */ \ - HID_REPORT_COUNT ( 1 ) ,\ - HID_REPORT_SIZE ( 3 ) ,\ - HID_OUTPUT ( HID_CONSTANT ) ,\ - /* 6-byte Keycodes */ \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\ - HID_USAGE_MIN ( 0 ) ,\ - HID_USAGE_MAX_N ( 255, 2 ) ,\ - HID_LOGICAL_MIN ( 0 ) ,\ - HID_LOGICAL_MAX_N( 255, 2 ) ,\ - HID_REPORT_COUNT ( 6 ) ,\ - HID_REPORT_SIZE ( 8 ) ,\ - HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\ - HID_COLLECTION_END \ - -// Mouse Report Descriptor Template -#define TUD_HID_REPORT_DESC_MOUSE(...) \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ) ,\ - HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ - /* Report ID if any */\ - __VA_ARGS__ \ - HID_USAGE ( HID_USAGE_DESKTOP_POINTER ) ,\ - HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\ - HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\ - HID_USAGE_MIN ( 1 ) ,\ - HID_USAGE_MAX ( 5 ) ,\ - HID_LOGICAL_MIN ( 0 ) ,\ - HID_LOGICAL_MAX ( 1 ) ,\ - /* Left, Right, Middle, Backward, Forward buttons */ \ - HID_REPORT_COUNT( 5 ) ,\ - HID_REPORT_SIZE ( 1 ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ - /* 3 bit padding */ \ - HID_REPORT_COUNT( 1 ) ,\ - HID_REPORT_SIZE ( 3 ) ,\ - HID_INPUT ( HID_CONSTANT ) ,\ - HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ - /* X, Y position [-127, 127] */ \ - HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\ - HID_LOGICAL_MIN ( 0x81 ) ,\ - HID_LOGICAL_MAX ( 0x7f ) ,\ - HID_REPORT_COUNT( 2 ) ,\ - HID_REPORT_SIZE ( 8 ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\ - /* Verital wheel scroll [-127, 127] */ \ - HID_USAGE ( HID_USAGE_DESKTOP_WHEEL ) ,\ - HID_LOGICAL_MIN ( 0x81 ) ,\ - HID_LOGICAL_MAX ( 0x7f ) ,\ - HID_REPORT_COUNT( 1 ) ,\ - HID_REPORT_SIZE ( 8 ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\ - HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ), \ - /* Horizontal wheel scroll [-127, 127] */ \ - HID_USAGE_N ( HID_USAGE_CONSUMER_AC_PAN, 2 ), \ - HID_LOGICAL_MIN ( 0x81 ), \ - HID_LOGICAL_MAX ( 0x7f ), \ - HID_REPORT_COUNT( 1 ), \ - HID_REPORT_SIZE ( 8 ), \ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), \ - HID_COLLECTION_END , \ - HID_COLLECTION_END \ - -// Consumer Control Report Descriptor Template -#define TUD_HID_REPORT_DESC_CONSUMER(...) \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ) ,\ - HID_USAGE ( HID_USAGE_CONSUMER_CONTROL ) ,\ - HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ - /* Report ID if any */\ - __VA_ARGS__ \ - HID_LOGICAL_MIN ( 0x00 ) ,\ - HID_LOGICAL_MAX_N( 0x03FF, 2 ) ,\ - HID_USAGE_MIN ( 0x00 ) ,\ - HID_USAGE_MAX_N ( 0x03FF, 2 ) ,\ - HID_REPORT_COUNT ( 1 ) ,\ - HID_REPORT_SIZE ( 16 ) ,\ - HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\ - HID_COLLECTION_END \ - -/* System Control Report Descriptor Template - * 0x00 - do nothing - * 0x01 - Power Off - * 0x02 - Standby - * 0x03 - Wake Host - */ -#define TUD_HID_REPORT_DESC_SYSTEM_CONTROL(...) \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_CONTROL ) ,\ - HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ - /* Report ID if any */\ - __VA_ARGS__ \ - /* 2 bit system power control */ \ - HID_LOGICAL_MIN ( 1 ) ,\ - HID_LOGICAL_MAX ( 3 ) ,\ - HID_REPORT_COUNT ( 1 ) ,\ - HID_REPORT_SIZE ( 2 ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_SLEEP ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_WAKE_UP ) ,\ - HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\ - /* 6 bit padding */ \ - HID_REPORT_COUNT ( 1 ) ,\ - HID_REPORT_SIZE ( 6 ) ,\ - HID_INPUT ( HID_CONSTANT ) ,\ - HID_COLLECTION_END \ - -// Gamepad Report Descriptor Template -// with 32 buttons, 2 joysticks and 1 hat/dpad with following layout -// | X | Y | Z | Rz | Rx | Ry (1 byte each) | hat/DPAD (1 byte) | Button Map (4 bytes) | -#define TUD_HID_REPORT_DESC_GAMEPAD(...) \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_GAMEPAD ) ,\ - HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ - /* Report ID if any */\ - __VA_ARGS__ \ - /* 8 bit X, Y, Z, Rz, Rx, Ry (min -127, max 127 ) */ \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_Z ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_RZ ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_RX ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_RY ) ,\ - HID_LOGICAL_MIN ( 0x81 ) ,\ - HID_LOGICAL_MAX ( 0x7f ) ,\ - HID_REPORT_COUNT ( 6 ) ,\ - HID_REPORT_SIZE ( 8 ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ - /* 8 bit DPad/Hat Button Map */ \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_HAT_SWITCH ) ,\ - HID_LOGICAL_MIN ( 1 ) ,\ - HID_LOGICAL_MAX ( 8 ) ,\ - HID_PHYSICAL_MIN ( 0 ) ,\ - HID_PHYSICAL_MAX_N ( 315, 2 ) ,\ - HID_REPORT_COUNT ( 1 ) ,\ - HID_REPORT_SIZE ( 8 ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ - /* 32 bit Button Map */ \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\ - HID_USAGE_MIN ( 1 ) ,\ - HID_USAGE_MAX ( 32 ) ,\ - HID_LOGICAL_MIN ( 0 ) ,\ - HID_LOGICAL_MAX ( 1 ) ,\ - HID_REPORT_COUNT ( 32 ) ,\ - HID_REPORT_SIZE ( 1 ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ - HID_COLLECTION_END \ - -// FIDO U2F Authenticator Descriptor Template -// - 1st parameter is report size, which is 64 bytes maximum in U2F -// - 2nd parameter is HID_REPORT_ID(n) (optional) -#define TUD_HID_REPORT_DESC_FIDO_U2F(report_size, ...) \ - HID_USAGE_PAGE_N ( HID_USAGE_PAGE_FIDO, 2 ) ,\ - HID_USAGE ( HID_USAGE_FIDO_U2FHID ) ,\ - HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ - /* Report ID if any */ \ - __VA_ARGS__ \ - /* Usage Data In */ \ - HID_USAGE ( HID_USAGE_FIDO_DATA_IN ) ,\ - HID_LOGICAL_MIN ( 0 ) ,\ - HID_LOGICAL_MAX_N ( 0xff, 2 ) ,\ - HID_REPORT_SIZE ( 8 ) ,\ - HID_REPORT_COUNT ( report_size ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ - /* Usage Data Out */ \ - HID_USAGE ( HID_USAGE_FIDO_DATA_OUT ) ,\ - HID_LOGICAL_MIN ( 0 ) ,\ - HID_LOGICAL_MAX_N ( 0xff, 2 ) ,\ - HID_REPORT_SIZE ( 8 ) ,\ - HID_REPORT_COUNT ( report_size ) ,\ - HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ - HID_COLLECTION_END \ - -// HID Generic Input & Output -// - 1st parameter is report size (mandatory) -// - 2nd parameter is report id HID_REPORT_ID(n) (optional) -#define TUD_HID_REPORT_DESC_GENERIC_INOUT(report_size, ...) \ - HID_USAGE_PAGE_N ( HID_USAGE_PAGE_VENDOR, 2 ),\ - HID_USAGE ( 0x01 ),\ - HID_COLLECTION ( HID_COLLECTION_APPLICATION ),\ - /* Report ID if any */\ - __VA_ARGS__ \ - /* Input */ \ - HID_USAGE ( 0x02 ),\ - HID_LOGICAL_MIN ( 0x00 ),\ - HID_LOGICAL_MAX_N ( 0xff, 2 ),\ - HID_REPORT_SIZE ( 8 ),\ - HID_REPORT_COUNT( report_size ),\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\ - /* Output */ \ - HID_USAGE ( 0x03 ),\ - HID_LOGICAL_MIN ( 0x00 ),\ - HID_LOGICAL_MAX_N ( 0xff, 2 ),\ - HID_REPORT_SIZE ( 8 ),\ - HID_REPORT_COUNT( report_size ),\ - HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\ - HID_COLLECTION_END \ - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void hidd_init (void); -void hidd_reset (uint8_t rhport); -uint16_t hidd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -bool hidd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_HID_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.c b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.c deleted file mode 100644 index d95d3ef3..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.c +++ /dev/null @@ -1,772 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUH_ENABLED && CFG_TUH_HID) - -#include "host/usbh.h" -#include "host/usbh_classdriver.h" - -#include "hid_host.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -typedef struct -{ - uint8_t daddr; - - uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; - - uint8_t itf_protocol; // None, Keyboard, Mouse - uint8_t protocol_mode; // Boot (0) or Report protocol (1) - - uint8_t report_desc_type; - uint16_t report_desc_len; - - uint16_t epin_size; - uint16_t epout_size; - - CFG_TUH_MEM_ALIGN uint8_t epin_buf[CFG_TUH_HID_EPIN_BUFSIZE]; - CFG_TUH_MEM_ALIGN uint8_t epout_buf[CFG_TUH_HID_EPOUT_BUFSIZE]; -} hidh_interface_t; - -CFG_TUH_MEM_SECTION -tu_static hidh_interface_t _hidh_itf[CFG_TUH_HID]; - -//--------------------------------------------------------------------+ -// Helper -//--------------------------------------------------------------------+ - -TU_ATTR_ALWAYS_INLINE static inline -hidh_interface_t* get_hid_itf(uint8_t daddr, uint8_t idx) -{ - TU_ASSERT(daddr && idx < CFG_TUH_HID, NULL); - hidh_interface_t* p_hid = &_hidh_itf[idx]; - return (p_hid->daddr == daddr) ? p_hid : NULL; -} - -// Get instance ID by endpoint address -static uint8_t get_idx_by_epaddr(uint8_t daddr, uint8_t ep_addr) -{ - for ( uint8_t idx = 0; idx < CFG_TUH_HID; idx++ ) - { - hidh_interface_t const * p_hid = &_hidh_itf[idx]; - - if ( p_hid->daddr == daddr && - (p_hid->ep_in == ep_addr || p_hid->ep_out == ep_addr) ) - { - return idx; - } - } - - return TUSB_INDEX_INVALID_8; -} - -static hidh_interface_t* find_new_itf(void) -{ - for(uint8_t i=0; idaddr = daddr; - - // re-construct descriptor - tusb_desc_interface_t* desc = &info->desc; - desc->bLength = sizeof(tusb_desc_interface_t); - desc->bDescriptorType = TUSB_DESC_INTERFACE; - - desc->bInterfaceNumber = p_hid->itf_num; - desc->bAlternateSetting = 0; - desc->bNumEndpoints = (uint8_t) ((p_hid->ep_in ? 1u : 0u) + (p_hid->ep_out ? 1u : 0u)); - desc->bInterfaceClass = TUSB_CLASS_HID; - desc->bInterfaceSubClass = (p_hid->itf_protocol ? HID_SUBCLASS_BOOT : HID_SUBCLASS_NONE); - desc->bInterfaceProtocol = p_hid->itf_protocol; - desc->iInterface = 0; // not used yet - - return true; -} - -uint8_t tuh_hid_itf_get_index(uint8_t daddr, uint8_t itf_num) -{ - for ( uint8_t idx = 0; idx < CFG_TUH_HID; idx++ ) - { - hidh_interface_t const * p_hid = &_hidh_itf[idx]; - - if ( p_hid->daddr == daddr && p_hid->itf_num == itf_num) return idx; - } - - return TUSB_INDEX_INVALID_8; -} - -uint8_t tuh_hid_interface_protocol(uint8_t daddr, uint8_t idx) -{ - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - return p_hid ? p_hid->itf_protocol : 0; -} - -//--------------------------------------------------------------------+ -// Control Endpoint API -//--------------------------------------------------------------------+ - -uint8_t tuh_hid_get_protocol(uint8_t daddr, uint8_t idx) -{ - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - return p_hid ? p_hid->protocol_mode : 0; -} - -static void set_protocol_complete(tuh_xfer_t* xfer) -{ - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const daddr = xfer->daddr; - uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num); - - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid, ); - - if (XFER_RESULT_SUCCESS == xfer->result) - { - p_hid->protocol_mode = (uint8_t) tu_le16toh(xfer->setup->wValue); - } - - if (tuh_hid_set_protocol_complete_cb) - { - tuh_hid_set_protocol_complete_cb(daddr, idx, p_hid->protocol_mode); - } -} - -static bool _hidh_set_protocol(uint8_t daddr, uint8_t itf_num, uint8_t protocol, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - TU_LOG2("HID Set Protocol = %d\r\n", protocol); - - tusb_control_request_t const request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = HID_REQ_CONTROL_SET_PROTOCOL, - .wValue = protocol, - .wIndex = itf_num, - .wLength = 0 - }; - - tuh_xfer_t xfer = - { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = NULL, - .complete_cb = complete_cb, - .user_data = user_data - }; - - return tuh_control_xfer(&xfer); -} - -bool tuh_hid_set_protocol(uint8_t daddr, uint8_t idx, uint8_t protocol) -{ - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid && p_hid->itf_protocol != HID_ITF_PROTOCOL_NONE); - - return _hidh_set_protocol(daddr, p_hid->itf_num, protocol, set_protocol_complete, 0); -} - -static void set_report_complete(tuh_xfer_t* xfer) -{ - TU_LOG2("HID Set Report complete\r\n"); - - if (tuh_hid_set_report_complete_cb) - { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num); - - uint8_t const report_type = tu_u16_high(xfer->setup->wValue); - uint8_t const report_id = tu_u16_low(xfer->setup->wValue); - - tuh_hid_set_report_complete_cb(xfer->daddr, idx, report_id, report_type, - (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0); - } -} - -bool tuh_hid_set_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) -{ - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid); - - TU_LOG2("HID Set Report: id = %u, type = %u, len = %u\r\n", report_id, report_type, len); - - tusb_control_request_t const request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = HID_REQ_CONTROL_SET_REPORT, - .wValue = tu_htole16(tu_u16(report_type, report_id)), - .wIndex = tu_htole16((uint16_t)p_hid->itf_num), - .wLength = len - }; - - tuh_xfer_t xfer = - { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = report, - .complete_cb = set_report_complete, - .user_data = 0 - }; - - return tuh_control_xfer(&xfer); -} - -static bool _hidh_set_idle(uint8_t daddr, uint8_t itf_num, uint16_t idle_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - // SET IDLE request, device can stall if not support this request - TU_LOG2("HID Set Idle \r\n"); - - tusb_control_request_t const request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = HID_REQ_CONTROL_SET_IDLE, - .wValue = tu_htole16(idle_rate), - .wIndex = tu_htole16((uint16_t)itf_num), - .wLength = 0 - }; - - tuh_xfer_t xfer = - { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = NULL, - .complete_cb = complete_cb, - .user_data = user_data - }; - - return tuh_control_xfer(&xfer); -} - -//--------------------------------------------------------------------+ -// Interrupt Endpoint API -//--------------------------------------------------------------------+ - -// Check if HID interface is ready to receive report -bool tuh_hid_receive_ready(uint8_t dev_addr, uint8_t idx) -{ - hidh_interface_t* p_hid = get_hid_itf(dev_addr, idx); - TU_VERIFY(p_hid); - - return !usbh_edpt_busy(dev_addr, p_hid->ep_in); -} - -bool tuh_hid_receive_report(uint8_t daddr, uint8_t idx) -{ - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid); - - // claim endpoint - TU_VERIFY( usbh_edpt_claim(daddr, p_hid->ep_in) ); - - if ( !usbh_edpt_xfer(daddr, p_hid->ep_in, p_hid->epin_buf, p_hid->epin_size) ) - { - usbh_edpt_release(daddr, p_hid->ep_in); - return false; - } - - return true; -} - -bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx) -{ - hidh_interface_t* p_hid = get_hid_itf(dev_addr, idx); - TU_VERIFY(p_hid); - - return !usbh_edpt_busy(dev_addr, p_hid->ep_out); -} - -bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const void* report, uint16_t len) -{ - TU_LOG2("HID Send Report %d\r\n", report_id); - - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid); - - if (p_hid->ep_out == 0) - { - // This HID does not have an out endpoint (other than control) - return false; - } - else if (len > CFG_TUH_HID_EPOUT_BUFSIZE || - (report_id != 0 && len > (CFG_TUH_HID_EPOUT_BUFSIZE - 1))) - { - // ep_out buffer is not large enough to hold contents - return false; - } - - // claim endpoint - TU_VERIFY( usbh_edpt_claim(daddr, p_hid->ep_out) ); - - if (report_id == 0) - { - // No report ID in transmission - memcpy(&p_hid->epout_buf[0], report, len); - } - else - { - p_hid->epout_buf[0] = report_id; - memcpy(&p_hid->epout_buf[1], report, len); - ++len; // 1 more byte for report_id - } - - TU_LOG3_MEM(p_hid->epout_buf, len, 2); - - if ( !usbh_edpt_xfer(daddr, p_hid->ep_out, p_hid->epout_buf, len) ) - { - usbh_edpt_release(daddr, p_hid->ep_out); - return false; - } - - return true; -} - -//--------------------------------------------------------------------+ -// USBH API -//--------------------------------------------------------------------+ -void hidh_init(void) -{ - tu_memclr(_hidh_itf, sizeof(_hidh_itf)); -} - -bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void) result; - - uint8_t const dir = tu_edpt_dir(ep_addr); - uint8_t const idx = get_idx_by_epaddr(daddr, ep_addr); - - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid); - - if ( dir == TUSB_DIR_IN ) - { - TU_LOG2(" Get Report callback (%u, %u)\r\n", daddr, idx); - TU_LOG3_MEM(p_hid->epin_buf, xferred_bytes, 2); - tuh_hid_report_received_cb(daddr, idx, p_hid->epin_buf, (uint16_t) xferred_bytes); - }else - { - if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(daddr, idx, p_hid->epout_buf, (uint16_t) xferred_bytes); - } - - return true; -} - -void hidh_close(uint8_t daddr) -{ - for(uint8_t i=0; idaddr == daddr) - { - if(tuh_hid_umount_cb) tuh_hid_umount_cb(daddr, i); - p_hid->daddr = 0; - } - } -} - -//--------------------------------------------------------------------+ -// Enumeration -//--------------------------------------------------------------------+ - -bool hidh_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) -{ - (void) rhport; - (void) max_len; - - TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass); - - TU_LOG2("[%u] HID opening Interface %u\r\n", daddr, desc_itf->bInterfaceNumber); - - // len = interface + hid + n*endpoints - uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + - desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); - TU_ASSERT(max_len >= drv_len); - - uint8_t const *p_desc = (uint8_t const *) desc_itf; - - //------------- HID descriptor -------------// - p_desc = tu_desc_next(p_desc); - tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc; - TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType); - - hidh_interface_t* p_hid = find_new_itf(); - TU_ASSERT(p_hid); // not enough interface, try to increase CFG_TUH_HID - p_hid->daddr = daddr; - - //------------- Endpoint Descriptors -------------// - p_desc = tu_desc_next(p_desc); - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; - - for(int i = 0; i < desc_itf->bNumEndpoints; i++) - { - TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType); - TU_ASSERT( tuh_edpt_open(daddr, desc_ep) ); - - if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) - { - p_hid->ep_in = desc_ep->bEndpointAddress; - p_hid->epin_size = tu_edpt_packet_size(desc_ep); - } - else - { - p_hid->ep_out = desc_ep->bEndpointAddress; - p_hid->epout_size = tu_edpt_packet_size(desc_ep); - } - - p_desc = tu_desc_next(p_desc); - desc_ep = (tusb_desc_endpoint_t const *) p_desc; - } - - p_hid->itf_num = desc_itf->bInterfaceNumber; - - // Assume bNumDescriptors = 1 - p_hid->report_desc_type = desc_hid->bReportType; - p_hid->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength); - - // Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config - p_hid->protocol_mode = HID_PROTOCOL_BOOT; - if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass ) - { - p_hid->itf_protocol = desc_itf->bInterfaceProtocol; - } - - return true; -} - -//--------------------------------------------------------------------+ -// Set Configure -//--------------------------------------------------------------------+ - -enum { - CONFG_SET_IDLE, - CONFIG_SET_PROTOCOL, - CONFIG_GET_REPORT_DESC, - CONFIG_COMPLETE -}; - -static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t const* desc_report, uint16_t desc_len); -static void process_set_config(tuh_xfer_t* xfer); - -bool hidh_set_config(uint8_t daddr, uint8_t itf_num) -{ - tusb_control_request_t request; - request.wIndex = tu_htole16((uint16_t) itf_num); - - tuh_xfer_t xfer; - xfer.daddr = daddr; - xfer.result = XFER_RESULT_SUCCESS; - xfer.setup = &request; - xfer.user_data = CONFG_SET_IDLE; - - // fake request to kick-off the set config process - process_set_config(&xfer); - - return true; -} - -static void process_set_config(tuh_xfer_t* xfer) -{ - // Stall is a valid response for SET_IDLE, sometime SET_PROTOCOL as well - // therefore we could ignore its result - if ( !(xfer->setup->bRequest == HID_REQ_CONTROL_SET_IDLE || - xfer->setup->bRequest == HID_REQ_CONTROL_SET_PROTOCOL) ) - { - TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, ); - } - - uintptr_t const state = xfer->user_data; - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const daddr = xfer->daddr; - - uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num); - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid, ); - - switch(state) - { - case CONFG_SET_IDLE: - { - // Idle rate = 0 mean only report when there is changes - const uint16_t idle_rate = 0; - const uintptr_t next_state = (p_hid->itf_protocol != HID_ITF_PROTOCOL_NONE) ? CONFIG_SET_PROTOCOL : CONFIG_GET_REPORT_DESC; - _hidh_set_idle(daddr, itf_num, idle_rate, process_set_config, next_state); - } - break; - - case CONFIG_SET_PROTOCOL: - _hidh_set_protocol(daddr, p_hid->itf_num, HID_PROTOCOL_BOOT, process_set_config, CONFIG_GET_REPORT_DESC); - break; - - case CONFIG_GET_REPORT_DESC: - // Get Report Descriptor if possible - // using usbh enumeration buffer since report descriptor can be very long - if( p_hid->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE ) - { - TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", p_hid->report_desc_len); - - // Driver is mounted without report descriptor - config_driver_mount_complete(daddr, idx, NULL, 0); - }else - { - tuh_descriptor_get_hid_report(daddr, itf_num, p_hid->report_desc_type, 0, usbh_get_enum_buf(), p_hid->report_desc_len, process_set_config, CONFIG_COMPLETE); - } - break; - - case CONFIG_COMPLETE: - { - uint8_t const* desc_report = usbh_get_enum_buf(); - uint16_t const desc_len = tu_le16toh(xfer->setup->wLength); - - config_driver_mount_complete(daddr, idx, desc_report, desc_len); - } - break; - - default: break; - } -} - -static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t const* desc_report, uint16_t desc_len) -{ - hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid, ); - - // enumeration is complete - if (tuh_hid_mount_cb) tuh_hid_mount_cb(daddr, idx, desc_report, desc_len); - - // notify usbh that driver enumeration is complete - usbh_driver_set_config_complete(daddr, p_hid->itf_num); -} - -//--------------------------------------------------------------------+ -// Report Descriptor Parser -//--------------------------------------------------------------------+ - -uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) -{ - // Report Item 6.2.2.2 USB HID 1.11 - union TU_ATTR_PACKED - { - uint8_t byte; - struct TU_ATTR_PACKED - { - uint8_t size : 2; - uint8_t type : 2; - uint8_t tag : 4; - }; - } header; - - tu_memclr(report_info_arr, arr_count*sizeof(tuh_hid_report_info_t)); - - uint8_t report_num = 0; - tuh_hid_report_info_t* info = report_info_arr; - - // current parsed report count & size from descriptor -// uint8_t ri_report_count = 0; -// uint8_t ri_report_size = 0; - - uint8_t ri_collection_depth = 0; - - while(desc_len && report_num < arr_count) - { - header.byte = *desc_report++; - desc_len--; - - uint8_t const tag = header.tag; - uint8_t const type = header.type; - uint8_t const size = header.size; - - uint8_t const data8 = desc_report[0]; - - TU_LOG(3, "tag = %d, type = %d, size = %d, data = ", tag, type, size); - for(uint32_t i=0; iusage_page, desc_report, size); - break; - - case RI_GLOBAL_LOGICAL_MIN : break; - case RI_GLOBAL_LOGICAL_MAX : break; - case RI_GLOBAL_PHYSICAL_MIN : break; - case RI_GLOBAL_PHYSICAL_MAX : break; - - case RI_GLOBAL_REPORT_ID: - info->report_id = data8; - break; - - case RI_GLOBAL_REPORT_SIZE: -// ri_report_size = data8; - break; - - case RI_GLOBAL_REPORT_COUNT: -// ri_report_count = data8; - break; - - case RI_GLOBAL_UNIT_EXPONENT : break; - case RI_GLOBAL_UNIT : break; - case RI_GLOBAL_PUSH : break; - case RI_GLOBAL_POP : break; - - default: break; - } - break; - - case RI_TYPE_LOCAL: - switch(tag) - { - case RI_LOCAL_USAGE: - // only take in account the "usage" before starting REPORT ID - if ( ri_collection_depth == 0 ) info->usage = data8; - break; - - case RI_LOCAL_USAGE_MIN : break; - case RI_LOCAL_USAGE_MAX : break; - case RI_LOCAL_DESIGNATOR_INDEX : break; - case RI_LOCAL_DESIGNATOR_MIN : break; - case RI_LOCAL_DESIGNATOR_MAX : break; - case RI_LOCAL_STRING_INDEX : break; - case RI_LOCAL_STRING_MIN : break; - case RI_LOCAL_STRING_MAX : break; - case RI_LOCAL_DELIMITER : break; - default: break; - } - break; - - // error - default: break; - } - - desc_report += size; - desc_len -= size; - } - - for ( uint8_t i = 0; i < report_num; i++ ) - { - info = report_info_arr+i; - TU_LOG2("%u: id = %u, usage_page = %u, usage = %u\r\n", i, info->report_id, info->usage_page, info->usage); - } - - return report_num; -} - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.h b/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.h deleted file mode 100644 index 08ad421d..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/hid/hid_host.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_HID_HOST_H_ -#define _TUSB_HID_HOST_H_ - -#include "hid.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Class Driver Configuration -//--------------------------------------------------------------------+ - -// TODO Highspeed interrupt can be up to 512 bytes -#ifndef CFG_TUH_HID_EPIN_BUFSIZE -#define CFG_TUH_HID_EPIN_BUFSIZE 64 -#endif - -#ifndef CFG_TUH_HID_EPOUT_BUFSIZE -#define CFG_TUH_HID_EPOUT_BUFSIZE 64 -#endif - - -typedef struct -{ - uint8_t report_id; - uint8_t usage; - uint16_t usage_page; - - // TODO still use the endpoint size for now -// uint8_t in_len; // length of IN report -// uint8_t out_len; // length of OUT report -} tuh_hid_report_info_t; - -//--------------------------------------------------------------------+ -// Interface API -//--------------------------------------------------------------------+ - -// Get the total number of mounted HID interfaces of a device -uint8_t tuh_hid_itf_get_count(uint8_t dev_addr); - -// Get all mounted interfaces across devices -uint8_t tuh_hid_itf_get_total_count(void); - -// backward compatible rename -#define tuh_hid_instance_count tuh_hid_itf_get_count - -// Get Interface information -bool tuh_hid_itf_get_info(uint8_t daddr, uint8_t idx, tuh_itf_info_t* itf_info); - -// Get Interface index from device address + interface number -// return TUSB_INDEX_INVALID_8 (0xFF) if not found -uint8_t tuh_hid_itf_get_index(uint8_t daddr, uint8_t itf_num); - -// Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values -uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t idx); - -// Check if HID interface is mounted -bool tuh_hid_mounted(uint8_t dev_addr, uint8_t idx); - -// Parse report descriptor into array of report_info struct and return number of reports. -// For complicated report, application should write its own parser. -uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED; - -//--------------------------------------------------------------------+ -// Control Endpoint API -//--------------------------------------------------------------------+ - -// Get current protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) -// Note: Device will be initialized in Boot protocol for simplicity. -// Application can use set_protocol() to switch back to Report protocol. -uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t idx); - -// Set protocol to HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) -// This function is only supported by Boot interface (tuh_n_hid_interface_protocol() != NONE) -bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t idx, uint8_t protocol); - -// Set Report using control endpoint -// report_type is either Input, Output or Feature, (value from hid_report_type_t) -bool tuh_hid_set_report(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len); - -//--------------------------------------------------------------------+ -// Interrupt Endpoint API -//--------------------------------------------------------------------+ - -// Check if HID interface is ready to receive report -bool tuh_hid_receive_ready(uint8_t dev_addr, uint8_t idx); - -// Try to receive next report on Interrupt Endpoint. Immediately return -// - true If succeeded, tuh_hid_report_received_cb() callback will be invoked when report is available -// - false if failed to queue the transfer e.g endpoint is busy -bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t idx); - -// Check if HID interface is ready to send report -bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx); - -// Send report using interrupt endpoint -// If report_id > 0 (composite), it will be sent as 1st byte, then report contents. Otherwise only report content is sent. -bool tuh_hid_send_report(uint8_t dev_addr, uint8_t idx, uint8_t report_id, const void* report, uint16_t len); - -//--------------------------------------------------------------------+ -// Callbacks (Weak is optional) -//--------------------------------------------------------------------+ - -// Invoked when device with hid interface is mounted -// Report descriptor is also available for use. tuh_hid_parse_report_descriptor() -// can be used to parse common/simple enough descriptor. -// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped -// therefore report_desc = NULL, desc_len = 0 -TU_ATTR_WEAK void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report_desc, uint16_t desc_len); - -// Invoked when device with hid interface is un-mounted -TU_ATTR_WEAK void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t idx); - -// Invoked when received report from device via interrupt endpoint -// Note: if there is report ID (composite), it is 1st byte of report -void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len); - -// Invoked when sent report to device successfully via interrupt endpoint -TU_ATTR_WEAK void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len); - -// Invoked when Sent Report to device via either control endpoint -// len = 0 indicate there is error in the transfer e.g stalled response -TU_ATTR_WEAK void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len); - -// Invoked when Set Protocol request is complete -TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t protocol); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void hidh_init (void); -bool hidh_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); -bool hidh_set_config (uint8_t dev_addr, uint8_t itf_num); -bool hidh_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); -void hidh_close (uint8_t dev_addr); - -#ifdef __cplusplus -} -#endif - -#endif /* _TUSB_HID_HOST_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi.h b/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi.h deleted file mode 100644 index 8ddcdfda..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -/** \ingroup group_class - * \defgroup ClassDriver_CDC Communication Device Class (CDC) - * Currently only Abstract Control Model subclass is supported - * @{ */ - -#ifndef _TUSB_MIDI_H__ -#define _TUSB_MIDI_H__ - -#include "common/tusb_common.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Class Specific Descriptor -//--------------------------------------------------------------------+ - -typedef enum -{ - MIDI_CS_INTERFACE_HEADER = 0x01, - MIDI_CS_INTERFACE_IN_JACK = 0x02, - MIDI_CS_INTERFACE_OUT_JACK = 0x03, - MIDI_CS_INTERFACE_ELEMENT = 0x04, -} midi_cs_interface_subtype_t; - -typedef enum -{ - MIDI_CS_ENDPOINT_GENERAL = 0x01 -} midi_cs_endpoint_subtype_t; - -typedef enum -{ - MIDI_JACK_EMBEDDED = 0x01, - MIDI_JACK_EXTERNAL = 0x02 -} midi_jack_type_t; - -typedef enum -{ - MIDI_CIN_MISC = 0, - MIDI_CIN_CABLE_EVENT = 1, - MIDI_CIN_SYSCOM_2BYTE = 2, // 2 byte system common message e.g MTC, SongSelect - MIDI_CIN_SYSCOM_3BYTE = 3, // 3 byte system common message e.g SPP - MIDI_CIN_SYSEX_START = 4, // SysEx starts or continue - MIDI_CIN_SYSEX_END_1BYTE = 5, // SysEx ends with 1 data, or 1 byte system common message - MIDI_CIN_SYSEX_END_2BYTE = 6, // SysEx ends with 2 data - MIDI_CIN_SYSEX_END_3BYTE = 7, // SysEx ends with 3 data - MIDI_CIN_NOTE_OFF = 8, - MIDI_CIN_NOTE_ON = 9, - MIDI_CIN_POLY_KEYPRESS = 10, - MIDI_CIN_CONTROL_CHANGE = 11, - MIDI_CIN_PROGRAM_CHANGE = 12, - MIDI_CIN_CHANNEL_PRESSURE = 13, - MIDI_CIN_PITCH_BEND_CHANGE = 14, - MIDI_CIN_1BYTE_DATA = 15 -} midi_code_index_number_t; - -// MIDI 1.0 status byte -enum -{ - //------------- System Exclusive -------------// - MIDI_STATUS_SYSEX_START = 0xF0, - MIDI_STATUS_SYSEX_END = 0xF7, - - //------------- System Common -------------// - MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME = 0xF1, - MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER = 0xF2, - MIDI_STATUS_SYSCOM_SONG_SELECT = 0xF3, - // F4, F5 is undefined - MIDI_STATUS_SYSCOM_TUNE_REQUEST = 0xF6, - - //------------- System RealTime -------------// - MIDI_STATUS_SYSREAL_TIMING_CLOCK = 0xF8, - // 0xF9 is undefined - MIDI_STATUS_SYSREAL_START = 0xFA, - MIDI_STATUS_SYSREAL_CONTINUE = 0xFB, - MIDI_STATUS_SYSREAL_STOP = 0xFC, - // 0xFD is undefined - MIDI_STATUS_SYSREAL_ACTIVE_SENSING = 0xFE, - MIDI_STATUS_SYSREAL_SYSTEM_RESET = 0xFF, -}; - -/// MIDI Interface Header Descriptor -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType - uint16_t bcdMSC ; ///< MidiStreaming SubClass release number in Binary-Coded Decimal - uint16_t wTotalLength ; -} midi_desc_header_t; - -/// MIDI In Jack Descriptor -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType - uint8_t bJackType ; ///< Embedded or External - uint8_t bJackID ; ///< Unique ID for MIDI IN Jack - uint8_t iJack ; ///< string descriptor -} midi_desc_in_jack_t; - - -/// MIDI Out Jack Descriptor with single pin -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType - uint8_t bJackType ; ///< Embedded or External - uint8_t bJackID ; ///< Unique ID for MIDI IN Jack - uint8_t bNrInputPins; - - uint8_t baSourceID; - uint8_t baSourcePin; - - uint8_t iJack ; ///< string descriptor -} midi_desc_out_jack_t ; - -/// MIDI Out Jack Descriptor with multiple pins -#define midi_desc_out_jack_n_t(input_num) \ - struct TU_ATTR_PACKED { \ - uint8_t bLength ; \ - uint8_t bDescriptorType ; \ - uint8_t bDescriptorSubType ; \ - uint8_t bJackType ; \ - uint8_t bJackID ; \ - uint8_t bNrInputPins ; \ - struct TU_ATTR_PACKED { \ - uint8_t baSourceID; \ - uint8_t baSourcePin; \ - } pins[input_num]; \ - uint8_t iJack ; \ - } - -/// MIDI Element Descriptor -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType - uint8_t bElementID; - - uint8_t bNrInputPins; - uint8_t baSourceID; - uint8_t baSourcePin; - - uint8_t bNrOutputPins; - uint8_t bInTerminalLink; - uint8_t bOutTerminalLink; - uint8_t bElCapsSize; - - uint16_t bmElementCaps; - uint8_t iElement; -} midi_desc_element_t; - -/// MIDI Element Descriptor with multiple pins -#define midi_desc_element_n_t(input_num) \ - struct TU_ATTR_PACKED { \ - uint8_t bLength; \ - uint8_t bDescriptorType; \ - uint8_t bDescriptorSubType; \ - uint8_t bElementID; \ - uint8_t bNrInputPins; \ - struct TU_ATTR_PACKED { \ - uint8_t baSourceID; \ - uint8_t baSourcePin; \ - } pins[input_num]; \ - uint8_t bNrOutputPins; \ - uint8_t bInTerminalLink; \ - uint8_t bOutTerminalLink; \ - uint8_t bElCapsSize; \ - uint16_t bmElementCaps; \ - uint8_t iElement; \ - } - -/** @} */ - -#ifdef __cplusplus - } -#endif - -#endif - -/** @} */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.c deleted file mode 100644 index e3e7826d..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_MIDI) - -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "midi_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -typedef struct -{ - uint8_t buffer[4]; - uint8_t index; - uint8_t total; -}midid_stream_t; - -typedef struct -{ - uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; - - // For Stream read()/write() API - // Messages are always 4 bytes long, queue them for reading and writing so the - // callers can use the Stream interface with single-byte read/write calls. - midid_stream_t stream_write; - midid_stream_t stream_read; - - /*------------- From this point, data is not cleared by bus reset -------------*/ - // FIFO - tu_fifo_t rx_ff; - tu_fifo_t tx_ff; - uint8_t rx_ff_buf[CFG_TUD_MIDI_RX_BUFSIZE]; - uint8_t tx_ff_buf[CFG_TUD_MIDI_TX_BUFSIZE]; - - #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_ff_mutex; - osal_mutex_def_t tx_ff_mutex; - #endif - - // Endpoint Transfer buffer - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_MIDI_EP_BUFSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_MIDI_EP_BUFSIZE]; - -} midid_interface_t; - -#define ITF_MEM_RESET_SIZE offsetof(midid_interface_t, rx_ff) - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION midid_interface_t _midid_itf[CFG_TUD_MIDI]; - -bool tud_midi_n_mounted (uint8_t itf) -{ - midid_interface_t* midi = &_midid_itf[itf]; - return midi->ep_in && midi->ep_out; -} - -static void _prep_out_transaction (midid_interface_t* p_midi) -{ - uint8_t const rhport = 0; - uint16_t available = tu_fifo_remaining(&p_midi->rx_ff); - - // Prepare for incoming data but only allow what we can store in the ring buffer. - // TODO Actually we can still carry out the transfer, keeping count of received bytes - // and slowly move it to the FIFO when read(). - // This pre-check reduces endpoint claiming - TU_VERIFY(available >= sizeof(p_midi->epout_buf), ); - - // claim endpoint - TU_VERIFY(usbd_edpt_claim(rhport, p_midi->ep_out), ); - - // fifo can be changed before endpoint is claimed - available = tu_fifo_remaining(&p_midi->rx_ff); - - if ( available >= sizeof(p_midi->epout_buf) ) { - usbd_edpt_xfer(rhport, p_midi->ep_out, p_midi->epout_buf, sizeof(p_midi->epout_buf)); - }else - { - // Release endpoint since we don't make any transfer - usbd_edpt_release(rhport, p_midi->ep_out); - } -} - -//--------------------------------------------------------------------+ -// READ API -//--------------------------------------------------------------------+ -uint32_t tud_midi_n_available(uint8_t itf, uint8_t cable_num) -{ - (void) cable_num; - - midid_interface_t* midi = &_midid_itf[itf]; - midid_stream_t const* stream = &midi->stream_read; - - // when using with packet API stream total & index are both zero - return tu_fifo_count(&midi->rx_ff) + (uint8_t) (stream->total - stream->index); -} - -uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize) -{ - (void) cable_num; - TU_VERIFY(bufsize, 0); - - uint8_t* buf8 = (uint8_t*) buffer; - - midid_interface_t* midi = &_midid_itf[itf]; - midid_stream_t* stream = &midi->stream_read; - - uint32_t total_read = 0; - while( bufsize ) - { - // Get new packet from fifo, then set packet expected bytes - if ( stream->total == 0 ) - { - // return if there is no more data from fifo - if ( !tud_midi_n_packet_read(itf, stream->buffer) ) return total_read; - - uint8_t const code_index = stream->buffer[0] & 0x0f; - - // MIDI 1.0 Table 4-1: Code Index Number Classifications - switch(code_index) - { - case MIDI_CIN_MISC: - case MIDI_CIN_CABLE_EVENT: - // These are reserved and unused, possibly issue somewhere, skip this packet - return 0; - break; - - case MIDI_CIN_SYSEX_END_1BYTE: - case MIDI_CIN_1BYTE_DATA: - stream->total = 1; - break; - - case MIDI_CIN_SYSCOM_2BYTE : - case MIDI_CIN_SYSEX_END_2BYTE : - case MIDI_CIN_PROGRAM_CHANGE : - case MIDI_CIN_CHANNEL_PRESSURE : - stream->total = 2; - break; - - default: - stream->total = 3; - break; - } - } - - // Copy data up to bufsize - uint8_t const count = (uint8_t) tu_min32(stream->total - stream->index, bufsize); - - // Skip the header (1st byte) in the buffer - TU_VERIFY(0 == tu_memcpy_s(buf8, bufsize, stream->buffer + 1 + stream->index, count)); - - total_read += count; - stream->index += count; - buf8 += count; - bufsize -= count; - - // complete current event packet, reset stream - if ( stream->total == stream->index ) - { - stream->index = 0; - stream->total = 0; - } - } - - return total_read; -} - -bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]) -{ - midid_interface_t* midi = &_midid_itf[itf]; - TU_VERIFY(midi->ep_out); - - uint32_t const num_read = tu_fifo_read_n(&midi->rx_ff, packet, 4); - _prep_out_transaction(midi); - return (num_read == 4); -} - -//--------------------------------------------------------------------+ -// WRITE API -//--------------------------------------------------------------------+ - -static uint32_t write_flush(midid_interface_t* midi) -{ - // No data to send - if ( !tu_fifo_count(&midi->tx_ff) ) return 0; - - uint8_t const rhport = 0; - - // skip if previous transfer not complete - TU_VERIFY( usbd_edpt_claim(rhport, midi->ep_in), 0 ); - - uint16_t count = tu_fifo_read_n(&midi->tx_ff, midi->epin_buf, CFG_TUD_MIDI_EP_BUFSIZE); - - if (count) - { - TU_ASSERT( usbd_edpt_xfer(rhport, midi->ep_in, midi->epin_buf, count), 0 ); - return count; - }else - { - // Release endpoint since we don't make any transfer - usbd_edpt_release(rhport, midi->ep_in); - return 0; - } -} - -uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) -{ - midid_interface_t* midi = &_midid_itf[itf]; - TU_VERIFY(midi->ep_in, 0); - - midid_stream_t* stream = &midi->stream_write; - - uint32_t i = 0; - while ( (i < bufsize) && (tu_fifo_remaining(&midi->tx_ff) >= 4) ) - { - uint8_t const data = buffer[i]; - i++; - - if ( stream->index == 0 ) - { - //------------- New event packet -------------// - - uint8_t const msg = data >> 4; - - stream->index = 2; - stream->buffer[1] = data; - - // Check to see if we're still in a SysEx transmit. - if ( ((stream->buffer[0]) & 0xF) == MIDI_CIN_SYSEX_START ) - { - if ( data == MIDI_STATUS_SYSEX_END ) - { - stream->buffer[0] = (uint8_t) ((cable_num << 4) | MIDI_CIN_SYSEX_END_1BYTE); - stream->total = 2; - } - else - { - stream->total = 4; - } - } - else if ( (msg >= 0x8 && msg <= 0xB) || msg == 0xE ) - { - // Channel Voice Messages - stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg); - stream->total = 4; - } - else if ( msg == 0xC || msg == 0xD) - { - // Channel Voice Messages, two-byte variants (Program Change and Channel Pressure) - stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg); - stream->total = 3; - } - else if ( msg == 0xf ) - { - // System message - if ( data == MIDI_STATUS_SYSEX_START ) - { - stream->buffer[0] = MIDI_CIN_SYSEX_START; - stream->total = 4; - } - else if ( data == MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME || data == MIDI_STATUS_SYSCOM_SONG_SELECT ) - { - stream->buffer[0] = MIDI_CIN_SYSCOM_2BYTE; - stream->total = 3; - } - else if ( data == MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER ) - { - stream->buffer[0] = MIDI_CIN_SYSCOM_3BYTE; - stream->total = 4; - } - else - { - stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; - stream->total = 2; - } - stream->buffer[0] |= (uint8_t)(cable_num << 4); - } - else - { - // Pack individual bytes if we don't support packing them into words. - stream->buffer[0] = (uint8_t) (cable_num << 4 | 0xf); - stream->buffer[2] = 0; - stream->buffer[3] = 0; - stream->index = 2; - stream->total = 2; - } - } - else - { - //------------- On-going (buffering) packet -------------// - - TU_ASSERT(stream->index < 4, i); - stream->buffer[stream->index] = data; - stream->index++; - - // See if this byte ends a SysEx. - if ( (stream->buffer[0] & 0xF) == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END ) - { - stream->buffer[0] = (uint8_t) ((cable_num << 4) | (MIDI_CIN_SYSEX_START + (stream->index - 1))); - stream->total = stream->index; - } - } - - // Send out packet - if ( stream->index == stream->total ) - { - // zeroes unused bytes - for(uint8_t idx = stream->total; idx < 4; idx++) stream->buffer[idx] = 0; - - uint16_t const count = tu_fifo_write_n(&midi->tx_ff, stream->buffer, 4); - - // complete current event packet, reset stream - stream->index = stream->total = 0; - - // FIFO overflown, since we already check fifo remaining. It is probably race condition - TU_ASSERT(count == 4, i); - } - } - - write_flush(midi); - - return i; -} - -bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]) -{ - midid_interface_t* midi = &_midid_itf[itf]; - TU_VERIFY(midi->ep_in); - - if (tu_fifo_remaining(&midi->tx_ff) < 4) return false; - - tu_fifo_write_n(&midi->tx_ff, packet, 4); - write_flush(midi); - - return true; -} - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void midid_init(void) -{ - tu_memclr(_midid_itf, sizeof(_midid_itf)); - - for(uint8_t i=0; irx_ff, midi->rx_ff_buf, CFG_TUD_MIDI_RX_BUFSIZE, 1, false); // true, true - tu_fifo_config(&midi->tx_ff, midi->tx_ff_buf, CFG_TUD_MIDI_TX_BUFSIZE, 1, false); // OBVS. - - #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&midi->rx_ff, NULL, osal_mutex_create(&midi->rx_ff_mutex)); - tu_fifo_config_mutex(&midi->tx_ff, osal_mutex_create(&midi->tx_ff_mutex), NULL); - #endif - } -} - -void midid_reset(uint8_t rhport) -{ - (void) rhport; - - for(uint8_t i=0; irx_ff); - tu_fifo_clear(&midi->tx_ff); - } -} - -uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) -{ - // 1st Interface is Audio Control v1 - TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass && - AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass && - AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_itf->bInterfaceProtocol, 0); - - uint16_t drv_len = tu_desc_len(desc_itf); - uint8_t const * p_desc = tu_desc_next(desc_itf); - - // Skip Class Specific descriptors - while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) - { - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - // 2nd Interface is MIDI Streaming - TU_VERIFY(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); - tusb_desc_interface_t const * desc_midi = (tusb_desc_interface_t const *) p_desc; - - TU_VERIFY(TUSB_CLASS_AUDIO == desc_midi->bInterfaceClass && - AUDIO_SUBCLASS_MIDI_STREAMING == desc_midi->bInterfaceSubClass && - AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_midi->bInterfaceProtocol, 0); - - // Find available interface - midid_interface_t * p_midi = NULL; - for(uint8_t i=0; iitf_num = desc_midi->bInterfaceNumber; - (void) p_midi->itf_num; - - // next descriptor - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - - // Find and open endpoint descriptors - uint8_t found_endpoints = 0; - while ( (found_endpoints < desc_midi->bNumEndpoints) && (drv_len <= max_len) ) - { - if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) - { - TU_ASSERT(usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0); - uint8_t ep_addr = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; - - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) - { - p_midi->ep_in = ep_addr; - } else { - p_midi->ep_out = ep_addr; - } - - // Class Specific MIDI Stream endpoint descriptor - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - - found_endpoints += 1; - } - - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - // Prepare for incoming data - _prep_out_transaction(p_midi); - - return drv_len; -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool midid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - (void) rhport; - (void) stage; - (void) request; - - // driver doesn't support any request yet - return false; -} - -bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void) result; - (void) rhport; - - uint8_t itf; - midid_interface_t* p_midi; - - // Identify which interface to use - for (itf = 0; itf < CFG_TUD_MIDI; itf++) - { - p_midi = &_midid_itf[itf]; - if ( ( ep_addr == p_midi->ep_out ) || ( ep_addr == p_midi->ep_in ) ) break; - } - TU_ASSERT(itf < CFG_TUD_MIDI); - - // receive new data - if ( ep_addr == p_midi->ep_out ) - { - tu_fifo_write_n(&p_midi->rx_ff, p_midi->epout_buf, (uint16_t) xferred_bytes); - - // invoke receive callback if available - if (tud_midi_rx_cb) tud_midi_rx_cb(itf); - - // prepare for next - // TODO for now ep_out is not used by public API therefore there is no race condition, - // and does not need to claim like ep_in - _prep_out_transaction(p_midi); - } - else if ( ep_addr == p_midi->ep_in ) - { - if (0 == write_flush(p_midi)) - { - // If there is no data left, a ZLP should be sent if - // xferred_bytes is multiple of EP size and not zero - if ( !tu_fifo_count(&p_midi->tx_ff) && xferred_bytes && (0 == (xferred_bytes % CFG_TUD_MIDI_EP_BUFSIZE)) ) - { - if ( usbd_edpt_claim(rhport, p_midi->ep_in) ) - { - usbd_edpt_xfer(rhport, p_midi->ep_in, NULL, 0); - } - } - } - } - - return true; -} - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.h deleted file mode 100644 index 1c6f996b..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/midi/midi_device.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_MIDI_DEVICE_H_ -#define _TUSB_MIDI_DEVICE_H_ - -#include "class/audio/audio.h" -#include "midi.h" - -//--------------------------------------------------------------------+ -// Class Driver Configuration -//--------------------------------------------------------------------+ - -#if !defined(CFG_TUD_MIDI_EP_BUFSIZE) && defined(CFG_TUD_MIDI_EPSIZE) - #warning CFG_TUD_MIDI_EPSIZE is renamed to CFG_TUD_MIDI_EP_BUFSIZE, please update to use the new name - #define CFG_TUD_MIDI_EP_BUFSIZE CFG_TUD_MIDI_EPSIZE -#endif - -#ifndef CFG_TUD_MIDI_EP_BUFSIZE - #define CFG_TUD_MIDI_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) -#endif - -#ifdef __cplusplus - extern "C" { -#endif - -/** \addtogroup MIDI_Serial Serial - * @{ - * \defgroup MIDI_Serial_Device Device - * @{ */ - -//--------------------------------------------------------------------+ -// Application API (Multiple Interfaces) -// CFG_TUD_MIDI > 1 -//--------------------------------------------------------------------+ - -// Check if midi interface is mounted -bool tud_midi_n_mounted (uint8_t itf); - -// Get the number of bytes available for reading -uint32_t tud_midi_n_available (uint8_t itf, uint8_t cable_num); - -// Read byte stream (legacy) -uint32_t tud_midi_n_stream_read (uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize); - -// Write byte Stream (legacy) -uint32_t tud_midi_n_stream_write (uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); - -// Read event packet (4 bytes) -bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]); - -// Write event packet (4 bytes) -bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]); - -//--------------------------------------------------------------------+ -// Application API (Single Interface) -//--------------------------------------------------------------------+ -static inline bool tud_midi_mounted (void); -static inline uint32_t tud_midi_available (void); - -static inline uint32_t tud_midi_stream_read (void* buffer, uint32_t bufsize); -static inline uint32_t tud_midi_stream_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); - -static inline bool tud_midi_packet_read (uint8_t packet[4]); -static inline bool tud_midi_packet_write (uint8_t const packet[4]); - -//------------- Deprecated API name -------------// -// TODO remove after 0.10.0 release - -TU_ATTR_DEPRECATED("tud_midi_read() is renamed to tud_midi_stream_read()") -static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize) -{ - return tud_midi_stream_read(buffer, bufsize); -} - -TU_ATTR_DEPRECATED("tud_midi_write() is renamed to tud_midi_stream_write()") -static inline uint32_t tud_midi_write(uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) -{ - return tud_midi_stream_write(cable_num, buffer, bufsize); -} - - -TU_ATTR_DEPRECATED("tud_midi_send() is renamed to tud_midi_packet_write()") -static inline bool tud_midi_send(uint8_t packet[4]) -{ - return tud_midi_packet_write(packet); -} - -TU_ATTR_DEPRECATED("tud_midi_receive() is renamed to tud_midi_packet_read()") -static inline bool tud_midi_receive(uint8_t packet[4]) -{ - return tud_midi_packet_read(packet); -} - -//--------------------------------------------------------------------+ -// Application Callback API (weak is optional) -//--------------------------------------------------------------------+ -TU_ATTR_WEAK void tud_midi_rx_cb(uint8_t itf); - -//--------------------------------------------------------------------+ -// Inline Functions -//--------------------------------------------------------------------+ - -static inline bool tud_midi_mounted (void) -{ - return tud_midi_n_mounted(0); -} - -static inline uint32_t tud_midi_available (void) -{ - return tud_midi_n_available(0, 0); -} - -static inline uint32_t tud_midi_stream_read (void* buffer, uint32_t bufsize) -{ - return tud_midi_n_stream_read(0, 0, buffer, bufsize); -} - -static inline uint32_t tud_midi_stream_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) -{ - return tud_midi_n_stream_write(0, cable_num, buffer, bufsize); -} - -static inline bool tud_midi_packet_read (uint8_t packet[4]) -{ - return tud_midi_n_packet_read(0, packet); -} - -static inline bool tud_midi_packet_write (uint8_t const packet[4]) -{ - return tud_midi_n_packet_write(0, packet); -} - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void midid_init (void); -void midid_reset (uint8_t rhport); -uint16_t midid_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool midid_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -bool midid_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_MIDI_DEVICE_H_ */ - -/** @} */ -/** @} */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc.h b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc.h deleted file mode 100644 index 7f25a29b..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc.h +++ /dev/null @@ -1,382 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_MSC_H_ -#define _TUSB_MSC_H_ - -#include "common/tusb_common.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Mass Storage Class Constant -//--------------------------------------------------------------------+ -/// MassStorage Subclass -typedef enum -{ - MSC_SUBCLASS_RBC = 1 , ///< Reduced Block Commands (RBC) T10 Project 1240-D - MSC_SUBCLASS_SFF_MMC , ///< SFF-8020i, MMC-2 (ATAPI). Typically used by a CD/DVD device - MSC_SUBCLASS_QIC , ///< QIC-157. Typically used by a tape device - MSC_SUBCLASS_UFI , ///< UFI. Typically used by Floppy Disk Drive (FDD) device - MSC_SUBCLASS_SFF , ///< SFF-8070i. Can be used by Floppy Disk Drive (FDD) device - MSC_SUBCLASS_SCSI ///< SCSI transparent command set -}msc_subclass_type_t; - -enum { - MSC_CBW_SIGNATURE = 0x43425355, ///< Constant value of 43425355h (little endian) - MSC_CSW_SIGNATURE = 0x53425355 ///< Constant value of 53425355h (little endian) -}; - -/// \brief MassStorage Protocol. -/// \details CBI only approved to use with full-speed floopy disk & should not used with highspeed or device other than floopy -typedef enum -{ - MSC_PROTOCOL_CBI = 0 , ///< Control/Bulk/Interrupt protocol (with command completion interrupt) - MSC_PROTOCOL_CBI_NO_INTERRUPT = 1 , ///< Control/Bulk/Interrupt protocol (without command completion interrupt) - MSC_PROTOCOL_BOT = 0x50 ///< Bulk-Only Transport -}msc_protocol_type_t; - -/// MassStorage Class-Specific Control Request -typedef enum -{ - MSC_REQ_GET_MAX_LUN = 254, ///< The Get Max LUN device request is used to determine the number of logical units supported by the device. Logical Unit Numbers on the device shall be numbered contiguously starting from LUN 0 to a maximum LUN of 15 - MSC_REQ_RESET = 255 ///< This request is used to reset the mass storage device and its associated interface. This class-specific request shall ready the device for the next CBW from the host. -}msc_request_type_t; - -/// \brief Command Block Status Values -/// \details Indicates the success or failure of the command. The device shall set this byte to zero if the command completed -/// successfully. A non-zero value shall indicate a failure during command execution according to the following -typedef enum -{ - MSC_CSW_STATUS_PASSED = 0 , ///< MSC_CSW_STATUS_PASSED - MSC_CSW_STATUS_FAILED , ///< MSC_CSW_STATUS_FAILED - MSC_CSW_STATUS_PHASE_ERROR ///< MSC_CSW_STATUS_PHASE_ERROR -}msc_csw_status_t; - -/// Command Block Wrapper -typedef struct TU_ATTR_PACKED -{ - uint32_t signature; ///< Signature that helps identify this data packet as a CBW. The signature field shall contain the value 43425355h (little endian), indicating a CBW. - uint32_t tag; ///< Tag sent by the host. The device shall echo the contents of this field back to the host in the dCSWTagfield of the associated CSW. The dCSWTagpositively associates a CSW with the corresponding CBW. - uint32_t total_bytes; ///< The number of bytes of data that the host expects to transfer on the Bulk-In or Bulk-Out endpoint (as indicated by the Direction bit) during the execution of this command. If this field is zero, the device and the host shall transfer no data between the CBW and the associated CSW, and the device shall ignore the value of the Direction bit in bmCBWFlags. - uint8_t dir; ///< Bit 7 of this field define transfer direction \n - 0 : Data-Out from host to the device. \n - 1 : Data-In from the device to the host. - uint8_t lun; ///< The device Logical Unit Number (LUN) to which the command block is being sent. For devices that support multiple LUNs, the host shall place into this field the LUN to which this command block is addressed. Otherwise, the host shall set this field to zero. - uint8_t cmd_len; ///< The valid length of the CBWCBin bytes. This defines the valid length of the command block. The only legal values are 1 through 16 - uint8_t command[16]; ///< The command block to be executed by the device. The device shall interpret the first cmd_len bytes in this field as a command block -}msc_cbw_t; - -TU_VERIFY_STATIC(sizeof(msc_cbw_t) == 31, "size is not correct"); - -/// Command Status Wrapper -typedef struct TU_ATTR_PACKED -{ - uint32_t signature ; ///< Signature that helps identify this data packet as a CSW. The signature field shall contain the value 53425355h (little endian), indicating CSW. - uint32_t tag ; ///< The device shall set this field to the value received in the dCBWTag of the associated CBW. - uint32_t data_residue ; ///< For Data-Out the device shall report in the dCSWDataResiduethe difference between the amount of data expected as stated in the dCBWDataTransferLength, and the actual amount of data processed by the device. For Data-In the device shall report in the dCSWDataResiduethe difference between the amount of data expected as stated in the dCBWDataTransferLengthand the actual amount of relevant data sent by the device - uint8_t status ; ///< indicates the success or failure of the command. Values from \ref msc_csw_status_t -}msc_csw_t; - -TU_VERIFY_STATIC(sizeof(msc_csw_t) == 13, "size is not correct"); - -//--------------------------------------------------------------------+ -// SCSI Constant -//--------------------------------------------------------------------+ - -/// SCSI Command Operation Code -typedef enum -{ - SCSI_CMD_TEST_UNIT_READY = 0x00, ///< The SCSI Test Unit Ready command is used to determine if a device is ready to transfer data (read/write), i.e. if a disk has spun up, if a tape is loaded and ready etc. The device does not perform a self-test operation. - SCSI_CMD_INQUIRY = 0x12, ///< The SCSI Inquiry command is used to obtain basic information from a target device. - SCSI_CMD_MODE_SELECT_6 = 0x15, ///< provides a means for the application client to specify medium, logical unit, or peripheral device parameters to the device server. Device servers that implement the MODE SELECT(6) command shall also implement the MODE SENSE(6) command. Application clients should issue MODE SENSE(6) prior to each MODE SELECT(6) to determine supported mode pages, page lengths, and other parameters. - SCSI_CMD_MODE_SENSE_6 = 0x1A, ///< provides a means for a device server to report parameters to an application client. It is a complementary command to the MODE SELECT(6) command. Device servers that implement the MODE SENSE(6) command shall also implement the MODE SELECT(6) command. - SCSI_CMD_START_STOP_UNIT = 0x1B, - SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1E, - SCSI_CMD_READ_CAPACITY_10 = 0x25, ///< The SCSI Read Capacity command is used to obtain data capacity information from a target device. - SCSI_CMD_REQUEST_SENSE = 0x03, ///< The SCSI Request Sense command is part of the SCSI computer protocol standard. This command is used to obtain sense data -- status/error information -- from a target device. - SCSI_CMD_READ_FORMAT_CAPACITY = 0x23, ///< The command allows the Host to request a list of the possible format capacities for an installed writable media. This command also has the capability to report the writable capacity for a media when it is installed - SCSI_CMD_READ_10 = 0x28, ///< The READ (10) command requests that the device server read the specified logical block(s) and transfer them to the data-in buffer. - SCSI_CMD_WRITE_10 = 0x2A, ///< The WRITE (10) command requests thatthe device server transfer the specified logical block(s) from the data-out buffer and write them. -}scsi_cmd_type_t; - -/// SCSI Sense Key -typedef enum -{ - SCSI_SENSE_NONE = 0x00, ///< no specific Sense Key. This would be the case for a successful command - SCSI_SENSE_RECOVERED_ERROR = 0x01, ///< ndicates the last command completed successfully with some recovery action performed by the disc drive. - SCSI_SENSE_NOT_READY = 0x02, ///< Indicates the logical unit addressed cannot be accessed. - SCSI_SENSE_MEDIUM_ERROR = 0x03, ///< Indicates the command terminated with a non-recovered error condition. - SCSI_SENSE_HARDWARE_ERROR = 0x04, ///< Indicates the disc drive detected a nonrecoverable hardware failure while performing the command or during a self test. - SCSI_SENSE_ILLEGAL_REQUEST = 0x05, ///< Indicates an illegal parameter in the command descriptor block or in the additional parameters - SCSI_SENSE_UNIT_ATTENTION = 0x06, ///< Indicates the disc drive may have been reset. - SCSI_SENSE_DATA_PROTECT = 0x07, ///< Indicates that a command that reads or writes the medium was attempted on a block that is protected from this operation. The read or write operation is not performed. - SCSI_SENSE_FIRMWARE_ERROR = 0x08, ///< Vendor specific sense key. - SCSI_SENSE_ABORTED_COMMAND = 0x0b, ///< Indicates the disc drive aborted the command. - SCSI_SENSE_EQUAL = 0x0c, ///< Indicates a SEARCH DATA command has satisfied an equal comparison. - SCSI_SENSE_VOLUME_OVERFLOW = 0x0d, ///< Indicates a buffered peripheral device has reached the end of medium partition and data remains in the buffer that has not been written to the medium. - SCSI_SENSE_MISCOMPARE = 0x0e ///< ndicates that the source data did not match the data read from the medium. -}scsi_sense_key_type_t; - -//--------------------------------------------------------------------+ -// SCSI Primary Command (SPC-4) -//--------------------------------------------------------------------+ - -/// SCSI Test Unit Ready Command -typedef struct TU_ATTR_PACKED -{ - uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_TEST_UNIT_READY - uint8_t lun ; ///< Logical Unit - uint8_t reserved[3] ; - uint8_t control ; -} scsi_test_unit_ready_t; - -TU_VERIFY_STATIC(sizeof(scsi_test_unit_ready_t) == 6, "size is not correct"); - -/// SCSI Inquiry Command -typedef struct TU_ATTR_PACKED -{ - uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_INQUIRY - uint8_t reserved1 ; - uint8_t page_code ; - uint8_t reserved2 ; - uint8_t alloc_length ; ///< specifies the maximum number of bytes that USB host has allocated in the Data-In Buffer. An allocation length of zero specifies that no data shall be transferred. - uint8_t control ; -} scsi_inquiry_t, scsi_request_sense_t; - -TU_VERIFY_STATIC(sizeof(scsi_inquiry_t) == 6, "size is not correct"); - -/// SCSI Inquiry Response Data -typedef struct TU_ATTR_PACKED -{ - uint8_t peripheral_device_type : 5; - uint8_t peripheral_qualifier : 3; - - uint8_t : 7; - uint8_t is_removable : 1; - - uint8_t version; - - uint8_t response_data_format : 4; - uint8_t hierarchical_support : 1; - uint8_t normal_aca : 1; - uint8_t : 2; - - uint8_t additional_length; - - uint8_t protect : 1; - uint8_t : 2; - uint8_t third_party_copy : 1; - uint8_t target_port_group_support : 2; - uint8_t access_control_coordinator : 1; - uint8_t scc_support : 1; - - uint8_t addr16 : 1; - uint8_t : 3; - uint8_t multi_port : 1; - uint8_t : 1; // vendor specific - uint8_t enclosure_service : 1; - uint8_t : 1; - - uint8_t : 1; // vendor specific - uint8_t cmd_que : 1; - uint8_t : 2; - uint8_t sync : 1; - uint8_t wbus16 : 1; - uint8_t : 2; - - uint8_t vendor_id[8] ; ///< 8 bytes of ASCII data identifying the vendor of the product. - uint8_t product_id[16]; ///< 16 bytes of ASCII data defined by the vendor. - uint8_t product_rev[4]; ///< 4 bytes of ASCII data defined by the vendor. -} scsi_inquiry_resp_t; - -TU_VERIFY_STATIC(sizeof(scsi_inquiry_resp_t) == 36, "size is not correct"); - - -typedef struct TU_ATTR_PACKED -{ - uint8_t response_code : 7; ///< 70h - current errors, Fixed Format 71h - deferred errors, Fixed Format - uint8_t valid : 1; - - uint8_t reserved; - - uint8_t sense_key : 4; - uint8_t : 1; - uint8_t ili : 1; ///< Incorrect length indicator - uint8_t end_of_medium : 1; - uint8_t filemark : 1; - - uint32_t information; - uint8_t add_sense_len; - uint32_t command_specific_info; - uint8_t add_sense_code; - uint8_t add_sense_qualifier; - uint8_t field_replaceable_unit_code; - - uint8_t sense_key_specific[3]; ///< sense key specific valid bit is bit 7 of key[0], aka MSB in Big Endian layout - -} scsi_sense_fixed_resp_t; - -TU_VERIFY_STATIC(sizeof(scsi_sense_fixed_resp_t) == 18, "size is not correct"); - -typedef struct TU_ATTR_PACKED -{ - uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_MODE_SENSE_6 - - uint8_t : 3; - uint8_t disable_block_descriptor : 1; - uint8_t : 4; - - uint8_t page_code : 6; - uint8_t page_control : 2; - - uint8_t subpage_code; - uint8_t alloc_length; - uint8_t control; -} scsi_mode_sense6_t; - -TU_VERIFY_STATIC( sizeof(scsi_mode_sense6_t) == 6, "size is not correct"); - -// This is only a Mode parameter header(6). -typedef struct TU_ATTR_PACKED -{ - uint8_t data_len; - uint8_t medium_type; - - uint8_t reserved : 7; - bool write_protected : 1; - - uint8_t block_descriptor_len; -} scsi_mode_sense6_resp_t; - -TU_VERIFY_STATIC( sizeof(scsi_mode_sense6_resp_t) == 4, "size is not correct"); - -typedef struct TU_ATTR_PACKED -{ - uint8_t cmd_code; ///< SCSI OpCode for \ref SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL - uint8_t reserved[3]; - uint8_t prohibit_removal; - uint8_t control; -} scsi_prevent_allow_medium_removal_t; - -TU_VERIFY_STATIC( sizeof(scsi_prevent_allow_medium_removal_t) == 6, "size is not correct"); - -typedef struct TU_ATTR_PACKED -{ - uint8_t cmd_code; - - uint8_t immded : 1; - uint8_t : 7; - - uint8_t TU_RESERVED; - - uint8_t power_condition_mod : 4; - uint8_t : 4; - - uint8_t start : 1; - uint8_t load_eject : 1; - uint8_t no_flush : 1; - uint8_t : 1; - uint8_t power_condition : 4; - - uint8_t control; -} scsi_start_stop_unit_t; - -TU_VERIFY_STATIC( sizeof(scsi_start_stop_unit_t) == 6, "size is not correct"); - -//--------------------------------------------------------------------+ -// SCSI MMC -//--------------------------------------------------------------------+ -/// SCSI Read Format Capacity: Write Capacity -typedef struct TU_ATTR_PACKED -{ - uint8_t cmd_code; - uint8_t reserved[6]; - uint16_t alloc_length; - uint8_t control; -} scsi_read_format_capacity_t; - -TU_VERIFY_STATIC( sizeof(scsi_read_format_capacity_t) == 10, "size is not correct"); - -typedef struct TU_ATTR_PACKED{ - uint8_t reserved[3]; - uint8_t list_length; /// must be 8*n, length in bytes of formattable capacity descriptor followed it. - - uint32_t block_num; /// Number of Logical Blocks - uint8_t descriptor_type; // 00: reserved, 01 unformatted media , 10 Formatted media, 11 No media present - - uint8_t reserved2; - uint16_t block_size_u16; - -} scsi_read_format_capacity_data_t; - -TU_VERIFY_STATIC( sizeof(scsi_read_format_capacity_data_t) == 12, "size is not correct"); - -//--------------------------------------------------------------------+ -// SCSI Block Command (SBC-3) -// NOTE: All data in SCSI command are in Big Endian -//--------------------------------------------------------------------+ - -/// SCSI Read Capacity 10 Command: Read Capacity -typedef struct TU_ATTR_PACKED -{ - uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_READ_CAPACITY_10 - uint8_t reserved1 ; - uint32_t lba ; ///< The first Logical Block Address (LBA) accessed by this command - uint16_t reserved2 ; - uint8_t partial_medium_indicator ; - uint8_t control ; -} scsi_read_capacity10_t; - -TU_VERIFY_STATIC(sizeof(scsi_read_capacity10_t) == 10, "size is not correct"); - -/// SCSI Read Capacity 10 Response Data -typedef struct { - uint32_t last_lba ; ///< The last Logical Block Address of the device - uint32_t block_size ; ///< Block size in bytes -} scsi_read_capacity10_resp_t; - -TU_VERIFY_STATIC(sizeof(scsi_read_capacity10_resp_t) == 8, "size is not correct"); - -/// SCSI Read 10 Command -typedef struct TU_ATTR_PACKED -{ - uint8_t cmd_code ; ///< SCSI OpCode - uint8_t reserved ; // has LUN according to wiki - uint32_t lba ; ///< The first Logical Block Address (LBA) accessed by this command - uint8_t reserved2 ; - uint16_t block_count ; ///< Number of Blocks used by this command - uint8_t control ; -} scsi_read10_t, scsi_write10_t; - -TU_VERIFY_STATIC(sizeof(scsi_read10_t) == 10, "size is not correct"); -TU_VERIFY_STATIC(sizeof(scsi_write10_t) == 10, "size is not correct"); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_MSC_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.c deleted file mode 100644 index 159a1125..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.c +++ /dev/null @@ -1,952 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_MSC) - -#include "device/dcd.h" // for faking dcd_event_xfer_complete -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "msc_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -// Can be selectively disabled to reduce logging when troubleshooting other driver -#define MSC_DEBUG 2 - -enum -{ - MSC_STAGE_CMD = 0, - MSC_STAGE_DATA, - MSC_STAGE_STATUS, - MSC_STAGE_STATUS_SENT, - MSC_STAGE_NEED_RESET, -}; - -typedef struct -{ - // TODO optimize alignment - CFG_TUSB_MEM_ALIGN msc_cbw_t cbw; - CFG_TUSB_MEM_ALIGN msc_csw_t csw; - - uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; - - // Bulk Only Transfer (BOT) Protocol - uint8_t stage; - uint32_t total_len; // byte to be transferred, can be smaller than total_bytes in cbw - uint32_t xferred_len; // numbered of bytes transferred so far in the Data Stage - - // Sense Response Data - uint8_t sense_key; - uint8_t add_sense_code; - uint8_t add_sense_qualifier; -}mscd_interface_t; - -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static mscd_interface_t _mscd_itf; -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t _mscd_buf[CFG_TUD_MSC_EP_BUFSIZE]; - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize); -static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc); - -static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc); -static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes); - -TU_ATTR_ALWAYS_INLINE static inline bool is_data_in(uint8_t dir) -{ - return tu_bit_test(dir, 7); -} - -static inline bool send_csw(uint8_t rhport, mscd_interface_t* p_msc) -{ - // Data residue is always = host expect - actual transferred - p_msc->csw.data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len; - - p_msc->stage = MSC_STAGE_STATUS_SENT; - return usbd_edpt_xfer(rhport, p_msc->ep_in , (uint8_t*) &p_msc->csw, sizeof(msc_csw_t)); -} - -static inline bool prepare_cbw(uint8_t rhport, mscd_interface_t* p_msc) -{ - p_msc->stage = MSC_STAGE_CMD; - return usbd_edpt_xfer(rhport, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)); -} - -static void fail_scsi_op(uint8_t rhport, mscd_interface_t* p_msc, uint8_t status) -{ - msc_cbw_t const * p_cbw = &p_msc->cbw; - msc_csw_t * p_csw = &p_msc->csw; - - p_csw->status = status; - p_csw->data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len; - p_msc->stage = MSC_STAGE_STATUS; - - // failed but sense key is not set: default to Illegal Request - if ( p_msc->sense_key == 0 ) tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); - - // If there is data stage and not yet complete, stall it - if ( p_cbw->total_bytes && p_csw->data_residue ) - { - if ( is_data_in(p_cbw->dir) ) - { - usbd_edpt_stall(rhport, p_msc->ep_in); - } - else - { - usbd_edpt_stall(rhport, p_msc->ep_out); - } - } -} - -static inline uint32_t rdwr10_get_lba(uint8_t const command[]) -{ - // use offsetof to avoid pointer to the odd/unaligned address - uint32_t const lba = tu_unaligned_read32(command + offsetof(scsi_write10_t, lba)); - - // lba is in Big Endian - return tu_ntohl(lba); -} - -static inline uint16_t rdwr10_get_blockcount(msc_cbw_t const* cbw) -{ - uint16_t const block_count = tu_unaligned_read16(cbw->command + offsetof(scsi_write10_t, block_count)); - return tu_ntohs(block_count); -} - -static inline uint16_t rdwr10_get_blocksize(msc_cbw_t const* cbw) -{ - // first extract block count in the command - uint16_t const block_count = rdwr10_get_blockcount(cbw); - - // invalid block count - if (block_count == 0) return 0; - - return (uint16_t) (cbw->total_bytes / block_count); -} - -uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw) -{ - uint8_t status = MSC_CSW_STATUS_PASSED; - uint16_t const block_count = rdwr10_get_blockcount(cbw); - - if ( cbw->total_bytes == 0 ) - { - if ( block_count ) - { - TU_LOG(MSC_DEBUG, " SCSI case 2 (Hn < Di) or case 3 (Hn < Do) \r\n"); - status = MSC_CSW_STATUS_PHASE_ERROR; - }else - { - // no data transfer, only exist in complaint test suite - } - }else - { - if ( SCSI_CMD_READ_10 == cbw->command[0] && !is_data_in(cbw->dir) ) - { - TU_LOG(MSC_DEBUG, " SCSI case 10 (Ho <> Di)\r\n"); - status = MSC_CSW_STATUS_PHASE_ERROR; - } - else if ( SCSI_CMD_WRITE_10 == cbw->command[0] && is_data_in(cbw->dir) ) - { - TU_LOG(MSC_DEBUG, " SCSI case 8 (Hi <> Do)\r\n"); - status = MSC_CSW_STATUS_PHASE_ERROR; - } - else if ( 0 == block_count ) - { - TU_LOG(MSC_DEBUG, " SCSI case 4 Hi > Dn (READ10) or case 9 Ho > Dn (WRITE10) \r\n"); - status = MSC_CSW_STATUS_FAILED; - } - else if ( cbw->total_bytes / block_count == 0 ) - { - TU_LOG(MSC_DEBUG, " Computed block size = 0. SCSI case 7 Hi < Di (READ10) or case 13 Ho < Do (WRIT10)\r\n"); - status = MSC_CSW_STATUS_PHASE_ERROR; - } - } - - return status; -} - -//--------------------------------------------------------------------+ -// Debug -//--------------------------------------------------------------------+ -#if CFG_TUSB_DEBUG >= 2 - -TU_ATTR_UNUSED tu_static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] = -{ - { .key = SCSI_CMD_TEST_UNIT_READY , .data = "Test Unit Ready" }, - { .key = SCSI_CMD_INQUIRY , .data = "Inquiry" }, - { .key = SCSI_CMD_MODE_SELECT_6 , .data = "Mode_Select 6" }, - { .key = SCSI_CMD_MODE_SENSE_6 , .data = "Mode_Sense 6" }, - { .key = SCSI_CMD_START_STOP_UNIT , .data = "Start Stop Unit" }, - { .key = SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL , .data = "Prevent/Allow Medium Removal" }, - { .key = SCSI_CMD_READ_CAPACITY_10 , .data = "Read Capacity10" }, - { .key = SCSI_CMD_REQUEST_SENSE , .data = "Request Sense" }, - { .key = SCSI_CMD_READ_FORMAT_CAPACITY , .data = "Read Format Capacity" }, - { .key = SCSI_CMD_READ_10 , .data = "Read10" }, - { .key = SCSI_CMD_WRITE_10 , .data = "Write10" } -}; - -TU_ATTR_UNUSED tu_static tu_lookup_table_t const _msc_scsi_cmd_table = -{ - .count = TU_ARRAY_SIZE(_msc_scsi_cmd_lookup), - .items = _msc_scsi_cmd_lookup -}; - -#endif - -//--------------------------------------------------------------------+ -// APPLICATION API -//--------------------------------------------------------------------+ -bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier) -{ - (void) lun; - - _mscd_itf.sense_key = sense_key; - _mscd_itf.add_sense_code = add_sense_code; - _mscd_itf.add_sense_qualifier = add_sense_qualifier; - - return true; -} - -static inline void set_sense_medium_not_present(uint8_t lun) -{ - // default sense is NOT READY, MEDIUM NOT PRESENT - tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00); -} - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void mscd_init(void) -{ - tu_memclr(&_mscd_itf, sizeof(mscd_interface_t)); -} - -void mscd_reset(uint8_t rhport) -{ - (void) rhport; - tu_memclr(&_mscd_itf, sizeof(mscd_interface_t)); -} - -uint16_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ - // only support SCSI's BOT protocol - TU_VERIFY(TUSB_CLASS_MSC == itf_desc->bInterfaceClass && - MSC_SUBCLASS_SCSI == itf_desc->bInterfaceSubClass && - MSC_PROTOCOL_BOT == itf_desc->bInterfaceProtocol, 0); - - // msc driver length is fixed - uint16_t const drv_len = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t); - - // Max length must be at least 1 interface + 2 endpoints - TU_ASSERT(max_len >= drv_len, 0); - - mscd_interface_t * p_msc = &_mscd_itf; - p_msc->itf_num = itf_desc->bInterfaceNumber; - - // Open endpoint pair - TU_ASSERT( usbd_open_edpt_pair(rhport, tu_desc_next(itf_desc), 2, TUSB_XFER_BULK, &p_msc->ep_out, &p_msc->ep_in), 0 ); - - // Prepare for Command Block Wrapper - TU_ASSERT( prepare_cbw(rhport, p_msc), drv_len); - - return drv_len; -} - -static void proc_bot_reset(mscd_interface_t* p_msc) -{ - p_msc->stage = MSC_STAGE_CMD; - p_msc->total_len = 0; - p_msc->xferred_len = 0; - - p_msc->sense_key = 0; - p_msc->add_sense_code = 0; - p_msc->add_sense_qualifier = 0; -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - // nothing to do with DATA & ACK stage - if (stage != CONTROL_STAGE_SETUP) return true; - - mscd_interface_t* p_msc = &_mscd_itf; - - // Clear Endpoint Feature (stall) for recovery - if ( TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type && - TUSB_REQ_RCPT_ENDPOINT == request->bmRequestType_bit.recipient && - TUSB_REQ_CLEAR_FEATURE == request->bRequest && - TUSB_REQ_FEATURE_EDPT_HALT == request->wValue ) - { - uint8_t const ep_addr = tu_u16_low(request->wIndex); - - if ( p_msc->stage == MSC_STAGE_NEED_RESET ) - { - // reset recovery is required to recover from this stage - // Clear Stall request cannot resolve this -> continue to stall endpoint - usbd_edpt_stall(rhport, ep_addr); - } - else - { - if ( ep_addr == p_msc->ep_in ) - { - if ( p_msc->stage == MSC_STAGE_STATUS ) - { - // resume sending SCSI status if we are in this stage previously before stalled - TU_ASSERT( send_csw(rhport, p_msc) ); - } - } - else if ( ep_addr == p_msc->ep_out ) - { - if ( p_msc->stage == MSC_STAGE_CMD ) - { - // part of reset recovery (probably due to invalid CBW) -> prepare for new command - // Note: skip if already queued previously - if ( usbd_edpt_ready(rhport, p_msc->ep_out) ) - { - TU_ASSERT( prepare_cbw(rhport, p_msc) ); - } - } - } - } - - return true; - } - - // From this point only handle class request only - TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); - - switch ( request->bRequest ) - { - case MSC_REQ_RESET: - TU_LOG(MSC_DEBUG, " MSC BOT Reset\r\n"); - TU_VERIFY(request->wValue == 0 && request->wLength == 0); - - // driver state reset - proc_bot_reset(p_msc); - - tud_control_status(rhport, request); - break; - - case MSC_REQ_GET_MAX_LUN: - { - TU_LOG(MSC_DEBUG, " MSC Get Max Lun\r\n"); - TU_VERIFY(request->wValue == 0 && request->wLength == 1); - - uint8_t maxlun = 1; - if (tud_msc_get_maxlun_cb) maxlun = tud_msc_get_maxlun_cb(); - TU_VERIFY(maxlun); - - // MAX LUN is minus 1 by specs - maxlun--; - - tud_control_xfer(rhport, request, &maxlun, 1); - } - break; - - default: return false; // stall unsupported request - } - - return true; -} - -bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) -{ - (void) event; - - mscd_interface_t* p_msc = &_mscd_itf; - msc_cbw_t const * p_cbw = &p_msc->cbw; - msc_csw_t * p_csw = &p_msc->csw; - - switch (p_msc->stage) - { - case MSC_STAGE_CMD: - //------------- new CBW received -------------// - // Complete IN while waiting for CMD is usually Status of previous SCSI op, ignore it - if(ep_addr != p_msc->ep_out) return true; - - if ( !(xferred_bytes == sizeof(msc_cbw_t) && p_cbw->signature == MSC_CBW_SIGNATURE) ) - { - TU_LOG(MSC_DEBUG, " SCSI CBW is not valid\r\n"); - - // BOT 6.6.1 If CBW is not valid stall both endpoints until reset recovery - p_msc->stage = MSC_STAGE_NEED_RESET; - - // invalid CBW stall both endpoints - usbd_edpt_stall(rhport, p_msc->ep_in); - usbd_edpt_stall(rhport, p_msc->ep_out); - - return false; - } - - TU_LOG(MSC_DEBUG, " SCSI Command [Lun%u]: %s\r\n", p_cbw->lun, tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0])); - //TU_LOG_MEM(MSC_DEBUG, p_cbw, xferred_bytes, 2); - - p_csw->signature = MSC_CSW_SIGNATURE; - p_csw->tag = p_cbw->tag; - p_csw->data_residue = 0; - p_csw->status = MSC_CSW_STATUS_PASSED; - - /*------------- Parse command and prepare DATA -------------*/ - p_msc->stage = MSC_STAGE_DATA; - p_msc->total_len = p_cbw->total_bytes; - p_msc->xferred_len = 0; - - // Read10 or Write10 - if ( (SCSI_CMD_READ_10 == p_cbw->command[0]) || (SCSI_CMD_WRITE_10 == p_cbw->command[0]) ) - { - uint8_t const status = rdwr10_validate_cmd(p_cbw); - - if ( status != MSC_CSW_STATUS_PASSED) - { - fail_scsi_op(rhport, p_msc, status); - }else if ( p_cbw->total_bytes ) - { - if (SCSI_CMD_READ_10 == p_cbw->command[0]) - { - proc_read10_cmd(rhport, p_msc); - }else - { - proc_write10_cmd(rhport, p_msc); - } - }else - { - // no data transfer, only exist in complaint test suite - p_msc->stage = MSC_STAGE_STATUS; - } - } - else - { - // For other SCSI commands - // 1. OUT : queue transfer (invoke app callback after done) - // 2. IN & Zero: Process if is built-in, else Invoke app callback. Skip DATA if zero length - if ( (p_cbw->total_bytes > 0 ) && !is_data_in(p_cbw->dir) ) - { - if (p_cbw->total_bytes > sizeof(_mscd_buf)) - { - TU_LOG(MSC_DEBUG, " SCSI reject non READ10/WRITE10 with large data\r\n"); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); - }else - { - // Didn't check for case 9 (Ho > Dn), which requires examining scsi command first - // but it is OK to just receive data then responded with failed status - TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, (uint16_t) p_msc->total_len) ); - } - }else - { - // First process if it is a built-in commands - int32_t resplen = proc_builtin_scsi(p_cbw->lun, p_cbw->command, _mscd_buf, sizeof(_mscd_buf)); - - // Invoke user callback if not built-in - if ( (resplen < 0) && (p_msc->sense_key == 0) ) - { - resplen = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, (uint16_t) p_msc->total_len); - } - - if ( resplen < 0 ) - { - // unsupported command - TU_LOG(MSC_DEBUG, " SCSI unsupported or failed command\r\n"); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); - } - else if (resplen == 0) - { - if (p_cbw->total_bytes) - { - // 6.7 The 13 Cases: case 4 (Hi > Dn) - // TU_LOG(MSC_DEBUG, " SCSI case 4 (Hi > Dn): %lu\r\n", p_cbw->total_bytes); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); - }else - { - // case 1 Hn = Dn: all good - p_msc->stage = MSC_STAGE_STATUS; - } - } - else - { - if ( p_cbw->total_bytes == 0 ) - { - // 6.7 The 13 Cases: case 2 (Hn < Di) - // TU_LOG(MSC_DEBUG, " SCSI case 2 (Hn < Di): %lu\r\n", p_cbw->total_bytes); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); - }else - { - // cannot return more than host expect - p_msc->total_len = tu_min32((uint32_t) resplen, p_cbw->total_bytes); - TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, (uint16_t) p_msc->total_len) ); - } - } - } - } - break; - - case MSC_STAGE_DATA: - TU_LOG(MSC_DEBUG, " SCSI Data [Lun%u]\r\n", p_cbw->lun); - //TU_LOG_MEM(MSC_DEBUG, _mscd_buf, xferred_bytes, 2); - - if (SCSI_CMD_READ_10 == p_cbw->command[0]) - { - p_msc->xferred_len += xferred_bytes; - - if ( p_msc->xferred_len >= p_msc->total_len ) - { - // Data Stage is complete - p_msc->stage = MSC_STAGE_STATUS; - }else - { - proc_read10_cmd(rhport, p_msc); - } - } - else if (SCSI_CMD_WRITE_10 == p_cbw->command[0]) - { - proc_write10_new_data(rhport, p_msc, xferred_bytes); - } - else - { - p_msc->xferred_len += xferred_bytes; - - // OUT transfer, invoke callback if needed - if ( !is_data_in(p_cbw->dir) ) - { - int32_t cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, (uint16_t) p_msc->total_len); - - if ( cb_result < 0 ) - { - // unsupported command - TU_LOG(MSC_DEBUG, " SCSI unsupported command\r\n"); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); - }else - { - // TODO haven't implement this scenario any further yet - } - } - - if ( p_msc->xferred_len >= p_msc->total_len ) - { - // Data Stage is complete - p_msc->stage = MSC_STAGE_STATUS; - } - else - { - // This scenario with command that take more than one transfer is already rejected at Command stage - TU_BREAKPOINT(); - } - } - break; - - case MSC_STAGE_STATUS: - // processed immediately after this switch, supposedly to be empty - break; - - case MSC_STAGE_STATUS_SENT: - // Wait for the Status phase to complete - if( (ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t)) ) - { - TU_LOG(MSC_DEBUG, " SCSI Status [Lun%u] = %u\r\n", p_cbw->lun, p_csw->status); - // TU_LOG_MEM(MSC_DEBUG, p_csw, xferred_bytes, 2); - - // Invoke complete callback if defined - // Note: There is racing issue with samd51 + qspi flash testing with arduino - // if complete_cb() is invoked after queuing the status. - switch(p_cbw->command[0]) - { - case SCSI_CMD_READ_10: - if ( tud_msc_read10_complete_cb ) tud_msc_read10_complete_cb(p_cbw->lun); - break; - - case SCSI_CMD_WRITE_10: - if ( tud_msc_write10_complete_cb ) tud_msc_write10_complete_cb(p_cbw->lun); - break; - - default: - if ( tud_msc_scsi_complete_cb ) tud_msc_scsi_complete_cb(p_cbw->lun, p_cbw->command); - break; - } - - TU_ASSERT( prepare_cbw(rhport, p_msc) ); - }else - { - // Any xfer ended here is consider unknown error, ignore it - TU_LOG1(" Warning expect SCSI Status but received unknown data\r\n"); - } - break; - - default : break; - } - - if ( p_msc->stage == MSC_STAGE_STATUS ) - { - // skip status if epin is currently stalled, will do it when received Clear Stall request - if ( !usbd_edpt_stalled(rhport, p_msc->ep_in) ) - { - if ( (p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir) ) - { - // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status - // TU_LOG(MSC_DEBUG, " SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len); - usbd_edpt_stall(rhport, p_msc->ep_in); - }else - { - TU_ASSERT( send_csw(rhport, p_msc) ); - } - } - - #if TU_CHECK_MCU(OPT_MCU_CXD56) - // WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD. - // There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and - // hope everything will work - if ( usbd_edpt_stalled(rhport, p_msc->ep_in) ) - { - usbd_edpt_clear_stall(rhport, p_msc->ep_in); - send_csw(rhport, p_msc); - } - #endif - } - - return true; -} - -/*------------------------------------------------------------------*/ -/* SCSI Command Process - *------------------------------------------------------------------*/ - -// return response's length (copied to buffer). Negative if it is not an built-in command or indicate Failed status (CSW) -// In case of a failed status, sense key must be set for reason of failure -static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize) -{ - (void) bufsize; // TODO refractor later - int32_t resplen; - - mscd_interface_t* p_msc = &_mscd_itf; - - switch ( scsi_cmd[0] ) - { - case SCSI_CMD_TEST_UNIT_READY: - resplen = 0; - if ( !tud_msc_test_unit_ready_cb(lun) ) - { - // Failed status response - resplen = - 1; - - // set default sense if not set by callback - if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); - } - break; - - case SCSI_CMD_START_STOP_UNIT: - resplen = 0; - - if (tud_msc_start_stop_cb) - { - scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const *) scsi_cmd; - if ( !tud_msc_start_stop_cb(lun, start_stop->power_condition, start_stop->start, start_stop->load_eject) ) - { - // Failed status response - resplen = - 1; - - // set default sense if not set by callback - if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); - } - } - break; - - case SCSI_CMD_READ_CAPACITY_10: - { - uint32_t block_count; - uint32_t block_size; - uint16_t block_size_u16; - - tud_msc_capacity_cb(lun, &block_count, &block_size_u16); - block_size = (uint32_t) block_size_u16; - - // Invalid block size/count from callback, possibly unit is not ready - // stall this request, set sense key to NOT READY - if (block_count == 0 || block_size == 0) - { - resplen = -1; - - // set default sense if not set by callback - if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); - }else - { - scsi_read_capacity10_resp_t read_capa10; - - read_capa10.last_lba = tu_htonl(block_count-1); - read_capa10.block_size = tu_htonl(block_size); - - resplen = sizeof(read_capa10); - TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &read_capa10, (size_t) resplen)); - } - } - break; - - case SCSI_CMD_READ_FORMAT_CAPACITY: - { - scsi_read_format_capacity_data_t read_fmt_capa = - { - .list_length = 8, - .block_num = 0, - .descriptor_type = 2, // formatted media - .block_size_u16 = 0 - }; - - uint32_t block_count; - uint16_t block_size; - - tud_msc_capacity_cb(lun, &block_count, &block_size); - - // Invalid block size/count from callback, possibly unit is not ready - // stall this request, set sense key to NOT READY - if (block_count == 0 || block_size == 0) - { - resplen = -1; - - // set default sense if not set by callback - if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); - }else - { - read_fmt_capa.block_num = tu_htonl(block_count); - read_fmt_capa.block_size_u16 = tu_htons(block_size); - - resplen = sizeof(read_fmt_capa); - TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &read_fmt_capa, (size_t) resplen)); - } - } - break; - - case SCSI_CMD_INQUIRY: - { - scsi_inquiry_resp_t inquiry_rsp = - { - .is_removable = 1, - .version = 2, - .response_data_format = 2, - .additional_length = sizeof(scsi_inquiry_resp_t) - 5, - }; - - // vendor_id, product_id, product_rev is space padded string - memset(inquiry_rsp.vendor_id , ' ', sizeof(inquiry_rsp.vendor_id)); - memset(inquiry_rsp.product_id , ' ', sizeof(inquiry_rsp.product_id)); - memset(inquiry_rsp.product_rev, ' ', sizeof(inquiry_rsp.product_rev)); - - tud_msc_inquiry_cb(lun, inquiry_rsp.vendor_id, inquiry_rsp.product_id, inquiry_rsp.product_rev); - - resplen = sizeof(inquiry_rsp); - TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &inquiry_rsp, (size_t) resplen)); - } - break; - - case SCSI_CMD_MODE_SENSE_6: - { - scsi_mode_sense6_resp_t mode_resp = - { - .data_len = 3, - .medium_type = 0, - .write_protected = false, - .reserved = 0, - .block_descriptor_len = 0 // no block descriptor are included - }; - - bool writable = true; - if ( tud_msc_is_writable_cb ) - { - writable = tud_msc_is_writable_cb(lun); - } - - mode_resp.write_protected = !writable; - - resplen = sizeof(mode_resp); - TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &mode_resp, (size_t) resplen)); - } - break; - - case SCSI_CMD_REQUEST_SENSE: - { - scsi_sense_fixed_resp_t sense_rsp = - { - .response_code = 0x70, // current, fixed format - .valid = 1 - }; - - sense_rsp.add_sense_len = sizeof(scsi_sense_fixed_resp_t) - 8; - sense_rsp.sense_key = (uint8_t) (p_msc->sense_key & 0x0F); - sense_rsp.add_sense_code = p_msc->add_sense_code; - sense_rsp.add_sense_qualifier = p_msc->add_sense_qualifier; - - resplen = sizeof(sense_rsp); - TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &sense_rsp, (size_t) resplen)); - - // request sense callback could overwrite the sense data - if (tud_msc_request_sense_cb) - { - resplen = tud_msc_request_sense_cb(lun, buffer, (uint16_t) bufsize); - } - - // Clear sense data after copy - tud_msc_set_sense(lun, 0, 0, 0); - } - break; - - default: resplen = -1; break; - } - - return resplen; -} - -static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc) -{ - msc_cbw_t const * p_cbw = &p_msc->cbw; - - // block size already verified not zero - uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); - - // Adjust lba with transferred bytes - uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz); - - // remaining bytes capped at class buffer - int32_t nbytes = (int32_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len); - - // Application can consume smaller bytes - uint32_t const offset = p_msc->xferred_len % block_sz; - nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_buf, (uint32_t) nbytes); - - if ( nbytes < 0 ) - { - // negative means error -> endpoint is stalled & status in CSW set to failed - TU_LOG(MSC_DEBUG, " tud_msc_read10_cb() return -1\r\n"); - - // set sense - set_sense_medium_not_present(p_cbw->lun); - - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); - } - else if ( nbytes == 0 ) - { - // zero means not ready -> simulate an transfer complete so that this driver callback will fired again - dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false); - } - else - { - TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, (uint16_t) nbytes), ); - } -} - -static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc) -{ - msc_cbw_t const * p_cbw = &p_msc->cbw; - bool writable = true; - - if ( tud_msc_is_writable_cb ) - { - writable = tud_msc_is_writable_cb(p_cbw->lun); - } - - if ( !writable ) - { - // Not writable, complete this SCSI op with error - // Sense = Write protected - tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_DATA_PROTECT, 0x27, 0x00); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); - return; - } - - // remaining bytes capped at class buffer - uint16_t nbytes = (uint16_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len); - - // Write10 callback will be called later when usb transfer complete - TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, nbytes), ); -} - -// process new data arrived from WRITE10 -static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes) -{ - msc_cbw_t const * p_cbw = &p_msc->cbw; - - // block size already verified not zero - uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); - - // Adjust lba with transferred bytes - uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz); - - // Invoke callback to consume new data - uint32_t const offset = p_msc->xferred_len % block_sz; - int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_buf, xferred_bytes); - - if ( nbytes < 0 ) - { - // negative means error -> failed this scsi op - TU_LOG(MSC_DEBUG, " tud_msc_write10_cb() return -1\r\n"); - - // update actual byte before failed - p_msc->xferred_len += xferred_bytes; - - // Set sense - set_sense_medium_not_present(p_cbw->lun); - - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); - }else - { - // Application consume less than what we got (including zero) - if ( (uint32_t) nbytes < xferred_bytes ) - { - uint32_t const left_over = xferred_bytes - (uint32_t) nbytes; - if ( nbytes > 0 ) - { - p_msc->xferred_len += (uint16_t) nbytes; - memmove(_mscd_buf, _mscd_buf+nbytes, left_over); - } - - // simulate an transfer complete with adjusted parameters --> callback will be invoked with adjusted parameter - dcd_event_xfer_complete(rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false); - } - else - { - // Application consume all bytes in our buffer - p_msc->xferred_len += xferred_bytes; - - if ( p_msc->xferred_len >= p_msc->total_len ) - { - // Data Stage is complete - p_msc->stage = MSC_STAGE_STATUS; - }else - { - // prepare to receive more data from host - proc_write10_cmd(rhport, p_msc); - } - } - } -} - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.h deleted file mode 100644 index 72f95be0..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_device.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_MSC_DEVICE_H_ -#define _TUSB_MSC_DEVICE_H_ - -#include "common/tusb_common.h" -#include "msc.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Class Driver Configuration -//--------------------------------------------------------------------+ - -#if !defined(CFG_TUD_MSC_EP_BUFSIZE) & defined(CFG_TUD_MSC_BUFSIZE) - // TODO warn user to use new name later on - // #warning CFG_TUD_MSC_BUFSIZE is renamed to CFG_TUD_MSC_EP_BUFSIZE, please update to use the new name - #define CFG_TUD_MSC_EP_BUFSIZE CFG_TUD_MSC_BUFSIZE -#endif - -#ifndef CFG_TUD_MSC_EP_BUFSIZE - #error CFG_TUD_MSC_EP_BUFSIZE must be defined, value of a block size should work well, the more the better -#endif - -TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct"); - -//--------------------------------------------------------------------+ -// Application API -//--------------------------------------------------------------------+ - -// Set SCSI sense response -bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier); - -//--------------------------------------------------------------------+ -// Application Callbacks (WEAK is optional) -//--------------------------------------------------------------------+ - -// Invoked when received SCSI READ10 command -// - Address = lba * BLOCK_SIZE + offset -// - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. -// -// - Application fill the buffer (up to bufsize) with address contents and return number of read byte. If -// - read < bufsize : These bytes are transferred first and callback invoked again for remaining data. -// -// - read == 0 : Indicate application is not ready yet e.g disk I/O busy. -// Callback invoked again with the same parameters later on. -// -// - read < 0 : Indicate application error e.g invalid address. This request will be STALLed -// and return failed status in command status wrapper phase. -int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); - -// Invoked when received SCSI WRITE10 command -// - Address = lba * BLOCK_SIZE + offset -// - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. -// -// - Application write data from buffer to address contents (up to bufsize) and return number of written byte. If -// - write < bufsize : callback invoked again with remaining data later on. -// -// - write == 0 : Indicate application is not ready yet e.g disk I/O busy. -// Callback invoked again with the same parameters later on. -// -// - write < 0 : Indicate application error e.g invalid address. This request will be STALLed -// and return failed status in command status wrapper phase. -// -// TODO change buffer to const uint8_t* -int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize); - -// Invoked when received SCSI_CMD_INQUIRY -// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively -void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]); - -// Invoked when received Test Unit Ready command. -// return true allowing host to read/write this LUN e.g SD card inserted -bool tud_msc_test_unit_ready_cb(uint8_t lun); - -// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size -// Application update block count and block size -void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size); - -/** - * Invoked when received an SCSI command not in built-in list below. - * - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, TEST_UNIT_READY, START_STOP_UNIT, MODE_SENSE6, REQUEST_SENSE - * - READ10 and WRITE10 has their own callbacks - * - * \param[in] lun Logical unit number - * \param[in] scsi_cmd SCSI command contents which application must examine to response accordingly - * \param[out] buffer Buffer for SCSI Data Stage. - * - For INPUT: application must fill this with response. - * - For OUTPUT it holds the Data from host - * \param[in] bufsize Buffer's length. - * - * \return Actual bytes processed, can be zero for no-data command. - * \retval negative Indicate error e.g unsupported command, tinyusb will \b STALL the corresponding - * endpoint and return failed status in command status wrapper phase. - */ -int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize); - -/*------------- Optional callbacks -------------*/ - -// Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation -TU_ATTR_WEAK uint8_t tud_msc_get_maxlun_cb(void); - -// Invoked when received Start Stop Unit command -// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage -// - Start = 1 : active mode, if load_eject = 1 : load disk storage -TU_ATTR_WEAK bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject); - -// Invoked when received REQUEST_SENSE -TU_ATTR_WEAK int32_t tud_msc_request_sense_cb(uint8_t lun, void* buffer, uint16_t bufsize); - -// Invoked when Read10 command is complete -TU_ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun); - -// Invoke when Write10 command is complete, can be used to flush flash caching -TU_ATTR_WEAK void tud_msc_write10_complete_cb(uint8_t lun); - -// Invoked when command in tud_msc_scsi_cb is complete -TU_ATTR_WEAK void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16]); - -// Invoked to check if device is writable as part of SCSI WRITE10 -TU_ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void mscd_init (void); -void mscd_reset (uint8_t rhport); -uint16_t mscd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool mscd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * p_request); -bool mscd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_MSC_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.c b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.c deleted file mode 100644 index 1b48813e..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.c +++ /dev/null @@ -1,525 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if CFG_TUH_ENABLED && CFG_TUH_MSC - -#include "host/usbh.h" -#include "host/usbh_classdriver.h" - -#include "msc_host.h" - -// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message -#define MSCH_DEBUG 2 - -#define TU_LOG_MSCH(...) TU_LOG(MSCH_DEBUG, __VA_ARGS__) - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -enum -{ - MSC_STAGE_IDLE = 0, - MSC_STAGE_CMD, - MSC_STAGE_DATA, - MSC_STAGE_STATUS, -}; - -typedef struct -{ - uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; - - uint8_t max_lun; - - volatile bool configured; // Receive SET_CONFIGURE - volatile bool mounted; // Enumeration is complete - - struct { - uint32_t block_size; - uint32_t block_count; - } capacity[CFG_TUH_MSC_MAXLUN]; - - //------------- SCSI -------------// - uint8_t stage; - void* buffer; - tuh_msc_complete_cb_t complete_cb; - uintptr_t complete_arg; - - CFG_TUH_MEM_ALIGN msc_cbw_t cbw; - CFG_TUH_MEM_ALIGN msc_csw_t csw; -}msch_interface_t; - -CFG_TUH_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUH_DEVICE_MAX]; - -// buffer used to read scsi information when mounted -// largest response data currently is inquiry TODO Inquiry is not part of enum anymore -CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN -static uint8_t _msch_buffer[sizeof(scsi_inquiry_resp_t)]; - -TU_ATTR_ALWAYS_INLINE -static inline msch_interface_t* get_itf(uint8_t dev_addr) -{ - return &_msch_itf[dev_addr-1]; -} - -//--------------------------------------------------------------------+ -// PUBLIC API -//--------------------------------------------------------------------+ -uint8_t tuh_msc_get_maxlun(uint8_t dev_addr) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - return p_msc->max_lun; -} - -uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - return p_msc->capacity[lun].block_count; -} - -uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - return p_msc->capacity[lun].block_size; -} - -bool tuh_msc_mounted(uint8_t dev_addr) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - return p_msc->mounted; -} - -bool tuh_msc_ready(uint8_t dev_addr) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - return p_msc->mounted && !usbh_edpt_busy(dev_addr, p_msc->ep_in); -} - -//--------------------------------------------------------------------+ -// PUBLIC API: SCSI COMMAND -//--------------------------------------------------------------------+ -static inline void cbw_init(msc_cbw_t *cbw, uint8_t lun) -{ - tu_memclr(cbw, sizeof(msc_cbw_t)); - cbw->signature = MSC_CBW_SIGNATURE; - cbw->tag = 0x54555342; // TUSB - cbw->lun = lun; -} - -bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - TU_VERIFY(p_msc->configured); - - // TODO claim endpoint - - p_msc->cbw = *cbw; - p_msc->stage = MSC_STAGE_CMD; - p_msc->buffer = data; - p_msc->complete_cb = complete_cb; - p_msc->complete_arg = arg; - - TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t))); - - return true; -} - -bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - TU_VERIFY(p_msc->configured); - - msc_cbw_t cbw; - cbw_init(&cbw, lun); - - cbw.total_bytes = sizeof(scsi_read_capacity10_resp_t); - cbw.dir = TUSB_DIR_IN_MASK; - cbw.cmd_len = sizeof(scsi_read_capacity10_t); - cbw.command[0] = SCSI_CMD_READ_CAPACITY_10; - - return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg); -} - -bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - TU_VERIFY(p_msc->mounted); - - msc_cbw_t cbw; - cbw_init(&cbw, lun); - - cbw.total_bytes = sizeof(scsi_inquiry_resp_t); - cbw.dir = TUSB_DIR_IN_MASK; - cbw.cmd_len = sizeof(scsi_inquiry_t); - - scsi_inquiry_t const cmd_inquiry = - { - .cmd_code = SCSI_CMD_INQUIRY, - .alloc_length = sizeof(scsi_inquiry_resp_t) - }; - memcpy(cbw.command, &cmd_inquiry, cbw.cmd_len); - - return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg); -} - -bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - TU_VERIFY(p_msc->configured); - - msc_cbw_t cbw; - cbw_init(&cbw, lun); - - cbw.total_bytes = 0; - cbw.dir = TUSB_DIR_OUT; - cbw.cmd_len = sizeof(scsi_test_unit_ready_t); - cbw.command[0] = SCSI_CMD_TEST_UNIT_READY; - cbw.command[1] = lun; // according to wiki TODO need verification - - return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb, arg); -} - -bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ - msc_cbw_t cbw; - cbw_init(&cbw, lun); - - cbw.total_bytes = 18; // TODO sense response - cbw.dir = TUSB_DIR_IN_MASK; - cbw.cmd_len = sizeof(scsi_request_sense_t); - - scsi_request_sense_t const cmd_request_sense = - { - .cmd_code = SCSI_CMD_REQUEST_SENSE, - .alloc_length = 18 - }; - - memcpy(cbw.command, &cmd_request_sense, cbw.cmd_len); - - return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg); -} - -bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - TU_VERIFY(p_msc->mounted); - - msc_cbw_t cbw; - cbw_init(&cbw, lun); - - cbw.total_bytes = block_count*p_msc->capacity[lun].block_size; - cbw.dir = TUSB_DIR_IN_MASK; - cbw.cmd_len = sizeof(scsi_read10_t); - - scsi_read10_t const cmd_read10 = - { - .cmd_code = SCSI_CMD_READ_10, - .lba = tu_htonl(lba), - .block_count = tu_htons(block_count) - }; - - memcpy(cbw.command, &cmd_read10, cbw.cmd_len); - - return tuh_msc_scsi_command(dev_addr, &cbw, buffer, complete_cb, arg); -} - -bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - TU_VERIFY(p_msc->mounted); - - msc_cbw_t cbw; - cbw_init(&cbw, lun); - - cbw.total_bytes = block_count*p_msc->capacity[lun].block_size; - cbw.dir = TUSB_DIR_OUT; - cbw.cmd_len = sizeof(scsi_write10_t); - - scsi_write10_t const cmd_write10 = - { - .cmd_code = SCSI_CMD_WRITE_10, - .lba = tu_htonl(lba), - .block_count = tu_htons(block_count) - }; - - memcpy(cbw.command, &cmd_write10, cbw.cmd_len); - - return tuh_msc_scsi_command(dev_addr, &cbw, (void*)(uintptr_t) buffer, complete_cb, arg); -} - -#if 0 -// MSC interface Reset (not used now) -bool tuh_msc_reset(uint8_t dev_addr) -{ - tusb_control_request_t const new_request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = MSC_REQ_RESET, - .wValue = 0, - .wIndex = p_msc->itf_num, - .wLength = 0 - }; - TU_ASSERT( usbh_control_xfer( dev_addr, &new_request, NULL ) ); -} -#endif - -//--------------------------------------------------------------------+ -// CLASS-USBH API -//--------------------------------------------------------------------+ -void msch_init(void) -{ - tu_memclr(_msch_itf, sizeof(_msch_itf)); -} - -void msch_close(uint8_t dev_addr) -{ - TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); - - msch_interface_t* p_msc = get_itf(dev_addr); - - // invoke Application Callback - if (p_msc->mounted && tuh_msc_umount_cb) tuh_msc_umount_cb(dev_addr); - - tu_memclr(p_msc, sizeof(msch_interface_t)); -} - -bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - msc_cbw_t const * cbw = &p_msc->cbw; - msc_csw_t * csw = &p_msc->csw; - - switch (p_msc->stage) - { - case MSC_STAGE_CMD: - // Must be Command Block - TU_ASSERT(ep_addr == p_msc->ep_out && event == XFER_RESULT_SUCCESS && xferred_bytes == sizeof(msc_cbw_t)); - - if ( cbw->total_bytes && p_msc->buffer ) - { - // Data stage if any - p_msc->stage = MSC_STAGE_DATA; - - uint8_t const ep_data = (cbw->dir & TUSB_DIR_IN_MASK) ? p_msc->ep_in : p_msc->ep_out; - TU_ASSERT(usbh_edpt_xfer(dev_addr, ep_data, p_msc->buffer, (uint16_t) cbw->total_bytes)); - }else - { - // Status stage - p_msc->stage = MSC_STAGE_STATUS; - TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t))); - } - break; - - case MSC_STAGE_DATA: - // Status stage - p_msc->stage = MSC_STAGE_STATUS; - TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t))); - break; - - case MSC_STAGE_STATUS: - // SCSI op is complete - p_msc->stage = MSC_STAGE_IDLE; - - if (p_msc->complete_cb) - { - tuh_msc_complete_data_t const cb_data = - { - .cbw = cbw, - .csw = csw, - .scsi_data = p_msc->buffer, - .user_arg = p_msc->complete_arg - }; - p_msc->complete_cb(dev_addr, &cb_data); - } - break; - - // unknown state - default: break; - } - - return true; -} - -//--------------------------------------------------------------------+ -// MSC Enumeration -//--------------------------------------------------------------------+ - -static void config_get_maxlun_complete (tuh_xfer_t* xfer); -static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data); -static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); -static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); - -bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) -{ - (void) rhport; - TU_VERIFY (MSC_SUBCLASS_SCSI == desc_itf->bInterfaceSubClass && - MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol); - - // msc driver length is fixed - uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); - TU_ASSERT(drv_len <= max_len); - - msch_interface_t* p_msc = get_itf(dev_addr); - tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(desc_itf); - - for(uint32_t i=0; i<2; i++) - { - TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer); - TU_ASSERT(tuh_edpt_open(dev_addr, ep_desc)); - - if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN ) - { - p_msc->ep_in = ep_desc->bEndpointAddress; - }else - { - p_msc->ep_out = ep_desc->bEndpointAddress; - } - - ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(ep_desc); - } - - p_msc->itf_num = desc_itf->bInterfaceNumber; - - return true; -} - -bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - TU_ASSERT(p_msc->itf_num == itf_num); - - p_msc->configured = true; - - //------------- Get Max Lun -------------// - TU_LOG_MSCH("MSC Get Max Lun\r\n"); - tusb_control_request_t const request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_IN - }, - .bRequest = MSC_REQ_GET_MAX_LUN, - .wValue = 0, - .wIndex = itf_num, - .wLength = 1 - }; - - tuh_xfer_t xfer = - { - .daddr = dev_addr, - .ep_addr = 0, - .setup = &request, - .buffer = &p_msc->max_lun, - .complete_cb = config_get_maxlun_complete, - .user_data = 0 - }; - TU_ASSERT(tuh_control_xfer(&xfer)); - - return true; -} - -static void config_get_maxlun_complete (tuh_xfer_t* xfer) -{ - uint8_t const daddr = xfer->daddr; - msch_interface_t* p_msc = get_itf(daddr); - - // STALL means zero - p_msc->max_lun = (XFER_RESULT_SUCCESS == xfer->result) ? _msch_buffer[0] : 0; - p_msc->max_lun++; // MAX LUN is minus 1 by specs - - // TODO multiple LUN support - TU_LOG_MSCH("SCSI Test Unit Ready\r\n"); - uint8_t const lun = 0; - tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete, 0); -} - -static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) -{ - msc_cbw_t const* cbw = cb_data->cbw; - msc_csw_t const* csw = cb_data->csw; - - if (csw->status == 0) - { - // Unit is ready, read its capacity - TU_LOG_MSCH("SCSI Read Capacity\r\n"); - tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete, 0); - }else - { - // Note: During enumeration, some device fails Test Unit Ready and require a few retries - // with Request Sense to start working !! - // TODO limit number of retries - TU_LOG_MSCH("SCSI Request Sense\r\n"); - TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, _msch_buffer, config_request_sense_complete, 0)); - } - - return true; -} - -static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) -{ - msc_cbw_t const* cbw = cb_data->cbw; - msc_csw_t const* csw = cb_data->csw; - - TU_ASSERT(csw->status == 0); - TU_ASSERT(tuh_msc_test_unit_ready(dev_addr, cbw->lun, config_test_unit_ready_complete, 0)); - return true; -} - -static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) -{ - msc_cbw_t const* cbw = cb_data->cbw; - msc_csw_t const* csw = cb_data->csw; - - TU_ASSERT(csw->status == 0); - - msch_interface_t* p_msc = get_itf(dev_addr); - - // Capacity response field: Block size and Last LBA are both Big-Endian - scsi_read_capacity10_resp_t* resp = (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer); - p_msc->capacity[cbw->lun].block_count = tu_ntohl(resp->last_lba) + 1; - p_msc->capacity[cbw->lun].block_size = tu_ntohl(resp->block_size); - - // Mark enumeration is complete - p_msc->mounted = true; - if (tuh_msc_mount_cb) tuh_msc_mount_cb(dev_addr); - - // notify usbh that driver enumeration is complete - usbh_driver_set_config_complete(dev_addr, p_msc->itf_num); - - return true; -} - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.h b/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.h deleted file mode 100644 index 6c0e5c9d..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/msc/msc_host.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_MSC_HOST_H_ -#define _TUSB_MSC_HOST_H_ - -#include "msc.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Class Driver Configuration -//--------------------------------------------------------------------+ - -#ifndef CFG_TUH_MSC_MAXLUN -#define CFG_TUH_MSC_MAXLUN 4 -#endif - -typedef struct { - msc_cbw_t const* cbw; // SCSI command - msc_csw_t const* csw; // SCSI status - void* scsi_data; // SCSI Data - uintptr_t user_arg; // user argument -}tuh_msc_complete_data_t; - -typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); - -//--------------------------------------------------------------------+ -// Application API -//--------------------------------------------------------------------+ - -// Check if device supports MassStorage interface. -// This function true after tuh_msc_mounted_cb() and false after tuh_msc_unmounted_cb() -bool tuh_msc_mounted(uint8_t dev_addr); - -// Check if the interface is currently ready or busy transferring data -bool tuh_msc_ready(uint8_t dev_addr); - -// Get Max Lun -uint8_t tuh_msc_get_maxlun(uint8_t dev_addr); - -// Get number of block -uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun); - -// Get block size in bytes -uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun); - -// Perform a full SCSI command (cbw, data, csw) in non-blocking manner. -// Complete callback is invoked when SCSI op is complete. -// return true if success, false if there is already pending operation. -bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); - -// Perform SCSI Inquiry command -// Complete callback is invoked when SCSI op is complete. -bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); - -// Perform SCSI Test Unit Ready command -// Complete callback is invoked when SCSI op is complete. -bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); - -// Perform SCSI Request Sense 10 command -// Complete callback is invoked when SCSI op is complete. -bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); - -// Perform SCSI Read 10 command. Read n blocks starting from LBA to buffer -// Complete callback is invoked when SCSI op is complete. -bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); - -// Perform SCSI Write 10 command. Write n blocks starting from LBA to device -// Complete callback is invoked when SCSI op is complete. -bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); - -// Perform SCSI Read Capacity 10 command -// Complete callback is invoked when SCSI op is complete. -// Note: during enumeration, host stack already carried out this request. Application can retrieve capacity by -// simply call tuh_msc_get_block_count() and tuh_msc_get_block_size() -bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); - -//------------- Application Callback -------------// - -// Invoked when a device with MassStorage interface is mounted -TU_ATTR_WEAK void tuh_msc_mount_cb(uint8_t dev_addr); - -// Invoked when a device with MassStorage interface is unmounted -TU_ATTR_WEAK void tuh_msc_umount_cb(uint8_t dev_addr); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ - -void msch_init (void); -bool msch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); -bool msch_set_config (uint8_t dev_addr, uint8_t itf_num); -void msch_close (uint8_t dev_addr); -bool msch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_MSC_HOST_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/net/ecm_rndis_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/net/ecm_rndis_device.c deleted file mode 100644 index 8ac7cbd0..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/net/ecm_rndis_device.c +++ /dev/null @@ -1,450 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Peter Lawrence - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if ( CFG_TUD_ENABLED && CFG_TUD_ECM_RNDIS ) - -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "net_device.h" -#include "rndis_protocol.h" - -void rndis_class_set_handler(uint8_t *data, int size); /* found in ./misc/networking/rndis_reports.c */ - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -typedef struct -{ - uint8_t itf_num; // Index number of Management Interface, +1 for Data Interface - uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active - - uint8_t ep_notif; - uint8_t ep_in; - uint8_t ep_out; - - bool ecm_mode; - - // Endpoint descriptor use to open/close when receiving SetInterface - // TODO since configuration descriptor may not be long-lived memory, we should - // keep a copy of endpoint attribute instead - uint8_t const * ecm_desc_epdata; - -} netd_interface_t; - -#define CFG_TUD_NET_PACKET_PREFIX_LEN sizeof(rndis_data_packet_t) -#define CFG_TUD_NET_PACKET_SUFFIX_LEN 0 - -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static -uint8_t received[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; - -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static -uint8_t transmitted[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; - -struct ecm_notify_struct -{ - tusb_control_request_t header; - uint32_t downlink, uplink; -}; - -tu_static const struct ecm_notify_struct ecm_notify_nc = -{ - .header = { - .bmRequestType = 0xA1, - .bRequest = 0 /* NETWORK_CONNECTION aka NetworkConnection */, - .wValue = 1 /* Connected */, - .wLength = 0, - }, -}; - -tu_static const struct ecm_notify_struct ecm_notify_csc = -{ - .header = { - .bmRequestType = 0xA1, - .bRequest = 0x2A /* CONNECTION_SPEED_CHANGE aka ConnectionSpeedChange */, - .wLength = 8, - }, - .downlink = 9728000, - .uplink = 9728000, -}; - -// TODO remove CFG_TUSB_MEM_SECTION, control internal buffer is already in this special section -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static union -{ - uint8_t rndis_buf[120]; - struct ecm_notify_struct ecm_buf; -} notify; - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -// TODO remove CFG_TUSB_MEM_SECTION -CFG_TUSB_MEM_SECTION tu_static netd_interface_t _netd_itf; - -tu_static bool can_xmit; - -void tud_network_recv_renew(void) -{ - usbd_edpt_xfer(0, _netd_itf.ep_out, received, sizeof(received)); -} - -static void do_in_xfer(uint8_t *buf, uint16_t len) -{ - can_xmit = false; - usbd_edpt_xfer(0, _netd_itf.ep_in, buf, len); -} - -void netd_report(uint8_t *buf, uint16_t len) -{ - uint8_t const rhport = 0; - - // skip if previous report not yet acknowledged by host - if ( usbd_edpt_busy(rhport, _netd_itf.ep_notif) ) return; - usbd_edpt_xfer(rhport, _netd_itf.ep_notif, buf, len); -} - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void netd_init(void) -{ - tu_memclr(&_netd_itf, sizeof(_netd_itf)); -} - -void netd_reset(uint8_t rhport) -{ - (void) rhport; - - netd_init(); -} - -uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ - bool const is_rndis = (TUD_RNDIS_ITF_CLASS == itf_desc->bInterfaceClass && - TUD_RNDIS_ITF_SUBCLASS == itf_desc->bInterfaceSubClass && - TUD_RNDIS_ITF_PROTOCOL == itf_desc->bInterfaceProtocol); - - bool const is_ecm = (TUSB_CLASS_CDC == itf_desc->bInterfaceClass && - CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL == itf_desc->bInterfaceSubClass && - 0x00 == itf_desc->bInterfaceProtocol); - - TU_VERIFY(is_rndis || is_ecm, 0); - - // confirm interface hasn't already been allocated - TU_ASSERT(0 == _netd_itf.ep_notif, 0); - - // sanity check the descriptor - _netd_itf.ecm_mode = is_ecm; - - //------------- Management Interface -------------// - _netd_itf.itf_num = itf_desc->bInterfaceNumber; - - uint16_t drv_len = sizeof(tusb_desc_interface_t); - uint8_t const * p_desc = tu_desc_next( itf_desc ); - - // Communication Functional Descriptors - while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) - { - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - // notification endpoint (if any) - if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) - { - TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 ); - - _netd_itf.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; - - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - //------------- Data Interface -------------// - // - RNDIS Data followed immediately by a pair of endpoints - // - CDC-ECM data interface has 2 alternate settings - // - 0 : zero endpoints for inactive (default) - // - 1 : IN & OUT endpoints for active networking - TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); - - do - { - tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc; - TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass, 0); - - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - }while( _netd_itf.ecm_mode && (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (drv_len <= max_len) ); - - // Pair of endpoints - TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0); - - if ( _netd_itf.ecm_mode ) - { - // ECM by default is in-active, save the endpoint attribute - // to open later when received setInterface - _netd_itf.ecm_desc_epdata = p_desc; - }else - { - // Open endpoint pair for RNDIS - TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in), 0 ); - - tud_network_init_cb(); - - // we are ready to transmit a packet - can_xmit = true; - - // prepare for incoming packets - tud_network_recv_renew(); - } - - drv_len += 2*sizeof(tusb_desc_endpoint_t); - - return drv_len; -} - -static void ecm_report(bool nc) -{ - notify.ecm_buf = (nc) ? ecm_notify_nc : ecm_notify_csc; - notify.ecm_buf.header.wIndex = _netd_itf.itf_num; - netd_report((uint8_t *)¬ify.ecm_buf, (nc) ? sizeof(notify.ecm_buf.header) : sizeof(notify.ecm_buf)); -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - if ( stage == CONTROL_STAGE_SETUP ) - { - switch ( request->bmRequestType_bit.type ) - { - case TUSB_REQ_TYPE_STANDARD: - switch ( request->bRequest ) - { - case TUSB_REQ_GET_INTERFACE: - { - uint8_t const req_itfnum = (uint8_t) request->wIndex; - TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum); - - tud_control_xfer(rhport, request, &_netd_itf.itf_data_alt, 1); - } - break; - - case TUSB_REQ_SET_INTERFACE: - { - uint8_t const req_itfnum = (uint8_t) request->wIndex; - uint8_t const req_alt = (uint8_t) request->wValue; - - // Only valid for Data Interface with Alternate is either 0 or 1 - TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum && req_alt < 2); - - // ACM-ECM only: qequest to enable/disable network activities - TU_VERIFY(_netd_itf.ecm_mode); - - _netd_itf.itf_data_alt = req_alt; - - if ( _netd_itf.itf_data_alt ) - { - // TODO since we don't actually close endpoint - // hack here to not re-open it - if ( _netd_itf.ep_in == 0 && _netd_itf.ep_out == 0 ) - { - TU_ASSERT(_netd_itf.ecm_desc_epdata); - TU_ASSERT( usbd_open_edpt_pair(rhport, _netd_itf.ecm_desc_epdata, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in) ); - - // TODO should be merge with RNDIS's after endpoint opened - // Also should have opposite callback for application to disable network !! - tud_network_init_cb(); - can_xmit = true; // we are ready to transmit a packet - tud_network_recv_renew(); // prepare for incoming packets - } - }else - { - // TODO close the endpoint pair - // For now pretend that we did, this should have no harm since host won't try to - // communicate with the endpoints again - // _netd_itf.ep_in = _netd_itf.ep_out = 0 - } - - tud_control_status(rhport, request); - } - break; - - // unsupported request - default: return false; - } - break; - - case TUSB_REQ_TYPE_CLASS: - TU_VERIFY (_netd_itf.itf_num == request->wIndex); - - if (_netd_itf.ecm_mode) - { - /* the only required CDC-ECM Management Element Request is SetEthernetPacketFilter */ - if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest) - { - tud_control_xfer(rhport, request, NULL, 0); - ecm_report(true); - } - } - else - { - if (request->bmRequestType_bit.direction == TUSB_DIR_IN) - { - rndis_generic_msg_t *rndis_msg = (rndis_generic_msg_t *) ((void*) notify.rndis_buf); - uint32_t msglen = tu_le32toh(rndis_msg->MessageLength); - TU_ASSERT(msglen <= sizeof(notify.rndis_buf)); - tud_control_xfer(rhport, request, notify.rndis_buf, (uint16_t) msglen); - } - else - { - tud_control_xfer(rhport, request, notify.rndis_buf, (uint16_t) sizeof(notify.rndis_buf)); - } - } - break; - - // unsupported request - default: return false; - } - } - else if ( stage == CONTROL_STAGE_DATA ) - { - // Handle RNDIS class control OUT only - if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && - request->bmRequestType_bit.direction == TUSB_DIR_OUT && - _netd_itf.itf_num == request->wIndex) - { - if ( !_netd_itf.ecm_mode ) - { - rndis_class_set_handler(notify.rndis_buf, request->wLength); - } - } - } - - return true; -} - -static void handle_incoming_packet(uint32_t len) -{ - uint8_t *pnt = received; - uint32_t size = 0; - - if (_netd_itf.ecm_mode) - { - size = len; - } - else - { - rndis_data_packet_t *r = (rndis_data_packet_t *) ((void*) pnt); - if (len >= sizeof(rndis_data_packet_t)) - if ( (r->MessageType == REMOTE_NDIS_PACKET_MSG) && (r->MessageLength <= len)) - if ( (r->DataOffset + offsetof(rndis_data_packet_t, DataOffset) + r->DataLength) <= len) - { - pnt = &received[r->DataOffset + offsetof(rndis_data_packet_t, DataOffset)]; - size = r->DataLength; - } - } - - if (!tud_network_recv_cb(pnt, (uint16_t) size)) - { - /* if a buffer was never handled by user code, we must renew on the user's behalf */ - tud_network_recv_renew(); - } -} - -bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void) rhport; - (void) result; - - /* new packet received */ - if ( ep_addr == _netd_itf.ep_out ) - { - handle_incoming_packet(xferred_bytes); - } - - /* data transmission finished */ - if ( ep_addr == _netd_itf.ep_in ) - { - /* TinyUSB requires the class driver to implement ZLP (since ZLP usage is class-specific) */ - - if ( xferred_bytes && (0 == (xferred_bytes % CFG_TUD_NET_ENDPOINT_SIZE)) ) - { - do_in_xfer(NULL, 0); /* a ZLP is needed */ - } - else - { - /* we're finally finished */ - can_xmit = true; - } - } - - if ( _netd_itf.ecm_mode && (ep_addr == _netd_itf.ep_notif) ) - { - if (sizeof(notify.ecm_buf.header) == xferred_bytes) ecm_report(false); - } - - return true; -} - -bool tud_network_can_xmit(uint16_t size) -{ - (void)size; - - return can_xmit; -} - -void tud_network_xmit(void *ref, uint16_t arg) -{ - uint8_t *data; - uint16_t len; - - if (!can_xmit) - return; - - len = (_netd_itf.ecm_mode) ? 0 : CFG_TUD_NET_PACKET_PREFIX_LEN; - data = transmitted + len; - - len += tud_network_xmit_cb(data, ref, arg); - - if (!_netd_itf.ecm_mode) - { - rndis_data_packet_t *hdr = (rndis_data_packet_t *) ((void*) transmitted); - memset(hdr, 0, sizeof(rndis_data_packet_t)); - hdr->MessageType = REMOTE_NDIS_PACKET_MSG; - hdr->MessageLength = len; - hdr->DataOffset = sizeof(rndis_data_packet_t) - offsetof(rndis_data_packet_t, DataOffset); - hdr->DataLength = len - sizeof(rndis_data_packet_t); - } - - do_in_xfer(transmitted, len); -} - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/net/ncm.h b/test-devices/loopback-stm32/lib/tinyusb/class/net/ncm.h deleted file mode 100644 index 96ba11fb..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/net/ncm.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - - -#ifndef _TUSB_NCM_H_ -#define _TUSB_NCM_H_ - -#include "common/tusb_common.h" - -#ifdef __cplusplus - extern "C" { -#endif - -// Table 4.3 Data Class Interface Protocol Codes -typedef enum -{ - NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK = 0x01 -} ncm_data_interface_protocol_code_t; - - -// Table 6.2 Class-Specific Request Codes for Network Control Model subclass -typedef enum -{ - NCM_SET_ETHERNET_MULTICAST_FILTERS = 0x40, - NCM_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x41, - NCM_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x42, - NCM_SET_ETHERNET_PACKET_FILTER = 0x43, - NCM_GET_ETHERNET_STATISTIC = 0x44, - NCM_GET_NTB_PARAMETERS = 0x80, - NCM_GET_NET_ADDRESS = 0x81, - NCM_SET_NET_ADDRESS = 0x82, - NCM_GET_NTB_FORMAT = 0x83, - NCM_SET_NTB_FORMAT = 0x84, - NCM_GET_NTB_INPUT_SIZE = 0x85, - NCM_SET_NTB_INPUT_SIZE = 0x86, - NCM_GET_MAX_DATAGRAM_SIZE = 0x87, - NCM_SET_MAX_DATAGRAM_SIZE = 0x88, - NCM_GET_CRC_MODE = 0x89, - NCM_SET_CRC_MODE = 0x8A, -} ncm_request_code_t; - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/net/ncm_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/net/ncm_device.c deleted file mode 100644 index 9e958024..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/net/ncm_device.c +++ /dev/null @@ -1,511 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Jacob Berg Potter - * Copyright (c) 2020 Peter Lawrence - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if ( CFG_TUD_ENABLED && CFG_TUD_NCM ) - -#include "device/usbd.h" -#include "device/usbd_pvt.h" -#include "net_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -#define NTH16_SIGNATURE 0x484D434E -#define NDP16_SIGNATURE_NCM0 0x304D434E -#define NDP16_SIGNATURE_NCM1 0x314D434E - -typedef struct TU_ATTR_PACKED -{ - uint16_t wLength; - uint16_t bmNtbFormatsSupported; - uint32_t dwNtbInMaxSize; - uint16_t wNdbInDivisor; - uint16_t wNdbInPayloadRemainder; - uint16_t wNdbInAlignment; - uint16_t wReserved; - uint32_t dwNtbOutMaxSize; - uint16_t wNdbOutDivisor; - uint16_t wNdbOutPayloadRemainder; - uint16_t wNdbOutAlignment; - uint16_t wNtbOutMaxDatagrams; -} ntb_parameters_t; - -typedef struct TU_ATTR_PACKED -{ - uint32_t dwSignature; - uint16_t wHeaderLength; - uint16_t wSequence; - uint16_t wBlockLength; - uint16_t wNdpIndex; -} nth16_t; - -typedef struct TU_ATTR_PACKED -{ - uint16_t wDatagramIndex; - uint16_t wDatagramLength; -} ndp16_datagram_t; - -typedef struct TU_ATTR_PACKED -{ - uint32_t dwSignature; - uint16_t wLength; - uint16_t wNextNdpIndex; - ndp16_datagram_t datagram[]; -} ndp16_t; - -typedef union TU_ATTR_PACKED { - struct { - nth16_t nth; - ndp16_t ndp; - }; - uint8_t data[CFG_TUD_NCM_IN_NTB_MAX_SIZE]; -} transmit_ntb_t; - -struct ecm_notify_struct -{ - tusb_control_request_t header; - uint32_t downlink, uplink; -}; - -typedef struct -{ - uint8_t itf_num; // Index number of Management Interface, +1 for Data Interface - uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active - - uint8_t ep_notif; - uint8_t ep_in; - uint8_t ep_out; - - const ndp16_t *ndp; - uint8_t num_datagrams, current_datagram_index; - - enum { - REPORT_SPEED, - REPORT_CONNECTED, - REPORT_DONE - } report_state; - bool report_pending; - - uint8_t current_ntb; // Index in transmit_ntb[] that is currently being filled with datagrams - uint8_t datagram_count; // Number of datagrams in transmit_ntb[current_ntb] - uint16_t next_datagram_offset; // Offset in transmit_ntb[current_ntb].data to place the next datagram - uint16_t ntb_in_size; // Maximum size of transmitted (IN to host) NTBs; initially CFG_TUD_NCM_IN_NTB_MAX_SIZE - uint8_t max_datagrams_per_ntb; // Maximum number of datagrams per NTB; initially CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB - - uint16_t nth_sequence; // Sequence number counter for transmitted NTBs - - bool transferring; - -} ncm_interface_t; - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ - -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static const ntb_parameters_t ntb_parameters = { - .wLength = sizeof(ntb_parameters_t), - .bmNtbFormatsSupported = 0x01, - .dwNtbInMaxSize = CFG_TUD_NCM_IN_NTB_MAX_SIZE, - .wNdbInDivisor = 4, - .wNdbInPayloadRemainder = 0, - .wNdbInAlignment = CFG_TUD_NCM_ALIGNMENT, - .wReserved = 0, - .dwNtbOutMaxSize = CFG_TUD_NCM_OUT_NTB_MAX_SIZE, - .wNdbOutDivisor = 4, - .wNdbOutPayloadRemainder = 0, - .wNdbOutAlignment = CFG_TUD_NCM_ALIGNMENT, - .wNtbOutMaxDatagrams = 0 -}; - -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static transmit_ntb_t transmit_ntb[2]; - -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t receive_ntb[CFG_TUD_NCM_OUT_NTB_MAX_SIZE]; - -tu_static ncm_interface_t ncm_interface; - -/* - * Set up the NTB state in ncm_interface to be ready to add datagrams. - */ -static void ncm_prepare_for_tx(void) { - ncm_interface.datagram_count = 0; - // datagrams start after all the headers - ncm_interface.next_datagram_offset = sizeof(nth16_t) + sizeof(ndp16_t) - + ((CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB + 1) * sizeof(ndp16_datagram_t)); -} - -/* - * If not already transmitting, start sending the current NTB to the host and swap buffers - * to start filling the other one with datagrams. - */ -static void ncm_start_tx(void) { - if (ncm_interface.transferring) { - return; - } - - transmit_ntb_t *ntb = &transmit_ntb[ncm_interface.current_ntb]; - size_t ntb_length = ncm_interface.next_datagram_offset; - - // Fill in NTB header - ntb->nth.dwSignature = NTH16_SIGNATURE; - ntb->nth.wHeaderLength = sizeof(nth16_t); - ntb->nth.wSequence = ncm_interface.nth_sequence++; - ntb->nth.wBlockLength = ntb_length; - ntb->nth.wNdpIndex = sizeof(nth16_t); - - // Fill in NDP16 header and terminator - ntb->ndp.dwSignature = NDP16_SIGNATURE_NCM0; - ntb->ndp.wLength = sizeof(ndp16_t) + (ncm_interface.datagram_count + 1) * sizeof(ndp16_datagram_t); - ntb->ndp.wNextNdpIndex = 0; - ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramIndex = 0; - ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramLength = 0; - - // Kick off an endpoint transfer - usbd_edpt_xfer(0, ncm_interface.ep_in, ntb->data, ntb_length); - ncm_interface.transferring = true; - - // Swap to the other NTB and clear it out - ncm_interface.current_ntb = 1 - ncm_interface.current_ntb; - ncm_prepare_for_tx(); -} - -tu_static struct ecm_notify_struct ncm_notify_connected = -{ - .header = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_IN - }, - .bRequest = CDC_NOTIF_NETWORK_CONNECTION, - .wValue = 1 /* Connected */, - .wLength = 0, - }, -}; - -tu_static struct ecm_notify_struct ncm_notify_speed_change = -{ - .header = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_IN - }, - .bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE, - .wLength = 8, - }, - .downlink = 10000000, - .uplink = 10000000, -}; - -void tud_network_recv_renew(void) -{ - if (!ncm_interface.num_datagrams) - { - usbd_edpt_xfer(0, ncm_interface.ep_out, receive_ntb, sizeof(receive_ntb)); - return; - } - - const ndp16_t *ndp = ncm_interface.ndp; - const int i = ncm_interface.current_datagram_index; - ncm_interface.current_datagram_index++; - ncm_interface.num_datagrams--; - - tud_network_recv_cb(receive_ntb + ndp->datagram[i].wDatagramIndex, ndp->datagram[i].wDatagramLength); -} - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ - -void netd_init(void) -{ - tu_memclr(&ncm_interface, sizeof(ncm_interface)); - ncm_interface.ntb_in_size = CFG_TUD_NCM_IN_NTB_MAX_SIZE; - ncm_interface.max_datagrams_per_ntb = CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB; - ncm_prepare_for_tx(); -} - -void netd_reset(uint8_t rhport) -{ - (void) rhport; - - netd_init(); -} - -uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ - // confirm interface hasn't already been allocated - TU_ASSERT(0 == ncm_interface.ep_notif, 0); - - //------------- Management Interface -------------// - ncm_interface.itf_num = itf_desc->bInterfaceNumber; - - uint16_t drv_len = sizeof(tusb_desc_interface_t); - uint8_t const * p_desc = tu_desc_next( itf_desc ); - - // Communication Functional Descriptors - while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) - { - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - // notification endpoint (if any) - if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) - { - TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 ); - - ncm_interface.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; - - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - //------------- Data Interface -------------// - // - CDC-NCM data interface has 2 alternate settings - // - 0 : zero endpoints for inactive (default) - // - 1 : IN & OUT endpoints for transfer of NTBs - TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); - - do - { - tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc; - TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass, 0); - - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } while((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (drv_len <= max_len)); - - // Pair of endpoints - TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0); - - TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &ncm_interface.ep_out, &ncm_interface.ep_in) ); - - drv_len += 2*sizeof(tusb_desc_endpoint_t); - - return drv_len; -} - -static void ncm_report(void) -{ - uint8_t const rhport = 0; - if (ncm_interface.report_state == REPORT_SPEED) { - ncm_notify_speed_change.header.wIndex = ncm_interface.itf_num; - usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_speed_change, sizeof(ncm_notify_speed_change)); - ncm_interface.report_state = REPORT_CONNECTED; - ncm_interface.report_pending = true; - } else if (ncm_interface.report_state == REPORT_CONNECTED) { - ncm_notify_connected.header.wIndex = ncm_interface.itf_num; - usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_connected, sizeof(ncm_notify_connected)); - ncm_interface.report_state = REPORT_DONE; - ncm_interface.report_pending = true; - } -} - -TU_ATTR_WEAK void tud_network_link_state_cb(bool state) -{ - (void)state; -} - -// Handle class control request -// return false to stall control endpoint (e.g unsupported request) -bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - if ( stage != CONTROL_STAGE_SETUP ) return true; - - switch ( request->bmRequestType_bit.type ) - { - case TUSB_REQ_TYPE_STANDARD: - switch ( request->bRequest ) - { - case TUSB_REQ_GET_INTERFACE: - { - uint8_t const req_itfnum = (uint8_t) request->wIndex; - TU_VERIFY(ncm_interface.itf_num + 1 == req_itfnum); - - tud_control_xfer(rhport, request, &ncm_interface.itf_data_alt, 1); - } - break; - - case TUSB_REQ_SET_INTERFACE: - { - uint8_t const req_itfnum = (uint8_t) request->wIndex; - uint8_t const req_alt = (uint8_t) request->wValue; - - // Only valid for Data Interface with Alternate is either 0 or 1 - TU_VERIFY(ncm_interface.itf_num + 1 == req_itfnum && req_alt < 2); - - if (req_alt != ncm_interface.itf_data_alt) { - ncm_interface.itf_data_alt = req_alt; - - if (ncm_interface.itf_data_alt) { - if (!usbd_edpt_busy(rhport, ncm_interface.ep_out)) { - tud_network_recv_renew(); // prepare for incoming datagrams - } - if (!ncm_interface.report_pending) { - ncm_report(); - } - } - - tud_network_link_state_cb(ncm_interface.itf_data_alt); - } - - tud_control_status(rhport, request); - } - break; - - // unsupported request - default: return false; - } - break; - - case TUSB_REQ_TYPE_CLASS: - TU_VERIFY (ncm_interface.itf_num == request->wIndex); - - if (NCM_GET_NTB_PARAMETERS == request->bRequest) - { - tud_control_xfer(rhport, request, (void*)(uintptr_t) &ntb_parameters, sizeof(ntb_parameters)); - } - - break; - - // unsupported request - default: return false; - } - - return true; -} - -static void handle_incoming_datagram(uint32_t len) -{ - uint32_t size = len; - - if (len == 0) { - return; - } - - TU_ASSERT(size >= sizeof(nth16_t), ); - - const nth16_t *hdr = (const nth16_t *)receive_ntb; - TU_ASSERT(hdr->dwSignature == NTH16_SIGNATURE, ); - TU_ASSERT(hdr->wNdpIndex >= sizeof(nth16_t) && (hdr->wNdpIndex + sizeof(ndp16_t)) <= len, ); - - const ndp16_t *ndp = (const ndp16_t *)(receive_ntb + hdr->wNdpIndex); - TU_ASSERT(ndp->dwSignature == NDP16_SIGNATURE_NCM0 || ndp->dwSignature == NDP16_SIGNATURE_NCM1, ); - TU_ASSERT(hdr->wNdpIndex + ndp->wLength <= len, ); - - int num_datagrams = (ndp->wLength - 12) / 4; - ncm_interface.current_datagram_index = 0; - ncm_interface.num_datagrams = 0; - ncm_interface.ndp = ndp; - for (int i = 0; i < num_datagrams && ndp->datagram[i].wDatagramIndex && ndp->datagram[i].wDatagramLength; i++) - { - ncm_interface.num_datagrams++; - } - - tud_network_recv_renew(); -} - -bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void) rhport; - (void) result; - - /* new datagram receive_ntb */ - if (ep_addr == ncm_interface.ep_out ) - { - handle_incoming_datagram(xferred_bytes); - } - - /* data transmission finished */ - if (ep_addr == ncm_interface.ep_in ) - { - if (ncm_interface.transferring) { - ncm_interface.transferring = false; - } - - // If there are datagrams queued up that we tried to send while this NTB was being emitted, send them now - if (ncm_interface.datagram_count && ncm_interface.itf_data_alt == 1) { - ncm_start_tx(); - } - } - - if (ep_addr == ncm_interface.ep_notif ) - { - ncm_interface.report_pending = false; - ncm_report(); - } - - return true; -} - -// poll network driver for its ability to accept another packet to transmit -bool tud_network_can_xmit(uint16_t size) -{ - TU_VERIFY(ncm_interface.itf_data_alt == 1); - - if (ncm_interface.datagram_count >= ncm_interface.max_datagrams_per_ntb) { - TU_LOG2("NTB full [by count]\r\n"); - return false; - } - - size_t next_datagram_offset = ncm_interface.next_datagram_offset; - if (next_datagram_offset + size > ncm_interface.ntb_in_size) { - TU_LOG2("ntb full [by size]\r\n"); - return false; - } - - return true; -} - -void tud_network_xmit(void *ref, uint16_t arg) -{ - transmit_ntb_t *ntb = &transmit_ntb[ncm_interface.current_ntb]; - size_t next_datagram_offset = ncm_interface.next_datagram_offset; - - uint16_t size = tud_network_xmit_cb(ntb->data + next_datagram_offset, ref, arg); - - ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramIndex = ncm_interface.next_datagram_offset; - ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramLength = size; - - ncm_interface.datagram_count++; - next_datagram_offset += size; - - // round up so the next datagram is aligned correctly - next_datagram_offset += (CFG_TUD_NCM_ALIGNMENT - 1); - next_datagram_offset -= (next_datagram_offset % CFG_TUD_NCM_ALIGNMENT); - - ncm_interface.next_datagram_offset = next_datagram_offset; - - ncm_start_tx(); -} - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/net/net_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/net/net_device.h deleted file mode 100644 index 39991635..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/net/net_device.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Peter Lawrence - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_NET_DEVICE_H_ -#define _TUSB_NET_DEVICE_H_ - -#include "class/cdc/cdc.h" - -#if CFG_TUD_ECM_RNDIS && CFG_TUD_NCM -#error "Cannot enable both ECM_RNDIS and NCM network drivers" -#endif - -#include "ncm.h" - -/* declared here, NOT in usb_descriptors.c, so that the driver can intelligently ZLP as needed */ -#define CFG_TUD_NET_ENDPOINT_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) - -/* Maximum Transmission Unit (in bytes) of the network, including Ethernet header */ -#ifndef CFG_TUD_NET_MTU -#define CFG_TUD_NET_MTU 1514 -#endif - -#ifndef CFG_TUD_NCM_IN_NTB_MAX_SIZE -#define CFG_TUD_NCM_IN_NTB_MAX_SIZE 3200 -#endif - -#ifndef CFG_TUD_NCM_OUT_NTB_MAX_SIZE -#define CFG_TUD_NCM_OUT_NTB_MAX_SIZE 3200 -#endif - -#ifndef CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB -#define CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB 8 -#endif - -#ifndef CFG_TUD_NCM_ALIGNMENT -#define CFG_TUD_NCM_ALIGNMENT 4 -#endif - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Application API -//--------------------------------------------------------------------+ - -// indicate to network driver that client has finished with the packet provided to network_recv_cb() -void tud_network_recv_renew(void); - -// poll network driver for its ability to accept another packet to transmit -bool tud_network_can_xmit(uint16_t size); - -// if network_can_xmit() returns true, network_xmit() can be called once -void tud_network_xmit(void *ref, uint16_t arg); - -//--------------------------------------------------------------------+ -// Application Callbacks (WEAK is optional) -//--------------------------------------------------------------------+ - -// client must provide this: return false if the packet buffer was not accepted -bool tud_network_recv_cb(const uint8_t *src, uint16_t size); - -// client must provide this: copy from network stack packet pointer to dst -uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg); - -//------------- ECM/RNDIS -------------// - -// client must provide this: initialize any network state back to the beginning -void tud_network_init_cb(void); - -// client must provide this: 48-bit MAC address -// TODO removed later since it is not part of tinyusb stack -extern uint8_t tud_network_mac_address[6]; - -//------------- NCM -------------// - -// callback to client providing optional indication of internal state of network driver -void tud_network_link_state_cb(bool state); - -//--------------------------------------------------------------------+ -// INTERNAL USBD-CLASS DRIVER API -//--------------------------------------------------------------------+ -void netd_init (void); -void netd_reset (uint8_t rhport); -uint16_t netd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -bool netd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); -void netd_report (uint8_t *buf, uint16_t len); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_NET_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc.h b/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc.h deleted file mode 100644 index 090ab3c4..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc.h +++ /dev/null @@ -1,318 +0,0 @@ - -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 N Conrad - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_USBTMC_H__ -#define _TUSB_USBTMC_H__ - -#include "common/tusb_common.h" - - -/* Implements USBTMC Revision 1.0, April 14, 2003 - - String descriptors must have a "LANGID=0x409"/US English string. - Characters must be 0x20 (' ') to 0x7E ('~') ASCII, - But MUST not contain: "/:?\* - Also must not have leading or trailing space (' ') - Device descriptor must state USB version 0x0200 or greater - - If USB488DeviceCapabilites.D2 = 1 (SR1), then there must be a INT endpoint. -*/ - -#define USBTMC_VERSION 0x0100 -#define USBTMC_488_VERSION 0x0100 - -typedef enum { - USBTMC_MSGID_DEV_DEP_MSG_OUT = 1u, - USBTMC_MSGID_DEV_DEP_MSG_IN = 2u, - USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT = 126u, - USBTMC_MSGID_VENDOR_SPECIFIC_IN = 127u, - USBTMC_MSGID_USB488_TRIGGER = 128u, -} usbtmc_msgid_enum; - -/// \brief Message header (For BULK OUT and BULK IN); 4 bytes -typedef struct TU_ATTR_PACKED -{ - uint8_t MsgID ; ///< Message type ID (usbtmc_msgid_enum) - uint8_t bTag ; ///< Transfer ID 1<=bTag<=255 - uint8_t bTagInverse ; ///< Complement of the tag - uint8_t _reserved ; ///< Must be 0x00 -} usbtmc_msg_header_t; - -typedef struct TU_ATTR_PACKED -{ - usbtmc_msg_header_t header; - uint8_t data[8]; -} usbtmc_msg_generic_t; - -/* Uses on the bulk-out endpoint: */ -// Next 8 bytes are message-specific -typedef struct TU_ATTR_PACKED { - usbtmc_msg_header_t header ; ///< Header - uint32_t TransferSize ; ///< Transfer size; LSB first - struct TU_ATTR_PACKED - { - unsigned int EOM : 1 ; ///< EOM set on last byte - } bmTransferAttributes; - uint8_t _reserved[3]; -} usbtmc_msg_request_dev_dep_out; - -TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_dev_dep_out) == 12u, "struct wrong length"); - -// Next 8 bytes are message-specific -typedef struct TU_ATTR_PACKED -{ - usbtmc_msg_header_t header ; ///< Header - uint32_t TransferSize ; ///< Transfer size; LSB first - struct TU_ATTR_PACKED - { - unsigned int TermCharEnabled : 1 ; ///< "The Bulk-IN transfer must terminate on the specified TermChar."; CAPABILITIES must list TermChar - } bmTransferAttributes; - uint8_t TermChar; - uint8_t _reserved[2]; -} usbtmc_msg_request_dev_dep_in; - -TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_dev_dep_in) == 12u, "struct wrong length"); - -/* Bulk-in headers */ - -typedef struct TU_ATTR_PACKED -{ - usbtmc_msg_header_t header; - uint32_t TransferSize; - struct TU_ATTR_PACKED - { - uint8_t EOM: 1; ///< Last byte of transfer is the end of the message - uint8_t UsingTermChar: 1; ///< Support TermChar && Request.TermCharEnabled && last char in transfer is TermChar - } bmTransferAttributes; - uint8_t _reserved[3]; -} usbtmc_msg_dev_dep_msg_in_header_t; - -TU_VERIFY_STATIC(sizeof(usbtmc_msg_dev_dep_msg_in_header_t) == 12u, "struct wrong length"); - -/* Unsupported vendor things.... Are these ever used?*/ - -typedef struct TU_ATTR_PACKED -{ - usbtmc_msg_header_t header ; ///< Header - uint32_t TransferSize ; ///< Transfer size; LSB first - uint8_t _reserved[4]; -} usbtmc_msg_request_vendor_specific_out; - - -TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_vendor_specific_out) == 12u, "struct wrong length"); - -typedef struct TU_ATTR_PACKED -{ - usbtmc_msg_header_t header ; ///< Header - uint32_t TransferSize ; ///< Transfer size; LSB first - uint8_t _reserved[4]; -} usbtmc_msg_request_vendor_specific_in; - -TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_vendor_specific_in) == 12u, "struct wrong length"); - -// Control request type should use tusb_control_request_t - -/* -typedef struct TU_ATTR_PACKED { - struct { - unsigned int Recipient : 5 ; ///< EOM set on last byte - unsigned int Type : 2 ; ///< EOM set on last byte - unsigned int DirectionToHost : 1 ; ///< 0 is OUT, 1 is IN - } bmRequestType; - uint8_t bRequest ; ///< If bmRequestType.Type = Class, see usmtmc_request_type_enum - uint16_t wValue ; - uint16_t wIndex ; - uint16_t wLength ; // Number of bytes in data stage -} usbtmc_class_specific_control_req; - -*/ -// bulk-in protocol errors -enum { - USBTMC_BULK_IN_ERR_INCOMPLETE_HEADER = 1u, - USBTMC_BULK_IN_ERR_UNSUPPORTED = 2u, - USBTMC_BULK_IN_ERR_BAD_PARAMETER = 3u, - USBTMC_BULK_IN_ERR_DATA_TOO_SHORT = 4u, - USBTMC_BULK_IN_ERR_DATA_TOO_LONG = 5u, -}; -// built-in halt errors -enum { - USBTMC_BULK_IN_ERR = 1u, ///< receives a USBTMC command message that expects a response while a - /// Bulk-IN transfer is in progress -}; - -typedef enum { - USBTMC_bREQUEST_INITIATE_ABORT_BULK_OUT = 1u, - USBTMC_bREQUEST_CHECK_ABORT_BULK_OUT_STATUS = 2u, - USBTMC_bREQUEST_INITIATE_ABORT_BULK_IN = 3u, - USBTMC_bREQUEST_CHECK_ABORT_BULK_IN_STATUS = 4u, - USBTMC_bREQUEST_INITIATE_CLEAR = 5u, - USBTMC_bREQUEST_CHECK_CLEAR_STATUS = 6u, - USBTMC_bREQUEST_GET_CAPABILITIES = 7u, - - USBTMC_bREQUEST_INDICATOR_PULSE = 64u, // Optional - - /****** USBTMC 488 *************/ - USB488_bREQUEST_READ_STATUS_BYTE = 128u, - USB488_bREQUEST_REN_CONTROL = 160u, - USB488_bREQUEST_GO_TO_LOCAL = 161u, - USB488_bREQUEST_LOCAL_LOCKOUT = 162u, - -} usmtmc_request_type_enum; - -typedef enum { - USBTMC_STATUS_SUCCESS = 0x01, - USBTMC_STATUS_PENDING = 0x02, - USBTMC_STATUS_FAILED = 0x80, - USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS = 0x81, - USBTMC_STATUS_SPLIT_NOT_IN_PROGRESS = 0x82, - USBTMC_STATUS_SPLIT_IN_PROGRESS = 0x83, - - /****** USBTMC 488 *************/ - USB488_STATUS_INTERRUPT_IN_BUSY = 0x20 -} usbtmc_status_enum; - -/************************************************************ - * Control Responses - */ - -typedef struct TU_ATTR_PACKED { - uint8_t USBTMC_status; ///< usbtmc_status_enum - uint8_t _reserved; - uint16_t bcdUSBTMC; ///< USBTMC_VERSION - - struct TU_ATTR_PACKED - { - unsigned int listenOnly :1; - unsigned int talkOnly :1; - unsigned int supportsIndicatorPulse :1; - } bmIntfcCapabilities; - struct TU_ATTR_PACKED - { - unsigned int canEndBulkInOnTermChar :1; - } bmDevCapabilities; - uint8_t _reserved2[6]; - uint8_t _reserved3[12]; -} usbtmc_response_capabilities_t; - -TU_VERIFY_STATIC(sizeof(usbtmc_response_capabilities_t) == 0x18, "struct wrong length"); - -typedef struct TU_ATTR_PACKED -{ - uint8_t USBTMC_status; - struct TU_ATTR_PACKED - { - unsigned int BulkInFifoBytes :1; - } bmClear; -} usbtmc_get_clear_status_rsp_t; - -TU_VERIFY_STATIC(sizeof(usbtmc_get_clear_status_rsp_t) == 2u, "struct wrong length"); - -// Used for both abort bulk IN and bulk OUT -typedef struct TU_ATTR_PACKED -{ - uint8_t USBTMC_status; - uint8_t bTag; -} usbtmc_initiate_abort_rsp_t; - -TU_VERIFY_STATIC(sizeof(usbtmc_get_clear_status_rsp_t) == 2u, "struct wrong length"); - -// Used for both check_abort_bulk_in_status and check_abort_bulk_out_status -typedef struct TU_ATTR_PACKED -{ - uint8_t USBTMC_status; - struct TU_ATTR_PACKED - { - unsigned int BulkInFifoBytes : 1; ///< Has queued data or a short packet that is queued - } bmAbortBulkIn; - uint8_t _reserved[2]; ///< Must be zero - uint32_t NBYTES_RXD_TXD; -} usbtmc_check_abort_bulk_rsp_t; - -TU_VERIFY_STATIC(sizeof(usbtmc_check_abort_bulk_rsp_t) == 8u, "struct wrong length"); - -typedef struct TU_ATTR_PACKED -{ - uint8_t USBTMC_status; ///< usbtmc_status_enum - uint8_t _reserved; - uint16_t bcdUSBTMC; ///< USBTMC_VERSION - - struct TU_ATTR_PACKED - { - uint8_t listenOnly :1; - uint8_t talkOnly :1; - uint8_t supportsIndicatorPulse :1; - } bmIntfcCapabilities; - - struct TU_ATTR_PACKED - { - uint8_t canEndBulkInOnTermChar :1; - } bmDevCapabilities; - - uint8_t _reserved2[6]; - uint16_t bcdUSB488; - - struct TU_ATTR_PACKED - { - uint8_t supportsTrigger :1; - uint8_t supportsREN_GTL_LLO :1; - uint8_t is488_2 :1; - } bmIntfcCapabilities488; - - struct TU_ATTR_PACKED - { - uint8_t DT1 :1; - uint8_t RL1 :1; - uint8_t SR1 :1; - uint8_t SCPI :1; - } bmDevCapabilities488; - uint8_t _reserved3[8]; -} usbtmc_response_capabilities_488_t; - -TU_VERIFY_STATIC(sizeof(usbtmc_response_capabilities_488_t) == 0x18, "struct wrong length"); - -typedef struct TU_ATTR_PACKED -{ - uint8_t USBTMC_status; - uint8_t bTag; - uint8_t statusByte; -} usbtmc_read_stb_rsp_488_t; - -TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_rsp_488_t) == 3u, "struct wrong length"); - -typedef struct TU_ATTR_PACKED -{ - struct TU_ATTR_PACKED - { - unsigned int bTag : 7; - unsigned int one : 1; - } bNotify1; - uint8_t StatusByte; -} usbtmc_read_stb_interrupt_488_t; - -TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_interrupt_488_t) == 2u, "struct wrong length"); - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c deleted file mode 100644 index 4e320a77..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.c +++ /dev/null @@ -1,890 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Nathan Conrad - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -/* - * This library is not fully reentrant, though it is reentrant from the view - * of either the application layer or the USB stack. Due to its locking, - * it is not safe to call its functions from interrupts. - * - * The one exception is that its functions may not be called from the application - * until the USB stack is initialized. This should not be a problem since the - * device shouldn't be sending messages until it receives a request from the - * host. - */ - - -/* - * In the case of single-CPU "no OS", this task is never preempted other than by - * interrupts, and the USBTMC code isn't called by interrupts, so all is OK. For "no OS", - * the mutex structure's main effect is to disable the USB interrupts. - * With an OS, this class driver uses the OSAL to perform locking. The code uses a single lock - * and does not call outside of this class with a lock held, so deadlocks won't happen. - */ - -//Limitations: -// "vendor-specific" commands are not handled. -// Dealing with "termchar" must be handled by the application layer, -// though additional error checking is does in this module. -// talkOnly and listenOnly are NOT supported. They're not permitted -// in USB488, anyway. - -/* Supported: - * - * Notification pulse - * Trigger - * Read status byte (both by interrupt endpoint and control message) - * - */ - - -// TODO: -// USBTMC 3.2.2 error conditions not strictly followed -// No local lock-out, REN, or GTL. -// Clear message available status byte at the correct time? (488 4.3.1.3) -// Ability to defer status byte transmission -// Transmission of status byte in response to USB488 SRQ condition - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_USBTMC) - -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "usbtmc_device.h" - -#ifdef xDEBUG -#include "uart_util.h" -tu_static char logMsg[150]; -#endif - -// Buffer size must be an exact multiple of the max packet size for both -// bulk (up to 64 bytes for FS, 512 bytes for HS). In addation, this driver -// imposes a minimum buffer size of 32 bytes. -#define USBTMCD_BUFFER_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) - -/* - * The state machine does not allow simultaneous reading and writing. This is - * consistent with USBTMC. - */ - -typedef enum -{ - STATE_CLOSED, // Endpoints have not yet been opened since USB reset - STATE_NAK, // Bulk-out endpoint is in NAK state. - STATE_IDLE, // Bulk-out endpoint is waiting for CMD. - STATE_RCV, // Bulk-out is receiving DEV_DEP message - STATE_TX_REQUESTED, - STATE_TX_INITIATED, - STATE_TX_SHORTED, - STATE_CLEARING, - STATE_ABORTING_BULK_IN, - STATE_ABORTING_BULK_IN_SHORTED, // aborting, and short packet has been queued for transmission - STATE_ABORTING_BULK_IN_ABORTED, // aborting, and short packet has been transmitted - STATE_ABORTING_BULK_OUT, - STATE_NUM_STATES -} usbtmcd_state_enum; - -#if (CFG_TUD_USBTMC_ENABLE_488) - typedef usbtmc_response_capabilities_488_t usbtmc_capabilities_specific_t; -#else - typedef usbtmc_response_capabilities_t usbtmc_capabilities_specific_t; -#endif - - -typedef struct -{ - volatile usbtmcd_state_enum state; - - uint8_t itf_id; - uint8_t rhport; - uint8_t ep_bulk_in; - uint8_t ep_bulk_out; - uint8_t ep_int_in; - // IN buffer is only used for first packet, not the remainder - // in order to deal with prepending header - CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_in_buf[USBTMCD_BUFFER_SIZE]; - uint32_t ep_bulk_in_wMaxPacketSize; - // OUT buffer receives one packet at a time - CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_out_buf[USBTMCD_BUFFER_SIZE]; - uint32_t ep_bulk_out_wMaxPacketSize; - - uint32_t transfer_size_remaining; // also used for requested length for bulk IN. - uint32_t transfer_size_sent; // To keep track of data bytes that have been queued in FIFO (not header bytes) - - uint8_t lastBulkOutTag; // used for aborts (mostly) - uint8_t lastBulkInTag; // used for aborts (mostly) - - uint8_t const * devInBuffer; // pointer to application-layer used for transmissions - - usbtmc_capabilities_specific_t const * capabilities; -} usbtmc_interface_state_t; - -CFG_TUSB_MEM_SECTION tu_static usbtmc_interface_state_t usbtmc_state = -{ - .itf_id = 0xFF, -}; - -// We need all headers to fit in a single packet in this implementation, 32 bytes will fit all standard USBTMC headers -TU_VERIFY_STATIC(USBTMCD_BUFFER_SIZE >= 32u,"USBTMC dev buffer size too small"); - -static bool handle_devMsgOutStart(uint8_t rhport, void *data, size_t len); -static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t packetLen); - -#ifndef NDEBUG -tu_static uint8_t termChar; -#endif - -tu_static uint8_t termCharRequested = false; - -#if OSAL_MUTEX_REQUIRED -static OSAL_MUTEX_DEF(usbtmcLockBuffer); -#endif -osal_mutex_t usbtmcLock; - -// Our own private lock, mostly for the state variable. -#define criticalEnter() do { (void) osal_mutex_lock(usbtmcLock,OSAL_TIMEOUT_WAIT_FOREVER); } while (0) -#define criticalLeave() do { (void) osal_mutex_unlock(usbtmcLock); } while (0) - -bool atomicChangeState(usbtmcd_state_enum expectedState, usbtmcd_state_enum newState) -{ - bool ret = true; - criticalEnter(); - usbtmcd_state_enum oldState = usbtmc_state.state; - if (oldState == expectedState) - { - usbtmc_state.state = newState; - } - else - { - ret = false; - } - criticalLeave(); - return ret; -} - -// called from app -// We keep a reference to the buffer, so it MUST not change until the app is -// notified that the transfer is complete. -// length of data is specified in the hdr. - -// We can't just send the whole thing at once because we need to concatanate the -// header with the data. -bool tud_usbtmc_transmit_dev_msg_data( - const void * data, size_t len, - bool endOfMessage, - bool usingTermChar) -{ - const unsigned int txBufLen = sizeof(usbtmc_state.ep_bulk_in_buf); - -#ifndef NDEBUG - TU_ASSERT(len > 0u); - TU_ASSERT(len <= usbtmc_state.transfer_size_remaining); - TU_ASSERT(usbtmc_state.transfer_size_sent == 0u); - if(usingTermChar) - { - TU_ASSERT(usbtmc_state.capabilities->bmDevCapabilities.canEndBulkInOnTermChar); - TU_ASSERT(termCharRequested); - TU_ASSERT(((uint8_t const*)data)[len-1u] == termChar); - } -#endif - - TU_VERIFY(usbtmc_state.state == STATE_TX_REQUESTED); - usbtmc_msg_dev_dep_msg_in_header_t *hdr = (usbtmc_msg_dev_dep_msg_in_header_t*)usbtmc_state.ep_bulk_in_buf; - tu_varclr(hdr); - hdr->header.MsgID = USBTMC_MSGID_DEV_DEP_MSG_IN; - hdr->header.bTag = usbtmc_state.lastBulkInTag; - hdr->header.bTagInverse = (uint8_t)~(usbtmc_state.lastBulkInTag); - hdr->TransferSize = len; - hdr->bmTransferAttributes.EOM = endOfMessage; - hdr->bmTransferAttributes.UsingTermChar = usingTermChar; - - // Copy in the header - const size_t headerLen = sizeof(*hdr); - const size_t dataLen = ((headerLen + hdr->TransferSize) <= txBufLen) ? - len : (txBufLen - headerLen); - const size_t packetLen = headerLen + dataLen; - - memcpy((uint8_t*)(usbtmc_state.ep_bulk_in_buf) + headerLen, data, dataLen); - usbtmc_state.transfer_size_remaining = len - dataLen; - usbtmc_state.transfer_size_sent = dataLen; - usbtmc_state.devInBuffer = (uint8_t const*) data + (dataLen); - - bool stateChanged = - atomicChangeState(STATE_TX_REQUESTED, (packetLen >= txBufLen) ? STATE_TX_INITIATED : STATE_TX_SHORTED); - TU_VERIFY(stateChanged); - TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf, (uint16_t)packetLen)); - return true; -} - -void usbtmcd_init_cb(void) -{ - usbtmc_state.capabilities = tud_usbtmc_get_capabilities_cb(); -#ifndef NDEBUG -# if CFG_TUD_USBTMC_ENABLE_488 - if (usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger) { - TU_ASSERT(&tud_usbtmc_msg_trigger_cb != NULL,); - } - // Per USB488 spec: table 8 - TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.listenOnly,); - TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.talkOnly,); -# endif - if (usbtmc_state.capabilities->bmIntfcCapabilities.supportsIndicatorPulse) { - TU_ASSERT(&tud_usbtmc_indicator_pulse_cb != NULL,); - } -#endif - - usbtmcLock = osal_mutex_create(&usbtmcLockBuffer); -} - -uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ - (void)rhport; - - uint16_t drv_len; - uint8_t const * p_desc; - uint8_t found_endpoints = 0; - - TU_VERIFY(itf_desc->bInterfaceClass == TUD_USBTMC_APP_CLASS , 0); - TU_VERIFY(itf_desc->bInterfaceSubClass == TUD_USBTMC_APP_SUBCLASS, 0); - -#ifndef NDEBUG - // Only 2 or 3 endpoints are allowed for USBTMC. - TU_ASSERT((itf_desc->bNumEndpoints == 2) || (itf_desc->bNumEndpoints ==3), 0); -#endif - - TU_ASSERT(usbtmc_state.state == STATE_CLOSED, 0); - - // Interface - drv_len = 0u; - p_desc = (uint8_t const *) itf_desc; - - usbtmc_state.itf_id = itf_desc->bInterfaceNumber; - usbtmc_state.rhport = rhport; - - while (found_endpoints < itf_desc->bNumEndpoints && drv_len <= max_len) - { - if ( TUSB_DESC_ENDPOINT == p_desc[DESC_OFFSET_TYPE]) - { - tusb_desc_endpoint_t const *ep_desc = (tusb_desc_endpoint_t const *)p_desc; - switch(ep_desc->bmAttributes.xfer) { - case TUSB_XFER_BULK: - // Ensure buffer is an exact multiple of the maxPacketSize - TU_ASSERT((USBTMCD_BUFFER_SIZE % tu_edpt_packet_size(ep_desc)) == 0, 0); - if (tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN) - { - usbtmc_state.ep_bulk_in = ep_desc->bEndpointAddress; - usbtmc_state.ep_bulk_in_wMaxPacketSize = tu_edpt_packet_size(ep_desc); - } else { - usbtmc_state.ep_bulk_out = ep_desc->bEndpointAddress; - usbtmc_state.ep_bulk_out_wMaxPacketSize = tu_edpt_packet_size(ep_desc); - } - - break; - case TUSB_XFER_INTERRUPT: -#ifndef NDEBUG - TU_ASSERT(tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN, 0); - TU_ASSERT(usbtmc_state.ep_int_in == 0, 0); -#endif - usbtmc_state.ep_int_in = ep_desc->bEndpointAddress; - break; - default: - TU_ASSERT(false, 0); - } - TU_ASSERT( usbd_edpt_open(rhport, ep_desc), 0); - found_endpoints++; - } - - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - // bulk endpoints are required, but interrupt IN is optional -#ifndef NDEBUG - TU_ASSERT(usbtmc_state.ep_bulk_in != 0, 0); - TU_ASSERT(usbtmc_state.ep_bulk_out != 0, 0); - if (itf_desc->bNumEndpoints == 2) - { - TU_ASSERT(usbtmc_state.ep_int_in == 0, 0); - } - else if (itf_desc->bNumEndpoints == 3) - { - TU_ASSERT(usbtmc_state.ep_int_in != 0, 0); - } -#if (CFG_TUD_USBTMC_ENABLE_488) - if(usbtmc_state.capabilities->bmIntfcCapabilities488.is488_2 || - usbtmc_state.capabilities->bmDevCapabilities488.SR1) - { - TU_ASSERT(usbtmc_state.ep_int_in != 0, 0); - } -#endif -#endif - atomicChangeState(STATE_CLOSED, STATE_NAK); - tud_usbtmc_open_cb(itf_desc->iInterface); - - return drv_len; -} -// Tell USBTMC class to set its bulk-in EP to ACK so that it can -// receive USBTMC commands. -// Returns false if it was already in an ACK state or is busy -// processing a command (such as a clear). Returns true if it was -// in the NAK state and successfully transitioned to the ACK wait -// state. -bool tud_usbtmc_start_bus_read() -{ - usbtmcd_state_enum oldState = usbtmc_state.state; - switch(oldState) - { - // These may transition to IDLE - case STATE_NAK: - case STATE_ABORTING_BULK_IN_ABORTED: - TU_VERIFY(atomicChangeState(oldState, STATE_IDLE)); - break; - // When receiving, let it remain receiving - case STATE_RCV: - break; - default: - return false; - } - TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, (uint16_t)usbtmc_state.ep_bulk_out_wMaxPacketSize)); - return true; -} - -void usbtmcd_reset_cb(uint8_t rhport) -{ - (void)rhport; - usbtmc_capabilities_specific_t const * capabilities = tud_usbtmc_get_capabilities_cb(); - - criticalEnter(); - tu_varclr(&usbtmc_state); - usbtmc_state.capabilities = capabilities; - usbtmc_state.itf_id = 0xFFu; - criticalLeave(); -} - -static bool handle_devMsgOutStart(uint8_t rhport, void *data, size_t len) -{ - (void)rhport; - // return true upon failure, as we can assume error is being handled elsewhere. - TU_VERIFY(atomicChangeState(STATE_IDLE, STATE_RCV), true); - usbtmc_state.transfer_size_sent = 0u; - - // must be a header, should have been confirmed before calling here. - usbtmc_msg_request_dev_dep_out *msg = (usbtmc_msg_request_dev_dep_out*)data; - usbtmc_state.transfer_size_remaining = msg->TransferSize; - TU_VERIFY(tud_usbtmc_msgBulkOut_start_cb(msg)); - - TU_VERIFY(handle_devMsgOut(rhport, (uint8_t*)data + sizeof(*msg), len - sizeof(*msg), len)); - usbtmc_state.lastBulkOutTag = msg->header.bTag; - return true; -} - -static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t packetLen) -{ - (void)rhport; - // return true upon failure, as we can assume error is being handled elsewhere. - TU_VERIFY(usbtmc_state.state == STATE_RCV,true); - - bool shortPacket = (packetLen < usbtmc_state.ep_bulk_out_wMaxPacketSize); - - // Packet is to be considered complete when we get enough data or at a short packet. - bool atEnd = false; - if(len >= usbtmc_state.transfer_size_remaining || shortPacket) - { - atEnd = true; - TU_VERIFY(atomicChangeState(STATE_RCV, STATE_NAK)); - } - - len = tu_min32(len, usbtmc_state.transfer_size_remaining); - - usbtmc_state.transfer_size_remaining -= len; - usbtmc_state.transfer_size_sent += len; - - // App may (should?) call the wait_for_bus() command at this point - if(!tud_usbtmc_msg_data_cb(data, len, atEnd)) - { - // TODO: Go to an error state upon failure other than just stalling the EP? - return false; - } - - - return true; -} - -static bool handle_devMsgIn(void *data, size_t len) -{ - TU_VERIFY(len == sizeof(usbtmc_msg_request_dev_dep_in)); - usbtmc_msg_request_dev_dep_in *msg = (usbtmc_msg_request_dev_dep_in*)data; - bool stateChanged = atomicChangeState(STATE_IDLE, STATE_TX_REQUESTED); - TU_VERIFY(stateChanged); - usbtmc_state.lastBulkInTag = msg->header.bTag; - usbtmc_state.transfer_size_remaining = msg->TransferSize; - usbtmc_state.transfer_size_sent = 0u; - - termCharRequested = msg->bmTransferAttributes.TermCharEnabled; - -#ifndef NDEBUG - termChar = msg->TermChar; -#endif - - if(termCharRequested) - TU_VERIFY(usbtmc_state.capabilities->bmDevCapabilities.canEndBulkInOnTermChar); - - TU_VERIFY(tud_usbtmc_msgBulkIn_request_cb(msg)); - return true; -} - -bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - TU_VERIFY(result == XFER_RESULT_SUCCESS); - //uart_tx_str_sync("TMC XFER CB\r\n"); - if(usbtmc_state.state == STATE_CLEARING) { - return true; /* I think we can ignore everything here */ - } - - if(ep_addr == usbtmc_state.ep_bulk_out) - { - usbtmc_msg_generic_t *msg = NULL; - - switch(usbtmc_state.state) - { - case STATE_IDLE: - { - TU_VERIFY(xferred_bytes >= sizeof(usbtmc_msg_generic_t)); - msg = (usbtmc_msg_generic_t*)(usbtmc_state.ep_bulk_out_buf); - uint8_t invInvTag = (uint8_t)~(msg->header.bTagInverse); - TU_VERIFY(msg->header.bTag == invInvTag); - TU_VERIFY(msg->header.bTag != 0x00); - - switch(msg->header.MsgID) { - case USBTMC_MSGID_DEV_DEP_MSG_OUT: - if(!handle_devMsgOutStart(rhport, msg, xferred_bytes)) - { - usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); - return false; - } - break; - - case USBTMC_MSGID_DEV_DEP_MSG_IN: - TU_VERIFY(handle_devMsgIn(msg, xferred_bytes)); - break; - -#if (CFG_TUD_USBTMC_ENABLE_488) - case USBTMC_MSGID_USB488_TRIGGER: - // Spec says we halt the EP if we didn't declare we support it. - TU_VERIFY(usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger); - TU_VERIFY(tud_usbtmc_msg_trigger_cb(msg)); - - break; -#endif - case USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT: - case USBTMC_MSGID_VENDOR_SPECIFIC_IN: - default: - usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); - return false; - } - return true; - } - case STATE_RCV: - if(!handle_devMsgOut(rhport, usbtmc_state.ep_bulk_out_buf, xferred_bytes, xferred_bytes)) - { - usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); - return false; - } - return true; - - case STATE_ABORTING_BULK_OUT: - // Should be stalled by now, shouldn't have received a packet. - return false; - - case STATE_TX_REQUESTED: - case STATE_TX_INITIATED: - case STATE_ABORTING_BULK_IN: - case STATE_ABORTING_BULK_IN_SHORTED: - case STATE_ABORTING_BULK_IN_ABORTED: - default: - return false; - } - } - else if(ep_addr == usbtmc_state.ep_bulk_in) - { - switch(usbtmc_state.state) { - case STATE_TX_SHORTED: - TU_VERIFY(atomicChangeState(STATE_TX_SHORTED, STATE_NAK)); - TU_VERIFY(tud_usbtmc_msgBulkIn_complete_cb()); - break; - - case STATE_TX_INITIATED: - if(usbtmc_state.transfer_size_remaining >= sizeof(usbtmc_state.ep_bulk_in_buf)) - { - // FIXME! This removes const below! - TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, - (void*)(uintptr_t) usbtmc_state.devInBuffer, sizeof(usbtmc_state.ep_bulk_in_buf))); - usbtmc_state.devInBuffer += sizeof(usbtmc_state.ep_bulk_in_buf); - usbtmc_state.transfer_size_remaining -= sizeof(usbtmc_state.ep_bulk_in_buf); - usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.ep_bulk_in_buf); - } - else // last packet - { - size_t packetLen = usbtmc_state.transfer_size_remaining; - memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, usbtmc_state.transfer_size_remaining); - usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.transfer_size_remaining); - usbtmc_state.transfer_size_remaining = 0; - usbtmc_state.devInBuffer = NULL; - TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf, (uint16_t)packetLen) ); - if(((packetLen % usbtmc_state.ep_bulk_in_wMaxPacketSize) != 0) || (packetLen == 0 )) - { - usbtmc_state.state = STATE_TX_SHORTED; - } - } - return true; - - case STATE_ABORTING_BULK_IN: - // need to send short packet (ZLP?) - TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,(uint16_t)0u)); - usbtmc_state.state = STATE_ABORTING_BULK_IN_SHORTED; - return true; - - case STATE_ABORTING_BULK_IN_SHORTED: - /* Done. :)*/ - usbtmc_state.state = STATE_ABORTING_BULK_IN_ABORTED; - return true; - - default: - TU_ASSERT(false); - } - } - else if (ep_addr == usbtmc_state.ep_int_in) { - // Good? - return true; - } - return false; -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - // nothing to do with DATA and ACK stage - if ( stage != CONTROL_STAGE_SETUP ) return true; - - uint8_t tmcStatusCode = USBTMC_STATUS_FAILED; -#if (CFG_TUD_USBTMC_ENABLE_488) - uint8_t bTag; -#endif - - if((request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) && - (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_ENDPOINT) && - (request->bRequest == TUSB_REQ_CLEAR_FEATURE) && - (request->wValue == TUSB_REQ_FEATURE_EDPT_HALT)) - { - uint32_t ep_addr = (request->wIndex); - - // At this point, a transfer MAY be in progress. Based on USB spec, when clearing bulk EP HALT, - // the EP transfer buffer needs to be cleared and DTOG needs to be reset, even if - // the EP is not halted. The only USBD API interface to do this is to stall and then un-stall the EP. - if(ep_addr == usbtmc_state.ep_bulk_out) - { - criticalEnter(); - usbd_edpt_stall(rhport, (uint8_t)ep_addr); - usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr); - usbtmc_state.state = STATE_NAK; // USBD core has placed EP in NAK state for us - criticalLeave(); - tud_usbtmc_bulkOut_clearFeature_cb(); - } - else if (ep_addr == usbtmc_state.ep_bulk_in) - { - usbd_edpt_stall(rhport, (uint8_t)ep_addr); - usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr); - tud_usbtmc_bulkIn_clearFeature_cb(); - } - else if ((usbtmc_state.ep_int_in != 0) && (ep_addr == usbtmc_state.ep_int_in)) - { - // Clearing interrupt in EP - usbd_edpt_stall(rhport, (uint8_t)ep_addr); - usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr); - } - else - { - return false; - } - return true; - } - - // Otherwise, we only handle class requests. - if(request->bmRequestType_bit.type != TUSB_REQ_TYPE_CLASS) - { - return false; - } - - // Verification that we own the interface is unneeded since it's been routed to us specifically. - - switch(request->bRequest) - { - // USBTMC required requests - case USBTMC_bREQUEST_INITIATE_ABORT_BULK_OUT: - { - usbtmc_initiate_abort_rsp_t rsp = { - .bTag = usbtmc_state.lastBulkOutTag, - }; - TU_VERIFY(request->bmRequestType == 0xA2); // in,class,interface - TU_VERIFY(request->wLength == sizeof(rsp)); - TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_out); - - // wValue is the requested bTag to abort - if(usbtmc_state.state != STATE_RCV) - { - rsp.USBTMC_status = USBTMC_STATUS_FAILED; - } - else if(usbtmc_state.lastBulkOutTag == (request->wValue & 0x7Fu)) - { - rsp.USBTMC_status = USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS; - } - else - { - rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; - // Check if we've queued a short packet - criticalEnter(); - usbtmc_state.state = STATE_ABORTING_BULK_OUT; - criticalLeave(); - TU_VERIFY(tud_usbtmc_initiate_abort_bulk_out_cb(&(rsp.USBTMC_status))); - usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); - } - TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); - return true; - } - - case USBTMC_bREQUEST_CHECK_ABORT_BULK_OUT_STATUS: - { - usbtmc_check_abort_bulk_rsp_t rsp = { - .USBTMC_status = USBTMC_STATUS_SUCCESS, - .NBYTES_RXD_TXD = usbtmc_state.transfer_size_sent - }; - TU_VERIFY(request->bmRequestType == 0xA2); // in,class,EP - TU_VERIFY(request->wLength == sizeof(rsp)); - TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_out); - TU_VERIFY(tud_usbtmc_check_abort_bulk_out_cb(&rsp)); - TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); - return true; - } - - case USBTMC_bREQUEST_INITIATE_ABORT_BULK_IN: - { - usbtmc_initiate_abort_rsp_t rsp = { - .bTag = usbtmc_state.lastBulkInTag, - }; - TU_VERIFY(request->bmRequestType == 0xA2); // in,class,interface - TU_VERIFY(request->wLength == sizeof(rsp)); - TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_in); - // wValue is the requested bTag to abort - if((usbtmc_state.state == STATE_TX_REQUESTED || usbtmc_state.state == STATE_TX_INITIATED) && - usbtmc_state.lastBulkInTag == (request->wValue & 0x7Fu)) - { - rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; - usbtmc_state.transfer_size_remaining = 0u; - // Check if we've queued a short packet - criticalEnter(); - usbtmc_state.state = ((usbtmc_state.transfer_size_sent % usbtmc_state.ep_bulk_in_wMaxPacketSize) == 0) ? - STATE_ABORTING_BULK_IN : STATE_ABORTING_BULK_IN_SHORTED; - criticalLeave(); - if(usbtmc_state.transfer_size_sent == 0) - { - // Send short packet, nothing is in the buffer yet - TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,(uint16_t)0u)); - usbtmc_state.state = STATE_ABORTING_BULK_IN_SHORTED; - } - TU_VERIFY(tud_usbtmc_initiate_abort_bulk_in_cb(&(rsp.USBTMC_status))); - } - else if((usbtmc_state.state == STATE_TX_REQUESTED || usbtmc_state.state == STATE_TX_INITIATED)) - { // FIXME: Unsure how to check if the OUT endpoint fifo is non-empty.... - rsp.USBTMC_status = USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS; - } - else - { - rsp.USBTMC_status = USBTMC_STATUS_FAILED; - } - TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); - return true; - } - - case USBTMC_bREQUEST_CHECK_ABORT_BULK_IN_STATUS: - { - TU_VERIFY(request->bmRequestType == 0xA2); // in,class,EP - TU_VERIFY(request->wLength == 8u); - - usbtmc_check_abort_bulk_rsp_t rsp = - { - .USBTMC_status = USBTMC_STATUS_FAILED, - .bmAbortBulkIn = - { - .BulkInFifoBytes = (usbtmc_state.state != STATE_ABORTING_BULK_IN_ABORTED) - }, - .NBYTES_RXD_TXD = usbtmc_state.transfer_size_sent, - }; - TU_VERIFY(tud_usbtmc_check_abort_bulk_in_cb(&rsp)); - criticalEnter(); - switch(usbtmc_state.state) - { - case STATE_ABORTING_BULK_IN_ABORTED: - rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; - usbtmc_state.state = STATE_IDLE; - break; - case STATE_ABORTING_BULK_IN: - case STATE_ABORTING_BULK_OUT: - rsp.USBTMC_status = USBTMC_STATUS_PENDING; - break; - default: - break; - } - criticalLeave(); - TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); - - return true; - } - - case USBTMC_bREQUEST_INITIATE_CLEAR: - { - TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface - TU_VERIFY(request->wLength == sizeof(tmcStatusCode)); - // After receiving an INITIATE_CLEAR request, the device must Halt the Bulk-OUT endpoint, queue the - // control endpoint response shown in Table 31, and clear all input buffers and output buffers. - usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); - usbtmc_state.transfer_size_remaining = 0; - criticalEnter(); - usbtmc_state.state = STATE_CLEARING; - criticalLeave(); - TU_VERIFY(tud_usbtmc_initiate_clear_cb(&tmcStatusCode)); - TU_VERIFY(tud_control_xfer(rhport, request, (void*)&tmcStatusCode,sizeof(tmcStatusCode))); - return true; - } - - case USBTMC_bREQUEST_CHECK_CLEAR_STATUS: - { - TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface - usbtmc_get_clear_status_rsp_t clearStatusRsp = {0}; - TU_VERIFY(request->wLength == sizeof(clearStatusRsp)); - - if(usbd_edpt_busy(rhport, usbtmc_state.ep_bulk_in)) - { - // Stuff stuck in TX buffer? - clearStatusRsp.bmClear.BulkInFifoBytes = 1; - clearStatusRsp.USBTMC_status = USBTMC_STATUS_PENDING; - } - else - { - // Let app check if it's clear - TU_VERIFY(tud_usbtmc_check_clear_cb(&clearStatusRsp)); - } - if(clearStatusRsp.USBTMC_status == USBTMC_STATUS_SUCCESS) - { - criticalEnter(); - usbtmc_state.state = STATE_IDLE; - criticalLeave(); - } - TU_VERIFY(tud_control_xfer(rhport, request, (void*)&clearStatusRsp,sizeof(clearStatusRsp))); - return true; - } - - case USBTMC_bREQUEST_GET_CAPABILITIES: - { - TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface - TU_VERIFY(request->wLength == sizeof(*(usbtmc_state.capabilities))); - TU_VERIFY(tud_control_xfer(rhport, request, (void*)(uintptr_t) usbtmc_state.capabilities, sizeof(*usbtmc_state.capabilities))); - return true; - } - // USBTMC Optional Requests - - case USBTMC_bREQUEST_INDICATOR_PULSE: // Optional - { - TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface - TU_VERIFY(request->wLength == sizeof(tmcStatusCode)); - TU_VERIFY(usbtmc_state.capabilities->bmIntfcCapabilities.supportsIndicatorPulse); - TU_VERIFY(tud_usbtmc_indicator_pulse_cb(request, &tmcStatusCode)); - TU_VERIFY(tud_control_xfer(rhport, request, (void*)&tmcStatusCode, sizeof(tmcStatusCode))); - return true; - } -#if (CFG_TUD_USBTMC_ENABLE_488) - - // USB488 required requests - case USB488_bREQUEST_READ_STATUS_BYTE: - { - usbtmc_read_stb_rsp_488_t rsp; - TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface - TU_VERIFY(request->wLength == sizeof(rsp)); // in,class,interface - - bTag = request->wValue & 0x7F; - TU_VERIFY(request->bmRequestType == 0xA1); - TU_VERIFY((request->wValue & (~0x7F)) == 0u); // Other bits are required to be zero (USB488v1.0 Table 11) - TU_VERIFY(bTag >= 0x02 && bTag <= 127); - TU_VERIFY(request->wIndex == usbtmc_state.itf_id); - TU_VERIFY(request->wLength == 0x0003); - rsp.bTag = (uint8_t)bTag; - if(usbtmc_state.ep_int_in != 0) - { - rsp.statusByte = 0x00; // Use interrupt endpoint, instead. Must be 0x00 (USB488v1.0 4.3.1.2) - if(usbd_edpt_busy(rhport, usbtmc_state.ep_int_in)) - { - rsp.USBTMC_status = USB488_STATUS_INTERRUPT_IN_BUSY; - } - else - { - rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; - usbtmc_read_stb_interrupt_488_t intMsg = - { - .bNotify1 = { - .one = 1, - .bTag = bTag & 0x7Fu, - }, - .StatusByte = tud_usbtmc_get_stb_cb(&(rsp.USBTMC_status)) - }; - // Must be queued before control request response sent (USB488v1.0 4.3.1.2) - usbd_edpt_xfer(rhport, usbtmc_state.ep_int_in, (void*)&intMsg, sizeof(intMsg)); - } - } - else - { - rsp.statusByte = tud_usbtmc_get_stb_cb(&(rsp.USBTMC_status)); - } - TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp, sizeof(rsp))); - return true; - } - // USB488 optional requests - case USB488_bREQUEST_REN_CONTROL: - case USB488_bREQUEST_GO_TO_LOCAL: - case USB488_bREQUEST_LOCAL_LOCKOUT: - { - TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface - return false; - } -#endif - - default: - return false; - } -} - -#endif /* CFG_TUD_TSMC */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h deleted file mode 100644 index c1298ddb..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/usbtmc/usbtmc_device.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 N Conrad - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - - -#ifndef CLASS_USBTMC_USBTMC_DEVICE_H_ -#define CLASS_USBTMC_USBTMC_DEVICE_H_ - -#include "usbtmc.h" - -// Enable 488 mode by default -#if !defined(CFG_TUD_USBTMC_ENABLE_488) -#define CFG_TUD_USBTMC_ENABLE_488 (1) -#endif - -/*********************************************** - * Functions to be implemented by the class implementation - */ - -// In order to proceed, app must call call tud_usbtmc_start_bus_read(rhport) during or soon after: -// * tud_usbtmc_open_cb -// * tud_usbtmc_msg_data_cb -// * tud_usbtmc_msgBulkIn_complete_cb -// * tud_usbtmc_msg_trigger_cb -// * (successful) tud_usbtmc_check_abort_bulk_out_cb -// * (successful) tud_usbtmc_check_abort_bulk_in_cb -// * (successful) tud_usmtmc_bulkOut_clearFeature_cb - -#if (CFG_TUD_USBTMC_ENABLE_488) -usbtmc_response_capabilities_488_t const * tud_usbtmc_get_capabilities_cb(void); -#else -usbtmc_response_capabilities_t const * tud_usbtmc_get_capabilities_cb(void); -#endif - -void tud_usbtmc_open_cb(uint8_t interface_id); - -bool tud_usbtmc_msgBulkOut_start_cb(usbtmc_msg_request_dev_dep_out const * msgHeader); -// transfer_complete does not imply that a message is complete. -bool tud_usbtmc_msg_data_cb( void *data, size_t len, bool transfer_complete); -void tud_usbtmc_bulkOut_clearFeature_cb(void); // Notice to clear and abort the pending BULK out transfer - -bool tud_usbtmc_msgBulkIn_request_cb(usbtmc_msg_request_dev_dep_in const * request); -bool tud_usbtmc_msgBulkIn_complete_cb(void); -void tud_usbtmc_bulkIn_clearFeature_cb(void); // Notice to clear and abort the pending BULK out transfer - -bool tud_usbtmc_initiate_abort_bulk_in_cb(uint8_t *tmcResult); -bool tud_usbtmc_initiate_abort_bulk_out_cb(uint8_t *tmcResult); -bool tud_usbtmc_initiate_clear_cb(uint8_t *tmcResult); - -bool tud_usbtmc_check_abort_bulk_in_cb(usbtmc_check_abort_bulk_rsp_t *rsp); -bool tud_usbtmc_check_abort_bulk_out_cb(usbtmc_check_abort_bulk_rsp_t *rsp); -bool tud_usbtmc_check_clear_cb(usbtmc_get_clear_status_rsp_t *rsp); - -// Indicator pulse should be 0.5 to 1.0 seconds long -TU_ATTR_WEAK bool tud_usbtmc_indicator_pulse_cb(tusb_control_request_t const * msg, uint8_t *tmcResult); - -#if (CFG_TUD_USBTMC_ENABLE_488) -uint8_t tud_usbtmc_get_stb_cb(uint8_t *tmcResult); -TU_ATTR_WEAK bool tud_usbtmc_msg_trigger_cb(usbtmc_msg_generic_t* msg); -//TU_ATTR_WEAK bool tud_usbtmc_app_go_to_local_cb(); -#endif - -/******************************************* - * Called from app - * - * We keep a reference to the buffer, so it MUST not change until the app is - * notified that the transfer is complete. - ******************************************/ - -bool tud_usbtmc_transmit_dev_msg_data( - const void * data, size_t len, - bool endOfMessage, bool usingTermChar); - -bool tud_usbtmc_start_bus_read(void); - - -/* "callbacks" from USB device core */ - -uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -void usbtmcd_reset_cb(uint8_t rhport); -bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); -bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -void usbtmcd_init_cb(void); - -/************************************************************ - * USBTMC Descriptor Templates - *************************************************************/ - - -#endif /* CLASS_USBTMC_USBTMC_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.c deleted file mode 100644 index 93596ee3..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_VENDOR) - -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "vendor_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -typedef struct -{ - uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; - - /*------------- From this point, data is not cleared by bus reset -------------*/ - tu_fifo_t rx_ff; - tu_fifo_t tx_ff; - - uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE]; - uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE]; - -#if CFG_FIFO_MUTEX - osal_mutex_def_t rx_ff_mutex; - osal_mutex_def_t tx_ff_mutex; -#endif - - // Endpoint Transfer buffer - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_VENDOR_EPSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_VENDOR_EPSIZE]; -} vendord_interface_t; - -CFG_TUSB_MEM_SECTION tu_static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR]; - -#define ITF_MEM_RESET_SIZE offsetof(vendord_interface_t, rx_ff) - - -bool tud_vendor_n_mounted (uint8_t itf) -{ - return _vendord_itf[itf].ep_in && _vendord_itf[itf].ep_out; -} - -uint32_t tud_vendor_n_available (uint8_t itf) -{ - return tu_fifo_count(&_vendord_itf[itf].rx_ff); -} - -bool tud_vendor_n_peek(uint8_t itf, uint8_t* u8) -{ - return tu_fifo_peek(&_vendord_itf[itf].rx_ff, u8); -} - -//--------------------------------------------------------------------+ -// Read API -//--------------------------------------------------------------------+ -static void _prep_out_transaction (vendord_interface_t* p_itf) -{ - uint8_t const rhport = 0; - - // claim endpoint - TU_VERIFY(usbd_edpt_claim(rhport, p_itf->ep_out), ); - - // Prepare for incoming data but only allow what we can store in the ring buffer. - uint16_t max_read = tu_fifo_remaining(&p_itf->rx_ff); - if ( max_read >= CFG_TUD_VENDOR_EPSIZE ) - { - usbd_edpt_xfer(rhport, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE); - } - else - { - // Release endpoint since we don't make any transfer - usbd_edpt_release(rhport, p_itf->ep_out); - } -} - -uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize) -{ - vendord_interface_t* p_itf = &_vendord_itf[itf]; - uint32_t num_read = tu_fifo_read_n(&p_itf->rx_ff, buffer, (uint16_t) bufsize); - _prep_out_transaction(p_itf); - return num_read; -} - -void tud_vendor_n_read_flush (uint8_t itf) -{ - vendord_interface_t* p_itf = &_vendord_itf[itf]; - tu_fifo_clear(&p_itf->rx_ff); - _prep_out_transaction(p_itf); -} - -//--------------------------------------------------------------------+ -// Write API -//--------------------------------------------------------------------+ -uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize) -{ - vendord_interface_t* p_itf = &_vendord_itf[itf]; - uint16_t ret = tu_fifo_write_n(&p_itf->tx_ff, buffer, (uint16_t) bufsize); - - // flush if queue more than packet size - if (tu_fifo_count(&p_itf->tx_ff) >= CFG_TUD_VENDOR_EPSIZE) { - tud_vendor_n_write_flush(itf); - } - return ret; -} - -uint32_t tud_vendor_n_write_flush (uint8_t itf) -{ - vendord_interface_t* p_itf = &_vendord_itf[itf]; - - // Skip if usb is not ready yet - TU_VERIFY( tud_ready(), 0 ); - - // No data to send - if ( !tu_fifo_count(&p_itf->tx_ff) ) return 0; - - uint8_t const rhport = 0; - - // Claim the endpoint - TU_VERIFY( usbd_edpt_claim(rhport, p_itf->ep_in), 0 ); - - // Pull data from FIFO - uint16_t const count = tu_fifo_read_n(&p_itf->tx_ff, p_itf->epin_buf, sizeof(p_itf->epin_buf)); - - if ( count ) - { - TU_ASSERT( usbd_edpt_xfer(rhport, p_itf->ep_in, p_itf->epin_buf, count), 0 ); - return count; - }else - { - // Release endpoint since we don't make any transfer - // Note: data is dropped if terminal is not connected - usbd_edpt_release(rhport, p_itf->ep_in); - return 0; - } -} - -uint32_t tud_vendor_n_write_available (uint8_t itf) -{ - return tu_fifo_remaining(&_vendord_itf[itf].tx_ff); -} - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void vendord_init(void) -{ - tu_memclr(_vendord_itf, sizeof(_vendord_itf)); - - for(uint8_t i=0; irx_ff, p_itf->rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, 1, false); - tu_fifo_config(&p_itf->tx_ff, p_itf->tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, 1, false); - -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&p_itf->rx_ff, NULL, osal_mutex_create(&p_itf->rx_ff_mutex)); - tu_fifo_config_mutex(&p_itf->tx_ff, osal_mutex_create(&p_itf->tx_ff_mutex), NULL); -#endif - } -} - -void vendord_reset(uint8_t rhport) -{ - (void) rhport; - - for(uint8_t i=0; irx_ff); - tu_fifo_clear(&p_itf->tx_ff); - } -} - -uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) -{ - TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0); - - uint8_t const * p_desc = tu_desc_next(desc_itf); - uint8_t const * desc_end = p_desc + max_len; - - // Find available interface - vendord_interface_t* p_vendor = NULL; - for(uint8_t i=0; iitf_num = desc_itf->bInterfaceNumber; - if (desc_itf->bNumEndpoints) - { - // skip non-endpoint descriptors - while ( (TUSB_DESC_ENDPOINT != tu_desc_type(p_desc)) && (p_desc < desc_end) ) - { - p_desc = tu_desc_next(p_desc); - } - - // Open endpoint pair with usbd helper - TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_BULK, &p_vendor->ep_out, &p_vendor->ep_in), 0); - - p_desc += desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t); - - // Prepare for incoming data - if ( p_vendor->ep_out ) - { - _prep_out_transaction(p_vendor); - } - - if ( p_vendor->ep_in ) tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); - } - - return (uint16_t) ((uintptr_t) p_desc - (uintptr_t) desc_itf); -} - -bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void) rhport; - (void) result; - - uint8_t itf = 0; - vendord_interface_t* p_itf = _vendord_itf; - - for ( ; ; itf++, p_itf++) - { - if (itf >= TU_ARRAY_SIZE(_vendord_itf)) return false; - - if ( ( ep_addr == p_itf->ep_out ) || ( ep_addr == p_itf->ep_in ) ) break; - } - - if ( ep_addr == p_itf->ep_out ) - { - // Receive new data - tu_fifo_write_n(&p_itf->rx_ff, p_itf->epout_buf, (uint16_t) xferred_bytes); - - // Invoked callback if any - if (tud_vendor_rx_cb) tud_vendor_rx_cb(itf); - - _prep_out_transaction(p_itf); - } - else if ( ep_addr == p_itf->ep_in ) - { - if (tud_vendor_tx_cb) tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes); - // Send complete, try to send more if possible - tud_vendor_n_write_flush(itf); - } - - return true; -} - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.h deleted file mode 100644 index d239406b..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_device.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_VENDOR_DEVICE_H_ -#define _TUSB_VENDOR_DEVICE_H_ - -#include "common/tusb_common.h" - -#ifndef CFG_TUD_VENDOR_EPSIZE -#define CFG_TUD_VENDOR_EPSIZE 64 -#endif - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Application API (Multiple Interfaces) -//--------------------------------------------------------------------+ -bool tud_vendor_n_mounted (uint8_t itf); - -uint32_t tud_vendor_n_available (uint8_t itf); -uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize); -bool tud_vendor_n_peek (uint8_t itf, uint8_t* ui8); -void tud_vendor_n_read_flush (uint8_t itf); - -uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize); -uint32_t tud_vendor_n_write_flush (uint8_t itf); -uint32_t tud_vendor_n_write_available (uint8_t itf); - -static inline uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str); - -// backward compatible -#define tud_vendor_n_flush(itf) tud_vendor_n_write_flush(itf) - -//--------------------------------------------------------------------+ -// Application API (Single Port) -//--------------------------------------------------------------------+ -static inline bool tud_vendor_mounted (void); -static inline uint32_t tud_vendor_available (void); -static inline uint32_t tud_vendor_read (void* buffer, uint32_t bufsize); -static inline bool tud_vendor_peek (uint8_t* ui8); -static inline void tud_vendor_read_flush (void); -static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize); -static inline uint32_t tud_vendor_write_str (char const* str); -static inline uint32_t tud_vendor_write_available (void); -static inline uint32_t tud_vendor_write_flush (void); - -// backward compatible -#define tud_vendor_flush() tud_vendor_write_flush() - -//--------------------------------------------------------------------+ -// Application Callback API (weak is optional) -//--------------------------------------------------------------------+ - -// Invoked when received new data -TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf); -// Invoked when last rx transfer finished -TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes); - -//--------------------------------------------------------------------+ -// Inline Functions -//--------------------------------------------------------------------+ - -static inline uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str) -{ - return tud_vendor_n_write(itf, str, strlen(str)); -} - -static inline bool tud_vendor_mounted (void) -{ - return tud_vendor_n_mounted(0); -} - -static inline uint32_t tud_vendor_available (void) -{ - return tud_vendor_n_available(0); -} - -static inline uint32_t tud_vendor_read (void* buffer, uint32_t bufsize) -{ - return tud_vendor_n_read(0, buffer, bufsize); -} - -static inline bool tud_vendor_peek (uint8_t* ui8) -{ - return tud_vendor_n_peek(0, ui8); -} - -static inline void tud_vendor_read_flush(void) -{ - tud_vendor_n_read_flush(0); -} - -static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize) -{ - return tud_vendor_n_write(0, buffer, bufsize); -} - -static inline uint32_t tud_vendor_write_flush (void) -{ - return tud_vendor_n_write_flush(0); -} - -static inline uint32_t tud_vendor_write_str (char const* str) -{ - return tud_vendor_n_write_str(0, str); -} - -static inline uint32_t tud_vendor_write_available (void) -{ - return tud_vendor_n_write_available(0); -} - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void vendord_init(void); -void vendord_reset(uint8_t rhport); -uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_VENDOR_DEVICE_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.c b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.c deleted file mode 100644 index e66c5007..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUH_ENABLED && CFG_TUH_VENDOR) - -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "host/usbh.h" -#include "vendor_host.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -custom_interface_info_t custom_interface[CFG_TUH_DEVICE_MAX]; - -static tusb_error_t cush_validate_paras(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length) -{ - if ( !tusbh_custom_is_mounted(dev_addr, vendor_id, product_id) ) - { - return TUSB_ERROR_DEVICE_NOT_READY; - } - - TU_ASSERT( p_buffer != NULL && length != 0, TUSB_ERROR_INVALID_PARA); - - return TUSB_ERROR_NONE; -} -//--------------------------------------------------------------------+ -// APPLICATION API (need to check parameters) -//--------------------------------------------------------------------+ -tusb_error_t tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length) -{ - TU_ASSERT_ERR( cush_validate_paras(dev_addr, vendor_id, product_id, p_buffer, length) ); - - if ( !hcd_pipe_is_idle(custom_interface[dev_addr-1].pipe_in) ) - { - return TUSB_ERROR_INTERFACE_IS_BUSY; - } - - (void) usbh_edpt_xfer( custom_interface[dev_addr-1].pipe_in, p_buffer, length); - - return TUSB_ERROR_NONE; -} - -tusb_error_t tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length) -{ - TU_ASSERT_ERR( cush_validate_paras(dev_addr, vendor_id, product_id, p_data, length) ); - - if ( !hcd_pipe_is_idle(custom_interface[dev_addr-1].pipe_out) ) - { - return TUSB_ERROR_INTERFACE_IS_BUSY; - } - - (void) usbh_edpt_xfer( custom_interface[dev_addr-1].pipe_out, p_data, length); - - return TUSB_ERROR_NONE; -} - -//--------------------------------------------------------------------+ -// USBH-CLASS API -//--------------------------------------------------------------------+ -void cush_init(void) -{ - tu_memclr(&custom_interface, sizeof(custom_interface_info_t) * CFG_TUH_DEVICE_MAX); -} - -tusb_error_t cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length) -{ - // FIXME quick hack to test lpc1k custom class with 2 bulk endpoints - uint8_t const *p_desc = (uint8_t const *) p_interface_desc; - p_desc = tu_desc_next(p_desc); - - //------------- Bulk Endpoints Descriptor -------------// - for(uint32_t i=0; i<2; i++) - { - tusb_desc_endpoint_t const *p_endpoint = (tusb_desc_endpoint_t const *) p_desc; - TU_ASSERT(TUSB_DESC_ENDPOINT == p_endpoint->bDescriptorType, TUSB_ERROR_INVALID_PARA); - - pipe_handle_t * p_pipe_hdl = ( p_endpoint->bEndpointAddress & TUSB_DIR_IN_MASK ) ? - &custom_interface[dev_addr-1].pipe_in : &custom_interface[dev_addr-1].pipe_out; - *p_pipe_hdl = usbh_edpt_open(dev_addr, p_endpoint, TUSB_CLASS_VENDOR_SPECIFIC); - TU_ASSERT ( pipehandle_is_valid(*p_pipe_hdl), TUSB_ERROR_HCD_OPEN_PIPE_FAILED ); - - p_desc = tu_desc_next(p_desc); - } - - (*p_length) = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t); - return TUSB_ERROR_NONE; -} - -void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event) -{ - -} - -void cush_close(uint8_t dev_addr) -{ - tusb_error_t err1, err2; - custom_interface_info_t * p_interface = &custom_interface[dev_addr-1]; - - // TODO re-consider to check pipe valid before calling pipe_close - if( pipehandle_is_valid( p_interface->pipe_in ) ) - { - err1 = hcd_pipe_close( p_interface->pipe_in ); - } - - if ( pipehandle_is_valid( p_interface->pipe_out ) ) - { - err2 = hcd_pipe_close( p_interface->pipe_out ); - } - - tu_memclr(p_interface, sizeof(custom_interface_info_t)); - - TU_ASSERT(err1 == TUSB_ERROR_NONE && err2 == TUSB_ERROR_NONE, (void) 0 ); -} - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.h b/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.h deleted file mode 100644 index acfebe7a..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/vendor/vendor_host.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_VENDOR_HOST_H_ -#define _TUSB_VENDOR_HOST_H_ - -#include "common/tusb_common.h" - -#ifdef __cplusplus - extern "C" { -#endif - -typedef struct { - pipe_handle_t pipe_in; - pipe_handle_t pipe_out; -}custom_interface_info_t; - -//--------------------------------------------------------------------+ -// USBH-CLASS DRIVER API -//--------------------------------------------------------------------+ -static inline bool tusbh_custom_is_mounted(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id) -{ - (void) vendor_id; // TODO check this later - (void) product_id; -// return (tusbh_device_get_mounted_class_flag(dev_addr) & TU_BIT(TUSB_CLASS_MAPPED_INDEX_END-1) ) != 0; - return false; -} - -bool tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length); -bool tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void cush_init(void); -bool cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length); -void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event); -void cush_close(uint8_t dev_addr); - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_VENDOR_HOST_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/video/video.h b/test-devices/loopback-stm32/lib/tinyusb/class/video/video.h deleted file mode 100644 index c0088c4f..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/video/video.h +++ /dev/null @@ -1,559 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2021 Koji KITAYAMA - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef TUSB_VIDEO_H_ -#define TUSB_VIDEO_H_ - -#include "common/tusb_common.h" - -// Table 3-19 Color Matching Descriptor -typedef enum { - VIDEO_COLOR_PRIMARIES_UNDEFINED = 0x00, - VIDEO_COLOR_PRIMARIES_BT709, // sRGB (default) - VIDEO_COLOR_PRIMARIES_BT470_2M, - VIDEO_COLOR_PRIMARIES_BT470_2BG, - VIDEO_COLOR_PRIMARIES_SMPTE170M, - VIDEO_COLOR_PRIMARIES_SMPTE240M, -} video_color_primaries_t; - -// Table 3-19 Color Matching Descriptor -typedef enum { - VIDEO_COLOR_XFER_CH_UNDEFINED = 0x00, - VIDEO_COLOR_XFER_CH_BT709, // default - VIDEO_COLOR_XFER_CH_BT470_2M, - VIDEO_COLOR_XFER_CH_BT470_2BG, - VIDEO_COLOR_XFER_CH_SMPTE170M, - VIDEO_COLOR_XFER_CH_SMPTE240M, - VIDEO_COLOR_XFER_CH_LINEAR, - VIDEO_COLOR_XFER_CH_SRGB, -} video_color_transfer_characteristics_t; - -// Table 3-19 Color Matching Descriptor -typedef enum { - VIDEO_COLOR_COEF_UNDEFINED = 0x00, - VIDEO_COLOR_COEF_BT709, - VIDEO_COLOR_COEF_FCC, - VIDEO_COLOR_COEF_BT470_2BG, - VIDEO_COLOR_COEF_SMPTE170M, // BT.601 default - VIDEO_COLOR_COEF_SMPTE240M, -} video_color_matrix_coefficients_t; - -/* 4.2.1.2 Request Error Code Control */ -typedef enum { - VIDEO_ERROR_NONE = 0, /* The request succeeded. */ - VIDEO_ERROR_NOT_READY, - VIDEO_ERROR_WRONG_STATE, - VIDEO_ERROR_POWER, - VIDEO_ERROR_OUT_OF_RANGE, - VIDEO_ERROR_INVALID_UNIT, - VIDEO_ERROR_INVALID_CONTROL, - VIDEO_ERROR_INVALID_REQUEST, - VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE, - VIDEO_ERROR_UNKNOWN = 0xFF, -} video_error_code_t; - -/* A.2 Interface Subclass */ -typedef enum { - VIDEO_SUBCLASS_UNDEFINED = 0x00, - VIDEO_SUBCLASS_CONTROL, - VIDEO_SUBCLASS_STREAMING, - VIDEO_SUBCLASS_INTERFACE_COLLECTION, -} video_subclass_type_t; - -/* A.3 Interface Protocol */ -typedef enum { - VIDEO_ITF_PROTOCOL_UNDEFINED = 0x00, - VIDEO_ITF_PROTOCOL_15, -} video_interface_protocol_code_t; - -/* A.5 Class-Specific VideoControl Interface Descriptor Subtypes */ -typedef enum { - VIDEO_CS_ITF_VC_UNDEFINED = 0x00, - VIDEO_CS_ITF_VC_HEADER, - VIDEO_CS_ITF_VC_INPUT_TERMINAL, - VIDEO_CS_ITF_VC_OUTPUT_TERMINAL, - VIDEO_CS_ITF_VC_SELECTOR_UNIT, - VIDEO_CS_ITF_VC_PROCESSING_UNIT, - VIDEO_CS_ITF_VC_EXTENSION_UNIT, - VIDEO_CS_ITF_VC_ENCODING_UNIT, - VIDEO_CS_ITF_VC_MAX, -} video_cs_vc_interface_subtype_t; - -/* A.6 Class-Specific VideoStreaming Interface Descriptor Subtypes */ -typedef enum { - VIDEO_CS_ITF_VS_UNDEFINED = 0x00, - VIDEO_CS_ITF_VS_INPUT_HEADER = 0x01, - VIDEO_CS_ITF_VS_OUTPUT_HEADER = 0x02, - VIDEO_CS_ITF_VS_STILL_IMAGE_FRAME = 0x03, - VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED = 0x04, - VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED = 0x05, - VIDEO_CS_ITF_VS_FORMAT_MJPEG = 0x06, - VIDEO_CS_ITF_VS_FRAME_MJPEG = 0x07, - VIDEO_CS_ITF_VS_FORMAT_MPEG2TS = 0x0A, - VIDEO_CS_ITF_VS_FORMAT_DV = 0x0C, - VIDEO_CS_ITF_VS_COLORFORMAT = 0x0D, - VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED = 0x10, - VIDEO_CS_ITF_VS_FRAME_FRAME_BASED = 0x11, - VIDEO_CS_ITF_VS_FORMAT_STREAM_BASED = 0x12, - VIDEO_CS_ITF_VS_FORMAT_H264 = 0x13, - VIDEO_CS_ITF_VS_FRAME_H264 = 0x14, - VIDEO_CS_ITF_VS_FORMAT_H264_SIMULCAST = 0x15, - VIDEO_CS_ITF_VS_FORMAT_VP8 = 0x16, - VIDEO_CS_ITF_VS_FRAME_VP8 = 0x17, - VIDEO_CS_ITF_VS_FORMAT_VP8_SIMULCAST = 0x18, -} video_cs_vs_interface_subtype_t; - -/* A.7. Class-Specific Endpoint Descriptor Subtypes */ -typedef enum { - VIDEO_CS_EP_UNDEFINED = 0x00, - VIDEO_CS_EP_GENERAL, - VIDEO_CS_EP_ENDPOINT, - VIDEO_CS_EP_INTERRUPT -} video_cs_ep_subtype_t; - -/* A.8 Class-Specific Request Codes */ -typedef enum { - VIDEO_REQUEST_UNDEFINED = 0x00, - VIDEO_REQUEST_SET_CUR = 0x01, - VIDEO_REQUEST_SET_CUR_ALL = 0x11, - VIDEO_REQUEST_GET_CUR = 0x81, - VIDEO_REQUEST_GET_MIN = 0x82, - VIDEO_REQUEST_GET_MAX = 0x83, - VIDEO_REQUEST_GET_RES = 0x84, - VIDEO_REQUEST_GET_LEN = 0x85, - VIDEO_REQUEST_GET_INFO = 0x86, - VIDEO_REQUEST_GET_DEF = 0x87, - VIDEO_REQUEST_GET_CUR_ALL = 0x91, - VIDEO_REQUEST_GET_MIN_ALL = 0x92, - VIDEO_REQUEST_GET_MAX_ALL = 0x93, - VIDEO_REQUEST_GET_RES_ALL = 0x94, - VIDEO_REQUEST_GET_DEF_ALL = 0x97 -} video_control_request_t; - -/* A.9.1 VideoControl Interface Control Selectors */ -typedef enum { - VIDEO_VC_CTL_UNDEFINED = 0x00, - VIDEO_VC_CTL_VIDEO_POWER_MODE, - VIDEO_VC_CTL_REQUEST_ERROR_CODE, -} video_interface_control_selector_t; - -/* A.9.8 VideoStreaming Interface Control Selectors */ -typedef enum { - VIDEO_VS_CTL_UNDEFINED = 0x00, - VIDEO_VS_CTL_PROBE, - VIDEO_VS_CTL_COMMIT, - VIDEO_VS_CTL_STILL_PROBE, - VIDEO_VS_CTL_STILL_COMMIT, - VIDEO_VS_CTL_STILL_IMAGE_TRIGGER, - VIDEO_VS_CTL_STREAM_ERROR_CODE, - VIDEO_VS_CTL_GENERATE_KEY_FRAME, - VIDEO_VS_CTL_UPDATE_FRAME_SEGMENT, - VIDEO_VS_CTL_SYNCH_DELAY_CONTROL, -} video_interface_streaming_selector_t; - -/* B. Terminal Types */ -typedef enum { - // Terminal - VIDEO_TT_VENDOR_SPECIFIC = 0x0100, - VIDEO_TT_STREAMING = 0x0101, - - // Input - VIDEO_ITT_VENDOR_SPECIFIC = 0x0200, - VIDEO_ITT_CAMERA = 0x0201, - VIDEO_ITT_MEDIA_TRANSPORT_INPUT = 0x0202, - - // Output - VIDEO_OTT_VENDOR_SPECIFIC = 0x0300, - VIDEO_OTT_DISPLAY = 0x0301, - VIDEO_OTT_MEDIA_TRANSPORT_OUTPUT = 0x0302, - - // External - VIDEO_ETT_VENDOR_SPEIFIC = 0x0400, - VIDEO_ETT_COMPOSITE_CONNECTOR = 0x0401, - VIDEO_ETT_SVIDEO_CONNECTOR = 0x0402, - VIDEO_ETT_COMPONENT_CONNECTOR = 0x0403, -} video_terminal_type_t; - -//--------------------------------------------------------------------+ -// Descriptors -//--------------------------------------------------------------------+ - -/* 2.3.4.2 */ -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint16_t bcdUVC; - uint16_t wTotalLength; - uint32_t dwClockFrequency; - uint8_t bInCollection; - uint8_t baInterfaceNr[]; -} tusb_desc_cs_video_ctl_itf_hdr_t; - -/* 2.4.3.3 */ -typedef struct TU_ATTR_PACKED { - uint8_t bHeaderLength; - union { - uint8_t bmHeaderInfo; - struct { - uint8_t FrameID: 1; - uint8_t EndOfFrame: 1; - uint8_t PresentationTime: 1; - uint8_t SourceClockReference: 1; - uint8_t PayloadSpecific: 1; - uint8_t StillImage: 1; - uint8_t Error: 1; - uint8_t EndOfHeader: 1; - }; - }; -} tusb_video_payload_header_t; - -/* 3.9.2.1 */ -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bNumFormats; - uint16_t wTotalLength; - uint8_t bEndpointAddress; - uint8_t bmInfo; - uint8_t bTerminalLink; - uint8_t bStillCaptureMethod; - uint8_t bTriggerSupport; - uint8_t bTriggerUsage; - uint8_t bControlSize; - uint8_t bmaControls[]; -} tusb_desc_cs_video_stm_itf_in_hdr_t; - -/* 3.9.2.2 */ -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bNumFormats; - uint16_t wTotalLength; - uint8_t bEndpointAddress; - uint8_t bTerminalLink; - uint8_t bControlSize; - uint8_t bmaControls[]; -} tusb_desc_cs_video_stm_itf_out_hdr_t; - -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bNumFormats; - uint16_t wTotalLength; - uint8_t bEndpointAddress; - union { - struct { - uint8_t bmInfo; - uint8_t bTerminalLink; - uint8_t bStillCaptureMethod; - uint8_t bTriggerSupport; - uint8_t bTriggerUsage; - uint8_t bControlSize; - uint8_t bmaControls[]; - } input; - struct { - uint8_t bEndpointAddress; - uint8_t bTerminalLink; - uint8_t bControlSize; - uint8_t bmaControls[]; - } output; - }; -} tusb_desc_cs_video_stm_itf_hdr_t; - -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bFormatIndex; - uint8_t bNumFrameDescriptors; - uint8_t guidFormat[16]; - uint8_t bBitsPerPixel; - uint8_t bDefaultFrameIndex; - uint8_t bAspectRatioX; - uint8_t bAspectRatioY; - uint8_t bmInterlaceFlags; - uint8_t bCopyProtect; -} tusb_desc_cs_video_fmt_uncompressed_t; - -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bFormatIndex; - uint8_t bNumFrameDescriptors; - uint8_t bmFlags; - uint8_t bDefaultFrameIndex; - uint8_t bAspectRatioX; - uint8_t bAspectRatioY; - uint8_t bmInterlaceFlags; - uint8_t bCopyProtect; -} tusb_desc_cs_video_fmt_mjpeg_t; - -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bFormatIndex; - uint32_t dwMaxVideoFrameBufferSize; /* deprecated */ - uint8_t bFormatType; -} tusb_desc_cs_video_fmt_dv_t; - -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bFormatIndex; - uint8_t bNumFrameDescriptors; - uint8_t guidFormat[16]; - uint8_t bBitsPerPixel; - uint8_t bDefaultFrameIndex; - uint8_t bAspectRatioX; - uint8_t bAspectRatioY; - uint8_t bmInterlaceFlags; - uint8_t bCopyProtect; - uint8_t bVaribaleSize; -} tusb_desc_cs_video_fmt_frame_based_t; - -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bFrameIndex; - uint8_t bmCapabilities; - uint16_t wWidth; - uint16_t wHeight; - uint32_t dwMinBitRate; - uint32_t dwMaxBitRate; - uint32_t dwMaxVideoFrameBufferSize; /* deprecated */ - uint32_t dwDefaultFrameInterval; - uint8_t bFrameIntervalType; - uint32_t dwFrameInterval[]; -} tusb_desc_cs_video_frm_uncompressed_t; - -typedef tusb_desc_cs_video_frm_uncompressed_t tusb_desc_cs_video_frm_mjpeg_t; - -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bFrameIndex; - uint8_t bmCapabilities; - uint16_t wWidth; - uint16_t wHeight; - uint32_t dwMinBitRate; - uint32_t dwMaxBitRate; - uint32_t dwDefaultFrameInterval; - uint8_t bFrameIntervalType; - uint32_t dwBytesPerLine; - uint32_t dwFrameInterval[]; -} tusb_desc_cs_video_frm_frame_based_t; - -//--------------------------------------------------------------------+ -// Requests -//--------------------------------------------------------------------+ - -/* 4.3.1.1 */ -typedef struct TU_ATTR_PACKED { - union { - uint8_t bmHint; - struct TU_ATTR_PACKED { - uint16_t dwFrameInterval: 1; - uint16_t wKeyFrameRatel : 1; - uint16_t wPFrameRate : 1; - uint16_t wCompQuality : 1; - uint16_t wCompWindowSize: 1; - uint16_t : 0; - } Hint; - }; - uint8_t bFormatIndex; - uint8_t bFrameIndex; - uint32_t dwFrameInterval; - uint16_t wKeyFrameRate; - uint16_t wPFrameRate; - uint16_t wCompQuality; - uint16_t wCompWindowSize; - uint16_t wDelay; - uint32_t dwMaxVideoFrameSize; - uint32_t dwMaxPayloadTransferSize; - uint32_t dwClockFrequency; - union { - uint8_t bmFramingInfo; - struct TU_ATTR_PACKED { - uint8_t FrameID : 1; - uint8_t EndOfFrame: 1; - uint8_t EndOfSlice: 1; - uint8_t : 0; - } FramingInfo; - }; - uint8_t bPreferedVersion; - uint8_t bMinVersion; - uint8_t bMaxVersion; - uint8_t bUsage; - uint8_t bBitDepthLuma; - uint8_t bmSettings; - uint8_t bMaxNumberOfRefFramesPlus1; - uint16_t bmRateControlModes; - uint64_t bmLayoutPerStream; -} video_probe_and_commit_control_t; - -TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not correct"); - -#define TUD_VIDEO_DESC_IAD_LEN 8 -#define TUD_VIDEO_DESC_STD_VC_LEN 9 -#define TUD_VIDEO_DESC_CS_VC_LEN 12 -#define TUD_VIDEO_DESC_INPUT_TERM_LEN 8 -#define TUD_VIDEO_DESC_OUTPUT_TERM_LEN 9 -#define TUD_VIDEO_DESC_CAMERA_TERM_LEN 18 -#define TUD_VIDEO_DESC_STD_VS_LEN 9 -#define TUD_VIDEO_DESC_CS_VS_IN_LEN 13 -#define TUD_VIDEO_DESC_CS_VS_OUT_LEN 9 -#define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN 27 -#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN 11 -#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN 38 -#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN 26 -#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN 38 -#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN 26 -#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN 6 - -/* 2.2 compression formats */ -#define TUD_VIDEO_GUID_YUY2 0x59,0x55,0x59,0x32,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 -#define TUD_VIDEO_GUID_NV12 0x4E,0x56,0x31,0x32,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 -#define TUD_VIDEO_GUID_M420 0x4D,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 -#define TUD_VIDEO_GUID_I420 0x49,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 - -#define TUD_VIDEO_DESC_IAD(_firstitfs, _nitfs, _stridx) \ - TUD_VIDEO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, \ - _firstitfs, _nitfs, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_INTERFACE_COLLECTION, \ - VIDEO_ITF_PROTOCOL_UNDEFINED, _stridx - -#define TUD_VIDEO_DESC_STD_VC(_itfnum, _nEPs, _stridx) \ - TUD_VIDEO_DESC_STD_VC_LEN, TUSB_DESC_INTERFACE, _itfnum, /* fixed to zero */ 0x00, \ - _nEPs, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_CONTROL, VIDEO_ITF_PROTOCOL_15, _stridx - -/* 3.7.2 */ -#define TUD_VIDEO_DESC_CS_VC(_bcdUVC, _totallen, _clkfreq, ...) \ - TUD_VIDEO_DESC_CS_VC_LEN + (TU_ARGS_NUM(__VA_ARGS__)), TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_HEADER, \ - U16_TO_U8S_LE(_bcdUVC), U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VC_LEN + (TU_ARGS_NUM(__VA_ARGS__))), \ - U32_TO_U8S_LE(_clkfreq), TU_ARGS_NUM(__VA_ARGS__), __VA_ARGS__ - -/* 3.7.2.1 */ -#define TUD_VIDEO_DESC_INPUT_TERM(_tid, _tt, _at, _stridx) \ - TUD_VIDEO_DESC_INPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_INPUT_TERMINAL, \ - _tid, U16_TO_U8S_LE(_tt), _at, _stridx - -/* 3.7.2.2 */ -#define TUD_VIDEO_DESC_OUTPUT_TERM(_tid, _tt, _at, _srcid, _stridx) \ - TUD_VIDEO_DESC_OUTPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_OUTPUT_TERMINAL, \ - _tid, U16_TO_U8S_LE(_tt), _at, _srcid, _stridx - -/* 3.7.2.3 */ -#define TUD_VIDEO_DESC_CAMERA_TERM(_tid, _at, _stridx, _focal_min, _focal_max, _focal, _ctls) \ - TUD_VIDEO_DESC_CAMERA_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_INPUT_TERMINAL, \ - _tid, U16_TO_U8S_LE(VIDEO_ITT_CAMERA), _at, _stridx, \ - U16_TO_U8S_LE(_focal_min), U16_TO_U8S_LE(_focal_max), U16_TO_U8S_LE(_focal), 3, \ - TU_U32_BYTE0(_ctls), TU_U32_BYTE1(_ctls), TU_U32_BYTE2(_ctls) - -/* 3.9.1 */ -#define TUD_VIDEO_DESC_STD_VS(_itfnum, _alt, _epn, _stridx) \ - TUD_VIDEO_DESC_STD_VS_LEN, TUSB_DESC_INTERFACE, _itfnum, _alt, \ - _epn, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_STREAMING, VIDEO_ITF_PROTOCOL_15, _stridx - -/* 3.9.2.1 */ -#define TUD_VIDEO_DESC_CS_VS_INPUT(_numfmt, _totallen, _ep, _inf, _termlnk, _sticaptmeth, _trgspt, _trgusg, ...) \ - TUD_VIDEO_DESC_CS_VS_IN_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__)), TUSB_DESC_CS_INTERFACE, \ - VIDEO_CS_ITF_VS_INPUT_HEADER, _numfmt, \ - U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VS_IN_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__))), \ - _ep, _inf, _termlnk, _sticaptmeth, _trgspt, _trgusg, (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ - -/* 3.9.2.2 */ -#define TUD_VIDEO_DESC_CS_VS_OUTPUT(_numfmt, _totallen, _ep, _inf, _termlnk, ...) \ - TUD_VIDEO_DESC_CS_VS_OUT_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__)), TUSB_DESC_CS_INTERFACE, \ - VIDEO_CS_ITF_VS_OUTPUT_HEADER, _numfmt, \ - U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VS_OUT_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__))), \ - _ep, _inf, _termlnk, (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ - -/* Uncompressed 3.1.1 */ -#define TUD_VIDEO_GUID(_g0,_g1,_g2,_g3,_g4,_g5,_g6,_g7,_g8,_g9,_g10,_g11,_g12,_g13,_g14,_g15) _g0,_g1,_g2,_g3,_g4,_g5,_g6,_g7,_g8,_g9,_g10,_g11,_g12,_g13,_g14,_g15 - -#define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR(_fmtidx, _numfrmdesc, \ - _guid, _bitsperpix, _frmidx, _asrx, _asry, _interlace, _cp) \ - TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED, \ - _fmtidx, _numfrmdesc, TUD_VIDEO_GUID(_guid), \ - _bitsperpix, _frmidx, _asrx, _asry, _interlace, _cp - -/* Uncompressed 3.1.2 Table 3-3 */ -#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, _minfrminterval, _maxfrminterval, _frmintervalstep) \ - TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, \ - _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ - U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), 0, \ - U32_TO_U8S_LE(_minfrminterval), U32_TO_U8S_LE(_maxfrminterval), U32_TO_U8S_LE(_frmintervalstep) - -/* Uncompressed 3.1.2 Table 3-4 */ -#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, ...) \ - TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN + (TU_ARGS_NUM(__VA_ARGS__)) * 4, \ - TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, \ - _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ - U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ - -/* Motion-JPEG 3.1.1 Table 3-1 */ -#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG(_fmtidx, _numfrmdesc, _fixed_sz, _frmidx, _asrx, _asry, _interlace, _cp) \ - TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_MJPEG, \ - _fmtidx, _numfrmdesc, _fixed_sz, _frmidx, _asrx, _asry, _interlace, _cp - -/* Motion-JPEG 3.1.1 Table 3-2 and 3-3 */ -#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, _minfrminterval, _maxfrminterval, _frmintervalstep) \ - TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_MJPEG, \ - _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ - U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), 0, \ - U32_TO_U8S_LE(_minfrminterval), U32_TO_U8S_LE(_maxfrminterval), U32_TO_U8S_LE(_frmintervalstep) - -/* Motion-JPEG 3.1.1 Table 3-2 and 3-4 */ -#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, ...) \ - TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN + (TU_ARGS_NUM(__VA_ARGS__)) * 4, \ - TUSB_DESC_CS_INTERFACE, VIDEO_CS_VS_INTERFACE_FRAME_MJPEG, \ - _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ - U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ - -/* 3.9.2.6 */ -#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(_color, _trns, _mat) \ - TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN, \ - TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_COLORFORMAT, \ - _color, _trns, _mat - -/* 3.10.1.1 */ -#define TUD_VIDEO_DESC_EP_ISO(_ep, _epsize, _ep_interval) \ - 7, TUSB_DESC_ENDPOINT, _ep, (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS),\ - U16_TO_U8S_LE(_epsize), _ep_interval - -/* 3.10.1.2 */ -#define TUD_VIDEO_DESC_EP_BULK(_ep, _epsize, _ep_interval) \ - 7, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), _ep_interval - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.c b/test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.c deleted file mode 100644 index d6e98602..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.c +++ /dev/null @@ -1,1257 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2021 Koji KITAYAMA - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUD_ENABLED && CFG_TUD_VIDEO && CFG_TUD_VIDEO_STREAMING) - -#include "device/usbd.h" -#include "device/usbd_pvt.h" - -#include "video_device.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -typedef struct { - tusb_desc_interface_t std; - tusb_desc_cs_video_ctl_itf_hdr_t ctl; -} tusb_desc_vc_itf_t; - -typedef struct { - tusb_desc_interface_t std; - tusb_desc_cs_video_stm_itf_hdr_t stm; -} tusb_desc_vs_itf_t; - -typedef union { - tusb_desc_cs_video_ctl_itf_hdr_t ctl; - tusb_desc_cs_video_stm_itf_hdr_t stm; -} tusb_desc_video_itf_hdr_t; - -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubtype; - uint8_t bEntityId; -} tusb_desc_cs_video_entity_itf_t; - -typedef union { - struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bFormatIndex; - uint8_t bNumFrameDescriptors; - }; - tusb_desc_cs_video_fmt_uncompressed_t uncompressed; - tusb_desc_cs_video_fmt_mjpeg_t mjpeg; - tusb_desc_cs_video_fmt_frame_based_t frame_based; -} tusb_desc_cs_video_fmt_t; - -typedef union { - struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bFrameIndex; - uint8_t bmCapabilities; - uint16_t wWidth; - uint16_t wHeight; - }; - tusb_desc_cs_video_frm_uncompressed_t uncompressed; - tusb_desc_cs_video_frm_mjpeg_t mjpeg; - tusb_desc_cs_video_frm_frame_based_t frame_based; -} tusb_desc_cs_video_frm_t; - -/* video streaming interface */ -typedef struct TU_ATTR_PACKED { - uint8_t index_vc; /* index of bound video control interface */ - uint8_t index_vs; /* index from the video control interface */ - struct { - uint16_t beg; /* Offset of the begging of video streaming interface descriptor */ - uint16_t end; /* Offset of the end of video streaming interface descriptor */ - uint16_t cur; /* Offset of the current settings */ - uint16_t ep[2]; /* Offset of endpoint descriptors. 0: streaming, 1: still capture */ - } desc; - uint8_t *buffer; /* frame buffer. assume linear buffer. no support for stride access */ - uint32_t bufsize; /* frame buffer size */ - uint32_t offset; /* offset for the next payload transfer */ - uint32_t max_payload_transfer_size; - uint8_t error_code;/* error code */ - /*------------- From this point, data is not cleared by bus reset -------------*/ - CFG_TUSB_MEM_ALIGN uint8_t ep_buf[CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE]; /* EP transfer buffer for streaming */ -} videod_streaming_interface_t; - -/* video control interface */ -typedef struct TU_ATTR_PACKED { - uint8_t const *beg; /* The head of the first video control interface descriptor */ - uint16_t len; /* Byte length of the descriptors */ - uint16_t cur; /* offset for current video control interface */ - uint8_t stm[CFG_TUD_VIDEO_STREAMING]; /* Indices of streaming interface */ - uint8_t error_code; /* error code */ - uint8_t power_mode; - - /*------------- From this point, data is not cleared by bus reset -------------*/ - // CFG_TUSB_MEM_ALIGN uint8_t ctl_buf[64]; /* EP transfer buffer for interrupt transfer */ - -} videod_interface_t; - -#define ITF_STM_MEM_RESET_SIZE offsetof(videod_streaming_interface_t, ep_buf) - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION tu_static videod_interface_t _videod_itf[CFG_TUD_VIDEO]; -CFG_TUSB_MEM_SECTION tu_static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING]; - -tu_static uint8_t const _cap_get = 0x1u; /* support for GET */ -tu_static uint8_t const _cap_get_set = 0x3u; /* support for GET and SET */ - -/** Get interface number from the interface descriptor - * - * @param[in] desc interface descriptor - * - * @return bInterfaceNumber */ -static inline uint8_t _desc_itfnum(void const *desc) -{ - return ((uint8_t const*)desc)[2]; -} - -/** Get endpoint address from the endpoint descriptor - * - * @param[in] desc endpoint descriptor - * - * @return bEndpointAddress */ -static inline uint8_t _desc_ep_addr(void const *desc) -{ - return ((uint8_t const*)desc)[2]; -} - -/** Get instance of streaming interface - * - * @param[in] ctl_idx instance number of video control - * @param[in] stm_idx index number of streaming interface - * - * @return instance */ -static videod_streaming_interface_t* _get_instance_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) -{ - videod_interface_t *ctl = &_videod_itf[ctl_idx]; - if (!ctl->beg) return NULL; - videod_streaming_interface_t *stm = &_videod_streaming_itf[ctl->stm[stm_idx]]; - if (!stm->desc.beg) return NULL; - return stm; -} - -static tusb_desc_vc_itf_t const* _get_desc_vc(videod_interface_t const *self) -{ - return (tusb_desc_vc_itf_t const *)(self->beg + self->cur); -} - -static tusb_desc_vs_itf_t const* _get_desc_vs(videod_streaming_interface_t const *self) -{ - if (!self->desc.cur) return NULL; - uint8_t const *desc = _videod_itf[self->index_vc].beg; - return (tusb_desc_vs_itf_t const*)(desc + self->desc.cur); -} - -/** Find the first descriptor of a given type - * - * @param[in] beg The head of descriptor byte array. - * @param[in] end The tail of descriptor byte array. - * @param[in] desc_type The target descriptor type. - * - * @return The pointer for interface descriptor. - * @retval end did not found interface descriptor */ -static void const* _find_desc(void const *beg, void const *end, uint_fast8_t desc_type) -{ - void const *cur = beg; - while ((cur < end) && (desc_type != tu_desc_type(cur))) { - cur = tu_desc_next(cur); - } - return cur; -} - -/** Find the first descriptor specified by the arguments - * - * @param[in] beg The head of descriptor byte array. - * @param[in] end The tail of descriptor byte array. - * @param[in] desc_type The target descriptor type - * @param[in] element_0 The target element following the desc_type - * @param[in] element_1 The target element following the element_0 - * - * @return The pointer for interface descriptor. - * @retval end did not found interface descriptor */ -static void const* _find_desc_3(void const *beg, void const *end, - uint_fast8_t desc_type, - uint_fast8_t element_0, - uint_fast8_t element_1) -{ - for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, desc_type)) { - uint8_t const *p = (uint8_t const *)cur; - if ((p[2] == element_0) && (p[3] == element_1)) { - return cur; - } - cur = tu_desc_next(cur); - } - return end; -} - -/** Return the next interface descriptor which has another interface number. - * - * @param[in] beg The head of descriptor byte array. - * @param[in] end The tail of descriptor byte array. - * - * @return The pointer for interface descriptor. - * @retval end did not found interface descriptor */ -static void const* _next_desc_itf(void const *beg, void const *end) -{ - void const *cur = beg; - uint_fast8_t itfnum = ((tusb_desc_interface_t const*)cur)->bInterfaceNumber; - while ((cur < end) && - (itfnum == ((tusb_desc_interface_t const*)cur)->bInterfaceNumber)) { - cur = _find_desc(tu_desc_next(cur), end, TUSB_DESC_INTERFACE); - } - return cur; -} - -/** Find the first interface descriptor with the specified interface number and alternate setting number. - * - * @param[in] beg The head of descriptor byte array. - * @param[in] end The tail of descriptor byte array. - * @param[in] itfnum The target interface number. - * @param[in] altnum The target alternate setting number. - * - * @return The pointer for interface descriptor. - * @retval end did not found interface descriptor */ -static inline uint8_t const* _find_desc_itf(void const *beg, void const *end, uint_fast8_t itfnum, uint_fast8_t altnum) -{ - return (uint8_t const*) _find_desc_3(beg, end, TUSB_DESC_INTERFACE, itfnum, altnum); -} - -/** Find the first endpoint descriptor belonging to the current interface descriptor. - * - * The search range is from `beg` to `end` or the next interface descriptor. - * - * @param[in] beg The head of descriptor byte array. - * @param[in] end The tail of descriptor byte array. - * - * @return The pointer for endpoint descriptor. - * @retval end did not found endpoint descriptor */ -static void const* _find_desc_ep(void const *beg, void const *end) -{ - for (void const *cur = beg; cur < end; cur = tu_desc_next(cur)) { - uint_fast8_t desc_type = tu_desc_type(cur); - if (TUSB_DESC_ENDPOINT == desc_type) return cur; - if (TUSB_DESC_INTERFACE == desc_type) break; - } - return end; -} - -/** Return the end of the video control descriptor. */ -static inline void const* _end_of_control_descriptor(void const *desc) -{ - tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const *)desc; - return ((uint8_t const*) desc) + vc->std.bLength + tu_le16toh(vc->ctl.wTotalLength); -} - -/** Find the first entity descriptor with the entity ID - * specified by the argument belonging to the current video control descriptor. - * - * @param[in] desc The video control interface descriptor. - * @param[in] entityid The target entity id. - * - * @return The pointer for interface descriptor. - * @retval end did not found interface descriptor */ -static void const* _find_desc_entity(void const *desc, uint_fast8_t entityid) -{ - void const *end = _end_of_control_descriptor(desc); - for (void const *cur = desc; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) { - tusb_desc_cs_video_entity_itf_t const *itf = (tusb_desc_cs_video_entity_itf_t const *)cur; - if ((VIDEO_CS_ITF_VC_INPUT_TERMINAL <= itf->bDescriptorSubtype - && itf->bDescriptorSubtype < VIDEO_CS_ITF_VC_MAX) - && itf->bEntityId == entityid) { - return itf; - } - cur = tu_desc_next(cur); - } - return end; -} - -/** Return the end of the video streaming descriptor. */ -static inline void const* _end_of_streaming_descriptor(void const *desc) -{ - tusb_desc_vs_itf_t const *vs = (tusb_desc_vs_itf_t const *)desc; - return ((uint8_t const*) desc) + vs->std.bLength + tu_le16toh(vs->stm.wTotalLength); -} - -/** Find the first format descriptor with the specified format number. */ -static inline void const *_find_desc_format(void const *beg, void const *end, uint_fast8_t fmtnum) -{ - for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) { - uint8_t const *p = (uint8_t const *)cur; - uint_fast8_t fmt = p[2]; - if ((fmt == VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED || - fmt == VIDEO_CS_ITF_VS_FORMAT_MJPEG || - fmt == VIDEO_CS_ITF_VS_FORMAT_DV || - fmt == VIDEO_CS_ITF_VS_FRAME_FRAME_BASED) && - fmtnum == p[3]) { - return cur; - } - cur = tu_desc_next(cur); - } - return end; -} - -/** Find the first frame descriptor with the specified format number. */ -static inline void const *_find_desc_frame(void const *beg, void const *end, uint_fast8_t frmnum) -{ - for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) { - uint8_t const *p = (uint8_t const *)cur; - uint_fast8_t frm = p[2]; - if ((frm == VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED || - frm == VIDEO_CS_ITF_VS_FRAME_MJPEG || - frm == VIDEO_CS_ITF_VS_FRAME_FRAME_BASED) && - frmnum == p[3]) { - return cur; - } - cur = tu_desc_next(cur); - } - return end; -} - -/** Set uniquely determined values to variables that have not been set - * - * @param[in,out] param Target */ -static bool _update_streaming_parameters(videod_streaming_interface_t const *stm, - video_probe_and_commit_control_t *param) -{ - tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); - uint_fast8_t fmtnum = param->bFormatIndex; - TU_ASSERT(vs && fmtnum <= vs->stm.bNumFormats); - if (!fmtnum) { - if (1 < vs->stm.bNumFormats) return true; /* Need to negotiate all variables. */ - fmtnum = 1; - param->bFormatIndex = 1; - } - - /* Set the parameters determined by the format */ - param->wKeyFrameRate = 1; - param->wPFrameRate = 0; - param->wCompWindowSize = 1; /* GOP size? */ - param->wDelay = 0; /* milliseconds */ - param->dwClockFrequency = 27000000; /* same as MPEG-2 system time clock */ - param->bmFramingInfo = 0x3; /* enables FrameID and EndOfFrame */ - param->bPreferedVersion = 1; - param->bMinVersion = 1; - param->bMaxVersion = 1; - param->bUsage = 0; - param->bBitDepthLuma = 8; - - void const *end = _end_of_streaming_descriptor(vs); - tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); - TU_ASSERT(fmt != end); - - switch (fmt->bDescriptorSubType) { - case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED: - param->wCompQuality = 1; /* 1 to 10000 */ - break; - case VIDEO_CS_ITF_VS_FORMAT_MJPEG: - break; - default: return false; - } - - uint_fast8_t frmnum = param->bFrameIndex; - TU_ASSERT(frmnum <= fmt->bNumFrameDescriptors); - if (!frmnum) { - if (1 < fmt->bNumFrameDescriptors) return true; - frmnum = 1; - param->bFrameIndex = 1; - } - tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); - TU_ASSERT(frm != end); - - /* Set the parameters determined by the frame */ - uint_fast32_t frame_size = param->dwMaxVideoFrameSize; - if (!frame_size) { - switch (fmt->bDescriptorSubType) { - case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED: - frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->uncompressed.bBitsPerPixel / 8; - break; - case VIDEO_CS_ITF_VS_FORMAT_MJPEG: - frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */ - break; - default: break; - } - param->dwMaxVideoFrameSize = frame_size; - } - - uint_fast32_t interval = param->dwFrameInterval; - if (!interval) { - if ((1 < frm->uncompressed.bFrameIntervalType) || - ((0 == frm->uncompressed.bFrameIntervalType) && - (frm->uncompressed.dwFrameInterval[1] != frm->uncompressed.dwFrameInterval[0]))) { - return true; - } - interval = frm->uncompressed.dwFrameInterval[0]; - param->dwFrameInterval = interval; - } - uint_fast32_t interval_ms = interval / 10000; - TU_ASSERT(interval_ms); - uint_fast32_t payload_size = (frame_size + interval_ms - 1) / interval_ms + 2; - if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) - payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE; - param->dwMaxPayloadTransferSize = payload_size; - return true; -} - -/** Set the minimum, maximum, default values or resolutions to variables which need to negotiate with the host - * - * @param[in] request GET_MAX, GET_MIN, GET_RES or GET_DEF - * @param[in,out] param Target - */ -static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *stm, uint_fast8_t request, - video_probe_and_commit_control_t *param) -{ - uint_fast8_t const fmtnum = param->bFormatIndex; - if (!fmtnum) { - switch (request) { - case VIDEO_REQUEST_GET_MAX: - if (_get_desc_vs(stm)) - param->bFormatIndex = _get_desc_vs(stm)->stm.bNumFormats; - break; - case VIDEO_REQUEST_GET_MIN: - case VIDEO_REQUEST_GET_DEF: - param->bFormatIndex = 1; - break; - default: return false; - } - /* Set the parameters determined by the format */ - param->wKeyFrameRate = 1; - param->wPFrameRate = 0; - param->wCompQuality = 1; /* 1 to 10000 */ - param->wCompWindowSize = 1; /* GOP size? */ - param->wDelay = 0; /* milliseconds */ - param->dwClockFrequency = 27000000; /* same as MPEG-2 system time clock */ - param->bmFramingInfo = 0x3; /* enables FrameID and EndOfFrame */ - param->bPreferedVersion = 1; - param->bMinVersion = 1; - param->bMaxVersion = 1; - param->bUsage = 0; - param->bBitDepthLuma = 8; - return true; - } - - uint_fast8_t frmnum = param->bFrameIndex; - if (!frmnum) { - tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); - TU_ASSERT(vs); - void const *end = _end_of_streaming_descriptor(vs); - tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); - switch (request) { - case VIDEO_REQUEST_GET_MAX: - frmnum = fmt->bNumFrameDescriptors; - break; - case VIDEO_REQUEST_GET_MIN: - frmnum = 1; - break; - case VIDEO_REQUEST_GET_DEF: - switch (fmt->bDescriptorSubType) { - case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED: - frmnum = fmt->uncompressed.bDefaultFrameIndex; - break; - case VIDEO_CS_ITF_VS_FORMAT_MJPEG: - frmnum = fmt->mjpeg.bDefaultFrameIndex; - break; - default: return false; - } - break; - default: return false; - } - param->bFrameIndex = (uint8_t)frmnum; - /* Set the parameters determined by the frame */ - tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); - uint_fast32_t frame_size; - switch (fmt->bDescriptorSubType) { - case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED: - frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->uncompressed.bBitsPerPixel / 8; - break; - case VIDEO_CS_ITF_VS_FORMAT_MJPEG: - frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */ - break; - default: return false; - } - param->dwMaxVideoFrameSize = frame_size; - return true; - } - - if (!param->dwFrameInterval) { - tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); - TU_ASSERT(vs); - void const *end = _end_of_streaming_descriptor(vs); - tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); - tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); - - uint_fast32_t interval, interval_ms; - switch (request) { - case VIDEO_REQUEST_GET_MAX: - { - uint_fast32_t min_interval, max_interval; - uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType; - max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1]; - min_interval = frm->uncompressed.dwFrameInterval[0]; - interval = max_interval; - interval_ms = min_interval / 10000; - } - break; - case VIDEO_REQUEST_GET_MIN: - { - uint_fast32_t min_interval, max_interval; - uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType; - max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1]; - min_interval = frm->uncompressed.dwFrameInterval[0]; - interval = min_interval; - interval_ms = max_interval / 10000; - } - break; - case VIDEO_REQUEST_GET_DEF: - interval = frm->uncompressed.dwDefaultFrameInterval; - interval_ms = interval / 10000; - break; - case VIDEO_REQUEST_GET_RES: - { - uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType; - if (num_intervals) { - interval = 0; - } else { - interval = frm->uncompressed.dwFrameInterval[2]; - interval_ms = interval / 10000; - } - } - break; - default: return false; - } - param->dwFrameInterval = interval; - if (!interval) { - param->dwMaxPayloadTransferSize = 0; - } else { - uint_fast32_t frame_size = param->dwMaxVideoFrameSize; - uint_fast32_t payload_size; - if (!interval_ms) { - payload_size = frame_size + 2; - } else { - payload_size = (frame_size + interval_ms - 1) / interval_ms + 2; - } - if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) - payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE; - param->dwMaxPayloadTransferSize = payload_size; - } - return true; - } - return true; -} - -/** Close current video control interface. - * - * @param[in,out] self Video control interface context. - * @param[in] altnum The target alternate setting number. */ -static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self) -{ - tusb_desc_vc_itf_t const *vc = _get_desc_vc(self); - - /* The next descriptor after the class-specific VC interface header descriptor. */ - void const *cur = (uint8_t const*)vc + vc->std.bLength + vc->ctl.bLength; - - /* The end of the video control interface descriptor. */ - void const *end = _end_of_control_descriptor(vc); - if (vc->std.bNumEndpoints) { - /* Find the notification endpoint descriptor. */ - cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT); - TU_ASSERT(cur < end); - tusb_desc_endpoint_t const *notif = (tusb_desc_endpoint_t const *)cur; - usbd_edpt_close(rhport, notif->bEndpointAddress); - } - self->cur = 0; - return true; -} - -/** Set the alternate setting to own video control interface. - * - * @param[in,out] self Video control interface context. - * @param[in] altnum The target alternate setting number. */ -static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t altnum) -{ - TU_LOG2(" open VC %d\n", altnum); - uint8_t const *beg = self->beg; - uint8_t const *end = beg + self->len; - - /* The first descriptor is a video control interface descriptor. */ - uint8_t const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); - TU_LOG2(" cur %d\n", cur - beg); - TU_VERIFY(cur < end); - - tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const *)cur; - TU_LOG2(" bInCollection %d\n", vc->ctl.bInCollection); - /* Support for up to 2 streaming interfaces only. */ - TU_ASSERT(vc->ctl.bInCollection <= CFG_TUD_VIDEO_STREAMING); - - /* Update to point the end of the video control interface descriptor. */ - end = _end_of_control_descriptor(cur); - - /* Advance to the next descriptor after the class-specific VC interface header descriptor. */ - cur += vc->std.bLength + vc->ctl.bLength; - TU_LOG2(" bNumEndpoints %d\n", vc->std.bNumEndpoints); - /* Open the notification endpoint if it exist. */ - if (vc->std.bNumEndpoints) { - /* Support for 1 endpoint only. */ - TU_VERIFY(1 == vc->std.bNumEndpoints); - /* Find the notification endpoint descriptor. */ - cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT); - TU_VERIFY(cur < end); - tusb_desc_endpoint_t const *notif = (tusb_desc_endpoint_t const *)cur; - /* Open the notification endpoint */ - TU_ASSERT(usbd_edpt_open(rhport, notif)); - } - self->cur = (uint16_t) ((uint8_t const*)vc - beg); - return true; -} - -/** Set the alternate setting to own video streaming interface. - * - * @param[in,out] stm Streaming interface context. - * @param[in] altnum The target alternate setting number. */ -static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint_fast8_t altnum) -{ - uint_fast8_t i; - TU_LOG2(" reopen VS %d\n", altnum); - uint8_t const *desc = _videod_itf[stm->index_vc].beg; - - /* Close endpoints of previous settings. */ - for (i = 0; i < TU_ARRAY_SIZE(stm->desc.ep); ++i) { - uint_fast16_t ofs_ep = stm->desc.ep[i]; - if (!ofs_ep) break; - uint8_t ep_adr = _desc_ep_addr(desc + ofs_ep); - usbd_edpt_close(rhport, ep_adr); - stm->desc.ep[i] = 0; - TU_LOG2(" close EP%02x\n", ep_adr); - } - - /* clear transfer management information */ - stm->buffer = NULL; - stm->bufsize = 0; - stm->offset = 0; - - /* Find a alternate interface */ - uint8_t const *beg = desc + stm->desc.beg; - uint8_t const *end = desc + stm->desc.end; - uint8_t const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); - TU_VERIFY(cur < end); - - uint_fast8_t numeps = ((tusb_desc_interface_t const *)cur)->bNumEndpoints; - TU_ASSERT(numeps <= TU_ARRAY_SIZE(stm->desc.ep)); - stm->desc.cur = (uint16_t) (cur - desc); /* Save the offset of the new settings */ - if (!altnum) { - /* initialize streaming settings */ - stm->max_payload_transfer_size = 0; - video_probe_and_commit_control_t *param = - (video_probe_and_commit_control_t *)&stm->ep_buf; - tu_memclr(param, sizeof(*param)); - TU_LOG2(" done 0\n"); - return _update_streaming_parameters(stm, param); - } - /* Open endpoints of the new settings. */ - for (i = 0, cur = tu_desc_next(cur); i < numeps; ++i, cur = tu_desc_next(cur)) { - cur = _find_desc_ep(cur, end); - TU_ASSERT(cur < end); - tusb_desc_endpoint_t const *ep = (tusb_desc_endpoint_t const*)cur; - if (!stm->max_payload_transfer_size) { - video_probe_and_commit_control_t const *param = (video_probe_and_commit_control_t const*)&stm->ep_buf; - uint_fast32_t max_size = param->dwMaxPayloadTransferSize; - if ((TUSB_XFER_ISOCHRONOUS == ep->bmAttributes.xfer) && - (tu_edpt_packet_size(ep) < max_size)) - { - /* FS must be less than or equal to max packet size */ - return false; - } - /* Set the negotiated value */ - stm->max_payload_transfer_size = max_size; - } - TU_ASSERT(usbd_edpt_open(rhport, ep)); - stm->desc.ep[i] = (uint16_t) (cur - desc); - TU_LOG2(" open EP%02x\n", _desc_ep_addr(cur)); - } - /* initialize payload header */ - tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf; - hdr->bHeaderLength = sizeof(*hdr); - hdr->bmHeaderInfo = 0; - - TU_LOG2(" done\n"); - return true; -} - -/** Prepare the next packet payload. */ -static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm) -{ - uint_fast16_t remaining = stm->bufsize - stm->offset; - uint_fast16_t hdr_len = stm->ep_buf[0]; - uint_fast16_t pkt_len = stm->max_payload_transfer_size; - if (hdr_len + remaining < pkt_len) { - pkt_len = hdr_len + remaining; - } - uint_fast16_t data_len = pkt_len - hdr_len; - memcpy(&stm->ep_buf[hdr_len], stm->buffer + stm->offset, data_len); - stm->offset += data_len; - remaining -= data_len; - if (!remaining) { - tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf; - hdr->EndOfFrame = 1; - } - return hdr_len + data_len; -} - -/** Handle a standard request to the video control interface. */ -static int handle_video_ctl_std_req(uint8_t rhport, uint8_t stage, - tusb_control_request_t const *request, - uint_fast8_t ctl_idx) -{ - switch (request->bRequest) { - case TUSB_REQ_GET_INTERFACE: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); - tusb_desc_vc_itf_t const *vc = _get_desc_vc(&_videod_itf[ctl_idx]); - TU_VERIFY(vc, VIDEO_ERROR_UNKNOWN); - - uint8_t alt_num = vc->std.bAlternateSetting; - - TU_VERIFY(tud_control_xfer(rhport, request, &alt_num, sizeof(alt_num)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case TUSB_REQ_SET_INTERFACE: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(0 == request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(_close_vc_itf(rhport, &_videod_itf[ctl_idx]), VIDEO_ERROR_UNKNOWN); - TU_VERIFY(_open_vc_itf(rhport, &_videod_itf[ctl_idx], request->wValue), VIDEO_ERROR_UNKNOWN); - tud_control_status(rhport, request); - } - return VIDEO_ERROR_NONE; - - default: /* Unknown/Unsupported request */ - TU_BREAKPOINT(); - return VIDEO_ERROR_INVALID_REQUEST; - } -} - -static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage, - tusb_control_request_t const *request, - uint_fast8_t ctl_idx) -{ - videod_interface_t *self = &_videod_itf[ctl_idx]; - - /* 4.2.1 Interface Control Request */ - switch (TU_U16_HIGH(request->wValue)) { - case VIDEO_VC_CTL_VIDEO_POWER_MODE: - switch (request->bRequest) { - case VIDEO_REQUEST_SET_CUR: - if (stage == CONTROL_STAGE_SETUP) { - TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, &self->power_mode, sizeof(self->power_mode)), VIDEO_ERROR_UNKNOWN); - } else if (stage == CONTROL_STAGE_DATA) { - if (tud_video_power_mode_cb) return tud_video_power_mode_cb(ctl_idx, self->power_mode); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_CUR: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, &self->power_mode, sizeof(self->power_mode)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_INFO: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - default: break; - } - break; - - case VIDEO_VC_CTL_REQUEST_ERROR_CODE: - switch (request->bRequest) { - case VIDEO_REQUEST_GET_CUR: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(tud_control_xfer(rhport, request, &self->error_code, sizeof(uint8_t)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_INFO: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get, sizeof(_cap_get)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - default: break; - } - break; - - default: break; - } - - /* Unknown/Unsupported request */ - TU_BREAKPOINT(); - return VIDEO_ERROR_INVALID_REQUEST; -} - -static int handle_video_ctl_req(uint8_t rhport, uint8_t stage, - tusb_control_request_t const *request, - uint_fast8_t ctl_idx) -{ - uint_fast8_t entity_id; - switch (request->bmRequestType_bit.type) { - case TUSB_REQ_TYPE_STANDARD: - return handle_video_ctl_std_req(rhport, stage, request, ctl_idx); - - case TUSB_REQ_TYPE_CLASS: - entity_id = TU_U16_HIGH(request->wIndex); - if (!entity_id) { - return handle_video_ctl_cs_req(rhport, stage, request, ctl_idx); - } else { - TU_VERIFY(_find_desc_entity(_get_desc_vc(&_videod_itf[ctl_idx]), entity_id), VIDEO_ERROR_INVALID_REQUEST); - return VIDEO_ERROR_NONE; - } - - default: - return VIDEO_ERROR_INVALID_REQUEST; - } -} - -static int handle_video_stm_std_req(uint8_t rhport, uint8_t stage, - tusb_control_request_t const *request, - uint_fast8_t stm_idx) -{ - videod_streaming_interface_t *self = &_videod_streaming_itf[stm_idx]; - switch (request->bRequest) { - case TUSB_REQ_GET_INTERFACE: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); - tusb_desc_vs_itf_t const *vs = _get_desc_vs(self); - TU_VERIFY(vs, VIDEO_ERROR_UNKNOWN); - uint8_t alt_num = vs->std.bAlternateSetting; - - TU_VERIFY(tud_control_xfer(rhport, request, &alt_num, sizeof(alt_num)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case TUSB_REQ_SET_INTERFACE: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(_open_vs_itf(rhport, self, request->wValue), VIDEO_ERROR_UNKNOWN); - tud_control_status(rhport, request); - } - return VIDEO_ERROR_NONE; - - default: /* Unknown/Unsupported request */ - TU_BREAKPOINT(); - return VIDEO_ERROR_INVALID_REQUEST; - } -} - -static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, - tusb_control_request_t const *request, - uint_fast8_t stm_idx) -{ - (void)rhport; - videod_streaming_interface_t *self = &_videod_streaming_itf[stm_idx]; - - /* 4.2.1 Interface Control Request */ - switch (TU_U16_HIGH(request->wValue)) { - case VIDEO_VS_CTL_STREAM_ERROR_CODE: - switch (request->bRequest) { - case VIDEO_REQUEST_GET_CUR: - if (stage == CONTROL_STAGE_SETUP) - { - /* TODO */ - TU_VERIFY(tud_control_xfer(rhport, request, &self->error_code, sizeof(uint8_t)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_INFO: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get, sizeof(_cap_get)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - default: break; - } - break; - - case VIDEO_VS_CTL_PROBE: - switch (request->bRequest) { - case VIDEO_REQUEST_SET_CUR: - if (stage == CONTROL_STAGE_SETUP) { - TU_VERIFY(sizeof(video_probe_and_commit_control_t) >= request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), - VIDEO_ERROR_UNKNOWN); - } else if (stage == CONTROL_STAGE_DATA) { - TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf), - VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_CUR: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_MIN: - case VIDEO_REQUEST_GET_MAX: - case VIDEO_REQUEST_GET_RES: - case VIDEO_REQUEST_GET_DEF: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN); - video_probe_and_commit_control_t tmp; - tmp = *(video_probe_and_commit_control_t*)&self->ep_buf; - TU_VERIFY(_negotiate_streaming_parameters(self, request->bRequest, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); - TU_VERIFY(tud_control_xfer(rhport, request, &tmp, sizeof(tmp)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_LEN: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN); - uint16_t len = sizeof(video_probe_and_commit_control_t); - TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_INFO: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t)&_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - default: break; - } - break; - - case VIDEO_VS_CTL_COMMIT: - switch (request->bRequest) { - case VIDEO_REQUEST_SET_CUR: - if (stage == CONTROL_STAGE_SETUP) { - TU_VERIFY(sizeof(video_probe_and_commit_control_t) >= request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); - } else if (stage == CONTROL_STAGE_DATA) { - TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); - if (tud_video_commit_cb) { - return tud_video_commit_cb(self->index_vc, self->index_vs, (video_probe_and_commit_control_t*)self->ep_buf); - } - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_CUR: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_LEN: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN); - uint16_t len = sizeof(video_probe_and_commit_control_t); - TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_INFO: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); - TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - default: break; - } - break; - - case VIDEO_VS_CTL_STILL_PROBE: - case VIDEO_VS_CTL_STILL_COMMIT: - case VIDEO_VS_CTL_STILL_IMAGE_TRIGGER: - case VIDEO_VS_CTL_GENERATE_KEY_FRAME: - case VIDEO_VS_CTL_UPDATE_FRAME_SEGMENT: - case VIDEO_VS_CTL_SYNCH_DELAY_CONTROL: - /* TODO */ - break; - - default: break; - } - - /* Unknown/Unsupported request */ - TU_BREAKPOINT(); - return VIDEO_ERROR_INVALID_REQUEST; -} - -static int handle_video_stm_req(uint8_t rhport, uint8_t stage, - tusb_control_request_t const *request, - uint_fast8_t stm_idx) -{ - switch (request->bmRequestType_bit.type) { - case TUSB_REQ_TYPE_STANDARD: - return handle_video_stm_std_req(rhport, stage, request, stm_idx); - - case TUSB_REQ_TYPE_CLASS: - if (TU_U16_HIGH(request->wIndex)) return VIDEO_ERROR_INVALID_REQUEST; - return handle_video_stm_cs_req(rhport, stage, request, stm_idx); - - default: return VIDEO_ERROR_INVALID_REQUEST; - } -} - -//--------------------------------------------------------------------+ -// APPLICATION API -//--------------------------------------------------------------------+ - -bool tud_video_n_connected(uint_fast8_t ctl_idx) -{ - TU_ASSERT(ctl_idx < CFG_TUD_VIDEO); - videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, 0); - if (stm) return true; - return false; -} - -bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) -{ - TU_ASSERT(ctl_idx < CFG_TUD_VIDEO); - TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING); - videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx); - if (!stm || !stm->desc.ep[0]) return false; - return true; -} - -bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *buffer, size_t bufsize) -{ - TU_ASSERT(ctl_idx < CFG_TUD_VIDEO); - TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING); - if (!buffer || !bufsize) return false; - videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx); - if (!stm || !stm->desc.ep[0] || stm->buffer) return false; - - /* Find EP address */ - uint8_t const *desc = _videod_itf[stm->index_vc].beg; - uint8_t ep_addr = 0; - for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { - uint_fast16_t ofs_ep = stm->desc.ep[i]; - if (!ofs_ep) continue; - ep_addr = _desc_ep_addr(desc + ofs_ep); - break; - } - if (!ep_addr) return false; - - TU_VERIFY( usbd_edpt_claim(0, ep_addr) ); - /* update the packet header */ - tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf; - hdr->FrameID ^= 1; - hdr->EndOfFrame = 0; - /* update the packet data */ - stm->buffer = (uint8_t*)buffer; - stm->bufsize = bufsize; - uint_fast16_t pkt_len = _prepare_in_payload(stm); - TU_ASSERT( usbd_edpt_xfer(0, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0); - return true; -} - -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void videod_init(void) -{ - for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) { - videod_interface_t* ctl = &_videod_itf[i]; - tu_memclr(ctl, sizeof(*ctl)); - } - for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { - videod_streaming_interface_t *stm = &_videod_streaming_itf[i]; - tu_memclr(stm, ITF_STM_MEM_RESET_SIZE); - } -} - -void videod_reset(uint8_t rhport) -{ - (void) rhport; - for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) { - videod_interface_t* ctl = &_videod_itf[i]; - tu_memclr(ctl, sizeof(*ctl)); - } - for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { - videod_streaming_interface_t *stm = &_videod_streaming_itf[i]; - tu_memclr(stm, ITF_STM_MEM_RESET_SIZE); - } -} - -uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ - TU_VERIFY((TUSB_CLASS_VIDEO == itf_desc->bInterfaceClass) && - (VIDEO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass) && - (VIDEO_ITF_PROTOCOL_15 == itf_desc->bInterfaceProtocol), 0); - - /* Find available interface */ - videod_interface_t *self = NULL; - uint8_t ctl_idx; - for (ctl_idx = 0; ctl_idx < CFG_TUD_VIDEO; ++ctl_idx) { - if (_videod_itf[ctl_idx].beg) continue; - self = &_videod_itf[ctl_idx]; - break; - } - TU_ASSERT(ctl_idx < CFG_TUD_VIDEO, 0); - - uint8_t const *end = (uint8_t const*)itf_desc + max_len; - self->beg = (uint8_t const*) itf_desc; - self->len = max_len; - - /*------------- Video Control Interface -------------*/ - TU_VERIFY(_open_vc_itf(rhport, self, 0), 0); - tusb_desc_vc_itf_t const *vc = _get_desc_vc(self); - uint_fast8_t bInCollection = vc->ctl.bInCollection; - - /* Find the end of the video interface descriptor */ - void const *cur = _next_desc_itf(itf_desc, end); - for (uint8_t stm_idx = 0; stm_idx < bInCollection; ++stm_idx) { - videod_streaming_interface_t *stm = NULL; - /* find free streaming interface handle */ - for (uint8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) { - if (_videod_streaming_itf[i].desc.beg) continue; - stm = &_videod_streaming_itf[i]; - self->stm[stm_idx] = i; - break; - } - TU_ASSERT(stm, 0); - stm->index_vc = ctl_idx; - stm->index_vs = stm_idx; - stm->desc.beg = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); - cur = _next_desc_itf(cur, end); - stm->desc.end = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); - } - self->len = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); - return (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); -} - -// Invoked when a control transfer occurred on an interface of this class -// Driver response accordingly to the request and the transfer stage (setup/data/ack) -// return false to stall control endpoint (e.g unsupported request) -bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - int err; - TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); - uint_fast8_t itfnum = tu_u16_low(request->wIndex); - - /* Identify which control interface to use */ - uint_fast8_t itf; - for (itf = 0; itf < CFG_TUD_VIDEO; ++itf) { - void const *desc = _videod_itf[itf].beg; - if (!desc) continue; - if (itfnum == _desc_itfnum(desc)) break; - } - - if (itf < CFG_TUD_VIDEO) { - err = handle_video_ctl_req(rhport, stage, request, itf); - _videod_itf[itf].error_code = (uint8_t)err; - if (err) return false; - return true; - } - - /* Identify which streaming interface to use */ - for (itf = 0; itf < CFG_TUD_VIDEO_STREAMING; ++itf) { - videod_streaming_interface_t *stm = &_videod_streaming_itf[itf]; - if (!stm->desc.beg) continue; - uint8_t const *desc = _videod_itf[stm->index_vc].beg; - if (itfnum == _desc_itfnum(desc + stm->desc.beg)) break; - } - - if (itf < CFG_TUD_VIDEO_STREAMING) { - err = handle_video_stm_req(rhport, stage, request, itf); - _videod_streaming_itf[itf].error_code = (uint8_t)err; - if (err) return false; - return true; - } - return false; -} - -bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void)result; (void)xferred_bytes; - - /* find streaming handle */ - uint_fast8_t itf; - videod_interface_t *ctl; - videod_streaming_interface_t *stm; - for (itf = 0; itf < CFG_TUD_VIDEO_STREAMING; ++itf) { - stm = &_videod_streaming_itf[itf]; - uint_fast16_t const ep_ofs = stm->desc.ep[0]; - if (!ep_ofs) continue; - ctl = &_videod_itf[stm->index_vc]; - uint8_t const *desc = ctl->beg; - if (ep_addr == _desc_ep_addr(desc + ep_ofs)) break; - } - - TU_ASSERT(itf < CFG_TUD_VIDEO_STREAMING); - if (stm->offset < stm->bufsize) { - /* Claim the endpoint */ - TU_VERIFY( usbd_edpt_claim(rhport, ep_addr), 0); - uint_fast16_t pkt_len = _prepare_in_payload(stm); - TU_ASSERT( usbd_edpt_xfer(rhport, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0); - } else { - stm->buffer = NULL; - stm->bufsize = 0; - stm->offset = 0; - if (tud_video_frame_xfer_complete_cb) { - tud_video_frame_xfer_complete_cb(stm->index_vc, stm->index_vs); - } - } - return true; -} - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.h b/test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.h deleted file mode 100644 index ee2fcb9d..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/class/video/video_device.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * Copyright (c) 2021 Koji KITAYAMA - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef TUSB_VIDEO_DEVICE_H_ -#define TUSB_VIDEO_DEVICE_H_ - -#include "common/tusb_common.h" -#include "video.h" - -#ifdef __cplusplus -extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Application API (Multiple Ports) -// CFG_TUD_VIDEO > 1 -//--------------------------------------------------------------------+ - -/** Return true if streaming - * - * @param[in] ctl_idx Destination control interface index - * @param[in] stm_idx Destination streaming interface index */ -bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx); - -/** Transfer a frame - * - * @param[in] ctl_idx Destination control interface index - * @param[in] stm_idx Destination streaming interface index - * @param[in] buffer Frame buffer. The caller must not use this buffer until the operation is completed. - * @param[in] bufsize Byte size of the frame buffer */ -bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *buffer, size_t bufsize); - -/*------------- Optional callbacks -------------*/ -/** Invoked when compeletion of a frame transfer - * - * @param[in] ctl_idx Destination control interface index - * @param[in] stm_idx Destination streaming interface index */ -TU_ATTR_WEAK void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx); - -//--------------------------------------------------------------------+ -// Application Callback API (weak is optional) -//--------------------------------------------------------------------+ - -/** Invoked when SET_POWER_MODE request received - * - * @param[in] ctl_idx Destination control interface index - * @param[in] stm_idx Destination streaming interface index - * @return video_error_code_t */ -TU_ATTR_WEAK int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod); - -/** Invoked when VS_COMMIT_CONTROL(SET_CUR) request received - * - * @param[in] ctl_idx Destination control interface index - * @param[in] stm_idx Destination streaming interface index - * @param[in] parameters Video streaming parameters - * @return video_error_code_t */ -TU_ATTR_WEAK int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, - video_probe_and_commit_control_t const *parameters); - -//--------------------------------------------------------------------+ -// INTERNAL USBD-CLASS DRIVER API -//--------------------------------------------------------------------+ -void videod_init (void); -void videod_reset (uint8_t rhport); -uint16_t videod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -bool videod_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_common.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_common.h index 957491aa..0d4082c0 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_common.h +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_common.h @@ -37,6 +37,7 @@ #define TU_ARRAY_SIZE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) ) #define TU_MIN(_x, _y) ( ( (_x) < (_y) ) ? (_x) : (_y) ) #define TU_MAX(_x, _y) ( ( (_x) > (_y) ) ? (_x) : (_y) ) +#define TU_DIV_CEIL(n, d) (((n) + (d) - 1) / (d)) #define TU_U16(_high, _low) ((uint16_t) (((_high) << 8) | (_low))) #define TU_U16_HIGH(_u16) ((uint8_t) (((_u16) >> 8) & 0x00ff)) @@ -53,6 +54,8 @@ #define U32_TO_U8S_LE(_u32) TU_U32_BYTE0(_u32), TU_U32_BYTE1(_u32), TU_U32_BYTE2(_u32), TU_U32_BYTE3(_u32) #define TU_BIT(n) (1UL << (n)) + +// Generate a mask with bit from high (31) to low (0) set, e.g TU_GENMASK(3, 0) = 0b1111 #define TU_GENMASK(h, l) ( (UINT32_MAX << (l)) & (UINT32_MAX >> (31 - (h))) ) //--------------------------------------------------------------------+ @@ -62,6 +65,7 @@ // Standard Headers #include #include +#include #include #include #include @@ -73,8 +77,6 @@ #include "tusb_types.h" #include "tusb_debug.h" -#include "tusb_timeout.h" // TODO remove - //--------------------------------------------------------------------+ // Optional API implemented by application if needed // TODO move to a more ovious place/file @@ -99,10 +101,9 @@ TU_ATTR_WEAK extern void* tusb_app_phys_to_virt(void *phys_addr); #define tu_varclr(_var) tu_memclr(_var, sizeof(*(_var))) // This is a backport of memset_s from c11 -TU_ATTR_ALWAYS_INLINE static inline int tu_memset_s(void *dest, size_t destsz, int ch, size_t count) -{ +TU_ATTR_ALWAYS_INLINE static inline int tu_memset_s(void *dest, size_t destsz, int ch, size_t count) { // TODO may check if desst and src is not NULL - if (count > destsz) { + if ( count > destsz ) { return -1; } memset(dest, ch, count); @@ -110,10 +111,9 @@ TU_ATTR_ALWAYS_INLINE static inline int tu_memset_s(void *dest, size_t destsz, i } // This is a backport of memcpy_s from c11 -TU_ATTR_ALWAYS_INLINE static inline int tu_memcpy_s(void *dest, size_t destsz, const void * src, size_t count ) -{ +TU_ATTR_ALWAYS_INLINE static inline int tu_memcpy_s(void *dest, size_t destsz, const void *src, size_t count) { // TODO may check if desst and src is not NULL - if (count > destsz) { + if ( count > destsz ) { return -1; } memcpy(dest, src, count); @@ -122,13 +122,11 @@ TU_ATTR_ALWAYS_INLINE static inline int tu_memcpy_s(void *dest, size_t destsz, c //------------- Bytes -------------// -TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_u32(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_u32(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0) { return ( ((uint32_t) b3) << 24) | ( ((uint32_t) b2) << 16) | ( ((uint32_t) b1) << 8) | b0; } -TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u16(uint8_t high, uint8_t low) -{ +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u16(uint8_t high, uint8_t low) { return (uint16_t) ((((uint16_t) high) << 8) | low); } @@ -159,16 +157,20 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_max16 (uint16_t x, uint16_t y) { TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_max32 (uint32_t x, uint32_t y) { return (x > y) ? x : y; } //------------- Align -------------// -TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align(uint32_t value, uint32_t alignment) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align(uint32_t value, uint32_t alignment) { return value & ((uint32_t) ~(alignment-1)); } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align4 (uint32_t value) { return (value & 0xFFFFFFFCUL); } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align8 (uint32_t value) { return (value & 0xFFFFFFF8UL); } TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align16 (uint32_t value) { return (value & 0xFFFFFFF0UL); } TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align32 (uint32_t value) { return (value & 0xFFFFFFE0UL); } TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align4k (uint32_t value) { return (value & 0xFFFFF000UL); } TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_offset4k(uint32_t value) { return (value & 0xFFFUL); } +TU_ATTR_ALWAYS_INLINE static inline bool tu_is_aligned32(uint32_t value) { return (value & 0x1FUL) == 0; } +TU_ATTR_ALWAYS_INLINE static inline bool tu_is_aligned64(uint64_t value) { return (value & 0x3FUL) == 0; } + //------------- Mathematics -------------// TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_div_ceil(uint32_t v, uint32_t d) { return (v + d -1)/d; } @@ -260,11 +262,21 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void* mem, uint16_ #else // MCU that could access unaligned memory natively -TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32 (const void* mem) { return *((uint32_t const *) mem); } -TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16 (const void* mem) { return *((uint16_t const *) mem); } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32(const void *mem) { + return *((uint32_t const *) mem); +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16(const void *mem) { + return *((uint16_t const *) mem); +} -TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32 (void* mem, uint32_t value ) { *((uint32_t*) mem) = value; } -TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16 (void* mem, uint16_t value ) { *((uint16_t*) mem) = value; } +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32(void *mem, uint32_t value) { + *((uint32_t *) mem) = value; +} + +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void *mem, uint16_t value) { + *((uint16_t *) mem) = value; +} #endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_compiler.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_compiler.h index 5ab56e14..0d5570b1 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_compiler.h +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_compiler.h @@ -56,7 +56,7 @@ #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L #define TU_VERIFY_STATIC _Static_assert #elif defined(__CCRX__) - #define TU_VERIFY_STATIC(const_expr, _mess) typedef char TU_XSTRCAT(Line, __LINE__)[(const_expr) ? 1 : 0]; + #define TU_VERIFY_STATIC(const_expr, _mess) typedef char TU_XSTRCAT(_verify_static_, _TU_COUNTER_)[(const_expr) ? 1 : 0]; #else #define TU_VERIFY_STATIC(const_expr, _mess) enum { TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1/(!!(const_expr)) } #endif @@ -128,7 +128,9 @@ #define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name))) #define TU_ATTR_PACKED __attribute__ ((packed)) #define TU_ATTR_WEAK __attribute__ ((weak)) - #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) + #ifndef TU_ATTR_ALWAYS_INLINE // allow to override for debug + #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) + #endif #define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used #define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused #define TU_ATTR_USED __attribute__ ((used)) // Function/Variable is meant to be used @@ -205,7 +207,9 @@ #define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name))) #define TU_ATTR_PACKED __attribute__ ((packed)) #define TU_ATTR_WEAK __attribute__ ((weak)) - #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) + #ifndef TU_ATTR_ALWAYS_INLINE // allow to override for debug + #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) + #endif #define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used #define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused #define TU_ATTR_USED __attribute__ ((used)) // Function/Variable is meant to be used diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_debug.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_debug.h index 82f68204..2e9f1d9c 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_debug.h +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_debug.h @@ -43,9 +43,10 @@ #if CFG_TUSB_DEBUG // Enum to String for debugging purposes -#if CFG_TUSB_DEBUG >= 2 +#if CFG_TUSB_DEBUG >= CFG_TUH_LOG_LEVEL || CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL extern char const* const tu_str_speed[]; extern char const* const tu_str_std_request[]; +extern char const* const tu_str_xfer_result[]; #endif void tu_print_mem(void const *buf, uint32_t count, uint8_t indent); @@ -57,16 +58,15 @@ void tu_print_mem(void const *buf, uint32_t count, uint8_t indent); #define tu_printf printf #endif -static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) -{ +static inline void tu_print_buf(uint8_t const* buf, uint32_t bufsize) { for(uint32_t i=0; i= 2 #define TU_LOG2 TU_LOG1 #define TU_LOG2_MEM TU_LOG1_MEM - #define TU_LOG2_ARR TU_LOG1_ARR - #define TU_LOG2_PTR TU_LOG1_PTR + #define TU_LOG2_BUF TU_LOG1_BUF #define TU_LOG2_INT TU_LOG1_INT #define TU_LOG2_HEX TU_LOG1_HEX #endif @@ -94,30 +92,25 @@ static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) #if CFG_TUSB_DEBUG >= 3 #define TU_LOG3 TU_LOG1 #define TU_LOG3_MEM TU_LOG1_MEM - #define TU_LOG3_ARR TU_LOG1_ARR - #define TU_LOG3_PTR TU_LOG1_PTR + #define TU_LOG3_BUF TU_LOG1_BUF #define TU_LOG3_INT TU_LOG1_INT #define TU_LOG3_HEX TU_LOG1_HEX #endif -typedef struct -{ +typedef struct { uint32_t key; const char* data; } tu_lookup_entry_t; -typedef struct -{ +typedef struct { uint16_t count; tu_lookup_entry_t const* items; } tu_lookup_table_t; -static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) -{ +static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) { tu_static char not_found[11]; - for(uint16_t i=0; icount; i++) - { + for(uint16_t i=0; icount; i++) { if (p_table->items[i].key == key) return p_table->items[i].data; } @@ -132,7 +125,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG #define TU_LOG(n, ...) #define TU_LOG_MEM(n, ...) - #define TU_LOG_PTR(n, ...) + #define TU_LOG_BUF(n, ...) #define TU_LOG_INT(n, ...) #define TU_LOG_HEX(n, ...) #define TU_LOG_LOCATION() @@ -143,14 +136,14 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #define TU_LOG0(...) #define TU_LOG0_MEM(...) -#define TU_LOG0_PTR(...) +#define TU_LOG0_BUF(...) #define TU_LOG0_INT(...) #define TU_LOG0_HEX(...) #ifndef TU_LOG1 #define TU_LOG1(...) #define TU_LOG1_MEM(...) - #define TU_LOG1_PTR(...) + #define TU_LOG1_BUF(...) #define TU_LOG1_INT(...) #define TU_LOG1_HEX(...) #endif @@ -158,7 +151,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG2 #define TU_LOG2(...) #define TU_LOG2_MEM(...) - #define TU_LOG2_PTR(...) + #define TU_LOG2_BUF(...) #define TU_LOG2_INT(...) #define TU_LOG2_HEX(...) #endif @@ -166,7 +159,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG3 #define TU_LOG3(...) #define TU_LOG3_MEM(...) - #define TU_LOG3_PTR(...) + #define TU_LOG3_BUF(...) #define TU_LOG3_INT(...) #define TU_LOG3_HEX(...) #endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.c b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.c index a52c9226..76696396 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.c +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.c @@ -224,6 +224,7 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t if (wrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, wrap_bytes); } break; + default: break; } } @@ -539,7 +540,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu // Advance index f->wr_idx = advance_index(f->depth, wr_idx, n); - TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\n", f->wr_idx); + TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\r\n", f->wr_idx); } _ff_unlock(f->mutex_wr); diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.h index 2f60ec2f..2d9f5e66 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.h +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_fifo.h @@ -102,10 +102,8 @@ extern "C" { * | * ------------------------- * | R | 1 | 2 | W | 4 | 5 | - */ -typedef struct -{ +typedef struct { uint8_t* buffer ; // buffer pointer uint16_t depth ; // max items @@ -124,16 +122,14 @@ typedef struct } tu_fifo_t; -typedef struct -{ +typedef struct { uint16_t len_lin ; ///< linear length in item size uint16_t len_wrap ; ///< wrapped length in item size void * ptr_lin ; ///< linear part start pointer void * ptr_wrap ; ///< wrapped part start pointer } tu_fifo_buffer_info_t; -#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable) \ -{ \ +#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable){\ .buffer = _buffer, \ .depth = _depth, \ .item_size = sizeof(_type), \ @@ -144,23 +140,18 @@ typedef struct uint8_t _name##_buf[_depth*sizeof(_type)]; \ tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _type, _overwritable) - bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable); bool tu_fifo_clear(tu_fifo_t *f); bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable); #if OSAL_MUTEX_REQUIRED -TU_ATTR_ALWAYS_INLINE static inline -void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_mutex) -{ - f->mutex_wr = wr_mutex; - f->mutex_rd = rd_mutex; -} - + TU_ATTR_ALWAYS_INLINE static inline + void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_mutex) { + f->mutex_wr = wr_mutex; + f->mutex_rd = rd_mutex; + } #else - -#define tu_fifo_config_mutex(_f, _wr_mutex, _rd_mutex) - + #define tu_fifo_config_mutex(_f, _wr_mutex, _rd_mutex) #endif bool tu_fifo_write (tu_fifo_t* f, void const * p_data); @@ -182,8 +173,7 @@ bool tu_fifo_overflowed (tu_fifo_t* f); void tu_fifo_correct_read_pointer (tu_fifo_t* f); TU_ATTR_ALWAYS_INLINE static inline -uint16_t tu_fifo_depth(tu_fifo_t* f) -{ +uint16_t tu_fifo_depth(tu_fifo_t* f) { return f->depth; } @@ -198,7 +188,6 @@ void tu_fifo_advance_read_pointer (tu_fifo_t *f, uint16_t n); void tu_fifo_get_read_info (tu_fifo_t *f, tu_fifo_buffer_info_t *info); void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info); - #ifdef __cplusplus } #endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_mcu.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_mcu.h index ba8976a8..5a567f2d 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_mcu.h +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_mcu.h @@ -34,10 +34,16 @@ //------------- Unaligned Memory Access -------------// -// ARMv7+ (M3-M7, M23-M33) can access unaligned memory -#if (defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) - #define TUP_ARCH_STRICT_ALIGN 0 +#ifdef __ARM_ARCH + // ARM Architecture set __ARM_FEATURE_UNALIGNED to 1 for mcu supports unaligned access + #if defined(__ARM_FEATURE_UNALIGNED) && __ARM_FEATURE_UNALIGNED == 1 + #define TUP_ARCH_STRICT_ALIGN 0 + #else + #define TUP_ARCH_STRICT_ALIGN 1 + #endif #else + // TODO default to strict align for others + // Should investigate other architecture such as risv, xtensa, mips for optimal setting #define TUP_ARCH_STRICT_ALIGN 1 #endif @@ -52,6 +58,7 @@ // NXP //--------------------------------------------------------------------+ #if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX) + #define TUP_USBIP_IP3511 #define TUP_DCD_ENDPOINT_MAX 5 #elif TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX) @@ -59,33 +66,55 @@ #define TUP_USBIP_OHCI #define TUP_OHCI_RHPORTS 2 -#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX) - // TODO USB0 has 6, USB1 has 4 - #define TUP_USBIP_CHIPIDEA_HS - #define TUP_USBIP_EHCI - - #define TUP_DCD_ENDPOINT_MAX 6 - #define TUP_RHPORT_HIGHSPEED 1 // Port0 HS, Port1 FS - #elif TU_CHECK_MCU(OPT_MCU_LPC51UXX) + #define TUP_USBIP_IP3511 #define TUP_DCD_ENDPOINT_MAX 5 -#elif TU_CHECK_MCU(OPT_MCU_LPC54XXX) +#elif TU_CHECK_MCU(OPT_MCU_LPC54) // TODO USB0 has 5, USB1 has 6 + #define TUP_USBIP_IP3511 #define TUP_DCD_ENDPOINT_MAX 6 -#elif TU_CHECK_MCU(OPT_MCU_LPC55XX) +#elif TU_CHECK_MCU(OPT_MCU_LPC55) // TODO USB0 has 5, USB1 has 6 + #define TUP_USBIP_IP3511 #define TUP_DCD_ENDPOINT_MAX 6 -#elif TU_CHECK_MCU(OPT_MCU_MIMXRT) +#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX) + // USB0 has 6 with HS PHY, USB1 has 4 only FS + #define TUP_USBIP_CHIPIDEA_HS + #define TUP_USBIP_EHCI + + #define TUP_DCD_ENDPOINT_MAX 6 + #define TUP_RHPORT_HIGHSPEED 1 + +#elif TU_CHECK_MCU(OPT_MCU_MCXN9) + // USB0 is chipidea FS + #define TUP_USBIP_CHIPIDEA_FS + #define TUP_USBIP_CHIPIDEA_FS_MCX + + // USB1 is chipidea HS + #define TUP_USBIP_CHIPIDEA_HS + #define TUP_USBIP_EHCI + + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_RHPORT_HIGHSPEED 1 + +#elif TU_CHECK_MCU(OPT_MCU_MCXA15) + // USB0 is chipidea FS + #define TUP_USBIP_CHIPIDEA_FS + #define TUP_USBIP_CHIPIDEA_FS_MCX + + #define TUP_DCD_ENDPOINT_MAX 16 + +#elif TU_CHECK_MCU(OPT_MCU_MIMXRT1XXX) #define TUP_USBIP_CHIPIDEA_HS #define TUP_USBIP_EHCI #define TUP_DCD_ENDPOINT_MAX 8 - #define TUP_RHPORT_HIGHSPEED 1 // Port0 HS, Port1 HS + #define TUP_RHPORT_HIGHSPEED 1 -#elif TU_CHECK_MCU(OPT_MCU_KINETIS_KL, OPT_MCU_KINETIS_K32) +#elif TU_CHECK_MCU(OPT_MCU_KINETIS_KL, OPT_MCU_KINETIS_K32L, OPT_MCU_KINETIS_K) #define TUP_USBIP_CHIPIDEA_FS #define TUP_USBIP_CHIPIDEA_FS_KINETIS #define TUP_DCD_ENDPOINT_MAX 16 @@ -188,7 +217,22 @@ #define TUP_DCD_ENDPOINT_MAX 9 +#elif TU_CHECK_MCU(OPT_MCU_STM32H5) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 + #define TUP_DCD_ENDPOINT_MAX 8 + #elif TU_CHECK_MCU(OPT_MCU_STM32G4) + // Device controller + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 + + // TypeC controller + #define TUP_USBIP_TYPEC_STM32 + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_TYPEC_RHPORTS_NUM 1 + +#elif TU_CHECK_MCU(OPT_MCU_STM32G0) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 @@ -227,14 +271,21 @@ #elif TU_CHECK_MCU(OPT_MCU_STM32U5) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 - #define TUP_DCD_ENDPOINT_MAX 6 + + // U59x/5Ax/5Fx/5Gx are highspeed with built-in HS PHY + #if defined(STM32U595xx) || defined(STM32U599xx) || defined(STM32U5A5xx) || defined(STM32U5A9xx) || \ + defined(STM32U5F7xx) || defined(STM32U5F9xx) || defined(STM32U5G7xx) || defined(STM32U5G9xx) + #define TUP_DCD_ENDPOINT_MAX 9 + #define TUP_RHPORT_HIGHSPEED 1 + #else + #define TUP_DCD_ENDPOINT_MAX 6 + #endif #elif TU_CHECK_MCU(OPT_MCU_STM32L5) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 #define TUP_DCD_ENDPOINT_MAX 8 - //--------------------------------------------------------------------+ // Sony //--------------------------------------------------------------------+ @@ -278,6 +329,9 @@ #define TUP_USBIP_DWC2 #define TUP_DCD_ENDPOINT_MAX 6 +#elif TU_CHECK_MCU(OPT_MCU_ESP32) && (CFG_TUD_ENABLED || !(defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421)) + #error "MCUs are only supported with CFG_TUH_MAX3421 enabled" + //--------------------------------------------------------------------+ // Dialog //--------------------------------------------------------------------+ @@ -303,6 +357,7 @@ // Renesas //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N, OPT_MCU_RAXXX) + #define TUP_USBIP_RUSB2 #define TUP_DCD_ENDPOINT_MAX 10 //--------------------------------------------------------------------+ @@ -348,8 +403,24 @@ #elif TU_CHECK_MCU(OPT_MCU_CH32V307) #define TUP_DCD_ENDPOINT_MAX 16 #define TUP_RHPORT_HIGHSPEED 1 + +#elif TU_CHECK_MCU(OPT_MCU_CH32F20X) + #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_RHPORT_HIGHSPEED 1 +#endif + + +//--------------------------------------------------------------------+ +// External USB controller +//--------------------------------------------------------------------+ + +#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 + #ifndef CFG_TUH_MAX3421_ENDPOINT_TOTAL + #define CFG_TUH_MAX3421_ENDPOINT_TOTAL (8 + 4*(CFG_TUH_DEVICE_MAX-1)) + #endif #endif + //--------------------------------------------------------------------+ // Default Values //--------------------------------------------------------------------+ @@ -358,8 +429,8 @@ #define TUP_MCU_MULTIPLE_CORE 0 #endif -#ifndef TUP_DCD_ENDPOINT_MAX - #warning "TUP_DCD_ENDPOINT_MAX is not defined for this MCU, default to 8" +#if !defined(TUP_DCD_ENDPOINT_MAX) && defined(CFG_TUD_ENABLED) && CFG_TUD_ENABLED +#warning "TUP_DCD_ENDPOINT_MAX is not defined for this MCU, default to 8" #define TUP_DCD_ENDPOINT_MAX 8 #endif @@ -373,4 +444,8 @@ #define TU_ATTR_FAST_FUNC #endif +#if defined(TUP_USBIP_DWC2) || defined(TUP_USBIP_FSDEV) + #define TUP_DCD_EDPT_ISO_ALLOC +#endif + #endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_private.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_private.h index d5541856..373a5025 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_private.h +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_private.h @@ -60,7 +60,7 @@ typedef struct { tu_fifo_t ff; // mutex: read if ep rx, write if e tx - OSAL_MUTEX_DEF(ff_mutex); + OSAL_MUTEX_DEF(ff_mutexdef); }tu_edpt_stream_t; @@ -87,15 +87,17 @@ bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex); // Endpoint Stream //--------------------------------------------------------------------+ -// Init an stream, should only be called once +// Init an endpoint stream bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool overwritable, void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize); +// Deinit an endpoint stream +bool tu_edpt_stream_deinit(tu_edpt_stream_t* s); + // Open an stream for an endpoint // hwid is either device address (host mode) or rhport (device mode) TU_ATTR_ALWAYS_INLINE static inline -void tu_edpt_stream_open(tu_edpt_stream_t* s, uint8_t hwid, tusb_desc_endpoint_t const *desc_ep) -{ +void tu_edpt_stream_open(tu_edpt_stream_t* s, uint8_t hwid, tusb_desc_endpoint_t const *desc_ep) { tu_fifo_clear(&s->ff); s->hwid = hwid; s->ep_addr = desc_ep->bEndpointAddress; @@ -103,16 +105,14 @@ void tu_edpt_stream_open(tu_edpt_stream_t* s, uint8_t hwid, tusb_desc_endpoint_t } TU_ATTR_ALWAYS_INLINE static inline -void tu_edpt_stream_close(tu_edpt_stream_t* s) -{ +void tu_edpt_stream_close(tu_edpt_stream_t* s) { s->hwid = 0; s->ep_addr = 0; } // Clear fifo TU_ATTR_ALWAYS_INLINE static inline -bool tu_edpt_stream_clear(tu_edpt_stream_t* s) -{ +bool tu_edpt_stream_clear(tu_edpt_stream_t* s) { return tu_fifo_clear(&s->ff); } @@ -131,8 +131,7 @@ bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferr // Get the number of bytes available for writing TU_ATTR_ALWAYS_INLINE static inline -uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) -{ +uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) { return (uint32_t) tu_fifo_remaining(&s->ff); } @@ -148,21 +147,26 @@ uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s); // Must be called in the transfer complete callback TU_ATTR_ALWAYS_INLINE static inline -void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) -{ +void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) { tu_fifo_write_n(&s->ff, s->ep_buf, (uint16_t) xferred_bytes); } +// Same as tu_edpt_stream_read_xfer_complete but skip the first n bytes +TU_ATTR_ALWAYS_INLINE static inline +void tu_edpt_stream_read_xfer_complete_offset(tu_edpt_stream_t* s, uint32_t xferred_bytes, uint32_t skip_offset) { + if (skip_offset < xferred_bytes) { + tu_fifo_write_n(&s->ff, s->ep_buf + skip_offset, (uint16_t) (xferred_bytes - skip_offset)); + } +} + // Get the number of bytes available for reading TU_ATTR_ALWAYS_INLINE static inline -uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t* s) -{ +uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t* s) { return (uint32_t) tu_fifo_count(&s->ff); } TU_ATTR_ALWAYS_INLINE static inline -bool tu_edpt_stream_peek(tu_edpt_stream_t* s, uint8_t* ch) -{ +bool tu_edpt_stream_peek(tu_edpt_stream_t* s, uint8_t* ch) { return tu_fifo_peek(&s->ff, ch); } diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_timeout.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_timeout.h deleted file mode 100644 index 533e67ab..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_timeout.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -/** \ingroup Group_Common Common Files - * \defgroup Group_TimeoutTimer timeout timer - * @{ */ - -#ifndef _TUSB_TIMEOUT_H_ -#define _TUSB_TIMEOUT_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - uint32_t start; - uint32_t interval; -}tu_timeout_t; - -#if 0 - -extern uint32_t tusb_hal_millis(void); - -static inline void tu_timeout_set(tu_timeout_t* tt, uint32_t msec) -{ - tt->interval = msec; - tt->start = tusb_hal_millis(); -} - -static inline bool tu_timeout_expired(tu_timeout_t* tt) -{ - return ( tusb_hal_millis() - tt->start ) >= tt->interval; -} - -// For used with periodic event to prevent drift -static inline void tu_timeout_reset(tu_timeout_t* tt) -{ - tt->start += tt->interval; -} - -static inline void tu_timeout_restart(tu_timeout_t* tt) -{ - tt->start = tusb_hal_millis(); -} - -#endif - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_TIMEOUT_H_ */ - -/** @} */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_types.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_types.h index 39a2d456..b571f9b7 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_types.h +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_types.h @@ -24,12 +24,8 @@ * This file is part of the TinyUSB stack. */ -/** \ingroup group_usb_definitions - * \defgroup USBDef_Type USB Types - * @{ */ - -#ifndef _TUSB_TYPES_H_ -#define _TUSB_TYPES_H_ +#ifndef TUSB_TYPES_H_ +#define TUSB_TYPES_H_ #include #include @@ -44,43 +40,38 @@ *------------------------------------------------------------------*/ /// defined base on EHCI specs value for Endpoint Speed -typedef enum -{ +typedef enum { TUSB_SPEED_FULL = 0, TUSB_SPEED_LOW = 1, TUSB_SPEED_HIGH = 2, TUSB_SPEED_INVALID = 0xff, -}tusb_speed_t; +} tusb_speed_t; /// defined base on USB Specs Endpoint's bmAttributes -typedef enum -{ +typedef enum { TUSB_XFER_CONTROL = 0 , TUSB_XFER_ISOCHRONOUS , TUSB_XFER_BULK , TUSB_XFER_INTERRUPT -}tusb_xfer_type_t; +} tusb_xfer_type_t; -typedef enum -{ +typedef enum { TUSB_DIR_OUT = 0, TUSB_DIR_IN = 1, TUSB_DIR_IN_MASK = 0x80 -}tusb_dir_t; +} tusb_dir_t; -enum -{ +enum { TUSB_EPSIZE_BULK_FS = 64, - TUSB_EPSIZE_BULK_HS= 512, + TUSB_EPSIZE_BULK_HS = 512, TUSB_EPSIZE_ISO_FS_MAX = 1023, TUSB_EPSIZE_ISO_HS_MAX = 1024, }; -/// Isochronous End Point Attributes -typedef enum -{ +/// Isochronous Endpoint Attributes +typedef enum { TUSB_ISO_EP_ATT_NO_SYNC = 0x00, TUSB_ISO_EP_ATT_ASYNCHRONOUS = 0x04, TUSB_ISO_EP_ATT_ADAPTIVE = 0x08, @@ -88,11 +79,10 @@ typedef enum TUSB_ISO_EP_ATT_DATA = 0x00, ///< Data End Point TUSB_ISO_EP_ATT_EXPLICIT_FB = 0x10, ///< Feedback End Point TUSB_ISO_EP_ATT_IMPLICIT_FB = 0x20, ///< Data endpoint that also serves as an implicit feedback -}tusb_iso_ep_attribute_t; +} tusb_iso_ep_attribute_t; /// USB Descriptor Types -typedef enum -{ +typedef enum { TUSB_DESC_DEVICE = 0x01, TUSB_DESC_CONFIGURATION = 0x02, TUSB_DESC_STRING = 0x03, @@ -119,10 +109,9 @@ typedef enum TUSB_DESC_SUPERSPEED_ENDPOINT_COMPANION = 0x30, TUSB_DESC_SUPERSPEED_ISO_ENDPOINT_COMPANION = 0x31 -}tusb_desc_type_t; +} tusb_desc_type_t; -typedef enum -{ +typedef enum { TUSB_REQ_GET_STATUS = 0 , TUSB_REQ_CLEAR_FEATURE = 1 , TUSB_REQ_RESERVED = 2 , @@ -136,25 +125,22 @@ typedef enum TUSB_REQ_GET_INTERFACE = 10 , TUSB_REQ_SET_INTERFACE = 11 , TUSB_REQ_SYNCH_FRAME = 12 -}tusb_request_code_t; +} tusb_request_code_t; -typedef enum -{ +typedef enum { TUSB_REQ_FEATURE_EDPT_HALT = 0, TUSB_REQ_FEATURE_REMOTE_WAKEUP = 1, TUSB_REQ_FEATURE_TEST_MODE = 2 -}tusb_request_feature_selector_t; +} tusb_request_feature_selector_t; -typedef enum -{ +typedef enum { TUSB_REQ_TYPE_STANDARD = 0, TUSB_REQ_TYPE_CLASS, TUSB_REQ_TYPE_VENDOR, TUSB_REQ_TYPE_INVALID } tusb_request_type_t; -typedef enum -{ +typedef enum { TUSB_REQ_RCPT_DEVICE =0, TUSB_REQ_RCPT_INTERFACE, TUSB_REQ_RCPT_ENDPOINT, @@ -162,8 +148,7 @@ typedef enum } tusb_request_recipient_t; // https://www.usb.org/defined-class-codes -typedef enum -{ +typedef enum { TUSB_CLASS_UNSPECIFIED = 0 , TUSB_CLASS_AUDIO = 1 , TUSB_CLASS_CDC = 2 , @@ -187,26 +172,23 @@ typedef enum TUSB_CLASS_MISC = 0xEF , TUSB_CLASS_APPLICATION_SPECIFIC = 0xFE , TUSB_CLASS_VENDOR_SPECIFIC = 0xFF -}tusb_class_code_t; +} tusb_class_code_t; typedef enum { MISC_SUBCLASS_COMMON = 2 }misc_subclass_type_t; -typedef enum -{ +typedef enum { MISC_PROTOCOL_IAD = 1 -}misc_protocol_type_t; +} misc_protocol_type_t; -typedef enum -{ +typedef enum { APP_SUBCLASS_USBTMC = 0x03, APP_SUBCLASS_DFU_RUNTIME = 0x01 } app_subclass_type_t; -typedef enum -{ +typedef enum { DEVICE_CAPABILITY_WIRELESS_USB = 0x01, DEVICE_CAPABILITY_USB20_EXTENSION = 0x02, DEVICE_CAPABILITY_SUPERSPEED_USB = 0x03, @@ -223,37 +205,37 @@ typedef enum DEVICE_CAPABILITY_AUTHENTICATION = 0x0E, DEVICE_CAPABILITY_BILLBOARD_EX = 0x0F, DEVICE_CAPABILITY_CONFIGURATION_SUMMARY = 0x10 -}device_capability_type_t; +} device_capability_type_t; enum { - TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = TU_BIT(5), - TUSB_DESC_CONFIG_ATT_SELF_POWERED = TU_BIT(6), + TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = 1u << 5, + TUSB_DESC_CONFIG_ATT_SELF_POWERED = 1u << 6, }; #define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2) -typedef enum -{ +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ +typedef enum { XFER_RESULT_SUCCESS = 0, XFER_RESULT_FAILED, XFER_RESULT_STALLED, XFER_RESULT_TIMEOUT, XFER_RESULT_INVALID -}xfer_result_t; +} xfer_result_t; -enum // TODO remove -{ +// TODO remove +enum { DESC_OFFSET_LEN = 0, DESC_OFFSET_TYPE = 1 }; -enum -{ +enum { INTERFACE_INVALID_NUMBER = 0xff }; -typedef enum -{ +typedef enum { MS_OS_20_SET_HEADER_DESCRIPTOR = 0x00, MS_OS_20_SUBSET_HEADER_CONFIGURATION = 0x01, MS_OS_20_SUBSET_HEADER_FUNCTION = 0x02, @@ -265,16 +247,14 @@ typedef enum MS_OS_20_FEATURE_VENDOR_REVISION = 0x08 } microsoft_os_20_type_t; -enum -{ +enum { CONTROL_STAGE_IDLE, CONTROL_STAGE_SETUP, CONTROL_STAGE_DATA, CONTROL_STAGE_ACK }; -enum -{ +enum { TUSB_INDEX_INVALID_8 = 0xFFu }; @@ -287,15 +267,14 @@ TU_ATTR_PACKED_BEGIN TU_ATTR_BIT_FIELD_ORDER_BEGIN /// USB Device Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes. uint8_t bDescriptorType ; ///< DEVICE Descriptor Type. - uint16_t bcdUSB ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). This field identifies the release of the USB Specification with which the device and its descriptors are compliant. + uint16_t bcdUSB ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). - uint8_t bDeviceClass ; ///< Class code (assigned by the USB-IF). \li If this field is reset to zero, each interface within a configuration specifies its own class information and the various interfaces operate independently. \li If this field is set to a value between 1 and FEH, the device supports different class specifications on different interfaces and the interfaces may not operate independently. This value identifies the class definition used for the aggregate interfaces. \li If this field is set to FFH, the device class is vendor-specific. - uint8_t bDeviceSubClass ; ///< Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass field. \li If the bDeviceClass field is reset to zero, this field must also be reset to zero. \li If the bDeviceClass field is not set to FFH, all values are reserved for assignment by the USB-IF. - uint8_t bDeviceProtocol ; ///< Protocol code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass and the bDeviceSubClass fields. If a device supports class-specific protocols on a device basis as opposed to an interface basis, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use class-specific protocols on a device basis. However, it may use classspecific protocols on an interface basis. \li If this field is set to FFH, the device uses a vendor-specific protocol on a device basis. + uint8_t bDeviceClass ; ///< Class code (assigned by the USB-IF). + uint8_t bDeviceSubClass ; ///< Subclass code (assigned by the USB-IF). + uint8_t bDeviceProtocol ; ///< Protocol code (assigned by the USB-IF). uint8_t bMaxPacketSize0 ; ///< Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid). For HS devices is fixed to 64. uint16_t idVendor ; ///< Vendor ID (assigned by the USB-IF). @@ -311,8 +290,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_device_t) == 18, "size is not correct"); // USB Binary Device Object Store (BOS) Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type uint16_t wTotalLength ; ///< Total length of data returned for this descriptor @@ -322,8 +300,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_bos_t) == 5, "size is not correct"); /// USB Configuration Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type uint16_t wTotalLength ; ///< Total length of data returned for this configuration. Includes the combined length of all descriptors (configuration, interface, endpoint, and class- or vendor-specific) returned for this configuration. @@ -338,8 +315,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_configuration_t) == 9, "size is not correct"); /// USB Interface Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< INTERFACE Descriptor Type @@ -355,8 +331,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_interface_t) == 9, "size is not correct"); /// USB Endpoint Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; // Size of this descriptor in bytes uint8_t bDescriptorType ; // ENDPOINT Descriptor Type @@ -376,8 +351,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_endpoint_t) == 7, "size is not correct"); /// USB Other Speed Configuration Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of descriptor uint8_t bDescriptorType ; ///< Other_speed_Configuration Type uint16_t wTotalLength ; ///< Total length of data returned @@ -390,8 +364,7 @@ typedef struct TU_ATTR_PACKED } tusb_desc_other_speed_t; /// USB Device Qualifier Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of descriptor uint8_t bDescriptorType ; ///< Device Qualifier Type uint16_t bcdUSB ; ///< USB specification version number (e.g., 0200H for V2.00) @@ -408,8 +381,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_device_qualifier_t) == 10, "size is not correct"); /// USB Interface Association Descriptor (IAD ECN) -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of descriptor uint8_t bDescriptorType ; ///< Other_speed_Configuration Type @@ -423,17 +395,17 @@ typedef struct TU_ATTR_PACKED uint8_t iFunction ; ///< Index of the string descriptor describing the interface association. } tusb_desc_interface_assoc_t; +TU_VERIFY_STATIC( sizeof(tusb_desc_interface_assoc_t) == 8, "size is not correct"); + // USB String Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< Descriptor Type uint16_t unicode_string[]; } tusb_desc_string_t; // USB Binary Device Object Store (BOS) -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType ; uint8_t bDevCapabilityType; @@ -442,9 +414,8 @@ typedef struct TU_ATTR_PACKED uint8_t CapabilityData[]; } tusb_desc_bos_platform_t; -// USB WebuSB URL Descriptor -typedef struct TU_ATTR_PACKED -{ +// USB WebUSB URL Descriptor +typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType; uint8_t bScheme; @@ -452,8 +423,7 @@ typedef struct TU_ATTR_PACKED } tusb_desc_webusb_url_t; // DFU Functional Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType; @@ -474,10 +444,11 @@ typedef struct TU_ATTR_PACKED uint16_t bcdDFUVersion; } tusb_desc_dfu_functional_t; -/*------------------------------------------------------------------*/ -/* Types - *------------------------------------------------------------------*/ -typedef struct TU_ATTR_PACKED{ +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +typedef struct TU_ATTR_PACKED { union { struct TU_ATTR_PACKED { uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t. @@ -496,7 +467,6 @@ typedef struct TU_ATTR_PACKED{ TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "size is not correct"); - TU_ATTR_PACKED_END // End of all packed definitions TU_ATTR_BIT_FIELD_ORDER_END @@ -505,36 +475,25 @@ TU_ATTR_BIT_FIELD_ORDER_END //--------------------------------------------------------------------+ // Get direction from Endpoint address -TU_ATTR_ALWAYS_INLINE static inline tusb_dir_t tu_edpt_dir(uint8_t addr) -{ +TU_ATTR_ALWAYS_INLINE static inline tusb_dir_t tu_edpt_dir(uint8_t addr) { return (addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; } // Get Endpoint number from address -TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_number(uint8_t addr) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_number(uint8_t addr) { return (uint8_t)(addr & (~TUSB_DIR_IN_MASK)); } -TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir) { return (uint8_t)(num | (dir ? TUSB_DIR_IN_MASK : 0)); } -TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep) -{ - return tu_le16toh(desc_ep->wMaxPacketSize) & TU_GENMASK(10, 0); +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep) { + return tu_le16toh(desc_ep->wMaxPacketSize) & 0x7FF; } #if CFG_TUSB_DEBUG -TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_dir_str(tusb_dir_t dir) -{ - tu_static const char *str[] = {"out", "in"}; - return str[dir]; -} - -TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_t t) -{ +TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_t t) { tu_static const char *str[] = {"control", "isochronous", "bulk", "interrupt"}; return str[t]; } @@ -545,21 +504,18 @@ TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_ //--------------------------------------------------------------------+ // return next descriptor -TU_ATTR_ALWAYS_INLINE static inline uint8_t const * tu_desc_next(void const* desc) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t const * tu_desc_next(void const* desc) { uint8_t const* desc8 = (uint8_t const*) desc; return desc8 + desc8[DESC_OFFSET_LEN]; } // get descriptor type -TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_type(void const* desc) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_type(void const* desc) { return ((uint8_t const*) desc)[DESC_OFFSET_TYPE]; } // get descriptor length -TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc) { return ((uint8_t const*) desc)[DESC_OFFSET_LEN]; } @@ -576,6 +532,4 @@ uint8_t const * tu_desc_find3(uint8_t const* desc, uint8_t const* end, uint8_t b } #endif -#endif /* _TUSB_TYPES_H_ */ - -/** @} */ +#endif // TUSB_TYPES_H_ diff --git a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_verify.h b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_verify.h index 12355e8b..0a9549c9 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/common/tusb_verify.h +++ b/test-devices/loopback-stm32/lib/tinyusb/common/tusb_verify.h @@ -56,12 +56,8 @@ * #define TU_VERIFY(cond) if(cond) return false; * #define TU_VERIFY(cond,ret) if(cond) return ret; * - * #define TU_VERIFY_HDLR(cond,handler) if(cond) {handler; return false;} - * #define TU_VERIFY_HDLR(cond,ret,handler) if(cond) {handler; return ret;} - * * #define TU_ASSERT(cond) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return false;} * #define TU_ASSERT(cond,ret) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return ret;} - * *------------------------------------------------------------------*/ #ifdef __cplusplus @@ -79,15 +75,16 @@ #define _MESS_FAILED() do {} while (0) #endif -// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7, M33 -#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__) +// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7, M33. M55 +#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8_1M_MAIN__) || \ + defined(__ARM7M__) || defined (__ARM7EM__) || defined(__ARM8M_MAINLINE__) || defined(__ARM8EM_MAINLINE__) #define TU_BREAKPOINT() do \ { \ volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \ if ( (*ARM_CM_DHCSR) & 1UL ) __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */ \ } while(0) -#elif defined(__riscv) +#elif defined(__riscv) && !TUP_MCU_ESPRESSIF #define TU_BREAKPOINT() do { __asm("ebreak\n"); } while(0) #elif defined(_mips) @@ -97,40 +94,23 @@ #define TU_BREAKPOINT() do {} while (0) #endif -/*------------------------------------------------------------------*/ -/* Macro Generator - *------------------------------------------------------------------*/ - // Helper to implement optional parameter for TU_VERIFY Macro family #define _GET_3RD_ARG(arg1, arg2, arg3, ...) arg3 -#define _GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4 - -/*------------- Generator for TU_VERIFY and TU_VERIFY_HDLR -------------*/ -#define TU_VERIFY_DEFINE(_cond, _handler, _ret) do \ -{ \ - if ( !(_cond) ) { _handler; return _ret; } \ -} while(0) /*------------------------------------------------------------------*/ /* TU_VERIFY * - TU_VERIFY_1ARGS : return false if failed * - TU_VERIFY_2ARGS : return provided value if failed *------------------------------------------------------------------*/ -#define TU_VERIFY_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, , false) -#define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, , _ret) +#define TU_VERIFY_DEFINE(_cond, _ret) \ + do { \ + if ( !(_cond) ) { return _ret; } \ + } while(0) -#define TU_VERIFY(...) _GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, UNUSED)(__VA_ARGS__) +#define TU_VERIFY_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, false) +#define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _ret) - -/*------------------------------------------------------------------*/ -/* TU_VERIFY WITH HANDLER - * - TU_VERIFY_HDLR_2ARGS : execute handler, return false if failed - * - TU_VERIFY_HDLR_3ARGS : execute handler, return provided error if failed - *------------------------------------------------------------------*/ -#define TU_VERIFY_HDLR_2ARGS(_cond, _handler) TU_VERIFY_DEFINE(_cond, _handler, false) -#define TU_VERIFY_HDLR_3ARGS(_cond, _handler, _ret) TU_VERIFY_DEFINE(_cond, _handler, _ret) - -#define TU_VERIFY_HDLR(...) _GET_4TH_ARG(__VA_ARGS__, TU_VERIFY_HDLR_3ARGS, TU_VERIFY_HDLR_2ARGS,UNUSED)(__VA_ARGS__) +#define TU_VERIFY(...) _GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, _dummy)(__VA_ARGS__) /*------------------------------------------------------------------*/ /* ASSERT @@ -138,19 +118,20 @@ * - 1 arg : return false if failed * - 2 arg : return error if failed *------------------------------------------------------------------*/ -#define ASSERT_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), false) -#define ASSERT_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), _ret) +#define TU_ASSERT_DEFINE(_cond, _ret) \ + do { \ + if ( !(_cond) ) { _MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \ + } while(0) + +#define TU_ASSERT_1ARGS(_cond) TU_ASSERT_DEFINE(_cond, false) +#define TU_ASSERT_2ARGS(_cond, _ret) TU_ASSERT_DEFINE(_cond, _ret) #ifndef TU_ASSERT -#define TU_ASSERT(...) _GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS,UNUSED)(__VA_ARGS__) +#define TU_ASSERT(...) _GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__) #endif -/*------------------------------------------------------------------*/ -/* ASSERT HDLR - *------------------------------------------------------------------*/ - #ifdef __cplusplus } #endif -#endif /* TUSB_VERIFY_H_ */ +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/device/dcd.h b/test-devices/loopback-stm32/lib/tinyusb/device/dcd.h index 00419ff0..d4f105aa 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/device/dcd.h +++ b/test-devices/loopback-stm32/lib/tinyusb/device/dcd.h @@ -47,8 +47,7 @@ // MACRO CONSTANT TYPEDEF PROTYPES //--------------------------------------------------------------------+ -typedef enum -{ +typedef enum { DCD_EVENT_INVALID = 0, DCD_EVENT_BUS_RESET, DCD_EVENT_UNPLUGGED, @@ -65,13 +64,11 @@ typedef enum DCD_EVENT_COUNT } dcd_eventid_t; -typedef struct TU_ATTR_ALIGNED(4) -{ +typedef struct TU_ATTR_ALIGNED(4) { uint8_t rhport; uint8_t event_id; - union - { + union { // BUS RESET struct { tusb_speed_t speed; @@ -102,12 +99,31 @@ typedef struct TU_ATTR_ALIGNED(4) //TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct"); +//--------------------------------------------------------------------+ +// Memory API +//--------------------------------------------------------------------+ + +// clean/flush data cache: write cache -> memory. +// Required before an DMA TX transfer to make sure data is in memory +void dcd_dcache_clean(void const* addr, uint32_t data_size) TU_ATTR_WEAK; + +// invalidate data cache: mark cache as invalid, next read will read from memory +// Required BOTH before and after an DMA RX transfer +void dcd_dcache_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK; + +// clean and invalidate data cache +// Required before an DMA transfer where memory is both read/write by DMA +void dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK; + //--------------------------------------------------------------------+ // Controller API //--------------------------------------------------------------------+ // Initialize controller to device mode -void dcd_init (uint8_t rhport); +void dcd_init(uint8_t rhport); + +// Deinitialize controller, unset device mode. +bool dcd_deinit(uint8_t rhport); // Interrupt Handler void dcd_int_handler(uint8_t rhport); @@ -139,7 +155,7 @@ void dcd_sof_enable(uint8_t rhport, bool en); // Invoked when a control transfer's status stage is complete. // May help DCD to prepare for next control transfer, this API is optional. -void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) TU_ATTR_WEAK; +void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request); // Configure endpoint's registers according to descriptor bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_ep); @@ -168,11 +184,12 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr); // Allocate packet buffer used by ISO endpoints -// Some MCU need manual packet buffer allocation, we allocation largest size to avoid clustering +// Some MCU need manual packet buffer allocation, we allocate the largest size to avoid clustering TU_ATTR_WEAK bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size); // Configure and enable an ISO endpoint according to descriptor -TU_ATTR_WEAK bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); +TU_ATTR_WEAK bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); + //--------------------------------------------------------------------+ // Event API (implemented by stack) //--------------------------------------------------------------------+ @@ -181,23 +198,20 @@ TU_ATTR_WEAK bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t co extern void dcd_event_handler(dcd_event_t const * event, bool in_isr); // helper to send bus signal event -TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr) -{ +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr) { dcd_event_t event = { .rhport = rhport, .event_id = eid }; dcd_event_handler(&event, in_isr); } // helper to send bus reset event -TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_reset (uint8_t rhport, tusb_speed_t speed, bool in_isr) -{ +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_reset (uint8_t rhport, tusb_speed_t speed, bool in_isr) { dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_BUS_RESET }; event.bus_reset.speed = speed; dcd_event_handler(&event, in_isr); } // helper to send setup received -TU_ATTR_ALWAYS_INLINE static inline void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr) -{ +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr) { dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SETUP_RECEIVED }; memcpy(&event.setup_received, setup, sizeof(tusb_control_request_t)); @@ -205,8 +219,7 @@ TU_ATTR_ALWAYS_INLINE static inline void dcd_event_setup_received(uint8_t rhport } // helper to send transfer complete event -TU_ATTR_ALWAYS_INLINE static inline void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr) -{ +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr) { dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_XFER_COMPLETE }; event.xfer_complete.ep_addr = ep_addr; @@ -216,8 +229,7 @@ TU_ATTR_ALWAYS_INLINE static inline void dcd_event_xfer_complete (uint8_t rhport dcd_event_handler(&event, in_isr); } -static inline void dcd_event_sof(uint8_t rhport, uint32_t frame_count, bool in_isr) -{ +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_sof(uint8_t rhport, uint32_t frame_count, bool in_isr) { dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SOF }; event.sof.frame_count = frame_count; dcd_event_handler(&event, in_isr); diff --git a/test-devices/loopback-stm32/lib/tinyusb/device/usbd.c b/test-devices/loopback-stm32/lib/tinyusb/device/usbd.c index cee56af6..e51aa0fc 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/device/usbd.c +++ b/test-devices/loopback-stm32/lib/tinyusb/device/usbd.c @@ -38,13 +38,23 @@ //--------------------------------------------------------------------+ // USBD Configuration //--------------------------------------------------------------------+ - #ifndef CFG_TUD_TASK_QUEUE_SZ #define CFG_TUD_TASK_QUEUE_SZ 16 #endif -// Debug level of USBD -#define USBD_DBG 2 +//--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK bool dcd_deinit(uint8_t rhport) { + (void) rhport; + return false; +} + +TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) { + (void)rhport; + (void)eventid; + (void)in_isr; +} //--------------------------------------------------------------------+ // Device Data @@ -53,10 +63,8 @@ // Invalid driver ID in itf2drv[] ep2drv[][] mapping enum { DRVID_INVALID = 0xFFu }; -typedef struct -{ - struct TU_ATTR_PACKED - { +typedef struct { + struct TU_ATTR_PACKED { volatile uint8_t connected : 1; volatile uint8_t addressed : 1; volatile uint8_t suspended : 1; @@ -65,9 +73,9 @@ typedef struct uint8_t remote_wakeup_support : 1; // configuration descriptor's attribute uint8_t self_powered : 1; // configuration descriptor's attribute }; - volatile uint8_t cfg_num; // current active configuration (0x00 is not configured) uint8_t speed; + volatile uint8_t setup_count; uint8_t itf2drv[CFG_TUD_INTERFACE_MAX]; // map interface number to driver (0xff is invalid) uint8_t ep2drv[CFG_TUD_ENDPPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid ), can use only 4-bit each @@ -81,158 +89,169 @@ tu_static usbd_device_t _usbd_dev; //--------------------------------------------------------------------+ // Class Driver //--------------------------------------------------------------------+ -#if CFG_TUSB_DEBUG >= 2 +#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL #define DRIVER_NAME(_name) .name = _name, #else #define DRIVER_NAME(_name) #endif // Built-in class drivers -tu_static usbd_class_driver_t const _usbd_driver[] = -{ - #if CFG_TUD_CDC - { - DRIVER_NAME("CDC") - .init = cdcd_init, - .reset = cdcd_reset, - .open = cdcd_open, - .control_xfer_cb = cdcd_control_xfer_cb, - .xfer_cb = cdcd_xfer_cb, - .sof = NULL - }, - #endif - - #if CFG_TUD_MSC - { - DRIVER_NAME("MSC") - .init = mscd_init, - .reset = mscd_reset, - .open = mscd_open, - .control_xfer_cb = mscd_control_xfer_cb, - .xfer_cb = mscd_xfer_cb, - .sof = NULL - }, - #endif - - #if CFG_TUD_HID - { - DRIVER_NAME("HID") - .init = hidd_init, - .reset = hidd_reset, - .open = hidd_open, - .control_xfer_cb = hidd_control_xfer_cb, - .xfer_cb = hidd_xfer_cb, - .sof = NULL - }, - #endif - - #if CFG_TUD_AUDIO - { - DRIVER_NAME("AUDIO") - .init = audiod_init, - .reset = audiod_reset, - .open = audiod_open, - .control_xfer_cb = audiod_control_xfer_cb, - .xfer_cb = audiod_xfer_cb, - .sof = audiod_sof_isr - }, - #endif - - #if CFG_TUD_VIDEO - { - DRIVER_NAME("VIDEO") - .init = videod_init, - .reset = videod_reset, - .open = videod_open, - .control_xfer_cb = videod_control_xfer_cb, - .xfer_cb = videod_xfer_cb, - .sof = NULL - }, - #endif - - #if CFG_TUD_MIDI - { - DRIVER_NAME("MIDI") - .init = midid_init, - .open = midid_open, - .reset = midid_reset, - .control_xfer_cb = midid_control_xfer_cb, - .xfer_cb = midid_xfer_cb, - .sof = NULL - }, - #endif - - #if CFG_TUD_VENDOR - { - DRIVER_NAME("VENDOR") - .init = vendord_init, - .reset = vendord_reset, - .open = vendord_open, - .control_xfer_cb = tud_vendor_control_xfer_cb, - .xfer_cb = vendord_xfer_cb, - .sof = NULL - }, - #endif - - #if CFG_TUD_USBTMC - { - DRIVER_NAME("TMC") - .init = usbtmcd_init_cb, - .reset = usbtmcd_reset_cb, - .open = usbtmcd_open_cb, - .control_xfer_cb = usbtmcd_control_xfer_cb, - .xfer_cb = usbtmcd_xfer_cb, - .sof = NULL - }, - #endif - - #if CFG_TUD_DFU_RUNTIME - { - DRIVER_NAME("DFU-RUNTIME") - .init = dfu_rtd_init, - .reset = dfu_rtd_reset, - .open = dfu_rtd_open, - .control_xfer_cb = dfu_rtd_control_xfer_cb, - .xfer_cb = NULL, - .sof = NULL - }, - #endif - - #if CFG_TUD_DFU - { - DRIVER_NAME("DFU") - .init = dfu_moded_init, - .reset = dfu_moded_reset, - .open = dfu_moded_open, - .control_xfer_cb = dfu_moded_control_xfer_cb, - .xfer_cb = NULL, - .sof = NULL - }, - #endif - - #if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM - { - DRIVER_NAME("NET") - .init = netd_init, - .reset = netd_reset, - .open = netd_open, - .control_xfer_cb = netd_control_xfer_cb, - .xfer_cb = netd_xfer_cb, - .sof = NULL, - }, - #endif - - #if CFG_TUD_BTH - { - DRIVER_NAME("BTH") - .init = btd_init, - .reset = btd_reset, - .open = btd_open, - .control_xfer_cb = btd_control_xfer_cb, - .xfer_cb = btd_xfer_cb, - .sof = NULL - }, - #endif +tu_static usbd_class_driver_t const _usbd_driver[] = { + #if CFG_TUD_CDC + { + DRIVER_NAME("CDC") + .init = cdcd_init, + .deinit = cdcd_deinit, + .reset = cdcd_reset, + .open = cdcd_open, + .control_xfer_cb = cdcd_control_xfer_cb, + .xfer_cb = cdcd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_MSC + { + DRIVER_NAME("MSC") + .init = mscd_init, + .deinit = NULL, + .reset = mscd_reset, + .open = mscd_open, + .control_xfer_cb = mscd_control_xfer_cb, + .xfer_cb = mscd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_HID + { + DRIVER_NAME("HID") + .init = hidd_init, + .deinit = hidd_deinit, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hidd_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_AUDIO + { + DRIVER_NAME("AUDIO") + .init = audiod_init, + .deinit = audiod_deinit, + .reset = audiod_reset, + .open = audiod_open, + .control_xfer_cb = audiod_control_xfer_cb, + .xfer_cb = audiod_xfer_cb, + .sof = audiod_sof_isr + }, + #endif + + #if CFG_TUD_VIDEO + { + DRIVER_NAME("VIDEO") + .init = videod_init, + .deinit = videod_deinit, + .reset = videod_reset, + .open = videod_open, + .control_xfer_cb = videod_control_xfer_cb, + .xfer_cb = videod_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_MIDI + { + DRIVER_NAME("MIDI") + .init = midid_init, + .deinit = midid_deinit, + .open = midid_open, + .reset = midid_reset, + .control_xfer_cb = midid_control_xfer_cb, + .xfer_cb = midid_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_VENDOR + { + DRIVER_NAME("VENDOR") + .init = vendord_init, + .deinit = vendord_deinit, + .reset = vendord_reset, + .open = vendord_open, + .control_xfer_cb = tud_vendor_control_xfer_cb, + .xfer_cb = vendord_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_USBTMC + { + DRIVER_NAME("TMC") + .init = usbtmcd_init_cb, + .deinit = usbtmcd_deinit, + .reset = usbtmcd_reset_cb, + .open = usbtmcd_open_cb, + .control_xfer_cb = usbtmcd_control_xfer_cb, + .xfer_cb = usbtmcd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_DFU_RUNTIME + { + DRIVER_NAME("DFU-RUNTIME") + .init = dfu_rtd_init, + .deinit = dfu_rtd_deinit, + .reset = dfu_rtd_reset, + .open = dfu_rtd_open, + .control_xfer_cb = dfu_rtd_control_xfer_cb, + .xfer_cb = NULL, + .sof = NULL + }, + #endif + + #if CFG_TUD_DFU + { + DRIVER_NAME("DFU") + .init = dfu_moded_init, + .deinit = dfu_moded_deinit, + .reset = dfu_moded_reset, + .open = dfu_moded_open, + .control_xfer_cb = dfu_moded_control_xfer_cb, + .xfer_cb = NULL, + .sof = NULL + }, + #endif + + #if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM + { + DRIVER_NAME("NET") + .init = netd_init, + .deinit = netd_deinit, + .reset = netd_reset, + .open = netd_open, + .control_xfer_cb = netd_control_xfer_cb, + .xfer_cb = netd_xfer_cb, + .sof = NULL, + }, + #endif + + #if CFG_TUD_BTH + { + DRIVER_NAME("BTH") + .init = btd_init, + .deinit = btd_deinit, + .reset = btd_reset, + .open = btd_open, + .control_xfer_cb = btd_control_xfer_cb, + .xfer_cb = btd_xfer_cb, + .sof = NULL + }, + #endif }; enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(_usbd_driver) }; @@ -241,25 +260,21 @@ enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(_usbd_driver) }; tu_static usbd_class_driver_t const * _app_driver = NULL; tu_static uint8_t _app_driver_count = 0; +#define TOTAL_DRIVER_COUNT (_app_driver_count + BUILTIN_DRIVER_COUNT) + // virtually joins built-in and application drivers together. // Application is positioned first to allow overwriting built-in ones. -static inline usbd_class_driver_t const * get_driver(uint8_t drvid) -{ - // Application drivers - if ( usbd_app_driver_get_cb ) - { - if ( drvid < _app_driver_count ) return &_app_driver[drvid]; - drvid -= _app_driver_count; +TU_ATTR_ALWAYS_INLINE static inline usbd_class_driver_t const * get_driver(uint8_t drvid) { + usbd_class_driver_t const * driver = NULL; + if ( drvid < _app_driver_count ) { + // Application drivers + driver = &_app_driver[drvid]; + } else if ( drvid < TOTAL_DRIVER_COUNT && BUILTIN_DRIVER_COUNT > 0 ){ + driver = &_usbd_driver[drvid - _app_driver_count]; } - - // Built-in drivers - if (drvid < BUILTIN_DRIVER_COUNT) return &_usbd_driver[drvid]; - - return NULL; + return driver; } -#define TOTAL_DRIVER_COUNT (_app_driver_count + BUILTIN_DRIVER_COUNT) - //--------------------------------------------------------------------+ // DCD Event //--------------------------------------------------------------------+ @@ -280,6 +295,11 @@ tu_static osal_queue_t _usbd_q; #define _usbd_mutex NULL #endif +TU_ATTR_ALWAYS_INLINE static inline bool queue_event(dcd_event_t const * event, bool in_isr) { + TU_ASSERT(osal_queue_send(_usbd_q, event, in_isr)); + tud_event_hook_cb(event->rhport, event->event_id, in_isr); + return true; +} //--------------------------------------------------------------------+ // Prototypes @@ -298,29 +318,25 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, //--------------------------------------------------------------------+ // Debug //--------------------------------------------------------------------+ -#if CFG_TUSB_DEBUG >= 2 -tu_static char const* const _usbd_event_str[DCD_EVENT_COUNT] = -{ - "Invalid" , - "Bus Reset" , - "Unplugged" , - "SOF" , - "Suspend" , - "Resume" , - "Setup Received" , - "Xfer Complete" , - "Func Call" +#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL +tu_static char const* const _usbd_event_str[DCD_EVENT_COUNT] = { + "Invalid", + "Bus Reset", + "Unplugged", + "SOF", + "Suspend", + "Resume", + "Setup Received", + "Xfer Complete", + "Func Call" }; // for usbd_control to print the name of control complete driver -void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback) -{ - for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) - { - usbd_class_driver_t const * driver = get_driver(i); - if ( driver && driver->control_xfer_cb == callback ) - { - TU_LOG(USBD_DBG, " %s control complete\r\n", driver->name); +void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback) { + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) { + usbd_class_driver_t const* driver = get_driver(i); + if (driver && driver->control_xfer_cb == callback) { + TU_LOG_USBD("%s control complete\r\n", driver->name); return; } } @@ -331,43 +347,36 @@ void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback) //--------------------------------------------------------------------+ // Application API //--------------------------------------------------------------------+ -tusb_speed_t tud_speed_get(void) -{ +tusb_speed_t tud_speed_get(void) { return (tusb_speed_t) _usbd_dev.speed; } -bool tud_connected(void) -{ +bool tud_connected(void) { return _usbd_dev.connected; } -bool tud_mounted(void) -{ +bool tud_mounted(void) { return _usbd_dev.cfg_num ? true : false; } -bool tud_suspended(void) -{ +bool tud_suspended(void) { return _usbd_dev.suspended; } -bool tud_remote_wakeup(void) -{ +bool tud_remote_wakeup(void) { // only wake up host if this feature is supported and enabled and we are suspended - TU_VERIFY (_usbd_dev.suspended && _usbd_dev.remote_wakeup_support && _usbd_dev.remote_wakeup_en ); + TU_VERIFY (_usbd_dev.suspended && _usbd_dev.remote_wakeup_support && _usbd_dev.remote_wakeup_en); dcd_remote_wakeup(_usbd_rhport); return true; } -bool tud_disconnect(void) -{ +bool tud_disconnect(void) { TU_VERIFY(dcd_disconnect); dcd_disconnect(_usbd_rhport); return true; } -bool tud_connect(void) -{ +bool tud_connect(void) { TU_VERIFY(dcd_connect); dcd_connect(_usbd_rhport); return true; @@ -376,20 +385,19 @@ bool tud_connect(void) //--------------------------------------------------------------------+ // USBD Task //--------------------------------------------------------------------+ -bool tud_inited(void) -{ +bool tud_inited(void) { return _usbd_rhport != RHPORT_INVALID; } -bool tud_init (uint8_t rhport) -{ +bool tud_init(uint8_t rhport) { // skip if already initialized - if ( tud_inited() ) return true; + if (tud_inited()) return true; - TU_LOG(USBD_DBG, "USBD init on controller %u\r\n", rhport); - TU_LOG_INT(USBD_DBG, sizeof(usbd_device_t)); - TU_LOG_INT(USBD_DBG, sizeof(tu_fifo_t)); - TU_LOG_INT(USBD_DBG, sizeof(tu_edpt_stream_t)); + TU_LOG_USBD("USBD init on controller %u\r\n", rhport); + TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(usbd_device_t)); + TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(dcd_event_t)); + TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_fifo_t)); + TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_edpt_stream_t)); tu_varclr(&_usbd_dev); @@ -404,17 +412,15 @@ bool tud_init (uint8_t rhport) TU_ASSERT(_usbd_q); // Get application driver if available - if ( usbd_app_driver_get_cb ) - { + if (usbd_app_driver_get_cb) { _app_driver = usbd_app_driver_get_cb(&_app_driver_count); } // Init class drivers - for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) - { - usbd_class_driver_t const * driver = get_driver(i); - TU_ASSERT(driver); - TU_LOG(USBD_DBG, "%s init\r\n", driver->name); + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) { + usbd_class_driver_t const* driver = get_driver(i); + TU_ASSERT(driver && driver->init); + TU_LOG_USBD("%s init\r\n", driver->name); driver->init(); } @@ -427,31 +433,61 @@ bool tud_init (uint8_t rhport) return true; } -static void configuration_reset(uint8_t rhport) -{ - for ( uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++ ) - { - usbd_class_driver_t const * driver = get_driver(i); - TU_ASSERT(driver, ); +bool tud_deinit(uint8_t rhport) { + // skip if not initialized + if (!tud_inited()) return true; + + TU_LOG_USBD("USBD deinit on controller %u\r\n", rhport); + + // Deinit device controller driver + dcd_int_disable(rhport); + dcd_disconnect(rhport); + dcd_deinit(rhport); + + // Deinit class drivers + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) { + usbd_class_driver_t const* driver = get_driver(i); + if(driver && driver->deinit) { + TU_LOG_USBD("%s deinit\r\n", driver->name); + driver->deinit(); + } + } + + // Deinit device queue & task + osal_queue_delete(_usbd_q); + _usbd_q = NULL; + +#if OSAL_MUTEX_REQUIRED + // TODO make sure there is no task waiting on this mutex + osal_mutex_delete(_usbd_mutex); + _usbd_mutex = NULL; +#endif + + _usbd_rhport = RHPORT_INVALID; + + return true; +} + +static void configuration_reset(uint8_t rhport) { + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) { + usbd_class_driver_t const* driver = get_driver(i); + TU_ASSERT(driver,); driver->reset(rhport); } tu_varclr(&_usbd_dev); memset(_usbd_dev.itf2drv, DRVID_INVALID, sizeof(_usbd_dev.itf2drv)); // invalid mapping - memset(_usbd_dev.ep2drv , DRVID_INVALID, sizeof(_usbd_dev.ep2drv )); // invalid mapping + memset(_usbd_dev.ep2drv, DRVID_INVALID, sizeof(_usbd_dev.ep2drv)); // invalid mapping } -static void usbd_reset(uint8_t rhport) -{ +static void usbd_reset(uint8_t rhport) { configuration_reset(rhport); usbd_control_reset(); } -bool tud_task_event_ready(void) -{ +bool tud_task_event_ready(void) { // Skip if stack is not initialized - if ( !tud_inited() ) return false; - + if (!tud_inited()) return false; return !osal_queue_empty(_usbd_q); } @@ -459,139 +495,126 @@ bool tud_task_event_ready(void) * This top level thread manages all device controller event and delegates events to class-specific drivers. * This should be called periodically within the mainloop or rtos thread. * - @code - int main(void) - { + int main(void) { application_init(); tusb_init(); - while(1) // the mainloop - { + while(1) { // the mainloop application_code(); tud_task(); // tinyusb device task } } - @endcode */ -void tud_task_ext(uint32_t timeout_ms, bool in_isr) -{ +void tud_task_ext(uint32_t timeout_ms, bool in_isr) { (void) in_isr; // not implemented yet // Skip if stack is not initialized - if ( !tud_inited() ) return; + if (!tud_inited()) return; // Loop until there is no more events in the queue - while (1) - { + while (1) { dcd_event_t event; - if ( !osal_queue_receive(_usbd_q, &event, timeout_ms) ) return; + if (!osal_queue_receive(_usbd_q, &event, timeout_ms)) return; -#if CFG_TUSB_DEBUG >= 2 - if (event.event_id == DCD_EVENT_SETUP_RECEIVED) TU_LOG(USBD_DBG, "\r\n"); // extra line for setup - TU_LOG(USBD_DBG, "USBD %s ", event.event_id < DCD_EVENT_COUNT ? _usbd_event_str[event.event_id] : "CORRUPTED"); +#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL + if (event.event_id == DCD_EVENT_SETUP_RECEIVED) TU_LOG_USBD("\r\n"); // extra line for setup + TU_LOG_USBD("USBD %s ", event.event_id < DCD_EVENT_COUNT ? _usbd_event_str[event.event_id] : "CORRUPTED"); #endif - switch ( event.event_id ) - { + switch (event.event_id) { case DCD_EVENT_BUS_RESET: - TU_LOG(USBD_DBG, ": %s Speed\r\n", tu_str_speed[event.bus_reset.speed]); + TU_LOG_USBD(": %s Speed\r\n", tu_str_speed[event.bus_reset.speed]); usbd_reset(event.rhport); _usbd_dev.speed = event.bus_reset.speed; - break; + break; case DCD_EVENT_UNPLUGGED: - TU_LOG(USBD_DBG, "\r\n"); + TU_LOG_USBD("\r\n"); usbd_reset(event.rhport); - - // invoke callback if (tud_umount_cb) tud_umount_cb(); - break; + break; case DCD_EVENT_SETUP_RECEIVED: - TU_LOG_PTR(USBD_DBG, &event.setup_received); - TU_LOG(USBD_DBG, "\r\n"); + _usbd_dev.setup_count--; + TU_LOG_BUF(CFG_TUD_LOG_LEVEL, &event.setup_received, 8); + if (_usbd_dev.setup_count) { + TU_LOG_USBD(" Skipped since there is other SETUP in queue\r\n"); + break; + } // Mark as connected after receiving 1st setup packet. // But it is easier to set it every time instead of wasting time to check then set _usbd_dev.connected = 1; // mark both in & out control as free - _usbd_dev.ep_status[0][TUSB_DIR_OUT].busy = false; + _usbd_dev.ep_status[0][TUSB_DIR_OUT].busy = 0; _usbd_dev.ep_status[0][TUSB_DIR_OUT].claimed = 0; - _usbd_dev.ep_status[0][TUSB_DIR_IN ].busy = false; - _usbd_dev.ep_status[0][TUSB_DIR_IN ].claimed = 0; + _usbd_dev.ep_status[0][TUSB_DIR_IN].busy = 0; + _usbd_dev.ep_status[0][TUSB_DIR_IN].claimed = 0; // Process control request - if ( !process_control_request(event.rhport, &event.setup_received) ) - { - TU_LOG(USBD_DBG, " Stall EP0\r\n"); + if (!process_control_request(event.rhport, &event.setup_received)) { + TU_LOG_USBD(" Stall EP0\r\n"); // Failed -> stall both control endpoint IN and OUT dcd_edpt_stall(event.rhport, 0); dcd_edpt_stall(event.rhport, 0 | TUSB_DIR_IN_MASK); } - break; + break; - case DCD_EVENT_XFER_COMPLETE: - { + case DCD_EVENT_XFER_COMPLETE: { // Invoke the class callback associated with the endpoint address uint8_t const ep_addr = event.xfer_complete.ep_addr; - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const ep_dir = tu_edpt_dir(ep_addr); + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const ep_dir = tu_edpt_dir(ep_addr); - TU_LOG(USBD_DBG, "on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len); + TU_LOG_USBD("on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len); - _usbd_dev.ep_status[epnum][ep_dir].busy = false; + _usbd_dev.ep_status[epnum][ep_dir].busy = 0; _usbd_dev.ep_status[epnum][ep_dir].claimed = 0; - if ( 0 == epnum ) - { - usbd_control_xfer_cb(event.rhport, ep_addr, (xfer_result_t)event.xfer_complete.result, event.xfer_complete.len); - } - else - { - usbd_class_driver_t const * driver = get_driver( _usbd_dev.ep2drv[epnum][ep_dir] ); - TU_ASSERT(driver, ); + if (0 == epnum) { + usbd_control_xfer_cb(event.rhport, ep_addr, (xfer_result_t) event.xfer_complete.result, + event.xfer_complete.len); + } else { + usbd_class_driver_t const* driver = get_driver(_usbd_dev.ep2drv[epnum][ep_dir]); + TU_ASSERT(driver,); - TU_LOG(USBD_DBG, " %s xfer callback\r\n", driver->name); - driver->xfer_cb(event.rhport, ep_addr, (xfer_result_t)event.xfer_complete.result, event.xfer_complete.len); + TU_LOG_USBD(" %s xfer callback\r\n", driver->name); + driver->xfer_cb(event.rhport, ep_addr, (xfer_result_t) event.xfer_complete.result, event.xfer_complete.len); } + break; } - break; case DCD_EVENT_SUSPEND: // NOTE: When plugging/unplugging device, the D+/D- state are unstable and // can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ), which result in a series of event // e.g suspend -> resume -> unplug/plug. Skip suspend/resume if not connected - if ( _usbd_dev.connected ) - { - TU_LOG(USBD_DBG, ": Remote Wakeup = %u\r\n", _usbd_dev.remote_wakeup_en); + if (_usbd_dev.connected) { + TU_LOG_USBD(": Remote Wakeup = %u\r\n", _usbd_dev.remote_wakeup_en); if (tud_suspend_cb) tud_suspend_cb(_usbd_dev.remote_wakeup_en); - }else - { - TU_LOG(USBD_DBG, " Skipped\r\n"); + } else { + TU_LOG_USBD(" Skipped\r\n"); } - break; + break; case DCD_EVENT_RESUME: - if ( _usbd_dev.connected ) - { - TU_LOG(USBD_DBG, "\r\n"); + if (_usbd_dev.connected) { + TU_LOG_USBD("\r\n"); if (tud_resume_cb) tud_resume_cb(); - }else - { - TU_LOG(USBD_DBG, " Skipped\r\n"); + } else { + TU_LOG_USBD(" Skipped\r\n"); } - break; + break; case USBD_EVENT_FUNC_CALL: - TU_LOG(USBD_DBG, "\r\n"); - if ( event.func_call.func ) event.func_call.func(event.func_call.param); - break; + TU_LOG_USBD("\r\n"); + if (event.func_call.func) event.func_call.func(event.func_call.param); + break; case DCD_EVENT_SOF: default: TU_BREAKPOINT(); - break; + break; } #if CFG_TUSB_OS != OPT_OS_NONE && CFG_TUSB_OS != OPT_OS_PICO @@ -606,44 +629,37 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) //--------------------------------------------------------------------+ // Helper to invoke class driver control request handler -static bool invoke_class_control(uint8_t rhport, usbd_class_driver_t const * driver, tusb_control_request_t const * request) -{ +static bool invoke_class_control(uint8_t rhport, usbd_class_driver_t const * driver, tusb_control_request_t const * request) { usbd_control_set_complete_callback(driver->control_xfer_cb); - TU_LOG(USBD_DBG, " %s control request\r\n", driver->name); + TU_LOG_USBD(" %s control request\r\n", driver->name); return driver->control_xfer_cb(rhport, CONTROL_STAGE_SETUP, request); } // This handles the actual request and its response. -// return false will cause its caller to stall control endpoint -static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request) -{ +// Returns false if unable to complete the request, causing caller to stall control endpoints. +static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request) { usbd_control_set_complete_callback(NULL); - TU_ASSERT(p_request->bmRequestType_bit.type < TUSB_REQ_TYPE_INVALID); // Vendor request - if ( p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR ) - { + if ( p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR ) { TU_VERIFY(tud_vendor_control_xfer_cb); usbd_control_set_complete_callback(tud_vendor_control_xfer_cb); return tud_vendor_control_xfer_cb(rhport, CONTROL_STAGE_SETUP, p_request); } -#if CFG_TUSB_DEBUG >= 2 - if (TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type && p_request->bRequest <= TUSB_REQ_SYNCH_FRAME) - { - TU_LOG(USBD_DBG, " %s", tu_str_std_request[p_request->bRequest]); - if (TUSB_REQ_GET_DESCRIPTOR != p_request->bRequest) TU_LOG(USBD_DBG, "\r\n"); +#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL + if (TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type && p_request->bRequest <= TUSB_REQ_SYNCH_FRAME) { + TU_LOG_USBD(" %s", tu_str_std_request[p_request->bRequest]); + if (TUSB_REQ_GET_DESCRIPTOR != p_request->bRequest) TU_LOG_USBD("\r\n"); } #endif - switch ( p_request->bmRequestType_bit.recipient ) - { + switch ( p_request->bmRequestType_bit.recipient ) { //------------- Device Requests e.g in enumeration -------------// case TUSB_REQ_RCPT_DEVICE: - if ( TUSB_REQ_TYPE_CLASS == p_request->bmRequestType_bit.type ) - { + if ( TUSB_REQ_TYPE_CLASS == p_request->bmRequestType_bit.type ) { uint8_t const itf = tu_u16_low(p_request->wIndex); TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv)); @@ -654,15 +670,13 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const return invoke_class_control(rhport, driver, p_request); } - if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) - { + if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) { // Non standard request is not supported TU_BREAKPOINT(); return false; } - switch ( p_request->bRequest ) - { + switch ( p_request->bRequest ) { case TUSB_REQ_SET_ADDRESS: // Depending on mcu, status phase could be sent either before or after changing device address, // or even require stack to not response with status at all @@ -673,24 +687,20 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const _usbd_dev.addressed = 1; break; - case TUSB_REQ_GET_CONFIGURATION: - { + case TUSB_REQ_GET_CONFIGURATION: { uint8_t cfg_num = _usbd_dev.cfg_num; tud_control_xfer(rhport, p_request, &cfg_num, 1); } break; - case TUSB_REQ_SET_CONFIGURATION: - { + case TUSB_REQ_SET_CONFIGURATION: { uint8_t const cfg_num = (uint8_t) p_request->wValue; // Only process if new configure is different - if (_usbd_dev.cfg_num != cfg_num) - { - if ( _usbd_dev.cfg_num ) - { + if (_usbd_dev.cfg_num != cfg_num) { + if ( _usbd_dev.cfg_num ) { // already configured: need to clear all endpoints and driver first - TU_LOG(USBD_DBG, " Clear current Configuration (%u) before switching\r\n", _usbd_dev.cfg_num); + TU_LOG_USBD(" Clear current Configuration (%u) before switching\r\n", _usbd_dev.cfg_num); // close all non-control endpoints, cancel all pending transfers if any dcd_edpt_close_all(rhport); @@ -702,8 +712,14 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const _usbd_dev.speed = speed; // restore speed } - // switch to new configuration if not zero - if ( cfg_num ) TU_ASSERT( process_set_config(rhport, cfg_num) ); + // Handle the new configuration and execute the corresponding callback + if ( cfg_num ) { + // switch to new configuration if not zero + TU_ASSERT( process_set_config(rhport, cfg_num) ); + if ( tud_mount_cb ) tud_mount_cb(); + } else { + if ( tud_umount_cb ) tud_umount_cb(); + } } _usbd_dev.cfg_num = cfg_num; @@ -719,7 +735,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const // Only support remote wakeup for device feature TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue); - TU_LOG(USBD_DBG, " Enable Remote Wakeup\r\n"); + TU_LOG_USBD(" Enable Remote Wakeup\r\n"); // Host may enable remote wake up before suspending especially HID device _usbd_dev.remote_wakeup_en = true; @@ -730,22 +746,21 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const // Only support remote wakeup for device feature TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue); - TU_LOG(USBD_DBG, " Disable Remote Wakeup\r\n"); + TU_LOG_USBD(" Disable Remote Wakeup\r\n"); // Host may disable remote wake up after resuming _usbd_dev.remote_wakeup_en = false; tud_control_status(rhport, p_request); break; - case TUSB_REQ_GET_STATUS: - { + case TUSB_REQ_GET_STATUS: { // Device status bit mask // - Bit 0: Self Powered // - Bit 1: Remote Wakeup enabled uint16_t status = (uint16_t) ((_usbd_dev.self_powered ? 1u : 0u) | (_usbd_dev.remote_wakeup_en ? 2u : 0u)); tud_control_xfer(rhport, p_request, &status, 2); + break; } - break; // Unknown/Unsupported request default: TU_BREAKPOINT(); return false; @@ -753,8 +768,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const break; //------------- Class/Interface Specific Request -------------// - case TUSB_REQ_RCPT_INTERFACE: - { + case TUSB_REQ_RCPT_INTERFACE: { uint8_t const itf = tu_u16_low(p_request->wIndex); TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv)); @@ -763,25 +777,21 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const // all requests to Interface (STD or Class) is forwarded to class driver. // notable requests are: GET HID REPORT DESCRIPTOR, SET_INTERFACE, GET_INTERFACE - if ( !invoke_class_control(rhport, driver, p_request) ) - { + if ( !invoke_class_control(rhport, driver, p_request) ) { // For GET_INTERFACE and SET_INTERFACE, it is mandatory to respond even if the class // driver doesn't use alternate settings or implement this TU_VERIFY(TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type); - switch(p_request->bRequest) - { + switch(p_request->bRequest) { case TUSB_REQ_GET_INTERFACE: case TUSB_REQ_SET_INTERFACE: // Clear complete callback if driver set since it can also stall the request. usbd_control_set_complete_callback(NULL); - if (TUSB_REQ_GET_INTERFACE == p_request->bRequest) - { + if (TUSB_REQ_GET_INTERFACE == p_request->bRequest) { uint8_t alternate = 0; tud_control_xfer(rhport, p_request, &alternate, 1); - }else - { + }else { tud_control_status(rhport, p_request); } break; @@ -789,54 +799,42 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const default: return false; } } + break; } - break; //------------- Endpoint Request -------------// - case TUSB_REQ_RCPT_ENDPOINT: - { + case TUSB_REQ_RCPT_ENDPOINT: { uint8_t const ep_addr = tu_u16_low(p_request->wIndex); uint8_t const ep_num = tu_edpt_number(ep_addr); uint8_t const ep_dir = tu_edpt_dir(ep_addr); TU_ASSERT(ep_num < TU_ARRAY_SIZE(_usbd_dev.ep2drv) ); - usbd_class_driver_t const * driver = get_driver(_usbd_dev.ep2drv[ep_num][ep_dir]); - if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) - { + if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) { // Forward class request to its driver TU_VERIFY(driver); return invoke_class_control(rhport, driver, p_request); - } - else - { + } else { // Handle STD request to endpoint - switch ( p_request->bRequest ) - { - case TUSB_REQ_GET_STATUS: - { + switch ( p_request->bRequest ) { + case TUSB_REQ_GET_STATUS: { uint16_t status = usbd_edpt_stalled(rhport, ep_addr) ? 0x0001 : 0x0000; tud_control_xfer(rhport, p_request, &status, 2); } break; case TUSB_REQ_CLEAR_FEATURE: - case TUSB_REQ_SET_FEATURE: - { - if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) - { - if ( TUSB_REQ_CLEAR_FEATURE == p_request->bRequest ) - { + case TUSB_REQ_SET_FEATURE: { + if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) { + if ( TUSB_REQ_CLEAR_FEATURE == p_request->bRequest ) { usbd_edpt_clear_stall(rhport, ep_addr); - }else - { + }else { usbd_edpt_stall(rhport, ep_addr); } } - if (driver) - { + if (driver) { // Some classes such as USBTMC needs to clear/re-init its buffer when receiving CLEAR_FEATURE request // We will also forward std request targeted endpoint to class drivers as well @@ -852,14 +850,18 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const break; // Unknown/Unsupported request - default: TU_BREAKPOINT(); return false; + default: + TU_BREAKPOINT(); + return false; } } } break; // Unknown recipient - default: TU_BREAKPOINT(); return false; + default: + TU_BREAKPOINT(); + return false; } return true; @@ -913,7 +915,7 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num) if ( (sizeof(tusb_desc_interface_t) <= drv_len) && (drv_len <= remaining_len) ) { // Open successfully - TU_LOG(USBD_DBG, " %s opened\r\n", driver->name); + TU_LOG_USBD(" %s opened\r\n", driver->name); // Some drivers use 2 or more interfaces but may not have IAD e.g MIDI (always) or // BTH (even CDC) with class in device descriptor (single interface) @@ -956,9 +958,6 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num) TU_ASSERT(drv_id < TOTAL_DRIVER_COUNT); } - // invoke callback - if (tud_mount_cb) tud_mount_cb(); - return true; } @@ -972,7 +971,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const { case TUSB_DESC_DEVICE: { - TU_LOG(USBD_DBG, " Device\r\n"); + TU_LOG_USBD(" Device\r\n"); void* desc_device = (void*) (uintptr_t) tud_descriptor_device_cb(); @@ -996,7 +995,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const case TUSB_DESC_BOS: { - TU_LOG(USBD_DBG, " BOS\r\n"); + TU_LOG_USBD(" BOS\r\n"); // requested by host if USB > 2.0 ( i.e 2.1 or 3.x ) if (!tud_descriptor_bos_cb) return false; @@ -1018,12 +1017,12 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const if ( desc_type == TUSB_DESC_CONFIGURATION ) { - TU_LOG(USBD_DBG, " Configuration[%u]\r\n", desc_index); + TU_LOG_USBD(" Configuration[%u]\r\n", desc_index); desc_config = (uintptr_t) tud_descriptor_configuration_cb(desc_index); }else { // Host only request this after getting Device Qualifier descriptor - TU_LOG(USBD_DBG, " Other Speed Configuration\r\n"); + TU_LOG_USBD(" Other Speed Configuration\r\n"); TU_VERIFY( tud_descriptor_other_speed_configuration_cb ); desc_config = (uintptr_t) tud_descriptor_other_speed_configuration_cb(desc_index); } @@ -1039,7 +1038,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const case TUSB_DESC_STRING: { - TU_LOG(USBD_DBG, " String[%u]\r\n", desc_index); + TU_LOG_USBD(" String[%u]\r\n", desc_index); // String Descriptor always uses the desc set from user uint8_t const* desc_str = (uint8_t const*) tud_descriptor_string_cb(desc_index, tu_le16toh(p_request->wIndex)); @@ -1052,7 +1051,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const case TUSB_DESC_DEVICE_QUALIFIER: { - TU_LOG(USBD_DBG, " Device Qualifier\r\n"); + TU_LOG_USBD(" Device Qualifier\r\n"); TU_VERIFY( tud_descriptor_device_qualifier_cb ); @@ -1071,66 +1070,69 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const //--------------------------------------------------------------------+ // DCD Event Handler //--------------------------------------------------------------------+ -TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const * event, bool in_isr) -{ - switch (event->event_id) - { +TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr) { + bool send = false; + switch (event->event_id) { case DCD_EVENT_UNPLUGGED: - _usbd_dev.connected = 0; - _usbd_dev.addressed = 0; - _usbd_dev.cfg_num = 0; - _usbd_dev.suspended = 0; - osal_queue_send(_usbd_q, event, in_isr); - break; + _usbd_dev.connected = 0; + _usbd_dev.addressed = 0; + _usbd_dev.cfg_num = 0; + _usbd_dev.suspended = 0; + send = true; + break; case DCD_EVENT_SUSPEND: // NOTE: When plugging/unplugging device, the D+/D- state are unstable and // can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ). // In addition, some MCUs such as SAMD or boards that haven no VBUS detection cannot distinguish // suspended vs disconnected. We will skip handling SUSPEND/RESUME event if not currently connected - if ( _usbd_dev.connected ) - { + if (_usbd_dev.connected) { _usbd_dev.suspended = 1; - osal_queue_send(_usbd_q, event, in_isr); + send = true; } - break; + break; case DCD_EVENT_RESUME: // skip event if not connected (especially required for SAMD) - if ( _usbd_dev.connected ) - { + if (_usbd_dev.connected) { _usbd_dev.suspended = 0; - osal_queue_send(_usbd_q, event, in_isr); + send = true; } - break; + break; case DCD_EVENT_SOF: - // SOF driver handler in ISR context - for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) - { - usbd_class_driver_t const * driver = get_driver(i); - if (driver && driver->sof) - { - driver->sof(event->rhport, event->sof.frame_count); - } - } - // Some MCUs after running dcd_remote_wakeup() does not have way to detect the end of remote wakeup // which last 1-15 ms. DCD can use SOF as a clear indicator that bus is back to operational - if ( _usbd_dev.suspended ) - { + if (_usbd_dev.suspended) { _usbd_dev.suspended = 0; - dcd_event_t const event_resume = { .rhport = event->rhport, .event_id = DCD_EVENT_RESUME }; - osal_queue_send(_usbd_q, &event_resume, in_isr); + dcd_event_t const event_resume = {.rhport = event->rhport, .event_id = DCD_EVENT_RESUME}; + queue_event(&event_resume, in_isr); + } + + // SOF driver handler in ISR context + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) { + usbd_class_driver_t const* driver = get_driver(i); + if (driver && driver->sof) { + driver->sof(event->rhport, event->sof.frame_count); + } } // skip osal queue for SOF in usbd task - break; + break; + + case DCD_EVENT_SETUP_RECEIVED: + _usbd_dev.setup_count++; + send = true; + break; default: - osal_queue_send(_usbd_q, event, in_isr); - break; + send = true; + break; + } + + if (send) { + queue_event(event, in_isr); } } @@ -1174,26 +1176,22 @@ bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count } // Helper to defer an isr function -void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr) -{ - dcd_event_t event = - { +void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr) { + dcd_event_t event = { .rhport = 0, .event_id = USBD_EVENT_FUNC_CALL, }; - event.func_call.func = func; event.func_call.param = param; - dcd_event_handler(&event, in_isr); + queue_event(&event, in_isr); } //--------------------------------------------------------------------+ // USBD Endpoint API //--------------------------------------------------------------------+ -bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) -{ +bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { rhport = _usbd_rhport; TU_ASSERT(tu_edpt_number(desc_ep->bEndpointAddress) < CFG_TUD_ENDPPOINT_MAX); @@ -1202,59 +1200,59 @@ bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) return dcd_edpt_open(rhport, desc_ep); } -bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr) -{ +bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr) { (void) rhport; // TODO add this check later, also make sure we don't starve an out endpoint while suspending // TU_VERIFY(tud_ready()); - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir]; return tu_edpt_claim(ep_state, _usbd_mutex); } -bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr) -{ +bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr) { (void) rhport; - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir]; return tu_edpt_release(ep_state, _usbd_mutex); } -bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) -{ +bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { rhport = _usbd_rhport; uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); // TODO skip ready() check for now since enumeration also use this API // TU_VERIFY(tud_ready()); - TU_LOG(USBD_DBG, " Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes); + TU_LOG_USBD(" Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes); +#if CFG_TUD_LOG_LEVEL >= 3 + if(dir == TUSB_DIR_IN) { + TU_LOG_MEM(CFG_TUD_LOG_LEVEL, buffer, total_bytes, 2); + } +#endif // Attempt to transfer on a busy endpoint, sound like an race condition ! TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0); // Set busy first since the actual transfer can be complete before dcd_edpt_xfer() // could return and USBD task can preempt and clear the busy - _usbd_dev.ep_status[epnum][dir].busy = true; + _usbd_dev.ep_status[epnum][dir].busy = 1; - if ( dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes) ) - { + if (dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes)) { return true; - }else - { + } else { // DCD error, mark endpoint as ready to allow next transfer - _usbd_dev.ep_status[epnum][dir].busy = false; + _usbd_dev.ep_status[epnum][dir].busy = 0; _usbd_dev.ep_status[epnum][dir].claimed = 0; - TU_LOG(USBD_DBG, "FAILED\r\n"); + TU_LOG_USBD("FAILED\r\n"); TU_BREAKPOINT(); return false; } @@ -1264,117 +1262,100 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t // bytes should be written and second to keep the return value free to give back a boolean // success message. If total_bytes is too big, the FIFO will copy only what is available // into the USB buffer! -bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) -{ +bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t total_bytes) { rhport = _usbd_rhport; uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); - TU_LOG(USBD_DBG, " Queue ISO EP %02X with %u bytes ... ", ep_addr, total_bytes); + TU_LOG_USBD(" Queue ISO EP %02X with %u bytes ... ", ep_addr, total_bytes); // Attempt to transfer on a busy endpoint, sound like an race condition ! TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0); // Set busy first since the actual transfer can be complete before dcd_edpt_xfer() could return // and usbd task can preempt and clear the busy - _usbd_dev.ep_status[epnum][dir].busy = true; + _usbd_dev.ep_status[epnum][dir].busy = 1; - if (dcd_edpt_xfer_fifo(rhport, ep_addr, ff, total_bytes)) - { - TU_LOG(USBD_DBG, "OK\r\n"); + if (dcd_edpt_xfer_fifo(rhport, ep_addr, ff, total_bytes)) { + TU_LOG_USBD("OK\r\n"); return true; - }else - { + } else { // DCD error, mark endpoint as ready to allow next transfer - _usbd_dev.ep_status[epnum][dir].busy = false; + _usbd_dev.ep_status[epnum][dir].busy = 0; _usbd_dev.ep_status[epnum][dir].claimed = 0; - TU_LOG(USBD_DBG, "failed\r\n"); + TU_LOG_USBD("failed\r\n"); TU_BREAKPOINT(); return false; } } -bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr) -{ +bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr) { (void) rhport; uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); return _usbd_dev.ep_status[epnum][dir].busy; } -void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr) -{ +void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { rhport = _usbd_rhport; uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); // only stalled if currently cleared - if ( !_usbd_dev.ep_status[epnum][dir].stalled ) - { - TU_LOG(USBD_DBG, " Stall EP %02X\r\n", ep_addr); - dcd_edpt_stall(rhport, ep_addr); - _usbd_dev.ep_status[epnum][dir].stalled = true; - _usbd_dev.ep_status[epnum][dir].busy = true; - } + TU_LOG_USBD(" Stall EP %02X\r\n", ep_addr); + dcd_edpt_stall(rhport, ep_addr); + _usbd_dev.ep_status[epnum][dir].stalled = 1; + _usbd_dev.ep_status[epnum][dir].busy = 1; } -void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) -{ +void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { rhport = _usbd_rhport; uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); // only clear if currently stalled - if ( _usbd_dev.ep_status[epnum][dir].stalled ) - { - TU_LOG(USBD_DBG, " Clear Stall EP %02X\r\n", ep_addr); - dcd_edpt_clear_stall(rhport, ep_addr); - _usbd_dev.ep_status[epnum][dir].stalled = false; - _usbd_dev.ep_status[epnum][dir].busy = false; - } + TU_LOG_USBD(" Clear Stall EP %02X\r\n", ep_addr); + dcd_edpt_clear_stall(rhport, ep_addr); + _usbd_dev.ep_status[epnum][dir].stalled = 0; + _usbd_dev.ep_status[epnum][dir].busy = 0; } -bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr) -{ +bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr) { (void) rhport; uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); return _usbd_dev.ep_status[epnum][dir].stalled; } /** * usbd_edpt_close will disable an endpoint. - * * In progress transfers on this EP may be delivered after this call. - * */ -void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) -{ +void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) { rhport = _usbd_rhport; TU_ASSERT(dcd_edpt_close, /**/); - TU_LOG(USBD_DBG, " CLOSING Endpoint: 0x%02X\r\n", ep_addr); + TU_LOG_USBD(" CLOSING Endpoint: 0x%02X\r\n", ep_addr); uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); dcd_edpt_close(rhport, ep_addr); - _usbd_dev.ep_status[epnum][dir].stalled = false; - _usbd_dev.ep_status[epnum][dir].busy = false; - _usbd_dev.ep_status[epnum][dir].claimed = false; + _usbd_dev.ep_status[epnum][dir].stalled = 0; + _usbd_dev.ep_status[epnum][dir].busy = 0; + _usbd_dev.ep_status[epnum][dir].claimed = 0; return; } -void usbd_sof_enable(uint8_t rhport, bool en) -{ +void usbd_sof_enable(uint8_t rhport, bool en) { rhport = _usbd_rhport; // TODO: Check needed if all drivers including the user sof_cb does not need an active SOF ISR any more. @@ -1382,8 +1363,7 @@ void usbd_sof_enable(uint8_t rhport, bool en) dcd_sof_enable(rhport, en); } -bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) -{ +bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { rhport = _usbd_rhport; TU_ASSERT(dcd_edpt_iso_alloc); @@ -1392,20 +1372,19 @@ bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packe return dcd_edpt_iso_alloc(rhport, ep_addr, largest_packet_size); } -bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) -{ +bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { rhport = _usbd_rhport; uint8_t const epnum = tu_edpt_number(desc_ep->bEndpointAddress); - uint8_t const dir = tu_edpt_dir(desc_ep->bEndpointAddress); + uint8_t const dir = tu_edpt_dir(desc_ep->bEndpointAddress); TU_ASSERT(dcd_edpt_iso_activate); TU_ASSERT(epnum < CFG_TUD_ENDPPOINT_MAX); TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed)); - _usbd_dev.ep_status[epnum][dir].stalled = false; - _usbd_dev.ep_status[epnum][dir].busy = false; - _usbd_dev.ep_status[epnum][dir].claimed = false; + _usbd_dev.ep_status[epnum][dir].stalled = 0; + _usbd_dev.ep_status[epnum][dir].busy = 0; + _usbd_dev.ep_status[epnum][dir].claimed = 0; return dcd_edpt_iso_activate(rhport, desc_ep); } diff --git a/test-devices/loopback-stm32/lib/tinyusb/device/usbd.h b/test-devices/loopback-stm32/lib/tinyusb/device/usbd.h index 255e5a84..f3673404 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/device/usbd.h +++ b/test-devices/loopback-stm32/lib/tinyusb/device/usbd.h @@ -37,9 +37,12 @@ extern "C" { // Application API //--------------------------------------------------------------------+ -// Init device stack +// Init device stack on roothub port bool tud_init (uint8_t rhport); +// Deinit device stack on roothub port +bool tud_deinit(uint8_t rhport); + // Check if device stack is already initialized bool tud_inited(void); @@ -50,8 +53,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr); // Task function should be called in main/rtos loop TU_ATTR_ALWAYS_INLINE static inline -void tud_task (void) -{ +void tud_task (void) { tud_task_ext(UINT32_MAX, false); } @@ -80,8 +82,7 @@ bool tud_suspended(void); // Check if device is ready to transfer TU_ATTR_ALWAYS_INLINE static inline -bool tud_ready(void) -{ +bool tud_ready(void) { return tud_mounted() && !tud_suspended(); } @@ -148,6 +149,9 @@ TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en); // Invoked when usb bus is resumed TU_ATTR_WEAK void tud_resume_cb(void); +// Invoked when there is a new usb event, which need to be processed by tud_task()/tud_task_ext() +void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr); + // Invoked when received control request with VENDOR TYPE TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); @@ -217,8 +221,8 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\ /* CDC Call */\ 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (uint8_t)((_itfnum) + 1),\ - /* CDC ACM: support line request */\ - 4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 2,\ + /* CDC ACM: support line request + send break */\ + 4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 6,\ /* CDC Union */\ 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\ /* Endpoint Notification */\ @@ -347,8 +351,8 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Standard Interface Association Descriptor (IAD) */ #define TUD_AUDIO_DESC_IAD_LEN 8 -#define TUD_AUDIO_DESC_IAD(_firstitfs, _nitfs, _stridx) \ - TUD_AUDIO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, _firstitfs, _nitfs, TUSB_CLASS_AUDIO, AUDIO_FUNCTION_SUBCLASS_UNDEFINED, AUDIO_FUNC_PROTOCOL_CODE_V2, _stridx +#define TUD_AUDIO_DESC_IAD(_firstitf, _nitfs, _stridx) \ + TUD_AUDIO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, _firstitf, _nitfs, TUSB_CLASS_AUDIO, AUDIO_FUNCTION_SUBCLASS_UNDEFINED, AUDIO_FUNC_PROTOCOL_CODE_V2, _stridx /* Standard AC Interface Descriptor(4.7.1) */ #define TUD_AUDIO_DESC_STD_AC_LEN 9 @@ -392,6 +396,11 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb // For more channels, add definitions here +/* Standard AC Interrupt Endpoint Descriptor(4.8.2.1) */ +#define TUD_AUDIO_DESC_STD_AC_INT_EP_LEN 7 +#define TUD_AUDIO_DESC_STD_AC_INT_EP(_ep, _interval) \ + TUD_AUDIO_DESC_STD_AC_INT_EP_LEN, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(6), _interval + /* Standard AS Interface Descriptor(4.9.1) */ #define TUD_AUDIO_DESC_STD_AS_INT_LEN 9 #define TUD_AUDIO_DESC_STD_AS_INT(_itfnum, _altset, _nEPs, _stridx) \ @@ -420,7 +429,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */ #define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN 7 #define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_ep, _interval) \ - TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_NO_SYNC | TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_NO_SYNC | (uint8_t)TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval // AUDIO simple descriptor (UAC2) for 1 microphone input // - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source @@ -443,7 +452,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb #define TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ /* Standard Interface Association Descriptor (IAD) */\ - TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ @@ -467,7 +476,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) @@ -492,7 +501,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb #define TUD_AUDIO_MIC_FOUR_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ /* Standard Interface Association Descriptor (IAD) */\ - TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ @@ -516,7 +525,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) @@ -540,7 +549,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb #define TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize, _epfb) \ /* Standard Interface Association Descriptor (IAD) */\ - TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ @@ -564,7 +573,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\ /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\ @@ -773,10 +782,6 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb #define TUD_BT_PROTOCOL_PRIMARY_CONTROLLER 0x01 #define TUD_BT_PROTOCOL_AMP_CONTROLLER 0x02 -#ifndef CFG_TUD_BTH_ISO_ALT_COUNT -#define CFG_TUD_BTH_ISO_ALT_COUNT 0 -#endif - // Length of template descriptor: 38 bytes + number of ISO alternatives * 23 #define TUD_BTH_DESC_LEN (8 + 9 + 7 + 7 + 7 + (CFG_TUD_BTH_ISO_ALT_COUNT) * (9 + 7 + 7)) diff --git a/test-devices/loopback-stm32/lib/tinyusb/device/usbd_control.c b/test-devices/loopback-stm32/lib/tinyusb/device/usbd_control.c index ea8eef28..35cce1f7 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/device/usbd_control.c +++ b/test-devices/loopback-stm32/lib/tinyusb/device/usbd_control.c @@ -32,30 +32,38 @@ #include "tusb.h" #include "device/usbd_pvt.h" -#if CFG_TUSB_DEBUG >= 2 +//--------------------------------------------------------------------+ +// Callback weak stubs (called if application does not provide) +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) { + (void) rhport; + (void) request; +} + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL extern void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback); #endif -enum -{ +enum { EDPT_CTRL_OUT = 0x00, - EDPT_CTRL_IN = 0x80 + EDPT_CTRL_IN = 0x80 }; -typedef struct -{ +typedef struct { tusb_control_request_t request; - uint8_t* buffer; uint16_t data_len; uint16_t total_xferred; - usbd_control_xfer_cb_t complete_cb; } usbd_control_xfer_t; tu_static usbd_control_xfer_t _ctrl_xfer; -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN +CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t _usbd_ctrl_buf[CFG_TUD_ENDPOINT0_SIZE]; //--------------------------------------------------------------------+ @@ -63,20 +71,18 @@ tu_static uint8_t _usbd_ctrl_buf[CFG_TUD_ENDPOINT0_SIZE]; //--------------------------------------------------------------------+ // Queue ZLP status transaction -static inline bool _status_stage_xact(uint8_t rhport, tusb_control_request_t const * request) -{ +static inline bool _status_stage_xact(uint8_t rhport, tusb_control_request_t const* request) { // Opposite to endpoint in Data Phase uint8_t const ep_addr = request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN; return usbd_edpt_xfer(rhport, ep_addr, NULL, 0); } // Status phase -bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request) -{ - _ctrl_xfer.request = (*request); - _ctrl_xfer.buffer = NULL; +bool tud_control_status(uint8_t rhport, tusb_control_request_t const* request) { + _ctrl_xfer.request = (*request); + _ctrl_xfer.buffer = NULL; _ctrl_xfer.total_xferred = 0; - _ctrl_xfer.data_len = 0; + _ctrl_xfer.data_len = 0; return _status_stage_xact(rhport, request); } @@ -84,16 +90,15 @@ bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request) // Queue a transaction in Data Stage // Each transaction has up to Endpoint0's max packet size. // This function can also transfer an zero-length packet -static bool _data_stage_xact(uint8_t rhport) -{ - uint16_t const xact_len = tu_min16(_ctrl_xfer.data_len - _ctrl_xfer.total_xferred, CFG_TUD_ENDPOINT0_SIZE); +static bool _data_stage_xact(uint8_t rhport) { + uint16_t const xact_len = tu_min16(_ctrl_xfer.data_len - _ctrl_xfer.total_xferred, + CFG_TUD_ENDPOINT0_SIZE); uint8_t ep_addr = EDPT_CTRL_OUT; - if ( _ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN ) - { + if (_ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN) { ep_addr = EDPT_CTRL_IN; - if ( xact_len ) { + if (xact_len) { TU_VERIFY(0 == tu_memcpy_s(_usbd_ctrl_buf, CFG_TUD_ENDPOINT0_SIZE, _ctrl_xfer.buffer, xact_len)); } } @@ -103,29 +108,24 @@ static bool _data_stage_xact(uint8_t rhport) // Transmit data to/from the control endpoint. // If the request's wLength is zero, a status packet is sent instead. -bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len) -{ - _ctrl_xfer.request = (*request); - _ctrl_xfer.buffer = (uint8_t*) buffer; +bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const* request, void* buffer, uint16_t len) { + _ctrl_xfer.request = (*request); + _ctrl_xfer.buffer = (uint8_t*) buffer; _ctrl_xfer.total_xferred = 0U; - _ctrl_xfer.data_len = tu_min16(len, request->wLength); + _ctrl_xfer.data_len = tu_min16(len, request->wLength); - if (request->wLength > 0U) - { - if(_ctrl_xfer.data_len > 0U) - { + if (request->wLength > 0U) { + if (_ctrl_xfer.data_len > 0U) { TU_ASSERT(buffer); } // TU_LOG2(" Control total data length is %u bytes\r\n", _ctrl_xfer.data_len); // Data stage - TU_ASSERT( _data_stage_xact(rhport) ); - } - else - { + TU_ASSERT(_data_stage_xact(rhport)); + } else { // Status stage - TU_ASSERT( _status_stage_xact(rhport, request) ); + TU_ASSERT(_status_stage_xact(rhport, request)); } return true; @@ -134,49 +134,42 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, vo //--------------------------------------------------------------------+ // USBD API //--------------------------------------------------------------------+ - void usbd_control_reset(void); -void usbd_control_set_request(tusb_control_request_t const *request); -void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp ); -bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); +void usbd_control_set_request(tusb_control_request_t const* request); +void usbd_control_set_complete_callback(usbd_control_xfer_cb_t fp); +bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); -void usbd_control_reset(void) -{ +void usbd_control_reset(void) { tu_varclr(&_ctrl_xfer); } // Set complete callback -void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp ) -{ +void usbd_control_set_complete_callback(usbd_control_xfer_cb_t fp) { _ctrl_xfer.complete_cb = fp; } // for dcd_set_address where DCD is responsible for status response -void usbd_control_set_request(tusb_control_request_t const *request) -{ - _ctrl_xfer.request = (*request); - _ctrl_xfer.buffer = NULL; +void usbd_control_set_request(tusb_control_request_t const* request) { + _ctrl_xfer.request = (*request); + _ctrl_xfer.buffer = NULL; _ctrl_xfer.total_xferred = 0; - _ctrl_xfer.data_len = 0; + _ctrl_xfer.data_len = 0; } // callback when a transaction complete on // - DATA stage of control endpoint or // - Status stage -bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ +bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { (void) result; // Endpoint Address is opposite to direction bit, this is Status Stage complete event - if ( tu_edpt_dir(ep_addr) != _ctrl_xfer.request.bmRequestType_bit.direction ) - { + if (tu_edpt_dir(ep_addr) != _ctrl_xfer.request.bmRequestType_bit.direction) { TU_ASSERT(0 == xferred_bytes); // invoke optional dcd hook if available - if (dcd_edpt0_status_complete) dcd_edpt0_status_complete(rhport, &_ctrl_xfer.request); + dcd_edpt0_status_complete(rhport, &_ctrl_xfer.request); - if (_ctrl_xfer.complete_cb) - { + if (_ctrl_xfer.complete_cb) { // TODO refactor with usbd_driver_print_control_complete_name _ctrl_xfer.complete_cb(rhport, CONTROL_STAGE_ACK, &_ctrl_xfer.request); } @@ -184,11 +177,10 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result return true; } - if ( _ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_OUT ) - { + if (_ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_OUT) { TU_VERIFY(_ctrl_xfer.buffer); memcpy(_ctrl_xfer.buffer, _usbd_ctrl_buf, xferred_bytes); - TU_LOG_MEM(2, _usbd_ctrl_buf, xferred_bytes, 2); + TU_LOG_MEM(CFG_TUD_LOG_LEVEL, _usbd_ctrl_buf, xferred_bytes, 2); } _ctrl_xfer.total_xferred += (uint16_t) xferred_bytes; @@ -196,37 +188,32 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result // Data Stage is complete when all request's length are transferred or // a short packet is sent including zero-length packet. - if ( (_ctrl_xfer.request.wLength == _ctrl_xfer.total_xferred) || (xferred_bytes < CFG_TUD_ENDPOINT0_SIZE) ) - { + if ((_ctrl_xfer.request.wLength == _ctrl_xfer.total_xferred) || + (xferred_bytes < CFG_TUD_ENDPOINT0_SIZE)) { // DATA stage is complete bool is_ok = true; // invoke complete callback if set // callback can still stall control in status phase e.g out data does not make sense - if ( _ctrl_xfer.complete_cb ) - { - #if CFG_TUSB_DEBUG >= 2 + if (_ctrl_xfer.complete_cb) { + #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL usbd_driver_print_control_complete_name(_ctrl_xfer.complete_cb); #endif is_ok = _ctrl_xfer.complete_cb(rhport, CONTROL_STAGE_DATA, &_ctrl_xfer.request); } - if ( is_ok ) - { + if (is_ok) { // Send status - TU_ASSERT( _status_stage_xact(rhport, &_ctrl_xfer.request) ); - }else - { + TU_ASSERT(_status_stage_xact(rhport, &_ctrl_xfer.request)); + } else { // Stall both IN and OUT control endpoint dcd_edpt_stall(rhport, EDPT_CTRL_OUT); dcd_edpt_stall(rhport, EDPT_CTRL_IN); } - } - else - { + } else { // More data to transfer - TU_ASSERT( _data_stage_xact(rhport) ); + TU_ASSERT(_data_stage_xact(rhport)); } return true; diff --git a/test-devices/loopback-stm32/lib/tinyusb/device/usbd_pvt.h b/test-devices/loopback-stm32/lib/tinyusb/device/usbd_pvt.h index 8393d346..47752f32 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/device/usbd_pvt.h +++ b/test-devices/loopback-stm32/lib/tinyusb/device/usbd_pvt.h @@ -23,8 +23,8 @@ * * This file is part of the TinyUSB stack. */ -#ifndef USBD_PVT_H_ -#define USBD_PVT_H_ +#ifndef _TUSB_USBD_PVT_H_ +#define _TUSB_USBD_PVT_H_ #include "osal/osal.h" #include "common/tusb_fifo.h" @@ -33,17 +33,19 @@ extern "C" { #endif +#define TU_LOG_USBD(...) TU_LOG(CFG_TUD_LOG_LEVEL, __VA_ARGS__) + //--------------------------------------------------------------------+ // Class Driver API //--------------------------------------------------------------------+ -typedef struct -{ - #if CFG_TUSB_DEBUG >= 2 +typedef struct { + #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL char const* name; #endif void (* init ) (void); + bool (* deinit ) (void); void (* reset ) (uint8_t rhport); uint16_t (* open ) (uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t max_len); bool (* control_xfer_cb ) (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); @@ -52,7 +54,7 @@ typedef struct } usbd_class_driver_t; // Invoked when initializing device stack to get additional class drivers. -// Can optionally implemented by application to extend/overwrite class driver support. +// Can be implemented by application to extend/overwrite class driver support. // Note: The drivers array must be accessible at all time when stack is active usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) TU_ATTR_WEAK; @@ -104,8 +106,7 @@ bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endp // Check if endpoint is ready (not busy and not stalled) TU_ATTR_ALWAYS_INLINE static inline -bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr) -{ +bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr) { return !usbd_edpt_busy(rhport, ep_addr) && !usbd_edpt_stalled(rhport, ep_addr); } @@ -117,11 +118,10 @@ void usbd_sof_enable(uint8_t rhport, bool en); *------------------------------------------------------------------*/ bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in); -void usbd_defer_func( osal_task_func_t func, void* param, bool in_isr ); - +void usbd_defer_func(osal_task_func_t func, void *param, bool in_isr); #ifdef __cplusplus } #endif -#endif /* USBD_PVT_H_ */ +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/hwcfg_list.md b/test-devices/loopback-stm32/lib/tinyusb/dwc2/hwcfg_list.md deleted file mode 100644 index b5590da0..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/dwc2/hwcfg_list.md +++ /dev/null @@ -1,777 +0,0 @@ -# DWC2 Hardware Configuration Registers - -## Broadcom BCM2711 (Pi4) - -dwc2->guid = 2708A000 -dwc2->gsnpsid = 4F54280A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 228DDD50 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 2 -hw_cfg2->point2point = 0 -hw_cfg2->hs_phy_type = 1 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 7 -hw_cfg2->num_host_ch = 7 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 0 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = FF000E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 0 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 0 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 0 -hw_cfg3->lpm_mode = 0 -hw_cfg3->total_fifo_size = 4080 - -dwc2->ghwcfg4 = 1FF00020 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 0 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 0 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 15 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## EFM32GG FS - -dwc2->guid = 0 -dwc2->gsnpsid = 4F54330A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 228F5910 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 2 -hw_cfg2->point2point = 0 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 6 -hw_cfg2->num_host_ch = 13 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 0 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 1F204E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 0 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 1 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 0 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 0 -hw_cfg3->lpm_mode = 0 -hw_cfg3->total_fifo_size = 498 - -dwc2->ghwcfg4 = 1BF08030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 2 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 13 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## ESP32-S2 Fullspeed - -dwc2->guid = 0 -dwc2->gsnpsid = 4F54400A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 224DD930 -hw_cfg2->op_mode = 2 -hw_cfg2->arch = 3 -hw_cfg2->point2point = 0 -hw_cfg2->hs_phy_type = 1 -hw_cfg2->fs_phy_type = 2 -hw_cfg2->num_dev_ep = 6 -hw_cfg2->num_host_ch = 9 -hw_cfg2->period_channel_support = 0 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 1 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 22 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = C804B5 -hw_cfg3->xfer_size_width = 10 -hw_cfg3->packet_size_width = 5 -hw_cfg3->otg_enable = 0 -hw_cfg3->i2c_enable = 0 -hw_cfg3->vendor_ctrl_itf = 1 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 1 -hw_cfg3->otg_adp_support = 1 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 1 -hw_cfg3->lpm_mode = 0 -hw_cfg3->total_fifo_size = 23130 - -dwc2->ghwcfg4 = D3F0A030 -hw_cfg4->num_dev_period_in_ep = 10 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 0 -hw_cfg4->hibernation = 1 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 1 -hw_cfg4->acg_enable = 1 -hw_cfg4->utmi_phy_data_width = 1 -hw_cfg4->dev_ctrl_ep_num = 10 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 0 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 0 -hw_cfg4->dedicated_fifos = 0 -hw_cfg4->num_dev_in_eps = 13 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 1 - -## STM32F407 and STM32F207 - -STM32F407 and STM32F207 are exactly the same - -### STM32F407 Fullspeed - -dwc2->guid = 1200 -dwc2->gsnpsid = 4F54281A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229DCD20 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 0 -hw_cfg2->point2point = 1 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 3 -hw_cfg2->num_host_ch = 7 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 20001E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 1 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 0 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 0 -hw_cfg3->lpm_mode = 0 -hw_cfg3->total_fifo_size = 512 - -dwc2->ghwcfg4 = FF08030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 2 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 7 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -### STM32F407 Highspeed - -dwc2->guid = 1100 -dwc2->gsnpsid = 4F54281A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229ED590 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 2 -hw_cfg2->point2point = 0 -hw_cfg2->hs_phy_type = 2 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 5 -hw_cfg2->num_host_ch = 11 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 3F403E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 1 -hw_cfg3->vendor_ctrl_itf = 1 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 0 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 0 -hw_cfg3->lpm_mode = 0 -hw_cfg3->total_fifo_size = 1012 - -dwc2->ghwcfg4 = 17F00030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 0 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 11 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## STM32F411 Fullspeed - -dwc2->guid = 1200 -dwc2->gsnpsid = 4F54281A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229DCD20 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 0 -hw_cfg2->point2point = 1 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 3 -hw_cfg2->num_host_ch = 7 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 20001E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 1 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 0 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 0 -hw_cfg3->lpm_mode = 0 -hw_cfg3->total_fifo_size = 512 - -dwc2->ghwcfg4 = FF08030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 2 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 7 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## STM32F412 FS - -dwc2->guid = 2000 -dwc2->gsnpsid = 4F54320A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229ED520 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 0 -hw_cfg2->point2point = 1 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 5 -hw_cfg2->num_host_ch = 11 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 200D1E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 1 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 1 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 1 -hw_cfg3->lpm_mode = 1 -hw_cfg3->total_fifo_size = 512 - -dwc2->ghwcfg4 = 17F08030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 2 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 11 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## STM32F723 - -### STM32F723 HighSpeed - -dwc2->guid = 3100 -dwc2->gsnpsid = 4F54330A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229FE1D0 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 2 -hw_cfg2->point2point = 0 -hw_cfg2->hs_phy_type = 3 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 8 -hw_cfg2->num_host_ch = 15 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 3EED2E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 0 -hw_cfg3->vendor_ctrl_itf = 1 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 1 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 1 -hw_cfg3->lpm_mode = 1 -hw_cfg3->total_fifo_size = 1006 - -dwc2->ghwcfg4 = 23F00030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 0 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 1 -hw_cfg4->dma_desc_enable = 1 -hw_cfg4->dma_dynamic = 0 - -### STM32F723 Fullspeed - -dwc2->guid = 3000 -dwc2->gsnpsid = 4F54330A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229ED520 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 0 -hw_cfg2->point2point = 1 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 5 -hw_cfg2->num_host_ch = 11 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 200D1E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 1 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 1 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 1 -hw_cfg3->lpm_mode = 1 -hw_cfg3->total_fifo_size = 512 - -dwc2->ghwcfg4 = 17F08030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 2 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 11 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## STM32F767 FS - -dwc2->guid = 2000 -dwc2->gsnpsid = 4F54320A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229ED520 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 0 -hw_cfg2->point2point = 1 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 5 -hw_cfg2->num_host_ch = 11 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 200D1E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 1 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 1 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 1 -hw_cfg3->lpm_mode = 1 -hw_cfg3->total_fifo_size = 512 - -dwc2->ghwcfg4 = 17F08030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 2 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 11 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## STM32H743 (both cores HS) - -dwc2->guid = 2300 -dwc2->gsnpsid = 4F54330A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229FE190 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 2 -hw_cfg2->point2point = 0 -hw_cfg2->hs_phy_type = 2 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 8 -hw_cfg2->num_host_ch = 15 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 3B8D2E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 0 -hw_cfg3->vendor_ctrl_itf = 1 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 1 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 1 -hw_cfg3->lpm_mode = 1 -hw_cfg3->total_fifo_size = 952 - -dwc2->ghwcfg4 = E3F00030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 0 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 1 -hw_cfg4->dma_desc_enable = 1 -hw_cfg4->dma_dynamic = 1 - -## STM32L476 FS - -dwc2->guid = 2000 -dwc2->gsnpsid = 4F54310A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 229ED520 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 0 -hw_cfg2->point2point = 1 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 5 -hw_cfg2->num_host_ch = 11 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 1 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 200D1E8 -hw_cfg3->xfer_size_width = 8 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 1 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 1 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 1 -hw_cfg3->lpm_mode = 1 -hw_cfg3->total_fifo_size = 512 - -dwc2->ghwcfg4 = 17F08030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 2 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 11 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## GD32VF103 Fullspeed - -dwc2->guid = 1000 -dwc2->gsnpsid = 0 -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 0 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 0 -hw_cfg2->point2point = 0 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 0 -hw_cfg2->num_dev_ep = 0 -hw_cfg2->num_host_ch = 0 -hw_cfg2->period_channel_support = 0 -hw_cfg2->enable_dynamic_fifo = 0 -hw_cfg2->mul_cpu_int = 0 -hw_cfg2->nperiod_tx_q_depth = 0 -hw_cfg2->host_period_tx_q_depth = 0 -hw_cfg2->dev_token_q_depth = 0 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 0 -hw_cfg3->xfer_size_width = 0 -hw_cfg3->packet_size_width = 0 -hw_cfg3->otg_enable = 0 -hw_cfg3->i2c_enable = 0 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 0 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 0 -hw_cfg3->lpm_mode = 0 -hw_cfg3->total_fifo_size = 0 - -dwc2->ghwcfg4 = 0 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 0 -hw_cfg4->ahb_freq_min = 0 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 0 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 0 -hw_cfg4->vbus_valid_filter_enabled = 0 -hw_cfg4->a_valid_filter_enabled = 0 -hw_cfg4->b_valid_filter_enabled = 0 -hw_cfg4->dedicated_fifos = 0 -hw_cfg4->num_dev_in_eps = 0 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 0 - -## XMC4500 - -dwc2->guid = AEC000 -dwc2->gsnpsid = 4F54292A -dwc2->ghwcfg1 = 0 - -dwc2->ghwcfg2 = 228F5930 -hw_cfg2->op_mode = 0 -hw_cfg2->arch = 2 -hw_cfg2->point2point = 1 -hw_cfg2->hs_phy_type = 0 -hw_cfg2->fs_phy_type = 1 -hw_cfg2->num_dev_ep = 6 -hw_cfg2->num_host_ch = 13 -hw_cfg2->period_channel_support = 1 -hw_cfg2->enable_dynamic_fifo = 1 -hw_cfg2->mul_cpu_int = 0 -hw_cfg2->nperiod_tx_q_depth = 2 -hw_cfg2->host_period_tx_q_depth = 2 -hw_cfg2->dev_token_q_depth = 8 -hw_cfg2->otg_enable_ic_usb = 0 - -dwc2->ghwcfg3 = 27A01E5 -hw_cfg3->xfer_size_width = 5 -hw_cfg3->packet_size_width = 6 -hw_cfg3->otg_enable = 1 -hw_cfg3->i2c_enable = 1 -hw_cfg3->vendor_ctrl_itf = 0 -hw_cfg3->optional_feature_removed = 0 -hw_cfg3->synch_reset = 0 -hw_cfg3->otg_adp_support = 0 -hw_cfg3->otg_enable_hsic = 0 -hw_cfg3->battery_charger_support = 0 -hw_cfg3->lpm_mode = 0 -hw_cfg3->total_fifo_size = 634 - -dwc2->ghwcfg4 = DBF08030 -hw_cfg4->num_dev_period_in_ep = 0 -hw_cfg4->power_optimized = 1 -hw_cfg4->ahb_freq_min = 1 -hw_cfg4->hibernation = 0 -hw_cfg4->service_interval_mode = 0 -hw_cfg4->ipg_isoc_en = 0 -hw_cfg4->acg_enable = 0 -hw_cfg4->utmi_phy_data_width = 2 -hw_cfg4->dev_ctrl_ep_num = 0 -hw_cfg4->iddg_filter_enabled = 1 -hw_cfg4->vbus_valid_filter_enabled = 1 -hw_cfg4->a_valid_filter_enabled = 1 -hw_cfg4->b_valid_filter_enabled = 1 -hw_cfg4->dedicated_fifos = 1 -hw_cfg4->num_dev_in_eps = 13 -hw_cfg4->dma_desc_enable = 0 -hw_cfg4->dma_dynamic = 1 diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal.h index f092e8ff..8f45ea5c 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/osal/osal.h +++ b/test-devices/loopback-stm32/lib/tinyusb/osal/osal.h @@ -74,15 +74,18 @@ typedef void (*osal_task_func_t)( void * ); // Should be implemented as static inline function in osal_port.h header /* osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef); + bool osal_semaphore_delete(osal_semaphore_t semd_hdl); bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr); bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec); void osal_semaphore_reset(osal_semaphore_t sem_hdl); // TODO removed osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef); + bool osal_mutex_delete(osal_mutex_t mutex_hdl) bool osal_mutex_lock (osal_mutex_t sem_hdl, uint32_t msec); bool osal_mutex_unlock(osal_mutex_t mutex_hdl); osal_queue_t osal_queue_create(osal_queue_def_t* qdef); + bool osal_queue_delete(osal_queue_t qhdl); bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec); bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr); bool osal_queue_empty(osal_queue_t qhdl); diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_freertos.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_freertos.h deleted file mode 100644 index 477f6489..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_freertos.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_OSAL_FREERTOS_H_ -#define _TUSB_OSAL_FREERTOS_H_ - -// FreeRTOS Headers -#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,FreeRTOS.h) -#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,semphr.h) -#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,queue.h) -#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,task.h) - -#ifdef __cplusplus -extern "C" { -#endif - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF PROTYPES -//--------------------------------------------------------------------+ - -#if configSUPPORT_STATIC_ALLOCATION - typedef StaticSemaphore_t osal_semaphore_def_t; - typedef StaticSemaphore_t osal_mutex_def_t; -#else - // not used therefore defined to smallest possible type to save space - typedef uint8_t osal_semaphore_def_t; - typedef uint8_t osal_mutex_def_t; -#endif - -typedef SemaphoreHandle_t osal_semaphore_t; -typedef SemaphoreHandle_t osal_mutex_t; - -// _int_set is not used with an RTOS -#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ - static _type _name##_##buf[_depth];\ - osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf }; - -typedef struct -{ - uint16_t depth; - uint16_t item_sz; - void* buf; -#if configSUPPORT_STATIC_ALLOCATION - StaticQueue_t sq; -#endif -}osal_queue_def_t; - -typedef QueueHandle_t osal_queue_t; - -//--------------------------------------------------------------------+ -// TASK API -//--------------------------------------------------------------------+ - -TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec) -{ - if (msec == OSAL_TIMEOUT_WAIT_FOREVER) return portMAX_DELAY; - if (msec == 0) return 0; - - uint32_t ticks = pdMS_TO_TICKS(msec); - - // configTICK_RATE_HZ is less than 1000 and 1 tick > 1 ms - // we still need to delay at least 1 tick - if (ticks == 0) ticks =1 ; - - return ticks; -} - -TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) -{ - vTaskDelay( pdMS_TO_TICKS(msec) ); -} - -//--------------------------------------------------------------------+ -// Semaphore API -//--------------------------------------------------------------------+ - -TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) -{ -#if configSUPPORT_STATIC_ALLOCATION - return xSemaphoreCreateBinaryStatic(semdef); -#else - (void) semdef; - return xSemaphoreCreateBinary(); -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) -{ - if ( !in_isr ) - { - return xSemaphoreGive(sem_hdl) != 0; - } - else - { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - BaseType_t res = xSemaphoreGiveFromISR(sem_hdl, &xHigherPriorityTaskWoken); - -#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3 - // not needed after https://github.com/espressif/esp-idf/commit/c5fd79547ac9b7bae06fa660e9f814d18d3390b7 - if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR(); -#else - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); -#endif - - return res != 0; - } -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) -{ - return xSemaphoreTake(sem_hdl, _osal_ms2tick(msec)); -} - -TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) -{ - xQueueReset(sem_hdl); -} - -//--------------------------------------------------------------------+ -// MUTEX API (priority inheritance) -//--------------------------------------------------------------------+ - -TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) -{ -#if configSUPPORT_STATIC_ALLOCATION - return xSemaphoreCreateMutexStatic(mdef); -#else - (void) mdef; - return xSemaphoreCreateMutex(); -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) -{ - return osal_semaphore_wait(mutex_hdl, msec); -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) -{ - return xSemaphoreGive(mutex_hdl); -} - -//--------------------------------------------------------------------+ -// QUEUE API -//--------------------------------------------------------------------+ - -TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) -{ -#if configSUPPORT_STATIC_ALLOCATION - return xQueueCreateStatic(qdef->depth, qdef->item_sz, (uint8_t*) qdef->buf, &qdef->sq); -#else - return xQueueCreate(qdef->depth, qdef->item_sz); -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) -{ - return xQueueReceive(qhdl, data, _osal_ms2tick(msec)); -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) -{ - if ( !in_isr ) - { - return xQueueSendToBack(qhdl, data, OSAL_TIMEOUT_WAIT_FOREVER) != 0; - } - else - { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - BaseType_t res = xQueueSendToBackFromISR(qhdl, data, &xHigherPriorityTaskWoken); - -#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3 - // not needed after https://github.com/espressif/esp-idf/commit/c5fd79547ac9b7bae06fa660e9f814d18d3390b7 - if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR(); -#else - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); -#endif - - return res != 0; - } -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) -{ - return uxQueueMessagesWaiting(qhdl) == 0; -} - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_mynewt.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_mynewt.h deleted file mode 100644 index b8ea2087..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_mynewt.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef OSAL_MYNEWT_H_ -#define OSAL_MYNEWT_H_ - -#include "os/os.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// TASK API -//--------------------------------------------------------------------+ -TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) -{ - os_time_delay( os_time_ms_to_ticks32(msec) ); -} - -//--------------------------------------------------------------------+ -// Semaphore API -//--------------------------------------------------------------------+ -typedef struct os_sem osal_semaphore_def_t; -typedef struct os_sem* osal_semaphore_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) -{ - return (os_sem_init(semdef, 0) == OS_OK) ? (osal_semaphore_t) semdef : NULL; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) -{ - (void) in_isr; - return os_sem_release(sem_hdl) == OS_OK; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) -{ - uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? OS_TIMEOUT_NEVER : os_time_ms_to_ticks32(msec); - return os_sem_pend(sem_hdl, ticks) == OS_OK; -} - -static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) -{ - // TODO implement later -} - -//--------------------------------------------------------------------+ -// MUTEX API (priority inheritance) -//--------------------------------------------------------------------+ -typedef struct os_mutex osal_mutex_def_t; -typedef struct os_mutex* osal_mutex_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) -{ - return (os_mutex_init(mdef) == OS_OK) ? (osal_mutex_t) mdef : NULL; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) -{ - uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? OS_TIMEOUT_NEVER : os_time_ms_to_ticks32(msec); - return os_mutex_pend(mutex_hdl, ticks) == OS_OK; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) -{ - return os_mutex_release(mutex_hdl) == OS_OK; -} - -//--------------------------------------------------------------------+ -// QUEUE API -//--------------------------------------------------------------------+ - -// role device/host is used by OS NONE for mutex (disable usb isr) only -#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ - static _type _name##_##buf[_depth];\ - static struct os_event _name##_##evbuf[_depth];\ - osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf, .evbuf = _name##_##evbuf};\ - -typedef struct -{ - uint16_t depth; - uint16_t item_sz; - void* buf; - void* evbuf; - - struct os_mempool mpool; - struct os_mempool epool; - - struct os_eventq evq; -}osal_queue_def_t; - -typedef osal_queue_def_t* osal_queue_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) -{ - if ( OS_OK != os_mempool_init(&qdef->mpool, qdef->depth, qdef->item_sz, qdef->buf, "usbd queue") ) return NULL; - if ( OS_OK != os_mempool_init(&qdef->epool, qdef->depth, sizeof(struct os_event), qdef->evbuf, "usbd evqueue") ) return NULL; - - os_eventq_init(&qdef->evq); - return (osal_queue_t) qdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) -{ - (void) msec; // os_eventq_get() does not take timeout, always behave as msec = WAIT_FOREVER - - struct os_event* ev; - ev = os_eventq_get(&qhdl->evq); - - memcpy(data, ev->ev_arg, qhdl->item_sz); // copy message - os_memblock_put(&qhdl->mpool, ev->ev_arg); // put back mem block - os_memblock_put(&qhdl->epool, ev); // put back ev block - - return true; -} - -static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) -{ - (void) in_isr; - - // get a block from mem pool for data - void* ptr = os_memblock_get(&qhdl->mpool); - if (!ptr) return false; - memcpy(ptr, data, qhdl->item_sz); - - // get a block from event pool to put into queue - struct os_event* ev = (struct os_event*) os_memblock_get(&qhdl->epool); - if (!ev) - { - os_memblock_put(&qhdl->mpool, ptr); - return false; - } - tu_memclr(ev, sizeof(struct os_event)); - ev->ev_arg = ptr; - - os_eventq_put(&qhdl->evq, ev); - - return true; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) -{ - return STAILQ_EMPTY(&qhdl->evq.evq_list); -} - - -#ifdef __cplusplus - } -#endif - -#endif /* OSAL_MYNEWT_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_none.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_none.h index 5f407378..c93f7a86 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_none.h +++ b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_none.h @@ -24,11 +24,11 @@ * This file is part of the TinyUSB stack. */ -#ifndef _TUSB_OSAL_NONE_H_ -#define _TUSB_OSAL_NONE_H_ +#ifndef TUSB_OSAL_NONE_H_ +#define TUSB_OSAL_NONE_H_ #ifdef __cplusplus - extern "C" { +extern "C" { #endif //--------------------------------------------------------------------+ @@ -37,45 +37,46 @@ #if CFG_TUH_ENABLED // currently only needed/available in host mode -void osal_task_delay(uint32_t msec); +TU_ATTR_WEAK void osal_task_delay(uint32_t msec); #endif //--------------------------------------------------------------------+ // Binary Semaphore API //--------------------------------------------------------------------+ -typedef struct -{ +typedef struct { volatile uint16_t count; -}osal_semaphore_def_t; +} osal_semaphore_def_t; typedef osal_semaphore_def_t* osal_semaphore_t; -TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) -{ +TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) { semdef->count = 0; return semdef; } -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) -{ +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t semd_hdl) { + (void) semd_hdl; + return true; // nothing to do +} + + +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) { (void) in_isr; sem_hdl->count++; return true; } // TODO blocking for now -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) -{ +TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) { (void) msec; - while (sem_hdl->count == 0) { } + while (sem_hdl->count == 0) {} sem_hdl->count--; return true; } -TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) -{ +TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) { sem_hdl->count = 0; } @@ -90,19 +91,21 @@ typedef osal_semaphore_t osal_mutex_t; // Note: multiple cores MCUs usually do provide IPC API for mutex // or we can use std atomic function -TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) -{ +TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) { mdef->count = 1; return mdef; } -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) -{ +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl) { + (void) mutex_hdl; + return true; // nothing to do +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) { return osal_semaphore_wait(mutex_hdl, msec); } -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) -{ +TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) { return osal_semaphore_post(mutex_hdl, false); } @@ -119,11 +122,10 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd //--------------------------------------------------------------------+ #include "common/tusb_fifo.h" -typedef struct -{ - void (*interrupt_set)(bool); +typedef struct { + void (* interrupt_set)(bool); tu_fifo_t ff; -}osal_queue_def_t; +} osal_queue_def_t; typedef osal_queue_def_t* osal_queue_t; @@ -136,27 +138,28 @@ typedef osal_queue_def_t* osal_queue_t; } // lock queue by disable USB interrupt -TU_ATTR_ALWAYS_INLINE static inline void _osal_q_lock(osal_queue_t qhdl) -{ +TU_ATTR_ALWAYS_INLINE static inline void _osal_q_lock(osal_queue_t qhdl) { // disable dcd/hcd interrupt qhdl->interrupt_set(false); } // unlock queue -TU_ATTR_ALWAYS_INLINE static inline void _osal_q_unlock(osal_queue_t qhdl) -{ +TU_ATTR_ALWAYS_INLINE static inline void _osal_q_unlock(osal_queue_t qhdl) { // enable dcd/hcd interrupt qhdl->interrupt_set(true); } -TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) -{ +TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) { tu_fifo_clear(&qdef->ff); return (osal_queue_t) qdef; } -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) -{ +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) { + (void) qhdl; + return true; // nothing to do +} + +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) { (void) msec; // not used, always behave as msec = 0 _osal_q_lock(qhdl); @@ -166,8 +169,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, v return success; } -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) -{ +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const* data, bool in_isr) { if (!in_isr) { _osal_q_lock(qhdl); } @@ -178,20 +180,17 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void _osal_q_unlock(qhdl); } - TU_ASSERT(success); - return success; } -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) -{ +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) { // Skip queue lock/unlock since this function is primarily called // with interrupt disabled before going into low power mode return tu_fifo_empty(&qhdl->ff); } #ifdef __cplusplus - } +} #endif -#endif /* _TUSB_OSAL_NONE_H_ */ +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_pico.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_pico.h deleted file mode 100644 index e6efa096..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_pico.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_OSAL_PICO_H_ -#define _TUSB_OSAL_PICO_H_ - -#include "pico/time.h" -#include "pico/sem.h" -#include "pico/mutex.h" -#include "pico/critical_section.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// TASK API -//--------------------------------------------------------------------+ -TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) -{ - sleep_ms(msec); -} - -//--------------------------------------------------------------------+ -// Binary Semaphore API -//--------------------------------------------------------------------+ -typedef struct semaphore osal_semaphore_def_t, *osal_semaphore_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) -{ - sem_init(semdef, 0, 255); - return semdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) -{ - (void) in_isr; - sem_release(sem_hdl); - return true; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) -{ - return sem_acquire_timeout_ms(sem_hdl, msec); -} - -TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) -{ - sem_reset(sem_hdl, 0); -} - -//--------------------------------------------------------------------+ -// MUTEX API -// Within tinyusb, mutex is never used in ISR context -//--------------------------------------------------------------------+ -typedef struct mutex osal_mutex_def_t, *osal_mutex_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) -{ - mutex_init(mdef); - return mdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) -{ - return mutex_enter_timeout_ms(mutex_hdl, msec); -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) -{ - mutex_exit(mutex_hdl); - return true; -} - -//--------------------------------------------------------------------+ -// QUEUE API -//--------------------------------------------------------------------+ -#include "common/tusb_fifo.h" - -typedef struct -{ - tu_fifo_t ff; - struct critical_section critsec; // osal_queue may be used in IRQs, so need critical section -} osal_queue_def_t; - -typedef osal_queue_def_t* osal_queue_t; - -// role device/host is used by OS NONE for mutex (disable usb isr) only -#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ - uint8_t _name##_buf[_depth*sizeof(_type)]; \ - osal_queue_def_t _name = { \ - .ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \ - } - -// lock queue by disable USB interrupt -TU_ATTR_ALWAYS_INLINE static inline void _osal_q_lock(osal_queue_t qhdl) -{ - critical_section_enter_blocking(&qhdl->critsec); -} - -// unlock queue -TU_ATTR_ALWAYS_INLINE static inline void _osal_q_unlock(osal_queue_t qhdl) -{ - critical_section_exit(&qhdl->critsec); -} - -TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) -{ - critical_section_init(&qdef->critsec); - tu_fifo_clear(&qdef->ff); - return (osal_queue_t) qdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) -{ - (void) msec; // not used, always behave as msec = 0 - - // TODO: revisit... docs say that mutexes are never used from IRQ context, - // however osal_queue_recieve may be. therefore my assumption is that - // the fifo mutex is not populated for queues used from an IRQ context - //assert(!qhdl->ff.mutex); - - _osal_q_lock(qhdl); - bool success = tu_fifo_read(&qhdl->ff, data); - _osal_q_unlock(qhdl); - - return success; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) -{ - // TODO: revisit... docs say that mutexes are never used from IRQ context, - // however osal_queue_recieve may be. therefore my assumption is that - // the fifo mutex is not populated for queues used from an IRQ context - //assert(!qhdl->ff.mutex); - (void) in_isr; - - _osal_q_lock(qhdl); - bool success = tu_fifo_write(&qhdl->ff, data); - _osal_q_unlock(qhdl); - - TU_ASSERT(success); - - return success; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) -{ - // TODO: revisit; whether this is true or not currently, tu_fifo_empty is a single - // volatile read. - - // Skip queue lock/unlock since this function is primarily called - // with interrupt disabled before going into low power mode - return tu_fifo_empty(&qhdl->ff); -} - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_OSAL_PICO_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtthread.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtthread.h deleted file mode 100644 index 18eb9c69..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtthread.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 tfx2001 (2479727366@qq.com) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_OSAL_RTTHREAD_H_ -#define _TUSB_OSAL_RTTHREAD_H_ - -// RT-Thread Headers -#include "rtthread.h" - -#ifdef __cplusplus -extern "C" { -#endif - -//--------------------------------------------------------------------+ -// TASK API -//--------------------------------------------------------------------+ -TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) { - rt_thread_mdelay(msec); -} - -//--------------------------------------------------------------------+ -// Semaphore API -//--------------------------------------------------------------------+ -typedef struct rt_semaphore osal_semaphore_def_t; -typedef rt_sem_t osal_semaphore_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t -osal_semaphore_create(osal_semaphore_def_t *semdef) { - rt_sem_init(semdef, "tusb", 0, RT_IPC_FLAG_PRIO); - return semdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) { - (void) in_isr; - return rt_sem_release(sem_hdl) == RT_EOK; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) { - return rt_sem_take(sem_hdl, rt_tick_from_millisecond((rt_int32_t) msec)) == RT_EOK; -} - -TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) { - rt_sem_control(sem_hdl, RT_IPC_CMD_RESET, 0); -} - -//--------------------------------------------------------------------+ -// MUTEX API (priority inheritance) -//--------------------------------------------------------------------+ -typedef struct rt_mutex osal_mutex_def_t; -typedef rt_mutex_t osal_mutex_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) { - rt_mutex_init(mdef, "tusb", RT_IPC_FLAG_PRIO); - return mdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) { - return rt_mutex_take(mutex_hdl, rt_tick_from_millisecond((rt_int32_t) msec)) == RT_EOK; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) { - return rt_mutex_release(mutex_hdl) == RT_EOK; -} - -//--------------------------------------------------------------------+ -// QUEUE API -//--------------------------------------------------------------------+ - -// role device/host is used by OS NONE for mutex (disable usb isr) only -#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ - static _type _name##_##buf[_depth]; \ - osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf }; - -typedef struct { - uint16_t depth; - uint16_t item_sz; - void *buf; - - struct rt_messagequeue sq; -} osal_queue_def_t; - -typedef rt_mq_t osal_queue_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t *qdef) { - rt_mq_init(&(qdef->sq), "tusb", qdef->buf, qdef->item_sz, - qdef->item_sz * qdef->depth, RT_IPC_FLAG_PRIO); - return &(qdef->sq); -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void *data, uint32_t msec) { - - rt_tick_t tick = rt_tick_from_millisecond((rt_int32_t) msec); - return rt_mq_recv(qhdl, data, qhdl->msg_size, tick) == RT_EOK; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const *data, bool in_isr) { - (void) in_isr; - return rt_mq_send(qhdl, (void *)data, qhdl->msg_size) == RT_EOK; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) { - return (qhdl->entry) == 0; -} - -#ifdef __cplusplus -} -#endif - -#endif /* _TUSB_OSAL_RTTHREAD_H_ */ diff --git a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtx4.h b/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtx4.h deleted file mode 100644 index e443135e..00000000 --- a/test-devices/loopback-stm32/lib/tinyusb/osal/osal_rtx4.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2021 Tian Yunhao (t123yh) - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_OSAL_RTX4_H_ -#define _TUSB_OSAL_RTX4_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -//--------------------------------------------------------------------+ -// TASK API -//--------------------------------------------------------------------+ -TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) -{ - uint16_t hi = msec >> 16; - uint16_t lo = msec; - while (hi--) { - os_dly_wait(0xFFFE); - } - os_dly_wait(lo); -} - -TU_ATTR_ALWAYS_INLINE static inline uint16_t msec2wait(uint32_t msec) { - if (msec == OSAL_TIMEOUT_WAIT_FOREVER) - return 0xFFFF; - else if (msec >= 0xFFFE) - return 0xFFFE; - else - return msec; -} - -//--------------------------------------------------------------------+ -// Semaphore API -//--------------------------------------------------------------------+ -typedef OS_SEM osal_semaphore_def_t; -typedef OS_ID osal_semaphore_t; - -TU_ATTR_ALWAYS_INLINE static inline OS_ID osal_semaphore_create(osal_semaphore_def_t* semdef) { - os_sem_init(semdef, 0); - return semdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) { - if ( !in_isr ) { - os_sem_send(sem_hdl); - } else { - isr_sem_send(sem_hdl); - } - return true; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) { - return os_sem_wait(sem_hdl, msec2wait(msec)) != OS_R_TMO; -} - -TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) { - // TODO: implement -} - -//--------------------------------------------------------------------+ -// MUTEX API (priority inheritance) -//--------------------------------------------------------------------+ -typedef OS_MUT osal_mutex_def_t; -typedef OS_ID osal_mutex_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) -{ - os_mut_init(mdef); - return mdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) -{ - return os_mut_wait(mutex_hdl, msec2wait(msec)) != OS_R_TMO; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) -{ - return os_mut_release(mutex_hdl) == OS_R_OK; -} - -//--------------------------------------------------------------------+ -// QUEUE API -//--------------------------------------------------------------------+ - -// role device/host is used by OS NONE for mutex (disable usb isr) only -#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ - os_mbx_declare(_name##__mbox, _depth); \ - _declare_box(_name##__pool, sizeof(_type), _depth); \ - osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .pool = _name##__pool, .mbox = _name##__mbox }; - - -typedef struct -{ - uint16_t depth; - uint16_t item_sz; - U32* pool; - U32* mbox; -}osal_queue_def_t; - -typedef osal_queue_def_t* osal_queue_t; - -TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) -{ - os_mbx_init(qdef->mbox, (qdef->depth + 4) * 4); - _init_box(qdef->pool, ((qdef->item_sz+3)/4)*(qdef->depth) + 3, qdef->item_sz); - return qdef; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) -{ - void* buf; - os_mbx_wait(qhdl->mbox, &buf, msec2wait(msec)); - memcpy(data, buf, qhdl->item_sz); - _free_box(qhdl->pool, buf); - return true; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) -{ - void* buf = _alloc_box(qhdl->pool); - memcpy(buf, data, qhdl->item_sz); - if ( !in_isr ) - { - os_mbx_send(qhdl->mbox, buf, 0xFFFF); - } - else - { - isr_mbx_send(qhdl->mbox, buf); - } - return true; -} - -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) -{ - return os_mbx_check(qhdl->mbox) == qhdl->depth; -} - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c b/test-devices/loopback-stm32/lib/tinyusb/portable/st/stm32_fsdev/dcd_stm32_fsdev.c similarity index 53% rename from test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c rename to test-devices/loopback-stm32/lib/tinyusb/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 30a2e9c8..a26c6689 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev.c +++ b/test-devices/loopback-stm32/lib/tinyusb/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -44,6 +44,7 @@ * L0x2, L0x3 1024 byte buffer * L1 512 byte buffer * L4x2, L4x3 1024 byte buffer + * G0 2048 byte buffer * * To use this driver, you must: * - If you are using a device with crystal-less USB, set up the clock recovery system (CRS) @@ -106,9 +107,9 @@ #include "device/dcd.h" #ifdef TUP_USBIP_FSDEV_STM32 - // Undefine to reduce the dependence on HAL - #undef USE_HAL_DRIVER - #include "dcd_stm32_fsdev_pvt_st.h" +// Undefine to reduce the dependence on HAL +#undef USE_HAL_DRIVER +#include "portable/st/stm32_fsdev/dcd_stm32_fsdev.h" #endif /***************************************************** @@ -118,17 +119,17 @@ // HW supports max of 8 bidirectional endpoints, but this can be reduced to save RAM // (8u here would mean 8 IN and 8 OUT) #ifndef MAX_EP_COUNT -# define MAX_EP_COUNT 8U +#define MAX_EP_COUNT 8U #endif // If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it // Both of these MUST be a multiple of 2, and are in byte units. #ifndef DCD_STM32_BTABLE_BASE -# define DCD_STM32_BTABLE_BASE 0U +#define DCD_STM32_BTABLE_BASE 0U #endif -#ifndef DCD_STM32_BTABLE_LENGTH -# define DCD_STM32_BTABLE_LENGTH (PMA_LENGTH - DCD_STM32_BTABLE_BASE) +#ifndef DCD_STM32_BTABLE_SIZE +#define DCD_STM32_BTABLE_SIZE (FSDEV_PMA_SIZE - DCD_STM32_BTABLE_BASE) #endif /*************************************************** @@ -136,7 +137,7 @@ */ TU_VERIFY_STATIC((MAX_EP_COUNT) <= STFSDEV_EP_COUNT, "Only 8 endpoints supported on the hardware"); -TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_LENGTH))<=(PMA_LENGTH), "BTABLE does not fit in PMA RAM"); +TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_SIZE)) <= (FSDEV_PMA_SIZE), "BTABLE does not fit in PMA RAM"); TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligned to 8 bytes"); //--------------------------------------------------------------------+ @@ -144,21 +145,18 @@ TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligne //--------------------------------------------------------------------+ // One of these for every EP IN & OUT, uses a bit of RAM.... -typedef struct -{ - uint8_t * buffer; - tu_fifo_t * ff; +typedef struct { + uint8_t *buffer; + tu_fifo_t *ff; uint16_t total_len; uint16_t queued_len; - uint16_t pma_ptr; uint16_t max_packet_size; - uint16_t pma_alloc_size; - uint8_t ep_idx; // index for USB_EPnR register + uint8_t ep_idx; // index for USB_EPnR register + bool iso_in_sending; // Workaround for ISO IN EP doesn't have interrupt mask } xfer_ctl_t; // EP allocator -typedef struct -{ +typedef struct { uint8_t ep_num; uint8_t ep_type; bool allocated[2]; @@ -178,28 +176,25 @@ static uint8_t remoteWakeCountdown; // When wake is requested // into the stack. static void dcd_handle_bus_reset(void); -static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix); +static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix); +static bool edpt_xfer(uint8_t rhport, uint8_t ep_addr); static void dcd_ep_ctr_handler(void); // PMA allocation/access -static uint8_t open_ep_count; static uint16_t ep_buf_ptr; ///< Points to first free memory location -static void dcd_pma_alloc_reset(void); -static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length); -static void dcd_pma_free(uint8_t ep_addr); -static void dcd_ep_free(uint8_t ep_addr); +static uint32_t dcd_pma_alloc(uint16_t length, bool dbuf); static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type); -static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes); -static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes); +static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes); +static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes); -static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes); -static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes); +static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes); +static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes); //--------------------------------------------------------------------+ // Inline helper //--------------------------------------------------------------------+ -TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t ep_addr) +TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint32_t ep_addr) { uint8_t epnum = tu_edpt_number(ep_addr); uint8_t dir = tu_edpt_dir(ep_addr); @@ -209,22 +204,11 @@ TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t ep_addr) return &xfer_status[epnum][dir]; } -// Using a function due to better type checks -// This seems better than having to do type casts everywhere else -TU_ATTR_ALWAYS_INLINE static inline void reg16_clear_bits(__IO uint16_t *reg, uint16_t mask) { - *reg = (uint16_t)(*reg & ~mask); -} - -// Bits in ISTR are cleared upon writing 0 -TU_ATTR_ALWAYS_INLINE static inline void clear_istr_bits(uint16_t mask) { - USB->ISTR = ~mask; -} - //--------------------------------------------------------------------+ // Controller API //--------------------------------------------------------------------+ -void dcd_init (uint8_t rhport) +void dcd_init(uint8_t rhport) { /* Clocks should already be enabled */ /* Use __HAL_RCC_USB_CLK_ENABLE(); to enable the clocks before calling this function */ @@ -232,40 +216,41 @@ void dcd_init (uint8_t rhport) /* The RM mentions to use a special ordering of PDWN and FRES, but this isn't done in HAL. * Here, the RM is followed. */ - for(uint32_t i = 0; i<200; i++) // should be a few us - { + for (uint32_t i = 0; i < 200; i++) { // should be a few us asm("NOP"); } // Perform USB peripheral reset USB->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; - for(uint32_t i = 0; i<200; i++) // should be a few us - { + for (uint32_t i = 0; i < 200; i++) { // should be a few us asm("NOP"); } - reg16_clear_bits(&USB->CNTR, USB_CNTR_PDWN);// Remove powerdown + + USB->CNTR &= ~USB_CNTR_PDWN; + // Wait startup time, for F042 and F070, this is <= 1 us. - for(uint32_t i = 0; i<200; i++) // should be a few us - { + for (uint32_t i = 0; i < 200; i++) { // should be a few us asm("NOP"); } USB->CNTR = 0; // Enable USB +#if !defined(STM32G0) && !defined(STM32H5) // BTABLE register does not exist any more on STM32G0, it is fixed to USB SRAM base address USB->BTABLE = DCD_STM32_BTABLE_BASE; - +#endif USB->ISTR = 0; // Clear pending interrupts // Reset endpoints to disabled - for(uint32_t i=0; iCNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; dcd_handle_bus_reset(); // Enable pull-up if supported - if ( dcd_connect ) dcd_connect(rhport); + if (dcd_connect) { + dcd_connect(rhport); + } } // Define only on MCU with internal pull-up. BSP can define on MCU without internal PU. @@ -274,14 +259,14 @@ void dcd_init (uint8_t rhport) // Disable internal D+ PU void dcd_disconnect(uint8_t rhport) { - (void) rhport; + (void)rhport; USB->BCDR &= ~(USB_BCDR_DPPU); } // Enable internal D+ PU void dcd_connect(uint8_t rhport) { - (void) rhport; + (void)rhport; USB->BCDR |= USB_BCDR_DPPU; } @@ -289,60 +274,54 @@ void dcd_connect(uint8_t rhport) // Disable internal D+ PU void dcd_disconnect(uint8_t rhport) { - (void) rhport; + (void)rhport; SYSCFG->PMC &= ~(SYSCFG_PMC_USB_PU); } // Enable internal D+ PU void dcd_connect(uint8_t rhport) { - (void) rhport; + (void)rhport; SYSCFG->PMC |= SYSCFG_PMC_USB_PU; } #endif void dcd_sof_enable(uint8_t rhport, bool en) { - (void) rhport; - (void) en; + (void)rhport; + (void)en; - if (en) - { + if (en) { USB->CNTR |= USB_CNTR_SOFM; - } - else - { - USB->CNTR &= (uint16_t) ~USB_CNTR_SOFM; + } else { + USB->CNTR &= ~USB_CNTR_SOFM; } } // Enable device interrupt -void dcd_int_enable (uint8_t rhport) +void dcd_int_enable(uint8_t rhport) { (void)rhport; // Member here forces write to RAM before allowing ISR to execute __DSB(); __ISB(); -#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || \ - CFG_TUSB_MCU == OPT_MCU_STM32L4 +#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || CFG_TUSB_MCU == OPT_MCU_STM32L4 NVIC_EnableIRQ(USB_IRQn); #elif CFG_TUSB_MCU == OPT_MCU_STM32L1 NVIC_EnableIRQ(USB_LP_IRQn); #elif CFG_TUSB_MCU == OPT_MCU_STM32F3 - // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from - // shared USB/CAN IRQs to separate CAN and USB IRQs. - // This dynamically checks if this remap is active to enable the right IRQs. - #ifdef SYSCFG_CFGR1_USB_IT_RMP - if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) - { +// Some STM32F302/F303 devices allow to remap the USB interrupt vectors from +// shared USB/CAN IRQs to separate CAN and USB IRQs. +// This dynamically checks if this remap is active to enable the right IRQs. +#ifdef SYSCFG_CFGR1_USB_IT_RMP + if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) { NVIC_EnableIRQ(USB_HP_IRQn); NVIC_EnableIRQ(USB_LP_IRQn); NVIC_EnableIRQ(USBWakeUp_RMP_IRQn); - } - else - #endif + } else +#endif { NVIC_EnableIRQ(USB_HP_CAN_TX_IRQn); NVIC_EnableIRQ(USB_LP_CAN_RX0_IRQn); @@ -358,6 +337,16 @@ void dcd_int_enable (uint8_t rhport) NVIC_EnableIRQ(USB_LP_IRQn); NVIC_EnableIRQ(USBWakeUp_IRQn); +#elif CFG_TUSB_MCU == OPT_MCU_STM32G0 +#ifdef STM32G0B0xx + NVIC_EnableIRQ(USB_IRQn); +#else + NVIC_EnableIRQ(USB_UCPD1_2_IRQn); +#endif + +#elif CFG_TUSB_MCU == OPT_MCU_STM32H5 + NVIC_EnableIRQ(USB_DRD_FS_IRQn); + #elif CFG_TUSB_MCU == OPT_MCU_STM32WB NVIC_EnableIRQ(USB_HP_IRQn); NVIC_EnableIRQ(USB_LP_IRQn); @@ -366,7 +355,7 @@ void dcd_int_enable (uint8_t rhport) NVIC_EnableIRQ(USB_FS_IRQn); #else - #error Unknown arch in USB driver +#error Unknown arch in USB driver #endif } @@ -375,24 +364,21 @@ void dcd_int_disable(uint8_t rhport) { (void)rhport; -#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || \ - CFG_TUSB_MCU == OPT_MCU_STM32L4 +#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || CFG_TUSB_MCU == OPT_MCU_STM32L4 NVIC_DisableIRQ(USB_IRQn); #elif CFG_TUSB_MCU == OPT_MCU_STM32L1 NVIC_DisableIRQ(USB_LP_IRQn); #elif CFG_TUSB_MCU == OPT_MCU_STM32F3 - // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from - // shared USB/CAN IRQs to separate CAN and USB IRQs. - // This dynamically checks if this remap is active to disable the right IRQs. - #ifdef SYSCFG_CFGR1_USB_IT_RMP - if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) - { +// Some STM32F302/F303 devices allow to remap the USB interrupt vectors from +// shared USB/CAN IRQs to separate CAN and USB IRQs. +// This dynamically checks if this remap is active to disable the right IRQs. +#ifdef SYSCFG_CFGR1_USB_IT_RMP + if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) { NVIC_DisableIRQ(USB_HP_IRQn); NVIC_DisableIRQ(USB_LP_IRQn); NVIC_DisableIRQ(USBWakeUp_RMP_IRQn); - } - else - #endif + } else +#endif { NVIC_DisableIRQ(USB_HP_CAN_TX_IRQn); NVIC_DisableIRQ(USB_LP_CAN_RX0_IRQn); @@ -408,6 +394,16 @@ void dcd_int_disable(uint8_t rhport) NVIC_DisableIRQ(USB_LP_IRQn); NVIC_DisableIRQ(USBWakeUp_IRQn); +#elif CFG_TUSB_MCU == OPT_MCU_STM32G0 +#ifdef STM32G0B0xx + NVIC_DisableIRQ(USB_IRQn); +#else + NVIC_DisableIRQ(USB_UCPD1_2_IRQn); +#endif + +#elif CFG_TUSB_MCU == OPT_MCU_STM32H5 + NVIC_DisableIRQ(USB_DRD_FS_IRQn); + #elif CFG_TUSB_MCU == OPT_MCU_STM32WB NVIC_DisableIRQ(USB_HP_IRQn); NVIC_DisableIRQ(USB_LP_IRQn); @@ -416,7 +412,7 @@ void dcd_int_disable(uint8_t rhport) NVIC_DisableIRQ(USB_FS_IRQn); #else - #error Unknown arch in USB driver +#error Unknown arch in USB driver #endif // CMSIS has a membar after disabling interrupts @@ -425,8 +421,8 @@ void dcd_int_disable(uint8_t rhport) // Receive Set Address request, mcu port must also include status IN response void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { - (void) rhport; - (void) dev_addr; + (void)rhport; + (void)dev_addr; // Respond with status dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK | 0x00, NULL, 0); @@ -437,45 +433,35 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) void dcd_remote_wakeup(uint8_t rhport) { - (void) rhport; + (void)rhport; - USB->CNTR |= (uint16_t) USB_CNTR_RESUME; + USB->CNTR |= USB_CNTR_RESUME; remoteWakeCountdown = 4u; // required to be 1 to 15 ms, ESOF should trigger every 1ms. } -static const tusb_desc_endpoint_t ep0OUT_desc = -{ - .bLength = sizeof(tusb_desc_endpoint_t), - .bDescriptorType = TUSB_DESC_ENDPOINT, - - .bEndpointAddress = 0x00, - .bmAttributes = { .xfer = TUSB_XFER_CONTROL }, - .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE, - .bInterval = 0 +static const tusb_desc_endpoint_t ep0OUT_desc = { + .bLength = sizeof(tusb_desc_endpoint_t), + .bDescriptorType = TUSB_DESC_ENDPOINT, + .bEndpointAddress = 0x00, + .bmAttributes = {.xfer = TUSB_XFER_CONTROL}, + .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE, + .bInterval = 0 }; -static const tusb_desc_endpoint_t ep0IN_desc = -{ - .bLength = sizeof(tusb_desc_endpoint_t), - .bDescriptorType = TUSB_DESC_ENDPOINT, - - .bEndpointAddress = 0x80, - .bmAttributes = { .xfer = TUSB_XFER_CONTROL }, - .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE, - .bInterval = 0 +static const tusb_desc_endpoint_t ep0IN_desc = { + .bLength = sizeof(tusb_desc_endpoint_t), + .bDescriptorType = TUSB_DESC_ENDPOINT, + .bEndpointAddress = 0x80, + .bmAttributes = {.xfer = TUSB_XFER_CONTROL}, + .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE, + .bInterval = 0 }; static void dcd_handle_bus_reset(void) { - //__IO uint16_t * const epreg = &(EPREG(0)); USB->DADDR = 0u; // disable USB peripheral by clearing the EF flag - - for(uint32_t i=0; iDADDR = USB_DADDR_EF; // Set enable flag, and leaving the device address as zero. } @@ -501,30 +489,63 @@ static void dcd_ep_ctr_tx_handler(uint32_t wIstr) // Verify the CTR_TX bit is set. This was in the ST Micro code, // but I'm not sure it's actually necessary? - if((wEPRegVal & USB_EP_CTR_TX) == 0U) - { + if ((wEPRegVal & USB_EP_CTR_TX) == 0U) { return; } /* clear int flag */ pcd_clear_tx_ep_ctr(USB, EPindex); - xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); - if((xfer->total_len != xfer->queued_len)) /* TX not complete */ - { - dcd_transmit_packet(xfer, EPindex); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); + + if ((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) { + // Ignore spurious interrupts that we don't schedule + // host can send IN token while there is no data to send, since ISO does not have NAK + // this will result to zero length packet --> trigger interrupt (which cannot be masked) + if (!xfer->iso_in_sending) { + return; + } + xfer->iso_in_sending = false; + + if (wEPRegVal & USB_EP_DTOG_TX) { + pcd_set_ep_tx_dbuf0_cnt(USB, EPindex, 0); + } else { + pcd_set_ep_tx_dbuf1_cnt(USB, EPindex, 0); + } } - else /* TX Complete */ - { + + if ((xfer->total_len != xfer->queued_len)) { + dcd_transmit_packet(xfer, EPindex); + } else { dcd_event_xfer_complete(0, ep_addr, xfer->total_len, XFER_RESULT_SUCCESS, true); } } // Handle CTR interrupt for the RX/OUT direction -// // Upon call, (wIstr & USB_ISTR_DIR) == 0U static void dcd_ep_ctr_rx_handler(uint32_t wIstr) { +#ifdef FSDEV_BUS_32BIT + /* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf + * From STM32H503 errata 2.15.1: Buffer description table update completes after CTR interrupt triggers + * Description: + * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses + * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct. + * Workaround: + * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay + * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode + * - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code + * also takes time, so we'll wait 60 cycles (count = 20). + * - Since Low Speed mode is not supported/popular, we will ignore it for now. + * + * Note: this errata also seems to apply to G0, U5, H5 etc. + */ + volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver + while (cycle_count > 0U) { + cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare) + } +#endif + uint32_t EPindex = wIstr & USB_ISTR_EP_ID; uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex); uint8_t ep_addr = wEPRegVal & USB_EPADDR_FIELD; @@ -533,92 +554,83 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr) // Verify the CTR_RX bit is set. This was in the ST Micro code, // but I'm not sure it's actually necessary? - if((wEPRegVal & USB_EP_CTR_RX) == 0U) - { + if ((wEPRegVal & USB_EP_CTR_RX) == 0U) { return; } - if((ep_addr == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) /* Setup packet */ - { - // The setup_received function uses memcpy, so this must first copy the setup data into - // user memory, to allow for the 32-bit access that memcpy performs. - uint8_t userMemBuf[8]; + if ((ep_addr == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) { + /* Setup packet */ uint32_t count = pcd_get_ep_rx_cnt(USB, EPindex); - /* Get SETUP Packet*/ - if(count == 8) // Setup packet should always be 8 bytes. If not, ignore it, and try again. - { + // Setup packet should always be 8 bytes. If not, ignore it, and try again. + if (count == 8) { // Must reset EP to NAK (in case it had been stalling) (though, maybe too late here) - pcd_set_ep_rx_status(USB,0u,USB_EP_RX_NAK); - pcd_set_ep_tx_status(USB,0u,USB_EP_TX_NAK); - dcd_read_packet_memory(userMemBuf, *pcd_ep_rx_address_ptr(USB,EPindex), 8); - dcd_event_setup_received(0, (uint8_t*)userMemBuf, true); + pcd_set_ep_rx_status(USB, 0u, USB_EP_RX_NAK); + pcd_set_ep_tx_status(USB, 0u, USB_EP_TX_NAK); +#ifdef FSDEV_BUS_32BIT + dcd_event_setup_received(0, (uint8_t *)(USB_PMAADDR + pcd_get_ep_rx_address(USB, EPindex)), true); +#else + // The setup_received function uses memcpy, so this must first copy the setup data into + // user memory, to allow for the 32-bit access that memcpy performs. + uint8_t userMemBuf[8]; + dcd_read_packet_memory(userMemBuf, pcd_get_ep_rx_address(USB, EPindex), 8); + dcd_event_setup_received(0, (uint8_t *)userMemBuf, true); +#endif } - } - else - { + } else { + // Clear RX CTR interrupt flag + if (ep_addr != 0u) { + pcd_clear_rx_ep_ctr(USB, EPindex); + } + uint32_t count; + uint16_t addr; /* Read from correct register when ISOCHRONOUS (double buffered) */ - if ( (wEPRegVal & USB_EP_DTOG_RX) && ( (wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) ) { - count = pcd_get_ep_tx_cnt(USB, EPindex); + if ((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) { + if (wEPRegVal & USB_EP_DTOG_RX) { + count = pcd_get_ep_dbuf0_cnt(USB, EPindex); + addr = pcd_get_ep_dbuf0_address(USB, EPindex); + } else { + count = pcd_get_ep_dbuf1_cnt(USB, EPindex); + addr = pcd_get_ep_dbuf1_address(USB, EPindex); + } } else { count = pcd_get_ep_rx_cnt(USB, EPindex); + addr = pcd_get_ep_rx_address(USB, EPindex); } TU_ASSERT(count <= xfer->max_packet_size, /**/); - // Clear RX CTR interrupt flag - if(ep_addr != 0u) - { - pcd_clear_rx_ep_ctr(USB, EPindex); - } - - if (count != 0U) - { - uint16_t addr = *pcd_ep_rx_address_ptr(USB, EPindex); - - if (xfer->ff) - { + if (count != 0U) { + if (xfer->ff) { dcd_read_packet_memory_ff(xfer->ff, addr, count); - } - else - { + } else { dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), addr, count); } xfer->queued_len = (uint16_t)(xfer->queued_len + count); } - if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len)) - { - /* RX COMPLETE */ + if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len)) { + // all bytes received or short packet dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true); - // Though the host could still send, we don't know. - // Does the bulk pipe need to be reset to valid to allow for a ZLP? - } - else - { - uint32_t remaining = (uint32_t)xfer->total_len - (uint32_t)xfer->queued_len; - if(remaining >= xfer->max_packet_size) { - pcd_set_ep_rx_bufsize(USB, EPindex,xfer->max_packet_size); - } else { - pcd_set_ep_rx_bufsize(USB, EPindex,remaining); - } - - if (!((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS)) { - /* Set endpoint active again for receiving more data. - * Note that isochronous endpoints stay active always */ - pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID); + } else { + /* Set endpoint active again for receiving more data. + * Note that isochronous endpoints stay active always */ + if ((wEPRegVal & USB_EP_TYPE_MASK) != USB_EP_ISOCHRONOUS) { + uint16_t remaining = xfer->total_len - xfer->queued_len; + uint16_t cnt = tu_min16(remaining, xfer->max_packet_size); + pcd_set_ep_rx_cnt(USB, EPindex, cnt); } + pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID); } } // For EP0, prepare to receive another SETUP packet. // Clear CTR last so that a new packet does not overwrite the packing being read. // (Based on the docs, it seems SETUP will always be accepted after CTR is cleared) - if(ep_addr == 0u) - { - // Always be prepared for a status packet... - pcd_set_ep_rx_bufsize(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE); + if (ep_addr == 0u) { + // Always be prepared for a status packet... + pcd_set_ep_rx_cnt(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE); pcd_clear_rx_ep_ctr(USB, EPindex); } } @@ -628,64 +640,60 @@ static void dcd_ep_ctr_handler(void) uint32_t wIstr; /* stay in loop while pending interrupts */ - while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U) - { - - if ((wIstr & USB_ISTR_DIR) == 0U) /* TX/IN */ - { + while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U) { + if ((wIstr & USB_ISTR_DIR) == 0U) { + /* TX/IN */ dcd_ep_ctr_tx_handler(wIstr); - } - else /* RX/OUT*/ - { + } else { + /* RX/OUT*/ dcd_ep_ctr_rx_handler(wIstr); } } } -void dcd_int_handler(uint8_t rhport) { +void dcd_int_handler(uint8_t rhport) +{ - (void) rhport; + (void)rhport; uint32_t int_status = USB->ISTR; - //const uint32_t handled_ints = USB_ISTR_CTR | USB_ISTR_RESET | USB_ISTR_WKUP - // | USB_ISTR_SUSP | USB_ISTR_SOF | USB_ISTR_ESOF; - // unused IRQs: (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_L1REQ ) + // const uint32_t handled_ints = USB_ISTR_CTR | USB_ISTR_RESET | USB_ISTR_WKUP + // | USB_ISTR_SUSP | USB_ISTR_SOF | USB_ISTR_ESOF; + // unused IRQs: (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_L1REQ ) // The ST driver loops here on the CTR bit, but that loop has been moved into the // dcd_ep_ctr_handler(), so less need to loop here. The other interrupts shouldn't // be triggered repeatedly. /* Put SOF flag at the beginning of ISR in case to get least amount of jitter if it is used for timing purposes */ - if(int_status & USB_ISTR_SOF) { - clear_istr_bits(USB_ISTR_SOF); + if (int_status & USB_ISTR_SOF) { + USB->ISTR = (fsdev_bus_t)~USB_ISTR_SOF; dcd_event_sof(0, USB->FNR & USB_FNR_FN, true); } - if(int_status & USB_ISTR_RESET) { + if (int_status & USB_ISTR_RESET) { // USBRST is start of reset. - clear_istr_bits(USB_ISTR_RESET); + USB->ISTR = (fsdev_bus_t)~USB_ISTR_RESET; dcd_handle_bus_reset(); dcd_event_bus_reset(0, TUSB_SPEED_FULL, true); return; // Don't do the rest of the things here; perhaps they've been cleared? } - if (int_status & USB_ISTR_CTR) - { + if (int_status & USB_ISTR_CTR) { /* servicing of the endpoint correct transfer interrupt */ /* clear of the CTR flag into the sub */ dcd_ep_ctr_handler(); } - if (int_status & USB_ISTR_WKUP) - { - reg16_clear_bits(&USB->CNTR, USB_CNTR_LPMODE); - reg16_clear_bits(&USB->CNTR, USB_CNTR_FSUSP); - clear_istr_bits(USB_ISTR_WKUP); + if (int_status & USB_ISTR_WKUP) { + USB->CNTR &= ~USB_CNTR_LPMODE; + USB->CNTR &= ~USB_CNTR_FSUSP; + + USB->ISTR = (fsdev_bus_t)~USB_ISTR_WKUP; dcd_event_bus_signal(0, DCD_EVENT_RESUME, true); } - if (int_status & USB_ISTR_SUSP) - { + if (int_status & USB_ISTR_SUSP) { /* Suspend is asserted for both suspend and unplug events. without Vbus monitoring, * these events cannot be differentiated, so we only trigger suspend. */ @@ -694,20 +702,18 @@ void dcd_int_handler(uint8_t rhport) { USB->CNTR |= USB_CNTR_LPMODE; /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ - clear_istr_bits(USB_ISTR_SUSP); + USB->ISTR = (fsdev_bus_t)~USB_ISTR_SUSP; dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); } - if(int_status & USB_ISTR_ESOF) { - if(remoteWakeCountdown == 1u) - { - USB->CNTR &= (uint16_t)(~USB_CNTR_RESUME); + if (int_status & USB_ISTR_ESOF) { + if (remoteWakeCountdown == 1u) { + USB->CNTR &= ~USB_CNTR_RESUME; } - if(remoteWakeCountdown > 0u) - { + if (remoteWakeCountdown > 0u) { remoteWakeCountdown--; } - clear_istr_bits(USB_ISTR_ESOF); + USB->ISTR = (fsdev_bus_t)~USB_ISTR_ESOF; } } @@ -717,130 +723,73 @@ void dcd_int_handler(uint8_t rhport) { // Invoked when a control transfer's status stage is complete. // May help DCD to prepare for next control transfer, this API is optional. -void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) +void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) { - (void) rhport; + (void)rhport; if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && - request->bRequest == TUSB_REQ_SET_ADDRESS ) - { - uint8_t const dev_addr = (uint8_t) request->wValue; + request->bRequest == TUSB_REQ_SET_ADDRESS) { + uint8_t const dev_addr = (uint8_t)request->wValue; // Setting new address after the whole request is complete - reg16_clear_bits(&USB->DADDR, USB_DADDR_ADD); - USB->DADDR = (uint16_t)(USB->DADDR | dev_addr); // leave the enable bit set - } -} - -static void dcd_pma_alloc_reset(void) -{ - open_ep_count = 0; - ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT; // 8 bytes per endpoint (two TX and two RX words, each) - //TU_LOG2("dcd_pma_alloc_reset()\r\n"); - for(uint32_t i=0; ipma_alloc_size = 0U; - xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_alloc_size = 0U; - xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_OUT))->pma_ptr = 0U; - xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_ptr = 0U; + USB->DADDR &= ~USB_DADDR_ADD; + USB->DADDR |= dev_addr; // leave the enable bit set } } /*** * Allocate a section of PMA - * - * If the EP number has already been allocated, and the new allocation - * is larger than the old allocation, then this will fail with a TU_ASSERT. - * (This is done to simplify the code. More complicated algorithms could be used) - * + * In case of double buffering, high 16bit is the address of 2nd buffer * During failure, TU_ASSERT is used. If this happens, rework/reallocate memory manually. */ -static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length) +static uint32_t dcd_pma_alloc(uint16_t length, bool dbuf) { - xfer_ctl_t* epXferCtl = xfer_ctl_ptr(ep_addr); - - if(epXferCtl->pma_alloc_size != 0U) - { - //TU_LOG2("dcd_pma_alloc(%x,%x)=%x (cached)\r\n",ep_addr,length,epXferCtl->pma_ptr); - // Previously allocated - TU_ASSERT(length <= epXferCtl->pma_alloc_size, 0xFFFF); // Verify no larger than previous alloc - return epXferCtl->pma_ptr; - } - - open_ep_count++; + // Ensure allocated buffer is aligned +#ifdef FSDEV_BUS_32BIT + length = (length + 3) & ~0x03; +#else + length = (length + 1) & ~0x01; +#endif - uint16_t addr = ep_buf_ptr; + uint32_t addr = ep_buf_ptr; ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer - // Verify no overflow - TU_ASSERT(ep_buf_ptr <= PMA_LENGTH, 0xFFFF); + if (dbuf) { + addr |= ((uint32_t)ep_buf_ptr) << 16; + ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer + } - epXferCtl->pma_ptr = addr; - epXferCtl->pma_alloc_size = length; - //TU_LOG2("dcd_pma_alloc(%x,%x)=%x\r\n",ep_addr,length,addr); + // Verify packet buffer is not overflowed + TU_ASSERT(ep_buf_ptr <= FSDEV_PMA_SIZE, 0xFFFF); return addr; } -/*** - * Free a block of PMA space - */ -static void dcd_pma_free(uint8_t ep_addr) -{ - // Presently, this should never be called for EP0 IN/OUT - TU_ASSERT(open_ep_count > 2, /**/); - TU_ASSERT(xfer_ctl_ptr(ep_addr)->max_packet_size != 0, /**/); - open_ep_count--; - - // If count is 2, only EP0 should be open, so allocations can be mostly reset. - - if(open_ep_count == 2) - { - ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT + 2*CFG_TUD_ENDPOINT0_SIZE; // 8 bytes per endpoint (two TX and two RX words, each), and EP0 - - // Skip EP0 - for(uint32_t i=1; ipma_alloc_size = 0U; - xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_alloc_size = 0U; - xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_OUT))->pma_ptr = 0U; - xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_ptr = 0U; - } - } -} - /*** * Allocate hardware endpoint */ static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type) { uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); - for(uint8_t i = 0; i < STFSDEV_EP_COUNT; i++) - { + for (uint8_t i = 0; i < STFSDEV_EP_COUNT; i++) { // Check if already allocated - if(ep_alloc_status[i].allocated[dir] && - ep_alloc_status[i].ep_type == ep_type && - ep_alloc_status[i].ep_num == epnum) - { + if (ep_alloc_status[i].allocated[dir] && + ep_alloc_status[i].ep_type == ep_type && + ep_alloc_status[i].ep_num == epnum) { return i; } // If EP of current direction is not allocated // Except for ISO endpoint, both direction should be free - if(!ep_alloc_status[i].allocated[dir] && - (ep_type != TUSB_XFER_ISOCHRONOUS || !ep_alloc_status[i].allocated[dir ^ 1])) - { + if (!ep_alloc_status[i].allocated[dir] && + (ep_type != TUSB_XFER_ISOCHRONOUS || !ep_alloc_status[i].allocated[dir ^ 1])) { // Check if EP number is the same - if(ep_alloc_status[i].ep_num == 0xFF || - ep_alloc_status[i].ep_num == epnum) - { + if (ep_alloc_status[i].ep_num == 0xFF || ep_alloc_status[i].ep_num == epnum) { // One EP pair has to be the same type - if(ep_alloc_status[i].ep_type == 0xFF || - ep_alloc_status[i].ep_type == ep_type) - { + if (ep_alloc_status[i].ep_type == 0xFF || ep_alloc_status[i].ep_type == ep_type) { ep_alloc_status[i].ep_num = epnum; ep_alloc_status[i].ep_type = ep_type; ep_alloc_status[i].allocated[dir] = true; @@ -855,121 +804,79 @@ static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type) TU_ASSERT(0); } -/*** - * Free hardware endpoint - */ -static void dcd_ep_free(uint8_t ep_addr) -{ - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - - for(uint8_t i = 0; i < STFSDEV_EP_COUNT; i++) - { - // Check if EP number & dir are the same - if(ep_alloc_status[i].ep_num == epnum && - ep_alloc_status[i].allocated[dir] == dir) - { - ep_alloc_status[i].allocated[dir] = false; - // Reset entry if ISO endpoint or both direction are free - if(ep_alloc_status[i].ep_type == TUSB_XFER_ISOCHRONOUS || - !ep_alloc_status[i].allocated[dir ^ 1]) - { - ep_alloc_status[i].ep_num = 0xFF; - ep_alloc_status[i].ep_type = 0xFF; - - return; - } - } - } -} - // The STM32F0 doesn't seem to like |= or &= to manipulate the EP#R registers, // so I'm using the #define from HAL here, instead. -bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) +bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc) { (void)rhport; - uint8_t const ep_idx = dcd_ep_alloc(p_endpoint_desc->bEndpointAddress, p_endpoint_desc->bmAttributes.xfer); - uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); + uint8_t const ep_addr = p_endpoint_desc->bEndpointAddress; + uint8_t const ep_idx = dcd_ep_alloc(ep_addr, p_endpoint_desc->bmAttributes.xfer); + uint8_t const dir = tu_edpt_dir(ep_addr); const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc); const uint16_t buffer_size = pcd_aligned_buffer_size(packet_size); uint16_t pma_addr; uint32_t wType; TU_ASSERT(ep_idx < STFSDEV_EP_COUNT); - TU_ASSERT(buffer_size <= 1024); + TU_ASSERT(buffer_size <= 64); // Set type - switch(p_endpoint_desc->bmAttributes.xfer) { - case TUSB_XFER_CONTROL: - wType = USB_EP_CONTROL; - break; - case TUSB_XFER_ISOCHRONOUS: - wType = USB_EP_ISOCHRONOUS; - break; - case TUSB_XFER_BULK: - wType = USB_EP_CONTROL; - break; - - case TUSB_XFER_INTERRUPT: - wType = USB_EP_INTERRUPT; - break; - - default: - TU_ASSERT(false); + switch (p_endpoint_desc->bmAttributes.xfer) { + case TUSB_XFER_CONTROL: + wType = USB_EP_CONTROL; + break; + case TUSB_XFER_BULK: + wType = USB_EP_CONTROL; + break; + + case TUSB_XFER_INTERRUPT: + wType = USB_EP_INTERRUPT; + break; + + default: + // Note: ISO endpoint should use alloc / active functions + TU_ASSERT(false); } pcd_set_eptype(USB, ep_idx, wType); - pcd_set_ep_address(USB, ep_idx, tu_edpt_number(p_endpoint_desc->bEndpointAddress)); - // Be normal, for now, instead of only accepting zero-byte packets (on control endpoint) - // or being double-buffered (bulk endpoints) - pcd_clear_ep_kind(USB,0); + pcd_set_ep_address(USB, ep_idx, tu_edpt_number(ep_addr)); - /* Create a packet memory buffer area. For isochronous endpoints, - * use the same buffer as the double buffer, essentially disabling double buffering */ - pma_addr = dcd_pma_alloc(p_endpoint_desc->bEndpointAddress, buffer_size); + /* Create a packet memory buffer area. */ + pma_addr = dcd_pma_alloc(buffer_size, false); - if( (dir == TUSB_DIR_IN) || (wType == USB_EP_ISOCHRONOUS) ) - { - *pcd_ep_tx_address_ptr(USB, ep_idx) = pma_addr; - pcd_set_ep_tx_bufsize(USB, ep_idx, buffer_size); + if (dir == TUSB_DIR_IN) { + pcd_set_ep_tx_address(USB, ep_idx, pma_addr); + pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK); pcd_clear_tx_dtog(USB, ep_idx); - } - - if( (dir == TUSB_DIR_OUT) || (wType == USB_EP_ISOCHRONOUS) ) - { - *pcd_ep_rx_address_ptr(USB, ep_idx) = pma_addr; - pcd_set_ep_rx_bufsize(USB, ep_idx, buffer_size); + } else { + pcd_set_ep_rx_address(USB, ep_idx, pma_addr); + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK); pcd_clear_rx_dtog(USB, ep_idx); } - /* Enable endpoint */ - if (dir == TUSB_DIR_IN) - { - if(wType == USB_EP_ISOCHRONOUS) { - pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); - } else { - pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK); - } - } else - { - if(wType == USB_EP_ISOCHRONOUS) { - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); - } else { - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK); - } - } - - xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->max_packet_size = packet_size; - xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->ep_idx = ep_idx; + xfer_ctl_ptr(ep_addr)->max_packet_size = packet_size; + xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx; return true; } -void dcd_edpt_close_all (uint8_t rhport) +void dcd_edpt_close_all(uint8_t rhport) { - (void) rhport; - // TODO implement dcd_edpt_close_all() + (void)rhport; + + for (uint32_t i = 1; i < STFSDEV_EP_COUNT; i++) { + // Reset endpoint + pcd_set_endpoint(USB, i, 0); + // Clear EP allocation status + ep_alloc_status[i].ep_num = 0xFF; + ep_alloc_status[i].ep_type = 0xFF; + ep_alloc_status[i].allocated[0] = false; + ep_alloc_status[i].allocated[1] = false; + } + + // Reset PMA allocation + ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * MAX_EP_COUNT + 2 * CFG_TUD_ENDPOINT0_SIZE; } /** @@ -979,223 +886,203 @@ void dcd_edpt_close_all (uint8_t rhport) * * This also clears transfers in progress, should there be any. */ -void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { (void)rhport; - xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); uint8_t const ep_idx = xfer->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); - if(dir == TUSB_DIR_IN) - { + if (dir == TUSB_DIR_IN) { pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); - } - else - { + } else { pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); } - - dcd_ep_free(ep_addr); - - dcd_pma_free(ep_addr); } bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { (void)rhport; - TU_ASSERT(largest_packet_size <= 1024); - uint8_t const ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS); const uint16_t buffer_size = pcd_aligned_buffer_size(largest_packet_size); - /* Create a packet memory buffer area. For isochronous endpoints, - * use the same buffer as the double buffer, essentially disabling double buffering */ - uint16_t pma_addr = dcd_pma_alloc(ep_addr, buffer_size); - - xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx; + /* Create a packet memory buffer area. Enable double buffering for devices with 2048 bytes PMA, + for smaller devices double buffering occupy too much space. */ +#if FSDEV_PMA_SIZE > 1024u + uint32_t pma_addr = dcd_pma_alloc(buffer_size, true); + uint16_t pma_addr2 = pma_addr >> 16; +#else + uint32_t pma_addr = dcd_pma_alloc(buffer_size, true); + uint16_t pma_addr2 = pma_addr; +#endif + pcd_set_ep_tx_address(USB, ep_idx, pma_addr); + pcd_set_ep_rx_address(USB, ep_idx, pma_addr2); pcd_set_eptype(USB, ep_idx, USB_EP_ISOCHRONOUS); - *pcd_ep_tx_address_ptr(USB, ep_idx) = pma_addr; - *pcd_ep_rx_address_ptr(USB, ep_idx) = pma_addr; + xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx; return true; } -bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc) { (void)rhport; - uint8_t const ep_idx = xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->ep_idx; - uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); + uint8_t const ep_addr = p_endpoint_desc->bEndpointAddress; + uint8_t const ep_idx = xfer_ctl_ptr(ep_addr)->ep_idx; + uint8_t const dir = tu_edpt_dir(ep_addr); const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc); - const uint16_t buffer_size = pcd_aligned_buffer_size(packet_size); - /* Disable endpoint */ - if(dir == TUSB_DIR_IN) - { - pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); - } - else - { - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); - } + pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); - pcd_set_ep_address(USB, ep_idx, tu_edpt_number(p_endpoint_desc->bEndpointAddress)); - // Be normal, for now, instead of only accepting zero-byte packets (on control endpoint) - // or being double-buffered (bulk endpoints) - pcd_clear_ep_kind(USB,0); + pcd_set_ep_address(USB, ep_idx, tu_edpt_number(ep_addr)); - pcd_set_ep_tx_bufsize(USB, ep_idx, buffer_size); - pcd_set_ep_rx_bufsize(USB, ep_idx, buffer_size); pcd_clear_tx_dtog(USB, ep_idx); pcd_clear_rx_dtog(USB, ep_idx); - xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->max_packet_size = packet_size; + if (dir == TUSB_DIR_IN) { + pcd_rx_dtog(USB, ep_idx); + } else { + pcd_tx_dtog(USB, ep_idx); + } + + xfer_ctl_ptr(ep_addr)->max_packet_size = packet_size; return true; } // Currently, single-buffered, and only 64 bytes at a time (max) -static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix) +static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) { uint16_t len = (uint16_t)(xfer->total_len - xfer->queued_len); - - if(len > xfer->max_packet_size) // max packet size for FS transfer - { + if (len > xfer->max_packet_size) { len = xfer->max_packet_size; } uint16_t ep_reg = pcd_get_endpoint(USB, ep_ix); - uint16_t addr_ptr = *pcd_ep_tx_address_ptr(USB,ep_ix); + bool const is_iso = (ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS; + uint16_t addr_ptr; - if (xfer->ff) - { - dcd_write_packet_memory_ff(xfer->ff, addr_ptr, len); - } - else - { - dcd_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len); + if (is_iso) { + if (ep_reg & USB_EP_DTOG_TX) { + addr_ptr = pcd_get_ep_dbuf1_address(USB, ep_ix); + pcd_set_ep_tx_dbuf1_cnt(USB, ep_ix, len); + } else { + addr_ptr = pcd_get_ep_dbuf0_address(USB, ep_ix); + pcd_set_ep_tx_dbuf0_cnt(USB, ep_ix, len); + } + } else { + addr_ptr = pcd_get_ep_tx_address(USB, ep_ix); + pcd_set_ep_tx_cnt(USB, ep_ix, len); } - xfer->queued_len = (uint16_t)(xfer->queued_len + len); - /* Write into correct register when ISOCHRONOUS (double buffered) */ - if ( (ep_reg & USB_EP_DTOG_TX) && ( (ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) ) { - pcd_set_ep_rx_cnt(USB, ep_ix, len); + if (xfer->ff) { + dcd_write_packet_memory_ff(xfer->ff, addr_ptr, len); } else { - pcd_set_ep_tx_cnt(USB, ep_ix, len); + dcd_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len); } + xfer->queued_len = (uint16_t)(xfer->queued_len + len); + dcd_int_disable(0); pcd_set_ep_tx_status(USB, ep_ix, USB_EP_TX_VALID); + if (is_iso) { + xfer->iso_in_sending = true; + } + dcd_int_enable(0); } -bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +static bool edpt_xfer(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; + (void)rhport; - xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); uint8_t const ep_idx = xfer->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); - xfer->buffer = buffer; - xfer->ff = NULL; - xfer->total_len = total_bytes; - xfer->queued_len = 0; - - if ( dir == TUSB_DIR_OUT ) - { + if (dir == TUSB_DIR_IN) { + dcd_transmit_packet(xfer, ep_idx); + } else { // A setup token can occur immediately after an OUT STATUS packet so make sure we have a valid // buffer for the control endpoint. - if (ep_idx == 0 && buffer == NULL) - { - xfer->buffer = (uint8_t*)_setup_packet; + if (ep_idx == 0 && xfer->buffer == NULL) { + xfer->buffer = (uint8_t *)_setup_packet; } - if(total_bytes > xfer->max_packet_size) - { - pcd_set_ep_rx_bufsize(USB,ep_idx,xfer->max_packet_size); + uint32_t cnt = (uint32_t ) tu_min16(xfer->total_len, xfer->max_packet_size); + uint16_t ep_reg = pcd_get_endpoint(USB, ep_idx); + + if ((ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) { + pcd_set_ep_rx_dbuf0_cnt(USB, ep_idx, cnt); + pcd_set_ep_rx_dbuf1_cnt(USB, ep_idx, cnt); } else { - pcd_set_ep_rx_bufsize(USB,ep_idx,total_bytes); + pcd_set_ep_rx_cnt(USB, ep_idx, cnt); } + pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_VALID); } - else // IN - { - dcd_transmit_packet(xfer,ep_idx); - } + return true; } -bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) { - (void) rhport; + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); - xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); - uint8_t const epnum = xfer->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); + xfer->buffer = buffer; + xfer->ff = NULL; + xfer->total_len = total_bytes; + xfer->queued_len = 0; + return edpt_xfer(rhport, ep_addr); +} + +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes) +{ + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); xfer->buffer = NULL; - xfer->ff = ff; + xfer->ff = ff; xfer->total_len = total_bytes; xfer->queued_len = 0; - if ( dir == TUSB_DIR_OUT ) - { - if(total_bytes > xfer->max_packet_size) - { - pcd_set_ep_rx_bufsize(USB,epnum,xfer->max_packet_size); - } else { - pcd_set_ep_rx_bufsize(USB,epnum,total_bytes); - } - pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_VALID); - } - else // IN - { - dcd_transmit_packet(xfer,epnum); - } - return true; + return edpt_xfer(rhport, ep_addr); } -void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { (void)rhport; - xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); uint8_t const ep_idx = xfer->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); - if (dir == TUSB_DIR_IN) - { // IN + if (dir == TUSB_DIR_IN) { pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_STALL); - } - else - { // OUT + } else { pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_STALL); } } -void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) +void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { (void)rhport; - xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); uint8_t const ep_idx = xfer->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); - if (dir == TUSB_DIR_IN) - { // IN - if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) { + if (dir == TUSB_DIR_IN) { // IN + if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) { pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK); } /* Reset to DATA0 if clearing stall condition. */ pcd_clear_tx_dtog(USB, ep_idx); - } - else - { // OUT - if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) { + } else { // OUT + if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) { pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK); } /* Reset to DATA0 if clearing stall condition. */ @@ -1203,89 +1090,144 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) } } +#ifdef FSDEV_BUS_32BIT +static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes) +{ + const uint8_t *srcVal = src; + volatile uint32_t *dst32 = (volatile uint32_t *)(USB_PMAADDR + dst); + + for (uint32_t n = wNBytes / 4; n > 0; --n) { + *dst32++ = tu_unaligned_read32(srcVal); + srcVal += 4; + } + + wNBytes = wNBytes & 0x03; + if (wNBytes) { + uint32_t wrVal = *srcVal; + wNBytes--; + + if (wNBytes) { + wrVal |= *++srcVal << 8; + wNBytes--; + + if (wNBytes) { + wrVal |= *++srcVal << 16; + } + } + + *dst32 = wrVal; + } + + return true; +} +#else // Packet buffer access can only be 8- or 16-bit. /** - * @brief Copy a buffer from user memory area to packet memory area (PMA). - * This uses byte-access for user memory (so support non-aligned buffers) - * and 16-bit access for packet memory. - * @param dst, byte address in PMA; must be 16-bit aligned - * @param src pointer to user memory area. - * @param wPMABufAddr address into PMA. - * @param wNBytes no. of bytes to be copied. - * @retval None - */ -static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes) + * @brief Copy a buffer from user memory area to packet memory area (PMA). + * This uses byte-access for user memory (so support non-aligned buffers) + * and 16-bit access for packet memory. + * @param dst, byte address in PMA; must be 16-bit aligned + * @param src pointer to user memory area. + * @param wPMABufAddr address into PMA. + * @param wNBytes no. of bytes to be copied. + * @retval None + */ +static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes) { uint32_t n = (uint32_t)wNBytes >> 1U; uint16_t temp1, temp2; - const uint8_t * srcVal; + const uint8_t *srcVal; // The GCC optimizer will combine access to 32-bit sizes if we let it. Force // it volatile so that it won't do that. __IO uint16_t *pdwVal; srcVal = src; - pdwVal = &pma[PMA_STRIDE*(dst>>1)]; + pdwVal = &pma[FSDEV_PMA_STRIDE * (dst >> 1)]; - while (n--) - { + while (n--) { temp1 = (uint16_t)*srcVal; srcVal++; - temp2 = temp1 | ((uint16_t)(((uint16_t)(*srcVal)) << 8U)) ; + temp2 = temp1 | ((uint16_t)(((uint16_t)(*srcVal)) << 8U)); *pdwVal = temp2; - pdwVal += PMA_STRIDE; + pdwVal += FSDEV_PMA_STRIDE; srcVal++; } - if (wNBytes & 0x01) - { + if (wNBytes) { temp1 = *srcVal; *pdwVal = temp1; } return true; } +#endif /** - * @brief Copy from FIFO to packet memory area (PMA). - * Uses byte-access of system memory and 16-bit access of packet memory - * @param wNBytes no. of bytes to be copied. - * @retval None - */ -static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes) + * @brief Copy from FIFO to packet memory area (PMA). + * Uses byte-access of system memory and 16-bit access of packet memory + * @param wNBytes no. of bytes to be copied. + * @retval None + */ +static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes) { // Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies tu_fifo_buffer_info_t info; tu_fifo_get_read_info(ff, &info); - uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin); + uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin); uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap); // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part, // last lin byte will be combined with wrapped part - // To ensure PMA is always access 16bit aligned (dst aligned to 16 bit) - if((cnt_lin & 0x01) && cnt_wrap) - { + // To ensure PMA is always access aligned (dst aligned to 16 or 32 bit) +#ifdef FSDEV_BUS_32BIT + if ((cnt_lin & 0x03) && cnt_wrap) { // Copy first linear part - dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin &~0x01); - dst += cnt_lin &~0x01; + dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin & ~0x03); + dst += cnt_lin & ~0x03; + + // Copy last linear bytes & first wrapped bytes to buffer + uint32_t i; + uint8_t tmp[4]; + for (i = 0; i < (cnt_lin & 0x03); i++) { + tmp[i] = ((uint8_t *)info.ptr_lin)[(cnt_lin & ~0x03) + i]; + } + uint32_t wCnt = cnt_wrap; + for (; i < 4 && wCnt > 0; i++, wCnt--) { + tmp[i] = *(uint8_t *)info.ptr_wrap; + info.ptr_wrap = (uint8_t *)info.ptr_wrap + 1; + } + + // Write unaligned buffer + dcd_write_packet_memory(dst, &tmp, 4); + dst += 4; + + // Copy rest of wrapped byte + if (wCnt) + dcd_write_packet_memory(dst, info.ptr_wrap, wCnt); + } +#else + if ((cnt_lin & 0x01) && cnt_wrap) { + // Copy first linear part + dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin & ~0x01); + dst += cnt_lin & ~0x01; // Copy last linear byte & first wrapped byte - uint16_t tmp = ((uint8_t*)info.ptr_lin)[cnt_lin - 1] | ((uint16_t)(((uint8_t*)info.ptr_wrap)[0]) << 8U); + uint16_t tmp = ((uint8_t *)info.ptr_lin)[cnt_lin - 1] | ((uint16_t)(((uint8_t *)info.ptr_wrap)[0]) << 8U); dcd_write_packet_memory(dst, &tmp, 2); dst += 2; // Copy rest of wrapped byte - dcd_write_packet_memory(dst, ((uint8_t*)info.ptr_wrap) + 1, cnt_wrap - 1); + dcd_write_packet_memory(dst, ((uint8_t *)info.ptr_wrap) + 1, cnt_wrap - 1); } - else - { +#endif + else { // Copy linear part dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin); dst += info.len_lin; - if(info.len_wrap) - { + if (info.len_wrap) { // Copy wrapped byte dcd_write_packet_memory(dst, info.ptr_wrap, cnt_wrap); } @@ -1296,13 +1238,44 @@ static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wN return true; } +#ifdef FSDEV_BUS_32BIT +static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes) +{ + uint8_t *dstVal = dst; + volatile uint32_t *src32 = (volatile uint32_t *)(USB_PMAADDR + src); + + for (uint32_t n = wNBytes / 4; n > 0; --n) { + tu_unaligned_write32(dstVal, *src32++); + dstVal += 4; + } + + wNBytes = wNBytes & 0x03; + if (wNBytes) { + uint32_t rdVal = *src32; + + *dstVal = tu_u32_byte0(rdVal); + wNBytes--; + + if (wNBytes) { + *++dstVal = tu_u32_byte1(rdVal); + wNBytes--; + + if (wNBytes) { + *++dstVal = tu_u32_byte2(rdVal); + } + } + } + + return true; +} +#else /** - * @brief Copy a buffer from packet memory area (PMA) to user memory area. - * Uses byte-access of system memory and 16-bit access of packet memory - * @param wNBytes no. of bytes to be copied. - * @retval None - */ -static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes) + * @brief Copy a buffer from packet memory area (PMA) to user memory area. + * Uses byte-access of system memory and 16-bit access of packet memory + * @param wNBytes no. of bytes to be copied. + * @retval None + */ +static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes) { uint32_t n = (uint32_t)wNBytes >> 1U; // The GCC optimizer will combine access to 32-bit sizes if we let it. Force @@ -1310,70 +1283,93 @@ static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wN __IO const uint16_t *pdwVal; uint32_t temp; - pdwVal = &pma[PMA_STRIDE*(src>>1)]; - uint8_t *dstVal = (uint8_t*)dst; + pdwVal = &pma[FSDEV_PMA_STRIDE * (src >> 1)]; + uint8_t *dstVal = (uint8_t *)dst; - while (n--) - { + while (n--) { temp = *pdwVal; - pdwVal += PMA_STRIDE; + pdwVal += FSDEV_PMA_STRIDE; *dstVal++ = ((temp >> 0) & 0xFF); *dstVal++ = ((temp >> 8) & 0xFF); } - if (wNBytes & 0x01) - { + if (wNBytes & 0x01) { temp = *pdwVal; - pdwVal += PMA_STRIDE; + pdwVal += FSDEV_PMA_STRIDE; *dstVal++ = ((temp >> 0) & 0xFF); } return true; } +#endif /** - * @brief Copy a buffer from user packet memory area (PMA) to FIFO. - * Uses byte-access of system memory and 16-bit access of packet memory - * @param wNBytes no. of bytes to be copied. - * @retval None - */ -static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes) + * @brief Copy a buffer from user packet memory area (PMA) to FIFO. + * Uses byte-access of system memory and 16-bit access of packet memory + * @param wNBytes no. of bytes to be copied. + * @retval None + */ +static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes) { // Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies // Check for first linear part tu_fifo_buffer_info_t info; - tu_fifo_get_write_info(ff, &info); // We want to read from the FIFO + tu_fifo_get_write_info(ff, &info); // We want to read from the FIFO - uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin); + uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin); uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap); // We want to read from PMA and write it into the FIFO, if LIN part is ODD and has WRAPPED part, // last lin byte will be combined with wrapped part - // To ensure PMA is always access 16bit aligned (src aligned to 16 bit) - if((cnt_lin & 0x01) && cnt_wrap) - { + // To ensure PMA is always access aligned (src aligned to 16 or 32 bit) +#ifdef FSDEV_BUS_32BIT + if ((cnt_lin & 0x03) && cnt_wrap) { // Copy first linear part - dcd_read_packet_memory(info.ptr_lin, src, cnt_lin &~0x01); - src += cnt_lin &~0x01; + dcd_read_packet_memory(info.ptr_lin, src, cnt_lin & ~0x03); + src += cnt_lin & ~0x03; - // Copy last linear byte & first wrapped byte - uint16_t tmp; - dcd_read_packet_memory(&tmp, src, 2); + // Copy last linear bytes & first wrapped bytes + uint8_t tmp[4]; + dcd_read_packet_memory(tmp, src, 4); + src += 4; + + uint32_t i; + for (i = 0; i < (cnt_lin & 0x03); i++) { + ((uint8_t *)info.ptr_lin)[(cnt_lin & ~0x03) + i] = tmp[i]; + } + uint32_t wCnt = cnt_wrap; + for (; i < 4 && wCnt > 0; i++, wCnt--) { + *(uint8_t *)info.ptr_wrap = tmp[i]; + info.ptr_wrap = (uint8_t *)info.ptr_wrap + 1; + } - ((uint8_t*)info.ptr_lin)[cnt_lin - 1] = (uint8_t)tmp; - ((uint8_t*)info.ptr_wrap)[0] = (uint8_t)(tmp >> 8U); + // Copy rest of wrapped byte + if (wCnt) + dcd_read_packet_memory(info.ptr_wrap, src, wCnt); + } +#else + if ((cnt_lin & 0x01) && cnt_wrap) { + // Copy first linear part + dcd_read_packet_memory(info.ptr_lin, src, cnt_lin & ~0x01); + src += cnt_lin & ~0x01; + + // Copy last linear byte & first wrapped byte + uint8_t tmp[2]; + dcd_read_packet_memory(tmp, src, 2); src += 2; + ((uint8_t *)info.ptr_lin)[cnt_lin - 1] = tmp[0]; + ((uint8_t *)info.ptr_wrap)[0] = tmp[1]; + // Copy rest of wrapped byte - dcd_read_packet_memory(((uint8_t*)info.ptr_wrap) + 1, src, cnt_wrap - 1); + dcd_read_packet_memory(((uint8_t *)info.ptr_wrap) + 1, src, cnt_wrap - 1); } - else - { +#endif + else { // Copy linear part dcd_read_packet_memory(info.ptr_lin, src, cnt_lin); src += cnt_lin; - if(info.len_wrap) - { + if (info.len_wrap) { // Copy wrapped byte dcd_read_packet_memory(info.ptr_wrap, src, cnt_wrap); } diff --git a/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h b/test-devices/loopback-stm32/lib/tinyusb/portable/st/stm32_fsdev/dcd_stm32_fsdev.h similarity index 53% rename from test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h rename to test-devices/loopback-stm32/lib/tinyusb/portable/st/stm32_fsdev/dcd_stm32_fsdev.h index e3fc8aeb..7992f34a 100644 --- a/test-devices/composite-stm32/lib/tinyusb/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h +++ b/test-devices/loopback-stm32/lib/tinyusb/portable/st/stm32_fsdev/dcd_stm32_fsdev.h @@ -1,34 +1,36 @@ -/** - * Copyright(c) 2016 STMicroelectronics - * Copyright(c) N Conrad - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ +/* + * Copyright(c) 2016 STMicroelectronics + * Copyright(c) N Conrad + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the TinyUSB stack. + */ // This file contains source copied from ST's HAL, and thus should have their copyright statement. -// PMA_LENGTH is PMA buffer size in bytes. +// FSDEV_PMA_SIZE is PMA buffer size in bytes. // On 512-byte devices, access with a stride of two words (use every other 16-bit address) // On 1024-byte devices, access with a stride of one word (use every 16-bit address) @@ -37,7 +39,7 @@ #if CFG_TUSB_MCU == OPT_MCU_STM32F0 #include "stm32f0xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) // F0x2 models are crystal-less // All have internal D+ pull-up // 070RB: 2 x 16 bits/word memory LPM Support, BCD Support @@ -45,7 +47,7 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32F1 #include "stm32f1xx.h" - #define PMA_LENGTH (512u) + #define FSDEV_PMA_SIZE (512u) // NO internal Pull-ups // *B, and *C: 2 x 16 bits/word @@ -56,7 +58,7 @@ defined(STM32F303xB) || defined(STM32F303xC) || \ defined(STM32F373xC) #include "stm32f3xx.h" - #define PMA_LENGTH (512u) + #define FSDEV_PMA_SIZE (512u) // NO internal Pull-ups // *B, and *C: 1 x 16 bits/word // PMA dedicated to USB (no sharing with CAN) @@ -65,37 +67,98 @@ defined(STM32F302xD) || defined(STM32F302xE) || \ defined(STM32F303xD) || defined(STM32F303xE) #include "stm32f3xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) // NO internal Pull-ups // *6, *8, *D, and *E: 2 x 16 bits/word LPM Support // When CAN clock is enabled, USB can use first 768 bytes ONLY. #elif CFG_TUSB_MCU == OPT_MCU_STM32L0 #include "stm32l0xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) #elif CFG_TUSB_MCU == OPT_MCU_STM32L1 #include "stm32l1xx.h" - #define PMA_LENGTH (512u) + #define FSDEV_PMA_SIZE (512u) #elif CFG_TUSB_MCU == OPT_MCU_STM32G4 #include "stm32g4xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) + +#elif CFG_TUSB_MCU == OPT_MCU_STM32G0 + #include "stm32g0xx.h" + #define FSDEV_BUS_32BIT + #define FSDEV_PMA_SIZE (2048u) + #undef USB_PMAADDR + #define USB_PMAADDR USB_DRD_PMAADDR + #define USB_TypeDef USB_DRD_TypeDef + #define EP0R CHEP0R + #define USB_EP_CTR_RX USB_EP_VTRX + #define USB_EP_CTR_TX USB_EP_VTTX + #define USB_EP_T_FIELD USB_CHEP_UTYPE + #define USB_EPREG_MASK USB_CHEP_REG_MASK + #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK + #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK + #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1 + #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2 + #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1 + #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 + #define USB_EPRX_STAT USB_CH_RX_VALID + #define USB_EPKIND_MASK USB_EP_KIND_MASK + #define USB USB_DRD_FS + #define USB_CNTR_FRES USB_CNTR_USBRST + #define USB_CNTR_RESUME USB_CNTR_L2RES + #define USB_ISTR_EP_ID USB_ISTR_IDN + #define USB_EPADDR_FIELD USB_CHEP_ADDR + #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY + #define USB_CNTR_FSUSP USB_CNTR_SUSPEN + +#elif CFG_TUSB_MCU == OPT_MCU_STM32H5 + #include "stm32h5xx.h" + #define FSDEV_BUS_32BIT + + #if !defined(USB_DRD_BASE) && defined(USB_DRD_FS_BASE) + #define USB_DRD_BASE USB_DRD_FS_BASE + #endif + + #define FSDEV_PMA_SIZE (2048u) + #undef USB_PMAADDR + #define USB_PMAADDR USB_DRD_PMAADDR + #define USB_TypeDef USB_DRD_TypeDef + #define EP0R CHEP0R + #define USB_EP_CTR_RX USB_EP_VTRX + #define USB_EP_CTR_TX USB_EP_VTTX + #define USB_EP_T_FIELD USB_CHEP_UTYPE + #define USB_EPREG_MASK USB_CHEP_REG_MASK + #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK + #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK + #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1 + #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2 + #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1 + #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 + #define USB_EPRX_STAT USB_CH_RX_VALID + #define USB_EPKIND_MASK USB_EP_KIND_MASK + #define USB USB_DRD_FS + #define USB_CNTR_FRES USB_CNTR_USBRST + #define USB_CNTR_RESUME USB_CNTR_L2RES + #define USB_ISTR_EP_ID USB_ISTR_IDN + #define USB_EPADDR_FIELD USB_CHEP_ADDR + #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY + #define USB_CNTR_FSUSP USB_CNTR_SUSPEN #elif CFG_TUSB_MCU == OPT_MCU_STM32WB #include "stm32wbxx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) /* ST provided header has incorrect value */ #undef USB_PMAADDR #define USB_PMAADDR USB1_PMAADDR #elif CFG_TUSB_MCU == OPT_MCU_STM32L4 #include "stm32l4xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) #elif CFG_TUSB_MCU == OPT_MCU_STM32L5 #include "stm32l5xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) #ifndef USB_PMAADDR #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS)) @@ -107,25 +170,41 @@ #endif // For purposes of accessing the packet -#if ((PMA_LENGTH) == 512u) - #define PMA_STRIDE (2u) -#elif ((PMA_LENGTH) == 1024u) - #define PMA_STRIDE (1u) +#if ((FSDEV_PMA_SIZE) == 512u) + #define FSDEV_PMA_STRIDE (2u) +#elif ((FSDEV_PMA_SIZE) == 1024u) + #define FSDEV_PMA_STRIDE (1u) #endif -// And for type-safety create a new macro for the volatile address of PMAADDR +// The fsdev_bus_t type can be used for both register and PMA access necessities +// For type-safety create a new macro for the volatile address of PMAADDR // The compiler should warn us if we cast it to a non-volatile type? +#ifdef FSDEV_BUS_32BIT +typedef uint32_t fsdev_bus_t; +static __IO uint32_t * const pma32 = (__IO uint32_t*)USB_PMAADDR; + +#else +typedef uint16_t fsdev_bus_t; // Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden) static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR; -// prototypes -TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx); -TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx); -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue); +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) { + size_t total_word_offset = (((USBx)->BTABLE)>>1) + x; + total_word_offset *= FSDEV_PMA_STRIDE; + return &(pma[total_word_offset]); +} + +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { + return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 1u); +} + +TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { + return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 3u); +} +#endif /* Aligned buffer size according to hardware */ -TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t size) -{ +TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t size) { /* The STM32 full speed USB peripheral supports only a limited set of * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */ uint16_t blocksize = (size > 62) ? 32 : 2; @@ -136,21 +215,28 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t si return numblocks * blocksize; } -/* SetENDPOINT */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + __O uint32_t *reg = (__O uint32_t *)(USB_DRD_BASE + bEpIdx*4); + *reg = wRegValue; +#else __O uint16_t *reg = (__O uint16_t *)((&USBx->EP0R) + bEpIdx*2u); *reg = (uint16_t)wRegValue; +#endif } -/* GetENDPOINT */ -TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx) { +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + __I uint32_t *reg = (__I uint32_t *)(USB_DRD_BASE + bEpIdx*4); +#else __I uint16_t *reg = (__I uint16_t *)((&USBx->EP0R) + bEpIdx*2u); +#endif return *reg; } -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wType) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wType) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= (uint32_t)USB_EP_T_MASK; regVal |= wType; @@ -158,20 +244,19 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint pcd_set_endpoint(USBx, bEpIdx, regVal); } -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EP_T_FIELD; return regVal; } + /** * @brief Clears bit CTR_RX / CTR_TX in the endpoint register. * @param USBx USB peripheral instance register address. * @param bEpIdx Endpoint Number. * @retval None */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal &= ~USB_EP_CTR_RX; @@ -179,51 +264,42 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, pcd_set_endpoint(USBx, bEpIdx, regVal); } -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal &= ~USB_EP_CTR_TX; regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0) pcd_set_endpoint(USBx, bEpIdx,regVal); } + /** * @brief gets counter of the tx buffer. * @param USBx USB peripheral instance register address. * @param bEpIdx Endpoint Number. * @retval Counter value */ -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + return (pma32[2*bEpIdx] & 0x03FF0000) >> 16; +#else __I uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpIdx); return *regPtr & 0x3ffU; +#endif } -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + return (pma32[2*bEpIdx + 1] & 0x03FF0000) >> 16; +#else __I uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpIdx); return *regPtr & 0x3ffU; +#endif } -/** - * @brief Sets counter of rx buffer with no. of blocks. - * @param dwReg Register - * @param wCount Counter. - * @param wNBlocks no. of Blocks. - * @retval None - */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_cnt_reg(__O uint16_t * pdwReg, size_t wCount) -{ - /* We assume that the buffer size is already aligned to hardware requirements. */ - uint16_t blocksize = (wCount > 62) ? 1 : 0; - uint16_t numblocks = wCount / (blocksize ? 32 : 2); - - /* There should be no remainder in the above calculation */ - TU_ASSERT((wCount - (numblocks * (blocksize ? 32 : 2))) == 0, /**/); - - /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ - *pdwReg = (blocksize << 15) | ((numblocks - blocksize) << 10); -} +#define pcd_get_ep_dbuf0_cnt pcd_get_ep_tx_cnt +#define pcd_get_ep_dbuf1_cnt pcd_get_ep_rx_cnt /** * @brief Sets address in an endpoint register. @@ -232,8 +308,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_cnt_reg(__O uint16_t * pdwRe * @param bAddr Address. * @retval None */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t bAddr) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t bAddr) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal |= bAddr; @@ -241,59 +316,106 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, pcd_set_endpoint(USBx, bEpIdx,regVal); } -TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) -{ - size_t total_word_offset = (((USBx)->BTABLE)>>1) + x; - total_word_offset *= PMA_STRIDE; - return &(pma[total_word_offset]); +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + return pma32[2*bEpIdx] & 0x0000FFFFu ; +#else + return *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 0u); +#endif } -// Pointers to the PMA table entries (using the ARM address space) -TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_address_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) -{ - return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 0u); -} -TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) -{ - return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 1u); +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + return pma32[2*bEpIdx + 1] & 0x0000FFFFu; +#else + return *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 2u); +#endif } -TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_address_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) -{ - return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 2u); +#define pcd_get_ep_dbuf0_address pcd_get_ep_tx_address +#define pcd_get_ep_dbuf1_address pcd_get_ep_rx_address + +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + pma32[2*bEpIdx] = (pma32[2*bEpIdx] & 0xFFFF0000u) | (addr & 0x0000FFFCu); +#else + *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 0u) = addr; +#endif } -TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) -{ - return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 3u); +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & 0xFFFF0000u) | (addr & 0x0000FFFCu); +#else + *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 2u) = addr; +#endif } -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) -{ +#define pcd_set_ep_dbuf0_address pcd_set_ep_tx_address +#define pcd_set_ep_dbuf1_address pcd_set_ep_rx_address + +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + pma32[2*bEpIdx] = (pma32[2*bEpIdx] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16); +#else __IO uint16_t * reg = pcd_ep_tx_cnt_ptr(USBx, bEpIdx); *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU); +#endif } -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) -{ +#define pcd_set_ep_tx_dbuf0_cnt pcd_set_ep_tx_cnt + +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_dbuf1_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { +#ifdef FSDEV_BUS_32BIT + (void) USBx; + pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16); +#else __IO uint16_t * reg = pcd_ep_rx_cnt_ptr(USBx, bEpIdx); *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU); +#endif } -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) -{ - __IO uint16_t *pdwReg = pcd_ep_tx_cnt_ptr((USBx),(bEpIdx)); - wCount = pcd_aligned_buffer_size(wCount); - pcd_set_ep_cnt_reg(pdwReg, wCount); +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDef * USBx, uint32_t rxtx_idx, + uint32_t blocksize, uint32_t numblocks) { + /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ +#ifdef FSDEV_BUS_32BIT + (void) USBx; + pma32[rxtx_idx] = (pma32[rxtx_idx] & 0x0000FFFFu) | (blocksize << 31) | ((numblocks - blocksize) << 26); +#else + __IO uint16_t *pdwReg = pcd_btable_word_ptr(USBx, rxtx_idx*2u + 1u); + *pdwReg = (blocksize << 15) | ((numblocks - blocksize) << 10); +#endif } -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) -{ - __IO uint16_t *pdwReg = pcd_ep_rx_cnt_ptr((USBx),(bEpIdx)); +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_bufsize(USB_TypeDef * USBx, uint32_t rxtx_idx, uint32_t wCount) { wCount = pcd_aligned_buffer_size(wCount); - pcd_set_ep_cnt_reg(pdwReg, wCount); + + /* We assume that the buffer size is already aligned to hardware requirements. */ + uint16_t blocksize = (wCount > 62) ? 1 : 0; + uint16_t numblocks = wCount / (blocksize ? 32 : 2); + + /* There should be no remainder in the above calculation */ + TU_ASSERT((wCount - (numblocks * (blocksize ? 32 : 2))) == 0, /**/); + + /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ + pcd_set_ep_blsize_num_blocks(USBx, rxtx_idx, blocksize, numblocks); +} + +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_dbuf0_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { + pcd_set_ep_bufsize(USBx, 2*bEpIdx, wCount); +} + +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { + pcd_set_ep_bufsize(USBx, 2*bEpIdx + 1, wCount); } +#define pcd_set_ep_rx_dbuf1_cnt pcd_set_ep_rx_cnt + /** * @brief sets the status for tx transfer (bits STAT_TX[1:0]). * @param USBx USB peripheral instance register address. @@ -301,8 +423,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_bufsize(USB_TypeDef * USB * @param wState new state * @retval None */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPTX_DTOGMASK; @@ -319,7 +440,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; pcd_set_endpoint(USBx, bEpIdx, regVal); -} /* pcd_set_ep_tx_status */ +} /** * @brief sets the status for rx transfer (bits STAT_TX[1:0]) @@ -329,31 +450,27 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx * @retval None */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPRX_DTOGMASK; /* toggle first bit ? */ - if((USB_EPRX_DTOG1 & wState)!= 0U) - { + if((USB_EPRX_DTOG1 & wState)!= 0U) { regVal ^= USB_EPRX_DTOG1; } /* toggle second bit ? */ - if((USB_EPRX_DTOG2 & wState)!= 0U) - { + if((USB_EPRX_DTOG2 & wState)!= 0U) { regVal ^= USB_EPRX_DTOG2; } regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; pcd_set_endpoint(USBx, bEpIdx, regVal); -} /* pcd_set_ep_rx_status */ +} -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); return (regVal & USB_EPRX_STAT) >> (12u); -} /* pcd_get_ep_rx_status */ +} /** @@ -362,16 +479,14 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * * @param bEpIdx Endpoint Number. * @retval None */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_RX; pcd_set_endpoint(USBx, bEpIdx, regVal); } -TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_TX; @@ -384,21 +499,16 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32 * @param bEpIdx Endpoint Number. * @retval None */ - -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - if((regVal & USB_EP_DTOG_RX) != 0) - { + if((regVal & USB_EP_DTOG_RX) != 0) { pcd_rx_dtog(USBx,bEpIdx); } } -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - if((regVal & USB_EP_DTOG_TX) != 0) - { + if((regVal & USB_EP_DTOG_TX) != 0) { pcd_tx_dtog(USBx,bEpIdx); } } @@ -409,17 +519,15 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, * @param bEpIdx Endpoint Number. * @retval None */ - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) -{ +TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal |= USB_EP_KIND; regVal &= USB_EPREG_MASK; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; pcd_set_endpoint(USBx, bEpIdx, regVal); } -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) -{ + +TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPKIND_MASK; regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c b/test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dcd_dwc2.c similarity index 60% rename from test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c rename to test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dcd_dwc2.c index aa6757ee..692096fc 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dcd_dwc2.c +++ b/test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dcd_dwc2.c @@ -82,8 +82,8 @@ static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2]; typedef struct { - uint8_t * buffer; - tu_fifo_t * ff; + uint8_t* buffer; + tu_fifo_t* ff; uint16_t total_len; uint16_t max_size; uint8_t interval; @@ -93,45 +93,182 @@ static xfer_ctl_t xfer_status[DWC2_EP_MAX][2]; #define XFER_CTL_BASE(_ep, _dir) (&xfer_status[_ep][_dir]) // EP0 transfers are limited to 1 packet - larger sizes has to be split -static uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type +static uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type // TX FIFO RAM allocation so far in words - RX FIFO size is readily available from dwc2->grxfsiz -static uint16_t _allocated_fifo_words_tx; // TX FIFO size in words (IN EPs) -static bool _out_ep_closed; // Flag to check if RX FIFO size needs an update (reduce its size) +static uint16_t _allocated_fifo_words_tx; // TX FIFO size in words (IN EPs) // SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by static bool _sof_en; -// Calculate the RX FIFO size according to recommendations from reference manual -static inline uint16_t calc_grxfsiz(uint16_t max_ep_size, uint8_t ep_count) -{ - return 15 + 2*(max_ep_size/4) + 2*ep_count; +// Calculate the RX FIFO size according to minimum recommendations from reference manual +// RxFIFO = (5 * number of control endpoints + 8) + +// ((largest USB packet used / 4) + 1 for status information) + +// (2 * number of OUT endpoints) + 1 for Global NAK +// with number of control endpoints = 1 we have +// RxFIFO = 15 + (largest USB packet used / 4) + 2 * number of OUT endpoints +// we double the largest USB packet size to be able to hold up to 2 packets +static inline uint16_t calc_grxfsiz(uint16_t max_ep_size, uint8_t ep_count) { + return 15 + 2 * (max_ep_size / 4) + 2 * ep_count; } -static void update_grxfsiz(uint8_t rhport) -{ - dwc2_regs_t * dwc2 = DWC2_REG(rhport); +TU_ATTR_ALWAYS_INLINE static inline void fifo_flush_tx(dwc2_regs_t* dwc2, uint8_t epnum) { + // flush TX fifo and wait for it cleared + dwc2->grstctl = GRSTCTL_TXFFLSH | (epnum << GRSTCTL_TXFNUM_Pos); + while (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) {} +} +TU_ATTR_ALWAYS_INLINE static inline void fifo_flush_rx(dwc2_regs_t* dwc2) { + // flush RX fifo and wait for it cleared + dwc2->grstctl = GRSTCTL_RXFFLSH; + while (dwc2->grstctl & GRSTCTL_RXFFLSH_Msk) {} +} + +static bool fifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + TU_ASSERT(epnum < ep_count); + + uint16_t fifo_size = tu_div_ceil(packet_size, 4); + + // "USB Data FIFOs" section in reference manual + // Peripheral FIFO architecture + // + // --------------- 320 or 1024 ( 1280 or 4096 bytes ) + // | IN FIFO 0 | + // --------------- (320 or 1024) - 16 + // | IN FIFO 1 | + // --------------- (320 or 1024) - 16 - x + // | . . . . | + // --------------- (320 or 1024) - 16 - x - y - ... - z + // | IN FIFO MAX | + // --------------- + // | FREE | + // --------------- GRXFSIZ + // | OUT FIFO | + // | ( Shared ) | + // --------------- 0 + // + // In FIFO is allocated by following rules: + // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n". + if (dir == TUSB_DIR_OUT) { + // Calculate required size of RX FIFO + uint16_t const sz = calc_grxfsiz(4 * fifo_size, ep_count); + + // If size_rx needs to be extended check if possible and if so enlarge it + if (dwc2->grxfsiz < sz) { + TU_ASSERT(sz + _allocated_fifo_words_tx <= _dwc2_controller[rhport].ep_fifo_size / 4); + + // Enlarge RX FIFO + dwc2->grxfsiz = sz; + } + } else { + // Note if The TXFELVL is configured as half empty. In order + // to be able to write a packet at that point, the fifo must be twice the max_size. + if ((dwc2->gahbcfg & GAHBCFG_TXFELVL) == 0) { + fifo_size *= 2; + } - // Determine largest EP size for RX FIFO - uint16_t max_epsize = 0; - for (uint8_t epnum = 0; epnum < ep_count; epnum++) - { - max_epsize = tu_max16(max_epsize, xfer_status[epnum][TUSB_DIR_OUT].max_size); + // Check if free space is available + TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= _dwc2_controller[rhport].ep_fifo_size / 4); + _allocated_fifo_words_tx += fifo_size; + TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %" PRIu32, fifo_size * 4, + _dwc2_controller[rhport].ep_fifo_size - _allocated_fifo_words_tx * 4); + + // DIEPTXF starts at FIFO #1. + // Both TXFD and TXSA are in unit of 32-bit words. + dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | + (_dwc2_controller[rhport].ep_fifo_size / 4 - _allocated_fifo_words_tx); } - // Update size of RX FIFO - dwc2->grxfsiz = calc_grxfsiz(max_epsize, ep_count); + return true; +} + +static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); + uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); + + xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir); + xfer->max_size = tu_edpt_packet_size(p_endpoint_desc); + xfer->interval = p_endpoint_desc->bInterval; + + // USBAEP, EPTYP, SD0PID_SEVNFRM, MPSIZ are the same for IN and OUT endpoints. + uint32_t const dxepctl = (1 << DOEPCTL_USBAEP_Pos) | + (p_endpoint_desc->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) | + (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) | + (xfer->max_size << DOEPCTL_MPSIZ_Pos); + + if (dir == TUSB_DIR_OUT) { + dwc2->epout[epnum].doepctl = dxepctl; + dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum); + } else { + dwc2->epin[epnum].diepctl = dxepctl | (epnum << DIEPCTL_TXFNUM_Pos); + dwc2->daintmsk |= (1 << (DAINTMSK_IEPM_Pos + epnum)); + } +} + +static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) { + (void) rhport; + + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + if (dir == TUSB_DIR_IN) { + dwc2_epin_t* epin = dwc2->epin; + + // Only disable currently enabled non-control endpoint + if ((epnum == 0) || !(epin[epnum].diepctl & DIEPCTL_EPENA)) { + epin[epnum].diepctl |= DIEPCTL_SNAK | (stall ? DIEPCTL_STALL : 0); + } else { + // Stop transmitting packets and NAK IN xfers. + epin[epnum].diepctl |= DIEPCTL_SNAK; + while ((epin[epnum].diepint & DIEPINT_INEPNE) == 0) {} + + // Disable the endpoint. + epin[epnum].diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0); + while ((epin[epnum].diepint & DIEPINT_EPDISD_Msk) == 0) {} + + epin[epnum].diepint = DIEPINT_EPDISD; + } + + // Flush the FIFO, and wait until we have confirmed it cleared. + fifo_flush_tx(dwc2, epnum); + } else { + dwc2_epout_t* epout = dwc2->epout; + + // Only disable currently enabled non-control endpoint + if ((epnum == 0) || !(epout[epnum].doepctl & DOEPCTL_EPENA)) { + epout[epnum].doepctl |= stall ? DOEPCTL_STALL : 0; + } else { + // Asserting GONAK is required to STALL an OUT endpoint. + // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt + // anyway, and it can't be cleared by user code. If this while loop never + // finishes, we have bigger problems than just the stack. + dwc2->dctl |= DCTL_SGONAK; + while ((dwc2->gintsts & GINTSTS_BOUTNAKEFF_Msk) == 0) {} + + // Ditto here- disable the endpoint. + epout[epnum].doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0); + while ((epout[epnum].doepint & DOEPINT_EPDISD_Msk) == 0) {} + + epout[epnum].doepint = DOEPINT_EPDISD; + + // Allow other OUT endpoints to keep receiving. + dwc2->dctl |= DCTL_CGONAK; + } + } } // Start of Bus Reset -static void bus_reset(uint8_t rhport) -{ - dwc2_regs_t * dwc2 = DWC2_REG(rhport); +static void bus_reset(uint8_t rhport) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint8_t const ep_count = _dwc2_controller[rhport].ep_count; tu_memclr(xfer_status, sizeof(xfer_status)); - _out_ep_closed = false; _sof_en = false; @@ -139,15 +276,24 @@ static void bus_reset(uint8_t rhport) dwc2->dcfg &= ~DCFG_DAD_Msk; // 1. NAK for all OUT endpoints - for ( uint8_t n = 0; n < ep_count; n++ ) - { + for (uint8_t n = 0; n < ep_count; n++) { dwc2->epout[n].doepctl |= DOEPCTL_SNAK; } - // 2. Set up interrupt mask + // 2. Disable all IN endpoints + for (uint8_t n = 0; n < ep_count; n++) { + if (dwc2->epin[n].diepctl & DIEPCTL_EPENA) { + dwc2->epin[n].diepctl |= DIEPCTL_SNAK | DIEPCTL_EPDIS; + } + } + + fifo_flush_tx(dwc2, 0x10); // all tx fifo + fifo_flush_rx(dwc2); + + // 3. Set up interrupt mask dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos); - dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM; - dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM; + dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM; + dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM; // "USB Data FIFOs" section in reference manual // Peripheral FIFO architecture @@ -206,38 +352,34 @@ static void bus_reset(uint8_t rhport) _allocated_fifo_words_tx = 16; // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word ) - dwc2->dieptxf0 = (16 << DIEPTXF0_TX0FD_Pos) | (_dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx); + dwc2->dieptxf0 = (16 << DIEPTXF0_TX0FD_Pos) | (_dwc2_controller[rhport].ep_fifo_size / 4 - _allocated_fifo_words_tx); // Fixed control EP0 size to 64 bytes dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos); xfer_status[0][TUSB_DIR_OUT].max_size = 64; - xfer_status[0][TUSB_DIR_IN ].max_size = 64; + xfer_status[0][TUSB_DIR_IN].max_size = 64; dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); dwc2->gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT; } -static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets, uint16_t total_bytes) -{ +static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets, + uint16_t total_bytes) { (void) rhport; - TU_ASSERT(epnum < DWC2_EP_MAX, ); - - dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2_regs_t* dwc2 = DWC2_REG(rhport); // EP0 is limited to one packet each xfer // We use multiple transaction of xfer->max_size length to get a whole transfer done - if ( epnum == 0 ) - { - xfer_ctl_t *const xfer = XFER_CTL_BASE(epnum, dir); + if (epnum == 0) { + xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir); total_bytes = tu_min16(ep0_pending[dir], xfer->max_size); ep0_pending[dir] -= total_bytes; } // IN and OUT endpoint xfers are interrupt-driven, we just schedule them here. - if ( dir == TUSB_DIR_IN ) - { + if (dir == TUSB_DIR_IN) { dwc2_epin_t* epin = dwc2->epin; // A full IN transfer (multiple packets, possibly) triggers XFRC. @@ -247,20 +389,16 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c epin[epnum].diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK; // For ISO endpoint set correct odd/even bit for next frame. - if ( (epin[epnum].diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1 ) - { + if ((epin[epnum].diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1) { // Take odd/even bit from frame counter. uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); epin[epnum].diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk); } // Enable fifo empty interrupt only if there are something to put in the fifo. - if ( total_bytes != 0 ) - { + if (total_bytes != 0) { dwc2->diepempmsk |= (1 << epnum); } - } - else - { + } else { dwc2_epout_t* epout = dwc2->epout; // A full OUT transfer (multiple packets, possibly) triggers XFRC. @@ -269,9 +407,8 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c ((total_bytes << DOEPTSIZ_XFRSIZ_Pos) & DOEPTSIZ_XFRSIZ_Msk); epout[epnum].doepctl |= DOEPCTL_EPENA | DOEPCTL_CNAK; - if ( (epout[epnum].doepctl & DOEPCTL_EPTYP) == DOEPCTL_EPTYP_0 && - XFER_CTL_BASE(epnum, dir)->interval == 1 ) - { + if ((epout[epnum].doepctl & DOEPCTL_EPTYP) == DOEPCTL_EPTYP_0 && + XFER_CTL_BASE(epnum, dir)->interval == 1) { // Take odd/even bit from frame counter. uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); epout[epnum].doepctl |= (odd_frame_now ? DOEPCTL_SD0PID_SEVNFRM_Msk : DOEPCTL_SODDFRM_Msk); @@ -283,103 +420,46 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c /* Controller API *------------------------------------------------------------------*/ #if CFG_TUSB_DEBUG >= DWC2_DEBUG -void print_dwc2_info(dwc2_regs_t * dwc2) -{ - dwc2_ghwcfg2_t const * hw_cfg2 = &dwc2->ghwcfg2_bm; - dwc2_ghwcfg3_t const * hw_cfg3 = &dwc2->ghwcfg3_bm; - dwc2_ghwcfg4_t const * hw_cfg4 = &dwc2->ghwcfg4_bm; - -// TU_LOG_HEX(DWC2_DEBUG, dwc2->gotgctl); -// TU_LOG_HEX(DWC2_DEBUG, dwc2->gusbcfg); -// TU_LOG_HEX(DWC2_DEBUG, dwc2->dcfg); - TU_LOG_HEX(DWC2_DEBUG, dwc2->guid); - TU_LOG_HEX(DWC2_DEBUG, dwc2->gsnpsid); - TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg1); - - // HW configure 2 - TU_LOG(DWC2_DEBUG, "\r\n"); - TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg2); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->op_mode ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->arch ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->point2point ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->hs_phy_type ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->fs_phy_type ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->num_dev_ep ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->num_host_ch ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->period_channel_support ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->enable_dynamic_fifo ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->mul_cpu_int ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->nperiod_tx_q_depth ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->host_period_tx_q_depth ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->dev_token_q_depth ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg2->otg_enable_ic_usb ); - - // HW configure 3 - TU_LOG(DWC2_DEBUG, "\r\n"); - TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg3); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->xfer_size_width ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->packet_size_width ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_enable ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->i2c_enable ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->vendor_ctrl_itf ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->optional_feature_removed ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->synch_reset ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_adp_support ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_enable_hsic ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->battery_charger_support ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->lpm_mode ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg3->total_fifo_size ); - - // HW configure 4 - TU_LOG(DWC2_DEBUG, "\r\n"); - TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg4); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->num_dev_period_in_ep ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->power_optimized ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->ahb_freq_min ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->hibernation ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->service_interval_mode ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->ipg_isoc_en ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->acg_enable ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->utmi_phy_data_width ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dev_ctrl_ep_num ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->iddg_filter_enabled ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->vbus_valid_filter_enabled ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->a_valid_filter_enabled ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->b_valid_filter_enabled ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dedicated_fifos ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->num_dev_in_eps ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dma_desc_enable ); - TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dma_dynamic ); +void print_dwc2_info(dwc2_regs_t* dwc2) { + // print guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4 + // use dwc2_info.py/md for bit-field value and comparison with other ports + volatile uint32_t const* p = (volatile uint32_t const*) &dwc2->guid; + TU_LOG(DWC2_DEBUG, "guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4\r\n"); + for (size_t i = 0; i < 5; i++) { + TU_LOG(DWC2_DEBUG, "0x%08" PRIX32 ", ", p[i]); + } + TU_LOG(DWC2_DEBUG, "0x%08" PRIX32 "\r\n", p[5]); } #endif -static void reset_core(dwc2_regs_t * dwc2) -{ +static void reset_core(dwc2_regs_t* dwc2) { // reset core dwc2->grstctl |= GRSTCTL_CSRST; // wait for reset bit is cleared // TODO version 4.20a should wait for RESET DONE mask - while (dwc2->grstctl & GRSTCTL_CSRST) { } + while (dwc2->grstctl & GRSTCTL_CSRST) {} // wait for AHB master IDLE - while ( !(dwc2->grstctl & GRSTCTL_AHBIDL) ) { } + while (!(dwc2->grstctl & GRSTCTL_AHBIDL)) {} // wait for device mode ? } -static bool phy_hs_supported(dwc2_regs_t * dwc2) -{ - // note: esp32 incorrect report its hs_phy_type as utmi +static bool phy_hs_supported(dwc2_regs_t* dwc2) { + (void) dwc2; + #if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + // note: esp32 incorrect report its hs_phy_type as utmi + return false; +#elif !TUD_OPT_HIGH_SPEED return false; #else - return TUD_OPT_HIGH_SPEED && dwc2->ghwcfg2_bm.hs_phy_type != HS_PHY_TYPE_NONE; + return dwc2->ghwcfg2_bm.hs_phy_type != HS_PHY_TYPE_NONE; #endif } -static void phy_fs_init(dwc2_regs_t * dwc2) -{ +static void phy_fs_init(dwc2_regs_t* dwc2) { TU_LOG(DWC2_DEBUG, "Fullspeed PHY init\r\n"); // Select FS PHY @@ -403,15 +483,13 @@ static void phy_fs_init(dwc2_regs_t * dwc2) dwc2->dcfg = (dwc2->dcfg & ~DCFG_DSPD_Msk) | (DCFG_DSPD_FS << DCFG_DSPD_Pos); } -static void phy_hs_init(dwc2_regs_t * dwc2) -{ +static void phy_hs_init(dwc2_regs_t* dwc2) { uint32_t gusbcfg = dwc2->gusbcfg; // De-select FS PHY gusbcfg &= ~GUSBCFG_PHYSEL; - if (dwc2->ghwcfg2_bm.hs_phy_type == HS_PHY_TYPE_ULPI) - { + if (dwc2->ghwcfg2_bm.hs_phy_type == HS_PHY_TYPE_ULPI) { TU_LOG(DWC2_DEBUG, "Highspeed ULPI PHY init\r\n"); // Select ULPI @@ -425,8 +503,7 @@ static void phy_hs_init(dwc2_regs_t * dwc2) // Disable FS/LS ULPI gusbcfg &= ~(GUSBCFG_ULPIFSLS | GUSBCFG_ULPICSM); - }else - { + } else { TU_LOG(DWC2_DEBUG, "Highspeed UTMI+ PHY init\r\n"); // Select UTMI+ with 8-bit interface @@ -467,8 +544,7 @@ static void phy_hs_init(dwc2_regs_t * dwc2) dwc2->dcfg = dcfg; } -static bool check_dwc2(dwc2_regs_t * dwc2) -{ +static bool check_dwc2(dwc2_regs_t* dwc2) { #if CFG_TUSB_DEBUG >= DWC2_DEBUG print_dwc2_info(dwc2); #endif @@ -483,41 +559,35 @@ static bool check_dwc2(dwc2_regs_t * dwc2) return true; } -void dcd_init (uint8_t rhport) -{ +void dcd_init(uint8_t rhport) { // Programming model begins in the last section of the chapter on the USB // peripheral in each Reference Manual. - dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2_regs_t* dwc2 = DWC2_REG(rhport); // Check Synopsys ID register, failed if controller clock/power is not enabled - TU_VERIFY(check_dwc2(dwc2), ); - + if (!check_dwc2(dwc2)) return; dcd_disconnect(rhport); // max number of endpoints & total_fifo_size are: // hw_cfg2->num_dev_ep, hw_cfg2->total_fifo_size - if( phy_hs_supported(dwc2) ) - { - // Highspeed - phy_hs_init(dwc2); - }else - { - // core does not support highspeed or hs-phy is not present - phy_fs_init(dwc2); + if (phy_hs_supported(dwc2)) { + phy_hs_init(dwc2); // Highspeed + } else { + phy_fs_init(dwc2); // core does not support highspeed or hs phy is not present } // Restart PHY clock dwc2->pcgctl &= ~(PCGCTL_STOPPCLK | PCGCTL_GATEHCLK | PCGCTL_PWRCLMP | PCGCTL_RSTPDWNMODULE); - /* Set HS/FS Timeout Calibration to 7 (max available value). - * The number of PHY clocks that the application programs in - * this field is added to the high/full speed interpacket timeout - * duration in the core to account for any additional delays - * introduced by the PHY. This can be required, because the delay - * introduced by the PHY in generating the linestate condition - * can vary from one PHY to another. - */ + /* Set HS/FS Timeout Calibration to 7 (max available value). + * The number of PHY clocks that the application programs in + * this field is added to the high/full speed interpacket timeout + * duration in the core to account for any additional delays + * introduced by the PHY. This can be required, because the delay + * introduced by the PHY in generating the linestate condition + * can vary from one PHY to another. + */ dwc2->gusbcfg |= (7ul << GUSBCFG_TOCAL_Pos); // Force device mode @@ -530,6 +600,9 @@ void dcd_init (uint8_t rhport) // (non zero-length packet), send STALL back and discard. dwc2->dcfg |= DCFG_NZLSOHSK; + fifo_flush_tx(dwc2, 0x10); // all tx fifo + fifo_flush_rx(dwc2); + // Clear all interrupts uint32_t int_mask = dwc2->gintsts; dwc2->gintsts |= int_mask; @@ -537,11 +610,12 @@ void dcd_init (uint8_t rhport) dwc2->gotgint |= int_mask; // Required as part of core initialization. - // TODO: How should mode mismatch be handled? It will cause - // the core to stop working/require reset. - dwc2->gintmsk = GINTMSK_OTGINT | GINTMSK_MMISM | GINTMSK_RXFLVLM | + dwc2->gintmsk = GINTMSK_OTGINT | GINTMSK_RXFLVLM | GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM; + // Configure TX FIFO empty level for interrupt. Default is complete empty + dwc2->gahbcfg |= GAHBCFG_TXFELVL; + // Enable global interrupt dwc2->gahbcfg |= GAHBCFG_GINT; @@ -556,30 +630,26 @@ void dcd_init (uint8_t rhport) dcd_connect(rhport); } -void dcd_int_enable (uint8_t rhport) -{ +void dcd_int_enable(uint8_t rhport) { dwc2_dcd_int_enable(rhport); } -void dcd_int_disable (uint8_t rhport) -{ +void dcd_int_disable(uint8_t rhport) { dwc2_dcd_int_disable(rhport); } -void dcd_set_address (uint8_t rhport, uint8_t dev_addr) -{ - dwc2_regs_t * dwc2 = DWC2_REG(rhport); +void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); dwc2->dcfg = (dwc2->dcfg & ~DCFG_DAD_Msk) | (dev_addr << DCFG_DAD_Pos); // Response with status after changing device address dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); } -void dcd_remote_wakeup(uint8_t rhport) -{ +void dcd_remote_wakeup(uint8_t rhport) { (void) rhport; - dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2_regs_t* dwc2 = DWC2_REG(rhport); // set remote wakeup dwc2->dctl |= DCTL_RWUSIG; @@ -594,35 +664,29 @@ void dcd_remote_wakeup(uint8_t rhport) dwc2->dctl &= ~DCTL_RWUSIG; } -void dcd_connect(uint8_t rhport) -{ +void dcd_connect(uint8_t rhport) { (void) rhport; - dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2_regs_t* dwc2 = DWC2_REG(rhport); dwc2->dctl &= ~DCTL_SDIS; } -void dcd_disconnect(uint8_t rhport) -{ +void dcd_disconnect(uint8_t rhport) { (void) rhport; - dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2_regs_t* dwc2 = DWC2_REG(rhport); dwc2->dctl |= DCTL_SDIS; } // Be advised: audio, video and possibly other iso-ep classes use dcd_sof_enable() to enable/disable its corresponding ISR on purpose! -void dcd_sof_enable(uint8_t rhport, bool en) -{ +void dcd_sof_enable(uint8_t rhport, bool en) { (void) rhport; - dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2_regs_t* dwc2 = DWC2_REG(rhport); _sof_en = en; - if (en) - { + if (en) { dwc2->gintsts = GINTSTS_SOF; dwc2->gintmsk |= GINTMSK_SOFM; - } - else - { + } else { dwc2->gintmsk &= ~GINTMSK_SOFM; } } @@ -631,143 +695,78 @@ void dcd_sof_enable(uint8_t rhport, bool en) /* DCD Endpoint port *------------------------------------------------------------------*/ -bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) -{ - (void) rhport; - - dwc2_regs_t * dwc2 = DWC2_REG(rhport); - uint8_t const ep_count = _dwc2_controller[rhport].ep_count; - - uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress); - uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress); - - TU_ASSERT(epnum < ep_count); - - xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); - xfer->max_size = tu_edpt_packet_size(desc_edpt); - xfer->interval = desc_edpt->bInterval; - - uint16_t const fifo_size = tu_div_ceil(xfer->max_size, 4); - - if(dir == TUSB_DIR_OUT) - { - // Calculate required size of RX FIFO - uint16_t const sz = calc_grxfsiz(4*fifo_size, ep_count); - - // If size_rx needs to be extended check if possible and if so enlarge it - if (dwc2->grxfsiz < sz) - { - TU_ASSERT(sz + _allocated_fifo_words_tx <= _dwc2_controller[rhport].ep_fifo_size/4); - - // Enlarge RX FIFO - dwc2->grxfsiz = sz; - } - - dwc2->epout[epnum].doepctl |= (1 << DOEPCTL_USBAEP_Pos) | - (desc_edpt->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) | - (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) | - (xfer->max_size << DOEPCTL_MPSIZ_Pos); - - dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum); - } - else - { - // "USB Data FIFOs" section in reference manual - // Peripheral FIFO architecture - // - // --------------- 320 or 1024 ( 1280 or 4096 bytes ) - // | IN FIFO 0 | - // --------------- (320 or 1024) - 16 - // | IN FIFO 1 | - // --------------- (320 or 1024) - 16 - x - // | . . . . | - // --------------- (320 or 1024) - 16 - x - y - ... - z - // | IN FIFO MAX | - // --------------- - // | FREE | - // --------------- GRXFSIZ - // | OUT FIFO | - // | ( Shared ) | - // --------------- 0 - // - // In FIFO is allocated by following rules: - // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n". - - // Check if free space is available - TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= _dwc2_controller[rhport].ep_fifo_size/4); - - _allocated_fifo_words_tx += fifo_size; - - TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %lu", fifo_size*4, _dwc2_controller[rhport].ep_fifo_size-_allocated_fifo_words_tx*4); - - // DIEPTXF starts at FIFO #1. - // Both TXFD and TXSA are in unit of 32-bit words. - dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | (_dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx); - - dwc2->epin[epnum].diepctl |= (1 << DIEPCTL_USBAEP_Pos) | - (epnum << DIEPCTL_TXFNUM_Pos) | - (desc_edpt->bmAttributes.xfer << DIEPCTL_EPTYP_Pos) | - (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DIEPCTL_SD0PID_SEVNFRM : 0) | - (xfer->max_size << DIEPCTL_MPSIZ_Pos); - - dwc2->daintmsk |= (1 << (DAINTMSK_IEPM_Pos + epnum)); - } - +bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { + TU_ASSERT(fifo_alloc(rhport, desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt))); + edpt_activate(rhport, desc_edpt); return true; } // Close all non-control endpoints, cancel all pending transfers if any. -void dcd_edpt_close_all (uint8_t rhport) -{ - dwc2_regs_t * dwc2 = DWC2_REG(rhport); +void dcd_edpt_close_all(uint8_t rhport) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint8_t const ep_count = _dwc2_controller[rhport].ep_count; // Disable non-control interrupt dwc2->daintmsk = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos); - for(uint8_t n = 1; n < ep_count; n++) - { + for (uint8_t n = 1; n < ep_count; n++) { // disable OUT endpoint - dwc2->epout[n].doepctl = 0; + if (dwc2->epout[n].doepctl & DOEPCTL_EPENA) { + dwc2->epout[n].doepctl |= DOEPCTL_SNAK | DOEPCTL_EPDIS; + } xfer_status[n][TUSB_DIR_OUT].max_size = 0; // disable IN endpoint - dwc2->epin[n].diepctl = 0; + if (dwc2->epin[n].diepctl & DIEPCTL_EPENA) { + dwc2->epin[n].diepctl |= DIEPCTL_SNAK | DIEPCTL_EPDIS; + } xfer_status[n][TUSB_DIR_IN].max_size = 0; } + // reset allocated fifo OUT + dwc2->grxfsiz = calc_grxfsiz(64, ep_count); // reset allocated fifo IN _allocated_fifo_words_tx = 16; + + fifo_flush_tx(dwc2, 0x10); // all tx fifo + fifo_flush_rx(dwc2); } -bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) -{ - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + TU_ASSERT(fifo_alloc(rhport, ep_addr, largest_packet_size)); + return true; +} - uint8_t const ep_count = _dwc2_controller[rhport].ep_count; - TU_ASSERT(epnum < ep_count); +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) { + // Disable EP to clear potential incomplete transfers + edpt_disable(rhport, p_endpoint_desc->bEndpointAddress, false); - xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); - xfer->buffer = buffer; - xfer->ff = NULL; - xfer->total_len = total_bytes; + edpt_activate(rhport, p_endpoint_desc); + + return true; +} + +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir); + xfer->buffer = buffer; + xfer->ff = NULL; + xfer->total_len = total_bytes; // EP0 can only handle one packet - if(epnum == 0) - { + if (epnum == 0) { ep0_pending[dir] = total_bytes; // Schedule the first transaction for EP0 transfer edpt_schedule_packets(rhport, epnum, dir, 1, ep0_pending[dir]); - } - else - { + } else { uint16_t num_packets = (total_bytes / xfer->max_size); uint16_t const short_packet_size = total_bytes % xfer->max_size; // Zero-size packet is special case. - if ( (short_packet_size > 0) || (total_bytes == 0) ) num_packets++; + if ((short_packet_size > 0) || (total_bytes == 0)) num_packets++; // Schedule packets to be sent within interrupt edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes); @@ -780,27 +779,23 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t // bytes should be written and second to keep the return value free to give back a boolean // success message. If total_bytes is too big, the FIFO will copy only what is available // into the USB buffer! -bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) -{ +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t total_bytes) { // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1 TU_ASSERT(ff->item_size == 1); uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); - uint8_t const ep_count = _dwc2_controller[rhport].ep_count; - TU_ASSERT(epnum < ep_count); - - xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); - xfer->buffer = NULL; - xfer->ff = ff; - xfer->total_len = total_bytes; + xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir); + xfer->buffer = NULL; + xfer->ff = ff; + xfer->total_len = total_bytes; uint16_t num_packets = (total_bytes / xfer->max_size); uint16_t const short_packet_size = total_bytes % xfer->max_size; // Zero-size packet is special case. - if ( short_packet_size > 0 || (total_bytes == 0) ) num_packets++; + if (short_packet_size > 0 || (total_bytes == 0)) num_packets++; // Schedule packets to be sent within interrupt edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes); @@ -808,123 +803,27 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 return true; } -static void dcd_edpt_disable (uint8_t rhport, uint8_t ep_addr, bool stall) -{ - (void) rhport; - - dwc2_regs_t *dwc2 = DWC2_REG(rhport); - - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - - if ( dir == TUSB_DIR_IN ) - { - dwc2_epin_t* epin = dwc2->epin; - - // Only disable currently enabled non-control endpoint - if ( (epnum == 0) || !(epin[epnum].diepctl & DIEPCTL_EPENA) ) - { - epin[epnum].diepctl |= DIEPCTL_SNAK | (stall ? DIEPCTL_STALL : 0); - } - else - { - // Stop transmitting packets and NAK IN xfers. - epin[epnum].diepctl |= DIEPCTL_SNAK; - while ( (epin[epnum].diepint & DIEPINT_INEPNE) == 0 ) {} - - // Disable the endpoint. - epin[epnum].diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0); - while ( (epin[epnum].diepint & DIEPINT_EPDISD_Msk) == 0 ) {} - - epin[epnum].diepint = DIEPINT_EPDISD; - } - - // Flush the FIFO, and wait until we have confirmed it cleared. - dwc2->grstctl = ((epnum << GRSTCTL_TXFNUM_Pos) | GRSTCTL_TXFFLSH); - while ( (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) != 0 ) {} - } - else - { - dwc2_epout_t* epout = dwc2->epout; - - // Only disable currently enabled non-control endpoint - if ( (epnum == 0) || !(epout[epnum].doepctl & DOEPCTL_EPENA) ) - { - epout[epnum].doepctl |= stall ? DOEPCTL_STALL : 0; - } - else - { - // Asserting GONAK is required to STALL an OUT endpoint. - // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt - // anyway, and it can't be cleared by user code. If this while loop never - // finishes, we have bigger problems than just the stack. - dwc2->dctl |= DCTL_SGONAK; - while ( (dwc2->gintsts & GINTSTS_BOUTNAKEFF_Msk) == 0 ) {} - - // Ditto here- disable the endpoint. - epout[epnum].doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0); - while ( (epout[epnum].doepint & DOEPINT_EPDISD_Msk) == 0 ) {} - - epout[epnum].doepint = DOEPINT_EPDISD; - - // Allow other OUT endpoints to keep receiving. - dwc2->dctl |= DCTL_CGONAK; - } - } -} - -/** - * Close an endpoint. - */ -void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) -{ - dwc2_regs_t * dwc2 = DWC2_REG(rhport); - - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - - dcd_edpt_disable(rhport, ep_addr, false); - - // Update max_size - xfer_status[epnum][dir].max_size = 0; // max_size = 0 marks a disabled EP - required for changing FIFO allocation - - if (dir == TUSB_DIR_IN) - { - uint16_t const fifo_size = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXFD_Msk) >> DIEPTXF_INEPTXFD_Pos; - uint16_t const fifo_start = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXSA_Msk) >> DIEPTXF_INEPTXSA_Pos; - - // For now only the last opened endpoint can be closed without fuss. - TU_ASSERT(fifo_start == _dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx,); - _allocated_fifo_words_tx -= fifo_size; - } - else - { - _out_ep_closed = true; // Set flag such that RX FIFO gets reduced in size once RX FIFO is empty - } +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { + edpt_disable(rhport, ep_addr, false); } -void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) -{ - dcd_edpt_disable(rhport, ep_addr, true); +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { + edpt_disable(rhport, ep_addr, true); } -void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) -{ +void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { (void) rhport; - dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); // Clear stall and reset data toggle - if ( dir == TUSB_DIR_IN ) - { + if (dir == TUSB_DIR_IN) { dwc2->epin[epnum].diepctl &= ~DIEPCTL_STALL; dwc2->epin[epnum].diepctl |= DIEPCTL_SD0PID_SEVNFRM; - } - else - { + } else { dwc2->epout[epnum].doepctl &= ~DOEPCTL_STALL; dwc2->epout[epnum].doepctl |= DOEPCTL_SD0PID_SEVNFRM; } @@ -933,70 +832,63 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) /*------------------------------------------------------------------*/ // Read a single data packet from receive FIFO -static void read_fifo_packet(uint8_t rhport, uint8_t * dst, uint16_t len) -{ +static void read_fifo_packet(uint8_t rhport, uint8_t* dst, uint16_t len) { (void) rhport; - dwc2_regs_t * dwc2 = DWC2_REG(rhport); - volatile const uint32_t * rx_fifo = dwc2->fifo[0]; + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + volatile const uint32_t* rx_fifo = dwc2->fifo[0]; // Reading full available 32 bit words from fifo uint16_t full_words = len >> 2; - while(full_words--) - { + while (full_words--) { tu_unaligned_write32(dst, *rx_fifo); dst += 4; } // Read the remaining 1-3 bytes from fifo uint8_t const bytes_rem = len & 0x03; - if ( bytes_rem != 0 ) - { + if (bytes_rem != 0) { uint32_t const tmp = *rx_fifo; dst[0] = tu_u32_byte0(tmp); - if ( bytes_rem > 1 ) dst[1] = tu_u32_byte1(tmp); - if ( bytes_rem > 2 ) dst[2] = tu_u32_byte2(tmp); + if (bytes_rem > 1) dst[1] = tu_u32_byte1(tmp); + if (bytes_rem > 2) dst[2] = tu_u32_byte2(tmp); } } // Write a single data packet to EPIN FIFO -static void write_fifo_packet(uint8_t rhport, uint8_t fifo_num, uint8_t const * src, uint16_t len) -{ +static void write_fifo_packet(uint8_t rhport, uint8_t fifo_num, uint8_t const* src, uint16_t len) { (void) rhport; - dwc2_regs_t * dwc2 = DWC2_REG(rhport); - volatile uint32_t * tx_fifo = dwc2->fifo[fifo_num]; + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + volatile uint32_t* tx_fifo = dwc2->fifo[fifo_num]; // Pushing full available 32 bit words to fifo uint16_t full_words = len >> 2; - while(full_words--) - { + while (full_words--) { *tx_fifo = tu_unaligned_read32(src); src += 4; } // Write the remaining 1-3 bytes into fifo uint8_t const bytes_rem = len & 0x03; - if ( bytes_rem ) - { + if (bytes_rem) { uint32_t tmp_word = src[0]; - if ( bytes_rem > 1 ) tmp_word |= (src[1] << 8); - if ( bytes_rem > 2 ) tmp_word |= (src[2] << 16); + if (bytes_rem > 1) tmp_word |= (src[1] << 8); + if (bytes_rem > 2) tmp_word |= (src[2] << 16); *tx_fifo = tmp_word; } } -static void handle_rxflvl_irq(uint8_t rhport) -{ - dwc2_regs_t * dwc2 = DWC2_REG(rhport); - volatile uint32_t const * rx_fifo = dwc2->fifo[0]; +static void handle_rxflvl_irq(uint8_t rhport) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + volatile uint32_t const* rx_fifo = dwc2->fifo[0]; // Pop control word off FIFO uint32_t const ctl_word = dwc2->grxstsp; - uint8_t const pktsts = (ctl_word & GRXSTSP_PKTSTS_Msk ) >> GRXSTSP_PKTSTS_Pos; - uint8_t const epnum = (ctl_word & GRXSTSP_EPNUM_Msk ) >> GRXSTSP_EPNUM_Pos; - uint16_t const bcnt = (ctl_word & GRXSTSP_BCNT_Msk ) >> GRXSTSP_BCNT_Pos; + uint8_t const pktsts = (ctl_word & GRXSTSP_PKTSTS_Msk) >> GRXSTSP_PKTSTS_Pos; + uint8_t const epnum = (ctl_word & GRXSTSP_EPNUM_Msk) >> GRXSTSP_EPNUM_Pos; + uint16_t const bcnt = (ctl_word & GRXSTSP_BCNT_Msk) >> GRXSTSP_BCNT_Pos; dwc2_epout_t* epout = &dwc2->epout[epnum]; @@ -1011,10 +903,10 @@ static void handle_rxflvl_irq(uint8_t rhport) // TU_LOG(DWC2_DEBUG, " daint = %08lX, doepint = %04X\r\n", (unsigned long) dwc2->daint, (unsigned int) epout->doepint); //#endif - switch ( pktsts ) - { + switch (pktsts) { // Global OUT NAK: do nothing - case GRXSTS_PKTSTS_GLOBALOUTNAK: break; + case GRXSTS_PKTSTS_GLOBALOUTNAK: + break; case GRXSTS_PKTSTS_SETUPRX: // Setup packet received @@ -1023,29 +915,22 @@ static void handle_rxflvl_irq(uint8_t rhport) // only the last one is valid. _setup_packet[0] = (*rx_fifo); _setup_packet[1] = (*rx_fifo); - break; + break; case GRXSTS_PKTSTS_SETUPDONE: // Setup packet done (Interrupt) epout->doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); - break; + break; - case GRXSTS_PKTSTS_OUTRX: - { - uint8_t const ep_count = _dwc2_controller[rhport].ep_count; - TU_ASSERT(epnum < ep_count, ); - + case GRXSTS_PKTSTS_OUTRX: { // Out packet received - xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); + xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); // Read packet off RxFIFO - if ( xfer->ff ) - { + if (xfer->ff) { // Ring buffer tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void*) (uintptr_t) rx_fifo, bcnt); - } - else - { + } else { // Linear buffer read_fifo_packet(rhport, xfer->buffer, bcnt); @@ -1054,73 +939,64 @@ static void handle_rxflvl_irq(uint8_t rhport) } // Truncate transfer length in case of short packet - if ( bcnt < xfer->max_size ) - { + if (bcnt < xfer->max_size) { xfer->total_len -= (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos; - if ( epnum == 0 ) - { + if (epnum == 0) { xfer->total_len -= ep0_pending[TUSB_DIR_OUT]; ep0_pending[TUSB_DIR_OUT] = 0; } } } - break; + break; - // Out packet done (Interrupt) + // Out packet done (Interrupt) case GRXSTS_PKTSTS_OUTDONE: - // Occurred on STM32L47 with dwc2 version 3.10a but not found on other version like 2.80a or 3.30a - // May (or not) be 3.10a specific feature/bug or depending on MCU configuration - // XFRC complete is additionally generated when - // - setup packet is received - // - complete the data stage of control write is complete - if ((epnum == 0) && (bcnt == 0) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) - { - uint32_t doepint = epout->doepint; - - if (doepint & (DOEPINT_STPKTRX | DOEPINT_OTEPSPR)) - { - // skip this "no-data" transfer complete event - // Note: STPKTRX will be clear later by setup received handler - uint32_t clear_flags = DOEPINT_XFRC; - - if (doepint & DOEPINT_OTEPSPR) clear_flags |= DOEPINT_OTEPSPR; - - epout->doepint = clear_flags; - - // TU_LOG(DWC2_DEBUG, " FIX extra transfer complete on setup/data compete\r\n"); - } + // Occurred on STM32L47 with dwc2 version 3.10a but not found on other version like 2.80a or 3.30a + // May (or not) be 3.10a specific feature/bug or depending on MCU configuration + // XFRC complete is additionally generated when + // - setup packet is received + // - complete the data stage of control write is complete + if ((epnum == 0) && (bcnt == 0) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) { + uint32_t doepint = epout->doepint; + + if (doepint & (DOEPINT_STPKTRX | DOEPINT_OTEPSPR)) { + // skip this "no-data" transfer complete event + // Note: STPKTRX will be clear later by setup received handler + uint32_t clear_flags = DOEPINT_XFRC; + + if (doepint & DOEPINT_OTEPSPR) clear_flags |= DOEPINT_OTEPSPR; + + epout->doepint = clear_flags; + + // TU_LOG(DWC2_DEBUG, " FIX extra transfer complete on setup/data compete\r\n"); } - break; + } + break; default: // Invalid TU_BREAKPOINT(); - break; + break; } } -static void handle_epout_irq (uint8_t rhport) -{ - dwc2_regs_t * dwc2 = DWC2_REG(rhport); +static void handle_epout_irq(uint8_t rhport) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint8_t const ep_count = _dwc2_controller[rhport].ep_count; // DAINT for a given EP clears when DOEPINTx is cleared. // OEPINT will be cleared when DAINT's out bits are cleared. - for ( uint8_t n = 0; n < ep_count; n++ ) - { - if ( dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + n) ) - { + for (uint8_t n = 0; n < ep_count; n++) { + if (dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + n)) { dwc2_epout_t* epout = &dwc2->epout[n]; uint32_t const doepint = epout->doepint; // SETUP packet Setup Phase done. - if ( doepint & DOEPINT_STUP ) - { + if (doepint & DOEPINT_STUP) { uint32_t clear_flag = DOEPINT_STUP; // STPKTRX is only available for version from 3_00a - if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) - { + if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) { clear_flag |= DOEPINT_STPKTRX; } @@ -1129,20 +1005,16 @@ static void handle_epout_irq (uint8_t rhport) } // OUT XFER complete - if ( epout->doepint & DOEPINT_XFRC ) - { + if (epout->doepint & DOEPINT_XFRC) { epout->doepint = DOEPINT_XFRC; - xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT); + xfer_ctl_t* xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT); // EP0 can only handle one packet - if ( (n == 0) && ep0_pending[TUSB_DIR_OUT] ) - { + if ((n == 0) && ep0_pending[TUSB_DIR_OUT]) { // Schedule another packet to be received. edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); - } - else - { + } else { dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true); } } @@ -1150,40 +1022,32 @@ static void handle_epout_irq (uint8_t rhport) } } -static void handle_epin_irq (uint8_t rhport) -{ - dwc2_regs_t * dwc2 = DWC2_REG(rhport); +static void handle_epin_irq(uint8_t rhport) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint8_t const ep_count = _dwc2_controller[rhport].ep_count; - dwc2_epin_t* epin = dwc2->epin; + dwc2_epin_t* epin = dwc2->epin; // DAINT for a given EP clears when DIEPINTx is cleared. // IEPINT will be cleared when DAINT's out bits are cleared. - for ( uint8_t n = 0; n < ep_count; n++ ) - { - if ( dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + n) ) - { + for (uint8_t n = 0; n < ep_count; n++) { + if (dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + n)) { // IN XFER complete (entire xfer). - xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_IN); + xfer_ctl_t* xfer = XFER_CTL_BASE(n, TUSB_DIR_IN); - if ( epin[n].diepint & DIEPINT_XFRC ) - { + if (epin[n].diepint & DIEPINT_XFRC) { epin[n].diepint = DIEPINT_XFRC; // EP0 can only handle one packet - if ( (n == 0) && ep0_pending[TUSB_DIR_IN] ) - { + if ((n == 0) && ep0_pending[TUSB_DIR_IN]) { // Schedule another packet to be transmitted. edpt_schedule_packets(rhport, n, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]); - } - else - { + } else { dcd_event_xfer_complete(rhport, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); } } // XFER FIFO empty - if ( (epin[n].diepint & DIEPINT_TXFE) && (dwc2->diepempmsk & (1 << n)) ) - { + if ((epin[n].diepint & DIEPINT_TXFE) && (dwc2->diepempmsk & (1 << n))) { // diepint's TXFE bit is read-only, software cannot clear it. // It will only be cleared by hardware when written bytes is more than // - 64 bytes or @@ -1192,8 +1056,7 @@ static void handle_epin_irq (uint8_t rhport) uint16_t remaining_packets = (epin[n].dieptsiz & DIEPTSIZ_PKTCNT_Msk) >> DIEPTSIZ_PKTCNT_Pos; // Process every single packet (only whole packets can be written to fifo) - for ( uint16_t i = 0; i < remaining_packets; i++ ) - { + for (uint16_t i = 0; i < remaining_packets; i++) { uint16_t const remaining_bytes = (epin[n].dieptsiz & DIEPTSIZ_XFRSIZ_Msk) >> DIEPTSIZ_XFRSIZ_Pos; // Packet can not be larger than ep max size @@ -1201,16 +1064,13 @@ static void handle_epin_irq (uint8_t rhport) // It's only possible to write full packets into FIFO. Therefore DTXFSTS register of current // EP has to be checked if the buffer can take another WHOLE packet - if ( packet_size > ((epin[n].dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2) ) break; + if (packet_size > ((epin[n].dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2)) break; // Push packet to Tx-FIFO - if ( xfer->ff ) - { - volatile uint32_t *tx_fifo = dwc2->fifo[n]; + if (xfer->ff) { + volatile uint32_t* tx_fifo = dwc2->fifo[n]; tu_fifo_read_n_const_addr_full_words(xfer->ff, (void*) (uintptr_t) tx_fifo, packet_size); - } - else - { + } else { write_fifo_packet(rhport, n, xfer->buffer, packet_size); // Increment pointer to xfer data @@ -1219,8 +1079,7 @@ static void handle_epin_irq (uint8_t rhport) } // Turn off TXFE if all bytes are written. - if ( ((epin[n].dieptsiz & DIEPTSIZ_XFRSIZ_Msk) >> DIEPTSIZ_XFRSIZ_Pos) == 0 ) - { + if (((epin[n].dieptsiz & DIEPTSIZ_XFRSIZ_Msk) >> DIEPTSIZ_XFRSIZ_Pos) == 0) { dwc2->diepempmsk &= ~(1 << n); } } @@ -1228,55 +1087,50 @@ static void handle_epin_irq (uint8_t rhport) } } -void dcd_int_handler(uint8_t rhport) -{ - dwc2_regs_t *dwc2 = DWC2_REG(rhport); +void dcd_int_handler(uint8_t rhport) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint32_t const int_mask = dwc2->gintmsk; uint32_t const int_status = dwc2->gintsts & int_mask; - if(int_status & GINTSTS_USBRST) - { + if (int_status & GINTSTS_USBRST) { // USBRST is start of reset. dwc2->gintsts = GINTSTS_USBRST; bus_reset(rhport); } - if(int_status & GINTSTS_ENUMDNE) - { + if (int_status & GINTSTS_ENUMDNE) { // ENUMDNE is the end of reset where speed of the link is detected - dwc2->gintsts = GINTSTS_ENUMDNE; tusb_speed_t speed; - switch ((dwc2->dsts & DSTS_ENUMSPD_Msk) >> DSTS_ENUMSPD_Pos) - { + switch ((dwc2->dsts & DSTS_ENUMSPD_Msk) >> DSTS_ENUMSPD_Pos) { case DSTS_ENUMSPD_HS: speed = TUSB_SPEED_HIGH; - break; + break; case DSTS_ENUMSPD_LS: speed = TUSB_SPEED_LOW; - break; + break; case DSTS_ENUMSPD_FS_HSPHY: case DSTS_ENUMSPD_FS: default: speed = TUSB_SPEED_FULL; - break; + break; } + // TODO must update GUSBCFG_TRDT according to link speed + dcd_event_bus_reset(rhport, speed, true); } - if(int_status & GINTSTS_USBSUSP) - { + if (int_status & GINTSTS_USBSUSP) { dwc2->gintsts = GINTSTS_USBSUSP; dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); } - if(int_status & GINTSTS_WKUINT) - { + if (int_status & GINTSTS_WKUINT) { dwc2->gintsts = GINTSTS_WKUINT; dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); } @@ -1284,73 +1138,52 @@ void dcd_int_handler(uint8_t rhport) // TODO check GINTSTS_DISCINT for disconnect detection // if(int_status & GINTSTS_DISCINT) - if(int_status & GINTSTS_OTGINT) - { + if (int_status & GINTSTS_OTGINT) { // OTG INT bit is read-only uint32_t const otg_int = dwc2->gotgint; - if (otg_int & GOTGINT_SEDET) - { + if (otg_int & GOTGINT_SEDET) { dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); } dwc2->gotgint = otg_int; } - if(int_status & GINTSTS_SOF) - { + if(int_status & GINTSTS_SOF) { dwc2->gintsts = GINTSTS_SOF; + const uint32_t frame = (dwc2->dsts & DSTS_FNSOF) >> DSTS_FNSOF_Pos; - if (_sof_en) - { - uint32_t frame = (dwc2->dsts & (DSTS_FNSOF)) >> 8; - dcd_event_sof(rhport, frame, true); - } - else - { - // Disable SOF interrupt if SOF was not explicitly enabled. SOF was used for remote wakeup detection + // Disable SOF interrupt if SOF was not explicitly enabled since SOF was used for remote wakeup detection + if (!_sof_en) { dwc2->gintmsk &= ~GINTMSK_SOFM; } - dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true); + dcd_event_sof(rhport, frame, true); } // RxFIFO non-empty interrupt handling. - if(int_status & GINTSTS_RXFLVL) - { + if (int_status & GINTSTS_RXFLVL) { // RXFLVL bit is read-only // Mask out RXFLVL while reading data from FIFO dwc2->gintmsk &= ~GINTMSK_RXFLVLM; // Loop until all available packets were handled - do - { + do { handle_rxflvl_irq(rhport); } while(dwc2->gintsts & GINTSTS_RXFLVL); - // Manage RX FIFO size - if (_out_ep_closed) - { - update_grxfsiz(rhport); - - // Disable flag - _out_ep_closed = false; - } - dwc2->gintmsk |= GINTMSK_RXFLVLM; } // OUT endpoint interrupt handling. - if(int_status & GINTSTS_OEPINT) - { + if (int_status & GINTSTS_OEPINT) { // OEPINT is read-only, clear using DOEPINTn handle_epout_irq(rhport); } // IN endpoint interrupt handling. - if(int_status & GINTSTS_IEPINT) - { + if (int_status & GINTSTS_IEPINT) { // IEPINT bit read-only, clear using DIEPINTn handle_epin_irq(rhport); } diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_bcm.h b/test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_bcm.h similarity index 100% rename from test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_bcm.h rename to test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_bcm.h diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_efm32.h b/test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_efm32.h similarity index 100% rename from test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_efm32.h rename to test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_efm32.h diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_esp32.h b/test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_esp32.h similarity index 100% rename from test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_esp32.h rename to test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_esp32.h diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_gd32.h b/test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_gd32.h similarity index 100% rename from test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_gd32.h rename to test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_gd32.h diff --git a/test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_info.md b/test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_info.md new file mode 100644 index 00000000..8690a075 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_info.md @@ -0,0 +1,55 @@ +| | BCM2711 (Pi4) | EFM32GG FullSpeed | ESP32-S2 | STM32F407 Fullspeed | STM32F407 Highspeed | STM32F411 Fullspeed | STM32F412 Fullspeed | STM32F429 Fullspeed | STM32F429 Highspeed | STM32F723 Fullspeed | STM32F723 HighSpeed | STM32F767 Fullspeed | STM32H743 Highspeed | STM32L476 Fullspeed | STM32U5A5 Highspeed | GD32VF103 Fullspeed | XMC4500 | +|:----------------------------|:----------------|:--------------------|:-----------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:-----------| +| guid | 0x2708A000 | 0x00000000 | 0x00000000 | 0x00001200 | 0x00001100 | 0x00001200 | 0x00002000 | 0x00001200 | 0x00001100 | 0x00003000 | 0x00003100 | 0x00002000 | 0x00002300 | 0x00002000 | 0x00005000 | 0x00001000 | 0x00AEC000 | +| gsnpsid | 0x4F54280A | 0x4F54330A | 0x4F54400A | 0x4F54281A | 0x4F54281A | 0x4F54281A | 0x4F54320A | 0x4F54281A | 0x4F54281A | 0x4F54330A | 0x4F54330A | 0x4F54320A | 0x4F54330A | 0x4F54310A | 0x4F54411A | 0x00000000 | 0x4F54292A | +| - specs version | 2.80a | 3.30a | 4.00a | 2.81a | 2.81a | 2.81a | 3.20a | 2.81a | 2.81a | 3.30a | 3.30a | 3.20a | 3.30a | 3.10a | 4.11a | 0.00W | 2.92a | +| ghwcfg1 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | +| ghwcfg2 | 0x228DDD50 | 0x228F5910 | 0x224DD930 | 0x229DCD20 | 0x229ED590 | 0x229DCD20 | 0x229ED520 | 0x229DCD20 | 0x229ED590 | 0x229ED520 | 0x229FE1D0 | 0x229ED520 | 0x229FE190 | 0x229ED520 | 0x228FE052 | 0x00000000 | 0x228F5930 | +| - op_mode | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | +| - arch | 2 | 2 | 2 | 0 | 2 | 0 | 0 | 0 | 2 | 0 | 2 | 0 | 2 | 0 | 2 | 0 | 2 | +| - point2point | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | +| - hs_phy_type | 1 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 2 | 0 | 3 | 0 | 2 | 0 | 1 | 0 | 0 | +| - fs_phy_type | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | +| - num_dev_ep | 7 | 6 | 6 | 3 | 5 | 3 | 5 | 3 | 5 | 5 | 8 | 5 | 8 | 5 | 8 | 0 | 6 | +| - num_host_ch | 7 | 13 | 7 | 7 | 11 | 7 | 11 | 7 | 11 | 11 | 15 | 11 | 15 | 11 | 15 | 0 | 13 | +| - period_channel_support | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | +| - enable_dynamic_fifo | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | +| - mul_cpu_int | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | +| - reserved21 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| - nperiod_tx_q_depth | 2 | 2 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 0 | 2 | +| - host_period_tx_q_depth | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 0 | 2 | +| - dev_token_q_depth | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 0 | 8 | +| - otg_enable_ic_usb | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| ghwcfg3 | 0x0FF000E8 | 0x01F204E8 | 0x00C804B5 | 0x020001E8 | 0x03F403E8 | 0x020001E8 | 0x0200D1E8 | 0x020001E8 | 0x03F403E8 | 0x0200D1E8 | 0x03EED2E8 | 0x0200D1E8 | 0x03B8D2E8 | 0x0200D1E8 | 0x03B882E8 | 0x00000000 | 0x027A01E5 | +| - xfer_size_width | 8 | 8 | 5 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 0 | 5 | +| - packet_size_width | 6 | 6 | 3 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 0 | 6 | +| - otg_enable | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | +| - i2c_enable | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | +| - vendor_ctrl_itf | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | +| - optional_feature_removed | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| - synch_reset | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| - otg_adp_support | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | +| - otg_enable_hsic | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| - battery_charger_support | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | +| - lpm_mode | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | +| - total_fifo_size | 4080 | 498 | 200 | 512 | 1012 | 512 | 512 | 512 | 1012 | 512 | 1006 | 512 | 952 | 512 | 952 | 0 | 634 | +| ghwcfg4 | 0x1FF00020 | 0x1BF08030 | 0xD3F0A030 | 0x0FF08030 | 0x17F00030 | 0x0FF08030 | 0x17F08030 | 0x0FF08030 | 0x17F00030 | 0x17F08030 | 0x23F00030 | 0x17F08030 | 0xE3F00030 | 0x17F08030 | 0xE2103E30 | 0x00000000 | 0xDBF08030 | +| - num_dev_period_in_ep | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| - power_optimized | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | +| - ahb_freq_min | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | +| - hibernation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| - reserved7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | +| - service_interval_mode | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | +| - ipg_isoc_en | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | +| - acg_enable | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | +| - reserved13 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | +| - utmi_phy_data_width | 0 | 2 | 2 | 2 | 0 | 2 | 2 | 2 | 0 | 2 | 0 | 2 | 0 | 2 | 0 | 0 | 2 | +| - dev_ctrl_ep_num | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| - iddg_filter_enabled | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | +| - vbus_valid_filter_enabled | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | +| - a_valid_filter_enabled | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | +| - b_valid_filter_enabled | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | +| - dedicated_fifos | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | +| - num_dev_in_eps | 15 | 13 | 9 | 7 | 11 | 7 | 11 | 7 | 11 | 11 | 1 | 11 | 1 | 11 | 1 | 0 | 13 | +| - dma_desc_enable | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | +| - dma_dynamic | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | diff --git a/test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_info.py b/test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_info.py new file mode 100644 index 00000000..55bec3d2 --- /dev/null +++ b/test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_info.py @@ -0,0 +1,169 @@ +import click +import ctypes +import pandas as pd + +# hex value for register: guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4 +dwc2_reg_list = ['guid', 'gsnpsid', 'ghwcfg1', 'ghwcfg2', 'ghwcfg3', 'ghwcfg4'] +dwc2_reg_value = { + 'BCM2711 (Pi4)': [0x2708A000, 0x4F54280A, 0, 0x228DDD50, 0xFF000E8, 0x1FF00020], + 'EFM32GG FullSpeed': [0, 0x4F54330A, 0, 0x228F5910, 0x1F204E8, 0x1BF08030], + 'ESP32-S2': [0, 0x4F54400A, 0, 0x224DD930, 0xC804B5, 0xD3F0A030], + 'STM32F407 Fullspeed': [0x1200, 0x4F54281A, 0, 0x229DCD20, 0x20001E8, 0xFF08030], + 'STM32F407 Highspeed': [0x1100, 0x4F54281A, 0, 0x229ED590, 0x3F403E8, 0x17F00030], + 'STM32F411 Fullspeed': [0x1200, 0x4F54281A, 0, 0x229DCD20, 0x20001E8, 0xFF08030], + 'STM32F412 Fullspeed': [0x2000, 0x4F54320A, 0, 0x229ED520, 0x200D1E8, 0x17F08030], + 'STM32F429 Fullspeed': [0x1200, 0x4F54281A, 0, 0x229DCD20, 0x20001E8, 0xFF08030], + 'STM32F429 Highspeed': [0x1100, 0x4F54281A, 0, 0x229ED590, 0x3F403E8, 0x17F00030], + 'STM32F723 Fullspeed': [0x3000, 0x4F54330A, 0, 0x229ED520, 0x200D1E8, 0x17F08030], + 'STM32F723 HighSpeed': [0x3100, 0x4F54330A, 0, 0x229FE1D0, 0x3EED2E8, 0x23F00030], + 'STM32F767 Fullspeed': [0x2000, 0x4F54320A, 0, 0x229ED520, 0x200D1E8, 0x17F08030], + 'STM32H743 Highspeed': [0x2300, 0x4F54330A, 0, 0x229FE190, 0x3B8D2E8, 0xE3F00030], # both HS cores + 'STM32L476 Fullspeed': [0x2000, 0x4F54310A, 0, 0x229ED520, 0x200D1E8, 0x17F08030], + 'STM32U5A5 Highspeed': [0x00005000, 0x4F54411A, 0x00000000, 0x228FE052, 0x03B882E8, 0xE2103E30], + 'GD32VF103 Fullspeed': [0x1000, 0, 0, 0, 0, 0], + 'XMC4500': [0xAEC000, 0x4F54292A, 0, 0x228F5930, 0x27A01E5, 0xDBF08030] +} + +# Combine dwc2_info with dwc2_reg_list +# dwc2_info = { +# 'BCM2711 (Pi4)': { +# 'guid': 0x2708A000, +# 'gsnpsid': 0x4F54280A, +# 'ghwcfg1': 0, +# 'ghwcfg2': 0x228DDD50, +# 'ghwcfg3': 0xFF000E8, +# 'ghwcfg4': 0x1FF00020 +# }, +dwc2_info = {key: {field: value for field, value in zip(dwc2_reg_list, values)} for key, values in dwc2_reg_value.items()} + + +class GHWCFG2(ctypes.LittleEndianStructure): + _fields_ = [ + ("op_mode", ctypes.c_uint32, 3), + ("arch", ctypes.c_uint32, 2), + ("point2point", ctypes.c_uint32, 1), + ("hs_phy_type", ctypes.c_uint32, 2), + ("fs_phy_type", ctypes.c_uint32, 2), + ("num_dev_ep", ctypes.c_uint32, 4), + ("num_host_ch", ctypes.c_uint32, 4), + ("period_channel_support", ctypes.c_uint32, 1), + ("enable_dynamic_fifo", ctypes.c_uint32, 1), + ("mul_cpu_int", ctypes.c_uint32, 1), + ("reserved21", ctypes.c_uint32, 1), + ("nperiod_tx_q_depth", ctypes.c_uint32, 2), + ("host_period_tx_q_depth", ctypes.c_uint32, 2), + ("dev_token_q_depth", ctypes.c_uint32, 5), + ("otg_enable_ic_usb", ctypes.c_uint32, 1) + ] + + +class GHWCFG3(ctypes.LittleEndianStructure): + _fields_ = [ + ("xfer_size_width", ctypes.c_uint32, 4), + ("packet_size_width", ctypes.c_uint32, 3), + ("otg_enable", ctypes.c_uint32, 1), + ("i2c_enable", ctypes.c_uint32, 1), + ("vendor_ctrl_itf", ctypes.c_uint32, 1), + ("optional_feature_removed", ctypes.c_uint32, 1), + ("synch_reset", ctypes.c_uint32, 1), + ("otg_adp_support", ctypes.c_uint32, 1), + ("otg_enable_hsic", ctypes.c_uint32, 1), + ("battery_charger_support", ctypes.c_uint32, 1), + ("lpm_mode", ctypes.c_uint32, 1), + ("total_fifo_size", ctypes.c_uint32, 16) + ] + + +class GHWCFG4(ctypes.LittleEndianStructure): + _fields_ = [ + ("num_dev_period_in_ep", ctypes.c_uint32, 4), + ("power_optimized", ctypes.c_uint32, 1), + ("ahb_freq_min", ctypes.c_uint32, 1), + ("hibernation", ctypes.c_uint32, 1), + ("reserved7", ctypes.c_uint32, 3), + ("service_interval_mode", ctypes.c_uint32, 1), + ("ipg_isoc_en", ctypes.c_uint32, 1), + ("acg_enable", ctypes.c_uint32, 1), + ("reserved13", ctypes.c_uint32, 1), + ("utmi_phy_data_width", ctypes.c_uint32, 2), + ("dev_ctrl_ep_num", ctypes.c_uint32, 4), + ("iddg_filter_enabled", ctypes.c_uint32, 1), + ("vbus_valid_filter_enabled", ctypes.c_uint32, 1), + ("a_valid_filter_enabled", ctypes.c_uint32, 1), + ("b_valid_filter_enabled", ctypes.c_uint32, 1), + ("dedicated_fifos", ctypes.c_uint32, 1), + ("num_dev_in_eps", ctypes.c_uint32, 4), + ("dma_desc_enable", ctypes.c_uint32, 1), + ("dma_dynamic", ctypes.c_uint32, 1) + ] + + +@click.group() +def cli(): + pass + + +@cli.command() +@click.argument('mcus', nargs=-1) +@click.option('-a', '--all', is_flag=True, help='Print all bit-field values') +def info(mcus, all): + """Print DWC2 register values for given MCU(s)""" + if len(mcus) == 0: + mcus = dwc2_info + + for mcu in mcus: + for entry in dwc2_info: + if mcu.lower() in entry.lower(): + print(f"## {entry}") + for r_name, r_value in dwc2_info[entry].items(): + print(f"{r_name} = 0x{r_value:08X}") + # Print bit-field values + if all and r_name.upper() in globals(): + class_name = globals()[r_name.upper()] + ghwcfg = class_name.from_buffer_copy(r_value.to_bytes(4, byteorder='little')) + for field_name, field_type, _ in class_name._fields_: + print(f" {field_name} = {getattr(ghwcfg, field_name)}") + + +@cli.command() +def render_md(): + """Render dwc2_info to Markdown table""" + # Create an empty list to hold the dictionaries + dwc2_info_list = [] + + # Iterate over the dwc2_info dictionary and extract fields + for device, reg_values in dwc2_info.items(): + entry_dict = {"Device": device} + for r_name, r_value in reg_values.items(): + entry_dict[r_name] = f"0x{r_value:08X}" + + if r_name == 'gsnpsid': + # Get dwc2 specs version + major = ((r_value >> 8) >> 4) & 0x0F + minor = (r_value >> 4) & 0xFF + patch = chr((r_value & 0x0F) + ord('a') - 0xA) + entry_dict[f' - specs version'] = f"{major:X}.{minor:02X}{patch}" + elif r_name.upper() in globals(): + # Get bit-field values which exist as ctypes structures + class_name = globals()[r_name.upper()] + ghwcfg = class_name.from_buffer_copy(r_value.to_bytes(4, byteorder='little')) + for field_name, field_type, _ in class_name._fields_: + entry_dict[f' - {field_name}'] = getattr(ghwcfg, field_name) + + dwc2_info_list.append(entry_dict) + + # Create a Pandas DataFrame from the list of dictionaries + df = pd.DataFrame(dwc2_info_list).set_index('Device') + + # Transpose the DataFrame to switch rows and columns + df = df.T + #print(df) + + # Write the Markdown table to a file + with open('dwc2_info.md', 'w') as md_file: + md_file.write(df.to_markdown()) + md_file.write('\n') + + +if __name__ == '__main__': + cli() diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_stm32.h b/test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_stm32.h similarity index 63% rename from test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_stm32.h rename to test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_stm32.h index cb455bd9..3237a50f 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_stm32.h +++ b/test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_stm32.h @@ -24,11 +24,11 @@ * This file is part of the TinyUSB stack. */ -#ifndef _DWC2_STM32_H_ -#define _DWC2_STM32_H_ +#ifndef DWC2_STM32_H_ +#define DWC2_STM32_H_ #ifdef __cplusplus - extern "C" { +extern "C" { #endif // EP_MAX : Max number of bi-directional endpoints including EP0 @@ -84,10 +84,16 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32U5 #include "stm32u5xx.h" - #define USB_OTG_FS_PERIPH_BASE USB_OTG_FS_BASE - #define EP_MAX_FS 6 - #define EP_FIFO_SIZE_FS 1280 - + // U59x/5Ax/5Fx/5Gx are highspeed with built-in HS PHY + #ifdef USB_OTG_FS + #define USB_OTG_FS_PERIPH_BASE USB_OTG_FS_BASE + #define EP_MAX_FS 6 + #define EP_FIFO_SIZE_FS 1280 + #else + #define USB_OTG_HS_PERIPH_BASE USB_OTG_HS_BASE + #define EP_MAX_HS 9 + #define EP_FIFO_SIZE_HS 4096 + #endif #else #error "Unsupported MCUs" #endif @@ -101,15 +107,14 @@ // On STM32 for consistency we associate // - Port0 to OTG_FS, and Port1 to OTG_HS -static const dwc2_controller_t _dwc2_controller[] = -{ -#ifdef USB_OTG_FS_PERIPH_BASE - { .reg_base = USB_OTG_FS_PERIPH_BASE, .irqnum = OTG_FS_IRQn, .ep_count = EP_MAX_FS, .ep_fifo_size = EP_FIFO_SIZE_FS }, -#endif - -#ifdef USB_OTG_HS_PERIPH_BASE - { .reg_base = USB_OTG_HS_PERIPH_BASE, .irqnum = OTG_HS_IRQn, .ep_count = EP_MAX_HS, .ep_fifo_size = EP_FIFO_SIZE_HS }, -#endif +static const dwc2_controller_t _dwc2_controller[] = { + #ifdef USB_OTG_FS_PERIPH_BASE + { .reg_base = USB_OTG_FS_PERIPH_BASE, .irqnum = OTG_FS_IRQn, .ep_count = EP_MAX_FS, .ep_fifo_size = EP_FIFO_SIZE_FS }, + #endif + + #ifdef USB_OTG_HS_PERIPH_BASE + { .reg_base = USB_OTG_HS_PERIPH_BASE, .irqnum = OTG_HS_IRQn, .ep_count = EP_MAX_HS, .ep_fifo_size = EP_FIFO_SIZE_HS }, + #endif }; //--------------------------------------------------------------------+ @@ -119,42 +124,59 @@ static const dwc2_controller_t _dwc2_controller[] = // SystemCoreClock is already included by family header // extern uint32_t SystemCoreClock; -TU_ATTR_ALWAYS_INLINE -static inline void dwc2_dcd_int_enable(uint8_t rhport) -{ - NVIC_EnableIRQ((IRQn_Type)_dwc2_controller[rhport].irqnum); +TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_enable(uint8_t rhport) { + NVIC_EnableIRQ((IRQn_Type) _dwc2_controller[rhport].irqnum); } -TU_ATTR_ALWAYS_INLINE -static inline void dwc2_dcd_int_disable (uint8_t rhport) -{ - NVIC_DisableIRQ((IRQn_Type)_dwc2_controller[rhport].irqnum); +TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_disable(uint8_t rhport) { + NVIC_DisableIRQ((IRQn_Type) _dwc2_controller[rhport].irqnum); } -TU_ATTR_ALWAYS_INLINE -static inline void dwc2_remote_wakeup_delay(void) -{ +TU_ATTR_ALWAYS_INLINE static inline void dwc2_remote_wakeup_delay(void) { // try to delay for 1 ms uint32_t count = SystemCoreClock / 1000; - while ( count-- ) __NOP(); + while (count--) __NOP(); } // MCU specific PHY init, called BEFORE core reset -static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) -{ - if ( hs_phy_type == HS_PHY_TYPE_NONE ) - { +// - dwc2 3.30a (H5) use USB_HS_PHYC +// - dwc2 4.11a (U5) use femtoPHY +static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) { + if (hs_phy_type == HS_PHY_TYPE_NONE) { // Enable on-chip FS PHY dwc2->stm32_gccfg |= STM32_GCCFG_PWRDWN; - }else - { - // Disable FS PHY + + // https://community.st.com/t5/stm32cubemx-mcus/why-stm32h743-usb-fs-doesn-t-work-if-freertos-tickless-idle/m-p/349480#M18867 + // H7 running on full-speed phy need to disable ULPI clock in sleep mode. + // Otherwise, USB won't work when mcu executing WFI/WFE instruction i.e tick-less RTOS. + // Note: there may be other family that is affected by this, but only H7 and F7 is tested so far + #if defined(USB_OTG_FS_PERIPH_BASE) && defined(RCC_AHB1LPENR_USB2OTGFSULPILPEN) + if ( USB_OTG_FS_PERIPH_BASE == (uint32_t) dwc2 ) { + RCC->AHB1LPENR &= ~RCC_AHB1LPENR_USB2OTGFSULPILPEN; + } + #endif + + #if defined(USB_OTG_HS_PERIPH_BASE) && defined(RCC_AHB1LPENR_USB1OTGHSULPILPEN) + if ( USB_OTG_HS_PERIPH_BASE == (uint32_t) dwc2 ) { + RCC->AHB1LPENR &= ~RCC_AHB1LPENR_USB1OTGHSULPILPEN; + } + #endif + + #if defined(USB_OTG_HS_PERIPH_BASE) && defined(RCC_AHB1LPENR_OTGHSULPILPEN) + if ( USB_OTG_HS_PERIPH_BASE == (uint32_t) dwc2 ) { + RCC->AHB1LPENR &= ~RCC_AHB1LPENR_OTGHSULPILPEN; + } + #endif + + } else { +#if CFG_TUSB_MCU != OPT_MCU_STM32U5 + // Disable FS PHY, TODO on U5A5 (dwc2 4.11a) 16th bit is 'Host CDP behavior enable' dwc2->stm32_gccfg &= ~STM32_GCCFG_PWRDWN; +#endif // Enable on-chip HS PHY - if (hs_phy_type == HS_PHY_TYPE_UTMI || hs_phy_type == HS_PHY_TYPE_UTMI_ULPI) - { -#ifdef USB_HS_PHYC + if (hs_phy_type == HS_PHY_TYPE_UTMI || hs_phy_type == HS_PHY_TYPE_UTMI_ULPI) { + #ifdef USB_HS_PHYC // Enable UTMI HS PHY dwc2->stm32_gccfg |= STM32_GCCFG_PHYHSEN; @@ -186,40 +208,47 @@ static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) // Enable PLL internal PHY USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL_PLLEN; -#endif + #else + + #endif } } } // MCU specific PHY update, it is called AFTER init() and core reset -static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) -{ +static inline void dwc2_phy_update(dwc2_regs_t* dwc2, uint8_t hs_phy_type) { // used to set turnaround time for fullspeed, nothing to do in highspeed mode - if ( hs_phy_type == HS_PHY_TYPE_NONE ) - { + if (hs_phy_type == HS_PHY_TYPE_NONE) { // Turnaround timeout depends on the AHB clock dictated by STM32 Reference Manual uint32_t turnaround; - if ( SystemCoreClock >= 32000000u ) + if (SystemCoreClock >= 32000000u) { turnaround = 0x6u; - else if ( SystemCoreClock >= 27500000u ) + } else if (SystemCoreClock >= 27500000u) { turnaround = 0x7u; - else if ( SystemCoreClock >= 24000000u ) + } else if (SystemCoreClock >= 24000000u) { turnaround = 0x8u; - else if ( SystemCoreClock >= 21800000u ) + } else if (SystemCoreClock >= 21800000u) { turnaround = 0x9u; - else if ( SystemCoreClock >= 20000000u ) + } + else if (SystemCoreClock >= 20000000u) { turnaround = 0xAu; - else if ( SystemCoreClock >= 18500000u ) + } + else if (SystemCoreClock >= 18500000u) { turnaround = 0xBu; - else if ( SystemCoreClock >= 17200000u ) + } + else if (SystemCoreClock >= 17200000u) { turnaround = 0xCu; - else if ( SystemCoreClock >= 16000000u ) + } + else if (SystemCoreClock >= 16000000u) { turnaround = 0xDu; - else if ( SystemCoreClock >= 15000000u ) + } + else if (SystemCoreClock >= 15000000u) { turnaround = 0xEu; - else + } + else { turnaround = 0xFu; + } dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (turnaround << GUSBCFG_TRDT_Pos); } @@ -229,4 +258,4 @@ static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) } #endif -#endif /* _DWC2_STM32_H_ */ +#endif diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_type.h b/test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_type.h similarity index 71% rename from test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_type.h rename to test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_type.h index 3fc97933..c1577123 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_type.h +++ b/test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_type.h @@ -32,7 +32,7 @@ typedef struct uint32_t ep_fifo_size; }dwc2_controller_t; -/* DWC OTG HW Release versions */ +// DWC OTG HW Release versions #define DWC2_CORE_REV_2_71a 0x4f54271a #define DWC2_CORE_REV_2_72a 0x4f54272a #define DWC2_CORE_REV_2_80a 0x4f54280a @@ -43,12 +43,13 @@ typedef struct #define DWC2_CORE_REV_3_00a 0x4f54300a #define DWC2_CORE_REV_3_10a 0x4f54310a #define DWC2_CORE_REV_4_00a 0x4f54400a +#define DWC2_CORE_REV_4_11a 0x4f54411a #define DWC2_CORE_REV_4_20a 0x4f54420a #define DWC2_FS_IOT_REV_1_00a 0x5531100a #define DWC2_HS_IOT_REV_1_00a 0x5532100a #define DWC2_CORE_REV_MASK 0x0000ffff -/* DWC OTG HW Core ID */ +// DWC OTG HW Core ID #define DWC2_OTG_ID 0x4f540000 #define DWC2_FS_IOT_ID 0x55310000 #define DWC2_HS_IOT_ID 0x55320000 @@ -57,13 +58,13 @@ typedef struct // HS PHY typedef struct { - volatile uint32_t HS_PHYC_PLL; // This register is used to control the PLL of the HS PHY. 000h */ - volatile uint32_t Reserved04; // Reserved 004h */ - volatile uint32_t Reserved08; // Reserved 008h */ - volatile uint32_t HS_PHYC_TUNE; // This register is used to control the tuning interface of the High Speed PHY. 00Ch */ - volatile uint32_t Reserved10; // Reserved 010h */ - volatile uint32_t Reserved14; // Reserved 014h */ - volatile uint32_t HS_PHYC_LDO; // This register is used to control the regulator (LDO). 018h */ + volatile uint32_t HS_PHYC_PLL; // 000h This register is used to control the PLL of the HS PHY. + volatile uint32_t Reserved04; // 004h Reserved + volatile uint32_t Reserved08; // 008h Reserved + volatile uint32_t HS_PHYC_TUNE; // 00Ch This register is used to control the tuning interface of the High Speed PHY. + volatile uint32_t Reserved10; // 010h Reserved + volatile uint32_t Reserved14; // 014h Reserved + volatile uint32_t HS_PHYC_LDO; // 018h This register is used to control the regulator (LDO). } HS_PHYC_GlobalTypeDef; #endif @@ -298,103 +299,103 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size"); /******************** Bit definition for GOTGCTL register ********************/ #define GOTGCTL_SRQSCS_Pos (0U) -#define GOTGCTL_SRQSCS_Msk (0x1UL << GOTGCTL_SRQSCS_Pos) // 0x00000001 */ -#define GOTGCTL_SRQSCS GOTGCTL_SRQSCS_Msk // Session request success */ +#define GOTGCTL_SRQSCS_Msk (0x1UL << GOTGCTL_SRQSCS_Pos) // 0x00000001 +#define GOTGCTL_SRQSCS GOTGCTL_SRQSCS_Msk // Session request success #define GOTGCTL_SRQ_Pos (1U) -#define GOTGCTL_SRQ_Msk (0x1UL << GOTGCTL_SRQ_Pos) // 0x00000002 */ -#define GOTGCTL_SRQ GOTGCTL_SRQ_Msk // Session request */ +#define GOTGCTL_SRQ_Msk (0x1UL << GOTGCTL_SRQ_Pos) // 0x00000002 +#define GOTGCTL_SRQ GOTGCTL_SRQ_Msk // Session request #define GOTGCTL_VBVALOEN_Pos (2U) -#define GOTGCTL_VBVALOEN_Msk (0x1UL << GOTGCTL_VBVALOEN_Pos) // 0x00000004 */ -#define GOTGCTL_VBVALOEN GOTGCTL_VBVALOEN_Msk // VBUS valid override enable */ +#define GOTGCTL_VBVALOEN_Msk (0x1UL << GOTGCTL_VBVALOEN_Pos) // 0x00000004 +#define GOTGCTL_VBVALOEN GOTGCTL_VBVALOEN_Msk // VBUS valid override enable #define GOTGCTL_VBVALOVAL_Pos (3U) -#define GOTGCTL_VBVALOVAL_Msk (0x1UL << GOTGCTL_VBVALOVAL_Pos) // 0x00000008 */ -#define GOTGCTL_VBVALOVAL GOTGCTL_VBVALOVAL_Msk // VBUS valid override value */ +#define GOTGCTL_VBVALOVAL_Msk (0x1UL << GOTGCTL_VBVALOVAL_Pos) // 0x00000008 +#define GOTGCTL_VBVALOVAL GOTGCTL_VBVALOVAL_Msk // VBUS valid override value #define GOTGCTL_AVALOEN_Pos (4U) -#define GOTGCTL_AVALOEN_Msk (0x1UL << GOTGCTL_AVALOEN_Pos) // 0x00000010 */ -#define GOTGCTL_AVALOEN GOTGCTL_AVALOEN_Msk // A-peripheral session valid override enable */ +#define GOTGCTL_AVALOEN_Msk (0x1UL << GOTGCTL_AVALOEN_Pos) // 0x00000010 +#define GOTGCTL_AVALOEN GOTGCTL_AVALOEN_Msk // A-peripheral session valid override enable #define GOTGCTL_AVALOVAL_Pos (5U) -#define GOTGCTL_AVALOVAL_Msk (0x1UL << GOTGCTL_AVALOVAL_Pos) // 0x00000020 */ -#define GOTGCTL_AVALOVAL GOTGCTL_AVALOVAL_Msk // A-peripheral session valid override value */ +#define GOTGCTL_AVALOVAL_Msk (0x1UL << GOTGCTL_AVALOVAL_Pos) // 0x00000020 +#define GOTGCTL_AVALOVAL GOTGCTL_AVALOVAL_Msk // A-peripheral session valid override value #define GOTGCTL_BVALOEN_Pos (6U) -#define GOTGCTL_BVALOEN_Msk (0x1UL << GOTGCTL_BVALOEN_Pos) // 0x00000040 */ -#define GOTGCTL_BVALOEN GOTGCTL_BVALOEN_Msk // B-peripheral session valid override enable */ +#define GOTGCTL_BVALOEN_Msk (0x1UL << GOTGCTL_BVALOEN_Pos) // 0x00000040 +#define GOTGCTL_BVALOEN GOTGCTL_BVALOEN_Msk // B-peripheral session valid override enable #define GOTGCTL_BVALOVAL_Pos (7U) -#define GOTGCTL_BVALOVAL_Msk (0x1UL << GOTGCTL_BVALOVAL_Pos) // 0x00000080 */ -#define GOTGCTL_BVALOVAL GOTGCTL_BVALOVAL_Msk // B-peripheral session valid override value */ +#define GOTGCTL_BVALOVAL_Msk (0x1UL << GOTGCTL_BVALOVAL_Pos) // 0x00000080 +#define GOTGCTL_BVALOVAL GOTGCTL_BVALOVAL_Msk // B-peripheral session valid override value #define GOTGCTL_HNGSCS_Pos (8U) -#define GOTGCTL_HNGSCS_Msk (0x1UL << GOTGCTL_HNGSCS_Pos) // 0x00000100 */ -#define GOTGCTL_HNGSCS GOTGCTL_HNGSCS_Msk // Host set HNP enable */ +#define GOTGCTL_HNGSCS_Msk (0x1UL << GOTGCTL_HNGSCS_Pos) // 0x00000100 +#define GOTGCTL_HNGSCS GOTGCTL_HNGSCS_Msk // Host set HNP enable #define GOTGCTL_HNPRQ_Pos (9U) -#define GOTGCTL_HNPRQ_Msk (0x1UL << GOTGCTL_HNPRQ_Pos) // 0x00000200 */ -#define GOTGCTL_HNPRQ GOTGCTL_HNPRQ_Msk // HNP request */ +#define GOTGCTL_HNPRQ_Msk (0x1UL << GOTGCTL_HNPRQ_Pos) // 0x00000200 +#define GOTGCTL_HNPRQ GOTGCTL_HNPRQ_Msk // HNP request #define GOTGCTL_HSHNPEN_Pos (10U) -#define GOTGCTL_HSHNPEN_Msk (0x1UL << GOTGCTL_HSHNPEN_Pos) // 0x00000400 */ -#define GOTGCTL_HSHNPEN GOTGCTL_HSHNPEN_Msk // Host set HNP enable */ +#define GOTGCTL_HSHNPEN_Msk (0x1UL << GOTGCTL_HSHNPEN_Pos) // 0x00000400 +#define GOTGCTL_HSHNPEN GOTGCTL_HSHNPEN_Msk // Host set HNP enable #define GOTGCTL_DHNPEN_Pos (11U) -#define GOTGCTL_DHNPEN_Msk (0x1UL << GOTGCTL_DHNPEN_Pos) // 0x00000800 */ -#define GOTGCTL_DHNPEN GOTGCTL_DHNPEN_Msk // Device HNP enabled */ +#define GOTGCTL_DHNPEN_Msk (0x1UL << GOTGCTL_DHNPEN_Pos) // 0x00000800 +#define GOTGCTL_DHNPEN GOTGCTL_DHNPEN_Msk // Device HNP enabled #define GOTGCTL_EHEN_Pos (12U) -#define GOTGCTL_EHEN_Msk (0x1UL << GOTGCTL_EHEN_Pos) // 0x00001000 */ -#define GOTGCTL_EHEN GOTGCTL_EHEN_Msk // Embedded host enable */ +#define GOTGCTL_EHEN_Msk (0x1UL << GOTGCTL_EHEN_Pos) // 0x00001000 +#define GOTGCTL_EHEN GOTGCTL_EHEN_Msk // Embedded host enable #define GOTGCTL_CIDSTS_Pos (16U) -#define GOTGCTL_CIDSTS_Msk (0x1UL << GOTGCTL_CIDSTS_Pos) // 0x00010000 */ -#define GOTGCTL_CIDSTS GOTGCTL_CIDSTS_Msk // Connector ID status */ +#define GOTGCTL_CIDSTS_Msk (0x1UL << GOTGCTL_CIDSTS_Pos) // 0x00010000 +#define GOTGCTL_CIDSTS GOTGCTL_CIDSTS_Msk // Connector ID status #define GOTGCTL_DBCT_Pos (17U) -#define GOTGCTL_DBCT_Msk (0x1UL << GOTGCTL_DBCT_Pos) // 0x00020000 */ -#define GOTGCTL_DBCT GOTGCTL_DBCT_Msk // Long/short debounce time */ +#define GOTGCTL_DBCT_Msk (0x1UL << GOTGCTL_DBCT_Pos) // 0x00020000 +#define GOTGCTL_DBCT GOTGCTL_DBCT_Msk // Long/short debounce time #define GOTGCTL_ASVLD_Pos (18U) -#define GOTGCTL_ASVLD_Msk (0x1UL << GOTGCTL_ASVLD_Pos) // 0x00040000 */ -#define GOTGCTL_ASVLD GOTGCTL_ASVLD_Msk // A-session valid */ +#define GOTGCTL_ASVLD_Msk (0x1UL << GOTGCTL_ASVLD_Pos) // 0x00040000 +#define GOTGCTL_ASVLD GOTGCTL_ASVLD_Msk // A-session valid #define GOTGCTL_BSESVLD_Pos (19U) -#define GOTGCTL_BSESVLD_Msk (0x1UL << GOTGCTL_BSESVLD_Pos) // 0x00080000 */ -#define GOTGCTL_BSESVLD GOTGCTL_BSESVLD_Msk // B-session valid */ +#define GOTGCTL_BSESVLD_Msk (0x1UL << GOTGCTL_BSESVLD_Pos) // 0x00080000 +#define GOTGCTL_BSESVLD GOTGCTL_BSESVLD_Msk // B-session valid #define GOTGCTL_OTGVER_Pos (20U) -#define GOTGCTL_OTGVER_Msk (0x1UL << GOTGCTL_OTGVER_Pos) // 0x00100000 */ -#define GOTGCTL_OTGVER GOTGCTL_OTGVER_Msk // OTG version */ +#define GOTGCTL_OTGVER_Msk (0x1UL << GOTGCTL_OTGVER_Pos) // 0x00100000 +#define GOTGCTL_OTGVER GOTGCTL_OTGVER_Msk // OTG version /******************** Bit definition for HCFG register ********************/ #define HCFG_FSLSPCS_Pos (0U) -#define HCFG_FSLSPCS_Msk (0x3UL << HCFG_FSLSPCS_Pos) // 0x00000003 */ -#define HCFG_FSLSPCS HCFG_FSLSPCS_Msk // FS/LS PHY clock select */ -#define HCFG_FSLSPCS_0 (0x1UL << HCFG_FSLSPCS_Pos) // 0x00000001 */ -#define HCFG_FSLSPCS_1 (0x2UL << HCFG_FSLSPCS_Pos) // 0x00000002 */ +#define HCFG_FSLSPCS_Msk (0x3UL << HCFG_FSLSPCS_Pos) // 0x00000003 +#define HCFG_FSLSPCS HCFG_FSLSPCS_Msk // FS/LS PHY clock select +#define HCFG_FSLSPCS_0 (0x1UL << HCFG_FSLSPCS_Pos) // 0x00000001 +#define HCFG_FSLSPCS_1 (0x2UL << HCFG_FSLSPCS_Pos) // 0x00000002 #define HCFG_FSLSS_Pos (2U) -#define HCFG_FSLSS_Msk (0x1UL << HCFG_FSLSS_Pos) // 0x00000004 */ -#define HCFG_FSLSS HCFG_FSLSS_Msk // FS- and LS-only support */ +#define HCFG_FSLSS_Msk (0x1UL << HCFG_FSLSS_Pos) // 0x00000004 +#define HCFG_FSLSS HCFG_FSLSS_Msk // FS- and LS-only support /******************** Bit definition for PCGCR register ********************/ #define PCGCR_STPPCLK_Pos (0U) -#define PCGCR_STPPCLK_Msk (0x1UL << PCGCR_STPPCLK_Pos) // 0x00000001 */ -#define PCGCR_STPPCLK PCGCR_STPPCLK_Msk // Stop PHY clock */ +#define PCGCR_STPPCLK_Msk (0x1UL << PCGCR_STPPCLK_Pos) // 0x00000001 +#define PCGCR_STPPCLK PCGCR_STPPCLK_Msk // Stop PHY clock #define PCGCR_GATEHCLK_Pos (1U) -#define PCGCR_GATEHCLK_Msk (0x1UL << PCGCR_GATEHCLK_Pos) // 0x00000002 */ -#define PCGCR_GATEHCLK PCGCR_GATEHCLK_Msk // Gate HCLK */ +#define PCGCR_GATEHCLK_Msk (0x1UL << PCGCR_GATEHCLK_Pos) // 0x00000002 +#define PCGCR_GATEHCLK PCGCR_GATEHCLK_Msk // Gate HCLK #define PCGCR_PHYSUSP_Pos (4U) -#define PCGCR_PHYSUSP_Msk (0x1UL << PCGCR_PHYSUSP_Pos) // 0x00000010 */ -#define PCGCR_PHYSUSP PCGCR_PHYSUSP_Msk // PHY suspended */ +#define PCGCR_PHYSUSP_Msk (0x1UL << PCGCR_PHYSUSP_Pos) // 0x00000010 +#define PCGCR_PHYSUSP PCGCR_PHYSUSP_Msk // PHY suspended /******************** Bit definition for GOTGINT register ********************/ #define GOTGINT_SEDET_Pos (2U) -#define GOTGINT_SEDET_Msk (0x1UL << GOTGINT_SEDET_Pos) // 0x00000004 */ -#define GOTGINT_SEDET GOTGINT_SEDET_Msk // Session end detected */ +#define GOTGINT_SEDET_Msk (0x1UL << GOTGINT_SEDET_Pos) // 0x00000004 +#define GOTGINT_SEDET GOTGINT_SEDET_Msk // Session end detected #define GOTGINT_SRSSCHG_Pos (8U) -#define GOTGINT_SRSSCHG_Msk (0x1UL << GOTGINT_SRSSCHG_Pos) // 0x00000100 */ -#define GOTGINT_SRSSCHG GOTGINT_SRSSCHG_Msk // Session request success status change */ +#define GOTGINT_SRSSCHG_Msk (0x1UL << GOTGINT_SRSSCHG_Pos) // 0x00000100 +#define GOTGINT_SRSSCHG GOTGINT_SRSSCHG_Msk // Session request success status change #define GOTGINT_HNSSCHG_Pos (9U) -#define GOTGINT_HNSSCHG_Msk (0x1UL << GOTGINT_HNSSCHG_Pos) // 0x00000200 */ -#define GOTGINT_HNSSCHG GOTGINT_HNSSCHG_Msk // Host negotiation success status change */ +#define GOTGINT_HNSSCHG_Msk (0x1UL << GOTGINT_HNSSCHG_Pos) // 0x00000200 +#define GOTGINT_HNSSCHG GOTGINT_HNSSCHG_Msk // Host negotiation success status change #define GOTGINT_HNGDET_Pos (17U) -#define GOTGINT_HNGDET_Msk (0x1UL << GOTGINT_HNGDET_Pos) // 0x00020000 */ -#define GOTGINT_HNGDET GOTGINT_HNGDET_Msk // Host negotiation detected */ +#define GOTGINT_HNGDET_Msk (0x1UL << GOTGINT_HNGDET_Pos) // 0x00020000 +#define GOTGINT_HNGDET GOTGINT_HNGDET_Msk // Host negotiation detected #define GOTGINT_ADTOCHG_Pos (18U) -#define GOTGINT_ADTOCHG_Msk (0x1UL << GOTGINT_ADTOCHG_Pos) // 0x00040000 */ -#define GOTGINT_ADTOCHG GOTGINT_ADTOCHG_Msk // A-device timeout change */ +#define GOTGINT_ADTOCHG_Msk (0x1UL << GOTGINT_ADTOCHG_Pos) // 0x00040000 +#define GOTGINT_ADTOCHG GOTGINT_ADTOCHG_Msk // A-device timeout change #define GOTGINT_DBCDNE_Pos (19U) -#define GOTGINT_DBCDNE_Msk (0x1UL << GOTGINT_DBCDNE_Pos) // 0x00080000 */ -#define GOTGINT_DBCDNE GOTGINT_DBCDNE_Msk // Debounce done */ +#define GOTGINT_DBCDNE_Msk (0x1UL << GOTGINT_DBCDNE_Pos) // 0x00080000 +#define GOTGINT_DBCDNE GOTGINT_DBCDNE_Msk // Debounce done #define GOTGINT_IDCHNG_Pos (20U) -#define GOTGINT_IDCHNG_Msk (0x1UL << GOTGINT_IDCHNG_Pos) // 0x00100000 */ -#define GOTGINT_IDCHNG GOTGINT_IDCHNG_Msk // Change in ID pin input value */ +#define GOTGINT_IDCHNG_Msk (0x1UL << GOTGINT_IDCHNG_Pos) // 0x00100000 +#define GOTGINT_IDCHNG GOTGINT_IDCHNG_Msk // Change in ID pin input value /******************** Bit definition for DCFG register ********************/ #define DCFG_DSPD_Pos (0U) @@ -405,92 +406,92 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size"); #define DCFG_DSPD_FS 3 // Fullspeed on FS PHY #define DCFG_NZLSOHSK_Pos (2U) -#define DCFG_NZLSOHSK_Msk (0x1UL << DCFG_NZLSOHSK_Pos) // 0x00000004 */ -#define DCFG_NZLSOHSK DCFG_NZLSOHSK_Msk // Nonzero-length status OUT handshake */ +#define DCFG_NZLSOHSK_Msk (0x1UL << DCFG_NZLSOHSK_Pos) // 0x00000004 +#define DCFG_NZLSOHSK DCFG_NZLSOHSK_Msk // Nonzero-length status OUT handshake #define DCFG_DAD_Pos (4U) -#define DCFG_DAD_Msk (0x7FUL << DCFG_DAD_Pos) // 0x000007F0 */ -#define DCFG_DAD DCFG_DAD_Msk // Device address */ -#define DCFG_DAD_0 (0x01UL << DCFG_DAD_Pos) // 0x00000010 */ -#define DCFG_DAD_1 (0x02UL << DCFG_DAD_Pos) // 0x00000020 */ -#define DCFG_DAD_2 (0x04UL << DCFG_DAD_Pos) // 0x00000040 */ -#define DCFG_DAD_3 (0x08UL << DCFG_DAD_Pos) // 0x00000080 */ -#define DCFG_DAD_4 (0x10UL << DCFG_DAD_Pos) // 0x00000100 */ -#define DCFG_DAD_5 (0x20UL << DCFG_DAD_Pos) // 0x00000200 */ -#define DCFG_DAD_6 (0x40UL << DCFG_DAD_Pos) // 0x00000400 */ +#define DCFG_DAD_Msk (0x7FUL << DCFG_DAD_Pos) // 0x000007F0 +#define DCFG_DAD DCFG_DAD_Msk // Device address +#define DCFG_DAD_0 (0x01UL << DCFG_DAD_Pos) // 0x00000010 +#define DCFG_DAD_1 (0x02UL << DCFG_DAD_Pos) // 0x00000020 +#define DCFG_DAD_2 (0x04UL << DCFG_DAD_Pos) // 0x00000040 +#define DCFG_DAD_3 (0x08UL << DCFG_DAD_Pos) // 0x00000080 +#define DCFG_DAD_4 (0x10UL << DCFG_DAD_Pos) // 0x00000100 +#define DCFG_DAD_5 (0x20UL << DCFG_DAD_Pos) // 0x00000200 +#define DCFG_DAD_6 (0x40UL << DCFG_DAD_Pos) // 0x00000400 #define DCFG_PFIVL_Pos (11U) -#define DCFG_PFIVL_Msk (0x3UL << DCFG_PFIVL_Pos) // 0x00001800 */ -#define DCFG_PFIVL DCFG_PFIVL_Msk // Periodic (micro)frame interval */ -#define DCFG_PFIVL_0 (0x1UL << DCFG_PFIVL_Pos) // 0x00000800 */ -#define DCFG_PFIVL_1 (0x2UL << DCFG_PFIVL_Pos) // 0x00001000 */ +#define DCFG_PFIVL_Msk (0x3UL << DCFG_PFIVL_Pos) // 0x00001800 +#define DCFG_PFIVL DCFG_PFIVL_Msk // Periodic (micro)frame interval +#define DCFG_PFIVL_0 (0x1UL << DCFG_PFIVL_Pos) // 0x00000800 +#define DCFG_PFIVL_1 (0x2UL << DCFG_PFIVL_Pos) // 0x00001000 #define DCFG_XCVRDLY_Pos (14U) -#define DCFG_XCVRDLY_Msk (0x1UL << DCFG_XCVRDLY_Pos) /*!< 0x00004000 */ +#define DCFG_XCVRDLY_Msk (0x1UL << DCFG_XCVRDLY_Pos) // 0x00004000 #define DCFG_XCVRDLY DCFG_XCVRDLY_Msk // Enables delay between xcvr_sel and txvalid during device chirp #define DCFG_PERSCHIVL_Pos (24U) -#define DCFG_PERSCHIVL_Msk (0x3UL << DCFG_PERSCHIVL_Pos) // 0x03000000 */ -#define DCFG_PERSCHIVL DCFG_PERSCHIVL_Msk // Periodic scheduling interval */ -#define DCFG_PERSCHIVL_0 (0x1UL << DCFG_PERSCHIVL_Pos) // 0x01000000 */ -#define DCFG_PERSCHIVL_1 (0x2UL << DCFG_PERSCHIVL_Pos) // 0x02000000 */ +#define DCFG_PERSCHIVL_Msk (0x3UL << DCFG_PERSCHIVL_Pos) // 0x03000000 +#define DCFG_PERSCHIVL DCFG_PERSCHIVL_Msk // Periodic scheduling interval +#define DCFG_PERSCHIVL_0 (0x1UL << DCFG_PERSCHIVL_Pos) // 0x01000000 +#define DCFG_PERSCHIVL_1 (0x2UL << DCFG_PERSCHIVL_Pos) // 0x02000000 /******************** Bit definition for DCTL register ********************/ #define DCTL_RWUSIG_Pos (0U) -#define DCTL_RWUSIG_Msk (0x1UL << DCTL_RWUSIG_Pos) // 0x00000001 */ -#define DCTL_RWUSIG DCTL_RWUSIG_Msk // Remote wakeup signaling */ +#define DCTL_RWUSIG_Msk (0x1UL << DCTL_RWUSIG_Pos) // 0x00000001 +#define DCTL_RWUSIG DCTL_RWUSIG_Msk // Remote wakeup signaling #define DCTL_SDIS_Pos (1U) -#define DCTL_SDIS_Msk (0x1UL << DCTL_SDIS_Pos) // 0x00000002 */ -#define DCTL_SDIS DCTL_SDIS_Msk // Soft disconnect */ +#define DCTL_SDIS_Msk (0x1UL << DCTL_SDIS_Pos) // 0x00000002 +#define DCTL_SDIS DCTL_SDIS_Msk // Soft disconnect #define DCTL_GINSTS_Pos (2U) -#define DCTL_GINSTS_Msk (0x1UL << DCTL_GINSTS_Pos) // 0x00000004 */ -#define DCTL_GINSTS DCTL_GINSTS_Msk // Global IN NAK status */ +#define DCTL_GINSTS_Msk (0x1UL << DCTL_GINSTS_Pos) // 0x00000004 +#define DCTL_GINSTS DCTL_GINSTS_Msk // Global IN NAK status #define DCTL_GONSTS_Pos (3U) -#define DCTL_GONSTS_Msk (0x1UL << DCTL_GONSTS_Pos) // 0x00000008 */ -#define DCTL_GONSTS DCTL_GONSTS_Msk // Global OUT NAK status */ +#define DCTL_GONSTS_Msk (0x1UL << DCTL_GONSTS_Pos) // 0x00000008 +#define DCTL_GONSTS DCTL_GONSTS_Msk // Global OUT NAK status #define DCTL_TCTL_Pos (4U) -#define DCTL_TCTL_Msk (0x7UL << DCTL_TCTL_Pos) // 0x00000070 */ -#define DCTL_TCTL DCTL_TCTL_Msk // Test control */ -#define DCTL_TCTL_0 (0x1UL << DCTL_TCTL_Pos) // 0x00000010 */ -#define DCTL_TCTL_1 (0x2UL << DCTL_TCTL_Pos) // 0x00000020 */ -#define DCTL_TCTL_2 (0x4UL << DCTL_TCTL_Pos) // 0x00000040 */ +#define DCTL_TCTL_Msk (0x7UL << DCTL_TCTL_Pos) // 0x00000070 +#define DCTL_TCTL DCTL_TCTL_Msk // Test control +#define DCTL_TCTL_0 (0x1UL << DCTL_TCTL_Pos) // 0x00000010 +#define DCTL_TCTL_1 (0x2UL << DCTL_TCTL_Pos) // 0x00000020 +#define DCTL_TCTL_2 (0x4UL << DCTL_TCTL_Pos) // 0x00000040 #define DCTL_SGINAK_Pos (7U) -#define DCTL_SGINAK_Msk (0x1UL << DCTL_SGINAK_Pos) // 0x00000080 */ -#define DCTL_SGINAK DCTL_SGINAK_Msk // Set global IN NAK */ +#define DCTL_SGINAK_Msk (0x1UL << DCTL_SGINAK_Pos) // 0x00000080 +#define DCTL_SGINAK DCTL_SGINAK_Msk // Set global IN NAK #define DCTL_CGINAK_Pos (8U) -#define DCTL_CGINAK_Msk (0x1UL << DCTL_CGINAK_Pos) // 0x00000100 */ -#define DCTL_CGINAK DCTL_CGINAK_Msk // Clear global IN NAK */ +#define DCTL_CGINAK_Msk (0x1UL << DCTL_CGINAK_Pos) // 0x00000100 +#define DCTL_CGINAK DCTL_CGINAK_Msk // Clear global IN NAK #define DCTL_SGONAK_Pos (9U) -#define DCTL_SGONAK_Msk (0x1UL << DCTL_SGONAK_Pos) // 0x00000200 */ -#define DCTL_SGONAK DCTL_SGONAK_Msk // Set global OUT NAK */ +#define DCTL_SGONAK_Msk (0x1UL << DCTL_SGONAK_Pos) // 0x00000200 +#define DCTL_SGONAK DCTL_SGONAK_Msk // Set global OUT NAK #define DCTL_CGONAK_Pos (10U) -#define DCTL_CGONAK_Msk (0x1UL << DCTL_CGONAK_Pos) // 0x00000400 */ -#define DCTL_CGONAK DCTL_CGONAK_Msk // Clear global OUT NAK */ +#define DCTL_CGONAK_Msk (0x1UL << DCTL_CGONAK_Pos) // 0x00000400 +#define DCTL_CGONAK DCTL_CGONAK_Msk // Clear global OUT NAK #define DCTL_POPRGDNE_Pos (11U) -#define DCTL_POPRGDNE_Msk (0x1UL << DCTL_POPRGDNE_Pos) // 0x00000800 */ -#define DCTL_POPRGDNE DCTL_POPRGDNE_Msk // Power-on programming done */ +#define DCTL_POPRGDNE_Msk (0x1UL << DCTL_POPRGDNE_Pos) // 0x00000800 +#define DCTL_POPRGDNE DCTL_POPRGDNE_Msk // Power-on programming done /******************** Bit definition for HFIR register ********************/ #define HFIR_FRIVL_Pos (0U) -#define HFIR_FRIVL_Msk (0xFFFFUL << HFIR_FRIVL_Pos) // 0x0000FFFF */ -#define HFIR_FRIVL HFIR_FRIVL_Msk // Frame interval */ +#define HFIR_FRIVL_Msk (0xFFFFUL << HFIR_FRIVL_Pos) // 0x0000FFFF +#define HFIR_FRIVL HFIR_FRIVL_Msk // Frame interval /******************** Bit definition for HFNUM register ********************/ #define HFNUM_FRNUM_Pos (0U) -#define HFNUM_FRNUM_Msk (0xFFFFUL << HFNUM_FRNUM_Pos) // 0x0000FFFF */ -#define HFNUM_FRNUM HFNUM_FRNUM_Msk // Frame number */ +#define HFNUM_FRNUM_Msk (0xFFFFUL << HFNUM_FRNUM_Pos) // 0x0000FFFF +#define HFNUM_FRNUM HFNUM_FRNUM_Msk // Frame number #define HFNUM_FTREM_Pos (16U) -#define HFNUM_FTREM_Msk (0xFFFFUL << HFNUM_FTREM_Pos) // 0xFFFF0000 */ -#define HFNUM_FTREM HFNUM_FTREM_Msk // Frame time remaining */ +#define HFNUM_FTREM_Msk (0xFFFFUL << HFNUM_FTREM_Pos) // 0xFFFF0000 +#define HFNUM_FTREM HFNUM_FTREM_Msk // Frame time remaining /******************** Bit definition for DSTS register ********************/ #define DSTS_SUSPSTS_Pos (0U) -#define DSTS_SUSPSTS_Msk (0x1UL << DSTS_SUSPSTS_Pos) // 0x00000001 */ -#define DSTS_SUSPSTS DSTS_SUSPSTS_Msk // Suspend status */ +#define DSTS_SUSPSTS_Msk (0x1UL << DSTS_SUSPSTS_Pos) // 0x00000001 +#define DSTS_SUSPSTS DSTS_SUSPSTS_Msk // Suspend status #define DSTS_ENUMSPD_Pos (1U) -#define DSTS_ENUMSPD_Msk (0x3UL << DSTS_ENUMSPD_Pos) // 0x00000006 */ -#define DSTS_ENUMSPD DSTS_ENUMSPD_Msk // Enumerated speed */ +#define DSTS_ENUMSPD_Msk (0x3UL << DSTS_ENUMSPD_Pos) // 0x00000006 +#define DSTS_ENUMSPD DSTS_ENUMSPD_Msk // Enumerated speed #define DSTS_ENUMSPD_HS 0 // Highspeed #define DSTS_ENUMSPD_FS_HSPHY 1 // Fullspeed on HS PHY #define DSTS_ENUMSPD_LS 2 // Lowspeed @@ -498,427 +499,427 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size"); #define DSTS_EERR_Pos (3U) -#define DSTS_EERR_Msk (0x1UL << DSTS_EERR_Pos) // 0x00000008 */ -#define DSTS_EERR DSTS_EERR_Msk // Erratic error */ +#define DSTS_EERR_Msk (0x1UL << DSTS_EERR_Pos) // 0x00000008 +#define DSTS_EERR DSTS_EERR_Msk // Erratic error #define DSTS_FNSOF_Pos (8U) -#define DSTS_FNSOF_Msk (0x3FFFUL << DSTS_FNSOF_Pos) // 0x003FFF00 */ -#define DSTS_FNSOF DSTS_FNSOF_Msk // Frame number of the received SOF */ +#define DSTS_FNSOF_Msk (0x3FFFUL << DSTS_FNSOF_Pos) // 0x003FFF00 +#define DSTS_FNSOF DSTS_FNSOF_Msk // Frame number of the received SOF /******************** Bit definition for GAHBCFG register ********************/ #define GAHBCFG_GINT_Pos (0U) -#define GAHBCFG_GINT_Msk (0x1UL << GAHBCFG_GINT_Pos) // 0x00000001 */ -#define GAHBCFG_GINT GAHBCFG_GINT_Msk // Global interrupt mask */ +#define GAHBCFG_GINT_Msk (0x1UL << GAHBCFG_GINT_Pos) // 0x00000001 +#define GAHBCFG_GINT GAHBCFG_GINT_Msk // Global interrupt mask #define GAHBCFG_HBSTLEN_Pos (1U) -#define GAHBCFG_HBSTLEN_Msk (0xFUL << GAHBCFG_HBSTLEN_Pos) // 0x0000001E */ -#define GAHBCFG_HBSTLEN GAHBCFG_HBSTLEN_Msk // Burst length/type */ -#define GAHBCFG_HBSTLEN_0 (0x0UL << GAHBCFG_HBSTLEN_Pos) // Single */ -#define GAHBCFG_HBSTLEN_1 (0x1UL << GAHBCFG_HBSTLEN_Pos) // INCR */ -#define GAHBCFG_HBSTLEN_2 (0x3UL << GAHBCFG_HBSTLEN_Pos) // INCR4 */ -#define GAHBCFG_HBSTLEN_3 (0x5UL << GAHBCFG_HBSTLEN_Pos) // INCR8 */ -#define GAHBCFG_HBSTLEN_4 (0x7UL << GAHBCFG_HBSTLEN_Pos) // INCR16 */ +#define GAHBCFG_HBSTLEN_Msk (0xFUL << GAHBCFG_HBSTLEN_Pos) // 0x0000001E +#define GAHBCFG_HBSTLEN GAHBCFG_HBSTLEN_Msk // Burst length/type +#define GAHBCFG_HBSTLEN_0 (0x0UL << GAHBCFG_HBSTLEN_Pos) // Single +#define GAHBCFG_HBSTLEN_1 (0x1UL << GAHBCFG_HBSTLEN_Pos) // INCR +#define GAHBCFG_HBSTLEN_2 (0x3UL << GAHBCFG_HBSTLEN_Pos) // INCR4 +#define GAHBCFG_HBSTLEN_3 (0x5UL << GAHBCFG_HBSTLEN_Pos) // INCR8 +#define GAHBCFG_HBSTLEN_4 (0x7UL << GAHBCFG_HBSTLEN_Pos) // INCR16 #define GAHBCFG_DMAEN_Pos (5U) -#define GAHBCFG_DMAEN_Msk (0x1UL << GAHBCFG_DMAEN_Pos) // 0x00000020 */ -#define GAHBCFG_DMAEN GAHBCFG_DMAEN_Msk // DMA enable */ +#define GAHBCFG_DMAEN_Msk (0x1UL << GAHBCFG_DMAEN_Pos) // 0x00000020 +#define GAHBCFG_DMAEN GAHBCFG_DMAEN_Msk // DMA enable #define GAHBCFG_TXFELVL_Pos (7U) -#define GAHBCFG_TXFELVL_Msk (0x1UL << GAHBCFG_TXFELVL_Pos) // 0x00000080 */ -#define GAHBCFG_TXFELVL GAHBCFG_TXFELVL_Msk // TxFIFO empty level */ +#define GAHBCFG_TXFELVL_Msk (0x1UL << GAHBCFG_TXFELVL_Pos) // 0x00000080 +#define GAHBCFG_TXFELVL GAHBCFG_TXFELVL_Msk // TxFIFO empty level #define GAHBCFG_PTXFELVL_Pos (8U) -#define GAHBCFG_PTXFELVL_Msk (0x1UL << GAHBCFG_PTXFELVL_Pos) // 0x00000100 */ -#define GAHBCFG_PTXFELVL GAHBCFG_PTXFELVL_Msk // Periodic TxFIFO empty level */ +#define GAHBCFG_PTXFELVL_Msk (0x1UL << GAHBCFG_PTXFELVL_Pos) // 0x00000100 +#define GAHBCFG_PTXFELVL GAHBCFG_PTXFELVL_Msk // Periodic TxFIFO empty level #define GSNPSID_ID_MASK TU_GENMASK(31, 16) /******************** Bit definition for GUSBCFG register ********************/ #define GUSBCFG_TOCAL_Pos (0U) -#define GUSBCFG_TOCAL_Msk (0x7UL << GUSBCFG_TOCAL_Pos) // 0x00000007 */ -#define GUSBCFG_TOCAL GUSBCFG_TOCAL_Msk // FS timeout calibration */ +#define GUSBCFG_TOCAL_Msk (0x7UL << GUSBCFG_TOCAL_Pos) // 0x00000007 +#define GUSBCFG_TOCAL GUSBCFG_TOCAL_Msk // FS timeout calibration #define GUSBCFG_PHYIF16_Pos (3U) -#define GUSBCFG_PHYIF16_Msk (0x1UL << GUSBCFG_PHYIF16_Pos) // 0x00000008 */ -#define GUSBCFG_PHYIF16 GUSBCFG_PHYIF16_Msk // PHY Interface (PHYIf) */ +#define GUSBCFG_PHYIF16_Msk (0x1UL << GUSBCFG_PHYIF16_Pos) // 0x00000008 +#define GUSBCFG_PHYIF16 GUSBCFG_PHYIF16_Msk // PHY Interface (PHYIf) #define GUSBCFG_ULPI_UTMI_SEL_Pos (4U) -#define GUSBCFG_ULPI_UTMI_SEL_Msk (0x1UL << GUSBCFG_ULPI_UTMI_SEL_Pos) // 0x00000010 */ -#define GUSBCFG_ULPI_UTMI_SEL GUSBCFG_ULPI_UTMI_SEL_Msk // ULPI or UTMI+ Select (ULPI_UTMI_Sel) */ +#define GUSBCFG_ULPI_UTMI_SEL_Msk (0x1UL << GUSBCFG_ULPI_UTMI_SEL_Pos) // 0x00000010 +#define GUSBCFG_ULPI_UTMI_SEL GUSBCFG_ULPI_UTMI_SEL_Msk // ULPI or UTMI+ Select (ULPI_UTMI_Sel) #define GUSBCFG_PHYSEL_Pos (6U) -#define GUSBCFG_PHYSEL_Msk (0x1UL << GUSBCFG_PHYSEL_Pos) // 0x00000040 */ -#define GUSBCFG_PHYSEL GUSBCFG_PHYSEL_Msk // USB 2.0 high-speed ULPI PHY or USB 1.1 full-speed serial transceiver select */ +#define GUSBCFG_PHYSEL_Msk (0x1UL << GUSBCFG_PHYSEL_Pos) // 0x00000040 +#define GUSBCFG_PHYSEL GUSBCFG_PHYSEL_Msk // USB 2.0 high-speed ULPI PHY or USB 1.1 full-speed serial transceiver select #define GUSBCFG_DDRSEL TU_BIT(7) // Single Data Rate (SDR) or Double Data Rate (DDR) or ULPI interface. #define GUSBCFG_SRPCAP_Pos (8U) -#define GUSBCFG_SRPCAP_Msk (0x1UL << GUSBCFG_SRPCAP_Pos) // 0x00000100 */ -#define GUSBCFG_SRPCAP GUSBCFG_SRPCAP_Msk // SRP-capable */ +#define GUSBCFG_SRPCAP_Msk (0x1UL << GUSBCFG_SRPCAP_Pos) // 0x00000100 +#define GUSBCFG_SRPCAP GUSBCFG_SRPCAP_Msk // SRP-capable #define GUSBCFG_HNPCAP_Pos (9U) -#define GUSBCFG_HNPCAP_Msk (0x1UL << GUSBCFG_HNPCAP_Pos) // 0x00000200 */ -#define GUSBCFG_HNPCAP GUSBCFG_HNPCAP_Msk // HNP-capable */ +#define GUSBCFG_HNPCAP_Msk (0x1UL << GUSBCFG_HNPCAP_Pos) // 0x00000200 +#define GUSBCFG_HNPCAP GUSBCFG_HNPCAP_Msk // HNP-capable #define GUSBCFG_TRDT_Pos (10U) -#define GUSBCFG_TRDT_Msk (0xFUL << GUSBCFG_TRDT_Pos) // 0x00003C00 */ -#define GUSBCFG_TRDT GUSBCFG_TRDT_Msk // USB turnaround time */ +#define GUSBCFG_TRDT_Msk (0xFUL << GUSBCFG_TRDT_Pos) // 0x00003C00 +#define GUSBCFG_TRDT GUSBCFG_TRDT_Msk // USB turnaround time #define GUSBCFG_PHYLPCS_Pos (15U) -#define GUSBCFG_PHYLPCS_Msk (0x1UL << GUSBCFG_PHYLPCS_Pos) // 0x00008000 */ -#define GUSBCFG_PHYLPCS GUSBCFG_PHYLPCS_Msk // PHY Low-power clock select */ +#define GUSBCFG_PHYLPCS_Msk (0x1UL << GUSBCFG_PHYLPCS_Pos) // 0x00008000 +#define GUSBCFG_PHYLPCS GUSBCFG_PHYLPCS_Msk // PHY Low-power clock select #define GUSBCFG_ULPIFSLS_Pos (17U) -#define GUSBCFG_ULPIFSLS_Msk (0x1UL << GUSBCFG_ULPIFSLS_Pos) // 0x00020000 */ -#define GUSBCFG_ULPIFSLS GUSBCFG_ULPIFSLS_Msk // ULPI FS/LS select */ +#define GUSBCFG_ULPIFSLS_Msk (0x1UL << GUSBCFG_ULPIFSLS_Pos) // 0x00020000 +#define GUSBCFG_ULPIFSLS GUSBCFG_ULPIFSLS_Msk // ULPI FS/LS select #define GUSBCFG_ULPIAR_Pos (18U) -#define GUSBCFG_ULPIAR_Msk (0x1UL << GUSBCFG_ULPIAR_Pos) // 0x00040000 */ -#define GUSBCFG_ULPIAR GUSBCFG_ULPIAR_Msk // ULPI Auto-resume */ +#define GUSBCFG_ULPIAR_Msk (0x1UL << GUSBCFG_ULPIAR_Pos) // 0x00040000 +#define GUSBCFG_ULPIAR GUSBCFG_ULPIAR_Msk // ULPI Auto-resume #define GUSBCFG_ULPICSM_Pos (19U) -#define GUSBCFG_ULPICSM_Msk (0x1UL << GUSBCFG_ULPICSM_Pos) // 0x00080000 */ -#define GUSBCFG_ULPICSM GUSBCFG_ULPICSM_Msk // ULPI Clock SuspendM */ +#define GUSBCFG_ULPICSM_Msk (0x1UL << GUSBCFG_ULPICSM_Pos) // 0x00080000 +#define GUSBCFG_ULPICSM GUSBCFG_ULPICSM_Msk // ULPI Clock SuspendM #define GUSBCFG_ULPIEVBUSD_Pos (20U) -#define GUSBCFG_ULPIEVBUSD_Msk (0x1UL << GUSBCFG_ULPIEVBUSD_Pos) // 0x00100000 */ -#define GUSBCFG_ULPIEVBUSD GUSBCFG_ULPIEVBUSD_Msk // ULPI External VBUS Drive */ +#define GUSBCFG_ULPIEVBUSD_Msk (0x1UL << GUSBCFG_ULPIEVBUSD_Pos) // 0x00100000 +#define GUSBCFG_ULPIEVBUSD GUSBCFG_ULPIEVBUSD_Msk // ULPI External VBUS Drive #define GUSBCFG_ULPIEVBUSI_Pos (21U) -#define GUSBCFG_ULPIEVBUSI_Msk (0x1UL << GUSBCFG_ULPIEVBUSI_Pos) // 0x00200000 */ -#define GUSBCFG_ULPIEVBUSI GUSBCFG_ULPIEVBUSI_Msk // ULPI external VBUS indicator */ +#define GUSBCFG_ULPIEVBUSI_Msk (0x1UL << GUSBCFG_ULPIEVBUSI_Pos) // 0x00200000 +#define GUSBCFG_ULPIEVBUSI GUSBCFG_ULPIEVBUSI_Msk // ULPI external VBUS indicator #define GUSBCFG_TSDPS_Pos (22U) -#define GUSBCFG_TSDPS_Msk (0x1UL << GUSBCFG_TSDPS_Pos) // 0x00400000 */ -#define GUSBCFG_TSDPS GUSBCFG_TSDPS_Msk // TermSel DLine pulsing selection */ +#define GUSBCFG_TSDPS_Msk (0x1UL << GUSBCFG_TSDPS_Pos) // 0x00400000 +#define GUSBCFG_TSDPS GUSBCFG_TSDPS_Msk // TermSel DLine pulsing selection #define GUSBCFG_PCCI_Pos (23U) -#define GUSBCFG_PCCI_Msk (0x1UL << GUSBCFG_PCCI_Pos) // 0x00800000 */ -#define GUSBCFG_PCCI GUSBCFG_PCCI_Msk // Indicator complement */ +#define GUSBCFG_PCCI_Msk (0x1UL << GUSBCFG_PCCI_Pos) // 0x00800000 +#define GUSBCFG_PCCI GUSBCFG_PCCI_Msk // Indicator complement #define GUSBCFG_PTCI_Pos (24U) -#define GUSBCFG_PTCI_Msk (0x1UL << GUSBCFG_PTCI_Pos) // 0x01000000 */ -#define GUSBCFG_PTCI GUSBCFG_PTCI_Msk // Indicator pass through */ +#define GUSBCFG_PTCI_Msk (0x1UL << GUSBCFG_PTCI_Pos) // 0x01000000 +#define GUSBCFG_PTCI GUSBCFG_PTCI_Msk // Indicator pass through #define GUSBCFG_ULPIIPD_Pos (25U) -#define GUSBCFG_ULPIIPD_Msk (0x1UL << GUSBCFG_ULPIIPD_Pos) // 0x02000000 */ -#define GUSBCFG_ULPIIPD GUSBCFG_ULPIIPD_Msk // ULPI interface protect disable */ +#define GUSBCFG_ULPIIPD_Msk (0x1UL << GUSBCFG_ULPIIPD_Pos) // 0x02000000 +#define GUSBCFG_ULPIIPD GUSBCFG_ULPIIPD_Msk // ULPI interface protect disable #define GUSBCFG_FHMOD_Pos (29U) -#define GUSBCFG_FHMOD_Msk (0x1UL << GUSBCFG_FHMOD_Pos) // 0x20000000 */ -#define GUSBCFG_FHMOD GUSBCFG_FHMOD_Msk // Forced host mode */ +#define GUSBCFG_FHMOD_Msk (0x1UL << GUSBCFG_FHMOD_Pos) // 0x20000000 +#define GUSBCFG_FHMOD GUSBCFG_FHMOD_Msk // Forced host mode #define GUSBCFG_FDMOD_Pos (30U) -#define GUSBCFG_FDMOD_Msk (0x1UL << GUSBCFG_FDMOD_Pos) // 0x40000000 */ -#define GUSBCFG_FDMOD GUSBCFG_FDMOD_Msk // Forced peripheral mode */ +#define GUSBCFG_FDMOD_Msk (0x1UL << GUSBCFG_FDMOD_Pos) // 0x40000000 +#define GUSBCFG_FDMOD GUSBCFG_FDMOD_Msk // Forced peripheral mode #define GUSBCFG_CTXPKT_Pos (31U) -#define GUSBCFG_CTXPKT_Msk (0x1UL << GUSBCFG_CTXPKT_Pos) // 0x80000000 */ -#define GUSBCFG_CTXPKT GUSBCFG_CTXPKT_Msk // Corrupt Tx packet */ +#define GUSBCFG_CTXPKT_Msk (0x1UL << GUSBCFG_CTXPKT_Pos) // 0x80000000 +#define GUSBCFG_CTXPKT GUSBCFG_CTXPKT_Msk // Corrupt Tx packet /******************** Bit definition for GRSTCTL register ********************/ #define GRSTCTL_CSRST_Pos (0U) -#define GRSTCTL_CSRST_Msk (0x1UL << GRSTCTL_CSRST_Pos) // 0x00000001 */ -#define GRSTCTL_CSRST GRSTCTL_CSRST_Msk // Core soft reset */ +#define GRSTCTL_CSRST_Msk (0x1UL << GRSTCTL_CSRST_Pos) // 0x00000001 +#define GRSTCTL_CSRST GRSTCTL_CSRST_Msk // Core soft reset #define GRSTCTL_HSRST_Pos (1U) -#define GRSTCTL_HSRST_Msk (0x1UL << GRSTCTL_HSRST_Pos) // 0x00000002 */ -#define GRSTCTL_HSRST GRSTCTL_HSRST_Msk // HCLK soft reset */ +#define GRSTCTL_HSRST_Msk (0x1UL << GRSTCTL_HSRST_Pos) // 0x00000002 +#define GRSTCTL_HSRST GRSTCTL_HSRST_Msk // HCLK soft reset #define GRSTCTL_FCRST_Pos (2U) -#define GRSTCTL_FCRST_Msk (0x1UL << GRSTCTL_FCRST_Pos) // 0x00000004 */ -#define GRSTCTL_FCRST GRSTCTL_FCRST_Msk // Host frame counter reset */ +#define GRSTCTL_FCRST_Msk (0x1UL << GRSTCTL_FCRST_Pos) // 0x00000004 +#define GRSTCTL_FCRST GRSTCTL_FCRST_Msk // Host frame counter reset #define GRSTCTL_RXFFLSH_Pos (4U) -#define GRSTCTL_RXFFLSH_Msk (0x1UL << GRSTCTL_RXFFLSH_Pos) // 0x00000010 */ -#define GRSTCTL_RXFFLSH GRSTCTL_RXFFLSH_Msk // RxFIFO flush */ +#define GRSTCTL_RXFFLSH_Msk (0x1UL << GRSTCTL_RXFFLSH_Pos) // 0x00000010 +#define GRSTCTL_RXFFLSH GRSTCTL_RXFFLSH_Msk // RxFIFO flush #define GRSTCTL_TXFFLSH_Pos (5U) -#define GRSTCTL_TXFFLSH_Msk (0x1UL << GRSTCTL_TXFFLSH_Pos) // 0x00000020 */ -#define GRSTCTL_TXFFLSH GRSTCTL_TXFFLSH_Msk // TxFIFO flush */ +#define GRSTCTL_TXFFLSH_Msk (0x1UL << GRSTCTL_TXFFLSH_Pos) // 0x00000020 +#define GRSTCTL_TXFFLSH GRSTCTL_TXFFLSH_Msk // TxFIFO flush #define GRSTCTL_TXFNUM_Pos (6U) -#define GRSTCTL_TXFNUM_Msk (0x1FUL << GRSTCTL_TXFNUM_Pos) // 0x000007C0 */ -#define GRSTCTL_TXFNUM GRSTCTL_TXFNUM_Msk // TxFIFO number */ -#define GRSTCTL_TXFNUM_0 (0x01UL << GRSTCTL_TXFNUM_Pos) // 0x00000040 */ -#define GRSTCTL_TXFNUM_1 (0x02UL << GRSTCTL_TXFNUM_Pos) // 0x00000080 */ -#define GRSTCTL_TXFNUM_2 (0x04UL << GRSTCTL_TXFNUM_Pos) // 0x00000100 */ -#define GRSTCTL_TXFNUM_3 (0x08UL << GRSTCTL_TXFNUM_Pos) // 0x00000200 */ -#define GRSTCTL_TXFNUM_4 (0x10UL << GRSTCTL_TXFNUM_Pos) // 0x00000400 */ +#define GRSTCTL_TXFNUM_Msk (0x1FUL << GRSTCTL_TXFNUM_Pos) // 0x000007C0 +#define GRSTCTL_TXFNUM GRSTCTL_TXFNUM_Msk // TxFIFO number +#define GRSTCTL_TXFNUM_0 (0x01UL << GRSTCTL_TXFNUM_Pos) // 0x00000040 +#define GRSTCTL_TXFNUM_1 (0x02UL << GRSTCTL_TXFNUM_Pos) // 0x00000080 +#define GRSTCTL_TXFNUM_2 (0x04UL << GRSTCTL_TXFNUM_Pos) // 0x00000100 +#define GRSTCTL_TXFNUM_3 (0x08UL << GRSTCTL_TXFNUM_Pos) // 0x00000200 +#define GRSTCTL_TXFNUM_4 (0x10UL << GRSTCTL_TXFNUM_Pos) // 0x00000400 #define GRSTCTL_CSFTRST_DONE_Pos (29) #define GRSTCTL_CSFTRST_DONE (1u << GRSTCTL_CSFTRST_DONE_Pos) // Reset Done, only available from v4.20a #define GRSTCTL_DMAREQ_Pos (30U) -#define GRSTCTL_DMAREQ_Msk (0x1UL << GRSTCTL_DMAREQ_Pos) // 0x40000000 */ -#define GRSTCTL_DMAREQ GRSTCTL_DMAREQ_Msk // DMA request signal */ +#define GRSTCTL_DMAREQ_Msk (0x1UL << GRSTCTL_DMAREQ_Pos) // 0x40000000 +#define GRSTCTL_DMAREQ GRSTCTL_DMAREQ_Msk // DMA request signal #define GRSTCTL_AHBIDL_Pos (31U) -#define GRSTCTL_AHBIDL_Msk (0x1UL << GRSTCTL_AHBIDL_Pos) // 0x80000000 */ -#define GRSTCTL_AHBIDL GRSTCTL_AHBIDL_Msk // AHB master idle */ +#define GRSTCTL_AHBIDL_Msk (0x1UL << GRSTCTL_AHBIDL_Pos) // 0x80000000 +#define GRSTCTL_AHBIDL GRSTCTL_AHBIDL_Msk // AHB master idle /******************** Bit definition for DIEPMSK register ********************/ #define DIEPMSK_XFRCM_Pos (0U) -#define DIEPMSK_XFRCM_Msk (0x1UL << DIEPMSK_XFRCM_Pos) // 0x00000001 */ -#define DIEPMSK_XFRCM DIEPMSK_XFRCM_Msk // Transfer completed interrupt mask */ +#define DIEPMSK_XFRCM_Msk (0x1UL << DIEPMSK_XFRCM_Pos) // 0x00000001 +#define DIEPMSK_XFRCM DIEPMSK_XFRCM_Msk // Transfer completed interrupt mask #define DIEPMSK_EPDM_Pos (1U) -#define DIEPMSK_EPDM_Msk (0x1UL << DIEPMSK_EPDM_Pos) // 0x00000002 */ -#define DIEPMSK_EPDM DIEPMSK_EPDM_Msk // Endpoint disabled interrupt mask */ +#define DIEPMSK_EPDM_Msk (0x1UL << DIEPMSK_EPDM_Pos) // 0x00000002 +#define DIEPMSK_EPDM DIEPMSK_EPDM_Msk // Endpoint disabled interrupt mask #define DIEPMSK_TOM_Pos (3U) -#define DIEPMSK_TOM_Msk (0x1UL << DIEPMSK_TOM_Pos) // 0x00000008 */ -#define DIEPMSK_TOM DIEPMSK_TOM_Msk // Timeout condition mask (nonisochronous endpoints) */ +#define DIEPMSK_TOM_Msk (0x1UL << DIEPMSK_TOM_Pos) // 0x00000008 +#define DIEPMSK_TOM DIEPMSK_TOM_Msk // Timeout condition mask (nonisochronous endpoints) #define DIEPMSK_ITTXFEMSK_Pos (4U) -#define DIEPMSK_ITTXFEMSK_Msk (0x1UL << DIEPMSK_ITTXFEMSK_Pos) // 0x00000010 */ -#define DIEPMSK_ITTXFEMSK DIEPMSK_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask */ +#define DIEPMSK_ITTXFEMSK_Msk (0x1UL << DIEPMSK_ITTXFEMSK_Pos) // 0x00000010 +#define DIEPMSK_ITTXFEMSK DIEPMSK_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask #define DIEPMSK_INEPNMM_Pos (5U) -#define DIEPMSK_INEPNMM_Msk (0x1UL << DIEPMSK_INEPNMM_Pos) // 0x00000020 */ -#define DIEPMSK_INEPNMM DIEPMSK_INEPNMM_Msk // IN token received with EP mismatch mask */ +#define DIEPMSK_INEPNMM_Msk (0x1UL << DIEPMSK_INEPNMM_Pos) // 0x00000020 +#define DIEPMSK_INEPNMM DIEPMSK_INEPNMM_Msk // IN token received with EP mismatch mask #define DIEPMSK_INEPNEM_Pos (6U) -#define DIEPMSK_INEPNEM_Msk (0x1UL << DIEPMSK_INEPNEM_Pos) // 0x00000040 */ -#define DIEPMSK_INEPNEM DIEPMSK_INEPNEM_Msk // IN endpoint NAK effective mask */ +#define DIEPMSK_INEPNEM_Msk (0x1UL << DIEPMSK_INEPNEM_Pos) // 0x00000040 +#define DIEPMSK_INEPNEM DIEPMSK_INEPNEM_Msk // IN endpoint NAK effective mask #define DIEPMSK_TXFURM_Pos (8U) -#define DIEPMSK_TXFURM_Msk (0x1UL << DIEPMSK_TXFURM_Pos) // 0x00000100 */ -#define DIEPMSK_TXFURM DIEPMSK_TXFURM_Msk // FIFO underrun mask */ +#define DIEPMSK_TXFURM_Msk (0x1UL << DIEPMSK_TXFURM_Pos) // 0x00000100 +#define DIEPMSK_TXFURM DIEPMSK_TXFURM_Msk // FIFO underrun mask #define DIEPMSK_BIM_Pos (9U) -#define DIEPMSK_BIM_Msk (0x1UL << DIEPMSK_BIM_Pos) // 0x00000200 */ -#define DIEPMSK_BIM DIEPMSK_BIM_Msk // BNA interrupt mask */ +#define DIEPMSK_BIM_Msk (0x1UL << DIEPMSK_BIM_Pos) // 0x00000200 +#define DIEPMSK_BIM DIEPMSK_BIM_Msk // BNA interrupt mask /******************** Bit definition for HPTXSTS register ********************/ #define HPTXSTS_PTXFSAVL_Pos (0U) -#define HPTXSTS_PTXFSAVL_Msk (0xFFFFUL << HPTXSTS_PTXFSAVL_Pos) // 0x0000FFFF */ -#define HPTXSTS_PTXFSAVL HPTXSTS_PTXFSAVL_Msk // Periodic transmit data FIFO space available */ +#define HPTXSTS_PTXFSAVL_Msk (0xFFFFUL << HPTXSTS_PTXFSAVL_Pos) // 0x0000FFFF +#define HPTXSTS_PTXFSAVL HPTXSTS_PTXFSAVL_Msk // Periodic transmit data FIFO space available #define HPTXSTS_PTXQSAV_Pos (16U) -#define HPTXSTS_PTXQSAV_Msk (0xFFUL << HPTXSTS_PTXQSAV_Pos) // 0x00FF0000 */ -#define HPTXSTS_PTXQSAV HPTXSTS_PTXQSAV_Msk // Periodic transmit request queue space available */ -#define HPTXSTS_PTXQSAV_0 (0x01UL << HPTXSTS_PTXQSAV_Pos) // 0x00010000 */ -#define HPTXSTS_PTXQSAV_1 (0x02UL << HPTXSTS_PTXQSAV_Pos) // 0x00020000 */ -#define HPTXSTS_PTXQSAV_2 (0x04UL << HPTXSTS_PTXQSAV_Pos) // 0x00040000 */ -#define HPTXSTS_PTXQSAV_3 (0x08UL << HPTXSTS_PTXQSAV_Pos) // 0x00080000 */ -#define HPTXSTS_PTXQSAV_4 (0x10UL << HPTXSTS_PTXQSAV_Pos) // 0x00100000 */ -#define HPTXSTS_PTXQSAV_5 (0x20UL << HPTXSTS_PTXQSAV_Pos) // 0x00200000 */ -#define HPTXSTS_PTXQSAV_6 (0x40UL << HPTXSTS_PTXQSAV_Pos) // 0x00400000 */ -#define HPTXSTS_PTXQSAV_7 (0x80UL << HPTXSTS_PTXQSAV_Pos) // 0x00800000 */ +#define HPTXSTS_PTXQSAV_Msk (0xFFUL << HPTXSTS_PTXQSAV_Pos) // 0x00FF0000 +#define HPTXSTS_PTXQSAV HPTXSTS_PTXQSAV_Msk // Periodic transmit request queue space available +#define HPTXSTS_PTXQSAV_0 (0x01UL << HPTXSTS_PTXQSAV_Pos) // 0x00010000 +#define HPTXSTS_PTXQSAV_1 (0x02UL << HPTXSTS_PTXQSAV_Pos) // 0x00020000 +#define HPTXSTS_PTXQSAV_2 (0x04UL << HPTXSTS_PTXQSAV_Pos) // 0x00040000 +#define HPTXSTS_PTXQSAV_3 (0x08UL << HPTXSTS_PTXQSAV_Pos) // 0x00080000 +#define HPTXSTS_PTXQSAV_4 (0x10UL << HPTXSTS_PTXQSAV_Pos) // 0x00100000 +#define HPTXSTS_PTXQSAV_5 (0x20UL << HPTXSTS_PTXQSAV_Pos) // 0x00200000 +#define HPTXSTS_PTXQSAV_6 (0x40UL << HPTXSTS_PTXQSAV_Pos) // 0x00400000 +#define HPTXSTS_PTXQSAV_7 (0x80UL << HPTXSTS_PTXQSAV_Pos) // 0x00800000 #define HPTXSTS_PTXQTOP_Pos (24U) -#define HPTXSTS_PTXQTOP_Msk (0xFFUL << HPTXSTS_PTXQTOP_Pos) // 0xFF000000 */ -#define HPTXSTS_PTXQTOP HPTXSTS_PTXQTOP_Msk // Top of the periodic transmit request queue */ -#define HPTXSTS_PTXQTOP_0 (0x01UL << HPTXSTS_PTXQTOP_Pos) // 0x01000000 */ -#define HPTXSTS_PTXQTOP_1 (0x02UL << HPTXSTS_PTXQTOP_Pos) // 0x02000000 */ -#define HPTXSTS_PTXQTOP_2 (0x04UL << HPTXSTS_PTXQTOP_Pos) // 0x04000000 */ -#define HPTXSTS_PTXQTOP_3 (0x08UL << HPTXSTS_PTXQTOP_Pos) // 0x08000000 */ -#define HPTXSTS_PTXQTOP_4 (0x10UL << HPTXSTS_PTXQTOP_Pos) // 0x10000000 */ -#define HPTXSTS_PTXQTOP_5 (0x20UL << HPTXSTS_PTXQTOP_Pos) // 0x20000000 */ -#define HPTXSTS_PTXQTOP_6 (0x40UL << HPTXSTS_PTXQTOP_Pos) // 0x40000000 */ -#define HPTXSTS_PTXQTOP_7 (0x80UL << HPTXSTS_PTXQTOP_Pos) // 0x80000000 */ +#define HPTXSTS_PTXQTOP_Msk (0xFFUL << HPTXSTS_PTXQTOP_Pos) // 0xFF000000 +#define HPTXSTS_PTXQTOP HPTXSTS_PTXQTOP_Msk // Top of the periodic transmit request queue +#define HPTXSTS_PTXQTOP_0 (0x01UL << HPTXSTS_PTXQTOP_Pos) // 0x01000000 +#define HPTXSTS_PTXQTOP_1 (0x02UL << HPTXSTS_PTXQTOP_Pos) // 0x02000000 +#define HPTXSTS_PTXQTOP_2 (0x04UL << HPTXSTS_PTXQTOP_Pos) // 0x04000000 +#define HPTXSTS_PTXQTOP_3 (0x08UL << HPTXSTS_PTXQTOP_Pos) // 0x08000000 +#define HPTXSTS_PTXQTOP_4 (0x10UL << HPTXSTS_PTXQTOP_Pos) // 0x10000000 +#define HPTXSTS_PTXQTOP_5 (0x20UL << HPTXSTS_PTXQTOP_Pos) // 0x20000000 +#define HPTXSTS_PTXQTOP_6 (0x40UL << HPTXSTS_PTXQTOP_Pos) // 0x40000000 +#define HPTXSTS_PTXQTOP_7 (0x80UL << HPTXSTS_PTXQTOP_Pos) // 0x80000000 /******************** Bit definition for HAINT register ********************/ #define HAINT_HAINT_Pos (0U) -#define HAINT_HAINT_Msk (0xFFFFUL << HAINT_HAINT_Pos) // 0x0000FFFF */ -#define HAINT_HAINT HAINT_HAINT_Msk // Channel interrupts */ +#define HAINT_HAINT_Msk (0xFFFFUL << HAINT_HAINT_Pos) // 0x0000FFFF +#define HAINT_HAINT HAINT_HAINT_Msk // Channel interrupts /******************** Bit definition for DOEPMSK register ********************/ #define DOEPMSK_XFRCM_Pos (0U) -#define DOEPMSK_XFRCM_Msk (0x1UL << DOEPMSK_XFRCM_Pos) // 0x00000001 */ -#define DOEPMSK_XFRCM DOEPMSK_XFRCM_Msk // Transfer completed interrupt mask */ +#define DOEPMSK_XFRCM_Msk (0x1UL << DOEPMSK_XFRCM_Pos) // 0x00000001 +#define DOEPMSK_XFRCM DOEPMSK_XFRCM_Msk // Transfer completed interrupt mask #define DOEPMSK_EPDM_Pos (1U) -#define DOEPMSK_EPDM_Msk (0x1UL << DOEPMSK_EPDM_Pos) // 0x00000002 */ -#define DOEPMSK_EPDM DOEPMSK_EPDM_Msk // Endpoint disabled interrupt mask */ +#define DOEPMSK_EPDM_Msk (0x1UL << DOEPMSK_EPDM_Pos) // 0x00000002 +#define DOEPMSK_EPDM DOEPMSK_EPDM_Msk // Endpoint disabled interrupt mask #define DOEPMSK_AHBERRM_Pos (2U) -#define DOEPMSK_AHBERRM_Msk (0x1UL << DOEPMSK_AHBERRM_Pos) // 0x00000004 */ -#define DOEPMSK_AHBERRM DOEPMSK_AHBERRM_Msk // OUT transaction AHB Error interrupt mask */ +#define DOEPMSK_AHBERRM_Msk (0x1UL << DOEPMSK_AHBERRM_Pos) // 0x00000004 +#define DOEPMSK_AHBERRM DOEPMSK_AHBERRM_Msk // OUT transaction AHB Error interrupt mask #define DOEPMSK_STUPM_Pos (3U) -#define DOEPMSK_STUPM_Msk (0x1UL << DOEPMSK_STUPM_Pos) // 0x00000008 */ -#define DOEPMSK_STUPM DOEPMSK_STUPM_Msk // SETUP phase done mask */ +#define DOEPMSK_STUPM_Msk (0x1UL << DOEPMSK_STUPM_Pos) // 0x00000008 +#define DOEPMSK_STUPM DOEPMSK_STUPM_Msk // SETUP phase done mask #define DOEPMSK_OTEPDM_Pos (4U) -#define DOEPMSK_OTEPDM_Msk (0x1UL << DOEPMSK_OTEPDM_Pos) // 0x00000010 */ -#define DOEPMSK_OTEPDM DOEPMSK_OTEPDM_Msk // OUT token received when endpoint disabled mask */ +#define DOEPMSK_OTEPDM_Msk (0x1UL << DOEPMSK_OTEPDM_Pos) // 0x00000010 +#define DOEPMSK_OTEPDM DOEPMSK_OTEPDM_Msk // OUT token received when endpoint disabled mask #define DOEPMSK_OTEPSPRM_Pos (5U) -#define DOEPMSK_OTEPSPRM_Msk (0x1UL << DOEPMSK_OTEPSPRM_Pos) // 0x00000020 */ -#define DOEPMSK_OTEPSPRM DOEPMSK_OTEPSPRM_Msk // Status Phase Received mask */ +#define DOEPMSK_OTEPSPRM_Msk (0x1UL << DOEPMSK_OTEPSPRM_Pos) // 0x00000020 +#define DOEPMSK_OTEPSPRM DOEPMSK_OTEPSPRM_Msk // Status Phase Received mask #define DOEPMSK_B2BSTUP_Pos (6U) -#define DOEPMSK_B2BSTUP_Msk (0x1UL << DOEPMSK_B2BSTUP_Pos) // 0x00000040 */ -#define DOEPMSK_B2BSTUP DOEPMSK_B2BSTUP_Msk // Back-to-back SETUP packets received mask */ +#define DOEPMSK_B2BSTUP_Msk (0x1UL << DOEPMSK_B2BSTUP_Pos) // 0x00000040 +#define DOEPMSK_B2BSTUP DOEPMSK_B2BSTUP_Msk // Back-to-back SETUP packets received mask #define DOEPMSK_OPEM_Pos (8U) -#define DOEPMSK_OPEM_Msk (0x1UL << DOEPMSK_OPEM_Pos) // 0x00000100 */ -#define DOEPMSK_OPEM DOEPMSK_OPEM_Msk // OUT packet error mask */ +#define DOEPMSK_OPEM_Msk (0x1UL << DOEPMSK_OPEM_Pos) // 0x00000100 +#define DOEPMSK_OPEM DOEPMSK_OPEM_Msk // OUT packet error mask #define DOEPMSK_BOIM_Pos (9U) -#define DOEPMSK_BOIM_Msk (0x1UL << DOEPMSK_BOIM_Pos) // 0x00000200 */ -#define DOEPMSK_BOIM DOEPMSK_BOIM_Msk // BNA interrupt mask */ +#define DOEPMSK_BOIM_Msk (0x1UL << DOEPMSK_BOIM_Pos) // 0x00000200 +#define DOEPMSK_BOIM DOEPMSK_BOIM_Msk // BNA interrupt mask #define DOEPMSK_BERRM_Pos (12U) -#define DOEPMSK_BERRM_Msk (0x1UL << DOEPMSK_BERRM_Pos) // 0x00001000 */ -#define DOEPMSK_BERRM DOEPMSK_BERRM_Msk // Babble error interrupt mask */ +#define DOEPMSK_BERRM_Msk (0x1UL << DOEPMSK_BERRM_Pos) // 0x00001000 +#define DOEPMSK_BERRM DOEPMSK_BERRM_Msk // Babble error interrupt mask #define DOEPMSK_NAKM_Pos (13U) -#define DOEPMSK_NAKM_Msk (0x1UL << DOEPMSK_NAKM_Pos) // 0x00002000 */ -#define DOEPMSK_NAKM DOEPMSK_NAKM_Msk // OUT Packet NAK interrupt mask */ +#define DOEPMSK_NAKM_Msk (0x1UL << DOEPMSK_NAKM_Pos) // 0x00002000 +#define DOEPMSK_NAKM DOEPMSK_NAKM_Msk // OUT Packet NAK interrupt mask #define DOEPMSK_NYETM_Pos (14U) -#define DOEPMSK_NYETM_Msk (0x1UL << DOEPMSK_NYETM_Pos) // 0x00004000 */ -#define DOEPMSK_NYETM DOEPMSK_NYETM_Msk // NYET interrupt mask */ +#define DOEPMSK_NYETM_Msk (0x1UL << DOEPMSK_NYETM_Pos) // 0x00004000 +#define DOEPMSK_NYETM DOEPMSK_NYETM_Msk // NYET interrupt mask /******************** Bit definition for GINTSTS register ********************/ #define GINTSTS_CMOD_Pos (0U) -#define GINTSTS_CMOD_Msk (0x1UL << GINTSTS_CMOD_Pos) // 0x00000001 */ -#define GINTSTS_CMOD GINTSTS_CMOD_Msk // Current mode of operation */ +#define GINTSTS_CMOD_Msk (0x1UL << GINTSTS_CMOD_Pos) // 0x00000001 +#define GINTSTS_CMOD GINTSTS_CMOD_Msk // Current mode of operation #define GINTSTS_MMIS_Pos (1U) -#define GINTSTS_MMIS_Msk (0x1UL << GINTSTS_MMIS_Pos) // 0x00000002 */ -#define GINTSTS_MMIS GINTSTS_MMIS_Msk // Mode mismatch interrupt */ +#define GINTSTS_MMIS_Msk (0x1UL << GINTSTS_MMIS_Pos) // 0x00000002 +#define GINTSTS_MMIS GINTSTS_MMIS_Msk // Mode mismatch interrupt #define GINTSTS_OTGINT_Pos (2U) -#define GINTSTS_OTGINT_Msk (0x1UL << GINTSTS_OTGINT_Pos) // 0x00000004 */ -#define GINTSTS_OTGINT GINTSTS_OTGINT_Msk // OTG interrupt */ +#define GINTSTS_OTGINT_Msk (0x1UL << GINTSTS_OTGINT_Pos) // 0x00000004 +#define GINTSTS_OTGINT GINTSTS_OTGINT_Msk // OTG interrupt #define GINTSTS_SOF_Pos (3U) -#define GINTSTS_SOF_Msk (0x1UL << GINTSTS_SOF_Pos) // 0x00000008 */ -#define GINTSTS_SOF GINTSTS_SOF_Msk // Start of frame */ +#define GINTSTS_SOF_Msk (0x1UL << GINTSTS_SOF_Pos) // 0x00000008 +#define GINTSTS_SOF GINTSTS_SOF_Msk // Start of frame #define GINTSTS_RXFLVL_Pos (4U) -#define GINTSTS_RXFLVL_Msk (0x1UL << GINTSTS_RXFLVL_Pos) // 0x00000010 */ -#define GINTSTS_RXFLVL GINTSTS_RXFLVL_Msk // RxFIFO nonempty */ +#define GINTSTS_RXFLVL_Msk (0x1UL << GINTSTS_RXFLVL_Pos) // 0x00000010 +#define GINTSTS_RXFLVL GINTSTS_RXFLVL_Msk // RxFIFO nonempty #define GINTSTS_NPTXFE_Pos (5U) -#define GINTSTS_NPTXFE_Msk (0x1UL << GINTSTS_NPTXFE_Pos) // 0x00000020 */ -#define GINTSTS_NPTXFE GINTSTS_NPTXFE_Msk // Nonperiodic TxFIFO empty */ +#define GINTSTS_NPTXFE_Msk (0x1UL << GINTSTS_NPTXFE_Pos) // 0x00000020 +#define GINTSTS_NPTXFE GINTSTS_NPTXFE_Msk // Nonperiodic TxFIFO empty #define GINTSTS_GINAKEFF_Pos (6U) -#define GINTSTS_GINAKEFF_Msk (0x1UL << GINTSTS_GINAKEFF_Pos) // 0x00000040 */ -#define GINTSTS_GINAKEFF GINTSTS_GINAKEFF_Msk // Global IN nonperiodic NAK effective */ +#define GINTSTS_GINAKEFF_Msk (0x1UL << GINTSTS_GINAKEFF_Pos) // 0x00000040 +#define GINTSTS_GINAKEFF GINTSTS_GINAKEFF_Msk // Global IN nonperiodic NAK effective #define GINTSTS_BOUTNAKEFF_Pos (7U) -#define GINTSTS_BOUTNAKEFF_Msk (0x1UL << GINTSTS_BOUTNAKEFF_Pos) // 0x00000080 */ -#define GINTSTS_BOUTNAKEFF GINTSTS_BOUTNAKEFF_Msk // Global OUT NAK effective */ +#define GINTSTS_BOUTNAKEFF_Msk (0x1UL << GINTSTS_BOUTNAKEFF_Pos) // 0x00000080 +#define GINTSTS_BOUTNAKEFF GINTSTS_BOUTNAKEFF_Msk // Global OUT NAK effective #define GINTSTS_ESUSP_Pos (10U) -#define GINTSTS_ESUSP_Msk (0x1UL << GINTSTS_ESUSP_Pos) // 0x00000400 */ -#define GINTSTS_ESUSP GINTSTS_ESUSP_Msk // Early suspend */ +#define GINTSTS_ESUSP_Msk (0x1UL << GINTSTS_ESUSP_Pos) // 0x00000400 +#define GINTSTS_ESUSP GINTSTS_ESUSP_Msk // Early suspend #define GINTSTS_USBSUSP_Pos (11U) -#define GINTSTS_USBSUSP_Msk (0x1UL << GINTSTS_USBSUSP_Pos) // 0x00000800 */ -#define GINTSTS_USBSUSP GINTSTS_USBSUSP_Msk // USB suspend */ +#define GINTSTS_USBSUSP_Msk (0x1UL << GINTSTS_USBSUSP_Pos) // 0x00000800 +#define GINTSTS_USBSUSP GINTSTS_USBSUSP_Msk // USB suspend #define GINTSTS_USBRST_Pos (12U) -#define GINTSTS_USBRST_Msk (0x1UL << GINTSTS_USBRST_Pos) // 0x00001000 */ -#define GINTSTS_USBRST GINTSTS_USBRST_Msk // USB reset */ +#define GINTSTS_USBRST_Msk (0x1UL << GINTSTS_USBRST_Pos) // 0x00001000 +#define GINTSTS_USBRST GINTSTS_USBRST_Msk // USB reset #define GINTSTS_ENUMDNE_Pos (13U) -#define GINTSTS_ENUMDNE_Msk (0x1UL << GINTSTS_ENUMDNE_Pos) // 0x00002000 */ -#define GINTSTS_ENUMDNE GINTSTS_ENUMDNE_Msk // Enumeration done */ +#define GINTSTS_ENUMDNE_Msk (0x1UL << GINTSTS_ENUMDNE_Pos) // 0x00002000 +#define GINTSTS_ENUMDNE GINTSTS_ENUMDNE_Msk // Enumeration done #define GINTSTS_ISOODRP_Pos (14U) -#define GINTSTS_ISOODRP_Msk (0x1UL << GINTSTS_ISOODRP_Pos) // 0x00004000 */ -#define GINTSTS_ISOODRP GINTSTS_ISOODRP_Msk // Isochronous OUT packet dropped interrupt */ +#define GINTSTS_ISOODRP_Msk (0x1UL << GINTSTS_ISOODRP_Pos) // 0x00004000 +#define GINTSTS_ISOODRP GINTSTS_ISOODRP_Msk // Isochronous OUT packet dropped interrupt #define GINTSTS_EOPF_Pos (15U) -#define GINTSTS_EOPF_Msk (0x1UL << GINTSTS_EOPF_Pos) // 0x00008000 */ -#define GINTSTS_EOPF GINTSTS_EOPF_Msk // End of periodic frame interrupt */ +#define GINTSTS_EOPF_Msk (0x1UL << GINTSTS_EOPF_Pos) // 0x00008000 +#define GINTSTS_EOPF GINTSTS_EOPF_Msk // End of periodic frame interrupt #define GINTSTS_IEPINT_Pos (18U) -#define GINTSTS_IEPINT_Msk (0x1UL << GINTSTS_IEPINT_Pos) // 0x00040000 */ -#define GINTSTS_IEPINT GINTSTS_IEPINT_Msk // IN endpoint interrupt */ +#define GINTSTS_IEPINT_Msk (0x1UL << GINTSTS_IEPINT_Pos) // 0x00040000 +#define GINTSTS_IEPINT GINTSTS_IEPINT_Msk // IN endpoint interrupt #define GINTSTS_OEPINT_Pos (19U) -#define GINTSTS_OEPINT_Msk (0x1UL << GINTSTS_OEPINT_Pos) // 0x00080000 */ -#define GINTSTS_OEPINT GINTSTS_OEPINT_Msk // OUT endpoint interrupt */ +#define GINTSTS_OEPINT_Msk (0x1UL << GINTSTS_OEPINT_Pos) // 0x00080000 +#define GINTSTS_OEPINT GINTSTS_OEPINT_Msk // OUT endpoint interrupt #define GINTSTS_IISOIXFR_Pos (20U) -#define GINTSTS_IISOIXFR_Msk (0x1UL << GINTSTS_IISOIXFR_Pos) // 0x00100000 */ -#define GINTSTS_IISOIXFR GINTSTS_IISOIXFR_Msk // Incomplete isochronous IN transfer */ +#define GINTSTS_IISOIXFR_Msk (0x1UL << GINTSTS_IISOIXFR_Pos) // 0x00100000 +#define GINTSTS_IISOIXFR GINTSTS_IISOIXFR_Msk // Incomplete isochronous IN transfer #define GINTSTS_PXFR_INCOMPISOOUT_Pos (21U) -#define GINTSTS_PXFR_INCOMPISOOUT_Msk (0x1UL << GINTSTS_PXFR_INCOMPISOOUT_Pos) // 0x00200000 */ -#define GINTSTS_PXFR_INCOMPISOOUT GINTSTS_PXFR_INCOMPISOOUT_Msk // Incomplete periodic transfer */ +#define GINTSTS_PXFR_INCOMPISOOUT_Msk (0x1UL << GINTSTS_PXFR_INCOMPISOOUT_Pos) // 0x00200000 +#define GINTSTS_PXFR_INCOMPISOOUT GINTSTS_PXFR_INCOMPISOOUT_Msk // Incomplete periodic transfer #define GINTSTS_DATAFSUSP_Pos (22U) -#define GINTSTS_DATAFSUSP_Msk (0x1UL << GINTSTS_DATAFSUSP_Pos) // 0x00400000 */ -#define GINTSTS_DATAFSUSP GINTSTS_DATAFSUSP_Msk // Data fetch suspended */ +#define GINTSTS_DATAFSUSP_Msk (0x1UL << GINTSTS_DATAFSUSP_Pos) // 0x00400000 +#define GINTSTS_DATAFSUSP GINTSTS_DATAFSUSP_Msk // Data fetch suspended #define GINTSTS_RSTDET_Pos (23U) -#define GINTSTS_RSTDET_Msk (0x1UL << GINTSTS_RSTDET_Pos) // 0x00800000 */ -#define GINTSTS_RSTDET GINTSTS_RSTDET_Msk // Reset detected interrupt */ +#define GINTSTS_RSTDET_Msk (0x1UL << GINTSTS_RSTDET_Pos) // 0x00800000 +#define GINTSTS_RSTDET GINTSTS_RSTDET_Msk // Reset detected interrupt #define GINTSTS_HPRTINT_Pos (24U) -#define GINTSTS_HPRTINT_Msk (0x1UL << GINTSTS_HPRTINT_Pos) // 0x01000000 */ -#define GINTSTS_HPRTINT GINTSTS_HPRTINT_Msk // Host port interrupt */ +#define GINTSTS_HPRTINT_Msk (0x1UL << GINTSTS_HPRTINT_Pos) // 0x01000000 +#define GINTSTS_HPRTINT GINTSTS_HPRTINT_Msk // Host port interrupt #define GINTSTS_HCINT_Pos (25U) -#define GINTSTS_HCINT_Msk (0x1UL << GINTSTS_HCINT_Pos) // 0x02000000 */ -#define GINTSTS_HCINT GINTSTS_HCINT_Msk // Host channels interrupt */ +#define GINTSTS_HCINT_Msk (0x1UL << GINTSTS_HCINT_Pos) // 0x02000000 +#define GINTSTS_HCINT GINTSTS_HCINT_Msk // Host channels interrupt #define GINTSTS_PTXFE_Pos (26U) -#define GINTSTS_PTXFE_Msk (0x1UL << GINTSTS_PTXFE_Pos) // 0x04000000 */ -#define GINTSTS_PTXFE GINTSTS_PTXFE_Msk // Periodic TxFIFO empty */ +#define GINTSTS_PTXFE_Msk (0x1UL << GINTSTS_PTXFE_Pos) // 0x04000000 +#define GINTSTS_PTXFE GINTSTS_PTXFE_Msk // Periodic TxFIFO empty #define GINTSTS_LPMINT_Pos (27U) -#define GINTSTS_LPMINT_Msk (0x1UL << GINTSTS_LPMINT_Pos) // 0x08000000 */ -#define GINTSTS_LPMINT GINTSTS_LPMINT_Msk // LPM interrupt */ +#define GINTSTS_LPMINT_Msk (0x1UL << GINTSTS_LPMINT_Pos) // 0x08000000 +#define GINTSTS_LPMINT GINTSTS_LPMINT_Msk // LPM interrupt #define GINTSTS_CIDSCHG_Pos (28U) -#define GINTSTS_CIDSCHG_Msk (0x1UL << GINTSTS_CIDSCHG_Pos) // 0x10000000 */ -#define GINTSTS_CIDSCHG GINTSTS_CIDSCHG_Msk // Connector ID status change */ +#define GINTSTS_CIDSCHG_Msk (0x1UL << GINTSTS_CIDSCHG_Pos) // 0x10000000 +#define GINTSTS_CIDSCHG GINTSTS_CIDSCHG_Msk // Connector ID status change #define GINTSTS_DISCINT_Pos (29U) -#define GINTSTS_DISCINT_Msk (0x1UL << GINTSTS_DISCINT_Pos) // 0x20000000 */ -#define GINTSTS_DISCINT GINTSTS_DISCINT_Msk // Disconnect detected interrupt */ +#define GINTSTS_DISCINT_Msk (0x1UL << GINTSTS_DISCINT_Pos) // 0x20000000 +#define GINTSTS_DISCINT GINTSTS_DISCINT_Msk // Disconnect detected interrupt #define GINTSTS_SRQINT_Pos (30U) -#define GINTSTS_SRQINT_Msk (0x1UL << GINTSTS_SRQINT_Pos) // 0x40000000 */ -#define GINTSTS_SRQINT GINTSTS_SRQINT_Msk // Session request/new session detected interrupt */ +#define GINTSTS_SRQINT_Msk (0x1UL << GINTSTS_SRQINT_Pos) // 0x40000000 +#define GINTSTS_SRQINT GINTSTS_SRQINT_Msk // Session request/new session detected interrupt #define GINTSTS_WKUINT_Pos (31U) -#define GINTSTS_WKUINT_Msk (0x1UL << GINTSTS_WKUINT_Pos) // 0x80000000 */ -#define GINTSTS_WKUINT GINTSTS_WKUINT_Msk // Resume/remote wakeup detected interrupt */ +#define GINTSTS_WKUINT_Msk (0x1UL << GINTSTS_WKUINT_Pos) // 0x80000000 +#define GINTSTS_WKUINT GINTSTS_WKUINT_Msk // Resume/remote wakeup detected interrupt /******************** Bit definition for GINTMSK register ********************/ #define GINTMSK_MMISM_Pos (1U) -#define GINTMSK_MMISM_Msk (0x1UL << GINTMSK_MMISM_Pos) // 0x00000002 */ -#define GINTMSK_MMISM GINTMSK_MMISM_Msk // Mode mismatch interrupt mask */ +#define GINTMSK_MMISM_Msk (0x1UL << GINTMSK_MMISM_Pos) // 0x00000002 +#define GINTMSK_MMISM GINTMSK_MMISM_Msk // Mode mismatch interrupt mask #define GINTMSK_OTGINT_Pos (2U) -#define GINTMSK_OTGINT_Msk (0x1UL << GINTMSK_OTGINT_Pos) // 0x00000004 */ -#define GINTMSK_OTGINT GINTMSK_OTGINT_Msk // OTG interrupt mask */ +#define GINTMSK_OTGINT_Msk (0x1UL << GINTMSK_OTGINT_Pos) // 0x00000004 +#define GINTMSK_OTGINT GINTMSK_OTGINT_Msk // OTG interrupt mask #define GINTMSK_SOFM_Pos (3U) -#define GINTMSK_SOFM_Msk (0x1UL << GINTMSK_SOFM_Pos) // 0x00000008 */ -#define GINTMSK_SOFM GINTMSK_SOFM_Msk // Start of frame mask */ +#define GINTMSK_SOFM_Msk (0x1UL << GINTMSK_SOFM_Pos) // 0x00000008 +#define GINTMSK_SOFM GINTMSK_SOFM_Msk // Start of frame mask #define GINTMSK_RXFLVLM_Pos (4U) -#define GINTMSK_RXFLVLM_Msk (0x1UL << GINTMSK_RXFLVLM_Pos) // 0x00000010 */ -#define GINTMSK_RXFLVLM GINTMSK_RXFLVLM_Msk // Receive FIFO nonempty mask */ +#define GINTMSK_RXFLVLM_Msk (0x1UL << GINTMSK_RXFLVLM_Pos) // 0x00000010 +#define GINTMSK_RXFLVLM GINTMSK_RXFLVLM_Msk // Receive FIFO nonempty mask #define GINTMSK_NPTXFEM_Pos (5U) -#define GINTMSK_NPTXFEM_Msk (0x1UL << GINTMSK_NPTXFEM_Pos) // 0x00000020 */ -#define GINTMSK_NPTXFEM GINTMSK_NPTXFEM_Msk // Nonperiodic TxFIFO empty mask */ +#define GINTMSK_NPTXFEM_Msk (0x1UL << GINTMSK_NPTXFEM_Pos) // 0x00000020 +#define GINTMSK_NPTXFEM GINTMSK_NPTXFEM_Msk // Nonperiodic TxFIFO empty mask #define GINTMSK_GINAKEFFM_Pos (6U) -#define GINTMSK_GINAKEFFM_Msk (0x1UL << GINTMSK_GINAKEFFM_Pos) // 0x00000040 */ -#define GINTMSK_GINAKEFFM GINTMSK_GINAKEFFM_Msk // Global nonperiodic IN NAK effective mask */ +#define GINTMSK_GINAKEFFM_Msk (0x1UL << GINTMSK_GINAKEFFM_Pos) // 0x00000040 +#define GINTMSK_GINAKEFFM GINTMSK_GINAKEFFM_Msk // Global nonperiodic IN NAK effective mask #define GINTMSK_GONAKEFFM_Pos (7U) -#define GINTMSK_GONAKEFFM_Msk (0x1UL << GINTMSK_GONAKEFFM_Pos) // 0x00000080 */ -#define GINTMSK_GONAKEFFM GINTMSK_GONAKEFFM_Msk // Global OUT NAK effective mask */ +#define GINTMSK_GONAKEFFM_Msk (0x1UL << GINTMSK_GONAKEFFM_Pos) // 0x00000080 +#define GINTMSK_GONAKEFFM GINTMSK_GONAKEFFM_Msk // Global OUT NAK effective mask #define GINTMSK_ESUSPM_Pos (10U) -#define GINTMSK_ESUSPM_Msk (0x1UL << GINTMSK_ESUSPM_Pos) // 0x00000400 */ -#define GINTMSK_ESUSPM GINTMSK_ESUSPM_Msk // Early suspend mask */ +#define GINTMSK_ESUSPM_Msk (0x1UL << GINTMSK_ESUSPM_Pos) // 0x00000400 +#define GINTMSK_ESUSPM GINTMSK_ESUSPM_Msk // Early suspend mask #define GINTMSK_USBSUSPM_Pos (11U) -#define GINTMSK_USBSUSPM_Msk (0x1UL << GINTMSK_USBSUSPM_Pos) // 0x00000800 */ -#define GINTMSK_USBSUSPM GINTMSK_USBSUSPM_Msk // USB suspend mask */ +#define GINTMSK_USBSUSPM_Msk (0x1UL << GINTMSK_USBSUSPM_Pos) // 0x00000800 +#define GINTMSK_USBSUSPM GINTMSK_USBSUSPM_Msk // USB suspend mask #define GINTMSK_USBRST_Pos (12U) -#define GINTMSK_USBRST_Msk (0x1UL << GINTMSK_USBRST_Pos) // 0x00001000 */ -#define GINTMSK_USBRST GINTMSK_USBRST_Msk // USB reset mask */ +#define GINTMSK_USBRST_Msk (0x1UL << GINTMSK_USBRST_Pos) // 0x00001000 +#define GINTMSK_USBRST GINTMSK_USBRST_Msk // USB reset mask #define GINTMSK_ENUMDNEM_Pos (13U) -#define GINTMSK_ENUMDNEM_Msk (0x1UL << GINTMSK_ENUMDNEM_Pos) // 0x00002000 */ -#define GINTMSK_ENUMDNEM GINTMSK_ENUMDNEM_Msk // Enumeration done mask */ +#define GINTMSK_ENUMDNEM_Msk (0x1UL << GINTMSK_ENUMDNEM_Pos) // 0x00002000 +#define GINTMSK_ENUMDNEM GINTMSK_ENUMDNEM_Msk // Enumeration done mask #define GINTMSK_ISOODRPM_Pos (14U) -#define GINTMSK_ISOODRPM_Msk (0x1UL << GINTMSK_ISOODRPM_Pos) // 0x00004000 */ -#define GINTMSK_ISOODRPM GINTMSK_ISOODRPM_Msk // Isochronous OUT packet dropped interrupt mask */ +#define GINTMSK_ISOODRPM_Msk (0x1UL << GINTMSK_ISOODRPM_Pos) // 0x00004000 +#define GINTMSK_ISOODRPM GINTMSK_ISOODRPM_Msk // Isochronous OUT packet dropped interrupt mask #define GINTMSK_EOPFM_Pos (15U) -#define GINTMSK_EOPFM_Msk (0x1UL << GINTMSK_EOPFM_Pos) // 0x00008000 */ -#define GINTMSK_EOPFM GINTMSK_EOPFM_Msk // End of periodic frame interrupt mask */ +#define GINTMSK_EOPFM_Msk (0x1UL << GINTMSK_EOPFM_Pos) // 0x00008000 +#define GINTMSK_EOPFM GINTMSK_EOPFM_Msk // End of periodic frame interrupt mask #define GINTMSK_EPMISM_Pos (17U) -#define GINTMSK_EPMISM_Msk (0x1UL << GINTMSK_EPMISM_Pos) // 0x00020000 */ -#define GINTMSK_EPMISM GINTMSK_EPMISM_Msk // Endpoint mismatch interrupt mask */ +#define GINTMSK_EPMISM_Msk (0x1UL << GINTMSK_EPMISM_Pos) // 0x00020000 +#define GINTMSK_EPMISM GINTMSK_EPMISM_Msk // Endpoint mismatch interrupt mask #define GINTMSK_IEPINT_Pos (18U) -#define GINTMSK_IEPINT_Msk (0x1UL << GINTMSK_IEPINT_Pos) // 0x00040000 */ -#define GINTMSK_IEPINT GINTMSK_IEPINT_Msk // IN endpoints interrupt mask */ +#define GINTMSK_IEPINT_Msk (0x1UL << GINTMSK_IEPINT_Pos) // 0x00040000 +#define GINTMSK_IEPINT GINTMSK_IEPINT_Msk // IN endpoints interrupt mask #define GINTMSK_OEPINT_Pos (19U) -#define GINTMSK_OEPINT_Msk (0x1UL << GINTMSK_OEPINT_Pos) // 0x00080000 */ -#define GINTMSK_OEPINT GINTMSK_OEPINT_Msk // OUT endpoints interrupt mask */ +#define GINTMSK_OEPINT_Msk (0x1UL << GINTMSK_OEPINT_Pos) // 0x00080000 +#define GINTMSK_OEPINT GINTMSK_OEPINT_Msk // OUT endpoints interrupt mask #define GINTMSK_IISOIXFRM_Pos (20U) -#define GINTMSK_IISOIXFRM_Msk (0x1UL << GINTMSK_IISOIXFRM_Pos) // 0x00100000 */ -#define GINTMSK_IISOIXFRM GINTMSK_IISOIXFRM_Msk // Incomplete isochronous IN transfer mask */ +#define GINTMSK_IISOIXFRM_Msk (0x1UL << GINTMSK_IISOIXFRM_Pos) // 0x00100000 +#define GINTMSK_IISOIXFRM GINTMSK_IISOIXFRM_Msk // Incomplete isochronous IN transfer mask #define GINTMSK_PXFRM_IISOOXFRM_Pos (21U) -#define GINTMSK_PXFRM_IISOOXFRM_Msk (0x1UL << GINTMSK_PXFRM_IISOOXFRM_Pos) // 0x00200000 */ -#define GINTMSK_PXFRM_IISOOXFRM GINTMSK_PXFRM_IISOOXFRM_Msk // Incomplete periodic transfer mask */ +#define GINTMSK_PXFRM_IISOOXFRM_Msk (0x1UL << GINTMSK_PXFRM_IISOOXFRM_Pos) // 0x00200000 +#define GINTMSK_PXFRM_IISOOXFRM GINTMSK_PXFRM_IISOOXFRM_Msk // Incomplete periodic transfer mask #define GINTMSK_FSUSPM_Pos (22U) -#define GINTMSK_FSUSPM_Msk (0x1UL << GINTMSK_FSUSPM_Pos) // 0x00400000 */ -#define GINTMSK_FSUSPM GINTMSK_FSUSPM_Msk // Data fetch suspended mask */ +#define GINTMSK_FSUSPM_Msk (0x1UL << GINTMSK_FSUSPM_Pos) // 0x00400000 +#define GINTMSK_FSUSPM GINTMSK_FSUSPM_Msk // Data fetch suspended mask #define GINTMSK_RSTDEM_Pos (23U) -#define GINTMSK_RSTDEM_Msk (0x1UL << GINTMSK_RSTDEM_Pos) // 0x00800000 */ -#define GINTMSK_RSTDEM GINTMSK_RSTDEM_Msk // Reset detected interrupt mask */ +#define GINTMSK_RSTDEM_Msk (0x1UL << GINTMSK_RSTDEM_Pos) // 0x00800000 +#define GINTMSK_RSTDEM GINTMSK_RSTDEM_Msk // Reset detected interrupt mask #define GINTMSK_PRTIM_Pos (24U) -#define GINTMSK_PRTIM_Msk (0x1UL << GINTMSK_PRTIM_Pos) // 0x01000000 */ -#define GINTMSK_PRTIM GINTMSK_PRTIM_Msk // Host port interrupt mask */ +#define GINTMSK_PRTIM_Msk (0x1UL << GINTMSK_PRTIM_Pos) // 0x01000000 +#define GINTMSK_PRTIM GINTMSK_PRTIM_Msk // Host port interrupt mask #define GINTMSK_HCIM_Pos (25U) -#define GINTMSK_HCIM_Msk (0x1UL << GINTMSK_HCIM_Pos) // 0x02000000 */ -#define GINTMSK_HCIM GINTMSK_HCIM_Msk // Host channels interrupt mask */ +#define GINTMSK_HCIM_Msk (0x1UL << GINTMSK_HCIM_Pos) // 0x02000000 +#define GINTMSK_HCIM GINTMSK_HCIM_Msk // Host channels interrupt mask #define GINTMSK_PTXFEM_Pos (26U) -#define GINTMSK_PTXFEM_Msk (0x1UL << GINTMSK_PTXFEM_Pos) // 0x04000000 */ -#define GINTMSK_PTXFEM GINTMSK_PTXFEM_Msk // Periodic TxFIFO empty mask */ +#define GINTMSK_PTXFEM_Msk (0x1UL << GINTMSK_PTXFEM_Pos) // 0x04000000 +#define GINTMSK_PTXFEM GINTMSK_PTXFEM_Msk // Periodic TxFIFO empty mask #define GINTMSK_LPMINTM_Pos (27U) -#define GINTMSK_LPMINTM_Msk (0x1UL << GINTMSK_LPMINTM_Pos) // 0x08000000 */ -#define GINTMSK_LPMINTM GINTMSK_LPMINTM_Msk // LPM interrupt Mask */ +#define GINTMSK_LPMINTM_Msk (0x1UL << GINTMSK_LPMINTM_Pos) // 0x08000000 +#define GINTMSK_LPMINTM GINTMSK_LPMINTM_Msk // LPM interrupt Mask #define GINTMSK_CIDSCHGM_Pos (28U) -#define GINTMSK_CIDSCHGM_Msk (0x1UL << GINTMSK_CIDSCHGM_Pos) // 0x10000000 */ -#define GINTMSK_CIDSCHGM GINTMSK_CIDSCHGM_Msk // Connector ID status change mask */ +#define GINTMSK_CIDSCHGM_Msk (0x1UL << GINTMSK_CIDSCHGM_Pos) // 0x10000000 +#define GINTMSK_CIDSCHGM GINTMSK_CIDSCHGM_Msk // Connector ID status change mask #define GINTMSK_DISCINT_Pos (29U) -#define GINTMSK_DISCINT_Msk (0x1UL << GINTMSK_DISCINT_Pos) // 0x20000000 */ -#define GINTMSK_DISCINT GINTMSK_DISCINT_Msk // Disconnect detected interrupt mask */ +#define GINTMSK_DISCINT_Msk (0x1UL << GINTMSK_DISCINT_Pos) // 0x20000000 +#define GINTMSK_DISCINT GINTMSK_DISCINT_Msk // Disconnect detected interrupt mask #define GINTMSK_SRQIM_Pos (30U) -#define GINTMSK_SRQIM_Msk (0x1UL << GINTMSK_SRQIM_Pos) // 0x40000000 */ -#define GINTMSK_SRQIM GINTMSK_SRQIM_Msk // Session request/new session detected interrupt mask */ +#define GINTMSK_SRQIM_Msk (0x1UL << GINTMSK_SRQIM_Pos) // 0x40000000 +#define GINTMSK_SRQIM GINTMSK_SRQIM_Msk // Session request/new session detected interrupt mask #define GINTMSK_WUIM_Pos (31U) -#define GINTMSK_WUIM_Msk (0x1UL << GINTMSK_WUIM_Pos) // 0x80000000 */ -#define GINTMSK_WUIM GINTMSK_WUIM_Msk // Resume/remote wakeup detected interrupt mask */ +#define GINTMSK_WUIM_Msk (0x1UL << GINTMSK_WUIM_Pos) // 0x80000000 +#define GINTMSK_WUIM GINTMSK_WUIM_Msk // Resume/remote wakeup detected interrupt mask /******************** Bit definition for DAINT register ********************/ #define DAINT_IEPINT_Pos (0U) -#define DAINT_IEPINT_Msk (0xFFFFUL << DAINT_IEPINT_Pos) // 0x0000FFFF */ -#define DAINT_IEPINT DAINT_IEPINT_Msk // IN endpoint interrupt bits */ +#define DAINT_IEPINT_Msk (0xFFFFUL << DAINT_IEPINT_Pos) // 0x0000FFFF +#define DAINT_IEPINT DAINT_IEPINT_Msk // IN endpoint interrupt bits #define DAINT_OEPINT_Pos (16U) -#define DAINT_OEPINT_Msk (0xFFFFUL << DAINT_OEPINT_Pos) // 0xFFFF0000 */ -#define DAINT_OEPINT DAINT_OEPINT_Msk // OUT endpoint interrupt bits */ +#define DAINT_OEPINT_Msk (0xFFFFUL << DAINT_OEPINT_Pos) // 0xFFFF0000 +#define DAINT_OEPINT DAINT_OEPINT_Msk // OUT endpoint interrupt bits /******************** Bit definition for HAINTMSK register ********************/ #define HAINTMSK_HAINTM_Pos (0U) -#define HAINTMSK_HAINTM_Msk (0xFFFFUL << HAINTMSK_HAINTM_Pos) // 0x0000FFFF */ -#define HAINTMSK_HAINTM HAINTMSK_HAINTM_Msk // Channel interrupt mask */ +#define HAINTMSK_HAINTM_Msk (0xFFFFUL << HAINTMSK_HAINTM_Pos) // 0x0000FFFF +#define HAINTMSK_HAINTM HAINTMSK_HAINTM_Msk // Channel interrupt mask /******************** Bit definition for GRXSTSP register ********************/ #define GRXSTSP_EPNUM_Pos (0U) -#define GRXSTSP_EPNUM_Msk (0xFUL << GRXSTSP_EPNUM_Pos) // 0x0000000F */ -#define GRXSTSP_EPNUM GRXSTSP_EPNUM_Msk // IN EP interrupt mask bits */ +#define GRXSTSP_EPNUM_Msk (0xFUL << GRXSTSP_EPNUM_Pos) // 0x0000000F +#define GRXSTSP_EPNUM GRXSTSP_EPNUM_Msk // IN EP interrupt mask bits #define GRXSTSP_BCNT_Pos (4U) -#define GRXSTSP_BCNT_Msk (0x7FFUL << GRXSTSP_BCNT_Pos) // 0x00007FF0 */ -#define GRXSTSP_BCNT GRXSTSP_BCNT_Msk // OUT EP interrupt mask bits */ +#define GRXSTSP_BCNT_Msk (0x7FFUL << GRXSTSP_BCNT_Pos) // 0x00007FF0 +#define GRXSTSP_BCNT GRXSTSP_BCNT_Msk // OUT EP interrupt mask bits #define GRXSTSP_DPID_Pos (15U) -#define GRXSTSP_DPID_Msk (0x3UL << GRXSTSP_DPID_Pos) // 0x00018000 */ -#define GRXSTSP_DPID GRXSTSP_DPID_Msk // OUT EP interrupt mask bits */ +#define GRXSTSP_DPID_Msk (0x3UL << GRXSTSP_DPID_Pos) // 0x00018000 +#define GRXSTSP_DPID GRXSTSP_DPID_Msk // OUT EP interrupt mask bits #define GRXSTSP_PKTSTS_Pos (17U) -#define GRXSTSP_PKTSTS_Msk (0xFUL << GRXSTSP_PKTSTS_Pos) // 0x001E0000 */ -#define GRXSTSP_PKTSTS GRXSTSP_PKTSTS_Msk // OUT EP interrupt mask bits */ +#define GRXSTSP_PKTSTS_Msk (0xFUL << GRXSTSP_PKTSTS_Pos) // 0x001E0000 +#define GRXSTSP_PKTSTS GRXSTSP_PKTSTS_Msk // OUT EP interrupt mask bits #define GRXSTS_PKTSTS_GLOBALOUTNAK 1 #define GRXSTS_PKTSTS_OUTRX 2 @@ -933,773 +934,803 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size"); /******************** Bit definition for DAINTMSK register ********************/ #define DAINTMSK_IEPM_Pos (0U) -#define DAINTMSK_IEPM_Msk (0xFFFFUL << DAINTMSK_IEPM_Pos) // 0x0000FFFF */ -#define DAINTMSK_IEPM DAINTMSK_IEPM_Msk // IN EP interrupt mask bits */ +#define DAINTMSK_IEPM_Msk (0xFFFFUL << DAINTMSK_IEPM_Pos) // 0x0000FFFF +#define DAINTMSK_IEPM DAINTMSK_IEPM_Msk // IN EP interrupt mask bits #define DAINTMSK_OEPM_Pos (16U) -#define DAINTMSK_OEPM_Msk (0xFFFFUL << DAINTMSK_OEPM_Pos) // 0xFFFF0000 */ -#define DAINTMSK_OEPM DAINTMSK_OEPM_Msk // OUT EP interrupt mask bits */ +#define DAINTMSK_OEPM_Msk (0xFFFFUL << DAINTMSK_OEPM_Pos) // 0xFFFF0000 +#define DAINTMSK_OEPM DAINTMSK_OEPM_Msk // OUT EP interrupt mask bits #if 0 /******************** Bit definition for OTG register ********************/ #define CHNUM_Pos (0U) -#define CHNUM_Msk (0xFUL << CHNUM_Pos) // 0x0000000F */ -#define CHNUM CHNUM_Msk // Channel number */ -#define CHNUM_0 (0x1UL << CHNUM_Pos) // 0x00000001 */ -#define CHNUM_1 (0x2UL << CHNUM_Pos) // 0x00000002 */ -#define CHNUM_2 (0x4UL << CHNUM_Pos) // 0x00000004 */ -#define CHNUM_3 (0x8UL << CHNUM_Pos) // 0x00000008 */ +#define CHNUM_Msk (0xFUL << CHNUM_Pos) // 0x0000000F +#define CHNUM CHNUM_Msk // Channel number +#define CHNUM_0 (0x1UL << CHNUM_Pos) // 0x00000001 +#define CHNUM_1 (0x2UL << CHNUM_Pos) // 0x00000002 +#define CHNUM_2 (0x4UL << CHNUM_Pos) // 0x00000004 +#define CHNUM_3 (0x8UL << CHNUM_Pos) // 0x00000008 #define BCNT_Pos (4U) -#define BCNT_Msk (0x7FFUL << BCNT_Pos) // 0x00007FF0 */ -#define BCNT BCNT_Msk // Byte count */ +#define BCNT_Msk (0x7FFUL << BCNT_Pos) // 0x00007FF0 +#define BCNT BCNT_Msk // Byte count #define DPID_Pos (15U) -#define DPID_Msk (0x3UL << DPID_Pos) // 0x00018000 */ -#define DPID DPID_Msk // Data PID */ -#define DPID_0 (0x1UL << DPID_Pos) // 0x00008000 */ -#define DPID_1 (0x2UL << DPID_Pos) // 0x00010000 */ +#define DPID_Msk (0x3UL << DPID_Pos) // 0x00018000 +#define DPID DPID_Msk // Data PID +#define DPID_0 (0x1UL << DPID_Pos) // 0x00008000 +#define DPID_1 (0x2UL << DPID_Pos) // 0x00010000 #define PKTSTS_Pos (17U) -#define PKTSTS_Msk (0xFUL << PKTSTS_Pos) // 0x001E0000 */ -#define PKTSTS PKTSTS_Msk // Packet status */ -#define PKTSTS_0 (0x1UL << PKTSTS_Pos) // 0x00020000 */ -#define PKTSTS_1 (0x2UL << PKTSTS_Pos) // 0x00040000 */ -#define PKTSTS_2 (0x4UL << PKTSTS_Pos) // 0x00080000 */ -#define PKTSTS_3 (0x8UL << PKTSTS_Pos) // 0x00100000 */ +#define PKTSTS_Msk (0xFUL << PKTSTS_Pos) // 0x001E0000 +#define PKTSTS PKTSTS_Msk // Packet status +#define PKTSTS_0 (0x1UL << PKTSTS_Pos) // 0x00020000 +#define PKTSTS_1 (0x2UL << PKTSTS_Pos) // 0x00040000 +#define PKTSTS_2 (0x4UL << PKTSTS_Pos) // 0x00080000 +#define PKTSTS_3 (0x8UL << PKTSTS_Pos) // 0x00100000 #define EPNUM_Pos (0U) -#define EPNUM_Msk (0xFUL << EPNUM_Pos) // 0x0000000F */ -#define EPNUM EPNUM_Msk // Endpoint number */ -#define EPNUM_0 (0x1UL << EPNUM_Pos) // 0x00000001 */ -#define EPNUM_1 (0x2UL << EPNUM_Pos) // 0x00000002 */ -#define EPNUM_2 (0x4UL << EPNUM_Pos) // 0x00000004 */ -#define EPNUM_3 (0x8UL << EPNUM_Pos) // 0x00000008 */ +#define EPNUM_Msk (0xFUL << EPNUM_Pos) // 0x0000000F +#define EPNUM EPNUM_Msk // Endpoint number +#define EPNUM_0 (0x1UL << EPNUM_Pos) // 0x00000001 +#define EPNUM_1 (0x2UL << EPNUM_Pos) // 0x00000002 +#define EPNUM_2 (0x4UL << EPNUM_Pos) // 0x00000004 +#define EPNUM_3 (0x8UL << EPNUM_Pos) // 0x00000008 #define FRMNUM_Pos (21U) -#define FRMNUM_Msk (0xFUL << FRMNUM_Pos) // 0x01E00000 */ -#define FRMNUM FRMNUM_Msk // Frame number */ -#define FRMNUM_0 (0x1UL << FRMNUM_Pos) // 0x00200000 */ -#define FRMNUM_1 (0x2UL << FRMNUM_Pos) // 0x00400000 */ -#define FRMNUM_2 (0x4UL << FRMNUM_Pos) // 0x00800000 */ -#define FRMNUM_3 (0x8UL << FRMNUM_Pos) // 0x01000000 */ +#define FRMNUM_Msk (0xFUL << FRMNUM_Pos) // 0x01E00000 +#define FRMNUM FRMNUM_Msk // Frame number +#define FRMNUM_0 (0x1UL << FRMNUM_Pos) // 0x00200000 +#define FRMNUM_1 (0x2UL << FRMNUM_Pos) // 0x00400000 +#define FRMNUM_2 (0x4UL << FRMNUM_Pos) // 0x00800000 +#define FRMNUM_3 (0x8UL << FRMNUM_Pos) // 0x01000000 #endif /******************** Bit definition for GRXFSIZ register ********************/ #define GRXFSIZ_RXFD_Pos (0U) -#define GRXFSIZ_RXFD_Msk (0xFFFFUL << GRXFSIZ_RXFD_Pos) // 0x0000FFFF */ -#define GRXFSIZ_RXFD GRXFSIZ_RXFD_Msk // RxFIFO depth */ +#define GRXFSIZ_RXFD_Msk (0xFFFFUL << GRXFSIZ_RXFD_Pos) // 0x0000FFFF +#define GRXFSIZ_RXFD GRXFSIZ_RXFD_Msk // RxFIFO depth /******************** Bit definition for DVBUSDIS register ********************/ #define DVBUSDIS_VBUSDT_Pos (0U) -#define DVBUSDIS_VBUSDT_Msk (0xFFFFUL << DVBUSDIS_VBUSDT_Pos) // 0x0000FFFF */ -#define DVBUSDIS_VBUSDT DVBUSDIS_VBUSDT_Msk // Device VBUS discharge time */ +#define DVBUSDIS_VBUSDT_Msk (0xFFFFUL << DVBUSDIS_VBUSDT_Pos) // 0x0000FFFF +#define DVBUSDIS_VBUSDT DVBUSDIS_VBUSDT_Msk // Device VBUS discharge time /******************** Bit definition for OTG register ********************/ #define GNPTXFSIZ_NPTXFSA_Pos (0U) -#define GNPTXFSIZ_NPTXFSA_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFSA_Pos) // 0x0000FFFF */ -#define GNPTXFSIZ_NPTXFSA GNPTXFSIZ_NPTXFSA_Msk // Nonperiodic transmit RAM start address */ +#define GNPTXFSIZ_NPTXFSA_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFSA_Pos) // 0x0000FFFF +#define GNPTXFSIZ_NPTXFSA GNPTXFSIZ_NPTXFSA_Msk // Nonperiodic transmit RAM start address #define GNPTXFSIZ_NPTXFD_Pos (16U) -#define GNPTXFSIZ_NPTXFD_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFD_Pos) // 0xFFFF0000 */ -#define GNPTXFSIZ_NPTXFD GNPTXFSIZ_NPTXFD_Msk // Nonperiodic TxFIFO depth */ +#define GNPTXFSIZ_NPTXFD_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFD_Pos) // 0xFFFF0000 +#define GNPTXFSIZ_NPTXFD GNPTXFSIZ_NPTXFD_Msk // Nonperiodic TxFIFO depth #define DIEPTXF0_TX0FSA_Pos (0U) -#define DIEPTXF0_TX0FSA_Msk (0xFFFFUL << DIEPTXF0_TX0FSA_Pos) // 0x0000FFFF */ -#define DIEPTXF0_TX0FSA DIEPTXF0_TX0FSA_Msk // Endpoint 0 transmit RAM start address */ +#define DIEPTXF0_TX0FSA_Msk (0xFFFFUL << DIEPTXF0_TX0FSA_Pos) // 0x0000FFFF +#define DIEPTXF0_TX0FSA DIEPTXF0_TX0FSA_Msk // Endpoint 0 transmit RAM start address #define DIEPTXF0_TX0FD_Pos (16U) -#define DIEPTXF0_TX0FD_Msk (0xFFFFUL << DIEPTXF0_TX0FD_Pos) // 0xFFFF0000 */ -#define DIEPTXF0_TX0FD DIEPTXF0_TX0FD_Msk // Endpoint 0 TxFIFO depth */ +#define DIEPTXF0_TX0FD_Msk (0xFFFFUL << DIEPTXF0_TX0FD_Pos) // 0xFFFF0000 +#define DIEPTXF0_TX0FD DIEPTXF0_TX0FD_Msk // Endpoint 0 TxFIFO depth /******************** Bit definition for DVBUSPULSE register ********************/ #define DVBUSPULSE_DVBUSP_Pos (0U) -#define DVBUSPULSE_DVBUSP_Msk (0xFFFUL << DVBUSPULSE_DVBUSP_Pos) // 0x00000FFF */ -#define DVBUSPULSE_DVBUSP DVBUSPULSE_DVBUSP_Msk // Device VBUS pulsing time */ +#define DVBUSPULSE_DVBUSP_Msk (0xFFFUL << DVBUSPULSE_DVBUSP_Pos) // 0x00000FFF +#define DVBUSPULSE_DVBUSP DVBUSPULSE_DVBUSP_Msk // Device VBUS pulsing time /******************** Bit definition for GNPTXSTS register ********************/ #define GNPTXSTS_NPTXFSAV_Pos (0U) -#define GNPTXSTS_NPTXFSAV_Msk (0xFFFFUL << GNPTXSTS_NPTXFSAV_Pos) // 0x0000FFFF */ -#define GNPTXSTS_NPTXFSAV GNPTXSTS_NPTXFSAV_Msk // Nonperiodic TxFIFO space available */ +#define GNPTXSTS_NPTXFSAV_Msk (0xFFFFUL << GNPTXSTS_NPTXFSAV_Pos) // 0x0000FFFF +#define GNPTXSTS_NPTXFSAV GNPTXSTS_NPTXFSAV_Msk // Nonperiodic TxFIFO space available #define GNPTXSTS_NPTQXSAV_Pos (16U) -#define GNPTXSTS_NPTQXSAV_Msk (0xFFUL << GNPTXSTS_NPTQXSAV_Pos) // 0x00FF0000 */ -#define GNPTXSTS_NPTQXSAV GNPTXSTS_NPTQXSAV_Msk // Nonperiodic transmit request queue space available */ -#define GNPTXSTS_NPTQXSAV_0 (0x01UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00010000 */ -#define GNPTXSTS_NPTQXSAV_1 (0x02UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00020000 */ -#define GNPTXSTS_NPTQXSAV_2 (0x04UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00040000 */ -#define GNPTXSTS_NPTQXSAV_3 (0x08UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00080000 */ -#define GNPTXSTS_NPTQXSAV_4 (0x10UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00100000 */ -#define GNPTXSTS_NPTQXSAV_5 (0x20UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00200000 */ -#define GNPTXSTS_NPTQXSAV_6 (0x40UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00400000 */ -#define GNPTXSTS_NPTQXSAV_7 (0x80UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00800000 */ +#define GNPTXSTS_NPTQXSAV_Msk (0xFFUL << GNPTXSTS_NPTQXSAV_Pos) // 0x00FF0000 +#define GNPTXSTS_NPTQXSAV GNPTXSTS_NPTQXSAV_Msk // Nonperiodic transmit request queue space available +#define GNPTXSTS_NPTQXSAV_0 (0x01UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00010000 +#define GNPTXSTS_NPTQXSAV_1 (0x02UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00020000 +#define GNPTXSTS_NPTQXSAV_2 (0x04UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00040000 +#define GNPTXSTS_NPTQXSAV_3 (0x08UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00080000 +#define GNPTXSTS_NPTQXSAV_4 (0x10UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00100000 +#define GNPTXSTS_NPTQXSAV_5 (0x20UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00200000 +#define GNPTXSTS_NPTQXSAV_6 (0x40UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00400000 +#define GNPTXSTS_NPTQXSAV_7 (0x80UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00800000 #define GNPTXSTS_NPTXQTOP_Pos (24U) -#define GNPTXSTS_NPTXQTOP_Msk (0x7FUL << GNPTXSTS_NPTXQTOP_Pos) // 0x7F000000 */ -#define GNPTXSTS_NPTXQTOP GNPTXSTS_NPTXQTOP_Msk // Top of the nonperiodic transmit request queue */ -#define GNPTXSTS_NPTXQTOP_0 (0x01UL << GNPTXSTS_NPTXQTOP_Pos) // 0x01000000 */ -#define GNPTXSTS_NPTXQTOP_1 (0x02UL << GNPTXSTS_NPTXQTOP_Pos) // 0x02000000 */ -#define GNPTXSTS_NPTXQTOP_2 (0x04UL << GNPTXSTS_NPTXQTOP_Pos) // 0x04000000 */ -#define GNPTXSTS_NPTXQTOP_3 (0x08UL << GNPTXSTS_NPTXQTOP_Pos) // 0x08000000 */ -#define GNPTXSTS_NPTXQTOP_4 (0x10UL << GNPTXSTS_NPTXQTOP_Pos) // 0x10000000 */ -#define GNPTXSTS_NPTXQTOP_5 (0x20UL << GNPTXSTS_NPTXQTOP_Pos) // 0x20000000 */ -#define GNPTXSTS_NPTXQTOP_6 (0x40UL << GNPTXSTS_NPTXQTOP_Pos) // 0x40000000 */ +#define GNPTXSTS_NPTXQTOP_Msk (0x7FUL << GNPTXSTS_NPTXQTOP_Pos) // 0x7F000000 +#define GNPTXSTS_NPTXQTOP GNPTXSTS_NPTXQTOP_Msk // Top of the nonperiodic transmit request queue +#define GNPTXSTS_NPTXQTOP_0 (0x01UL << GNPTXSTS_NPTXQTOP_Pos) // 0x01000000 +#define GNPTXSTS_NPTXQTOP_1 (0x02UL << GNPTXSTS_NPTXQTOP_Pos) // 0x02000000 +#define GNPTXSTS_NPTXQTOP_2 (0x04UL << GNPTXSTS_NPTXQTOP_Pos) // 0x04000000 +#define GNPTXSTS_NPTXQTOP_3 (0x08UL << GNPTXSTS_NPTXQTOP_Pos) // 0x08000000 +#define GNPTXSTS_NPTXQTOP_4 (0x10UL << GNPTXSTS_NPTXQTOP_Pos) // 0x10000000 +#define GNPTXSTS_NPTXQTOP_5 (0x20UL << GNPTXSTS_NPTXQTOP_Pos) // 0x20000000 +#define GNPTXSTS_NPTXQTOP_6 (0x40UL << GNPTXSTS_NPTXQTOP_Pos) // 0x40000000 /******************** Bit definition for DTHRCTL register ********************/ #define DTHRCTL_NONISOTHREN_Pos (0U) -#define DTHRCTL_NONISOTHREN_Msk (0x1UL << DTHRCTL_NONISOTHREN_Pos) // 0x00000001 */ -#define DTHRCTL_NONISOTHREN DTHRCTL_NONISOTHREN_Msk // Nonisochronous IN endpoints threshold enable */ +#define DTHRCTL_NONISOTHREN_Msk (0x1UL << DTHRCTL_NONISOTHREN_Pos) // 0x00000001 +#define DTHRCTL_NONISOTHREN DTHRCTL_NONISOTHREN_Msk // Nonisochronous IN endpoints threshold enable #define DTHRCTL_ISOTHREN_Pos (1U) -#define DTHRCTL_ISOTHREN_Msk (0x1UL << DTHRCTL_ISOTHREN_Pos) // 0x00000002 */ -#define DTHRCTL_ISOTHREN DTHRCTL_ISOTHREN_Msk // ISO IN endpoint threshold enable */ +#define DTHRCTL_ISOTHREN_Msk (0x1UL << DTHRCTL_ISOTHREN_Pos) // 0x00000002 +#define DTHRCTL_ISOTHREN DTHRCTL_ISOTHREN_Msk // ISO IN endpoint threshold enable #define DTHRCTL_TXTHRLEN_Pos (2U) -#define DTHRCTL_TXTHRLEN_Msk (0x1FFUL << DTHRCTL_TXTHRLEN_Pos) // 0x000007FC */ -#define DTHRCTL_TXTHRLEN DTHRCTL_TXTHRLEN_Msk // Transmit threshold length */ -#define DTHRCTL_TXTHRLEN_0 (0x001UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000004 */ -#define DTHRCTL_TXTHRLEN_1 (0x002UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000008 */ -#define DTHRCTL_TXTHRLEN_2 (0x004UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000010 */ -#define DTHRCTL_TXTHRLEN_3 (0x008UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000020 */ -#define DTHRCTL_TXTHRLEN_4 (0x010UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000040 */ -#define DTHRCTL_TXTHRLEN_5 (0x020UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000080 */ -#define DTHRCTL_TXTHRLEN_6 (0x040UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000100 */ -#define DTHRCTL_TXTHRLEN_7 (0x080UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000200 */ -#define DTHRCTL_TXTHRLEN_8 (0x100UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000400 */ +#define DTHRCTL_TXTHRLEN_Msk (0x1FFUL << DTHRCTL_TXTHRLEN_Pos) // 0x000007FC +#define DTHRCTL_TXTHRLEN DTHRCTL_TXTHRLEN_Msk // Transmit threshold length +#define DTHRCTL_TXTHRLEN_0 (0x001UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000004 +#define DTHRCTL_TXTHRLEN_1 (0x002UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000008 +#define DTHRCTL_TXTHRLEN_2 (0x004UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000010 +#define DTHRCTL_TXTHRLEN_3 (0x008UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000020 +#define DTHRCTL_TXTHRLEN_4 (0x010UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000040 +#define DTHRCTL_TXTHRLEN_5 (0x020UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000080 +#define DTHRCTL_TXTHRLEN_6 (0x040UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000100 +#define DTHRCTL_TXTHRLEN_7 (0x080UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000200 +#define DTHRCTL_TXTHRLEN_8 (0x100UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000400 #define DTHRCTL_RXTHREN_Pos (16U) -#define DTHRCTL_RXTHREN_Msk (0x1UL << DTHRCTL_RXTHREN_Pos) // 0x00010000 */ -#define DTHRCTL_RXTHREN DTHRCTL_RXTHREN_Msk // Receive threshold enable */ +#define DTHRCTL_RXTHREN_Msk (0x1UL << DTHRCTL_RXTHREN_Pos) // 0x00010000 +#define DTHRCTL_RXTHREN DTHRCTL_RXTHREN_Msk // Receive threshold enable #define DTHRCTL_RXTHRLEN_Pos (17U) -#define DTHRCTL_RXTHRLEN_Msk (0x1FFUL << DTHRCTL_RXTHRLEN_Pos) // 0x03FE0000 */ -#define DTHRCTL_RXTHRLEN DTHRCTL_RXTHRLEN_Msk // Receive threshold length */ -#define DTHRCTL_RXTHRLEN_0 (0x001UL << DTHRCTL_RXTHRLEN_Pos) // 0x00020000 */ -#define DTHRCTL_RXTHRLEN_1 (0x002UL << DTHRCTL_RXTHRLEN_Pos) // 0x00040000 */ -#define DTHRCTL_RXTHRLEN_2 (0x004UL << DTHRCTL_RXTHRLEN_Pos) // 0x00080000 */ -#define DTHRCTL_RXTHRLEN_3 (0x008UL << DTHRCTL_RXTHRLEN_Pos) // 0x00100000 */ -#define DTHRCTL_RXTHRLEN_4 (0x010UL << DTHRCTL_RXTHRLEN_Pos) // 0x00200000 */ -#define DTHRCTL_RXTHRLEN_5 (0x020UL << DTHRCTL_RXTHRLEN_Pos) // 0x00400000 */ -#define DTHRCTL_RXTHRLEN_6 (0x040UL << DTHRCTL_RXTHRLEN_Pos) // 0x00800000 */ -#define DTHRCTL_RXTHRLEN_7 (0x080UL << DTHRCTL_RXTHRLEN_Pos) // 0x01000000 */ -#define DTHRCTL_RXTHRLEN_8 (0x100UL << DTHRCTL_RXTHRLEN_Pos) // 0x02000000 */ +#define DTHRCTL_RXTHRLEN_Msk (0x1FFUL << DTHRCTL_RXTHRLEN_Pos) // 0x03FE0000 +#define DTHRCTL_RXTHRLEN DTHRCTL_RXTHRLEN_Msk // Receive threshold length +#define DTHRCTL_RXTHRLEN_0 (0x001UL << DTHRCTL_RXTHRLEN_Pos) // 0x00020000 +#define DTHRCTL_RXTHRLEN_1 (0x002UL << DTHRCTL_RXTHRLEN_Pos) // 0x00040000 +#define DTHRCTL_RXTHRLEN_2 (0x004UL << DTHRCTL_RXTHRLEN_Pos) // 0x00080000 +#define DTHRCTL_RXTHRLEN_3 (0x008UL << DTHRCTL_RXTHRLEN_Pos) // 0x00100000 +#define DTHRCTL_RXTHRLEN_4 (0x010UL << DTHRCTL_RXTHRLEN_Pos) // 0x00200000 +#define DTHRCTL_RXTHRLEN_5 (0x020UL << DTHRCTL_RXTHRLEN_Pos) // 0x00400000 +#define DTHRCTL_RXTHRLEN_6 (0x040UL << DTHRCTL_RXTHRLEN_Pos) // 0x00800000 +#define DTHRCTL_RXTHRLEN_7 (0x080UL << DTHRCTL_RXTHRLEN_Pos) // 0x01000000 +#define DTHRCTL_RXTHRLEN_8 (0x100UL << DTHRCTL_RXTHRLEN_Pos) // 0x02000000 #define DTHRCTL_ARPEN_Pos (27U) -#define DTHRCTL_ARPEN_Msk (0x1UL << DTHRCTL_ARPEN_Pos) // 0x08000000 */ -#define DTHRCTL_ARPEN DTHRCTL_ARPEN_Msk // Arbiter parking enable */ +#define DTHRCTL_ARPEN_Msk (0x1UL << DTHRCTL_ARPEN_Pos) // 0x08000000 +#define DTHRCTL_ARPEN DTHRCTL_ARPEN_Msk // Arbiter parking enable /******************** Bit definition for DIEPEMPMSK register ********************/ #define DIEPEMPMSK_INEPTXFEM_Pos (0U) -#define DIEPEMPMSK_INEPTXFEM_Msk (0xFFFFUL << DIEPEMPMSK_INEPTXFEM_Pos) // 0x0000FFFF */ -#define DIEPEMPMSK_INEPTXFEM DIEPEMPMSK_INEPTXFEM_Msk // IN EP Tx FIFO empty interrupt mask bits */ +#define DIEPEMPMSK_INEPTXFEM_Msk (0xFFFFUL << DIEPEMPMSK_INEPTXFEM_Pos) // 0x0000FFFF +#define DIEPEMPMSK_INEPTXFEM DIEPEMPMSK_INEPTXFEM_Msk // IN EP Tx FIFO empty interrupt mask bits /******************** Bit definition for DEACHINT register ********************/ #define DEACHINT_IEP1INT_Pos (1U) -#define DEACHINT_IEP1INT_Msk (0x1UL << DEACHINT_IEP1INT_Pos) // 0x00000002 */ -#define DEACHINT_IEP1INT DEACHINT_IEP1INT_Msk // IN endpoint 1interrupt bit */ +#define DEACHINT_IEP1INT_Msk (0x1UL << DEACHINT_IEP1INT_Pos) // 0x00000002 +#define DEACHINT_IEP1INT DEACHINT_IEP1INT_Msk // IN endpoint 1interrupt bit #define DEACHINT_OEP1INT_Pos (17U) -#define DEACHINT_OEP1INT_Msk (0x1UL << DEACHINT_OEP1INT_Pos) // 0x00020000 */ -#define DEACHINT_OEP1INT DEACHINT_OEP1INT_Msk // OUT endpoint 1 interrupt bit */ +#define DEACHINT_OEP1INT_Msk (0x1UL << DEACHINT_OEP1INT_Pos) // 0x00020000 +#define DEACHINT_OEP1INT DEACHINT_OEP1INT_Msk // OUT endpoint 1 interrupt bit /******************** Bit definition for GCCFG register ********************/ #define STM32_GCCFG_DCDET_Pos (0U) -#define STM32_GCCFG_DCDET_Msk (0x1UL << STM32_GCCFG_DCDET_Pos) // 0x00000001 */ -#define STM32_GCCFG_DCDET STM32_GCCFG_DCDET_Msk // Data contact detection (DCD) status */ +#define STM32_GCCFG_DCDET_Msk (0x1UL << STM32_GCCFG_DCDET_Pos) // 0x00000001 +#define STM32_GCCFG_DCDET STM32_GCCFG_DCDET_Msk // Data contact detection (DCD) status + #define STM32_GCCFG_PDET_Pos (1U) -#define STM32_GCCFG_PDET_Msk (0x1UL << STM32_GCCFG_PDET_Pos) // 0x00000002 */ -#define STM32_GCCFG_PDET STM32_GCCFG_PDET_Msk // Primary detection (PD) status */ +#define STM32_GCCFG_PDET_Msk (0x1UL << STM32_GCCFG_PDET_Pos) // 0x00000002 +#define STM32_GCCFG_PDET STM32_GCCFG_PDET_Msk // Primary detection (PD) status + #define STM32_GCCFG_SDET_Pos (2U) -#define STM32_GCCFG_SDET_Msk (0x1UL << STM32_GCCFG_SDET_Pos) // 0x00000004 */ -#define STM32_GCCFG_SDET STM32_GCCFG_SDET_Msk // Secondary detection (SD) status */ +#define STM32_GCCFG_SDET_Msk (0x1UL << STM32_GCCFG_SDET_Pos) // 0x00000004 +#define STM32_GCCFG_SDET STM32_GCCFG_SDET_Msk // Secondary detection (SD) status + #define STM32_GCCFG_PS2DET_Pos (3U) -#define STM32_GCCFG_PS2DET_Msk (0x1UL << STM32_GCCFG_PS2DET_Pos) // 0x00000008 */ -#define STM32_GCCFG_PS2DET STM32_GCCFG_PS2DET_Msk // DM pull-up detection status */ +#define STM32_GCCFG_PS2DET_Msk (0x1UL << STM32_GCCFG_PS2DET_Pos) // 0x00000008 +#define STM32_GCCFG_PS2DET STM32_GCCFG_PS2DET_Msk // DM pull-up detection status + #define STM32_GCCFG_PWRDWN_Pos (16U) -#define STM32_GCCFG_PWRDWN_Msk (0x1UL << STM32_GCCFG_PWRDWN_Pos) // 0x00010000 */ -#define STM32_GCCFG_PWRDWN STM32_GCCFG_PWRDWN_Msk // Power down */ +#define STM32_GCCFG_PWRDWN_Msk (0x1UL << STM32_GCCFG_PWRDWN_Pos) // 0x00010000 +#define STM32_GCCFG_PWRDWN STM32_GCCFG_PWRDWN_Msk // Power down + #define STM32_GCCFG_BCDEN_Pos (17U) -#define STM32_GCCFG_BCDEN_Msk (0x1UL << STM32_GCCFG_BCDEN_Pos) // 0x00020000 */ -#define STM32_GCCFG_BCDEN STM32_GCCFG_BCDEN_Msk // Battery charging detector (BCD) enable */ +#define STM32_GCCFG_BCDEN_Msk (0x1UL << STM32_GCCFG_BCDEN_Pos) // 0x00020000 +#define STM32_GCCFG_BCDEN STM32_GCCFG_BCDEN_Msk // Battery charging detector (BCD) enable + #define STM32_GCCFG_DCDEN_Pos (18U) -#define STM32_GCCFG_DCDEN_Msk (0x1UL << STM32_GCCFG_DCDEN_Pos) // 0x00040000 */ +#define STM32_GCCFG_DCDEN_Msk (0x1UL << STM32_GCCFG_DCDEN_Pos) // 0x00040000 #define STM32_GCCFG_DCDEN STM32_GCCFG_DCDEN_Msk // Data contact detection (DCD) mode enable*/ + #define STM32_GCCFG_PDEN_Pos (19U) -#define STM32_GCCFG_PDEN_Msk (0x1UL << STM32_GCCFG_PDEN_Pos) // 0x00080000 */ +#define STM32_GCCFG_PDEN_Msk (0x1UL << STM32_GCCFG_PDEN_Pos) // 0x00080000 #define STM32_GCCFG_PDEN STM32_GCCFG_PDEN_Msk // Primary detection (PD) mode enable*/ + #define STM32_GCCFG_SDEN_Pos (20U) -#define STM32_GCCFG_SDEN_Msk (0x1UL << STM32_GCCFG_SDEN_Pos) // 0x00100000 */ -#define STM32_GCCFG_SDEN STM32_GCCFG_SDEN_Msk // Secondary detection (SD) mode enable */ +#define STM32_GCCFG_SDEN_Msk (0x1UL << STM32_GCCFG_SDEN_Pos) // 0x00100000 +#define STM32_GCCFG_SDEN STM32_GCCFG_SDEN_Msk // Secondary detection (SD) mode enable + #define STM32_GCCFG_VBDEN_Pos (21U) -#define STM32_GCCFG_VBDEN_Msk (0x1UL << STM32_GCCFG_VBDEN_Pos) // 0x00200000 */ -#define STM32_GCCFG_VBDEN STM32_GCCFG_VBDEN_Msk // VBUS mode enable */ +#define STM32_GCCFG_VBDEN_Msk (0x1UL << STM32_GCCFG_VBDEN_Pos) // 0x00200000 +#define STM32_GCCFG_VBDEN STM32_GCCFG_VBDEN_Msk // VBUS mode enable + #define STM32_GCCFG_OTGIDEN_Pos (22U) -#define STM32_GCCFG_OTGIDEN_Msk (0x1UL << STM32_GCCFG_OTGIDEN_Pos) // 0x00400000 */ -#define STM32_GCCFG_OTGIDEN STM32_GCCFG_OTGIDEN_Msk // OTG Id enable */ +#define STM32_GCCFG_OTGIDEN_Msk (0x1UL << STM32_GCCFG_OTGIDEN_Pos) // 0x00400000 +#define STM32_GCCFG_OTGIDEN STM32_GCCFG_OTGIDEN_Msk // OTG Id enable + #define STM32_GCCFG_PHYHSEN_Pos (23U) -#define STM32_GCCFG_PHYHSEN_Msk (0x1UL << STM32_GCCFG_PHYHSEN_Pos) // 0x00800000 */ -#define STM32_GCCFG_PHYHSEN STM32_GCCFG_PHYHSEN_Msk // HS PHY enable */ +#define STM32_GCCFG_PHYHSEN_Msk (0x1UL << STM32_GCCFG_PHYHSEN_Pos) // 0x00800000 +#define STM32_GCCFG_PHYHSEN STM32_GCCFG_PHYHSEN_Msk // HS PHY enable + +// TODO stm32u5a5 SDEN is 22nd bit, conflict with 20th bit above +//#define STM32_GCCFG_SDEN_Pos (22U) +//#define STM32_GCCFG_SDEN_Msk (0x1U << STM32_GCCFG_SDEN_Pos) // 0x00400000 +//#define STM32_GCCFG_SDEN STM32_GCCFG_SDEN_Msk // Secondary detection (PD) mode enable + +// TODO stm32u5a5 VBVALOVA is 23rd bit, conflict with PHYHSEN bit above +#define STM32_GCCFG_VBVALOVAL_Pos (23U) +#define STM32_GCCFG_VBVALOVAL_Msk (0x1U << STM32_GCCFG_VBVALOVAL_Pos) // 0x00800000 +#define STM32_GCCFG_VBVALOVAL STM32_GCCFG_VBVALOVAL_Msk // Value of VBUSVLDEXT0 femtoPHY input + +#define STM32_GCCFG_VBVALEXTOEN_Pos (24U) +#define STM32_GCCFG_VBVALEXTOEN_Msk (0x1U << STM32_GCCFG_VBVALEXTOEN_Pos) // 0x01000000 +#define STM32_GCCFG_VBVALEXTOEN STM32_GCCFG_VBVALEXTOEN_Msk // Enables of VBUSVLDEXT0 femtoPHY input override + +#define STM32_GCCFG_PULLDOWNEN_Pos (25U) +#define STM32_GCCFG_PULLDOWNEN_Msk (0x1U << STM32_GCCFG_PULLDOWNEN_Pos) // 0x02000000 +#define STM32_GCCFG_PULLDOWNEN STM32_GCCFG_PULLDOWNEN_Msk // Enables of femtoPHY pulldown resistors, used when ID PAD is disabled + /******************** Bit definition for DEACHINTMSK register ********************/ #define DEACHINTMSK_IEP1INTM_Pos (1U) -#define DEACHINTMSK_IEP1INTM_Msk (0x1UL << DEACHINTMSK_IEP1INTM_Pos) // 0x00000002 */ -#define DEACHINTMSK_IEP1INTM DEACHINTMSK_IEP1INTM_Msk // IN Endpoint 1 interrupt mask bit */ +#define DEACHINTMSK_IEP1INTM_Msk (0x1UL << DEACHINTMSK_IEP1INTM_Pos) // 0x00000002 +#define DEACHINTMSK_IEP1INTM DEACHINTMSK_IEP1INTM_Msk // IN Endpoint 1 interrupt mask bit #define DEACHINTMSK_OEP1INTM_Pos (17U) -#define DEACHINTMSK_OEP1INTM_Msk (0x1UL << DEACHINTMSK_OEP1INTM_Pos) // 0x00020000 */ -#define DEACHINTMSK_OEP1INTM DEACHINTMSK_OEP1INTM_Msk // OUT Endpoint 1 interrupt mask bit */ +#define DEACHINTMSK_OEP1INTM_Msk (0x1UL << DEACHINTMSK_OEP1INTM_Pos) // 0x00020000 +#define DEACHINTMSK_OEP1INTM DEACHINTMSK_OEP1INTM_Msk // OUT Endpoint 1 interrupt mask bit /******************** Bit definition for CID register ********************/ #define CID_PRODUCT_ID_Pos (0U) -#define CID_PRODUCT_ID_Msk (0xFFFFFFFFUL << CID_PRODUCT_ID_Pos) // 0xFFFFFFFF */ -#define CID_PRODUCT_ID CID_PRODUCT_ID_Msk // Product ID field */ +#define CID_PRODUCT_ID_Msk (0xFFFFFFFFUL << CID_PRODUCT_ID_Pos) // 0xFFFFFFFF +#define CID_PRODUCT_ID CID_PRODUCT_ID_Msk // Product ID field /******************** Bit definition for GLPMCFG register ********************/ #define GLPMCFG_LPMEN_Pos (0U) -#define GLPMCFG_LPMEN_Msk (0x1UL << GLPMCFG_LPMEN_Pos) // 0x00000001 */ -#define GLPMCFG_LPMEN GLPMCFG_LPMEN_Msk // LPM support enable */ +#define GLPMCFG_LPMEN_Msk (0x1UL << GLPMCFG_LPMEN_Pos) // 0x00000001 +#define GLPMCFG_LPMEN GLPMCFG_LPMEN_Msk // LPM support enable #define GLPMCFG_LPMACK_Pos (1U) -#define GLPMCFG_LPMACK_Msk (0x1UL << GLPMCFG_LPMACK_Pos) // 0x00000002 */ -#define GLPMCFG_LPMACK GLPMCFG_LPMACK_Msk // LPM Token acknowledge enable */ +#define GLPMCFG_LPMACK_Msk (0x1UL << GLPMCFG_LPMACK_Pos) // 0x00000002 +#define GLPMCFG_LPMACK GLPMCFG_LPMACK_Msk // LPM Token acknowledge enable #define GLPMCFG_BESL_Pos (2U) -#define GLPMCFG_BESL_Msk (0xFUL << GLPMCFG_BESL_Pos) // 0x0000003C */ -#define GLPMCFG_BESL GLPMCFG_BESL_Msk // BESL value received with last ACKed LPM Token */ +#define GLPMCFG_BESL_Msk (0xFUL << GLPMCFG_BESL_Pos) // 0x0000003C +#define GLPMCFG_BESL GLPMCFG_BESL_Msk // BESL value received with last ACKed LPM Token #define GLPMCFG_REMWAKE_Pos (6U) -#define GLPMCFG_REMWAKE_Msk (0x1UL << GLPMCFG_REMWAKE_Pos) // 0x00000040 */ -#define GLPMCFG_REMWAKE GLPMCFG_REMWAKE_Msk // bRemoteWake value received with last ACKed LPM Token */ +#define GLPMCFG_REMWAKE_Msk (0x1UL << GLPMCFG_REMWAKE_Pos) // 0x00000040 +#define GLPMCFG_REMWAKE GLPMCFG_REMWAKE_Msk // bRemoteWake value received with last ACKed LPM Token #define GLPMCFG_L1SSEN_Pos (7U) -#define GLPMCFG_L1SSEN_Msk (0x1UL << GLPMCFG_L1SSEN_Pos) // 0x00000080 */ -#define GLPMCFG_L1SSEN GLPMCFG_L1SSEN_Msk // L1 shallow sleep enable */ +#define GLPMCFG_L1SSEN_Msk (0x1UL << GLPMCFG_L1SSEN_Pos) // 0x00000080 +#define GLPMCFG_L1SSEN GLPMCFG_L1SSEN_Msk // L1 shallow sleep enable #define GLPMCFG_BESLTHRS_Pos (8U) -#define GLPMCFG_BESLTHRS_Msk (0xFUL << GLPMCFG_BESLTHRS_Pos) // 0x00000F00 */ -#define GLPMCFG_BESLTHRS GLPMCFG_BESLTHRS_Msk // BESL threshold */ +#define GLPMCFG_BESLTHRS_Msk (0xFUL << GLPMCFG_BESLTHRS_Pos) // 0x00000F00 +#define GLPMCFG_BESLTHRS GLPMCFG_BESLTHRS_Msk // BESL threshold #define GLPMCFG_L1DSEN_Pos (12U) -#define GLPMCFG_L1DSEN_Msk (0x1UL << GLPMCFG_L1DSEN_Pos) // 0x00001000 */ -#define GLPMCFG_L1DSEN GLPMCFG_L1DSEN_Msk // L1 deep sleep enable */ +#define GLPMCFG_L1DSEN_Msk (0x1UL << GLPMCFG_L1DSEN_Pos) // 0x00001000 +#define GLPMCFG_L1DSEN GLPMCFG_L1DSEN_Msk // L1 deep sleep enable #define GLPMCFG_LPMRSP_Pos (13U) -#define GLPMCFG_LPMRSP_Msk (0x3UL << GLPMCFG_LPMRSP_Pos) // 0x00006000 */ -#define GLPMCFG_LPMRSP GLPMCFG_LPMRSP_Msk // LPM response */ +#define GLPMCFG_LPMRSP_Msk (0x3UL << GLPMCFG_LPMRSP_Pos) // 0x00006000 +#define GLPMCFG_LPMRSP GLPMCFG_LPMRSP_Msk // LPM response #define GLPMCFG_SLPSTS_Pos (15U) -#define GLPMCFG_SLPSTS_Msk (0x1UL << GLPMCFG_SLPSTS_Pos) // 0x00008000 */ -#define GLPMCFG_SLPSTS GLPMCFG_SLPSTS_Msk // Port sleep status */ +#define GLPMCFG_SLPSTS_Msk (0x1UL << GLPMCFG_SLPSTS_Pos) // 0x00008000 +#define GLPMCFG_SLPSTS GLPMCFG_SLPSTS_Msk // Port sleep status #define GLPMCFG_L1RSMOK_Pos (16U) -#define GLPMCFG_L1RSMOK_Msk (0x1UL << GLPMCFG_L1RSMOK_Pos) // 0x00010000 */ -#define GLPMCFG_L1RSMOK GLPMCFG_L1RSMOK_Msk // Sleep State Resume OK */ +#define GLPMCFG_L1RSMOK_Msk (0x1UL << GLPMCFG_L1RSMOK_Pos) // 0x00010000 +#define GLPMCFG_L1RSMOK GLPMCFG_L1RSMOK_Msk // Sleep State Resume OK #define GLPMCFG_LPMCHIDX_Pos (17U) -#define GLPMCFG_LPMCHIDX_Msk (0xFUL << GLPMCFG_LPMCHIDX_Pos) // 0x001E0000 */ -#define GLPMCFG_LPMCHIDX GLPMCFG_LPMCHIDX_Msk // LPM Channel Index */ +#define GLPMCFG_LPMCHIDX_Msk (0xFUL << GLPMCFG_LPMCHIDX_Pos) // 0x001E0000 +#define GLPMCFG_LPMCHIDX GLPMCFG_LPMCHIDX_Msk // LPM Channel Index #define GLPMCFG_LPMRCNT_Pos (21U) -#define GLPMCFG_LPMRCNT_Msk (0x7UL << GLPMCFG_LPMRCNT_Pos) // 0x00E00000 */ -#define GLPMCFG_LPMRCNT GLPMCFG_LPMRCNT_Msk // LPM retry count */ +#define GLPMCFG_LPMRCNT_Msk (0x7UL << GLPMCFG_LPMRCNT_Pos) // 0x00E00000 +#define GLPMCFG_LPMRCNT GLPMCFG_LPMRCNT_Msk // LPM retry count #define GLPMCFG_SNDLPM_Pos (24U) -#define GLPMCFG_SNDLPM_Msk (0x1UL << GLPMCFG_SNDLPM_Pos) // 0x01000000 */ -#define GLPMCFG_SNDLPM GLPMCFG_SNDLPM_Msk // Send LPM transaction */ +#define GLPMCFG_SNDLPM_Msk (0x1UL << GLPMCFG_SNDLPM_Pos) // 0x01000000 +#define GLPMCFG_SNDLPM GLPMCFG_SNDLPM_Msk // Send LPM transaction #define GLPMCFG_LPMRCNTSTS_Pos (25U) -#define GLPMCFG_LPMRCNTSTS_Msk (0x7UL << GLPMCFG_LPMRCNTSTS_Pos) // 0x0E000000 */ -#define GLPMCFG_LPMRCNTSTS GLPMCFG_LPMRCNTSTS_Msk // LPM retry count status */ +#define GLPMCFG_LPMRCNTSTS_Msk (0x7UL << GLPMCFG_LPMRCNTSTS_Pos) // 0x0E000000 +#define GLPMCFG_LPMRCNTSTS GLPMCFG_LPMRCNTSTS_Msk // LPM retry count status #define GLPMCFG_ENBESL_Pos (28U) -#define GLPMCFG_ENBESL_Msk (0x1UL << GLPMCFG_ENBESL_Pos) // 0x10000000 */ -#define GLPMCFG_ENBESL GLPMCFG_ENBESL_Msk // Enable best effort service latency */ +#define GLPMCFG_ENBESL_Msk (0x1UL << GLPMCFG_ENBESL_Pos) // 0x10000000 +#define GLPMCFG_ENBESL GLPMCFG_ENBESL_Msk // Enable best effort service latency /******************** Bit definition for DIEPEACHMSK1 register ********************/ #define DIEPEACHMSK1_XFRCM_Pos (0U) -#define DIEPEACHMSK1_XFRCM_Msk (0x1UL << DIEPEACHMSK1_XFRCM_Pos) // 0x00000001 */ -#define DIEPEACHMSK1_XFRCM DIEPEACHMSK1_XFRCM_Msk // Transfer completed interrupt mask */ +#define DIEPEACHMSK1_XFRCM_Msk (0x1UL << DIEPEACHMSK1_XFRCM_Pos) // 0x00000001 +#define DIEPEACHMSK1_XFRCM DIEPEACHMSK1_XFRCM_Msk // Transfer completed interrupt mask #define DIEPEACHMSK1_EPDM_Pos (1U) -#define DIEPEACHMSK1_EPDM_Msk (0x1UL << DIEPEACHMSK1_EPDM_Pos) // 0x00000002 */ -#define DIEPEACHMSK1_EPDM DIEPEACHMSK1_EPDM_Msk // Endpoint disabled interrupt mask */ +#define DIEPEACHMSK1_EPDM_Msk (0x1UL << DIEPEACHMSK1_EPDM_Pos) // 0x00000002 +#define DIEPEACHMSK1_EPDM DIEPEACHMSK1_EPDM_Msk // Endpoint disabled interrupt mask #define DIEPEACHMSK1_TOM_Pos (3U) -#define DIEPEACHMSK1_TOM_Msk (0x1UL << DIEPEACHMSK1_TOM_Pos) // 0x00000008 */ -#define DIEPEACHMSK1_TOM DIEPEACHMSK1_TOM_Msk // Timeout condition mask (nonisochronous endpoints) */ +#define DIEPEACHMSK1_TOM_Msk (0x1UL << DIEPEACHMSK1_TOM_Pos) // 0x00000008 +#define DIEPEACHMSK1_TOM DIEPEACHMSK1_TOM_Msk // Timeout condition mask (nonisochronous endpoints) #define DIEPEACHMSK1_ITTXFEMSK_Pos (4U) -#define DIEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << DIEPEACHMSK1_ITTXFEMSK_Pos) // 0x00000010 */ -#define DIEPEACHMSK1_ITTXFEMSK DIEPEACHMSK1_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask */ +#define DIEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << DIEPEACHMSK1_ITTXFEMSK_Pos) // 0x00000010 +#define DIEPEACHMSK1_ITTXFEMSK DIEPEACHMSK1_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask #define DIEPEACHMSK1_INEPNMM_Pos (5U) -#define DIEPEACHMSK1_INEPNMM_Msk (0x1UL << DIEPEACHMSK1_INEPNMM_Pos) // 0x00000020 */ -#define DIEPEACHMSK1_INEPNMM DIEPEACHMSK1_INEPNMM_Msk // IN token received with EP mismatch mask */ +#define DIEPEACHMSK1_INEPNMM_Msk (0x1UL << DIEPEACHMSK1_INEPNMM_Pos) // 0x00000020 +#define DIEPEACHMSK1_INEPNMM DIEPEACHMSK1_INEPNMM_Msk // IN token received with EP mismatch mask #define DIEPEACHMSK1_INEPNEM_Pos (6U) -#define DIEPEACHMSK1_INEPNEM_Msk (0x1UL << DIEPEACHMSK1_INEPNEM_Pos) // 0x00000040 */ -#define DIEPEACHMSK1_INEPNEM DIEPEACHMSK1_INEPNEM_Msk // IN endpoint NAK effective mask */ +#define DIEPEACHMSK1_INEPNEM_Msk (0x1UL << DIEPEACHMSK1_INEPNEM_Pos) // 0x00000040 +#define DIEPEACHMSK1_INEPNEM DIEPEACHMSK1_INEPNEM_Msk // IN endpoint NAK effective mask #define DIEPEACHMSK1_TXFURM_Pos (8U) -#define DIEPEACHMSK1_TXFURM_Msk (0x1UL << DIEPEACHMSK1_TXFURM_Pos) // 0x00000100 */ -#define DIEPEACHMSK1_TXFURM DIEPEACHMSK1_TXFURM_Msk // FIFO underrun mask */ +#define DIEPEACHMSK1_TXFURM_Msk (0x1UL << DIEPEACHMSK1_TXFURM_Pos) // 0x00000100 +#define DIEPEACHMSK1_TXFURM DIEPEACHMSK1_TXFURM_Msk // FIFO underrun mask #define DIEPEACHMSK1_BIM_Pos (9U) -#define DIEPEACHMSK1_BIM_Msk (0x1UL << DIEPEACHMSK1_BIM_Pos) // 0x00000200 */ -#define DIEPEACHMSK1_BIM DIEPEACHMSK1_BIM_Msk // BNA interrupt mask */ +#define DIEPEACHMSK1_BIM_Msk (0x1UL << DIEPEACHMSK1_BIM_Pos) // 0x00000200 +#define DIEPEACHMSK1_BIM DIEPEACHMSK1_BIM_Msk // BNA interrupt mask #define DIEPEACHMSK1_NAKM_Pos (13U) -#define DIEPEACHMSK1_NAKM_Msk (0x1UL << DIEPEACHMSK1_NAKM_Pos) // 0x00002000 */ -#define DIEPEACHMSK1_NAKM DIEPEACHMSK1_NAKM_Msk // NAK interrupt mask */ +#define DIEPEACHMSK1_NAKM_Msk (0x1UL << DIEPEACHMSK1_NAKM_Pos) // 0x00002000 +#define DIEPEACHMSK1_NAKM DIEPEACHMSK1_NAKM_Msk // NAK interrupt mask /******************** Bit definition for HPRT register ********************/ #define HPRT_PCSTS_Pos (0U) -#define HPRT_PCSTS_Msk (0x1UL << HPRT_PCSTS_Pos) // 0x00000001 */ -#define HPRT_PCSTS HPRT_PCSTS_Msk // Port connect status */ +#define HPRT_PCSTS_Msk (0x1UL << HPRT_PCSTS_Pos) // 0x00000001 +#define HPRT_PCSTS HPRT_PCSTS_Msk // Port connect status #define HPRT_PCDET_Pos (1U) -#define HPRT_PCDET_Msk (0x1UL << HPRT_PCDET_Pos) // 0x00000002 */ -#define HPRT_PCDET HPRT_PCDET_Msk // Port connect detected */ +#define HPRT_PCDET_Msk (0x1UL << HPRT_PCDET_Pos) // 0x00000002 +#define HPRT_PCDET HPRT_PCDET_Msk // Port connect detected #define HPRT_PENA_Pos (2U) -#define HPRT_PENA_Msk (0x1UL << HPRT_PENA_Pos) // 0x00000004 */ -#define HPRT_PENA HPRT_PENA_Msk // Port enable */ +#define HPRT_PENA_Msk (0x1UL << HPRT_PENA_Pos) // 0x00000004 +#define HPRT_PENA HPRT_PENA_Msk // Port enable #define HPRT_PENCHNG_Pos (3U) -#define HPRT_PENCHNG_Msk (0x1UL << HPRT_PENCHNG_Pos) // 0x00000008 */ -#define HPRT_PENCHNG HPRT_PENCHNG_Msk // Port enable/disable change */ +#define HPRT_PENCHNG_Msk (0x1UL << HPRT_PENCHNG_Pos) // 0x00000008 +#define HPRT_PENCHNG HPRT_PENCHNG_Msk // Port enable/disable change #define HPRT_POCA_Pos (4U) -#define HPRT_POCA_Msk (0x1UL << HPRT_POCA_Pos) // 0x00000010 */ -#define HPRT_POCA HPRT_POCA_Msk // Port overcurrent active */ +#define HPRT_POCA_Msk (0x1UL << HPRT_POCA_Pos) // 0x00000010 +#define HPRT_POCA HPRT_POCA_Msk // Port overcurrent active #define HPRT_POCCHNG_Pos (5U) -#define HPRT_POCCHNG_Msk (0x1UL << HPRT_POCCHNG_Pos) // 0x00000020 */ -#define HPRT_POCCHNG HPRT_POCCHNG_Msk // Port overcurrent change */ +#define HPRT_POCCHNG_Msk (0x1UL << HPRT_POCCHNG_Pos) // 0x00000020 +#define HPRT_POCCHNG HPRT_POCCHNG_Msk // Port overcurrent change #define HPRT_PRES_Pos (6U) -#define HPRT_PRES_Msk (0x1UL << HPRT_PRES_Pos) // 0x00000040 */ -#define HPRT_PRES HPRT_PRES_Msk // Port resume */ +#define HPRT_PRES_Msk (0x1UL << HPRT_PRES_Pos) // 0x00000040 +#define HPRT_PRES HPRT_PRES_Msk // Port resume #define HPRT_PSUSP_Pos (7U) -#define HPRT_PSUSP_Msk (0x1UL << HPRT_PSUSP_Pos) // 0x00000080 */ -#define HPRT_PSUSP HPRT_PSUSP_Msk // Port suspend */ +#define HPRT_PSUSP_Msk (0x1UL << HPRT_PSUSP_Pos) // 0x00000080 +#define HPRT_PSUSP HPRT_PSUSP_Msk // Port suspend #define HPRT_PRST_Pos (8U) -#define HPRT_PRST_Msk (0x1UL << HPRT_PRST_Pos) // 0x00000100 */ -#define HPRT_PRST HPRT_PRST_Msk // Port reset */ +#define HPRT_PRST_Msk (0x1UL << HPRT_PRST_Pos) // 0x00000100 +#define HPRT_PRST HPRT_PRST_Msk // Port reset #define HPRT_PLSTS_Pos (10U) -#define HPRT_PLSTS_Msk (0x3UL << HPRT_PLSTS_Pos) // 0x00000C00 */ -#define HPRT_PLSTS HPRT_PLSTS_Msk // Port line status */ -#define HPRT_PLSTS_0 (0x1UL << HPRT_PLSTS_Pos) // 0x00000400 */ -#define HPRT_PLSTS_1 (0x2UL << HPRT_PLSTS_Pos) // 0x00000800 */ +#define HPRT_PLSTS_Msk (0x3UL << HPRT_PLSTS_Pos) // 0x00000C00 +#define HPRT_PLSTS HPRT_PLSTS_Msk // Port line status +#define HPRT_PLSTS_0 (0x1UL << HPRT_PLSTS_Pos) // 0x00000400 +#define HPRT_PLSTS_1 (0x2UL << HPRT_PLSTS_Pos) // 0x00000800 #define HPRT_PPWR_Pos (12U) -#define HPRT_PPWR_Msk (0x1UL << HPRT_PPWR_Pos) // 0x00001000 */ -#define HPRT_PPWR HPRT_PPWR_Msk // Port power */ +#define HPRT_PPWR_Msk (0x1UL << HPRT_PPWR_Pos) // 0x00001000 +#define HPRT_PPWR HPRT_PPWR_Msk // Port power #define HPRT_PTCTL_Pos (13U) -#define HPRT_PTCTL_Msk (0xFUL << HPRT_PTCTL_Pos) // 0x0001E000 */ -#define HPRT_PTCTL HPRT_PTCTL_Msk // Port test control */ -#define HPRT_PTCTL_0 (0x1UL << HPRT_PTCTL_Pos) // 0x00002000 */ -#define HPRT_PTCTL_1 (0x2UL << HPRT_PTCTL_Pos) // 0x00004000 */ -#define HPRT_PTCTL_2 (0x4UL << HPRT_PTCTL_Pos) // 0x00008000 */ -#define HPRT_PTCTL_3 (0x8UL << HPRT_PTCTL_Pos) // 0x00010000 */ +#define HPRT_PTCTL_Msk (0xFUL << HPRT_PTCTL_Pos) // 0x0001E000 +#define HPRT_PTCTL HPRT_PTCTL_Msk // Port test control +#define HPRT_PTCTL_0 (0x1UL << HPRT_PTCTL_Pos) // 0x00002000 +#define HPRT_PTCTL_1 (0x2UL << HPRT_PTCTL_Pos) // 0x00004000 +#define HPRT_PTCTL_2 (0x4UL << HPRT_PTCTL_Pos) // 0x00008000 +#define HPRT_PTCTL_3 (0x8UL << HPRT_PTCTL_Pos) // 0x00010000 #define HPRT_PSPD_Pos (17U) -#define HPRT_PSPD_Msk (0x3UL << HPRT_PSPD_Pos) // 0x00060000 */ -#define HPRT_PSPD HPRT_PSPD_Msk // Port speed */ -#define HPRT_PSPD_0 (0x1UL << HPRT_PSPD_Pos) // 0x00020000 */ -#define HPRT_PSPD_1 (0x2UL << HPRT_PSPD_Pos) // 0x00040000 */ +#define HPRT_PSPD_Msk (0x3UL << HPRT_PSPD_Pos) // 0x00060000 +#define HPRT_PSPD HPRT_PSPD_Msk // Port speed +#define HPRT_PSPD_0 (0x1UL << HPRT_PSPD_Pos) // 0x00020000 +#define HPRT_PSPD_1 (0x2UL << HPRT_PSPD_Pos) // 0x00040000 /******************** Bit definition for DOEPEACHMSK1 register ********************/ #define DOEPEACHMSK1_XFRCM_Pos (0U) -#define DOEPEACHMSK1_XFRCM_Msk (0x1UL << DOEPEACHMSK1_XFRCM_Pos) // 0x00000001 */ -#define DOEPEACHMSK1_XFRCM DOEPEACHMSK1_XFRCM_Msk // Transfer completed interrupt mask */ +#define DOEPEACHMSK1_XFRCM_Msk (0x1UL << DOEPEACHMSK1_XFRCM_Pos) // 0x00000001 +#define DOEPEACHMSK1_XFRCM DOEPEACHMSK1_XFRCM_Msk // Transfer completed interrupt mask #define DOEPEACHMSK1_EPDM_Pos (1U) -#define DOEPEACHMSK1_EPDM_Msk (0x1UL << DOEPEACHMSK1_EPDM_Pos) // 0x00000002 */ -#define DOEPEACHMSK1_EPDM DOEPEACHMSK1_EPDM_Msk // Endpoint disabled interrupt mask */ +#define DOEPEACHMSK1_EPDM_Msk (0x1UL << DOEPEACHMSK1_EPDM_Pos) // 0x00000002 +#define DOEPEACHMSK1_EPDM DOEPEACHMSK1_EPDM_Msk // Endpoint disabled interrupt mask #define DOEPEACHMSK1_TOM_Pos (3U) -#define DOEPEACHMSK1_TOM_Msk (0x1UL << DOEPEACHMSK1_TOM_Pos) // 0x00000008 */ -#define DOEPEACHMSK1_TOM DOEPEACHMSK1_TOM_Msk // Timeout condition mask */ +#define DOEPEACHMSK1_TOM_Msk (0x1UL << DOEPEACHMSK1_TOM_Pos) // 0x00000008 +#define DOEPEACHMSK1_TOM DOEPEACHMSK1_TOM_Msk // Timeout condition mask #define DOEPEACHMSK1_ITTXFEMSK_Pos (4U) -#define DOEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << DOEPEACHMSK1_ITTXFEMSK_Pos) // 0x00000010 */ -#define DOEPEACHMSK1_ITTXFEMSK DOEPEACHMSK1_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask */ +#define DOEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << DOEPEACHMSK1_ITTXFEMSK_Pos) // 0x00000010 +#define DOEPEACHMSK1_ITTXFEMSK DOEPEACHMSK1_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask #define DOEPEACHMSK1_INEPNMM_Pos (5U) -#define DOEPEACHMSK1_INEPNMM_Msk (0x1UL << DOEPEACHMSK1_INEPNMM_Pos) // 0x00000020 */ -#define DOEPEACHMSK1_INEPNMM DOEPEACHMSK1_INEPNMM_Msk // IN token received with EP mismatch mask */ +#define DOEPEACHMSK1_INEPNMM_Msk (0x1UL << DOEPEACHMSK1_INEPNMM_Pos) // 0x00000020 +#define DOEPEACHMSK1_INEPNMM DOEPEACHMSK1_INEPNMM_Msk // IN token received with EP mismatch mask #define DOEPEACHMSK1_INEPNEM_Pos (6U) -#define DOEPEACHMSK1_INEPNEM_Msk (0x1UL << DOEPEACHMSK1_INEPNEM_Pos) // 0x00000040 */ -#define DOEPEACHMSK1_INEPNEM DOEPEACHMSK1_INEPNEM_Msk // IN endpoint NAK effective mask */ +#define DOEPEACHMSK1_INEPNEM_Msk (0x1UL << DOEPEACHMSK1_INEPNEM_Pos) // 0x00000040 +#define DOEPEACHMSK1_INEPNEM DOEPEACHMSK1_INEPNEM_Msk // IN endpoint NAK effective mask #define DOEPEACHMSK1_TXFURM_Pos (8U) -#define DOEPEACHMSK1_TXFURM_Msk (0x1UL << DOEPEACHMSK1_TXFURM_Pos) // 0x00000100 */ -#define DOEPEACHMSK1_TXFURM DOEPEACHMSK1_TXFURM_Msk // OUT packet error mask */ +#define DOEPEACHMSK1_TXFURM_Msk (0x1UL << DOEPEACHMSK1_TXFURM_Pos) // 0x00000100 +#define DOEPEACHMSK1_TXFURM DOEPEACHMSK1_TXFURM_Msk // OUT packet error mask #define DOEPEACHMSK1_BIM_Pos (9U) -#define DOEPEACHMSK1_BIM_Msk (0x1UL << DOEPEACHMSK1_BIM_Pos) // 0x00000200 */ -#define DOEPEACHMSK1_BIM DOEPEACHMSK1_BIM_Msk // BNA interrupt mask */ +#define DOEPEACHMSK1_BIM_Msk (0x1UL << DOEPEACHMSK1_BIM_Pos) // 0x00000200 +#define DOEPEACHMSK1_BIM DOEPEACHMSK1_BIM_Msk // BNA interrupt mask #define DOEPEACHMSK1_BERRM_Pos (12U) -#define DOEPEACHMSK1_BERRM_Msk (0x1UL << DOEPEACHMSK1_BERRM_Pos) // 0x00001000 */ -#define DOEPEACHMSK1_BERRM DOEPEACHMSK1_BERRM_Msk // Bubble error interrupt mask */ +#define DOEPEACHMSK1_BERRM_Msk (0x1UL << DOEPEACHMSK1_BERRM_Pos) // 0x00001000 +#define DOEPEACHMSK1_BERRM DOEPEACHMSK1_BERRM_Msk // Bubble error interrupt mask #define DOEPEACHMSK1_NAKM_Pos (13U) -#define DOEPEACHMSK1_NAKM_Msk (0x1UL << DOEPEACHMSK1_NAKM_Pos) // 0x00002000 */ -#define DOEPEACHMSK1_NAKM DOEPEACHMSK1_NAKM_Msk // NAK interrupt mask */ +#define DOEPEACHMSK1_NAKM_Msk (0x1UL << DOEPEACHMSK1_NAKM_Pos) // 0x00002000 +#define DOEPEACHMSK1_NAKM DOEPEACHMSK1_NAKM_Msk // NAK interrupt mask #define DOEPEACHMSK1_NYETM_Pos (14U) -#define DOEPEACHMSK1_NYETM_Msk (0x1UL << DOEPEACHMSK1_NYETM_Pos) // 0x00004000 */ -#define DOEPEACHMSK1_NYETM DOEPEACHMSK1_NYETM_Msk // NYET interrupt mask */ +#define DOEPEACHMSK1_NYETM_Msk (0x1UL << DOEPEACHMSK1_NYETM_Pos) // 0x00004000 +#define DOEPEACHMSK1_NYETM DOEPEACHMSK1_NYETM_Msk // NYET interrupt mask /******************** Bit definition for HPTXFSIZ register ********************/ #define HPTXFSIZ_PTXSA_Pos (0U) -#define HPTXFSIZ_PTXSA_Msk (0xFFFFUL << HPTXFSIZ_PTXSA_Pos) // 0x0000FFFF */ -#define HPTXFSIZ_PTXSA HPTXFSIZ_PTXSA_Msk // Host periodic TxFIFO start address */ +#define HPTXFSIZ_PTXSA_Msk (0xFFFFUL << HPTXFSIZ_PTXSA_Pos) // 0x0000FFFF +#define HPTXFSIZ_PTXSA HPTXFSIZ_PTXSA_Msk // Host periodic TxFIFO start address #define HPTXFSIZ_PTXFD_Pos (16U) -#define HPTXFSIZ_PTXFD_Msk (0xFFFFUL << HPTXFSIZ_PTXFD_Pos) // 0xFFFF0000 */ -#define HPTXFSIZ_PTXFD HPTXFSIZ_PTXFD_Msk // Host periodic TxFIFO depth */ +#define HPTXFSIZ_PTXFD_Msk (0xFFFFUL << HPTXFSIZ_PTXFD_Pos) // 0xFFFF0000 +#define HPTXFSIZ_PTXFD HPTXFSIZ_PTXFD_Msk // Host periodic TxFIFO depth /******************** Bit definition for DIEPCTL register ********************/ #define DIEPCTL_MPSIZ_Pos (0U) -#define DIEPCTL_MPSIZ_Msk (0x7FFUL << DIEPCTL_MPSIZ_Pos) // 0x000007FF */ -#define DIEPCTL_MPSIZ DIEPCTL_MPSIZ_Msk // Maximum packet size */ +#define DIEPCTL_MPSIZ_Msk (0x7FFUL << DIEPCTL_MPSIZ_Pos) // 0x000007FF +#define DIEPCTL_MPSIZ DIEPCTL_MPSIZ_Msk // Maximum packet size #define DIEPCTL_USBAEP_Pos (15U) -#define DIEPCTL_USBAEP_Msk (0x1UL << DIEPCTL_USBAEP_Pos) // 0x00008000 */ -#define DIEPCTL_USBAEP DIEPCTL_USBAEP_Msk // USB active endpoint */ +#define DIEPCTL_USBAEP_Msk (0x1UL << DIEPCTL_USBAEP_Pos) // 0x00008000 +#define DIEPCTL_USBAEP DIEPCTL_USBAEP_Msk // USB active endpoint #define DIEPCTL_EONUM_DPID_Pos (16U) -#define DIEPCTL_EONUM_DPID_Msk (0x1UL << DIEPCTL_EONUM_DPID_Pos) // 0x00010000 */ -#define DIEPCTL_EONUM_DPID DIEPCTL_EONUM_DPID_Msk // Even/odd frame */ +#define DIEPCTL_EONUM_DPID_Msk (0x1UL << DIEPCTL_EONUM_DPID_Pos) // 0x00010000 +#define DIEPCTL_EONUM_DPID DIEPCTL_EONUM_DPID_Msk // Even/odd frame #define DIEPCTL_NAKSTS_Pos (17U) -#define DIEPCTL_NAKSTS_Msk (0x1UL << DIEPCTL_NAKSTS_Pos) // 0x00020000 */ -#define DIEPCTL_NAKSTS DIEPCTL_NAKSTS_Msk // NAK status */ +#define DIEPCTL_NAKSTS_Msk (0x1UL << DIEPCTL_NAKSTS_Pos) // 0x00020000 +#define DIEPCTL_NAKSTS DIEPCTL_NAKSTS_Msk // NAK status #define DIEPCTL_EPTYP_Pos (18U) -#define DIEPCTL_EPTYP_Msk (0x3UL << DIEPCTL_EPTYP_Pos) // 0x000C0000 */ -#define DIEPCTL_EPTYP DIEPCTL_EPTYP_Msk // Endpoint type */ -#define DIEPCTL_EPTYP_0 (0x1UL << DIEPCTL_EPTYP_Pos) // 0x00040000 */ -#define DIEPCTL_EPTYP_1 (0x2UL << DIEPCTL_EPTYP_Pos) // 0x00080000 */ +#define DIEPCTL_EPTYP_Msk (0x3UL << DIEPCTL_EPTYP_Pos) // 0x000C0000 +#define DIEPCTL_EPTYP DIEPCTL_EPTYP_Msk // Endpoint type +#define DIEPCTL_EPTYP_0 (0x1UL << DIEPCTL_EPTYP_Pos) // 0x00040000 +#define DIEPCTL_EPTYP_1 (0x2UL << DIEPCTL_EPTYP_Pos) // 0x00080000 #define DIEPCTL_STALL_Pos (21U) -#define DIEPCTL_STALL_Msk (0x1UL << DIEPCTL_STALL_Pos) // 0x00200000 */ -#define DIEPCTL_STALL DIEPCTL_STALL_Msk // STALL handshake */ +#define DIEPCTL_STALL_Msk (0x1UL << DIEPCTL_STALL_Pos) // 0x00200000 +#define DIEPCTL_STALL DIEPCTL_STALL_Msk // STALL handshake #define DIEPCTL_TXFNUM_Pos (22U) -#define DIEPCTL_TXFNUM_Msk (0xFUL << DIEPCTL_TXFNUM_Pos) // 0x03C00000 */ -#define DIEPCTL_TXFNUM DIEPCTL_TXFNUM_Msk // TxFIFO number */ -#define DIEPCTL_TXFNUM_0 (0x1UL << DIEPCTL_TXFNUM_Pos) // 0x00400000 */ -#define DIEPCTL_TXFNUM_1 (0x2UL << DIEPCTL_TXFNUM_Pos) // 0x00800000 */ -#define DIEPCTL_TXFNUM_2 (0x4UL << DIEPCTL_TXFNUM_Pos) // 0x01000000 */ -#define DIEPCTL_TXFNUM_3 (0x8UL << DIEPCTL_TXFNUM_Pos) // 0x02000000 */ +#define DIEPCTL_TXFNUM_Msk (0xFUL << DIEPCTL_TXFNUM_Pos) // 0x03C00000 +#define DIEPCTL_TXFNUM DIEPCTL_TXFNUM_Msk // TxFIFO number +#define DIEPCTL_TXFNUM_0 (0x1UL << DIEPCTL_TXFNUM_Pos) // 0x00400000 +#define DIEPCTL_TXFNUM_1 (0x2UL << DIEPCTL_TXFNUM_Pos) // 0x00800000 +#define DIEPCTL_TXFNUM_2 (0x4UL << DIEPCTL_TXFNUM_Pos) // 0x01000000 +#define DIEPCTL_TXFNUM_3 (0x8UL << DIEPCTL_TXFNUM_Pos) // 0x02000000 #define DIEPCTL_CNAK_Pos (26U) -#define DIEPCTL_CNAK_Msk (0x1UL << DIEPCTL_CNAK_Pos) // 0x04000000 */ -#define DIEPCTL_CNAK DIEPCTL_CNAK_Msk // Clear NAK */ +#define DIEPCTL_CNAK_Msk (0x1UL << DIEPCTL_CNAK_Pos) // 0x04000000 +#define DIEPCTL_CNAK DIEPCTL_CNAK_Msk // Clear NAK #define DIEPCTL_SNAK_Pos (27U) -#define DIEPCTL_SNAK_Msk (0x1UL << DIEPCTL_SNAK_Pos) // 0x08000000 */ -#define DIEPCTL_SNAK DIEPCTL_SNAK_Msk // Set NAK */ +#define DIEPCTL_SNAK_Msk (0x1UL << DIEPCTL_SNAK_Pos) // 0x08000000 +#define DIEPCTL_SNAK DIEPCTL_SNAK_Msk // Set NAK #define DIEPCTL_SD0PID_SEVNFRM_Pos (28U) -#define DIEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << DIEPCTL_SD0PID_SEVNFRM_Pos) // 0x10000000 */ -#define DIEPCTL_SD0PID_SEVNFRM DIEPCTL_SD0PID_SEVNFRM_Msk // Set DATA0 PID */ +#define DIEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << DIEPCTL_SD0PID_SEVNFRM_Pos) // 0x10000000 +#define DIEPCTL_SD0PID_SEVNFRM DIEPCTL_SD0PID_SEVNFRM_Msk // Set DATA0 PID #define DIEPCTL_SODDFRM_Pos (29U) -#define DIEPCTL_SODDFRM_Msk (0x1UL << DIEPCTL_SODDFRM_Pos) // 0x20000000 */ -#define DIEPCTL_SODDFRM DIEPCTL_SODDFRM_Msk // Set odd frame */ +#define DIEPCTL_SODDFRM_Msk (0x1UL << DIEPCTL_SODDFRM_Pos) // 0x20000000 +#define DIEPCTL_SODDFRM DIEPCTL_SODDFRM_Msk // Set odd frame #define DIEPCTL_EPDIS_Pos (30U) -#define DIEPCTL_EPDIS_Msk (0x1UL << DIEPCTL_EPDIS_Pos) // 0x40000000 */ -#define DIEPCTL_EPDIS DIEPCTL_EPDIS_Msk // Endpoint disable */ +#define DIEPCTL_EPDIS_Msk (0x1UL << DIEPCTL_EPDIS_Pos) // 0x40000000 +#define DIEPCTL_EPDIS DIEPCTL_EPDIS_Msk // Endpoint disable #define DIEPCTL_EPENA_Pos (31U) -#define DIEPCTL_EPENA_Msk (0x1UL << DIEPCTL_EPENA_Pos) // 0x80000000 */ -#define DIEPCTL_EPENA DIEPCTL_EPENA_Msk // Endpoint enable */ +#define DIEPCTL_EPENA_Msk (0x1UL << DIEPCTL_EPENA_Pos) // 0x80000000 +#define DIEPCTL_EPENA DIEPCTL_EPENA_Msk // Endpoint enable /******************** Bit definition for HCCHAR register ********************/ #define HCCHAR_MPSIZ_Pos (0U) -#define HCCHAR_MPSIZ_Msk (0x7FFUL << HCCHAR_MPSIZ_Pos) // 0x000007FF */ -#define HCCHAR_MPSIZ HCCHAR_MPSIZ_Msk // Maximum packet size */ +#define HCCHAR_MPSIZ_Msk (0x7FFUL << HCCHAR_MPSIZ_Pos) // 0x000007FF +#define HCCHAR_MPSIZ HCCHAR_MPSIZ_Msk // Maximum packet size #define HCCHAR_EPNUM_Pos (11U) -#define HCCHAR_EPNUM_Msk (0xFUL << HCCHAR_EPNUM_Pos) // 0x00007800 */ -#define HCCHAR_EPNUM HCCHAR_EPNUM_Msk // Endpoint number */ -#define HCCHAR_EPNUM_0 (0x1UL << HCCHAR_EPNUM_Pos) // 0x00000800 */ -#define HCCHAR_EPNUM_1 (0x2UL << HCCHAR_EPNUM_Pos) // 0x00001000 */ -#define HCCHAR_EPNUM_2 (0x4UL << HCCHAR_EPNUM_Pos) // 0x00002000 */ -#define HCCHAR_EPNUM_3 (0x8UL << HCCHAR_EPNUM_Pos) // 0x00004000 */ +#define HCCHAR_EPNUM_Msk (0xFUL << HCCHAR_EPNUM_Pos) // 0x00007800 +#define HCCHAR_EPNUM HCCHAR_EPNUM_Msk // Endpoint number +#define HCCHAR_EPNUM_0 (0x1UL << HCCHAR_EPNUM_Pos) // 0x00000800 +#define HCCHAR_EPNUM_1 (0x2UL << HCCHAR_EPNUM_Pos) // 0x00001000 +#define HCCHAR_EPNUM_2 (0x4UL << HCCHAR_EPNUM_Pos) // 0x00002000 +#define HCCHAR_EPNUM_3 (0x8UL << HCCHAR_EPNUM_Pos) // 0x00004000 #define HCCHAR_EPDIR_Pos (15U) -#define HCCHAR_EPDIR_Msk (0x1UL << HCCHAR_EPDIR_Pos) // 0x00008000 */ -#define HCCHAR_EPDIR HCCHAR_EPDIR_Msk // Endpoint direction */ +#define HCCHAR_EPDIR_Msk (0x1UL << HCCHAR_EPDIR_Pos) // 0x00008000 +#define HCCHAR_EPDIR HCCHAR_EPDIR_Msk // Endpoint direction #define HCCHAR_LSDEV_Pos (17U) -#define HCCHAR_LSDEV_Msk (0x1UL << HCCHAR_LSDEV_Pos) // 0x00020000 */ -#define HCCHAR_LSDEV HCCHAR_LSDEV_Msk // Low-speed device */ +#define HCCHAR_LSDEV_Msk (0x1UL << HCCHAR_LSDEV_Pos) // 0x00020000 +#define HCCHAR_LSDEV HCCHAR_LSDEV_Msk // Low-speed device #define HCCHAR_EPTYP_Pos (18U) -#define HCCHAR_EPTYP_Msk (0x3UL << HCCHAR_EPTYP_Pos) // 0x000C0000 */ -#define HCCHAR_EPTYP HCCHAR_EPTYP_Msk // Endpoint type */ -#define HCCHAR_EPTYP_0 (0x1UL << HCCHAR_EPTYP_Pos) // 0x00040000 */ -#define HCCHAR_EPTYP_1 (0x2UL << HCCHAR_EPTYP_Pos) // 0x00080000 */ +#define HCCHAR_EPTYP_Msk (0x3UL << HCCHAR_EPTYP_Pos) // 0x000C0000 +#define HCCHAR_EPTYP HCCHAR_EPTYP_Msk // Endpoint type +#define HCCHAR_EPTYP_0 (0x1UL << HCCHAR_EPTYP_Pos) // 0x00040000 +#define HCCHAR_EPTYP_1 (0x2UL << HCCHAR_EPTYP_Pos) // 0x00080000 #define HCCHAR_MC_Pos (20U) -#define HCCHAR_MC_Msk (0x3UL << HCCHAR_MC_Pos) // 0x00300000 */ -#define HCCHAR_MC HCCHAR_MC_Msk // Multi Count (MC) / Error Count (EC) */ -#define HCCHAR_MC_0 (0x1UL << HCCHAR_MC_Pos) // 0x00100000 */ -#define HCCHAR_MC_1 (0x2UL << HCCHAR_MC_Pos) // 0x00200000 */ +#define HCCHAR_MC_Msk (0x3UL << HCCHAR_MC_Pos) // 0x00300000 +#define HCCHAR_MC HCCHAR_MC_Msk // Multi Count (MC) / Error Count (EC) +#define HCCHAR_MC_0 (0x1UL << HCCHAR_MC_Pos) // 0x00100000 +#define HCCHAR_MC_1 (0x2UL << HCCHAR_MC_Pos) // 0x00200000 #define HCCHAR_DAD_Pos (22U) -#define HCCHAR_DAD_Msk (0x7FUL << HCCHAR_DAD_Pos) // 0x1FC00000 */ -#define HCCHAR_DAD HCCHAR_DAD_Msk // Device address */ -#define HCCHAR_DAD_0 (0x01UL << HCCHAR_DAD_Pos) // 0x00400000 */ -#define HCCHAR_DAD_1 (0x02UL << HCCHAR_DAD_Pos) // 0x00800000 */ -#define HCCHAR_DAD_2 (0x04UL << HCCHAR_DAD_Pos) // 0x01000000 */ -#define HCCHAR_DAD_3 (0x08UL << HCCHAR_DAD_Pos) // 0x02000000 */ -#define HCCHAR_DAD_4 (0x10UL << HCCHAR_DAD_Pos) // 0x04000000 */ -#define HCCHAR_DAD_5 (0x20UL << HCCHAR_DAD_Pos) // 0x08000000 */ -#define HCCHAR_DAD_6 (0x40UL << HCCHAR_DAD_Pos) // 0x10000000 */ +#define HCCHAR_DAD_Msk (0x7FUL << HCCHAR_DAD_Pos) // 0x1FC00000 +#define HCCHAR_DAD HCCHAR_DAD_Msk // Device address +#define HCCHAR_DAD_0 (0x01UL << HCCHAR_DAD_Pos) // 0x00400000 +#define HCCHAR_DAD_1 (0x02UL << HCCHAR_DAD_Pos) // 0x00800000 +#define HCCHAR_DAD_2 (0x04UL << HCCHAR_DAD_Pos) // 0x01000000 +#define HCCHAR_DAD_3 (0x08UL << HCCHAR_DAD_Pos) // 0x02000000 +#define HCCHAR_DAD_4 (0x10UL << HCCHAR_DAD_Pos) // 0x04000000 +#define HCCHAR_DAD_5 (0x20UL << HCCHAR_DAD_Pos) // 0x08000000 +#define HCCHAR_DAD_6 (0x40UL << HCCHAR_DAD_Pos) // 0x10000000 #define HCCHAR_ODDFRM_Pos (29U) -#define HCCHAR_ODDFRM_Msk (0x1UL << HCCHAR_ODDFRM_Pos) // 0x20000000 */ -#define HCCHAR_ODDFRM HCCHAR_ODDFRM_Msk // Odd frame */ +#define HCCHAR_ODDFRM_Msk (0x1UL << HCCHAR_ODDFRM_Pos) // 0x20000000 +#define HCCHAR_ODDFRM HCCHAR_ODDFRM_Msk // Odd frame #define HCCHAR_CHDIS_Pos (30U) -#define HCCHAR_CHDIS_Msk (0x1UL << HCCHAR_CHDIS_Pos) // 0x40000000 */ -#define HCCHAR_CHDIS HCCHAR_CHDIS_Msk // Channel disable */ +#define HCCHAR_CHDIS_Msk (0x1UL << HCCHAR_CHDIS_Pos) // 0x40000000 +#define HCCHAR_CHDIS HCCHAR_CHDIS_Msk // Channel disable #define HCCHAR_CHENA_Pos (31U) -#define HCCHAR_CHENA_Msk (0x1UL << HCCHAR_CHENA_Pos) // 0x80000000 */ -#define HCCHAR_CHENA HCCHAR_CHENA_Msk // Channel enable */ +#define HCCHAR_CHENA_Msk (0x1UL << HCCHAR_CHENA_Pos) // 0x80000000 +#define HCCHAR_CHENA HCCHAR_CHENA_Msk // Channel enable /******************** Bit definition for HCSPLT register ********************/ #define HCSPLT_PRTADDR_Pos (0U) -#define HCSPLT_PRTADDR_Msk (0x7FUL << HCSPLT_PRTADDR_Pos) // 0x0000007F */ -#define HCSPLT_PRTADDR HCSPLT_PRTADDR_Msk // Port address */ -#define HCSPLT_PRTADDR_0 (0x01UL << HCSPLT_PRTADDR_Pos) // 0x00000001 */ -#define HCSPLT_PRTADDR_1 (0x02UL << HCSPLT_PRTADDR_Pos) // 0x00000002 */ -#define HCSPLT_PRTADDR_2 (0x04UL << HCSPLT_PRTADDR_Pos) // 0x00000004 */ -#define HCSPLT_PRTADDR_3 (0x08UL << HCSPLT_PRTADDR_Pos) // 0x00000008 */ -#define HCSPLT_PRTADDR_4 (0x10UL << HCSPLT_PRTADDR_Pos) // 0x00000010 */ -#define HCSPLT_PRTADDR_5 (0x20UL << HCSPLT_PRTADDR_Pos) // 0x00000020 */ -#define HCSPLT_PRTADDR_6 (0x40UL << HCSPLT_PRTADDR_Pos) // 0x00000040 */ +#define HCSPLT_PRTADDR_Msk (0x7FUL << HCSPLT_PRTADDR_Pos) // 0x0000007F +#define HCSPLT_PRTADDR HCSPLT_PRTADDR_Msk // Port address +#define HCSPLT_PRTADDR_0 (0x01UL << HCSPLT_PRTADDR_Pos) // 0x00000001 +#define HCSPLT_PRTADDR_1 (0x02UL << HCSPLT_PRTADDR_Pos) // 0x00000002 +#define HCSPLT_PRTADDR_2 (0x04UL << HCSPLT_PRTADDR_Pos) // 0x00000004 +#define HCSPLT_PRTADDR_3 (0x08UL << HCSPLT_PRTADDR_Pos) // 0x00000008 +#define HCSPLT_PRTADDR_4 (0x10UL << HCSPLT_PRTADDR_Pos) // 0x00000010 +#define HCSPLT_PRTADDR_5 (0x20UL << HCSPLT_PRTADDR_Pos) // 0x00000020 +#define HCSPLT_PRTADDR_6 (0x40UL << HCSPLT_PRTADDR_Pos) // 0x00000040 #define HCSPLT_HUBADDR_Pos (7U) -#define HCSPLT_HUBADDR_Msk (0x7FUL << HCSPLT_HUBADDR_Pos) // 0x00003F80 */ -#define HCSPLT_HUBADDR HCSPLT_HUBADDR_Msk // Hub address */ -#define HCSPLT_HUBADDR_0 (0x01UL << HCSPLT_HUBADDR_Pos) // 0x00000080 */ -#define HCSPLT_HUBADDR_1 (0x02UL << HCSPLT_HUBADDR_Pos) // 0x00000100 */ -#define HCSPLT_HUBADDR_2 (0x04UL << HCSPLT_HUBADDR_Pos) // 0x00000200 */ -#define HCSPLT_HUBADDR_3 (0x08UL << HCSPLT_HUBADDR_Pos) // 0x00000400 */ -#define HCSPLT_HUBADDR_4 (0x10UL << HCSPLT_HUBADDR_Pos) // 0x00000800 */ -#define HCSPLT_HUBADDR_5 (0x20UL << HCSPLT_HUBADDR_Pos) // 0x00001000 */ -#define HCSPLT_HUBADDR_6 (0x40UL << HCSPLT_HUBADDR_Pos) // 0x00002000 */ +#define HCSPLT_HUBADDR_Msk (0x7FUL << HCSPLT_HUBADDR_Pos) // 0x00003F80 +#define HCSPLT_HUBADDR HCSPLT_HUBADDR_Msk // Hub address +#define HCSPLT_HUBADDR_0 (0x01UL << HCSPLT_HUBADDR_Pos) // 0x00000080 +#define HCSPLT_HUBADDR_1 (0x02UL << HCSPLT_HUBADDR_Pos) // 0x00000100 +#define HCSPLT_HUBADDR_2 (0x04UL << HCSPLT_HUBADDR_Pos) // 0x00000200 +#define HCSPLT_HUBADDR_3 (0x08UL << HCSPLT_HUBADDR_Pos) // 0x00000400 +#define HCSPLT_HUBADDR_4 (0x10UL << HCSPLT_HUBADDR_Pos) // 0x00000800 +#define HCSPLT_HUBADDR_5 (0x20UL << HCSPLT_HUBADDR_Pos) // 0x00001000 +#define HCSPLT_HUBADDR_6 (0x40UL << HCSPLT_HUBADDR_Pos) // 0x00002000 #define HCSPLT_XACTPOS_Pos (14U) -#define HCSPLT_XACTPOS_Msk (0x3UL << HCSPLT_XACTPOS_Pos) // 0x0000C000 */ -#define HCSPLT_XACTPOS HCSPLT_XACTPOS_Msk // XACTPOS */ -#define HCSPLT_XACTPOS_0 (0x1UL << HCSPLT_XACTPOS_Pos) // 0x00004000 */ -#define HCSPLT_XACTPOS_1 (0x2UL << HCSPLT_XACTPOS_Pos) // 0x00008000 */ +#define HCSPLT_XACTPOS_Msk (0x3UL << HCSPLT_XACTPOS_Pos) // 0x0000C000 +#define HCSPLT_XACTPOS HCSPLT_XACTPOS_Msk // XACTPOS +#define HCSPLT_XACTPOS_0 (0x1UL << HCSPLT_XACTPOS_Pos) // 0x00004000 +#define HCSPLT_XACTPOS_1 (0x2UL << HCSPLT_XACTPOS_Pos) // 0x00008000 #define HCSPLT_COMPLSPLT_Pos (16U) -#define HCSPLT_COMPLSPLT_Msk (0x1UL << HCSPLT_COMPLSPLT_Pos) // 0x00010000 */ -#define HCSPLT_COMPLSPLT HCSPLT_COMPLSPLT_Msk // Do complete split */ +#define HCSPLT_COMPLSPLT_Msk (0x1UL << HCSPLT_COMPLSPLT_Pos) // 0x00010000 +#define HCSPLT_COMPLSPLT HCSPLT_COMPLSPLT_Msk // Do complete split #define HCSPLT_SPLITEN_Pos (31U) -#define HCSPLT_SPLITEN_Msk (0x1UL << HCSPLT_SPLITEN_Pos) // 0x80000000 */ -#define HCSPLT_SPLITEN HCSPLT_SPLITEN_Msk // Split enable */ +#define HCSPLT_SPLITEN_Msk (0x1UL << HCSPLT_SPLITEN_Pos) // 0x80000000 +#define HCSPLT_SPLITEN HCSPLT_SPLITEN_Msk // Split enable /******************** Bit definition for HCINT register ********************/ #define HCINT_XFRC_Pos (0U) -#define HCINT_XFRC_Msk (0x1UL << HCINT_XFRC_Pos) // 0x00000001 */ -#define HCINT_XFRC HCINT_XFRC_Msk // Transfer completed */ +#define HCINT_XFRC_Msk (0x1UL << HCINT_XFRC_Pos) // 0x00000001 +#define HCINT_XFRC HCINT_XFRC_Msk // Transfer completed #define HCINT_CHH_Pos (1U) -#define HCINT_CHH_Msk (0x1UL << HCINT_CHH_Pos) // 0x00000002 */ -#define HCINT_CHH HCINT_CHH_Msk // Channel halted */ +#define HCINT_CHH_Msk (0x1UL << HCINT_CHH_Pos) // 0x00000002 +#define HCINT_CHH HCINT_CHH_Msk // Channel halted #define HCINT_AHBERR_Pos (2U) -#define HCINT_AHBERR_Msk (0x1UL << HCINT_AHBERR_Pos) // 0x00000004 */ -#define HCINT_AHBERR HCINT_AHBERR_Msk // AHB error */ +#define HCINT_AHBERR_Msk (0x1UL << HCINT_AHBERR_Pos) // 0x00000004 +#define HCINT_AHBERR HCINT_AHBERR_Msk // AHB error #define HCINT_STALL_Pos (3U) -#define HCINT_STALL_Msk (0x1UL << HCINT_STALL_Pos) // 0x00000008 */ -#define HCINT_STALL HCINT_STALL_Msk // STALL response received interrupt */ +#define HCINT_STALL_Msk (0x1UL << HCINT_STALL_Pos) // 0x00000008 +#define HCINT_STALL HCINT_STALL_Msk // STALL response received interrupt #define HCINT_NAK_Pos (4U) -#define HCINT_NAK_Msk (0x1UL << HCINT_NAK_Pos) // 0x00000010 */ -#define HCINT_NAK HCINT_NAK_Msk // NAK response received interrupt */ +#define HCINT_NAK_Msk (0x1UL << HCINT_NAK_Pos) // 0x00000010 +#define HCINT_NAK HCINT_NAK_Msk // NAK response received interrupt #define HCINT_ACK_Pos (5U) -#define HCINT_ACK_Msk (0x1UL << HCINT_ACK_Pos) // 0x00000020 */ -#define HCINT_ACK HCINT_ACK_Msk // ACK response received/transmitted interrupt */ +#define HCINT_ACK_Msk (0x1UL << HCINT_ACK_Pos) // 0x00000020 +#define HCINT_ACK HCINT_ACK_Msk // ACK response received/transmitted interrupt #define HCINT_NYET_Pos (6U) -#define HCINT_NYET_Msk (0x1UL << HCINT_NYET_Pos) // 0x00000040 */ -#define HCINT_NYET HCINT_NYET_Msk // Response received interrupt */ +#define HCINT_NYET_Msk (0x1UL << HCINT_NYET_Pos) // 0x00000040 +#define HCINT_NYET HCINT_NYET_Msk // Response received interrupt #define HCINT_TXERR_Pos (7U) -#define HCINT_TXERR_Msk (0x1UL << HCINT_TXERR_Pos) // 0x00000080 */ -#define HCINT_TXERR HCINT_TXERR_Msk // Transaction error */ +#define HCINT_TXERR_Msk (0x1UL << HCINT_TXERR_Pos) // 0x00000080 +#define HCINT_TXERR HCINT_TXERR_Msk // Transaction error #define HCINT_BBERR_Pos (8U) -#define HCINT_BBERR_Msk (0x1UL << HCINT_BBERR_Pos) // 0x00000100 */ -#define HCINT_BBERR HCINT_BBERR_Msk // Babble error */ +#define HCINT_BBERR_Msk (0x1UL << HCINT_BBERR_Pos) // 0x00000100 +#define HCINT_BBERR HCINT_BBERR_Msk // Babble error #define HCINT_FRMOR_Pos (9U) -#define HCINT_FRMOR_Msk (0x1UL << HCINT_FRMOR_Pos) // 0x00000200 */ -#define HCINT_FRMOR HCINT_FRMOR_Msk // Frame overrun */ +#define HCINT_FRMOR_Msk (0x1UL << HCINT_FRMOR_Pos) // 0x00000200 +#define HCINT_FRMOR HCINT_FRMOR_Msk // Frame overrun #define HCINT_DTERR_Pos (10U) -#define HCINT_DTERR_Msk (0x1UL << HCINT_DTERR_Pos) // 0x00000400 */ -#define HCINT_DTERR HCINT_DTERR_Msk // Data toggle error */ +#define HCINT_DTERR_Msk (0x1UL << HCINT_DTERR_Pos) // 0x00000400 +#define HCINT_DTERR HCINT_DTERR_Msk // Data toggle error /******************** Bit definition for DIEPINT register ********************/ #define DIEPINT_XFRC_Pos (0U) -#define DIEPINT_XFRC_Msk (0x1UL << DIEPINT_XFRC_Pos) // 0x00000001 */ -#define DIEPINT_XFRC DIEPINT_XFRC_Msk // Transfer completed interrupt */ +#define DIEPINT_XFRC_Msk (0x1UL << DIEPINT_XFRC_Pos) // 0x00000001 +#define DIEPINT_XFRC DIEPINT_XFRC_Msk // Transfer completed interrupt #define DIEPINT_EPDISD_Pos (1U) -#define DIEPINT_EPDISD_Msk (0x1UL << DIEPINT_EPDISD_Pos) // 0x00000002 */ -#define DIEPINT_EPDISD DIEPINT_EPDISD_Msk // Endpoint disabled interrupt */ +#define DIEPINT_EPDISD_Msk (0x1UL << DIEPINT_EPDISD_Pos) // 0x00000002 +#define DIEPINT_EPDISD DIEPINT_EPDISD_Msk // Endpoint disabled interrupt #define DIEPINT_AHBERR_Pos (2U) -#define DIEPINT_AHBERR_Msk (0x1UL << DIEPINT_AHBERR_Pos) // 0x00000004 */ -#define DIEPINT_AHBERR DIEPINT_AHBERR_Msk // AHB Error (AHBErr) during an IN transaction */ +#define DIEPINT_AHBERR_Msk (0x1UL << DIEPINT_AHBERR_Pos) // 0x00000004 +#define DIEPINT_AHBERR DIEPINT_AHBERR_Msk // AHB Error (AHBErr) during an IN transaction #define DIEPINT_TOC_Pos (3U) -#define DIEPINT_TOC_Msk (0x1UL << DIEPINT_TOC_Pos) // 0x00000008 */ -#define DIEPINT_TOC DIEPINT_TOC_Msk // Timeout condition */ +#define DIEPINT_TOC_Msk (0x1UL << DIEPINT_TOC_Pos) // 0x00000008 +#define DIEPINT_TOC DIEPINT_TOC_Msk // Timeout condition #define DIEPINT_ITTXFE_Pos (4U) -#define DIEPINT_ITTXFE_Msk (0x1UL << DIEPINT_ITTXFE_Pos) // 0x00000010 */ -#define DIEPINT_ITTXFE DIEPINT_ITTXFE_Msk // IN token received when TxFIFO is empty */ +#define DIEPINT_ITTXFE_Msk (0x1UL << DIEPINT_ITTXFE_Pos) // 0x00000010 +#define DIEPINT_ITTXFE DIEPINT_ITTXFE_Msk // IN token received when TxFIFO is empty #define DIEPINT_INEPNM_Pos (5U) -#define DIEPINT_INEPNM_Msk (0x1UL << DIEPINT_INEPNM_Pos) // 0x00000020 */ -#define DIEPINT_INEPNM DIEPINT_INEPNM_Msk // IN token received with EP mismatch */ +#define DIEPINT_INEPNM_Msk (0x1UL << DIEPINT_INEPNM_Pos) // 0x00000020 +#define DIEPINT_INEPNM DIEPINT_INEPNM_Msk // IN token received with EP mismatch #define DIEPINT_INEPNE_Pos (6U) -#define DIEPINT_INEPNE_Msk (0x1UL << DIEPINT_INEPNE_Pos) // 0x00000040 */ -#define DIEPINT_INEPNE DIEPINT_INEPNE_Msk // IN endpoint NAK effective */ +#define DIEPINT_INEPNE_Msk (0x1UL << DIEPINT_INEPNE_Pos) // 0x00000040 +#define DIEPINT_INEPNE DIEPINT_INEPNE_Msk // IN endpoint NAK effective #define DIEPINT_TXFE_Pos (7U) -#define DIEPINT_TXFE_Msk (0x1UL << DIEPINT_TXFE_Pos) // 0x00000080 */ -#define DIEPINT_TXFE DIEPINT_TXFE_Msk // Transmit FIFO empty */ +#define DIEPINT_TXFE_Msk (0x1UL << DIEPINT_TXFE_Pos) // 0x00000080 +#define DIEPINT_TXFE DIEPINT_TXFE_Msk // Transmit FIFO empty #define DIEPINT_TXFIFOUDRN_Pos (8U) -#define DIEPINT_TXFIFOUDRN_Msk (0x1UL << DIEPINT_TXFIFOUDRN_Pos) // 0x00000100 */ -#define DIEPINT_TXFIFOUDRN DIEPINT_TXFIFOUDRN_Msk // Transmit Fifo Underrun */ +#define DIEPINT_TXFIFOUDRN_Msk (0x1UL << DIEPINT_TXFIFOUDRN_Pos) // 0x00000100 +#define DIEPINT_TXFIFOUDRN DIEPINT_TXFIFOUDRN_Msk // Transmit Fifo Underrun #define DIEPINT_BNA_Pos (9U) -#define DIEPINT_BNA_Msk (0x1UL << DIEPINT_BNA_Pos) // 0x00000200 */ -#define DIEPINT_BNA DIEPINT_BNA_Msk // Buffer not available interrupt */ +#define DIEPINT_BNA_Msk (0x1UL << DIEPINT_BNA_Pos) // 0x00000200 +#define DIEPINT_BNA DIEPINT_BNA_Msk // Buffer not available interrupt #define DIEPINT_PKTDRPSTS_Pos (11U) -#define DIEPINT_PKTDRPSTS_Msk (0x1UL << DIEPINT_PKTDRPSTS_Pos) // 0x00000800 */ -#define DIEPINT_PKTDRPSTS DIEPINT_PKTDRPSTS_Msk // Packet dropped status */ +#define DIEPINT_PKTDRPSTS_Msk (0x1UL << DIEPINT_PKTDRPSTS_Pos) // 0x00000800 +#define DIEPINT_PKTDRPSTS DIEPINT_PKTDRPSTS_Msk // Packet dropped status #define DIEPINT_BERR_Pos (12U) -#define DIEPINT_BERR_Msk (0x1UL << DIEPINT_BERR_Pos) // 0x00001000 */ -#define DIEPINT_BERR DIEPINT_BERR_Msk // Babble error interrupt */ +#define DIEPINT_BERR_Msk (0x1UL << DIEPINT_BERR_Pos) // 0x00001000 +#define DIEPINT_BERR DIEPINT_BERR_Msk // Babble error interrupt #define DIEPINT_NAK_Pos (13U) -#define DIEPINT_NAK_Msk (0x1UL << DIEPINT_NAK_Pos) // 0x00002000 */ -#define DIEPINT_NAK DIEPINT_NAK_Msk // NAK interrupt */ +#define DIEPINT_NAK_Msk (0x1UL << DIEPINT_NAK_Pos) // 0x00002000 +#define DIEPINT_NAK DIEPINT_NAK_Msk // NAK interrupt /******************** Bit definition for HCINTMSK register ********************/ #define HCINTMSK_XFRCM_Pos (0U) -#define HCINTMSK_XFRCM_Msk (0x1UL << HCINTMSK_XFRCM_Pos) // 0x00000001 */ -#define HCINTMSK_XFRCM HCINTMSK_XFRCM_Msk // Transfer completed mask */ +#define HCINTMSK_XFRCM_Msk (0x1UL << HCINTMSK_XFRCM_Pos) // 0x00000001 +#define HCINTMSK_XFRCM HCINTMSK_XFRCM_Msk // Transfer completed mask #define HCINTMSK_CHHM_Pos (1U) -#define HCINTMSK_CHHM_Msk (0x1UL << HCINTMSK_CHHM_Pos) // 0x00000002 */ -#define HCINTMSK_CHHM HCINTMSK_CHHM_Msk // Channel halted mask */ +#define HCINTMSK_CHHM_Msk (0x1UL << HCINTMSK_CHHM_Pos) // 0x00000002 +#define HCINTMSK_CHHM HCINTMSK_CHHM_Msk // Channel halted mask #define HCINTMSK_AHBERR_Pos (2U) -#define HCINTMSK_AHBERR_Msk (0x1UL << HCINTMSK_AHBERR_Pos) // 0x00000004 */ -#define HCINTMSK_AHBERR HCINTMSK_AHBERR_Msk // AHB error */ +#define HCINTMSK_AHBERR_Msk (0x1UL << HCINTMSK_AHBERR_Pos) // 0x00000004 +#define HCINTMSK_AHBERR HCINTMSK_AHBERR_Msk // AHB error #define HCINTMSK_STALLM_Pos (3U) -#define HCINTMSK_STALLM_Msk (0x1UL << HCINTMSK_STALLM_Pos) // 0x00000008 */ -#define HCINTMSK_STALLM HCINTMSK_STALLM_Msk // STALL response received interrupt mask */ +#define HCINTMSK_STALLM_Msk (0x1UL << HCINTMSK_STALLM_Pos) // 0x00000008 +#define HCINTMSK_STALLM HCINTMSK_STALLM_Msk // STALL response received interrupt mask #define HCINTMSK_NAKM_Pos (4U) -#define HCINTMSK_NAKM_Msk (0x1UL << HCINTMSK_NAKM_Pos) // 0x00000010 */ -#define HCINTMSK_NAKM HCINTMSK_NAKM_Msk // NAK response received interrupt mask */ +#define HCINTMSK_NAKM_Msk (0x1UL << HCINTMSK_NAKM_Pos) // 0x00000010 +#define HCINTMSK_NAKM HCINTMSK_NAKM_Msk // NAK response received interrupt mask #define HCINTMSK_ACKM_Pos (5U) -#define HCINTMSK_ACKM_Msk (0x1UL << HCINTMSK_ACKM_Pos) // 0x00000020 */ -#define HCINTMSK_ACKM HCINTMSK_ACKM_Msk // ACK response received/transmitted interrupt mask */ +#define HCINTMSK_ACKM_Msk (0x1UL << HCINTMSK_ACKM_Pos) // 0x00000020 +#define HCINTMSK_ACKM HCINTMSK_ACKM_Msk // ACK response received/transmitted interrupt mask #define HCINTMSK_NYET_Pos (6U) -#define HCINTMSK_NYET_Msk (0x1UL << HCINTMSK_NYET_Pos) // 0x00000040 */ -#define HCINTMSK_NYET HCINTMSK_NYET_Msk // response received interrupt mask */ +#define HCINTMSK_NYET_Msk (0x1UL << HCINTMSK_NYET_Pos) // 0x00000040 +#define HCINTMSK_NYET HCINTMSK_NYET_Msk // response received interrupt mask #define HCINTMSK_TXERRM_Pos (7U) -#define HCINTMSK_TXERRM_Msk (0x1UL << HCINTMSK_TXERRM_Pos) // 0x00000080 */ -#define HCINTMSK_TXERRM HCINTMSK_TXERRM_Msk // Transaction error mask */ +#define HCINTMSK_TXERRM_Msk (0x1UL << HCINTMSK_TXERRM_Pos) // 0x00000080 +#define HCINTMSK_TXERRM HCINTMSK_TXERRM_Msk // Transaction error mask #define HCINTMSK_BBERRM_Pos (8U) -#define HCINTMSK_BBERRM_Msk (0x1UL << HCINTMSK_BBERRM_Pos) // 0x00000100 */ -#define HCINTMSK_BBERRM HCINTMSK_BBERRM_Msk // Babble error mask */ +#define HCINTMSK_BBERRM_Msk (0x1UL << HCINTMSK_BBERRM_Pos) // 0x00000100 +#define HCINTMSK_BBERRM HCINTMSK_BBERRM_Msk // Babble error mask #define HCINTMSK_FRMORM_Pos (9U) -#define HCINTMSK_FRMORM_Msk (0x1UL << HCINTMSK_FRMORM_Pos) // 0x00000200 */ -#define HCINTMSK_FRMORM HCINTMSK_FRMORM_Msk // Frame overrun mask */ +#define HCINTMSK_FRMORM_Msk (0x1UL << HCINTMSK_FRMORM_Pos) // 0x00000200 +#define HCINTMSK_FRMORM HCINTMSK_FRMORM_Msk // Frame overrun mask #define HCINTMSK_DTERRM_Pos (10U) -#define HCINTMSK_DTERRM_Msk (0x1UL << HCINTMSK_DTERRM_Pos) // 0x00000400 */ -#define HCINTMSK_DTERRM HCINTMSK_DTERRM_Msk // Data toggle error mask */ +#define HCINTMSK_DTERRM_Msk (0x1UL << HCINTMSK_DTERRM_Pos) // 0x00000400 +#define HCINTMSK_DTERRM HCINTMSK_DTERRM_Msk // Data toggle error mask /******************** Bit definition for DIEPTSIZ register ********************/ #define DIEPTSIZ_XFRSIZ_Pos (0U) -#define DIEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << DIEPTSIZ_XFRSIZ_Pos) // 0x0007FFFF */ -#define DIEPTSIZ_XFRSIZ DIEPTSIZ_XFRSIZ_Msk // Transfer size */ +#define DIEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << DIEPTSIZ_XFRSIZ_Pos) // 0x0007FFFF +#define DIEPTSIZ_XFRSIZ DIEPTSIZ_XFRSIZ_Msk // Transfer size #define DIEPTSIZ_PKTCNT_Pos (19U) -#define DIEPTSIZ_PKTCNT_Msk (0x3FFUL << DIEPTSIZ_PKTCNT_Pos) // 0x1FF80000 */ -#define DIEPTSIZ_PKTCNT DIEPTSIZ_PKTCNT_Msk // Packet count */ +#define DIEPTSIZ_PKTCNT_Msk (0x3FFUL << DIEPTSIZ_PKTCNT_Pos) // 0x1FF80000 +#define DIEPTSIZ_PKTCNT DIEPTSIZ_PKTCNT_Msk // Packet count #define DIEPTSIZ_MULCNT_Pos (29U) -#define DIEPTSIZ_MULCNT_Msk (0x3UL << DIEPTSIZ_MULCNT_Pos) // 0x60000000 */ -#define DIEPTSIZ_MULCNT DIEPTSIZ_MULCNT_Msk // Packet count */ +#define DIEPTSIZ_MULCNT_Msk (0x3UL << DIEPTSIZ_MULCNT_Pos) // 0x60000000 +#define DIEPTSIZ_MULCNT DIEPTSIZ_MULCNT_Msk // Packet count /******************** Bit definition for HCTSIZ register ********************/ #define HCTSIZ_XFRSIZ_Pos (0U) -#define HCTSIZ_XFRSIZ_Msk (0x7FFFFUL << HCTSIZ_XFRSIZ_Pos) // 0x0007FFFF */ -#define HCTSIZ_XFRSIZ HCTSIZ_XFRSIZ_Msk // Transfer size */ +#define HCTSIZ_XFRSIZ_Msk (0x7FFFFUL << HCTSIZ_XFRSIZ_Pos) // 0x0007FFFF +#define HCTSIZ_XFRSIZ HCTSIZ_XFRSIZ_Msk // Transfer size #define HCTSIZ_PKTCNT_Pos (19U) -#define HCTSIZ_PKTCNT_Msk (0x3FFUL << HCTSIZ_PKTCNT_Pos) // 0x1FF80000 */ -#define HCTSIZ_PKTCNT HCTSIZ_PKTCNT_Msk // Packet count */ +#define HCTSIZ_PKTCNT_Msk (0x3FFUL << HCTSIZ_PKTCNT_Pos) // 0x1FF80000 +#define HCTSIZ_PKTCNT HCTSIZ_PKTCNT_Msk // Packet count #define HCTSIZ_DOPING_Pos (31U) -#define HCTSIZ_DOPING_Msk (0x1UL << HCTSIZ_DOPING_Pos) // 0x80000000 */ -#define HCTSIZ_DOPING HCTSIZ_DOPING_Msk // Do PING */ +#define HCTSIZ_DOPING_Msk (0x1UL << HCTSIZ_DOPING_Pos) // 0x80000000 +#define HCTSIZ_DOPING HCTSIZ_DOPING_Msk // Do PING #define HCTSIZ_DPID_Pos (29U) -#define HCTSIZ_DPID_Msk (0x3UL << HCTSIZ_DPID_Pos) // 0x60000000 */ -#define HCTSIZ_DPID HCTSIZ_DPID_Msk // Data PID */ -#define HCTSIZ_DPID_0 (0x1UL << HCTSIZ_DPID_Pos) // 0x20000000 */ -#define HCTSIZ_DPID_1 (0x2UL << HCTSIZ_DPID_Pos) // 0x40000000 */ +#define HCTSIZ_DPID_Msk (0x3UL << HCTSIZ_DPID_Pos) // 0x60000000 +#define HCTSIZ_DPID HCTSIZ_DPID_Msk // Data PID +#define HCTSIZ_DPID_0 (0x1UL << HCTSIZ_DPID_Pos) // 0x20000000 +#define HCTSIZ_DPID_1 (0x2UL << HCTSIZ_DPID_Pos) // 0x40000000 /******************** Bit definition for DIEPDMA register ********************/ #define DIEPDMA_DMAADDR_Pos (0U) -#define DIEPDMA_DMAADDR_Msk (0xFFFFFFFFUL << DIEPDMA_DMAADDR_Pos) // 0xFFFFFFFF */ -#define DIEPDMA_DMAADDR DIEPDMA_DMAADDR_Msk // DMA address */ +#define DIEPDMA_DMAADDR_Msk (0xFFFFFFFFUL << DIEPDMA_DMAADDR_Pos) // 0xFFFFFFFF +#define DIEPDMA_DMAADDR DIEPDMA_DMAADDR_Msk // DMA address /******************** Bit definition for HCDMA register ********************/ #define HCDMA_DMAADDR_Pos (0U) -#define HCDMA_DMAADDR_Msk (0xFFFFFFFFUL << HCDMA_DMAADDR_Pos) // 0xFFFFFFFF */ -#define HCDMA_DMAADDR HCDMA_DMAADDR_Msk // DMA address */ +#define HCDMA_DMAADDR_Msk (0xFFFFFFFFUL << HCDMA_DMAADDR_Pos) // 0xFFFFFFFF +#define HCDMA_DMAADDR HCDMA_DMAADDR_Msk // DMA address /******************** Bit definition for DTXFSTS register ********************/ #define DTXFSTS_INEPTFSAV_Pos (0U) -#define DTXFSTS_INEPTFSAV_Msk (0xFFFFUL << DTXFSTS_INEPTFSAV_Pos) // 0x0000FFFF */ -#define DTXFSTS_INEPTFSAV DTXFSTS_INEPTFSAV_Msk // IN endpoint TxFIFO space available */ +#define DTXFSTS_INEPTFSAV_Msk (0xFFFFUL << DTXFSTS_INEPTFSAV_Pos) // 0x0000FFFF +#define DTXFSTS_INEPTFSAV DTXFSTS_INEPTFSAV_Msk // IN endpoint TxFIFO space available /******************** Bit definition for DIEPTXF register ********************/ #define DIEPTXF_INEPTXSA_Pos (0U) -#define DIEPTXF_INEPTXSA_Msk (0xFFFFUL << DIEPTXF_INEPTXSA_Pos) // 0x0000FFFF */ -#define DIEPTXF_INEPTXSA DIEPTXF_INEPTXSA_Msk // IN endpoint FIFOx transmit RAM start address */ +#define DIEPTXF_INEPTXSA_Msk (0xFFFFUL << DIEPTXF_INEPTXSA_Pos) // 0x0000FFFF +#define DIEPTXF_INEPTXSA DIEPTXF_INEPTXSA_Msk // IN endpoint FIFOx transmit RAM start address #define DIEPTXF_INEPTXFD_Pos (16U) -#define DIEPTXF_INEPTXFD_Msk (0xFFFFUL << DIEPTXF_INEPTXFD_Pos) // 0xFFFF0000 */ -#define DIEPTXF_INEPTXFD DIEPTXF_INEPTXFD_Msk // IN endpoint TxFIFO depth */ +#define DIEPTXF_INEPTXFD_Msk (0xFFFFUL << DIEPTXF_INEPTXFD_Pos) // 0xFFFF0000 +#define DIEPTXF_INEPTXFD DIEPTXF_INEPTXFD_Msk // IN endpoint TxFIFO depth /******************** Bit definition for DOEPCTL register ********************/ #define DOEPCTL_MPSIZ_Pos (0U) -#define DOEPCTL_MPSIZ_Msk (0x7FFUL << DOEPCTL_MPSIZ_Pos) // 0x000007FF */ -#define DOEPCTL_MPSIZ DOEPCTL_MPSIZ_Msk // Maximum packet size */ //Bit 1 */ +#define DOEPCTL_MPSIZ_Msk (0x7FFUL << DOEPCTL_MPSIZ_Pos) // 0x000007FF +#define DOEPCTL_MPSIZ DOEPCTL_MPSIZ_Msk // Maximum packet size //Bit 1 #define DOEPCTL_USBAEP_Pos (15U) -#define DOEPCTL_USBAEP_Msk (0x1UL << DOEPCTL_USBAEP_Pos) // 0x00008000 */ -#define DOEPCTL_USBAEP DOEPCTL_USBAEP_Msk // USB active endpoint */ +#define DOEPCTL_USBAEP_Msk (0x1UL << DOEPCTL_USBAEP_Pos) // 0x00008000 +#define DOEPCTL_USBAEP DOEPCTL_USBAEP_Msk // USB active endpoint #define DOEPCTL_NAKSTS_Pos (17U) -#define DOEPCTL_NAKSTS_Msk (0x1UL << DOEPCTL_NAKSTS_Pos) // 0x00020000 */ -#define DOEPCTL_NAKSTS DOEPCTL_NAKSTS_Msk // NAK status */ +#define DOEPCTL_NAKSTS_Msk (0x1UL << DOEPCTL_NAKSTS_Pos) // 0x00020000 +#define DOEPCTL_NAKSTS DOEPCTL_NAKSTS_Msk // NAK status #define DOEPCTL_SD0PID_SEVNFRM_Pos (28U) -#define DOEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << DOEPCTL_SD0PID_SEVNFRM_Pos) // 0x10000000 */ -#define DOEPCTL_SD0PID_SEVNFRM DOEPCTL_SD0PID_SEVNFRM_Msk // Set DATA0 PID */ +#define DOEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << DOEPCTL_SD0PID_SEVNFRM_Pos) // 0x10000000 +#define DOEPCTL_SD0PID_SEVNFRM DOEPCTL_SD0PID_SEVNFRM_Msk // Set DATA0 PID #define DOEPCTL_SODDFRM_Pos (29U) -#define DOEPCTL_SODDFRM_Msk (0x1UL << DOEPCTL_SODDFRM_Pos) // 0x20000000 */ -#define DOEPCTL_SODDFRM DOEPCTL_SODDFRM_Msk // Set odd frame */ +#define DOEPCTL_SODDFRM_Msk (0x1UL << DOEPCTL_SODDFRM_Pos) // 0x20000000 +#define DOEPCTL_SODDFRM DOEPCTL_SODDFRM_Msk // Set odd frame #define DOEPCTL_EPTYP_Pos (18U) -#define DOEPCTL_EPTYP_Msk (0x3UL << DOEPCTL_EPTYP_Pos) // 0x000C0000 */ -#define DOEPCTL_EPTYP DOEPCTL_EPTYP_Msk // Endpoint type */ -#define DOEPCTL_EPTYP_0 (0x1UL << DOEPCTL_EPTYP_Pos) // 0x00040000 */ -#define DOEPCTL_EPTYP_1 (0x2UL << DOEPCTL_EPTYP_Pos) // 0x00080000 */ +#define DOEPCTL_EPTYP_Msk (0x3UL << DOEPCTL_EPTYP_Pos) // 0x000C0000 +#define DOEPCTL_EPTYP DOEPCTL_EPTYP_Msk // Endpoint type +#define DOEPCTL_EPTYP_0 (0x1UL << DOEPCTL_EPTYP_Pos) // 0x00040000 +#define DOEPCTL_EPTYP_1 (0x2UL << DOEPCTL_EPTYP_Pos) // 0x00080000 #define DOEPCTL_SNPM_Pos (20U) -#define DOEPCTL_SNPM_Msk (0x1UL << DOEPCTL_SNPM_Pos) // 0x00100000 */ -#define DOEPCTL_SNPM DOEPCTL_SNPM_Msk // Snoop mode */ +#define DOEPCTL_SNPM_Msk (0x1UL << DOEPCTL_SNPM_Pos) // 0x00100000 +#define DOEPCTL_SNPM DOEPCTL_SNPM_Msk // Snoop mode #define DOEPCTL_STALL_Pos (21U) -#define DOEPCTL_STALL_Msk (0x1UL << DOEPCTL_STALL_Pos) // 0x00200000 */ -#define DOEPCTL_STALL DOEPCTL_STALL_Msk // STALL handshake */ +#define DOEPCTL_STALL_Msk (0x1UL << DOEPCTL_STALL_Pos) // 0x00200000 +#define DOEPCTL_STALL DOEPCTL_STALL_Msk // STALL handshake #define DOEPCTL_CNAK_Pos (26U) -#define DOEPCTL_CNAK_Msk (0x1UL << DOEPCTL_CNAK_Pos) // 0x04000000 */ -#define DOEPCTL_CNAK DOEPCTL_CNAK_Msk // Clear NAK */ +#define DOEPCTL_CNAK_Msk (0x1UL << DOEPCTL_CNAK_Pos) // 0x04000000 +#define DOEPCTL_CNAK DOEPCTL_CNAK_Msk // Clear NAK #define DOEPCTL_SNAK_Pos (27U) -#define DOEPCTL_SNAK_Msk (0x1UL << DOEPCTL_SNAK_Pos) // 0x08000000 */ -#define DOEPCTL_SNAK DOEPCTL_SNAK_Msk // Set NAK */ +#define DOEPCTL_SNAK_Msk (0x1UL << DOEPCTL_SNAK_Pos) // 0x08000000 +#define DOEPCTL_SNAK DOEPCTL_SNAK_Msk // Set NAK #define DOEPCTL_EPDIS_Pos (30U) -#define DOEPCTL_EPDIS_Msk (0x1UL << DOEPCTL_EPDIS_Pos) // 0x40000000 */ -#define DOEPCTL_EPDIS DOEPCTL_EPDIS_Msk // Endpoint disable */ +#define DOEPCTL_EPDIS_Msk (0x1UL << DOEPCTL_EPDIS_Pos) // 0x40000000 +#define DOEPCTL_EPDIS DOEPCTL_EPDIS_Msk // Endpoint disable #define DOEPCTL_EPENA_Pos (31U) -#define DOEPCTL_EPENA_Msk (0x1UL << DOEPCTL_EPENA_Pos) // 0x80000000 */ -#define DOEPCTL_EPENA DOEPCTL_EPENA_Msk // Endpoint enable */ +#define DOEPCTL_EPENA_Msk (0x1UL << DOEPCTL_EPENA_Pos) // 0x80000000 +#define DOEPCTL_EPENA DOEPCTL_EPENA_Msk // Endpoint enable /******************** Bit definition for DOEPINT register ********************/ #define DOEPINT_XFRC_Pos (0U) -#define DOEPINT_XFRC_Msk (0x1UL << DOEPINT_XFRC_Pos) // 0x00000001 */ -#define DOEPINT_XFRC DOEPINT_XFRC_Msk // Transfer completed interrupt */ +#define DOEPINT_XFRC_Msk (0x1UL << DOEPINT_XFRC_Pos) // 0x00000001 +#define DOEPINT_XFRC DOEPINT_XFRC_Msk // Transfer completed interrupt #define DOEPINT_EPDISD_Pos (1U) -#define DOEPINT_EPDISD_Msk (0x1UL << DOEPINT_EPDISD_Pos) // 0x00000002 */ -#define DOEPINT_EPDISD DOEPINT_EPDISD_Msk // Endpoint disabled interrupt */ +#define DOEPINT_EPDISD_Msk (0x1UL << DOEPINT_EPDISD_Pos) // 0x00000002 +#define DOEPINT_EPDISD DOEPINT_EPDISD_Msk // Endpoint disabled interrupt #define DOEPINT_AHBERR_Pos (2U) -#define DOEPINT_AHBERR_Msk (0x1UL << DOEPINT_AHBERR_Pos) // 0x00000004 */ -#define DOEPINT_AHBERR DOEPINT_AHBERR_Msk // AHB Error (AHBErr) during an OUT transaction */ +#define DOEPINT_AHBERR_Msk (0x1UL << DOEPINT_AHBERR_Pos) // 0x00000004 +#define DOEPINT_AHBERR DOEPINT_AHBERR_Msk // AHB Error (AHBErr) during an OUT transaction #define DOEPINT_STUP_Pos (3U) -#define DOEPINT_STUP_Msk (0x1UL << DOEPINT_STUP_Pos) // 0x00000008 */ -#define DOEPINT_STUP DOEPINT_STUP_Msk // SETUP phase done */ +#define DOEPINT_STUP_Msk (0x1UL << DOEPINT_STUP_Pos) // 0x00000008 +#define DOEPINT_STUP DOEPINT_STUP_Msk // SETUP phase done #define DOEPINT_OTEPDIS_Pos (4U) -#define DOEPINT_OTEPDIS_Msk (0x1UL << DOEPINT_OTEPDIS_Pos) // 0x00000010 */ -#define DOEPINT_OTEPDIS DOEPINT_OTEPDIS_Msk // OUT token received when endpoint disabled */ +#define DOEPINT_OTEPDIS_Msk (0x1UL << DOEPINT_OTEPDIS_Pos) // 0x00000010 +#define DOEPINT_OTEPDIS DOEPINT_OTEPDIS_Msk // OUT token received when endpoint disabled #define DOEPINT_OTEPSPR_Pos (5U) -#define DOEPINT_OTEPSPR_Msk (0x1UL << DOEPINT_OTEPSPR_Pos) // 0x00000020 */ -#define DOEPINT_OTEPSPR DOEPINT_OTEPSPR_Msk // Status Phase Received For Control Write */ +#define DOEPINT_OTEPSPR_Msk (0x1UL << DOEPINT_OTEPSPR_Pos) // 0x00000020 +#define DOEPINT_OTEPSPR DOEPINT_OTEPSPR_Msk // Status Phase Received For Control Write #define DOEPINT_B2BSTUP_Pos (6U) -#define DOEPINT_B2BSTUP_Msk (0x1UL << DOEPINT_B2BSTUP_Pos) // 0x00000040 */ -#define DOEPINT_B2BSTUP DOEPINT_B2BSTUP_Msk // Back-to-back SETUP packets received */ +#define DOEPINT_B2BSTUP_Msk (0x1UL << DOEPINT_B2BSTUP_Pos) // 0x00000040 +#define DOEPINT_B2BSTUP DOEPINT_B2BSTUP_Msk // Back-to-back SETUP packets received #define DOEPINT_OUTPKTERR_Pos (8U) -#define DOEPINT_OUTPKTERR_Msk (0x1UL << DOEPINT_OUTPKTERR_Pos) // 0x00000100 */ -#define DOEPINT_OUTPKTERR DOEPINT_OUTPKTERR_Msk // OUT packet error */ +#define DOEPINT_OUTPKTERR_Msk (0x1UL << DOEPINT_OUTPKTERR_Pos) // 0x00000100 +#define DOEPINT_OUTPKTERR DOEPINT_OUTPKTERR_Msk // OUT packet error #define DOEPINT_NAK_Pos (13U) -#define DOEPINT_NAK_Msk (0x1UL << DOEPINT_NAK_Pos) // 0x00002000 */ -#define DOEPINT_NAK DOEPINT_NAK_Msk // NAK Packet is transmitted by the device */ +#define DOEPINT_NAK_Msk (0x1UL << DOEPINT_NAK_Pos) // 0x00002000 +#define DOEPINT_NAK DOEPINT_NAK_Msk // NAK Packet is transmitted by the device #define DOEPINT_NYET_Pos (14U) -#define DOEPINT_NYET_Msk (0x1UL << DOEPINT_NYET_Pos) // 0x00004000 */ -#define DOEPINT_NYET DOEPINT_NYET_Msk // NYET interrupt */ +#define DOEPINT_NYET_Msk (0x1UL << DOEPINT_NYET_Pos) // 0x00004000 +#define DOEPINT_NYET DOEPINT_NYET_Msk // NYET interrupt #define DOEPINT_STPKTRX_Pos (15U) -#define DOEPINT_STPKTRX_Msk (0x1UL << DOEPINT_STPKTRX_Pos) // 0x00008000 */ -#define DOEPINT_STPKTRX DOEPINT_STPKTRX_Msk // Setup Packet Received */ +#define DOEPINT_STPKTRX_Msk (0x1UL << DOEPINT_STPKTRX_Pos) // 0x00008000 +#define DOEPINT_STPKTRX DOEPINT_STPKTRX_Msk // Setup Packet Received /******************** Bit definition for DOEPTSIZ register ********************/ #define DOEPTSIZ_XFRSIZ_Pos (0U) -#define DOEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << DOEPTSIZ_XFRSIZ_Pos) // 0x0007FFFF */ -#define DOEPTSIZ_XFRSIZ DOEPTSIZ_XFRSIZ_Msk // Transfer size */ +#define DOEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << DOEPTSIZ_XFRSIZ_Pos) // 0x0007FFFF +#define DOEPTSIZ_XFRSIZ DOEPTSIZ_XFRSIZ_Msk // Transfer size #define DOEPTSIZ_PKTCNT_Pos (19U) -#define DOEPTSIZ_PKTCNT_Msk (0x3FFUL << DOEPTSIZ_PKTCNT_Pos) // 0x1FF80000 */ -#define DOEPTSIZ_PKTCNT DOEPTSIZ_PKTCNT_Msk // Packet count */ +#define DOEPTSIZ_PKTCNT_Msk (0x3FFUL << DOEPTSIZ_PKTCNT_Pos) // 0x1FF80000 +#define DOEPTSIZ_PKTCNT DOEPTSIZ_PKTCNT_Msk // Packet count #define DOEPTSIZ_STUPCNT_Pos (29U) -#define DOEPTSIZ_STUPCNT_Msk (0x3UL << DOEPTSIZ_STUPCNT_Pos) // 0x60000000 */ -#define DOEPTSIZ_STUPCNT DOEPTSIZ_STUPCNT_Msk // SETUP packet count */ -#define DOEPTSIZ_STUPCNT_0 (0x1UL << DOEPTSIZ_STUPCNT_Pos) // 0x20000000 */ -#define DOEPTSIZ_STUPCNT_1 (0x2UL << DOEPTSIZ_STUPCNT_Pos) // 0x40000000 */ +#define DOEPTSIZ_STUPCNT_Msk (0x3UL << DOEPTSIZ_STUPCNT_Pos) // 0x60000000 +#define DOEPTSIZ_STUPCNT DOEPTSIZ_STUPCNT_Msk // SETUP packet count +#define DOEPTSIZ_STUPCNT_0 (0x1UL << DOEPTSIZ_STUPCNT_Pos) // 0x20000000 +#define DOEPTSIZ_STUPCNT_1 (0x2UL << DOEPTSIZ_STUPCNT_Pos) // 0x40000000 /******************** Bit definition for PCGCTL register ********************/ #define PCGCTL_IF_DEV_MODE TU_BIT(31) diff --git a/test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_xmc.h b/test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_xmc.h similarity index 100% rename from test-devices/loopback-stm32/lib/tinyusb/dwc2/dwc2_xmc.h rename to test-devices/loopback-stm32/lib/tinyusb/portable/synopsys/dwc2/dwc2_xmc.h diff --git a/test-devices/loopback-stm32/lib/tinyusb/tusb.c b/test-devices/loopback-stm32/lib/tinyusb/tusb.c index 85fe5a3c..0092267a 100644 --- a/test-devices/loopback-stm32/lib/tinyusb/tusb.c +++ b/test-devices/loopback-stm32/lib/tinyusb/tusb.c @@ -36,39 +36,37 @@ #endif #if CFG_TUH_ENABLED -#include "host/usbh_classdriver.h" +#include "host/usbh_pvt.h" #endif //--------------------------------------------------------------------+ // Public API //--------------------------------------------------------------------+ -bool tusb_init(void) -{ -#if CFG_TUD_ENABLED && defined(TUD_OPT_RHPORT) +bool tusb_init(void) { + #if CFG_TUD_ENABLED && defined(TUD_OPT_RHPORT) // init device stack CFG_TUSB_RHPORTx_MODE must be defined TU_ASSERT ( tud_init(TUD_OPT_RHPORT) ); -#endif + #endif -#if CFG_TUH_ENABLED && defined(TUH_OPT_RHPORT) + #if CFG_TUH_ENABLED && defined(TUH_OPT_RHPORT) // init host stack CFG_TUSB_RHPORTx_MODE must be defined TU_ASSERT( tuh_init(TUH_OPT_RHPORT) ); -#endif + #endif return true; } -bool tusb_inited(void) -{ +bool tusb_inited(void) { bool ret = false; -#if CFG_TUD_ENABLED + #if CFG_TUD_ENABLED ret = ret || tud_inited(); -#endif + #endif -#if CFG_TUH_ENABLED + #if CFG_TUH_ENABLED ret = ret || tuh_inited(); -#endif + #endif return ret; } @@ -77,43 +75,35 @@ bool tusb_inited(void) // Descriptor helper //--------------------------------------------------------------------+ -uint8_t const * tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byte1) -{ - while(desc+1 < end) - { - if ( desc[1] == byte1 ) return desc; +uint8_t const* tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byte1) { + while (desc + 1 < end) { + if (desc[1] == byte1) return desc; desc += desc[DESC_OFFSET_LEN]; } return NULL; } -uint8_t const * tu_desc_find2(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2) -{ - while(desc+2 < end) - { - if ( desc[1] == byte1 && desc[2] == byte2) return desc; +uint8_t const* tu_desc_find2(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2) { + while (desc + 2 < end) { + if (desc[1] == byte1 && desc[2] == byte2) return desc; desc += desc[DESC_OFFSET_LEN]; } return NULL; } -uint8_t const * tu_desc_find3(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2, uint8_t byte3) -{ - while(desc+3 < end) - { +uint8_t const* tu_desc_find3(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2, uint8_t byte3) { + while (desc + 3 < end) { if (desc[1] == byte1 && desc[2] == byte2 && desc[3] == byte3) return desc; desc += desc[DESC_OFFSET_LEN]; } return NULL; } - //--------------------------------------------------------------------+ // Endpoint Helper for both Host and Device stack //--------------------------------------------------------------------+ -bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex) -{ +bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex) { (void) mutex; // pre-check to help reducing mutex lock @@ -122,111 +112,93 @@ bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex) // can only claim the endpoint if it is not busy and not claimed yet. bool const available = (ep_state->busy == 0) && (ep_state->claimed == 0); - if (available) - { + if (available) { ep_state->claimed = 1; } (void) osal_mutex_unlock(mutex); - return available; } -bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex) -{ +bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex) { (void) mutex; - (void) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); // can only release the endpoint if it is claimed and not busy bool const ret = (ep_state->claimed == 1) && (ep_state->busy == 0); - if (ret) - { + if (ret) { ep_state->claimed = 0; } (void) osal_mutex_unlock(mutex); - return ret; } -bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed) -{ +bool tu_edpt_validate(tusb_desc_endpoint_t const* desc_ep, tusb_speed_t speed) { uint16_t const max_packet_size = tu_edpt_packet_size(desc_ep); TU_LOG2(" Open EP %02X with Size = %u\r\n", desc_ep->bEndpointAddress, max_packet_size); - switch (desc_ep->bmAttributes.xfer) - { - case TUSB_XFER_ISOCHRONOUS: - { + switch (desc_ep->bmAttributes.xfer) { + case TUSB_XFER_ISOCHRONOUS: { uint16_t const spec_size = (speed == TUSB_SPEED_HIGH ? 1024 : 1023); TU_ASSERT(max_packet_size <= spec_size); + break; } - break; case TUSB_XFER_BULK: - if (speed == TUSB_SPEED_HIGH) - { + if (speed == TUSB_SPEED_HIGH) { // Bulk highspeed must be EXACTLY 512 TU_ASSERT(max_packet_size == 512); - }else - { + } else { // TODO Bulk fullspeed can only be 8, 16, 32, 64 TU_ASSERT(max_packet_size <= 64); } - break; + break; - case TUSB_XFER_INTERRUPT: - { + case TUSB_XFER_INTERRUPT: { uint16_t const spec_size = (speed == TUSB_SPEED_HIGH ? 1024 : 64); TU_ASSERT(max_packet_size <= spec_size); + break; } - break; - default: return false; + default: + return false; } return true; } -void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* desc_itf, uint16_t desc_len, uint8_t driver_id) -{ +void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* desc_itf, uint16_t desc_len, + uint8_t driver_id) { uint8_t const* p_desc = (uint8_t const*) desc_itf; uint8_t const* desc_end = p_desc + desc_len; - while( p_desc < desc_end ) - { - if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) - { + while (p_desc < desc_end) { + if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) { uint8_t const ep_addr = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress; - TU_LOG(2, " Bind EP %02x to driver id %u\r\n", ep_addr, driver_id); ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)] = driver_id; } - p_desc = tu_desc_next(p_desc); } } -uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len) -{ +uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len) { uint8_t const* p_desc = (uint8_t const*) desc_itf; uint16_t len = 0; - while (itf_count--) - { + while (itf_count--) { // Next on interface desc len += tu_desc_len(desc_itf); p_desc = tu_desc_next(p_desc); - while (len < max_len) - { + while (len < max_len) { // return on IAD regardless of itf count - if ( tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION ) return len; - - if ( (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) && - ((tusb_desc_interface_t const*) p_desc)->bAlternateSetting == 0 ) - { + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION) { + return len; + } + if ((tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) && + ((tusb_desc_interface_t const*) p_desc)->bAlternateSetting == 0) { break; } @@ -243,9 +215,8 @@ uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, //--------------------------------------------------------------------+ bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool overwritable, - void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize) -{ - osal_mutex_t new_mutex = osal_mutex_create(&s->ff_mutex); + void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize) { + osal_mutex_t new_mutex = osal_mutex_create(&s->ff_mutexdef); (void) new_mutex; (void) is_tx; @@ -259,92 +230,82 @@ bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool ove return true; } +bool tu_edpt_stream_deinit(tu_edpt_stream_t* s) { + (void) s; + #if OSAL_MUTEX_REQUIRED + if (s->ff.mutex_wr) osal_mutex_delete(s->ff.mutex_wr); + if (s->ff.mutex_rd) osal_mutex_delete(s->ff.mutex_rd); + #endif + return true; +} + TU_ATTR_ALWAYS_INLINE static inline -bool stream_claim(tu_edpt_stream_t* s) -{ - if (s->is_host) - { +bool stream_claim(tu_edpt_stream_t* s) { + if (s->is_host) { #if CFG_TUH_ENABLED return usbh_edpt_claim(s->daddr, s->ep_addr); #endif - }else - { + } else { #if CFG_TUD_ENABLED return usbd_edpt_claim(s->rhport, s->ep_addr); #endif } - return false; } TU_ATTR_ALWAYS_INLINE static inline -bool stream_xfer(tu_edpt_stream_t* s, uint16_t count) -{ - if (s->is_host) - { +bool stream_xfer(tu_edpt_stream_t* s, uint16_t count) { + if (s->is_host) { #if CFG_TUH_ENABLED return usbh_edpt_xfer(s->daddr, s->ep_addr, count ? s->ep_buf : NULL, count); #endif - }else - { + } else { #if CFG_TUD_ENABLED return usbd_edpt_xfer(s->rhport, s->ep_addr, count ? s->ep_buf : NULL, count); #endif } - return false; } TU_ATTR_ALWAYS_INLINE static inline -bool stream_release(tu_edpt_stream_t* s) -{ - if (s->is_host) - { +bool stream_release(tu_edpt_stream_t* s) { + if (s->is_host) { #if CFG_TUH_ENABLED return usbh_edpt_release(s->daddr, s->ep_addr); #endif - }else - { + } else { #if CFG_TUD_ENABLED return usbd_edpt_release(s->rhport, s->ep_addr); #endif } - return false; } //--------------------------------------------------------------------+ // Stream Write //--------------------------------------------------------------------+ - -bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes) -{ +bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes) { // ZLP condition: no pending data, last transferred bytes is multiple of packet size - TU_VERIFY( !tu_fifo_count(&s->ff) && last_xferred_bytes && (0 == (last_xferred_bytes & (s->ep_packetsize-1))) ); - - TU_VERIFY( stream_claim(s) ); - TU_ASSERT( stream_xfer(s, 0) ); - + TU_VERIFY(!tu_fifo_count(&s->ff) && last_xferred_bytes && (0 == (last_xferred_bytes & (s->ep_packetsize - 1)))); + TU_VERIFY(stream_claim(s)); + TU_ASSERT(stream_xfer(s, 0)); return true; } -uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) -{ +uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) { // skip if no data - TU_VERIFY( tu_fifo_count(&s->ff), 0 ); + TU_VERIFY(tu_fifo_count(&s->ff), 0); // Claim the endpoint - TU_VERIFY( stream_claim(s), 0 ); + TU_VERIFY(stream_claim(s), 0); // Pull data from FIFO -> EP buf uint16_t const count = tu_fifo_read_n(&s->ff, s->ep_buf, s->ep_bufsize); - if ( count ) - { - TU_ASSERT( stream_xfer(s, count), 0 ); + if (count) { + TU_ASSERT(stream_xfer(s, count), 0); return count; - }else - { + } else { // Release endpoint since we don't make any transfer // Note: data is dropped if terminal is not connected stream_release(s); @@ -352,16 +313,13 @@ uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) } } -uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize) -{ +uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const* buffer, uint32_t bufsize) { TU_VERIFY(bufsize); // TODO support ZLP - uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); // flush if fifo has more than packet size or // in rare case: fifo depth is configured too small (which never reach packet size) - if ( (tu_fifo_count(&s->ff) >= s->ep_packetsize) || (tu_fifo_depth(&s->ff) < s->ep_packetsize) ) - { + if ((tu_fifo_count(&s->ff) >= s->ep_packetsize) || (tu_fifo_depth(&s->ff) < s->ep_packetsize)) { tu_edpt_stream_write_xfer(s); } @@ -371,9 +329,7 @@ uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const *buffer, uint32_t //--------------------------------------------------------------------+ // Stream Read //--------------------------------------------------------------------+ - -uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) -{ +uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) { uint16_t available = tu_fifo_remaining(&s->ff); // Prepare for incoming data but only allow what we can store in the ring buffer. @@ -388,25 +344,21 @@ uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) // get available again since fifo can be changed before endpoint is claimed available = tu_fifo_remaining(&s->ff); - if ( available >= s->ep_packetsize ) - { + if (available >= s->ep_packetsize) { // multiple of packet size limit by ep bufsize - uint16_t count = (uint16_t) (available & ~(s->ep_packetsize -1)); + uint16_t count = (uint16_t) (available & ~(s->ep_packetsize - 1)); count = tu_min16(count, s->ep_bufsize); - TU_ASSERT( stream_xfer(s, count), 0 ); - + TU_ASSERT(stream_xfer(s, count), 0); return count; - }else - { + } else { // Release endpoint since we don't make any transfer stream_release(s); return 0; } } -uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize) -{ +uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize) { uint32_t num_read = tu_fifo_read_n(&s->ff, buffer, (uint16_t) bufsize); tu_edpt_stream_read_xfer(s); return num_read; @@ -419,39 +371,36 @@ uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize #if CFG_TUSB_DEBUG #include -#if CFG_TUSB_DEBUG >= 2 - -char const* const tu_str_speed[] = { "Full", "Low", "High" }; -char const* const tu_str_std_request[] = -{ - "Get Status" , - "Clear Feature" , - "Reserved" , - "Set Feature" , - "Reserved" , - "Set Address" , - "Get Descriptor" , - "Set Descriptor" , - "Get Configuration" , - "Set Configuration" , - "Get Interface" , - "Set Interface" , - "Synch Frame" +#if CFG_TUSB_DEBUG >= CFG_TUH_LOG_LEVEL || CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL +char const* const tu_str_speed[] = {"Full", "Low", "High"}; +char const* const tu_str_std_request[] = { + "Get Status", + "Clear Feature", + "Reserved", + "Set Feature", + "Reserved", + "Set Address", + "Get Descriptor", + "Set Descriptor", + "Get Configuration", + "Set Configuration", + "Get Interface", + "Set Interface", + "Synch Frame" }; +char const* const tu_str_xfer_result[] = { + "OK", "FAILED", "STALLED", "TIMEOUT" +}; #endif -static void dump_str_line(uint8_t const* buf, uint16_t count) -{ +static void dump_str_line(uint8_t const* buf, uint16_t count) { tu_printf(" |"); - // each line is 16 bytes - for(uint16_t i=0; i= 900 && CFG_TUSB_MCU < 1000) // check if Espressif MCU // Dialog #define OPT_MCU_DA1469X 1000 ///< Dialog Semiconductor DA1469x @@ -119,7 +132,9 @@ // NXP Kinetis #define OPT_MCU_KINETIS_KL 1200 ///< NXP KL series -#define OPT_MCU_KINETIS_K32 1201 ///< NXP K32 series +#define OPT_MCU_KINETIS_K32L 1201 ///< NXP K32L series +#define OPT_MCU_KINETIS_K32 1201 ///< Alias to K32L +#define OPT_MCU_KINETIS_K 1202 ///< NXP K series #define OPT_MCU_MKL25ZXX 1200 ///< Alias to KL (obsolete) #define OPT_MCU_K32L2BXX 1201 ///< Alias to K32 (obsolete) @@ -133,7 +148,6 @@ #define OPT_MCU_RX72N 1402 ///< Renesas RX72N #define OPT_MCU_RAXXX 1403 ///< Renesas RAxxx families - // Mind Motion #define OPT_MCU_MM32F327X 1500 ///< Mind Motion MM32F327 @@ -165,11 +179,17 @@ // WCH #define OPT_MCU_CH32V307 2200 ///< WCH CH32V307 +#define OPT_MCU_CH32F20X 2210 ///< WCH CH32F20x + -// Helper to check if configured MCU is one of listed +// NXP LPC MCX +#define OPT_MCU_MCXN9 2300 ///< NXP MCX N9 Series +#define OPT_MCU_MCXA15 2301 ///< NXP MCX A15 Series + +// Check if configured MCU is one of listed // Apply _TU_CHECK_MCU with || as separator to list of input -#define _TU_CHECK_MCU(_m) (CFG_TUSB_MCU == _m) -#define TU_CHECK_MCU(...) (TU_ARGS_APPLY(_TU_CHECK_MCU, ||, __VA_ARGS__)) +#define _TU_CHECK_MCU(_m) (CFG_TUSB_MCU == _m) +#define TU_CHECK_MCU(...) (TU_ARGS_APPLY(_TU_CHECK_MCU, ||, __VA_ARGS__)) //--------------------------------------------------------------------+ // Supported OS @@ -274,7 +294,7 @@ // In case TUP_MCU_STRICT_ALIGN = 1 and TUP_ARCH_STRICT_ALIGN =0, we will not reply on compiler // to generate unaligned access code. // LPC_IP3511 Highspeed cannot access unaligned memory on USB_RAM -#if TUD_OPT_HIGH_SPEED && (CFG_TUSB_MCU == OPT_MCU_LPC54XXX || CFG_TUSB_MCU == OPT_MCU_LPC55XX) +#if TUD_OPT_HIGH_SPEED && TU_CHECK_MCU(OPT_MCU_LPC54XXX, OPT_MCU_LPC55XX) #define TUP_MCU_STRICT_ALIGN 1 #else #define TUP_MCU_STRICT_ALIGN 0 @@ -290,15 +310,24 @@ #define CFG_TUSB_DEBUG 0 #endif -// TODO MEM_SECTION can be different for host and device controller -// should use CFG_TUD_MEM_SECTION, CFG_TUH_MEM_SECTION +// Level where CFG_TUSB_DEBUG must be at least for USBH is logged +#ifndef CFG_TUH_LOG_LEVEL + #define CFG_TUH_LOG_LEVEL 2 +#endif + +// Level where CFG_TUSB_DEBUG must be at least for USBD is logged +#ifndef CFG_TUD_LOG_LEVEL + #define CFG_TUD_LOG_LEVEL 2 +#endif + +// Memory section for placing buffer used for usb transferring. If MEM_SECTION is different for +// host and device use: CFG_TUD_MEM_SECTION, CFG_TUH_MEM_SECTION instead #ifndef CFG_TUSB_MEM_SECTION #define CFG_TUSB_MEM_SECTION #endif -// alignment requirement of buffer used for endpoint transferring -// TODO MEM_ALIGN can be different for host and device controller -// should use CFG_TUD_MEM_ALIGN, CFG_TUH_MEM_ALIGN +// Alignment requirement of buffer used for usb transferring. if MEM_ALIGN is different for +// host and device controller use: CFG_TUD_MEM_ALIGN, CFG_TUH_MEM_ALIGN instead #ifndef CFG_TUSB_MEM_ALIGN #define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4) #endif @@ -316,24 +345,14 @@ // Device Options (Default) //-------------------------------------------------------------------- -// Attribute to place data in accessible RAM for device controller -// default to CFG_TUSB_MEM_SECTION for backward-compatible +// Attribute to place data in accessible RAM for device controller (default: CFG_TUSB_MEM_SECTION) #ifndef CFG_TUD_MEM_SECTION - #ifdef CFG_TUSB_MEM_SECTION - #define CFG_TUD_MEM_SECTION CFG_TUSB_MEM_SECTION - #else - #define CFG_TUD_MEM_SECTION - #endif + #define CFG_TUD_MEM_SECTION CFG_TUSB_MEM_SECTION #endif -// Attribute to align memory for device controller -// default to CFG_TUSB_MEM_ALIGN for backward-compatible +// Attribute to align memory for device controller (default: CFG_TUSB_MEM_ALIGN) #ifndef CFG_TUD_MEM_ALIGN - #ifdef CFG_TUSB_MEM_ALIGN - #define CFG_TUD_MEM_ALIGN CFG_TUSB_MEM_ALIGN - #else - #define CFG_TUD_MEM_ALIGN TU_ATTR_ALIGNED(4) - #endif + #define CFG_TUD_MEM_ALIGN CFG_TUSB_MEM_ALIGN #endif #ifndef CFG_TUD_ENDPOINT0_SIZE @@ -344,6 +363,15 @@ #define CFG_TUD_INTERFACE_MAX 16 #endif +//------------- Device Class Driver -------------// +#ifndef CFG_TUD_BTH + #define CFG_TUD_BTH 0 +#endif + +#if CFG_TUD_BTH && !defined(CFG_TUD_BTH_ISO_ALT_COUNT) +#error CFG_TUD_BTH_ISO_ALT_COUNT must be defined to tell Bluetooth driver the number of ISO endpoints to use +#endif + #ifndef CFG_TUD_CDC #define CFG_TUD_CDC 0 #endif @@ -384,10 +412,6 @@ #define CFG_TUD_DFU 0 #endif -#ifndef CFG_TUD_BTH - #define CFG_TUD_BTH 0 -#endif - #ifndef CFG_TUD_ECM_RNDIS #ifdef CFG_TUD_NET #warning "CFG_TUD_NET is renamed to CFG_TUD_ECM_RNDIS" @@ -414,29 +438,24 @@ #endif #endif // CFG_TUH_ENABLED -// Attribute to place data in accessible RAM for host controller -// default to CFG_TUSB_MEM_SECTION for backward-compatible +// Attribute to place data in accessible RAM for host controller (default: CFG_TUSB_MEM_SECTION) #ifndef CFG_TUH_MEM_SECTION - #ifdef CFG_TUSB_MEM_SECTION - #define CFG_TUH_MEM_SECTION CFG_TUSB_MEM_SECTION - #else - #define CFG_TUH_MEM_SECTION - #endif + #define CFG_TUH_MEM_SECTION CFG_TUSB_MEM_SECTION #endif // Attribute to align memory for host controller #ifndef CFG_TUH_MEM_ALIGN - #define CFG_TUH_MEM_ALIGN TU_ATTR_ALIGNED(4) + #define CFG_TUH_MEM_ALIGN CFG_TUSB_MEM_ALIGN #endif //------------- CLASS -------------// #ifndef CFG_TUH_HUB -#define CFG_TUH_HUB 0 + #define CFG_TUH_HUB 0 #endif #ifndef CFG_TUH_CDC -#define CFG_TUH_CDC 0 + #define CFG_TUH_CDC 0 #endif #ifndef CFG_TUH_CDC_FTDI @@ -444,40 +463,85 @@ #define CFG_TUH_CDC_FTDI 0 #endif +#ifndef CFG_TUH_CDC_FTDI_VID_PID_LIST + // List of product IDs that can use the FTDI CDC driver. 0x0403 is FTDI's VID + #define CFG_TUH_CDC_FTDI_VID_PID_LIST \ + {0x0403, 0x6001}, {0x0403, 0x6006}, {0x0403, 0x6010}, {0x0403, 0x6011}, \ + {0x0403, 0x6014}, {0x0403, 0x6015}, {0x0403, 0x8372}, {0x0403, 0xFBFA}, \ + {0x0403, 0xCD18} +#endif + #ifndef CFG_TUH_CDC_CP210X // CP210X is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CP210X 0 #endif +#ifndef CFG_TUH_CDC_CP210X_VID_PID_LIST + // List of product IDs that can use the CP210X CDC driver. 0x10C4 is Silicon Labs' VID + #define CFG_TUH_CDC_CP210X_VID_PID_LIST \ + {0x10C4, 0xEA60}, {0x10C4, 0xEA70} +#endif + +#ifndef CFG_TUH_CDC_CH34X + // CH34X is not part of CDC class, only to re-use CDC driver API + #define CFG_TUH_CDC_CH34X 0 +#endif + +#ifndef CFG_TUH_CDC_CH34X_VID_PID_LIST + // List of product IDs that can use the CH34X CDC driver + #define CFG_TUH_CDC_CH34X_VID_PID_LIST \ + { 0x1a86, 0x5523 }, /* ch341 chip */ \ + { 0x1a86, 0x7522 }, /* ch340k chip */ \ + { 0x1a86, 0x7523 }, /* ch340 chip */ \ + { 0x1a86, 0xe523 }, /* ch330 chip */ \ + { 0x4348, 0x5523 }, /* ch340 custom chip */ \ + { 0x2184, 0x0057 }, /* overtaken from Linux Kernel driver /drivers/usb/serial/ch341.c */ \ + { 0x9986, 0x7523 } /* overtaken from Linux Kernel driver /drivers/usb/serial/ch341.c */ +#endif + #ifndef CFG_TUH_HID -#define CFG_TUH_HID 0 + #define CFG_TUH_HID 0 #endif #ifndef CFG_TUH_MIDI -#define CFG_TUH_MIDI 0 + #define CFG_TUH_MIDI 0 #endif #ifndef CFG_TUH_MSC -#define CFG_TUH_MSC 0 + #define CFG_TUH_MSC 0 #endif #ifndef CFG_TUH_VENDOR -#define CFG_TUH_VENDOR 0 + #define CFG_TUH_VENDOR 0 #endif #ifndef CFG_TUH_API_EDPT_XFER -#define CFG_TUH_API_EDPT_XFER 0 + #define CFG_TUH_API_EDPT_XFER 0 #endif // Enable PIO-USB software host controller #ifndef CFG_TUH_RPI_PIO_USB -#define CFG_TUH_RPI_PIO_USB 0 + #define CFG_TUH_RPI_PIO_USB 0 #endif #ifndef CFG_TUD_RPI_PIO_USB -#define CFG_TUD_RPI_PIO_USB 0 + #define CFG_TUD_RPI_PIO_USB 0 #endif +// MAX3421 Host controller option +#ifndef CFG_TUH_MAX3421 + #define CFG_TUH_MAX3421 0 +#endif + +//--------------------------------------------------------------------+ +// TypeC Options (Default) +//--------------------------------------------------------------------+ + +#ifndef CFG_TUC_ENABLED +#define CFG_TUC_ENABLED 0 + +#define tuc_int_handler(_p) +#endif //------------------------------------------------------------------ // Configuration Validation diff --git a/test-devices/loopback-stm32/src/vendor_custom.c b/test-devices/loopback-stm32/src/vendor_custom.c index a408fc5a..cebf47b7 100644 --- a/test-devices/loopback-stm32/src/vendor_custom.c +++ b/test-devices/loopback-stm32/src/vendor_custom.c @@ -19,6 +19,8 @@ #include "device/usbd.h" #include "vendor_custom.h" +void dcd_edpt_close_all(uint8_t rhport); + static void cv_init(void); static void cv_reset(uint8_t rhport); @@ -136,6 +138,8 @@ void close_endpoints() { cv_num_eps_open -= 1; usbd_edpt_close(rhport, cv_eps_open[cv_num_eps_open]); } + + dcd_edpt_close_all(rhport); } bool cv_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) { From cc2ac047095e6378882c422a336dd95dc3c48058 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 18 Aug 2024 10:09:33 +0200 Subject: [PATCH 362/433] Test device: fix ZLP handling --- .../net/codecrete/usb/TestDeviceBase.java | 29 +++++++++---------- .../java/net/codecrete/usb/TimeoutTest.java | 13 ++------- test-devices/composite-stm32/src/main.c | 20 ++++++++----- test-devices/loopback-stm32/src/main.c | 16 ++++++++-- 4 files changed, 42 insertions(+), 36 deletions(-) diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index 9b81680f..e3c9adb3 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -68,24 +68,11 @@ private static void resetDevice() { resetBuffers(); // drain loopback data - while (true) { - try { - testDevice.transferIn(config.endpointLoopbackIn(), 1); - } catch (UsbTimeoutException e) { - break; - } - } + drainData(config.endpointLoopbackIn()); // drain interrupt data - if (isLoopbackDevice()) { - while (true) { - try { - testDevice.transferIn(config.endpointEchoIn(), 1); - } catch (UsbTimeoutException e) { - break; - } - } - } + if (isLoopbackDevice()) + drainData(config.endpointEchoIn()); // reset buffers again resetBuffers(); @@ -96,6 +83,16 @@ static void resetBuffers() { (byte) 0x04, (short) 0, (short) config.interfaceNumber()), null); } + static void drainData(int endpointNumber) { + while (true) { + try { + testDevice.transferIn(endpointNumber, 1); + } catch (UsbTimeoutException e) { + break; + } + } + } + static byte[] generateRandomBytes(int numBytes, long seed) { var random = new Random(seed); var bytes = new byte[numBytes]; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java index b9028797..b7b9c4a8 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java @@ -34,16 +34,14 @@ void bulkTransfer_doesNotTimeOut() { var data = generateRandomBytes(20, 7280277392L); testDevice.transferOut(config.endpointLoopbackOut(), data); - var received = testDevice.transferIn(config.endpointLoopbackIn(), 200); + var received = testDevice.transferIn(config.endpointLoopbackIn(), 200); assertArrayEquals(data, received); - } @Test @Timeout(value = 1, unit = TimeUnit.SECONDS) void bulkTransferOut_timesOut() { var endpointOut = config.endpointLoopbackOut(); - var endpointIn = config.endpointLoopbackIn(); // The test device has an internal buffer of about 2KB for full-speed // and 16KB for high-speed. The first transfer should not time out. @@ -59,14 +57,7 @@ void bulkTransferOut_timesOut() { } }); - // drain data in loopback loop - while (true) { - try { - testDevice.transferIn(endpointIn, 200); - } catch (UsbTimeoutException e) { - break; - } - } + drainData(config.endpointLoopbackIn()); } @Test diff --git a/test-devices/composite-stm32/src/main.c b/test-devices/composite-stm32/src/main.c index 0ae69a2f..0259b140 100644 --- a/test-devices/composite-stm32/src/main.c +++ b/test-devices/composite-stm32/src/main.c @@ -21,6 +21,7 @@ // FIFO buffer for loopback data tu_fifo_t loopback_fifo; uint8_t loopback_buffer[512]; +bool delay_loopback_reset = false; // RX buffer for loopback uint8_t loopback_rx_buffer[64]; @@ -62,7 +63,11 @@ int main(void) { // reset device in predictable state void reset_buffers(void) { - tu_fifo_clear(&loopback_fifo); + if (cust_vendor_is_transmitting(EP_LOOPBACK_TX)) { + delay_loopback_reset = true; + } else { + tu_fifo_clear(&loopback_fifo); + } } // --- Loopback @@ -74,6 +79,11 @@ void loopback_init(void) { // Check if the next transmission should be started void loopback_check_tx(void) { + if (delay_loopback_reset) { + tu_fifo_clear(&loopback_fifo); + delay_loopback_reset = false; + } + tu_fifo_buffer_info_t info; tu_fifo_get_read_info(&loopback_fifo, &info); @@ -123,11 +133,6 @@ void cust_vendor_rx_cb(uint8_t ep_addr, uint32_t recv_bytes) { // Invoked when last tx transfer finished void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes) { - // If buffer has been reset in the mean time, - // we might not be able to advance it fully or at all. - int max_advance = tu_fifo_count(&loopback_fifo); - if (sent_bytes > max_advance) - sent_bytes = max_advance; if (sent_bytes > 0) tu_fifo_advance_read_pointer(&loopback_fifo, sent_bytes); @@ -135,7 +140,8 @@ void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes) { loopback_check_rx(); // check ZLP - if ((sent_bytes & (BULK_MAX_PACKET_SIZE - 1)) == 0 + if (sent_bytes > 0 + && (sent_bytes & (BULK_MAX_PACKET_SIZE - 1)) == 0 && !cust_vendor_is_transmitting(ep_addr)) cust_vendor_start_transmit(EP_LOOPBACK_TX, NULL, 0); diff --git a/test-devices/loopback-stm32/src/main.c b/test-devices/loopback-stm32/src/main.c index 94495653..d826197e 100644 --- a/test-devices/loopback-stm32/src/main.c +++ b/test-devices/loopback-stm32/src/main.c @@ -27,6 +27,7 @@ // FIFO buffer for loopback data tu_fifo_t loopback_fifo; uint8_t loopback_buffer[BUFFER_SIZE] __attribute__ ((aligned(4))); +bool delay_loopback_reset = false; uint16_t bulk_packet_size = 64; const int num_rx_packets = 2; @@ -74,7 +75,12 @@ int main(void) { // reset device in predictable state void reset_buffers(void) { - tu_fifo_clear(&loopback_fifo); + if (cust_vendor_is_transmitting(EP_LOOPBACK_TX)) { + delay_loopback_reset = true; + } else { + tu_fifo_clear(&loopback_fifo); + } + num_echos = 0; } @@ -87,6 +93,11 @@ void loopback_init(void) { // Check if the next transmission should be started void loopback_check_tx(void) { + if (delay_loopback_reset) { + tu_fifo_clear(&loopback_fifo); + delay_loopback_reset = false; + } + uint16_t n = tu_fifo_count(&loopback_fifo); if (n > 0 && !cust_vendor_is_transmitting(EP_LOOPBACK_TX)) { @@ -143,7 +154,8 @@ void cust_vendor_tx_cb(uint8_t ep_addr, uint32_t sent_bytes) { loopback_check_rx(); // check ZLP - if ((sent_bytes & (bulk_packet_size - 1)) == 0 + if (sent_bytes > 0 + && (sent_bytes & (bulk_packet_size - 1)) == 0 && !cust_vendor_is_transmitting(ep_addr)) { cust_vendor_start_transmit(EP_LOOPBACK_TX, NULL, 0); led_busy(); From 0c8e5f2bab03b3f333a168b7552df0d8e14b3bdc Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 18 Aug 2024 12:50:11 +0200 Subject: [PATCH 363/433] Linux: robuster test timing --- .../src/test/java/net/codecrete/usb/TestDeviceBase.java | 2 +- java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index e3c9adb3..9fff5237 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -86,7 +86,7 @@ static void resetBuffers() { static void drainData(int endpointNumber) { while (true) { try { - testDevice.transferIn(endpointNumber, 1); + testDevice.transferIn(endpointNumber, 2); } catch (UsbTimeoutException e) { break; } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java index b7b9c4a8..80f19b23 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java @@ -22,7 +22,7 @@ class TimeoutTest extends TestDeviceBase { @Test - @Timeout(value = 1, unit = TimeUnit.SECONDS) + @Timeout(value = 2, unit = TimeUnit.SECONDS) void bulkTransferIn_timesOut() { var endpointIn = config.endpointLoopbackIn(); assertThrows(UsbTimeoutException.class, () -> testDevice.transferIn(endpointIn, 200)); From 0f1d2efc2024f8658c7a560c9602037a820f1187 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Sun, 13 Oct 2024 11:08:02 +0200 Subject: [PATCH 364/433] Windows: Helpful error message if WinUSB driver not installed --- java-does-usb/jextract/windows/gen_win.cmd | 1 + java-does-usb/pom.xml | 1 + .../java/net/codecrete/usb/UsbException.java | 2 +- .../codecrete/usb/windows/WindowsUsbDevice.java | 16 ++++++++++++---- .../usb/windows/gen/kernel32/Kernel32.java | 9 +++++++++ 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd index d0cf4f12..fe8a7c99 100644 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ b/java-does-usb/jextract/windows/gen_win.cmd @@ -19,6 +19,7 @@ call %JEXTRACT% --output ../../src/main/java ^ --include-constant ERROR_MORE_DATA ^ --include-constant ERROR_INSUFFICIENT_BUFFER ^ --include-constant ERROR_FILE_NOT_FOUND ^ + --include-constant ERROR_INVALID_PARAMETER ^ --include-constant ERROR_GEN_FAILURE ^ --include-constant ERROR_NOT_FOUND ^ --include-constant ERROR_IO_PENDING ^ diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 5eb88b45..2d7a807c 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -12,6 +12,7 @@ 22 22 UTF-8 + src/main/java/net/codecrete/usb/**/gen/**/*
Java Does USB diff --git a/java-does-usb/src/main/java/net/codecrete/usb/UsbException.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbException.java index d5e07fa3..e0c62acb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/UsbException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbException.java @@ -37,7 +37,7 @@ public UsbException(@NotNull String message) { * @param errorCode the error code */ public UsbException(@NotNull String message, int errorCode) { - super(message + " (error code:" + errorCode + ")"); + super(message + " (error code: " + errorCode + ")"); code = errorCode; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java index f2a11b05..d59e071e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java @@ -42,6 +42,7 @@ import static net.codecrete.usb.windows.Win.allocateErrorState; import static net.codecrete.usb.windows.WindowsUsbException.throwException; import static net.codecrete.usb.windows.WindowsUsbException.throwLastError; +import static net.codecrete.usb.windows.gen.kernel32.Kernel32.ERROR_INVALID_PARAMETER; /** * Windows implementation for USB device. @@ -121,7 +122,7 @@ public void claimInterface(int interfaceNumber) { // retries might be needed until the device path is available. var numRetries = 30; // 30 x 100ms while (true) { - if (claimInteraceSynchronized(interfaceNumber)) + if (claimInterfaceSynchronized(interfaceNumber)) return; // success numRetries -= 1; @@ -139,7 +140,8 @@ public void claimInterface(int interfaceNumber) { } } - private synchronized boolean claimInteraceSynchronized(int interfaceNumber) { + @SuppressWarnings("java:S3776") + private synchronized boolean claimInterfaceSynchronized(int interfaceNumber) { checkIsOpen(); getInterfaceWithCheck(interfaceNumber, false); @@ -172,8 +174,14 @@ private synchronized boolean claimInteraceSynchronized(int interfaceNumber) { try { // open first interface var interfaceHandleHolder = arena.allocate(ADDRESS); - if (WinUSB2.WinUsb_Initialize(deviceHandle, interfaceHandleHolder, errorState) == 0) + if (WinUSB2.WinUsb_Initialize(deviceHandle, interfaceHandleHolder, errorState) == 0) { + if (Win.getLastError(errorState) == ERROR_INVALID_PARAMETER()) + throw new UsbException( + "claiming interface failed (required WinUSB driver is probably not installed for the device)", + ERROR_INVALID_PARAMETER() + ); throwLastError(errorState, "claiming interface failed"); + } var interfaceHandle = dereference(interfaceHandleHolder); firstIntfHandle.deviceHandle = deviceHandle; @@ -571,7 +579,7 @@ private String getChildDevicePath(String instanceId, int interfaceNumber) { var devicePath = deviceInfoSet.getDevicePathByGUID(instanceId); if (devicePath == null) { LOG.log(INFO, "Child device {0} has no device path / interface GUID", instanceId); - throw new UsbException("claiming interface failed (function has no device path / interface GUID, might be missing WinUSB driver)"); + throw new UsbException("claiming interface failed (composite function has no device path / interface GUID; the required WinUSB driver is probably not installed)"); } if (devicePaths == null) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java index fcd1d7b3..5bf1f30c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java @@ -390,6 +390,15 @@ public static int ERROR_FILE_NOT_FOUND() { public static int ERROR_GEN_FAILURE() { return ERROR_GEN_FAILURE; } + private static final int ERROR_INVALID_PARAMETER = (int)87L; + /** + * {@snippet lang=c : + * #define ERROR_INVALID_PARAMETER 87 + * } + */ + public static int ERROR_INVALID_PARAMETER() { + return ERROR_INVALID_PARAMETER; + } private static final int ERROR_INSUFFICIENT_BUFFER = (int)122L; /** * {@snippet lang=c : From b434f4b2e094520226fa264a4f08e304c67be331 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Sun, 13 Oct 2024 11:36:00 +0200 Subject: [PATCH 365/433] Windows: Query string descriptor languages --- .../usb/windows/WindowsUsbDeviceRegistry.java | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java index b6998125..dd5086d9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java @@ -44,6 +44,7 @@ import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_INT; import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; import static java.lang.foreign.ValueLayout.PathElement; import static net.codecrete.usb.usbstandard.Constants.CONFIGURATION_DESCRIPTOR_TYPE; import static net.codecrete.usb.usbstandard.Constants.DEFAULT_LANGUAGE; @@ -225,8 +226,9 @@ private UsbDevice createDevice(String devicePath, boolean isComposite, MemorySeg // create new device var device = new WindowsUsbDevice(devicePath, vendorId, productId, configDesc, isComposite); device.setFromDeviceDescriptor(descriptorSegment); - device.setProductString(descriptorSegment, index -> getStringDescriptor(hubHandle, usbPortNum, index)); + var languages = getLanguages(hubHandle, usbPortNum, arena); + device.setProductString(descriptorSegment, index -> getStringDescriptor(hubHandle, usbPortNum, index, languages)); return device; } } @@ -282,17 +284,37 @@ private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, } @SuppressWarnings("java:S106") - private String getStringDescriptor(MemorySegment hubHandle, int usbPortNumber, int index) { + private String getStringDescriptor(MemorySegment hubHandle, int usbPortNumber, int index, short[] languages) { if (index == 0) return null; try (var arena = Arena.ofConfined()) { - var stringDesc = new StringDescriptor(getDescriptor(hubHandle, usbPortNumber, STRING_DESCRIPTOR_TYPE, - index, DEFAULT_LANGUAGE, arena)); - return stringDesc.string(); + for (var language : languages) { + try { + var stringDesc = new StringDescriptor(getDescriptor(hubHandle, usbPortNumber, STRING_DESCRIPTOR_TYPE, + index, language, arena)); + return stringDesc.string(); + + } catch (UsbException e) { + // ignore and try next language + } + } + } + + // Even though this function is only called for string descriptors referenced in the + // configuration descriptor, some device might not provide them; so ignore it. + return null; + } + private short[] getLanguages(MemorySegment hubHandle, int usbPortNumber, Arena arena) { + try { + var languages = getDescriptor(hubHandle, usbPortNumber, STRING_DESCRIPTOR_TYPE, 0, (short) 0, arena); + var n = (languages.byteSize() - 2) / 2; + if (n == 0) + return new short[] { DEFAULT_LANGUAGE }; + return languages.asSlice(2, n * 2).toArray(JAVA_SHORT); } catch (UsbException e) { - return null; + return new short[] { DEFAULT_LANGUAGE }; } } From be52fc47fb2053c29209dfb598ea7bae42db3608 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Sun, 13 Oct 2024 11:46:11 +0200 Subject: [PATCH 366/433] Pipeline: Use Java 23 --- .github/workflows/continuous-integration.yaml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index 44fa638c..529a6190 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -26,11 +26,10 @@ jobs: steps: - uses: actions/checkout@v4 - name: Setup Java - uses: oracle-actions/setup-java@v1 + uses: actions/setup-java@v4 with: - website: jdk.java.net - release: 22 - version: latest + distribution: 'zulu' + java-version: '23' - name: Configure unit test GPG key run: | echo -n "$UNIT_TEST_SIGNING_KEY" | base64 --decode | gpg --import From a690c723b9fdde0a0042e09a7d49a8cbc21a528b Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 13 Oct 2024 13:50:24 +0200 Subject: [PATCH 367/433] Increase version to 1.1.0 --- README.md | 26 +++++++++++++------------- examples/bulk_transfer/README.md | 8 ++++---- examples/bulk_transfer/pom.xml | 4 ++-- examples/enumerate/README.md | 6 +++--- examples/enumerate/pom.xml | 4 ++-- examples/enumerate_kotlin/README.md | 6 +++--- examples/enumerate_kotlin/pom.xml | 4 ++-- examples/epaper_display/README.md | 10 +++++----- examples/epaper_display/pom.xml | 4 ++-- examples/monitor/README.md | 8 ++++---- examples/monitor/pom.xml | 4 ++-- examples/monitor_kotlin/README.md | 6 +++--- examples/monitor_kotlin/pom.xml | 4 ++-- examples/stm_dfu/README.md | 6 +++--- examples/stm_dfu/pom.xml | 4 ++-- java-does-usb/pom.xml | 2 +- 16 files changed, 53 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 329cca3a..20550947 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ [![javadoc](https://javadoc.io/badge2/net.codecrete.usb/java-does-usb/javadoc.svg)](https://javadoc.io/doc/net.codecrete.usb/java-does-usb) -*Java Does USB* is a Java library for working with USB devices. It allows to query the conntected USB devices and to communicate with them using custom / vendor specific protocols. (It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc.) +*Java Does USB* is a Java library for working with USB devices. It allows to query the conntected USB devices and to communicate with them using custom / vendor specific protocols. It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc. -The library uses the [Foreign Function and Memory API](https://docs.oracle.com/en/java/javase/21/core/foreign-function-and-memory-api.html#GUID-FBE990DA-C356-46E8-9109-C75567849BA8) to access native APIs of the underlying operating system. It is written entirely in Java and does not use JNI or any native third-party library. The *Foreign Function and Memory API* has been introduced with Java 22. Preview versions were available in several earlier releases. +The library uses the [Foreign Function and Memory API](https://docs.oracle.com/en/java/javase/22/core/foreign-function-and-memory-api.html) to access native APIs of the underlying operating system. It is written entirely in Java and does not use JNI or any native third-party library. The *Foreign Function and Memory API* has been introduced with Java 22. @@ -31,14 +31,14 @@ If you are using Maven, add the below dependency to your pom.xml: net.codecrete.usb java-does-usb - 1.0.0 + 1.1.0 ``` If you are using Gradle, add the below dependency to your build.gradle file: ```groovy -compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '1.0.0' +compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '1.1.0' ``` ```java @@ -69,7 +69,7 @@ public class EnumerateDevices { - [Bulk Transfer](examples/bulk_transfer/) demonstrates how to find a USB device, open it and communicate using bulk transfer. - Enumeration ([Java](examples/enumerate/) / [Kotlin](examples/enumerate_kotlin/)) lists all connected USB devices and displays information about interfaces and endpoints. -- Monitor ([Java](examples/monitor/) / [Kotlin](examples/monitor_kotlin/)) lists the connected USB devices and then monitors for devices being connected and disconnnected. +- Monitor ([Java](examples/monitor/) / [Kotlin](examples/monitor_kotlin/)) lists the connected USB devices and then monitors for devices being connected and disconnected. - [Device Firmware Upload (DFU) for STM32](examples/stm_dfu) uploads firmware to STM32 microcontrollers supporting the built-in DFU mode. - [ePaper Display](examples/epaper_display) communicates with an IT8951 controller for e-Paper displays and shows an image on the display. @@ -77,8 +77,8 @@ public class EnumerateDevices { ## Prerequisite -- Java 22 available at [jdk.java.net](https://jdk.java.net/21/), [Azul](https://www.azul.com/downloads/?package=jdk), [Adoptium](https://adoptium.net/temurin/releases/) or with your favorite package manager. -- Windows (x86 64-bit), macOS (x86 64-bit, ARM 64-bit) or Linux 64 bit (x86 64-bit, ARM 64-bit) +- Java 22 or higher, available at [jdk.java.net](https://jdk.java.net/), [Azul](https://www.azul.com/downloads/?package=jdk), [Adoptium](https://adoptium.net/temurin/releases/) or with your favorite package manager. +- Windows (x86 64-bit), macOS (x86 64-bit, ARM 64-bit) or Linux 64 bit (x86 64-bit, ARM 64-bit). @@ -87,14 +87,14 @@ public class EnumerateDevices { ### macOS -No special considerations apply. Using this library, a Java application can connect to any USB device and claim any interfaces that isn't claimed by an operating system driver or another application. Standard operation system drivers can be unloaded if the application is run with root privileges. It runs both on Macs with Apple Silicon and Intel processors. +No special considerations apply. Using this library, a Java application can connect to any USB device and claim any interface that isn't claimed by an operating system driver or another application. Standard operation system drivers can be unloaded if the application is run with *root* privileges. It runs both on Macs with Apple Silicon and Intel processors. ### Linux -*libudev* is used to discover and monitor USB devices. It is closely tied to *systemd*. So the library only runs on Linux distributions with *systemd* and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfill this requirement. It runs on both Intel and ARM64 processors. +*libudev* is used to discover and monitor USB devices. It is closely tied to *systemd*. So the library runs on Linux distributions with *systemd* and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfill this requirement. It runs on both Intel and ARM64 processors. -Similar to macOS, a Java application can connect to any USB device and claim any interfaces that isn't claimed by an operating system driver or another application. Standard operation system drivers can be unloaded (without the need for root privileges). +Similar to macOS, a Java application can connect to any USB device and claim any interface that isn't claimed by an operating system driver or another application. Standard operation system drivers can be unloaded (without the need for root privileges). Most Linux distributions set up user accounts without permissions to access USB devices. The *udev* system daemon is responsible for assigning permissions to USB devices. It can be configured to assign specific permissions or ownership: @@ -111,13 +111,13 @@ Without the *udev* rule, it is still possible to enumerate and query all USB dev ### Windows -The Windows driver model is rather rigid. It's not possible to open any USB device unless it uses the *WinUSB* driver. This even applies to devices with no installed driver. Enumerating and querying USB devices is possible independent of the driver. +The Windows driver model is rather rigid. It's not possible to open a USB device unless it uses the *WinUSB* driver. This even applies to devices with no installed driver. Enumerating and querying USB devices is possible independent of the driver. USB devices can implement special control requests to instruct Windows to automatically install the WinUSB driver (search for *WCID* or *Microsoft OS Compatibility Descriptors*). The WinUSB driver can also be manually installed or replaced using a software called [Zadig](https://zadig.akeo.ie/). The test devices implement the required control requests. So the driver is installed automatically. -Windows for ARM64 is not yet supported. A port is probably easy, provided you have hardware to test it. +Windows for ARM64 is not yet supported. It will once an official Java build for version 22 or higher is available. @@ -135,7 +135,7 @@ The *Foreign Function And Memory API* has been available as a preview feature in | Version | Main New Features | Compatibility | | - | - | - | -| 1.0.x | Release for final Java API | JDK 22 | +| 1.x.x | Release for final Java API | JDK 22 and higher | | 0.7.x | New setter/getter names for improved Kotlin support; Kotlin examples | JDK 21 | | 0.6.x | Support for JDK 21; better handling of composite devices on Windows | JDK 21 | | 0.5.x | Support for JDK 20; high-throuput I/O streams | JDK 20 | diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index 4e03d796..8a86e903 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -11,9 +11,9 @@ This sample shows how to find a device, open it and transfer data from and to bu ## How to run -### Install Java 22 +### Install Java 22 or higher -Check that *Java 22* is installed: +Check that Java 22 or higher is installed: ```shell $ java -version @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] --------------< net.codecrete.usb.examples:bulk-transfer >-------------- -[INFO] Building bulk-transfer 1.0.0 +[INFO] Building bulk-transfer 1.1.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ bulk-transfer --- @@ -55,6 +55,6 @@ $ mvn compile exec:exec [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.228 s -[INFO] Finished at: 2024-02-18T16:23:29+01:00 +[INFO] Finished at: 2024-10-13T16:23:29+01:00 [INFO] ------------------------------------------------------------------------ ``` diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index a7f46a50..f822cd69 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples bulk-transfer - 1.0.0 + 1.1.0 bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.0.0 + 1.1.0 diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index fcb26056..4c828744 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -10,9 +10,9 @@ This sample enumerates the connected USB devices and provides information about ## How to run -### Install Java 22 +### Install Java 22 or higher -Check that *Java 22* is installed: +Check that Java 22 or higher is installed: ```shell $ java -version @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] ----------------< net.codecrete.usb.examples:enumerate >---------------- -[INFO] Building enumerate 1.0.0 +[INFO] Building enumerate 1.1.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ enumerate --- diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index b4f4cf4d..0da4fb2d 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples enumerate - 1.0.0 + 1.1.0 enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.0.0 + 1.1.0 org.tinylog diff --git a/examples/enumerate_kotlin/README.md b/examples/enumerate_kotlin/README.md index 57b40728..e5dd07ab 100644 --- a/examples/enumerate_kotlin/README.md +++ b/examples/enumerate_kotlin/README.md @@ -10,9 +10,9 @@ This sample enumerates the connected USB devices and provides information about ## How to run -### Install Java 22 +### Install Java 22 or higher -Check that *Java 22* is installed: +Check that Java 22 or higher is installed: ```shell $ java -version @@ -40,7 +40,7 @@ $ mvn clean package ### Run the jar ```shell -$ java --enable-native-access=ALL-UNNAMED -jar target/enumerate-1.0.0-jar-with-dependencies.jar +$ java --enable-native-access=ALL-UNNAMED -jar target/enumerate-1.1.0-jar-with-dependencies.jar Device: VID: 0xcafe PID: 0xceaf diff --git a/examples/enumerate_kotlin/pom.xml b/examples/enumerate_kotlin/pom.xml index 57234065..19cc08ec 100644 --- a/examples/enumerate_kotlin/pom.xml +++ b/examples/enumerate_kotlin/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples enumerate - 1.0.0 + 1.1.0 jar enumerate @@ -64,7 +64,7 @@ net.codecrete.usb java-does-usb - 1.0.0 + 1.1.0 org.tinylog diff --git a/examples/epaper_display/README.md b/examples/epaper_display/README.md index 27789d50..7d29543a 100644 --- a/examples/epaper_display/README.md +++ b/examples/epaper_display/README.md @@ -17,9 +17,9 @@ be temporarily detached.) ## How to run -### Install Java 22 +### Install Java 22 or higher -Check that *Java 22* is installed: +Check that Java 22 or higher is installed: ```shell $ java -version @@ -45,7 +45,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -------------< net.codecrete.usb.examples:epaper-display >-------------- -[INFO] Building epaper-display 1.0.0 +[INFO] Building epaper-display 1.1.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ epaper-display --- @@ -60,7 +60,7 @@ Display size: 1200 x 825 [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 2.247 s -[INFO] Finished at: 2024-02-18T16:48:43+01:00 +[INFO] Finished at: 2024-10-13T16:48:43+01:00 [INFO] ------------------------------------------------------------------------ ``` @@ -79,6 +79,6 @@ $ sudo -i Password: $ cd /Users/me/Documents/JavaDoesUSB/examples/epaper_display $ export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-20.jdk/Contents/Home -$ $JAVA_HOME/bin/java --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/1.0.0/java-does-usb-1.0.0.jar net.codecrete.usb.examples.EPaperDisplay +$ $JAVA_HOME/bin/java --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/1.1.0/java-does-usb-1.1.0.jar net.codecrete.usb.examples.EPaperDisplay Display size: 1200 x 825 ``` diff --git a/examples/epaper_display/pom.xml b/examples/epaper_display/pom.xml index 98b8da45..70c5e816 100644 --- a/examples/epaper_display/pom.xml +++ b/examples/epaper_display/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples epaper-display - 1.0.0 + 1.1.0 epaper-display https://github.com/manuelbl/JavaDoesUSB/examples/epaper_display @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.0.0 + 1.1.0 diff --git a/examples/monitor/README.md b/examples/monitor/README.md index dcd2f672..85e74d74 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -10,9 +10,9 @@ This sample program monitors USB devices as they are connected and disconnected. ## How to run -### Install Java 22 +### Install Java 22 or higher -Check that *Java 22* is installed: +Check that Java 22 or higher is installed: ```shell $ java -version @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -----------------< net.codecrete.usb.examples:monitor >----------------- -[INFO] Building monitor 1.0.0 +[INFO] Building monitor 1.1.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ monitor --- @@ -59,6 +59,6 @@ Connected: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loop [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 17.647 s -[INFO] Finished at: 2024-02-18T16:50:59+01:00 +[INFO] Finished at: 2024-10-13T16:50:59+01:00 [INFO] ----------------------------------------------------------------------- ``` diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index 99c09f6f..28f0e920 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples monitor - 1.0.0 + 1.1.0 monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.0.0 + 1.1.0 org.tinylog diff --git a/examples/monitor_kotlin/README.md b/examples/monitor_kotlin/README.md index 9941837d..ebf7de70 100644 --- a/examples/monitor_kotlin/README.md +++ b/examples/monitor_kotlin/README.md @@ -10,9 +10,9 @@ This sample enumerates the connected USB devices and provides information about ## How to run -### Install Java 22 +### Install Java 22 or higher -Check that *Java 22* is installed: +Check that Java 22 or higher is installed: ```shell $ java -version @@ -40,7 +40,7 @@ $ mvn clean package ### Run the jar ```shell -$ java --enable-native-access=ALL-UNNAMED -jar target/monitor-1.0.0-jar-with-dependencies.jar +$ java --enable-native-access=ALL-UNNAMED -jar target/monitor-1.1.0-jar-with-dependencies.jar Present: VID: 0x1d6b, PID: 0x0002, manufacturer: Linux 6.5.0-18-generic xhci-hcd, product: xHCI Host Controller, serial: 0000:00:14.0, ID: /dev/bus/usb/001/001 Present: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 35A737883336, ID: /dev/bus/usb/001/009 Monitoring... Press ENTER to quit. diff --git a/examples/monitor_kotlin/pom.xml b/examples/monitor_kotlin/pom.xml index c359f204..bc262586 100644 --- a/examples/monitor_kotlin/pom.xml +++ b/examples/monitor_kotlin/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples monitor - 1.0.0 + 1.1.0 jar monitor @@ -64,7 +64,7 @@ net.codecrete.usb java-does-usb - 1.0.0 + 1.1.0 org.tinylog diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index 83b7e793..2575b168 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -12,9 +12,9 @@ Even though the DFU ## How to run -### Install Java 22 +### Install Java 22 or higher -Check that *Java 22* is installed: +Check that Java 22 or higher is installed: ```shell $ java -version @@ -58,7 +58,7 @@ Run the command below (adapting the file path depending on your specific board): ```shell $ mvn package -$ java --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-1.0.0.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin +$ java --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-1.1.0.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin DFU device found with serial 35A737883336. Target memory segment: Internal Flash Erasing page at 0x8000000 (size 0x4000) diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index 19d2f508..c2634cc7 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples stm_dfu - 1.0.0 + 1.1.0 stm_dfu https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu @@ -19,7 +19,7 @@ net.codecrete.usb java-does-usb - 1.0.0 + 1.1.0 diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 2d7a807c..cbd36338 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 1.0.0 + 1.1.0 22 From 5f2cd32ccc8db6a8c57394ae19bbe4f1dd671a62 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Wed, 13 Nov 2024 21:57:26 +0100 Subject: [PATCH 368/433] Linux: fix varhandle for variable length array --- .../main/java/net/codecrete/usb/linux/EPoll.java | 13 +------------ .../net/codecrete/usb/linux/LinuxAsyncTask.java | 3 ++- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java index e644dd47..ac33efee 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java @@ -15,7 +15,6 @@ import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; -import java.lang.foreign.SequenceLayout; import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; @@ -51,18 +50,8 @@ private EPoll() {} JAVA_INT_UNALIGNED.withName("events"), DATA$LAYOUT.withName("data")).withName("epoll_event"); - // Memory layout for an array of epoll_event structs - private static final SequenceLayout EVENT_ARRAY$LAYOUT = MemoryLayout.sequenceLayout(1, EVENT$LAYOUT); - - // varhandle to access the "fd" field in an array of epoll_event structs - static final VarHandle EVENT_ARRAY_DATA_FD$VH = EVENT_ARRAY$LAYOUT.varHandle( - MemoryLayout.PathElement.sequenceElement(), - MemoryLayout.PathElement.groupElement("data"), - MemoryLayout.PathElement.groupElement("fd") - ); - // varhandle to access the "fd" field in an epoll_event struct - private static final VarHandle EVENT_DATA_FD$VH = EVENT$LAYOUT.varHandle( + static final VarHandle EVENT_DATA_FD$VH = EVENT$LAYOUT.varHandle( MemoryLayout.PathElement.groupElement("data"), MemoryLayout.PathElement.groupElement("fd") ); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index 1a33d164..1fe40ceb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -98,7 +98,8 @@ private void asyncCompletionTask() { // for all ready file descriptors, reap URBs for (int i = 0; i < res; i++) { - var fd = (int) EPoll.EVENT_ARRAY_DATA_FD$VH.get(events, 0, i); + var event = events.asSlice(i * EPoll.EVENT$LAYOUT.byteSize(), EPoll.EVENT$LAYOUT); + var fd = (int) EPoll.EVENT_DATA_FD$VH.get(event, 0L); reapURBs(fd, urbPointerHolder, errorState); } } From 2de2bb088012a82c4aa8ac1d50a072daf178a530 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 13 Nov 2024 22:32:55 +0100 Subject: [PATCH 369/433] Increase version to 1.1.1 --- README.md | 4 ++-- examples/bulk_transfer/README.md | 2 +- examples/bulk_transfer/pom.xml | 4 ++-- examples/enumerate/README.md | 2 +- examples/enumerate/pom.xml | 4 ++-- examples/enumerate_kotlin/README.md | 2 +- examples/enumerate_kotlin/pom.xml | 4 ++-- examples/epaper_display/README.md | 4 ++-- examples/epaper_display/pom.xml | 4 ++-- examples/monitor/README.md | 2 +- examples/monitor/pom.xml | 4 ++-- examples/monitor_kotlin/README.md | 2 +- examples/monitor_kotlin/pom.xml | 4 ++-- examples/stm_dfu/README.md | 2 +- examples/stm_dfu/pom.xml | 4 ++-- java-does-usb/pom.xml | 2 +- 16 files changed, 25 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 20550947..f7dbcfe9 100644 --- a/README.md +++ b/README.md @@ -31,14 +31,14 @@ If you are using Maven, add the below dependency to your pom.xml: net.codecrete.usb java-does-usb - 1.1.0 + 1.1.1 ``` If you are using Gradle, add the below dependency to your build.gradle file: ```groovy -compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '1.1.0' +compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '1.1.1' ``` ```java diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index 8a86e903..90b98d43 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] --------------< net.codecrete.usb.examples:bulk-transfer >-------------- -[INFO] Building bulk-transfer 1.1.0 +[INFO] Building bulk-transfer 1.1.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ bulk-transfer --- diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index f822cd69..cdea7693 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples bulk-transfer - 1.1.0 + 1.1.1 bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.1.0 + 1.1.1 diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index 4c828744..5abbb54b 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] ----------------< net.codecrete.usb.examples:enumerate >---------------- -[INFO] Building enumerate 1.1.0 +[INFO] Building enumerate 1.1.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ enumerate --- diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index 0da4fb2d..3abf3465 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples enumerate - 1.1.0 + 1.1.1 enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.1.0 + 1.1.1 org.tinylog diff --git a/examples/enumerate_kotlin/README.md b/examples/enumerate_kotlin/README.md index e5dd07ab..ad566702 100644 --- a/examples/enumerate_kotlin/README.md +++ b/examples/enumerate_kotlin/README.md @@ -40,7 +40,7 @@ $ mvn clean package ### Run the jar ```shell -$ java --enable-native-access=ALL-UNNAMED -jar target/enumerate-1.1.0-jar-with-dependencies.jar +$ java --enable-native-access=ALL-UNNAMED -jar target/enumerate-1.1.1-jar-with-dependencies.jar Device: VID: 0xcafe PID: 0xceaf diff --git a/examples/enumerate_kotlin/pom.xml b/examples/enumerate_kotlin/pom.xml index 19cc08ec..717034b6 100644 --- a/examples/enumerate_kotlin/pom.xml +++ b/examples/enumerate_kotlin/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples enumerate - 1.1.0 + 1.1.1 jar enumerate @@ -64,7 +64,7 @@ net.codecrete.usb java-does-usb - 1.1.0 + 1.1.1 org.tinylog diff --git a/examples/epaper_display/README.md b/examples/epaper_display/README.md index 7d29543a..cacffde0 100644 --- a/examples/epaper_display/README.md +++ b/examples/epaper_display/README.md @@ -45,7 +45,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -------------< net.codecrete.usb.examples:epaper-display >-------------- -[INFO] Building epaper-display 1.1.0 +[INFO] Building epaper-display 1.1.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ epaper-display --- @@ -79,6 +79,6 @@ $ sudo -i Password: $ cd /Users/me/Documents/JavaDoesUSB/examples/epaper_display $ export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-20.jdk/Contents/Home -$ $JAVA_HOME/bin/java --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/1.1.0/java-does-usb-1.1.0.jar net.codecrete.usb.examples.EPaperDisplay +$ $JAVA_HOME/bin/java --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/1.1.1/java-does-usb-1.1.1.jar net.codecrete.usb.examples.EPaperDisplay Display size: 1200 x 825 ``` diff --git a/examples/epaper_display/pom.xml b/examples/epaper_display/pom.xml index 70c5e816..486b9a64 100644 --- a/examples/epaper_display/pom.xml +++ b/examples/epaper_display/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples epaper-display - 1.1.0 + 1.1.1 epaper-display https://github.com/manuelbl/JavaDoesUSB/examples/epaper_display @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.1.0 + 1.1.1 diff --git a/examples/monitor/README.md b/examples/monitor/README.md index 85e74d74..39519350 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -----------------< net.codecrete.usb.examples:monitor >----------------- -[INFO] Building monitor 1.1.0 +[INFO] Building monitor 1.1.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ monitor --- diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index 28f0e920..ae21e995 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples monitor - 1.1.0 + 1.1.1 monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.1.0 + 1.1.1 org.tinylog diff --git a/examples/monitor_kotlin/README.md b/examples/monitor_kotlin/README.md index ebf7de70..92b796a8 100644 --- a/examples/monitor_kotlin/README.md +++ b/examples/monitor_kotlin/README.md @@ -40,7 +40,7 @@ $ mvn clean package ### Run the jar ```shell -$ java --enable-native-access=ALL-UNNAMED -jar target/monitor-1.1.0-jar-with-dependencies.jar +$ java --enable-native-access=ALL-UNNAMED -jar target/monitor-1.1.1-jar-with-dependencies.jar Present: VID: 0x1d6b, PID: 0x0002, manufacturer: Linux 6.5.0-18-generic xhci-hcd, product: xHCI Host Controller, serial: 0000:00:14.0, ID: /dev/bus/usb/001/001 Present: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 35A737883336, ID: /dev/bus/usb/001/009 Monitoring... Press ENTER to quit. diff --git a/examples/monitor_kotlin/pom.xml b/examples/monitor_kotlin/pom.xml index bc262586..04dcb203 100644 --- a/examples/monitor_kotlin/pom.xml +++ b/examples/monitor_kotlin/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples monitor - 1.1.0 + 1.1.1 jar monitor @@ -64,7 +64,7 @@ net.codecrete.usb java-does-usb - 1.1.0 + 1.1.1 org.tinylog diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index 2575b168..1aa490c5 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -58,7 +58,7 @@ Run the command below (adapting the file path depending on your specific board): ```shell $ mvn package -$ java --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-1.1.0.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin +$ java --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-1.1.1.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin DFU device found with serial 35A737883336. Target memory segment: Internal Flash Erasing page at 0x8000000 (size 0x4000) diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index c2634cc7..7f8c8ba0 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples stm_dfu - 1.1.0 + 1.1.1 stm_dfu https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu @@ -19,7 +19,7 @@ net.codecrete.usb java-does-usb - 1.1.0 + 1.1.1 diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index cbd36338..871a3349 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 1.1.0 + 1.1.1 22 From 8497de15a1d5eb91382635dada9e570dd25e3949 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 6 Dec 2024 09:19:50 +0100 Subject: [PATCH 370/433] Windows: Handle invalid string descriptors --- .../usb/usbstandard/StringDescriptor.java | 42 ++++++- .../codecrete/usb/StringDescriptorTest.java | 107 ++++++++++++++++++ 2 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/StringDescriptorTest.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java index 6cd245aa..de83547e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java @@ -7,12 +7,14 @@ package net.codecrete.usb.usbstandard; +import net.codecrete.usb.UsbException; + import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.nio.charset.StandardCharsets; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_CHAR; import static java.lang.foreign.ValueLayout.JAVA_SHORT; /** @@ -27,13 +29,46 @@ public StringDescriptor(MemorySegment descriptor) { this.descriptor = descriptor; } + /** + * Indicates if this string descriptor is valid. + *

+ * Invalid string descriptors might be missing the header, + * have a descriptor type that is not a string descriptor, + * indicate an incorrect length or have incomplete UTF-16 code units. + *

+ * @return if this descriptor is valid + */ + public boolean isValid() { + return descriptor.byteSize() >= 2 + && descriptor.get(JAVA_BYTE, bDescriptorType$OFFSET) == 3 + && length() == descriptor.byteSize() + && (descriptor.byteSize() & 1) == 0; + } + public int length() { return 0xff & descriptor.get(JAVA_BYTE, bLength$OFFSET); } + /** + * Returns the string of this string descriptor. + *

+ * Invalid UTF-16 code units are replaced with the Unicode replacement character. + * Trailing 0s (UTF-16 code unit with value 0) are truncated. + *

+ * @throws UsbException if the string descriptor is invalid + * @return the string value + */ public String string() { - var chars = descriptor.asSlice(string$OFFSET, length() - 2L).toArray(JAVA_CHAR); - return new String(chars); + if (!isValid()) + throw new UsbException("String descriptor is invalid"); + var len = (int)(length() - 2L); + var bytes = descriptor.asSlice(string$OFFSET, len).toArray(JAVA_BYTE); + + // truncate trailing 0s + while (len > 0 && bytes[len-2] == 0 && bytes[len-1] == 0) + len--; + + return new String(bytes, 0, len, StandardCharsets.UTF_16LE); } // struct USBStringDescriptor { @@ -48,5 +83,6 @@ public String string() { ); private static final long bLength$OFFSET = 0; + private static final long bDescriptorType$OFFSET = 1; private static final long string$OFFSET = 2; } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StringDescriptorTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StringDescriptorTest.java new file mode 100644 index 00000000..542e3142 --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/StringDescriptorTest.java @@ -0,0 +1,107 @@ +package net.codecrete.usb; + +import net.codecrete.usb.usbstandard.StringDescriptor; +import org.junit.jupiter.api.Test; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.util.function.Consumer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class StringDescriptorTest { + + @Test + void validStringDescriptor() { + testDescriptor( + new byte[]{0x0c, 0x03, 'H', 0, 'e', 0, 'l', 0, 'l', 0, 'o', 0}, + stringDescriptor -> { + assertThat(stringDescriptor.isValid()).isTrue(); + assertThat(stringDescriptor.string()).isEqualTo("Hello"); + } + ); + } + + @Test + void truncateTrailingZeros() { + testDescriptor( + new byte[]{0x0e, 0x03, 'H', 0, 'e', 0, 'l', 0, 'l', 0, 'o', 0, 0, 0}, + stringDescriptor -> { + assertThat(stringDescriptor.isValid()).isTrue(); + assertThat(stringDescriptor.string()).isEqualTo("Hello"); + } + ); + } + + @Test + void invalidDescriptorType() { + testDescriptor( + new byte[]{0x0c, 0x04, 'H', 0, 'e', 0, 'l', 0, 'l', 0, 'o', 0}, + stringDescriptor -> assertThat(stringDescriptor.isValid()).isFalse() + ); + } + + @Test + void inconsistentLength() { + testDescriptor( + new byte[]{0x0c, 0x03, 'H', 0, 'e', 0, 'l', 0, 'l', 0, 'o', 0, 0, 0}, + stringDescriptor -> assertThat(stringDescriptor.isValid()).isFalse() + ); + } + + @Test + void inconsistentLengthThrowsException() { + testDescriptor( + new byte[]{0x0c, 0x03, 'H', 0, 'e', 0, 'l', 0, 'l', 0, 'o', 0, 0, 0}, + stringDescriptor -> { + assertThat(stringDescriptor.isValid()).isFalse(); + assertThatThrownBy(stringDescriptor::string) + .isInstanceOf(UsbException.class) + .hasMessage("String descriptor is invalid"); + } + ); + } + + @Test + void oddLength() { + testDescriptor( + new byte[]{0x0d, 0x03, 'H', 0, 'e', 0, 'l', 0, 'l', 0, 'o', 0, 0}, + stringDescriptor -> assertThat(stringDescriptor.isValid()).isFalse() + ); + } + + @Test + void unicodeSurrogates() { + // In theory, USB is stuck with an old Unicode standard and the below is invalid. + // In practice, it will work anyway. + testDescriptor( + new byte[]{0x06, 0x03, 0x3D, (byte)0xD8, 0x1B, (byte)0xDE}, + stringDescriptor -> { + assertThat(stringDescriptor.isValid()).isTrue(); + assertThat(stringDescriptor.string()).isEqualTo("\uD83D\uDE1B"); + } + ); + } + + @Test + void invalidUnicodeCharactersAreReplaced() { + testDescriptor( + new byte[]{0x06, 0x03, 'H', 0, 0x1B, (byte)0xDE}, + stringDescriptor -> { + assertThat(stringDescriptor.isValid()).isTrue(); + assertThat(stringDescriptor.string()).isEqualTo("H�"); + } + ); + } + + private void testDescriptor(byte[] descriptorBytes, Consumer validator) { + try (var arena = Arena.ofConfined()) { + var memorySegment = arena.allocate(descriptorBytes.length); + memorySegment.copyFrom(MemorySegment.ofArray(descriptorBytes)); + + var stringDescriptor = new StringDescriptor(memorySegment); + validator.accept(stringDescriptor); + } + } +} From 62d35531ac9d8aa1617468f9888e4509924b7fdb Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 6 Dec 2024 14:07:08 +0100 Subject: [PATCH 371/433] Mark as snapshot --- java-does-usb/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 871a3349..9773c66e 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 1.1.1 + 1.1.2-SNAPSHOT 22 From 393218fd18981b3a030ea971b5eafae54cd638cc Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Sat, 7 Dec 2024 22:01:48 +0100 Subject: [PATCH 372/433] Linux: use array element var handle --- .../src/main/java/net/codecrete/usb/linux/EPoll.java | 8 +++++++- .../main/java/net/codecrete/usb/linux/LinuxAsyncTask.java | 3 +-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java index ac33efee..2b6c411e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java @@ -50,8 +50,14 @@ private EPoll() {} JAVA_INT_UNALIGNED.withName("events"), DATA$LAYOUT.withName("data")).withName("epoll_event"); + // varhandle to access the "fd" field in an epoll_event array + static final VarHandle EVENT_ARRAY_DATA_FD$VH = EVENT$LAYOUT.arrayElementVarHandle( + MemoryLayout.PathElement.groupElement("data"), + MemoryLayout.PathElement.groupElement("fd") + ); + // varhandle to access the "fd" field in an epoll_event struct - static final VarHandle EVENT_DATA_FD$VH = EVENT$LAYOUT.varHandle( + private static final VarHandle EVENT_DATA_FD$VH = EVENT$LAYOUT.varHandle( MemoryLayout.PathElement.groupElement("data"), MemoryLayout.PathElement.groupElement("fd") ); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index 1fe40ceb..079b68e2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -98,8 +98,7 @@ private void asyncCompletionTask() { // for all ready file descriptors, reap URBs for (int i = 0; i < res; i++) { - var event = events.asSlice(i * EPoll.EVENT$LAYOUT.byteSize(), EPoll.EVENT$LAYOUT); - var fd = (int) EPoll.EVENT_DATA_FD$VH.get(event, 0L); + var fd = (int) EPoll.EVENT_ARRAY_DATA_FD$VH.get(events, 0L, i); reapURBs(fd, urbPointerHolder, errorState); } } From 22d8b6998a21276c5820f94374e7e702dfbed458 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 11 Dec 2024 20:44:02 +0100 Subject: [PATCH 373/433] Increase version to 1.1.2 --- README.md | 4 ++-- examples/bulk_transfer/README.md | 2 +- examples/bulk_transfer/pom.xml | 4 ++-- examples/enumerate/README.md | 2 +- examples/enumerate/pom.xml | 4 ++-- examples/enumerate_kotlin/README.md | 2 +- examples/enumerate_kotlin/pom.xml | 4 ++-- examples/epaper_display/README.md | 4 ++-- examples/epaper_display/pom.xml | 4 ++-- examples/monitor/README.md | 2 +- examples/monitor/pom.xml | 4 ++-- examples/monitor_kotlin/README.md | 2 +- examples/monitor_kotlin/pom.xml | 4 ++-- examples/stm_dfu/README.md | 2 +- examples/stm_dfu/pom.xml | 4 ++-- java-does-usb/pom.xml | 2 +- 16 files changed, 25 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index f7dbcfe9..944c4fce 100644 --- a/README.md +++ b/README.md @@ -31,14 +31,14 @@ If you are using Maven, add the below dependency to your pom.xml: net.codecrete.usb java-does-usb - 1.1.1 + 1.1.2 ``` If you are using Gradle, add the below dependency to your build.gradle file: ```groovy -compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '1.1.1' +compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '1.1.2' ``` ```java diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index 90b98d43..960bc44a 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] --------------< net.codecrete.usb.examples:bulk-transfer >-------------- -[INFO] Building bulk-transfer 1.1.1 +[INFO] Building bulk-transfer 1.1.2 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ bulk-transfer --- diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index cdea7693..84e0aea1 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples bulk-transfer - 1.1.1 + 1.1.2 bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.1.1 + 1.1.2 diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index 5abbb54b..2ecd19b9 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] ----------------< net.codecrete.usb.examples:enumerate >---------------- -[INFO] Building enumerate 1.1.1 +[INFO] Building enumerate 1.1.2 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ enumerate --- diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index 3abf3465..b59f45b0 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples enumerate - 1.1.1 + 1.1.2 enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.1.1 + 1.1.2 org.tinylog diff --git a/examples/enumerate_kotlin/README.md b/examples/enumerate_kotlin/README.md index ad566702..05a2871d 100644 --- a/examples/enumerate_kotlin/README.md +++ b/examples/enumerate_kotlin/README.md @@ -40,7 +40,7 @@ $ mvn clean package ### Run the jar ```shell -$ java --enable-native-access=ALL-UNNAMED -jar target/enumerate-1.1.1-jar-with-dependencies.jar +$ java --enable-native-access=ALL-UNNAMED -jar target/enumerate-1.1.2-jar-with-dependencies.jar Device: VID: 0xcafe PID: 0xceaf diff --git a/examples/enumerate_kotlin/pom.xml b/examples/enumerate_kotlin/pom.xml index 717034b6..ed4676b6 100644 --- a/examples/enumerate_kotlin/pom.xml +++ b/examples/enumerate_kotlin/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples enumerate - 1.1.1 + 1.1.2 jar enumerate @@ -64,7 +64,7 @@ net.codecrete.usb java-does-usb - 1.1.1 + 1.1.2 org.tinylog diff --git a/examples/epaper_display/README.md b/examples/epaper_display/README.md index cacffde0..e15eccd5 100644 --- a/examples/epaper_display/README.md +++ b/examples/epaper_display/README.md @@ -45,7 +45,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -------------< net.codecrete.usb.examples:epaper-display >-------------- -[INFO] Building epaper-display 1.1.1 +[INFO] Building epaper-display 1.1.2 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ epaper-display --- @@ -79,6 +79,6 @@ $ sudo -i Password: $ cd /Users/me/Documents/JavaDoesUSB/examples/epaper_display $ export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-20.jdk/Contents/Home -$ $JAVA_HOME/bin/java --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/1.1.1/java-does-usb-1.1.1.jar net.codecrete.usb.examples.EPaperDisplay +$ $JAVA_HOME/bin/java --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/1.1.2/java-does-usb-1.1.2.jar net.codecrete.usb.examples.EPaperDisplay Display size: 1200 x 825 ``` diff --git a/examples/epaper_display/pom.xml b/examples/epaper_display/pom.xml index 486b9a64..d1630422 100644 --- a/examples/epaper_display/pom.xml +++ b/examples/epaper_display/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples epaper-display - 1.1.1 + 1.1.2 epaper-display https://github.com/manuelbl/JavaDoesUSB/examples/epaper_display @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.1.1 + 1.1.2 diff --git a/examples/monitor/README.md b/examples/monitor/README.md index 39519350..eb4fe6be 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -----------------< net.codecrete.usb.examples:monitor >----------------- -[INFO] Building monitor 1.1.1 +[INFO] Building monitor 1.1.2 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ monitor --- diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index ae21e995..f09f7144 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples monitor - 1.1.1 + 1.1.2 monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.1.1 + 1.1.2 org.tinylog diff --git a/examples/monitor_kotlin/README.md b/examples/monitor_kotlin/README.md index 92b796a8..6a1b72d3 100644 --- a/examples/monitor_kotlin/README.md +++ b/examples/monitor_kotlin/README.md @@ -40,7 +40,7 @@ $ mvn clean package ### Run the jar ```shell -$ java --enable-native-access=ALL-UNNAMED -jar target/monitor-1.1.1-jar-with-dependencies.jar +$ java --enable-native-access=ALL-UNNAMED -jar target/monitor-1.1.2-jar-with-dependencies.jar Present: VID: 0x1d6b, PID: 0x0002, manufacturer: Linux 6.5.0-18-generic xhci-hcd, product: xHCI Host Controller, serial: 0000:00:14.0, ID: /dev/bus/usb/001/001 Present: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 35A737883336, ID: /dev/bus/usb/001/009 Monitoring... Press ENTER to quit. diff --git a/examples/monitor_kotlin/pom.xml b/examples/monitor_kotlin/pom.xml index 04dcb203..ec6ad73a 100644 --- a/examples/monitor_kotlin/pom.xml +++ b/examples/monitor_kotlin/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples monitor - 1.1.1 + 1.1.2 jar monitor @@ -64,7 +64,7 @@ net.codecrete.usb java-does-usb - 1.1.1 + 1.1.2 org.tinylog diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index 1aa490c5..deceb358 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -58,7 +58,7 @@ Run the command below (adapting the file path depending on your specific board): ```shell $ mvn package -$ java --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-1.1.1.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin +$ java --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-1.1.2.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin DFU device found with serial 35A737883336. Target memory segment: Internal Flash Erasing page at 0x8000000 (size 0x4000) diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index 7f8c8ba0..ad13ac30 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples stm_dfu - 1.1.1 + 1.1.2 stm_dfu https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu @@ -19,7 +19,7 @@ net.codecrete.usb java-does-usb - 1.1.1 + 1.1.2 diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 9773c66e..f431b574 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 1.1.2-SNAPSHOT + 1.1.2 22 From 7eda01665c178cb71385270121694a87f6e80406 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 26 Dec 2024 11:31:26 +0100 Subject: [PATCH 374/433] STM32 DFU improvements --- .../main/java/net/codecrete/usb/dfu/DFU.java | 8 +- .../java/net/codecrete/usb/dfu/DFUDevice.java | 110 ++++++++++-------- .../net/codecrete/usb/dfu/DFURequest.java | 6 +- .../java/net/codecrete/usb/dfu/DFUStatus.java | 5 +- .../net/codecrete/usb/dfu/DeviceState.java | 75 ++++++++---- .../net/codecrete/usb/dfu/DeviceStatus.java | 88 ++++++++++---- .../main/java/net/codecrete/usb/dfu/Page.java | 2 +- .../java/net/codecrete/usb/dfu/Segment.java | 97 ++++++--------- 8 files changed, 224 insertions(+), 167 deletions(-) diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFU.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFU.java index 0c785461..b3d9d9ad 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFU.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFU.java @@ -12,7 +12,7 @@ import java.nio.file.Path; /** - * Command line application for upload firmware to STM32. + * Command line application for uploading firmware to STM32 microcontrollers. *

* Only the STM32 variant of the DFU protocol is supported. * Only binary firmware format is supported (no .hex or .dfu files). @@ -53,8 +53,8 @@ public static void main(String[] args) { System.exit(4); return; } - var device = devices.get(0); - System.out.printf("DFU device found with serial %s.%n", device.serialNumber()); + var device = devices.getFirst(); + System.out.printf("DFU device found with serial %s.%n", device.getSerialNumber()); // download and verify firmware try { @@ -64,7 +64,7 @@ public static void main(String[] args) { System.out.println("Firmware successfully downloaded and verified"); device.startApplication(); - System.out.println("DFU mode exited and firmware started"); + System.out.println("DFU mode ended and firmware started"); device.close(); diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java index c8b0d79f..edaa785c 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java @@ -23,12 +23,12 @@ */ public class DFUDevice { - private final UsbDevice usbDevice_; - private final int interfaceNumber_; - private final int transferSize_; - private final Version dfuVersion_; + private final UsbDevice usbDevice; + private final int interfaceNumber; + private final int transferSize; + private final Version dfuVersion; - private List segments_; + private List segments; /** * Gets all connected DFU devices @@ -89,40 +89,40 @@ public static int getDFUInterfaceNumber(UsbDevice device) { * @param usbDevice the USB device */ public DFUDevice(UsbDevice usbDevice) { - usbDevice_ = usbDevice; - interfaceNumber_ = getDFUInterfaceNumber(usbDevice); + this.usbDevice = usbDevice; + interfaceNumber = getDFUInterfaceNumber(usbDevice); var configDesc = usbDevice.getConfigurationDescriptor(); int offset = getDFUDescriptorOffset(configDesc); assert offset > 0; - transferSize_ = getInt16(configDesc, offset + 5); - dfuVersion_ = new Version(getInt16(configDesc, offset + 7)); + transferSize = getInt16(configDesc, offset + 5); + dfuVersion = new Version(getInt16(configDesc, offset + 7)); } /** * Gets the DFU protocol version. * @return the protocol version */ - public Version dfuVersion() { - return dfuVersion_; + public Version getDfuVersion() { + return dfuVersion; } /** * Gets the device serial number. * @return the serial number */ - public String serialNumber() { - return usbDevice_.getSerialNumber(); + public String getSerialNumber() { + return usbDevice.getSerialNumber(); } /** * Opens the DFU device for communication. */ public void open() { - usbDevice_.open(); - usbDevice_.claimInterface(interfaceNumber_); - segments_ = Segment.getSegments(usbDevice_, interfaceNumber_); + usbDevice.open(); + usbDevice.claimInterface(interfaceNumber); + segments = Segment.getSegments(usbDevice, interfaceNumber); clearErrorIfNeeded(); } @@ -130,23 +130,23 @@ public void open() { * Closes the DFU device. */ public void close() { - usbDevice_.close(); + usbDevice.close(); } /** * Clears an error status. */ public void clearStatus() { - var setup = new UsbControlTransfer(CLASS, INTERFACE, DFURequest.CLEAR_STATUS.value(), 0, interfaceNumber_); - usbDevice_.controlTransferOut(setup, null); + var transfer = createDfuControlTransfer(DFURequest.CLEAR_STATUS, 0); + usbDevice.controlTransferOut(transfer, null); } /** * Aborts the download mode. */ public void abort() { - var setup = new UsbControlTransfer(CLASS, INTERFACE, DFURequest.ABORT.value(), 0, interfaceNumber_); - usbDevice_.controlTransferOut(setup, null); + var transfer = createDfuControlTransfer(DFURequest.ABORT, 0); + usbDevice.controlTransferOut(transfer, null); } /** @@ -154,8 +154,11 @@ public void abort() { * @return the status */ public DFUStatus getStatus() { - var setup = new UsbControlTransfer(CLASS, INTERFACE, DFURequest.GET_STATUS.value(), 0, interfaceNumber_); - return DFUStatus.fromBytes(usbDevice_.controlTransferIn(setup, 6)); + var transfer = createDfuControlTransfer(DFURequest.GET_STATUS, 0); + var response = usbDevice.controlTransferIn(transfer, 6); + if (response.length != 6) + throw new DFUException("Invalid response from GET_STATUS request"); + return DFUStatus.fromBytes(response); } /** @@ -168,7 +171,6 @@ public byte[] read(int address, int length) { expectState(DeviceState.DFU_IDLE, DeviceState.DFU_DNLOAD_IDLE); setAddress(address); exitDownloadMode(); - expectState(DeviceState.DFU_IDLE, DeviceState.DFU_UPLOAD_IDLE); var result = new byte[length]; @@ -177,17 +179,28 @@ public byte[] read(int address, int length) { int offset = 0; int blockNum = 2; while (offset < length) { - int chunkSize = Math.min(transferSize_, length - offset); - var setup = new UsbControlTransfer(CLASS, INTERFACE, DFURequest.UPLOAD.value(), blockNum, interfaceNumber_); - var chunk = usbDevice_.controlTransferIn(setup, chunkSize); + int chunkSize = Math.min(transferSize, length - offset); + var transfer = createDfuControlTransfer(DFURequest.UPLOAD, blockNum); + var chunk = usbDevice.controlTransferIn(transfer, chunkSize); System.arraycopy(chunk, 0, result, offset, chunkSize); offset += chunkSize; blockNum += 1; } - // request zero lenght chunk to exit out of upload mode - var setup = new UsbControlTransfer(CLASS, INTERFACE, DFURequest.UPLOAD.value(), blockNum, interfaceNumber_); - usbDevice_.controlTransferIn(setup, 0); + // request zero length chunk to exit out of upload mode + var transfer = createDfuControlTransfer(DFURequest.UPLOAD, blockNum); + usbDevice.controlTransferIn(transfer, 0); + + DFUStatus status; + try { + status = getStatus(); + } catch (DFUException e) { + // Device might respond with an empty response; try again + status = getStatus(); + } + + if (status.state() != DeviceState.DFU_IDLE) + throw new DFUException("Unexpected state after exiting from upload mode"); return result; } @@ -201,13 +214,13 @@ public void verify(byte[] firmware) { public void download(byte[] firmware) { int length = firmware.length; - // validate start and end address exist and are writable + // validate that start and end address exist and are writable int startAddress = STM32.FLASH_BASE_ADDRESS; var firstPage = getWritablePage(startAddress); getWritablePage(startAddress + length); - usbDevice_.selectAlternateSetting(interfaceNumber_, firstPage.segment().altSetting()); - System.out.printf("Target memory segment: %s%n", firstPage.segment().name()); + usbDevice.selectAlternateSetting(interfaceNumber, firstPage.segment().getAltSetting()); + System.out.printf("Target memory segment: %s%n", firstPage.segment().getName()); // erase if needed if (firstPage.isErasable()) @@ -219,14 +232,14 @@ public void download(byte[] firmware) { int offset = 0; int transaction = 2; while (offset < length) { - int chunkSize = Math.min(length - offset, transferSize_); + int chunkSize = Math.min(length - offset, transferSize); byte[] chunk = new byte[chunkSize]; System.arraycopy(firmware, offset, chunk, 0, chunkSize); System.out.printf("Writing data at 0x%x (size 0x%x)%n", startAddress + offset, chunkSize); - var setup = new UsbControlTransfer(CLASS, INTERFACE, DFURequest.DOWNLOAD.value(), transaction, interfaceNumber_); - usbDevice_.controlTransferOut(setup, chunk); + var transfer = createDfuControlTransfer(DFURequest.DOWNLOAD, transaction); + usbDevice.controlTransferOut(transfer, chunk); finishDownloadCommand("writing data"); @@ -243,7 +256,7 @@ public void download(byte[] firmware) { * Only applicable to erasable sector, i.e. flash memory. *

*

- * Only entire pages can be erase. If start and end address to not fall onto + * Only entire pages can be erased. If start and end address to not fall onto * page boundaries, this method will extend the range to be erased. *

* @param startAddress the start address of the range @@ -261,20 +274,20 @@ public void erase(int startAddress, int length) { System.out.printf("Erasing page at 0x%x (size 0x%x)%n", page.startAddress(), page.pageSize()); erasePage(page.startAddress()); - startAddress = page.endAddress(); + startAddress = page.getEndAddress(); } } public void erasePage(int address) { - execDownloadCommandWithAddress((byte) 0x41, "erasing page", address); + executeSpecialCommand((byte) 0x41, "erasing page", address); } public void setAddress(int address) { - execDownloadCommandWithAddress((byte) 0x21, "setting address", address); + executeSpecialCommand((byte) 0x21, "setting address", address); } - private void execDownloadCommandWithAddress(byte command, String action, int address) { - var setup = new UsbControlTransfer(CLASS, INTERFACE, DFURequest.DOWNLOAD.value(), 0, interfaceNumber_); + private void executeSpecialCommand(byte command, String action, int address) { + var transfer = createDfuControlTransfer(DFURequest.DOWNLOAD, 0); var data = new byte[] { command, (byte) address, @@ -282,7 +295,7 @@ private void execDownloadCommandWithAddress(byte command, String action, int add (byte) (address >> 16), (byte) (address >> 24) }; - usbDevice_.controlTransferOut(setup, data); + usbDevice.controlTransferOut(transfer, data); finishDownloadCommand(action); } @@ -311,7 +324,7 @@ private Page getWritablePage(int address) { } private Page findPage(int address) { - return Segment.findPage(segments_, address); + return Segment.findPage(segments, address); } private void exitDownloadMode() { @@ -327,8 +340,8 @@ private void exitDownloadMode() { public void startApplication() { expectState(DeviceState.DFU_IDLE, DeviceState.DFU_DNLOAD_IDLE); - var setup = new UsbControlTransfer(CLASS, INTERFACE, DFURequest.DOWNLOAD.value(), 2, interfaceNumber_); - usbDevice_.controlTransferOut(setup, null); + var transfer = createDfuControlTransfer(DFURequest.DOWNLOAD, 0); + usbDevice.controlTransferOut(transfer, null); var status = getStatus(); if (status.state() != DeviceState.DFU_MANIFEST) @@ -365,4 +378,9 @@ private static void sleep(int millis) { throw new DFUException("Sleep failed", e); } } + + private UsbControlTransfer createDfuControlTransfer(DFURequest request, int value) { + return new UsbControlTransfer(CLASS, INTERFACE, request.ordinal(), value, interfaceNumber); + } + } diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFURequest.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFURequest.java index 00607e37..6c01b989 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFURequest.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFURequest.java @@ -20,9 +20,5 @@ public enum DFURequest { GET_STATUS, CLEAR_STATUS, GET_STATE, - ABORT; - - public int value() { - return ordinal(); - } + ABORT } diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUStatus.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUStatus.java index 4cd6e967..d6b44b00 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUStatus.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUStatus.java @@ -13,13 +13,12 @@ * See USB Device Class Specification for Device Firmware Upgrade, version 1.1. *

*/ -public record DFUStatus(DeviceStatus status, int pollTimeout, DeviceState state, int iString) { +public record DFUStatus(DeviceStatus status, int pollTimeout, DeviceState state) { public static DFUStatus fromBytes(byte[] data) { var status = DeviceStatus.fromValue(data[0]); var pollTimeout = (data[1] & 0xff) + 256 * (data[2] & 0xff) + 256 * 256 * (data[3] & 0xff); var state = DeviceState.fromValue(data[4]); - var iString = data[5] & 0x55; - return new DFUStatus(status, pollTimeout, state, iString); + return new DFUStatus(status, pollTimeout, state); } } diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DeviceState.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DeviceState.java index 759da304..35532fd9 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DeviceState.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DeviceState.java @@ -14,31 +14,58 @@ *

*/ public enum DeviceState { - APP_IDLE, // Device is running its normal application. - APP_DETACH, // Device is running its normal application, has received the DFU_DETACH request, - // and is waiting for a USB reset. - DFU_IDLE, // Device is operating in the DFU mode and is waiting for requests. - DFU_DNLOAD_SYNC, // Device has received a block and is waiting for the host to solicit the status via DFU_GETSTATUS. - DFU_DNBUSY, // Device is programming a control-write block into its nonvolatile memories. - DFU_DNLOAD_IDLE, // Device is processing a download operation. Expecting DFU_DNLOAD requests. - DFU_MANIFEST_SYNC, // Device has received the final block of firmware from the host and is waiting for receipt of - // DFU_GETSTATUS to begin the Manifestation phase; or device has completed the Manifestation phase and is - // waiting for receipt of DFU_GETSTATUS. (Devices that can enter this state after the Manifestation phase - // set bmAttributes bit bitManifestationTolerant to 1.) - DFU_MANIFEST, // Device is in the Manifestation phase. (Not all devices will be able to respond to DFU_GETSTATUS - // when in this state.) - DFU_MANIFEST_WAIT_RESET, // Device has programmed its memories and is waiting for a USB reset or a power on reset. - // (Devices that must enter this state clear bitManifestationTolerant to 0.) - DFU_UPLOAD_IDLE, // The device is processing an upload operation. Expecting DFU_UPLOAD requests. - DFU_ERROR; // An error has occurred. Awaiting the DFU_CLRSTATUS request. - - public byte value() { - return (byte) ordinal(); - } - - private static final DeviceState[] values = values(); + /** + * Device is running its normal application. + */ + APP_IDLE, + /** + * Device is running its normal application, has received the DFU_DETACH request, + * and is waiting for a USB reset. + */ + APP_DETACH, + /** + * Device is operating in the DFU mode and is waiting for requests. + */ + DFU_IDLE, + /** + * Device has received a block and is waiting for the host to solicit the status via DFU_GETSTATUS. + */ + DFU_DNLOAD_SYNC, + /** + * Device is programming a control-write block into its nonvolatile memories. + */ + DFU_DNBUSY, + /** + * Device is processing a download operation. Expecting DFU_DNLOAD requests. + */ + DFU_DNLOAD_IDLE, + /** + * Device has received the final block of firmware from the host and is waiting for receipt of + * DFU_GETSTATUS to begin the Manifestation phase; or device has completed the Manifestation phase and is + * waiting for receipt of DFU_GETSTATUS. (Devices that can enter this state after the Manifestation phase + * set bmAttributes bit bitManifestationTolerant to 1.) + */ + DFU_MANIFEST_SYNC, + /** + * Device is in the Manifestation phase. (Not all devices will be able to respond to DFU_GETSTATUS + * when in this state. + */ + DFU_MANIFEST, + /** + * Device has programmed its memories and is waiting for a USB reset or a power on reset. + * (Devices that must enter this state clear bitManifestationTolerant to 0.) + */ + DFU_MANIFEST_WAIT_RESET, + /** + * The device is processing an upload operation. Expecting DFU_UPLOAD requests. + */ + DFU_UPLOAD_IDLE, + /** + * An error has occurred. Awaiting the DFU_CLRSTATUS request. + */ + DFU_ERROR; public static DeviceState fromValue(byte value) { - return values[value]; + return values()[value]; } } diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DeviceStatus.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DeviceStatus.java index 9ae30d63..c702112b 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DeviceStatus.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DeviceStatus.java @@ -15,30 +15,72 @@ */ public enum DeviceStatus { - OK, // No error condition is present - ERR_TARGET, // File is not targeted for use by this device. - ERR_FILE, // File is for this device but fails some vendor-specific verification test. - ERR_WRITE, // Device is unable to write memory. - ERR_ERASE, // Memory erase function failed. - ERR_CHECK_ERASED, // Memory erase check failed. - ERR_PROG, // Program memory function failed. - ERR_VERIFY, // Programmed memory failed verification. - ERR_ADDRESS, // Cannot program memory due to received address that is out of range. - ERR_NOTDONE, // Received DFU_DNLOAD with wLength = 0, but device does not think it has all of the data yet. - ERR_FIRMWARE, // Device’s firmware is corrupt. It cannot return to run-time (non-DFU) operations. - ERR_VENDOR, // iString indicates a vendor-specific error. - ERR_USBR, // Device detected unexpected USB reset signaling. - ERR_POR, // Device detected unexpected power on reset. - ERR_UNKNOWN, // Something went wrong, but the device does not know what it was. - ERR_STALLEDPKT; // Device stalled an unexpected request. + /** + * No error condition is present + */ + OK, + /** + * File is not targeted for use by this device. + */ + ERR_TARGET, + /** + * File is for this device but fails some vendor-specific verification test. + */ + ERR_FILE, + /** + * Device is unable to write memory. + */ + ERR_WRITE, + /** + * Memory erase function failed. + */ + ERR_ERASE, + /** + * Memory erase check failed. + */ + ERR_CHECK_ERASED, + /** + * Program memory function failed. + */ + ERR_PROG, + /** + * Programmed memory failed verification. + */ + ERR_VERIFY, + /** + * Cannot program memory due to received address that is out of range. + */ + ERR_ADDRESS, + /** + * Received DFU_DNLOAD with wLength = 0, but device does not think it has all of the data yet. + */ + ERR_NOTDONE, + /** + * Device’s firmware is corrupt. It cannot return to run-time (non-DFU) operations. + */ + ERR_FIRMWARE, + /** + * iString indicates a vendor-specific error. + */ + ERR_VENDOR, + /** + * Device detected unexpected USB reset signaling. + */ + ERR_USBR, + /** + * Device detected unexpected power on reset. + */ + ERR_POR, + /** + * Something went wrong, but the device does not know what it was. + */ + ERR_UNKNOWN, + /** + * Device stalled an unexpected request. + */ + ERR_STALLEDPKT; - public byte value() { - return (byte) ordinal(); - } - - private static final DeviceStatus[] values = values(); - public static DeviceStatus fromValue(byte value) { - return values[value]; + return values()[value]; } } diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Page.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Page.java index d7d90b31..92158670 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Page.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Page.java @@ -24,7 +24,7 @@ public record Page(Segment segment, int startAddress, int count, int pageSize, i * Gets the end address of the page or sector. * @return the end address */ - public int endAddress() { + public int getEndAddress() { return startAddress + count * pageSize; } diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Segment.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Segment.java index 740a845f..f3fdad2b 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Segment.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/Segment.java @@ -13,6 +13,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.regex.Pattern; import static net.codecrete.usb.UsbRecipient.DEVICE; import static net.codecrete.usb.UsbRequestType.STANDARD; @@ -22,8 +23,11 @@ */ public class Segment { + private static final Pattern SEGMENT_PATTERN = Pattern.compile("@([^/]+)/0x([0-9A-Fa-f]+)/"); + private static final Pattern SECTOR_PATTERN = Pattern.compile(",?(\\d+)\\*(\\d+) ?([BKM]?)(.)"); + /** - * Derives the segments from the USB interface description. + * Decodes the segment information from the USB interface description. * @param device the USB device * @param interfaceNumber the number of the DFU USB interface * @return list of segments @@ -32,7 +36,7 @@ public static List getSegments(UsbDevice device, int interfaceNumber) { var result = new ArrayList(); // STM uses multiple alternate interface settings to represent segments. - // The alternate interface settings name describes the sectors within the segment. + // The alternate interface setting name describes the sectors within the segment. var configDesc = device.getConfigurationDescriptor(); int offset = 0; while (offset < configDesc.length) { @@ -69,8 +73,8 @@ private static String getStringDescriptor(UsbDevice device, int index) { */ public static Page findPage(List segments, int address) { for (var seg : segments) { - for (var sec : seg.sectors()) { - if (address >= sec.startAddress() && address < sec.endAddress()) { + for (var sec : seg.getSectors()) { + if (address >= sec.startAddress() && address < sec.getEndAddress()) { int offset = address - sec.startAddress(); int pageNum = offset / sec.pageSize(); return new Page(seg, sec.startAddress() + pageNum * sec.pageSize(), 1, sec.pageSize(), sec.attributes()); @@ -81,10 +85,10 @@ public static Page findPage(List segments, int address) { return null; } - private final int altSetting_; - private final String name_; + private final int altSetting; + private final String name; - private final List sectors_; + private final List sectors; /** @@ -97,58 +101,29 @@ public static Page findPage(List segments, int address) { */ private Segment(int altSetting, String segmentDesc) { // The format is described in "UM0424 STM32 USB-FS-Device development kit", ch. 10.3.2 - altSetting_ = altSetting; - sectors_ = new ArrayList<>(); - int offset = segmentDesc.indexOf('/', 1); - name_ = segmentDesc.substring(1, offset).trim(); - - int startAddress = 0; - while (offset < segmentDesc.length()) { - // parse start address - if (segmentDesc.charAt(offset) == '/') { - int addressEnd = segmentDesc.indexOf('/', offset + 1); - startAddress = (int) Long.parseLong(segmentDesc.substring(offset + 3, addressEnd), 16); - offset = addressEnd + 1; - continue; - } - - // skip comma - if (segmentDesc.charAt(offset) == ',') - offset += 1; - - // parse count - int countEnd = segmentDesc.indexOf('*', offset); - int count = Integer.parseInt(segmentDesc.substring(offset, countEnd)); - offset = countEnd + 1; - - // parse sector size - int sizeEnd = offset; - while (Character.isDigit(segmentDesc.charAt(sizeEnd))) - sizeEnd += 1; - int size = Integer.parseInt(segmentDesc.substring(offset, sizeEnd)); - offset = sizeEnd; - - // skip whitespace - while (segmentDesc.charAt(offset) == ' ') - offset += 1; - - // parse unit - char unitChar = segmentDesc.charAt(offset); - if (unitChar == 'B') { - offset += 1; - } else if (unitChar == 'K') { + this.altSetting = altSetting; + sectors = new ArrayList<>(); + + var match = SEGMENT_PATTERN.matcher(segmentDesc); + if (!match.find()) + throw new DFUException("Invalid segment description: " + segmentDesc); + this.name = match.group(1).trim(); + var startAddress = (int) Long.parseLong(match.group(2), 16); + + match = SECTOR_PATTERN.matcher(segmentDesc.substring(match.end())); + while (match.find()) { + var count = Integer.parseInt(match.group(1)); + var size = Integer.parseInt(match.group(2)); + var multiplier = match.group(3); + var attributes = match.group(4).charAt(0) - 0x60; + + if (multiplier.equals("K")) { size *= 1024; - offset += 1; - } else if (unitChar == 'M') { + } else if (multiplier.equals("M")) { size *= 1024 * 1024; - offset += 1; } - // parse sector attributes - int sectorAttrs = segmentDesc.charAt(offset) - 0x40; - offset += 1; - - sectors_.add(new Page(this, startAddress, count, size, sectorAttrs)); + sectors.add(new Page(this, startAddress, count, size, attributes)); startAddress += size; } } @@ -157,23 +132,23 @@ private Segment(int altSetting, String segmentDesc) { * Gets the alternative interface setting number * @return the setting number */ - public int altSetting() { - return altSetting_; + public int getAltSetting() { + return altSetting; } /** * Gets the segment name. * @return the name */ - public String name() { - return name_; + public String getName() { + return name; } /** * Gets the sectors withing the segment * @return list of sectors */ - public List sectors() { - return sectors_; + public List getSectors() { + return sectors; } } From af728cfa16cfb8bc656f56f5db5fa7dec052fa18 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 26 Dec 2024 13:09:08 +0100 Subject: [PATCH 375/433] STM32 DFU: more improvements --- .../main/java/net/codecrete/usb/dfu/DFU.java | 1 + .../java/net/codecrete/usb/dfu/DFUDevice.java | 44 ++++++++++++------- .../net/codecrete/usb/dfu/DFURequest.java | 34 +++++++++++++- 3 files changed, 61 insertions(+), 18 deletions(-) diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFU.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFU.java index b3d9d9ad..4ca4d2a3 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFU.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFU.java @@ -64,6 +64,7 @@ public static void main(String[] args) { System.out.println("Firmware successfully downloaded and verified"); device.startApplication(); + device.waitForDisconnect(); System.out.println("DFU mode ended and firmware started"); device.close(); diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java index edaa785c..4678e066 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java @@ -133,6 +133,27 @@ public void close() { usbDevice.close(); } + /** + * Waits until the device disconnects. + *

+ * Disconnection is a side effect of leaving DFU mode. + *

+ *

+ * If the device does not disconnect after 5 seconds, + * an exception will be thrown. + *

+ */ + public void waitForDisconnect() { + var waitingTime = 5000; + while (waitingTime > 0 && usbDevice.isConnected()) { + sleep(100); + waitingTime -= 100; + } + + if (usbDevice.isConnected()) + throw new DFUException("Device did not restart (try disconnecting and reconnecting it)"); + } + /** * Clears an error status. */ @@ -170,7 +191,7 @@ public DFUStatus getStatus() { public byte[] read(int address, int length) { expectState(DeviceState.DFU_IDLE, DeviceState.DFU_DNLOAD_IDLE); setAddress(address); - exitDownloadMode(); + exitMode(); expectState(DeviceState.DFU_IDLE, DeviceState.DFU_UPLOAD_IDLE); var result = new byte[length]; @@ -187,20 +208,7 @@ public byte[] read(int address, int length) { blockNum += 1; } - // request zero length chunk to exit out of upload mode - var transfer = createDfuControlTransfer(DFURequest.UPLOAD, blockNum); - usbDevice.controlTransferIn(transfer, 0); - - DFUStatus status; - try { - status = getStatus(); - } catch (DFUException e) { - // Device might respond with an empty response; try again - status = getStatus(); - } - - if (status.state() != DeviceState.DFU_IDLE) - throw new DFUException("Unexpected state after exiting from upload mode"); + exitMode(); return result; } @@ -247,7 +255,7 @@ public void download(byte[] firmware) { transaction += 1; } - exitDownloadMode(); + exitMode(); } /** @@ -327,7 +335,7 @@ private Page findPage(int address) { return Segment.findPage(segments, address); } - private void exitDownloadMode() { + private void exitMode() { abort(); var status = getStatus(); @@ -340,6 +348,8 @@ private void exitDownloadMode() { public void startApplication() { expectState(DeviceState.DFU_IDLE, DeviceState.DFU_DNLOAD_IDLE); + // By sending a zero-length download packet and querying the status, + // the device will leave DFU mode and restart. var transfer = createDfuControlTransfer(DFURequest.DOWNLOAD, 0); usbDevice.controlTransferOut(transfer, null); diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFURequest.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFURequest.java index 6c01b989..c927e105 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFURequest.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFURequest.java @@ -10,15 +10,47 @@ /** * DFU request. *

- * See USB Device Class Specification for Device Firmware Upgrade, version 1.1. + * See ST Microelectronics, application note AN3156. *

*/ public enum DFURequest { + /** + * Requests the device to leave DFU mode and enter the application. + *

+ * The Detach request is not meaningful in the case of the bootloader. The bootloader starts + * with a system reset depending on the boot mode configuration settings, which means that + * no other application is running at that time. + *

+ */ DETACH, + /** + * Requests data transfer from Host to the device in order to load them + * into device internal flash memory. Includes also erase commands. + */ DOWNLOAD, + /** + * Requests data transfer from device to Host in order to load content + * of device internal flash memory into a Host file. + */ UPLOAD, + /** + * Requests device to send status report to the Host (including status + * resulting from the last request execution and the state the device + * enters immediately after this request). + */ GET_STATUS, + /** + * Requests device to clear error status and move to next step. + */ CLEAR_STATUS, + /** + * Requests the device to send only the state it enters immediately + * after this request. + */ GET_STATE, + /** + * Requests device to exit the current state/operation and enter idle + * state immediately + */ ABORT } From ee675e281944e62fc23f2797c1586d0cdc5bdf7e Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 16 Feb 2025 22:55:59 +0100 Subject: [PATCH 376/433] Update test device firmware --- .../composite-stm32/bin/blackpill-f401cc.bin | Bin 12248 -> 12276 bytes .../composite-stm32/bin/blackpill-f411ce.bin | Bin 12252 -> 12280 bytes .../composite-stm32/bin/bluepill-f103c8.bin | Bin 12408 -> 12436 bytes .../loopback-stm32/bin/blackpill-f401cc.bin | Bin 11360 -> 11396 bytes .../loopback-stm32/bin/blackpill-f411ce.bin | Bin 11364 -> 11400 bytes .../loopback-stm32/bin/bluepill-f103c8.bin | Bin 10892 -> 10928 bytes .../loopback-stm32/bin/disco_f723ie.bin | Bin 11920 -> 11956 bytes 7 files changed, 0 insertions(+), 0 deletions(-) diff --git a/test-devices/composite-stm32/bin/blackpill-f401cc.bin b/test-devices/composite-stm32/bin/blackpill-f401cc.bin index 71988d4f67b70fd52d0fc7e3c03ce61d035e07cf..bba469dc4d71710e3dba9d52275eb1364b5b3c12 100755 GIT binary patch delta 1582 zcmX|BZERCj7=F*~$Id>=irv`SF?QR#jg84xTueszK@IbEqhp{h0Zf*GF=0kcE+7$p zb;6%wm}VT*5Fy5Z36m)6x<>k=X{7;!1hc{-g9U+rcEka98Q2zVukYzvPwxA1-p}X0 z_uMl*@N{5og49M=1EoQor^c`A)^(j*fFT+NTp~VE7AG5OPi8=krxiB<5vSXLa_90q zscemKh)f59f+U!x1Q0s_wg44ev+Pg(dhg})05qs2?`V3@yUywzL=4YTmzKO8fk-Eo zs0*5Vr2Ue=ybILfEJ%_?g4$?KYa z%p8V@3+vSDK%_y6nNKt8n@VmHjQJz&^oCpxefMHhP-7t)=7A3oCIs0S)N9F+EF2@! z=BKd7(e3DxHi7y@MwCI#WbHkhRm}-@qAsK`9?L0ymqQrk`h&DED#%=0_nh;85Y7=z zOMak9`(u7fcj;iv1}!gn*b-xX%{J}VL`%+aX~wMT%GHDuL2w|QY?IOIoy%xRA13e6 z7H88NDS+$<8sswB>OVYQif{G=<9ab}kJjfuWu);Ygt;{>$kibt^O<N*kgHw*GeU{WWy5eS%Nh0#a2t?3VD!ajP~-*$+qjAEvY#3 z6}3EzuVSl<^FN>C{qc30QxhN`MB|0zxzn*x%g4vwQ=35 z;Z%`0x@B5Rp3Sz)ruib_w*(O*35a~t3i!!EESvx$=@jTv+&(;{!~+hSqPPv{=eA*t z<3IU;X@nL+sXl_c6Kto&y_D|+Pxb!j!Vutp840nF ztI zF#_el_)BFt(7?C0CxVTe)|LXjns*gatdxCU`zB(@)NVD-@j3!~d&Mhcjt#GPe=Rrg zq7@GOPw@nG;V$|Ln2AhvDSQu>Y!s-U}o zQgKHE{gRhp(Czvg|EIfHxM9H1i-r1_y-`B%>y2-bXyAC`4Ix*F_vk@#AvuW|I#Kop z4mbZI6mvBPA+Y^r3o%V%-vUhq4y?XUUV8&g{Yd;G-i2}>&E3}UG0MwGBS;7Gwr~m1 hVw|`MiBJAE(s6dOZDqwL7NAZ8h-N6`Ukx;*{{StgD3AaE delta 1538 zcmX|BeQZ-z6hHU1U2pf{wsf$zquXnXV`Cc|HpCer6j)xnRb;`KO_9KeMxvM$2}J)O zT|iACSro3KhQEk4aWT`5?kSBl6^J9CCM#qPSO_DCE$HO&vAmYiKF?h@U-~=e-1BvR z=k~t$Xxo)-kr84Kw*aNG&R;XE>(u$ae+d0F4)}=p3$rBIVE;G=%K2=-3qZuvtw4Ej z$vpmHD}{sPbW|2xLfM!AVmm-LP{H#XyRBav{OJ?`l{NK-ruV(vzj`o86sOV`dLv2B9*BR z6eYK|q4+An__b_X%;VH|7W#vdh|xIay(Uf}C6HMJmTKzpJbX%An;yZt&Q7P#wGosf zIZ*;7n|HjhNzvNCL6mzL%*S?tVUJT77kn_{(gna5@b1DZNBrQl1p;0J#<*`c=5d|J%ggn3)B(9SR_XUVFs*;JpRg8M zN0MwKtuy$rrkCxeW>bkqL>kxB88$#0%k7#dRm4GjlA_Y%)CBv5c9OfS+%!x=?2O5c za>f)yxwm)&%2=@|U2k0i z)Py*00jky%^tcu1JM;EEv}djCU+Z@cPKfW!XX8816anSL_)s@F(P-RuPq1;9y#(lm z`Ord1&d5gXn~{UHwx=kK!6$_6t9^!~*x^Vo2_*GO2RDXxHT8; z#@Dcm-El5MU!}`!=Q(f_ru2Rww%$t_eY;B$bZ1cqykXYoswUy+`>r6t^z71!|68nP zSD)Ty=)z{*Y)!ojqkZ)+VX9m|Az0`3#gGrN8qr27z=OIg`gP-Z!Nkou8qvMYW>PkS z3>I)I`dP~@vThZ+)*<-E)sOlWI`;*JEvSbOdl6gbeJ6^6P9yFk`01ZP>}RpoWmRvO Qfi@dJtbkJf&w+;c54+YEs{jB1 diff --git a/test-devices/composite-stm32/bin/blackpill-f411ce.bin b/test-devices/composite-stm32/bin/blackpill-f411ce.bin index e3ba54a6c179771c33d21462a5a804a871b96578..5662aad96057af77963b8b2ad324a4bf346773e2 100755 GIT binary patch delta 1487 zcmX|BeMnnZ6hHSRG1reYk!UrE(U(N6AFHMl!BI*x3@^Gk+fhgRkFyTO3f&-UDJY{T zEdw`n!``|vR{tnvppvoO{pb z?|!_y+>_{;x=hF%3lR&-pGd29JOy$z>GJ>x;&LNU01(SEkXf^Enk)xGf<22i*4ZEGz2q9J)mR4H7+euFbU6APetjFrBWZ9rd}Oi!$LG@FgxY!Be@X;7o!lS7 znJ9cZST_+Fv~$~^NhN+uQBN7d5OHChN)?DSNHOziYHv;6&je$BO*%s^ySkl-;Wg?4 zc{W7DJnla7fgtOef=VSmnufE)vF|Ayv$xyZ94~`BmJ%h9Q)yerK3Q>sjmS?Dn1JPc zewSUC;^+#sSQ2*VML00MIm=oLb)^7Gn zj%i>$rNoCY`mn-@De=xomR3tpBNa#{|NGPVxRgg2*NJh*lrH~;92%`bUI&wcR2m`@ z-vnDS();?5`LIo@k%;`!Kf;tRd?pD_s9#$8eMsG~ z7**nT)0UT-q^*dLS-;lWeKpOgtt1S7gSXtb5aTD?otlqrWlrC{JwzJ5jGh^~IjyQ2 zNod8%MJ0YQ-6ZKAYlR$&%ph=p|Rn04LtwKZ^R^pG@30kW+Dx!opNBlQNrDw5Kc8Ru= zdn``58>Vnd&B4{XuenP<@Nq=a~!iItKUy zxKerN|8y6-Qq`mB#6n%Hs@j3x_UZ# XI6L3Cqv$;&P^Sh&0~GLNP!RtCP&)u5 delta 1516 zcmX|BZA@EL7=F)f3#Sx>rF@mI-L{j_!3MD*Ld2{acw6Wc=6-BO7i5VMKYmmfjhGnN zX0#(C%8t%0`(cclK#ZoPR@Z1#92pB+Oxi6I0gWt3%BHx>CTTm?Uf)w%Z}L3vd*1JJ z?!718`&+N)0wH58Kq`@MkoM{ik|1ABxac{$|a>2{P#m2xg%mEP&Vo z&;wMkh1o6jZt?@OXetM77`)Y=?;ztKpGgJd>ZYUK<08oML{9)$qHu0#$5?2{#BD1H zCAOewJcr}z4N(Om^-~APa&mWF-W);ye4;5}GpRd?7+j$?kV63)b<0W<7>Rr*jtN-K<+YiFajq{WgmFRQ+N1Y5 z-^EeRC`#;2R+eKOJfd8Q*7r|UK>hSWk*q3|qYc=Wx8~c^AleXW1oaP3XdF46xS6C9 zb7O^<6+WyII~2-}+Tzzpg^qljsU!LB-nx)ls`7p|p~I~%W6sl<^Q!WB4vo}d#8U}D zD&H3%5K*U5xsb*uhMBONi7_zb1UVE+@R%Pz)(ChZ2t}F^jSuC6=Su zwpi+8x?E%P2&rKW?xA?gj;$xIh*kW=6`XMUEf7c zyRS{Cc8tVxMbEEF?E92eDp<=EZbXSV9fi>QyMT7!LGr^QW|a#ZF1rgqJmLgXh09f8 z=cmn$Z(tyoLPp+XM%qXsY(L#|Mh*If(bb-y#PI8;+wO-<8m$X*ogmw^lAg>)cnCC>+>Kc(-b>}s1>@m#dbYB&4 z?L$5lK3}lW{AdZc@D+c~W<9=`CF6sh5&!I zke|)zKQVCYpNP3!pghlm;5ny!CyVW*B(Ot~r>qg1!fYyV!h&DtMDFPeH zF5kH2vY_Q^dIaAul-<%5H;vQ%SQd-PGUj4(-CV?9 zG{}RFvPeS=l+w7GG&K_ZVZ?weMz>5cYC1MCm&k0pNssS=_9oAB-t(UK z<2mP^dvl@D-su*MLv%N;1rFd2o3DV>H}i_W--`%BNUAI1D!qoU<9>QTaN-C(CA8t8 z_?Y0scn@9BG!Aq@SYyJ}ao9YSY=*h$ErRL2~bXnbvlG7xBtis zQ9UWzg8-WTT#wD}tp>#>=-h?Pu$hO$f?D7i4P^ z%lu%1`P6gw_CkTytpX&$vd4=hU1{tl32|}Ity|n~QkUk%av7F&v4e~D%PD!d-q6|4!_Ww(sg zE0l>A84-%oEYX11%%-2O3wTc?&TMShsk zG+)f=rRYyAI|)^c>w4k)43^RvlAwt-A7w7kSM&kALa*p!c!a)0e8A_)0I+Cy9ynkK0)J#^1D-d0B91_h59o=qNh7yL zxh!}lXnlFc!aaP(pHE9Gaa%>D&UO>S1p#SE7*l`+fVzfOX6gPa|C8J+1g-sF{S!ut zAElFYtm?9jdsV==4iTO|%jb~O6%SPVv8A-kU8VA~^oH4wlXT7e9`IY1THuS8W5BBx zC$MoxJ8*z={QQneEIcmIk9Xd8mDeKjxCW66I}uqej`LPTUMt$ag8hKruuj>zAl{kp zk#~-Yh;U(ib5Slde$MtluyNO)21NKiOZ(<2^Yq=imqEfp-BED^)(CB?_u&nCy#Dkv ze9lXn9q@5>W3}ZbN^>6$T6_7aY}vB*AnL1@1AUq~_p=iI2^B+-q9F_gzduJ@p0#87!T0{uAngl&M@F42oJ@_UB@(*!D5^?ggPq#1TYjg zHhn0FJTgSDdD*2n_ s-|Bnvr+yDRo delta 1436 zcmXw3du&rx7(eH>w>{lD_w3e=jo!9SS~|8S%`z5ZsAIeBsEARM4H?O%SuzFURZM&Y zT?d*}lSSkpu=vV?i7x&@w_33=O~oa|kq|ct3XFsi61xqF7j(HTxE;Tsq8(Vy*$HDcUBx8M!HU3j~#VHK$_=9FNs4-tfrRF}tRbPS)ty|hzs;REy~p&3Ww zqk!-4ow`9kebasorIGlj7Bzpla4sKZXw6CIVQ&T zW%UndbVwoz5<=?jmF@1LYZ&gY=X}Z30tp11x-NcBCrOIi9Rr|8QG&*pW@qRGcJ2Nb zz2@w4hEPC#e?^j!TE(O%9lLg`%!eFU)#bne!YLC0r!da<^EqK$kom6l0q6Tr%1Oqw z*J)bsxA(D&8Smg!E%IKND^qo)YUT!{VIbAX*OkXbiaJe3n3n1b(^`lKco7l zt6+0;)i2k8KezajdJXkM7gryFR$5m6$gJBYum2v!P2bNRkN!5P+dPsrO0la$zwoU(E4Uw~l)BHTX);6Cp7KxGhH3fEj!2p^;8tAaQ|O_rm;BbE)ol@j{JTK_P^5e*0T;?5YNne$PER}Q{aB@M)$ecPXCAW3 z3EyZ4tBpUPG}qyKIiiS94tb_L-+VLRdrS%azjK?88UNc!~p*TKtJu? diff --git a/test-devices/loopback-stm32/bin/blackpill-f401cc.bin b/test-devices/loopback-stm32/bin/blackpill-f401cc.bin index 58d4a27d5cabbd94a28622f092484ed2c0b403e2..f4ab388c87270337036242c9fcaa00ba01cae6fb 100755 GIT binary patch delta 1658 zcmZuyeQZ-z6uN>Au7*;0I$M%Z5s9Vo+jY zHiv%{A~DMqBJm&5nD~c@8>MPzN@a@yMaT+6hB!o#y-kKZKz%T~KF@78{_>^go^#K~ z@0@$ydACOf=7T~4N2kkuB~aL?3@YLB7}vm z<%pxk#dCCutYY@!=c6&Ei7}62Bm@v@MjTW9GAYm}@fMQO`?_nunTz!bNMZi17|@5X z+Y#1f-KlMu(u7;GADtifs8R! zs;N6N=shep{e`yMg7!LlgQF2Ct!Y6*O4Y2b9+fmHS_M+_G)={1+^}ltpP4JNziZfm zd_P^bDC|N-=9t{kjZkR~Sz%nnKdt4m`$&UvQPq6TUT+|#lgv_aN>kSY-ZpJ~U_r8F-u#hV#Y4w?z5K{tubSdQ z&MxFL{d`B(RDG#-3)om@T83c*^&}jjNV_i6V(_w8V|uAjdX{u>CEbCMhtEG&elO)T z{Bz;sh|YHxJojg=MT8ArpEv0hZC9O!snKf@4sDM(+BNl!Oo`-`u=3h{razom zVz@Lq5z(#u5h8bGtQ-7N&f0zdmTWWJ9{pan8%|{rz6FmL;dM9+-&~l8;FXEgNA;0& zN7?cN_l&}qW6+h1Uozh|GFN0Qq~v^<|2pU(7TGYW3)emZdrU_;9ImDBPE#imRR1P? zRg}L=w()*!CI@+uuLpY?^rPeiZ{;sRXSsx?eoe;t)Amon_8HJSK!<>oo9Jpk@B`$8 z$!_e;2vQ)?PkuEu;ZCwD&*SRMjLJwjFI%LPOk-#)#VF$t*FbjXeZXg^VE)fan5nB~gLV?fBfzt%@4^2Rm?Izf{$-Jf% zadc+`ZJcyCn+(%529rVOYCKJDI$v5#71X8BjY=?FL>rSRNp(16+XlB{PL^~VP*z9GYVM;o51^w|Lkz9}SRguKj#73=9RUCbwPPdb(>NyO*5C&E(0Y*Rs|Y_#PU` z3c&-qR>2SJKEY|Ho^WSk$L4eQbb<8>!wvxt*EUBJLN^AdC)^hwgjW-nxK-Z>KrQ4g zQ3UHJVkd4P=F&~LIoeTrk;&rGO!Yw3Ko!`6YJfLJTRkTko{G6b%F2h$?T~z)c96fz yWqtzY_)d0~ulsyOQ!qxfy*GeQnGnb4A?_wATka`rEr5R)6WqQiKihu|*8c$Kk1JyU delta 1649 zcmZuxUrbY17(b`Cf9@?5TA|WE6mBVmN-LA`U=1u|;%-|m40JJSG6HIhByL%^z39sz z=;C#W5A*mivMgIR&0L}ptoH$yu8ByTGjUXLGBFP0pIf5~m$pyw ze}3P0zWd!C*)_j&^dk1~0mQO0Bf7_!C=)sV91XDv1P>2Co}_TQr)veN(dAeeA#iT-J5#EYleAA%uDmt80r8n<0rsk}?Da+rZf>TOvrkv!WNi92@45 z`gHl=I481EhctwSE_}P$pX7z%3)C{ZoJd>Sw9IVMnn1}V;MC{h%@K1aW$;O(Puok2 z<}mnPUJi}dNKAAalt!bF`ptwjQHWt>v*;c`lZ?wk|bw-?Bu6K~ScZC;_+V!ua6M4H;Z39xBnwIerkEyA; zM7yUn4@|mH;Le;?WlB{=uR}bo!31@;kq=B2T(6eTE|TM>iort8VSh;03l_ni(lYJ9 zw_7U_-4bpIY+jq9`PMJ%1Zf-#bYBhihoF9M^042OGIW#;;Fhxfysj@9O3)rrURI`k zS+lGc9Yb0s1gt%)x%J6HA0x#;xPOHcQ4Qu@{YZWJ!jyCOYQ^I;DE|VU{Y)=GNogSC zXJz}eVHW#~r}LM&OZr%Qot9ltw9MV?GX-X700q);nNsbMLgVndPh^8oF7%QS);riT z{o2iq4NEDv@t<4YOZvcb@H~}$Ak}pE1OBAn=a_dJpUgavP~dT@O57v4`nAl-tXJ?0 zSpD>cZZwvtGX631SkgEC4v|N*_Ks#DZ$0{AL2(!tXMRHzC$ZMvA`T3XCV>Zxovh+(j^s0%X!< zyJC}J_Ykm&Lu}3xuUpfCU#V$DIW_sHER1C`UbY{kxBNqpUzGbm%H=H}7paV|w|g*l z5pnHE-9{&3>i~;(#M)NZCu{bxD=YAchiLLU0mnx`Bc@6Sn7_V(fm>AGu(Xku;9+PSEb!7$k%9WGmf-evZ zdp_raFhDf4mDsBW4fNDQMyjsiAlX;_AZP7?@1=umFa=L!UY5NDHs~s%qy@? bnGyR4aFs-Z_2o@ADBBGG`lvY9Z4Kmq$>%E2 diff --git a/test-devices/loopback-stm32/bin/blackpill-f411ce.bin b/test-devices/loopback-stm32/bin/blackpill-f411ce.bin index 3d65c7503b99f0aee9859264d47cebbc979cf4d7..da3a8766e0f1cc73170c9a2545d348139dd8ac60 100755 GIT binary patch delta 1650 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 DlAtG0 diff --git a/test-devices/loopback-stm32/bin/bluepill-f103c8.bin b/test-devices/loopback-stm32/bin/bluepill-f103c8.bin index cec3c4df7542f623da8a524ec7499af6351494cd..9f0eaf0b95651be22eb9829bdb868b34de269d36 100755 GIT binary patch delta 1591 zcmZuxYitx%6ux(7XLqJ_+v#K3ZP%9B9oufZ^3W!@P>n6Lvt72dqCpZ(=oVsVBqU3W zu^LHBY2s)~w7CtID2Ygjn3S+(U18fSt2V?Z+LdB>1O$m4e2@;YI(^8F=l0<*C;84j z_uTJ(=iD=Qrgv*}YxE(EBV;9Zfeqp(ibm#;HZv0m^j9GcAtXMqhz@cTAHxc1FrC2z zw(6_yG5j#=GF{hk2zEvLDYu1B-4nrb91^{3!Huv5(fc7 zJg-UWkcI?Ui_RfQisXPN&za?cA*%AzY)2w1#0Q;97wS6w{swPKl)F#Um2YR0cZ6C) zA5IBLl%krT_lRf)M~G*ENW&c8Bq`C~H|8$8hGD}ev;KrfVS-N~EYht=>l+r5g9Nj# zt%pI31F<(!f`@uckbxcBhiRDufcF6CL2KO5$1|uOOD$7qhcj3NS-zhYWu&e6$FbSb z>}*2r7R^|LwCnc`eHq!yKD=T&b3?6eA1y|{tJegL$<@@ephb^vg-YwmXRL#N+E~c$ zBez&b=TgpYuRm^0(d75S|oi)iy0?X7F-~@g+0ZJY4 zTGQ;Nf_7X}5MGFFPx+xmv@=wji_>nHX3ZgIm!Yo(<>tlwKc556W6-{A+0cK>P}<}S zJ5Q60?1Z7O2O{nHca$hHUM_AQV=rTG_SnJ!J|`)Qy^J*`RYSj=`9ozwu6E?R0|&4h zzo;}hu6!}h%7yZ?WX9s|^pCB+_-NI1+GY9s(lN#C`xBUNW^OCuCa=$%@=DH|F3Ydu zw-w}@NbgWwaElE6)r?#A%2=zPHbo=JQp=U`3B|nXN7%V1Q!VFjT3BtFo>ZNdd*ffL zMV2q;70v_W1$Y_7mQOEDD0o#e{XvuR!)d1K;Ivgda~Zk-+imx(rW-02)2biteIpza zOH2ecMgn2_9e6NY=SYCQIYZZyH2zT~#9C#mG5vL;yfQa&IOhy*y9ixw2($Gi9UhbQ9CxAH!=mi`CXm`=gD2xXI{y37@CYvn5p{jv14BvwnWEx{_r5|G4LwGS{3q!CAZ~(5*Yq2)*ImX_- z$TNpgZ8m@d^u*HATPBt=!{qt$ZLm98UITWfJOH+?q804Xic?^>ct>r$ptgj!iMvwe v^C40S=plJkKKnjy{%4OmVcf?f?g(H%*-}+ec-#iJA`5=4D0{wN2H1ZAoslNk delta 1557 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 Date: Sun, 23 Feb 2025 20:41:09 +0100 Subject: [PATCH 377/433] Enable Windows on ARM --- java-does-usb/src/main/java/net/codecrete/usb/Usb.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/Usb.java b/java-does-usb/src/main/java/net/codecrete/usb/Usb.java index 99381a85..59fb0b20 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/Usb.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/Usb.java @@ -33,13 +33,13 @@ private static UsbDeviceRegistry createInstance() { UsbDeviceRegistry impl; if (osName.equals("Mac OS X") && (osArch.equals("x86_64") || osArch.equals("aarch64"))) { impl = new MacosUsbDeviceRegistry(); - } else if (osName.startsWith("Windows") && osArch.equals("amd64")) { + } else if (osName.startsWith("Windows") && (osArch.equals("amd64") || osArch.equals("aarch64"))) { impl = new WindowsUsbDeviceRegistry(); } else if (osName.equals("Linux") && (osArch.equals("amd64") || osArch.equals("aarch64"))) { impl = new LinuxUsbDeviceRegistry(); } else { throw new UnsupportedOperationException(String.format( - "Java Does USB has no implementation for architecture %s/%s", + "The \"Java Does USB\" library has no implementation for JRE/JDK %s/%s", osName, osArch)); } return impl; From 80f46ecf5ea23bd20c75a707568f8e0b23219bb7 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sun, 23 Feb 2025 21:05:49 +0100 Subject: [PATCH 378/433] Version 1.2.0 --- README.md | 10 +++++----- examples/bulk_transfer/README.md | 2 +- examples/bulk_transfer/pom.xml | 4 ++-- examples/enumerate/README.md | 2 +- examples/enumerate/pom.xml | 4 ++-- examples/enumerate_kotlin/README.md | 2 +- examples/enumerate_kotlin/pom.xml | 4 ++-- examples/epaper_display/README.md | 4 ++-- examples/epaper_display/pom.xml | 4 ++-- examples/monitor/README.md | 2 +- examples/monitor/pom.xml | 4 ++-- examples/monitor_kotlin/README.md | 2 +- examples/monitor_kotlin/pom.xml | 4 ++-- examples/stm_dfu/README.md | 2 +- examples/stm_dfu/pom.xml | 4 ++-- java-does-usb/pom.xml | 2 +- 16 files changed, 28 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 944c4fce..a99a557d 100644 --- a/README.md +++ b/README.md @@ -31,14 +31,14 @@ If you are using Maven, add the below dependency to your pom.xml: net.codecrete.usb java-does-usb - 1.1.2 + 1.2.0 ``` If you are using Gradle, add the below dependency to your build.gradle file: ```groovy -compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '1.1.2' +compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '1.2.0' ``` ```java @@ -78,7 +78,7 @@ public class EnumerateDevices { ## Prerequisite - Java 22 or higher, available at [jdk.java.net](https://jdk.java.net/), [Azul](https://www.azul.com/downloads/?package=jdk), [Adoptium](https://adoptium.net/temurin/releases/) or with your favorite package manager. -- Windows (x86 64-bit), macOS (x86 64-bit, ARM 64-bit) or Linux 64 bit (x86 64-bit, ARM 64-bit). +- Windows (x86 64-bit, ARM 64-bit), macOS (x86 64-bit, ARM 64-bit) or Linux 64 bit (x86 64-bit, ARM 64-bit). @@ -92,7 +92,7 @@ No special considerations apply. Using this library, a Java application can conn ### Linux -*libudev* is used to discover and monitor USB devices. It is closely tied to *systemd*. So the library runs on Linux distributions with *systemd* and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfill this requirement. It runs on both Intel and ARM64 processors. +*libudev* is used to discover and monitor USB devices. It is closely tied to *systemd*. So the library runs on Linux distributions with *systemd* and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfill this requirement. It runs on both Intel/AMD and ARM processors. Similar to macOS, a Java application can connect to any USB device and claim any interface that isn't claimed by an operating system driver or another application. Standard operation system drivers can be unloaded (without the need for root privileges). @@ -117,7 +117,7 @@ USB devices can implement special control requests to instruct Windows to automa The test devices implement the required control requests. So the driver is installed automatically. -Windows for ARM64 is not yet supported. It will once an official Java build for version 22 or higher is available. +The implementation runs on both Windows for Intel/AMD and ARM processors. Few OpenJDK distributions support Windows on ARM, and they do not support all recent versions of Java. [Eclipse Temurin](https://adoptium.net/temurin/releases/?os=windows&arch=aarch64&version=23) has released a version for Java 23. diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index 960bc44a..bd8e5fdd 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] --------------< net.codecrete.usb.examples:bulk-transfer >-------------- -[INFO] Building bulk-transfer 1.1.2 +[INFO] Building bulk-transfer 1.2.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ bulk-transfer --- diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index 84e0aea1..46af793d 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples bulk-transfer - 1.1.2 + 1.2.0 bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.1.2 + 1.2.0 diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index 2ecd19b9..7c16a27e 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] ----------------< net.codecrete.usb.examples:enumerate >---------------- -[INFO] Building enumerate 1.1.2 +[INFO] Building enumerate 1.2.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ enumerate --- diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index b59f45b0..aa1cab83 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples enumerate - 1.1.2 + 1.2.0 enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.1.2 + 1.2.0 org.tinylog diff --git a/examples/enumerate_kotlin/README.md b/examples/enumerate_kotlin/README.md index 05a2871d..b52bdaeb 100644 --- a/examples/enumerate_kotlin/README.md +++ b/examples/enumerate_kotlin/README.md @@ -40,7 +40,7 @@ $ mvn clean package ### Run the jar ```shell -$ java --enable-native-access=ALL-UNNAMED -jar target/enumerate-1.1.2-jar-with-dependencies.jar +$ java --enable-native-access=ALL-UNNAMED -jar target/enumerate-1.2.0-jar-with-dependencies.jar Device: VID: 0xcafe PID: 0xceaf diff --git a/examples/enumerate_kotlin/pom.xml b/examples/enumerate_kotlin/pom.xml index ed4676b6..70a99a87 100644 --- a/examples/enumerate_kotlin/pom.xml +++ b/examples/enumerate_kotlin/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples enumerate - 1.1.2 + 1.2.0 jar enumerate @@ -64,7 +64,7 @@ net.codecrete.usb java-does-usb - 1.1.2 + 1.2.0 org.tinylog diff --git a/examples/epaper_display/README.md b/examples/epaper_display/README.md index e15eccd5..2b75482f 100644 --- a/examples/epaper_display/README.md +++ b/examples/epaper_display/README.md @@ -45,7 +45,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -------------< net.codecrete.usb.examples:epaper-display >-------------- -[INFO] Building epaper-display 1.1.2 +[INFO] Building epaper-display 1.2.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ epaper-display --- @@ -79,6 +79,6 @@ $ sudo -i Password: $ cd /Users/me/Documents/JavaDoesUSB/examples/epaper_display $ export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-20.jdk/Contents/Home -$ $JAVA_HOME/bin/java --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/1.1.2/java-does-usb-1.1.2.jar net.codecrete.usb.examples.EPaperDisplay +$ $JAVA_HOME/bin/java --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/1.2.0/java-does-usb-1.2.0.jar net.codecrete.usb.examples.EPaperDisplay Display size: 1200 x 825 ``` diff --git a/examples/epaper_display/pom.xml b/examples/epaper_display/pom.xml index d1630422..7ba68557 100644 --- a/examples/epaper_display/pom.xml +++ b/examples/epaper_display/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples epaper-display - 1.1.2 + 1.2.0 epaper-display https://github.com/manuelbl/JavaDoesUSB/examples/epaper_display @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.1.2 + 1.2.0 diff --git a/examples/monitor/README.md b/examples/monitor/README.md index eb4fe6be..271fec69 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -----------------< net.codecrete.usb.examples:monitor >----------------- -[INFO] Building monitor 1.1.2 +[INFO] Building monitor 1.2.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ monitor --- diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index f09f7144..a927df0e 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples monitor - 1.1.2 + 1.2.0 monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.1.2 + 1.2.0 org.tinylog diff --git a/examples/monitor_kotlin/README.md b/examples/monitor_kotlin/README.md index 6a1b72d3..69056f03 100644 --- a/examples/monitor_kotlin/README.md +++ b/examples/monitor_kotlin/README.md @@ -40,7 +40,7 @@ $ mvn clean package ### Run the jar ```shell -$ java --enable-native-access=ALL-UNNAMED -jar target/monitor-1.1.2-jar-with-dependencies.jar +$ java --enable-native-access=ALL-UNNAMED -jar target/monitor-1.2.0-jar-with-dependencies.jar Present: VID: 0x1d6b, PID: 0x0002, manufacturer: Linux 6.5.0-18-generic xhci-hcd, product: xHCI Host Controller, serial: 0000:00:14.0, ID: /dev/bus/usb/001/001 Present: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 35A737883336, ID: /dev/bus/usb/001/009 Monitoring... Press ENTER to quit. diff --git a/examples/monitor_kotlin/pom.xml b/examples/monitor_kotlin/pom.xml index ec6ad73a..766851b4 100644 --- a/examples/monitor_kotlin/pom.xml +++ b/examples/monitor_kotlin/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples monitor - 1.1.2 + 1.2.0 jar monitor @@ -64,7 +64,7 @@ net.codecrete.usb java-does-usb - 1.1.2 + 1.2.0 org.tinylog diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index deceb358..5072eb70 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -58,7 +58,7 @@ Run the command below (adapting the file path depending on your specific board): ```shell $ mvn package -$ java --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-1.1.2.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin +$ java --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-1.2.0.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin DFU device found with serial 35A737883336. Target memory segment: Internal Flash Erasing page at 0x8000000 (size 0x4000) diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index ad13ac30..ed607b89 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples stm_dfu - 1.1.2 + 1.2.0 stm_dfu https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu @@ -19,7 +19,7 @@ net.codecrete.usb java-does-usb - 1.1.2 + 1.2.0 diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index f431b574..35d94d9e 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 1.1.2 + 1.2.0 22 From a4da0d558c298f63cc725754d57fe7baecf0a993 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Sat, 5 Apr 2025 21:07:14 +0200 Subject: [PATCH 379/433] Use Windows API generator --- java-does-usb/.mvn/wrapper/maven-wrapper.jar | Bin 62547 -> 0 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 - java-does-usb/jextract/README.md | 21 +- java-does-usb/jextract/windows/gen_win.cmd | 143 ---- .../jextract/windows/windows_headers.h | 6 - java-does-usb/pom.xml | 99 ++- .../src/main/java/net/codecrete/usb/Usb.java | 1 + .../codecrete/usb/UsbAlternateInterface.java | 4 +- .../java/net/codecrete/usb/UsbDevice.java | 8 +- .../java/net/codecrete/usb/UsbInterface.java | 4 +- .../usb/common/CompositeFunction.java | 17 + .../codecrete/usb/common/Configuration.java | 6 +- .../usb/common/EndpointInputStream.java | 6 +- .../usb/common/EndpointOutputStream.java | 4 +- .../codecrete/usb/common/ScopeCleanup.java | 3 +- .../codecrete/usb/common/UsbDeviceImpl.java | 6 +- .../usb/common/UsbDeviceRegistry.java | 2 +- .../java/net/codecrete/usb/linux/EPoll.java | 22 +- .../codecrete/usb/linux/LinuxAsyncTask.java | 2 +- .../net/codecrete/usb/macos/IoKitUsb.java | 16 +- .../codecrete/usb/macos/MacosUsbDevice.java | 2 +- .../usb/usbstandard/StringDescriptor.java | 4 +- .../net/codecrete/usb/windows/CustomApis.java | 58 ++ .../codecrete/usb/windows/DeviceInfoSet.java | 156 ++-- .../usb/windows/DevicePropertyKey.java | 77 -- .../usb/windows/InterfaceHandle.java | 1 + .../codecrete/usb/windows/UsbConstants.java | 32 - .../java/net/codecrete/usb/windows/Win.java | 87 +-- .../usb/windows/WindowsAsyncTask.java | 21 +- .../usb/windows/WindowsUsbDevice.java | 102 ++- .../usb/windows/WindowsUsbDeviceRegistry.java | 176 ++--- .../usb/windows/WindowsUsbException.java | 32 +- .../usb/windows/gen/advapi32/Advapi32.java | 182 ----- .../usb/windows/gen/kernel32/Kernel32.java | 448 ----------- .../usb/windows/gen/kernel32/_GUID.java | 298 ------- .../usb/windows/gen/kernel32/_OVERLAPPED.java | 365 --------- .../usb/windows/gen/ntdll/NtDll.java | 82 -- .../usb/windows/gen/ole32/Ole32.java | 122 --- .../usb/windows/gen/setupapi/SetupAPI.java | 232 ------ .../usb/windows/gen/setupapi/_DEVPROPKEY.java | 173 ----- .../usb/windows/gen/setupapi/_GUID.java | 298 ------- .../setupapi/_SP_DEVICE_INTERFACE_DATA.java | 265 ------- .../_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java | 207 ----- .../gen/setupapi/_SP_DEVINFO_DATA.java | 265 ------- .../usb/windows/gen/usbioctl/USBIoctl.java | 91 --- .../gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java | 579 -------------- .../gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java | 725 ------------------ .../usbioctl/_USB_ENDPOINT_DESCRIPTOR.java | 357 --------- .../_USB_NODE_CONNECTION_INFORMATION_EX.java | 532 ------------- .../windows/gen/usbioctl/_USB_PIPE_INFO.java | 173 ----- .../usb/windows/gen/user32/User32.java | 178 ----- .../_DEV_BROADCAST_DEVICEINTERFACE_W.java | 345 --------- .../gen/user32/_DEV_BROADCAST_HDR.java | 219 ------ .../usb/windows/gen/user32/_GUID.java | 298 ------- .../usb/windows/gen/user32/tagMSG.java | 359 --------- .../usb/windows/gen/user32/tagPOINT.java | 173 ----- .../windows/gen/user32/tagWNDCLASSEXW.java | 633 --------------- .../usb/windows/gen/winusb/WinUSB.java | 139 ---- .../usb/windows/winsdk/Kernel32B.java | 110 --- .../usb/windows/winsdk/SetupAPI2.java | 191 ----- .../codecrete/usb/windows/winsdk/User32B.java | 104 --- .../codecrete/usb/windows/winsdk/WinUSB2.java | 178 ----- .../codecrete/usb/AlternateInterfaceTest.java | 6 +- .../net/codecrete/usb/BulkTransferTest.java | 1 + .../usb/ConfigurationParserTest.java | 260 ------- .../codecrete/usb/InvalidOperationTest.java | 2 +- .../java/net/codecrete/usb/SpeedTest.java | 3 +- .../java/net/codecrete/usb/StallTest.java | 4 +- .../java/net/codecrete/usb/StreamTest.java | 7 +- .../net/codecrete/usb/TestDeviceBase.java | 4 +- .../java/net/codecrete/usb/TimeoutTest.java | 2 +- .../ConfigurationDescriptors.java | 4 +- .../usb/common/ConfigurationParserTest.java | 252 ++++++ .../net/codecrete/usb/special/Continuous.java | 8 +- .../codecrete/usb/special/LogicAnalyzer.java | 29 +- .../codecrete/usb/special/MonitorDevices.java | 6 +- .../net/codecrete/usb/special/USBSerial.java | 4 +- .../net/codecrete/usb/special/Unplug.java | 11 +- .../StringDescriptorTest.java | 8 +- 79 files changed, 805 insertions(+), 9263 deletions(-) delete mode 100644 java-does-usb/.mvn/wrapper/maven-wrapper.jar delete mode 100644 java-does-usb/.mvn/wrapper/maven-wrapper.properties delete mode 100644 java-does-usb/jextract/windows/gen_win.cmd delete mode 100644 java-does-usb/jextract/windows/windows_headers.h create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/CustomApis.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/DevicePropertyKey.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/UsbConstants.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_GUID.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_ENDPOINT_DESCRIPTOR.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_PIPE_INFO.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_GUID.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagPOINT.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java delete mode 100644 java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java delete mode 100644 java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java rename java-does-usb/src/test/java/net/codecrete/usb/{ => common}/ConfigurationDescriptors.java (99%) create mode 100644 java-does-usb/src/test/java/net/codecrete/usb/common/ConfigurationParserTest.java rename java-does-usb/src/test/java/net/codecrete/usb/{ => usbstandard}/StringDescriptorTest.java (93%) diff --git a/java-does-usb/.mvn/wrapper/maven-wrapper.jar b/java-does-usb/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index cb28b0e37c7d206feb564310fdeec0927af4123a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62547 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 A?*IS* diff --git a/java-does-usb/.mvn/wrapper/maven-wrapper.properties b/java-does-usb/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index 346d645f..00000000 --- a/java-does-usb/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,18 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index eb94c181..b730400a 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -15,7 +15,7 @@ The resulting code is then committed to the source code repository. - According to the jextract mailing list, it would be required to create separate code for Intel x64 and ARM64 architecture. And jextract would need to be run on each architecture separately (no cross-compilation). Fortunately, this doesn't seem to be the case. Linux code generated on Intel x64 also runs on ARM64 without change. The same holds for macOS. However, jextract needs to be run on each operating system separately. -- The *Foreign Function And Memory* API has the abilitiy to save the thread-specific error values (`GetLastError()` on Windows, `errno` on Linux). This is required as the JVM calls operation system functions as well, which overwrite the result values. To save the values, an additional parameter must be added to function calls. Unfortunately, this is not supported by jextract. So a good number of function bindings have to be written manually. +- The *Foreign Function And Memory* API has the abilitiy to save the thread-specific error values (`GetLastError()` on Windows, `errno` on Linux). This is required as the JVM calls operating system functions as well, which overwrite the result values. To save the values, an additional parameter must be added to function calls. Unfortunately, this is not supported by jextract. So a good number of function bindings have to be written manually. - *jextract* is not really transparent about what it does. It often skips elements without providing any information. In particular, it will silently skip a requested element in these cases: @@ -53,22 +53,11 @@ Most of the required native functions on macOS are part of a framework. Framewor ## Windows -Most Windows SDK header files are not independent. They require `Windows.h` to be included first. So instead of specifying the target header files directly, a helper header file (`windows_headers.h` in this directory) is specified. - -Compared to Linux and macOS, the code generation on Windows is very slow (about 1 min vs 3 seconds). And jextract crashes sometimes. - -The known limitations are: - -- Variable size `struct`: Several Windows struct are of variable size. The last member is an array. The `struct` definition specifies array length 1. But you are expected to allocate more space depending on the actual array size you need. *jextract* generates code for array length 1 and checks the length when the members are accessed. So the generated code is difficult to use. Variable size `struct`s are a pain - in any language. - -- GUID constants like `GUID_DEVINTERFACE_USB_DEVICE` do not work. While code is generated, the code fails at run-time as it is unable to locate the symbol. This is due to the fact that `GUID_DEVINTERFACE_USB_DEVICE` actually resolve to a variable definition and not to a variable declaration. The GUID constant is not contained in any library; instead the header files use linkage options to generate the constant in the callers code, which does not work with FFM. Such constants should be skipped by *jextract*. - -- *jextract* is a batch script and turns off *echo mode*. If a single batch scripts has multiple calls of *jextract*, two things need to be considered: - - - If the regular command interpreter `cmd.exe` is used, *jextract* must be called using `call`, i.e. `call jextract header.h`. - - If *PowerShell* is used instead, `call` is not needed but *PowerShell* must be configured to allow the execution of scripts. - - *jextract* turns off *echo mode*. So the first call will behave differently than the following calls. +The Windows code is not generated with _jextract_ but with [Windows API Generator](https://github.com/manuelbl/WindowsApiGenerator) +instead. It is run as a Maven plugin. The generated code is not committed to GitHub. +Windows API Generator supports call state capturing (`GetLastError()`), structs with a +variable size, GUID and device property key (`DEVPKEY`) constants etc. ## Code Size diff --git a/java-does-usb/jextract/windows/gen_win.cmd b/java-does-usb/jextract/windows/gen_win.cmd deleted file mode 100644 index fe8a7c99..00000000 --- a/java-does-usb/jextract/windows/gen_win.cmd +++ /dev/null @@ -1,143 +0,0 @@ -set JEXTRACT=..\..\..\..\jextract\bin\jextract.bat -set SDK_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0 - -del /s /q ..\..\src\main\java\net\codecrete\usb\windows\gen -rmdir /s /q ..\..\src\main\java\net\codecrete\usb\windows\gen - -call %JEXTRACT% --output ../../src/main/java ^ - -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ - -I "%SDK_DIR%\um" ^ - -I "%SDK_DIR%\shared" ^ - -l Kernel32 ^ - --header-class-name Kernel32 ^ - --target-package net.codecrete.usb.windows.gen.kernel32 ^ - --include-function CloseHandle ^ - --include-function GetModuleHandleW ^ - --include-function FormatMessageW ^ - --include-function LocalFree ^ - --include-constant ERROR_NO_MORE_ITEMS ^ - --include-constant ERROR_MORE_DATA ^ - --include-constant ERROR_INSUFFICIENT_BUFFER ^ - --include-constant ERROR_FILE_NOT_FOUND ^ - --include-constant ERROR_INVALID_PARAMETER ^ - --include-constant ERROR_GEN_FAILURE ^ - --include-constant ERROR_NOT_FOUND ^ - --include-constant ERROR_IO_PENDING ^ - --include-constant GENERIC_READ ^ - --include-constant GENERIC_WRITE ^ - --include-constant FILE_SHARE_READ ^ - --include-constant FILE_SHARE_WRITE ^ - --include-constant FILE_ATTRIBUTE_NORMAL ^ - --include-constant FILE_FLAG_OVERLAPPED ^ - --include-constant OPEN_EXISTING ^ - --include-constant FORMAT_MESSAGE_ALLOCATE_BUFFER ^ - --include-constant FORMAT_MESSAGE_FROM_SYSTEM ^ - --include-constant FORMAT_MESSAGE_IGNORE_INSERTS ^ - --include-constant FORMAT_MESSAGE_FROM_HMODULE ^ - --include-constant INFINITE ^ - --include-struct _GUID ^ - --include-struct _OVERLAPPED ^ - windows_headers.h - -call %JEXTRACT% --output ../../src/main/java ^ - -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ - -I "%SDK_DIR%\um" ^ - -I "%SDK_DIR%\shared" ^ - -l SetupAPI ^ - --header-class-name SetupAPI ^ - --target-package net.codecrete.usb.windows.gen.setupapi ^ - --include-function SetupDiDestroyDeviceInfoList ^ - --include-function SetupDiDeleteDeviceInterfaceData ^ - --include-struct _SP_DEVINFO_DATA ^ - --include-struct _SP_DEVICE_INTERFACE_DATA ^ - --include-struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W ^ - --include-struct _DEVPROPKEY ^ - --include-struct _GUID ^ - --include-constant DIGCF_PRESENT ^ - --include-constant DIGCF_DEVICEINTERFACE ^ - --include-constant DEVPROP_TYPE_UINT32 ^ - --include-constant DEVPROP_TYPE_STRING ^ - --include-constant DEVPROP_TYPEMOD_LIST ^ - --include-constant DICS_FLAG_GLOBAL ^ - --include-constant DIREG_DEV ^ - windows_headers.h - -call %JEXTRACT% --output ../../src/main/java ^ - -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ - -I "%SDK_DIR%\um" ^ - -I "%SDK_DIR%\shared" ^ - --header-class-name USBIoctl ^ - --target-package net.codecrete.usb.windows.gen.usbioctl ^ - --include-struct _USB_NODE_CONNECTION_INFORMATION_EX ^ - --include-struct _USB_DESCRIPTOR_REQUEST ^ - --include-struct _USB_DEVICE_DESCRIPTOR ^ - --include-struct _USB_ENDPOINT_DESCRIPTOR ^ - --include-struct _USB_PIPE_INFO ^ - --include-constant IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX ^ - --include-constant IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION ^ - windows_headers.h - -call %JEXTRACT% --output ../../src/main/java ^ - -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ - -I "%SDK_DIR%\um" ^ - -I "%SDK_DIR%\shared" ^ - -l User32 ^ - --header-class-name User32 ^ - --target-package net.codecrete.usb.windows.gen.user32 ^ - --include-function DefWindowProcW ^ - --include-constant DEVICE_NOTIFY_WINDOW_HANDLE ^ - --include-constant HWND_MESSAGE ^ - --include-constant WM_DEVICECHANGE ^ - --include-constant DBT_DEVICEARRIVAL ^ - --include-constant DBT_DEVICEREMOVECOMPLETE ^ - --include-constant DBT_DEVTYP_DEVICEINTERFACE ^ - --include-struct tagMSG ^ - --include-struct tagPOINT ^ - --include-struct tagWNDCLASSEXW ^ - --include-struct _DEV_BROADCAST_HDR ^ - --include-struct _DEV_BROADCAST_DEVICEINTERFACE_W ^ - --include-struct _GUID ^ - windows_headers.h - -call %JEXTRACT% --output ../../src/main/java ^ - -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ - -I "%SDK_DIR%\um" ^ - -I "%SDK_DIR%\shared" ^ - -l Winusb ^ - --header-class-name WinUSB ^ - --target-package net.codecrete.usb.windows.gen.winusb ^ - --include-function WinUsb_Free ^ - --include-constant PIPE_TRANSFER_TIMEOUT ^ - --include-constant RAW_IO ^ - windows_headers.h - -call %JEXTRACT% --output ../../src/main/java ^ - -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ - -I "%SDK_DIR%\um" ^ - -I "%SDK_DIR%\shared" ^ - -l Advapi32 ^ - --header-class-name Advapi32 ^ - --target-package net.codecrete.usb.windows.gen.advapi32 ^ - --include-function RegQueryValueExW ^ - --include-function RegCloseKey ^ - --include-constant KEY_READ ^ - windows_headers.h - -call %JEXTRACT% --output ../../src/main/java ^ - -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ - -I "%SDK_DIR%\um" ^ - -I "%SDK_DIR%\shared" ^ - -l Ole32 ^ - --header-class-name Ole32 ^ - --target-package net.codecrete.usb.windows.gen.ole32 ^ - --include-function CLSIDFromString ^ - windows_headers.h - -call %JEXTRACT% --output ../../src/main/java ^ - -D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^ - -I "%SDK_DIR%\um" ^ - -I "%SDK_DIR%\shared" ^ - --header-class-name NtDll ^ - --target-package net.codecrete.usb.windows.gen.ntdll ^ - --include-constant STATUS_UNSUCCESSFUL ^ - windows_headers.h diff --git a/java-does-usb/jextract/windows/windows_headers.h b/java-does-usb/jextract/windows/windows_headers.h deleted file mode 100644 index 171b98ee..00000000 --- a/java-does-usb/jextract/windows/windows_headers.h +++ /dev/null @@ -1,6 +0,0 @@ -#include -#include -#include -#include -#include -#include diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 35d94d9e..9684ae52 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -9,8 +9,8 @@ 1.2.0 - 22 - 22 + 23 + 23 UTF-8 src/main/java/net/codecrete/usb/**/gen/**/* @@ -52,14 +52,97 @@ + + net.codecrete.windows-api + windowsapi-maven-plugin + + + + windows-api + + + + CLSIDFromString + CreateFileW + CreateIoCompletionPort + CreateWindowExW + DefWindowProcW + DeviceIoControl + FormatMessageW + GetMessageW + GetModuleHandleW + GetQueuedCompletionStatus + LocalFree + RegCloseKey + RegQueryValueExW + RegisterClassExW + RegisterDeviceNotificationW + SetupDiCreateDeviceInfoList + SetupDiDeleteDeviceInterfaceData + SetupDiDestroyDeviceInfoList + SetupDiEnumDeviceInfo + SetupDiEnumDeviceInterfaces + SetupDiGetClassDevsW + SetupDiGetDeviceInterfaceDetailW + SetupDiGetDevicePropertyW + SetupDiOpenDevRegKey + SetupDiOpenDeviceInfoW + SetupDiOpenDeviceInterfaceW + WinUsb_AbortPipe + WinUsb_Free + WinUsb_GetAssociatedInterface + WinUsb_Initialize + WinUsb_ReadPipe + WinUsb_ResetPipe + WinUsb_SetCurrentAlternateSetting + WinUsb_SetPipePolicy + WinUsb_WritePipe + + + DEV_BROADCAST_DEVICEINTERFACE_W + DEV_BROADCAST_HDR + USB_DESCRIPTOR_REQUEST + USB_NODE_CONNECTION_INFORMATION_EX + + + DEV_BROADCAST_HDR_DEVICE_TYPE + FORMAT_MESSAGE_OPTIONS + GENERIC_ACCESS_RIGHTS + REG_SAM_FLAGS + SETUP_DI_PROPERTY_CHANGE_SCOPE + + + DBT_DEVICEARRIVAL + DBT_DEVICEREMOVECOMPLETE + DEVPKEY_Device_Address + DEVPKEY_Device_Children + DEVPKEY_Device_HardwareIds + DEVPKEY_Device_InstanceId + DEVPKEY_Device_Parent + DEVPKEY_Device_Service + DIREG_DEV + GUID_DEVINTERFACE_USB_DEVICE + GUID_DEVINTERFACE_USB_HUB + HWND_MESSAGE + INFINITE + IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION + IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX + STATUS_UNSUCCESSFUL + USB_REQUEST_GET_DESCRIPTOR + WM_DEVICECHANGE + + + + + org.apache.maven.plugins maven-compiler-plugin 3.12.1 - 22 - 22 - 22 + 23 + 23 + 23 @@ -129,6 +212,12 @@ true
+ + + net.codecrete.windows-api + windowsapi-maven-plugin + 0.8.0 +
diff --git a/java-does-usb/src/main/java/net/codecrete/usb/Usb.java b/java-does-usb/src/main/java/net/codecrete/usb/Usb.java index 59fb0b20..b17fc604 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/Usb.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/Usb.java @@ -26,6 +26,7 @@ */ public class Usb { + @SuppressWarnings("java:S1192") private static UsbDeviceRegistry createInstance() { var osName = System.getProperty("os.name"); var osArch = System.getProperty("os.arch"); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/UsbAlternateInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbAlternateInterface.java index 68d3bcff..c4cfbefc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/UsbAlternateInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbAlternateInterface.java @@ -71,7 +71,9 @@ public interface UsbAlternateInterface { * * @return a list of endpoints. */ - @NotNull @Unmodifiable List getEndpoints(); + @NotNull + @Unmodifiable + List getEndpoints(); /** * Gets the endpoint with the specified number and direction. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/UsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbDevice.java index 427f5e21..1fe22e9a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/UsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbDevice.java @@ -189,7 +189,9 @@ public interface UsbDevice { * * @return a list of USB interfaces */ - @NotNull @Unmodifiable List getInterfaces(); + @NotNull + @Unmodifiable + List getInterfaces(); /** * Gets the interface with the specified number. @@ -260,7 +262,7 @@ public interface UsbDevice { /** * Executes a control transfer request and optionally sends data. *

- * This method blocks until the device has acknowledge the request or an error has occurred. + * This method blocks until the device has acknowledged the request or an error has occurred. *

*

* The control transfer request is sent to endpoint 0. The transfer is expected to either have @@ -390,7 +392,7 @@ public interface UsbDevice { * and the last packet size was equal to maximum packet size of the endpoint. *

*

- * If {@link #transferOut(int, byte[])} and a output stream or multiple output streams + * If {@link #transferOut(int, byte[])} and an output stream or multiple output streams * are used concurrently for the same endpoint, the behavior is unpredictable. *

* diff --git a/java-does-usb/src/main/java/net/codecrete/usb/UsbInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbInterface.java index 372ebfd1..b0aad6c2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/UsbInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbInterface.java @@ -64,5 +64,7 @@ public interface UsbInterface { * * @return a list of the alternate settings */ - @NotNull @Unmodifiable List getAlternates(); + @NotNull + @Unmodifiable + List getAlternates(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java b/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java index 049bbdc6..b6e751a4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/CompositeFunction.java @@ -45,14 +45,31 @@ public CompositeFunction(int firstInterfaceNumber, int numInterfaces, int classC functionProtocol = protocolCode; } + /** + * Gets the number of the first interface contained in this function. + * @return the interface number + */ public int firstInterfaceNumber() { return firstIntfNumber; } + /** + * Gets the number of interfaces contained in this function. + * @return the number of interfaces + */ public int numInterfaces() { return interfaceCount; } + /** + * Indicates if this function contains the specified interface. + * @param interfaceNumber the interface number + * @return {@code true} if it is contained, {@code false} otherwise + */ + public boolean containsInterface(int interfaceNumber) { + return interfaceNumber >= firstIntfNumber && interfaceNumber < firstIntfNumber + interfaceCount; + } + public int classCode() { return functionCode; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java b/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java index 87c54a71..dc5317d1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/Configuration.java @@ -55,7 +55,8 @@ public void addInterface(UsbInterface intf) { } public UsbInterfaceImpl findInterfaceByNumber(int number) { - return (UsbInterfaceImpl) interfaceList.stream().filter(intf -> intf.getNumber() == number).findFirst().orElse(null); + return (UsbInterfaceImpl) interfaceList.stream().filter(intf -> intf.getNumber() == number) + .findFirst().orElse(null); } public void addFunction(CompositeFunction function) { @@ -63,6 +64,7 @@ public void addFunction(CompositeFunction function) { } public CompositeFunction findFunction(int interfaceNumber) { - return functionList.stream().filter(f -> interfaceNumber >= f.firstInterfaceNumber() && interfaceNumber < f.firstInterfaceNumber() + f.numInterfaces()).findFirst().orElse(null); + return functionList.stream().filter(f -> f.containsInterface(interfaceNumber)) + .findFirst().orElse(null); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index 5db3fb49..224dc2c4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -68,7 +68,7 @@ protected EndpointInputStream(UsbDeviceImpl device, int endpointNumber, int buff // use between 4 and 32 packets per transfer (256B to 2KB for FS, 2KB to 16KB for HS) var numPacketsPerTransfer = (int) Math.round(Math.sqrt((double) bufferSize / packetSize)); - numPacketsPerTransfer = Math.min(Math.max(numPacketsPerTransfer, 4), 32); + numPacketsPerTransfer = Math.clamp(numPacketsPerTransfer, 4, 32); transferSize = numPacketsPerTransfer * packetSize; // use at least 2 outstanding transfers (3 in total) @@ -112,7 +112,7 @@ public void close() throws IOException { try { device.abortTransfers(UsbDirection.IN, endpointNumber); - } catch (UsbException e) { + } catch (UsbException _) { // If aborting the transfer is not possible, the device has // likely been closed or unplugged. So all outstanding // transfers will terminate anyway. @@ -196,7 +196,7 @@ private Transfer waitForCompletedTransfer() { var transfer = completedTransferQueue.take(); numOutstandingTransfers -= 1; return transfer; - } catch (InterruptedException e) { + } catch (InterruptedException _) { Thread.currentThread().interrupt(); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java index 3fb6dc83..e9cbbfae 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -70,7 +70,7 @@ protected EndpointOutputStream(UsbDeviceImpl device, int endpointNumber, int buf // use between 4 and 32 packets per transfer (256B to 2KB for FS, 2KB to 16KB for HS) var numPacketsPerTransfer = (int) Math.round(Math.sqrt((double) bufferSize / packetSize)); - numPacketsPerTransfer = Math.min(Math.max(numPacketsPerTransfer, 4), 32); + numPacketsPerTransfer = Math.clamp(numPacketsPerTransfer, 4, 32); transferSize = numPacketsPerTransfer * packetSize; // use at least 2 outstanding transfers (3 in total) @@ -234,7 +234,7 @@ private Transfer waitForAvailableTransfer() { return transfer; - } catch (InterruptedException e) { + } catch (InterruptedException _) { Thread.currentThread().interrupt(); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java b/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java index 4624a2d2..44f0d8ce 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/ScopeCleanup.java @@ -8,6 +8,7 @@ package net.codecrete.usb.common; import java.util.ArrayList; +import java.util.List; /** * Auto closeable object for clean up actions. @@ -31,7 +32,7 @@ */ public class ScopeCleanup implements AutoCloseable { - private final ArrayList cleanupActions = new ArrayList<>(); + private final List cleanupActions = new ArrayList<>(); /** * Registers a cleanup action to be run later. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java index 137d6c86..427bc749 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java @@ -221,7 +221,7 @@ public void setProductStrings(String manufacturer, String product, String serial /** * Sets the product strings from the device descriptor. *

- * To lookup the string, a lookup function is provided. It takes the + * To look up the string, a lookup function is provided. It takes the * string ID and returns the string from the string descriptor. *

* @@ -393,7 +393,7 @@ private static void waitNoTimeout(Transfer transfer) { while (transfer.resultSize() == -1) { try { transfer.wait(); - } catch (InterruptedException e) { + } catch (InterruptedException _) { Thread.currentThread().interrupt(); } } @@ -409,7 +409,7 @@ private static boolean waitWithTimeout(Transfer transfer, int timeout) { transfer.wait(remainingTimeout); remainingTimeout = expiration - System.currentTimeMillis(); - } catch (InterruptedException e) { + } catch (InterruptedException _) { Thread.currentThread().interrupt(); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceRegistry.java index 54521bbd..b49a19c7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceRegistry.java @@ -204,7 +204,7 @@ protected void closeAndRemoveDevice(Object deviceId) { return; try { - ((UsbDeviceImpl)device).disconnect(); + ((UsbDeviceImpl) device).disconnect(); } catch (Exception e) { LOG.log(INFO, "failed to close disconnected USB device - ignoring exception", e); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java index 2b6c411e..06c684ba 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java @@ -30,25 +30,27 @@ @SuppressWarnings({"OptionalGetWithoutIsPresent", "SameParameterValue", "java:S100", "java:S1192"}) public class EPoll { - private EPoll() {} + private EPoll() { } private static final boolean IS_AARCH64 = System.getProperty("os.arch").equals("aarch64"); private static final GroupLayout DATA$LAYOUT = MemoryLayout.unionLayout( - ADDRESS_UNALIGNED.withName("ptr"), - JAVA_INT_UNALIGNED.withName("fd"), - JAVA_INT_UNALIGNED.withName("u32"), - JAVA_LONG_UNALIGNED.withName("u64") + ADDRESS_UNALIGNED.withName("ptr"), + JAVA_INT_UNALIGNED.withName("fd"), + JAVA_INT_UNALIGNED.withName("u32"), + JAVA_LONG_UNALIGNED.withName("u64") ).withName("epoll_data"); - static final GroupLayout EVENT$LAYOUT = IS_AARCH64 - ? MemoryLayout.structLayout( + static final GroupLayout EVENT$LAYOUT = IS_AARCH64 ? + MemoryLayout.structLayout( JAVA_INT.withName("events"), MemoryLayout.paddingLayout(4), - DATA$LAYOUT.withName("data")).withName("epoll_event") - : MemoryLayout.structLayout( + DATA$LAYOUT.withName("data") + ).withName("epoll_event") : + MemoryLayout.structLayout( JAVA_INT_UNALIGNED.withName("events"), - DATA$LAYOUT.withName("data")).withName("epoll_event"); + DATA$LAYOUT.withName("data") + ).withName("epoll_event"); // varhandle to access the "fd" field in an epoll_event array static final VarHandle EVENT_ARRAY_DATA_FD$VH = EVENT$LAYOUT.arrayElementVarHandle( diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index 079b68e2..b7b39725 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -215,7 +215,7 @@ private static int urbTransferType(UsbTransferType transferType) { /** * Links the specified transfer instance to a URB. *

- * The transfer is assigned an URB instance, and a list + * The transfer is assigned a URB instance, and a list * of associations from URB to transfer is maintained. *

* @param transfer the transfer to assign a URB. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUsb.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUsb.java index f15fa5b5..b1fd6fbe 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUsb.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/IoKitUsb.java @@ -117,8 +117,8 @@ static int GetNumEndpoints(MemorySegment self, MemorySegment intfNumEndpointsHol // IOReturn (*GetPipeProperties)(void *self, UInt8 pipeRef, UInt8 *direction, UInt8 *number, UInt8 *transferType, // UInt16 *maxPacketSize, UInt8 *interval) static int GetPipeProperties(MemorySegment self, byte pipeRef, MemorySegment directionHolder, - MemorySegment numberHolder, MemorySegment transferTypeHolder, - MemorySegment maxPacketSizeHolder, MemorySegment intervalHolder) { + MemorySegment numberHolder, MemorySegment transferTypeHolder, + MemorySegment maxPacketSizeHolder, MemorySegment intervalHolder) { return IOUSBInterfaceStruct190.GetPipeProperties.invoke(IOUSBInterfaceStruct190.GetPipeProperties(getVtable(self)), self, pipeRef, directionHolder, numberHolder, transferTypeHolder, maxPacketSizeHolder, intervalHolder); } @@ -126,7 +126,7 @@ static int GetPipeProperties(MemorySegment self, byte pipeRef, MemorySegment dir // IOReturn (*ReadPipeAsync)(void *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, void // *refcon) static int ReadPipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, - MemorySegment callback, MemorySegment refcon) { + MemorySegment callback, MemorySegment refcon) { return IOUSBInterfaceStruct190.ReadPipeAsync.invoke(IOUSBInterfaceStruct190.ReadPipeAsync(getVtable(self)), self, pipeRef, buf, size, callback, refcon); } @@ -134,8 +134,8 @@ static int ReadPipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, in // IOReturn (*ReadPipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 // completionTimeout, IOAsyncCallback1 callback, void *refcon) static int ReadPipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, - int noDataTimeout, int completionTimeout, MemorySegment callback, - MemorySegment refcon) { + int noDataTimeout, int completionTimeout, MemorySegment callback, + MemorySegment refcon) { return IOUSBInterfaceStruct190.ReadPipeAsyncTO.invoke(IOUSBInterfaceStruct190.ReadPipeAsyncTO(getVtable(self)), self, pipeRef, buf, size, noDataTimeout, completionTimeout, callback, refcon); } @@ -143,7 +143,7 @@ static int ReadPipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, // IOReturn (*WritePipeAsync)(vovoid *self, UInt8 pipeRef, void *buf, UInt32 size, IOAsyncCallback1 callback, // void *refcon) static int WritePipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, int size, - MemorySegment callback, MemorySegment refcon) { + MemorySegment callback, MemorySegment refcon) { return IOUSBInterfaceStruct190.WritePipeAsync.invoke(IOUSBInterfaceStruct190.WritePipeAsync(getVtable(self)), self, pipeRef, buf, size, callback, refcon); } @@ -151,8 +151,8 @@ static int WritePipeAsync(MemorySegment self, byte pipeRef, MemorySegment buf, i // IOReturn (*WritePipeAsyncTO)(void *self, UInt8 pipeRef, void *buf, UInt32 size, UInt32 noDataTimeout, UInt32 // completionTimeout, IOAsyncCallback1 callback, void *refcon) static int WritePipeAsyncTO(MemorySegment self, byte pipeRef, MemorySegment buf, int size, - int noDataTimeout, int completionTimeout, MemorySegment callback, - MemorySegment refcon) { + int noDataTimeout, int completionTimeout, MemorySegment callback, + MemorySegment refcon) { return IOUSBInterfaceStruct190.WritePipeAsyncTO.invoke(IOUSBInterfaceStruct190.WritePipeAsyncTO(getVtable(self)), self, pipeRef, buf, size, noDataTimeout, completionTimeout, callback, refcon); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java index c4b2046c..1eaa9e93 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java @@ -116,7 +116,7 @@ public synchronized void open() { // sleep and retry try { Thread.sleep(90); - } catch (InterruptedException e) { + } catch (InterruptedException _) { Thread.currentThread().interrupt(); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java index de83547e..a324e531 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/usbstandard/StringDescriptor.java @@ -61,11 +61,11 @@ public int length() { public String string() { if (!isValid()) throw new UsbException("String descriptor is invalid"); - var len = (int)(length() - 2L); + var len = (int) (length() - 2L); var bytes = descriptor.asSlice(string$OFFSET, len).toArray(JAVA_BYTE); // truncate trailing 0s - while (len > 0 && bytes[len-2] == 0 && bytes[len-1] == 0) + while (len > 0 && bytes[len - 2] == 0 && bytes[len - 1] == 0) len--; return new String(bytes, 0, len, StandardCharsets.UTF_16LE); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/CustomApis.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/CustomApis.java new file mode 100644 index 00000000..34ecb727 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/CustomApis.java @@ -0,0 +1,58 @@ +package net.codecrete.usb.windows; + +import net.codecrete.usb.usbstandard.SetupPacket; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; + +@SuppressWarnings({"java:S100", "java:S101", "java:S112", "java:S117"}) +public class CustomApis { + private CustomApis() { + } + + static { + System.loadLibrary("KERNEL32"); + System.loadLibrary("WINUSB"); + } + + private static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup(); + private static final Linker LINKER = Linker.nativeLinker(); + private static final Linker.Option LAST_ERROR_STATE = Linker.Option.captureCallState("GetLastError"); + + // Custom implementation of WinUsb_ControlTransfer as FFM cannot deal with the + // WINUSB_SETUP_PACKET being passed by value as it uses unaligned fields. + // SetupPacket does not use unaligned fields. + private static class WinUsb_ControlTransfer$IMPL { + private static final FunctionDescriptor DESC = FunctionDescriptor.of(JAVA_INT, ADDRESS, SetupPacket.LAYOUT, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); + private static final MethodHandle HANDLE = LINKER.downcallHandle(SYMBOL_LOOKUP.findOrThrow("WinUsb_ControlTransfer"), DESC, LAST_ERROR_STATE); + } + + public static int WinUsb_ControlTransfer(MemorySegment lastErrorState, MemorySegment InterfaceHandle, MemorySegment SetupPacket, MemorySegment Buffer, int BufferLength, MemorySegment LengthTransferred, MemorySegment Overlapped) { + try { + return (int) WinUsb_ControlTransfer$IMPL.HANDLE.invokeExact(lastErrorState, InterfaceHandle, SetupPacket, Buffer, BufferLength, LengthTransferred, Overlapped); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + // CloseHandle implementation without error state + private static class CloseHandle$IMPL { + private static final FunctionDescriptor DESC = FunctionDescriptor.of(JAVA_INT, ADDRESS); + private static final MethodHandle HANDLE = LINKER.downcallHandle(SYMBOL_LOOKUP.findOrThrow("CloseHandle"), DESC); + } + + public static int CloseHandle(MemorySegment hObject) { + try { + return (int) CloseHandle$IMPL.HANDLE.invokeExact(hObject); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java index 344753cf..e9d3bfb8 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/DeviceInfoSet.java @@ -1,15 +1,10 @@ package net.codecrete.usb.windows; import net.codecrete.usb.common.ScopeCleanup; -import net.codecrete.usb.windows.gen.advapi32.Advapi32; -import net.codecrete.usb.windows.gen.kernel32.Kernel32; -import net.codecrete.usb.windows.gen.kernel32._GUID; -import net.codecrete.usb.windows.gen.ole32.Ole32; -import net.codecrete.usb.windows.gen.setupapi.SetupAPI; -import net.codecrete.usb.windows.gen.setupapi._SP_DEVICE_INTERFACE_DATA; -import net.codecrete.usb.windows.gen.setupapi._SP_DEVICE_INTERFACE_DETAIL_DATA_W; -import net.codecrete.usb.windows.gen.setupapi._SP_DEVINFO_DATA; -import net.codecrete.usb.windows.winsdk.SetupAPI2; +import system.Guid; +import windows.win32.devices.deviceanddriverinstallation.SP_DEVICE_INTERFACE_DATA; +import windows.win32.devices.deviceanddriverinstallation.SP_DEVICE_INTERFACE_DETAIL_DATA_W; +import windows.win32.devices.deviceanddriverinstallation.SP_DEVINFO_DATA; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; @@ -18,10 +13,38 @@ import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.JAVA_CHAR; import static java.lang.foreign.ValueLayout.JAVA_INT; -import static net.codecrete.usb.windows.DevicePropertyKey.Service; +import static java.nio.charset.StandardCharsets.UTF_16LE; import static net.codecrete.usb.windows.Win.allocateErrorState; import static net.codecrete.usb.windows.WindowsUsbException.throwException; import static net.codecrete.usb.windows.WindowsUsbException.throwLastError; +import static windows.win32.devices.deviceanddriverinstallation.Apis.SetupDiDeleteDeviceInterfaceData; +import static windows.win32.devices.deviceanddriverinstallation.Apis.SetupDiDestroyDeviceInfoList; +import static windows.win32.devices.deviceanddriverinstallation.Apis.SetupDiEnumDeviceInfo; +import static windows.win32.devices.deviceanddriverinstallation.Apis.SetupDiEnumDeviceInterfaces; +import static windows.win32.devices.deviceanddriverinstallation.Apis.SetupDiGetClassDevsW; +import static windows.win32.devices.deviceanddriverinstallation.Apis.SetupDiCreateDeviceInfoList; +import static windows.win32.devices.deviceanddriverinstallation.Apis.SetupDiGetDeviceInterfaceDetailW; +import static windows.win32.devices.deviceanddriverinstallation.Apis.SetupDiGetDevicePropertyW; +import static windows.win32.devices.deviceanddriverinstallation.Apis.SetupDiOpenDevRegKey; +import static windows.win32.devices.deviceanddriverinstallation.Apis.SetupDiOpenDeviceInfoW; +import static windows.win32.devices.deviceanddriverinstallation.Apis.SetupDiOpenDeviceInterfaceW; +import static windows.win32.devices.deviceanddriverinstallation.Constants.DIREG_DEV; +import static windows.win32.devices.deviceanddriverinstallation.SETUP_DI_GET_CLASS_DEVS_FLAGS.DIGCF_DEVICEINTERFACE; +import static windows.win32.devices.deviceanddriverinstallation.SETUP_DI_GET_CLASS_DEVS_FLAGS.DIGCF_PRESENT; +import static windows.win32.devices.deviceanddriverinstallation.SETUP_DI_PROPERTY_CHANGE_SCOPE.DICS_FLAG_GLOBAL; +import static windows.win32.devices.properties.Constants.DEVPKEY_Device_Service; +import static windows.win32.devices.properties.DEVPROPTYPE.DEVPROP_TYPEMOD_LIST; +import static windows.win32.devices.properties.DEVPROPTYPE.DEVPROP_TYPE_STRING; +import static windows.win32.devices.properties.DEVPROPTYPE.DEVPROP_TYPE_UINT32; +import static windows.win32.foundation.WIN32_ERROR.ERROR_FILE_NOT_FOUND; +import static windows.win32.foundation.WIN32_ERROR.ERROR_INSUFFICIENT_BUFFER; +import static windows.win32.foundation.WIN32_ERROR.ERROR_MORE_DATA; +import static windows.win32.foundation.WIN32_ERROR.ERROR_NOT_FOUND; +import static windows.win32.foundation.WIN32_ERROR.ERROR_NO_MORE_ITEMS; +import static windows.win32.system.com.Apis.CLSIDFromString; +import static windows.win32.system.registry.Apis.RegCloseKey; +import static windows.win32.system.registry.Apis.RegQueryValueExW; +import static windows.win32.system.registry.REG_SAM_FLAGS.KEY_READ; /** * Device information set (of Windows Setup API). @@ -35,12 +58,12 @@ public class DeviceInfoSet implements AutoCloseable { @FunctionalInterface interface InfoSetCreator { - MemorySegment create(Arena arena, MemorySegment errorState); + long create(Arena arena, MemorySegment errorState); } private final Arena arena; private final MemorySegment errorState; - private final MemorySegment devInfoSet; + private final long devInfoSet; private final MemorySegment devInfoData; private MemorySegment devIntfData; private int iterationIndex = -1; @@ -60,9 +83,9 @@ interface InfoSetCreator { */ static DeviceInfoSet ofPresentDevices(MemorySegment interfaceGuid, String instanceId) { return new DeviceInfoSet((arena, errorState) -> { - var instanceIdSegment = instanceId != null ? Win.createSegmentFromString(instanceId, arena) : NULL; - return SetupAPI2.SetupDiGetClassDevsW(interfaceGuid, instanceIdSegment, NULL, - SetupAPI.DIGCF_PRESENT() | SetupAPI.DIGCF_DEVICEINTERFACE(), errorState); + var instanceIdSegment = instanceId != null ? arena.allocateFrom(instanceId, UTF_16LE) : NULL; + return SetupDiGetClassDevsW(errorState, interfaceGuid, instanceIdSegment, NULL, + DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); }); } @@ -79,7 +102,7 @@ static DeviceInfoSet ofInstance(String instanceId) { var devInfoSet = ofEmpty(); try { devInfoSet.addInstanceId(instanceId); - } catch (Throwable t) { + } catch (Exception t) { devInfoSet.close(); throw t; } @@ -99,7 +122,7 @@ static DeviceInfoSet ofPath(String devicePath) { var devInfoSet = ofEmpty(); try { devInfoSet.addDevicePath(devicePath); - } catch (Throwable t) { + } catch (Exception t) { devInfoSet.close(); throw t; } @@ -112,7 +135,7 @@ static DeviceInfoSet ofPath(String devicePath) { * @return device info set */ private static DeviceInfoSet ofEmpty() { - return new DeviceInfoSet((_, errorState) -> SetupAPI2.SetupDiCreateDeviceInfoList(NULL, NULL, errorState)); + return new DeviceInfoSet((_, errorState) -> SetupDiCreateDeviceInfoList(errorState, NULL, NULL)); } private DeviceInfoSet(InfoSetCreator creator) { @@ -125,8 +148,7 @@ private DeviceInfoSet(InfoSetCreator creator) { throwLastError(errorState, "internal error (creating device info set)"); // allocate SP_DEVINFO_DATA (will receive device details) - devInfoData = _SP_DEVINFO_DATA.allocate(arena); - _SP_DEVINFO_DATA.cbSize(devInfoData, (int) _SP_DEVINFO_DATA.layout().byteSize()); + devInfoData = SP_DEVINFO_DATA.allocate(arena); } catch (Exception e) { arena.close(); @@ -137,14 +159,14 @@ private DeviceInfoSet(InfoSetCreator creator) { @Override public void close() { if (devIntfData != null) - SetupAPI.SetupDiDeleteDeviceInterfaceData(devInfoSet, devIntfData); - SetupAPI.SetupDiDestroyDeviceInfoList(devInfoSet); + SetupDiDeleteDeviceInterfaceData(errorState, devInfoSet, devIntfData); + SetupDiDestroyDeviceInfoList(errorState, devInfoSet); arena.close(); } private void addInstanceId(String instanceId) { - var instanceIdSegment = Win.createSegmentFromString(instanceId, arena); - if (SetupAPI2.SetupDiOpenDeviceInfoW(devInfoSet, instanceIdSegment, NULL, 0, devInfoData, errorState) == 0) + var instanceIdSegment = arena.allocateFrom(instanceId, UTF_16LE); + if (SetupDiOpenDeviceInfoW(errorState, devInfoSet, instanceIdSegment, NULL, 0, devInfoData) == 0) throwLastError(errorState, "internal error (SetupDiOpenDeviceInfoW)"); } @@ -153,18 +175,16 @@ private void addDevicePath(String devicePath) { throw new AssertionError("calling addDevice() multiple times is not implemented"); // load device information into dev info set - var intfData = _SP_DEVICE_INTERFACE_DATA.allocate(arena); - _SP_DEVICE_INTERFACE_DATA.cbSize(intfData, (int) intfData.byteSize()); - var devicePathSegment = Win.createSegmentFromString(devicePath, arena); - if (SetupAPI2.SetupDiOpenDeviceInterfaceW(devInfoSet, devicePathSegment, 0, intfData, errorState) == 0) + var intfData = SP_DEVICE_INTERFACE_DATA.allocate(arena); + var devicePathSegment = arena.allocateFrom(devicePath, UTF_16LE); + if (SetupDiOpenDeviceInterfaceW(errorState, devInfoSet, devicePathSegment, 0, intfData) == 0) throwLastError(errorState, "internal error (SetupDiOpenDeviceInterfaceW)"); devIntfData = intfData; // for later cleanup - if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSet, intfData, NULL, 0, NULL, - devInfoData, errorState) == 0) { + if (SetupDiGetDeviceInterfaceDetailW(errorState, devInfoSet, intfData, NULL, 0, NULL, devInfoData) == 0) { var err = Win.getLastError(errorState); - if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) + if (err != ERROR_INSUFFICIENT_BUFFER) throwException(err, "internal error (SetupDiGetDeviceInterfaceDetailW)"); } } @@ -176,9 +196,9 @@ private void addDevicePath(String devicePath) { */ boolean next() { iterationIndex += 1; - if (SetupAPI2.SetupDiEnumDeviceInfo(devInfoSet, iterationIndex, devInfoData, errorState) == 0) { + if (SetupDiEnumDeviceInfo(errorState, devInfoSet, iterationIndex, devInfoData) == 0) { var err = Win.getLastError(errorState); - if (err == Kernel32.ERROR_NO_MORE_ITEMS()) + if (err == ERROR_NO_MORE_ITEMS) return false; throwLastError(errorState, "internal error (SetupDiEnumDeviceInfo)"); } @@ -192,7 +212,7 @@ boolean next() { * @return {@code true} if it is a composite device */ boolean isCompositeDevice() { - var deviceService = getStringProperty(Service); + var deviceService = getStringProperty(DEVPKEY_Device_Service()); // usbccgp is the USB Generic Parent Driver used for composite devices return "usbccgp".equalsIgnoreCase(deviceService); @@ -212,14 +232,14 @@ String getDevicePathByGUID(String instanceId) { for (var guid : guids) { // check for class GUID - var guidSegment = Win.createSegmentFromString(guid, arena); - var clsid = _GUID.allocate(arena); - if (Ole32.CLSIDFromString(guidSegment, clsid) != 0) + var guidSegment = arena.allocateFrom(guid, UTF_16LE); + var clsid = Guid.allocate(arena); + if (CLSIDFromString(guidSegment, clsid) != 0) continue; try { return getDevicePath(instanceId, clsid); - } catch (Exception e) { + } catch (Exception _) { // ignore and try next one } } @@ -238,26 +258,26 @@ private List findDeviceInterfaceGUIDs(Arena arena) { try (var cleanup = new ScopeCleanup()) { // open device registry key - var regKey = SetupAPI2.SetupDiOpenDevRegKey(devInfoSet, devInfoData, SetupAPI.DICS_FLAG_GLOBAL(), 0, - SetupAPI.DIREG_DEV(), Advapi32.KEY_READ(), errorState); + var regKey = SetupDiOpenDevRegKey(errorState, devInfoSet, devInfoData, DICS_FLAG_GLOBAL, 0, + DIREG_DEV, KEY_READ); if (Win.isInvalidHandle(regKey)) throwLastError(errorState, "internal error (SetupDiOpenDevRegKey)"); - cleanup.add(() -> Advapi32.RegCloseKey(regKey)); + cleanup.add(() -> RegCloseKey(regKey)); // read registry value (without buffer, to query length) - var keyNameSegment = Win.createSegmentFromString("DeviceInterfaceGUIDs", arena); + var keyNameSegment = arena.allocateFrom("DeviceInterfaceGUIDs", UTF_16LE); var valueTypeHolder = arena.allocate(JAVA_INT); var valueSizeHolder = arena.allocate(JAVA_INT); - var res = Advapi32.RegQueryValueExW(regKey, keyNameSegment, NULL, valueTypeHolder, NULL, valueSizeHolder); - if (res == Kernel32.ERROR_FILE_NOT_FOUND()) + var res = RegQueryValueExW(regKey, keyNameSegment, NULL, valueTypeHolder, NULL, valueSizeHolder); + if (res == ERROR_FILE_NOT_FOUND) return List.of(); // no device interface GUIDs - if (res != 0 && res != Kernel32.ERROR_MORE_DATA()) + if (res != 0 && res != ERROR_MORE_DATA) throwException(res, "internal error (RegQueryValueExW)"); // read registry value (with buffer) var valueSize = valueSizeHolder.get(JAVA_INT, 0); var value = arena.allocate(valueSize); - res = Advapi32.RegQueryValueExW(regKey, keyNameSegment, NULL, valueTypeHolder, value, valueSizeHolder); + res = RegQueryValueExW(regKey, keyNameSegment, NULL, valueTypeHolder, value, valueSizeHolder); if (res != 0) throwException(res, "internal error (RegQueryValueExW)"); @@ -275,11 +295,11 @@ private List findDeviceInterfaceGUIDs(Arena arena) { int getIntProperty(MemorySegment propertyKey) { var propertyTypeHolder = arena.allocate(JAVA_INT); var propertyValueHolder = arena.allocate(JAVA_INT); - if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, - propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, errorState) == 0) + if (SetupDiGetDevicePropertyW(errorState, devInfoSet, devInfoData, propertyKey, propertyTypeHolder, + propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0) == 0) throwLastError(errorState, "internal error (SetupDiGetDevicePropertyW - A)"); - if (propertyTypeHolder.get(JAVA_INT, 0) != SetupAPI.DEVPROP_TYPE_UINT32()) + if (propertyTypeHolder.get(JAVA_INT, 0) != DEVPROP_TYPE_UINT32) throwException("internal error (expected property type UINT32)"); return propertyValueHolder.get(JAVA_INT, 0); @@ -292,10 +312,10 @@ int getIntProperty(MemorySegment propertyKey) { * @return property value */ String getStringProperty(MemorySegment propertyKey) { - var propertyValue = getVariableLengthProperty(propertyKey, SetupAPI.DEVPROP_TYPE_STRING(), arena); + var propertyValue = getVariableLengthProperty(propertyKey, DEVPROP_TYPE_STRING, arena); if (propertyValue == null) return null; - return Win.createStringFromSegment(propertyValue); + return propertyValue.getString(0, UTF_16LE); } /** @@ -307,7 +327,7 @@ String getStringProperty(MemorySegment propertyKey) { @SuppressWarnings("java:S1168") List getStringListProperty(MemorySegment propertyKey) { var propertyValue = getVariableLengthProperty(propertyKey, - SetupAPI.DEVPROP_TYPE_STRING() | SetupAPI.DEVPROP_TYPEMOD_LIST(), arena); + DEVPROP_TYPE_STRING | DEVPROP_TYPEMOD_LIST, arena); if (propertyValue == null) return null; @@ -319,12 +339,12 @@ private MemorySegment getVariableLengthProperty(MemorySegment propertyKey, int p // query length (thus no buffer) var propertyTypeHolder = arena.allocate(JAVA_INT); var requiredSizeHolder = arena.allocate(JAVA_INT); - if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, NULL, 0, - requiredSizeHolder, 0, errorState) == 0) { + if (SetupDiGetDevicePropertyW(errorState, devInfoSet, devInfoData, propertyKey, propertyTypeHolder, NULL, 0, + requiredSizeHolder, 0) == 0) { var err = Win.getLastError(errorState); - if (err == Kernel32.ERROR_NOT_FOUND()) + if (err == ERROR_NOT_FOUND) return null; - if (err != Kernel32.ERROR_INSUFFICIENT_BUFFER()) + if (err != ERROR_INSUFFICIENT_BUFFER) throwException(err, "internal error (SetupDiGetDevicePropertyW - B)"); } @@ -337,8 +357,8 @@ private MemorySegment getVariableLengthProperty(MemorySegment propertyKey, int p var propertyValueHolder = arena.allocate(JAVA_CHAR, stringLen); // get property value - if (SetupAPI2.SetupDiGetDevicePropertyW(devInfoSet, devInfoData, propertyKey, propertyTypeHolder, - propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0, errorState) == 0) + if (SetupDiGetDevicePropertyW(errorState, devInfoSet, devInfoData, propertyKey, propertyTypeHolder, + propertyValueHolder, (int) propertyValueHolder.byteSize(), NULL, 0) == 0) throwLastError(errorState, "internal error (SetupDiGetDevicePropertyW - C)"); return propertyValueHolder; @@ -359,23 +379,17 @@ static String getDevicePath(String instanceId, MemorySegment interfaceGuid) { private String getDevicePathForGuid(MemorySegment interfaceGuid) { // retrieve first element of enumeration - devIntfData = _SP_DEVICE_INTERFACE_DATA.allocate(arena); - _SP_DEVICE_INTERFACE_DATA.cbSize(devIntfData, (int) devIntfData.byteSize()); - if (SetupAPI2.SetupDiEnumDeviceInterfaces(devInfoSet, NULL, interfaceGuid, 0, devIntfData, - errorState) == 0) + devIntfData = SP_DEVICE_INTERFACE_DATA.allocate(arena); + if (SetupDiEnumDeviceInterfaces(errorState, devInfoSet, NULL, interfaceGuid, 0, devIntfData) == 0) throwLastError(errorState, "internal error (SetupDiEnumDeviceInterfaces)"); // get device path - // (SP_DEVICE_INTERFACE_DETAIL_DATA_W is of variable length and requires a bigger allocation so - // the device path fits) - final var devicePathOffset = 4; - var intfDetailData = arena.allocate(4L + 260 * 2); - _SP_DEVICE_INTERFACE_DETAIL_DATA_W.cbSize(intfDetailData, - (int) _SP_DEVICE_INTERFACE_DETAIL_DATA_W.sizeof()); - if (SetupAPI2.SetupDiGetDeviceInterfaceDetailW(devInfoSet, devIntfData, intfDetailData, - (int) intfDetailData.byteSize(), NULL, NULL, errorState) == 0) + var intfDetailData = SP_DEVICE_INTERFACE_DETAIL_DATA_W.allocate(arena, 260); + if (SetupDiGetDeviceInterfaceDetailW(errorState, devInfoSet, devIntfData, intfDetailData, + (int) intfDetailData.byteSize(), NULL, NULL) == 0) throwLastError(errorState, "Internal error (SetupDiGetDeviceInterfaceDetailW)"); - return Win.createStringFromSegment(intfDetailData.asSlice(devicePathOffset)); + var devicePath = SP_DEVICE_INTERFACE_DETAIL_DATA_W.DevicePath(intfDetailData); + return devicePath.getString(0, UTF_16LE); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/DevicePropertyKey.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/DevicePropertyKey.java deleted file mode 100644 index 18ff46e9..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/DevicePropertyKey.java +++ /dev/null @@ -1,77 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.windows; - -import net.codecrete.usb.windows.gen.setupapi._DEVPROPKEY; - -import java.lang.foreign.Arena; -import java.lang.foreign.MemorySegment; - -/** - * Device property keys (GUIDs) - */ -class DevicePropertyKey { - - private DevicePropertyKey() { - } - - /** - * DEVPKEY_Device_Address - */ - static final MemorySegment Address = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, - (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50 - , (byte) 0xe0, 30); - - /** - * DEVPKEY_Device_InstanceId - */ - static final MemorySegment InstanceId = createDEVPROPKEY(0x78c34fc8, (short) 0x104a, - (short) 0x4aca, (byte) 0x9e, (byte) 0xa4, (byte) 0x52, (byte) 0x4d, (byte) 0x52, (byte) 0x99, (byte) 0x6e - , (byte) 0x57, 256); - - /** - * DEVPKEY_Device_Parent - */ - static final MemorySegment Parent = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, - (short) 0x4706, (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, (byte) 0x80, (byte) 0x08, (byte) 0xa5 - , (byte) 0xa7, 8); - - /** - * DEVPKEY_Device_Service - */ - static final MemorySegment Service = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, - (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50 - , (byte) 0xe0, 6); - - /** - * DEVPKEY_Device_Children - */ - static final MemorySegment Children = createDEVPROPKEY(0x4340a6c5, (short) 0x93fa, - (short) 0x4706, (byte) 0x97, (byte) 0x2c, (byte) 0x7b, (byte) 0x64, (byte) 0x80, (byte) 0x08, (byte) 0xa5 - , (byte) 0xa7, 9); - - /** - * DEVPKEY_Device_HardwareIds - */ - static final MemorySegment HardwareIds = createDEVPROPKEY(0xa45c254e, (short) 0xdf1c, - (short) 0x4efd, (byte) 0x80, (byte) 0x20, (byte) 0x67, (byte) 0xd1, (byte) 0x46, (byte) 0xa8, (byte) 0x50 - , (byte) 0xe0, 3); - - - @SuppressWarnings({"java:S107", "java:S117"}) - private static MemorySegment createDEVPROPKEY(int data1, short data2, short data3, byte data4_0, byte data4_1, - byte data4_2, byte data4_3, byte data4_4, byte data4_5, - byte data4_6, byte data4_7, int pid) { - @SuppressWarnings("resource") - var propKey = Arena.global().allocate(_DEVPROPKEY.layout()); - Win.setGUID(_DEVPROPKEY.fmtid(propKey), data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4 - , data4_5, data4_6, data4_7); - _DEVPROPKEY.pid(propKey, pid); - return propKey; - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java index ea4160c4..c3d56a74 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/InterfaceHandle.java @@ -17,6 +17,7 @@ class InterfaceHandle { this.interfaceNumber = interfaceNumber; this.firstInterfaceNumber = firstInterfaceNumber; } + /** * The number of this interface. */ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/UsbConstants.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/UsbConstants.java deleted file mode 100644 index da14dffe..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/UsbConstants.java +++ /dev/null @@ -1,32 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// - -package net.codecrete.usb.windows; - -import java.lang.foreign.MemorySegment; - -/** - * USB constants (general ones and Windows specific ones) - */ -@SuppressWarnings({"java:S125", "java:S1192", "java:S115", "java:S100"}) -class UsbConstants { - - private UsbConstants() { - } - - static final byte USB_REQUEST_GET_DESCRIPTOR = 0x06; - - // A5DCBF10-6530-11D2-901F-00C04FB951ED - static final MemorySegment GUID_DEVINTERFACE_USB_DEVICE = Win.createGUID(0xA5DCBF10, (short) 0x6530, - (short) 0x11D2, (byte) 0x90, (byte) 0x1F, (byte) 0x00, (byte) 0xC0, (byte) 0x4F, (byte) 0xB9, (byte) 0x51 - , (byte) 0xED); - - // f18a0e88-c30c-11d0-8815-00a0c906bed8 - static final MemorySegment GUID_DEVINTERFACE_USB_HUB = Win.createGUID(0xf18a0e88, (short) 0xc30c, - (short) 0x11d0, (byte) 0x88, (byte) 0x15, (byte) 0x00, (byte) 0xa0, (byte) 0xc9, (byte) 0x06, (byte) 0xbe - , (byte) 0xd8); -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java index 59b64f84..6f5791bf 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/Win.java @@ -7,20 +7,17 @@ package net.codecrete.usb.windows; -import net.codecrete.usb.windows.gen.kernel32._GUID; - import java.lang.foreign.Arena; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout.PathElement; import java.lang.foreign.MemorySegment; import java.lang.foreign.StructLayout; -import java.lang.foreign.ValueLayout; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.List; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_CHAR; +import static java.nio.charset.StandardCharsets.UTF_16LE; /** * Windows helpers. @@ -63,45 +60,19 @@ public static boolean isInvalidHandle(MemorySegment handle) { } /** - * Creates a memory segment as a copy of a Java string. - *

- * The memory segment contains a copy of the string (null-terminated, UTF-16/wide characters). - *

- * - * @param str the string to copy - * @param arena the arena for the memory segment - * @return the resulting memory segment - */ - public static MemorySegment createSegmentFromString(String str, Arena arena) { - // allocate segment (including space for terminating null) - var segment = arena.allocate(ValueLayout.JAVA_CHAR, str.length() + 1L); - // copy characters - segment.copyFrom(MemorySegment.ofArray(str.toCharArray())); - return segment; - } - - /** - * Creates a copy of the string in the memory segment. - *

- * The string must be a null-terminated UTF-16 (wide character) string. - *

+ * Checks if a Windows handle is invalid. * - * @param segment the memory segment - * @return copied string + * @param handle Windows handle + * @return {@code true} if the handle is invalid, {@code false} otherwise */ - public static String createStringFromSegment(MemorySegment segment) { - var len = 0; - while (segment.get(JAVA_CHAR, len) != 0) { - len += 2; - } - - return new String(segment.asSlice(0, len).toArray(JAVA_CHAR)); + public static boolean isInvalidHandle(long handle) { + return handle == -1L; } /** * Creates a copy of the string list in the memory segment. *

- * The string list a a series of null-terminated UTF-16 (wide character) strings. + * The string list is a series of null-terminated UTF-16 (wide character) strings. * The list is terminated with yet another null character. *

* @@ -112,52 +83,10 @@ public static List createStringListFromSegment(MemorySegment segment) { var stringList = new ArrayList(); var offset = 0; while (segment.get(JAVA_CHAR, offset) != '\0') { - var str = Win.createStringFromSegment(segment.asSlice(offset)); + var str = segment.getString(offset, UTF_16LE); offset += str.length() * 2 + 2; stringList.add(str); } return stringList; } - - /** - * Creates a GUID in native memory. - * - * @param data1 Group 1 (4 bytes). - * @param data2 Group 2 (2 bytes). - * @param data3 Group 3 (2 bytes). - * @param data4_0 Byte 0 of group 4 - * @param data4_1 Byte 1 of group 4 - * @param data4_2 Byte 2 of group 4 - * @param data4_3 Byte 3 of group 4 - * @param data4_4 Byte 4 of group 4 - * @param data4_5 Byte 5 of group 4 - * @param data4_6 Byte 6 of group 4 - * @param data4_7 Byte 7 of group 4 - * @return GUID as memory segment - */ - @SuppressWarnings({"java:S117", "java:S107", "resource"}) - public static MemorySegment createGUID(int data1, short data2, short data3, byte data4_0, byte data4_1, - byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, - byte data4_7) { - var guid = Arena.global().allocate(_GUID.layout()); - setGUID(guid, data1, data2, data3, data4_0, data4_1, data4_2, data4_3, data4_4, data4_5, data4_6, data4_7); - return guid; - } - - @SuppressWarnings({"java:S117", "java:S107"}) - public static void setGUID(MemorySegment guid, int data1, short data2, short data3, byte data4_0, byte data4_1, - byte data4_2, byte data4_3, byte data4_4, byte data4_5, byte data4_6, byte data4_7) { - _GUID.Data1(guid, data1); - _GUID.Data2(guid, data2); - _GUID.Data3(guid, data3); - var data4 = _GUID.Data4(guid); - data4.set(JAVA_BYTE, 0, data4_0); - data4.set(JAVA_BYTE, 1, data4_1); - data4.set(JAVA_BYTE, 2, data4_2); - data4.set(JAVA_BYTE, 3, data4_3); - data4.set(JAVA_BYTE, 4, data4_4); - data4.set(JAVA_BYTE, 5, data4_5); - data4.set(JAVA_BYTE, 6, data4_6); - data4.set(JAVA_BYTE, 7, data4_7); - } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java index 8150b78a..ee06eafe 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java @@ -7,9 +7,7 @@ package net.codecrete.usb.windows; -import net.codecrete.usb.windows.gen.kernel32.Kernel32; -import net.codecrete.usb.windows.gen.kernel32._OVERLAPPED; -import net.codecrete.usb.windows.winsdk.Kernel32B; +import windows.win32.system.io.OVERLAPPED; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; @@ -24,6 +22,9 @@ import static java.lang.foreign.ValueLayout.JAVA_LONG; import static net.codecrete.usb.windows.Win.allocateErrorState; import static net.codecrete.usb.windows.WindowsUsbException.throwLastError; +import static windows.win32.system.io.Apis.CreateIoCompletionPort; +import static windows.win32.system.io.Apis.GetQueuedCompletionStatus; +import static windows.win32.system.threading.Constants.INFINITE; /** * Background task for handling asynchronous transfers. @@ -77,8 +78,8 @@ private void asyncCompletionTask() { overlappedHolder.set(ADDRESS, 0, NULL); completionKeyHolder.set(JAVA_LONG, 0, 0); - var res = Kernel32B.GetQueuedCompletionStatus(asyncIoCompletionPort, numBytesHolder, - completionKeyHolder, overlappedHolder, Kernel32.INFINITE(), errorState); + var res = GetQueuedCompletionStatus(errorState, asyncIoCompletionPort, numBytesHolder, + completionKeyHolder, overlappedHolder, INFINITE); var overlappedAddr = overlappedHolder.get(JAVA_LONG, 0); if (res == 0 && overlappedAddr == 0) @@ -106,8 +107,8 @@ synchronized void addDevice(MemorySegment handle) { var errorState = allocateErrorState(arena); // Creates a new port if it doesn't exist; adds handle to existing port if it exists - var portHandle = Kernel32B.CreateIoCompletionPort(handle, asyncIoCompletionPort, - handle.address(), 0, errorState); + var portHandle = CreateIoCompletionPort(errorState, handle, asyncIoCompletionPort, + handle.address(), 0); if (portHandle == MemorySegment.NULL) throwLastError(errorState, "internal error (CreateIoCompletionPort)"); @@ -138,7 +139,7 @@ synchronized void prepareForSubmission(WindowsTransfer transfer) { MemorySegment overlapped; var size = availableOverlappedStructs.size(); if (size == 0) { - overlapped = _OVERLAPPED.allocate(overlappedArena); + overlapped = OVERLAPPED.allocate(overlappedArena); } else { overlapped = availableOverlappedStructs.remove(size - 1); } @@ -158,8 +159,8 @@ private synchronized void completeTransfer(long overlappedAddr) { if (transfer == null) return; - transfer.setResultCode((int) _OVERLAPPED.Internal(transfer.overlapped())); - transfer.setResultSize((int) _OVERLAPPED.InternalHigh(transfer.overlapped())); + transfer.setResultCode((int) OVERLAPPED.Internal(transfer.overlapped())); + transfer.setResultSize((int) OVERLAPPED.InternalHigh(transfer.overlapped())); availableOverlappedStructs.add(transfer.overlapped()); transfer.setOverlapped(null); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java index d59e071e..f8001437 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java @@ -15,10 +15,6 @@ import net.codecrete.usb.common.Transfer; import net.codecrete.usb.common.UsbDeviceImpl; import net.codecrete.usb.usbstandard.SetupPacket; -import net.codecrete.usb.windows.gen.kernel32.Kernel32; -import net.codecrete.usb.windows.gen.winusb.WinUSB; -import net.codecrete.usb.windows.winsdk.Kernel32B; -import net.codecrete.usb.windows.winsdk.WinUSB2; import org.jetbrains.annotations.NotNull; import java.io.InputStream; @@ -36,13 +32,36 @@ import static java.lang.foreign.ValueLayout.ADDRESS; import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.nio.charset.StandardCharsets.UTF_16LE; import static net.codecrete.usb.common.ForeignMemory.dereference; -import static net.codecrete.usb.windows.DevicePropertyKey.Children; -import static net.codecrete.usb.windows.DevicePropertyKey.HardwareIds; +import static net.codecrete.usb.windows.CustomApis.CloseHandle; +import static net.codecrete.usb.windows.CustomApis.WinUsb_ControlTransfer; import static net.codecrete.usb.windows.Win.allocateErrorState; import static net.codecrete.usb.windows.WindowsUsbException.throwException; import static net.codecrete.usb.windows.WindowsUsbException.throwLastError; -import static net.codecrete.usb.windows.gen.kernel32.Kernel32.ERROR_INVALID_PARAMETER; +import static windows.win32.devices.properties.Constants.DEVPKEY_Device_Children; +import static windows.win32.devices.properties.Constants.DEVPKEY_Device_HardwareIds; +import static windows.win32.devices.usb.Apis.WinUsb_AbortPipe; +import static windows.win32.devices.usb.Apis.WinUsb_Free; +import static windows.win32.devices.usb.Apis.WinUsb_GetAssociatedInterface; +import static windows.win32.devices.usb.Apis.WinUsb_Initialize; +import static windows.win32.devices.usb.Apis.WinUsb_ReadPipe; +import static windows.win32.devices.usb.Apis.WinUsb_ResetPipe; +import static windows.win32.devices.usb.Apis.WinUsb_SetCurrentAlternateSetting; +import static windows.win32.devices.usb.Apis.WinUsb_SetPipePolicy; +import static windows.win32.devices.usb.Apis.WinUsb_WritePipe; +import static windows.win32.devices.usb.WINUSB_PIPE_POLICY.PIPE_TRANSFER_TIMEOUT; +import static windows.win32.devices.usb.WINUSB_PIPE_POLICY.RAW_IO; +import static windows.win32.foundation.GENERIC_ACCESS_RIGHTS.GENERIC_READ; +import static windows.win32.foundation.GENERIC_ACCESS_RIGHTS.GENERIC_WRITE; +import static windows.win32.foundation.WIN32_ERROR.ERROR_INVALID_PARAMETER; +import static windows.win32.foundation.WIN32_ERROR.ERROR_IO_PENDING; +import static windows.win32.storage.filesystem.Apis.CreateFileW; +import static windows.win32.storage.filesystem.FILE_CREATION_DISPOSITION.OPEN_EXISTING; +import static windows.win32.storage.filesystem.FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL; +import static windows.win32.storage.filesystem.FILE_FLAGS_AND_ATTRIBUTES.FILE_FLAG_OVERLAPPED; +import static windows.win32.storage.filesystem.FILE_SHARE_MODE.FILE_SHARE_READ; +import static windows.win32.storage.filesystem.FILE_SHARE_MODE.FILE_SHARE_WRITE; /** * Windows implementation for USB device. @@ -134,7 +153,7 @@ public void claimInterface(int interfaceNumber) { LOG.log(DEBUG, "Sleeping for 100ms..."); //noinspection BusyWait Thread.sleep(100); - } catch (InterruptedException e) { + } catch (InterruptedException _) { Thread.currentThread().interrupt(); } } @@ -163,10 +182,10 @@ private synchronized boolean claimInterfaceSynchronized(int interfaceNumber) { LOG.log(DEBUG, "opening device {0}", devicePath); // open Windows device if needed - var pathSegment = Win.createSegmentFromString(devicePath, arena); - var deviceHandle = Kernel32B.CreateFileW(pathSegment, Kernel32.GENERIC_WRITE() | Kernel32.GENERIC_READ(), - Kernel32.FILE_SHARE_WRITE() | Kernel32.FILE_SHARE_READ(), NULL, Kernel32.OPEN_EXISTING(), - Kernel32.FILE_ATTRIBUTE_NORMAL() | Kernel32.FILE_FLAG_OVERLAPPED(), NULL, errorState); + var pathSegment = arena.allocateFrom(devicePath, UTF_16LE); + var deviceHandle = CreateFileW(errorState, pathSegment, GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if (Win.isInvalidHandle(deviceHandle)) throwLastError(errorState, "claiming interface failed (opening USB device %s failed)", devicePath); @@ -174,11 +193,11 @@ private synchronized boolean claimInterfaceSynchronized(int interfaceNumber) { try { // open first interface var interfaceHandleHolder = arena.allocate(ADDRESS); - if (WinUSB2.WinUsb_Initialize(deviceHandle, interfaceHandleHolder, errorState) == 0) { - if (Win.getLastError(errorState) == ERROR_INVALID_PARAMETER()) + if (WinUsb_Initialize(errorState, deviceHandle, interfaceHandleHolder) == 0) { + if (Win.getLastError(errorState) == ERROR_INVALID_PARAMETER) throw new UsbException( "claiming interface failed (required WinUSB driver is probably not installed for the device)", - ERROR_INVALID_PARAMETER() + ERROR_INVALID_PARAMETER ); throwLastError(errorState, "claiming interface failed"); } @@ -189,7 +208,7 @@ private synchronized boolean claimInterfaceSynchronized(int interfaceNumber) { asyncTask.addDevice(deviceHandle); } catch (Exception e) { - Kernel32.CloseHandle(deviceHandle); + CloseHandle(deviceHandle); throw e; } } @@ -197,9 +216,9 @@ private synchronized boolean claimInterfaceSynchronized(int interfaceNumber) { if (intfHandle != firstIntfHandle) { // open associated interface var interfaceHandleHolder = arena.allocate(ADDRESS); - if (WinUSB2.WinUsb_GetAssociatedInterface(firstIntfHandle.winusbHandle, - (byte)(intfHandle.interfaceNumber - firstIntfHandle.interfaceNumber - 1), - interfaceHandleHolder, errorState) == 0) + if (WinUsb_GetAssociatedInterface(errorState, firstIntfHandle.winusbHandle, + (byte) (intfHandle.interfaceNumber - firstIntfHandle.interfaceNumber - 1), + interfaceHandleHolder) == 0) throwLastError(errorState, "claiming (associated) interface failed"); intfHandle.winusbHandle = dereference(interfaceHandleHolder); } @@ -222,8 +241,7 @@ public synchronized void selectAlternateSetting(int interfaceNumber, int alterna try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); - if (WinUSB2.WinUsb_SetCurrentAlternateSetting(intfHandle.winusbHandle, (byte) alternateNumber, - errorState) == 0) + if (WinUsb_SetCurrentAlternateSetting(errorState, intfHandle.winusbHandle, (byte) alternateNumber) == 0) throwLastError(errorState, "setting alternate interface failed"); } intf.setAlternate(altSetting); @@ -243,19 +261,19 @@ public synchronized void releaseInterface(int interfaceNumber) { if (intfHandle != firstIntfHandle) { // close associated interface - WinUSB.WinUsb_Free(intfHandle.winusbHandle); + WinUsb_Free(intfHandle.winusbHandle); intfHandle.winusbHandle = null; } // close device if needed firstIntfHandle.deviceOpenCount -= 1; if (firstIntfHandle.deviceOpenCount == 0) { - WinUSB.WinUsb_Free(firstIntfHandle.winusbHandle); + WinUsb_Free(firstIntfHandle.winusbHandle); firstIntfHandle.winusbHandle = null; LOG.log(DEBUG, "closing device {0}", getCachedInterfaceDevicePath(interfaceNumber)); - Kernel32.CloseHandle(firstIntfHandle.deviceHandle); + CloseHandle(firstIntfHandle.deviceHandle); firstIntfHandle.deviceHandle = null; } } @@ -372,10 +390,10 @@ synchronized void submitControlTransfer(UsbDirection direction, UsbControlTransf asyncTask.prepareForSubmission(transfer); // submit transfer - if (WinUSB2.WinUsb_ControlTransfer(intfHandle.winusbHandle, setupPacket.segment(), transfer.data(), - transfer.dataSize(), NULL, transfer.overlapped(), errorState) == 0) { + if (WinUsb_ControlTransfer(errorState, intfHandle.winusbHandle, setupPacket.segment(), transfer.data(), + transfer.dataSize(), NULL, transfer.overlapped()) == 0) { var err = Win.getLastError(errorState); - if (err != Kernel32.ERROR_IO_PENDING()) + if (err != ERROR_IO_PENDING) throwException(err, "submitting control transfer failed"); } } @@ -390,10 +408,10 @@ synchronized void submitTransferOut(int endpointNumber, WindowsTransfer transfer asyncTask.prepareForSubmission(transfer); // submit transfer - if (WinUSB2.WinUsb_WritePipe(intfHandle.winusbHandle, endpoint.endpointAddress(), transfer.data(), - transfer.dataSize(), NULL, transfer.overlapped(), errorState) == 0) { + if (WinUsb_WritePipe(errorState, intfHandle.winusbHandle, endpoint.endpointAddress(), transfer.data(), + transfer.dataSize(), NULL, transfer.overlapped()) == 0) { var err = Win.getLastError(errorState); - if (err != Kernel32.ERROR_IO_PENDING()) + if (err != ERROR_IO_PENDING) throwException(err, "submitting transfer OUT failed"); } } @@ -408,10 +426,10 @@ synchronized void submitTransferIn(int endpointNumber, WindowsTransfer transfer) asyncTask.prepareForSubmission(transfer); // submit transfer - if (WinUSB2.WinUsb_ReadPipe(intfHandle.winusbHandle, endpoint.endpointAddress(), transfer.data(), - transfer.dataSize(), NULL, transfer.overlapped(), errorState) == 0) { + if (WinUsb_ReadPipe(errorState, intfHandle.winusbHandle, endpoint.endpointAddress(), transfer.data(), + transfer.dataSize(), NULL, transfer.overlapped()) == 0) { var err = Win.getLastError(errorState); - if (err != Kernel32.ERROR_IO_PENDING()) + if (err != ERROR_IO_PENDING) throwException(err, "submitting transfer IN failed"); } } @@ -425,14 +443,14 @@ synchronized void configureForAsyncIo(UsbDirection direction, int endpointNumber var errorState = allocateErrorState(arena); var timeoutHolder = arena.allocate(JAVA_INT); - if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.winusbHandle, endpoint.endpointAddress(), - WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder, errorState) == 0) + if (WinUsb_SetPipePolicy(errorState, intfHandle.winusbHandle, endpoint.endpointAddress(), + PIPE_TRANSFER_TIMEOUT, (int) timeoutHolder.byteSize(), timeoutHolder) == 0) throwLastError(errorState, "setting timeout failed"); var rawIoHolder = arena.allocate(JAVA_BYTE); rawIoHolder.setAtIndex(JAVA_BYTE, 0, (byte) 1); - if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.winusbHandle, endpoint.endpointAddress(), WinUSB.RAW_IO(), - (int) rawIoHolder.byteSize(), rawIoHolder, errorState) == 0) + if (WinUsb_SetPipePolicy(errorState, intfHandle.winusbHandle, endpoint.endpointAddress(), RAW_IO, + (int) rawIoHolder.byteSize(), rawIoHolder) == 0) throwLastError(errorState, "setting raw IO failed"); } } @@ -444,7 +462,7 @@ public synchronized void clearHalt(UsbDirection direction, int endpointNumber) { try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); - if (WinUSB2.WinUsb_ResetPipe(intfHandle.winusbHandle, endpoint.endpointAddress(), errorState) == 0) + if (WinUsb_ResetPipe(errorState, intfHandle.winusbHandle, endpoint.endpointAddress()) == 0) throwLastError(errorState, "clearing halt failed"); } } @@ -456,7 +474,7 @@ public synchronized void abortTransfers(UsbDirection direction, int endpointNumb try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); - if (WinUSB2.WinUsb_AbortPipe(intfHandle.winusbHandle, endpoint.endpointAddress(), errorState) == 0) + if (WinUsb_AbortPipe(errorState, intfHandle.winusbHandle, endpoint.endpointAddress()) == 0) throwLastError(errorState, "aborting transfers on endpoint failed"); } } @@ -532,7 +550,7 @@ private String getInterfaceDevicePath(int interfaceNumber) { var parentDevicePath = (String) getUniqueId(); try (var deviceInfoSet = DeviceInfoSet.ofPath(parentDevicePath)) { - var childrenInstanceIDs = deviceInfoSet.getStringListProperty(Children); + var childrenInstanceIDs = deviceInfoSet.getStringListProperty(DEVPKEY_Device_Children()); if (childrenInstanceIDs == null) { LOG.log(DEBUG, "missing children instance IDs for device {0}", parentDevicePath); return null; @@ -561,7 +579,7 @@ private String getChildDevicePath(String instanceId, int interfaceNumber) { try (var deviceInfoSet = DeviceInfoSet.ofInstance(instanceId)) { // get hardware IDs (to extract interface number) - var hardwareIds = deviceInfoSet.getStringListProperty(HardwareIds); + var hardwareIds = deviceInfoSet.getStringListProperty(DEVPKEY_Device_HardwareIds()); if (hardwareIds == null) { LOG.log(DEBUG, "child device {0} has no hardware IDs", instanceId); return null; @@ -601,7 +619,7 @@ private static int extractInterfaceNumber(List hardwareIds) { var intfHexNumber = matcher.group(1); try { return Integer.parseInt(intfHexNumber, 16); - } catch (NumberFormatException e) { + } catch (NumberFormatException _) { // ignore and try next one } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java index dd5086d9..d9f86393 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDeviceRegistry.java @@ -16,47 +16,60 @@ import net.codecrete.usb.usbstandard.DeviceDescriptor; import net.codecrete.usb.usbstandard.SetupPacket; import net.codecrete.usb.usbstandard.StringDescriptor; -import net.codecrete.usb.windows.gen.kernel32.Kernel32; -import net.codecrete.usb.windows.gen.usbioctl.USBIoctl; -import net.codecrete.usb.windows.gen.usbioctl._USB_DESCRIPTOR_REQUEST; -import net.codecrete.usb.windows.gen.usbioctl._USB_NODE_CONNECTION_INFORMATION_EX; -import net.codecrete.usb.windows.gen.user32.User32; -import net.codecrete.usb.windows.gen.user32._DEV_BROADCAST_DEVICEINTERFACE_W; -import net.codecrete.usb.windows.gen.user32._DEV_BROADCAST_HDR; -import net.codecrete.usb.windows.gen.user32.tagMSG; -import net.codecrete.usb.windows.gen.user32.tagWNDCLASSEXW; -import net.codecrete.usb.windows.winsdk.Kernel32B; -import net.codecrete.usb.windows.winsdk.User32B; +import windows.win32.devices.usb.USB_DESCRIPTOR_REQUEST; +import windows.win32.devices.usb.USB_NODE_CONNECTION_INFORMATION_EX; +import windows.win32.ui.windowsandmessaging.DEV_BROADCAST_DEVICEINTERFACE_W; +import windows.win32.ui.windowsandmessaging.DEV_BROADCAST_HDR; +import windows.win32.ui.windowsandmessaging.MSG; +import windows.win32.ui.windowsandmessaging.WNDCLASSEXW; +import windows.win32.ui.windowsandmessaging.WNDPROC; import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.Linker; import java.lang.foreign.MemorySegment; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; import static java.lang.System.Logger.Level.INFO; import static java.lang.foreign.MemorySegment.NULL; -import static java.lang.foreign.ValueLayout.ADDRESS; import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; import static java.lang.foreign.ValueLayout.JAVA_SHORT; import static java.lang.foreign.ValueLayout.PathElement; +import static java.nio.charset.StandardCharsets.UTF_16LE; import static net.codecrete.usb.usbstandard.Constants.CONFIGURATION_DESCRIPTOR_TYPE; import static net.codecrete.usb.usbstandard.Constants.DEFAULT_LANGUAGE; import static net.codecrete.usb.usbstandard.Constants.STRING_DESCRIPTOR_TYPE; -import static net.codecrete.usb.windows.DevicePropertyKey.Address; -import static net.codecrete.usb.windows.DevicePropertyKey.InstanceId; -import static net.codecrete.usb.windows.DevicePropertyKey.Parent; -import static net.codecrete.usb.windows.UsbConstants.GUID_DEVINTERFACE_USB_DEVICE; -import static net.codecrete.usb.windows.UsbConstants.GUID_DEVINTERFACE_USB_HUB; +import static net.codecrete.usb.windows.CustomApis.CloseHandle; import static net.codecrete.usb.windows.Win.allocateErrorState; import static net.codecrete.usb.windows.WindowsUsbException.throwException; import static net.codecrete.usb.windows.WindowsUsbException.throwLastError; +import static windows.win32.devices.properties.Constants.DEVPKEY_Device_Address; +import static windows.win32.devices.properties.Constants.DEVPKEY_Device_InstanceId; +import static windows.win32.devices.properties.Constants.DEVPKEY_Device_Parent; +import static windows.win32.devices.usb.Constants.GUID_DEVINTERFACE_USB_DEVICE; +import static windows.win32.devices.usb.Constants.GUID_DEVINTERFACE_USB_HUB; +import static windows.win32.devices.usb.Constants.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION; +import static windows.win32.devices.usb.Constants.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX; +import static windows.win32.devices.usb.Constants.USB_REQUEST_GET_DESCRIPTOR; +import static windows.win32.foundation.GENERIC_ACCESS_RIGHTS.GENERIC_WRITE; +import static windows.win32.storage.filesystem.Apis.CreateFileW; +import static windows.win32.storage.filesystem.FILE_CREATION_DISPOSITION.OPEN_EXISTING; +import static windows.win32.storage.filesystem.FILE_SHARE_MODE.FILE_SHARE_WRITE; +import static windows.win32.system.io.Apis.DeviceIoControl; +import static windows.win32.system.libraryloader.Apis.GetModuleHandleW; +import static windows.win32.ui.windowsandmessaging.Apis.CreateWindowExW; +import static windows.win32.ui.windowsandmessaging.Apis.DefWindowProcW; +import static windows.win32.ui.windowsandmessaging.Apis.GetMessageW; +import static windows.win32.ui.windowsandmessaging.Apis.RegisterClassExW; +import static windows.win32.ui.windowsandmessaging.Apis.RegisterDeviceNotificationW; +import static windows.win32.ui.windowsandmessaging.Constants.DBT_DEVICEARRIVAL; +import static windows.win32.ui.windowsandmessaging.Constants.DBT_DEVICEREMOVECOMPLETE; +import static windows.win32.ui.windowsandmessaging.Constants.HWND_MESSAGE; +import static windows.win32.ui.windowsandmessaging.Constants.WM_DEVICECHANGE; +import static windows.win32.ui.windowsandmessaging.DEV_BROADCAST_HDR_DEVICE_TYPE.DBT_DEVTYP_DEVICEINTERFACE; +import static windows.win32.ui.windowsandmessaging.REGISTER_NOTIFICATION_FLAGS.DEVICE_NOTIFY_WINDOW_HANDLE; /** * Windows implementation of USB device registry. @@ -71,7 +84,7 @@ public class WindowsUsbDeviceRegistry extends UsbDeviceRegistry { private static final System.Logger LOG = System.getLogger(WindowsUsbDeviceRegistry.class.getName()); private static final long REQUEST_DATA_OFFSET - = _USB_DESCRIPTOR_REQUEST.layout().byteOffset(PathElement.groupElement("Data")); + = USB_DESCRIPTOR_REQUEST.layout().byteOffset(PathElement.groupElement("Data")); @Override protected void monitorDevices() { @@ -81,42 +94,33 @@ protected void monitorDevices() { var errorState = allocateErrorState(arena); try { - final var className = Win.createSegmentFromString("USB_MONITOR", arena); - final var windowName = Win.createSegmentFromString("USB device monitor", arena); - final var instance = Kernel32.GetModuleHandleW(NULL); - - // create upcall for handling window messages - var handleWindowMessageMH = MethodHandles.lookup().findVirtual(WindowsUsbDeviceRegistry.class, - "handleWindowMessage", MethodType.methodType(long.class, MemorySegment.class, int.class, - long.class, long.class)).bindTo(this); - var handleWindowMessageStub = Linker.nativeLinker().upcallStub(handleWindowMessageMH, - FunctionDescriptor.of(JAVA_LONG, ADDRESS, JAVA_INT, JAVA_LONG, JAVA_LONG), arena); + final var className = arena.allocateFrom("USB_MONITOR", UTF_16LE); + final var windowName = arena.allocateFrom("USB device monitor", UTF_16LE); + final var instance = GetModuleHandleW(errorState, NULL); // register window class - var wx = tagWNDCLASSEXW.allocate(arena); - tagWNDCLASSEXW.cbSize(wx, (int) wx.byteSize()); - tagWNDCLASSEXW.lpfnWndProc(wx, handleWindowMessageStub); - tagWNDCLASSEXW.hInstance(wx, instance); - tagWNDCLASSEXW.lpszClassName(wx, className); - var atom = User32B.RegisterClassExW(wx, errorState); + var wx = WNDCLASSEXW.allocate(arena); + WNDCLASSEXW.lpfnWndProc(wx, WNDPROC.allocate(arena, this::handleWindowMessage)); + WNDCLASSEXW.hInstance(wx, instance); + WNDCLASSEXW.lpszClassName(wx, className); + var atom = RegisterClassExW(errorState, wx); if (atom == 0) throwLastError(errorState, "internal error (RegisterClassExW)"); // create message-only window - hwnd = User32B.CreateWindowExW(0, className, windowName, 0, 0, 0, 0, 0, User32.HWND_MESSAGE(), NULL, - instance, NULL, errorState); + hwnd = CreateWindowExW(errorState, 0, className, windowName, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, + instance, NULL); if (hwnd.address() == 0) throwLastError(errorState, "internal error (CreateWindowExW)"); // configure notifications - var notificationFilter = _DEV_BROADCAST_DEVICEINTERFACE_W.allocate(arena); - _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size(notificationFilter, (int) notificationFilter.byteSize()); - _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype(notificationFilter, - User32.DBT_DEVTYP_DEVICEINTERFACE()); - _DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid(notificationFilter).copyFrom(GUID_DEVINTERFACE_USB_DEVICE); - - var notifyHandle = User32B.RegisterDeviceNotificationW(hwnd, notificationFilter, - User32.DEVICE_NOTIFY_WINDOW_HANDLE(), errorState); + var notificationFilter = DEV_BROADCAST_DEVICEINTERFACE_W.allocate(arena, 260); + DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_size(notificationFilter, (int) notificationFilter.byteSize()); + DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_devicetype(notificationFilter, DBT_DEVTYP_DEVICEINTERFACE); + DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_classguid(notificationFilter).copyFrom(GUID_DEVINTERFACE_USB_DEVICE()); + + var notifyHandle = RegisterDeviceNotificationW(errorState, hwnd, notificationFilter, + DEVICE_NOTIFY_WINDOW_HANDLE); if (notifyHandle.address() == 0) throwLastError(errorState, "internal error (RegisterDeviceNotificationW)"); @@ -129,10 +133,10 @@ protected void monitorDevices() { } // process messages - var msg = tagMSG.allocate(arena); + var msg = MSG.allocate(arena); int err; //noinspection StatementWithEmptyBody - while ((err = User32B.GetMessageW(msg, hwnd, 0, 0, errorState)) > 0) + while ((err = GetMessageW(errorState, msg, hwnd, 0, 0)) > 0) ; // do nothing if (err == -1) @@ -145,17 +149,17 @@ private void enumeratePresentDevices() { List deviceList = new ArrayList<>(); try (var cleanup = new ScopeCleanup(); - var deviceInfoSet = DeviceInfoSet.ofPresentDevices(GUID_DEVINTERFACE_USB_DEVICE, null)) { + var deviceInfoSet = DeviceInfoSet.ofPresentDevices(GUID_DEVINTERFACE_USB_DEVICE(), null)) { // ensure all hubs are closed later final var hubHandles = new HashMap(); - cleanup.add(() -> hubHandles.forEach((_, handle) -> Kernel32.CloseHandle(handle))); + cleanup.add(() -> hubHandles.forEach((_, handle) -> CloseHandle(handle))); // iterate all devices while (deviceInfoSet.next()) { - var instanceId = deviceInfoSet.getStringProperty(InstanceId); - var devicePath = DeviceInfoSet.getDevicePath(instanceId, GUID_DEVINTERFACE_USB_DEVICE); + var instanceId = deviceInfoSet.getStringProperty(DEVPKEY_Device_InstanceId()); + var devicePath = DeviceInfoSet.getDevicePath(instanceId, GUID_DEVINTERFACE_USB_DEVICE()); try { deviceList.add(createDeviceFromDeviceInfo(deviceInfoSet, devicePath, hubHandles)); @@ -170,20 +174,20 @@ private void enumeratePresentDevices() { } private UsbDevice createDeviceFromDeviceInfo(DeviceInfoSet deviceInfoSet, String devicePath, - HashMap hubHandles) { + Map hubHandles) { try (var arena = Arena.ofConfined()) { - var usbPortNum = deviceInfoSet.getIntProperty(Address); - var parentInstanceId = deviceInfoSet.getStringProperty(Parent); - var hubPath = DeviceInfoSet.getDevicePath(parentInstanceId, GUID_DEVINTERFACE_USB_HUB); + var usbPortNum = deviceInfoSet.getIntProperty(DEVPKEY_Device_Address()); + var parentInstanceId = deviceInfoSet.getStringProperty(DEVPKEY_Device_Parent()); + var hubPath = DeviceInfoSet.getDevicePath(parentInstanceId, GUID_DEVINTERFACE_USB_HUB()); // open hub if not open yet var hubHandle = hubHandles.get(hubPath); if (hubHandle == null) { - var hubPathSeg = Win.createSegmentFromString(hubPath, arena); + var hubPathSeg = arena.allocateFrom(hubPath, UTF_16LE); var errorState = allocateErrorState(arena); - hubHandle = Kernel32B.CreateFileW(hubPathSeg, Kernel32.GENERIC_WRITE(), Kernel32.FILE_SHARE_WRITE(), - NULL, Kernel32.OPEN_EXISTING(), 0, NULL, errorState); + hubHandle = CreateFileW(errorState, hubPathSeg, GENERIC_WRITE, FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); if (Win.isInvalidHandle(hubHandle)) throwLastError(errorState, "internal error (opening hub device)"); hubHandles.put(hubPath, hubHandle); @@ -206,16 +210,15 @@ private UsbDevice createDevice(String devicePath, boolean isComposite, MemorySeg try (var arena = Arena.ofConfined()) { // get device descriptor - var connInfo = _USB_NODE_CONNECTION_INFORMATION_EX.allocate(arena); - _USB_NODE_CONNECTION_INFORMATION_EX.ConnectionIndex(connInfo, usbPortNum); + var connInfo = USB_NODE_CONNECTION_INFORMATION_EX.allocate(arena, 0); + USB_NODE_CONNECTION_INFORMATION_EX.ConnectionIndex(connInfo, usbPortNum); var sizeHolder = arena.allocate(JAVA_INT); var errorState = allocateErrorState(arena); - if (Kernel32B.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX(), - connInfo, (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL, - errorState) == 0) + if (DeviceIoControl(errorState, hubHandle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, + connInfo, (int) connInfo.byteSize(), connInfo, (int) connInfo.byteSize(), sizeHolder, NULL) == 0) throwLastError(errorState, "internal error (getting device descriptor failed)"); - var descriptorSegment = _USB_NODE_CONNECTION_INFORMATION_EX.DeviceDescriptor(connInfo); + var descriptorSegment = USB_NODE_CONNECTION_INFORMATION_EX.DeviceDescriptor(connInfo); var deviceDescriptor = new DeviceDescriptor(descriptorSegment); var vendorId = deviceDescriptor.vendorID(); @@ -245,10 +248,11 @@ private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, // create descriptor requests var descriptorRequest = arena.allocate(size); - _USB_DESCRIPTOR_REQUEST.ConnectionIndex(descriptorRequest, usbPortNumber); - var setupPacket = new SetupPacket(_USB_DESCRIPTOR_REQUEST.SetupPacket(descriptorRequest)); + USB_DESCRIPTOR_REQUEST.ConnectionIndex(descriptorRequest, usbPortNumber); + var setupPacket = new SetupPacket(descriptorRequest.asSlice( + USB_DESCRIPTOR_REQUEST.SetupPacket_bmRequest$offset(), SetupPacket.LAYOUT.byteSize())); setupPacket.setRequestType(0x80); // device-to-host / type standard / recipient device - setupPacket.setRequest(UsbConstants.USB_REQUEST_GET_DESCRIPTOR); + setupPacket.setRequest(USB_REQUEST_GET_DESCRIPTOR); setupPacket.setValue((descriptorType << 8) | index); setupPacket.setIndex(languageID); setupPacket.setLength(size - (int) REQUEST_DATA_OFFSET); @@ -256,8 +260,8 @@ private MemorySegment getDescriptor(MemorySegment hubHandle, int usbPortNumber, // execute request var effectiveSizeHolder = arena.allocate(JAVA_INT); var errorState = allocateErrorState(arena); - if (Kernel32B.DeviceIoControl(hubHandle, USBIoctl.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION(), - descriptorRequest, size, descriptorRequest, size, effectiveSizeHolder, NULL, errorState) == 0) + if (DeviceIoControl(errorState, hubHandle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + descriptorRequest, size, descriptorRequest, size, effectiveSizeHolder, NULL) == 0) throwLastError(errorState, "internal error (retrieving descriptor %d failed)", index); // determine size of descriptor @@ -295,7 +299,7 @@ private String getStringDescriptor(MemorySegment hubHandle, int usbPortNumber, i index, language, arena)); return stringDesc.string(); - } catch (UsbException e) { + } catch (UsbException _) { // ignore and try next language } } @@ -311,10 +315,10 @@ private short[] getLanguages(MemorySegment hubHandle, int usbPortNumber, Arena a var languages = getDescriptor(hubHandle, usbPortNumber, STRING_DESCRIPTOR_TYPE, 0, (short) 0, arena); var n = (languages.byteSize() - 2) / 2; if (n == 0) - return new short[] { DEFAULT_LANGUAGE }; + return new short[]{DEFAULT_LANGUAGE}; return languages.asSlice(2, n * 2).toArray(JAVA_SHORT); - } catch (UsbException e) { - return new short[] { DEFAULT_LANGUAGE }; + } catch (UsbException _) { + return new short[]{DEFAULT_LANGUAGE}; } } @@ -322,15 +326,15 @@ private short[] getLanguages(MemorySegment hubHandle, int usbPortNumber, Arena a private long handleWindowMessage(MemorySegment hWnd, int uMsg, long wParam, long lParam) { // check for message related to connecting/disconnecting devices - if (uMsg == User32.WM_DEVICECHANGE() && (wParam == User32.DBT_DEVICEARRIVAL() || wParam == User32.DBT_DEVICEREMOVECOMPLETE())) { - var data = MemorySegment.ofAddress(lParam).reinterpret(_DEV_BROADCAST_DEVICEINTERFACE_W.sizeof()); - if (_DEV_BROADCAST_HDR.dbch_devicetype(data) == User32.DBT_DEVTYP_DEVICEINTERFACE()) { + if (uMsg == WM_DEVICECHANGE && (wParam == DBT_DEVICEARRIVAL || wParam == DBT_DEVICEREMOVECOMPLETE)) { + var data = MemorySegment.ofAddress(lParam).reinterpret(DEV_BROADCAST_DEVICEINTERFACE_W.sizeof()); + if (DEV_BROADCAST_HDR.dbch_devicetype(data) == DBT_DEVTYP_DEVICEINTERFACE) { // get device path var nameSlice = - MemorySegment.ofAddress(_DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name(data).address()).reinterpret(500); - var devicePath = Win.createStringFromSegment(nameSlice); - if (wParam == User32.DBT_DEVICEARRIVAL()) + MemorySegment.ofAddress(DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name(data).address()).reinterpret(500); + var devicePath = nameSlice.getString(0, UTF_16LE); + if (wParam == DBT_DEVICEARRIVAL) onDeviceConnected(devicePath); else onDeviceDisconnected(devicePath); @@ -339,7 +343,7 @@ private long handleWindowMessage(MemorySegment hWnd, int uMsg, long wParam, long } // default message handling - return User32.DefWindowProcW(hWnd, uMsg, wParam, lParam); + return DefWindowProcW(hWnd, uMsg, wParam, lParam); } @SuppressWarnings("java:S106") @@ -349,7 +353,7 @@ private void onDeviceConnected(String devicePath) { // ensure all hubs are closed later final var hubHandles = new HashMap(); - cleanup.add(() -> hubHandles.forEach((_, handle) -> Kernel32.CloseHandle(handle))); + cleanup.add(() -> hubHandles.forEach((_, handle) -> CloseHandle(handle))); try { // create device instance @@ -359,7 +363,7 @@ private void onDeviceConnected(String devicePath) { addDevice(device); } catch (Exception e) { - LOG.log(INFO, String.format("failed to retrieve information about device %s - ignoring device", devicePath), e); + LOG.log(INFO, String.format("failed to retrieve information about device %s - ignoring device", devicePath), e); } } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbException.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbException.java index 734a03f1..94f70bf5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbException.java @@ -8,15 +8,23 @@ import net.codecrete.usb.UsbException; import net.codecrete.usb.UsbStallException; -import net.codecrete.usb.windows.gen.kernel32.Kernel32; -import net.codecrete.usb.windows.gen.ntdll.NtDll; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.nio.charset.StandardCharsets.UTF_16LE; import static net.codecrete.usb.common.ForeignMemory.dereference; +import static windows.win32.foundation.Apis.LocalFree; +import static windows.win32.foundation.Constants.STATUS_UNSUCCESSFUL; +import static windows.win32.foundation.WIN32_ERROR.ERROR_GEN_FAILURE; +import static windows.win32.system.diagnostics.debug.Apis.FormatMessageW; +import static windows.win32.system.diagnostics.debug.FORMAT_MESSAGE_OPTIONS.FORMAT_MESSAGE_ALLOCATE_BUFFER; +import static windows.win32.system.diagnostics.debug.FORMAT_MESSAGE_OPTIONS.FORMAT_MESSAGE_FROM_HMODULE; +import static windows.win32.system.diagnostics.debug.FORMAT_MESSAGE_OPTIONS.FORMAT_MESSAGE_FROM_SYSTEM; +import static windows.win32.system.diagnostics.debug.FORMAT_MESSAGE_OPTIONS.FORMAT_MESSAGE_IGNORE_INSERTS; +import static windows.win32.system.libraryloader.Apis.GetModuleHandleW; /** * Exception thrown if a Windows specific error occurs. @@ -48,7 +56,7 @@ public WindowsUsbException(String message, int errorCode) { */ static void throwException(int errorCode, String message, Object... args) { var formattedMessage = String.format(message, args); - if (errorCode == Kernel32.ERROR_GEN_FAILURE() || errorCode == NtDll.STATUS_UNSUCCESSFUL()) { + if (errorCode == ERROR_GEN_FAILURE || errorCode == STATUS_UNSUCCESSFUL) { throw new UsbStallException(formattedMessage); } else { throw new WindowsUsbException(formattedMessage, errorCode); @@ -85,8 +93,9 @@ static void throwLastError(MemorySegment errorState, String message, Object... a private static MemorySegment getNtModule() { if (ntModule == null) { try (var arena = Arena.ofConfined()) { - var moduleName = Win.createSegmentFromString("NTDLL.DLL", arena); - ntModule = Kernel32.GetModuleHandleW(moduleName); + var errorState = Win.allocateErrorState(arena); + var moduleName = arena.allocateFrom("NTDLL.DLL", UTF_16LE); + ntModule = GetModuleHandleW(errorState, moduleName); } } @@ -95,17 +104,18 @@ private static MemorySegment getNtModule() { static String getErrorMessage(int errorCode) { try (var arena = Arena.ofConfined()) { + var errorState = Win.allocateErrorState(arena); var messagePointerHolder = arena.allocate(ADDRESS); // First try: Win32 error code - var res = Kernel32.FormatMessageW( - Kernel32.FORMAT_MESSAGE_ALLOCATE_BUFFER() | Kernel32.FORMAT_MESSAGE_FROM_SYSTEM() | Kernel32.FORMAT_MESSAGE_IGNORE_INSERTS(), + var res = FormatMessageW( + errorState, FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorCode, 0, messagePointerHolder, 0, NULL); // Second try: NTSTATUS error code if (res == 0) { - res = Kernel32.FormatMessageW( - Kernel32.FORMAT_MESSAGE_ALLOCATE_BUFFER() | Kernel32.FORMAT_MESSAGE_FROM_HMODULE() | Kernel32.FORMAT_MESSAGE_IGNORE_INSERTS(), + res = FormatMessageW( + errorState, FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, getNtModule(), errorCode, 0, messagePointerHolder, 0, NULL); } @@ -114,8 +124,8 @@ static String getErrorMessage(int errorCode) { return "unspecified error"; var messagePointer = dereference(messagePointerHolder).reinterpret(128 * 1024); // NOSONAR - var message = Win.createStringFromSegment(messagePointer); - Kernel32.LocalFree(messagePointer); + var message = messagePointer.getString(0, UTF_16LE); + LocalFree(errorState, messagePointer); return message.trim(); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java deleted file mode 100644 index aa61da82..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/advapi32/Advapi32.java +++ /dev/null @@ -1,182 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.advapi32; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -public class Advapi32 { - - Advapi32() { - // Should not be called directly - } - - static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } - - static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("Advapi32"), LIBRARY_ARENA) - .or(SymbolLookup.loaderLookup()) - .or(Linker.nativeLinker().defaultLookup()); - - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfInt C_LONG = ValueLayout.JAVA_INT; - public static final ValueLayout.OfDouble C_LONG_DOUBLE = ValueLayout.JAVA_DOUBLE; - - private static class RegCloseKey { - public static final FunctionDescriptor DESC = FunctionDescriptor.of( - Advapi32.C_LONG, - Advapi32.C_POINTER - ); - - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - Advapi32.findOrThrow("RegCloseKey"), - DESC); - } - - /** - * Function descriptor for: - * {@snippet lang=c : - * LSTATUS RegCloseKey(HKEY hKey) - * } - */ - public static FunctionDescriptor RegCloseKey$descriptor() { - return RegCloseKey.DESC; - } - - /** - * Downcall method handle for: - * {@snippet lang=c : - * LSTATUS RegCloseKey(HKEY hKey) - * } - */ - public static MethodHandle RegCloseKey$handle() { - return RegCloseKey.HANDLE; - } - /** - * {@snippet lang=c : - * LSTATUS RegCloseKey(HKEY hKey) - * } - */ - public static int RegCloseKey(MemorySegment hKey) { - var mh$ = RegCloseKey.HANDLE; - try { - if (TRACE_DOWNCALLS) { - traceDowncall("RegCloseKey", hKey); - } - return (int)mh$.invokeExact(hKey); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - private static class RegQueryValueExW { - public static final FunctionDescriptor DESC = FunctionDescriptor.of( - Advapi32.C_LONG, - Advapi32.C_POINTER, - Advapi32.C_POINTER, - Advapi32.C_POINTER, - Advapi32.C_POINTER, - Advapi32.C_POINTER, - Advapi32.C_POINTER - ); - - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - Advapi32.findOrThrow("RegQueryValueExW"), - DESC); - } - - /** - * Function descriptor for: - * {@snippet lang=c : - * LSTATUS RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) - * } - */ - public static FunctionDescriptor RegQueryValueExW$descriptor() { - return RegQueryValueExW.DESC; - } - - /** - * Downcall method handle for: - * {@snippet lang=c : - * LSTATUS RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) - * } - */ - public static MethodHandle RegQueryValueExW$handle() { - return RegQueryValueExW.HANDLE; - } - /** - * {@snippet lang=c : - * LSTATUS RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) - * } - */ - public static int RegQueryValueExW(MemorySegment hKey, MemorySegment lpValueName, MemorySegment lpReserved, MemorySegment lpType, MemorySegment lpData, MemorySegment lpcbData) { - var mh$ = RegQueryValueExW.HANDLE; - try { - if (TRACE_DOWNCALLS) { - traceDowncall("RegQueryValueExW", hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); - } - return (int)mh$.invokeExact(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - private static final int KEY_READ = (int)131097L; - /** - * {@snippet lang=c : - * #define KEY_READ 131097 - * } - */ - public static int KEY_READ() { - return KEY_READ; - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java deleted file mode 100644 index 5bf1f30c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/Kernel32.java +++ /dev/null @@ -1,448 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.kernel32; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -public class Kernel32 { - - Kernel32() { - // Should not be called directly - } - - static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } - - static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("Kernel32"), LIBRARY_ARENA) - .or(SymbolLookup.loaderLookup()) - .or(Linker.nativeLinker().defaultLookup()); - - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfInt C_LONG = ValueLayout.JAVA_INT; - public static final ValueLayout.OfDouble C_LONG_DOUBLE = ValueLayout.JAVA_DOUBLE; - private static final int FILE_SHARE_READ = (int)1L; - /** - * {@snippet lang=c : - * #define FILE_SHARE_READ 1 - * } - */ - public static int FILE_SHARE_READ() { - return FILE_SHARE_READ; - } - private static final int FILE_SHARE_WRITE = (int)2L; - /** - * {@snippet lang=c : - * #define FILE_SHARE_WRITE 2 - * } - */ - public static int FILE_SHARE_WRITE() { - return FILE_SHARE_WRITE; - } - private static final int FILE_ATTRIBUTE_NORMAL = (int)128L; - /** - * {@snippet lang=c : - * #define FILE_ATTRIBUTE_NORMAL 128 - * } - */ - public static int FILE_ATTRIBUTE_NORMAL() { - return FILE_ATTRIBUTE_NORMAL; - } - private static final int OPEN_EXISTING = (int)3L; - /** - * {@snippet lang=c : - * #define OPEN_EXISTING 3 - * } - */ - public static int OPEN_EXISTING() { - return OPEN_EXISTING; - } - private static final int FILE_FLAG_OVERLAPPED = (int)1073741824L; - /** - * {@snippet lang=c : - * #define FILE_FLAG_OVERLAPPED 1073741824 - * } - */ - public static int FILE_FLAG_OVERLAPPED() { - return FILE_FLAG_OVERLAPPED; - } - private static final int FORMAT_MESSAGE_ALLOCATE_BUFFER = (int)256L; - /** - * {@snippet lang=c : - * #define FORMAT_MESSAGE_ALLOCATE_BUFFER 256 - * } - */ - public static int FORMAT_MESSAGE_ALLOCATE_BUFFER() { - return FORMAT_MESSAGE_ALLOCATE_BUFFER; - } - private static final int FORMAT_MESSAGE_IGNORE_INSERTS = (int)512L; - /** - * {@snippet lang=c : - * #define FORMAT_MESSAGE_IGNORE_INSERTS 512 - * } - */ - public static int FORMAT_MESSAGE_IGNORE_INSERTS() { - return FORMAT_MESSAGE_IGNORE_INSERTS; - } - private static final int FORMAT_MESSAGE_FROM_HMODULE = (int)2048L; - /** - * {@snippet lang=c : - * #define FORMAT_MESSAGE_FROM_HMODULE 2048 - * } - */ - public static int FORMAT_MESSAGE_FROM_HMODULE() { - return FORMAT_MESSAGE_FROM_HMODULE; - } - private static final int FORMAT_MESSAGE_FROM_SYSTEM = (int)4096L; - /** - * {@snippet lang=c : - * #define FORMAT_MESSAGE_FROM_SYSTEM 4096 - * } - */ - public static int FORMAT_MESSAGE_FROM_SYSTEM() { - return FORMAT_MESSAGE_FROM_SYSTEM; - } - - private static class CloseHandle { - public static final FunctionDescriptor DESC = FunctionDescriptor.of( - Kernel32.C_INT, - Kernel32.C_POINTER - ); - - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - Kernel32.findOrThrow("CloseHandle"), - DESC); - } - - /** - * Function descriptor for: - * {@snippet lang=c : - * BOOL CloseHandle(HANDLE hObject) - * } - */ - public static FunctionDescriptor CloseHandle$descriptor() { - return CloseHandle.DESC; - } - - /** - * Downcall method handle for: - * {@snippet lang=c : - * BOOL CloseHandle(HANDLE hObject) - * } - */ - public static MethodHandle CloseHandle$handle() { - return CloseHandle.HANDLE; - } - /** - * {@snippet lang=c : - * BOOL CloseHandle(HANDLE hObject) - * } - */ - public static int CloseHandle(MemorySegment hObject) { - var mh$ = CloseHandle.HANDLE; - try { - if (TRACE_DOWNCALLS) { - traceDowncall("CloseHandle", hObject); - } - return (int)mh$.invokeExact(hObject); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - private static class GetModuleHandleW { - public static final FunctionDescriptor DESC = FunctionDescriptor.of( - Kernel32.C_POINTER, - Kernel32.C_POINTER - ); - - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - Kernel32.findOrThrow("GetModuleHandleW"), - DESC); - } - - /** - * Function descriptor for: - * {@snippet lang=c : - * HMODULE GetModuleHandleW(LPCWSTR lpModuleName) - * } - */ - public static FunctionDescriptor GetModuleHandleW$descriptor() { - return GetModuleHandleW.DESC; - } - - /** - * Downcall method handle for: - * {@snippet lang=c : - * HMODULE GetModuleHandleW(LPCWSTR lpModuleName) - * } - */ - public static MethodHandle GetModuleHandleW$handle() { - return GetModuleHandleW.HANDLE; - } - /** - * {@snippet lang=c : - * HMODULE GetModuleHandleW(LPCWSTR lpModuleName) - * } - */ - public static MemorySegment GetModuleHandleW(MemorySegment lpModuleName) { - var mh$ = GetModuleHandleW.HANDLE; - try { - if (TRACE_DOWNCALLS) { - traceDowncall("GetModuleHandleW", lpModuleName); - } - return (MemorySegment)mh$.invokeExact(lpModuleName); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - private static class LocalFree { - public static final FunctionDescriptor DESC = FunctionDescriptor.of( - Kernel32.C_POINTER, - Kernel32.C_POINTER - ); - - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - Kernel32.findOrThrow("LocalFree"), - DESC); - } - - /** - * Function descriptor for: - * {@snippet lang=c : - * HLOCAL LocalFree(HLOCAL hMem) - * } - */ - public static FunctionDescriptor LocalFree$descriptor() { - return LocalFree.DESC; - } - - /** - * Downcall method handle for: - * {@snippet lang=c : - * HLOCAL LocalFree(HLOCAL hMem) - * } - */ - public static MethodHandle LocalFree$handle() { - return LocalFree.HANDLE; - } - /** - * {@snippet lang=c : - * HLOCAL LocalFree(HLOCAL hMem) - * } - */ - public static MemorySegment LocalFree(MemorySegment hMem) { - var mh$ = LocalFree.HANDLE; - try { - if (TRACE_DOWNCALLS) { - traceDowncall("LocalFree", hMem); - } - return (MemorySegment)mh$.invokeExact(hMem); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - private static class FormatMessageW { - public static final FunctionDescriptor DESC = FunctionDescriptor.of( - Kernel32.C_LONG, - Kernel32.C_LONG, - Kernel32.C_POINTER, - Kernel32.C_LONG, - Kernel32.C_LONG, - Kernel32.C_POINTER, - Kernel32.C_LONG, - Kernel32.C_POINTER - ); - - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - Kernel32.findOrThrow("FormatMessageW"), - DESC); - } - - /** - * Function descriptor for: - * {@snippet lang=c : - * DWORD FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments) - * } - */ - public static FunctionDescriptor FormatMessageW$descriptor() { - return FormatMessageW.DESC; - } - - /** - * Downcall method handle for: - * {@snippet lang=c : - * DWORD FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments) - * } - */ - public static MethodHandle FormatMessageW$handle() { - return FormatMessageW.HANDLE; - } - /** - * {@snippet lang=c : - * DWORD FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments) - * } - */ - public static int FormatMessageW(int dwFlags, MemorySegment lpSource, int dwMessageId, int dwLanguageId, MemorySegment lpBuffer, int nSize, MemorySegment Arguments) { - var mh$ = FormatMessageW.HANDLE; - try { - if (TRACE_DOWNCALLS) { - traceDowncall("FormatMessageW", dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments); - } - return (int)mh$.invokeExact(dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - private static final int GENERIC_READ = (int)2147483648L; - /** - * {@snippet lang=c : - * #define GENERIC_READ 2147483648 - * } - */ - public static int GENERIC_READ() { - return GENERIC_READ; - } - private static final int GENERIC_WRITE = (int)1073741824L; - /** - * {@snippet lang=c : - * #define GENERIC_WRITE 1073741824 - * } - */ - public static int GENERIC_WRITE() { - return GENERIC_WRITE; - } - private static final int INFINITE = (int)4294967295L; - /** - * {@snippet lang=c : - * #define INFINITE 4294967295 - * } - */ - public static int INFINITE() { - return INFINITE; - } - private static final int ERROR_FILE_NOT_FOUND = (int)2L; - /** - * {@snippet lang=c : - * #define ERROR_FILE_NOT_FOUND 2 - * } - */ - public static int ERROR_FILE_NOT_FOUND() { - return ERROR_FILE_NOT_FOUND; - } - private static final int ERROR_GEN_FAILURE = (int)31L; - /** - * {@snippet lang=c : - * #define ERROR_GEN_FAILURE 31 - * } - */ - public static int ERROR_GEN_FAILURE() { - return ERROR_GEN_FAILURE; - } - private static final int ERROR_INVALID_PARAMETER = (int)87L; - /** - * {@snippet lang=c : - * #define ERROR_INVALID_PARAMETER 87 - * } - */ - public static int ERROR_INVALID_PARAMETER() { - return ERROR_INVALID_PARAMETER; - } - private static final int ERROR_INSUFFICIENT_BUFFER = (int)122L; - /** - * {@snippet lang=c : - * #define ERROR_INSUFFICIENT_BUFFER 122 - * } - */ - public static int ERROR_INSUFFICIENT_BUFFER() { - return ERROR_INSUFFICIENT_BUFFER; - } - private static final int ERROR_MORE_DATA = (int)234L; - /** - * {@snippet lang=c : - * #define ERROR_MORE_DATA 234 - * } - */ - public static int ERROR_MORE_DATA() { - return ERROR_MORE_DATA; - } - private static final int ERROR_NO_MORE_ITEMS = (int)259L; - /** - * {@snippet lang=c : - * #define ERROR_NO_MORE_ITEMS 259 - * } - */ - public static int ERROR_NO_MORE_ITEMS() { - return ERROR_NO_MORE_ITEMS; - } - private static final int ERROR_IO_PENDING = (int)997L; - /** - * {@snippet lang=c : - * #define ERROR_IO_PENDING 997 - * } - */ - public static int ERROR_IO_PENDING() { - return ERROR_IO_PENDING; - } - private static final int ERROR_NOT_FOUND = (int)1168L; - /** - * {@snippet lang=c : - * #define ERROR_NOT_FOUND 1168 - * } - */ - public static int ERROR_NOT_FOUND() { - return ERROR_NOT_FOUND; - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java deleted file mode 100644 index 3464e8f0..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_GUID.java +++ /dev/null @@ -1,298 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.kernel32; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct _GUID { - * unsigned long Data1; - * unsigned short Data2; - * unsigned short Data3; - * unsigned char Data4[8]; - * } - * } - */ -public class _GUID { - - _GUID() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - Kernel32.C_LONG.withName("Data1"), - Kernel32.C_SHORT.withName("Data2"), - Kernel32.C_SHORT.withName("Data3"), - MemoryLayout.sequenceLayout(8, Kernel32.C_CHAR).withName("Data4") - ).withName("_GUID"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final OfInt Data1$LAYOUT = (OfInt)$LAYOUT.select(groupElement("Data1")); - - /** - * Layout for field: - * {@snippet lang=c : - * unsigned long Data1 - * } - */ - public static final OfInt Data1$layout() { - return Data1$LAYOUT; - } - - private static final long Data1$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * unsigned long Data1 - * } - */ - public static final long Data1$offset() { - return Data1$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * unsigned long Data1 - * } - */ - public static int Data1(MemorySegment struct) { - return struct.get(Data1$LAYOUT, Data1$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * unsigned long Data1 - * } - */ - public static void Data1(MemorySegment struct, int fieldValue) { - struct.set(Data1$LAYOUT, Data1$OFFSET, fieldValue); - } - - private static final OfShort Data2$LAYOUT = (OfShort)$LAYOUT.select(groupElement("Data2")); - - /** - * Layout for field: - * {@snippet lang=c : - * unsigned short Data2 - * } - */ - public static final OfShort Data2$layout() { - return Data2$LAYOUT; - } - - private static final long Data2$OFFSET = 4; - - /** - * Offset for field: - * {@snippet lang=c : - * unsigned short Data2 - * } - */ - public static final long Data2$offset() { - return Data2$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * unsigned short Data2 - * } - */ - public static short Data2(MemorySegment struct) { - return struct.get(Data2$LAYOUT, Data2$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * unsigned short Data2 - * } - */ - public static void Data2(MemorySegment struct, short fieldValue) { - struct.set(Data2$LAYOUT, Data2$OFFSET, fieldValue); - } - - private static final OfShort Data3$LAYOUT = (OfShort)$LAYOUT.select(groupElement("Data3")); - - /** - * Layout for field: - * {@snippet lang=c : - * unsigned short Data3 - * } - */ - public static final OfShort Data3$layout() { - return Data3$LAYOUT; - } - - private static final long Data3$OFFSET = 6; - - /** - * Offset for field: - * {@snippet lang=c : - * unsigned short Data3 - * } - */ - public static final long Data3$offset() { - return Data3$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * unsigned short Data3 - * } - */ - public static short Data3(MemorySegment struct) { - return struct.get(Data3$LAYOUT, Data3$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * unsigned short Data3 - * } - */ - public static void Data3(MemorySegment struct, short fieldValue) { - struct.set(Data3$LAYOUT, Data3$OFFSET, fieldValue); - } - - private static final SequenceLayout Data4$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("Data4")); - - /** - * Layout for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static final SequenceLayout Data4$layout() { - return Data4$LAYOUT; - } - - private static final long Data4$OFFSET = 8; - - /** - * Offset for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static final long Data4$offset() { - return Data4$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static MemorySegment Data4(MemorySegment struct) { - return struct.asSlice(Data4$OFFSET, Data4$LAYOUT.byteSize()); - } - - /** - * Setter for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static void Data4(MemorySegment struct, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, struct, Data4$OFFSET, Data4$LAYOUT.byteSize()); - } - - private static long[] Data4$DIMS = { 8 }; - - /** - * Dimensions for array field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static long[] Data4$dimensions() { - return Data4$DIMS; - } - private static final VarHandle Data4$ELEM_HANDLE = Data4$LAYOUT.varHandle(sequenceElement()); - - /** - * Indexed getter for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static byte Data4(MemorySegment struct, long index0) { - return (byte)Data4$ELEM_HANDLE.get(struct, 0L, index0); - } - - /** - * Indexed setter for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static void Data4(MemorySegment struct, long index0, byte fieldValue) { - Data4$ELEM_HANDLE.set(struct, 0L, index0, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java deleted file mode 100644 index 9bc7d1c7..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/kernel32/_OVERLAPPED.java +++ /dev/null @@ -1,365 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.kernel32; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct _OVERLAPPED { - * ULONG_PTR Internal; - * ULONG_PTR InternalHigh; - * union { - * struct { - * DWORD Offset; - * DWORD OffsetHigh; - * }; - * PVOID Pointer; - * }; - * HANDLE hEvent; - * } - * } - */ -public class _OVERLAPPED { - - _OVERLAPPED() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - Kernel32.C_LONG_LONG.withName("Internal"), - Kernel32.C_LONG_LONG.withName("InternalHigh"), - MemoryLayout.unionLayout( - MemoryLayout.structLayout( - Kernel32.C_LONG.withName("Offset"), - Kernel32.C_LONG.withName("OffsetHigh") - ).withName("$anon$56:9"), - Kernel32.C_POINTER.withName("Pointer") - ).withName("$anon$55:5"), - Kernel32.C_POINTER.withName("hEvent") - ).withName("_OVERLAPPED"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final OfLong Internal$LAYOUT = (OfLong)$LAYOUT.select(groupElement("Internal")); - - /** - * Layout for field: - * {@snippet lang=c : - * ULONG_PTR Internal - * } - */ - public static final OfLong Internal$layout() { - return Internal$LAYOUT; - } - - private static final long Internal$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * ULONG_PTR Internal - * } - */ - public static final long Internal$offset() { - return Internal$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * ULONG_PTR Internal - * } - */ - public static long Internal(MemorySegment struct) { - return struct.get(Internal$LAYOUT, Internal$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * ULONG_PTR Internal - * } - */ - public static void Internal(MemorySegment struct, long fieldValue) { - struct.set(Internal$LAYOUT, Internal$OFFSET, fieldValue); - } - - private static final OfLong InternalHigh$LAYOUT = (OfLong)$LAYOUT.select(groupElement("InternalHigh")); - - /** - * Layout for field: - * {@snippet lang=c : - * ULONG_PTR InternalHigh - * } - */ - public static final OfLong InternalHigh$layout() { - return InternalHigh$LAYOUT; - } - - private static final long InternalHigh$OFFSET = 8; - - /** - * Offset for field: - * {@snippet lang=c : - * ULONG_PTR InternalHigh - * } - */ - public static final long InternalHigh$offset() { - return InternalHigh$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * ULONG_PTR InternalHigh - * } - */ - public static long InternalHigh(MemorySegment struct) { - return struct.get(InternalHigh$LAYOUT, InternalHigh$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * ULONG_PTR InternalHigh - * } - */ - public static void InternalHigh(MemorySegment struct, long fieldValue) { - struct.set(InternalHigh$LAYOUT, InternalHigh$OFFSET, fieldValue); - } - - private static final OfInt Offset$LAYOUT = (OfInt)$LAYOUT.select(groupElement("$anon$55:5"), groupElement("$anon$56:9"), groupElement("Offset")); - - /** - * Layout for field: - * {@snippet lang=c : - * DWORD Offset - * } - */ - public static final OfInt Offset$layout() { - return Offset$LAYOUT; - } - - private static final long Offset$OFFSET = 16; - - /** - * Offset for field: - * {@snippet lang=c : - * DWORD Offset - * } - */ - public static final long Offset$offset() { - return Offset$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * DWORD Offset - * } - */ - public static int Offset(MemorySegment struct) { - return struct.get(Offset$LAYOUT, Offset$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * DWORD Offset - * } - */ - public static void Offset(MemorySegment struct, int fieldValue) { - struct.set(Offset$LAYOUT, Offset$OFFSET, fieldValue); - } - - private static final OfInt OffsetHigh$LAYOUT = (OfInt)$LAYOUT.select(groupElement("$anon$55:5"), groupElement("$anon$56:9"), groupElement("OffsetHigh")); - - /** - * Layout for field: - * {@snippet lang=c : - * DWORD OffsetHigh - * } - */ - public static final OfInt OffsetHigh$layout() { - return OffsetHigh$LAYOUT; - } - - private static final long OffsetHigh$OFFSET = 20; - - /** - * Offset for field: - * {@snippet lang=c : - * DWORD OffsetHigh - * } - */ - public static final long OffsetHigh$offset() { - return OffsetHigh$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * DWORD OffsetHigh - * } - */ - public static int OffsetHigh(MemorySegment struct) { - return struct.get(OffsetHigh$LAYOUT, OffsetHigh$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * DWORD OffsetHigh - * } - */ - public static void OffsetHigh(MemorySegment struct, int fieldValue) { - struct.set(OffsetHigh$LAYOUT, OffsetHigh$OFFSET, fieldValue); - } - - private static final AddressLayout Pointer$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("$anon$55:5"), groupElement("Pointer")); - - /** - * Layout for field: - * {@snippet lang=c : - * PVOID Pointer - * } - */ - public static final AddressLayout Pointer$layout() { - return Pointer$LAYOUT; - } - - private static final long Pointer$OFFSET = 16; - - /** - * Offset for field: - * {@snippet lang=c : - * PVOID Pointer - * } - */ - public static final long Pointer$offset() { - return Pointer$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * PVOID Pointer - * } - */ - public static MemorySegment Pointer(MemorySegment struct) { - return struct.get(Pointer$LAYOUT, Pointer$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * PVOID Pointer - * } - */ - public static void Pointer(MemorySegment struct, MemorySegment fieldValue) { - struct.set(Pointer$LAYOUT, Pointer$OFFSET, fieldValue); - } - - private static final AddressLayout hEvent$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("hEvent")); - - /** - * Layout for field: - * {@snippet lang=c : - * HANDLE hEvent - * } - */ - public static final AddressLayout hEvent$layout() { - return hEvent$LAYOUT; - } - - private static final long hEvent$OFFSET = 24; - - /** - * Offset for field: - * {@snippet lang=c : - * HANDLE hEvent - * } - */ - public static final long hEvent$offset() { - return hEvent$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * HANDLE hEvent - * } - */ - public static MemorySegment hEvent(MemorySegment struct) { - return struct.get(hEvent$LAYOUT, hEvent$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * HANDLE hEvent - * } - */ - public static void hEvent(MemorySegment struct, MemorySegment fieldValue) { - struct.set(hEvent$LAYOUT, hEvent$OFFSET, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java deleted file mode 100644 index 43434083..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ntdll/NtDll.java +++ /dev/null @@ -1,82 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.ntdll; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -public class NtDll { - - NtDll() { - // Should not be called directly - } - - static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } - - static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() - .or(Linker.nativeLinker().defaultLookup()); - - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfInt C_LONG = ValueLayout.JAVA_INT; - public static final ValueLayout.OfDouble C_LONG_DOUBLE = ValueLayout.JAVA_DOUBLE; - private static final int STATUS_UNSUCCESSFUL = (int)-1073741823L; - /** - * {@snippet lang=c : - * #define STATUS_UNSUCCESSFUL -1073741823 - * } - */ - public static int STATUS_UNSUCCESSFUL() { - return STATUS_UNSUCCESSFUL; - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java deleted file mode 100644 index a94f7735..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/ole32/Ole32.java +++ /dev/null @@ -1,122 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.ole32; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -public class Ole32 { - - Ole32() { - // Should not be called directly - } - - static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } - - static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("Ole32"), LIBRARY_ARENA) - .or(SymbolLookup.loaderLookup()) - .or(Linker.nativeLinker().defaultLookup()); - - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfInt C_LONG = ValueLayout.JAVA_INT; - public static final ValueLayout.OfDouble C_LONG_DOUBLE = ValueLayout.JAVA_DOUBLE; - - private static class CLSIDFromString { - public static final FunctionDescriptor DESC = FunctionDescriptor.of( - Ole32.C_LONG, - Ole32.C_POINTER, - Ole32.C_POINTER - ); - - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - Ole32.findOrThrow("CLSIDFromString"), - DESC); - } - - /** - * Function descriptor for: - * {@snippet lang=c : - * extern HRESULT CLSIDFromString(LPCOLESTR lpsz, LPCLSID pclsid) - * } - */ - public static FunctionDescriptor CLSIDFromString$descriptor() { - return CLSIDFromString.DESC; - } - - /** - * Downcall method handle for: - * {@snippet lang=c : - * extern HRESULT CLSIDFromString(LPCOLESTR lpsz, LPCLSID pclsid) - * } - */ - public static MethodHandle CLSIDFromString$handle() { - return CLSIDFromString.HANDLE; - } - /** - * {@snippet lang=c : - * extern HRESULT CLSIDFromString(LPCOLESTR lpsz, LPCLSID pclsid) - * } - */ - public static int CLSIDFromString(MemorySegment lpsz, MemorySegment pclsid) { - var mh$ = CLSIDFromString.HANDLE; - try { - if (TRACE_DOWNCALLS) { - traceDowncall("CLSIDFromString", lpsz, pclsid); - } - return (int)mh$.invokeExact(lpsz, pclsid); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java deleted file mode 100644 index d206dd3e..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/SetupAPI.java +++ /dev/null @@ -1,232 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.setupapi; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -public class SetupAPI { - - SetupAPI() { - // Should not be called directly - } - - static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } - - static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("SetupAPI"), LIBRARY_ARENA) - .or(SymbolLookup.loaderLookup()) - .or(Linker.nativeLinker().defaultLookup()); - - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfInt C_LONG = ValueLayout.JAVA_INT; - public static final ValueLayout.OfDouble C_LONG_DOUBLE = ValueLayout.JAVA_DOUBLE; - private static final int DEVPROP_TYPEMOD_LIST = (int)8192L; - /** - * {@snippet lang=c : - * #define DEVPROP_TYPEMOD_LIST 8192 - * } - */ - public static int DEVPROP_TYPEMOD_LIST() { - return DEVPROP_TYPEMOD_LIST; - } - private static final int DEVPROP_TYPE_UINT32 = (int)7L; - /** - * {@snippet lang=c : - * #define DEVPROP_TYPE_UINT32 7 - * } - */ - public static int DEVPROP_TYPE_UINT32() { - return DEVPROP_TYPE_UINT32; - } - private static final int DEVPROP_TYPE_STRING = (int)18L; - /** - * {@snippet lang=c : - * #define DEVPROP_TYPE_STRING 18 - * } - */ - public static int DEVPROP_TYPE_STRING() { - return DEVPROP_TYPE_STRING; - } - private static final int DICS_FLAG_GLOBAL = (int)1L; - /** - * {@snippet lang=c : - * #define DICS_FLAG_GLOBAL 1 - * } - */ - public static int DICS_FLAG_GLOBAL() { - return DICS_FLAG_GLOBAL; - } - private static final int DIGCF_PRESENT = (int)2L; - /** - * {@snippet lang=c : - * #define DIGCF_PRESENT 2 - * } - */ - public static int DIGCF_PRESENT() { - return DIGCF_PRESENT; - } - private static final int DIGCF_DEVICEINTERFACE = (int)16L; - /** - * {@snippet lang=c : - * #define DIGCF_DEVICEINTERFACE 16 - * } - */ - public static int DIGCF_DEVICEINTERFACE() { - return DIGCF_DEVICEINTERFACE; - } - private static final int DIREG_DEV = (int)1L; - /** - * {@snippet lang=c : - * #define DIREG_DEV 1 - * } - */ - public static int DIREG_DEV() { - return DIREG_DEV; - } - - private static class SetupDiDestroyDeviceInfoList { - public static final FunctionDescriptor DESC = FunctionDescriptor.of( - SetupAPI.C_INT, - SetupAPI.C_POINTER - ); - - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - SetupAPI.findOrThrow("SetupDiDestroyDeviceInfoList"), - DESC); - } - - /** - * Function descriptor for: - * {@snippet lang=c : - * BOOL SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet) - * } - */ - public static FunctionDescriptor SetupDiDestroyDeviceInfoList$descriptor() { - return SetupDiDestroyDeviceInfoList.DESC; - } - - /** - * Downcall method handle for: - * {@snippet lang=c : - * BOOL SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet) - * } - */ - public static MethodHandle SetupDiDestroyDeviceInfoList$handle() { - return SetupDiDestroyDeviceInfoList.HANDLE; - } - /** - * {@snippet lang=c : - * BOOL SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet) - * } - */ - public static int SetupDiDestroyDeviceInfoList(MemorySegment DeviceInfoSet) { - var mh$ = SetupDiDestroyDeviceInfoList.HANDLE; - try { - if (TRACE_DOWNCALLS) { - traceDowncall("SetupDiDestroyDeviceInfoList", DeviceInfoSet); - } - return (int)mh$.invokeExact(DeviceInfoSet); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - private static class SetupDiDeleteDeviceInterfaceData { - public static final FunctionDescriptor DESC = FunctionDescriptor.of( - SetupAPI.C_INT, - SetupAPI.C_POINTER, - SetupAPI.C_POINTER - ); - - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - SetupAPI.findOrThrow("SetupDiDeleteDeviceInterfaceData"), - DESC); - } - - /** - * Function descriptor for: - * {@snippet lang=c : - * BOOL SetupDiDeleteDeviceInterfaceData(HDEVINFO DeviceInfoSet, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) - * } - */ - public static FunctionDescriptor SetupDiDeleteDeviceInterfaceData$descriptor() { - return SetupDiDeleteDeviceInterfaceData.DESC; - } - - /** - * Downcall method handle for: - * {@snippet lang=c : - * BOOL SetupDiDeleteDeviceInterfaceData(HDEVINFO DeviceInfoSet, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) - * } - */ - public static MethodHandle SetupDiDeleteDeviceInterfaceData$handle() { - return SetupDiDeleteDeviceInterfaceData.HANDLE; - } - /** - * {@snippet lang=c : - * BOOL SetupDiDeleteDeviceInterfaceData(HDEVINFO DeviceInfoSet, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) - * } - */ - public static int SetupDiDeleteDeviceInterfaceData(MemorySegment DeviceInfoSet, MemorySegment DeviceInterfaceData) { - var mh$ = SetupDiDeleteDeviceInterfaceData.HANDLE; - try { - if (TRACE_DOWNCALLS) { - traceDowncall("SetupDiDeleteDeviceInterfaceData", DeviceInfoSet, DeviceInterfaceData); - } - return (int)mh$.invokeExact(DeviceInfoSet, DeviceInterfaceData); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java deleted file mode 100644 index 56dae5a6..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_DEVPROPKEY.java +++ /dev/null @@ -1,173 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.setupapi; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct _DEVPROPKEY { - * DEVPROPGUID fmtid; - * DEVPROPID pid; - * } - * } - */ -public class _DEVPROPKEY { - - _DEVPROPKEY() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - _GUID.layout().withName("fmtid"), - SetupAPI.C_LONG.withName("pid") - ).withName("_DEVPROPKEY"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final GroupLayout fmtid$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("fmtid")); - - /** - * Layout for field: - * {@snippet lang=c : - * DEVPROPGUID fmtid - * } - */ - public static final GroupLayout fmtid$layout() { - return fmtid$LAYOUT; - } - - private static final long fmtid$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * DEVPROPGUID fmtid - * } - */ - public static final long fmtid$offset() { - return fmtid$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * DEVPROPGUID fmtid - * } - */ - public static MemorySegment fmtid(MemorySegment struct) { - return struct.asSlice(fmtid$OFFSET, fmtid$LAYOUT.byteSize()); - } - - /** - * Setter for field: - * {@snippet lang=c : - * DEVPROPGUID fmtid - * } - */ - public static void fmtid(MemorySegment struct, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, struct, fmtid$OFFSET, fmtid$LAYOUT.byteSize()); - } - - private static final OfInt pid$LAYOUT = (OfInt)$LAYOUT.select(groupElement("pid")); - - /** - * Layout for field: - * {@snippet lang=c : - * DEVPROPID pid - * } - */ - public static final OfInt pid$layout() { - return pid$LAYOUT; - } - - private static final long pid$OFFSET = 16; - - /** - * Offset for field: - * {@snippet lang=c : - * DEVPROPID pid - * } - */ - public static final long pid$offset() { - return pid$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * DEVPROPID pid - * } - */ - public static int pid(MemorySegment struct) { - return struct.get(pid$LAYOUT, pid$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * DEVPROPID pid - * } - */ - public static void pid(MemorySegment struct, int fieldValue) { - struct.set(pid$LAYOUT, pid$OFFSET, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_GUID.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_GUID.java deleted file mode 100644 index 019decc9..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_GUID.java +++ /dev/null @@ -1,298 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.setupapi; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct _GUID { - * unsigned long Data1; - * unsigned short Data2; - * unsigned short Data3; - * unsigned char Data4[8]; - * } - * } - */ -public class _GUID { - - _GUID() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - SetupAPI.C_LONG.withName("Data1"), - SetupAPI.C_SHORT.withName("Data2"), - SetupAPI.C_SHORT.withName("Data3"), - MemoryLayout.sequenceLayout(8, SetupAPI.C_CHAR).withName("Data4") - ).withName("_GUID"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final OfInt Data1$LAYOUT = (OfInt)$LAYOUT.select(groupElement("Data1")); - - /** - * Layout for field: - * {@snippet lang=c : - * unsigned long Data1 - * } - */ - public static final OfInt Data1$layout() { - return Data1$LAYOUT; - } - - private static final long Data1$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * unsigned long Data1 - * } - */ - public static final long Data1$offset() { - return Data1$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * unsigned long Data1 - * } - */ - public static int Data1(MemorySegment struct) { - return struct.get(Data1$LAYOUT, Data1$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * unsigned long Data1 - * } - */ - public static void Data1(MemorySegment struct, int fieldValue) { - struct.set(Data1$LAYOUT, Data1$OFFSET, fieldValue); - } - - private static final OfShort Data2$LAYOUT = (OfShort)$LAYOUT.select(groupElement("Data2")); - - /** - * Layout for field: - * {@snippet lang=c : - * unsigned short Data2 - * } - */ - public static final OfShort Data2$layout() { - return Data2$LAYOUT; - } - - private static final long Data2$OFFSET = 4; - - /** - * Offset for field: - * {@snippet lang=c : - * unsigned short Data2 - * } - */ - public static final long Data2$offset() { - return Data2$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * unsigned short Data2 - * } - */ - public static short Data2(MemorySegment struct) { - return struct.get(Data2$LAYOUT, Data2$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * unsigned short Data2 - * } - */ - public static void Data2(MemorySegment struct, short fieldValue) { - struct.set(Data2$LAYOUT, Data2$OFFSET, fieldValue); - } - - private static final OfShort Data3$LAYOUT = (OfShort)$LAYOUT.select(groupElement("Data3")); - - /** - * Layout for field: - * {@snippet lang=c : - * unsigned short Data3 - * } - */ - public static final OfShort Data3$layout() { - return Data3$LAYOUT; - } - - private static final long Data3$OFFSET = 6; - - /** - * Offset for field: - * {@snippet lang=c : - * unsigned short Data3 - * } - */ - public static final long Data3$offset() { - return Data3$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * unsigned short Data3 - * } - */ - public static short Data3(MemorySegment struct) { - return struct.get(Data3$LAYOUT, Data3$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * unsigned short Data3 - * } - */ - public static void Data3(MemorySegment struct, short fieldValue) { - struct.set(Data3$LAYOUT, Data3$OFFSET, fieldValue); - } - - private static final SequenceLayout Data4$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("Data4")); - - /** - * Layout for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static final SequenceLayout Data4$layout() { - return Data4$LAYOUT; - } - - private static final long Data4$OFFSET = 8; - - /** - * Offset for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static final long Data4$offset() { - return Data4$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static MemorySegment Data4(MemorySegment struct) { - return struct.asSlice(Data4$OFFSET, Data4$LAYOUT.byteSize()); - } - - /** - * Setter for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static void Data4(MemorySegment struct, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, struct, Data4$OFFSET, Data4$LAYOUT.byteSize()); - } - - private static long[] Data4$DIMS = { 8 }; - - /** - * Dimensions for array field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static long[] Data4$dimensions() { - return Data4$DIMS; - } - private static final VarHandle Data4$ELEM_HANDLE = Data4$LAYOUT.varHandle(sequenceElement()); - - /** - * Indexed getter for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static byte Data4(MemorySegment struct, long index0) { - return (byte)Data4$ELEM_HANDLE.get(struct, 0L, index0); - } - - /** - * Indexed setter for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static void Data4(MemorySegment struct, long index0, byte fieldValue) { - Data4$ELEM_HANDLE.set(struct, 0L, index0, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java deleted file mode 100644 index b97ad0d7..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DATA.java +++ /dev/null @@ -1,265 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.setupapi; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct _SP_DEVICE_INTERFACE_DATA { - * DWORD cbSize; - * GUID InterfaceClassGuid; - * DWORD Flags; - * ULONG_PTR Reserved; - * } - * } - */ -public class _SP_DEVICE_INTERFACE_DATA { - - _SP_DEVICE_INTERFACE_DATA() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - SetupAPI.C_LONG.withName("cbSize"), - _GUID.layout().withName("InterfaceClassGuid"), - SetupAPI.C_LONG.withName("Flags"), - SetupAPI.C_LONG_LONG.withName("Reserved") - ).withName("_SP_DEVICE_INTERFACE_DATA"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final OfInt cbSize$LAYOUT = (OfInt)$LAYOUT.select(groupElement("cbSize")); - - /** - * Layout for field: - * {@snippet lang=c : - * DWORD cbSize - * } - */ - public static final OfInt cbSize$layout() { - return cbSize$LAYOUT; - } - - private static final long cbSize$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * DWORD cbSize - * } - */ - public static final long cbSize$offset() { - return cbSize$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * DWORD cbSize - * } - */ - public static int cbSize(MemorySegment struct) { - return struct.get(cbSize$LAYOUT, cbSize$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * DWORD cbSize - * } - */ - public static void cbSize(MemorySegment struct, int fieldValue) { - struct.set(cbSize$LAYOUT, cbSize$OFFSET, fieldValue); - } - - private static final GroupLayout InterfaceClassGuid$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("InterfaceClassGuid")); - - /** - * Layout for field: - * {@snippet lang=c : - * GUID InterfaceClassGuid - * } - */ - public static final GroupLayout InterfaceClassGuid$layout() { - return InterfaceClassGuid$LAYOUT; - } - - private static final long InterfaceClassGuid$OFFSET = 4; - - /** - * Offset for field: - * {@snippet lang=c : - * GUID InterfaceClassGuid - * } - */ - public static final long InterfaceClassGuid$offset() { - return InterfaceClassGuid$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * GUID InterfaceClassGuid - * } - */ - public static MemorySegment InterfaceClassGuid(MemorySegment struct) { - return struct.asSlice(InterfaceClassGuid$OFFSET, InterfaceClassGuid$LAYOUT.byteSize()); - } - - /** - * Setter for field: - * {@snippet lang=c : - * GUID InterfaceClassGuid - * } - */ - public static void InterfaceClassGuid(MemorySegment struct, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, struct, InterfaceClassGuid$OFFSET, InterfaceClassGuid$LAYOUT.byteSize()); - } - - private static final OfInt Flags$LAYOUT = (OfInt)$LAYOUT.select(groupElement("Flags")); - - /** - * Layout for field: - * {@snippet lang=c : - * DWORD Flags - * } - */ - public static final OfInt Flags$layout() { - return Flags$LAYOUT; - } - - private static final long Flags$OFFSET = 20; - - /** - * Offset for field: - * {@snippet lang=c : - * DWORD Flags - * } - */ - public static final long Flags$offset() { - return Flags$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * DWORD Flags - * } - */ - public static int Flags(MemorySegment struct) { - return struct.get(Flags$LAYOUT, Flags$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * DWORD Flags - * } - */ - public static void Flags(MemorySegment struct, int fieldValue) { - struct.set(Flags$LAYOUT, Flags$OFFSET, fieldValue); - } - - private static final OfLong Reserved$LAYOUT = (OfLong)$LAYOUT.select(groupElement("Reserved")); - - /** - * Layout for field: - * {@snippet lang=c : - * ULONG_PTR Reserved - * } - */ - public static final OfLong Reserved$layout() { - return Reserved$LAYOUT; - } - - private static final long Reserved$OFFSET = 24; - - /** - * Offset for field: - * {@snippet lang=c : - * ULONG_PTR Reserved - * } - */ - public static final long Reserved$offset() { - return Reserved$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * ULONG_PTR Reserved - * } - */ - public static long Reserved(MemorySegment struct) { - return struct.get(Reserved$LAYOUT, Reserved$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * ULONG_PTR Reserved - * } - */ - public static void Reserved(MemorySegment struct, long fieldValue) { - struct.set(Reserved$LAYOUT, Reserved$OFFSET, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java deleted file mode 100644 index 7a07f13e..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVICE_INTERFACE_DETAIL_DATA_W.java +++ /dev/null @@ -1,207 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.setupapi; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W { - * DWORD cbSize; - * WCHAR DevicePath[1]; - * } - * } - */ -public class _SP_DEVICE_INTERFACE_DETAIL_DATA_W { - - _SP_DEVICE_INTERFACE_DETAIL_DATA_W() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - SetupAPI.C_LONG.withName("cbSize"), - MemoryLayout.sequenceLayout(1, SetupAPI.C_SHORT).withName("DevicePath"), - MemoryLayout.paddingLayout(2) - ).withName("_SP_DEVICE_INTERFACE_DETAIL_DATA_W"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final OfInt cbSize$LAYOUT = (OfInt)$LAYOUT.select(groupElement("cbSize")); - - /** - * Layout for field: - * {@snippet lang=c : - * DWORD cbSize - * } - */ - public static final OfInt cbSize$layout() { - return cbSize$LAYOUT; - } - - private static final long cbSize$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * DWORD cbSize - * } - */ - public static final long cbSize$offset() { - return cbSize$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * DWORD cbSize - * } - */ - public static int cbSize(MemorySegment struct) { - return struct.get(cbSize$LAYOUT, cbSize$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * DWORD cbSize - * } - */ - public static void cbSize(MemorySegment struct, int fieldValue) { - struct.set(cbSize$LAYOUT, cbSize$OFFSET, fieldValue); - } - - private static final SequenceLayout DevicePath$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("DevicePath")); - - /** - * Layout for field: - * {@snippet lang=c : - * WCHAR DevicePath[1] - * } - */ - public static final SequenceLayout DevicePath$layout() { - return DevicePath$LAYOUT; - } - - private static final long DevicePath$OFFSET = 4; - - /** - * Offset for field: - * {@snippet lang=c : - * WCHAR DevicePath[1] - * } - */ - public static final long DevicePath$offset() { - return DevicePath$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * WCHAR DevicePath[1] - * } - */ - public static MemorySegment DevicePath(MemorySegment struct) { - return struct.asSlice(DevicePath$OFFSET, DevicePath$LAYOUT.byteSize()); - } - - /** - * Setter for field: - * {@snippet lang=c : - * WCHAR DevicePath[1] - * } - */ - public static void DevicePath(MemorySegment struct, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, struct, DevicePath$OFFSET, DevicePath$LAYOUT.byteSize()); - } - - private static long[] DevicePath$DIMS = { 1 }; - - /** - * Dimensions for array field: - * {@snippet lang=c : - * WCHAR DevicePath[1] - * } - */ - public static long[] DevicePath$dimensions() { - return DevicePath$DIMS; - } - private static final VarHandle DevicePath$ELEM_HANDLE = DevicePath$LAYOUT.varHandle(sequenceElement()); - - /** - * Indexed getter for field: - * {@snippet lang=c : - * WCHAR DevicePath[1] - * } - */ - public static short DevicePath(MemorySegment struct, long index0) { - return (short)DevicePath$ELEM_HANDLE.get(struct, 0L, index0); - } - - /** - * Indexed setter for field: - * {@snippet lang=c : - * WCHAR DevicePath[1] - * } - */ - public static void DevicePath(MemorySegment struct, long index0, short fieldValue) { - DevicePath$ELEM_HANDLE.set(struct, 0L, index0, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java deleted file mode 100644 index 03699c70..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/setupapi/_SP_DEVINFO_DATA.java +++ /dev/null @@ -1,265 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.setupapi; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct _SP_DEVINFO_DATA { - * DWORD cbSize; - * GUID ClassGuid; - * DWORD DevInst; - * ULONG_PTR Reserved; - * } - * } - */ -public class _SP_DEVINFO_DATA { - - _SP_DEVINFO_DATA() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - SetupAPI.C_LONG.withName("cbSize"), - _GUID.layout().withName("ClassGuid"), - SetupAPI.C_LONG.withName("DevInst"), - SetupAPI.C_LONG_LONG.withName("Reserved") - ).withName("_SP_DEVINFO_DATA"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final OfInt cbSize$LAYOUT = (OfInt)$LAYOUT.select(groupElement("cbSize")); - - /** - * Layout for field: - * {@snippet lang=c : - * DWORD cbSize - * } - */ - public static final OfInt cbSize$layout() { - return cbSize$LAYOUT; - } - - private static final long cbSize$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * DWORD cbSize - * } - */ - public static final long cbSize$offset() { - return cbSize$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * DWORD cbSize - * } - */ - public static int cbSize(MemorySegment struct) { - return struct.get(cbSize$LAYOUT, cbSize$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * DWORD cbSize - * } - */ - public static void cbSize(MemorySegment struct, int fieldValue) { - struct.set(cbSize$LAYOUT, cbSize$OFFSET, fieldValue); - } - - private static final GroupLayout ClassGuid$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("ClassGuid")); - - /** - * Layout for field: - * {@snippet lang=c : - * GUID ClassGuid - * } - */ - public static final GroupLayout ClassGuid$layout() { - return ClassGuid$LAYOUT; - } - - private static final long ClassGuid$OFFSET = 4; - - /** - * Offset for field: - * {@snippet lang=c : - * GUID ClassGuid - * } - */ - public static final long ClassGuid$offset() { - return ClassGuid$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * GUID ClassGuid - * } - */ - public static MemorySegment ClassGuid(MemorySegment struct) { - return struct.asSlice(ClassGuid$OFFSET, ClassGuid$LAYOUT.byteSize()); - } - - /** - * Setter for field: - * {@snippet lang=c : - * GUID ClassGuid - * } - */ - public static void ClassGuid(MemorySegment struct, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, struct, ClassGuid$OFFSET, ClassGuid$LAYOUT.byteSize()); - } - - private static final OfInt DevInst$LAYOUT = (OfInt)$LAYOUT.select(groupElement("DevInst")); - - /** - * Layout for field: - * {@snippet lang=c : - * DWORD DevInst - * } - */ - public static final OfInt DevInst$layout() { - return DevInst$LAYOUT; - } - - private static final long DevInst$OFFSET = 20; - - /** - * Offset for field: - * {@snippet lang=c : - * DWORD DevInst - * } - */ - public static final long DevInst$offset() { - return DevInst$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * DWORD DevInst - * } - */ - public static int DevInst(MemorySegment struct) { - return struct.get(DevInst$LAYOUT, DevInst$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * DWORD DevInst - * } - */ - public static void DevInst(MemorySegment struct, int fieldValue) { - struct.set(DevInst$LAYOUT, DevInst$OFFSET, fieldValue); - } - - private static final OfLong Reserved$LAYOUT = (OfLong)$LAYOUT.select(groupElement("Reserved")); - - /** - * Layout for field: - * {@snippet lang=c : - * ULONG_PTR Reserved - * } - */ - public static final OfLong Reserved$layout() { - return Reserved$LAYOUT; - } - - private static final long Reserved$OFFSET = 24; - - /** - * Offset for field: - * {@snippet lang=c : - * ULONG_PTR Reserved - * } - */ - public static final long Reserved$offset() { - return Reserved$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * ULONG_PTR Reserved - * } - */ - public static long Reserved(MemorySegment struct) { - return struct.get(Reserved$LAYOUT, Reserved$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * ULONG_PTR Reserved - * } - */ - public static void Reserved(MemorySegment struct, long fieldValue) { - struct.set(Reserved$LAYOUT, Reserved$OFFSET, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java deleted file mode 100644 index 3ce529cc..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/USBIoctl.java +++ /dev/null @@ -1,91 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.usbioctl; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -public class USBIoctl { - - USBIoctl() { - // Should not be called directly - } - - static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } - - static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() - .or(Linker.nativeLinker().defaultLookup()); - - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfInt C_LONG = ValueLayout.JAVA_INT; - public static final ValueLayout.OfDouble C_LONG_DOUBLE = ValueLayout.JAVA_DOUBLE; - private static final int IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION = (int)2229264L; - /** - * {@snippet lang=c : - * #define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 2229264 - * } - */ - public static int IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION() { - return IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION; - } - private static final int IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX = (int)2229320L; - /** - * {@snippet lang=c : - * #define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX 2229320 - * } - */ - public static int IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX() { - return IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX; - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java deleted file mode 100644 index c3e9a665..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DESCRIPTOR_REQUEST.java +++ /dev/null @@ -1,579 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.usbioctl; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct _USB_DESCRIPTOR_REQUEST { - * ULONG ConnectionIndex; - * struct { - * UCHAR bmRequest; - * UCHAR bRequest; - * USHORT wValue; - * USHORT wIndex; - * USHORT wLength; - * } SetupPacket; - * UCHAR Data[0]; - * } - * } - */ -public class _USB_DESCRIPTOR_REQUEST { - - _USB_DESCRIPTOR_REQUEST() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - USBIoctl.align(USBIoctl.C_LONG, 1).withName("ConnectionIndex"), - _USB_DESCRIPTOR_REQUEST.SetupPacket.layout().withName("SetupPacket"), - MemoryLayout.sequenceLayout(0, USBIoctl.C_CHAR).withName("Data") - ).withName("_USB_DESCRIPTOR_REQUEST"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final OfInt ConnectionIndex$LAYOUT = (OfInt)$LAYOUT.select(groupElement("ConnectionIndex")); - - /** - * Layout for field: - * {@snippet lang=c : - * ULONG ConnectionIndex - * } - */ - public static final OfInt ConnectionIndex$layout() { - return ConnectionIndex$LAYOUT; - } - - private static final long ConnectionIndex$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * ULONG ConnectionIndex - * } - */ - public static final long ConnectionIndex$offset() { - return ConnectionIndex$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * ULONG ConnectionIndex - * } - */ - public static int ConnectionIndex(MemorySegment struct) { - return struct.get(ConnectionIndex$LAYOUT, ConnectionIndex$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * ULONG ConnectionIndex - * } - */ - public static void ConnectionIndex(MemorySegment struct, int fieldValue) { - struct.set(ConnectionIndex$LAYOUT, ConnectionIndex$OFFSET, fieldValue); - } - - /** - * {@snippet lang=c : - * struct { - * UCHAR bmRequest; - * UCHAR bRequest; - * USHORT wValue; - * USHORT wIndex; - * USHORT wLength; - * } - * } - */ - public static class SetupPacket { - - SetupPacket() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - USBIoctl.C_CHAR.withName("bmRequest"), - USBIoctl.C_CHAR.withName("bRequest"), - USBIoctl.align(USBIoctl.C_SHORT, 1).withName("wValue"), - USBIoctl.align(USBIoctl.C_SHORT, 1).withName("wIndex"), - USBIoctl.align(USBIoctl.C_SHORT, 1).withName("wLength") - ).withName("$anon$971:5"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final OfByte bmRequest$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bmRequest")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR bmRequest - * } - */ - public static final OfByte bmRequest$layout() { - return bmRequest$LAYOUT; - } - - private static final long bmRequest$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR bmRequest - * } - */ - public static final long bmRequest$offset() { - return bmRequest$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR bmRequest - * } - */ - public static byte bmRequest(MemorySegment struct) { - return struct.get(bmRequest$LAYOUT, bmRequest$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR bmRequest - * } - */ - public static void bmRequest(MemorySegment struct, byte fieldValue) { - struct.set(bmRequest$LAYOUT, bmRequest$OFFSET, fieldValue); - } - - private static final OfByte bRequest$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bRequest")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR bRequest - * } - */ - public static final OfByte bRequest$layout() { - return bRequest$LAYOUT; - } - - private static final long bRequest$OFFSET = 1; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR bRequest - * } - */ - public static final long bRequest$offset() { - return bRequest$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR bRequest - * } - */ - public static byte bRequest(MemorySegment struct) { - return struct.get(bRequest$LAYOUT, bRequest$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR bRequest - * } - */ - public static void bRequest(MemorySegment struct, byte fieldValue) { - struct.set(bRequest$LAYOUT, bRequest$OFFSET, fieldValue); - } - - private static final OfShort wValue$LAYOUT = (OfShort)$LAYOUT.select(groupElement("wValue")); - - /** - * Layout for field: - * {@snippet lang=c : - * USHORT wValue - * } - */ - public static final OfShort wValue$layout() { - return wValue$LAYOUT; - } - - private static final long wValue$OFFSET = 2; - - /** - * Offset for field: - * {@snippet lang=c : - * USHORT wValue - * } - */ - public static final long wValue$offset() { - return wValue$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * USHORT wValue - * } - */ - public static short wValue(MemorySegment struct) { - return struct.get(wValue$LAYOUT, wValue$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * USHORT wValue - * } - */ - public static void wValue(MemorySegment struct, short fieldValue) { - struct.set(wValue$LAYOUT, wValue$OFFSET, fieldValue); - } - - private static final OfShort wIndex$LAYOUT = (OfShort)$LAYOUT.select(groupElement("wIndex")); - - /** - * Layout for field: - * {@snippet lang=c : - * USHORT wIndex - * } - */ - public static final OfShort wIndex$layout() { - return wIndex$LAYOUT; - } - - private static final long wIndex$OFFSET = 4; - - /** - * Offset for field: - * {@snippet lang=c : - * USHORT wIndex - * } - */ - public static final long wIndex$offset() { - return wIndex$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * USHORT wIndex - * } - */ - public static short wIndex(MemorySegment struct) { - return struct.get(wIndex$LAYOUT, wIndex$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * USHORT wIndex - * } - */ - public static void wIndex(MemorySegment struct, short fieldValue) { - struct.set(wIndex$LAYOUT, wIndex$OFFSET, fieldValue); - } - - private static final OfShort wLength$LAYOUT = (OfShort)$LAYOUT.select(groupElement("wLength")); - - /** - * Layout for field: - * {@snippet lang=c : - * USHORT wLength - * } - */ - public static final OfShort wLength$layout() { - return wLength$LAYOUT; - } - - private static final long wLength$OFFSET = 6; - - /** - * Offset for field: - * {@snippet lang=c : - * USHORT wLength - * } - */ - public static final long wLength$offset() { - return wLength$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * USHORT wLength - * } - */ - public static short wLength(MemorySegment struct) { - return struct.get(wLength$LAYOUT, wLength$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * USHORT wLength - * } - */ - public static void wLength(MemorySegment struct, short fieldValue) { - struct.set(wLength$LAYOUT, wLength$OFFSET, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } - } - - private static final GroupLayout SetupPacket$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("SetupPacket")); - - /** - * Layout for field: - * {@snippet lang=c : - * struct { - * UCHAR bmRequest; - * UCHAR bRequest; - * USHORT wValue; - * USHORT wIndex; - * USHORT wLength; - * } SetupPacket - * } - */ - public static final GroupLayout SetupPacket$layout() { - return SetupPacket$LAYOUT; - } - - private static final long SetupPacket$OFFSET = 4; - - /** - * Offset for field: - * {@snippet lang=c : - * struct { - * UCHAR bmRequest; - * UCHAR bRequest; - * USHORT wValue; - * USHORT wIndex; - * USHORT wLength; - * } SetupPacket - * } - */ - public static final long SetupPacket$offset() { - return SetupPacket$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * struct { - * UCHAR bmRequest; - * UCHAR bRequest; - * USHORT wValue; - * USHORT wIndex; - * USHORT wLength; - * } SetupPacket - * } - */ - public static MemorySegment SetupPacket(MemorySegment struct) { - return struct.asSlice(SetupPacket$OFFSET, SetupPacket$LAYOUT.byteSize()); - } - - /** - * Setter for field: - * {@snippet lang=c : - * struct { - * UCHAR bmRequest; - * UCHAR bRequest; - * USHORT wValue; - * USHORT wIndex; - * USHORT wLength; - * } SetupPacket - * } - */ - public static void SetupPacket(MemorySegment struct, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, struct, SetupPacket$OFFSET, SetupPacket$LAYOUT.byteSize()); - } - - private static final SequenceLayout Data$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("Data")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR Data[0] - * } - */ - public static final SequenceLayout Data$layout() { - return Data$LAYOUT; - } - - private static final long Data$OFFSET = 12; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR Data[0] - * } - */ - public static final long Data$offset() { - return Data$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR Data[0] - * } - */ - public static MemorySegment Data(MemorySegment struct) { - return struct.asSlice(Data$OFFSET, Data$LAYOUT.byteSize()); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR Data[0] - * } - */ - public static void Data(MemorySegment struct, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, struct, Data$OFFSET, Data$LAYOUT.byteSize()); - } - - private static long[] Data$DIMS = { 0 }; - - /** - * Dimensions for array field: - * {@snippet lang=c : - * UCHAR Data[0] - * } - */ - public static long[] Data$dimensions() { - return Data$DIMS; - } - private static final VarHandle Data$ELEM_HANDLE = Data$LAYOUT.varHandle(sequenceElement()); - - /** - * Indexed getter for field: - * {@snippet lang=c : - * UCHAR Data[0] - * } - */ - public static byte Data(MemorySegment struct, long index0) { - return (byte)Data$ELEM_HANDLE.get(struct, 0L, index0); - } - - /** - * Indexed setter for field: - * {@snippet lang=c : - * UCHAR Data[0] - * } - */ - public static void Data(MemorySegment struct, long index0, byte fieldValue) { - Data$ELEM_HANDLE.set(struct, 0L, index0, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java deleted file mode 100644 index c8c41cb3..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_DEVICE_DESCRIPTOR.java +++ /dev/null @@ -1,725 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.usbioctl; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct _USB_DEVICE_DESCRIPTOR { - * UCHAR bLength; - * UCHAR bDescriptorType; - * USHORT bcdUSB; - * UCHAR bDeviceClass; - * UCHAR bDeviceSubClass; - * UCHAR bDeviceProtocol; - * UCHAR bMaxPacketSize0; - * USHORT idVendor; - * USHORT idProduct; - * USHORT bcdDevice; - * UCHAR iManufacturer; - * UCHAR iProduct; - * UCHAR iSerialNumber; - * UCHAR bNumConfigurations; - * } - * } - */ -public class _USB_DEVICE_DESCRIPTOR { - - _USB_DEVICE_DESCRIPTOR() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - USBIoctl.C_CHAR.withName("bLength"), - USBIoctl.C_CHAR.withName("bDescriptorType"), - USBIoctl.align(USBIoctl.C_SHORT, 1).withName("bcdUSB"), - USBIoctl.C_CHAR.withName("bDeviceClass"), - USBIoctl.C_CHAR.withName("bDeviceSubClass"), - USBIoctl.C_CHAR.withName("bDeviceProtocol"), - USBIoctl.C_CHAR.withName("bMaxPacketSize0"), - USBIoctl.align(USBIoctl.C_SHORT, 1).withName("idVendor"), - USBIoctl.align(USBIoctl.C_SHORT, 1).withName("idProduct"), - USBIoctl.align(USBIoctl.C_SHORT, 1).withName("bcdDevice"), - USBIoctl.C_CHAR.withName("iManufacturer"), - USBIoctl.C_CHAR.withName("iProduct"), - USBIoctl.C_CHAR.withName("iSerialNumber"), - USBIoctl.C_CHAR.withName("bNumConfigurations") - ).withName("_USB_DEVICE_DESCRIPTOR"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final OfByte bLength$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bLength")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR bLength - * } - */ - public static final OfByte bLength$layout() { - return bLength$LAYOUT; - } - - private static final long bLength$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR bLength - * } - */ - public static final long bLength$offset() { - return bLength$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR bLength - * } - */ - public static byte bLength(MemorySegment struct) { - return struct.get(bLength$LAYOUT, bLength$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR bLength - * } - */ - public static void bLength(MemorySegment struct, byte fieldValue) { - struct.set(bLength$LAYOUT, bLength$OFFSET, fieldValue); - } - - private static final OfByte bDescriptorType$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bDescriptorType")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR bDescriptorType - * } - */ - public static final OfByte bDescriptorType$layout() { - return bDescriptorType$LAYOUT; - } - - private static final long bDescriptorType$OFFSET = 1; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR bDescriptorType - * } - */ - public static final long bDescriptorType$offset() { - return bDescriptorType$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR bDescriptorType - * } - */ - public static byte bDescriptorType(MemorySegment struct) { - return struct.get(bDescriptorType$LAYOUT, bDescriptorType$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR bDescriptorType - * } - */ - public static void bDescriptorType(MemorySegment struct, byte fieldValue) { - struct.set(bDescriptorType$LAYOUT, bDescriptorType$OFFSET, fieldValue); - } - - private static final OfShort bcdUSB$LAYOUT = (OfShort)$LAYOUT.select(groupElement("bcdUSB")); - - /** - * Layout for field: - * {@snippet lang=c : - * USHORT bcdUSB - * } - */ - public static final OfShort bcdUSB$layout() { - return bcdUSB$LAYOUT; - } - - private static final long bcdUSB$OFFSET = 2; - - /** - * Offset for field: - * {@snippet lang=c : - * USHORT bcdUSB - * } - */ - public static final long bcdUSB$offset() { - return bcdUSB$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * USHORT bcdUSB - * } - */ - public static short bcdUSB(MemorySegment struct) { - return struct.get(bcdUSB$LAYOUT, bcdUSB$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * USHORT bcdUSB - * } - */ - public static void bcdUSB(MemorySegment struct, short fieldValue) { - struct.set(bcdUSB$LAYOUT, bcdUSB$OFFSET, fieldValue); - } - - private static final OfByte bDeviceClass$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bDeviceClass")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR bDeviceClass - * } - */ - public static final OfByte bDeviceClass$layout() { - return bDeviceClass$LAYOUT; - } - - private static final long bDeviceClass$OFFSET = 4; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR bDeviceClass - * } - */ - public static final long bDeviceClass$offset() { - return bDeviceClass$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR bDeviceClass - * } - */ - public static byte bDeviceClass(MemorySegment struct) { - return struct.get(bDeviceClass$LAYOUT, bDeviceClass$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR bDeviceClass - * } - */ - public static void bDeviceClass(MemorySegment struct, byte fieldValue) { - struct.set(bDeviceClass$LAYOUT, bDeviceClass$OFFSET, fieldValue); - } - - private static final OfByte bDeviceSubClass$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bDeviceSubClass")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR bDeviceSubClass - * } - */ - public static final OfByte bDeviceSubClass$layout() { - return bDeviceSubClass$LAYOUT; - } - - private static final long bDeviceSubClass$OFFSET = 5; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR bDeviceSubClass - * } - */ - public static final long bDeviceSubClass$offset() { - return bDeviceSubClass$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR bDeviceSubClass - * } - */ - public static byte bDeviceSubClass(MemorySegment struct) { - return struct.get(bDeviceSubClass$LAYOUT, bDeviceSubClass$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR bDeviceSubClass - * } - */ - public static void bDeviceSubClass(MemorySegment struct, byte fieldValue) { - struct.set(bDeviceSubClass$LAYOUT, bDeviceSubClass$OFFSET, fieldValue); - } - - private static final OfByte bDeviceProtocol$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bDeviceProtocol")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR bDeviceProtocol - * } - */ - public static final OfByte bDeviceProtocol$layout() { - return bDeviceProtocol$LAYOUT; - } - - private static final long bDeviceProtocol$OFFSET = 6; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR bDeviceProtocol - * } - */ - public static final long bDeviceProtocol$offset() { - return bDeviceProtocol$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR bDeviceProtocol - * } - */ - public static byte bDeviceProtocol(MemorySegment struct) { - return struct.get(bDeviceProtocol$LAYOUT, bDeviceProtocol$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR bDeviceProtocol - * } - */ - public static void bDeviceProtocol(MemorySegment struct, byte fieldValue) { - struct.set(bDeviceProtocol$LAYOUT, bDeviceProtocol$OFFSET, fieldValue); - } - - private static final OfByte bMaxPacketSize0$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bMaxPacketSize0")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR bMaxPacketSize0 - * } - */ - public static final OfByte bMaxPacketSize0$layout() { - return bMaxPacketSize0$LAYOUT; - } - - private static final long bMaxPacketSize0$OFFSET = 7; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR bMaxPacketSize0 - * } - */ - public static final long bMaxPacketSize0$offset() { - return bMaxPacketSize0$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR bMaxPacketSize0 - * } - */ - public static byte bMaxPacketSize0(MemorySegment struct) { - return struct.get(bMaxPacketSize0$LAYOUT, bMaxPacketSize0$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR bMaxPacketSize0 - * } - */ - public static void bMaxPacketSize0(MemorySegment struct, byte fieldValue) { - struct.set(bMaxPacketSize0$LAYOUT, bMaxPacketSize0$OFFSET, fieldValue); - } - - private static final OfShort idVendor$LAYOUT = (OfShort)$LAYOUT.select(groupElement("idVendor")); - - /** - * Layout for field: - * {@snippet lang=c : - * USHORT idVendor - * } - */ - public static final OfShort idVendor$layout() { - return idVendor$LAYOUT; - } - - private static final long idVendor$OFFSET = 8; - - /** - * Offset for field: - * {@snippet lang=c : - * USHORT idVendor - * } - */ - public static final long idVendor$offset() { - return idVendor$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * USHORT idVendor - * } - */ - public static short idVendor(MemorySegment struct) { - return struct.get(idVendor$LAYOUT, idVendor$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * USHORT idVendor - * } - */ - public static void idVendor(MemorySegment struct, short fieldValue) { - struct.set(idVendor$LAYOUT, idVendor$OFFSET, fieldValue); - } - - private static final OfShort idProduct$LAYOUT = (OfShort)$LAYOUT.select(groupElement("idProduct")); - - /** - * Layout for field: - * {@snippet lang=c : - * USHORT idProduct - * } - */ - public static final OfShort idProduct$layout() { - return idProduct$LAYOUT; - } - - private static final long idProduct$OFFSET = 10; - - /** - * Offset for field: - * {@snippet lang=c : - * USHORT idProduct - * } - */ - public static final long idProduct$offset() { - return idProduct$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * USHORT idProduct - * } - */ - public static short idProduct(MemorySegment struct) { - return struct.get(idProduct$LAYOUT, idProduct$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * USHORT idProduct - * } - */ - public static void idProduct(MemorySegment struct, short fieldValue) { - struct.set(idProduct$LAYOUT, idProduct$OFFSET, fieldValue); - } - - private static final OfShort bcdDevice$LAYOUT = (OfShort)$LAYOUT.select(groupElement("bcdDevice")); - - /** - * Layout for field: - * {@snippet lang=c : - * USHORT bcdDevice - * } - */ - public static final OfShort bcdDevice$layout() { - return bcdDevice$LAYOUT; - } - - private static final long bcdDevice$OFFSET = 12; - - /** - * Offset for field: - * {@snippet lang=c : - * USHORT bcdDevice - * } - */ - public static final long bcdDevice$offset() { - return bcdDevice$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * USHORT bcdDevice - * } - */ - public static short bcdDevice(MemorySegment struct) { - return struct.get(bcdDevice$LAYOUT, bcdDevice$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * USHORT bcdDevice - * } - */ - public static void bcdDevice(MemorySegment struct, short fieldValue) { - struct.set(bcdDevice$LAYOUT, bcdDevice$OFFSET, fieldValue); - } - - private static final OfByte iManufacturer$LAYOUT = (OfByte)$LAYOUT.select(groupElement("iManufacturer")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR iManufacturer - * } - */ - public static final OfByte iManufacturer$layout() { - return iManufacturer$LAYOUT; - } - - private static final long iManufacturer$OFFSET = 14; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR iManufacturer - * } - */ - public static final long iManufacturer$offset() { - return iManufacturer$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR iManufacturer - * } - */ - public static byte iManufacturer(MemorySegment struct) { - return struct.get(iManufacturer$LAYOUT, iManufacturer$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR iManufacturer - * } - */ - public static void iManufacturer(MemorySegment struct, byte fieldValue) { - struct.set(iManufacturer$LAYOUT, iManufacturer$OFFSET, fieldValue); - } - - private static final OfByte iProduct$LAYOUT = (OfByte)$LAYOUT.select(groupElement("iProduct")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR iProduct - * } - */ - public static final OfByte iProduct$layout() { - return iProduct$LAYOUT; - } - - private static final long iProduct$OFFSET = 15; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR iProduct - * } - */ - public static final long iProduct$offset() { - return iProduct$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR iProduct - * } - */ - public static byte iProduct(MemorySegment struct) { - return struct.get(iProduct$LAYOUT, iProduct$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR iProduct - * } - */ - public static void iProduct(MemorySegment struct, byte fieldValue) { - struct.set(iProduct$LAYOUT, iProduct$OFFSET, fieldValue); - } - - private static final OfByte iSerialNumber$LAYOUT = (OfByte)$LAYOUT.select(groupElement("iSerialNumber")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR iSerialNumber - * } - */ - public static final OfByte iSerialNumber$layout() { - return iSerialNumber$LAYOUT; - } - - private static final long iSerialNumber$OFFSET = 16; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR iSerialNumber - * } - */ - public static final long iSerialNumber$offset() { - return iSerialNumber$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR iSerialNumber - * } - */ - public static byte iSerialNumber(MemorySegment struct) { - return struct.get(iSerialNumber$LAYOUT, iSerialNumber$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR iSerialNumber - * } - */ - public static void iSerialNumber(MemorySegment struct, byte fieldValue) { - struct.set(iSerialNumber$LAYOUT, iSerialNumber$OFFSET, fieldValue); - } - - private static final OfByte bNumConfigurations$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bNumConfigurations")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR bNumConfigurations - * } - */ - public static final OfByte bNumConfigurations$layout() { - return bNumConfigurations$LAYOUT; - } - - private static final long bNumConfigurations$OFFSET = 17; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR bNumConfigurations - * } - */ - public static final long bNumConfigurations$offset() { - return bNumConfigurations$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR bNumConfigurations - * } - */ - public static byte bNumConfigurations(MemorySegment struct) { - return struct.get(bNumConfigurations$LAYOUT, bNumConfigurations$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR bNumConfigurations - * } - */ - public static void bNumConfigurations(MemorySegment struct, byte fieldValue) { - struct.set(bNumConfigurations$LAYOUT, bNumConfigurations$OFFSET, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_ENDPOINT_DESCRIPTOR.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_ENDPOINT_DESCRIPTOR.java deleted file mode 100644 index 965cedf2..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_ENDPOINT_DESCRIPTOR.java +++ /dev/null @@ -1,357 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.usbioctl; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct _USB_ENDPOINT_DESCRIPTOR { - * UCHAR bLength; - * UCHAR bDescriptorType; - * UCHAR bEndpointAddress; - * UCHAR bmAttributes; - * USHORT wMaxPacketSize; - * UCHAR bInterval; - * } - * } - */ -public class _USB_ENDPOINT_DESCRIPTOR { - - _USB_ENDPOINT_DESCRIPTOR() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - USBIoctl.C_CHAR.withName("bLength"), - USBIoctl.C_CHAR.withName("bDescriptorType"), - USBIoctl.C_CHAR.withName("bEndpointAddress"), - USBIoctl.C_CHAR.withName("bmAttributes"), - USBIoctl.align(USBIoctl.C_SHORT, 1).withName("wMaxPacketSize"), - USBIoctl.C_CHAR.withName("bInterval") - ).withName("_USB_ENDPOINT_DESCRIPTOR"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final OfByte bLength$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bLength")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR bLength - * } - */ - public static final OfByte bLength$layout() { - return bLength$LAYOUT; - } - - private static final long bLength$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR bLength - * } - */ - public static final long bLength$offset() { - return bLength$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR bLength - * } - */ - public static byte bLength(MemorySegment struct) { - return struct.get(bLength$LAYOUT, bLength$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR bLength - * } - */ - public static void bLength(MemorySegment struct, byte fieldValue) { - struct.set(bLength$LAYOUT, bLength$OFFSET, fieldValue); - } - - private static final OfByte bDescriptorType$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bDescriptorType")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR bDescriptorType - * } - */ - public static final OfByte bDescriptorType$layout() { - return bDescriptorType$LAYOUT; - } - - private static final long bDescriptorType$OFFSET = 1; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR bDescriptorType - * } - */ - public static final long bDescriptorType$offset() { - return bDescriptorType$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR bDescriptorType - * } - */ - public static byte bDescriptorType(MemorySegment struct) { - return struct.get(bDescriptorType$LAYOUT, bDescriptorType$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR bDescriptorType - * } - */ - public static void bDescriptorType(MemorySegment struct, byte fieldValue) { - struct.set(bDescriptorType$LAYOUT, bDescriptorType$OFFSET, fieldValue); - } - - private static final OfByte bEndpointAddress$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bEndpointAddress")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR bEndpointAddress - * } - */ - public static final OfByte bEndpointAddress$layout() { - return bEndpointAddress$LAYOUT; - } - - private static final long bEndpointAddress$OFFSET = 2; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR bEndpointAddress - * } - */ - public static final long bEndpointAddress$offset() { - return bEndpointAddress$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR bEndpointAddress - * } - */ - public static byte bEndpointAddress(MemorySegment struct) { - return struct.get(bEndpointAddress$LAYOUT, bEndpointAddress$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR bEndpointAddress - * } - */ - public static void bEndpointAddress(MemorySegment struct, byte fieldValue) { - struct.set(bEndpointAddress$LAYOUT, bEndpointAddress$OFFSET, fieldValue); - } - - private static final OfByte bmAttributes$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bmAttributes")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR bmAttributes - * } - */ - public static final OfByte bmAttributes$layout() { - return bmAttributes$LAYOUT; - } - - private static final long bmAttributes$OFFSET = 3; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR bmAttributes - * } - */ - public static final long bmAttributes$offset() { - return bmAttributes$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR bmAttributes - * } - */ - public static byte bmAttributes(MemorySegment struct) { - return struct.get(bmAttributes$LAYOUT, bmAttributes$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR bmAttributes - * } - */ - public static void bmAttributes(MemorySegment struct, byte fieldValue) { - struct.set(bmAttributes$LAYOUT, bmAttributes$OFFSET, fieldValue); - } - - private static final OfShort wMaxPacketSize$LAYOUT = (OfShort)$LAYOUT.select(groupElement("wMaxPacketSize")); - - /** - * Layout for field: - * {@snippet lang=c : - * USHORT wMaxPacketSize - * } - */ - public static final OfShort wMaxPacketSize$layout() { - return wMaxPacketSize$LAYOUT; - } - - private static final long wMaxPacketSize$OFFSET = 4; - - /** - * Offset for field: - * {@snippet lang=c : - * USHORT wMaxPacketSize - * } - */ - public static final long wMaxPacketSize$offset() { - return wMaxPacketSize$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * USHORT wMaxPacketSize - * } - */ - public static short wMaxPacketSize(MemorySegment struct) { - return struct.get(wMaxPacketSize$LAYOUT, wMaxPacketSize$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * USHORT wMaxPacketSize - * } - */ - public static void wMaxPacketSize(MemorySegment struct, short fieldValue) { - struct.set(wMaxPacketSize$LAYOUT, wMaxPacketSize$OFFSET, fieldValue); - } - - private static final OfByte bInterval$LAYOUT = (OfByte)$LAYOUT.select(groupElement("bInterval")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR bInterval - * } - */ - public static final OfByte bInterval$layout() { - return bInterval$LAYOUT; - } - - private static final long bInterval$OFFSET = 6; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR bInterval - * } - */ - public static final long bInterval$offset() { - return bInterval$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR bInterval - * } - */ - public static byte bInterval(MemorySegment struct) { - return struct.get(bInterval$LAYOUT, bInterval$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR bInterval - * } - */ - public static void bInterval(MemorySegment struct, byte fieldValue) { - struct.set(bInterval$LAYOUT, bInterval$OFFSET, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java deleted file mode 100644 index 199c11c9..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_NODE_CONNECTION_INFORMATION_EX.java +++ /dev/null @@ -1,532 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.usbioctl; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct _USB_NODE_CONNECTION_INFORMATION_EX { - * ULONG ConnectionIndex; - * USB_DEVICE_DESCRIPTOR DeviceDescriptor; - * UCHAR CurrentConfigurationValue; - * UCHAR Speed; - * BOOLEAN DeviceIsHub; - * USHORT DeviceAddress; - * ULONG NumberOfOpenPipes; - * USB_CONNECTION_STATUS ConnectionStatus; - * USB_PIPE_INFO PipeList[0]; - * } - * } - */ -public class _USB_NODE_CONNECTION_INFORMATION_EX { - - _USB_NODE_CONNECTION_INFORMATION_EX() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - USBIoctl.align(USBIoctl.C_LONG, 1).withName("ConnectionIndex"), - _USB_DEVICE_DESCRIPTOR.layout().withName("DeviceDescriptor"), - USBIoctl.C_CHAR.withName("CurrentConfigurationValue"), - USBIoctl.C_CHAR.withName("Speed"), - USBIoctl.C_CHAR.withName("DeviceIsHub"), - USBIoctl.align(USBIoctl.C_SHORT, 1).withName("DeviceAddress"), - USBIoctl.align(USBIoctl.C_LONG, 1).withName("NumberOfOpenPipes"), - USBIoctl.align(USBIoctl.C_INT, 1).withName("ConnectionStatus"), - MemoryLayout.sequenceLayout(0, _USB_PIPE_INFO.layout()).withName("PipeList") - ).withName("_USB_NODE_CONNECTION_INFORMATION_EX"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final OfInt ConnectionIndex$LAYOUT = (OfInt)$LAYOUT.select(groupElement("ConnectionIndex")); - - /** - * Layout for field: - * {@snippet lang=c : - * ULONG ConnectionIndex - * } - */ - public static final OfInt ConnectionIndex$layout() { - return ConnectionIndex$LAYOUT; - } - - private static final long ConnectionIndex$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * ULONG ConnectionIndex - * } - */ - public static final long ConnectionIndex$offset() { - return ConnectionIndex$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * ULONG ConnectionIndex - * } - */ - public static int ConnectionIndex(MemorySegment struct) { - return struct.get(ConnectionIndex$LAYOUT, ConnectionIndex$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * ULONG ConnectionIndex - * } - */ - public static void ConnectionIndex(MemorySegment struct, int fieldValue) { - struct.set(ConnectionIndex$LAYOUT, ConnectionIndex$OFFSET, fieldValue); - } - - private static final GroupLayout DeviceDescriptor$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("DeviceDescriptor")); - - /** - * Layout for field: - * {@snippet lang=c : - * USB_DEVICE_DESCRIPTOR DeviceDescriptor - * } - */ - public static final GroupLayout DeviceDescriptor$layout() { - return DeviceDescriptor$LAYOUT; - } - - private static final long DeviceDescriptor$OFFSET = 4; - - /** - * Offset for field: - * {@snippet lang=c : - * USB_DEVICE_DESCRIPTOR DeviceDescriptor - * } - */ - public static final long DeviceDescriptor$offset() { - return DeviceDescriptor$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * USB_DEVICE_DESCRIPTOR DeviceDescriptor - * } - */ - public static MemorySegment DeviceDescriptor(MemorySegment struct) { - return struct.asSlice(DeviceDescriptor$OFFSET, DeviceDescriptor$LAYOUT.byteSize()); - } - - /** - * Setter for field: - * {@snippet lang=c : - * USB_DEVICE_DESCRIPTOR DeviceDescriptor - * } - */ - public static void DeviceDescriptor(MemorySegment struct, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, struct, DeviceDescriptor$OFFSET, DeviceDescriptor$LAYOUT.byteSize()); - } - - private static final OfByte CurrentConfigurationValue$LAYOUT = (OfByte)$LAYOUT.select(groupElement("CurrentConfigurationValue")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR CurrentConfigurationValue - * } - */ - public static final OfByte CurrentConfigurationValue$layout() { - return CurrentConfigurationValue$LAYOUT; - } - - private static final long CurrentConfigurationValue$OFFSET = 22; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR CurrentConfigurationValue - * } - */ - public static final long CurrentConfigurationValue$offset() { - return CurrentConfigurationValue$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR CurrentConfigurationValue - * } - */ - public static byte CurrentConfigurationValue(MemorySegment struct) { - return struct.get(CurrentConfigurationValue$LAYOUT, CurrentConfigurationValue$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR CurrentConfigurationValue - * } - */ - public static void CurrentConfigurationValue(MemorySegment struct, byte fieldValue) { - struct.set(CurrentConfigurationValue$LAYOUT, CurrentConfigurationValue$OFFSET, fieldValue); - } - - private static final OfByte Speed$LAYOUT = (OfByte)$LAYOUT.select(groupElement("Speed")); - - /** - * Layout for field: - * {@snippet lang=c : - * UCHAR Speed - * } - */ - public static final OfByte Speed$layout() { - return Speed$LAYOUT; - } - - private static final long Speed$OFFSET = 23; - - /** - * Offset for field: - * {@snippet lang=c : - * UCHAR Speed - * } - */ - public static final long Speed$offset() { - return Speed$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UCHAR Speed - * } - */ - public static byte Speed(MemorySegment struct) { - return struct.get(Speed$LAYOUT, Speed$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UCHAR Speed - * } - */ - public static void Speed(MemorySegment struct, byte fieldValue) { - struct.set(Speed$LAYOUT, Speed$OFFSET, fieldValue); - } - - private static final OfByte DeviceIsHub$LAYOUT = (OfByte)$LAYOUT.select(groupElement("DeviceIsHub")); - - /** - * Layout for field: - * {@snippet lang=c : - * BOOLEAN DeviceIsHub - * } - */ - public static final OfByte DeviceIsHub$layout() { - return DeviceIsHub$LAYOUT; - } - - private static final long DeviceIsHub$OFFSET = 24; - - /** - * Offset for field: - * {@snippet lang=c : - * BOOLEAN DeviceIsHub - * } - */ - public static final long DeviceIsHub$offset() { - return DeviceIsHub$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * BOOLEAN DeviceIsHub - * } - */ - public static byte DeviceIsHub(MemorySegment struct) { - return struct.get(DeviceIsHub$LAYOUT, DeviceIsHub$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * BOOLEAN DeviceIsHub - * } - */ - public static void DeviceIsHub(MemorySegment struct, byte fieldValue) { - struct.set(DeviceIsHub$LAYOUT, DeviceIsHub$OFFSET, fieldValue); - } - - private static final OfShort DeviceAddress$LAYOUT = (OfShort)$LAYOUT.select(groupElement("DeviceAddress")); - - /** - * Layout for field: - * {@snippet lang=c : - * USHORT DeviceAddress - * } - */ - public static final OfShort DeviceAddress$layout() { - return DeviceAddress$LAYOUT; - } - - private static final long DeviceAddress$OFFSET = 25; - - /** - * Offset for field: - * {@snippet lang=c : - * USHORT DeviceAddress - * } - */ - public static final long DeviceAddress$offset() { - return DeviceAddress$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * USHORT DeviceAddress - * } - */ - public static short DeviceAddress(MemorySegment struct) { - return struct.get(DeviceAddress$LAYOUT, DeviceAddress$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * USHORT DeviceAddress - * } - */ - public static void DeviceAddress(MemorySegment struct, short fieldValue) { - struct.set(DeviceAddress$LAYOUT, DeviceAddress$OFFSET, fieldValue); - } - - private static final OfInt NumberOfOpenPipes$LAYOUT = (OfInt)$LAYOUT.select(groupElement("NumberOfOpenPipes")); - - /** - * Layout for field: - * {@snippet lang=c : - * ULONG NumberOfOpenPipes - * } - */ - public static final OfInt NumberOfOpenPipes$layout() { - return NumberOfOpenPipes$LAYOUT; - } - - private static final long NumberOfOpenPipes$OFFSET = 27; - - /** - * Offset for field: - * {@snippet lang=c : - * ULONG NumberOfOpenPipes - * } - */ - public static final long NumberOfOpenPipes$offset() { - return NumberOfOpenPipes$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * ULONG NumberOfOpenPipes - * } - */ - public static int NumberOfOpenPipes(MemorySegment struct) { - return struct.get(NumberOfOpenPipes$LAYOUT, NumberOfOpenPipes$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * ULONG NumberOfOpenPipes - * } - */ - public static void NumberOfOpenPipes(MemorySegment struct, int fieldValue) { - struct.set(NumberOfOpenPipes$LAYOUT, NumberOfOpenPipes$OFFSET, fieldValue); - } - - private static final OfInt ConnectionStatus$LAYOUT = (OfInt)$LAYOUT.select(groupElement("ConnectionStatus")); - - /** - * Layout for field: - * {@snippet lang=c : - * USB_CONNECTION_STATUS ConnectionStatus - * } - */ - public static final OfInt ConnectionStatus$layout() { - return ConnectionStatus$LAYOUT; - } - - private static final long ConnectionStatus$OFFSET = 31; - - /** - * Offset for field: - * {@snippet lang=c : - * USB_CONNECTION_STATUS ConnectionStatus - * } - */ - public static final long ConnectionStatus$offset() { - return ConnectionStatus$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * USB_CONNECTION_STATUS ConnectionStatus - * } - */ - public static int ConnectionStatus(MemorySegment struct) { - return struct.get(ConnectionStatus$LAYOUT, ConnectionStatus$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * USB_CONNECTION_STATUS ConnectionStatus - * } - */ - public static void ConnectionStatus(MemorySegment struct, int fieldValue) { - struct.set(ConnectionStatus$LAYOUT, ConnectionStatus$OFFSET, fieldValue); - } - - private static final SequenceLayout PipeList$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("PipeList")); - - /** - * Layout for field: - * {@snippet lang=c : - * USB_PIPE_INFO PipeList[0] - * } - */ - public static final SequenceLayout PipeList$layout() { - return PipeList$LAYOUT; - } - - private static final long PipeList$OFFSET = 35; - - /** - * Offset for field: - * {@snippet lang=c : - * USB_PIPE_INFO PipeList[0] - * } - */ - public static final long PipeList$offset() { - return PipeList$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * USB_PIPE_INFO PipeList[0] - * } - */ - public static MemorySegment PipeList(MemorySegment struct) { - return struct.asSlice(PipeList$OFFSET, PipeList$LAYOUT.byteSize()); - } - - /** - * Setter for field: - * {@snippet lang=c : - * USB_PIPE_INFO PipeList[0] - * } - */ - public static void PipeList(MemorySegment struct, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, struct, PipeList$OFFSET, PipeList$LAYOUT.byteSize()); - } - - private static long[] PipeList$DIMS = { 0 }; - - /** - * Dimensions for array field: - * {@snippet lang=c : - * USB_PIPE_INFO PipeList[0] - * } - */ - public static long[] PipeList$dimensions() { - return PipeList$DIMS; - } - private static final MethodHandle PipeList$ELEM_HANDLE = PipeList$LAYOUT.sliceHandle(sequenceElement()); - - /** - * Indexed getter for field: - * {@snippet lang=c : - * USB_PIPE_INFO PipeList[0] - * } - */ - public static MemorySegment PipeList(MemorySegment struct, long index0) { - try { - return (MemorySegment)PipeList$ELEM_HANDLE.invokeExact(struct, 0L, index0); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - /** - * Indexed setter for field: - * {@snippet lang=c : - * USB_PIPE_INFO PipeList[0] - * } - */ - public static void PipeList(MemorySegment struct, long index0, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, PipeList(struct, index0), 0L, _USB_PIPE_INFO.layout().byteSize()); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_PIPE_INFO.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_PIPE_INFO.java deleted file mode 100644 index 0777bc3c..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/usbioctl/_USB_PIPE_INFO.java +++ /dev/null @@ -1,173 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.usbioctl; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct _USB_PIPE_INFO { - * USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; - * ULONG ScheduleOffset; - * } - * } - */ -public class _USB_PIPE_INFO { - - _USB_PIPE_INFO() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - _USB_ENDPOINT_DESCRIPTOR.layout().withName("EndpointDescriptor"), - USBIoctl.align(USBIoctl.C_LONG, 1).withName("ScheduleOffset") - ).withName("_USB_PIPE_INFO"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final GroupLayout EndpointDescriptor$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("EndpointDescriptor")); - - /** - * Layout for field: - * {@snippet lang=c : - * USB_ENDPOINT_DESCRIPTOR EndpointDescriptor - * } - */ - public static final GroupLayout EndpointDescriptor$layout() { - return EndpointDescriptor$LAYOUT; - } - - private static final long EndpointDescriptor$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * USB_ENDPOINT_DESCRIPTOR EndpointDescriptor - * } - */ - public static final long EndpointDescriptor$offset() { - return EndpointDescriptor$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * USB_ENDPOINT_DESCRIPTOR EndpointDescriptor - * } - */ - public static MemorySegment EndpointDescriptor(MemorySegment struct) { - return struct.asSlice(EndpointDescriptor$OFFSET, EndpointDescriptor$LAYOUT.byteSize()); - } - - /** - * Setter for field: - * {@snippet lang=c : - * USB_ENDPOINT_DESCRIPTOR EndpointDescriptor - * } - */ - public static void EndpointDescriptor(MemorySegment struct, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, struct, EndpointDescriptor$OFFSET, EndpointDescriptor$LAYOUT.byteSize()); - } - - private static final OfInt ScheduleOffset$LAYOUT = (OfInt)$LAYOUT.select(groupElement("ScheduleOffset")); - - /** - * Layout for field: - * {@snippet lang=c : - * ULONG ScheduleOffset - * } - */ - public static final OfInt ScheduleOffset$layout() { - return ScheduleOffset$LAYOUT; - } - - private static final long ScheduleOffset$OFFSET = 7; - - /** - * Offset for field: - * {@snippet lang=c : - * ULONG ScheduleOffset - * } - */ - public static final long ScheduleOffset$offset() { - return ScheduleOffset$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * ULONG ScheduleOffset - * } - */ - public static int ScheduleOffset(MemorySegment struct) { - return struct.get(ScheduleOffset$LAYOUT, ScheduleOffset$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * ULONG ScheduleOffset - * } - */ - public static void ScheduleOffset(MemorySegment struct, int fieldValue) { - struct.set(ScheduleOffset$LAYOUT, ScheduleOffset$OFFSET, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java deleted file mode 100644 index f22968ba..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/User32.java +++ /dev/null @@ -1,178 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.user32; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -public class User32 { - - User32() { - // Should not be called directly - } - - static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } - - static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("User32"), LIBRARY_ARENA) - .or(SymbolLookup.loaderLookup()) - .or(Linker.nativeLinker().defaultLookup()); - - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfInt C_LONG = ValueLayout.JAVA_INT; - public static final ValueLayout.OfDouble C_LONG_DOUBLE = ValueLayout.JAVA_DOUBLE; - private static final int WM_DEVICECHANGE = (int)537L; - /** - * {@snippet lang=c : - * #define WM_DEVICECHANGE 537 - * } - */ - public static int WM_DEVICECHANGE() { - return WM_DEVICECHANGE; - } - private static final int DEVICE_NOTIFY_WINDOW_HANDLE = (int)0L; - /** - * {@snippet lang=c : - * #define DEVICE_NOTIFY_WINDOW_HANDLE 0 - * } - */ - public static int DEVICE_NOTIFY_WINDOW_HANDLE() { - return DEVICE_NOTIFY_WINDOW_HANDLE; - } - private static final int DBT_DEVICEARRIVAL = (int)32768L; - /** - * {@snippet lang=c : - * #define DBT_DEVICEARRIVAL 32768 - * } - */ - public static int DBT_DEVICEARRIVAL() { - return DBT_DEVICEARRIVAL; - } - private static final int DBT_DEVICEREMOVECOMPLETE = (int)32772L; - /** - * {@snippet lang=c : - * #define DBT_DEVICEREMOVECOMPLETE 32772 - * } - */ - public static int DBT_DEVICEREMOVECOMPLETE() { - return DBT_DEVICEREMOVECOMPLETE; - } - private static final int DBT_DEVTYP_DEVICEINTERFACE = (int)5L; - /** - * {@snippet lang=c : - * #define DBT_DEVTYP_DEVICEINTERFACE 5 - * } - */ - public static int DBT_DEVTYP_DEVICEINTERFACE() { - return DBT_DEVTYP_DEVICEINTERFACE; - } - - private static class DefWindowProcW { - public static final FunctionDescriptor DESC = FunctionDescriptor.of( - User32.C_LONG_LONG, - User32.C_POINTER, - User32.C_INT, - User32.C_LONG_LONG, - User32.C_LONG_LONG - ); - - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - User32.findOrThrow("DefWindowProcW"), - DESC); - } - - /** - * Function descriptor for: - * {@snippet lang=c : - * LRESULT DefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) - * } - */ - public static FunctionDescriptor DefWindowProcW$descriptor() { - return DefWindowProcW.DESC; - } - - /** - * Downcall method handle for: - * {@snippet lang=c : - * LRESULT DefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) - * } - */ - public static MethodHandle DefWindowProcW$handle() { - return DefWindowProcW.HANDLE; - } - /** - * {@snippet lang=c : - * LRESULT DefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) - * } - */ - public static long DefWindowProcW(MemorySegment hWnd, int Msg, long wParam, long lParam) { - var mh$ = DefWindowProcW.HANDLE; - try { - if (TRACE_DOWNCALLS) { - traceDowncall("DefWindowProcW", hWnd, Msg, wParam, lParam); - } - return (long)mh$.invokeExact(hWnd, Msg, wParam, lParam); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - private static final MemorySegment HWND_MESSAGE = MemorySegment.ofAddress(-3L); - /** - * {@snippet lang=c : - * #define HWND_MESSAGE (void*) -3 - * } - */ - public static MemorySegment HWND_MESSAGE() { - return HWND_MESSAGE; - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java deleted file mode 100644 index 67bbb286..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_DEVICEINTERFACE_W.java +++ /dev/null @@ -1,345 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.user32; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct _DEV_BROADCAST_DEVICEINTERFACE_W { - * DWORD dbcc_size; - * DWORD dbcc_devicetype; - * DWORD dbcc_reserved; - * GUID dbcc_classguid; - * wchar_t dbcc_name[1]; - * } - * } - */ -public class _DEV_BROADCAST_DEVICEINTERFACE_W { - - _DEV_BROADCAST_DEVICEINTERFACE_W() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - User32.C_LONG.withName("dbcc_size"), - User32.C_LONG.withName("dbcc_devicetype"), - User32.C_LONG.withName("dbcc_reserved"), - _GUID.layout().withName("dbcc_classguid"), - MemoryLayout.sequenceLayout(1, User32.C_SHORT).withName("dbcc_name"), - MemoryLayout.paddingLayout(2) - ).withName("_DEV_BROADCAST_DEVICEINTERFACE_W"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final OfInt dbcc_size$LAYOUT = (OfInt)$LAYOUT.select(groupElement("dbcc_size")); - - /** - * Layout for field: - * {@snippet lang=c : - * DWORD dbcc_size - * } - */ - public static final OfInt dbcc_size$layout() { - return dbcc_size$LAYOUT; - } - - private static final long dbcc_size$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * DWORD dbcc_size - * } - */ - public static final long dbcc_size$offset() { - return dbcc_size$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * DWORD dbcc_size - * } - */ - public static int dbcc_size(MemorySegment struct) { - return struct.get(dbcc_size$LAYOUT, dbcc_size$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * DWORD dbcc_size - * } - */ - public static void dbcc_size(MemorySegment struct, int fieldValue) { - struct.set(dbcc_size$LAYOUT, dbcc_size$OFFSET, fieldValue); - } - - private static final OfInt dbcc_devicetype$LAYOUT = (OfInt)$LAYOUT.select(groupElement("dbcc_devicetype")); - - /** - * Layout for field: - * {@snippet lang=c : - * DWORD dbcc_devicetype - * } - */ - public static final OfInt dbcc_devicetype$layout() { - return dbcc_devicetype$LAYOUT; - } - - private static final long dbcc_devicetype$OFFSET = 4; - - /** - * Offset for field: - * {@snippet lang=c : - * DWORD dbcc_devicetype - * } - */ - public static final long dbcc_devicetype$offset() { - return dbcc_devicetype$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * DWORD dbcc_devicetype - * } - */ - public static int dbcc_devicetype(MemorySegment struct) { - return struct.get(dbcc_devicetype$LAYOUT, dbcc_devicetype$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * DWORD dbcc_devicetype - * } - */ - public static void dbcc_devicetype(MemorySegment struct, int fieldValue) { - struct.set(dbcc_devicetype$LAYOUT, dbcc_devicetype$OFFSET, fieldValue); - } - - private static final OfInt dbcc_reserved$LAYOUT = (OfInt)$LAYOUT.select(groupElement("dbcc_reserved")); - - /** - * Layout for field: - * {@snippet lang=c : - * DWORD dbcc_reserved - * } - */ - public static final OfInt dbcc_reserved$layout() { - return dbcc_reserved$LAYOUT; - } - - private static final long dbcc_reserved$OFFSET = 8; - - /** - * Offset for field: - * {@snippet lang=c : - * DWORD dbcc_reserved - * } - */ - public static final long dbcc_reserved$offset() { - return dbcc_reserved$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * DWORD dbcc_reserved - * } - */ - public static int dbcc_reserved(MemorySegment struct) { - return struct.get(dbcc_reserved$LAYOUT, dbcc_reserved$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * DWORD dbcc_reserved - * } - */ - public static void dbcc_reserved(MemorySegment struct, int fieldValue) { - struct.set(dbcc_reserved$LAYOUT, dbcc_reserved$OFFSET, fieldValue); - } - - private static final GroupLayout dbcc_classguid$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("dbcc_classguid")); - - /** - * Layout for field: - * {@snippet lang=c : - * GUID dbcc_classguid - * } - */ - public static final GroupLayout dbcc_classguid$layout() { - return dbcc_classguid$LAYOUT; - } - - private static final long dbcc_classguid$OFFSET = 12; - - /** - * Offset for field: - * {@snippet lang=c : - * GUID dbcc_classguid - * } - */ - public static final long dbcc_classguid$offset() { - return dbcc_classguid$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * GUID dbcc_classguid - * } - */ - public static MemorySegment dbcc_classguid(MemorySegment struct) { - return struct.asSlice(dbcc_classguid$OFFSET, dbcc_classguid$LAYOUT.byteSize()); - } - - /** - * Setter for field: - * {@snippet lang=c : - * GUID dbcc_classguid - * } - */ - public static void dbcc_classguid(MemorySegment struct, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, struct, dbcc_classguid$OFFSET, dbcc_classguid$LAYOUT.byteSize()); - } - - private static final SequenceLayout dbcc_name$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("dbcc_name")); - - /** - * Layout for field: - * {@snippet lang=c : - * wchar_t dbcc_name[1] - * } - */ - public static final SequenceLayout dbcc_name$layout() { - return dbcc_name$LAYOUT; - } - - private static final long dbcc_name$OFFSET = 28; - - /** - * Offset for field: - * {@snippet lang=c : - * wchar_t dbcc_name[1] - * } - */ - public static final long dbcc_name$offset() { - return dbcc_name$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * wchar_t dbcc_name[1] - * } - */ - public static MemorySegment dbcc_name(MemorySegment struct) { - return struct.asSlice(dbcc_name$OFFSET, dbcc_name$LAYOUT.byteSize()); - } - - /** - * Setter for field: - * {@snippet lang=c : - * wchar_t dbcc_name[1] - * } - */ - public static void dbcc_name(MemorySegment struct, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, struct, dbcc_name$OFFSET, dbcc_name$LAYOUT.byteSize()); - } - - private static long[] dbcc_name$DIMS = { 1 }; - - /** - * Dimensions for array field: - * {@snippet lang=c : - * wchar_t dbcc_name[1] - * } - */ - public static long[] dbcc_name$dimensions() { - return dbcc_name$DIMS; - } - private static final VarHandle dbcc_name$ELEM_HANDLE = dbcc_name$LAYOUT.varHandle(sequenceElement()); - - /** - * Indexed getter for field: - * {@snippet lang=c : - * wchar_t dbcc_name[1] - * } - */ - public static short dbcc_name(MemorySegment struct, long index0) { - return (short)dbcc_name$ELEM_HANDLE.get(struct, 0L, index0); - } - - /** - * Indexed setter for field: - * {@snippet lang=c : - * wchar_t dbcc_name[1] - * } - */ - public static void dbcc_name(MemorySegment struct, long index0, short fieldValue) { - dbcc_name$ELEM_HANDLE.set(struct, 0L, index0, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java deleted file mode 100644 index c6723356..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_DEV_BROADCAST_HDR.java +++ /dev/null @@ -1,219 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.user32; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct _DEV_BROADCAST_HDR { - * DWORD dbch_size; - * DWORD dbch_devicetype; - * DWORD dbch_reserved; - * } - * } - */ -public class _DEV_BROADCAST_HDR { - - _DEV_BROADCAST_HDR() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - User32.C_LONG.withName("dbch_size"), - User32.C_LONG.withName("dbch_devicetype"), - User32.C_LONG.withName("dbch_reserved") - ).withName("_DEV_BROADCAST_HDR"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final OfInt dbch_size$LAYOUT = (OfInt)$LAYOUT.select(groupElement("dbch_size")); - - /** - * Layout for field: - * {@snippet lang=c : - * DWORD dbch_size - * } - */ - public static final OfInt dbch_size$layout() { - return dbch_size$LAYOUT; - } - - private static final long dbch_size$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * DWORD dbch_size - * } - */ - public static final long dbch_size$offset() { - return dbch_size$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * DWORD dbch_size - * } - */ - public static int dbch_size(MemorySegment struct) { - return struct.get(dbch_size$LAYOUT, dbch_size$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * DWORD dbch_size - * } - */ - public static void dbch_size(MemorySegment struct, int fieldValue) { - struct.set(dbch_size$LAYOUT, dbch_size$OFFSET, fieldValue); - } - - private static final OfInt dbch_devicetype$LAYOUT = (OfInt)$LAYOUT.select(groupElement("dbch_devicetype")); - - /** - * Layout for field: - * {@snippet lang=c : - * DWORD dbch_devicetype - * } - */ - public static final OfInt dbch_devicetype$layout() { - return dbch_devicetype$LAYOUT; - } - - private static final long dbch_devicetype$OFFSET = 4; - - /** - * Offset for field: - * {@snippet lang=c : - * DWORD dbch_devicetype - * } - */ - public static final long dbch_devicetype$offset() { - return dbch_devicetype$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * DWORD dbch_devicetype - * } - */ - public static int dbch_devicetype(MemorySegment struct) { - return struct.get(dbch_devicetype$LAYOUT, dbch_devicetype$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * DWORD dbch_devicetype - * } - */ - public static void dbch_devicetype(MemorySegment struct, int fieldValue) { - struct.set(dbch_devicetype$LAYOUT, dbch_devicetype$OFFSET, fieldValue); - } - - private static final OfInt dbch_reserved$LAYOUT = (OfInt)$LAYOUT.select(groupElement("dbch_reserved")); - - /** - * Layout for field: - * {@snippet lang=c : - * DWORD dbch_reserved - * } - */ - public static final OfInt dbch_reserved$layout() { - return dbch_reserved$LAYOUT; - } - - private static final long dbch_reserved$OFFSET = 8; - - /** - * Offset for field: - * {@snippet lang=c : - * DWORD dbch_reserved - * } - */ - public static final long dbch_reserved$offset() { - return dbch_reserved$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * DWORD dbch_reserved - * } - */ - public static int dbch_reserved(MemorySegment struct) { - return struct.get(dbch_reserved$LAYOUT, dbch_reserved$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * DWORD dbch_reserved - * } - */ - public static void dbch_reserved(MemorySegment struct, int fieldValue) { - struct.set(dbch_reserved$LAYOUT, dbch_reserved$OFFSET, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_GUID.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_GUID.java deleted file mode 100644 index ecef1ab6..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/_GUID.java +++ /dev/null @@ -1,298 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.user32; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct _GUID { - * unsigned long Data1; - * unsigned short Data2; - * unsigned short Data3; - * unsigned char Data4[8]; - * } - * } - */ -public class _GUID { - - _GUID() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - User32.C_LONG.withName("Data1"), - User32.C_SHORT.withName("Data2"), - User32.C_SHORT.withName("Data3"), - MemoryLayout.sequenceLayout(8, User32.C_CHAR).withName("Data4") - ).withName("_GUID"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final OfInt Data1$LAYOUT = (OfInt)$LAYOUT.select(groupElement("Data1")); - - /** - * Layout for field: - * {@snippet lang=c : - * unsigned long Data1 - * } - */ - public static final OfInt Data1$layout() { - return Data1$LAYOUT; - } - - private static final long Data1$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * unsigned long Data1 - * } - */ - public static final long Data1$offset() { - return Data1$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * unsigned long Data1 - * } - */ - public static int Data1(MemorySegment struct) { - return struct.get(Data1$LAYOUT, Data1$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * unsigned long Data1 - * } - */ - public static void Data1(MemorySegment struct, int fieldValue) { - struct.set(Data1$LAYOUT, Data1$OFFSET, fieldValue); - } - - private static final OfShort Data2$LAYOUT = (OfShort)$LAYOUT.select(groupElement("Data2")); - - /** - * Layout for field: - * {@snippet lang=c : - * unsigned short Data2 - * } - */ - public static final OfShort Data2$layout() { - return Data2$LAYOUT; - } - - private static final long Data2$OFFSET = 4; - - /** - * Offset for field: - * {@snippet lang=c : - * unsigned short Data2 - * } - */ - public static final long Data2$offset() { - return Data2$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * unsigned short Data2 - * } - */ - public static short Data2(MemorySegment struct) { - return struct.get(Data2$LAYOUT, Data2$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * unsigned short Data2 - * } - */ - public static void Data2(MemorySegment struct, short fieldValue) { - struct.set(Data2$LAYOUT, Data2$OFFSET, fieldValue); - } - - private static final OfShort Data3$LAYOUT = (OfShort)$LAYOUT.select(groupElement("Data3")); - - /** - * Layout for field: - * {@snippet lang=c : - * unsigned short Data3 - * } - */ - public static final OfShort Data3$layout() { - return Data3$LAYOUT; - } - - private static final long Data3$OFFSET = 6; - - /** - * Offset for field: - * {@snippet lang=c : - * unsigned short Data3 - * } - */ - public static final long Data3$offset() { - return Data3$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * unsigned short Data3 - * } - */ - public static short Data3(MemorySegment struct) { - return struct.get(Data3$LAYOUT, Data3$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * unsigned short Data3 - * } - */ - public static void Data3(MemorySegment struct, short fieldValue) { - struct.set(Data3$LAYOUT, Data3$OFFSET, fieldValue); - } - - private static final SequenceLayout Data4$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("Data4")); - - /** - * Layout for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static final SequenceLayout Data4$layout() { - return Data4$LAYOUT; - } - - private static final long Data4$OFFSET = 8; - - /** - * Offset for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static final long Data4$offset() { - return Data4$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static MemorySegment Data4(MemorySegment struct) { - return struct.asSlice(Data4$OFFSET, Data4$LAYOUT.byteSize()); - } - - /** - * Setter for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static void Data4(MemorySegment struct, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, struct, Data4$OFFSET, Data4$LAYOUT.byteSize()); - } - - private static long[] Data4$DIMS = { 8 }; - - /** - * Dimensions for array field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static long[] Data4$dimensions() { - return Data4$DIMS; - } - private static final VarHandle Data4$ELEM_HANDLE = Data4$LAYOUT.varHandle(sequenceElement()); - - /** - * Indexed getter for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static byte Data4(MemorySegment struct, long index0) { - return (byte)Data4$ELEM_HANDLE.get(struct, 0L, index0); - } - - /** - * Indexed setter for field: - * {@snippet lang=c : - * unsigned char Data4[8] - * } - */ - public static void Data4(MemorySegment struct, long index0, byte fieldValue) { - Data4$ELEM_HANDLE.set(struct, 0L, index0, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java deleted file mode 100644 index b75ef832..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagMSG.java +++ /dev/null @@ -1,359 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.user32; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct tagMSG { - * HWND hwnd; - * UINT message; - * WPARAM wParam; - * LPARAM lParam; - * DWORD time; - * POINT pt; - * } - * } - */ -public class tagMSG { - - tagMSG() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - User32.C_POINTER.withName("hwnd"), - User32.C_INT.withName("message"), - MemoryLayout.paddingLayout(4), - User32.C_LONG_LONG.withName("wParam"), - User32.C_LONG_LONG.withName("lParam"), - User32.C_LONG.withName("time"), - tagPOINT.layout().withName("pt"), - MemoryLayout.paddingLayout(4) - ).withName("tagMSG"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final AddressLayout hwnd$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("hwnd")); - - /** - * Layout for field: - * {@snippet lang=c : - * HWND hwnd - * } - */ - public static final AddressLayout hwnd$layout() { - return hwnd$LAYOUT; - } - - private static final long hwnd$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * HWND hwnd - * } - */ - public static final long hwnd$offset() { - return hwnd$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * HWND hwnd - * } - */ - public static MemorySegment hwnd(MemorySegment struct) { - return struct.get(hwnd$LAYOUT, hwnd$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * HWND hwnd - * } - */ - public static void hwnd(MemorySegment struct, MemorySegment fieldValue) { - struct.set(hwnd$LAYOUT, hwnd$OFFSET, fieldValue); - } - - private static final OfInt message$LAYOUT = (OfInt)$LAYOUT.select(groupElement("message")); - - /** - * Layout for field: - * {@snippet lang=c : - * UINT message - * } - */ - public static final OfInt message$layout() { - return message$LAYOUT; - } - - private static final long message$OFFSET = 8; - - /** - * Offset for field: - * {@snippet lang=c : - * UINT message - * } - */ - public static final long message$offset() { - return message$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UINT message - * } - */ - public static int message(MemorySegment struct) { - return struct.get(message$LAYOUT, message$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UINT message - * } - */ - public static void message(MemorySegment struct, int fieldValue) { - struct.set(message$LAYOUT, message$OFFSET, fieldValue); - } - - private static final OfLong wParam$LAYOUT = (OfLong)$LAYOUT.select(groupElement("wParam")); - - /** - * Layout for field: - * {@snippet lang=c : - * WPARAM wParam - * } - */ - public static final OfLong wParam$layout() { - return wParam$LAYOUT; - } - - private static final long wParam$OFFSET = 16; - - /** - * Offset for field: - * {@snippet lang=c : - * WPARAM wParam - * } - */ - public static final long wParam$offset() { - return wParam$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * WPARAM wParam - * } - */ - public static long wParam(MemorySegment struct) { - return struct.get(wParam$LAYOUT, wParam$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * WPARAM wParam - * } - */ - public static void wParam(MemorySegment struct, long fieldValue) { - struct.set(wParam$LAYOUT, wParam$OFFSET, fieldValue); - } - - private static final OfLong lParam$LAYOUT = (OfLong)$LAYOUT.select(groupElement("lParam")); - - /** - * Layout for field: - * {@snippet lang=c : - * LPARAM lParam - * } - */ - public static final OfLong lParam$layout() { - return lParam$LAYOUT; - } - - private static final long lParam$OFFSET = 24; - - /** - * Offset for field: - * {@snippet lang=c : - * LPARAM lParam - * } - */ - public static final long lParam$offset() { - return lParam$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * LPARAM lParam - * } - */ - public static long lParam(MemorySegment struct) { - return struct.get(lParam$LAYOUT, lParam$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * LPARAM lParam - * } - */ - public static void lParam(MemorySegment struct, long fieldValue) { - struct.set(lParam$LAYOUT, lParam$OFFSET, fieldValue); - } - - private static final OfInt time$LAYOUT = (OfInt)$LAYOUT.select(groupElement("time")); - - /** - * Layout for field: - * {@snippet lang=c : - * DWORD time - * } - */ - public static final OfInt time$layout() { - return time$LAYOUT; - } - - private static final long time$OFFSET = 32; - - /** - * Offset for field: - * {@snippet lang=c : - * DWORD time - * } - */ - public static final long time$offset() { - return time$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * DWORD time - * } - */ - public static int time(MemorySegment struct) { - return struct.get(time$LAYOUT, time$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * DWORD time - * } - */ - public static void time(MemorySegment struct, int fieldValue) { - struct.set(time$LAYOUT, time$OFFSET, fieldValue); - } - - private static final GroupLayout pt$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("pt")); - - /** - * Layout for field: - * {@snippet lang=c : - * POINT pt - * } - */ - public static final GroupLayout pt$layout() { - return pt$LAYOUT; - } - - private static final long pt$OFFSET = 36; - - /** - * Offset for field: - * {@snippet lang=c : - * POINT pt - * } - */ - public static final long pt$offset() { - return pt$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * POINT pt - * } - */ - public static MemorySegment pt(MemorySegment struct) { - return struct.asSlice(pt$OFFSET, pt$LAYOUT.byteSize()); - } - - /** - * Setter for field: - * {@snippet lang=c : - * POINT pt - * } - */ - public static void pt(MemorySegment struct, MemorySegment fieldValue) { - MemorySegment.copy(fieldValue, 0L, struct, pt$OFFSET, pt$LAYOUT.byteSize()); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagPOINT.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagPOINT.java deleted file mode 100644 index 54888fc4..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagPOINT.java +++ /dev/null @@ -1,173 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.user32; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct tagPOINT { - * LONG x; - * LONG y; - * } - * } - */ -public class tagPOINT { - - tagPOINT() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - User32.C_LONG.withName("x"), - User32.C_LONG.withName("y") - ).withName("tagPOINT"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final OfInt x$LAYOUT = (OfInt)$LAYOUT.select(groupElement("x")); - - /** - * Layout for field: - * {@snippet lang=c : - * LONG x - * } - */ - public static final OfInt x$layout() { - return x$LAYOUT; - } - - private static final long x$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * LONG x - * } - */ - public static final long x$offset() { - return x$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * LONG x - * } - */ - public static int x(MemorySegment struct) { - return struct.get(x$LAYOUT, x$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * LONG x - * } - */ - public static void x(MemorySegment struct, int fieldValue) { - struct.set(x$LAYOUT, x$OFFSET, fieldValue); - } - - private static final OfInt y$LAYOUT = (OfInt)$LAYOUT.select(groupElement("y")); - - /** - * Layout for field: - * {@snippet lang=c : - * LONG y - * } - */ - public static final OfInt y$layout() { - return y$LAYOUT; - } - - private static final long y$OFFSET = 4; - - /** - * Offset for field: - * {@snippet lang=c : - * LONG y - * } - */ - public static final long y$offset() { - return y$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * LONG y - * } - */ - public static int y(MemorySegment struct) { - return struct.get(y$LAYOUT, y$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * LONG y - * } - */ - public static void y(MemorySegment struct, int fieldValue) { - struct.set(y$LAYOUT, y$OFFSET, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java deleted file mode 100644 index 525ff27b..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/user32/tagWNDCLASSEXW.java +++ /dev/null @@ -1,633 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.user32; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -/** - * {@snippet lang=c : - * struct tagWNDCLASSEXW { - * UINT cbSize; - * UINT style; - * WNDPROC lpfnWndProc; - * int cbClsExtra; - * int cbWndExtra; - * HINSTANCE hInstance; - * HICON hIcon; - * HCURSOR hCursor; - * HBRUSH hbrBackground; - * LPCWSTR lpszMenuName; - * LPCWSTR lpszClassName; - * HICON hIconSm; - * } - * } - */ -public class tagWNDCLASSEXW { - - tagWNDCLASSEXW() { - // Should not be called directly - } - - private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( - User32.C_INT.withName("cbSize"), - User32.C_INT.withName("style"), - User32.C_POINTER.withName("lpfnWndProc"), - User32.C_INT.withName("cbClsExtra"), - User32.C_INT.withName("cbWndExtra"), - User32.C_POINTER.withName("hInstance"), - User32.C_POINTER.withName("hIcon"), - User32.C_POINTER.withName("hCursor"), - User32.C_POINTER.withName("hbrBackground"), - User32.C_POINTER.withName("lpszMenuName"), - User32.C_POINTER.withName("lpszClassName"), - User32.C_POINTER.withName("hIconSm") - ).withName("tagWNDCLASSEXW"); - - /** - * The layout of this struct - */ - public static final GroupLayout layout() { - return $LAYOUT; - } - - private static final OfInt cbSize$LAYOUT = (OfInt)$LAYOUT.select(groupElement("cbSize")); - - /** - * Layout for field: - * {@snippet lang=c : - * UINT cbSize - * } - */ - public static final OfInt cbSize$layout() { - return cbSize$LAYOUT; - } - - private static final long cbSize$OFFSET = 0; - - /** - * Offset for field: - * {@snippet lang=c : - * UINT cbSize - * } - */ - public static final long cbSize$offset() { - return cbSize$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UINT cbSize - * } - */ - public static int cbSize(MemorySegment struct) { - return struct.get(cbSize$LAYOUT, cbSize$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UINT cbSize - * } - */ - public static void cbSize(MemorySegment struct, int fieldValue) { - struct.set(cbSize$LAYOUT, cbSize$OFFSET, fieldValue); - } - - private static final OfInt style$LAYOUT = (OfInt)$LAYOUT.select(groupElement("style")); - - /** - * Layout for field: - * {@snippet lang=c : - * UINT style - * } - */ - public static final OfInt style$layout() { - return style$LAYOUT; - } - - private static final long style$OFFSET = 4; - - /** - * Offset for field: - * {@snippet lang=c : - * UINT style - * } - */ - public static final long style$offset() { - return style$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * UINT style - * } - */ - public static int style(MemorySegment struct) { - return struct.get(style$LAYOUT, style$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * UINT style - * } - */ - public static void style(MemorySegment struct, int fieldValue) { - struct.set(style$LAYOUT, style$OFFSET, fieldValue); - } - - private static final AddressLayout lpfnWndProc$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("lpfnWndProc")); - - /** - * Layout for field: - * {@snippet lang=c : - * WNDPROC lpfnWndProc - * } - */ - public static final AddressLayout lpfnWndProc$layout() { - return lpfnWndProc$LAYOUT; - } - - private static final long lpfnWndProc$OFFSET = 8; - - /** - * Offset for field: - * {@snippet lang=c : - * WNDPROC lpfnWndProc - * } - */ - public static final long lpfnWndProc$offset() { - return lpfnWndProc$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * WNDPROC lpfnWndProc - * } - */ - public static MemorySegment lpfnWndProc(MemorySegment struct) { - return struct.get(lpfnWndProc$LAYOUT, lpfnWndProc$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * WNDPROC lpfnWndProc - * } - */ - public static void lpfnWndProc(MemorySegment struct, MemorySegment fieldValue) { - struct.set(lpfnWndProc$LAYOUT, lpfnWndProc$OFFSET, fieldValue); - } - - private static final OfInt cbClsExtra$LAYOUT = (OfInt)$LAYOUT.select(groupElement("cbClsExtra")); - - /** - * Layout for field: - * {@snippet lang=c : - * int cbClsExtra - * } - */ - public static final OfInt cbClsExtra$layout() { - return cbClsExtra$LAYOUT; - } - - private static final long cbClsExtra$OFFSET = 16; - - /** - * Offset for field: - * {@snippet lang=c : - * int cbClsExtra - * } - */ - public static final long cbClsExtra$offset() { - return cbClsExtra$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * int cbClsExtra - * } - */ - public static int cbClsExtra(MemorySegment struct) { - return struct.get(cbClsExtra$LAYOUT, cbClsExtra$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * int cbClsExtra - * } - */ - public static void cbClsExtra(MemorySegment struct, int fieldValue) { - struct.set(cbClsExtra$LAYOUT, cbClsExtra$OFFSET, fieldValue); - } - - private static final OfInt cbWndExtra$LAYOUT = (OfInt)$LAYOUT.select(groupElement("cbWndExtra")); - - /** - * Layout for field: - * {@snippet lang=c : - * int cbWndExtra - * } - */ - public static final OfInt cbWndExtra$layout() { - return cbWndExtra$LAYOUT; - } - - private static final long cbWndExtra$OFFSET = 20; - - /** - * Offset for field: - * {@snippet lang=c : - * int cbWndExtra - * } - */ - public static final long cbWndExtra$offset() { - return cbWndExtra$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * int cbWndExtra - * } - */ - public static int cbWndExtra(MemorySegment struct) { - return struct.get(cbWndExtra$LAYOUT, cbWndExtra$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * int cbWndExtra - * } - */ - public static void cbWndExtra(MemorySegment struct, int fieldValue) { - struct.set(cbWndExtra$LAYOUT, cbWndExtra$OFFSET, fieldValue); - } - - private static final AddressLayout hInstance$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("hInstance")); - - /** - * Layout for field: - * {@snippet lang=c : - * HINSTANCE hInstance - * } - */ - public static final AddressLayout hInstance$layout() { - return hInstance$LAYOUT; - } - - private static final long hInstance$OFFSET = 24; - - /** - * Offset for field: - * {@snippet lang=c : - * HINSTANCE hInstance - * } - */ - public static final long hInstance$offset() { - return hInstance$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * HINSTANCE hInstance - * } - */ - public static MemorySegment hInstance(MemorySegment struct) { - return struct.get(hInstance$LAYOUT, hInstance$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * HINSTANCE hInstance - * } - */ - public static void hInstance(MemorySegment struct, MemorySegment fieldValue) { - struct.set(hInstance$LAYOUT, hInstance$OFFSET, fieldValue); - } - - private static final AddressLayout hIcon$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("hIcon")); - - /** - * Layout for field: - * {@snippet lang=c : - * HICON hIcon - * } - */ - public static final AddressLayout hIcon$layout() { - return hIcon$LAYOUT; - } - - private static final long hIcon$OFFSET = 32; - - /** - * Offset for field: - * {@snippet lang=c : - * HICON hIcon - * } - */ - public static final long hIcon$offset() { - return hIcon$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * HICON hIcon - * } - */ - public static MemorySegment hIcon(MemorySegment struct) { - return struct.get(hIcon$LAYOUT, hIcon$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * HICON hIcon - * } - */ - public static void hIcon(MemorySegment struct, MemorySegment fieldValue) { - struct.set(hIcon$LAYOUT, hIcon$OFFSET, fieldValue); - } - - private static final AddressLayout hCursor$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("hCursor")); - - /** - * Layout for field: - * {@snippet lang=c : - * HCURSOR hCursor - * } - */ - public static final AddressLayout hCursor$layout() { - return hCursor$LAYOUT; - } - - private static final long hCursor$OFFSET = 40; - - /** - * Offset for field: - * {@snippet lang=c : - * HCURSOR hCursor - * } - */ - public static final long hCursor$offset() { - return hCursor$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * HCURSOR hCursor - * } - */ - public static MemorySegment hCursor(MemorySegment struct) { - return struct.get(hCursor$LAYOUT, hCursor$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * HCURSOR hCursor - * } - */ - public static void hCursor(MemorySegment struct, MemorySegment fieldValue) { - struct.set(hCursor$LAYOUT, hCursor$OFFSET, fieldValue); - } - - private static final AddressLayout hbrBackground$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("hbrBackground")); - - /** - * Layout for field: - * {@snippet lang=c : - * HBRUSH hbrBackground - * } - */ - public static final AddressLayout hbrBackground$layout() { - return hbrBackground$LAYOUT; - } - - private static final long hbrBackground$OFFSET = 48; - - /** - * Offset for field: - * {@snippet lang=c : - * HBRUSH hbrBackground - * } - */ - public static final long hbrBackground$offset() { - return hbrBackground$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * HBRUSH hbrBackground - * } - */ - public static MemorySegment hbrBackground(MemorySegment struct) { - return struct.get(hbrBackground$LAYOUT, hbrBackground$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * HBRUSH hbrBackground - * } - */ - public static void hbrBackground(MemorySegment struct, MemorySegment fieldValue) { - struct.set(hbrBackground$LAYOUT, hbrBackground$OFFSET, fieldValue); - } - - private static final AddressLayout lpszMenuName$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("lpszMenuName")); - - /** - * Layout for field: - * {@snippet lang=c : - * LPCWSTR lpszMenuName - * } - */ - public static final AddressLayout lpszMenuName$layout() { - return lpszMenuName$LAYOUT; - } - - private static final long lpszMenuName$OFFSET = 56; - - /** - * Offset for field: - * {@snippet lang=c : - * LPCWSTR lpszMenuName - * } - */ - public static final long lpszMenuName$offset() { - return lpszMenuName$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * LPCWSTR lpszMenuName - * } - */ - public static MemorySegment lpszMenuName(MemorySegment struct) { - return struct.get(lpszMenuName$LAYOUT, lpszMenuName$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * LPCWSTR lpszMenuName - * } - */ - public static void lpszMenuName(MemorySegment struct, MemorySegment fieldValue) { - struct.set(lpszMenuName$LAYOUT, lpszMenuName$OFFSET, fieldValue); - } - - private static final AddressLayout lpszClassName$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("lpszClassName")); - - /** - * Layout for field: - * {@snippet lang=c : - * LPCWSTR lpszClassName - * } - */ - public static final AddressLayout lpszClassName$layout() { - return lpszClassName$LAYOUT; - } - - private static final long lpszClassName$OFFSET = 64; - - /** - * Offset for field: - * {@snippet lang=c : - * LPCWSTR lpszClassName - * } - */ - public static final long lpszClassName$offset() { - return lpszClassName$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * LPCWSTR lpszClassName - * } - */ - public static MemorySegment lpszClassName(MemorySegment struct) { - return struct.get(lpszClassName$LAYOUT, lpszClassName$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * LPCWSTR lpszClassName - * } - */ - public static void lpszClassName(MemorySegment struct, MemorySegment fieldValue) { - struct.set(lpszClassName$LAYOUT, lpszClassName$OFFSET, fieldValue); - } - - private static final AddressLayout hIconSm$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("hIconSm")); - - /** - * Layout for field: - * {@snippet lang=c : - * HICON hIconSm - * } - */ - public static final AddressLayout hIconSm$layout() { - return hIconSm$LAYOUT; - } - - private static final long hIconSm$OFFSET = 72; - - /** - * Offset for field: - * {@snippet lang=c : - * HICON hIconSm - * } - */ - public static final long hIconSm$offset() { - return hIconSm$OFFSET; - } - - /** - * Getter for field: - * {@snippet lang=c : - * HICON hIconSm - * } - */ - public static MemorySegment hIconSm(MemorySegment struct) { - return struct.get(hIconSm$LAYOUT, hIconSm$OFFSET); - } - - /** - * Setter for field: - * {@snippet lang=c : - * HICON hIconSm - * } - */ - public static void hIconSm(MemorySegment struct, MemorySegment fieldValue) { - struct.set(hIconSm$LAYOUT, hIconSm$OFFSET, fieldValue); - } - - /** - * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. - * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} - */ - public static MemorySegment asSlice(MemorySegment array, long index) { - return array.asSlice(layout().byteSize() * index); - } - - /** - * The size (in bytes) of this struct - */ - public static long sizeof() { return layout().byteSize(); } - - /** - * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} - */ - public static MemorySegment allocate(SegmentAllocator allocator) { - return allocator.allocate(layout()); - } - - /** - * Allocate an array of size {@code elementCount} using {@code allocator}. - * The returned segment has size {@code elementCount * layout().byteSize()}. - */ - public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { - return reinterpret(addr, 1, arena, cleanup); - } - - /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). - * The returned segment has size {@code elementCount * layout().byteSize()} - */ - public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { - return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java deleted file mode 100644 index 5d9a82ff..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/gen/winusb/WinUSB.java +++ /dev/null @@ -1,139 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.windows.gen.winusb; - -import java.lang.invoke.*; -import java.lang.foreign.*; -import java.nio.ByteOrder; -import java.util.*; -import java.util.function.*; -import java.util.stream.*; - -import static java.lang.foreign.ValueLayout.*; -import static java.lang.foreign.MemoryLayout.PathElement.*; - -public class WinUSB { - - WinUSB() { - // Should not be called directly - } - - static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } - - static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("Winusb"), LIBRARY_ARENA) - .or(SymbolLookup.loaderLookup()) - .or(Linker.nativeLinker().defaultLookup()); - - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfInt C_LONG = ValueLayout.JAVA_INT; - public static final ValueLayout.OfDouble C_LONG_DOUBLE = ValueLayout.JAVA_DOUBLE; - private static final int PIPE_TRANSFER_TIMEOUT = (int)3L; - /** - * {@snippet lang=c : - * #define PIPE_TRANSFER_TIMEOUT 3 - * } - */ - public static int PIPE_TRANSFER_TIMEOUT() { - return PIPE_TRANSFER_TIMEOUT; - } - private static final int RAW_IO = (int)7L; - /** - * {@snippet lang=c : - * #define RAW_IO 7 - * } - */ - public static int RAW_IO() { - return RAW_IO; - } - - private static class WinUsb_Free { - public static final FunctionDescriptor DESC = FunctionDescriptor.of( - WinUSB.C_INT, - WinUSB.C_POINTER - ); - - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - WinUSB.findOrThrow("WinUsb_Free"), - DESC); - } - - /** - * Function descriptor for: - * {@snippet lang=c : - * BOOL WinUsb_Free(WINUSB_INTERFACE_HANDLE InterfaceHandle) - * } - */ - public static FunctionDescriptor WinUsb_Free$descriptor() { - return WinUsb_Free.DESC; - } - - /** - * Downcall method handle for: - * {@snippet lang=c : - * BOOL WinUsb_Free(WINUSB_INTERFACE_HANDLE InterfaceHandle) - * } - */ - public static MethodHandle WinUsb_Free$handle() { - return WinUsb_Free.HANDLE; - } - /** - * {@snippet lang=c : - * BOOL WinUsb_Free(WINUSB_INTERFACE_HANDLE InterfaceHandle) - * } - */ - public static int WinUsb_Free(MemorySegment InterfaceHandle) { - var mh$ = WinUsb_Free.HANDLE; - try { - if (TRACE_DOWNCALLS) { - traceDowncall("WinUsb_Free", InterfaceHandle); - } - return (int)mh$.invokeExact(InterfaceHandle); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } -} - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java deleted file mode 100644 index f1779553..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/Kernel32B.java +++ /dev/null @@ -1,110 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -package net.codecrete.usb.windows.winsdk; - -import net.codecrete.usb.windows.Win; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.Linker; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SymbolLookup; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; - -/** - * Native function calls for Kernel32. - *

- * This code is manually created to include the additional parameters for capturing - * {@code GetLastError()} until jextract catches up and can generate the corresponding code. - *

- */ -@SuppressWarnings({"OptionalGetWithoutIsPresent", "java:S100", "java:S107", "java:S117"}) -public class Kernel32B { - static { - System.loadLibrary("Kernel32"); - } - - private Kernel32B() { - } - - private static final Linker LINKER = Linker.nativeLinker(); - private static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup(); - - - private static final FunctionDescriptor CreateFileW$FUNC = FunctionDescriptor.of(ADDRESS, ADDRESS, JAVA_INT, - JAVA_INT, ADDRESS, JAVA_INT, JAVA_INT, ADDRESS); - - private static final MethodHandle CreateFileW$MH = LINKER.downcallHandle(LOOKUP.find("CreateFileW").get(), - CreateFileW$FUNC, Win.LAST_ERROR_STATE); - - public static MemorySegment CreateFileW(MemorySegment lpFileName, int dwDesiredAccess, int dwShareMode, - MemorySegment lpSecurityAttributes, int dwCreationDisposition, - int dwFlagsAndAttributes, MemorySegment hTemplateFile, - MemorySegment lastErrorState) { - try { - return (MemorySegment) CreateFileW$MH.invokeExact(lastErrorState, lpFileName, dwDesiredAccess, - dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor DeviceIoControl$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT, - ADDRESS, JAVA_INT, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); - - private static final MethodHandle DeviceIoControl$MH = LINKER.downcallHandle(LOOKUP.find("DeviceIoControl").get() - , DeviceIoControl$FUNC, Win.LAST_ERROR_STATE); - - public static int DeviceIoControl(MemorySegment hDevice, int dwIoControlCode, MemorySegment lpInBuffer, - int nInBufferSize, MemorySegment lpOutBuffer, int nOutBufferSize, - MemorySegment lpBytesReturned, MemorySegment lpOverlapped, - MemorySegment lastErrorState) { - try { - return (int) DeviceIoControl$MH.invokeExact(lastErrorState, hDevice, dwIoControlCode, lpInBuffer, - nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor GetQueuedCompletionStatus$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, - ADDRESS, ADDRESS, ADDRESS, JAVA_INT); - - private static final MethodHandle GetQueuedCompletionStatus$MH = LINKER.downcallHandle(LOOKUP.find( - "GetQueuedCompletionStatus").get(), GetQueuedCompletionStatus$FUNC, Win.LAST_ERROR_STATE); - - public static int GetQueuedCompletionStatus(MemorySegment CompletionPort, - MemorySegment lpNumberOfBytesTransferred, - MemorySegment lpCompletionKey, MemorySegment lpOverlapped, - int dwMilliseconds, MemorySegment lastErrorState) { - try { - return (int) GetQueuedCompletionStatus$MH.invokeExact(lastErrorState, CompletionPort, - lpNumberOfBytesTransferred, lpCompletionKey, lpOverlapped, dwMilliseconds); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor CreateIoCompletionPort$FUNC = FunctionDescriptor.of(ADDRESS, ADDRESS, - ADDRESS, JAVA_LONG, JAVA_INT); - - private static final MethodHandle CreateIoCompletionPort$MH = LINKER.downcallHandle(LOOKUP.find( - "CreateIoCompletionPort").get(), CreateIoCompletionPort$FUNC, Win.LAST_ERROR_STATE); - - public static MemorySegment CreateIoCompletionPort(MemorySegment FileHandle, MemorySegment ExistingCompletionPort - , long CompletionKey, int NumberOfConcurrentThreads, MemorySegment lastErrorState) { - try { - return (MemorySegment) CreateIoCompletionPort$MH.invokeExact(lastErrorState, FileHandle, - ExistingCompletionPort, CompletionKey, NumberOfConcurrentThreads); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java deleted file mode 100644 index ff9d15f8..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/SetupAPI2.java +++ /dev/null @@ -1,191 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -package net.codecrete.usb.windows.winsdk; - -import net.codecrete.usb.windows.Win; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.Linker; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SymbolLookup; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_INT; - -/** - * Native function calls for SetupAPI. - *

- * This code is manually created to include the additional parameters for capturing - * {@code GetLastError()} until jextract catches up and can generate the corresponding code. - *

- */ -@SuppressWarnings({"OptionalGetWithoutIsPresent", "java:S100", "java:S107", "java:S117"}) -public class SetupAPI2 { - private SetupAPI2() { - } - - static { - System.loadLibrary("SetupAPI"); - } - - private static final Linker LINKER = Linker.nativeLinker(); - private static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup(); - - private static final FunctionDescriptor SetupDiGetDevicePropertyW$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, - ADDRESS, ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS, JAVA_INT); - - private static final MethodHandle SetupDiGetDevicePropertyW$MH = LINKER.downcallHandle(LOOKUP.find( - "SetupDiGetDevicePropertyW").get(), SetupDiGetDevicePropertyW$FUNC, Win.LAST_ERROR_STATE); - - public static int SetupDiGetDevicePropertyW(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, - MemorySegment PropertyKey, MemorySegment PropertyType, - MemorySegment PropertyBuffer, int PropertyBufferSize, - MemorySegment RequiredSize, int Flags, MemorySegment lastErrorState) { - try { - return (int) SetupDiGetDevicePropertyW$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, - PropertyKey, PropertyType, PropertyBuffer, PropertyBufferSize, RequiredSize, Flags); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor SetupDiEnumDeviceInfo$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, - JAVA_INT, ADDRESS); - - private static final MethodHandle SetupDiEnumDeviceInfo$MH = LINKER.downcallHandle(LOOKUP.find( - "SetupDiEnumDeviceInfo").get(), SetupDiEnumDeviceInfo$FUNC, Win.LAST_ERROR_STATE); - - public static int SetupDiEnumDeviceInfo(MemorySegment DeviceInfoSet, int MemberIndex, - MemorySegment DeviceInfoData, MemorySegment lastErrorState) { - try { - return (int) SetupDiEnumDeviceInfo$MH.invokeExact(lastErrorState, DeviceInfoSet, MemberIndex, - DeviceInfoData); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor SetupDiOpenDevRegKey$FUNC = FunctionDescriptor.of(ADDRESS, ADDRESS, - ADDRESS, JAVA_INT, JAVA_INT, JAVA_INT, JAVA_INT); - - private static final MethodHandle SetupDiOpenDevRegKey$MH = LINKER.downcallHandle(LOOKUP.find( - "SetupDiOpenDevRegKey").get(), SetupDiOpenDevRegKey$FUNC, Win.LAST_ERROR_STATE); - - public static MemorySegment SetupDiOpenDevRegKey(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, - int Scope, int HwProfile, int KeyType, int samDesired, - MemorySegment lastErrorState) { - try { - return (MemorySegment) SetupDiOpenDevRegKey$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, - Scope, HwProfile, KeyType, samDesired); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor SetupDiGetClassDevsW$FUNC = FunctionDescriptor.of(ADDRESS, ADDRESS, - ADDRESS, ADDRESS, JAVA_INT); - - private static final MethodHandle SetupDiGetClassDevsW$MH = LINKER.downcallHandle(LOOKUP.find( - "SetupDiGetClassDevsW").get(), SetupDiGetClassDevsW$FUNC, Win.LAST_ERROR_STATE); - - public static MemorySegment SetupDiGetClassDevsW(MemorySegment ClassGuid, MemorySegment Enumerator, - MemorySegment hwndParent, int Flags, - MemorySegment lastErrorState) { - try { - return (MemorySegment) SetupDiGetClassDevsW$MH.invokeExact(lastErrorState, ClassGuid, Enumerator, - hwndParent, Flags); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor SetupDiEnumDeviceInterfaces$FUNC = FunctionDescriptor.of(JAVA_INT, - ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS); - - private static final MethodHandle SetupDiEnumDeviceInterfaces$MH = LINKER.downcallHandle(LOOKUP.find( - "SetupDiEnumDeviceInterfaces").get(), SetupDiEnumDeviceInterfaces$FUNC, Win.LAST_ERROR_STATE); - - public static int SetupDiEnumDeviceInterfaces(MemorySegment DeviceInfoSet, MemorySegment DeviceInfoData, - MemorySegment InterfaceClassGuid, int MemberIndex, - MemorySegment DeviceInterfaceData, MemorySegment lastErrorState) { - try { - return (int) SetupDiEnumDeviceInterfaces$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInfoData, - InterfaceClassGuid, MemberIndex, DeviceInterfaceData); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor SetupDiGetDeviceInterfaceDetailW$FUNC = FunctionDescriptor.of(JAVA_INT, - ADDRESS, ADDRESS, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); - - private static final MethodHandle SetupDiGetDeviceInterfaceDetailW$MH = LINKER.downcallHandle(LOOKUP.find( - "SetupDiGetDeviceInterfaceDetailW").get(), SetupDiGetDeviceInterfaceDetailW$FUNC, Win.LAST_ERROR_STATE); - - public static int SetupDiGetDeviceInterfaceDetailW(MemorySegment DeviceInfoSet, MemorySegment DeviceInterfaceData - , MemorySegment DeviceInterfaceDetailData, int DeviceInterfaceDetailDataSize, MemorySegment RequiredSize, - MemorySegment DeviceInfoData, MemorySegment lastErrorState) { - try { - return (int) SetupDiGetDeviceInterfaceDetailW$MH.invokeExact(lastErrorState, DeviceInfoSet, - DeviceInterfaceData, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize, RequiredSize, - DeviceInfoData); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor SetupDiCreateDeviceInfoList$FUNC = FunctionDescriptor.of(ADDRESS, ADDRESS - , ADDRESS); - - private static final MethodHandle SetupDiCreateDeviceInfoList$MH = LINKER.downcallHandle(LOOKUP.find( - "SetupDiCreateDeviceInfoList").get(), SetupDiCreateDeviceInfoList$FUNC, Win.LAST_ERROR_STATE); - - public static MemorySegment SetupDiCreateDeviceInfoList(MemorySegment ClassGuid, MemorySegment hwndParent, - MemorySegment lastErrorState) { - try { - return (MemorySegment) SetupDiCreateDeviceInfoList$MH.invokeExact(lastErrorState, ClassGuid, hwndParent); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor SetupDiOpenDeviceInfoW$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, - ADDRESS, ADDRESS, JAVA_INT, ADDRESS); - - private static final MethodHandle SetupDiOpenDeviceInfoW$MH = LINKER.downcallHandle(LOOKUP.find( - "SetupDiOpenDeviceInfoW").get(), SetupDiOpenDeviceInfoW$FUNC, Win.LAST_ERROR_STATE); - - public static int SetupDiOpenDeviceInfoW(MemorySegment DeviceInfoSet, MemorySegment DeviceInstanceId, - MemorySegment hwndParent, int OpenFlags, MemorySegment DeviceInfoData, - MemorySegment lastErrorState) { - try { - return (int) SetupDiOpenDeviceInfoW$MH.invokeExact(lastErrorState, DeviceInfoSet, DeviceInstanceId, - hwndParent, OpenFlags, DeviceInfoData); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor SetupDiOpenDeviceInterfaceW$FUNC = FunctionDescriptor.of(JAVA_INT, - ADDRESS, ADDRESS, JAVA_INT, ADDRESS); - - private static final MethodHandle SetupDiOpenDeviceInterfaceW$MH = LINKER.downcallHandle(LOOKUP.find( - "SetupDiOpenDeviceInterfaceW").get(), SetupDiOpenDeviceInterfaceW$FUNC, Win.LAST_ERROR_STATE); - - public static int SetupDiOpenDeviceInterfaceW(MemorySegment DeviceInfoSet, MemorySegment DevicePath, - int OpenFlags, MemorySegment DeviceInterfaceData, - MemorySegment lastErrorState) { - try { - return (int) SetupDiOpenDeviceInterfaceW$MH.invokeExact(lastErrorState, DeviceInfoSet, DevicePath, - OpenFlags, DeviceInterfaceData); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java deleted file mode 100644 index 3d718927..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/User32B.java +++ /dev/null @@ -1,104 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -package net.codecrete.usb.windows.winsdk; - -import net.codecrete.usb.windows.Win; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.Linker; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SymbolLookup; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_SHORT; - -/** - * Native function calls for User32. - *

- * This code is manually created to include the additional parameters for capturing - * {@code GetLastError()} until jextract catches up and can generate the corresponding code. - *

- */ -@SuppressWarnings({"OptionalGetWithoutIsPresent", "java:S100", "java:S107", "java:S117"}) -public class User32B { - - private User32B() { - } - - static { - System.loadLibrary("User32"); - } - - private static final Linker LINKER = Linker.nativeLinker(); - private static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup(); - - private static final FunctionDescriptor RegisterClassExW$FUNC = FunctionDescriptor.of(JAVA_SHORT, ADDRESS); - - private static final MethodHandle RegisterClassExW$MH = - LINKER.downcallHandle(LOOKUP.find("RegisterClassExW").get(), RegisterClassExW$FUNC, Win.LAST_ERROR_STATE); - - public static short RegisterClassExW(MemorySegment unnamedParam1, MemorySegment lastErrorState) { - try { - return (short) RegisterClassExW$MH.invokeExact(lastErrorState, unnamedParam1); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor CreateWindowExW$FUNC = FunctionDescriptor.of(ADDRESS, JAVA_INT, ADDRESS, - ADDRESS, JAVA_INT, JAVA_INT, JAVA_INT, JAVA_INT, JAVA_INT, ADDRESS, ADDRESS, ADDRESS, ADDRESS); - - private static final MethodHandle CreateWindowExW$MH = LINKER.downcallHandle(LOOKUP.find("CreateWindowExW").get() - , CreateWindowExW$FUNC, Win.LAST_ERROR_STATE); - - public static MemorySegment CreateWindowExW(int dwExStyle, MemorySegment lpClassName, MemorySegment lpWindowName, - int dwStyle, int X, int Y, int nWidth, int nHeight, - MemorySegment hWndParent, MemorySegment hMenu, - MemorySegment hInstance, MemorySegment lpParam, - MemorySegment lastErrorState) { - try { - return (MemorySegment) CreateWindowExW$MH.invokeExact(lastErrorState, dwExStyle, lpClassName, - lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor RegisterDeviceNotificationW$FUNC = FunctionDescriptor.of(ADDRESS, ADDRESS - , ADDRESS, JAVA_INT); - - private static final MethodHandle RegisterDeviceNotificationW$MH = LINKER.downcallHandle(LOOKUP.find( - "RegisterDeviceNotificationW").get(), RegisterDeviceNotificationW$FUNC, Win.LAST_ERROR_STATE); - - public static MemorySegment RegisterDeviceNotificationW(MemorySegment hRecipient, - MemorySegment NotificationFilter, int Flags, - MemorySegment lastErrorState) { - try { - return (MemorySegment) RegisterDeviceNotificationW$MH.invokeExact(lastErrorState, hRecipient, - NotificationFilter, Flags); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor GetMessageW$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, - JAVA_INT, JAVA_INT); - - private static final MethodHandle GetMessageW$MH = LINKER.downcallHandle(LOOKUP.find("GetMessageW").get(), - GetMessageW$FUNC, Win.LAST_ERROR_STATE); - - public static int GetMessageW(MemorySegment lpMsg, MemorySegment hWnd, int wMsgFilterMin, int wMsgFilterMax, - MemorySegment lastErrorState) { - try { - return (int) GetMessageW$MH.invokeExact(lastErrorState, lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } -} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java deleted file mode 100644 index f8d6cd8b..00000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/winsdk/WinUSB2.java +++ /dev/null @@ -1,178 +0,0 @@ -// -// Java Does USB -// Copyright (c) 2022 Manuel Bleichenbacher -// Licensed under MIT License -// https://opensource.org/licenses/MIT -// -package net.codecrete.usb.windows.winsdk; - -import net.codecrete.usb.usbstandard.SetupPacket; -import net.codecrete.usb.windows.Win; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.Linker; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SymbolLookup; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static java.lang.foreign.ValueLayout.JAVA_INT; - -/** - * Native function calls for WinUSB. - *

- * This code is manually created to include the additional parameters for capturing - * {@code GetLastError()} until jextract catches up and can generate the corresponding code. - *

- */ -@SuppressWarnings({"OptionalGetWithoutIsPresent", "java:S100", "java:S107", "java:S117"}) -public class WinUSB2 { - private WinUSB2() { - } - - static { - System.loadLibrary("Winusb"); - } - - private static final Linker LINKER = Linker.nativeLinker(); - private static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup(); - - - private static final FunctionDescriptor WinUsb_Initialize$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS); - - private static final MethodHandle WinUsb_Initialize$MH = - LINKER.downcallHandle(LOOKUP.find("WinUsb_Initialize").get(), WinUsb_Initialize$FUNC, Win.LAST_ERROR_STATE); - - public static int WinUsb_Initialize(MemorySegment DeviceHandle, MemorySegment InterfaceHandle, - MemorySegment lastErrorState) { - try { - return (int) WinUsb_Initialize$MH.invokeExact(lastErrorState, DeviceHandle, InterfaceHandle); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor WinUsb_GetAssociatedInterface$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE, ADDRESS); - - private static final MethodHandle WinUsb_GetAssociatedInterface$MH = - LINKER.downcallHandle(LOOKUP.find("WinUsb_GetAssociatedInterface").get(), WinUsb_GetAssociatedInterface$FUNC, Win.LAST_ERROR_STATE); - - public static int WinUsb_GetAssociatedInterface(MemorySegment InterfaceHandle, byte AssociatedInterfaceIndex, - MemorySegment AssociatedInterfaceHandle, MemorySegment lastErrorState) { - try { - return (int) WinUsb_GetAssociatedInterface$MH.invokeExact(lastErrorState, InterfaceHandle, AssociatedInterfaceIndex, AssociatedInterfaceHandle); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor WinUsb_SetCurrentAlternateSetting$FUNC = FunctionDescriptor.of(JAVA_INT, - ADDRESS, JAVA_BYTE); - - private static final MethodHandle WinUsb_SetCurrentAlternateSetting$MH = LINKER.downcallHandle(LOOKUP.find( - "WinUsb_SetCurrentAlternateSetting").get(), WinUsb_SetCurrentAlternateSetting$FUNC, Win.LAST_ERROR_STATE); - - public static int WinUsb_SetCurrentAlternateSetting(MemorySegment InterfaceHandle, byte SettingNumber, - MemorySegment lastErrorState) { - try { - return (int) WinUsb_SetCurrentAlternateSetting$MH.invokeExact(lastErrorState, InterfaceHandle, - SettingNumber); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor WinUsb_ControlTransfer$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, - SetupPacket.LAYOUT, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); - - private static final MethodHandle WinUsb_ControlTransfer$MH = LINKER.downcallHandle(LOOKUP.find( - "WinUsb_ControlTransfer").get(), WinUsb_ControlTransfer$FUNC, Win.LAST_ERROR_STATE); - - public static int WinUsb_ControlTransfer(MemorySegment InterfaceHandle, MemorySegment SetupPacket, - MemorySegment Buffer, int BufferLength, MemorySegment LengthTransferred, - MemorySegment Overlapped, MemorySegment lastErrorState) { - try { - return (int) WinUsb_ControlTransfer$MH.invokeExact(lastErrorState, InterfaceHandle, SetupPacket, Buffer, - BufferLength, LengthTransferred, Overlapped); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor WinUsb_SetPipePolicy$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, - JAVA_BYTE, JAVA_INT, JAVA_INT, ADDRESS); - - private static final MethodHandle WinUsb_SetPipePolicy$MH = LINKER.downcallHandle(LOOKUP.find( - "WinUsb_SetPipePolicy").get(), WinUsb_SetPipePolicy$FUNC, Win.LAST_ERROR_STATE); - - public static int WinUsb_SetPipePolicy(MemorySegment InterfaceHandle, byte PipeID, int PolicyType, - int ValueLength, MemorySegment Value, MemorySegment lastErrorState) { - try { - return (int) WinUsb_SetPipePolicy$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID, PolicyType, - ValueLength, Value); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor WinUsb_WritePipe$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, - JAVA_BYTE, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); - - private static final MethodHandle WinUsb_WritePipe$MH = - LINKER.downcallHandle(LOOKUP.find("WinUsb_WritePipe").get(), WinUsb_WritePipe$FUNC, Win.LAST_ERROR_STATE); - - public static int WinUsb_WritePipe(MemorySegment InterfaceHandle, byte PipeID, MemorySegment Buffer, - int BufferLength, MemorySegment LengthTransferred, MemorySegment Overlapped, - MemorySegment lastErrorState) { - try { - return (int) WinUsb_WritePipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID, Buffer, - BufferLength, LengthTransferred, Overlapped); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor WinUsb_ReadPipe$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE - , ADDRESS, JAVA_INT, ADDRESS, ADDRESS); - - private static final MethodHandle WinUsb_ReadPipe$MH = LINKER.downcallHandle(LOOKUP.find("WinUsb_ReadPipe").get() - , WinUsb_ReadPipe$FUNC, Win.LAST_ERROR_STATE); - - public static int WinUsb_ReadPipe(MemorySegment InterfaceHandle, byte PipeID, MemorySegment Buffer, - int BufferLength, MemorySegment LengthTransferred, MemorySegment Overlapped, - MemorySegment lastErrorState) { - try { - return (int) WinUsb_ReadPipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID, Buffer, BufferLength - , LengthTransferred, Overlapped); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor WinUsb_ResetPipe$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE); - - private static final MethodHandle WinUsb_ResetPipe$MH = - LINKER.downcallHandle(LOOKUP.find("WinUsb_ResetPipe").get(), WinUsb_ResetPipe$FUNC, Win.LAST_ERROR_STATE); - - public static int WinUsb_ResetPipe(MemorySegment InterfaceHandle, byte PipeID, MemorySegment lastErrorState) { - try { - return (int) WinUsb_ResetPipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - private static final FunctionDescriptor WinUsb_AbortPipe$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_BYTE); - - private static final MethodHandle WinUsb_AbortPipe$MH = - LINKER.downcallHandle(LOOKUP.find("WinUsb_AbortPipe").get(), WinUsb_AbortPipe$FUNC, Win.LAST_ERROR_STATE); - - public static int WinUsb_AbortPipe(MemorySegment InterfaceHandle, byte PipeID, MemorySegment lastErrorState) { - try { - return (int) WinUsb_AbortPipe$MH.invokeExact(lastErrorState, InterfaceHandle, PipeID); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } -} diff --git a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java index e268725c..11f53b2a 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/AlternateInterfaceTest.java @@ -43,8 +43,8 @@ void selectAlternateIntf_succeeds() { void selectInvalidAlternateIntf_fails() { assertThrows(UsbException.class, () -> testDevice.selectAlternateSetting(1, 0)); - var interface_number = config.interfaceNumber(); - assertThrows(UsbException.class, () -> testDevice.selectAlternateSetting(interface_number, 2)); + var interfaceNumber = config.interfaceNumber(); + assertThrows(UsbException.class, () -> testDevice.selectAlternateSetting(interfaceNumber, 2)); } @Test @@ -62,7 +62,7 @@ void transferOnInvalidEndpoint_fails() { testDevice.selectAlternateSetting(config.interfaceNumber(), 1); var endpointOut = config.endpointEchoOut(); - assertThrows(UsbException.class, () -> testDevice.transferOut(endpointOut, new byte[] { 1, 2, 3 })); + assertThrows(UsbException.class, () -> testDevice.transferOut(endpointOut, new byte[]{1, 2, 3})); var endpointIn = config.endpointEchoIn(); assertThrows(UsbException.class, () -> testDevice.transferIn(endpointIn)); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java index 582fca20..1323b380 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/BulkTransferTest.java @@ -73,6 +73,7 @@ static void writeBytes(byte[] data) { numBytes += size; } } + static byte[] readBytes(int numBytes) { var buffer = new ByteArrayOutputStream(); var bytesRead = 0; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java b/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java deleted file mode 100644 index 2117df2a..00000000 --- a/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationParserTest.java +++ /dev/null @@ -1,260 +0,0 @@ -package net.codecrete.usb; - -import net.codecrete.usb.common.ConfigurationParser; -import org.assertj.core.api.SoftAssertions; -import org.junit.jupiter.api.Test; - -import java.lang.foreign.MemorySegment; - -import static net.codecrete.usb.ConfigurationDescriptors.COMPOSITE_LARGE; -import static net.codecrete.usb.ConfigurationDescriptors.COMPOSITE_TEST_DEVICE; -import static net.codecrete.usb.ConfigurationDescriptors.SIMPLE; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -class ConfigurationParserTest { - - @Test - void simpleDescriptor_canBeParsed() { - - var configuration = ConfigurationParser.parseConfigurationDescriptor(MemorySegment.ofArray(SIMPLE)); - - var softly = new SoftAssertions(); - softly.assertThat(configuration.interfaces()) - .hasSize(1) - .singleElement().satisfies(intf -> { - softly.assertThat(intf.getNumber()).isEqualTo(0); - softly.assertThat(intf.getAlternates()) - .hasSize(1) - .singleElement().satisfies(altIntf -> { - softly.assertThat(altIntf).isSameAs(intf.getCurrentAlternate()); - softly.assertThat(altIntf.getNumber()).isEqualTo(0); - softly.assertThat(altIntf.getEndpoints()).isEmpty(); - softly.assertThat(altIntf.getClassCode()).isEqualTo(0x0ff); - softly.assertThat(altIntf.getSubclassCode()).isEqualTo(0x0dd); - softly.assertThat(altIntf.getProtocolCode()).isEqualTo(0x0cc); - }); - softly.assertThat(intf.isClaimed()).isFalse(); - }); - softly.assertThat(configuration.functions()).hasSize(1); - softly.assertThat(configuration.configValue()).isEqualTo(1); - softly.assertThat(configuration.attributes()).isEqualTo(0x34); - softly.assertThat(configuration.maxPower()).isEqualTo(0x64); - softly.assertAll(); - } - - @Test - @SuppressWarnings("java:S5961") - void largeCompositeDescriptor_canBeParsed() { - var configuration = ConfigurationParser.parseConfigurationDescriptor(MemorySegment.ofArray(COMPOSITE_LARGE)); - - var softly = new SoftAssertions(); - - // 2 functions - softly.assertThat(configuration.functions()) - .hasSize(2); - - // function 0: 3 interfaces - softly.assertThat(configuration.functions().get(0)).satisfies(function -> { - softly.assertThat(function.firstInterfaceNumber()).isEqualTo(0); - softly.assertThat(function.numInterfaces()).isEqualTo(3); - }); - - // function 1: 1 interface - softly.assertThat(configuration.functions().get(1)).satisfies(function -> { - softly.assertThat(function.firstInterfaceNumber()).isEqualTo(3); - softly.assertThat(function.numInterfaces()).isEqualTo(1); - }); - - softly.assertThat(configuration.interfaces()).hasSize(4); - - // interface 0 - softly.assertThat(configuration.interfaces().get(0)).satisfies(intf -> { - softly.assertThat(intf.getNumber()).isEqualTo(0); - softly.assertThat(intf.getAlternates()).hasSize(1); - softly.assertThat(intf.getCurrentAlternate().getEndpoints()).hasSize(1); - softly.assertThat(intf.getCurrentAlternate().getEndpoints().getFirst()).satisfies(endpoint -> { - softly.assertThat(endpoint.getNumber()).isEqualTo(5); - softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); - softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.INTERRUPT); - }); - }); - - // interface 1 - softly.assertThat(configuration.interfaces().get(1)).satisfies(intf -> { - softly.assertThat(intf.getNumber()).isEqualTo(1); - softly.assertThat(intf.getAlternates()).hasSize(2); - softly.assertThat(intf.getAlternates().get(0)).satisfies(alternate -> { - softly.assertThat(alternate.getNumber()).isEqualTo(0); - softly.assertThat(alternate.getEndpoints()).isEmpty(); - }); - softly.assertThat(intf.getAlternates().get(1)).satisfies(alternate -> { - softly.assertThat(alternate.getNumber()).isEqualTo(1); - softly.assertThat(alternate.getEndpoints()).hasSize(1); - softly.assertThat(alternate.getEndpoints().getFirst()).satisfies(endpoint -> { - softly.assertThat(endpoint.getNumber()).isEqualTo(1); - softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); - softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.ISOCHRONOUS); - }); - }); - }); - - // interface 2 - softly.assertThat(configuration.interfaces().get(2)).satisfies(intf -> { - softly.assertThat(intf.getNumber()).isEqualTo(2); - softly.assertThat(intf.getAlternates()).hasSize(2); - softly.assertThat(intf.getAlternates().get(0)).satisfies(alternate -> { - softly.assertThat(alternate.getNumber()).isEqualTo(0); - softly.assertThat(alternate.getEndpoints()).isEmpty(); - }); - softly.assertThat(intf.getAlternates().get(1)).satisfies(alternate -> { - softly.assertThat(alternate.getNumber()).isEqualTo(1); - softly.assertThat(alternate.getEndpoints()).hasSize(1); - softly.assertThat(alternate.getEndpoints().getFirst()).satisfies(endpoint -> { - softly.assertThat(endpoint.getNumber()).isEqualTo(2); - softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); - softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.ISOCHRONOUS); - }); - }); - }); - - // interface 3 - softly.assertThat(configuration.interfaces().get(3)).satisfies(intf -> { - softly.assertThat(intf.getNumber()).isEqualTo(3); - softly.assertThat(intf.getAlternates()).hasSize(1); - softly.assertThat(intf.getAlternates().getFirst()).satisfies(alternate -> { - softly.assertThat(alternate.getNumber()).isEqualTo(0); - softly.assertThat(alternate.getEndpoints()).hasSize(1); - softly.assertThat(alternate.getEndpoints().getFirst()).satisfies(endpoint -> { - softly.assertThat(endpoint.getNumber()).isEqualTo(4); - softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); - softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.INTERRUPT); - }); - }); - }); - - softly.assertAll(); - } - - - @Test - @SuppressWarnings("java:S5961") - void compositeTestDeviceDescriptor_canBeParsed() { - var configuration = ConfigurationParser.parseConfigurationDescriptor(MemorySegment.ofArray(COMPOSITE_TEST_DEVICE)); - - var softly = new SoftAssertions(); - - // 2 functions - softly.assertThat(configuration.functions()) - .hasSize(2); - - // function 0: 2 interfaces - softly.assertThat(configuration.functions().get(0)).satisfies(function -> { - softly.assertThat(function.firstInterfaceNumber()).isEqualTo(0); - softly.assertThat(function.numInterfaces()).isEqualTo(2); - }); - - // function 1: 2 interfaces - softly.assertThat(configuration.functions().get(1)).satisfies(function -> { - softly.assertThat(function.firstInterfaceNumber()).isEqualTo(2); - softly.assertThat(function.numInterfaces()).isEqualTo(2); - }); - - softly.assertThat(configuration.interfaces()).hasSize(4); - - // interface 0 - softly.assertThat(configuration.interfaces().get(0)).satisfies(intf -> { - softly.assertThat(intf.getNumber()).isEqualTo(0); - softly.assertThat(intf.getAlternates()).hasSize(1); - softly.assertThat(intf.getCurrentAlternate().getEndpoints()).hasSize(1); - softly.assertThat(intf.getCurrentAlternate().getEndpoints().getFirst()).satisfies(endpoint -> { - softly.assertThat(endpoint.getNumber()).isEqualTo(3); - softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); - softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.INTERRUPT); - }); - }); - - // interface 1 - softly.assertThat(configuration.interfaces().get(1)).satisfies(intf -> { - softly.assertThat(intf.getNumber()).isEqualTo(1); - softly.assertThat(intf.getAlternates()).hasSize(1); - softly.assertThat(intf.getAlternates().getFirst()).satisfies(alternate -> { - softly.assertThat(alternate.getNumber()).isEqualTo(0); - softly.assertThat(alternate.getEndpoints()).hasSize(2); - softly.assertThat(alternate.getEndpoints().get(0)).satisfies(endpoint -> { - softly.assertThat(endpoint.getNumber()).isEqualTo(2); - softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.OUT); - softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.BULK); - }); - softly.assertThat(alternate.getEndpoints().get(1)).satisfies(endpoint -> { - softly.assertThat(endpoint.getNumber()).isEqualTo(1); - softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); - softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.BULK); - }); - }); - }); - - // interface 2 - softly.assertThat(configuration.interfaces().get(2)).satisfies(intf -> { - softly.assertThat(intf.getNumber()).isEqualTo(2); - softly.assertThat(intf.getAlternates()).hasSize(1); - softly.assertThat(intf.getAlternates().getFirst()).satisfies(alternate -> { - softly.assertThat(alternate.getNumber()).isEqualTo(0); - softly.assertThat(alternate.getEndpoints()).isEmpty(); - }); - }); - - // interface 3 - softly.assertThat(configuration.interfaces().get(3)).satisfies(intf -> { - softly.assertThat(intf.getNumber()).isEqualTo(3); - softly.assertThat(intf.getAlternates()).hasSize(1); - softly.assertThat(intf.getAlternates().getFirst()).satisfies(alternate -> { - softly.assertThat(alternate.getNumber()).isEqualTo(0); - softly.assertThat(alternate.getEndpoints()).hasSize(2); - softly.assertThat(alternate.getEndpoints().get(0)).satisfies(endpoint -> { - softly.assertThat(endpoint.getNumber()).isEqualTo(1); - softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.OUT); - softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.BULK); - }); - softly.assertThat(alternate.getEndpoints().get(1)).satisfies(endpoint -> { - softly.assertThat(endpoint.getNumber()).isEqualTo(2); - softly.assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); - softly.assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.BULK); - }); - }); - }); - - softly.assertAll(); - } - - @Test - void tooShortDescriptor_throwsException() { - var desc = new byte[COMPOSITE_LARGE.length - 1]; - System.arraycopy(COMPOSITE_LARGE, 0, desc, 0, desc.length); - var segment = MemorySegment.ofArray(desc); - - assertThatThrownBy(() -> ConfigurationParser.parseConfigurationDescriptor(segment)) - .isInstanceOf(UsbException.class) - .hasMessage("invalid USB configuration descriptor (invalid length)"); - } - - @Test - void tooLongDescriptor_throwsException() { - var desc = new byte[COMPOSITE_LARGE.length + 1]; - System.arraycopy(COMPOSITE_LARGE, 0, desc, 0, COMPOSITE_LARGE.length); - var segment = MemorySegment.ofArray(desc); - - assertThatThrownBy(() -> ConfigurationParser.parseConfigurationDescriptor(segment)) - .isInstanceOf(UsbException.class) - .hasMessage("invalid USB configuration descriptor (invalid length)"); - } - - @Test - void invalidDescriptor_throwsException() { - var desc = new byte[] { 0x5a, 0x41, 0x03, 0x07 }; - var segment = MemorySegment.ofArray(desc); - - assertThatThrownBy(() -> ConfigurationParser.parseConfigurationDescriptor(segment)) - .isInstanceOf(UsbException.class) - .hasMessage("invalid USB configuration descriptor"); - } -} diff --git a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java index 014f4cb9..4cc8634f 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/InvalidOperationTest.java @@ -33,7 +33,7 @@ void releaseInvalidInterface_throws() { @Test void invalidEndpoint_throws() { - var data = new byte[] { 34, 23, 99, 0, 17 }; + var data = new byte[]{34, 23, 99, 0, 17}; Assertions.assertThrows(UsbException.class, () -> testDevice.transferOut(2, data)); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java index 1733b586..0c3b68c2 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/SpeedTest.java @@ -50,9 +50,10 @@ static void writeBytes(byte[] data) { throw new RuntimeException(e); } } + static byte[] readBytes(int numBytes) { try (var is = testDevice.openInputStream(config.endpointLoopbackIn())) { - var buffer = new byte[numBytes]; + var buffer = new byte[numBytes]; var bytesRead = 0; while (bytesRead < numBytes) { var n = is.read(buffer, bytesRead, numBytes - bytesRead); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java index 1fd63748..e79903b8 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StallTest.java @@ -22,7 +22,7 @@ void stalledBulkTransferOut_recovers() { var endpointOut = config.endpointLoopbackOut(); haltEndpoint(UsbDirection.OUT, endpointOut); - var data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + var data = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; assertThrows(UsbStallException.class, () -> testDevice.transferOut(endpointOut, data)); testDevice.clearHalt(UsbDirection.OUT, endpointOut); @@ -42,7 +42,7 @@ void stalledBulkTransferIn_recovers() { testDevice.clearHalt(UsbDirection.IN, endpointIn); - var data = new byte[] { 9, 8, 7, 6, 5, 4, 3, 2 }; + var data = new byte[]{9, 8, 7, 6, 5, 4, 3, 2}; testDevice.transferOut(endpointOut, data); var receivedData = testDevice.transferIn(endpointIn); assertArrayEquals(data, receivedData); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java index c6e0da3e..adb6652a 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java @@ -22,7 +22,7 @@ class StreamTest extends TestDeviceBase { @Test void smallTransfer_succeeds() { - var sampleData = generateRandomBytes(12, 293872394); + var sampleData = generateRandomBytes(12, 293872394); writeBytes(sampleData, 100); var data = readBytes(sampleData.length); assertArrayEquals(sampleData, data); @@ -34,7 +34,7 @@ void mediumTransfer_succeeds() { // has an internal buffer of about 500 bytes. var sampleData = generateRandomBytes(140, 97333894); writeBytes(sampleData, 30); - var data = readBytes(sampleData.length); + var data = readBytes(sampleData.length); assertArrayEquals(sampleData, data); } @@ -89,6 +89,7 @@ static void writeBytes(byte[] data, int chunkSize) { throw new RuntimeException(e); } } + static byte[] readBytes(int numBytes) { var buffer = new byte[numBytes]; try (var is = testDevice.openInputStream(config.endpointLoopbackIn())) { @@ -109,7 +110,7 @@ static byte[] readBytes(int numBytes) { private static void sleep(int millis) { try { Thread.sleep(millis); - } catch (InterruptedException e) { + } catch (InterruptedException _) { Thread.currentThread().interrupt(); } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java index 9fff5237..c0a35a0f 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TestDeviceBase.java @@ -86,8 +86,8 @@ static void resetBuffers() { static void drainData(int endpointNumber) { while (true) { try { - testDevice.transferIn(endpointNumber, 2); - } catch (UsbTimeoutException e) { + testDevice.transferIn(endpointNumber, 5); + } catch (UsbTimeoutException _) { break; } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java index 80f19b23..7f5f1cdd 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/TimeoutTest.java @@ -18,7 +18,6 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -@SuppressWarnings("DefaultAnnotationParam") class TimeoutTest extends TestDeviceBase { @Test @@ -41,6 +40,7 @@ void bulkTransfer_doesNotTimeOut() { @Test @Timeout(value = 1, unit = TimeUnit.SECONDS) void bulkTransferOut_timesOut() { + drainData(config.endpointLoopbackIn()); var endpointOut = config.endpointLoopbackOut(); // The test device has an internal buffer of about 2KB for full-speed diff --git a/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationDescriptors.java b/java-does-usb/src/test/java/net/codecrete/usb/common/ConfigurationDescriptors.java similarity index 99% rename from java-does-usb/src/test/java/net/codecrete/usb/ConfigurationDescriptors.java rename to java-does-usb/src/test/java/net/codecrete/usb/common/ConfigurationDescriptors.java index 7a2ae7c9..9d98afc9 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/ConfigurationDescriptors.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/common/ConfigurationDescriptors.java @@ -1,4 +1,4 @@ -package net.codecrete.usb; +package net.codecrete.usb.common; class ConfigurationDescriptors { @@ -119,7 +119,7 @@ class ConfigurationDescriptors { 0x0E, // bInterfaceClass = 0x0E (Video) 0x02, // bInterfaceSubClass = 0x02 (Video Streaming) 0x00, // bInterfaceProtocol = 0x00 (Undefined) - 0x00, // iInterface (sstring index) + 0x00, // iInterface (string index) 0x10, // bLength = 16 0x24, // bDescriptorType = 0x24 (CS_INTERFACE) diff --git a/java-does-usb/src/test/java/net/codecrete/usb/common/ConfigurationParserTest.java b/java-does-usb/src/test/java/net/codecrete/usb/common/ConfigurationParserTest.java new file mode 100644 index 00000000..f9a65e25 --- /dev/null +++ b/java-does-usb/src/test/java/net/codecrete/usb/common/ConfigurationParserTest.java @@ -0,0 +1,252 @@ +package net.codecrete.usb.common; + +import net.codecrete.usb.UsbDirection; +import net.codecrete.usb.UsbException; +import net.codecrete.usb.UsbTransferType; +import org.junit.jupiter.api.Test; + +import java.lang.foreign.MemorySegment; + +import static net.codecrete.usb.common.ConfigurationDescriptors.COMPOSITE_LARGE; +import static net.codecrete.usb.common.ConfigurationDescriptors.COMPOSITE_TEST_DEVICE; +import static net.codecrete.usb.common.ConfigurationDescriptors.SIMPLE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class ConfigurationParserTest { + + @Test + void simpleDescriptor_canBeParsed() { + + var configuration = ConfigurationParser.parseConfigurationDescriptor(MemorySegment.ofArray(SIMPLE)); + + assertThat(configuration.interfaces()) + .hasSize(1) + .singleElement().satisfies(intf -> { + assertThat(intf.getNumber()).isZero(); + assertThat(intf.getAlternates()) + .hasSize(1) + .singleElement().satisfies(altIntf -> { + assertThat(altIntf).isSameAs(intf.getCurrentAlternate()); + assertThat(altIntf.getNumber()).isZero(); + assertThat(altIntf.getEndpoints()).isEmpty(); + assertThat(altIntf.getClassCode()).isEqualTo(0x0ff); + assertThat(altIntf.getSubclassCode()).isEqualTo(0x0dd); + assertThat(altIntf.getProtocolCode()).isEqualTo(0x0cc); + }); + assertThat(intf.isClaimed()).isFalse(); + }); + assertThat(configuration.functions()).hasSize(1); + assertThat(configuration.configValue()).isEqualTo(1); + assertThat(configuration.attributes()).isEqualTo(0x34); + assertThat(configuration.maxPower()).isEqualTo(0x64); + } + + @Test + @SuppressWarnings("java:S5961") + void largeCompositeDescriptor_canBeParsed() { + var configuration = ConfigurationParser.parseConfigurationDescriptor(MemorySegment.ofArray(COMPOSITE_LARGE)); + + // 2 functions + assertThat(configuration.functions()) + .hasSize(2); + + // function 0: 3 interfaces + assertThat(configuration.functions().get(0)).satisfies(function -> { + assertThat(function.firstInterfaceNumber()).isZero(); + assertThat(function.numInterfaces()).isEqualTo(3); + }); + + // function 1: 1 interface + assertThat(configuration.functions().get(1)).satisfies(function -> { + assertThat(function.firstInterfaceNumber()).isEqualTo(3); + assertThat(function.numInterfaces()).isEqualTo(1); + }); + + assertThat(configuration.interfaces()).hasSize(4); + + // interface 0 + assertThat(configuration.interfaces().get(0)).satisfies(intf -> { + assertThat(intf.getNumber()).isZero(); + assertThat(intf.getAlternates()).hasSize(1); + assertThat(intf.getCurrentAlternate().getEndpoints()).hasSize(1); + assertThat(intf.getCurrentAlternate().getEndpoints().getFirst()).satisfies(endpoint -> { + assertThat(endpoint.getNumber()).isEqualTo(5); + assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); + assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.INTERRUPT); + }); + }); + + // interface 1 + assertThat(configuration.interfaces().get(1)).satisfies(intf -> { + assertThat(intf.getNumber()).isEqualTo(1); + assertThat(intf.getAlternates()).hasSize(2); + assertThat(intf.getAlternates().get(0)).satisfies(alternate -> { + assertThat(alternate.getNumber()).isZero(); + assertThat(alternate.getEndpoints()).isEmpty(); + }); + assertThat(intf.getAlternates().get(1)).satisfies(alternate -> { + assertThat(alternate.getNumber()).isEqualTo(1); + assertThat(alternate.getEndpoints()).hasSize(1); + assertThat(alternate.getEndpoints().getFirst()).satisfies(endpoint -> { + assertThat(endpoint.getNumber()).isEqualTo(1); + assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); + assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.ISOCHRONOUS); + }); + }); + }); + + // interface 2 + assertThat(configuration.interfaces().get(2)).satisfies(intf -> { + assertThat(intf.getNumber()).isEqualTo(2); + assertThat(intf.getAlternates()).hasSize(2); + assertThat(intf.getAlternates().get(0)).satisfies(alternate -> { + assertThat(alternate.getNumber()).isZero(); + assertThat(alternate.getEndpoints()).isEmpty(); + }); + assertThat(intf.getAlternates().get(1)).satisfies(alternate -> { + assertThat(alternate.getNumber()).isEqualTo(1); + assertThat(alternate.getEndpoints()).hasSize(1); + assertThat(alternate.getEndpoints().getFirst()).satisfies(endpoint -> { + assertThat(endpoint.getNumber()).isEqualTo(2); + assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); + assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.ISOCHRONOUS); + }); + }); + }); + + // interface 3 + assertThat(configuration.interfaces().get(3)).satisfies(intf -> { + assertThat(intf.getNumber()).isEqualTo(3); + assertThat(intf.getAlternates()).hasSize(1); + assertThat(intf.getAlternates().getFirst()).satisfies(alternate -> { + assertThat(alternate.getNumber()).isZero(); + assertThat(alternate.getEndpoints()).hasSize(1); + assertThat(alternate.getEndpoints().getFirst()).satisfies(endpoint -> { + assertThat(endpoint.getNumber()).isEqualTo(4); + assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); + assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.INTERRUPT); + }); + }); + }); + } + + + @Test + @SuppressWarnings("java:S5961") + void compositeTestDeviceDescriptor_canBeParsed() { + var configuration = ConfigurationParser.parseConfigurationDescriptor(MemorySegment.ofArray(COMPOSITE_TEST_DEVICE)); + + // 2 functions + assertThat(configuration.functions()) + .hasSize(2); + + // function 0: 2 interfaces + assertThat(configuration.functions().get(0)).satisfies(function -> { + assertThat(function.firstInterfaceNumber()).isZero(); + assertThat(function.numInterfaces()).isEqualTo(2); + }); + + // function 1: 2 interfaces + assertThat(configuration.functions().get(1)).satisfies(function -> { + assertThat(function.firstInterfaceNumber()).isEqualTo(2); + assertThat(function.numInterfaces()).isEqualTo(2); + }); + + assertThat(configuration.interfaces()).hasSize(4); + + // interface 0 + assertThat(configuration.interfaces().get(0)).satisfies(intf -> { + assertThat(intf.getNumber()).isZero(); + assertThat(intf.getAlternates()).hasSize(1); + assertThat(intf.getCurrentAlternate().getEndpoints()).hasSize(1); + assertThat(intf.getCurrentAlternate().getEndpoints().getFirst()).satisfies(endpoint -> { + assertThat(endpoint.getNumber()).isEqualTo(3); + assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); + assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.INTERRUPT); + }); + }); + + // interface 1 + assertThat(configuration.interfaces().get(1)).satisfies(intf -> { + assertThat(intf.getNumber()).isEqualTo(1); + assertThat(intf.getAlternates()).hasSize(1); + assertThat(intf.getAlternates().getFirst()).satisfies(alternate -> { + assertThat(alternate.getNumber()).isZero(); + assertThat(alternate.getEndpoints()).hasSize(2); + assertThat(alternate.getEndpoints().get(0)).satisfies(endpoint -> { + assertThat(endpoint.getNumber()).isEqualTo(2); + assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.OUT); + assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.BULK); + }); + assertThat(alternate.getEndpoints().get(1)).satisfies(endpoint -> { + assertThat(endpoint.getNumber()).isEqualTo(1); + assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); + assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.BULK); + }); + }); + }); + + // interface 2 + assertThat(configuration.interfaces().get(2)).satisfies(intf -> { + assertThat(intf.getNumber()).isEqualTo(2); + assertThat(intf.getAlternates()).hasSize(1); + assertThat(intf.getAlternates().getFirst()).satisfies(alternate -> { + assertThat(alternate.getNumber()).isZero(); + assertThat(alternate.getEndpoints()).isEmpty(); + }); + }); + + // interface 3 + assertThat(configuration.interfaces().get(3)).satisfies(intf -> { + assertThat(intf.getNumber()).isEqualTo(3); + assertThat(intf.getAlternates()).hasSize(1); + assertThat(intf.getAlternates().getFirst()).satisfies(alternate -> { + assertThat(alternate.getNumber()).isZero(); + assertThat(alternate.getEndpoints()).hasSize(2); + assertThat(alternate.getEndpoints().get(0)).satisfies(endpoint -> { + assertThat(endpoint.getNumber()).isEqualTo(1); + assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.OUT); + assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.BULK); + }); + assertThat(alternate.getEndpoints().get(1)).satisfies(endpoint -> { + assertThat(endpoint.getNumber()).isEqualTo(2); + assertThat(endpoint.getDirection()).isEqualTo(UsbDirection.IN); + assertThat(endpoint.getTransferType()).isEqualTo(UsbTransferType.BULK); + }); + }); + }); + } + + @Test + void tooShortDescriptor_throwsException() { + var desc = new byte[COMPOSITE_LARGE.length - 1]; + System.arraycopy(COMPOSITE_LARGE, 0, desc, 0, desc.length); + var segment = MemorySegment.ofArray(desc); + + assertThatThrownBy(() -> ConfigurationParser.parseConfigurationDescriptor(segment)) + .isInstanceOf(UsbException.class) + .hasMessage("invalid USB configuration descriptor (invalid length)"); + } + + @Test + void tooLongDescriptor_throwsException() { + var desc = new byte[COMPOSITE_LARGE.length + 1]; + System.arraycopy(COMPOSITE_LARGE, 0, desc, 0, COMPOSITE_LARGE.length); + var segment = MemorySegment.ofArray(desc); + + assertThatThrownBy(() -> ConfigurationParser.parseConfigurationDescriptor(segment)) + .isInstanceOf(UsbException.class) + .hasMessage("invalid USB configuration descriptor (invalid length)"); + } + + @Test + void invalidDescriptor_throwsException() { + var desc = new byte[]{0x5a, 0x41, 0x03, 0x07}; + var segment = MemorySegment.ofArray(desc); + + assertThatThrownBy(() -> ConfigurationParser.parseConfigurationDescriptor(segment)) + .isInstanceOf(UsbException.class) + .hasMessage("invalid USB configuration descriptor"); + } +} diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/Continuous.java b/java-does-usb/src/test/java/net/codecrete/usb/special/Continuous.java index d9c6ad44..c432972b 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/Continuous.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/Continuous.java @@ -39,9 +39,9 @@ private static void sendData(UsbDevice device) { try { device.transferOut(1, buffer); Thread.sleep(3000); - } catch (UsbException e) { + } catch (UsbException _) { return; - } catch (InterruptedException e) { + } catch (InterruptedException _) { Thread.currentThread().interrupt(); } } @@ -52,8 +52,8 @@ private static void readData(UsbDevice device) { while (true) { try { var packet = device.transferIn(2); - System.out.printf("%s packet of %d bytes received\n", LocalDateTime.now().format(formatter), packet.length); - } catch (UsbException e) { + System.out.printf("%s packet of %d bytes received%n", LocalDateTime.now().format(formatter), packet.length); + } catch (UsbException _) { return; } } diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java b/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java index 12b9b6ed..006f6693 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/LogicAnalyzer.java @@ -52,12 +52,12 @@ public class LogicAnalyzer implements Closeable { /// USB vendor ID - final static int VID = 0x0925; + static final int VID = 0x0925; /// USB product ID - final static int PID = 0x3881; + static final int PID = 0x3881; // bulk endpoint number - final static int EP = 2; + static final int EP = 2; /// Effective sample rate (in Hz) private int effSampleRate; @@ -172,12 +172,12 @@ void startAcquisition() { // Byte 1-2: clock ticks (-1) between two samples (16 bit, big endian) int ticks = period - 1; - byte flags = use48Mhz ? (byte)(1 << 6) : 0; + byte flags = use48Mhz ? (byte) (1 << 6) : 0; var cmd = new byte[3]; cmd[0] = flags; - cmd[1] = (byte)(ticks >> 8); - cmd[2] = (byte)(ticks & 0xff); + cmd[1] = (byte) (ticks >> 8); + cmd[2] = (byte) (ticks & 0xff); // send the start command final int commandCodeStart = 0xb1; @@ -187,7 +187,7 @@ void startAcquisition() { void saveSamples() { // retrieve the sample data from the bulk endpoint - int expectedSize = (int)(((long)duration * effSampleRate + 500) / 1000); + int expectedSize = (int) (((long) duration * effSampleRate + 500) / 1000); byte[] sampleData = new byte[expectedSize]; @@ -279,7 +279,7 @@ void checkFirmware() { device.open(); device.claimInterface(0); - byte[] cmd = new byte[] { 1 }; + byte[] cmd = new byte[]{1}; device.controlTransferOut(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.DEVICE, 0xa0, 0xe600, 0x0000), cmd); final int len = firmware.length; @@ -291,7 +291,7 @@ void checkFirmware() { offset += n; } - cmd = new byte[] { 0 }; + cmd = new byte[]{0}; device.controlTransferOut(new UsbControlTransfer(UsbRequestType.VENDOR, UsbRecipient.DEVICE, 0xa0, 0xe600, 0x0000), cmd); device.close(); @@ -318,7 +318,7 @@ void sleep(long milliseconds) { //noinspection BusyWait Thread.sleep(milliseconds); // NOSONAR return; - } catch (InterruptedException e) { + } catch (InterruptedException _) { // ignore and try again } } @@ -341,16 +341,17 @@ static synchronized DeviceMonitor instance() { return singleInstance; } - private DeviceMonitor() { } + private DeviceMonitor() { + } private void start() { - Usb.setOnDeviceConnected((device) -> onDeviceConnected(device, true)); - Usb.setOnDeviceDisconnected((device) -> onDeviceConnected(device, false)); + Usb.setOnDeviceConnected(dev -> onDeviceConnected(dev, true)); + Usb.setOnDeviceDisconnected(dev -> onDeviceConnected(dev, false)); isDeviceConnected = Usb.findDevice(VID, PID).isPresent(); } private void onDeviceConnected(UsbDevice device, boolean connected) { - if (device.getVendorId() == VID && device.getProductId() == device.getProductId()) { + if (device.getVendorId() == VID && device.getProductId() == PID) { try { deviceLock.lock(); isDeviceConnected = connected; diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java b/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java index cc318262..ebf0df0f 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/MonitorDevices.java @@ -16,7 +16,7 @@ import java.io.IOException; /** - * Test program that communicates with the device as soon as it has been pugged in. + * Test program that communicates with the device as soon as it has been plugged in. *

* Quit with Ctrl-C or whatever stops a program on your platform. *

@@ -24,11 +24,11 @@ public class MonitorDevices { public static void main(String[] args) throws IOException { - Usb.setOnDeviceConnected((device) -> { + Usb.setOnDeviceConnected(device -> { System.out.println("Connected: " + device.toString()); talkToTestDevice(device); }); - Usb.setOnDeviceDisconnected((device) -> System.out.println("Disconnected: " + device.toString())); + Usb.setOnDeviceDisconnected(device -> System.out.println("Disconnected: " + device.toString())); for (var device : Usb.getDevices()) { System.out.println("Present: " + device.toString()); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/USBSerial.java b/java-does-usb/src/test/java/net/codecrete/usb/special/USBSerial.java index efaaaf45..ec4e4b67 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/USBSerial.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/USBSerial.java @@ -53,14 +53,14 @@ static void interact(UsbDevice device, int commInterfaceNum) { device.claimInterface(dataInterfaceNum); // set line coding (9600bps, 8 bit) - byte[] coding = { (byte)0x80, 0x25, 0, 0, 0, 0, 8 }; + byte[] coding = {(byte) 0x80, 0x25, 0, 0, 0, 0, 8}; device.controlTransferOut( new UsbControlTransfer(UsbRequestType.CLASS, UsbRecipient.INTERFACE, 0x20, 0, commInterfaceNum), coding); // send some data int dataOutEp = getDataOutEndpointNum(device, dataInterfaceNum); - byte[] data = { 'H', 'e', 'l', 'l', 'o', '\r', '\n' }; + byte[] data = {'H', 'e', 'l', 'l', 'o', '\r', '\n'}; device.transferOut(dataOutEp, data); // close device and interfaces diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java index cc5e7671..cb79dd39 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java @@ -14,6 +14,7 @@ import java.io.IOException; import java.util.HashMap; +import java.util.Map; import static java.time.Duration.ofSeconds; @@ -25,7 +26,7 @@ *

*/ public class Unplug { - private static final HashMap activeDevices = new HashMap<>(); + private static final Map activeDevices = new HashMap<>(); public static void main(String[] args) throws IOException { System.out.println("Plug and unplug test device multiple times."); @@ -76,7 +77,7 @@ private static void sleep(long millis) { try { Thread.sleep(millis); - } catch (InterruptedException e) { + } catch (InterruptedException _) { Thread.currentThread().interrupt(); } } @@ -90,7 +91,7 @@ static class DeviceWorker { private long disconnectTime; - private final HashMap workTracking = new HashMap<>(); + private final Map workTracking = new HashMap<>(); DeviceWorker(UsbDevice device, TestDeviceConfig config) { this.device = device; @@ -180,7 +181,7 @@ private void logWork(long amount) { private void runAction(Runnable action) { try { action.run(); - } catch (UsbException e) { + } catch (UsbException _) { logFinish(); } } @@ -246,7 +247,7 @@ private void receiveLoopbackDataStream() { private void sendEcho() { logStart("sending echo", 7); - var data = new byte[] { 0x03, 0x45, 0x73, (byte)0xb3, (byte)0x9f, 0x3f, 0x00, 0x6a }; + var data = new byte[]{0x03, 0x45, 0x73, (byte) 0xb3, (byte) 0x9f, 0x3f, 0x00, 0x6a}; //noinspection InfiniteLoopStatement while (true) { device.transferOut(config.endpointEchoOut(), data); diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StringDescriptorTest.java b/java-does-usb/src/test/java/net/codecrete/usb/usbstandard/StringDescriptorTest.java similarity index 93% rename from java-does-usb/src/test/java/net/codecrete/usb/StringDescriptorTest.java rename to java-does-usb/src/test/java/net/codecrete/usb/usbstandard/StringDescriptorTest.java index 542e3142..d2b638be 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StringDescriptorTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/usbstandard/StringDescriptorTest.java @@ -1,6 +1,6 @@ -package net.codecrete.usb; +package net.codecrete.usb.usbstandard; -import net.codecrete.usb.usbstandard.StringDescriptor; +import net.codecrete.usb.UsbException; import org.junit.jupiter.api.Test; import java.lang.foreign.Arena; @@ -76,7 +76,7 @@ void unicodeSurrogates() { // In theory, USB is stuck with an old Unicode standard and the below is invalid. // In practice, it will work anyway. testDescriptor( - new byte[]{0x06, 0x03, 0x3D, (byte)0xD8, 0x1B, (byte)0xDE}, + new byte[]{0x06, 0x03, 0x3D, (byte) 0xD8, 0x1B, (byte) 0xDE}, stringDescriptor -> { assertThat(stringDescriptor.isValid()).isTrue(); assertThat(stringDescriptor.string()).isEqualTo("\uD83D\uDE1B"); @@ -87,7 +87,7 @@ void unicodeSurrogates() { @Test void invalidUnicodeCharactersAreReplaced() { testDescriptor( - new byte[]{0x06, 0x03, 'H', 0, 0x1B, (byte)0xDE}, + new byte[]{0x06, 0x03, 'H', 0, 0x1B, (byte) 0xDE}, stringDescriptor -> { assertThat(stringDescriptor.isValid()).isTrue(); assertThat(stringDescriptor.string()).isEqualTo("H�"); From 016f9333f4395cb690fdd627077a4da98adcdc4b Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 2 Jun 2025 19:50:52 +0200 Subject: [PATCH 380/433] Fix Maven wrapper --- .../.mvn/wrapper/maven-wrapper.properties | 19 + java-does-usb/mvnw | 435 ++++++++---------- java-does-usb/mvnw.cmd | 304 +++++------- 3 files changed, 336 insertions(+), 422 deletions(-) create mode 100644 java-does-usb/.mvn/wrapper/maven-wrapper.properties diff --git a/java-does-usb/.mvn/wrapper/maven-wrapper.properties b/java-does-usb/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..d58dfb70 --- /dev/null +++ b/java-does-usb/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +wrapperVersion=3.3.2 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/java-does-usb/mvnw b/java-does-usb/mvnw index 8d937f4c..19529ddf 100755 --- a/java-does-usb/mvnw +++ b/java-does-usb/mvnw @@ -19,290 +19,241 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.2.0 -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir +# Apache Maven Wrapper startup batch script, version 3.3.2 # # Optional ENV vars # ----------------- -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output # ---------------------------------------------------------------------------- -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false +# OS specific support. +native_path() { printf %s\\n "$1"; } case "$(uname)" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME - else - JAVA_HOME="/Library/Java/Home"; export JAVA_HOME - fi - fi - ;; +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; esac -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=$(java-config --jre-home) - fi -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --unix "$JAVA_HOME") - [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --unix "$CLASSPATH") -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && - JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="$(which javac)" - if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=$(which readlink) - if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then - if $darwin ; then - javaHome="$(dirname "\"$javaExecutable\"")" - javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" - else - javaExecutable="$(readlink -f "\"$javaExecutable\"")" - fi - javaHome="$(dirname "\"$javaExecutable\"")" - javaHome=$(expr "$javaHome" : '\(.*\)/bin') - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" else JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi fi else - JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi fi +} - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=$(cd "$wdir/.." || exit 1; pwd) - fi - # end of workaround +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" done - printf '%s' "$(cd "$basedir" || exit 1; pwd)" + printf %x\\n $h } -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - # Remove \r in case we run on Windows within Git Bash - # and check out the repository with auto CRLF management - # enabled. Otherwise, we may read lines that are delimited with - # \r\n and produce $'-Xarg\r' rather than -Xarg due to word - # splitting rules. - tr -s '\r\n' ' ' < "$1" - fi +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 } -log() { - if [ "$MVNW_VERBOSE" = true ]; then - printf '%s\n' "$1" - fi +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" } -BASE_DIR=$(find_maven_basedir "$(dirname "$0")") -if [ -z "$BASE_DIR" ]; then - exit 1; +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" fi -MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR -log "$MAVEN_PROJECTBASEDIR" +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" -if [ -r "$wrapperJarPath" ]; then - log "Found $wrapperJarPath" +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT else - log "Couldn't find $wrapperJarPath, downloading it ..." + die "cannot create temp dir" +fi - if [ -n "$MVNW_REPOURL" ]; then - wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - else - wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - fi - while IFS="=" read -r key value; do - # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) - safeValue=$(echo "$value" | tr -d '\r') - case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; - esac - done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" - log "Downloading from: $wrapperUrl" +mkdir -p -- "${MAVEN_HOME%/*}" - if $cygwin; then - wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") - fi +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - if command -v wget > /dev/null; then - log "Found wget ... using wget" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - else - wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - log "Found curl ... using curl" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" - else - curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" - fi - else - log "Falling back to using Java to download" - javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" - javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaSource=$(cygpath --path --windows "$javaSource") - javaClass=$(cygpath --path --windows "$javaClass") - fi - if [ -e "$javaSource" ]; then - if [ ! -e "$javaClass" ]; then - log " - Compiling MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/javac" "$javaSource") - fi - if [ -e "$javaClass" ]; then - log " - Running MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" - fi - fi - fi +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" fi -########################################################################################## -# End of extension -########################################################################################## -# If specified, validate the SHA-256 sum of the Maven wrapper jar file -wrapperSha256Sum="" -while IFS="=" read -r key value; do - case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; - esac -done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" -if [ -n "$wrapperSha256Sum" ]; then - wrapperSha256Result=false - if command -v sha256sum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then - wrapperSha256Result=true +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + distributionSha256Result=true fi - elif command -v shasum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then - wrapperSha256Result=true + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true fi else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." - echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 exit 1 fi - if [ $wrapperSha256Result = false ]; then - echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 - echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 - echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 exit 1 fi fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") - [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --windows "$CLASSPATH") - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" fi +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -# shellcheck disable=SC2086 # safe args -exec "$JAVACMD" \ - $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" +clean || : +exec_maven "$@" diff --git a/java-does-usb/mvnw.cmd b/java-does-usb/mvnw.cmd index c4586b56..249bdf38 100644 --- a/java-does-usb/mvnw.cmd +++ b/java-does-usb/mvnw.cmd @@ -1,3 +1,4 @@ +<# : batch portion @REM ---------------------------------------------------------------------------- @REM Licensed to the Apache Software Foundation (ASF) under one @REM or more contributor license agreements. See the NOTICE file @@ -18,188 +19,131 @@ @REM ---------------------------------------------------------------------------- @REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.2.0 -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir +@REM Apache Maven Wrapper startup batch script, version 3.3.2 @REM @REM Optional ENV vars -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output @REM ---------------------------------------------------------------------------- -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %WRAPPER_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file -SET WRAPPER_SHA_256_SUM="" -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) ) -IF NOT %WRAPPER_SHA_256_SUM%=="" ( - powershell -Command "&{"^ - "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ - "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ - " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ - " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ - " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ - " exit 1;"^ - "}"^ - "}" - if ERRORLEVEL 1 goto error -) - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' +$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" +if ($env:MAVEN_USER_HOME) { + $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" +} +$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" From ae38b312e31e968a94e9e78b15da2f2e74ab9f45 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 2 Jun 2025 19:58:07 +0200 Subject: [PATCH 381/433] Exclude generated sources from JavaDoc --- java-does-usb/pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 9684ae52..3c411e3b 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -166,8 +166,9 @@ - 22 + 23 ${java.home}/bin/javadoc + windows.*
From 7ff270d91413037cc8eee48b9a2f0fefcb400a66 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 2 Jun 2025 20:03:31 +0200 Subject: [PATCH 382/433] More Javadoc exclusions --- java-does-usb/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 3c411e3b..67b18c03 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -168,7 +168,7 @@ 23 ${java.home}/bin/javadoc - windows.* + net.codecrete.usb.linux.gen.*:net.codecrete.usb.macos.gen.*:windows.*:system From 074344f876eb7bfa007b8dc89f9f687728560b39 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Mon, 8 Sep 2025 10:31:50 +0200 Subject: [PATCH 383/433] Updated jextract generated code for macOS --- java-does-usb/pom.xml | 1 - .../codecrete/usb/macos/MacosAsyncTask.java | 12 +- .../CFMessagePortCreateLocal$callout.java | 8 +- .../usb/macos/gen/corefoundation/CFRange.java | 8 +- .../macos/gen/corefoundation/CFUUIDBytes.java | 36 +- .../corefoundation/CoreFoundation$shared.java | 63 +++ .../gen/corefoundation/CoreFoundation.java | 427 +++++++++++---- .../usb/macos/gen/iokit/CFUUIDBytes.java | 36 +- .../gen/iokit/IOCFPlugInInterfaceStruct.java | 70 +-- .../usb/macos/gen/iokit/IOKit$shared.java | 63 +++ .../codecrete/usb/macos/gen/iokit/IOKit.java | 222 +++++--- ...rviceAddMatchingNotification$callback.java | 8 +- .../usb/macos/gen/iokit/IOUSBDevRequest.java | 18 +- .../macos/gen/iokit/IOUSBDeviceStruct187.java | 376 ++++++++------ .../gen/iokit/IOUSBFindInterfaceRequest.java | 12 +- .../gen/iokit/IOUSBInterfaceStruct190.java | 486 +++++++++++------- .../usb/macos/gen/mach/mach$shared.java | 63 +++ .../codecrete/usb/macos/gen/mach/mach.java | 66 +-- 18 files changed, 1299 insertions(+), 676 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation$shared.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit$shared.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach$shared.java diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 67b18c03..51278b36 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -12,7 +12,6 @@ 23 23 UTF-8 - src/main/java/net/codecrete/usb/**/gen/**/*
Java Does USB diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java index ec0bd96d..6411682c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java @@ -8,6 +8,7 @@ package net.codecrete.usb.macos; import net.codecrete.usb.UsbException; +import net.codecrete.usb.macos.gen.corefoundation.CFMessagePortCreateLocal$callout; import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; import net.codecrete.usb.macos.gen.iokit.IOKit; @@ -122,21 +123,14 @@ private void startAsyncIOThread() { var completionHandlerFuncDesc = FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT, ADDRESS); var asyncIOCompletedMH = MethodHandles.lookup().findVirtual(MacosAsyncTask.class, "asyncIOCompleted", MethodType.methodType(void.class, MemorySegment.class, int.class, MemorySegment.class)); - var methodHandle = asyncIOCompletedMH.bindTo(this); completionUpcallStub = Linker.nativeLinker().upcallStub(methodHandle, completionHandlerFuncDesc, Arena.global()); - // create descriptor for message port callback function - var messagePortCallbackFuncDec = FunctionDescriptor.of(ADDRESS, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); - var messagePortCallbackMH = MethodHandles.lookup().findVirtual(MacosAsyncTask.class, "messagePortCallback", - MethodType.methodType(MemorySegment.class, MemorySegment.class, int.class, MemorySegment.class, MemorySegment.class)); - var messagePortCallbackHandle = messagePortCallbackMH.bindTo(this); - var messagePortCallbackStub = Linker.nativeLinker().upcallStub(messagePortCallbackHandle, messagePortCallbackFuncDec, Arena.global()); - // create local and remote message ports var pid = ProcessHandle.current().pid(); var portName = CoreFoundationHelper.createCFStringRef("net.codecrete.usb.macos.eventsource." + pid, Arena.global()); - var localPort = CoreFoundation.CFMessagePortCreateLocal(NULL, portName, messagePortCallbackStub, NULL, NULL); + var messagePortCallback = CFMessagePortCreateLocal$callout.allocate(this::messagePortCallback, Arena.global()); + var localPort = CoreFoundation.CFMessagePortCreateLocal(NULL, portName, messagePortCallback, NULL, NULL); messagePortSource = CoreFoundation.CFMessagePortCreateRunLoopSource(NULL, localPort, 0); messagePort = CoreFoundation.CFMessagePortCreateRemote(NULL, portName); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFMessagePortCreateLocal$callout.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFMessagePortCreateLocal$callout.java index df8fbeda..760f9200 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFMessagePortCreateLocal$callout.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFMessagePortCreateLocal$callout.java @@ -17,9 +17,9 @@ * CFMessagePortCallBack callout * } */ -public class CFMessagePortCreateLocal$callout { +public final class CFMessagePortCreateLocal$callout { - CFMessagePortCreateLocal$callout() { + private CFMessagePortCreateLocal$callout() { // Should not be called directly } @@ -60,9 +60,11 @@ public static MemorySegment allocate(CFMessagePortCreateLocal$callout.Function f /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static MemorySegment invoke(MemorySegment funcPtr,MemorySegment _x0, int _x1, MemorySegment _x2, MemorySegment _x3) { + public static MemorySegment invoke(MemorySegment funcPtr, MemorySegment _x0, int _x1, MemorySegment _x2, MemorySegment _x3) { try { return (MemorySegment) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java index 07ec2197..52df333e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFRange.java @@ -50,7 +50,7 @@ public static final GroupLayout layout() { return location$LAYOUT; } - private static final long location$OFFSET = 0; + private static final long location$OFFSET = $LAYOUT.byteOffset(groupElement("location")); /** * Offset for field: @@ -94,7 +94,7 @@ public static void location(MemorySegment struct, long fieldValue) { return length$LAYOUT; } - private static final long length$OFFSET = 8; + private static final long length$OFFSET = $LAYOUT.byteOffset(groupElement("length")); /** * Offset for field: @@ -155,7 +155,7 @@ public static MemorySegment allocateArray(long elementCount, SegmentAllocator al } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { @@ -163,7 +163,7 @@ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consume } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code elementCount * layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java index bcbb50a6..5b52339e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CFUUIDBytes.java @@ -78,7 +78,7 @@ public static final GroupLayout layout() { return byte0$LAYOUT; } - private static final long byte0$OFFSET = 0; + private static final long byte0$OFFSET = $LAYOUT.byteOffset(groupElement("byte0")); /** * Offset for field: @@ -122,7 +122,7 @@ public static void byte0(MemorySegment struct, byte fieldValue) { return byte1$LAYOUT; } - private static final long byte1$OFFSET = 1; + private static final long byte1$OFFSET = $LAYOUT.byteOffset(groupElement("byte1")); /** * Offset for field: @@ -166,7 +166,7 @@ public static void byte1(MemorySegment struct, byte fieldValue) { return byte2$LAYOUT; } - private static final long byte2$OFFSET = 2; + private static final long byte2$OFFSET = $LAYOUT.byteOffset(groupElement("byte2")); /** * Offset for field: @@ -210,7 +210,7 @@ public static void byte2(MemorySegment struct, byte fieldValue) { return byte3$LAYOUT; } - private static final long byte3$OFFSET = 3; + private static final long byte3$OFFSET = $LAYOUT.byteOffset(groupElement("byte3")); /** * Offset for field: @@ -254,7 +254,7 @@ public static void byte3(MemorySegment struct, byte fieldValue) { return byte4$LAYOUT; } - private static final long byte4$OFFSET = 4; + private static final long byte4$OFFSET = $LAYOUT.byteOffset(groupElement("byte4")); /** * Offset for field: @@ -298,7 +298,7 @@ public static void byte4(MemorySegment struct, byte fieldValue) { return byte5$LAYOUT; } - private static final long byte5$OFFSET = 5; + private static final long byte5$OFFSET = $LAYOUT.byteOffset(groupElement("byte5")); /** * Offset for field: @@ -342,7 +342,7 @@ public static void byte5(MemorySegment struct, byte fieldValue) { return byte6$LAYOUT; } - private static final long byte6$OFFSET = 6; + private static final long byte6$OFFSET = $LAYOUT.byteOffset(groupElement("byte6")); /** * Offset for field: @@ -386,7 +386,7 @@ public static void byte6(MemorySegment struct, byte fieldValue) { return byte7$LAYOUT; } - private static final long byte7$OFFSET = 7; + private static final long byte7$OFFSET = $LAYOUT.byteOffset(groupElement("byte7")); /** * Offset for field: @@ -430,7 +430,7 @@ public static void byte7(MemorySegment struct, byte fieldValue) { return byte8$LAYOUT; } - private static final long byte8$OFFSET = 8; + private static final long byte8$OFFSET = $LAYOUT.byteOffset(groupElement("byte8")); /** * Offset for field: @@ -474,7 +474,7 @@ public static void byte8(MemorySegment struct, byte fieldValue) { return byte9$LAYOUT; } - private static final long byte9$OFFSET = 9; + private static final long byte9$OFFSET = $LAYOUT.byteOffset(groupElement("byte9")); /** * Offset for field: @@ -518,7 +518,7 @@ public static void byte9(MemorySegment struct, byte fieldValue) { return byte10$LAYOUT; } - private static final long byte10$OFFSET = 10; + private static final long byte10$OFFSET = $LAYOUT.byteOffset(groupElement("byte10")); /** * Offset for field: @@ -562,7 +562,7 @@ public static void byte10(MemorySegment struct, byte fieldValue) { return byte11$LAYOUT; } - private static final long byte11$OFFSET = 11; + private static final long byte11$OFFSET = $LAYOUT.byteOffset(groupElement("byte11")); /** * Offset for field: @@ -606,7 +606,7 @@ public static void byte11(MemorySegment struct, byte fieldValue) { return byte12$LAYOUT; } - private static final long byte12$OFFSET = 12; + private static final long byte12$OFFSET = $LAYOUT.byteOffset(groupElement("byte12")); /** * Offset for field: @@ -650,7 +650,7 @@ public static void byte12(MemorySegment struct, byte fieldValue) { return byte13$LAYOUT; } - private static final long byte13$OFFSET = 13; + private static final long byte13$OFFSET = $LAYOUT.byteOffset(groupElement("byte13")); /** * Offset for field: @@ -694,7 +694,7 @@ public static void byte13(MemorySegment struct, byte fieldValue) { return byte14$LAYOUT; } - private static final long byte14$OFFSET = 14; + private static final long byte14$OFFSET = $LAYOUT.byteOffset(groupElement("byte14")); /** * Offset for field: @@ -738,7 +738,7 @@ public static void byte14(MemorySegment struct, byte fieldValue) { return byte15$LAYOUT; } - private static final long byte15$OFFSET = 15; + private static final long byte15$OFFSET = $LAYOUT.byteOffset(groupElement("byte15")); /** * Offset for field: @@ -799,7 +799,7 @@ public static MemorySegment allocateArray(long elementCount, SegmentAllocator al } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { @@ -807,7 +807,7 @@ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consume } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code elementCount * layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation$shared.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation$shared.java new file mode 100644 index 00000000..1994933a --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation$shared.java @@ -0,0 +1,63 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.corefoundation; + +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; + +public class CoreFoundation$shared { + + CoreFoundation$shared() { + // Should not be called directly + } + + public static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool"); + public static final ValueLayout.OfByte C_CHAR =(ValueLayout.OfByte)Linker.nativeLinker().canonicalLayouts().get("char"); + public static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) Linker.nativeLinker().canonicalLayouts().get("short"); + public static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get("int"); + public static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long long"); + public static final ValueLayout.OfFloat C_FLOAT = (ValueLayout.OfFloat) Linker.nativeLinker().canonicalLayouts().get("float"); + public static final ValueLayout.OfDouble C_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get("double"); + public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*")) + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, C_CHAR)); + public static final ValueLayout.OfLong C_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long"); + + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java index 0413e52c..a1690ca3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/corefoundation/CoreFoundation.java @@ -12,63 +12,18 @@ import static java.lang.foreign.ValueLayout.*; import static java.lang.foreign.MemoryLayout.PathElement.*; -public class CoreFoundation { +public class CoreFoundation extends CoreFoundation$shared { CoreFoundation() { // Should not be called directly } static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", LIBRARY_ARENA) .or(SymbolLookup.loaderLookup()) .or(Linker.nativeLinker().defaultLookup()); - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; private static class CFGetTypeID { public static final FunctionDescriptor DESC = FunctionDescriptor.of( @@ -76,9 +31,9 @@ private static class CFGetTypeID { CoreFoundation.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFGetTypeID"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFGetTypeID"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -100,6 +55,17 @@ private static class CFGetTypeID { public static MethodHandle CFGetTypeID$handle() { return CFGetTypeID.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern CFTypeID CFGetTypeID(CFTypeRef cf) + * } + */ + public static MemorySegment CFGetTypeID$address() { + return CFGetTypeID.ADDR; + } + /** * {@snippet lang=c : * extern CFTypeID CFGetTypeID(CFTypeRef cf) @@ -112,6 +78,8 @@ public static long CFGetTypeID(MemorySegment cf) { traceDowncall("CFGetTypeID", cf); } return (long)mh$.invokeExact(cf); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -122,9 +90,9 @@ private static class CFRelease { CoreFoundation.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFRelease"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFRelease"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -146,6 +114,17 @@ private static class CFRelease { public static MethodHandle CFRelease$handle() { return CFRelease.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern void CFRelease(CFTypeRef cf) + * } + */ + public static MemorySegment CFRelease$address() { + return CFRelease.ADDR; + } + /** * {@snippet lang=c : * extern void CFRelease(CFTypeRef cf) @@ -158,6 +137,8 @@ public static void CFRelease(MemorySegment cf) { traceDowncall("CFRelease", cf); } mh$.invokeExact(cf); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -171,9 +152,9 @@ private static class CFDataCreate { CoreFoundation.C_LONG ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFDataCreate"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFDataCreate"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -195,6 +176,17 @@ private static class CFDataCreate { public static MethodHandle CFDataCreate$handle() { return CFDataCreate.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern CFDataRef CFDataCreate(CFAllocatorRef allocator, const UInt8 *bytes, CFIndex length) + * } + */ + public static MemorySegment CFDataCreate$address() { + return CFDataCreate.ADDR; + } + /** * {@snippet lang=c : * extern CFDataRef CFDataCreate(CFAllocatorRef allocator, const UInt8 *bytes, CFIndex length) @@ -207,6 +199,8 @@ public static MemorySegment CFDataCreate(MemorySegment allocator, MemorySegment traceDowncall("CFDataCreate", allocator, bytes, length); } return (MemorySegment)mh$.invokeExact(allocator, bytes, length); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -218,9 +212,9 @@ private static class CFDataGetBytePtr { CoreFoundation.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFDataGetBytePtr"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFDataGetBytePtr"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -242,6 +236,17 @@ private static class CFDataGetBytePtr { public static MethodHandle CFDataGetBytePtr$handle() { return CFDataGetBytePtr.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern const UInt8 *CFDataGetBytePtr(CFDataRef theData) + * } + */ + public static MemorySegment CFDataGetBytePtr$address() { + return CFDataGetBytePtr.ADDR; + } + /** * {@snippet lang=c : * extern const UInt8 *CFDataGetBytePtr(CFDataRef theData) @@ -254,6 +259,8 @@ public static MemorySegment CFDataGetBytePtr(MemorySegment theData) { traceDowncall("CFDataGetBytePtr", theData); } return (MemorySegment)mh$.invokeExact(theData); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -263,9 +270,9 @@ private static class CFStringGetTypeID { public static final FunctionDescriptor DESC = FunctionDescriptor.of( CoreFoundation.C_LONG ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFStringGetTypeID"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFStringGetTypeID"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -287,6 +294,17 @@ private static class CFStringGetTypeID { public static MethodHandle CFStringGetTypeID$handle() { return CFStringGetTypeID.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern CFTypeID CFStringGetTypeID(void) + * } + */ + public static MemorySegment CFStringGetTypeID$address() { + return CFStringGetTypeID.ADDR; + } + /** * {@snippet lang=c : * extern CFTypeID CFStringGetTypeID(void) @@ -299,6 +317,8 @@ public static long CFStringGetTypeID() { traceDowncall("CFStringGetTypeID"); } return (long)mh$.invokeExact(); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -312,9 +332,9 @@ private static class CFStringCreateWithCharacters { CoreFoundation.C_LONG ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFStringCreateWithCharacters"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFStringCreateWithCharacters"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -336,6 +356,17 @@ private static class CFStringCreateWithCharacters { public static MethodHandle CFStringCreateWithCharacters$handle() { return CFStringCreateWithCharacters.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, const UniChar *chars, CFIndex numChars) + * } + */ + public static MemorySegment CFStringCreateWithCharacters$address() { + return CFStringCreateWithCharacters.ADDR; + } + /** * {@snippet lang=c : * extern CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, const UniChar *chars, CFIndex numChars) @@ -348,6 +379,8 @@ public static MemorySegment CFStringCreateWithCharacters(MemorySegment alloc, Me traceDowncall("CFStringCreateWithCharacters", alloc, chars, numChars); } return (MemorySegment)mh$.invokeExact(alloc, chars, numChars); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -359,9 +392,9 @@ private static class CFStringGetLength { CoreFoundation.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFStringGetLength"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFStringGetLength"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -383,6 +416,17 @@ private static class CFStringGetLength { public static MethodHandle CFStringGetLength$handle() { return CFStringGetLength.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern CFIndex CFStringGetLength(CFStringRef theString) + * } + */ + public static MemorySegment CFStringGetLength$address() { + return CFStringGetLength.ADDR; + } + /** * {@snippet lang=c : * extern CFIndex CFStringGetLength(CFStringRef theString) @@ -395,6 +439,8 @@ public static long CFStringGetLength(MemorySegment theString) { traceDowncall("CFStringGetLength", theString); } return (long)mh$.invokeExact(theString); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -407,9 +453,9 @@ private static class CFStringGetCharacters { CoreFoundation.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFStringGetCharacters"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFStringGetCharacters"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -431,6 +477,17 @@ private static class CFStringGetCharacters { public static MethodHandle CFStringGetCharacters$handle() { return CFStringGetCharacters.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern void CFStringGetCharacters(CFStringRef theString, CFRange range, UniChar *buffer) + * } + */ + public static MemorySegment CFStringGetCharacters$address() { + return CFStringGetCharacters.ADDR; + } + /** * {@snippet lang=c : * extern void CFStringGetCharacters(CFStringRef theString, CFRange range, UniChar *buffer) @@ -443,6 +500,8 @@ public static void CFStringGetCharacters(MemorySegment theString, MemorySegment traceDowncall("CFStringGetCharacters", theString, range, buffer); } mh$.invokeExact(theString, range, buffer); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -461,9 +520,9 @@ private static class CFNumberGetTypeID { public static final FunctionDescriptor DESC = FunctionDescriptor.of( CoreFoundation.C_LONG ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFNumberGetTypeID"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFNumberGetTypeID"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -485,6 +544,17 @@ private static class CFNumberGetTypeID { public static MethodHandle CFNumberGetTypeID$handle() { return CFNumberGetTypeID.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern CFTypeID CFNumberGetTypeID(void) + * } + */ + public static MemorySegment CFNumberGetTypeID$address() { + return CFNumberGetTypeID.ADDR; + } + /** * {@snippet lang=c : * extern CFTypeID CFNumberGetTypeID(void) @@ -497,6 +567,8 @@ public static long CFNumberGetTypeID() { traceDowncall("CFNumberGetTypeID"); } return (long)mh$.invokeExact(); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -510,9 +582,9 @@ private static class CFNumberGetValue { CoreFoundation.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFNumberGetValue"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFNumberGetValue"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -534,6 +606,17 @@ private static class CFNumberGetValue { public static MethodHandle CFNumberGetValue$handle() { return CFNumberGetValue.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void *valuePtr) + * } + */ + public static MemorySegment CFNumberGetValue$address() { + return CFNumberGetValue.ADDR; + } + /** * {@snippet lang=c : * extern Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void *valuePtr) @@ -546,6 +629,8 @@ public static byte CFNumberGetValue(MemorySegment number, long theType, MemorySe traceDowncall("CFNumberGetValue", number, theType, valuePtr); } return (byte)mh$.invokeExact(number, theType, valuePtr); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -555,9 +640,9 @@ private static class CFRunLoopGetCurrent { public static final FunctionDescriptor DESC = FunctionDescriptor.of( CoreFoundation.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFRunLoopGetCurrent"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFRunLoopGetCurrent"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -579,6 +664,17 @@ private static class CFRunLoopGetCurrent { public static MethodHandle CFRunLoopGetCurrent$handle() { return CFRunLoopGetCurrent.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern CFRunLoopRef CFRunLoopGetCurrent(void) + * } + */ + public static MemorySegment CFRunLoopGetCurrent$address() { + return CFRunLoopGetCurrent.ADDR; + } + /** * {@snippet lang=c : * extern CFRunLoopRef CFRunLoopGetCurrent(void) @@ -591,6 +687,8 @@ public static MemorySegment CFRunLoopGetCurrent() { traceDowncall("CFRunLoopGetCurrent"); } return (MemorySegment)mh$.invokeExact(); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -599,9 +697,9 @@ public static MemorySegment CFRunLoopGetCurrent() { private static class CFRunLoopRun { public static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid( ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFRunLoopRun"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFRunLoopRun"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -623,6 +721,17 @@ private static class CFRunLoopRun { public static MethodHandle CFRunLoopRun$handle() { return CFRunLoopRun.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern void CFRunLoopRun(void) + * } + */ + public static MemorySegment CFRunLoopRun$address() { + return CFRunLoopRun.ADDR; + } + /** * {@snippet lang=c : * extern void CFRunLoopRun(void) @@ -635,6 +744,8 @@ public static void CFRunLoopRun() { traceDowncall("CFRunLoopRun"); } mh$.invokeExact(); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -647,9 +758,9 @@ private static class CFRunLoopAddSource { CoreFoundation.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFRunLoopAddSource"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFRunLoopAddSource"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -671,6 +782,17 @@ private static class CFRunLoopAddSource { public static MethodHandle CFRunLoopAddSource$handle() { return CFRunLoopAddSource.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode) + * } + */ + public static MemorySegment CFRunLoopAddSource$address() { + return CFRunLoopAddSource.ADDR; + } + /** * {@snippet lang=c : * extern void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode) @@ -683,6 +805,8 @@ public static void CFRunLoopAddSource(MemorySegment rl, MemorySegment source, Me traceDowncall("CFRunLoopAddSource", rl, source, mode); } mh$.invokeExact(rl, source, mode); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -695,9 +819,9 @@ private static class CFRunLoopRemoveSource { CoreFoundation.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFRunLoopRemoveSource"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFRunLoopRemoveSource"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -719,6 +843,17 @@ private static class CFRunLoopRemoveSource { public static MethodHandle CFRunLoopRemoveSource$handle() { return CFRunLoopRemoveSource.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode) + * } + */ + public static MemorySegment CFRunLoopRemoveSource$address() { + return CFRunLoopRemoveSource.ADDR; + } + /** * {@snippet lang=c : * extern void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode) @@ -731,6 +866,8 @@ public static void CFRunLoopRemoveSource(MemorySegment rl, MemorySegment source, traceDowncall("CFRunLoopRemoveSource", rl, source, mode); } mh$.invokeExact(rl, source, mode); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -742,9 +879,9 @@ private static class CFUUIDGetUUIDBytes { CoreFoundation.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFUUIDGetUUIDBytes"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFUUIDGetUUIDBytes"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -766,6 +903,17 @@ private static class CFUUIDGetUUIDBytes { public static MethodHandle CFUUIDGetUUIDBytes$handle() { return CFUUIDGetUUIDBytes.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern CFUUIDBytes CFUUIDGetUUIDBytes(CFUUIDRef uuid) + * } + */ + public static MemorySegment CFUUIDGetUUIDBytes$address() { + return CFUUIDGetUUIDBytes.ADDR; + } + /** * {@snippet lang=c : * extern CFUUIDBytes CFUUIDGetUUIDBytes(CFUUIDRef uuid) @@ -778,6 +926,8 @@ public static MemorySegment CFUUIDGetUUIDBytes(SegmentAllocator allocator, Memor traceDowncall("CFUUIDGetUUIDBytes", allocator, uuid); } return (MemorySegment)mh$.invokeExact(allocator, uuid); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -790,9 +940,9 @@ private static class CFUUIDCreateFromUUIDBytes { CFUUIDBytes.layout() ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFUUIDCreateFromUUIDBytes"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFUUIDCreateFromUUIDBytes"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -814,6 +964,17 @@ private static class CFUUIDCreateFromUUIDBytes { public static MethodHandle CFUUIDCreateFromUUIDBytes$handle() { return CFUUIDCreateFromUUIDBytes.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern CFUUIDRef CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc, CFUUIDBytes bytes) + * } + */ + public static MemorySegment CFUUIDCreateFromUUIDBytes$address() { + return CFUUIDCreateFromUUIDBytes.ADDR; + } + /** * {@snippet lang=c : * extern CFUUIDRef CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc, CFUUIDBytes bytes) @@ -826,6 +987,8 @@ public static MemorySegment CFUUIDCreateFromUUIDBytes(MemorySegment alloc, Memor traceDowncall("CFUUIDCreateFromUUIDBytes", alloc, bytes); } return (MemorySegment)mh$.invokeExact(alloc, bytes); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -841,9 +1004,9 @@ private static class CFMessagePortCreateLocal { CoreFoundation.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFMessagePortCreateLocal"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFMessagePortCreateLocal"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -865,6 +1028,17 @@ private static class CFMessagePortCreateLocal { public static MethodHandle CFMessagePortCreateLocal$handle() { return CFMessagePortCreateLocal.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern CFMessagePortRef CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo) + * } + */ + public static MemorySegment CFMessagePortCreateLocal$address() { + return CFMessagePortCreateLocal.ADDR; + } + /** * {@snippet lang=c : * extern CFMessagePortRef CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo) @@ -877,6 +1051,8 @@ public static MemorySegment CFMessagePortCreateLocal(MemorySegment allocator, Me traceDowncall("CFMessagePortCreateLocal", allocator, name, callout, context, shouldFreeInfo); } return (MemorySegment)mh$.invokeExact(allocator, name, callout, context, shouldFreeInfo); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -889,9 +1065,9 @@ private static class CFMessagePortCreateRemote { CoreFoundation.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFMessagePortCreateRemote"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFMessagePortCreateRemote"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -913,6 +1089,17 @@ private static class CFMessagePortCreateRemote { public static MethodHandle CFMessagePortCreateRemote$handle() { return CFMessagePortCreateRemote.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern CFMessagePortRef CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef name) + * } + */ + public static MemorySegment CFMessagePortCreateRemote$address() { + return CFMessagePortCreateRemote.ADDR; + } + /** * {@snippet lang=c : * extern CFMessagePortRef CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef name) @@ -925,6 +1112,8 @@ public static MemorySegment CFMessagePortCreateRemote(MemorySegment allocator, M traceDowncall("CFMessagePortCreateRemote", allocator, name); } return (MemorySegment)mh$.invokeExact(allocator, name); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -942,9 +1131,9 @@ private static class CFMessagePortSendRequest { CoreFoundation.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFMessagePortSendRequest"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFMessagePortSendRequest"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -966,6 +1155,17 @@ private static class CFMessagePortSendRequest { public static MethodHandle CFMessagePortSendRequest$handle() { return CFMessagePortSendRequest.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern SInt32 CFMessagePortSendRequest(CFMessagePortRef remote, SInt32 msgid, CFDataRef data, CFTimeInterval sendTimeout, CFTimeInterval rcvTimeout, CFStringRef replyMode, CFDataRef *returnData) + * } + */ + public static MemorySegment CFMessagePortSendRequest$address() { + return CFMessagePortSendRequest.ADDR; + } + /** * {@snippet lang=c : * extern SInt32 CFMessagePortSendRequest(CFMessagePortRef remote, SInt32 msgid, CFDataRef data, CFTimeInterval sendTimeout, CFTimeInterval rcvTimeout, CFStringRef replyMode, CFDataRef *returnData) @@ -978,6 +1178,8 @@ public static int CFMessagePortSendRequest(MemorySegment remote, int msgid, Memo traceDowncall("CFMessagePortSendRequest", remote, msgid, data, sendTimeout, rcvTimeout, replyMode, returnData); } return (int)mh$.invokeExact(remote, msgid, data, sendTimeout, rcvTimeout, replyMode, returnData); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -991,9 +1193,9 @@ private static class CFMessagePortCreateRunLoopSource { CoreFoundation.C_LONG ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - CoreFoundation.findOrThrow("CFMessagePortCreateRunLoopSource"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("CFMessagePortCreateRunLoopSource"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -1015,6 +1217,17 @@ private static class CFMessagePortCreateRunLoopSource { public static MethodHandle CFMessagePortCreateRunLoopSource$handle() { return CFMessagePortCreateRunLoopSource.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern CFRunLoopSourceRef CFMessagePortCreateRunLoopSource(CFAllocatorRef allocator, CFMessagePortRef local, CFIndex order) + * } + */ + public static MemorySegment CFMessagePortCreateRunLoopSource$address() { + return CFMessagePortCreateRunLoopSource.ADDR; + } + /** * {@snippet lang=c : * extern CFRunLoopSourceRef CFMessagePortCreateRunLoopSource(CFAllocatorRef allocator, CFMessagePortRef local, CFIndex order) @@ -1027,6 +1240,8 @@ public static MemorySegment CFMessagePortCreateRunLoopSource(MemorySegment alloc traceDowncall("CFMessagePortCreateRunLoopSource", allocator, local, order); } return (MemorySegment)mh$.invokeExact(allocator, local, order); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/CFUUIDBytes.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/CFUUIDBytes.java index 4885f492..b1ab37eb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/CFUUIDBytes.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/CFUUIDBytes.java @@ -78,7 +78,7 @@ public static final GroupLayout layout() { return byte0$LAYOUT; } - private static final long byte0$OFFSET = 0; + private static final long byte0$OFFSET = $LAYOUT.byteOffset(groupElement("byte0")); /** * Offset for field: @@ -122,7 +122,7 @@ public static void byte0(MemorySegment struct, byte fieldValue) { return byte1$LAYOUT; } - private static final long byte1$OFFSET = 1; + private static final long byte1$OFFSET = $LAYOUT.byteOffset(groupElement("byte1")); /** * Offset for field: @@ -166,7 +166,7 @@ public static void byte1(MemorySegment struct, byte fieldValue) { return byte2$LAYOUT; } - private static final long byte2$OFFSET = 2; + private static final long byte2$OFFSET = $LAYOUT.byteOffset(groupElement("byte2")); /** * Offset for field: @@ -210,7 +210,7 @@ public static void byte2(MemorySegment struct, byte fieldValue) { return byte3$LAYOUT; } - private static final long byte3$OFFSET = 3; + private static final long byte3$OFFSET = $LAYOUT.byteOffset(groupElement("byte3")); /** * Offset for field: @@ -254,7 +254,7 @@ public static void byte3(MemorySegment struct, byte fieldValue) { return byte4$LAYOUT; } - private static final long byte4$OFFSET = 4; + private static final long byte4$OFFSET = $LAYOUT.byteOffset(groupElement("byte4")); /** * Offset for field: @@ -298,7 +298,7 @@ public static void byte4(MemorySegment struct, byte fieldValue) { return byte5$LAYOUT; } - private static final long byte5$OFFSET = 5; + private static final long byte5$OFFSET = $LAYOUT.byteOffset(groupElement("byte5")); /** * Offset for field: @@ -342,7 +342,7 @@ public static void byte5(MemorySegment struct, byte fieldValue) { return byte6$LAYOUT; } - private static final long byte6$OFFSET = 6; + private static final long byte6$OFFSET = $LAYOUT.byteOffset(groupElement("byte6")); /** * Offset for field: @@ -386,7 +386,7 @@ public static void byte6(MemorySegment struct, byte fieldValue) { return byte7$LAYOUT; } - private static final long byte7$OFFSET = 7; + private static final long byte7$OFFSET = $LAYOUT.byteOffset(groupElement("byte7")); /** * Offset for field: @@ -430,7 +430,7 @@ public static void byte7(MemorySegment struct, byte fieldValue) { return byte8$LAYOUT; } - private static final long byte8$OFFSET = 8; + private static final long byte8$OFFSET = $LAYOUT.byteOffset(groupElement("byte8")); /** * Offset for field: @@ -474,7 +474,7 @@ public static void byte8(MemorySegment struct, byte fieldValue) { return byte9$LAYOUT; } - private static final long byte9$OFFSET = 9; + private static final long byte9$OFFSET = $LAYOUT.byteOffset(groupElement("byte9")); /** * Offset for field: @@ -518,7 +518,7 @@ public static void byte9(MemorySegment struct, byte fieldValue) { return byte10$LAYOUT; } - private static final long byte10$OFFSET = 10; + private static final long byte10$OFFSET = $LAYOUT.byteOffset(groupElement("byte10")); /** * Offset for field: @@ -562,7 +562,7 @@ public static void byte10(MemorySegment struct, byte fieldValue) { return byte11$LAYOUT; } - private static final long byte11$OFFSET = 11; + private static final long byte11$OFFSET = $LAYOUT.byteOffset(groupElement("byte11")); /** * Offset for field: @@ -606,7 +606,7 @@ public static void byte11(MemorySegment struct, byte fieldValue) { return byte12$LAYOUT; } - private static final long byte12$OFFSET = 12; + private static final long byte12$OFFSET = $LAYOUT.byteOffset(groupElement("byte12")); /** * Offset for field: @@ -650,7 +650,7 @@ public static void byte12(MemorySegment struct, byte fieldValue) { return byte13$LAYOUT; } - private static final long byte13$OFFSET = 13; + private static final long byte13$OFFSET = $LAYOUT.byteOffset(groupElement("byte13")); /** * Offset for field: @@ -694,7 +694,7 @@ public static void byte13(MemorySegment struct, byte fieldValue) { return byte14$LAYOUT; } - private static final long byte14$OFFSET = 14; + private static final long byte14$OFFSET = $LAYOUT.byteOffset(groupElement("byte14")); /** * Offset for field: @@ -738,7 +738,7 @@ public static void byte14(MemorySegment struct, byte fieldValue) { return byte15$LAYOUT; } - private static final long byte15$OFFSET = 15; + private static final long byte15$OFFSET = $LAYOUT.byteOffset(groupElement("byte15")); /** * Offset for field: @@ -799,7 +799,7 @@ public static MemorySegment allocateArray(long elementCount, SegmentAllocator al } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { @@ -807,7 +807,7 @@ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consume } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code elementCount * layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java index 26862c8c..8a027f5a 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java @@ -65,7 +65,7 @@ public static final GroupLayout layout() { return _reserved$LAYOUT; } - private static final long _reserved$OFFSET = 0; + private static final long _reserved$OFFSET = $LAYOUT.byteOffset(groupElement("_reserved")); /** * Offset for field: @@ -102,9 +102,9 @@ public static void _reserved(MemorySegment struct, MemorySegment fieldValue) { * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) * } */ - public static class QueryInterface { + public final static class QueryInterface { - QueryInterface() { + private QueryInterface() { // Should not be called directly } @@ -144,9 +144,11 @@ public static MemorySegment allocate(QueryInterface.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -165,7 +167,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return QueryInterface$LAYOUT; } - private static final long QueryInterface$OFFSET = 8; + private static final long QueryInterface$OFFSET = $LAYOUT.byteOffset(groupElement("QueryInterface")); /** * Offset for field: @@ -202,9 +204,9 @@ public static void QueryInterface(MemorySegment struct, MemorySegment fieldValue * ULONG (*AddRef)(void *) * } */ - public static class AddRef { + public final static class AddRef { - AddRef() { + private AddRef() { // Should not be called directly } @@ -242,9 +244,11 @@ public static MemorySegment allocate(AddRef.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -263,7 +267,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { return AddRef$LAYOUT; } - private static final long AddRef$OFFSET = 16; + private static final long AddRef$OFFSET = $LAYOUT.byteOffset(groupElement("AddRef")); /** * Offset for field: @@ -300,9 +304,9 @@ public static void AddRef(MemorySegment struct, MemorySegment fieldValue) { * ULONG (*Release)(void *) * } */ - public static class Release { + public final static class Release { - Release() { + private Release() { // Should not be called directly } @@ -340,9 +344,11 @@ public static MemorySegment allocate(Release.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -361,7 +367,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { return Release$LAYOUT; } - private static final long Release$OFFSET = 24; + private static final long Release$OFFSET = $LAYOUT.byteOffset(groupElement("Release")); /** * Offset for field: @@ -405,7 +411,7 @@ public static void Release(MemorySegment struct, MemorySegment fieldValue) { return version$LAYOUT; } - private static final long version$OFFSET = 32; + private static final long version$OFFSET = $LAYOUT.byteOffset(groupElement("version")); /** * Offset for field: @@ -449,7 +455,7 @@ public static void version(MemorySegment struct, short fieldValue) { return revision$LAYOUT; } - private static final long revision$OFFSET = 34; + private static final long revision$OFFSET = $LAYOUT.byteOffset(groupElement("revision")); /** * Offset for field: @@ -486,9 +492,9 @@ public static void revision(MemorySegment struct, short fieldValue) { * IOReturn (*Probe)(void *, CFDictionaryRef, io_service_t, SInt32 *) * } */ - public static class Probe { + public final static class Probe { - Probe() { + private Probe() { // Should not be called directly } @@ -529,9 +535,11 @@ public static MemorySegment allocate(Probe.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, int _x2, MemorySegment _x3) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1, int _x2, MemorySegment _x3) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -550,7 +558,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return Probe$LAYOUT; } - private static final long Probe$OFFSET = 40; + private static final long Probe$OFFSET = $LAYOUT.byteOffset(groupElement("Probe")); /** * Offset for field: @@ -587,9 +595,9 @@ public static void Probe(MemorySegment struct, MemorySegment fieldValue) { * IOReturn (*Start)(void *, CFDictionaryRef, io_service_t) * } */ - public static class Start { + public final static class Start { - Start() { + private Start() { // Should not be called directly } @@ -629,9 +637,11 @@ public static MemorySegment allocate(Start.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, int _x2) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1, int _x2) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -650,7 +660,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return Start$LAYOUT; } - private static final long Start$OFFSET = 48; + private static final long Start$OFFSET = $LAYOUT.byteOffset(groupElement("Start")); /** * Offset for field: @@ -687,9 +697,9 @@ public static void Start(MemorySegment struct, MemorySegment fieldValue) { * IOReturn (*Stop)(void *) * } */ - public static class Stop { + public final static class Stop { - Stop() { + private Stop() { // Should not be called directly } @@ -727,9 +737,11 @@ public static MemorySegment allocate(Stop.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -748,7 +760,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { return Stop$LAYOUT; } - private static final long Stop$OFFSET = 56; + private static final long Stop$OFFSET = $LAYOUT.byteOffset(groupElement("Stop")); /** * Offset for field: @@ -809,7 +821,7 @@ public static MemorySegment allocateArray(long elementCount, SegmentAllocator al } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { @@ -817,7 +829,7 @@ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consume } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code elementCount * layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit$shared.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit$shared.java new file mode 100644 index 00000000..c3328897 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit$shared.java @@ -0,0 +1,63 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.iokit; + +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; + +public class IOKit$shared { + + IOKit$shared() { + // Should not be called directly + } + + public static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool"); + public static final ValueLayout.OfByte C_CHAR =(ValueLayout.OfByte)Linker.nativeLinker().canonicalLayouts().get("char"); + public static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) Linker.nativeLinker().canonicalLayouts().get("short"); + public static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get("int"); + public static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long long"); + public static final ValueLayout.OfFloat C_FLOAT = (ValueLayout.OfFloat) Linker.nativeLinker().canonicalLayouts().get("float"); + public static final ValueLayout.OfDouble C_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get("double"); + public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*")) + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, C_CHAR)); + public static final ValueLayout.OfLong C_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long"); + + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java index ff608624..0eb5e6dc 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOKit.java @@ -12,63 +12,18 @@ import static java.lang.foreign.ValueLayout.*; import static java.lang.foreign.MemoryLayout.PathElement.*; -public class IOKit { +public class IOKit extends IOKit$shared { IOKit() { // Should not be called directly } static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup("/System/Library/Frameworks/IOKit.framework/IOKit", LIBRARY_ARENA) .or(SymbolLookup.loaderLookup()) .or(Linker.nativeLinker().defaultLookup()); - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; private static final int kIOUSBFindInterfaceDontCare = (int)65535L; /** * {@snippet lang=c : @@ -99,7 +54,7 @@ public static int kUSBReEnumerateReleaseDeviceMask() { private static class kCFRunLoopDefaultMode$constants { public static final AddressLayout LAYOUT = IOKit.C_POINTER; - public static final MemorySegment SEGMENT = IOKit.findOrThrow("kCFRunLoopDefaultMode").reinterpret(LAYOUT.byteSize()); + public static final MemorySegment SEGMENT = SYMBOL_LOOKUP.findOrThrow("kCFRunLoopDefaultMode").reinterpret(LAYOUT.byteSize()); } /** @@ -144,7 +99,7 @@ public static void kCFRunLoopDefaultMode(MemorySegment varValue) { private static class kIOMasterPortDefault$constants { public static final OfInt LAYOUT = IOKit.C_INT; - public static final MemorySegment SEGMENT = IOKit.findOrThrow("kIOMasterPortDefault").reinterpret(LAYOUT.byteSize()); + public static final MemorySegment SEGMENT = SYMBOL_LOOKUP.findOrThrow("kIOMasterPortDefault").reinterpret(LAYOUT.byteSize()); } /** @@ -193,9 +148,9 @@ private static class IONotificationPortCreate { IOKit.C_INT ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - IOKit.findOrThrow("IONotificationPortCreate"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("IONotificationPortCreate"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -217,6 +172,17 @@ private static class IONotificationPortCreate { public static MethodHandle IONotificationPortCreate$handle() { return IONotificationPortCreate.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * IONotificationPortRef IONotificationPortCreate(mach_port_t mainPort) + * } + */ + public static MemorySegment IONotificationPortCreate$address() { + return IONotificationPortCreate.ADDR; + } + /** * {@snippet lang=c : * IONotificationPortRef IONotificationPortCreate(mach_port_t mainPort) @@ -229,6 +195,8 @@ public static MemorySegment IONotificationPortCreate(int mainPort) { traceDowncall("IONotificationPortCreate", mainPort); } return (MemorySegment)mh$.invokeExact(mainPort); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -240,9 +208,9 @@ private static class IONotificationPortGetRunLoopSource { IOKit.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - IOKit.findOrThrow("IONotificationPortGetRunLoopSource"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("IONotificationPortGetRunLoopSource"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -264,6 +232,17 @@ private static class IONotificationPortGetRunLoopSource { public static MethodHandle IONotificationPortGetRunLoopSource$handle() { return IONotificationPortGetRunLoopSource.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * CFRunLoopSourceRef IONotificationPortGetRunLoopSource(IONotificationPortRef notify) + * } + */ + public static MemorySegment IONotificationPortGetRunLoopSource$address() { + return IONotificationPortGetRunLoopSource.ADDR; + } + /** * {@snippet lang=c : * CFRunLoopSourceRef IONotificationPortGetRunLoopSource(IONotificationPortRef notify) @@ -276,6 +255,8 @@ public static MemorySegment IONotificationPortGetRunLoopSource(MemorySegment not traceDowncall("IONotificationPortGetRunLoopSource", notify); } return (MemorySegment)mh$.invokeExact(notify); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -287,9 +268,9 @@ private static class IOObjectRelease { IOKit.C_INT ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - IOKit.findOrThrow("IOObjectRelease"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("IOObjectRelease"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -311,6 +292,17 @@ private static class IOObjectRelease { public static MethodHandle IOObjectRelease$handle() { return IOObjectRelease.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * kern_return_t IOObjectRelease(io_object_t object) + * } + */ + public static MemorySegment IOObjectRelease$address() { + return IOObjectRelease.ADDR; + } + /** * {@snippet lang=c : * kern_return_t IOObjectRelease(io_object_t object) @@ -323,6 +315,8 @@ public static int IOObjectRelease(int object) { traceDowncall("IOObjectRelease", object); } return (int)mh$.invokeExact(object); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -334,9 +328,9 @@ private static class IOIteratorNext { IOKit.C_INT ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - IOKit.findOrThrow("IOIteratorNext"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("IOIteratorNext"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -358,6 +352,17 @@ private static class IOIteratorNext { public static MethodHandle IOIteratorNext$handle() { return IOIteratorNext.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * io_object_t IOIteratorNext(io_iterator_t iterator) + * } + */ + public static MemorySegment IOIteratorNext$address() { + return IOIteratorNext.ADDR; + } + /** * {@snippet lang=c : * io_object_t IOIteratorNext(io_iterator_t iterator) @@ -370,6 +375,8 @@ public static int IOIteratorNext(int iterator) { traceDowncall("IOIteratorNext", iterator); } return (int)mh$.invokeExact(iterator); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -386,9 +393,9 @@ private static class IOServiceAddMatchingNotification { IOKit.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - IOKit.findOrThrow("IOServiceAddMatchingNotification"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("IOServiceAddMatchingNotification"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -410,6 +417,17 @@ private static class IOServiceAddMatchingNotification { public static MethodHandle IOServiceAddMatchingNotification$handle() { return IOServiceAddMatchingNotification.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * kern_return_t IOServiceAddMatchingNotification(IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void *refCon, io_iterator_t *notification) + * } + */ + public static MemorySegment IOServiceAddMatchingNotification$address() { + return IOServiceAddMatchingNotification.ADDR; + } + /** * {@snippet lang=c : * kern_return_t IOServiceAddMatchingNotification(IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void *refCon, io_iterator_t *notification) @@ -422,6 +440,8 @@ public static int IOServiceAddMatchingNotification(MemorySegment notifyPort, Mem traceDowncall("IOServiceAddMatchingNotification", notifyPort, notificationType, matching, callback, refCon, notification); } return (int)mh$.invokeExact(notifyPort, notificationType, matching, callback, refCon, notification); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -434,9 +454,9 @@ private static class IORegistryEntryGetRegistryEntryID { IOKit.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - IOKit.findOrThrow("IORegistryEntryGetRegistryEntryID"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("IORegistryEntryGetRegistryEntryID"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -458,6 +478,17 @@ private static class IORegistryEntryGetRegistryEntryID { public static MethodHandle IORegistryEntryGetRegistryEntryID$handle() { return IORegistryEntryGetRegistryEntryID.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t *entryID) + * } + */ + public static MemorySegment IORegistryEntryGetRegistryEntryID$address() { + return IORegistryEntryGetRegistryEntryID.ADDR; + } + /** * {@snippet lang=c : * kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t *entryID) @@ -470,6 +501,8 @@ public static int IORegistryEntryGetRegistryEntryID(int entry, MemorySegment ent traceDowncall("IORegistryEntryGetRegistryEntryID", entry, entryID); } return (int)mh$.invokeExact(entry, entryID); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -484,9 +517,9 @@ private static class IORegistryEntryCreateCFProperty { IOKit.C_INT ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - IOKit.findOrThrow("IORegistryEntryCreateCFProperty"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("IORegistryEntryCreateCFProperty"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -508,6 +541,17 @@ private static class IORegistryEntryCreateCFProperty { public static MethodHandle IORegistryEntryCreateCFProperty$handle() { return IORegistryEntryCreateCFProperty.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options) + * } + */ + public static MemorySegment IORegistryEntryCreateCFProperty$address() { + return IORegistryEntryCreateCFProperty.ADDR; + } + /** * {@snippet lang=c : * CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options) @@ -520,6 +564,8 @@ public static MemorySegment IORegistryEntryCreateCFProperty(int entry, MemorySeg traceDowncall("IORegistryEntryCreateCFProperty", entry, key, allocator, options); } return (MemorySegment)mh$.invokeExact(entry, key, allocator, options); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -531,9 +577,9 @@ private static class IOServiceMatching { IOKit.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - IOKit.findOrThrow("IOServiceMatching"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("IOServiceMatching"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -555,6 +601,17 @@ private static class IOServiceMatching { public static MethodHandle IOServiceMatching$handle() { return IOServiceMatching.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * CFMutableDictionaryRef IOServiceMatching(const char *name) + * } + */ + public static MemorySegment IOServiceMatching$address() { + return IOServiceMatching.ADDR; + } + /** * {@snippet lang=c : * CFMutableDictionaryRef IOServiceMatching(const char *name) @@ -567,6 +624,8 @@ public static MemorySegment IOServiceMatching(MemorySegment name) { traceDowncall("IOServiceMatching", name); } return (MemorySegment)mh$.invokeExact(name); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -582,9 +641,9 @@ private static class IOCreatePlugInInterfaceForService { IOKit.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - IOKit.findOrThrow("IOCreatePlugInInterfaceForService"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("IOCreatePlugInInterfaceForService"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -606,6 +665,17 @@ private static class IOCreatePlugInInterfaceForService { public static MethodHandle IOCreatePlugInInterfaceForService$handle() { return IOCreatePlugInInterfaceForService.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * kern_return_t IOCreatePlugInInterfaceForService(io_service_t service, CFUUIDRef pluginType, CFUUIDRef interfaceType, IOCFPlugInInterface ***theInterface, SInt32 *theScore) + * } + */ + public static MemorySegment IOCreatePlugInInterfaceForService$address() { + return IOCreatePlugInInterfaceForService.ADDR; + } + /** * {@snippet lang=c : * kern_return_t IOCreatePlugInInterfaceForService(io_service_t service, CFUUIDRef pluginType, CFUUIDRef interfaceType, IOCFPlugInInterface ***theInterface, SInt32 *theScore) @@ -618,6 +688,8 @@ public static int IOCreatePlugInInterfaceForService(int service, MemorySegment p traceDowncall("IOCreatePlugInInterfaceForService", service, pluginType, interfaceType, theInterface, theScore); } return (int)mh$.invokeExact(service, pluginType, interfaceType, theInterface, theScore); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOServiceAddMatchingNotification$callback.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOServiceAddMatchingNotification$callback.java index c57ad0c0..87fa4df1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOServiceAddMatchingNotification$callback.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOServiceAddMatchingNotification$callback.java @@ -17,9 +17,9 @@ * IOServiceMatchingCallback callback * } */ -public class IOServiceAddMatchingNotification$callback { +public final class IOServiceAddMatchingNotification$callback { - IOServiceAddMatchingNotification$callback() { + private IOServiceAddMatchingNotification$callback() { // Should not be called directly } @@ -57,9 +57,11 @@ public static MemorySegment allocate(IOServiceAddMatchingNotification$callback.F /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static void invoke(MemorySegment funcPtr,MemorySegment _x0, int _x1) { + public static void invoke(MemorySegment funcPtr, MemorySegment _x0, int _x1) { try { DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java index d57579d5..0f65940c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDevRequest.java @@ -61,7 +61,7 @@ public static final GroupLayout layout() { return bmRequestType$LAYOUT; } - private static final long bmRequestType$OFFSET = 0; + private static final long bmRequestType$OFFSET = $LAYOUT.byteOffset(groupElement("bmRequestType")); /** * Offset for field: @@ -105,7 +105,7 @@ public static void bmRequestType(MemorySegment struct, byte fieldValue) { return bRequest$LAYOUT; } - private static final long bRequest$OFFSET = 1; + private static final long bRequest$OFFSET = $LAYOUT.byteOffset(groupElement("bRequest")); /** * Offset for field: @@ -149,7 +149,7 @@ public static void bRequest(MemorySegment struct, byte fieldValue) { return wValue$LAYOUT; } - private static final long wValue$OFFSET = 2; + private static final long wValue$OFFSET = $LAYOUT.byteOffset(groupElement("wValue")); /** * Offset for field: @@ -193,7 +193,7 @@ public static void wValue(MemorySegment struct, short fieldValue) { return wIndex$LAYOUT; } - private static final long wIndex$OFFSET = 4; + private static final long wIndex$OFFSET = $LAYOUT.byteOffset(groupElement("wIndex")); /** * Offset for field: @@ -237,7 +237,7 @@ public static void wIndex(MemorySegment struct, short fieldValue) { return wLength$LAYOUT; } - private static final long wLength$OFFSET = 6; + private static final long wLength$OFFSET = $LAYOUT.byteOffset(groupElement("wLength")); /** * Offset for field: @@ -281,7 +281,7 @@ public static void wLength(MemorySegment struct, short fieldValue) { return pData$LAYOUT; } - private static final long pData$OFFSET = 8; + private static final long pData$OFFSET = $LAYOUT.byteOffset(groupElement("pData")); /** * Offset for field: @@ -325,7 +325,7 @@ public static void pData(MemorySegment struct, MemorySegment fieldValue) { return wLenDone$LAYOUT; } - private static final long wLenDone$OFFSET = 16; + private static final long wLenDone$OFFSET = $LAYOUT.byteOffset(groupElement("wLenDone")); /** * Offset for field: @@ -386,7 +386,7 @@ public static MemorySegment allocateArray(long elementCount, SegmentAllocator al } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { @@ -394,7 +394,7 @@ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consume } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code elementCount * layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java index dbbe8e33..b8bba278 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java @@ -122,7 +122,7 @@ public static final GroupLayout layout() { return _reserved$LAYOUT; } - private static final long _reserved$OFFSET = 0; + private static final long _reserved$OFFSET = $LAYOUT.byteOffset(groupElement("_reserved")); /** * Offset for field: @@ -159,9 +159,9 @@ public static void _reserved(MemorySegment struct, MemorySegment fieldValue) { * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) * } */ - public static class QueryInterface { + public final static class QueryInterface { - QueryInterface() { + private QueryInterface() { // Should not be called directly } @@ -201,9 +201,11 @@ public static MemorySegment allocate(QueryInterface.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -222,7 +224,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return QueryInterface$LAYOUT; } - private static final long QueryInterface$OFFSET = 8; + private static final long QueryInterface$OFFSET = $LAYOUT.byteOffset(groupElement("QueryInterface")); /** * Offset for field: @@ -259,9 +261,9 @@ public static void QueryInterface(MemorySegment struct, MemorySegment fieldValue * ULONG (*AddRef)(void *) * } */ - public static class AddRef { + public final static class AddRef { - AddRef() { + private AddRef() { // Should not be called directly } @@ -299,9 +301,11 @@ public static MemorySegment allocate(AddRef.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -320,7 +324,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { return AddRef$LAYOUT; } - private static final long AddRef$OFFSET = 16; + private static final long AddRef$OFFSET = $LAYOUT.byteOffset(groupElement("AddRef")); /** * Offset for field: @@ -357,9 +361,9 @@ public static void AddRef(MemorySegment struct, MemorySegment fieldValue) { * ULONG (*Release)(void *) * } */ - public static class Release { + public final static class Release { - Release() { + private Release() { // Should not be called directly } @@ -397,9 +401,11 @@ public static MemorySegment allocate(Release.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -418,7 +424,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { return Release$LAYOUT; } - private static final long Release$OFFSET = 24; + private static final long Release$OFFSET = $LAYOUT.byteOffset(groupElement("Release")); /** * Offset for field: @@ -455,9 +461,9 @@ public static void Release(MemorySegment struct, MemorySegment fieldValue) { * IOReturn (*CreateDeviceAsyncEventSource)(void *, CFRunLoopSourceRef *) * } */ - public static class CreateDeviceAsyncEventSource { + public final static class CreateDeviceAsyncEventSource { - CreateDeviceAsyncEventSource() { + private CreateDeviceAsyncEventSource() { // Should not be called directly } @@ -496,9 +502,11 @@ public static MemorySegment allocate(CreateDeviceAsyncEventSource.Function fi, A /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -517,7 +525,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return CreateDeviceAsyncEventSource$LAYOUT; } - private static final long CreateDeviceAsyncEventSource$OFFSET = 32; + private static final long CreateDeviceAsyncEventSource$OFFSET = $LAYOUT.byteOffset(groupElement("CreateDeviceAsyncEventSource")); /** * Offset for field: @@ -554,9 +562,9 @@ public static void CreateDeviceAsyncEventSource(MemorySegment struct, MemorySegm * CFRunLoopSourceRef (*GetDeviceAsyncEventSource)(void *) * } */ - public static class GetDeviceAsyncEventSource { + public final static class GetDeviceAsyncEventSource { - GetDeviceAsyncEventSource() { + private GetDeviceAsyncEventSource() { // Should not be called directly } @@ -594,9 +602,11 @@ public static MemorySegment allocate(GetDeviceAsyncEventSource.Function fi, Aren /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static MemorySegment invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static MemorySegment invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (MemorySegment) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -615,7 +625,7 @@ public static MemorySegment invoke(MemorySegment funcPtr,MemorySegment _x0) { return GetDeviceAsyncEventSource$LAYOUT; } - private static final long GetDeviceAsyncEventSource$OFFSET = 40; + private static final long GetDeviceAsyncEventSource$OFFSET = $LAYOUT.byteOffset(groupElement("GetDeviceAsyncEventSource")); /** * Offset for field: @@ -652,9 +662,9 @@ public static void GetDeviceAsyncEventSource(MemorySegment struct, MemorySegment * IOReturn (*CreateDeviceAsyncPort)(void *, mach_port_t *) * } */ - public static class CreateDeviceAsyncPort { + public final static class CreateDeviceAsyncPort { - CreateDeviceAsyncPort() { + private CreateDeviceAsyncPort() { // Should not be called directly } @@ -693,9 +703,11 @@ public static MemorySegment allocate(CreateDeviceAsyncPort.Function fi, Arena ar /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -714,7 +726,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return CreateDeviceAsyncPort$LAYOUT; } - private static final long CreateDeviceAsyncPort$OFFSET = 48; + private static final long CreateDeviceAsyncPort$OFFSET = $LAYOUT.byteOffset(groupElement("CreateDeviceAsyncPort")); /** * Offset for field: @@ -751,9 +763,9 @@ public static void CreateDeviceAsyncPort(MemorySegment struct, MemorySegment fie * mach_port_t (*GetDeviceAsyncPort)(void *) * } */ - public static class GetDeviceAsyncPort { + public final static class GetDeviceAsyncPort { - GetDeviceAsyncPort() { + private GetDeviceAsyncPort() { // Should not be called directly } @@ -791,9 +803,11 @@ public static MemorySegment allocate(GetDeviceAsyncPort.Function fi, Arena arena /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -812,7 +826,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { return GetDeviceAsyncPort$LAYOUT; } - private static final long GetDeviceAsyncPort$OFFSET = 56; + private static final long GetDeviceAsyncPort$OFFSET = $LAYOUT.byteOffset(groupElement("GetDeviceAsyncPort")); /** * Offset for field: @@ -849,9 +863,9 @@ public static void GetDeviceAsyncPort(MemorySegment struct, MemorySegment fieldV * IOReturn (*USBDeviceOpen)(void *) * } */ - public static class USBDeviceOpen { + public final static class USBDeviceOpen { - USBDeviceOpen() { + private USBDeviceOpen() { // Should not be called directly } @@ -889,9 +903,11 @@ public static MemorySegment allocate(USBDeviceOpen.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -910,7 +926,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { return USBDeviceOpen$LAYOUT; } - private static final long USBDeviceOpen$OFFSET = 64; + private static final long USBDeviceOpen$OFFSET = $LAYOUT.byteOffset(groupElement("USBDeviceOpen")); /** * Offset for field: @@ -947,9 +963,9 @@ public static void USBDeviceOpen(MemorySegment struct, MemorySegment fieldValue) * IOReturn (*USBDeviceClose)(void *) * } */ - public static class USBDeviceClose { + public final static class USBDeviceClose { - USBDeviceClose() { + private USBDeviceClose() { // Should not be called directly } @@ -987,9 +1003,11 @@ public static MemorySegment allocate(USBDeviceClose.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1008,7 +1026,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { return USBDeviceClose$LAYOUT; } - private static final long USBDeviceClose$OFFSET = 72; + private static final long USBDeviceClose$OFFSET = $LAYOUT.byteOffset(groupElement("USBDeviceClose")); /** * Offset for field: @@ -1045,9 +1063,9 @@ public static void USBDeviceClose(MemorySegment struct, MemorySegment fieldValue * IOReturn (*GetDeviceClass)(void *, UInt8 *) * } */ - public static class GetDeviceClass { + public final static class GetDeviceClass { - GetDeviceClass() { + private GetDeviceClass() { // Should not be called directly } @@ -1086,9 +1104,11 @@ public static MemorySegment allocate(GetDeviceClass.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1107,7 +1127,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetDeviceClass$LAYOUT; } - private static final long GetDeviceClass$OFFSET = 80; + private static final long GetDeviceClass$OFFSET = $LAYOUT.byteOffset(groupElement("GetDeviceClass")); /** * Offset for field: @@ -1144,9 +1164,9 @@ public static void GetDeviceClass(MemorySegment struct, MemorySegment fieldValue * IOReturn (*GetDeviceSubClass)(void *, UInt8 *) * } */ - public static class GetDeviceSubClass { + public final static class GetDeviceSubClass { - GetDeviceSubClass() { + private GetDeviceSubClass() { // Should not be called directly } @@ -1185,9 +1205,11 @@ public static MemorySegment allocate(GetDeviceSubClass.Function fi, Arena arena) /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1206,7 +1228,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetDeviceSubClass$LAYOUT; } - private static final long GetDeviceSubClass$OFFSET = 88; + private static final long GetDeviceSubClass$OFFSET = $LAYOUT.byteOffset(groupElement("GetDeviceSubClass")); /** * Offset for field: @@ -1243,9 +1265,9 @@ public static void GetDeviceSubClass(MemorySegment struct, MemorySegment fieldVa * IOReturn (*GetDeviceProtocol)(void *, UInt8 *) * } */ - public static class GetDeviceProtocol { + public final static class GetDeviceProtocol { - GetDeviceProtocol() { + private GetDeviceProtocol() { // Should not be called directly } @@ -1284,9 +1306,11 @@ public static MemorySegment allocate(GetDeviceProtocol.Function fi, Arena arena) /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1305,7 +1329,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetDeviceProtocol$LAYOUT; } - private static final long GetDeviceProtocol$OFFSET = 96; + private static final long GetDeviceProtocol$OFFSET = $LAYOUT.byteOffset(groupElement("GetDeviceProtocol")); /** * Offset for field: @@ -1342,9 +1366,9 @@ public static void GetDeviceProtocol(MemorySegment struct, MemorySegment fieldVa * IOReturn (*GetDeviceVendor)(void *, UInt16 *) * } */ - public static class GetDeviceVendor { + public final static class GetDeviceVendor { - GetDeviceVendor() { + private GetDeviceVendor() { // Should not be called directly } @@ -1383,9 +1407,11 @@ public static MemorySegment allocate(GetDeviceVendor.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1404,7 +1430,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetDeviceVendor$LAYOUT; } - private static final long GetDeviceVendor$OFFSET = 104; + private static final long GetDeviceVendor$OFFSET = $LAYOUT.byteOffset(groupElement("GetDeviceVendor")); /** * Offset for field: @@ -1441,9 +1467,9 @@ public static void GetDeviceVendor(MemorySegment struct, MemorySegment fieldValu * IOReturn (*GetDeviceProduct)(void *, UInt16 *) * } */ - public static class GetDeviceProduct { + public final static class GetDeviceProduct { - GetDeviceProduct() { + private GetDeviceProduct() { // Should not be called directly } @@ -1482,9 +1508,11 @@ public static MemorySegment allocate(GetDeviceProduct.Function fi, Arena arena) /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1503,7 +1531,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetDeviceProduct$LAYOUT; } - private static final long GetDeviceProduct$OFFSET = 112; + private static final long GetDeviceProduct$OFFSET = $LAYOUT.byteOffset(groupElement("GetDeviceProduct")); /** * Offset for field: @@ -1540,9 +1568,9 @@ public static void GetDeviceProduct(MemorySegment struct, MemorySegment fieldVal * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *) * } */ - public static class GetDeviceReleaseNumber { + public final static class GetDeviceReleaseNumber { - GetDeviceReleaseNumber() { + private GetDeviceReleaseNumber() { // Should not be called directly } @@ -1581,9 +1609,11 @@ public static MemorySegment allocate(GetDeviceReleaseNumber.Function fi, Arena a /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1602,7 +1632,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetDeviceReleaseNumber$LAYOUT; } - private static final long GetDeviceReleaseNumber$OFFSET = 120; + private static final long GetDeviceReleaseNumber$OFFSET = $LAYOUT.byteOffset(groupElement("GetDeviceReleaseNumber")); /** * Offset for field: @@ -1639,9 +1669,9 @@ public static void GetDeviceReleaseNumber(MemorySegment struct, MemorySegment fi * IOReturn (*GetDeviceAddress)(void *, USBDeviceAddress *) * } */ - public static class GetDeviceAddress { + public final static class GetDeviceAddress { - GetDeviceAddress() { + private GetDeviceAddress() { // Should not be called directly } @@ -1680,9 +1710,11 @@ public static MemorySegment allocate(GetDeviceAddress.Function fi, Arena arena) /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1701,7 +1733,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetDeviceAddress$LAYOUT; } - private static final long GetDeviceAddress$OFFSET = 128; + private static final long GetDeviceAddress$OFFSET = $LAYOUT.byteOffset(groupElement("GetDeviceAddress")); /** * Offset for field: @@ -1738,9 +1770,9 @@ public static void GetDeviceAddress(MemorySegment struct, MemorySegment fieldVal * IOReturn (*GetDeviceBusPowerAvailable)(void *, UInt32 *) * } */ - public static class GetDeviceBusPowerAvailable { + public final static class GetDeviceBusPowerAvailable { - GetDeviceBusPowerAvailable() { + private GetDeviceBusPowerAvailable() { // Should not be called directly } @@ -1779,9 +1811,11 @@ public static MemorySegment allocate(GetDeviceBusPowerAvailable.Function fi, Are /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1800,7 +1834,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetDeviceBusPowerAvailable$LAYOUT; } - private static final long GetDeviceBusPowerAvailable$OFFSET = 136; + private static final long GetDeviceBusPowerAvailable$OFFSET = $LAYOUT.byteOffset(groupElement("GetDeviceBusPowerAvailable")); /** * Offset for field: @@ -1837,9 +1871,9 @@ public static void GetDeviceBusPowerAvailable(MemorySegment struct, MemorySegmen * IOReturn (*GetDeviceSpeed)(void *, UInt8 *) * } */ - public static class GetDeviceSpeed { + public final static class GetDeviceSpeed { - GetDeviceSpeed() { + private GetDeviceSpeed() { // Should not be called directly } @@ -1878,9 +1912,11 @@ public static MemorySegment allocate(GetDeviceSpeed.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1899,7 +1935,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetDeviceSpeed$LAYOUT; } - private static final long GetDeviceSpeed$OFFSET = 144; + private static final long GetDeviceSpeed$OFFSET = $LAYOUT.byteOffset(groupElement("GetDeviceSpeed")); /** * Offset for field: @@ -1936,9 +1972,9 @@ public static void GetDeviceSpeed(MemorySegment struct, MemorySegment fieldValue * IOReturn (*GetNumberOfConfigurations)(void *, UInt8 *) * } */ - public static class GetNumberOfConfigurations { + public final static class GetNumberOfConfigurations { - GetNumberOfConfigurations() { + private GetNumberOfConfigurations() { // Should not be called directly } @@ -1977,9 +2013,11 @@ public static MemorySegment allocate(GetNumberOfConfigurations.Function fi, Aren /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1998,7 +2036,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetNumberOfConfigurations$LAYOUT; } - private static final long GetNumberOfConfigurations$OFFSET = 152; + private static final long GetNumberOfConfigurations$OFFSET = $LAYOUT.byteOffset(groupElement("GetNumberOfConfigurations")); /** * Offset for field: @@ -2035,9 +2073,9 @@ public static void GetNumberOfConfigurations(MemorySegment struct, MemorySegment * IOReturn (*GetLocationID)(void *, UInt32 *) * } */ - public static class GetLocationID { + public final static class GetLocationID { - GetLocationID() { + private GetLocationID() { // Should not be called directly } @@ -2076,9 +2114,11 @@ public static MemorySegment allocate(GetLocationID.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2097,7 +2137,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetLocationID$LAYOUT; } - private static final long GetLocationID$OFFSET = 160; + private static final long GetLocationID$OFFSET = $LAYOUT.byteOffset(groupElement("GetLocationID")); /** * Offset for field: @@ -2134,9 +2174,9 @@ public static void GetLocationID(MemorySegment struct, MemorySegment fieldValue) * IOReturn (*GetConfigurationDescriptorPtr)(void *, UInt8, IOUSBConfigurationDescriptorPtr *) * } */ - public static class GetConfigurationDescriptorPtr { + public final static class GetConfigurationDescriptorPtr { - GetConfigurationDescriptorPtr() { + private GetConfigurationDescriptorPtr() { // Should not be called directly } @@ -2176,9 +2216,11 @@ public static MemorySegment allocate(GetConfigurationDescriptorPtr.Function fi, /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, MemorySegment _x2) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2197,7 +2239,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, Memo return GetConfigurationDescriptorPtr$LAYOUT; } - private static final long GetConfigurationDescriptorPtr$OFFSET = 168; + private static final long GetConfigurationDescriptorPtr$OFFSET = $LAYOUT.byteOffset(groupElement("GetConfigurationDescriptorPtr")); /** * Offset for field: @@ -2234,9 +2276,9 @@ public static void GetConfigurationDescriptorPtr(MemorySegment struct, MemorySeg * IOReturn (*GetConfiguration)(void *, UInt8 *) * } */ - public static class GetConfiguration { + public final static class GetConfiguration { - GetConfiguration() { + private GetConfiguration() { // Should not be called directly } @@ -2275,9 +2317,11 @@ public static MemorySegment allocate(GetConfiguration.Function fi, Arena arena) /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2296,7 +2340,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetConfiguration$LAYOUT; } - private static final long GetConfiguration$OFFSET = 176; + private static final long GetConfiguration$OFFSET = $LAYOUT.byteOffset(groupElement("GetConfiguration")); /** * Offset for field: @@ -2333,9 +2377,9 @@ public static void GetConfiguration(MemorySegment struct, MemorySegment fieldVal * IOReturn (*SetConfiguration)(void *, UInt8) * } */ - public static class SetConfiguration { + public final static class SetConfiguration { - SetConfiguration() { + private SetConfiguration() { // Should not be called directly } @@ -2374,9 +2418,11 @@ public static MemorySegment allocate(SetConfiguration.Function fi, Arena arena) /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2395,7 +2441,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { return SetConfiguration$LAYOUT; } - private static final long SetConfiguration$OFFSET = 184; + private static final long SetConfiguration$OFFSET = $LAYOUT.byteOffset(groupElement("SetConfiguration")); /** * Offset for field: @@ -2432,9 +2478,9 @@ public static void SetConfiguration(MemorySegment struct, MemorySegment fieldVal * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *) * } */ - public static class GetBusFrameNumber { + public final static class GetBusFrameNumber { - GetBusFrameNumber() { + private GetBusFrameNumber() { // Should not be called directly } @@ -2474,9 +2520,11 @@ public static MemorySegment allocate(GetBusFrameNumber.Function fi, Arena arena) /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2495,7 +2543,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetBusFrameNumber$LAYOUT; } - private static final long GetBusFrameNumber$OFFSET = 192; + private static final long GetBusFrameNumber$OFFSET = $LAYOUT.byteOffset(groupElement("GetBusFrameNumber")); /** * Offset for field: @@ -2532,9 +2580,9 @@ public static void GetBusFrameNumber(MemorySegment struct, MemorySegment fieldVa * IOReturn (*ResetDevice)(void *) * } */ - public static class ResetDevice { + public final static class ResetDevice { - ResetDevice() { + private ResetDevice() { // Should not be called directly } @@ -2572,9 +2620,11 @@ public static MemorySegment allocate(ResetDevice.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2593,7 +2643,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { return ResetDevice$LAYOUT; } - private static final long ResetDevice$OFFSET = 200; + private static final long ResetDevice$OFFSET = $LAYOUT.byteOffset(groupElement("ResetDevice")); /** * Offset for field: @@ -2630,9 +2680,9 @@ public static void ResetDevice(MemorySegment struct, MemorySegment fieldValue) { * IOReturn (*DeviceRequest)(void *, IOUSBDevRequest *) * } */ - public static class DeviceRequest { + public final static class DeviceRequest { - DeviceRequest() { + private DeviceRequest() { // Should not be called directly } @@ -2671,9 +2721,11 @@ public static MemorySegment allocate(DeviceRequest.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2692,7 +2744,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return DeviceRequest$LAYOUT; } - private static final long DeviceRequest$OFFSET = 208; + private static final long DeviceRequest$OFFSET = $LAYOUT.byteOffset(groupElement("DeviceRequest")); /** * Offset for field: @@ -2729,9 +2781,9 @@ public static void DeviceRequest(MemorySegment struct, MemorySegment fieldValue) * IOReturn (*DeviceRequestAsync)(void *, IOUSBDevRequest *, IOAsyncCallback1, void *) * } */ - public static class DeviceRequestAsync { + public final static class DeviceRequestAsync { - DeviceRequestAsync() { + private DeviceRequestAsync() { // Should not be called directly } @@ -2772,9 +2824,11 @@ public static MemorySegment allocate(DeviceRequestAsync.Function fi, Arena arena /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, MemorySegment _x2, MemorySegment _x3) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1, MemorySegment _x2, MemorySegment _x3) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2793,7 +2847,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return DeviceRequestAsync$LAYOUT; } - private static final long DeviceRequestAsync$OFFSET = 216; + private static final long DeviceRequestAsync$OFFSET = $LAYOUT.byteOffset(groupElement("DeviceRequestAsync")); /** * Offset for field: @@ -2830,9 +2884,9 @@ public static void DeviceRequestAsync(MemorySegment struct, MemorySegment fieldV * IOReturn (*CreateInterfaceIterator)(void *, IOUSBFindInterfaceRequest *, io_iterator_t *) * } */ - public static class CreateInterfaceIterator { + public final static class CreateInterfaceIterator { - CreateInterfaceIterator() { + private CreateInterfaceIterator() { // Should not be called directly } @@ -2872,9 +2926,11 @@ public static MemorySegment allocate(CreateInterfaceIterator.Function fi, Arena /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2893,7 +2949,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return CreateInterfaceIterator$LAYOUT; } - private static final long CreateInterfaceIterator$OFFSET = 224; + private static final long CreateInterfaceIterator$OFFSET = $LAYOUT.byteOffset(groupElement("CreateInterfaceIterator")); /** * Offset for field: @@ -2930,9 +2986,9 @@ public static void CreateInterfaceIterator(MemorySegment struct, MemorySegment f * IOReturn (*USBDeviceOpenSeize)(void *) * } */ - public static class USBDeviceOpenSeize { + public final static class USBDeviceOpenSeize { - USBDeviceOpenSeize() { + private USBDeviceOpenSeize() { // Should not be called directly } @@ -2970,9 +3026,11 @@ public static MemorySegment allocate(USBDeviceOpenSeize.Function fi, Arena arena /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2991,7 +3049,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { return USBDeviceOpenSeize$LAYOUT; } - private static final long USBDeviceOpenSeize$OFFSET = 232; + private static final long USBDeviceOpenSeize$OFFSET = $LAYOUT.byteOffset(groupElement("USBDeviceOpenSeize")); /** * Offset for field: @@ -3028,9 +3086,9 @@ public static void USBDeviceOpenSeize(MemorySegment struct, MemorySegment fieldV * IOReturn (*DeviceRequestTO)(void *, IOUSBDevRequestTO *) * } */ - public static class DeviceRequestTO { + public final static class DeviceRequestTO { - DeviceRequestTO() { + private DeviceRequestTO() { // Should not be called directly } @@ -3069,9 +3127,11 @@ public static MemorySegment allocate(DeviceRequestTO.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3090,7 +3150,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return DeviceRequestTO$LAYOUT; } - private static final long DeviceRequestTO$OFFSET = 240; + private static final long DeviceRequestTO$OFFSET = $LAYOUT.byteOffset(groupElement("DeviceRequestTO")); /** * Offset for field: @@ -3127,9 +3187,9 @@ public static void DeviceRequestTO(MemorySegment struct, MemorySegment fieldValu * IOReturn (*DeviceRequestAsyncTO)(void *, IOUSBDevRequestTO *, IOAsyncCallback1, void *) * } */ - public static class DeviceRequestAsyncTO { + public final static class DeviceRequestAsyncTO { - DeviceRequestAsyncTO() { + private DeviceRequestAsyncTO() { // Should not be called directly } @@ -3170,9 +3230,11 @@ public static MemorySegment allocate(DeviceRequestAsyncTO.Function fi, Arena are /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, MemorySegment _x2, MemorySegment _x3) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1, MemorySegment _x2, MemorySegment _x3) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3191,7 +3253,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return DeviceRequestAsyncTO$LAYOUT; } - private static final long DeviceRequestAsyncTO$OFFSET = 248; + private static final long DeviceRequestAsyncTO$OFFSET = $LAYOUT.byteOffset(groupElement("DeviceRequestAsyncTO")); /** * Offset for field: @@ -3228,9 +3290,9 @@ public static void DeviceRequestAsyncTO(MemorySegment struct, MemorySegment fiel * IOReturn (*USBDeviceSuspend)(void *, Boolean) * } */ - public static class USBDeviceSuspend { + public final static class USBDeviceSuspend { - USBDeviceSuspend() { + private USBDeviceSuspend() { // Should not be called directly } @@ -3269,9 +3331,11 @@ public static MemorySegment allocate(USBDeviceSuspend.Function fi, Arena arena) /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3290,7 +3354,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { return USBDeviceSuspend$LAYOUT; } - private static final long USBDeviceSuspend$OFFSET = 256; + private static final long USBDeviceSuspend$OFFSET = $LAYOUT.byteOffset(groupElement("USBDeviceSuspend")); /** * Offset for field: @@ -3327,9 +3391,9 @@ public static void USBDeviceSuspend(MemorySegment struct, MemorySegment fieldVal * IOReturn (*USBDeviceAbortPipeZero)(void *) * } */ - public static class USBDeviceAbortPipeZero { + public final static class USBDeviceAbortPipeZero { - USBDeviceAbortPipeZero() { + private USBDeviceAbortPipeZero() { // Should not be called directly } @@ -3367,9 +3431,11 @@ public static MemorySegment allocate(USBDeviceAbortPipeZero.Function fi, Arena a /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3388,7 +3454,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { return USBDeviceAbortPipeZero$LAYOUT; } - private static final long USBDeviceAbortPipeZero$OFFSET = 264; + private static final long USBDeviceAbortPipeZero$OFFSET = $LAYOUT.byteOffset(groupElement("USBDeviceAbortPipeZero")); /** * Offset for field: @@ -3425,9 +3491,9 @@ public static void USBDeviceAbortPipeZero(MemorySegment struct, MemorySegment fi * IOReturn (*USBGetManufacturerStringIndex)(void *, UInt8 *) * } */ - public static class USBGetManufacturerStringIndex { + public final static class USBGetManufacturerStringIndex { - USBGetManufacturerStringIndex() { + private USBGetManufacturerStringIndex() { // Should not be called directly } @@ -3466,9 +3532,11 @@ public static MemorySegment allocate(USBGetManufacturerStringIndex.Function fi, /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3487,7 +3555,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return USBGetManufacturerStringIndex$LAYOUT; } - private static final long USBGetManufacturerStringIndex$OFFSET = 272; + private static final long USBGetManufacturerStringIndex$OFFSET = $LAYOUT.byteOffset(groupElement("USBGetManufacturerStringIndex")); /** * Offset for field: @@ -3524,9 +3592,9 @@ public static void USBGetManufacturerStringIndex(MemorySegment struct, MemorySeg * IOReturn (*USBGetProductStringIndex)(void *, UInt8 *) * } */ - public static class USBGetProductStringIndex { + public final static class USBGetProductStringIndex { - USBGetProductStringIndex() { + private USBGetProductStringIndex() { // Should not be called directly } @@ -3565,9 +3633,11 @@ public static MemorySegment allocate(USBGetProductStringIndex.Function fi, Arena /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3586,7 +3656,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return USBGetProductStringIndex$LAYOUT; } - private static final long USBGetProductStringIndex$OFFSET = 280; + private static final long USBGetProductStringIndex$OFFSET = $LAYOUT.byteOffset(groupElement("USBGetProductStringIndex")); /** * Offset for field: @@ -3623,9 +3693,9 @@ public static void USBGetProductStringIndex(MemorySegment struct, MemorySegment * IOReturn (*USBGetSerialNumberStringIndex)(void *, UInt8 *) * } */ - public static class USBGetSerialNumberStringIndex { + public final static class USBGetSerialNumberStringIndex { - USBGetSerialNumberStringIndex() { + private USBGetSerialNumberStringIndex() { // Should not be called directly } @@ -3664,9 +3734,11 @@ public static MemorySegment allocate(USBGetSerialNumberStringIndex.Function fi, /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3685,7 +3757,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return USBGetSerialNumberStringIndex$LAYOUT; } - private static final long USBGetSerialNumberStringIndex$OFFSET = 288; + private static final long USBGetSerialNumberStringIndex$OFFSET = $LAYOUT.byteOffset(groupElement("USBGetSerialNumberStringIndex")); /** * Offset for field: @@ -3722,9 +3794,9 @@ public static void USBGetSerialNumberStringIndex(MemorySegment struct, MemorySeg * IOReturn (*USBDeviceReEnumerate)(void *, UInt32) * } */ - public static class USBDeviceReEnumerate { + public final static class USBDeviceReEnumerate { - USBDeviceReEnumerate() { + private USBDeviceReEnumerate() { // Should not be called directly } @@ -3763,9 +3835,11 @@ public static MemorySegment allocate(USBDeviceReEnumerate.Function fi, Arena are /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, int _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, int _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3784,7 +3858,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, int _x1) { return USBDeviceReEnumerate$LAYOUT; } - private static final long USBDeviceReEnumerate$OFFSET = 296; + private static final long USBDeviceReEnumerate$OFFSET = $LAYOUT.byteOffset(groupElement("USBDeviceReEnumerate")); /** * Offset for field: @@ -3845,7 +3919,7 @@ public static MemorySegment allocateArray(long elementCount, SegmentAllocator al } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { @@ -3853,7 +3927,7 @@ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consume } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code elementCount * layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java index 9f543412..e0ded3eb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBFindInterfaceRequest.java @@ -54,7 +54,7 @@ public static final GroupLayout layout() { return bInterfaceClass$LAYOUT; } - private static final long bInterfaceClass$OFFSET = 0; + private static final long bInterfaceClass$OFFSET = $LAYOUT.byteOffset(groupElement("bInterfaceClass")); /** * Offset for field: @@ -98,7 +98,7 @@ public static void bInterfaceClass(MemorySegment struct, short fieldValue) { return bInterfaceSubClass$LAYOUT; } - private static final long bInterfaceSubClass$OFFSET = 2; + private static final long bInterfaceSubClass$OFFSET = $LAYOUT.byteOffset(groupElement("bInterfaceSubClass")); /** * Offset for field: @@ -142,7 +142,7 @@ public static void bInterfaceSubClass(MemorySegment struct, short fieldValue) { return bInterfaceProtocol$LAYOUT; } - private static final long bInterfaceProtocol$OFFSET = 4; + private static final long bInterfaceProtocol$OFFSET = $LAYOUT.byteOffset(groupElement("bInterfaceProtocol")); /** * Offset for field: @@ -186,7 +186,7 @@ public static void bInterfaceProtocol(MemorySegment struct, short fieldValue) { return bAlternateSetting$LAYOUT; } - private static final long bAlternateSetting$OFFSET = 6; + private static final long bAlternateSetting$OFFSET = $LAYOUT.byteOffset(groupElement("bAlternateSetting")); /** * Offset for field: @@ -247,7 +247,7 @@ public static MemorySegment allocateArray(long elementCount, SegmentAllocator al } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { @@ -255,7 +255,7 @@ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consume } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code elementCount * layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java index 46cc32e1..ddcc6243 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java @@ -144,7 +144,7 @@ public static final GroupLayout layout() { return _reserved$LAYOUT; } - private static final long _reserved$OFFSET = 0; + private static final long _reserved$OFFSET = $LAYOUT.byteOffset(groupElement("_reserved")); /** * Offset for field: @@ -181,9 +181,9 @@ public static void _reserved(MemorySegment struct, MemorySegment fieldValue) { * HRESULT (*QueryInterface)(void *, REFIID, LPVOID *) * } */ - public static class QueryInterface { + public final static class QueryInterface { - QueryInterface() { + private QueryInterface() { // Should not be called directly } @@ -223,9 +223,11 @@ public static MemorySegment allocate(QueryInterface.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -244,7 +246,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return QueryInterface$LAYOUT; } - private static final long QueryInterface$OFFSET = 8; + private static final long QueryInterface$OFFSET = $LAYOUT.byteOffset(groupElement("QueryInterface")); /** * Offset for field: @@ -281,9 +283,9 @@ public static void QueryInterface(MemorySegment struct, MemorySegment fieldValue * ULONG (*AddRef)(void *) * } */ - public static class AddRef { + public final static class AddRef { - AddRef() { + private AddRef() { // Should not be called directly } @@ -321,9 +323,11 @@ public static MemorySegment allocate(AddRef.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -342,7 +346,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { return AddRef$LAYOUT; } - private static final long AddRef$OFFSET = 16; + private static final long AddRef$OFFSET = $LAYOUT.byteOffset(groupElement("AddRef")); /** * Offset for field: @@ -379,9 +383,9 @@ public static void AddRef(MemorySegment struct, MemorySegment fieldValue) { * ULONG (*Release)(void *) * } */ - public static class Release { + public final static class Release { - Release() { + private Release() { // Should not be called directly } @@ -419,9 +423,11 @@ public static MemorySegment allocate(Release.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -440,7 +446,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { return Release$LAYOUT; } - private static final long Release$OFFSET = 24; + private static final long Release$OFFSET = $LAYOUT.byteOffset(groupElement("Release")); /** * Offset for field: @@ -477,9 +483,9 @@ public static void Release(MemorySegment struct, MemorySegment fieldValue) { * IOReturn (*CreateInterfaceAsyncEventSource)(void *, CFRunLoopSourceRef *) * } */ - public static class CreateInterfaceAsyncEventSource { + public final static class CreateInterfaceAsyncEventSource { - CreateInterfaceAsyncEventSource() { + private CreateInterfaceAsyncEventSource() { // Should not be called directly } @@ -518,9 +524,11 @@ public static MemorySegment allocate(CreateInterfaceAsyncEventSource.Function fi /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -539,7 +547,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return CreateInterfaceAsyncEventSource$LAYOUT; } - private static final long CreateInterfaceAsyncEventSource$OFFSET = 32; + private static final long CreateInterfaceAsyncEventSource$OFFSET = $LAYOUT.byteOffset(groupElement("CreateInterfaceAsyncEventSource")); /** * Offset for field: @@ -576,9 +584,9 @@ public static void CreateInterfaceAsyncEventSource(MemorySegment struct, MemoryS * CFRunLoopSourceRef (*GetInterfaceAsyncEventSource)(void *) * } */ - public static class GetInterfaceAsyncEventSource { + public final static class GetInterfaceAsyncEventSource { - GetInterfaceAsyncEventSource() { + private GetInterfaceAsyncEventSource() { // Should not be called directly } @@ -616,9 +624,11 @@ public static MemorySegment allocate(GetInterfaceAsyncEventSource.Function fi, A /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static MemorySegment invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static MemorySegment invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (MemorySegment) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -637,7 +647,7 @@ public static MemorySegment invoke(MemorySegment funcPtr,MemorySegment _x0) { return GetInterfaceAsyncEventSource$LAYOUT; } - private static final long GetInterfaceAsyncEventSource$OFFSET = 40; + private static final long GetInterfaceAsyncEventSource$OFFSET = $LAYOUT.byteOffset(groupElement("GetInterfaceAsyncEventSource")); /** * Offset for field: @@ -674,9 +684,9 @@ public static void GetInterfaceAsyncEventSource(MemorySegment struct, MemorySegm * IOReturn (*CreateInterfaceAsyncPort)(void *, mach_port_t *) * } */ - public static class CreateInterfaceAsyncPort { + public final static class CreateInterfaceAsyncPort { - CreateInterfaceAsyncPort() { + private CreateInterfaceAsyncPort() { // Should not be called directly } @@ -715,9 +725,11 @@ public static MemorySegment allocate(CreateInterfaceAsyncPort.Function fi, Arena /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -736,7 +748,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return CreateInterfaceAsyncPort$LAYOUT; } - private static final long CreateInterfaceAsyncPort$OFFSET = 48; + private static final long CreateInterfaceAsyncPort$OFFSET = $LAYOUT.byteOffset(groupElement("CreateInterfaceAsyncPort")); /** * Offset for field: @@ -773,9 +785,9 @@ public static void CreateInterfaceAsyncPort(MemorySegment struct, MemorySegment * mach_port_t (*GetInterfaceAsyncPort)(void *) * } */ - public static class GetInterfaceAsyncPort { + public final static class GetInterfaceAsyncPort { - GetInterfaceAsyncPort() { + private GetInterfaceAsyncPort() { // Should not be called directly } @@ -813,9 +825,11 @@ public static MemorySegment allocate(GetInterfaceAsyncPort.Function fi, Arena ar /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -834,7 +848,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { return GetInterfaceAsyncPort$LAYOUT; } - private static final long GetInterfaceAsyncPort$OFFSET = 56; + private static final long GetInterfaceAsyncPort$OFFSET = $LAYOUT.byteOffset(groupElement("GetInterfaceAsyncPort")); /** * Offset for field: @@ -871,9 +885,9 @@ public static void GetInterfaceAsyncPort(MemorySegment struct, MemorySegment fie * IOReturn (*USBInterfaceOpen)(void *) * } */ - public static class USBInterfaceOpen { + public final static class USBInterfaceOpen { - USBInterfaceOpen() { + private USBInterfaceOpen() { // Should not be called directly } @@ -911,9 +925,11 @@ public static MemorySegment allocate(USBInterfaceOpen.Function fi, Arena arena) /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -932,7 +948,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { return USBInterfaceOpen$LAYOUT; } - private static final long USBInterfaceOpen$OFFSET = 64; + private static final long USBInterfaceOpen$OFFSET = $LAYOUT.byteOffset(groupElement("USBInterfaceOpen")); /** * Offset for field: @@ -969,9 +985,9 @@ public static void USBInterfaceOpen(MemorySegment struct, MemorySegment fieldVal * IOReturn (*USBInterfaceClose)(void *) * } */ - public static class USBInterfaceClose { + public final static class USBInterfaceClose { - USBInterfaceClose() { + private USBInterfaceClose() { // Should not be called directly } @@ -1009,9 +1025,11 @@ public static MemorySegment allocate(USBInterfaceClose.Function fi, Arena arena) /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1030,7 +1048,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { return USBInterfaceClose$LAYOUT; } - private static final long USBInterfaceClose$OFFSET = 72; + private static final long USBInterfaceClose$OFFSET = $LAYOUT.byteOffset(groupElement("USBInterfaceClose")); /** * Offset for field: @@ -1067,9 +1085,9 @@ public static void USBInterfaceClose(MemorySegment struct, MemorySegment fieldVa * IOReturn (*GetInterfaceClass)(void *, UInt8 *) * } */ - public static class GetInterfaceClass { + public final static class GetInterfaceClass { - GetInterfaceClass() { + private GetInterfaceClass() { // Should not be called directly } @@ -1108,9 +1126,11 @@ public static MemorySegment allocate(GetInterfaceClass.Function fi, Arena arena) /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1129,7 +1149,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetInterfaceClass$LAYOUT; } - private static final long GetInterfaceClass$OFFSET = 80; + private static final long GetInterfaceClass$OFFSET = $LAYOUT.byteOffset(groupElement("GetInterfaceClass")); /** * Offset for field: @@ -1166,9 +1186,9 @@ public static void GetInterfaceClass(MemorySegment struct, MemorySegment fieldVa * IOReturn (*GetInterfaceSubClass)(void *, UInt8 *) * } */ - public static class GetInterfaceSubClass { + public final static class GetInterfaceSubClass { - GetInterfaceSubClass() { + private GetInterfaceSubClass() { // Should not be called directly } @@ -1207,9 +1227,11 @@ public static MemorySegment allocate(GetInterfaceSubClass.Function fi, Arena are /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1228,7 +1250,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetInterfaceSubClass$LAYOUT; } - private static final long GetInterfaceSubClass$OFFSET = 88; + private static final long GetInterfaceSubClass$OFFSET = $LAYOUT.byteOffset(groupElement("GetInterfaceSubClass")); /** * Offset for field: @@ -1265,9 +1287,9 @@ public static void GetInterfaceSubClass(MemorySegment struct, MemorySegment fiel * IOReturn (*GetInterfaceProtocol)(void *, UInt8 *) * } */ - public static class GetInterfaceProtocol { + public final static class GetInterfaceProtocol { - GetInterfaceProtocol() { + private GetInterfaceProtocol() { // Should not be called directly } @@ -1306,9 +1328,11 @@ public static MemorySegment allocate(GetInterfaceProtocol.Function fi, Arena are /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1327,7 +1351,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetInterfaceProtocol$LAYOUT; } - private static final long GetInterfaceProtocol$OFFSET = 96; + private static final long GetInterfaceProtocol$OFFSET = $LAYOUT.byteOffset(groupElement("GetInterfaceProtocol")); /** * Offset for field: @@ -1364,9 +1388,9 @@ public static void GetInterfaceProtocol(MemorySegment struct, MemorySegment fiel * IOReturn (*GetDeviceVendor)(void *, UInt16 *) * } */ - public static class GetDeviceVendor { + public final static class GetDeviceVendor { - GetDeviceVendor() { + private GetDeviceVendor() { // Should not be called directly } @@ -1405,9 +1429,11 @@ public static MemorySegment allocate(GetDeviceVendor.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1426,7 +1452,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetDeviceVendor$LAYOUT; } - private static final long GetDeviceVendor$OFFSET = 104; + private static final long GetDeviceVendor$OFFSET = $LAYOUT.byteOffset(groupElement("GetDeviceVendor")); /** * Offset for field: @@ -1463,9 +1489,9 @@ public static void GetDeviceVendor(MemorySegment struct, MemorySegment fieldValu * IOReturn (*GetDeviceProduct)(void *, UInt16 *) * } */ - public static class GetDeviceProduct { + public final static class GetDeviceProduct { - GetDeviceProduct() { + private GetDeviceProduct() { // Should not be called directly } @@ -1504,9 +1530,11 @@ public static MemorySegment allocate(GetDeviceProduct.Function fi, Arena arena) /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1525,7 +1553,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetDeviceProduct$LAYOUT; } - private static final long GetDeviceProduct$OFFSET = 112; + private static final long GetDeviceProduct$OFFSET = $LAYOUT.byteOffset(groupElement("GetDeviceProduct")); /** * Offset for field: @@ -1562,9 +1590,9 @@ public static void GetDeviceProduct(MemorySegment struct, MemorySegment fieldVal * IOReturn (*GetDeviceReleaseNumber)(void *, UInt16 *) * } */ - public static class GetDeviceReleaseNumber { + public final static class GetDeviceReleaseNumber { - GetDeviceReleaseNumber() { + private GetDeviceReleaseNumber() { // Should not be called directly } @@ -1603,9 +1631,11 @@ public static MemorySegment allocate(GetDeviceReleaseNumber.Function fi, Arena a /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1624,7 +1654,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetDeviceReleaseNumber$LAYOUT; } - private static final long GetDeviceReleaseNumber$OFFSET = 120; + private static final long GetDeviceReleaseNumber$OFFSET = $LAYOUT.byteOffset(groupElement("GetDeviceReleaseNumber")); /** * Offset for field: @@ -1661,9 +1691,9 @@ public static void GetDeviceReleaseNumber(MemorySegment struct, MemorySegment fi * IOReturn (*GetConfigurationValue)(void *, UInt8 *) * } */ - public static class GetConfigurationValue { + public final static class GetConfigurationValue { - GetConfigurationValue() { + private GetConfigurationValue() { // Should not be called directly } @@ -1702,9 +1732,11 @@ public static MemorySegment allocate(GetConfigurationValue.Function fi, Arena ar /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1723,7 +1755,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetConfigurationValue$LAYOUT; } - private static final long GetConfigurationValue$OFFSET = 128; + private static final long GetConfigurationValue$OFFSET = $LAYOUT.byteOffset(groupElement("GetConfigurationValue")); /** * Offset for field: @@ -1760,9 +1792,9 @@ public static void GetConfigurationValue(MemorySegment struct, MemorySegment fie * IOReturn (*GetInterfaceNumber)(void *, UInt8 *) * } */ - public static class GetInterfaceNumber { + public final static class GetInterfaceNumber { - GetInterfaceNumber() { + private GetInterfaceNumber() { // Should not be called directly } @@ -1801,9 +1833,11 @@ public static MemorySegment allocate(GetInterfaceNumber.Function fi, Arena arena /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1822,7 +1856,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetInterfaceNumber$LAYOUT; } - private static final long GetInterfaceNumber$OFFSET = 136; + private static final long GetInterfaceNumber$OFFSET = $LAYOUT.byteOffset(groupElement("GetInterfaceNumber")); /** * Offset for field: @@ -1859,9 +1893,9 @@ public static void GetInterfaceNumber(MemorySegment struct, MemorySegment fieldV * IOReturn (*GetAlternateSetting)(void *, UInt8 *) * } */ - public static class GetAlternateSetting { + public final static class GetAlternateSetting { - GetAlternateSetting() { + private GetAlternateSetting() { // Should not be called directly } @@ -1900,9 +1934,11 @@ public static MemorySegment allocate(GetAlternateSetting.Function fi, Arena aren /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -1921,7 +1957,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetAlternateSetting$LAYOUT; } - private static final long GetAlternateSetting$OFFSET = 144; + private static final long GetAlternateSetting$OFFSET = $LAYOUT.byteOffset(groupElement("GetAlternateSetting")); /** * Offset for field: @@ -1958,9 +1994,9 @@ public static void GetAlternateSetting(MemorySegment struct, MemorySegment field * IOReturn (*GetNumEndpoints)(void *, UInt8 *) * } */ - public static class GetNumEndpoints { + public final static class GetNumEndpoints { - GetNumEndpoints() { + private GetNumEndpoints() { // Should not be called directly } @@ -1999,9 +2035,11 @@ public static MemorySegment allocate(GetNumEndpoints.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2020,7 +2058,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetNumEndpoints$LAYOUT; } - private static final long GetNumEndpoints$OFFSET = 152; + private static final long GetNumEndpoints$OFFSET = $LAYOUT.byteOffset(groupElement("GetNumEndpoints")); /** * Offset for field: @@ -2057,9 +2095,9 @@ public static void GetNumEndpoints(MemorySegment struct, MemorySegment fieldValu * IOReturn (*GetLocationID)(void *, UInt32 *) * } */ - public static class GetLocationID { + public final static class GetLocationID { - GetLocationID() { + private GetLocationID() { // Should not be called directly } @@ -2098,9 +2136,11 @@ public static MemorySegment allocate(GetLocationID.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2119,7 +2159,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetLocationID$LAYOUT; } - private static final long GetLocationID$OFFSET = 160; + private static final long GetLocationID$OFFSET = $LAYOUT.byteOffset(groupElement("GetLocationID")); /** * Offset for field: @@ -2156,9 +2196,9 @@ public static void GetLocationID(MemorySegment struct, MemorySegment fieldValue) * IOReturn (*GetDevice)(void *, io_service_t *) * } */ - public static class GetDevice { + public final static class GetDevice { - GetDevice() { + private GetDevice() { // Should not be called directly } @@ -2197,9 +2237,11 @@ public static MemorySegment allocate(GetDevice.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2218,7 +2260,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetDevice$LAYOUT; } - private static final long GetDevice$OFFSET = 168; + private static final long GetDevice$OFFSET = $LAYOUT.byteOffset(groupElement("GetDevice")); /** * Offset for field: @@ -2255,9 +2297,9 @@ public static void GetDevice(MemorySegment struct, MemorySegment fieldValue) { * IOReturn (*SetAlternateInterface)(void *, UInt8) * } */ - public static class SetAlternateInterface { + public final static class SetAlternateInterface { - SetAlternateInterface() { + private SetAlternateInterface() { // Should not be called directly } @@ -2296,9 +2338,11 @@ public static MemorySegment allocate(SetAlternateInterface.Function fi, Arena ar /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2317,7 +2361,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { return SetAlternateInterface$LAYOUT; } - private static final long SetAlternateInterface$OFFSET = 176; + private static final long SetAlternateInterface$OFFSET = $LAYOUT.byteOffset(groupElement("SetAlternateInterface")); /** * Offset for field: @@ -2354,9 +2398,9 @@ public static void SetAlternateInterface(MemorySegment struct, MemorySegment fie * IOReturn (*GetBusFrameNumber)(void *, UInt64 *, AbsoluteTime *) * } */ - public static class GetBusFrameNumber { + public final static class GetBusFrameNumber { - GetBusFrameNumber() { + private GetBusFrameNumber() { // Should not be called directly } @@ -2396,9 +2440,11 @@ public static MemorySegment allocate(GetBusFrameNumber.Function fi, Arena arena) /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1, MemorySegment _x2) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2417,7 +2463,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetBusFrameNumber$LAYOUT; } - private static final long GetBusFrameNumber$OFFSET = 184; + private static final long GetBusFrameNumber$OFFSET = $LAYOUT.byteOffset(groupElement("GetBusFrameNumber")); /** * Offset for field: @@ -2454,9 +2500,9 @@ public static void GetBusFrameNumber(MemorySegment struct, MemorySegment fieldVa * IOReturn (*ControlRequest)(void *, UInt8, IOUSBDevRequest *) * } */ - public static class ControlRequest { + public final static class ControlRequest { - ControlRequest() { + private ControlRequest() { // Should not be called directly } @@ -2496,9 +2542,11 @@ public static MemorySegment allocate(ControlRequest.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, MemorySegment _x2) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2517,7 +2565,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, Memo return ControlRequest$LAYOUT; } - private static final long ControlRequest$OFFSET = 192; + private static final long ControlRequest$OFFSET = $LAYOUT.byteOffset(groupElement("ControlRequest")); /** * Offset for field: @@ -2554,9 +2602,9 @@ public static void ControlRequest(MemorySegment struct, MemorySegment fieldValue * IOReturn (*ControlRequestAsync)(void *, UInt8, IOUSBDevRequest *, IOAsyncCallback1, void *) * } */ - public static class ControlRequestAsync { + public final static class ControlRequestAsync { - ControlRequestAsync() { + private ControlRequestAsync() { // Should not be called directly } @@ -2598,9 +2646,11 @@ public static MemorySegment allocate(ControlRequestAsync.Function fi, Arena aren /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, MemorySegment _x4) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, MemorySegment _x4) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2619,7 +2669,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, Memo return ControlRequestAsync$LAYOUT; } - private static final long ControlRequestAsync$OFFSET = 200; + private static final long ControlRequestAsync$OFFSET = $LAYOUT.byteOffset(groupElement("ControlRequestAsync")); /** * Offset for field: @@ -2656,9 +2706,9 @@ public static void ControlRequestAsync(MemorySegment struct, MemorySegment field * IOReturn (*GetPipeProperties)(void *, UInt8, UInt8 *, UInt8 *, UInt8 *, UInt16 *, UInt8 *) * } */ - public static class GetPipeProperties { + public final static class GetPipeProperties { - GetPipeProperties() { + private GetPipeProperties() { // Should not be called directly } @@ -2702,9 +2752,11 @@ public static MemorySegment allocate(GetPipeProperties.Function fi, Arena arena) /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, MemorySegment _x4, MemorySegment _x5, MemorySegment _x6) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, MemorySegment _x4, MemorySegment _x5, MemorySegment _x6) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5, _x6); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2723,7 +2775,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, Memo return GetPipeProperties$LAYOUT; } - private static final long GetPipeProperties$OFFSET = 208; + private static final long GetPipeProperties$OFFSET = $LAYOUT.byteOffset(groupElement("GetPipeProperties")); /** * Offset for field: @@ -2760,9 +2812,9 @@ public static void GetPipeProperties(MemorySegment struct, MemorySegment fieldVa * IOReturn (*GetPipeStatus)(void *, UInt8) * } */ - public static class GetPipeStatus { + public final static class GetPipeStatus { - GetPipeStatus() { + private GetPipeStatus() { // Should not be called directly } @@ -2801,9 +2853,11 @@ public static MemorySegment allocate(GetPipeStatus.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2822,7 +2876,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { return GetPipeStatus$LAYOUT; } - private static final long GetPipeStatus$OFFSET = 216; + private static final long GetPipeStatus$OFFSET = $LAYOUT.byteOffset(groupElement("GetPipeStatus")); /** * Offset for field: @@ -2859,9 +2913,9 @@ public static void GetPipeStatus(MemorySegment struct, MemorySegment fieldValue) * IOReturn (*AbortPipe)(void *, UInt8) * } */ - public static class AbortPipe { + public final static class AbortPipe { - AbortPipe() { + private AbortPipe() { // Should not be called directly } @@ -2900,9 +2954,11 @@ public static MemorySegment allocate(AbortPipe.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -2921,7 +2977,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { return AbortPipe$LAYOUT; } - private static final long AbortPipe$OFFSET = 224; + private static final long AbortPipe$OFFSET = $LAYOUT.byteOffset(groupElement("AbortPipe")); /** * Offset for field: @@ -2958,9 +3014,9 @@ public static void AbortPipe(MemorySegment struct, MemorySegment fieldValue) { * IOReturn (*ResetPipe)(void *, UInt8) * } */ - public static class ResetPipe { + public final static class ResetPipe { - ResetPipe() { + private ResetPipe() { // Should not be called directly } @@ -2999,9 +3055,11 @@ public static MemorySegment allocate(ResetPipe.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3020,7 +3078,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { return ResetPipe$LAYOUT; } - private static final long ResetPipe$OFFSET = 232; + private static final long ResetPipe$OFFSET = $LAYOUT.byteOffset(groupElement("ResetPipe")); /** * Offset for field: @@ -3057,9 +3115,9 @@ public static void ResetPipe(MemorySegment struct, MemorySegment fieldValue) { * IOReturn (*ClearPipeStall)(void *, UInt8) * } */ - public static class ClearPipeStall { + public final static class ClearPipeStall { - ClearPipeStall() { + private ClearPipeStall() { // Should not be called directly } @@ -3098,9 +3156,11 @@ public static MemorySegment allocate(ClearPipeStall.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3119,7 +3179,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { return ClearPipeStall$LAYOUT; } - private static final long ClearPipeStall$OFFSET = 240; + private static final long ClearPipeStall$OFFSET = $LAYOUT.byteOffset(groupElement("ClearPipeStall")); /** * Offset for field: @@ -3156,9 +3216,9 @@ public static void ClearPipeStall(MemorySegment struct, MemorySegment fieldValue * IOReturn (*ReadPipe)(void *, UInt8, void *, UInt32 *) * } */ - public static class ReadPipe { + public final static class ReadPipe { - ReadPipe() { + private ReadPipe() { // Should not be called directly } @@ -3199,9 +3259,11 @@ public static MemorySegment allocate(ReadPipe.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3220,7 +3282,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, Memo return ReadPipe$LAYOUT; } - private static final long ReadPipe$OFFSET = 248; + private static final long ReadPipe$OFFSET = $LAYOUT.byteOffset(groupElement("ReadPipe")); /** * Offset for field: @@ -3257,9 +3319,9 @@ public static void ReadPipe(MemorySegment struct, MemorySegment fieldValue) { * IOReturn (*WritePipe)(void *, UInt8, void *, UInt32) * } */ - public static class WritePipe { + public final static class WritePipe { - WritePipe() { + private WritePipe() { // Should not be called directly } @@ -3300,9 +3362,11 @@ public static MemorySegment allocate(WritePipe.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3321,7 +3385,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, Memo return WritePipe$LAYOUT; } - private static final long WritePipe$OFFSET = 256; + private static final long WritePipe$OFFSET = $LAYOUT.byteOffset(groupElement("WritePipe")); /** * Offset for field: @@ -3358,9 +3422,9 @@ public static void WritePipe(MemorySegment struct, MemorySegment fieldValue) { * IOReturn (*ReadPipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *) * } */ - public static class ReadPipeAsync { + public final static class ReadPipeAsync { - ReadPipeAsync() { + private ReadPipeAsync() { // Should not be called directly } @@ -3403,9 +3467,11 @@ public static MemorySegment allocate(ReadPipeAsync.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, MemorySegment _x4, MemorySegment _x5) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, MemorySegment _x4, MemorySegment _x5) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3424,7 +3490,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, Memo return ReadPipeAsync$LAYOUT; } - private static final long ReadPipeAsync$OFFSET = 264; + private static final long ReadPipeAsync$OFFSET = $LAYOUT.byteOffset(groupElement("ReadPipeAsync")); /** * Offset for field: @@ -3461,9 +3527,9 @@ public static void ReadPipeAsync(MemorySegment struct, MemorySegment fieldValue) * IOReturn (*WritePipeAsync)(void *, UInt8, void *, UInt32, IOAsyncCallback1, void *) * } */ - public static class WritePipeAsync { + public final static class WritePipeAsync { - WritePipeAsync() { + private WritePipeAsync() { // Should not be called directly } @@ -3506,9 +3572,11 @@ public static MemorySegment allocate(WritePipeAsync.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, MemorySegment _x4, MemorySegment _x5) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, MemorySegment _x4, MemorySegment _x5) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3527,7 +3595,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, Memo return WritePipeAsync$LAYOUT; } - private static final long WritePipeAsync$OFFSET = 272; + private static final long WritePipeAsync$OFFSET = $LAYOUT.byteOffset(groupElement("WritePipeAsync")); /** * Offset for field: @@ -3564,9 +3632,9 @@ public static void WritePipeAsync(MemorySegment struct, MemorySegment fieldValue * IOReturn (*ReadIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *) * } */ - public static class ReadIsochPipeAsync { + public final static class ReadIsochPipeAsync { - ReadIsochPipeAsync() { + private ReadIsochPipeAsync() { // Should not be called directly } @@ -3611,9 +3679,11 @@ public static MemorySegment allocate(ReadIsochPipeAsync.Function fi, Arena arena /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, long _x3, int _x4, MemorySegment _x5, MemorySegment _x6, MemorySegment _x7) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, MemorySegment _x2, long _x3, int _x4, MemorySegment _x5, MemorySegment _x6, MemorySegment _x7) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5, _x6, _x7); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3632,7 +3702,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, Memo return ReadIsochPipeAsync$LAYOUT; } - private static final long ReadIsochPipeAsync$OFFSET = 280; + private static final long ReadIsochPipeAsync$OFFSET = $LAYOUT.byteOffset(groupElement("ReadIsochPipeAsync")); /** * Offset for field: @@ -3669,9 +3739,9 @@ public static void ReadIsochPipeAsync(MemorySegment struct, MemorySegment fieldV * IOReturn (*WriteIsochPipeAsync)(void *, UInt8, void *, UInt64, UInt32, IOUSBIsocFrame *, IOAsyncCallback1, void *) * } */ - public static class WriteIsochPipeAsync { + public final static class WriteIsochPipeAsync { - WriteIsochPipeAsync() { + private WriteIsochPipeAsync() { // Should not be called directly } @@ -3716,9 +3786,11 @@ public static MemorySegment allocate(WriteIsochPipeAsync.Function fi, Arena aren /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, long _x3, int _x4, MemorySegment _x5, MemorySegment _x6, MemorySegment _x7) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, MemorySegment _x2, long _x3, int _x4, MemorySegment _x5, MemorySegment _x6, MemorySegment _x7) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5, _x6, _x7); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3737,7 +3809,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, Memo return WriteIsochPipeAsync$LAYOUT; } - private static final long WriteIsochPipeAsync$OFFSET = 288; + private static final long WriteIsochPipeAsync$OFFSET = $LAYOUT.byteOffset(groupElement("WriteIsochPipeAsync")); /** * Offset for field: @@ -3774,9 +3846,9 @@ public static void WriteIsochPipeAsync(MemorySegment struct, MemorySegment field * IOReturn (*ControlRequestTO)(void *, UInt8, IOUSBDevRequestTO *) * } */ - public static class ControlRequestTO { + public final static class ControlRequestTO { - ControlRequestTO() { + private ControlRequestTO() { // Should not be called directly } @@ -3816,9 +3888,11 @@ public static MemorySegment allocate(ControlRequestTO.Function fi, Arena arena) /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, MemorySegment _x2) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3837,7 +3911,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, Memo return ControlRequestTO$LAYOUT; } - private static final long ControlRequestTO$OFFSET = 296; + private static final long ControlRequestTO$OFFSET = $LAYOUT.byteOffset(groupElement("ControlRequestTO")); /** * Offset for field: @@ -3874,9 +3948,9 @@ public static void ControlRequestTO(MemorySegment struct, MemorySegment fieldVal * IOReturn (*ControlRequestAsyncTO)(void *, UInt8, IOUSBDevRequestTO *, IOAsyncCallback1, void *) * } */ - public static class ControlRequestAsyncTO { + public final static class ControlRequestAsyncTO { - ControlRequestAsyncTO() { + private ControlRequestAsyncTO() { // Should not be called directly } @@ -3918,9 +3992,11 @@ public static MemorySegment allocate(ControlRequestAsyncTO.Function fi, Arena ar /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, MemorySegment _x4) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, MemorySegment _x4) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -3939,7 +4015,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, Memo return ControlRequestAsyncTO$LAYOUT; } - private static final long ControlRequestAsyncTO$OFFSET = 304; + private static final long ControlRequestAsyncTO$OFFSET = $LAYOUT.byteOffset(groupElement("ControlRequestAsyncTO")); /** * Offset for field: @@ -3976,9 +4052,9 @@ public static void ControlRequestAsyncTO(MemorySegment struct, MemorySegment fie * IOReturn (*ReadPipeTO)(void *, UInt8, void *, UInt32 *, UInt32, UInt32) * } */ - public static class ReadPipeTO { + public final static class ReadPipeTO { - ReadPipeTO() { + private ReadPipeTO() { // Should not be called directly } @@ -4021,9 +4097,11 @@ public static MemorySegment allocate(ReadPipeTO.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, int _x4, int _x5) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, int _x4, int _x5) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -4042,7 +4120,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, Memo return ReadPipeTO$LAYOUT; } - private static final long ReadPipeTO$OFFSET = 312; + private static final long ReadPipeTO$OFFSET = $LAYOUT.byteOffset(groupElement("ReadPipeTO")); /** * Offset for field: @@ -4079,9 +4157,9 @@ public static void ReadPipeTO(MemorySegment struct, MemorySegment fieldValue) { * IOReturn (*WritePipeTO)(void *, UInt8, void *, UInt32, UInt32, UInt32) * } */ - public static class WritePipeTO { + public final static class WritePipeTO { - WritePipeTO() { + private WritePipeTO() { // Should not be called directly } @@ -4124,9 +4202,11 @@ public static MemorySegment allocate(WritePipeTO.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, int _x4, int _x5) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, int _x4, int _x5) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -4145,7 +4225,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, Memo return WritePipeTO$LAYOUT; } - private static final long WritePipeTO$OFFSET = 320; + private static final long WritePipeTO$OFFSET = $LAYOUT.byteOffset(groupElement("WritePipeTO")); /** * Offset for field: @@ -4182,9 +4262,9 @@ public static void WritePipeTO(MemorySegment struct, MemorySegment fieldValue) { * IOReturn (*ReadPipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *) * } */ - public static class ReadPipeAsyncTO { + public final static class ReadPipeAsyncTO { - ReadPipeAsyncTO() { + private ReadPipeAsyncTO() { // Should not be called directly } @@ -4229,9 +4309,11 @@ public static MemorySegment allocate(ReadPipeAsyncTO.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, int _x4, int _x5, MemorySegment _x6, MemorySegment _x7) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, int _x4, int _x5, MemorySegment _x6, MemorySegment _x7) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5, _x6, _x7); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -4250,7 +4332,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, Memo return ReadPipeAsyncTO$LAYOUT; } - private static final long ReadPipeAsyncTO$OFFSET = 328; + private static final long ReadPipeAsyncTO$OFFSET = $LAYOUT.byteOffset(groupElement("ReadPipeAsyncTO")); /** * Offset for field: @@ -4287,9 +4369,9 @@ public static void ReadPipeAsyncTO(MemorySegment struct, MemorySegment fieldValu * IOReturn (*WritePipeAsyncTO)(void *, UInt8, void *, UInt32, UInt32, UInt32, IOAsyncCallback1, void *) * } */ - public static class WritePipeAsyncTO { + public final static class WritePipeAsyncTO { - WritePipeAsyncTO() { + private WritePipeAsyncTO() { // Should not be called directly } @@ -4334,9 +4416,11 @@ public static MemorySegment allocate(WritePipeAsyncTO.Function fi, Arena arena) /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, int _x4, int _x5, MemorySegment _x6, MemorySegment _x7) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, int _x4, int _x5, MemorySegment _x6, MemorySegment _x7) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5, _x6, _x7); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -4355,7 +4439,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, Memo return WritePipeAsyncTO$LAYOUT; } - private static final long WritePipeAsyncTO$OFFSET = 336; + private static final long WritePipeAsyncTO$OFFSET = $LAYOUT.byteOffset(groupElement("WritePipeAsyncTO")); /** * Offset for field: @@ -4392,9 +4476,9 @@ public static void WritePipeAsyncTO(MemorySegment struct, MemorySegment fieldVal * IOReturn (*USBInterfaceGetStringIndex)(void *, UInt8 *) * } */ - public static class USBInterfaceGetStringIndex { + public final static class USBInterfaceGetStringIndex { - USBInterfaceGetStringIndex() { + private USBInterfaceGetStringIndex() { // Should not be called directly } @@ -4433,9 +4517,11 @@ public static MemorySegment allocate(USBInterfaceGetStringIndex.Function fi, Are /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -4454,7 +4540,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return USBInterfaceGetStringIndex$LAYOUT; } - private static final long USBInterfaceGetStringIndex$OFFSET = 344; + private static final long USBInterfaceGetStringIndex$OFFSET = $LAYOUT.byteOffset(groupElement("USBInterfaceGetStringIndex")); /** * Offset for field: @@ -4491,9 +4577,9 @@ public static void USBInterfaceGetStringIndex(MemorySegment struct, MemorySegmen * IOReturn (*USBInterfaceOpenSeize)(void *) * } */ - public static class USBInterfaceOpenSeize { + public final static class USBInterfaceOpenSeize { - USBInterfaceOpenSeize() { + private USBInterfaceOpenSeize() { // Should not be called directly } @@ -4531,9 +4617,11 @@ public static MemorySegment allocate(USBInterfaceOpenSeize.Function fi, Arena ar /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -4552,7 +4640,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0) { return USBInterfaceOpenSeize$LAYOUT; } - private static final long USBInterfaceOpenSeize$OFFSET = 352; + private static final long USBInterfaceOpenSeize$OFFSET = $LAYOUT.byteOffset(groupElement("USBInterfaceOpenSeize")); /** * Offset for field: @@ -4589,9 +4677,9 @@ public static void USBInterfaceOpenSeize(MemorySegment struct, MemorySegment fie * IOReturn (*ClearPipeStallBothEnds)(void *, UInt8) * } */ - public static class ClearPipeStallBothEnds { + public final static class ClearPipeStallBothEnds { - ClearPipeStallBothEnds() { + private ClearPipeStallBothEnds() { // Should not be called directly } @@ -4630,9 +4718,11 @@ public static MemorySegment allocate(ClearPipeStallBothEnds.Function fi, Arena a /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -4651,7 +4741,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1) { return ClearPipeStallBothEnds$LAYOUT; } - private static final long ClearPipeStallBothEnds$OFFSET = 360; + private static final long ClearPipeStallBothEnds$OFFSET = $LAYOUT.byteOffset(groupElement("ClearPipeStallBothEnds")); /** * Offset for field: @@ -4688,9 +4778,9 @@ public static void ClearPipeStallBothEnds(MemorySegment struct, MemorySegment fi * IOReturn (*SetPipePolicy)(void *, UInt8, UInt16, UInt8) * } */ - public static class SetPipePolicy { + public final static class SetPipePolicy { - SetPipePolicy() { + private SetPipePolicy() { // Should not be called directly } @@ -4731,9 +4821,11 @@ public static MemorySegment allocate(SetPipePolicy.Function fi, Arena arena) { /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, short _x2, byte _x3) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, short _x2, byte _x3) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -4752,7 +4844,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, shor return SetPipePolicy$LAYOUT; } - private static final long SetPipePolicy$OFFSET = 368; + private static final long SetPipePolicy$OFFSET = $LAYOUT.byteOffset(groupElement("SetPipePolicy")); /** * Offset for field: @@ -4789,9 +4881,9 @@ public static void SetPipePolicy(MemorySegment struct, MemorySegment fieldValue) * IOReturn (*GetBandwidthAvailable)(void *, UInt32 *) * } */ - public static class GetBandwidthAvailable { + public final static class GetBandwidthAvailable { - GetBandwidthAvailable() { + private GetBandwidthAvailable() { // Should not be called directly } @@ -4830,9 +4922,11 @@ public static MemorySegment allocate(GetBandwidthAvailable.Function fi, Arena ar /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, MemorySegment _x1) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -4851,7 +4945,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment return GetBandwidthAvailable$LAYOUT; } - private static final long GetBandwidthAvailable$OFFSET = 376; + private static final long GetBandwidthAvailable$OFFSET = $LAYOUT.byteOffset(groupElement("GetBandwidthAvailable")); /** * Offset for field: @@ -4888,9 +4982,9 @@ public static void GetBandwidthAvailable(MemorySegment struct, MemorySegment fie * IOReturn (*GetEndpointProperties)(void *, UInt8, UInt8, UInt8, UInt8 *, UInt16 *, UInt8 *) * } */ - public static class GetEndpointProperties { + public final static class GetEndpointProperties { - GetEndpointProperties() { + private GetEndpointProperties() { // Should not be called directly } @@ -4934,9 +5028,11 @@ public static MemorySegment allocate(GetEndpointProperties.Function fi, Arena ar /** * Invoke the upcall stub {@code funcPtr}, with given parameters */ - public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, byte _x2, byte _x3, MemorySegment _x4, MemorySegment _x5, MemorySegment _x6) { + public static int invoke(MemorySegment funcPtr, MemorySegment _x0, byte _x1, byte _x2, byte _x3, MemorySegment _x4, MemorySegment _x5, MemorySegment _x6) { try { return (int) DOWN$MH.invokeExact(funcPtr, _x0, _x1, _x2, _x3, _x4, _x5, _x6); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -4955,7 +5051,7 @@ public static int invoke(MemorySegment funcPtr,MemorySegment _x0, byte _x1, byte return GetEndpointProperties$LAYOUT; } - private static final long GetEndpointProperties$OFFSET = 384; + private static final long GetEndpointProperties$OFFSET = $LAYOUT.byteOffset(groupElement("GetEndpointProperties")); /** * Offset for field: @@ -5016,7 +5112,7 @@ public static MemorySegment allocateArray(long elementCount, SegmentAllocator al } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { @@ -5024,7 +5120,7 @@ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consume } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code elementCount * layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach$shared.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach$shared.java new file mode 100644 index 00000000..afa05d01 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach$shared.java @@ -0,0 +1,63 @@ +// Generated by jextract + +package net.codecrete.usb.macos.gen.mach; + +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; + +public class mach$shared { + + mach$shared() { + // Should not be called directly + } + + public static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool"); + public static final ValueLayout.OfByte C_CHAR =(ValueLayout.OfByte)Linker.nativeLinker().canonicalLayouts().get("char"); + public static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) Linker.nativeLinker().canonicalLayouts().get("short"); + public static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get("int"); + public static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long long"); + public static final ValueLayout.OfFloat C_FLOAT = (ValueLayout.OfFloat) Linker.nativeLinker().canonicalLayouts().get("float"); + public static final ValueLayout.OfDouble C_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get("double"); + public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*")) + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, C_CHAR)); + public static final ValueLayout.OfLong C_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long"); + + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java index 6c7ce22a..80f92c11 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/mach/mach.java @@ -12,62 +12,17 @@ import static java.lang.foreign.ValueLayout.*; import static java.lang.foreign.MemoryLayout.PathElement.*; -public class mach { +public class mach extends mach$shared { mach() { // Should not be called directly } static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() .or(Linker.nativeLinker().defaultLookup()); - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; private static class mach_error_string { public static final FunctionDescriptor DESC = FunctionDescriptor.of( @@ -75,9 +30,9 @@ private static class mach_error_string { mach.C_INT ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - mach.findOrThrow("mach_error_string"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("mach_error_string"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -99,6 +54,17 @@ private static class mach_error_string { public static MethodHandle mach_error_string$handle() { return mach_error_string.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * char *mach_error_string(mach_error_t error_value) + * } + */ + public static MemorySegment mach_error_string$address() { + return mach_error_string.ADDR; + } + /** * {@snippet lang=c : * char *mach_error_string(mach_error_t error_value) @@ -111,6 +77,8 @@ public static MemorySegment mach_error_string(int error_value) { traceDowncall("mach_error_string", error_value); } return (MemorySegment)mh$.invokeExact(error_value); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } From 99a80e6843755d2b36429767db5022339f6bce81 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Mon, 8 Sep 2025 12:26:50 +0200 Subject: [PATCH 384/433] Linux: update jextract generated code --- java-does-usb/jextract/linux/gen_linux.sh | 2 +- .../usb/linux/gen/epoll/epoll$shared.java | 63 +++ .../codecrete/usb/linux/gen/epoll/epoll.java | 47 +- .../usb/linux/gen/errno/errno$shared.java | 63 +++ .../codecrete/usb/linux/gen/errno/errno.java | 47 +- .../usb/linux/gen/fcntl/fcntl$shared.java | 63 +++ .../codecrete/usb/linux/gen/fcntl/fcntl.java | 47 +- .../usb/linux/gen/string/string$shared.java | 63 +++ .../usb/linux/gen/string/string.java | 66 +-- .../usb/linux/gen/udev/udev$shared.java | 63 +++ .../codecrete/usb/linux/gen/udev/udev.java | 408 +++++++++++++----- .../usb/linux/gen/unistd/unistd$shared.java | 63 +++ .../usb/linux/gen/unistd/unistd.java | 66 +-- .../usbdevice_fs/usbdevfs_bulktransfer.java | 12 +- .../usbdevice_fs/usbdevfs_ctrltransfer.java | 18 +- .../usbdevfs_disconnect_claim.java | 10 +- .../gen/usbdevice_fs/usbdevfs_ioctl.java | 10 +- .../usbdevfs_iso_packet_desc.java | 10 +- .../usbdevice_fs/usbdevfs_setinterface.java | 8 +- .../linux/gen/usbdevice_fs/usbdevfs_urb.java | 28 +- .../gen/usbdevice_fs/usbdevice_fs$shared.java | 63 +++ .../linux/gen/usbdevice_fs/usbdevice_fs.java | 47 +- 22 files changed, 833 insertions(+), 434 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll$shared.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno$shared.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl$shared.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string$shared.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev$shared.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd$shared.java create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs$shared.java diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index 99ebe244..35b04784 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -1,6 +1,6 @@ #!/bin/sh -JEXTRACT=../../../../jextract/build/jextract/bin/jextract +JEXTRACT=../../../../jextract/bin/jextract rm -rf ../../src/main/java/net/codecrete/usb/linux/gen diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll$shared.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll$shared.java new file mode 100644 index 00000000..5cb27567 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll$shared.java @@ -0,0 +1,63 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.epoll; + +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; + +public class epoll$shared { + + epoll$shared() { + // Should not be called directly + } + + public static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool"); + public static final ValueLayout.OfByte C_CHAR =(ValueLayout.OfByte)Linker.nativeLinker().canonicalLayouts().get("char"); + public static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) Linker.nativeLinker().canonicalLayouts().get("short"); + public static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get("int"); + public static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long long"); + public static final ValueLayout.OfFloat C_FLOAT = (ValueLayout.OfFloat) Linker.nativeLinker().canonicalLayouts().get("float"); + public static final ValueLayout.OfDouble C_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get("double"); + public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*")) + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, C_CHAR)); + public static final ValueLayout.OfLong C_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long"); + + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java index 99a00787..22e0cb02 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java @@ -12,62 +12,17 @@ import static java.lang.foreign.ValueLayout.*; import static java.lang.foreign.MemoryLayout.PathElement.*; -public class epoll { +public class epoll extends epoll$shared { epoll() { // Should not be called directly } static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() .or(Linker.nativeLinker().defaultLookup()); - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; private static final int EPOLL_CTL_ADD = (int)1L; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno$shared.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno$shared.java new file mode 100644 index 00000000..499be5f7 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno$shared.java @@ -0,0 +1,63 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.errno; + +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; + +public class errno$shared { + + errno$shared() { + // Should not be called directly + } + + public static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool"); + public static final ValueLayout.OfByte C_CHAR =(ValueLayout.OfByte)Linker.nativeLinker().canonicalLayouts().get("char"); + public static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) Linker.nativeLinker().canonicalLayouts().get("short"); + public static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get("int"); + public static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long long"); + public static final ValueLayout.OfFloat C_FLOAT = (ValueLayout.OfFloat) Linker.nativeLinker().canonicalLayouts().get("float"); + public static final ValueLayout.OfDouble C_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get("double"); + public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*")) + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, C_CHAR)); + public static final ValueLayout.OfLong C_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long"); + + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java index 3d970a3c..4ef548f3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -12,62 +12,17 @@ import static java.lang.foreign.ValueLayout.*; import static java.lang.foreign.MemoryLayout.PathElement.*; -public class errno { +public class errno extends errno$shared { errno() { // Should not be called directly } static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() .or(Linker.nativeLinker().defaultLookup()); - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; private static final int ENOENT = (int)2L; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl$shared.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl$shared.java new file mode 100644 index 00000000..0a6ca8e4 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl$shared.java @@ -0,0 +1,63 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.fcntl; + +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; + +public class fcntl$shared { + + fcntl$shared() { + // Should not be called directly + } + + public static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool"); + public static final ValueLayout.OfByte C_CHAR =(ValueLayout.OfByte)Linker.nativeLinker().canonicalLayouts().get("char"); + public static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) Linker.nativeLinker().canonicalLayouts().get("short"); + public static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get("int"); + public static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long long"); + public static final ValueLayout.OfFloat C_FLOAT = (ValueLayout.OfFloat) Linker.nativeLinker().canonicalLayouts().get("float"); + public static final ValueLayout.OfDouble C_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get("double"); + public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*")) + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, C_CHAR)); + public static final ValueLayout.OfLong C_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long"); + + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java index 1fb52864..72cbfb53 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/fcntl/fcntl.java @@ -12,62 +12,17 @@ import static java.lang.foreign.ValueLayout.*; import static java.lang.foreign.MemoryLayout.PathElement.*; -public class fcntl { +public class fcntl extends fcntl$shared { fcntl() { // Should not be called directly } static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() .or(Linker.nativeLinker().defaultLookup()); - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; private static final int O_RDWR = (int)2L; /** * {@snippet lang=c : diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string$shared.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string$shared.java new file mode 100644 index 00000000..824bb277 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string$shared.java @@ -0,0 +1,63 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.string; + +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; + +public class string$shared { + + string$shared() { + // Should not be called directly + } + + public static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool"); + public static final ValueLayout.OfByte C_CHAR =(ValueLayout.OfByte)Linker.nativeLinker().canonicalLayouts().get("char"); + public static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) Linker.nativeLinker().canonicalLayouts().get("short"); + public static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get("int"); + public static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long long"); + public static final ValueLayout.OfFloat C_FLOAT = (ValueLayout.OfFloat) Linker.nativeLinker().canonicalLayouts().get("float"); + public static final ValueLayout.OfDouble C_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get("double"); + public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*")) + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, C_CHAR)); + public static final ValueLayout.OfLong C_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long"); + + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java index f5cfc2d7..de0e4452 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/string/string.java @@ -12,62 +12,17 @@ import static java.lang.foreign.ValueLayout.*; import static java.lang.foreign.MemoryLayout.PathElement.*; -public class string { +public class string extends string$shared { string() { // Should not be called directly } static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() .or(Linker.nativeLinker().defaultLookup()); - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; private static class strerror { public static final FunctionDescriptor DESC = FunctionDescriptor.of( @@ -75,9 +30,9 @@ private static class strerror { string.C_INT ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - string.findOrThrow("strerror"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("strerror"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -99,6 +54,17 @@ private static class strerror { public static MethodHandle strerror$handle() { return strerror.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern char *strerror(int __errnum) + * } + */ + public static MemorySegment strerror$address() { + return strerror.ADDR; + } + /** * {@snippet lang=c : * extern char *strerror(int __errnum) @@ -111,6 +77,8 @@ public static MemorySegment strerror(int __errnum) { traceDowncall("strerror", __errnum); } return (MemorySegment)mh$.invokeExact(__errnum); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev$shared.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev$shared.java new file mode 100644 index 00000000..b7958526 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev$shared.java @@ -0,0 +1,63 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.udev; + +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; + +public class udev$shared { + + udev$shared() { + // Should not be called directly + } + + public static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool"); + public static final ValueLayout.OfByte C_CHAR =(ValueLayout.OfByte)Linker.nativeLinker().canonicalLayouts().get("char"); + public static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) Linker.nativeLinker().canonicalLayouts().get("short"); + public static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get("int"); + public static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long long"); + public static final ValueLayout.OfFloat C_FLOAT = (ValueLayout.OfFloat) Linker.nativeLinker().canonicalLayouts().get("float"); + public static final ValueLayout.OfDouble C_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get("double"); + public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*")) + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, C_CHAR)); + public static final ValueLayout.OfLong C_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long"); + + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java index be48336d..f43a699d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/udev/udev.java @@ -12,71 +12,26 @@ import static java.lang.foreign.ValueLayout.*; import static java.lang.foreign.MemoryLayout.PathElement.*; -public class udev { +public class udev extends udev$shared { udev() { // Should not be called directly } static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup("libudev.so.1", LIBRARY_ARENA) .or(SymbolLookup.loaderLookup()) .or(Linker.nativeLinker().defaultLookup()); - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; private static class udev_new { public static final FunctionDescriptor DESC = FunctionDescriptor.of( udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_new"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_new"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -98,6 +53,17 @@ private static class udev_new { public static MethodHandle udev_new$handle() { return udev_new.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * struct udev *udev_new(void) + * } + */ + public static MemorySegment udev_new$address() { + return udev_new.ADDR; + } + /** * {@snippet lang=c : * struct udev *udev_new(void) @@ -110,6 +76,8 @@ public static MemorySegment udev_new() { traceDowncall("udev_new"); } return (MemorySegment)mh$.invokeExact(); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -121,9 +89,9 @@ private static class udev_list_entry_get_next { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_list_entry_get_next"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_list_entry_get_next"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -145,6 +113,17 @@ private static class udev_list_entry_get_next { public static MethodHandle udev_list_entry_get_next$handle() { return udev_list_entry_get_next.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) + * } + */ + public static MemorySegment udev_list_entry_get_next$address() { + return udev_list_entry_get_next.ADDR; + } + /** * {@snippet lang=c : * struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) @@ -157,6 +136,8 @@ public static MemorySegment udev_list_entry_get_next(MemorySegment list_entry) { traceDowncall("udev_list_entry_get_next", list_entry); } return (MemorySegment)mh$.invokeExact(list_entry); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -168,9 +149,9 @@ private static class udev_list_entry_get_name { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_list_entry_get_name"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_list_entry_get_name"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -192,6 +173,17 @@ private static class udev_list_entry_get_name { public static MethodHandle udev_list_entry_get_name$handle() { return udev_list_entry_get_name.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) + * } + */ + public static MemorySegment udev_list_entry_get_name$address() { + return udev_list_entry_get_name.ADDR; + } + /** * {@snippet lang=c : * const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) @@ -204,6 +196,8 @@ public static MemorySegment udev_list_entry_get_name(MemorySegment list_entry) { traceDowncall("udev_list_entry_get_name", list_entry); } return (MemorySegment)mh$.invokeExact(list_entry); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -215,9 +209,9 @@ private static class udev_device_unref { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_device_unref"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_device_unref"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -239,6 +233,17 @@ private static class udev_device_unref { public static MethodHandle udev_device_unref$handle() { return udev_device_unref.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * struct udev_device *udev_device_unref(struct udev_device *udev_device) + * } + */ + public static MemorySegment udev_device_unref$address() { + return udev_device_unref.ADDR; + } + /** * {@snippet lang=c : * struct udev_device *udev_device_unref(struct udev_device *udev_device) @@ -251,6 +256,8 @@ public static MemorySegment udev_device_unref(MemorySegment udev_device) { traceDowncall("udev_device_unref", udev_device); } return (MemorySegment)mh$.invokeExact(udev_device); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -263,9 +270,9 @@ private static class udev_device_new_from_syspath { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_device_new_from_syspath"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_device_new_from_syspath"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -287,6 +294,17 @@ private static class udev_device_new_from_syspath { public static MethodHandle udev_device_new_from_syspath$handle() { return udev_device_new_from_syspath.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) + * } + */ + public static MemorySegment udev_device_new_from_syspath$address() { + return udev_device_new_from_syspath.ADDR; + } + /** * {@snippet lang=c : * struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) @@ -299,6 +317,8 @@ public static MemorySegment udev_device_new_from_syspath(MemorySegment udev, Mem traceDowncall("udev_device_new_from_syspath", udev, syspath); } return (MemorySegment)mh$.invokeExact(udev, syspath); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -310,9 +330,9 @@ private static class udev_device_get_devtype { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_device_get_devtype"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_device_get_devtype"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -334,6 +354,17 @@ private static class udev_device_get_devtype { public static MethodHandle udev_device_get_devtype$handle() { return udev_device_get_devtype.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * const char *udev_device_get_devtype(struct udev_device *udev_device) + * } + */ + public static MemorySegment udev_device_get_devtype$address() { + return udev_device_get_devtype.ADDR; + } + /** * {@snippet lang=c : * const char *udev_device_get_devtype(struct udev_device *udev_device) @@ -346,6 +377,8 @@ public static MemorySegment udev_device_get_devtype(MemorySegment udev_device) { traceDowncall("udev_device_get_devtype", udev_device); } return (MemorySegment)mh$.invokeExact(udev_device); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -357,9 +390,9 @@ private static class udev_device_get_devnode { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_device_get_devnode"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_device_get_devnode"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -381,6 +414,17 @@ private static class udev_device_get_devnode { public static MethodHandle udev_device_get_devnode$handle() { return udev_device_get_devnode.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * const char *udev_device_get_devnode(struct udev_device *udev_device) + * } + */ + public static MemorySegment udev_device_get_devnode$address() { + return udev_device_get_devnode.ADDR; + } + /** * {@snippet lang=c : * const char *udev_device_get_devnode(struct udev_device *udev_device) @@ -393,6 +437,8 @@ public static MemorySegment udev_device_get_devnode(MemorySegment udev_device) { traceDowncall("udev_device_get_devnode", udev_device); } return (MemorySegment)mh$.invokeExact(udev_device); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -404,9 +450,9 @@ private static class udev_device_get_action { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_device_get_action"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_device_get_action"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -428,6 +474,17 @@ private static class udev_device_get_action { public static MethodHandle udev_device_get_action$handle() { return udev_device_get_action.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * const char *udev_device_get_action(struct udev_device *udev_device) + * } + */ + public static MemorySegment udev_device_get_action$address() { + return udev_device_get_action.ADDR; + } + /** * {@snippet lang=c : * const char *udev_device_get_action(struct udev_device *udev_device) @@ -440,6 +497,8 @@ public static MemorySegment udev_device_get_action(MemorySegment udev_device) { traceDowncall("udev_device_get_action", udev_device); } return (MemorySegment)mh$.invokeExact(udev_device); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -452,9 +511,9 @@ private static class udev_device_get_sysattr_value { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_device_get_sysattr_value"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_device_get_sysattr_value"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -476,6 +535,17 @@ private static class udev_device_get_sysattr_value { public static MethodHandle udev_device_get_sysattr_value$handle() { return udev_device_get_sysattr_value.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) + * } + */ + public static MemorySegment udev_device_get_sysattr_value$address() { + return udev_device_get_sysattr_value.ADDR; + } + /** * {@snippet lang=c : * const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) @@ -488,6 +558,8 @@ public static MemorySegment udev_device_get_sysattr_value(MemorySegment udev_dev traceDowncall("udev_device_get_sysattr_value", udev_device, sysattr); } return (MemorySegment)mh$.invokeExact(udev_device, sysattr); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -500,9 +572,9 @@ private static class udev_monitor_new_from_netlink { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_monitor_new_from_netlink"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_monitor_new_from_netlink"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -524,6 +596,17 @@ private static class udev_monitor_new_from_netlink { public static MethodHandle udev_monitor_new_from_netlink$handle() { return udev_monitor_new_from_netlink.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name) + * } + */ + public static MemorySegment udev_monitor_new_from_netlink$address() { + return udev_monitor_new_from_netlink.ADDR; + } + /** * {@snippet lang=c : * struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name) @@ -536,6 +619,8 @@ public static MemorySegment udev_monitor_new_from_netlink(MemorySegment udev, Me traceDowncall("udev_monitor_new_from_netlink", udev, name); } return (MemorySegment)mh$.invokeExact(udev, name); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -547,9 +632,9 @@ private static class udev_monitor_enable_receiving { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_monitor_enable_receiving"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_monitor_enable_receiving"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -571,6 +656,17 @@ private static class udev_monitor_enable_receiving { public static MethodHandle udev_monitor_enable_receiving$handle() { return udev_monitor_enable_receiving.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) + * } + */ + public static MemorySegment udev_monitor_enable_receiving$address() { + return udev_monitor_enable_receiving.ADDR; + } + /** * {@snippet lang=c : * int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) @@ -583,6 +679,8 @@ public static int udev_monitor_enable_receiving(MemorySegment udev_monitor) { traceDowncall("udev_monitor_enable_receiving", udev_monitor); } return (int)mh$.invokeExact(udev_monitor); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -594,9 +692,9 @@ private static class udev_monitor_get_fd { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_monitor_get_fd"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_monitor_get_fd"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -618,6 +716,17 @@ private static class udev_monitor_get_fd { public static MethodHandle udev_monitor_get_fd$handle() { return udev_monitor_get_fd.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * int udev_monitor_get_fd(struct udev_monitor *udev_monitor) + * } + */ + public static MemorySegment udev_monitor_get_fd$address() { + return udev_monitor_get_fd.ADDR; + } + /** * {@snippet lang=c : * int udev_monitor_get_fd(struct udev_monitor *udev_monitor) @@ -630,6 +739,8 @@ public static int udev_monitor_get_fd(MemorySegment udev_monitor) { traceDowncall("udev_monitor_get_fd", udev_monitor); } return (int)mh$.invokeExact(udev_monitor); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -641,9 +752,9 @@ private static class udev_monitor_receive_device { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_monitor_receive_device"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_monitor_receive_device"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -665,6 +776,17 @@ private static class udev_monitor_receive_device { public static MethodHandle udev_monitor_receive_device$handle() { return udev_monitor_receive_device.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) + * } + */ + public static MemorySegment udev_monitor_receive_device$address() { + return udev_monitor_receive_device.ADDR; + } + /** * {@snippet lang=c : * struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) @@ -677,6 +799,8 @@ public static MemorySegment udev_monitor_receive_device(MemorySegment udev_monit traceDowncall("udev_monitor_receive_device", udev_monitor); } return (MemorySegment)mh$.invokeExact(udev_monitor); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -690,9 +814,9 @@ private static class udev_monitor_filter_add_match_subsystem_devtype { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_monitor_filter_add_match_subsystem_devtype"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_monitor_filter_add_match_subsystem_devtype"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -714,6 +838,17 @@ private static class udev_monitor_filter_add_match_subsystem_devtype { public static MethodHandle udev_monitor_filter_add_match_subsystem_devtype$handle() { return udev_monitor_filter_add_match_subsystem_devtype.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) + * } + */ + public static MemorySegment udev_monitor_filter_add_match_subsystem_devtype$address() { + return udev_monitor_filter_add_match_subsystem_devtype.ADDR; + } + /** * {@snippet lang=c : * int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) @@ -726,6 +861,8 @@ public static int udev_monitor_filter_add_match_subsystem_devtype(MemorySegment traceDowncall("udev_monitor_filter_add_match_subsystem_devtype", udev_monitor, subsystem, devtype); } return (int)mh$.invokeExact(udev_monitor, subsystem, devtype); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -737,9 +874,9 @@ private static class udev_enumerate_unref { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_enumerate_unref"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_enumerate_unref"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -761,6 +898,17 @@ private static class udev_enumerate_unref { public static MethodHandle udev_enumerate_unref$handle() { return udev_enumerate_unref.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate) + * } + */ + public static MemorySegment udev_enumerate_unref$address() { + return udev_enumerate_unref.ADDR; + } + /** * {@snippet lang=c : * struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate) @@ -773,6 +921,8 @@ public static MemorySegment udev_enumerate_unref(MemorySegment udev_enumerate) { traceDowncall("udev_enumerate_unref", udev_enumerate); } return (MemorySegment)mh$.invokeExact(udev_enumerate); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -784,9 +934,9 @@ private static class udev_enumerate_new { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_enumerate_new"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_enumerate_new"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -808,6 +958,17 @@ private static class udev_enumerate_new { public static MethodHandle udev_enumerate_new$handle() { return udev_enumerate_new.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * struct udev_enumerate *udev_enumerate_new(struct udev *udev) + * } + */ + public static MemorySegment udev_enumerate_new$address() { + return udev_enumerate_new.ADDR; + } + /** * {@snippet lang=c : * struct udev_enumerate *udev_enumerate_new(struct udev *udev) @@ -820,6 +981,8 @@ public static MemorySegment udev_enumerate_new(MemorySegment udev) { traceDowncall("udev_enumerate_new", udev); } return (MemorySegment)mh$.invokeExact(udev); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -832,9 +995,9 @@ private static class udev_enumerate_add_match_subsystem { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_enumerate_add_match_subsystem"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_enumerate_add_match_subsystem"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -856,6 +1019,17 @@ private static class udev_enumerate_add_match_subsystem { public static MethodHandle udev_enumerate_add_match_subsystem$handle() { return udev_enumerate_add_match_subsystem.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) + * } + */ + public static MemorySegment udev_enumerate_add_match_subsystem$address() { + return udev_enumerate_add_match_subsystem.ADDR; + } + /** * {@snippet lang=c : * int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) @@ -868,6 +1042,8 @@ public static int udev_enumerate_add_match_subsystem(MemorySegment udev_enumerat traceDowncall("udev_enumerate_add_match_subsystem", udev_enumerate, subsystem); } return (int)mh$.invokeExact(udev_enumerate, subsystem); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -879,9 +1055,9 @@ private static class udev_enumerate_scan_devices { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_enumerate_scan_devices"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_enumerate_scan_devices"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -903,6 +1079,17 @@ private static class udev_enumerate_scan_devices { public static MethodHandle udev_enumerate_scan_devices$handle() { return udev_enumerate_scan_devices.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) + * } + */ + public static MemorySegment udev_enumerate_scan_devices$address() { + return udev_enumerate_scan_devices.ADDR; + } + /** * {@snippet lang=c : * int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) @@ -915,6 +1102,8 @@ public static int udev_enumerate_scan_devices(MemorySegment udev_enumerate) { traceDowncall("udev_enumerate_scan_devices", udev_enumerate); } return (int)mh$.invokeExact(udev_enumerate); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } @@ -926,9 +1115,9 @@ private static class udev_enumerate_get_list_entry { udev.C_POINTER ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - udev.findOrThrow("udev_enumerate_get_list_entry"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("udev_enumerate_get_list_entry"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -950,6 +1139,17 @@ private static class udev_enumerate_get_list_entry { public static MethodHandle udev_enumerate_get_list_entry$handle() { return udev_enumerate_get_list_entry.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) + * } + */ + public static MemorySegment udev_enumerate_get_list_entry$address() { + return udev_enumerate_get_list_entry.ADDR; + } + /** * {@snippet lang=c : * struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) @@ -962,6 +1162,8 @@ public static MemorySegment udev_enumerate_get_list_entry(MemorySegment udev_enu traceDowncall("udev_enumerate_get_list_entry", udev_enumerate); } return (MemorySegment)mh$.invokeExact(udev_enumerate); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd$shared.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd$shared.java new file mode 100644 index 00000000..11064c54 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd$shared.java @@ -0,0 +1,63 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.unistd; + +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; + +public class unistd$shared { + + unistd$shared() { + // Should not be called directly + } + + public static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool"); + public static final ValueLayout.OfByte C_CHAR =(ValueLayout.OfByte)Linker.nativeLinker().canonicalLayouts().get("char"); + public static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) Linker.nativeLinker().canonicalLayouts().get("short"); + public static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get("int"); + public static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long long"); + public static final ValueLayout.OfFloat C_FLOAT = (ValueLayout.OfFloat) Linker.nativeLinker().canonicalLayouts().get("float"); + public static final ValueLayout.OfDouble C_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get("double"); + public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*")) + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, C_CHAR)); + public static final ValueLayout.OfLong C_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long"); + + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java index b0b3a136..e0f89fcf 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/unistd/unistd.java @@ -12,62 +12,17 @@ import static java.lang.foreign.ValueLayout.*; import static java.lang.foreign.MemoryLayout.PathElement.*; -public class unistd { +public class unistd extends unistd$shared { unistd() { // Should not be called directly } static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() .or(Linker.nativeLinker().defaultLookup()); - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; private static class close { public static final FunctionDescriptor DESC = FunctionDescriptor.of( @@ -75,9 +30,9 @@ private static class close { unistd.C_INT ); - public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - unistd.findOrThrow("close"), - DESC); + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("close"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } /** @@ -99,6 +54,17 @@ private static class close { public static MethodHandle close$handle() { return close.HANDLE; } + + /** + * Address for: + * {@snippet lang=c : + * extern int close(int __fd) + * } + */ + public static MemorySegment close$address() { + return close.ADDR; + } + /** * {@snippet lang=c : * extern int close(int __fd) @@ -111,6 +77,8 @@ public static int close(int __fd) { traceDowncall("close", __fd); } return (int)mh$.invokeExact(__fd); + } catch (Error | RuntimeException ex) { + throw ex; } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java index f241c02e..5e4eba47 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_bulktransfer.java @@ -55,7 +55,7 @@ public static final GroupLayout layout() { return ep$LAYOUT; } - private static final long ep$OFFSET = 0; + private static final long ep$OFFSET = $LAYOUT.byteOffset(groupElement("ep")); /** * Offset for field: @@ -99,7 +99,7 @@ public static void ep(MemorySegment struct, int fieldValue) { return len$LAYOUT; } - private static final long len$OFFSET = 4; + private static final long len$OFFSET = $LAYOUT.byteOffset(groupElement("len")); /** * Offset for field: @@ -143,7 +143,7 @@ public static void len(MemorySegment struct, int fieldValue) { return timeout$LAYOUT; } - private static final long timeout$OFFSET = 8; + private static final long timeout$OFFSET = $LAYOUT.byteOffset(groupElement("timeout")); /** * Offset for field: @@ -187,7 +187,7 @@ public static void timeout(MemorySegment struct, int fieldValue) { return data$LAYOUT; } - private static final long data$OFFSET = 16; + private static final long data$OFFSET = $LAYOUT.byteOffset(groupElement("data")); /** * Offset for field: @@ -248,7 +248,7 @@ public static MemorySegment allocateArray(long elementCount, SegmentAllocator al } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { @@ -256,7 +256,7 @@ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consume } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code elementCount * layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java index e857dd12..c5071566 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ctrltransfer.java @@ -61,7 +61,7 @@ public static final GroupLayout layout() { return bRequestType$LAYOUT; } - private static final long bRequestType$OFFSET = 0; + private static final long bRequestType$OFFSET = $LAYOUT.byteOffset(groupElement("bRequestType")); /** * Offset for field: @@ -105,7 +105,7 @@ public static void bRequestType(MemorySegment struct, byte fieldValue) { return bRequest$LAYOUT; } - private static final long bRequest$OFFSET = 1; + private static final long bRequest$OFFSET = $LAYOUT.byteOffset(groupElement("bRequest")); /** * Offset for field: @@ -149,7 +149,7 @@ public static void bRequest(MemorySegment struct, byte fieldValue) { return wValue$LAYOUT; } - private static final long wValue$OFFSET = 2; + private static final long wValue$OFFSET = $LAYOUT.byteOffset(groupElement("wValue")); /** * Offset for field: @@ -193,7 +193,7 @@ public static void wValue(MemorySegment struct, short fieldValue) { return wIndex$LAYOUT; } - private static final long wIndex$OFFSET = 4; + private static final long wIndex$OFFSET = $LAYOUT.byteOffset(groupElement("wIndex")); /** * Offset for field: @@ -237,7 +237,7 @@ public static void wIndex(MemorySegment struct, short fieldValue) { return wLength$LAYOUT; } - private static final long wLength$OFFSET = 6; + private static final long wLength$OFFSET = $LAYOUT.byteOffset(groupElement("wLength")); /** * Offset for field: @@ -281,7 +281,7 @@ public static void wLength(MemorySegment struct, short fieldValue) { return timeout$LAYOUT; } - private static final long timeout$OFFSET = 8; + private static final long timeout$OFFSET = $LAYOUT.byteOffset(groupElement("timeout")); /** * Offset for field: @@ -325,7 +325,7 @@ public static void timeout(MemorySegment struct, int fieldValue) { return data$LAYOUT; } - private static final long data$OFFSET = 16; + private static final long data$OFFSET = $LAYOUT.byteOffset(groupElement("data")); /** * Offset for field: @@ -386,7 +386,7 @@ public static MemorySegment allocateArray(long elementCount, SegmentAllocator al } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { @@ -394,7 +394,7 @@ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consume } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code elementCount * layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java index 5fbea293..a41ba1db 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_disconnect_claim.java @@ -52,7 +52,7 @@ public static final GroupLayout layout() { return interface_$LAYOUT; } - private static final long interface_$OFFSET = 0; + private static final long interface_$OFFSET = $LAYOUT.byteOffset(groupElement("interface")); /** * Offset for field: @@ -96,7 +96,7 @@ public static void interface_(MemorySegment struct, int fieldValue) { return flags$LAYOUT; } - private static final long flags$OFFSET = 4; + private static final long flags$OFFSET = $LAYOUT.byteOffset(groupElement("flags")); /** * Offset for field: @@ -140,7 +140,7 @@ public static void flags(MemorySegment struct, int fieldValue) { return driver$LAYOUT; } - private static final long driver$OFFSET = 8; + private static final long driver$OFFSET = $LAYOUT.byteOffset(groupElement("driver")); /** * Offset for field: @@ -234,7 +234,7 @@ public static MemorySegment allocateArray(long elementCount, SegmentAllocator al } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { @@ -242,7 +242,7 @@ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consume } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code elementCount * layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java index 0e8d44d6..8d4b6143 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_ioctl.java @@ -52,7 +52,7 @@ public static final GroupLayout layout() { return ifno$LAYOUT; } - private static final long ifno$OFFSET = 0; + private static final long ifno$OFFSET = $LAYOUT.byteOffset(groupElement("ifno")); /** * Offset for field: @@ -96,7 +96,7 @@ public static void ifno(MemorySegment struct, int fieldValue) { return ioctl_code$LAYOUT; } - private static final long ioctl_code$OFFSET = 4; + private static final long ioctl_code$OFFSET = $LAYOUT.byteOffset(groupElement("ioctl_code")); /** * Offset for field: @@ -140,7 +140,7 @@ public static void ioctl_code(MemorySegment struct, int fieldValue) { return data$LAYOUT; } - private static final long data$OFFSET = 8; + private static final long data$OFFSET = $LAYOUT.byteOffset(groupElement("data")); /** * Offset for field: @@ -201,7 +201,7 @@ public static MemorySegment allocateArray(long elementCount, SegmentAllocator al } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { @@ -209,7 +209,7 @@ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consume } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code elementCount * layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java index d4a335a0..c269241e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_iso_packet_desc.java @@ -52,7 +52,7 @@ public static final GroupLayout layout() { return length$LAYOUT; } - private static final long length$OFFSET = 0; + private static final long length$OFFSET = $LAYOUT.byteOffset(groupElement("length")); /** * Offset for field: @@ -96,7 +96,7 @@ public static void length(MemorySegment struct, int fieldValue) { return actual_length$LAYOUT; } - private static final long actual_length$OFFSET = 4; + private static final long actual_length$OFFSET = $LAYOUT.byteOffset(groupElement("actual_length")); /** * Offset for field: @@ -140,7 +140,7 @@ public static void actual_length(MemorySegment struct, int fieldValue) { return status$LAYOUT; } - private static final long status$OFFSET = 8; + private static final long status$OFFSET = $LAYOUT.byteOffset(groupElement("status")); /** * Offset for field: @@ -201,7 +201,7 @@ public static MemorySegment allocateArray(long elementCount, SegmentAllocator al } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { @@ -209,7 +209,7 @@ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consume } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code elementCount * layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java index 26b6181f..fdae516e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_setinterface.java @@ -50,7 +50,7 @@ public static final GroupLayout layout() { return interface_$LAYOUT; } - private static final long interface_$OFFSET = 0; + private static final long interface_$OFFSET = $LAYOUT.byteOffset(groupElement("interface")); /** * Offset for field: @@ -94,7 +94,7 @@ public static void interface_(MemorySegment struct, int fieldValue) { return altsetting$LAYOUT; } - private static final long altsetting$OFFSET = 4; + private static final long altsetting$OFFSET = $LAYOUT.byteOffset(groupElement("altsetting")); /** * Offset for field: @@ -155,7 +155,7 @@ public static MemorySegment allocateArray(long elementCount, SegmentAllocator al } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { @@ -163,7 +163,7 @@ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consume } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code elementCount * layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java index 648718b9..556be6c4 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevfs_urb.java @@ -77,7 +77,7 @@ public static final GroupLayout layout() { return type$LAYOUT; } - private static final long type$OFFSET = 0; + private static final long type$OFFSET = $LAYOUT.byteOffset(groupElement("type")); /** * Offset for field: @@ -121,7 +121,7 @@ public static void type(MemorySegment struct, byte fieldValue) { return endpoint$LAYOUT; } - private static final long endpoint$OFFSET = 1; + private static final long endpoint$OFFSET = $LAYOUT.byteOffset(groupElement("endpoint")); /** * Offset for field: @@ -165,7 +165,7 @@ public static void endpoint(MemorySegment struct, byte fieldValue) { return status$LAYOUT; } - private static final long status$OFFSET = 4; + private static final long status$OFFSET = $LAYOUT.byteOffset(groupElement("status")); /** * Offset for field: @@ -209,7 +209,7 @@ public static void status(MemorySegment struct, int fieldValue) { return flags$LAYOUT; } - private static final long flags$OFFSET = 8; + private static final long flags$OFFSET = $LAYOUT.byteOffset(groupElement("flags")); /** * Offset for field: @@ -253,7 +253,7 @@ public static void flags(MemorySegment struct, int fieldValue) { return buffer$LAYOUT; } - private static final long buffer$OFFSET = 16; + private static final long buffer$OFFSET = $LAYOUT.byteOffset(groupElement("buffer")); /** * Offset for field: @@ -297,7 +297,7 @@ public static void buffer(MemorySegment struct, MemorySegment fieldValue) { return buffer_length$LAYOUT; } - private static final long buffer_length$OFFSET = 24; + private static final long buffer_length$OFFSET = $LAYOUT.byteOffset(groupElement("buffer_length")); /** * Offset for field: @@ -341,7 +341,7 @@ public static void buffer_length(MemorySegment struct, int fieldValue) { return actual_length$LAYOUT; } - private static final long actual_length$OFFSET = 28; + private static final long actual_length$OFFSET = $LAYOUT.byteOffset(groupElement("actual_length")); /** * Offset for field: @@ -385,7 +385,7 @@ public static void actual_length(MemorySegment struct, int fieldValue) { return start_frame$LAYOUT; } - private static final long start_frame$OFFSET = 32; + private static final long start_frame$OFFSET = $LAYOUT.byteOffset(groupElement("start_frame")); /** * Offset for field: @@ -429,7 +429,7 @@ public static void start_frame(MemorySegment struct, int fieldValue) { return error_count$LAYOUT; } - private static final long error_count$OFFSET = 40; + private static final long error_count$OFFSET = $LAYOUT.byteOffset(groupElement("error_count")); /** * Offset for field: @@ -473,7 +473,7 @@ public static void error_count(MemorySegment struct, int fieldValue) { return signr$LAYOUT; } - private static final long signr$OFFSET = 44; + private static final long signr$OFFSET = $LAYOUT.byteOffset(groupElement("signr")); /** * Offset for field: @@ -517,7 +517,7 @@ public static void signr(MemorySegment struct, int fieldValue) { return usercontext$LAYOUT; } - private static final long usercontext$OFFSET = 48; + private static final long usercontext$OFFSET = $LAYOUT.byteOffset(groupElement("usercontext")); /** * Offset for field: @@ -561,7 +561,7 @@ public static void usercontext(MemorySegment struct, MemorySegment fieldValue) { return iso_frame_desc$LAYOUT; } - private static final long iso_frame_desc$OFFSET = 56; + private static final long iso_frame_desc$OFFSET = $LAYOUT.byteOffset(groupElement("iso_frame_desc")); /** * Offset for field: @@ -622,7 +622,7 @@ public static MemorySegment allocateArray(long elementCount, SegmentAllocator al } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { @@ -630,7 +630,7 @@ public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consume } /** - * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction) (if any). + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). * The returned segment has size {@code elementCount * layout().byteSize()} */ public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs$shared.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs$shared.java new file mode 100644 index 00000000..bdf645da --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs$shared.java @@ -0,0 +1,63 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.usbdevice_fs; + +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; + +public class usbdevice_fs$shared { + + usbdevice_fs$shared() { + // Should not be called directly + } + + public static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool"); + public static final ValueLayout.OfByte C_CHAR =(ValueLayout.OfByte)Linker.nativeLinker().canonicalLayouts().get("char"); + public static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) Linker.nativeLinker().canonicalLayouts().get("short"); + public static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get("int"); + public static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long long"); + public static final ValueLayout.OfFloat C_FLOAT = (ValueLayout.OfFloat) Linker.nativeLinker().canonicalLayouts().get("float"); + public static final ValueLayout.OfDouble C_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get("double"); + public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*")) + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, C_CHAR)); + public static final ValueLayout.OfLong C_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long"); + + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } +} + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java index 8153386f..8521d71b 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/usbdevice_fs/usbdevice_fs.java @@ -12,62 +12,17 @@ import static java.lang.foreign.ValueLayout.*; import static java.lang.foreign.MemoryLayout.PathElement.*; -public class usbdevice_fs { +public class usbdevice_fs extends usbdevice_fs$shared { usbdevice_fs() { // Should not be called directly } static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() .or(Linker.nativeLinker().defaultLookup()); - public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; - public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; - public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; - public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; - public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; - public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; - public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; - public static final AddressLayout C_POINTER = ValueLayout.ADDRESS - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, JAVA_BYTE)); - public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG; private static final int USBDEVFS_URB_TYPE_ISO = (int)0L; /** * {@snippet lang=c : From 98e840fddcb0a405b7d12c05d45ad8cff0d8d3bd Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 10 Sep 2025 20:23:28 +0200 Subject: [PATCH 385/433] Improved compatibility with GraalVM --- java-does-usb/jextract/macos/gen_macos.sh | 4 + .../jextract/macos/remove_fp_upcall.sed | 6 + java-does-usb/pom.xml | 2 +- .../usb/common/EndpointInputStream.java | 5 +- .../usb/common/EndpointOutputStream.java | 5 +- .../usb/macos/MacosUsbDeviceRegistry.java | 20 +- .../gen/iokit/IOCFPlugInInterfaceStruct.java | 78 --- .../macos/gen/iokit/IOUSBDeviceStruct187.java | 481 -------------- .../gen/iokit/IOUSBInterfaceStruct190.java | 624 ------------------ 9 files changed, 22 insertions(+), 1203 deletions(-) create mode 100644 java-does-usb/jextract/macos/remove_fp_upcall.sed diff --git a/java-does-usb/jextract/macos/gen_macos.sh b/java-does-usb/jextract/macos/gen_macos.sh index 24a0c05d..d74e38c2 100755 --- a/java-does-usb/jextract/macos/gen_macos.sh +++ b/java-does-usb/jextract/macos/gen_macos.sh @@ -79,3 +79,7 @@ $JEXTRACT --output ../../src/main/java \ --target-package net.codecrete.usb.macos.gen.mach \ --include-function mach_error_string \ $SDK_DIR/usr/include/mach/mach.h + +sed -i '' -E -f remove_fp_upcall.sed ../../src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java +sed -i '' -E -f remove_fp_upcall.sed ../../src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java +sed -i '' -E -f remove_fp_upcall.sed ../../src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java diff --git a/java-does-usb/jextract/macos/remove_fp_upcall.sed b/java-does-usb/jextract/macos/remove_fp_upcall.sed new file mode 100644 index 00000000..d90e01d3 --- /dev/null +++ b/java-does-usb/jextract/macos/remove_fp_upcall.sed @@ -0,0 +1,6 @@ +/The function pointer signature/,/ \}/ { + s/^.*function pointer signature.*$/ *\//p + d + +} +/MethodHandle UP\$MH = /,/ \}/d diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 51278b36..62bdbbe1 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 1.2.0 + 1.3.0-SNAPSHOT 23 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index 224dc2c4..07a94b7c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -62,7 +62,8 @@ public abstract class EndpointInputStream extends InputStream { protected EndpointInputStream(UsbDeviceImpl device, int endpointNumber, int bufferSize) { this.device = device; this.endpointNumber = endpointNumber; - arena = Arena.ofShared(); + //arena = Arena.ofShared(); // not supported by GraalVM + arena = Arena.ofAuto(); var packetSize = device.getEndpoint(UsbDirection.IN, endpointNumber).getPacketSize(); @@ -218,7 +219,7 @@ private void collectOutstandingTransfers() { completedTransferQueue.clear(); currentTransfer = null; - arena.close(); + //arena.close(); } protected abstract void submitTransferIn(Transfer transfer); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java index e9cbbfae..60478408 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -64,7 +64,8 @@ public abstract class EndpointOutputStream extends OutputStream { protected EndpointOutputStream(UsbDeviceImpl device, int endpointNumber, int bufferSize) { this.device = device; this.endpointNumber = endpointNumber; - arena = Arena.ofShared(); + //arena = Arena.ofShared(); // not supported by GraalVM + arena = Arena.ofAuto(); packetSize = device.getEndpoint(UsbDirection.OUT, endpointNumber).getPacketSize(); @@ -111,7 +112,7 @@ public void close() throws IOException { device = null; availableTransferQueue.clear(); currentTransfer = null; - arena.close(); + //arena.close(); } @Override diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java index 3654be7a..275ab726 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java @@ -12,21 +12,16 @@ import net.codecrete.usb.common.UsbDeviceRegistry; import net.codecrete.usb.macos.gen.corefoundation.CoreFoundation; import net.codecrete.usb.macos.gen.iokit.IOKit; +import net.codecrete.usb.macos.gen.iokit.IOServiceAddMatchingNotification$callback; import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.Linker; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.function.Consumer; import static java.lang.System.Logger.Level.INFO; import static java.lang.foreign.MemorySegment.NULL; -import static java.lang.foreign.ValueLayout.ADDRESS; import static java.lang.foreign.ValueLayout.JAVA_INT; import static java.lang.foreign.ValueLayout.JAVA_LONG; import static net.codecrete.usb.macos.CoreFoundationHelper.createCFStringRef; @@ -86,10 +81,8 @@ protected void monitorDevices() { CoreFoundation.CFRunLoopAddSource(runLoop, runLoopSource, IOKit.kCFRunLoopDefaultMode()); // setup notification for connected devices - var onDeviceConnectedMH = MethodHandles.lookup().findVirtual(MacosUsbDeviceRegistry.class, - "onDevicesConnected", MethodType.methodType(void.class, MemorySegment.class, int.class)); var deviceConnectedIter = setupNotification(arena, notifyPort, IOKit.kIOFirstMatchNotification(), - onDeviceConnectedMH); + this::onDevicesConnected); // iterate current devices in order to arm the notifications (and build initial device list) var deviceList = new ArrayList(); @@ -97,10 +90,8 @@ protected void monitorDevices() { setInitialDeviceList(deviceList); // setup notification for disconnected devices - var onDeviceDisconnectedMH = MethodHandles.lookup().findVirtual(MacosUsbDeviceRegistry.class, - "onDevicesDisconnected", MethodType.methodType(void.class, MemorySegment.class, int.class)); var deviceDisconnectedIter = setupNotification(arena, notifyPort, IOKit.kIOTerminatedNotification(), - onDeviceDisconnectedMH); + this::onDevicesDisconnected); // iterate current devices in order to arm the notifications onDevicesDisconnected(NULL, deviceDisconnectedIter); @@ -218,14 +209,13 @@ private UsbDevice createDevice(Long entryID, int service, MemorySegment deviceIn } private int setupNotification(Arena arena, MemorySegment notifyPort, MemorySegment notificationType, - MethodHandle callback) { + IOServiceAddMatchingNotification$callback.Function callback) { // new matching dictionary for (dis)connected device notifications (NOSONAR) var matchingDict = IOKit.IOServiceMatching(IOKit.kIOUSBDeviceClassName()); // create callback stub - var onDeviceCallbackStub = Linker.nativeLinker().upcallStub(callback.bindTo(this), - FunctionDescriptor.ofVoid(ADDRESS, JAVA_INT), Arena.global()); + var onDeviceCallbackStub = IOServiceAddMatchingNotification$callback.allocate(callback, Arena.global()); // Set up a notification to be called when a device is first matched / terminated by I/O Kit. // This method consumes the matchingDict reference. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java index 8a027f5a..74f3414d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOCFPlugInInterfaceStruct.java @@ -109,11 +109,7 @@ private QueryInterface() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1, MemorySegment _x2); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -129,15 +125,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(QueryInterface.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(QueryInterface.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -211,11 +198,7 @@ private AddRef() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -229,15 +212,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(AddRef.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(AddRef.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -311,11 +285,7 @@ private Release() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -329,15 +299,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(Release.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(Release.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -499,11 +460,7 @@ private Probe() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1, int _x2, MemorySegment _x3); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -520,15 +477,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(Probe.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(Probe.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -602,11 +550,7 @@ private Start() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1, int _x2); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -622,15 +566,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(Start.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(Start.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -704,11 +639,7 @@ private Stop() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -722,15 +653,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(Stop.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(Stop.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java index b8bba278..db64afe0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBDeviceStruct187.java @@ -166,11 +166,7 @@ private QueryInterface() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1, MemorySegment _x2); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -186,15 +182,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(QueryInterface.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(QueryInterface.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -268,11 +255,7 @@ private AddRef() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -286,15 +269,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(AddRef.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(AddRef.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -368,11 +342,7 @@ private Release() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -386,15 +356,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(Release.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(Release.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -468,11 +429,7 @@ private CreateDeviceAsyncEventSource() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -487,15 +444,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(CreateDeviceAsyncEventSource.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(CreateDeviceAsyncEventSource.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -569,11 +517,7 @@ private GetDeviceAsyncEventSource() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - MemorySegment apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_POINTER, @@ -587,15 +531,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceAsyncEventSource.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetDeviceAsyncEventSource.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -669,11 +604,7 @@ private CreateDeviceAsyncPort() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -688,15 +619,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(CreateDeviceAsyncPort.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(CreateDeviceAsyncPort.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -770,11 +692,7 @@ private GetDeviceAsyncPort() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -788,15 +706,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceAsyncPort.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetDeviceAsyncPort.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -870,11 +779,7 @@ private USBDeviceOpen() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -888,15 +793,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(USBDeviceOpen.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(USBDeviceOpen.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -970,11 +866,7 @@ private USBDeviceClose() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -988,15 +880,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(USBDeviceClose.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(USBDeviceClose.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1070,11 +953,7 @@ private GetDeviceClass() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1089,15 +968,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceClass.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetDeviceClass.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1171,11 +1041,7 @@ private GetDeviceSubClass() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1190,15 +1056,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceSubClass.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetDeviceSubClass.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1272,11 +1129,7 @@ private GetDeviceProtocol() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1291,15 +1144,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceProtocol.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetDeviceProtocol.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1373,11 +1217,7 @@ private GetDeviceVendor() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1392,15 +1232,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceVendor.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetDeviceVendor.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1474,11 +1305,7 @@ private GetDeviceProduct() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1493,15 +1320,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceProduct.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetDeviceProduct.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1575,11 +1393,7 @@ private GetDeviceReleaseNumber() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1594,15 +1408,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceReleaseNumber.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetDeviceReleaseNumber.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1676,11 +1481,7 @@ private GetDeviceAddress() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1695,15 +1496,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceAddress.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetDeviceAddress.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1777,11 +1569,7 @@ private GetDeviceBusPowerAvailable() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1796,15 +1584,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceBusPowerAvailable.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetDeviceBusPowerAvailable.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1878,11 +1657,7 @@ private GetDeviceSpeed() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1897,15 +1672,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceSpeed.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetDeviceSpeed.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1979,11 +1745,7 @@ private GetNumberOfConfigurations() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1998,15 +1760,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetNumberOfConfigurations.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetNumberOfConfigurations.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2080,11 +1833,7 @@ private GetLocationID() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2099,15 +1848,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetLocationID.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetLocationID.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2181,11 +1921,7 @@ private GetConfigurationDescriptorPtr() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, MemorySegment _x2); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2201,15 +1937,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetConfigurationDescriptorPtr.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetConfigurationDescriptorPtr.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2283,11 +2010,7 @@ private GetConfiguration() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2302,15 +2025,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetConfiguration.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetConfiguration.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2384,11 +2098,7 @@ private SetConfiguration() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2403,15 +2113,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(SetConfiguration.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(SetConfiguration.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2485,11 +2186,7 @@ private GetBusFrameNumber() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1, MemorySegment _x2); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2505,15 +2202,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetBusFrameNumber.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetBusFrameNumber.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2587,11 +2275,7 @@ private ResetDevice() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2605,15 +2289,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(ResetDevice.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(ResetDevice.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2687,11 +2362,7 @@ private DeviceRequest() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2706,15 +2377,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(DeviceRequest.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(DeviceRequest.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2788,11 +2450,7 @@ private DeviceRequestAsync() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1, MemorySegment _x2, MemorySegment _x3); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2809,15 +2467,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(DeviceRequestAsync.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(DeviceRequestAsync.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2891,11 +2540,7 @@ private CreateInterfaceIterator() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1, MemorySegment _x2); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2911,15 +2556,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(CreateInterfaceIterator.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(CreateInterfaceIterator.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2993,11 +2629,7 @@ private USBDeviceOpenSeize() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3011,15 +2643,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(USBDeviceOpenSeize.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(USBDeviceOpenSeize.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3093,11 +2716,7 @@ private DeviceRequestTO() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3112,15 +2731,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(DeviceRequestTO.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(DeviceRequestTO.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3194,11 +2804,7 @@ private DeviceRequestAsyncTO() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1, MemorySegment _x2, MemorySegment _x3); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3215,15 +2821,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(DeviceRequestAsyncTO.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(DeviceRequestAsyncTO.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3297,11 +2894,7 @@ private USBDeviceSuspend() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3316,15 +2909,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(USBDeviceSuspend.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(USBDeviceSuspend.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3398,11 +2982,7 @@ private USBDeviceAbortPipeZero() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3416,15 +2996,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(USBDeviceAbortPipeZero.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(USBDeviceAbortPipeZero.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3498,11 +3069,7 @@ private USBGetManufacturerStringIndex() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3517,15 +3084,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(USBGetManufacturerStringIndex.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(USBGetManufacturerStringIndex.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3599,11 +3157,7 @@ private USBGetProductStringIndex() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3618,15 +3172,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(USBGetProductStringIndex.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(USBGetProductStringIndex.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3700,11 +3245,7 @@ private USBGetSerialNumberStringIndex() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3719,15 +3260,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(USBGetSerialNumberStringIndex.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(USBGetSerialNumberStringIndex.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3801,11 +3333,7 @@ private USBDeviceReEnumerate() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, int _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3820,15 +3348,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(USBDeviceReEnumerate.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(USBDeviceReEnumerate.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java index ddcc6243..f63ecf5f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java @@ -188,11 +188,7 @@ private QueryInterface() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1, MemorySegment _x2); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -208,15 +204,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(QueryInterface.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(QueryInterface.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -290,11 +277,7 @@ private AddRef() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -308,15 +291,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(AddRef.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(AddRef.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -390,11 +364,7 @@ private Release() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -408,15 +378,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(Release.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(Release.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -490,11 +451,7 @@ private CreateInterfaceAsyncEventSource() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -509,15 +466,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(CreateInterfaceAsyncEventSource.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(CreateInterfaceAsyncEventSource.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -591,11 +539,7 @@ private GetInterfaceAsyncEventSource() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - MemorySegment apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_POINTER, @@ -609,15 +553,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetInterfaceAsyncEventSource.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetInterfaceAsyncEventSource.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -691,11 +626,7 @@ private CreateInterfaceAsyncPort() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -710,15 +641,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(CreateInterfaceAsyncPort.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(CreateInterfaceAsyncPort.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -792,11 +714,7 @@ private GetInterfaceAsyncPort() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -810,15 +728,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetInterfaceAsyncPort.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetInterfaceAsyncPort.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -892,11 +801,7 @@ private USBInterfaceOpen() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -910,15 +815,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(USBInterfaceOpen.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(USBInterfaceOpen.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -992,11 +888,7 @@ private USBInterfaceClose() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1010,15 +902,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(USBInterfaceClose.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(USBInterfaceClose.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1092,11 +975,7 @@ private GetInterfaceClass() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1111,15 +990,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetInterfaceClass.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetInterfaceClass.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1193,11 +1063,7 @@ private GetInterfaceSubClass() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1212,15 +1078,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetInterfaceSubClass.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetInterfaceSubClass.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1294,11 +1151,7 @@ private GetInterfaceProtocol() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1313,15 +1166,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetInterfaceProtocol.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetInterfaceProtocol.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1395,11 +1239,7 @@ private GetDeviceVendor() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1414,15 +1254,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceVendor.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetDeviceVendor.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1496,11 +1327,7 @@ private GetDeviceProduct() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1515,15 +1342,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceProduct.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetDeviceProduct.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1597,11 +1415,7 @@ private GetDeviceReleaseNumber() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1616,15 +1430,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDeviceReleaseNumber.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetDeviceReleaseNumber.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1698,11 +1503,7 @@ private GetConfigurationValue() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1717,15 +1518,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetConfigurationValue.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetConfigurationValue.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1799,11 +1591,7 @@ private GetInterfaceNumber() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1818,15 +1606,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetInterfaceNumber.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetInterfaceNumber.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -1900,11 +1679,7 @@ private GetAlternateSetting() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -1919,15 +1694,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetAlternateSetting.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetAlternateSetting.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2001,11 +1767,7 @@ private GetNumEndpoints() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2020,15 +1782,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetNumEndpoints.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetNumEndpoints.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2102,11 +1855,7 @@ private GetLocationID() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2121,15 +1870,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetLocationID.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetLocationID.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2203,11 +1943,7 @@ private GetDevice() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2222,15 +1958,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetDevice.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetDevice.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2304,11 +2031,7 @@ private SetAlternateInterface() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2323,15 +2046,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(SetAlternateInterface.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(SetAlternateInterface.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2405,11 +2119,7 @@ private GetBusFrameNumber() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1, MemorySegment _x2); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2425,15 +2135,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetBusFrameNumber.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetBusFrameNumber.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2507,11 +2208,7 @@ private ControlRequest() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, MemorySegment _x2); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2527,15 +2224,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(ControlRequest.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(ControlRequest.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2609,11 +2297,7 @@ private ControlRequestAsync() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, MemorySegment _x4); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2631,15 +2315,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(ControlRequestAsync.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(ControlRequestAsync.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2713,11 +2388,7 @@ private GetPipeProperties() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, MemorySegment _x4, MemorySegment _x5, MemorySegment _x6); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2737,15 +2408,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetPipeProperties.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetPipeProperties.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2819,11 +2481,7 @@ private GetPipeStatus() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2838,15 +2496,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetPipeStatus.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetPipeStatus.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -2920,11 +2569,7 @@ private AbortPipe() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -2939,15 +2584,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(AbortPipe.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(AbortPipe.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3021,11 +2657,7 @@ private ResetPipe() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3040,15 +2672,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(ResetPipe.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(ResetPipe.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3122,11 +2745,7 @@ private ClearPipeStall() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3141,15 +2760,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(ClearPipeStall.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(ClearPipeStall.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3223,11 +2833,7 @@ private ReadPipe() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3244,15 +2850,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(ReadPipe.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(ReadPipe.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3326,11 +2923,7 @@ private WritePipe() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3347,15 +2940,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(WritePipe.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(WritePipe.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3429,11 +3013,7 @@ private ReadPipeAsync() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, MemorySegment _x4, MemorySegment _x5); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3452,15 +3032,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(ReadPipeAsync.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(ReadPipeAsync.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3534,11 +3105,7 @@ private WritePipeAsync() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, MemorySegment _x4, MemorySegment _x5); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3557,15 +3124,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(WritePipeAsync.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(WritePipeAsync.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3639,11 +3197,7 @@ private ReadIsochPipeAsync() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, long _x3, int _x4, MemorySegment _x5, MemorySegment _x6, MemorySegment _x7); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3664,15 +3218,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(ReadIsochPipeAsync.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(ReadIsochPipeAsync.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3746,11 +3291,7 @@ private WriteIsochPipeAsync() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, long _x3, int _x4, MemorySegment _x5, MemorySegment _x6, MemorySegment _x7); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3771,15 +3312,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(WriteIsochPipeAsync.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(WriteIsochPipeAsync.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3853,11 +3385,7 @@ private ControlRequestTO() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, MemorySegment _x2); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3873,15 +3401,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(ControlRequestTO.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(ControlRequestTO.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -3955,11 +3474,7 @@ private ControlRequestAsyncTO() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, MemorySegment _x4); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -3977,15 +3492,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(ControlRequestAsyncTO.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(ControlRequestAsyncTO.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -4059,11 +3565,7 @@ private ReadPipeTO() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, MemorySegment _x3, int _x4, int _x5); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -4082,15 +3584,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(ReadPipeTO.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(ReadPipeTO.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -4164,11 +3657,7 @@ private WritePipeTO() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, int _x4, int _x5); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -4187,15 +3676,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(WritePipeTO.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(WritePipeTO.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -4269,11 +3749,7 @@ private ReadPipeAsyncTO() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, int _x4, int _x5, MemorySegment _x6, MemorySegment _x7); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -4294,15 +3770,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(ReadPipeAsyncTO.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(ReadPipeAsyncTO.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -4376,11 +3843,7 @@ private WritePipeAsyncTO() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, MemorySegment _x2, int _x3, int _x4, int _x5, MemorySegment _x6, MemorySegment _x7); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -4401,15 +3864,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(WritePipeAsyncTO.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(WritePipeAsyncTO.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -4483,11 +3937,7 @@ private USBInterfaceGetStringIndex() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -4502,15 +3952,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(USBInterfaceGetStringIndex.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(USBInterfaceGetStringIndex.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -4584,11 +4025,7 @@ private USBInterfaceOpenSeize() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -4602,15 +4039,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(USBInterfaceOpenSeize.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(USBInterfaceOpenSeize.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -4684,11 +4112,7 @@ private ClearPipeStallBothEnds() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -4703,15 +4127,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(ClearPipeStallBothEnds.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(ClearPipeStallBothEnds.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -4785,11 +4200,7 @@ private SetPipePolicy() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, short _x2, byte _x3); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -4806,15 +4217,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(SetPipePolicy.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(SetPipePolicy.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -4888,11 +4290,7 @@ private GetBandwidthAvailable() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, MemorySegment _x1); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -4907,15 +4305,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetBandwidthAvailable.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetBandwidthAvailable.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); @@ -4989,11 +4378,7 @@ private GetEndpointProperties() { } /** - * The function pointer signature, expressed as a functional interface */ - public interface Function { - int apply(MemorySegment _x0, byte _x1, byte _x2, byte _x3, MemorySegment _x4, MemorySegment _x5, MemorySegment _x6); - } private static final FunctionDescriptor $DESC = FunctionDescriptor.of( IOKit.C_INT, @@ -5013,15 +4398,6 @@ public static FunctionDescriptor descriptor() { return $DESC; } - private static final MethodHandle UP$MH = IOKit.upcallHandle(GetEndpointProperties.Function.class, "apply", $DESC); - - /** - * Allocates a new upcall stub, whose implementation is defined by {@code fi}. - * The lifetime of the returned segment is managed by {@code arena} - */ - public static MemorySegment allocate(GetEndpointProperties.Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); - } private static final MethodHandle DOWN$MH = Linker.nativeLinker().downcallHandle($DESC); From 1339041480e8f96ed7355315dcd7e0b2fafb1ecf Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 10 Sep 2025 20:56:40 +0200 Subject: [PATCH 386/433] Test application for native image --- .../config/macos/reachability-metadata.json | 318 +++++++++++++++++ test-graalvm/pom.xml | 84 +++++ .../java/net/codecrete/usb/examples/App.java | 324 ++++++++++++++++++ .../usb/examples/CommunicationException.java | 21 ++ .../codecrete/usb/examples/DeviceConfig.java | 68 ++++ .../test_graalvm/native-image.properties | 1 + 6 files changed, 816 insertions(+) create mode 100644 test-graalvm/config/macos/reachability-metadata.json create mode 100644 test-graalvm/pom.xml create mode 100644 test-graalvm/src/main/java/net/codecrete/usb/examples/App.java create mode 100644 test-graalvm/src/main/java/net/codecrete/usb/examples/CommunicationException.java create mode 100644 test-graalvm/src/main/java/net/codecrete/usb/examples/DeviceConfig.java create mode 100644 test-graalvm/src/main/resources/META-INF/native-image/net.codecrete.usb.examples/test_graalvm/native-image.properties diff --git a/test-graalvm/config/macos/reachability-metadata.json b/test-graalvm/config/macos/reachability-metadata.json new file mode 100644 index 00000000..113fb587 --- /dev/null +++ b/test-graalvm/config/macos/reachability-metadata.json @@ -0,0 +1,318 @@ +{ + "foreign": { + "upcalls": [ + { + "returnType": "void", + "parameterTypes": [ + "void*", + "jint", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "jint", + "void*", + "void*" + ] + }, + { + "returnType": "void", + "parameterTypes": [ + "void*", + "jint" + ] + } + ], + "downcalls": [ + { + "returnType": "void", + "parameterTypes": [ + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "void", + "parameterTypes": [ + "void*", + "struct(jlong,jlong)", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*", + "jlong" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jint", + "void*", + "jdouble", + "jdouble", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "void*", + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint" + ] + }, + { + "returnType": "jlong", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "void*", + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "jint", + "void*", + "void*", + "jint" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "jint", + "void*", + "void*" + ] + }, + { + "returnType": "jbyte", + "parameterTypes": [ + "void*", + "jlong", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "struct(jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte)" + ] + }, + { + "returnType": "void", + "parameterTypes": [] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "void*", + "jint", + "jint", + "jint", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "void*", + "void*", + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "jlong", + "parameterTypes": [] + }, + { + "returnType": "void", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "jint" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*", + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "void*", + "jint", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "struct(jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte)", + "void*" + ] + }, + { + "returnType": "struct(jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte)", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "void", + "parameterTypes": [ + "void*", + "jint" + ] + } + ] + }, + "reflection": [ + { + "type": "net.codecrete.usb.macos.gen.corefoundation.CFMessagePortCreateLocal$callout$Function", + "methods": [ + { + "name": "apply", + "parameterTypes": [ + "java.lang.foreign.MemorySegment", + "int", + "java.lang.foreign.MemorySegment", + "java.lang.foreign.MemorySegment" + ] + } + ] + }, + { + "type": "net.codecrete.usb.macos.gen.iokit.IOServiceAddMatchingNotification$callback$Function", + "methods": [ + { + "name": "apply", + "parameterTypes": [ + "java.lang.foreign.MemorySegment", + "int" + ] + } + ] + } + ] +} diff --git a/test-graalvm/pom.xml b/test-graalvm/pom.xml new file mode 100644 index 00000000..e5e516ce --- /dev/null +++ b/test-graalvm/pom.xml @@ -0,0 +1,84 @@ + + 4.0.0 + + net.codecrete.usb.examples + test_graalvm + jar + 1.0-SNAPSHOT + test_graalvm + https://www.github.com/manuelbl/java-does-usb + + + 25 + 25 + UTF-8 + 0.11.0 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.14.0 + + true + + + + org.apache.maven.plugins + maven-jar-plugin + 3.4.2 + + + + net.codecrete.usb.examples.App + true + + + + + + + + + + net.codecrete.usb + java-does-usb + 1.3.0-SNAPSHOT + + + junit + junit + 3.8.1 + test + + + + + + native + + + + org.graalvm.buildtools + native-maven-plugin + ${native.maven.plugin.version} + true + + + build-native + + compile-no-fork + + package + + + + + + + + + diff --git a/test-graalvm/src/main/java/net/codecrete/usb/examples/App.java b/test-graalvm/src/main/java/net/codecrete/usb/examples/App.java new file mode 100644 index 00000000..18dd1636 --- /dev/null +++ b/test-graalvm/src/main/java/net/codecrete/usb/examples/App.java @@ -0,0 +1,324 @@ +// +// Java Does USB +// Copyright (c) 2025 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.examples; + +import net.codecrete.usb.Usb; +import net.codecrete.usb.UsbDevice; +import net.codecrete.usb.UsbException; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static java.time.Duration.ofSeconds; + +/** + * Test for robustness when USB devices is unplugged during operation. + * + *

+ * Requires use of test device. + *

+ */ +@SuppressWarnings({"java:S106", "java:S2189"}) +public class App { + private static final Map activeDevices = new HashMap<>(); + + public static void main(String[] args) throws IOException { + System.out.println("Plug and unplug test device multiple times."); + System.out.println("Hit ENTER to exit."); + + Usb.setOnDeviceConnected(App::onPluggedDevice); + Usb.setOnDeviceDisconnected(App::onUnpluggedDevice); + Usb.getDevices().forEach(App::onPluggedDevice); + + //noinspection ResultOfMethodCallIgnored + System.in.read(); + } + + private static void onPluggedDevice(UsbDevice device) { + var config = DeviceConfig.getConfig(device); + if (config.isEmpty()) + return; + + var worker = new DeviceWorker(device, config.get()); + activeDevices.put(device, worker); + worker.start(); + } + + private static void onUnpluggedDevice(UsbDevice device) { + var config = DeviceConfig.getConfig(device); + if (config.isEmpty()) + return; + + var worker = activeDevices.remove(device); + worker.setDisconnectTime(System.currentTimeMillis()); + worker.join(); + + // test handling of disconnected devices + new Thread(() -> { + sleep(2000); + try { + device.open(); + System.err.println("Device should not be openable after disconnect"); + } catch (UsbException e) { + if (!e.getMessage().contains("disconnected")) + System.err.println("Unexpected error: " + e.getMessage()); + } + }).start(); + } + + @SuppressWarnings({"SameParameterValue", "java:S2925"}) + private static void sleep(long millis) { + try { + Thread.sleep(millis); + + } catch (InterruptedException _) { + Thread.currentThread().interrupt(); + } + } + + static class DeviceWorker { + + private final UsbDevice device; + private final DeviceConfig config; + + private final int seed; + + private long disconnectTime; + + private final Map workTracking = new HashMap<>(); + + DeviceWorker(UsbDevice device, DeviceConfig config) { + this.device = device; + this.config = config; + this.seed = (int) System.currentTimeMillis(); + } + + void start() { + System.out.println("Device connected"); + + device.open(); + device.claimInterface(config.interfaceNumber()); + + // start loopback sender and receiver + startThread((seed & 1) != 0 ? this::sendLoopbackDataStream : this::sendLoopbackData); + startThread((seed & 2) != 0 ? this::receiveLoopbackDataStream : this::receiveLoopbackData); + + // start echo sender and receiver + if (config.endpointEchoOut() > 0) { + startThread(this::sendEcho); + startThread(this::receiveEcho); + } + } + + private void startThread(Runnable action) { + var thread = new Thread(() -> runAction(action)); + var work = new Work(); + workTracking.put(thread, work); + thread.start(); + } + + void join() { + // wait for threads to finish + for (var thread : workTracking.keySet()) { + try { + boolean terminated = thread.join(ofSeconds(5)); + if (!terminated) + System.err.printf("Thread \"%s\" failed to join within 5s%n", thread.getName()); + + } catch (InterruptedException _) { + Thread.currentThread().interrupt(); + } + } + + device.close(); + + // check achieved work + for (var e : workTracking.entrySet()) { + var work = e.getValue(); + var expectedWork = work.expectedWorkPerSec * 0.001 * (work.finishTime - work.startTime); + if (work.actualWork < expectedWork) + System.err.printf("Thread \"%s\" achieved insufficient work executed. Expected: %.0f, achieved: %d%n", + e.getKey().getName(), expectedWork, work.actualWork); + } + + // check that the threads haven't terminated early + for (var e : workTracking.entrySet()) { + long duration = Math.abs(e.getValue().finishTime - disconnectTime); + if (duration > 500) + System.err.printf("Thread \"%s\" has likely crashed early%n", e.getKey().getName()); + } + + System.out.println("Device disconnected"); + } + + void setDisconnectTime(long time) { + disconnectTime = time; + } + + private synchronized void logFinish() { + var work = workTracking.get(Thread.currentThread()); + work.finishTime = System.currentTimeMillis(); + } + + private void logStart(String operation, long expectedWorkPerSec) { + Thread.currentThread().setName(operation); + var work = workTracking.get(Thread.currentThread()); + work.startTime = System.currentTimeMillis(); + work.expectedWorkPerSec = expectedWorkPerSec; + } + + private void logWork(long amount) { + var work = workTracking.get(Thread.currentThread()); + work.actualWork += amount; + } + + private void runAction(Runnable action) { + try { + action.run(); + } catch (UsbException _) { + logFinish(); + } + } + + private void sendLoopbackData() { + logStart("sending loopback data", 300_000); + var prng = new PRNG(); + var data = new byte[5000]; + //noinspection InfiniteLoopStatement + while (true) { + prng.fill(data); + device.transferOut(config.endpointLoopbackOut(), data, 1000); + logWork(data.length); + } + } + + private void receiveLoopbackData() { + logStart("receiving loopback data", 300_000); + var prng = new PRNG(); + //noinspection InfiniteLoopStatement + while (true) { + byte[] data = device.transferIn(config.endpointLoopbackIn()); + int index = prng.verify(data); + if (index >= 0) + throw new CommunicationException("invalid data received"); + logWork(data.length); + } + } + + private void sendLoopbackDataStream() { + logStart("sending loopback data with output stream", 300_000); + var prng = new PRNG(); + var data = new byte[5000]; + try (var os = device.openOutputStream(config.endpointLoopbackOut())) { + //noinspection InfiniteLoopStatement + while (true) { + prng.fill(data); + os.write(data); + logWork(data.length); + } + } catch (IOException e) { + throw new CommunicationException(e); + } + } + + private void receiveLoopbackDataStream() { + logStart("receiving loopback data with input stream", 300_000); + var prng = new PRNG(); + try (var is = device.openInputStream(config.endpointLoopbackIn())) { + //noinspection InfiniteLoopStatement + while (true) { + var data = new byte[2000]; + int n = is.read(data); + int index = prng.verify(data, n); + if (index >= 0) + throw new CommunicationException("invalid data received"); + logWork(n); + } + } catch (IOException e) { + throw new CommunicationException(e); + } + } + + private void sendEcho() { + logStart("sending echo", 7); + var data = new byte[]{0x03, 0x45, 0x73, (byte) 0xb3, (byte) 0x9f, 0x3f, 0x00, 0x6a}; + //noinspection InfiniteLoopStatement + while (true) { + device.transferOut(config.endpointEchoOut(), data); + logWork(1); + sleep(100); + } + } + + private void receiveEcho() { + logStart("receiving echo", 14); + //noinspection InfiniteLoopStatement + while (true) { + device.transferIn(config.endpointEchoIn()); + logWork(1); + } + } + } + + static class Work { + long startTime; + long expectedWorkPerSec; + long actualWork; + long finishTime; + } + + /** + * Pseudo random number generator + */ + static class PRNG { + private int state; + private int nBytes; + private int bits; + + int next() { + int x = state; + x ^= x << 13; + x ^= x >>> 17; + x ^= x << 5; + state = x; + return x; + } + + void fill(byte[] data) { + int len = data.length; + for (int i = 0; i < len; i++) { + if (nBytes == 0) { + bits = next(); + nBytes = 4; + } + data[i] = (byte) bits; + bits >>>= 8; + nBytes--; + } + } + + int verify(byte[] data) { + return verify(data, data.length); + } + + int verify(byte[] data, int len) { + for (int i = 0; i < len; i++) { + if (nBytes == 0) { + bits = next(); + nBytes = 4; + } + if (data[i] != (byte) bits) + return i; + bits >>>= 8; + nBytes--; + } + return -1; + } + } +} diff --git a/test-graalvm/src/main/java/net/codecrete/usb/examples/CommunicationException.java b/test-graalvm/src/main/java/net/codecrete/usb/examples/CommunicationException.java new file mode 100644 index 00000000..d8660f7f --- /dev/null +++ b/test-graalvm/src/main/java/net/codecrete/usb/examples/CommunicationException.java @@ -0,0 +1,21 @@ +// +// Java Does USB +// Copyright (c) 2025 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.examples; + +import java.io.IOException; + +public class CommunicationException extends RuntimeException { + + public CommunicationException(String message) { + super(message); + } + + public CommunicationException(IOException cause) { + super("Error in communication with USB device", cause); + } +} diff --git a/test-graalvm/src/main/java/net/codecrete/usb/examples/DeviceConfig.java b/test-graalvm/src/main/java/net/codecrete/usb/examples/DeviceConfig.java new file mode 100644 index 00000000..05bf8bdd --- /dev/null +++ b/test-graalvm/src/main/java/net/codecrete/usb/examples/DeviceConfig.java @@ -0,0 +1,68 @@ +// +// Java Does USB +// Copyright (c) 2025 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// +// Configuration information about test device +// + +package net.codecrete.usb.examples; + +import net.codecrete.usb.UsbDevice; + +import java.util.Optional; +import java.util.stream.Stream; + +/** + * Test device configuration + * @param vid vendor ID + * @param pid product ID + * @param isComposite indicates if this is the composite test device + * @param interfaceNumber interface number for loopback and echo endpoints + * @param endpointLoopbackOut loopback OUT endpoint number + * @param endpointLoopbackIn loopback IN endpoint number + * @param endpointEchoOut echo OUT endpoint number + * @param endpointEchoIn echo IN endpoint number + */ +public record DeviceConfig(int vid, int pid, + boolean isComposite, + int interfaceNumber, + int endpointLoopbackOut, int endpointLoopbackIn, + int endpointEchoOut, int endpointEchoIn +) { + + private static final DeviceConfig LOOPBACK_DEVICE = new DeviceConfig( + 0xcafe, + 0xceaf, + false, + 0, + 1, + 2, + 3, + 3 + ); + + private static final DeviceConfig COMPOSITE_DEVICE = new DeviceConfig( + 0xcafe, + 0xcea0, + true, + 3, + 1, + 2, + -1, + -1 + ); + + + /** + * Gets the configuration fo the specified USB device. + * @param device USB device + * @return configuration, or empty if the USB device is not a test device + */ + public static Optional getConfig(UsbDevice device) { + return Stream.of(LOOPBACK_DEVICE, COMPOSITE_DEVICE) + .filter(config -> device.getVendorId() == config.vid() && device.getProductId() == config.pid()) + .findFirst(); + } +} diff --git a/test-graalvm/src/main/resources/META-INF/native-image/net.codecrete.usb.examples/test_graalvm/native-image.properties b/test-graalvm/src/main/resources/META-INF/native-image/net.codecrete.usb.examples/test_graalvm/native-image.properties new file mode 100644 index 00000000..4e4f3471 --- /dev/null +++ b/test-graalvm/src/main/resources/META-INF/native-image/net.codecrete.usb.examples/test_graalvm/native-image.properties @@ -0,0 +1 @@ +Args = --enable-native-access=ALL-UNNAMED -H:ConfigurationFileDirectories=config/macos From 9574e20a20d1c44d78f64af91225b70eed8bc3e7 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Wed, 10 Sep 2025 21:13:10 +0200 Subject: [PATCH 387/433] Example project for native image --- examples/enumerate_native/README.md | 47 +++ .../config/macos/reachability-metadata.json | 318 ++++++++++++++++++ examples/enumerate_native/pom.xml | 84 +++++ .../java/net/codecrete/usb/examples/App.java | 19 ++ .../enumerate_native/native-image.properties | 1 + 5 files changed, 469 insertions(+) create mode 100644 examples/enumerate_native/README.md create mode 100644 examples/enumerate_native/config/macos/reachability-metadata.json create mode 100644 examples/enumerate_native/pom.xml create mode 100644 examples/enumerate_native/src/main/java/net/codecrete/usb/examples/App.java create mode 100644 examples/enumerate_native/src/main/resources/META-INF/native-image/net.codecrete.usb.examples/enumerate_native/native-image.properties diff --git a/examples/enumerate_native/README.md b/examples/enumerate_native/README.md new file mode 100644 index 00000000..23a351bd --- /dev/null +++ b/examples/enumerate_native/README.md @@ -0,0 +1,47 @@ +# Device Enumeration (Native) + +This example project demonstrates how th build a native application that +enumerates connected devices using [GraalVM](https://www.graalvm.org/) and +this _Java Does USB_ library. + +## Build and Run + +### Prerequisites + +- [GraalVM](https://www.graalvm.org/) 25 or higher +- [Maven](https://maven.apache.org/) 3.9 or higher + + +### Preparation + +GraalVM needs help to learn about the Java FFM downcall and upcall descriptors, +and it needs some help to include all required methods. The relevant items +differ from operating system to operating system. When building the native image, +the operating system must be selected by changing the path in the file +`native-image.properties` in the directory +`src/main/resources/META-INF/native-image/net.codecrete.usb.examples/enumerate_native`. + +```properties +Args = --enable-native-access=ALL-UNNAMED -H:ConfigurationFileDirectories=config/macos +``` + +Note the last word of the line. In this case, it is `macos`. Change this to +`linux` or `windows` if needed. (Windows and Linux are yet to come.) + +In your own Maven project, you might also need to move the file or rather rename +directory. It must be named according to the pattern +`src/main/resources/META-INF/native-image//`. + + +### Building + +```shell +mvn -Dnative package +``` + + +### Running + +```shell +./target/enumerate-native +``` diff --git a/examples/enumerate_native/config/macos/reachability-metadata.json b/examples/enumerate_native/config/macos/reachability-metadata.json new file mode 100644 index 00000000..113fb587 --- /dev/null +++ b/examples/enumerate_native/config/macos/reachability-metadata.json @@ -0,0 +1,318 @@ +{ + "foreign": { + "upcalls": [ + { + "returnType": "void", + "parameterTypes": [ + "void*", + "jint", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "jint", + "void*", + "void*" + ] + }, + { + "returnType": "void", + "parameterTypes": [ + "void*", + "jint" + ] + } + ], + "downcalls": [ + { + "returnType": "void", + "parameterTypes": [ + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "void", + "parameterTypes": [ + "void*", + "struct(jlong,jlong)", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*", + "jlong" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jint", + "void*", + "jdouble", + "jdouble", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "void*", + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint" + ] + }, + { + "returnType": "jlong", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "void*", + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "jint", + "void*", + "void*", + "jint" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "jint", + "void*", + "void*" + ] + }, + { + "returnType": "jbyte", + "parameterTypes": [ + "void*", + "jlong", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "struct(jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte)" + ] + }, + { + "returnType": "void", + "parameterTypes": [] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "void*", + "jint", + "jint", + "jint", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "void*", + "void*", + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "jlong", + "parameterTypes": [] + }, + { + "returnType": "void", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "jint" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*", + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "void*", + "jint", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "struct(jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte)", + "void*" + ] + }, + { + "returnType": "struct(jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte)", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "void", + "parameterTypes": [ + "void*", + "jint" + ] + } + ] + }, + "reflection": [ + { + "type": "net.codecrete.usb.macos.gen.corefoundation.CFMessagePortCreateLocal$callout$Function", + "methods": [ + { + "name": "apply", + "parameterTypes": [ + "java.lang.foreign.MemorySegment", + "int", + "java.lang.foreign.MemorySegment", + "java.lang.foreign.MemorySegment" + ] + } + ] + }, + { + "type": "net.codecrete.usb.macos.gen.iokit.IOServiceAddMatchingNotification$callback$Function", + "methods": [ + { + "name": "apply", + "parameterTypes": [ + "java.lang.foreign.MemorySegment", + "int" + ] + } + ] + } + ] +} diff --git a/examples/enumerate_native/pom.xml b/examples/enumerate_native/pom.xml new file mode 100644 index 00000000..09bdbe59 --- /dev/null +++ b/examples/enumerate_native/pom.xml @@ -0,0 +1,84 @@ + + 4.0.0 + + net.codecrete.usb.examples + enumerate_native + jar + 1.0-SNAPSHOT + enumerate_native + https://www.github.com/manuelbl/java-does-usb + + + 25 + 25 + UTF-8 + 0.11.0 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.14.0 + + true + + + + org.apache.maven.plugins + maven-jar-plugin + 3.4.2 + + + + net.codecrete.usb.examples.App + true + + + + + + + + + + net.codecrete.usb + java-does-usb + 1.3.0-SNAPSHOT + + + junit + junit + 3.8.1 + test + + + + + + native + + + + org.graalvm.buildtools + native-maven-plugin + ${native.maven.plugin.version} + true + + + build-native + + compile-no-fork + + package + + + + + + + + + diff --git a/examples/enumerate_native/src/main/java/net/codecrete/usb/examples/App.java b/examples/enumerate_native/src/main/java/net/codecrete/usb/examples/App.java new file mode 100644 index 00000000..943f20e3 --- /dev/null +++ b/examples/enumerate_native/src/main/java/net/codecrete/usb/examples/App.java @@ -0,0 +1,19 @@ +// +// Java Does USB +// Copyright (c) 2025 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.examples; + +import net.codecrete.usb.Usb; + +public class App +{ + public static void main(String[] args) { + for (var device : Usb.getDevices()) { + System.out.println(device); + } + } +} diff --git a/examples/enumerate_native/src/main/resources/META-INF/native-image/net.codecrete.usb.examples/enumerate_native/native-image.properties b/examples/enumerate_native/src/main/resources/META-INF/native-image/net.codecrete.usb.examples/enumerate_native/native-image.properties new file mode 100644 index 00000000..4e4f3471 --- /dev/null +++ b/examples/enumerate_native/src/main/resources/META-INF/native-image/net.codecrete.usb.examples/enumerate_native/native-image.properties @@ -0,0 +1 @@ +Args = --enable-native-access=ALL-UNNAMED -H:ConfigurationFileDirectories=config/macos From c03c470a221459bc5ad0abe050ea722da4d0fc33 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Thu, 11 Sep 2025 16:16:27 +0200 Subject: [PATCH 388/433] Linux reachability --- test-graalvm/README.md | 26 ++++ .../config/linux/reachability-metadata.json | 111 ++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 test-graalvm/README.md create mode 100644 test-graalvm/config/linux/reachability-metadata.json diff --git a/test-graalvm/README.md b/test-graalvm/README.md new file mode 100644 index 00000000..51de086f --- /dev/null +++ b/test-graalvm/README.md @@ -0,0 +1,26 @@ +# Application for Testing the GraalVM Configuration + +## Collection Reachability Data + +Reachability data can be collected by running the unit test +of the _java-does-usb_ project: + +```shell +cd java-does-usb +export JAVA_TOOL_OPTIONS="-agentlib:native-image-agent=config-output-dir=metadata-{pid}-{datetime}/" +mvn test +``` + + +## Building + +```shell +mvn -Pnative package +``` + + +## Running + +```shell +./target/test_graalvm +``` diff --git a/test-graalvm/config/linux/reachability-metadata.json b/test-graalvm/config/linux/reachability-metadata.json new file mode 100644 index 00000000..e1746c04 --- /dev/null +++ b/test-graalvm/config/linux/reachability-metadata.json @@ -0,0 +1,111 @@ +{ + "foreign": { + "downcalls": [ + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "jlong", + "void*" + ], + "options": { + "captureCallState": true, + "firstVariadicArg": 2 + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "void*", + "jint", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "jint" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "jint", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + } + ] + } +} \ No newline at end of file From d76dc0b8753be6b45e64233c5adbdb0832a3ea2c Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Thu, 11 Sep 2025 16:25:45 +0200 Subject: [PATCH 389/433] Native example app for Linux --- examples/enumerate_native/README.md | 23 +++- .../config/linux/reachability-metadata.json | 111 ++++++++++++++++++ 2 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 examples/enumerate_native/config/linux/reachability-metadata.json diff --git a/examples/enumerate_native/README.md b/examples/enumerate_native/README.md index 23a351bd..77cdce2f 100644 --- a/examples/enumerate_native/README.md +++ b/examples/enumerate_native/README.md @@ -10,6 +10,27 @@ this _Java Does USB_ library. - [GraalVM](https://www.graalvm.org/) 25 or higher - [Maven](https://maven.apache.org/) 3.9 or higher +- Latest snapshot of _Java Does USB_ + + +#### Java Does USB Snapshot + +Check out the latest version of _Java Does USB_ and build it: + +```shell +git clone https://github.com/manuelbl/JavaDoesUSB.git +cd JavaDoesUSB/java-does-usb +mvn clean install -DskipTests +``` + +The installation requires a valid GPG key pair. If you don't have one, +create it with and do not set a password: + +```shell +gpg --gen-key +``` + +The full name and email address can be anyone's. ### Preparation @@ -26,7 +47,7 @@ Args = --enable-native-access=ALL-UNNAMED -H:ConfigurationFileDirectories=config ``` Note the last word of the line. In this case, it is `macos`. Change this to -`linux` or `windows` if needed. (Windows and Linux are yet to come.) +`linux` or `windows` if needed. (Windows is yet to come.) In your own Maven project, you might also need to move the file or rather rename directory. It must be named according to the pattern diff --git a/examples/enumerate_native/config/linux/reachability-metadata.json b/examples/enumerate_native/config/linux/reachability-metadata.json new file mode 100644 index 00000000..e1746c04 --- /dev/null +++ b/examples/enumerate_native/config/linux/reachability-metadata.json @@ -0,0 +1,111 @@ +{ + "foreign": { + "downcalls": [ + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "jlong", + "void*" + ], + "options": { + "captureCallState": true, + "firstVariadicArg": 2 + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "void*", + "jint", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "jint" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "jint", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + } + ] + } +} \ No newline at end of file From 19517c96f6e4cabf8b9a78f2f90e1aea9fd6c3ef Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 12 Sep 2025 08:41:28 +0200 Subject: [PATCH 390/433] Reachability metadata for Windows --- test-graalvm/README.md | 2 +- .../config/windows/reachability-metadata.json | 348 ++++++++++++++++++ 2 files changed, 349 insertions(+), 1 deletion(-) create mode 100644 test-graalvm/config/windows/reachability-metadata.json diff --git a/test-graalvm/README.md b/test-graalvm/README.md index 51de086f..ffe37b77 100644 --- a/test-graalvm/README.md +++ b/test-graalvm/README.md @@ -1,6 +1,6 @@ # Application for Testing the GraalVM Configuration -## Collection Reachability Data +## Collect Reachability Data Reachability data can be collected by running the unit test of the _java-does-usb_ project: diff --git a/test-graalvm/config/windows/reachability-metadata.json b/test-graalvm/config/windows/reachability-metadata.json new file mode 100644 index 00000000..fe1ba6cc --- /dev/null +++ b/test-graalvm/config/windows/reachability-metadata.json @@ -0,0 +1,348 @@ +{ + "foreign": { + "upcalls": [ + { + "returnType": "jlong", + "parameterTypes": [ + "void*", + "jint", + "jlong", + "jlong" + ] + } + ], + "downcalls": [ + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong", + "void*", + "void*", + "void*", + "void*", + "jint", + "void*", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "jint", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jlong", + "parameterTypes": [ + "void*", + "jint", + "jlong", + "jlong" + ] + }, + { + "returnType": "jlong", + "parameterTypes": [ + "void*", + "void*", + "void*", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*", + "jlong", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong", + "void*", + "void*", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "struct(jbyte,jbyte,jshort,jshort,jshort)", + "void*", + "jint", + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "jint", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jint", + "void*", + "jint", + "void*", + "jint", + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "jint", + "void*", + "void*", + "jint", + "jint", + "jint", + "jint", + "jint", + "void*", + "void*", + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "jint", + "jint", + "void*", + "jint", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "void*", + "void*", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jshort", + "parameterTypes": [ + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong", + "void*", + "void*", + "jint", + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "void*", + "jint", + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "void*", + "jint", + "jint", + "void*", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jlong", + "parameterTypes": [ + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + } + ] + }, + "reflection": [ + { + "type": "windows.win32.ui.windowsandmessaging.WNDPROC$Function", + "methods": [ + { + "name": "invoke", + "parameterTypes": [ + "java.lang.foreign.MemorySegment", + "int", + "long", + "long" + ] + } + ] + } + ] +} From 1a5f5cd78e87f3e94b31d785a9c379443db1bc09 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 12 Sep 2025 08:46:46 +0200 Subject: [PATCH 391/433] Native enumeration example (Windows) --- examples/enumerate_native/README.md | 2 +- .../config/windows/reachability-metadata.json | 348 ++++++++++++++++++ 2 files changed, 349 insertions(+), 1 deletion(-) create mode 100644 examples/enumerate_native/config/windows/reachability-metadata.json diff --git a/examples/enumerate_native/README.md b/examples/enumerate_native/README.md index 77cdce2f..886ea2ef 100644 --- a/examples/enumerate_native/README.md +++ b/examples/enumerate_native/README.md @@ -47,7 +47,7 @@ Args = --enable-native-access=ALL-UNNAMED -H:ConfigurationFileDirectories=config ``` Note the last word of the line. In this case, it is `macos`. Change this to -`linux` or `windows` if needed. (Windows is yet to come.) +`linux` or `windows` if needed. In your own Maven project, you might also need to move the file or rather rename directory. It must be named according to the pattern diff --git a/examples/enumerate_native/config/windows/reachability-metadata.json b/examples/enumerate_native/config/windows/reachability-metadata.json new file mode 100644 index 00000000..fe1ba6cc --- /dev/null +++ b/examples/enumerate_native/config/windows/reachability-metadata.json @@ -0,0 +1,348 @@ +{ + "foreign": { + "upcalls": [ + { + "returnType": "jlong", + "parameterTypes": [ + "void*", + "jint", + "jlong", + "jlong" + ] + } + ], + "downcalls": [ + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong", + "void*", + "void*", + "void*", + "void*", + "jint", + "void*", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "jint", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jlong", + "parameterTypes": [ + "void*", + "jint", + "jlong", + "jlong" + ] + }, + { + "returnType": "jlong", + "parameterTypes": [ + "void*", + "void*", + "void*", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*", + "jlong", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong", + "void*", + "void*", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "struct(jbyte,jbyte,jshort,jshort,jshort)", + "void*", + "jint", + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "jint", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jint", + "void*", + "jint", + "void*", + "jint", + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "jint", + "void*", + "void*", + "jint", + "jint", + "jint", + "jint", + "jint", + "void*", + "void*", + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "jint", + "jint", + "void*", + "jint", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "void*", + "void*", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jshort", + "parameterTypes": [ + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong", + "void*", + "void*", + "jint", + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "void*", + "jint", + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "void*", + "jint", + "jint", + "void*", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jlong", + "parameterTypes": [ + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + } + ] + }, + "reflection": [ + { + "type": "windows.win32.ui.windowsandmessaging.WNDPROC$Function", + "methods": [ + { + "name": "invoke", + "parameterTypes": [ + "java.lang.foreign.MemorySegment", + "int", + "long", + "long" + ] + } + ] + } + ] +} From 1bce63eb7e521b2322fe6b86e610ee7dd3953f19 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 13 Sep 2025 13:42:01 +0200 Subject: [PATCH 392/433] Fix testing parameter --- java-does-usb/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 62bdbbe1..164540cc 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -149,7 +149,7 @@ maven-surefire-plugin 3.2.5 - --enable-native-access=net.codecrete.usb + --enable-native-access=ALL-UNNAMED From 5e4a4f5e44391bae910b25514332bfe5296b97d3 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 13 Sep 2025 15:33:58 +0200 Subject: [PATCH 393/433] Increase version to 1.2.1 --- README.md | 4 ++-- examples/bulk_transfer/README.md | 2 +- examples/bulk_transfer/pom.xml | 4 ++-- examples/enumerate/README.md | 2 +- examples/enumerate/pom.xml | 4 ++-- examples/enumerate_kotlin/README.md | 2 +- examples/enumerate_kotlin/pom.xml | 4 ++-- examples/enumerate_native/README.md | 21 --------------------- examples/enumerate_native/pom.xml | 2 +- examples/epaper_display/README.md | 4 ++-- examples/epaper_display/pom.xml | 4 ++-- examples/monitor/README.md | 2 +- examples/monitor/pom.xml | 4 ++-- examples/monitor_kotlin/README.md | 2 +- examples/monitor_kotlin/pom.xml | 4 ++-- examples/stm_dfu/README.md | 2 +- examples/stm_dfu/pom.xml | 4 ++-- java-does-usb/pom.xml | 4 ++-- test-graalvm/pom.xml | 2 +- 19 files changed, 28 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index a99a557d..f323ea9f 100644 --- a/README.md +++ b/README.md @@ -31,14 +31,14 @@ If you are using Maven, add the below dependency to your pom.xml: net.codecrete.usb java-does-usb - 1.2.0 + 1.2.1 ``` If you are using Gradle, add the below dependency to your build.gradle file: ```groovy -compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '1.2.0' +compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '1.2.1' ``` ```java diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index bd8e5fdd..4d8c964d 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] --------------< net.codecrete.usb.examples:bulk-transfer >-------------- -[INFO] Building bulk-transfer 1.2.0 +[INFO] Building bulk-transfer 1.2.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ bulk-transfer --- diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index 46af793d..c6fc930b 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples bulk-transfer - 1.2.0 + 1.2.1 bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.2.0 + 1.2.1 diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index 7c16a27e..0fcfbc34 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] ----------------< net.codecrete.usb.examples:enumerate >---------------- -[INFO] Building enumerate 1.2.0 +[INFO] Building enumerate 1.2.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ enumerate --- diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index aa1cab83..5ba2e679 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples enumerate - 1.2.0 + 1.2.1 enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.2.0 + 1.2.1 org.tinylog diff --git a/examples/enumerate_kotlin/README.md b/examples/enumerate_kotlin/README.md index b52bdaeb..ca2fdcda 100644 --- a/examples/enumerate_kotlin/README.md +++ b/examples/enumerate_kotlin/README.md @@ -40,7 +40,7 @@ $ mvn clean package ### Run the jar ```shell -$ java --enable-native-access=ALL-UNNAMED -jar target/enumerate-1.2.0-jar-with-dependencies.jar +$ java --enable-native-access=ALL-UNNAMED -jar target/enumerate-1.2.1-jar-with-dependencies.jar Device: VID: 0xcafe PID: 0xceaf diff --git a/examples/enumerate_kotlin/pom.xml b/examples/enumerate_kotlin/pom.xml index 70a99a87..9fcc28c3 100644 --- a/examples/enumerate_kotlin/pom.xml +++ b/examples/enumerate_kotlin/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples enumerate - 1.2.0 + 1.2.1 jar enumerate @@ -64,7 +64,7 @@ net.codecrete.usb java-does-usb - 1.2.0 + 1.2.1 org.tinylog diff --git a/examples/enumerate_native/README.md b/examples/enumerate_native/README.md index 886ea2ef..bbccef5b 100644 --- a/examples/enumerate_native/README.md +++ b/examples/enumerate_native/README.md @@ -10,27 +10,6 @@ this _Java Does USB_ library. - [GraalVM](https://www.graalvm.org/) 25 or higher - [Maven](https://maven.apache.org/) 3.9 or higher -- Latest snapshot of _Java Does USB_ - - -#### Java Does USB Snapshot - -Check out the latest version of _Java Does USB_ and build it: - -```shell -git clone https://github.com/manuelbl/JavaDoesUSB.git -cd JavaDoesUSB/java-does-usb -mvn clean install -DskipTests -``` - -The installation requires a valid GPG key pair. If you don't have one, -create it with and do not set a password: - -```shell -gpg --gen-key -``` - -The full name and email address can be anyone's. ### Preparation diff --git a/examples/enumerate_native/pom.xml b/examples/enumerate_native/pom.xml index 09bdbe59..d0bac23e 100644 --- a/examples/enumerate_native/pom.xml +++ b/examples/enumerate_native/pom.xml @@ -46,7 +46,7 @@ net.codecrete.usb java-does-usb - 1.3.0-SNAPSHOT + 1.2.1 junit diff --git a/examples/epaper_display/README.md b/examples/epaper_display/README.md index 2b75482f..9b6b77a1 100644 --- a/examples/epaper_display/README.md +++ b/examples/epaper_display/README.md @@ -45,7 +45,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -------------< net.codecrete.usb.examples:epaper-display >-------------- -[INFO] Building epaper-display 1.2.0 +[INFO] Building epaper-display 1.2.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ epaper-display --- @@ -79,6 +79,6 @@ $ sudo -i Password: $ cd /Users/me/Documents/JavaDoesUSB/examples/epaper_display $ export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-20.jdk/Contents/Home -$ $JAVA_HOME/bin/java --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/1.2.0/java-does-usb-1.2.0.jar net.codecrete.usb.examples.EPaperDisplay +$ $JAVA_HOME/bin/java --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/1.2.1/java-does-usb-1.2.1.jar net.codecrete.usb.examples.EPaperDisplay Display size: 1200 x 825 ``` diff --git a/examples/epaper_display/pom.xml b/examples/epaper_display/pom.xml index 7ba68557..d68e4e3b 100644 --- a/examples/epaper_display/pom.xml +++ b/examples/epaper_display/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples epaper-display - 1.2.0 + 1.2.1 epaper-display https://github.com/manuelbl/JavaDoesUSB/examples/epaper_display @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.2.0 + 1.2.1 diff --git a/examples/monitor/README.md b/examples/monitor/README.md index 271fec69..5473a9fb 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -----------------< net.codecrete.usb.examples:monitor >----------------- -[INFO] Building monitor 1.2.0 +[INFO] Building monitor 1.2.1 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ monitor --- diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index a927df0e..cebd39db 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples monitor - 1.2.0 + 1.2.1 monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor @@ -21,7 +21,7 @@ net.codecrete.usb java-does-usb - 1.2.0 + 1.2.1 org.tinylog diff --git a/examples/monitor_kotlin/README.md b/examples/monitor_kotlin/README.md index 69056f03..ea13928b 100644 --- a/examples/monitor_kotlin/README.md +++ b/examples/monitor_kotlin/README.md @@ -40,7 +40,7 @@ $ mvn clean package ### Run the jar ```shell -$ java --enable-native-access=ALL-UNNAMED -jar target/monitor-1.2.0-jar-with-dependencies.jar +$ java --enable-native-access=ALL-UNNAMED -jar target/monitor-1.2.1-jar-with-dependencies.jar Present: VID: 0x1d6b, PID: 0x0002, manufacturer: Linux 6.5.0-18-generic xhci-hcd, product: xHCI Host Controller, serial: 0000:00:14.0, ID: /dev/bus/usb/001/001 Present: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 35A737883336, ID: /dev/bus/usb/001/009 Monitoring... Press ENTER to quit. diff --git a/examples/monitor_kotlin/pom.xml b/examples/monitor_kotlin/pom.xml index 766851b4..be60a362 100644 --- a/examples/monitor_kotlin/pom.xml +++ b/examples/monitor_kotlin/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples monitor - 1.2.0 + 1.2.1 jar monitor @@ -64,7 +64,7 @@ net.codecrete.usb java-does-usb - 1.2.0 + 1.2.1 org.tinylog diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index 5072eb70..04c1e279 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -58,7 +58,7 @@ Run the command below (adapting the file path depending on your specific board): ```shell $ mvn package -$ java --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-1.2.0.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin +$ java --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-1.2.1.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin DFU device found with serial 35A737883336. Target memory segment: Internal Flash Erasing page at 0x8000000 (size 0x4000) diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index ed607b89..c0cbf01c 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples stm_dfu - 1.2.0 + 1.2.1 stm_dfu https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu @@ -19,7 +19,7 @@ net.codecrete.usb java-does-usb - 1.2.0 + 1.2.1 diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 164540cc..e98865e4 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 1.3.0-SNAPSHOT + 1.2.1 23 @@ -216,7 +216,7 @@ net.codecrete.windows-api windowsapi-maven-plugin - 0.8.0 + 0.8.2 diff --git a/test-graalvm/pom.xml b/test-graalvm/pom.xml index e5e516ce..f67ae206 100644 --- a/test-graalvm/pom.xml +++ b/test-graalvm/pom.xml @@ -46,7 +46,7 @@ net.codecrete.usb java-does-usb - 1.3.0-SNAPSHOT + 1.2.1 junit From 14b8de7f3518f7759c8b2fded9910a1eac5cc631 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Sat, 13 Sep 2025 16:06:20 +0200 Subject: [PATCH 394/433] Sonatype publishing plugin --- java-does-usb/pom.xml | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index e98865e4..dda10aed 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -12,8 +12,11 @@ 23 23 UTF-8 + 0.8.0 + jar + Java Does USB https://github.com/manuelbl/JavaDoesUSB Access USB devices from Java without additional libraries @@ -38,17 +41,6 @@ https://github.com/manuelbl/JavaDoesUSB - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - @@ -197,22 +189,20 @@ + + org.sonatype.central + central-publishing-maven-plugin + ${sonatype-central-publishing.version} + true + + central + true + + - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.13 - true - - ossrh - https://s01.oss.sonatype.org/ - true - - - net.codecrete.windows-api windowsapi-maven-plugin From 16bb994201cec71c04fa20831ccb78566b536864 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 19 Jun 2026 17:26:11 +0200 Subject: [PATCH 395/433] Updated reachability metadata for GraalVM --- examples/enumerate_native/README.md | 2 +- .../config/windows/reachability-metadata.json | 199 ++++++++++-------- java-does-usb/pom.xml | 2 +- 3 files changed, 116 insertions(+), 87 deletions(-) diff --git a/examples/enumerate_native/README.md b/examples/enumerate_native/README.md index bbccef5b..f35b1095 100644 --- a/examples/enumerate_native/README.md +++ b/examples/enumerate_native/README.md @@ -36,7 +36,7 @@ directory. It must be named according to the pattern ### Building ```shell -mvn -Dnative package +mvn -Pnative package ``` diff --git a/examples/enumerate_native/config/windows/reachability-metadata.json b/examples/enumerate_native/config/windows/reachability-metadata.json index fe1ba6cc..f3abe566 100644 --- a/examples/enumerate_native/config/windows/reachability-metadata.json +++ b/examples/enumerate_native/config/windows/reachability-metadata.json @@ -1,23 +1,25 @@ { "foreign": { - "upcalls": [ + "downcalls": [ { - "returnType": "jlong", + "returnType": "jint", "parameterTypes": [ + "jint", "void*", "jint", - "jlong", - "jlong" - ] - } - ], - "downcalls": [ + "jint", + "void*", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + }, { - "returnType": "void*", + "returnType": "jint", "parameterTypes": [ - "void*", - "void*", - "jint" + "jlong" ], "options": { "captureCallState": true @@ -27,13 +29,8 @@ "returnType": "jint", "parameterTypes": [ "jlong", - "void*", - "void*", - "void*", - "void*", "jint", - "void*", - "jint" + "void*" ], "options": { "captureCallState": true @@ -42,10 +39,7 @@ { "returnType": "jint", "parameterTypes": [ - "void*", - "jbyte", - "jint", - "jint", + "jlong", "void*" ], "options": { @@ -53,33 +47,39 @@ } }, { - "returnType": "jlong", + "returnType": "jint", "parameterTypes": [ + "jlong", "void*", "jint", - "jlong", - "jlong" - ] + "void*" + ], + "options": { + "captureCallState": true + } }, { - "returnType": "jlong", + "returnType": "jint", "parameterTypes": [ + "jlong", "void*", "void*", - "void*", - "jint" + "jint", + "void*" ], "options": { "captureCallState": true } }, { - "returnType": "void*", + "returnType": "jint", "parameterTypes": [ + "jlong", "void*", "void*", - "jlong", - "jint" + "jint", + "void*", + "void*" ], "options": { "captureCallState": true @@ -91,13 +91,22 @@ "jlong", "void*", "void*", + "void*", + "void*", "jint", - "void*" + "void*", + "jint" ], "options": { "captureCallState": true } }, + { + "returnType": "jint", + "parameterTypes": [ + "void*" + ] + }, { "returnType": "jint", "parameterTypes": [ @@ -111,7 +120,9 @@ { "returnType": "jint", "parameterTypes": [ - "jlong", + "void*", + "jbyte", + "jint", "jint", "void*" ], @@ -122,7 +133,9 @@ { "returnType": "jint", "parameterTypes": [ - "jlong" + "void*", + "jbyte", + "void*" ], "options": { "captureCallState": true @@ -132,7 +145,7 @@ "returnType": "jint", "parameterTypes": [ "void*", - "struct(jbyte,jbyte,jshort,jshort,jshort)", + "jbyte", "void*", "jint", "void*", @@ -145,7 +158,13 @@ { "returnType": "jint", "parameterTypes": [ - "jlong", + "void*", + "jint", + "void*", + "jint", + "void*", + "jint", + "void*", "void*" ], "options": { @@ -156,17 +175,13 @@ "returnType": "jint", "parameterTypes": [ "void*", - "void*", - "jint", - "jint" - ], - "options": { - "captureCallState": true - } + "void*" + ] }, { - "returnType": "void*", + "returnType": "jint", "parameterTypes": [ + "void*", "void*" ], "options": { @@ -177,7 +192,9 @@ "returnType": "jint", "parameterTypes": [ "void*", - "void*" + "void*", + "jint", + "jint" ], "options": { "captureCallState": true @@ -187,13 +204,10 @@ "returnType": "jint", "parameterTypes": [ "void*", - "jint", "void*", - "jint", "void*", - "jint", "void*", - "void*" + "jint" ], "options": { "captureCallState": true @@ -202,38 +216,27 @@ { "returnType": "jint", "parameterTypes": [ - "void*" - ] - }, - { - "returnType": "void*", - "parameterTypes": [ - "jint", "void*", "void*", - "jint", - "jint", - "jint", - "jint", - "jint", "void*", "void*", "void*", "void*" - ], - "options": { - "captureCallState": true - } + ] }, { - "returnType": "void*", + "returnType": "jlong", "parameterTypes": [ "void*", "jint", - "jint", + "jlong", + "jlong" + ] + }, + { + "returnType": "jlong", + "parameterTypes": [ "void*", - "jint", - "jint", "void*" ], "options": { @@ -241,12 +244,11 @@ } }, { - "returnType": "jint", + "returnType": "jlong", "parameterTypes": [ "void*", "void*", "void*", - "void*", "jint" ], "options": { @@ -263,12 +265,18 @@ } }, { - "returnType": "jint", + "returnType": "void*", "parameterTypes": [ - "jlong", + "jint", "void*", "void*", "jint", + "jint", + "jint", + "jint", + "jint", + "void*", + "void*", "void*", "void*" ], @@ -277,13 +285,22 @@ } }, { - "returnType": "jint", + "returnType": "void*", "parameterTypes": [ - "void*", - "jbyte", + "jlong", "void*", "jint", - "void*", + "jint", + "jint", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [ "void*" ], "options": { @@ -291,14 +308,14 @@ } }, { - "returnType": "jint", + "returnType": "void*", "parameterTypes": [ - "jint", "void*", "jint", "jint", "void*", "jint", + "jint", "void*" ], "options": { @@ -306,27 +323,39 @@ } }, { - "returnType": "jlong", + "returnType": "void*", "parameterTypes": [ "void*", - "void*" + "void*", + "jint" ], "options": { "captureCallState": true } }, { - "returnType": "jint", + "returnType": "void*", "parameterTypes": [ "void*", "void*", - "jint", - "void*" + "jlong", + "jint" ], "options": { "captureCallState": true } } + ], + "upcalls": [ + { + "returnType": "jlong", + "parameterTypes": [ + "void*", + "jint", + "jlong", + "jlong" + ] + } ] }, "reflection": [ diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index dda10aed..4a5296f5 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -206,7 +206,7 @@ net.codecrete.windows-api windowsapi-maven-plugin - 0.8.2 + 0.8.5 From 5b58eac3c20a40143e1a7dfd29be8178dce75c06 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Sat, 20 Jun 2026 09:05:03 +0200 Subject: [PATCH 396/433] Upgrade GitHub actions --- .github/workflows/continuous-integration.yaml | 4 ++-- .github/workflows/test-devices.yaml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index 529a6190..d4c81395 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -24,9 +24,9 @@ jobs: os: [ubuntu-latest, macOS-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - name: Setup Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: '23' diff --git a/.github/workflows/test-devices.yaml b/.github/workflows/test-devices.yaml index bc6d1c5a..0ad9cc6e 100644 --- a/.github/workflows/test-devices.yaml +++ b/.github/workflows/test-devices.yaml @@ -15,14 +15,14 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/cache@v4 + - uses: actions/checkout@v7 + - uses: actions/cache@v5 with: path: | ~/.cache/pip ~/.platformio/.cache key: ${{ runner.os }}-pio - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: '3.9' - name: Install PlatformIO Core From ccaa37582b38e46e3a9fe0edd1a0f2491d7d6559 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Sat, 20 Jun 2026 09:14:18 +0200 Subject: [PATCH 397/433] Upgrade to JDK 25 --- .github/workflows/continuous-integration.yaml | 2 +- README.md | 2 +- java-does-usb/pom.xml | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index d4c81395..17dc3742 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -29,7 +29,7 @@ jobs: uses: actions/setup-java@v5 with: distribution: 'zulu' - java-version: '23' + java-version: '25' - name: Configure unit test GPG key run: | echo -n "$UNIT_TEST_SIGNING_KEY" | base64 --decode | gpg --import diff --git a/README.md b/README.md index f323ea9f..03c03f3b 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ USB devices can implement special control requests to instruct Windows to automa The test devices implement the required control requests. So the driver is installed automatically. -The implementation runs on both Windows for Intel/AMD and ARM processors. Few OpenJDK distributions support Windows on ARM, and they do not support all recent versions of Java. [Eclipse Temurin](https://adoptium.net/temurin/releases/?os=windows&arch=aarch64&version=23) has released a version for Java 23. +The implementation runs on both Windows for Intel/AMD and ARM processors. diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 4a5296f5..a53780ff 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -9,8 +9,8 @@ 1.2.1 - 23 - 23 + 25 + 25 UTF-8 0.8.0 @@ -131,9 +131,9 @@ maven-compiler-plugin 3.12.1 - 23 - 23 - 23 + 25 + 25 + 25 @@ -157,7 +157,7 @@ - 23 + 25 ${java.home}/bin/javadoc net.codecrete.usb.linux.gen.*:net.codecrete.usb.macos.gen.*:windows.*:system From 8a330a5c536c75dac82c6b650cbeec923f491261 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Sat, 20 Jun 2026 10:05:02 +0200 Subject: [PATCH 398/433] Convert Kotlin example to Gradle --- examples/enumerate_kotlin/.gitignore | 21 +- .../.mvn/wrapper/maven-wrapper.jar | Bin 62547 -> 0 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 - examples/enumerate_kotlin/README.md | 20 +- examples/enumerate_kotlin/build.gradle.kts | 37 +++ examples/enumerate_kotlin/gradle.properties | 2 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 48462 bytes .../gradle/wrapper/gradle-wrapper.properties | 9 + examples/enumerate_kotlin/gradlew | 248 ++++++++++++++ examples/enumerate_kotlin/gradlew.bat | 82 +++++ examples/enumerate_kotlin/mvnw | 308 ------------------ examples/enumerate_kotlin/mvnw.cmd | 205 ------------ examples/enumerate_kotlin/pom.xml | 91 ------ examples/enumerate_kotlin/settings.gradle.kts | 4 + .../net/codecrete/usb/examples/Enumerate.kt | 2 +- 15 files changed, 404 insertions(+), 643 deletions(-) delete mode 100644 examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.jar delete mode 100644 examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.properties create mode 100644 examples/enumerate_kotlin/build.gradle.kts create mode 100644 examples/enumerate_kotlin/gradle.properties create mode 100644 examples/enumerate_kotlin/gradle/wrapper/gradle-wrapper.jar create mode 100644 examples/enumerate_kotlin/gradle/wrapper/gradle-wrapper.properties create mode 100755 examples/enumerate_kotlin/gradlew create mode 100644 examples/enumerate_kotlin/gradlew.bat delete mode 100755 examples/enumerate_kotlin/mvnw delete mode 100644 examples/enumerate_kotlin/mvnw.cmd delete mode 100644 examples/enumerate_kotlin/pom.xml create mode 100644 examples/enumerate_kotlin/settings.gradle.kts diff --git a/examples/enumerate_kotlin/.gitignore b/examples/enumerate_kotlin/.gitignore index 5ff6309b..b1dff0dd 100644 --- a/examples/enumerate_kotlin/.gitignore +++ b/examples/enumerate_kotlin/.gitignore @@ -1,7 +1,8 @@ -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/**/target/ -!**/src/test/**/target/ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ ### IntelliJ IDEA ### .idea/modules.xml @@ -11,6 +12,12 @@ target/ *.iws *.iml *.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Kotlin ### +.kotlin ### Eclipse ### .apt_generated @@ -20,6 +27,9 @@ target/ .settings .springBeans .sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ ### NetBeans ### /nbproject/private/ @@ -27,9 +37,6 @@ target/ /dist/ /nbdist/ /.nb-gradle/ -build/ -!**/src/main/**/build/ -!**/src/test/**/build/ ### VS Code ### .vscode/ diff --git a/examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.jar b/examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index cb28b0e37c7d206feb564310fdeec0927af4123a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62547 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 A?*IS* diff --git a/examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.properties b/examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index f3283b08..00000000 --- a/examples/enumerate_kotlin/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,18 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/examples/enumerate_kotlin/README.md b/examples/enumerate_kotlin/README.md index ca2fdcda..63418d03 100644 --- a/examples/enumerate_kotlin/README.md +++ b/examples/enumerate_kotlin/README.md @@ -4,15 +4,15 @@ This sample enumerates the connected USB devices and provides information about ## Prerequisites -- Java 22 -- Apache Maven +- Java 25 +- Gradle - 64-bit operating system (Windows, macOS, Linux) ## How to run -### Install Java 22 or higher +### Install Java 25 or higher -Check that Java 22 or higher is installed: +Check that Java 25 or higher is installed: ```shell $ java -version @@ -25,22 +25,16 @@ If not, download and install it, e.g. from [Azul](https://www.azul.com/downloads Check that *Maven* is installed: ```shell -$ mvn -version +$ gradle -version ``` If it is not present, install it, typically using package manager like *Homebrew* on macOS, *Chocolately* on Windows and *apt* on Linux. -### Build a self-contained jar file +### Build and run the program ```shell $ cd JavaDoesUSB/examples/enumerate_kotlin -$ mvn clean package -``` - -### Run the jar - -```shell -$ java --enable-native-access=ALL-UNNAMED -jar target/enumerate-1.2.1-jar-with-dependencies.jar +$ gradle run Device: VID: 0xcafe PID: 0xceaf diff --git a/examples/enumerate_kotlin/build.gradle.kts b/examples/enumerate_kotlin/build.gradle.kts new file mode 100644 index 00000000..03155481 --- /dev/null +++ b/examples/enumerate_kotlin/build.gradle.kts @@ -0,0 +1,37 @@ +plugins { + kotlin("jvm") version "2.3.21" + application +} + +group = "net.codecrete.usb.examples" +version = "1.2.1" + +val javaDoesUsbVersion = "1.2.1" +val tinyLogVersion = "2.7.0" + +repositories { + mavenLocal() + mavenCentral() +} + +dependencies { + implementation("net.codecrete.usb:java-does-usb:$javaDoesUsbVersion") + implementation("org.tinylog:tinylog-api:$tinyLogVersion") + implementation("org.tinylog:tinylog-impl:$tinyLogVersion") + implementation("org.tinylog:jsl-tinylog:$tinyLogVersion") + + testImplementation(kotlin("test")) +} + +kotlin { + jvmToolchain(25) +} + +application { + mainClass = "net.codecrete.usb.examples.EnumerateKt" + applicationDefaultJvmArgs = listOf("--enable-native-access=ALL-UNNAMED") +} + +tasks.test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/examples/enumerate_kotlin/gradle.properties b/examples/enumerate_kotlin/gradle.properties new file mode 100644 index 00000000..2610d58f --- /dev/null +++ b/examples/enumerate_kotlin/gradle.properties @@ -0,0 +1,2 @@ +kotlin.code.style=official +org.gradle.configuration-cache=true diff --git a/examples/enumerate_kotlin/gradle/wrapper/gradle-wrapper.jar b/examples/enumerate_kotlin/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..b1b8ef56b44f16b14dc800fa8103a6d89abb526f GIT binary patch literal 48462 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 R2np~f1o-$>Q}y+){|A@R9n$~+ literal 0 HcmV?d00001 diff --git a/examples/enumerate_kotlin/gradle/wrapper/gradle-wrapper.properties b/examples/enumerate_kotlin/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..df6a6ad7 --- /dev/null +++ b/examples/enumerate_kotlin/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,9 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip +networkTimeout=10000 +retries=0 +retryBackOffMs=500 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/examples/enumerate_kotlin/gradlew b/examples/enumerate_kotlin/gradlew new file mode 100755 index 00000000..b9bb139f --- /dev/null +++ b/examples/enumerate_kotlin/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/examples/enumerate_kotlin/gradlew.bat b/examples/enumerate_kotlin/gradlew.bat new file mode 100644 index 00000000..24c62d56 --- /dev/null +++ b/examples/enumerate_kotlin/gradlew.bat @@ -0,0 +1,82 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel + +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/examples/enumerate_kotlin/mvnw b/examples/enumerate_kotlin/mvnw deleted file mode 100755 index 8d937f4c..00000000 --- a/examples/enumerate_kotlin/mvnw +++ /dev/null @@ -1,308 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.2.0 -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "$(uname)" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME - else - JAVA_HOME="/Library/Java/Home"; export JAVA_HOME - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=$(java-config --jre-home) - fi -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --unix "$JAVA_HOME") - [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --unix "$CLASSPATH") -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && - JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="$(which javac)" - if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=$(which readlink) - if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then - if $darwin ; then - javaHome="$(dirname "\"$javaExecutable\"")" - javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" - else - javaExecutable="$(readlink -f "\"$javaExecutable\"")" - fi - javaHome="$(dirname "\"$javaExecutable\"")" - javaHome=$(expr "$javaHome" : '\(.*\)/bin') - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=$(cd "$wdir/.." || exit 1; pwd) - fi - # end of workaround - done - printf '%s' "$(cd "$basedir" || exit 1; pwd)" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - # Remove \r in case we run on Windows within Git Bash - # and check out the repository with auto CRLF management - # enabled. Otherwise, we may read lines that are delimited with - # \r\n and produce $'-Xarg\r' rather than -Xarg due to word - # splitting rules. - tr -s '\r\n' ' ' < "$1" - fi -} - -log() { - if [ "$MVNW_VERBOSE" = true ]; then - printf '%s\n' "$1" - fi -} - -BASE_DIR=$(find_maven_basedir "$(dirname "$0")") -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR -log "$MAVEN_PROJECTBASEDIR" - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" -if [ -r "$wrapperJarPath" ]; then - log "Found $wrapperJarPath" -else - log "Couldn't find $wrapperJarPath, downloading it ..." - - if [ -n "$MVNW_REPOURL" ]; then - wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - else - wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - fi - while IFS="=" read -r key value; do - # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) - safeValue=$(echo "$value" | tr -d '\r') - case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; - esac - done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" - log "Downloading from: $wrapperUrl" - - if $cygwin; then - wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") - fi - - if command -v wget > /dev/null; then - log "Found wget ... using wget" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - else - wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - log "Found curl ... using curl" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" - else - curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" - fi - else - log "Falling back to using Java to download" - javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" - javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaSource=$(cygpath --path --windows "$javaSource") - javaClass=$(cygpath --path --windows "$javaClass") - fi - if [ -e "$javaSource" ]; then - if [ ! -e "$javaClass" ]; then - log " - Compiling MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/javac" "$javaSource") - fi - if [ -e "$javaClass" ]; then - log " - Running MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -# If specified, validate the SHA-256 sum of the Maven wrapper jar file -wrapperSha256Sum="" -while IFS="=" read -r key value; do - case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; - esac -done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" -if [ -n "$wrapperSha256Sum" ]; then - wrapperSha256Result=false - if command -v sha256sum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then - wrapperSha256Result=true - fi - elif command -v shasum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then - wrapperSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." - echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." - exit 1 - fi - if [ $wrapperSha256Result = false ]; then - echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 - echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 - echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 - exit 1 - fi -fi - -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") - [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --windows "$CLASSPATH") - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") -fi - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -# shellcheck disable=SC2086 # safe args -exec "$JAVACMD" \ - $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/examples/enumerate_kotlin/mvnw.cmd b/examples/enumerate_kotlin/mvnw.cmd deleted file mode 100644 index f80fbad3..00000000 --- a/examples/enumerate_kotlin/mvnw.cmd +++ /dev/null @@ -1,205 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.2.0 -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %WRAPPER_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file -SET WRAPPER_SHA_256_SUM="" -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B -) -IF NOT %WRAPPER_SHA_256_SUM%=="" ( - powershell -Command "&{"^ - "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ - "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ - " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ - " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ - " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ - " exit 1;"^ - "}"^ - "}" - if ERRORLEVEL 1 goto error -) - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% diff --git a/examples/enumerate_kotlin/pom.xml b/examples/enumerate_kotlin/pom.xml deleted file mode 100644 index 9fcc28c3..00000000 --- a/examples/enumerate_kotlin/pom.xml +++ /dev/null @@ -1,91 +0,0 @@ - - 4.0.0 - - net.codecrete.usb.examples - enumerate - 1.2.1 - jar - - enumerate - https://github.com/manuelbl/JavaDoesUSB/examples/enumerate_kotlin - - - 1.9.22 - true - UTF-8 - net.codecrete.usb.examples.EnumerateKt - - - - ${project.basedir}/src/main/kotlin - ${project.basedir}/src/test/kotlin - - - - org.jetbrains.kotlin - kotlin-maven-plugin - ${kotlin.version} - true - - - org.apache.maven.plugins - maven-assembly-plugin - 3.6.0 - - - make-assembly - package - - single - - - - - ${main.class} - - - - jar-with-dependencies - - - - - - - - - - - org.jetbrains.kotlin - kotlin-stdlib - ${kotlin.version} - - - net.codecrete.usb - java-does-usb - 1.2.1 - - - org.tinylog - tinylog-api - 2.7.0 - - - org.tinylog - tinylog-impl - 2.7.0 - - - org.tinylog - jsl-tinylog - 2.7.0 - - - junit - junit - 4.13.2 - test - - - diff --git a/examples/enumerate_kotlin/settings.gradle.kts b/examples/enumerate_kotlin/settings.gradle.kts new file mode 100644 index 00000000..d48b99a0 --- /dev/null +++ b/examples/enumerate_kotlin/settings.gradle.kts @@ -0,0 +1,4 @@ +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" +} +rootProject.name = "enumerate" \ No newline at end of file diff --git a/examples/enumerate_kotlin/src/main/kotlin/net/codecrete/usb/examples/Enumerate.kt b/examples/enumerate_kotlin/src/main/kotlin/net/codecrete/usb/examples/Enumerate.kt index cf741727..1d15c964 100644 --- a/examples/enumerate_kotlin/src/main/kotlin/net/codecrete/usb/examples/Enumerate.kt +++ b/examples/enumerate_kotlin/src/main/kotlin/net/codecrete/usb/examples/Enumerate.kt @@ -92,4 +92,4 @@ class Enumerate { } } -} \ No newline at end of file +} From 224a25eba330e4a093354b60f6bd3fb795920d13 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Sat, 20 Jun 2026 11:23:11 +0200 Subject: [PATCH 399/433] Fix Kotlin build --- .github/workflows/continuous-integration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index 17dc3742..4039eb94 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -46,7 +46,7 @@ jobs: run: ./mvnw $MAVEN_ARGS clean compile working-directory: ./examples/enumerate - name: Example "enumerate" (Kotlin) - run: ./mvnw $MAVEN_ARGS clean package + run: ./gradlew clean build working-directory: ./examples/enumerate_kotlin - name: Example "monitor" run: ./mvnw $MAVEN_ARGS clean compile From a8567468d7d4998a76d1010f3ae87d24f33d9461 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Sat, 20 Jun 2026 12:13:43 +0200 Subject: [PATCH 400/433] Upgrade monitor Kotlin example --- .../.mvn/wrapper/maven-wrapper.jar | Bin 62547 -> 0 bytes .../.mvn/wrapper/maven-wrapper.properties | 21 +- examples/monitor_kotlin/README.md | 6 +- examples/monitor_kotlin/mvnw | 467 +++++++++--------- examples/monitor_kotlin/mvnw.cmd | 344 ++++++------- examples/monitor_kotlin/pom.xml | 2 +- 6 files changed, 398 insertions(+), 442 deletions(-) delete mode 100644 examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.jar diff --git a/examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.jar b/examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index cb28b0e37c7d206feb564310fdeec0927af4123a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62547 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 A?*IS* diff --git a/examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.properties b/examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.properties index f3283b08..c595b009 100644 --- a/examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.properties +++ b/examples/monitor_kotlin/.mvn/wrapper/maven-wrapper.properties @@ -1,18 +1,3 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar +wrapperVersion=3.3.4 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.14/apache-maven-3.9.14-bin.zip diff --git a/examples/monitor_kotlin/README.md b/examples/monitor_kotlin/README.md index ea13928b..eae39270 100644 --- a/examples/monitor_kotlin/README.md +++ b/examples/monitor_kotlin/README.md @@ -4,15 +4,15 @@ This sample enumerates the connected USB devices and provides information about ## Prerequisites -- Java 22 +- Java 25 - Apache Maven - 64-bit operating system (Windows, macOS, Linux) ## How to run -### Install Java 22 or higher +### Install Java 25 or higher -Check that Java 22 or higher is installed: +Check that Java 25 or higher is installed: ```shell $ java -version diff --git a/examples/monitor_kotlin/mvnw b/examples/monitor_kotlin/mvnw index 8d937f4c..bd8896bf 100755 --- a/examples/monitor_kotlin/mvnw +++ b/examples/monitor_kotlin/mvnw @@ -19,290 +19,277 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.2.0 -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir +# Apache Maven Wrapper startup batch script, version 3.3.4 # # Optional ENV vars # ----------------- -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output # ---------------------------------------------------------------------------- -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false +# OS specific support. +native_path() { printf %s\\n "$1"; } case "$(uname)" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME - else - JAVA_HOME="/Library/Java/Home"; export JAVA_HOME - fi - fi - ;; +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; esac -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=$(java-config --jre-home) - fi -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --unix "$JAVA_HOME") - [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --unix "$CLASSPATH") -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && - JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="$(which javac)" - if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=$(which readlink) - if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then - if $darwin ; then - javaHome="$(dirname "\"$javaExecutable\"")" - javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" - else - javaExecutable="$(readlink -f "\"$javaExecutable\"")" - fi - javaHome="$(dirname "\"$javaExecutable\"")" - javaHome=$(expr "$javaHome" : '\(.*\)/bin') - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" else JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi fi else - JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" - fi -fi + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi fi +} - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=$(cd "$wdir/.." || exit 1; pwd) - fi - # end of workaround +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" done - printf '%s' "$(cd "$basedir" || exit 1; pwd)" + printf %x\\n $h } -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - # Remove \r in case we run on Windows within Git Bash - # and check out the repository with auto CRLF management - # enabled. Otherwise, we may read lines that are delimited with - # \r\n and produce $'-Xarg\r' rather than -Xarg due to word - # splitting rules. - tr -s '\r\n' ' ' < "$1" - fi +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 } -log() { - if [ "$MVNW_VERBOSE" = true ]; then - printf '%s\n' "$1" - fi +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +scriptDir="$(dirname "$0")" +scriptName="$(basename "$0")" + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" } -BASE_DIR=$(find_maven_basedir "$(dirname "$0")") -if [ -z "$BASE_DIR" ]; then - exit 1; +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" fi -MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR -log "$MAVEN_PROJECTBASEDIR" +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" -if [ -r "$wrapperJarPath" ]; then - log "Found $wrapperJarPath" +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT else - log "Couldn't find $wrapperJarPath, downloading it ..." + die "cannot create temp dir" +fi - if [ -n "$MVNW_REPOURL" ]; then - wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - else - wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - fi - while IFS="=" read -r key value; do - # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) - safeValue=$(echo "$value" | tr -d '\r') - case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; - esac - done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" - log "Downloading from: $wrapperUrl" - - if $cygwin; then - wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") - fi +mkdir -p -- "${MAVEN_HOME%/*}" - if command -v wget > /dev/null; then - log "Found wget ... using wget" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - else - wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - log "Found curl ... using curl" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" - else - curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" - fi - else - log "Falling back to using Java to download" - javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" - javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaSource=$(cygpath --path --windows "$javaSource") - javaClass=$(cygpath --path --windows "$javaClass") - fi - if [ -e "$javaSource" ]; then - if [ ! -e "$javaClass" ]; then - log " - Compiling MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/javac" "$javaSource") - fi - if [ -e "$javaClass" ]; then - log " - Running MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" - fi - fi - fi +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" fi -########################################################################################## -# End of extension -########################################################################################## -# If specified, validate the SHA-256 sum of the Maven wrapper jar file -wrapperSha256Sum="" -while IFS="=" read -r key value; do - case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; - esac -done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" -if [ -n "$wrapperSha256Sum" ]; then - wrapperSha256Result=false - if command -v sha256sum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then - wrapperSha256Result=true +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then + distributionSha256Result=true fi - elif command -v shasum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then - wrapperSha256Result=true + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true fi else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." - echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 exit 1 fi - if [ $wrapperSha256Result = false ]; then - echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 - echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 - echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 exit 1 fi fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +actualDistributionDir="" -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") - [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --windows "$CLASSPATH") - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +# First try the expected directory name (for regular distributions) +if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then + if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then + actualDistributionDir="$distributionUrlNameMain" + fi fi -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" -export MAVEN_CMD_LINE_ARGS +# If not found, search for any directory with the Maven executable (for snapshots) +if [ -z "$actualDistributionDir" ]; then + # enable globbing to iterate over items + set +f + for dir in "$TMP_DOWNLOAD_DIR"/*; do + if [ -d "$dir" ]; then + if [ -f "$dir/bin/$MVN_CMD" ]; then + actualDistributionDir="$(basename "$dir")" + break + fi + fi + done + set -f +fi + +if [ -z "$actualDistributionDir" ]; then + verbose "Contents of $TMP_DOWNLOAD_DIR:" + verbose "$(ls -la "$TMP_DOWNLOAD_DIR")" + die "Could not find Maven distribution directory in extracted archive" +fi -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain +verbose "Found extracted Maven distribution directory: $actualDistributionDir" +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" -# shellcheck disable=SC2086 # safe args -exec "$JAVACMD" \ - $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" +clean || : +exec_maven "$@" diff --git a/examples/monitor_kotlin/mvnw.cmd b/examples/monitor_kotlin/mvnw.cmd index f80fbad3..5761d948 100644 --- a/examples/monitor_kotlin/mvnw.cmd +++ b/examples/monitor_kotlin/mvnw.cmd @@ -1,3 +1,4 @@ +<# : batch portion @REM ---------------------------------------------------------------------------- @REM Licensed to the Apache Software Foundation (ASF) under one @REM or more contributor license agreements. See the NOTICE file @@ -18,188 +19,171 @@ @REM ---------------------------------------------------------------------------- @REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.2.0 -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir +@REM Apache Maven Wrapper startup batch script, version 3.3.4 @REM @REM Optional ENV vars -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output @REM ---------------------------------------------------------------------------- -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %WRAPPER_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file -SET WRAPPER_SHA_256_SUM="" -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) ) -IF NOT %WRAPPER_SHA_256_SUM%=="" ( - powershell -Command "&{"^ - "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ - "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ - " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ - " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ - " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ - " exit 1;"^ - "}"^ - "}" - if ERRORLEVEL 1 goto error -) - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' + +$MAVEN_M2_PATH = "$HOME/.m2" +if ($env:MAVEN_USER_HOME) { + $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME" +} + +if (-not (Test-Path -Path $MAVEN_M2_PATH)) { + New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null +} + +$MAVEN_WRAPPER_DISTS = $null +if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) { + $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists" +} else { + $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists" +} + +$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain" +$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +$actualDistributionDir = "" + +# First try the expected directory name (for regular distributions) +$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain" +$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD" +if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) { + $actualDistributionDir = $distributionUrlNameMain +} + +# If not found, search for any directory with the Maven executable (for snapshots) +if (!$actualDistributionDir) { + Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object { + $testPath = Join-Path $_.FullName "bin/$MVN_CMD" + if (Test-Path -Path $testPath -PathType Leaf) { + $actualDistributionDir = $_.Name + } + } +} + +if (!$actualDistributionDir) { + Write-Error "Could not find Maven distribution directory in extracted archive" +} + +Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir" +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/examples/monitor_kotlin/pom.xml b/examples/monitor_kotlin/pom.xml index be60a362..c0c3d6b2 100644 --- a/examples/monitor_kotlin/pom.xml +++ b/examples/monitor_kotlin/pom.xml @@ -11,7 +11,7 @@ https://github.com/manuelbl/JavaDoesUSB/examples/monitor_kotlin - 1.9.22 + 2.3.21 true UTF-8 net.codecrete.usb.examples.MonitorKt From 312ae8a90ea97ad9a8cc52052fa6b723efb8538e Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 26 Jun 2026 16:11:56 +0200 Subject: [PATCH 401/433] Native monitoring example --- examples/monitor_native/README.md | 49 +++ .../config/linux/reachability-metadata.json | 111 ++++++ .../config/macos/reachability-metadata.json | 318 +++++++++++++++ .../config/windows/reachability-metadata.json | 377 ++++++++++++++++++ examples/monitor_native/pom.xml | 84 ++++ .../java/net/codecrete/usb/examples/App.java | 38 ++ .../monitor_native/native-image.properties | 1 + 7 files changed, 978 insertions(+) create mode 100644 examples/monitor_native/README.md create mode 100644 examples/monitor_native/config/linux/reachability-metadata.json create mode 100644 examples/monitor_native/config/macos/reachability-metadata.json create mode 100644 examples/monitor_native/config/windows/reachability-metadata.json create mode 100644 examples/monitor_native/pom.xml create mode 100644 examples/monitor_native/src/main/java/net/codecrete/usb/examples/App.java create mode 100644 examples/monitor_native/src/main/resources/META-INF/native-image/net.codecrete.usb.examples/monitor_native/native-image.properties diff --git a/examples/monitor_native/README.md b/examples/monitor_native/README.md new file mode 100644 index 00000000..3018321d --- /dev/null +++ b/examples/monitor_native/README.md @@ -0,0 +1,49 @@ +# Device Monitoring (Native) + +This example project demonstrates how to build a native application that +monitors USB devices using [GraalVM](https://www.graalvm.org/) and +this _Java Does USB_ library. + +## Build and Run + +### Prerequisites + +- [GraalVM](https://www.graalvm.org/) 25 or higher +- [Maven](https://maven.apache.org/) 3.9 or higher + + +### Preparation + +GraalVM needs help to learn about the Java FFM downcall and upcall descriptors, +and it needs some help to include all required methods. The relevant items +differ from operating system to operating system. When building the native image, +the operating system must be selected by changing the path in the file +`native-image.properties` in the directory +`src/main/resources/META-INF/native-image/net.codecrete.usb.examples/monitor_native`. + +```properties +Args = --enable-native-access=ALL-UNNAMED -H:ConfigurationFileDirectories=config/macos +``` + +Note the last word of the line. In this case, it is `macos`. Change this to +`linux` or `windows` if needed. + +In your own Maven project, you might also need to move the file or rather rename +directory. It must be named according to the pattern +`src/main/resources/META-INF/native-image//`. + +Also check that the environment variable `JAVA_HOME` points to the GraalVM directory. + + +### Building + +```shell +mvn -Pnative package +``` + + +### Running + +```shell +./target/monitor-native +``` diff --git a/examples/monitor_native/config/linux/reachability-metadata.json b/examples/monitor_native/config/linux/reachability-metadata.json new file mode 100644 index 00000000..e1746c04 --- /dev/null +++ b/examples/monitor_native/config/linux/reachability-metadata.json @@ -0,0 +1,111 @@ +{ + "foreign": { + "downcalls": [ + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "jlong", + "void*" + ], + "options": { + "captureCallState": true, + "firstVariadicArg": 2 + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "void*", + "jint", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "jint" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "jint", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + } + ] + } +} \ No newline at end of file diff --git a/examples/monitor_native/config/macos/reachability-metadata.json b/examples/monitor_native/config/macos/reachability-metadata.json new file mode 100644 index 00000000..113fb587 --- /dev/null +++ b/examples/monitor_native/config/macos/reachability-metadata.json @@ -0,0 +1,318 @@ +{ + "foreign": { + "upcalls": [ + { + "returnType": "void", + "parameterTypes": [ + "void*", + "jint", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "jint", + "void*", + "void*" + ] + }, + { + "returnType": "void", + "parameterTypes": [ + "void*", + "jint" + ] + } + ], + "downcalls": [ + { + "returnType": "void", + "parameterTypes": [ + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "void", + "parameterTypes": [ + "void*", + "struct(jlong,jlong)", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*", + "jlong" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jint", + "void*", + "jdouble", + "jdouble", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "void*", + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint" + ] + }, + { + "returnType": "jlong", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "void*", + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "jint", + "void*", + "void*", + "jint" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "jint", + "void*", + "void*" + ] + }, + { + "returnType": "jbyte", + "parameterTypes": [ + "void*", + "jlong", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "struct(jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte)" + ] + }, + { + "returnType": "void", + "parameterTypes": [] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "void*", + "jint", + "jint", + "jint", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "void*", + "void*", + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "jlong", + "parameterTypes": [] + }, + { + "returnType": "void", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "jint" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*", + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "void*", + "jint", + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "struct(jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte)", + "void*" + ] + }, + { + "returnType": "struct(jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte,jbyte)", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "void", + "parameterTypes": [ + "void*", + "jint" + ] + } + ] + }, + "reflection": [ + { + "type": "net.codecrete.usb.macos.gen.corefoundation.CFMessagePortCreateLocal$callout$Function", + "methods": [ + { + "name": "apply", + "parameterTypes": [ + "java.lang.foreign.MemorySegment", + "int", + "java.lang.foreign.MemorySegment", + "java.lang.foreign.MemorySegment" + ] + } + ] + }, + { + "type": "net.codecrete.usb.macos.gen.iokit.IOServiceAddMatchingNotification$callback$Function", + "methods": [ + { + "name": "apply", + "parameterTypes": [ + "java.lang.foreign.MemorySegment", + "int" + ] + } + ] + } + ] +} diff --git a/examples/monitor_native/config/windows/reachability-metadata.json b/examples/monitor_native/config/windows/reachability-metadata.json new file mode 100644 index 00000000..f3abe566 --- /dev/null +++ b/examples/monitor_native/config/windows/reachability-metadata.json @@ -0,0 +1,377 @@ +{ + "foreign": { + "downcalls": [ + { + "returnType": "jint", + "parameterTypes": [ + "jint", + "void*", + "jint", + "jint", + "void*", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong", + "void*", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong", + "void*", + "void*", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong", + "void*", + "void*", + "jint", + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "jlong", + "void*", + "void*", + "void*", + "void*", + "jint", + "void*", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "jint", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jbyte", + "void*", + "jint", + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "jint", + "void*", + "jint", + "void*", + "jint", + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*" + ] + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "jint", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "void*", + "void*", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jint", + "parameterTypes": [ + "void*", + "void*", + "void*", + "void*", + "void*", + "void*" + ] + }, + { + "returnType": "jlong", + "parameterTypes": [ + "void*", + "jint", + "jlong", + "jlong" + ] + }, + { + "returnType": "jlong", + "parameterTypes": [ + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jlong", + "parameterTypes": [ + "void*", + "void*", + "void*", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "jshort", + "parameterTypes": [ + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [ + "jint", + "void*", + "void*", + "jint", + "jint", + "jint", + "jint", + "jint", + "void*", + "void*", + "void*", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [ + "jlong", + "void*", + "jint", + "jint", + "jint", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "jint", + "jint", + "void*", + "jint", + "jint", + "void*" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*", + "jint" + ], + "options": { + "captureCallState": true + } + }, + { + "returnType": "void*", + "parameterTypes": [ + "void*", + "void*", + "jlong", + "jint" + ], + "options": { + "captureCallState": true + } + } + ], + "upcalls": [ + { + "returnType": "jlong", + "parameterTypes": [ + "void*", + "jint", + "jlong", + "jlong" + ] + } + ] + }, + "reflection": [ + { + "type": "windows.win32.ui.windowsandmessaging.WNDPROC$Function", + "methods": [ + { + "name": "invoke", + "parameterTypes": [ + "java.lang.foreign.MemorySegment", + "int", + "long", + "long" + ] + } + ] + } + ] +} diff --git a/examples/monitor_native/pom.xml b/examples/monitor_native/pom.xml new file mode 100644 index 00000000..55f59768 --- /dev/null +++ b/examples/monitor_native/pom.xml @@ -0,0 +1,84 @@ + + 4.0.0 + + net.codecrete.usb.examples + monitor_native + jar + 1.0-SNAPSHOT + monitor_native + https://www.github.com/manuelbl/java-does-usb + + + 25 + 25 + UTF-8 + 0.11.0 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.14.0 + + true + + + + org.apache.maven.plugins + maven-jar-plugin + 3.4.2 + + + + net.codecrete.usb.examples.App + true + + + + + + + + + + net.codecrete.usb + java-does-usb + 1.2.1 + + + junit + junit + 3.8.1 + test + + + + + + native + + + + org.graalvm.buildtools + native-maven-plugin + ${native.maven.plugin.version} + true + + + build-native + + compile-no-fork + + package + + + + + + + + + diff --git a/examples/monitor_native/src/main/java/net/codecrete/usb/examples/App.java b/examples/monitor_native/src/main/java/net/codecrete/usb/examples/App.java new file mode 100644 index 00000000..3bb1ccb9 --- /dev/null +++ b/examples/monitor_native/src/main/java/net/codecrete/usb/examples/App.java @@ -0,0 +1,38 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.examples; + +import net.codecrete.usb.Usb; +import net.codecrete.usb.UsbDevice; + +import java.io.IOException; + +/** + * Sample application monitoring USB devices as they are connected and disconnected. + */ +public class App { + + static void main() throws IOException { + // register callbacks for events + Usb.setOnDeviceConnected(device -> printDetails(device, "Connected")); + Usb.setOnDeviceDisconnected(device -> printDetails(device, "Disconnected")); + + // display the already present USB devices + for (var device : Usb.getDevices()) + printDetails(device, "Present"); + + // wait for ENTER to quit program + System.out.println("Monitoring... Press ENTER to quit."); + System.in.read(); + } + + private static void printDetails(UsbDevice device, String event) { + System.out.printf("%-14s", event + ":"); + System.out.println(device.toString()); + } +} \ No newline at end of file diff --git a/examples/monitor_native/src/main/resources/META-INF/native-image/net.codecrete.usb.examples/monitor_native/native-image.properties b/examples/monitor_native/src/main/resources/META-INF/native-image/net.codecrete.usb.examples/monitor_native/native-image.properties new file mode 100644 index 00000000..cf6e3f9a --- /dev/null +++ b/examples/monitor_native/src/main/resources/META-INF/native-image/net.codecrete.usb.examples/monitor_native/native-image.properties @@ -0,0 +1 @@ +Args = --enable-native-access=ALL-UNNAMED -H:ConfigurationFileDirectories=config/windows From c3b36ee38c213d2d1e699e41f5e8672dee98cbfb Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Thu, 2 Jul 2026 11:38:49 +0200 Subject: [PATCH 402/433] Add CLAUDE.md --- CLAUDE.md | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..9c988cc8 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,77 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this is + +*Java Does USB* is a pure-Java USB library for communicating with USB devices using custom/vendor-specific protocols (not standard device classes like mass storage or HID). It accesses the OS's native USB APIs through the **Foreign Function and Memory API** — no JNI, no native third-party libraries. Requires **JDK 25** (the `pom.xml` targets release 25; older JDKs need older library versions, see README). + +The publishable library lives in `java-does-usb/`. The repo root also holds `examples/`, `test-devices/` (microcontroller firmware for the hardware test rig), `test-graalvm/` (GraalVM native-image compatibility check), and `reference/`. + +## Commands + +All library commands run from the `java-does-usb/` directory using the Maven wrapper (`./mvnw`). + +```bash +cd java-does-usb + +# Build & install to local Maven repo, skipping hardware tests +./mvnw clean install -DskipTests + +# Run all tests (REQUIRES a physical test device connected — see below) +./mvnw clean test + +# Run a single test class +./mvnw test -Dtest=BulkTransferTest + +# Run a single test method +./mvnw test -Dtest=BulkTransferTest#transferData + +# Build javadoc +./mvnw javadoc:javadoc +``` + +Examples are independent projects, each with its own `mvnw`/`gradlew`. Build one with `cd examples/ && ./mvnw clean compile` (or `./gradlew build` for Kotlin examples). + +### Native access flag + +Any code calling into the library needs native access enabled. Maven surefire passes `--enable-native-access=ALL-UNNAMED` automatically. When running from an IDE or standalone, add the VM option: +`--enable-native-access=net.codecrete.usb` (or `ALL-UNNAMED` if modules are ignored). + +## Testing requires hardware + +The unit tests are integration tests against a real USB device — they will fail with "No test device connected" without one. The device is built from an inexpensive STM32 board flashed with firmware from `test-devices/`: + +- **loopback-stm32** (VID `0xcafe`, PID `0xceaf`): supports all tests. +- **composite-stm32** (VID `0xcafe`, PID `0xcea0`): exercises composite-device handling; some tests are skipped. + +`TestDeviceConfig.java` hard-codes the VID/PID and endpoint numbers for both variants; `TestDeviceBase` auto-detects which one is connected. On Linux, a udev rule is needed for device access (see README "Linux" section). On Windows the test device auto-installs the WinUSB driver via WCID descriptors. + +The `continuous-integration.yaml` workflow only compiles the library and examples on all three OSes — it does **not** run the hardware tests. + +## Architecture + +### Cross-platform abstraction + +The public API is in package `net.codecrete.usb` (`Usb`, `UsbDevice`, `UsbInterface`, `UsbEndpoint`, exceptions, enums). It is the only exported package (`module-info.java`). + +`Usb.java` is the entry point. `Usb.instance()` lazily picks a platform implementation of `UsbDeviceRegistry` based on `os.name`/`os.arch` (Macos/Windows/Linux). Everything else flows through platform-specific subclasses of the abstractions in `net.codecrete.usb.common`: + +- `UsbDeviceRegistry` (common) — singleton that runs a background daemon thread enumerating devices and emitting connect/disconnect events. Each OS subclass implements `monitorDevices()` and calls `setInitialDeviceList()` when the first enumeration completes. +- `UsbDeviceImpl`, `UsbInterfaceImpl`, `UsbEndpointImpl`, `UsbAlternateInterfaceImpl` (common) — shared state and logic; each OS provides a `*UsbDevice` subclass that implements the actual native transfers. +- `EndpointInputStream`/`EndpointOutputStream` + platform `*EndpointInputStream`/`*EndpointOutputStream` — the high-throughput streaming layer. +- `Transfer`/`TransferCompletion` + platform `*Transfer` and `*AsyncTask` — asynchronous transfer plumbing (I/O completion ports on Windows, epoll on Linux, run loop on macOS). +- `ConfigurationParser` (common) — parses raw USB configuration descriptors (portable, byte-level; not OS-specific). + +When adding a feature, expect to touch the common abstraction plus **all three** platform implementations (`linux/`, `macos/`, `windows/`). + +### Native bindings (`gen` packages) + +Native API bindings live under `*/gen/` subpackages and are **generated code**, one package per shared library / macOS framework: + +- **Linux & macOS**: generated with [jextract](https://jdk.java.net/jextract/) via scripts in `java-does-usb/jextract/{linux,macos}/`. The generated code **is committed** to the repo (must be regenerated per-OS; it is portable across x64/ARM64 of the same OS). +- **Windows**: generated at build time by the `windowsapi-maven-plugin` (Windows API Generator) — the function/struct/constant list is configured in `pom.xml`, and the output is **not committed**. + +Some bindings are hand-written rather than generated, because jextract cannot capture thread-local error state (`errno` on Linux, `GetLastError()` on Windows) — those need an extra call-state parameter. See `java-does-usb/jextract/README.md` for the full generation process and jextract's quirks before regenerating. + +Standard USB descriptor structs (device/config/interface/endpoint/string descriptors, setup packet) are modeled in `net.codecrete.usb.usbstandard` as `MemorySegment` views — these are portable and shared across platforms. From f64b19b8177f314ca564b7874820cad667596869 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Thu, 2 Jul 2026 12:00:35 +0200 Subject: [PATCH 403/433] Improve async IO robustness (macOS) --- .../codecrete/usb/macos/MacosAsyncTask.java | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java index 6411682c..1b8f6a68 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java @@ -23,6 +23,8 @@ import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; +import static java.lang.System.Logger.Level.ERROR; +import static java.lang.System.Logger.Level.WARNING; import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.ADDRESS; import static java.lang.foreign.ValueLayout.JAVA_INT; @@ -54,6 +56,8 @@ enum TaskState { */ static final MacosAsyncTask INSTANCE = new MacosAsyncTask(); + private static final System.Logger LOG = System.getLogger(MacosAsyncTask.class.getName()); + private final ReentrantLock asyncIoLock = new ReentrantLock(); private final Condition asyncIoReady = asyncIoLock.newCondition(); private TaskState state = TaskState.NOT_STARTED; @@ -193,14 +197,29 @@ synchronized void prepareForSubmission(MacosTransfer transfer) { @SuppressWarnings("java:S1144") private void asyncIOCompleted(MemorySegment refcon, int result, MemorySegment arg0) { - MacosTransfer transfer; - synchronized (this) { - transfer = transfersById.remove(refcon.address()); - } + try { + MacosTransfer transfer; + synchronized (this) { + transfer = transfersById.remove(refcon.address()); + } - transfer.setResultCode(result); - transfer.setResultSize((int) arg0.address()); - transfer.completion().completed(transfer); + if (transfer == null) { + // A completion for an unknown transfer ID (e.g. a duplicate or spurious + // callback). Ignore it rather than dereferencing null. + LOG.log(WARNING, "Ignoring async IO completion for unknown transfer ID {0}", refcon.address()); + return; + } + + transfer.setResultCode(result); + transfer.setResultSize((int) arg0.address()); + transfer.completion().completed(transfer); + + } catch (Exception e) { + // This method is a native upcall running on the process-wide async IO thread. + // Any exception escaping into CFRunLoopRun() would kill that thread and hang + // all async transfers for the entire library, so nothing must escape here. + LOG.log(ERROR, "Unexpected exception while handling async IO completion", e); + } } /** From e4d7564b26b4f8cd81dd659ef7963baa4696ac2e Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Thu, 2 Jul 2026 18:11:05 +0200 Subject: [PATCH 404/433] Improve robustness of streams on close (all platforms) --- .../usb/common/EndpointInputStream.java | 41 ++++- .../usb/common/EndpointOutputStream.java | 140 ++++++++++++++++-- 2 files changed, 169 insertions(+), 12 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index 07a94b7c..98260f46 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -16,7 +16,9 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.TimeUnit; +import static java.lang.System.Logger.Level.WARNING; import static java.lang.foreign.ValueLayout.JAVA_BYTE; /** @@ -36,6 +38,13 @@ */ public abstract class EndpointInputStream extends InputStream { + private static final System.Logger LOG = System.getLogger(EndpointInputStream.class.getName()); + + // Maximum time (ms) to wait for outstanding transfers to complete during teardown. + // A completion that is never delivered (e.g. after an unplug) then degrades to a + // logged warning instead of a permanent hang. + private static final long TEARDOWN_TIMEOUT_MS = 1000; + protected UsbDeviceImpl device; protected final int endpointNumber; // Arena to allocate buffers and completion handlers @@ -212,10 +221,36 @@ private void onCompletion(Transfer transfer) { completedTransferQueue.add(transfer); } + @SuppressWarnings("java:S2142") private void collectOutstandingTransfers() { - // wait until completion handlers have been called - while (numOutstandingTransfers > 0) - waitForCompletedTransfer(); + // Wait until the completion handlers have been called. This is a teardown path, + // so the wait is bounded: if a completion is never delivered (device unplugged, + // or the completion is lost in a source-removal race), abandon the transfer and + // log a warning instead of blocking the application thread forever. + var deadline = System.currentTimeMillis() + TEARDOWN_TIMEOUT_MS; + var wasInterrupted = false; + + while (numOutstandingTransfers > 0) { + var remaining = deadline - System.currentTimeMillis(); + if (remaining <= 0) { + LOG.log(WARNING, + "abandoning {0} outstanding transfer(s) during input stream teardown - no completion within {1} ms", + numOutstandingTransfers, TEARDOWN_TIMEOUT_MS); + break; + } + + try { + if (completedTransferQueue.poll(remaining, TimeUnit.MILLISECONDS) != null) + numOutstandingTransfers -= 1; + } catch (InterruptedException _) { + // defer the interrupt: keep polling the remaining time without re-setting + // the flag (avoids a busy-spin), then re-assert it once we are done + wasInterrupted = true; + } + } + + if (wasInterrupted) + Thread.currentThread().interrupt(); completedTransferQueue.clear(); currentTransfer = null; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java index 60478408..a81744ce 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -16,7 +16,9 @@ import java.lang.foreign.MemorySegment; import java.util.Arrays; import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.TimeUnit; +import static java.lang.System.Logger.Level.WARNING; import static java.lang.foreign.ValueLayout.JAVA_BYTE; /** @@ -38,6 +40,13 @@ */ public abstract class EndpointOutputStream extends OutputStream { + private static final System.Logger LOG = System.getLogger(EndpointOutputStream.class.getName()); + + // Maximum time (ms) to wait for outstanding transfers to complete during teardown. + // A completion that is never delivered (e.g. after an unplug) then degrades to a + // logged warning instead of a permanent hang. + private static final long TEARDOWN_TIMEOUT_MS = 1000; + protected UsbDeviceImpl device; protected final int endpointNumber; protected final Arena arena; @@ -104,15 +113,128 @@ public void close() throws IOException { if (isClosed()) return; - if (!hasError) - flush(); - else - waitForOutstandingTransfers(); - - device = null; - availableTransferQueue.clear(); - currentTransfer = null; - //arena.close(); + // Teardown path: every wait is bounded by a single deadline so a lost completion + // (device unplugged, or completion dropped in a source-removal race) degrades to a + // logged warning instead of hanging the application thread. Unlike the public + // flush(), this must not route through the unbounded waits. + var deadline = System.currentTimeMillis() + TEARDOWN_TIMEOUT_MS; + + try { + if (!hasError) { + // best-effort: transmit any remaining buffered data (and a ZLP if needed) + if (writeOffset > 0) + submitForClose(writeOffset, deadline); + if (needsZlp && currentTransfer != null) + submitForClose(0, deadline); + } + + drainOutstandingTransfers(deadline); + + } catch (Exception e) { + // teardown must not fail; data-path errors are already surfaced by write()/flush() + LOG.log(WARNING, "error while closing output stream - ignoring", e); + + } finally { + device = null; + availableTransferQueue.clear(); + currentTransfer = null; + //arena.close(); + } + } + + /** + * Submits the current transfer during teardown and acquires a replacement, + * both bounded by the given deadline. + *

+ * Unlike {@link #submitTransfer(int)} this does not recurse into {@link #close()} on error, + * and it does not block indefinitely when acquiring the next transfer instance. + *

+ * + * @param size size of data to be transmitted + * @param deadline absolute deadline (ms since epoch) for acquiring the next transfer + */ + private void submitForClose(int size, long deadline) { + currentTransfer.setDataSize(size); + submitTransferOut(currentTransfer); + + synchronized (this) { + numOutstandingTransfers += 1; + } + + needsZlp = size == packetSize; + writeOffset = 0; + // if no transfer becomes available within the deadline, currentTransfer stays null, + // the drain below still bounded-waits for the in-flight transfer to complete + currentTransfer = pollAvailableTransfer(deadline); + } + + /** + * Waits for all outstanding transfers to complete, bounded by the given deadline. + *

+ * If a completion is not delivered in time, the remaining transfers are abandoned and a + * warning is logged. + *

+ * + * @param deadline absolute deadline (ms since epoch) + */ + private void drainOutstandingTransfers(long deadline) { + int numTransfers; + synchronized (this) { + numTransfers = numOutstandingTransfers + availableTransferQueue.size(); + } + + for (var i = 0; i < numTransfers; i++) { + if (pollAvailableTransfer(deadline) == null) { + int abandoned; + synchronized (this) { + abandoned = numOutstandingTransfers; + } + LOG.log(WARNING, + "abandoning {0} outstanding transfer(s) during output stream teardown - no completion within {1} ms", + abandoned, TEARDOWN_TIMEOUT_MS); + break; + } + } + } + + /** + * Waits until a transfer instance is available for use, bounded by the given deadline. + * + * @param deadline absolute deadline (ms since epoch) + * @return transfer instance ready for use, or {@code null} if the deadline expired + */ + private Transfer pollAvailableTransfer(long deadline) { + var wasInterrupted = false; + try { + while (true) { + var remaining = deadline - System.currentTimeMillis(); + if (remaining <= 0) + return null; + + try { + var transfer = availableTransferQueue.poll(remaining, TimeUnit.MILLISECONDS); + if (transfer == null) + return null; + + // surface a transfer error unless we are already in the error path + var result = transfer.resultCode(); + if (result != 0 && !hasError) { + transfer.setResultCode(0); + device.throwOSException(result, "error occurred while transmitting to endpoint %d", endpointNumber); + } + + return transfer; + + } catch (InterruptedException _) { + // defer the interrupt: keep polling the remaining time without re-setting + // the flag (avoids a busy-spin), then re-assert it once we are done + wasInterrupted = true; + } + } + } finally { + if (wasInterrupted) + Thread.currentThread().interrupt(); + } } @Override From f84342f62552fdd60c8546a23b49c8bb5e362376 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Thu, 2 Jul 2026 22:51:17 +0200 Subject: [PATCH 405/433] Defer thread interruptions (all platforms) --- .../usb/common/EndpointInputStream.java | 23 +++++++---- .../usb/common/EndpointOutputStream.java | 35 ++++++++++------- .../codecrete/usb/common/UsbDeviceImpl.java | 29 ++++++++++---- .../codecrete/usb/macos/MacosUsbDevice.java | 10 ++++- .../usb/windows/WindowsUsbDevice.java | 39 ++++++++++++------- 5 files changed, 91 insertions(+), 45 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index 98260f46..c77c10c0 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -201,14 +201,23 @@ private void receiveMoreData() throws IOException { } private Transfer waitForCompletedTransfer() { - while (true) { - try { - var transfer = completedTransferQueue.take(); - numOutstandingTransfers -= 1; - return transfer; - } catch (InterruptedException _) { - Thread.currentThread().interrupt(); + // Defer interruption: keep a local flag instead of re-asserting the interrupt + // inside the loop (which would make the next take() throw immediately and + // busy-spin). Re-assert once the completion has actually arrived. + var wasInterrupted = false; + try { + while (true) { + try { + var transfer = completedTransferQueue.take(); + numOutstandingTransfers -= 1; + return transfer; + } catch (InterruptedException _) { + wasInterrupted = true; + } } + } finally { + if (wasInterrupted) + Thread.currentThread().interrupt(); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java index a81744ce..95b51dcb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -344,22 +344,31 @@ private void waitForOutstandingTransfers() { * @return transfer instance ready for use */ private Transfer waitForAvailableTransfer() { - while (true) { - try { - var transfer = availableTransferQueue.take(); - - // check for error - var result = transfer.resultCode(); - if (result != 0 && !hasError) { - transfer.setResultCode(0); - device.throwOSException(result, "error occurred while transmitting to endpoint %d", endpointNumber); - } + // Defer interruption: keep a local flag instead of re-asserting the interrupt + // inside the loop (which would make the next take() throw immediately and + // busy-spin). Re-assert once a transfer has actually become available. + var wasInterrupted = false; + try { + while (true) { + try { + var transfer = availableTransferQueue.take(); - return transfer; + // check for error + var result = transfer.resultCode(); + if (result != 0 && !hasError) { + transfer.setResultCode(0); + device.throwOSException(result, "error occurred while transmitting to endpoint %d", endpointNumber); + } - } catch (InterruptedException _) { - Thread.currentThread().interrupt(); + return transfer; + + } catch (InterruptedException _) { + wasInterrupted = true; + } } + } finally { + if (wasInterrupted) + Thread.currentThread().interrupt(); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java index 427bc749..79f4cfb7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java @@ -387,33 +387,46 @@ protected void waitForTransfer(Transfer transfer, int timeout, UsbDirection dire } } - @SuppressWarnings("java:S2273") + @SuppressWarnings({"java:S2273", "java:S2142"}) private static void waitNoTimeout(Transfer transfer) { - // wait for transfer + // wait for transfer. + // Defer interruption: keep a local flag instead of re-asserting the interrupt + // inside the loop (which would make the next wait() throw immediately and + // busy-spin). Re-assert once the transfer has actually completed. + var wasInterrupted = false; while (transfer.resultSize() == -1) { try { transfer.wait(); } catch (InterruptedException _) { - Thread.currentThread().interrupt(); + wasInterrupted = true; } } + if (wasInterrupted) + Thread.currentThread().interrupt(); } - @SuppressWarnings("java:S2273") + @SuppressWarnings({"java:S2273", "java:S2142"}) private static boolean waitWithTimeout(Transfer transfer, int timeout) { - // wait for transfer to complete, or abort when timeout occurs + // wait for transfer to complete, or abort when timeout occurs. + // Defer interruption: keep a local flag instead of re-asserting the interrupt + // inside the loop (which would make the next wait() throw immediately and + // busy-spin). The remaining timeout is recomputed on both the normal and the + // interrupted path, so the wait stays bounded by the original expiration. var expiration = System.currentTimeMillis() + timeout; long remainingTimeout = timeout; + var wasInterrupted = false; while (remainingTimeout > 0 && transfer.resultSize() == -1) { try { transfer.wait(remainingTimeout); - remainingTimeout = expiration - System.currentTimeMillis(); - } catch (InterruptedException _) { - Thread.currentThread().interrupt(); + wasInterrupted = true; } + remainingTimeout = expiration - System.currentTimeMillis(); } + if (wasInterrupted) + Thread.currentThread().interrupt(); + return remainingTimeout <= 0; } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java index 1eaa9e93..5cb9c7d3 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java @@ -98,7 +98,7 @@ public boolean isOpened() { return claimedInterfaces != null; } - @SuppressWarnings("java:S2276") + @SuppressWarnings({"java:S2276", "java:S2142"}) @Override public synchronized void open() { checkIsClosed("device is already open"); @@ -107,6 +107,10 @@ public synchronized void open() { var duration = System.currentTimeMillis() - discoveryTime; var numTries = duration < 1000 ? 4 : 1; var ret = 0; + // Defer interruption: keep a local flag instead of re-asserting the interrupt + // (which would make the remaining backoff sleeps throw immediately and defeat + // the retry delay). Re-assert once the retries are done. + var wasInterrupted = false; while (numTries > 0) { numTries -= 1; ret = IoKitUsb.USBDeviceOpenSeize(device); @@ -117,9 +121,11 @@ public synchronized void open() { try { Thread.sleep(90); } catch (InterruptedException _) { - Thread.currentThread().interrupt(); + wasInterrupted = true; } } + if (wasInterrupted) + Thread.currentThread().interrupt(); if (ret != 0) throwException(ret, "opening USB device failed"); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java index f8001437..727b5a37 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java @@ -140,22 +140,31 @@ public void claimInterface(int interfaceNumber) { // the related information will be available with a delay. So for composite functions, several // retries might be needed until the device path is available. var numRetries = 30; // 30 x 100ms - while (true) { - if (claimInterfaceSynchronized(interfaceNumber)) - return; // success - - numRetries -= 1; - if (numRetries == 0) - throw new UsbException("claiming interface failed (function has no device path / interface GUID, might be missing WinUSB driver)"); - - // sleep and retry - try { - LOG.log(DEBUG, "Sleeping for 100ms..."); - //noinspection BusyWait - Thread.sleep(100); - } catch (InterruptedException _) { - Thread.currentThread().interrupt(); + // Defer interruption: keep a local flag instead of re-asserting the interrupt + // (which would make the remaining backoff sleeps throw immediately and defeat + // the retry delay). Re-assert when leaving the method. + var wasInterrupted = false; + try { + while (true) { + if (claimInterfaceSynchronized(interfaceNumber)) + return; // success + + numRetries -= 1; + if (numRetries == 0) + throw new UsbException("claiming interface failed (function has no device path / interface GUID, might be missing WinUSB driver)"); + + // sleep and retry + try { + LOG.log(DEBUG, "Sleeping for 100ms..."); + //noinspection BusyWait + Thread.sleep(100); + } catch (InterruptedException _) { + wasInterrupted = true; + } } + } finally { + if (wasInterrupted) + Thread.currentThread().interrupt(); } } From bbfbfca29ea67c019200da22fac31ca277daba78 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 3 Jul 2026 11:45:06 +0200 Subject: [PATCH 406/433] Unit test for tear down of blocked writer --- .../java/net/codecrete/usb/StreamTest.java | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java index adb6652a..f586aa3a 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java @@ -12,10 +12,15 @@ import org.junit.jupiter.api.Test; import java.io.IOException; +import java.io.InputStream; import java.util.Arrays; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertTrue; class StreamTest extends TestDeviceBase { @@ -76,6 +81,102 @@ void largeTransferBigChunks_succeeds() { assertArrayEquals(sampleData, reader.resultNow()); } + @Test + @SuppressWarnings({"java:S2925", "BusyWait"}) + void blockedWriter_canBeAborted() throws InterruptedException { + // A writer that fills the pipe faster than it is drained eventually blocks in write(). + // Aborting the outstanding transfers from another thread must terminate it promptly and + // safely (with a USB exception) rather than leave it wedged forever. + + final var data = generateRandomBytes(1_000_000, 0x5c7f10ebL); + + final var bytesWritten = new AtomicLong(0); + final var writerError = new AtomicReference(); + final var readerStream = new AtomicReference(); + + // Thread 1: write to the loopback OUT endpoint until it blocks (nothing keeps draining it). + var writer = new Thread(() -> { + try (var os = testDevice.openOutputStream(config.endpointLoopbackOut())) { + var offset = 0; + while (offset < data.length) { + var size = Math.min(100, data.length - offset); + os.write(data, offset, size); + offset += size; + bytesWritten.set(offset); + } + } catch (Throwable t) { + writerError.set(t); + } + }, "loopback-writer"); + + // Thread 2: read a limited amount from the loopback IN endpoint, then stop draining + // (the stream stays open, modelling a stalled consumer that applies back pressure). + var reader = new Thread(() -> { + try { + var is = testDevice.openInputStream(config.endpointLoopbackIn()); + readerStream.set(is); + var buffer = new byte[64]; + var n = is.read(buffer); + assertTrue(n > 0); + } catch (IOException e) { + throw new RuntimeException(e); + } + }, "loopback-reader"); + + try { + writer.start(); + reader.start(); + reader.join(); + + // Wait until the writer is actually blocked: its progress must stall for 300 ms. + var giveUp = System.currentTimeMillis() + 5000; + var lastCount = -1L; + var stableSince = System.currentTimeMillis(); + while (writer.isAlive() && System.currentTimeMillis() < giveUp) { + var count = bytesWritten.get(); + var now = System.currentTimeMillis(); + if (count != lastCount) { + lastCount = count; + stableSince = now; + } else if (now - stableSince >= 300) { + break; + } + Thread.sleep(20); + } + assertTrue(writer.isAlive(), "writer terminated before it could block"); + + // Abort the outstanding OUT transfers from this thread; the blocked writer must unwind. + testDevice.abortTransfers(UsbDirection.OUT, config.endpointLoopbackOut()); + + writer.join(1500); + assertFalse(writer.isAlive(), "writer thread did not terminate within 1.5 s after abort"); + + // It must have unwound because of the abort, not by finishing or dying some other way. + assertInstanceOf(UsbException.class, writerError.get()); + + } finally { + // Restore a clean device state so subsequent tests are not affected. + var is = readerStream.get(); + if (is != null) { + try { + is.close(); + } catch (IOException _) { + // ignore + } + } + if (writer.isAlive()) { + try { + testDevice.abortTransfers(UsbDirection.OUT, config.endpointLoopbackOut()); + } catch (Exception _) { + // ignore + } + writer.join(1500); + } + resetBuffers(); + drainData(config.endpointLoopbackIn()); + } + } + static void writeBytes(byte[] data, int chunkSize) { try (var os = testDevice.openOutputStream(config.endpointLoopbackOut())) { var numBytes = 0; From f700ebbeee2929ceaf98f92cb00cfcc4d4704b88 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 3 Jul 2026 14:59:20 +0200 Subject: [PATCH 407/433] Timeout considered when aborting completion --- .../codecrete/usb/common/UsbDeviceImpl.java | 19 ++++- .../codecrete/usb/linux/LinuxUsbDevice.java | 38 +++++---- .../codecrete/usb/macos/MacosUsbDevice.java | 84 ++++++++++--------- .../usb/windows/WindowsUsbDevice.java | 38 +++++---- 4 files changed, 101 insertions(+), 78 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java index 79f4cfb7..0156d5b1 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java @@ -24,11 +24,19 @@ import java.util.List; import java.util.function.IntFunction; +import static java.lang.System.Logger.Level.WARNING; import static java.lang.foreign.ValueLayout.JAVA_BYTE; @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") public abstract class UsbDeviceImpl implements UsbDevice { + private static final System.Logger LOG = System.getLogger(UsbDeviceImpl.class.getName()); + + // Maximum time (ms) to wait for the completion of a transfer that was aborted due to a + // timeout. If the abort's completion is never delivered (e.g. after an unplug), the wait + // degrades to a logged warning instead of a permanent hang. The transfer is then abandoned. + private static final long ABORT_COMPLETION_TIMEOUT_MS = 1000; + /** * Operating system-specific device ID used for {@link #equals(Object)} and {@link #hashCode()}. *

@@ -375,7 +383,16 @@ protected void waitForTransfer(Transfer transfer, int timeout, UsbDirection dire // test for timeout if (hasTimedOut && transfer.resultCode() == 0) { abortTransfers(direction, endpointNumber); - waitNoTimeout(transfer); + + // Wait for the abort's completion, but bounded: if it never arrives (device + // vanished such that neither the transfer nor the abort yields a callback), + // abandon the transfer instead of blocking forever. Abandoning is safe because + // buffers reaching this path come from an auto arena and survive a late completion. + var abortCompleted = !waitWithTimeout(transfer, (int) ABORT_COMPLETION_TIMEOUT_MS); + if (!abortCompleted) + LOG.log(WARNING, "abort completion for {0} did not arrive within {1} ms - abandoning transfer", + getOperationDescription(direction, endpointNumber), ABORT_COMPLETION_TIMEOUT_MS); + throw new UsbTimeoutException(getOperationDescription(direction, endpointNumber) + " aborted due to timeout"); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java index 4e8c66a7..29bc77a9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java @@ -259,15 +259,16 @@ private LinuxTransfer createSyncCtrlTransfer(Arena arena, UsbDirection direction @Override public void transferOut(int endpointNumber, byte @NotNull [] data, int offset, int length, int timeout) { - try (var arena = Arena.ofConfined()) { - var buffer = arena.allocate(length); - buffer.copyFrom(MemorySegment.ofArray(data).asSlice(offset, length)); - var transfer = createSyncTransfer(buffer); - - synchronized (transfer) { - submitTransfer(UsbDirection.OUT, endpointNumber, transfer); - waitForTransfer(transfer, timeout, UsbDirection.OUT, endpointNumber); - } + // Auto arena: a transfer that times out may be abandoned (see UsbDeviceImpl.waitForTransfer), + // so the buffer must outlive a possible late completion instead of being freed deterministically. + var arena = Arena.ofAuto(); + var buffer = arena.allocate(length); + buffer.copyFrom(MemorySegment.ofArray(data).asSlice(offset, length)); + var transfer = createSyncTransfer(buffer); + + synchronized (transfer) { + submitTransfer(UsbDirection.OUT, endpointNumber, transfer); + waitForTransfer(transfer, timeout, UsbDirection.OUT, endpointNumber); } } @@ -275,17 +276,18 @@ public void transferOut(int endpointNumber, byte @NotNull [] data, int offset, i public byte @NotNull [] transferIn(int endpointNumber, int timeout) { var endpoint = getEndpoint(UsbDirection.IN, endpointNumber, UsbTransferType.BULK, UsbTransferType.INTERRUPT); - try (var arena = Arena.ofConfined()) { - var buffer = arena.allocate(endpoint.packetSize()); - var transfer = createSyncTransfer(buffer); + // Auto arena: a transfer that times out may be abandoned (see UsbDeviceImpl.waitForTransfer), + // so the buffer must outlive a possible late completion instead of being freed deterministically. + var arena = Arena.ofAuto(); + var buffer = arena.allocate(endpoint.packetSize()); + var transfer = createSyncTransfer(buffer); - synchronized (transfer) { - submitTransfer(UsbDirection.IN, endpointNumber, transfer); - waitForTransfer(transfer, timeout, UsbDirection.IN, endpointNumber); - } - - return buffer.asSlice(0, transfer.resultSize()).toArray(JAVA_BYTE); + synchronized (transfer) { + submitTransfer(UsbDirection.IN, endpointNumber, transfer); + waitForTransfer(transfer, timeout, UsbDirection.IN, endpointNumber); } + + return buffer.asSlice(0, transfer.resultSize()).toArray(JAVA_BYTE); } private LinuxTransfer createSyncTransfer(MemorySegment data) { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java index 5cb9c7d3..0b5532d2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java @@ -444,26 +444,27 @@ public void transferOut(int endpointNumber, byte @NotNull [] data, int offset, i var epInfo = getEndpointInfo(endpointNumber, UsbDirection.OUT, UsbTransferType.BULK, UsbTransferType.INTERRUPT); - try (var arena = Arena.ofConfined()) { - var nativeData = arena.allocate(JAVA_BYTE, length); - nativeData.copyFrom(MemorySegment.ofArray(data).asSlice(offset, length)); - - var transfer = new MacosTransfer(); - transfer.setData(nativeData); - transfer.setDataSize(length); - transfer.setCompletion(UsbDeviceImpl::onSyncTransferCompleted); - - synchronized (transfer) { - if (timeout <= 0 || epInfo.transferType() == UsbTransferType.BULK) { - // no timeout or timeout handled by operating system - submitTransferOut(endpointNumber, transfer, timeout); - waitForTransfer(transfer, 0, UsbDirection.OUT, endpointNumber); - - } else { - // interrupt transfer with timeout - submitTransferOut(endpointNumber, transfer, 0); - waitForTransfer(transfer, timeout, UsbDirection.OUT, endpointNumber); - } + // Auto arena: a transfer that times out may be abandoned (see UsbDeviceImpl.waitForTransfer), + // so the buffer must outlive a possible late completion instead of being freed deterministically. + var arena = Arena.ofAuto(); + var nativeData = arena.allocate(JAVA_BYTE, length); + nativeData.copyFrom(MemorySegment.ofArray(data).asSlice(offset, length)); + + var transfer = new MacosTransfer(); + transfer.setData(nativeData); + transfer.setDataSize(length); + transfer.setCompletion(UsbDeviceImpl::onSyncTransferCompleted); + + synchronized (transfer) { + if (timeout <= 0 || epInfo.transferType() == UsbTransferType.BULK) { + // no timeout or timeout handled by operating system + submitTransferOut(endpointNumber, transfer, timeout); + waitForTransfer(transfer, 0, UsbDirection.OUT, endpointNumber); + + } else { + // interrupt transfer with timeout + submitTransferOut(endpointNumber, transfer, 0); + waitForTransfer(transfer, timeout, UsbDirection.OUT, endpointNumber); } } } @@ -474,29 +475,30 @@ public void transferOut(int endpointNumber, byte @NotNull [] data, int offset, i var epInfo = getEndpointInfo(endpointNumber, UsbDirection.IN, UsbTransferType.BULK, UsbTransferType.INTERRUPT); - try (var arena = Arena.ofConfined()) { - var nativeData = arena.allocate(JAVA_BYTE, epInfo.packetSize()); - - var transfer = new MacosTransfer(); - transfer.setData(nativeData); - transfer.setDataSize(epInfo.packetSize()); - transfer.setCompletion(UsbDeviceImpl::onSyncTransferCompleted); - - synchronized (transfer) { - if (timeout <= 0 || epInfo.transferType() == UsbTransferType.BULK) { - // no timeout, or timeout handled by operating system - submitTransferIn(endpointNumber, transfer, timeout); - waitForTransfer(transfer, 0, UsbDirection.IN, endpointNumber); - - } else { - // interrupt transfer with timeout - submitTransferIn(endpointNumber, transfer, 0); - waitForTransfer(transfer, timeout, UsbDirection.IN, endpointNumber); - } + // Auto arena: a transfer that times out may be abandoned (see UsbDeviceImpl.waitForTransfer), + // so the buffer must outlive a possible late completion instead of being freed deterministically. + var arena = Arena.ofAuto(); + var nativeData = arena.allocate(JAVA_BYTE, epInfo.packetSize()); + + var transfer = new MacosTransfer(); + transfer.setData(nativeData); + transfer.setDataSize(epInfo.packetSize()); + transfer.setCompletion(UsbDeviceImpl::onSyncTransferCompleted); + + synchronized (transfer) { + if (timeout <= 0 || epInfo.transferType() == UsbTransferType.BULK) { + // no timeout, or timeout handled by operating system + submitTransferIn(endpointNumber, transfer, timeout); + waitForTransfer(transfer, 0, UsbDirection.IN, endpointNumber); + + } else { + // interrupt transfer with timeout + submitTransferIn(endpointNumber, transfer, 0); + waitForTransfer(transfer, timeout, UsbDirection.IN, endpointNumber); } - - return nativeData.asSlice(0, transfer.resultSize()).toArray(JAVA_BYTE); } + + return nativeData.asSlice(0, transfer.resultSize()).toArray(JAVA_BYTE); } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java index 727b5a37..9c700cee 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java @@ -328,15 +328,16 @@ public void controlTransferOut(@NotNull UsbControlTransfer setup, byte[] data) { @Override public void transferOut(int endpointNumber, byte @NotNull [] data, int offset, int length, int timeout) { - try (var arena = Arena.ofConfined()) { - var buffer = arena.allocate(data.length); - buffer.copyFrom(MemorySegment.ofArray(data).asSlice(offset, length)); - var transfer = createSyncTransfer(buffer); - - synchronized (transfer) { - submitTransferOut(endpointNumber, transfer); - waitForTransfer(transfer, timeout, UsbDirection.OUT, endpointNumber); - } + // Auto arena: a transfer that times out may be abandoned (see UsbDeviceImpl.waitForTransfer), + // so the buffer must outlive a possible late completion instead of being freed deterministically. + var arena = Arena.ofAuto(); + var buffer = arena.allocate(data.length); + buffer.copyFrom(MemorySegment.ofArray(data).asSlice(offset, length)); + var transfer = createSyncTransfer(buffer); + + synchronized (transfer) { + submitTransferOut(endpointNumber, transfer); + waitForTransfer(transfer, timeout, UsbDirection.OUT, endpointNumber); } } @@ -344,17 +345,18 @@ public void transferOut(int endpointNumber, byte @NotNull [] data, int offset, i public byte @NotNull [] transferIn(int endpointNumber, int timeout) { var endpoint = getEndpoint(UsbDirection.IN, endpointNumber, UsbTransferType.BULK, UsbTransferType.INTERRUPT); - try (var arena = Arena.ofConfined()) { - var buffer = arena.allocate(endpoint.packetSize()); - var transfer = createSyncTransfer(buffer); + // Auto arena: a transfer that times out may be abandoned (see UsbDeviceImpl.waitForTransfer), + // so the buffer must outlive a possible late completion instead of being freed deterministically. + var arena = Arena.ofAuto(); + var buffer = arena.allocate(endpoint.packetSize()); + var transfer = createSyncTransfer(buffer); - synchronized (transfer) { - submitTransferIn(endpointNumber, transfer); - waitForTransfer(transfer, timeout, UsbDirection.IN, endpointNumber); - } - - return buffer.asSlice(0, transfer.resultSize()).toArray(JAVA_BYTE); + synchronized (transfer) { + submitTransferIn(endpointNumber, transfer); + waitForTransfer(transfer, timeout, UsbDirection.IN, endpointNumber); } + + return buffer.asSlice(0, transfer.resultSize()).toArray(JAVA_BYTE); } private WindowsTransfer createSyncControlTransfer() { From 60a47aff34c6a16b7e33c42f69483cfe4c737267 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 3 Jul 2026 15:06:27 +0200 Subject: [PATCH 408/433] Deregister transfer on exception (macOS) --- .../net/codecrete/usb/macos/MacosAsyncTask.java | 14 ++++++++++++++ .../net/codecrete/usb/macos/MacosUsbDevice.java | 12 +++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java index 1b8f6a68..991ce592 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java @@ -187,6 +187,20 @@ synchronized void prepareForSubmission(MacosTransfer transfer) { transfersById.put(lastTransferId, transfer); } + /** + * Undoes the registration performed by {@link #prepareForSubmission(MacosTransfer)}. + *

+ * Must be called if the native submission of a prepared transfer fails. In that case, + * no completion callback will ever fire for the transfer, so its map entry would leak + * unless it is removed here. + *

+ * + * @param transfer transfer whose submission failed + */ + synchronized void submissionFailed(MacosTransfer transfer) { + transfersById.remove(transfer.id()); + } + /** * Callback function called when an asynchronous transfer has completed. * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java index 0b5532d2..ffa7ff8d 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java @@ -527,8 +527,10 @@ synchronized void submitTransferIn(int endpointNumber, MacosTransfer transfer, i transfer.dataSize(), timeout, timeout, asyncTask.nativeCompletionCallback(), MemorySegment.ofAddress(transfer.id())); - if (ret != 0) + if (ret != 0) { + asyncTask.submissionFailed(transfer); throwException(ret, "error occurred while reading from endpoint %d", endpointNumber); + } } /** @@ -557,8 +559,10 @@ synchronized void submitTransferOut(int endpointNumber, MacosTransfer transfer, transfer.dataSize(), timeout, timeout, asyncTask.nativeCompletionCallback(), MemorySegment.ofAddress(transfer.id())); - if (ret != 0) + if (ret != 0) { + asyncTask.submissionFailed(transfer); throwException(ret, "error occurred while transmitting to endpoint %d", endpointNumber); + } } /** @@ -576,8 +580,10 @@ synchronized void submitControlTransfer(MemorySegment deviceRequest, MacosTransf var ret = IoKitUsb.DeviceRequestAsync(device, deviceRequest, asyncTask.nativeCompletionCallback(), MemorySegment.ofAddress(transfer.id())); - if (ret != 0) + if (ret != 0) { + asyncTask.submissionFailed(transfer); throwException(ret, "control transfer failed"); + } } @Override From 02cd55ba2c9812b127ad56ca8c059dd89ada7fe4 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 3 Jul 2026 15:25:27 +0200 Subject: [PATCH 409/433] Throw checked IOException in input/output stream methods --- .../usb/common/EndpointInputStream.java | 67 +++++++++++++------ .../usb/common/EndpointOutputStream.java | 64 ++++++++++++------ .../codecrete/usb/common/EndpointStreams.java | 44 ++++++++++++ .../java/net/codecrete/usb/StreamTest.java | 7 +- 4 files changed, 137 insertions(+), 45 deletions(-) create mode 100644 java-does-usb/src/main/java/net/codecrete/usb/common/EndpointStreams.java diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java index c77c10c0..167b041c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java @@ -15,9 +15,12 @@ import java.io.InputStream; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; +import java.util.Objects; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeUnit; +import static net.codecrete.usb.common.EndpointStreams.toIOException; + import static java.lang.System.Logger.Level.WARNING; import static java.lang.foreign.ValueLayout.JAVA_BYTE; @@ -134,44 +137,66 @@ public void close() throws IOException { @Override public int read() throws IOException { - if (isClosed()) - return -1; + ensureOpen(); + + try { + if (bufferedBytes() == 0) + receiveMoreData(); - if (available() == 0) - receiveMoreData(); + var b = currentTransfer.data().get(JAVA_BYTE, readOffset) & 0xff; + readOffset += 1; + return b; - var b = currentTransfer.data().get(JAVA_BYTE, readOffset) & 0xff; - readOffset += 1; - return b; + } catch (UsbException e) { + throw toIOException(e); + } } @Override public int read(byte @NotNull [] b, int off, int len) throws IOException { - if (isClosed()) - return -1; + Objects.checkFromIndexSize(off, len, b.length); + ensureOpen(); + if (len == 0) + return 0; - var numRead = 0; - do { - if (available() == 0) - receiveMoreData(); + try { + var numRead = 0; + do { + if (bufferedBytes() == 0) + receiveMoreData(); + + // copy data to receiving buffer + var n = Math.min(len - numRead, currentTransfer.resultSize() - readOffset); + MemorySegment.copy(currentTransfer.data(), readOffset, MemorySegment.ofArray(b), (long) off + numRead, n); + readOffset += n; + numRead += n; - // copy data to receiving buffer - var n = Math.min(len - numRead, currentTransfer.resultSize() - readOffset); - MemorySegment.copy(currentTransfer.data(), readOffset, MemorySegment.ofArray(b), (long) off + numRead, n); - readOffset += n; - numRead += n; + } while (numRead < len && hasMoreTransfers()); - } while (numRead < len && hasMoreTransfers()); + return numRead; - return numRead; + } catch (UsbException e) { + throw toIOException(e); + } } - @SuppressWarnings("RedundantThrows") @Override public int available() throws IOException { + ensureOpen(); + return bufferedBytes(); + } + + // Bytes buffered in the current transfer, without a closed-stream check. + // Callers on the read path guard with ensureOpen() first. + private int bufferedBytes() { return currentTransfer.resultSize() - readOffset; } + private void ensureOpen() throws IOException { + if (isClosed()) + throw new IOException("input stream has been closed"); + } + private boolean hasMoreTransfers() { return !completedTransferQueue.isEmpty(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java index 95b51dcb..c371939e 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java @@ -8,6 +8,7 @@ package net.codecrete.usb.common; import net.codecrete.usb.UsbDirection; +import net.codecrete.usb.UsbException; import org.jetbrains.annotations.NotNull; import java.io.IOException; @@ -15,9 +16,12 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.util.Arrays; +import java.util.Objects; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeUnit; +import static net.codecrete.usb.common.EndpointStreams.toIOException; + import static java.lang.System.Logger.Level.WARNING; import static java.lang.foreign.ValueLayout.JAVA_BYTE; @@ -239,41 +243,57 @@ private Transfer pollAvailableTransfer(long deadline) { @Override public void write(int b) throws IOException { - checkIsOpen(); + ensureOpen(); - currentTransfer.data().set(JAVA_BYTE, writeOffset, (byte) b); - writeOffset += 1; - if (writeOffset == transferSize) - submitTransfer(writeOffset); + try { + currentTransfer.data().set(JAVA_BYTE, writeOffset, (byte) b); + writeOffset += 1; + if (writeOffset == transferSize) + submitTransfer(writeOffset); + + } catch (UsbException e) { + throw toIOException(e); + } } @Override public void write(byte @NotNull [] b, int off, int len) throws IOException { - checkIsOpen(); + Objects.checkFromIndexSize(off, len, b.length); + ensureOpen(); - while (len > 0) { - var chunkSize = Math.min(len, transferSize - writeOffset); - MemorySegment.copy(b, off, currentTransfer.data(), JAVA_BYTE, writeOffset, chunkSize); - writeOffset += chunkSize; - off += chunkSize; - len -= chunkSize; + try { + while (len > 0) { + var chunkSize = Math.min(len, transferSize - writeOffset); + MemorySegment.copy(b, off, currentTransfer.data(), JAVA_BYTE, writeOffset, chunkSize); + writeOffset += chunkSize; + off += chunkSize; + len -= chunkSize; + + if (writeOffset == transferSize) + submitTransfer(writeOffset); + } - if (writeOffset == transferSize) - submitTransfer(writeOffset); + } catch (UsbException e) { + throw toIOException(e); } } @Override public void flush() throws IOException { - checkIsOpen(); + ensureOpen(); - if (writeOffset > 0) - submitTransfer(writeOffset); + try { + if (writeOffset > 0) + submitTransfer(writeOffset); + + if (needsZlp) + submitTransfer(0); - if (needsZlp) - submitTransfer(0); + waitForOutstandingTransfers(); - waitForOutstandingTransfers(); + } catch (UsbException e) { + throw toIOException(e); + } } /** @@ -387,8 +407,8 @@ private synchronized void onCompletion(Transfer transfer) { protected void configureEndpoint() { } - private void checkIsOpen() throws IOException { + private void ensureOpen() throws IOException { if (isClosed()) - throw new IOException("endpoint output stream has been closed"); + throw new IOException("output stream has been closed"); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointStreams.java b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointStreams.java new file mode 100644 index 00000000..5e9fda43 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/EndpointStreams.java @@ -0,0 +1,44 @@ +// +// Java Does USB +// Copyright (c) 2023 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.common; + +import net.codecrete.usb.UsbException; +import net.codecrete.usb.UsbTimeoutException; + +import java.io.IOException; +import java.io.InterruptedIOException; + +/** + * Helpers shared by {@link EndpointInputStream} and {@link EndpointOutputStream}. + */ +final class EndpointStreams { + + private EndpointStreams() { + } + + /** + * Wraps a USB error in an {@link IOException} so it is surfaced through the + * {@link java.io.InputStream}/{@link java.io.OutputStream} contract. + *

+ * A transfer timeout is mapped to {@link InterruptedIOException} (java.io's "I/O timed out"). + * All other USB errors become a plain {@link IOException} with the {@link UsbException} as cause, + * which preserves the USB error code and any stall/timeout subtype for callers that inspect it. + *

+ * + * @param e the USB error + * @return the corresponding I/O exception + */ + static IOException toIOException(UsbException e) { + if (e instanceof UsbTimeoutException) { + var ioException = new InterruptedIOException(e.getMessage()); + ioException.initCause(e); + return ioException; + } + return new IOException(e.getMessage(), e); + } +} diff --git a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java index f586aa3a..4109f7b6 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/StreamTest.java @@ -86,7 +86,7 @@ void largeTransferBigChunks_succeeds() { void blockedWriter_canBeAborted() throws InterruptedException { // A writer that fills the pipe faster than it is drained eventually blocks in write(). // Aborting the outstanding transfers from another thread must terminate it promptly and - // safely (with a USB exception) rather than leave it wedged forever. + // safely (with an IOException wrapping the USB error) rather than leave it wedged forever. final var data = generateRandomBytes(1_000_000, 0x5c7f10ebL); @@ -152,7 +152,10 @@ void blockedWriter_canBeAborted() throws InterruptedException { assertFalse(writer.isAlive(), "writer thread did not terminate within 1.5 s after abort"); // It must have unwound because of the abort, not by finishing or dying some other way. - assertInstanceOf(UsbException.class, writerError.get()); + // The stream surfaces the USB error as an IOException (with the UsbException as cause). + var err = writerError.get(); + assertInstanceOf(IOException.class, err); + assertInstanceOf(UsbException.class, err.getCause()); } finally { // Restore a clean device state so subsequent tests are not affected. From 6cf6402da6e063cfb8dda1c8b229c6945c1d9d86 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 3 Jul 2026 19:46:57 +0200 Subject: [PATCH 410/433] Log of CFRunLoop exits --- .../src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java | 1 + .../java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java | 2 ++ 2 files changed, 3 insertions(+) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java index 991ce592..19f93f37 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java @@ -169,6 +169,7 @@ private void asyncIOCompletionTask(MemorySegment firstSource) { // loop forever CoreFoundation.CFRunLoopRun(); + LOG.log(WARNING, "unexpected end of CFRunLoopRun"); } /** diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java index 275ab726..b2126246 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDeviceRegistry.java @@ -21,6 +21,7 @@ import java.util.function.Consumer; import static java.lang.System.Logger.Level.INFO; +import static java.lang.System.Logger.Level.WARNING; import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.JAVA_INT; import static java.lang.foreign.ValueLayout.JAVA_LONG; @@ -103,6 +104,7 @@ protected void monitorDevices() { // loop forever CoreFoundation.CFRunLoopRun(); + LOG.log(WARNING, "unexpected end of CFRunLoopRun"); } } From 5a69e3ca484d25bd0eb3dd60c710b43c22ca13c5 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 3 Jul 2026 20:25:43 +0200 Subject: [PATCH 411/433] Avoid deadlock in async completion (Windows) --- .../usb/windows/WindowsAsyncTask.java | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java index ee06eafe..2abc2342 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java @@ -16,6 +16,7 @@ import java.util.List; import java.util.Map; +import static java.lang.System.Logger.Level.ERROR; import static java.lang.foreign.MemorySegment.NULL; import static java.lang.foreign.ValueLayout.ADDRESS; import static java.lang.foreign.ValueLayout.JAVA_INT; @@ -44,6 +45,8 @@ @SuppressWarnings("java:S6548") class WindowsAsyncTask { + private static final System.Logger LOG = System.getLogger(WindowsAsyncTask.class.getName()); + /** * Singleton instance of background task. */ @@ -154,16 +157,32 @@ synchronized void prepareForSubmission(WindowsTransfer transfer) { * * @param overlappedAddr address of OVERLAPPED struct */ - private synchronized void completeTransfer(long overlappedAddr) { - var transfer = requestsByOverlapped.remove(overlappedAddr); - if (transfer == null) - return; - - transfer.setResultCode((int) OVERLAPPED.Internal(transfer.overlapped())); - transfer.setResultSize((int) OVERLAPPED.InternalHigh(transfer.overlapped())); + private void completeTransfer(long overlappedAddr) { + WindowsTransfer transfer; + synchronized (this) { + transfer = requestsByOverlapped.remove(overlappedAddr); + if (transfer == null) + return; + + // the results must be read from the OVERLAPPED struct before it is + // returned to the pool and possibly reused by another submission + transfer.setResultCode((int) OVERLAPPED.Internal(transfer.overlapped())); + transfer.setResultSize((int) OVERLAPPED.InternalHigh(transfer.overlapped())); + + availableOverlappedStructs.add(transfer.overlapped()); + transfer.setOverlapped(null); + } - availableOverlappedStructs.add(transfer.overlapped()); - transfer.setOverlapped(null); - transfer.completion().completed(transfer); + // The completion handler must be called without holding the lock: handlers acquire + // other monitors (transfer, device), and threads submitting transfers acquire this + // task's lock while holding those monitors, so calling handlers under the lock can + // deadlock. + try { + transfer.completion().completed(transfer); + } catch (Exception e) { + // This method runs on the process-wide async IO thread. Any exception escaping + // would kill that thread and hang all async transfers for the entire library. + LOG.log(ERROR, "Unexpected exception while handling async IO completion", e); + } } } From 8f2fdb3523eed27747b43d5488bb39d756d37d90 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 3 Jul 2026 20:33:36 +0200 Subject: [PATCH 412/433] Unregister transfer on failure (Windows) --- .../codecrete/usb/windows/WindowsAsyncTask.java | 17 +++++++++++++++++ .../codecrete/usb/windows/WindowsUsbDevice.java | 12 +++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java index 2abc2342..5cc88100 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java @@ -152,6 +152,23 @@ synchronized void prepareForSubmission(WindowsTransfer transfer) { requestsByOverlapped.put(overlapped.address(), transfer); } + /** + * Undoes the registration performed by {@link #prepareForSubmission(WindowsTransfer)}. + *

+ * Must be called if the native submission of a prepared transfer fails synchronously. + * In that case, no completion packet will ever be posted for the transfer, so its map + * entry would leak and the OVERLAPPED struct would never return to the pool unless + * they are cleaned up here. + *

+ * + * @param transfer transfer whose submission failed + */ + synchronized void submissionFailed(WindowsTransfer transfer) { + requestsByOverlapped.remove(transfer.overlapped().address()); + availableOverlappedStructs.add(transfer.overlapped()); + transfer.setOverlapped(null); + } + /** * Completes the transfer by calling the completion handler. * diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java index 9c700cee..962aeab7 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java @@ -404,8 +404,10 @@ synchronized void submitControlTransfer(UsbDirection direction, UsbControlTransf if (WinUsb_ControlTransfer(errorState, intfHandle.winusbHandle, setupPacket.segment(), transfer.data(), transfer.dataSize(), NULL, transfer.overlapped()) == 0) { var err = Win.getLastError(errorState); - if (err != ERROR_IO_PENDING) + if (err != ERROR_IO_PENDING) { + asyncTask.submissionFailed(transfer); throwException(err, "submitting control transfer failed"); + } } } } @@ -422,8 +424,10 @@ synchronized void submitTransferOut(int endpointNumber, WindowsTransfer transfer if (WinUsb_WritePipe(errorState, intfHandle.winusbHandle, endpoint.endpointAddress(), transfer.data(), transfer.dataSize(), NULL, transfer.overlapped()) == 0) { var err = Win.getLastError(errorState); - if (err != ERROR_IO_PENDING) + if (err != ERROR_IO_PENDING) { + asyncTask.submissionFailed(transfer); throwException(err, "submitting transfer OUT failed"); + } } } } @@ -440,8 +444,10 @@ synchronized void submitTransferIn(int endpointNumber, WindowsTransfer transfer) if (WinUsb_ReadPipe(errorState, intfHandle.winusbHandle, endpoint.endpointAddress(), transfer.data(), transfer.dataSize(), NULL, transfer.overlapped()) == 0) { var err = Win.getLastError(errorState); - if (err != ERROR_IO_PENDING) + if (err != ERROR_IO_PENDING) { + asyncTask.submissionFailed(transfer); throwException(err, "submitting transfer IN failed"); + } } } } From 18f6f203d7b2a2e0ec38bed0e4da7e91dc94734e Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 3 Jul 2026 20:36:41 +0200 Subject: [PATCH 413/433] Unregister transfer on failure (Linux) --- .../codecrete/usb/linux/LinuxAsyncTask.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index b7b39725..6606f18f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -196,6 +196,7 @@ synchronized void submitTransfer(LinuxUsbDevice device, int endpointAddress, Usb try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); if (IO.ioctl(device.fileDescriptor(), SUBMITURB, urb, errorState) < 0) { + submissionFailed(transfer); var action = endpointAddress >= 128 ? "reading from" : "writing to"; var endpoint = endpointAddress == 0 ? "control endpoint" : String.format("endpoint %d", endpointAddress); throwLastError(errorState, "error occurred while %s %s", action, endpoint); @@ -203,6 +204,23 @@ synchronized void submitTransfer(LinuxUsbDevice device, int endpointAddress, Usb } } + /** + * Undoes the registration performed by {@link #linkToUrb(LinuxTransfer)}. + *

+ * Must be called if the {@code SUBMITURB} ioctl for a linked transfer fails. In that + * case, the kernel has not queued the URB and it will never be reaped, so its map + * entry would leak and the URB would never return to the pool unless they are + * cleaned up here. + *

+ * + * @param transfer transfer whose submission failed + */ + private void submissionFailed(LinuxTransfer transfer) { + transfersByURB.remove(transfer.urb); + availableURBs.add(transfer.urb); + transfer.urb = null; + } + private static int urbTransferType(UsbTransferType transferType) { return switch (transferType) { case BULK -> USBDEVFS_URB_TYPE_BULK(); From 4ffea1c781a983c789b8b741f0b2c194e34d5e4d Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 3 Jul 2026 21:48:44 +0200 Subject: [PATCH 414/433] Avoid deadlock on completion (Linux) --- .../codecrete/usb/linux/LinuxAsyncTask.java | 103 ++++++++++++------ 1 file changed, 71 insertions(+), 32 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index 6606f18f..510776ce 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -18,6 +18,7 @@ import java.util.List; import java.util.Map; +import static java.lang.System.Logger.Level.ERROR; import static java.lang.foreign.ValueLayout.ADDRESS; import static net.codecrete.usb.common.ForeignMemory.dereference; import static net.codecrete.usb.linux.EPoll.epoll_create1; @@ -55,6 +56,9 @@ */ @SuppressWarnings("java:S6548") class LinuxAsyncTask { + + private static final System.Logger LOG = System.getLogger(LinuxAsyncTask.class.getName()); + /** * Singleton instance of background task. */ @@ -112,26 +116,55 @@ private void asyncCompletionTask() { * @param urbPointerHolder native memory to receive the URB pointer * @param errorState native memory to receive the errno */ - private synchronized void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment errorState) { - - while (true) { - var res = IO.ioctl(fd, REAPURBNDELAY, urbPointerHolder, errorState); - if (res < 0) { - var err = Linux.getErrno(errorState); - if (err == errno.EAGAIN()) - return; // no more pending URBs - if (err == errno.ENODEV()) { - // device might have been unplugged - EPoll.removeFileDescriptor(epollFd, fd); - return; + private void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment errorState) { + + var completedTransfers = new ArrayList(); + try { + synchronized (this) { + while (true) { + var res = IO.ioctl(fd, REAPURBNDELAY, urbPointerHolder, errorState); + if (res < 0) { + var err = Linux.getErrno(errorState); + if (err == errno.EAGAIN()) + return; // no more pending URBs + if (err == errno.ENODEV()) { + // device might have been unplugged + EPoll.removeFileDescriptor(epollFd, fd); + return; + } + throwException(err, "internal error (reap URB)"); + } + + var urb = dereference(urbPointerHolder); + completedTransfers.add(getTransferWithResult(urb)); } - throwException(err, "internal error (reap URB)"); } + } finally { + // Even if reaping fails, the already reaped transfers must be completed. + completeTransfers(completedTransfers); + } + } - // call completion handler - var urb = dereference(urbPointerHolder); - var transfer = getTransferWithResult(urb); - transfer.completion().completed(transfer); + /** + * Calls the completion handlers of the specified transfers. + *

+ * Must be called without holding the lock: handlers acquire other monitors + * (transfer, device), and threads submitting transfers acquire this task's lock + * while holding those monitors, so calling handlers under the lock can deadlock. + *

+ * + * @param transfers completed transfers + */ + private void completeTransfers(List transfers) { + for (var transfer : transfers) { + try { + transfer.completion().completed(transfer); + } catch (Exception e) { + // This method also runs on the process-wide async IO thread. Any exception + // escaping would kill that thread and hang all async transfers for the + // entire library. + LOG.log(ERROR, "Unexpected exception while handling async IO completion", e); + } } } @@ -153,11 +186,13 @@ synchronized void addForAsyncIOCompletion(LinuxUsbDevice device) { * * @param device USB device */ - synchronized void removeFromAsyncIOCompletion(LinuxUsbDevice device) { + void removeFromAsyncIOCompletion(LinuxUsbDevice device) { int fd = device.fileDescriptor(); // remove file descriptor from epoll - EPoll.removeFileDescriptor(epollFd, fd); + synchronized (this) { + EPoll.removeFileDescriptor(epollFd, fd); + } // reap outstanding URBs try (var arena = Arena.ofConfined()) { @@ -167,19 +202,23 @@ synchronized void removeFromAsyncIOCompletion(LinuxUsbDevice device) { } // reclaim stale URBs - transfersByURB.entrySet().removeIf(e -> { - var urb = e.getKey(); - var isMatch = usbdevfs_urb.usercontext(urb).address() == fd; - if (isMatch) { - var transfer = e.getValue(); - transfer.urb = null; - transfer.setResultCode(ENODEV()); - transfer.setResultSize(0); - transfer.completion().completed(transfer); - availableURBs.add(urb); - } - return isMatch; - }); + var staleTransfers = new ArrayList(); + synchronized (this) { + transfersByURB.entrySet().removeIf(e -> { + var urb = e.getKey(); + var isMatch = usbdevfs_urb.usercontext(urb).address() == fd; + if (isMatch) { + var transfer = e.getValue(); + transfer.urb = null; + transfer.setResultCode(ENODEV()); + transfer.setResultSize(0); + availableURBs.add(urb); + staleTransfers.add(transfer); + } + return isMatch; + }); + } + completeTransfers(staleTransfers); } synchronized void submitTransfer(LinuxUsbDevice device, int endpointAddress, UsbTransferType transferType, LinuxTransfer transfer) { From 43c0b907f22640a62e0f0c03b985101ede6286e9 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 3 Jul 2026 22:09:05 +0200 Subject: [PATCH 415/433] Handle errors in async background task (Windows) --- .../usb/windows/WindowsAsyncTask.java | 73 ++++++++++++++++--- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java index 5cc88100..fa31dad2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsAsyncTask.java @@ -7,6 +7,7 @@ package net.codecrete.usb.windows; +import net.codecrete.usb.UsbException; import windows.win32.system.io.OVERLAPPED; import java.lang.foreign.Arena; @@ -23,6 +24,7 @@ import static java.lang.foreign.ValueLayout.JAVA_LONG; import static net.codecrete.usb.windows.Win.allocateErrorState; import static net.codecrete.usb.windows.WindowsUsbException.throwLastError; +import static windows.win32.foundation.WIN32_ERROR.ERROR_OPERATION_ABORTED; import static windows.win32.system.io.Apis.CreateIoCompletionPort; import static windows.win32.system.io.Apis.GetQueuedCompletionStatus; import static windows.win32.system.threading.Constants.INFINITE; @@ -65,9 +67,15 @@ class WindowsAsyncTask { */ private MemorySegment asyncIoCompletionPort = NULL; + /** + * Indicates that the background task has terminated due to an unrecoverable error. + */ + private boolean taskTerminated; + /** * Background task for handling asynchronous IO completions. */ + @SuppressWarnings("java:S2189") private void asyncCompletionTask() { try (var arena = Arena.ofConfined()) { @@ -78,20 +86,61 @@ private void asyncCompletionTask() { var errorState = allocateErrorState(arena); while (true) { - overlappedHolder.set(ADDRESS, 0, NULL); - completionKeyHolder.set(JAVA_LONG, 0, 0); + try { + overlappedHolder.set(ADDRESS, 0, NULL); + completionKeyHolder.set(JAVA_LONG, 0, 0); + + var res = GetQueuedCompletionStatus(errorState, asyncIoCompletionPort, numBytesHolder, + completionKeyHolder, overlappedHolder, INFINITE); + var overlappedAddr = overlappedHolder.get(JAVA_LONG, 0); - var res = GetQueuedCompletionStatus(errorState, asyncIoCompletionPort, numBytesHolder, - completionKeyHolder, overlappedHolder, INFINITE); - var overlappedAddr = overlappedHolder.get(JAVA_LONG, 0); + // A null OVERLAPPED means no completion packet was dequeued (nothing posts + // packets without an OVERLAPPED): the completion port itself has failed, + // and no further completions will ever be delivered. + if (overlappedAddr == 0) { + var success = res != 0; + throwLastError(errorState, "internal error (GetQueuedCompletionStatus, success: %s)", success); + } - if (res == 0 && overlappedAddr == 0) - throwLastError(errorState, "internal error (SetupDiGetDeviceInterfaceDetailW)"); + completeTransfer(overlappedAddr); + + } catch (Exception e) { + LOG.log(ERROR, "USB async IO thread failed and is terminating; " + + "all outstanding transfers will fail, and no further transfers are possible", e); + failAllPendingTransfers(); + return; + } + } + } + } - if (overlappedAddr == 0) - return; // registry closing? + /** + * Fails all outstanding transfers and marks this task as terminated. + *

+ * Called when the background task can no longer dispatch completions. Waiters blocked + * on the failed transfers wake up with an error result instead of hanging forever, + * and future submissions are rejected. + *

+ */ + private void failAllPendingTransfers() { + List pendingTransfers; + synchronized (this) { + taskTerminated = true; + pendingTransfers = new ArrayList<>(requestsByOverlapped.values()); + requestsByOverlapped.clear(); + availableOverlappedStructs.clear(); + for (var transfer : pendingTransfers) { + transfer.setResultCode(ERROR_OPERATION_ABORTED); + transfer.setResultSize(0); + transfer.setOverlapped(null); + } + } - completeTransfer(overlappedAddr); + for (var transfer : pendingTransfers) { + try { + transfer.completion().completed(transfer); + } catch (Exception e) { + LOG.log(ERROR, "Unexpected exception while handling async IO completion", e); } } } @@ -139,6 +188,10 @@ private void startAsyncIOTask() { * @param transfer transfer to prepare */ synchronized void prepareForSubmission(WindowsTransfer transfer) { + if (taskTerminated) + throw new UsbException("USB async IO background thread has terminated due to an unrecoverable error; " + + "USB transfers are no longer possible"); + MemorySegment overlapped; var size = availableOverlappedStructs.size(); if (size == 0) { From 8bd452546d278dc9d725a3e26c45eef8bea358af Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 3 Jul 2026 22:09:32 +0200 Subject: [PATCH 416/433] Handle errors in async background task (Linux) --- java-does-usb/jextract/linux/gen_linux.sh | 2 + .../java/net/codecrete/usb/linux/EPoll.java | 6 +- .../codecrete/usb/linux/LinuxAsyncTask.java | 72 +++++++++++++++---- .../codecrete/usb/linux/gen/errno/errno.java | 18 +++++ 4 files changed, 83 insertions(+), 15 deletions(-) diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index 35b04784..7e5eb5ec 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -10,6 +10,8 @@ $JEXTRACT --output ../../src/main/java \ --target-package net.codecrete.usb.linux.gen.errno \ --include-constant EPIPE \ --include-constant EAGAIN \ + --include-constant EBADF \ + --include-constant ECANCELED \ --include-constant EINVAL \ --include-constant ENODEV \ --include-constant EINTR \ diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java index 06c684ba..38b9d5bb 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java @@ -129,8 +129,10 @@ static void removeFileDescriptor(int epfd, int fd) { var ret = epoll_ctl(epfd, EPOLL_CTL_DEL(), fd, event, errorState); if (ret < 0) { var err = Linux.getErrno(errorState); - // ignore ENOENT as this method might be called twice when cleaning up - if (err != errno.ENOENT()) + // ignore ENOENT as this method might be called twice when cleaning up, + // and EBADF as the file descriptor might have been closed concurrently + // (closing deregisters it from epoll anyway) + if (err != errno.ENOENT() && err != errno.EBADF()) throwLastError(errorState, "internal error (epoll_ctl_del)"); } } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index 510776ce..3d6bf71f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -7,6 +7,7 @@ package net.codecrete.usb.linux; +import net.codecrete.usb.UsbException; import net.codecrete.usb.UsbTransferType; import net.codecrete.usb.linux.gen.errno.errno; import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_urb; @@ -73,6 +74,8 @@ class LinuxAsyncTask { private final Map transfersByURB = new LinkedHashMap<>(); /// file descriptor of epoll private int epollFd = -1; + /// indicates that the background task has terminated due to an unrecoverable error + private boolean taskTerminated; /** * Background task for handling asynchronous IO completions. @@ -90,25 +93,56 @@ private void asyncCompletionTask() { var events = arena.allocate(EPoll.EVENT$LAYOUT, NUM_EVENTS); while (true) { + try { + // wait for file descriptor to be ready + var res = epoll_wait(epollFd, events, NUM_EVENTS, -1, errorState); + if (res < 0) { + var err = Linux.getErrno(errorState); + if (err == EINTR()) + continue; // continue on interrupt + throwException(err, "internal error (epoll_wait)"); + } - // wait for file descriptor to be ready - var res = epoll_wait(epollFd, events, NUM_EVENTS, -1, errorState); - if (res < 0) { - var err = Linux.getErrno(errorState); - if (err == EINTR()) - continue; // continue on interrupt - throwException(err, "internal error (epoll_wait)"); - } + // for all ready file descriptors, reap URBs + for (int i = 0; i < res; i++) { + var fd = (int) EPoll.EVENT_ARRAY_DATA_FD$VH.get(events, 0L, i); + reapURBs(fd, urbPointerHolder, errorState); + } - // for all ready file descriptors, reap URBs - for (int i = 0; i < res; i++) { - var fd = (int) EPoll.EVENT_ARRAY_DATA_FD$VH.get(events, 0L, i); - reapURBs(fd, urbPointerHolder, errorState); + } catch (Exception e) { + LOG.log(ERROR, "USB async IO thread failed and is terminating; " + + "all outstanding transfers will fail, and no further transfers are possible", e); + failAllPendingTransfers(); + return; } } } } + /** + * Fails all outstanding transfers and marks this task as terminated. + *

+ * Called when the background task can no longer dispatch completions. Waiters blocked + * on the failed transfers wake up with an error result instead of hanging forever, + * and future submissions are rejected. + *

+ */ + private void failAllPendingTransfers() { + var failedTransfers = new ArrayList(); + synchronized (this) { + taskTerminated = true; + for (var transfer : transfersByURB.values()) { + transfer.urb = null; + transfer.setResultCode(errno.ECANCELED()); + transfer.setResultSize(0); + failedTransfers.add(transfer); + } + transfersByURB.clear(); + availableURBs.clear(); + } + completeTransfers(failedTransfers); + } + /** * Reap all pending URBs and handle the completed transfers. * @@ -127,12 +161,21 @@ private void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment erro var err = Linux.getErrno(errorState); if (err == errno.EAGAIN()) return; // no more pending URBs + if (err == errno.EBADF()) + return; // file descriptor was closed concurrently (deregisters it from epoll) if (err == errno.ENODEV()) { // device might have been unplugged EPoll.removeFileDescriptor(epollFd, fd); return; } - throwException(err, "internal error (reap URB)"); + // Unexpected error: stop handling this device's completions but keep + // the task alive for all other devices. The file descriptor must be + // deregistered, or epoll would report it ready again immediately, + // resulting in a hot loop. + LOG.log(ERROR, "reaping URBs for file descriptor {0} failed with errno {1}; " + + "no further transfers will complete for this device", fd, err); + EPoll.removeFileDescriptor(epollFd, fd); + return; } var urb = dereference(urbPointerHolder); @@ -222,6 +265,9 @@ void removeFromAsyncIOCompletion(LinuxUsbDevice device) { } synchronized void submitTransfer(LinuxUsbDevice device, int endpointAddress, UsbTransferType transferType, LinuxTransfer transfer) { + if (taskTerminated) + throw new UsbException("USB async IO background thread has terminated due to an unrecoverable error; " + + "USB transfers are no longer possible"); linkToUrb(transfer); var urb = transfer.urb; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java index 4ef548f3..d4397f45 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -41,6 +41,15 @@ public static int ENOENT() { public static int EINTR() { return EINTR; } + private static final int EBADF = (int)9L; + /** + * {@snippet lang=c : + * #define EBADF 9 + * } + */ + public static int EBADF() { + return EBADF; + } private static final int EAGAIN = (int)11L; /** * {@snippet lang=c : @@ -77,5 +86,14 @@ public static int EINVAL() { public static int EPIPE() { return EPIPE; } + private static final int ECANCELED = (int)125L; + /** + * {@snippet lang=c : + * #define ECANCELED 125 + * } + */ + public static int ECANCELED() { + return ECANCELED; + } } From 0c0975da7087cfeb38e629e9b2206a738756c025 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 3 Jul 2026 23:14:38 +0200 Subject: [PATCH 417/433] Robustness spec --- java-does-usb/robustness.md | 203 ++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 java-does-usb/robustness.md diff --git a/java-does-usb/robustness.md b/java-does-usb/robustness.md new file mode 100644 index 00000000..b24e0ed2 --- /dev/null +++ b/java-does-usb/robustness.md @@ -0,0 +1,203 @@ +# Concurrency and Robustness Review — Windows Implementation + +Review of the library's concurrency behavior, focused on the Windows implementation. +Threads involved: user threads, the "USB async IO" completion thread (`WindowsAsyncTask`), +and the "USB device monitor" thread (window message loop in `WindowsUsbDeviceRegistry`). + +Findings are ordered by severity. + +--- + +## 1. Potential permanent deadlock: completion handlers are invoked while holding the `WindowsAsyncTask` monitor — **FIXED (Windows & Linux)** + +> **Status:** Fixed on 2026-07-03. `WindowsAsyncTask.completeTransfer` now removes the transfer +> from the map, copies the results out of the OVERLAPPED, and recycles the OVERLAPPED under the +> lock, then invokes the completion handler after releasing it, wrapped in try/catch so a throwing +> handler cannot kill the async IO thread (partially addressing finding 3 as well). Verified with +> the full hardware test suite (59 tests, all passing). macOS was already correct. +> +> The Linux counterpart is fixed the same way: `reapURBs` now reaps and unlinks transfers under the +> task monitor, collecting them into a list, and invokes the handlers after releasing it (in a +> `finally`, so already-reaped transfers still complete if reaping throws), each wrapped in +> try/catch. `removeFromAsyncIOCompletion` is no longer method-synchronized: the epoll removal and +> the stale-URB sweep each take the lock briefly, and the ENODEV completions are invoked outside +> it. This is safe against a concurrent submit on the same device because `LinuxUsbDevice.close()` +> and `LinuxUsbDevice.submitTransfer` serialize on the device monitor. Compile-verified only (see +> finding 2's note on Linux verification). +> +> **Residual (pre-existing, Linux):** the ENODEV completions in `removeFromAsyncIOCompletion` run +> on the closing thread, which holds the *device* monitor (`LinuxUsbDevice.close()` is +> synchronized). A timed-out waiter holding a transfer monitor and calling `abortTransfers` (wants +> the device monitor) while `close()` invokes that transfer's handler (wants the transfer monitor) +> could still cycle. This inversion predates this fix and no longer involves the async IO thread, +> so it can only stall the closing thread and the waiter, not the whole library. Windows doesn't +> have it (close-triggered completions arrive via the IO thread, which holds no device monitor). + +`WindowsAsyncTask.completeTransfer()` (`WindowsAsyncTask.java:157`) is `synchronized` and calls +`transfer.completion().completed(transfer)` inside the lock. This creates a lock-order inversion +with the user-thread paths: + +- **User thread A** (sync transfer with timeout): holds the `transfer` monitor + (`synchronized (transfer)` block in `WindowsUsbDevice.transferOut`, `WindowsUsbDevice.java:338`) + and, when the timeout fires, calls `abortTransfers(...)` from inside `waitForTransfer` + (`UsbDeviceImpl.java:385`) → **wants the device monitor** (`abortTransfers` is `synchronized`, + `WindowsUsbDevice.java:482`). +- **User thread B**: holds the device monitor (`submitTransferOut` is `synchronized`, + `WindowsUsbDevice.java:413`) and calls `asyncTask.prepareForSubmission(...)` → + **wants the asyncTask monitor**. +- **Async IO thread**: holds the asyncTask monitor in `completeTransfer` and calls + `onSyncTransferCompleted` → **wants A's transfer monitor** (`UsbDeviceImpl.java:477`). + +If A's transfer completes right as its timeout expires (exactly the window in which timeouts race +with completions), the cycle A→device→B, B→asyncTask→IO thread, IO thread→transfer→A closes and is +permanent. Because `WindowsAsyncTask` is a process-wide singleton, a stuck IO thread freezes +completions for **all** devices, and every no-timeout transfer then blocks forever in +`waitNoTimeout`. The trigger is realistic: one thread doing timed transfers while another thread +submits on the same or another device. + +**Fix:** in `completeTransfer`, do the map removal / result copying / OVERLAPPED recycling under +the lock, but invoke the completion handler *after* releasing it. (The macOS `MacosAsyncTask` has +the same structural pattern and is worth the same check.) + +## 2. Failed submission leaks the transfer registration — the Windows counterpart of the macOS fix is missing — **FIXED (Windows & Linux)** + +> **Status:** Fixed on 2026-07-03. `WindowsAsyncTask.submissionFailed(transfer)` now undoes the +> registration when a `WinUsb_*` call fails synchronously: it removes the map entry, returns the +> OVERLAPPED to the pool, and clears the transfer's reference (safe because Win32 posts no +> completion packet for a synchronous failure). Called from the error paths of all three submit +> methods, mirroring the macOS fix. Verified with the full hardware test suite (59 tests, all +> passing). +> +> The same leak was discovered and fixed in Linux: `LinuxAsyncTask.submitTransfer` called +> `linkToUrb` (registers the URB→transfer mapping and takes a URB from the pool) and then threw on +> `SUBMITURB` ioctl failure without cleanup. A private `submissionFailed(transfer)` (safe to call +> under the already-held task monitor) now unlinks the transfer and recycles the URB — safe +> because a URB rejected by the ioctl is never queued and will never be reaped. Compile-verified +> only; the hardware test suite was run on Windows and does not exercise the Linux code path. + +Commit `60a47af` ("Deregister transfer on exception (macOS)") added +`asyncTask.submissionFailed(transfer)` when an async submission fails synchronously. Windows has +the identical bug, unfixed: in `submitControlTransfer`, `submitTransferOut`, and `submitTransferIn` +(`WindowsUsbDevice.java:404–408, 422–426, 440–444`), `asyncTask.prepareForSubmission(transfer)` +registers the OVERLAPPED→transfer mapping and takes an OVERLAPPED from the pool; if `WinUsb_*` then +fails with anything other than `ERROR_IO_PENDING`, the exception path leaves the entry in +`requestsByOverlapped` forever and the OVERLAPPED never returns to `availableOverlappedStructs`. + +Synchronous failures are the *normal* case right after an unplug, so an application that keeps +retrying on a hot-unplugged device leaks an OVERLAPPED, a map entry, and the pinned transfer buffer +per attempt. + +**Fix:** add the same `submissionFailed()` cleanup to `WindowsAsyncTask` and call it from the three +submit methods' error paths. + +## 3. The singleton async IO thread can die, silently hanging the whole library — **FIXED (Windows & Linux)** + +> **Status:** Fixed on 2026-07-03 (handler-exception protection was already added with finding 1; +> macOS needed nothing — its upcall is fully wrapped and a run loop exit is logged). +> +> **Windows:** the completion loop body is wrapped in try/catch. Any exception — including a +> `GetQueuedCompletionStatus` failure with a null OVERLAPPED, whose error text is also fixed — +> now logs an ERROR, fails every transfer in `requestsByOverlapped` with +> `ERROR_OPERATION_ABORTED` (handlers invoked outside the lock, individually guarded), marks the +> task terminated, and exits. `prepareForSubmission` rejects new submissions with a clear +> `UsbException` once terminated, so callers fail fast instead of hanging in `waitNoTimeout`. +> The silent `return` on a successful dequeue with null OVERLAPPED ("registry closing?") was +> speculative — nothing posts such packets — and now goes through the same fatal path. +> +> **Linux:** same structure — the epoll loop body is wrapped; a non-EINTR `epoll_wait` failure +> (or an escaping exception) fails all pending transfers with `ECANCELED`, marks the task +> terminated, and exits; `submitTransfer` then rejects new work. In addition, two per-device reap +> failures no longer kill the thread: `EBADF` is treated as a benign race (the fd was closed +> concurrently — reachable from an ordinary `close()` while the event thread already holds a +> ready event) and any other unexpected reap errno degrades only that device (log, deregister +> from epoll to avoid a hot loop, continue serving other devices). +> `EPoll.removeFileDescriptor` now tolerates `EBADF` like `ENOENT`. `EBADF`/`ECANCELED` were +> added to the committed jextract errno bindings by hand (asm-generic values, valid on +> x64/ARM64) and to `gen_linux.sh` for the next regeneration on a Linux machine. +> +> Verified with the full hardware test suite on Windows (59 tests, all passing); the fatal paths +> themselves and the Linux changes are verified by inspection/compilation only. + +Two ways `asyncCompletionTask()` (`WindowsAsyncTask.java:68`) can terminate: + +- `GetQueuedCompletionStatus` fails with a null OVERLAPPED → `throwLastError` (line 86) kills the + thread. +- Any `RuntimeException` escaping a completion handler — handlers run inline in this thread (see + finding 1), so a bug or unexpected state in stream/user completion code is fatal to the loop. + +There is no restart, and the failure mode is nasty: subsequent transfers submit fine but never +complete, so callers block forever in `waitNoTimeout` (unbounded) and +`flush()`/`waitForAvailableTransfer` (also unbounded by design). + +**Fix:** wrap the loop body in a catch-log-continue (a failed handler must not stop dispatching +other devices' completions) and reserve thread death for truly unrecoverable port errors — ideally +then failing all pending transfers in `requestsByOverlapped` so waiters wake up. + +Minor: the error text at line 86 says "SetupDiGetDeviceInterfaceDetailW" — a copy-paste from +elsewhere. + +## 4. `claimInterfaceSynchronized` leaves inconsistent state on error paths + +In `WindowsUsbDevice.java:215–217`, `firstIntfHandle.deviceHandle` and `winusbHandle` are assigned +**before** `asyncTask.addDevice(deviceHandle)`. If `addDevice` throws (CreateIoCompletionPort +failure), the catch closes the device handle but leaves both fields set — a later claim sees +`deviceHandle != null`, skips reopening, and submits I/O on a closed handle. + +**Fix:** assign the fields only after `addDevice` succeeds (or null them in the catch, and +`WinUsb_Free` the interface handle too). + +Related: when claiming an associated interface (e.g. interface 1 of a function starting at 0) opens +the device and then `WinUsb_GetAssociatedInterface` fails (line 228), the exception propagates with +the device left open but `deviceOpenCount == 0` and no interface claimed. Since `close()` only +releases *claimed* interfaces, that device handle (still registered with the completion port) leaks +until process exit. + +## 5. Visibility: shared flags are neither volatile nor consistently synchronized + +- `showAsOpen`: written under the device monitor, but `isOpened()` (`WindowsUsbDevice.java:114`) + reads it unlocked — `checkIsOpen`/`checkIsClosed` can act on stale state on a different thread. +- `UsbDeviceImpl.connected`: written by the monitor thread in `disconnect()`, read unlocked via + `isConnected()` and `checkIsClosed`. +- `UsbDeviceRegistry.onDeviceConnectedHandler` / `onDeviceDisconnectedHandler`: set by the app + thread, read by the monitor thread with no happens-before edge — a handler registered after + `start()` may never be seen. + +All are cheap to fix with `volatile`. Practical impact is low (stale reads, not corruption), but +`isConnected()` returning `true` long after unplug is user-visible. + +## 6. Minor observations + +- **Data race on result fields in the timeout path**: `completeTransfer` writes + `resultCode`/`resultSize` before taking the transfer monitor, while the timed-out waiter reads + `transfer.resultCode()` holding it (`UsbDeviceImpl.java:384`). Consequences are benign (a + redundant `WinUsb_AbortPipe`, or a timeout exception despite late data — inherent to the race + anyway), but it's formally a data race. +- **User callbacks run on the monitor thread inside the window procedure** + (`WindowsUsbDeviceRegistry.java:326–347`). A slow `onDeviceConnected`/`onDeviceDisconnected` + handler stalls all further device notifications (and the `disconnect()` cleanup of other + devices). Exceptions are caught, which is good; the latency constraint is worth documenting if it + isn't already. +- `completeTransfer` dispatches all devices through one lock and one thread, so one slow handler + delays every device's completions — currently fine since internal handlers are cheap queue + operations, but it compounds finding 1's argument for invoking handlers outside the lock. + +## What holds up well + +The overall unplug/teardown story is sound: closing the WinUSB/file handles cancels pending I/O, +cancelled I/O still posts completion packets to the port, so blocked waiters wake with an error +result; the stream teardown paths (`close()`, `collectOutstandingTransfers`, abort-completion wait) +are all deadline-bounded so a genuinely lost completion degrades to a logged warning rather than a +hang — only the *non*-teardown unbounded waits remain exposed, and only via finding 3. + +The `claimInterface` retry loop sleeps outside the device monitor, interrupts are deferred rather +than swallowed, `transfer.wait()` correctly releases the transfer monitor while submissions on +other threads proceed, and the copy-on-write device list with the case-insensitive Windows override +applied to both add and remove paths is correct. The timed-out-transfer buffers using +`Arena.ofAuto()` so an abandoned transfer can't have its buffer freed under a late completion is a +well-handled detail. + +## Recommended priority + +Findings 1, 2 and 3 are fixed on all platforms (see above). Next up: finding 4 +(`claimInterfaceSynchronized` error-path state), then the `volatile` flags of finding 5. +The Linux fixes for findings 1–3 still need a hardware test run on a Linux machine. From 90fba1878eed3b643e4023a4cbc7759eb6a86cfe Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Mon, 6 Jul 2026 17:10:07 +0200 Subject: [PATCH 418/433] Better error handling in claim interface (Windows) --- java-does-usb/robustness.md | 352 +++++++++++++++--- .../usb/windows/WindowsUsbDevice.java | 39 +- 2 files changed, 332 insertions(+), 59 deletions(-) diff --git a/java-does-usb/robustness.md b/java-does-usb/robustness.md index b24e0ed2..545c0b8a 100644 --- a/java-does-usb/robustness.md +++ b/java-does-usb/robustness.md @@ -1,20 +1,39 @@ -# Concurrency and Robustness Review — Windows Implementation +# Concurrency and Robustness Review -Review of the library's concurrency behavior, focused on the Windows implementation. -Threads involved: user threads, the "USB async IO" completion thread (`WindowsAsyncTask`), -and the "USB device monitor" thread (window message loop in `WindowsUsbDeviceRegistry`). +Merged from two parallel reviews: one focused on the **Windows** implementation (with the +resulting fixes ported to **Linux**), one focused on the **macOS** implementation (with several +fixes landing in the shared common classes, benefiting all three platforms). -Findings are ordered by severity. +Threads involved: + +- user threads submitting transfers and blocking on results, +- the "USB async IO" completion thread — I/O completion port loop on Windows + (`WindowsAsyncTask`), epoll loop on Linux (`LinuxAsyncTask`), CFRunLoop on macOS + (`MacosAsyncTask`); a **process-wide singleton** on every platform, +- the "USB device monitor" thread — window message loop (`WindowsUsbDeviceRegistry`), + udev monitoring (Linux), IOKit notification run loop (`MacosUsbDeviceRegistry`). + +Files reviewed on the macOS side: `MacosUsbDevice`, `MacosAsyncTask`, `MacosUsbDeviceRegistry`, +`MacosEndpointInputStream` / `MacosEndpointOutputStream`, `MacosTransfer`, `IoKitHelper`, and the +shared base classes `EndpointInputStream`, `EndpointOutputStream`, `Transfer`, `UsbDeviceImpl`, +`UsbDeviceRegistry`. + +Findings are ordered by severity. Fixed findings keep their status note followed by the original +description. --- -## 1. Potential permanent deadlock: completion handlers are invoked while holding the `WindowsAsyncTask` monitor — **FIXED (Windows & Linux)** +## 1. Potential permanent deadlock: completion handlers invoked while holding the `WindowsAsyncTask` monitor — **FIXED (Windows & Linux; macOS was already correct)** > **Status:** Fixed on 2026-07-03. `WindowsAsyncTask.completeTransfer` now removes the transfer > from the map, copies the results out of the OVERLAPPED, and recycles the OVERLAPPED under the > lock, then invokes the completion handler after releasing it, wrapped in try/catch so a throwing > handler cannot kill the async IO thread (partially addressing finding 3 as well). Verified with -> the full hardware test suite (59 tests, all passing). macOS was already correct. +> the full hardware test suite (59 tests, all passing). +> +> macOS was already correct: `completed()` is invoked outside the `asyncTask` monitor +> (`MacosAsyncTask.java:197-203`), avoiding the lock cycle with the submit path +> (`device → asyncTask → transfer`). > > The Linux counterpart is fixed the same way: `reapURBs` now reaps and unlinks transfers under the > task monitor, collecting them into a list, and invokes the handlers after releasing it (in a @@ -56,44 +75,66 @@ completions for **all** devices, and every no-timeout transfer then blocks forev submits on the same or another device. **Fix:** in `completeTransfer`, do the map removal / result copying / OVERLAPPED recycling under -the lock, but invoke the completion handler *after* releasing it. (The macOS `MacosAsyncTask` has -the same structural pattern and is worth the same check.) - -## 2. Failed submission leaks the transfer registration — the Windows counterpart of the macOS fix is missing — **FIXED (Windows & Linux)** - -> **Status:** Fixed on 2026-07-03. `WindowsAsyncTask.submissionFailed(transfer)` now undoes the -> registration when a `WinUsb_*` call fails synchronously: it removes the map entry, returns the -> OVERLAPPED to the pool, and clears the transfer's reference (safe because Win32 posts no -> completion packet for a synchronous failure). Called from the error paths of all three submit -> methods, mirroring the macOS fix. Verified with the full hardware test suite (59 tests, all -> passing). +the lock, but invoke the completion handler *after* releasing it. + +## 2. Failed submission leaks the transfer registration — **FIXED (macOS, Windows & Linux)** + +Both reviews found the same bug independently, on different platforms. The macOS fix landed first +(commit `60a47af`, "Deregister transfer on exception (macOS)"); the Windows and Linux counterparts +followed. + +> **Status (macOS):** Fixed. `MacosAsyncTask` now has a `submissionFailed` counterpart to +> `prepareForSubmission` that removes the transfer's map entry. Each of the three submit methods +> (`submitTransferIn`, `submitTransferOut`, `submitControlTransfer`) calls it in the native-error +> path, before `throwException`, so a failed submission no longer leaks an entry. Removal (rather +> than the alternative of registering only after a successful native call) was chosen deliberately: +> the completion callback runs on the async-IO run-loop thread and could otherwise race ahead of a +> post-success registration, find no map entry, and hang the waiting thread. Removing only on +> failure is race-free because a failed native submission produces no completion callback. +> +> **Status (Windows):** Fixed on 2026-07-03. `WindowsAsyncTask.submissionFailed(transfer)` now +> undoes the registration when a `WinUsb_*` call fails synchronously: it removes the map entry, +> returns the OVERLAPPED to the pool, and clears the transfer's reference (safe because Win32 +> posts no completion packet for a synchronous failure). Called from the error paths of all three +> submit methods, mirroring the macOS fix. Verified with the full hardware test suite (59 tests, +> all passing). > -> The same leak was discovered and fixed in Linux: `LinuxAsyncTask.submitTransfer` called -> `linkToUrb` (registers the URB→transfer mapping and takes a URB from the pool) and then threw on -> `SUBMITURB` ioctl failure without cleanup. A private `submissionFailed(transfer)` (safe to call -> under the already-held task monitor) now unlinks the transfer and recycles the URB — safe -> because a URB rejected by the ioctl is never queued and will never be reaped. Compile-verified -> only; the hardware test suite was run on Windows and does not exercise the Linux code path. - -Commit `60a47af` ("Deregister transfer on exception (macOS)") added -`asyncTask.submissionFailed(transfer)` when an async submission fails synchronously. Windows has -the identical bug, unfixed: in `submitControlTransfer`, `submitTransferOut`, and `submitTransferIn` +> **Status (Linux):** the same leak was discovered and fixed: `LinuxAsyncTask.submitTransfer` +> called `linkToUrb` (registers the URB→transfer mapping and takes a URB from the pool) and then +> threw on `SUBMITURB` ioctl failure without cleanup. A private `submissionFailed(transfer)` (safe +> to call under the already-held task monitor) now unlinks the transfer and recycles the URB — +> safe because a URB rejected by the ioctl is never queued and will never be reaped. +> Compile-verified only; the hardware test suite was run on Windows and does not exercise the +> Linux code path. + +The original descriptions follow. + +**macOS:** `prepareForSubmission` (`MacosAsyncTask.java:179-184`) registers the transfer in +the map *before* the native `ReadPipeAsync` / `WritePipeAsync` / `DeviceRequestAsync` call. If +that native call returns an error (`MacosUsbDevice.java:522`, `552`, `571`), the method throws and +the map entry is never removed (no completion will fire for it). Each failed submission +permanently leaks one entry in the singleton's map. Not fatal, but unbounded over a long-running +process that hits repeated submit failures. + +**Windows:** in `submitControlTransfer`, `submitTransferOut`, and `submitTransferIn` (`WindowsUsbDevice.java:404–408, 422–426, 440–444`), `asyncTask.prepareForSubmission(transfer)` registers the OVERLAPPED→transfer mapping and takes an OVERLAPPED from the pool; if `WinUsb_*` then fails with anything other than `ERROR_IO_PENDING`, the exception path leaves the entry in `requestsByOverlapped` forever and the OVERLAPPED never returns to `availableOverlappedStructs`. - Synchronous failures are the *normal* case right after an unplug, so an application that keeps retrying on a hot-unplugged device leaks an OVERLAPPED, a map entry, and the pinned transfer buffer per attempt. -**Fix:** add the same `submissionFailed()` cleanup to `WindowsAsyncTask` and call it from the three -submit methods' error paths. - -## 3. The singleton async IO thread can die, silently hanging the whole library — **FIXED (Windows & Linux)** +## 3. The singleton async IO thread can die, silently hanging the whole library — **FIXED (all platforms)** -> **Status:** Fixed on 2026-07-03 (handler-exception protection was already added with finding 1; -> macOS needed nothing — its upcall is fully wrapped and a run loop exit is logged). +> **Status:** Fixed on 2026-07-03 (handler-exception protection was already added with finding 1). +> +> **macOS:** `MacosAsyncTask.asyncIOCompleted` now null-checks the map lookup (logging and +> ignoring a completion for an unknown transfer ID) and wraps the whole callback body in a +> `try/catch` that logs and swallows, so a bad completion can no longer escape into `CFRunLoopRun` +> and take down the shared IO thread. In addition, an unexpected `CFRunLoopRun` exit is now logged +> (WARNING) in both `MacosAsyncTask.asyncIOCompletionTask` and +> `MacosUsbDeviceRegistry.monitorDevices`, so a dead run loop is observable instead of silent. > > **Windows:** the completion loop body is wrapped in try/catch. Any exception — including a > `GetQueuedCompletionStatus` failure with a null OVERLAPPED, whose error text is also fixed — @@ -118,7 +159,9 @@ submit methods' error paths. > Verified with the full hardware test suite on Windows (59 tests, all passing); the fatal paths > themselves and the Linux changes are verified by inspection/compilation only. -Two ways `asyncCompletionTask()` (`WindowsAsyncTask.java:68`) can terminate: +The original descriptions follow. + +**Windows:** two ways `asyncCompletionTask()` (`WindowsAsyncTask.java:68`) can terminate: - `GetQueuedCompletionStatus` fails with a null OVERLAPPED → `throwLastError` (line 86) kills the thread. @@ -129,14 +172,155 @@ There is no restart, and the failure mode is nasty: subsequent transfers submit complete, so callers block forever in `waitNoTimeout` (unbounded) and `flush()`/`waitForAvailableTransfer` (also unbounded by design). -**Fix:** wrap the loop body in a catch-log-continue (a failed handler must not stop dispatching -other devices' completions) and reserve thread death for truly unrecoverable port errors — ideally -then failing all pending transfers in `requestsByOverlapped` so waiters wake up. +Minor: the error text at line 86 said "SetupDiGetDeviceInterfaceDetailW" — a copy-paste from +elsewhere (fixed along with the above). + +**macOS:** `MacosAsyncTask.java:194-204`: + +```java +transfer = transfersById.remove(refcon.address()); +transfer.setResultCode(result); // NPE if remove() returned null +``` + +There was no null check and no `try/catch` around the whole callback. If a completion ever fires +for an ID not in the map — a double completion (e.g. a transfer that both times out/aborts *and* +completes), a spurious callback, or a bug in ID bookkeeping — this throws inside an upcall from +`CFRunLoopRun`. Because `MacosAsyncTask` is a **process-wide singleton** servicing *every* device +and interface, losing that thread hangs all outstanding and future async transfers for the whole +library, not just one device. + +Related (originally a separate low-severity note): `MacosUsbDeviceRegistry.monitorDevices` and +`MacosAsyncTask.asyncIOCompletionTask` both call `CFRunLoopRun()` and assumed it never returns. If +it ever does (e.g. all sources removed), the thread exits silently and device monitoring / async +IO stops with no signal to the application. Both sites now log a warning. + +## 4. Teardown waits (`collectOutstandingTransfers` / output-stream drain) could hang forever — **FIXED (all platforms, common code)** + +> **Status:** Fixed. The teardown waits are now bounded. `EndpointInputStream.collectOutstandingTransfers` +> and a dedicated bounded drain in `EndpointOutputStream.close()` poll with a shared 1 s +> deadline (`TEARDOWN_TIMEOUT_MS`) instead of blocking on `take()`. When the deadline expires +> with transfers still outstanding, the remaining transfers are abandoned and a warning is +> logged rather than freezing the application thread. Abandoning is safe because buffers come +> from an auto arena and survive a late completion writing into them. Interruption during the +> drain is deferred (no busy-spin) and re-asserted afterwards. The normal `read()`/`write()` +> data path and the public `flush()` keep their unbounded, correct blocking-stream semantics. +> The fix lives in the shared common base classes, so all three platforms benefit. + +The original description (from the macOS review) follows. + +`EndpointInputStream.java:215-223` and `EndpointOutputStream.java:194-213` both +block until *every* outstanding transfer reports back: + +```java +while (numOutstandingTransfers > 0) + waitForCompletedTransfer(); // completedTransferQueue.take() +``` + +The entire teardown correctness rests on the assumption that **every submitted +transfer eventually produces exactly one completion callback.** In the normal +path this holds (`AbortPipe` / `USBInterfaceClose` abort pending pipes and +deliver completions). But there are windows where it may not: + +- In `close()` (`EndpointInputStream.java:112-124`), if `device.abortTransfers` + throws (device already disconnected), the abort is silently swallowed and we + proceed straight to `collectOutstandingTransfers()`. We then rely entirely on + the monitor thread's `device.close()` having already aborted the same pipes. + If that hasn't happened yet, or if a completion is lost, `take()` blocks with + no timeout and no interruptibility — a permanent hang of the application + thread. +- The ordering guarantee in `MacosUsbDevice.close()` (abort → then post + source-removal message) only holds if `USBInterfaceClose` has *signaled* the + abort completions to the run loop before it returns. If IOKit signals them + slightly later, the source-removal message can be processed first and the + completions dropped → hang. + +## 5. Interruption caused a busy-spin, and transfers are effectively non-interruptible — **FIXED (all platforms, common code)** + +> **Status:** Fixed. Every blocking wait now uses a deferred-interrupt pattern. A caught +> `InterruptedException` sets a local `wasInterrupted` flag instead of re-asserting +> `Thread.currentThread().interrupt()` inside the loop; the flag is re-asserted only +> once the wait returns. Because the interrupt flag is no longer set *during* the loop, +> the blocking primitive (`queue.take()` / `transfer.wait()` / `Thread.sleep()`) blocks +> normally on the next iteration instead of throwing immediately — eliminating the 100% +> CPU spin. Applied to all six sites: `EndpointInputStream.waitForCompletedTransfer`, +> `EndpointOutputStream.waitForAvailableTransfer`, `UsbDeviceImpl.waitNoTimeout` and +> `waitWithTimeout`, plus the retry-backoff sleeps in `MacosUsbDevice.open()` and +> `WindowsUsbDevice.claimInterface()`. As part of this, `waitWithTimeout` now recomputes +> its remaining timeout on both the normal and interrupted paths, so it stays bounded by +> the original expiration and its timed-out return value stays accurate. +> +> Transfers remain intentionally **non-interruptible** (interruption is deferred, not +> turned into cancellation): a blocked USB call still returns only when the transfer +> completes, but the interrupt is preserved and observed afterwards. True cancellation +> was rejected because the only abort primitive (`AbortPipe`) tears down the whole +> endpoint, and the two call sites have incompatible exception vocabularies (checked +> `IOException` on the streams vs. unchecked `UsbException` on control transfers). + +The original description follows. + +Every blocking wait swallowed `InterruptedException`, re-asserted the interrupt +flag, and looped: + +- `waitForCompletedTransfer` — `EndpointInputStream.java:194-204` +- `waitForAvailableTransfer` — `EndpointOutputStream.java:224-242` +- `waitNoTimeout` / `waitWithTimeout` — `UsbDeviceImpl.java:390-418` + +Once the interrupt flag is set, the next `queue.take()` / `transfer.wait()` +throws `InterruptedException` **immediately**, which is caught, re-sets the +flag, and loops again. If the awaited completion hasn't arrived yet, this spins +at 100% CPU until it does. For `waitNoTimeout` with an unplugged device that +never delivers a completion, it spins indefinitely. Beyond the CPU cost, the +practical effect is that a blocked USB call cannot be cancelled by interrupting +the thread — the interrupt is neither honored nor cleanly deferred. + +## 6. `waitWithTimeout` post-timeout `waitNoTimeout` assumed a completion still comes — **FIXED (all platforms, common code)** + +> **Status:** Fixed. The post-timeout drain is now bounded. After a timeout, `UsbDeviceImpl.waitForTransfer` +> aborts the transfer and then waits for the abort's completion via `waitWithTimeout` with a fixed +> `ABORT_COMPLETION_TIMEOUT_MS` (1 s) bound instead of the unbounded `waitNoTimeout`. If the abort's +> completion never arrives (device vanished such that neither the transfer nor the abort yields a +> callback), the transfer is abandoned and a warning is logged; the method still throws the same +> `UsbTimeoutException`, so the user-facing outcome is unchanged. The no-timeout path +> (`timeout <= 0`) intentionally keeps its unbounded `waitNoTimeout` — a caller that asked for no +> timeout has opted into blocking. +> +> Abandoning is only memory-safe because the buffers that can reach this path — those in the +> synchronous `transferIn` / `transferOut` on all three platforms — were switched from +> `Arena.ofConfined()` to `Arena.ofAuto()`, so a late completion writing into the buffer can never +> touch freed memory. Control-transfer buffers stay confined: they only ever use the no-timeout path +> and so cannot reach the drain. -Minor: the error text at line 86 says "SetupDiGetDeviceInterfaceDetailW" — a copy-paste from -elsewhere. +The original description follows. -## 4. `claimInterfaceSynchronized` leaves inconsistent state on error paths +`UsbDeviceImpl.java:368-388`: on timeout, `abortTransfers` is called and then +`waitNoTimeout(transfer)` blocks for the abort completion. This is correct *if* +the abort produces a completion. If the device vanished such that neither the +timeout nor the abort yields a callback, `waitNoTimeout` hangs (same root cause +as finding 4). The timeout feature gives users an expectation of bounded blocking +that the post-timeout `waitNoTimeout` quietly breaks. + +## 7. `claimInterfaceSynchronized` leaves inconsistent state on error paths (Windows) — **FIXED** + +> **Status:** Fixed on 2026-07-06. Both error paths in `claimInterfaceSynchronized` are addressed: +> +> - The device-open block now commits `firstIntfHandle.deviceHandle` / `winusbHandle` only *after* +> the last fallible operation (`asyncTask.addDevice`) has succeeded, so no error path can leave +> the fields pointing at a closed handle. The catch block cleans up purely local state — and now +> also frees the WinUSB interface handle (previously leaked) before closing the device handle, +> mirroring the cleanup order of `releaseInterface`. Closing the handle is a complete undo: +> `addDevice` can only fail if `CreateIoCompletionPort` itself failed, in which case the handle +> was never associated with the completion port, so no stray completion packets can result. +> - The associated-interface path is wrapped so that a `WinUsb_GetAssociatedInterface` failure +> undoes the device open if (and only if) this call performed it, tracked by a local +> `deviceOpenedHere` flag: free the first interface handle, close the device handle, null both +> fields, rethrow. If the device was already open on entry, nothing is undone — the handle is +> legitimately in use by a previously claimed interface, and no state was mutated. +> +> Compile-verified only: the error paths themselves (`CreateIoCompletionPort` / +> `WinUsb_GetAssociatedInterface` failures) require injected native failures and are verified by +> inspection. A hardware regression run on Windows is pending (see note at the end). + +The original description follows. In `WindowsUsbDevice.java:215–217`, `firstIntfHandle.deviceHandle` and `winusbHandle` are assigned **before** `asyncTask.addDevice(deviceHandle)`. If `addDevice` throws (CreateIoCompletionPort @@ -152,7 +336,11 @@ the device left open but `deviceOpenCount == 0` and no interface claimed. Since releases *claimed* interfaces, that device handle (still registered with the completion port) leaks until process exit. -## 5. Visibility: shared flags are neither volatile nor consistently synchronized +--- + +## Open findings + +## 8. Visibility: shared flags are neither volatile nor consistently synchronized - `showAsOpen`: written under the device monitor, but `isOpened()` (`WindowsUsbDevice.java:114`) reads it unlocked — `checkIsOpen`/`checkIsClosed` can act on stale state on a different thread. @@ -165,9 +353,30 @@ until process exit. All are cheap to fix with `volatile`. Practical impact is low (stale reads, not corruption), but `isConnected()` returning `true` long after unplug is user-visible. -## 6. Minor observations +## 9. `messagePort` (remote) creation is unchecked (macOS) + +`MacosAsyncTask.java:135`: `CFMessagePortCreateRemote` can return NULL (e.g. a +race where the local port's run-loop source isn't serviced yet). +`removeEventSource` would then send on a NULL port and the event source would +never be removed — a slow leak of run-loop sources. Worth asserting non-null at +creation. + +## 10. Magic-number reinterpret in `loadDescription` (macOS) + +`MacosUsbDevice.java:194`: `dereference(descPtrHolder).reinterpret(999999)` +before re-slicing to `totalLength()`. It's bounded immediately afterward so it's +safe in practice, but the arbitrary size is fragile if a malformed descriptor +ever reports a `totalLength` beyond the real buffer. + +## 11. `open()` holds the device monitor across up to 4×90 ms sleeps (macOS) + +`MacosUsbDevice.java:103-135` is `synchronized` and sleeps while retrying +`USBDeviceOpenSeize`. Any other thread calling a synchronized method on that +device blocks for up to ~360 ms. Minor, and only during open, but worth noting. -- **Data race on result fields in the timeout path**: `completeTransfer` writes +## 12. Minor observations + +- **Data race on result fields in the timeout path** (Windows): `completeTransfer` writes `resultCode`/`resultSize` before taking the transfer monitor, while the timed-out waiter reads `transfer.resultCode()` holding it (`UsbDeviceImpl.java:384`). Consequences are benign (a redundant `WinUsb_AbortPipe`, or a timeout exception despite late data — inherent to the race @@ -176,18 +385,22 @@ All are cheap to fix with `volatile`. Practical impact is low (stale reads, not (`WindowsUsbDeviceRegistry.java:326–347`). A slow `onDeviceConnected`/`onDeviceDisconnected` handler stalls all further device notifications (and the `disconnect()` cleanup of other devices). Exceptions are caught, which is good; the latency constraint is worth documenting if it - isn't already. + isn't already. The same applies to the macOS and Linux monitor threads. - `completeTransfer` dispatches all devices through one lock and one thread, so one slow handler delays every device's completions — currently fine since internal handlers are cheap queue operations, but it compounds finding 1's argument for invoking handlers outside the lock. +--- + ## What holds up well +### Windows / Linux + The overall unplug/teardown story is sound: closing the WinUSB/file handles cancels pending I/O, cancelled I/O still posts completion packets to the port, so blocked waiters wake with an error result; the stream teardown paths (`close()`, `collectOutstandingTransfers`, abort-completion wait) are all deadline-bounded so a genuinely lost completion degrades to a logged warning rather than a -hang — only the *non*-teardown unbounded waits remain exposed, and only via finding 3. +hang. The `claimInterface` retry loop sleeps outside the device monitor, interrupts are deferred rather than swallowed, `transfer.wait()` correctly releases the transfer monitor while submissions on @@ -196,8 +409,47 @@ applied to both add and remove paths is correct. The timed-out-transfer buffers `Arena.ofAuto()` so an abandoned transfer can't have its buffer freed under a late completion is a well-handled detail. +### macOS + +- **`synchronized` on the device** serializes submission against `close()` / + `disconnect()`, so native interface/device pointers can't be released out + from under a submitting thread (as the class Javadoc promises). +- **The wait/notify guard is correct**: `asyncIOCompleted` sets `resultSize` / + `resultCode` *before* calling the completion handler, and `waitNoTimeout` + loops on `resultSize() == -1` under the `transfer` monitor. A completion that + races ahead of `wait()` is not lost + (`MacosUsbDevice.java:407-410`, `UsbDeviceImpl.java:391-400`). +- **`completed()` is invoked outside the `asyncTask` monitor** + (`MacosAsyncTask.java:197-203`), avoiding a lock cycle with the submit path + (`device → asyncTask → transfer`). +- **Deferred event-source removal via the message port** + (`MacosAsyncTask.removeEventSource`) is a deliberate and correct move to keep + completion callbacks ordered ahead of source removal on the run-loop thread. +- **Stream buffers use `Arena.ofAuto()`** (`EndpointInputStream.java:66`), so a + completion callback that writes into a buffer *after* the stream/device is + gone won't touch freed memory — it stays alive until GC. Good defensive + choice given the async model. + +### Concurrency model — verdict (macOS) + +The core two-thread interaction (app thread submitting/waiting vs. the run-loop +IO thread completing) is **sound**: lock ordering is consistent, there's no +reverse-order acquisition, the notify guard is correct, and buffer lifetime is +handled via `ofAuto`. Disconnect-during-blocking-transfer works *as long as +IOKit delivers a completion for every aborted transfer* — and that single +assumption was the load-bearing one. Findings 3, 4, and 6 were all facets of +"what happens when a completion is late, duplicated, or missing," which is +precisely the unplug scenario; all three are now hardened (null-safe callback, +bounded teardown waits, and treating a missing completion as a recoverable +timeout rather than an infinite block). + +--- + ## Recommended priority -Findings 1, 2 and 3 are fixed on all platforms (see above). Next up: finding 4 -(`claimInterfaceSynchronized` error-path state), then the `volatile` flags of finding 5. -The Linux fixes for findings 1–3 still need a hardware test run on a Linux machine. +Findings 1–7 are fixed (see above). Next up: the `volatile` flags of finding 8 and the +macOS message-port null check of finding 9. Findings 10–12 are low-priority +robustness notes. + +The Linux fixes for findings 1–3 still need a hardware test run on a Linux machine, and the +finding 7 fix a hardware regression run on Windows. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java index 962aeab7..a69e3f7f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java @@ -179,6 +179,8 @@ private synchronized boolean claimInterfaceSynchronized(int interfaceNumber) { if (intfHandle.firstInterfaceNumber != interfaceNumber) firstIntfHandle = getInterfaceHandle(intfHandle.firstInterfaceNumber); + var deviceOpenedHere = false; + try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); @@ -199,6 +201,7 @@ private synchronized boolean claimInterfaceSynchronized(int interfaceNumber) { if (Win.isInvalidHandle(deviceHandle)) throwLastError(errorState, "claiming interface failed (opening USB device %s failed)", devicePath); + MemorySegment interfaceHandle = null; try { // open first interface var interfaceHandleHolder = arena.allocate(ADDRESS); @@ -210,26 +213,44 @@ private synchronized boolean claimInterfaceSynchronized(int interfaceNumber) { ); throwLastError(errorState, "claiming interface failed"); } - var interfaceHandle = dereference(interfaceHandleHolder); + interfaceHandle = dereference(interfaceHandleHolder); + + asyncTask.addDevice(deviceHandle); + // Assign handles only after all fallible operations have succeeded. + // Otherwise a later claim would see them and submit I/O on a closed handle. firstIntfHandle.deviceHandle = deviceHandle; firstIntfHandle.winusbHandle = interfaceHandle; - asyncTask.addDevice(deviceHandle); + deviceOpenedHere = true; } catch (Exception e) { + if (interfaceHandle != null) + WinUsb_Free(interfaceHandle); CloseHandle(deviceHandle); throw e; } } if (intfHandle != firstIntfHandle) { - // open associated interface - var interfaceHandleHolder = arena.allocate(ADDRESS); - if (WinUsb_GetAssociatedInterface(errorState, firstIntfHandle.winusbHandle, - (byte) (intfHandle.interfaceNumber - firstIntfHandle.interfaceNumber - 1), - interfaceHandleHolder) == 0) - throwLastError(errorState, "claiming (associated) interface failed"); - intfHandle.winusbHandle = dereference(interfaceHandleHolder); + try { + // open associated interface + var interfaceHandleHolder = arena.allocate(ADDRESS); + if (WinUsb_GetAssociatedInterface(errorState, firstIntfHandle.winusbHandle, + (byte) (intfHandle.interfaceNumber - firstIntfHandle.interfaceNumber - 1), + interfaceHandleHolder) == 0) + throwLastError(errorState, "claiming (associated) interface failed"); + intfHandle.winusbHandle = dereference(interfaceHandleHolder); + + } catch (Exception e) { + if (deviceOpenedHere) { + // no interface has been claimed yet, so close() would never release the device + WinUsb_Free(firstIntfHandle.winusbHandle); + CloseHandle(firstIntfHandle.deviceHandle); + firstIntfHandle.winusbHandle = null; + firstIntfHandle.deviceHandle = null; + } + throw e; + } } } From c69c072aa37af0193e876ab5ae796b5e94158d68 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Mon, 6 Jul 2026 17:22:53 +0200 Subject: [PATCH 419/433] Volatile for concurrently access variables --- java-does-usb/robustness.md | 30 ++++++++++++++----- .../codecrete/usb/common/UsbDeviceImpl.java | 4 ++- .../usb/common/UsbDeviceRegistry.java | 17 +++++++---- .../codecrete/usb/linux/LinuxUsbDevice.java | 3 +- .../codecrete/usb/macos/MacosUsbDevice.java | 6 ++-- .../usb/windows/WindowsUsbDevice.java | 3 +- 6 files changed, 45 insertions(+), 18 deletions(-) diff --git a/java-does-usb/robustness.md b/java-does-usb/robustness.md index 545c0b8a..59e0c881 100644 --- a/java-does-usb/robustness.md +++ b/java-does-usb/robustness.md @@ -336,11 +336,24 @@ the device left open but `deviceOpenCount == 0` and no interface claimed. Since releases *claimed* interfaces, that device handle (still registered with the completion port) leaks until process exit. ---- - -## Open findings +## 8. Visibility: shared flags are neither volatile nor consistently synchronized — **FIXED (all platforms)** + +> **Status:** Fixed on 2026-07-06. All three listed items are now `volatile`: +> `WindowsUsbDevice.showAsOpen`, `UsbDeviceImpl.connected`, and the two registry handler fields. +> The same unlocked-`isOpened()` pattern exists on the other two platforms (the finding named +> Windows only because that's where the review looked) and was fixed there too: `LinuxUsbDevice.fd` +> and the `MacosUsbDevice.claimedInterfaces` reference are also `volatile` now (for the latter, +> `isOpened()` only null-checks the reference; the list contents are only accessed while holding +> the device monitor, so `volatile` on the reference suffices). +> +> In addition, `emitOnDeviceConnected` / `emitOnDeviceDisconnected` now read the handler field once +> into a local before the null check. With `volatile` alone, a concurrent +> `setOnDeviceConnected(null)` between the null check and the invocation would have thrown an NPE +> that the catch block then mislabels as an exception *inside* the user's handler. +> +> Compile-verified; pure visibility changes of this kind are not exercisable by the test suite. -## 8. Visibility: shared flags are neither volatile nor consistently synchronized +The original description follows. - `showAsOpen`: written under the device monitor, but `isOpened()` (`WindowsUsbDevice.java:114`) reads it unlocked — `checkIsOpen`/`checkIsClosed` can act on stale state on a different thread. @@ -353,6 +366,10 @@ until process exit. All are cheap to fix with `volatile`. Practical impact is low (stale reads, not corruption), but `isConnected()` returning `true` long after unplug is user-visible. +--- + +## Open findings + ## 9. `messagePort` (remote) creation is unchecked (macOS) `MacosAsyncTask.java:135`: `CFMessagePortCreateRemote` can return NULL (e.g. a @@ -447,9 +464,8 @@ timeout rather than an infinite block). ## Recommended priority -Findings 1–7 are fixed (see above). Next up: the `volatile` flags of finding 8 and the -macOS message-port null check of finding 9. Findings 10–12 are low-priority -robustness notes. +Findings 1–8 are fixed (see above). Next up: the macOS message-port null check of +finding 9. Findings 10–12 are low-priority robustness notes. The Linux fixes for findings 1–3 still need a hardware test run on a Linux machine, and the finding 7 fix a hardware regression run on Windows. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java index 0156d5b1..41a1fb4f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceImpl.java @@ -63,7 +63,9 @@ public abstract class UsbDeviceImpl implements UsbDevice { protected int deviceProtocol; protected Version versionUsb; protected Version versionDevice; - protected boolean connected; + // volatile: written by the device monitor thread in disconnect(), read unlocked + // via isConnected() and checkIsClosed() + protected volatile boolean connected; /** * Creates a new instance. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceRegistry.java index b49a19c7..ed7999af 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/common/UsbDeviceRegistry.java @@ -32,14 +32,16 @@ * and builds the initial device list. *

*/ +@SuppressWarnings("java:S3077") public abstract class UsbDeviceRegistry { private static final System.Logger LOG = System.getLogger(UsbDeviceRegistry.class.getName()); private List devices; private Throwable failureCause; - protected Consumer onDeviceConnectedHandler; - protected Consumer onDeviceDisconnectedHandler; + // volatile: set by the application thread, read by the device monitor thread + protected volatile Consumer onDeviceConnectedHandler; + protected volatile Consumer onDeviceDisconnectedHandler; private final Lock lock = new ReentrantLock(); private final Condition enumerationComplete = lock.newCondition(); @@ -86,11 +88,13 @@ public void setOnDeviceDisconnected(Consumer handler) { } protected void emitOnDeviceConnected(UsbDevice device) { - if (onDeviceConnectedHandler == null) + // read once so a concurrent setOnDeviceConnected(null) cannot fail between check and call + var handler = onDeviceConnectedHandler; + if (handler == null) return; try { - onDeviceConnectedHandler.accept(device); + handler.accept(device); } catch (Exception e) { LOG.log(WARNING, "unhandled exception in 'onDeviceConnected' handler - ignoring", e); @@ -98,11 +102,12 @@ protected void emitOnDeviceConnected(UsbDevice device) { } protected void emitOnDeviceDisconnected(UsbDevice device) { - if (onDeviceDisconnectedHandler == null) + var handler = onDeviceDisconnectedHandler; + if (handler == null) return; try { - onDeviceDisconnectedHandler.accept(device); + handler.accept(device); } catch (Exception e) { LOG.log(WARNING, "unhandled exception in 'onDeviceDisconnected' handler - ignoring", e); diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java index 29bc77a9..d0c87f09 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDevice.java @@ -43,7 +43,8 @@ public class LinuxUsbDevice extends UsbDeviceImpl { private static final MemorySegment DRIVER_NAME_USBFS = Arena.global().allocateFrom("usbfs"); - private int fd = -1; + // volatile: written under the device monitor, read unlocked via isOpened() + private volatile int fd = -1; private final LinuxAsyncTask asyncTask; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java index ffa7ff8d..840390d9 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java @@ -51,7 +51,7 @@ * asynchronous transfer and waiting for the completion. *

*/ -@SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter", "java:S2160"}) +@SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter", "java:S2160", "java:S3077"}) public class MacosUsbDevice extends UsbDeviceImpl { private final MacosAsyncTask asyncTask; @@ -60,7 +60,9 @@ public class MacosUsbDevice extends UsbDeviceImpl { // Currently selected configuration private int configurationValue; // Details about interfaces that have been claimed - private List claimedInterfaces; + // (volatile: written under the device monitor, read unlocked via isOpened(); + // the list contents are only accessed while holding the device monitor) + private volatile List claimedInterfaces; // Details about endpoints of current alternate settings (for claimed interfaces) private Map endpoints; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java index a69e3f7f..b98839c2 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUsbDevice.java @@ -85,8 +85,9 @@ public class WindowsUsbDevice extends UsbDeviceImpl { /** * Indicates if {@link #open()} has been called. Since separate interfaces can have separate underlying * Windows device, {@link #claimInterface(int)} instead of {@link #open()} will open the Windows device. + * (volatile: written under the device monitor, read unlocked via {@link #isOpened()}) */ - private boolean showAsOpen; + private volatile boolean showAsOpen; WindowsUsbDevice(String devicePath, int vendorId, int productId, MemorySegment configDesc, boolean isComposite) { super(devicePath, vendorId, productId); From 18cf2f6e0ab7e2d3d599eabcadcdb5d727c1d27f Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Mon, 6 Jul 2026 17:35:48 +0200 Subject: [PATCH 420/433] Error handling for Async IO task (macOS) --- java-does-usb/robustness.md | 43 ++++++++++++++++--- .../codecrete/usb/macos/MacosAsyncTask.java | 31 ++++++++++--- .../codecrete/usb/macos/MacosUsbDevice.java | 11 +++-- 3 files changed, 69 insertions(+), 16 deletions(-) diff --git a/java-does-usb/robustness.md b/java-does-usb/robustness.md index 59e0c881..55194fc2 100644 --- a/java-does-usb/robustness.md +++ b/java-does-usb/robustness.md @@ -366,11 +366,26 @@ The original description follows. All are cheap to fix with `volatile`. Practical impact is low (stale reads, not corruption), but `isConnected()` returning `true` long after unplug is user-visible. ---- - -## Open findings +## 9. `messagePort` (remote) creation is unchecked (macOS) — **FIXED** + +> **Status:** Fixed on 2026-07-06. `startAsyncIOThread` now null-checks all *three* CF creations +> that can return NULL — `CFMessagePortCreateLocal`, `CFMessagePortCreateRunLoopSource`, and +> `CFMessagePortCreateRemote` (a NULL anywhere in the chain causes the same downstream damage, +> e.g. when bootstrap-port registration fails in a sandboxed process) — and throws a `UsbException` +> naming the failed call. The remote port is assigned to the `messagePort` field only after the +> check, so `removeEventSource` can never send on a NULL port. +> +> The naive throw would have traded the leak for a hang: the singleton would be stuck in state +> `STARTING` and every later `addEventSource` call would block forever in `waitForRunLoopReady`. +> The catch block therefore releases the partially created ports (`CFRelease`; releasing the last +> reference also invalidates the local port and deregisters its name, so a retry can recreate it) +> and resets the state to `NOT_STARTED`, so a later `open()` retries cleanly. The exception +> surfaces from `MacosUsbDevice.open()` before anything is registered with the run loop. +> +> Verified with the full hardware test suite on macOS (59 tests, all passing); the failure paths +> themselves require injected CF failures and are verified by inspection. -## 9. `messagePort` (remote) creation is unchecked (macOS) +The original description follows. `MacosAsyncTask.java:135`: `CFMessagePortCreateRemote` can return NULL (e.g. a race where the local port's run-loop source isn't serviced yet). @@ -378,13 +393,28 @@ race where the local port's run-loop source isn't serviced yet). never be removed — a slow leak of run-loop sources. Worth asserting non-null at creation. -## 10. Magic-number reinterpret in `loadDescription` (macOS) +## 10. Magic-number reinterpret in `loadDescription` (macOS) — **FIXED** + +> **Status:** Fixed on 2026-07-06. The pointer returned by `GetConfigurationDescriptorPtr` is now +> first reinterpreted to exactly `ConfigurationDescriptor.LAYOUT.byteSize()` (9 bytes) — the +> minimum needed to read the header — then, after a sanity check that `wTotalLength` is at least +> the header size (throwing a `UsbException` naming the bogus value otherwise), reinterpreted to +> exactly `totalLength`. No magic number remains, and the view never claims memory beyond the +> kernel buffer, which IOKit itself sized from the same `wTotalLength` field when caching the +> descriptor. Verified with the full hardware test suite on macOS (59 tests, all passing) — +> `loadDescription` runs during enumeration of every connected device. + +The original description follows. `MacosUsbDevice.java:194`: `dereference(descPtrHolder).reinterpret(999999)` before re-slicing to `totalLength()`. It's bounded immediately afterward so it's safe in practice, but the arbitrary size is fragile if a malformed descriptor ever reports a `totalLength` beyond the real buffer. +--- + +## Open findings + ## 11. `open()` holds the device monitor across up to 4×90 ms sleeps (macOS) `MacosUsbDevice.java:103-135` is `synchronized` and sleeps while retrying @@ -464,8 +494,7 @@ timeout rather than an infinite block). ## Recommended priority -Findings 1–8 are fixed (see above). Next up: the macOS message-port null check of -finding 9. Findings 10–12 are low-priority robustness notes. +Findings 1–10 are fixed (see above). Findings 11–12 are low-priority robustness notes. The Linux fixes for findings 1–3 still need a hardware test run on a Linux machine, and the finding 7 fix a hardware regression run on Windows. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java index 19f93f37..b4b71b62 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosAsyncTask.java @@ -118,7 +118,8 @@ void removeEventSource(MemorySegment source) { */ @SuppressWarnings("java:S125") private void startAsyncIOThread() { - MemorySegment messagePortSource; + MemorySegment messagePortSource = NULL; + MemorySegment localPort = NULL; try { state = TaskState.STARTING; @@ -130,19 +131,37 @@ private void startAsyncIOThread() { var methodHandle = asyncIOCompletedMH.bindTo(this); completionUpcallStub = Linker.nativeLinker().upcallStub(methodHandle, completionHandlerFuncDesc, Arena.global()); - // create local and remote message ports + // create local and remote message ports (all three CF creations can return NULL, + // e.g. if bootstrap port registration fails in a sandboxed process) var pid = ProcessHandle.current().pid(); var portName = CoreFoundationHelper.createCFStringRef("net.codecrete.usb.macos.eventsource." + pid, Arena.global()); var messagePortCallback = CFMessagePortCreateLocal$callout.allocate(this::messagePortCallback, Arena.global()); - var localPort = CoreFoundation.CFMessagePortCreateLocal(NULL, portName, messagePortCallback, NULL, NULL); + localPort = CoreFoundation.CFMessagePortCreateLocal(NULL, portName, messagePortCallback, NULL, NULL); + if (localPort.address() == 0) + throw new UsbException("internal error (CFMessagePortCreateLocal failed)"); messagePortSource = CoreFoundation.CFMessagePortCreateRunLoopSource(NULL, localPort, 0); - messagePort = CoreFoundation.CFMessagePortCreateRemote(NULL, portName); + if (messagePortSource.address() == 0) + throw new UsbException("internal error (CFMessagePortCreateRunLoopSource failed)"); + var remotePort = CoreFoundation.CFMessagePortCreateRemote(NULL, portName); + if (remotePort.address() == 0) + throw new UsbException("internal error (CFMessagePortCreateRemote failed)"); + messagePort = remotePort; - } catch (IllegalAccessException | NoSuchMethodException e) { + } catch (Exception e) { + // release partially created ports and reset the state; otherwise the task would be + // stuck in STARTING and all later addEventSource() calls would wait forever + if (messagePortSource.address() != 0) + CoreFoundation.CFRelease(messagePortSource); + if (localPort.address() != 0) + CoreFoundation.CFRelease(localPort); + state = TaskState.NOT_STARTED; + if (e instanceof RuntimeException runtimeException) + throw runtimeException; throw new UsbException("internal error (creating method handle)", e); } - var thread = new Thread(() -> asyncIOCompletionTask(messagePortSource), "USB async IO"); + var source = messagePortSource; + var thread = new Thread(() -> asyncIOCompletionTask(source), "USB async IO"); thread.setDaemon(true); thread.start(); } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java index 840390d9..57065c7c 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUsbDevice.java @@ -199,9 +199,14 @@ private void loadDescription(MemorySegment device) { if (ret != 0) throwException(ret, "querying first configuration failed"); - var configDesc = dereference(descPtrHolder).reinterpret(999999); - var configDescHeader = new ConfigurationDescriptor(configDesc); - configDesc = configDesc.asSlice(0, configDescHeader.totalLength()); + // read the descriptor header with a minimally sized view first, then resize to the + // total length the header reports (the kernel buffer was sized from the same field) + var headerSize = ConfigurationDescriptor.LAYOUT.byteSize(); + var configDescHeader = new ConfigurationDescriptor(dereference(descPtrHolder).reinterpret(headerSize)); + var totalLength = configDescHeader.totalLength(); + if (totalLength < headerSize) + throwException("invalid configuration descriptor (wTotalLength: %d)", totalLength); + var configDesc = dereference(descPtrHolder).reinterpret(totalLength); var configuration = setConfigurationDescriptor(configDesc); configurationValue = 255 & configuration.configValue(); From 40cee4a23fe1281f9fd08c5041a023bbb4b00403 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Mon, 6 Jul 2026 17:36:10 +0200 Subject: [PATCH 421/433] Cleanup --- java-does-usb/robustness.md | 500 ------------------------------------ 1 file changed, 500 deletions(-) delete mode 100644 java-does-usb/robustness.md diff --git a/java-does-usb/robustness.md b/java-does-usb/robustness.md deleted file mode 100644 index 55194fc2..00000000 --- a/java-does-usb/robustness.md +++ /dev/null @@ -1,500 +0,0 @@ -# Concurrency and Robustness Review - -Merged from two parallel reviews: one focused on the **Windows** implementation (with the -resulting fixes ported to **Linux**), one focused on the **macOS** implementation (with several -fixes landing in the shared common classes, benefiting all three platforms). - -Threads involved: - -- user threads submitting transfers and blocking on results, -- the "USB async IO" completion thread — I/O completion port loop on Windows - (`WindowsAsyncTask`), epoll loop on Linux (`LinuxAsyncTask`), CFRunLoop on macOS - (`MacosAsyncTask`); a **process-wide singleton** on every platform, -- the "USB device monitor" thread — window message loop (`WindowsUsbDeviceRegistry`), - udev monitoring (Linux), IOKit notification run loop (`MacosUsbDeviceRegistry`). - -Files reviewed on the macOS side: `MacosUsbDevice`, `MacosAsyncTask`, `MacosUsbDeviceRegistry`, -`MacosEndpointInputStream` / `MacosEndpointOutputStream`, `MacosTransfer`, `IoKitHelper`, and the -shared base classes `EndpointInputStream`, `EndpointOutputStream`, `Transfer`, `UsbDeviceImpl`, -`UsbDeviceRegistry`. - -Findings are ordered by severity. Fixed findings keep their status note followed by the original -description. - ---- - -## 1. Potential permanent deadlock: completion handlers invoked while holding the `WindowsAsyncTask` monitor — **FIXED (Windows & Linux; macOS was already correct)** - -> **Status:** Fixed on 2026-07-03. `WindowsAsyncTask.completeTransfer` now removes the transfer -> from the map, copies the results out of the OVERLAPPED, and recycles the OVERLAPPED under the -> lock, then invokes the completion handler after releasing it, wrapped in try/catch so a throwing -> handler cannot kill the async IO thread (partially addressing finding 3 as well). Verified with -> the full hardware test suite (59 tests, all passing). -> -> macOS was already correct: `completed()` is invoked outside the `asyncTask` monitor -> (`MacosAsyncTask.java:197-203`), avoiding the lock cycle with the submit path -> (`device → asyncTask → transfer`). -> -> The Linux counterpart is fixed the same way: `reapURBs` now reaps and unlinks transfers under the -> task monitor, collecting them into a list, and invokes the handlers after releasing it (in a -> `finally`, so already-reaped transfers still complete if reaping throws), each wrapped in -> try/catch. `removeFromAsyncIOCompletion` is no longer method-synchronized: the epoll removal and -> the stale-URB sweep each take the lock briefly, and the ENODEV completions are invoked outside -> it. This is safe against a concurrent submit on the same device because `LinuxUsbDevice.close()` -> and `LinuxUsbDevice.submitTransfer` serialize on the device monitor. Compile-verified only (see -> finding 2's note on Linux verification). -> -> **Residual (pre-existing, Linux):** the ENODEV completions in `removeFromAsyncIOCompletion` run -> on the closing thread, which holds the *device* monitor (`LinuxUsbDevice.close()` is -> synchronized). A timed-out waiter holding a transfer monitor and calling `abortTransfers` (wants -> the device monitor) while `close()` invokes that transfer's handler (wants the transfer monitor) -> could still cycle. This inversion predates this fix and no longer involves the async IO thread, -> so it can only stall the closing thread and the waiter, not the whole library. Windows doesn't -> have it (close-triggered completions arrive via the IO thread, which holds no device monitor). - -`WindowsAsyncTask.completeTransfer()` (`WindowsAsyncTask.java:157`) is `synchronized` and calls -`transfer.completion().completed(transfer)` inside the lock. This creates a lock-order inversion -with the user-thread paths: - -- **User thread A** (sync transfer with timeout): holds the `transfer` monitor - (`synchronized (transfer)` block in `WindowsUsbDevice.transferOut`, `WindowsUsbDevice.java:338`) - and, when the timeout fires, calls `abortTransfers(...)` from inside `waitForTransfer` - (`UsbDeviceImpl.java:385`) → **wants the device monitor** (`abortTransfers` is `synchronized`, - `WindowsUsbDevice.java:482`). -- **User thread B**: holds the device monitor (`submitTransferOut` is `synchronized`, - `WindowsUsbDevice.java:413`) and calls `asyncTask.prepareForSubmission(...)` → - **wants the asyncTask monitor**. -- **Async IO thread**: holds the asyncTask monitor in `completeTransfer` and calls - `onSyncTransferCompleted` → **wants A's transfer monitor** (`UsbDeviceImpl.java:477`). - -If A's transfer completes right as its timeout expires (exactly the window in which timeouts race -with completions), the cycle A→device→B, B→asyncTask→IO thread, IO thread→transfer→A closes and is -permanent. Because `WindowsAsyncTask` is a process-wide singleton, a stuck IO thread freezes -completions for **all** devices, and every no-timeout transfer then blocks forever in -`waitNoTimeout`. The trigger is realistic: one thread doing timed transfers while another thread -submits on the same or another device. - -**Fix:** in `completeTransfer`, do the map removal / result copying / OVERLAPPED recycling under -the lock, but invoke the completion handler *after* releasing it. - -## 2. Failed submission leaks the transfer registration — **FIXED (macOS, Windows & Linux)** - -Both reviews found the same bug independently, on different platforms. The macOS fix landed first -(commit `60a47af`, "Deregister transfer on exception (macOS)"); the Windows and Linux counterparts -followed. - -> **Status (macOS):** Fixed. `MacosAsyncTask` now has a `submissionFailed` counterpart to -> `prepareForSubmission` that removes the transfer's map entry. Each of the three submit methods -> (`submitTransferIn`, `submitTransferOut`, `submitControlTransfer`) calls it in the native-error -> path, before `throwException`, so a failed submission no longer leaks an entry. Removal (rather -> than the alternative of registering only after a successful native call) was chosen deliberately: -> the completion callback runs on the async-IO run-loop thread and could otherwise race ahead of a -> post-success registration, find no map entry, and hang the waiting thread. Removing only on -> failure is race-free because a failed native submission produces no completion callback. -> -> **Status (Windows):** Fixed on 2026-07-03. `WindowsAsyncTask.submissionFailed(transfer)` now -> undoes the registration when a `WinUsb_*` call fails synchronously: it removes the map entry, -> returns the OVERLAPPED to the pool, and clears the transfer's reference (safe because Win32 -> posts no completion packet for a synchronous failure). Called from the error paths of all three -> submit methods, mirroring the macOS fix. Verified with the full hardware test suite (59 tests, -> all passing). -> -> **Status (Linux):** the same leak was discovered and fixed: `LinuxAsyncTask.submitTransfer` -> called `linkToUrb` (registers the URB→transfer mapping and takes a URB from the pool) and then -> threw on `SUBMITURB` ioctl failure without cleanup. A private `submissionFailed(transfer)` (safe -> to call under the already-held task monitor) now unlinks the transfer and recycles the URB — -> safe because a URB rejected by the ioctl is never queued and will never be reaped. -> Compile-verified only; the hardware test suite was run on Windows and does not exercise the -> Linux code path. - -The original descriptions follow. - -**macOS:** `prepareForSubmission` (`MacosAsyncTask.java:179-184`) registers the transfer in -the map *before* the native `ReadPipeAsync` / `WritePipeAsync` / `DeviceRequestAsync` call. If -that native call returns an error (`MacosUsbDevice.java:522`, `552`, `571`), the method throws and -the map entry is never removed (no completion will fire for it). Each failed submission -permanently leaks one entry in the singleton's map. Not fatal, but unbounded over a long-running -process that hits repeated submit failures. - -**Windows:** in `submitControlTransfer`, `submitTransferOut`, and `submitTransferIn` -(`WindowsUsbDevice.java:404–408, 422–426, 440–444`), `asyncTask.prepareForSubmission(transfer)` -registers the OVERLAPPED→transfer mapping and takes an OVERLAPPED from the pool; if `WinUsb_*` then -fails with anything other than `ERROR_IO_PENDING`, the exception path leaves the entry in -`requestsByOverlapped` forever and the OVERLAPPED never returns to `availableOverlappedStructs`. -Synchronous failures are the *normal* case right after an unplug, so an application that keeps -retrying on a hot-unplugged device leaks an OVERLAPPED, a map entry, and the pinned transfer buffer -per attempt. - -## 3. The singleton async IO thread can die, silently hanging the whole library — **FIXED (all platforms)** - -> **Status:** Fixed on 2026-07-03 (handler-exception protection was already added with finding 1). -> -> **macOS:** `MacosAsyncTask.asyncIOCompleted` now null-checks the map lookup (logging and -> ignoring a completion for an unknown transfer ID) and wraps the whole callback body in a -> `try/catch` that logs and swallows, so a bad completion can no longer escape into `CFRunLoopRun` -> and take down the shared IO thread. In addition, an unexpected `CFRunLoopRun` exit is now logged -> (WARNING) in both `MacosAsyncTask.asyncIOCompletionTask` and -> `MacosUsbDeviceRegistry.monitorDevices`, so a dead run loop is observable instead of silent. -> -> **Windows:** the completion loop body is wrapped in try/catch. Any exception — including a -> `GetQueuedCompletionStatus` failure with a null OVERLAPPED, whose error text is also fixed — -> now logs an ERROR, fails every transfer in `requestsByOverlapped` with -> `ERROR_OPERATION_ABORTED` (handlers invoked outside the lock, individually guarded), marks the -> task terminated, and exits. `prepareForSubmission` rejects new submissions with a clear -> `UsbException` once terminated, so callers fail fast instead of hanging in `waitNoTimeout`. -> The silent `return` on a successful dequeue with null OVERLAPPED ("registry closing?") was -> speculative — nothing posts such packets — and now goes through the same fatal path. -> -> **Linux:** same structure — the epoll loop body is wrapped; a non-EINTR `epoll_wait` failure -> (or an escaping exception) fails all pending transfers with `ECANCELED`, marks the task -> terminated, and exits; `submitTransfer` then rejects new work. In addition, two per-device reap -> failures no longer kill the thread: `EBADF` is treated as a benign race (the fd was closed -> concurrently — reachable from an ordinary `close()` while the event thread already holds a -> ready event) and any other unexpected reap errno degrades only that device (log, deregister -> from epoll to avoid a hot loop, continue serving other devices). -> `EPoll.removeFileDescriptor` now tolerates `EBADF` like `ENOENT`. `EBADF`/`ECANCELED` were -> added to the committed jextract errno bindings by hand (asm-generic values, valid on -> x64/ARM64) and to `gen_linux.sh` for the next regeneration on a Linux machine. -> -> Verified with the full hardware test suite on Windows (59 tests, all passing); the fatal paths -> themselves and the Linux changes are verified by inspection/compilation only. - -The original descriptions follow. - -**Windows:** two ways `asyncCompletionTask()` (`WindowsAsyncTask.java:68`) can terminate: - -- `GetQueuedCompletionStatus` fails with a null OVERLAPPED → `throwLastError` (line 86) kills the - thread. -- Any `RuntimeException` escaping a completion handler — handlers run inline in this thread (see - finding 1), so a bug or unexpected state in stream/user completion code is fatal to the loop. - -There is no restart, and the failure mode is nasty: subsequent transfers submit fine but never -complete, so callers block forever in `waitNoTimeout` (unbounded) and -`flush()`/`waitForAvailableTransfer` (also unbounded by design). - -Minor: the error text at line 86 said "SetupDiGetDeviceInterfaceDetailW" — a copy-paste from -elsewhere (fixed along with the above). - -**macOS:** `MacosAsyncTask.java:194-204`: - -```java -transfer = transfersById.remove(refcon.address()); -transfer.setResultCode(result); // NPE if remove() returned null -``` - -There was no null check and no `try/catch` around the whole callback. If a completion ever fires -for an ID not in the map — a double completion (e.g. a transfer that both times out/aborts *and* -completes), a spurious callback, or a bug in ID bookkeeping — this throws inside an upcall from -`CFRunLoopRun`. Because `MacosAsyncTask` is a **process-wide singleton** servicing *every* device -and interface, losing that thread hangs all outstanding and future async transfers for the whole -library, not just one device. - -Related (originally a separate low-severity note): `MacosUsbDeviceRegistry.monitorDevices` and -`MacosAsyncTask.asyncIOCompletionTask` both call `CFRunLoopRun()` and assumed it never returns. If -it ever does (e.g. all sources removed), the thread exits silently and device monitoring / async -IO stops with no signal to the application. Both sites now log a warning. - -## 4. Teardown waits (`collectOutstandingTransfers` / output-stream drain) could hang forever — **FIXED (all platforms, common code)** - -> **Status:** Fixed. The teardown waits are now bounded. `EndpointInputStream.collectOutstandingTransfers` -> and a dedicated bounded drain in `EndpointOutputStream.close()` poll with a shared 1 s -> deadline (`TEARDOWN_TIMEOUT_MS`) instead of blocking on `take()`. When the deadline expires -> with transfers still outstanding, the remaining transfers are abandoned and a warning is -> logged rather than freezing the application thread. Abandoning is safe because buffers come -> from an auto arena and survive a late completion writing into them. Interruption during the -> drain is deferred (no busy-spin) and re-asserted afterwards. The normal `read()`/`write()` -> data path and the public `flush()` keep their unbounded, correct blocking-stream semantics. -> The fix lives in the shared common base classes, so all three platforms benefit. - -The original description (from the macOS review) follows. - -`EndpointInputStream.java:215-223` and `EndpointOutputStream.java:194-213` both -block until *every* outstanding transfer reports back: - -```java -while (numOutstandingTransfers > 0) - waitForCompletedTransfer(); // completedTransferQueue.take() -``` - -The entire teardown correctness rests on the assumption that **every submitted -transfer eventually produces exactly one completion callback.** In the normal -path this holds (`AbortPipe` / `USBInterfaceClose` abort pending pipes and -deliver completions). But there are windows where it may not: - -- In `close()` (`EndpointInputStream.java:112-124`), if `device.abortTransfers` - throws (device already disconnected), the abort is silently swallowed and we - proceed straight to `collectOutstandingTransfers()`. We then rely entirely on - the monitor thread's `device.close()` having already aborted the same pipes. - If that hasn't happened yet, or if a completion is lost, `take()` blocks with - no timeout and no interruptibility — a permanent hang of the application - thread. -- The ordering guarantee in `MacosUsbDevice.close()` (abort → then post - source-removal message) only holds if `USBInterfaceClose` has *signaled* the - abort completions to the run loop before it returns. If IOKit signals them - slightly later, the source-removal message can be processed first and the - completions dropped → hang. - -## 5. Interruption caused a busy-spin, and transfers are effectively non-interruptible — **FIXED (all platforms, common code)** - -> **Status:** Fixed. Every blocking wait now uses a deferred-interrupt pattern. A caught -> `InterruptedException` sets a local `wasInterrupted` flag instead of re-asserting -> `Thread.currentThread().interrupt()` inside the loop; the flag is re-asserted only -> once the wait returns. Because the interrupt flag is no longer set *during* the loop, -> the blocking primitive (`queue.take()` / `transfer.wait()` / `Thread.sleep()`) blocks -> normally on the next iteration instead of throwing immediately — eliminating the 100% -> CPU spin. Applied to all six sites: `EndpointInputStream.waitForCompletedTransfer`, -> `EndpointOutputStream.waitForAvailableTransfer`, `UsbDeviceImpl.waitNoTimeout` and -> `waitWithTimeout`, plus the retry-backoff sleeps in `MacosUsbDevice.open()` and -> `WindowsUsbDevice.claimInterface()`. As part of this, `waitWithTimeout` now recomputes -> its remaining timeout on both the normal and interrupted paths, so it stays bounded by -> the original expiration and its timed-out return value stays accurate. -> -> Transfers remain intentionally **non-interruptible** (interruption is deferred, not -> turned into cancellation): a blocked USB call still returns only when the transfer -> completes, but the interrupt is preserved and observed afterwards. True cancellation -> was rejected because the only abort primitive (`AbortPipe`) tears down the whole -> endpoint, and the two call sites have incompatible exception vocabularies (checked -> `IOException` on the streams vs. unchecked `UsbException` on control transfers). - -The original description follows. - -Every blocking wait swallowed `InterruptedException`, re-asserted the interrupt -flag, and looped: - -- `waitForCompletedTransfer` — `EndpointInputStream.java:194-204` -- `waitForAvailableTransfer` — `EndpointOutputStream.java:224-242` -- `waitNoTimeout` / `waitWithTimeout` — `UsbDeviceImpl.java:390-418` - -Once the interrupt flag is set, the next `queue.take()` / `transfer.wait()` -throws `InterruptedException` **immediately**, which is caught, re-sets the -flag, and loops again. If the awaited completion hasn't arrived yet, this spins -at 100% CPU until it does. For `waitNoTimeout` with an unplugged device that -never delivers a completion, it spins indefinitely. Beyond the CPU cost, the -practical effect is that a blocked USB call cannot be cancelled by interrupting -the thread — the interrupt is neither honored nor cleanly deferred. - -## 6. `waitWithTimeout` post-timeout `waitNoTimeout` assumed a completion still comes — **FIXED (all platforms, common code)** - -> **Status:** Fixed. The post-timeout drain is now bounded. After a timeout, `UsbDeviceImpl.waitForTransfer` -> aborts the transfer and then waits for the abort's completion via `waitWithTimeout` with a fixed -> `ABORT_COMPLETION_TIMEOUT_MS` (1 s) bound instead of the unbounded `waitNoTimeout`. If the abort's -> completion never arrives (device vanished such that neither the transfer nor the abort yields a -> callback), the transfer is abandoned and a warning is logged; the method still throws the same -> `UsbTimeoutException`, so the user-facing outcome is unchanged. The no-timeout path -> (`timeout <= 0`) intentionally keeps its unbounded `waitNoTimeout` — a caller that asked for no -> timeout has opted into blocking. -> -> Abandoning is only memory-safe because the buffers that can reach this path — those in the -> synchronous `transferIn` / `transferOut` on all three platforms — were switched from -> `Arena.ofConfined()` to `Arena.ofAuto()`, so a late completion writing into the buffer can never -> touch freed memory. Control-transfer buffers stay confined: they only ever use the no-timeout path -> and so cannot reach the drain. - -The original description follows. - -`UsbDeviceImpl.java:368-388`: on timeout, `abortTransfers` is called and then -`waitNoTimeout(transfer)` blocks for the abort completion. This is correct *if* -the abort produces a completion. If the device vanished such that neither the -timeout nor the abort yields a callback, `waitNoTimeout` hangs (same root cause -as finding 4). The timeout feature gives users an expectation of bounded blocking -that the post-timeout `waitNoTimeout` quietly breaks. - -## 7. `claimInterfaceSynchronized` leaves inconsistent state on error paths (Windows) — **FIXED** - -> **Status:** Fixed on 2026-07-06. Both error paths in `claimInterfaceSynchronized` are addressed: -> -> - The device-open block now commits `firstIntfHandle.deviceHandle` / `winusbHandle` only *after* -> the last fallible operation (`asyncTask.addDevice`) has succeeded, so no error path can leave -> the fields pointing at a closed handle. The catch block cleans up purely local state — and now -> also frees the WinUSB interface handle (previously leaked) before closing the device handle, -> mirroring the cleanup order of `releaseInterface`. Closing the handle is a complete undo: -> `addDevice` can only fail if `CreateIoCompletionPort` itself failed, in which case the handle -> was never associated with the completion port, so no stray completion packets can result. -> - The associated-interface path is wrapped so that a `WinUsb_GetAssociatedInterface` failure -> undoes the device open if (and only if) this call performed it, tracked by a local -> `deviceOpenedHere` flag: free the first interface handle, close the device handle, null both -> fields, rethrow. If the device was already open on entry, nothing is undone — the handle is -> legitimately in use by a previously claimed interface, and no state was mutated. -> -> Compile-verified only: the error paths themselves (`CreateIoCompletionPort` / -> `WinUsb_GetAssociatedInterface` failures) require injected native failures and are verified by -> inspection. A hardware regression run on Windows is pending (see note at the end). - -The original description follows. - -In `WindowsUsbDevice.java:215–217`, `firstIntfHandle.deviceHandle` and `winusbHandle` are assigned -**before** `asyncTask.addDevice(deviceHandle)`. If `addDevice` throws (CreateIoCompletionPort -failure), the catch closes the device handle but leaves both fields set — a later claim sees -`deviceHandle != null`, skips reopening, and submits I/O on a closed handle. - -**Fix:** assign the fields only after `addDevice` succeeds (or null them in the catch, and -`WinUsb_Free` the interface handle too). - -Related: when claiming an associated interface (e.g. interface 1 of a function starting at 0) opens -the device and then `WinUsb_GetAssociatedInterface` fails (line 228), the exception propagates with -the device left open but `deviceOpenCount == 0` and no interface claimed. Since `close()` only -releases *claimed* interfaces, that device handle (still registered with the completion port) leaks -until process exit. - -## 8. Visibility: shared flags are neither volatile nor consistently synchronized — **FIXED (all platforms)** - -> **Status:** Fixed on 2026-07-06. All three listed items are now `volatile`: -> `WindowsUsbDevice.showAsOpen`, `UsbDeviceImpl.connected`, and the two registry handler fields. -> The same unlocked-`isOpened()` pattern exists on the other two platforms (the finding named -> Windows only because that's where the review looked) and was fixed there too: `LinuxUsbDevice.fd` -> and the `MacosUsbDevice.claimedInterfaces` reference are also `volatile` now (for the latter, -> `isOpened()` only null-checks the reference; the list contents are only accessed while holding -> the device monitor, so `volatile` on the reference suffices). -> -> In addition, `emitOnDeviceConnected` / `emitOnDeviceDisconnected` now read the handler field once -> into a local before the null check. With `volatile` alone, a concurrent -> `setOnDeviceConnected(null)` between the null check and the invocation would have thrown an NPE -> that the catch block then mislabels as an exception *inside* the user's handler. -> -> Compile-verified; pure visibility changes of this kind are not exercisable by the test suite. - -The original description follows. - -- `showAsOpen`: written under the device monitor, but `isOpened()` (`WindowsUsbDevice.java:114`) - reads it unlocked — `checkIsOpen`/`checkIsClosed` can act on stale state on a different thread. -- `UsbDeviceImpl.connected`: written by the monitor thread in `disconnect()`, read unlocked via - `isConnected()` and `checkIsClosed`. -- `UsbDeviceRegistry.onDeviceConnectedHandler` / `onDeviceDisconnectedHandler`: set by the app - thread, read by the monitor thread with no happens-before edge — a handler registered after - `start()` may never be seen. - -All are cheap to fix with `volatile`. Practical impact is low (stale reads, not corruption), but -`isConnected()` returning `true` long after unplug is user-visible. - -## 9. `messagePort` (remote) creation is unchecked (macOS) — **FIXED** - -> **Status:** Fixed on 2026-07-06. `startAsyncIOThread` now null-checks all *three* CF creations -> that can return NULL — `CFMessagePortCreateLocal`, `CFMessagePortCreateRunLoopSource`, and -> `CFMessagePortCreateRemote` (a NULL anywhere in the chain causes the same downstream damage, -> e.g. when bootstrap-port registration fails in a sandboxed process) — and throws a `UsbException` -> naming the failed call. The remote port is assigned to the `messagePort` field only after the -> check, so `removeEventSource` can never send on a NULL port. -> -> The naive throw would have traded the leak for a hang: the singleton would be stuck in state -> `STARTING` and every later `addEventSource` call would block forever in `waitForRunLoopReady`. -> The catch block therefore releases the partially created ports (`CFRelease`; releasing the last -> reference also invalidates the local port and deregisters its name, so a retry can recreate it) -> and resets the state to `NOT_STARTED`, so a later `open()` retries cleanly. The exception -> surfaces from `MacosUsbDevice.open()` before anything is registered with the run loop. -> -> Verified with the full hardware test suite on macOS (59 tests, all passing); the failure paths -> themselves require injected CF failures and are verified by inspection. - -The original description follows. - -`MacosAsyncTask.java:135`: `CFMessagePortCreateRemote` can return NULL (e.g. a -race where the local port's run-loop source isn't serviced yet). -`removeEventSource` would then send on a NULL port and the event source would -never be removed — a slow leak of run-loop sources. Worth asserting non-null at -creation. - -## 10. Magic-number reinterpret in `loadDescription` (macOS) — **FIXED** - -> **Status:** Fixed on 2026-07-06. The pointer returned by `GetConfigurationDescriptorPtr` is now -> first reinterpreted to exactly `ConfigurationDescriptor.LAYOUT.byteSize()` (9 bytes) — the -> minimum needed to read the header — then, after a sanity check that `wTotalLength` is at least -> the header size (throwing a `UsbException` naming the bogus value otherwise), reinterpreted to -> exactly `totalLength`. No magic number remains, and the view never claims memory beyond the -> kernel buffer, which IOKit itself sized from the same `wTotalLength` field when caching the -> descriptor. Verified with the full hardware test suite on macOS (59 tests, all passing) — -> `loadDescription` runs during enumeration of every connected device. - -The original description follows. - -`MacosUsbDevice.java:194`: `dereference(descPtrHolder).reinterpret(999999)` -before re-slicing to `totalLength()`. It's bounded immediately afterward so it's -safe in practice, but the arbitrary size is fragile if a malformed descriptor -ever reports a `totalLength` beyond the real buffer. - ---- - -## Open findings - -## 11. `open()` holds the device monitor across up to 4×90 ms sleeps (macOS) - -`MacosUsbDevice.java:103-135` is `synchronized` and sleeps while retrying -`USBDeviceOpenSeize`. Any other thread calling a synchronized method on that -device blocks for up to ~360 ms. Minor, and only during open, but worth noting. - -## 12. Minor observations - -- **Data race on result fields in the timeout path** (Windows): `completeTransfer` writes - `resultCode`/`resultSize` before taking the transfer monitor, while the timed-out waiter reads - `transfer.resultCode()` holding it (`UsbDeviceImpl.java:384`). Consequences are benign (a - redundant `WinUsb_AbortPipe`, or a timeout exception despite late data — inherent to the race - anyway), but it's formally a data race. -- **User callbacks run on the monitor thread inside the window procedure** - (`WindowsUsbDeviceRegistry.java:326–347`). A slow `onDeviceConnected`/`onDeviceDisconnected` - handler stalls all further device notifications (and the `disconnect()` cleanup of other - devices). Exceptions are caught, which is good; the latency constraint is worth documenting if it - isn't already. The same applies to the macOS and Linux monitor threads. -- `completeTransfer` dispatches all devices through one lock and one thread, so one slow handler - delays every device's completions — currently fine since internal handlers are cheap queue - operations, but it compounds finding 1's argument for invoking handlers outside the lock. - ---- - -## What holds up well - -### Windows / Linux - -The overall unplug/teardown story is sound: closing the WinUSB/file handles cancels pending I/O, -cancelled I/O still posts completion packets to the port, so blocked waiters wake with an error -result; the stream teardown paths (`close()`, `collectOutstandingTransfers`, abort-completion wait) -are all deadline-bounded so a genuinely lost completion degrades to a logged warning rather than a -hang. - -The `claimInterface` retry loop sleeps outside the device monitor, interrupts are deferred rather -than swallowed, `transfer.wait()` correctly releases the transfer monitor while submissions on -other threads proceed, and the copy-on-write device list with the case-insensitive Windows override -applied to both add and remove paths is correct. The timed-out-transfer buffers using -`Arena.ofAuto()` so an abandoned transfer can't have its buffer freed under a late completion is a -well-handled detail. - -### macOS - -- **`synchronized` on the device** serializes submission against `close()` / - `disconnect()`, so native interface/device pointers can't be released out - from under a submitting thread (as the class Javadoc promises). -- **The wait/notify guard is correct**: `asyncIOCompleted` sets `resultSize` / - `resultCode` *before* calling the completion handler, and `waitNoTimeout` - loops on `resultSize() == -1` under the `transfer` monitor. A completion that - races ahead of `wait()` is not lost - (`MacosUsbDevice.java:407-410`, `UsbDeviceImpl.java:391-400`). -- **`completed()` is invoked outside the `asyncTask` monitor** - (`MacosAsyncTask.java:197-203`), avoiding a lock cycle with the submit path - (`device → asyncTask → transfer`). -- **Deferred event-source removal via the message port** - (`MacosAsyncTask.removeEventSource`) is a deliberate and correct move to keep - completion callbacks ordered ahead of source removal on the run-loop thread. -- **Stream buffers use `Arena.ofAuto()`** (`EndpointInputStream.java:66`), so a - completion callback that writes into a buffer *after* the stream/device is - gone won't touch freed memory — it stays alive until GC. Good defensive - choice given the async model. - -### Concurrency model — verdict (macOS) - -The core two-thread interaction (app thread submitting/waiting vs. the run-loop -IO thread completing) is **sound**: lock ordering is consistent, there's no -reverse-order acquisition, the notify guard is correct, and buffer lifetime is -handled via `ofAuto`. Disconnect-during-blocking-transfer works *as long as -IOKit delivers a completion for every aborted transfer* — and that single -assumption was the load-bearing one. Findings 3, 4, and 6 were all facets of -"what happens when a completion is late, duplicated, or missing," which is -precisely the unplug scenario; all three are now hardened (null-safe callback, -bounded teardown waits, and treating a missing completion as a recoverable -timeout rather than an infinite block). - ---- - -## Recommended priority - -Findings 1–10 are fixed (see above). Findings 11–12 are low-priority robustness notes. - -The Linux fixes for findings 1–3 still need a hardware test run on a Linux machine, and the -finding 7 fix a hardware regression run on Windows. From 9ecc41b822d0ca69b8987cfef95f6624709550cd Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Mon, 6 Jul 2026 21:38:55 +0200 Subject: [PATCH 422/433] Handle IOException in unplug test --- .../src/test/java/net/codecrete/usb/special/Unplug.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java index cb79dd39..abba3d4c 100644 --- a/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java +++ b/java-does-usb/src/test/java/net/codecrete/usb/special/Unplug.java @@ -28,7 +28,7 @@ public class Unplug { private static final Map activeDevices = new HashMap<>(); - public static void main(String[] args) throws IOException { + static void main() throws IOException { System.out.println("Plug and unplug test device multiple times."); System.out.println("Hit ENTER to exit."); @@ -223,6 +223,8 @@ private void sendLoopbackDataStream() { logWork(data.length); } } catch (IOException e) { + if (e.getCause() instanceof UsbException usbException) + throw usbException; throw new RuntimeException(e); } } @@ -241,6 +243,8 @@ private void receiveLoopbackDataStream() { logWork(n); } } catch (IOException e) { + if (e.getCause() instanceof UsbException usbException) + throw usbException; throw new RuntimeException(e); } } From 069bd65c097dcd9a8a7b49703ff71254e11f1515 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 10 Jul 2026 12:50:59 +0200 Subject: [PATCH 423/433] Use snapshot version during development --- .github/workflows/continuous-integration.yaml | 21 ++-- RELEASING.md | 101 ++++++++++++++++++ examples/bulk_transfer/pom.xml | 3 +- examples/enumerate/pom.xml | 3 +- examples/enumerate_kotlin/build.gradle.kts | 2 +- examples/enumerate_native/pom.xml | 3 +- examples/epaper_display/pom.xml | 3 +- examples/monitor/pom.xml | 3 +- examples/monitor_kotlin/pom.xml | 3 +- examples/monitor_native/pom.xml | 3 +- examples/stm_dfu/pom.xml | 3 +- java-does-usb/pom.xml | 2 +- 12 files changed, 133 insertions(+), 17 deletions(-) create mode 100644 RELEASING.md diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index 4039eb94..7c385f3b 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -39,24 +39,31 @@ jobs: - name: Build java-does-usb run: ./mvnw $MAVEN_ARGS -DskipTests clean install javadoc:javadoc working-directory: ./java-does-usb + - name: Determine java-does-usb version + id: libver + run: echo "version=$(./mvnw -q help:evaluate -Dexpression=project.version -DforceStdout)" >> "$GITHUB_OUTPUT" + working-directory: ./java-does-usb + shell: bash + # Examples pin the latest released version so they double as user-facing documentation; + # override that pin here to compile them against the HEAD version just installed above. - name: Example "bulk_transfer" - run: ./mvnw $MAVEN_ARGS clean compile + run: ./mvnw $MAVEN_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean compile working-directory: ./examples/bulk_transfer - name: Example "enumerate" - run: ./mvnw $MAVEN_ARGS clean compile + run: ./mvnw $MAVEN_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean compile working-directory: ./examples/enumerate - name: Example "enumerate" (Kotlin) - run: ./gradlew clean build + run: ./gradlew -PjavaDoesUsbVersion=${{ steps.libver.outputs.version }} clean build working-directory: ./examples/enumerate_kotlin - name: Example "monitor" - run: ./mvnw $MAVEN_ARGS clean compile + run: ./mvnw $MAVEN_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean compile working-directory: ./examples/monitor - name: Example "monitor" (Kotlin) - run: ./mvnw $MAVEN_ARGS clean package + run: ./mvnw $MAVEN_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean package working-directory: ./examples/monitor_kotlin - name: Example "stm_dfu" - run: ./mvnw $MAVEN_ARGS clean compile + run: ./mvnw $MAVEN_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean compile working-directory: ./examples/stm_dfu - name: Example "epaper_display" - run: ./mvnw $MAVEN_ARGS clean compile + run: ./mvnw $MAVEN_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean compile working-directory: ./examples/epaper_display diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 00000000..948576cf --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,101 @@ +# Releasing Java Does USB + +This document describes how a new version of the library is released to Maven Central, and how +version numbers flow through the repository afterwards. + +## Versioning scheme + +- The library follows [Semantic Versioning](https://semver.org/) (`MAJOR.MINOR.PATCH`). +- On the `main` branch, `java-does-usb/pom.xml` always carries the *next*, unreleased version + with a `-SNAPSHOT` suffix (e.g. `1.2.2-SNAPSHOT`). This makes it obvious that a build from `main` + is a development build, not something published to Central. +- `README.md` and the example projects under `examples/` intentionally do **not** track this + SNAPSHOT. They pin the latest *released* version, because they double as user-facing + documentation: a user reading the README or copying an example's `pom.xml`/`build.gradle.kts` + should see the version they can actually `mvn install` from Central today. +- Continuous integration overrides the pinned example version at build time so it still compiles + the examples against `main`'s HEAD (see "How CI stays honest" below). No file needs to be edited + for this to work. + +## Release checklist + +1. **Drop the `-SNAPSHOT` suffix.** + In `java-does-usb/pom.xml`, set `` to the release version, e.g.: + ```bash + cd java-does-usb + ./mvnw versions:set -DnewVersion=1.2.2 -DgenerateBackupPoms=false + ``` + +2. **Update the version everywhere it's pinned for users.** This means: + - `README.md` — the Maven (`...`) and Gradle (`version: '...'`) snippets + under "Getting Started", and the version history table if you're adding an entry. + - Every example's dependency on `java-does-usb`, pinned via a single property so it's one edit + per file (`java-does-usb.version` in the Maven examples, `javaDoesUsbVersion` in the Gradle + one): + - `examples/enumerate/pom.xml` + - `examples/bulk_transfer/pom.xml` + - `examples/monitor/pom.xml` + - `examples/monitor_kotlin/pom.xml` + - `examples/stm_dfu/pom.xml` + - `examples/epaper_display/pom.xml` + - `examples/enumerate_native/pom.xml` + - `examples/monitor_native/pom.xml` + - `examples/enumerate_kotlin/build.gradle.kts` + - The example's *own* project version (its `` / `version = "..."`, separate from the + `java-does-usb.version`/`javaDoesUsbVersion` property), which by convention tracks the library + release it was last verified against, for `enumerate`, `bulk_transfer`, `monitor`, + `monitor_kotlin`, `stm_dfu`, `epaper_display`, and `enumerate_kotlin`. (`enumerate_native` and + `monitor_native` version themselves independently as `1.0-SNAPSHOT` and don't need this.) + - The sample console output hardcoded in each example's own `README.md` (e.g. build log lines + like `[INFO] Building enumerate 1.2.1` or jar filenames like `stm_dfu-1.2.1.jar`), which + embeds the example's own project version from the point above. + + A simple search for the previous version number across `README.md` and `examples/` will locate + every occurrence listed above. + +3. **Commit, tag, and publish.** + ```bash + git add -A + git commit -m "Release 1.2.2" + git tag v1.2.2 + git push origin main v1.2.2 + cd java-does-usb + ./mvnw clean deploy -Prelease # or whatever profile/flags drive maven-gpg-plugin + central-publishing-maven-plugin + ``` + (Adjust to however signing/publishing is actually invoked locally today — this step is manual + and not run by CI.) + +4. **Prepare `main` for the next development iteration.** + ```bash + cd java-does-usb + ./mvnw versions:set -DnewVersion=1.2.3-SNAPSHOT -DgenerateBackupPoms=false + git add pom.xml + git commit -m "Prepare for next development iteration" + git push origin main + ``` + Deliberately do **not** touch `README.md` or the examples in this step — they should keep + pointing at the release just made (1.2.2) until the *next* release checklist run. + +## How CI stays honest + +Because the examples pin the released version, a naive CI setup would silently compile them +against whatever is available on Maven Central instead of the code actually being tested — i.e. +after step 4 above, `main` might contain a breaking change that no CI run would ever catch until +the next release. + +To prevent that, `.github/workflows/continuous-integration.yaml`: + +1. Builds and `install`s the library from the checked-out `pom.xml` (whatever version — released + or `-SNAPSHOT` — is on HEAD) into the local Maven repository. +2. Reads that exact version back out with `mvn help:evaluate -Dexpression=project.version`. +3. Passes it to each example build as an override: + - Maven examples: `-Djava-does-usb.version=` + - The Gradle example (`enumerate_kotlin`): `-PjavaDoesUsbVersion=` + +This means CI always compiles every example against the exact commit under test, while the +committed example files keep showing users the last real release. + +If you add a new example, give its `java-does-usb` dependency the same treatment: introduce a +`java-does-usb.version` property (Maven) or an overridable `javaDoesUsbVersion` val (Gradle) +defaulting to the current released version, add a CI step following the existing pattern, and add +it to the list in step 2 of the release checklist above. diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index c6fc930b..589f744b 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -15,13 +15,14 @@ UTF-8 22 22 + 1.2.1
net.codecrete.usb java-does-usb - 1.2.1 + ${java-does-usb.version} diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index 5ba2e679..3f9f8a37 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -15,13 +15,14 @@ UTF-8 22 22 + 1.2.1
net.codecrete.usb java-does-usb - 1.2.1 + ${java-does-usb.version} org.tinylog diff --git a/examples/enumerate_kotlin/build.gradle.kts b/examples/enumerate_kotlin/build.gradle.kts index 03155481..bf275db3 100644 --- a/examples/enumerate_kotlin/build.gradle.kts +++ b/examples/enumerate_kotlin/build.gradle.kts @@ -6,7 +6,7 @@ plugins { group = "net.codecrete.usb.examples" version = "1.2.1" -val javaDoesUsbVersion = "1.2.1" +val javaDoesUsbVersion = (findProperty("javaDoesUsbVersion") as String?) ?: "1.2.1" val tinyLogVersion = "2.7.0" repositories { diff --git a/examples/enumerate_native/pom.xml b/examples/enumerate_native/pom.xml index d0bac23e..c31097e6 100644 --- a/examples/enumerate_native/pom.xml +++ b/examples/enumerate_native/pom.xml @@ -14,6 +14,7 @@ 25 UTF-8 0.11.0 + 1.2.1
@@ -46,7 +47,7 @@ net.codecrete.usb java-does-usb - 1.2.1 + ${java-does-usb.version} junit diff --git a/examples/epaper_display/pom.xml b/examples/epaper_display/pom.xml index d68e4e3b..02d00f8d 100644 --- a/examples/epaper_display/pom.xml +++ b/examples/epaper_display/pom.xml @@ -15,13 +15,14 @@ UTF-8 22 22 + 1.2.1
net.codecrete.usb java-does-usb - 1.2.1 + ${java-does-usb.version} diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index cebd39db..277c5bd3 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -15,13 +15,14 @@ UTF-8 22 22 + 1.2.1 net.codecrete.usb java-does-usb - 1.2.1 + ${java-does-usb.version} org.tinylog diff --git a/examples/monitor_kotlin/pom.xml b/examples/monitor_kotlin/pom.xml index c0c3d6b2..6afc0d25 100644 --- a/examples/monitor_kotlin/pom.xml +++ b/examples/monitor_kotlin/pom.xml @@ -15,6 +15,7 @@ true UTF-8 net.codecrete.usb.examples.MonitorKt + 1.2.1 @@ -64,7 +65,7 @@ net.codecrete.usb java-does-usb - 1.2.1 + ${java-does-usb.version} org.tinylog diff --git a/examples/monitor_native/pom.xml b/examples/monitor_native/pom.xml index 55f59768..709605a2 100644 --- a/examples/monitor_native/pom.xml +++ b/examples/monitor_native/pom.xml @@ -14,6 +14,7 @@ 25 UTF-8 0.11.0 + 1.2.1 @@ -46,7 +47,7 @@ net.codecrete.usb java-does-usb - 1.2.1 + ${java-does-usb.version} junit diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index c0cbf01c..06d38603 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -13,13 +13,14 @@ UTF-8 22 22 + 1.2.1 net.codecrete.usb java-does-usb - 1.2.1 + ${java-does-usb.version} diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index a53780ff..a6008ef5 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 1.2.1 + 1.2.2-SNAPSHOT 25 From efdb20d73d4a8a15a92c1deac5e85642ada85a29 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 10 Jul 2026 13:03:56 +0200 Subject: [PATCH 424/433] Fix mvn wrapper output --- .github/workflows/continuous-integration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index 7c385f3b..5f5d89bd 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -41,7 +41,7 @@ jobs: working-directory: ./java-does-usb - name: Determine java-does-usb version id: libver - run: echo "version=$(./mvnw -q help:evaluate -Dexpression=project.version -DforceStdout)" >> "$GITHUB_OUTPUT" + run: echo "version=$(./mvnw -q help:evaluate -Dexpression=project.version -DforceStdout | tail -n 1)" >> "$GITHUB_OUTPUT" working-directory: ./java-does-usb shell: bash # Examples pin the latest released version so they double as user-facing documentation; From f4cbf29f32e68a4dcd4e98156b1d6e437aa58f3d Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 10 Jul 2026 13:13:50 +0200 Subject: [PATCH 425/433] Fix Windows build --- .github/workflows/continuous-integration.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index 5f5d89bd..6dff4f7f 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -23,6 +23,9 @@ jobs: matrix: os: [ubuntu-latest, macOS-latest, windows-latest] runs-on: ${{ matrix.os }} + defaults: + run: + shell: bash steps: - uses: actions/checkout@v7 - name: Setup Java @@ -35,7 +38,6 @@ jobs: echo -n "$UNIT_TEST_SIGNING_KEY" | base64 --decode | gpg --import env: UNIT_TEST_SIGNING_KEY: ${{ vars.UNIT_TEST_SIGNING_KEY }} - shell: bash - name: Build java-does-usb run: ./mvnw $MAVEN_ARGS -DskipTests clean install javadoc:javadoc working-directory: ./java-does-usb @@ -43,7 +45,6 @@ jobs: id: libver run: echo "version=$(./mvnw -q help:evaluate -Dexpression=project.version -DforceStdout | tail -n 1)" >> "$GITHUB_OUTPUT" working-directory: ./java-does-usb - shell: bash # Examples pin the latest released version so they double as user-facing documentation; # override that pin here to compile them against the HEAD version just installed above. - name: Example "bulk_transfer" From da8f5fb1ab939e2be3292c672950a8fd2cbac32b Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 10 Jul 2026 13:19:03 +0200 Subject: [PATCH 426/433] Improved mvn default argument handling --- .github/workflows/continuous-integration.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index 6dff4f7f..50c693af 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -12,7 +12,7 @@ on: env: - MAVEN_ARGS: -B -V -ntp -e -Djansi.passthrough=true -Dstyle.color=always + MVN_DEFAULT_ARGS: -B -V -ntp -e -Djansi.passthrough=true -Dstyle.color=always jobs: @@ -39,32 +39,32 @@ jobs: env: UNIT_TEST_SIGNING_KEY: ${{ vars.UNIT_TEST_SIGNING_KEY }} - name: Build java-does-usb - run: ./mvnw $MAVEN_ARGS -DskipTests clean install javadoc:javadoc + run: ./mvnw $MVN_DEFAULT_ARGS -DskipTests clean install javadoc:javadoc working-directory: ./java-does-usb - name: Determine java-does-usb version id: libver - run: echo "version=$(./mvnw -q help:evaluate -Dexpression=project.version -DforceStdout | tail -n 1)" >> "$GITHUB_OUTPUT" + run: echo "version=$(./mvnw -q -ntp help:evaluate -Dexpression=project.version -DforceStdout)" >> "$GITHUB_OUTPUT" working-directory: ./java-does-usb # Examples pin the latest released version so they double as user-facing documentation; # override that pin here to compile them against the HEAD version just installed above. - name: Example "bulk_transfer" - run: ./mvnw $MAVEN_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean compile + run: ./mvnw $MVN_DEFAULT_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean compile working-directory: ./examples/bulk_transfer - name: Example "enumerate" - run: ./mvnw $MAVEN_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean compile + run: ./mvnw $MVN_DEFAULT_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean compile working-directory: ./examples/enumerate - name: Example "enumerate" (Kotlin) run: ./gradlew -PjavaDoesUsbVersion=${{ steps.libver.outputs.version }} clean build working-directory: ./examples/enumerate_kotlin - name: Example "monitor" - run: ./mvnw $MAVEN_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean compile + run: ./mvnw $MVN_DEFAULT_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean compile working-directory: ./examples/monitor - name: Example "monitor" (Kotlin) - run: ./mvnw $MAVEN_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean package + run: ./mvnw $MVN_DEFAULT_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean package working-directory: ./examples/monitor_kotlin - name: Example "stm_dfu" - run: ./mvnw $MAVEN_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean compile + run: ./mvnw $MVN_DEFAULT_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean compile working-directory: ./examples/stm_dfu - name: Example "epaper_display" - run: ./mvnw $MAVEN_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean compile + run: ./mvnw $MVN_DEFAULT_ARGS -Djava-does-usb.version=${{ steps.libver.outputs.version }} clean compile working-directory: ./examples/epaper_display From a779a021cc6a61f3b528f4835634274b854df584 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 10 Jul 2026 14:21:20 +0200 Subject: [PATCH 427/433] Make Java 25 a prerequisite --- README.md | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 03c03f3b..4ee8295c 100644 --- a/README.md +++ b/README.md @@ -77,8 +77,8 @@ public class EnumerateDevices { ## Prerequisite -- Java 22 or higher, available at [jdk.java.net](https://jdk.java.net/), [Azul](https://www.azul.com/downloads/?package=jdk), [Adoptium](https://adoptium.net/temurin/releases/) or with your favorite package manager. -- Windows (x86 64-bit, ARM 64-bit), macOS (x86 64-bit, ARM 64-bit) or Linux 64 bit (x86 64-bit, ARM 64-bit). +- Java 25 or higher +- Windows (x86 64-bit, ARM 64-bit), macOS (x86 64-bit, ARM 64-bit) or Linux 64 bit (x86 64-bit, ARM 64-bit) @@ -121,30 +121,6 @@ The implementation runs on both Windows for Intel/AMD and ARM processors. -## Troubleshooting - -### 32-bit versions - -The *Foreign Function And Memory API* has not been implemented for 32-bit operating systems / JDKs (and likely never will be). - - - -## Running on older JDK versions - -The *Foreign Function And Memory API* has been available as a preview feature in JDKs before 22. However, incompatible changes were made from preview to preview to release. Earlier versions can be used with specific versions of this library: - -| Version | Main New Features | Compatibility | -| - | - | - | -| 1.x.x | Release for final Java API | JDK 22 and higher | -| 0.7.x | New setter/getter names for improved Kotlin support; Kotlin examples | JDK 21 | -| 0.6.x | Support for JDK 21; better handling of composite devices on Windows | JDK 21 | -| 0.5.x | Support for JDK 20; high-throuput I/O streams | JDK 20 | -| 0.4.x | Early release | JDK 19 | - -When using an older JDK, preview features must be enabled using the `--enable-preview` VM option. - - - ## Building from source To build from source, run the following command: From b5b29fc537a3c52019baa0dc1f79a3a0f0656a9c Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 10 Jul 2026 14:33:11 +0200 Subject: [PATCH 428/433] Update code size statistics --- java-does-usb/jextract/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/java-does-usb/jextract/README.md b/java-does-usb/jextract/README.md index b730400a..79d0f270 100644 --- a/java-does-usb/jextract/README.md +++ b/java-does-usb/jextract/README.md @@ -66,15 +66,15 @@ variable size, GUID and device property key (`DEVPKEY`) constants etc. The worst example is [`IOUSBInterfaceStruct190`](https://github.com/manuelbl/JavaDoesUSB/blob/main/java-does-usb/src/main/java/net/codecrete/usb/macos/gen/iokit/IOUSBInterfaceStruct190.java) (macOS). This is a `struct` consisting of about 50 member functions. It's basically a vtable of a C++ class. For this single `struct`, *jextract* generates codes resulting in 100 class files with a total size of 213kByte. -The table below shows class file size statistics for version 1.0.0 of the library: +The table below shows class file size statistics for version 1.2.2 of the library: | Operating Systems | Manually Written | % | Generated | % | Total | % | |-------------------|-----------------:|------:|----------:|------:|----------:|--------:| -| Linux | 54,022 | 4.3% | 162,099 | 12.8% | 216,121 | 17.1% | -| macOS | 77,149 | 6.1% | 529,347 | 41.8% | 606,496 | 47.9% | -| Windows | 106,358 | 8.4% | 232,395 | 18.3% | 338,753 | 26.7% | -| Common | 105,423 | 8.3% | | | 105,423 | 8.3% | -| Grand Total | 342,952 | 27.1% | 923,841 | 72.9% | 1,266,793 | 100.0% | +| Linux | 58,393 | 4.5% | 154,398 | 11.8% | 212,791 | 16.3% | +| macOS | 81,441 | 6.2% | 427,258 | 32.8% | 508,699 | 39.0% | +| Windows | 84,099 | 6.5% | 384,452 | 29.5% | 468,551 | 35.9% | +| Common | 113,568 | 8.7% | | | 113,568 | 8.7% | +| Grand Total | 337,501 | 25.9% | 966,108 | 74.1% | 1,303,609 | 100.0% | *Class File Size (compiled), in bytes and percentage of total size* From c566603902504a7c6d1513fd0ea2c15c197a510d Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 10 Jul 2026 14:36:28 +0200 Subject: [PATCH 429/433] Fix mistakes in README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4ee8295c..0207a662 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![javadoc](https://javadoc.io/badge2/net.codecrete.usb/java-does-usb/javadoc.svg)](https://javadoc.io/doc/net.codecrete.usb/java-does-usb) -*Java Does USB* is a Java library for working with USB devices. It allows to query the conntected USB devices and to communicate with them using custom / vendor specific protocols. It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc. +*Java Does USB* is a Java library for working with USB devices. It allows you to query the connected USB devices and to communicate with them using custom / vendor-specific protocols. It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc. The library uses the [Foreign Function and Memory API](https://docs.oracle.com/en/java/javase/22/core/foreign-function-and-memory-api.html) to access native APIs of the underlying operating system. It is written entirely in Java and does not use JNI or any native third-party library. The *Foreign Function and Memory API* has been introduced with Java 22. @@ -87,14 +87,14 @@ public class EnumerateDevices { ### macOS -No special considerations apply. Using this library, a Java application can connect to any USB device and claim any interface that isn't claimed by an operating system driver or another application. Standard operation system drivers can be unloaded if the application is run with *root* privileges. It runs both on Macs with Apple Silicon and Intel processors. +No special considerations apply. Using this library, a Java application can connect to any USB device and claim any interface that isn't claimed by an operating system driver or another application. Standard operating system drivers can be unloaded if the application is run with *root* privileges. It runs both on Macs with Apple Silicon and Intel processors. ### Linux *libudev* is used to discover and monitor USB devices. It is closely tied to *systemd*. So the library runs on Linux distributions with *systemd* and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfill this requirement. It runs on both Intel/AMD and ARM processors. -Similar to macOS, a Java application can connect to any USB device and claim any interface that isn't claimed by an operating system driver or another application. Standard operation system drivers can be unloaded (without the need for root privileges). +Similar to macOS, a Java application can connect to any USB device and claim any interface that isn't claimed by an operating system driver or another application. Standard operating system drivers can be unloaded (without the need for root privileges). Most Linux distributions set up user accounts without permissions to access USB devices. The *udev* system daemon is responsible for assigning permissions to USB devices. It can be configured to assign specific permissions or ownership: @@ -113,7 +113,7 @@ Without the *udev* rule, it is still possible to enumerate and query all USB dev The Windows driver model is rather rigid. It's not possible to open a USB device unless it uses the *WinUSB* driver. This even applies to devices with no installed driver. Enumerating and querying USB devices is possible independent of the driver. -USB devices can implement special control requests to instruct Windows to automatically install the WinUSB driver (search for *WCID* or *Microsoft OS Compatibility Descriptors*). The WinUSB driver can also be manually installed or replaced using a software called [Zadig](https://zadig.akeo.ie/). +USB devices can implement special control requests to instruct Windows to automatically install the WinUSB driver (search for *WCID* or *Microsoft OS Compatibility Descriptors*). The WinUSB driver can also be manually installed or replaced using a tool called [Zadig](https://zadig.akeo.ie/). The test devices implement the required control requests. So the driver is installed automatically. @@ -141,7 +141,7 @@ In order to run the unit tests, a special test device must be connected to the c - [loopback-stm32](test-devices/loopback-stm32) - [composite-stm32](test-devices/composite-stm32) -The test device with the *loopback-stm32* code supports all tests. If the test device with the *composite-stm32* code is connected, some tests are skipped. However, if it is used, the correct handling of composite devices is verified. +The test device with the *loopback-stm32* code supports all tests. If the test device with the *composite-stm32* code is connected, some tests are skipped, but the correct handling of composite devices is verified instead. Tests can be run from the command line: @@ -150,7 +150,7 @@ cd java-does-usb mvn clean test ``` -If they are run from an IDE (such as IntelliJ IDEA), you must likely configure VM options to allow native access: +If they are run from an IDE (such as IntelliJ IDEA), you will likely need to configure VM options to allow native access: ``` --enable-native-access=net.codecrete.usb From c4cec3b2a5693765af83e6ed7be50eac50522b81 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 10 Jul 2026 14:41:17 +0200 Subject: [PATCH 430/433] Minor fixes in Javadoc --- .../java/net/codecrete/usb/UsbAlternateInterface.java | 3 ++- .../main/java/net/codecrete/usb/UsbControlTransfer.java | 6 +++--- .../src/main/java/net/codecrete/usb/UsbDevice.java | 8 ++++---- .../main/java/net/codecrete/usb/UsbDevicePredicate.java | 4 ++-- .../src/main/java/net/codecrete/usb/UsbInterface.java | 4 ++-- .../main/java/net/codecrete/usb/UsbStallException.java | 4 ++-- .../src/main/java/net/codecrete/usb/Version.java | 2 +- 7 files changed, 16 insertions(+), 15 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/UsbAlternateInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbAlternateInterface.java index c4cfbefc..835f68aa 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/UsbAlternateInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbAlternateInterface.java @@ -24,6 +24,7 @@ public interface UsbAlternateInterface { * Gets the alternate setting number. *

* It is equal to the {@code bAlternateSetting} field of the interface descriptor. + *

* * @return the alternate setting number */ @@ -60,7 +61,7 @@ public interface UsbAlternateInterface { int getProtocolCode(); /** - * Gets the endpoints of this alternate interface settings. + * Gets the endpoints of this alternate interface setting. *

* The endpoint list does not include endpoint 0, which * is always available and reserved for control transfers. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/UsbControlTransfer.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbControlTransfer.java index 60089114..dbc2e042 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/UsbControlTransfer.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbControlTransfer.java @@ -20,9 +20,9 @@ * * @param requestType request type (bits 5 and 6 of {@code bmRequestType}) * @param recipient recipient (bits 0–4 of {@code bmRequestType}) - * @param request request code (value between 0 and 255, called {@code bRequest} in USB specification) - * @param value value (value between 0 and 65535, called {@code wValue} in USB specification) - * @param index index (value between 0 and 65535, called {@code wIndex} in USB specification). + * @param request request code (value between 0 and 255, called {@code bRequest} in the USB specification) + * @param value value (value between 0 and 65535, called {@code wValue} in the USB specification) + * @param index index (value between 0 and 65535, called {@code wIndex} in the USB specification) */ public record UsbControlTransfer( UsbRequestType requestType, diff --git a/java-does-usb/src/main/java/net/codecrete/usb/UsbDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbDevice.java index 1fe22e9a..786956ba 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/UsbDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbDevice.java @@ -18,7 +18,7 @@ * USB device. *

* In order to make control requests and transfer data, the device must be - * opened and an interface must be claimed. In the open state, this current + * opened and an interface must be claimed. In the open state, the current * process has exclusive access to the device. *

*

@@ -50,14 +50,14 @@ public interface UsbDevice { String getProduct(); /** - * Manufacturer name + * Manufacturer name. * * @return manufacturer name or {@code null} if not provided by the device */ String getManufacturer(); /** - * Serial number + * Serial number. *

* Even though this is supposed to be a human-readable string, * some devices are known to provide binary data. @@ -144,7 +144,7 @@ public interface UsbDevice { *

* On Linux, this method changes the behavior of {@link #claimInterface(int)}. Standard drivers will no longer be * detached when the interface is claimed. Standard drivers are automatically reattached when the interfaces - * are released, at the lasted when the device is closed. + * are released, at the latest when the device is closed. *

*

* On Windows, this method does nothing. diff --git a/java-does-usb/src/main/java/net/codecrete/usb/UsbDevicePredicate.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbDevicePredicate.java index 609db9b4..687db9ed 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/UsbDevicePredicate.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbDevicePredicate.java @@ -23,12 +23,12 @@ public interface UsbDevicePredicate { * Evaluates this predicate on the given USB device. * * @param device the USB device - * @return {@code true} of the devices matches the predicate, otherwise {@code false} + * @return {@code true} if the device matches the predicate, otherwise {@code false} */ boolean matches(@NotNull UsbDevice device); /** - * Test if the USB devices matches any of the filter conditions. + * Tests whether the USB device matches any of the filter conditions. * * @param device the USB device * @param predicates a list of filter predicates diff --git a/java-does-usb/src/main/java/net/codecrete/usb/UsbInterface.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbInterface.java index b0aad6c2..67fde72f 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/UsbInterface.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbInterface.java @@ -40,7 +40,7 @@ public interface UsbInterface { /** * Gets the currently selected alternate interface setting. *

- * Initially, the alternate settings with number 0 is selected. + * Initially, the alternate setting with number 0 is selected. *

* * @return the alternate interface setting. @@ -48,7 +48,7 @@ public interface UsbInterface { @NotNull UsbAlternateInterface getCurrentAlternate(); /** - * Gets the alternate interface settings with the specified number. + * Gets the alternate interface setting with the specified number. * * @param alternateNumber alternate setting number * @return alternate interface setting diff --git a/java-does-usb/src/main/java/net/codecrete/usb/UsbStallException.java b/java-does-usb/src/main/java/net/codecrete/usb/UsbStallException.java index b6b7ed46..e60da595 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/UsbStallException.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/UsbStallException.java @@ -10,13 +10,13 @@ import org.jetbrains.annotations.NotNull; /** - * Exception thrown if a communication on a USB endpoint failed. + * Exception thrown if communication on a USB endpoint fails. *

* If a USB endpoint stalls, it is halted and the halt condition must be cleared * using {@link UsbDevice#clearHalt(UsbDirection, int)} before communication can resume. *

*

- * If the control endpoint 0 stalls, it throws this exception but is not halted. + * If the control endpoint 0 stalls, this exception is thrown but the endpoint is not halted. *

*/ public class UsbStallException extends UsbException { diff --git a/java-does-usb/src/main/java/net/codecrete/usb/Version.java b/java-does-usb/src/main/java/net/codecrete/usb/Version.java index f9722ef8..90b507f5 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/Version.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/Version.java @@ -19,7 +19,7 @@ public final class Version { *

* {@code bcdVersion} contains the version: the high byte is the major * version. The low byte is split into two nibbles (4 bits), the high one - * is minor version, the low one is the subminor version. As an example, + * is the minor version, the low one is the subminor version. As an example, * 0x0321 represents the version 3.2.1. *

* From 094dd1ce39ca1f28d18ab8a4e701cb4b6ee00738 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 10 Jul 2026 14:49:42 +0200 Subject: [PATCH 431/433] Release 1.3.0 --- README.md | 4 ++-- RELEASING.md | 2 +- examples/bulk_transfer/README.md | 2 +- examples/bulk_transfer/pom.xml | 4 ++-- examples/enumerate/README.md | 2 +- examples/enumerate/pom.xml | 4 ++-- examples/enumerate_kotlin/build.gradle.kts | 4 ++-- examples/enumerate_native/pom.xml | 2 +- examples/epaper_display/README.md | 4 ++-- examples/epaper_display/pom.xml | 4 ++-- examples/monitor/README.md | 2 +- examples/monitor/pom.xml | 4 ++-- examples/monitor_kotlin/README.md | 2 +- examples/monitor_kotlin/pom.xml | 4 ++-- examples/monitor_native/pom.xml | 2 +- examples/stm_dfu/README.md | 2 +- examples/stm_dfu/pom.xml | 4 ++-- java-does-usb/pom.xml | 2 +- test-graalvm/pom.xml | 2 +- 19 files changed, 28 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 0207a662..be31a6cd 100644 --- a/README.md +++ b/README.md @@ -31,14 +31,14 @@ If you are using Maven, add the below dependency to your pom.xml: net.codecrete.usb java-does-usb - 1.2.1 + 1.3.0 ``` If you are using Gradle, add the below dependency to your build.gradle file: ```groovy -compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '1.2.1' +compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '1.3.0' ``` ```java diff --git a/RELEASING.md b/RELEASING.md index 948576cf..cec63a4d 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -23,7 +23,7 @@ version numbers flow through the repository afterwards. In `java-does-usb/pom.xml`, set `` to the release version, e.g.: ```bash cd java-does-usb - ./mvnw versions:set -DnewVersion=1.2.2 -DgenerateBackupPoms=false + ./mvnw versions:set -DnewVersion=1.3.1 -DgenerateBackupPoms=false ``` 2. **Update the version everywhere it's pinned for users.** This means: diff --git a/examples/bulk_transfer/README.md b/examples/bulk_transfer/README.md index 4d8c964d..83b4d92e 100644 --- a/examples/bulk_transfer/README.md +++ b/examples/bulk_transfer/README.md @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] --------------< net.codecrete.usb.examples:bulk-transfer >-------------- -[INFO] Building bulk-transfer 1.2.1 +[INFO] Building bulk-transfer 1.3.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ bulk-transfer --- diff --git a/examples/bulk_transfer/pom.xml b/examples/bulk_transfer/pom.xml index 589f744b..e6734349 100644 --- a/examples/bulk_transfer/pom.xml +++ b/examples/bulk_transfer/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples bulk-transfer - 1.2.1 + 1.3.0 bulk-transfer https://github.com/manuelbl/JavaDoesUSB/examples/bulk_transfer @@ -15,7 +15,7 @@ UTF-8 22 22 - 1.2.1 + 1.3.0
diff --git a/examples/enumerate/README.md b/examples/enumerate/README.md index 0fcfbc34..42683a15 100644 --- a/examples/enumerate/README.md +++ b/examples/enumerate/README.md @@ -38,7 +38,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] ----------------< net.codecrete.usb.examples:enumerate >---------------- -[INFO] Building enumerate 1.2.1 +[INFO] Building enumerate 1.3.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ enumerate --- diff --git a/examples/enumerate/pom.xml b/examples/enumerate/pom.xml index 3f9f8a37..07c06829 100644 --- a/examples/enumerate/pom.xml +++ b/examples/enumerate/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples enumerate - 1.2.1 + 1.3.0 enumerate https://github.com/manuelbl/JavaDoesUSB/examples/enumerate @@ -15,7 +15,7 @@ UTF-8 22 22 - 1.2.1 + 1.3.0 diff --git a/examples/enumerate_kotlin/build.gradle.kts b/examples/enumerate_kotlin/build.gradle.kts index bf275db3..6d836d13 100644 --- a/examples/enumerate_kotlin/build.gradle.kts +++ b/examples/enumerate_kotlin/build.gradle.kts @@ -4,9 +4,9 @@ plugins { } group = "net.codecrete.usb.examples" -version = "1.2.1" +version = "1.3.0" -val javaDoesUsbVersion = (findProperty("javaDoesUsbVersion") as String?) ?: "1.2.1" +val javaDoesUsbVersion = (findProperty("javaDoesUsbVersion") as String?) ?: "1.3.0" val tinyLogVersion = "2.7.0" repositories { diff --git a/examples/enumerate_native/pom.xml b/examples/enumerate_native/pom.xml index c31097e6..c6a9c555 100644 --- a/examples/enumerate_native/pom.xml +++ b/examples/enumerate_native/pom.xml @@ -14,7 +14,7 @@ 25 UTF-8 0.11.0 - 1.2.1 + 1.3.0 diff --git a/examples/epaper_display/README.md b/examples/epaper_display/README.md index 9b6b77a1..c45f7e08 100644 --- a/examples/epaper_display/README.md +++ b/examples/epaper_display/README.md @@ -45,7 +45,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -------------< net.codecrete.usb.examples:epaper-display >-------------- -[INFO] Building epaper-display 1.2.1 +[INFO] Building epaper-display 1.3.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ epaper-display --- @@ -79,6 +79,6 @@ $ sudo -i Password: $ cd /Users/me/Documents/JavaDoesUSB/examples/epaper_display $ export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-20.jdk/Contents/Home -$ $JAVA_HOME/bin/java --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/1.2.1/java-does-usb-1.2.1.jar net.codecrete.usb.examples.EPaperDisplay +$ $JAVA_HOME/bin/java --enable-native-access=ALL-UNNAMED -cp target/classes:/Users/me/.m2/repository/net/codecrete/usb/java-does-usb/1.3.0/java-does-usb-1.3.0.jar net.codecrete.usb.examples.EPaperDisplay Display size: 1200 x 825 ``` diff --git a/examples/epaper_display/pom.xml b/examples/epaper_display/pom.xml index 02d00f8d..b69b1432 100644 --- a/examples/epaper_display/pom.xml +++ b/examples/epaper_display/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples epaper-display - 1.2.1 + 1.3.0 epaper-display https://github.com/manuelbl/JavaDoesUSB/examples/epaper_display @@ -15,7 +15,7 @@ UTF-8 22 22 - 1.2.1 + 1.3.0 diff --git a/examples/monitor/README.md b/examples/monitor/README.md index 5473a9fb..f32c60c9 100644 --- a/examples/monitor/README.md +++ b/examples/monitor/README.md @@ -39,7 +39,7 @@ $ mvn compile exec:exec [INFO] Scanning for projects... [INFO] [INFO] -----------------< net.codecrete.usb.examples:monitor >----------------- -[INFO] Building monitor 1.2.1 +[INFO] Building monitor 1.3.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ monitor --- diff --git a/examples/monitor/pom.xml b/examples/monitor/pom.xml index 277c5bd3..52206a11 100644 --- a/examples/monitor/pom.xml +++ b/examples/monitor/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb.examples monitor - 1.2.1 + 1.3.0 monitor https://github.com/manuelbl/JavaDoesUSB/examples/monitor @@ -15,7 +15,7 @@ UTF-8 22 22 - 1.2.1 + 1.3.0 diff --git a/examples/monitor_kotlin/README.md b/examples/monitor_kotlin/README.md index eae39270..f98849da 100644 --- a/examples/monitor_kotlin/README.md +++ b/examples/monitor_kotlin/README.md @@ -40,7 +40,7 @@ $ mvn clean package ### Run the jar ```shell -$ java --enable-native-access=ALL-UNNAMED -jar target/monitor-1.2.1-jar-with-dependencies.jar +$ java --enable-native-access=ALL-UNNAMED -jar target/monitor-1.3.0-jar-with-dependencies.jar Present: VID: 0x1d6b, PID: 0x0002, manufacturer: Linux 6.5.0-18-generic xhci-hcd, product: xHCI Host Controller, serial: 0000:00:14.0, ID: /dev/bus/usb/001/001 Present: VID: 0xcafe, PID: 0xceaf, manufacturer: JavaDoesUSB, product: Loopback, serial: 35A737883336, ID: /dev/bus/usb/001/009 Monitoring... Press ENTER to quit. diff --git a/examples/monitor_kotlin/pom.xml b/examples/monitor_kotlin/pom.xml index 6afc0d25..2612f221 100644 --- a/examples/monitor_kotlin/pom.xml +++ b/examples/monitor_kotlin/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples monitor - 1.2.1 + 1.3.0 jar monitor @@ -15,7 +15,7 @@ true UTF-8 net.codecrete.usb.examples.MonitorKt - 1.2.1 + 1.3.0 diff --git a/examples/monitor_native/pom.xml b/examples/monitor_native/pom.xml index 709605a2..68e930de 100644 --- a/examples/monitor_native/pom.xml +++ b/examples/monitor_native/pom.xml @@ -14,7 +14,7 @@ 25 UTF-8 0.11.0 - 1.2.1 + 1.3.0 diff --git a/examples/stm_dfu/README.md b/examples/stm_dfu/README.md index 04c1e279..8c5285d0 100644 --- a/examples/stm_dfu/README.md +++ b/examples/stm_dfu/README.md @@ -58,7 +58,7 @@ Run the command below (adapting the file path depending on your specific board): ```shell $ mvn package -$ java --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-1.2.1.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin +$ java --enable-native-access=ALL-UNNAMED -jar target/stm_dfu-1.3.0.jar ../../test-devices/loopback-stm32/bin/blackpill-f401cc.bin DFU device found with serial 35A737883336. Target memory segment: Internal Flash Erasing page at 0x8000000 (size 0x4000) diff --git a/examples/stm_dfu/pom.xml b/examples/stm_dfu/pom.xml index 06d38603..0e3aa46d 100644 --- a/examples/stm_dfu/pom.xml +++ b/examples/stm_dfu/pom.xml @@ -4,7 +4,7 @@ net.codecrete.usb.examples stm_dfu - 1.2.1 + 1.3.0 stm_dfu https://github.com/manuelbl/JavaDoesUSB/examples/stm_dfu @@ -13,7 +13,7 @@ UTF-8 22 22 - 1.2.1 + 1.3.0 diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index a6008ef5..156fff97 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 1.2.2-SNAPSHOT + 1.3.0 25 diff --git a/test-graalvm/pom.xml b/test-graalvm/pom.xml index f67ae206..cfaf0bbf 100644 --- a/test-graalvm/pom.xml +++ b/test-graalvm/pom.xml @@ -46,7 +46,7 @@ net.codecrete.usb java-does-usb - 1.2.1 + 1.3.0 junit From 299019dbf1c7a10ec06860bff5ec82bcea6f26dd Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 10 Jul 2026 14:56:42 +0200 Subject: [PATCH 432/433] Prepare for next development iteration --- RELEASING.md | 5 ++--- java-does-usb/pom.xml | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index cec63a4d..3e3511a0 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -60,10 +60,9 @@ version numbers flow through the repository afterwards. git tag v1.2.2 git push origin main v1.2.2 cd java-does-usb - ./mvnw clean deploy -Prelease # or whatever profile/flags drive maven-gpg-plugin + central-publishing-maven-plugin + ./mvnw clean install # GPG passphrase from password store + ./mvnw clean deploy ``` - (Adjust to however signing/publishing is actually invoked locally today — this step is manual - and not run by CI.) 4. **Prepare `main` for the next development iteration.** ```bash diff --git a/java-does-usb/pom.xml b/java-does-usb/pom.xml index 156fff97..e8ad6aec 100644 --- a/java-does-usb/pom.xml +++ b/java-does-usb/pom.xml @@ -6,7 +6,7 @@ net.codecrete.usb java-does-usb - 1.3.0 + 1.3.1-SNAPSHOT 25 From 8d1a6e5c313f3a9f90b5b0b7b91bd1d6adc78d02 Mon Sep 17 00:00:00 2001 From: "Manuel Bl." Date: Fri, 10 Jul 2026 21:24:17 +0200 Subject: [PATCH 433/433] Link to native examples --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index be31a6cd..6ee637da 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ public class EnumerateDevices { - Monitor ([Java](examples/monitor/) / [Kotlin](examples/monitor_kotlin/)) lists the connected USB devices and then monitors for devices being connected and disconnected. - [Device Firmware Upload (DFU) for STM32](examples/stm_dfu) uploads firmware to STM32 microcontrollers supporting the built-in DFU mode. - [ePaper Display](examples/epaper_display) communicates with an IT8951 controller for e-Paper displays and shows an image on the display. +- [Enumerate Native](examples/enumerate_native/) and [Monitor Native](examples/monitor_native/) demostrate how to build a native image with GraalVM.

* This example assumes that one of the interfaces has two bulk endpoints, * one for sending and one for receiving data. The test device fulfils - * this requirement (see https://github.com/manuelbl/JavaDoesUSB/tree/main/test-devices/loopback-stm32) + * this requirement (see + * loopback-stm32) *